diff --git a/Documentation/ABI/testing/sysfs-driver-wacom b/Documentation/ABI/testing/sysfs-driver-wacom
index 8d55a83..7fc7810 100644
--- a/Documentation/ABI/testing/sysfs-driver-wacom
+++ b/Documentation/ABI/testing/sysfs-driver-wacom
@@ -1,3 +1,16 @@
+WWhat:		/sys/class/hidraw/hidraw*/device/oled*_img
+Date:		June 2012
+Contact:	linux-bluetooth@vger.kernel.org
+Description:
+		The /sys/class/hidraw/hidraw*/device/oled*_img files control
+		OLED mocro displays on Intuos4 Wireless tablet. Accepted image
+		has to contain 256 bytes (64x32 px 1 bit colour). The format
+		is the same as PBM image 62x32px without header (64 bits per
+		horizontal line, 32 lines). An example of setting OLED No. 0:
+		dd bs=256 count=1 if=img_file of=[path to oled0_img]/oled0_img
+		The attribute is read only and no local copy of the image is
+		stored.
+
 What:		/sys/class/hidraw/hidraw*/device/speed
 Date:		April 2010
 Kernel Version:	2.6.35
diff --git a/Documentation/ABI/testing/sysfs-fs-ext4 b/Documentation/ABI/testing/sysfs-fs-ext4
index f22ac08..c631253 100644
--- a/Documentation/ABI/testing/sysfs-fs-ext4
+++ b/Documentation/ABI/testing/sysfs-fs-ext4
@@ -96,3 +96,16 @@ Contact:	"Theodore Ts'o" <tytso@mit.edu>
 Description:
 		The maximum number of megabytes the writeback code will
 		try to write out before move on to another inode.
+
+What:		/sys/fs/ext4/<disk>/extent_max_zeroout_kb
+Date:		August 2012
+Contact:	"Theodore Ts'o" <tytso@mit.edu>
+Description:
+		The maximum number of kilobytes which will be zeroed
+		out in preference to creating a new uninitialized
+		extent when manipulating an inode's extent tree.  Note
+		that using a larger value will increase the
+		variability of time necessary to complete a random
+		write operation (since a 4k random write might turn
+		into a much larger write due to the zeroout
+		operation).
diff --git a/Documentation/DocBook/media/Makefile b/Documentation/DocBook/media/Makefile
index 3625209..9b7e4c5 100644
--- a/Documentation/DocBook/media/Makefile
+++ b/Documentation/DocBook/media/Makefile
@@ -300,7 +300,7 @@ $(MEDIA_OBJ_DIR)/media-entities.tmpl: $(MEDIA_OBJ_DIR)/v4l2.xml
 	@(								\
 	for ident in $(IOCTLS) ; do					\
 	  entity=`echo $$ident | tr _ -` ;				\
-	  id=`grep "<refname>$$ident" $(MEDIA_OBJ_DIR)/vidioc-*.xml | sed -r s,"^.*/(.*).xml.*","\1",` ; \
+	  id=`grep "<refname>$$ident" $(MEDIA_OBJ_DIR)/vidioc-*.xml $(MEDIA_OBJ_DIR)/media-ioc-*.xml | sed -r s,"^.*/(.*).xml.*","\1",` ; \
 	  echo "<!ENTITY $$entity \"<link"				\
 	    "linkend='$$id'><constant>$$ident</constant></link>\">"	\
 	  >>$@ ;							\
diff --git a/Documentation/DocBook/media/dvb/audio.xml b/Documentation/DocBook/media/dvb/audio.xml
index d643862..a7ea56c 100644
--- a/Documentation/DocBook/media/dvb/audio.xml
+++ b/Documentation/DocBook/media/dvb/audio.xml
@@ -1,12 +1,16 @@
 <title>DVB Audio Device</title>
 <para>The DVB audio device controls the MPEG2 audio decoder of the DVB hardware. It
 can be accessed through <emphasis role="tt">/dev/dvb/adapter0/audio0</emphasis>. Data types and and
-ioctl definitions can be accessed by including <emphasis role="tt">linux/dvb/video.h</emphasis> in your
+ioctl definitions can be accessed by including <emphasis role="tt">linux/dvb/audio.h</emphasis> in your
 application.
 </para>
 <para>Please note that some DVB cards don&#8217;t have their own MPEG decoder, which results in
 the omission of the audio and video device.
 </para>
+<para>
+These ioctls were also used by V4L2 to control MPEG decoders implemented in V4L2. The use
+of these ioctls for that purpose has been made obsolete and proper V4L2 ioctls or controls
+have been created to replace that functionality.</para>
 
 <section id="audio_data_types">
 <title>Audio Data Types</title>
@@ -558,6 +562,8 @@ role="subsection"><title>AUDIO_SELECT_SOURCE</title>
 role="subsection"><title>AUDIO_SET_MUTE</title>
 <para>DESCRIPTION
 </para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+&VIDIOC-DECODER-CMD; with the <constant>V4L2_DEC_CMD_START_MUTE_AUDIO</constant> flag instead.</para>
 <informaltable><tgroup cols="1"><tbody><row><entry
  align="char">
 <para>This ioctl call asks the audio device to mute the stream that is currently being
@@ -730,6 +736,8 @@ role="subsection"><title>AUDIO_SET_BYPASS_MODE</title>
 role="subsection"><title>AUDIO_CHANNEL_SELECT</title>
 <para>DESCRIPTION
 </para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+<constant>V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK</constant> control instead.</para>
 <informaltable><tgroup cols="1"><tbody><row><entry
  align="char">
 <para>This ioctl call asks the Audio Device to select the requested channel if possible.</para>
@@ -772,6 +780,109 @@ role="subsection"><title>AUDIO_CHANNEL_SELECT</title>
  </row></tbody></tgroup></informaltable>
 &return-value-dvb;
 
+</section><section id="AUDIO_BILINGUAL_CHANNEL_SELECT"
+role="subsection"><title>AUDIO_BILINGUAL_CHANNEL_SELECT</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. It has been replaced by
+the V4L2 <constant>V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK</constant> control
+for MPEG decoders controlled through V4L2.</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Audio Device to select the requested channel for bilingual streams if possible.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ AUDIO_BILINGUAL_CHANNEL_SELECT, audio_channel_select_t);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_BILINGUAL_CHANNEL_SELECT for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>audio_channel_select_t
+ch</para>
+</entry><entry
+ align="char">
+<para>Select the output format of the audio (mono left/right,
+ stereo).</para>
+</entry>
+ </row>
+</tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="AUDIO_GET_PTS"
+role="subsection"><title>AUDIO_GET_PTS</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. If you need this functionality,
+then please contact the linux-media mailing list (&v4l-ml;).</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Audio Device to return the current PTS timestamp.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ AUDIO_GET_PTS, __u64 *pts);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_GET_PTS for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u64 *pts
+</para>
+</entry><entry
+ align="char">
+<para>Returns the 33-bit timestamp as defined in ITU T-REC-H.222.0 / ISO/IEC 13818-1.
+</para>
+<para>
+The PTS should belong to the currently played
+frame if possible, but may also be a value close to it
+like the PTS of the last decoded frame or the last PTS
+extracted by the PES parser.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
 </section><section id="AUDIO_GET_STATUS"
 role="subsection"><title>AUDIO_GET_STATUS</title>
 <para>DESCRIPTION
diff --git a/Documentation/DocBook/media/dvb/ca.xml b/Documentation/DocBook/media/dvb/ca.xml
index 5c4adb4..85eaf4f 100644
--- a/Documentation/DocBook/media/dvb/ca.xml
+++ b/Documentation/DocBook/media/dvb/ca.xml
@@ -226,4 +226,357 @@ typedef struct ca_pid {
 </entry>
  </row></tbody></tgroup></informaltable>
  </section>
+
+<section id="CA_RESET"
+role="subsection"><title>CA_RESET</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_RESET);
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_RESET for this command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_GET_CAP"
+role="subsection"><title>CA_GET_CAP</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_GET_CAP,
+ ca_caps_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_GET_CAP for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_caps_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_GET_SLOT_INFO"
+role="subsection"><title>CA_GET_SLOT_INFO</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_GET_SLOT_INFO,
+ ca_slot_info_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_GET_SLOT_INFO for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_slot_info_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_GET_DESCR_INFO"
+role="subsection"><title>CA_GET_DESCR_INFO</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_GET_DESCR_INFO,
+ ca_descr_info_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_GET_DESCR_INFO for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_descr_info_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_GET_MSG"
+role="subsection"><title>CA_GET_MSG</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_GET_MSG,
+ ca_msg_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_GET_MSG for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_msg_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_SEND_MSG"
+role="subsection"><title>CA_SEND_MSG</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_SEND_MSG,
+ ca_msg_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_SEND_MSG for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_msg_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_SET_DESCR"
+role="subsection"><title>CA_SET_DESCR</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_SET_DESCR,
+ ca_descr_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_SET_DESCR for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_descr_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_SET_PID"
+role="subsection"><title>CA_SET_PID</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_SET_PID,
+ ca_pid_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_SET_PID for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_pid_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
 </section>
diff --git a/Documentation/DocBook/media/dvb/demux.xml b/Documentation/DocBook/media/dvb/demux.xml
index 37c1790..86de89c 100644
--- a/Documentation/DocBook/media/dvb/demux.xml
+++ b/Documentation/DocBook/media/dvb/demux.xml
@@ -899,4 +899,232 @@ typedef enum {
 <para>Invalid stc number.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
- </section></section>
+ </section>
+
+<section id="DMX_GET_PES_PIDS"
+role="subsection"><title>DMX_GET_PES_PIDS</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = DMX_GET_PES_PIDS,
+ __u16[5]);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_GET_PES_PIDS for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u16[5]
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="DMX_GET_CAPS"
+role="subsection"><title>DMX_GET_CAPS</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = DMX_GET_CAPS,
+ dmx_caps_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_GET_CAPS for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_caps_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="DMX_SET_SOURCE"
+role="subsection"><title>DMX_SET_SOURCE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = DMX_SET_SOURCE,
+ dmx_source_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_SET_SOURCE for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_source_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="DMX_ADD_PID"
+role="subsection"><title>DMX_ADD_PID</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = DMX_ADD_PID,
+ __u16 *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_ADD_PID for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u16 *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="DMX_REMOVE_PID"
+role="subsection"><title>DMX_REMOVE_PID</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = DMX_REMOVE_PID,
+ __u16 *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_REMOVE_PID for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u16 *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+
+</section>
diff --git a/Documentation/DocBook/media/dvb/dvbapi.xml b/Documentation/DocBook/media/dvb/dvbapi.xml
index 2ab6ddc..d36f8f9 100644
--- a/Documentation/DocBook/media/dvb/dvbapi.xml
+++ b/Documentation/DocBook/media/dvb/dvbapi.xml
@@ -28,7 +28,7 @@
 	<holder>Convergence GmbH</holder>
 </copyright>
 <copyright>
-	<year>2009-2011</year>
+	<year>2009-2012</year>
 	<holder>Mauro Carvalho Chehab</holder>
 </copyright>
 
diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml
index e633c09..d188be9 100644
--- a/Documentation/DocBook/media/dvb/dvbproperty.xml
+++ b/Documentation/DocBook/media/dvb/dvbproperty.xml
@@ -194,6 +194,7 @@ get/set up to 64 properties. The actual meaning of each property is described on
 	APSK_16,
 	APSK_32,
 	DQPSK,
+	QAM_4_NR,
  } fe_modulation_t;
 </programlisting>
 	</section>
@@ -265,6 +266,7 @@ typedef enum fe_code_rate {
 	FEC_AUTO,
 	FEC_3_5,
 	FEC_9_10,
+	FEC_2_5,
 } fe_code_rate_t;
 	</programlisting>
 	<para>which correspond to error correction rates of 1/2, 2/3, etc.,
@@ -351,7 +353,7 @@ typedef enum fe_delivery_system {
 	SYS_ISDBC,
 	SYS_ATSC,
 	SYS_ATSCMH,
-	SYS_DMBTH,
+	SYS_DTMB,
 	SYS_CMMB,
 	SYS_DAB,
 	SYS_DVBT2,
@@ -567,28 +569,33 @@ typedef enum fe_delivery_system {
 			<title><constant>DTV_ATSCMH_RS_FRAME_MODE</constant></title>
 			<para>RS frame mode.</para>
 			<para>Possible values are:</para>
+		  <para id="atscmh-rs-frame-mode">
 <programlisting>
 typedef enum atscmh_rs_frame_mode {
 	ATSCMH_RSFRAME_PRI_ONLY  = 0,
 	ATSCMH_RSFRAME_PRI_SEC   = 1,
 } atscmh_rs_frame_mode_t;
 </programlisting>
+		  </para>
 		</section>
 		<section id="DTV-ATSCMH-RS-FRAME-ENSEMBLE">
 			<title><constant>DTV_ATSCMH_RS_FRAME_ENSEMBLE</constant></title>
 			<para>RS frame ensemble.</para>
 			<para>Possible values are:</para>
+		  <para id="atscmh-rs-frame-ensemble">
 <programlisting>
 typedef enum atscmh_rs_frame_ensemble {
 	ATSCMH_RSFRAME_ENS_PRI   = 0,
 	ATSCMH_RSFRAME_ENS_SEC   = 1,
 } atscmh_rs_frame_ensemble_t;
 </programlisting>
+		  </para>
 		</section>
 		<section id="DTV-ATSCMH-RS-CODE-MODE-PRI">
 			<title><constant>DTV_ATSCMH_RS_CODE_MODE_PRI</constant></title>
 			<para>RS code mode (primary).</para>
 			<para>Possible values are:</para>
+		  <para id="atscmh-rs-code-mode">
 <programlisting>
 typedef enum atscmh_rs_code_mode {
 	ATSCMH_RSCODE_211_187    = 0,
@@ -596,6 +603,7 @@ typedef enum atscmh_rs_code_mode {
 	ATSCMH_RSCODE_235_187    = 2,
 } atscmh_rs_code_mode_t;
 </programlisting>
+		  </para>
 		</section>
 		<section id="DTV-ATSCMH-RS-CODE-MODE-SEC">
 			<title><constant>DTV_ATSCMH_RS_CODE_MODE_SEC</constant></title>
@@ -613,23 +621,27 @@ typedef enum atscmh_rs_code_mode {
 			<title><constant>DTV_ATSCMH_SCCC_BLOCK_MODE</constant></title>
 			<para>Series Concatenated Convolutional Code Block Mode.</para>
 			<para>Possible values are:</para>
+		  <para id="atscmh-sccc-block-mode">
 <programlisting>
 typedef enum atscmh_sccc_block_mode {
 	ATSCMH_SCCC_BLK_SEP      = 0,
 	ATSCMH_SCCC_BLK_COMB     = 1,
 } atscmh_sccc_block_mode_t;
 </programlisting>
+		  </para>
 		</section>
 		<section id="DTV-ATSCMH-SCCC-CODE-MODE-A">
 			<title><constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant></title>
 			<para>Series Concatenated Convolutional Code Rate.</para>
 			<para>Possible values are:</para>
+		  <para id="atscmh-sccc-code-mode">
 <programlisting>
 typedef enum atscmh_sccc_code_mode {
 	ATSCMH_SCCC_CODE_HLF     = 0,
 	ATSCMH_SCCC_CODE_QTR     = 1,
 } atscmh_sccc_code_mode_t;
 </programlisting>
+		  </para>
 		</section>
 		<section id="DTV-ATSCMH-SCCC-CODE-MODE-B">
 			<title><constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant></title>
@@ -725,6 +737,9 @@ typedef enum fe_guard_interval {
 	GUARD_INTERVAL_1_128,
 	GUARD_INTERVAL_19_128,
 	GUARD_INTERVAL_19_256,
+	GUARD_INTERVAL_PN420,
+	GUARD_INTERVAL_PN595,
+	GUARD_INTERVAL_PN945,
 } fe_guard_interval_t;
 </programlisting>
 
@@ -733,6 +748,7 @@ typedef enum fe_guard_interval {
 			try to find the correct guard interval (if capable) and will use TMCC to fill
 			in the missing parameters.</para>
 		<para>2) Intervals 1/128, 19/128 and 19/256 are used only for DVB-T2 at present</para>
+		<para>3) DTMB specifies PN420, PN595 and PN945.</para>
 	</section>
 	<section id="DTV-TRANSMISSION-MODE">
 		<title><constant>DTV_TRANSMISSION_MODE</constant></title>
@@ -749,6 +765,8 @@ typedef enum fe_transmit_mode {
 	TRANSMISSION_MODE_1K,
 	TRANSMISSION_MODE_16K,
 	TRANSMISSION_MODE_32K,
+	TRANSMISSION_MODE_C1,
+	TRANSMISSION_MODE_C3780,
 } fe_transmit_mode_t;
 </programlisting>
 		<para>Notes:</para>
@@ -760,6 +778,7 @@ typedef enum fe_transmit_mode {
 			use TMCC to fill in the missing parameters.</para>
 		<para>3) DVB-T specifies 2K and 8K as valid sizes.</para>
 		<para>4) DVB-T2 specifies 1K, 2K, 4K, 8K, 16K and 32K.</para>
+		<para>5) DTMB specifies C1 and C3780.</para>
 	</section>
 	<section id="DTV-HIERARCHY">
 	<title><constant>DTV_HIERARCHY</constant></title>
@@ -784,7 +803,7 @@ typedef enum fe_hierarchy {
 			many data types via a single multiplex. The API will soon support this
 			at which point this section will be expanded.</para>
 	</section>
-	<section id="DTV_ENUM_DELSYS">
+	<section id="DTV-ENUM-DELSYS">
 		<title><constant>DTV_ENUM_DELSYS</constant></title>
 		<para>A Multi standard frontend needs to advertise the delivery systems provided.
 			Applications need to enumerate the provided delivery systems, before using
@@ -796,6 +815,18 @@ typedef enum fe_hierarchy {
 			FE_GET_INFO. In the case of a legacy frontend, the result is just the same
 			as with FE_GET_INFO, but in a more structured format </para>
 	</section>
+	<section id="DTV-INTERLEAVING">
+	<title><constant>DTV_INTERLEAVING</constant></title>
+	<para id="fe-interleaving">Interleaving mode</para>
+	<programlisting>
+enum fe_interleaving {
+	INTERLEAVING_NONE,
+	INTERLEAVING_AUTO,
+	INTERLEAVING_240,
+	INTERLEAVING_720,
+};
+	</programlisting>
+	</section>
 </section>
 	<section id="frontend-property-terrestrial-systems">
 	<title>Properties used on terrestrial delivery systems</title>
@@ -925,13 +956,31 @@ typedef enum fe_hierarchy {
 				<listitem><para><link linkend="DTV-ATSCMH-PRC"><constant>DTV_ATSCMH_PRC</constant></link></para></listitem>
 				<listitem><para><link linkend="DTV-ATSCMH-RS-FRAME-MODE"><constant>DTV_ATSCMH_RS_FRAME_MODE</constant></link></para></listitem>
 				<listitem><para><link linkend="DTV-ATSCMH-RS-FRAME-ENSEMBLE"><constant>DTV_ATSCMH_RS_FRAME_ENSEMBLE</constant></link></para></listitem>
-				<listitem><para><link linkend="DTV-ATSCMH-CODE-MODE-PRI"><constant>DTV_ATSCMH_CODE_MODE_PRI</constant></link></para></listitem>
-				<listitem><para><link linkend="DTV-ATSCMH-CODE-MODE-SEC"><constant>DTV_ATSCMH_CODE_MODE_SEC</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-RS-CODE-MODE-PRI"><constant>DTV_ATSCMH_RS_CODE_MODE_PRI</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-RS-CODE-MODE-SEC"><constant>DTV_ATSCMH_RS_CODE_MODE_SEC</constant></link></para></listitem>
 				<listitem><para><link linkend="DTV-ATSCMH-SCCC-BLOCK-MODE"><constant>DTV_ATSCMH_SCCC_BLOCK_MODE</constant></link></para></listitem>
-				<listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-A"><constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant></link></para></listitem>
-				<listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-B"><constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant></link></para></listitem>
-				<listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-C"><constant>DTV_ATSCMH_SCCC_CODE_MODE_C</constant></link></para></listitem>
-				<listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-D"><constant>DTV_ATSCMH_SCCC_CODE_MODE_D</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-A"><constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-B"><constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-C"><constant>DTV_ATSCMH_SCCC_CODE_MODE_C</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-D"><constant>DTV_ATSCMH_SCCC_CODE_MODE_D</constant></link></para></listitem>
+			</itemizedlist>
+		</section>
+		<section id="dtmb-params">
+			<title>DTMB delivery system</title>
+			<para>The following parameters are valid for DTMB:</para>
+			<itemizedlist mark='opencircle'>
+				<listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-GUARD-INTERVAL"><constant>DTV_GUARD_INTERVAL</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-TRANSMISSION-MODE"><constant>DTV_TRANSMISSION_MODE</constant></link></para></listitem>
+				<listitem><para><link linkend="DTV-INTERLEAVING"><constant>DTV_INTERLEAVING</constant></link></para></listitem>
 			</itemizedlist>
 		</section>
 	</section>
diff --git a/Documentation/DocBook/media/dvb/frontend.xml b/Documentation/DocBook/media/dvb/frontend.xml
index aeaed59..950bdfb 100644
--- a/Documentation/DocBook/media/dvb/frontend.xml
+++ b/Documentation/DocBook/media/dvb/frontend.xml
@@ -66,7 +66,7 @@ supported via the new <link linkend="FE_GET_SET_PROPERTY">FE_GET_PROPERTY/FE_GET
 
 <para>The usage of this field is deprecated, as it doesn't report all supported standards, and
 will provide an incomplete information for frontends that support multiple delivery systems.
-Please use <link linkend="DTV_ENUM_DELSYS">DTV_ENUM_DELSYS</link> instead.</para>
+Please use <link linkend="DTV-ENUM-DELSYS">DTV_ENUM_DELSYS</link> instead.</para>
 </section>
 
 <section id="fe-caps-t">
@@ -207,18 +207,44 @@ spec.</para>
 <para>Several functions of the frontend device use the fe_status data type defined
 by</para>
 <programlisting>
- typedef enum fe_status {
-	 FE_HAS_SIGNAL     = 0x01,   /&#x22C6;  found something above the noise level &#x22C6;/
-	 FE_HAS_CARRIER    = 0x02,   /&#x22C6;  found a DVB signal  &#x22C6;/
-	 FE_HAS_VITERBI    = 0x04,   /&#x22C6;  FEC is stable  &#x22C6;/
-	 FE_HAS_SYNC       = 0x08,   /&#x22C6;  found sync bytes  &#x22C6;/
-	 FE_HAS_LOCK       = 0x10,   /&#x22C6;  everything's working... &#x22C6;/
-	 FE_TIMEDOUT       = 0x20,   /&#x22C6;  no lock within the last ~2 seconds &#x22C6;/
-	 FE_REINIT         = 0x40    /&#x22C6;  frontend was reinitialized,  &#x22C6;/
- } fe_status_t;                      /&#x22C6;  application is recommned to reset &#x22C6;/
+typedef enum fe_status {
+	FE_HAS_SIGNAL		= 0x01,
+	FE_HAS_CARRIER		= 0x02,
+	FE_HAS_VITERBI		= 0x04,
+	FE_HAS_SYNC		= 0x08,
+	FE_HAS_LOCK		= 0x10,
+	FE_TIMEDOUT		= 0x20,
+	FE_REINIT		= 0x40,
+} fe_status_t;
 </programlisting>
-<para>to indicate the current state and/or state changes of the frontend hardware.
-</para>
+<para>to indicate the current state and/or state changes of the frontend hardware:
+</para>
+
+<informaltable><tgroup cols="2"><tbody>
+<row>
+<entry align="char">FE_HAS_SIGNAL</entry>
+<entry align="char">The frontend has found something above the noise level</entry>
+</row><row>
+<entry align="char">FE_HAS_CARRIER</entry>
+<entry align="char">The frontend has found a DVB signal</entry>
+</row><row>
+<entry align="char">FE_HAS_VITERBI</entry>
+<entry align="char">The frontend FEC code is stable</entry>
+</row><row>
+<entry align="char">FE_HAS_SYNC</entry>
+<entry align="char">Syncronization bytes was found</entry>
+</row><row>
+<entry align="char">FE_HAS_LOCK</entry>
+<entry align="char">The DVB were locked and everything is working</entry>
+</row><row>
+<entry align="char">FE_TIMEDOUT</entry>
+<entry align="char">no lock within the last about 2 seconds</entry>
+</row><row>
+<entry align="char">FE_REINIT</entry>
+<entry align="char">The frontend was reinitialized, application is
+recommended to reset DiSEqC, tone and parameters</entry>
+</row>
+</tbody></tgroup></informaltable>
 
 </section>
 
@@ -238,7 +264,7 @@ and to add newer delivery systems.</para>
 <constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant></link> instead, in
 order to be able to support the newer System Delivery like  DVB-S2, DVB-T2,
 DVB-C2, ISDB, etc.</para>
-<para>All kinds of parameters are combined as an union in the FrontendParameters structure:</para>
+<para>All kinds of parameters are combined as an union in the FrontendParameters structure:
 <programlisting>
 struct dvb_frontend_parameters {
 	uint32_t frequency;     /&#x22C6; (absolute) frequency in Hz for QAM/OFDM &#x22C6;/
@@ -251,12 +277,13 @@ struct dvb_frontend_parameters {
 		struct dvb_vsb_parameters  vsb;
 	} u;
 };
-</programlisting>
+</programlisting></para>
 <para>In the case of QPSK frontends the <constant>frequency</constant> field specifies the intermediate
 frequency, i.e. the offset which is effectively added to the local oscillator frequency (LOF) of
 the LNB. The intermediate frequency has to be specified in units of kHz. For QAM and
 OFDM frontends the <constant>frequency</constant> specifies the absolute frequency and is given in Hz.
 </para>
+
 <section id="dvb-qpsk-parameters">
 <title>QPSK parameters</title>
 <para>For satellite QPSK frontends you have to use the <constant>dvb_qpsk_parameters</constant> structure:</para>
@@ -321,8 +348,8 @@ itself.
 <section id="fe-code-rate-t">
 <title>frontend code rate</title>
 <para>The possible values for the <constant>fec_inner</constant> field used on
-<link refend="dvb-qpsk-parameters"><constant>struct dvb_qpsk_parameters</constant></link> and
-<link refend="dvb-qam-parameters"><constant>struct dvb_qam_parameters</constant></link> are:
+<link linkend="dvb-qpsk-parameters"><constant>struct dvb_qpsk_parameters</constant></link> and
+<link linkend="dvb-qam-parameters"><constant>struct dvb_qam_parameters</constant></link> are:
 </para>
 <programlisting>
 typedef enum fe_code_rate {
@@ -347,9 +374,9 @@ detection.
 <section id="fe-modulation-t">
 <title>frontend modulation type for QAM, OFDM and VSB</title>
 <para>For cable and terrestrial frontends, e. g. for
-<link refend="dvb-qam-parameters"><constant>struct dvb_qpsk_parameters</constant></link>,
-<link refend="dvb-ofdm-parameters"><constant>struct dvb_qam_parameters</constant></link> and
-<link refend="dvb-vsb-parameters"><constant>struct dvb_qam_parameters</constant></link>,
+<link linkend="dvb-qam-parameters"><constant>struct dvb_qpsk_parameters</constant></link>,
+<link linkend="dvb-ofdm-parameters"><constant>struct dvb_qam_parameters</constant></link> and
+<link linkend="dvb-vsb-parameters"><constant>struct dvb_qam_parameters</constant></link>,
 it needs to specify the quadrature modulation mode which can be one of the following:
 </para>
 <programlisting>
@@ -370,8 +397,8 @@ it needs to specify the quadrature modulation mode which can be one of the follo
  } fe_modulation_t;
 </programlisting>
 </section>
-<para>Finally, there are several more parameters for OFDM:
-</para>
+<section>
+<title>More OFDM parameters</title>
 <section id="fe-transmit-mode-t">
 <title>Number of carriers per channel</title>
 <programlisting>
@@ -427,6 +454,7 @@ typedef enum fe_hierarchy {
  } fe_hierarchy_t;
 </programlisting>
 </section>
+</section>
 
 </section>
 
diff --git a/Documentation/DocBook/media/dvb/kdapi.xml b/Documentation/DocBook/media/dvb/kdapi.xml
index 6c67481..6c11ec5 100644
--- a/Documentation/DocBook/media/dvb/kdapi.xml
+++ b/Documentation/DocBook/media/dvb/kdapi.xml
@@ -2,7 +2,7 @@
 <para>The kernel demux API defines a driver-internal interface for registering low-level,
 hardware specific driver to a hardware independent demux layer. It is only of interest for
 DVB device driver writers. The header file for this API is named <emphasis role="tt">demux.h</emphasis> and located in
-<emphasis role="tt">drivers/media/dvb/dvb-core</emphasis>.
+<emphasis role="tt">drivers/media/dvb-core</emphasis>.
 </para>
 <para>Maintainer note: This section must be reviewed. It is probably out of date.
 </para>
diff --git a/Documentation/DocBook/media/dvb/net.xml b/Documentation/DocBook/media/dvb/net.xml
index 67d37e5..a193e86 100644
--- a/Documentation/DocBook/media/dvb/net.xml
+++ b/Documentation/DocBook/media/dvb/net.xml
@@ -26,4 +26,131 @@ struct dvb_net_if {
 <title>DVB net Function Calls</title>
 <para>To be written&#x2026;
 </para>
+
+<section id="NET_ADD_IF"
+role="subsection"><title>NET_ADD_IF</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = NET_ADD_IF,
+ struct dvb_net_if *if);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals NET_ADD_IF for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct dvb_net_if *if
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="NET_REMOVE_IF"
+role="subsection"><title>NET_REMOVE_IF</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = NET_REMOVE_IF);
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals NET_REMOVE_IF for this command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="NET_GET_IF"
+role="subsection"><title>NET_GET_IF</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = NET_GET_IF,
+ struct dvb_net_if *if);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals NET_GET_IF for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct dvb_net_if *if
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
 </section>
diff --git a/Documentation/DocBook/media/dvb/video.xml b/Documentation/DocBook/media/dvb/video.xml
index 25fb823..3ea1ca7 100644
--- a/Documentation/DocBook/media/dvb/video.xml
+++ b/Documentation/DocBook/media/dvb/video.xml
@@ -15,6 +15,10 @@ the audio and video device as well as the video4linux device.
 <para>The ioctls that deal with SPUs (sub picture units) and navigation packets are only
 supported on some MPEG decoders made for DVD playback.
 </para>
+<para>
+These ioctls were also used by V4L2 to control MPEG decoders implemented in V4L2. The use
+of these ioctls for that purpose has been made obsolete and proper V4L2 ioctls or controls
+have been created to replace that functionality.</para>
 <section id="video_types">
 <title>Video Data Types</title>
 
@@ -55,7 +59,7 @@ typedef enum {
 </section>
 
 <section id="video-stream-source-t">
-<title>video stream source</title>
+<title>video_stream_source_t</title>
 <para>The video stream source is set through the VIDEO_SELECT_SOURCE call and can take
 the following values, depending on whether we are replaying from an internal (demuxer) or
 external (user write) source.
@@ -76,7 +80,7 @@ call.
 </section>
 
 <section id="video-play-state-t">
-<title>video play state</title>
+<title>video_play_state_t</title>
 <para>The following values can be returned by the VIDEO_GET_STATUS call representing the
 state of video playback.
 </para>
@@ -90,9 +94,9 @@ typedef enum {
 </section>
 
 <section id="video-command">
+<title>struct video_command</title>
 <para>The structure must be zeroed before use by the application
 This ensures it can be extended safely in the future.</para>
-<title>struct video-command</title>
 <programlisting>
 struct video_command {
 	__u32 cmd;
@@ -121,7 +125,7 @@ struct video_command {
 </section>
 
 <section id="video-size-t">
-<title>struct video_size-t</title>
+<title>video_size_t</title>
 <programlisting>
 typedef struct {
 	int w;
@@ -217,7 +221,7 @@ bits set according to the hardwares capabilities.
 </section>
 
 <section id="video-system">
-<title>video system</title>
+<title>video_system_t</title>
 <para>A call to VIDEO_SET_SYSTEM sets the desired video system for TV output. The
 following system types can be set:
 </para>
@@ -263,7 +267,7 @@ call expects the following format for that information:
 
 </section>
 <section id="video-spu">
-<title>video SPU</title>
+<title>struct video_spu</title>
 <para>Calling VIDEO_SET_SPU deactivates or activates SPU decoding, according to the
 following format:
 </para>
@@ -277,12 +281,12 @@ following format:
 
 </section>
 <section id="video-spu-palette">
-<title>video SPU palette</title>
+<title>struct video_spu_palette</title>
 <para>The following structure is used to set the SPU palette by calling VIDEO_SPU_PALETTE:
 </para>
 <programlisting>
  typedef
- struct video_spu_palette{
+ struct video_spu_palette {
 	 int length;
 	 uint8_t &#x22C6;palette;
  } video_spu_palette_t;
@@ -290,13 +294,13 @@ following format:
 
 </section>
 <section id="video-navi-pack">
-<title>video NAVI pack</title>
+<title>struct video_navi_pack</title>
 <para>In order to get the navigational data the following structure has to be passed to the ioctl
 VIDEO_GET_NAVI:
 </para>
 <programlisting>
  typedef
- struct video_navi_pack{
+ struct video_navi_pack {
 	 int length;         /&#x22C6; 0 ... 1024 &#x22C6;/
 	 uint8_t data[1024];
  } video_navi_pack_t;
@@ -305,7 +309,7 @@ VIDEO_GET_NAVI:
 
 
 <section id="video-attributes-t">
-<title>video attributes</title>
+<title>video_attributes_t</title>
 <para>The following attributes can be set by a call to VIDEO_SET_ATTRIBUTES:
 </para>
 <programlisting>
@@ -541,6 +545,8 @@ VIDEO_GET_NAVI:
 role="subsection"><title>VIDEO_STOP</title>
 <para>DESCRIPTION
 </para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+&VIDIOC-DECODER-CMD; instead.</para>
 <informaltable><tgroup cols="1"><tbody><row><entry
  align="char">
 <para>This ioctl call asks the Video Device to stop playing the current stream.
@@ -598,6 +604,8 @@ role="subsection"><title>VIDEO_STOP</title>
 role="subsection"><title>VIDEO_PLAY</title>
 <para>DESCRIPTION
 </para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+&VIDIOC-DECODER-CMD; instead.</para>
 <informaltable><tgroup cols="1"><tbody><row><entry
  align="char">
 <para>This ioctl call asks the Video Device to start playing a video stream from the
@@ -634,6 +642,8 @@ role="subsection"><title>VIDEO_PLAY</title>
 role="subsection"><title>VIDEO_FREEZE</title>
 <para>DESCRIPTION
 </para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+&VIDIOC-DECODER-CMD; instead.</para>
 <informaltable><tgroup cols="1"><tbody><row><entry
  align="char">
 <para>This ioctl call suspends the live video stream being played. Decoding
@@ -674,6 +684,8 @@ role="subsection"><title>VIDEO_FREEZE</title>
 role="subsection"><title>VIDEO_CONTINUE</title>
 <para>DESCRIPTION
 </para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+&VIDIOC-DECODER-CMD; instead.</para>
 <informaltable><tgroup cols="1"><tbody><row><entry
  align="char">
 <para>This ioctl call restarts decoding and playing processes of the video stream
@@ -710,6 +722,9 @@ role="subsection"><title>VIDEO_CONTINUE</title>
 role="subsection"><title>VIDEO_SELECT_SOURCE</title>
 <para>DESCRIPTION
 </para>
+<para>This ioctl is for DVB devices only. This ioctl was also supported by the
+V4L2 ivtv driver, but that has been replaced by the ivtv-specific
+<constant>IVTV_IOC_PASSTHROUGH_MODE</constant> ioctl.</para>
 <informaltable><tgroup cols="1"><tbody><row><entry
  align="char">
 <para>This ioctl call informs the video device which source shall be used for the input
@@ -845,10 +860,160 @@ role="subsection"><title>VIDEO_GET_STATUS</title>
  </row></tbody></tgroup></informaltable>
 &return-value-dvb;
 
+</section><section id="VIDEO_GET_FRAME_COUNT"
+role="subsection"><title>VIDEO_GET_FRAME_COUNT</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this
+ioctl has been replaced by the <constant>V4L2_CID_MPEG_VIDEO_DEC_FRAME</constant> control.</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Video Device to return the number of displayed frames
+since the decoder was started.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_GET_FRAME_COUNT, __u64 *pts);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_GET_FRAME_COUNT for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u64 *pts
+</para>
+</entry><entry
+ align="char">
+<para>Returns the number of frames displayed since the decoder was started.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_GET_PTS"
+role="subsection"><title>VIDEO_GET_PTS</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this
+ioctl has been replaced by the <constant>V4L2_CID_MPEG_VIDEO_DEC_PTS</constant> control.</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Video Device to return the current PTS timestamp.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_GET_PTS, __u64 *pts);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_GET_PTS for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u64 *pts
+</para>
+</entry><entry
+ align="char">
+<para>Returns the 33-bit timestamp as defined in ITU T-REC-H.222.0 / ISO/IEC 13818-1.
+</para>
+<para>
+The PTS should belong to the currently played
+frame if possible, but may also be a value close to it
+like the PTS of the last decoded frame or the last PTS
+extracted by the PES parser.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_GET_FRAME_RATE"
+role="subsection"><title>VIDEO_GET_FRAME_RATE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Video Device to return the current framerate.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_GET_FRAME_RATE, unsigned int *rate);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_GET_FRAME_RATE for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>unsigned int *rate
+</para>
+</entry><entry
+ align="char">
+<para>Returns the framerate in number of frames per 1000 seconds.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
 </section><section id="VIDEO_GET_EVENT"
 role="subsection"><title>VIDEO_GET_EVENT</title>
 <para>DESCRIPTION
 </para>
+<para>This ioctl is for DVB devices only. To get events from a V4L2 decoder use the V4L2
+&VIDIOC-DQEVENT; ioctl instead.</para>
 <informaltable><tgroup cols="1"><tbody><row><entry
  align="char">
 <para>This ioctl call returns an event of type video_event if available. If an event is
@@ -914,6 +1079,152 @@ role="subsection"><title>VIDEO_GET_EVENT</title>
 </entry>
  </row></tbody></tgroup></informaltable>
 
+</section><section id="VIDEO_COMMAND"
+role="subsection"><title>VIDEO_COMMAND</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this
+ioctl has been replaced by the &VIDIOC-DECODER-CMD; ioctl.</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl commands the decoder. The <constant>video_command</constant> struct
+is a subset of the <constant>v4l2_decoder_cmd</constant> struct, so refer to the
+&VIDIOC-DECODER-CMD; documentation for more information.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_COMMAND, struct video_command *cmd);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_COMMAND for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct video_command *cmd
+</para>
+</entry><entry
+ align="char">
+<para>Commands the decoder.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_TRY_COMMAND"
+role="subsection"><title>VIDEO_TRY_COMMAND</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this
+ioctl has been replaced by the &VIDIOC-TRY-DECODER-CMD; ioctl.</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl tries a decoder command. The <constant>video_command</constant> struct
+is a subset of the <constant>v4l2_decoder_cmd</constant> struct, so refer to the
+&VIDIOC-TRY-DECODER-CMD; documentation for more information.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_TRY_COMMAND, struct video_command *cmd);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_TRY_COMMAND for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct video_command *cmd
+</para>
+</entry><entry
+ align="char">
+<para>Try a decoder command.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_GET_SIZE"
+role="subsection"><title>VIDEO_GET_SIZE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl returns the size and aspect ratio.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_GET_SIZE, video_size_t *size);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_GET_SIZE for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>video_size_t *size
+</para>
+</entry><entry
+ align="char">
+<para>Returns the size and aspect ratio.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
 </section><section id="VIDEO_SET_DISPLAY_FORMAT"
 role="subsection"><title>VIDEO_SET_DISPLAY_FORMAT</title>
 <para>DESCRIPTION
diff --git a/Documentation/DocBook/media/v4l/biblio.xml b/Documentation/DocBook/media/v4l/biblio.xml
index 1078e45..18b6fc9 100644
--- a/Documentation/DocBook/media/v4l/biblio.xml
+++ b/Documentation/DocBook/media/v4l/biblio.xml
@@ -178,23 +178,23 @@ Signal - NTSC for Studio Applications"</title>
 1125-Line High-Definition Production"</title>
     </biblioentry>
 
-    <biblioentry id="en50067">
-      <abbrev>EN&nbsp;50067</abbrev>
+    <biblioentry id="iec62106">
+      <abbrev>IEC&nbsp;62106</abbrev>
       <authorgroup>
-	<corpauthor>European Committee for Electrotechnical Standardization
-(<ulink url="http://www.cenelec.eu">http://www.cenelec.eu</ulink>)</corpauthor>
+	<corpauthor>International Electrotechnical Commission
+(<ulink url="http://www.iec.ch">http://www.iec.ch</ulink>)</corpauthor>
       </authorgroup>
       <title>Specification of the radio data system (RDS) for VHF/FM sound broadcasting
 in the frequency range from 87,5 to 108,0 MHz</title>
     </biblioentry>
 
     <biblioentry id="nrsc4">
-      <abbrev>NRSC-4</abbrev>
+      <abbrev>NRSC-4-B</abbrev>
       <authorgroup>
 	<corpauthor>National Radio Systems Committee
 (<ulink url="http://www.nrscstandards.org">http://www.nrscstandards.org</ulink>)</corpauthor>
       </authorgroup>
-      <title>NRSC-4: United States RBDS Standard</title>
+      <title>NRSC-4-B: United States RBDS Standard</title>
     </biblioentry>
 
     <biblioentry id="iso12232">
diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml
index faa0fd1..98e8d08 100644
--- a/Documentation/DocBook/media/v4l/compat.xml
+++ b/Documentation/DocBook/media/v4l/compat.xml
@@ -2468,21 +2468,9 @@ that used it. It was originally scheduled for removal in 2.6.35.
 	  <structfield>reserved2</structfield> and removed
 	  <constant>V4L2_BUF_FLAG_INPUT</constant>.</para>
 	</listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 3.6</title>
-      <orderedlist>
         <listitem>
 	  <para>Added V4L2_CAP_VIDEO_M2M and V4L2_CAP_VIDEO_M2M_MPLANE capabilities.</para>
         </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 3.6</title>
-      <orderedlist>
         <listitem>
 	  <para>Added support for frequency band enumerations: &VIDIOC-ENUM-FREQ-BANDS;.</para>
         </listitem>
@@ -2615,10 +2603,6 @@ ioctls.</para>
 	  and &VIDIOC-SUBDEV-S-SELECTION; ioctls.</para>
         </listitem>
         <listitem>
-	  <para><link linkend="v4l2-auto-focus-area"><constant>
-	  V4L2_CID_AUTO_FOCUS_AREA</constant></link> control.</para>
-        </listitem>
-        <listitem>
 	  <para>Support for frequency band enumeration: &VIDIOC-ENUM-FREQ-BANDS; ioctl.</para>
         </listitem>
       </itemizedlist>
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index b0964fb..93b9c68 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -3505,7 +3505,7 @@ This encodes up to 31 pre-defined programme types.</entry>
 	  </row>
 	  <row><entry spanname="descr">Sets the Programme Service name (PS_NAME) for transmission.
 It is intended for static display on a receiver. It is the primary aid to listeners in programme service
-identification and selection.  In Annex E of <xref linkend="en50067" />, the RDS specification,
+identification and selection.  In Annex E of <xref linkend="iec62106" />, the RDS specification,
 there is a full description of the correct character encoding for Programme Service name strings.
 Also from RDS specification, PS is usually a single eight character text. However, it is also possible
 to find receivers which can scroll strings sized as 8 x N characters. So, this control must be configured
@@ -3519,7 +3519,7 @@ with steps of 8 characters. The result is it must always contain a string with s
 what is being broadcasted. RDS Radio Text can be applied when broadcaster wishes to transmit longer PS names,
 programme-related information or any other text. In these cases, RadioText should be used in addition to
 <constant>V4L2_CID_RDS_TX_PS_NAME</constant>. The encoding for Radio Text strings is also fully described
-in Annex E of <xref linkend="en50067" />. The length of Radio Text strings depends on which RDS Block is being
+in Annex E of <xref linkend="iec62106" />. The length of Radio Text strings depends on which RDS Block is being
 used to transmit it, either 32 (2A block) or 64 (2B block).  However, it is also possible
 to find receivers which can scroll strings sized as 32 x N or 64 x N characters. So, this control must be configured
 with steps of 32 or 64 characters. The result is it must always contain a string with size multiple of 32 or 64. </entry>
@@ -3650,7 +3650,7 @@ manually or automatically if set to zero. Unit, range and step are driver-specif
       </table>
 
 <para>For more details about RDS specification, refer to
-<xref linkend="en50067" /> document, from CENELEC.</para>
+<xref linkend="iec62106" /> document, from CENELEC.</para>
     </section>
 
     <section id="flash-controls">
@@ -3717,232 +3717,231 @@ interface and may change in the future.</para>
 	    use case involving camera or individually.
 	  </para>
 
-	</section>
 
+          <table pgwide="1" frame="none" id="flash-control-id">
+          <title>Flash Control IDs</title>
+    
+          <tgroup cols="4">
+    	<colspec colname="c1" colwidth="1*" />
+    	<colspec colname="c2" colwidth="6*" />
+    	<colspec colname="c3" colwidth="2*" />
+    	<colspec colname="c4" colwidth="6*" />
+    	<spanspec namest="c1" nameend="c2" spanname="id" />
+    	<spanspec namest="c2" nameend="c4" spanname="descr" />
+    	<thead>
+    	  <row>
+    	    <entry spanname="id" align="left">ID</entry>
+    	    <entry align="left">Type</entry>
+    	  </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+    	  </row>
+    	</thead>
+    	<tbody valign="top">
+    	  <row><entry></entry></row>
+    	  <row>
+    	    <entry spanname="id"><constant>V4L2_CID_FLASH_CLASS</constant></entry>
+    	    <entry>class</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="descr">The FLASH class descriptor.</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="id"><constant>V4L2_CID_FLASH_LED_MODE</constant></entry>
+    	    <entry>menu</entry>
+    	  </row>
+    	  <row id="v4l2-flash-led-mode">
+    	    <entry spanname="descr">Defines the mode of the flash LED,
+    	    the high-power white LED attached to the flash controller.
+    	    Setting this control may not be possible in presence of
+    	    some faults. See V4L2_CID_FLASH_FAULT.</entry>
+    	  </row>
+    	  <row>
+    	    <entrytbl spanname="descr" cols="2">
+    	      <tbody valign="top">
+    		<row>
+    		  <entry><constant>V4L2_FLASH_LED_MODE_NONE</constant></entry>
+    		  <entry>Off.</entry>
+    		</row>
+    		<row>
+    		  <entry><constant>V4L2_FLASH_LED_MODE_FLASH</constant></entry>
+    		  <entry>Flash mode.</entry>
+    		</row>
+    		<row>
+    		  <entry><constant>V4L2_FLASH_LED_MODE_TORCH</constant></entry>
+    		  <entry>Torch mode. See V4L2_CID_FLASH_TORCH_INTENSITY.</entry>
+    		</row>
+    	      </tbody>
+    	    </entrytbl>
+    	  </row>
+    	  <row>
+    	    <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_SOURCE</constant></entry>
+    	    <entry>menu</entry>
+    	  </row>
+    	  <row id="v4l2-flash-strobe-source"><entry
+    	  spanname="descr">Defines the source of the flash LED
+    	  strobe.</entry>
+    	  </row>
+    	  <row>
+    	    <entrytbl spanname="descr" cols="2">
+    	      <tbody valign="top">
+    		<row>
+    		  <entry><constant>V4L2_FLASH_STROBE_SOURCE_SOFTWARE</constant></entry>
+    		  <entry>The flash strobe is triggered by using
+    		  the V4L2_CID_FLASH_STROBE control.</entry>
+    		</row>
+    		<row>
+    		  <entry><constant>V4L2_FLASH_STROBE_SOURCE_EXTERNAL</constant></entry>
+    		  <entry>The flash strobe is triggered by an
+    		  external source. Typically this is a sensor,
+    		  which makes it possible to synchronises the
+    		  flash strobe start to exposure start.</entry>
+    		</row>
+    	      </tbody>
+    	    </entrytbl>
+    	  </row>
+    	  <row>
+    	    <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE</constant></entry>
+    	    <entry>button</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="descr">Strobe flash. Valid when
+    	    V4L2_CID_FLASH_LED_MODE is set to
+    	    V4L2_FLASH_LED_MODE_FLASH and V4L2_CID_FLASH_STROBE_SOURCE
+    	    is set to V4L2_FLASH_STROBE_SOURCE_SOFTWARE. Setting this
+    	    control may not be possible in presence of some faults.
+    	    See V4L2_CID_FLASH_FAULT.</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_STOP</constant></entry>
+    	    <entry>button</entry>
+    	  </row>
+    	  <row><entry spanname="descr">Stop flash strobe immediately.</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_STATUS</constant></entry>
+    	    <entry>boolean</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="descr">Strobe status: whether the flash
+    	    is strobing at the moment or not. This is a read-only
+    	    control.</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="id"><constant>V4L2_CID_FLASH_TIMEOUT</constant></entry>
+    	    <entry>integer</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="descr">Hardware timeout for flash. The
+    	    flash strobe is stopped after this period of time has
+    	    passed from the start of the strobe.</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="id"><constant>V4L2_CID_FLASH_INTENSITY</constant></entry>
+    	    <entry>integer</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="descr">Intensity of the flash strobe when
+    	    the flash LED is in flash mode
+    	    (V4L2_FLASH_LED_MODE_FLASH). The unit should be milliamps
+    	    (mA) if possible.</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="id"><constant>V4L2_CID_FLASH_TORCH_INTENSITY</constant></entry>
+    	    <entry>integer</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="descr">Intensity of the flash LED in
+    	    torch mode (V4L2_FLASH_LED_MODE_TORCH). The unit should be
+    	    milliamps (mA) if possible. Setting this control may not
+    	    be possible in presence of some faults. See
+    	    V4L2_CID_FLASH_FAULT.</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="id"><constant>V4L2_CID_FLASH_INDICATOR_INTENSITY</constant></entry>
+    	    <entry>integer</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="descr">Intensity of the indicator LED.
+    	    The indicator LED may be fully independent of the flash
+    	    LED. The unit should be microamps (uA) if possible.</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="id"><constant>V4L2_CID_FLASH_FAULT</constant></entry>
+    	    <entry>bitmask</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="descr">Faults related to the flash. The
+    	    faults tell about specific problems in the flash chip
+    	    itself or the LEDs attached to it. Faults may prevent
+    	    further use of some of the flash controls. In particular,
+    	    V4L2_CID_FLASH_LED_MODE is set to V4L2_FLASH_LED_MODE_NONE
+    	    if the fault affects the flash LED. Exactly which faults
+    	    have such an effect is chip dependent. Reading the faults
+    	    resets the control and returns the chip to a usable state
+    	    if possible.</entry>
+    	  </row>
+    	  <row>
+    	    <entrytbl spanname="descr" cols="2">
+    	      <tbody valign="top">
+    		<row>
+    		  <entry><constant>V4L2_FLASH_FAULT_OVER_VOLTAGE</constant></entry>
+    		  <entry>Flash controller voltage to the flash LED
+    		  has exceeded the limit specific to the flash
+    		  controller.</entry>
+    		</row>
+    		<row>
+    		  <entry><constant>V4L2_FLASH_FAULT_TIMEOUT</constant></entry>
+    		  <entry>The flash strobe was still on when
+    		  the timeout set by the user ---
+    		  V4L2_CID_FLASH_TIMEOUT control --- has expired.
+    		  Not all flash controllers may set this in all
+    		  such conditions.</entry>
+    		</row>
+    		<row>
+    		  <entry><constant>V4L2_FLASH_FAULT_OVER_TEMPERATURE</constant></entry>
+    		  <entry>The flash controller has overheated.</entry>
+    		</row>
+    		<row>
+    		  <entry><constant>V4L2_FLASH_FAULT_SHORT_CIRCUIT</constant></entry>
+    		  <entry>The short circuit protection of the flash
+    		  controller has been triggered.</entry>
+    		</row>
+    		<row>
+    		  <entry><constant>V4L2_FLASH_FAULT_OVER_CURRENT</constant></entry>
+    		  <entry>Current in the LED power supply has exceeded the limit
+    		  specific to the flash controller.</entry>
+    		</row>
+    		<row>
+    		  <entry><constant>V4L2_FLASH_FAULT_INDICATOR</constant></entry>
+    		  <entry>The flash controller has detected a short or open
+    		  circuit condition on the indicator LED.</entry>
+    		</row>
+    	      </tbody>
+    	    </entrytbl>
+    	  </row>
+    	  <row>
+    	    <entry spanname="id"><constant>V4L2_CID_FLASH_CHARGE</constant></entry>
+    	    <entry>boolean</entry>
+    	  </row>
+    	  <row><entry spanname="descr">Enable or disable charging of the xenon
+    	  flash capacitor.</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="id"><constant>V4L2_CID_FLASH_READY</constant></entry>
+    	    <entry>boolean</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="descr">Is the flash ready to strobe?
+    	    Xenon flashes require their capacitors charged before
+    	    strobing. LED flashes often require a cooldown period
+    	    after strobe during which another strobe will not be
+    	    possible. This is a read-only control.</entry>
+    	  </row>
+    	  <row><entry></entry></row>
+    	</tbody>
+          </tgroup>
+          </table>
+	</section>
       </section>
-
-      <table pgwide="1" frame="none" id="flash-control-id">
-      <title>Flash Control IDs</title>
-
-      <tgroup cols="4">
-	<colspec colname="c1" colwidth="1*" />
-	<colspec colname="c2" colwidth="6*" />
-	<colspec colname="c3" colwidth="2*" />
-	<colspec colname="c4" colwidth="6*" />
-	<spanspec namest="c1" nameend="c2" spanname="id" />
-	<spanspec namest="c2" nameend="c4" spanname="descr" />
-	<thead>
-	  <row>
-	    <entry spanname="id" align="left">ID</entry>
-	    <entry align="left">Type</entry>
-	  </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
-	  </row>
-	</thead>
-	<tbody valign="top">
-	  <row><entry></entry></row>
-	  <row>
-	    <entry spanname="id"><constant>V4L2_CID_FLASH_CLASS</constant></entry>
-	    <entry>class</entry>
-	  </row>
-	  <row>
-	    <entry spanname="descr">The FLASH class descriptor.</entry>
-	  </row>
-	  <row>
-	    <entry spanname="id"><constant>V4L2_CID_FLASH_LED_MODE</constant></entry>
-	    <entry>menu</entry>
-	  </row>
-	  <row id="v4l2-flash-led-mode">
-	    <entry spanname="descr">Defines the mode of the flash LED,
-	    the high-power white LED attached to the flash controller.
-	    Setting this control may not be possible in presence of
-	    some faults. See V4L2_CID_FLASH_FAULT.</entry>
-	  </row>
-	  <row>
-	    <entrytbl spanname="descr" cols="2">
-	      <tbody valign="top">
-		<row>
-		  <entry><constant>V4L2_FLASH_LED_MODE_NONE</constant></entry>
-		  <entry>Off.</entry>
-		</row>
-		<row>
-		  <entry><constant>V4L2_FLASH_LED_MODE_FLASH</constant></entry>
-		  <entry>Flash mode.</entry>
-		</row>
-		<row>
-		  <entry><constant>V4L2_FLASH_LED_MODE_TORCH</constant></entry>
-		  <entry>Torch mode. See V4L2_CID_FLASH_TORCH_INTENSITY.</entry>
-		</row>
-	      </tbody>
-	    </entrytbl>
-	  </row>
-	  <row>
-	    <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_SOURCE</constant></entry>
-	    <entry>menu</entry>
-	  </row>
-	  <row id="v4l2-flash-strobe-source"><entry
-	  spanname="descr">Defines the source of the flash LED
-	  strobe.</entry>
-	  </row>
-	  <row>
-	    <entrytbl spanname="descr" cols="2">
-	      <tbody valign="top">
-		<row>
-		  <entry><constant>V4L2_FLASH_STROBE_SOURCE_SOFTWARE</constant></entry>
-		  <entry>The flash strobe is triggered by using
-		  the V4L2_CID_FLASH_STROBE control.</entry>
-		</row>
-		<row>
-		  <entry><constant>V4L2_FLASH_STROBE_SOURCE_EXTERNAL</constant></entry>
-		  <entry>The flash strobe is triggered by an
-		  external source. Typically this is a sensor,
-		  which makes it possible to synchronises the
-		  flash strobe start to exposure start.</entry>
-		</row>
-	      </tbody>
-	    </entrytbl>
-	  </row>
-	  <row>
-	    <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE</constant></entry>
-	    <entry>button</entry>
-	  </row>
-	  <row>
-	    <entry spanname="descr">Strobe flash. Valid when
-	    V4L2_CID_FLASH_LED_MODE is set to
-	    V4L2_FLASH_LED_MODE_FLASH and V4L2_CID_FLASH_STROBE_SOURCE
-	    is set to V4L2_FLASH_STROBE_SOURCE_SOFTWARE. Setting this
-	    control may not be possible in presence of some faults.
-	    See V4L2_CID_FLASH_FAULT.</entry>
-	  </row>
-	  <row>
-	    <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_STOP</constant></entry>
-	    <entry>button</entry>
-	  </row>
-	  <row><entry spanname="descr">Stop flash strobe immediately.</entry>
-	  </row>
-	  <row>
-	    <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_STATUS</constant></entry>
-	    <entry>boolean</entry>
-	  </row>
-	  <row>
-	    <entry spanname="descr">Strobe status: whether the flash
-	    is strobing at the moment or not. This is a read-only
-	    control.</entry>
-	  </row>
-	  <row>
-	    <entry spanname="id"><constant>V4L2_CID_FLASH_TIMEOUT</constant></entry>
-	    <entry>integer</entry>
-	  </row>
-	  <row>
-	    <entry spanname="descr">Hardware timeout for flash. The
-	    flash strobe is stopped after this period of time has
-	    passed from the start of the strobe.</entry>
-	  </row>
-	  <row>
-	    <entry spanname="id"><constant>V4L2_CID_FLASH_INTENSITY</constant></entry>
-	    <entry>integer</entry>
-	  </row>
-	  <row>
-	    <entry spanname="descr">Intensity of the flash strobe when
-	    the flash LED is in flash mode
-	    (V4L2_FLASH_LED_MODE_FLASH). The unit should be milliamps
-	    (mA) if possible.</entry>
-	  </row>
-	  <row>
-	    <entry spanname="id"><constant>V4L2_CID_FLASH_TORCH_INTENSITY</constant></entry>
-	    <entry>integer</entry>
-	  </row>
-	  <row>
-	    <entry spanname="descr">Intensity of the flash LED in
-	    torch mode (V4L2_FLASH_LED_MODE_TORCH). The unit should be
-	    milliamps (mA) if possible. Setting this control may not
-	    be possible in presence of some faults. See
-	    V4L2_CID_FLASH_FAULT.</entry>
-	  </row>
-	  <row>
-	    <entry spanname="id"><constant>V4L2_CID_FLASH_INDICATOR_INTENSITY</constant></entry>
-	    <entry>integer</entry>
-	  </row>
-	  <row>
-	    <entry spanname="descr">Intensity of the indicator LED.
-	    The indicator LED may be fully independent of the flash
-	    LED. The unit should be microamps (uA) if possible.</entry>
-	  </row>
-	  <row>
-	    <entry spanname="id"><constant>V4L2_CID_FLASH_FAULT</constant></entry>
-	    <entry>bitmask</entry>
-	  </row>
-	  <row>
-	    <entry spanname="descr">Faults related to the flash. The
-	    faults tell about specific problems in the flash chip
-	    itself or the LEDs attached to it. Faults may prevent
-	    further use of some of the flash controls. In particular,
-	    V4L2_CID_FLASH_LED_MODE is set to V4L2_FLASH_LED_MODE_NONE
-	    if the fault affects the flash LED. Exactly which faults
-	    have such an effect is chip dependent. Reading the faults
-	    resets the control and returns the chip to a usable state
-	    if possible.</entry>
-	  </row>
-	  <row>
-	    <entrytbl spanname="descr" cols="2">
-	      <tbody valign="top">
-		<row>
-		  <entry><constant>V4L2_FLASH_FAULT_OVER_VOLTAGE</constant></entry>
-		  <entry>Flash controller voltage to the flash LED
-		  has exceeded the limit specific to the flash
-		  controller.</entry>
-		</row>
-		<row>
-		  <entry><constant>V4L2_FLASH_FAULT_TIMEOUT</constant></entry>
-		  <entry>The flash strobe was still on when
-		  the timeout set by the user ---
-		  V4L2_CID_FLASH_TIMEOUT control --- has expired.
-		  Not all flash controllers may set this in all
-		  such conditions.</entry>
-		</row>
-		<row>
-		  <entry><constant>V4L2_FLASH_FAULT_OVER_TEMPERATURE</constant></entry>
-		  <entry>The flash controller has overheated.</entry>
-		</row>
-		<row>
-		  <entry><constant>V4L2_FLASH_FAULT_SHORT_CIRCUIT</constant></entry>
-		  <entry>The short circuit protection of the flash
-		  controller has been triggered.</entry>
-		</row>
-		<row>
-		  <entry><constant>V4L2_FLASH_FAULT_OVER_CURRENT</constant></entry>
-		  <entry>Current in the LED power supply has exceeded the limit
-		  specific to the flash controller.</entry>
-		</row>
-		<row>
-		  <entry><constant>V4L2_FLASH_FAULT_INDICATOR</constant></entry>
-		  <entry>The flash controller has detected a short or open
-		  circuit condition on the indicator LED.</entry>
-		</row>
-	      </tbody>
-	    </entrytbl>
-	  </row>
-	  <row>
-	    <entry spanname="id"><constant>V4L2_CID_FLASH_CHARGE</constant></entry>
-	    <entry>boolean</entry>
-	  </row>
-	  <row><entry spanname="descr">Enable or disable charging of the xenon
-	  flash capacitor.</entry>
-	  </row>
-	  <row>
-	    <entry spanname="id"><constant>V4L2_CID_FLASH_READY</constant></entry>
-	    <entry>boolean</entry>
-	  </row>
-	  <row>
-	    <entry spanname="descr">Is the flash ready to strobe?
-	    Xenon flashes require their capacitors charged before
-	    strobing. LED flashes often require a cooldown period
-	    after strobe during which another strobe will not be
-	    possible. This is a read-only control.</entry>
-	  </row>
-	  <row><entry></entry></row>
-	</tbody>
-      </tgroup>
-      </table>
     </section>
 
     <section id="jpeg-controls">
diff --git a/Documentation/DocBook/media/v4l/dev-rds.xml b/Documentation/DocBook/media/v4l/dev-rds.xml
index 38883a4..be2f337 100644
--- a/Documentation/DocBook/media/v4l/dev-rds.xml
+++ b/Documentation/DocBook/media/v4l/dev-rds.xml
@@ -6,7 +6,7 @@ information, on an inaudible audio subcarrier of a radio program. This
 interface is aimed at devices capable of receiving and/or transmitting RDS
 information.</para>
 
-      <para>For more information see the core RDS standard <xref linkend="en50067" />
+      <para>For more information see the core RDS standard <xref linkend="iec62106" />
 and the RBDS standard <xref linkend="nrsc4" />.</para>
 
       <para>Note that the RBDS standard as is used in the USA is almost identical
diff --git a/Documentation/DocBook/media/v4l/dev-subdev.xml b/Documentation/DocBook/media/v4l/dev-subdev.xml
index a3d9dd0..d15aaf8 100644
--- a/Documentation/DocBook/media/v4l/dev-subdev.xml
+++ b/Documentation/DocBook/media/v4l/dev-subdev.xml
@@ -374,29 +374,29 @@
       rectangle --- if it is supported by the hardware.</para>
 
       <orderedlist>
-	<listitem>Sink pad format. The user configures the sink pad
+	<listitem><para>Sink pad format. The user configures the sink pad
 	format. This format defines the parameters of the image the
-	entity receives through the pad for further processing.</listitem>
+	entity receives through the pad for further processing.</para></listitem>
 
-	<listitem>Sink pad actual crop selection. The sink pad crop
-	defines the crop performed to the sink pad format.</listitem>
+	<listitem><para>Sink pad actual crop selection. The sink pad crop
+	defines the crop performed to the sink pad format.</para></listitem>
 
-	<listitem>Sink pad actual compose selection. The size of the
+	<listitem><para>Sink pad actual compose selection. The size of the
 	sink pad compose rectangle defines the scaling ratio compared
 	to the size of the sink pad crop rectangle. The location of
 	the compose rectangle specifies the location of the actual
 	sink compose rectangle in the sink compose bounds
-	rectangle.</listitem>
+	rectangle.</para></listitem>
 
-	<listitem>Source pad actual crop selection. Crop on the source
+	<listitem><para>Source pad actual crop selection. Crop on the source
 	pad defines crop performed to the image in the sink compose
-	bounds rectangle.</listitem>
+	bounds rectangle.</para></listitem>
 
-	<listitem>Source pad format. The source pad format defines the
+	<listitem><para>Source pad format. The source pad format defines the
 	output pixel format of the subdev, as well as the other
 	parameters with the exception of the image width and height.
 	Width and height are defined by the size of the source pad
-	actual crop selection.</listitem>
+	actual crop selection.</para></listitem>
       </orderedlist>
 
       <para>Accessing any of the above rectangles not supported by the
diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml
index 8eace3e..2d3f0b1a 100644
--- a/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml
@@ -22,8 +22,7 @@
 	with 10 bits per colour compressed to 8 bits each, using DPCM
 	compression. DPCM, differential pulse-code modulation, is lossy.
 	Each colour component consumes 8 bits of memory. In other respects
-	this format is similar to <xref
-	linkend="pixfmt-srggb10">.</xref></para>
+	this format is similar to <xref linkend="pixfmt-srggb10" />.</para>
 
       </refsect1>
     </refentry>
diff --git a/Documentation/DocBook/media/v4l/selection-api.xml b/Documentation/DocBook/media/v4l/selection-api.xml
index e7ed507..4c238ce 100644
--- a/Documentation/DocBook/media/v4l/selection-api.xml
+++ b/Documentation/DocBook/media/v4l/selection-api.xml
@@ -40,6 +40,7 @@ cropping and composing rectangles have the same size.</para>
     <section>
       <title>Selection targets</title>
 
+      <para>
       <figure id="sel-targets-capture">
 	<title>Cropping and composing targets</title>
 	<mediaobject>
@@ -52,12 +53,12 @@ cropping and composing rectangles have the same size.</para>
 	  </textobject>
 	</mediaobject>
       </figure>
+      </para>
 
+      <para>See <xref linkend="v4l2-selection-targets" /> for more
+    information.</para>
     </section>
 
-    See <xref linkend="v4l2-selection-targets" /> for more
-    information.
-
   <section>
 
   <title>Configuration</title>
@@ -216,18 +217,17 @@ composing and cropping operations by setting the appropriate targets.  The V4L2
 API lacks any support for composing to and cropping from an image inside a
 memory buffer.  The application could configure a capture device to fill only a
 part of an image by abusing V4L2 API.  Cropping a smaller image from a larger
-one is achieved by setting the field <structfield>
-&v4l2-pix-format;::bytesperline </structfield>.  Introducing an image offsets
-could be done by modifying field <structfield> &v4l2-buffer;::m:userptr
-</structfield> before calling <constant> VIDIOC_QBUF </constant>. Those
+one is achieved by setting the field
+&v4l2-pix-format;<structfield>::bytesperline</structfield>.  Introducing an image offsets
+could be done by modifying field &v4l2-buffer;<structfield>::m_userptr</structfield>
+before calling <constant> VIDIOC_QBUF </constant>. Those
 operations should be avoided because they are not portable (endianness), and do
 not work for macroblock and Bayer formats and mmap buffers.  The selection API
 deals with configuration of buffer cropping/composing in a clear, intuitive and
 portable way.  Next, with the selection API the concepts of the padded target
-and constraints flags are introduced.  Finally, <structname> &v4l2-crop;
-</structname> and <structname> &v4l2-cropcap; </structname> have no reserved
-fields. Therefore there is no way to extend their functionality.  The new
-<structname> &v4l2-selection; </structname> provides a lot of place for future
+and constraints flags are introduced.  Finally, &v4l2-crop; and &v4l2-cropcap;
+have no reserved fields. Therefore there is no way to extend their functionality.
+The new &v4l2-selection; provides a lot of place for future
 extensions.  Driver developers are encouraged to implement only selection API.
 The former cropping API would be simulated using the new one. </para>
 
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index eee6908..0292ed1 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -145,9 +145,12 @@ applications. -->
 	<authorinitials>hv</authorinitials>
 	<revremark>Added VIDIOC_ENUM_FREQ_BANDS.
 	</revremark>
+      </revision>
+
+      <revision>
 	<revnumber>3.5</revnumber>
 	<date>2012-05-07</date>
-	<authorinitials>sa, sn</authorinitials>
+	<authorinitials>sa, sn, hv</authorinitials>
 	<revremark>Added V4L2_CTRL_TYPE_INTEGER_MENU and V4L2 subdev
 	    selections API. Improved the description of V4L2_CID_COLORFX
 	    control, added V4L2_CID_COLORFX_CBCR control.
@@ -158,11 +161,8 @@ applications. -->
 	    V4L2_CID_3A_LOCK, V4L2_CID_AUTO_FOCUS_START,
 	    V4L2_CID_AUTO_FOCUS_STOP, V4L2_CID_AUTO_FOCUS_STATUS
 	    and V4L2_CID_AUTO_FOCUS_RANGE.
-	</revremark>
-	<date>2012-05-01</date>
-	<authorinitials>hv</authorinitials>
-	<revremark>Added VIDIOC_ENUM_DV_TIMINGS, VIDIOC_QUERY_DV_TIMINGS and
-	VIDIOC_DV_TIMINGS_CAP.
+	    Added VIDIOC_ENUM_DV_TIMINGS, VIDIOC_QUERY_DV_TIMINGS and
+	    VIDIOC_DV_TIMINGS_CAP.
 	</revremark>
       </revision>
 
@@ -472,7 +472,7 @@ and discussions on the V4L mailing list.</revremark>
 </partinfo>
 
 <title>Video for Linux Two API Specification</title>
- <subtitle>Revision 3.5</subtitle>
+ <subtitle>Revision 3.6</subtitle>
 
   <chapter id="common">
     &sub-common;
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml
index f76d8a6..b11ec75 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml
@@ -152,12 +152,10 @@ satisfactory parameters have been negotiated. If constraints flags have to be
 violated at then ERANGE is returned. The error indicates that <emphasis> there
 exist no rectangle </emphasis> that satisfies the constraints.</para>
 
-  </refsect1>
-
   <para>Selection targets and flags are documented in <xref
   linkend="v4l2-selections-common"/>.</para>
 
-    <section>
+    <para>
       <figure id="sel-const-adjust">
 	<title>Size adjustments with constraint flags.</title>
 	<mediaobject>
@@ -170,9 +168,9 @@ exist no rectangle </emphasis> that satisfies the constraints.</para>
 	  </textobject>
 	</mediaobject>
       </figure>
-    </section>
+    </para>
 
-  <refsect1>
+  <para>
     <table pgwide="1" frame="none" id="v4l2-selection">
       <title>struct <structname>v4l2_selection</structname></title>
       <tgroup cols="3">
@@ -208,6 +206,7 @@ exist no rectangle </emphasis> that satisfies the constraints.</para>
 	</tbody>
       </tgroup>
     </table>
+  </para>
   </refsect1>
 
   <refsect1>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
index 7203951..701138f 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
@@ -125,7 +125,7 @@ the structure refers to a radio tuner the
 <constant>V4L2_TUNER_CAP_NORM</constant> flags can't be used.</para>
 <para>If multiple frequency bands are supported, then
 <structfield>capability</structfield> is the union of all
-<structfield>capability></structfield> fields of each &v4l2-frequency-band;.
+<structfield>capability</structfield> fields of each &v4l2-frequency-band;.
 </para></entry>
 	  </row>
 	  <row>
diff --git a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml
index 77ff5be..6a821a6 100644
--- a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml
@@ -155,6 +155,8 @@ or no buffers have been allocated yet, or the
 <structfield>userptr</structfield> or
 <structfield>length</structfield> are invalid.</para>
 	</listitem>
+      </varlistentry>
+      <varlistentry>
 	<term><errorcode>EIO</errorcode></term>
 	<listitem>
 	  <para><constant>VIDIOC_DQBUF</constant> failed due to an
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
index f33cc81..1ba9e99 100644
--- a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
@@ -69,23 +69,22 @@
     more information on how each selection target affects the image
     processing pipeline inside the subdevice.</para>
 
-    <section>
+    <refsect2>
       <title>Types of selection targets</title>
 
       <para>There are two types of selection targets: actual and bounds. The
       actual targets are the targets which configure the hardware. The BOUNDS
       target will return a rectangle that contain all possible actual
       rectangles.</para>
-    </section>
+    </refsect2>
 
-    <section>
+    <refsect2>
       <title>Discovering supported features</title>
 
       <para>To discover which targets are supported, the user can
       perform <constant>VIDIOC_SUBDEV_G_SELECTION</constant> on them.
       Any unsupported target will return
       <constant>EINVAL</constant>.</para>
-    </section>
 
     <para>Selection targets and flags are documented in <xref
     linkend="v4l2-selections-common"/>.</para>
@@ -132,6 +131,7 @@
 	</tbody>
       </tgroup>
     </table>
+    </refsect2>
 
   </refsect1>
 
diff --git a/Documentation/DocBook/media_api.tmpl b/Documentation/DocBook/media_api.tmpl
index 4e8e898..f2413ac 100644
--- a/Documentation/DocBook/media_api.tmpl
+++ b/Documentation/DocBook/media_api.tmpl
@@ -29,7 +29,7 @@
 <title>LINUX MEDIA INFRASTRUCTURE API</title>
 
 <copyright>
-	<year>2009-2011</year>
+	<year>2009-2012</year>
 	<holder>LinuxTV Developers</holder>
 </copyright>
 
@@ -53,7 +53,7 @@ Foundation. A copy of the license is included in the chapter entitled
 		video and radio straming devices, including video cameras,
 		analog and digital TV receiver cards, AM/FM receiver cards,
 		streaming capture devices.</para>
-	<para>It is divided into three parts.</para>
+	<para>It is divided into four parts.</para>
 	<para>The first part covers radio, capture,
 		cameras and analog TV devices.</para>
 	<para>The second part covers the
@@ -62,7 +62,8 @@ Foundation. A copy of the license is included in the chapter entitled
 		in fact it covers several different video standards including
 		DVB-T, DVB-S, DVB-C and ATSC. The API is currently being updated
 		to documment support also for DVB-S2, ISDB-T and ISDB-S.</para>
-	<para>The third part covers Remote Controller API</para>
+	<para>The third part covers the Remote Controller API.</para>
+	<para>The fourth part covers the Media Controller API.</para>
 	<para>For additional information and for the latest development code,
 		see: <ulink url="http://linuxtv.org">http://linuxtv.org</ulink>.</para>
 	<para>For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: <ulink url="http://vger.kernel.org/vger-lists.html#linux-media">Linux Media Mailing List (LMML).</ulink>.</para>
@@ -87,7 +88,7 @@ Foundation. A copy of the license is included in the chapter entitled
 </author>
 </authorgroup>
 <copyright>
-	<year>2009-2011</year>
+	<year>2009-2012</year>
 	<holder>Mauro Carvalho Chehab</holder>
 </copyright>
 
diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl
index e0aedb7..fe122d6 100644
--- a/Documentation/DocBook/mtdnand.tmpl
+++ b/Documentation/DocBook/mtdnand.tmpl
@@ -1216,8 +1216,6 @@ in this page</entry>
 #define	NAND_BBT_LASTBLOCK	0x00000010
 /* The bbt is at the given page, else we must scan for the bbt */
 #define NAND_BBT_ABSPAGE	0x00000020
-/* The bbt is at the given page, else we must scan for the bbt */
-#define NAND_BBT_SEARCH		0x00000040
 /* bbt is stored per chip on multichip devices */
 #define NAND_BBT_PERCHIP	0x00000080
 /* bbt has a version counter at offset veroffs */
diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt
index f6f15ce..672d190 100644
--- a/Documentation/RCU/trace.txt
+++ b/Documentation/RCU/trace.txt
@@ -333,23 +333,23 @@ o	Each element of the form "1/1 0:127 ^0" represents one struct
 The output of "cat rcu/rcu_pending" looks as follows:
 
 rcu_sched:
-  0 np=255892 qsp=53936 rpq=85 cbr=0 cng=14417 gpc=10033 gps=24320 nf=6445 nn=146741
-  1 np=261224 qsp=54638 rpq=33 cbr=0 cng=25723 gpc=16310 gps=2849 nf=5912 nn=155792
-  2 np=237496 qsp=49664 rpq=23 cbr=0 cng=2762 gpc=45478 gps=1762 nf=1201 nn=136629
-  3 np=236249 qsp=48766 rpq=98 cbr=0 cng=286 gpc=48049 gps=1218 nf=207 nn=137723
-  4 np=221310 qsp=46850 rpq=7 cbr=0 cng=26 gpc=43161 gps=4634 nf=3529 nn=123110
-  5 np=237332 qsp=48449 rpq=9 cbr=0 cng=54 gpc=47920 gps=3252 nf=201 nn=137456
-  6 np=219995 qsp=46718 rpq=12 cbr=0 cng=50 gpc=42098 gps=6093 nf=4202 nn=120834
-  7 np=249893 qsp=49390 rpq=42 cbr=0 cng=72 gpc=38400 gps=17102 nf=41 nn=144888
+  0 np=255892 qsp=53936 rpq=85 cbr=0 cng=14417 gpc=10033 gps=24320 nn=146741
+  1 np=261224 qsp=54638 rpq=33 cbr=0 cng=25723 gpc=16310 gps=2849 nn=155792
+  2 np=237496 qsp=49664 rpq=23 cbr=0 cng=2762 gpc=45478 gps=1762 nn=136629
+  3 np=236249 qsp=48766 rpq=98 cbr=0 cng=286 gpc=48049 gps=1218 nn=137723
+  4 np=221310 qsp=46850 rpq=7 cbr=0 cng=26 gpc=43161 gps=4634 nn=123110
+  5 np=237332 qsp=48449 rpq=9 cbr=0 cng=54 gpc=47920 gps=3252 nn=137456
+  6 np=219995 qsp=46718 rpq=12 cbr=0 cng=50 gpc=42098 gps=6093 nn=120834
+  7 np=249893 qsp=49390 rpq=42 cbr=0 cng=72 gpc=38400 gps=17102 nn=144888
 rcu_bh:
-  0 np=146741 qsp=1419 rpq=6 cbr=0 cng=6 gpc=0 gps=0 nf=2 nn=145314
-  1 np=155792 qsp=12597 rpq=3 cbr=0 cng=0 gpc=4 gps=8 nf=3 nn=143180
-  2 np=136629 qsp=18680 rpq=1 cbr=0 cng=0 gpc=7 gps=6 nf=0 nn=117936
-  3 np=137723 qsp=2843 rpq=0 cbr=0 cng=0 gpc=10 gps=7 nf=0 nn=134863
-  4 np=123110 qsp=12433 rpq=0 cbr=0 cng=0 gpc=4 gps=2 nf=0 nn=110671
-  5 np=137456 qsp=4210 rpq=1 cbr=0 cng=0 gpc=6 gps=5 nf=0 nn=133235
-  6 np=120834 qsp=9902 rpq=2 cbr=0 cng=0 gpc=6 gps=3 nf=2 nn=110921
-  7 np=144888 qsp=26336 rpq=0 cbr=0 cng=0 gpc=8 gps=2 nf=0 nn=118542
+  0 np=146741 qsp=1419 rpq=6 cbr=0 cng=6 gpc=0 gps=0 nn=145314
+  1 np=155792 qsp=12597 rpq=3 cbr=0 cng=0 gpc=4 gps=8 nn=143180
+  2 np=136629 qsp=18680 rpq=1 cbr=0 cng=0 gpc=7 gps=6 nn=117936
+  3 np=137723 qsp=2843 rpq=0 cbr=0 cng=0 gpc=10 gps=7 nn=134863
+  4 np=123110 qsp=12433 rpq=0 cbr=0 cng=0 gpc=4 gps=2 nn=110671
+  5 np=137456 qsp=4210 rpq=1 cbr=0 cng=0 gpc=6 gps=5 nn=133235
+  6 np=120834 qsp=9902 rpq=2 cbr=0 cng=0 gpc=6 gps=3 nn=110921
+  7 np=144888 qsp=26336 rpq=0 cbr=0 cng=0 gpc=8 gps=2 nn=118542
 
 As always, this is once again split into "rcu_sched" and "rcu_bh"
 portions, with CONFIG_TREE_PREEMPT_RCU kernels having an additional
@@ -377,17 +377,6 @@ o	"gpc" is the number of times that an old grace period had
 o	"gps" is the number of times that a new grace period had started,
 	but this CPU was not yet aware of it.
 
-o	"nf" is the number of times that this CPU suspected that the
-	current grace period had run for too long, and thus needed to
-	be forced.
-
-	Please note that "forcing" consists of sending resched IPIs
-	to holdout CPUs.  If that CPU really still is in an old RCU
-	read-side critical section, then we really do have to wait for it.
-	The assumption behing "forcing" is that the CPU is not still in
-	an old RCU read-side critical section, but has not yet responded
-	for some other reason.
-
 o	"nn" is the number of times that this CPU needed nothing.  Alert
 	readers will note that the rcu "nn" number for a given CPU very
 	closely matches the rcu_bh "np" number for that same CPU.  This
diff --git a/Documentation/arm/Marvell/README b/Documentation/arm/Marvell/README
new file mode 100644
index 0000000..8f08a86
--- /dev/null
+++ b/Documentation/arm/Marvell/README
@@ -0,0 +1,232 @@
+ARM Marvell SoCs
+================
+
+This document lists all the ARM Marvell SoCs that are currently
+supported in mainline by the Linux kernel. As the Marvell families of
+SoCs are large and complex, it is hard to understand where the support
+for a particular SoC is available in the Linux kernel. This document
+tries to help in understanding where those SoCs are supported, and to
+match them with their corresponding public datasheet, when available.
+
+Orion family
+------------
+
+  Flavors:
+        88F5082
+        88F5181
+        88F5181L
+        88F5182
+               Datasheet               : http://www.embeddedarm.com/documentation/third-party/MV88F5182-datasheet.pdf
+               Programmer's User Guide : http://www.embeddedarm.com/documentation/third-party/MV88F5182-opensource-manual.pdf
+               User Manual             : http://www.embeddedarm.com/documentation/third-party/MV88F5182-usermanual.pdf
+        88F5281
+               Datasheet               : http://www.ocmodshop.com/images/reviews/networking/qnap_ts409u/marvel_88f5281_data_sheet.pdf
+        88F6183
+  Core: Feroceon ARMv5 compatible
+  Linux kernel mach directory: arch/arm/mach-orion5x
+  Linux kernel plat directory: arch/arm/plat-orion
+
+Kirkwood family
+---------------
+
+  Flavors:
+        88F6282 a.k.a Armada 300
+                Product Brief  : http://www.marvell.com/embedded-processors/armada-300/assets/armada_310.pdf
+        88F6283 a.k.a Armada 310
+                Product Brief  : http://www.marvell.com/embedded-processors/armada-300/assets/armada_310.pdf
+        88F6190
+                Product Brief  : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6190-003_WEB.pdf
+                Hardware Spec  : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F619x_OpenSource.pdf
+                Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
+        88F6192
+                Product Brief  : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6192-003_ver1.pdf
+                Hardware Spec  : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F619x_OpenSource.pdf
+                Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
+        88F6182
+        88F6180
+                Product Brief  : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6180-003_ver1.pdf
+                Hardware Spec  : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F6180_OpenSource.pdf
+                Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
+        88F6281
+                Product Brief  : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6281-004_ver1.pdf
+                Hardware Spec  : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F6281_OpenSource.pdf
+                Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
+  Homepage: http://www.marvell.com/embedded-processors/kirkwood/
+  Core: Feroceon ARMv5 compatible
+  Linux kernel mach directory: arch/arm/mach-kirkwood
+  Linux kernel plat directory: arch/arm/plat-orion
+
+Discovery family
+----------------
+
+  Flavors:
+        MV78100
+                Product Brief  : http://www.marvell.com/embedded-processors/discovery-innovation/assets/MV78100-003_WEB.pdf
+                Hardware Spec  : http://www.marvell.com/embedded-processors/discovery-innovation/assets/HW_MV78100_OpenSource.pdf
+                Functional Spec: http://www.marvell.com/embedded-processors/discovery-innovation/assets/FS_MV76100_78100_78200_OpenSource.pdf
+        MV78200
+                Product Brief  : http://www.marvell.com/embedded-processors/discovery-innovation/assets/MV78200-002_WEB.pdf
+                Hardware Spec  : http://www.marvell.com/embedded-processors/discovery-innovation/assets/HW_MV78200_OpenSource.pdf
+                Functional Spec: http://www.marvell.com/embedded-processors/discovery-innovation/assets/FS_MV76100_78100_78200_OpenSource.pdf
+        MV76100
+                Not supported by the Linux kernel.
+
+  Core: Feroceon ARMv5 compatible
+
+  Linux kernel mach directory: arch/arm/mach-mv78xx0
+  Linux kernel plat directory: arch/arm/plat-orion
+
+EBU Armada family
+-----------------
+
+  Armada 370 Flavors:
+        88F6710
+        88F6707
+        88F6W11
+
+  Armada XP Flavors:
+        MV78230
+        MV78260
+        MV78460
+
+  Product Brief: http://www.marvell.com/embedded-processors/armada-xp/assets/Marvell-ArmadaXP-SoC-product%20brief.pdf
+  No public datasheet available.
+
+  Core: Sheeva ARMv7 compatible
+
+  Linux kernel mach directory: arch/arm/mach-mvebu
+  Linux kernel plat directory: none
+
+Avanta family
+-------------
+
+  Flavors:
+       88F6510
+       88F6530P
+       88F6550
+       88F6560
+  Homepage     : http://www.marvell.com/broadband/
+  Product Brief: http://www.marvell.com/broadband/assets/Marvell_Avanta_88F6510_305_060-001_product_brief.pdf
+  No public datasheet available.
+
+  Core: ARMv5 compatible
+
+  Linux kernel mach directory: no code in mainline yet, planned for the future
+  Linux kernel plat directory: no code in mainline yet, planned for the future
+
+Dove family (application processor)
+-----------------------------------
+
+  Flavors:
+        88AP510 a.k.a Armada 510
+                Product Brief   : http://www.marvell.com/application-processors/armada-500/assets/Marvell_Armada510_SoC.pdf
+                Hardware Spec   : http://www.marvell.com/application-processors/armada-500/assets/Armada-510-Hardware-Spec.pdf
+                Functional Spec : http://www.marvell.com/application-processors/armada-500/assets/Armada-510-Functional-Spec.pdf
+  Homepage: http://www.marvell.com/application-processors/armada-500/
+  Core: ARMv7 compatible
+  Directory: arch/arm/mach-dove
+
+PXA 2xx/3xx/93x/95x family
+--------------------------
+
+  Flavors:
+        PXA21x, PXA25x, PXA26x
+             Application processor only
+             Core: ARMv5 XScale core
+        PXA270, PXA271, PXA272
+             Product Brief         : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_pb.pdf
+             Design guide          : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_design_guide.pdf
+             Developers manual     : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_dev_man.pdf
+             Specification         : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_emts.pdf
+             Specification update  : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_spec_update.pdf
+             Application processor only
+             Core: ARMv5 XScale core
+        PXA300, PXA310, PXA320
+             PXA 300 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA300_PB_R4.pdf
+             PXA 310 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA310_PB_R4.pdf
+             PXA 320 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA320_PB_R4.pdf
+             Design guide          : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Design_Guide.pdf
+             Developers manual     : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Developers_Manual.zip
+             Specifications        : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_EMTS.pdf
+             Specification Update  : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Spec_Update.zip
+             Reference Manual      : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_TavorP_BootROM_Ref_Manual.pdf
+             Application processor only
+             Core: ARMv5 XScale core
+        PXA930, PXA935
+             Application processor with Communication processor
+             Core: ARMv5 XScale core
+        PXA955
+             Application processor with Communication processor
+             Core: ARMv7 compatible Sheeva PJ4 core
+
+   Comments:
+
+    * This line of SoCs originates from the XScale family developed by
+      Intel and acquired by Marvell in ~2006. The PXA21x, PXA25x,
+      PXA26x, PXA27x, PXA3xx and PXA93x were developed by Intel, while
+      the later PXA95x were developed by Marvell.
+
+    * Due to their XScale origin, these SoCs have virtually nothing in
+      common with the other (Kirkwood, Dove, etc.) families of Marvell
+      SoCs, except with the MMP/MMP2 family of SoCs.
+
+   Linux kernel mach directory: arch/arm/mach-pxa
+   Linux kernel plat directory: arch/arm/plat-pxa
+
+MMP/MMP2 family (communication processor)
+-----------------------------------------
+
+   Flavors:
+        PXA168, a.k.a Armada 168
+             Homepage             : http://www.marvell.com/application-processors/armada-100/armada-168.jsp
+             Product brief        : http://www.marvell.com/application-processors/armada-100/assets/pxa_168_pb.pdf
+             Hardware manual      : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_datasheet.pdf
+             Software manual      : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_software_manual.pdf
+             Specification update : http://www.marvell.com/application-processors/armada-100/assets/ARMADA16x_Spec_update.pdf
+             Boot ROM manual      : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_ref_manual.pdf
+             App node package     : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_app_note_package.pdf
+             Application processor only
+             Core: ARMv5 compatible Marvell PJ1 (Mohawk)
+        PXA910
+             Homepage             : http://www.marvell.com/communication-processors/pxa910/
+             Product Brief        : http://www.marvell.com/communication-processors/pxa910/assets/Marvell_PXA910_Platform-001_PB_final.pdf
+             Application processor with Communication processor
+             Core: ARMv5 compatible Marvell PJ1 (Mohawk)
+        MMP2, a.k.a Armada 610
+             Product Brief        : http://www.marvell.com/application-processors/armada-600/assets/armada610_pb.pdf
+             Application processor only
+             Core: ARMv7 compatible Sheeva PJ4 core
+
+   Comments:
+
+    * This line of SoCs originates from the XScale family developed by
+      Intel and acquired by Marvell in ~2006. All the processors of
+      this MMP/MMP2 family were developed by Marvell.
+
+    * Due to their XScale origin, these SoCs have virtually nothing in
+      common with the other (Kirkwood, Dove, etc.) families of Marvell
+      SoCs, except with the PXA family of SoCs listed above.
+
+   Linux kernel mach directory: arch/arm/mach-mmp
+   Linux kernel plat directory: arch/arm/plat-pxa
+
+Long-term plans
+---------------
+
+ * Unify the mach-dove/, mach-mv78xx0/, mach-orion5x/ and
+   mach-kirkwood/ into the mach-mvebu/ to support all SoCs from the
+   Marvell EBU (Engineering Business Unit) in a single mach-<foo>
+   directory. The plat-orion/ would therefore disappear.
+
+ * Unify the mach-mmp/ and mach-pxa/ into the same mach-pxa
+   directory. The plat-pxa/ would therefore disappear.
+
+Credits
+-------
+
+ Maen Suleiman <maen@marvell.com>
+ Lior Amsalem <alior@marvell.com>
+ Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ Andrew Lunn <andrew@lunn.ch>
+ Nicolas Pitre <nico@fluxnic.net>
+ Eric Miao <eric.y.miao@gmail.com>
diff --git a/Documentation/arm/memory.txt b/Documentation/arm/memory.txt
index 208a2d4..4bfb9ff 100644
--- a/Documentation/arm/memory.txt
+++ b/Documentation/arm/memory.txt
@@ -51,6 +51,9 @@ ffc00000	ffefffff	DMA memory mapping region.  Memory returned
 ff000000	ffbfffff	Reserved for future expansion of DMA
 				mapping region.
 
+fee00000	feffffff	Mapping of PCI I/O space. This is a static
+				mapping within the vmalloc space.
+
 VMALLOC_START	VMALLOC_END-1	vmalloc() / ioremap() space.
 				Memory returned by vmalloc/ioremap will
 				be dynamically placed in this region.
diff --git a/Documentation/block/00-INDEX b/Documentation/block/00-INDEX
index d111e3b..d18ecd8 100644
--- a/Documentation/block/00-INDEX
+++ b/Documentation/block/00-INDEX
@@ -3,15 +3,21 @@
 biodoc.txt
 	- Notes on the Generic Block Layer Rewrite in Linux 2.5
 capability.txt
-	- Generic Block Device Capability (/sys/block/<disk>/capability)
+	- Generic Block Device Capability (/sys/block/<device>/capability)
+cfq-iosched.txt
+	- CFQ IO scheduler tunables
+data-integrity.txt
+	- Block data integrity
 deadline-iosched.txt
 	- Deadline IO scheduler tunables
 ioprio.txt
 	- Block io priorities (in CFQ scheduler)
+queue-sysfs.txt
+	- Queue's sysfs entries
 request.txt
 	- The members of struct request (in include/linux/blkdev.h)
 stat.txt
-	- Block layer statistics in /sys/block/<dev>/stat
+	- Block layer statistics in /sys/block/<device>/stat
 switching-sched.txt
 	- Switching I/O schedulers at runtime
 writeback_cache_control.txt
diff --git a/Documentation/block/cfq-iosched.txt b/Documentation/block/cfq-iosched.txt
index 6d670f5..d89b4fe 100644
--- a/Documentation/block/cfq-iosched.txt
+++ b/Documentation/block/cfq-iosched.txt
@@ -1,3 +1,14 @@
+CFQ (Complete Fairness Queueing)
+===============================
+
+The main aim of CFQ scheduler is to provide a fair allocation of the disk
+I/O bandwidth for all the processes which requests an I/O operation.
+
+CFQ maintains the per process queue for the processes which request I/O
+operation(syncronous requests). In case of asynchronous requests, all the
+requests from all the processes are batched together according to their
+process's I/O priority.
+
 CFQ ioscheduler tunables
 ========================
 
@@ -25,6 +36,72 @@ there are multiple spindles behind single LUN (Host based hardware RAID
 controller or for storage arrays), setting slice_idle=0 might end up in better
 throughput and acceptable latencies.
 
+back_seek_max
+-------------
+This specifies, given in Kbytes, the maximum "distance" for backward seeking.
+The distance is the amount of space from the current head location to the
+sectors that are backward in terms of distance.
+
+This parameter allows the scheduler to anticipate requests in the "backward"
+direction and consider them as being the "next" if they are within this
+distance from the current head location.
+
+back_seek_penalty
+-----------------
+This parameter is used to compute the cost of backward seeking. If the
+backward distance of request is just 1/back_seek_penalty from a "front"
+request, then the seeking cost of two requests is considered equivalent.
+
+So scheduler will not bias toward one or the other request (otherwise scheduler
+will bias toward front request). Default value of back_seek_penalty is 2.
+
+fifo_expire_async
+-----------------
+This parameter is used to set the timeout of asynchronous requests. Default
+value of this is 248ms.
+
+fifo_expire_sync
+----------------
+This parameter is used to set the timeout of synchronous requests. Default
+value of this is 124ms. In case to favor synchronous requests over asynchronous
+one, this value should be decreased relative to fifo_expire_async.
+
+slice_async
+-----------
+This parameter is same as of slice_sync but for asynchronous queue. The
+default value is 40ms.
+
+slice_async_rq
+--------------
+This parameter is used to limit the dispatching of asynchronous request to
+device request queue in queue's slice time. The maximum number of request that
+are allowed to be dispatched also depends upon the io priority. Default value
+for this is 2.
+
+slice_sync
+----------
+When a queue is selected for execution, the queues IO requests are only
+executed for a certain amount of time(time_slice) before switching to another
+queue. This parameter is used to calculate the time slice of synchronous
+queue.
+
+time_slice is computed using the below equation:-
+time_slice = slice_sync + (slice_sync/5 * (4 - prio)). To increase the
+time_slice of synchronous queue, increase the value of slice_sync. Default
+value is 100ms.
+
+quantum
+-------
+This specifies the number of request dispatched to the device queue. In a
+queue's time slice, a request will not be dispatched if the number of request
+in the device exceeds this parameter. This parameter is used for synchronous
+request.
+
+In case of storage with several disk, this setting can limit the parallel
+processing of request. Therefore, increasing the value can imporve the
+performace although this can cause the latency of some I/O to increase due
+to more number of requests.
+
 CFQ IOPS Mode for group scheduling
 ===================================
 Basic CFQ design is to provide priority based time slices. Higher priority
diff --git a/Documentation/block/queue-sysfs.txt b/Documentation/block/queue-sysfs.txt
index 6518a55..e54ac1d 100644
--- a/Documentation/block/queue-sysfs.txt
+++ b/Documentation/block/queue-sysfs.txt
@@ -9,20 +9,71 @@ These files are the ones found in the /sys/block/xxx/queue/ directory.
 Files denoted with a RO postfix are readonly and the RW postfix means
 read-write.
 
+add_random (RW)
+----------------
+This file allows to trun off the disk entropy contribution. Default
+value of this file is '1'(on).
+
+discard_granularity (RO)
+-----------------------
+This shows the size of internal allocation of the device in bytes, if
+reported by the device. A value of '0' means device does not support
+the discard functionality.
+
+discard_max_bytes (RO)
+----------------------
+Devices that support discard functionality may have internal limits on
+the number of bytes that can be trimmed or unmapped in a single operation.
+The discard_max_bytes parameter is set by the device driver to the maximum
+number of bytes that can be discarded in a single operation. Discard
+requests issued to the device must not exceed this limit. A discard_max_bytes
+value of 0 means that the device does not support discard functionality.
+
+discard_zeroes_data (RO)
+------------------------
+When read, this file will show if the discarded block are zeroed by the
+device or not. If its value is '1' the blocks are zeroed otherwise not.
+
 hw_sector_size (RO)
 -------------------
 This is the hardware sector size of the device, in bytes.
 
+iostats (RW)
+-------------
+This file is used to control (on/off) the iostats accounting of the
+disk.
+
+logical_block_size (RO)
+-----------------------
+This is the logcal block size of the device, in bytes.
+
 max_hw_sectors_kb (RO)
 ----------------------
 This is the maximum number of kilobytes supported in a single data transfer.
 
+max_integrity_segments (RO)
+---------------------------
+When read, this file shows the max limit of integrity segments as
+set by block layer which a hardware controller can handle.
+
 max_sectors_kb (RW)
 -------------------
 This is the maximum number of kilobytes that the block layer will allow
 for a filesystem request. Must be smaller than or equal to the maximum
 size allowed by the hardware.
 
+max_segments (RO)
+-----------------
+Maximum number of segments of the device.
+
+max_segment_size (RO)
+---------------------
+Maximum segment size of the device.
+
+minimum_io_size (RO)
+--------------------
+This is the smallest preferred io size reported by the device.
+
 nomerges (RW)
 -------------
 This enables the user to disable the lookup logic involved with IO
@@ -45,11 +96,24 @@ per-block-cgroup request pool.  IOW, if there are N block cgroups,
 each request queue may have upto N request pools, each independently
 regulated by nr_requests.
 
+optimal_io_size (RO)
+--------------------
+This is the optimal io size reported by the device.
+
+physical_block_size (RO)
+------------------------
+This is the physical block size of device, in bytes.
+
 read_ahead_kb (RW)
 ------------------
 Maximum number of kilobytes to read-ahead for filesystems on this block
 device.
 
+rotational (RW)
+---------------
+This file is used to stat if the device is of rotational type or
+non-rotational type.
+
 rq_affinity (RW)
 ----------------
 If this option is '1', the block layer will migrate request completions to the
diff --git a/Documentation/cpuidle/sysfs.txt b/Documentation/cpuidle/sysfs.txt
index 9d28a34..b6f44f4 100644
--- a/Documentation/cpuidle/sysfs.txt
+++ b/Documentation/cpuidle/sysfs.txt
@@ -76,9 +76,17 @@ total 0
 
 
 * desc : Small description about the idle state (string)
-* disable : Option to disable this idle state (bool)
+* disable : Option to disable this idle state (bool) -> see note below
 * latency : Latency to exit out of this idle state (in microseconds)
 * name : Name of the idle state (string)
 * power : Power consumed while in this idle state (in milliwatts)
 * time : Total time spent in this idle state (in microseconds)
 * usage : Number of times this state was entered (count)
+
+Note:
+The behavior and the effect of the disable variable depends on the
+implementation of a particular governor. In the ladder governor, for
+example, it is not coherent, i.e. if one is disabling a light state,
+then all deeper states are disabled as well, but the disable variable
+does not reflect it. Likewise, if one enables a deep state but a lighter
+state still is disabled, then this has no effect.
diff --git a/Documentation/devicetree/bindings/arm/mrvl/tauros2.txt b/Documentation/devicetree/bindings/arm/mrvl/tauros2.txt
new file mode 100644
index 0000000..31af1cbb
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mrvl/tauros2.txt
@@ -0,0 +1,17 @@
+* Marvell Tauros2 Cache
+
+Required properties:
+- compatible : Should be "marvell,tauros2-cache".
+- marvell,tauros2-cache-features : Specify the features supported for the
+  tauros2 cache.
+  The features including
+    CACHE_TAUROS2_PREFETCH_ON       (1 << 0)
+    CACHE_TAUROS2_LINEFILL_BURST8   (1 << 1)
+  The definition can be found at
+  arch/arm/include/asm/hardware/cache-tauros2.h
+
+Example:
+	L2: l2-cache {
+		compatible = "marvell,tauros2-cache";
+		marvell,tauros2-cache-features = <0x3>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/pmu.txt b/Documentation/devicetree/bindings/arm/pmu.txt
index 1c044eb..343781b 100644
--- a/Documentation/devicetree/bindings/arm/pmu.txt
+++ b/Documentation/devicetree/bindings/arm/pmu.txt
@@ -7,8 +7,12 @@ representation in the device tree should be done as under:-
 Required properties:
 
 - compatible : should be one of
+	"arm,cortex-a15-pmu"
 	"arm,cortex-a9-pmu"
 	"arm,cortex-a8-pmu"
+	"arm,cortex-a7-pmu"
+	"arm,cortex-a5-pmu"
+	"arm,arm11mpcore-pmu"
 	"arm,arm1176-pmu"
 	"arm,arm1136-pmu"
 - interrupts : 1 combined interrupt or 1 per core.
diff --git a/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
new file mode 100644
index 0000000..0a85c70
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
@@ -0,0 +1,68 @@
+* Atmel High Speed MultiMedia Card Interface
+
+This controller on atmel products provides an interface for MMC, SD and SDIO
+types of memory cards.
+
+This file documents differences between the core properties described
+by mmc.txt and the properties used by the atmel-mci driver.
+
+1) MCI node
+
+Required properties:
+- compatible: should be "atmel,hsmci"
+- #address-cells: should be one. The cell is the slot id.
+- #size-cells: should be zero.
+- at least one slot node
+
+The node contains child nodes for each slot that the platform uses
+
+Example MCI node:
+
+mmc0: mmc@f0008000 {
+	compatible = "atmel,hsmci";
+	reg = <0xf0008000 0x600>;
+	interrupts = <12 4>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	[ child node definitions...]
+};
+
+2) slot nodes
+
+Required properties:
+- reg: should contain the slot id.
+- bus-width: number of data lines connected to the controller
+
+Optional properties:
+- cd-gpios: specify GPIOs for card detection
+- cd-inverted: invert the value of external card detect gpio line
+- wp-gpios: specify GPIOs for write protection
+
+Example slot node:
+
+slot@0 {
+	reg = <0>;
+	bus-width = <4>;
+	cd-gpios = <&pioD 15 0>
+	cd-inverted;
+};
+
+Example full MCI node:
+mmc0: mmc@f0008000 {
+	compatible = "atmel,hsmci";
+	reg = <0xf0008000 0x600>;
+	interrupts = <12 4>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	slot@0 {
+		reg = <0>;
+		bus-width = <4>;
+		cd-gpios = <&pioD 15 0>
+		cd-inverted;
+	};
+	slot@1 {
+		reg = <1>;
+		bus-width = <4>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/mmc/pxa-mmc.txt b/Documentation/devicetree/bindings/mmc/pxa-mmc.txt
new file mode 100644
index 0000000..b7025de
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/pxa-mmc.txt
@@ -0,0 +1,25 @@
+* PXA MMC drivers
+
+Driver bindings for the PXA MCI (MMC/SDIO) interfaces
+
+Required properties:
+- compatible: Should be "marvell,pxa-mmc".
+- vmmc-supply: A regulator for VMMC
+
+Optional properties:
+- marvell,detect-delay-ms: sets the detection delay timeout in ms.
+- marvell,gpio-power: GPIO spec for the card power enable pin
+
+This file documents differences between the core properties in mmc.txt
+and the properties used by the pxa-mmc driver.
+
+Examples:
+
+mmc0: mmc@41100000 {
+	compatible = "marvell,pxa-mmc";
+	reg = <0x41100000 0x1000>;
+	interrupts = <23>;
+	cd-gpios = <&gpio 23 0>;
+	wp-gpios = <&gpio 24 0>;
+};
+
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-dove.txt b/Documentation/devicetree/bindings/mmc/sdhci-dove.txt
new file mode 100644
index 0000000..ae9aab9
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/sdhci-dove.txt
@@ -0,0 +1,14 @@
+* Marvell sdhci-dove controller
+
+This file documents differences between the core properties in mmc.txt
+and the properties used by the sdhci-pxav2 and sdhci-pxav3 drivers.
+
+- compatible: Should be "marvell,dove-sdhci".
+
+Example:
+
+sdio0: sdio@92000 {
+	compatible = "marvell,dove-sdhci";
+	reg = <0x92000 0x100>;
+	interrupts = <35>;
+};
diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
index a200695..d555421 100644
--- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
@@ -3,7 +3,9 @@ Atmel NAND flash
 Required properties:
 - compatible : "atmel,at91rm9200-nand".
 - reg : should specify localbus address and size used for the chip,
-	and if availlable the ECC.
+	and hardware ECC controller if available.
+	If the hardware ECC is PMECC, it should contain address and size for
+	PMECC, PMECC Error Location controller and ROM which has lookup tables.
 - atmel,nand-addr-offset : offset for the address latch.
 - atmel,nand-cmd-offset : offset for the command latch.
 - #address-cells, #size-cells : Must be present if the device has sub-nodes
@@ -16,6 +18,15 @@ Optional properties:
 - nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default.
   Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
   "soft_bch".
+- atmel,has-pmecc : boolean to enable Programmable Multibit ECC hardware.
+  Only supported by at91sam9x5 or later sam9 product.
+- atmel,pmecc-cap : error correct capability for Programmable Multibit ECC
+  Controller. Supported values are: 2, 4, 8, 12, 24.
+- atmel,pmecc-sector-size : sector size for ECC computation. Supported values
+  are: 512, 1024.
+- atmel,pmecc-lookup-table-offset : includes two offsets of lookup table in ROM
+  for different sector size. First one is for sector size 512, the next is for
+  sector size 1024.
 - nand-bus-width : 8 or 16 bus width if not present 8
 - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
 
@@ -39,3 +50,30 @@ nand0: nand@40000000,0 {
 		...
 	};
 };
+
+/* for PMECC supported chips */
+nand0: nand@40000000 {
+	compatible = "atmel,at91rm9200-nand";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	reg = < 0x40000000 0x10000000	/* bus addr & size */
+		0xffffe000 0x00000600	/* PMECC addr & size */
+		0xffffe600 0x00000200	/* PMECC ERRLOC addr & size */
+		0x00100000 0x00100000	/* ROM addr & size */
+		>;
+	atmel,nand-addr-offset = <21>;	/* ale */
+	atmel,nand-cmd-offset = <22>;	/* cle */
+	nand-on-flash-bbt;
+	nand-ecc-mode = "hw";
+	atmel,has-pmecc;	/* enable PMECC */
+	atmel,pmecc-cap = <2>;
+	atmel,pmecc-sector-size = <512>;
+	atmel,pmecc-lookup-table-offset = <0x8000 0x10000>;
+	gpios = <&pioD 5 0	/* rdy */
+		 &pioD 4 0	/* nce */
+		 0		/* cd */
+		>;
+	partition@0 {
+		...
+	};
+};
diff --git a/Documentation/devicetree/bindings/mtd/gpmi-nand.txt b/Documentation/devicetree/bindings/mtd/gpmi-nand.txt
index 1a5bbd3..3fb3f90 100644
--- a/Documentation/devicetree/bindings/mtd/gpmi-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/gpmi-nand.txt
@@ -12,6 +12,10 @@ Required properties:
   - interrupt-names : The interrupt names "gpmi-dma", "bch";
   - fsl,gpmi-dma-channel : Should contain the dma channel it uses.
 
+Optional properties:
+  - nand-on-flash-bbt: boolean to enable on flash bbt option if not
+                       present false
+
 The device tree may optionally contain sub-nodes describing partitions of the
 address space. See partition.txt for more detail.
 
diff --git a/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt b/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt
new file mode 100644
index 0000000..d0a3725
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt
@@ -0,0 +1,50 @@
+NXP LPC32xx SoC NAND MLC controller
+
+Required properties:
+- compatible: "nxp,lpc3220-mlc"
+- reg: Address and size of the controller
+- interrupts: The NAND interrupt specification
+- gpios: GPIO specification for NAND write protect
+
+The following required properties are very controller specific. See the LPC32xx
+User Manual 7.5.14 MLC NAND Timing Register (the values here are specified in
+Hz, to make them independent of actual clock speed and to provide for good
+accuracy:)
+- nxp,tcea_delay: TCEA_DELAY
+- nxp,busy_delay: BUSY_DELAY
+- nxp,nand_ta: NAND_TA
+- nxp,rd_high: RD_HIGH
+- nxp,rd_low: RD_LOW
+- nxp,wr_high: WR_HIGH
+- nxp,wr_low: WR_LOW
+
+Optional subnodes:
+- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt
+
+Example:
+
+	mlc: flash@200A8000 {
+		compatible = "nxp,lpc3220-mlc";
+		reg = <0x200A8000 0x11000>;
+		interrupts = <11 0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		nxp,tcea-delay = <333333333>;
+		nxp,busy-delay = <10000000>;
+		nxp,nand-ta = <18181818>;
+		nxp,rd-high = <31250000>;
+		nxp,rd-low = <45454545>;
+		nxp,wr-high = <40000000>;
+		nxp,wr-low = <83333333>;
+		gpios = <&gpio 5 19 1>; /* GPO_P3 19, active low */
+
+		mtd0@00000000 {
+			label = "boot";
+			reg = <0x00000000 0x00064000>;
+			read-only;
+		};
+
+		...
+
+	};
diff --git a/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt b/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt
new file mode 100644
index 0000000..d94edc0
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt
@@ -0,0 +1,52 @@
+NXP LPC32xx SoC NAND SLC controller
+
+Required properties:
+- compatible: "nxp,lpc3220-slc"
+- reg: Address and size of the controller
+- nand-on-flash-bbt: Use bad block table on flash
+- gpios: GPIO specification for NAND write protect
+
+The following required properties are very controller specific. See the LPC32xx
+User Manual:
+- nxp,wdr-clks: Delay before Ready signal is tested on write (W_RDY)
+- nxp,rdr-clks: Delay before Ready signal is tested on read (R_RDY)
+(The following values are specified in Hz, to make them independent of actual
+clock speed:)
+- nxp,wwidth: Write pulse width (W_WIDTH)
+- nxp,whold: Write hold time (W_HOLD)
+- nxp,wsetup: Write setup time (W_SETUP)
+- nxp,rwidth: Read pulse width (R_WIDTH)
+- nxp,rhold: Read hold time (R_HOLD)
+- nxp,rsetup: Read setup time (R_SETUP)
+
+Optional subnodes:
+- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt
+
+Example:
+
+	slc: flash@20020000 {
+		compatible = "nxp,lpc3220-slc";
+		reg = <0x20020000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		nxp,wdr-clks = <14>;
+		nxp,wwidth = <40000000>;
+		nxp,whold = <100000000>;
+		nxp,wsetup = <100000000>;
+		nxp,rdr-clks = <14>;
+		nxp,rwidth = <40000000>;
+		nxp,rhold = <66666666>;
+		nxp,rsetup = <100000000>;
+		nand-on-flash-bbt;
+		gpios = <&gpio 5 19 1>; /* GPO_P3 19, active low */
+
+		mtd0@00000000 {
+			label = "phy3250-boot";
+			reg = <0x00000000 0x00064000>;
+			read-only;
+		};
+
+		...
+
+	};
diff --git a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
new file mode 100644
index 0000000..f1421e2
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
@@ -0,0 +1,31 @@
+PXA3xx NAND DT bindings
+
+Required properties:
+
+ - compatible:		Should be "marvell,pxa3xx-nand"
+ - reg: 		The register base for the controller
+ - interrupts:		The interrupt to map
+ - #address-cells:	Set to <1> if the node includes partitions
+
+Optional properties:
+
+ - marvell,nand-enable-arbiter:	Set to enable the bus arbiter
+ - marvell,nand-keep-config:	Set to keep the NAND controller config as set
+				by the bootloader
+ - num-cs:			Number of chipselect lines to usw
+
+Example:
+
+	nand0: nand@43100000 {
+		compatible = "marvell,pxa3xx-nand";
+		reg = <0x43100000 90>;
+		interrupts = <45>;
+		#address-cells = <1>;
+
+		marvell,nand-enable-arbiter;
+		marvell,nand-keep-config;
+		num-cs = <1>;
+
+		/* partitions (optional) */
+	};
+
diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
new file mode 100644
index 0000000..dcaabe9
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/cpsw.txt
@@ -0,0 +1,109 @@
+TI SoC Ethernet Switch Controller Device Tree Bindings
+------------------------------------------------------
+
+Required properties:
+- compatible		: Should be "ti,cpsw"
+- reg			: physical base address and size of the cpsw
+			  registers map
+- interrupts		: property with a value describing the interrupt
+			  number
+- interrupt-parent	: The parent interrupt controller
+- cpdma_channels 	: Specifies number of channels in CPDMA
+- host_port_no		: Specifies host port shift
+- cpdma_reg_ofs		: Specifies CPDMA submodule register offset
+- cpdma_sram_ofs	: Specifies CPDMA SRAM offset
+- ale_reg_ofs		: Specifies ALE submodule register offset
+- ale_entries		: Specifies No of entries ALE can hold
+- host_port_reg_ofs	: Specifies host port register offset
+- hw_stats_reg_ofs	: Specifies hardware statistics register offset
+- bd_ram_ofs		: Specifies internal desciptor RAM offset
+- bd_ram_size		: Specifies internal descriptor RAM size
+- rx_descs		: Specifies number of Rx descriptors
+- mac_control		: Specifies Default MAC control register content
+			  for the specific platform
+- slaves		: Specifies number for slaves
+- slave_reg_ofs		: Specifies slave register offset
+- sliver_reg_ofs	: Specifies slave sliver register offset
+- phy_id		: Specifies slave phy id
+- mac-address		: Specifies slave MAC address
+
+Optional properties:
+- ti,hwmods		: Must be "cpgmac0"
+- no_bd_ram		: Must be 0 or 1
+
+Note: "ti,hwmods" field is used to fetch the base address and irq
+resources from TI, omap hwmod data base during device registration.
+Future plan is to migrate hwmod data base contents into device tree
+blob so that, all the required data will be used from device tree dts
+file.
+
+Examples:
+
+	mac: ethernet@4A100000 {
+		compatible = "ti,cpsw";
+		reg = <0x4A100000 0x1000>;
+		interrupts = <55 0x4>;
+		interrupt-parent = <&intc>;
+		cpdma_channels = <8>;
+		host_port_no = <0>;
+		cpdma_reg_ofs = <0x800>;
+		cpdma_sram_ofs = <0xa00>;
+		ale_reg_ofs = <0xd00>;
+		ale_entries = <1024>;
+		host_port_reg_ofs = <0x108>;
+		hw_stats_reg_ofs = <0x900>;
+		bd_ram_ofs = <0x2000>;
+		bd_ram_size = <0x2000>;
+		no_bd_ram = <0>;
+		rx_descs = <64>;
+		mac_control = <0x20>;
+		slaves = <2>;
+		cpsw_emac0: slave@0 {
+			slave_reg_ofs = <0x208>;
+			sliver_reg_ofs = <0xd80>;
+			phy_id = "davinci_mdio.16:00";
+			/* Filled in by U-Boot */
+			mac-address = [ 00 00 00 00 00 00 ];
+		};
+		cpsw_emac1: slave@1 {
+			slave_reg_ofs = <0x308>;
+			sliver_reg_ofs = <0xdc0>;
+			phy_id = "davinci_mdio.16:01";
+			/* Filled in by U-Boot */
+			mac-address = [ 00 00 00 00 00 00 ];
+		};
+	};
+
+(or)
+	mac: ethernet@4A100000 {
+		compatible = "ti,cpsw";
+		ti,hwmods = "cpgmac0";
+		cpdma_channels = <8>;
+		host_port_no = <0>;
+		cpdma_reg_ofs = <0x800>;
+		cpdma_sram_ofs = <0xa00>;
+		ale_reg_ofs = <0xd00>;
+		ale_entries = <1024>;
+		host_port_reg_ofs = <0x108>;
+		hw_stats_reg_ofs = <0x900>;
+		bd_ram_ofs = <0x2000>;
+		bd_ram_size = <0x2000>;
+		no_bd_ram = <0>;
+		rx_descs = <64>;
+		mac_control = <0x20>;
+		slaves = <2>;
+		cpsw_emac0: slave@0 {
+			slave_reg_ofs = <0x208>;
+			sliver_reg_ofs = <0xd80>;
+			phy_id = "davinci_mdio.16:00";
+			/* Filled in by U-Boot */
+			mac-address = [ 00 00 00 00 00 00 ];
+		};
+		cpsw_emac1: slave@1 {
+			slave_reg_ofs = <0x308>;
+			sliver_reg_ofs = <0xdc0>;
+			phy_id = "davinci_mdio.16:01";
+			/* Filled in by U-Boot */
+			mac-address = [ 00 00 00 00 00 00 ];
+		};
+	};
diff --git a/Documentation/devicetree/bindings/net/davinci-mdio.txt b/Documentation/devicetree/bindings/net/davinci-mdio.txt
new file mode 100644
index 0000000..72efaaf
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/davinci-mdio.txt
@@ -0,0 +1,33 @@
+TI SoC Davinci MDIO Controller Device Tree Bindings
+---------------------------------------------------
+
+Required properties:
+- compatible		: Should be "ti,davinci_mdio"
+- reg			: physical base address and size of the davinci mdio
+			  registers map
+- bus_freq		: Mdio Bus frequency
+
+Optional properties:
+- ti,hwmods		: Must be "davinci_mdio"
+
+Note: "ti,hwmods" field is used to fetch the base address and irq
+resources from TI, omap hwmod data base during device registration.
+Future plan is to migrate hwmod data base contents into device tree
+blob so that, all the required data will be used from device tree dts
+file.
+
+Examples:
+
+	mdio: davinci_mdio@4A101000 {
+		compatible = "ti,cpsw";
+		reg = <0x4A101000 0x1000>;
+		bus_freq = <1000000>;
+	};
+
+(or)
+
+	mdio: davinci_mdio@4A101000 {
+		compatible = "ti,cpsw";
+		ti,hwmods = "davinci_mdio";
+		bus_freq = <1000000>;
+	};
diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx35-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx35-pinctrl.txt
new file mode 100644
index 0000000..1183f1a
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx35-pinctrl.txt
@@ -0,0 +1,984 @@
+* Freescale IMX35 IOMUX Controller
+
+Please refer to fsl,imx-pinctrl.txt in this directory for common binding part
+and usage.
+
+Required properties:
+- compatible: "fsl,imx35-iomuxc"
+- fsl,pins: two integers array, represents a group of pins mux and config
+  setting. The format is fsl,pins = <PIN_FUNC_ID CONFIG>, PIN_FUNC_ID is a
+  pin working on a specific function, CONFIG is the pad setting value like
+  pull-up for this pin. Please refer to imx35 datasheet for the valid pad
+  config settings.
+
+CONFIG bits definition:
+PAD_CTL_DRIVE_VOLAGAGE_18	(1 << 13)
+PAD_CTL_DRIVE_VOLAGAGE_33	(0 << 13)
+PAD_CTL_HYS			(1 << 8)
+PAD_CTL_PKE			(1 << 7)
+PAD_CTL_PUE			(1 << 6)
+PAD_CTL_PUS_100K_DOWN		(0 << 4)
+PAD_CTL_PUS_47K_UP		(1 << 4)
+PAD_CTL_PUS_100K_UP		(2 << 4)
+PAD_CTL_PUS_22K_UP		(3 << 4)
+PAD_CTL_ODE_CMOS		(0 << 3)
+PAD_CTL_ODE_OPENDRAIN		(1 << 3)
+PAD_CTL_DSE_NOMINAL		(0 << 1)
+PAD_CTL_DSE_HIGH		(1 << 1)
+PAD_CTL_DSE_MAX			(2 << 1)
+PAD_CTL_SRE_FAST		(1 << 0)
+PAD_CTL_SRE_SLOW		(0 << 0)
+
+See below for available PIN_FUNC_ID for imx35:
+0 MX35_PAD_CAPTURE__GPT_CAPIN1
+1 MX35_PAD_CAPTURE__GPT_CMPOUT2
+2 MX35_PAD_CAPTURE__CSPI2_SS1
+3 MX35_PAD_CAPTURE__EPIT1_EPITO
+4 MX35_PAD_CAPTURE__CCM_CLK32K
+5 MX35_PAD_CAPTURE__GPIO1_4
+6 MX35_PAD_COMPARE__GPT_CMPOUT1
+7 MX35_PAD_COMPARE__GPT_CAPIN2
+8 MX35_PAD_COMPARE__GPT_CMPOUT3
+9 MX35_PAD_COMPARE__EPIT2_EPITO
+10 MX35_PAD_COMPARE__GPIO1_5
+11 MX35_PAD_COMPARE__SDMA_EXTDMA_2
+12 MX35_PAD_WDOG_RST__WDOG_WDOG_B
+13 MX35_PAD_WDOG_RST__IPU_FLASH_STROBE
+14 MX35_PAD_WDOG_RST__GPIO1_6
+15 MX35_PAD_GPIO1_0__GPIO1_0
+16 MX35_PAD_GPIO1_0__CCM_PMIC_RDY
+17 MX35_PAD_GPIO1_0__OWIRE_LINE
+18 MX35_PAD_GPIO1_0__SDMA_EXTDMA_0
+19 MX35_PAD_GPIO1_1__GPIO1_1
+20 MX35_PAD_GPIO1_1__PWM_PWMO
+21 MX35_PAD_GPIO1_1__CSPI1_SS2
+22 MX35_PAD_GPIO1_1__SCC_TAMPER_DETECT
+23 MX35_PAD_GPIO1_1__SDMA_EXTDMA_1
+24 MX35_PAD_GPIO2_0__GPIO2_0
+25 MX35_PAD_GPIO2_0__USB_TOP_USBOTG_CLK
+26 MX35_PAD_GPIO3_0__GPIO3_0
+27 MX35_PAD_GPIO3_0__USB_TOP_USBH2_CLK
+28 MX35_PAD_RESET_IN_B__CCM_RESET_IN_B
+29 MX35_PAD_POR_B__CCM_POR_B
+30 MX35_PAD_CLKO__CCM_CLKO
+31 MX35_PAD_CLKO__GPIO1_8
+32 MX35_PAD_BOOT_MODE0__CCM_BOOT_MODE_0
+33 MX35_PAD_BOOT_MODE1__CCM_BOOT_MODE_1
+34 MX35_PAD_CLK_MODE0__CCM_CLK_MODE_0
+35 MX35_PAD_CLK_MODE1__CCM_CLK_MODE_1
+36 MX35_PAD_POWER_FAIL__CCM_DSM_WAKEUP_INT_26
+37 MX35_PAD_VSTBY__CCM_VSTBY
+38 MX35_PAD_VSTBY__GPIO1_7
+39 MX35_PAD_A0__EMI_EIM_DA_L_0
+40 MX35_PAD_A1__EMI_EIM_DA_L_1
+41 MX35_PAD_A2__EMI_EIM_DA_L_2
+42 MX35_PAD_A3__EMI_EIM_DA_L_3
+43 MX35_PAD_A4__EMI_EIM_DA_L_4
+44 MX35_PAD_A5__EMI_EIM_DA_L_5
+45 MX35_PAD_A6__EMI_EIM_DA_L_6
+46 MX35_PAD_A7__EMI_EIM_DA_L_7
+47 MX35_PAD_A8__EMI_EIM_DA_H_8
+48 MX35_PAD_A9__EMI_EIM_DA_H_9
+49 MX35_PAD_A10__EMI_EIM_DA_H_10
+50 MX35_PAD_MA10__EMI_MA10
+51 MX35_PAD_A11__EMI_EIM_DA_H_11
+52 MX35_PAD_A12__EMI_EIM_DA_H_12
+53 MX35_PAD_A13__EMI_EIM_DA_H_13
+54 MX35_PAD_A14__EMI_EIM_DA_H2_14
+55 MX35_PAD_A15__EMI_EIM_DA_H2_15
+56 MX35_PAD_A16__EMI_EIM_A_16
+57 MX35_PAD_A17__EMI_EIM_A_17
+58 MX35_PAD_A18__EMI_EIM_A_18
+59 MX35_PAD_A19__EMI_EIM_A_19
+60 MX35_PAD_A20__EMI_EIM_A_20
+61 MX35_PAD_A21__EMI_EIM_A_21
+62 MX35_PAD_A22__EMI_EIM_A_22
+63 MX35_PAD_A23__EMI_EIM_A_23
+64 MX35_PAD_A24__EMI_EIM_A_24
+65 MX35_PAD_A25__EMI_EIM_A_25
+66 MX35_PAD_SDBA1__EMI_EIM_SDBA1
+67 MX35_PAD_SDBA0__EMI_EIM_SDBA0
+68 MX35_PAD_SD0__EMI_DRAM_D_0
+69 MX35_PAD_SD1__EMI_DRAM_D_1
+70 MX35_PAD_SD2__EMI_DRAM_D_2
+71 MX35_PAD_SD3__EMI_DRAM_D_3
+72 MX35_PAD_SD4__EMI_DRAM_D_4
+73 MX35_PAD_SD5__EMI_DRAM_D_5
+74 MX35_PAD_SD6__EMI_DRAM_D_6
+75 MX35_PAD_SD7__EMI_DRAM_D_7
+76 MX35_PAD_SD8__EMI_DRAM_D_8
+77 MX35_PAD_SD9__EMI_DRAM_D_9
+78 MX35_PAD_SD10__EMI_DRAM_D_10
+79 MX35_PAD_SD11__EMI_DRAM_D_11
+80 MX35_PAD_SD12__EMI_DRAM_D_12
+81 MX35_PAD_SD13__EMI_DRAM_D_13
+82 MX35_PAD_SD14__EMI_DRAM_D_14
+83 MX35_PAD_SD15__EMI_DRAM_D_15
+84 MX35_PAD_SD16__EMI_DRAM_D_16
+85 MX35_PAD_SD17__EMI_DRAM_D_17
+86 MX35_PAD_SD18__EMI_DRAM_D_18
+87 MX35_PAD_SD19__EMI_DRAM_D_19
+88 MX35_PAD_SD20__EMI_DRAM_D_20
+89 MX35_PAD_SD21__EMI_DRAM_D_21
+90 MX35_PAD_SD22__EMI_DRAM_D_22
+91 MX35_PAD_SD23__EMI_DRAM_D_23
+92 MX35_PAD_SD24__EMI_DRAM_D_24
+93 MX35_PAD_SD25__EMI_DRAM_D_25
+94 MX35_PAD_SD26__EMI_DRAM_D_26
+95 MX35_PAD_SD27__EMI_DRAM_D_27
+96 MX35_PAD_SD28__EMI_DRAM_D_28
+97 MX35_PAD_SD29__EMI_DRAM_D_29
+98 MX35_PAD_SD30__EMI_DRAM_D_30
+99 MX35_PAD_SD31__EMI_DRAM_D_31
+100 MX35_PAD_DQM0__EMI_DRAM_DQM_0
+101 MX35_PAD_DQM1__EMI_DRAM_DQM_1
+102 MX35_PAD_DQM2__EMI_DRAM_DQM_2
+103 MX35_PAD_DQM3__EMI_DRAM_DQM_3
+104 MX35_PAD_EB0__EMI_EIM_EB0_B
+105 MX35_PAD_EB1__EMI_EIM_EB1_B
+106 MX35_PAD_OE__EMI_EIM_OE
+107 MX35_PAD_CS0__EMI_EIM_CS0
+108 MX35_PAD_CS1__EMI_EIM_CS1
+109 MX35_PAD_CS1__EMI_NANDF_CE3
+110 MX35_PAD_CS2__EMI_EIM_CS2
+111 MX35_PAD_CS3__EMI_EIM_CS3
+112 MX35_PAD_CS4__EMI_EIM_CS4
+113 MX35_PAD_CS4__EMI_DTACK_B
+114 MX35_PAD_CS4__EMI_NANDF_CE1
+115 MX35_PAD_CS4__GPIO1_20
+116 MX35_PAD_CS5__EMI_EIM_CS5
+117 MX35_PAD_CS5__CSPI2_SS2
+118 MX35_PAD_CS5__CSPI1_SS2
+119 MX35_PAD_CS5__EMI_NANDF_CE2
+120 MX35_PAD_CS5__GPIO1_21
+121 MX35_PAD_NF_CE0__EMI_NANDF_CE0
+122 MX35_PAD_NF_CE0__GPIO1_22
+123 MX35_PAD_ECB__EMI_EIM_ECB
+124 MX35_PAD_LBA__EMI_EIM_LBA
+125 MX35_PAD_BCLK__EMI_EIM_BCLK
+126 MX35_PAD_RW__EMI_EIM_RW
+127 MX35_PAD_RAS__EMI_DRAM_RAS
+128 MX35_PAD_CAS__EMI_DRAM_CAS
+129 MX35_PAD_SDWE__EMI_DRAM_SDWE
+130 MX35_PAD_SDCKE0__EMI_DRAM_SDCKE_0
+131 MX35_PAD_SDCKE1__EMI_DRAM_SDCKE_1
+132 MX35_PAD_SDCLK__EMI_DRAM_SDCLK
+133 MX35_PAD_SDQS0__EMI_DRAM_SDQS_0
+134 MX35_PAD_SDQS1__EMI_DRAM_SDQS_1
+135 MX35_PAD_SDQS2__EMI_DRAM_SDQS_2
+136 MX35_PAD_SDQS3__EMI_DRAM_SDQS_3
+137 MX35_PAD_NFWE_B__EMI_NANDF_WE_B
+138 MX35_PAD_NFWE_B__USB_TOP_USBH2_DATA_3
+139 MX35_PAD_NFWE_B__IPU_DISPB_D0_VSYNC
+140 MX35_PAD_NFWE_B__GPIO2_18
+141 MX35_PAD_NFWE_B__ARM11P_TOP_TRACE_0
+142 MX35_PAD_NFRE_B__EMI_NANDF_RE_B
+143 MX35_PAD_NFRE_B__USB_TOP_USBH2_DIR
+144 MX35_PAD_NFRE_B__IPU_DISPB_BCLK
+145 MX35_PAD_NFRE_B__GPIO2_19
+146 MX35_PAD_NFRE_B__ARM11P_TOP_TRACE_1
+147 MX35_PAD_NFALE__EMI_NANDF_ALE
+148 MX35_PAD_NFALE__USB_TOP_USBH2_STP
+149 MX35_PAD_NFALE__IPU_DISPB_CS0
+150 MX35_PAD_NFALE__GPIO2_20
+151 MX35_PAD_NFALE__ARM11P_TOP_TRACE_2
+152 MX35_PAD_NFCLE__EMI_NANDF_CLE
+153 MX35_PAD_NFCLE__USB_TOP_USBH2_NXT
+154 MX35_PAD_NFCLE__IPU_DISPB_PAR_RS
+155 MX35_PAD_NFCLE__GPIO2_21
+156 MX35_PAD_NFCLE__ARM11P_TOP_TRACE_3
+157 MX35_PAD_NFWP_B__EMI_NANDF_WP_B
+158 MX35_PAD_NFWP_B__USB_TOP_USBH2_DATA_7
+159 MX35_PAD_NFWP_B__IPU_DISPB_WR
+160 MX35_PAD_NFWP_B__GPIO2_22
+161 MX35_PAD_NFWP_B__ARM11P_TOP_TRCTL
+162 MX35_PAD_NFRB__EMI_NANDF_RB
+163 MX35_PAD_NFRB__IPU_DISPB_RD
+164 MX35_PAD_NFRB__GPIO2_23
+165 MX35_PAD_NFRB__ARM11P_TOP_TRCLK
+166 MX35_PAD_D15__EMI_EIM_D_15
+167 MX35_PAD_D14__EMI_EIM_D_14
+168 MX35_PAD_D13__EMI_EIM_D_13
+169 MX35_PAD_D12__EMI_EIM_D_12
+170 MX35_PAD_D11__EMI_EIM_D_11
+171 MX35_PAD_D10__EMI_EIM_D_10
+172 MX35_PAD_D9__EMI_EIM_D_9
+173 MX35_PAD_D8__EMI_EIM_D_8
+174 MX35_PAD_D7__EMI_EIM_D_7
+175 MX35_PAD_D6__EMI_EIM_D_6
+176 MX35_PAD_D5__EMI_EIM_D_5
+177 MX35_PAD_D4__EMI_EIM_D_4
+178 MX35_PAD_D3__EMI_EIM_D_3
+179 MX35_PAD_D2__EMI_EIM_D_2
+180 MX35_PAD_D1__EMI_EIM_D_1
+181 MX35_PAD_D0__EMI_EIM_D_0
+182 MX35_PAD_CSI_D8__IPU_CSI_D_8
+183 MX35_PAD_CSI_D8__KPP_COL_0
+184 MX35_PAD_CSI_D8__GPIO1_20
+185 MX35_PAD_CSI_D8__ARM11P_TOP_EVNTBUS_13
+186 MX35_PAD_CSI_D9__IPU_CSI_D_9
+187 MX35_PAD_CSI_D9__KPP_COL_1
+188 MX35_PAD_CSI_D9__GPIO1_21
+189 MX35_PAD_CSI_D9__ARM11P_TOP_EVNTBUS_14
+190 MX35_PAD_CSI_D10__IPU_CSI_D_10
+191 MX35_PAD_CSI_D10__KPP_COL_2
+192 MX35_PAD_CSI_D10__GPIO1_22
+193 MX35_PAD_CSI_D10__ARM11P_TOP_EVNTBUS_15
+194 MX35_PAD_CSI_D11__IPU_CSI_D_11
+195 MX35_PAD_CSI_D11__KPP_COL_3
+196 MX35_PAD_CSI_D11__GPIO1_23
+197 MX35_PAD_CSI_D12__IPU_CSI_D_12
+198 MX35_PAD_CSI_D12__KPP_ROW_0
+199 MX35_PAD_CSI_D12__GPIO1_24
+200 MX35_PAD_CSI_D13__IPU_CSI_D_13
+201 MX35_PAD_CSI_D13__KPP_ROW_1
+202 MX35_PAD_CSI_D13__GPIO1_25
+203 MX35_PAD_CSI_D14__IPU_CSI_D_14
+204 MX35_PAD_CSI_D14__KPP_ROW_2
+205 MX35_PAD_CSI_D14__GPIO1_26
+206 MX35_PAD_CSI_D15__IPU_CSI_D_15
+207 MX35_PAD_CSI_D15__KPP_ROW_3
+208 MX35_PAD_CSI_D15__GPIO1_27
+209 MX35_PAD_CSI_MCLK__IPU_CSI_MCLK
+210 MX35_PAD_CSI_MCLK__GPIO1_28
+211 MX35_PAD_CSI_VSYNC__IPU_CSI_VSYNC
+212 MX35_PAD_CSI_VSYNC__GPIO1_29
+213 MX35_PAD_CSI_HSYNC__IPU_CSI_HSYNC
+214 MX35_PAD_CSI_HSYNC__GPIO1_30
+215 MX35_PAD_CSI_PIXCLK__IPU_CSI_PIXCLK
+216 MX35_PAD_CSI_PIXCLK__GPIO1_31
+217 MX35_PAD_I2C1_CLK__I2C1_SCL
+218 MX35_PAD_I2C1_CLK__GPIO2_24
+219 MX35_PAD_I2C1_CLK__CCM_USB_BYP_CLK
+220 MX35_PAD_I2C1_DAT__I2C1_SDA
+221 MX35_PAD_I2C1_DAT__GPIO2_25
+222 MX35_PAD_I2C2_CLK__I2C2_SCL
+223 MX35_PAD_I2C2_CLK__CAN1_TXCAN
+224 MX35_PAD_I2C2_CLK__USB_TOP_USBH2_PWR
+225 MX35_PAD_I2C2_CLK__GPIO2_26
+226 MX35_PAD_I2C2_CLK__SDMA_DEBUG_BUS_DEVICE_2
+227 MX35_PAD_I2C2_DAT__I2C2_SDA
+228 MX35_PAD_I2C2_DAT__CAN1_RXCAN
+229 MX35_PAD_I2C2_DAT__USB_TOP_USBH2_OC
+230 MX35_PAD_I2C2_DAT__GPIO2_27
+231 MX35_PAD_I2C2_DAT__SDMA_DEBUG_BUS_DEVICE_3
+232 MX35_PAD_STXD4__AUDMUX_AUD4_TXD
+233 MX35_PAD_STXD4__GPIO2_28
+234 MX35_PAD_STXD4__ARM11P_TOP_ARM_COREASID0
+235 MX35_PAD_SRXD4__AUDMUX_AUD4_RXD
+236 MX35_PAD_SRXD4__GPIO2_29
+237 MX35_PAD_SRXD4__ARM11P_TOP_ARM_COREASID1
+238 MX35_PAD_SCK4__AUDMUX_AUD4_TXC
+239 MX35_PAD_SCK4__GPIO2_30
+240 MX35_PAD_SCK4__ARM11P_TOP_ARM_COREASID2
+241 MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS
+242 MX35_PAD_STXFS4__GPIO2_31
+243 MX35_PAD_STXFS4__ARM11P_TOP_ARM_COREASID3
+244 MX35_PAD_STXD5__AUDMUX_AUD5_TXD
+245 MX35_PAD_STXD5__SPDIF_SPDIF_OUT1
+246 MX35_PAD_STXD5__CSPI2_MOSI
+247 MX35_PAD_STXD5__GPIO1_0
+248 MX35_PAD_STXD5__ARM11P_TOP_ARM_COREASID4
+249 MX35_PAD_SRXD5__AUDMUX_AUD5_RXD
+250 MX35_PAD_SRXD5__SPDIF_SPDIF_IN1
+251 MX35_PAD_SRXD5__CSPI2_MISO
+252 MX35_PAD_SRXD5__GPIO1_1
+253 MX35_PAD_SRXD5__ARM11P_TOP_ARM_COREASID5
+254 MX35_PAD_SCK5__AUDMUX_AUD5_TXC
+255 MX35_PAD_SCK5__SPDIF_SPDIF_EXTCLK
+256 MX35_PAD_SCK5__CSPI2_SCLK
+257 MX35_PAD_SCK5__GPIO1_2
+258 MX35_PAD_SCK5__ARM11P_TOP_ARM_COREASID6
+259 MX35_PAD_STXFS5__AUDMUX_AUD5_TXFS
+260 MX35_PAD_STXFS5__CSPI2_RDY
+261 MX35_PAD_STXFS5__GPIO1_3
+262 MX35_PAD_STXFS5__ARM11P_TOP_ARM_COREASID7
+263 MX35_PAD_SCKR__ESAI_SCKR
+264 MX35_PAD_SCKR__GPIO1_4
+265 MX35_PAD_SCKR__ARM11P_TOP_EVNTBUS_10
+266 MX35_PAD_FSR__ESAI_FSR
+267 MX35_PAD_FSR__GPIO1_5
+268 MX35_PAD_FSR__ARM11P_TOP_EVNTBUS_11
+269 MX35_PAD_HCKR__ESAI_HCKR
+270 MX35_PAD_HCKR__AUDMUX_AUD5_RXFS
+271 MX35_PAD_HCKR__CSPI2_SS0
+272 MX35_PAD_HCKR__IPU_FLASH_STROBE
+273 MX35_PAD_HCKR__GPIO1_6
+274 MX35_PAD_HCKR__ARM11P_TOP_EVNTBUS_12
+275 MX35_PAD_SCKT__ESAI_SCKT
+276 MX35_PAD_SCKT__GPIO1_7
+277 MX35_PAD_SCKT__IPU_CSI_D_0
+278 MX35_PAD_SCKT__KPP_ROW_2
+279 MX35_PAD_FST__ESAI_FST
+280 MX35_PAD_FST__GPIO1_8
+281 MX35_PAD_FST__IPU_CSI_D_1
+282 MX35_PAD_FST__KPP_ROW_3
+283 MX35_PAD_HCKT__ESAI_HCKT
+284 MX35_PAD_HCKT__AUDMUX_AUD5_RXC
+285 MX35_PAD_HCKT__GPIO1_9
+286 MX35_PAD_HCKT__IPU_CSI_D_2
+287 MX35_PAD_HCKT__KPP_COL_3
+288 MX35_PAD_TX5_RX0__ESAI_TX5_RX0
+289 MX35_PAD_TX5_RX0__AUDMUX_AUD4_RXC
+290 MX35_PAD_TX5_RX0__CSPI2_SS2
+291 MX35_PAD_TX5_RX0__CAN2_TXCAN
+292 MX35_PAD_TX5_RX0__UART2_DTR
+293 MX35_PAD_TX5_RX0__GPIO1_10
+294 MX35_PAD_TX5_RX0__EMI_M3IF_CHOSEN_MASTER_0
+295 MX35_PAD_TX4_RX1__ESAI_TX4_RX1
+296 MX35_PAD_TX4_RX1__AUDMUX_AUD4_RXFS
+297 MX35_PAD_TX4_RX1__CSPI2_SS3
+298 MX35_PAD_TX4_RX1__CAN2_RXCAN
+299 MX35_PAD_TX4_RX1__UART2_DSR
+300 MX35_PAD_TX4_RX1__GPIO1_11
+301 MX35_PAD_TX4_RX1__IPU_CSI_D_3
+302 MX35_PAD_TX4_RX1__KPP_ROW_0
+303 MX35_PAD_TX3_RX2__ESAI_TX3_RX2
+304 MX35_PAD_TX3_RX2__I2C3_SCL
+305 MX35_PAD_TX3_RX2__EMI_NANDF_CE1
+306 MX35_PAD_TX3_RX2__GPIO1_12
+307 MX35_PAD_TX3_RX2__IPU_CSI_D_4
+308 MX35_PAD_TX3_RX2__KPP_ROW_1
+309 MX35_PAD_TX2_RX3__ESAI_TX2_RX3
+310 MX35_PAD_TX2_RX3__I2C3_SDA
+311 MX35_PAD_TX2_RX3__EMI_NANDF_CE2
+312 MX35_PAD_TX2_RX3__GPIO1_13
+313 MX35_PAD_TX2_RX3__IPU_CSI_D_5
+314 MX35_PAD_TX2_RX3__KPP_COL_0
+315 MX35_PAD_TX1__ESAI_TX1
+316 MX35_PAD_TX1__CCM_PMIC_RDY
+317 MX35_PAD_TX1__CSPI1_SS2
+318 MX35_PAD_TX1__EMI_NANDF_CE3
+319 MX35_PAD_TX1__UART2_RI
+320 MX35_PAD_TX1__GPIO1_14
+321 MX35_PAD_TX1__IPU_CSI_D_6
+322 MX35_PAD_TX1__KPP_COL_1
+323 MX35_PAD_TX0__ESAI_TX0
+324 MX35_PAD_TX0__SPDIF_SPDIF_EXTCLK
+325 MX35_PAD_TX0__CSPI1_SS3
+326 MX35_PAD_TX0__EMI_DTACK_B
+327 MX35_PAD_TX0__UART2_DCD
+328 MX35_PAD_TX0__GPIO1_15
+329 MX35_PAD_TX0__IPU_CSI_D_7
+330 MX35_PAD_TX0__KPP_COL_2
+331 MX35_PAD_CSPI1_MOSI__CSPI1_MOSI
+332 MX35_PAD_CSPI1_MOSI__GPIO1_16
+333 MX35_PAD_CSPI1_MOSI__ECT_CTI_TRIG_OUT1_2
+334 MX35_PAD_CSPI1_MISO__CSPI1_MISO
+335 MX35_PAD_CSPI1_MISO__GPIO1_17
+336 MX35_PAD_CSPI1_MISO__ECT_CTI_TRIG_OUT1_3
+337 MX35_PAD_CSPI1_SS0__CSPI1_SS0
+338 MX35_PAD_CSPI1_SS0__OWIRE_LINE
+339 MX35_PAD_CSPI1_SS0__CSPI2_SS3
+340 MX35_PAD_CSPI1_SS0__GPIO1_18
+341 MX35_PAD_CSPI1_SS0__ECT_CTI_TRIG_OUT1_4
+342 MX35_PAD_CSPI1_SS1__CSPI1_SS1
+343 MX35_PAD_CSPI1_SS1__PWM_PWMO
+344 MX35_PAD_CSPI1_SS1__CCM_CLK32K
+345 MX35_PAD_CSPI1_SS1__GPIO1_19
+346 MX35_PAD_CSPI1_SS1__IPU_DIAGB_29
+347 MX35_PAD_CSPI1_SS1__ECT_CTI_TRIG_OUT1_5
+348 MX35_PAD_CSPI1_SCLK__CSPI1_SCLK
+349 MX35_PAD_CSPI1_SCLK__GPIO3_4
+350 MX35_PAD_CSPI1_SCLK__IPU_DIAGB_30
+351 MX35_PAD_CSPI1_SCLK__EMI_M3IF_CHOSEN_MASTER_1
+352 MX35_PAD_CSPI1_SPI_RDY__CSPI1_RDY
+353 MX35_PAD_CSPI1_SPI_RDY__GPIO3_5
+354 MX35_PAD_CSPI1_SPI_RDY__IPU_DIAGB_31
+355 MX35_PAD_CSPI1_SPI_RDY__EMI_M3IF_CHOSEN_MASTER_2
+356 MX35_PAD_RXD1__UART1_RXD_MUX
+357 MX35_PAD_RXD1__CSPI2_MOSI
+358 MX35_PAD_RXD1__KPP_COL_4
+359 MX35_PAD_RXD1__GPIO3_6
+360 MX35_PAD_RXD1__ARM11P_TOP_EVNTBUS_16
+361 MX35_PAD_TXD1__UART1_TXD_MUX
+362 MX35_PAD_TXD1__CSPI2_MISO
+363 MX35_PAD_TXD1__KPP_COL_5
+364 MX35_PAD_TXD1__GPIO3_7
+365 MX35_PAD_TXD1__ARM11P_TOP_EVNTBUS_17
+366 MX35_PAD_RTS1__UART1_RTS
+367 MX35_PAD_RTS1__CSPI2_SCLK
+368 MX35_PAD_RTS1__I2C3_SCL
+369 MX35_PAD_RTS1__IPU_CSI_D_0
+370 MX35_PAD_RTS1__KPP_COL_6
+371 MX35_PAD_RTS1__GPIO3_8
+372 MX35_PAD_RTS1__EMI_NANDF_CE1
+373 MX35_PAD_RTS1__ARM11P_TOP_EVNTBUS_18
+374 MX35_PAD_CTS1__UART1_CTS
+375 MX35_PAD_CTS1__CSPI2_RDY
+376 MX35_PAD_CTS1__I2C3_SDA
+377 MX35_PAD_CTS1__IPU_CSI_D_1
+378 MX35_PAD_CTS1__KPP_COL_7
+379 MX35_PAD_CTS1__GPIO3_9
+380 MX35_PAD_CTS1__EMI_NANDF_CE2
+381 MX35_PAD_CTS1__ARM11P_TOP_EVNTBUS_19
+382 MX35_PAD_RXD2__UART2_RXD_MUX
+383 MX35_PAD_RXD2__KPP_ROW_4
+384 MX35_PAD_RXD2__GPIO3_10
+385 MX35_PAD_TXD2__UART2_TXD_MUX
+386 MX35_PAD_TXD2__SPDIF_SPDIF_EXTCLK
+387 MX35_PAD_TXD2__KPP_ROW_5
+388 MX35_PAD_TXD2__GPIO3_11
+389 MX35_PAD_RTS2__UART2_RTS
+390 MX35_PAD_RTS2__SPDIF_SPDIF_IN1
+391 MX35_PAD_RTS2__CAN2_RXCAN
+392 MX35_PAD_RTS2__IPU_CSI_D_2
+393 MX35_PAD_RTS2__KPP_ROW_6
+394 MX35_PAD_RTS2__GPIO3_12
+395 MX35_PAD_RTS2__AUDMUX_AUD5_RXC
+396 MX35_PAD_RTS2__UART3_RXD_MUX
+397 MX35_PAD_CTS2__UART2_CTS
+398 MX35_PAD_CTS2__SPDIF_SPDIF_OUT1
+399 MX35_PAD_CTS2__CAN2_TXCAN
+400 MX35_PAD_CTS2__IPU_CSI_D_3
+401 MX35_PAD_CTS2__KPP_ROW_7
+402 MX35_PAD_CTS2__GPIO3_13
+403 MX35_PAD_CTS2__AUDMUX_AUD5_RXFS
+404 MX35_PAD_CTS2__UART3_TXD_MUX
+405 MX35_PAD_RTCK__ARM11P_TOP_RTCK
+406 MX35_PAD_TCK__SJC_TCK
+407 MX35_PAD_TMS__SJC_TMS
+408 MX35_PAD_TDI__SJC_TDI
+409 MX35_PAD_TDO__SJC_TDO
+410 MX35_PAD_TRSTB__SJC_TRSTB
+411 MX35_PAD_DE_B__SJC_DE_B
+412 MX35_PAD_SJC_MOD__SJC_MOD
+413 MX35_PAD_USBOTG_PWR__USB_TOP_USBOTG_PWR
+414 MX35_PAD_USBOTG_PWR__USB_TOP_USBH2_PWR
+415 MX35_PAD_USBOTG_PWR__GPIO3_14
+416 MX35_PAD_USBOTG_OC__USB_TOP_USBOTG_OC
+417 MX35_PAD_USBOTG_OC__USB_TOP_USBH2_OC
+418 MX35_PAD_USBOTG_OC__GPIO3_15
+419 MX35_PAD_LD0__IPU_DISPB_DAT_0
+420 MX35_PAD_LD0__GPIO2_0
+421 MX35_PAD_LD0__SDMA_SDMA_DEBUG_PC_0
+422 MX35_PAD_LD1__IPU_DISPB_DAT_1
+423 MX35_PAD_LD1__GPIO2_1
+424 MX35_PAD_LD1__SDMA_SDMA_DEBUG_PC_1
+425 MX35_PAD_LD2__IPU_DISPB_DAT_2
+426 MX35_PAD_LD2__GPIO2_2
+427 MX35_PAD_LD2__SDMA_SDMA_DEBUG_PC_2
+428 MX35_PAD_LD3__IPU_DISPB_DAT_3
+429 MX35_PAD_LD3__GPIO2_3
+430 MX35_PAD_LD3__SDMA_SDMA_DEBUG_PC_3
+431 MX35_PAD_LD4__IPU_DISPB_DAT_4
+432 MX35_PAD_LD4__GPIO2_4
+433 MX35_PAD_LD4__SDMA_SDMA_DEBUG_PC_4
+434 MX35_PAD_LD5__IPU_DISPB_DAT_5
+435 MX35_PAD_LD5__GPIO2_5
+436 MX35_PAD_LD5__SDMA_SDMA_DEBUG_PC_5
+437 MX35_PAD_LD6__IPU_DISPB_DAT_6
+438 MX35_PAD_LD6__GPIO2_6
+439 MX35_PAD_LD6__SDMA_SDMA_DEBUG_PC_6
+440 MX35_PAD_LD7__IPU_DISPB_DAT_7
+441 MX35_PAD_LD7__GPIO2_7
+442 MX35_PAD_LD7__SDMA_SDMA_DEBUG_PC_7
+443 MX35_PAD_LD8__IPU_DISPB_DAT_8
+444 MX35_PAD_LD8__GPIO2_8
+445 MX35_PAD_LD8__SDMA_SDMA_DEBUG_PC_8
+446 MX35_PAD_LD9__IPU_DISPB_DAT_9
+447 MX35_PAD_LD9__GPIO2_9
+448 MX35_PAD_LD9__SDMA_SDMA_DEBUG_PC_9
+449 MX35_PAD_LD10__IPU_DISPB_DAT_10
+450 MX35_PAD_LD10__GPIO2_10
+451 MX35_PAD_LD10__SDMA_SDMA_DEBUG_PC_10
+452 MX35_PAD_LD11__IPU_DISPB_DAT_11
+453 MX35_PAD_LD11__GPIO2_11
+454 MX35_PAD_LD11__SDMA_SDMA_DEBUG_PC_11
+455 MX35_PAD_LD11__ARM11P_TOP_TRACE_4
+456 MX35_PAD_LD12__IPU_DISPB_DAT_12
+457 MX35_PAD_LD12__GPIO2_12
+458 MX35_PAD_LD12__SDMA_SDMA_DEBUG_PC_12
+459 MX35_PAD_LD12__ARM11P_TOP_TRACE_5
+460 MX35_PAD_LD13__IPU_DISPB_DAT_13
+461 MX35_PAD_LD13__GPIO2_13
+462 MX35_PAD_LD13__SDMA_SDMA_DEBUG_PC_13
+463 MX35_PAD_LD13__ARM11P_TOP_TRACE_6
+464 MX35_PAD_LD14__IPU_DISPB_DAT_14
+465 MX35_PAD_LD14__GPIO2_14
+466 MX35_PAD_LD14__SDMA_SDMA_DEBUG_EVENT_CHANNEL_0
+467 MX35_PAD_LD14__ARM11P_TOP_TRACE_7
+468 MX35_PAD_LD15__IPU_DISPB_DAT_15
+469 MX35_PAD_LD15__GPIO2_15
+470 MX35_PAD_LD15__SDMA_SDMA_DEBUG_EVENT_CHANNEL_1
+471 MX35_PAD_LD15__ARM11P_TOP_TRACE_8
+472 MX35_PAD_LD16__IPU_DISPB_DAT_16
+473 MX35_PAD_LD16__IPU_DISPB_D12_VSYNC
+474 MX35_PAD_LD16__GPIO2_16
+475 MX35_PAD_LD16__SDMA_SDMA_DEBUG_EVENT_CHANNEL_2
+476 MX35_PAD_LD16__ARM11P_TOP_TRACE_9
+477 MX35_PAD_LD17__IPU_DISPB_DAT_17
+478 MX35_PAD_LD17__IPU_DISPB_CS2
+479 MX35_PAD_LD17__GPIO2_17
+480 MX35_PAD_LD17__SDMA_SDMA_DEBUG_EVENT_CHANNEL_3
+481 MX35_PAD_LD17__ARM11P_TOP_TRACE_10
+482 MX35_PAD_LD18__IPU_DISPB_DAT_18
+483 MX35_PAD_LD18__IPU_DISPB_D0_VSYNC
+484 MX35_PAD_LD18__IPU_DISPB_D12_VSYNC
+485 MX35_PAD_LD18__ESDHC3_CMD
+486 MX35_PAD_LD18__USB_TOP_USBOTG_DATA_3
+487 MX35_PAD_LD18__GPIO3_24
+488 MX35_PAD_LD18__SDMA_SDMA_DEBUG_EVENT_CHANNEL_4
+489 MX35_PAD_LD18__ARM11P_TOP_TRACE_11
+490 MX35_PAD_LD19__IPU_DISPB_DAT_19
+491 MX35_PAD_LD19__IPU_DISPB_BCLK
+492 MX35_PAD_LD19__IPU_DISPB_CS1
+493 MX35_PAD_LD19__ESDHC3_CLK
+494 MX35_PAD_LD19__USB_TOP_USBOTG_DIR
+495 MX35_PAD_LD19__GPIO3_25
+496 MX35_PAD_LD19__SDMA_SDMA_DEBUG_EVENT_CHANNEL_5
+497 MX35_PAD_LD19__ARM11P_TOP_TRACE_12
+498 MX35_PAD_LD20__IPU_DISPB_DAT_20
+499 MX35_PAD_LD20__IPU_DISPB_CS0
+500 MX35_PAD_LD20__IPU_DISPB_SD_CLK
+501 MX35_PAD_LD20__ESDHC3_DAT0
+502 MX35_PAD_LD20__GPIO3_26
+503 MX35_PAD_LD20__SDMA_SDMA_DEBUG_CORE_STATUS_3
+504 MX35_PAD_LD20__ARM11P_TOP_TRACE_13
+505 MX35_PAD_LD21__IPU_DISPB_DAT_21
+506 MX35_PAD_LD21__IPU_DISPB_PAR_RS
+507 MX35_PAD_LD21__IPU_DISPB_SER_RS
+508 MX35_PAD_LD21__ESDHC3_DAT1
+509 MX35_PAD_LD21__USB_TOP_USBOTG_STP
+510 MX35_PAD_LD21__GPIO3_27
+511 MX35_PAD_LD21__SDMA_DEBUG_EVENT_CHANNEL_SEL
+512 MX35_PAD_LD21__ARM11P_TOP_TRACE_14
+513 MX35_PAD_LD22__IPU_DISPB_DAT_22
+514 MX35_PAD_LD22__IPU_DISPB_WR
+515 MX35_PAD_LD22__IPU_DISPB_SD_D_I
+516 MX35_PAD_LD22__ESDHC3_DAT2
+517 MX35_PAD_LD22__USB_TOP_USBOTG_NXT
+518 MX35_PAD_LD22__GPIO3_28
+519 MX35_PAD_LD22__SDMA_DEBUG_BUS_ERROR
+520 MX35_PAD_LD22__ARM11P_TOP_TRCTL
+521 MX35_PAD_LD23__IPU_DISPB_DAT_23
+522 MX35_PAD_LD23__IPU_DISPB_RD
+523 MX35_PAD_LD23__IPU_DISPB_SD_D_IO
+524 MX35_PAD_LD23__ESDHC3_DAT3
+525 MX35_PAD_LD23__USB_TOP_USBOTG_DATA_7
+526 MX35_PAD_LD23__GPIO3_29
+527 MX35_PAD_LD23__SDMA_DEBUG_MATCHED_DMBUS
+528 MX35_PAD_LD23__ARM11P_TOP_TRCLK
+529 MX35_PAD_D3_HSYNC__IPU_DISPB_D3_HSYNC
+530 MX35_PAD_D3_HSYNC__IPU_DISPB_SD_D_IO
+531 MX35_PAD_D3_HSYNC__GPIO3_30
+532 MX35_PAD_D3_HSYNC__SDMA_DEBUG_RTBUFFER_WRITE
+533 MX35_PAD_D3_HSYNC__ARM11P_TOP_TRACE_15
+534 MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK
+535 MX35_PAD_D3_FPSHIFT__IPU_DISPB_SD_CLK
+536 MX35_PAD_D3_FPSHIFT__GPIO3_31
+537 MX35_PAD_D3_FPSHIFT__SDMA_SDMA_DEBUG_CORE_STATUS_0
+538 MX35_PAD_D3_FPSHIFT__ARM11P_TOP_TRACE_16
+539 MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY
+540 MX35_PAD_D3_DRDY__IPU_DISPB_SD_D_O
+541 MX35_PAD_D3_DRDY__GPIO1_0
+542 MX35_PAD_D3_DRDY__SDMA_SDMA_DEBUG_CORE_STATUS_1
+543 MX35_PAD_D3_DRDY__ARM11P_TOP_TRACE_17
+544 MX35_PAD_CONTRAST__IPU_DISPB_CONTR
+545 MX35_PAD_CONTRAST__GPIO1_1
+546 MX35_PAD_CONTRAST__SDMA_SDMA_DEBUG_CORE_STATUS_2
+547 MX35_PAD_CONTRAST__ARM11P_TOP_TRACE_18
+548 MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC
+549 MX35_PAD_D3_VSYNC__IPU_DISPB_CS1
+550 MX35_PAD_D3_VSYNC__GPIO1_2
+551 MX35_PAD_D3_VSYNC__SDMA_DEBUG_YIELD
+552 MX35_PAD_D3_VSYNC__ARM11P_TOP_TRACE_19
+553 MX35_PAD_D3_REV__IPU_DISPB_D3_REV
+554 MX35_PAD_D3_REV__IPU_DISPB_SER_RS
+555 MX35_PAD_D3_REV__GPIO1_3
+556 MX35_PAD_D3_REV__SDMA_DEBUG_BUS_RWB
+557 MX35_PAD_D3_REV__ARM11P_TOP_TRACE_20
+558 MX35_PAD_D3_CLS__IPU_DISPB_D3_CLS
+559 MX35_PAD_D3_CLS__IPU_DISPB_CS2
+560 MX35_PAD_D3_CLS__GPIO1_4
+561 MX35_PAD_D3_CLS__SDMA_DEBUG_BUS_DEVICE_0
+562 MX35_PAD_D3_CLS__ARM11P_TOP_TRACE_21
+563 MX35_PAD_D3_SPL__IPU_DISPB_D3_SPL
+564 MX35_PAD_D3_SPL__IPU_DISPB_D12_VSYNC
+565 MX35_PAD_D3_SPL__GPIO1_5
+566 MX35_PAD_D3_SPL__SDMA_DEBUG_BUS_DEVICE_1
+567 MX35_PAD_D3_SPL__ARM11P_TOP_TRACE_22
+568 MX35_PAD_SD1_CMD__ESDHC1_CMD
+569 MX35_PAD_SD1_CMD__MSHC_SCLK
+570 MX35_PAD_SD1_CMD__IPU_DISPB_D0_VSYNC
+571 MX35_PAD_SD1_CMD__USB_TOP_USBOTG_DATA_4
+572 MX35_PAD_SD1_CMD__GPIO1_6
+573 MX35_PAD_SD1_CMD__ARM11P_TOP_TRCTL
+574 MX35_PAD_SD1_CLK__ESDHC1_CLK
+575 MX35_PAD_SD1_CLK__MSHC_BS
+576 MX35_PAD_SD1_CLK__IPU_DISPB_BCLK
+577 MX35_PAD_SD1_CLK__USB_TOP_USBOTG_DATA_5
+578 MX35_PAD_SD1_CLK__GPIO1_7
+579 MX35_PAD_SD1_CLK__ARM11P_TOP_TRCLK
+580 MX35_PAD_SD1_DATA0__ESDHC1_DAT0
+581 MX35_PAD_SD1_DATA0__MSHC_DATA_0
+582 MX35_PAD_SD1_DATA0__IPU_DISPB_CS0
+583 MX35_PAD_SD1_DATA0__USB_TOP_USBOTG_DATA_6
+584 MX35_PAD_SD1_DATA0__GPIO1_8
+585 MX35_PAD_SD1_DATA0__ARM11P_TOP_TRACE_23
+586 MX35_PAD_SD1_DATA1__ESDHC1_DAT1
+587 MX35_PAD_SD1_DATA1__MSHC_DATA_1
+588 MX35_PAD_SD1_DATA1__IPU_DISPB_PAR_RS
+589 MX35_PAD_SD1_DATA1__USB_TOP_USBOTG_DATA_0
+590 MX35_PAD_SD1_DATA1__GPIO1_9
+591 MX35_PAD_SD1_DATA1__ARM11P_TOP_TRACE_24
+592 MX35_PAD_SD1_DATA2__ESDHC1_DAT2
+593 MX35_PAD_SD1_DATA2__MSHC_DATA_2
+594 MX35_PAD_SD1_DATA2__IPU_DISPB_WR
+595 MX35_PAD_SD1_DATA2__USB_TOP_USBOTG_DATA_1
+596 MX35_PAD_SD1_DATA2__GPIO1_10
+597 MX35_PAD_SD1_DATA2__ARM11P_TOP_TRACE_25
+598 MX35_PAD_SD1_DATA3__ESDHC1_DAT3
+599 MX35_PAD_SD1_DATA3__MSHC_DATA_3
+600 MX35_PAD_SD1_DATA3__IPU_DISPB_RD
+601 MX35_PAD_SD1_DATA3__USB_TOP_USBOTG_DATA_2
+602 MX35_PAD_SD1_DATA3__GPIO1_11
+603 MX35_PAD_SD1_DATA3__ARM11P_TOP_TRACE_26
+604 MX35_PAD_SD2_CMD__ESDHC2_CMD
+605 MX35_PAD_SD2_CMD__I2C3_SCL
+606 MX35_PAD_SD2_CMD__ESDHC1_DAT4
+607 MX35_PAD_SD2_CMD__IPU_CSI_D_2
+608 MX35_PAD_SD2_CMD__USB_TOP_USBH2_DATA_4
+609 MX35_PAD_SD2_CMD__GPIO2_0
+610 MX35_PAD_SD2_CMD__SPDIF_SPDIF_OUT1
+611 MX35_PAD_SD2_CMD__IPU_DISPB_D12_VSYNC
+612 MX35_PAD_SD2_CLK__ESDHC2_CLK
+613 MX35_PAD_SD2_CLK__I2C3_SDA
+614 MX35_PAD_SD2_CLK__ESDHC1_DAT5
+615 MX35_PAD_SD2_CLK__IPU_CSI_D_3
+616 MX35_PAD_SD2_CLK__USB_TOP_USBH2_DATA_5
+617 MX35_PAD_SD2_CLK__GPIO2_1
+618 MX35_PAD_SD2_CLK__SPDIF_SPDIF_IN1
+619 MX35_PAD_SD2_CLK__IPU_DISPB_CS2
+620 MX35_PAD_SD2_DATA0__ESDHC2_DAT0
+621 MX35_PAD_SD2_DATA0__UART3_RXD_MUX
+622 MX35_PAD_SD2_DATA0__ESDHC1_DAT6
+623 MX35_PAD_SD2_DATA0__IPU_CSI_D_4
+624 MX35_PAD_SD2_DATA0__USB_TOP_USBH2_DATA_6
+625 MX35_PAD_SD2_DATA0__GPIO2_2
+626 MX35_PAD_SD2_DATA0__SPDIF_SPDIF_EXTCLK
+627 MX35_PAD_SD2_DATA1__ESDHC2_DAT1
+628 MX35_PAD_SD2_DATA1__UART3_TXD_MUX
+629 MX35_PAD_SD2_DATA1__ESDHC1_DAT7
+630 MX35_PAD_SD2_DATA1__IPU_CSI_D_5
+631 MX35_PAD_SD2_DATA1__USB_TOP_USBH2_DATA_0
+632 MX35_PAD_SD2_DATA1__GPIO2_3
+633 MX35_PAD_SD2_DATA2__ESDHC2_DAT2
+634 MX35_PAD_SD2_DATA2__UART3_RTS
+635 MX35_PAD_SD2_DATA2__CAN1_RXCAN
+636 MX35_PAD_SD2_DATA2__IPU_CSI_D_6
+637 MX35_PAD_SD2_DATA2__USB_TOP_USBH2_DATA_1
+638 MX35_PAD_SD2_DATA2__GPIO2_4
+639 MX35_PAD_SD2_DATA3__ESDHC2_DAT3
+640 MX35_PAD_SD2_DATA3__UART3_CTS
+641 MX35_PAD_SD2_DATA3__CAN1_TXCAN
+642 MX35_PAD_SD2_DATA3__IPU_CSI_D_7
+643 MX35_PAD_SD2_DATA3__USB_TOP_USBH2_DATA_2
+644 MX35_PAD_SD2_DATA3__GPIO2_5
+645 MX35_PAD_ATA_CS0__ATA_CS0
+646 MX35_PAD_ATA_CS0__CSPI1_SS3
+647 MX35_PAD_ATA_CS0__IPU_DISPB_CS1
+648 MX35_PAD_ATA_CS0__GPIO2_6
+649 MX35_PAD_ATA_CS0__IPU_DIAGB_0
+650 MX35_PAD_ATA_CS0__ARM11P_TOP_MAX1_HMASTER_0
+651 MX35_PAD_ATA_CS1__ATA_CS1
+652 MX35_PAD_ATA_CS1__IPU_DISPB_CS2
+653 MX35_PAD_ATA_CS1__CSPI2_SS0
+654 MX35_PAD_ATA_CS1__GPIO2_7
+655 MX35_PAD_ATA_CS1__IPU_DIAGB_1
+656 MX35_PAD_ATA_CS1__ARM11P_TOP_MAX1_HMASTER_1
+657 MX35_PAD_ATA_DIOR__ATA_DIOR
+658 MX35_PAD_ATA_DIOR__ESDHC3_DAT0
+659 MX35_PAD_ATA_DIOR__USB_TOP_USBOTG_DIR
+660 MX35_PAD_ATA_DIOR__IPU_DISPB_BE0
+661 MX35_PAD_ATA_DIOR__CSPI2_SS1
+662 MX35_PAD_ATA_DIOR__GPIO2_8
+663 MX35_PAD_ATA_DIOR__IPU_DIAGB_2
+664 MX35_PAD_ATA_DIOR__ARM11P_TOP_MAX1_HMASTER_2
+665 MX35_PAD_ATA_DIOW__ATA_DIOW
+666 MX35_PAD_ATA_DIOW__ESDHC3_DAT1
+667 MX35_PAD_ATA_DIOW__USB_TOP_USBOTG_STP
+668 MX35_PAD_ATA_DIOW__IPU_DISPB_BE1
+669 MX35_PAD_ATA_DIOW__CSPI2_MOSI
+670 MX35_PAD_ATA_DIOW__GPIO2_9
+671 MX35_PAD_ATA_DIOW__IPU_DIAGB_3
+672 MX35_PAD_ATA_DIOW__ARM11P_TOP_MAX1_HMASTER_3
+673 MX35_PAD_ATA_DMACK__ATA_DMACK
+674 MX35_PAD_ATA_DMACK__ESDHC3_DAT2
+675 MX35_PAD_ATA_DMACK__USB_TOP_USBOTG_NXT
+676 MX35_PAD_ATA_DMACK__CSPI2_MISO
+677 MX35_PAD_ATA_DMACK__GPIO2_10
+678 MX35_PAD_ATA_DMACK__IPU_DIAGB_4
+679 MX35_PAD_ATA_DMACK__ARM11P_TOP_MAX0_HMASTER_0
+680 MX35_PAD_ATA_RESET_B__ATA_RESET_B
+681 MX35_PAD_ATA_RESET_B__ESDHC3_DAT3
+682 MX35_PAD_ATA_RESET_B__USB_TOP_USBOTG_DATA_0
+683 MX35_PAD_ATA_RESET_B__IPU_DISPB_SD_D_O
+684 MX35_PAD_ATA_RESET_B__CSPI2_RDY
+685 MX35_PAD_ATA_RESET_B__GPIO2_11
+686 MX35_PAD_ATA_RESET_B__IPU_DIAGB_5
+687 MX35_PAD_ATA_RESET_B__ARM11P_TOP_MAX0_HMASTER_1
+688 MX35_PAD_ATA_IORDY__ATA_IORDY
+689 MX35_PAD_ATA_IORDY__ESDHC3_DAT4
+690 MX35_PAD_ATA_IORDY__USB_TOP_USBOTG_DATA_1
+691 MX35_PAD_ATA_IORDY__IPU_DISPB_SD_D_IO
+692 MX35_PAD_ATA_IORDY__ESDHC2_DAT4
+693 MX35_PAD_ATA_IORDY__GPIO2_12
+694 MX35_PAD_ATA_IORDY__IPU_DIAGB_6
+695 MX35_PAD_ATA_IORDY__ARM11P_TOP_MAX0_HMASTER_2
+696 MX35_PAD_ATA_DATA0__ATA_DATA_0
+697 MX35_PAD_ATA_DATA0__ESDHC3_DAT5
+698 MX35_PAD_ATA_DATA0__USB_TOP_USBOTG_DATA_2
+699 MX35_PAD_ATA_DATA0__IPU_DISPB_D12_VSYNC
+700 MX35_PAD_ATA_DATA0__ESDHC2_DAT5
+701 MX35_PAD_ATA_DATA0__GPIO2_13
+702 MX35_PAD_ATA_DATA0__IPU_DIAGB_7
+703 MX35_PAD_ATA_DATA0__ARM11P_TOP_MAX0_HMASTER_3
+704 MX35_PAD_ATA_DATA1__ATA_DATA_1
+705 MX35_PAD_ATA_DATA1__ESDHC3_DAT6
+706 MX35_PAD_ATA_DATA1__USB_TOP_USBOTG_DATA_3
+707 MX35_PAD_ATA_DATA1__IPU_DISPB_SD_CLK
+708 MX35_PAD_ATA_DATA1__ESDHC2_DAT6
+709 MX35_PAD_ATA_DATA1__GPIO2_14
+710 MX35_PAD_ATA_DATA1__IPU_DIAGB_8
+711 MX35_PAD_ATA_DATA1__ARM11P_TOP_TRACE_27
+712 MX35_PAD_ATA_DATA2__ATA_DATA_2
+713 MX35_PAD_ATA_DATA2__ESDHC3_DAT7
+714 MX35_PAD_ATA_DATA2__USB_TOP_USBOTG_DATA_4
+715 MX35_PAD_ATA_DATA2__IPU_DISPB_SER_RS
+716 MX35_PAD_ATA_DATA2__ESDHC2_DAT7
+717 MX35_PAD_ATA_DATA2__GPIO2_15
+718 MX35_PAD_ATA_DATA2__IPU_DIAGB_9
+719 MX35_PAD_ATA_DATA2__ARM11P_TOP_TRACE_28
+720 MX35_PAD_ATA_DATA3__ATA_DATA_3
+721 MX35_PAD_ATA_DATA3__ESDHC3_CLK
+722 MX35_PAD_ATA_DATA3__USB_TOP_USBOTG_DATA_5
+723 MX35_PAD_ATA_DATA3__CSPI2_SCLK
+724 MX35_PAD_ATA_DATA3__GPIO2_16
+725 MX35_PAD_ATA_DATA3__IPU_DIAGB_10
+726 MX35_PAD_ATA_DATA3__ARM11P_TOP_TRACE_29
+727 MX35_PAD_ATA_DATA4__ATA_DATA_4
+728 MX35_PAD_ATA_DATA4__ESDHC3_CMD
+729 MX35_PAD_ATA_DATA4__USB_TOP_USBOTG_DATA_6
+730 MX35_PAD_ATA_DATA4__GPIO2_17
+731 MX35_PAD_ATA_DATA4__IPU_DIAGB_11
+732 MX35_PAD_ATA_DATA4__ARM11P_TOP_TRACE_30
+733 MX35_PAD_ATA_DATA5__ATA_DATA_5
+734 MX35_PAD_ATA_DATA5__USB_TOP_USBOTG_DATA_7
+735 MX35_PAD_ATA_DATA5__GPIO2_18
+736 MX35_PAD_ATA_DATA5__IPU_DIAGB_12
+737 MX35_PAD_ATA_DATA5__ARM11P_TOP_TRACE_31
+738 MX35_PAD_ATA_DATA6__ATA_DATA_6
+739 MX35_PAD_ATA_DATA6__CAN1_TXCAN
+740 MX35_PAD_ATA_DATA6__UART1_DTR
+741 MX35_PAD_ATA_DATA6__AUDMUX_AUD6_TXD
+742 MX35_PAD_ATA_DATA6__GPIO2_19
+743 MX35_PAD_ATA_DATA6__IPU_DIAGB_13
+744 MX35_PAD_ATA_DATA7__ATA_DATA_7
+745 MX35_PAD_ATA_DATA7__CAN1_RXCAN
+746 MX35_PAD_ATA_DATA7__UART1_DSR
+747 MX35_PAD_ATA_DATA7__AUDMUX_AUD6_RXD
+748 MX35_PAD_ATA_DATA7__GPIO2_20
+749 MX35_PAD_ATA_DATA7__IPU_DIAGB_14
+750 MX35_PAD_ATA_DATA8__ATA_DATA_8
+751 MX35_PAD_ATA_DATA8__UART3_RTS
+752 MX35_PAD_ATA_DATA8__UART1_RI
+753 MX35_PAD_ATA_DATA8__AUDMUX_AUD6_TXC
+754 MX35_PAD_ATA_DATA8__GPIO2_21
+755 MX35_PAD_ATA_DATA8__IPU_DIAGB_15
+756 MX35_PAD_ATA_DATA9__ATA_DATA_9
+757 MX35_PAD_ATA_DATA9__UART3_CTS
+758 MX35_PAD_ATA_DATA9__UART1_DCD
+759 MX35_PAD_ATA_DATA9__AUDMUX_AUD6_TXFS
+760 MX35_PAD_ATA_DATA9__GPIO2_22
+761 MX35_PAD_ATA_DATA9__IPU_DIAGB_16
+762 MX35_PAD_ATA_DATA10__ATA_DATA_10
+763 MX35_PAD_ATA_DATA10__UART3_RXD_MUX
+764 MX35_PAD_ATA_DATA10__AUDMUX_AUD6_RXC
+765 MX35_PAD_ATA_DATA10__GPIO2_23
+766 MX35_PAD_ATA_DATA10__IPU_DIAGB_17
+767 MX35_PAD_ATA_DATA11__ATA_DATA_11
+768 MX35_PAD_ATA_DATA11__UART3_TXD_MUX
+769 MX35_PAD_ATA_DATA11__AUDMUX_AUD6_RXFS
+770 MX35_PAD_ATA_DATA11__GPIO2_24
+771 MX35_PAD_ATA_DATA11__IPU_DIAGB_18
+772 MX35_PAD_ATA_DATA12__ATA_DATA_12
+773 MX35_PAD_ATA_DATA12__I2C3_SCL
+774 MX35_PAD_ATA_DATA12__GPIO2_25
+775 MX35_PAD_ATA_DATA12__IPU_DIAGB_19
+776 MX35_PAD_ATA_DATA13__ATA_DATA_13
+777 MX35_PAD_ATA_DATA13__I2C3_SDA
+778 MX35_PAD_ATA_DATA13__GPIO2_26
+779 MX35_PAD_ATA_DATA13__IPU_DIAGB_20
+780 MX35_PAD_ATA_DATA14__ATA_DATA_14
+781 MX35_PAD_ATA_DATA14__IPU_CSI_D_0
+782 MX35_PAD_ATA_DATA14__KPP_ROW_0
+783 MX35_PAD_ATA_DATA14__GPIO2_27
+784 MX35_PAD_ATA_DATA14__IPU_DIAGB_21
+785 MX35_PAD_ATA_DATA15__ATA_DATA_15
+786 MX35_PAD_ATA_DATA15__IPU_CSI_D_1
+787 MX35_PAD_ATA_DATA15__KPP_ROW_1
+788 MX35_PAD_ATA_DATA15__GPIO2_28
+789 MX35_PAD_ATA_DATA15__IPU_DIAGB_22
+790 MX35_PAD_ATA_INTRQ__ATA_INTRQ
+791 MX35_PAD_ATA_INTRQ__IPU_CSI_D_2
+792 MX35_PAD_ATA_INTRQ__KPP_ROW_2
+793 MX35_PAD_ATA_INTRQ__GPIO2_29
+794 MX35_PAD_ATA_INTRQ__IPU_DIAGB_23
+795 MX35_PAD_ATA_BUFF_EN__ATA_BUFFER_EN
+796 MX35_PAD_ATA_BUFF_EN__IPU_CSI_D_3
+797 MX35_PAD_ATA_BUFF_EN__KPP_ROW_3
+798 MX35_PAD_ATA_BUFF_EN__GPIO2_30
+799 MX35_PAD_ATA_BUFF_EN__IPU_DIAGB_24
+800 MX35_PAD_ATA_DMARQ__ATA_DMARQ
+801 MX35_PAD_ATA_DMARQ__IPU_CSI_D_4
+802 MX35_PAD_ATA_DMARQ__KPP_COL_0
+803 MX35_PAD_ATA_DMARQ__GPIO2_31
+804 MX35_PAD_ATA_DMARQ__IPU_DIAGB_25
+805 MX35_PAD_ATA_DMARQ__ECT_CTI_TRIG_IN1_4
+806 MX35_PAD_ATA_DA0__ATA_DA_0
+807 MX35_PAD_ATA_DA0__IPU_CSI_D_5
+808 MX35_PAD_ATA_DA0__KPP_COL_1
+809 MX35_PAD_ATA_DA0__GPIO3_0
+810 MX35_PAD_ATA_DA0__IPU_DIAGB_26
+811 MX35_PAD_ATA_DA0__ECT_CTI_TRIG_IN1_5
+812 MX35_PAD_ATA_DA1__ATA_DA_1
+813 MX35_PAD_ATA_DA1__IPU_CSI_D_6
+814 MX35_PAD_ATA_DA1__KPP_COL_2
+815 MX35_PAD_ATA_DA1__GPIO3_1
+816 MX35_PAD_ATA_DA1__IPU_DIAGB_27
+817 MX35_PAD_ATA_DA1__ECT_CTI_TRIG_IN1_6
+818 MX35_PAD_ATA_DA2__ATA_DA_2
+819 MX35_PAD_ATA_DA2__IPU_CSI_D_7
+820 MX35_PAD_ATA_DA2__KPP_COL_3
+821 MX35_PAD_ATA_DA2__GPIO3_2
+822 MX35_PAD_ATA_DA2__IPU_DIAGB_28
+823 MX35_PAD_ATA_DA2__ECT_CTI_TRIG_IN1_7
+824 MX35_PAD_MLB_CLK__MLB_MLBCLK
+825 MX35_PAD_MLB_CLK__GPIO3_3
+826 MX35_PAD_MLB_DAT__MLB_MLBDAT
+827 MX35_PAD_MLB_DAT__GPIO3_4
+828 MX35_PAD_MLB_SIG__MLB_MLBSIG
+829 MX35_PAD_MLB_SIG__GPIO3_5
+830 MX35_PAD_FEC_TX_CLK__FEC_TX_CLK
+831 MX35_PAD_FEC_TX_CLK__ESDHC1_DAT4
+832 MX35_PAD_FEC_TX_CLK__UART3_RXD_MUX
+833 MX35_PAD_FEC_TX_CLK__USB_TOP_USBH2_DIR
+834 MX35_PAD_FEC_TX_CLK__CSPI2_MOSI
+835 MX35_PAD_FEC_TX_CLK__GPIO3_6
+836 MX35_PAD_FEC_TX_CLK__IPU_DISPB_D12_VSYNC
+837 MX35_PAD_FEC_TX_CLK__ARM11P_TOP_EVNTBUS_0
+838 MX35_PAD_FEC_RX_CLK__FEC_RX_CLK
+839 MX35_PAD_FEC_RX_CLK__ESDHC1_DAT5
+840 MX35_PAD_FEC_RX_CLK__UART3_TXD_MUX
+841 MX35_PAD_FEC_RX_CLK__USB_TOP_USBH2_STP
+842 MX35_PAD_FEC_RX_CLK__CSPI2_MISO
+843 MX35_PAD_FEC_RX_CLK__GPIO3_7
+844 MX35_PAD_FEC_RX_CLK__IPU_DISPB_SD_D_I
+845 MX35_PAD_FEC_RX_CLK__ARM11P_TOP_EVNTBUS_1
+846 MX35_PAD_FEC_RX_DV__FEC_RX_DV
+847 MX35_PAD_FEC_RX_DV__ESDHC1_DAT6
+848 MX35_PAD_FEC_RX_DV__UART3_RTS
+849 MX35_PAD_FEC_RX_DV__USB_TOP_USBH2_NXT
+850 MX35_PAD_FEC_RX_DV__CSPI2_SCLK
+851 MX35_PAD_FEC_RX_DV__GPIO3_8
+852 MX35_PAD_FEC_RX_DV__IPU_DISPB_SD_CLK
+853 MX35_PAD_FEC_RX_DV__ARM11P_TOP_EVNTBUS_2
+854 MX35_PAD_FEC_COL__FEC_COL
+855 MX35_PAD_FEC_COL__ESDHC1_DAT7
+856 MX35_PAD_FEC_COL__UART3_CTS
+857 MX35_PAD_FEC_COL__USB_TOP_USBH2_DATA_0
+858 MX35_PAD_FEC_COL__CSPI2_RDY
+859 MX35_PAD_FEC_COL__GPIO3_9
+860 MX35_PAD_FEC_COL__IPU_DISPB_SER_RS
+861 MX35_PAD_FEC_COL__ARM11P_TOP_EVNTBUS_3
+862 MX35_PAD_FEC_RDATA0__FEC_RDATA_0
+863 MX35_PAD_FEC_RDATA0__PWM_PWMO
+864 MX35_PAD_FEC_RDATA0__UART3_DTR
+865 MX35_PAD_FEC_RDATA0__USB_TOP_USBH2_DATA_1
+866 MX35_PAD_FEC_RDATA0__CSPI2_SS0
+867 MX35_PAD_FEC_RDATA0__GPIO3_10
+868 MX35_PAD_FEC_RDATA0__IPU_DISPB_CS1
+869 MX35_PAD_FEC_RDATA0__ARM11P_TOP_EVNTBUS_4
+870 MX35_PAD_FEC_TDATA0__FEC_TDATA_0
+871 MX35_PAD_FEC_TDATA0__SPDIF_SPDIF_OUT1
+872 MX35_PAD_FEC_TDATA0__UART3_DSR
+873 MX35_PAD_FEC_TDATA0__USB_TOP_USBH2_DATA_2
+874 MX35_PAD_FEC_TDATA0__CSPI2_SS1
+875 MX35_PAD_FEC_TDATA0__GPIO3_11
+876 MX35_PAD_FEC_TDATA0__IPU_DISPB_CS0
+877 MX35_PAD_FEC_TDATA0__ARM11P_TOP_EVNTBUS_5
+878 MX35_PAD_FEC_TX_EN__FEC_TX_EN
+879 MX35_PAD_FEC_TX_EN__SPDIF_SPDIF_IN1
+880 MX35_PAD_FEC_TX_EN__UART3_RI
+881 MX35_PAD_FEC_TX_EN__USB_TOP_USBH2_DATA_3
+882 MX35_PAD_FEC_TX_EN__GPIO3_12
+883 MX35_PAD_FEC_TX_EN__IPU_DISPB_PAR_RS
+884 MX35_PAD_FEC_TX_EN__ARM11P_TOP_EVNTBUS_6
+885 MX35_PAD_FEC_MDC__FEC_MDC
+886 MX35_PAD_FEC_MDC__CAN2_TXCAN
+887 MX35_PAD_FEC_MDC__UART3_DCD
+888 MX35_PAD_FEC_MDC__USB_TOP_USBH2_DATA_4
+889 MX35_PAD_FEC_MDC__GPIO3_13
+890 MX35_PAD_FEC_MDC__IPU_DISPB_WR
+891 MX35_PAD_FEC_MDC__ARM11P_TOP_EVNTBUS_7
+892 MX35_PAD_FEC_MDIO__FEC_MDIO
+893 MX35_PAD_FEC_MDIO__CAN2_RXCAN
+894 MX35_PAD_FEC_MDIO__USB_TOP_USBH2_DATA_5
+895 MX35_PAD_FEC_MDIO__GPIO3_14
+896 MX35_PAD_FEC_MDIO__IPU_DISPB_RD
+897 MX35_PAD_FEC_MDIO__ARM11P_TOP_EVNTBUS_8
+898 MX35_PAD_FEC_TX_ERR__FEC_TX_ERR
+899 MX35_PAD_FEC_TX_ERR__OWIRE_LINE
+900 MX35_PAD_FEC_TX_ERR__SPDIF_SPDIF_EXTCLK
+901 MX35_PAD_FEC_TX_ERR__USB_TOP_USBH2_DATA_6
+902 MX35_PAD_FEC_TX_ERR__GPIO3_15
+903 MX35_PAD_FEC_TX_ERR__IPU_DISPB_D0_VSYNC
+904 MX35_PAD_FEC_TX_ERR__ARM11P_TOP_EVNTBUS_9
+905 MX35_PAD_FEC_RX_ERR__FEC_RX_ERR
+906 MX35_PAD_FEC_RX_ERR__IPU_CSI_D_0
+907 MX35_PAD_FEC_RX_ERR__USB_TOP_USBH2_DATA_7
+908 MX35_PAD_FEC_RX_ERR__KPP_COL_4
+909 MX35_PAD_FEC_RX_ERR__GPIO3_16
+910 MX35_PAD_FEC_RX_ERR__IPU_DISPB_SD_D_IO
+911 MX35_PAD_FEC_CRS__FEC_CRS
+912 MX35_PAD_FEC_CRS__IPU_CSI_D_1
+913 MX35_PAD_FEC_CRS__USB_TOP_USBH2_PWR
+914 MX35_PAD_FEC_CRS__KPP_COL_5
+915 MX35_PAD_FEC_CRS__GPIO3_17
+916 MX35_PAD_FEC_CRS__IPU_FLASH_STROBE
+917 MX35_PAD_FEC_RDATA1__FEC_RDATA_1
+918 MX35_PAD_FEC_RDATA1__IPU_CSI_D_2
+919 MX35_PAD_FEC_RDATA1__AUDMUX_AUD6_RXC
+920 MX35_PAD_FEC_RDATA1__USB_TOP_USBH2_OC
+921 MX35_PAD_FEC_RDATA1__KPP_COL_6
+922 MX35_PAD_FEC_RDATA1__GPIO3_18
+923 MX35_PAD_FEC_RDATA1__IPU_DISPB_BE0
+924 MX35_PAD_FEC_TDATA1__FEC_TDATA_1
+925 MX35_PAD_FEC_TDATA1__IPU_CSI_D_3
+926 MX35_PAD_FEC_TDATA1__AUDMUX_AUD6_RXFS
+927 MX35_PAD_FEC_TDATA1__KPP_COL_7
+928 MX35_PAD_FEC_TDATA1__GPIO3_19
+929 MX35_PAD_FEC_TDATA1__IPU_DISPB_BE1
+930 MX35_PAD_FEC_RDATA2__FEC_RDATA_2
+931 MX35_PAD_FEC_RDATA2__IPU_CSI_D_4
+932 MX35_PAD_FEC_RDATA2__AUDMUX_AUD6_TXD
+933 MX35_PAD_FEC_RDATA2__KPP_ROW_4
+934 MX35_PAD_FEC_RDATA2__GPIO3_20
+935 MX35_PAD_FEC_TDATA2__FEC_TDATA_2
+936 MX35_PAD_FEC_TDATA2__IPU_CSI_D_5
+937 MX35_PAD_FEC_TDATA2__AUDMUX_AUD6_RXD
+938 MX35_PAD_FEC_TDATA2__KPP_ROW_5
+939 MX35_PAD_FEC_TDATA2__GPIO3_21
+940 MX35_PAD_FEC_RDATA3__FEC_RDATA_3
+941 MX35_PAD_FEC_RDATA3__IPU_CSI_D_6
+942 MX35_PAD_FEC_RDATA3__AUDMUX_AUD6_TXC
+943 MX35_PAD_FEC_RDATA3__KPP_ROW_6
+944 MX35_PAD_FEC_RDATA3__GPIO3_22
+945 MX35_PAD_FEC_TDATA3__FEC_TDATA_3
+946 MX35_PAD_FEC_TDATA3__IPU_CSI_D_7
+947 MX35_PAD_FEC_TDATA3__AUDMUX_AUD6_TXFS
+948 MX35_PAD_FEC_TDATA3__KPP_ROW_7
+949 MX35_PAD_FEC_TDATA3__GPIO3_23
+950 MX35_PAD_EXT_ARMCLK__CCM_EXT_ARMCLK
+951 MX35_PAD_TEST_MODE__TCU_TEST_MODE
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt b/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt
index 939a26d..d5e3704 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt
+++ b/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt
@@ -12,9 +12,12 @@ Properties:
 - #size-cells : Either one or two, depending on how large each chipselect
                 can be.
 - reg : Offset and length of the register set for the device
-- interrupts : IFC has two interrupts. The first one is the "common"
-               interrupt(CM_EVTER_STAT), and second is the NAND interrupt
-               (NAND_EVTER_STAT).
+- interrupts: IFC may have one or two interrupts.  If two interrupt
+              specifiers are present, the first is the "common"
+              interrupt (CM_EVTER_STAT), and the second is the NAND
+              interrupt (NAND_EVTER_STAT).  If there is only one,
+              that interrupt reports both types of event.
+
 
 - ranges : Each range corresponds to a single chipselect, and covers
            the entire access window as configured.
diff --git a/Documentation/devicetree/bindings/regulator/tps6586x.txt b/Documentation/devicetree/bindings/regulator/tps6586x.txt
index d156e1b..4d1218f 100644
--- a/Documentation/devicetree/bindings/regulator/tps6586x.txt
+++ b/Documentation/devicetree/bindings/regulator/tps6586x.txt
@@ -9,6 +9,10 @@ Required properties:
 - regulators: list of regulators provided by this controller, must have
   property "regulator-compatible" to match their hardware counterparts:
   sm[0-2], ldo[0-9] and ldo_rtc
+- vin-sm0-supply: The input supply for the SM0.
+- vin-sm1-supply: The input supply for the SM1.
+- vin-sm2-supply: The input supply for the SM2.
+- sys-supply: The input supply for SYS.
 - sm0-supply: The input supply for the SM0.
 - sm1-supply: The input supply for the SM1.
 - sm2-supply: The input supply for the SM2.
@@ -20,6 +24,9 @@ Required properties:
 
 Each regulator is defined using the standard binding for regulators.
 
+Note: LDO5 and LDO_RTC is supplied by SYS regulator internally and driver
+      take care of making proper parent child relationship.
+
 Example:
 
 	pmu: tps6586x@34 {
@@ -30,9 +37,9 @@ Example:
 		#gpio-cells = <2>;
 		gpio-controller;
 
-		sm0-supply = <&some_reg>;
-		sm1-supply = <&some_reg>;
-		sm2-supply = <&some_reg>;
+		vin-sm0-supply = <&some_reg>;
+		vin-sm1-supply = <&some_reg>;
+		vin-sm2-supply = <&some_reg>;
 		vinldo01-supply = <...>;
 		vinldo23-supply = <...>;
 		vinldo4-supply = <...>;
@@ -43,8 +50,16 @@ Example:
 			#address-cells = <1>;
 			#size-cells = <0>;
 
-			sm0_reg: regulator@0 {
+			sys_reg: regulator@0 {
 				reg = <0>;
+				regulator-compatible = "sys";
+				regulator-name = "vdd_sys";
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			sm0_reg: regulator@1 {
+				reg = <1>;
 				regulator-compatible = "sm0";
 				regulator-min-microvolt = < 725000>;
 				regulator-max-microvolt = <1500000>;
@@ -52,8 +67,8 @@ Example:
 				regulator-always-on;
 			};
 
-			sm1_reg: regulator@1 {
-				reg = <1>;
+			sm1_reg: regulator@2 {
+				reg = <2>;
 				regulator-compatible = "sm1";
 				regulator-min-microvolt = < 725000>;
 				regulator-max-microvolt = <1500000>;
@@ -61,8 +76,8 @@ Example:
 				regulator-always-on;
 			};
 
-			sm2_reg: regulator@2 {
-				reg = <2>;
+			sm2_reg: regulator@3 {
+				reg = <3>;
 				regulator-compatible = "sm2";
 				regulator-min-microvolt = <3000000>;
 				regulator-max-microvolt = <4550000>;
@@ -70,72 +85,72 @@ Example:
 				regulator-always-on;
 			};
 
-			ldo0_reg: regulator@3 {
-				reg = <3>;
+			ldo0_reg: regulator@4 {
+				reg = <4>;
 				regulator-compatible = "ldo0";
 				regulator-name = "PCIE CLK";
 				regulator-min-microvolt = <3300000>;
 				regulator-max-microvolt = <3300000>;
 			};
 
-			ldo1_reg: regulator@4 {
-				reg = <4>;
+			ldo1_reg: regulator@5 {
+				reg = <5>;
 				regulator-compatible = "ldo1";
 				regulator-min-microvolt = < 725000>;
 				regulator-max-microvolt = <1500000>;
 			};
 
-			ldo2_reg: regulator@5 {
-				reg = <5>;
+			ldo2_reg: regulator@6 {
+				reg = <6>;
 				regulator-compatible = "ldo2";
 				regulator-min-microvolt = < 725000>;
 				regulator-max-microvolt = <1500000>;
 			};
 
-			ldo3_reg: regulator@6 {
-				reg = <6>;
+			ldo3_reg: regulator@7 {
+				reg = <7>;
 				regulator-compatible = "ldo3";
 				regulator-min-microvolt = <1250000>;
 				regulator-max-microvolt = <3300000>;
 			};
 
-			ldo4_reg: regulator@7 {
-				reg = <7>;
+			ldo4_reg: regulator@8 {
+				reg = <8>;
 				regulator-compatible = "ldo4";
 				regulator-min-microvolt = <1700000>;
 				regulator-max-microvolt = <2475000>;
 			};
 
-			ldo5_reg: regulator@8 {
-				reg = <8>;
+			ldo5_reg: regulator@9 {
+				reg = <9>;
 				regulator-compatible = "ldo5";
 				regulator-min-microvolt = <1250000>;
 				regulator-max-microvolt = <3300000>;
 			};
 
-			ldo6_reg: regulator@9 {
-				reg = <9>;
+			ldo6_reg: regulator@10 {
+				reg = <10>;
 				regulator-compatible = "ldo6";
 				regulator-min-microvolt = <1250000>;
 				regulator-max-microvolt = <3300000>;
 			};
 
-			ldo7_reg: regulator@10 {
-				reg = <10>;
+			ldo7_reg: regulator@11 {
+				reg = <11>;
 				regulator-compatible = "ldo7";
 				regulator-min-microvolt = <1250000>;
 				regulator-max-microvolt = <3300000>;
 			};
 
-			ldo8_reg: regulator@11 {
-				reg = <11>;
+			ldo8_reg: regulator@12 {
+				reg = <12>;
 				regulator-compatible = "ldo8";
 				regulator-min-microvolt = <1250000>;
 				regulator-max-microvolt = <3300000>;
 			};
 
-			ldo9_reg: regulator@12 {
-				reg = <12>;
+			ldo9_reg: regulator@13 {
+				reg = <13>;
 				regulator-compatible = "ldo9";
 				regulator-min-microvolt = <1250000>;
 				regulator-max-microvolt = <3300000>;
diff --git a/Documentation/devicetree/bindings/rtc/pxa-rtc.txt b/Documentation/devicetree/bindings/rtc/pxa-rtc.txt
new file mode 100644
index 0000000..8c6672a
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/pxa-rtc.txt
@@ -0,0 +1,14 @@
+* PXA RTC
+
+PXA specific RTC driver.
+
+Required properties:
+- compatible : Should be "marvell,pxa-rtc"
+
+Examples:
+
+rtc@40900000 {
+	compatible = "marvell,pxa-rtc";
+	reg = <0x40900000 0x3c>;
+	interrupts = <30 31>;
+};
diff --git a/Documentation/devicetree/bindings/sound/cs4270.txt b/Documentation/devicetree/bindings/sound/cs4270.txt
new file mode 100644
index 0000000..6b222f9
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/cs4270.txt
@@ -0,0 +1,21 @@
+CS4270 audio CODEC
+
+The driver for this device currently only supports I2C.
+
+Required properties:
+
+  - compatible : "cirrus,cs4270"
+
+  - reg : the I2C address of the device for I2C
+
+Optional properties:
+
+  - reset-gpio : a GPIO spec for the reset pin. If specified, it will be
+		 deasserted before communication to the codec starts.
+
+Example:
+
+codec: cs4270@48 {
+	compatible = "cirrus,cs4270";
+	reg = <0x48>;
+};
diff --git a/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt b/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt
new file mode 100644
index 0000000..65dec87
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt
@@ -0,0 +1,91 @@
+* Texas Instruments OMAP4+ and twl6040 based audio setups
+
+Required properties:
+- compatible: "ti,abe-twl6040"
+- ti,model: Name of the sound card ( for example "SDP4430")
+- ti,mclk-freq: MCLK frequency for HPPLL operation
+- ti,mcpdm: phandle for the McPDM node
+- ti,twl6040: phandle for the twl6040 core node
+- ti,audio-routing: List of connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source.
+
+Optional properties:
+- ti,dmic: phandle for the OMAP dmic node if the machine have it connected
+- ti,jack_detection: Need to be set to <1> if the board capable to detect jack
+  insertion, removal.
+
+Available audio endpoints for the audio-routing table:
+
+Board connectors:
+ * Headset Stereophone
+ * Earphone Spk
+ * Ext Spk
+ * Line Out
+ * Vibrator
+ * Headset Mic
+ * Main Handset Mic
+ * Sub Handset Mic
+ * Line In
+ * Digital Mic
+
+twl6040 pins:
+ * HSOL
+ * HSOR
+ * EP
+ * HFL
+ * HFR
+ * AUXL
+ * AUXR
+ * VIBRAL
+ * VIBRAR
+ * HSMIC
+ * MAINMIC
+ * SUBMIC
+ * AFML
+ * AFMR
+
+ * Headset Mic Bias
+ * Main Mic Bias
+ * Digital Mic1 Bias
+ * Digital Mic2 Bias
+
+Digital mic pins:
+ * DMic
+
+Example:
+
+sound {
+	compatible = "ti,abe-twl6040";
+	ti,model = "SDP4430";
+
+	ti,jack-detection = <1>;
+	ti,mclk-freq = <38400000>;
+
+	ti,mcpdm = <&mcpdm>;
+	ti,dmic = <&dmic>;
+
+	ti,twl6040 = <&twl6040>;
+
+	/* Audio routing */
+	ti,audio-routing =
+		"Headset Stereophone", "HSOL",
+		"Headset Stereophone", "HSOR",
+		"Earphone Spk", "EP",
+		"Ext Spk", "HFL",
+		"Ext Spk", "HFR",
+		"Line Out", "AUXL",
+		"Line Out", "AUXR",
+		"Vibrator", "VIBRAL",
+		"Vibrator", "VIBRAR",
+		"HSMIC", "Headset Mic",
+		"Headset Mic", "Headset Mic Bias",
+		"MAINMIC", "Main Handset Mic",
+		"Main Handset Mic", "Main Mic Bias",
+		"SUBMIC", "Sub Handset Mic",
+		"Sub Handset Mic", "Main Mic Bias",
+		"AFML", "Line In",
+		"AFMR", "Line In",
+		"DMic", "Digital Mic",
+		"Digital Mic", "Digital Mic1 Bias";
+};
diff --git a/Documentation/devicetree/bindings/sound/omap-twl4030.txt b/Documentation/devicetree/bindings/sound/omap-twl4030.txt
new file mode 100644
index 0000000..6fae51c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/omap-twl4030.txt
@@ -0,0 +1,17 @@
+* Texas Instruments SoC with twl4030 based audio setups
+
+Required properties:
+- compatible: "ti,omap-twl4030"
+- ti,model: Name of the sound card (for example "omap3beagle")
+- ti,mcbsp: phandle for the McBSP node
+- ti,codec: phandle for the twl4030 audio node
+
+Example:
+
+sound {
+	compatible = "ti,omap-twl4030";
+	ti,model = "omap3beagle";
+
+	ti,mcbsp = <&mcbsp2>;
+	ti,codec = <&twl_audio>;
+};
diff --git a/Documentation/devicetree/bindings/spi/mxs-spi.txt b/Documentation/devicetree/bindings/spi/mxs-spi.txt
new file mode 100644
index 0000000..c36296f
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/mxs-spi.txt
@@ -0,0 +1,18 @@
+* Freescale MX233/MX28 SSP/SPI
+
+Required properties:
+- compatible: Should be "fsl,<soc>-spi", where soc is "imx23" or "imx28"
+- reg: Offset and length of the register set for the device
+- interrupts: Should contain SSP interrupts (error irq first, dma irq second)
+- fsl,ssp-dma-channel: APBX DMA channel for the SSP
+
+Example:
+
+ssp0: ssp@80010000 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	compatible = "fsl,imx28-spi";
+	reg = <0x80010000 0x2000>;
+	interrupts = <96 82>;
+	fsl,ssp-dma-channel = <0>;
+};
diff --git a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
new file mode 100644
index 0000000..801d58c
--- /dev/null
+++ b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
@@ -0,0 +1,15 @@
+* Freescale i.MX28 LRADC device driver
+
+Required properties:
+- compatible: Should be "fsl,imx28-lradc"
+- reg: Address and length of the register set for the device
+- interrupts: Should contain the LRADC interrupts
+
+Examples:
+
+	lradc@80050000 {
+		compatible = "fsl,imx28-lradc";
+		reg = <0x80050000 0x2000>;
+		interrupts = <10 14 15 16 17 18 19
+				20 21 22 23 24 25>;
+	};
diff --git a/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt b/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt
new file mode 100644
index 0000000..0d439df
--- /dev/null
+++ b/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt
@@ -0,0 +1,14 @@
+* NXP LPC32xx SoC High Speed UART
+
+Required properties:
+- compatible: Should be "nxp,lpc3220-hsuart"
+- reg: Should contain registers location and length
+- interrupts: Should contain interrupt
+
+Example:
+
+	uart1: serial@40014000 {
+		compatible = "nxp,lpc3220-hsuart";
+		reg = <0x40014000 0x1000>;
+		interrupts = <26 0>;
+	};
diff --git a/Documentation/devicetree/bindings/tty/serial/of-serial.txt b/Documentation/devicetree/bindings/tty/serial/of-serial.txt
index 0847fde..ba385f2 100644
--- a/Documentation/devicetree/bindings/tty/serial/of-serial.txt
+++ b/Documentation/devicetree/bindings/tty/serial/of-serial.txt
@@ -25,6 +25,8 @@ Optional properties:
   accesses to the UART (e.g. TI davinci).
 - used-by-rtas : set to indicate that the port is in use by the OpenFirmware
   RTAS and should not be registered.
+- no-loopback-test: set to indicate that the port does not implements loopback
+  test mode
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/usb/platform-uhci.txt b/Documentation/devicetree/bindings/usb/platform-uhci.txt
new file mode 100644
index 0000000..91477d6
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/platform-uhci.txt
@@ -0,0 +1,12 @@
+Generic Platform UHCI controllers.
+
+Required properties:
+ - compatible: Should be "platform-uhci".
+ - reg: Address range of the uhci registers
+ - interrupts: Should contain the uhci interrupt.
+
+usb: uhci@D8007301 {
+	compatible = "platform-uhci", "usb-uhci";
+	reg = <0xD8007301 0x200>;
+	interrupts = <0>;
+};
diff --git a/Documentation/devicetree/bindings/usb/pxa-usb.txt b/Documentation/devicetree/bindings/usb/pxa-usb.txt
new file mode 100644
index 0000000..79729a9
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/pxa-usb.txt
@@ -0,0 +1,31 @@
+PXA USB controllers
+
+OHCI
+
+Required properties:
+ - compatible: Should be "marvell,pxa-ohci" for USB controllers
+   used in host mode.
+
+Optional properties:
+ - "marvell,enable-port1", "marvell,enable-port2", "marvell,enable-port3"
+   If present, enables the appropriate USB port of the controller.
+ - "marvell,port-mode" selects the mode of the ports:
+	1 = PMM_NPS_MODE
+	2 = PMM_GLOBAL_MODE
+	3 = PMM_PERPORT_MODE
+ - "marvell,power-sense-low" - power sense pin is low-active.
+ - "marvell,power-control-low" - power control pin is low-active.
+ - "marvell,no-oc-protection" - disable over-current protection.
+ - "marvell,oc-mode-perport" - enable per-port over-current protection.
+ - "marvell,power_on_delay" Power On to Power Good time - in ms.
+
+Example:
+
+	usb0: ohci@4c000000 {
+		compatible = "marvell,pxa-ohci", "usb-ohci";
+		reg = <0x4c000000 0x100000>;
+		interrupts = <18>;
+		marvell,enable-port1;
+		marvell,port-mode = <2>; /* PMM_GLOBAL_MODE */
+	};
+
diff --git a/Documentation/devicetree/bindings/usb/vt8500-ehci.txt b/Documentation/devicetree/bindings/usb/vt8500-ehci.txt
new file mode 100644
index 0000000..5fb8fd6
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/vt8500-ehci.txt
@@ -0,0 +1,12 @@
+VIA VT8500 and Wondermedia WM8xxx SoC USB controllers.
+
+Required properties:
+ - compatible: Should be "via,vt8500-ehci" or "wm,prizm-ehci".
+ - reg: Address range of the ehci registers. size should be 0x200
+ - interrupts: Should contain the ehci interrupt.
+
+usb: ehci@D8007100 {
+	compatible = "wm,prizm-ehci", "usb-ehci";
+	reg = <0xD8007100 0x200>;
+	interrupts = <1>;
+};
diff --git a/Documentation/devicetree/bindings/w1/w1-gpio.txt b/Documentation/devicetree/bindings/w1/w1-gpio.txt
new file mode 100644
index 0000000..6e09c35
--- /dev/null
+++ b/Documentation/devicetree/bindings/w1/w1-gpio.txt
@@ -0,0 +1,22 @@
+w1-gpio devicetree bindings
+
+Required properties:
+
+ - compatible: "w1-gpio"
+ - gpios: one or two GPIO specs:
+		- the first one is used as data I/O pin
+		- the second one is optional. If specified, it is used as
+		  enable pin for an external pin pullup.
+
+Optional properties:
+
+ - linux,open-drain: if specified, the data pin is considered in
+		     open-drain mode.
+
+Examples:
+
+	onewire@0 {
+		compatible = "w1-gpio";
+		gpios = <&gpio 126 0>, <&gpio 105 0>;
+	};
+
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index 950856b..43cff70 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -284,3 +284,7 @@ CLOCK
 PINCTRL
   devm_pinctrl_get()
   devm_pinctrl_put()
+
+PWM
+  devm_pwm_get()
+  devm_pwm_put()
diff --git a/Documentation/dvb/README.dvb-usb b/Documentation/dvb/README.dvb-usb
index c4d963a..8eb9226 100644
--- a/Documentation/dvb/README.dvb-usb
+++ b/Documentation/dvb/README.dvb-usb
@@ -30,7 +30,7 @@ with the device via the bus. The connection between the DVB-API-functionality
 is done via callbacks, assigned in a static device-description (struct
 dvb_usb_device) each device-driver has to have.
 
-For an example have a look in drivers/media/dvb/dvb-usb/vp7045*.
+For an example have a look in drivers/media/usb/dvb-usb/vp7045*.
 
 Objective is to migrate all the usb-devices (dibusb, cinergyT2, maybe the
 ttusb; flexcop-usb already benefits from the generic flexcop-device) to use
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index afaff31..a52924e 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -6,6 +6,15 @@ be removed from this file.  The suggested deprecation period is 3 releases.
 
 ---------------------------
 
+What:	support for i.mx25 in mx2_camera.c
+When:	v3.8
+Why:	it's been broken for a year. Furthermore, i.MX25 video capture
+	HW doesn't have much in common with i.MX27. A separate driver
+	will be needed for it.
+Who:	Javier Martin<javier.martin@vista-silicon.com>
+
+---------------------------
+
 What:	ddebug_query="query" boot cmdline param
 When:	v3.8
 Why:	obsoleted by dyndbg="query" and module.dyndbg="query"
diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt
index 1b7f9ac..104322b 100644
--- a/Documentation/filesystems/ext4.txt
+++ b/Documentation/filesystems/ext4.txt
@@ -375,6 +375,16 @@ dioread_nolock		locking. If the dioread_nolock option is specified
 			Because of the restrictions this options comprises
 			it is off by default (e.g. dioread_lock).
 
+max_dir_size_kb=n	This limits the size of directories so that any
+			attempt to expand them beyond the specified
+			limit in kilobytes will cause an ENOSPC error.
+			This is useful in memory constrained
+			environments, where a very large directory can
+			cause severe performance problems or even
+			provoke the Out Of Memory killer.  (For example,
+			if there is only 512mb memory available, a 176mb
+			directory may seriously cramp the system's style.)
+
 i_version		Enable 64-bit inode version support. This option is
 			off by default.
 
diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt
index ead764b..de1e6c4 100644
--- a/Documentation/filesystems/vfat.txt
+++ b/Documentation/filesystems/vfat.txt
@@ -137,6 +137,17 @@ errors=panic|continue|remount-ro
 		 without doing anything or remount the partition in
 		 read-only mode (default behavior).
 
+discard       -- If set, issues discard/TRIM commands to the block
+		 device when blocks are freed. This is useful for SSD devices
+		 and sparse/thinly-provisoned LUNs.
+
+nfs           -- This option maintains an index (cache) of directory
+		 inodes by i_logstart which is used by the nfs-related code to
+		 improve look-ups.
+
+		 Enable this only if you want to export the FAT filesystem
+		 over NFS
+
 <bool>: 0,1,yes,no,true,false
 
 TODO
diff --git a/Documentation/hwmon/adt7410 b/Documentation/hwmon/adt7410
new file mode 100644
index 0000000..9600400
--- /dev/null
+++ b/Documentation/hwmon/adt7410
@@ -0,0 +1,51 @@
+Kernel driver adt7410
+=====================
+
+Supported chips:
+  * Analog Devices ADT7410
+    Prefix: 'adt7410'
+    Addresses scanned: I2C 0x48 - 0x4B
+    Datasheet: Publicly available at the Analog Devices website
+               http://www.analog.com/static/imported-files/data_sheets/ADT7410.pdf
+
+Author: Hartmut Knaack <knaack.h@gmx.de>
+
+Description
+-----------
+
+The ADT7410 is a temperature sensor with rated temperature range of -55°C to
++150°C. It has a high accuracy of +/-0.5°C and can be operated at a resolution
+of 13 bits (0.0625°C) or 16 bits (0.0078°C). The sensor provides an INT pin to
+indicate that a minimum or maximum temperature set point has been exceeded, as
+well as a critical temperature (CT) pin to indicate that the critical
+temperature set point has been exceeded. Both pins can be set up with a common
+hysteresis of 0°C - 15°C and a fault queue, ranging from 1 to 4 events. Both
+pins can individually set to be active-low or active-high, while the whole
+device can either run in comparator mode or interrupt mode. The ADT7410
+supports continous temperature sampling, as well as sampling one temperature
+value per second or even justget one sample on demand for power saving.
+Besides, it can completely power down its ADC, if power management is
+required.
+
+Configuration Notes
+-------------------
+
+Since the device uses one hysteresis value, which is an offset to minimum,
+maximum and critical temperature, it can only be set for temp#_max_hyst.
+However, temp#_min_hyst and temp#_crit_hyst show their corresponding
+hysteresis.
+The device is set to 16 bit resolution and comparator mode.
+
+sysfs-Interface
+---------------
+
+temp#_input		- temperature input
+temp#_min		- temperature minimum setpoint
+temp#_max		- temperature maximum setpoint
+temp#_crit		- critical temperature setpoint
+temp#_min_hyst		- hysteresis for temperature minimum (read-only)
+temp#_max_hyst		- hysteresis for temperature maximum (read/write)
+temp#_crit_hyst		- hysteresis for critical temperature (read-only)
+temp#_min_alarm		- temperature minimum alarm flag
+temp#_max_alarm		- temperature maximum alarm flag
+temp#_crit_alarm	- critical temperature alarm flag
diff --git a/Documentation/hwmon/exynos4_tmu b/Documentation/hwmon/exynos4_tmu
deleted file mode 100644
index c3c6b41..0000000
--- a/Documentation/hwmon/exynos4_tmu
+++ /dev/null
@@ -1,81 +0,0 @@
-Kernel driver exynos4_tmu
-=================
-
-Supported chips:
-* ARM SAMSUNG EXYNOS4 series of SoC
-  Prefix: 'exynos4-tmu'
-  Datasheet: Not publicly available
-
-Authors: Donggeun Kim <dg77.kim@samsung.com>
-
-Description
------------
-
-This driver allows to read temperature inside SAMSUNG EXYNOS4 series of SoC.
-
-The chip only exposes the measured 8-bit temperature code value
-through a register.
-Temperature can be taken from the temperature code.
-There are three equations converting from temperature to temperature code.
-
-The three equations are:
-  1. Two point trimming
-	Tc = (T - 25) * (TI2 - TI1) / (85 - 25) + TI1
-
-  2. One point trimming
-	Tc = T + TI1 - 25
-
-  3. No trimming
-	Tc = T + 50
-
-  Tc: Temperature code, T: Temperature,
-  TI1: Trimming info for 25 degree Celsius (stored at TRIMINFO register)
-       Temperature code measured at 25 degree Celsius which is unchanged
-  TI2: Trimming info for 85 degree Celsius (stored at TRIMINFO register)
-       Temperature code measured at 85 degree Celsius which is unchanged
-
-TMU(Thermal Management Unit) in EXYNOS4 generates interrupt
-when temperature exceeds pre-defined levels.
-The maximum number of configurable threshold is four.
-The threshold levels are defined as follows:
-  Level_0: current temperature > trigger_level_0 + threshold
-  Level_1: current temperature > trigger_level_1 + threshold
-  Level_2: current temperature > trigger_level_2 + threshold
-  Level_3: current temperature > trigger_level_3 + threshold
-
-  The threshold and each trigger_level are set
-  through the corresponding registers.
-
-When an interrupt occurs, this driver notify user space of
-one of four threshold levels for the interrupt
-through kobject_uevent_env and sysfs_notify functions.
-Although an interrupt condition for level_0 can be set,
-it is not notified to user space through sysfs_notify function.
-
-Sysfs Interface
----------------
-name		name of the temperature sensor
-		RO
-
-temp1_input	temperature
-		RO
-
-temp1_max	temperature for level_1 interrupt
-		RO
-
-temp1_crit	temperature for level_2 interrupt
-		RO
-
-temp1_emergency	temperature for level_3 interrupt
-		RO
-
-temp1_max_alarm	alarm for level_1 interrupt
-		RO
-
-temp1_crit_alarm
-		alarm for level_2 interrupt
-		RO
-
-temp1_emergency_alarm
-		alarm for level_3 interrupt
-		RO
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 849b771..2152b0e 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -178,7 +178,6 @@ Code  Seq#(hex)	Include File		Comments
 'V'	C0	linux/ivtv.h		conflict!
 'V'	C0	media/davinci/vpfe_capture.h	conflict!
 'V'	C0	media/si4713.h		conflict!
-'V'	C0-CF	drivers/media/video/mxb.h	conflict!
 'W'	00-1F	linux/watchdog.h	conflict!
 'W'	00-1F	linux/wanrouter.h	conflict!
 'W'	00-3F	sound/asound.h		conflict!
@@ -204,8 +203,6 @@ Code  Seq#(hex)	Include File		Comments
 'c'	A0-AF   arch/x86/include/asm/msr.h	conflict!
 'd'	00-FF	linux/char/drm/drm/h	conflict!
 'd'	02-40	pcmcia/ds.h		conflict!
-'d'	10-3F	drivers/media/video/dabusb.h	conflict!
-'d'	C0-CF	drivers/media/video/saa7191.h	conflict!
 'd'	F0-FF	linux/digi1.h
 'e'	all	linux/digi1.h		conflict!
 'e'	00-1F	drivers/net/irda/irtty-sir.h	conflict!
@@ -267,9 +264,7 @@ Code  Seq#(hex)	Include File		Comments
 'v'	00-1F	linux/ext2_fs.h		conflict!
 'v'	00-1F	linux/fs.h		conflict!
 'v'	00-0F	linux/sonypi.h		conflict!
-'v'	C0-DF	media/pwc-ioctl.h	conflict!
 'v'	C0-FF	linux/meye.h		conflict!
-'v'	D0-DF	drivers/media/video/cpia2/cpia2dev.h	conflict!
 'w'	all				CERN SCI driver
 'y'	00-1F				packet based user level communications
 					<mailto:zapman@interlan.net>
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index ad7e2e5..a3740ac 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1350,6 +1350,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			* nohrst, nosrst, norst: suppress hard, soft
                           and both resets.
 
+			* rstonce: only attempt one reset during
+			  hot-unplug link recovery
+
 			* dump_id: dump IDENTIFY data.
 
 			If there are multiple matching configurations changing
@@ -2385,6 +2388,17 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 	rcutree.rcu_cpu_stall_timeout= [KNL,BOOT]
 			Set timeout for RCU CPU stall warning messages.
 
+	rcutree.jiffies_till_first_fqs= [KNL,BOOT]
+			Set delay from grace-period initialization to
+			first attempt to force quiescent states.
+			Units are jiffies, minimum value is zero,
+			and maximum value is HZ.
+
+	rcutree.jiffies_till_next_fqs= [KNL,BOOT]
+			Set delay between subsequent attempts to force
+			quiescent states.  Units are jiffies, minimum
+			value is one, and maximum value is HZ.
+
 	rcutorture.fqs_duration= [KNL,BOOT]
 			Set duration of force_quiescent_state bursts.
 
diff --git a/Documentation/networking/netconsole.txt b/Documentation/networking/netconsole.txt
index 8d02207..2e9e0ae2 100644
--- a/Documentation/networking/netconsole.txt
+++ b/Documentation/networking/netconsole.txt
@@ -51,8 +51,23 @@ Built-in netconsole starts immediately after the TCP stack is
 initialized and attempts to bring up the supplied dev at the supplied
 address.
 
-The remote host can run either 'netcat -u -l -p <port>',
-'nc -l -u <port>' or syslogd.
+The remote host has several options to receive the kernel messages,
+for example:
+
+1) syslogd
+
+2) netcat
+
+   On distributions using a BSD-based netcat version (e.g. Fedora,
+   openSUSE and Ubuntu) the listening port must be specified without
+   the -p switch:
+
+   'nc -u -l -p <port>' / 'nc -u -l <port>' or
+   'netcat -u -l -p <port>' / 'netcat -u -l <port>'
+
+3) socat
+
+   'socat udp-recv:<port> -'
 
 Dynamic reconfiguration:
 ========================
diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
index e40f4b4..1479aca 100644
--- a/Documentation/pinctrl.txt
+++ b/Documentation/pinctrl.txt
@@ -840,9 +840,9 @@ static unsigned long i2c_pin_configs[] = {
 
 static struct pinctrl_map __initdata mapping[] = {
 	PIN_MAP_MUX_GROUP("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0", "i2c0"),
-	PIN_MAP_MUX_CONFIGS_GROUP("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0", i2c_grp_configs),
-	PIN_MAP_MUX_CONFIGS_PIN("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0scl", i2c_pin_configs),
-	PIN_MAP_MUX_CONFIGS_PIN("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0sda", i2c_pin_configs),
+	PIN_MAP_CONFIGS_GROUP("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0", i2c_grp_configs),
+	PIN_MAP_CONFIGS_PIN("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0scl", i2c_pin_configs),
+	PIN_MAP_CONFIGS_PIN("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0sda", i2c_pin_configs),
 };
 
 Finally, some devices expect the mapping table to contain certain specific
diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt
index 554290e..7d2b4c9 100644
--- a/Documentation/pwm.txt
+++ b/Documentation/pwm.txt
@@ -36,7 +36,8 @@ Legacy users can request a PWM device using pwm_request() and free it
 after usage with pwm_free().
 
 New users should use the pwm_get() function and pass to it the consumer
-device or a consumer name. pwm_put() is used to free the PWM device.
+device or a consumer name. pwm_put() is used to free the PWM device. Managed
+variants of these functions, devm_pwm_get() and devm_pwm_put(), also exist.
 
 After being requested a PWM has to be configured using:
 
diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
index 80441ab..3a30794 100644
--- a/Documentation/scsi/ChangeLog.megaraid_sas
+++ b/Documentation/scsi/ChangeLog.megaraid_sas
@@ -1,3 +1,13 @@
+Release Date    : Tue. Jun 17, 2012 17:00:00 PST 2012 -
+			(emaild-id:megaraidlinux@lsi.com)
+			Adam Radford/Kashyap Desai
+Current Version : 00.00.06.18-rc1
+Old Version     : 00.00.06.15-rc1
+    1. Fix Copyright dates.
+    2. Add throttlequeuedepth module parameter.
+    3. Add resetwaittime module parameter.
+    4. Move poll_aen_lock initializer.
+-------------------------------------------------------------------------------
 Release Date    : Mon. Mar 19, 2012 17:00:00 PST 2012 -
 			(emaild-id:megaraidlinux@lsi.com)
 			Adam Radford
diff --git a/Documentation/serial/00-INDEX b/Documentation/serial/00-INDEX
index e09468a..f7b0c7d 100644
--- a/Documentation/serial/00-INDEX
+++ b/Documentation/serial/00-INDEX
@@ -2,8 +2,6 @@
 	- this file.
 README.cycladesZ
 	- info on Cyclades-Z firmware loading.
-computone.txt
-	- info on Computone Intelliport II/Plus Multiport Serial Driver.
 digiepca.txt
 	- info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
 hayes-esp.txt
diff --git a/Documentation/serial/computone.txt b/Documentation/serial/computone.txt
deleted file mode 100644
index a6a1158..0000000
--- a/Documentation/serial/computone.txt
+++ /dev/null
@@ -1,520 +0,0 @@
-NOTE: This is an unmaintained driver.  It is not guaranteed to work due to
-changes made in the tty layer in 2.6.  If you wish to take over maintenance of
-this driver, contact Michael Warfield <mhw@wittsend.com>.
-
-Changelog:
-----------
-11-01-2001:	Original Document
-
-10-29-2004:	Minor misspelling & format fix, update status of driver.
-		James Nelson <james4765@gmail.com>
-
-Computone Intelliport II/Plus Multiport Serial Driver
------------------------------------------------------
-
-Release Notes For Linux Kernel 2.2 and higher.
-These notes are for the drivers which have already been integrated into the
-kernel and have been tested on Linux kernels 2.0, 2.2, 2.3, and 2.4.
-
-Version: 1.2.14
-Date: 11/01/2001
-Historical Author: Andrew Manison <amanison@america.net>
-Primary Author: Doug McNash
-
-This file assumes that you are using the Computone drivers which are
-integrated into the kernel sources.  For updating the drivers or installing
-drivers into kernels which do not already have Computone drivers, please
-refer to the instructions in the README.computone file in the driver patch.
-
-
-1. INTRODUCTION
-
-This driver supports the entire family of Intelliport II/Plus controllers
-with the exception of the MicroChannel controllers.  It does not support
-products previous to the Intelliport II.
-
-This driver was developed on the v2.0.x Linux tree and has been tested up
-to v2.4.14; it will probably not work with earlier v1.X kernels,.
-
-
-2. QUICK INSTALLATION
-
-Hardware - If you have an ISA card, find a free interrupt and io port. 
-		   List those in use with `cat /proc/interrupts` and 
-		   `cat /proc/ioports`.  Set the card dip switches to a free 
-		   address.  You may need to configure your BIOS to reserve an
-		   irq for an ISA card.  PCI and EISA parameters are set
-		   automagically.  Insert card into computer with the power off 
-		   before or after drivers installation.
-
-	Note the hardware address from the Computone ISA cards installed into
-		the system.  These are required for editing ip2.c or editing
-		/etc/modprobe.d/*.conf, or for specification on the modprobe
-		command line.
-
-	Note that the /etc/modules.conf should be used for older (pre-2.6)
-		kernels.
-
-Software -
-
-Module installation:
-
-a) Determine free irq/address to use if any (configure BIOS if need be)
-b) Run "make config" or "make menuconfig" or "make xconfig"
-   Select (m) module for CONFIG_COMPUTONE under character
-   devices.  CONFIG_PCI and CONFIG_MODULES also may need to be set.
-c) Set address on ISA cards then:
-   edit /usr/src/linux/drivers/char/ip2.c if needed 
-	or
-   edit config file in  /etc/modprobe.d/ if needed (module).
-	or both to match this setting.
-d) Run "make modules"
-e) Run "make modules_install"
-f) Run "/sbin/depmod -a"
-g) install driver using `modprobe ip2 <options>` (options listed below)
-h) run ip2mkdev (either the script below or the binary version)
-
-
-Kernel installation:
-
-a) Determine free irq/address to use if any (configure BIOS if need be)
-b) Run "make config" or "make menuconfig" or "make xconfig"
-   Select (y) kernel for CONFIG_COMPUTONE under character
-   devices.  CONFIG_PCI may need to be set if you have PCI bus.
-c) Set address on ISA cards then:
-	   edit /usr/src/linux/drivers/char/ip2.c  
-           (Optional - may be specified on kernel command line now)
-d) Run "make zImage" or whatever target you prefer.
-e) mv /usr/src/linux/arch/x86/boot/zImage to /boot.
-f) Add new config for this kernel into /etc/lilo.conf, run "lilo"
-	or copy to a floppy disk and boot from that floppy disk.
-g) Reboot using this kernel
-h) run ip2mkdev (either the script below or the binary version)
-
-Kernel command line options:
-
-When compiling the driver into the kernel, io and irq may be
-compiled into the driver by editing ip2.c and setting the values for
-io and irq in the appropriate array.  An alternative is to specify
-a command line parameter to the kernel at boot up.
-
-        ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
-
-Note that this order is very different from the specifications for the
-modload parameters which have separate IRQ and IO specifiers.
-
-The io port also selects PCI (1) and EISA (2) boards.
-
-        io=0    No board
-        io=1    PCI board
-        io=2    EISA board
-        else    ISA board io address
-
-You only need to specify the boards which are present.
-
-        Examples:
-
-                2 PCI boards:
-
-                        ip2=1,0,1,0
-
-                1 ISA board at 0x310 irq 5:
-
-                        ip2=0x310,5
-
-This can be added to and "append" option in lilo.conf similar to this:
-
-        append="ip2=1,0,1,0"
-
-
-3. INSTALLATION
-
-Previously, the driver sources were packaged with a set of patch files
-to update the character drivers' makefile and configuration file, and other 
-kernel source files. A build script (ip2build) was included which applies 
-the patches if needed, and build any utilities needed.
-What you receive may be a single patch file in conventional kernel
-patch format build script. That form can also be applied by
-running patch -p1 < ThePatchFile.  Otherwise run ip2build.
- 
-The driver can be installed as a module (recommended) or built into the 
-kernel. This is selected as for other drivers through the `make config`
-command from the root of the Linux source tree. If the driver is built 
-into the kernel you will need to edit the file ip2.c to match the boards 
-you are installing. See that file for instructions. If the driver is 
-installed as a module the configuration can also be specified on the
-modprobe command line as follows:
-
-	modprobe ip2 irq=irq1,irq2,irq3,irq4 io=addr1,addr2,addr3,addr4
-
-where irqnum is one of the valid Intelliport II interrupts (3,4,5,7,10,11,
-12,15) and addr1-4 are the base addresses for up to four controllers. If 
-the irqs are not specified the driver uses the default in ip2.c (which 
-selects polled mode). If no base addresses are specified the defaults in 
-ip2.c are used. If you are autoloading the driver module with kerneld or
-kmod the base addresses and interrupt number must also be set in ip2.c
-and recompile or just insert and options line in /etc/modprobe.d/*.conf or both.
-The options line is equivalent to the command line and takes precedence over
-what is in ip2.c. 
-
-config sample to put /etc/modprobe.d/*.conf:
-	options ip2 io=1,0x328 irq=1,10
-	alias char-major-71 ip2
-	alias char-major-72 ip2
-	alias char-major-73 ip2
-
-The equivalent in ip2.c:
-
-static int io[IP2_MAX_BOARDS]= { 1, 0x328, 0, 0 };
-static int irq[IP2_MAX_BOARDS] = { 1, 10, -1, -1 }; 
-
-The equivalent for the kernel command line (in lilo.conf):
-
-        append="ip2=1,1,0x328,10"
-
-
-Note:	Both io and irq should be updated to reflect YOUR system.  An "io"
-	address of 1 or 2 indicates a PCI or EISA card in the board table.
-	The PCI or EISA irq will be assigned automatically.
-
-Specifying an invalid or in-use irq will default the driver into
-running in polled mode for that card.  If all irq entries are 0 then
-all cards will operate in polled mode.
-
-If you select the driver as part of the kernel run :
-
-	make zlilo (or whatever you do to create a bootable kernel)
-
-If you selected a module run :
-
-	make modules && make modules_install
-
-The utility ip2mkdev (see 5 and 7 below) creates all the device nodes
-required by the driver.  For a device to be created it must be configured
-in the driver and the board must be installed. Only devices corresponding
-to real IntelliPort II ports are created. With multiple boards and expansion
-boxes this will leave gaps in the sequence of device names. ip2mkdev uses
-Linux tty naming conventions: ttyF0 - ttyF255 for normal devices, and
-cuf0 - cuf255 for callout devices.
-
-
-4. USING THE DRIVERS
-
-As noted above, the driver implements the ports in accordance with Linux
-conventions, and the devices should be interchangeable with the standard
-serial devices. (This is a key point for problem reporting: please make
-sure that what you are trying do works on the ttySx/cuax ports first; then 
-tell us what went wrong with the ip2 ports!)
-
-Higher speeds can be obtained using the setserial utility which remaps 
-38,400 bps (extb) to 57,600 bps, 115,200 bps, or a custom speed. 
-Intelliport II installations using the PowerPort expansion module can
-use the custom speed setting to select the highest speeds: 153,600 bps,
-230,400 bps, 307,200 bps, 460,800bps and 921,600 bps. The base for
-custom baud rate configuration is fixed at 921,600 for cards/expansion
-modules with ST654's and 115200 for those with Cirrus CD1400's.  This
-corresponds to the maximum bit rates those chips are capable.  
-For example if the baud base is 921600 and the baud divisor is 18 then
-the custom rate is 921600/18 = 51200 bps.  See the setserial man page for
-complete details. Of course if stty accepts the higher rates now you can
-use that as well as the standard ioctls().
-
-
-5. ip2mkdev and assorted utilities...
-
-Several utilities, including the source for a binary ip2mkdev utility are
-available under .../drivers/char/ip2.  These can be build by changing to
-that directory and typing "make" after the kernel has be built.  If you do
-not wish to compile the binary utilities, the shell script below can be
-cut out and run as "ip2mkdev" to create the necessary device files.  To
-use the ip2mkdev script, you must have procfs enabled and the proc file
-system mounted on /proc.
-
-
-6. NOTES
-
-This is a release version of the driver, but it is impossible to test it
-in all configurations of Linux. If there is any anomalous behaviour that 
-does not match the standard serial port's behaviour please let us know.
-
-
-7. ip2mkdev shell script
-
-Previously, this script was simply attached here.  It is now attached as a
-shar archive to make it easier to extract the script from the documentation.
-To create the ip2mkdev shell script change to a convenient directory (/tmp
-works just fine) and run the following command:
-
-	unshar Documentation/serial/computone.txt
-		(This file)
-
-You should now have a file ip2mkdev in your current working directory with
-permissions set to execute.  Running that script with then create the
-necessary devices for the Computone boards, interfaces, and ports which
-are present on you system at the time it is run.
-
-
-#!/bin/sh
-# This is a shell archive (produced by GNU sharutils 4.2.1).
-# To extract the files from this archive, save it to some FILE, remove
-# everything before the `!/bin/sh' line above, then type `sh FILE'.
-#
-# Made on 2001-10-29 10:32 EST by <mhw@alcove.wittsend.com>.
-# Source directory was `/home2/src/tmp'.
-#
-# Existing files will *not* be overwritten unless `-c' is specified.
-#
-# This shar contains:
-# length mode       name
-# ------ ---------- ------------------------------------------
-#   4251 -rwxr-xr-x ip2mkdev
-#
-save_IFS="${IFS}"
-IFS="${IFS}:"
-gettext_dir=FAILED
-locale_dir=FAILED
-first_param="$1"
-for dir in $PATH
-do
-  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
-     && ($dir/gettext --version >/dev/null 2>&1)
-  then
-    set `$dir/gettext --version 2>&1`
-    if test "$3" = GNU
-    then
-      gettext_dir=$dir
-    fi
-  fi
-  if test "$locale_dir" = FAILED && test -f $dir/shar \
-     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
-  then
-    locale_dir=`$dir/shar --print-text-domain-dir`
-  fi
-done
-IFS="$save_IFS"
-if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
-then
-  echo=echo
-else
-  TEXTDOMAINDIR=$locale_dir
-  export TEXTDOMAINDIR
-  TEXTDOMAIN=sharutils
-  export TEXTDOMAIN
-  echo="$gettext_dir/gettext -s"
-fi
-if touch -am -t 200112312359.59 $$.touch >/dev/null 2>&1 && test ! -f 200112312359.59 -a -f $$.touch; then
-  shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
-elif touch -am 123123592001.59 $$.touch >/dev/null 2>&1 && test ! -f 123123592001.59 -a ! -f 123123592001.5 -a -f $$.touch; then
-  shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
-elif touch -am 1231235901 $$.touch >/dev/null 2>&1 && test ! -f 1231235901 -a -f $$.touch; then
-  shar_touch='touch -am $3$4$5$6$2 "$8"'
-else
-  shar_touch=:
-  echo
-  $echo 'WARNING: not restoring timestamps.  Consider getting and'
-  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
-  echo
-fi
-rm -f 200112312359.59 123123592001.59 123123592001.5 1231235901 $$.touch
-#
-if mkdir _sh17581; then
-  $echo 'x -' 'creating lock directory'
-else
-  $echo 'failed to create lock directory'
-  exit 1
-fi
-# ============= ip2mkdev ==============
-if test -f 'ip2mkdev' && test "$first_param" != -c; then
-  $echo 'x -' SKIPPING 'ip2mkdev' '(file already exists)'
-else
-  $echo 'x -' extracting 'ip2mkdev' '(text)'
-  sed 's/^X//' << 'SHAR_EOF' > 'ip2mkdev' &&
-#!/bin/sh -
-#
-#	ip2mkdev
-#
-#	Make or remove devices as needed for Computone Intelliport drivers
-#
-#	First rule!  If the dev file exists and you need it, don't mess
-#	with it.  That prevents us from screwing up open ttys, ownership
-#	and permissions on a running system!
-#
-#	This script will NOT remove devices that no longer exist if their
-#	board or interface box has been removed.  If you want to get rid
-#	of them, you can manually do an "rm -f /dev/ttyF* /dev/cuaf*"
-#	before running this script.  Running this script will then recreate
-#	all the valid devices.
-#
-#	Michael H. Warfield
-#	/\/\|=mhw=|\/\/
-#	mhw@wittsend.com
-#
-#	Updated 10/29/2000 for version 1.2.13 naming convention
-#		under devfs.	/\/\|=mhw=|\/\/
-#
-#	Updated 03/09/2000 for devfs support in ip2 drivers. /\/\|=mhw=|\/\/
-#
-X
-if test -d /dev/ip2 ; then
-#	This is devfs mode...  We don't do anything except create symlinks
-#	from the real devices to the old names!
-X	cd /dev
-X	echo "Creating symbolic links to devfs devices"
-X	for i in `ls ip2` ; do
-X		if test ! -L ip2$i ; then
-X			# Remove it incase it wasn't a symlink (old device)
-X			rm -f ip2$i
-X			ln -s ip2/$i ip2$i
-X		fi
-X	done
-X	for i in `( cd tts ; ls F* )` ; do
-X		if test ! -L tty$i ; then
-X			# Remove it incase it wasn't a symlink (old device)
-X			rm -f tty$i
-X			ln -s tts/$i tty$i
-X		fi
-X	done
-X	for i in `( cd cua ; ls F* )` ; do
-X		DEVNUMBER=`expr $i : 'F\(.*\)'`
-X		if test ! -L cuf$DEVNUMBER ; then
-X			# Remove it incase it wasn't a symlink (old device)
-X			rm -f cuf$DEVNUMBER
-X			ln -s cua/$i cuf$DEVNUMBER
-X		fi
-X	done
-X	exit 0
-fi
-X
-if test ! -f /proc/tty/drivers
-then
-X	echo "\
-Unable to check driver status.
-Make sure proc file system is mounted."
-X
-X	exit 255
-fi
-X
-if test ! -f /proc/tty/driver/ip2
-then
-X	echo "\
-Unable to locate ip2 proc file.
-Attempting to load driver"
-X
-X	if /sbin/insmod ip2
-X	then
-X		if test ! -f /proc/tty/driver/ip2
-X		then
-X			echo "\
-Unable to locate ip2 proc file after loading driver.
-Driver initialization failure or driver version error.
-"
-X		exit 255
-X		fi
-X	else
-X		echo "Unable to load ip2 driver."
-X		exit 255
-X	fi
-fi
-X
-# Ok...  So we got the driver loaded and we can locate the procfs files.
-# Next we need our major numbers.
-X
-TTYMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/tt/!d' -e 's/.*tt[^ 	]*[ 	]*\([0-9]*\)[ 	]*.*/\1/' < /proc/tty/drivers`
-CUAMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/cu/!d' -e 's/.*cu[^ 	]*[ 	]*\([0-9]*\)[ 	]*.*/\1/' < /proc/tty/drivers`
-BRDMAJOR=`sed -e '/^Driver: /!d' -e 's/.*IMajor=\([0-9]*\)[ 	]*.*/\1/' < /proc/tty/driver/ip2`
-X
-echo "\
-TTYMAJOR = $TTYMAJOR
-CUAMAJOR = $CUAMAJOR
-BRDMAJOR = $BRDMAJOR
-"
-X
-# Ok...  Now we should know our major numbers, if appropriate...
-# Now we need our boards and start the device loops.
-X
-grep '^Board [0-9]:' /proc/tty/driver/ip2 | while read token number type alltherest
-do
-X	# The test for blank "type" will catch the stats lead-in lines
-X	# if they exist in the file
-X	if test "$type" = "vacant" -o "$type" = "Vacant" -o "$type" = ""
-X	then
-X		continue
-X	fi
-X
-X	BOARDNO=`expr "$number" : '\([0-9]\):'`
-X	PORTS=`expr "$alltherest" : '.*ports=\([0-9]*\)' | tr ',' ' '`
-X	MINORS=`expr "$alltherest" : '.*minors=\([0-9,]*\)' | tr ',' ' '`
-X
-X	if test "$BOARDNO" = "" -o "$PORTS" = ""
-X	then
-#	This may be a bug.  We should at least get this much information
-X		echo "Unable to process board line"
-X		continue
-X	fi
-X
-X	if test "$MINORS" = ""
-X	then
-#	Silently skip this one.  This board seems to have no boxes
-X		continue
-X	fi
-X
-X	echo "board $BOARDNO: $type ports = $PORTS; port numbers = $MINORS"
-X
-X	if test "$BRDMAJOR" != ""
-X	then
-X		BRDMINOR=`expr $BOARDNO \* 4`
-X		STSMINOR=`expr $BRDMINOR + 1`
-X		if test ! -c /dev/ip2ipl$BOARDNO ; then
-X			mknod /dev/ip2ipl$BOARDNO c $BRDMAJOR $BRDMINOR
-X		fi
-X		if test ! -c /dev/ip2stat$BOARDNO ; then
-X			mknod /dev/ip2stat$BOARDNO c $BRDMAJOR $STSMINOR
-X		fi
-X	fi
-X
-X	if test "$TTYMAJOR" != ""
-X	then
-X		PORTNO=$BOARDBASE
-X
-X		for PORTNO in $MINORS
-X		do
-X			if test ! -c /dev/ttyF$PORTNO ; then
-X				# We got the hardware but no device - make it
-X				mknod /dev/ttyF$PORTNO c $TTYMAJOR $PORTNO
-X			fi	
-X		done
-X	fi
-X
-X	if test "$CUAMAJOR" != ""
-X	then
-X		PORTNO=$BOARDBASE
-X
-X		for PORTNO in $MINORS
-X		do
-X			if test ! -c /dev/cuf$PORTNO ; then
-X				# We got the hardware but no device - make it
-X				mknod /dev/cuf$PORTNO c $CUAMAJOR $PORTNO
-X			fi	
-X		done
-X	fi
-done
-X
-Xexit 0
-SHAR_EOF
-  (set 20 01 10 29 10 32 01 'ip2mkdev'; eval "$shar_touch") &&
-  chmod 0755 'ip2mkdev' ||
-  $echo 'restore of' 'ip2mkdev' 'failed'
-  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
-  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
-    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
-    || $echo 'ip2mkdev:' 'MD5 check failed'
-cb5717134509f38bad9fde6b1f79b4a4  ip2mkdev
-SHAR_EOF
-  else
-    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'ip2mkdev'`"
-    test 4251 -eq "$shar_count" ||
-    $echo 'ip2mkdev:' 'original size' '4251,' 'current size' "$shar_count!"
-  fi
-fi
-rm -fr _sh17581
-exit 0
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
index a92bba8..16dfe57 100644
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -74,7 +74,8 @@ CMI9880
 
 AD1882 / AD1882A
 ================
-  3stack	3-stack mode (default)
+  3stack	3-stack mode
+  3stack-automute 3-stack with automute front HP (default)
   6stack	6-stack mode
 
 AD1884A / AD1883 / AD1984A / AD1984B
diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py
index a78879b..3fe0d81 100755
--- a/Documentation/target/tcm_mod_builder.py
+++ b/Documentation/target/tcm_mod_builder.py
@@ -402,8 +402,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
 	buf += "	.queue_data_in			= " + fabric_mod_name + "_queue_data_in,\n"
 	buf += "	.queue_status			= " + fabric_mod_name + "_queue_status,\n"
 	buf += "	.queue_tm_rsp			= " + fabric_mod_name + "_queue_tm_rsp,\n"
-	buf += "	.get_fabric_sense_len		= " + fabric_mod_name + "_get_fabric_sense_len,\n"
-	buf += "	.set_fabric_sense_len		= " + fabric_mod_name + "_set_fabric_sense_len,\n"
 	buf += "	.is_state_remove		= " + fabric_mod_name + "_is_state_remove,\n"
 	buf += "	/*\n"
 	buf += "	 * Setup function pointers for generic logic in target_core_fabric_configfs.c\n"
@@ -906,20 +904,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name):
 			buf += "}\n\n"
 			bufi += "int " + fabric_mod_name + "_queue_tm_rsp(struct se_cmd *);\n"
 
-		if re.search('get_fabric_sense_len\)\(', fo):
-			buf += "u16 " + fabric_mod_name + "_get_fabric_sense_len(void)\n"
-			buf += "{\n"
-			buf += "	return 0;\n"
-			buf += "}\n\n"
-			bufi += "u16 " + fabric_mod_name + "_get_fabric_sense_len(void);\n"
-
-		if re.search('set_fabric_sense_len\)\(', fo):
-			buf += "u16 " + fabric_mod_name + "_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)\n"
-			buf += "{\n"
-			buf += "	return 0;\n"
-			buf += "}\n\n"
-			bufi += "u16 " + fabric_mod_name + "_set_fabric_sense_len(struct se_cmd *, u32);\n"
-
 		if re.search('is_state_remove\)\(', fo):
 			buf += "int " + fabric_mod_name + "_is_state_remove(struct se_cmd *se_cmd)\n"
 			buf += "{\n"
diff --git a/Documentation/thermal/cpu-cooling-api.txt b/Documentation/thermal/cpu-cooling-api.txt
new file mode 100644
index 0000000..557adb8
--- /dev/null
+++ b/Documentation/thermal/cpu-cooling-api.txt
@@ -0,0 +1,60 @@
+CPU cooling APIs How To
+===================================
+
+Written by Amit Daniel Kachhap <amit.kachhap@linaro.org>
+
+Updated: 12 May 2012
+
+Copyright (c)  2012 Samsung Electronics Co., Ltd(http://www.samsung.com)
+
+0. Introduction
+
+The generic cpu cooling(freq clipping, cpuhotplug etc) provides
+registration/unregistration APIs to the caller. The binding of the cooling
+devices to the trip point is left for the user. The registration APIs returns
+the cooling device pointer.
+
+1. cpu cooling APIs
+
+1.1 cpufreq registration/unregistration APIs
+1.1.1 struct thermal_cooling_device *cpufreq_cooling_register(
+	struct freq_clip_table *tab_ptr, unsigned int tab_size)
+
+    This interface function registers the cpufreq cooling device with the name
+    "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
+    cooling devices.
+
+    tab_ptr: The table containing the maximum value of frequency to be clipped
+    for each cooling state.
+	.freq_clip_max: Value of frequency to be clipped for each allowed
+	 cpus.
+	.temp_level: Temperature level at which the frequency clamping will
+	happen.
+	.mask_val: cpumask of the allowed cpu's
+    tab_size: the total number of cpufreq cooling states.
+
+1.1.2 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
+
+    This interface function unregisters the "thermal-cpufreq-%x" cooling device.
+
+    cdev: Cooling device pointer which has to be unregistered.
+
+
+1.2 CPU cooling action notifier register/unregister interface
+1.2.1 int cputherm_register_notifier(struct notifier_block *nb,
+	unsigned int list)
+
+    This interface registers a driver with cpu cooling layer. The driver will
+    be notified when any cpu cooling action is called.
+
+    nb: notifier function to register
+    list: CPUFREQ_COOLING_START or CPUFREQ_COOLING_STOP
+
+1.2.2 int cputherm_unregister_notifier(struct notifier_block *nb,
+	unsigned int list)
+
+    This interface registers a driver with cpu cooling layer. The driver will
+    be notified when any cpu cooling action is called.
+
+    nb: notifier function to register
+    list: CPUFREQ_COOLING_START or CPUFREQ_COOLING_STOP
diff --git a/Documentation/thermal/exynos_thermal b/Documentation/thermal/exynos_thermal
new file mode 100644
index 0000000..2b46f67
--- /dev/null
+++ b/Documentation/thermal/exynos_thermal
@@ -0,0 +1,52 @@
+Kernel driver exynos4_tmu
+=================
+
+Supported chips:
+* ARM SAMSUNG EXYNOS4 series of SoC
+  Prefix: 'exynos4-tmu'
+  Datasheet: Not publicly available
+
+Authors: Donggeun Kim <dg77.kim@samsung.com>
+
+Description
+-----------
+
+This driver allows to read temperature inside SAMSUNG EXYNOS4 series of SoC.
+
+The chip only exposes the measured 8-bit temperature code value
+through a register.
+Temperature can be taken from the temperature code.
+There are three equations converting from temperature to temperature code.
+
+The three equations are:
+  1. Two point trimming
+	Tc = (T - 25) * (TI2 - TI1) / (85 - 25) + TI1
+
+  2. One point trimming
+	Tc = T + TI1 - 25
+
+  3. No trimming
+	Tc = T + 50
+
+  Tc: Temperature code, T: Temperature,
+  TI1: Trimming info for 25 degree Celsius (stored at TRIMINFO register)
+       Temperature code measured at 25 degree Celsius which is unchanged
+  TI2: Trimming info for 85 degree Celsius (stored at TRIMINFO register)
+       Temperature code measured at 85 degree Celsius which is unchanged
+
+TMU(Thermal Management Unit) in EXYNOS4 generates interrupt
+when temperature exceeds pre-defined levels.
+The maximum number of configurable threshold is four.
+The threshold levels are defined as follows:
+  Level_0: current temperature > trigger_level_0 + threshold
+  Level_1: current temperature > trigger_level_1 + threshold
+  Level_2: current temperature > trigger_level_2 + threshold
+  Level_3: current temperature > trigger_level_3 + threshold
+
+  The threshold and each trigger_level are set
+  through the corresponding registers.
+
+When an interrupt occurs, this driver notify kernel thermal framework
+with the function exynos4_report_trigger.
+Although an interrupt condition for level_0 can be set,
+it can be used to synchronize the cooling action.
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index c087dbc..ca1a1a3 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -84,7 +84,8 @@ temperature) and throttle appropriate devices.
 
 1.3 interface for binding a thermal zone device with a thermal cooling device
 1.3.1 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
-		int trip, struct thermal_cooling_device *cdev);
+	int trip, struct thermal_cooling_device *cdev,
+	unsigned long upper, unsigned long lower);
 
     This interface function bind a thermal cooling device to the certain trip
     point of a thermal zone device.
@@ -93,6 +94,12 @@ temperature) and throttle appropriate devices.
     cdev: thermal cooling device
     trip: indicates which trip point the cooling devices is associated with
 	  in this thermal zone.
+    upper:the Maximum cooling state for this trip point.
+          THERMAL_NO_LIMIT means no upper limit,
+	  and the cooling device can be in max_state.
+    lower:the Minimum cooling state can be used for this trip point.
+          THERMAL_NO_LIMIT means no lower limit,
+	  and the cooling device can be in cooling state 0.
 
 1.3.2 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
 		int trip, struct thermal_cooling_device *cdev);
diff --git a/Documentation/usb/persist.txt b/Documentation/usb/persist.txt
index 074b159..35d70ed 100644
--- a/Documentation/usb/persist.txt
+++ b/Documentation/usb/persist.txt
@@ -155,6 +155,9 @@ If the kernel gets fooled in this way, it's almost certain to cause
 data corruption and to crash your system.  You'll have no one to blame
 but yourself.
 
+For those devices with avoid_reset_quirk attribute being set, persist
+maybe fail because they may morph after reset.
+
 YOU HAVE BEEN WARNED!  USE AT YOUR OWN RISK!
 
 That having been said, most of the time there shouldn't be any trouble
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index bf33aaa..2c32651 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1190,12 +1190,15 @@ struct kvm_ppc_pvinfo {
 This ioctl fetches PV specific information that need to be passed to the guest
 using the device tree or other means from vm context.
 
-For now the only implemented piece of information distributed here is an array
-of 4 instructions that make up a hypercall.
+The hcall array defines 4 instructions that make up a hypercall.
 
 If any additional field gets added to this structure later on, a bit for that
 additional piece of information will be set in the flags bitmap.
 
+The flags bitmap is defined as:
+
+   /* the host supports the ePAPR idle hcall
+   #define KVM_PPC_PVINFO_FLAGS_EV_IDLE   (1<<0)
 
 4.48 KVM_ASSIGN_PCI_DEVICE
 
@@ -1727,7 +1730,12 @@ registers, find a list below:
   Arch  |       Register        | Width (bits)
         |                       |
   PPC   | KVM_REG_PPC_HIOR      | 64
-
+  PPC   | KVM_REG_PPC_IAC1      | 64
+  PPC   | KVM_REG_PPC_IAC2      | 64
+  PPC   | KVM_REG_PPC_IAC3      | 64
+  PPC   | KVM_REG_PPC_IAC4      | 64
+  PPC   | KVM_REG_PPC_DAC1      | 64
+  PPC   | KVM_REG_PPC_DAC2      | 64
 
 4.69 KVM_GET_ONE_REG
 
@@ -1743,7 +1751,7 @@ kvm_one_reg struct passed in. On success, the register value can be found
 at the memory location pointed to by "addr".
 
 The list of registers accessible using this interface is identical to the
-list in 4.64.
+list in 4.68.
 
 
 4.70 KVM_KVMCLOCK_CTRL
diff --git a/Documentation/virtual/kvm/hypercalls.txt b/Documentation/virtual/kvm/hypercalls.txt
new file mode 100644
index 0000000..ea113b5
--- /dev/null
+++ b/Documentation/virtual/kvm/hypercalls.txt
@@ -0,0 +1,66 @@
+Linux KVM Hypercall:
+===================
+X86:
+ KVM Hypercalls have a three-byte sequence of either the vmcall or the vmmcall
+ instruction. The hypervisor can replace it with instructions that are
+ guaranteed to be supported.
+
+ Up to four arguments may be passed in rbx, rcx, rdx, and rsi respectively.
+ The hypercall number should be placed in rax and the return value will be
+ placed in rax.  No other registers will be clobbered unless explicitly stated
+ by the particular hypercall.
+
+S390:
+  R2-R7 are used for parameters 1-6. In addition, R1 is used for hypercall
+  number. The return value is written to R2.
+
+  S390 uses diagnose instruction as hypercall (0x500) along with hypercall
+  number in R1.
+
+ PowerPC:
+  It uses R3-R10 and hypercall number in R11. R4-R11 are used as output registers.
+  Return value is placed in R3.
+
+  KVM hypercalls uses 4 byte opcode, that are patched with 'hypercall-instructions'
+  property inside the device tree's /hypervisor node.
+  For more information refer to Documentation/virtual/kvm/ppc-pv.txt
+
+KVM Hypercalls Documentation
+===========================
+The template for each hypercall is:
+1. Hypercall name.
+2. Architecture(s)
+3. Status (deprecated, obsolete, active)
+4. Purpose
+
+1. KVM_HC_VAPIC_POLL_IRQ
+------------------------
+Architecture: x86
+Status: active
+Purpose: Trigger guest exit so that the host can check for pending
+interrupts on reentry.
+
+2. KVM_HC_MMU_OP
+------------------------
+Architecture: x86
+Status: deprecated.
+Purpose: Support MMU operations such as writing to PTE,
+flushing TLB, release PT.
+
+3. KVM_HC_FEATURES
+------------------------
+Architecture: PPC
+Status: active
+Purpose: Expose hypercall availability to the guest. On x86 platforms, cpuid
+used to enumerate which hypercalls are available. On PPC, either device tree
+based lookup ( which is also what EPAPR dictates) OR KVM specific enumeration
+mechanism (which is this hypercall) can be used.
+
+4. KVM_HC_PPC_MAP_MAGIC_PAGE
+------------------------
+Architecture: PPC
+Status: active
+Purpose: To enable communication between the hypervisor and guest there is a
+shared page that contains parts of supervisor visible register state.
+The guest can map this shared page to access its supervisor register through
+memory using this hypercall.
diff --git a/Documentation/virtual/kvm/ppc-pv.txt b/Documentation/virtual/kvm/ppc-pv.txt
index 4911cf9..4cd076f 100644
--- a/Documentation/virtual/kvm/ppc-pv.txt
+++ b/Documentation/virtual/kvm/ppc-pv.txt
@@ -174,3 +174,25 @@ following:
 That way we can inject an arbitrary amount of code as replacement for a single
 instruction. This allows us to check for pending interrupts when setting EE=1
 for example.
+
+Hypercall ABIs in KVM on PowerPC
+=================================
+1) KVM hypercalls (ePAPR)
+
+These are ePAPR compliant hypercall implementation (mentioned above). Even
+generic hypercalls are implemented here, like the ePAPR idle hcall. These are
+available on all targets.
+
+2) PAPR hypercalls
+
+PAPR hypercalls are needed to run server PowerPC PAPR guests (-M pseries in QEMU).
+These are the same hypercalls that pHyp, the POWER hypervisor implements. Some of
+them are handled in the kernel, some are handled in user space. This is only
+available on book3s_64.
+
+3) OSI hypercalls
+
+Mac-on-Linux is another user of KVM on PowerPC, which has its own hypercall (long
+before KVM). This is supported to maintain compatibility. All these hypercalls get
+forwarded to user space. This is only useful on book3s_32, but can be used with
+book3s_64 as well.
diff --git a/Documentation/vm/unevictable-lru.txt b/Documentation/vm/unevictable-lru.txt
index fa206cc..323ff5d 100644
--- a/Documentation/vm/unevictable-lru.txt
+++ b/Documentation/vm/unevictable-lru.txt
@@ -371,8 +371,8 @@ mlock_fixup() filters several classes of "special" VMAs:
    mlock_fixup() will call make_pages_present() in the hugetlbfs VMA range to
    allocate the huge pages and populate the ptes.
 
-3) VMAs with VM_DONTEXPAND or VM_RESERVED are generally userspace mappings of
-   kernel pages, such as the VDSO page, relay channel pages, etc.  These pages
+3) VMAs with VM_DONTEXPAND are generally userspace mappings of kernel pages,
+   such as the VDSO page, relay channel pages, etc. These pages
    are inherently unevictable and are not managed on the LRU lists.
    mlock_fixup() treats these VMAs the same as hugetlbfs VMAs.  It calls
    make_pages_present() to populate the ptes.
diff --git a/Documentation/w1/slaves/w1_therm b/Documentation/w1/slaves/w1_therm
index 0403aaa..874a8ca 100644
--- a/Documentation/w1/slaves/w1_therm
+++ b/Documentation/w1/slaves/w1_therm
@@ -3,6 +3,7 @@ Kernel driver w1_therm
 
 Supported chips:
   * Maxim ds18*20 based temperature sensors.
+  * Maxim ds1825 based temperature sensors.
 
 Author: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
 
@@ -15,6 +16,7 @@ supported family codes:
 W1_THERM_DS18S20	0x10
 W1_THERM_DS1822		0x22
 W1_THERM_DS18B20	0x28
+W1_THERM_DS1825		0x3B
 
 Support is provided through the sysfs w1_slave file.  Each open and
 read sequence will initiate a temperature conversion then provide two
diff --git a/Documentation/watchdog/src/watchdog-test.c b/Documentation/watchdog/src/watchdog-test.c
index 73ff5cc..3da8229 100644
--- a/Documentation/watchdog/src/watchdog-test.c
+++ b/Documentation/watchdog/src/watchdog-test.c
@@ -31,7 +31,7 @@ static void keep_alive(void)
  * or "-e" to enable the card.
  */
 
-void term(int sig)
+static void term(int sig)
 {
     close(fd);
     fprintf(stderr, "Stopping watchdog ticks...\n");
diff --git a/MAINTAINERS b/MAINTAINERS
index 61ad79e..515f455 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -595,7 +595,6 @@ M:	Will Deacon <will.deacon@arm.com>
 S:	Maintained
 F:	arch/arm/kernel/perf_event*
 F:	arch/arm/oprofile/common.c
-F:	arch/arm/kernel/pmu.c
 F:	arch/arm/include/asm/pmu.h
 F:	arch/arm/kernel/hw_breakpoint.c
 F:	arch/arm/include/asm/hw_breakpoint.h
@@ -1518,7 +1517,7 @@ S:	Supported
 F:	drivers/rtc/rtc-bfin.c
 
 BLACKFIN SDH DRIVER
-M:	Cliff Cai <cliff.cai@analog.com>
+M:	Sonic Zhang <sonic.zhang@analog.com>
 L:	uclinux-dist-devel@blackfin.uclinux.org
 W:	http://blackfin.uclinux.org
 S:	Supported
@@ -2217,7 +2216,7 @@ S:	Maintained
 F:	drivers/scsi/tmscsim.*
 
 DC395x SCSI driver
-M:	Oliver Neukum <oliver@neukum.name>
+M:	Oliver Neukum <oliver@neukum.org>
 M:	Ali Akcaagac <aliakc@web.de>
 M:	Jamie Lenehan <lenehan@twibble.org>
 W:	http://twibble.org/dist/dc395x/
@@ -2778,8 +2777,8 @@ FC0011 TUNER DRIVER
 M:	Michael Buesch <m@bues.ch>
 L:	linux-media@vger.kernel.org
 S:	Maintained
-F:	drivers/media/common/tuners/fc0011.h
-F:	drivers/media/common/tuners/fc0011.c
+F:	drivers/media/tuners/fc0011.h
+F:	drivers/media/tuners/fc0011.c
 
 FANOTIFY
 M:	Eric Paris <eparis@redhat.com>
@@ -3124,49 +3123,49 @@ M:	Frank Zago <frank@zago.net>
 L:	linux-media@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
-F:	drivers/media/video/gspca/finepix.c
+F:	drivers/media/usb/gspca/finepix.c
 
 GSPCA GL860 SUBDRIVER
 M:	Olivier Lorin <o.lorin@laposte.net>
 L:	linux-media@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
-F:	drivers/media/video/gspca/gl860/
+F:	drivers/media/usb/gspca/gl860/
 
 GSPCA M5602 SUBDRIVER
 M:	Erik Andren <erik.andren@gmail.com>
 L:	linux-media@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
-F:	drivers/media/video/gspca/m5602/
+F:	drivers/media/usb/gspca/m5602/
 
 GSPCA PAC207 SONIXB SUBDRIVER
 M:	Hans de Goede <hdegoede@redhat.com>
 L:	linux-media@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
-F:	drivers/media/video/gspca/pac207.c
+F:	drivers/media/usb/gspca/pac207.c
 
 GSPCA SN9C20X SUBDRIVER
 M:	Brian Johnson <brijohn@gmail.com>
 L:	linux-media@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
-F:	drivers/media/video/gspca/sn9c20x.c
+F:	drivers/media/usb/gspca/sn9c20x.c
 
 GSPCA T613 SUBDRIVER
 M:	Leandro Costantino <lcostantino@gmail.com>
 L:	linux-media@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
-F:	drivers/media/video/gspca/t613.c
+F:	drivers/media/usb/gspca/t613.c
 
 GSPCA USB WEBCAM DRIVER
 M:	Hans de Goede <hdegoede@redhat.com>
 L:	linux-media@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
-F:	drivers/media/video/gspca/
+F:	drivers/media/usb/gspca/
 
 HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
 M:	Frank Seidel <frank@f-seidel.de>
@@ -3420,6 +3419,12 @@ T:	git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux.git
 S:	Maintained
 F:	arch/ia64/
 
+IBM Power 842 compression accelerator
+M:	Robert Jennings <rcj@linux.vnet.ibm.com>
+S:	Supported
+F:	drivers/crypto/nx/nx-842.c
+F:	include/linux/nx842.h
+
 IBM Power Linux RAID adapter
 M:	Brian King <brking@us.ibm.com>
 S:	Supported
@@ -4537,7 +4542,7 @@ S:	Supported
 F:	arch/microblaze/
 
 MICROTEK X6 SCANNER
-M:	Oliver Neukum <oliver@neukum.name>
+M:	Oliver Neukum <oliver@neukum.org>
 S:	Maintained
 F:	drivers/usb/image/microtek.*
 
@@ -4643,6 +4648,14 @@ L:	alsa-devel@alsa-project.org
 W:	http://www.native-instruments.com
 F:	sound/usb/caiaq/
 
+NATIVE LINUX KVM TOOL
+M:	Pekka Enberg <penberg@kernel.org>
+M:	Sasha Levin <levinsasha928@gmail.com>
+M:	Asias He <asias.hejun@gmail.com>
+L:	kvm@vger.kernel.org
+S:	Maintained
+F:	tools/kvm/
+
 NCP FILESYSTEM
 M:	Petr Vandrovec <petr@vandrovec.name>
 S:	Odd Fixes
@@ -5320,6 +5333,12 @@ L:	linux-mtd@lists.infradead.org
 S:	Maintained
 F:	drivers/mtd/devices/phram.c
 
+PICOLCD HID DRIVER
+M:	Bruno Prémont <bonbons@linux-vserver.org>
+L:	linux-input@vger.kernel.org
+S:	Maintained
+F:	drivers/hid/hid-picolcd*
+
 PICOXCELL SUPPORT
 M:	Jamie Iles <jamie@jamieiles.com>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -5530,7 +5549,7 @@ W:	http://www.isely.net/pvrusb2/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
 F:	Documentation/video4linux/README.pvrusb2
-F:	drivers/media/video/pvrusb2/
+F:	drivers/media/usb/pvrusb2/
 
 PWM SUBSYSTEM
 M:	Thierry Reding <thierry.reding@avionic-design.de>
@@ -5961,7 +5980,7 @@ M:	Huang Shijie <shijie8@gmail.com>
 M:	Kang Yong <kangyong@telegent.com>
 M:	Zhang Xiaobing <xbzhang@telegent.com>
 S:	Supported
-F:	drivers/media/video/tlg2300
+F:	drivers/media/usb/tlg2300
 
 SC1200 WDT DRIVER
 M:	Zwane Mwaikambo <zwane@arm.linux.org.uk>
@@ -6798,6 +6817,8 @@ F:	drivers/char/tlclk.c
 
 TENSILICA XTENSA PORT (xtensa)
 M:	Chris Zankel <chris@zankel.net>
+M:	Max Filippov <jcmvbkbc@gmail.com>
+L:	linux-xtensa@linux-xtensa.org
 S:	Maintained
 F:	arch/xtensa/
 
@@ -7076,7 +7097,7 @@ F:	include/linux/mtd/ubi.h
 F:	include/mtd/ubi-user.h
 
 USB ACM DRIVER
-M:	Oliver Neukum <oliver@neukum.name>
+M:	Oliver Neukum <oliver@neukum.org>
 L:	linux-usb@vger.kernel.org
 S:	Maintained
 F:	Documentation/usb/acm.txt
@@ -7097,7 +7118,7 @@ S:	Supported
 F:	drivers/block/ub.c
 
 USB CDC ETHERNET DRIVER
-M:	Oliver Neukum <oliver@neukum.name>
+M:	Oliver Neukum <oliver@neukum.org>
 L:	linux-usb@vger.kernel.org
 S:	Maintained
 F:	drivers/net/usb/cdc_*.c
@@ -7170,7 +7191,7 @@ F:	drivers/usb/host/isp116x*
 F:	include/linux/usb/isp116x.h
 
 USB KAWASAKI LSI DRIVER
-M:	Oliver Neukum <oliver@neukum.name>
+M:	Oliver Neukum <oliver@neukum.org>
 L:	linux-usb@vger.kernel.org
 S:	Maintained
 F:	drivers/usb/serial/kl5kusb105.*
@@ -7302,7 +7323,7 @@ T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:	http://www.linux-projects.org
 S:	Maintained
 F:	Documentation/video4linux/sn9c102.txt
-F:	drivers/media/video/sn9c102/
+F:	drivers/media/usb/sn9c102/
 
 USB SUBSYSTEM
 M:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
@@ -7337,7 +7358,7 @@ L:	linux-media@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:	http://www.ideasonboard.org/uvc/
 S:	Maintained
-F:	drivers/media/video/uvc/
+F:	drivers/media/usb/uvc/
 
 USB W996[87]CF DRIVER
 M:	Luca Risolia <luca.risolia@studio.unibo.it>
@@ -7376,7 +7397,7 @@ T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:	http://royale.zerezo.com/zr364xx/
 S:	Maintained
 F:	Documentation/video4linux/zr364xx.txt
-F:	drivers/media/video/zr364xx.c
+F:	drivers/media/usb/zr364xx.c
 
 USER-MODE LINUX (UML)
 M:	Jeff Dike <jdike@addtoit.com>
@@ -7670,23 +7691,28 @@ S:	Supported
 F:	Documentation/hwmon/wm83??
 F:	arch/arm/mach-s3c64xx/mach-crag6410*
 F:	drivers/clk/clk-wm83*.c
+F:	drivers/extcon/extcon-arizona.c
 F:	drivers/leds/leds-wm83*.c
 F:	drivers/gpio/gpio-*wm*.c
+F:	drivers/gpio/gpio-arizona.c
 F:	drivers/hwmon/wm83??-hwmon.c
 F:	drivers/input/misc/wm831x-on.c
 F:	drivers/input/touchscreen/wm831x-ts.c
 F:	drivers/input/touchscreen/wm97*.c
-F:	drivers/mfd/wm8*.c
+F:	drivers/mfd/arizona*
+F:	drivers/mfd/wm*.c
 F:	drivers/power/wm83*.c
 F:	drivers/rtc/rtc-wm83*.c
 F:	drivers/regulator/wm8*.c
 F:	drivers/video/backlight/wm83*_bl.c
 F:	drivers/watchdog/wm83*_wdt.c
+F:	include/linux/mfd/arizona/
 F:	include/linux/mfd/wm831x/
 F:	include/linux/mfd/wm8350/
 F:	include/linux/mfd/wm8400*
 F:	include/linux/wm97xx.h
 F:	include/sound/wm????.h
+F:	sound/soc/codecs/arizona.?
 F:	sound/soc/codecs/wm*
 
 WORKQUEUE
diff --git a/Next/SHA1s b/Next/SHA1s
new file mode 100644
index 0000000..1fb9e47
--- /dev/null
+++ b/Next/SHA1s
@@ -0,0 +1,197 @@
+Name		SHA1
+----		----
+origin		6dab7ede9390d4d937cb89feca932e4fd575d2da
+fixes		9023a4093d6594040fb8142cdd2615d3461caa7a
+kbuild-current	f8f5701bdaf9134b1f90e5044a82c66324d2073f
+arm-current	89868730a756feca7e4b21a97c86487cd565ed22
+m68k-current	9e2760d18b3cf179534bbc27692c84879c61b97c
+powerpc-merge	ad36cb0d1d3e2b7f161cd33932433f9349cade1e
+sparc		6dab7ede9390d4d937cb89feca932e4fd575d2da
+net		476ad154f3b41dd7d9a08a2f641e28388abc2fd1
+sound-current	5e68fb3cab23b327e9f15803607e697d7eea1966
+pci-current	9f6445a05b712663b8101a5d2c060a5c40a41fe4
+wireless	7dd6753f6d2e7e0ccbf2263cef3a9fff6bc89988
+driver-core.current	ebdc82899ec5ed35af1c79ed6a4eeda69dad9b90
+tty.current	38f8eefccf3a23c4058a570fa2938a4f553cf8e0
+usb.current	99f347caa4568cb803862730b3b1f1942639523f
+staging.current	3a491aeae86577e0f23cd094f3e16351b6061209
+char-misc.current	f3261dfb5538e2ff0264fde3050dbd4e922fa296
+input-current	cf45b5a2525d9e7473db955750a8db9d4160b6ab
+md-current	58e94ae18478c08229626daece2fc108a4a23261
+audit-current	c158a35c8a681cf68d36f22f058f9f5466386c71
+crypto-current	76f16f83ee520d6c10356b0f6ff592441a6f08bd
+ide		39a50b42f7026027b54131291ad0f350100eac95
+dwmw2		244dc4e54b73567fae7f8fd9ba56584be9375442
+sh-current	44033109e99cf584d6285226ed521098f5ef7250
+irqdomain-current	15e06bf64f686befd2030da867a3dad965b96cc0
+devicetree-current	4e8383b6b06b275999f51337adf7064b2c135a04
+spi-current	d1c185bcb15184ebcbc1b2e003e9a6c4658985c4
+gpio-current	96b70641b937e99c1579cb6ebbcdb7b0af98cdd0
+arm		22018e9473e91a04c74c3d4a96a246f374ab916c
+arm-perf	b90c4b95f5cee1ce804e227fa4308f7deb370a3b
+davinci		fe0d42203cb5616eeff68b14576a0f7e2dd56625
+xilinx		b85a3ef4ac65169b65fd2fe9bec7912bbf475ba4
+blackfin	719154c6d1c1a3a404f4ff570c4b36bb2ef868ca
+c6x		01ddd9a809b9a95df097ff1b5565f806e681a606
+cris		2608747768e9a1b039b365a460ebe306fc73d9e1
+hexagon		5042ab91c4272e158748180ae70a2e097f9e90e3
+ia64		a119365586b0130dfea06457f584953e0ff6481d
+m68k		f82735d55056b200eab19749398457a2f534306b
+m68knommu	aa27fbab38f0c475afb736dd4a640c4fba290995
+microblaze	a01ee165a132fadb57659d26246e340d6ac53265
+mips		9754e2651b09eb6b98146446b2feb83fefbae303
+openrisc	207e715ff17b42e022df107210dc8c736a703eb3
+parisc		5b24c421621792fcc588af6f644d6acf2dd798cc
+powerpc		bdc0077af574800d24318b6945cf2344e8dbb050
+4xx		2074b1d9d53ae696dd3f49482bad43254f40f01d
+mpc5xxx		4d2f4e1644b70b452f8c76c8ab27879bf8acabc9
+galak		1ee9545c838f355ce4cc87eb81dafc0885bc83d3
+s390		3c011c612acbea50c3325db76513baa476879127
+sh		fa75ce649ee2600b117631f8794e0e7dbedb1d68
+sparc-next	6dab7ede9390d4d937cb89feca932e4fd575d2da
+tile		bdc0077af574800d24318b6945cf2344e8dbb050
+unicore32	e4baa56a9a94a75580cffc657c7fad8e1d92e9a6
+xtensa		499d9ec8d92f7e888fc255aa97294d0d8dae18fb
+ceph		1fe5e9932156f6122c3b1ff6ba7541c27c86718c
+cifs		30e59137af17b3d560c20ac199acc41c83dc1480
+configfs	b930c26416c4ea6855726fd977145ccea9afbdda
+ecryptfs	0d7614f09c1ebdbaa1599a5aba7593f147bf96ee
+ext3		68766a2edcd5cd744262a70a2f67a320ac944760
+ext4		8a2f8460e816f4786939a0cefbda35af6bd1a1c5
+fuse		fb6ccff667712c46b4501b920ea73a326e49626a
+gfs2		257cd649be9710e12f9e3c7b3384c8b07802a6a0
+logfs		9f0bbd8ca7905fcc0602c038013b095322fec939
+nfs		12dfd080556124088ed61a292184947711b46cbe
+nfsd		2c142baa7b237584bae7dc28630851701497e1ef
+ocfs2		4538df64655dcfe17b33080b219dc783161a262e
+omfs		976d167615b64e14bc1491ca51d424e2ba9a5e84
+squashfs	4b0180a49f08dd1c681cdc99edc9e0cec0a833fa
+v9fs		5fcb08befaf57faa1b00e514915c1660252b8c26
+ubifs		7074e5eb233343e4bad8c0a3f9e73167cf85a159
+xfs		643bfc061c47e9c7661324a09fb0a0bc6601e5d6
+vfs		808d1b7a63de73d213aebb8096aa7b6c5d4701d3
+pci		0d7614f09c1ebdbaa1599a5aba7593f147bf96ee
+hid		86476aaa5aecc3b219b96df40a1a3d16289e3a69
+i2c		a918790f6f4711df18afd5f6c6d26a429770aba9
+i2c-embedded	d9875690d9b89a866022ff49e3fcea892345ad92
+jdelvare-hwmon	4ac12236d93b961b1df821d0d5a284008b3de2af
+hwmon-staging	b7e3a9ffa9d748f9784ed6ec6e358dcc8b02bf33
+v4l-dvb		34d9daca026e69c61b3f81272add3e40209482e9
+kbuild		85b170eb0737292a92d39ce83d9be883e37c5a17
+kconfig		45f4c81d690a57838822d4d01ad4c03651b76b95
+libata		1b26d29ccd592ea585c7cc291384184c5568da92
+infiniband	c0369b296e839beccd20ffe21b52940eaf1bd9fc
+acpi		9d0b01a1bbb7a4ad23000240b67bca33c4235fcf
+cpuidle		3cf7997a389de59498c966c529456696ce8bc1a7
+cpupowerutils	f16603386b38c28979f4df1cafdc2fe73fa87d37
+thermal		449488ced03a3552b45d5993c06f6f3e422308b7
+ieee1394	e3cbd92002a30aecae8cb8b31a5e1916eb270a14
+ubi		a07ade12e77f424c6f222e5efe66f8c453f00f6f
+dlm		9c5bef5849c9fde1a37ac005299f759440cbaf4c
+scsi		641aa03172de0c66fc1d6472562cffeb6a360572
+target-updates	6a922a33d4d1d15cb7318e97f987b366d5f6b384
+target-merge	d9875690d9b89a866022ff49e3fcea892345ad92
+ibft		935a9fee51c945b8942be2d7b4bae069167b4886
+isci		6734092e66011def7875bd67beef889d0fee1cc9
+slave-dma	c87a9fcd1ed6cd4ad27a0c65db6a470c8dd56190
+dmaengine	a2bd1140a264b561e38d99e656cd843c2d840e86
+net-next	56892261ed1a854db5363df8bb3fbdb2c6c28d4c
+wireless-next	22c5649eef0fc37532e20c14d2656b28ca708a69
+bluetooth	b691f1ab753d7677d875205d54deb511cbcb2172
+mtd		4800399e335658aae632f587f6759a860f584804
+l2-mtd		31311c4ca676035f3a8a1ef6d02742880f0792c5
+crypto		35a1fc1873dd6deac6c005ead85424a8ee28183a
+drm		e2f895fac1e9fb5f59444e07391bfb3da719716f
+sound		1c86845268dc91fa6a53de9a4479b407cd4ee903
+sound-asoc	6664923451dd214b1049a04d353f57306690df46
+rr		d673c23ca730080f44184733b48ff1b7a150850e
+input		2b94e2569441099e01b157fc6821d00806e22ed4
+input-mt	0d7614f09c1ebdbaa1599a5aba7593f147bf96ee
+cgroup		4b2ebf051905258bfee1a2d420f5b4fa149ca6f5
+block		4004e90cfa4488cf99798b1138183158b64f4a42
+device-mapper	057d04004635ab5c57d1f8a855ae2858bdbda61a
+embedded	4744b43431e8613f920c5cba88346756f53c5165
+firmware	6e03a201bbe8137487f340d26aa662110e324b20
+pcmcia		80af9e6d7ae633309cc5bca96aee6a45117e7c98
+mmc		72d0f1126b92970f4ff62c1ef1b5df634a5fd150
+kgdb		15d7ea09071e85388729062e4df0224593a6db5d
+slab		77be4b1366c97b95bb197e18187ff45b0e4f6bd3
+uclinux		5e442a493fc59fa536c76db1fff5b49ca36a88c5
+md		eef0978072c3b83c77a1215933be48a4d70b6206
+mfd		3c1534c7ecffeb4330bba4c55d17f301528195b6
+battery		ecc2edd56c49fa31a0a9ed15a7bf810ae79d3b85
+fbdev		a0239073fd75489d25575cf3aaf71ab55b416020
+viafb		838ac785d521e091bd8b5f6a2b545166f5f32b77
+omap_dss2	974a65825e0b5fbda49605f0416a2c975d66e9e6
+regulator	4785f972944f58c5b84a95dbacaeff230043e6d0
+security	51b743fe87d7fb3dba7a2ff4a1fe23bb65dc2245
+selinux		c2d7b247f0c028d325a5da5b9611b60ba160f237
+lblnet		7e27d6e778cd87b6f2415515d7127eba53fe5d02
+watchdog	06a3fa7a858ae1de852fd7c074ab3ce0ebcc6a5a
+dwmw2-iommu	c3b92c8787367a8bb53d57d9789b558f1295cc96
+iommu		6f286ccde747ee337e0dbc8a9e7908705094c48a
+vfio		d9875690d9b89a866022ff49e3fcea892345ad92
+osd		b8017d2957fb0ebf0c2aa91d48f2465f6f799738
+jc_docs		5c050fb96380a87a85aad9084b68fdcd2b84c193
+trivial		ef706fb55670dfe959b69dde24c2768e4083ef66
+audit		dcd6c92267155e70a94b3927bce681ce74b80d1f
+pm		8b97819fb97bcbcaf42b4f3e7a9a08e2bed00b6b
+apm		f283d22713b0bdc147097c92c9b45855339cf1c8
+fsnotify	1aec9c0d718693553543349e92138033b0bcea4c
+edac		a92cdece496c63d7c44da0ff0b92ba2c7600eff0
+edac-amd	305f1c3cfd7eef63bef2128b6934a9054d902976
+devicetree	efd68e7254503f3207805f674a1ea1d743f5dfe2
+dt-rh		5d61b165c892853f2daf6220d2ec6577487e273a
+spi		d8e328b3bd65fdefc9c49a27ee80c28e0a44b653
+spi-mb		a6c16d9d9ba7547808df8330928a5724af3a4940
+tip		176b900eed575f9a8fcb4e2ddae0a08761a21cd7
+rcu		d1d61c117a7be3ad34bee463ef657f6f51b3046f
+cputime		c3e0ef9a298e028a82ada28101ccd5cf64d209ee
+uprobes		0326f5a94ddea33fa331b2519f4172f4fb387baa
+kmemleak	48786770bf3b3a47bda766ba5f711199e7f24d8f
+kvm		8fbe6a541f50eeec5e3e49bd92db23ade9496673
+kvm-ppc		e9908a44fe2cb5a2178fab44f4cefeb8cca4f04a
+oprofile	c16fa4f2ad19908a47c63d8fa436a1178438c7e7
+xen		af3a3ab2966112c0d0a44df7eeb1e95fe32d4495
+xen-two		df3c572cd86829b5e6bac4da8a28498ae3b88aea
+xen-pvhvm	b056b6a0144de90707cd22cf7b4f60bf69c86d59
+percpu		6101167727932a929e37fb8a6eeb68bdbf54d58e
+workqueues	7635d2fd7f0fa63b6ec03050614c314d7139f14a
+drivers-x86	00d39597e825a2b09ec88d4dd429ff72fe60d9d4
+hwpoison	46e387bbd82d438b9131e237e6e2cb55a825da49
+sysctl		4e474a00d7ff746ed177ddae14fa8b2d4bad7a00
+regmap		e0bf1211ee3ce321ed322c9ddaae2f9377d07408
+hsi		43139a61fc68f4b0af7327a0e63f340a7c81c69a
+leds		052a876eee2f6541a8862739ff2b87b34a5c213f
+driver-core	0592969e73ae50ce6852d1aff3d222a335289094
+tty		5d4121c04b3577e37e389b3553d442f44bb346d7
+usb		26f944b2716717aa243f16cd2181f80441153f0d
+staging		d602a064f9818819d6c99d99f101bc6b1ae1540d
+char-misc	877cdf3949cc67d00677a1dfb913001f324ac40d
+tmem		15773b68fc5854e8890a8e251c568d583a540e4c
+writeback	331cbdeedeb2f4ef01ccb761513708af0fe77098
+arm-dt		ede338f4ce2fb5ee99d18751df32fbd3b10df268
+hwspinlock	8b37fcfc9b3400b647748783a2cafff67793e0ad
+pinctrl		2853ff28b7a189b34941c1ac444363af85272a4f
+vhost		e0953c8b85baaa38d77ebd5dc4051bc3837c1191
+memblock	7bd0b0f0da3b1ec11cbcc798eb0ef747a1184077
+remoteproc	6bb697b6b06041d2d0affc862b17b4b443a107e0
+irqdomain	f5a1ad057e6da5d0fc9c5677ff44797d193d3e62
+gpio		ddf343f635fe4440cad528e12f96f28bd50aa099
+gpio-lw		f47c3df5ef7f0f72e543f9b8116df3f226c30abb
+arm-soc		e149302b10b9437b0c0a66c442b46647779b1918
+ep93xx		fbad8786e3daf0a200d1b4eeef392c58f3626afe
+renesas		45c7a01f070146e08f5c838315ffca5ade6e3844
+samsung		c1f9beea67d7ac68b93a27c5c5a06c660722c740
+tegra		eb9c6a7f028aaadf38b167667038b3ad86f60115
+kvmtool		3c8ef41661c84bc8c96ae120b65fc0a8f4f8029f
+dma-mapping	d9875690d9b89a866022ff49e3fcea892345ad92
+pwm		d767a4106c494307f019eee0ea2008ba20cea5a5
+dma-buf		42a579a0f960081cd16fc945036e4780c3ad3202
+userns		898132ae76d1aeb52301f10e8795c34fbb54e853
+ktest		648a182c615272f01b5cda01dc87a16de9f695bb
+signal		2e117f2dde025f5ca24f8cf97d7dcfbf88748b21
+clk		137f8a7213d80c1388ca48280c1ef0856b6fec30
+random		d2e7c96af1e54b507ae2a6a7dd2baf588417a7e5
+scsi-post-merge	65112dccf8a113737684366349d7f9ec373ddc47
+akpm		5fb158a955632e5a6c2ff161551236bbdd1ee229
diff --git a/Next/Trees b/Next/Trees
new file mode 100644
index 0000000..b6fb040
--- /dev/null
+++ b/Next/Trees
@@ -0,0 +1,199 @@
+Trees included into this release:
+
+Name		Type	URL
+----		----	---
+origin		git	git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git#master
+fixes		git	git://git.kernel.org/pub/scm/linux/kernel/git/sfr/next-fixes.git#master
+kbuild-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild.git#rc-fixes
+arm-current	git	git://ftp.arm.linux.org.uk/pub/linux/arm/kernel/git-cur/linux-arm.git#fixes
+m68k-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git#for-linus
+powerpc-merge	git	git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git#merge
+sparc		git	git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc.git#master
+net		git	git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git#master
+sound-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git#for-linus
+pci-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git#for-linus
+wireless	git	git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git#master
+driver-core.current	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git#driver-core-linus
+tty.current	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git#tty-linus
+usb.current	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git#usb-linus
+staging.current	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git#staging-linus
+char-misc.current	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git#char-misc-linus
+input-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git#for-linus
+md-current	git	git://neil.brown.name/md#for-linus
+audit-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit.git#for-linus
+crypto-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6.git#master
+ide		git	git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide.git#master
+dwmw2		git	git://git.infradead.org/users/dwmw2/random-2.6.git#master
+sh-current	git	git://github.com/pmundt/linux-sh.git#sh-fixes-for-linus
+irqdomain-current	git	git://git.secretlab.ca/git/linux-2.6.git#irqdomain/merge
+devicetree-current	git	git://git.secretlab.ca/git/linux-2.6#devicetree/merge
+spi-current	git	git://git.secretlab.ca/git/linux-2.6#spi/merge
+gpio-current	git	git://git.secretlab.ca/git/linux-2.6#gpio/merge
+arm		git	git://ftp.arm.linux.org.uk/pub/linux/arm/kernel/git-cur/linux-arm.git#for-next
+arm-perf	git	git://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git#for-next/perf
+davinci		git	git://gitorious.org/linux-davinci/linux-davinci.git#davinci-next
+xilinx		git	git://git.xilinx.com/linux-2.6-xlnx.git#arm-next
+blackfin	git	git://git.kernel.org/pub/scm/linux/kernel/git/lliubbo/blackfin.git#for-linus
+c6x		git	git://linux-c6x.org/git/projects/linux-c6x-upstreaming.git#for-linux-next
+cris		git	git://www.jni.nu/cris.git#for-next
+hexagon		git	git://git.kernel.org/pub/scm/linux/kernel/git/rkuo/linux-hexagon-kernel.git#linux-next
+ia64		git	git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux.git#next
+m68k		git	git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git#for-next
+m68knommu	git	git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu.git#for-next
+microblaze	git	git://git.monstr.eu/linux-2.6-microblaze.git#next
+mips		git	git://git.linux-mips.org/pub/scm/ralf/upstream-sfr.git#mips-for-linux-next
+openrisc	git	git://openrisc.net/jonas/linux#for-upstream
+parisc		git	git://git.kernel.org/pub/scm/linux/kernel/git/jejb/parisc-2.6.git#for-next
+powerpc		git	git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git#next
+4xx		git	git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git#next
+mpc5xxx		git	git://git.denx.de/linux-2.6-agust.git#next
+galak		git	git://git.kernel.org/pub/scm/linux/kernel/git/galak/powerpc.git#next
+s390		git	git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux.git#features
+sh		git	git://github.com/pmundt/linux-sh.git#sh-latest
+sparc-next	git	git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next.git#master
+tile		git	git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile.git#master
+unicore32	git	git://github.com/gxt/linux.git#unicore32
+xtensa		git	git://github.com/czankel/xtensa-linux.git#for_next
+ceph		git	git://github.com/ceph/ceph-client.git#master
+cifs		git	git://git.samba.org/sfrench/cifs-2.6.git#for-next
+configfs	git	git://git.kernel.org/pub/scm/linux/kernel/git/jlbec/configfs.git#linux-next
+ecryptfs	git	git://git.kernel.org/pub/scm/linux/kernel/git/tyhicks/ecryptfs.git#next
+ext3		git	git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git#for_next
+ext4		git	git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git#dev
+fuse		git	git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git#for-next
+gfs2		git	git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw.git#master
+logfs		git	git://github.com/prasad-joshi/logfs_upstream.git#master
+nfs		git	git://git.linux-nfs.org/projects/trondmy/nfs-2.6.git#linux-next
+nfsd		git	git://git.linux-nfs.org/~bfields/linux.git#nfsd-next
+ocfs2		git	git://git.kernel.org/pub/scm/linux/kernel/git/jlbec/ocfs2.git#linux-next
+omfs		git	git://github.com/bcopeland/omfs.git#for-next
+squashfs	git	git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-next.git#master
+v9fs		git	git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs.git#for-next
+ubifs		git	git://git.infradead.org/ubifs-2.6.git#linux-next
+xfs		git	git://oss.sgi.com/xfs/xfs.git#for-next
+vfs		git	git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6.git#for-next
+pci		git	git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git#next
+hid		git	git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git#for-next
+i2c		quilt	http://khali.linux-fr.org/devel/linux-3/jdelvare-i2c/
+i2c-embedded	git	git://git.pengutronix.de/git/wsa/linux.git#i2c-embedded/for-next
+jdelvare-hwmon	quilt	http://khali.linux-fr.org/devel/linux-3/jdelvare-hwmon/
+hwmon-staging	git	git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git#hwmon-next
+v4l-dvb		git	git://linuxtv.org/mchehab/media-next.git#master
+kbuild		git	git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild.git#for-next
+kconfig		git	git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-kconfig.git#for-next
+libata		git	git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev.git#NEXT
+infiniband	git	git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband.git#for-next
+acpi		git	git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git#next
+cpuidle		git	git://git.linaro.org/people/dlezcano/cpuidle-next.git#cpuidle-next
+cpupowerutils	git	git://git.kernel.org/pub/scm/linux/kernel/git/brodo/cpupowerutils.git#master
+thermal		git	git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git#next
+ieee1394	git	git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394.git#for-next
+ubi		git	git://git.infradead.org/ubi-2.6.git#linux-next
+dlm		git	git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm.git#next
+scsi		git	git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git#for-next
+target-updates	git	git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git#for-next
+target-merge	git	git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git#for-next-merge
+ibft		git	git://git.kernel.org/pub/scm/linux/kernel/git/konrad/ibft.git#linux-next
+isci		git	git://git.kernel.org/pub/scm/linux/kernel/git/djbw/isci.git#all
+slave-dma	git	git://git.infradead.org/users/vkoul/slave-dma.git#next
+dmaengine	git	git://git.kernel.org/pub/scm/linux/kernel/git/djbw/dmaengine.git#next
+net-next	git	git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git#master
+wireless-next	git	git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next.git#master
+bluetooth	git	git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git#master
+mtd		git	git://git.infradead.org/mtd-2.6.git#master
+l2-mtd		git	git://git.infradead.org/users/dedekind/l2-mtd-2.6.git#master
+crypto		git	git://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git#master
+drm		git	git://people.freedesktop.org/~airlied/linux.git#drm-next
+sound		git	git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git#for-next
+sound-asoc	git	git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git#for-next
+rr		quilt	http://ozlabs.org/~rusty/kernel/rr-latest/
+input		git	git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git#next
+input-mt	git	git://github.com/rydberg/linux.git#for-next
+cgroup		git	git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git#for-next
+block		git	git://git.kernel.dk/linux-block.git#for-next
+device-mapper	quilt	http://people.redhat.com/agk/patches/linux/editing/
+embedded	git	git://git.infradead.org/embedded-2.6.git#master
+firmware	git	git://git.infradead.org/users/dwmw2/firmware-2.6.git#master
+pcmcia		git	git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia.git#master
+mmc		git	git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git#mmc-next
+kgdb		git	git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb.git#kgdb-next
+slab		git	git://github.com/penberg/linux.git#for-next
+uclinux		git	git://git.kernel.org/pub/scm/linux/kernel/git/gerg/uclinux.git#for-next
+md		git	git://neil.brown.name/md#for-next
+mfd		git	git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6.git#for-next
+battery		git	git://git.infradead.org/battery-2.6.git#master
+fbdev		git	git://github.com/schandinat/linux-2.6.git#fbdev-next
+viafb		git	git://github.com/schandinat/linux-2.6.git#viafb-next
+omap_dss2	git	git://gitorious.org/linux-omap-dss2/linux.git#for-next
+regulator	git	git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git#for-next
+security	git	git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git#next
+selinux		git	git://git.infradead.org/users/eparis/selinux.git#master
+lblnet		git	git://git.infradead.org/users/pcmoore/lblnet-2.6_next#master
+watchdog	git	git://www.linux-watchdog.org/linux-watchdog-next.git#master
+dwmw2-iommu	git	git://git.infradead.org/iommu-2.6.git#master
+iommu		git	git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git#next
+vfio		git	git://github.com/awilliam/linux-vfio.git#next
+osd		git	git://git.open-osd.org/linux-open-osd.git#linux-next
+jc_docs		git	git://git.lwn.net/linux-2.6.git#docs-next
+trivial		git	git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial.git#for-next
+audit		git	git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit.git#for-next
+pm		git	git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git#linux-next
+apm		git	git://git.kernel.org/pub/scm/linux/kernel/git/jikos/apm.git#for-next
+fsnotify	git	git://git.infradead.org/users/eparis/notify.git#for-next
+edac		git	git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac.git#linux_next
+edac-amd	git	git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git#for-next
+devicetree	git	git://git.secretlab.ca/git/linux-2.6#devicetree/next
+dt-rh		git	git://sources.calxeda.com/kernel/linux.git#for-next
+spi		git	git://git.secretlab.ca/git/linux-2.6#spi/next
+spi-mb		git	git://git.kernel.org/pub/scm/linux/kernel/git/broonie/misc.git#spi-next
+tip		git	git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git#auto-latest
+rcu		git	git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git#rcu/next
+cputime		git	git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux.git#cputime
+uprobes		git	git://github.com/srikard/linux.git#for-next
+kmemleak	git	git://git.kernel.org/pub/scm/linux/kernel/git/cmarinas/linux.git#kmemleak
+kvm		git	git://git.kernel.org/pub/scm/virt/kvm/kvm.git#linux-next
+kvm-ppc		git	git://github.com/agraf/linux-2.6.git#kvm-ppc-next
+oprofile	git	git://git.kernel.org/pub/scm/linux/kernel/git/rric/oprofile.git#for-next
+xen		git	git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git#upstream/xen
+xen-two		git	git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen.git#linux-next
+xen-pvhvm	git	git://xenbits.xen.org/people/sstabellini/linux-pvhvm.git#linux-next
+percpu		git	git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu.git#for-next
+workqueues	git	git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git#for-next
+drivers-x86	git	git://cavan.codon.org.uk/platform-drivers-x86.git#linux-next
+hwpoison	git	git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6.git#hwpoison
+sysctl		git	git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/sysctl.git#master
+regmap		git	git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git#for-next
+hsi		git	git://gitorious.org/kernel-hsi/kernel-hsi.git#for-next
+leds		git	git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds.git#for-next
+driver-core	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git#driver-core-next
+tty		git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git#tty-next
+usb		git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git#usb-next
+staging		git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git#staging-next
+char-misc	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git#char-misc-next
+tmem		git	git://git.kernel.org/pub/scm/linux/kernel/git/konrad/mm.git#linux-next
+writeback	git	git://git.kernel.org/pub/scm/linux/kernel/git/wfg/linux.git#writeback-for-next
+arm-dt		git	git://git.secretlab.ca/git/linux-2.6#devicetree/arm-next
+hwspinlock	git	git://github.com/ohadbc/hwspinlock-next.git#linux-next
+pinctrl		git	git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git#for-next
+vhost		git	git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git#linux-next
+memblock	git	git://git.kernel.org/pub/scm/linux/kernel/git/tj/misc.git#memblock-kill-early_node_map
+remoteproc	git	git://git.kernel.org/pub/scm/linux/kernel/git/ohad/remoteproc.git#for-next
+irqdomain	git	git://git.secretlab.ca/git/linux-2.6.git#irqdomain/next
+gpio		git	git://git.secretlab.ca/git/linux-2.6#gpio/next
+gpio-lw		git	git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git#for-next
+arm-soc		git	git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git#for-next
+ep93xx		git	git://github.com/RyanMallon/linux-ep93xx.git#ep93xx-for-next
+renesas		git	git://git.kernel.org/pub/scm/linux/kernel/git/rafael/renesas.git#next
+samsung		git	git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git#for-next
+tegra		git	git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra.git#for-next
+kvmtool		git	git://github.com/penberg/linux-kvm.git#master
+dma-mapping	git	git://git.linaro.org/people/mszyprowski/linux-dma-mapping.git#dma-mapping-next
+pwm		git	git://gitorious.org/linux-pwm/linux-pwm.git#for-next
+dma-buf		git	git://git.linaro.org/people/sumitsemwal/linux-dma-buf.git#for-next
+userns		git	git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git#for-next
+ktest		git	git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-ktest.git#for-next
+signal		git	git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal.git#from-sfr
+clk		git	git://git.linaro.org/people/mturquette/linux.git#clk-next
+random		git	git://git.kernel.org/pub/scm/linux/kernel/git/tytso/random.git#dev
+scsi-post-merge	git	git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-post-merge-2.6.git#master
+akpm		mmotm	http://www.ozlabs.org/~akpm/mmotm/
diff --git a/Next/merge.log b/Next/merge.log
new file mode 100644
index 0000000..a699df6
--- /dev/null
+++ b/Next/merge.log
@@ -0,0 +1,8373 @@
+$ date
+Monday 20 August  11:47:24 EST 2012
+$ git checkout master
+Already on 'master'
+$ git reset --hard stable
+HEAD is now at d987569 Linux 3.6-rc2
+Merging origin/master (6dab7ed Merge branch 'fixes' of git://git.linaro.org/people/rmk/linux-arm)
+$ git merge origin/master
+Updating d987569..6dab7ed
+Fast-forward
+ Documentation/w1/slaves/w1_therm              |    2 +
+ MAINTAINERS                                   |   10 +-
+ arch/arm/Kconfig                              |    6 -
+ arch/arm/include/asm/pgtable.h                |   40 +-
+ arch/arm/include/asm/sched_clock.h            |    2 +
+ arch/arm/kernel/sched_clock.c                 |   24 ++
+ arch/arm/kernel/topology.c                    |    2 +-
+ arch/arm/lib/Makefile                         |   23 +-
+ arch/arm/lib/io-readsw-armv3.S                |  106 +++++
+ arch/arm/lib/io-writesw-armv3.S               |  126 ++++++
+ arch/arm/lib/uaccess.S                        |  564 +++++++++++++++++++++++++
+ arch/arm/mm/flush.c                           |    2 -
+ arch/arm/mm/tlb-v7.S                          |    6 +-
+ arch/arm/vfp/vfpmodule.c                      |    2 +
+ arch/c6x/Kconfig                              |    1 +
+ arch/c6x/include/asm/cache.h                  |   16 +-
+ drivers/base/core.c                           |    9 +-
+ drivers/base/power/runtime.c                  |   13 +-
+ drivers/cpuidle/coupled.c                     |   14 +-
+ drivers/extcon/extcon_gpio.c                  |    3 +-
+ drivers/idle/intel_idle.c                     |    3 +-
+ drivers/iio/frequency/adf4350.c               |   24 +-
+ drivers/iio/light/adjd_s311.c                 |    7 +-
+ drivers/iio/light/lm3533-als.c                |    4 +-
+ drivers/infiniband/core/ucma.c                |    2 +-
+ drivers/infiniband/hw/amso1100/c2_rnic.c      |    2 +-
+ drivers/infiniband/hw/cxgb3/iwch_cm.c         |    2 +-
+ drivers/infiniband/hw/mlx4/mad.c              |   16 +-
+ drivers/infiniband/hw/mlx4/main.c             |    5 +-
+ drivers/infiniband/hw/mlx4/qp.c               |    6 +-
+ drivers/infiniband/hw/ocrdma/ocrdma_main.c    |   16 +-
+ drivers/infiniband/hw/qib/qib_iba7322.c       |    4 +-
+ drivers/infiniband/hw/qib/qib_sd7220.c        |    2 +-
+ drivers/infiniband/ulp/ipoib/ipoib_cm.c       |    3 +
+ drivers/infiniband/ulp/ipoib/ipoib_main.c     |    2 +-
+ drivers/infiniband/ulp/srp/ib_srp.c           |   87 ++--
+ drivers/infiniband/ulp/srpt/ib_srpt.c         |    2 +-
+ drivers/md/md.c                               |    9 +-
+ drivers/md/raid10.c                           |   30 +-
+ drivers/md/raid10.h                           |    2 +-
+ drivers/misc/mei/interrupt.c                  |    2 +-
+ drivers/misc/mei/main.c                       |   27 ++
+ drivers/misc/ti-st/st_ll.c                    |    2 +-
+ drivers/net/ethernet/mellanox/mlx4/icm.c      |    9 +-
+ drivers/net/ethernet/mellanox/mlx4/icm.h      |    2 +-
+ drivers/net/ethernet/mellanox/mlx4/mlx4.h     |    4 +-
+ drivers/net/ethernet/mellanox/mlx4/mr.c       |   27 +-
+ drivers/net/ethernet/mellanox/mlx4/profile.c  |    4 +-
+ drivers/staging/comedi/drivers.c              |    2 +-
+ drivers/staging/comedi/drivers/adv_pci1710.c  |    3 -
+ drivers/staging/comedi/drivers/adv_pci1723.c  |    2 -
+ drivers/staging/comedi/drivers/adv_pci_dio.c  |    2 -
+ drivers/staging/comedi/drivers/daqboard2000.c |   17 +-
+ drivers/staging/comedi/drivers/dt3000.c       |    6 +-
+ drivers/staging/comedi/drivers/rtd520.c       |   26 +-
+ drivers/staging/comedi/drivers/usbdux.c       |    4 +-
+ drivers/staging/comedi/drivers/usbduxfast.c   |    4 +-
+ drivers/staging/comedi/drivers/usbduxsigma.c  |    4 +-
+ drivers/staging/csr/Kconfig                   |    2 +-
+ drivers/staging/iio/adc/ad7192.c              |   48 ++-
+ drivers/staging/iio/adc/ad7298_ring.c         |    2 +-
+ drivers/staging/iio/adc/ad7780.c              |   10 +-
+ drivers/staging/iio/adc/ad7793.c              |   99 +++--
+ drivers/tty/serial/Kconfig                    |   10 +-
+ drivers/tty/serial/ifx6x60.c                  |    2 +-
+ drivers/tty/serial/mxs-auart.c                |   14 +-
+ drivers/tty/serial/pmac_zilog.c               |   12 +-
+ drivers/usb/chipidea/Kconfig                  |    9 +-
+ drivers/usb/gadget/u_ether.c                  |    6 +
+ drivers/usb/host/ehci-omap.c                  |  167 +-------
+ drivers/usb/host/ehci-sead3.c                 |    2 +-
+ drivers/usb/host/ehci-tegra.c                 |    3 +-
+ drivers/usb/host/isp1362-hcd.c                |    8 +-
+ drivers/usb/host/pci-quirks.c                 |    7 +
+ drivers/usb/host/pci-quirks.h                 |    1 +
+ drivers/usb/host/xhci-pci.c                   |   10 +
+ drivers/usb/host/xhci-ring.c                  |   40 +-
+ drivers/usb/host/xhci.c                       |    8 +-
+ drivers/usb/host/xhci.h                       |    3 +
+ drivers/usb/musb/Kconfig                      |    4 +-
+ drivers/usb/musb/musb_dsps.c                  |   19 +-
+ drivers/usb/renesas_usbhs/common.c            |    6 +-
+ drivers/usb/renesas_usbhs/mod_host.c          |    8 +
+ drivers/usb/serial/bus.c                      |   15 +-
+ drivers/usb/serial/ftdi_sio.c                 |    1 +
+ drivers/usb/serial/ftdi_sio_ids.h             |    7 +
+ drivers/usb/serial/ipw.c                      |    3 +-
+ drivers/usb/serial/mos7840.c                  |   16 +-
+ drivers/usb/serial/option.c                   |  285 +++++--------
+ drivers/usb/serial/qcserial.c                 |   47 ++-
+ drivers/usb/serial/usb-wwan.h                 |    3 +-
+ drivers/usb/serial/usb_wwan.c                 |   68 ++-
+ drivers/w1/slaves/w1_therm.c                  |    9 +
+ drivers/w1/w1_family.h                        |    1 +
+ fs/autofs4/expire.c                           |    5 -
+ fs/ext4/balloc.c                              |   62 +--
+ fs/ext4/bitmap.c                              |    1 -
+ fs/ext4/extents.c                             |    1 +
+ fs/ext4/super.c                               |    6 +
+ fs/fuse/dir.c                                 |    3 +
+ fs/jbd2/journal.c                             |    3 +-
+ fs/namei.c                                    |    8 +-
+ fs/open.c                                     |    7 +-
+ include/linux/iio/frequency/adf4350.h         |    2 +
+ include/linux/jbd2.h                          |    1 +
+ scripts/kernel-doc                            |    1 +
+ security/yama/yama_lsm.c                      |   10 +-
+ 107 files changed, 1643 insertions(+), 768 deletions(-)
+ create mode 100644 arch/arm/lib/io-readsw-armv3.S
+ create mode 100644 arch/arm/lib/io-writesw-armv3.S
+ create mode 100644 arch/arm/lib/uaccess.S
+Merging fixes/master (9023a40 Merge tag 'mmc-fixes-for-3.5-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc)
+$ git merge fixes/master
+Already up-to-date.
+Merging kbuild-current/rc-fixes (f8f5701 Linux 3.5-rc1)
+$ git merge kbuild-current/rc-fixes
+Already up-to-date.
+Merging arm-current/fixes (8986873 ARM: 7490/1: Drop duplicate select for GENERIC_IRQ_PROBE)
+$ git merge arm-current/fixes
+Already up-to-date.
+Merging m68k-current/for-linus (9e2760d m68k: Make sys_atomic_cmpxchg_32 work on classic m68k)
+$ git merge m68k-current/for-linus
+Already up-to-date.
+Merging powerpc-merge/merge (ad36cb0 powerpc/kvm/book3s_32: Fix MTMSR_EERI macro)
+$ git merge powerpc-merge/merge
+Already up-to-date.
+Merging sparc/master (6dab7ed Merge branch 'fixes' of git://git.linaro.org/people/rmk/linux-arm)
+$ git merge sparc/master
+Already up-to-date.
+Merging net/master (476ad15 net: netprio: fix cgrp create and write priomap race)
+$ git merge net/master
+Merge made by the 'recursive' strategy.
+ Documentation/networking/netconsole.txt            |   19 +-
+ drivers/bluetooth/ath3k.c                          |    2 +
+ drivers/bluetooth/btusb.c                          |    2 +
+ drivers/net/bonding/bond_main.c                    |   12 +-
+ .../net/ethernet/freescale/fs_enet/mii-bitbang.c   |    4 +-
+ drivers/net/ethernet/freescale/fs_enet/mii-fec.c   |    8 +-
+ drivers/net/ethernet/mellanox/mlx4/mcg.c           |    4 +-
+ drivers/net/ethernet/ti/davinci_cpdma.c            |    3 +-
+ drivers/net/netconsole.c                           |    5 -
+ drivers/net/team/team.c                            |   16 +-
+ drivers/net/usb/qmi_wwan.c                         |  248 ++++----------------
+ drivers/net/usb/sierra_net.c                       |   52 +---
+ drivers/net/vmxnet3/vmxnet3_drv.c                  |    2 +-
+ drivers/net/wireless/at76c50x-usb.c                |    2 +-
+ drivers/net/wireless/ath/ath5k/base.c              |    6 +-
+ drivers/net/wireless/ath/ath5k/mac80211-ops.c      |    5 +-
+ drivers/net/wireless/ath/ath9k/mac.c               |   18 +-
+ drivers/net/wireless/ath/ath9k/mac.h               |    1 +
+ drivers/net/wireless/ath/ath9k/main.c              |    4 +-
+ drivers/net/wireless/ath/ath9k/pci.c               |    1 +
+ drivers/net/wireless/ath/ath9k/recv.c              |    2 +-
+ drivers/net/wireless/rndis_wlan.c                  |    6 +-
+ include/linux/if_team.h                            |   30 +--
+ include/linux/netdevice.h                          |    3 +-
+ include/linux/netpoll.h                            |   42 ++--
+ include/net/llc.h                                  |    2 +-
+ net/8021q/vlan_dev.c                               |   52 ++--
+ net/atm/common.c                                   |    1 +
+ net/atm/pvc.c                                      |    1 +
+ net/bluetooth/hci_event.c                          |   28 ++-
+ net/bluetooth/hci_sock.c                           |    2 +
+ net/bluetooth/l2cap_core.c                         |    1 +
+ net/bluetooth/l2cap_sock.c                         |    3 +-
+ net/bluetooth/rfcomm/sock.c                        |    2 +
+ net/bluetooth/rfcomm/tty.c                         |    2 +-
+ net/bluetooth/sco.c                                |   19 +-
+ net/bluetooth/smp.c                                |    5 +-
+ net/bridge/br_device.c                             |   30 +--
+ net/bridge/br_forward.c                            |    2 +-
+ net/bridge/br_if.c                                 |    6 +-
+ net/bridge/br_private.h                            |    4 +-
+ net/core/netpoll.c                                 |  109 ++++++---
+ net/core/netprio_cgroup.c                          |   30 +--
+ net/core/scm.c                                     |    4 +
+ net/dccp/ccid.h                                    |    4 +-
+ net/dccp/ccids/ccid3.c                             |    1 +
+ net/ipv4/route.c                                   |    1 -
+ net/ipv6/addrconf.c                                |    4 +-
+ net/ipv6/proc.c                                    |    4 +-
+ net/l2tp/l2tp_ip6.c                                |    1 +
+ net/llc/af_llc.c                                   |    8 +-
+ net/llc/llc_input.c                                |   21 +-
+ net/llc/llc_station.c                              |   23 +-
+ net/netfilter/ipvs/ip_vs_ctl.c                     |    1 +
+ net/sched/act_mirred.c                             |   11 +-
+ net/socket.c                                       |    1 +
+ 56 files changed, 396 insertions(+), 484 deletions(-)
+Merging sound-current/for-linus (5e68fb3 ALSA: hda - Don't send invalid volume knob command on IDT 92hd75bxx)
+$ git merge sound-current/for-linus
+Merge made by the 'recursive' strategy.
+ sound/arm/pxa2xx-ac97.c        |    4 ++--
+ sound/atmel/abdac.c            |    2 +-
+ sound/atmel/ac97c.c            |    2 +-
+ sound/drivers/aloop.c          |    2 +-
+ sound/drivers/dummy.c          |    2 +-
+ sound/drivers/pcsp/pcsp.c      |    4 ++--
+ sound/pci/cs46xx/cs46xx_lib.c  |    2 +-
+ sound/pci/hda/hda_beep.c       |   29 +++++++++++++++++++++++------
+ sound/pci/hda/hda_codec.c      |    2 +-
+ sound/pci/hda/hda_intel.c      |    9 +++++++++
+ sound/pci/hda/hda_proc.c       |    2 +-
+ sound/pci/hda/patch_sigmatel.c |    9 +++++----
+ sound/pci/hda/patch_via.c      |    8 ++++++++
+ sound/pci/lx6464es/lx6464es.c  |    2 ++
+ sound/ppc/powermac.c           |    2 +-
+ sound/usb/endpoint.c           |    4 ----
+ sound/usb/pcm.c                |    3 +++
+ 17 files changed, 62 insertions(+), 26 deletions(-)
+Merging pci-current/for-linus (9f6445a Merge branch 'pci/rafael-3.6-fixes' into for-linus)
+$ git merge pci-current/for-linus
+Merge made by the 'recursive' strategy.
+ drivers/pci/pci-acpi.c   |    4 ++--
+ drivers/pci/pci-driver.c |    7 +++++++
+ 2 files changed, 9 insertions(+), 2 deletions(-)
+Merging wireless/master (7dd6753 ath5k: fix spin_lock_irqsave/spin_lock_bh nesting in mesh)
+$ git merge wireless/master
+Already up-to-date.
+Merging driver-core.current/driver-core-linus (ebdc828 dyndbg: fix for SOH in logging messages)
+$ git merge driver-core.current/driver-core-linus
+Merge made by the 'recursive' strategy.
+ drivers/base/core.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+Merging tty.current/tty-linus (38f8eef pmac_zilog,kdb: Fix console poll hook to return instead of loop)
+$ git merge tty.current/tty-linus
+Already up-to-date.
+Merging usb.current/usb-linus (99f347c USB: CDC ACM: Fix NULL pointer dereference)
+$ git merge usb.current/usb-linus
+Merge made by the 'recursive' strategy.
+ drivers/media/dvb/siano/smsusb.c           |    2 +-
+ drivers/media/video/gspca/jl2005bcd.c      |    2 +-
+ drivers/media/video/gspca/spca506.c        |    2 +-
+ drivers/net/wireless/p54/p54usb.c          |    2 +-
+ drivers/net/wireless/rtl818x/rtl8187/dev.c |    2 +-
+ drivers/staging/vt6656/main_usb.c          |    2 +-
+ drivers/staging/winbond/wbusb.c            |    2 +-
+ drivers/usb/class/cdc-acm.c                |    3 ++-
+ drivers/usb/misc/emi62.c                   |    2 +-
+ 9 files changed, 10 insertions(+), 9 deletions(-)
+Merging staging.current/staging-linus (3a491ae Merge tag 'v3.6-rc1-iio-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-linus)
+$ git merge staging.current/staging-linus
+Already up-to-date.
+Merging char-misc.current/char-misc-linus (f3261df 1-Wire: Add support for the maxim ds1825 temperature sensor)
+$ git merge char-misc.current/char-misc-linus
+Already up-to-date.
+Merging input-current/for-linus (cf45b5a Merge branch 'next' into for-linus)
+$ git merge input-current/for-linus
+Already up-to-date.
+Merging md-current/for-linus (58e94ae md/raid1: close some possible races on write errors during resync)
+$ git merge md-current/for-linus
+Already up-to-date.
+Merging audit-current/for-linus (c158a35 audit: no leading space in audit_log_d_path prefix)
+$ git merge audit-current/for-linus
+Already up-to-date.
+Merging crypto-current/master (76f16f8 crypto: hifn_795x - fix 64bit division and undefined __divdi3 on 32bit archs)
+$ git merge crypto-current/master
+Merge made by the 'recursive' strategy.
+ drivers/crypto/hifn_795x.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+Merging ide/master (39a50b4 Merge branch 'hfsplus')
+$ git merge ide/master
+Already up-to-date.
+Merging dwmw2/master (244dc4e Merge git://git.infradead.org/users/dwmw2/random-2.6)
+$ git merge dwmw2/master
+Already up-to-date.
+Merging sh-current/sh-fixes-for-linus (4403310 SH: Convert out[bwl] macros to inline functions)
+$ git merge sh-current/sh-fixes-for-linus
+Already up-to-date.
+Merging irqdomain-current/irqdomain/merge (15e06bf irqdomain: Fix debugfs formatting)
+$ git merge irqdomain-current/irqdomain/merge
+Already up-to-date.
+Merging devicetree-current/devicetree/merge (4e8383b of: release node fix for of_parse_phandle_with_args)
+$ git merge devicetree-current/devicetree/merge
+Auto-merging drivers/of/base.c
+Merge made by the 'recursive' strategy.
+ drivers/of/base.c |    2 ++
+ 1 file changed, 2 insertions(+)
+Merging spi-current/spi/merge (d1c185b of/spi: Fix SPI module loading by using proper "spi:" modalias prefixes.)
+$ git merge spi-current/spi/merge
+Auto-merging drivers/spi/spi.c
+Auto-merging drivers/spi/spi-s3c64xx.c
+Auto-merging drivers/spi/spi-bcm63xx.c
+Merge made by the 'recursive' strategy.
+ drivers/spi/spi-bcm63xx.c |   16 ++++++----------
+ drivers/spi/spi-s3c64xx.c |   10 ++++------
+ drivers/spi/spi.c         |    5 ++++-
+ 3 files changed, 14 insertions(+), 17 deletions(-)
+Merging gpio-current/gpio/merge (96b7064 gpio/tca6424: merge I2C transactions, remove cast)
+$ git merge gpio-current/gpio/merge
+Already up-to-date.
+Merging arm/for-next (22018e9 Merge branches 'fixes' and 'misc' into for-next)
+$ git merge arm/for-next
+Merge made by the 'recursive' strategy.
+ arch/arm/mach-exynos/platsmp.c |    2 +-
+ arch/arm/mm/init.c             |    2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+Merging arm-perf/for-next/perf (b90c4b9 Merge branch 'hw-breakpoint' into for-next/perf)
+$ git merge arm-perf/for-next/perf
+Removing arch/arm/kernel/pmu.c
+Auto-merging arch/arm/Kconfig
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ Documentation/devicetree/bindings/arm/pmu.txt |    4 +
+ MAINTAINERS                                   |    1 -
+ arch/arm/Kconfig                              |    8 +-
+ arch/arm/include/asm/perf_event.h             |    9 +-
+ arch/arm/include/asm/pmu.h                    |   77 ++----
+ arch/arm/kernel/Makefile                      |    3 +-
+ arch/arm/kernel/hw_breakpoint.c               |   61 +++--
+ arch/arm/kernel/perf_event.c                  |  347 ++++---------------------
+ arch/arm/kernel/perf_event_cpu.c              |  295 +++++++++++++++++++++
+ arch/arm/kernel/perf_event_v6.c               |   12 +-
+ arch/arm/kernel/perf_event_v7.c               |   32 +--
+ arch/arm/kernel/perf_event_xscale.c           |   10 +-
+ arch/arm/kernel/pmu.c                         |   36 ---
+ arch/arm/mach-bcmring/arch.c                  |    3 +-
+ arch/arm/mach-omap2/devices.c                 |    3 +-
+ arch/arm/mach-pxa/devices.c                   |    3 +-
+ arch/arm/mach-realview/realview_eb.c          |    3 +-
+ arch/arm/mach-realview/realview_pb1176.c      |    3 +-
+ arch/arm/mach-realview/realview_pb11mp.c      |    3 +-
+ arch/arm/mach-realview/realview_pba8.c        |    3 +-
+ arch/arm/mach-realview/realview_pbx.c         |    3 +-
+ arch/arm/mach-tegra/devices.c                 |    3 +-
+ arch/arm/mach-ux500/cpu-db8500.c              |    3 +-
+ arch/arm/mach-vexpress/ct-ca9x4.c             |    3 +-
+ arch/arm/plat-iop/pmu.c                       |    3 +-
+ arch/arm/plat-samsung/devs.c                  |    3 +-
+ 26 files changed, 467 insertions(+), 467 deletions(-)
+ create mode 100644 arch/arm/kernel/perf_event_cpu.c
+ delete mode 100644 arch/arm/kernel/pmu.c
+Merging davinci/davinci-next (fe0d422 Linux 3.0-rc6)
+$ git merge davinci/davinci-next
+Already up-to-date.
+Merging xilinx/arm-next (b85a3ef ARM: Xilinx: Adding Xilinx board support)
+$ git merge xilinx/arm-next
+Already up-to-date.
+Merging blackfin/for-linus (719154c bf60x: fix build warning)
+$ git merge blackfin/for-linus
+Already up-to-date.
+Merging c6x/for-linux-next (01ddd9a C6X: select GENERIC_ATOMIC64)
+$ git merge c6x/for-linux-next
+Already up-to-date.
+Merging cris/for-next (2608747 CRIS: Remove VCS simulator specific code)
+$ git merge cris/for-next
+Removing arch/cris/arch-v32/mach-fs/vcs_hook.h
+Removing arch/cris/arch-v32/mach-fs/vcs_hook.c
+Removing arch/cris/arch-v32/mach-a3/vcs_hook.h
+Removing arch/cris/arch-v32/mach-a3/vcs_hook.c
+Auto-merging arch/cris/arch-v32/drivers/pci/bios.c
+Auto-merging arch/cris/Kconfig
+Merge made by the 'recursive' strategy.
+ arch/cris/Kconfig                                  |    5 -
+ arch/cris/arch-v32/drivers/axisflashmap.c          |   29 ------
+ arch/cris/arch-v32/drivers/pci/bios.c              |   25 -----
+ arch/cris/arch-v32/kernel/head.S                   |   58 +----------
+ arch/cris/arch-v32/kernel/kgdb.c                   |   14 ---
+ arch/cris/arch-v32/mach-a3/Makefile                |    2 -
+ arch/cris/arch-v32/mach-a3/vcs_hook.c              |  103 --------------------
+ arch/cris/arch-v32/mach-a3/vcs_hook.h              |   58 -----------
+ arch/cris/arch-v32/mach-fs/Makefile                |    2 -
+ arch/cris/arch-v32/mach-fs/vcs_hook.c              |  100 -------------------
+ arch/cris/arch-v32/mach-fs/vcs_hook.h              |   42 --------
+ arch/cris/arch-v32/mm/init.c                       |    8 --
+ arch/cris/include/arch-v32/arch/page.h             |    5 -
+ arch/cris/include/arch-v32/arch/processor.h        |    6 +-
+ .../cris/include/arch-v32/mach-fs/mach/startup.inc |    6 --
+ arch/cris/include/asm/pci.h                        |    1 -
+ 16 files changed, 3 insertions(+), 461 deletions(-)
+ delete mode 100644 arch/cris/arch-v32/mach-a3/vcs_hook.c
+ delete mode 100644 arch/cris/arch-v32/mach-a3/vcs_hook.h
+ delete mode 100644 arch/cris/arch-v32/mach-fs/vcs_hook.c
+ delete mode 100644 arch/cris/arch-v32/mach-fs/vcs_hook.h
+Merging hexagon/linux-next (5042ab9 various Kconfig cleanup and old platform build code removal)
+$ git merge hexagon/linux-next
+Already up-to-date.
+Merging ia64/next (a119365 [IA64] Redefine ATOMIC_INIT and ATOMIC64_INIT to drop the casts)
+$ git merge ia64/next
+Already up-to-date.
+Merging m68k/for-next (f82735d m68k: Use PTR_RET rather than if(IS_ERR(...)) + PTR_ERR)
+$ git merge m68k/for-next
+Merge made by the 'recursive' strategy.
+ arch/m68k/amiga/platform.c       |    5 +----
+ arch/m68k/include/asm/apollohw.h |   12 ------------
+ arch/m68k/kernel/time.c          |    5 +----
+ arch/m68k/q40/config.c           |    5 +----
+ 4 files changed, 3 insertions(+), 24 deletions(-)
+Merging m68knommu/for-next (aa27fba m68k: select CONFIG_GENERIC_ATOMIC64 for all m68k CPU types)
+$ git merge m68knommu/for-next
+Merge made by the 'recursive' strategy.
+ arch/m68k/Kconfig     |    1 +
+ arch/m68k/Kconfig.cpu |    5 +----
+ 2 files changed, 2 insertions(+), 4 deletions(-)
+Merging microblaze/next (a01ee16 Merge branch 'for-linus' of git://git.open-osd.org/linux-open-osd)
+$ git merge microblaze/next
+Already up-to-date.
+Merging mips/mips-for-linux-next (9754e26 Merge branches 'next/ath79', 'next/for-linus', 'next/generic', 'next/lantiq' and 'next/trace' into mips-for-linux-next)
+$ git merge mips/mips-for-linux-next
+Auto-merging drivers/spi/spi-bcm63xx.c
+Merge made by the 'recursive' strategy.
+ arch/mips/Kconfig                                  |    8 +
+ arch/mips/alchemy/board-mtx1.c                     |    2 +
+ arch/mips/ath79/dev-usb.c                          |    2 +
+ arch/mips/ath79/gpio.c                             |    6 +-
+ arch/mips/bcm63xx/dev-spi.c                        |    4 +
+ arch/mips/cavium-octeon/octeon-irq.c               |   89 +-
+ arch/mips/configs/ath79_defconfig                  |  111 +++
+ arch/mips/include/asm/atomic.h                     |   64 +-
+ arch/mips/include/asm/cpu-features.h               |    4 +
+ arch/mips/include/asm/cpu.h                        |    1 +
+ arch/mips/include/asm/elf.h                        |    1 +
+ arch/mips/include/asm/mach-ath79/ar71xx_regs.h     |    3 +-
+ .../include/asm/mach-ath79/cpu-feature-overrides.h |    1 -
+ .../include/asm/mach-bcm63xx/bcm63xx_dev_spi.h     |    2 +
+ arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h  |   13 +-
+ arch/mips/include/asm/mach-cavium-octeon/irq.h     |   10 +-
+ .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h |    3 +
+ arch/mips/include/asm/mipsregs.h                   |    2 +
+ arch/mips/include/asm/module.h                     |    1 +
+ arch/mips/include/asm/ptrace.h                     |   17 +-
+ arch/mips/include/asm/r4k-timer.h                  |    8 +-
+ arch/mips/include/asm/siginfo.h                    |    9 +
+ arch/mips/include/asm/syscall.h                    |  183 ++++
+ arch/mips/include/asm/thread_info.h                |    7 +
+ arch/mips/include/asm/unistd.h                     |   11 +
+ arch/mips/kernel/Makefile                          |    1 +
+ arch/mips/kernel/cpu-probe.c                       |    5 +-
+ arch/mips/kernel/ftrace.c                          |   33 +
+ arch/mips/kernel/module.c                          |   43 +-
+ arch/mips/kernel/perf_event_mipsxx.c               |  262 +++---
+ arch/mips/kernel/ptrace.c                          |  210 +++--
+ arch/mips/kernel/scall32-o32.S                     |  887 +++++++++-----------
+ arch/mips/kernel/scall64-64.S                      |   40 +-
+ arch/mips/kernel/scall64-n32.S                     |   48 +-
+ arch/mips/kernel/scall64-o32.S                     |   82 +-
+ arch/mips/kernel/smp.c                             |    4 +-
+ arch/mips/kernel/sync-r4k.c                        |   26 +-
+ arch/mips/kernel/vmlinux.lds.S                     |   21 +-
+ arch/mips/lantiq/xway/sysctrl.c                    |   14 +
+ arch/mips/mm/init.c                                |   17 +-
+ arch/mips/mti-malta/malta-pci.c                    |   13 -
+ arch/mips/pci/pci-lantiq.c                         |    7 +-
+ drivers/spi/spi-bcm63xx.c                          |   31 +-
+ include/asm-generic/vmlinux.lds.h                  |    9 +
+ 44 files changed, 1371 insertions(+), 944 deletions(-)
+ create mode 100644 arch/mips/configs/ath79_defconfig
+ create mode 100644 arch/mips/include/asm/syscall.h
+Merging openrisc/for-upstream (207e715 openrisc: use scratch regs in atomic syscall)
+$ git merge openrisc/for-upstream
+Already up-to-date.
+Merging parisc/for-next (5b24c42 [PARISC] fix personality flag check in copy_thread())
+$ git merge parisc/for-next
+Merge made by the 'recursive' strategy.
+ arch/parisc/include/asm/atomic.h |    4 ++--
+ arch/parisc/kernel/process.c     |    2 +-
+ arch/parisc/kernel/sys_parisc.c  |    8 ++++----
+ 3 files changed, 7 insertions(+), 7 deletions(-)
+Merging powerpc/next (bdc0077 Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi)
+$ git merge powerpc/next
+Already up-to-date.
+Merging 4xx/next (2074b1d powerpc: Fix irq distribution)
+$ git merge 4xx/next
+Already up-to-date.
+Merging mpc5xxx/next (4d2f4e1 powerpc: Option FB_FSL_DIU is not really optional for mpc512x)
+$ git merge mpc5xxx/next
+Merge made by the 'recursive' strategy.
+ arch/powerpc/platforms/512x/Kconfig          |    1 +
+ arch/powerpc/platforms/512x/clock.c          |    6 ++++--
+ arch/powerpc/platforms/512x/mpc512x_shared.c |    6 ------
+ 3 files changed, 5 insertions(+), 8 deletions(-)
+Merging galak/next (1ee9545 powerpc/mpc85xx: Add new ext fields to Integrated FLash Controller)
+$ git merge galak/next
+Removing arch/powerpc/boot/dts/p2020rdb_camp_core1.dts
+Removing arch/powerpc/boot/dts/p2020rdb_camp_core0.dts
+Removing arch/powerpc/boot/dts/p1020rdb_camp_core1.dts
+Removing arch/powerpc/boot/dts/p1020rdb_camp_core0.dts
+Merge made by the 'recursive' strategy.
+ .../devicetree/bindings/powerpc/fsl/ifc.txt        |    9 +-
+ arch/powerpc/Kconfig                               |    6 +-
+ arch/powerpc/boot/dts/fsl/e500mc_power_isa.dtsi    |   58 ++++
+ arch/powerpc/boot/dts/fsl/e500v2_power_isa.dtsi    |   52 ++++
+ arch/powerpc/boot/dts/fsl/e5500_power_isa.dtsi     |   59 ++++
+ arch/powerpc/boot/dts/fsl/mpc8536si-pre.dtsi       |    3 +
+ arch/powerpc/boot/dts/fsl/mpc8544si-pre.dtsi       |    3 +
+ arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi       |    3 +
+ arch/powerpc/boot/dts/fsl/mpc8568si-pre.dtsi       |    3 +
+ arch/powerpc/boot/dts/fsl/mpc8569si-pre.dtsi       |    3 +
+ arch/powerpc/boot/dts/fsl/mpc8572si-pre.dtsi       |    3 +
+ arch/powerpc/boot/dts/fsl/p1010si-pre.dtsi         |    3 +
+ arch/powerpc/boot/dts/fsl/p1020si-pre.dtsi         |    3 +
+ arch/powerpc/boot/dts/fsl/p1021si-pre.dtsi         |    3 +
+ arch/powerpc/boot/dts/fsl/p1022si-pre.dtsi         |    3 +
+ arch/powerpc/boot/dts/fsl/p1023si-pre.dtsi         |    3 +
+ arch/powerpc/boot/dts/fsl/p2020si-pre.dtsi         |    3 +
+ arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi         |    3 +
+ arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi         |    3 +
+ arch/powerpc/boot/dts/fsl/p4080si-post.dtsi        |    7 +
+ arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi         |    3 +
+ arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi         |    3 +
+ arch/powerpc/boot/dts/fsl/p5040si-post.dtsi        |  320 ++++++++++++++++++++
+ arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi         |  114 +++++++
+ arch/powerpc/boot/dts/fsl/qoriq-sec5.2-0.dtsi      |  118 ++++++++
+ arch/powerpc/boot/dts/mpc8540ads.dts               |    2 +
+ arch/powerpc/boot/dts/mpc8541cds.dts               |    2 +
+ arch/powerpc/boot/dts/mpc8555cds.dts               |    2 +
+ arch/powerpc/boot/dts/mpc8560ads.dts               |    2 +
+ arch/powerpc/boot/dts/p1020rdb_camp_core0.dts      |   63 ----
+ arch/powerpc/boot/dts/p1020rdb_camp_core1.dts      |  141 ---------
+ arch/powerpc/boot/dts/p1022rdk.dts                 |  188 ++++++++++++
+ arch/powerpc/boot/dts/p2020rdb_camp_core0.dts      |   67 ----
+ arch/powerpc/boot/dts/p2020rdb_camp_core1.dts      |  125 --------
+ arch/powerpc/boot/dts/p5040ds.dts                  |  203 +++++++++++++
+ arch/powerpc/configs/corenet32_smp_defconfig       |    1 +
+ arch/powerpc/configs/corenet64_smp_defconfig       |    1 +
+ arch/powerpc/configs/mpc85xx_defconfig             |    2 +
+ arch/powerpc/configs/mpc85xx_smp_defconfig         |    1 +
+ arch/powerpc/include/asm/cacheflush.h              |    2 +
+ arch/powerpc/include/asm/fsl_guts.h                |    2 +
+ arch/powerpc/include/asm/fsl_ifc.h                 |   14 +-
+ arch/powerpc/include/asm/mpic.h                    |   19 ++
+ arch/powerpc/include/asm/smp.h                     |    2 +
+ arch/powerpc/include/asm/swiotlb.h                 |    6 +
+ arch/powerpc/kernel/cpu_setup_fsl_booke.S          |   74 ++++-
+ arch/powerpc/kernel/cputable.c                     |    4 +
+ arch/powerpc/kernel/dma-swiotlb.c                  |   20 ++
+ arch/powerpc/kernel/exceptions-64e.S               |   18 +-
+ arch/powerpc/kernel/head_fsl_booke.S               |   46 ++-
+ arch/powerpc/kernel/smp.c                          |   12 +-
+ arch/powerpc/mm/mem.c                              |    3 +-
+ arch/powerpc/platforms/44x/currituck.c             |   10 +-
+ arch/powerpc/platforms/85xx/Kconfig                |   21 ++
+ arch/powerpc/platforms/85xx/Makefile               |    2 +
+ arch/powerpc/platforms/85xx/corenet_ds.c           |   10 +-
+ arch/powerpc/platforms/85xx/mpc85xx_ds.c           |    1 +
+ arch/powerpc/platforms/85xx/p1022_rdk.c            |  195 ++++++++++++
+ arch/powerpc/platforms/85xx/p5040_ds.c             |   89 ++++++
+ arch/powerpc/platforms/85xx/qemu_e500.c            |    1 +
+ arch/powerpc/platforms/85xx/smp.c                  |  220 +++++++++++---
+ arch/powerpc/sysdev/Makefile                       |    2 +-
+ arch/powerpc/sysdev/fsl_85xx_l2ctlr.c              |   10 +
+ arch/powerpc/sysdev/fsl_mpic_err.c                 |  149 +++++++++
+ arch/powerpc/sysdev/fsl_pci.c                      |   19 +-
+ arch/powerpc/sysdev/mpic.c                         |  102 +++++--
+ arch/powerpc/sysdev/mpic.h                         |   22 ++
+ 67 files changed, 2144 insertions(+), 522 deletions(-)
+ create mode 100644 arch/powerpc/boot/dts/fsl/e500mc_power_isa.dtsi
+ create mode 100644 arch/powerpc/boot/dts/fsl/e500v2_power_isa.dtsi
+ create mode 100644 arch/powerpc/boot/dts/fsl/e5500_power_isa.dtsi
+ create mode 100644 arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
+ create mode 100644 arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi
+ create mode 100644 arch/powerpc/boot/dts/fsl/qoriq-sec5.2-0.dtsi
+ delete mode 100644 arch/powerpc/boot/dts/p1020rdb_camp_core0.dts
+ delete mode 100644 arch/powerpc/boot/dts/p1020rdb_camp_core1.dts
+ create mode 100644 arch/powerpc/boot/dts/p1022rdk.dts
+ delete mode 100644 arch/powerpc/boot/dts/p2020rdb_camp_core0.dts
+ delete mode 100644 arch/powerpc/boot/dts/p2020rdb_camp_core1.dts
+ create mode 100644 arch/powerpc/boot/dts/p5040ds.dts
+ create mode 100644 arch/powerpc/platforms/85xx/p1022_rdk.c
+ create mode 100644 arch/powerpc/platforms/85xx/p5040_ds.c
+ create mode 100644 arch/powerpc/sysdev/fsl_mpic_err.c
+Merging s390/features (3c011c6 s390/bpf,jit: BPF Just In Time compiler for s390)
+$ git merge s390/features
+Merge made by the 'recursive' strategy.
+ arch/s390/Kbuild                  |    1 +
+ arch/s390/Kconfig                 |    1 +
+ arch/s390/include/asm/processor.h |    1 +
+ arch/s390/kernel/dis.c            |   23 ++
+ arch/s390/net/Makefile            |    4 +
+ arch/s390/net/bpf_jit.S           |  130 +++++++
+ arch/s390/net/bpf_jit_comp.c      |  738 +++++++++++++++++++++++++++++++++++++
+ 7 files changed, 898 insertions(+)
+ create mode 100644 arch/s390/net/Makefile
+ create mode 100644 arch/s390/net/bpf_jit.S
+ create mode 100644 arch/s390/net/bpf_jit_comp.c
+Merging sh/sh-latest (fa75ce6 Merge branches 'sh/urgent' and 'sh/gpiolib' into sh-latest)
+$ git merge sh/sh-latest
+Already up-to-date.
+Merging sparc-next/master (6dab7ed Merge branch 'fixes' of git://git.linaro.org/people/rmk/linux-arm)
+$ git merge sparc-next/master
+Already up-to-date.
+Merging tile/master (bdc0077 Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi)
+$ git merge tile/master
+Already up-to-date.
+Merging unicore32/unicore32 (e4baa56 UniCore32-bugfix: Remove definitions in asm/bug.h to solve difference between native and cross compiler)
+$ git merge unicore32/unicore32
+Auto-merging arch/unicore32/Kconfig
+Merge made by the 'recursive' strategy.
+ arch/unicore32/Kconfig               |    3 +++
+ arch/unicore32/include/asm/bug.h     |    5 -----
+ arch/unicore32/include/asm/cmpxchg.h |    2 +-
+ arch/unicore32/kernel/setup.h        |    6 ++++++
+ arch/unicore32/mm/fault.c            |   37 +++++++++++++++++++++++++---------
+ 5 files changed, 37 insertions(+), 16 deletions(-)
+Merging xtensa/for_next (499d9ec xtensa: ISS: exit simulator in case of halt or panic)
+$ git merge xtensa/for_next
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ MAINTAINERS                         |    2 ++
+ arch/xtensa/Kconfig                 |    2 ++
+ arch/xtensa/include/asm/io.h        |   10 ++++++++++
+ arch/xtensa/kernel/Makefile         |    1 +
+ arch/xtensa/kernel/irq.c            |    4 ++--
+ arch/xtensa/kernel/pci.c            |    9 ++++++++-
+ arch/xtensa/kernel/platform.c       |    4 ++--
+ arch/xtensa/platforms/iss/Makefile  |    4 ++--
+ arch/xtensa/platforms/iss/console.c |   18 +++++++++++++-----
+ arch/xtensa/platforms/iss/setup.c   |   14 ++++++++++----
+ 10 files changed, 52 insertions(+), 16 deletions(-)
+Merging ceph/master (1fe5e99 rbd: create rbd_refresh_helper())
+$ git merge ceph/master
+Already up-to-date.
+Merging cifs/for-next (30e5913 Remove sparse warning in cifsfs.c)
+$ git merge cifs/for-next
+Merge made by the 'recursive' strategy.
+ fs/cifs/Kconfig         |    1 +
+ fs/cifs/Makefile        |    2 +-
+ fs/cifs/cifsacl.c       |    2 +-
+ fs/cifs/cifsencrypt.c   |   30 +-
+ fs/cifs/cifsfs.c        |   33 +-
+ fs/cifs/cifsglob.h      |  221 ++++++++++-
+ fs/cifs/cifsproto.h     |   85 ++---
+ fs/cifs/cifssmb.c       |  151 ++++----
+ fs/cifs/connect.c       |  148 +-------
+ fs/cifs/dir.c           |  105 +++---
+ fs/cifs/file.c          |  444 ++++++++++++----------
+ fs/cifs/inode.c         |  347 ++++++++---------
+ fs/cifs/ioctl.c         |   13 +-
+ fs/cifs/link.c          |   76 ++--
+ fs/cifs/misc.c          |    2 +-
+ fs/cifs/netmisc.c       |    3 +-
+ fs/cifs/readdir.c       |  165 ++++----
+ fs/cifs/smb1ops.c       |  324 +++++++++++++++-
+ fs/cifs/smb2file.c      |  106 ++++++
+ fs/cifs/smb2glob.h      |   14 +
+ fs/cifs/smb2inode.c     |   98 ++++-
+ fs/cifs/smb2maperror.c  |    3 +-
+ fs/cifs/smb2misc.c      |  102 ++++-
+ fs/cifs/smb2ops.c       |  282 +++++++++++++-
+ fs/cifs/smb2pdu.c       |  956 ++++++++++++++++++++++++++++++++++++++++++++++-
+ fs/cifs/smb2pdu.h       |  185 ++++++++-
+ fs/cifs/smb2proto.h     |   63 +++-
+ fs/cifs/smb2transport.c |  157 +++++++-
+ fs/cifs/transport.c     |   33 +-
+ 29 files changed, 3236 insertions(+), 915 deletions(-)
+ create mode 100644 fs/cifs/smb2file.c
+Merging configfs/linux-next (b930c26 Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs)
+$ git merge configfs/linux-next
+Already up-to-date.
+Merging ecryptfs/next (0d7614f Linux 3.6-rc1)
+$ git merge ecryptfs/next
+Already up-to-date.
+Merging ext3/for_next (68766a2 udf: fix retun value on error path in udf_load_logicalvol)
+$ git merge ext3/for_next
+Merge made by the 'recursive' strategy.
+ fs/jbd/journal.c     |    5 +++++
+ fs/quota/dquot.c     |    2 +-
+ fs/reiserfs/bitmap.c |    2 --
+ fs/reiserfs/inode.c  |    2 +-
+ fs/udf/inode.c       |    5 ++++-
+ fs/udf/super.c       |    7 ++++++-
+ 6 files changed, 17 insertions(+), 6 deletions(-)
+Merging ext4/dev (8a2f846 ext4: remove duplicated declarations in inode.c)
+$ git merge ext4/dev
+Auto-merging fs/jbd2/journal.c
+Auto-merging fs/ext4/super.c
+Auto-merging fs/ext4/inode.c
+Merge made by the 'recursive' strategy.
+ Documentation/ABI/testing/sysfs-fs-ext4 |   13 ++
+ Documentation/filesystems/ext4.txt      |   10 ++
+ fs/ext4/ext4.h                          |    4 +
+ fs/ext4/extents.c                       |  103 +++++++++----
+ fs/ext4/fsync.c                         |    9 +-
+ fs/ext4/inode.c                         |    3 -
+ fs/ext4/mballoc.c                       |   34 ++---
+ fs/ext4/mballoc.h                       |    5 -
+ fs/ext4/namei.c                         |    7 +
+ fs/ext4/super.c                         |   27 ++--
+ fs/jbd2/journal.c                       |    5 +
+ fs/jbd2/recovery.c                      |    7 +-
+ include/trace/events/ext4.h             |  242 +++++++++++++++----------------
+ 13 files changed, 275 insertions(+), 194 deletions(-)
+Merging fuse/for-next (fb6ccff fuse: verify all ioctl retry iov elements)
+$ git merge fuse/for-next
+Already up-to-date.
+Merging gfs2/master (257cd64 GFS2: Use rbm for gfs2_setbit())
+$ git merge gfs2/master
+Merge made by the 'recursive' strategy.
+ fs/gfs2/aops.c       |   11 +-
+ fs/gfs2/bmap.c       |    2 +-
+ fs/gfs2/file.c       |   35 ++-
+ fs/gfs2/glock.c      |   60 ++--
+ fs/gfs2/incore.h     |   25 +-
+ fs/gfs2/inode.c      |   17 +-
+ fs/gfs2/quota.c      |    9 +-
+ fs/gfs2/rgrp.c       |  834 ++++++++++++++++++++++++--------------------------
+ fs/gfs2/rgrp.h       |   22 +-
+ fs/gfs2/super.c      |    2 +-
+ fs/gfs2/trace_gfs2.h |   10 +-
+ fs/gfs2/trans.h      |    7 +-
+ fs/gfs2/xattr.c      |   96 ++----
+ 13 files changed, 527 insertions(+), 603 deletions(-)
+Merging logfs/master (9f0bbd8 logfs: query block device for number of pages to send with bio)
+$ git merge logfs/master
+Auto-merging fs/logfs/readwrite.c
+Merge made by the 'recursive' strategy.
+ fs/logfs/dev_bdev.c  |   15 +++++++--------
+ fs/logfs/inode.c     |   18 +++++++++++++++++-
+ fs/logfs/journal.c   |    2 +-
+ fs/logfs/readwrite.c |    1 -
+ fs/logfs/segment.c   |    2 +-
+ 5 files changed, 26 insertions(+), 12 deletions(-)
+Merging nfs/linux-next (12dfd08 NFS: return -ENOKEY when the upcall fails to map the name)
+$ git merge nfs/linux-next
+Merge made by the 'recursive' strategy.
+ fs/nfs/Makefile              |   18 +++++-----
+ fs/nfs/client.c              |    2 +-
+ fs/nfs/idmap.c               |   62 ++++++++++++++++++++++++----------
+ fs/nfs/nfs4_fs.h             |    3 ++
+ fs/nfs/nfs4proc.c            |   76 +++++++++++++++++++++++++++++++++++-------
+ fs/nfs/nfs4super.c           |   15 ---------
+ fs/nfs/nfs4xdr.c             |   26 ++++++---------
+ fs/nfs/objlayout/objio_osd.c |   55 ++++++++++++++++++++++++++++--
+ fs/nfs/pagelist.c            |    2 ++
+ fs/nfs/pnfs.c                |   39 +---------------------
+ fs/nfs/pnfs.h                |    2 +-
+ fs/nfs/super.c               |   39 +++++++++++++++++++++-
+ fs/nfs/write.c               |   15 +++++++--
+ include/linux/nfs_page.h     |    1 +
+ include/linux/nfs_xdr.h      |    1 +
+ 15 files changed, 239 insertions(+), 117 deletions(-)
+Merging nfsd/nfsd-next (2c142ba NFSd: make boot_time variable per network namespace)
+$ git merge nfsd/nfsd-next
+Already up-to-date.
+Merging ocfs2/linux-next (4538df6 ocfs2: Don't spam on -EDQUOT.)
+$ git merge ocfs2/linux-next
+Merge made by the 'recursive' strategy.
+ fs/ocfs2/cluster/heartbeat.c |   40 +++++++++-------------------------------
+ fs/ocfs2/cluster/masklog.h   |    3 ++-
+ fs/ocfs2/dlm/dlmmaster.c     |   10 ++++++++--
+ fs/ocfs2/dlm/dlmrecovery.c   |    7 +++++++
+ fs/ocfs2/symlink.c           |    2 +-
+ 5 files changed, 27 insertions(+), 35 deletions(-)
+Merging omfs/for-next (976d167 Linux 3.1-rc9)
+$ git merge omfs/for-next
+Already up-to-date.
+Merging squashfs/master (4b0180a Squashfs: add mount time sanity check for block_size and block_log match)
+$ git merge squashfs/master
+Already up-to-date.
+Merging v9fs/for-next (5fcb08b 9p: BUG before corrupting memory)
+$ git merge v9fs/for-next
+Already up-to-date.
+Merging ubifs/linux-next (7074e5e UBIFS: remove invalid reference to list iterator variable)
+$ git merge ubifs/linux-next
+Already up-to-date.
+Merging xfs/for-next (643bfc0 xfs: check for possible overflow in xfs_ioc_trim)
+$ git merge xfs/for-next
+Merge made by the 'recursive' strategy.
+ fs/xfs/xfs_discard.c |    6 ++++--
+ fs/xfs/xfs_ialloc.c  |   17 +++++++++--------
+ fs/xfs/xfs_mount.h   |    5 -----
+ fs/xfs/xfs_rtalloc.c |    2 +-
+ fs/xfs/xfs_trace.h   |    1 +
+ 5 files changed, 15 insertions(+), 16 deletions(-)
+Merging vfs/for-next (808d1b7 unexport sock_map_fd(), switch to sock_alloc_file())
+$ git merge vfs/for-next
+Auto-merging net/socket.c
+Merge made by the 'recursive' strategy.
+ drivers/vfio/vfio.c  |   19 ++++++---------
+ fs/eventpoll.c       |    2 +-
+ include/linux/kref.h |   18 ++++++++++++++
+ include/linux/net.h  |    3 ++-
+ ipc/mqueue.c         |   61 +++++++++++++++++++++-------------------------
+ net/9p/trans_fd.c    |   16 ++++++------
+ net/sctp/socket.c    |   25 +++++++++++++++----
+ net/socket.c         |   66 ++++++++++++++++++++++++++++++++------------------
+ 8 files changed, 125 insertions(+), 85 deletions(-)
+Merging pci/next (0d7614f Linux 3.6-rc1)
+$ git merge pci/next
+Already up-to-date.
+Merging hid/for-next (86476aa Merge branch 'picolcd' into for-next)
+$ git merge hid/for-next
+Removing drivers/hid/hid-picolcd.c
+Auto-merging drivers/hid/hid-ids.h
+Auto-merging drivers/hid/hid-core.c
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ Documentation/ABI/testing/sysfs-driver-wacom |   13 +
+ MAINTAINERS                                  |    6 +
+ drivers/hid/Kconfig                          |    8 +
+ drivers/hid/Makefile                         |   20 +
+ drivers/hid/hid-core.c                       |    2 +-
+ drivers/hid/hid-ids.h                        |    7 +
+ drivers/hid/hid-multitouch.c                 |   49 +-
+ drivers/hid/hid-picolcd.c                    | 2748 --------------------------
+ drivers/hid/hid-picolcd.h                    |  300 +++
+ drivers/hid/hid-picolcd_backlight.c          |  122 ++
+ drivers/hid/hid-picolcd_cir.c                |   61 +
+ drivers/hid/hid-picolcd_core.c               |  712 +++++++
+ drivers/hid/hid-picolcd_debugfs.c            |  898 +++++++++
+ drivers/hid/hid-picolcd_fb.c                 |  605 ++++++
+ drivers/hid/hid-picolcd_lcd.c                |  107 +
+ drivers/hid/hid-picolcd_leds.c               |  175 ++
+ drivers/hid/hid-wacom.c                      |  146 +-
+ drivers/hid/hidraw.c                         |   15 +-
+ drivers/hid/usbhid/hid-quirks.c              |    1 +
+ 19 files changed, 3235 insertions(+), 2760 deletions(-)
+ delete mode 100644 drivers/hid/hid-picolcd.c
+ create mode 100644 drivers/hid/hid-picolcd.h
+ create mode 100644 drivers/hid/hid-picolcd_backlight.c
+ create mode 100644 drivers/hid/hid-picolcd_cir.c
+ create mode 100644 drivers/hid/hid-picolcd_core.c
+ create mode 100644 drivers/hid/hid-picolcd_debugfs.c
+ create mode 100644 drivers/hid/hid-picolcd_fb.c
+ create mode 100644 drivers/hid/hid-picolcd_lcd.c
+ create mode 100644 drivers/hid/hid-picolcd_leds.c
+Merging quilt/i2c (a918790 i2c: Convert struct i2c_msg initialization to C99 format)
+$ git merge quilt/i2c
+Merge made by the 'recursive' strategy.
+ drivers/i2c/busses/Kconfig          |    1 +
+ drivers/i2c/busses/i2c-i801.c       |  214 ++++++++++++++++++++++++++++++++++-
+ drivers/i2c/i2c-core.c              |   16 ++-
+ drivers/i2c/i2c-mux.c               |   22 ++++
+ drivers/i2c/i2c-smbus.c             |   11 +-
+ drivers/i2c/muxes/i2c-mux-gpio.c    |    4 +-
+ drivers/i2c/muxes/i2c-mux-pca9541.c |    2 +-
+ drivers/i2c/muxes/i2c-mux-pca954x.c |   10 +-
+ drivers/i2c/muxes/i2c-mux-pinctrl.c |    2 +-
+ include/linux/i2c-mux-gpio.h        |    2 +
+ include/linux/i2c-mux.h             |    1 +
+ include/linux/i2c/pca954x.h         |    1 +
+ 12 files changed, 268 insertions(+), 18 deletions(-)
+Merging i2c-embedded/i2c-embedded/for-next (d987569 Linux 3.6-rc2)
+$ git merge i2c-embedded/i2c-embedded/for-next
+Already up-to-date.
+Merging quilt/jdelvare-hwmon (4ac1223 hwmon: (coretemp) Use get_online_cpus to avoid races involving CPU hotplug)
+$ git merge quilt/jdelvare-hwmon
+Merge made by the 'recursive' strategy.
+ drivers/hwmon/coretemp.c    |    5 +++++
+ drivers/hwmon/via-cputemp.c |    5 +++++
+ 2 files changed, 10 insertions(+)
+Merging hwmon-staging/hwmon-next (b7e3a9f hwmon: (adt7410) handle errors from adt7410_update_device())
+$ git merge hwmon-staging/hwmon-next
+Auto-merging drivers/hwmon/via-cputemp.c
+Auto-merging drivers/hwmon/coretemp.c
+Merge made by the 'recursive' strategy.
+ Documentation/hwmon/adt7410    |   51 +++++
+ drivers/hwmon/Kconfig          |   10 +
+ drivers/hwmon/Makefile         |    1 +
+ drivers/hwmon/abituguru.c      |    7 +-
+ drivers/hwmon/abituguru3.c     |    6 +-
+ drivers/hwmon/ad7314.c         |   16 +-
+ drivers/hwmon/ad7414.c         |   21 +-
+ drivers/hwmon/ad7418.c         |   21 +-
+ drivers/hwmon/adcxx.c          |    4 +-
+ drivers/hwmon/adm1029.c        |   21 +-
+ drivers/hwmon/ads1015.c        |   12 +-
+ drivers/hwmon/ads7828.c        |   15 +-
+ drivers/hwmon/ads7871.c        |   21 +-
+ drivers/hwmon/adt7410.c        |  464 ++++++++++++++++++++++++++++++++++++++++
+ drivers/hwmon/adt7411.c        |    9 +-
+ drivers/hwmon/adt7462.c        |   15 +-
+ drivers/hwmon/adt7470.c        |   15 +-
+ drivers/hwmon/amc6821.c        |   16 +-
+ drivers/hwmon/asb100.c         |   17 +-
+ drivers/hwmon/coretemp.c       |    2 +-
+ drivers/hwmon/dme1737.c        |   45 ++--
+ drivers/hwmon/ds620.c          |   16 +-
+ drivers/hwmon/emc1403.c        |   18 +-
+ drivers/hwmon/emc2103.c        |   10 +-
+ drivers/hwmon/f71882fg.c       |   48 ++---
+ drivers/hwmon/f75375s.c        |    8 +-
+ drivers/hwmon/fam15h_power.c   |   25 +--
+ drivers/hwmon/g760a.c          |   10 +-
+ drivers/hwmon/jz4740-hwmon.c   |   49 ++---
+ drivers/hwmon/lm70.c           |    4 +-
+ drivers/hwmon/lm95241.c        |   15 +-
+ drivers/hwmon/lm95245.c        |   15 +-
+ drivers/hwmon/ltc4151.c        |   15 +-
+ drivers/hwmon/ltc4215.c        |   15 +-
+ drivers/hwmon/ltc4245.c        |   14 +-
+ drivers/hwmon/max1668.c        |    8 +-
+ drivers/hwmon/mcp3021.c        |   15 +-
+ drivers/hwmon/sch5627.c        |    5 +-
+ drivers/hwmon/sch5636.c        |    6 +-
+ drivers/hwmon/sch56xx-common.c |   28 +--
+ drivers/hwmon/sht15.c          |   58 ++---
+ drivers/hwmon/sht21.c          |   13 +-
+ drivers/hwmon/via-cputemp.c    |   23 +-
+ drivers/hwmon/vt8231.c         |   24 +--
+ drivers/hwmon/w83627hf.c       |    2 +-
+ drivers/hwmon/w83l786ng.c      |   13 +-
+ 46 files changed, 766 insertions(+), 480 deletions(-)
+ create mode 100644 Documentation/hwmon/adt7410
+ create mode 100644 drivers/hwmon/adt7410.c
+Merging v4l-dvb/master (34d9dac Merge /home/v4l/v4l/patchwork)
+$ git merge v4l-dvb/master
+Removing drivers/staging/media/lirc/lirc_ttusbir.c
+Removing drivers/staging/media/lirc/lirc_ene0100.h
+Removing drivers/staging/media/easycap/easycap_testcard.c
+Removing drivers/staging/media/easycap/easycap_sound.c
+Removing drivers/staging/media/easycap/easycap_settings.c
+Removing drivers/staging/media/easycap/easycap_main.c
+Removing drivers/staging/media/easycap/easycap_low.c
+Removing drivers/staging/media/easycap/easycap_ioctl.c
+Removing drivers/staging/media/easycap/easycap.h
+Removing drivers/staging/media/easycap/README
+Removing drivers/staging/media/easycap/Makefile
+Removing drivers/staging/media/easycap/Kconfig
+Removing drivers/media/video/tlg2300/Makefile
+Removing drivers/media/video/bt8xx/Makefile
+Removing drivers/media/video/bt8xx/Kconfig
+Removing drivers/media/video/Makefile
+Removing drivers/media/video/Kconfig
+Auto-merging drivers/media/v4l2-core/videobuf2-vmalloc.c
+Auto-merging drivers/media/v4l2-core/videobuf2-core.c
+Auto-merging drivers/media/v4l2-core/videobuf-dvb.c
+Auto-merging drivers/media/v4l2-core/v4l2-ioctl.c
+Auto-merging drivers/media/v4l2-core/v4l2-dev.c
+Auto-merging drivers/media/v4l2-core/v4l2-common.c
+Auto-merging drivers/media/usb/uvc/uvcvideo.h
+Auto-merging drivers/media/usb/uvc/uvc_video.c
+Auto-merging drivers/media/usb/uvc/uvc_queue.c
+Auto-merging drivers/media/usb/uvc/uvc_driver.c
+Auto-merging drivers/media/usb/usbvision/usbvision-video.c
+Auto-merging drivers/media/usb/usbvision/Makefile
+Auto-merging drivers/media/usb/ttusb-dec/Makefile
+Auto-merging drivers/media/usb/tm6000/tm6000-video.c
+Auto-merging drivers/media/usb/tm6000/tm6000-input.c
+Auto-merging drivers/media/usb/tm6000/tm6000-alsa.c
+Auto-merging drivers/media/usb/tm6000/Makefile
+Auto-merging drivers/media/usb/s2255/s2255drv.c
+Auto-merging drivers/media/usb/pwc/Makefile
+Auto-merging drivers/media/usb/pvrusb2/pvrusb2-devattr.c
+Auto-merging drivers/media/usb/pvrusb2/Makefile
+Auto-merging drivers/media/usb/hdpvr/Makefile
+Auto-merging drivers/media/usb/gspca/vc032x.c
+Auto-merging drivers/media/usb/gspca/stv06xx/Makefile
+Auto-merging drivers/media/usb/gspca/sq930x.c
+Auto-merging drivers/media/usb/gspca/sq905c.c
+Auto-merging drivers/media/usb/gspca/m5602/Makefile
+Auto-merging drivers/media/usb/gspca/gl860/Makefile
+Auto-merging drivers/media/usb/gspca/Kconfig
+Auto-merging drivers/media/usb/em28xx/em28xx-video.c
+Auto-merging drivers/media/usb/em28xx/em28xx-core.c
+Auto-merging drivers/media/usb/em28xx/em28xx-audio.c
+Auto-merging drivers/media/usb/em28xx/Makefile
+Auto-merging drivers/media/usb/dvb-usb/pctv452e.c
+Auto-merging drivers/media/usb/dvb-usb/dvb-usb.h
+Auto-merging drivers/media/usb/dvb-usb/dvb-usb-dvb.c
+Auto-merging drivers/media/usb/dvb-usb/dib0700_core.c
+Auto-merging drivers/media/usb/dvb-usb/Kconfig
+Auto-merging drivers/media/usb/dvb-usb-v2/rtl28xxu.h
+Auto-merging drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+Auto-merging drivers/media/usb/dvb-usb-v2/mxl111sf.h
+Auto-merging drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
+Auto-merging drivers/media/usb/dvb-usb-v2/lmedm04.c
+Auto-merging drivers/media/usb/dvb-usb-v2/gl861.h
+Auto-merging drivers/media/usb/dvb-usb-v2/gl861.c
+Auto-merging drivers/media/usb/dvb-usb-v2/ec168.h
+Auto-merging drivers/media/usb/dvb-usb-v2/ec168.c
+Auto-merging drivers/media/usb/dvb-usb-v2/ce6230.h
+Auto-merging drivers/media/usb/dvb-usb-v2/ce6230.c
+Auto-merging drivers/media/usb/dvb-usb-v2/az6007.c
+Auto-merging drivers/media/usb/dvb-usb-v2/au6610.h
+Auto-merging drivers/media/usb/dvb-usb-v2/au6610.c
+Auto-merging drivers/media/usb/dvb-usb-v2/anysee.h
+Auto-merging drivers/media/usb/dvb-usb-v2/anysee.c
+Auto-merging drivers/media/usb/dvb-usb-v2/af9035.h
+Auto-merging drivers/media/usb/dvb-usb-v2/af9035.c
+Auto-merging drivers/media/usb/dvb-usb-v2/af9015.h
+Auto-merging drivers/media/usb/cx231xx/cx231xx-video.c
+Auto-merging drivers/media/usb/cx231xx/cx231xx-417.c
+Auto-merging drivers/media/usb/cx231xx/Makefile
+Auto-merging drivers/media/usb/cpia2/cpia2_v4l.c
+Auto-merging drivers/media/usb/cpia2/cpia2_core.c
+Auto-merging drivers/media/usb/b2c2/flexcop-usb.c
+Auto-merging drivers/media/usb/au0828/au0828.h
+Auto-merging drivers/media/usb/au0828/au0828-video.c
+Auto-merging drivers/media/usb/au0828/au0828-reg.h
+Auto-merging drivers/media/usb/au0828/au0828-i2c.c
+Auto-merging drivers/media/usb/au0828/au0828-dvb.c
+Auto-merging drivers/media/usb/au0828/au0828-core.c
+Auto-merging drivers/media/usb/au0828/au0828-cards.c
+Auto-merging drivers/media/usb/au0828/Makefile
+Auto-merging drivers/media/tuners/xc5000.c
+Auto-merging drivers/media/tuners/xc4000.c
+Auto-merging drivers/media/tuners/tuner-xc2028.c
+Auto-merging drivers/media/tuners/tda18218.c
+Auto-merging drivers/media/tuners/tda18212.c
+Auto-merging drivers/media/tuners/qt1010.c
+Auto-merging drivers/media/tuners/Makefile
+Auto-merging drivers/media/platform/vivi.c
+Auto-merging drivers/media/platform/soc_mediabus.c
+Auto-merging drivers/media/platform/soc_camera_platform.c
+Auto-merging drivers/media/platform/soc_camera.c
+Auto-merging drivers/media/platform/sh_vou.c
+Auto-merging drivers/media/platform/s5p-tv/sii9234_drv.c
+Auto-merging drivers/media/platform/s5p-tv/sdo_drv.c
+Auto-merging drivers/media/platform/s5p-tv/regs-sdo.h
+Auto-merging drivers/media/platform/s5p-tv/mixer_video.c
+Auto-merging drivers/media/platform/s5p-tv/mixer_drv.c
+Auto-merging drivers/media/platform/s5p-tv/hdmi_drv.c
+Auto-merging drivers/media/platform/s5p-tv/Makefile
+Auto-merging drivers/media/platform/s5p-tv/Kconfig
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc_shm.h
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc_shm.c
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc_pm.h
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc_intr.h
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc_intr.c
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc_enc.h
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc_dec.h
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc_debug.h
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c
+Auto-merging drivers/media/platform/s5p-mfc/s5p_mfc.c
+Auto-merging drivers/media/platform/s5p-jpeg/jpeg-regs.h
+Auto-merging drivers/media/platform/s5p-jpeg/jpeg-hw.h
+Auto-merging drivers/media/platform/s5p-jpeg/jpeg-core.h
+Auto-merging drivers/media/platform/s5p-jpeg/jpeg-core.c
+Auto-merging drivers/media/platform/s5p-g2d/g2d.c
+Auto-merging drivers/media/platform/omap3isp/ispvideo.h
+Auto-merging drivers/media/platform/omap3isp/ispvideo.c
+Auto-merging drivers/media/platform/omap3isp/ispresizer.c
+Auto-merging drivers/media/platform/omap3isp/ispqueue.c
+Auto-merging drivers/media/platform/omap3isp/isppreview.h
+Auto-merging drivers/media/platform/omap3isp/isppreview.c
+Auto-merging drivers/media/platform/omap3isp/isphist.c
+Auto-merging drivers/media/platform/omap3isp/isph3a_af.c
+Auto-merging drivers/media/platform/omap3isp/isph3a_aewb.c
+Auto-merging drivers/media/platform/omap3isp/ispcsi2.c
+Auto-merging drivers/media/platform/omap3isp/ispccdc.h
+Auto-merging drivers/media/platform/omap3isp/ispccdc.c
+Auto-merging drivers/media/platform/omap3isp/isp.h
+Auto-merging drivers/media/platform/omap3isp/isp.c
+Auto-merging drivers/media/platform/omap3isp/cfa_coef_table.h
+Auto-merging drivers/media/platform/omap24xxcam.h
+Auto-merging drivers/media/platform/omap24xxcam.c
+Auto-merging drivers/media/platform/omap24xxcam-dma.c
+Auto-merging drivers/media/platform/omap1_camera.c
+Auto-merging drivers/media/platform/omap/Makefile
+Auto-merging drivers/media/platform/mx3_camera.c
+Auto-merging drivers/media/platform/mx2_emmaprp.c
+Auto-merging drivers/media/platform/mx2_camera.c
+Auto-merging drivers/media/platform/mx1_camera.c
+Auto-merging drivers/media/platform/mem2mem_testdev.c
+Auto-merging drivers/media/platform/fsl-viu.c
+Auto-merging drivers/media/platform/davinci/vpss.c
+Auto-merging drivers/media/platform/davinci/vpif_display.c
+Auto-merging drivers/media/platform/davinci/vpif_capture.c
+Auto-merging drivers/media/platform/davinci/vpif.c
+Auto-merging drivers/media/platform/davinci/vpfe_capture.c
+Auto-merging drivers/media/platform/davinci/vpbe_display.c
+Auto-merging drivers/media/platform/davinci/isif.c
+Auto-merging drivers/media/platform/davinci/dm644x_ccdc.c
+Auto-merging drivers/media/platform/davinci/dm355_ccdc.c
+Auto-merging drivers/media/platform/blackfin/bfin_capture.c
+Auto-merging drivers/media/pci/ttpci/budget.c
+Auto-merging drivers/media/pci/ttpci/Makefile
+Auto-merging drivers/media/pci/saa7164/saa7164.h
+Auto-merging drivers/media/pci/saa7164/saa7164-core.c
+Auto-merging drivers/media/pci/saa7164/saa7164-api.c
+Auto-merging drivers/media/pci/saa7164/Makefile
+Auto-merging drivers/media/pci/saa7134/saa7134.h
+Auto-merging drivers/media/pci/saa7134/saa7134-input.c
+Auto-merging drivers/media/pci/saa7134/saa7134-dvb.c
+Auto-merging drivers/media/pci/saa7134/Makefile
+Auto-merging drivers/media/pci/pt1/Makefile
+Auto-merging drivers/media/pci/ngene/ngene-core.c
+Auto-merging drivers/media/pci/ngene/ngene-cards.c
+Auto-merging drivers/media/pci/ngene/Makefile
+Auto-merging drivers/media/pci/mantis/mantis_dvb.c
+Auto-merging drivers/media/pci/mantis/mantis_core.c
+Auto-merging drivers/media/pci/mantis/mantis_cards.c
+Auto-merging drivers/media/pci/mantis/Makefile
+Auto-merging drivers/media/pci/ivtv/ivtv-streams.c
+Auto-merging drivers/media/pci/ivtv/ivtv-firmware.c
+Auto-merging drivers/media/pci/ivtv/ivtv-fileops.c
+Auto-merging drivers/media/pci/ivtv/Makefile
+Auto-merging drivers/media/pci/ddbridge/Makefile
+Auto-merging drivers/media/pci/cx88/cx88.h
+Auto-merging drivers/media/pci/cx88/cx88-dvb.c
+Auto-merging drivers/media/pci/cx88/cx88-core.c
+Auto-merging drivers/media/pci/cx88/cx88-alsa.c
+Auto-merging drivers/media/pci/cx88/Makefile
+Auto-merging drivers/media/pci/cx25821/Makefile
+Auto-merging drivers/media/pci/cx23885/cx23885-input.c
+Auto-merging drivers/media/pci/cx23885/cx23885-dvb.c
+Auto-merging drivers/media/pci/cx23885/cx23885-cards.c
+Auto-merging drivers/media/pci/cx23885/cx23885-417.c
+Auto-merging drivers/media/pci/cx23885/Makefile
+Auto-merging drivers/media/pci/cx18/cx18-firmware.c
+Auto-merging drivers/media/pci/cx18/cx18-dvb.c
+Auto-merging drivers/media/pci/cx18/cx18-driver.c
+Auto-merging drivers/media/pci/cx18/cx18-av-firmware.c
+Auto-merging drivers/media/pci/cx18/Makefile
+Auto-merging drivers/media/pci/bt8xx/dst_ca.c
+Auto-merging drivers/media/pci/bt8xx/Kconfig
+Auto-merging drivers/media/i2c/tvp514x_regs.h
+Auto-merging drivers/media/i2c/tvp514x.c
+Auto-merging drivers/media/i2c/tcm825x.h
+Auto-merging drivers/media/i2c/tcm825x.c
+Auto-merging drivers/media/i2c/soc_camera/tw9910.c
+Auto-merging drivers/media/i2c/soc_camera/rj54n1cb0c.c
+Auto-merging drivers/media/i2c/soc_camera/ov9740.c
+Auto-merging drivers/media/i2c/soc_camera/ov9640.c
+Auto-merging drivers/media/i2c/soc_camera/ov772x.c
+Auto-merging drivers/media/i2c/soc_camera/ov6650.c
+Auto-merging drivers/media/i2c/soc_camera/ov5642.c
+Auto-merging drivers/media/i2c/soc_camera/ov2640.c
+Auto-merging drivers/media/i2c/soc_camera/mt9v022.c
+Auto-merging drivers/media/i2c/soc_camera/mt9t112.c
+Auto-merging drivers/media/i2c/soc_camera/mt9t031.c
+Auto-merging drivers/media/i2c/soc_camera/mt9m111.c
+Auto-merging drivers/media/i2c/soc_camera/mt9m001.c
+Auto-merging drivers/media/i2c/soc_camera/imx074.c
+Auto-merging drivers/media/i2c/smiapp/smiapp.h
+Auto-merging drivers/media/i2c/smiapp/smiapp-regs.c
+Auto-merging drivers/media/i2c/smiapp/smiapp-reg.h
+Auto-merging drivers/media/i2c/smiapp/smiapp-reg-defs.h
+Auto-merging drivers/media/i2c/smiapp/smiapp-quirk.h
+Auto-merging drivers/media/i2c/smiapp/smiapp-quirk.c
+Auto-merging drivers/media/i2c/smiapp/smiapp-limits.h
+Auto-merging drivers/media/i2c/smiapp/smiapp-limits.c
+Auto-merging drivers/media/i2c/smiapp/smiapp-core.c
+Auto-merging drivers/media/i2c/smiapp/Makefile
+Auto-merging drivers/media/i2c/smiapp-pll.h
+Auto-merging drivers/media/i2c/smiapp-pll.c
+Auto-merging drivers/media/i2c/saa7127.c
+Auto-merging drivers/media/i2c/s5k6aa.c
+Auto-merging drivers/media/i2c/cx25840/cx25840-firmware.c
+Auto-merging drivers/media/i2c/cx25840/Makefile
+Auto-merging drivers/media/i2c/as3645a.c
+Auto-merging drivers/media/i2c/adp1653.c
+Auto-merging drivers/media/firewire/Makefile
+Removing drivers/media/dvb/ttusb-budget/Makefile
+Removing drivers/media/dvb/siano/Kconfig
+Removing drivers/media/dvb/pluto2/Makefile
+Removing drivers/media/dvb/dvb-usb/mxl111sf.c
+Removing drivers/media/dvb/dvb-usb/it913x.c
+Removing drivers/media/dvb/dvb-usb/af9015.c
+Removing drivers/media/dvb/dvb-usb/Makefile
+Removing drivers/media/dvb/dm1105/Makefile
+Removing drivers/media/dvb/bt8xx/Makefile
+Removing drivers/media/dvb/b2c2/Makefile
+Removing drivers/media/dvb/Makefile
+Removing drivers/media/dvb/Kconfig
+Auto-merging drivers/media/dvb-frontends/rtl2830.c
+Auto-merging drivers/media/dvb-frontends/nxt200x.c
+Auto-merging drivers/media/dvb-frontends/m88rs2000.c
+Auto-merging drivers/media/dvb-frontends/lgs8gxx.c
+Auto-merging drivers/media/dvb-frontends/lgs8gl5.c
+Auto-merging drivers/media/dvb-frontends/it913x-fe.c
+Auto-merging drivers/media/dvb-frontends/dvb-pll.h
+Auto-merging drivers/media/dvb-frontends/dvb-pll.c
+Auto-merging drivers/media/dvb-frontends/cxd2820r_t.c
+Auto-merging drivers/media/dvb-frontends/au8522_priv.h
+Auto-merging drivers/media/dvb-frontends/au8522_dig.c
+Auto-merging drivers/media/dvb-frontends/au8522_decoder.c
+Auto-merging drivers/media/dvb-frontends/au8522_common.c
+Auto-merging drivers/media/dvb-frontends/atbm8830.c
+Auto-merging drivers/media/dvb-frontends/Makefile
+Auto-merging drivers/media/dvb-core/dvbdev.h
+Auto-merging drivers/media/dvb-core/dvb_frontend.h
+Auto-merging drivers/media/dvb-core/dvb_frontend.c
+Auto-merging drivers/media/dvb-core/dvb_demux.c
+Auto-merging drivers/media/dvb-core/dmxdev.c
+Auto-merging drivers/media/common/siano/Makefile
+Auto-merging drivers/media/common/saa7146/saa7146_fops.c
+Auto-merging drivers/media/common/saa7146/saa7146_core.c
+Auto-merging drivers/media/common/b2c2/flexcop.c
+Auto-merging drivers/media/common/b2c2/Kconfig
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ Documentation/DocBook/media/Makefile               |    2 +-
+ Documentation/DocBook/media/dvb/audio.xml          |  113 +-
+ Documentation/DocBook/media/dvb/ca.xml             |  353 ++
+ Documentation/DocBook/media/dvb/demux.xml          |  230 +-
+ Documentation/DocBook/media/dvb/dvbapi.xml         |    2 +-
+ Documentation/DocBook/media/dvb/dvbproperty.xml    |   65 +-
+ Documentation/DocBook/media/dvb/frontend.xml       |   70 +-
+ Documentation/DocBook/media/dvb/kdapi.xml          |    2 +-
+ Documentation/DocBook/media/dvb/net.xml            |  127 +
+ Documentation/DocBook/media/dvb/video.xml          |  333 +-
+ Documentation/DocBook/media/v4l/biblio.xml         |   12 +-
+ Documentation/DocBook/media/v4l/compat.xml         |   16 -
+ Documentation/DocBook/media/v4l/controls.xml       |  453 ++-
+ Documentation/DocBook/media/v4l/dev-rds.xml        |    2 +-
+ Documentation/DocBook/media/v4l/dev-subdev.xml     |   20 +-
+ .../DocBook/media/v4l/pixfmt-srggb10dpcm8.xml      |    3 +-
+ Documentation/DocBook/media/v4l/selection-api.xml  |   22 +-
+ Documentation/DocBook/media/v4l/v4l2.xml           |   14 +-
+ .../DocBook/media/v4l/vidioc-g-selection.xml       |    9 +-
+ Documentation/DocBook/media/v4l/vidioc-g-tuner.xml |    2 +-
+ Documentation/DocBook/media/v4l/vidioc-qbuf.xml    |    2 +
+ .../media/v4l/vidioc-subdev-g-selection.xml        |    8 +-
+ Documentation/DocBook/media_api.tmpl               |    9 +-
+ Documentation/dvb/README.dvb-usb                   |    2 +-
+ Documentation/feature-removal-schedule.txt         |    9 +
+ Documentation/ioctl/ioctl-number.txt               |    5 -
+ MAINTAINERS                                        |   28 +-
+ arch/arm/mach-imx/clk-imx27.c                      |    4 +-
+ arch/arm/mach-imx/devices-imx27.h                  |    4 +
+ arch/arm/mach-imx/mach-imx27_visstrim_m10.c        |   49 +-
+ arch/arm/mach-omap2/board-rx51-peripherals.c       |   30 +
+ arch/arm/plat-mxc/devices/Kconfig                  |    6 +-
+ arch/arm/plat-mxc/devices/Makefile                 |    1 +
+ arch/arm/plat-mxc/devices/platform-imx27-coda.c    |   37 +
+ arch/arm/plat-mxc/include/mach/devices-common.h    |    8 +
+ drivers/media/Kconfig                              |   32 +-
+ drivers/media/Makefile                             |    7 +-
+ drivers/media/common/Kconfig                       |   12 +-
+ drivers/media/common/Makefile                      |    7 +-
+ drivers/media/{dvb => common}/b2c2/Kconfig         |   20 +-
+ drivers/media/common/b2c2/Makefile                 |    8 +
+ .../media/{dvb => common}/b2c2/flexcop-common.h    |    0
+ .../media/{dvb => common}/b2c2/flexcop-eeprom.c    |    0
+ .../media/{dvb => common}/b2c2/flexcop-fe-tuner.c  |    0
+ .../media/{dvb => common}/b2c2/flexcop-hw-filter.c |    0
+ drivers/media/{dvb => common}/b2c2/flexcop-i2c.c   |    0
+ drivers/media/{dvb => common}/b2c2/flexcop-misc.c  |    0
+ drivers/media/{dvb => common}/b2c2/flexcop-reg.h   |    0
+ drivers/media/{dvb => common}/b2c2/flexcop-sram.c  |    0
+ drivers/media/{dvb => common}/b2c2/flexcop.c       |    1 +
+ drivers/media/{dvb => common}/b2c2/flexcop.h       |    0
+ .../{dvb => common}/b2c2/flexcop_ibi_value_be.h    |    0
+ .../{dvb => common}/b2c2/flexcop_ibi_value_le.h    |    0
+ drivers/media/common/saa7146/Kconfig               |    9 +
+ drivers/media/common/saa7146/Makefile              |    5 +
+ drivers/media/common/{ => saa7146}/saa7146_core.c  |    8 -
+ drivers/media/common/{ => saa7146}/saa7146_fops.c  |   55 +-
+ drivers/media/common/{ => saa7146}/saa7146_hlp.c   |    0
+ drivers/media/common/{ => saa7146}/saa7146_i2c.c   |    0
+ drivers/media/common/{ => saa7146}/saa7146_vbi.c   |    0
+ drivers/media/common/{ => saa7146}/saa7146_video.c |    0
+ drivers/media/common/siano/Kconfig                 |   17 +
+ drivers/media/{dvb => common}/siano/Makefile       |    6 +-
+ drivers/media/{dvb => common}/siano/sms-cards.c    |    0
+ drivers/media/{dvb => common}/siano/sms-cards.h    |    0
+ drivers/media/{dvb => common}/siano/smscoreapi.c   |    0
+ drivers/media/{dvb => common}/siano/smscoreapi.h   |    0
+ drivers/media/{dvb => common}/siano/smsdvb.c       |    0
+ drivers/media/{dvb => common}/siano/smsendian.c    |    0
+ drivers/media/{dvb => common}/siano/smsendian.h    |    0
+ drivers/media/{dvb => common}/siano/smsir.c        |    0
+ drivers/media/{dvb => common}/siano/smsir.h        |    0
+ drivers/media/dvb-core/Kconfig                     |   29 +
+ drivers/media/{dvb => }/dvb-core/Makefile          |    0
+ drivers/media/{dvb => }/dvb-core/demux.h           |    0
+ drivers/media/{dvb => }/dvb-core/dmxdev.c          |    4 +-
+ drivers/media/{dvb => }/dvb-core/dmxdev.h          |    0
+ .../media/{dvb/dvb-usb => dvb-core}/dvb-usb-ids.h  |    0
+ drivers/media/{dvb => }/dvb-core/dvb_ca_en50221.c  |    0
+ drivers/media/{dvb => }/dvb-core/dvb_ca_en50221.h  |    0
+ drivers/media/{dvb => }/dvb-core/dvb_demux.c       |   19 +-
+ drivers/media/{dvb => }/dvb-core/dvb_demux.h       |    0
+ drivers/media/{dvb => }/dvb-core/dvb_filter.c      |    0
+ drivers/media/{dvb => }/dvb-core/dvb_filter.h      |    0
+ drivers/media/{dvb => }/dvb-core/dvb_frontend.c    |   72 +-
+ drivers/media/{dvb => }/dvb-core/dvb_frontend.h    |    4 +
+ drivers/media/{dvb => }/dvb-core/dvb_math.c        |    0
+ drivers/media/{dvb => }/dvb-core/dvb_math.h        |    0
+ drivers/media/{dvb => }/dvb-core/dvb_net.c         |    0
+ drivers/media/{dvb => }/dvb-core/dvb_net.h         |    0
+ drivers/media/{dvb => }/dvb-core/dvb_ringbuffer.c  |    0
+ drivers/media/{dvb => }/dvb-core/dvb_ringbuffer.h  |    0
+ drivers/media/{dvb => }/dvb-core/dvbdev.c          |    0
+ drivers/media/{dvb => }/dvb-core/dvbdev.h          |   26 -
+ .../media/{dvb/frontends => dvb-frontends}/Kconfig |    0
+ .../{dvb/frontends => dvb-frontends}/Makefile      |   12 +-
+ .../media/{dvb/frontends => dvb-frontends}/a8293.c |    0
+ .../media/{dvb/frontends => dvb-frontends}/a8293.h |    0
+ .../{dvb/frontends => dvb-frontends}/af9013.c      |    0
+ .../{dvb/frontends => dvb-frontends}/af9013.h      |    0
+ .../{dvb/frontends => dvb-frontends}/af9013_priv.h |    0
+ .../{dvb/frontends => dvb-frontends}/af9033.c      |    0
+ .../{dvb/frontends => dvb-frontends}/af9033.h      |    0
+ .../{dvb/frontends => dvb-frontends}/af9033_priv.h |    0
+ .../{dvb/frontends => dvb-frontends}/atbm8830.c    |    2 +-
+ .../{dvb/frontends => dvb-frontends}/atbm8830.h    |    0
+ .../frontends => dvb-frontends}/atbm8830_priv.h    |    0
+ .../{dvb/frontends => dvb-frontends}/au8522.h      |    0
+ .../frontends => dvb-frontends}/au8522_common.c    |   22 +-
+ .../frontends => dvb-frontends}/au8522_decoder.c   |   11 +-
+ .../{dvb/frontends => dvb-frontends}/au8522_dig.c  |   98 +-
+ .../{dvb/frontends => dvb-frontends}/au8522_priv.h |   29 +-
+ .../{dvb/frontends => dvb-frontends}/bcm3510.c     |    0
+ .../{dvb/frontends => dvb-frontends}/bcm3510.h     |    0
+ .../frontends => dvb-frontends}/bcm3510_priv.h     |    0
+ .../{dvb/frontends => dvb-frontends}/bsbe1-d01a.h  |    0
+ .../media/{dvb/frontends => dvb-frontends}/bsbe1.h |    0
+ .../media/{dvb/frontends => dvb-frontends}/bsru6.h |    0
+ .../{dvb/frontends => dvb-frontends}/cx22700.c     |    0
+ .../{dvb/frontends => dvb-frontends}/cx22700.h     |    0
+ .../{dvb/frontends => dvb-frontends}/cx22702.c     |    0
+ .../{dvb/frontends => dvb-frontends}/cx22702.h     |    0
+ .../{dvb/frontends => dvb-frontends}/cx24110.c     |    0
+ .../{dvb/frontends => dvb-frontends}/cx24110.h     |    0
+ .../{dvb/frontends => dvb-frontends}/cx24113.c     |    0
+ .../{dvb/frontends => dvb-frontends}/cx24113.h     |    0
+ .../{dvb/frontends => dvb-frontends}/cx24116.c     |    0
+ .../{dvb/frontends => dvb-frontends}/cx24116.h     |    0
+ .../{dvb/frontends => dvb-frontends}/cx24123.c     |    0
+ .../{dvb/frontends => dvb-frontends}/cx24123.h     |    0
+ .../{dvb/frontends => dvb-frontends}/cxd2820r.h    |    0
+ .../{dvb/frontends => dvb-frontends}/cxd2820r_c.c  |    0
+ .../frontends => dvb-frontends}/cxd2820r_core.c    |    0
+ .../frontends => dvb-frontends}/cxd2820r_priv.h    |    0
+ .../{dvb/frontends => dvb-frontends}/cxd2820r_t.c  |    3 +-
+ .../{dvb/frontends => dvb-frontends}/cxd2820r_t2.c |    0
+ .../{dvb/frontends => dvb-frontends}/dib0070.c     |    0
+ .../{dvb/frontends => dvb-frontends}/dib0070.h     |    0
+ .../{dvb/frontends => dvb-frontends}/dib0090.c     |    0
+ .../{dvb/frontends => dvb-frontends}/dib0090.h     |    0
+ .../{dvb/frontends => dvb-frontends}/dib3000.h     |    0
+ .../{dvb/frontends => dvb-frontends}/dib3000mb.c   |    0
+ .../frontends => dvb-frontends}/dib3000mb_priv.h   |    0
+ .../{dvb/frontends => dvb-frontends}/dib3000mc.c   |    0
+ .../{dvb/frontends => dvb-frontends}/dib3000mc.h   |    0
+ .../{dvb/frontends => dvb-frontends}/dib7000m.c    |    0
+ .../{dvb/frontends => dvb-frontends}/dib7000m.h    |    0
+ .../{dvb/frontends => dvb-frontends}/dib7000p.c    |    0
+ .../{dvb/frontends => dvb-frontends}/dib7000p.h    |    0
+ .../{dvb/frontends => dvb-frontends}/dib8000.c     |    0
+ .../{dvb/frontends => dvb-frontends}/dib8000.h     |    0
+ .../{dvb/frontends => dvb-frontends}/dib9000.c     |    0
+ .../{dvb/frontends => dvb-frontends}/dib9000.h     |    0
+ .../frontends => dvb-frontends}/dibx000_common.c   |    0
+ .../frontends => dvb-frontends}/dibx000_common.h   |    0
+ .../media/{dvb/frontends => dvb-frontends}/drxd.h  |    0
+ .../{dvb/frontends => dvb-frontends}/drxd_firm.c   |    0
+ .../{dvb/frontends => dvb-frontends}/drxd_firm.h   |    0
+ .../{dvb/frontends => dvb-frontends}/drxd_hard.c   |    0
+ .../frontends => dvb-frontends}/drxd_map_firm.h    |    0
+ .../media/{dvb/frontends => dvb-frontends}/drxk.h  |    0
+ .../{dvb/frontends => dvb-frontends}/drxk_hard.c   |    0
+ .../{dvb/frontends => dvb-frontends}/drxk_hard.h   |    0
+ .../{dvb/frontends => dvb-frontends}/drxk_map.h    |    0
+ .../{dvb/frontends => dvb-frontends}/ds3000.c      |    0
+ .../{dvb/frontends => dvb-frontends}/ds3000.h      |    0
+ .../{dvb/frontends => dvb-frontends}/dvb-pll.c     |   26 +
+ .../{dvb/frontends => dvb-frontends}/dvb-pll.h     |    1 +
+ .../frontends => dvb-frontends}/dvb_dummy_fe.c     |    0
+ .../frontends => dvb-frontends}/dvb_dummy_fe.h     |    0
+ .../media/{dvb/frontends => dvb-frontends}/ec100.c |    0
+ .../media/{dvb/frontends => dvb-frontends}/ec100.h |    0
+ .../{dvb/frontends => dvb-frontends}/ec100_priv.h  |    0
+ .../{dvb/frontends => dvb-frontends}/eds1547.h     |    0
+ .../{dvb/frontends => dvb-frontends}/hd29l2.c      |    0
+ .../{dvb/frontends => dvb-frontends}/hd29l2.h      |    0
+ .../{dvb/frontends => dvb-frontends}/hd29l2_priv.h |    0
+ .../{dvb/frontends => dvb-frontends}/isl6405.c     |    0
+ .../{dvb/frontends => dvb-frontends}/isl6405.h     |    0
+ .../{dvb/frontends => dvb-frontends}/isl6421.c     |    0
+ .../{dvb/frontends => dvb-frontends}/isl6421.h     |    0
+ .../{dvb/frontends => dvb-frontends}/isl6423.c     |    0
+ .../{dvb/frontends => dvb-frontends}/isl6423.h     |    0
+ .../frontends => dvb-frontends}/it913x-fe-priv.h   |    0
+ .../{dvb/frontends => dvb-frontends}/it913x-fe.c   |    2 +-
+ .../{dvb/frontends => dvb-frontends}/it913x-fe.h   |    0
+ .../{dvb/frontends => dvb-frontends}/itd1000.c     |    0
+ .../{dvb/frontends => dvb-frontends}/itd1000.h     |    0
+ .../frontends => dvb-frontends}/itd1000_priv.h     |    0
+ .../{dvb/frontends => dvb-frontends}/ix2505v.c     |    0
+ .../{dvb/frontends => dvb-frontends}/ix2505v.h     |    0
+ .../{dvb/frontends => dvb-frontends}/l64781.c      |    0
+ .../{dvb/frontends => dvb-frontends}/l64781.h      |    0
+ .../{dvb/frontends => dvb-frontends}/lg2160.c      |    0
+ .../{dvb/frontends => dvb-frontends}/lg2160.h      |    0
+ .../{dvb/frontends => dvb-frontends}/lgdt3305.c    |    0
+ .../{dvb/frontends => dvb-frontends}/lgdt3305.h    |    0
+ .../{dvb/frontends => dvb-frontends}/lgdt330x.c    |    0
+ .../{dvb/frontends => dvb-frontends}/lgdt330x.h    |    0
+ .../frontends => dvb-frontends}/lgdt330x_priv.h    |    0
+ .../{dvb/frontends => dvb-frontends}/lgs8gl5.c     |    2 +-
+ .../{dvb/frontends => dvb-frontends}/lgs8gl5.h     |    0
+ .../{dvb/frontends => dvb-frontends}/lgs8gxx.c     |    2 +-
+ .../{dvb/frontends => dvb-frontends}/lgs8gxx.h     |    0
+ .../frontends => dvb-frontends}/lgs8gxx_priv.h     |    0
+ .../{dvb/frontends => dvb-frontends}/lnbh24.h      |    0
+ .../{dvb/frontends => dvb-frontends}/lnbp21.c      |    0
+ .../{dvb/frontends => dvb-frontends}/lnbp21.h      |    0
+ .../{dvb/frontends => dvb-frontends}/lnbp22.c      |    0
+ .../{dvb/frontends => dvb-frontends}/lnbp22.h      |    0
+ .../{dvb/frontends => dvb-frontends}/m88rs2000.c   |    2 +-
+ .../{dvb/frontends => dvb-frontends}/m88rs2000.h   |    0
+ .../{dvb/frontends => dvb-frontends}/mb86a16.c     |    0
+ .../{dvb/frontends => dvb-frontends}/mb86a16.h     |    0
+ .../frontends => dvb-frontends}/mb86a16_priv.h     |    0
+ .../{dvb/frontends => dvb-frontends}/mb86a20s.c    |    0
+ .../{dvb/frontends => dvb-frontends}/mb86a20s.h    |    0
+ .../media/{dvb/frontends => dvb-frontends}/mt312.c |    0
+ .../media/{dvb/frontends => dvb-frontends}/mt312.h |    0
+ .../{dvb/frontends => dvb-frontends}/mt312_priv.h  |    0
+ .../media/{dvb/frontends => dvb-frontends}/mt352.c |    0
+ .../media/{dvb/frontends => dvb-frontends}/mt352.h |    0
+ .../{dvb/frontends => dvb-frontends}/mt352_priv.h  |    0
+ .../{dvb/frontends => dvb-frontends}/nxt200x.c     |   64 +-
+ .../{dvb/frontends => dvb-frontends}/nxt200x.h     |    0
+ .../{dvb/frontends => dvb-frontends}/nxt6000.c     |    0
+ .../{dvb/frontends => dvb-frontends}/nxt6000.h     |    0
+ .../frontends => dvb-frontends}/nxt6000_priv.h     |    0
+ .../{dvb/frontends => dvb-frontends}/or51132.c     |    0
+ .../{dvb/frontends => dvb-frontends}/or51132.h     |    0
+ .../{dvb/frontends => dvb-frontends}/or51211.c     |    0
+ .../{dvb/frontends => dvb-frontends}/or51211.h     |    0
+ .../{dvb/frontends => dvb-frontends}/rtl2830.c     |    2 +-
+ .../{dvb/frontends => dvb-frontends}/rtl2830.h     |    0
+ .../frontends => dvb-frontends}/rtl2830_priv.h     |    0
+ .../{dvb/frontends => dvb-frontends}/rtl2832.c     |    0
+ .../{dvb/frontends => dvb-frontends}/rtl2832.h     |    0
+ .../frontends => dvb-frontends}/rtl2832_priv.h     |    0
+ .../{dvb/frontends => dvb-frontends}/s5h1409.c     |    0
+ .../{dvb/frontends => dvb-frontends}/s5h1409.h     |    0
+ .../{dvb/frontends => dvb-frontends}/s5h1411.c     |    0
+ .../{dvb/frontends => dvb-frontends}/s5h1411.h     |    0
+ .../{dvb/frontends => dvb-frontends}/s5h1420.c     |    0
+ .../{dvb/frontends => dvb-frontends}/s5h1420.h     |    0
+ .../frontends => dvb-frontends}/s5h1420_priv.h     |    0
+ .../{dvb/frontends => dvb-frontends}/s5h1432.c     |    0
+ .../{dvb/frontends => dvb-frontends}/s5h1432.h     |    0
+ .../media/{dvb/frontends => dvb-frontends}/s921.c  |    0
+ .../media/{dvb/frontends => dvb-frontends}/s921.h  |    0
+ .../{dvb/frontends => dvb-frontends}/si21xx.c      |    0
+ .../{dvb/frontends => dvb-frontends}/si21xx.h      |    0
+ .../{dvb/frontends => dvb-frontends}/sp8870.c      |    0
+ .../{dvb/frontends => dvb-frontends}/sp8870.h      |    0
+ .../{dvb/frontends => dvb-frontends}/sp887x.c      |    0
+ .../{dvb/frontends => dvb-frontends}/sp887x.h      |    0
+ .../frontends => dvb-frontends}/stb0899_algo.c     |    0
+ .../{dvb/frontends => dvb-frontends}/stb0899_cfg.h |    0
+ .../{dvb/frontends => dvb-frontends}/stb0899_drv.c |    0
+ .../{dvb/frontends => dvb-frontends}/stb0899_drv.h |    0
+ .../frontends => dvb-frontends}/stb0899_priv.h     |    0
+ .../{dvb/frontends => dvb-frontends}/stb0899_reg.h |    0
+ .../{dvb/frontends => dvb-frontends}/stb6000.c     |    0
+ .../{dvb/frontends => dvb-frontends}/stb6000.h     |    0
+ .../{dvb/frontends => dvb-frontends}/stb6100.c     |    0
+ .../{dvb/frontends => dvb-frontends}/stb6100.h     |    0
+ .../{dvb/frontends => dvb-frontends}/stb6100_cfg.h |    0
+ .../frontends => dvb-frontends}/stb6100_proc.h     |    0
+ .../{dvb/frontends => dvb-frontends}/stv0288.c     |    0
+ .../{dvb/frontends => dvb-frontends}/stv0288.h     |    0
+ .../{dvb/frontends => dvb-frontends}/stv0297.c     |    0
+ .../{dvb/frontends => dvb-frontends}/stv0297.h     |    0
+ .../{dvb/frontends => dvb-frontends}/stv0299.c     |    0
+ .../{dvb/frontends => dvb-frontends}/stv0299.h     |    0
+ .../{dvb/frontends => dvb-frontends}/stv0367.c     |    0
+ .../{dvb/frontends => dvb-frontends}/stv0367.h     |    0
+ .../frontends => dvb-frontends}/stv0367_priv.h     |    0
+ .../frontends => dvb-frontends}/stv0367_regs.h     |    0
+ .../{dvb/frontends => dvb-frontends}/stv0900.h     |    0
+ .../frontends => dvb-frontends}/stv0900_core.c     |    0
+ .../frontends => dvb-frontends}/stv0900_init.h     |    0
+ .../frontends => dvb-frontends}/stv0900_priv.h     |    0
+ .../{dvb/frontends => dvb-frontends}/stv0900_reg.h |    0
+ .../{dvb/frontends => dvb-frontends}/stv0900_sw.c  |    0
+ .../{dvb/frontends => dvb-frontends}/stv090x.c     |    0
+ .../{dvb/frontends => dvb-frontends}/stv090x.h     |    0
+ .../frontends => dvb-frontends}/stv090x_priv.h     |    0
+ .../{dvb/frontends => dvb-frontends}/stv090x_reg.h |    0
+ .../{dvb/frontends => dvb-frontends}/stv6110.c     |    0
+ .../{dvb/frontends => dvb-frontends}/stv6110.h     |    0
+ .../{dvb/frontends => dvb-frontends}/stv6110x.c    |    0
+ .../{dvb/frontends => dvb-frontends}/stv6110x.h    |    0
+ .../frontends => dvb-frontends}/stv6110x_priv.h    |    0
+ .../frontends => dvb-frontends}/stv6110x_reg.h     |    0
+ .../{dvb/frontends => dvb-frontends}/tda10021.c    |    0
+ .../{dvb/frontends => dvb-frontends}/tda10023.c    |    0
+ .../{dvb/frontends => dvb-frontends}/tda1002x.h    |    0
+ .../{dvb/frontends => dvb-frontends}/tda10048.c    |    0
+ .../{dvb/frontends => dvb-frontends}/tda10048.h    |    0
+ .../{dvb/frontends => dvb-frontends}/tda1004x.c    |    0
+ .../{dvb/frontends => dvb-frontends}/tda1004x.h    |    0
+ .../{dvb/frontends => dvb-frontends}/tda10071.c    |    0
+ .../{dvb/frontends => dvb-frontends}/tda10071.h    |    0
+ .../frontends => dvb-frontends}/tda10071_priv.h    |    0
+ .../{dvb/frontends => dvb-frontends}/tda10086.c    |    0
+ .../{dvb/frontends => dvb-frontends}/tda10086.h    |    0
+ .../frontends => dvb-frontends}/tda18271c2dd.c     |    0
+ .../frontends => dvb-frontends}/tda18271c2dd.h     |    0
+ .../tda18271c2dd_maps.h                            |    0
+ .../{dvb/frontends => dvb-frontends}/tda665x.c     |    0
+ .../{dvb/frontends => dvb-frontends}/tda665x.h     |    0
+ .../{dvb/frontends => dvb-frontends}/tda8083.c     |    0
+ .../{dvb/frontends => dvb-frontends}/tda8083.h     |    0
+ .../{dvb/frontends => dvb-frontends}/tda8261.c     |    0
+ .../{dvb/frontends => dvb-frontends}/tda8261.h     |    0
+ .../{dvb/frontends => dvb-frontends}/tda8261_cfg.h |    0
+ .../{dvb/frontends => dvb-frontends}/tda826x.c     |    0
+ .../{dvb/frontends => dvb-frontends}/tda826x.h     |    0
+ .../media/{dvb/frontends => dvb-frontends}/tdhd1.h |    0
+ .../{dvb/frontends => dvb-frontends}/tua6100.c     |    0
+ .../{dvb/frontends => dvb-frontends}/tua6100.h     |    0
+ .../{dvb/frontends => dvb-frontends}/ves1820.c     |    0
+ .../{dvb/frontends => dvb-frontends}/ves1820.h     |    0
+ .../{dvb/frontends => dvb-frontends}/ves1x93.c     |    0
+ .../{dvb/frontends => dvb-frontends}/ves1x93.h     |    0
+ .../{dvb/frontends => dvb-frontends}/z0194a.h      |    0
+ .../{dvb/frontends => dvb-frontends}/zl10036.c     |    0
+ .../{dvb/frontends => dvb-frontends}/zl10036.h     |    0
+ .../{dvb/frontends => dvb-frontends}/zl10039.c     |    0
+ .../{dvb/frontends => dvb-frontends}/zl10039.h     |    0
+ .../{dvb/frontends => dvb-frontends}/zl10353.c     |    0
+ .../{dvb/frontends => dvb-frontends}/zl10353.h     |    0
+ .../frontends => dvb-frontends}/zl10353_priv.h     |    0
+ drivers/media/dvb/Kconfig                          |   91 -
+ drivers/media/dvb/Makefile                         |   21 -
+ drivers/media/dvb/b2c2/Makefile                    |   16 -
+ drivers/media/dvb/bt8xx/Makefile                   |    6 -
+ drivers/media/dvb/dm1105/Makefile                  |    3 -
+ drivers/media/dvb/dvb-usb/Makefile                 |  121 -
+ drivers/media/dvb/dvb-usb/af9015.c                 | 1952 ---------
+ drivers/media/dvb/dvb-usb/it913x.c                 |  931 -----
+ drivers/media/dvb/dvb-usb/mxl111sf.c               | 1835 ---------
+ drivers/media/dvb/pluto2/Makefile                  |    3 -
+ drivers/media/dvb/siano/Kconfig                    |   34 -
+ drivers/media/dvb/ttusb-budget/Makefile            |    3 -
+ drivers/media/{dvb => }/firewire/Kconfig           |    0
+ drivers/media/{dvb => }/firewire/Makefile          |    4 +-
+ drivers/media/{dvb => }/firewire/firedtv-avc.c     |    0
+ drivers/media/{dvb => }/firewire/firedtv-ci.c      |    0
+ drivers/media/{dvb => }/firewire/firedtv-dvb.c     |    0
+ drivers/media/{dvb => }/firewire/firedtv-fe.c      |    0
+ drivers/media/{dvb => }/firewire/firedtv-fw.c      |    0
+ drivers/media/{dvb => }/firewire/firedtv-rc.c      |    0
+ drivers/media/{dvb => }/firewire/firedtv.h         |    0
+ drivers/media/i2c/Kconfig                          |  570 +++
+ drivers/media/i2c/Makefile                         |   64 +
+ drivers/media/{video => i2c}/adp1653.c             |    2 +-
+ drivers/media/{video => i2c}/adv7170.c             |    0
+ drivers/media/{video => i2c}/adv7175.c             |    0
+ drivers/media/{video => i2c}/adv7180.c             |    0
+ drivers/media/{video => i2c}/adv7183.c             |    0
+ drivers/media/{video => i2c}/adv7183_regs.h        |    0
+ drivers/media/{video => i2c}/adv7343.c             |    0
+ drivers/media/{video => i2c}/adv7343_regs.h        |    0
+ drivers/media/{video => i2c}/adv7393.c             |    0
+ drivers/media/{video => i2c}/adv7393_regs.h        |    0
+ drivers/media/{video => i2c}/ak881x.c              |    0
+ drivers/media/{video => i2c}/aptina-pll.c          |    0
+ drivers/media/{video => i2c}/aptina-pll.h          |    0
+ drivers/media/{video => i2c}/as3645a.c             |    2 +-
+ drivers/media/{video => i2c}/bt819.c               |    0
+ drivers/media/{video => i2c}/bt856.c               |    0
+ drivers/media/{video => i2c}/bt866.c               |    0
+ drivers/media/{video => i2c}/btcx-risc.c           |    0
+ drivers/media/{video => i2c}/btcx-risc.h           |    0
+ drivers/media/{video => i2c}/cs5345.c              |    0
+ drivers/media/{video => i2c}/cs53l32a.c            |    0
+ drivers/media/{video => i2c}/cx2341x.c             |    0
+ drivers/media/{video => i2c}/cx25840/Kconfig       |    0
+ drivers/media/{video => i2c}/cx25840/Makefile      |    2 +-
+ .../media/{video => i2c}/cx25840/cx25840-audio.c   |    0
+ .../media/{video => i2c}/cx25840/cx25840-core.c    |    0
+ .../media/{video => i2c}/cx25840/cx25840-core.h    |    0
+ .../{video => i2c}/cx25840/cx25840-firmware.c      |   15 +-
+ drivers/media/{video => i2c}/cx25840/cx25840-ir.c  |    0
+ drivers/media/{video => i2c}/cx25840/cx25840-vbi.c |    0
+ drivers/media/{video => i2c}/ir-kbd-i2c.c          |    0
+ drivers/media/{video => i2c}/ks0127.c              |    0
+ drivers/media/{video => i2c}/ks0127.h              |    0
+ drivers/media/{video => i2c}/m52790.c              |    0
+ drivers/media/{video => i2c}/m5mols/Kconfig        |    0
+ drivers/media/{video => i2c}/m5mols/Makefile       |    0
+ drivers/media/{video => i2c}/m5mols/m5mols.h       |    0
+ .../media/{video => i2c}/m5mols/m5mols_capture.c   |    0
+ .../media/{video => i2c}/m5mols/m5mols_controls.c  |    0
+ drivers/media/{video => i2c}/m5mols/m5mols_core.c  |    0
+ drivers/media/{video => i2c}/m5mols/m5mols_reg.h   |    0
+ drivers/media/{video => i2c}/msp3400-driver.c      |    0
+ drivers/media/{video => i2c}/msp3400-driver.h      |    0
+ drivers/media/{video => i2c}/msp3400-kthreads.c    |    0
+ drivers/media/{video => i2c}/mt9m032.c             |    0
+ drivers/media/{video => i2c}/mt9p031.c             |    0
+ drivers/media/{video => i2c}/mt9t001.c             |    0
+ drivers/media/{video => i2c}/mt9v011.c             |    0
+ drivers/media/{video => i2c}/mt9v032.c             |    0
+ drivers/media/{video => i2c}/noon010pc30.c         |    0
+ drivers/media/{video => i2c}/ov7670.c              |    0
+ drivers/media/{video => i2c}/s5k6aa.c              |    9 +-
+ drivers/media/{video => i2c}/saa6588.c             |    0
+ drivers/media/{video => i2c}/saa7110.c             |    0
+ drivers/media/{video => i2c}/saa7115.c             |    0
+ drivers/media/{video => i2c}/saa711x_regs.h        |    0
+ drivers/media/{video => i2c}/saa7127.c             |    5 +-
+ drivers/media/{video => i2c}/saa717x.c             |    0
+ drivers/media/{video => i2c}/saa7185.c             |    0
+ drivers/media/{video => i2c}/saa7191.c             |    0
+ drivers/media/{video => i2c}/saa7191.h             |    0
+ drivers/media/{video => i2c}/smiapp-pll.c          |    2 +-
+ drivers/media/{video => i2c}/smiapp-pll.h          |    2 +-
+ drivers/media/{video => i2c}/smiapp/Kconfig        |    0
+ drivers/media/{video => i2c}/smiapp/Makefile       |    2 +-
+ drivers/media/{video => i2c}/smiapp/smiapp-core.c  |    2 +-
+ .../media/{video => i2c}/smiapp/smiapp-limits.c    |    2 +-
+ .../media/{video => i2c}/smiapp/smiapp-limits.h    |    2 +-
+ drivers/media/{video => i2c}/smiapp/smiapp-quirk.c |    2 +-
+ drivers/media/{video => i2c}/smiapp/smiapp-quirk.h |    2 +-
+ .../media/{video => i2c}/smiapp/smiapp-reg-defs.h  |    2 +-
+ drivers/media/{video => i2c}/smiapp/smiapp-reg.h   |    2 +-
+ drivers/media/{video => i2c}/smiapp/smiapp-regs.c  |    2 +-
+ drivers/media/{video => i2c}/smiapp/smiapp-regs.h  |    0
+ drivers/media/{video => i2c}/smiapp/smiapp.h       |    2 +-
+ drivers/media/i2c/soc_camera/Kconfig               |   89 +
+ drivers/media/i2c/soc_camera/Makefile              |   14 +
+ drivers/media/{video => i2c/soc_camera}/imx074.c   |   30 +-
+ drivers/media/{video => i2c/soc_camera}/mt9m001.c  |   26 +-
+ drivers/media/{video => i2c/soc_camera}/mt9m111.c  |  116 +-
+ drivers/media/{video => i2c/soc_camera}/mt9t031.c  |   48 +-
+ drivers/media/{video => i2c/soc_camera}/mt9t112.c  |   21 +-
+ drivers/media/{video => i2c/soc_camera}/mt9v022.c  |   50 +-
+ drivers/media/{video => i2c/soc_camera}/ov2640.c   |   20 +-
+ drivers/media/{video => i2c/soc_camera}/ov5642.c   |   31 +-
+ drivers/media/{video => i2c/soc_camera}/ov6650.c   |   28 +-
+ drivers/media/{video => i2c/soc_camera}/ov772x.c   |  447 ++-
+ drivers/media/{video => i2c/soc_camera}/ov9640.c   |   27 +-
+ drivers/media/{video => i2c/soc_camera}/ov9640.h   |    0
+ drivers/media/{video => i2c/soc_camera}/ov9740.c   |   47 +-
+ .../media/{video => i2c/soc_camera}/rj54n1cb0c.c   |   27 +-
+ .../{video => i2c/soc_camera}/sh_mobile_csi2.c     |    0
+ drivers/media/{video => i2c/soc_camera}/tw9910.c   |   21 +-
+ drivers/media/{video => i2c}/sr030pc30.c           |    0
+ drivers/media/{video => i2c}/tcm825x.c             |    2 +-
+ drivers/media/{video => i2c}/tcm825x.h             |    2 +-
+ drivers/media/{video => i2c}/tda7432.c             |    0
+ drivers/media/{video => i2c}/tda9840.c             |    0
+ drivers/media/{video => i2c}/tea6415c.c            |    0
+ drivers/media/{video => i2c}/tea6415c.h            |    0
+ drivers/media/{video => i2c}/tea6420.c             |    0
+ drivers/media/{video => i2c}/tea6420.h             |    0
+ drivers/media/{video => i2c}/ths7303.c             |    0
+ drivers/media/{video => i2c}/tlv320aic23b.c        |    0
+ drivers/media/{video => i2c}/tvaudio.c             |    0
+ drivers/media/{video => i2c}/tveeprom.c            |    0
+ drivers/media/{video => i2c}/tvp514x.c             |    2 +-
+ drivers/media/{video => i2c}/tvp514x_regs.h        |    2 +-
+ drivers/media/{video => i2c}/tvp5150.c             |    0
+ drivers/media/{video => i2c}/tvp5150_reg.h         |    0
+ drivers/media/{video => i2c}/tvp7002.c             |    0
+ drivers/media/{video => i2c}/tvp7002_reg.h         |    0
+ drivers/media/{video => i2c}/upd64031a.c           |    0
+ drivers/media/{video => i2c}/upd64083.c            |    0
+ drivers/media/{video => i2c}/vp27smpx.c            |    0
+ drivers/media/{video => i2c}/vpx3220.c             |    0
+ drivers/media/{video => i2c}/vs6624.c              |    0
+ drivers/media/{video => i2c}/vs6624_regs.h         |    0
+ drivers/media/{video => i2c}/wm8739.c              |    0
+ drivers/media/{video => i2c}/wm8775.c              |    0
+ drivers/media/media-device.c                       |    4 +-
+ drivers/media/mmc/Kconfig                          |    2 +
+ drivers/media/mmc/Makefile                         |    1 +
+ drivers/media/mmc/siano/Kconfig                    |   10 +
+ drivers/media/mmc/siano/Makefile                   |    6 +
+ drivers/media/{dvb => mmc}/siano/smssdio.c         |    0
+ drivers/media/parport/Kconfig                      |   47 +
+ drivers/media/parport/Makefile                     |    4 +
+ drivers/media/{video => parport}/bw-qcam.c         |    0
+ drivers/media/{video => parport}/c-qcam.c          |    0
+ drivers/media/{video => parport}/pms.c             |    0
+ drivers/media/{video => parport}/w9966.c           |    0
+ drivers/media/pci/Kconfig                          |   45 +
+ drivers/media/pci/Makefile                         |   26 +
+ drivers/media/pci/b2c2/Kconfig                     |    6 +
+ drivers/media/pci/b2c2/Makefile                    |    9 +
+ drivers/media/{dvb => pci}/b2c2/flexcop-dma.c      |    0
+ drivers/media/{dvb => pci}/b2c2/flexcop-pci.c      |    0
+ drivers/media/{dvb => pci}/bt8xx/Kconfig           |   23 +-
+ drivers/media/pci/bt8xx/Makefile                   |   11 +
+ drivers/media/{video => pci}/bt8xx/bt848.h         |    0
+ drivers/media/{dvb => pci}/bt8xx/bt878.c           |    0
+ drivers/media/{dvb => pci}/bt8xx/bt878.h           |    0
+ .../media/{video => pci}/bt8xx/bttv-audio-hook.c   |    0
+ .../media/{video => pci}/bt8xx/bttv-audio-hook.h   |    0
+ drivers/media/{video => pci}/bt8xx/bttv-cards.c    |    0
+ drivers/media/{video => pci}/bt8xx/bttv-driver.c   |    0
+ drivers/media/{video => pci}/bt8xx/bttv-gpio.c     |    0
+ drivers/media/{video => pci}/bt8xx/bttv-i2c.c      |    0
+ drivers/media/{video => pci}/bt8xx/bttv-if.c       |    0
+ drivers/media/{video => pci}/bt8xx/bttv-input.c    |    0
+ drivers/media/{video => pci}/bt8xx/bttv-risc.c     |    0
+ drivers/media/{video => pci}/bt8xx/bttv-vbi.c      |    0
+ drivers/media/{video => pci}/bt8xx/bttv.h          |    0
+ drivers/media/{video => pci}/bt8xx/bttvp.h         |    0
+ drivers/media/{dvb => pci}/bt8xx/dst.c             |    0
+ drivers/media/{dvb => pci}/bt8xx/dst_ca.c          |    3 +-
+ drivers/media/{dvb => pci}/bt8xx/dst_ca.h          |    0
+ drivers/media/{dvb => pci}/bt8xx/dst_common.h      |    0
+ drivers/media/{dvb => pci}/bt8xx/dst_priv.h        |    0
+ drivers/media/{dvb => pci}/bt8xx/dvb-bt8xx.c       |    0
+ drivers/media/{dvb => pci}/bt8xx/dvb-bt8xx.h       |    0
+ drivers/media/{video => pci}/cx18/Kconfig          |    0
+ drivers/media/{video => pci}/cx18/Makefile         |    6 +-
+ drivers/media/{video => pci}/cx18/cx18-alsa-main.c |    0
+ .../media/{video => pci}/cx18/cx18-alsa-mixer.c    |    0
+ .../media/{video => pci}/cx18/cx18-alsa-mixer.h    |    0
+ drivers/media/{video => pci}/cx18/cx18-alsa-pcm.c  |    0
+ drivers/media/{video => pci}/cx18/cx18-alsa-pcm.h  |    0
+ drivers/media/{video => pci}/cx18/cx18-alsa.h      |    0
+ drivers/media/{video => pci}/cx18/cx18-audio.c     |    0
+ drivers/media/{video => pci}/cx18/cx18-audio.h     |    0
+ drivers/media/{video => pci}/cx18/cx18-av-audio.c  |    0
+ drivers/media/{video => pci}/cx18/cx18-av-core.c   |    0
+ drivers/media/{video => pci}/cx18/cx18-av-core.h   |    0
+ .../media/{video => pci}/cx18/cx18-av-firmware.c   |    2 +
+ drivers/media/{video => pci}/cx18/cx18-av-vbi.c    |    0
+ drivers/media/{video => pci}/cx18/cx18-cards.c     |    0
+ drivers/media/{video => pci}/cx18/cx18-cards.h     |    0
+ drivers/media/{video => pci}/cx18/cx18-controls.c  |    0
+ drivers/media/{video => pci}/cx18/cx18-controls.h  |    0
+ drivers/media/{video => pci}/cx18/cx18-driver.c    |    1 +
+ drivers/media/{video => pci}/cx18/cx18-driver.h    |    0
+ drivers/media/{video => pci}/cx18/cx18-dvb.c       |    6 +-
+ drivers/media/{video => pci}/cx18/cx18-dvb.h       |    0
+ drivers/media/{video => pci}/cx18/cx18-fileops.c   |    0
+ drivers/media/{video => pci}/cx18/cx18-fileops.h   |    0
+ drivers/media/{video => pci}/cx18/cx18-firmware.c  |   10 +-
+ drivers/media/{video => pci}/cx18/cx18-firmware.h  |    0
+ drivers/media/{video => pci}/cx18/cx18-gpio.c      |    0
+ drivers/media/{video => pci}/cx18/cx18-gpio.h      |    0
+ drivers/media/{video => pci}/cx18/cx18-i2c.c       |    0
+ drivers/media/{video => pci}/cx18/cx18-i2c.h       |    0
+ drivers/media/{video => pci}/cx18/cx18-io.c        |    0
+ drivers/media/{video => pci}/cx18/cx18-io.h        |    0
+ drivers/media/{video => pci}/cx18/cx18-ioctl.c     |    0
+ drivers/media/{video => pci}/cx18/cx18-ioctl.h     |    0
+ drivers/media/{video => pci}/cx18/cx18-irq.c       |    0
+ drivers/media/{video => pci}/cx18/cx18-irq.h       |    0
+ drivers/media/{video => pci}/cx18/cx18-mailbox.c   |    0
+ drivers/media/{video => pci}/cx18/cx18-mailbox.h   |    0
+ drivers/media/{video => pci}/cx18/cx18-queue.c     |    0
+ drivers/media/{video => pci}/cx18/cx18-queue.h     |    0
+ drivers/media/{video => pci}/cx18/cx18-scb.c       |    0
+ drivers/media/{video => pci}/cx18/cx18-scb.h       |    0
+ drivers/media/{video => pci}/cx18/cx18-streams.c   |    0
+ drivers/media/{video => pci}/cx18/cx18-streams.h   |    0
+ drivers/media/{video => pci}/cx18/cx18-vbi.c       |    0
+ drivers/media/{video => pci}/cx18/cx18-vbi.h       |    0
+ drivers/media/{video => pci}/cx18/cx18-version.h   |    0
+ drivers/media/{video => pci}/cx18/cx18-video.c     |    0
+ drivers/media/{video => pci}/cx18/cx18-video.h     |    0
+ drivers/media/{video => pci}/cx18/cx23418.h        |    0
+ drivers/media/{video => pci}/cx23885/Kconfig       |    0
+ drivers/media/{video => pci}/cx23885/Makefile      |    8 +-
+ drivers/media/{video => pci}/cx23885/altera-ci.c   |    0
+ drivers/media/{video => pci}/cx23885/altera-ci.h   |    0
+ drivers/media/{video => pci}/cx23885/cimax2.c      |    0
+ drivers/media/{video => pci}/cx23885/cimax2.h      |    0
+ drivers/media/{video => pci}/cx23885/cx23885-417.c |    2 +
+ .../media/{video => pci}/cx23885/cx23885-alsa.c    |    0
+ drivers/media/{video => pci}/cx23885/cx23885-av.c  |    0
+ drivers/media/{video => pci}/cx23885/cx23885-av.h  |    0
+ .../media/{video => pci}/cx23885/cx23885-cards.c   |    6 +-
+ .../media/{video => pci}/cx23885/cx23885-core.c    |    0
+ drivers/media/{video => pci}/cx23885/cx23885-dvb.c |    3 +-
+ .../media/{video => pci}/cx23885/cx23885-f300.c    |    0
+ .../media/{video => pci}/cx23885/cx23885-f300.h    |    0
+ drivers/media/{video => pci}/cx23885/cx23885-i2c.c |    0
+ .../media/{video => pci}/cx23885/cx23885-input.c   |    9 +
+ .../media/{video => pci}/cx23885/cx23885-input.h   |    0
+ .../media/{video => pci}/cx23885/cx23885-ioctl.c   |    0
+ .../media/{video => pci}/cx23885/cx23885-ioctl.h   |    0
+ drivers/media/{video => pci}/cx23885/cx23885-ir.c  |    0
+ drivers/media/{video => pci}/cx23885/cx23885-ir.h  |    0
+ drivers/media/{video => pci}/cx23885/cx23885-reg.h |    0
+ drivers/media/{video => pci}/cx23885/cx23885-vbi.c |    0
+ .../media/{video => pci}/cx23885/cx23885-video.c   |    0
+ drivers/media/{video => pci}/cx23885/cx23885.h     |    0
+ drivers/media/{video => pci}/cx23885/cx23888-ir.c  |    0
+ drivers/media/{video => pci}/cx23885/cx23888-ir.h  |    0
+ .../media/{video => pci}/cx23885/netup-eeprom.c    |    0
+ .../media/{video => pci}/cx23885/netup-eeprom.h    |    0
+ drivers/media/{video => pci}/cx23885/netup-init.c  |    0
+ drivers/media/{video => pci}/cx23885/netup-init.h  |    0
+ drivers/media/{video => pci}/cx25821/Kconfig       |    0
+ drivers/media/{video => pci}/cx25821/Makefile      |    8 +-
+ .../media/{video => pci}/cx25821/cx25821-alsa.c    |    0
+ .../cx25821/cx25821-audio-upstream.c               |    0
+ .../cx25821/cx25821-audio-upstream.h               |    0
+ .../media/{video => pci}/cx25821/cx25821-audio.h   |    0
+ .../{video => pci}/cx25821/cx25821-biffuncs.h      |    0
+ .../media/{video => pci}/cx25821/cx25821-cards.c   |    0
+ .../media/{video => pci}/cx25821/cx25821-core.c    |    0
+ .../media/{video => pci}/cx25821/cx25821-gpio.c    |    0
+ drivers/media/{video => pci}/cx25821/cx25821-i2c.c |    0
+ .../cx25821/cx25821-medusa-defines.h               |    0
+ .../{video => pci}/cx25821/cx25821-medusa-reg.h    |    0
+ .../{video => pci}/cx25821/cx25821-medusa-video.c  |    0
+ .../{video => pci}/cx25821/cx25821-medusa-video.h  |    0
+ drivers/media/{video => pci}/cx25821/cx25821-reg.h |    0
+ .../media/{video => pci}/cx25821/cx25821-sram.h    |    0
+ .../cx25821/cx25821-video-upstream-ch2.c           |    0
+ .../cx25821/cx25821-video-upstream-ch2.h           |    0
+ .../cx25821/cx25821-video-upstream.c               |    0
+ .../cx25821/cx25821-video-upstream.h               |    0
+ .../media/{video => pci}/cx25821/cx25821-video.c   |    0
+ .../media/{video => pci}/cx25821/cx25821-video.h   |    0
+ drivers/media/{video => pci}/cx25821/cx25821.h     |    0
+ drivers/media/{video => pci}/cx88/Kconfig          |    0
+ drivers/media/{video => pci}/cx88/Makefile         |    8 +-
+ drivers/media/{video => pci}/cx88/cx88-alsa.c      |    2 +-
+ drivers/media/{video => pci}/cx88/cx88-blackbird.c |    0
+ drivers/media/{video => pci}/cx88/cx88-cards.c     |    0
+ drivers/media/{video => pci}/cx88/cx88-core.c      |    2 +-
+ drivers/media/{video => pci}/cx88/cx88-dsp.c       |    0
+ drivers/media/{video => pci}/cx88/cx88-dvb.c       |    2 +-
+ drivers/media/{video => pci}/cx88/cx88-i2c.c       |    0
+ drivers/media/{video => pci}/cx88/cx88-input.c     |    0
+ drivers/media/{video => pci}/cx88/cx88-mpeg.c      |    0
+ drivers/media/{video => pci}/cx88/cx88-reg.h       |    0
+ drivers/media/{video => pci}/cx88/cx88-tvaudio.c   |    0
+ drivers/media/{video => pci}/cx88/cx88-vbi.c       |    0
+ drivers/media/{video => pci}/cx88/cx88-video.c     |    0
+ .../media/{video => pci}/cx88/cx88-vp3054-i2c.c    |    0
+ .../media/{video => pci}/cx88/cx88-vp3054-i2c.h    |    0
+ drivers/media/{video => pci}/cx88/cx88.h           |    2 +-
+ drivers/media/{dvb => pci}/ddbridge/Kconfig        |    0
+ drivers/media/{dvb => pci}/ddbridge/Makefile       |    6 +-
+ .../media/{dvb => pci}/ddbridge/ddbridge-core.c    |    0
+ .../media/{dvb => pci}/ddbridge/ddbridge-regs.h    |    0
+ drivers/media/{dvb => pci}/ddbridge/ddbridge.h     |    0
+ drivers/media/{dvb => pci}/dm1105/Kconfig          |    0
+ drivers/media/pci/dm1105/Makefile                  |    3 +
+ drivers/media/{dvb => pci}/dm1105/dm1105.c         |    0
+ drivers/media/{video => pci}/ivtv/Kconfig          |    0
+ drivers/media/{video => pci}/ivtv/Makefile         |    8 +-
+ drivers/media/{video => pci}/ivtv/ivtv-cards.c     |    0
+ drivers/media/{video => pci}/ivtv/ivtv-cards.h     |    0
+ drivers/media/{video => pci}/ivtv/ivtv-controls.c  |    0
+ drivers/media/{video => pci}/ivtv/ivtv-controls.h  |    0
+ drivers/media/{video => pci}/ivtv/ivtv-driver.c    |    0
+ drivers/media/{video => pci}/ivtv/ivtv-driver.h    |    0
+ drivers/media/{video => pci}/ivtv/ivtv-fileops.c   |   52 +-
+ drivers/media/{video => pci}/ivtv/ivtv-fileops.h   |    0
+ drivers/media/{video => pci}/ivtv/ivtv-firmware.c  |    4 +
+ drivers/media/{video => pci}/ivtv/ivtv-firmware.h  |    0
+ drivers/media/{video => pci}/ivtv/ivtv-gpio.c      |    0
+ drivers/media/{video => pci}/ivtv/ivtv-gpio.h      |    0
+ drivers/media/{video => pci}/ivtv/ivtv-i2c.c       |    0
+ drivers/media/{video => pci}/ivtv/ivtv-i2c.h       |    0
+ drivers/media/{video => pci}/ivtv/ivtv-ioctl.c     |    0
+ drivers/media/{video => pci}/ivtv/ivtv-ioctl.h     |    0
+ drivers/media/{video => pci}/ivtv/ivtv-irq.c       |    0
+ drivers/media/{video => pci}/ivtv/ivtv-irq.h       |    0
+ drivers/media/{video => pci}/ivtv/ivtv-mailbox.c   |    0
+ drivers/media/{video => pci}/ivtv/ivtv-mailbox.h   |    0
+ drivers/media/{video => pci}/ivtv/ivtv-queue.c     |    0
+ drivers/media/{video => pci}/ivtv/ivtv-queue.h     |    0
+ drivers/media/{video => pci}/ivtv/ivtv-routing.c   |    0
+ drivers/media/{video => pci}/ivtv/ivtv-routing.h   |    0
+ drivers/media/{video => pci}/ivtv/ivtv-streams.c   |    4 -
+ drivers/media/{video => pci}/ivtv/ivtv-streams.h   |    0
+ drivers/media/{video => pci}/ivtv/ivtv-udma.c      |    0
+ drivers/media/{video => pci}/ivtv/ivtv-udma.h      |    0
+ drivers/media/{video => pci}/ivtv/ivtv-vbi.c       |    0
+ drivers/media/{video => pci}/ivtv/ivtv-vbi.h       |    0
+ drivers/media/{video => pci}/ivtv/ivtv-version.h   |    0
+ drivers/media/{video => pci}/ivtv/ivtv-yuv.c       |    0
+ drivers/media/{video => pci}/ivtv/ivtv-yuv.h       |    0
+ drivers/media/{video => pci}/ivtv/ivtvfb.c         |    0
+ drivers/media/{dvb => pci}/mantis/Kconfig          |    0
+ drivers/media/{dvb => pci}/mantis/Makefile         |    2 +-
+ drivers/media/{dvb => pci}/mantis/hopper_cards.c   |    0
+ drivers/media/{dvb => pci}/mantis/hopper_vp3028.c  |    0
+ drivers/media/{dvb => pci}/mantis/hopper_vp3028.h  |    0
+ drivers/media/{dvb => pci}/mantis/mantis_ca.c      |    0
+ drivers/media/{dvb => pci}/mantis/mantis_ca.h      |    0
+ drivers/media/{dvb => pci}/mantis/mantis_cards.c   |    2 +-
+ drivers/media/{dvb => pci}/mantis/mantis_common.h  |    0
+ drivers/media/{dvb => pci}/mantis/mantis_core.c    |    2 +-
+ drivers/media/{dvb => pci}/mantis/mantis_core.h    |    0
+ drivers/media/{dvb => pci}/mantis/mantis_dma.c     |    0
+ drivers/media/{dvb => pci}/mantis/mantis_dma.h     |    0
+ drivers/media/{dvb => pci}/mantis/mantis_dvb.c     |    6 +-
+ drivers/media/{dvb => pci}/mantis/mantis_dvb.h     |    0
+ drivers/media/{dvb => pci}/mantis/mantis_evm.c     |    0
+ drivers/media/{dvb => pci}/mantis/mantis_hif.c     |    0
+ drivers/media/{dvb => pci}/mantis/mantis_hif.h     |    0
+ drivers/media/{dvb => pci}/mantis/mantis_i2c.c     |    0
+ drivers/media/{dvb => pci}/mantis/mantis_i2c.h     |    0
+ drivers/media/{dvb => pci}/mantis/mantis_input.c   |    0
+ drivers/media/{dvb => pci}/mantis/mantis_ioc.c     |    0
+ drivers/media/{dvb => pci}/mantis/mantis_ioc.h     |    0
+ drivers/media/{dvb => pci}/mantis/mantis_link.h    |    0
+ drivers/media/{dvb => pci}/mantis/mantis_pci.c     |    0
+ drivers/media/{dvb => pci}/mantis/mantis_pci.h     |    0
+ drivers/media/{dvb => pci}/mantis/mantis_pcmcia.c  |    0
+ drivers/media/{dvb => pci}/mantis/mantis_reg.h     |    0
+ drivers/media/{dvb => pci}/mantis/mantis_uart.c    |    0
+ drivers/media/{dvb => pci}/mantis/mantis_uart.h    |    0
+ drivers/media/{dvb => pci}/mantis/mantis_vp1033.c  |    0
+ drivers/media/{dvb => pci}/mantis/mantis_vp1033.h  |    0
+ drivers/media/{dvb => pci}/mantis/mantis_vp1034.c  |    0
+ drivers/media/{dvb => pci}/mantis/mantis_vp1034.h  |    0
+ drivers/media/{dvb => pci}/mantis/mantis_vp1041.c  |    0
+ drivers/media/{dvb => pci}/mantis/mantis_vp1041.h  |    0
+ drivers/media/{dvb => pci}/mantis/mantis_vp2033.c  |    0
+ drivers/media/{dvb => pci}/mantis/mantis_vp2033.h  |    0
+ drivers/media/{dvb => pci}/mantis/mantis_vp2040.c  |    0
+ drivers/media/{dvb => pci}/mantis/mantis_vp2040.h  |    0
+ drivers/media/{dvb => pci}/mantis/mantis_vp3028.c  |    0
+ drivers/media/{dvb => pci}/mantis/mantis_vp3028.h  |    0
+ drivers/media/{dvb => pci}/mantis/mantis_vp3030.c  |    0
+ drivers/media/{dvb => pci}/mantis/mantis_vp3030.h  |    0
+ drivers/media/pci/meye/Kconfig                     |   13 +
+ drivers/media/pci/meye/Makefile                    |    1 +
+ drivers/media/{video => pci/meye}/meye.c           |    0
+ drivers/media/{video => pci/meye}/meye.h           |    0
+ drivers/media/{dvb => pci}/ngene/Kconfig           |    0
+ drivers/media/{dvb => pci}/ngene/Makefile          |    6 +-
+ drivers/media/{dvb => pci}/ngene/ngene-cards.c     |  263 ++
+ drivers/media/{dvb => pci}/ngene/ngene-core.c      |   14 +-
+ drivers/media/{dvb => pci}/ngene/ngene-dvb.c       |    0
+ drivers/media/{dvb => pci}/ngene/ngene-i2c.c       |    0
+ drivers/media/{dvb => pci}/ngene/ngene.h           |    0
+ drivers/media/{dvb => pci}/pluto2/Kconfig          |    0
+ drivers/media/pci/pluto2/Makefile                  |    3 +
+ drivers/media/{dvb => pci}/pluto2/pluto2.c         |    0
+ drivers/media/{dvb => pci}/pt1/Kconfig             |    0
+ drivers/media/{dvb => pci}/pt1/Makefile            |    2 +-
+ drivers/media/{dvb => pci}/pt1/pt1.c               |    0
+ drivers/media/{dvb => pci}/pt1/va1j5jf8007s.c      |    0
+ drivers/media/{dvb => pci}/pt1/va1j5jf8007s.h      |    0
+ drivers/media/{dvb => pci}/pt1/va1j5jf8007t.c      |    0
+ drivers/media/{dvb => pci}/pt1/va1j5jf8007t.h      |    0
+ drivers/media/{video => pci}/saa7134/Kconfig       |    0
+ drivers/media/{video => pci}/saa7134/Makefile      |   10 +-
+ drivers/media/{video => pci}/saa7134/saa6752hs.c   |    0
+ .../media/{video => pci}/saa7134/saa7134-alsa.c    |    0
+ .../media/{video => pci}/saa7134/saa7134-cards.c   |    0
+ .../media/{video => pci}/saa7134/saa7134-core.c    |    0
+ drivers/media/{video => pci}/saa7134/saa7134-dvb.c |    4 +-
+ .../media/{video => pci}/saa7134/saa7134-empress.c |    0
+ drivers/media/{video => pci}/saa7134/saa7134-i2c.c |    0
+ .../media/{video => pci}/saa7134/saa7134-input.c   |   10 +-
+ drivers/media/{video => pci}/saa7134/saa7134-reg.h |    0
+ drivers/media/{video => pci}/saa7134/saa7134-ts.c  |    0
+ .../media/{video => pci}/saa7134/saa7134-tvaudio.c |    0
+ drivers/media/{video => pci}/saa7134/saa7134-vbi.c |    0
+ .../media/{video => pci}/saa7134/saa7134-video.c   |    0
+ drivers/media/{video => pci}/saa7134/saa7134.h     |    1 -
+ drivers/media/pci/saa7146/Kconfig                  |   38 +
+ drivers/media/pci/saa7146/Makefile                 |    5 +
+ .../media/{video => pci/saa7146}/hexium_gemini.c   |    0
+ .../media/{video => pci/saa7146}/hexium_orion.c    |    0
+ drivers/media/{video => pci/saa7146}/mxb.c         |    0
+ drivers/media/{video => pci}/saa7164/Kconfig       |    0
+ drivers/media/{video => pci}/saa7164/Makefile      |    8 +-
+ drivers/media/{video => pci}/saa7164/saa7164-api.c |   15 +-
+ .../media/{video => pci}/saa7164/saa7164-buffer.c  |    0
+ drivers/media/{video => pci}/saa7164/saa7164-bus.c |    0
+ .../media/{video => pci}/saa7164/saa7164-cards.c   |    0
+ drivers/media/{video => pci}/saa7164/saa7164-cmd.c |    0
+ .../media/{video => pci}/saa7164/saa7164-core.c    |   46 +-
+ drivers/media/{video => pci}/saa7164/saa7164-dvb.c |    0
+ .../media/{video => pci}/saa7164/saa7164-encoder.c |    0
+ drivers/media/{video => pci}/saa7164/saa7164-fw.c  |    0
+ drivers/media/{video => pci}/saa7164/saa7164-i2c.c |    0
+ drivers/media/{video => pci}/saa7164/saa7164-reg.h |    0
+ .../media/{video => pci}/saa7164/saa7164-types.h   |    0
+ drivers/media/{video => pci}/saa7164/saa7164-vbi.c |    0
+ drivers/media/{video => pci}/saa7164/saa7164.h     |    1 -
+ drivers/media/pci/sta2x11/Kconfig                  |   12 +
+ drivers/media/pci/sta2x11/Makefile                 |    1 +
+ drivers/media/{video => pci/sta2x11}/sta2x11_vip.c |    0
+ drivers/media/{video => pci/sta2x11}/sta2x11_vip.h |    0
+ drivers/media/{dvb => pci}/ttpci/Kconfig           |    0
+ drivers/media/{dvb => pci}/ttpci/Makefile          |    4 +-
+ drivers/media/{dvb => pci}/ttpci/av7110.c          |    0
+ drivers/media/{dvb => pci}/ttpci/av7110.h          |    0
+ drivers/media/{dvb => pci}/ttpci/av7110_av.c       |    0
+ drivers/media/{dvb => pci}/ttpci/av7110_av.h       |    0
+ drivers/media/{dvb => pci}/ttpci/av7110_ca.c       |    0
+ drivers/media/{dvb => pci}/ttpci/av7110_ca.h       |    0
+ drivers/media/{dvb => pci}/ttpci/av7110_hw.c       |    0
+ drivers/media/{dvb => pci}/ttpci/av7110_hw.h       |    0
+ drivers/media/{dvb => pci}/ttpci/av7110_ipack.c    |    0
+ drivers/media/{dvb => pci}/ttpci/av7110_ipack.h    |    0
+ drivers/media/{dvb => pci}/ttpci/av7110_ir.c       |    0
+ drivers/media/{dvb => pci}/ttpci/av7110_v4l.c      |    0
+ drivers/media/{dvb => pci}/ttpci/budget-av.c       |    0
+ drivers/media/{dvb => pci}/ttpci/budget-ci.c       |    0
+ drivers/media/{dvb => pci}/ttpci/budget-core.c     |    0
+ drivers/media/{dvb => pci}/ttpci/budget-patch.c    |    0
+ drivers/media/{dvb => pci}/ttpci/budget.c          |   60 +
+ drivers/media/{dvb => pci}/ttpci/budget.h          |    0
+ drivers/media/{dvb => pci}/ttpci/ttpci-eeprom.c    |    0
+ drivers/media/{dvb => pci}/ttpci/ttpci-eeprom.h    |    0
+ drivers/media/{video => pci}/zoran/Kconfig         |    0
+ drivers/media/{video => pci}/zoran/Makefile        |    0
+ drivers/media/{video => pci}/zoran/videocodec.c    |    0
+ drivers/media/{video => pci}/zoran/videocodec.h    |    0
+ drivers/media/{video => pci}/zoran/zoran.h         |    0
+ drivers/media/{video => pci}/zoran/zoran_card.c    |    0
+ drivers/media/{video => pci}/zoran/zoran_card.h    |    0
+ drivers/media/{video => pci}/zoran/zoran_device.c  |    0
+ drivers/media/{video => pci}/zoran/zoran_device.h  |    0
+ drivers/media/{video => pci}/zoran/zoran_driver.c  |    0
+ drivers/media/{video => pci}/zoran/zoran_procfs.c  |    0
+ drivers/media/{video => pci}/zoran/zoran_procfs.h  |    0
+ drivers/media/{video => pci}/zoran/zr36016.c       |    0
+ drivers/media/{video => pci}/zoran/zr36016.h       |    0
+ drivers/media/{video => pci}/zoran/zr36050.c       |    0
+ drivers/media/{video => pci}/zoran/zr36050.h       |    0
+ drivers/media/{video => pci}/zoran/zr36057.h       |    0
+ drivers/media/{video => pci}/zoran/zr36060.c       |    0
+ drivers/media/{video => pci}/zoran/zr36060.h       |    0
+ drivers/media/platform/Kconfig                     |  297 ++
+ drivers/media/platform/Makefile                    |   66 +
+ drivers/media/{video => platform}/arv.c            |    0
+ drivers/media/{video => platform}/atmel-isi.c      |    0
+ drivers/media/{video => platform}/blackfin/Kconfig |    0
+ .../media/{video => platform}/blackfin/Makefile    |    0
+ .../{video => platform}/blackfin/bfin_capture.c    |   17 +-
+ drivers/media/{video => platform}/blackfin/ppi.c   |    0
+ drivers/media/platform/coda.c                      | 1849 +++++++++
+ drivers/media/platform/coda.h                      |  216 +
+ drivers/media/{video => platform}/davinci/Kconfig  |    0
+ drivers/media/{video => platform}/davinci/Makefile |    0
+ .../{video => platform}/davinci/ccdc_hw_device.h   |    0
+ .../media/{video => platform}/davinci/dm355_ccdc.c |    2 +-
+ .../{video => platform}/davinci/dm355_ccdc_regs.h  |    0
+ .../{video => platform}/davinci/dm644x_ccdc.c      |    2 +-
+ .../{video => platform}/davinci/dm644x_ccdc_regs.h |    0
+ drivers/media/{video => platform}/davinci/isif.c   |    2 +-
+ .../media/{video => platform}/davinci/isif_regs.h  |    0
+ drivers/media/{video => platform}/davinci/vpbe.c   |    0
+ .../{video => platform}/davinci/vpbe_display.c     |   22 +-
+ .../media/{video => platform}/davinci/vpbe_osd.c   |    0
+ .../{video => platform}/davinci/vpbe_osd_regs.h    |    0
+ .../media/{video => platform}/davinci/vpbe_venc.c  |    0
+ .../{video => platform}/davinci/vpbe_venc_regs.h   |    0
+ .../{video => platform}/davinci/vpfe_capture.c     |    2 +-
+ drivers/media/{video => platform}/davinci/vpif.c   |    2 +-
+ drivers/media/{video => platform}/davinci/vpif.h   |    0
+ .../{video => platform}/davinci/vpif_capture.c     |   28 +-
+ .../{video => platform}/davinci/vpif_capture.h     |    0
+ .../{video => platform}/davinci/vpif_display.c     |   34 +-
+ .../{video => platform}/davinci/vpif_display.h     |    0
+ drivers/media/{video => platform}/davinci/vpss.c   |    2 +-
+ drivers/media/{video => platform}/fsl-viu.c        |   27 +-
+ drivers/media/{video => platform}/indycam.c        |    0
+ drivers/media/{video => platform}/indycam.h        |    0
+ drivers/media/platform/m2m-deinterlace.c           | 1120 ++++++
+ .../media/{video => platform}/marvell-ccic/Kconfig |    0
+ .../{video => platform}/marvell-ccic/Makefile      |    0
+ .../{video => platform}/marvell-ccic/cafe-driver.c |    0
+ .../{video => platform}/marvell-ccic/mcam-core.c   |    0
+ .../{video => platform}/marvell-ccic/mcam-core.h   |    0
+ .../{video => platform}/marvell-ccic/mmp-driver.c  |    0
+ .../media/{video => platform}/mem2mem_testdev.c    |   38 +-
+ drivers/media/{video => platform}/mx1_camera.c     |    4 +-
+ drivers/media/{video => platform}/mx2_camera.c     |   87 +-
+ drivers/media/{video => platform}/mx2_emmaprp.c    |   76 +-
+ drivers/media/{video => platform}/mx3_camera.c     |   26 +-
+ drivers/media/{video => platform}/omap/Kconfig     |    0
+ drivers/media/{video => platform}/omap/Makefile    |    2 +-
+ drivers/media/{video => platform}/omap/omap_vout.c |    0
+ .../{video => platform}/omap/omap_vout_vrfb.c      |    0
+ .../{video => platform}/omap/omap_vout_vrfb.h      |    0
+ .../media/{video => platform}/omap/omap_voutdef.h  |    0
+ .../media/{video => platform}/omap/omap_voutlib.c  |    0
+ .../media/{video => platform}/omap/omap_voutlib.h  |    0
+ drivers/media/{video => platform}/omap1_camera.c   |    2 +-
+ .../media/{video => platform}/omap24xxcam-dma.c    |    2 +-
+ drivers/media/{video => platform}/omap24xxcam.c    |    2 +-
+ drivers/media/{video => platform}/omap24xxcam.h    |    2 +-
+ .../media/{video => platform}/omap3isp/Makefile    |    0
+ .../{video => platform}/omap3isp/cfa_coef_table.h  |   16 +-
+ .../{video => platform}/omap3isp/gamma_table.h     |    0
+ drivers/media/{video => platform}/omap3isp/isp.c   |   51 +-
+ drivers/media/{video => platform}/omap3isp/isp.h   |   11 +-
+ .../media/{video => platform}/omap3isp/ispccdc.c   |  234 +-
+ .../media/{video => platform}/omap3isp/ispccdc.h   |   37 -
+ .../media/{video => platform}/omap3isp/ispccp2.c   |    0
+ .../media/{video => platform}/omap3isp/ispccp2.h   |    0
+ .../media/{video => platform}/omap3isp/ispcsi2.c   |   27 +-
+ .../media/{video => platform}/omap3isp/ispcsi2.h   |    0
+ .../media/{video => platform}/omap3isp/ispcsiphy.c |    0
+ .../media/{video => platform}/omap3isp/ispcsiphy.h |    0
+ .../media/{video => platform}/omap3isp/isph3a.h    |    0
+ .../{video => platform}/omap3isp/isph3a_aewb.c     |   10 +-
+ .../media/{video => platform}/omap3isp/isph3a_af.c |   10 +-
+ .../media/{video => platform}/omap3isp/isphist.c   |    6 +-
+ .../media/{video => platform}/omap3isp/isphist.h   |    0
+ .../{video => platform}/omap3isp/isppreview.c      |  707 ++--
+ .../{video => platform}/omap3isp/isppreview.h      |    1 +
+ .../media/{video => platform}/omap3isp/ispqueue.c  |   15 +-
+ .../media/{video => platform}/omap3isp/ispqueue.h  |    0
+ .../media/{video => platform}/omap3isp/ispreg.h    |    0
+ .../{video => platform}/omap3isp/ispresizer.c      |    8 +-
+ .../{video => platform}/omap3isp/ispresizer.h      |    0
+ .../media/{video => platform}/omap3isp/ispstat.c   |    0
+ .../media/{video => platform}/omap3isp/ispstat.h   |    0
+ .../media/{video => platform}/omap3isp/ispvideo.c  |   57 +-
+ .../media/{video => platform}/omap3isp/ispvideo.h  |    6 +-
+ .../omap3isp/luma_enhance_table.h                  |    0
+ .../omap3isp/noise_filter_table.h                  |    0
+ drivers/media/{video => platform}/pxa_camera.c     |    0
+ drivers/media/{video => platform}/s5p-fimc/Kconfig |    0
+ .../media/{video => platform}/s5p-fimc/Makefile    |    0
+ .../{video => platform}/s5p-fimc/fimc-capture.c    |    0
+ .../media/{video => platform}/s5p-fimc/fimc-core.c |    0
+ .../media/{video => platform}/s5p-fimc/fimc-core.h |    0
+ .../{video => platform}/s5p-fimc/fimc-lite-reg.c   |    0
+ .../{video => platform}/s5p-fimc/fimc-lite-reg.h   |    0
+ .../media/{video => platform}/s5p-fimc/fimc-lite.c |    0
+ .../media/{video => platform}/s5p-fimc/fimc-lite.h |    0
+ .../media/{video => platform}/s5p-fimc/fimc-m2m.c  |    0
+ .../{video => platform}/s5p-fimc/fimc-mdevice.c    |    0
+ .../{video => platform}/s5p-fimc/fimc-mdevice.h    |    0
+ .../media/{video => platform}/s5p-fimc/fimc-reg.c  |    0
+ .../media/{video => platform}/s5p-fimc/fimc-reg.h  |    0
+ .../media/{video => platform}/s5p-fimc/mipi-csis.c |    0
+ .../media/{video => platform}/s5p-fimc/mipi-csis.h |    0
+ drivers/media/{video => platform}/s5p-g2d/Makefile |    0
+ drivers/media/{video => platform}/s5p-g2d/g2d-hw.c |    0
+ .../media/{video => platform}/s5p-g2d/g2d-regs.h   |    0
+ drivers/media/{video => platform}/s5p-g2d/g2d.c    |   27 +-
+ drivers/media/{video => platform}/s5p-g2d/g2d.h    |    0
+ .../media/{video => platform}/s5p-jpeg/Makefile    |    0
+ .../media/{video => platform}/s5p-jpeg/jpeg-core.c |   36 +-
+ .../media/{video => platform}/s5p-jpeg/jpeg-core.h |    2 +-
+ .../media/{video => platform}/s5p-jpeg/jpeg-hw.h   |    2 +-
+ .../media/{video => platform}/s5p-jpeg/jpeg-regs.h |    2 +-
+ drivers/media/{video => platform}/s5p-mfc/Makefile |    0
+ .../media/{video => platform}/s5p-mfc/regs-mfc.h   |    0
+ .../media/{video => platform}/s5p-mfc/s5p_mfc.c    |   19 +-
+ .../{video => platform}/s5p-mfc/s5p_mfc_cmd.c      |    2 +-
+ .../{video => platform}/s5p-mfc/s5p_mfc_cmd.h      |    2 +-
+ .../{video => platform}/s5p-mfc/s5p_mfc_common.h   |    0
+ .../{video => platform}/s5p-mfc/s5p_mfc_ctrl.c     |    2 +-
+ .../{video => platform}/s5p-mfc/s5p_mfc_ctrl.h     |    2 +-
+ .../{video => platform}/s5p-mfc/s5p_mfc_debug.h    |    2 +-
+ .../{video => platform}/s5p-mfc/s5p_mfc_dec.c      |    2 +-
+ .../{video => platform}/s5p-mfc/s5p_mfc_dec.h      |    2 +-
+ .../{video => platform}/s5p-mfc/s5p_mfc_enc.c      |    2 +-
+ .../{video => platform}/s5p-mfc/s5p_mfc_enc.h      |    2 +-
+ .../{video => platform}/s5p-mfc/s5p_mfc_intr.c     |    2 +-
+ .../{video => platform}/s5p-mfc/s5p_mfc_intr.h     |    2 +-
+ .../{video => platform}/s5p-mfc/s5p_mfc_opr.c      |    2 +-
+ .../{video => platform}/s5p-mfc/s5p_mfc_opr.h      |    2 +-
+ .../media/{video => platform}/s5p-mfc/s5p_mfc_pm.c |    2 +-
+ .../media/{video => platform}/s5p-mfc/s5p_mfc_pm.h |    2 +-
+ .../{video => platform}/s5p-mfc/s5p_mfc_shm.c      |    2 +-
+ .../{video => platform}/s5p-mfc/s5p_mfc_shm.h      |    2 +-
+ drivers/media/{video => platform}/s5p-tv/Kconfig   |    2 +-
+ drivers/media/{video => platform}/s5p-tv/Makefile  |    2 +-
+ .../media/{video => platform}/s5p-tv/hdmi_drv.c    |    6 +-
+ .../media/{video => platform}/s5p-tv/hdmiphy_drv.c |    0
+ drivers/media/{video => platform}/s5p-tv/mixer.h   |    0
+ .../media/{video => platform}/s5p-tv/mixer_drv.c   |    6 +-
+ .../{video => platform}/s5p-tv/mixer_grp_layer.c   |    0
+ .../media/{video => platform}/s5p-tv/mixer_reg.c   |    0
+ .../media/{video => platform}/s5p-tv/mixer_video.c |   33 +-
+ .../{video => platform}/s5p-tv/mixer_vp_layer.c    |    0
+ .../media/{video => platform}/s5p-tv/regs-hdmi.h   |    0
+ .../media/{video => platform}/s5p-tv/regs-mixer.h  |    0
+ .../media/{video => platform}/s5p-tv/regs-sdo.h    |    2 +-
+ drivers/media/{video => platform}/s5p-tv/regs-vp.h |    0
+ drivers/media/{video => platform}/s5p-tv/sdo_drv.c |   10 +-
+ .../media/{video => platform}/s5p-tv/sii9234_drv.c |   17 +-
+ .../{video => platform}/sh_mobile_ceu_camera.c     |    0
+ drivers/media/{video => platform}/sh_vou.c         |   25 +-
+ drivers/media/{video => platform}/soc_camera.c     |  200 +-
+ .../{video => platform}/soc_camera_platform.c      |   11 +-
+ drivers/media/{video => platform}/soc_mediabus.c   |    6 +
+ drivers/media/{video => platform}/timblogiw.c      |    0
+ drivers/media/{video => platform}/via-camera.c     |    0
+ drivers/media/{video => platform}/via-camera.h     |    0
+ drivers/media/{video => platform}/vino.c           |    0
+ drivers/media/{video => platform}/vino.h           |    0
+ drivers/media/{video => platform}/vivi.c           |   48 +-
+ drivers/media/radio/radio-shark.c                  |  151 +-
+ drivers/media/radio/radio-shark2.c                 |  150 +-
+ drivers/media/radio/radio-si4713.c                 |    7 +-
+ drivers/media/radio/radio-timb.c                   |    8 +-
+ drivers/media/radio/radio-wl1273.c                 |   23 +-
+ drivers/media/radio/si470x/radio-si470x-common.c   |    3 +
+ drivers/media/radio/si470x/radio-si470x-i2c.c      |    5 +-
+ drivers/media/radio/si470x/radio-si470x-usb.c      |    2 +-
+ drivers/media/radio/wl128x/fmdrv_v4l2.c            |   38 +-
+ drivers/media/rc/Kconfig                           |   32 +-
+ drivers/media/rc/Makefile                          |    2 +
+ drivers/media/rc/ati_remote.c                      |   11 +-
+ drivers/media/rc/fintek-cir.c                      |   11 +-
+ drivers/media/rc/iguanair.c                        |  220 +-
+ drivers/media/rc/ir-lirc-codec.c                   |   35 +-
+ drivers/media/rc/ir-nec-decoder.c                  |    4 +-
+ drivers/media/rc/ir-raw.c                          |    6 +-
+ drivers/media/rc/ir-rx51.c                         |  496 +++
+ drivers/media/rc/keymaps/rc-tt-1500.c              |    2 +-
+ drivers/media/rc/mceusb.c                          |   28 +-
+ drivers/media/rc/rc-loopback.c                     |   12 -
+ drivers/media/rc/ttusbir.c                         |  407 ++
+ drivers/media/{common => }/tuners/Kconfig          |    0
+ drivers/media/{common => }/tuners/Makefile         |    4 +-
+ drivers/media/{common => }/tuners/fc0011.c         |    0
+ drivers/media/{common => }/tuners/fc0011.h         |    0
+ drivers/media/{common => }/tuners/fc0012-priv.h    |    0
+ drivers/media/{common => }/tuners/fc0012.c         |    0
+ drivers/media/{common => }/tuners/fc0012.h         |    0
+ drivers/media/{common => }/tuners/fc0013-priv.h    |    0
+ drivers/media/{common => }/tuners/fc0013.c         |    0
+ drivers/media/{common => }/tuners/fc0013.h         |    0
+ drivers/media/{common => }/tuners/fc001x-common.h  |    0
+ drivers/media/{common => }/tuners/max2165.c        |    0
+ drivers/media/{common => }/tuners/max2165.h        |    0
+ drivers/media/{common => }/tuners/max2165_priv.h   |    0
+ drivers/media/{common => }/tuners/mc44s803.c       |    0
+ drivers/media/{common => }/tuners/mc44s803.h       |    0
+ drivers/media/{common => }/tuners/mc44s803_priv.h  |    0
+ drivers/media/{common => }/tuners/mt2060.c         |    0
+ drivers/media/{common => }/tuners/mt2060.h         |    0
+ drivers/media/{common => }/tuners/mt2060_priv.h    |    0
+ drivers/media/{common => }/tuners/mt2063.c         |    0
+ drivers/media/{common => }/tuners/mt2063.h         |    0
+ drivers/media/{common => }/tuners/mt20xx.c         |    0
+ drivers/media/{common => }/tuners/mt20xx.h         |    0
+ drivers/media/{common => }/tuners/mt2131.c         |    0
+ drivers/media/{common => }/tuners/mt2131.h         |    0
+ drivers/media/{common => }/tuners/mt2131_priv.h    |    0
+ drivers/media/{common => }/tuners/mt2266.c         |    0
+ drivers/media/{common => }/tuners/mt2266.h         |    0
+ drivers/media/{common => }/tuners/mxl5005s.c       |    0
+ drivers/media/{common => }/tuners/mxl5005s.h       |    0
+ drivers/media/{common => }/tuners/mxl5007t.c       |    0
+ drivers/media/{common => }/tuners/mxl5007t.h       |    0
+ drivers/media/{common => }/tuners/qt1010.c         |    2 +-
+ drivers/media/{common => }/tuners/qt1010.h         |    0
+ drivers/media/{common => }/tuners/qt1010_priv.h    |    0
+ drivers/media/{common => }/tuners/tda18212.c       |   37 +-
+ drivers/media/{common => }/tuners/tda18212.h       |    0
+ drivers/media/{common => }/tuners/tda18218.c       |    2 +-
+ drivers/media/{common => }/tuners/tda18218.h       |    0
+ drivers/media/{common => }/tuners/tda18218_priv.h  |    0
+ .../media/{common => }/tuners/tda18271-common.c    |    0
+ drivers/media/{common => }/tuners/tda18271-fe.c    |    0
+ drivers/media/{common => }/tuners/tda18271-maps.c  |    0
+ drivers/media/{common => }/tuners/tda18271-priv.h  |    0
+ drivers/media/{common => }/tuners/tda18271.h       |    0
+ drivers/media/{common => }/tuners/tda827x.c        |    0
+ drivers/media/{common => }/tuners/tda827x.h        |    0
+ drivers/media/{common => }/tuners/tda8290.c        |    0
+ drivers/media/{common => }/tuners/tda8290.h        |    0
+ drivers/media/{common => }/tuners/tda9887.c        |    0
+ drivers/media/{common => }/tuners/tda9887.h        |    0
+ drivers/media/{common => }/tuners/tea5761.c        |    0
+ drivers/media/{common => }/tuners/tea5761.h        |    0
+ drivers/media/{common => }/tuners/tea5767.c        |    0
+ drivers/media/{common => }/tuners/tea5767.h        |    0
+ drivers/media/{common => }/tuners/tua9001.c        |    0
+ drivers/media/{common => }/tuners/tua9001.h        |    0
+ drivers/media/{common => }/tuners/tua9001_priv.h   |    0
+ drivers/media/{common => }/tuners/tuner-i2c.h      |    0
+ drivers/media/{common => }/tuners/tuner-simple.c   |    0
+ drivers/media/{common => }/tuners/tuner-simple.h   |    0
+ drivers/media/{common => }/tuners/tuner-types.c    |    0
+ .../media/{common => }/tuners/tuner-xc2028-types.h |    0
+ drivers/media/{common => }/tuners/tuner-xc2028.c   |    7 +-
+ drivers/media/{common => }/tuners/tuner-xc2028.h   |    0
+ drivers/media/{common => }/tuners/xc4000.c         |    3 +-
+ drivers/media/{common => }/tuners/xc4000.h         |    0
+ drivers/media/{common => }/tuners/xc5000.c         |  161 +-
+ drivers/media/{common => }/tuners/xc5000.h         |    0
+ drivers/media/usb/Kconfig                          |   53 +
+ drivers/media/usb/Makefile                         |   22 +
+ drivers/media/{video => usb}/au0828/Kconfig        |    0
+ drivers/media/{video => usb}/au0828/Makefile       |    6 +-
+ drivers/media/{video => usb}/au0828/au0828-cards.c |    4 +-
+ drivers/media/{video => usb}/au0828/au0828-cards.h |    0
+ drivers/media/{video => usb}/au0828/au0828-core.c  |   59 +-
+ drivers/media/{video => usb}/au0828/au0828-dvb.c   |   54 +-
+ drivers/media/{video => usb}/au0828/au0828-i2c.c   |   21 +-
+ drivers/media/{video => usb}/au0828/au0828-reg.h   |    1 +
+ drivers/media/{video => usb}/au0828/au0828-vbi.c   |    0
+ drivers/media/{video => usb}/au0828/au0828-video.c |   76 +-
+ drivers/media/{video => usb}/au0828/au0828.h       |    2 +
+ drivers/media/usb/b2c2/Kconfig                     |    6 +
+ drivers/media/usb/b2c2/Makefile                    |    5 +
+ drivers/media/{dvb => usb}/b2c2/flexcop-usb.c      |    5 +-
+ drivers/media/{dvb => usb}/b2c2/flexcop-usb.h      |    0
+ drivers/media/{video => usb}/cpia2/Kconfig         |    0
+ drivers/media/{video => usb}/cpia2/Makefile        |    0
+ drivers/media/{video => usb}/cpia2/cpia2.h         |    0
+ drivers/media/{video => usb}/cpia2/cpia2_core.c    |    6 +-
+ .../media/{video => usb}/cpia2/cpia2_registers.h   |    0
+ drivers/media/{video => usb}/cpia2/cpia2_usb.c     |    0
+ drivers/media/{video => usb}/cpia2/cpia2_v4l.c     |   39 +-
+ drivers/media/{video => usb}/cx231xx/Kconfig       |    0
+ drivers/media/{video => usb}/cx231xx/Makefile      |   11 +-
+ drivers/media/{video => usb}/cx231xx/cx231xx-417.c |    2 +
+ .../media/{video => usb}/cx231xx/cx231xx-audio.c   |    0
+ .../media/{video => usb}/cx231xx/cx231xx-avcore.c  |    0
+ .../media/{video => usb}/cx231xx/cx231xx-cards.c   |    0
+ .../{video => usb}/cx231xx/cx231xx-conf-reg.h      |    0
+ .../media/{video => usb}/cx231xx/cx231xx-core.c    |    0
+ drivers/media/{video => usb}/cx231xx/cx231xx-dif.h |    0
+ drivers/media/{video => usb}/cx231xx/cx231xx-dvb.c |    0
+ drivers/media/{video => usb}/cx231xx/cx231xx-i2c.c |    0
+ .../media/{video => usb}/cx231xx/cx231xx-input.c   |    0
+ .../media/{video => usb}/cx231xx/cx231xx-pcb-cfg.c |    0
+ .../media/{video => usb}/cx231xx/cx231xx-pcb-cfg.h |    0
+ drivers/media/{video => usb}/cx231xx/cx231xx-reg.h |    0
+ drivers/media/{video => usb}/cx231xx/cx231xx-vbi.c |    0
+ drivers/media/{video => usb}/cx231xx/cx231xx-vbi.h |    0
+ .../media/{video => usb}/cx231xx/cx231xx-video.c   |   47 +-
+ drivers/media/{video => usb}/cx231xx/cx231xx.h     |    0
+ drivers/media/usb/dvb-usb-v2/Kconfig               |  146 +
+ drivers/media/usb/dvb-usb-v2/Makefile              |   49 +
+ drivers/media/usb/dvb-usb-v2/af9015.c              | 1435 +++++++
+ .../media/{dvb/dvb-usb => usb/dvb-usb-v2}/af9015.h |   68 +-
+ .../media/{dvb/dvb-usb => usb/dvb-usb-v2}/af9035.c |  735 ++--
+ .../media/{dvb/dvb-usb => usb/dvb-usb-v2}/af9035.h |    6 +-
+ .../media/{dvb/dvb-usb => usb/dvb-usb-v2}/anysee.c |  663 ++-
+ .../media/{dvb/dvb-usb => usb/dvb-usb-v2}/anysee.h |    9 +-
+ .../media/{dvb/dvb-usb => usb/dvb-usb-v2}/au6610.c |  116 +-
+ .../media/{dvb/dvb-usb => usb/dvb-usb-v2}/au6610.h |   13 +-
+ .../media/{dvb/dvb-usb => usb/dvb-usb-v2}/az6007.c |  410 +-
+ .../media/{dvb/dvb-usb => usb/dvb-usb-v2}/ce6230.c |  182 +-
+ .../media/{dvb/dvb-usb => usb/dvb-usb-v2}/ce6230.h |   36 +-
+ drivers/media/usb/dvb-usb-v2/cypress_firmware.c    |  125 +
+ drivers/media/usb/dvb-usb-v2/cypress_firmware.h    |   31 +
+ drivers/media/usb/dvb-usb-v2/dvb_usb.h             |  392 ++
+ drivers/media/usb/dvb-usb-v2/dvb_usb_common.h      |   35 +
+ drivers/media/usb/dvb-usb-v2/dvb_usb_core.c        | 1046 +++++
+ drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c         |   77 +
+ .../media/{dvb/dvb-usb => usb/dvb-usb-v2}/ec168.c  |  321 +-
+ .../media/{dvb/dvb-usb => usb/dvb-usb-v2}/ec168.h  |   26 +-
+ .../media/{dvb/dvb-usb => usb/dvb-usb-v2}/gl861.c  |  130 +-
+ .../media/{dvb/dvb-usb => usb/dvb-usb-v2}/gl861.h  |    5 +-
+ drivers/media/usb/dvb-usb-v2/it913x.c              |  799 ++++
+ .../{dvb/dvb-usb => usb/dvb-usb-v2}/lmedm04.c      |  586 ++-
+ .../{dvb/dvb-usb => usb/dvb-usb-v2}/lmedm04.h      |    0
+ .../dvb-usb => usb/dvb-usb-v2}/mxl111sf-demod.c    |    0
+ .../dvb-usb => usb/dvb-usb-v2}/mxl111sf-demod.h    |    0
+ .../dvb-usb => usb/dvb-usb-v2}/mxl111sf-gpio.c     |    0
+ .../dvb-usb => usb/dvb-usb-v2}/mxl111sf-gpio.h     |    0
+ .../{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf-i2c.c |    0
+ .../{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf-i2c.h |    0
+ .../{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf-phy.c |    0
+ .../{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf-phy.h |    0
+ .../{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf-reg.h |    0
+ .../dvb-usb => usb/dvb-usb-v2}/mxl111sf-tuner.c    |    2 +
+ .../dvb-usb => usb/dvb-usb-v2}/mxl111sf-tuner.h    |    0
+ drivers/media/usb/dvb-usb-v2/mxl111sf.c            | 1431 +++++++
+ .../{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf.h     |   22 +-
+ .../{dvb/dvb-usb => usb/dvb-usb-v2}/rtl28xxu.c     |  594 +--
+ .../{dvb/dvb-usb => usb/dvb-usb-v2}/rtl28xxu.h     |   26 +-
+ drivers/media/usb/dvb-usb-v2/usb_urb.c             |  357 ++
+ drivers/media/{dvb => usb}/dvb-usb/Kconfig         |  127 -
+ drivers/media/usb/dvb-usb/Makefile                 |   83 +
+ drivers/media/{dvb => usb}/dvb-usb/a800.c          |    0
+ drivers/media/{dvb => usb}/dvb-usb/af9005-fe.c     |    0
+ drivers/media/{dvb => usb}/dvb-usb/af9005-remote.c |    0
+ drivers/media/{dvb => usb}/dvb-usb/af9005-script.h |    0
+ drivers/media/{dvb => usb}/dvb-usb/af9005.c        |    0
+ drivers/media/{dvb => usb}/dvb-usb/af9005.h        |    0
+ drivers/media/{dvb => usb}/dvb-usb/az6027.c        |    0
+ drivers/media/{dvb => usb}/dvb-usb/az6027.h        |    0
+ .../media/{dvb => usb}/dvb-usb/cinergyT2-core.c    |    0
+ drivers/media/{dvb => usb}/dvb-usb/cinergyT2-fe.c  |    0
+ drivers/media/{dvb => usb}/dvb-usb/cinergyT2.h     |    0
+ drivers/media/{dvb => usb}/dvb-usb/cxusb.c         |    0
+ drivers/media/{dvb => usb}/dvb-usb/cxusb.h         |    0
+ drivers/media/{dvb => usb}/dvb-usb/dib0700.h       |    0
+ drivers/media/{dvb => usb}/dvb-usb/dib0700_core.c  |    6 +-
+ .../media/{dvb => usb}/dvb-usb/dib0700_devices.c   |    0
+ drivers/media/{dvb => usb}/dvb-usb/dib07x0.h       |    0
+ drivers/media/{dvb => usb}/dvb-usb/dibusb-common.c |    0
+ drivers/media/{dvb => usb}/dvb-usb/dibusb-mb.c     |    0
+ drivers/media/{dvb => usb}/dvb-usb/dibusb-mc.c     |    0
+ drivers/media/{dvb => usb}/dvb-usb/dibusb.h        |    0
+ drivers/media/{dvb => usb}/dvb-usb/digitv.c        |    0
+ drivers/media/{dvb => usb}/dvb-usb/digitv.h        |    0
+ drivers/media/{dvb => usb}/dvb-usb/dtt200u-fe.c    |    0
+ drivers/media/{dvb => usb}/dvb-usb/dtt200u.c       |    0
+ drivers/media/{dvb => usb}/dvb-usb/dtt200u.h       |    0
+ drivers/media/{dvb => usb}/dvb-usb/dtv5100.c       |    0
+ drivers/media/{dvb => usb}/dvb-usb/dtv5100.h       |    0
+ .../media/{dvb => usb}/dvb-usb/dvb-usb-common.h    |    0
+ drivers/media/{dvb => usb}/dvb-usb/dvb-usb-dvb.c   |    1 -
+ .../media/{dvb => usb}/dvb-usb/dvb-usb-firmware.c  |    0
+ drivers/media/{dvb => usb}/dvb-usb/dvb-usb-i2c.c   |    0
+ drivers/media/{dvb => usb}/dvb-usb/dvb-usb-init.c  |    0
+ .../media/{dvb => usb}/dvb-usb/dvb-usb-remote.c    |    0
+ drivers/media/{dvb => usb}/dvb-usb/dvb-usb-urb.c   |    0
+ drivers/media/{dvb => usb}/dvb-usb/dvb-usb.h       |    2 -
+ drivers/media/usb/dvb-usb/dvb_usb_dvb.c            |  403 ++
+ drivers/media/usb/dvb-usb/dvb_usb_remote.c         |  117 +
+ drivers/media/{dvb => usb}/dvb-usb/dw2102.c        |    0
+ drivers/media/{dvb => usb}/dvb-usb/dw2102.h        |    0
+ drivers/media/{dvb => usb}/dvb-usb/friio-fe.c      |    0
+ drivers/media/{dvb => usb}/dvb-usb/friio.c         |    0
+ drivers/media/{dvb => usb}/dvb-usb/friio.h         |    0
+ drivers/media/{dvb => usb}/dvb-usb/gp8psk-fe.c     |    0
+ drivers/media/{dvb => usb}/dvb-usb/gp8psk.c        |    0
+ drivers/media/{dvb => usb}/dvb-usb/gp8psk.h        |    0
+ drivers/media/{dvb => usb}/dvb-usb/m920x.c         |    0
+ drivers/media/{dvb => usb}/dvb-usb/m920x.h         |    0
+ drivers/media/{dvb => usb}/dvb-usb/nova-t-usb2.c   |    0
+ drivers/media/{dvb => usb}/dvb-usb/opera1.c        |    0
+ drivers/media/{dvb => usb}/dvb-usb/pctv452e.c      |    7 +-
+ .../media/{dvb => usb}/dvb-usb/technisat-usb2.c    |    0
+ drivers/media/{dvb => usb}/dvb-usb/ttusb2.c        |    0
+ drivers/media/{dvb => usb}/dvb-usb/ttusb2.h        |    0
+ drivers/media/{dvb => usb}/dvb-usb/umt-010.c       |    0
+ drivers/media/{dvb => usb}/dvb-usb/usb-urb.c       |    0
+ drivers/media/{dvb => usb}/dvb-usb/vp702x-fe.c     |    0
+ drivers/media/{dvb => usb}/dvb-usb/vp702x.c        |    0
+ drivers/media/{dvb => usb}/dvb-usb/vp702x.h        |    0
+ drivers/media/{dvb => usb}/dvb-usb/vp7045-fe.c     |    0
+ drivers/media/{dvb => usb}/dvb-usb/vp7045.c        |    0
+ drivers/media/{dvb => usb}/dvb-usb/vp7045.h        |    0
+ drivers/media/{video => usb}/em28xx/Kconfig        |    0
+ drivers/media/{video => usb}/em28xx/Makefile       |   10 +-
+ drivers/media/{video => usb}/em28xx/em28xx-audio.c |    1 -
+ drivers/media/{video => usb}/em28xx/em28xx-cards.c |    0
+ drivers/media/{video => usb}/em28xx/em28xx-core.c  |    4 -
+ drivers/media/{video => usb}/em28xx/em28xx-dvb.c   |    0
+ drivers/media/{video => usb}/em28xx/em28xx-i2c.c   |    0
+ drivers/media/{video => usb}/em28xx/em28xx-input.c |    0
+ drivers/media/{video => usb}/em28xx/em28xx-reg.h   |    0
+ drivers/media/{video => usb}/em28xx/em28xx-vbi.c   |    0
+ drivers/media/{video => usb}/em28xx/em28xx-video.c |   52 +-
+ drivers/media/{video => usb}/em28xx/em28xx.h       |    0
+ drivers/media/{video => usb}/gspca/Kconfig         |    6 +-
+ drivers/media/{video => usb}/gspca/Makefile        |    0
+ .../{video => usb}/gspca/autogain_functions.c      |    0
+ .../{video => usb}/gspca/autogain_functions.h      |    0
+ drivers/media/{video => usb}/gspca/benq.c          |    0
+ drivers/media/{video => usb}/gspca/conex.c         |    0
+ drivers/media/{video => usb}/gspca/cpia1.c         |    0
+ drivers/media/{video => usb}/gspca/etoms.c         |    0
+ drivers/media/{video => usb}/gspca/finepix.c       |    0
+ drivers/media/{video => usb}/gspca/gl860/Kconfig   |    0
+ drivers/media/{video => usb}/gspca/gl860/Makefile  |    2 +-
+ .../{video => usb}/gspca/gl860/gl860-mi1320.c      |    0
+ .../{video => usb}/gspca/gl860/gl860-mi2020.c      |    0
+ .../{video => usb}/gspca/gl860/gl860-ov2640.c      |    0
+ .../{video => usb}/gspca/gl860/gl860-ov9655.c      |    0
+ drivers/media/{video => usb}/gspca/gl860/gl860.c   |    0
+ drivers/media/{video => usb}/gspca/gl860/gl860.h   |    0
+ drivers/media/{video => usb}/gspca/gspca.c         |    0
+ drivers/media/{video => usb}/gspca/gspca.h         |    0
+ drivers/media/{video => usb}/gspca/jeilinj.c       |    0
+ drivers/media/{video => usb}/gspca/jl2005bcd.c     |    0
+ drivers/media/{video => usb}/gspca/jpeg.h          |    0
+ drivers/media/{video => usb}/gspca/kinect.c        |    0
+ drivers/media/{video => usb}/gspca/konica.c        |    0
+ drivers/media/{video => usb}/gspca/m5602/Kconfig   |    0
+ drivers/media/{video => usb}/gspca/m5602/Makefile  |    2 +-
+ .../{video => usb}/gspca/m5602/m5602_bridge.h      |    0
+ .../media/{video => usb}/gspca/m5602/m5602_core.c  |    0
+ .../{video => usb}/gspca/m5602/m5602_mt9m111.c     |    0
+ .../{video => usb}/gspca/m5602/m5602_mt9m111.h     |    0
+ .../{video => usb}/gspca/m5602/m5602_ov7660.c      |    0
+ .../{video => usb}/gspca/m5602/m5602_ov7660.h      |    0
+ .../{video => usb}/gspca/m5602/m5602_ov9650.c      |    0
+ .../{video => usb}/gspca/m5602/m5602_ov9650.h      |    0
+ .../{video => usb}/gspca/m5602/m5602_po1030.c      |    0
+ .../{video => usb}/gspca/m5602/m5602_po1030.h      |    0
+ .../{video => usb}/gspca/m5602/m5602_s5k4aa.c      |    0
+ .../{video => usb}/gspca/m5602/m5602_s5k4aa.h      |    0
+ .../{video => usb}/gspca/m5602/m5602_s5k83a.c      |    0
+ .../{video => usb}/gspca/m5602/m5602_s5k83a.h      |    0
+ .../{video => usb}/gspca/m5602/m5602_sensor.h      |    0
+ drivers/media/{video => usb}/gspca/mars.c          |    0
+ drivers/media/{video => usb}/gspca/mr97310a.c      |    0
+ drivers/media/{video => usb}/gspca/nw80x.c         |    0
+ drivers/media/{video => usb}/gspca/ov519.c         |    0
+ drivers/media/{video => usb}/gspca/ov534.c         |    0
+ drivers/media/{video => usb}/gspca/ov534_9.c       |    0
+ drivers/media/{video => usb}/gspca/pac207.c        |    0
+ drivers/media/{video => usb}/gspca/pac7302.c       |    0
+ drivers/media/{video => usb}/gspca/pac7311.c       |    0
+ drivers/media/{video => usb}/gspca/pac_common.h    |    0
+ drivers/media/{video => usb}/gspca/se401.c         |    0
+ drivers/media/{video => usb}/gspca/se401.h         |    0
+ drivers/media/{video => usb}/gspca/sn9c2028.c      |    0
+ drivers/media/{video => usb}/gspca/sn9c2028.h      |    0
+ drivers/media/{video => usb}/gspca/sn9c20x.c       |    0
+ drivers/media/{video => usb}/gspca/sonixb.c        |    0
+ drivers/media/{video => usb}/gspca/sonixj.c        |    0
+ drivers/media/{video => usb}/gspca/spca1528.c      |    0
+ drivers/media/{video => usb}/gspca/spca500.c       |    0
+ drivers/media/{video => usb}/gspca/spca501.c       |    0
+ drivers/media/{video => usb}/gspca/spca505.c       |    0
+ drivers/media/{video => usb}/gspca/spca506.c       |    0
+ drivers/media/{video => usb}/gspca/spca508.c       |    0
+ drivers/media/{video => usb}/gspca/spca561.c       |    0
+ drivers/media/{video => usb}/gspca/sq905.c         |    0
+ drivers/media/{video => usb}/gspca/sq905c.c        |    7 +-
+ drivers/media/{video => usb}/gspca/sq930x.c        |   10 +-
+ drivers/media/{video => usb}/gspca/stk014.c        |    0
+ drivers/media/{video => usb}/gspca/stv0680.c       |    0
+ drivers/media/{video => usb}/gspca/stv06xx/Kconfig |    0
+ .../media/{video => usb}/gspca/stv06xx/Makefile    |    2 +-
+ .../media/{video => usb}/gspca/stv06xx/stv06xx.c   |    0
+ .../media/{video => usb}/gspca/stv06xx/stv06xx.h   |    0
+ .../{video => usb}/gspca/stv06xx/stv06xx_hdcs.c    |    0
+ .../{video => usb}/gspca/stv06xx/stv06xx_hdcs.h    |    0
+ .../{video => usb}/gspca/stv06xx/stv06xx_pb0100.c  |    0
+ .../{video => usb}/gspca/stv06xx/stv06xx_pb0100.h  |    0
+ .../{video => usb}/gspca/stv06xx/stv06xx_sensor.h  |    0
+ .../{video => usb}/gspca/stv06xx/stv06xx_st6422.c  |    0
+ .../{video => usb}/gspca/stv06xx/stv06xx_st6422.h  |    0
+ .../{video => usb}/gspca/stv06xx/stv06xx_vv6410.c  |    0
+ .../{video => usb}/gspca/stv06xx/stv06xx_vv6410.h  |    0
+ drivers/media/{video => usb}/gspca/sunplus.c       |    0
+ drivers/media/{video => usb}/gspca/t613.c          |    0
+ drivers/media/{video => usb}/gspca/topro.c         |    0
+ drivers/media/{video => usb}/gspca/tv8532.c        |    0
+ drivers/media/{video => usb}/gspca/vc032x.c        |    7 +-
+ drivers/media/{video => usb}/gspca/vicam.c         |    0
+ drivers/media/{video => usb}/gspca/w996Xcf.c       |    0
+ drivers/media/{video => usb}/gspca/xirlink_cit.c   |    0
+ drivers/media/{video => usb}/gspca/zc3xx-reg.h     |    0
+ drivers/media/{video => usb}/gspca/zc3xx.c         |    0
+ drivers/media/{video => usb}/hdpvr/Kconfig         |    0
+ drivers/media/{video => usb}/hdpvr/Makefile        |    2 +-
+ drivers/media/{video => usb}/hdpvr/hdpvr-control.c |    0
+ drivers/media/{video => usb}/hdpvr/hdpvr-core.c    |    0
+ drivers/media/{video => usb}/hdpvr/hdpvr-i2c.c     |    0
+ drivers/media/{video => usb}/hdpvr/hdpvr-video.c   |    0
+ drivers/media/{video => usb}/hdpvr/hdpvr.h         |    0
+ drivers/media/{video => usb}/pvrusb2/Kconfig       |    0
+ drivers/media/{video => usb}/pvrusb2/Makefile      |    8 +-
+ .../media/{video => usb}/pvrusb2/pvrusb2-audio.c   |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-audio.h   |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-context.c |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-context.h |    0
+ .../{video => usb}/pvrusb2/pvrusb2-cs53l32a.c      |    0
+ .../{video => usb}/pvrusb2/pvrusb2-cs53l32a.h      |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-ctrl.c    |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-ctrl.h    |    0
+ .../{video => usb}/pvrusb2/pvrusb2-cx2584x-v4l.c   |    0
+ .../{video => usb}/pvrusb2/pvrusb2-cx2584x-v4l.h   |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-debug.h   |    0
+ .../{video => usb}/pvrusb2/pvrusb2-debugifc.c      |    0
+ .../{video => usb}/pvrusb2/pvrusb2-debugifc.h      |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-devattr.c |   17 +-
+ .../media/{video => usb}/pvrusb2/pvrusb2-devattr.h |    0
+ drivers/media/{video => usb}/pvrusb2/pvrusb2-dvb.c |    0
+ drivers/media/{video => usb}/pvrusb2/pvrusb2-dvb.h |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-eeprom.c  |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-eeprom.h  |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-encoder.c |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-encoder.h |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-fx2-cmd.h |    0
+ .../{video => usb}/pvrusb2/pvrusb2-hdw-internal.h  |    0
+ drivers/media/{video => usb}/pvrusb2/pvrusb2-hdw.c |    0
+ drivers/media/{video => usb}/pvrusb2/pvrusb2-hdw.h |    0
+ .../{video => usb}/pvrusb2/pvrusb2-i2c-core.c      |    0
+ .../{video => usb}/pvrusb2/pvrusb2-i2c-core.h      |    0
+ drivers/media/{video => usb}/pvrusb2/pvrusb2-io.c  |    0
+ drivers/media/{video => usb}/pvrusb2/pvrusb2-io.h  |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-ioread.c  |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-ioread.h  |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-main.c    |    0
+ drivers/media/{video => usb}/pvrusb2/pvrusb2-std.c |    0
+ drivers/media/{video => usb}/pvrusb2/pvrusb2-std.h |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-sysfs.c   |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-sysfs.h   |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-util.h    |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-v4l2.c    |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-v4l2.h    |    0
+ .../{video => usb}/pvrusb2/pvrusb2-video-v4l.c     |    0
+ .../{video => usb}/pvrusb2/pvrusb2-video-v4l.h     |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-wm8775.c  |    0
+ .../media/{video => usb}/pvrusb2/pvrusb2-wm8775.h  |    0
+ drivers/media/{video => usb}/pvrusb2/pvrusb2.h     |    0
+ drivers/media/{video => usb}/pwc/Kconfig           |    0
+ drivers/media/{video => usb}/pwc/Makefile          |    2 +-
+ drivers/media/{video => usb}/pwc/philips.txt       |    0
+ drivers/media/{video => usb}/pwc/pwc-ctrl.c        |    0
+ drivers/media/{video => usb}/pwc/pwc-dec1.c        |    0
+ drivers/media/{video => usb}/pwc/pwc-dec1.h        |    0
+ drivers/media/{video => usb}/pwc/pwc-dec23.c       |    0
+ drivers/media/{video => usb}/pwc/pwc-dec23.h       |    0
+ drivers/media/{video => usb}/pwc/pwc-if.c          |    0
+ drivers/media/{video => usb}/pwc/pwc-kiara.c       |    0
+ drivers/media/{video => usb}/pwc/pwc-kiara.h       |    0
+ drivers/media/{video => usb}/pwc/pwc-misc.c        |    0
+ drivers/media/{video => usb}/pwc/pwc-nala.h        |    0
+ drivers/media/{video => usb}/pwc/pwc-timon.c       |    0
+ drivers/media/{video => usb}/pwc/pwc-timon.h       |    0
+ drivers/media/{video => usb}/pwc/pwc-uncompress.c  |    0
+ drivers/media/{video => usb}/pwc/pwc-v4l.c         |    0
+ drivers/media/{video => usb}/pwc/pwc.h             |    0
+ drivers/media/usb/s2255/Kconfig                    |    9 +
+ drivers/media/usb/s2255/Makefile                   |    2 +
+ drivers/media/{video => usb/s2255}/s2255drv.c      |   43 +-
+ drivers/media/usb/siano/Kconfig                    |   10 +
+ drivers/media/usb/siano/Makefile                   |    6 +
+ drivers/media/{dvb => usb}/siano/smsusb.c          |    0
+ drivers/media/{video => usb}/sn9c102/Kconfig       |    0
+ drivers/media/{video => usb}/sn9c102/Makefile      |    0
+ drivers/media/{video => usb}/sn9c102/sn9c102.h     |    0
+ .../media/{video => usb}/sn9c102/sn9c102_config.h  |    0
+ .../media/{video => usb}/sn9c102/sn9c102_core.c    |    0
+ .../{video => usb}/sn9c102/sn9c102_devtable.h      |    0
+ .../media/{video => usb}/sn9c102/sn9c102_hv7131d.c |    0
+ .../media/{video => usb}/sn9c102/sn9c102_hv7131r.c |    0
+ .../media/{video => usb}/sn9c102/sn9c102_mi0343.c  |    0
+ .../media/{video => usb}/sn9c102/sn9c102_mi0360.c  |    0
+ .../media/{video => usb}/sn9c102/sn9c102_mt9v111.c |    0
+ .../media/{video => usb}/sn9c102/sn9c102_ov7630.c  |    0
+ .../media/{video => usb}/sn9c102/sn9c102_ov7660.c  |    0
+ .../media/{video => usb}/sn9c102/sn9c102_pas106b.c |    0
+ .../{video => usb}/sn9c102/sn9c102_pas202bcb.c     |    0
+ .../media/{video => usb}/sn9c102/sn9c102_sensor.h  |    0
+ .../{video => usb}/sn9c102/sn9c102_tas5110c1b.c    |    0
+ .../{video => usb}/sn9c102/sn9c102_tas5110d.c      |    0
+ .../{video => usb}/sn9c102/sn9c102_tas5130d1b.c    |    0
+ drivers/media/usb/stk1160/Kconfig                  |   20 +
+ drivers/media/usb/stk1160/Makefile                 |   11 +
+ drivers/media/usb/stk1160/stk1160-ac97.c           |  152 +
+ drivers/media/usb/stk1160/stk1160-core.c           |  432 ++
+ drivers/media/usb/stk1160/stk1160-i2c.c            |  294 ++
+ drivers/media/usb/stk1160/stk1160-reg.h            |   93 +
+ drivers/media/usb/stk1160/stk1160-v4l.c            |  740 ++++
+ drivers/media/usb/stk1160/stk1160-video.c          |  518 +++
+ drivers/media/usb/stk1160/stk1160.h                |  208 +
+ drivers/media/usb/stkwebcam/Kconfig                |   13 +
+ drivers/media/usb/stkwebcam/Makefile               |    4 +
+ .../media/{video => usb/stkwebcam}/stk-sensor.c    |    0
+ .../media/{video => usb/stkwebcam}/stk-webcam.c    |    0
+ .../media/{video => usb/stkwebcam}/stk-webcam.h    |    0
+ drivers/media/{video => usb}/tlg2300/Kconfig       |    0
+ drivers/media/usb/tlg2300/Makefile                 |    9 +
+ drivers/media/{video => usb}/tlg2300/pd-alsa.c     |    0
+ drivers/media/{video => usb}/tlg2300/pd-common.h   |    0
+ drivers/media/{video => usb}/tlg2300/pd-dvb.c      |    0
+ drivers/media/{video => usb}/tlg2300/pd-main.c     |    0
+ drivers/media/{video => usb}/tlg2300/pd-radio.c    |    0
+ drivers/media/{video => usb}/tlg2300/pd-video.c    |    0
+ drivers/media/{video => usb}/tlg2300/vendorcmds.h  |    0
+ drivers/media/{video => usb}/tm6000/Kconfig        |    0
+ drivers/media/{video => usb}/tm6000/Makefile       |    8 +-
+ drivers/media/{video => usb}/tm6000/tm6000-alsa.c  |    3 +-
+ drivers/media/{video => usb}/tm6000/tm6000-cards.c |    0
+ drivers/media/{video => usb}/tm6000/tm6000-core.c  |    0
+ drivers/media/{video => usb}/tm6000/tm6000-dvb.c   |    0
+ drivers/media/{video => usb}/tm6000/tm6000-i2c.c   |    0
+ drivers/media/{video => usb}/tm6000/tm6000-input.c |    3 +-
+ drivers/media/{video => usb}/tm6000/tm6000-regs.h  |    0
+ drivers/media/{video => usb}/tm6000/tm6000-stds.c  |    0
+ .../media/{video => usb}/tm6000/tm6000-usb-isoc.h  |    0
+ drivers/media/{video => usb}/tm6000/tm6000-video.c |   52 +-
+ drivers/media/{video => usb}/tm6000/tm6000.h       |    0
+ drivers/media/{dvb => usb}/ttusb-budget/Kconfig    |    0
+ drivers/media/usb/ttusb-budget/Makefile            |    3 +
+ .../{dvb => usb}/ttusb-budget/dvb-ttusb-budget.c   |    0
+ drivers/media/{dvb => usb}/ttusb-dec/Kconfig       |    0
+ drivers/media/{dvb => usb}/ttusb-dec/Makefile      |    2 +-
+ drivers/media/{dvb => usb}/ttusb-dec/ttusb_dec.c   |    0
+ drivers/media/{dvb => usb}/ttusb-dec/ttusbdecfe.c  |    0
+ drivers/media/{dvb => usb}/ttusb-dec/ttusbdecfe.h  |    0
+ drivers/media/{video => usb}/usbvision/Kconfig     |    0
+ drivers/media/{video => usb}/usbvision/Makefile    |    4 +-
+ .../{video => usb}/usbvision/usbvision-cards.c     |    0
+ .../{video => usb}/usbvision/usbvision-cards.h     |    0
+ .../{video => usb}/usbvision/usbvision-core.c      |    0
+ .../media/{video => usb}/usbvision/usbvision-i2c.c |    0
+ .../{video => usb}/usbvision/usbvision-video.c     |   42 +-
+ drivers/media/{video => usb}/usbvision/usbvision.h |    0
+ drivers/media/{video => usb}/uvc/Kconfig           |    0
+ drivers/media/{video => usb}/uvc/Makefile          |    0
+ drivers/media/{video => usb}/uvc/uvc_ctrl.c        |    0
+ drivers/media/{video => usb}/uvc/uvc_debugfs.c     |    0
+ drivers/media/{video => usb}/uvc/uvc_driver.c      |   28 +-
+ drivers/media/{video => usb}/uvc/uvc_entity.c      |    0
+ drivers/media/{video => usb}/uvc/uvc_isight.c      |    0
+ drivers/media/{video => usb}/uvc/uvc_queue.c       |    1 +
+ drivers/media/{video => usb}/uvc/uvc_status.c      |    0
+ drivers/media/{video => usb}/uvc/uvc_v4l2.c        |    0
+ drivers/media/{video => usb}/uvc/uvc_video.c       |   30 +-
+ drivers/media/{video => usb}/uvc/uvcvideo.h        |    9 +
+ drivers/media/usb/zr364xx/Kconfig                  |   14 +
+ drivers/media/usb/zr364xx/Makefile                 |    2 +
+ drivers/media/{video => usb/zr364xx}/zr364xx.c     |    0
+ drivers/media/v4l2-core/Kconfig                    |   76 +
+ drivers/media/v4l2-core/Makefile                   |   35 +
+ drivers/media/{video => v4l2-core}/tuner-core.c    |    0
+ drivers/media/{video => v4l2-core}/v4l2-common.c   |    2 +-
+ .../{video => v4l2-core}/v4l2-compat-ioctl32.c     |    0
+ drivers/media/{video => v4l2-core}/v4l2-ctrls.c    |    0
+ drivers/media/{video => v4l2-core}/v4l2-dev.c      |   51 +-
+ drivers/media/{video => v4l2-core}/v4l2-device.c   |    0
+ drivers/media/{video => v4l2-core}/v4l2-event.c    |    0
+ drivers/media/{video => v4l2-core}/v4l2-fh.c       |    0
+ .../media/{video => v4l2-core}/v4l2-int-device.c   |    0
+ drivers/media/{video => v4l2-core}/v4l2-ioctl.c    |   10 +-
+ drivers/media/{video => v4l2-core}/v4l2-mem2mem.c  |    0
+ drivers/media/{video => v4l2-core}/v4l2-subdev.c   |    0
+ drivers/media/{video => v4l2-core}/videobuf-core.c |    0
+ .../{video => v4l2-core}/videobuf-dma-contig.c     |    0
+ .../media/{video => v4l2-core}/videobuf-dma-sg.c   |    0
+ drivers/media/{video => v4l2-core}/videobuf-dvb.c  |   11 +-
+ .../media/{video => v4l2-core}/videobuf-vmalloc.c  |    0
+ .../media/{video => v4l2-core}/videobuf2-core.c    |   21 +-
+ .../{video => v4l2-core}/videobuf2-dma-contig.c    |    0
+ .../media/{video => v4l2-core}/videobuf2-dma-sg.c  |    0
+ .../media/{video => v4l2-core}/videobuf2-memops.c  |    0
+ .../media/{video => v4l2-core}/videobuf2-vmalloc.c |    1 +
+ drivers/media/video/Kconfig                        | 1263 ------
+ drivers/media/video/Makefile                       |  218 -
+ drivers/media/video/bt8xx/Kconfig                  |   27 -
+ drivers/media/video/bt8xx/Makefile                 |   13 -
+ drivers/media/video/tlg2300/Makefile               |    9 -
+ drivers/staging/media/Kconfig                      |    2 -
+ drivers/staging/media/Makefile                     |    1 -
+ drivers/staging/media/as102/Makefile               |    2 +-
+ drivers/staging/media/cxd2099/Makefile             |    6 +-
+ drivers/staging/media/cxd2099/cxd2099.c            |   13 +-
+ drivers/staging/media/dt3155v4l/dt3155v4l.c        |   29 +-
+ drivers/staging/media/easycap/Kconfig              |   30 -
+ drivers/staging/media/easycap/Makefile             |   10 -
+ drivers/staging/media/easycap/README               |  141 -
+ drivers/staging/media/easycap/easycap.h            |  567 ---
+ drivers/staging/media/easycap/easycap_ioctl.c      | 2443 -----------
+ drivers/staging/media/easycap/easycap_low.c        |  968 -----
+ drivers/staging/media/easycap/easycap_main.c       | 4239 --------------------
+ drivers/staging/media/easycap/easycap_settings.c   |  696 ----
+ drivers/staging/media/easycap/easycap_sound.c      |  750 ----
+ drivers/staging/media/easycap/easycap_testcard.c   |  155 -
+ drivers/staging/media/go7007/Makefile              |    6 +-
+ drivers/staging/media/lirc/Kconfig                 |    6 -
+ drivers/staging/media/lirc/Makefile                |    1 -
+ drivers/staging/media/lirc/lirc_ene0100.h          |  169 -
+ drivers/staging/media/lirc/lirc_igorplugusb.c      |    4 +-
+ drivers/staging/media/lirc/lirc_ttusbir.c          |  376 --
+ drivers/staging/media/lirc/lirc_zilog.c            |    3 +-
+ include/linux/dvb/frontend.h                       |   51 +-
+ include/linux/dvb/version.h                        |    2 +-
+ include/linux/omap3isp.h                           |    6 +-
+ include/linux/v4l2-common.h                        |    8 +-
+ include/media/ir-rx51.h                            |   10 +
+ include/media/omap3isp.h                           |   14 +-
+ include/media/saa7146.h                            |    4 -
+ include/media/soc_camera.h                         |   12 +
+ include/media/v4l2-common.h                        |    4 +-
+ include/media/v4l2-dev.h                           |    3 -
+ include/media/v4l2-subdev.h                        |    2 +-
+ include/media/videobuf-dvb.h                       |    4 +-
+ 1572 files changed, 21886 insertions(+), 22321 deletions(-)
+ create mode 100644 arch/arm/plat-mxc/devices/platform-imx27-coda.c
+ rename drivers/media/{dvb => common}/b2c2/Kconfig (64%)
+ create mode 100644 drivers/media/common/b2c2/Makefile
+ rename drivers/media/{dvb => common}/b2c2/flexcop-common.h (100%)
+ rename drivers/media/{dvb => common}/b2c2/flexcop-eeprom.c (100%)
+ rename drivers/media/{dvb => common}/b2c2/flexcop-fe-tuner.c (100%)
+ rename drivers/media/{dvb => common}/b2c2/flexcop-hw-filter.c (100%)
+ rename drivers/media/{dvb => common}/b2c2/flexcop-i2c.c (100%)
+ rename drivers/media/{dvb => common}/b2c2/flexcop-misc.c (100%)
+ rename drivers/media/{dvb => common}/b2c2/flexcop-reg.h (100%)
+ rename drivers/media/{dvb => common}/b2c2/flexcop-sram.c (100%)
+ rename drivers/media/{dvb => common}/b2c2/flexcop.c (99%)
+ rename drivers/media/{dvb => common}/b2c2/flexcop.h (100%)
+ rename drivers/media/{dvb => common}/b2c2/flexcop_ibi_value_be.h (100%)
+ rename drivers/media/{dvb => common}/b2c2/flexcop_ibi_value_le.h (100%)
+ create mode 100644 drivers/media/common/saa7146/Kconfig
+ create mode 100644 drivers/media/common/saa7146/Makefile
+ rename drivers/media/common/{ => saa7146}/saa7146_core.c (98%)
+ rename drivers/media/common/{ => saa7146}/saa7146_fops.c (94%)
+ rename drivers/media/common/{ => saa7146}/saa7146_hlp.c (100%)
+ rename drivers/media/common/{ => saa7146}/saa7146_i2c.c (100%)
+ rename drivers/media/common/{ => saa7146}/saa7146_vbi.c (100%)
+ rename drivers/media/common/{ => saa7146}/saa7146_video.c (100%)
+ create mode 100644 drivers/media/common/siano/Kconfig
+ rename drivers/media/{dvb => common}/siano/Makefile (57%)
+ rename drivers/media/{dvb => common}/siano/sms-cards.c (100%)
+ rename drivers/media/{dvb => common}/siano/sms-cards.h (100%)
+ rename drivers/media/{dvb => common}/siano/smscoreapi.c (100%)
+ rename drivers/media/{dvb => common}/siano/smscoreapi.h (100%)
+ rename drivers/media/{dvb => common}/siano/smsdvb.c (100%)
+ rename drivers/media/{dvb => common}/siano/smsendian.c (100%)
+ rename drivers/media/{dvb => common}/siano/smsendian.h (100%)
+ rename drivers/media/{dvb => common}/siano/smsir.c (100%)
+ rename drivers/media/{dvb => common}/siano/smsir.h (100%)
+ create mode 100644 drivers/media/dvb-core/Kconfig
+ rename drivers/media/{dvb => }/dvb-core/Makefile (100%)
+ rename drivers/media/{dvb => }/dvb-core/demux.h (100%)
+ rename drivers/media/{dvb => }/dvb-core/dmxdev.c (99%)
+ rename drivers/media/{dvb => }/dvb-core/dmxdev.h (100%)
+ rename drivers/media/{dvb/dvb-usb => dvb-core}/dvb-usb-ids.h (100%)
+ rename drivers/media/{dvb => }/dvb-core/dvb_ca_en50221.c (100%)
+ rename drivers/media/{dvb => }/dvb-core/dvb_ca_en50221.h (100%)
+ rename drivers/media/{dvb => }/dvb-core/dvb_demux.c (98%)
+ rename drivers/media/{dvb => }/dvb-core/dvb_demux.h (100%)
+ rename drivers/media/{dvb => }/dvb-core/dvb_filter.c (100%)
+ rename drivers/media/{dvb => }/dvb-core/dvb_filter.h (100%)
+ rename drivers/media/{dvb => }/dvb-core/dvb_frontend.c (98%)
+ rename drivers/media/{dvb => }/dvb-core/dvb_frontend.h (98%)
+ rename drivers/media/{dvb => }/dvb-core/dvb_math.c (100%)
+ rename drivers/media/{dvb => }/dvb-core/dvb_math.h (100%)
+ rename drivers/media/{dvb => }/dvb-core/dvb_net.c (100%)
+ rename drivers/media/{dvb => }/dvb-core/dvb_net.h (100%)
+ rename drivers/media/{dvb => }/dvb-core/dvb_ringbuffer.c (100%)
+ rename drivers/media/{dvb => }/dvb-core/dvb_ringbuffer.h (100%)
+ rename drivers/media/{dvb => }/dvb-core/dvbdev.c (100%)
+ rename drivers/media/{dvb => }/dvb-core/dvbdev.h (80%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/Kconfig (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/Makefile (92%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/a8293.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/a8293.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/af9013.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/af9013.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/af9013_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/af9033.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/af9033.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/af9033_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/atbm8830.c (99%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/atbm8830.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/atbm8830_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/au8522.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/au8522_common.c (93%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/au8522_decoder.c (98%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/au8522_dig.c (95%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/au8522_priv.h (93%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/bcm3510.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/bcm3510.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/bcm3510_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/bsbe1-d01a.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/bsbe1.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/bsru6.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cx22700.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cx22700.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cx22702.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cx22702.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cx24110.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cx24110.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cx24113.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cx24113.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cx24116.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cx24116.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cx24123.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cx24123.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cxd2820r.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cxd2820r_c.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cxd2820r_core.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cxd2820r_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cxd2820r_t.c (99%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/cxd2820r_t2.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dib0070.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dib0070.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dib0090.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dib0090.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dib3000.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dib3000mb.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dib3000mb_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dib3000mc.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dib3000mc.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dib7000m.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dib7000m.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dib7000p.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dib7000p.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dib8000.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dib8000.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dib9000.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dib9000.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dibx000_common.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dibx000_common.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/drxd.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/drxd_firm.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/drxd_firm.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/drxd_hard.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/drxd_map_firm.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/drxk.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/drxk_hard.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/drxk_hard.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/drxk_map.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/ds3000.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/ds3000.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dvb-pll.c (96%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dvb-pll.h (97%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dvb_dummy_fe.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/dvb_dummy_fe.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/ec100.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/ec100.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/ec100_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/eds1547.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/hd29l2.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/hd29l2.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/hd29l2_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/isl6405.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/isl6405.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/isl6421.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/isl6421.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/isl6423.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/isl6423.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/it913x-fe-priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/it913x-fe.c (99%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/it913x-fe.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/itd1000.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/itd1000.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/itd1000_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/ix2505v.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/ix2505v.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/l64781.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/l64781.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/lg2160.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/lg2160.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/lgdt3305.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/lgdt3305.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/lgdt330x.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/lgdt330x.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/lgdt330x_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/lgs8gl5.c (99%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/lgs8gl5.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/lgs8gxx.c (99%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/lgs8gxx.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/lgs8gxx_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/lnbh24.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/lnbp21.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/lnbp21.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/lnbp22.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/lnbp22.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/m88rs2000.c (99%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/m88rs2000.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/mb86a16.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/mb86a16.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/mb86a16_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/mb86a20s.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/mb86a20s.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/mt312.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/mt312.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/mt312_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/mt352.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/mt352.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/mt352_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/nxt200x.c (93%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/nxt200x.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/nxt6000.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/nxt6000.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/nxt6000_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/or51132.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/or51132.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/or51211.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/or51211.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/rtl2830.c (99%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/rtl2830.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/rtl2830_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/rtl2832.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/rtl2832.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/rtl2832_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/s5h1409.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/s5h1409.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/s5h1411.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/s5h1411.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/s5h1420.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/s5h1420.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/s5h1420_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/s5h1432.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/s5h1432.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/s921.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/s921.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/si21xx.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/si21xx.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/sp8870.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/sp8870.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/sp887x.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/sp887x.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stb0899_algo.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stb0899_cfg.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stb0899_drv.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stb0899_drv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stb0899_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stb0899_reg.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stb6000.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stb6000.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stb6100.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stb6100.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stb6100_cfg.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stb6100_proc.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv0288.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv0288.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv0297.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv0297.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv0299.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv0299.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv0367.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv0367.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv0367_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv0367_regs.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv0900.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv0900_core.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv0900_init.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv0900_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv0900_reg.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv0900_sw.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv090x.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv090x.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv090x_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv090x_reg.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv6110.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv6110.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv6110x.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv6110x.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv6110x_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/stv6110x_reg.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda10021.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda10023.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda1002x.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda10048.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda10048.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda1004x.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda1004x.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda10071.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda10071.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda10071_priv.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda10086.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda10086.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda18271c2dd.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda18271c2dd.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda18271c2dd_maps.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda665x.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda665x.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda8083.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda8083.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda8261.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda8261.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda8261_cfg.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda826x.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tda826x.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tdhd1.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tua6100.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/tua6100.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/ves1820.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/ves1820.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/ves1x93.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/ves1x93.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/z0194a.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/zl10036.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/zl10036.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/zl10039.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/zl10039.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/zl10353.c (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/zl10353.h (100%)
+ rename drivers/media/{dvb/frontends => dvb-frontends}/zl10353_priv.h (100%)
+ delete mode 100644 drivers/media/dvb/Kconfig
+ delete mode 100644 drivers/media/dvb/Makefile
+ delete mode 100644 drivers/media/dvb/b2c2/Makefile
+ delete mode 100644 drivers/media/dvb/bt8xx/Makefile
+ delete mode 100644 drivers/media/dvb/dm1105/Makefile
+ delete mode 100644 drivers/media/dvb/dvb-usb/Makefile
+ delete mode 100644 drivers/media/dvb/dvb-usb/af9015.c
+ delete mode 100644 drivers/media/dvb/dvb-usb/it913x.c
+ delete mode 100644 drivers/media/dvb/dvb-usb/mxl111sf.c
+ delete mode 100644 drivers/media/dvb/pluto2/Makefile
+ delete mode 100644 drivers/media/dvb/siano/Kconfig
+ delete mode 100644 drivers/media/dvb/ttusb-budget/Makefile
+ rename drivers/media/{dvb => }/firewire/Kconfig (100%)
+ rename drivers/media/{dvb => }/firewire/Makefile (51%)
+ rename drivers/media/{dvb => }/firewire/firedtv-avc.c (100%)
+ rename drivers/media/{dvb => }/firewire/firedtv-ci.c (100%)
+ rename drivers/media/{dvb => }/firewire/firedtv-dvb.c (100%)
+ rename drivers/media/{dvb => }/firewire/firedtv-fe.c (100%)
+ rename drivers/media/{dvb => }/firewire/firedtv-fw.c (100%)
+ rename drivers/media/{dvb => }/firewire/firedtv-rc.c (100%)
+ rename drivers/media/{dvb => }/firewire/firedtv.h (100%)
+ create mode 100644 drivers/media/i2c/Kconfig
+ create mode 100644 drivers/media/i2c/Makefile
+ rename drivers/media/{video => i2c}/adp1653.c (99%)
+ rename drivers/media/{video => i2c}/adv7170.c (100%)
+ rename drivers/media/{video => i2c}/adv7175.c (100%)
+ rename drivers/media/{video => i2c}/adv7180.c (100%)
+ rename drivers/media/{video => i2c}/adv7183.c (100%)
+ rename drivers/media/{video => i2c}/adv7183_regs.h (100%)
+ rename drivers/media/{video => i2c}/adv7343.c (100%)
+ rename drivers/media/{video => i2c}/adv7343_regs.h (100%)
+ rename drivers/media/{video => i2c}/adv7393.c (100%)
+ rename drivers/media/{video => i2c}/adv7393_regs.h (100%)
+ rename drivers/media/{video => i2c}/ak881x.c (100%)
+ rename drivers/media/{video => i2c}/aptina-pll.c (100%)
+ rename drivers/media/{video => i2c}/aptina-pll.h (100%)
+ rename drivers/media/{video => i2c}/as3645a.c (99%)
+ rename drivers/media/{video => i2c}/bt819.c (100%)
+ rename drivers/media/{video => i2c}/bt856.c (100%)
+ rename drivers/media/{video => i2c}/bt866.c (100%)
+ rename drivers/media/{video => i2c}/btcx-risc.c (100%)
+ rename drivers/media/{video => i2c}/btcx-risc.h (100%)
+ rename drivers/media/{video => i2c}/cs5345.c (100%)
+ rename drivers/media/{video => i2c}/cs53l32a.c (100%)
+ rename drivers/media/{video => i2c}/cx2341x.c (100%)
+ rename drivers/media/{video => i2c}/cx25840/Kconfig (100%)
+ rename drivers/media/{video => i2c}/cx25840/Makefile (80%)
+ rename drivers/media/{video => i2c}/cx25840/cx25840-audio.c (100%)
+ rename drivers/media/{video => i2c}/cx25840/cx25840-core.c (100%)
+ rename drivers/media/{video => i2c}/cx25840/cx25840-core.h (100%)
+ rename drivers/media/{video => i2c}/cx25840/cx25840-firmware.c (92%)
+ rename drivers/media/{video => i2c}/cx25840/cx25840-ir.c (100%)
+ rename drivers/media/{video => i2c}/cx25840/cx25840-vbi.c (100%)
+ rename drivers/media/{video => i2c}/ir-kbd-i2c.c (100%)
+ rename drivers/media/{video => i2c}/ks0127.c (100%)
+ rename drivers/media/{video => i2c}/ks0127.h (100%)
+ rename drivers/media/{video => i2c}/m52790.c (100%)
+ rename drivers/media/{video => i2c}/m5mols/Kconfig (100%)
+ rename drivers/media/{video => i2c}/m5mols/Makefile (100%)
+ rename drivers/media/{video => i2c}/m5mols/m5mols.h (100%)
+ rename drivers/media/{video => i2c}/m5mols/m5mols_capture.c (100%)
+ rename drivers/media/{video => i2c}/m5mols/m5mols_controls.c (100%)
+ rename drivers/media/{video => i2c}/m5mols/m5mols_core.c (100%)
+ rename drivers/media/{video => i2c}/m5mols/m5mols_reg.h (100%)
+ rename drivers/media/{video => i2c}/msp3400-driver.c (100%)
+ rename drivers/media/{video => i2c}/msp3400-driver.h (100%)
+ rename drivers/media/{video => i2c}/msp3400-kthreads.c (100%)
+ rename drivers/media/{video => i2c}/mt9m032.c (100%)
+ rename drivers/media/{video => i2c}/mt9p031.c (100%)
+ rename drivers/media/{video => i2c}/mt9t001.c (100%)
+ rename drivers/media/{video => i2c}/mt9v011.c (100%)
+ rename drivers/media/{video => i2c}/mt9v032.c (100%)
+ rename drivers/media/{video => i2c}/noon010pc30.c (100%)
+ rename drivers/media/{video => i2c}/ov7670.c (100%)
+ rename drivers/media/{video => i2c}/s5k6aa.c (99%)
+ rename drivers/media/{video => i2c}/saa6588.c (100%)
+ rename drivers/media/{video => i2c}/saa7110.c (100%)
+ rename drivers/media/{video => i2c}/saa7115.c (100%)
+ rename drivers/media/{video => i2c}/saa711x_regs.h (100%)
+ rename drivers/media/{video => i2c}/saa7127.c (99%)
+ rename drivers/media/{video => i2c}/saa717x.c (100%)
+ rename drivers/media/{video => i2c}/saa7185.c (100%)
+ rename drivers/media/{video => i2c}/saa7191.c (100%)
+ rename drivers/media/{video => i2c}/saa7191.h (100%)
+ rename drivers/media/{video => i2c}/smiapp-pll.c (99%)
+ rename drivers/media/{video => i2c}/smiapp-pll.h (98%)
+ rename drivers/media/{video => i2c}/smiapp/Kconfig (100%)
+ rename drivers/media/{video => i2c}/smiapp/Makefile (78%)
+ rename drivers/media/{video => i2c}/smiapp/smiapp-core.c (99%)
+ rename drivers/media/{video => i2c}/smiapp/smiapp-limits.c (99%)
+ rename drivers/media/{video => i2c}/smiapp/smiapp-limits.h (99%)
+ rename drivers/media/{video => i2c}/smiapp/smiapp-quirk.c (99%)
+ rename drivers/media/{video => i2c}/smiapp/smiapp-quirk.h (98%)
+ rename drivers/media/{video => i2c}/smiapp/smiapp-reg-defs.h (99%)
+ rename drivers/media/{video => i2c}/smiapp/smiapp-reg.h (98%)
+ rename drivers/media/{video => i2c}/smiapp/smiapp-regs.c (99%)
+ rename drivers/media/{video => i2c}/smiapp/smiapp-regs.h (100%)
+ rename drivers/media/{video => i2c}/smiapp/smiapp.h (99%)
+ create mode 100644 drivers/media/i2c/soc_camera/Kconfig
+ create mode 100644 drivers/media/i2c/soc_camera/Makefile
+ rename drivers/media/{video => i2c/soc_camera}/imx074.c (95%)
+ rename drivers/media/{video => i2c/soc_camera}/mt9m001.c (97%)
+ rename drivers/media/{video => i2c/soc_camera}/mt9m111.c (96%)
+ rename drivers/media/{video => i2c/soc_camera}/mt9t031.c (98%)
+ rename drivers/media/{video => i2c/soc_camera}/mt9t112.c (98%)
+ rename drivers/media/{video => i2c/soc_camera}/mt9v022.c (94%)
+ rename drivers/media/{video => i2c/soc_camera}/ov2640.c (98%)
+ rename drivers/media/{video => i2c/soc_camera}/ov5642.c (98%)
+ rename drivers/media/{video => i2c/soc_camera}/ov6650.c (98%)
+ rename drivers/media/{video => i2c/soc_camera}/ov772x.c (81%)
+ rename drivers/media/{video => i2c/soc_camera}/ov9640.c (97%)
+ rename drivers/media/{video => i2c/soc_camera}/ov9640.h (100%)
+ rename drivers/media/{video => i2c/soc_camera}/ov9740.c (97%)
+ rename drivers/media/{video => i2c/soc_camera}/rj54n1cb0c.c (98%)
+ rename drivers/media/{video => i2c/soc_camera}/sh_mobile_csi2.c (100%)
+ rename drivers/media/{video => i2c/soc_camera}/tw9910.c (98%)
+ rename drivers/media/{video => i2c}/sr030pc30.c (100%)
+ rename drivers/media/{video => i2c}/tcm825x.c (99%)
+ rename drivers/media/{video => i2c}/tcm825x.h (99%)
+ rename drivers/media/{video => i2c}/tda7432.c (100%)
+ rename drivers/media/{video => i2c}/tda9840.c (100%)
+ rename drivers/media/{video => i2c}/tea6415c.c (100%)
+ rename drivers/media/{video => i2c}/tea6415c.h (100%)
+ rename drivers/media/{video => i2c}/tea6420.c (100%)
+ rename drivers/media/{video => i2c}/tea6420.h (100%)
+ rename drivers/media/{video => i2c}/ths7303.c (100%)
+ rename drivers/media/{video => i2c}/tlv320aic23b.c (100%)
+ rename drivers/media/{video => i2c}/tvaudio.c (100%)
+ rename drivers/media/{video => i2c}/tveeprom.c (100%)
+ rename drivers/media/{video => i2c}/tvp514x.c (99%)
+ rename drivers/media/{video => i2c}/tvp514x_regs.h (99%)
+ rename drivers/media/{video => i2c}/tvp5150.c (100%)
+ rename drivers/media/{video => i2c}/tvp5150_reg.h (100%)
+ rename drivers/media/{video => i2c}/tvp7002.c (100%)
+ rename drivers/media/{video => i2c}/tvp7002_reg.h (100%)
+ rename drivers/media/{video => i2c}/upd64031a.c (100%)
+ rename drivers/media/{video => i2c}/upd64083.c (100%)
+ rename drivers/media/{video => i2c}/vp27smpx.c (100%)
+ rename drivers/media/{video => i2c}/vpx3220.c (100%)
+ rename drivers/media/{video => i2c}/vs6624.c (100%)
+ rename drivers/media/{video => i2c}/vs6624_regs.h (100%)
+ rename drivers/media/{video => i2c}/wm8739.c (100%)
+ rename drivers/media/{video => i2c}/wm8775.c (100%)
+ create mode 100644 drivers/media/mmc/Kconfig
+ create mode 100644 drivers/media/mmc/Makefile
+ create mode 100644 drivers/media/mmc/siano/Kconfig
+ create mode 100644 drivers/media/mmc/siano/Makefile
+ rename drivers/media/{dvb => mmc}/siano/smssdio.c (100%)
+ create mode 100644 drivers/media/parport/Kconfig
+ create mode 100644 drivers/media/parport/Makefile
+ rename drivers/media/{video => parport}/bw-qcam.c (100%)
+ rename drivers/media/{video => parport}/c-qcam.c (100%)
+ rename drivers/media/{video => parport}/pms.c (100%)
+ rename drivers/media/{video => parport}/w9966.c (100%)
+ create mode 100644 drivers/media/pci/Kconfig
+ create mode 100644 drivers/media/pci/Makefile
+ create mode 100644 drivers/media/pci/b2c2/Kconfig
+ create mode 100644 drivers/media/pci/b2c2/Makefile
+ rename drivers/media/{dvb => pci}/b2c2/flexcop-dma.c (100%)
+ rename drivers/media/{dvb => pci}/b2c2/flexcop-pci.c (100%)
+ rename drivers/media/{dvb => pci}/bt8xx/Kconfig (52%)
+ create mode 100644 drivers/media/pci/bt8xx/Makefile
+ rename drivers/media/{video => pci}/bt8xx/bt848.h (100%)
+ rename drivers/media/{dvb => pci}/bt8xx/bt878.c (100%)
+ rename drivers/media/{dvb => pci}/bt8xx/bt878.h (100%)
+ rename drivers/media/{video => pci}/bt8xx/bttv-audio-hook.c (100%)
+ rename drivers/media/{video => pci}/bt8xx/bttv-audio-hook.h (100%)
+ rename drivers/media/{video => pci}/bt8xx/bttv-cards.c (100%)
+ rename drivers/media/{video => pci}/bt8xx/bttv-driver.c (100%)
+ rename drivers/media/{video => pci}/bt8xx/bttv-gpio.c (100%)
+ rename drivers/media/{video => pci}/bt8xx/bttv-i2c.c (100%)
+ rename drivers/media/{video => pci}/bt8xx/bttv-if.c (100%)
+ rename drivers/media/{video => pci}/bt8xx/bttv-input.c (100%)
+ rename drivers/media/{video => pci}/bt8xx/bttv-risc.c (100%)
+ rename drivers/media/{video => pci}/bt8xx/bttv-vbi.c (100%)
+ rename drivers/media/{video => pci}/bt8xx/bttv.h (100%)
+ rename drivers/media/{video => pci}/bt8xx/bttvp.h (100%)
+ rename drivers/media/{dvb => pci}/bt8xx/dst.c (100%)
+ rename drivers/media/{dvb => pci}/bt8xx/dst_ca.c (99%)
+ rename drivers/media/{dvb => pci}/bt8xx/dst_ca.h (100%)
+ rename drivers/media/{dvb => pci}/bt8xx/dst_common.h (100%)
+ rename drivers/media/{dvb => pci}/bt8xx/dst_priv.h (100%)
+ rename drivers/media/{dvb => pci}/bt8xx/dvb-bt8xx.c (100%)
+ rename drivers/media/{dvb => pci}/bt8xx/dvb-bt8xx.h (100%)
+ rename drivers/media/{video => pci}/cx18/Kconfig (100%)
+ rename drivers/media/{video => pci}/cx18/Makefile (78%)
+ rename drivers/media/{video => pci}/cx18/cx18-alsa-main.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-alsa-mixer.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-alsa-mixer.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-alsa-pcm.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-alsa-pcm.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-alsa.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-audio.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-audio.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-av-audio.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-av-core.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-av-core.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-av-firmware.c (99%)
+ rename drivers/media/{video => pci}/cx18/cx18-av-vbi.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-cards.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-cards.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-controls.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-controls.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-driver.c (99%)
+ rename drivers/media/{video => pci}/cx18/cx18-driver.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-dvb.c (99%)
+ rename drivers/media/{video => pci}/cx18/cx18-dvb.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-fileops.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-fileops.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-firmware.c (98%)
+ rename drivers/media/{video => pci}/cx18/cx18-firmware.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-gpio.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-gpio.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-i2c.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-i2c.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-io.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-io.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-ioctl.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-ioctl.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-irq.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-irq.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-mailbox.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-mailbox.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-queue.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-queue.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-scb.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-scb.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-streams.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-streams.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-vbi.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-vbi.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-version.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-video.c (100%)
+ rename drivers/media/{video => pci}/cx18/cx18-video.h (100%)
+ rename drivers/media/{video => pci}/cx18/cx23418.h (100%)
+ rename drivers/media/{video => pci}/cx23885/Kconfig (100%)
+ rename drivers/media/{video => pci}/cx23885/Makefile (72%)
+ rename drivers/media/{video => pci}/cx23885/altera-ci.c (100%)
+ rename drivers/media/{video => pci}/cx23885/altera-ci.h (100%)
+ rename drivers/media/{video => pci}/cx23885/cimax2.c (100%)
+ rename drivers/media/{video => pci}/cx23885/cimax2.h (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-417.c (99%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-alsa.c (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-av.c (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-av.h (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-cards.c (99%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-core.c (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-dvb.c (99%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-f300.c (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-f300.h (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-i2c.c (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-input.c (96%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-input.h (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-ioctl.c (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-ioctl.h (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-ir.c (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-ir.h (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-reg.h (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-vbi.c (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23885-video.c (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23885.h (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23888-ir.c (100%)
+ rename drivers/media/{video => pci}/cx23885/cx23888-ir.h (100%)
+ rename drivers/media/{video => pci}/cx23885/netup-eeprom.c (100%)
+ rename drivers/media/{video => pci}/cx23885/netup-eeprom.h (100%)
+ rename drivers/media/{video => pci}/cx23885/netup-init.c (100%)
+ rename drivers/media/{video => pci}/cx23885/netup-init.h (100%)
+ rename drivers/media/{video => pci}/cx25821/Kconfig (100%)
+ rename drivers/media/{video => pci}/cx25821/Makefile (67%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-alsa.c (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-audio-upstream.c (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-audio-upstream.h (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-audio.h (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-biffuncs.h (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-cards.c (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-core.c (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-gpio.c (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-i2c.c (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-medusa-defines.h (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-medusa-reg.h (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-medusa-video.c (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-medusa-video.h (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-reg.h (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-sram.h (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-video-upstream-ch2.c (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-video-upstream-ch2.h (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-video-upstream.c (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-video-upstream.h (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-video.c (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821-video.h (100%)
+ rename drivers/media/{video => pci}/cx25821/cx25821.h (100%)
+ rename drivers/media/{video => pci}/cx88/Kconfig (100%)
+ rename drivers/media/{video => pci}/cx88/Makefile (73%)
+ rename drivers/media/{video => pci}/cx88/cx88-alsa.c (99%)
+ rename drivers/media/{video => pci}/cx88/cx88-blackbird.c (100%)
+ rename drivers/media/{video => pci}/cx88/cx88-cards.c (100%)
+ rename drivers/media/{video => pci}/cx88/cx88-core.c (99%)
+ rename drivers/media/{video => pci}/cx88/cx88-dsp.c (100%)
+ rename drivers/media/{video => pci}/cx88/cx88-dvb.c (99%)
+ rename drivers/media/{video => pci}/cx88/cx88-i2c.c (100%)
+ rename drivers/media/{video => pci}/cx88/cx88-input.c (100%)
+ rename drivers/media/{video => pci}/cx88/cx88-mpeg.c (100%)
+ rename drivers/media/{video => pci}/cx88/cx88-reg.h (100%)
+ rename drivers/media/{video => pci}/cx88/cx88-tvaudio.c (100%)
+ rename drivers/media/{video => pci}/cx88/cx88-vbi.c (100%)
+ rename drivers/media/{video => pci}/cx88/cx88-video.c (100%)
+ rename drivers/media/{video => pci}/cx88/cx88-vp3054-i2c.c (100%)
+ rename drivers/media/{video => pci}/cx88/cx88-vp3054-i2c.h (100%)
+ rename drivers/media/{video => pci}/cx88/cx88.h (99%)
+ rename drivers/media/{dvb => pci}/ddbridge/Kconfig (100%)
+ rename drivers/media/{dvb => pci}/ddbridge/Makefile (61%)
+ rename drivers/media/{dvb => pci}/ddbridge/ddbridge-core.c (100%)
+ rename drivers/media/{dvb => pci}/ddbridge/ddbridge-regs.h (100%)
+ rename drivers/media/{dvb => pci}/ddbridge/ddbridge.h (100%)
+ rename drivers/media/{dvb => pci}/dm1105/Kconfig (100%)
+ create mode 100644 drivers/media/pci/dm1105/Makefile
+ rename drivers/media/{dvb => pci}/dm1105/dm1105.c (100%)
+ rename drivers/media/{video => pci}/ivtv/Kconfig (100%)
+ rename drivers/media/{video => pci}/ivtv/Makefile (61%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-cards.c (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-cards.h (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-controls.c (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-controls.h (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-driver.c (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-driver.h (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-fileops.c (96%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-fileops.h (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-firmware.c (98%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-firmware.h (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-gpio.c (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-gpio.h (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-i2c.c (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-i2c.h (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-ioctl.c (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-ioctl.h (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-irq.c (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-irq.h (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-mailbox.c (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-mailbox.h (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-queue.c (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-queue.h (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-routing.c (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-routing.h (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-streams.c (99%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-streams.h (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-udma.c (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-udma.h (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-vbi.c (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-vbi.h (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-version.h (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-yuv.c (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtv-yuv.h (100%)
+ rename drivers/media/{video => pci}/ivtv/ivtvfb.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/Kconfig (100%)
+ rename drivers/media/{dvb => pci}/mantis/Makefile (88%)
+ rename drivers/media/{dvb => pci}/mantis/hopper_cards.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/hopper_vp3028.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/hopper_vp3028.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_ca.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_ca.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_cards.c (99%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_common.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_core.c (99%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_core.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_dma.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_dma.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_dvb.c (98%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_dvb.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_evm.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_hif.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_hif.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_i2c.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_i2c.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_input.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_ioc.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_ioc.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_link.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_pci.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_pci.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_pcmcia.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_reg.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_uart.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_uart.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_vp1033.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_vp1033.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_vp1034.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_vp1034.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_vp1041.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_vp1041.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_vp2033.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_vp2033.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_vp2040.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_vp2040.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_vp3028.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_vp3028.h (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_vp3030.c (100%)
+ rename drivers/media/{dvb => pci}/mantis/mantis_vp3030.h (100%)
+ create mode 100644 drivers/media/pci/meye/Kconfig
+ create mode 100644 drivers/media/pci/meye/Makefile
+ rename drivers/media/{video => pci/meye}/meye.c (100%)
+ rename drivers/media/{video => pci/meye}/meye.h (100%)
+ rename drivers/media/{dvb => pci}/ngene/Kconfig (100%)
+ rename drivers/media/{dvb => pci}/ngene/Makefile (63%)
+ rename drivers/media/{dvb => pci}/ngene/ngene-cards.c (71%)
+ rename drivers/media/{dvb => pci}/ngene/ngene-core.c (98%)
+ rename drivers/media/{dvb => pci}/ngene/ngene-dvb.c (100%)
+ rename drivers/media/{dvb => pci}/ngene/ngene-i2c.c (100%)
+ rename drivers/media/{dvb => pci}/ngene/ngene.h (100%)
+ rename drivers/media/{dvb => pci}/pluto2/Kconfig (100%)
+ create mode 100644 drivers/media/pci/pluto2/Makefile
+ rename drivers/media/{dvb => pci}/pluto2/pluto2.c (100%)
+ rename drivers/media/{dvb => pci}/pt1/Kconfig (100%)
+ rename drivers/media/{dvb => pci}/pt1/Makefile (56%)
+ rename drivers/media/{dvb => pci}/pt1/pt1.c (100%)
+ rename drivers/media/{dvb => pci}/pt1/va1j5jf8007s.c (100%)
+ rename drivers/media/{dvb => pci}/pt1/va1j5jf8007s.h (100%)
+ rename drivers/media/{dvb => pci}/pt1/va1j5jf8007t.c (100%)
+ rename drivers/media/{dvb => pci}/pt1/va1j5jf8007t.h (100%)
+ rename drivers/media/{video => pci}/saa7134/Kconfig (100%)
+ rename drivers/media/{video => pci}/saa7134/Makefile (54%)
+ rename drivers/media/{video => pci}/saa7134/saa6752hs.c (100%)
+ rename drivers/media/{video => pci}/saa7134/saa7134-alsa.c (100%)
+ rename drivers/media/{video => pci}/saa7134/saa7134-cards.c (100%)
+ rename drivers/media/{video => pci}/saa7134/saa7134-core.c (100%)
+ rename drivers/media/{video => pci}/saa7134/saa7134-dvb.c (99%)
+ rename drivers/media/{video => pci}/saa7134/saa7134-empress.c (100%)
+ rename drivers/media/{video => pci}/saa7134/saa7134-i2c.c (100%)
+ rename drivers/media/{video => pci}/saa7134/saa7134-input.c (99%)
+ rename drivers/media/{video => pci}/saa7134/saa7134-reg.h (100%)
+ rename drivers/media/{video => pci}/saa7134/saa7134-ts.c (100%)
+ rename drivers/media/{video => pci}/saa7134/saa7134-tvaudio.c (100%)
+ rename drivers/media/{video => pci}/saa7134/saa7134-vbi.c (100%)
+ rename drivers/media/{video => pci}/saa7134/saa7134-video.c (100%)
+ rename drivers/media/{video => pci}/saa7134/saa7134.h (99%)
+ create mode 100644 drivers/media/pci/saa7146/Kconfig
+ create mode 100644 drivers/media/pci/saa7146/Makefile
+ rename drivers/media/{video => pci/saa7146}/hexium_gemini.c (100%)
+ rename drivers/media/{video => pci/saa7146}/hexium_orion.c (100%)
+ rename drivers/media/{video => pci/saa7146}/mxb.c (100%)
+ rename drivers/media/{video => pci}/saa7164/Kconfig (100%)
+ rename drivers/media/{video => pci}/saa7164/Makefile (57%)
+ rename drivers/media/{video => pci}/saa7164/saa7164-api.c (98%)
+ rename drivers/media/{video => pci}/saa7164/saa7164-buffer.c (100%)
+ rename drivers/media/{video => pci}/saa7164/saa7164-bus.c (100%)
+ rename drivers/media/{video => pci}/saa7164/saa7164-cards.c (100%)
+ rename drivers/media/{video => pci}/saa7164/saa7164-cmd.c (100%)
+ rename drivers/media/{video => pci}/saa7164/saa7164-core.c (96%)
+ rename drivers/media/{video => pci}/saa7164/saa7164-dvb.c (100%)
+ rename drivers/media/{video => pci}/saa7164/saa7164-encoder.c (100%)
+ rename drivers/media/{video => pci}/saa7164/saa7164-fw.c (100%)
+ rename drivers/media/{video => pci}/saa7164/saa7164-i2c.c (100%)
+ rename drivers/media/{video => pci}/saa7164/saa7164-reg.h (100%)
+ rename drivers/media/{video => pci}/saa7164/saa7164-types.h (100%)
+ rename drivers/media/{video => pci}/saa7164/saa7164-vbi.c (100%)
+ rename drivers/media/{video => pci}/saa7164/saa7164.h (99%)
+ create mode 100644 drivers/media/pci/sta2x11/Kconfig
+ create mode 100644 drivers/media/pci/sta2x11/Makefile
+ rename drivers/media/{video => pci/sta2x11}/sta2x11_vip.c (100%)
+ rename drivers/media/{video => pci/sta2x11}/sta2x11_vip.h (100%)
+ rename drivers/media/{dvb => pci}/ttpci/Kconfig (100%)
+ rename drivers/media/{dvb => pci}/ttpci/Makefile (82%)
+ rename drivers/media/{dvb => pci}/ttpci/av7110.c (100%)
+ rename drivers/media/{dvb => pci}/ttpci/av7110.h (100%)
+ rename drivers/media/{dvb => pci}/ttpci/av7110_av.c (100%)
+ rename drivers/media/{dvb => pci}/ttpci/av7110_av.h (100%)
+ rename drivers/media/{dvb => pci}/ttpci/av7110_ca.c (100%)
+ rename drivers/media/{dvb => pci}/ttpci/av7110_ca.h (100%)
+ rename drivers/media/{dvb => pci}/ttpci/av7110_hw.c (100%)
+ rename drivers/media/{dvb => pci}/ttpci/av7110_hw.h (100%)
+ rename drivers/media/{dvb => pci}/ttpci/av7110_ipack.c (100%)
+ rename drivers/media/{dvb => pci}/ttpci/av7110_ipack.h (100%)
+ rename drivers/media/{dvb => pci}/ttpci/av7110_ir.c (100%)
+ rename drivers/media/{dvb => pci}/ttpci/av7110_v4l.c (100%)
+ rename drivers/media/{dvb => pci}/ttpci/budget-av.c (100%)
+ rename drivers/media/{dvb => pci}/ttpci/budget-ci.c (100%)
+ rename drivers/media/{dvb => pci}/ttpci/budget-core.c (100%)
+ rename drivers/media/{dvb => pci}/ttpci/budget-patch.c (100%)
+ rename drivers/media/{dvb => pci}/ttpci/budget.c (91%)
+ rename drivers/media/{dvb => pci}/ttpci/budget.h (100%)
+ rename drivers/media/{dvb => pci}/ttpci/ttpci-eeprom.c (100%)
+ rename drivers/media/{dvb => pci}/ttpci/ttpci-eeprom.h (100%)
+ rename drivers/media/{video => pci}/zoran/Kconfig (100%)
+ rename drivers/media/{video => pci}/zoran/Makefile (100%)
+ rename drivers/media/{video => pci}/zoran/videocodec.c (100%)
+ rename drivers/media/{video => pci}/zoran/videocodec.h (100%)
+ rename drivers/media/{video => pci}/zoran/zoran.h (100%)
+ rename drivers/media/{video => pci}/zoran/zoran_card.c (100%)
+ rename drivers/media/{video => pci}/zoran/zoran_card.h (100%)
+ rename drivers/media/{video => pci}/zoran/zoran_device.c (100%)
+ rename drivers/media/{video => pci}/zoran/zoran_device.h (100%)
+ rename drivers/media/{video => pci}/zoran/zoran_driver.c (100%)
+ rename drivers/media/{video => pci}/zoran/zoran_procfs.c (100%)
+ rename drivers/media/{video => pci}/zoran/zoran_procfs.h (100%)
+ rename drivers/media/{video => pci}/zoran/zr36016.c (100%)
+ rename drivers/media/{video => pci}/zoran/zr36016.h (100%)
+ rename drivers/media/{video => pci}/zoran/zr36050.c (100%)
+ rename drivers/media/{video => pci}/zoran/zr36050.h (100%)
+ rename drivers/media/{video => pci}/zoran/zr36057.h (100%)
+ rename drivers/media/{video => pci}/zoran/zr36060.c (100%)
+ rename drivers/media/{video => pci}/zoran/zr36060.h (100%)
+ create mode 100644 drivers/media/platform/Kconfig
+ create mode 100644 drivers/media/platform/Makefile
+ rename drivers/media/{video => platform}/arv.c (100%)
+ rename drivers/media/{video => platform}/atmel-isi.c (100%)
+ rename drivers/media/{video => platform}/blackfin/Kconfig (100%)
+ rename drivers/media/{video => platform}/blackfin/Makefile (100%)
+ rename drivers/media/{video => platform}/blackfin/bfin_capture.c (98%)
+ rename drivers/media/{video => platform}/blackfin/ppi.c (100%)
+ create mode 100644 drivers/media/platform/coda.c
+ create mode 100644 drivers/media/platform/coda.h
+ rename drivers/media/{video => platform}/davinci/Kconfig (100%)
+ rename drivers/media/{video => platform}/davinci/Makefile (100%)
+ rename drivers/media/{video => platform}/davinci/ccdc_hw_device.h (100%)
+ rename drivers/media/{video => platform}/davinci/dm355_ccdc.c (99%)
+ rename drivers/media/{video => platform}/davinci/dm355_ccdc_regs.h (100%)
+ rename drivers/media/{video => platform}/davinci/dm644x_ccdc.c (99%)
+ rename drivers/media/{video => platform}/davinci/dm644x_ccdc_regs.h (100%)
+ rename drivers/media/{video => platform}/davinci/isif.c (99%)
+ rename drivers/media/{video => platform}/davinci/isif_regs.h (100%)
+ rename drivers/media/{video => platform}/davinci/vpbe.c (100%)
+ rename drivers/media/{video => platform}/davinci/vpbe_display.c (99%)
+ rename drivers/media/{video => platform}/davinci/vpbe_osd.c (100%)
+ rename drivers/media/{video => platform}/davinci/vpbe_osd_regs.h (100%)
+ rename drivers/media/{video => platform}/davinci/vpbe_venc.c (100%)
+ rename drivers/media/{video => platform}/davinci/vpbe_venc_regs.h (100%)
+ rename drivers/media/{video => platform}/davinci/vpfe_capture.c (99%)
+ rename drivers/media/{video => platform}/davinci/vpif.c (99%)
+ rename drivers/media/{video => platform}/davinci/vpif.h (100%)
+ rename drivers/media/{video => platform}/davinci/vpif_capture.c (99%)
+ rename drivers/media/{video => platform}/davinci/vpif_capture.h (100%)
+ rename drivers/media/{video => platform}/davinci/vpif_display.c (98%)
+ rename drivers/media/{video => platform}/davinci/vpif_display.h (100%)
+ rename drivers/media/{video => platform}/davinci/vpss.c (99%)
+ rename drivers/media/{video => platform}/fsl-viu.c (98%)
+ rename drivers/media/{video => platform}/indycam.c (100%)
+ rename drivers/media/{video => platform}/indycam.h (100%)
+ create mode 100644 drivers/media/platform/m2m-deinterlace.c
+ rename drivers/media/{video => platform}/marvell-ccic/Kconfig (100%)
+ rename drivers/media/{video => platform}/marvell-ccic/Makefile (100%)
+ rename drivers/media/{video => platform}/marvell-ccic/cafe-driver.c (100%)
+ rename drivers/media/{video => platform}/marvell-ccic/mcam-core.c (100%)
+ rename drivers/media/{video => platform}/marvell-ccic/mcam-core.h (100%)
+ rename drivers/media/{video => platform}/marvell-ccic/mmp-driver.c (100%)
+ rename drivers/media/{video => platform}/mem2mem_testdev.c (97%)
+ rename drivers/media/{video => platform}/mx1_camera.c (99%)
+ rename drivers/media/{video => platform}/mx2_camera.c (95%)
+ rename drivers/media/{video => platform}/mx2_emmaprp.c (94%)
+ rename drivers/media/{video => platform}/mx3_camera.c (98%)
+ rename drivers/media/{video => platform}/omap/Kconfig (100%)
+ rename drivers/media/{video => platform}/omap/Makefile (81%)
+ rename drivers/media/{video => platform}/omap/omap_vout.c (100%)
+ rename drivers/media/{video => platform}/omap/omap_vout_vrfb.c (100%)
+ rename drivers/media/{video => platform}/omap/omap_vout_vrfb.h (100%)
+ rename drivers/media/{video => platform}/omap/omap_voutdef.h (100%)
+ rename drivers/media/{video => platform}/omap/omap_voutlib.c (100%)
+ rename drivers/media/{video => platform}/omap/omap_voutlib.h (100%)
+ rename drivers/media/{video => platform}/omap1_camera.c (99%)
+ rename drivers/media/{video => platform}/omap24xxcam-dma.c (99%)
+ rename drivers/media/{video => platform}/omap24xxcam.c (99%)
+ rename drivers/media/{video => platform}/omap24xxcam.h (99%)
+ rename drivers/media/{video => platform}/omap3isp/Makefile (100%)
+ rename drivers/media/{video => platform}/omap3isp/cfa_coef_table.h (91%)
+ rename drivers/media/{video => platform}/omap3isp/gamma_table.h (100%)
+ rename drivers/media/{video => platform}/omap3isp/isp.c (98%)
+ rename drivers/media/{video => platform}/omap3isp/isp.h (97%)
+ rename drivers/media/{video => platform}/omap3isp/ispccdc.c (94%)
+ rename drivers/media/{video => platform}/omap3isp/ispccdc.h (83%)
+ rename drivers/media/{video => platform}/omap3isp/ispccp2.c (100%)
+ rename drivers/media/{video => platform}/omap3isp/ispccp2.h (100%)
+ rename drivers/media/{video => platform}/omap3isp/ispcsi2.c (98%)
+ rename drivers/media/{video => platform}/omap3isp/ispcsi2.h (100%)
+ rename drivers/media/{video => platform}/omap3isp/ispcsiphy.c (100%)
+ rename drivers/media/{video => platform}/omap3isp/ispcsiphy.h (100%)
+ rename drivers/media/{video => platform}/omap3isp/isph3a.h (100%)
+ rename drivers/media/{video => platform}/omap3isp/isph3a_aewb.c (96%)
+ rename drivers/media/{video => platform}/omap3isp/isph3a_af.c (96%)
+ rename drivers/media/{video => platform}/omap3isp/isphist.c (98%)
+ rename drivers/media/{video => platform}/omap3isp/isphist.h (100%)
+ rename drivers/media/{video => platform}/omap3isp/isppreview.c (89%)
+ rename drivers/media/{video => platform}/omap3isp/isppreview.h (99%)
+ rename drivers/media/{video => platform}/omap3isp/ispqueue.c (98%)
+ rename drivers/media/{video => platform}/omap3isp/ispqueue.h (100%)
+ rename drivers/media/{video => platform}/omap3isp/ispreg.h (100%)
+ rename drivers/media/{video => platform}/omap3isp/ispresizer.c (99%)
+ rename drivers/media/{video => platform}/omap3isp/ispresizer.h (100%)
+ rename drivers/media/{video => platform}/omap3isp/ispstat.c (100%)
+ rename drivers/media/{video => platform}/omap3isp/ispstat.h (100%)
+ rename drivers/media/{video => platform}/omap3isp/ispvideo.c (96%)
+ rename drivers/media/{video => platform}/omap3isp/ispvideo.h (97%)
+ rename drivers/media/{video => platform}/omap3isp/luma_enhance_table.h (100%)
+ rename drivers/media/{video => platform}/omap3isp/noise_filter_table.h (100%)
+ rename drivers/media/{video => platform}/pxa_camera.c (100%)
+ rename drivers/media/{video => platform}/s5p-fimc/Kconfig (100%)
+ rename drivers/media/{video => platform}/s5p-fimc/Makefile (100%)
+ rename drivers/media/{video => platform}/s5p-fimc/fimc-capture.c (100%)
+ rename drivers/media/{video => platform}/s5p-fimc/fimc-core.c (100%)
+ rename drivers/media/{video => platform}/s5p-fimc/fimc-core.h (100%)
+ rename drivers/media/{video => platform}/s5p-fimc/fimc-lite-reg.c (100%)
+ rename drivers/media/{video => platform}/s5p-fimc/fimc-lite-reg.h (100%)
+ rename drivers/media/{video => platform}/s5p-fimc/fimc-lite.c (100%)
+ rename drivers/media/{video => platform}/s5p-fimc/fimc-lite.h (100%)
+ rename drivers/media/{video => platform}/s5p-fimc/fimc-m2m.c (100%)
+ rename drivers/media/{video => platform}/s5p-fimc/fimc-mdevice.c (100%)
+ rename drivers/media/{video => platform}/s5p-fimc/fimc-mdevice.h (100%)
+ rename drivers/media/{video => platform}/s5p-fimc/fimc-reg.c (100%)
+ rename drivers/media/{video => platform}/s5p-fimc/fimc-reg.h (100%)
+ rename drivers/media/{video => platform}/s5p-fimc/mipi-csis.c (100%)
+ rename drivers/media/{video => platform}/s5p-fimc/mipi-csis.h (100%)
+ rename drivers/media/{video => platform}/s5p-g2d/Makefile (100%)
+ rename drivers/media/{video => platform}/s5p-g2d/g2d-hw.c (100%)
+ rename drivers/media/{video => platform}/s5p-g2d/g2d-regs.h (100%)
+ rename drivers/media/{video => platform}/s5p-g2d/g2d.c (97%)
+ rename drivers/media/{video => platform}/s5p-g2d/g2d.h (100%)
+ rename drivers/media/{video => platform}/s5p-jpeg/Makefile (100%)
+ rename drivers/media/{video => platform}/s5p-jpeg/jpeg-core.c (98%)
+ rename drivers/media/{video => platform}/s5p-jpeg/jpeg-core.h (98%)
+ rename drivers/media/{video => platform}/s5p-jpeg/jpeg-hw.h (99%)
+ rename drivers/media/{video => platform}/s5p-jpeg/jpeg-regs.h (98%)
+ rename drivers/media/{video => platform}/s5p-mfc/Makefile (100%)
+ rename drivers/media/{video => platform}/s5p-mfc/regs-mfc.h (100%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc.c (98%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_cmd.c (98%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_cmd.h (93%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_common.h (100%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_ctrl.c (99%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_ctrl.h (93%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_debug.h (95%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_dec.c (99%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_dec.h (93%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_enc.c (99%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_enc.h (93%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_intr.c (97%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_intr.h (93%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_opr.c (99%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_opr.h (98%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_pm.c (98%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_pm.h (92%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_shm.c (96%)
+ rename drivers/media/{video => platform}/s5p-mfc/s5p_mfc_shm.h (98%)
+ rename drivers/media/{video => platform}/s5p-tv/Kconfig (98%)
+ rename drivers/media/{video => platform}/s5p-tv/Makefile (92%)
+ rename drivers/media/{video => platform}/s5p-tv/hdmi_drv.c (99%)
+ rename drivers/media/{video => platform}/s5p-tv/hdmiphy_drv.c (100%)
+ rename drivers/media/{video => platform}/s5p-tv/mixer.h (100%)
+ rename drivers/media/{video => platform}/s5p-tv/mixer_drv.c (98%)
+ rename drivers/media/{video => platform}/s5p-tv/mixer_grp_layer.c (100%)
+ rename drivers/media/{video => platform}/s5p-tv/mixer_reg.c (100%)
+ rename drivers/media/{video => platform}/s5p-tv/mixer_video.c (97%)
+ rename drivers/media/{video => platform}/s5p-tv/mixer_vp_layer.c (100%)
+ rename drivers/media/{video => platform}/s5p-tv/regs-hdmi.h (100%)
+ rename drivers/media/{video => platform}/s5p-tv/regs-mixer.h (100%)
+ rename drivers/media/{video => platform}/s5p-tv/regs-sdo.h (97%)
+ rename drivers/media/{video => platform}/s5p-tv/regs-vp.h (100%)
+ rename drivers/media/{video => platform}/s5p-tv/sdo_drv.c (98%)
+ rename drivers/media/{video => platform}/s5p-tv/sii9234_drv.c (97%)
+ rename drivers/media/{video => platform}/sh_mobile_ceu_camera.c (100%)
+ rename drivers/media/{video => platform}/sh_vou.c (98%)
+ rename drivers/media/{video => platform}/soc_camera.c (92%)
+ rename drivers/media/{video => platform}/soc_camera_platform.c (94%)
+ rename drivers/media/{video => platform}/soc_mediabus.c (99%)
+ rename drivers/media/{video => platform}/timblogiw.c (100%)
+ rename drivers/media/{video => platform}/via-camera.c (100%)
+ rename drivers/media/{video => platform}/via-camera.h (100%)
+ rename drivers/media/{video => platform}/vino.c (100%)
+ rename drivers/media/{video => platform}/vino.h (100%)
+ rename drivers/media/{video => platform}/vivi.c (97%)
+ create mode 100644 drivers/media/rc/ir-rx51.c
+ create mode 100644 drivers/media/rc/ttusbir.c
+ rename drivers/media/{common => }/tuners/Kconfig (100%)
+ rename drivers/media/{common => }/tuners/Makefile (93%)
+ rename drivers/media/{common => }/tuners/fc0011.c (100%)
+ rename drivers/media/{common => }/tuners/fc0011.h (100%)
+ rename drivers/media/{common => }/tuners/fc0012-priv.h (100%)
+ rename drivers/media/{common => }/tuners/fc0012.c (100%)
+ rename drivers/media/{common => }/tuners/fc0012.h (100%)
+ rename drivers/media/{common => }/tuners/fc0013-priv.h (100%)
+ rename drivers/media/{common => }/tuners/fc0013.c (100%)
+ rename drivers/media/{common => }/tuners/fc0013.h (100%)
+ rename drivers/media/{common => }/tuners/fc001x-common.h (100%)
+ rename drivers/media/{common => }/tuners/max2165.c (100%)
+ rename drivers/media/{common => }/tuners/max2165.h (100%)
+ rename drivers/media/{common => }/tuners/max2165_priv.h (100%)
+ rename drivers/media/{common => }/tuners/mc44s803.c (100%)
+ rename drivers/media/{common => }/tuners/mc44s803.h (100%)
+ rename drivers/media/{common => }/tuners/mc44s803_priv.h (100%)
+ rename drivers/media/{common => }/tuners/mt2060.c (100%)
+ rename drivers/media/{common => }/tuners/mt2060.h (100%)
+ rename drivers/media/{common => }/tuners/mt2060_priv.h (100%)
+ rename drivers/media/{common => }/tuners/mt2063.c (100%)
+ rename drivers/media/{common => }/tuners/mt2063.h (100%)
+ rename drivers/media/{common => }/tuners/mt20xx.c (100%)
+ rename drivers/media/{common => }/tuners/mt20xx.h (100%)
+ rename drivers/media/{common => }/tuners/mt2131.c (100%)
+ rename drivers/media/{common => }/tuners/mt2131.h (100%)
+ rename drivers/media/{common => }/tuners/mt2131_priv.h (100%)
+ rename drivers/media/{common => }/tuners/mt2266.c (100%)
+ rename drivers/media/{common => }/tuners/mt2266.h (100%)
+ rename drivers/media/{common => }/tuners/mxl5005s.c (100%)
+ rename drivers/media/{common => }/tuners/mxl5005s.h (100%)
+ rename drivers/media/{common => }/tuners/mxl5007t.c (100%)
+ rename drivers/media/{common => }/tuners/mxl5007t.h (100%)
+ rename drivers/media/{common => }/tuners/qt1010.c (99%)
+ rename drivers/media/{common => }/tuners/qt1010.h (100%)
+ rename drivers/media/{common => }/tuners/qt1010_priv.h (100%)
+ rename drivers/media/{common => }/tuners/tda18212.c (91%)
+ rename drivers/media/{common => }/tuners/tda18212.h (100%)
+ rename drivers/media/{common => }/tuners/tda18218.c (99%)
+ rename drivers/media/{common => }/tuners/tda18218.h (100%)
+ rename drivers/media/{common => }/tuners/tda18218_priv.h (100%)
+ rename drivers/media/{common => }/tuners/tda18271-common.c (100%)
+ rename drivers/media/{common => }/tuners/tda18271-fe.c (100%)
+ rename drivers/media/{common => }/tuners/tda18271-maps.c (100%)
+ rename drivers/media/{common => }/tuners/tda18271-priv.h (100%)
+ rename drivers/media/{common => }/tuners/tda18271.h (100%)
+ rename drivers/media/{common => }/tuners/tda827x.c (100%)
+ rename drivers/media/{common => }/tuners/tda827x.h (100%)
+ rename drivers/media/{common => }/tuners/tda8290.c (100%)
+ rename drivers/media/{common => }/tuners/tda8290.h (100%)
+ rename drivers/media/{common => }/tuners/tda9887.c (100%)
+ rename drivers/media/{common => }/tuners/tda9887.h (100%)
+ rename drivers/media/{common => }/tuners/tea5761.c (100%)
+ rename drivers/media/{common => }/tuners/tea5761.h (100%)
+ rename drivers/media/{common => }/tuners/tea5767.c (100%)
+ rename drivers/media/{common => }/tuners/tea5767.h (100%)
+ rename drivers/media/{common => }/tuners/tua9001.c (100%)
+ rename drivers/media/{common => }/tuners/tua9001.h (100%)
+ rename drivers/media/{common => }/tuners/tua9001_priv.h (100%)
+ rename drivers/media/{common => }/tuners/tuner-i2c.h (100%)
+ rename drivers/media/{common => }/tuners/tuner-simple.c (100%)
+ rename drivers/media/{common => }/tuners/tuner-simple.h (100%)
+ rename drivers/media/{common => }/tuners/tuner-types.c (100%)
+ rename drivers/media/{common => }/tuners/tuner-xc2028-types.h (100%)
+ rename drivers/media/{common => }/tuners/tuner-xc2028.c (99%)
+ rename drivers/media/{common => }/tuners/tuner-xc2028.h (100%)
+ rename drivers/media/{common => }/tuners/xc4000.c (99%)
+ rename drivers/media/{common => }/tuners/xc4000.h (100%)
+ rename drivers/media/{common => }/tuners/xc5000.c (88%)
+ rename drivers/media/{common => }/tuners/xc5000.h (100%)
+ create mode 100644 drivers/media/usb/Kconfig
+ create mode 100644 drivers/media/usb/Makefile
+ rename drivers/media/{video => usb}/au0828/Kconfig (100%)
+ rename drivers/media/{video => usb}/au0828/Makefile (59%)
+ rename drivers/media/{video => usb}/au0828/au0828-cards.c (99%)
+ rename drivers/media/{video => usb}/au0828/au0828-cards.h (100%)
+ rename drivers/media/{video => usb}/au0828/au0828-core.c (85%)
+ rename drivers/media/{video => usb}/au0828/au0828-dvb.c (90%)
+ rename drivers/media/{video => usb}/au0828/au0828-i2c.c (93%)
+ rename drivers/media/{video => usb}/au0828/au0828-reg.h (98%)
+ rename drivers/media/{video => usb}/au0828/au0828-vbi.c (100%)
+ rename drivers/media/{video => usb}/au0828/au0828-video.c (96%)
+ rename drivers/media/{video => usb}/au0828/au0828.h (98%)
+ create mode 100644 drivers/media/usb/b2c2/Kconfig
+ create mode 100644 drivers/media/usb/b2c2/Makefile
+ rename drivers/media/{dvb => usb}/b2c2/flexcop-usb.c (99%)
+ rename drivers/media/{dvb => usb}/b2c2/flexcop-usb.h (100%)
+ rename drivers/media/{video => usb}/cpia2/Kconfig (100%)
+ rename drivers/media/{video => usb}/cpia2/Makefile (100%)
+ rename drivers/media/{video => usb}/cpia2/cpia2.h (100%)
+ rename drivers/media/{video => usb}/cpia2/cpia2_core.c (99%)
+ rename drivers/media/{video => usb}/cpia2/cpia2_registers.h (100%)
+ rename drivers/media/{video => usb}/cpia2/cpia2_usb.c (100%)
+ rename drivers/media/{video => usb}/cpia2/cpia2_v4l.c (97%)
+ rename drivers/media/{video => usb}/cx231xx/Kconfig (100%)
+ rename drivers/media/{video => usb}/cx231xx/Makefile (65%)
+ rename drivers/media/{video => usb}/cx231xx/cx231xx-417.c (99%)
+ rename drivers/media/{video => usb}/cx231xx/cx231xx-audio.c (100%)
+ rename drivers/media/{video => usb}/cx231xx/cx231xx-avcore.c (100%)
+ rename drivers/media/{video => usb}/cx231xx/cx231xx-cards.c (100%)
+ rename drivers/media/{video => usb}/cx231xx/cx231xx-conf-reg.h (100%)
+ rename drivers/media/{video => usb}/cx231xx/cx231xx-core.c (100%)
+ rename drivers/media/{video => usb}/cx231xx/cx231xx-dif.h (100%)
+ rename drivers/media/{video => usb}/cx231xx/cx231xx-dvb.c (100%)
+ rename drivers/media/{video => usb}/cx231xx/cx231xx-i2c.c (100%)
+ rename drivers/media/{video => usb}/cx231xx/cx231xx-input.c (100%)
+ rename drivers/media/{video => usb}/cx231xx/cx231xx-pcb-cfg.c (100%)
+ rename drivers/media/{video => usb}/cx231xx/cx231xx-pcb-cfg.h (100%)
+ rename drivers/media/{video => usb}/cx231xx/cx231xx-reg.h (100%)
+ rename drivers/media/{video => usb}/cx231xx/cx231xx-vbi.c (100%)
+ rename drivers/media/{video => usb}/cx231xx/cx231xx-vbi.h (100%)
+ rename drivers/media/{video => usb}/cx231xx/cx231xx-video.c (98%)
+ rename drivers/media/{video => usb}/cx231xx/cx231xx.h (100%)
+ create mode 100644 drivers/media/usb/dvb-usb-v2/Kconfig
+ create mode 100644 drivers/media/usb/dvb-usb-v2/Makefile
+ create mode 100644 drivers/media/usb/dvb-usb-v2/af9015.c
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/af9015.h (72%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/af9035.c (62%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/af9035.h (96%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/anysee.c (67%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/anysee.h (97%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/au6610.c (64%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/au6610.h (80%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/az6007.c (63%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/ce6230.c (59%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/ce6230.h (60%)
+ create mode 100644 drivers/media/usb/dvb-usb-v2/cypress_firmware.c
+ create mode 100644 drivers/media/usb/dvb-usb-v2/cypress_firmware.h
+ create mode 100644 drivers/media/usb/dvb-usb-v2/dvb_usb.h
+ create mode 100644 drivers/media/usb/dvb-usb-v2/dvb_usb_common.h
+ create mode 100644 drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+ create mode 100644 drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/ec168.c (58%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/ec168.h (65%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/gl861.c (54%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/gl861.h (59%)
+ create mode 100644 drivers/media/usb/dvb-usb-v2/it913x.c
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/lmedm04.c (69%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/lmedm04.h (100%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf-demod.c (100%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf-demod.h (100%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf-gpio.c (100%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf-gpio.h (100%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf-i2c.c (100%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf-i2c.h (100%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf-phy.c (100%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf-phy.h (100%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf-reg.h (100%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf-tuner.c (99%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf-tuner.h (100%)
+ create mode 100644 drivers/media/usb/dvb-usb-v2/mxl111sf.c
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/mxl111sf.h (98%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/rtl28xxu.c (68%)
+ rename drivers/media/{dvb/dvb-usb => usb/dvb-usb-v2}/rtl28xxu.h (92%)
+ create mode 100644 drivers/media/usb/dvb-usb-v2/usb_urb.c
+ rename drivers/media/{dvb => usb}/dvb-usb/Kconfig (71%)
+ create mode 100644 drivers/media/usb/dvb-usb/Makefile
+ rename drivers/media/{dvb => usb}/dvb-usb/a800.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/af9005-fe.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/af9005-remote.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/af9005-script.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/af9005.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/af9005.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/az6027.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/az6027.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/cinergyT2-core.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/cinergyT2-fe.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/cinergyT2.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/cxusb.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/cxusb.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dib0700.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dib0700_core.c (99%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dib0700_devices.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dib07x0.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dibusb-common.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dibusb-mb.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dibusb-mc.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dibusb.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/digitv.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/digitv.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dtt200u-fe.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dtt200u.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dtt200u.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dtv5100.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dtv5100.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dvb-usb-common.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dvb-usb-dvb.c (99%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dvb-usb-firmware.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dvb-usb-i2c.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dvb-usb-init.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dvb-usb-remote.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dvb-usb-urb.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dvb-usb.h (99%)
+ create mode 100644 drivers/media/usb/dvb-usb/dvb_usb_dvb.c
+ create mode 100644 drivers/media/usb/dvb-usb/dvb_usb_remote.c
+ rename drivers/media/{dvb => usb}/dvb-usb/dw2102.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/dw2102.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/friio-fe.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/friio.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/friio.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/gp8psk-fe.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/gp8psk.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/gp8psk.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/m920x.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/m920x.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/nova-t-usb2.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/opera1.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/pctv452e.c (99%)
+ rename drivers/media/{dvb => usb}/dvb-usb/technisat-usb2.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/ttusb2.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/ttusb2.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/umt-010.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/usb-urb.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/vp702x-fe.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/vp702x.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/vp702x.h (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/vp7045-fe.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/vp7045.c (100%)
+ rename drivers/media/{dvb => usb}/dvb-usb/vp7045.h (100%)
+ rename drivers/media/{video => usb}/em28xx/Kconfig (100%)
+ rename drivers/media/{video => usb}/em28xx/Makefile (57%)
+ rename drivers/media/{video => usb}/em28xx/em28xx-audio.c (99%)
+ rename drivers/media/{video => usb}/em28xx/em28xx-cards.c (100%)
+ rename drivers/media/{video => usb}/em28xx/em28xx-core.c (99%)
+ rename drivers/media/{video => usb}/em28xx/em28xx-dvb.c (100%)
+ rename drivers/media/{video => usb}/em28xx/em28xx-i2c.c (100%)
+ rename drivers/media/{video => usb}/em28xx/em28xx-input.c (100%)
+ rename drivers/media/{video => usb}/em28xx/em28xx-reg.h (100%)
+ rename drivers/media/{video => usb}/em28xx/em28xx-vbi.c (100%)
+ rename drivers/media/{video => usb}/em28xx/em28xx-video.c (98%)
+ rename drivers/media/{video => usb}/em28xx/em28xx.h (100%)
+ rename drivers/media/{video => usb}/gspca/Kconfig (98%)
+ rename drivers/media/{video => usb}/gspca/Makefile (100%)
+ rename drivers/media/{video => usb}/gspca/autogain_functions.c (100%)
+ rename drivers/media/{video => usb}/gspca/autogain_functions.h (100%)
+ rename drivers/media/{video => usb}/gspca/benq.c (100%)
+ rename drivers/media/{video => usb}/gspca/conex.c (100%)
+ rename drivers/media/{video => usb}/gspca/cpia1.c (100%)
+ rename drivers/media/{video => usb}/gspca/etoms.c (100%)
+ rename drivers/media/{video => usb}/gspca/finepix.c (100%)
+ rename drivers/media/{video => usb}/gspca/gl860/Kconfig (100%)
+ rename drivers/media/{video => usb}/gspca/gl860/Makefile (75%)
+ rename drivers/media/{video => usb}/gspca/gl860/gl860-mi1320.c (100%)
+ rename drivers/media/{video => usb}/gspca/gl860/gl860-mi2020.c (100%)
+ rename drivers/media/{video => usb}/gspca/gl860/gl860-ov2640.c (100%)
+ rename drivers/media/{video => usb}/gspca/gl860/gl860-ov9655.c (100%)
+ rename drivers/media/{video => usb}/gspca/gl860/gl860.c (100%)
+ rename drivers/media/{video => usb}/gspca/gl860/gl860.h (100%)
+ rename drivers/media/{video => usb}/gspca/gspca.c (100%)
+ rename drivers/media/{video => usb}/gspca/gspca.h (100%)
+ rename drivers/media/{video => usb}/gspca/jeilinj.c (100%)
+ rename drivers/media/{video => usb}/gspca/jl2005bcd.c (100%)
+ rename drivers/media/{video => usb}/gspca/jpeg.h (100%)
+ rename drivers/media/{video => usb}/gspca/kinect.c (100%)
+ rename drivers/media/{video => usb}/gspca/konica.c (100%)
+ rename drivers/media/{video => usb}/gspca/m5602/Kconfig (100%)
+ rename drivers/media/{video => usb}/gspca/m5602/Makefile (80%)
+ rename drivers/media/{video => usb}/gspca/m5602/m5602_bridge.h (100%)
+ rename drivers/media/{video => usb}/gspca/m5602/m5602_core.c (100%)
+ rename drivers/media/{video => usb}/gspca/m5602/m5602_mt9m111.c (100%)
+ rename drivers/media/{video => usb}/gspca/m5602/m5602_mt9m111.h (100%)
+ rename drivers/media/{video => usb}/gspca/m5602/m5602_ov7660.c (100%)
+ rename drivers/media/{video => usb}/gspca/m5602/m5602_ov7660.h (100%)
+ rename drivers/media/{video => usb}/gspca/m5602/m5602_ov9650.c (100%)
+ rename drivers/media/{video => usb}/gspca/m5602/m5602_ov9650.h (100%)
+ rename drivers/media/{video => usb}/gspca/m5602/m5602_po1030.c (100%)
+ rename drivers/media/{video => usb}/gspca/m5602/m5602_po1030.h (100%)
+ rename drivers/media/{video => usb}/gspca/m5602/m5602_s5k4aa.c (100%)
+ rename drivers/media/{video => usb}/gspca/m5602/m5602_s5k4aa.h (100%)
+ rename drivers/media/{video => usb}/gspca/m5602/m5602_s5k83a.c (100%)
+ rename drivers/media/{video => usb}/gspca/m5602/m5602_s5k83a.h (100%)
+ rename drivers/media/{video => usb}/gspca/m5602/m5602_sensor.h (100%)
+ rename drivers/media/{video => usb}/gspca/mars.c (100%)
+ rename drivers/media/{video => usb}/gspca/mr97310a.c (100%)
+ rename drivers/media/{video => usb}/gspca/nw80x.c (100%)
+ rename drivers/media/{video => usb}/gspca/ov519.c (100%)
+ rename drivers/media/{video => usb}/gspca/ov534.c (100%)
+ rename drivers/media/{video => usb}/gspca/ov534_9.c (100%)
+ rename drivers/media/{video => usb}/gspca/pac207.c (100%)
+ rename drivers/media/{video => usb}/gspca/pac7302.c (100%)
+ rename drivers/media/{video => usb}/gspca/pac7311.c (100%)
+ rename drivers/media/{video => usb}/gspca/pac_common.h (100%)
+ rename drivers/media/{video => usb}/gspca/se401.c (100%)
+ rename drivers/media/{video => usb}/gspca/se401.h (100%)
+ rename drivers/media/{video => usb}/gspca/sn9c2028.c (100%)
+ rename drivers/media/{video => usb}/gspca/sn9c2028.h (100%)
+ rename drivers/media/{video => usb}/gspca/sn9c20x.c (100%)
+ rename drivers/media/{video => usb}/gspca/sonixb.c (100%)
+ rename drivers/media/{video => usb}/gspca/sonixj.c (100%)
+ rename drivers/media/{video => usb}/gspca/spca1528.c (100%)
+ rename drivers/media/{video => usb}/gspca/spca500.c (100%)
+ rename drivers/media/{video => usb}/gspca/spca501.c (100%)
+ rename drivers/media/{video => usb}/gspca/spca505.c (100%)
+ rename drivers/media/{video => usb}/gspca/spca506.c (100%)
+ rename drivers/media/{video => usb}/gspca/spca508.c (100%)
+ rename drivers/media/{video => usb}/gspca/spca561.c (100%)
+ rename drivers/media/{video => usb}/gspca/sq905.c (100%)
+ rename drivers/media/{video => usb}/gspca/sq905c.c (97%)
+ rename drivers/media/{video => usb}/gspca/sq930x.c (99%)
+ rename drivers/media/{video => usb}/gspca/stk014.c (100%)
+ rename drivers/media/{video => usb}/gspca/stv0680.c (100%)
+ rename drivers/media/{video => usb}/gspca/stv06xx/Kconfig (100%)
+ rename drivers/media/{video => usb}/gspca/stv06xx/Makefile (78%)
+ rename drivers/media/{video => usb}/gspca/stv06xx/stv06xx.c (100%)
+ rename drivers/media/{video => usb}/gspca/stv06xx/stv06xx.h (100%)
+ rename drivers/media/{video => usb}/gspca/stv06xx/stv06xx_hdcs.c (100%)
+ rename drivers/media/{video => usb}/gspca/stv06xx/stv06xx_hdcs.h (100%)
+ rename drivers/media/{video => usb}/gspca/stv06xx/stv06xx_pb0100.c (100%)
+ rename drivers/media/{video => usb}/gspca/stv06xx/stv06xx_pb0100.h (100%)
+ rename drivers/media/{video => usb}/gspca/stv06xx/stv06xx_sensor.h (100%)
+ rename drivers/media/{video => usb}/gspca/stv06xx/stv06xx_st6422.c (100%)
+ rename drivers/media/{video => usb}/gspca/stv06xx/stv06xx_st6422.h (100%)
+ rename drivers/media/{video => usb}/gspca/stv06xx/stv06xx_vv6410.c (100%)
+ rename drivers/media/{video => usb}/gspca/stv06xx/stv06xx_vv6410.h (100%)
+ rename drivers/media/{video => usb}/gspca/sunplus.c (100%)
+ rename drivers/media/{video => usb}/gspca/t613.c (100%)
+ rename drivers/media/{video => usb}/gspca/topro.c (100%)
+ rename drivers/media/{video => usb}/gspca/tv8532.c (100%)
+ rename drivers/media/{video => usb}/gspca/vc032x.c (99%)
+ rename drivers/media/{video => usb}/gspca/vicam.c (100%)
+ rename drivers/media/{video => usb}/gspca/w996Xcf.c (100%)
+ rename drivers/media/{video => usb}/gspca/xirlink_cit.c (100%)
+ rename drivers/media/{video => usb}/gspca/zc3xx-reg.h (100%)
+ rename drivers/media/{video => usb}/gspca/zc3xx.c (100%)
+ rename drivers/media/{video => usb}/hdpvr/Kconfig (100%)
+ rename drivers/media/{video => usb}/hdpvr/Makefile (81%)
+ rename drivers/media/{video => usb}/hdpvr/hdpvr-control.c (100%)
+ rename drivers/media/{video => usb}/hdpvr/hdpvr-core.c (100%)
+ rename drivers/media/{video => usb}/hdpvr/hdpvr-i2c.c (100%)
+ rename drivers/media/{video => usb}/hdpvr/hdpvr-video.c (100%)
+ rename drivers/media/{video => usb}/hdpvr/hdpvr.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/Kconfig (100%)
+ rename drivers/media/{video => usb}/pvrusb2/Makefile (80%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-audio.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-audio.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-context.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-context.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-cs53l32a.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-cs53l32a.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-ctrl.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-ctrl.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-cx2584x-v4l.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-cx2584x-v4l.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-debug.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-debugifc.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-debugifc.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-devattr.c (97%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-devattr.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-dvb.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-dvb.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-eeprom.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-eeprom.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-encoder.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-encoder.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-fx2-cmd.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-hdw-internal.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-hdw.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-hdw.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-i2c-core.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-i2c-core.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-io.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-io.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-ioread.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-ioread.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-main.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-std.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-std.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-sysfs.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-sysfs.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-util.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-v4l2.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-v4l2.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-video-v4l.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-video-v4l.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-wm8775.c (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2-wm8775.h (100%)
+ rename drivers/media/{video => usb}/pvrusb2/pvrusb2.h (100%)
+ rename drivers/media/{video => usb}/pwc/Kconfig (100%)
+ rename drivers/media/{video => usb}/pwc/Makefile (60%)
+ rename drivers/media/{video => usb}/pwc/philips.txt (100%)
+ rename drivers/media/{video => usb}/pwc/pwc-ctrl.c (100%)
+ rename drivers/media/{video => usb}/pwc/pwc-dec1.c (100%)
+ rename drivers/media/{video => usb}/pwc/pwc-dec1.h (100%)
+ rename drivers/media/{video => usb}/pwc/pwc-dec23.c (100%)
+ rename drivers/media/{video => usb}/pwc/pwc-dec23.h (100%)
+ rename drivers/media/{video => usb}/pwc/pwc-if.c (100%)
+ rename drivers/media/{video => usb}/pwc/pwc-kiara.c (100%)
+ rename drivers/media/{video => usb}/pwc/pwc-kiara.h (100%)
+ rename drivers/media/{video => usb}/pwc/pwc-misc.c (100%)
+ rename drivers/media/{video => usb}/pwc/pwc-nala.h (100%)
+ rename drivers/media/{video => usb}/pwc/pwc-timon.c (100%)
+ rename drivers/media/{video => usb}/pwc/pwc-timon.h (100%)
+ rename drivers/media/{video => usb}/pwc/pwc-uncompress.c (100%)
+ rename drivers/media/{video => usb}/pwc/pwc-v4l.c (100%)
+ rename drivers/media/{video => usb}/pwc/pwc.h (100%)
+ create mode 100644 drivers/media/usb/s2255/Kconfig
+ create mode 100644 drivers/media/usb/s2255/Makefile
+ rename drivers/media/{video => usb/s2255}/s2255drv.c (99%)
+ create mode 100644 drivers/media/usb/siano/Kconfig
+ create mode 100644 drivers/media/usb/siano/Makefile
+ rename drivers/media/{dvb => usb}/siano/smsusb.c (100%)
+ rename drivers/media/{video => usb}/sn9c102/Kconfig (100%)
+ rename drivers/media/{video => usb}/sn9c102/Makefile (100%)
+ rename drivers/media/{video => usb}/sn9c102/sn9c102.h (100%)
+ rename drivers/media/{video => usb}/sn9c102/sn9c102_config.h (100%)
+ rename drivers/media/{video => usb}/sn9c102/sn9c102_core.c (100%)
+ rename drivers/media/{video => usb}/sn9c102/sn9c102_devtable.h (100%)
+ rename drivers/media/{video => usb}/sn9c102/sn9c102_hv7131d.c (100%)
+ rename drivers/media/{video => usb}/sn9c102/sn9c102_hv7131r.c (100%)
+ rename drivers/media/{video => usb}/sn9c102/sn9c102_mi0343.c (100%)
+ rename drivers/media/{video => usb}/sn9c102/sn9c102_mi0360.c (100%)
+ rename drivers/media/{video => usb}/sn9c102/sn9c102_mt9v111.c (100%)
+ rename drivers/media/{video => usb}/sn9c102/sn9c102_ov7630.c (100%)
+ rename drivers/media/{video => usb}/sn9c102/sn9c102_ov7660.c (100%)
+ rename drivers/media/{video => usb}/sn9c102/sn9c102_pas106b.c (100%)
+ rename drivers/media/{video => usb}/sn9c102/sn9c102_pas202bcb.c (100%)
+ rename drivers/media/{video => usb}/sn9c102/sn9c102_sensor.h (100%)
+ rename drivers/media/{video => usb}/sn9c102/sn9c102_tas5110c1b.c (100%)
+ rename drivers/media/{video => usb}/sn9c102/sn9c102_tas5110d.c (100%)
+ rename drivers/media/{video => usb}/sn9c102/sn9c102_tas5130d1b.c (100%)
+ create mode 100644 drivers/media/usb/stk1160/Kconfig
+ create mode 100644 drivers/media/usb/stk1160/Makefile
+ create mode 100644 drivers/media/usb/stk1160/stk1160-ac97.c
+ create mode 100644 drivers/media/usb/stk1160/stk1160-core.c
+ create mode 100644 drivers/media/usb/stk1160/stk1160-i2c.c
+ create mode 100644 drivers/media/usb/stk1160/stk1160-reg.h
+ create mode 100644 drivers/media/usb/stk1160/stk1160-v4l.c
+ create mode 100644 drivers/media/usb/stk1160/stk1160-video.c
+ create mode 100644 drivers/media/usb/stk1160/stk1160.h
+ create mode 100644 drivers/media/usb/stkwebcam/Kconfig
+ create mode 100644 drivers/media/usb/stkwebcam/Makefile
+ rename drivers/media/{video => usb/stkwebcam}/stk-sensor.c (100%)
+ rename drivers/media/{video => usb/stkwebcam}/stk-webcam.c (100%)
+ rename drivers/media/{video => usb/stkwebcam}/stk-webcam.h (100%)
+ rename drivers/media/{video => usb}/tlg2300/Kconfig (100%)
+ create mode 100644 drivers/media/usb/tlg2300/Makefile
+ rename drivers/media/{video => usb}/tlg2300/pd-alsa.c (100%)
+ rename drivers/media/{video => usb}/tlg2300/pd-common.h (100%)
+ rename drivers/media/{video => usb}/tlg2300/pd-dvb.c (100%)
+ rename drivers/media/{video => usb}/tlg2300/pd-main.c (100%)
+ rename drivers/media/{video => usb}/tlg2300/pd-radio.c (100%)
+ rename drivers/media/{video => usb}/tlg2300/pd-video.c (100%)
+ rename drivers/media/{video => usb}/tlg2300/vendorcmds.h (100%)
+ rename drivers/media/{video => usb}/tm6000/Kconfig (100%)
+ rename drivers/media/{video => usb}/tm6000/Makefile (62%)
+ rename drivers/media/{video => usb}/tm6000/tm6000-alsa.c (99%)
+ rename drivers/media/{video => usb}/tm6000/tm6000-cards.c (100%)
+ rename drivers/media/{video => usb}/tm6000/tm6000-core.c (100%)
+ rename drivers/media/{video => usb}/tm6000/tm6000-dvb.c (100%)
+ rename drivers/media/{video => usb}/tm6000/tm6000-i2c.c (100%)
+ rename drivers/media/{video => usb}/tm6000/tm6000-input.c (99%)
+ rename drivers/media/{video => usb}/tm6000/tm6000-regs.h (100%)
+ rename drivers/media/{video => usb}/tm6000/tm6000-stds.c (100%)
+ rename drivers/media/{video => usb}/tm6000/tm6000-usb-isoc.h (100%)
+ rename drivers/media/{video => usb}/tm6000/tm6000-video.c (97%)
+ rename drivers/media/{video => usb}/tm6000/tm6000.h (100%)
+ rename drivers/media/{dvb => usb}/ttusb-budget/Kconfig (100%)
+ create mode 100644 drivers/media/usb/ttusb-budget/Makefile
+ rename drivers/media/{dvb => usb}/ttusb-budget/dvb-ttusb-budget.c (100%)
+ rename drivers/media/{dvb => usb}/ttusb-dec/Kconfig (100%)
+ rename drivers/media/{dvb => usb}/ttusb-dec/Makefile (57%)
+ rename drivers/media/{dvb => usb}/ttusb-dec/ttusb_dec.c (100%)
+ rename drivers/media/{dvb => usb}/ttusb-dec/ttusbdecfe.c (100%)
+ rename drivers/media/{dvb => usb}/ttusb-dec/ttusbdecfe.h (100%)
+ rename drivers/media/{video => usb}/usbvision/Kconfig (100%)
+ rename drivers/media/{video => usb}/usbvision/Makefile (63%)
+ rename drivers/media/{video => usb}/usbvision/usbvision-cards.c (100%)
+ rename drivers/media/{video => usb}/usbvision/usbvision-cards.h (100%)
+ rename drivers/media/{video => usb}/usbvision/usbvision-core.c (100%)
+ rename drivers/media/{video => usb}/usbvision/usbvision-i2c.c (100%)
+ rename drivers/media/{video => usb}/usbvision/usbvision-video.c (97%)
+ rename drivers/media/{video => usb}/usbvision/usbvision.h (100%)
+ rename drivers/media/{video => usb}/uvc/Kconfig (100%)
+ rename drivers/media/{video => usb}/uvc/Makefile (100%)
+ rename drivers/media/{video => usb}/uvc/uvc_ctrl.c (100%)
+ rename drivers/media/{video => usb}/uvc/uvc_debugfs.c (100%)
+ rename drivers/media/{video => usb}/uvc/uvc_driver.c (98%)
+ rename drivers/media/{video => usb}/uvc/uvc_entity.c (100%)
+ rename drivers/media/{video => usb}/uvc/uvc_isight.c (100%)
+ rename drivers/media/{video => usb}/uvc/uvc_queue.c (99%)
+ rename drivers/media/{video => usb}/uvc/uvc_status.c (100%)
+ rename drivers/media/{video => usb}/uvc/uvc_v4l2.c (100%)
+ rename drivers/media/{video => usb}/uvc/uvc_video.c (98%)
+ rename drivers/media/{video => usb}/uvc/uvcvideo.h (98%)
+ create mode 100644 drivers/media/usb/zr364xx/Kconfig
+ create mode 100644 drivers/media/usb/zr364xx/Makefile
+ rename drivers/media/{video => usb/zr364xx}/zr364xx.c (100%)
+ create mode 100644 drivers/media/v4l2-core/Kconfig
+ create mode 100644 drivers/media/v4l2-core/Makefile
+ rename drivers/media/{video => v4l2-core}/tuner-core.c (100%)
+ rename drivers/media/{video => v4l2-core}/v4l2-common.c (99%)
+ rename drivers/media/{video => v4l2-core}/v4l2-compat-ioctl32.c (100%)
+ rename drivers/media/{video => v4l2-core}/v4l2-ctrls.c (100%)
+ rename drivers/media/{video => v4l2-core}/v4l2-dev.c (95%)
+ rename drivers/media/{video => v4l2-core}/v4l2-device.c (100%)
+ rename drivers/media/{video => v4l2-core}/v4l2-event.c (100%)
+ rename drivers/media/{video => v4l2-core}/v4l2-fh.c (100%)
+ rename drivers/media/{video => v4l2-core}/v4l2-int-device.c (100%)
+ rename drivers/media/{video => v4l2-core}/v4l2-ioctl.c (99%)
+ rename drivers/media/{video => v4l2-core}/v4l2-mem2mem.c (100%)
+ rename drivers/media/{video => v4l2-core}/v4l2-subdev.c (100%)
+ rename drivers/media/{video => v4l2-core}/videobuf-core.c (100%)
+ rename drivers/media/{video => v4l2-core}/videobuf-dma-contig.c (100%)
+ rename drivers/media/{video => v4l2-core}/videobuf-dma-sg.c (100%)
+ rename drivers/media/{video => v4l2-core}/videobuf-dvb.c (96%)
+ rename drivers/media/{video => v4l2-core}/videobuf-vmalloc.c (100%)
+ rename drivers/media/{video => v4l2-core}/videobuf2-core.c (98%)
+ rename drivers/media/{video => v4l2-core}/videobuf2-dma-contig.c (100%)
+ rename drivers/media/{video => v4l2-core}/videobuf2-dma-sg.c (100%)
+ rename drivers/media/{video => v4l2-core}/videobuf2-memops.c (100%)
+ rename drivers/media/{video => v4l2-core}/videobuf2-vmalloc.c (99%)
+ delete mode 100644 drivers/media/video/Kconfig
+ delete mode 100644 drivers/media/video/Makefile
+ delete mode 100644 drivers/media/video/bt8xx/Kconfig
+ delete mode 100644 drivers/media/video/bt8xx/Makefile
+ delete mode 100644 drivers/media/video/tlg2300/Makefile
+ delete mode 100644 drivers/staging/media/easycap/Kconfig
+ delete mode 100644 drivers/staging/media/easycap/Makefile
+ delete mode 100644 drivers/staging/media/easycap/README
+ delete mode 100644 drivers/staging/media/easycap/easycap.h
+ delete mode 100644 drivers/staging/media/easycap/easycap_ioctl.c
+ delete mode 100644 drivers/staging/media/easycap/easycap_low.c
+ delete mode 100644 drivers/staging/media/easycap/easycap_main.c
+ delete mode 100644 drivers/staging/media/easycap/easycap_settings.c
+ delete mode 100644 drivers/staging/media/easycap/easycap_sound.c
+ delete mode 100644 drivers/staging/media/easycap/easycap_testcard.c
+ delete mode 100644 drivers/staging/media/lirc/lirc_ene0100.h
+ delete mode 100644 drivers/staging/media/lirc/lirc_ttusbir.c
+ create mode 100644 include/media/ir-rx51.h
+Merging kbuild/for-next (85b170e Merge branches 'kbuild/kconfig' and 'kbuild/misc' into kbuild/for-next)
+$ git merge kbuild/for-next
+Merge made by the 'recursive' strategy.
+Merging kconfig/for-next (45f4c81 localmodconfig: Use my variable for loop in streamline_config.pl)
+$ git merge kconfig/for-next
+Merge made by the 'recursive' strategy.
+ scripts/kconfig/streamline_config.pl |   48 ++++++++++++++++------------------
+ 1 file changed, 22 insertions(+), 26 deletions(-)
+Merging libata/NEXT (1b26d29 [libata] scsi: implement MODE SELECT command)
+$ git merge libata/NEXT
+Merge made by the 'recursive' strategy.
+ drivers/ata/Kconfig       |    2 +-
+ drivers/ata/ahci.c        |    8 ++
+ drivers/ata/ahci.h        |    1 +
+ drivers/ata/ata_piix.c    |    8 ++
+ drivers/ata/libahci.c     |    3 +-
+ drivers/ata/libata-acpi.c |   15 +--
+ drivers/ata/libata-core.c |    5 +-
+ drivers/ata/libata-scsi.c |  255 +++++++++++++++++++++++++++++++++++++++++----
+ drivers/ata/pata_atiixp.c |   16 +++
+ 9 files changed, 275 insertions(+), 38 deletions(-)
+Merging infiniband/for-next (c0369b2 Merge branches 'cma', 'ipoib', 'misc', 'mlx4', 'ocrdma', 'qib' and 'srp' into for-next)
+$ git merge infiniband/for-next
+Already up-to-date.
+Merging acpi/next (9d0b01a Merge branches 'delete-gts-bfs', 'misc', 'novell-bugzilla-757888-numa' and 'osc-pcie' into base)
+$ git merge acpi/next
+Already up-to-date.
+Merging cpuidle/cpuidle-next (3cf7997 acpi: intel_idle : break dependency between modules)
+$ git merge cpuidle/cpuidle-next
+Recorded preimage for 'drivers/cpuidle/coupled.c'
+Auto-merging drivers/cpuidle/coupled.c
+CONFLICT (add/add): Merge conflict in drivers/cpuidle/coupled.c
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+Recorded resolution for 'drivers/cpuidle/coupled.c'.
+[master c2b4031] Merge remote-tracking branch 'cpuidle/cpuidle-next'
+$ git diff -M --stat --summary HEAD^..
+Merging cpupowerutils/master (f166033 cpupower tools: add install target to the debug tools' makefiles)
+$ git merge cpupowerutils/master
+Already up-to-date.
+Merging thermal/next (449488c thermal: Fix potential NULL pointer accesses)
+$ git merge thermal/next
+Auto-merging drivers/acpi/thermal.c
+Merge made by the 'recursive' strategy.
+ Documentation/thermal/sysfs-api.txt                |    9 +-
+ drivers/acpi/thermal.c                             |   93 ++++--
+ drivers/platform/x86/acerhdf.c                     |    5 +-
+ drivers/platform/x86/intel_mid_thermal.c           |    2 +-
+ drivers/power/power_supply_core.c                  |    2 +-
+ drivers/staging/omap-thermal/omap-thermal-common.c |    2 +-
+ drivers/thermal/Kconfig                            |    8 +
+ drivers/thermal/Makefile                           |    3 +-
+ drivers/thermal/rcar_thermal.c                     |  260 ++++++++++++++++
+ drivers/thermal/spear_thermal.c                    |    2 +-
+ drivers/thermal/thermal_sys.c                      |  321 ++++++++++++--------
+ include/linux/thermal.h                            |   28 +-
+ 12 files changed, 576 insertions(+), 159 deletions(-)
+ create mode 100644 drivers/thermal/rcar_thermal.c
+Merging ieee1394/for-next (e3cbd92 firewire: core: document is_local sysfs attribute)
+$ git merge ieee1394/for-next
+Already up-to-date.
+Merging ubi/linux-next (a07ade1 arm: sam9_l9260_defconfig: remove non-existing config option)
+$ git merge ubi/linux-next
+Merge made by the 'recursive' strategy.
+ arch/arm/configs/sam9_l9260_defconfig |    2 +-
+ drivers/mtd/ubi/Kconfig               |   18 +++++--------
+ drivers/mtd/ubi/build.c               |   12 ++++++++-
+ drivers/mtd/ubi/misc.c                |   16 +++++++++---
+ drivers/mtd/ubi/ubi.h                 |    5 ++--
+ drivers/mtd/ubi/wl.c                  |   46 +++++++++++++++++++++------------
+ 6 files changed, 62 insertions(+), 37 deletions(-)
+Merging dlm/next (9c5bef5 dlm: cleanup send_to_sock routine)
+$ git merge dlm/next
+Merge made by the 'recursive' strategy.
+ fs/dlm/ast.c          |    4 +-
+ fs/dlm/config.c       |   79 ++++--------------
+ fs/dlm/config.h       |    2 -
+ fs/dlm/dlm_internal.h |   46 ++++++++---
+ fs/dlm/lockspace.c    |   15 +++-
+ fs/dlm/lowcomms.c     |  215 +++++++++++++++++++++++++++++++++++++++++--------
+ fs/dlm/lowcomms.h     |    2 +
+ fs/dlm/main.c         |    2 +
+ fs/dlm/member.c       |   17 ++--
+ fs/dlm/rcom.c         |    2 +-
+ fs/dlm/recoverd.c     |   27 ++++---
+ fs/dlm/recoverd.h     |    1 -
+ 12 files changed, 282 insertions(+), 130 deletions(-)
+Merging scsi/for-next (641aa03 Merge branch 'misc' into for-next)
+$ git merge scsi/for-next
+Resolved 'drivers/ata/libata-core.c' using previous resolution.
+Auto-merging include/linux/libata.h
+Auto-merging drivers/scsi/scsi_lib.c
+Auto-merging drivers/ata/libata-eh.c
+Auto-merging drivers/ata/libata-core.c
+CONFLICT (content): Merge conflict in drivers/ata/libata-core.c
+Auto-merging Documentation/kernel-parameters.txt
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master df8b5db] Merge remote-tracking branch 'scsi/for-next'
+$ git diff -M --stat --summary HEAD^..
+ Documentation/kernel-parameters.txt         |    3 +
+ Documentation/scsi/ChangeLog.megaraid_sas   |   10 ++
+ drivers/ata/libata-core.c                   |   69 +++++++++----
+ drivers/ata/libata-eh.c                     |    2 +
+ drivers/scsi/ipr.c                          |  149 +++++++++++++++++++--------
+ drivers/scsi/ipr.h                          |    5 +-
+ drivers/scsi/isci/host.c                    |    4 +-
+ drivers/scsi/isci/host.h                    |    2 +-
+ drivers/scsi/isci/init.c                    |   59 ++++++++++-
+ drivers/scsi/isci/phy.c                     |    4 +-
+ drivers/scsi/isci/probe_roms.c              |    1 -
+ drivers/scsi/isci/remote_node_context.h     |    2 +-
+ drivers/scsi/libsas/sas_ata.c               |   91 +++++++++++++++-
+ drivers/scsi/libsas/sas_discover.c          |   69 +++++++++++--
+ drivers/scsi/libsas/sas_dump.c              |    1 +
+ drivers/scsi/libsas/sas_event.c             |    4 +-
+ drivers/scsi/libsas/sas_init.c              |   90 +++++++++++++++-
+ drivers/scsi/libsas/sas_internal.h          |    1 +
+ drivers/scsi/libsas/sas_phy.c               |   21 ++++
+ drivers/scsi/libsas/sas_port.c              |   52 +++++++++-
+ drivers/scsi/megaraid/megaraid_sas.h        |    8 +-
+ drivers/scsi/megaraid/megaraid_sas_base.c   |   42 ++++++--
+ drivers/scsi/megaraid/megaraid_sas_fusion.c |    5 +-
+ drivers/scsi/mpt2sas/Kconfig                |    2 +-
+ drivers/scsi/mpt2sas/mpi/mpi2.h             |   14 ++-
+ drivers/scsi/mpt2sas/mpi/mpi2_init.h        |    9 +-
+ drivers/scsi/mpt2sas/mpi/mpi2_ioc.h         |    8 +-
+ drivers/scsi/mpt2sas/mpi/mpi2_raid.h        |    7 +-
+ drivers/scsi/mpt2sas/mpt2sas_base.c         |   19 ++--
+ drivers/scsi/mpt2sas/mpt2sas_base.h         |   14 +--
+ drivers/scsi/mpt2sas/mpt2sas_config.c       |   38 ++++++-
+ drivers/scsi/mpt2sas/mpt2sas_ctl.c          |   72 ++++++++++++-
+ drivers/scsi/mpt2sas/mpt2sas_ctl.h          |    2 +-
+ drivers/scsi/mpt2sas/mpt2sas_debug.h        |    2 +-
+ drivers/scsi/mpt2sas/mpt2sas_scsih.c        |   30 +++++-
+ drivers/scsi/mpt2sas/mpt2sas_transport.c    |    2 +-
+ drivers/scsi/scsi_lib.c                     |    5 +-
+ include/linux/libata.h                      |   15 ++-
+ include/scsi/libsas.h                       |   20 +++-
+ include/scsi/sas_ata.h                      |   10 ++
+ 40 files changed, 819 insertions(+), 144 deletions(-)
+Merging target-updates/for-next (6a922a3 target: Fix minor spelling typos in drivers/target)
+$ git merge target-updates/for-next
+Auto-merging drivers/infiniband/ulp/srpt/ib_srpt.c
+Merge made by the 'recursive' strategy.
+ Documentation/target/tcm_mod_builder.py      |   16 ---
+ drivers/infiniband/ulp/srpt/ib_srpt.c        |   12 --
+ drivers/scsi/qla2xxx/tcm_qla2xxx.c           |   15 ---
+ drivers/target/iscsi/iscsi_target.c          |   13 +-
+ drivers/target/iscsi/iscsi_target_configfs.c |   25 ----
+ drivers/target/loopback/tcm_loop.c           |   12 --
+ drivers/target/sbp/sbp_target.c              |   20 +--
+ drivers/target/target_core_alua.c            |    2 +-
+ drivers/target/target_core_configfs.c        |   10 +-
+ drivers/target/target_core_device.c          |    6 +-
+ drivers/target/target_core_fabric_lib.c      |    8 +-
+ drivers/target/target_core_pr.c              |    4 +-
+ drivers/target/target_core_pscsi.c           |    2 +-
+ drivers/target/target_core_tpg.c             |    2 +-
+ drivers/target/target_core_transport.c       |  167 ++++++++++++--------------
+ drivers/target/tcm_fc/tfc_conf.c             |   12 --
+ drivers/usb/gadget/tcm_usb_gadget.c          |   12 --
+ drivers/vhost/tcm_vhost.c                    |   13 --
+ include/target/target_core_fabric.h          |    2 -
+ 19 files changed, 99 insertions(+), 254 deletions(-)
+Merging target-merge/for-next-merge (d987569 Linux 3.6-rc2)
+$ git merge target-merge/for-next-merge
+Already up-to-date.
+Merging ibft/linux-next (935a9fe ibft: Fix finding IBFT ACPI table on UEFI)
+$ git merge ibft/linux-next
+Already up-to-date.
+Merging isci/all (6734092 isci: add a couple __iomem annotations)
+$ git merge isci/all
+Already up-to-date.
+Merging slave-dma/next (c87a9fc Merge branch 'fixes_for-3.6' into next)
+$ git merge slave-dma/next
+Merge made by the 'recursive' strategy.
+ drivers/dma/dw_dmac.c      |   53 +++++++++-----------------------------------
+ drivers/dma/dw_dmac_regs.h |    2 --
+ 2 files changed, 10 insertions(+), 45 deletions(-)
+Merging dmaengine/next (a2bd114 netdma: adding alignment check for NETDMA ops)
+$ git merge dmaengine/next
+Already up-to-date.
+Merging net-next/master (5689226 xfrm: Use rcu_dereference_bh to deference pointer protected by rcu_read_lock_bh)
+$ git merge net-next/master
+Auto-merging net/sctp/socket.c
+Auto-merging net/packet/af_packet.c
+Auto-merging net/ipv6/tcp_ipv6.c
+Auto-merging net/ipv4/tcp_ipv4.c
+Auto-merging net/ipv4/tcp_input.c
+Auto-merging net/ipv4/route.c
+Auto-merging net/ipv4/fib_trie.c
+Auto-merging net/core/dev.c
+Auto-merging net/bluetooth/sco.c
+Auto-merging net/bluetooth/rfcomm/sock.c
+Auto-merging net/bluetooth/l2cap_sock.c
+Auto-merging net/bluetooth/l2cap_core.c
+Auto-merging net/bluetooth/hci_sock.c
+Auto-merging net/bluetooth/hci_event.c
+Auto-merging include/net/dst.h
+Auto-merging include/linux/netdevice.h
+Auto-merging include/linux/jiffies.h
+Auto-merging include/linux/if_team.h
+Auto-merging include/linux/Kbuild
+Removing firmware/cxgb3/t3fw-7.10.0.bin.ihex
+Auto-merging drivers/net/wireless/ath/ath5k/mac80211-ops.c
+Auto-merging drivers/net/wireless/ath/ath5k/base.c
+Auto-merging drivers/net/team/team.c
+Auto-merging drivers/net/bonding/bond_main.c
+Auto-merging drivers/bluetooth/btusb.c
+Merge made by the 'recursive' strategy.
+ Documentation/devicetree/bindings/net/cpsw.txt     |  109 ++
+ .../devicetree/bindings/net/davinci-mdio.txt       |   33 +
+ drivers/bcma/driver_chipcommon_pmu.c               |    4 +-
+ drivers/bcma/host_pci.c                            |   11 +-
+ drivers/bcma/host_soc.c                            |    2 +-
+ drivers/bluetooth/bcm203x.c                        |    8 +-
+ drivers/bluetooth/bfusb.c                          |   12 +-
+ drivers/bluetooth/bluecard_cs.c                    |    5 +-
+ drivers/bluetooth/bpa10x.c                         |    8 +-
+ drivers/bluetooth/bt3c_cs.c                        |    5 +-
+ drivers/bluetooth/btmrvl_sdio.c                    |   15 +-
+ drivers/bluetooth/btsdio.c                         |    8 +-
+ drivers/bluetooth/btuart_cs.c                      |    5 +-
+ drivers/bluetooth/btusb.c                          |   13 +-
+ drivers/bluetooth/btwilink.c                       |    8 +-
+ drivers/bluetooth/dtl1_cs.c                        |    3 +-
+ drivers/net/bonding/bond_main.c                    |   20 +-
+ drivers/net/ethernet/ti/Kconfig                    |    4 +-
+ drivers/net/ethernet/ti/cpsw.c                     |  174 +-
+ drivers/net/ethernet/ti/davinci_mdio.c             |   41 +-
+ drivers/net/hyperv/netvsc_drv.c                    |    2 +-
+ drivers/net/hyperv/rndis_filter.c                  |    8 +-
+ drivers/net/loopback.c                             |    1 +
+ drivers/net/ppp/ppp_generic.c                      |   58 +-
+ drivers/net/team/team.c                            |  200 +-
+ drivers/net/veth.c                                 |    3 +
+ drivers/net/virtio_net.c                           |    2 +-
+ drivers/net/wireless/ath/ath5k/ath5k.h             |    2 +-
+ drivers/net/wireless/ath/ath5k/base.c              |    5 +-
+ drivers/net/wireless/ath/ath5k/mac80211-ops.c      |    4 +-
+ drivers/net/wireless/ath/ath5k/phy.c               |   43 +-
+ drivers/net/wireless/ath/ath9k/ar9003_eeprom.c     |  149 +-
+ drivers/net/wireless/ath/ath9k/rc.c                |  812 ++++----
+ drivers/net/wireless/ath/ath9k/rc.h                |    4 -
+ drivers/net/wireless/ath/carl9170/fw.c             |    1 +
+ drivers/net/wireless/ath/carl9170/mac.c            |    2 +-
+ drivers/net/wireless/ath/carl9170/main.c           |    4 +-
+ drivers/net/wireless/ath/carl9170/rx.c             |    1 +
+ drivers/net/wireless/b43/Makefile                  |    1 +
+ drivers/net/wireless/b43/b43.h                     |   10 +-
+ drivers/net/wireless/b43/main.c                    |   51 +-
+ drivers/net/wireless/b43/phy_common.c              |   17 +-
+ drivers/net/wireless/b43/phy_common.h              |    6 +
+ drivers/net/wireless/b43/phy_n.c                   |  668 ++++++-
+ drivers/net/wireless/b43/phy_n.h                   |    1 +
+ drivers/net/wireless/b43/radio_2057.c              |  141 ++
+ drivers/net/wireless/b43/radio_2057.h              |  430 +++++
+ drivers/net/wireless/b43/tables_nphy.c             |   75 +
+ drivers/net/wireless/b43/tables_nphy.h             |   10 +
+ drivers/net/wireless/b43legacy/main.c              |    2 +-
+ .../net/wireless/brcm80211/brcmsmac/mac80211_if.c  |    4 +-
+ drivers/net/wireless/brcm80211/brcmsmac/main.c     |   13 +-
+ .../net/wireless/brcm80211/include/brcmu_wifi.h    |    5 -
+ drivers/net/wireless/iwlegacy/common.c             |   15 +-
+ drivers/net/wireless/iwlegacy/common.h             |    2 -
+ drivers/net/wireless/mwifiex/11n.c                 |   26 +
+ drivers/net/wireless/mwifiex/11n.h                 |   15 +
+ drivers/net/wireless/mwifiex/11n_aggr.c            |   14 +-
+ drivers/net/wireless/mwifiex/11n_rxreorder.c       |   66 +-
+ drivers/net/wireless/mwifiex/11n_rxreorder.h       |    5 +
+ drivers/net/wireless/mwifiex/Makefile              |    2 +
+ drivers/net/wireless/mwifiex/cfg80211.c            |   17 +-
+ drivers/net/wireless/mwifiex/cmdevt.c              |    5 +-
+ drivers/net/wireless/mwifiex/decl.h                |    3 +
+ drivers/net/wireless/mwifiex/fw.h                  |   42 +-
+ drivers/net/wireless/mwifiex/init.c                |  107 +-
+ drivers/net/wireless/mwifiex/ioctl.h               |    5 +-
+ drivers/net/wireless/mwifiex/main.c                |    3 +
+ drivers/net/wireless/mwifiex/main.h                |   38 +-
+ drivers/net/wireless/mwifiex/scan.c                |    6 +-
+ drivers/net/wireless/mwifiex/sta_cmd.c             |   55 +-
+ drivers/net/wireless/mwifiex/sta_event.c           |   64 +-
+ drivers/net/wireless/mwifiex/sta_ioctl.c           |   12 +-
+ drivers/net/wireless/mwifiex/sta_rx.c              |   38 +-
+ drivers/net/wireless/mwifiex/txrx.c                |    5 +
+ drivers/net/wireless/mwifiex/uap_cmd.c             |    1 +
+ drivers/net/wireless/mwifiex/uap_event.c           |  290 +++
+ drivers/net/wireless/mwifiex/uap_txrx.c            |  255 +++
+ drivers/net/wireless/mwifiex/wmm.c                 |   59 +-
+ drivers/net/wireless/p54/eeprom.c                  |  108 +-
+ drivers/net/wireless/p54/eeprom.h                  |   12 +
+ drivers/net/wireless/p54/p54pci.c                  |   88 +-
+ drivers/net/wireless/p54/p54pci.h                  |    1 +
+ drivers/net/xen-netfront.c                         |    2 +-
+ drivers/ssb/driver_mipscore.c                      |   28 +-
+ firmware/Makefile                                  |    1 -
+ firmware/cxgb3/t3fw-7.10.0.bin.ihex                | 1935 --------------------
+ include/linux/Kbuild                               |    1 +
+ include/linux/bcma/bcma_driver_chipcommon.h        |   85 +
+ include/linux/bcma/bcma_regs.h                     |    2 +
+ include/linux/hash.h                               |   10 +
+ include/linux/if_arp.h                             |    1 +
+ include/linux/if_team.h                            |    7 +
+ include/linux/if_tunnel.h                          |    3 +
+ include/linux/inetdevice.h                         |   11 +-
+ include/linux/ip6_tunnel.h                         |   17 +
+ include/linux/jiffies.h                            |    6 +
+ include/linux/netdevice.h                          |    5 +-
+ include/linux/packet_diag.h                        |   57 +
+ include/linux/skbuff.h                             |    9 +-
+ include/linux/snmp.h                               |   12 +-
+ include/linux/ssb/ssb_driver_chipcommon.h          |    4 +-
+ include/net/arp.h                                  |    3 +-
+ include/net/bluetooth/bluetooth.h                  |   10 +
+ include/net/bluetooth/hci.h                        |   11 +
+ include/net/bluetooth/hci_core.h                   |   22 +-
+ include/net/bluetooth/l2cap.h                      |   17 +-
+ include/net/bluetooth/smp.h                        |    8 +-
+ include/net/dst.h                                  |   10 +-
+ include/net/ip6_tunnel.h                           |   41 +-
+ include/net/ipv6.h                                 |    1 +
+ include/net/ndisc.h                                |    3 +-
+ include/net/neighbour.h                            |   14 +-
+ include/net/net_namespace.h                        |   12 +
+ include/net/netlink.h                              |   98 +
+ include/net/netns/sctp.h                           |  131 ++
+ include/net/sctp/sctp.h                            |   69 +-
+ include/net/sctp/sm.h                              |    8 +-
+ include/net/sctp/structs.h                         |  154 +-
+ include/net/snmp.h                                 |   10 +-
+ include/net/xfrm.h                                 |    2 +-
+ net/bluetooth/a2mp.c                               |   16 +-
+ net/bluetooth/af_bluetooth.c                       |  141 ++
+ net/bluetooth/bnep/sock.c                          |   22 +-
+ net/bluetooth/cmtp/sock.c                          |   23 +-
+ net/bluetooth/hci_core.c                           |    6 +-
+ net/bluetooth/hci_event.c                          |   93 +-
+ net/bluetooth/hci_sock.c                           |   13 +-
+ net/bluetooth/hidp/sock.c                          |   22 +-
+ net/bluetooth/l2cap_core.c                         |   32 +-
+ net/bluetooth/l2cap_sock.c                         |   22 +-
+ net/bluetooth/mgmt.c                               |   34 +-
+ net/bluetooth/rfcomm/sock.c                        |   14 +-
+ net/bluetooth/sco.c                                |   16 +-
+ net/bridge/br_fdb.c                                |    2 +-
+ net/bridge/br_stp_timer.c                          |    2 +-
+ net/core/dev.c                                     |   29 +-
+ net/core/rtnetlink.c                               |   14 +-
+ net/decnet/dn_route.c                              |    6 +-
+ net/ipv4/af_inet.c                                 |    4 +-
+ net/ipv4/devinet.c                                 |   39 +-
+ net/ipv4/fib_frontend.c                            |    2 +-
+ net/ipv4/fib_trie.c                                |   13 +-
+ net/ipv4/igmp.c                                    |    7 +-
+ net/ipv4/ipmr.c                                    |    2 +-
+ net/ipv4/netfilter/ipt_rpfilter.c                  |    2 +-
+ net/ipv4/route.c                                   |   17 +-
+ net/ipv4/tcp_input.c                               |    9 +-
+ net/ipv4/tcp_ipv4.c                                |   13 +-
+ net/ipv6/Kconfig                                   |   16 +
+ net/ipv6/Makefile                                  |    1 +
+ net/ipv6/ip6_gre.c                                 | 1790 ++++++++++++++++++
+ net/ipv6/ip6_tunnel.c                              |   89 +-
+ net/ipv6/route.c                                   |    2 +-
+ net/ipv6/tcp_ipv6.c                                |    9 +-
+ net/key/af_key.c                                   |    4 +-
+ net/mac80211/mesh.c                                |   21 +-
+ net/mac80211/mesh.h                                |    2 +-
+ net/mac80211/mesh_plink.c                          |   44 +-
+ net/packet/Kconfig                                 |    8 +
+ net/packet/Makefile                                |    2 +
+ net/packet/af_packet.c                             |   99 +-
+ net/packet/diag.c                                  |  176 ++
+ net/packet/internal.h                              |  103 ++
+ net/sched/sch_generic.c                            |   18 -
+ net/sctp/associola.c                               |   25 +-
+ net/sctp/auth.c                                    |   20 +-
+ net/sctp/bind_addr.c                               |   20 +-
+ net/sctp/chunk.c                                   |    2 +-
+ net/sctp/endpointola.c                             |   25 +-
+ net/sctp/input.c                                   |  115 +-
+ net/sctp/ipv6.c                                    |   36 +-
+ net/sctp/objcnt.c                                  |    8 +-
+ net/sctp/output.c                                  |    2 +-
+ net/sctp/outqueue.c                                |   18 +-
+ net/sctp/primitive.c                               |    4 +-
+ net/sctp/proc.c                                    |   55 +-
+ net/sctp/protocol.c                                |  454 ++---
+ net/sctp/sm_make_chunk.c                           |   61 +-
+ net/sctp/sm_sideeffect.c                           |   26 +-
+ net/sctp/sm_statefuns.c                            |  725 ++++----
+ net/sctp/sm_statetable.c                           |   17 +-
+ net/sctp/socket.c                                  |  119 +-
+ net/sctp/sysctl.c                                  |  198 +-
+ net/sctp/transport.c                               |   23 +-
+ net/sctp/ulpqueue.c                                |   18 +-
+ net/xfrm/xfrm_policy.c                             |   39 +-
+ net/xfrm/xfrm_state.c                              |    2 +-
+ net/xfrm/xfrm_user.c                               |    9 +-
+ 189 files changed, 8014 insertions(+), 4408 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/net/cpsw.txt
+ create mode 100644 Documentation/devicetree/bindings/net/davinci-mdio.txt
+ create mode 100644 drivers/net/wireless/b43/radio_2057.c
+ create mode 100644 drivers/net/wireless/b43/radio_2057.h
+ create mode 100644 drivers/net/wireless/mwifiex/uap_event.c
+ create mode 100644 drivers/net/wireless/mwifiex/uap_txrx.c
+ delete mode 100644 firmware/cxgb3/t3fw-7.10.0.bin.ihex
+ create mode 100644 include/linux/packet_diag.h
+ create mode 100644 include/net/netns/sctp.h
+ create mode 100644 net/ipv6/ip6_gre.c
+ create mode 100644 net/packet/diag.c
+ create mode 100644 net/packet/internal.h
+Merging wireless-next/master (22c5649 p54: fix powerpc gcc warnings)
+$ git merge wireless-next/master
+Already up-to-date.
+Merging bluetooth/master (b691f1a Bluetooth: mgmt: Add device disconnect reason)
+$ git merge bluetooth/master
+Auto-merging net/bluetooth/hci_event.c
+Merge made by the 'recursive' strategy.
+ include/net/bluetooth/hci.h      |    3 ++
+ include/net/bluetooth/hci_core.h |    4 +-
+ include/net/bluetooth/mgmt.h     |    9 ++++
+ net/bluetooth/af_bluetooth.c     |   20 +++-----
+ net/bluetooth/hci_conn.c         |   99 ++++++++++++++++++++++++--------------
+ net/bluetooth/hci_event.c        |   32 +++++++++---
+ net/bluetooth/mgmt.c             |    9 ++--
+ 7 files changed, 114 insertions(+), 62 deletions(-)
+Merging mtd/master (4800399 mtd: m25p80: Add support for serial flash STM/Micron N25Q032)
+$ git merge mtd/master
+Auto-merging drivers/mtd/nand/Kconfig
+Auto-merging drivers/mtd/mtdoops.c
+Removing drivers/mtd/maps/wr_sbc82xx_flash.c
+Auto-merging arch/arm/mach-imx/clk-imx51-imx53.c
+Auto-merging arch/arm/boot/dts/imx53.dtsi
+Auto-merging arch/arm/boot/dts/imx51.dtsi
+Merge made by the 'recursive' strategy.
+ Documentation/DocBook/mtdnand.tmpl                 |    2 -
+ .../devicetree/bindings/mtd/atmel-nand.txt         |   40 +-
+ .../devicetree/bindings/mtd/gpmi-nand.txt          |    4 +
+ .../devicetree/bindings/mtd/lpc32xx-mlc.txt        |   50 +
+ .../devicetree/bindings/mtd/lpc32xx-slc.txt        |   52 +
+ arch/arm/boot/dts/imx51.dtsi                       |    7 +
+ arch/arm/boot/dts/imx53.dtsi                       |    7 +
+ arch/arm/mach-imx/clk-imx51-imx53.c                |    2 +
+ arch/arm/plat-mxc/devices/platform-mxc_nand.c      |   11 +-
+ drivers/mtd/chips/Kconfig                          |   11 +-
+ drivers/mtd/chips/cfi_cmdset_0002.c                |   67 ++
+ drivers/mtd/devices/Kconfig                        |    2 +-
+ drivers/mtd/devices/m25p80.c                       |    6 +
+ drivers/mtd/devices/spear_smi.c                    |   54 +-
+ drivers/mtd/maps/Kconfig                           |   12 -
+ drivers/mtd/maps/Makefile                          |    1 -
+ drivers/mtd/maps/wr_sbc82xx_flash.c                |  174 ----
+ drivers/mtd/mtdcore.c                              |    9 +
+ drivers/mtd/mtdoops.c                              |   14 +-
+ drivers/mtd/nand/Kconfig                           |   62 +-
+ drivers/mtd/nand/Makefile                          |    2 +
+ drivers/mtd/nand/atmel_nand.c                      |  934 +++++++++++++++--
+ drivers/mtd/nand/atmel_nand_ecc.h                  |  114 ++-
+ drivers/mtd/nand/bcm_umi_bch.c                     |    6 +-
+ drivers/mtd/nand/bf5xx_nand.c                      |    6 +-
+ drivers/mtd/nand/cafe_nand.c                       |   13 +-
+ drivers/mtd/nand/denali.c                          |   12 +-
+ drivers/mtd/nand/docg4.c                           |    8 +-
+ drivers/mtd/nand/fsl_elbc_nand.c                   |   15 +-
+ drivers/mtd/nand/fsl_ifc_nand.c                    |    5 +-
+ drivers/mtd/nand/gpmi-nand/gpmi-nand.c             |   13 +-
+ drivers/mtd/nand/lpc32xx_mlc.c                     |  925 +++++++++++++++++
+ drivers/mtd/nand/lpc32xx_slc.c                     | 1059 ++++++++++++++++++++
+ drivers/mtd/nand/mxc_nand.c                        |  141 +--
+ drivers/mtd/nand/nand_base.c                       |   50 +-
+ drivers/mtd/nand/nand_bbt.c                        |   21 +-
+ drivers/mtd/nand/nand_ids.c                        |    7 +-
+ drivers/mtd/nand/pxa3xx_nand.c                     |    5 +-
+ drivers/mtd/nand/sh_flctl.c                        |  302 +++---
+ drivers/mtd/tests/mtd_speedtest.c                  |   16 +-
+ drivers/mtd/tests/mtd_stresstest.c                 |   39 +-
+ include/linux/mtd/bbm.h                            |    7 +-
+ include/linux/mtd/mtd.h                            |    9 +-
+ include/linux/mtd/nand.h                           |   11 +-
+ include/linux/mtd/sh_flctl.h                       |   23 +-
+ 45 files changed, 3653 insertions(+), 677 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt
+ create mode 100644 Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt
+ delete mode 100644 drivers/mtd/maps/wr_sbc82xx_flash.c
+ create mode 100644 drivers/mtd/nand/lpc32xx_mlc.c
+ create mode 100644 drivers/mtd/nand/lpc32xx_slc.c
+Merging l2-mtd/master (31311c4 mtd: s3c2410: Fix line over 80 characters warning)
+$ git merge l2-mtd/master
+Merge made by the 'recursive' strategy.
+ arch/arm/mach-clps711x/autcpu12.c      |   19 ++++
+ drivers/mtd/devices/m25p80.c           |   11 +--
+ drivers/mtd/devices/spear_smi.c        |    4 +-
+ drivers/mtd/maps/Kconfig               |    2 +-
+ drivers/mtd/maps/autcpu12-nvram.c      |  153 ++++++++++++++++++--------------
+ drivers/mtd/mtdcore.c                  |   14 ++-
+ drivers/mtd/nand/Kconfig               |    2 +-
+ drivers/mtd/nand/atmel_nand.c          |   62 ++++++++++++-
+ drivers/mtd/nand/docg4.c               |   33 ++-----
+ drivers/mtd/nand/gpmi-nand/gpmi-lib.c  |   45 ++++++++--
+ drivers/mtd/nand/gpmi-nand/gpmi-nand.c |   82 +++++++++++++++--
+ drivers/mtd/nand/gpmi-nand/gpmi-nand.h |    3 +-
+ drivers/mtd/nand/lpc32xx_mlc.c         |   13 ++-
+ drivers/mtd/nand/lpc32xx_slc.c         |   13 ++-
+ drivers/mtd/nand/nand_base.c           |    7 +-
+ drivers/mtd/nand/nand_bbt.c            |   91 +++++++++----------
+ drivers/mtd/nand/omap2.c               |   10 +--
+ drivers/mtd/nand/s3c2410.c             |  134 +++++++++++++---------------
+ drivers/mtd/nand/sh_flctl.c            |   30 ++++---
+ include/linux/mtd/lpc32xx_mlc.h        |   20 +++++
+ include/linux/mtd/lpc32xx_slc.h        |   20 +++++
+ include/linux/mtd/nand.h               |    3 -
+ include/linux/mtd/sh_flctl.h           |    2 +-
+ 23 files changed, 501 insertions(+), 272 deletions(-)
+ create mode 100644 include/linux/mtd/lpc32xx_mlc.h
+ create mode 100644 include/linux/mtd/lpc32xx_slc.h
+Merging crypto/master (35a1fc1 powerpc/crypto: add 842 crypto driver)
+$ git merge crypto/master
+Auto-merging crypto/cast6_generic.c
+Auto-merging crypto/cast5_generic.c
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ MAINTAINERS                                |    6 +
+ arch/powerpc/configs/ppc64_defconfig       |    3 +-
+ arch/powerpc/configs/pseries_defconfig     |    3 +-
+ arch/powerpc/kernel/prom_init.c            |    4 +-
+ arch/s390/crypto/aes_s390.c                |    5 -
+ arch/s390/crypto/des_s390.c                |   10 -
+ arch/s390/crypto/ghash_s390.c              |    1 -
+ arch/x86/crypto/Makefile                   |    4 +
+ arch/x86/crypto/aes_glue.c                 |    1 -
+ arch/x86/crypto/aesni-intel_glue.c         |    5 +-
+ arch/x86/crypto/blowfish_glue.c            |    4 -
+ arch/x86/crypto/camellia_glue.c            |    6 -
+ arch/x86/crypto/cast5-avx-x86_64-asm_64.S  |  322 ++++
+ arch/x86/crypto/cast5_avx_glue.c           |  530 ++++++
+ arch/x86/crypto/cast6-avx-x86_64-asm_64.S  |  335 ++++
+ arch/x86/crypto/cast6_avx_glue.c           |  648 +++++++
+ arch/x86/crypto/ghash-clmulni-intel_glue.c |    2 -
+ arch/x86/crypto/salsa20_glue.c             |    1 -
+ arch/x86/crypto/serpent_avx_glue.c         |   10 -
+ arch/x86/crypto/serpent_sse2_glue.c        |   10 -
+ arch/x86/crypto/twofish_avx_glue.c         |   10 -
+ arch/x86/crypto/twofish_glue.c             |    1 -
+ arch/x86/crypto/twofish_glue_3way.c        |    5 -
+ crypto/842.c                               |  183 ++
+ crypto/Kconfig                             |   40 +
+ crypto/Makefile                            |    5 +-
+ crypto/aes_generic.c                       |    1 -
+ crypto/ansi_cprng.c                        |   63 +-
+ crypto/anubis.c                            |    1 -
+ crypto/blowfish_generic.c                  |    1 -
+ crypto/camellia_generic.c                  |    1 -
+ crypto/{cast5.c => cast5_generic.c}        |   80 +-
+ crypto/{cast6.c => cast6_generic.c}        |   67 +-
+ crypto/crypto_null.c                       |   57 +-
+ crypto/deflate.c                           |    1 -
+ crypto/des_generic.c                       |   25 +-
+ crypto/fcrypt.c                            |    1 -
+ crypto/ghash-generic.c                     |    1 -
+ crypto/khazad.c                            |    1 -
+ crypto/krng.c                              |    1 -
+ crypto/lzo.c                               |    1 -
+ crypto/salsa20_generic.c                   |    1 -
+ crypto/seed.c                              |    1 -
+ crypto/serpent_generic.c                   |   53 +-
+ crypto/sha256_generic.c                    |   25 +-
+ crypto/sha512_generic.c                    |   20 +-
+ crypto/shash.c                             |   36 +
+ crypto/tcrypt.c                            |   82 +
+ crypto/tcrypt.h                            |    1 +
+ crypto/tea.c                               |   41 +-
+ crypto/testmgr.c                           |  210 +++
+ crypto/testmgr.h                           | 2538 ++++++++++++++++++++++++++--
+ crypto/tgr192.c                            |   38 +-
+ crypto/twofish_generic.c                   |    1 -
+ crypto/wp512.c                             |   39 +-
+ drivers/crypto/Kconfig                     |   20 +-
+ drivers/crypto/atmel-aes.c                 |    2 -
+ drivers/crypto/atmel-tdes.c                |    1 -
+ drivers/crypto/caam/caamalg.c              |    8 +-
+ drivers/crypto/caam/caamhash.c             |   18 +-
+ drivers/crypto/caam/caamrng.c              |    9 +-
+ drivers/crypto/caam/jr.c                   |   10 +-
+ drivers/crypto/geode-aes.c                 |    3 -
+ drivers/crypto/nx/Kconfig                  |   26 +
+ drivers/crypto/nx/Makefile                 |    5 +-
+ drivers/crypto/nx/nx-842.c                 | 1615 ++++++++++++++++++
+ drivers/crypto/nx/nx-aes-cbc.c             |    1 -
+ drivers/crypto/nx/nx-aes-ccm.c             |    2 -
+ drivers/crypto/nx/nx-aes-ctr.c             |    2 -
+ drivers/crypto/nx/nx-aes-ecb.c             |    1 -
+ drivers/crypto/nx/nx-aes-gcm.c             |    2 -
+ drivers/crypto/omap-aes.c                  |    1 -
+ drivers/crypto/padlock-aes.c               |    3 -
+ drivers/crypto/s5p-sss.c                   |    1 -
+ drivers/crypto/tegra-aes.c                 |    2 -
+ include/crypto/cast5.h                     |   22 +
+ include/crypto/cast6.h                     |   23 +
+ include/crypto/internal/hash.h             |    2 +
+ include/linux/nx842.h                      |   11 +
+ 79 files changed, 6702 insertions(+), 630 deletions(-)
+ create mode 100644 arch/x86/crypto/cast5-avx-x86_64-asm_64.S
+ create mode 100644 arch/x86/crypto/cast5_avx_glue.c
+ create mode 100644 arch/x86/crypto/cast6-avx-x86_64-asm_64.S
+ create mode 100644 arch/x86/crypto/cast6_avx_glue.c
+ create mode 100644 crypto/842.c
+ rename crypto/{cast5.c => cast5_generic.c} (95%)
+ rename crypto/{cast6.c => cast6_generic.c} (94%)
+ create mode 100644 drivers/crypto/nx/Kconfig
+ create mode 100644 drivers/crypto/nx/nx-842.c
+ create mode 100644 include/crypto/cast5.h
+ create mode 100644 include/crypto/cast6.h
+ create mode 100644 include/linux/nx842.h
+Merging drm/drm-next (e2f895f Merge branch 'exynos-drm-next' of git://git.infradead.org/users/kmpark/linux-samsung into drm-next)
+$ git merge drm/drm-next
+Already up-to-date!
+Merge made by the 'recursive' strategy.
+Merging sound/for-next (1c86845 ALSA: hda - Add 3stack-automute model to AD1882 codec)
+$ git merge sound/for-next
+Auto-merging sound/pci/hda/hda_proc.c
+Auto-merging sound/pci/hda/hda_intel.c
+Auto-merging sound/pci/hda/hda_codec.c
+Auto-merging sound/pci/cs46xx/cs46xx_lib.c
+Merge made by the 'recursive' strategy.
+ Documentation/sound/alsa/HD-Audio-Models.txt |    3 +-
+ include/sound/emu10k1.h                      |    4 +-
+ include/sound/initval.h                      |   14 +++++
+ sound/isa/gus/interwave.c                    |    5 +-
+ sound/isa/opti9xx/miro.c                     |   15 +----
+ sound/isa/opti9xx/opti92x-ad1848.c           |   14 +----
+ sound/pci/ali5451/ali5451.c                  |   10 ++--
+ sound/pci/als300.c                           |    2 +-
+ sound/pci/als4000.c                          |    4 +-
+ sound/pci/asihpi/asihpi.c                    |    2 +-
+ sound/pci/atiixp.c                           |    6 +-
+ sound/pci/atiixp_modem.c                     |    6 +-
+ sound/pci/azt3328.c                          |    6 +-
+ sound/pci/ca0106/ca0106.h                    |    4 +-
+ sound/pci/ca0106/ca0106_main.c               |    2 +-
+ sound/pci/ca0106/ca0106_mixer.c              |    4 +-
+ sound/pci/cmipci.c                           |    6 +-
+ sound/pci/cs4281.c                           |    6 +-
+ sound/pci/cs46xx/cs46xx.c                    |    2 +-
+ sound/pci/cs46xx/cs46xx.h                    |    2 +-
+ sound/pci/cs46xx/cs46xx_lib.c                |    8 +--
+ sound/pci/cs46xx/cs46xx_lib.h                |    2 +-
+ sound/pci/cs46xx/dsp_spos.c                  |    8 +--
+ sound/pci/cs46xx/dsp_spos_scb_lib.c          |    2 +-
+ sound/pci/cs5535audio/Makefile               |    2 +-
+ sound/pci/cs5535audio/cs5535audio.c          |    2 +-
+ sound/pci/ctxfi/ctatc.c                      |    4 +-
+ sound/pci/ctxfi/ctatc.h                      |    2 +-
+ sound/pci/ctxfi/cthardware.h                 |    2 +-
+ sound/pci/ctxfi/cthw20k1.c                   |    4 +-
+ sound/pci/ctxfi/cthw20k2.c                   |    4 +-
+ sound/pci/ctxfi/ctmixer.c                    |    4 +-
+ sound/pci/ctxfi/ctmixer.h                    |    2 +-
+ sound/pci/ctxfi/ctpcm.c                      |    2 +-
+ sound/pci/ctxfi/xfi.c                        |    2 +-
+ sound/pci/echoaudio/echoaudio.c              |   12 ++--
+ sound/pci/echoaudio/echoaudio.h              |    2 +-
+ sound/pci/emu10k1/emu10k1.c                  |    4 +-
+ sound/pci/emu10k1/emu10k1_main.c             |    8 +--
+ sound/pci/emu10k1/emufx.c                    |    2 +-
+ sound/pci/emu10k1/p16v.c                     |    2 +-
+ sound/pci/ens1370.c                          |    4 +-
+ sound/pci/es1938.c                           |    6 +-
+ sound/pci/es1968.c                           |   12 ++--
+ sound/pci/fm801.c                            |    6 +-
+ sound/pci/hda/hda_codec.c                    |    2 +-
+ sound/pci/hda/hda_codec.h                    |    6 +-
+ sound/pci/hda/hda_hwdep.c                    |   39 +++++--------
+ sound/pci/hda/hda_intel.c                    |   78 +++++++++++++++++++++-----
+ sound/pci/hda/hda_proc.c                     |    9 ++-
+ sound/pci/hda/patch_analog.c                 |   40 +++++++++++++
+ sound/pci/ice1712/aureon.c                   |    4 +-
+ sound/pci/ice1712/ice1712.h                  |    2 +-
+ sound/pci/ice1712/ice1724.c                  |    4 +-
+ sound/pci/ice1712/juli.c                     |    4 +-
+ sound/pci/ice1712/prodigy_hifi.c             |    4 +-
+ sound/pci/intel8x0.c                         |    4 +-
+ sound/pci/intel8x0m.c                        |    4 +-
+ sound/pci/maestro3.c                         |   10 ++--
+ sound/pci/nm256/nm256.c                      |    4 +-
+ sound/pci/oxygen/oxygen.c                    |    2 +-
+ sound/pci/oxygen/oxygen.h                    |    2 +-
+ sound/pci/oxygen/oxygen_lib.c                |    4 +-
+ sound/pci/oxygen/virtuoso.c                  |    2 +-
+ sound/pci/riptide/riptide.c                  |    6 +-
+ sound/pci/sis7019.c                          |    6 +-
+ sound/pci/trident/trident.c                  |    2 +-
+ sound/pci/trident/trident_main.c             |    4 +-
+ sound/pci/via82xx.c                          |   10 ++--
+ sound/pci/via82xx_modem.c                    |    4 +-
+ sound/pci/vx222/vx222.c                      |    2 +-
+ sound/pci/ymfpci/ymfpci.c                    |    2 +-
+ sound/pci/ymfpci/ymfpci.h                    |    2 +-
+ sound/pci/ymfpci/ymfpci_main.c               |    8 +--
+ sound/usb/6fire/firmware.c                   |    5 +-
+ 75 files changed, 289 insertions(+), 211 deletions(-)
+Merging sound-asoc/for-next (6664923 Merge branches 'for-3.6' and 'for-3.7' into asoc-next)
+$ git merge sound-asoc/for-next
+Removing sound/soc/omap/overo.c
+Removing sound/soc/omap/omap3evm.c
+Removing sound/soc/omap/omap3beagle.c
+Removing sound/soc/omap/igep0020.c
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ Documentation/devicetree/bindings/sound/cs4270.txt |   21 ++
+ .../devicetree/bindings/sound/omap-abe-twl6040.txt |   91 +++++
+ .../devicetree/bindings/sound/omap-twl4030.txt     |   17 +
+ MAINTAINERS                                        |    7 +-
+ arch/arm/mach-omap2/board-cm-t35.c                 |    1 +
+ arch/arm/mach-omap2/board-devkit8000.c             |    1 +
+ arch/arm/mach-omap2/board-igep0020.c               |    1 +
+ arch/arm/mach-omap2/board-omap3beagle.c            |    1 +
+ arch/arm/mach-omap2/board-omap3evm.c               |    1 +
+ arch/arm/mach-omap2/board-overo.c                  |    1 +
+ arch/arm/mach-omap2/twl-common.c                   |   27 ++
+ arch/arm/mach-omap2/twl-common.h                   |    2 +
+ include/linux/platform_data/omap-twl4030.h         |   32 ++
+ sound/soc/blackfin/bf6xx-sport.c                   |    7 +
+ sound/soc/codecs/ab8500-codec.c                    |    6 +-
+ sound/soc/codecs/adau1373.c                        |   12 +-
+ sound/soc/codecs/adau1701.c                        |   12 +-
+ sound/soc/codecs/ak4671.c                          |   12 +-
+ sound/soc/codecs/arizona.c                         |   66 ++++
+ sound/soc/codecs/arizona.h                         |    6 +-
+ sound/soc/codecs/cs4270.c                          |   40 ++-
+ sound/soc/codecs/cs42l51.c                         |   19 +-
+ sound/soc/codecs/cs42l52.c                         |    1 -
+ sound/soc/codecs/isabelle.c                        |    1 -
+ sound/soc/codecs/lm4857.c                          |   12 +-
+ sound/soc/codecs/max98088.c                        |   18 +-
+ sound/soc/codecs/max98095.c                        |   18 +-
+ sound/soc/codecs/max9850.c                         |   12 +-
+ sound/soc/codecs/max9877.c                         |   12 +-
+ sound/soc/codecs/sta32x.c                          |   12 +-
+ sound/soc/codecs/sta529.c                          |    2 +-
+ sound/soc/codecs/tlv320aic32x4.c                   |   19 +-
+ sound/soc/codecs/tlv320aic3x.c                     |   18 +-
+ sound/soc/codecs/tlv320dac33.c                     |   19 +-
+ sound/soc/codecs/tpa6130a2.c                       |   13 +-
+ sound/soc/codecs/wm2000.c                          |   12 +-
+ sound/soc/codecs/wm2200.c                          |   12 +-
+ sound/soc/codecs/wm5102.c                          |   63 +++-
+ sound/soc/codecs/wm5110.c                          |   16 +
+ sound/soc/codecs/wm8903.c                          |   18 +-
+ sound/soc/codecs/wm8940.c                          |   18 +-
+ sound/soc/codecs/wm8955.c                          |   18 +-
+ sound/soc/codecs/wm8958-dsp2.c                     |   28 +-
+ sound/soc/codecs/wm8960.c                          |   18 +-
+ sound/soc/codecs/wm8961.c                          |   18 +-
+ sound/soc/codecs/wm8962.c                          |   15 -
+ sound/soc/codecs/wm8971.c                          |   18 +-
+ sound/soc/codecs/wm8974.c                          |   18 +-
+ sound/soc/codecs/wm8978.c                          |   18 +-
+ sound/soc/codecs/wm8991.c                          |   18 +-
+ sound/soc/codecs/wm8994.c                          |   98 ++++--
+ sound/soc/codecs/wm8994.h                          |   12 +-
+ sound/soc/codecs/wm9090.c                          |   12 +-
+ sound/soc/codecs/wm9712.c                          |    6 +-
+ sound/soc/codecs/wm_hubs.c                         |   71 ++--
+ sound/soc/codecs/wm_hubs.h                         |    2 +
+ sound/soc/davinci/davinci-evm.c                    |    1 -
+ sound/soc/davinci/davinci-mcasp.c                  |   50 +--
+ sound/soc/davinci/davinci-mcasp.h                  |    3 +-
+ sound/soc/fsl/imx-ssi.c                            |   30 +-
+ sound/soc/mxs/Kconfig                              |    2 +-
+ sound/soc/mxs/mxs-saif.c                           |   20 +-
+ sound/soc/omap/Kconfig                             |   48 +--
+ sound/soc/omap/Makefile                            |   10 +-
+ sound/soc/omap/igep0020.c                          |  120 -------
+ sound/soc/omap/mcbsp.c                             |    2 +-
+ sound/soc/omap/omap-abe-twl6040.c                  |  145 ++++++--
+ sound/soc/omap/omap-mcpdm.c                        |   52 +--
+ sound/soc/omap/omap-twl4030.c                      |  188 +++++++++++
+ sound/soc/omap/omap3beagle.c                       |  150 ---------
+ sound/soc/omap/omap3evm.c                          |  118 -------
+ sound/soc/omap/overo.c                             |  122 -------
+ sound/soc/samsung/Kconfig                          |    8 +
+ sound/soc/samsung/Makefile                         |    2 +
+ sound/soc/samsung/bells.c                          |  346 ++++++++++++++++++++
+ sound/soc/samsung/pcm.c                            |    2 +-
+ sound/soc/soc-core.c                               |   25 +-
+ sound/soc/soc-jack.c                               |    8 +-
+ sound/soc/ux500/ux500_msp_dai.c                    |    3 +
+ sound/soc/ux500/ux500_msp_i2s.c                    |    2 +
+ 80 files changed, 1303 insertions(+), 1203 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/sound/cs4270.txt
+ create mode 100644 Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt
+ create mode 100644 Documentation/devicetree/bindings/sound/omap-twl4030.txt
+ create mode 100644 include/linux/platform_data/omap-twl4030.h
+ delete mode 100644 sound/soc/omap/igep0020.c
+ create mode 100644 sound/soc/omap/omap-twl4030.c
+ delete mode 100644 sound/soc/omap/omap3beagle.c
+ delete mode 100644 sound/soc/omap/omap3evm.c
+ delete mode 100644 sound/soc/omap/overo.c
+ create mode 100644 sound/soc/samsung/bells.c
+Merging quilt/rr (d673c23 Make most arch asm/module.h files use asm-generic/module.h)
+$ git merge quilt/rr
+Resolved 'arch/s390/Kconfig' using previous resolution.
+Resolved 'arch/xtensa/Kconfig' using previous resolution.
+Auto-merging arch/xtensa/Kconfig
+CONFLICT (content): Merge conflict in arch/xtensa/Kconfig
+Auto-merging arch/x86/Kconfig
+Auto-merging arch/unicore32/Kconfig
+Removing arch/sparc/include/asm/module.h
+Auto-merging arch/s390/Kconfig
+CONFLICT (content): Merge conflict in arch/s390/Kconfig
+Auto-merging arch/powerpc/Kconfig
+Auto-merging arch/mips/kernel/module.c
+Auto-merging arch/mips/include/asm/module.h
+Auto-merging arch/mips/Kconfig
+Auto-merging arch/m68k/Kconfig
+Removing arch/m32r/include/asm/module.h
+Removing arch/h8300/include/asm/module.h
+Removing arch/cris/include/asm/module.h
+Auto-merging arch/cris/Kconfig
+Auto-merging arch/c6x/Kconfig
+Auto-merging arch/arm/Kconfig
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master a096b83] Merge branch 'quilt/rr'
+$ git diff -M --stat --summary HEAD^..
+ arch/Kconfig                       |   19 +++++++++++++++++
+ arch/alpha/Kconfig                 |    2 ++
+ arch/alpha/include/asm/module.h    |   10 ++-------
+ arch/arm/Kconfig                   |    2 ++
+ arch/arm/include/asm/module.h      |    8 ++------
+ arch/avr32/Kconfig                 |    2 ++
+ arch/avr32/include/asm/module.h    |    6 ++----
+ arch/blackfin/Kconfig              |    2 ++
+ arch/blackfin/include/asm/module.h |    4 +---
+ arch/c6x/Kconfig                   |    1 +
+ arch/c6x/include/asm/module.h      |   12 +----------
+ arch/cris/Kconfig                  |    1 +
+ arch/cris/include/asm/Kbuild       |    2 ++
+ arch/cris/include/asm/module.h     |    9 --------
+ arch/frv/include/asm/module.h      |    8 +-------
+ arch/h8300/Kconfig                 |    1 +
+ arch/h8300/include/asm/Kbuild      |    2 ++
+ arch/h8300/include/asm/module.h    |   11 ----------
+ arch/hexagon/Kconfig               |    1 +
+ arch/ia64/Kconfig                  |    2 ++
+ arch/ia64/include/asm/module.h     |    6 ++----
+ arch/m32r/Kconfig                  |    1 +
+ arch/m32r/include/asm/Kbuild       |    2 ++
+ arch/m32r/include/asm/module.h     |   10 ---------
+ arch/m32r/kernel/module.c          |   15 --------------
+ arch/m68k/Kconfig                  |    3 +++
+ arch/m68k/include/asm/module.h     |    6 ++----
+ arch/microblaze/Kconfig            |    1 +
+ arch/mips/Kconfig                  |    3 +++
+ arch/mips/include/asm/module.h     |   10 +++++++--
+ arch/mips/kernel/module.c          |    2 ++
+ arch/mn10300/Kconfig               |    1 +
+ arch/mn10300/include/asm/module.h  |    7 +------
+ arch/openrisc/Kconfig              |    1 +
+ arch/parisc/Kconfig                |    2 ++
+ arch/parisc/include/asm/module.h   |   16 +++------------
+ arch/powerpc/Kconfig               |    2 ++
+ arch/powerpc/include/asm/module.h  |    7 +------
+ arch/s390/Kconfig                  |    2 ++
+ arch/s390/include/asm/module.h     |   18 +++-------------
+ arch/score/Kconfig                 |    2 ++
+ arch/score/include/asm/module.h    |    6 +-----
+ arch/score/kernel/module.c         |   10 ---------
+ arch/sh/Kconfig                    |    2 ++
+ arch/sh/include/asm/module.h       |   14 +++----------
+ arch/sparc/Kconfig                 |    1 +
+ arch/sparc/include/asm/Kbuild      |    1 +
+ arch/sparc/include/asm/module.h    |   24 ----------------------
+ arch/tile/Kconfig                  |    1 +
+ arch/unicore32/Kconfig             |    1 +
+ arch/x86/Kconfig                   |    2 ++
+ arch/xtensa/Kconfig                |    1 +
+ arch/xtensa/include/asm/module.h   |    9 +-------
+ include/asm-generic/module.h       |   40 +++++++++++++++++++++++++++++-------
+ include/linux/moduleloader.h       |   36 ++++++++++++++++++++++++++++----
+ kernel/module.c                    |   24 ++++------------------
+ 56 files changed, 171 insertions(+), 223 deletions(-)
+ delete mode 100644 arch/cris/include/asm/module.h
+ delete mode 100644 arch/h8300/include/asm/module.h
+ delete mode 100644 arch/m32r/include/asm/module.h
+ delete mode 100644 arch/sparc/include/asm/module.h
+Merging input/next (2b94e25 Input: random formatting fixes)
+$ git merge input/next
+Merge made by the 'recursive' strategy.
+ drivers/input/apm-power.c              |    2 +-
+ drivers/input/ff-core.c                |    4 +-
+ drivers/input/ff-memless.c             |   14 +--
+ drivers/input/joydev.c                 |    2 +-
+ drivers/input/keyboard/gpio_keys.c     |  168 ++++++++++++++++----------------
+ drivers/input/misc/twl4030-pwrbutton.c |    1 +
+ drivers/input/mousedev.c               |    9 +-
+ drivers/input/sparse-keymap.c          |    4 +-
+ 8 files changed, 105 insertions(+), 99 deletions(-)
+Merging input-mt/for-next (0d7614f Linux 3.6-rc1)
+$ git merge input-mt/for-next
+Already up-to-date.
+Merging cgroup/for-next (4b2ebf0 Merge branch 'for-3.6' into for-next)
+$ git merge cgroup/for-next
+Already up-to-date!
+Merge made by the 'recursive' strategy.
+Merging block/for-next (4004e90 Documentation: update tunable options in block/cfq-iosched.txt)
+$ git merge block/for-next
+Auto-merging fs/bio.c
+Merge made by the 'recursive' strategy.
+ Documentation/block/00-INDEX        |   10 ++-
+ Documentation/block/cfq-iosched.txt |   77 +++++++++++++++++++++++
+ Documentation/block/queue-sysfs.txt |   64 +++++++++++++++++++
+ block/blk-lib.c                     |   41 ++++++++----
+ block/blk-merge.c                   |  117 ++++++++++++++++++++++++-----------
+ block/genhd.c                       |    2 +-
+ fs/bio.c                            |   11 ++--
+ fs/block_dev.c                      |    3 +
+ fs/direct-io.c                      |    5 ++
+ include/linux/blkdev.h              |   14 ++++-
+ mm/filemap.c                        |    7 ---
+ 11 files changed, 287 insertions(+), 64 deletions(-)
+Merging quilt/device-mapper (057d040 Overflow checking in dm-verity was not sufficient. It would check overflow if sector_t was smaller than long long but not if sector_t and long long have the same size. This patch implements proper overflow checking.)
+$ git merge quilt/device-mapper
+Merge made by the 'recursive' strategy.
+ drivers/md/dm-verity.c |    8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+Merging embedded/master (4744b43 embedded: fix vc_translate operator precedence)
+$ git merge embedded/master
+Already up-to-date.
+Merging firmware/master (6e03a20 firmware: speed up request_firmware(), v3)
+$ git merge firmware/master
+Already up-to-date.
+Merging pcmcia/master (80af9e6 pcmcia at91_cf: fix raw gpio number usage)
+$ git merge pcmcia/master
+Already up-to-date.
+Merging mmc/mmc-next (72d0f11 mmc: bfin_sdh: Reset SD controller when resume from power saving mode.)
+$ git merge mmc/mmc-next
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ .../devicetree/bindings/mmc/atmel-hsmci.txt        |   68 ++++++
+ Documentation/devicetree/bindings/mmc/pxa-mmc.txt  |   25 +++
+ .../devicetree/bindings/mmc/sdhci-dove.txt         |   14 ++
+ MAINTAINERS                                        |    2 +-
+ drivers/mmc/host/atmel-mci.c                       |   91 +++++++-
+ drivers/mmc/host/bfin_sdh.c                        |  217 +++++++++++++-------
+ drivers/mmc/host/dw_mmc.c                          |   85 ++++----
+ drivers/mmc/host/omap_hsmmc.c                      |    4 +-
+ drivers/mmc/host/pxamci.c                          |   52 +++++
+ drivers/mmc/host/sdhci-dove.c                      |    8 +
+ drivers/mmc/host/sdhci-of-esdhc.c                  |   36 +++-
+ drivers/mmc/host/sdhci-pxav2.c                     |    6 +-
+ drivers/mmc/host/sdhci-pxav3.c                     |    8 +-
+ drivers/mmc/host/sdhci.c                           |  188 +++++++++++------
+ drivers/mmc/host/vub300.c                          |    4 +-
+ include/linux/mmc/sdhci.h                          |    3 +-
+ 16 files changed, 608 insertions(+), 203 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
+ create mode 100644 Documentation/devicetree/bindings/mmc/pxa-mmc.txt
+ create mode 100644 Documentation/devicetree/bindings/mmc/sdhci-dove.txt
+Merging kgdb/kgdb-next (15d7ea0 kgdboc: Accept either kbd or kdb to activate the vga + keyboard kdb shell)
+$ git merge kgdb/kgdb-next
+Merge made by the 'recursive' strategy.
+ arch/mips/kernel/kgdb.c     |    9 +++++++++
+ arch/x86/kernel/kgdb.c      |    2 ++
+ drivers/tty/serial/kgdboc.c |    3 ++-
+ 3 files changed, 13 insertions(+), 1 deletion(-)
+Merging slab/for-next (77be4b1 mm/slab: restructure kmem_cache_create() debug checks)
+$ git merge slab/for-next
+Merge made by the 'recursive' strategy.
+ mm/slab.c        |    1 -
+ mm/slab_common.c |   97 +++++++++++++++++++++++++++---------------------------
+ mm/slub.c        |   33 +++++++++++--------
+ 3 files changed, 68 insertions(+), 63 deletions(-)
+Merging uclinux/for-next (5e442a4 Revert "proc: fix races against execve() of /proc/PID/fd**")
+$ git merge uclinux/for-next
+Already up-to-date.
+Merging md/for-next (eef0978 md: avoid taking the mutex on some ioctls.)
+$ git merge md/for-next
+Auto-merging fs/bio.c
+Merge made by the 'recursive' strategy.
+ drivers/md/linear.c    |   25 ++-
+ drivers/md/md.c        |   94 +++++++----
+ drivers/md/md.h        |   15 +-
+ drivers/md/multipath.c |    3 +-
+ drivers/md/raid0.c     |   19 ++-
+ drivers/md/raid1.c     |   23 ++-
+ drivers/md/raid10.c    |   30 +++-
+ drivers/md/raid5.c     |  411 +++++++++++++++++++++++++++++++++++++++++++++---
+ drivers/md/raid5.h     |   19 +++
+ fs/bio.c               |   22 +--
+ 10 files changed, 585 insertions(+), 76 deletions(-)
+Merging mfd/for-next (3c1534c mfd: Ensure AB8500 platform data is passed through db8500-prcmu to MFD Core)
+$ git merge mfd/for-next
+Already up-to-date.
+Merging battery/master (ecc2edd olpc-battery: update CHARGE_FULL_DESIGN property for BYD LiFe batteries)
+$ git merge battery/master
+Already up-to-date.
+Merging fbdev/fbdev-next (a023907 da8xx-fb: fix compile issue due to missing include)
+$ git merge fbdev/fbdev-next
+Already up-to-date.
+Merging viafb/viafb-next (838ac78 viafb: avoid refresh and mode lookup in set_par)
+$ git merge viafb/viafb-next
+Already up-to-date.
+Merging omap_dss2/for-next (974a658 Merge "Apply LCD manager related parameters" from Archit)
+$ git merge omap_dss2/for-next
+Already up-to-date.
+Merging regulator/for-next (4785f97 Merge branch 'regulator-drivers' into regulator-next)
+$ git merge regulator/for-next
+Merge made by the 'recursive' strategy.
+ .../devicetree/bindings/regulator/tps6586x.txt     |   71 ++--
+ drivers/mfd/tps6586x.c                             |   13 +
+ drivers/regulator/Kconfig                          |   27 +-
+ drivers/regulator/Makefile                         |    1 +
+ drivers/regulator/ab3100.c                         |    7 +-
+ drivers/regulator/ab8500.c                         |   16 +-
+ drivers/regulator/anatop-regulator.c               |    5 +-
+ drivers/regulator/core.c                           |   15 +-
+ drivers/regulator/da9052-regulator.c               |    4 +-
+ drivers/regulator/dummy.c                          |    2 +-
+ drivers/regulator/gpio-regulator.c                 |   38 +-
+ drivers/regulator/isl6271a-regulator.c             |    6 -
+ drivers/regulator/lp872x.c                         |   18 +-
+ drivers/regulator/lp8788-buck.c                    |   80 +---
+ drivers/regulator/lp8788-ldo.c                     |    8 +
+ drivers/regulator/max77686.c                       |   30 +-
+ drivers/regulator/max8907-regulator.c              |  384 ++++++++++++++++++++
+ drivers/regulator/mc13783-regulator.c              |   23 +-
+ drivers/regulator/mc13892-regulator.c              |   77 ++--
+ drivers/regulator/mc13xxx-regulator-core.c         |   17 +-
+ drivers/regulator/mc13xxx.h                        |    1 -
+ drivers/regulator/palmas-regulator.c               |   68 +---
+ drivers/regulator/s2mps11.c                        |   27 +-
+ drivers/regulator/tps6524x-regulator.c             |   10 +-
+ drivers/regulator/tps6586x-regulator.c             |  104 ++----
+ drivers/regulator/twl-regulator.c                  |  108 +++---
+ drivers/regulator/wm831x-dcdc.c                    |   11 +-
+ drivers/regulator/wm831x-ldo.c                     |    4 +
+ drivers/regulator/wm8400-regulator.c               |    7 +-
+ include/linux/mfd/max77686.h                       |    1 +
+ include/linux/mfd/tps6586x.h                       |    1 +
+ include/linux/regulator/consumer.h                 |    7 +
+ include/linux/regulator/driver.h                   |    1 +
+ 33 files changed, 723 insertions(+), 469 deletions(-)
+ create mode 100644 drivers/regulator/max8907-regulator.c
+Merging security/next (51b743f Merge tag 'v3.6-rc2' into next)
+$ git merge security/next
+Merge made by the 'recursive' strategy.
+ include/linux/ptrace.h       |    2 --
+ kernel/ptrace.c              |    3 ++-
+ samples/seccomp/bpf-helper.h |   15 ++++++++++-----
+ 3 files changed, 12 insertions(+), 8 deletions(-)
+Merging selinux/master (c2d7b24 Merge tag 'v3.4' into 20120409)
+$ git merge selinux/master
+Already up-to-date!
+Merge made by the 'recursive' strategy.
+Merging lblnet/master (7e27d6e Linux 2.6.35-rc3)
+$ git merge lblnet/master
+Already up-to-date.
+Merging watchdog/master (06a3fa7 watchdog: fix watchdog-test.c build warning)
+$ git merge watchdog/master
+Merge made by the 'recursive' strategy.
+ Documentation/watchdog/src/watchdog-test.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+Merging dwmw2-iommu/master (c3b92c8 Linux 3.1)
+$ git merge dwmw2-iommu/master
+Already up-to-date.
+Merging iommu/next (6f286cc Merge branches 'iommu/fixes' and 'arm/tegra' into next)
+$ git merge iommu/next
+Merge made by the 'recursive' strategy.
+ drivers/iommu/amd_iommu_init.c      |    2 +-
+ drivers/iommu/intel_irq_remapping.c |   18 +++-
+ drivers/iommu/tegra-smmu.c          |  202 ++++++++++++++++++++++++++++++++---
+ 3 files changed, 204 insertions(+), 18 deletions(-)
+Merging vfio/next (d987569 Linux 3.6-rc2)
+$ git merge vfio/next
+Already up-to-date.
+Merging osd/linux-next (b8017d2 exofs: check for allocation failure in uri_store())
+$ git merge osd/linux-next
+Merge made by the 'recursive' strategy.
+ fs/exofs/sys.c |    7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+Merging jc_docs/docs-next (5c050fb docs: update the development process document)
+$ git merge jc_docs/docs-next
+Already up-to-date.
+Merging trivial/for-next (ef706fb irqdesc: delete now orphaned references to timer_rand_state)
+$ git merge trivial/for-next
+Auto-merging include/linux/irqdesc.h
+Merge made by the 'recursive' strategy.
+ drivers/video/backlight/88pm860x_bl.c |    1 -
+ include/linux/irqdesc.h               |    2 --
+ 2 files changed, 3 deletions(-)
+Merging audit/for-next (dcd6c92 Linux 3.3-rc1)
+$ git merge audit/for-next
+Already up-to-date.
+Merging pm/linux-next (8b97819 Merge branch 'pm-cpuidle-next' into linux-next)
+$ git merge pm/linux-next
+Removing arch/arm/mach-shmobile/common.c
+Merge made by the 'recursive' strategy.
+ Documentation/cpuidle/sysfs.txt                  |   10 +-
+ arch/arm/mach-shmobile/Makefile                  |    2 +-
+ arch/arm/mach-shmobile/board-ap4evb.c            |   19 +-
+ arch/arm/mach-shmobile/board-armadillo800eva.c   |    6 +-
+ arch/arm/mach-shmobile/board-mackerel.c          |   32 +--
+ arch/arm/mach-shmobile/common.c                  |   24 ---
+ arch/arm/mach-shmobile/cpuidle.c                 |   39 ++--
+ arch/arm/mach-shmobile/include/mach/common.h     |   14 +-
+ arch/arm/mach-shmobile/include/mach/pm-rmobile.h |   35 +++-
+ arch/arm/mach-shmobile/include/mach/r8a7740.h    |    6 +-
+ arch/arm/mach-shmobile/include/mach/r8a7779.h    |   12 +-
+ arch/arm/mach-shmobile/include/mach/sh7372.h     |   18 +-
+ arch/arm/mach-shmobile/pm-r8a7740.c              |   42 ++--
+ arch/arm/mach-shmobile/pm-r8a7779.c              |   71 +++----
+ arch/arm/mach-shmobile/pm-rmobile.c              |   33 ++-
+ arch/arm/mach-shmobile/pm-sh7372.c               |  233 ++++++++++++---------
+ arch/arm/mach-shmobile/setup-r8a7740.c           |   27 +--
+ arch/arm/mach-shmobile/setup-r8a7779.c           |    5 +-
+ arch/arm/mach-shmobile/setup-sh7372.c            |   69 +++---
+ drivers/base/platform.c                          |    2 +
+ drivers/base/power/domain.c                      |  244 ++++++++++++++++++----
+ drivers/base/power/main.c                        |   35 +++-
+ drivers/base/power/power.h                       |   36 +++-
+ drivers/base/power/wakeup.c                      |   29 +++
+ drivers/clocksource/sh_cmt.c                     |   71 ++++++-
+ drivers/clocksource/sh_mtu2.c                    |   41 +++-
+ drivers/clocksource/sh_tmu.c                     |  112 +++++++++-
+ drivers/cpufreq/cpufreq_conservative.c           |    1 +
+ drivers/cpuidle/governors/ladder.c               |    6 +-
+ include/linux/clockchips.h                       |    8 +
+ include/linux/device.h                           |    7 +
+ include/linux/pm.h                               |    2 +
+ include/linux/pm_domain.h                        |   92 ++++++--
+ kernel/power/Kconfig                             |    4 +
+ kernel/time/clockevents.c                        |   24 +++
+ kernel/time/timekeeping.c                        |    2 +
+ 36 files changed, 990 insertions(+), 423 deletions(-)
+ delete mode 100644 arch/arm/mach-shmobile/common.c
+Merging apm/for-next (f283d22 APM: fix deadlock in APM_IOC_SUSPEND ioctl)
+$ git merge apm/for-next
+Already up-to-date.
+Merging fsnotify/for-next (1aec9c0 inotify: automatically restart syscalls)
+$ git merge fsnotify/for-next
+Auto-merging kernel/audit_watch.c
+Auto-merging kernel/audit_tree.c
+Auto-merging include/linux/fsnotify_backend.h
+Auto-merging fs/notify/notification.c
+Auto-merging fs/notify/fanotify/fanotify_user.c
+Merge made by the 'recursive' strategy.
+ fs/notify/dnotify/dnotify.c          |    4 +-
+ fs/notify/fanotify/fanotify.c        |    6 +++
+ fs/notify/fanotify/fanotify_user.c   |   37 +++++++++-----
+ fs/notify/group.c                    |   47 ++++++++++--------
+ fs/notify/inode_mark.c               |   14 ++++--
+ fs/notify/inotify/inotify_fsnotify.c |    4 +-
+ fs/notify/inotify/inotify_user.c     |   34 ++++++-------
+ fs/notify/mark.c                     |   91 +++++++++++++++++++---------------
+ fs/notify/notification.c             |    1 +
+ fs/notify/vfsmount_mark.c            |   14 ++++--
+ include/linux/fsnotify_backend.h     |   31 ++++++++----
+ kernel/audit_tree.c                  |   10 ++--
+ kernel/audit_watch.c                 |    4 +-
+ 13 files changed, 178 insertions(+), 119 deletions(-)
+Merging edac/linux_next (a92cdec Merge branch 'devel' into next)
+$ git merge edac/linux_next
+Already up-to-date!
+Merge made by the 'recursive' strategy.
+Merging edac-amd/for-next (305f1c3 Merge branch '3.3-pci_device_id' into edac-for-next)
+$ git merge edac-amd/for-next
+Resolved 'Documentation/edac.txt' using previous resolution.
+Resolved 'drivers/edac/amd64_edac.c' using previous resolution.
+Auto-merging drivers/edac/amd64_edac.c
+CONFLICT (content): Merge conflict in drivers/edac/amd64_edac.c
+Auto-merging Documentation/edac.txt
+CONFLICT (content): Merge conflict in Documentation/edac.txt
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master 3ca3330] Merge remote-tracking branch 'edac-amd/for-next'
+$ git diff -M --stat --summary HEAD^..
+Merging devicetree/devicetree/next (efd68e7 devicetree: add helper inline for retrieving a node's full name)
+$ git merge devicetree/devicetree/next
+Already up-to-date.
+Merging dt-rh/for-next (5d61b16 of: Allow busses with #size-cells=0)
+$ git merge dt-rh/for-next
+Merge made by the 'recursive' strategy.
+ drivers/of/address.c       |   27 +++++++++++++++++++++++----
+ drivers/of/platform.c      |   16 +++++++++++++---
+ include/linux/of_address.h |    1 +
+ 3 files changed, 37 insertions(+), 7 deletions(-)
+Merging spi/spi/next (d8e328b spi: Add "spi:" prefix to modalias attribute of spi devices)
+$ git merge spi/spi/next
+Already up-to-date.
+Merging spi-mb/spi-next (a6c16d9 Merge branch 'spi-mxs' into spi-next)
+$ git merge spi-mb/spi-next
+Auto-merging drivers/spi/spi-s3c64xx.c
+Auto-merging drivers/spi/spi-bcm63xx.c
+Merge made by the 'recursive' strategy.
+ Documentation/devicetree/bindings/spi/mxs-spi.txt |   18 +
+ drivers/clk/mxs/Makefile                          |    2 +-
+ drivers/clk/mxs/clk-ssp.c                         |   62 ++
+ drivers/mmc/host/mxs-mmc.c                        |  325 ++++-------
+ drivers/spi/Kconfig                               |    7 +
+ drivers/spi/Makefile                              |    1 +
+ drivers/spi/spi-altera.c                          |    4 +-
+ drivers/spi/spi-bcm63xx.c                         |    4 +-
+ drivers/spi/spi-coldfire-qspi.c                   |    5 +-
+ drivers/spi/spi-mxs.c                             |  631 +++++++++++++++++++++
+ drivers/spi/spi-omap2-mcspi.c                     |    8 +-
+ drivers/spi/spi-orion.c                           |  209 ++-----
+ drivers/spi/spi-pl022.c                           |    1 -
+ drivers/spi/spi-s3c64xx.c                         |   12 +-
+ include/linux/spi/mxs-spi.h                       |  150 +++++
+ 15 files changed, 1052 insertions(+), 387 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/spi/mxs-spi.txt
+ create mode 100644 drivers/clk/mxs/clk-ssp.c
+ create mode 100644 drivers/spi/spi-mxs.c
+ create mode 100644 include/linux/spi/mxs-spi.h
+Merging tip/auto-latest (bf09da2 Merge branch 'timers/urgent' into auto-latest)
+$ git merge tip/auto-latest
+Auto-merging kernel/time/timekeeping.c
+Auto-merging arch/x86/Kconfig
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ MAINTAINERS                                   |    8 +
+ arch/tile/include/asm/topology.h              |    1 -
+ arch/x86/Kconfig                              |   31 +
+ arch/x86/Makefile                             |    4 +
+ arch/x86/boot/Makefile                        |    2 +-
+ arch/x86/kernel/apic/io_apic.c                |   10 +
+ arch/x86/kernel/cpu/amd.c                     |   67 ++
+ arch/x86/kernel/cpu/common.c                  |    7 +-
+ arch/x86/kernel/cpu/intel.c                   |    4 +
+ arch/x86/kernel/cpu/mcheck/mce-inject.c       |    8 +
+ arch/x86/kernel/cpu/mcheck/mce-internal.h     |   12 +
+ arch/x86/kernel/cpu/mcheck/mce.c              |   84 +-
+ arch/x86/kernel/cpu/mcheck/mce_intel.c        |  133 ++-
+ arch/x86/kernel/cpu/perf_event_intel.c        |   10 +-
+ arch/x86/kernel/cpu/perf_event_intel_uncore.c |  253 ++--
+ arch/x86/kernel/cpu/perf_event_intel_uncore.h |   46 +-
+ arch/x86/mm/pageattr.c                        |   10 +-
+ arch/x86/platform/efi/efi.c                   |   30 +-
+ arch/x86/realmode/rm/Makefile                 |    2 +-
+ drivers/infiniband/hw/ehca/ehca_irq.c         |  250 ++--
+ drivers/infiniband/hw/ehca/ehca_irq.h         |    6 +-
+ include/linux/efi.h                           |    2 +
+ include/linux/kthread.h                       |   11 +-
+ include/linux/ktime.h                         |    7 -
+ include/linux/sched.h                         |    1 -
+ include/linux/smpboot.h                       |   43 +
+ include/linux/time.h                          |   22 +-
+ include/linux/topology.h                      |    2 -
+ init/main.c                                   |    8 +-
+ kernel/Makefile                               |    3 +-
+ kernel/cpu.c                                  |   10 +-
+ kernel/kthread.c                              |  185 ++-
+ kernel/rcutree.c                              |   12 +-
+ kernel/rcutree.h                              |   15 +-
+ kernel/rcutree_plugin.h                       |  403 ++-----
+ kernel/rcutree_trace.c                        |    3 +-
+ kernel/sched/core.c                           |   70 +-
+ kernel/sched/fair.c                           |   56 +-
+ kernel/sched/rt.c                             |   13 +
+ kernel/sched/sched.h                          |    8 +-
+ kernel/sched/stop_task.c                      |   22 +-
+ kernel/smpboot.c                              |  233 ++++
+ kernel/smpboot.h                              |    4 +
+ kernel/softirq.c                              |  111 +-
+ kernel/time/timekeeping.c                     |   26 +-
+ kernel/watchdog.c                             |  263 ++---
+ scripts/kconfig/Makefile                      |    7 +-
+ tools/kvm/.gitignore                          |   12 +
+ tools/kvm/CREDITS-Git                         |   30 +
+ tools/kvm/Documentation/kernel-debugging.txt  |   15 +
+ tools/kvm/Documentation/kvm-balloon.txt       |   24 +
+ tools/kvm/Documentation/kvm-debug.txt         |   16 +
+ tools/kvm/Documentation/kvm-list.txt          |   16 +
+ tools/kvm/Documentation/kvm-pause.txt         |   16 +
+ tools/kvm/Documentation/kvm-resume.txt        |   16 +
+ tools/kvm/Documentation/kvm-run.txt           |   62 +
+ tools/kvm/Documentation/kvm-sandbox.txt       |   16 +
+ tools/kvm/Documentation/kvm-setup.txt         |   15 +
+ tools/kvm/Documentation/kvm-stat.txt          |   19 +
+ tools/kvm/Documentation/kvm-stop.txt          |   16 +
+ tools/kvm/Documentation/kvm-version.txt       |   21 +
+ tools/kvm/Documentation/virtio-console.txt    |   41 +
+ tools/kvm/Makefile                            |  427 +++++++
+ tools/kvm/README                              |  112 ++
+ tools/kvm/builtin-balloon.c                   |   80 ++
+ tools/kvm/builtin-debug.c                     |  110 ++
+ tools/kvm/builtin-help.c                      |   63 +
+ tools/kvm/builtin-list.c                      |  149 +++
+ tools/kvm/builtin-pause.c                     |   88 ++
+ tools/kvm/builtin-resume.c                    |   88 ++
+ tools/kvm/builtin-run.c                       | 1393 ++++++++++++++++++++++
+ tools/kvm/builtin-sandbox.c                   |    9 +
+ tools/kvm/builtin-setup.c                     |  232 ++++
+ tools/kvm/builtin-stat.c                      |  127 ++
+ tools/kvm/builtin-stop.c                      |   70 ++
+ tools/kvm/builtin-version.c                   |   15 +
+ tools/kvm/code16gcc.h                         |   15 +
+ tools/kvm/command-list.txt                    |   15 +
+ tools/kvm/config/feature-tests.mak            |  177 +++
+ tools/kvm/config/utilities.mak                |  196 ++++
+ tools/kvm/disk/blk.c                          |   76 ++
+ tools/kvm/disk/core.c                         |  275 +++++
+ tools/kvm/disk/qcow.c                         | 1529 +++++++++++++++++++++++++
+ tools/kvm/disk/raw.c                          |  141 +++
+ tools/kvm/framebuffer.c                       |   75 ++
+ tools/kvm/guest/init.c                        |   38 +
+ tools/kvm/guest/init_stage2.c                 |   55 +
+ tools/kvm/guest/passwd                        |    1 +
+ tools/kvm/guest_compat.c                      |   99 ++
+ tools/kvm/hw/i8042.c                          |  348 ++++++
+ tools/kvm/hw/pci-shmem.c                      |  268 +++++
+ tools/kvm/hw/rtc.c                            |  137 +++
+ tools/kvm/hw/serial.c                         |  446 ++++++++
+ tools/kvm/hw/vesa.c                           |   85 ++
+ tools/kvm/include/asm/hweight.h               |    8 +
+ tools/kvm/include/bios/memcpy.h               |    9 +
+ tools/kvm/include/kvm/8250-serial.h           |   11 +
+ tools/kvm/include/kvm/apic.h                  |   17 +
+ tools/kvm/include/kvm/brlock.h                |   41 +
+ tools/kvm/include/kvm/builtin-balloon.h       |    9 +
+ tools/kvm/include/kvm/builtin-debug.h         |   20 +
+ tools/kvm/include/kvm/builtin-help.h          |    6 +
+ tools/kvm/include/kvm/builtin-list.h          |   10 +
+ tools/kvm/include/kvm/builtin-pause.h         |    9 +
+ tools/kvm/include/kvm/builtin-resume.h        |    9 +
+ tools/kvm/include/kvm/builtin-run.h           |   11 +
+ tools/kvm/include/kvm/builtin-sandbox.h       |    6 +
+ tools/kvm/include/kvm/builtin-setup.h         |   11 +
+ tools/kvm/include/kvm/builtin-stat.h          |    9 +
+ tools/kvm/include/kvm/builtin-stop.h          |    9 +
+ tools/kvm/include/kvm/builtin-version.h       |    6 +
+ tools/kvm/include/kvm/compiler.h              |   10 +
+ tools/kvm/include/kvm/disk-image.h            |   87 ++
+ tools/kvm/include/kvm/e820.h                  |   13 +
+ tools/kvm/include/kvm/framebuffer.h           |   35 +
+ tools/kvm/include/kvm/guest_compat.h          |    9 +
+ tools/kvm/include/kvm/i8042.h                 |   12 +
+ tools/kvm/include/kvm/ioeventfd.h             |   28 +
+ tools/kvm/include/kvm/ioport.h                |   69 ++
+ tools/kvm/include/kvm/irq.h                   |   33 +
+ tools/kvm/include/kvm/kvm-cmd.h               |   17 +
+ tools/kvm/include/kvm/kvm-cpu.h               |   24 +
+ tools/kvm/include/kvm/kvm-ipc.h               |   24 +
+ tools/kvm/include/kvm/kvm.h                   |   93 ++
+ tools/kvm/include/kvm/msi.h                   |   10 +
+ tools/kvm/include/kvm/mutex.h                 |   33 +
+ tools/kvm/include/kvm/parse-options.h         |  214 ++++
+ tools/kvm/include/kvm/pci-shmem.h             |   28 +
+ tools/kvm/include/kvm/pci.h                   |   95 ++
+ tools/kvm/include/kvm/qcow.h                  |  133 +++
+ tools/kvm/include/kvm/rbtree-interval.h       |   28 +
+ tools/kvm/include/kvm/read-write.h            |   43 +
+ tools/kvm/include/kvm/rtc.h                   |    9 +
+ tools/kvm/include/kvm/rwsem.h                 |   39 +
+ tools/kvm/include/kvm/sdl.h                   |   22 +
+ tools/kvm/include/kvm/segment.h               |   21 +
+ tools/kvm/include/kvm/strbuf.h                |   20 +
+ tools/kvm/include/kvm/symbol.h                |   30 +
+ tools/kvm/include/kvm/term.h                  |   20 +
+ tools/kvm/include/kvm/threadpool.h            |   37 +
+ tools/kvm/include/kvm/types.h                 |    7 +
+ tools/kvm/include/kvm/uip.h                   |  358 ++++++
+ tools/kvm/include/kvm/util.h                  |   97 ++
+ tools/kvm/include/kvm/vesa.h                  |   18 +
+ tools/kvm/include/kvm/virtio-9p.h             |   73 ++
+ tools/kvm/include/kvm/virtio-balloon.h        |    8 +
+ tools/kvm/include/kvm/virtio-blk.h            |   12 +
+ tools/kvm/include/kvm/virtio-console.h        |    9 +
+ tools/kvm/include/kvm/virtio-mmio.h           |   58 +
+ tools/kvm/include/kvm/virtio-net.h            |   26 +
+ tools/kvm/include/kvm/virtio-pci-dev.h        |   37 +
+ tools/kvm/include/kvm/virtio-pci.h            |   46 +
+ tools/kvm/include/kvm/virtio-rng.h            |    9 +
+ tools/kvm/include/kvm/virtio.h                |  103 ++
+ tools/kvm/include/kvm/vnc.h                   |   20 +
+ tools/kvm/include/linux/bitops.h              |   33 +
+ tools/kvm/include/linux/byteorder.h           |    7 +
+ tools/kvm/include/linux/compiler.h            |   19 +
+ tools/kvm/include/linux/kernel.h              |   39 +
+ tools/kvm/include/linux/module.h              |    6 +
+ tools/kvm/include/linux/prefetch.h            |    6 +
+ tools/kvm/include/linux/stddef.h              |   16 +
+ tools/kvm/include/linux/types.h               |   51 +
+ tools/kvm/ioeventfd.c                         |  215 ++++
+ tools/kvm/ioport.c                            |  195 ++++
+ tools/kvm/kvm-cmd.c                           |   91 ++
+ tools/kvm/kvm-cpu.c                           |  175 +++
+ tools/kvm/kvm-ipc.c                           |  231 ++++
+ tools/kvm/kvm.c                               |  593 ++++++++++
+ tools/kvm/main.c                              |   19 +
+ tools/kvm/mmio.c                              |  140 +++
+ tools/kvm/net/uip/arp.c                       |   30 +
+ tools/kvm/net/uip/buf.c                       |  114 ++
+ tools/kvm/net/uip/core.c                      |  190 +++
+ tools/kvm/net/uip/csum.c                      |   92 ++
+ tools/kvm/net/uip/dhcp.c                      |  203 ++++
+ tools/kvm/net/uip/icmp.c                      |   29 +
+ tools/kvm/net/uip/ipv4.c                      |   29 +
+ tools/kvm/net/uip/tcp.c                       |  317 +++++
+ tools/kvm/net/uip/udp.c                       |  236 ++++
+ tools/kvm/pci.c                               |  213 ++++
+ tools/kvm/powerpc/boot.c                      |    8 +
+ tools/kvm/powerpc/cpu_info.c                  |  195 ++++
+ tools/kvm/powerpc/cpu_info.h                  |   42 +
+ tools/kvm/powerpc/include/kvm/barrier.h       |    6 +
+ tools/kvm/powerpc/include/kvm/kvm-arch.h      |   90 ++
+ tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h  |   76 ++
+ tools/kvm/powerpc/ioport.c                    |   18 +
+ tools/kvm/powerpc/irq.c                       |   75 ++
+ tools/kvm/powerpc/kvm-cpu.c                   |  293 +++++
+ tools/kvm/powerpc/kvm.c                       |  529 +++++++++
+ tools/kvm/powerpc/spapr.h                     |   93 ++
+ tools/kvm/powerpc/spapr_hcall.c               |  134 +++
+ tools/kvm/powerpc/spapr_hvcons.c              |  102 ++
+ tools/kvm/powerpc/spapr_hvcons.h              |   19 +
+ tools/kvm/powerpc/spapr_pci.c                 |  423 +++++++
+ tools/kvm/powerpc/spapr_pci.h                 |   57 +
+ tools/kvm/powerpc/spapr_rtas.c                |  229 ++++
+ tools/kvm/powerpc/xics.c                      |  514 +++++++++
+ tools/kvm/powerpc/xics.h                      |   23 +
+ tools/kvm/symbol.c                            |  131 +++
+ tools/kvm/term.c                              |  166 +++
+ tools/kvm/tests/Makefile                      |   19 +
+ tools/kvm/tests/boot/Makefile                 |   13 +
+ tools/kvm/tests/boot/init.c                   |   11 +
+ tools/kvm/tests/kernel/.gitignore             |    2 +
+ tools/kvm/tests/kernel/Makefile               |   20 +
+ tools/kvm/tests/kernel/README                 |   16 +
+ tools/kvm/tests/kernel/kernel.S               |    8 +
+ tools/kvm/tests/pit/.gitignore                |    2 +
+ tools/kvm/tests/pit/Makefile                  |   20 +
+ tools/kvm/tests/pit/README                    |   16 +
+ tools/kvm/tests/pit/tick.S                    |  109 ++
+ tools/kvm/ui/sdl.c                            |  303 +++++
+ tools/kvm/ui/vnc.c                            |  230 ++++
+ tools/kvm/util/KVMTOOLS-VERSION-GEN           |   40 +
+ tools/kvm/util/generate-cmdlist.sh            |   23 +
+ tools/kvm/util/kvm-ifup-vbr0                  |    6 +
+ tools/kvm/util/parse-options.c                |  577 ++++++++++
+ tools/kvm/util/rbtree-interval.c              |   89 ++
+ tools/kvm/util/read-write.c                   |  354 ++++++
+ tools/kvm/util/set_private_br.sh              |   51 +
+ tools/kvm/util/strbuf.c                       |   62 +
+ tools/kvm/util/threadpool.c                   |  145 +++
+ tools/kvm/util/util.c                         |  133 +++
+ tools/kvm/virtio/9p-pdu.c                     |  287 +++++
+ tools/kvm/virtio/9p.c                         | 1409 +++++++++++++++++++++++
+ tools/kvm/virtio/balloon.c                    |  267 +++++
+ tools/kvm/virtio/blk.c                        |  313 +++++
+ tools/kvm/virtio/console.c                    |  193 ++++
+ tools/kvm/virtio/core.c                       |  233 ++++
+ tools/kvm/virtio/mmio.c                       |  264 +++++
+ tools/kvm/virtio/net.c                        |  555 +++++++++
+ tools/kvm/virtio/pci.c                        |  377 ++++++
+ tools/kvm/virtio/rng.c                        |  194 ++++
+ tools/kvm/x86/bios.c                          |  174 +++
+ tools/kvm/x86/bios/.gitignore                 |    3 +
+ tools/kvm/x86/bios/bios-rom.S                 |   12 +
+ tools/kvm/x86/bios/e820.c                     |   72 ++
+ tools/kvm/x86/bios/entry.S                    |   92 ++
+ tools/kvm/x86/bios/gen-offsets.sh             |   14 +
+ tools/kvm/x86/bios/int10.c                    |  110 ++
+ tools/kvm/x86/bios/int15.c                    |   18 +
+ tools/kvm/x86/bios/local.S                    |    7 +
+ tools/kvm/x86/bios/macro.S                    |   25 +
+ tools/kvm/x86/bios/memcpy.c                   |   23 +
+ tools/kvm/x86/bios/rom.ld.S                   |   16 +
+ tools/kvm/x86/boot.c                          |   41 +
+ tools/kvm/x86/cpuid.c                         |   60 +
+ tools/kvm/x86/include/kvm/assembly.h          |   24 +
+ tools/kvm/x86/include/kvm/barrier.h           |   20 +
+ tools/kvm/x86/include/kvm/bios-export.h       |   13 +
+ tools/kvm/x86/include/kvm/bios.h              |   93 ++
+ tools/kvm/x86/include/kvm/boot-protocol.h     |   16 +
+ tools/kvm/x86/include/kvm/cpufeature.h        |   41 +
+ tools/kvm/x86/include/kvm/interrupt.h         |   26 +
+ tools/kvm/x86/include/kvm/kvm-arch.h          |   67 ++
+ tools/kvm/x86/include/kvm/kvm-cpu-arch.h      |   49 +
+ tools/kvm/x86/include/kvm/mptable.h           |    9 +
+ tools/kvm/x86/interrupt.c                     |   28 +
+ tools/kvm/x86/ioport.c                        |   77 ++
+ tools/kvm/x86/irq.c                           |  222 ++++
+ tools/kvm/x86/kvm-cpu.c                       |  425 +++++++
+ tools/kvm/x86/kvm.c                           |  372 ++++++
+ tools/kvm/x86/mptable.c                       |  287 +++++
+ 265 files changed, 26317 insertions(+), 1082 deletions(-)
+ create mode 100644 include/linux/smpboot.h
+ create mode 100644 tools/kvm/.gitignore
+ create mode 100644 tools/kvm/CREDITS-Git
+ create mode 100644 tools/kvm/Documentation/kernel-debugging.txt
+ create mode 100644 tools/kvm/Documentation/kvm-balloon.txt
+ create mode 100644 tools/kvm/Documentation/kvm-debug.txt
+ create mode 100644 tools/kvm/Documentation/kvm-list.txt
+ create mode 100644 tools/kvm/Documentation/kvm-pause.txt
+ create mode 100644 tools/kvm/Documentation/kvm-resume.txt
+ create mode 100644 tools/kvm/Documentation/kvm-run.txt
+ create mode 100644 tools/kvm/Documentation/kvm-sandbox.txt
+ create mode 100644 tools/kvm/Documentation/kvm-setup.txt
+ create mode 100644 tools/kvm/Documentation/kvm-stat.txt
+ create mode 100644 tools/kvm/Documentation/kvm-stop.txt
+ create mode 100644 tools/kvm/Documentation/kvm-version.txt
+ create mode 100644 tools/kvm/Documentation/virtio-console.txt
+ create mode 100644 tools/kvm/Makefile
+ create mode 100644 tools/kvm/README
+ create mode 100644 tools/kvm/builtin-balloon.c
+ create mode 100644 tools/kvm/builtin-debug.c
+ create mode 100644 tools/kvm/builtin-help.c
+ create mode 100644 tools/kvm/builtin-list.c
+ create mode 100644 tools/kvm/builtin-pause.c
+ create mode 100644 tools/kvm/builtin-resume.c
+ create mode 100644 tools/kvm/builtin-run.c
+ create mode 100644 tools/kvm/builtin-sandbox.c
+ create mode 100644 tools/kvm/builtin-setup.c
+ create mode 100644 tools/kvm/builtin-stat.c
+ create mode 100644 tools/kvm/builtin-stop.c
+ create mode 100644 tools/kvm/builtin-version.c
+ create mode 100644 tools/kvm/code16gcc.h
+ create mode 100644 tools/kvm/command-list.txt
+ create mode 100644 tools/kvm/config/feature-tests.mak
+ create mode 100644 tools/kvm/config/utilities.mak
+ create mode 100644 tools/kvm/disk/blk.c
+ create mode 100644 tools/kvm/disk/core.c
+ create mode 100644 tools/kvm/disk/qcow.c
+ create mode 100644 tools/kvm/disk/raw.c
+ create mode 100644 tools/kvm/framebuffer.c
+ create mode 100644 tools/kvm/guest/init.c
+ create mode 100644 tools/kvm/guest/init_stage2.c
+ create mode 100644 tools/kvm/guest/passwd
+ create mode 100644 tools/kvm/guest_compat.c
+ create mode 100644 tools/kvm/hw/i8042.c
+ create mode 100644 tools/kvm/hw/pci-shmem.c
+ create mode 100644 tools/kvm/hw/rtc.c
+ create mode 100644 tools/kvm/hw/serial.c
+ create mode 100644 tools/kvm/hw/vesa.c
+ create mode 100644 tools/kvm/include/asm/hweight.h
+ create mode 100644 tools/kvm/include/bios/memcpy.h
+ create mode 100644 tools/kvm/include/kvm/8250-serial.h
+ create mode 100644 tools/kvm/include/kvm/apic.h
+ create mode 100644 tools/kvm/include/kvm/brlock.h
+ create mode 100644 tools/kvm/include/kvm/builtin-balloon.h
+ create mode 100644 tools/kvm/include/kvm/builtin-debug.h
+ create mode 100644 tools/kvm/include/kvm/builtin-help.h
+ create mode 100644 tools/kvm/include/kvm/builtin-list.h
+ create mode 100644 tools/kvm/include/kvm/builtin-pause.h
+ create mode 100644 tools/kvm/include/kvm/builtin-resume.h
+ create mode 100644 tools/kvm/include/kvm/builtin-run.h
+ create mode 100644 tools/kvm/include/kvm/builtin-sandbox.h
+ create mode 100644 tools/kvm/include/kvm/builtin-setup.h
+ create mode 100644 tools/kvm/include/kvm/builtin-stat.h
+ create mode 100644 tools/kvm/include/kvm/builtin-stop.h
+ create mode 100644 tools/kvm/include/kvm/builtin-version.h
+ create mode 100644 tools/kvm/include/kvm/compiler.h
+ create mode 100644 tools/kvm/include/kvm/disk-image.h
+ create mode 100644 tools/kvm/include/kvm/e820.h
+ create mode 100644 tools/kvm/include/kvm/framebuffer.h
+ create mode 100644 tools/kvm/include/kvm/guest_compat.h
+ create mode 100644 tools/kvm/include/kvm/i8042.h
+ create mode 100644 tools/kvm/include/kvm/ioeventfd.h
+ create mode 100644 tools/kvm/include/kvm/ioport.h
+ create mode 100644 tools/kvm/include/kvm/irq.h
+ create mode 100644 tools/kvm/include/kvm/kvm-cmd.h
+ create mode 100644 tools/kvm/include/kvm/kvm-cpu.h
+ create mode 100644 tools/kvm/include/kvm/kvm-ipc.h
+ create mode 100644 tools/kvm/include/kvm/kvm.h
+ create mode 100644 tools/kvm/include/kvm/msi.h
+ create mode 100644 tools/kvm/include/kvm/mutex.h
+ create mode 100644 tools/kvm/include/kvm/parse-options.h
+ create mode 100644 tools/kvm/include/kvm/pci-shmem.h
+ create mode 100644 tools/kvm/include/kvm/pci.h
+ create mode 100644 tools/kvm/include/kvm/qcow.h
+ create mode 100644 tools/kvm/include/kvm/rbtree-interval.h
+ create mode 100644 tools/kvm/include/kvm/read-write.h
+ create mode 100644 tools/kvm/include/kvm/rtc.h
+ create mode 100644 tools/kvm/include/kvm/rwsem.h
+ create mode 100644 tools/kvm/include/kvm/sdl.h
+ create mode 100644 tools/kvm/include/kvm/segment.h
+ create mode 100644 tools/kvm/include/kvm/strbuf.h
+ create mode 100644 tools/kvm/include/kvm/symbol.h
+ create mode 100644 tools/kvm/include/kvm/term.h
+ create mode 100644 tools/kvm/include/kvm/threadpool.h
+ create mode 100644 tools/kvm/include/kvm/types.h
+ create mode 100644 tools/kvm/include/kvm/uip.h
+ create mode 100644 tools/kvm/include/kvm/util.h
+ create mode 100644 tools/kvm/include/kvm/vesa.h
+ create mode 100644 tools/kvm/include/kvm/virtio-9p.h
+ create mode 100644 tools/kvm/include/kvm/virtio-balloon.h
+ create mode 100644 tools/kvm/include/kvm/virtio-blk.h
+ create mode 100644 tools/kvm/include/kvm/virtio-console.h
+ create mode 100644 tools/kvm/include/kvm/virtio-mmio.h
+ create mode 100644 tools/kvm/include/kvm/virtio-net.h
+ create mode 100644 tools/kvm/include/kvm/virtio-pci-dev.h
+ create mode 100644 tools/kvm/include/kvm/virtio-pci.h
+ create mode 100644 tools/kvm/include/kvm/virtio-rng.h
+ create mode 100644 tools/kvm/include/kvm/virtio.h
+ create mode 100644 tools/kvm/include/kvm/vnc.h
+ create mode 100644 tools/kvm/include/linux/bitops.h
+ create mode 100644 tools/kvm/include/linux/byteorder.h
+ create mode 100644 tools/kvm/include/linux/compiler.h
+ create mode 100644 tools/kvm/include/linux/kernel.h
+ create mode 100644 tools/kvm/include/linux/module.h
+ create mode 100644 tools/kvm/include/linux/prefetch.h
+ create mode 100644 tools/kvm/include/linux/stddef.h
+ create mode 100644 tools/kvm/include/linux/types.h
+ create mode 100644 tools/kvm/ioeventfd.c
+ create mode 100644 tools/kvm/ioport.c
+ create mode 100644 tools/kvm/kvm-cmd.c
+ create mode 100644 tools/kvm/kvm-cpu.c
+ create mode 100644 tools/kvm/kvm-ipc.c
+ create mode 100644 tools/kvm/kvm.c
+ create mode 100644 tools/kvm/main.c
+ create mode 100644 tools/kvm/mmio.c
+ create mode 100644 tools/kvm/net/uip/arp.c
+ create mode 100644 tools/kvm/net/uip/buf.c
+ create mode 100644 tools/kvm/net/uip/core.c
+ create mode 100644 tools/kvm/net/uip/csum.c
+ create mode 100644 tools/kvm/net/uip/dhcp.c
+ create mode 100644 tools/kvm/net/uip/icmp.c
+ create mode 100644 tools/kvm/net/uip/ipv4.c
+ create mode 100644 tools/kvm/net/uip/tcp.c
+ create mode 100644 tools/kvm/net/uip/udp.c
+ create mode 100644 tools/kvm/pci.c
+ create mode 100644 tools/kvm/powerpc/boot.c
+ create mode 100644 tools/kvm/powerpc/cpu_info.c
+ create mode 100644 tools/kvm/powerpc/cpu_info.h
+ create mode 100644 tools/kvm/powerpc/include/kvm/barrier.h
+ create mode 100644 tools/kvm/powerpc/include/kvm/kvm-arch.h
+ create mode 100644 tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h
+ create mode 100644 tools/kvm/powerpc/ioport.c
+ create mode 100644 tools/kvm/powerpc/irq.c
+ create mode 100644 tools/kvm/powerpc/kvm-cpu.c
+ create mode 100644 tools/kvm/powerpc/kvm.c
+ create mode 100644 tools/kvm/powerpc/spapr.h
+ create mode 100644 tools/kvm/powerpc/spapr_hcall.c
+ create mode 100644 tools/kvm/powerpc/spapr_hvcons.c
+ create mode 100644 tools/kvm/powerpc/spapr_hvcons.h
+ create mode 100644 tools/kvm/powerpc/spapr_pci.c
+ create mode 100644 tools/kvm/powerpc/spapr_pci.h
+ create mode 100644 tools/kvm/powerpc/spapr_rtas.c
+ create mode 100644 tools/kvm/powerpc/xics.c
+ create mode 100644 tools/kvm/powerpc/xics.h
+ create mode 100644 tools/kvm/symbol.c
+ create mode 100644 tools/kvm/term.c
+ create mode 100644 tools/kvm/tests/Makefile
+ create mode 100644 tools/kvm/tests/boot/Makefile
+ create mode 100644 tools/kvm/tests/boot/init.c
+ create mode 100644 tools/kvm/tests/kernel/.gitignore
+ create mode 100644 tools/kvm/tests/kernel/Makefile
+ create mode 100644 tools/kvm/tests/kernel/README
+ create mode 100644 tools/kvm/tests/kernel/kernel.S
+ create mode 100644 tools/kvm/tests/pit/.gitignore
+ create mode 100644 tools/kvm/tests/pit/Makefile
+ create mode 100644 tools/kvm/tests/pit/README
+ create mode 100644 tools/kvm/tests/pit/tick.S
+ create mode 100644 tools/kvm/ui/sdl.c
+ create mode 100644 tools/kvm/ui/vnc.c
+ create mode 100755 tools/kvm/util/KVMTOOLS-VERSION-GEN
+ create mode 100755 tools/kvm/util/generate-cmdlist.sh
+ create mode 100755 tools/kvm/util/kvm-ifup-vbr0
+ create mode 100644 tools/kvm/util/parse-options.c
+ create mode 100644 tools/kvm/util/rbtree-interval.c
+ create mode 100644 tools/kvm/util/read-write.c
+ create mode 100755 tools/kvm/util/set_private_br.sh
+ create mode 100644 tools/kvm/util/strbuf.c
+ create mode 100644 tools/kvm/util/threadpool.c
+ create mode 100644 tools/kvm/util/util.c
+ create mode 100644 tools/kvm/virtio/9p-pdu.c
+ create mode 100644 tools/kvm/virtio/9p.c
+ create mode 100644 tools/kvm/virtio/balloon.c
+ create mode 100644 tools/kvm/virtio/blk.c
+ create mode 100644 tools/kvm/virtio/console.c
+ create mode 100644 tools/kvm/virtio/core.c
+ create mode 100644 tools/kvm/virtio/mmio.c
+ create mode 100644 tools/kvm/virtio/net.c
+ create mode 100644 tools/kvm/virtio/pci.c
+ create mode 100644 tools/kvm/virtio/rng.c
+ create mode 100644 tools/kvm/x86/bios.c
+ create mode 100644 tools/kvm/x86/bios/.gitignore
+ create mode 100644 tools/kvm/x86/bios/bios-rom.S
+ create mode 100644 tools/kvm/x86/bios/e820.c
+ create mode 100644 tools/kvm/x86/bios/entry.S
+ create mode 100644 tools/kvm/x86/bios/gen-offsets.sh
+ create mode 100644 tools/kvm/x86/bios/int10.c
+ create mode 100644 tools/kvm/x86/bios/int15.c
+ create mode 100644 tools/kvm/x86/bios/local.S
+ create mode 100644 tools/kvm/x86/bios/macro.S
+ create mode 100644 tools/kvm/x86/bios/memcpy.c
+ create mode 100644 tools/kvm/x86/bios/rom.ld.S
+ create mode 100644 tools/kvm/x86/boot.c
+ create mode 100644 tools/kvm/x86/cpuid.c
+ create mode 100644 tools/kvm/x86/include/kvm/assembly.h
+ create mode 100644 tools/kvm/x86/include/kvm/barrier.h
+ create mode 100644 tools/kvm/x86/include/kvm/bios-export.h
+ create mode 100644 tools/kvm/x86/include/kvm/bios.h
+ create mode 100644 tools/kvm/x86/include/kvm/boot-protocol.h
+ create mode 100644 tools/kvm/x86/include/kvm/cpufeature.h
+ create mode 100644 tools/kvm/x86/include/kvm/interrupt.h
+ create mode 100644 tools/kvm/x86/include/kvm/kvm-arch.h
+ create mode 100644 tools/kvm/x86/include/kvm/kvm-cpu-arch.h
+ create mode 100644 tools/kvm/x86/include/kvm/mptable.h
+ create mode 100644 tools/kvm/x86/interrupt.c
+ create mode 100644 tools/kvm/x86/ioport.c
+ create mode 100644 tools/kvm/x86/irq.c
+ create mode 100644 tools/kvm/x86/kvm-cpu.c
+ create mode 100644 tools/kvm/x86/kvm.c
+ create mode 100644 tools/kvm/x86/mptable.c
+$ git reset --hard HEAD^
+HEAD is now at 9694ab0 Merge remote-tracking branch 'spi-mb/spi-next'
+Merging refs/next/20120814/tip
+$ git merge refs/next/20120814/tip
+Auto-merging arch/x86/Kconfig
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ MAINTAINERS                                  |    8 +
+ arch/x86/Kconfig                             |   31 +
+ arch/x86/kernel/cpu/amd.c                    |   67 ++
+ arch/x86/kernel/cpu/common.c                 |    5 +-
+ arch/x86/kernel/cpu/intel.c                  |    4 +
+ scripts/kconfig/Makefile                     |    7 +-
+ tools/kvm/.gitignore                         |   12 +
+ tools/kvm/CREDITS-Git                        |   30 +
+ tools/kvm/Documentation/kernel-debugging.txt |   15 +
+ tools/kvm/Documentation/kvm-balloon.txt      |   24 +
+ tools/kvm/Documentation/kvm-debug.txt        |   16 +
+ tools/kvm/Documentation/kvm-list.txt         |   16 +
+ tools/kvm/Documentation/kvm-pause.txt        |   16 +
+ tools/kvm/Documentation/kvm-resume.txt       |   16 +
+ tools/kvm/Documentation/kvm-run.txt          |   62 ++
+ tools/kvm/Documentation/kvm-sandbox.txt      |   16 +
+ tools/kvm/Documentation/kvm-setup.txt        |   15 +
+ tools/kvm/Documentation/kvm-stat.txt         |   19 +
+ tools/kvm/Documentation/kvm-stop.txt         |   16 +
+ tools/kvm/Documentation/kvm-version.txt      |   21 +
+ tools/kvm/Documentation/virtio-console.txt   |   41 +
+ tools/kvm/Makefile                           |  427 +++++++
+ tools/kvm/README                             |  112 ++
+ tools/kvm/builtin-balloon.c                  |   80 ++
+ tools/kvm/builtin-debug.c                    |  110 ++
+ tools/kvm/builtin-help.c                     |   63 ++
+ tools/kvm/builtin-list.c                     |  149 +++
+ tools/kvm/builtin-pause.c                    |   88 ++
+ tools/kvm/builtin-resume.c                   |   88 ++
+ tools/kvm/builtin-run.c                      | 1393 +++++++++++++++++++++++
+ tools/kvm/builtin-sandbox.c                  |    9 +
+ tools/kvm/builtin-setup.c                    |  232 ++++
+ tools/kvm/builtin-stat.c                     |  127 +++
+ tools/kvm/builtin-stop.c                     |   70 ++
+ tools/kvm/builtin-version.c                  |   15 +
+ tools/kvm/code16gcc.h                        |   15 +
+ tools/kvm/command-list.txt                   |   15 +
+ tools/kvm/config/feature-tests.mak           |  177 +++
+ tools/kvm/config/utilities.mak               |  196 ++++
+ tools/kvm/disk/blk.c                         |   76 ++
+ tools/kvm/disk/core.c                        |  275 +++++
+ tools/kvm/disk/qcow.c                        | 1529 ++++++++++++++++++++++++++
+ tools/kvm/disk/raw.c                         |  141 +++
+ tools/kvm/framebuffer.c                      |   75 ++
+ tools/kvm/guest/init.c                       |   38 +
+ tools/kvm/guest/init_stage2.c                |   55 +
+ tools/kvm/guest/passwd                       |    1 +
+ tools/kvm/guest_compat.c                     |   99 ++
+ tools/kvm/hw/i8042.c                         |  348 ++++++
+ tools/kvm/hw/pci-shmem.c                     |  268 +++++
+ tools/kvm/hw/rtc.c                           |  137 +++
+ tools/kvm/hw/serial.c                        |  446 ++++++++
+ tools/kvm/hw/vesa.c                          |   85 ++
+ tools/kvm/include/asm/hweight.h              |    8 +
+ tools/kvm/include/bios/memcpy.h              |    9 +
+ tools/kvm/include/kvm/8250-serial.h          |   11 +
+ tools/kvm/include/kvm/apic.h                 |   17 +
+ tools/kvm/include/kvm/brlock.h               |   41 +
+ tools/kvm/include/kvm/builtin-balloon.h      |    9 +
+ tools/kvm/include/kvm/builtin-debug.h        |   20 +
+ tools/kvm/include/kvm/builtin-help.h         |    6 +
+ tools/kvm/include/kvm/builtin-list.h         |   10 +
+ tools/kvm/include/kvm/builtin-pause.h        |    9 +
+ tools/kvm/include/kvm/builtin-resume.h       |    9 +
+ tools/kvm/include/kvm/builtin-run.h          |   11 +
+ tools/kvm/include/kvm/builtin-sandbox.h      |    6 +
+ tools/kvm/include/kvm/builtin-setup.h        |   11 +
+ tools/kvm/include/kvm/builtin-stat.h         |    9 +
+ tools/kvm/include/kvm/builtin-stop.h         |    9 +
+ tools/kvm/include/kvm/builtin-version.h      |    6 +
+ tools/kvm/include/kvm/compiler.h             |   10 +
+ tools/kvm/include/kvm/disk-image.h           |   87 ++
+ tools/kvm/include/kvm/e820.h                 |   13 +
+ tools/kvm/include/kvm/framebuffer.h          |   35 +
+ tools/kvm/include/kvm/guest_compat.h         |    9 +
+ tools/kvm/include/kvm/i8042.h                |   12 +
+ tools/kvm/include/kvm/ioeventfd.h            |   28 +
+ tools/kvm/include/kvm/ioport.h               |   69 ++
+ tools/kvm/include/kvm/irq.h                  |   33 +
+ tools/kvm/include/kvm/kvm-cmd.h              |   17 +
+ tools/kvm/include/kvm/kvm-cpu.h              |   24 +
+ tools/kvm/include/kvm/kvm-ipc.h              |   24 +
+ tools/kvm/include/kvm/kvm.h                  |   93 ++
+ tools/kvm/include/kvm/msi.h                  |   10 +
+ tools/kvm/include/kvm/mutex.h                |   33 +
+ tools/kvm/include/kvm/parse-options.h        |  214 ++++
+ tools/kvm/include/kvm/pci-shmem.h            |   28 +
+ tools/kvm/include/kvm/pci.h                  |   95 ++
+ tools/kvm/include/kvm/qcow.h                 |  133 +++
+ tools/kvm/include/kvm/rbtree-interval.h      |   28 +
+ tools/kvm/include/kvm/read-write.h           |   43 +
+ tools/kvm/include/kvm/rtc.h                  |    9 +
+ tools/kvm/include/kvm/rwsem.h                |   39 +
+ tools/kvm/include/kvm/sdl.h                  |   22 +
+ tools/kvm/include/kvm/segment.h              |   21 +
+ tools/kvm/include/kvm/strbuf.h               |   20 +
+ tools/kvm/include/kvm/symbol.h               |   30 +
+ tools/kvm/include/kvm/term.h                 |   20 +
+ tools/kvm/include/kvm/threadpool.h           |   37 +
+ tools/kvm/include/kvm/types.h                |    7 +
+ tools/kvm/include/kvm/uip.h                  |  358 ++++++
+ tools/kvm/include/kvm/util.h                 |   97 ++
+ tools/kvm/include/kvm/vesa.h                 |   18 +
+ tools/kvm/include/kvm/virtio-9p.h            |   73 ++
+ tools/kvm/include/kvm/virtio-balloon.h       |    8 +
+ tools/kvm/include/kvm/virtio-blk.h           |   12 +
+ tools/kvm/include/kvm/virtio-console.h       |    9 +
+ tools/kvm/include/kvm/virtio-mmio.h          |   58 +
+ tools/kvm/include/kvm/virtio-net.h           |   26 +
+ tools/kvm/include/kvm/virtio-pci-dev.h       |   37 +
+ tools/kvm/include/kvm/virtio-pci.h           |   46 +
+ tools/kvm/include/kvm/virtio-rng.h           |    9 +
+ tools/kvm/include/kvm/virtio.h               |  103 ++
+ tools/kvm/include/kvm/vnc.h                  |   20 +
+ tools/kvm/include/linux/bitops.h             |   33 +
+ tools/kvm/include/linux/byteorder.h          |    7 +
+ tools/kvm/include/linux/compiler.h           |   19 +
+ tools/kvm/include/linux/kernel.h             |   39 +
+ tools/kvm/include/linux/module.h             |    6 +
+ tools/kvm/include/linux/prefetch.h           |    6 +
+ tools/kvm/include/linux/stddef.h             |   16 +
+ tools/kvm/include/linux/types.h              |   51 +
+ tools/kvm/ioeventfd.c                        |  215 ++++
+ tools/kvm/ioport.c                           |  195 ++++
+ tools/kvm/kvm-cmd.c                          |   91 ++
+ tools/kvm/kvm-cpu.c                          |  175 +++
+ tools/kvm/kvm-ipc.c                          |  231 ++++
+ tools/kvm/kvm.c                              |  593 ++++++++++
+ tools/kvm/main.c                             |   19 +
+ tools/kvm/mmio.c                             |  140 +++
+ tools/kvm/net/uip/arp.c                      |   30 +
+ tools/kvm/net/uip/buf.c                      |  114 ++
+ tools/kvm/net/uip/core.c                     |  190 ++++
+ tools/kvm/net/uip/csum.c                     |   92 ++
+ tools/kvm/net/uip/dhcp.c                     |  203 ++++
+ tools/kvm/net/uip/icmp.c                     |   29 +
+ tools/kvm/net/uip/ipv4.c                     |   29 +
+ tools/kvm/net/uip/tcp.c                      |  317 ++++++
+ tools/kvm/net/uip/udp.c                      |  236 ++++
+ tools/kvm/pci.c                              |  213 ++++
+ tools/kvm/powerpc/boot.c                     |    8 +
+ tools/kvm/powerpc/cpu_info.c                 |  195 ++++
+ tools/kvm/powerpc/cpu_info.h                 |   42 +
+ tools/kvm/powerpc/include/kvm/barrier.h      |    6 +
+ tools/kvm/powerpc/include/kvm/kvm-arch.h     |   90 ++
+ tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h |   76 ++
+ tools/kvm/powerpc/ioport.c                   |   18 +
+ tools/kvm/powerpc/irq.c                      |   75 ++
+ tools/kvm/powerpc/kvm-cpu.c                  |  293 +++++
+ tools/kvm/powerpc/kvm.c                      |  529 +++++++++
+ tools/kvm/powerpc/spapr.h                    |   93 ++
+ tools/kvm/powerpc/spapr_hcall.c              |  134 +++
+ tools/kvm/powerpc/spapr_hvcons.c             |  102 ++
+ tools/kvm/powerpc/spapr_hvcons.h             |   19 +
+ tools/kvm/powerpc/spapr_pci.c                |  423 +++++++
+ tools/kvm/powerpc/spapr_pci.h                |   57 +
+ tools/kvm/powerpc/spapr_rtas.c               |  229 ++++
+ tools/kvm/powerpc/xics.c                     |  514 +++++++++
+ tools/kvm/powerpc/xics.h                     |   23 +
+ tools/kvm/symbol.c                           |  131 +++
+ tools/kvm/term.c                             |  166 +++
+ tools/kvm/tests/Makefile                     |   19 +
+ tools/kvm/tests/boot/Makefile                |   13 +
+ tools/kvm/tests/boot/init.c                  |   11 +
+ tools/kvm/tests/kernel/.gitignore            |    2 +
+ tools/kvm/tests/kernel/Makefile              |   20 +
+ tools/kvm/tests/kernel/README                |   16 +
+ tools/kvm/tests/kernel/kernel.S              |    8 +
+ tools/kvm/tests/pit/.gitignore               |    2 +
+ tools/kvm/tests/pit/Makefile                 |   20 +
+ tools/kvm/tests/pit/README                   |   16 +
+ tools/kvm/tests/pit/tick.S                   |  109 ++
+ tools/kvm/ui/sdl.c                           |  303 +++++
+ tools/kvm/ui/vnc.c                           |  230 ++++
+ tools/kvm/util/KVMTOOLS-VERSION-GEN          |   40 +
+ tools/kvm/util/generate-cmdlist.sh           |   23 +
+ tools/kvm/util/kvm-ifup-vbr0                 |    6 +
+ tools/kvm/util/parse-options.c               |  577 ++++++++++
+ tools/kvm/util/rbtree-interval.c             |   89 ++
+ tools/kvm/util/read-write.c                  |  354 ++++++
+ tools/kvm/util/set_private_br.sh             |   51 +
+ tools/kvm/util/strbuf.c                      |   62 ++
+ tools/kvm/util/threadpool.c                  |  145 +++
+ tools/kvm/util/util.c                        |  133 +++
+ tools/kvm/virtio/9p-pdu.c                    |  287 +++++
+ tools/kvm/virtio/9p.c                        | 1409 ++++++++++++++++++++++++
+ tools/kvm/virtio/balloon.c                   |  267 +++++
+ tools/kvm/virtio/blk.c                       |  313 ++++++
+ tools/kvm/virtio/console.c                   |  193 ++++
+ tools/kvm/virtio/core.c                      |  233 ++++
+ tools/kvm/virtio/mmio.c                      |  264 +++++
+ tools/kvm/virtio/net.c                       |  555 ++++++++++
+ tools/kvm/virtio/pci.c                       |  377 +++++++
+ tools/kvm/virtio/rng.c                       |  194 ++++
+ tools/kvm/x86/bios.c                         |  174 +++
+ tools/kvm/x86/bios/.gitignore                |    3 +
+ tools/kvm/x86/bios/bios-rom.S                |   12 +
+ tools/kvm/x86/bios/e820.c                    |   72 ++
+ tools/kvm/x86/bios/entry.S                   |   92 ++
+ tools/kvm/x86/bios/gen-offsets.sh            |   14 +
+ tools/kvm/x86/bios/int10.c                   |  110 ++
+ tools/kvm/x86/bios/int15.c                   |   18 +
+ tools/kvm/x86/bios/local.S                   |    7 +
+ tools/kvm/x86/bios/macro.S                   |   25 +
+ tools/kvm/x86/bios/memcpy.c                  |   23 +
+ tools/kvm/x86/bios/rom.ld.S                  |   16 +
+ tools/kvm/x86/boot.c                         |   41 +
+ tools/kvm/x86/cpuid.c                        |   60 +
+ tools/kvm/x86/include/kvm/assembly.h         |   24 +
+ tools/kvm/x86/include/kvm/barrier.h          |   20 +
+ tools/kvm/x86/include/kvm/bios-export.h      |   13 +
+ tools/kvm/x86/include/kvm/bios.h             |   93 ++
+ tools/kvm/x86/include/kvm/boot-protocol.h    |   16 +
+ tools/kvm/x86/include/kvm/cpufeature.h       |   41 +
+ tools/kvm/x86/include/kvm/interrupt.h        |   26 +
+ tools/kvm/x86/include/kvm/kvm-arch.h         |   67 ++
+ tools/kvm/x86/include/kvm/kvm-cpu-arch.h     |   49 +
+ tools/kvm/x86/include/kvm/mptable.h          |    9 +
+ tools/kvm/x86/interrupt.c                    |   28 +
+ tools/kvm/x86/ioport.c                       |   77 ++
+ tools/kvm/x86/irq.c                          |  222 ++++
+ tools/kvm/x86/kvm-cpu.c                      |  425 +++++++
+ tools/kvm/x86/kvm.c                          |  372 +++++++
+ tools/kvm/x86/mptable.c                      |  287 +++++
+ 224 files changed, 24999 insertions(+), 4 deletions(-)
+ create mode 100644 tools/kvm/.gitignore
+ create mode 100644 tools/kvm/CREDITS-Git
+ create mode 100644 tools/kvm/Documentation/kernel-debugging.txt
+ create mode 100644 tools/kvm/Documentation/kvm-balloon.txt
+ create mode 100644 tools/kvm/Documentation/kvm-debug.txt
+ create mode 100644 tools/kvm/Documentation/kvm-list.txt
+ create mode 100644 tools/kvm/Documentation/kvm-pause.txt
+ create mode 100644 tools/kvm/Documentation/kvm-resume.txt
+ create mode 100644 tools/kvm/Documentation/kvm-run.txt
+ create mode 100644 tools/kvm/Documentation/kvm-sandbox.txt
+ create mode 100644 tools/kvm/Documentation/kvm-setup.txt
+ create mode 100644 tools/kvm/Documentation/kvm-stat.txt
+ create mode 100644 tools/kvm/Documentation/kvm-stop.txt
+ create mode 100644 tools/kvm/Documentation/kvm-version.txt
+ create mode 100644 tools/kvm/Documentation/virtio-console.txt
+ create mode 100644 tools/kvm/Makefile
+ create mode 100644 tools/kvm/README
+ create mode 100644 tools/kvm/builtin-balloon.c
+ create mode 100644 tools/kvm/builtin-debug.c
+ create mode 100644 tools/kvm/builtin-help.c
+ create mode 100644 tools/kvm/builtin-list.c
+ create mode 100644 tools/kvm/builtin-pause.c
+ create mode 100644 tools/kvm/builtin-resume.c
+ create mode 100644 tools/kvm/builtin-run.c
+ create mode 100644 tools/kvm/builtin-sandbox.c
+ create mode 100644 tools/kvm/builtin-setup.c
+ create mode 100644 tools/kvm/builtin-stat.c
+ create mode 100644 tools/kvm/builtin-stop.c
+ create mode 100644 tools/kvm/builtin-version.c
+ create mode 100644 tools/kvm/code16gcc.h
+ create mode 100644 tools/kvm/command-list.txt
+ create mode 100644 tools/kvm/config/feature-tests.mak
+ create mode 100644 tools/kvm/config/utilities.mak
+ create mode 100644 tools/kvm/disk/blk.c
+ create mode 100644 tools/kvm/disk/core.c
+ create mode 100644 tools/kvm/disk/qcow.c
+ create mode 100644 tools/kvm/disk/raw.c
+ create mode 100644 tools/kvm/framebuffer.c
+ create mode 100644 tools/kvm/guest/init.c
+ create mode 100644 tools/kvm/guest/init_stage2.c
+ create mode 100644 tools/kvm/guest/passwd
+ create mode 100644 tools/kvm/guest_compat.c
+ create mode 100644 tools/kvm/hw/i8042.c
+ create mode 100644 tools/kvm/hw/pci-shmem.c
+ create mode 100644 tools/kvm/hw/rtc.c
+ create mode 100644 tools/kvm/hw/serial.c
+ create mode 100644 tools/kvm/hw/vesa.c
+ create mode 100644 tools/kvm/include/asm/hweight.h
+ create mode 100644 tools/kvm/include/bios/memcpy.h
+ create mode 100644 tools/kvm/include/kvm/8250-serial.h
+ create mode 100644 tools/kvm/include/kvm/apic.h
+ create mode 100644 tools/kvm/include/kvm/brlock.h
+ create mode 100644 tools/kvm/include/kvm/builtin-balloon.h
+ create mode 100644 tools/kvm/include/kvm/builtin-debug.h
+ create mode 100644 tools/kvm/include/kvm/builtin-help.h
+ create mode 100644 tools/kvm/include/kvm/builtin-list.h
+ create mode 100644 tools/kvm/include/kvm/builtin-pause.h
+ create mode 100644 tools/kvm/include/kvm/builtin-resume.h
+ create mode 100644 tools/kvm/include/kvm/builtin-run.h
+ create mode 100644 tools/kvm/include/kvm/builtin-sandbox.h
+ create mode 100644 tools/kvm/include/kvm/builtin-setup.h
+ create mode 100644 tools/kvm/include/kvm/builtin-stat.h
+ create mode 100644 tools/kvm/include/kvm/builtin-stop.h
+ create mode 100644 tools/kvm/include/kvm/builtin-version.h
+ create mode 100644 tools/kvm/include/kvm/compiler.h
+ create mode 100644 tools/kvm/include/kvm/disk-image.h
+ create mode 100644 tools/kvm/include/kvm/e820.h
+ create mode 100644 tools/kvm/include/kvm/framebuffer.h
+ create mode 100644 tools/kvm/include/kvm/guest_compat.h
+ create mode 100644 tools/kvm/include/kvm/i8042.h
+ create mode 100644 tools/kvm/include/kvm/ioeventfd.h
+ create mode 100644 tools/kvm/include/kvm/ioport.h
+ create mode 100644 tools/kvm/include/kvm/irq.h
+ create mode 100644 tools/kvm/include/kvm/kvm-cmd.h
+ create mode 100644 tools/kvm/include/kvm/kvm-cpu.h
+ create mode 100644 tools/kvm/include/kvm/kvm-ipc.h
+ create mode 100644 tools/kvm/include/kvm/kvm.h
+ create mode 100644 tools/kvm/include/kvm/msi.h
+ create mode 100644 tools/kvm/include/kvm/mutex.h
+ create mode 100644 tools/kvm/include/kvm/parse-options.h
+ create mode 100644 tools/kvm/include/kvm/pci-shmem.h
+ create mode 100644 tools/kvm/include/kvm/pci.h
+ create mode 100644 tools/kvm/include/kvm/qcow.h
+ create mode 100644 tools/kvm/include/kvm/rbtree-interval.h
+ create mode 100644 tools/kvm/include/kvm/read-write.h
+ create mode 100644 tools/kvm/include/kvm/rtc.h
+ create mode 100644 tools/kvm/include/kvm/rwsem.h
+ create mode 100644 tools/kvm/include/kvm/sdl.h
+ create mode 100644 tools/kvm/include/kvm/segment.h
+ create mode 100644 tools/kvm/include/kvm/strbuf.h
+ create mode 100644 tools/kvm/include/kvm/symbol.h
+ create mode 100644 tools/kvm/include/kvm/term.h
+ create mode 100644 tools/kvm/include/kvm/threadpool.h
+ create mode 100644 tools/kvm/include/kvm/types.h
+ create mode 100644 tools/kvm/include/kvm/uip.h
+ create mode 100644 tools/kvm/include/kvm/util.h
+ create mode 100644 tools/kvm/include/kvm/vesa.h
+ create mode 100644 tools/kvm/include/kvm/virtio-9p.h
+ create mode 100644 tools/kvm/include/kvm/virtio-balloon.h
+ create mode 100644 tools/kvm/include/kvm/virtio-blk.h
+ create mode 100644 tools/kvm/include/kvm/virtio-console.h
+ create mode 100644 tools/kvm/include/kvm/virtio-mmio.h
+ create mode 100644 tools/kvm/include/kvm/virtio-net.h
+ create mode 100644 tools/kvm/include/kvm/virtio-pci-dev.h
+ create mode 100644 tools/kvm/include/kvm/virtio-pci.h
+ create mode 100644 tools/kvm/include/kvm/virtio-rng.h
+ create mode 100644 tools/kvm/include/kvm/virtio.h
+ create mode 100644 tools/kvm/include/kvm/vnc.h
+ create mode 100644 tools/kvm/include/linux/bitops.h
+ create mode 100644 tools/kvm/include/linux/byteorder.h
+ create mode 100644 tools/kvm/include/linux/compiler.h
+ create mode 100644 tools/kvm/include/linux/kernel.h
+ create mode 100644 tools/kvm/include/linux/module.h
+ create mode 100644 tools/kvm/include/linux/prefetch.h
+ create mode 100644 tools/kvm/include/linux/stddef.h
+ create mode 100644 tools/kvm/include/linux/types.h
+ create mode 100644 tools/kvm/ioeventfd.c
+ create mode 100644 tools/kvm/ioport.c
+ create mode 100644 tools/kvm/kvm-cmd.c
+ create mode 100644 tools/kvm/kvm-cpu.c
+ create mode 100644 tools/kvm/kvm-ipc.c
+ create mode 100644 tools/kvm/kvm.c
+ create mode 100644 tools/kvm/main.c
+ create mode 100644 tools/kvm/mmio.c
+ create mode 100644 tools/kvm/net/uip/arp.c
+ create mode 100644 tools/kvm/net/uip/buf.c
+ create mode 100644 tools/kvm/net/uip/core.c
+ create mode 100644 tools/kvm/net/uip/csum.c
+ create mode 100644 tools/kvm/net/uip/dhcp.c
+ create mode 100644 tools/kvm/net/uip/icmp.c
+ create mode 100644 tools/kvm/net/uip/ipv4.c
+ create mode 100644 tools/kvm/net/uip/tcp.c
+ create mode 100644 tools/kvm/net/uip/udp.c
+ create mode 100644 tools/kvm/pci.c
+ create mode 100644 tools/kvm/powerpc/boot.c
+ create mode 100644 tools/kvm/powerpc/cpu_info.c
+ create mode 100644 tools/kvm/powerpc/cpu_info.h
+ create mode 100644 tools/kvm/powerpc/include/kvm/barrier.h
+ create mode 100644 tools/kvm/powerpc/include/kvm/kvm-arch.h
+ create mode 100644 tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h
+ create mode 100644 tools/kvm/powerpc/ioport.c
+ create mode 100644 tools/kvm/powerpc/irq.c
+ create mode 100644 tools/kvm/powerpc/kvm-cpu.c
+ create mode 100644 tools/kvm/powerpc/kvm.c
+ create mode 100644 tools/kvm/powerpc/spapr.h
+ create mode 100644 tools/kvm/powerpc/spapr_hcall.c
+ create mode 100644 tools/kvm/powerpc/spapr_hvcons.c
+ create mode 100644 tools/kvm/powerpc/spapr_hvcons.h
+ create mode 100644 tools/kvm/powerpc/spapr_pci.c
+ create mode 100644 tools/kvm/powerpc/spapr_pci.h
+ create mode 100644 tools/kvm/powerpc/spapr_rtas.c
+ create mode 100644 tools/kvm/powerpc/xics.c
+ create mode 100644 tools/kvm/powerpc/xics.h
+ create mode 100644 tools/kvm/symbol.c
+ create mode 100644 tools/kvm/term.c
+ create mode 100644 tools/kvm/tests/Makefile
+ create mode 100644 tools/kvm/tests/boot/Makefile
+ create mode 100644 tools/kvm/tests/boot/init.c
+ create mode 100644 tools/kvm/tests/kernel/.gitignore
+ create mode 100644 tools/kvm/tests/kernel/Makefile
+ create mode 100644 tools/kvm/tests/kernel/README
+ create mode 100644 tools/kvm/tests/kernel/kernel.S
+ create mode 100644 tools/kvm/tests/pit/.gitignore
+ create mode 100644 tools/kvm/tests/pit/Makefile
+ create mode 100644 tools/kvm/tests/pit/README
+ create mode 100644 tools/kvm/tests/pit/tick.S
+ create mode 100644 tools/kvm/ui/sdl.c
+ create mode 100644 tools/kvm/ui/vnc.c
+ create mode 100755 tools/kvm/util/KVMTOOLS-VERSION-GEN
+ create mode 100755 tools/kvm/util/generate-cmdlist.sh
+ create mode 100755 tools/kvm/util/kvm-ifup-vbr0
+ create mode 100644 tools/kvm/util/parse-options.c
+ create mode 100644 tools/kvm/util/rbtree-interval.c
+ create mode 100644 tools/kvm/util/read-write.c
+ create mode 100755 tools/kvm/util/set_private_br.sh
+ create mode 100644 tools/kvm/util/strbuf.c
+ create mode 100644 tools/kvm/util/threadpool.c
+ create mode 100644 tools/kvm/util/util.c
+ create mode 100644 tools/kvm/virtio/9p-pdu.c
+ create mode 100644 tools/kvm/virtio/9p.c
+ create mode 100644 tools/kvm/virtio/balloon.c
+ create mode 100644 tools/kvm/virtio/blk.c
+ create mode 100644 tools/kvm/virtio/console.c
+ create mode 100644 tools/kvm/virtio/core.c
+ create mode 100644 tools/kvm/virtio/mmio.c
+ create mode 100644 tools/kvm/virtio/net.c
+ create mode 100644 tools/kvm/virtio/pci.c
+ create mode 100644 tools/kvm/virtio/rng.c
+ create mode 100644 tools/kvm/x86/bios.c
+ create mode 100644 tools/kvm/x86/bios/.gitignore
+ create mode 100644 tools/kvm/x86/bios/bios-rom.S
+ create mode 100644 tools/kvm/x86/bios/e820.c
+ create mode 100644 tools/kvm/x86/bios/entry.S
+ create mode 100644 tools/kvm/x86/bios/gen-offsets.sh
+ create mode 100644 tools/kvm/x86/bios/int10.c
+ create mode 100644 tools/kvm/x86/bios/int15.c
+ create mode 100644 tools/kvm/x86/bios/local.S
+ create mode 100644 tools/kvm/x86/bios/macro.S
+ create mode 100644 tools/kvm/x86/bios/memcpy.c
+ create mode 100644 tools/kvm/x86/bios/rom.ld.S
+ create mode 100644 tools/kvm/x86/boot.c
+ create mode 100644 tools/kvm/x86/cpuid.c
+ create mode 100644 tools/kvm/x86/include/kvm/assembly.h
+ create mode 100644 tools/kvm/x86/include/kvm/barrier.h
+ create mode 100644 tools/kvm/x86/include/kvm/bios-export.h
+ create mode 100644 tools/kvm/x86/include/kvm/bios.h
+ create mode 100644 tools/kvm/x86/include/kvm/boot-protocol.h
+ create mode 100644 tools/kvm/x86/include/kvm/cpufeature.h
+ create mode 100644 tools/kvm/x86/include/kvm/interrupt.h
+ create mode 100644 tools/kvm/x86/include/kvm/kvm-arch.h
+ create mode 100644 tools/kvm/x86/include/kvm/kvm-cpu-arch.h
+ create mode 100644 tools/kvm/x86/include/kvm/mptable.h
+ create mode 100644 tools/kvm/x86/interrupt.c
+ create mode 100644 tools/kvm/x86/ioport.c
+ create mode 100644 tools/kvm/x86/irq.c
+ create mode 100644 tools/kvm/x86/kvm-cpu.c
+ create mode 100644 tools/kvm/x86/kvm.c
+ create mode 100644 tools/kvm/x86/mptable.c
+Merging rcu/rcu/next (d1d61c1 Merge branches 'bigrt.2012.07.31a', 'doctorture.2012.08.03a', 'fixes.2012.08.03a', 'hotplug.2012.08.03a' and 'idle.2012.07.31a' into dev.3.7.2012.08.03a)
+$ git merge rcu/rcu/next
+Resolved 'arch/Kconfig' using previous resolution.
+Resolved 'arch/x86/Kconfig' using previous resolution.
+Resolved 'include/linux/sched.h' using previous resolution.
+Auto-merging lib/Kconfig.debug
+Auto-merging kernel/sched/core.c
+Auto-merging init/Kconfig
+Auto-merging include/linux/sched.h
+CONFLICT (content): Merge conflict in include/linux/sched.h
+Auto-merging arch/x86/kernel/traps.c
+Auto-merging arch/x86/kernel/signal.c
+Auto-merging arch/x86/kernel/entry_64.S
+Auto-merging arch/x86/Kconfig
+CONFLICT (content): Merge conflict in arch/x86/Kconfig
+Auto-merging arch/um/drivers/mconsole_kern.c
+Auto-merging arch/Kconfig
+CONFLICT (content): Merge conflict in arch/Kconfig
+Auto-merging Documentation/kernel-parameters.txt
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master 34ed5cb] Merge remote-tracking branch 'rcu/rcu/next'
+$ git diff -M --stat --summary HEAD^..
+ Documentation/RCU/trace.txt         |   43 +-
+ Documentation/kernel-parameters.txt |   11 +
+ arch/Kconfig                        |   10 +
+ arch/um/drivers/mconsole_kern.c     |    1 +
+ arch/x86/Kconfig                    |    1 +
+ arch/x86/include/asm/rcu.h          |   20 +
+ arch/x86/include/asm/thread_info.h  |   10 +-
+ arch/x86/kernel/entry_64.S          |    8 +-
+ arch/x86/kernel/ptrace.c            |    5 +
+ arch/x86/kernel/signal.c            |    4 +
+ arch/x86/kernel/traps.c             |   30 +-
+ arch/x86/mm/fault.c                 |   13 +-
+ include/linux/rcupdate.h            |   20 +-
+ include/linux/sched.h               |    8 +
+ init/Kconfig                        |   18 +
+ kernel/rcupdate.c                   |    4 +
+ kernel/rcutiny.c                    |   31 +-
+ kernel/rcutorture.c                 |   46 +-
+ kernel/rcutree.c                    |  817 ++++++++++++++++++++---------------
+ kernel/rcutree.h                    |   33 +-
+ kernel/rcutree_plugin.h             |  172 +++++++-
+ kernel/rcutree_trace.c              |    7 +-
+ kernel/sched/core.c                 |   30 +-
+ lib/Kconfig.debug                   |   14 +
+ 24 files changed, 897 insertions(+), 459 deletions(-)
+ create mode 100644 arch/x86/include/asm/rcu.h
+Merging cputime/cputime (c3e0ef9 [S390] fix cputime overflow in uptime_proc_show)
+$ git merge cputime/cputime
+Already up-to-date.
+Merging uprobes/for-next (0326f5a uprobes/core: Handle breakpoint and singlestep exceptions)
+$ git merge uprobes/for-next
+Already up-to-date.
+Merging kmemleak/kmemleak (4878677 kmemleak: do not leak object after tree insertion error)
+$ git merge kmemleak/kmemleak
+Merge made by the 'recursive' strategy.
+ mm/kmemleak.c |    1 +
+ 1 file changed, 1 insertion(+)
+Merging kvm/linux-next (8fbe6a5 KVM guest: disable stealtime on reboot to avoid mem corruption)
+$ git merge kvm/linux-next
+Resolved 'arch/s390/include/asm/processor.h' using previous resolution.
+Removing arch/x86/kvm/timer.c
+Removing arch/x86/kvm/kvm_timer.h
+Auto-merging arch/s390/kernel/dis.c
+Auto-merging arch/s390/include/asm/processor.h
+CONFLICT (content): Merge conflict in arch/s390/include/asm/processor.h
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master 9d07291] Merge remote-tracking branch 'kvm/linux-next'
+$ git diff -M --stat --summary HEAD^..
+ Documentation/virtual/kvm/hypercalls.txt |   66 ++++++
+ Documentation/virtual/kvm/ppc-pv.txt     |   22 ++
+ arch/ia64/kvm/kvm-ia64.c                 |   33 +--
+ arch/powerpc/include/asm/kvm_host.h      |    3 +
+ arch/powerpc/kvm/44x_tlb.c               |    1 -
+ arch/powerpc/kvm/book3s_64_mmu_hv.c      |   51 +++--
+ arch/powerpc/kvm/book3s_hv_rm_mmu.c      |    4 +-
+ arch/powerpc/kvm/book3s_pr.c             |    4 +-
+ arch/powerpc/kvm/e500_tlb.c              |    3 +-
+ arch/powerpc/kvm/powerpc.c               |    8 +
+ arch/s390/include/asm/processor.h        |    1 +
+ arch/s390/kernel/dis.c                   |   27 +++
+ arch/s390/kvm/Kconfig                    |    1 +
+ arch/s390/kvm/diag.c                     |    4 +
+ arch/s390/kvm/intercept.c                |   11 +
+ arch/s390/kvm/interrupt.c                |   23 ++
+ arch/s390/kvm/kvm-s390.c                 |   10 +
+ arch/s390/kvm/priv.c                     |    9 +-
+ arch/s390/kvm/sigp.c                     |    2 +
+ arch/s390/kvm/trace-s390.h               |  210 ++++++++++++++++++
+ arch/s390/kvm/trace.h                    |  341 ++++++++++++++++++++++++++++++
+ arch/x86/include/asm/kvm_host.h          |    5 +-
+ arch/x86/include/asm/kvm_para.h          |    2 +-
+ arch/x86/kernel/kvm.c                    |    1 +
+ arch/x86/kvm/Kconfig                     |    1 +
+ arch/x86/kvm/Makefile                    |    2 +-
+ arch/x86/kvm/cpuid.c                     |    2 +-
+ arch/x86/kvm/emulate.c                   |   48 ++---
+ arch/x86/kvm/i8254.c                     |   64 +++---
+ arch/x86/kvm/i8254.h                     |    6 +-
+ arch/x86/kvm/i8259.c                     |   18 +-
+ arch/x86/kvm/irq.h                       |    2 +-
+ arch/x86/kvm/kvm_timer.h                 |   18 --
+ arch/x86/kvm/lapic.c                     |  264 +++++++++++++----------
+ arch/x86/kvm/lapic.h                     |   58 ++++-
+ arch/x86/kvm/mmu.c                       |  132 +++++++-----
+ arch/x86/kvm/mmu_audit.c                 |    8 +-
+ arch/x86/kvm/paging_tmpl.h               |    8 +-
+ arch/x86/kvm/pmu.c                       |    2 +-
+ arch/x86/kvm/svm.c                       |    5 +-
+ arch/x86/kvm/timer.c                     |   47 ----
+ arch/x86/kvm/vmx.c                       |   19 +-
+ arch/x86/kvm/x86.c                       |  149 +++++++------
+ arch/x86/kvm/x86.h                       |    1 +
+ include/linux/kvm_host.h                 |  107 ++++++++--
+ kernel/jump_label.c                      |    1 +
+ virt/kvm/Kconfig                         |    3 +
+ virt/kvm/async_pf.c                      |   11 +-
+ virt/kvm/ioapic.c                        |   37 ++--
+ virt/kvm/iommu.c                         |   16 +-
+ virt/kvm/irq_comm.c                      |    4 +-
+ virt/kvm/kvm_main.c                      |  229 ++++++++++----------
+ 52 files changed, 1483 insertions(+), 621 deletions(-)
+ create mode 100644 Documentation/virtual/kvm/hypercalls.txt
+ create mode 100644 arch/s390/kvm/trace-s390.h
+ create mode 100644 arch/s390/kvm/trace.h
+ delete mode 100644 arch/x86/kvm/kvm_timer.h
+ delete mode 100644 arch/x86/kvm/timer.c
+Merging kvm-ppc/kvm-ppc-next (e9908a4 KVM: PPC: BookE: Support FPU on non-hv systems)
+$ git merge kvm-ppc/kvm-ppc-next
+Auto-merging arch/powerpc/mm/mem.c
+Merge made by the 'recursive' strategy.
+ Documentation/virtual/kvm/api.txt       |   16 +-
+ arch/powerpc/include/asm/Kbuild         |    1 +
+ arch/powerpc/include/asm/epapr_hcalls.h |   36 ++--
+ arch/powerpc/include/asm/fsl_hcalls.h   |   36 ++--
+ arch/powerpc/include/asm/kvm.h          |   12 ++
+ arch/powerpc/include/asm/kvm_host.h     |   30 +++-
+ arch/powerpc/include/asm/kvm_para.h     |   21 +--
+ arch/powerpc/include/asm/kvm_ppc.h      |   28 +++
+ arch/powerpc/include/asm/reg_booke.h    |    7 +
+ arch/powerpc/kernel/epapr_hcalls.S      |   28 +++
+ arch/powerpc/kernel/epapr_paravirt.c    |   11 +-
+ arch/powerpc/kernel/kvm.c               |    2 +-
+ arch/powerpc/kernel/ppc_ksyms.c         |    5 +
+ arch/powerpc/kvm/44x.c                  |    1 +
+ arch/powerpc/kvm/44x_emulate.c          |  110 +++++++-----
+ arch/powerpc/kvm/Kconfig                |    3 +
+ arch/powerpc/kvm/book3s.c               |    9 +
+ arch/powerpc/kvm/book3s_32_mmu_host.c   |    4 +
+ arch/powerpc/kvm/book3s_64_mmu_host.c   |    3 +
+ arch/powerpc/kvm/book3s_hv_builtin.c    |    4 +-
+ arch/powerpc/kvm/book3s_hv_rmhandlers.S |   12 +-
+ arch/powerpc/kvm/book3s_mmu_hpte.c      |    5 -
+ arch/powerpc/kvm/book3s_pr.c            |  109 ++++++++----
+ arch/powerpc/kvm/book3s_rmhandlers.S    |   15 +-
+ arch/powerpc/kvm/booke.c                |  290 ++++++++++++++++++++++++++-----
+ arch/powerpc/kvm/booke_emulate.c        |   22 ++-
+ arch/powerpc/kvm/e500.h                 |    3 +-
+ arch/powerpc/kvm/e500_tlb.c             |   80 +++++++--
+ arch/powerpc/kvm/powerpc.c              |  128 ++++++++++++--
+ arch/powerpc/kvm/trace.h                |  200 ++++++++++++++++++---
+ arch/powerpc/mm/mem.c                   |    1 +
+ arch/powerpc/platforms/Kconfig          |    1 +
+ arch/powerpc/sysdev/fsl_msi.c           |    9 +-
+ arch/powerpc/sysdev/fsl_soc.c           |    2 +
+ drivers/tty/Kconfig                     |    1 +
+ drivers/virt/Kconfig                    |    1 +
+ include/linux/kvm.h                     |    4 +
+ include/linux/kvm_host.h                |    1 +
+ 38 files changed, 994 insertions(+), 257 deletions(-)
+Merging oprofile/for-next (c16fa4f Linux 3.3)
+$ git merge oprofile/for-next
+Already up-to-date.
+Merging xen/upstream/xen (af3a3ab Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-fixes)
+$ git merge xen/upstream/xen
+Already up-to-date.
+Merging xen-two/linux-next (df3c572 Merge branch 'stable/for-linus-3.6' into linux-next)
+$ git merge xen-two/linux-next
+Merge made by the 'recursive' strategy.
+ arch/x86/xen/enlighten.c   |  118 +++++---------------------------------------
+ arch/x86/xen/p2m.c         |   95 +++++++++++++++++++++++++++++++++--
+ arch/x86/xen/suspend.c     |    2 +-
+ arch/x86/xen/xen-ops.h     |    2 +-
+ drivers/xen/platform-pci.c |   15 ------
+ include/xen/events.h       |    2 -
+ 6 files changed, 105 insertions(+), 129 deletions(-)
+Merging xen-pvhvm/linux-next (b056b6a xen: suspend: remove xen_hvm_suspend)
+$ git merge xen-pvhvm/linux-next
+Already up-to-date.
+Merging percpu/for-next (61011677 Merge tag 'dlm-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm)
+$ git merge percpu/for-next
+Already up-to-date.
+Merging workqueues/for-next (7635d2f workqueue: use system_highpri_wq for unbind_work)
+$ git merge workqueues/for-next
+Auto-merging net/core/dst.c
+Auto-merging drivers/thermal/thermal_sys.c
+Auto-merging drivers/platform/x86/thinkpad_acpi.c
+Auto-merging block/genhd.c
+Merge made by the 'recursive' strategy.
+ block/genhd.c                          |    6 +-
+ drivers/edac/edac_mc.c                 |   17 +-
+ drivers/infiniband/core/addr.c         |    4 +-
+ drivers/infiniband/hw/nes/nes_hw.c     |    6 +-
+ drivers/infiniband/hw/nes/nes_nic.c    |    5 +-
+ drivers/net/wireless/ipw2x00/ipw2100.c |    8 +-
+ drivers/net/wireless/zd1211rw/zd_usb.c |    3 +-
+ drivers/platform/x86/thinkpad_acpi.c   |   20 +-
+ drivers/power/charger-manager.c        |    9 +-
+ drivers/power/ds2760_battery.c         |    9 +-
+ drivers/power/jz4740-battery.c         |    6 +-
+ drivers/thermal/thermal_sys.c          |   15 +-
+ fs/afs/callback.c                      |    4 +-
+ fs/afs/server.c                        |   10 +-
+ fs/afs/vlocation.c                     |   14 +-
+ fs/nfs/nfs4renewd.c                    |    3 +-
+ include/linux/workqueue.h              |   48 +-
+ kernel/workqueue.c                     |  779 ++++++++++++++++++++------------
+ net/core/dst.c                         |    4 +-
+ net/rfkill/input.c                     |    3 +-
+ 20 files changed, 564 insertions(+), 409 deletions(-)
+Merging drivers-x86/linux-next (973713e classmate-laptop: always call input_sync() after input_report_switch())
+$ git merge drivers-x86/linux-next
+Auto-merging drivers/platform/x86/thinkpad_acpi.c
+Merge made by the 'recursive' strategy.
+ drivers/gpu/drm/nouveau/nouveau_acpi.c  |    6 -
+ drivers/gpu/vga/vga_switcheroo.c        |   61 +++--
+ drivers/platform/x86/Kconfig            |    5 +-
+ drivers/platform/x86/apple-gmux.c       |  426 +++++++++++++++++++++++++++++--
+ drivers/platform/x86/asus-wmi.c         |   97 ++++++-
+ drivers/platform/x86/asus-wmi.h         |    1 +
+ drivers/platform/x86/classmate-laptop.c |   12 +-
+ drivers/platform/x86/dell-laptop.c      |   12 +-
+ drivers/platform/x86/thinkpad_acpi.c    |    7 +
+ 9 files changed, 563 insertions(+), 64 deletions(-)
+$ git reset --hard HEAD^
+HEAD is now at f05ed85 Merge remote-tracking branch 'workqueues/for-next'
+Merging refs/next/20120817/drivers-x86
+$ git merge refs/next/20120817/drivers-x86
+Already up-to-date.
+Merging hwpoison/hwpoison (46e387b Merge branch 'hwpoison-hugepages' into hwpoison)
+$ git merge hwpoison/hwpoison
+Already up-to-date.
+Merging sysctl/master (4e474a0 sysctl: protect poll() in entries that may go away)
+$ git merge sysctl/master
+Already up-to-date.
+Merging regmap/for-next (e0bf121 Merge branch 'regmap-irq' into regmap-next)
+$ git merge regmap/for-next
+Merge made by the 'recursive' strategy.
+ drivers/base/regmap/regmap-irq.c |   84 ++++++++++++++++++++++++++++++--------
+ drivers/base/regmap/regmap.c     |   13 ++----
+ drivers/mfd/wm8994-irq.c         |    1 +
+ include/linux/regmap.h           |    2 +
+ 4 files changed, 74 insertions(+), 26 deletions(-)
+Merging hsi/for-next (43139a6 HSI: hsi_char: Update ioctl-number.txt)
+$ git merge hsi/for-next
+Already up-to-date.
+Merging leds/for-next (052a876 leds: leds-gpio: Use platform_{get,set}_drvdata)
+$ git merge leds/for-next
+Merge made by the 'recursive' strategy.
+ drivers/leds/led-class.c       |   15 +++++++++++++++
+ drivers/leds/led-core.c        |   16 +++++++++++++---
+ drivers/leds/led-triggers.c    |    4 +++-
+ drivers/leds/leds-clevo-mail.c |   10 +++++-----
+ drivers/leds/leds-gpio.c       |    7 +++----
+ drivers/leds/leds-wm8350.c     |   29 +++++++----------------------
+ drivers/leds/leds.h            |    2 ++
+ include/linux/leds.h           |    4 ++++
+ 8 files changed, 52 insertions(+), 35 deletions(-)
+Merging driver-core/driver-core-next (0592969 hv: fail the probing immediately when we are not in hyperv platform)
+$ git merge driver-core/driver-core-next
+Auto-merging include/linux/pm.h
+Auto-merging include/linux/device.h
+Auto-merging drivers/extcon/extcon-class.c
+Auto-merging drivers/base/power/main.c
+Auto-merging drivers/base/platform.c
+Auto-merging drivers/base/core.c
+Merge made by the 'recursive' strategy.
+ drivers/base/core.c                               |   18 +-
+ drivers/base/devres.c                             |   42 ++
+ drivers/base/firmware_class.c                     |  761 ++++++++++++++++++---
+ drivers/base/platform.c                           |   38 +-
+ drivers/base/power/main.c                         |   22 +
+ drivers/extcon/Makefile                           |    4 +-
+ drivers/extcon/extcon-arizona.c                   |   72 +-
+ drivers/extcon/{extcon_class.c => extcon-class.c} |    4 +
+ drivers/extcon/{extcon_gpio.c => extcon-gpio.c}   |    0
+ drivers/hv/hv.c                                   |   34 +-
+ drivers/hv/hv_kvp.c                               |  251 ++++++-
+ drivers/hv/hv_util.c                              |    4 +-
+ drivers/hv/hyperv_vmbus.h                         |   47 +-
+ drivers/hv/vmbus_drv.c                            |   63 +-
+ fs/debugfs/inode.c                                |    6 +-
+ include/linux/device.h                            |    4 +
+ include/linux/firmware.h                          |   15 +
+ include/linux/hyperv.h                            |   99 ++-
+ include/linux/platform_device.h                   |    4 +
+ include/linux/pm.h                                |    5 +
+ tools/hv/hv_kvp_daemon.c                          |  337 ++++++---
+ 21 files changed, 1508 insertions(+), 322 deletions(-)
+ rename drivers/extcon/{extcon_class.c => extcon-class.c} (99%)
+ rename drivers/extcon/{extcon_gpio.c => extcon-gpio.c} (100%)
+Merging tty/tty-next (5d4121c TTY: check if tty->port is assigned)
+$ git merge tty/tty-next
+Auto-merging net/bluetooth/rfcomm/tty.c
+Removing include/linux/stallion.h
+Removing include/linux/serial167.h
+Removing include/linux/sc26198.h
+Removing include/linux/istallion.h
+Removing include/linux/generic_serial.h
+Removing include/linux/comstats.h
+Removing include/linux/cdk.h
+Removing include/linux/cd1400.h
+Auto-merging include/linux/Kbuild
+Removing firmware/intelliport2.bin.ihex
+Auto-merging firmware/Makefile
+Auto-merging drivers/usb/serial/usb_wwan.c
+Auto-merging drivers/usb/serial/mos7840.c
+Auto-merging drivers/usb/serial/ftdi_sio.c
+Auto-merging drivers/usb/class/cdc-acm.c
+Removing drivers/tty/serial/max3107.h
+Removing drivers/tty/serial/max3107.c
+Auto-merging drivers/tty/serial/ifx6x60.c
+Auto-merging drivers/tty/serial/Kconfig
+Auto-merging arch/xtensa/platforms/iss/console.c
+Removing Documentation/serial/computone.txt
+Merge made by the 'recursive' strategy.
+ .../bindings/tty/serial/nxp-lpc32xx-hsuart.txt     |   14 +
+ .../devicetree/bindings/tty/serial/of-serial.txt   |    2 +
+ Documentation/serial/00-INDEX                      |    2 -
+ Documentation/serial/computone.txt                 |  520 -----
+ arch/alpha/kernel/srmcons.c                        |    1 +
+ arch/arm/mach-omap2/serial.c                       |    3 +
+ arch/arm/plat-omap/include/plat/omap-serial.h      |    7 +
+ arch/ia64/hp/sim/simserial.c                       |    3 +-
+ arch/m68k/emu/nfcon.c                              |    4 +
+ arch/mips/cavium-octeon/serial.c                   |   30 +-
+ arch/parisc/kernel/pdc_cons.c                      |    1 +
+ arch/um/drivers/line.c                             |    3 +-
+ arch/xtensa/platforms/iss/console.c                |    1 +
+ drivers/bluetooth/hci_ath.c                        |    2 +-
+ drivers/char/mwave/mwavedd.c                       |   16 +-
+ drivers/char/pcmcia/synclink_cs.c                  |  129 +-
+ drivers/char/ttyprintk.c                           |   33 +-
+ drivers/isdn/capi/capi.c                           |    3 +-
+ drivers/isdn/gigaset/interface.c                   |    7 +-
+ drivers/isdn/i4l/isdn_tty.c                        |   41 +-
+ drivers/misc/ibmasm/uart.c                         |   16 +-
+ drivers/misc/pti.c                                 |  128 +-
+ drivers/mmc/card/sdio_uart.c                       |   24 +-
+ drivers/net/ethernet/sgi/ioc3-eth.c                |   22 +-
+ drivers/net/irda/irtty-sir.c                       |   10 +-
+ drivers/net/usb/hso.c                              |   19 +-
+ drivers/s390/char/con3215.c                        |   28 +-
+ drivers/s390/char/sclp_tty.c                       |    1 +
+ drivers/s390/char/sclp_vt220.c                     |    1 +
+ drivers/s390/char/tty3270.c                        |   34 +-
+ drivers/staging/ipack/devices/ipoctal.c            |   14 +-
+ drivers/staging/serqt_usb2/serqt_usb2.c            |   18 +-
+ drivers/tty/amiserial.c                            |   43 +-
+ drivers/tty/bfin_jtag_comm.c                       |    1 +
+ drivers/tty/cyclades.c                             |  100 +-
+ drivers/tty/ehv_bytechan.c                         |    9 +-
+ drivers/tty/hvc/hvc_console.c                      |   31 +-
+ drivers/tty/hvc/hvcs.c                             |   82 +-
+ drivers/tty/hvc/hvsi.c                             |    2 +
+ drivers/tty/hvc/hvsi_lib.c                         |    2 +-
+ drivers/tty/ipwireless/tty.c                       |    2 +-
+ drivers/tty/isicom.c                               |   11 +-
+ drivers/tty/moxa.c                                 |   39 +-
+ drivers/tty/mxser.c                                |   61 +-
+ drivers/tty/n_gsm.c                                |  142 +-
+ drivers/tty/n_r3964.c                              |   10 +-
+ drivers/tty/n_tty.c                                |   29 +-
+ drivers/tty/nozomi.c                               |    4 +-
+ drivers/tty/pty.c                                  |  234 ++-
+ drivers/tty/rocket.c                               |   22 +-
+ drivers/tty/serial/68328serial.c                   |   23 +-
+ drivers/tty/serial/8250/8250.c                     |   80 +-
+ drivers/tty/serial/8250/8250.h                     |   31 +-
+ drivers/tty/serial/8250/8250_acorn.c               |   22 +-
+ drivers/tty/serial/8250/8250_dw.c                  |   38 +-
+ drivers/tty/serial/8250/8250_gsc.c                 |   26 +-
+ drivers/tty/serial/8250/8250_hp300.c               |   26 +-
+ drivers/tty/serial/8250/8250_pci.c                 |  134 +-
+ drivers/tty/serial/8250/8250_pnp.c                 |   28 +-
+ drivers/tty/serial/8250/serial_cs.c                |   30 +-
+ drivers/tty/serial/Kconfig                         |   32 +-
+ drivers/tty/serial/Makefile                        |    3 +-
+ drivers/tty/serial/amba-pl011.c                    |   34 +-
+ drivers/tty/serial/bfin_uart.c                     |    2 +-
+ drivers/tty/serial/crisv10.c                       |   45 +-
+ drivers/tty/serial/ifx6x60.c                       |    4 +-
+ drivers/tty/serial/imx.c                           |    2 +-
+ drivers/tty/serial/ioc4_serial.c                   |    2 +-
+ drivers/tty/serial/jsm/jsm_tty.c                   |    8 +-
+ drivers/tty/serial/lpc32xx_hs.c                    |  823 ++++++++
+ drivers/tty/serial/max3107.c                       | 1215 -----------
+ drivers/tty/serial/max3107.h                       |  441 ----
+ drivers/tty/serial/max310x.c                       | 1259 ++++++++++++
+ drivers/tty/serial/msm_smd_tty.c                   |    8 +-
+ drivers/tty/serial/of_serial.c                     |   13 +-
+ drivers/tty/serial/omap-serial.c                   |   35 +-
+ drivers/tty/serial/pch_uart.c                      |    4 +
+ drivers/tty/serial/pxa.c                           |   14 +
+ drivers/tty/serial/samsung.c                       |   26 +-
+ drivers/tty/serial/sc26xx.c                        |    1 +
+ drivers/tty/serial/serial_core.c                   |   31 +-
+ drivers/tty/synclink.c                             |   84 +-
+ drivers/tty/synclink_gt.c                          |   35 +-
+ drivers/tty/synclinkmp.c                           |   56 +-
+ drivers/tty/tty_io.c                               |  313 +--
+ drivers/tty/tty_ioctl.c                            |  100 +-
+ drivers/tty/tty_ldisc.c                            |   78 +-
+ drivers/tty/tty_mutex.c                            |   71 +-
+ drivers/tty/tty_port.c                             |   70 +-
+ drivers/tty/vt/keyboard.c                          |   50 +-
+ drivers/tty/vt/vt.c                                |   63 +-
+ drivers/usb/class/cdc-acm.c                        |    5 +-
+ drivers/usb/gadget/u_serial.c                      |    3 +-
+ drivers/usb/serial/ark3116.c                       |    4 +-
+ drivers/usb/serial/belkin_sa.c                     |    2 +-
+ drivers/usb/serial/console.c                       |    4 +-
+ drivers/usb/serial/cp210x.c                        |    8 +-
+ drivers/usb/serial/cypress_m8.c                    |   40 +-
+ drivers/usb/serial/digi_acceleport.c               |   14 +-
+ drivers/usb/serial/empeg.c                         |    2 +-
+ drivers/usb/serial/f81232.c                        |    3 +-
+ drivers/usb/serial/ftdi_sio.c                      |    2 +-
+ drivers/usb/serial/io_edgeport.c                   |   12 +-
+ drivers/usb/serial/io_ti.c                         |   12 +-
+ drivers/usb/serial/ir-usb.c                        |    2 +-
+ drivers/usb/serial/iuu_phoenix.c                   |   28 +-
+ drivers/usb/serial/keyspan.c                       |    6 +-
+ drivers/usb/serial/keyspan_pda.c                   |    4 +-
+ drivers/usb/serial/kl5kusb105.c                    |   18 +-
+ drivers/usb/serial/kobil_sct.c                     |   14 +-
+ drivers/usb/serial/mct_u232.c                      |    4 +-
+ drivers/usb/serial/metro-usb.c                     |    6 -
+ drivers/usb/serial/mos7720.c                       |   14 +-
+ drivers/usb/serial/mos7840.c                       |   12 +-
+ drivers/usb/serial/oti6858.c                       |   10 +-
+ drivers/usb/serial/pl2303.c                        |    6 +-
+ drivers/usb/serial/quatech2.c                      |    4 +-
+ drivers/usb/serial/sierra.c                        |    2 +-
+ drivers/usb/serial/spcp8x5.c                       |   12 +-
+ drivers/usb/serial/ssu100.c                        |    4 +-
+ drivers/usb/serial/ti_usb_3410_5052.c              |   10 +-
+ drivers/usb/serial/usb-serial.c                    |    7 +-
+ drivers/usb/serial/usb_wwan.c                      |    2 +-
+ drivers/usb/serial/whiteheat.c                     |    2 +-
+ firmware/Makefile                                  |    1 -
+ firmware/intelliport2.bin.ihex                     | 2147 --------------------
+ include/linux/Kbuild                               |    3 -
+ include/linux/cd1400.h                             |  292 ---
+ include/linux/cdk.h                                |  486 -----
+ include/linux/comstats.h                           |  119 --
+ include/linux/generic_serial.h                     |   35 -
+ include/linux/istallion.h                          |  123 --
+ include/linux/kbd_kern.h                           |   13 -
+ include/linux/platform_data/max310x.h              |   67 +
+ include/linux/sc26198.h                            |  533 -----
+ include/linux/serial167.h                          |  157 --
+ include/linux/serial_8250.h                        |   33 +-
+ include/linux/serial_core.h                        |    4 +-
+ include/linux/stallion.h                           |  147 --
+ include/linux/tty.h                                |   77 +-
+ include/linux/tty_driver.h                         |   47 +-
+ include/net/irda/ircomm_tty.h                      |   17 +-
+ net/bluetooth/rfcomm/tty.c                         |   10 +-
+ net/irda/ircomm/ircomm_param.c                     |    5 -
+ net/irda/ircomm/ircomm_tty.c                       |  320 ++-
+ net/irda/ircomm/ircomm_tty_attach.c                |   40 +-
+ net/irda/ircomm/ircomm_tty_ioctl.c                 |   33 +-
+ 147 files changed, 4373 insertions(+), 7935 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt
+ delete mode 100644 Documentation/serial/computone.txt
+ create mode 100644 drivers/tty/serial/lpc32xx_hs.c
+ delete mode 100644 drivers/tty/serial/max3107.c
+ delete mode 100644 drivers/tty/serial/max3107.h
+ create mode 100644 drivers/tty/serial/max310x.c
+ delete mode 100644 firmware/intelliport2.bin.ihex
+ delete mode 100644 include/linux/cd1400.h
+ delete mode 100644 include/linux/cdk.h
+ delete mode 100644 include/linux/comstats.h
+ delete mode 100644 include/linux/generic_serial.h
+ delete mode 100644 include/linux/istallion.h
+ create mode 100644 include/linux/platform_data/max310x.h
+ delete mode 100644 include/linux/sc26198.h
+ delete mode 100644 include/linux/serial167.h
+ delete mode 100644 include/linux/stallion.h
+Merging usb/usb-next (26f944b usb: hcd: use *resource_size_t* for specifying resource data)
+$ git merge usb/usb-next
+Auto-merging drivers/usb/serial/ftdi_sio.c
+Auto-merging drivers/usb/host/ehci-tegra.c
+Auto-merging drivers/usb/host/ehci-sead3.c
+Merge made by the 'recursive' strategy.
+ .../devicetree/bindings/usb/platform-uhci.txt      |   12 ++
+ Documentation/devicetree/bindings/usb/pxa-usb.txt  |   31 ++++
+ .../devicetree/bindings/usb/vt8500-ehci.txt        |   12 ++
+ Documentation/usb/persist.txt                      |    3 +
+ arch/arm/mach-vt8500/bv07.c                        |    1 +
+ arch/arm/mach-vt8500/devices-vt8500.c              |    5 +
+ arch/arm/mach-vt8500/devices-wm8505.c              |    4 +
+ arch/arm/mach-vt8500/devices.c                     |   11 ++
+ arch/arm/mach-vt8500/devices.h                     |    1 +
+ arch/arm/mach-vt8500/wm8505_7in.c                  |    1 +
+ drivers/usb/atm/ueagle-atm.c                       |   79 ++++++++--
+ drivers/usb/core/sysfs.c                           |    6 +-
+ drivers/usb/gadget/s3c-hsotg.c                     |    3 +
+ drivers/usb/host/Kconfig                           |   12 +-
+ drivers/usb/host/ehci-atmel.c                      |   30 +---
+ drivers/usb/host/ehci-au1xxx.c                     |   20 +--
+ drivers/usb/host/ehci-cns3xxx.c                    |   16 +-
+ drivers/usb/host/ehci-grlib.c                      |   18 +--
+ drivers/usb/host/ehci-ixp4xx.c                     |   19 +--
+ drivers/usb/host/ehci-ls1x.c                       |   18 +--
+ drivers/usb/host/ehci-msm.c                        |   13 +-
+ drivers/usb/host/ehci-mv.c                         |   51 ++-----
+ drivers/usb/host/ehci-mxc.c                        |   45 ++----
+ drivers/usb/host/ehci-platform.c                   |   50 ++++++-
+ drivers/usb/host/ehci-ppc-of.c                     |   28 +---
+ drivers/usb/host/ehci-s5p.c                        |    7 +-
+ drivers/usb/host/ehci-sead3.c                      |   15 +-
+ drivers/usb/host/ehci-sh.c                         |   35 +----
+ drivers/usb/host/ehci-tegra.c                      |   40 ++---
+ drivers/usb/host/ehci-vt8500.c                     |   24 ++-
+ drivers/usb/host/ehci-xilinx-of.c                  |   20 +--
+ drivers/usb/host/ohci-platform.c                   |   46 +++++-
+ drivers/usb/host/ohci-pxa27x.c                     |   68 +++++++++
+ drivers/usb/host/uhci-hcd.c                        |    5 +
+ drivers/usb/host/uhci-platform.c                   |  157 ++++++++++++++++++++
+ drivers/usb/host/whci/hcd.c                        |    8 +-
+ drivers/usb/host/whci/qset.c                       |   11 +-
+ drivers/usb/misc/legousbtower.c                    |    3 -
+ drivers/usb/serial/ftdi_sio.c                      |    2 +-
+ drivers/usb/storage/ene_ub6250.c                   |   28 +++-
+ drivers/usb/wusbcore/security.c                    |    7 +-
+ drivers/usb/wusbcore/wa-hc.c                       |    4 +-
+ include/linux/usb/ehci_pdriver.h                   |    8 +
+ include/linux/usb/hcd.h                            |    4 +-
+ include/linux/usb/ohci_pdriver.h                   |    8 +
+ 45 files changed, 633 insertions(+), 356 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/usb/platform-uhci.txt
+ create mode 100644 Documentation/devicetree/bindings/usb/pxa-usb.txt
+ create mode 100644 Documentation/devicetree/bindings/usb/vt8500-ehci.txt
+ create mode 100644 drivers/usb/host/uhci-platform.c
+Merging staging/staging-next (d602a06 staging: comedi: contec_pci: remove manual legacy attach)
+$ git merge staging/staging-next
+Removing drivers/staging/zsmalloc/zsmalloc_int.h
+Removing drivers/staging/usbip/userspace/doc/usbip_bind_driver.8
+Auto-merging drivers/staging/serqt_usb2/serqt_usb2.c
+Auto-merging drivers/staging/iio/adc/ad7192.c
+Removing drivers/staging/csr/csr_formatted_io.h
+Removing drivers/staging/csr/csr_formatted_io.c
+Removing drivers/staging/comedi/drivers/adl_pci7432.c
+Removing drivers/staging/comedi/drivers/adl_pci7230.c
+Auto-merging drivers/staging/comedi/drivers.c
+Merge made by the 'recursive' strategy.
+ .../bindings/staging/iio/adc/mxs-lradc.txt         |   15 +
+ drivers/iio/adc/at91_adc.c                         |   42 +-
+ drivers/staging/android/ashmem.c                   |   32 +-
+ drivers/staging/android/binder.c                   |    6 +-
+ drivers/staging/android/logger.c                   |   40 +-
+ drivers/staging/android/logger.h                   |   24 +-
+ drivers/staging/android/timed_gpio.c               |   13 +-
+ drivers/staging/asus_oled/asus_oled.c              |   21 +-
+ drivers/staging/bcm/CmHost.c                       |   78 ++-
+ drivers/staging/bcm/Misc.c                         |    5 +-
+ drivers/staging/bcm/PHSModule.c                    |    4 +-
+ drivers/staging/bcm/cntrl_SignalingInterface.h     |    2 +-
+ drivers/staging/bcm/nvm.c                          |    2 +-
+ drivers/staging/bcm/target_params.h                |    2 +-
+ drivers/staging/ccg/ccg.c                          |    2 +-
+ drivers/staging/comedi/Kconfig                     |   25 +-
+ drivers/staging/comedi/comedi_fops.c               |   37 +-
+ drivers/staging/comedi/comedidev.h                 |    2 +-
+ drivers/staging/comedi/drivers.c                   |   69 ++-
+ drivers/staging/comedi/drivers/Makefile            |    3 +-
+ drivers/staging/comedi/drivers/adl_pci6208.c       |  179 +++---
+ drivers/staging/comedi/drivers/adl_pci7230.c       |  190 -------
+ drivers/staging/comedi/drivers/adl_pci7296.c       |  212 +++----
+ drivers/staging/comedi/drivers/adl_pci7432.c       |  200 -------
+ drivers/staging/comedi/drivers/adl_pci7x3x.c       |  332 +++++++++++
+ drivers/staging/comedi/drivers/adl_pci8164.c       |   65 +--
+ drivers/staging/comedi/drivers/amplc_dio200.c      |   57 +-
+ drivers/staging/comedi/drivers/amplc_pc236.c       |   64 ++-
+ drivers/staging/comedi/drivers/amplc_pc263.c       |   52 +-
+ drivers/staging/comedi/drivers/cb_pcidas.c         |   84 +--
+ drivers/staging/comedi/drivers/cb_pcidda.c         |  382 ++++++-------
+ drivers/staging/comedi/drivers/cb_pcidio.c         |  104 ++--
+ drivers/staging/comedi/drivers/cb_pcimdas.c        |  279 ++++-----
+ drivers/staging/comedi/drivers/cb_pcimdda.c        |  387 +++----------
+ drivers/staging/comedi/drivers/contec_pci_dio.c    |  138 ++---
+ drivers/staging/comedi/drivers/dyna_pci10xx.c      |  153 ++---
+ drivers/staging/comedi/drivers/ke_counter.c        |   83 +--
+ drivers/staging/comedi/drivers/ssv_dnp.c           |    5 +-
+ drivers/staging/comedi/range.c                     |   16 +-
+ drivers/staging/crystalhd/crystalhd_lnx.c          |    6 +-
+ drivers/staging/csr/Makefile                       |    1 -
+ drivers/staging/csr/bh.c                           |  173 +++---
+ drivers/staging/csr/csr_formatted_io.c             |   27 -
+ drivers/staging/csr/csr_formatted_io.h             |   25 -
+ drivers/staging/csr/csr_panic.c                    |    1 -
+ drivers/staging/csr/csr_time.c                     |   20 +-
+ drivers/staging/csr/csr_wifi_hip_card_sdio.c       |    8 +-
+ drivers/staging/csr/csr_wifi_hip_send.c            |    9 +-
+ drivers/staging/csr/csr_wifi_hip_udi.c             |   94 ++--
+ drivers/staging/csr/csr_wifi_hip_unifi.h           |    1 -
+ drivers/staging/csr/drv.c                          |    3 +-
+ drivers/staging/csr/firmware.c                     |    4 +-
+ drivers/staging/csr/io.c                           |   32 +-
+ drivers/staging/csr/monitor.c                      |    3 +-
+ drivers/staging/csr/netdev.c                       |    3 +-
+ drivers/staging/csr/sdio_mmc.c                     |   45 +-
+ drivers/staging/csr/sme_native.c                   |    2 +-
+ drivers/staging/csr/sme_sys.c                      |    2 +-
+ drivers/staging/csr/sme_wext.c                     |    4 +-
+ drivers/staging/csr/ul_int.c                       |    1 +
+ drivers/staging/csr/unifi_pdu_processing.c         |    2 +-
+ drivers/staging/csr/unifi_wext.h                   |    1 +
+ drivers/staging/csr/wext_events.c                  |    8 +-
+ drivers/staging/ft1000/ft1000-usb/ft1000_hw.c      |   14 +-
+ drivers/staging/ft1000/ft1000-usb/ft1000_usb.h     |    2 -
+ drivers/staging/gdm72xx/gdm_wimax.c                |   16 +-
+ drivers/staging/iio/Documentation/generic_buffer.c |   10 +
+ drivers/staging/iio/accel/adis16201_core.c         |    2 +-
+ drivers/staging/iio/accel/adis16203_core.c         |    2 +-
+ drivers/staging/iio/accel/adis16204_core.c         |    2 +-
+ drivers/staging/iio/accel/adis16209_core.c         |    2 +-
+ drivers/staging/iio/accel/adis16220_core.c         |    9 +-
+ drivers/staging/iio/accel/adis16240_core.c         |    2 +-
+ drivers/staging/iio/accel/kxsd9.c                  |    2 +-
+ drivers/staging/iio/accel/lis3l02dq_core.c         |    2 +-
+ drivers/staging/iio/accel/sca3000_core.c           |    2 +-
+ drivers/staging/iio/adc/Kconfig                    |   12 +
+ drivers/staging/iio/adc/Makefile                   |    1 +
+ drivers/staging/iio/adc/ad7192.c                   |    2 +-
+ drivers/staging/iio/adc/ad7298_core.c              |    2 +-
+ drivers/staging/iio/adc/ad7606.h                   |    2 +-
+ drivers/staging/iio/adc/ad7606_core.c              |    6 +-
+ drivers/staging/iio/adc/lpc32xx_adc.c              |    2 +-
+ drivers/staging/iio/adc/max1363.h                  |    2 +-
+ drivers/staging/iio/adc/max1363_core.c             |   26 +-
+ drivers/staging/iio/adc/mxs-lradc.c                |  590 ++++++++++++++++++++
+ drivers/staging/iio/adc/spear_adc.c                |    2 +-
+ drivers/staging/iio/iio_hwmon.c                    |   12 +-
+ drivers/staging/iio/iio_simple_dummy.c             |    2 +-
+ drivers/staging/iio/impedance-analyzer/ad5933.c    |    2 +-
+ drivers/staging/iio/imu/adis16400_core.c           |    6 +-
+ drivers/staging/iio/meter/ade7758.h                |    2 +-
+ drivers/staging/iio/meter/ade7758_core.c           |    2 +-
+ drivers/staging/iio/resolver/ad2s1210.c            |    2 +-
+ drivers/staging/ipack/bridges/tpci200.c            |   44 +-
+ drivers/staging/line6/pcm.c                        |    8 +-
+ drivers/staging/line6/variax.c                     |    8 +-
+ drivers/staging/nvec/nvec.c                        |    9 +-
+ drivers/staging/olpc_dcon/olpc_dcon.c              |   53 +-
+ drivers/staging/olpc_dcon/olpc_dcon_xo_1.c         |   15 +-
+ drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c       |    6 +-
+ drivers/staging/omapdrm/omap_crtc.c                |   10 +
+ drivers/staging/omapdrm/omap_dmm_tiler.c           |   51 +-
+ drivers/staging/omapdrm/omap_dmm_tiler.h           |   17 +-
+ drivers/staging/omapdrm/omap_drv.c                 |   18 +-
+ drivers/staging/omapdrm/omap_drv.h                 |   33 +-
+ drivers/staging/omapdrm/omap_fb.c                  |   99 +++-
+ drivers/staging/omapdrm/omap_gem.c                 |   43 +-
+ drivers/staging/omapdrm/omap_plane.c               |  111 +++-
+ drivers/staging/ozwpan/ozhcd.c                     |   89 ++-
+ drivers/staging/ozwpan/ozmain.c                    |    2 +-
+ drivers/staging/ozwpan/ozpd.c                      |    8 +-
+ drivers/staging/ozwpan/ozpd.h                      |    1 +
+ drivers/staging/ozwpan/ozproto.c                   |   13 +
+ drivers/staging/ozwpan/ozproto.h                   |    8 +-
+ drivers/staging/ozwpan/ozprotocol.h                |    6 +-
+ drivers/staging/panel/panel.c                      |    4 +-
+ drivers/staging/rtl8187se/ieee80211/ieee80211.h    |    2 +-
+ drivers/staging/rtl8187se/r8180_core.c             |    4 +-
+ drivers/staging/rtl8187se/r8180_hw.h               |    9 +-
+ drivers/staging/rtl8187se/r8185b_init.c            |    2 +-
+ .../staging/rtl8192e/rtl8192e/r8192E_firmware.c    |    9 +-
+ .../staging/rtl8192e/rtl8192e/r8192E_firmware.h    |    4 +
+ drivers/staging/rtl8192e/rtl8192e/rtl_core.c       |    3 +
+ drivers/staging/rtl8192e/rtl8192e/rtl_dm.c         |    2 +-
+ drivers/staging/rtl8192e/rtllib.h                  |    8 +-
+ drivers/staging/rtl8192e/rtllib_softmac.c          |    4 +-
+ drivers/staging/rtl8192u/ieee80211/ieee80211.h     |    4 +-
+ .../staging/rtl8192u/ieee80211/ieee80211_softmac.c |    4 +-
+ .../staging/rtl8192u/ieee80211/rtl819x_BAProc.c    |    2 +-
+ drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h    |    4 +-
+ .../staging/rtl8192u/ieee80211/rtl819x_HTProc.c    |    2 +-
+ drivers/staging/rtl8192u/r819xU_HTType.h           |    2 +-
+ drivers/staging/rtl8192u/r819xU_phyreg.h           |    2 +-
+ drivers/staging/rtl8712/rtl8712_recv.h             |    2 +-
+ drivers/staging/rts5139/trace.h                    |   32 +-
+ drivers/staging/rts_pstor/trace.h                  |   30 +-
+ drivers/staging/serqt_usb2/serqt_usb2.c            |    9 +-
+ drivers/staging/speakup/i18n.c                     |    1 +
+ .../staging/tidspbridge/Documentation/error-codes  |    2 +-
+ drivers/staging/tidspbridge/core/_tiomap.h         |    2 +-
+ drivers/staging/tidspbridge/core/chnl_sm.c         |    6 +-
+ drivers/staging/tidspbridge/core/io_sm.c           |   10 +-
+ drivers/staging/tidspbridge/core/sync.c            |    2 +-
+ drivers/staging/tidspbridge/core/tiomap3430.c      |    4 +-
+ drivers/staging/tidspbridge/core/tiomap3430_pwr.c  |    2 +-
+ drivers/staging/tidspbridge/dynload/tramp.c        |    8 +-
+ drivers/staging/tidspbridge/gen/uuidutil.c         |   21 -
+ drivers/staging/tidspbridge/hw/hw_mmu.c            |    6 +-
+ .../tidspbridge/include/dspbridge/dspioctl.h       |    2 +-
+ .../staging/tidspbridge/include/dspbridge/mbx_sh.h |    2 +-
+ .../staging/tidspbridge/include/dspbridge/node.h   |    2 +-
+ .../staging/tidspbridge/include/dspbridge/ntfy.h   |    2 +-
+ .../staging/tidspbridge/include/dspbridge/proc.h   |    2 +-
+ .../staging/tidspbridge/include/dspbridge/strm.h   |    2 +-
+ .../staging/tidspbridge/include/dspbridge/sync.h   |    4 +-
+ .../tidspbridge/include/dspbridge/uuidutil.h       |   20 -
+ drivers/staging/tidspbridge/rmgr/dbdcd.c           |   29 +-
+ drivers/staging/tidspbridge/rmgr/drv_interface.c   |   14 +-
+ drivers/staging/tidspbridge/rmgr/dspdrv.c          |    4 +-
+ drivers/staging/tidspbridge/rmgr/mgr.c             |    4 +-
+ drivers/staging/tidspbridge/rmgr/nldr.c            |    2 +-
+ drivers/staging/tidspbridge/rmgr/node.c            |    5 +-
+ drivers/staging/tidspbridge/rmgr/proc.c            |    2 +-
+ drivers/staging/usbip/stub_rx.c                    |    2 +-
+ drivers/staging/usbip/usbip_common.c               |    4 +
+ drivers/staging/usbip/userspace/configure.ac       |   12 +-
+ drivers/staging/usbip/userspace/doc/usbip.8        |   66 ++-
+ .../usbip/userspace/doc/usbip_bind_driver.8        |   42 --
+ drivers/staging/usbip/userspace/doc/usbipd.8       |   16 +-
+ drivers/staging/usbip/vhci_hcd.c                   |    4 +-
+ drivers/staging/vme/devices/vme_user.c             |    8 +-
+ drivers/staging/vt6655/ioctl.c                     |    7 +-
+ drivers/staging/vt6656/hostap.c                    |   12 +-
+ drivers/staging/vt6656/ioctl.c                     |    7 +-
+ drivers/staging/vt6656/rf.c                        |    4 +-
+ drivers/staging/vt6656/rxtx.c                      |    4 +-
+ drivers/staging/vt6656/wcmd.c                      |    2 +-
+ drivers/staging/vt6656/wmgr.c                      |    6 +-
+ drivers/staging/wlan-ng/p80211wep.c                |   18 +-
+ drivers/staging/xgifb/XGI_main_26.c                |   13 +-
+ drivers/staging/xgifb/vb_init.c                    |    2 +-
+ drivers/staging/zsmalloc/zsmalloc-main.c           |  322 +++++++++--
+ drivers/staging/zsmalloc/zsmalloc_int.h            |  155 -----
+ 184 files changed, 3260 insertions(+), 3025 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
+ delete mode 100644 drivers/staging/comedi/drivers/adl_pci7230.c
+ delete mode 100644 drivers/staging/comedi/drivers/adl_pci7432.c
+ create mode 100644 drivers/staging/comedi/drivers/adl_pci7x3x.c
+ delete mode 100644 drivers/staging/csr/csr_formatted_io.c
+ delete mode 100644 drivers/staging/csr/csr_formatted_io.h
+ create mode 100644 drivers/staging/iio/adc/mxs-lradc.c
+ delete mode 100644 drivers/staging/usbip/userspace/doc/usbip_bind_driver.8
+ delete mode 100644 drivers/staging/zsmalloc/zsmalloc_int.h
+Merging char-misc/char-misc-next (877cdf3 drivers/misc/ti-st: check chip_awake NULL check)
+$ git merge char-misc/char-misc-next
+Resolved 'drivers/misc/mei/interrupt.c' using previous resolution.
+Auto-merging drivers/misc/mei/main.c
+Auto-merging drivers/misc/mei/interrupt.c
+CONFLICT (content): Merge conflict in drivers/misc/mei/interrupt.c
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master 5bdf460] Merge remote-tracking branch 'char-misc/char-misc-next'
+$ git diff -M --stat --summary HEAD^..
+ Documentation/devicetree/bindings/w1/w1-gpio.txt |   22 +++++
+ drivers/char/tlclk.c                             |    4 +-
+ drivers/misc/bmp085-i2c.c                        |    7 --
+ drivers/misc/carma/carma-fpga-program.c          |    1 -
+ drivers/misc/carma/carma-fpga.c                  |    2 +-
+ drivers/misc/mei/hw.h                            |   79 ++++++++--------
+ drivers/misc/mei/init.c                          |   93 ++++++++++--------
+ drivers/misc/mei/interface.h                     |   10 +-
+ drivers/misc/mei/interrupt.c                     |   35 ++++---
+ drivers/misc/mei/iorw.c                          |   59 ++++++------
+ drivers/misc/mei/main.c                          |   78 ++++++----------
+ drivers/misc/mei/mei_dev.h                       |   57 ++++++-----
+ drivers/misc/mei/wd.c                            |   91 +++++++++---------
+ drivers/misc/pch_phub.c                          |   15 +--
+ drivers/misc/ti-st/st_core.c                     |   12 ++-
+ drivers/misc/ti-st/st_kim.c                      |  109 +++++++++-------------
+ drivers/w1/masters/Kconfig                       |    1 -
+ drivers/w1/masters/omap_hdq.c                    |   57 +++--------
+ drivers/w1/masters/w1-gpio.c                     |   66 ++++++++++++-
+ include/linux/ti_wilink_st.h                     |    3 +-
+ include/linux/w1-gpio.h                          |    1 +
+ 21 files changed, 417 insertions(+), 385 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/w1/w1-gpio.txt
+Merging tmem/linux-next (15773b6 Merge branch 'stable/for-linus-3.6' into linux-next)
+$ git merge tmem/linux-next
+Merge made by the 'recursive' strategy.
+ mm/frontswap.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+Merging writeback/writeback-for-next (331cbde writeback: Fix some comment errors)
+$ git merge writeback/writeback-for-next
+Already up-to-date.
+Merging arm-dt/devicetree/arm-next (ede338f dt: add documentation of ARM dt boot interface)
+$ git merge arm-dt/devicetree/arm-next
+Already up-to-date.
+Merging hwspinlock/linux-next (8b37fcf hwspinlock: add MAINTAINERS entries)
+$ git merge hwspinlock/linux-next
+Already up-to-date.
+Merging pinctrl/for-next (2853ff28 Merge branch 'devel' into for-next)
+$ git merge pinctrl/for-next
+Auto-merging arch/arm/Kconfig
+Merge made by the 'recursive' strategy.
+ .../bindings/pinctrl/fsl,imx35-pinctrl.txt         |  984 ++++++++++++
+ Documentation/pinctrl.txt                          |    6 +-
+ arch/arm/Kconfig                                   |    1 +
+ arch/arm/mach-nomadik/board-nhk8815.c              |   36 +
+ arch/arm/mach-nomadik/cpu-8815.c                   |   13 +
+ drivers/pinctrl/Kconfig                            |   16 +
+ drivers/pinctrl/Makefile                           |    3 +
+ drivers/pinctrl/core.c                             |   13 +-
+ drivers/pinctrl/pinctrl-imx35.c                    | 1595 ++++++++++++++++++++
+ drivers/pinctrl/pinctrl-imx51.c                    |  492 +++---
+ drivers/pinctrl/pinctrl-imx53.c                    |  402 ++---
+ drivers/pinctrl/pinctrl-nomadik-db8500.c           |    5 +-
+ drivers/pinctrl/pinctrl-nomadik-db8540.c           |  999 ++++++++++++
+ drivers/pinctrl/pinctrl-nomadik-stn8815.c          |  357 +++++
+ drivers/pinctrl/pinctrl-nomadik.c                  |    7 +-
+ drivers/pinctrl/pinctrl-nomadik.h                  |   27 +
+ include/linux/pinctrl/consumer.h                   |    3 +-
+ 17 files changed, 4496 insertions(+), 463 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,imx35-pinctrl.txt
+ create mode 100644 drivers/pinctrl/pinctrl-imx35.c
+ create mode 100644 drivers/pinctrl/pinctrl-nomadik-db8540.c
+ create mode 100644 drivers/pinctrl/pinctrl-nomadik-stn8815.c
+Merging vhost/linux-next (e0953c8 tun: experimental zero copy tx support)
+$ git merge vhost/linux-next
+Resolved 'drivers/net/tun.c' using previous resolution.
+Auto-merging drivers/net/tun.c
+CONFLICT (content): Merge conflict in drivers/net/tun.c
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master e99cbdc] Merge remote-tracking branch 'vhost/linux-next'
+$ git diff -M --stat --summary HEAD^..
+Merging memblock/memblock-kill-early_node_map (7bd0b0f memblock: Reimplement memblock allocation using reverse free area iterator)
+$ git merge memblock/memblock-kill-early_node_map
+Already up-to-date.
+Merging remoteproc/for-next (6bb697b MAINTAINERS: add remoteproc's git)
+$ git merge remoteproc/for-next
+Already up-to-date.
+Merging irqdomain/irqdomain/next (f5a1ad0 irqdomain: Improve diagnostics when a domain mapping fails)
+$ git merge irqdomain/irqdomain/next
+Already up-to-date.
+Merging gpio/gpio/next (ddf343f Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux)
+$ git merge gpio/gpio/next
+Already up-to-date.
+Merging gpio-lw/for-next (f47c3df Merge branch 'devel' into for-next)
+$ git merge gpio-lw/for-next
+Merge made by the 'recursive' strategy.
+ drivers/gpio/gpio-ml-ioh.c |   20 ++++-----
+ drivers/gpio/gpio-pch.c    |   22 +++++-----
+ drivers/gpio/gpiolib-of.c  |    2 +-
+ drivers/gpio/gpiolib.c     |  102 ++++++++++++++++++++++++++++++++------------
+ 4 files changed, 95 insertions(+), 51 deletions(-)
+Merging arm-soc/for-next (e149302 Merge branch 'next/dt' into for-next)
+$ git merge arm-soc/for-next
+Resolved 'drivers/mtd/nand/Kconfig' using previous resolution.
+Auto-merging include/linux/platform_data/pinctrl-coh901.h
+Auto-merging include/linux/leds.h
+Auto-merging drivers/spi/spi-omap2-mcspi.c
+Auto-merging drivers/mtd/nand/pxa3xx_nand.c
+Auto-merging drivers/mtd/nand/Kconfig
+CONFLICT (content): Merge conflict in drivers/mtd/nand/Kconfig
+Auto-merging drivers/mmc/host/omap_hsmmc.c
+Auto-merging drivers/gpio/gpio-pxa.c
+Auto-merging arch/powerpc/sysdev/fsl_msi.c
+Removing arch/arm/mach-versatile/include/mach/io.h
+Auto-merging arch/arm/mach-ux500/cpu-db8500.c
+Removing arch/arm/mach-u300/u300.c
+Removing arch/arm/mach-u300/include/mach/platform.h
+Removing arch/arm/mach-u300/include/mach/clkdev.h
+Auto-merging arch/arm/mach-u300/dma_channels.h
+Removing arch/arm/mach-tegra/include/mach/io.h
+Removing arch/arm/mach-shark/include/mach/io.h
+Removing arch/arm/mach-sa1100/leds.h
+Removing arch/arm/mach-sa1100/leds.c
+Removing arch/arm/mach-sa1100/leds-lart.c
+Removing arch/arm/mach-sa1100/leds-hackkit.c
+Removing arch/arm/mach-sa1100/leds-cerf.c
+Removing arch/arm/mach-sa1100/leds-badge4.c
+Removing arch/arm/mach-sa1100/leds-assabet.c
+Auto-merging arch/arm/mach-realview/realview_pbx.c
+Auto-merging arch/arm/mach-realview/realview_pba8.c
+Auto-merging arch/arm/mach-realview/realview_pb11mp.c
+Auto-merging arch/arm/mach-realview/realview_pb1176.c
+Auto-merging arch/arm/mach-realview/realview_eb.c
+Removing arch/arm/mach-pxa/leds.h
+Removing arch/arm/mach-pxa/leds.c
+Removing arch/arm/mach-pxa/leds-mainstone.c
+Removing arch/arm/mach-pxa/leds-lubbock.c
+Removing arch/arm/mach-pxa/leds-idp.c
+Removing arch/arm/mach-orion5x/include/mach/io.h
+Auto-merging arch/arm/mach-omap2/twl-common.c
+Auto-merging arch/arm/mach-omap2/board-omap3evm.c
+Auto-merging arch/arm/mach-omap2/board-igep0020.c
+Removing arch/arm/mach-omap1/leds.h
+Removing arch/arm/mach-omap1/leds.c
+Removing arch/arm/mach-omap1/leds-osk.c
+Removing arch/arm/mach-omap1/leds-innovator.c
+Removing arch/arm/mach-omap1/leds-h2p2-debug.c
+Removing arch/arm/mach-mv78xx0/include/mach/io.h
+Removing arch/arm/mach-ks8695/leds.c
+Removing arch/arm/mach-kirkwood/include/mach/io.h
+Removing arch/arm/mach-iop33x/include/mach/io.h
+Removing arch/arm/mach-iop32x/include/mach/io.h
+Removing arch/arm/mach-iop13xx/include/mach/io.h
+Removing arch/arm/mach-integrator/include/mach/io.h
+Removing arch/arm/mach-footbridge/netwinder-leds.c
+Removing arch/arm/mach-footbridge/ebsa285-leds.c
+Removing arch/arm/mach-dove/include/mach/io.h
+Removing arch/arm/mach-clps711x/p720t-leds.c
+Auto-merging arch/arm/mach-bcmring/include/mach/csp/tmrHw.h
+Auto-merging arch/arm/mach-bcmring/include/mach/csp/reg.h
+Auto-merging arch/arm/mach-bcmring/include/mach/csp/dmacHw.h
+Auto-merging arch/arm/mach-bcmring/include/mach/cfg_global.h
+Removing arch/arm/mach-bcmring/include/csp/string.h
+Removing arch/arm/mach-bcmring/include/csp/stdint.h
+Removing arch/arm/mach-bcmring/include/csp/secHw.h
+Removing arch/arm/mach-bcmring/include/csp/module.h
+Removing arch/arm/mach-bcmring/include/csp/intcHw.h
+Removing arch/arm/mach-bcmring/include/csp/errno.h
+Removing arch/arm/mach-bcmring/include/csp/delay.h
+Removing arch/arm/mach-bcmring/include/csp/cache.h
+Removing arch/arm/mach-bcmring/include/cfg_global.h
+Auto-merging arch/arm/mach-bcmring/arch.c
+Removing arch/arm/kernel/leds.c
+Auto-merging arch/arm/kernel/Makefile
+Removing arch/arm/include/asm/leds.h
+Auto-merging arch/arm/Kconfig
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master ce8283b] Merge remote-tracking branch 'arm-soc/for-next'
+$ git diff -M --stat --summary HEAD^..
+ Documentation/arm/Marvell/README                   |  232 ++++++++++++++++
+ Documentation/arm/memory.txt                       |    3 +
+ .../devicetree/bindings/arm/mrvl/tauros2.txt       |   17 ++
+ .../devicetree/bindings/mtd/pxa3xx-nand.txt        |   31 +++
+ Documentation/devicetree/bindings/rtc/pxa-rtc.txt  |   14 +
+ arch/arm/Kconfig                                   |   67 +----
+ arch/arm/arm-soc-for-next-contents.txt             |   40 +++
+ arch/arm/boot/dts/am33xx.dtsi                      |    5 +
+ arch/arm/boot/dts/kirkwood-iconnect.dts            |    6 +-
+ arch/arm/boot/dts/mmp2.dtsi                        |    5 +
+ arch/arm/boot/dts/pxa27x.dtsi                      |   14 +
+ arch/arm/boot/dts/pxa2xx.dtsi                      |  132 +++++++++
+ arch/arm/boot/dts/pxa3xx.dtsi                      |   32 +++
+ arch/arm/boot/dts/pxa910.dtsi                      |    5 +
+ arch/arm/boot/dts/twl6030.dtsi                     |    3 +
+ arch/arm/configs/afeb9260_defconfig                |    1 -
+ arch/arm/configs/at91rm9200_defconfig              |    2 +-
+ arch/arm/configs/at91sam9261_defconfig             |    2 +-
+ arch/arm/configs/at91sam9263_defconfig             |    3 +-
+ arch/arm/configs/at91sam9g20_defconfig             |    2 +-
+ arch/arm/configs/at91sam9rl_defconfig              |    2 +-
+ arch/arm/configs/cpu9260_defconfig                 |    2 +-
+ arch/arm/configs/cpu9g20_defconfig                 |    2 +-
+ arch/arm/configs/qil-a9260_defconfig               |    3 +-
+ arch/arm/configs/stamp9g20_defconfig               |    1 -
+ arch/arm/configs/usb-a9260_defconfig               |    1 -
+ arch/arm/include/asm/hardware/cache-tauros2.h      |    5 +-
+ arch/arm/include/asm/hardware/iop3xx.h             |   12 +-
+ arch/arm/include/asm/io.h                          |    8 +
+ arch/arm/include/asm/leds.h                        |   50 ----
+ arch/arm/include/asm/mach/map.h                    |    8 +
+ arch/arm/include/asm/mach/pci.h                    |   13 +
+ arch/arm/kernel/Makefile                           |    1 -
+ arch/arm/kernel/bios32.c                           |   54 +++-
+ arch/arm/kernel/leds.c                             |  121 --------
+ arch/arm/kernel/process.c                          |    6 +-
+ arch/arm/kernel/time.c                             |   17 --
+ arch/arm/mach-at91/at91rm9200_devices.c            |   92 +++---
+ arch/arm/mach-at91/at91sam9260_devices.c           |   84 +-----
+ arch/arm/mach-at91/at91sam9261_devices.c           |   60 ++--
+ arch/arm/mach-at91/at91sam9263.c                   |    4 +-
+ arch/arm/mach-at91/at91sam9263_devices.c           |  161 ++++++-----
+ arch/arm/mach-at91/at91sam9rl_devices.c            |   60 ++--
+ arch/arm/mach-at91/board-afeb-9260v1.c             |   14 +-
+ arch/arm/mach-at91/board-carmeva.c                 |   14 +-
+ arch/arm/mach-at91/board-cpu9krea.c                |   17 +-
+ arch/arm/mach-at91/board-cpuat91.c                 |   13 +-
+ arch/arm/mach-at91/board-csb337.c                  |   16 +-
+ arch/arm/mach-at91/board-eb9200.c                  |   14 +-
+ arch/arm/mach-at91/board-ecbat91.c                 |   32 ++-
+ arch/arm/mach-at91/board-eco920.c                  |   36 ++-
+ arch/arm/mach-at91/board-flexibity.c               |   14 +-
+ arch/arm/mach-at91/board-foxg20.c                  |   16 +-
+ arch/arm/mach-at91/board-kafa.c                    |   17 +-
+ arch/arm/mach-at91/board-kb9202.c                  |   37 ++-
+ arch/arm/mach-at91/board-neocore926.c              |   13 +-
+ arch/arm/mach-at91/board-picotux200.c              |   14 +-
+ arch/arm/mach-at91/board-qil-a9260.c               |   14 +-
+ arch/arm/mach-at91/board-rm9200dk.c                |   17 +-
+ arch/arm/mach-at91/board-rm9200ek.c                |   17 +-
+ arch/arm/mach-at91/board-rsi-ews.c                 |   16 +-
+ arch/arm/mach-at91/board-sam9-l9260.c              |   39 ++-
+ arch/arm/mach-at91/board-sam9260ek.c               |   16 +-
+ arch/arm/mach-at91/board-sam9261ek.c               |   16 +-
+ arch/arm/mach-at91/board-sam9263ek.c               |   13 +-
+ arch/arm/mach-at91/board-sam9g20ek.c               |   16 +-
+ arch/arm/mach-at91/board-sam9rlek.c                |   13 +-
+ arch/arm/mach-at91/board-stamp9g20.c               |   14 -
+ arch/arm/mach-at91/board-usb-a926x.c               |    2 -
+ arch/arm/mach-at91/board-yl-9200.c                 |   16 +-
+ arch/arm/mach-at91/include/mach/board.h            |    1 -
+ arch/arm/mach-at91/leds.c                          |  105 -------
+ arch/arm/mach-bcmring/arch.c                       |    2 +-
+ arch/arm/mach-bcmring/core.c                       |    3 +-
+ arch/arm/mach-bcmring/csp/chipc/chipcHw.c          |  137 ++++-----
+ arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c     |   90 +++---
+ arch/arm/mach-bcmring/csp/chipc/chipcHw_reset.c    |   19 +-
+ arch/arm/mach-bcmring/csp/dmac/dmacHw.c            |   27 +-
+ arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c      |    6 +-
+ arch/arm/mach-bcmring/csp/tmr/tmrHw.c              |    6 +-
+ arch/arm/mach-bcmring/include/cfg_global.h         |   13 -
+ arch/arm/mach-bcmring/include/csp/cache.h          |   35 ---
+ arch/arm/mach-bcmring/include/csp/delay.h          |   36 ---
+ arch/arm/mach-bcmring/include/csp/errno.h          |   32 ---
+ arch/arm/mach-bcmring/include/csp/intcHw.h         |   40 ---
+ arch/arm/mach-bcmring/include/csp/module.h         |   32 ---
+ arch/arm/mach-bcmring/include/csp/secHw.h          |   65 -----
+ arch/arm/mach-bcmring/include/csp/stdint.h         |   30 --
+ arch/arm/mach-bcmring/include/csp/string.h         |   34 ---
+ .../{cfg_global_defines.h => mach/cfg_global.h}    |   11 +
+ .../arm/mach-bcmring/include/mach/csp/cap_inline.h |    2 +-
+ .../mach-bcmring/include/mach/csp/chipcHw_def.h    |    6 +-
+ .../mach-bcmring/include/mach/csp/chipcHw_inline.h |  119 ++++----
+ .../mach-bcmring/include/mach/csp/chipcHw_reg.h    |    6 +-
+ arch/arm/mach-bcmring/include/mach/csp/ddrcReg.h   |    6 +-
+ .../mach-bcmring/include/{ => mach}/csp/dmacHw.h   |    4 +-
+ .../mach-bcmring/include/mach/csp/dmacHw_priv.h    |    2 +-
+ .../arm/mach-bcmring/include/mach/csp/dmacHw_reg.h |  106 +++----
+ arch/arm/mach-bcmring/include/mach/csp/hw_cfg.h    |    2 +-
+ .../arm/mach-bcmring/include/mach/csp/intcHw_reg.h |   18 +-
+ arch/arm/mach-bcmring/include/mach/csp/mm_addr.h   |    2 +-
+ arch/arm/mach-bcmring/include/mach/csp/mm_io.h     |    8 +-
+ arch/arm/mach-bcmring/include/{ => mach}/csp/reg.h |   25 +-
+ .../mach-bcmring/include/mach/csp/secHw_inline.h   |   10 +-
+ .../mach-bcmring/include/{ => mach}/csp/tmrHw.h    |    2 +-
+ arch/arm/mach-bcmring/include/mach/dma.h           |    2 +-
+ arch/arm/mach-bcmring/include/mach/hardware.h      |    2 +-
+ arch/arm/mach-bcmring/include/mach/reg_nand.h      |    2 +-
+ arch/arm/mach-bcmring/include/mach/reg_umi.h       |    4 +-
+ arch/arm/mach-bcmring/mm.c                         |    4 +-
+ arch/arm/mach-bcmring/timer.c                      |    2 +-
+ arch/arm/mach-clps711x/Makefile                    |    2 -
+ arch/arm/mach-clps711x/common.c                    |    1 -
+ arch/arm/mach-clps711x/p720t-leds.c                |   63 -----
+ arch/arm/mach-clps711x/p720t.c                     |   62 +++++
+ arch/arm/mach-dove/common.c                        |   15 +-
+ arch/arm/mach-dove/include/mach/dove.h             |    8 +-
+ arch/arm/mach-dove/include/mach/io.h               |   19 --
+ arch/arm/mach-dove/pcie.c                          |   43 +--
+ arch/arm/mach-ebsa110/Makefile                     |    4 +-
+ arch/arm/mach-ebsa110/leds.c                       |   81 +++---
+ arch/arm/mach-footbridge/Makefile                  |    4 -
+ arch/arm/mach-footbridge/common.c                  |   12 +-
+ arch/arm/mach-footbridge/dc21285.c                 |   16 +-
+ arch/arm/mach-footbridge/ebsa285-leds.c            |  138 ---------
+ arch/arm/mach-footbridge/ebsa285.c                 |   81 ++++++
+ .../arm/mach-footbridge/include/mach/debug-macro.S |    3 +-
+ arch/arm/mach-footbridge/include/mach/io.h         |   12 +-
+ arch/arm/mach-footbridge/netwinder-hw.c            |  112 +++++++-
+ arch/arm/mach-footbridge/netwinder-leds.c          |  138 ---------
+ arch/arm/mach-integrator/Makefile                  |    3 +-
+ arch/arm/mach-integrator/core.c                    |    3 -
+ arch/arm/mach-integrator/include/mach/cm.h         |    2 +
+ arch/arm/mach-integrator/include/mach/io.h         |   33 ---
+ arch/arm/mach-integrator/include/mach/platform.h   |    4 +
+ arch/arm/mach-integrator/integrator_ap.c           |    9 +-
+ arch/arm/mach-integrator/leds.c                    |  161 ++++++-----
+ arch/arm/mach-integrator/pci_v3.c                  |   50 ++--
+ arch/arm/mach-iop13xx/include/mach/io.h            |   28 --
+ arch/arm/mach-iop13xx/include/mach/iop13xx.h       |   28 +-
+ arch/arm/mach-iop13xx/io.c                         |   27 --
+ arch/arm/mach-iop13xx/pci.c                        |   37 +--
+ arch/arm/mach-iop13xx/setup.c                      |   10 -
+ arch/arm/mach-iop32x/include/mach/io.h             |   19 --
+ arch/arm/mach-iop33x/include/mach/io.h             |   19 --
+ arch/arm/mach-kirkwood/Makefile.boot               |    3 +-
+ arch/arm/mach-kirkwood/common.c                    |   14 +-
+ arch/arm/mach-kirkwood/include/mach/io.h           |   24 --
+ arch/arm/mach-kirkwood/include/mach/kirkwood.h     |    8 +-
+ arch/arm/mach-kirkwood/pcie.c                      |   44 +--
+ arch/arm/mach-ks8695/Makefile                      |    3 -
+ arch/arm/mach-ks8695/devices.c                     |   21 --
+ arch/arm/mach-ks8695/include/mach/devices.h        |    5 -
+ arch/arm/mach-ks8695/leds.c                        |   92 ------
+ arch/arm/mach-mmp/mmp2.c                           |    2 +-
+ arch/arm/mach-mmp/pxa910.c                         |    4 +
+ arch/arm/mach-mmp/ttc_dkb.c                        |   10 +
+ arch/arm/mach-mv78xx0/addr-map.c                   |    5 +-
+ arch/arm/mach-mv78xx0/common.c                     |   11 +-
+ arch/arm/mach-mv78xx0/include/mach/io.h            |   24 --
+ arch/arm/mach-mv78xx0/include/mach/mv78xx0.h       |   21 +-
+ arch/arm/mach-mv78xx0/pcie.c                       |  110 +++-----
+ arch/arm/mach-omap1/Makefile                       |    8 -
+ arch/arm/mach-omap1/board-h2.c                     |   32 +++
+ arch/arm/mach-omap1/board-h3.c                     |   32 +++
+ arch/arm/mach-omap1/board-osk.c                    |   33 +++
+ arch/arm/mach-omap1/leds-h2p2-debug.c              |  166 -----------
+ arch/arm/mach-omap1/leds-innovator.c               |   98 -------
+ arch/arm/mach-omap1/leds-osk.c                     |  113 --------
+ arch/arm/mach-omap1/leds.c                         |   69 -----
+ arch/arm/mach-omap1/leds.h                         |    3 -
+ arch/arm/mach-omap1/time.c                         |    1 -
+ arch/arm/mach-omap1/timer32k.c                     |    1 -
+ arch/arm/mach-omap2/Kconfig                        |    1 +
+ arch/arm/mach-omap2/board-igep0020.c               |    2 +
+ arch/arm/mach-omap2/board-omap3evm.c               |    1 +
+ arch/arm/mach-omap2/common-board-devices.c         |   11 -
+ arch/arm/mach-omap2/common-board-devices.h         |    1 -
+ arch/arm/mach-omap2/mux.h                          |    1 -
+ arch/arm/mach-omap2/opp4xxx_data.c                 |    2 +-
+ arch/arm/mach-omap2/pm34xx.c                       |   19 +-
+ arch/arm/mach-omap2/sleep44xx.S                    |    8 +-
+ arch/arm/mach-omap2/twl-common.c                   |    1 +
+ arch/arm/mach-orion5x/common.c                     |   13 +-
+ arch/arm/mach-orion5x/include/mach/io.h            |   22 --
+ arch/arm/mach-orion5x/include/mach/orion5x.h       |   20 +-
+ arch/arm/mach-orion5x/pci.c                        |   56 ++--
+ arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c       |    1 -
+ arch/arm/mach-orion5x/rd88f5181l-ge-setup.c        |    1 -
+ arch/arm/mach-orion5x/rd88f5182-setup.c            |   72 ++---
+ arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c       |    1 -
+ arch/arm/mach-pnx4008/time.c                       |    1 -
+ arch/arm/mach-pxa/Kconfig                          |   12 +
+ arch/arm/mach-pxa/Makefile                         |   11 +-
+ arch/arm/mach-pxa/clock-pxa3xx.c                   |    8 +-
+ arch/arm/mach-pxa/idp.c                            |   81 ++++++
+ arch/arm/mach-pxa/irq.c                            |  131 +++++++--
+ arch/arm/mach-pxa/leds-idp.c                       |  115 --------
+ arch/arm/mach-pxa/leds-lubbock.c                   |  124 ---------
+ arch/arm/mach-pxa/leds-mainstone.c                 |  119 --------
+ arch/arm/mach-pxa/leds.c                           |   32 ---
+ arch/arm/mach-pxa/leds.h                           |   13 -
+ arch/arm/mach-pxa/lubbock.c                        |   95 +++++++
+ arch/arm/mach-pxa/mainstone.c                      |   94 +++++++
+ arch/arm/mach-pxa/pxa-dt.c                         |   63 +++++
+ arch/arm/mach-pxa/pxa3xx.c                         |   21 +-
+ arch/arm/mach-realview/core.c                      |   39 ---
+ arch/arm/mach-realview/core.h                      |    2 -
+ arch/arm/mach-realview/realview_eb.c               |    5 -
+ arch/arm/mach-realview/realview_pb1176.c           |    5 -
+ arch/arm/mach-realview/realview_pb11mp.c           |    5 -
+ arch/arm/mach-realview/realview_pba8.c             |    5 -
+ arch/arm/mach-realview/realview_pbx.c              |    5 -
+ arch/arm/mach-sa1100/Makefile                      |    9 -
+ arch/arm/mach-sa1100/assabet.c                     |   85 ++++++
+ arch/arm/mach-sa1100/badge4.c                      |   30 ++
+ arch/arm/mach-sa1100/cerf.c                        |   42 +++
+ arch/arm/mach-sa1100/hackkit.c                     |   32 +++
+ arch/arm/mach-sa1100/lart.c                        |   26 ++
+ arch/arm/mach-sa1100/leds-assabet.c                |  113 --------
+ arch/arm/mach-sa1100/leds-badge4.c                 |  110 --------
+ arch/arm/mach-sa1100/leds-cerf.c                   |  110 --------
+ arch/arm/mach-sa1100/leds-hackkit.c                |  112 --------
+ arch/arm/mach-sa1100/leds-lart.c                   |  101 -------
+ arch/arm/mach-sa1100/leds.c                        |   50 ----
+ arch/arm/mach-sa1100/leds.h                        |   13 -
+ arch/arm/mach-shark/Makefile                       |    4 +-
+ arch/arm/mach-shark/core.c                         |   19 --
+ arch/arm/mach-shark/include/mach/debug-macro.S     |    7 +-
+ arch/arm/mach-shark/include/mach/entry-macro.S     |    3 +-
+ arch/arm/mach-shark/include/mach/io.h              |   18 --
+ arch/arm/mach-shark/leds.c                         |  220 ++++++---------
+ arch/arm/mach-shark/pci.c                          |    5 +
+ arch/arm/mach-tegra/include/mach/io.h              |   46 ---
+ arch/arm/mach-tegra/include/mach/iomap.h           |    3 +
+ arch/arm/mach-tegra/pcie.c                         |   95 ++-----
+ arch/arm/mach-u300/Kconfig                         |   43 +--
+ arch/arm/mach-u300/Makefile                        |    1 -
+ arch/arm/mach-u300/core.c                          |  100 ++-----
+ .../mach-u300/{include/mach => }/dma_channels.h    |   11 +-
+ arch/arm/mach-u300/i2c.c                           |    6 +-
+ arch/arm/mach-u300/include/mach/clkdev.h           |    7 -
+ arch/arm/mach-u300/include/mach/irqs.h             |   36 +--
+ arch/arm/mach-u300/include/mach/platform.h         |   20 --
+ arch/arm/mach-u300/include/mach/syscon.h           |   32 +--
+ arch/arm/mach-u300/include/mach/u300-regs.h        |   19 +-
+ arch/arm/mach-u300/spi.c                           |    2 +-
+ arch/arm/mach-u300/timer.c                         |    5 +-
+ arch/arm/mach-u300/timer.h                         |    1 +
+ arch/arm/mach-u300/u300-gpio.h                     |   46 +--
+ arch/arm/mach-u300/u300.c                          |   57 ----
+ arch/arm/mach-ux500/cache-l2x0.c                   |    2 +-
+ arch/arm/mach-ux500/cpu-db8500.c                   |    2 +-
+ arch/arm/mach-ux500/cpu.c                          |    2 +-
+ arch/arm/mach-ux500/include/mach/id.h              |   44 +--
+ arch/arm/mach-ux500/platsmp.c                      |    2 +-
+ arch/arm/mach-versatile/core.c                     |   10 -
+ arch/arm/mach-versatile/include/mach/hardware.h    |    1 -
+ arch/arm/mach-versatile/include/mach/io.h          |   27 --
+ arch/arm/mach-versatile/pci.c                      |   22 +-
+ arch/arm/mm/cache-l2x0.c                           |    2 +-
+ arch/arm/mm/cache-tauros2.c                        |   83 ++++--
+ arch/arm/mm/ioremap.c                              |   14 +
+ arch/arm/mm/mmu.c                                  |   54 +++-
+ arch/arm/plat-iop/pci.c                            |   25 +-
+ arch/arm/plat-iop/setup.c                          |    5 -
+ arch/arm/plat-omap/Kconfig                         |    3 +-
+ arch/arm/plat-omap/debug-leds.c                    |  293 +++++---------------
+ arch/arm/plat-omap/dmtimer.c                       |    6 +-
+ arch/arm/plat-omap/include/plat/cpu.h              |    3 +-
+ arch/arm/plat-omap/include/plat/multi.h            |    9 +
+ arch/arm/plat-omap/include/plat/uncompress.h       |    4 +-
+ arch/arm/plat-orion/common.c                       |    8 +-
+ arch/arm/plat-orion/include/plat/common.h          |    6 +-
+ arch/arm/plat-samsung/time.c                       |    1 -
+ arch/arm/plat-versatile/Kconfig                    |    4 +-
+ arch/arm/plat-versatile/leds.c                     |    8 +-
+ arch/powerpc/platforms/83xx/suspend.c              |    2 +-
+ arch/powerpc/platforms/cell/celleb_pci.c           |    2 +-
+ arch/powerpc/sysdev/fsl_msi.c                      |    8 +-
+ drivers/char/nwflash.c                             |   34 ---
+ drivers/cpufreq/omap-cpufreq.c                     |    4 +-
+ drivers/gpio/gpio-mpc8xxx.c                        |    2 +-
+ drivers/gpio/gpio-omap.c                           |    8 +-
+ drivers/gpio/gpio-pxa.c                            |   77 ++---
+ drivers/i2c/busses/i2c-iop3xx.c                    |  121 ++++----
+ drivers/i2c/busses/i2c-mpc.c                       |   12 +-
+ drivers/i2c/busses/i2c-omap.c                      |    3 +-
+ drivers/leds/Kconfig                               |   10 +
+ drivers/leds/Makefile                              |    1 +
+ drivers/leds/ledtrig-cpu.c                         |  163 +++++++++++
+ drivers/macintosh/mediabay.c                       |    8 +-
+ drivers/mfd/da9052-i2c.c                           |    4 +-
+ drivers/mmc/host/omap_hsmmc.c                      |    2 +-
+ drivers/mtd/nand/bcm_umi_nand.c                    |   12 +-
+ drivers/mtd/nand/nand_bcm_umi.h                    |   73 +++--
+ drivers/mtd/nand/pxa3xx_nand.c                     |   85 +++++-
+ drivers/net/can/mscan/mpc5xxx_can.c                |    4 +-
+ drivers/pinctrl/pinctrl-coh901.c                   |  220 +++------------
+ drivers/rtc/rtc-pxa.c                              |   11 +
+ drivers/spi/spi-imx.c                              |    2 +-
+ drivers/spi/spi-omap2-mcspi.c                      |    2 +-
+ drivers/tty/serial/mpc52xx_uart.c                  |    2 +-
+ drivers/watchdog/mpc8xxx_wdt.c                     |    2 +-
+ include/linux/atmel_tc.h                           |    2 +-
+ include/linux/leds.h                               |   16 ++
+ include/linux/mod_devicetable.h                    |    2 +-
+ include/linux/mv643xx_eth.h                        |    2 +
+ .../linux/platform_data/pinctrl-coh901.h           |   13 +-
+ 309 files changed, 3739 insertions(+), 5789 deletions(-)
+ create mode 100644 Documentation/arm/Marvell/README
+ create mode 100644 Documentation/devicetree/bindings/arm/mrvl/tauros2.txt
+ create mode 100644 Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
+ create mode 100644 Documentation/devicetree/bindings/rtc/pxa-rtc.txt
+ create mode 100644 arch/arm/arm-soc-for-next-contents.txt
+ create mode 100644 arch/arm/boot/dts/pxa27x.dtsi
+ create mode 100644 arch/arm/boot/dts/pxa2xx.dtsi
+ create mode 100644 arch/arm/boot/dts/pxa3xx.dtsi
+ delete mode 100644 arch/arm/include/asm/leds.h
+ delete mode 100644 arch/arm/kernel/leds.c
+ delete mode 100644 arch/arm/mach-bcmring/include/cfg_global.h
+ delete mode 100644 arch/arm/mach-bcmring/include/csp/cache.h
+ delete mode 100644 arch/arm/mach-bcmring/include/csp/delay.h
+ delete mode 100644 arch/arm/mach-bcmring/include/csp/errno.h
+ delete mode 100644 arch/arm/mach-bcmring/include/csp/intcHw.h
+ delete mode 100644 arch/arm/mach-bcmring/include/csp/module.h
+ delete mode 100644 arch/arm/mach-bcmring/include/csp/secHw.h
+ delete mode 100644 arch/arm/mach-bcmring/include/csp/stdint.h
+ delete mode 100644 arch/arm/mach-bcmring/include/csp/string.h
+ rename arch/arm/mach-bcmring/include/{cfg_global_defines.h => mach/cfg_global.h} (74%)
+ rename arch/arm/mach-bcmring/include/{ => mach}/csp/dmacHw.h (99%)
+ rename arch/arm/mach-bcmring/include/{ => mach}/csp/reg.h (81%)
+ rename arch/arm/mach-bcmring/include/{ => mach}/csp/tmrHw.h (99%)
+ delete mode 100644 arch/arm/mach-clps711x/p720t-leds.c
+ delete mode 100644 arch/arm/mach-dove/include/mach/io.h
+ delete mode 100644 arch/arm/mach-footbridge/ebsa285-leds.c
+ delete mode 100644 arch/arm/mach-footbridge/netwinder-leds.c
+ delete mode 100644 arch/arm/mach-integrator/include/mach/io.h
+ delete mode 100644 arch/arm/mach-iop13xx/include/mach/io.h
+ delete mode 100644 arch/arm/mach-iop32x/include/mach/io.h
+ delete mode 100644 arch/arm/mach-iop33x/include/mach/io.h
+ delete mode 100644 arch/arm/mach-kirkwood/include/mach/io.h
+ delete mode 100644 arch/arm/mach-ks8695/leds.c
+ delete mode 100644 arch/arm/mach-mv78xx0/include/mach/io.h
+ delete mode 100644 arch/arm/mach-omap1/leds-h2p2-debug.c
+ delete mode 100644 arch/arm/mach-omap1/leds-innovator.c
+ delete mode 100644 arch/arm/mach-omap1/leds-osk.c
+ delete mode 100644 arch/arm/mach-omap1/leds.c
+ delete mode 100644 arch/arm/mach-omap1/leds.h
+ delete mode 100644 arch/arm/mach-orion5x/include/mach/io.h
+ delete mode 100644 arch/arm/mach-pxa/leds-idp.c
+ delete mode 100644 arch/arm/mach-pxa/leds-lubbock.c
+ delete mode 100644 arch/arm/mach-pxa/leds-mainstone.c
+ delete mode 100644 arch/arm/mach-pxa/leds.c
+ delete mode 100644 arch/arm/mach-pxa/leds.h
+ create mode 100644 arch/arm/mach-pxa/pxa-dt.c
+ delete mode 100644 arch/arm/mach-sa1100/leds-assabet.c
+ delete mode 100644 arch/arm/mach-sa1100/leds-badge4.c
+ delete mode 100644 arch/arm/mach-sa1100/leds-cerf.c
+ delete mode 100644 arch/arm/mach-sa1100/leds-hackkit.c
+ delete mode 100644 arch/arm/mach-sa1100/leds-lart.c
+ delete mode 100644 arch/arm/mach-sa1100/leds.c
+ delete mode 100644 arch/arm/mach-sa1100/leds.h
+ delete mode 100644 arch/arm/mach-shark/include/mach/io.h
+ delete mode 100644 arch/arm/mach-tegra/include/mach/io.h
+ rename arch/arm/mach-u300/{include/mach => }/dma_channels.h (88%)
+ delete mode 100644 arch/arm/mach-u300/include/mach/clkdev.h
+ delete mode 100644 arch/arm/mach-u300/include/mach/platform.h
+ create mode 100644 arch/arm/mach-u300/timer.h
+ delete mode 100644 arch/arm/mach-u300/u300.c
+ delete mode 100644 arch/arm/mach-versatile/include/mach/io.h
+ create mode 100644 drivers/leds/ledtrig-cpu.c
+ rename arch/arm/mach-u300/include/mach/gpio-u300.h => include/linux/platform_data/pinctrl-coh901.h (72%)
+Merging ep93xx/ep93xx-for-next (fbad878 Merge branch 'ep93xx-cleanup' into ep93xx-for-next)
+$ git merge ep93xx/ep93xx-for-next
+Already up-to-date!
+Merge made by the 'recursive' strategy.
+Merging renesas/next (45c7a01 Merge branch 'renesas-marzen' into renesas-board)
+$ git merge renesas/next
+Already up-to-date.
+Merging samsung/for-next (c1f9bee Merge branch 'next/board-samsung' into for-next)
+$ git merge samsung/for-next
+Auto-merging include/video/samsung_fimd.h
+Removing arch/arm/plat-samsung/include/plat/regs-fb-v4.h
+Auto-merging arch/arm/plat-samsung/devs.c
+Merge made by the 'recursive' strategy.
+ arch/arm/mach-exynos/clock-exynos5.c               |    9 --
+ arch/arm/mach-exynos/include/mach/map.h            |    1 -
+ arch/arm/mach-exynos/mach-nuri.c                   |    2 +-
+ arch/arm/mach-exynos/mach-origen.c                 |    9 +-
+ arch/arm/mach-exynos/mach-smdk4x12.c               |    2 +-
+ arch/arm/mach-exynos/mach-smdkv310.c               |    9 +-
+ arch/arm/mach-exynos/mach-universal_c210.c         |    2 +-
+ arch/arm/mach-exynos/setup-fimd0.c                 |    2 +-
+ arch/arm/mach-s3c24xx/include/mach/dma.h           |    3 +-
+ arch/arm/mach-s3c24xx/mach-smdk2416.c              |    2 +-
+ arch/arm/mach-s3c64xx/mach-anw6410.c               |    2 +-
+ arch/arm/mach-s3c64xx/mach-crag6410-module.c       |   36 ++++-
+ arch/arm/mach-s3c64xx/mach-crag6410.c              |   14 +-
+ arch/arm/mach-s3c64xx/mach-hmt.c                   |    2 +-
+ arch/arm/mach-s3c64xx/mach-mini6410.c              |    2 +-
+ arch/arm/mach-s3c64xx/mach-ncp.c                   |    2 +-
+ arch/arm/mach-s3c64xx/mach-real6410.c              |    2 +-
+ arch/arm/mach-s3c64xx/mach-smartq5.c               |    2 +-
+ arch/arm/mach-s3c64xx/mach-smartq7.c               |    2 +-
+ arch/arm/mach-s3c64xx/mach-smdk6410.c              |    2 +-
+ arch/arm/mach-s5p64x0/mach-smdk6440.c              |    2 +-
+ arch/arm/mach-s5p64x0/mach-smdk6450.c              |    2 +-
+ arch/arm/mach-s5pc100/mach-smdkc100.c              |    2 +-
+ arch/arm/mach-s5pv210/mach-aquila.c                |    2 +-
+ arch/arm/mach-s5pv210/mach-goni.c                  |    2 +-
+ arch/arm/mach-s5pv210/mach-smdkv210.c              |    2 +-
+ arch/arm/plat-s3c24xx/dma.c                        |    2 +-
+ arch/arm/plat-samsung/devs.c                       |   29 +++-
+ arch/arm/plat-samsung/include/plat/hdmi.h          |   16 ++
+ arch/arm/plat-samsung/include/plat/regs-fb-v4.h    |  159 --------------------
+ arch/arm/plat-samsung/pm.c                         |    2 +-
+ drivers/gpu/drm/exynos/exynos_drm_fimd.c           |    2 +-
+ drivers/video/s3c-fb.c                             |    2 +-
+ .../plat/regs-fb.h => include/video/samsung_fimd.h |  152 +++++++++++++++++--
+ 34 files changed, 270 insertions(+), 213 deletions(-)
+ create mode 100644 arch/arm/plat-samsung/include/plat/hdmi.h
+ delete mode 100644 arch/arm/plat-samsung/include/plat/regs-fb-v4.h
+ rename arch/arm/plat-samsung/include/plat/regs-fb.h => include/video/samsung_fimd.h (73%)
+Merging tegra/for-next (eb9c6a7 Merge branch 'for-3.7/defconfig' into for-next)
+$ git merge tegra/for-next
+Removing arch/arm/mach-tegra/tegra2_clocks.c
+Removing arch/arm/mach-tegra/board-trimslice.h
+Removing arch/arm/mach-tegra/board-trimslice.c
+Removing arch/arm/mach-tegra/board-trimslice-pinmux.c
+Removing arch/arm/mach-tegra/board-paz00-pinmux.c
+Removing arch/arm/boot/dts/tegra30-cardhu.dts
+Auto-merging arch/arm/Kconfig
+Merge made by the 'recursive' strategy.
+ arch/arm/Kconfig                             |    1 +
+ arch/arm/boot/dts/tegra20-paz00.dts          |  173 ++
+ arch/arm/boot/dts/tegra20-seaboard.dts       |  184 ++
+ arch/arm/boot/dts/tegra20-ventana.dts        |  204 ++
+ arch/arm/boot/dts/tegra20-whistler.dts       |  293 +++
+ arch/arm/boot/dts/tegra30-cardhu-a02.dts     |   87 +
+ arch/arm/boot/dts/tegra30-cardhu-a04.dts     |   98 +
+ arch/arm/boot/dts/tegra30-cardhu.dts         |  171 --
+ arch/arm/boot/dts/tegra30-cardhu.dtsi        |  473 +++++
+ arch/arm/configs/tegra_defconfig             |   16 +-
+ arch/arm/mach-tegra/Kconfig                  |   13 -
+ arch/arm/mach-tegra/Makefile                 |   12 +-
+ arch/arm/mach-tegra/Makefile.boot            |    3 +-
+ arch/arm/mach-tegra/apbio.c                  |    4 +-
+ arch/arm/mach-tegra/board-dt-tegra20.c       |   11 +-
+ arch/arm/mach-tegra/board-paz00-pinmux.c     |  156 --
+ arch/arm/mach-tegra/board-paz00.c            |  192 --
+ arch/arm/mach-tegra/board-paz00.h            |   17 +-
+ arch/arm/mach-tegra/board-trimslice-pinmux.c |  155 --
+ arch/arm/mach-tegra/board-trimslice.c        |  183 --
+ arch/arm/mach-tegra/board-trimslice.h        |   30 -
+ arch/arm/mach-tegra/clock.c                  |  574 +-----
+ arch/arm/mach-tegra/clock.h                  |   40 +-
+ arch/arm/mach-tegra/common.c                 |    4 +-
+ arch/arm/mach-tegra/fuse.c                   |    4 +-
+ arch/arm/mach-tegra/headsmp.S                |    6 +-
+ arch/arm/mach-tegra/hotplug.c                |  118 +-
+ arch/arm/mach-tegra/include/mach/clk.h       |    3 +
+ arch/arm/mach-tegra/platsmp.c                |   29 +-
+ arch/arm/mach-tegra/sleep-t20.S              |   82 +
+ arch/arm/mach-tegra/sleep-t30.S              |  107 ++
+ arch/arm/mach-tegra/sleep.S                  |   33 +-
+ arch/arm/mach-tegra/sleep.h                  |   85 +
+ arch/arm/mach-tegra/tegra20_clocks.c         | 1606 ++++++++++++++++
+ arch/arm/mach-tegra/tegra20_clocks.h         |   41 +
+ arch/arm/mach-tegra/tegra20_clocks_data.c    | 1111 +++++++++++
+ arch/arm/mach-tegra/tegra2_clocks.c          | 2484 -------------------------
+ arch/arm/mach-tegra/tegra30_clocks.c         | 2581 +++++++++-----------------
+ arch/arm/mach-tegra/tegra30_clocks.h         |   53 +
+ arch/arm/mach-tegra/tegra30_clocks_data.c    | 1378 ++++++++++++++
+ arch/arm/mach-tegra/tegra_cpu_car.h          |   87 +
+ drivers/i2c/busses/i2c-tegra.c               |   46 +-
+ 42 files changed, 7090 insertions(+), 5858 deletions(-)
+ create mode 100644 arch/arm/boot/dts/tegra30-cardhu-a02.dts
+ create mode 100644 arch/arm/boot/dts/tegra30-cardhu-a04.dts
+ delete mode 100644 arch/arm/boot/dts/tegra30-cardhu.dts
+ create mode 100644 arch/arm/boot/dts/tegra30-cardhu.dtsi
+ delete mode 100644 arch/arm/mach-tegra/board-paz00-pinmux.c
+ delete mode 100644 arch/arm/mach-tegra/board-trimslice-pinmux.c
+ delete mode 100644 arch/arm/mach-tegra/board-trimslice.c
+ delete mode 100644 arch/arm/mach-tegra/board-trimslice.h
+ create mode 100644 arch/arm/mach-tegra/sleep-t20.S
+ create mode 100644 arch/arm/mach-tegra/sleep-t30.S
+ create mode 100644 arch/arm/mach-tegra/sleep.h
+ create mode 100644 arch/arm/mach-tegra/tegra20_clocks.c
+ create mode 100644 arch/arm/mach-tegra/tegra20_clocks.h
+ create mode 100644 arch/arm/mach-tegra/tegra20_clocks_data.c
+ delete mode 100644 arch/arm/mach-tegra/tegra2_clocks.c
+ create mode 100644 arch/arm/mach-tegra/tegra30_clocks.h
+ create mode 100644 arch/arm/mach-tegra/tegra30_clocks_data.c
+ create mode 100644 arch/arm/mach-tegra/tegra_cpu_car.h
+Merging kvmtool/master (3c8ef41 kvm tools: Add 'install' target to Makefile)
+$ git merge kvmtool/master
+Merge made by the 'recursive' strategy.
+ tools/kvm/Makefile       |   14 ++++++++++++++
+ tools/kvm/builtin-run.c  |    7 ++++---
+ tools/kvm/net/uip/dhcp.c |    3 +--
+ tools/kvm/virtio/net.c   |    3 +--
+ 4 files changed, 20 insertions(+), 7 deletions(-)
+Merging dma-mapping/dma-mapping-next (d987569 Linux 3.6-rc2)
+$ git merge dma-mapping/dma-mapping-next
+Already up-to-date.
+Merging pwm/for-next (d767a41 pwm: add devm_pwm_get() and devm_pwm_put())
+$ git merge pwm/for-next
+Merge made by the 'recursive' strategy.
+ Documentation/driver-model/devres.txt |    4 ++
+ Documentation/pwm.txt                 |    3 +-
+ drivers/pwm/Kconfig                   |   31 ++++++++---
+ drivers/pwm/core.c                    |   92 ++++++++++++++++++++++++++++++---
+ drivers/pwm/pwm-samsung.c             |    1 +
+ drivers/pwm/pwm-tegra.c               |    4 +-
+ drivers/pwm/pwm-tiecap.c              |    4 +-
+ drivers/pwm/pwm-tiehrpwm.c            |    4 +-
+ drivers/pwm/pwm-vt8500.c              |    2 +-
+ include/linux/pwm.h                   |   26 ++++++++++
+ 10 files changed, 148 insertions(+), 23 deletions(-)
+Merging dma-buf/for-next (42a579a Merge branches 'timers-urgent-for-linus' and 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip)
+$ git merge dma-buf/for-next
+Already up-to-date.
+Merging userns/for-next (898132a ipv6: move dereference after check in fl_free())
+$ git merge userns/for-next
+Auto-merging net/sctp/proc.c
+Auto-merging net/packet/af_packet.c
+Auto-merging net/key/af_key.c
+Auto-merging net/ipv6/tcp_ipv6.c
+Auto-merging net/ipv4/udp.c
+Auto-merging net/ipv4/tcp_ipv4.c
+Auto-merging net/core/sock.c
+Auto-merging net/core/scm.c
+Auto-merging net/core/dev.c
+Auto-merging init/Kconfig
+Auto-merging include/net/tcp.h
+Auto-merging include/net/sock.h
+Auto-merging include/net/ipv6.h
+Auto-merging fs/namei.c
+Auto-merging drivers/net/tun.c
+Merge made by the 'recursive' strategy.
+ drivers/net/tun.c             |   46 +++++++++++++++++++++++++++------------
+ drivers/net/wireless/airo.c   |   48 ++++++++++++++++++++++++-----------------
+ fs/namei.c                    |    6 +++---
+ fs/seq_file.c                 |    4 ++++
+ include/linux/inet_diag.h     |    1 +
+ include/linux/netlink.h       |    1 +
+ include/linux/seq_file.h      |   14 ++++++++++++
+ include/net/ax25.h            |    4 ++--
+ include/net/ipv6.h            |    5 ++++-
+ include/net/netns/ipv4.h      |    3 ++-
+ include/net/sch_generic.h     |    3 ++-
+ include/net/sock.h            |   11 +++++++++-
+ include/net/tcp.h             |    3 ++-
+ init/Kconfig                  |   19 ----------------
+ kernel/pid.c                  |    1 +
+ kernel/pid_namespace.c        |    2 ++
+ net/appletalk/atalk_proc.c    |    3 ++-
+ net/ax25/ax25_uid.c           |   21 ++++++++++++------
+ net/core/dev.c                |    7 +++---
+ net/core/scm.c                |   31 +++++++++++++++++++-------
+ net/core/sock.c               |   10 ++++-----
+ net/ipv4/inet_diag.c          |   21 ++++++++++++------
+ net/ipv4/ping.c               |   22 ++++++++-----------
+ net/ipv4/raw.c                |    4 +++-
+ net/ipv4/sysctl_net_ipv4.c    |   42 +++++++++++++++++++++++-------------
+ net/ipv4/tcp_ipv4.c           |    6 +++---
+ net/ipv4/udp.c                |    4 +++-
+ net/ipv4/udp_diag.c           |    5 ++++-
+ net/ipv6/ip6_flowlabel.c      |   47 ++++++++++++++++++++++++++++++++++------
+ net/ipv6/raw.c                |    3 ++-
+ net/ipv6/tcp_ipv6.c           |    6 +++---
+ net/ipv6/udp.c                |    3 ++-
+ net/ipx/ipx_proc.c            |    3 ++-
+ net/key/af_key.c              |    2 +-
+ net/llc/llc_proc.c            |    2 +-
+ net/netfilter/nfnetlink_log.c |   14 ++++++++----
+ net/netfilter/xt_LOG.c        |   16 ++++++++------
+ net/netfilter/xt_owner.c      |   30 ++++++++++++++++++++------
+ net/netfilter/xt_recent.c     |   13 +++++++++--
+ net/netlink/af_netlink.c      |    6 ++++--
+ net/packet/af_packet.c        |    2 +-
+ net/phonet/socket.c           |    6 ++++--
+ net/sched/cls_api.c           |    2 +-
+ net/sched/cls_basic.c         |    3 ++-
+ net/sched/cls_cgroup.c        |    3 ++-
+ net/sched/cls_flow.c          |   19 +++++++++++-----
+ net/sched/cls_fw.c            |    3 ++-
+ net/sched/cls_route.c         |    3 ++-
+ net/sched/cls_rsvp.h          |    3 ++-
+ net/sched/cls_tcindex.c       |    3 ++-
+ net/sched/cls_u32.c           |    3 ++-
+ net/sctp/proc.c               |    6 ++++--
+ 52 files changed, 368 insertions(+), 180 deletions(-)
+Merging ktest/for-next (648a182 ktest: Allow a test to override REBOOT_ON_SUCCESS)
+$ git merge ktest/for-next
+Already up-to-date.
+Merging signal/from-sfr (2e117f2 Revert "arm: pull all work_pending logics into C function")
+$ git merge signal/from-sfr
+Resolved 'arch/arm/include/asm/thread_info.h' using previous resolution.
+Resolved 'arch/powerpc/kernel/entry_64.S' using previous resolution.
+Resolved 'arch/x86/kernel/signal.c' using previous resolution.
+Auto-merging kernel/timer.c
+Auto-merging kernel/sched/core.c
+Auto-merging arch/xtensa/kernel/signal.c
+Auto-merging arch/x86/kernel/vm86_32.c
+Auto-merging arch/x86/kernel/signal.c
+CONFLICT (content): Merge conflict in arch/x86/kernel/signal.c
+Auto-merging arch/x86/kernel/process.c
+Auto-merging arch/x86/include/asm/thread_info.h
+Auto-merging arch/sh/kernel/cpu/sh5/entry.S
+Auto-merging arch/s390/include/asm/thread_info.h
+Auto-merging arch/powerpc/kernel/entry_64.S
+CONFLICT (content): Merge conflict in arch/powerpc/kernel/entry_64.S
+Auto-merging arch/powerpc/include/asm/thread_info.h
+Auto-merging arch/mn10300/kernel/signal.c
+Auto-merging arch/mn10300/include/asm/thread_info.h
+Auto-merging arch/mips/kernel/scall64-o32.S
+Auto-merging arch/mips/kernel/scall64-n32.S
+Auto-merging arch/mips/kernel/scall64-64.S
+Auto-merging arch/mips/kernel/scall32-o32.S
+Auto-merging arch/mips/include/asm/thread_info.h
+Auto-merging arch/m32r/kernel/signal.c
+Auto-merging arch/h8300/kernel/signal.c
+Auto-merging arch/frv/kernel/signal.c
+Auto-merging arch/avr32/kernel/signal.c
+Auto-merging arch/arm/kernel/signal.c
+Auto-merging arch/arm/include/asm/thread_info.h
+CONFLICT (content): Merge conflict in arch/arm/include/asm/thread_info.h
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master cf1f6ba] Merge branch 'signal/from-sfr'
+$ git diff -M --stat --summary HEAD^..
+ arch/alpha/include/asm/ptrace.h           |    5 +-
+ arch/alpha/include/asm/thread_info.h      |    3 +-
+ arch/alpha/kernel/alpha_ksyms.c           |    1 -
+ arch/alpha/kernel/entry.S                 |  161 -----------------------------
+ arch/alpha/kernel/osf_sys.c               |   49 +++++++++
+ arch/alpha/kernel/process.c               |   29 ++++++
+ arch/alpha/kernel/systbls.S               |    2 +-
+ arch/arm/include/asm/thread_info.h        |    2 -
+ arch/arm/kernel/signal.c                  |    1 -
+ arch/avr32/include/asm/thread_info.h      |   17 +--
+ arch/avr32/kernel/signal.c                |    1 -
+ arch/blackfin/include/asm/thread_info.h   |    4 -
+ arch/blackfin/kernel/signal.c             |    1 -
+ arch/c6x/include/asm/thread_info.h        |    1 -
+ arch/c6x/kernel/asm-offsets.c             |    1 -
+ arch/cris/include/asm/thread_info.h       |    3 -
+ arch/frv/include/asm/thread_info.h        |    3 -
+ arch/frv/kernel/signal.c                  |    9 --
+ arch/h8300/include/asm/thread_info.h      |    7 +-
+ arch/h8300/kernel/signal.c                |    1 -
+ arch/hexagon/include/asm/thread_info.h    |    5 -
+ arch/hexagon/kernel/signal.c              |    1 -
+ arch/ia64/include/asm/thread_info.h       |    2 -
+ arch/ia64/kernel/signal.c                 |    8 --
+ arch/m32r/include/asm/thread_info.h       |    9 +-
+ arch/m32r/kernel/signal.c                 |    3 -
+ arch/microblaze/include/asm/thread_info.h |    3 +-
+ arch/microblaze/kernel/entry-nommu.S      |   21 +++-
+ arch/microblaze/kernel/entry.S            |   62 ++++++-----
+ arch/microblaze/kernel/signal.c           |   16 +--
+ arch/mips/include/asm/thread_info.h       |    9 +-
+ arch/mips/kernel/entry.S                  |   15 ++-
+ arch/mips/kernel/scall32-o32.S            |   13 +--
+ arch/mips/kernel/scall64-64.S             |   13 +--
+ arch/mips/kernel/scall64-n32.S            |   13 +--
+ arch/mips/kernel/scall64-o32.S            |   13 +--
+ arch/mips/kernel/signal.c                 |    8 --
+ arch/mn10300/include/asm/thread_info.h    |    3 +-
+ arch/mn10300/kernel/entry.S               |    4 +
+ arch/mn10300/kernel/signal.c              |    9 --
+ arch/openrisc/include/asm/thread_info.h   |    3 +-
+ arch/parisc/hpux/gate.S                   |    2 +-
+ arch/parisc/include/asm/thread_info.h     |    5 +-
+ arch/parisc/kernel/signal.c               |   45 +++-----
+ arch/parisc/kernel/syscall.S              |    9 +-
+ arch/powerpc/include/asm/thread_info.h    |    2 +
+ arch/powerpc/kernel/signal_32.c           |    1 -
+ arch/s390/include/asm/thread_info.h       |    4 -
+ arch/score/include/asm/thread_info.h      |    4 -
+ arch/score/kernel/signal.c                |    1 +
+ arch/sh/include/asm/thread_info.h         |    3 +
+ arch/sh/kernel/cpu/sh5/entry.S            |    2 +-
+ arch/sh/kernel/entry-common.S             |    2 +-
+ arch/sh/kernel/signal_32.c                |    1 -
+ arch/sh/kernel/signal_64.c                |    1 -
+ arch/sparc/include/asm/thread_info_32.h   |    3 +-
+ arch/sparc/include/asm/thread_info_64.h   |    3 +
+ arch/tile/kernel/compat_signal.c          |    9 --
+ arch/tile/kernel/signal.c                 |   12 +--
+ arch/um/include/asm/thread_info.h         |    3 -
+ arch/unicore32/include/asm/thread_info.h  |    4 +-
+ arch/unicore32/kernel/entry.S             |    2 -
+ arch/unicore32/kernel/signal.c            |    1 -
+ arch/x86/include/asm/thread_info.h        |    2 -
+ arch/x86/kernel/entry_32.S                |   17 ++-
+ arch/x86/kernel/process.c                 |    2 +-
+ arch/x86/kernel/signal.c                  |    4 -
+ arch/x86/kernel/vm86_32.c                 |    2 +-
+ arch/xtensa/include/asm/thread_info.h     |    5 -
+ arch/xtensa/kernel/signal.c               |    4 -
+ kernel/sched/core.c                       |    2 +-
+ kernel/timer.c                            |    9 --
+ 72 files changed, 227 insertions(+), 473 deletions(-)
+Merging clk/clk-next (137f8a7 clk: fix compile for OF && !COMMON_CLK)
+$ git merge clk/clk-next
+Already up-to-date.
+Merging random/dev (d2e7c96 random: mix in architectural randomness in extract_buf())
+$ git merge random/dev
+Already up-to-date.
+Merging scsi-post-merge/merge-base:master ()
+$ git clone -s -l -n -q . ../rebase-tmp
+$ cd ../rebase-tmp
+$ git fetch --no-tags ../next refs/heads/akpm/master:akpm
+From ../next
+ * [new branch]      akpm/master -> akpm
+$ git fetch --no-tags ../next refs/heads/akpm/base:akpm-base
+From ../next
+ * [new branch]      akpm/base  -> akpm-base
+$ git checkout akpm
+Switched to branch 'akpm'
+$ git rebase --onto master akpm-base
+First, rewinding head to replay your work on top of it...
+Applying: cs5535-clockevt: typo, it's MFGPT, not MFPGT
+Applying: mm: change nr_ptes BUG_ON to WARN_ON
+Applying: Documentation: update mount option in filesystem/vfat.txt
+Applying: cciss: fix incorrect scsi status reporting
+Applying: acpi_memhotplug.c: fix memory leak when memory device is unbound from the module acpi_memhotplug
+Applying: acpi_memhotplug.c: free memory device if acpi_memory_enable_device() failed
+Applying: acpi_memhotplug.c: remove memory info from list before freeing it
+Applying: acpi_memhotplug.c: don't allow to eject the memory device if it is being used
+Applying: acpi_memhotplug.c: bind the memory device when the driver is being loaded
+Applying: acpi_memhotplug.c: auto bind the memory device which is hotplugged before the driver is loaded
+Applying: arch/x86/platform/iris/iris.c: register a platform device and a platform driver
+Applying: arch/x86/include/asm/spinlock.h: fix comment
+Applying: mn10300: only add -mmem-funcs to KBUILD_CFLAGS if gcc supports it
+Applying: drivers/dma/dmaengine.c: lower the priority of 'failed to get' dma channel message
+Applying: pcmcia: move unbind/rebind into dev_pm_ops.complete
+Applying: timeconst.pl: remove deprecated defined(@array)
+Applying: time: don't inline EXPORT_SYMBOL functions
+Applying: thermal: add generic cpufreq cooling implementation
+Applying: hwmon: exynos4: move thermal sensor driver to driver/thermal directory
+Applying: thermal: exynos5: add exynos5 thermal sensor driver support
+Applying: thermal: exynos: register the tmu sensor with the kernel thermal layer
+Applying: ARM: exynos: add thermal sensor driver platform data support
+Applying: drivers/scsi/atp870u.c: fix bad use of udelay
+Applying: vfs: increment iversion when a file is truncated
+Applying: fs: push rcu_barrier() from deactivate_locked_super() to filesystems
+Applying: mm/slab: remove duplicate check
+Applying: mm: remove __GFP_NO_KSWAPD
+Applying: mm: remove __GFP_NO_KSWAPD fixes
+Applying: remove-__gfp_no_kswapd-fixes-fix
+Applying: x86, pat: remove the dependency on 'vm_pgoff' in track/untrack pfn vma routines
+Applying: x86, pat: separate the pfn attribute tracking for remap_pfn_range and vm_insert_pfn
+Applying: x86-pat-separate-the-pfn-attribute-tracking-for-remap_pfn_range-and-vm_insert_pfn-fix
+Applying: mm, x86, pat: rework linear pfn-mmap tracking
+Applying: mm: introduce arch-specific vma flag VM_ARCH_1
+Applying: mm: kill vma flag VM_INSERTPAGE
+Applying: mm: kill vma flag VM_CAN_NONLINEAR
+Applying: mm: use mm->exe_file instead of first VM_EXECUTABLE vma->vm_file
+Applying: mm: kill vma flag VM_EXECUTABLE and mm->num_exe_file_vmas
+Applying: mm: prepare VM_DONTDUMP for using in drivers
+Applying: mm: kill vma flag VM_RESERVED and mm->reserved_vm counter
+Using index info to reconstruct a base tree...
+A	drivers/media/video/meye.c
+A	drivers/media/video/omap/omap_vout.c
+A	drivers/media/video/sn9c102/sn9c102_core.c
+A	drivers/media/video/usbvision/usbvision-video.c
+A	drivers/media/video/videobuf-dma-sg.c
+A	drivers/media/video/videobuf-vmalloc.c
+A	drivers/media/video/videobuf2-memops.c
+A	drivers/media/video/vino.c
+Falling back to patching base and 3-way merge...
+Auto-merging drivers/media/v4l2-core/videobuf2-memops.c
+Auto-merging drivers/media/v4l2-core/videobuf-vmalloc.c
+Auto-merging drivers/media/v4l2-core/videobuf-dma-sg.c
+Auto-merging drivers/media/usb/usbvision/usbvision-video.c
+Auto-merging drivers/media/usb/sn9c102/sn9c102_core.c
+Auto-merging drivers/media/platform/vino.c
+Auto-merging drivers/media/platform/omap/omap_vout.c
+Auto-merging drivers/media/pci/meye/meye.c
+Applying: mm-kill-vma-flag-vm_reserved-and-mm-reserved_vm-counter-fix
+Applying: frv: kill used but uninitialized variable
+Applying: ipc/mqueue: remove unnecessary rb_init_node() calls
+Applying: rbtree: reference Documentation/rbtree.txt for usage instructions
+Applying: rbtree: empty nodes have no color
+Applying: rbtree-empty-nodes-have-no-color-fix
+Applying: rbtree: fix incorrect rbtree node insertion in fs/proc/proc_sysctl.c
+Applying: rbtree: move some implementation details from rbtree.h to rbtree.c
+Applying: rbtree: fix jffs2 build issue due to renamed __rb_parent_color field
+Applying: rbtree: performance and correctness test
+Applying: rbtree-performance-and-correctness-test-fix
+Applying: rbtree: break out of rb_insert_color loop after tree rotation
+Applying: rbtree: adjust root color in rb_insert_color() only when necessary
+Applying: rbtree: low level optimizations in rb_insert_color()
+Applying: rbtree: adjust node color in __rb_erase_color() only when necessary
+Applying: rbtree: optimize case selection logic in __rb_erase_color()
+Applying: rbtree: low level optimizations in __rb_erase_color()
+Applying: rbtree: coding style adjustments
+Applying: rbtree: rb_erase updates and comments
+Applying: rbtree: optimize fetching of sibling node
+Applying: drivers/firmware/dmi_scan.c: check dmi version when get system uuid
+Applying: drivers-firmware-dmi_scanc-check-dmi-version-when-get-system-uuid-fix
+Applying: drivers/firmware/dmi_scan.c: fetch dmi version from SMBIOS if it exists
+Applying: drivers-firmware-dmi_scanc-fetch-dmi-version-from-smbios-if-it-exists-checkpatch-fixes
+Applying: fat (exportfs): move NFS support code
+Applying: fat (exportfs): fix dentry reconnection
+Applying: ipc/sem.c: alternatives to preempt_disable()
+$ cd ../next
+$ git fetch -f ../rebase-tmp akpm:akpm/master
+From ../rebase-tmp
+ + a96005b...5fb158a akpm       -> akpm/master  (forced update)
+$ rm -rf ../rebase-tmp
+Merging akpm/master (5fb158a ipc/sem.c: alternatives to preempt_disable())
+$ git merge --no-ff akpm/master
+Auto-merging include/linux/platform_data/exynos_thermal.h
+Removing drivers/hwmon/exynos4_tmu.c
+Auto-merging Documentation/thermal/exynos_thermal
+Merge made by the 'recursive' strategy.
+ Documentation/filesystems/vfat.txt                 |   11 +
+ Documentation/thermal/cpu-cooling-api.txt          |   60 ++
+ .../{hwmon/exynos4_tmu => thermal/exynos_thermal}  |   35 +-
+ Documentation/vm/unevictable-lru.txt               |    4 +-
+ arch/alpha/kernel/pci-sysfs.c                      |    2 +-
+ arch/frv/kernel/pm.c                               |   19 +-
+ arch/ia64/kernel/perfmon.c                         |    2 +-
+ arch/ia64/mm/init.c                                |    3 +-
+ arch/mn10300/Makefile                              |    2 +-
+ arch/powerpc/kvm/book3s_hv.c                       |    2 +-
+ arch/powerpc/oprofile/cell/spu_task_sync.c         |   15 +-
+ arch/sparc/kernel/pci.c                            |    2 +-
+ arch/tile/mm/elf.c                                 |   19 +-
+ arch/unicore32/kernel/process.c                    |    2 +-
+ arch/x86/include/asm/spinlock.h                    |    3 +-
+ arch/x86/mm/pat.c                                  |   87 +-
+ arch/x86/platform/iris/iris.c                      |   67 +-
+ arch/x86/xen/mmu.c                                 |    3 +-
+ drivers/acpi/acpi_memhotplug.c                     |  123 ++-
+ drivers/block/cciss_scsi.c                         |   11 +-
+ drivers/char/mbcs.c                                |    2 +-
+ drivers/char/mem.c                                 |    2 +-
+ drivers/char/mspec.c                               |    2 +-
+ drivers/clocksource/cs5535-clockevt.c              |    4 +-
+ drivers/dma/dmaengine.c                            |    2 +-
+ drivers/firmware/dmi_scan.c                        |   78 +-
+ drivers/gpu/drm/drm_gem.c                          |    2 +-
+ drivers/gpu/drm/drm_vm.c                           |   10 +-
+ drivers/gpu/drm/exynos/exynos_drm_gem.c            |    2 +-
+ drivers/gpu/drm/gma500/framebuffer.c               |    3 +-
+ drivers/gpu/drm/ttm/ttm_bo_vm.c                    |    4 +-
+ drivers/gpu/drm/udl/udl_fb.c                       |    2 +-
+ drivers/hwmon/Kconfig                              |   10 -
+ drivers/hwmon/Makefile                             |    1 -
+ drivers/hwmon/exynos4_tmu.c                        |  518 -----------
+ drivers/infiniband/hw/ehca/ehca_uverbs.c           |    4 +-
+ drivers/infiniband/hw/ipath/ipath_file_ops.c       |    2 +-
+ drivers/infiniband/hw/qib/qib_file_ops.c           |    2 +-
+ drivers/media/pci/meye/meye.c                      |    2 +-
+ drivers/media/platform/omap/omap_vout.c            |    2 +-
+ drivers/media/platform/vino.c                      |    2 +-
+ drivers/media/usb/sn9c102/sn9c102_core.c           |    3 +-
+ drivers/media/usb/usbvision/usbvision-video.c      |    3 +-
+ drivers/media/v4l2-core/videobuf-dma-sg.c          |    2 +-
+ drivers/media/v4l2-core/videobuf-vmalloc.c         |    2 +-
+ drivers/media/v4l2-core/videobuf2-memops.c         |    2 +-
+ drivers/misc/carma/carma-fpga.c                    |    2 -
+ drivers/misc/sgi-gru/grufile.c                     |    5 +-
+ drivers/mtd/mtdchar.c                              |    2 +-
+ drivers/mtd/mtdcore.c                              |    6 +-
+ drivers/oprofile/buffer_sync.c                     |   17 +-
+ drivers/pcmcia/cs.c                                |   37 +-
+ drivers/scsi/atp870u.c                             |   11 +-
+ drivers/scsi/sg.c                                  |    2 +-
+ drivers/staging/android/ashmem.c                   |    1 -
+ drivers/staging/omapdrm/omap_gem_dmabuf.c          |    2 +-
+ drivers/staging/tidspbridge/rmgr/drv_interface.c   |    2 +-
+ drivers/thermal/Kconfig                            |   20 +
+ drivers/thermal/Makefile                           |    4 +-
+ drivers/thermal/cpu_cooling.c                      |  483 ++++++++++
+ drivers/thermal/exynos_thermal.c                   |  960 ++++++++++++++++++++
+ drivers/uio/uio.c                                  |    4 +-
+ drivers/usb/mon/mon_bin.c                          |    2 +-
+ drivers/vfio/pci/vfio_pci.c                        |    2 +-
+ drivers/video/68328fb.c                            |    2 +-
+ drivers/video/aty/atyfb_base.c                     |    3 +-
+ drivers/video/fb-puv3.c                            |    3 +-
+ drivers/video/fb_defio.c                           |    2 +-
+ drivers/video/fbmem.c                              |    3 +-
+ drivers/video/gbefb.c                              |    2 +-
+ drivers/video/omap2/omapfb/omapfb-main.c           |    2 +-
+ drivers/video/sbuslib.c                            |    5 +-
+ drivers/video/smscufx.c                            |    1 -
+ drivers/video/udlfb.c                              |    1 -
+ drivers/video/vermilion/vermilion.c                |    1 -
+ drivers/video/vfb.c                                |    1 -
+ drivers/xen/gntalloc.c                             |    2 +-
+ drivers/xen/gntdev.c                               |    2 +-
+ drivers/xen/privcmd.c                              |    3 +-
+ fs/9p/v9fs.c                                       |    5 +
+ fs/9p/vfs_file.c                                   |    1 +
+ fs/adfs/super.c                                    |    5 +
+ fs/affs/super.c                                    |    5 +
+ fs/afs/super.c                                     |    5 +
+ fs/attr.c                                          |    5 +
+ fs/befs/linuxvfs.c                                 |    5 +
+ fs/bfs/inode.c                                     |    5 +
+ fs/binfmt_elf.c                                    |    4 +-
+ fs/binfmt_elf_fdpic.c                              |    2 +-
+ fs/btrfs/extent_io.c                               |    6 +
+ fs/btrfs/file.c                                    |    2 +-
+ fs/btrfs/inode.c                                   |    5 +
+ fs/ceph/addr.c                                     |    2 +-
+ fs/ceph/super.c                                    |    5 +
+ fs/cifs/cifsfs.c                                   |    5 +
+ fs/cifs/file.c                                     |    1 +
+ fs/coda/inode.c                                    |    5 +
+ fs/ecryptfs/main.c                                 |    6 +
+ fs/efs/super.c                                     |    5 +
+ fs/exofs/super.c                                   |    5 +
+ fs/ext2/super.c                                    |    5 +
+ fs/ext3/super.c                                    |    5 +
+ fs/ext4/file.c                                     |    2 +-
+ fs/ext4/super.c                                    |    5 +
+ fs/fat/Makefile                                    |    2 +-
+ fs/fat/dir.c                                       |   20 +-
+ fs/fat/fat.h                                       |   23 +-
+ fs/fat/inode.c                                     |  178 ++--
+ fs/fat/namei_msdos.c                               |    5 +-
+ fs/fat/namei_vfat.c                                |    5 +-
+ fs/fat/nfs.c                                       |  101 ++
+ fs/freevxfs/vxfs_super.c                           |    5 +
+ fs/fuse/file.c                                     |    1 +
+ fs/fuse/inode.c                                    |    6 +
+ fs/gfs2/file.c                                     |    2 +-
+ fs/hfs/super.c                                     |    6 +
+ fs/hfsplus/super.c                                 |    6 +
+ fs/hpfs/super.c                                    |    5 +
+ fs/hugetlbfs/inode.c                               |    7 +-
+ fs/isofs/inode.c                                   |    5 +
+ fs/jffs2/readinode.c                               |   13 +-
+ fs/jffs2/super.c                                   |    6 +
+ fs/jfs/super.c                                     |    6 +
+ fs/logfs/inode.c                                   |    5 +
+ fs/minix/inode.c                                   |    5 +
+ fs/ncpfs/inode.c                                   |    5 +
+ fs/nfs/file.c                                      |    1 +
+ fs/nfs/inode.c                                     |    5 +
+ fs/nilfs2/file.c                                   |    2 +-
+ fs/nilfs2/super.c                                  |    6 +
+ fs/ntfs/super.c                                    |    6 +
+ fs/ocfs2/dlmfs/dlmfs.c                             |    5 +
+ fs/ocfs2/mmap.c                                    |    2 +-
+ fs/ocfs2/super.c                                   |    5 +
+ fs/openpromfs/inode.c                              |    5 +
+ fs/proc/proc_sysctl.c                              |    5 +-
+ fs/proc/task_mmu.c                                 |    2 +-
+ fs/qnx4/inode.c                                    |    5 +
+ fs/qnx6/inode.c                                    |    5 +
+ fs/reiserfs/super.c                                |    5 +
+ fs/romfs/super.c                                   |    5 +
+ fs/squashfs/super.c                                |    5 +
+ fs/super.c                                         |    6 -
+ fs/sysv/inode.c                                    |    5 +
+ fs/ubifs/file.c                                    |    1 +
+ fs/ubifs/super.c                                   |    6 +
+ fs/udf/super.c                                     |    5 +
+ fs/ufs/super.c                                     |    5 +
+ fs/xfs/xfs_file.c                                  |    2 +-
+ fs/xfs/xfs_super.c                                 |    5 +
+ include/asm-generic/pgtable.h                      |   57 +-
+ include/linux/cpu_cooling.h                        |   99 ++
+ include/linux/fs.h                                 |    2 +
+ include/linux/gfp.h                                |    5 +-
+ include/linux/mempolicy.h                          |    2 +-
+ include/linux/mm.h                                 |   69 +-
+ include/linux/mm_types.h                           |    2 -
+ include/linux/mman.h                               |    1 -
+ .../{exynos4_tmu.h => exynos_thermal.h}            |   31 +-
+ include/linux/rbtree.h                             |  112 +--
+ include/linux/timerqueue.h                         |    2 +-
+ include/trace/events/gfpflags.h                    |    1 -
+ ipc/mqueue.c                                       |    3 -
+ ipc/sem.c                                          |  250 +++--
+ kernel/auditsc.c                                   |   13 +-
+ kernel/events/core.c                               |    2 +-
+ kernel/fork.c                                      |   24 +-
+ kernel/time.c                                      |    4 +-
+ kernel/timeconst.pl                                |    2 +-
+ lib/Kconfig.debug                                  |    7 +
+ lib/Makefile                                       |    2 +
+ lib/rbtree.c                                       |  597 +++++++-----
+ lib/rbtree_test.c                                  |  135 +++
+ mm/filemap.c                                       |    2 +-
+ mm/filemap_xip.c                                   |    3 +-
+ mm/fremap.c                                        |   14 +-
+ mm/huge_memory.c                                   |   22 +-
+ mm/ksm.c                                           |    8 +-
+ mm/madvise.c                                       |    8 +-
+ mm/memory.c                                        |   62 +-
+ mm/mlock.c                                         |    2 +-
+ mm/mmap.c                                          |   34 +-
+ mm/nommu.c                                         |   21 +-
+ mm/page_alloc.c                                    |   10 +-
+ mm/shmem.c                                         |    3 +-
+ mm/vmalloc.c                                       |    3 +-
+ net/ceph/osd_client.c                              |    1 -
+ security/selinux/selinuxfs.c                       |    2 +-
+ security/tomoyo/util.c                             |    9 +-
+ sound/core/pcm_native.c                            |    6 +-
+ sound/usb/usx2y/us122l.c                           |    2 +-
+ sound/usb/usx2y/usX2Yhwdep.c                       |    2 +-
+ sound/usb/usx2y/usx2yhwdeppcm.c                    |    2 +-
+ 193 files changed, 3400 insertions(+), 1600 deletions(-)
+ create mode 100644 Documentation/thermal/cpu-cooling-api.txt
+ rename Documentation/{hwmon/exynos4_tmu => thermal/exynos_thermal} (71%)
+ delete mode 100644 drivers/hwmon/exynos4_tmu.c
+ create mode 100644 drivers/thermal/cpu_cooling.c
+ create mode 100644 drivers/thermal/exynos_thermal.c
+ create mode 100644 fs/fat/nfs.c
+ create mode 100644 include/linux/cpu_cooling.h
+ rename include/linux/platform_data/{exynos4_tmu.h => exynos_thermal.h} (74%)
+ create mode 100644 lib/rbtree_test.c
diff --git a/Next/quilt-import.log b/Next/quilt-import.log
new file mode 100644
index 0000000..6bc648e
--- /dev/null
+++ b/Next/quilt-import.log
@@ -0,0 +1,17 @@
+Importing i2c based on e7882d6c40874a5b5033ca85f7508a602a60b662
+Unchanged quilt series i2c
+Importing jdelvare-hwmon based on e7882d6c40874a5b5033ca85f7508a602a60b662
+Unchanged quilt series jdelvare-hwmon
+Importing rr based on v3.5-8192-g1fad1e9
+Unchanged quilt series rr
+Importing device-mapper based on v3.6-rc1
+$ git clone -s -l -n -q . ../quilt-tmp
+$ cd ../quilt-tmp
+$ git reset --hard 0d7614f09c1ebdbaa1599a5aba7593f147bf96ee
+HEAD is now at 0d7614f Linux 3.6-rc1
+$ git am ../quilt/device-mapper/dm-verity-fix-overflow-check.patch
+Applying: Overflow checking in dm-verity was not sufficient.
+$ cd ../next
+$ git fetch -f ../quilt-tmp master:quilt/device-mapper
+From ../quilt-tmp
+   0d7614f..057d040  master     -> quilt/device-mapper
diff --git a/arch/Kconfig b/arch/Kconfig
index 72f2fa1..0e26d74 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -281,4 +281,33 @@ config SECCOMP_FILTER
 
 	  See Documentation/prctl/seccomp_filter.txt for details.
 
+config HAVE_MOD_ARCH_SPECIFIC
+	bool
+	help
+	  The arch uses struct mod_arch_specific to store data.  Many arches
+	  just need a simple module loader without arch specific data - those
+	  should not enable this.
+
+config MODULES_USE_ELF_RELA
+	bool
+	help
+	  Modules only use ELF RELA relocations.  Modules with ELF REL
+	  relocations will give an error.
+
+config MODULES_USE_ELF_REL
+	bool
+	help
+	  Modules only use ELF REL relocations.  Modules with ELF RELA
+	  relocations will give an error.
+
+config HAVE_RCU_USER_QS
+	bool
+	help
+	  Provide kernel entry/exit hooks necessary for userspace
+	  RCU extended quiescent state. Syscalls need to be wrapped inside
+	  rcu_user_exit()-rcu_user_enter() through the slow path using
+	  TIF_NOHZ flag. Exceptions handlers must be wrapped as well. Irqs
+	  are already protected inside rcu_irq_enter/rcu_irq_exit() but
+	  preemption or signal handling on irq exit still need to be protected.
+
 source "kernel/gcov/Kconfig"
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index d5b9b5e..e73a1a7 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -18,6 +18,8 @@ config ALPHA
 	select ARCH_HAVE_NMI_SAFE_CMPXCHG
 	select GENERIC_SMP_IDLE_THREAD
 	select GENERIC_CMOS_UPDATE
+	select HAVE_MOD_ARCH_SPECIFIC
+	select MODULES_USE_ELF_RELA
 	help
 	  The Alpha is a 64-bit general-purpose processor designed and
 	  marketed by the Digital Equipment Corporation of blessed memory,
diff --git a/arch/alpha/include/asm/module.h b/arch/alpha/include/asm/module.h
index 7b63743..9cd13b5 100644
--- a/arch/alpha/include/asm/module.h
+++ b/arch/alpha/include/asm/module.h
@@ -1,19 +1,13 @@
 #ifndef _ALPHA_MODULE_H
 #define _ALPHA_MODULE_H
 
+#include <asm-generic/module.h>
+
 struct mod_arch_specific
 {
 	unsigned int gotsecindex;
 };
 
-#define Elf_Sym Elf64_Sym
-#define Elf_Shdr Elf64_Shdr
-#define Elf_Ehdr Elf64_Ehdr
-#define Elf_Phdr Elf64_Phdr
-#define Elf_Dyn Elf64_Dyn
-#define Elf_Rel Elf64_Rel
-#define Elf_Rela Elf64_Rela
-
 #define ARCH_SHF_SMALL SHF_ALPHA_GPREL
 
 #ifdef MODULE
diff --git a/arch/alpha/include/asm/ptrace.h b/arch/alpha/include/asm/ptrace.h
index fd698a1..b87755a 100644
--- a/arch/alpha/include/asm/ptrace.h
+++ b/arch/alpha/include/asm/ptrace.h
@@ -76,7 +76,10 @@ struct switch_stack {
 #define task_pt_regs(task) \
   ((struct pt_regs *) (task_stack_page(task) + 2*PAGE_SIZE) - 1)
 
-#define force_successful_syscall_return() (task_pt_regs(current)->r0 = 0)
+#define current_pt_regs() \
+  ((struct pt_regs *) ((char *)current_thread_info() + 2*PAGE_SIZE) - 1)
+
+#define force_successful_syscall_return() (current_pt_regs()->r0 = 0)
 
 #endif
 
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h
index 28335bd..4554ecb 100644
--- a/arch/alpha/include/asm/thread_info.h
+++ b/arch/alpha/include/asm/thread_info.h
@@ -84,7 +84,6 @@ register struct thread_info *__current_thread_info __asm__("$8");
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 
 /* Work to do on interrupt/exception return.  */
@@ -117,5 +116,7 @@ register struct thread_info *__current_thread_info __asm__("$8");
 		 (int __user *)(value));				\
 	})
 
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
 #endif /* __KERNEL__ */
 #endif /* _ALPHA_THREAD_INFO_H */
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index d96e742..b77b813 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -52,7 +52,6 @@ EXPORT_SYMBOL(alpha_write_fp_reg_s);
 
 /* entry.S */
 EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(kernel_execve);
 
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_tcpudp_magic);
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index 6d159ce..ec0da05 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -663,58 +663,6 @@ kernel_thread:
 	br	ret_to_kernel
 .end kernel_thread
 
-/*
- * kernel_execve(path, argv, envp)
- */
-	.align	4
-	.globl	kernel_execve
-	.ent	kernel_execve
-kernel_execve:
-	/* We can be called from a module.  */
-	ldgp	$gp, 0($27)
-	lda	$sp, -(32+SIZEOF_PT_REGS+8)($sp)
-	.frame	$sp, 32+SIZEOF_PT_REGS+8, $26, 0
-	stq	$26, 0($sp)
-	stq	$16, 8($sp)
-	stq	$17, 16($sp)
-	stq	$18, 24($sp)
-	.prologue 1
-
-	lda	$16, 32($sp)
-	lda	$17, 0
-	lda	$18, SIZEOF_PT_REGS
-	bsr	$26, memset		!samegp
-
-	/* Avoid the HAE being gratuitously wrong, which would cause us
-	   to do the whole turn off interrupts thing and restore it.  */
-	ldq	$2, alpha_mv+HAE_CACHE
-	stq	$2, 152+32($sp)
-
-	ldq	$16, 8($sp)
-	ldq	$17, 16($sp)
-	ldq	$18, 24($sp)
-	lda	$19, 32($sp)
-	bsr	$26, do_execve		!samegp
-
-	ldq	$26, 0($sp)
-	bne	$0, 1f			/* error! */
-
-	/* Move the temporary pt_regs struct from its current location
-	   to the top of the kernel stack frame.  See copy_thread for
-	   details for a normal process.  */
-	lda	$16, 0x4000 - SIZEOF_PT_REGS($8)
-	lda	$17, 32($sp)
-	lda	$18, SIZEOF_PT_REGS
-	bsr	$26, memmove		!samegp
-
-	/* Take that over as our new stack frame and visit userland!  */
-	lda	$sp, 0x4000 - SIZEOF_PT_REGS($8)
-	br	$31, ret_from_sys_call
-
-1:	lda	$sp, 32+SIZEOF_PT_REGS+8($sp)
-	ret
-.end kernel_execve
-
 
 /*
  * Special system calls.  Most of these are special in that they either
@@ -797,115 +745,6 @@ sys_rt_sigreturn:
 .end sys_rt_sigreturn
 
 	.align	4
-	.globl	sys_sethae
-	.ent	sys_sethae
-sys_sethae:
-	.prologue 0
-	stq	$16, 152($sp)
-	ret
-.end sys_sethae
-
-	.align	4
-	.globl	osf_getpriority
-	.ent	osf_getpriority
-osf_getpriority:
-	lda	$sp, -16($sp)
-	stq	$26, 0($sp)
-	.prologue 0
-
-	jsr	$26, sys_getpriority
-
-	ldq	$26, 0($sp)
-	blt	$0, 1f
-
-	/* Return value is the unbiased priority, i.e. 20 - prio.
-	   This does result in negative return values, so signal
-	   no error by writing into the R0 slot.  */
-	lda	$1, 20
-	stq	$31, 16($sp)
-	subl	$1, $0, $0
-	unop
-
-1:	lda	$sp, 16($sp)
-	ret
-.end osf_getpriority
-
-	.align	4
-	.globl	sys_getxuid
-	.ent	sys_getxuid
-sys_getxuid:
-	.prologue 0
-	ldq	$2, TI_TASK($8)
-	ldq	$3, TASK_CRED($2)
-	ldl	$0, CRED_UID($3)
-	ldl	$1, CRED_EUID($3)
-	stq	$1, 80($sp)
-	ret
-.end sys_getxuid
-
-	.align	4
-	.globl	sys_getxgid
-	.ent	sys_getxgid
-sys_getxgid:
-	.prologue 0
-	ldq	$2, TI_TASK($8)
-	ldq	$3, TASK_CRED($2)
-	ldl	$0, CRED_GID($3)
-	ldl	$1, CRED_EGID($3)
-	stq	$1, 80($sp)
-	ret
-.end sys_getxgid
-
-	.align	4
-	.globl	sys_getxpid
-	.ent	sys_getxpid
-sys_getxpid:
-	.prologue 0
-	ldq	$2, TI_TASK($8)
-
-	/* See linux/kernel/timer.c sys_getppid for discussion
-	   about this loop.  */
-	ldq	$3, TASK_GROUP_LEADER($2)
-	ldq	$4, TASK_REAL_PARENT($3)
-	ldl	$0, TASK_TGID($2)
-1:	ldl	$1, TASK_TGID($4)
-#ifdef CONFIG_SMP
-	mov	$4, $5
-	mb
-	ldq	$3, TASK_GROUP_LEADER($2)
-	ldq	$4, TASK_REAL_PARENT($3)
-	cmpeq	$4, $5, $5
-	beq	$5, 1b
-#endif
-	stq	$1, 80($sp)
-	ret
-.end sys_getxpid
-
-	.align	4
-	.globl	sys_alpha_pipe
-	.ent	sys_alpha_pipe
-sys_alpha_pipe:
-	lda	$sp, -16($sp)
-	stq	$26, 0($sp)
-	.prologue 0
-
-	mov	$31, $17
-	lda	$16, 8($sp)
-	jsr	$26, do_pipe_flags
-
-	ldq	$26, 0($sp)
-	bne	$0, 1f
-
-	/* The return values are in $0 and $20.  */
-	ldl	$1, 12($sp)
-	ldl	$0, 8($sp)
-
-	stq	$1, 80+16($sp)
-1:	lda	$sp, 16($sp)
-	ret
-.end sys_alpha_pipe
-
-	.align	4
 	.globl	sys_execve
 	.ent	sys_execve
 sys_execve:
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 98a1036..bc1acdd 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -1404,3 +1404,52 @@ SYSCALL_DEFINE3(osf_writev, unsigned long, fd,
 }
 
 #endif
+
+SYSCALL_DEFINE2(osf_getpriority, int, which, int, who)
+{
+	int prio = sys_getpriority(which, who);
+	if (prio >= 0) {
+		/* Return value is the unbiased priority, i.e. 20 - prio.
+		   This does result in negative return values, so signal
+		   no error */
+		force_successful_syscall_return();
+		prio = 20 - prio;
+	}
+	return prio;
+}
+
+SYSCALL_DEFINE0(getxuid)
+{
+	current_pt_regs()->r20 = sys_geteuid();
+	return sys_getuid();
+}
+
+SYSCALL_DEFINE0(getxgid)
+{
+	current_pt_regs()->r20 = sys_getegid();
+	return sys_getgid();
+}
+
+SYSCALL_DEFINE0(getxpid)
+{
+	current_pt_regs()->r20 = sys_getppid();
+	return sys_getpid();
+}
+
+SYSCALL_DEFINE0(alpha_pipe)
+{
+	int fd[2];
+	int res = do_pipe_flags(fd, 0);
+	if (!res) {
+		/* The return values are in $0 and $20.  */
+		current_pt_regs()->r20 = fd[1];
+		res = fd[0];
+	}
+	return res;
+}
+
+SYSCALL_DEFINE1(sethae, unsigned long, val)
+{
+	current_pt_regs()->hae = val;
+	return 0;
+}
diff --git a/arch/alpha/kernel/pci-sysfs.c b/arch/alpha/kernel/pci-sysfs.c
index 53649c7..b51f7b4 100644
--- a/arch/alpha/kernel/pci-sysfs.c
+++ b/arch/alpha/kernel/pci-sysfs.c
@@ -26,7 +26,7 @@ static int hose_mmap_page_range(struct pci_controller *hose,
 		base = sparse ? hose->sparse_io_base : hose->dense_io_base;
 
 	vma->vm_pgoff += base >> PAGE_SHIFT;
-	vma->vm_flags |= (VM_IO | VM_RESERVED);
+	vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
 
 	return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
 				  vma->vm_end - vma->vm_start,
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 153d3fc..6251146 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -455,3 +455,32 @@ get_wchan(struct task_struct *p)
 	}
 	return pc;
 }
+
+int kernel_execve(const char *path, const char *const argv[], const char *const envp[])
+{
+	/* Avoid the HAE being gratuitously wrong, which would cause us
+	   to do the whole turn off interrupts thing and restore it.  */
+	struct pt_regs regs = {.hae = alpha_mv.hae_cache};
+	int err = do_execve(path, argv, envp, &regs);
+	if (!err) {
+		/*
+		 * copy regs to normal position and off to userland we go...
+		 * note that we are not guaranteed that we are deep enough
+		 * in stack for current_pt_regs() not to overlap our stack
+		 * frame; memcpy() would not be safe and we _must_ do
+		 * everything starting from that memmove() in assembler.
+		 * And we can't mangle $sp until after the call of memmove()
+		 * either...
+		 */
+		__asm__ __volatile__ (
+			"lda	$16, %0\n"
+			"lda	$17, %1\n"
+			"lda	$18, %2\n"
+			"bsr	$26, memmove\n"
+			"lda	$sp, %0\n"
+			"jsr	$31, ret_from_sys_call\n"
+			: : "m"(*current_pt_regs()), "m"(regs), "Ir"(sizeof(struct pt_regs)));
+	}
+	return err;
+}
+EXPORT_SYMBOL(kernel_execve);
diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c
index 3ea8094..5d58652 100644
--- a/arch/alpha/kernel/srmcons.c
+++ b/arch/alpha/kernel/srmcons.c
@@ -223,6 +223,7 @@ srmcons_init(void)
 		driver->subtype = SYSTEM_TYPE_SYSCONS;
 		driver->init_termios = tty_std_termios;
 		tty_set_operations(driver, &srmcons_ops);
+		tty_port_link_device(&srmcons_singleton.port, driver, 0);
 		err = tty_register_driver(driver);
 		if (err) {
 			put_tty_driver(driver);
diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S
index 8783523..0cfffdc 100644
--- a/arch/alpha/kernel/systbls.S
+++ b/arch/alpha/kernel/systbls.S
@@ -111,7 +111,7 @@ sys_call_table:
 	.quad sys_socket
 	.quad sys_connect
 	.quad sys_accept
-	.quad osf_getpriority			/* 100 */
+	.quad sys_osf_getpriority			/* 100 */
 	.quad sys_send
 	.quad sys_recv
 	.quad sys_sigreturn
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index e91c7cd..33c22d9 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -38,7 +38,6 @@ config ARM
 	select HARDIRQS_SW_RESEND
 	select GENERIC_IRQ_PROBE
 	select GENERIC_IRQ_SHOW
-	select GENERIC_IRQ_PROBE
 	select ARCH_WANT_IPC_PARSE_VERSION
 	select HARDIRQS_SW_RESEND
 	select CPU_PM if (SUSPEND || CPU_IDLE)
@@ -50,6 +49,8 @@ config ARM
 	select GENERIC_STRNCPY_FROM_USER
 	select GENERIC_STRNLEN_USER
 	select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN
+	select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND
+	select MODULES_USE_ELF_REL
 	help
 	  The ARM series is a line of low-power-consumption RISC chip designs
 	  licensed by ARM Ltd and targeted at embedded applications and
@@ -126,11 +127,6 @@ config TRACE_IRQFLAGS_SUPPORT
 	bool
 	default y
 
-config GENERIC_LOCKBREAK
-	bool
-	default y
-	depends on SMP && PREEMPT
-
 config RWSEM_GENERIC_SPINLOCK
 	bool
 	default y
@@ -285,7 +281,6 @@ config ARCH_INTEGRATOR
 	select GENERIC_CLOCKEVENTS
 	select PLAT_VERSATILE
 	select PLAT_VERSATILE_FPGA_IRQ
-	select NEED_MACH_IO_H
 	select NEED_MACH_MEMORY_H
 	select SPARSE_IRQ
 	select MULTI_IRQ_HANDLER
@@ -318,7 +313,6 @@ config ARCH_VERSATILE
 	select ICST
 	select GENERIC_CLOCKEVENTS
 	select ARCH_WANT_OPTIONAL_GPIOLIB
-	select NEED_MACH_IO_H if PCI
 	select PLAT_VERSATILE
 	select PLAT_VERSATILE_CLOCK
 	select PLAT_VERSATILE_CLCD
@@ -462,7 +456,7 @@ config ARCH_FOOTBRIDGE
 	select FOOTBRIDGE
 	select GENERIC_CLOCKEVENTS
 	select HAVE_IDE
-	select NEED_MACH_IO_H
+	select NEED_MACH_IO_H if !MMU
 	select NEED_MACH_MEMORY_H
 	help
 	  Support for systems based on the DC21285 companion chip
@@ -519,7 +513,6 @@ config ARCH_IOP13XX
 	select PCI
 	select ARCH_SUPPORTS_MSI
 	select VMSPLIT_1G
-	select NEED_MACH_IO_H
 	select NEED_MACH_MEMORY_H
 	select NEED_RET_TO_USER
 	help
@@ -529,7 +522,6 @@ config ARCH_IOP32X
 	bool "IOP32x-based"
 	depends on MMU
 	select CPU_XSCALE
-	select NEED_MACH_IO_H
 	select NEED_RET_TO_USER
 	select PLAT_IOP
 	select PCI
@@ -542,7 +534,6 @@ config ARCH_IOP33X
 	bool "IOP33x-based"
 	depends on MMU
 	select CPU_XSCALE
-	select NEED_MACH_IO_H
 	select NEED_RET_TO_USER
 	select PLAT_IOP
 	select PCI
@@ -582,7 +573,6 @@ config ARCH_DOVE
 	select PCI
 	select ARCH_REQUIRE_GPIOLIB
 	select GENERIC_CLOCKEVENTS
-	select NEED_MACH_IO_H
 	select PLAT_ORION
 	help
 	  Support for the Marvell Dove SoC 88AP510
@@ -593,7 +583,6 @@ config ARCH_KIRKWOOD
 	select PCI
 	select ARCH_REQUIRE_GPIOLIB
 	select GENERIC_CLOCKEVENTS
-	select NEED_MACH_IO_H
 	select PLAT_ORION
 	help
 	  Support for the following Marvell Kirkwood series SoCs:
@@ -620,7 +609,6 @@ config ARCH_MV78XX0
 	select PCI
 	select ARCH_REQUIRE_GPIOLIB
 	select GENERIC_CLOCKEVENTS
-	select NEED_MACH_IO_H
 	select PLAT_ORION
 	help
 	  Support for the following Marvell MV78xx0 series SoCs:
@@ -633,7 +621,6 @@ config ARCH_ORION5X
 	select PCI
 	select ARCH_REQUIRE_GPIOLIB
 	select GENERIC_CLOCKEVENTS
-	select NEED_MACH_IO_H
 	select PLAT_ORION
 	help
 	  Support for the following Marvell Orion 5x series SoCs:
@@ -689,9 +676,9 @@ config ARCH_TEGRA
 	select HAVE_CLK
 	select HAVE_SMP
 	select MIGHT_HAVE_CACHE_L2X0
-	select NEED_MACH_IO_H if PCI
 	select ARCH_HAS_CPUFREQ
 	select USE_OF
+	select COMMON_CLK
 	help
 	  This enables support for NVIDIA Tegra based systems (Tegra APX,
 	  Tegra 6xx and Tegra 2 series).
@@ -918,7 +905,6 @@ config ARCH_SHARK
 	select PCI
 	select ARCH_USES_GETTIMEOFFSET
 	select NEED_MACH_MEMORY_H
-	select NEED_MACH_IO_H
 	help
 	  Support for the StrongARM based Digital DNARD machine, also known
 	  as "Shark" (<http://www.shark-linux.de/shark.html>).
@@ -937,6 +923,7 @@ config ARCH_U300
 	select COMMON_CLK
 	select GENERIC_GPIO
 	select ARCH_REQUIRE_GPIOLIB
+	select SPARSE_IRQ
 	help
 	  Support for ST-Ericsson U300 series mobile platforms.
 
@@ -962,6 +949,7 @@ config ARCH_NOMADIK
 	select COMMON_CLK
 	select GENERIC_CLOCKEVENTS
 	select PINCTRL
+	select PINCTRL_STN8815
 	select MIGHT_HAVE_CACHE_L2X0
 	select ARCH_REQUIRE_GPIOLIB
 	help
@@ -1185,12 +1173,6 @@ config XSCALE_PMU
 	depends on CPU_XSCALE
 	default y
 
-config CPU_HAS_PMU
-	depends on (CPU_V6 || CPU_V6K || CPU_V7 || XSCALE_PMU) && \
-		   (!ARCH_OMAP3 || OMAP3_EMU)
-	default y
-	bool
-
 config MULTI_IRQ_HANDLER
 	bool
 	help
@@ -1763,7 +1745,7 @@ config HIGHPTE
 
 config HW_PERF_EVENTS
 	bool "Enable hardware performance counter support for perf events"
-	depends on PERF_EVENTS && CPU_HAS_PMU
+	depends on PERF_EVENTS
 	default y
 	help
 	  Enable hardware performance counter support for perf events. If
@@ -1787,59 +1769,6 @@ config FORCE_MAX_ZONEORDER
 	  This config option is actually maximum order plus one. For example,
 	  a value of 11 means that the largest free memory block is 2^10 pages.
 
-config LEDS
-	bool "Timer and CPU usage LEDs"
-	depends on ARCH_CDB89712 || ARCH_EBSA110 || \
-		   ARCH_EBSA285 || ARCH_INTEGRATOR || \
-		   ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_NETWINDER || \
-		   ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \
-		   ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE || \
-		   ARCH_AT91 || ARCH_DAVINCI || \
-		   ARCH_KS8695 || MACH_RD88F5182 || ARCH_REALVIEW
-	help
-	  If you say Y here, the LEDs on your machine will be used
-	  to provide useful information about your current system status.
-
-	  If you are compiling a kernel for a NetWinder or EBSA-285, you will
-	  be able to select which LEDs are active using the options below. If
-	  you are compiling a kernel for the EBSA-110 or the LART however, the
-	  red LED will simply flash regularly to indicate that the system is
-	  still functional. It is safe to say Y here if you have a CATS
-	  system, but the driver will do nothing.
-
-config LEDS_TIMER
-	bool "Timer LED" if (!ARCH_CDB89712 && !ARCH_OMAP) || \
-			    OMAP_OSK_MISTRAL || MACH_OMAP_H2 \
-			    || MACH_OMAP_PERSEUS2
-	depends on LEDS
-	depends on !GENERIC_CLOCKEVENTS
-	default y if ARCH_EBSA110
-	help
-	  If you say Y here, one of the system LEDs (the green one on the
-	  NetWinder, the amber one on the EBSA285, or the red one on the LART)
-	  will flash regularly to indicate that the system is still
-	  operational. This is mainly useful to kernel hackers who are
-	  debugging unstable kernels.
-
-	  The LART uses the same LED for both Timer LED and CPU usage LED
-	  functions. You may choose to use both, but the Timer LED function
-	  will overrule the CPU usage LED.
-
-config LEDS_CPU
-	bool "CPU usage LED" if (!ARCH_CDB89712 && !ARCH_EBSA110 && \
-			!ARCH_OMAP) \
-			|| OMAP_OSK_MISTRAL || MACH_OMAP_H2 \
-			|| MACH_OMAP_PERSEUS2
-	depends on LEDS
-	help
-	  If you say Y here, the red LED will be used to give a good real
-	  time indication of CPU usage, by lighting whenever the idle task
-	  is not currently executing.
-
-	  The LART uses the same LED for both Timer LED and CPU usage LED
-	  functions. You may choose to use both, but the Timer LED function
-	  will overrule the CPU usage LED.
-
 config ALIGNMENT_TRAP
 	bool
 	depends on CPU_CP15_MMU
diff --git a/arch/arm/arm-soc-for-next-contents.txt b/arch/arm/arm-soc-for-next-contents.txt
new file mode 100644
index 0000000..88031e7
--- /dev/null
+++ b/arch/arm/arm-soc-for-next-contents.txt
@@ -0,0 +1,40 @@
+This file lists all branches that are pulled into the for-next branch
+of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git
+and their external dependencies.
+
+It also includes a couple of directly applied patches for build breaks with subject
+The next/* branches are kept in the order in which they get applied.
+
+fixes:
+
+next/fixes-non-critical:
+
+next/cleanup:
+cleanup/io-pci:   git://sources.calxeda.com/kernel/linux.git io-cleanup-pci-v2
+bcmring/cleanup:  patches from Arnd
+u300/cleanup	  git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git u300-cleanup
+
+next/maintainers:
+
+next/soc:
+ux500/asic-id:	git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git ux500-core
+
+next/dt:
+pxa/dt:		git://github.com/hzhuang1/linux.git dt
+
+next/defconfig:
+
+next/drivers:
+devel/led-driver	git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds.git for-arm-soc
+at91/mci	git://github.com/at91linux/linux-at91 at91-for-next-soc
+
+next/boards:
+pxa/board	git://github.com/hzhuang1/linux.git board
+
+next/docs:
+mvebu/docs:	git://github.com/MISL-EBU-System-SW/mainline-public.git marvell-doc
+
+
+
+
+
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index 59509c4..bd0cff3 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -154,5 +154,10 @@
 			#size-cells = <0>;
 			ti,hwmods = "i2c3";
 		};
+
+		wdt2: wdt@44e35000 {
+			compatible = "ti,omap3-wdt";
+			ti,hwmods = "wd_timer2";
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi
index aba28dc..aaa0c0a 100644
--- a/arch/arm/boot/dts/imx51.dtsi
+++ b/arch/arm/boot/dts/imx51.dtsi
@@ -263,6 +263,13 @@
 				status = "disabled";
 			};
 
+			nand@83fdb000 {
+				compatible = "fsl,imx51-nand";
+				reg = <0x83fdb000 0x1000 0xcfff0000 0x10000>;
+				interrupts = <8>;
+				status = "disabled";
+			};
+
 			ssi3: ssi@83fe8000 {
 				compatible = "fsl,imx51-ssi", "fsl,imx21-ssi";
 				reg = <0x83fe8000 0x4000>;
diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
index cd37165..dc00c62 100644
--- a/arch/arm/boot/dts/imx53.dtsi
+++ b/arch/arm/boot/dts/imx53.dtsi
@@ -321,6 +321,13 @@
 				status = "disabled";
 			};
 
+			nand@63fdb000 {
+				compatible = "fsl,imx53-nand";
+				reg = <0x63fdb000 0x1000 0xf7ff0000 0x10000>;
+				interrupts = <8>;
+				status = "disabled";
+			};
+
 			ssi3: ssi@63fe8000 {
 				compatible = "fsl,imx53-ssi", "fsl,imx21-ssi";
 				reg = <0x63fe8000 0x4000>;
diff --git a/arch/arm/boot/dts/kirkwood-iconnect.dts b/arch/arm/boot/dts/kirkwood-iconnect.dts
index 52d9470..f8ca6fa 100644
--- a/arch/arm/boot/dts/kirkwood-iconnect.dts
+++ b/arch/arm/boot/dts/kirkwood-iconnect.dts
@@ -41,9 +41,13 @@
 		};
 		power-blue {
 			label = "power:blue";
-			gpios = <&gpio1 11 0>;
+			gpios = <&gpio1 10 0>;
 			linux,default-trigger = "timer";
 		};
+		power-red {
+			label = "power:red";
+			gpios = <&gpio1 11 0>;
+		};
 		usb1 {
 			label = "usb1:blue";
 			gpios = <&gpio1 12 0>;
diff --git a/arch/arm/boot/dts/mmp2.dtsi b/arch/arm/boot/dts/mmp2.dtsi
index 80f74e2..0514fb4 100644
--- a/arch/arm/boot/dts/mmp2.dtsi
+++ b/arch/arm/boot/dts/mmp2.dtsi
@@ -26,6 +26,11 @@
 		interrupt-parent = <&intc>;
 		ranges;
 
+		L2: l2-cache {
+			compatible = "marvell,tauros2-cache";
+			marvell,tauros2-cache-features = <0x3>;
+		};
+
 		axi@d4200000 {	/* AXI */
 			compatible = "mrvl,axi-bus", "simple-bus";
 			#address-cells = <1>;
diff --git a/arch/arm/boot/dts/pxa27x.dtsi b/arch/arm/boot/dts/pxa27x.dtsi
new file mode 100644
index 0000000..d7c5d72
--- /dev/null
+++ b/arch/arm/boot/dts/pxa27x.dtsi
@@ -0,0 +1,14 @@
+/* The pxa3xx skeleton simply augments the 2xx version */
+/include/ "pxa2xx.dtsi"
+
+/ {
+	model = "Marvell PXA27x familiy SoC";
+	compatible = "marvell,pxa27x";
+
+	pxabus {
+		pxairq: interrupt-controller@40d00000 {
+			marvell,intc-priority;
+			marvell,intc-nr-irqs = <34>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/pxa2xx.dtsi b/arch/arm/boot/dts/pxa2xx.dtsi
new file mode 100644
index 0000000..f18aad3
--- /dev/null
+++ b/arch/arm/boot/dts/pxa2xx.dtsi
@@ -0,0 +1,132 @@
+/*
+ * pxa2xx.dtsi - Device Tree Include file for Marvell PXA2xx family SoC
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	model = "Marvell PXA2xx family SoC";
+	compatible = "marvell,pxa2xx";
+	interrupt-parent = <&pxairq>;
+
+	aliases {
+		serial0 = &ffuart;
+		serial1 = &btuart;
+		serial2 = &stuart;
+		serial3 = &hwuart;
+		i2c0 = &pwri2c;
+		i2c1 = &pxai2c1;
+	};
+
+	cpus {
+		cpu@0 {
+			compatible = "arm,xscale";
+		};
+	};
+
+	pxabus {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		pxairq: interrupt-controller@40d00000 {
+			#interrupt-cells = <1>;
+			compatible = "marvell,pxa-intc";
+			interrupt-controller;
+			interrupt-parent;
+			marvell,intc-nr-irqs = <32>;
+			reg = <0x40d00000 0xd0>;
+		};
+
+		gpio: gpio@40e00000 {
+			compatible = "mrvl,pxa-gpio";
+			#address-cells = <0x1>;
+			#size-cells = <0x1>;
+			reg = <0x40e00000 0x10000>;
+			gpio-controller;
+			#gpio-cells = <0x2>;
+			interrupts = <10>;
+			interrupt-names = "gpio_mux";
+			interrupt-controller;
+			#interrupt-cells = <0x2>;
+			ranges;
+
+			gcb0: gpio@40e00000 {
+				reg = <0x40e00000 0x4>;
+			};
+
+			gcb1: gpio@40e00004 {
+				reg = <0x40e00004 0x4>;
+			};
+
+			gcb2: gpio@40e00008 {
+				reg = <0x40e00008 0x4>;
+			};
+			gcb3: gpio@40e0000c {
+				reg = <0x40e0000c 0x4>;
+			};
+		};
+
+		ffuart: uart@40100000 {
+			compatible = "mrvl,pxa-uart";
+			reg = <0x40100000 0x30>;
+			interrupts = <22>;
+			status = "disabled";
+		};
+
+		btuart: uart@40200000 {
+			compatible = "mrvl,pxa-uart";
+			reg = <0x40200000 0x30>;
+			interrupts = <21>;
+			status = "disabled";
+		};
+
+		stuart: uart@40700000 {
+			compatible = "mrvl,pxa-uart";
+			reg = <0x40700000 0x30>;
+			interrupts = <20>;
+			status = "disabled";
+		};
+
+		hwuart: uart@41100000 {
+			compatible = "mrvl,pxa-uart";
+			reg = <0x41100000 0x30>;
+			interrupts = <7>;
+			status = "disabled";
+		};
+
+		pxai2c1: i2c@40301680 {
+			compatible = "mrvl,pxa-i2c";
+			reg = <0x40301680 0x30>;
+			interrupts = <18>;
+			#address-cells = <0x1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		usb0: ohci@4c000000 {
+			compatible = "mrvl,pxa-ohci";
+			reg = <0x4c000000 0x10000>;
+			interrupts = <3>;
+			status = "disabled";
+		};
+
+		mmc0: mmc@41100000 {
+			compatible = "mrvl,pxa-mmc";
+			reg = <0x41100000 0x1000>;
+			interrupts = <23>;
+			status = "disabled";
+		};
+
+		rtc@40900000 {
+			compatible = "marvell,pxa-rtc";
+			reg = <0x40900000 0x3c>;
+			interrupts = <30 31>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/pxa3xx.dtsi b/arch/arm/boot/dts/pxa3xx.dtsi
new file mode 100644
index 0000000..f9d92da
--- /dev/null
+++ b/arch/arm/boot/dts/pxa3xx.dtsi
@@ -0,0 +1,32 @@
+/* The pxa3xx skeleton simply augments the 2xx version */
+/include/ "pxa2xx.dtsi"
+
+/ {
+	model = "Marvell PXA3xx familiy SoC";
+	compatible = "marvell,pxa3xx";
+
+	pxabus {
+		pwri2c: i2c@40f500c0 {
+			compatible = "mrvl,pwri2c";
+			reg = <0x40f500c0 0x30>;
+			interrupts = <6>;
+			#address-cells = <0x1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		nand0: nand@43100000 {
+			compatible = "marvell,pxa3xx-nand";
+			reg = <0x43100000 90>;
+			interrupts = <45>;
+			#address-cells = <1>;
+			#size-cells = <1>;	
+			status = "disabled";
+		};
+
+		pxairq: interrupt-controller@40d00000 {
+			marvell,intc-priority;
+			marvell,intc-nr-irqs = <56>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/pxa910.dtsi b/arch/arm/boot/dts/pxa910.dtsi
index aebf32d..a3be44d8 100644
--- a/arch/arm/boot/dts/pxa910.dtsi
+++ b/arch/arm/boot/dts/pxa910.dtsi
@@ -25,6 +25,11 @@
 		interrupt-parent = <&intc>;
 		ranges;
 
+		L2: l2-cache {
+			compatible = "marvell,tauros2-cache";
+			marvell,tauros2-cache-features = <0x3>;
+		};
+
 		axi@d4200000 {	/* AXI */
 			compatible = "mrvl,axi-bus", "simple-bus";
 			#address-cells = <1>;
diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts
index 684a9e1..ddf287f 100644
--- a/arch/arm/boot/dts/tegra20-paz00.dts
+++ b/arch/arm/boot/dts/tegra20-paz00.dts
@@ -272,12 +272,170 @@
 		status = "okay";
 		clock-frequency = <400000>;
 
+		pmic: tps6586x@34 {
+			compatible = "ti,tps6586x";
+			reg = <0x34>;
+			interrupts = <0 86 0x4>;
+
+			#gpio-cells = <2>;
+			gpio-controller;
+
+			sys-supply = <&p5valw_reg>;
+			vin-sm0-supply = <&sys_reg>;
+			vin-sm1-supply = <&sys_reg>;
+			vin-sm2-supply = <&sys_reg>;
+			vinldo01-supply = <&sm2_reg>;
+			vinldo23-supply = <&sm2_reg>;
+			vinldo4-supply = <&sm2_reg>;
+			vinldo678-supply = <&sm2_reg>;
+			vinldo9-supply = <&sm2_reg>;
+
+			regulators {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				sys_reg: regulator@0 {
+					reg = <0>;
+					regulator-compatible = "sys";
+					regulator-name = "vdd_sys";
+					regulator-always-on;
+				};
+
+				regulator@1 {
+					reg = <1>;
+					regulator-compatible = "sm0";
+					regulator-name = "+1.2vs_sm0,vdd_core";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+					regulator-always-on;
+				};
+
+				regulator@2 {
+					reg = <2>;
+					regulator-compatible = "sm1";
+					regulator-name = "+1.0vs_sm1,vdd_cpu";
+					regulator-min-microvolt = <1000000>;
+					regulator-max-microvolt = <1000000>;
+					regulator-always-on;
+				};
+
+				sm2_reg: regulator@3 {
+					reg = <3>;
+					regulator-compatible = "sm2";
+					regulator-name = "+3.7vs_sm2,vin_ldo*";
+					regulator-min-microvolt = <3700000>;
+					regulator-max-microvolt = <3700000>;
+					regulator-always-on;
+				};
+
+				/* LDO0 is not connected to anything */
+
+				regulator@5 {
+					reg = <5>;
+					regulator-compatible = "ldo1";
+					regulator-name = "+1.1vs_ldo1,avdd_pll*";
+					regulator-min-microvolt = <1100000>;
+					regulator-max-microvolt = <1100000>;
+					regulator-always-on;
+				};
+
+				regulator@6 {
+					reg = <6>;
+					regulator-compatible = "ldo2";
+					regulator-name = "+1.2vs_ldo2,vdd_rtc";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+				};
+
+				regulator@7 {
+					reg = <7>;
+					regulator-compatible = "ldo3";
+					regulator-name = "+3.3vs_ldo3,avdd_usb*";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+					regulator-always-on;
+				};
+
+				regulator@8 {
+					reg = <8>;
+					regulator-compatible = "ldo4";
+					regulator-name = "+1.8vs_ldo4,avdd_osc,vddio_sys";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+					regulator-always-on;
+				};
+
+				regulator@9 {
+					reg = <9>;
+					regulator-compatible = "ldo5";
+					regulator-name = "+2.85vs_ldo5,vcore_mmc";
+					regulator-min-microvolt = <2850000>;
+					regulator-max-microvolt = <2850000>;
+					regulator-always-on;
+				};
+
+				regulator@10 {
+					reg = <10>;
+					regulator-compatible = "ldo6";
+					/*
+					 * Research indicates this should be
+					 * 1.8v; other boards that use this
+					 * rail for the same purpose need it
+					 * set to 1.8v. The schematic signal
+					 * name is incorrect; perhaps copied
+					 * from an incorrect NVIDIA reference.
+					 */
+					regulator-name = "+2.85vs_ldo6,avdd_vdac";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				regulator@11 {
+					reg = <11>;
+					regulator-compatible = "ldo7";
+					regulator-name = "+3.3vs_ldo7,avdd_hdmi";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				regulator@12 {
+					reg = <12>;
+					regulator-compatible = "ldo8";
+					regulator-name = "+1.8vs_ldo8,avdd_hdmi_pll";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				regulator@13 {
+					reg = <13>;
+					regulator-compatible = "ldo9";
+					regulator-name = "+2.85vs_ldo9,vdd_ddr_rx";
+					regulator-min-microvolt = <2850000>;
+					regulator-max-microvolt = <2850000>;
+					regulator-always-on;
+				};
+
+				regulator@14 {
+					reg = <14>;
+					regulator-compatible = "ldo_rtc";
+					regulator-name = "+3.3vs_rtc";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+					regulator-always-on;
+				};
+			};
+		};
+
 		adt7461@4c {
 			compatible = "adi,adt7461";
 			reg = <0x4c>;
 		};
 	};
 
+	pmc {
+		nvidia,invert-interrupt;
+	};
+
 	usb@c5000000 {
 		status = "okay";
 	};
@@ -325,6 +483,21 @@
 		};
 	};
 
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		p5valw_reg: regulator@0 {
+			compatible = "regulator-fixed";
+			reg = <0>;
+			regulator-name = "+5valw";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			regulator-always-on;
+		};
+	};
+
 	sound {
 		compatible = "nvidia,tegra-audio-alc5632-paz00",
 			"nvidia,tegra-audio-alc5632";
diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts
index 85e621a..92deb36 100644
--- a/arch/arm/boot/dts/tegra20-seaboard.dts
+++ b/arch/arm/boot/dts/tegra20-seaboard.dts
@@ -374,6 +374,152 @@
 		status = "okay";
 		clock-frequency = <400000>;
 
+		pmic: tps6586x@34 {
+			compatible = "ti,tps6586x";
+			reg = <0x34>;
+			interrupts = <0 86 0x4>;
+
+			#gpio-cells = <2>;
+			gpio-controller;
+
+			sys-supply = <&vdd_5v0_reg>;
+			vin-sm0-supply = <&sys_reg>;
+			vin-sm1-supply = <&sys_reg>;
+			vin-sm2-supply = <&sys_reg>;
+			vinldo01-supply = <&sm2_reg>;
+			vinldo23-supply = <&sm2_reg>;
+			vinldo4-supply = <&sm2_reg>;
+			vinldo678-supply = <&sm2_reg>;
+			vinldo9-supply = <&sm2_reg>;
+
+			regulators {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				sys_reg: regulator@0 {
+					reg = <0>;
+					regulator-compatible = "sys";
+					regulator-name = "vdd_sys";
+					regulator-always-on;
+				};
+
+				regulator@1 {
+					reg = <1>;
+					regulator-compatible = "sm0";
+					regulator-name = "vdd_sm0,vdd_core";
+					regulator-min-microvolt = <1300000>;
+					regulator-max-microvolt = <1300000>;
+					regulator-always-on;
+				};
+
+				regulator@2 {
+					reg = <2>;
+					regulator-compatible = "sm1";
+					regulator-name = "vdd_sm1,vdd_cpu";
+					regulator-min-microvolt = <1125000>;
+					regulator-max-microvolt = <1125000>;
+					regulator-always-on;
+				};
+
+				sm2_reg: regulator@3 {
+					reg = <3>;
+					regulator-compatible = "sm2";
+					regulator-name = "vdd_sm2,vin_ldo*";
+					regulator-min-microvolt = <3700000>;
+					regulator-max-microvolt = <3700000>;
+					regulator-always-on;
+				};
+
+				/* LDO0 is not connected to anything */
+
+				regulator@5 {
+					reg = <5>;
+					regulator-compatible = "ldo1";
+					regulator-name = "vdd_ldo1,avdd_pll*";
+					regulator-min-microvolt = <1100000>;
+					regulator-max-microvolt = <1100000>;
+					regulator-always-on;
+				};
+
+				regulator@6 {
+					reg = <6>;
+					regulator-compatible = "ldo2";
+					regulator-name = "vdd_ldo2,vdd_rtc";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+				};
+
+				regulator@7 {
+					reg = <7>;
+					regulator-compatible = "ldo3";
+					regulator-name = "vdd_ldo3,avdd_usb*";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+					regulator-always-on;
+				};
+
+				regulator@8 {
+					reg = <8>;
+					regulator-compatible = "ldo4";
+					regulator-name = "vdd_ldo4,avdd_osc,vddio_sys";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+					regulator-always-on;
+				};
+
+				regulator@9 {
+					reg = <9>;
+					regulator-compatible = "ldo5";
+					regulator-name = "vdd_ldo5,vcore_mmc";
+					regulator-min-microvolt = <2850000>;
+					regulator-max-microvolt = <2850000>;
+					regulator-always-on;
+				};
+
+				regulator@10 {
+					reg = <10>;
+					regulator-compatible = "ldo6";
+					regulator-name = "vdd_ldo6,avdd_vdac,vddio_vi,vddio_cam";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				regulator@11 {
+					reg = <11>;
+					regulator-compatible = "ldo7";
+					regulator-name = "vdd_ldo7,avdd_hdmi,vdd_fuse";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				regulator@12 {
+					reg = <12>;
+					regulator-compatible = "ldo8";
+					regulator-name = "vdd_ldo8,avdd_hdmi_pll";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				regulator@13 {
+					reg = <13>;
+					regulator-compatible = "ldo9";
+					regulator-name = "vdd_ldo9,avdd_2v85,vdd_ddr_rx";
+					regulator-min-microvolt = <2850000>;
+					regulator-max-microvolt = <2850000>;
+					regulator-always-on;
+				};
+
+				regulator@14 {
+					reg = <14>;
+					regulator-compatible = "ldo_rtc";
+					regulator-name = "vdd_rtc_out,vdd_cell";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+					regulator-always-on;
+				};
+			};
+		};
+
 		temperature-sensor@4c {
 			compatible = "nct1008";
 			reg = <0x4c>;
@@ -387,6 +533,10 @@
 		};
 	};
 
+	pmc {
+		nvidia,invert-interrupt;
+	};
+
 	memory-controller@0x7000f400 {
 		emc-table@190000 {
 			reg = <190000>;
@@ -473,6 +623,40 @@
 		};
 	};
 
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vdd_5v0_reg: regulator@0 {
+			compatible = "regulator-fixed";
+			reg = <0>;
+			regulator-name = "vdd_5v0";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			regulator-always-on;
+		};
+
+		regulator@1 {
+			compatible = "regulator-fixed";
+			reg = <1>;
+			regulator-name = "vdd_1v5";
+			regulator-min-microvolt = <1500000>;
+			regulator-max-microvolt = <1500000>;
+			gpio = <&pmic 0 0>;
+		};
+
+		regulator@2 {
+			compatible = "regulator-fixed";
+			reg = <2>;
+			regulator-name = "vdd_1v2";
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			gpio = <&pmic 1 0>;
+			enable-active-high;
+		};
+	};
+
 	sound {
 		compatible = "nvidia,tegra-audio-wm8903-seaboard",
 			     "nvidia,tegra-audio-wm8903";
diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts
index be90544..4ec6b4c 100644
--- a/arch/arm/boot/dts/tegra20-ventana.dts
+++ b/arch/arm/boot/dts/tegra20-ventana.dts
@@ -289,6 +289,156 @@
 	i2c@7000d000 {
 		status = "okay";
 		clock-frequency = <400000>;
+
+		pmic: tps6586x@34 {
+			compatible = "ti,tps6586x";
+			reg = <0x34>;
+			interrupts = <0 86 0x4>;
+
+			#gpio-cells = <2>;
+			gpio-controller;
+
+			sys-supply = <&vdd_5v0_reg>;
+			vin-sm0-supply = <&sys_reg>;
+			vin-sm1-supply = <&sys_reg>;
+			vin-sm2-supply = <&sys_reg>;
+			vinldo01-supply = <&sm2_reg>;
+			vinldo23-supply = <&sm2_reg>;
+			vinldo4-supply = <&sm2_reg>;
+			vinldo678-supply = <&sm2_reg>;
+			vinldo9-supply = <&sm2_reg>;
+
+			regulators {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				sys_reg: regulator@0 {
+					reg = <0>;
+					regulator-compatible = "sys";
+					regulator-name = "vdd_sys";
+					regulator-always-on;
+				};
+
+				regulator@1 {
+					reg = <1>;
+					regulator-compatible = "sm0";
+					regulator-name = "vdd_sm0,vdd_core";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+					regulator-always-on;
+				};
+
+				regulator@2 {
+					reg = <2>;
+					regulator-compatible = "sm1";
+					regulator-name = "vdd_sm1,vdd_cpu";
+					regulator-min-microvolt = <1000000>;
+					regulator-max-microvolt = <1000000>;
+					regulator-always-on;
+				};
+
+				sm2_reg: regulator@3 {
+					reg = <3>;
+					regulator-compatible = "sm2";
+					regulator-name = "vdd_sm2,vin_ldo*";
+					regulator-min-microvolt = <3700000>;
+					regulator-max-microvolt = <3700000>;
+					regulator-always-on;
+				};
+
+				/* LDO0 is not connected to anything */
+
+				regulator@5 {
+					reg = <5>;
+					regulator-compatible = "ldo1";
+					regulator-name = "vdd_ldo1,avdd_pll*";
+					regulator-min-microvolt = <1100000>;
+					regulator-max-microvolt = <1100000>;
+					regulator-always-on;
+				};
+
+				regulator@6 {
+					reg = <6>;
+					regulator-compatible = "ldo2";
+					regulator-name = "vdd_ldo2,vdd_rtc";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+				};
+
+				regulator@7 {
+					reg = <7>;
+					regulator-compatible = "ldo3";
+					regulator-name = "vdd_ldo3,avdd_usb*";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+					regulator-always-on;
+				};
+
+				regulator@8 {
+					reg = <8>;
+					regulator-compatible = "ldo4";
+					regulator-name = "vdd_ldo4,avdd_osc,vddio_sys";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+					regulator-always-on;
+				};
+
+				regulator@9 {
+					reg = <9>;
+					regulator-compatible = "ldo5";
+					regulator-name = "vdd_ldo5,vcore_mmc";
+					regulator-min-microvolt = <2850000>;
+					regulator-max-microvolt = <2850000>;
+					regulator-always-on;
+				};
+
+				regulator@10 {
+					reg = <10>;
+					regulator-compatible = "ldo6";
+					regulator-name = "vdd_ldo6,avdd_vdac";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				regulator@11 {
+					reg = <11>;
+					regulator-compatible = "ldo7";
+					regulator-name = "vdd_ldo7,avdd_hdmi,vdd_fuse";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				regulator@12 {
+					reg = <12>;
+					regulator-compatible = "ldo8";
+					regulator-name = "vdd_ldo8,avdd_hdmi_pll";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				regulator@13 {
+					reg = <13>;
+					regulator-compatible = "ldo9";
+					regulator-name = "vdd_ldo9,avdd_2v85,vdd_ddr_rx";
+					regulator-min-microvolt = <2850000>;
+					regulator-max-microvolt = <2850000>;
+					regulator-always-on;
+				};
+
+				regulator@14 {
+					reg = <14>;
+					regulator-compatible = "ldo_rtc";
+					regulator-name = "vdd_rtc_out,vdd_cell";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+					regulator-always-on;
+				};
+			};
+		};
+	};
+
+	pmc {
+		nvidia,invert-interrupt;
 	};
 
 	usb@c5000000 {
@@ -317,6 +467,60 @@
 		bus-width = <8>;
 	};
 
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vdd_5v0_reg: regulator@0 {
+			compatible = "regulator-fixed";
+			reg = <0>;
+			regulator-name = "vdd_5v0";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			regulator-always-on;
+		};
+
+		regulator@1 {
+			compatible = "regulator-fixed";
+			reg = <1>;
+			regulator-name = "vdd_1v5";
+			regulator-min-microvolt = <1500000>;
+			regulator-max-microvolt = <1500000>;
+			gpio = <&pmic 0 0>;
+		};
+
+		regulator@2 {
+			compatible = "regulator-fixed";
+			reg = <2>;
+			regulator-name = "vdd_1v2";
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			gpio = <&pmic 1 0>;
+			enable-active-high;
+		};
+
+		regulator@3 {
+			compatible = "regulator-fixed";
+			reg = <3>;
+			regulator-name = "vdd_pnl";
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+			gpio = <&gpio 22 0>; /* gpio PC6 */
+			enable-active-high;
+		};
+
+		regulator@4 {
+			compatible = "regulator-fixed";
+			reg = <4>;
+			regulator-name = "vdd_bl";
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+			gpio = <&gpio 176 0>; /* gpio PW0 */
+			enable-active-high;
+		};
+	};
+
 	sound {
 		compatible = "nvidia,tegra-audio-wm8903-ventana",
 			     "nvidia,tegra-audio-wm8903";
diff --git a/arch/arm/boot/dts/tegra20-whistler.dts b/arch/arm/boot/dts/tegra20-whistler.dts
index 6916310..4ae1e5d 100644
--- a/arch/arm/boot/dts/tegra20-whistler.dts
+++ b/arch/arm/boot/dts/tegra20-whistler.dts
@@ -261,6 +261,284 @@
 			gpio-controller;
 			#gpio-cells = <2>;
 		};
+
+		max8907@3c {
+			compatible = "maxim,max8907";
+			reg = <0x3c>;
+			interrupts = <0 86 0x4>;
+
+			mbatt-supply = <&usb0_vbus_reg>;
+			in-v1-supply = <&mbatt_reg>;
+			in-v2-supply = <&mbatt_reg>;
+			in-v3-supply = <&mbatt_reg>;
+			in1-supply = <&mbatt_reg>;
+			in2-supply = <&nvvdd_sv3_reg>;
+			in3-supply = <&mbatt_reg>;
+			in4-supply = <&mbatt_reg>;
+			in5-supply = <&mbatt_reg>;
+			in6-supply = <&mbatt_reg>;
+			in7-supply = <&mbatt_reg>;
+			in8-supply = <&mbatt_reg>;
+			in9-supply = <&mbatt_reg>;
+			in10-supply = <&mbatt_reg>;
+			in11-supply = <&mbatt_reg>;
+			in12-supply = <&mbatt_reg>;
+			in13-supply = <&mbatt_reg>;
+			in14-supply = <&mbatt_reg>;
+			in15-supply = <&mbatt_reg>;
+			in16-supply = <&mbatt_reg>;
+			in17-supply = <&nvvdd_sv3_reg>;
+			in18-supply = <&nvvdd_sv3_reg>;
+			in19-supply = <&mbatt_reg>;
+			in20-supply = <&mbatt_reg>;
+
+			regulators {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				mbatt_reg: regulator@0 {
+					reg = <0>;
+					regulator-compatible = "mbatt";
+					regulator-name = "vbat_pmu";
+					regulator-always-on;
+				};
+
+				regulator@1 {
+					reg = <1>;
+					regulator-compatible = "sd1";
+					regulator-name = "nvvdd_sv1,vdd_cpu_pmu";
+					regulator-min-microvolt = <1000000>;
+					regulator-max-microvolt = <1000000>;
+					regulator-always-on;
+				};
+
+				regulator@2 {
+					reg = <2>;
+					regulator-compatible = "sd2";
+					regulator-name = "nvvdd_sv2,vdd_core";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+					regulator-always-on;
+				};
+
+				nvvdd_sv3_reg: regulator@3 {
+					reg = <3>;
+					regulator-compatible = "sd3";
+					regulator-name = "nvvdd_sv3";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+					regulator-always-on;
+				};
+
+				regulator@4 {
+					reg = <4>;
+					regulator-compatible = "ldo1";
+					regulator-name = "nvvdd_ldo1,vddio_rx_ddr,vcore_acc";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+					regulator-always-on;
+				};
+
+				regulator@5 {
+					reg = <5>;
+					regulator-compatible = "ldo2";
+					regulator-name = "nvvdd_ldo2,avdd_pll*";
+					regulator-min-microvolt = <1100000>;
+					regulator-max-microvolt = <1100000>;
+					regulator-always-on;
+				};
+
+				regulator@6 {
+					reg = <6>;
+					regulator-compatible = "ldo3";
+					regulator-name = "nvvdd_ldo3,vcom_1v8b";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+					regulator-always-on;
+				};
+
+				regulator@7 {
+					reg = <7>;
+					regulator-compatible = "ldo4";
+					regulator-name = "nvvdd_ldo4,avdd_usb*";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+					regulator-always-on;
+				};
+
+				regulator@8 {
+					reg = <8>;
+					regulator-compatible = "ldo5";
+					regulator-name = "nvvdd_ldo5,vcore_mmc,avdd_lcd1,vddio_1wire";
+					regulator-min-microvolt = <2800000>;
+					regulator-max-microvolt = <2800000>;
+					regulator-always-on;
+				};
+
+				regulator@9 {
+					reg = <9>;
+					regulator-compatible = "ldo6";
+					regulator-name = "nvvdd_ldo6,avdd_hdmi_pll";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				regulator@10 {
+					reg = <10>;
+					regulator-compatible = "ldo7";
+					regulator-name = "nvvdd_ldo7,avddio_audio";
+					regulator-min-microvolt = <2800000>;
+					regulator-max-microvolt = <2800000>;
+					regulator-always-on;
+				};
+
+				regulator@11 {
+					reg = <11>;
+					regulator-compatible = "ldo8";
+					regulator-name = "nvvdd_ldo8,vcom_3v0,vcore_cmps";
+					regulator-min-microvolt = <3000000>;
+					regulator-max-microvolt = <3000000>;
+				};
+
+				regulator@12 {
+					reg = <12>;
+					regulator-compatible = "ldo9";
+					regulator-name = "nvvdd_ldo9,avdd_cam*";
+					regulator-min-microvolt = <2800000>;
+					regulator-max-microvolt = <2800000>;
+				};
+
+				regulator@13 {
+					reg = <13>;
+					regulator-compatible = "ldo10";
+					regulator-name = "nvvdd_ldo10,avdd_usb_ic_3v0";
+					regulator-min-microvolt = <3000000>;
+					regulator-max-microvolt = <3000000>;
+					regulator-always-on;
+				};
+
+				regulator@14 {
+					reg = <14>;
+					regulator-compatible = "ldo11";
+					regulator-name = "nvvdd_ldo11,vddio_pex_clk,vcom_33,avdd_hdmi";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				regulator@15 {
+					reg = <15>;
+					regulator-compatible = "ldo12";
+					regulator-name = "nvvdd_ldo12,vddio_sdio";
+					regulator-min-microvolt = <2800000>;
+					regulator-max-microvolt = <2800000>;
+					regulator-always-on;
+				};
+
+				regulator@16 {
+					reg = <16>;
+					regulator-compatible = "ldo13";
+					regulator-name = "nvvdd_ldo13,vcore_phtn,vdd_af";
+					regulator-min-microvolt = <2800000>;
+					regulator-max-microvolt = <2800000>;
+				};
+
+				regulator@17 {
+					reg = <17>;
+					regulator-compatible = "ldo14";
+					regulator-name = "nvvdd_ldo14,avdd_vdac";
+					regulator-min-microvolt = <2800000>;
+					regulator-max-microvolt = <2800000>;
+				};
+
+				regulator@18 {
+					reg = <18>;
+					regulator-compatible = "ldo15";
+					regulator-name = "nvvdd_ldo15,vcore_temp,vddio_hdcp";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				regulator@19 {
+					reg = <19>;
+					regulator-compatible = "ldo16";
+					regulator-name = "nvvdd_ldo16,vdd_dbrtr";
+					regulator-min-microvolt = <1300000>;
+					regulator-max-microvolt = <1300000>;
+				};
+
+				regulator@20 {
+					reg = <20>;
+					regulator-compatible = "ldo17";
+					regulator-name = "nvvdd_ldo17,vddio_mipi";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+				};
+
+				regulator@21 {
+					reg = <21>;
+					regulator-compatible = "ldo18";
+					regulator-name = "nvvdd_ldo18,vddio_vi,vcore_cam*";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				regulator@22 {
+					reg = <22>;
+					regulator-compatible = "ldo19";
+					regulator-name = "nvvdd_ldo19,avdd_lcd2,vddio_lx";
+					regulator-min-microvolt = <2800000>;
+					regulator-max-microvolt = <2800000>;
+				};
+
+				regulator@23 {
+					reg = <23>;
+					regulator-compatible = "ldo20";
+					regulator-name = "nvvdd_ldo20,vddio_ddr_1v2,vddio_hsic,vcom_1v2";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+					regulator-always-on;
+				};
+
+				regulator@24 {
+					reg = <24>;
+					regulator-compatible = "out5v";
+					regulator-name = "usb0_vbus_reg";
+				};
+
+				regulator@25 {
+					reg = <25>;
+					regulator-compatible = "out33v";
+					regulator-name = "pmu_out3v3";
+				};
+
+				regulator@26 {
+					reg = <26>;
+					regulator-compatible = "bbat";
+					regulator-name = "pmu_bbat";
+					regulator-min-microvolt = <2400000>;
+					regulator-max-microvolt = <2400000>;
+					regulator-always-on;
+				};
+
+				regulator@27 {
+					reg = <27>;
+					regulator-compatible = "sdby";
+					regulator-name = "vdd_aon";
+					regulator-always-on;
+				};
+
+				regulator@28 {
+					reg = <28>;
+					regulator-compatible = "vrtc";
+					regulator-name = "vrtc,pmu_vccadc";
+					regulator-always-on;
+				};
+			};
+		};
+	};
+
+	pmc {
+		nvidia,invert-interrupt;
 	};
 
 	usb@c5000000 {
@@ -284,6 +562,21 @@
 		bus-width = <8>;
 	};
 
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		usb0_vbus_reg: regulator {
+			compatible = "regulator-fixed";
+			reg = <0>;
+			regulator-name = "usb0_vbus";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			regulator-always-on;
+		};
+	};
+
 	sound {
 		compatible = "nvidia,tegra-audio-wm8753-whistler",
 			     "nvidia,tegra-audio-wm8753";
diff --git a/arch/arm/boot/dts/tegra30-cardhu-a02.dts b/arch/arm/boot/dts/tegra30-cardhu-a02.dts
new file mode 100644
index 0000000..dd4222f
--- /dev/null
+++ b/arch/arm/boot/dts/tegra30-cardhu-a02.dts
@@ -0,0 +1,87 @@
+/dts-v1/;
+
+/include/ "tegra30-cardhu.dtsi"
+
+/* This dts file support the cardhu A02 version of board */
+
+/ {
+	model = "NVIDIA Tegra30 Cardhu A02 evaluation board";
+	compatible = "nvidia,cardhu-a02", "nvidia,cardhu", "nvidia,tegra30";
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ddr_reg: regulator@100 {
+			compatible = "regulator-fixed";
+			reg = <100>;
+			regulator-name = "vdd_ddr";
+			regulator-min-microvolt = <1500000>;
+			regulator-max-microvolt = <1500000>;
+			regulator-always-on;
+			regulator-boot-on;
+			enable-active-high;
+			gpio = <&pmic 6 0>;
+		};
+
+		sys_3v3_reg: regulator@101 {
+			compatible = "regulator-fixed";
+			reg = <101>;
+			regulator-name = "sys_3v3";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-always-on;
+			regulator-boot-on;
+			enable-active-high;
+			gpio = <&pmic 7 0>;
+		};
+
+		usb1_vbus_reg: regulator@102 {
+			compatible = "regulator-fixed";
+			reg = <102>;
+			regulator-name = "usb1_vbus";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			gpio = <&gpio 68 0>; /* GPIO PI4 */
+			gpio-open-drain;
+			vin-supply = <&vdd_5v0_reg>;
+		};
+
+		usb3_vbus_reg: regulator@103 {
+			compatible = "regulator-fixed";
+			reg = <103>;
+			regulator-name = "usb3_vbus";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			gpio = <&gpio 63 0>; /* GPIO PH7 */
+			gpio-open-drain;
+			vin-supply = <&vdd_5v0_reg>;
+		};
+
+		vdd_5v0_reg: regulator@104 {
+			compatible = "regulator-fixed";
+			reg = <104>;
+			regulator-name = "5v0";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			gpio = <&pmic 2 0>;
+		};
+
+		vdd_bl_reg: regulator@105 {
+			compatible = "regulator-fixed";
+			reg = <105>;
+			regulator-name = "vdd_bl";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			regulator-always-on;
+			regulator-boot-on;
+			enable-active-high;
+			gpio = <&gpio 83 0>; /* GPIO PK3 */
+		};
+	};
+};
+
diff --git a/arch/arm/boot/dts/tegra30-cardhu-a04.dts b/arch/arm/boot/dts/tegra30-cardhu-a04.dts
new file mode 100644
index 0000000..0828f09
--- /dev/null
+++ b/arch/arm/boot/dts/tegra30-cardhu-a04.dts
@@ -0,0 +1,98 @@
+/dts-v1/;
+
+/include/ "tegra30-cardhu.dtsi"
+
+/* This dts file support the cardhu A04 and later versions of board */
+
+/ {
+	model = "NVIDIA Tegra30 Cardhu A04 (A05, A06, A07) evaluation board";
+	compatible = "nvidia,cardhu-a04", "nvidia,cardhu", "nvidia,tegra30";
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ddr_reg: regulator@100 {
+			compatible = "regulator-fixed";
+			regulator-name = "ddr";
+			reg = <100>;
+			regulator-min-microvolt = <1500000>;
+			regulator-max-microvolt = <1500000>;
+			regulator-always-on;
+			regulator-boot-on;
+			enable-active-high;
+			gpio = <&pmic 7 0>;
+		};
+
+		sys_3v3_reg: regulator@101 {
+			compatible = "regulator-fixed";
+			reg = <101>;
+			regulator-name = "sys_3v3";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-always-on;
+			regulator-boot-on;
+			enable-active-high;
+			gpio = <&pmic 6 0>;
+		};
+
+		usb1_vbus_reg: regulator@102 {
+			compatible = "regulator-fixed";
+			reg = <102>;
+			regulator-name = "usb1_vbus";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			gpio = <&gpio 238 0>; /* GPIO PDD6 */
+			gpio-open-drain;
+			vin-supply = <&vdd_5v0_reg>;
+		};
+
+		usb3_vbus_reg: regulator@103 {
+			compatible = "regulator-fixed";
+			reg = <103>;
+			regulator-name = "usb3_vbus";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			gpio = <&gpio 236 0>; /* GPIO PDD4 */
+			gpio-open-drain;
+			vin-supply = <&vdd_5v0_reg>;
+		};
+
+		vdd_5v0_reg: regulator@104 {
+			compatible = "regulator-fixed";
+			reg = <104>;
+			regulator-name = "5v0";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			gpio = <&pmic 8 0>;
+		};
+
+		vdd_bl_reg: regulator@105 {
+			compatible = "regulator-fixed";
+			reg = <105>;
+			regulator-name = "vdd_bl";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			regulator-always-on;
+			regulator-boot-on;
+			enable-active-high;
+			gpio = <&gpio 234 0>; /* GPIO PDD2 */
+		};
+
+		vdd_bl2_reg: regulator@106 {
+			compatible = "regulator-fixed";
+			reg = <106>;
+			regulator-name = "vdd_bl2";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			regulator-always-on;
+			regulator-boot-on;
+			enable-active-high;
+			gpio = <&gpio 232 0>; /* GPIO PDD0 */
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/tegra30-cardhu.dts b/arch/arm/boot/dts/tegra30-cardhu.dts
deleted file mode 100644
index c169bce..0000000
--- a/arch/arm/boot/dts/tegra30-cardhu.dts
+++ /dev/null
@@ -1,171 +0,0 @@
-/dts-v1/;
-
-/include/ "tegra30.dtsi"
-
-/ {
-	model = "NVIDIA Tegra30 Cardhu evaluation board";
-	compatible = "nvidia,cardhu", "nvidia,tegra30";
-
-	memory {
-		reg = <0x80000000 0x40000000>;
-	};
-
-	pinmux {
-		pinctrl-names = "default";
-		pinctrl-0 = <&state_default>;
-
-		state_default: pinmux {
-			sdmmc1_clk_pz0 {
-				nvidia,pins = "sdmmc1_clk_pz0";
-				nvidia,function = "sdmmc1";
-				nvidia,pull = <0>;
-				nvidia,tristate = <0>;
-			};
-			sdmmc1_cmd_pz1 {
-				nvidia,pins =	"sdmmc1_cmd_pz1",
-						"sdmmc1_dat0_py7",
-						"sdmmc1_dat1_py6",
-						"sdmmc1_dat2_py5",
-						"sdmmc1_dat3_py4";
-				nvidia,function = "sdmmc1";
-				nvidia,pull = <2>;
-				nvidia,tristate = <0>;
-			};
-			sdmmc4_clk_pcc4 {
-				nvidia,pins =	"sdmmc4_clk_pcc4",
-						"sdmmc4_rst_n_pcc3";
-				nvidia,function = "sdmmc4";
-				nvidia,pull = <0>;
-				nvidia,tristate = <0>;
-			};
-			sdmmc4_dat0_paa0 {
-				nvidia,pins =	"sdmmc4_dat0_paa0",
-						"sdmmc4_dat1_paa1",
-						"sdmmc4_dat2_paa2",
-						"sdmmc4_dat3_paa3",
-						"sdmmc4_dat4_paa4",
-						"sdmmc4_dat5_paa5",
-						"sdmmc4_dat6_paa6",
-						"sdmmc4_dat7_paa7";
-				nvidia,function = "sdmmc4";
-				nvidia,pull = <2>;
-				nvidia,tristate = <0>;
-			};
-			dap2_fs_pa2 {
-				nvidia,pins =	"dap2_fs_pa2",
-						"dap2_sclk_pa3",
-						"dap2_din_pa4",
-						"dap2_dout_pa5";
-				nvidia,function = "i2s1";
-				nvidia,pull = <0>;
-				nvidia,tristate = <0>;
-			};
-		};
-	};
-
-	serial@70006000 {
-		status = "okay";
-		clock-frequency = <408000000>;
-	};
-
-	i2c@7000c000 {
-		status = "okay";
-		clock-frequency = <100000>;
-	};
-
-	i2c@7000c400 {
-		status = "okay";
-		clock-frequency = <100000>;
-	};
-
-	i2c@7000c500 {
-		status = "okay";
-		clock-frequency = <100000>;
-
-		/* ALS and Proximity sensor */
-		isl29028@44 {
-			compatible = "isil,isl29028";
-			reg = <0x44>;
-			interrupt-parent = <&gpio>;
-			interrupts = <88 0x04>; /*gpio PL0 */
-		};
-	};
-
-	i2c@7000c700 {
-		status = "okay";
-		clock-frequency = <100000>;
-	};
-
-	i2c@7000d000 {
-		status = "okay";
-		clock-frequency = <100000>;
-
-		wm8903: wm8903@1a {
-			compatible = "wlf,wm8903";
-			reg = <0x1a>;
-			interrupt-parent = <&gpio>;
-			interrupts = <179 0x04>; /* gpio PW3 */
-
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			micdet-cfg = <0>;
-			micdet-delay = <100>;
-			gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>;
-		};
-
-		tps62361 {
-			compatible = "ti,tps62361";
-			reg = <0x60>;
-
-			regulator-name = "tps62361-vout";
-			regulator-min-microvolt = <500000>;
-			regulator-max-microvolt = <1500000>;
-			regulator-boot-on;
-			regulator-always-on;
-			ti,vsel0-state-high;
-			ti,vsel1-state-high;
-		};
-	};
-
-	ahub {
-		i2s@70080400 {
-			status = "okay";
-		};
-	};
-
-	sdhci@78000000 {
-		status = "okay";
-		cd-gpios = <&gpio 69 0>; /* gpio PI5 */
-		wp-gpios = <&gpio 155 0>; /* gpio PT3 */
-		power-gpios = <&gpio 31 0>; /* gpio PD7 */
-		bus-width = <4>;
-	};
-
-	sdhci@78000600 {
-		status = "okay";
-		bus-width = <8>;
-	};
-
-	sound {
-		compatible = "nvidia,tegra-audio-wm8903-cardhu",
-			     "nvidia,tegra-audio-wm8903";
-		nvidia,model = "NVIDIA Tegra Cardhu";
-
-		nvidia,audio-routing =
-			"Headphone Jack", "HPOUTR",
-			"Headphone Jack", "HPOUTL",
-			"Int Spk", "ROP",
-			"Int Spk", "RON",
-			"Int Spk", "LOP",
-			"Int Spk", "LON",
-			"Mic Jack", "MICBIAS",
-			"IN1L", "Mic Jack";
-
-		nvidia,i2s-controller = <&tegra_i2s1>;
-		nvidia,audio-codec = <&wm8903>;
-
-		nvidia,spkr-en-gpios = <&wm8903 2 0>;
-		nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
-	};
-};
diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi
new file mode 100644
index 0000000..4794693
--- /dev/null
+++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi
@@ -0,0 +1,473 @@
+/include/ "tegra30.dtsi"
+
+/**
+ * This file contains common DT entry for all fab version of Cardhu.
+ * There is multiple fab version of Cardhu starting from A01 to A07.
+ * Cardhu fab version A01 and A03 are not supported. Cardhu fab version
+ * A02 will have different sets of GPIOs for fixed regulator compare to
+ * Cardhu fab version A04. The Cardhu fab version A05, A06, A07 are
+ * compatible with fab version A04. Based on Cardhu fab version, the
+ * related dts file need to be chosen like for Cardhu fab version A02,
+ * use tegra30-cardhu-a02.dts, Cardhu fab version A04 and later, use
+ * tegra30-cardhu-a04.dts.
+ * The identification of board is done in two ways, by looking the sticker
+ * on PCB and by reading board id eeprom.
+ * The stciker will have number like 600-81291-1000-002 C.3. In this 4th
+ * number is the fab version like here it is 002 and hence fab version A02.
+ * The (downstream internal) U-Boot of Cardhu display the board-id as
+ * follows:
+ * BoardID: 0C5B, SKU: 0A01, Fab: 02, Rev: 45.00
+ * In this Fab version is 02 i.e. A02.
+ * The BoardID I2C eeprom is interfaced through i2c5 (pwr_i2c address 0x56).
+ * The location 0x8 of this eeprom contains the Fab version. It is 1 byte
+ * wide.
+ */
+
+/ {
+	model = "NVIDIA Tegra30 Cardhu evaluation board";
+	compatible = "nvidia,cardhu", "nvidia,tegra30";
+
+	memory {
+		reg = <0x80000000 0x40000000>;
+	};
+
+	pinmux {
+		pinctrl-names = "default";
+		pinctrl-0 = <&state_default>;
+
+		state_default: pinmux {
+			sdmmc1_clk_pz0 {
+				nvidia,pins = "sdmmc1_clk_pz0";
+				nvidia,function = "sdmmc1";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			sdmmc1_cmd_pz1 {
+				nvidia,pins =	"sdmmc1_cmd_pz1",
+						"sdmmc1_dat0_py7",
+						"sdmmc1_dat1_py6",
+						"sdmmc1_dat2_py5",
+						"sdmmc1_dat3_py4";
+				nvidia,function = "sdmmc1";
+				nvidia,pull = <2>;
+				nvidia,tristate = <0>;
+			};
+			sdmmc4_clk_pcc4 {
+				nvidia,pins =	"sdmmc4_clk_pcc4",
+						"sdmmc4_rst_n_pcc3";
+				nvidia,function = "sdmmc4";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			sdmmc4_dat0_paa0 {
+				nvidia,pins =	"sdmmc4_dat0_paa0",
+						"sdmmc4_dat1_paa1",
+						"sdmmc4_dat2_paa2",
+						"sdmmc4_dat3_paa3",
+						"sdmmc4_dat4_paa4",
+						"sdmmc4_dat5_paa5",
+						"sdmmc4_dat6_paa6",
+						"sdmmc4_dat7_paa7";
+				nvidia,function = "sdmmc4";
+				nvidia,pull = <2>;
+				nvidia,tristate = <0>;
+			};
+			dap2_fs_pa2 {
+				nvidia,pins =	"dap2_fs_pa2",
+						"dap2_sclk_pa3",
+						"dap2_din_pa4",
+						"dap2_dout_pa5";
+				nvidia,function = "i2s1";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+		};
+	};
+
+	serial@70006000 {
+		status = "okay";
+		clock-frequency = <408000000>;
+	};
+
+	i2c@7000c000 {
+		status = "okay";
+		clock-frequency = <100000>;
+	};
+
+	i2c@7000c400 {
+		status = "okay";
+		clock-frequency = <100000>;
+	};
+
+	i2c@7000c500 {
+		status = "okay";
+		clock-frequency = <100000>;
+
+		/* ALS and Proximity sensor */
+		isl29028@44 {
+			compatible = "isil,isl29028";
+			reg = <0x44>;
+			interrupt-parent = <&gpio>;
+			interrupts = <88 0x04>; /*gpio PL0 */
+		};
+	};
+
+	i2c@7000c700 {
+		status = "okay";
+		clock-frequency = <100000>;
+	};
+
+	i2c@7000d000 {
+		status = "okay";
+		clock-frequency = <100000>;
+
+		wm8903: wm8903@1a {
+			compatible = "wlf,wm8903";
+			reg = <0x1a>;
+			interrupt-parent = <&gpio>;
+			interrupts = <179 0x04>; /* gpio PW3 */
+
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			micdet-cfg = <0>;
+			micdet-delay = <100>;
+			gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>;
+		};
+
+		tps62361 {
+			compatible = "ti,tps62361";
+			reg = <0x60>;
+
+			regulator-name = "tps62361-vout";
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1500000>;
+			regulator-boot-on;
+			regulator-always-on;
+			ti,vsel0-state-high;
+			ti,vsel1-state-high;
+		};
+
+		pmic: tps65911@2d {
+			compatible = "ti,tps65911";
+			reg = <0x2d>;
+
+			interrupts = <0 86 0x4>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+
+			#gpio-cells = <2>;
+			gpio-controller;
+
+			vcc1-supply = <&vdd_ac_bat_reg>;
+			vcc2-supply = <&vdd_ac_bat_reg>;
+			vcc3-supply = <&vio_reg>;
+			vcc4-supply = <&vdd_5v0_reg>;
+			vcc5-supply = <&vdd_ac_bat_reg>;
+			vcc6-supply = <&vdd2_reg>;
+			vcc7-supply = <&vdd_ac_bat_reg>;
+			vccio-supply = <&vdd_ac_bat_reg>;
+
+			regulators {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				vdd1_reg: regulator@0 {
+					reg = <0>;
+					regulator-compatible = "vdd1";
+					regulator-name = "vddio_ddr_1v2";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+					regulator-always-on;
+				};
+
+				vdd2_reg: regulator@1 {
+					reg = <1>;
+					regulator-compatible = "vdd2";
+					regulator-name = "vdd_1v5_gen";
+					regulator-min-microvolt = <1500000>;
+					regulator-max-microvolt = <1500000>;
+					regulator-always-on;
+				};
+
+				vddctrl_reg: regulator@2 {
+					reg = <2>;
+					regulator-compatible = "vddctrl";
+					regulator-name = "vdd_cpu,vdd_sys";
+					regulator-min-microvolt = <1000000>;
+					regulator-max-microvolt = <1000000>;
+					regulator-always-on;
+				};
+
+				vio_reg: regulator@3 {
+					reg = <3>;
+					regulator-compatible = "vio";
+					regulator-name = "vdd_1v8_gen";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+					regulator-always-on;
+				};
+
+				ldo1_reg: regulator@4 {
+					reg = <4>;
+					regulator-compatible = "ldo1";
+					regulator-name = "vdd_pexa,vdd_pexb";
+					regulator-min-microvolt = <1050000>;
+					regulator-max-microvolt = <1050000>;
+				};
+
+				ldo2_reg: regulator@5 {
+					reg = <5>;
+					regulator-compatible = "ldo2";
+					regulator-name = "vdd_sata,avdd_plle";
+					regulator-min-microvolt = <1050000>;
+					regulator-max-microvolt = <1050000>;
+				};
+
+				/* LDO3 is not connected to anything */
+
+				ldo4_reg: regulator@7 {
+					reg = <7>;
+					regulator-compatible = "ldo4";
+					regulator-name = "vdd_rtc";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+					regulator-always-on;
+				};
+
+				ldo5_reg: regulator@8 {
+					reg = <8>;
+					regulator-compatible = "ldo5";
+					regulator-name = "vddio_sdmmc,avdd_vdac";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+					regulator-always-on;
+				};
+
+				ldo6_reg: regulator@9 {
+					reg = <9>;
+					regulator-compatible = "ldo6";
+					regulator-name = "avdd_dsi_csi,pwrdet_mipi";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+				};
+
+				ldo7_reg: regulator@10 {
+					reg = <10>;
+					regulator-compatible = "ldo7";
+					regulator-name = "vdd_pllm,x,u,a_p_c_s";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+					regulator-always-on;
+				};
+
+				ldo8_reg: regulator@11 {
+					reg = <11>;
+					regulator-compatible = "ldo8";
+					regulator-name = "vdd_ddr_hs";
+					regulator-min-microvolt = <1000000>;
+					regulator-max-microvolt = <1000000>;
+					regulator-always-on;
+				};
+			};
+		};
+	};
+
+	ahub {
+		i2s@70080400 {
+			status = "okay";
+		};
+	};
+
+	pmc {
+		status = "okay";
+		nvidia,invert-interrupt;
+	};
+
+	sdhci@78000000 {
+		status = "okay";
+		cd-gpios = <&gpio 69 0>; /* gpio PI5 */
+		wp-gpios = <&gpio 155 0>; /* gpio PT3 */
+		power-gpios = <&gpio 31 0>; /* gpio PD7 */
+		bus-width = <4>;
+	};
+
+	sdhci@78000600 {
+		status = "okay";
+		bus-width = <8>;
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vdd_ac_bat_reg: regulator@0 {
+			compatible = "regulator-fixed";
+			reg = <0>;
+			regulator-name = "vdd_ac_bat";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			regulator-always-on;
+		};
+
+		cam_1v8_reg: regulator@1 {
+			compatible = "regulator-fixed";
+			reg = <1>;
+			regulator-name = "cam_1v8";
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			enable-active-high;
+			gpio = <&gpio 220 0>; /* gpio PBB4 */
+			vin-supply = <&vio_reg>;
+		};
+
+		cp_5v_reg: regulator@2 {
+			compatible = "regulator-fixed";
+			reg = <2>;
+			regulator-name = "cp_5v";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			regulator-boot-on;
+			regulator-always-on;
+			enable-active-high;
+			gpio = <&pmic 0 0>; /* PMIC TPS65911 GPIO0 */
+		};
+
+		emmc_3v3_reg: regulator@3 {
+			compatible = "regulator-fixed";
+			reg = <3>;
+			regulator-name = "emmc_3v3";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-always-on;
+			regulator-boot-on;
+			enable-active-high;
+			gpio = <&gpio 25 0>; /* gpio PD1 */
+			vin-supply = <&sys_3v3_reg>;
+		};
+
+		modem_3v3_reg: regulator@4 {
+			compatible = "regulator-fixed";
+			reg = <4>;
+			regulator-name = "modem_3v3";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			enable-active-high;
+			gpio = <&gpio 30 0>; /* gpio PD6 */
+		};
+
+		pex_hvdd_3v3_reg: regulator@5 {
+			compatible = "regulator-fixed";
+			reg = <5>;
+			regulator-name = "pex_hvdd_3v3";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			enable-active-high;
+			gpio = <&gpio 95 0>; /* gpio PL7 */
+			vin-supply = <&sys_3v3_reg>;
+		};
+
+		vdd_cam1_ldo_reg: regulator@6 {
+			compatible = "regulator-fixed";
+			reg = <6>;
+			regulator-name = "vdd_cam1_ldo";
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+			enable-active-high;
+			gpio = <&gpio 142 0>; /* gpio PR6 */
+			vin-supply = <&sys_3v3_reg>;
+		};
+
+		vdd_cam2_ldo_reg: regulator@7 {
+			compatible = "regulator-fixed";
+			reg = <7>;
+			regulator-name = "vdd_cam2_ldo";
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+			enable-active-high;
+			gpio = <&gpio 143 0>; /* gpio PR7 */
+			vin-supply = <&sys_3v3_reg>;
+		};
+
+		vdd_cam3_ldo_reg: regulator@8 {
+			compatible = "regulator-fixed";
+			reg = <8>;
+			regulator-name = "vdd_cam3_ldo";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			enable-active-high;
+			gpio = <&gpio 144 0>; /* gpio PS0 */
+			vin-supply = <&sys_3v3_reg>;
+		};
+
+		vdd_com_reg: regulator@9 {
+			compatible = "regulator-fixed";
+			reg = <9>;
+			regulator-name = "vdd_com";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			enable-active-high;
+			gpio = <&gpio 24 0>; /* gpio PD0 */
+			vin-supply = <&sys_3v3_reg>;
+		};
+
+		vdd_fuse_3v3_reg: regulator@10 {
+			compatible = "regulator-fixed";
+			reg = <10>;
+			regulator-name = "vdd_fuse_3v3";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			enable-active-high;
+			gpio = <&gpio 94 0>; /* gpio PL6 */
+			vin-supply = <&sys_3v3_reg>;
+		};
+
+		vdd_pnl1_reg: regulator@11 {
+			compatible = "regulator-fixed";
+			reg = <11>;
+			regulator-name = "vdd_pnl1";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-always-on;
+			regulator-boot-on;
+			enable-active-high;
+			gpio = <&gpio 92 0>; /* gpio PL4 */
+			vin-supply = <&sys_3v3_reg>;
+		};
+
+		vdd_vid_reg: regulator@12 {
+			compatible = "regulator-fixed";
+			reg = <12>;
+			regulator-name = "vddio_vid";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			gpio = <&gpio 152 0>; /* GPIO PT0 */
+			gpio-open-drain;
+			vin-supply = <&vdd_5v0_reg>;
+		};
+	};
+
+	sound {
+		compatible = "nvidia,tegra-audio-wm8903-cardhu",
+			     "nvidia,tegra-audio-wm8903";
+		nvidia,model = "NVIDIA Tegra Cardhu";
+
+		nvidia,audio-routing =
+			"Headphone Jack", "HPOUTR",
+			"Headphone Jack", "HPOUTL",
+			"Int Spk", "ROP",
+			"Int Spk", "RON",
+			"Int Spk", "LOP",
+			"Int Spk", "LON",
+			"Mic Jack", "MICBIAS",
+			"IN1L", "Mic Jack";
+
+		nvidia,i2s-controller = <&tegra_i2s1>;
+		nvidia,audio-codec = <&wm8903>;
+
+		nvidia,spkr-en-gpios = <&wm8903 2 0>;
+		nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
+	};
+};
diff --git a/arch/arm/boot/dts/twl6030.dtsi b/arch/arm/boot/dts/twl6030.dtsi
index 3b2f351..d351b27 100644
--- a/arch/arm/boot/dts/twl6030.dtsi
+++ b/arch/arm/boot/dts/twl6030.dtsi
@@ -66,6 +66,7 @@
 
 	vcxio: regulator@8 {
 		compatible = "ti,twl6030-vcxio";
+		regulator-always-on;
 	};
 
 	vusb: regulator@9 {
@@ -74,10 +75,12 @@
 
 	v1v8: regulator@10 {
 		compatible = "ti,twl6030-v1v8";
+		regulator-always-on;
 	};
 
 	v2v1: regulator@11 {
 		compatible = "ti,twl6030-v2v1";
+		regulator-always-on;
 	};
 
 	clk32kg: regulator@12 {
diff --git a/arch/arm/configs/afeb9260_defconfig b/arch/arm/configs/afeb9260_defconfig
index 2afdf67..c285a9d 100644
--- a/arch/arm/configs/afeb9260_defconfig
+++ b/arch/arm/configs/afeb9260_defconfig
@@ -39,7 +39,6 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_DATAFLASH=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_ATMEL_SSC=y
diff --git a/arch/arm/configs/at91rm9200_defconfig b/arch/arm/configs/at91rm9200_defconfig
index d54e2ac..4ae57a3 100644
--- a/arch/arm/configs/at91rm9200_defconfig
+++ b/arch/arm/configs/at91rm9200_defconfig
@@ -232,7 +232,7 @@ CONFIG_USB_GADGET=y
 CONFIG_USB_ETH=m
 CONFIG_USB_MASS_STORAGE=m
 CONFIG_MMC=y
-CONFIG_MMC_AT91=y
+CONFIG_MMC_ATMELMCI=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
diff --git a/arch/arm/configs/at91sam9261_defconfig b/arch/arm/configs/at91sam9261_defconfig
index ade6b2f..1e8712e 100644
--- a/arch/arm/configs/at91sam9261_defconfig
+++ b/arch/arm/configs/at91sam9261_defconfig
@@ -128,7 +128,7 @@ CONFIG_USB_GADGETFS=m
 CONFIG_USB_FILE_STORAGE=m
 CONFIG_USB_G_SERIAL=m
 CONFIG_MMC=y
-CONFIG_MMC_AT91=m
+CONFIG_MMC_ATMELMCI=m
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
diff --git a/arch/arm/configs/at91sam9263_defconfig b/arch/arm/configs/at91sam9263_defconfig
index 1cf9626..d2050ca 100644
--- a/arch/arm/configs/at91sam9263_defconfig
+++ b/arch/arm/configs/at91sam9263_defconfig
@@ -61,7 +61,6 @@ CONFIG_MTD_DATAFLASH=y
 CONFIG_MTD_BLOCK2MTD=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
 CONFIG_MTD_UBI=y
 CONFIG_MTD_UBI_GLUEBI=y
 CONFIG_BLK_DEV_LOOP=y
@@ -138,7 +137,7 @@ CONFIG_USB_FILE_STORAGE=m
 CONFIG_USB_G_SERIAL=m
 CONFIG_MMC=y
 CONFIG_SDIO_UART=m
-CONFIG_MMC_AT91=m
+CONFIG_MMC_ATMELMCI=m
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_ATMEL_PWM=y
diff --git a/arch/arm/configs/at91sam9g20_defconfig b/arch/arm/configs/at91sam9g20_defconfig
index 994d331..e1b0e80 100644
--- a/arch/arm/configs/at91sam9g20_defconfig
+++ b/arch/arm/configs/at91sam9g20_defconfig
@@ -99,7 +99,7 @@ CONFIG_USB_GADGETFS=m
 CONFIG_USB_FILE_STORAGE=m
 CONFIG_USB_G_SERIAL=m
 CONFIG_MMC=y
-CONFIG_MMC_AT91=m
+CONFIG_MMC_ATMELMCI=m
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
diff --git a/arch/arm/configs/at91sam9rl_defconfig b/arch/arm/configs/at91sam9rl_defconfig
index ad562ee..7cf8785 100644
--- a/arch/arm/configs/at91sam9rl_defconfig
+++ b/arch/arm/configs/at91sam9rl_defconfig
@@ -60,7 +60,7 @@ CONFIG_AT91SAM9X_WATCHDOG=y
 CONFIG_FB=y
 CONFIG_FB_ATMEL=y
 CONFIG_MMC=y
-CONFIG_MMC_AT91=m
+CONFIG_MMC_ATMELMCI=m
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_AT91SAM9=y
 CONFIG_EXT2_FS=y
diff --git a/arch/arm/configs/cpu9260_defconfig b/arch/arm/configs/cpu9260_defconfig
index bbf729e..921480c 100644
--- a/arch/arm/configs/cpu9260_defconfig
+++ b/arch/arm/configs/cpu9260_defconfig
@@ -82,7 +82,7 @@ CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_ETH=m
 CONFIG_MMC=y
-CONFIG_MMC_AT91=m
+CONFIG_MMC_ATMELMCI=m
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
diff --git a/arch/arm/configs/cpu9g20_defconfig b/arch/arm/configs/cpu9g20_defconfig
index e7d7942..ea116cb 100644
--- a/arch/arm/configs/cpu9g20_defconfig
+++ b/arch/arm/configs/cpu9g20_defconfig
@@ -82,7 +82,7 @@ CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_ETH=m
 CONFIG_MMC=y
-CONFIG_MMC_AT91=m
+CONFIG_MMC_ATMELMCI=m
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
diff --git a/arch/arm/configs/qil-a9260_defconfig b/arch/arm/configs/qil-a9260_defconfig
index 9160f3b..42d5db1 100644
--- a/arch/arm/configs/qil-a9260_defconfig
+++ b/arch/arm/configs/qil-a9260_defconfig
@@ -50,7 +50,6 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_DATAFLASH=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_MISC_DEVICES is not set
 CONFIG_SCSI=y
@@ -87,7 +86,7 @@ CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_ETH=m
 CONFIG_MMC=y
-CONFIG_MMC_AT91=m
+CONFIG_MMC_ATMELMCI=m
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
diff --git a/arch/arm/configs/sam9_l9260_defconfig b/arch/arm/configs/sam9_l9260_defconfig
index ecf2531..da276f9 100644
--- a/arch/arm/configs/sam9_l9260_defconfig
+++ b/arch/arm/configs/sam9_l9260_defconfig
@@ -39,7 +39,7 @@ CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
 CONFIG_MTD_NAND_PLATFORM=y
 CONFIG_MTD_UBI=y
-CONFIG_MTD_UBI_BEB_RESERVE=3
+CONFIG_MTD_UBI_BEB_LIMIT=3
 CONFIG_MTD_UBI_GLUEBI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
diff --git a/arch/arm/configs/stamp9g20_defconfig b/arch/arm/configs/stamp9g20_defconfig
index d5e260b..52f1488 100644
--- a/arch/arm/configs/stamp9g20_defconfig
+++ b/arch/arm/configs/stamp9g20_defconfig
@@ -100,7 +100,6 @@ CONFIG_USB_ETH=m
 CONFIG_USB_FILE_STORAGE=m
 CONFIG_USB_G_SERIAL=m
 CONFIG_MMC=y
-# CONFIG_MMC_AT91 is not set
 CONFIG_MMC_ATMELMCI=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index db22453..c7f7c7f 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -24,13 +24,14 @@ CONFIG_EFI_PARTITION=y
 # CONFIG_IOSCHED_DEADLINE is not set
 # CONFIG_IOSCHED_CFQ is not set
 CONFIG_ARCH_TEGRA=y
+CONFIG_GPIO_PCA953X=y
 CONFIG_ARCH_TEGRA_2x_SOC=y
 CONFIG_ARCH_TEGRA_3x_SOC=y
-CONFIG_MACH_HARMONY=y
-CONFIG_MACH_PAZ00=y
-CONFIG_MACH_TRIMSLICE=y
+CONFIG_TEGRA_PCI=y
+CONFIG_TEGRA_DEBUG_UART_AUTO_ODMDATA=y
 CONFIG_TEGRA_EMC_SCALING_ENABLE=y
 CONFIG_SMP=y
+CONFIG_HOTPLUG_CPU=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 # CONFIG_OABI_COMPAT is not set
@@ -105,17 +106,20 @@ CONFIG_I2C_MUX_PINCTRL=y
 CONFIG_I2C_TEGRA=y
 CONFIG_SPI=y
 CONFIG_SPI_TEGRA=y
-CONFIG_GPIO_TPS65910=y
+CONFIG_GPIO_PCA953X_IRQ=y
 CONFIG_GPIO_TPS6586X=y
+CONFIG_GPIO_TPS65910=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_BATTERY_SBS=y
 CONFIG_SENSORS_LM90=y
 CONFIG_MFD_TPS6586X=y
 CONFIG_MFD_TPS65910=y
+CONFIG_MFD_MAX8907=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
 CONFIG_REGULATOR_GPIO=y
+CONFIG_REGULATOR_MAX8907=y
 CONFIG_REGULATOR_TPS62360=y
 CONFIG_REGULATOR_TPS6586X=y
 CONFIG_REGULATOR_TPS65910=y
@@ -123,7 +127,6 @@ CONFIG_SOUND=y
 CONFIG_SND=y
 # CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_DRIVERS is not set
-# CONFIG_SND_PCI is not set
 # CONFIG_SND_ARM is not set
 # CONFIG_SND_SPI is not set
 # CONFIG_SND_USB is not set
@@ -143,6 +146,7 @@ CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_SDHCI_TEGRA=y
 CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_MAX8907=y
 CONFIG_RTC_DRV_EM3027=y
 CONFIG_RTC_DRV_TEGRA=y
 CONFIG_STAGING=y
@@ -156,6 +160,8 @@ CONFIG_TEGRA_IOMMU_GART=y
 CONFIG_TEGRA_IOMMU_SMMU=y
 CONFIG_MEMORY=y
 CONFIG_IIO=y
+CONFIG_PWM=y
+CONFIG_PWM_TEGRA=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
diff --git a/arch/arm/configs/usb-a9260_defconfig b/arch/arm/configs/usb-a9260_defconfig
index 2e39f38..a1501e1 100644
--- a/arch/arm/configs/usb-a9260_defconfig
+++ b/arch/arm/configs/usb-a9260_defconfig
@@ -49,7 +49,6 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_DATAFLASH=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_MISC_DEVICES is not set
 CONFIG_SCSI=y
diff --git a/arch/arm/include/asm/hardware/cache-tauros2.h b/arch/arm/include/asm/hardware/cache-tauros2.h
index 538f17c..295e2e4 100644
--- a/arch/arm/include/asm/hardware/cache-tauros2.h
+++ b/arch/arm/include/asm/hardware/cache-tauros2.h
@@ -8,4 +8,7 @@
  * warranty of any kind, whether express or implied.
  */
 
-extern void __init tauros2_init(void);
+#define CACHE_TAUROS2_PREFETCH_ON	(1 << 0)
+#define CACHE_TAUROS2_LINEFILL_BURST8	(1 << 1)
+
+extern void __init tauros2_init(unsigned int features);
diff --git a/arch/arm/include/asm/hardware/iop3xx.h b/arch/arm/include/asm/hardware/iop3xx.h
index 2ff2c75..02fe2fb 100644
--- a/arch/arm/include/asm/hardware/iop3xx.h
+++ b/arch/arm/include/asm/hardware/iop3xx.h
@@ -217,18 +217,8 @@ extern int iop3xx_get_init_atu(void);
 #define IOP3XX_PCI_LOWER_MEM_PA	0x80000000
 #define IOP3XX_PCI_MEM_WINDOW_SIZE	0x08000000
 
-#define IOP3XX_PCI_IO_WINDOW_SIZE	0x00010000
 #define IOP3XX_PCI_LOWER_IO_PA		0x90000000
-#define IOP3XX_PCI_LOWER_IO_VA		0xfe000000
-#define IOP3XX_PCI_LOWER_IO_BA		0x90000000
-#define IOP3XX_PCI_UPPER_IO_PA		(IOP3XX_PCI_LOWER_IO_PA +\
-					IOP3XX_PCI_IO_WINDOW_SIZE - 1)
-#define IOP3XX_PCI_UPPER_IO_VA		(IOP3XX_PCI_LOWER_IO_VA +\
-					IOP3XX_PCI_IO_WINDOW_SIZE - 1)
-#define IOP3XX_PCI_IO_PHYS_TO_VIRT(addr) (((u32) (addr) -\
-					IOP3XX_PCI_LOWER_IO_PA) +\
-					IOP3XX_PCI_LOWER_IO_VA)
-
+#define IOP3XX_PCI_LOWER_IO_BA		0x00000000
 
 #ifndef __ASSEMBLY__
 
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 815c669..8f4db67 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -113,11 +113,19 @@ static inline void __iomem *__typesafe_io(unsigned long addr)
 #define __iowmb()		do { } while (0)
 #endif
 
+/* PCI fixed i/o mapping */
+#define PCI_IO_VIRT_BASE	0xfee00000
+
+extern int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr);
+
 /*
  * Now, pick up the machine-defined IO definitions
  */
 #ifdef CONFIG_NEED_MACH_IO_H
 #include <mach/io.h>
+#elif defined(CONFIG_PCI)
+#define IO_SPACE_LIMIT	((resource_size_t)0xfffff)
+#define __io(a)		__typesafe_io(PCI_IO_VIRT_BASE + ((a) & IO_SPACE_LIMIT))
 #else
 #define __io(a)		__typesafe_io((a) & IO_SPACE_LIMIT)
 #endif
diff --git a/arch/arm/include/asm/leds.h b/arch/arm/include/asm/leds.h
deleted file mode 100644
index c545739..0000000
--- a/arch/arm/include/asm/leds.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- *  arch/arm/include/asm/leds.h
- *
- *  Copyright (C) 1998 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Event-driven interface for LEDs on machines
- *  Added led_start and led_stop- Alex Holden, 28th Dec 1998.
- */
-#ifndef ASM_ARM_LEDS_H
-#define ASM_ARM_LEDS_H
-
-
-typedef enum {
-	led_idle_start,
-	led_idle_end,
-	led_timer,
-	led_start,
-	led_stop,
-	led_claim,		/* override idle & timer leds */
-	led_release,		/* restore idle & timer leds */
-	led_start_timer_mode,
-	led_stop_timer_mode,
-	led_green_on,
-	led_green_off,
-	led_amber_on,
-	led_amber_off,
-	led_red_on,
-	led_red_off,
-	led_blue_on,
-	led_blue_off,
-	/*
-	 * I want this between led_timer and led_start, but
-	 * someone has decided to export this to user space
-	 */
-	led_halted
-} led_event_t;
-
-/* Use this routine to handle LEDs */
-
-#ifdef CONFIG_LEDS
-extern void (*leds_event)(led_event_t);
-#else
-#define leds_event(e)
-#endif
-
-#endif
diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h
index a6efcdd..195ac2f 100644
--- a/arch/arm/include/asm/mach/map.h
+++ b/arch/arm/include/asm/mach/map.h
@@ -9,6 +9,9 @@
  *
  *  Page table mapping constructs and function prototypes
  */
+#ifndef __ASM_MACH_MAP_H
+#define __ASM_MACH_MAP_H
+
 #include <asm/io.h>
 
 struct map_desc {
@@ -34,6 +37,8 @@ struct map_desc {
 
 #ifdef CONFIG_MMU
 extern void iotable_init(struct map_desc *, int);
+extern void vm_reserve_area_early(unsigned long addr, unsigned long size,
+				  void *caller);
 
 struct mem_type;
 extern const struct mem_type *get_mem_type(unsigned int type);
@@ -44,4 +49,7 @@ extern int ioremap_page(unsigned long virt, unsigned long phys,
 			const struct mem_type *mtype);
 #else
 #define iotable_init(map,num)	do { } while (0)
+#define vm_reserve_area_early(a,s,c)	do { } while (0)
+#endif
+
 #endif
diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h
index 26c511f..db9fedb 100644
--- a/arch/arm/include/asm/mach/pci.h
+++ b/arch/arm/include/asm/mach/pci.h
@@ -11,6 +11,8 @@
 #ifndef __ASM_MACH_PCI_H
 #define __ASM_MACH_PCI_H
 
+#include <linux/ioport.h>
+
 struct pci_sys_data;
 struct pci_ops;
 struct pci_bus;
@@ -42,6 +44,8 @@ struct pci_sys_data {
 	unsigned long	io_offset;	/* bus->cpu IO mapping offset		*/
 	struct pci_bus	*bus;		/* PCI bus				*/
 	struct list_head resources;	/* root bus resources (apertures)       */
+	struct resource io_res;
+	char		io_res_name[12];
 					/* Bridge swizzling			*/
 	u8		(*swizzle)(struct pci_dev *, u8 *);
 					/* IRQ mapping				*/
@@ -55,6 +59,15 @@ struct pci_sys_data {
 void pci_common_init(struct hw_pci *);
 
 /*
+ * Setup early fixed I/O mapping.
+ */
+#if defined(CONFIG_PCI)
+extern void pci_map_io_early(unsigned long pfn);
+#else
+static inline void pci_map_io_early(unsigned long pfn) {}
+#endif
+
+/*
  * PCI controllers
  */
 extern struct pci_ops iop3xx_ops;
diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h
index 6c6809f..0d3a28d 100644
--- a/arch/arm/include/asm/module.h
+++ b/arch/arm/include/asm/module.h
@@ -1,9 +1,7 @@
 #ifndef _ASM_ARM_MODULE_H
 #define _ASM_ARM_MODULE_H
 
-#define Elf_Shdr	Elf32_Shdr
-#define Elf_Sym		Elf32_Sym
-#define Elf_Ehdr	Elf32_Ehdr
+#include <asm-generic/module.h>
 
 struct unwind_table;
 
@@ -16,13 +14,11 @@ enum {
 	ARM_SEC_DEVEXIT,
 	ARM_SEC_MAX,
 };
-#endif
 
 struct mod_arch_specific {
-#ifdef CONFIG_ARM_UNWIND
 	struct unwind_table *unwind[ARM_SEC_MAX];
-#endif
 };
+#endif
 
 /*
  * Add the ARM architecture version to the version magic string
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h
index e074948..625cd62 100644
--- a/arch/arm/include/asm/perf_event.h
+++ b/arch/arm/include/asm/perf_event.h
@@ -12,6 +12,13 @@
 #ifndef __ARM_PERF_EVENT_H__
 #define __ARM_PERF_EVENT_H__
 
-/* Nothing to see here... */
+/*
+ * The ARMv7 CPU PMU supports up to 32 event counters.
+ */
+#define ARMPMU_MAX_HWEVENTS		32
+
+#define HW_OP_UNSUPPORTED		0xFFFF
+#define C(_x)				PERF_COUNT_HW_CACHE_##_x
+#define CACHE_OP_UNSUPPORTED		0xFFFF
 
 #endif /* __ARM_PERF_EVENT_H__ */
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index f66626d..41dc31f 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -195,6 +195,18 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd)
 
 #define pte_clear(mm,addr,ptep)	set_pte_ext(ptep, __pte(0), 0)
 
+#define pte_none(pte)		(!pte_val(pte))
+#define pte_present(pte)	(pte_val(pte) & L_PTE_PRESENT)
+#define pte_write(pte)		(!(pte_val(pte) & L_PTE_RDONLY))
+#define pte_dirty(pte)		(pte_val(pte) & L_PTE_DIRTY)
+#define pte_young(pte)		(pte_val(pte) & L_PTE_YOUNG)
+#define pte_exec(pte)		(!(pte_val(pte) & L_PTE_XN))
+#define pte_special(pte)	(0)
+
+#define pte_present_user(pte) \
+	((pte_val(pte) & (L_PTE_PRESENT | L_PTE_USER)) == \
+	 (L_PTE_PRESENT | L_PTE_USER))
+
 #if __LINUX_ARM_ARCH__ < 6
 static inline void __sync_icache_dcache(pte_t pteval)
 {
@@ -206,25 +218,15 @@ extern void __sync_icache_dcache(pte_t pteval);
 static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 			      pte_t *ptep, pte_t pteval)
 {
-	if (addr >= TASK_SIZE)
-		set_pte_ext(ptep, pteval, 0);
-	else {
+	unsigned long ext = 0;
+
+	if (addr < TASK_SIZE && pte_present_user(pteval)) {
 		__sync_icache_dcache(pteval);
-		set_pte_ext(ptep, pteval, PTE_EXT_NG);
+		ext |= PTE_EXT_NG;
 	}
-}
 
-#define pte_none(pte)		(!pte_val(pte))
-#define pte_present(pte)	(pte_val(pte) & L_PTE_PRESENT)
-#define pte_write(pte)		(!(pte_val(pte) & L_PTE_RDONLY))
-#define pte_dirty(pte)		(pte_val(pte) & L_PTE_DIRTY)
-#define pte_young(pte)		(pte_val(pte) & L_PTE_YOUNG)
-#define pte_exec(pte)		(!(pte_val(pte) & L_PTE_XN))
-#define pte_special(pte)	(0)
-
-#define pte_present_user(pte) \
-	((pte_val(pte) & (L_PTE_PRESENT | L_PTE_USER)) == \
-	 (L_PTE_PRESENT | L_PTE_USER))
+	set_pte_ext(ptep, pteval, ext);
+}
 
 #define PTE_BIT_FUNC(fn,op) \
 static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
@@ -251,13 +253,13 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
  *
  *   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
  *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- *   <--------------- offset --------------------> <- type --> 0 0 0
+ *   <--------------- offset ----------------------> < type -> 0 0 0
  *
- * This gives us up to 63 swap files and 32GB per swap file.  Note that
+ * This gives us up to 31 swap files and 64GB per swap file.  Note that
  * the offset field is always non-zero.
  */
 #define __SWP_TYPE_SHIFT	3
-#define __SWP_TYPE_BITS		6
+#define __SWP_TYPE_BITS		5
 #define __SWP_TYPE_MASK		((1 << __SWP_TYPE_BITS) - 1)
 #define __SWP_OFFSET_SHIFT	(__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
 
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 4432305..a26170d 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -16,69 +16,30 @@
 #include <linux/perf_event.h>
 
 /*
- * Types of PMUs that can be accessed directly and require mutual
- * exclusion between profiling tools.
- */
-enum arm_pmu_type {
-	ARM_PMU_DEVICE_CPU	= 0,
-	ARM_NUM_PMU_DEVICES,
-};
-
-/*
  * struct arm_pmu_platdata - ARM PMU platform data
  *
  * @handle_irq: an optional handler which will be called from the
  *	interrupt and passed the address of the low level handler,
  *	and can be used to implement any platform specific handling
  *	before or after calling it.
- * @enable_irq: an optional handler which will be called after
- *	request_irq and be used to handle some platform specific
- *	irq enablement
- * @disable_irq: an optional handler which will be called before
- *	free_irq and be used to handle some platform specific
- *	irq disablement
+ * @runtime_resume: an optional handler which will be called by the
+ *	runtime PM framework following a call to pm_runtime_get().
+ *	Note that if pm_runtime_get() is called more than once in
+ *	succession this handler will only be called once.
+ * @runtime_suspend: an optional handler which will be called by the
+ *	runtime PM framework following a call to pm_runtime_put().
+ *	Note that if pm_runtime_get() is called more than once in
+ *	succession this handler will only be called following the
+ *	final call to pm_runtime_put() that actually disables the
+ *	hardware.
  */
 struct arm_pmu_platdata {
 	irqreturn_t (*handle_irq)(int irq, void *dev,
 				  irq_handler_t pmu_handler);
-	void (*enable_irq)(int irq);
-	void (*disable_irq)(int irq);
+	int (*runtime_resume)(struct device *dev);
+	int (*runtime_suspend)(struct device *dev);
 };
 
-#ifdef CONFIG_CPU_HAS_PMU
-
-/**
- * reserve_pmu() - reserve the hardware performance counters
- *
- * Reserve the hardware performance counters in the system for exclusive use.
- * Returns 0 on success or -EBUSY if the lock is already held.
- */
-extern int
-reserve_pmu(enum arm_pmu_type type);
-
-/**
- * release_pmu() - Relinquish control of the performance counters
- *
- * Release the performance counters and allow someone else to use them.
- */
-extern void
-release_pmu(enum arm_pmu_type type);
-
-#else /* CONFIG_CPU_HAS_PMU */
-
-#include <linux/err.h>
-
-static inline int
-reserve_pmu(enum arm_pmu_type type)
-{
-	return -ENODEV;
-}
-
-static inline void
-release_pmu(enum arm_pmu_type type)	{ }
-
-#endif /* CONFIG_CPU_HAS_PMU */
-
 #ifdef CONFIG_HW_PERF_EVENTS
 
 /* The events for a given PMU register set. */
@@ -103,7 +64,6 @@ struct pmu_hw_events {
 
 struct arm_pmu {
 	struct pmu	pmu;
-	enum arm_pmu_type type;
 	cpumask_t	active_irqs;
 	char		*name;
 	irqreturn_t	(*handle_irq)(int irq_num, void *dev);
@@ -118,6 +78,8 @@ struct arm_pmu {
 	void		(*start)(void);
 	void		(*stop)(void);
 	void		(*reset)(void *);
+	int		(*request_irq)(irq_handler_t handler);
+	void		(*free_irq)(void);
 	int		(*map_event)(struct perf_event *event);
 	int		num_events;
 	atomic_t	active_events;
@@ -129,7 +91,9 @@ struct arm_pmu {
 
 #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
 
-int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type);
+extern const struct dev_pm_ops armpmu_dev_pm_ops;
+
+int armpmu_register(struct arm_pmu *armpmu, char *name, int type);
 
 u64 armpmu_event_update(struct perf_event *event,
 			struct hw_perf_event *hwc,
@@ -139,6 +103,13 @@ int armpmu_event_set_period(struct perf_event *event,
 			    struct hw_perf_event *hwc,
 			    int idx);
 
+int armpmu_map_event(struct perf_event *event,
+		     const unsigned (*event_map)[PERF_COUNT_HW_MAX],
+		     const unsigned (*cache_map)[PERF_COUNT_HW_CACHE_MAX]
+						[PERF_COUNT_HW_CACHE_OP_MAX]
+						[PERF_COUNT_HW_CACHE_RESULT_MAX],
+		     u32 raw_event_mask);
+
 #endif /* CONFIG_HW_PERF_EVENTS */
 
 #endif /* __ARM_PMU_H__ */
diff --git a/arch/arm/include/asm/sched_clock.h b/arch/arm/include/asm/sched_clock.h
index e3f7572..05b8e82 100644
--- a/arch/arm/include/asm/sched_clock.h
+++ b/arch/arm/include/asm/sched_clock.h
@@ -10,5 +10,7 @@
 
 extern void sched_clock_postinit(void);
 extern void setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate);
+extern void setup_sched_clock_needs_suspend(u32 (*read)(void), int bits,
+		unsigned long rate);
 
 #endif
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index af7b0bd..b2d6b41 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -148,7 +148,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
 #define TIF_NOTIFY_RESUME	2	/* callback before returning to user */
 #define TIF_SYSCALL_TRACE	8
 #define TIF_SYSCALL_AUDIT	9
-#define TIF_POLLING_NRFLAG	16
 #define TIF_USING_IWMMXT	17
 #define TIF_MEMDIE		18	/* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK	20
@@ -160,7 +159,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
-#define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 #define _TIF_USING_IWMMXT	(1 << TIF_USING_IWMMXT)
 #define _TIF_SECCOMP		(1 << TIF_SECCOMP)
 
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 7ad2d5c..d81f3a6d 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -21,7 +21,6 @@ obj-y		:= elf.o entry-armv.o entry-common.o irq.o opcodes.o \
 
 obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o
 
-obj-$(CONFIG_LEDS)		+= leds.o
 obj-$(CONFIG_OC_ETM)		+= etm.o
 obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
 obj-$(CONFIG_ISA_DMA_API)	+= dma.o
@@ -69,8 +68,7 @@ obj-$(CONFIG_CPU_XSC3)		+= xscale-cp0.o
 obj-$(CONFIG_CPU_MOHAWK)	+= xscale-cp0.o
 obj-$(CONFIG_CPU_PJ4)		+= pj4-cp0.o
 obj-$(CONFIG_IWMMXT)		+= iwmmxt.o
-obj-$(CONFIG_CPU_HAS_PMU)	+= pmu.o
-obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event.o
+obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event.o perf_event_cpu.o
 AFLAGS_iwmmxt.o			:= -Wa,-mcpu=iwmmxt
 obj-$(CONFIG_ARM_CPU_TOPOLOGY)  += topology.o
 
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 2b2f25e..b244696 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -13,6 +13,7 @@
 #include <linux/io.h>
 
 #include <asm/mach-types.h>
+#include <asm/mach/map.h>
 #include <asm/mach/pci.h>
 
 static int debug_pci;
@@ -423,6 +424,38 @@ static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 	return irq;
 }
 
+static int __init pcibios_init_resources(int busnr, struct pci_sys_data *sys)
+{
+	int ret;
+	struct pci_host_bridge_window *window;
+
+	if (list_empty(&sys->resources)) {
+		pci_add_resource_offset(&sys->resources,
+			 &iomem_resource, sys->mem_offset);
+	}
+
+	list_for_each_entry(window, &sys->resources, list) {
+		if (resource_type(window->res) == IORESOURCE_IO)
+			return 0;
+	}
+
+	sys->io_res.start = (busnr * SZ_64K) ?  : pcibios_min_io;
+	sys->io_res.end = (busnr + 1) * SZ_64K - 1;
+	sys->io_res.flags = IORESOURCE_IO;
+	sys->io_res.name = sys->io_res_name;
+	sprintf(sys->io_res_name, "PCI%d I/O", busnr);
+
+	ret = request_resource(&ioport_resource, &sys->io_res);
+	if (ret) {
+		pr_err("PCI: unable to allocate I/O port region (%d)\n", ret);
+		return ret;
+	}
+	pci_add_resource_offset(&sys->resources, &sys->io_res,
+				sys->io_offset);
+
+	return 0;
+}
+
 static void __init pcibios_init_hw(struct hw_pci *hw, struct list_head *head)
 {
 	struct pci_sys_data *sys = NULL;
@@ -445,11 +478,10 @@ static void __init pcibios_init_hw(struct hw_pci *hw, struct list_head *head)
 		ret = hw->setup(nr, sys);
 
 		if (ret > 0) {
-			if (list_empty(&sys->resources)) {
-				pci_add_resource_offset(&sys->resources,
-					 &ioport_resource, sys->io_offset);
-				pci_add_resource_offset(&sys->resources,
-					 &iomem_resource, sys->mem_offset);
+			ret = pcibios_init_resources(nr, sys);
+			if (ret)  {
+				kfree(sys);
+				break;
 			}
 
 			if (hw->scan)
@@ -627,3 +659,15 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
 
 	return 0;
 }
+
+void __init pci_map_io_early(unsigned long pfn)
+{
+	struct map_desc pci_io_desc = {
+		.virtual	= PCI_IO_VIRT_BASE,
+		.type		= MT_DEVICE,
+		.length		= SZ_64K,
+	};
+
+	pci_io_desc.pfn = pfn;
+	iotable_init(&pci_io_desc, 1);
+}
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index ba386bd..4eedfde 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -159,6 +159,12 @@ static int debug_arch_supported(void)
 		arch >= ARM_DEBUG_ARCH_V7_1;
 }
 
+/* Can we determine the watchpoint access type from the fsr? */
+static int debug_exception_updates_fsr(void)
+{
+	return 0;
+}
+
 /* Determine number of WRP registers available. */
 static int get_num_wrp_resources(void)
 {
@@ -604,13 +610,14 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
 		/* Aligned */
 		break;
 	case 1:
-		/* Allow single byte watchpoint. */
-		if (info->ctrl.len == ARM_BREAKPOINT_LEN_1)
-			break;
 	case 2:
 		/* Allow halfword watchpoints and breakpoints. */
 		if (info->ctrl.len == ARM_BREAKPOINT_LEN_2)
 			break;
+	case 3:
+		/* Allow single byte watchpoint. */
+		if (info->ctrl.len == ARM_BREAKPOINT_LEN_1)
+			break;
 	default:
 		ret = -EINVAL;
 		goto out;
@@ -619,18 +626,34 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
 	info->address &= ~alignment_mask;
 	info->ctrl.len <<= offset;
 
-	/*
-	 * Currently we rely on an overflow handler to take
-	 * care of single-stepping the breakpoint when it fires.
-	 * In the case of userspace breakpoints on a core with V7 debug,
-	 * we can use the mismatch feature as a poor-man's hardware
-	 * single-step, but this only works for per-task breakpoints.
-	 */
-	if (!bp->overflow_handler && (arch_check_bp_in_kernelspace(bp) ||
-	    !core_has_mismatch_brps() || !bp->hw.bp_target)) {
-		pr_warning("overflow handler required but none found\n");
-		ret = -EINVAL;
+	if (!bp->overflow_handler) {
+		/*
+		 * Mismatch breakpoints are required for single-stepping
+		 * breakpoints.
+		 */
+		if (!core_has_mismatch_brps())
+			return -EINVAL;
+
+		/* We don't allow mismatch breakpoints in kernel space. */
+		if (arch_check_bp_in_kernelspace(bp))
+			return -EPERM;
+
+		/*
+		 * Per-cpu breakpoints are not supported by our stepping
+		 * mechanism. */
+		if (!bp->hw.bp_target)
+			return -EINVAL;
+
+		/*
+		 * We only support specific access types if the fsr
+		 * reports them.
+		 */
+		if (!debug_exception_updates_fsr() &&
+		    (info->ctrl.type == ARM_BREAKPOINT_LOAD ||
+		     info->ctrl.type == ARM_BREAKPOINT_STORE))
+			return -EINVAL;
 	}
+
 out:
 	return ret;
 }
@@ -706,10 +729,12 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr,
 				goto unlock;
 
 			/* Check that the access type matches. */
-			access = (fsr & ARM_FSR_ACCESS_MASK) ? HW_BREAKPOINT_W :
-				 HW_BREAKPOINT_R;
-			if (!(access & hw_breakpoint_type(wp)))
-				goto unlock;
+			if (debug_exception_updates_fsr()) {
+				access = (fsr & ARM_FSR_ACCESS_MASK) ?
+					  HW_BREAKPOINT_W : HW_BREAKPOINT_R;
+				if (!(access & hw_breakpoint_type(wp)))
+					goto unlock;
+			}
 
 			/* We have a winner. */
 			info->trigger = addr;
diff --git a/arch/arm/kernel/leds.c b/arch/arm/kernel/leds.c
deleted file mode 100644
index 1911dae..0000000
--- a/arch/arm/kernel/leds.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * LED support code, ripped out of arch/arm/kernel/time.c
- *
- *  Copyright (C) 1994-2001 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/export.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-#include <linux/string.h>
-
-#include <asm/leds.h>
-
-static void dummy_leds_event(led_event_t evt)
-{
-}
-
-void (*leds_event)(led_event_t) = dummy_leds_event;
-
-struct leds_evt_name {
-	const char	name[8];
-	int		on;
-	int		off;
-};
-
-static const struct leds_evt_name evt_names[] = {
-	{ "amber", led_amber_on, led_amber_off },
-	{ "blue",  led_blue_on,  led_blue_off  },
-	{ "green", led_green_on, led_green_off },
-	{ "red",   led_red_on,   led_red_off   },
-};
-
-static ssize_t leds_store(struct device *dev,
-			struct device_attribute *attr,
-			const char *buf, size_t size)
-{
-	int ret = -EINVAL, len = strcspn(buf, " ");
-
-	if (len > 0 && buf[len] == '\0')
-		len--;
-
-	if (strncmp(buf, "claim", len) == 0) {
-		leds_event(led_claim);
-		ret = size;
-	} else if (strncmp(buf, "release", len) == 0) {
-		leds_event(led_release);
-		ret = size;
-	} else {
-		int i;
-
-		for (i = 0; i < ARRAY_SIZE(evt_names); i++) {
-			if (strlen(evt_names[i].name) != len ||
-			    strncmp(buf, evt_names[i].name, len) != 0)
-				continue;
-			if (strncmp(buf+len, " on", 3) == 0) {
-				leds_event(evt_names[i].on);
-				ret = size;
-			} else if (strncmp(buf+len, " off", 4) == 0) {
-				leds_event(evt_names[i].off);
-				ret = size;
-			}
-			break;
-		}
-	}
-	return ret;
-}
-
-static DEVICE_ATTR(event, 0200, NULL, leds_store);
-
-static struct bus_type leds_subsys = {
-	.name		= "leds",
-	.dev_name	= "leds",
-};
-
-static struct device leds_device = {
-	.id		= 0,
-	.bus		= &leds_subsys,
-};
-
-static int leds_suspend(void)
-{
-	leds_event(led_stop);
-	return 0;
-}
-
-static void leds_resume(void)
-{
-	leds_event(led_start);
-}
-
-static void leds_shutdown(void)
-{
-	leds_event(led_halted);
-}
-
-static struct syscore_ops leds_syscore_ops = {
-	.shutdown	= leds_shutdown,
-	.suspend	= leds_suspend,
-	.resume		= leds_resume,
-};
-
-static int __init leds_init(void)
-{
-	int ret;
-	ret = subsys_system_register(&leds_subsys, NULL);
-	if (ret == 0)
-		ret = device_register(&leds_device);
-	if (ret == 0)
-		ret = device_create_file(&leds_device, &dev_attr_event);
-	if (ret == 0)
-		register_syscore_ops(&leds_syscore_ops);
-	return ret;
-}
-
-device_initcall(leds_init);
-
-EXPORT_SYMBOL(leds_event);
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index ab243b8..93971b1 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -12,68 +12,15 @@
  */
 #define pr_fmt(fmt) "hw perfevents: " fmt
 
-#include <linux/bitmap.h>
-#include <linux/interrupt.h>
 #include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/perf_event.h>
 #include <linux/platform_device.h>
-#include <linux/spinlock.h>
+#include <linux/pm_runtime.h>
 #include <linux/uaccess.h>
 
-#include <asm/cputype.h>
-#include <asm/irq.h>
 #include <asm/irq_regs.h>
 #include <asm/pmu.h>
 #include <asm/stacktrace.h>
 
-/*
- * ARMv6 supports a maximum of 3 events, starting from index 0. If we add
- * another platform that supports more, we need to increase this to be the
- * largest of all platforms.
- *
- * ARMv7 supports up to 32 events:
- *  cycle counter CCNT + 31 events counters CNT0..30.
- *  Cortex-A8 has 1+4 counters, Cortex-A9 has 1+6 counters.
- */
-#define ARMPMU_MAX_HWEVENTS		32
-
-static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);
-static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);
-static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);
-
-#define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
-
-/* Set at runtime when we know what CPU type we are. */
-static struct arm_pmu *cpu_pmu;
-
-const char *perf_pmu_name(void)
-{
-	if (!cpu_pmu)
-		return NULL;
-
-	return cpu_pmu->pmu.name;
-}
-EXPORT_SYMBOL_GPL(perf_pmu_name);
-
-int perf_num_counters(void)
-{
-	int max_events = 0;
-
-	if (cpu_pmu != NULL)
-		max_events = cpu_pmu->num_events;
-
-	return max_events;
-}
-EXPORT_SYMBOL_GPL(perf_num_counters);
-
-#define HW_OP_UNSUPPORTED		0xFFFF
-
-#define C(_x) \
-	PERF_COUNT_HW_CACHE_##_x
-
-#define CACHE_OP_UNSUPPORTED		0xFFFF
-
 static int
 armpmu_map_cache_event(const unsigned (*cache_map)
 				      [PERF_COUNT_HW_CACHE_MAX]
@@ -104,7 +51,7 @@ armpmu_map_cache_event(const unsigned (*cache_map)
 }
 
 static int
-armpmu_map_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config)
+armpmu_map_hw_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config)
 {
 	int mapping = (*event_map)[config];
 	return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping;
@@ -116,19 +63,20 @@ armpmu_map_raw_event(u32 raw_event_mask, u64 config)
 	return (int)(config & raw_event_mask);
 }
 
-static int map_cpu_event(struct perf_event *event,
-			 const unsigned (*event_map)[PERF_COUNT_HW_MAX],
-			 const unsigned (*cache_map)
-					[PERF_COUNT_HW_CACHE_MAX]
-					[PERF_COUNT_HW_CACHE_OP_MAX]
-					[PERF_COUNT_HW_CACHE_RESULT_MAX],
-			 u32 raw_event_mask)
+int
+armpmu_map_event(struct perf_event *event,
+		 const unsigned (*event_map)[PERF_COUNT_HW_MAX],
+		 const unsigned (*cache_map)
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX],
+		 u32 raw_event_mask)
 {
 	u64 config = event->attr.config;
 
 	switch (event->attr.type) {
 	case PERF_TYPE_HARDWARE:
-		return armpmu_map_event(event_map, config);
+		return armpmu_map_hw_event(event_map, config);
 	case PERF_TYPE_HW_CACHE:
 		return armpmu_map_cache_event(cache_map, config);
 	case PERF_TYPE_RAW:
@@ -222,7 +170,6 @@ armpmu_stop(struct perf_event *event, int flags)
 	 */
 	if (!(hwc->state & PERF_HES_STOPPED)) {
 		armpmu->disable(hwc, hwc->idx);
-		barrier(); /* why? */
 		armpmu_event_update(event, hwc, hwc->idx);
 		hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
 	}
@@ -350,99 +297,41 @@ validate_group(struct perf_event *event)
 	return 0;
 }
 
-static irqreturn_t armpmu_platform_irq(int irq, void *dev)
+static irqreturn_t armpmu_dispatch_irq(int irq, void *dev)
 {
 	struct arm_pmu *armpmu = (struct arm_pmu *) dev;
 	struct platform_device *plat_device = armpmu->plat_device;
 	struct arm_pmu_platdata *plat = dev_get_platdata(&plat_device->dev);
 
-	return plat->handle_irq(irq, dev, armpmu->handle_irq);
+	if (plat && plat->handle_irq)
+		return plat->handle_irq(irq, dev, armpmu->handle_irq);
+	else
+		return armpmu->handle_irq(irq, dev);
 }
 
 static void
 armpmu_release_hardware(struct arm_pmu *armpmu)
 {
-	int i, irq, irqs;
-	struct platform_device *pmu_device = armpmu->plat_device;
-	struct arm_pmu_platdata *plat =
-		dev_get_platdata(&pmu_device->dev);
-
-	irqs = min(pmu_device->num_resources, num_possible_cpus());
-
-	for (i = 0; i < irqs; ++i) {
-		if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs))
-			continue;
-		irq = platform_get_irq(pmu_device, i);
-		if (irq >= 0) {
-			if (plat && plat->disable_irq)
-				plat->disable_irq(irq);
-			free_irq(irq, armpmu);
-		}
-	}
-
-	release_pmu(armpmu->type);
+	armpmu->free_irq();
+	pm_runtime_put_sync(&armpmu->plat_device->dev);
 }
 
 static int
 armpmu_reserve_hardware(struct arm_pmu *armpmu)
 {
-	struct arm_pmu_platdata *plat;
-	irq_handler_t handle_irq;
-	int i, err, irq, irqs;
+	int err;
 	struct platform_device *pmu_device = armpmu->plat_device;
 
 	if (!pmu_device)
 		return -ENODEV;
 
-	err = reserve_pmu(armpmu->type);
+	pm_runtime_get_sync(&pmu_device->dev);
+	err = armpmu->request_irq(armpmu_dispatch_irq);
 	if (err) {
-		pr_warning("unable to reserve pmu\n");
+		armpmu_release_hardware(armpmu);
 		return err;
 	}
 
-	plat = dev_get_platdata(&pmu_device->dev);
-	if (plat && plat->handle_irq)
-		handle_irq = armpmu_platform_irq;
-	else
-		handle_irq = armpmu->handle_irq;
-
-	irqs = min(pmu_device->num_resources, num_possible_cpus());
-	if (irqs < 1) {
-		pr_err("no irqs for PMUs defined\n");
-		return -ENODEV;
-	}
-
-	for (i = 0; i < irqs; ++i) {
-		err = 0;
-		irq = platform_get_irq(pmu_device, i);
-		if (irq < 0)
-			continue;
-
-		/*
-		 * If we have a single PMU interrupt that we can't shift,
-		 * assume that we're running on a uniprocessor machine and
-		 * continue. Otherwise, continue without this interrupt.
-		 */
-		if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
-			pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
-				    irq, i);
-			continue;
-		}
-
-		err = request_irq(irq, handle_irq,
-				  IRQF_DISABLED | IRQF_NOBALANCING,
-				  "arm-pmu", armpmu);
-		if (err) {
-			pr_err("unable to request IRQ%d for ARM PMU counters\n",
-				irq);
-			armpmu_release_hardware(armpmu);
-			return err;
-		} else if (plat && plat->enable_irq)
-			plat->enable_irq(irq);
-
-		cpumask_set_cpu(i, &armpmu->active_irqs);
-	}
-
 	return 0;
 }
 
@@ -581,6 +470,32 @@ static void armpmu_disable(struct pmu *pmu)
 	armpmu->stop();
 }
 
+#ifdef CONFIG_PM_RUNTIME
+static int armpmu_runtime_resume(struct device *dev)
+{
+	struct arm_pmu_platdata *plat = dev_get_platdata(dev);
+
+	if (plat && plat->runtime_resume)
+		return plat->runtime_resume(dev);
+
+	return 0;
+}
+
+static int armpmu_runtime_suspend(struct device *dev)
+{
+	struct arm_pmu_platdata *plat = dev_get_platdata(dev);
+
+	if (plat && plat->runtime_suspend)
+		return plat->runtime_suspend(dev);
+
+	return 0;
+}
+#endif
+
+const struct dev_pm_ops armpmu_dev_pm_ops = {
+	SET_RUNTIME_PM_OPS(armpmu_runtime_suspend, armpmu_runtime_resume, NULL)
+};
+
 static void __init armpmu_init(struct arm_pmu *armpmu)
 {
 	atomic_set(&armpmu->active_events, 0);
@@ -598,174 +513,14 @@ static void __init armpmu_init(struct arm_pmu *armpmu)
 	};
 }
 
-int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type)
+int armpmu_register(struct arm_pmu *armpmu, char *name, int type)
 {
 	armpmu_init(armpmu);
+	pr_info("enabled with %s PMU driver, %d counters available\n",
+			armpmu->name, armpmu->num_events);
 	return perf_pmu_register(&armpmu->pmu, name, type);
 }
 
-/* Include the PMU-specific implementations. */
-#include "perf_event_xscale.c"
-#include "perf_event_v6.c"
-#include "perf_event_v7.c"
-
-/*
- * Ensure the PMU has sane values out of reset.
- * This requires SMP to be available, so exists as a separate initcall.
- */
-static int __init
-cpu_pmu_reset(void)
-{
-	if (cpu_pmu && cpu_pmu->reset)
-		return on_each_cpu(cpu_pmu->reset, NULL, 1);
-	return 0;
-}
-arch_initcall(cpu_pmu_reset);
-
-/*
- * PMU platform driver and devicetree bindings.
- */
-static struct of_device_id armpmu_of_device_ids[] = {
-	{.compatible = "arm,cortex-a9-pmu"},
-	{.compatible = "arm,cortex-a8-pmu"},
-	{.compatible = "arm,arm1136-pmu"},
-	{.compatible = "arm,arm1176-pmu"},
-	{},
-};
-
-static struct platform_device_id armpmu_plat_device_ids[] = {
-	{.name = "arm-pmu"},
-	{},
-};
-
-static int __devinit armpmu_device_probe(struct platform_device *pdev)
-{
-	if (!cpu_pmu)
-		return -ENODEV;
-
-	cpu_pmu->plat_device = pdev;
-	return 0;
-}
-
-static struct platform_driver armpmu_driver = {
-	.driver		= {
-		.name	= "arm-pmu",
-		.of_match_table = armpmu_of_device_ids,
-	},
-	.probe		= armpmu_device_probe,
-	.id_table	= armpmu_plat_device_ids,
-};
-
-static int __init register_pmu_driver(void)
-{
-	return platform_driver_register(&armpmu_driver);
-}
-device_initcall(register_pmu_driver);
-
-static struct pmu_hw_events *armpmu_get_cpu_events(void)
-{
-	return &__get_cpu_var(cpu_hw_events);
-}
-
-static void __init cpu_pmu_init(struct arm_pmu *armpmu)
-{
-	int cpu;
-	for_each_possible_cpu(cpu) {
-		struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu);
-		events->events = per_cpu(hw_events, cpu);
-		events->used_mask = per_cpu(used_mask, cpu);
-		raw_spin_lock_init(&events->pmu_lock);
-	}
-	armpmu->get_hw_events = armpmu_get_cpu_events;
-	armpmu->type = ARM_PMU_DEVICE_CPU;
-}
-
-/*
- * PMU hardware loses all context when a CPU goes offline.
- * When a CPU is hotplugged back in, since some hardware registers are
- * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
- * junk values out of them.
- */
-static int __cpuinit pmu_cpu_notify(struct notifier_block *b,
-					unsigned long action, void *hcpu)
-{
-	if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
-		return NOTIFY_DONE;
-
-	if (cpu_pmu && cpu_pmu->reset)
-		cpu_pmu->reset(NULL);
-
-	return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata pmu_cpu_notifier = {
-	.notifier_call = pmu_cpu_notify,
-};
-
-/*
- * CPU PMU identification and registration.
- */
-static int __init
-init_hw_perf_events(void)
-{
-	unsigned long cpuid = read_cpuid_id();
-	unsigned long implementor = (cpuid & 0xFF000000) >> 24;
-	unsigned long part_number = (cpuid & 0xFFF0);
-
-	/* ARM Ltd CPUs. */
-	if (0x41 == implementor) {
-		switch (part_number) {
-		case 0xB360:	/* ARM1136 */
-		case 0xB560:	/* ARM1156 */
-		case 0xB760:	/* ARM1176 */
-			cpu_pmu = armv6pmu_init();
-			break;
-		case 0xB020:	/* ARM11mpcore */
-			cpu_pmu = armv6mpcore_pmu_init();
-			break;
-		case 0xC080:	/* Cortex-A8 */
-			cpu_pmu = armv7_a8_pmu_init();
-			break;
-		case 0xC090:	/* Cortex-A9 */
-			cpu_pmu = armv7_a9_pmu_init();
-			break;
-		case 0xC050:	/* Cortex-A5 */
-			cpu_pmu = armv7_a5_pmu_init();
-			break;
-		case 0xC0F0:	/* Cortex-A15 */
-			cpu_pmu = armv7_a15_pmu_init();
-			break;
-		case 0xC070:	/* Cortex-A7 */
-			cpu_pmu = armv7_a7_pmu_init();
-			break;
-		}
-	/* Intel CPUs [xscale]. */
-	} else if (0x69 == implementor) {
-		part_number = (cpuid >> 13) & 0x7;
-		switch (part_number) {
-		case 1:
-			cpu_pmu = xscale1pmu_init();
-			break;
-		case 2:
-			cpu_pmu = xscale2pmu_init();
-			break;
-		}
-	}
-
-	if (cpu_pmu) {
-		pr_info("enabled with %s PMU driver, %d counters available\n",
-			cpu_pmu->name, cpu_pmu->num_events);
-		cpu_pmu_init(cpu_pmu);
-		register_cpu_notifier(&pmu_cpu_notifier);
-		armpmu_register(cpu_pmu, cpu_pmu->name, PERF_TYPE_RAW);
-	} else {
-		pr_info("no hardware support available\n");
-	}
-
-	return 0;
-}
-early_initcall(init_hw_perf_events);
-
 /*
  * Callchain handling code.
  */
diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c
new file mode 100644
index 0000000..8d7d8d4
--- /dev/null
+++ b/arch/arm/kernel/perf_event_cpu.c
@@ -0,0 +1,295 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2012 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+#define pr_fmt(fmt) "CPU PMU: " fmt
+
+#include <linux/bitmap.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#include <asm/cputype.h>
+#include <asm/irq_regs.h>
+#include <asm/pmu.h>
+
+/* Set at runtime when we know what CPU type we are. */
+static struct arm_pmu *cpu_pmu;
+
+static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);
+static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);
+static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);
+
+/*
+ * Despite the names, these two functions are CPU-specific and are used
+ * by the OProfile/perf code.
+ */
+const char *perf_pmu_name(void)
+{
+	if (!cpu_pmu)
+		return NULL;
+
+	return cpu_pmu->pmu.name;
+}
+EXPORT_SYMBOL_GPL(perf_pmu_name);
+
+int perf_num_counters(void)
+{
+	int max_events = 0;
+
+	if (cpu_pmu != NULL)
+		max_events = cpu_pmu->num_events;
+
+	return max_events;
+}
+EXPORT_SYMBOL_GPL(perf_num_counters);
+
+/* Include the PMU-specific implementations. */
+#include "perf_event_xscale.c"
+#include "perf_event_v6.c"
+#include "perf_event_v7.c"
+
+static struct pmu_hw_events *cpu_pmu_get_cpu_events(void)
+{
+	return &__get_cpu_var(cpu_hw_events);
+}
+
+static void cpu_pmu_free_irq(void)
+{
+	int i, irq, irqs;
+	struct platform_device *pmu_device = cpu_pmu->plat_device;
+
+	irqs = min(pmu_device->num_resources, num_possible_cpus());
+
+	for (i = 0; i < irqs; ++i) {
+		if (!cpumask_test_and_clear_cpu(i, &cpu_pmu->active_irqs))
+			continue;
+		irq = platform_get_irq(pmu_device, i);
+		if (irq >= 0)
+			free_irq(irq, cpu_pmu);
+	}
+}
+
+static int cpu_pmu_request_irq(irq_handler_t handler)
+{
+	int i, err, irq, irqs;
+	struct platform_device *pmu_device = cpu_pmu->plat_device;
+
+	if (!pmu_device)
+		return -ENODEV;
+
+	irqs = min(pmu_device->num_resources, num_possible_cpus());
+	if (irqs < 1) {
+		pr_err("no irqs for PMUs defined\n");
+		return -ENODEV;
+	}
+
+	for (i = 0; i < irqs; ++i) {
+		err = 0;
+		irq = platform_get_irq(pmu_device, i);
+		if (irq < 0)
+			continue;
+
+		/*
+		 * If we have a single PMU interrupt that we can't shift,
+		 * assume that we're running on a uniprocessor machine and
+		 * continue. Otherwise, continue without this interrupt.
+		 */
+		if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
+			pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
+				    irq, i);
+			continue;
+		}
+
+		err = request_irq(irq, handler, IRQF_NOBALANCING, "arm-pmu",
+				  cpu_pmu);
+		if (err) {
+			pr_err("unable to request IRQ%d for ARM PMU counters\n",
+				irq);
+			return err;
+		}
+
+		cpumask_set_cpu(i, &cpu_pmu->active_irqs);
+	}
+
+	return 0;
+}
+
+static void __devinit cpu_pmu_init(struct arm_pmu *cpu_pmu)
+{
+	int cpu;
+	for_each_possible_cpu(cpu) {
+		struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu);
+		events->events = per_cpu(hw_events, cpu);
+		events->used_mask = per_cpu(used_mask, cpu);
+		raw_spin_lock_init(&events->pmu_lock);
+	}
+
+	cpu_pmu->get_hw_events	= cpu_pmu_get_cpu_events;
+	cpu_pmu->request_irq	= cpu_pmu_request_irq;
+	cpu_pmu->free_irq	= cpu_pmu_free_irq;
+
+	/* Ensure the PMU has sane values out of reset. */
+	if (cpu_pmu && cpu_pmu->reset)
+		on_each_cpu(cpu_pmu->reset, NULL, 1);
+}
+
+/*
+ * PMU hardware loses all context when a CPU goes offline.
+ * When a CPU is hotplugged back in, since some hardware registers are
+ * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
+ * junk values out of them.
+ */
+static int __cpuinit cpu_pmu_notify(struct notifier_block *b,
+				    unsigned long action, void *hcpu)
+{
+	if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
+		return NOTIFY_DONE;
+
+	if (cpu_pmu && cpu_pmu->reset)
+		cpu_pmu->reset(NULL);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata cpu_pmu_hotplug_notifier = {
+	.notifier_call = cpu_pmu_notify,
+};
+
+/*
+ * PMU platform driver and devicetree bindings.
+ */
+static struct of_device_id __devinitdata cpu_pmu_of_device_ids[] = {
+	{.compatible = "arm,cortex-a15-pmu",	.data = armv7_a15_pmu_init},
+	{.compatible = "arm,cortex-a9-pmu",	.data = armv7_a9_pmu_init},
+	{.compatible = "arm,cortex-a8-pmu",	.data = armv7_a8_pmu_init},
+	{.compatible = "arm,cortex-a7-pmu",	.data = armv7_a7_pmu_init},
+	{.compatible = "arm,cortex-a5-pmu",	.data = armv7_a5_pmu_init},
+	{.compatible = "arm,arm11mpcore-pmu",	.data = armv6mpcore_pmu_init},
+	{.compatible = "arm,arm1176-pmu",	.data = armv6pmu_init},
+	{.compatible = "arm,arm1136-pmu",	.data = armv6pmu_init},
+	{},
+};
+
+static struct platform_device_id __devinitdata cpu_pmu_plat_device_ids[] = {
+	{.name = "arm-pmu"},
+	{},
+};
+
+/*
+ * CPU PMU identification and probing.
+ */
+static struct arm_pmu *__devinit probe_current_pmu(void)
+{
+	struct arm_pmu *pmu = NULL;
+	int cpu = get_cpu();
+	unsigned long cpuid = read_cpuid_id();
+	unsigned long implementor = (cpuid & 0xFF000000) >> 24;
+	unsigned long part_number = (cpuid & 0xFFF0);
+
+	pr_info("probing PMU on CPU %d\n", cpu);
+
+	/* ARM Ltd CPUs. */
+	if (0x41 == implementor) {
+		switch (part_number) {
+		case 0xB360:	/* ARM1136 */
+		case 0xB560:	/* ARM1156 */
+		case 0xB760:	/* ARM1176 */
+			pmu = armv6pmu_init();
+			break;
+		case 0xB020:	/* ARM11mpcore */
+			pmu = armv6mpcore_pmu_init();
+			break;
+		case 0xC080:	/* Cortex-A8 */
+			pmu = armv7_a8_pmu_init();
+			break;
+		case 0xC090:	/* Cortex-A9 */
+			pmu = armv7_a9_pmu_init();
+			break;
+		case 0xC050:	/* Cortex-A5 */
+			pmu = armv7_a5_pmu_init();
+			break;
+		case 0xC0F0:	/* Cortex-A15 */
+			pmu = armv7_a15_pmu_init();
+			break;
+		case 0xC070:	/* Cortex-A7 */
+			pmu = armv7_a7_pmu_init();
+			break;
+		}
+	/* Intel CPUs [xscale]. */
+	} else if (0x69 == implementor) {
+		part_number = (cpuid >> 13) & 0x7;
+		switch (part_number) {
+		case 1:
+			pmu = xscale1pmu_init();
+			break;
+		case 2:
+			pmu = xscale2pmu_init();
+			break;
+		}
+	}
+
+	put_cpu();
+	return pmu;
+}
+
+static int __devinit cpu_pmu_device_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id;
+	struct arm_pmu *(*init_fn)(void);
+	struct device_node *node = pdev->dev.of_node;
+
+	if (cpu_pmu) {
+		pr_info("attempt to register multiple PMU devices!");
+		return -ENOSPC;
+	}
+
+	if (node && (of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node))) {
+		init_fn = of_id->data;
+		cpu_pmu = init_fn();
+	} else {
+		cpu_pmu = probe_current_pmu();
+	}
+
+	if (!cpu_pmu)
+		return -ENODEV;
+
+	cpu_pmu->plat_device = pdev;
+	cpu_pmu_init(cpu_pmu);
+	register_cpu_notifier(&cpu_pmu_hotplug_notifier);
+	armpmu_register(cpu_pmu, cpu_pmu->name, PERF_TYPE_RAW);
+
+	return 0;
+}
+
+static struct platform_driver cpu_pmu_driver = {
+	.driver		= {
+		.name	= "arm-pmu",
+		.pm	= &armpmu_dev_pm_ops,
+		.of_match_table = cpu_pmu_of_device_ids,
+	},
+	.probe		= cpu_pmu_device_probe,
+	.id_table	= cpu_pmu_plat_device_ids,
+};
+
+static int __init register_pmu_driver(void)
+{
+	return platform_driver_register(&cpu_pmu_driver);
+}
+device_initcall(register_pmu_driver);
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index c90fcb2..6ccc079 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -645,7 +645,7 @@ armv6mpcore_pmu_disable_event(struct hw_perf_event *hwc,
 
 static int armv6_map_event(struct perf_event *event)
 {
-	return map_cpu_event(event, &armv6_perf_map,
+	return armpmu_map_event(event, &armv6_perf_map,
 				&armv6_perf_cache_map, 0xFF);
 }
 
@@ -664,7 +664,7 @@ static struct arm_pmu armv6pmu = {
 	.max_period		= (1LLU << 32) - 1,
 };
 
-static struct arm_pmu *__init armv6pmu_init(void)
+static struct arm_pmu *__devinit armv6pmu_init(void)
 {
 	return &armv6pmu;
 }
@@ -679,7 +679,7 @@ static struct arm_pmu *__init armv6pmu_init(void)
 
 static int armv6mpcore_map_event(struct perf_event *event)
 {
-	return map_cpu_event(event, &armv6mpcore_perf_map,
+	return armpmu_map_event(event, &armv6mpcore_perf_map,
 				&armv6mpcore_perf_cache_map, 0xFF);
 }
 
@@ -698,17 +698,17 @@ static struct arm_pmu armv6mpcore_pmu = {
 	.max_period		= (1LLU << 32) - 1,
 };
 
-static struct arm_pmu *__init armv6mpcore_pmu_init(void)
+static struct arm_pmu *__devinit armv6mpcore_pmu_init(void)
 {
 	return &armv6mpcore_pmu;
 }
 #else
-static struct arm_pmu *__init armv6pmu_init(void)
+static struct arm_pmu *__devinit armv6pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init armv6mpcore_pmu_init(void)
+static struct arm_pmu *__devinit armv6mpcore_pmu_init(void)
 {
 	return NULL;
 }
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index f04070b..bd4b090 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -1204,31 +1204,31 @@ static void armv7pmu_reset(void *info)
 
 static int armv7_a8_map_event(struct perf_event *event)
 {
-	return map_cpu_event(event, &armv7_a8_perf_map,
+	return armpmu_map_event(event, &armv7_a8_perf_map,
 				&armv7_a8_perf_cache_map, 0xFF);
 }
 
 static int armv7_a9_map_event(struct perf_event *event)
 {
-	return map_cpu_event(event, &armv7_a9_perf_map,
+	return armpmu_map_event(event, &armv7_a9_perf_map,
 				&armv7_a9_perf_cache_map, 0xFF);
 }
 
 static int armv7_a5_map_event(struct perf_event *event)
 {
-	return map_cpu_event(event, &armv7_a5_perf_map,
+	return armpmu_map_event(event, &armv7_a5_perf_map,
 				&armv7_a5_perf_cache_map, 0xFF);
 }
 
 static int armv7_a15_map_event(struct perf_event *event)
 {
-	return map_cpu_event(event, &armv7_a15_perf_map,
+	return armpmu_map_event(event, &armv7_a15_perf_map,
 				&armv7_a15_perf_cache_map, 0xFF);
 }
 
 static int armv7_a7_map_event(struct perf_event *event)
 {
-	return map_cpu_event(event, &armv7_a7_perf_map,
+	return armpmu_map_event(event, &armv7_a7_perf_map,
 				&armv7_a7_perf_cache_map, 0xFF);
 }
 
@@ -1245,7 +1245,7 @@ static struct arm_pmu armv7pmu = {
 	.max_period		= (1LLU << 32) - 1,
 };
 
-static u32 __init armv7_read_num_pmnc_events(void)
+static u32 __devinit armv7_read_num_pmnc_events(void)
 {
 	u32 nb_cnt;
 
@@ -1256,7 +1256,7 @@ static u32 __init armv7_read_num_pmnc_events(void)
 	return nb_cnt + 1;
 }
 
-static struct arm_pmu *__init armv7_a8_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a8_pmu_init(void)
 {
 	armv7pmu.name		= "ARMv7 Cortex-A8";
 	armv7pmu.map_event	= armv7_a8_map_event;
@@ -1264,7 +1264,7 @@ static struct arm_pmu *__init armv7_a8_pmu_init(void)
 	return &armv7pmu;
 }
 
-static struct arm_pmu *__init armv7_a9_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a9_pmu_init(void)
 {
 	armv7pmu.name		= "ARMv7 Cortex-A9";
 	armv7pmu.map_event	= armv7_a9_map_event;
@@ -1272,7 +1272,7 @@ static struct arm_pmu *__init armv7_a9_pmu_init(void)
 	return &armv7pmu;
 }
 
-static struct arm_pmu *__init armv7_a5_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a5_pmu_init(void)
 {
 	armv7pmu.name		= "ARMv7 Cortex-A5";
 	armv7pmu.map_event	= armv7_a5_map_event;
@@ -1280,7 +1280,7 @@ static struct arm_pmu *__init armv7_a5_pmu_init(void)
 	return &armv7pmu;
 }
 
-static struct arm_pmu *__init armv7_a15_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a15_pmu_init(void)
 {
 	armv7pmu.name		= "ARMv7 Cortex-A15";
 	armv7pmu.map_event	= armv7_a15_map_event;
@@ -1289,7 +1289,7 @@ static struct arm_pmu *__init armv7_a15_pmu_init(void)
 	return &armv7pmu;
 }
 
-static struct arm_pmu *__init armv7_a7_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a7_pmu_init(void)
 {
 	armv7pmu.name		= "ARMv7 Cortex-A7";
 	armv7pmu.map_event	= armv7_a7_map_event;
@@ -1298,27 +1298,27 @@ static struct arm_pmu *__init armv7_a7_pmu_init(void)
 	return &armv7pmu;
 }
 #else
-static struct arm_pmu *__init armv7_a8_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a8_pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init armv7_a9_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a9_pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init armv7_a5_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a5_pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init armv7_a15_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a15_pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init armv7_a7_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a7_pmu_init(void)
 {
 	return NULL;
 }
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index f759fe0..426e19f 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -430,7 +430,7 @@ xscale1pmu_write_counter(int counter, u32 val)
 
 static int xscale_map_event(struct perf_event *event)
 {
-	return map_cpu_event(event, &xscale_perf_map,
+	return armpmu_map_event(event, &xscale_perf_map,
 				&xscale_perf_cache_map, 0xFF);
 }
 
@@ -449,7 +449,7 @@ static struct arm_pmu xscale1pmu = {
 	.max_period	= (1LLU << 32) - 1,
 };
 
-static struct arm_pmu *__init xscale1pmu_init(void)
+static struct arm_pmu *__devinit xscale1pmu_init(void)
 {
 	return &xscale1pmu;
 }
@@ -816,17 +816,17 @@ static struct arm_pmu xscale2pmu = {
 	.max_period	= (1LLU << 32) - 1,
 };
 
-static struct arm_pmu *__init xscale2pmu_init(void)
+static struct arm_pmu *__devinit xscale2pmu_init(void)
 {
 	return &xscale2pmu;
 }
 #else
-static struct arm_pmu *__init xscale1pmu_init(void)
+static struct arm_pmu *__devinit xscale1pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init xscale2pmu_init(void)
+static struct arm_pmu *__devinit xscale2pmu_init(void)
 {
 	return NULL;
 }
diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c
deleted file mode 100644
index 2334bf8..0000000
--- a/arch/arm/kernel/pmu.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- *  linux/arch/arm/kernel/pmu.c
- *
- *  Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles
- *  Copyright (C) 2010 ARM Ltd, Will Deacon
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/err.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include <asm/pmu.h>
-
-/*
- * PMU locking to ensure mutual exclusion between different subsystems.
- */
-static unsigned long pmu_lock[BITS_TO_LONGS(ARM_NUM_PMU_DEVICES)];
-
-int
-reserve_pmu(enum arm_pmu_type type)
-{
-	return test_and_set_bit_lock(type, pmu_lock) ? -EBUSY : 0;
-}
-EXPORT_SYMBOL_GPL(reserve_pmu);
-
-void
-release_pmu(enum arm_pmu_type type)
-{
-	clear_bit_unlock(type, pmu_lock);
-}
-EXPORT_SYMBOL_GPL(release_pmu);
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 693b744..04eea22 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -31,9 +31,9 @@
 #include <linux/random.h>
 #include <linux/hw_breakpoint.h>
 #include <linux/cpuidle.h>
+#include <linux/leds.h>
 
 #include <asm/cacheflush.h>
-#include <asm/leds.h>
 #include <asm/processor.h>
 #include <asm/thread_notify.h>
 #include <asm/stacktrace.h>
@@ -189,7 +189,7 @@ void cpu_idle(void)
 	while (1) {
 		tick_nohz_idle_enter();
 		rcu_idle_enter();
-		leds_event(led_idle_start);
+		ledtrig_cpu(CPU_LED_IDLE_START);
 		while (!need_resched()) {
 #ifdef CONFIG_HOTPLUG_CPU
 			if (cpu_is_offline(smp_processor_id()))
@@ -220,7 +220,7 @@ void cpu_idle(void)
 			} else
 				local_irq_enable();
 		}
-		leds_event(led_idle_end);
+		ledtrig_cpu(CPU_LED_IDLE_END);
 		rcu_idle_exit();
 		tick_nohz_idle_exit();
 		schedule_preempt_disabled();
diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c
index 27d186a..f451539 100644
--- a/arch/arm/kernel/sched_clock.c
+++ b/arch/arm/kernel/sched_clock.c
@@ -21,6 +21,8 @@ struct clock_data {
 	u32 epoch_cyc_copy;
 	u32 mult;
 	u32 shift;
+	bool suspended;
+	bool needs_suspend;
 };
 
 static void sched_clock_poll(unsigned long wrap_ticks);
@@ -49,6 +51,9 @@ static unsigned long long cyc_to_sched_clock(u32 cyc, u32 mask)
 	u64 epoch_ns;
 	u32 epoch_cyc;
 
+	if (cd.suspended)
+		return cd.epoch_ns;
+
 	/*
 	 * Load the epoch_cyc and epoch_ns atomically.  We do this by
 	 * ensuring that we always write epoch_cyc, epoch_ns and
@@ -98,6 +103,13 @@ static void sched_clock_poll(unsigned long wrap_ticks)
 	update_sched_clock();
 }
 
+void __init setup_sched_clock_needs_suspend(u32 (*read)(void), int bits,
+		unsigned long rate)
+{
+	setup_sched_clock(read, bits, rate);
+	cd.needs_suspend = true;
+}
+
 void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
 {
 	unsigned long r, w;
@@ -169,11 +181,23 @@ void __init sched_clock_postinit(void)
 static int sched_clock_suspend(void)
 {
 	sched_clock_poll(sched_clock_timer.data);
+	if (cd.needs_suspend)
+		cd.suspended = true;
 	return 0;
 }
 
+static void sched_clock_resume(void)
+{
+	if (cd.needs_suspend) {
+		cd.epoch_cyc = read_sched_clock();
+		cd.epoch_cyc_copy = cd.epoch_cyc;
+		cd.suspended = false;
+	}
+}
+
 static struct syscore_ops sched_clock_ops = {
 	.suspend = sched_clock_suspend,
+	.resume = sched_clock_resume,
 };
 
 static int __init sched_clock_syscore_init(void)
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index f27789e..56f72d2 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -10,7 +10,6 @@
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/personality.h>
-#include <linux/freezer.h>
 #include <linux/uaccess.h>
 #include <linux/tracehook.h>
 
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index af2afb0..09be0c3 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -25,7 +25,6 @@
 #include <linux/timer.h>
 #include <linux/irq.h>
 
-#include <asm/leds.h>
 #include <asm/thread_info.h>
 #include <asm/sched_clock.h>
 #include <asm/stacktrace.h>
@@ -80,21 +79,6 @@ u32 arch_gettimeoffset(void)
 }
 #endif /* CONFIG_ARCH_USES_GETTIMEOFFSET */
 
-#ifdef CONFIG_LEDS_TIMER
-static inline void do_leds(void)
-{
-	static unsigned int count = HZ/2;
-
-	if (--count == 0) {
-		count = HZ/2;
-		leds_event(led_timer);
-	}
-}
-#else
-#define	do_leds()
-#endif
-
-
 #ifndef CONFIG_GENERIC_CLOCKEVENTS
 /*
  * Kernel system timer support.
@@ -102,7 +86,6 @@ static inline void do_leds(void)
 void timer_tick(void)
 {
 	profile_tick(CPU_PROFILING);
-	do_leds();
 	xtime_update(1);
 #ifndef CONFIG_SMP
 	update_process_times(user_mode(get_irq_regs()));
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 198b084..26c12c6 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -321,7 +321,7 @@ void store_cpu_topology(unsigned int cpuid)
  * init_cpu_topology is called at boot when only one cpu is running
  * which prevent simultaneous write access to cpu_topology array
  */
-void init_cpu_topology(void)
+void __init init_cpu_topology(void)
 {
 	unsigned int cpu;
 
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index 2473fd1..af72969 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -16,13 +16,30 @@ lib-y		:= backtrace.o changebit.o csumipv6.o csumpartial.o   \
 		   call_with_stack.o
 
 mmu-y	:= clear_user.o copy_page.o getuser.o putuser.o
-mmu-y	+= copy_from_user.o copy_to_user.o
+
+# the code in uaccess.S is not preemption safe and
+# probably faster on ARMv3 only
+ifeq ($(CONFIG_PREEMPT),y)
+  mmu-y	+= copy_from_user.o copy_to_user.o
+else
+ifneq ($(CONFIG_CPU_32v3),y)
+  mmu-y	+= copy_from_user.o copy_to_user.o
+else
+  mmu-y	+= uaccess.o
+endif
+endif
 
 # using lib_ here won't override already available weak symbols
 obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o
 
-lib-$(CONFIG_MMU)		+= $(mmu-y)
-lib-y				+= io-readsw-armv4.o io-writesw-armv4.o
+lib-$(CONFIG_MMU) += $(mmu-y)
+
+ifeq ($(CONFIG_CPU_32v3),y)
+  lib-y	+= io-readsw-armv3.o io-writesw-armv3.o
+else
+  lib-y	+= io-readsw-armv4.o io-writesw-armv4.o
+endif
+
 lib-$(CONFIG_ARCH_RPC)		+= ecard.o io-acorn.o floppydma.o
 lib-$(CONFIG_ARCH_SHARK)	+= io-shark.o
 
diff --git a/arch/arm/lib/io-readsw-armv3.S b/arch/arm/lib/io-readsw-armv3.S
new file mode 100644
index 0000000..88487c8
--- /dev/null
+++ b/arch/arm/lib/io-readsw-armv3.S
@@ -0,0 +1,106 @@
+/*
+ *  linux/arch/arm/lib/io-readsw-armv3.S
+ *
+ *  Copyright (C) 1995-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+.Linsw_bad_alignment:
+		adr	r0, .Linsw_bad_align_msg
+		mov	r2, lr
+		b	panic
+.Linsw_bad_align_msg:
+		.asciz	"insw: bad buffer alignment (0x%p, lr=0x%08lX)\n"
+		.align
+
+.Linsw_align:	tst	r1, #1
+		bne	.Linsw_bad_alignment
+
+		ldr	r3, [r0]
+		strb	r3, [r1], #1
+		mov	r3, r3, lsr #8
+		strb	r3, [r1], #1
+
+		subs	r2, r2, #1
+		moveq	pc, lr
+
+ENTRY(__raw_readsw)
+		teq	r2, #0		@ do we have to check for the zero len?
+		moveq	pc, lr
+		tst	r1, #3
+		bne	.Linsw_align
+
+.Linsw_aligned:	mov	ip, #0xff
+		orr	ip, ip, ip, lsl #8
+		stmfd	sp!, {r4, r5, r6, lr}
+
+		subs	r2, r2, #8
+		bmi	.Lno_insw_8
+
+.Linsw_8_lp:	ldr	r3, [r0]
+		and	r3, r3, ip
+		ldr	r4, [r0]
+		orr	r3, r3, r4, lsl #16
+
+		ldr	r4, [r0]
+		and	r4, r4, ip
+		ldr	r5, [r0]
+		orr	r4, r4, r5, lsl #16
+
+		ldr	r5, [r0]
+		and	r5, r5, ip
+		ldr	r6, [r0]
+		orr	r5, r5, r6, lsl #16
+
+		ldr	r6, [r0]
+		and	r6, r6, ip
+		ldr	lr, [r0]
+		orr	r6, r6, lr, lsl #16
+
+		stmia	r1!, {r3 - r6}
+
+		subs	r2, r2, #8
+		bpl	.Linsw_8_lp
+
+		tst	r2, #7
+		ldmeqfd	sp!, {r4, r5, r6, pc}
+
+.Lno_insw_8:	tst	r2, #4
+		beq	.Lno_insw_4
+
+		ldr	r3, [r0]
+		and	r3, r3, ip
+		ldr	r4, [r0]
+		orr	r3, r3, r4, lsl #16
+
+		ldr	r4, [r0]
+		and	r4, r4, ip
+		ldr	r5, [r0]
+		orr	r4, r4, r5, lsl #16
+
+		stmia	r1!, {r3, r4}
+
+.Lno_insw_4:	tst	r2, #2
+		beq	.Lno_insw_2
+
+		ldr	r3, [r0]
+		and	r3, r3, ip
+		ldr	r4, [r0]
+		orr	r3, r3, r4, lsl #16
+
+		str	r3, [r1], #4
+
+.Lno_insw_2:	tst	r2, #1
+		ldrne	r3, [r0]
+		strneb	r3, [r1], #1
+		movne	r3, r3, lsr #8
+		strneb	r3, [r1]
+
+		ldmfd	sp!, {r4, r5, r6, pc}
+
+
diff --git a/arch/arm/lib/io-writesw-armv3.S b/arch/arm/lib/io-writesw-armv3.S
new file mode 100644
index 0000000..49b8004
--- /dev/null
+++ b/arch/arm/lib/io-writesw-armv3.S
@@ -0,0 +1,126 @@
+/*
+ *  linux/arch/arm/lib/io-writesw-armv3.S
+ *
+ *  Copyright (C) 1995-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+.Loutsw_bad_alignment:
+		adr	r0, .Loutsw_bad_align_msg
+		mov	r2, lr
+		b	panic
+.Loutsw_bad_align_msg:
+		.asciz	"outsw: bad buffer alignment (0x%p, lr=0x%08lX)\n"
+		.align
+
+.Loutsw_align:	tst	r1, #1
+		bne	.Loutsw_bad_alignment
+
+		add	r1, r1, #2
+
+		ldr	r3, [r1, #-4]
+		mov	r3, r3, lsr #16
+		orr	r3, r3, r3, lsl #16
+		str	r3, [r0]
+		subs	r2, r2, #1
+		moveq	pc, lr
+
+ENTRY(__raw_writesw)
+		teq	r2, #0		@ do we have to check for the zero len?
+		moveq	pc, lr
+		tst	r1, #3
+		bne	.Loutsw_align
+
+		stmfd	sp!, {r4, r5, r6, lr}
+
+		subs	r2, r2, #8
+		bmi	.Lno_outsw_8
+
+.Loutsw_8_lp:	ldmia	r1!, {r3, r4, r5, r6}
+
+		mov	ip, r3, lsl #16
+		orr	ip, ip, ip, lsr #16
+		str	ip, [r0]
+
+		mov	ip, r3, lsr #16
+		orr	ip, ip, ip, lsl #16
+		str	ip, [r0]
+
+		mov	ip, r4, lsl #16
+		orr	ip, ip, ip, lsr #16
+		str	ip, [r0]
+
+		mov	ip, r4, lsr #16
+		orr	ip, ip, ip, lsl #16
+		str	ip, [r0]
+
+		mov	ip, r5, lsl #16
+		orr	ip, ip, ip, lsr #16
+		str	ip, [r0]
+
+		mov	ip, r5, lsr #16
+		orr	ip, ip, ip, lsl #16
+		str	ip, [r0]
+
+		mov	ip, r6, lsl #16
+		orr	ip, ip, ip, lsr #16
+		str	ip, [r0]
+
+		mov	ip, r6, lsr #16
+		orr	ip, ip, ip, lsl #16
+		str	ip, [r0]
+
+		subs	r2, r2, #8
+		bpl	.Loutsw_8_lp
+
+		tst	r2, #7
+		ldmeqfd	sp!, {r4, r5, r6, pc}
+
+.Lno_outsw_8:	tst	r2, #4
+		beq	.Lno_outsw_4
+
+		ldmia	r1!, {r3, r4}
+
+		mov	ip, r3, lsl #16
+		orr	ip, ip, ip, lsr #16
+		str	ip, [r0]
+
+		mov	ip, r3, lsr #16
+		orr	ip, ip, ip, lsl #16
+		str	ip, [r0]
+
+		mov	ip, r4, lsl #16
+		orr	ip, ip, ip, lsr #16
+		str	ip, [r0]
+
+		mov	ip, r4, lsr #16
+		orr	ip, ip, ip, lsl #16
+		str	ip, [r0]
+
+.Lno_outsw_4:	tst	r2, #2
+		beq	.Lno_outsw_2
+
+		ldr	r3, [r1], #4
+
+		mov	ip, r3, lsl #16
+		orr	ip, ip, ip, lsr #16
+		str	ip, [r0]
+
+		mov	ip, r3, lsr #16
+		orr	ip, ip, ip, lsl #16
+		str	ip, [r0]
+
+.Lno_outsw_2:	tst	r2, #1
+
+		ldrne	r3, [r1]
+
+		movne	ip, r3, lsl #16
+		orrne	ip, ip, ip, lsr #16
+		strne	ip, [r0]
+
+		ldmfd	sp!, {r4, r5, r6, pc}
diff --git a/arch/arm/lib/uaccess.S b/arch/arm/lib/uaccess.S
new file mode 100644
index 0000000..5c908b1
--- /dev/null
+++ b/arch/arm/lib/uaccess.S
@@ -0,0 +1,564 @@
+/*
+ *  linux/arch/arm/lib/uaccess.S
+ *
+ *  Copyright (C) 1995, 1996,1997,1998 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Routines to block copy data to/from user memory
+ *   These are highly optimised both for the 4k page size
+ *   and for various alignments.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/errno.h>
+#include <asm/domain.h>
+
+		.text
+
+#define PAGE_SHIFT 12
+
+/* Prototype: int __copy_to_user(void *to, const char *from, size_t n)
+ * Purpose  : copy a block to user memory from kernel memory
+ * Params   : to   - user memory
+ *          : from - kernel memory
+ *          : n    - number of bytes to copy
+ * Returns  : Number of bytes NOT copied.
+ */
+
+.Lc2u_dest_not_aligned:
+		rsb	ip, ip, #4
+		cmp	ip, #2
+		ldrb	r3, [r1], #1
+USER(	TUSER(	strb)	r3, [r0], #1)			@ May fault
+		ldrgeb	r3, [r1], #1
+USER(	TUSER(	strgeb) r3, [r0], #1)			@ May fault
+		ldrgtb	r3, [r1], #1
+USER(	TUSER(	strgtb) r3, [r0], #1)			@ May fault
+		sub	r2, r2, ip
+		b	.Lc2u_dest_aligned
+
+ENTRY(__copy_to_user)
+		stmfd	sp!, {r2, r4 - r7, lr}
+		cmp	r2, #4
+		blt	.Lc2u_not_enough
+		ands	ip, r0, #3
+		bne	.Lc2u_dest_not_aligned
+.Lc2u_dest_aligned:
+
+		ands	ip, r1, #3
+		bne	.Lc2u_src_not_aligned
+/*
+ * Seeing as there has to be at least 8 bytes to copy, we can
+ * copy one word, and force a user-mode page fault...
+ */
+
+.Lc2u_0fupi:	subs	r2, r2, #4
+		addmi	ip, r2, #4
+		bmi	.Lc2u_0nowords
+		ldr	r3, [r1], #4
+USER(	TUSER(	str)	r3, [r0], #4)			@ May fault
+		mov	ip, r0, lsl #32 - PAGE_SHIFT	@ On each page, use a ld/st??t instruction
+		rsb	ip, ip, #0
+		movs	ip, ip, lsr #32 - PAGE_SHIFT
+		beq	.Lc2u_0fupi
+/*
+ * ip = max no. of bytes to copy before needing another "strt" insn
+ */
+		cmp	r2, ip
+		movlt	ip, r2
+		sub	r2, r2, ip
+		subs	ip, ip, #32
+		blt	.Lc2u_0rem8lp
+
+.Lc2u_0cpy8lp:	ldmia	r1!, {r3 - r6}
+		stmia	r0!, {r3 - r6}			@ Shouldnt fault
+		ldmia	r1!, {r3 - r6}
+		subs	ip, ip, #32
+		stmia	r0!, {r3 - r6}			@ Shouldnt fault
+		bpl	.Lc2u_0cpy8lp
+
+.Lc2u_0rem8lp:	cmn	ip, #16
+		ldmgeia	r1!, {r3 - r6}
+		stmgeia	r0!, {r3 - r6}			@ Shouldnt fault
+		tst	ip, #8
+		ldmneia	r1!, {r3 - r4}
+		stmneia	r0!, {r3 - r4}			@ Shouldnt fault
+		tst	ip, #4
+		ldrne	r3, [r1], #4
+	TUSER(	strne) r3, [r0], #4			@ Shouldnt fault
+		ands	ip, ip, #3
+		beq	.Lc2u_0fupi
+.Lc2u_0nowords:	teq	ip, #0
+		beq	.Lc2u_finished
+.Lc2u_nowords:	cmp	ip, #2
+		ldrb	r3, [r1], #1
+USER(	TUSER(	strb)	r3, [r0], #1)			@ May fault
+		ldrgeb	r3, [r1], #1
+USER(	TUSER(	strgeb) r3, [r0], #1)			@ May fault
+		ldrgtb	r3, [r1], #1
+USER(	TUSER(	strgtb) r3, [r0], #1)			@ May fault
+		b	.Lc2u_finished
+
+.Lc2u_not_enough:
+		movs	ip, r2
+		bne	.Lc2u_nowords
+.Lc2u_finished:	mov	r0, #0
+		ldmfd	sp!, {r2, r4 - r7, pc}
+
+.Lc2u_src_not_aligned:
+		bic	r1, r1, #3
+		ldr	r7, [r1], #4
+		cmp	ip, #2
+		bgt	.Lc2u_3fupi
+		beq	.Lc2u_2fupi
+.Lc2u_1fupi:	subs	r2, r2, #4
+		addmi	ip, r2, #4
+		bmi	.Lc2u_1nowords
+		mov	r3, r7, pull #8
+		ldr	r7, [r1], #4
+		orr	r3, r3, r7, push #24
+USER(	TUSER(	str)	r3, [r0], #4)			@ May fault
+		mov	ip, r0, lsl #32 - PAGE_SHIFT
+		rsb	ip, ip, #0
+		movs	ip, ip, lsr #32 - PAGE_SHIFT
+		beq	.Lc2u_1fupi
+		cmp	r2, ip
+		movlt	ip, r2
+		sub	r2, r2, ip
+		subs	ip, ip, #16
+		blt	.Lc2u_1rem8lp
+
+.Lc2u_1cpy8lp:	mov	r3, r7, pull #8
+		ldmia	r1!, {r4 - r7}
+		subs	ip, ip, #16
+		orr	r3, r3, r4, push #24
+		mov	r4, r4, pull #8
+		orr	r4, r4, r5, push #24
+		mov	r5, r5, pull #8
+		orr	r5, r5, r6, push #24
+		mov	r6, r6, pull #8
+		orr	r6, r6, r7, push #24
+		stmia	r0!, {r3 - r6}			@ Shouldnt fault
+		bpl	.Lc2u_1cpy8lp
+
+.Lc2u_1rem8lp:	tst	ip, #8
+		movne	r3, r7, pull #8
+		ldmneia	r1!, {r4, r7}
+		orrne	r3, r3, r4, push #24
+		movne	r4, r4, pull #8
+		orrne	r4, r4, r7, push #24
+		stmneia	r0!, {r3 - r4}			@ Shouldnt fault
+		tst	ip, #4
+		movne	r3, r7, pull #8
+		ldrne	r7, [r1], #4
+		orrne	r3, r3, r7, push #24
+	TUSER(	strne) r3, [r0], #4			@ Shouldnt fault
+		ands	ip, ip, #3
+		beq	.Lc2u_1fupi
+.Lc2u_1nowords:	mov	r3, r7, get_byte_1
+		teq	ip, #0
+		beq	.Lc2u_finished
+		cmp	ip, #2
+USER(	TUSER(	strb)	r3, [r0], #1)			@ May fault
+		movge	r3, r7, get_byte_2
+USER(	TUSER(	strgeb) r3, [r0], #1)			@ May fault
+		movgt	r3, r7, get_byte_3
+USER(	TUSER(	strgtb) r3, [r0], #1)			@ May fault
+		b	.Lc2u_finished
+
+.Lc2u_2fupi:	subs	r2, r2, #4
+		addmi	ip, r2, #4
+		bmi	.Lc2u_2nowords
+		mov	r3, r7, pull #16
+		ldr	r7, [r1], #4
+		orr	r3, r3, r7, push #16
+USER(	TUSER(	str)	r3, [r0], #4)			@ May fault
+		mov	ip, r0, lsl #32 - PAGE_SHIFT
+		rsb	ip, ip, #0
+		movs	ip, ip, lsr #32 - PAGE_SHIFT
+		beq	.Lc2u_2fupi
+		cmp	r2, ip
+		movlt	ip, r2
+		sub	r2, r2, ip
+		subs	ip, ip, #16
+		blt	.Lc2u_2rem8lp
+
+.Lc2u_2cpy8lp:	mov	r3, r7, pull #16
+		ldmia	r1!, {r4 - r7}
+		subs	ip, ip, #16
+		orr	r3, r3, r4, push #16
+		mov	r4, r4, pull #16
+		orr	r4, r4, r5, push #16
+		mov	r5, r5, pull #16
+		orr	r5, r5, r6, push #16
+		mov	r6, r6, pull #16
+		orr	r6, r6, r7, push #16
+		stmia	r0!, {r3 - r6}			@ Shouldnt fault
+		bpl	.Lc2u_2cpy8lp
+
+.Lc2u_2rem8lp:	tst	ip, #8
+		movne	r3, r7, pull #16
+		ldmneia	r1!, {r4, r7}
+		orrne	r3, r3, r4, push #16
+		movne	r4, r4, pull #16
+		orrne	r4, r4, r7, push #16
+		stmneia	r0!, {r3 - r4}			@ Shouldnt fault
+		tst	ip, #4
+		movne	r3, r7, pull #16
+		ldrne	r7, [r1], #4
+		orrne	r3, r3, r7, push #16
+	TUSER(	strne) r3, [r0], #4			@ Shouldnt fault
+		ands	ip, ip, #3
+		beq	.Lc2u_2fupi
+.Lc2u_2nowords:	mov	r3, r7, get_byte_2
+		teq	ip, #0
+		beq	.Lc2u_finished
+		cmp	ip, #2
+USER(	TUSER(	strb)	r3, [r0], #1)			@ May fault
+		movge	r3, r7, get_byte_3
+USER(	TUSER(	strgeb) r3, [r0], #1)			@ May fault
+		ldrgtb	r3, [r1], #0
+USER(	TUSER(	strgtb) r3, [r0], #1)			@ May fault
+		b	.Lc2u_finished
+
+.Lc2u_3fupi:	subs	r2, r2, #4
+		addmi	ip, r2, #4
+		bmi	.Lc2u_3nowords
+		mov	r3, r7, pull #24
+		ldr	r7, [r1], #4
+		orr	r3, r3, r7, push #8
+USER(	TUSER(	str)	r3, [r0], #4)			@ May fault
+		mov	ip, r0, lsl #32 - PAGE_SHIFT
+		rsb	ip, ip, #0
+		movs	ip, ip, lsr #32 - PAGE_SHIFT
+		beq	.Lc2u_3fupi
+		cmp	r2, ip
+		movlt	ip, r2
+		sub	r2, r2, ip
+		subs	ip, ip, #16
+		blt	.Lc2u_3rem8lp
+
+.Lc2u_3cpy8lp:	mov	r3, r7, pull #24
+		ldmia	r1!, {r4 - r7}
+		subs	ip, ip, #16
+		orr	r3, r3, r4, push #8
+		mov	r4, r4, pull #24
+		orr	r4, r4, r5, push #8
+		mov	r5, r5, pull #24
+		orr	r5, r5, r6, push #8
+		mov	r6, r6, pull #24
+		orr	r6, r6, r7, push #8
+		stmia	r0!, {r3 - r6}			@ Shouldnt fault
+		bpl	.Lc2u_3cpy8lp
+
+.Lc2u_3rem8lp:	tst	ip, #8
+		movne	r3, r7, pull #24
+		ldmneia	r1!, {r4, r7}
+		orrne	r3, r3, r4, push #8
+		movne	r4, r4, pull #24
+		orrne	r4, r4, r7, push #8
+		stmneia	r0!, {r3 - r4}			@ Shouldnt fault
+		tst	ip, #4
+		movne	r3, r7, pull #24
+		ldrne	r7, [r1], #4
+		orrne	r3, r3, r7, push #8
+	TUSER(	strne) r3, [r0], #4			@ Shouldnt fault
+		ands	ip, ip, #3
+		beq	.Lc2u_3fupi
+.Lc2u_3nowords:	mov	r3, r7, get_byte_3
+		teq	ip, #0
+		beq	.Lc2u_finished
+		cmp	ip, #2
+USER(	TUSER(	strb)	r3, [r0], #1)			@ May fault
+		ldrgeb	r3, [r1], #1
+USER(	TUSER(	strgeb) r3, [r0], #1)			@ May fault
+		ldrgtb	r3, [r1], #0
+USER(	TUSER(	strgtb) r3, [r0], #1)			@ May fault
+		b	.Lc2u_finished
+ENDPROC(__copy_to_user)
+
+		.pushsection .fixup,"ax"
+		.align	0
+9001:		ldmfd	sp!, {r0, r4 - r7, pc}
+		.popsection
+
+/* Prototype: unsigned long __copy_from_user(void *to,const void *from,unsigned long n);
+ * Purpose  : copy a block from user memory to kernel memory
+ * Params   : to   - kernel memory
+ *          : from - user memory
+ *          : n    - number of bytes to copy
+ * Returns  : Number of bytes NOT copied.
+ */
+.Lcfu_dest_not_aligned:
+		rsb	ip, ip, #4
+		cmp	ip, #2
+USER(	TUSER(	ldrb)	r3, [r1], #1)			@ May fault
+		strb	r3, [r0], #1
+USER(	TUSER(	ldrgeb) r3, [r1], #1)			@ May fault
+		strgeb	r3, [r0], #1
+USER(	TUSER(	ldrgtb) r3, [r1], #1)			@ May fault
+		strgtb	r3, [r0], #1
+		sub	r2, r2, ip
+		b	.Lcfu_dest_aligned
+
+ENTRY(__copy_from_user)
+		stmfd	sp!, {r0, r2, r4 - r7, lr}
+		cmp	r2, #4
+		blt	.Lcfu_not_enough
+		ands	ip, r0, #3
+		bne	.Lcfu_dest_not_aligned
+.Lcfu_dest_aligned:
+		ands	ip, r1, #3
+		bne	.Lcfu_src_not_aligned
+
+/*
+ * Seeing as there has to be at least 8 bytes to copy, we can
+ * copy one word, and force a user-mode page fault...
+ */
+
+.Lcfu_0fupi:	subs	r2, r2, #4
+		addmi	ip, r2, #4
+		bmi	.Lcfu_0nowords
+USER(	TUSER(	ldr)	r3, [r1], #4)
+		str	r3, [r0], #4
+		mov	ip, r1, lsl #32 - PAGE_SHIFT	@ On each page, use a ld/st??t instruction
+		rsb	ip, ip, #0
+		movs	ip, ip, lsr #32 - PAGE_SHIFT
+		beq	.Lcfu_0fupi
+/*
+ * ip = max no. of bytes to copy before needing another "strt" insn
+ */
+		cmp	r2, ip
+		movlt	ip, r2
+		sub	r2, r2, ip
+		subs	ip, ip, #32
+		blt	.Lcfu_0rem8lp
+
+.Lcfu_0cpy8lp:	ldmia	r1!, {r3 - r6}			@ Shouldnt fault
+		stmia	r0!, {r3 - r6}
+		ldmia	r1!, {r3 - r6}			@ Shouldnt fault
+		subs	ip, ip, #32
+		stmia	r0!, {r3 - r6}
+		bpl	.Lcfu_0cpy8lp
+
+.Lcfu_0rem8lp:	cmn	ip, #16
+		ldmgeia	r1!, {r3 - r6}			@ Shouldnt fault
+		stmgeia	r0!, {r3 - r6}
+		tst	ip, #8
+		ldmneia	r1!, {r3 - r4}			@ Shouldnt fault
+		stmneia	r0!, {r3 - r4}
+		tst	ip, #4
+	TUSER(	ldrne) r3, [r1], #4			@ Shouldnt fault
+		strne	r3, [r0], #4
+		ands	ip, ip, #3
+		beq	.Lcfu_0fupi
+.Lcfu_0nowords:	teq	ip, #0
+		beq	.Lcfu_finished
+.Lcfu_nowords:	cmp	ip, #2
+USER(	TUSER(	ldrb)	r3, [r1], #1)			@ May fault
+		strb	r3, [r0], #1
+USER(	TUSER(	ldrgeb) r3, [r1], #1)			@ May fault
+		strgeb	r3, [r0], #1
+USER(	TUSER(	ldrgtb) r3, [r1], #1)			@ May fault
+		strgtb	r3, [r0], #1
+		b	.Lcfu_finished
+
+.Lcfu_not_enough:
+		movs	ip, r2
+		bne	.Lcfu_nowords
+.Lcfu_finished:	mov	r0, #0
+		add	sp, sp, #8
+		ldmfd	sp!, {r4 - r7, pc}
+
+.Lcfu_src_not_aligned:
+		bic	r1, r1, #3
+USER(	TUSER(	ldr)	r7, [r1], #4)			@ May fault
+		cmp	ip, #2
+		bgt	.Lcfu_3fupi
+		beq	.Lcfu_2fupi
+.Lcfu_1fupi:	subs	r2, r2, #4
+		addmi	ip, r2, #4
+		bmi	.Lcfu_1nowords
+		mov	r3, r7, pull #8
+USER(	TUSER(	ldr)	r7, [r1], #4)			@ May fault
+		orr	r3, r3, r7, push #24
+		str	r3, [r0], #4
+		mov	ip, r1, lsl #32 - PAGE_SHIFT
+		rsb	ip, ip, #0
+		movs	ip, ip, lsr #32 - PAGE_SHIFT
+		beq	.Lcfu_1fupi
+		cmp	r2, ip
+		movlt	ip, r2
+		sub	r2, r2, ip
+		subs	ip, ip, #16
+		blt	.Lcfu_1rem8lp
+
+.Lcfu_1cpy8lp:	mov	r3, r7, pull #8
+		ldmia	r1!, {r4 - r7}			@ Shouldnt fault
+		subs	ip, ip, #16
+		orr	r3, r3, r4, push #24
+		mov	r4, r4, pull #8
+		orr	r4, r4, r5, push #24
+		mov	r5, r5, pull #8
+		orr	r5, r5, r6, push #24
+		mov	r6, r6, pull #8
+		orr	r6, r6, r7, push #24
+		stmia	r0!, {r3 - r6}
+		bpl	.Lcfu_1cpy8lp
+
+.Lcfu_1rem8lp:	tst	ip, #8
+		movne	r3, r7, pull #8
+		ldmneia	r1!, {r4, r7}			@ Shouldnt fault
+		orrne	r3, r3, r4, push #24
+		movne	r4, r4, pull #8
+		orrne	r4, r4, r7, push #24
+		stmneia	r0!, {r3 - r4}
+		tst	ip, #4
+		movne	r3, r7, pull #8
+USER(	TUSER(	ldrne) r7, [r1], #4)			@ May fault
+		orrne	r3, r3, r7, push #24
+		strne	r3, [r0], #4
+		ands	ip, ip, #3
+		beq	.Lcfu_1fupi
+.Lcfu_1nowords:	mov	r3, r7, get_byte_1
+		teq	ip, #0
+		beq	.Lcfu_finished
+		cmp	ip, #2
+		strb	r3, [r0], #1
+		movge	r3, r7, get_byte_2
+		strgeb	r3, [r0], #1
+		movgt	r3, r7, get_byte_3
+		strgtb	r3, [r0], #1
+		b	.Lcfu_finished
+
+.Lcfu_2fupi:	subs	r2, r2, #4
+		addmi	ip, r2, #4
+		bmi	.Lcfu_2nowords
+		mov	r3, r7, pull #16
+USER(	TUSER(	ldr)	r7, [r1], #4)			@ May fault
+		orr	r3, r3, r7, push #16
+		str	r3, [r0], #4
+		mov	ip, r1, lsl #32 - PAGE_SHIFT
+		rsb	ip, ip, #0
+		movs	ip, ip, lsr #32 - PAGE_SHIFT
+		beq	.Lcfu_2fupi
+		cmp	r2, ip
+		movlt	ip, r2
+		sub	r2, r2, ip
+		subs	ip, ip, #16
+		blt	.Lcfu_2rem8lp
+
+
+.Lcfu_2cpy8lp:	mov	r3, r7, pull #16
+		ldmia	r1!, {r4 - r7}			@ Shouldnt fault
+		subs	ip, ip, #16
+		orr	r3, r3, r4, push #16
+		mov	r4, r4, pull #16
+		orr	r4, r4, r5, push #16
+		mov	r5, r5, pull #16
+		orr	r5, r5, r6, push #16
+		mov	r6, r6, pull #16
+		orr	r6, r6, r7, push #16
+		stmia	r0!, {r3 - r6}
+		bpl	.Lcfu_2cpy8lp
+
+.Lcfu_2rem8lp:	tst	ip, #8
+		movne	r3, r7, pull #16
+		ldmneia	r1!, {r4, r7}			@ Shouldnt fault
+		orrne	r3, r3, r4, push #16
+		movne	r4, r4, pull #16
+		orrne	r4, r4, r7, push #16
+		stmneia	r0!, {r3 - r4}
+		tst	ip, #4
+		movne	r3, r7, pull #16
+USER(	TUSER(	ldrne) r7, [r1], #4)			@ May fault
+		orrne	r3, r3, r7, push #16
+		strne	r3, [r0], #4
+		ands	ip, ip, #3
+		beq	.Lcfu_2fupi
+.Lcfu_2nowords:	mov	r3, r7, get_byte_2
+		teq	ip, #0
+		beq	.Lcfu_finished
+		cmp	ip, #2
+		strb	r3, [r0], #1
+		movge	r3, r7, get_byte_3
+		strgeb	r3, [r0], #1
+USER(	TUSER(	ldrgtb) r3, [r1], #0)			@ May fault
+		strgtb	r3, [r0], #1
+		b	.Lcfu_finished
+
+.Lcfu_3fupi:	subs	r2, r2, #4
+		addmi	ip, r2, #4
+		bmi	.Lcfu_3nowords
+		mov	r3, r7, pull #24
+USER(	TUSER(	ldr)	r7, [r1], #4)			@ May fault
+		orr	r3, r3, r7, push #8
+		str	r3, [r0], #4
+		mov	ip, r1, lsl #32 - PAGE_SHIFT
+		rsb	ip, ip, #0
+		movs	ip, ip, lsr #32 - PAGE_SHIFT
+		beq	.Lcfu_3fupi
+		cmp	r2, ip
+		movlt	ip, r2
+		sub	r2, r2, ip
+		subs	ip, ip, #16
+		blt	.Lcfu_3rem8lp
+
+.Lcfu_3cpy8lp:	mov	r3, r7, pull #24
+		ldmia	r1!, {r4 - r7}			@ Shouldnt fault
+		orr	r3, r3, r4, push #8
+		mov	r4, r4, pull #24
+		orr	r4, r4, r5, push #8
+		mov	r5, r5, pull #24
+		orr	r5, r5, r6, push #8
+		mov	r6, r6, pull #24
+		orr	r6, r6, r7, push #8
+		stmia	r0!, {r3 - r6}
+		subs	ip, ip, #16
+		bpl	.Lcfu_3cpy8lp
+
+.Lcfu_3rem8lp:	tst	ip, #8
+		movne	r3, r7, pull #24
+		ldmneia	r1!, {r4, r7}			@ Shouldnt fault
+		orrne	r3, r3, r4, push #8
+		movne	r4, r4, pull #24
+		orrne	r4, r4, r7, push #8
+		stmneia	r0!, {r3 - r4}
+		tst	ip, #4
+		movne	r3, r7, pull #24
+USER(	TUSER(	ldrne) r7, [r1], #4)			@ May fault
+		orrne	r3, r3, r7, push #8
+		strne	r3, [r0], #4
+		ands	ip, ip, #3
+		beq	.Lcfu_3fupi
+.Lcfu_3nowords:	mov	r3, r7, get_byte_3
+		teq	ip, #0
+		beq	.Lcfu_finished
+		cmp	ip, #2
+		strb	r3, [r0], #1
+USER(	TUSER(	ldrgeb) r3, [r1], #1)			@ May fault
+		strgeb	r3, [r0], #1
+USER(	TUSER(	ldrgtb) r3, [r1], #1)			@ May fault
+		strgtb	r3, [r0], #1
+		b	.Lcfu_finished
+ENDPROC(__copy_from_user)
+
+		.pushsection .fixup,"ax"
+		.align	0
+		/*
+		 * We took an exception.  r0 contains a pointer to
+		 * the byte not copied.
+		 */
+9001:		ldr	r2, [sp], #4			@ void *to
+		sub	r2, r0, r2			@ bytes copied
+		ldr	r1, [sp], #4			@ unsigned long count
+		subs	r4, r1, r2			@ bytes left to copy
+		movne	r1, r4
+		blne	__memzero
+		mov	r0, r4
+		ldmfd	sp!, {r4 - r7, pc}
+		.popsection
+
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index 01fb732..9ac427a 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -294,9 +294,9 @@ void __init at91_add_device_cf(struct at91_cf_data *data) {}
  *  MMC / SD
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
 static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct at91_mmc_data mmc_data;
+static struct mci_platform_data mmc_data;
 
 static struct resource mmc_resources[] = {
 	[0] = {
@@ -312,7 +312,7 @@ static struct resource mmc_resources[] = {
 };
 
 static struct platform_device at91rm9200_mmc_device = {
-	.name		= "at91_mci",
+	.name		= "atmel_mci",
 	.id		= -1,
 	.dev		= {
 				.dma_mask		= &mmc_dmamask,
@@ -323,53 +323,69 @@ static struct platform_device at91rm9200_mmc_device = {
 	.num_resources	= ARRAY_SIZE(mmc_resources),
 };
 
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
 {
+	unsigned int i;
+	unsigned int slot_count = 0;
+
 	if (!data)
 		return;
 
-	/* input/irq */
-	if (gpio_is_valid(data->det_pin)) {
-		at91_set_gpio_input(data->det_pin, 1);
-		at91_set_deglitch(data->det_pin, 1);
-	}
-	if (gpio_is_valid(data->wp_pin))
-		at91_set_gpio_input(data->wp_pin, 1);
-	if (gpio_is_valid(data->vcc_pin))
-		at91_set_gpio_output(data->vcc_pin, 0);
-
-	/* CLK */
-	at91_set_A_periph(AT91_PIN_PA27, 0);
+	for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
 
-	if (data->slot_b) {
-		/* CMD */
-		at91_set_B_periph(AT91_PIN_PA8, 1);
+		if (!data->slot[i].bus_width)
+			continue;
 
-		/* DAT0, maybe DAT1..DAT3 */
-		at91_set_B_periph(AT91_PIN_PA9, 1);
-		if (data->wire4) {
-			at91_set_B_periph(AT91_PIN_PA10, 1);
-			at91_set_B_periph(AT91_PIN_PA11, 1);
-			at91_set_B_periph(AT91_PIN_PA12, 1);
+		/* input/irq */
+		if (gpio_is_valid(data->slot[i].detect_pin)) {
+			at91_set_gpio_input(data->slot[i].detect_pin, 1);
+			at91_set_deglitch(data->slot[i].detect_pin, 1);
 		}
-	} else {
-		/* CMD */
-		at91_set_A_periph(AT91_PIN_PA28, 1);
-
-		/* DAT0, maybe DAT1..DAT3 */
-		at91_set_A_periph(AT91_PIN_PA29, 1);
-		if (data->wire4) {
-			at91_set_B_periph(AT91_PIN_PB3, 1);
-			at91_set_B_periph(AT91_PIN_PB4, 1);
-			at91_set_B_periph(AT91_PIN_PB5, 1);
+		if (gpio_is_valid(data->slot[i].wp_pin))
+			at91_set_gpio_input(data->slot[i].wp_pin, 1);
+
+		switch (i) {
+		case 0:					/* slot A */
+			/* CMD */
+			at91_set_A_periph(AT91_PIN_PA28, 1);
+			/* DAT0, maybe DAT1..DAT3 */
+			at91_set_A_periph(AT91_PIN_PA29, 1);
+			if (data->slot[i].bus_width == 4) {
+				at91_set_B_periph(AT91_PIN_PB3, 1);
+				at91_set_B_periph(AT91_PIN_PB4, 1);
+				at91_set_B_periph(AT91_PIN_PB5, 1);
+			}
+			slot_count++;
+			break;
+		case 1:					/* slot B */
+			/* CMD */
+			at91_set_B_periph(AT91_PIN_PA8, 1);
+			/* DAT0, maybe DAT1..DAT3 */
+			at91_set_B_periph(AT91_PIN_PA9, 1);
+			if (data->slot[i].bus_width == 4) {
+				at91_set_B_periph(AT91_PIN_PA10, 1);
+				at91_set_B_periph(AT91_PIN_PA11, 1);
+				at91_set_B_periph(AT91_PIN_PA12, 1);
+			}
+			slot_count++;
+			break;
+		default:
+			printk(KERN_ERR
+			       "AT91: SD/MMC slot %d not available\n", i);
+			break;
+		}
+		if (slot_count) {
+			/* CLK */
+			at91_set_A_periph(AT91_PIN_PA27, 0);
+
+			mmc_data = *data;
+			platform_device_register(&at91rm9200_mmc_device);
 		}
 	}
 
-	mmc_data = *data;
-	platform_device_register(&at91rm9200_mmc_device);
 }
 #else
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
 #endif
 
 
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index 7b9c2ba..156e639 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -209,92 +209,10 @@ void __init at91_add_device_eth(struct macb_platform_data *data) {}
 
 
 /* --------------------------------------------------------------------
- *  MMC / SD
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
-static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct at91_mmc_data mmc_data;
-
-static struct resource mmc_resources[] = {
-	[0] = {
-		.start	= AT91SAM9260_BASE_MCI,
-		.end	= AT91SAM9260_BASE_MCI + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
-		.end	= NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91sam9260_mmc_device = {
-	.name		= "at91_mci",
-	.id		= -1,
-	.dev		= {
-				.dma_mask		= &mmc_dmamask,
-				.coherent_dma_mask	= DMA_BIT_MASK(32),
-				.platform_data		= &mmc_data,
-	},
-	.resource	= mmc_resources,
-	.num_resources	= ARRAY_SIZE(mmc_resources),
-};
-
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
-{
-	if (!data)
-		return;
-
-	/* input/irq */
-	if (gpio_is_valid(data->det_pin)) {
-		at91_set_gpio_input(data->det_pin, 1);
-		at91_set_deglitch(data->det_pin, 1);
-	}
-	if (gpio_is_valid(data->wp_pin))
-		at91_set_gpio_input(data->wp_pin, 1);
-	if (gpio_is_valid(data->vcc_pin))
-		at91_set_gpio_output(data->vcc_pin, 0);
-
-	/* CLK */
-	at91_set_A_periph(AT91_PIN_PA8, 0);
-
-	if (data->slot_b) {
-		/* CMD */
-		at91_set_B_periph(AT91_PIN_PA1, 1);
-
-		/* DAT0, maybe DAT1..DAT3 */
-		at91_set_B_periph(AT91_PIN_PA0, 1);
-		if (data->wire4) {
-			at91_set_B_periph(AT91_PIN_PA5, 1);
-			at91_set_B_periph(AT91_PIN_PA4, 1);
-			at91_set_B_periph(AT91_PIN_PA3, 1);
-		}
-	} else {
-		/* CMD */
-		at91_set_A_periph(AT91_PIN_PA7, 1);
-
-		/* DAT0, maybe DAT1..DAT3 */
-		at91_set_A_periph(AT91_PIN_PA6, 1);
-		if (data->wire4) {
-			at91_set_A_periph(AT91_PIN_PA9, 1);
-			at91_set_A_periph(AT91_PIN_PA10, 1);
-			at91_set_A_periph(AT91_PIN_PA11, 1);
-		}
-	}
-
-	mmc_data = *data;
-	platform_device_register(&at91sam9260_mmc_device);
-}
-#else
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
-#endif
-
-/* --------------------------------------------------------------------
  *  MMC / SD Slot for Atmel MCI Driver
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
 static u64 mmc_dmamask = DMA_BIT_MASK(32);
 static struct mci_platform_data mmc_data;
 
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 8df5c1b..06c0c6e 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -137,9 +137,9 @@ void __init at91_add_device_udc(struct at91_udc_data *data) {}
  *  MMC / SD
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
 static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct at91_mmc_data mmc_data;
+static struct mci_platform_data mmc_data;
 
 static struct resource mmc_resources[] = {
 	[0] = {
@@ -155,7 +155,7 @@ static struct resource mmc_resources[] = {
 };
 
 static struct platform_device at91sam9261_mmc_device = {
-	.name		= "at91_mci",
+	.name		= "atmel_mci",
 	.id		= -1,
 	.dev		= {
 				.dma_mask		= &mmc_dmamask,
@@ -166,40 +166,40 @@ static struct platform_device at91sam9261_mmc_device = {
 	.num_resources	= ARRAY_SIZE(mmc_resources),
 };
 
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
 {
 	if (!data)
 		return;
 
-	/* input/irq */
-	if (gpio_is_valid(data->det_pin)) {
-		at91_set_gpio_input(data->det_pin, 1);
-		at91_set_deglitch(data->det_pin, 1);
-	}
-	if (gpio_is_valid(data->wp_pin))
-		at91_set_gpio_input(data->wp_pin, 1);
-	if (gpio_is_valid(data->vcc_pin))
-		at91_set_gpio_output(data->vcc_pin, 0);
-
-	/* CLK */
-	at91_set_B_periph(AT91_PIN_PA2, 0);
-
-	/* CMD */
-	at91_set_B_periph(AT91_PIN_PA1, 1);
-
-	/* DAT0, maybe DAT1..DAT3 */
-	at91_set_B_periph(AT91_PIN_PA0, 1);
-	if (data->wire4) {
-		at91_set_B_periph(AT91_PIN_PA4, 1);
-		at91_set_B_periph(AT91_PIN_PA5, 1);
-		at91_set_B_periph(AT91_PIN_PA6, 1);
-	}
+	if (data->slot[0].bus_width) {
+		/* input/irq */
+		if (gpio_is_valid(data->slot[0].detect_pin)) {
+			at91_set_gpio_input(data->slot[0].detect_pin, 1);
+			at91_set_deglitch(data->slot[0].detect_pin, 1);
+		}
+		if (gpio_is_valid(data->slot[0].wp_pin))
+			at91_set_gpio_input(data->slot[0].wp_pin, 1);
+
+		/* CLK */
+		at91_set_B_periph(AT91_PIN_PA2, 0);
 
-	mmc_data = *data;
-	platform_device_register(&at91sam9261_mmc_device);
+		/* CMD */
+		at91_set_B_periph(AT91_PIN_PA1, 1);
+
+		/* DAT0, maybe DAT1..DAT3 */
+		at91_set_B_periph(AT91_PIN_PA0, 1);
+		if (data->slot[0].bus_width == 4) {
+			at91_set_B_periph(AT91_PIN_PA4, 1);
+			at91_set_B_periph(AT91_PIN_PA5, 1);
+			at91_set_B_periph(AT91_PIN_PA6, 1);
+		}
+
+		mmc_data = *data;
+		platform_device_register(&at91sam9261_mmc_device);
+	}
 }
 #else
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
 #endif
 
 
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index 84b3810..144ef5d 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -188,8 +188,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
 	CLKDEV_CON_ID("hclk", &macb_clk),
 	CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
 	CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
-	CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
-	CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
+	CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk),
+	CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk),
 	CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
 	CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
 	CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index eb6bbf8..1e176aa 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -218,9 +218,9 @@ void __init at91_add_device_eth(struct macb_platform_data *data) {}
  *  MMC / SD
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
 static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct at91_mmc_data mmc0_data, mmc1_data;
+static struct mci_platform_data mmc0_data, mmc1_data;
 
 static struct resource mmc0_resources[] = {
 	[0] = {
@@ -236,7 +236,7 @@ static struct resource mmc0_resources[] = {
 };
 
 static struct platform_device at91sam9263_mmc0_device = {
-	.name		= "at91_mci",
+	.name		= "atmel_mci",
 	.id		= 0,
 	.dev		= {
 				.dma_mask		= &mmc_dmamask,
@@ -261,7 +261,7 @@ static struct resource mmc1_resources[] = {
 };
 
 static struct platform_device at91sam9263_mmc1_device = {
-	.name		= "at91_mci",
+	.name		= "atmel_mci",
 	.id		= 1,
 	.dev		= {
 				.dma_mask		= &mmc_dmamask,
@@ -272,85 +272,110 @@ static struct platform_device at91sam9263_mmc1_device = {
 	.num_resources	= ARRAY_SIZE(mmc1_resources),
 };
 
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
 {
+	unsigned int i;
+	unsigned int slot_count = 0;
+
 	if (!data)
 		return;
 
-	/* input/irq */
-	if (gpio_is_valid(data->det_pin)) {
-		at91_set_gpio_input(data->det_pin, 1);
-		at91_set_deglitch(data->det_pin, 1);
-	}
-	if (gpio_is_valid(data->wp_pin))
-		at91_set_gpio_input(data->wp_pin, 1);
-	if (gpio_is_valid(data->vcc_pin))
-		at91_set_gpio_output(data->vcc_pin, 0);
+	for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
 
-	if (mmc_id == 0) {		/* MCI0 */
-		/* CLK */
-		at91_set_A_periph(AT91_PIN_PA12, 0);
+		if (!data->slot[i].bus_width)
+			continue;
 
-		if (data->slot_b) {
-			/* CMD */
-			at91_set_A_periph(AT91_PIN_PA16, 1);
+		/* input/irq */
+		if (gpio_is_valid(data->slot[i].detect_pin)) {
+			at91_set_gpio_input(data->slot[i].detect_pin,
+					1);
+			at91_set_deglitch(data->slot[i].detect_pin,
+					1);
+		}
+		if (gpio_is_valid(data->slot[i].wp_pin))
+			at91_set_gpio_input(data->slot[i].wp_pin, 1);
+
+		if (mmc_id == 0) {				/* MCI0 */
+			switch (i) {
+			case 0:					/* slot A */
+				/* CMD */
+				at91_set_A_periph(AT91_PIN_PA1, 1);
+				/* DAT0, maybe DAT1..DAT3 */
+				at91_set_A_periph(AT91_PIN_PA0, 1);
+				if (data->slot[i].bus_width == 4) {
+					at91_set_A_periph(AT91_PIN_PA3, 1);
+					at91_set_A_periph(AT91_PIN_PA4, 1);
+					at91_set_A_periph(AT91_PIN_PA5, 1);
+				}
+				slot_count++;
+				break;
+			case 1:					/* slot B */
+				/* CMD */
+				at91_set_A_periph(AT91_PIN_PA16, 1);
+				/* DAT0, maybe DAT1..DAT3 */
+				at91_set_A_periph(AT91_PIN_PA17, 1);
+				if (data->slot[i].bus_width == 4) {
+					at91_set_A_periph(AT91_PIN_PA18, 1);
+					at91_set_A_periph(AT91_PIN_PA19, 1);
+					at91_set_A_periph(AT91_PIN_PA20, 1);
+				}
+				slot_count++;
+				break;
+			default:
+				printk(KERN_ERR
+				       "AT91: SD/MMC slot %d not available\n", i);
+				break;
+			}
+			if (slot_count) {
+				/* CLK */
+				at91_set_A_periph(AT91_PIN_PA12, 0);
 
-			/* DAT0, maybe DAT1..DAT3 */
-			at91_set_A_periph(AT91_PIN_PA17, 1);
-			if (data->wire4) {
-				at91_set_A_periph(AT91_PIN_PA18, 1);
-				at91_set_A_periph(AT91_PIN_PA19, 1);
-				at91_set_A_periph(AT91_PIN_PA20, 1);
+				mmc0_data = *data;
+				platform_device_register(&at91sam9263_mmc0_device);
 			}
-		} else {
-			/* CMD */
-			at91_set_A_periph(AT91_PIN_PA1, 1);
-
-			/* DAT0, maybe DAT1..DAT3 */
-			at91_set_A_periph(AT91_PIN_PA0, 1);
-			if (data->wire4) {
-				at91_set_A_periph(AT91_PIN_PA3, 1);
-				at91_set_A_periph(AT91_PIN_PA4, 1);
-				at91_set_A_periph(AT91_PIN_PA5, 1);
+		} else if (mmc_id == 1) {			/* MCI1 */
+			switch (i) {
+			case 0:					/* slot A */
+				/* CMD */
+				at91_set_A_periph(AT91_PIN_PA7, 1);
+				/* DAT0, maybe DAT1..DAT3 */
+				at91_set_A_periph(AT91_PIN_PA8, 1);
+				if (data->slot[i].bus_width == 4) {
+					at91_set_A_periph(AT91_PIN_PA9, 1);
+					at91_set_A_periph(AT91_PIN_PA10, 1);
+					at91_set_A_periph(AT91_PIN_PA11, 1);
+				}
+				slot_count++;
+				break;
+			case 1:					/* slot B */
+				/* CMD */
+				at91_set_A_periph(AT91_PIN_PA21, 1);
+				/* DAT0, maybe DAT1..DAT3 */
+				at91_set_A_periph(AT91_PIN_PA22, 1);
+				if (data->slot[i].bus_width == 4) {
+					at91_set_A_periph(AT91_PIN_PA23, 1);
+					at91_set_A_periph(AT91_PIN_PA24, 1);
+					at91_set_A_periph(AT91_PIN_PA25, 1);
+				}
+				slot_count++;
+				break;
+			default:
+				printk(KERN_ERR
+				       "AT91: SD/MMC slot %d not available\n", i);
+				break;
 			}
-		}
+			if (slot_count) {
+				/* CLK */
+				at91_set_A_periph(AT91_PIN_PA6, 0);
 
-		mmc0_data = *data;
-		platform_device_register(&at91sam9263_mmc0_device);
-	} else {			/* MCI1 */
-		/* CLK */
-		at91_set_A_periph(AT91_PIN_PA6, 0);
-
-		if (data->slot_b) {
-			/* CMD */
-			at91_set_A_periph(AT91_PIN_PA21, 1);
-
-			/* DAT0, maybe DAT1..DAT3 */
-			at91_set_A_periph(AT91_PIN_PA22, 1);
-			if (data->wire4) {
-				at91_set_A_periph(AT91_PIN_PA23, 1);
-				at91_set_A_periph(AT91_PIN_PA24, 1);
-				at91_set_A_periph(AT91_PIN_PA25, 1);
-			}
-		} else {
-			/* CMD */
-			at91_set_A_periph(AT91_PIN_PA7, 1);
-
-			/* DAT0, maybe DAT1..DAT3 */
-			at91_set_A_periph(AT91_PIN_PA8, 1);
-			if (data->wire4) {
-				at91_set_A_periph(AT91_PIN_PA9, 1);
-				at91_set_A_periph(AT91_PIN_PA10, 1);
-				at91_set_A_periph(AT91_PIN_PA11, 1);
+				mmc1_data = *data;
+				platform_device_register(&at91sam9263_mmc1_device);
 			}
 		}
-
-		mmc1_data = *data;
-		platform_device_register(&at91sam9263_mmc1_device);
 	}
 }
 #else
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
 #endif
 
 /* --------------------------------------------------------------------
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index f09fff9..ea4479e 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -161,9 +161,9 @@ void __init at91_add_device_usba(struct usba_platform_data *data) {}
  *  MMC / SD
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
 static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct at91_mmc_data mmc_data;
+static struct mci_platform_data mmc_data;
 
 static struct resource mmc_resources[] = {
 	[0] = {
@@ -179,7 +179,7 @@ static struct resource mmc_resources[] = {
 };
 
 static struct platform_device at91sam9rl_mmc_device = {
-	.name		= "at91_mci",
+	.name		= "atmel_mci",
 	.id		= -1,
 	.dev		= {
 				.dma_mask		= &mmc_dmamask,
@@ -190,40 +190,40 @@ static struct platform_device at91sam9rl_mmc_device = {
 	.num_resources	= ARRAY_SIZE(mmc_resources),
 };
 
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
 {
 	if (!data)
 		return;
 
-	/* input/irq */
-	if (gpio_is_valid(data->det_pin)) {
-		at91_set_gpio_input(data->det_pin, 1);
-		at91_set_deglitch(data->det_pin, 1);
-	}
-	if (gpio_is_valid(data->wp_pin))
-		at91_set_gpio_input(data->wp_pin, 1);
-	if (gpio_is_valid(data->vcc_pin))
-		at91_set_gpio_output(data->vcc_pin, 0);
-
-	/* CLK */
-	at91_set_A_periph(AT91_PIN_PA2, 0);
-
-	/* CMD */
-	at91_set_A_periph(AT91_PIN_PA1, 1);
-
-	/* DAT0, maybe DAT1..DAT3 */
-	at91_set_A_periph(AT91_PIN_PA0, 1);
-	if (data->wire4) {
-		at91_set_A_periph(AT91_PIN_PA3, 1);
-		at91_set_A_periph(AT91_PIN_PA4, 1);
-		at91_set_A_periph(AT91_PIN_PA5, 1);
+	if (data->slot[0].bus_width) {
+		/* input/irq */
+		if (gpio_is_valid(data->slot[0].detect_pin)) {
+			at91_set_gpio_input(data->slot[0].detect_pin, 1);
+			at91_set_deglitch(data->slot[0].detect_pin, 1);
+		}
+		if (gpio_is_valid(data->slot[0].wp_pin))
+			at91_set_gpio_input(data->slot[0].wp_pin, 1);
+
+		/* CLK */
+		at91_set_A_periph(AT91_PIN_PA2, 0);
+
+		/* CMD */
+		at91_set_A_periph(AT91_PIN_PA1, 1);
+
+		/* DAT0, maybe DAT1..DAT3 */
+		at91_set_A_periph(AT91_PIN_PA0, 1);
+		if (data->slot[0].bus_width == 4) {
+			at91_set_A_periph(AT91_PIN_PA3, 1);
+			at91_set_A_periph(AT91_PIN_PA4, 1);
+			at91_set_A_periph(AT91_PIN_PA5, 1);
+		}
+
+		mmc_data = *data;
+		platform_device_register(&at91sam9rl_mmc_device);
 	}
-
-	mmc_data = *data;
-	platform_device_register(&at91sam9rl_mmc_device);
 }
 #else
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
 #endif
 
 
diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
index de7be19..93a832f 100644
--- a/arch/arm/mach-at91/board-afeb-9260v1.c
+++ b/arch/arm/mach-at91/board-afeb-9260v1.c
@@ -133,12 +133,12 @@ static struct atmel_nand_data __initdata afeb9260_nand_data = {
 /*
  * MCI (SD/MMC)
  */
-static struct at91_mmc_data __initdata afeb9260_mmc_data = {
-	.det_pin 	= AT91_PIN_PC9,
-	.wp_pin 	= AT91_PIN_PC4,
-	.slot_b		= 1,
-	.wire4		= 1,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata afeb9260_mci0_data = {
+	.slot[1] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PC9,
+		.wp_pin		= AT91_PIN_PC4,
+	},
 };
 
 
@@ -199,7 +199,7 @@ static void __init afeb9260_board_init(void)
 	at91_set_B_periph(AT91_PIN_PA10, 0);	/* ETX2 */
 	at91_set_B_periph(AT91_PIN_PA11, 0);	/* ETX3 */
 	/* MMC */
-	at91_add_device_mmc(0, &afeb9260_mmc_data);
+	at91_add_device_mci(0, &afeb9260_mci0_data);
 	/* I2C */
 	at91_add_device_i2c(afeb9260_i2c_devices,
 			ARRAY_SIZE(afeb9260_i2c_devices));
diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c
index a5b002f..71d8f36 100644
--- a/arch/arm/mach-at91/board-carmeva.c
+++ b/arch/arm/mach-at91/board-carmeva.c
@@ -71,12 +71,12 @@ static struct at91_udc_data __initdata carmeva_udc_data = {
 	// .vcc_pin	= -EINVAL,
 // };
 
-static struct at91_mmc_data __initdata carmeva_mmc_data = {
-	.slot_b		= 0,
-	.wire4		= 1,
-	.det_pin	= AT91_PIN_PB10,
-	.wp_pin		= AT91_PIN_PC14,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata carmeva_mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PB10,
+		.wp_pin		= AT91_PIN_PC14,
+	},
 };
 
 static struct spi_board_info carmeva_spi_devices[] = {
@@ -150,7 +150,7 @@ static void __init carmeva_board_init(void)
 	/* Compact Flash */
 //	at91_add_device_cf(&carmeva_cf_data);
 	/* MMC */
-	at91_add_device_mmc(0, &carmeva_mmc_data);
+	at91_add_device_mci(0, &carmeva_mci0_data);
 	/* LEDs */
 	at91_gpio_leds(carmeva_leds, ARRAY_SIZE(carmeva_leds));
 }
diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
index ecbc13b..e71c473 100644
--- a/arch/arm/mach-at91/board-cpu9krea.c
+++ b/arch/arm/mach-at91/board-cpu9krea.c
@@ -254,8 +254,7 @@ static struct gpio_led cpu9krea_leds[] = {
 
 static struct i2c_board_info __initdata cpu9krea_i2c_devices[] = {
 	{
-		I2C_BOARD_INFO("rtc-ds1307", 0x68),
-		.type	= "ds1339",
+		I2C_BOARD_INFO("ds1339", 0x68),
 	},
 };
 
@@ -312,12 +311,12 @@ static void __init cpu9krea_add_device_buttons(void)
 /*
  * MCI (SD/MMC)
  */
-static struct at91_mmc_data __initdata cpu9krea_mmc_data = {
-	.slot_b		= 0,
-	.wire4		= 1,
-	.det_pin	= AT91_PIN_PA29,
-	.wp_pin		= -EINVAL,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata cpu9krea_mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PA29,
+		.wp_pin		= -EINVAL,
+	},
 };
 
 static void __init cpu9krea_board_init(void)
@@ -359,7 +358,7 @@ static void __init cpu9krea_board_init(void)
 	/* Ethernet */
 	at91_add_device_eth(&cpu9krea_macb_data);
 	/* MMC */
-	at91_add_device_mmc(0, &cpu9krea_mmc_data);
+	at91_add_device_mci(0, &cpu9krea_mci0_data);
 	/* I2C */
 	at91_add_device_i2c(cpu9krea_i2c_devices,
 		ARRAY_SIZE(cpu9krea_i2c_devices));
diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c
index 2e6d043..2cbd1a2 100644
--- a/arch/arm/mach-at91/board-cpuat91.c
+++ b/arch/arm/mach-at91/board-cpuat91.c
@@ -78,11 +78,12 @@ static struct at91_udc_data __initdata cpuat91_udc_data = {
 	.pullup_pin	= AT91_PIN_PC14,
 };
 
-static struct at91_mmc_data __initdata cpuat91_mmc_data = {
-	.det_pin	= AT91_PIN_PC2,
-	.wire4		= 1,
-	.wp_pin		= -EINVAL,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata cpuat91_mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PC2,
+		.wp_pin		= -EINVAL,
+	},
 };
 
 static struct physmap_flash_data cpuat91_flash_data = {
@@ -168,7 +169,7 @@ static void __init cpuat91_board_init(void)
 	/* USB Device */
 	at91_add_device_udc(&cpuat91_udc_data);
 	/* MMC */
-	at91_add_device_mmc(0, &cpuat91_mmc_data);
+	at91_add_device_mci(0, &cpuat91_mci0_data);
 	/* I2C */
 	at91_add_device_i2c(NULL, 0);
 	/* Platform devices */
diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
index 462bc31..3e37437 100644
--- a/arch/arm/mach-at91/board-csb337.c
+++ b/arch/arm/mach-at91/board-csb337.c
@@ -87,12 +87,12 @@ static struct at91_cf_data __initdata csb337_cf_data = {
 	.rst_pin	= AT91_PIN_PD2,
 };
 
-static struct at91_mmc_data __initdata csb337_mmc_data = {
-	.det_pin	= AT91_PIN_PD5,
-	.slot_b		= 0,
-	.wire4		= 1,
-	.wp_pin		= AT91_PIN_PD6,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata csb337_mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PD5,
+		.wp_pin		= AT91_PIN_PD6,
+	},
 };
 
 static struct spi_board_info csb337_spi_devices[] = {
@@ -220,8 +220,6 @@ static struct gpio_led csb_leds[] = {
 
 static void __init csb337_board_init(void)
 {
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
 	/* Serial */
 	/* DBGU on ttyS0 */
 	at91_register_uart(0, 0, 0);
@@ -240,7 +238,7 @@ static void __init csb337_board_init(void)
 	/* SPI */
 	at91_add_device_spi(csb337_spi_devices, ARRAY_SIZE(csb337_spi_devices));
 	/* MMC */
-	at91_add_device_mmc(0, &csb337_mmc_data);
+	at91_add_device_mci(0, &csb337_mci0_data);
 	/* NOR flash */
 	platform_device_register(&csb_flash);
 	/* LEDs */
diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c
index d1e1f3f..0cfac16 100644
--- a/arch/arm/mach-at91/board-eb9200.c
+++ b/arch/arm/mach-at91/board-eb9200.c
@@ -70,12 +70,12 @@ static struct at91_cf_data __initdata eb9200_cf_data = {
 	.rst_pin	= AT91_PIN_PC5,
 };
 
-static struct at91_mmc_data __initdata eb9200_mmc_data = {
-	.slot_b		= 0,
-	.wire4		= 1,
-	.det_pin	= -EINVAL,
-	.wp_pin		= -EINVAL,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata eb9200_mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= -EINVAL,
+		.wp_pin		= -EINVAL,
+	},
 };
 
 static struct i2c_board_info __initdata eb9200_i2c_devices[] = {
@@ -113,7 +113,7 @@ static void __init eb9200_board_init(void)
 	at91_add_device_spi(NULL, 0);
 	/* MMC */
 	/* only supports 1 or 4 bit interface, not wired through to SPI */
-	at91_add_device_mmc(0, &eb9200_mmc_data);
+	at91_add_device_mci(0, &eb9200_mci0_data);
 }
 
 MACHINE_START(ATEB9200, "Embest ATEB9200")
diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c
index 9c24cb2..3d931ff 100644
--- a/arch/arm/mach-at91/board-ecbat91.c
+++ b/arch/arm/mach-at91/board-ecbat91.c
@@ -64,12 +64,12 @@ static struct at91_usbh_data __initdata ecb_at91usbh_data = {
 	.overcurrent_pin= {-EINVAL, -EINVAL},
 };
 
-static struct at91_mmc_data __initdata ecb_at91mmc_data = {
-	.slot_b		= 0,
-	.wire4		= 1,
-	.det_pin	= -EINVAL,
-	.wp_pin		= -EINVAL,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata ecbat91_mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= -EINVAL,
+		.wp_pin		= -EINVAL,
+	},
 };
 
 
@@ -138,11 +138,20 @@ static struct spi_board_info __initdata ecb_at91spi_devices[] = {
 	},
 };
 
+/*
+ * LEDs
+ */
+static struct gpio_led ecb_leds[] = {
+	{	/* D1 */
+		.name			= "led1",
+		.gpio			= AT91_PIN_PC7,
+		.active_low		= 1,
+		.default_trigger	= "heartbeat",
+	}
+};
+
 static void __init ecb_at91board_init(void)
 {
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	at91_register_uart(0, 0, 0);
@@ -161,10 +170,13 @@ static void __init ecb_at91board_init(void)
 	at91_add_device_i2c(NULL, 0);
 
 	/* MMC */
-	at91_add_device_mmc(0, &ecb_at91mmc_data);
+	at91_add_device_mci(0, &ecbat91_mci0_data);
 
 	/* SPI */
 	at91_add_device_spi(ecb_at91spi_devices, ARRAY_SIZE(ecb_at91spi_devices));
+
+	/* LEDs */
+	at91_gpio_leds(ecb_leds, ARRAY_SIZE(ecb_leds));
 }
 
 MACHINE_START(ECBAT91, "emQbit's ECB_AT91")
diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c
index 82bdfde..d93658a 100644
--- a/arch/arm/mach-at91/board-eco920.c
+++ b/arch/arm/mach-at91/board-eco920.c
@@ -56,12 +56,12 @@ static struct at91_udc_data __initdata eco920_udc_data = {
 	.pullup_pin	= AT91_PIN_PB13,
 };
 
-static struct at91_mmc_data __initdata eco920_mmc_data = {
-	.slot_b		= 0,
-	.wire4		= 0,
-	.det_pin	= -EINVAL,
-	.wp_pin		= -EINVAL,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata eco920_mci0_data = {
+	.slot[0] = {
+		.bus_width	= 1,
+		.detect_pin	= -EINVAL,
+		.wp_pin		= -EINVAL,
+	},
 };
 
 static struct physmap_flash_data eco920_flash_data = {
@@ -93,10 +93,26 @@ static struct spi_board_info eco920_spi_devices[] = {
 	},
 };
 
+/*
+ * LEDs
+ */
+static struct gpio_led eco920_leds[] = {
+	{       /* D1 */
+		.name                   = "led1",
+		.gpio                   = AT91_PIN_PB0,
+		.active_low             = 1,
+		.default_trigger        = "heartbeat",
+	},
+	{       /* D2 */
+		.name                   = "led2",
+		.gpio                   = AT91_PIN_PB1,
+		.active_low             = 1,
+		.default_trigger        = "timer",
+	}
+};
+
 static void __init eco920_board_init(void)
 {
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
 	/* DBGU on ttyS0. (Rx & Tx only */
 	at91_register_uart(0, 0, 0);
 	at91_add_device_serial();
@@ -104,7 +120,7 @@ static void __init eco920_board_init(void)
 	at91_add_device_usbh(&eco920_usbh_data);
 	at91_add_device_udc(&eco920_udc_data);
 
-	at91_add_device_mmc(0, &eco920_mmc_data);
+	at91_add_device_mci(0, &eco920_mci0_data);
 	platform_device_register(&eco920_flash);
 
 	at91_ramc_write(0, AT91_SMC_CSR(7),	AT91_SMC_RWHOLD_(1)
@@ -127,6 +143,8 @@ static void __init eco920_board_init(void)
 	);
 
 	at91_add_device_spi(eco920_spi_devices, ARRAY_SIZE(eco920_spi_devices));
+	/* LEDs */
+	at91_gpio_leds(eco920_leds, ARRAY_SIZE(eco920_leds));
 }
 
 MACHINE_START(ECO920, "eco920")
diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c
index 6cc83a8..fa98aba 100644
--- a/arch/arm/mach-at91/board-flexibity.c
+++ b/arch/arm/mach-at91/board-flexibity.c
@@ -75,12 +75,12 @@ static struct spi_board_info flexibity_spi_devices[] = {
 };
 
 /* MCI (SD/MMC) */
-static struct at91_mmc_data __initdata flexibity_mmc_data = {
-	.slot_b		= 0,
-	.wire4		= 1,
-	.det_pin	= AT91_PIN_PC9,
-	.wp_pin		= AT91_PIN_PC4,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata flexibity_mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PC9,
+		.wp_pin		= AT91_PIN_PC4,
+	},
 };
 
 /* LEDs */
@@ -152,7 +152,7 @@ static void __init flexibity_board_init(void)
 	at91_add_device_spi(flexibity_spi_devices,
 		ARRAY_SIZE(flexibity_spi_devices));
 	/* MMC */
-	at91_add_device_mmc(0, &flexibity_mmc_data);
+	at91_add_device_mci(0, &flexibity_mci0_data);
 	/* LEDs */
 	at91_gpio_leds(flexibity_leds, ARRAY_SIZE(flexibity_leds));
 }
diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c
index 69ab124..6e47071 100644
--- a/arch/arm/mach-at91/board-foxg20.c
+++ b/arch/arm/mach-at91/board-foxg20.c
@@ -86,7 +86,7 @@ static struct at91_udc_data __initdata foxg20_udc_data = {
  * SPI devices.
  */
 static struct spi_board_info foxg20_spi_devices[] = {
-#if !defined(CONFIG_MMC_AT91)
+#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
 	{
 		.modalias	= "mtd_dataflash",
 		.chip_select	= 1,
@@ -109,12 +109,12 @@ static struct macb_platform_data __initdata foxg20_macb_data = {
  * MCI (SD/MMC)
  * det_pin, wp_pin and vcc_pin are not connected
  */
-static struct at91_mmc_data __initdata foxg20_mmc_data = {
-	.slot_b		= 1,
-	.wire4		= 1,
-	.det_pin	= -EINVAL,
-	.wp_pin		= -EINVAL,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata foxg20_mci0_data = {
+	.slot[1] = {
+		.bus_width	= 4,
+		.detect_pin	= -EINVAL,
+		.wp_pin		= -EINVAL,
+	},
 };
 
 
@@ -247,7 +247,7 @@ static void __init foxg20_board_init(void)
 	/* Ethernet */
 	at91_add_device_eth(&foxg20_macb_data);
 	/* MMC */
-	at91_add_device_mmc(0, &foxg20_mmc_data);
+	at91_add_device_mci(0, &foxg20_mci0_data);
 	/* I2C */
 	at91_add_device_i2c(foxg20_i2c_devices, ARRAY_SIZE(foxg20_i2c_devices));
 	/* LEDs */
diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c
index 64c1dbf..86050da 100644
--- a/arch/arm/mach-at91/board-kafa.c
+++ b/arch/arm/mach-at91/board-kafa.c
@@ -66,11 +66,20 @@ static struct at91_udc_data __initdata kafa_udc_data = {
 	.pullup_pin	= AT91_PIN_PB7,
 };
 
+/*
+ * LEDs
+ */
+static struct gpio_led kafa_leds[] = {
+	{	/* D1 */
+		.name			= "led1",
+		.gpio			= AT91_PIN_PB4,
+		.active_low		= 1,
+		.default_trigger	= "heartbeat",
+	},
+};
+
 static void __init kafa_board_init(void)
 {
-	/* Set up the LEDs */
-	at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	at91_register_uart(0, 0, 0);
@@ -88,6 +97,8 @@ static void __init kafa_board_init(void)
 	at91_add_device_i2c(NULL, 0);
 	/* SPI */
 	at91_add_device_spi(NULL, 0);
+	/* LEDs */
+	at91_gpio_leds(kafa_leds, ARRAY_SIZE(kafa_leds));
 }
 
 MACHINE_START(KAFA, "Sperry-Sun KAFA")
diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
index 5d96cb8..abe9fed 100644
--- a/arch/arm/mach-at91/board-kb9202.c
+++ b/arch/arm/mach-at91/board-kb9202.c
@@ -69,12 +69,12 @@ static struct at91_udc_data __initdata kb9202_udc_data = {
 	.pullup_pin	= AT91_PIN_PB22,
 };
 
-static struct at91_mmc_data __initdata kb9202_mmc_data = {
-	.det_pin	= AT91_PIN_PB2,
-	.slot_b		= 0,
-	.wire4		= 1,
-	.wp_pin		= -EINVAL,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata kb9202_mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PB2,
+		.wp_pin		= -EINVAL,
+	},
 };
 
 static struct mtd_partition __initdata kb9202_nand_partition[] = {
@@ -96,11 +96,26 @@ static struct atmel_nand_data __initdata kb9202_nand_data = {
 	.num_parts	= ARRAY_SIZE(kb9202_nand_partition),
 };
 
+/*
+ * LEDs
+ */
+static struct gpio_led kb9202_leds[] = {
+	{	/* D1 */
+		.name			= "led1",
+		.gpio			= AT91_PIN_PC19,
+		.active_low		= 1,
+		.default_trigger	= "heartbeat",
+	},
+	{	/* D2 */
+		.name			= "led2",
+		.gpio			= AT91_PIN_PC18,
+		.active_low		= 1,
+		.default_trigger	= "timer",
+	}
+};
+
 static void __init kb9202_board_init(void)
 {
-	/* Set up the LEDs */
-	at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	at91_register_uart(0, 0, 0);
@@ -121,13 +136,15 @@ static void __init kb9202_board_init(void)
 	/* USB Device */
 	at91_add_device_udc(&kb9202_udc_data);
 	/* MMC */
-	at91_add_device_mmc(0, &kb9202_mmc_data);
+	at91_add_device_mci(0, &kb9202_mci0_data);
 	/* I2C */
 	at91_add_device_i2c(NULL, 0);
 	/* SPI */
 	at91_add_device_spi(NULL, 0);
 	/* NAND */
 	at91_add_device_nand(&kb9202_nand_data);
+	/* LEDs */
+	at91_gpio_leds(kb9202_leds, ARRAY_SIZE(kb9202_leds));
 }
 
 MACHINE_START(KB9200, "KB920x")
diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
index 18103c5d..9cda3fd 100644
--- a/arch/arm/mach-at91/board-neocore926.c
+++ b/arch/arm/mach-at91/board-neocore926.c
@@ -138,11 +138,12 @@ static struct spi_board_info neocore926_spi_devices[] = {
 /*
  * MCI (SD/MMC)
  */
-static struct at91_mmc_data __initdata neocore926_mmc_data = {
-	.wire4		= 1,
-	.det_pin	= AT91_PIN_PE18,
-	.wp_pin		= AT91_PIN_PE19,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata neocore926_mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PE18,
+		.wp_pin		= AT91_PIN_PE19,
+	},
 };
 
 
@@ -354,7 +355,7 @@ static void __init neocore926_board_init(void)
 	neocore926_add_device_ts();
 
 	/* MMC */
-	at91_add_device_mmc(1, &neocore926_mmc_data);
+	at91_add_device_mci(0, &neocore926_mci0_data);
 
 	/* Ethernet */
 	at91_add_device_eth(&neocore926_macb_data);
diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
index 1270655..f83e1de 100644
--- a/arch/arm/mach-at91/board-picotux200.c
+++ b/arch/arm/mach-at91/board-picotux200.c
@@ -62,12 +62,12 @@ static struct at91_usbh_data __initdata picotux200_usbh_data = {
 	.overcurrent_pin= {-EINVAL, -EINVAL},
 };
 
-static struct at91_mmc_data __initdata picotux200_mmc_data = {
-	.det_pin	= AT91_PIN_PB27,
-	.slot_b		= 0,
-	.wire4		= 1,
-	.wp_pin		= AT91_PIN_PA17,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata picotux200_mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PB27,
+		.wp_pin		= AT91_PIN_PA17,
+	},
 };
 
 #define PICOTUX200_FLASH_BASE	AT91_CHIPSELECT_0
@@ -112,7 +112,7 @@ static void __init picotux200_board_init(void)
 	at91_add_device_i2c(NULL, 0);
 	/* MMC */
 	at91_set_gpio_output(AT91_PIN_PB22, 1);	/* this MMC card slot can optionally use SPI signaling (CS3). */
-	at91_add_device_mmc(0, &picotux200_mmc_data);
+	at91_add_device_mci(0, &picotux200_mci0_data);
 	/* NOR Flash */
 	platform_device_register(&picotux200_flash);
 }
diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c
index bf351e2..799f214 100644
--- a/arch/arm/mach-at91/board-qil-a9260.c
+++ b/arch/arm/mach-at91/board-qil-a9260.c
@@ -156,12 +156,12 @@ static void __init ek_add_device_nand(void)
 /*
  * MCI (SD/MMC)
  */
-static struct at91_mmc_data __initdata ek_mmc_data = {
-	.slot_b		= 0,
-	.wire4		= 1,
-	.det_pin	= -EINVAL,
-	.wp_pin		= -EINVAL,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata ek_mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= -EINVAL,
+		.wp_pin		= -EINVAL,
+	},
 };
 
 /*
@@ -245,7 +245,7 @@ static void __init ek_board_init(void)
 	/* Ethernet */
 	at91_add_device_eth(&ek_macb_data);
 	/* MMC */
-	at91_add_device_mmc(0, &ek_mmc_data);
+	at91_add_device_mci(0, &ek_mci0_data);
 	/* Push Buttons */
 	ek_add_device_buttons();
 	/* LEDs */
diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c
index cc2bf97..66338e7 100644
--- a/arch/arm/mach-at91/board-rm9200dk.c
+++ b/arch/arm/mach-at91/board-rm9200dk.c
@@ -77,12 +77,12 @@ static struct at91_cf_data __initdata dk_cf_data = {
 };
 
 #ifndef CONFIG_MTD_AT91_DATAFLASH_CARD
-static struct at91_mmc_data __initdata dk_mmc_data = {
-	.slot_b		= 0,
-	.wire4		= 1,
-	.det_pin	= -EINVAL,
-	.wp_pin		= -EINVAL,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata dk_mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= -EINVAL,
+		.wp_pin		= -EINVAL,
+	},
 };
 #endif
 
@@ -177,9 +177,6 @@ static struct gpio_led dk_leds[] = {
 
 static void __init dk_board_init(void)
 {
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	at91_register_uart(0, 0, 0);
@@ -208,7 +205,7 @@ static void __init dk_board_init(void)
 #else
 	/* MMC */
 	at91_set_gpio_output(AT91_PIN_PB7, 1);	/* this MMC card slot can optionally use SPI signaling (CS3). */
-	at91_add_device_mmc(0, &dk_mmc_data);
+	at91_add_device_mci(0, &dk_mci0_data);
 #endif
 	/* NAND */
 	at91_add_device_nand(&dk_nand_data);
diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c
index 62e19e6..5d1b572 100644
--- a/arch/arm/mach-at91/board-rm9200ek.c
+++ b/arch/arm/mach-at91/board-rm9200ek.c
@@ -70,12 +70,12 @@ static struct at91_udc_data __initdata ek_udc_data = {
 };
 
 #ifndef CONFIG_MTD_AT91_DATAFLASH_CARD
-static struct at91_mmc_data __initdata ek_mmc_data = {
-	.det_pin	= AT91_PIN_PB27,
-	.slot_b		= 0,
-	.wire4		= 1,
-	.wp_pin		= AT91_PIN_PA17,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata ek_mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PB27,
+		.wp_pin		= AT91_PIN_PA17,
+	}
 };
 #endif
 
@@ -148,9 +148,6 @@ static struct gpio_led ek_leds[] = {
 
 static void __init ek_board_init(void)
 {
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	at91_register_uart(0, 0, 0);
@@ -177,7 +174,7 @@ static void __init ek_board_init(void)
 #else
 	/* MMC */
 	at91_set_gpio_output(AT91_PIN_PB22, 1);	/* this MMC card slot can optionally use SPI signaling (CS3). */
-	at91_add_device_mmc(0, &ek_mmc_data);
+	at91_add_device_mci(0, &ek_mci0_data);
 #endif
 	/* NOR Flash */
 	platform_device_register(&ek_flash);
diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c
index c3b43ae..a0ecf04 100644
--- a/arch/arm/mach-at91/board-rsi-ews.c
+++ b/arch/arm/mach-at91/board-rsi-ews.c
@@ -58,11 +58,12 @@ static struct at91_usbh_data rsi_ews_usbh_data __initdata = {
 /*
  * SD/MC
  */
-static struct at91_mmc_data rsi_ews_mmc_data __initdata = {
-	.slot_b		= 0,
-	.wire4		= 1,
-	.det_pin	= AT91_PIN_PB27,
-	.wp_pin		= AT91_PIN_PB29,
+static struct mci_platform_data __initdata rsi_ews_mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PB27,
+		.wp_pin		= AT91_PIN_PB29,
+	},
 };
 
 /*
@@ -185,9 +186,6 @@ static struct platform_device rsiews_nor_flash = {
  */
 static void __init rsi_ews_board_init(void)
 {
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PB6, AT91_PIN_PB9);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	/* This one is for debugging */
@@ -215,7 +213,7 @@ static void __init rsi_ews_board_init(void)
 	at91_add_device_spi(rsi_ews_spi_devices,
 			ARRAY_SIZE(rsi_ews_spi_devices));
 	/* MMC */
-	at91_add_device_mmc(0, &rsi_ews_mmc_data);
+	at91_add_device_mci(0, &rsi_ews_mci0_data);
 	/* NOR Flash */
 	platform_device_register(&rsiews_nor_flash);
 	/* LEDs */
diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
index 7bf6da7..c5f01ac 100644
--- a/arch/arm/mach-at91/board-sam9-l9260.c
+++ b/arch/arm/mach-at91/board-sam9-l9260.c
@@ -73,7 +73,7 @@ static struct at91_udc_data __initdata ek_udc_data = {
  * SPI devices.
  */
 static struct spi_board_info ek_spi_devices[] = {
-#if !defined(CONFIG_MMC_AT91)
+#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
 	{	/* DataFlash chip */
 		.modalias	= "mtd_dataflash",
 		.chip_select	= 1,
@@ -158,19 +158,34 @@ static void __init ek_add_device_nand(void)
 /*
  * MCI (SD/MMC)
  */
-static struct at91_mmc_data __initdata ek_mmc_data = {
-	.slot_b		= 1,
-	.wire4		= 1,
-	.det_pin	= AT91_PIN_PC8,
-	.wp_pin		= AT91_PIN_PC4,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata ek_mci0_data = {
+	.slot[1] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PC8,
+		.wp_pin		= AT91_PIN_PC4,
+	},
+};
+
+/*
+ * LEDs
+ */
+static struct gpio_led ek_leds[] = {
+	{	/* D1 */
+		.name			= "led1",
+		.gpio			= AT91_PIN_PA9,
+		.active_low		= 1,
+		.default_trigger	= "heartbeat",
+	},
+	{	/* D2 */
+		.name			= "led2",
+		.gpio			= AT91_PIN_PA6,
+		.active_low		= 1,
+		.default_trigger	= "timer",
+	}
 };
 
 static void __init ek_board_init(void)
 {
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	at91_register_uart(0, 0, 0);
@@ -194,9 +209,11 @@ static void __init ek_board_init(void)
 	/* Ethernet */
 	at91_add_device_eth(&ek_macb_data);
 	/* MMC */
-	at91_add_device_mmc(0, &ek_mmc_data);
+	at91_add_device_mci(0, &ek_mci0_data);
 	/* I2C */
 	at91_add_device_i2c(NULL, 0);
+	/* LEDs */
+	at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
 }
 
 MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
index 889c1bf..8cd6e67 100644
--- a/arch/arm/mach-at91/board-sam9260ek.c
+++ b/arch/arm/mach-at91/board-sam9260ek.c
@@ -108,7 +108,7 @@ static void __init at73c213_set_clk(struct at73c213_board_info *info) {}
  * SPI devices.
  */
 static struct spi_board_info ek_spi_devices[] = {
-#if !defined(CONFIG_MMC_AT91)
+#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
 	{	/* DataFlash chip */
 		.modalias	= "mtd_dataflash",
 		.chip_select	= 1,
@@ -211,12 +211,12 @@ static void __init ek_add_device_nand(void)
 /*
  * MCI (SD/MMC)
  */
-static struct at91_mmc_data __initdata ek_mmc_data = {
-	.slot_b		= 1,
-	.wire4		= 1,
-	.det_pin	= -EINVAL,
-	.wp_pin		= -EINVAL,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata ek_mci0_data = {
+	.slot[1] = {
+		.bus_width	= 4,
+		.detect_pin	= -EINVAL,
+		.wp_pin		= -EINVAL,
+	},
 };
 
 
@@ -329,7 +329,7 @@ static void __init ek_board_init(void)
 	/* Ethernet */
 	at91_add_device_eth(&ek_macb_data);
 	/* MMC */
-	at91_add_device_mmc(0, &ek_mmc_data);
+	at91_add_device_mci(0, &ek_mci0_data);
 	/* I2C */
 	at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
 	/* SSC (to AT73C213) */
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index 2269be5..27b3af1 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -340,11 +340,12 @@ static struct spi_board_info ek_spi_devices[] = {
  * MCI (SD/MMC)
  * det_pin, wp_pin and vcc_pin are not connected
  */
-static struct at91_mmc_data __initdata ek_mmc_data = {
-	.wire4		= 1,
-	.det_pin	= -EINVAL,
-	.wp_pin		= -EINVAL,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= -EINVAL,
+		.wp_pin		= -EINVAL,
+	},
 };
 
 #endif /* CONFIG_SPI_ATMEL_* */
@@ -569,9 +570,6 @@ static struct gpio_led ek_leds[] = {
 
 static void __init ek_board_init(void)
 {
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	at91_register_uart(0, 0, 0);
@@ -598,7 +596,7 @@ static void __init ek_board_init(void)
 	at91_add_device_ssc(AT91SAM9261_ID_SSC1, ATMEL_SSC_TX);
 #else
 	/* MMC */
-	at91_add_device_mmc(0, &ek_mmc_data);
+	at91_add_device_mci(0, &mci0_data);
 #endif
 	/* LCD Controller */
 	at91_add_device_lcdc(&ek_lcdc_data);
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
index 82adf58..073e174 100644
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ b/arch/arm/mach-at91/board-sam9263ek.c
@@ -141,11 +141,12 @@ static struct spi_board_info ek_spi_devices[] = {
 /*
  * MCI (SD/MMC)
  */
-static struct at91_mmc_data __initdata ek_mmc_data = {
-	.wire4		= 1,
-	.det_pin	= AT91_PIN_PE18,
-	.wp_pin		= AT91_PIN_PE19,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata mci1_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PE18,
+		.wp_pin		= AT91_PIN_PE19,
+	},
 };
 
 
@@ -420,7 +421,7 @@ static void __init ek_board_init(void)
 	/* Touchscreen */
 	ek_add_device_ts();
 	/* MMC */
-	at91_add_device_mmc(1, &ek_mmc_data);
+	at91_add_device_mci(1, &mci1_data);
 	/* Ethernet */
 	at91_add_device_eth(&ek_macb_data);
 	/* NAND */
diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
index 4ea4ee0..3ab2b86 100644
--- a/arch/arm/mach-at91/board-sam9g20ek.c
+++ b/arch/arm/mach-at91/board-sam9g20ek.c
@@ -92,7 +92,7 @@ static struct at91_udc_data __initdata ek_udc_data = {
  * SPI devices.
  */
 static struct spi_board_info ek_spi_devices[] = {
-#if !(defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_AT91))
+#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
 	{	/* DataFlash chip */
 		.modalias	= "mtd_dataflash",
 		.chip_select	= 1,
@@ -199,7 +199,6 @@ static void __init ek_add_device_nand(void)
  * MCI (SD/MMC)
  * wp_pin and vcc_pin are not connected
  */
-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
 static struct mci_platform_data __initdata ek_mmc_data = {
 	.slot[1] = {
 		.bus_width	= 4,
@@ -208,28 +207,15 @@ static struct mci_platform_data __initdata ek_mmc_data = {
 	},
 
 };
-#else
-static struct at91_mmc_data __initdata ek_mmc_data = {
-	.slot_b		= 1,	/* Only one slot so use slot B */
-	.wire4		= 1,
-	.det_pin	= AT91_PIN_PC9,
-	.wp_pin		= -EINVAL,
-	.vcc_pin	= -EINVAL,
-};
-#endif
 
 static void __init ek_add_device_mmc(void)
 {
-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
 	if (ek_have_2mmc()) {
 		ek_mmc_data.slot[0].bus_width = 4;
 		ek_mmc_data.slot[0].detect_pin = AT91_PIN_PC2;
 		ek_mmc_data.slot[0].wp_pin = -1;
 	}
 	at91_add_device_mci(0, &ek_mmc_data);
-#else
-	at91_add_device_mmc(0, &ek_mmc_data);
-#endif
 }
 
 /*
diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
index e7dc3ea..fb89ea9 100644
--- a/arch/arm/mach-at91/board-sam9rlek.c
+++ b/arch/arm/mach-at91/board-sam9rlek.c
@@ -56,11 +56,12 @@ static struct usba_platform_data __initdata ek_usba_udc_data = {
 /*
  * MCI (SD/MMC)
  */
-static struct at91_mmc_data __initdata ek_mmc_data = {
-	.wire4		= 1,
-	.det_pin	= AT91_PIN_PA15,
-	.wp_pin		= -EINVAL,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PA15,
+		.wp_pin		= -EINVAL,
+	},
 };
 
 
@@ -303,7 +304,7 @@ static void __init ek_board_init(void)
 	/* SPI */
 	at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
 	/* MMC */
-	at91_add_device_mmc(0, &ek_mmc_data);
+	at91_add_device_mci(0, &mci0_data);
 	/* LCD Controller */
 	at91_add_device_lcdc(&ek_lcdc_data);
 	/* AC97 */
diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c
index 29eae16..c3fb31d 100644
--- a/arch/arm/mach-at91/board-stamp9g20.c
+++ b/arch/arm/mach-at91/board-stamp9g20.c
@@ -83,7 +83,6 @@ static void __init add_device_nand(void)
  * MCI (SD/MMC)
  * det_pin, wp_pin and vcc_pin are not connected
  */
-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
 static struct mci_platform_data __initdata mmc_data = {
 	.slot[0] = {
 		.bus_width	= 4,
@@ -91,15 +90,6 @@ static struct mci_platform_data __initdata mmc_data = {
 		.wp_pin		= -1,
 	},
 };
-#else
-static struct at91_mmc_data __initdata mmc_data = {
-	.slot_b		= 0,
-	.wire4		= 1,
-	.det_pin	= -EINVAL,
-	.wp_pin		= -EINVAL,
-	.vcc_pin	= -EINVAL,
-};
-#endif
 
 
 /*
@@ -223,11 +213,7 @@ void __init stamp9g20_board_init(void)
 	/* NAND */
 	add_device_nand();
 	/* MMC */
-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
 	at91_add_device_mci(0, &mmc_data);
-#else
-	at91_add_device_mmc(0, &mmc_data);
-#endif
 	/* W1 */
 	add_w1();
 }
diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c
index c1476b9..6ea069b 100644
--- a/arch/arm/mach-at91/board-usb-a926x.c
+++ b/arch/arm/mach-at91/board-usb-a926x.c
@@ -109,14 +109,12 @@ static struct mmc_spi_platform_data at91_mmc_spi_pdata = {
  * SPI devices.
  */
 static struct spi_board_info usb_a9263_spi_devices[] = {
-#if !defined(CONFIG_MMC_AT91)
 	{	/* DataFlash chip */
 		.modalias	= "mtd_dataflash",
 		.chip_select	= 0,
 		.max_speed_hz	= 15 * 1000 * 1000,
 		.bus_num	= 0,
 	}
-#endif
 };
 
 static struct spi_board_info usb_a9g20_spi_devices[] = {
diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
index 516d340..f162fdf 100644
--- a/arch/arm/mach-at91/board-yl-9200.c
+++ b/arch/arm/mach-at91/board-yl-9200.c
@@ -119,11 +119,12 @@ static struct at91_udc_data __initdata yl9200_udc_data = {
 /*
  * MMC
  */
-static struct at91_mmc_data __initdata yl9200_mmc_data = {
-	.det_pin	= AT91_PIN_PB9,
-	.wire4		= 1,
-	.wp_pin		= -EINVAL,
-	.vcc_pin	= -EINVAL,
+static struct mci_platform_data __initdata yl9200_mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PB9,
+		.wp_pin		= -EINVAL,
+	},
 };
 
 /*
@@ -541,9 +542,6 @@ void __init yl9200_add_device_video(void) {}
 
 static void __init yl9200_board_init(void)
 {
-	/* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */
-	at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17);
-
 	/* Serial */
 	/* DBGU on ttyS0. (Rx & Tx only) */
 	at91_register_uart(0, 0, 0);
@@ -568,7 +566,7 @@ static void __init yl9200_board_init(void)
 	/* I2C */
 	at91_add_device_i2c(yl9200_i2c_devices, ARRAY_SIZE(yl9200_i2c_devices));
 	/* MMC */
-	at91_add_device_mmc(0, &yl9200_mmc_data);
+	at91_add_device_mci(0, &yl9200_mci0_data);
 	/* NAND */
 	at91_add_device_nand(&yl9200_nand_data);
 	/* NOR Flash */
diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
index 369afc2..c55a436 100644
--- a/arch/arm/mach-at91/include/mach/board.h
+++ b/arch/arm/mach-at91/include/mach/board.h
@@ -187,7 +187,6 @@ struct at91_can_data {
 extern void __init at91_add_device_can(struct at91_can_data *data);
 
  /* LEDs */
-extern void __init at91_init_leds(u8 cpu_led, u8 timer_led);
 extern void __init at91_gpio_leds(struct gpio_led *leds, int nr);
 extern void __init at91_pwm_leds(struct gpio_led *leds, int nr);
 
diff --git a/arch/arm/mach-at91/leds.c b/arch/arm/mach-at91/leds.c
index 8dfafe7..1b1e62b 100644
--- a/arch/arm/mach-at91/leds.c
+++ b/arch/arm/mach-at91/leds.c
@@ -90,108 +90,3 @@ void __init at91_pwm_leds(struct gpio_led *leds, int nr)
 #else
 void __init at91_pwm_leds(struct gpio_led *leds, int nr){}
 #endif
-
-
-/* ------------------------------------------------------------------------- */
-
-#if defined(CONFIG_LEDS)
-
-#include <asm/leds.h>
-
-/*
- * Old ARM-specific LED framework; not fully functional when generic time is
- * in use.
- */
-
-static u8 at91_leds_cpu;
-static u8 at91_leds_timer;
-
-static inline void at91_led_on(unsigned int led)
-{
-	at91_set_gpio_value(led, 0);
-}
-
-static inline void at91_led_off(unsigned int led)
-{
-	at91_set_gpio_value(led, 1);
-}
-
-static inline void at91_led_toggle(unsigned int led)
-{
-	unsigned long is_off = at91_get_gpio_value(led);
-	if (is_off)
-		at91_led_on(led);
-	else
-		at91_led_off(led);
-}
-
-
-/*
- * Handle LED events.
- */
-static void at91_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch(evt) {
-	case led_start:		/* System startup */
-		at91_led_on(at91_leds_cpu);
-		break;
-
-	case led_stop:		/* System stop / suspend */
-		at91_led_off(at91_leds_cpu);
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:		/* Every 50 timer ticks */
-		at91_led_toggle(at91_leds_timer);
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:	/* Entering idle state */
-		at91_led_off(at91_leds_cpu);
-		break;
-
-	case led_idle_end:	/* Exit idle state */
-		at91_led_on(at91_leds_cpu);
-		break;
-#endif
-
-	default:
-		break;
-	}
-
-	local_irq_restore(flags);
-}
-
-
-static int __init leds_init(void)
-{
-	if (!at91_leds_timer || !at91_leds_cpu)
-		return -ENODEV;
-
-	leds_event = at91_leds_event;
-
-	leds_event(led_start);
-	return 0;
-}
-
-__initcall(leds_init);
-
-
-void __init at91_init_leds(u8 cpu_led, u8 timer_led)
-{
-	/* Enable GPIO to access the LEDs */
-	at91_set_gpio_output(cpu_led, 1);
-	at91_set_gpio_output(timer_led, 1);
-
-	at91_leds_cpu	= cpu_led;
-	at91_leds_timer	= timer_led;
-}
-
-#else
-void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
-#endif
diff --git a/arch/arm/mach-bcmring/arch.c b/arch/arm/mach-bcmring/arch.c
index 45c97b1..c18a504 100644
--- a/arch/arm/mach-bcmring/arch.c
+++ b/arch/arm/mach-bcmring/arch.c
@@ -29,7 +29,6 @@
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/mach/time.h>
-#include <asm/pmu.h>
 
 #include <asm/mach/arch.h>
 #include <mach/dma.h>
@@ -38,7 +37,7 @@
 #include <mach/csp/chipcHw_def.h>
 #include <mach/csp/chipcHw_inline.h>
 
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 
 #include "core.h"
 
@@ -116,7 +115,7 @@ static struct resource pmu_resource = {
 
 static struct platform_device pmu_device = {
 	.name		= "arm-pmu",
-	.id		= ARM_PMU_DEVICE_CPU,
+	.id		= -1,
 	.resource	= &pmu_resource,
 	.num_resources	= 1,
 };
diff --git a/arch/arm/mach-bcmring/core.c b/arch/arm/mach-bcmring/core.c
index adbfb19..4b50228 100644
--- a/arch/arm/mach-bcmring/core.c
+++ b/arch/arm/mach-bcmring/core.c
@@ -43,11 +43,10 @@
 #include <asm/mach/time.h>
 #include <asm/mach/map.h>
 
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 
 #include "clock.h"
 
-#include <csp/secHw.h>
 #include <mach/csp/secHw_def.h>
 #include <mach/csp/chipcHw_inline.h>
 #include <mach/csp/tmrHw_reg.h>
diff --git a/arch/arm/mach-bcmring/csp/chipc/chipcHw.c b/arch/arm/mach-bcmring/csp/chipc/chipcHw.c
index 96273ff..5050833 100644
--- a/arch/arm/mach-bcmring/csp/chipc/chipcHw.c
+++ b/arch/arm/mach-bcmring/csp/chipc/chipcHw.c
@@ -26,15 +26,15 @@
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <csp/errno.h>
-#include <csp/stdint.h>
-#include <csp/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/export.h>
 
 #include <mach/csp/chipcHw_def.h>
 #include <mach/csp/chipcHw_inline.h>
 
-#include <csp/reg.h>
-#include <csp/delay.h>
+#include <mach/csp/reg.h>
+#include <linux/delay.h>
 
 /* ---- Private Constants and Types --------------------------------------- */
 
@@ -61,21 +61,21 @@ static int chipcHw_divide(int num, int denom)
 /****************************************************************************/
 chipcHw_freq chipcHw_getClockFrequency(chipcHw_CLOCK_e clock	/*  [ IN ] Configurable clock */
     ) {
-	volatile uint32_t *pPLLReg = (uint32_t *) 0x0;
-	volatile uint32_t *pClockCtrl = (uint32_t *) 0x0;
-	volatile uint32_t *pDependentClock = (uint32_t *) 0x0;
+	uint32_t __iomem *pPLLReg = NULL;
+	uint32_t __iomem *pClockCtrl = NULL;
+	uint32_t __iomem *pDependentClock = NULL;
 	uint32_t vcoFreqPll1Hz = 0;	/* Effective VCO frequency for PLL1 in Hz */
 	uint32_t vcoFreqPll2Hz = 0;	/* Effective VCO frequency for PLL2 in Hz */
 	uint32_t dependentClockType = 0;
 	uint32_t vcoHz = 0;
 
 	/* Get VCO frequencies */
-	if ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) != chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
+	if ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) != chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
 		uint64_t adjustFreq = 0;
 
 		vcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
 		    chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-		    ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+		    ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
 		     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
 
 		/* Adjusted frequency due to chipcHw_REG_PLL_DIVIDER_NDIV_f_SS */
@@ -86,13 +86,13 @@ chipcHw_freq chipcHw_getClockFrequency(chipcHw_CLOCK_e clock	/*  [ IN ] Configur
 	} else {
 		vcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
 		    chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-		    ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+		    ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
 		     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
 	}
 	vcoFreqPll2Hz =
 	    chipcHw_XTAL_FREQ_Hz *
 		 chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-	    ((pChipcHw->PLLPreDivider2 & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+	    ((readl(&pChipcHw->PLLPreDivider2) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
 	     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
 
 	switch (clock) {
@@ -187,51 +187,51 @@ chipcHw_freq chipcHw_getClockFrequency(chipcHw_CLOCK_e clock	/*  [ IN ] Configur
 
 	if (pPLLReg) {
 		/* Obtain PLL clock frequency */
-		if (*pPLLReg & chipcHw_REG_PLL_CLOCK_BYPASS_SELECT) {
+		if (readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_BYPASS_SELECT) {
 			/* Return crystal clock frequency when bypassed */
 			return chipcHw_XTAL_FREQ_Hz;
 		} else if (clock == chipcHw_CLOCK_DDR) {
 			/* DDR frequency is configured in PLLDivider register */
-			return chipcHw_divide (vcoHz, (((pChipcHw->PLLDivider & 0xFF000000) >> 24) ? ((pChipcHw->PLLDivider & 0xFF000000) >> 24) : 256));
+			return chipcHw_divide (vcoHz, (((readl(&pChipcHw->PLLDivider) & 0xFF000000) >> 24) ? ((readl(&pChipcHw->PLLDivider) & 0xFF000000) >> 24) : 256));
 		} else {
 			/* From chip revision number B0, LCD clock is internally divided by 2 */
 			if ((pPLLReg == &pChipcHw->LCDClock) && (chipcHw_getChipRevisionNumber() != chipcHw_REV_NUMBER_A0)) {
 				vcoHz >>= 1;
 			}
 			/* Obtain PLL clock frequency using VCO dividers */
-			return chipcHw_divide(vcoHz, ((*pPLLReg & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ? (*pPLLReg & chipcHw_REG_PLL_CLOCK_MDIV_MASK) : 256));
+			return chipcHw_divide(vcoHz, ((readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ?  (readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) : 256));
 		}
 	} else if (pClockCtrl) {
 		/* Obtain divider clock frequency */
 		uint32_t div;
 		uint32_t freq = 0;
 
-		if (*pClockCtrl & chipcHw_REG_DIV_CLOCK_BYPASS_SELECT) {
+		if (readl(pClockCtrl) & chipcHw_REG_DIV_CLOCK_BYPASS_SELECT) {
 			/* Return crystal clock frequency when bypassed */
 			return chipcHw_XTAL_FREQ_Hz;
 		} else if (pDependentClock) {
 			/* Identify the dependent clock frequency */
 			switch (dependentClockType) {
 			case PLL_CLOCK:
-				if (*pDependentClock & chipcHw_REG_PLL_CLOCK_BYPASS_SELECT) {
+				if (readl(pDependentClock) & chipcHw_REG_PLL_CLOCK_BYPASS_SELECT) {
 					/* Use crystal clock frequency when dependent PLL clock is bypassed */
 					freq = chipcHw_XTAL_FREQ_Hz;
 				} else {
 					/* Obtain PLL clock frequency using VCO dividers */
-					div = *pDependentClock & chipcHw_REG_PLL_CLOCK_MDIV_MASK;
+					div = readl(pDependentClock) & chipcHw_REG_PLL_CLOCK_MDIV_MASK;
 					freq = div ? chipcHw_divide(vcoHz, div) : 0;
 				}
 				break;
 			case NON_PLL_CLOCK:
-				if (pDependentClock == (uint32_t *) &pChipcHw->ACLKClock) {
+				if (pDependentClock == &pChipcHw->ACLKClock) {
 					freq = chipcHw_getClockFrequency (chipcHw_CLOCK_BUS);
 				} else {
-					if (*pDependentClock & chipcHw_REG_DIV_CLOCK_BYPASS_SELECT) {
+					if (readl(pDependentClock) & chipcHw_REG_DIV_CLOCK_BYPASS_SELECT) {
 						/* Use crystal clock frequency when dependent divider clock is bypassed */
 						freq = chipcHw_XTAL_FREQ_Hz;
 					} else {
 						/* Obtain divider clock frequency using XTAL dividers */
-						div = *pDependentClock & chipcHw_REG_DIV_CLOCK_DIV_MASK;
+						div = readl(pDependentClock) & chipcHw_REG_DIV_CLOCK_DIV_MASK;
 						freq = chipcHw_divide (chipcHw_XTAL_FREQ_Hz, (div ? div : 256));
 					}
 				}
@@ -242,7 +242,7 @@ chipcHw_freq chipcHw_getClockFrequency(chipcHw_CLOCK_e clock	/*  [ IN ] Configur
 			freq = chipcHw_XTAL_FREQ_Hz;
 		}
 
-		div = *pClockCtrl & chipcHw_REG_DIV_CLOCK_DIV_MASK;
+		div = readl(pClockCtrl) & chipcHw_REG_DIV_CLOCK_DIV_MASK;
 		return chipcHw_divide(freq, (div ? div : 256));
 	}
 	return 0;
@@ -261,9 +261,9 @@ chipcHw_freq chipcHw_getClockFrequency(chipcHw_CLOCK_e clock	/*  [ IN ] Configur
 chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,	/*  [ IN ] Configurable clock */
 				       uint32_t freq	/*  [ IN ] Clock frequency in Hz */
     ) {
-	volatile uint32_t *pPLLReg = (uint32_t *) 0x0;
-	volatile uint32_t *pClockCtrl = (uint32_t *) 0x0;
-	volatile uint32_t *pDependentClock = (uint32_t *) 0x0;
+	uint32_t __iomem *pPLLReg = NULL;
+	uint32_t __iomem *pClockCtrl = NULL;
+	uint32_t __iomem *pDependentClock = NULL;
 	uint32_t vcoFreqPll1Hz = 0;	/* Effective VCO frequency for PLL1 in Hz */
 	uint32_t desVcoFreqPll1Hz = 0;	/* Desired VCO frequency for PLL1 in Hz */
 	uint32_t vcoFreqPll2Hz = 0;	/* Effective VCO frequency for PLL2 in Hz */
@@ -272,12 +272,12 @@ chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,	/*  [ IN ] Configu
 	uint32_t desVcoHz = 0;
 
 	/* Get VCO frequencies */
-	if ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) != chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
+	if ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) != chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
 		uint64_t adjustFreq = 0;
 
 		vcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
 		    chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-		    ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+		    ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
 		     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
 
 		/* Adjusted frequency due to chipcHw_REG_PLL_DIVIDER_NDIV_f_SS */
@@ -289,16 +289,16 @@ chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,	/*  [ IN ] Configu
 		/* Desired VCO frequency */
 		desVcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
 		    chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-		    (((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+		    (((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
 		      chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) + 1);
 	} else {
 		vcoFreqPll1Hz = desVcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
 		    chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-		    ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+		    ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
 		     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
 	}
 	vcoFreqPll2Hz = chipcHw_XTAL_FREQ_Hz * chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-	    ((pChipcHw->PLLPreDivider2 & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+	    ((readl(&pChipcHw->PLLPreDivider2) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
 	     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
 
 	switch (clock) {
@@ -307,8 +307,7 @@ chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,	/*  [ IN ] Configu
 		{
 			REG_LOCAL_IRQ_SAVE;
 			/* Dvide DDR_phy by two to obtain DDR_ctrl clock */
-			pChipcHw->DDRClock = (pChipcHw->DDRClock & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((((freq / 2) / chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1)
-				<< chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT);
+			writel((readl(&pChipcHw->DDRClock) & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((((freq / 2) / chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1) << chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT), &pChipcHw->DDRClock);
 			REG_LOCAL_IRQ_RESTORE;
 		}
 		pPLLReg = &pChipcHw->DDRClock;
@@ -329,8 +328,7 @@ chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,	/*  [ IN ] Configu
 		/* Configure the VPM:BUS ratio settings */
 		{
 			REG_LOCAL_IRQ_SAVE;
-			pChipcHw->VPMClock = (pChipcHw->VPMClock & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((chipcHw_divide (freq, chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1)
-				<< chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT);
+			writel((readl(&pChipcHw->VPMClock) & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((chipcHw_divide (freq, chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1) << chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT), &pChipcHw->VPMClock);
 			REG_LOCAL_IRQ_RESTORE;
 		}
 		pPLLReg = &pChipcHw->VPMClock;
@@ -428,9 +426,9 @@ chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,	/*  [ IN ] Configu
 		/* For DDR settings use only the PLL divider clock */
 		if (pPLLReg == &pChipcHw->DDRClock) {
 			/* Set M1DIV for PLL1, which controls the DDR clock */
-			reg32_write(&pChipcHw->PLLDivider, (pChipcHw->PLLDivider & 0x00FFFFFF) | ((chipcHw_REG_PLL_DIVIDER_MDIV (desVcoHz, freq)) << 24));
+			reg32_write(&pChipcHw->PLLDivider, (readl(&pChipcHw->PLLDivider) & 0x00FFFFFF) | ((chipcHw_REG_PLL_DIVIDER_MDIV (desVcoHz, freq)) << 24));
 			/* Calculate expected frequency */
-			freq = chipcHw_divide(vcoHz, (((pChipcHw->PLLDivider & 0xFF000000) >> 24) ? ((pChipcHw->PLLDivider & 0xFF000000) >> 24) : 256));
+			freq = chipcHw_divide(vcoHz, (((readl(&pChipcHw->PLLDivider) & 0xFF000000) >> 24) ? ((readl(&pChipcHw->PLLDivider) & 0xFF000000) >> 24) : 256));
 		} else {
 			/* From chip revision number B0, LCD clock is internally divided by 2 */
 			if ((pPLLReg == &pChipcHw->LCDClock) && (chipcHw_getChipRevisionNumber() != chipcHw_REV_NUMBER_A0)) {
@@ -441,7 +439,7 @@ chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,	/*  [ IN ] Configu
 			reg32_modify_and(pPLLReg, ~(chipcHw_REG_PLL_CLOCK_MDIV_MASK));
 			reg32_modify_or(pPLLReg, chipcHw_REG_PLL_DIVIDER_MDIV(desVcoHz, freq));
 			/* Calculate expected frequency */
-			freq = chipcHw_divide(vcoHz, ((*(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ? (*(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) : 256));
+			freq = chipcHw_divide(vcoHz, ((readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ? (readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) : 256));
 		}
 		/* Wait for for atleast 200ns as per the protocol to change frequency */
 		udelay(1);
@@ -460,16 +458,16 @@ chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,	/*  [ IN ] Configu
 		if (pDependentClock) {
 			switch (dependentClockType) {
 			case PLL_CLOCK:
-				divider = chipcHw_divide(chipcHw_divide (desVcoHz, (*pDependentClock & chipcHw_REG_PLL_CLOCK_MDIV_MASK)), freq);
+				divider = chipcHw_divide(chipcHw_divide (desVcoHz, (readl(pDependentClock) & chipcHw_REG_PLL_CLOCK_MDIV_MASK)), freq);
 				break;
 			case NON_PLL_CLOCK:
 				{
 					uint32_t sourceClock = 0;
 
-					if (pDependentClock == (uint32_t *) &pChipcHw->ACLKClock) {
+					if (pDependentClock == &pChipcHw->ACLKClock) {
 						sourceClock = chipcHw_getClockFrequency (chipcHw_CLOCK_BUS);
 					} else {
-						uint32_t div = *pDependentClock & chipcHw_REG_DIV_CLOCK_DIV_MASK;
+						uint32_t div = readl(pDependentClock) & chipcHw_REG_DIV_CLOCK_DIV_MASK;
 						sourceClock = chipcHw_divide (chipcHw_XTAL_FREQ_Hz, ((div) ? div : 256));
 					}
 					divider = chipcHw_divide(sourceClock, freq);
@@ -483,7 +481,7 @@ chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,	/*  [ IN ] Configu
 		if (divider) {
 			REG_LOCAL_IRQ_SAVE;
 			/* Set the divider to obtain the required frequency */
-			*pClockCtrl = (*pClockCtrl & (~chipcHw_REG_DIV_CLOCK_DIV_MASK)) | (((divider > 256) ? chipcHw_REG_DIV_CLOCK_DIV_256 : divider) & chipcHw_REG_DIV_CLOCK_DIV_MASK);
+			writel((readl(pClockCtrl) & (~chipcHw_REG_DIV_CLOCK_DIV_MASK)) | (((divider > 256) ? chipcHw_REG_DIV_CLOCK_DIV_256 : divider) & chipcHw_REG_DIV_CLOCK_DIV_MASK), pClockCtrl);
 			REG_LOCAL_IRQ_RESTORE;
 			return freq;
 		}
@@ -515,25 +513,26 @@ static int vpmPhaseAlignA0(void)
 	int count = 0;
 
 	for (iter = 0; (iter < MAX_PHASE_ALIGN_ATTEMPTS) && (adjustCount < MAX_PHASE_ADJUST_COUNT); iter++) {
-		phaseControl = (pChipcHw->VPMClock & chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT;
+		phaseControl = (readl(&pChipcHw->VPMClock) & chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT;
 		phaseValue = 0;
 		prevPhaseComp = 0;
 
 		/* Step 1: Look for falling PH_COMP transition */
 
 		/* Read the contents of VPM Clock resgister */
-		phaseValue = pChipcHw->VPMClock;
+		phaseValue = readl(&pChipcHw->VPMClock);
 		do {
 			/* Store previous value of phase comparator */
 			prevPhaseComp = phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP;
 			/* Change the value of PH_CTRL. */
-			reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+			reg32_write(&pChipcHw->VPMClock,
+			(readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
 			/* Wait atleast 20 ns */
 			udelay(1);
 			/* Toggle the LOAD_CH after phase control is written. */
-			pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
+			writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
 			/* Read the contents of  VPM Clock resgister. */
-			phaseValue = pChipcHw->VPMClock;
+			phaseValue = readl(&pChipcHw->VPMClock);
 
 			if ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0x0) {
 				phaseControl = (0x3F & (phaseControl - 1));
@@ -557,12 +556,13 @@ static int vpmPhaseAlignA0(void)
 
 		for (count = 0; (count < 5) && ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0); count++) {
 			phaseControl = (0x3F & (phaseControl + 1));
-			reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+			reg32_write(&pChipcHw->VPMClock,
+			(readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
 			/* Wait atleast 20 ns */
 			udelay(1);
 			/* Toggle the LOAD_CH after phase control is written. */
-			pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
-			phaseValue = pChipcHw->VPMClock;
+			writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
+			phaseValue = readl(&pChipcHw->VPMClock);
 			/* Count number of adjustment made */
 			adjustCount++;
 		}
@@ -581,12 +581,13 @@ static int vpmPhaseAlignA0(void)
 
 		for (count = 0; (count < 3) && ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0); count++) {
 			phaseControl = (0x3F & (phaseControl - 1));
-			reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+			reg32_write(&pChipcHw->VPMClock,
+			(readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
 			/* Wait atleast 20 ns */
 			udelay(1);
 			/* Toggle the LOAD_CH after phase control is written. */
-			pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
-			phaseValue = pChipcHw->VPMClock;
+			writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
+			phaseValue = readl(&pChipcHw->VPMClock);
 			/* Count number of adjustment made */
 			adjustCount++;
 		}
@@ -605,12 +606,13 @@ static int vpmPhaseAlignA0(void)
 
 		for (count = 0; (count < 5); count++) {
 			phaseControl = (0x3F & (phaseControl - 1));
-			reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+			reg32_write(&pChipcHw->VPMClock,
+			(readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
 			/* Wait atleast 20 ns */
 			udelay(1);
 			/* Toggle the LOAD_CH after phase control is written. */
-			pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
-			phaseValue = pChipcHw->VPMClock;
+			writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
+			phaseValue = readl(&pChipcHw->VPMClock);
 			/* Count number of adjustment made */
 			adjustCount++;
 		}
@@ -631,14 +633,14 @@ static int vpmPhaseAlignA0(void)
 			/* Store previous value of phase comparator */
 			prevPhaseComp = phaseValue;
 			/* Change the value of PH_CTRL. */
-			reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+			reg32_write(&pChipcHw->VPMClock,
+			(readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
 			/* Wait atleast 20 ns */
 			udelay(1);
 			/* Toggle the LOAD_CH after phase control is written. */
-			pChipcHw->VPMClock ^=
-			    chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
+			writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
 			/* Read the contents of  VPM Clock resgister. */
-			phaseValue = pChipcHw->VPMClock;
+			phaseValue = readl(&pChipcHw->VPMClock);
 
 			if ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0x0) {
 				phaseControl = (0x3F & (phaseControl - 1));
@@ -661,13 +663,13 @@ static int vpmPhaseAlignA0(void)
 	}
 
 	/* For VPM Phase should be perfectly aligned. */
-	phaseControl = (((pChipcHw->VPMClock >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT) - 1) & 0x3F);
+	phaseControl = (((readl(&pChipcHw->VPMClock) >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT) - 1) & 0x3F);
 	{
 		REG_LOCAL_IRQ_SAVE;
 
-		pChipcHw->VPMClock = (pChipcHw->VPMClock & ~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT);
+		writel((readl(&pChipcHw->VPMClock) & ~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT), &pChipcHw->VPMClock);
 		/* Load new phase value */
-		pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
+		writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
 
 		REG_LOCAL_IRQ_RESTORE;
 	}
@@ -697,7 +699,7 @@ int chipcHw_vpmPhaseAlign(void)
 		int adjustCount = 0;
 
 		/* Disable VPM access */
-		pChipcHw->Spare1 &= ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE;
+		writel(readl(&pChipcHw->Spare1) & ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE, &pChipcHw->Spare1);
 		/* Disable HW VPM phase alignment  */
 		chipcHw_vpmHwPhaseAlignDisable();
 		/* Enable SW VPM phase alignment  */
@@ -715,23 +717,24 @@ int chipcHw_vpmPhaseAlign(void)
 				phaseControl--;
 			} else {
 				/* Enable VPM access */
-				pChipcHw->Spare1 |= chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE;
+				writel(readl(&pChipcHw->Spare1) | chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE, &pChipcHw->Spare1);
 				/* Return adjust count */
 				return adjustCount;
 			}
 			/* Change the value of PH_CTRL. */
-			reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+			reg32_write(&pChipcHw->VPMClock,
+			(readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
 			/* Wait atleast 20 ns */
 			udelay(1);
 			/* Toggle the LOAD_CH after phase control is written. */
-			pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
+			writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
 			/* Count adjustment */
 			adjustCount++;
 		}
 	}
 
 	/* Disable VPM access */
-	pChipcHw->Spare1 &= ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE;
+	writel(readl(&pChipcHw->Spare1) & ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE, &pChipcHw->Spare1);
 	return -1;
 }
 
diff --git a/arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c b/arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c
index 367df75..8377d80 100644
--- a/arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c
+++ b/arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c
@@ -26,15 +26,15 @@
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <csp/errno.h>
-#include <csp/stdint.h>
-#include <csp/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/export.h>
 
 #include <mach/csp/chipcHw_def.h>
 #include <mach/csp/chipcHw_inline.h>
 
-#include <csp/reg.h>
-#include <csp/delay.h>
+#include <mach/csp/reg.h>
+#include <linux/delay.h>
 /* ---- Private Constants and Types --------------------------------------- */
 
 /*
@@ -73,9 +73,9 @@ void chipcHw_pll2Enable(uint32_t vcoFreqHz)
 
 	{
 		REG_LOCAL_IRQ_SAVE;
-		pChipcHw->PLLConfig2 =
-		    chipcHw_REG_PLL_CONFIG_D_RESET |
-		    chipcHw_REG_PLL_CONFIG_A_RESET;
+		writel(chipcHw_REG_PLL_CONFIG_D_RESET |
+		       chipcHw_REG_PLL_CONFIG_A_RESET,
+			&pChipcHw->PLLConfig2);
 
 		pllPreDivider2 = chipcHw_REG_PLL_PREDIVIDER_POWER_DOWN |
 		    chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER |
@@ -87,28 +87,30 @@ void chipcHw_pll2Enable(uint32_t vcoFreqHz)
 		     chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT);
 
 		/* Enable CHIPC registers to control the PLL */
-		pChipcHw->PLLStatus |= chipcHw_REG_PLL_STATUS_CONTROL_ENABLE;
+		writel(readl(&pChipcHw->PLLStatus) | chipcHw_REG_PLL_STATUS_CONTROL_ENABLE, &pChipcHw->PLLStatus);
 
 		/* Set pre divider to get desired VCO frequency */
-		pChipcHw->PLLPreDivider2 = pllPreDivider2;
+		writel(pllPreDivider2, &pChipcHw->PLLPreDivider2);
 		/* Set NDIV Frac */
-		pChipcHw->PLLDivider2 = chipcHw_REG_PLL_DIVIDER_NDIV_f;
+		writel(chipcHw_REG_PLL_DIVIDER_NDIV_f, &pChipcHw->PLLDivider2);
 
 		/* This has to be removed once the default values are fixed for PLL2. */
-		pChipcHw->PLLControl12 = 0x38000700;
-		pChipcHw->PLLControl22 = 0x00000015;
+		writel(0x38000700, &pChipcHw->PLLControl12);
+		writel(0x00000015, &pChipcHw->PLLControl22);
 
 		/* Reset PLL2 */
 		if (vcoFreqHz > chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ) {
-			pChipcHw->PLLConfig2 = chipcHw_REG_PLL_CONFIG_D_RESET |
+			writel(chipcHw_REG_PLL_CONFIG_D_RESET |
 			    chipcHw_REG_PLL_CONFIG_A_RESET |
 			    chipcHw_REG_PLL_CONFIG_VCO_1601_3200 |
-			    chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+			    chipcHw_REG_PLL_CONFIG_POWER_DOWN,
+			    &pChipcHw->PLLConfig2);
 		} else {
-			pChipcHw->PLLConfig2 = chipcHw_REG_PLL_CONFIG_D_RESET |
+			writel(chipcHw_REG_PLL_CONFIG_D_RESET |
 			    chipcHw_REG_PLL_CONFIG_A_RESET |
 			    chipcHw_REG_PLL_CONFIG_VCO_800_1600 |
-			    chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+			    chipcHw_REG_PLL_CONFIG_POWER_DOWN,
+			    &pChipcHw->PLLConfig2);
 		}
 		REG_LOCAL_IRQ_RESTORE;
 	}
@@ -119,22 +121,25 @@ void chipcHw_pll2Enable(uint32_t vcoFreqHz)
 	{
 		REG_LOCAL_IRQ_SAVE;
 		/* Remove analog reset and Power on the PLL */
-		pChipcHw->PLLConfig2 &=
+		writel(readl(&pChipcHw->PLLConfig2) &
 		    ~(chipcHw_REG_PLL_CONFIG_A_RESET |
-		      chipcHw_REG_PLL_CONFIG_POWER_DOWN);
+		      chipcHw_REG_PLL_CONFIG_POWER_DOWN),
+		      &pChipcHw->PLLConfig2);
 
 		REG_LOCAL_IRQ_RESTORE;
 
 	}
 
 	/* Wait until PLL is locked */
-	while (!(pChipcHw->PLLStatus2 & chipcHw_REG_PLL_STATUS_LOCKED))
+	while (!(readl(&pChipcHw->PLLStatus2) & chipcHw_REG_PLL_STATUS_LOCKED))
 		;
 
 	{
 		REG_LOCAL_IRQ_SAVE;
 		/* Remove digital reset */
-		pChipcHw->PLLConfig2 &= ~chipcHw_REG_PLL_CONFIG_D_RESET;
+		writel(readl(&pChipcHw->PLLConfig2) &
+			~chipcHw_REG_PLL_CONFIG_D_RESET,
+			&pChipcHw->PLLConfig2);
 
 		REG_LOCAL_IRQ_RESTORE;
 	}
@@ -157,9 +162,9 @@ void chipcHw_pll1Enable(uint32_t vcoFreqHz, chipcHw_SPREAD_SPECTRUM_e ssSupport)
 	{
 		REG_LOCAL_IRQ_SAVE;
 
-		pChipcHw->PLLConfig =
-		    chipcHw_REG_PLL_CONFIG_D_RESET |
-		    chipcHw_REG_PLL_CONFIG_A_RESET;
+		writel(chipcHw_REG_PLL_CONFIG_D_RESET |
+		    chipcHw_REG_PLL_CONFIG_A_RESET,
+		    &pChipcHw->PLLConfig);
 		/* Setting VCO frequency */
 		if (ssSupport == chipcHw_SPREAD_SPECTRUM_ALLOW) {
 			pllPreDivider =
@@ -182,30 +187,22 @@ void chipcHw_pll1Enable(uint32_t vcoFreqHz, chipcHw_SPREAD_SPECTRUM_e ssSupport)
 		}
 
 		/* Enable CHIPC registers to control the PLL */
-		pChipcHw->PLLStatus |= chipcHw_REG_PLL_STATUS_CONTROL_ENABLE;
+		writel(readl(&pChipcHw->PLLStatus) | chipcHw_REG_PLL_STATUS_CONTROL_ENABLE, &pChipcHw->PLLStatus);
 
 		/* Set pre divider to get desired VCO frequency */
-		pChipcHw->PLLPreDivider = pllPreDivider;
+		writel(pllPreDivider, &pChipcHw->PLLPreDivider);
 		/* Set NDIV Frac */
 		if (ssSupport == chipcHw_SPREAD_SPECTRUM_ALLOW) {
-			pChipcHw->PLLDivider = chipcHw_REG_PLL_DIVIDER_M1DIV |
-			    chipcHw_REG_PLL_DIVIDER_NDIV_f_SS;
+			writel(chipcHw_REG_PLL_DIVIDER_M1DIV | chipcHw_REG_PLL_DIVIDER_NDIV_f_SS, &pChipcHw->PLLDivider);
 		} else {
-			pChipcHw->PLLDivider = chipcHw_REG_PLL_DIVIDER_M1DIV |
-			    chipcHw_REG_PLL_DIVIDER_NDIV_f;
+			writel(chipcHw_REG_PLL_DIVIDER_M1DIV | chipcHw_REG_PLL_DIVIDER_NDIV_f, &pChipcHw->PLLDivider);
 		}
 
 		/* Reset PLL1 */
 		if (vcoFreqHz > chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ) {
-			pChipcHw->PLLConfig = chipcHw_REG_PLL_CONFIG_D_RESET |
-			    chipcHw_REG_PLL_CONFIG_A_RESET |
-			    chipcHw_REG_PLL_CONFIG_VCO_1601_3200 |
-			    chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+			writel(chipcHw_REG_PLL_CONFIG_D_RESET | chipcHw_REG_PLL_CONFIG_A_RESET | chipcHw_REG_PLL_CONFIG_VCO_1601_3200 | chipcHw_REG_PLL_CONFIG_POWER_DOWN, &pChipcHw->PLLConfig);
 		} else {
-			pChipcHw->PLLConfig = chipcHw_REG_PLL_CONFIG_D_RESET |
-			    chipcHw_REG_PLL_CONFIG_A_RESET |
-			    chipcHw_REG_PLL_CONFIG_VCO_800_1600 |
-			    chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+			writel(chipcHw_REG_PLL_CONFIG_D_RESET | chipcHw_REG_PLL_CONFIG_A_RESET | chipcHw_REG_PLL_CONFIG_VCO_800_1600 | chipcHw_REG_PLL_CONFIG_POWER_DOWN, &pChipcHw->PLLConfig);
 		}
 
 		REG_LOCAL_IRQ_RESTORE;
@@ -216,22 +213,19 @@ void chipcHw_pll1Enable(uint32_t vcoFreqHz, chipcHw_SPREAD_SPECTRUM_e ssSupport)
 		{
 			REG_LOCAL_IRQ_SAVE;
 			/* Remove analog reset and Power on the PLL */
-			pChipcHw->PLLConfig &=
-			    ~(chipcHw_REG_PLL_CONFIG_A_RESET |
-			      chipcHw_REG_PLL_CONFIG_POWER_DOWN);
+			writel(readl(&pChipcHw->PLLConfig) & ~(chipcHw_REG_PLL_CONFIG_A_RESET | chipcHw_REG_PLL_CONFIG_POWER_DOWN), &pChipcHw->PLLConfig);
 			REG_LOCAL_IRQ_RESTORE;
 		}
 
 		/* Wait until PLL is locked */
-		while (!(pChipcHw->PLLStatus & chipcHw_REG_PLL_STATUS_LOCKED)
-		       || !(pChipcHw->
-			    PLLStatus2 & chipcHw_REG_PLL_STATUS_LOCKED))
+		while (!(readl(&pChipcHw->PLLStatus) & chipcHw_REG_PLL_STATUS_LOCKED)
+		       || !(readl(&pChipcHw->PLLStatus2) & chipcHw_REG_PLL_STATUS_LOCKED))
 			;
 
 		/* Remove digital reset */
 		{
 			REG_LOCAL_IRQ_SAVE;
-			pChipcHw->PLLConfig &= ~chipcHw_REG_PLL_CONFIG_D_RESET;
+			writel(readl(&pChipcHw->PLLConfig) & ~chipcHw_REG_PLL_CONFIG_D_RESET, &pChipcHw->PLLConfig);
 			REG_LOCAL_IRQ_RESTORE;
 		}
 	}
@@ -267,11 +261,7 @@ void chipcHw_Init(chipcHw_INIT_PARAM_t *initParam	/*  [ IN ] Misc chip initializ
 	chipcHw_clearStickyBits(chipcHw_REG_STICKY_CHIP_SOFT_RESET);
 
 	/* Before configuring the ARM clock, atleast we need to make sure BUS clock maintains the proper ratio with ARM clock */
-	pChipcHw->ACLKClock =
-	    (pChipcHw->
-	     ACLKClock & ~chipcHw_REG_ACLKClock_CLK_DIV_MASK) | (initParam->
-								 armBusRatio &
-								 chipcHw_REG_ACLKClock_CLK_DIV_MASK);
+	writel((readl(&pChipcHw->ACLKClock) & ~chipcHw_REG_ACLKClock_CLK_DIV_MASK) | (initParam-> armBusRatio & chipcHw_REG_ACLKClock_CLK_DIV_MASK), &pChipcHw->ACLKClock);
 
 	/* Set various core component frequencies. The order in which this is done is important for some. */
 	/* The RTBUS (DDR PHY) is derived from the BUS, and the BUS from the ARM, and VPM needs to know BUS */
diff --git a/arch/arm/mach-bcmring/csp/chipc/chipcHw_reset.c b/arch/arm/mach-bcmring/csp/chipc/chipcHw_reset.c
index 2671d88..f95ce91 100644
--- a/arch/arm/mach-bcmring/csp/chipc/chipcHw_reset.c
+++ b/arch/arm/mach-bcmring/csp/chipc/chipcHw_reset.c
@@ -13,11 +13,11 @@
 *****************************************************************************/
 
 /* ---- Include Files ---------------------------------------------------- */
-#include <csp/stdint.h>
+#include <linux/types.h>
 #include <mach/csp/chipcHw_def.h>
 #include <mach/csp/chipcHw_inline.h>
-#include <csp/intcHw.h>
-#include <csp/cache.h>
+#include <mach/csp/intcHw_reg.h>
+#include <asm/cacheflush.h>
 
 /* ---- Private Constants and Types --------------------------------------- */
 /* ---- Private Variables ------------------------------------------------- */
@@ -50,17 +50,18 @@ void chipcHw_reset(uint32_t mask)
 			chipcHw_softReset(chipcHw_REG_SOFT_RESET_CHIP_SOFT);
 		}
 		/* Bypass the PLL clocks before reboot */
-		pChipcHw->UARTClock |= chipcHw_REG_PLL_CLOCK_BYPASS_SELECT;
-		pChipcHw->SPIClock |= chipcHw_REG_PLL_CLOCK_BYPASS_SELECT;
+		writel(readl(&pChipcHw->UARTClock) | chipcHw_REG_PLL_CLOCK_BYPASS_SELECT,
+			&pChipcHw->UARTClock);
+		writel(readl(&pChipcHw->SPIClock) | chipcHw_REG_PLL_CLOCK_BYPASS_SELECT,
+			&pChipcHw->SPIClock);
 
 		/* Copy the chipcHw_warmReset_run_from_aram function into ARAM */
 		do {
-			((uint32_t *) MM_IO_BASE_ARAM)[i] =
-			    ((uint32_t *) &chipcHw_reset_run_from_aram)[i];
+			writel(((uint32_t *) &chipcHw_reset_run_from_aram)[i], ((uint32_t __iomem *) MM_IO_BASE_ARAM) + i);
 			i++;
-		} while (((uint32_t *) MM_IO_BASE_ARAM)[i - 1] != 0xe1a0f00f);	/* 0xe1a0f00f == asm ("mov r15, r15"); */
+		} while (readl(((uint32_t __iomem*) MM_IO_BASE_ARAM) + i - 1) != 0xe1a0f00f);	/* 0xe1a0f00f == asm ("mov r15, r15"); */
 
-		CSP_CACHE_FLUSH_ALL;
+		flush_cache_all();
 
 		/* run the function from ARAM */
 		runFunc();
diff --git a/arch/arm/mach-bcmring/csp/dmac/dmacHw.c b/arch/arm/mach-bcmring/csp/dmac/dmacHw.c
index 6b9be2e..547f746 100644
--- a/arch/arm/mach-bcmring/csp/dmac/dmacHw.c
+++ b/arch/arm/mach-bcmring/csp/dmac/dmacHw.c
@@ -25,11 +25,11 @@
 /****************************************************************************/
 
 /* ---- Include Files ---------------------------------------------------- */
-#include <csp/stdint.h>
-#include <csp/string.h>
-#include <stddef.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/stddef.h>
 
-#include <csp/dmacHw.h>
+#include <mach/csp/dmacHw.h>
 #include <mach/csp/dmacHw_reg.h>
 #include <mach/csp/dmacHw_priv.h>
 #include <mach/csp/chipcHw_inline.h>
@@ -55,33 +55,32 @@ static uint32_t GetFifoSize(dmacHw_HANDLE_t handle	/*   [ IN ] DMA Channel handl
     ) {
 	uint32_t val = 0;
 	dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
-	dmacHw_MISC_t *pMiscReg =
-	    (dmacHw_MISC_t *) dmacHw_REG_MISC_BASE(pCblk->module);
+	dmacHw_MISC_t __iomem *pMiscReg = (void __iomem *)dmacHw_REG_MISC_BASE(pCblk->module);
 
 	switch (pCblk->channel) {
 	case 0:
-		val = (pMiscReg->CompParm2.lo & 0x70000000) >> 28;
+		val = (readl(&pMiscReg->CompParm2.lo) & 0x70000000) >> 28;
 		break;
 	case 1:
-		val = (pMiscReg->CompParm3.hi & 0x70000000) >> 28;
+		val = (readl(&pMiscReg->CompParm3.hi) & 0x70000000) >> 28;
 		break;
 	case 2:
-		val = (pMiscReg->CompParm3.lo & 0x70000000) >> 28;
+		val = (readl(&pMiscReg->CompParm3.lo) & 0x70000000) >> 28;
 		break;
 	case 3:
-		val = (pMiscReg->CompParm4.hi & 0x70000000) >> 28;
+		val = (readl(&pMiscReg->CompParm4.hi) & 0x70000000) >> 28;
 		break;
 	case 4:
-		val = (pMiscReg->CompParm4.lo & 0x70000000) >> 28;
+		val = (readl(&pMiscReg->CompParm4.lo) & 0x70000000) >> 28;
 		break;
 	case 5:
-		val = (pMiscReg->CompParm5.hi & 0x70000000) >> 28;
+		val = (readl(&pMiscReg->CompParm5.hi) & 0x70000000) >> 28;
 		break;
 	case 6:
-		val = (pMiscReg->CompParm5.lo & 0x70000000) >> 28;
+		val = (readl(&pMiscReg->CompParm5.lo) & 0x70000000) >> 28;
 		break;
 	case 7:
-		val = (pMiscReg->CompParm6.hi & 0x70000000) >> 28;
+		val = (readl(&pMiscReg->CompParm6.hi) & 0x70000000) >> 28;
 		break;
 	}
 
diff --git a/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c b/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c
index a1f3283..fe43869 100644
--- a/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c
+++ b/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c
@@ -26,10 +26,10 @@
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <csp/stdint.h>
-#include <stddef.h>
+#include <linux/types.h>
+#include <linux/stddef.h>
 
-#include <csp/dmacHw.h>
+#include <mach/csp/dmacHw.h>
 #include <mach/csp/dmacHw_reg.h>
 #include <mach/csp/dmacHw_priv.h>
 
diff --git a/arch/arm/mach-bcmring/csp/tmr/tmrHw.c b/arch/arm/mach-bcmring/csp/tmr/tmrHw.c
index 16225e4..dc4137f 100644
--- a/arch/arm/mach-bcmring/csp/tmr/tmrHw.c
+++ b/arch/arm/mach-bcmring/csp/tmr/tmrHw.c
@@ -26,10 +26,10 @@
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <csp/errno.h>
-#include <csp/stdint.h>
+#include <linux/errno.h>
+#include <linux/types.h>
 
-#include <csp/tmrHw.h>
+#include <mach/csp/tmrHw.h>
 #include <mach/csp/tmrHw_reg.h>
 
 #define tmrHw_ASSERT(a)                     if (!(a)) *(char *)0 = 0
diff --git a/arch/arm/mach-bcmring/include/cfg_global.h b/arch/arm/mach-bcmring/include/cfg_global.h
deleted file mode 100644
index f01da87..0000000
--- a/arch/arm/mach-bcmring/include/cfg_global.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef _CFG_GLOBAL_H_
-#define _CFG_GLOBAL_H_
-
-#include <cfg_global_defines.h>
-
-#define CFG_GLOBAL_CHIP                         BCM11107
-#define CFG_GLOBAL_CHIP_FAMILY                  CFG_GLOBAL_CHIP_FAMILY_BCMRING
-#define CFG_GLOBAL_CHIP_REV                     0xB0
-#define CFG_GLOBAL_RAM_SIZE                     0x10000000
-#define CFG_GLOBAL_RAM_BASE                     0x00000000
-#define CFG_GLOBAL_RAM_RESERVED_SIZE            0x000000
-
-#endif /* _CFG_GLOBAL_H_ */
diff --git a/arch/arm/mach-bcmring/include/cfg_global_defines.h b/arch/arm/mach-bcmring/include/cfg_global_defines.h
deleted file mode 100644
index b5beb0b..0000000
--- a/arch/arm/mach-bcmring/include/cfg_global_defines.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*****************************************************************************
-* Copyright 2006 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-#ifndef CFG_GLOBAL_DEFINES_H
-#define CFG_GLOBAL_DEFINES_H
-
-/* CHIP */
-#define BCM1103 1
-
-#define BCM1191 4
-#define BCM2153 5
-#define BCM2820 6
-
-#define BCM2826 8
-#define FPGA11107 9
-#define BCM11107   10
-#define BCM11109   11
-#define BCM11170   12
-#define BCM11110   13
-#define BCM11211   14
-
-/* CFG_GLOBAL_CHIP_FAMILY types */
-#define CFG_GLOBAL_CHIP_FAMILY_NONE        0
-#define CFG_GLOBAL_CHIP_FAMILY_BCM116X     2
-#define CFG_GLOBAL_CHIP_FAMILY_BCMRING     4
-#define CFG_GLOBAL_CHIP_FAMILY_BCM1103     8
-
-#define IMAGE_HEADER_SIZE_CHECKSUM    4
-#endif
diff --git a/arch/arm/mach-bcmring/include/csp/cache.h b/arch/arm/mach-bcmring/include/csp/cache.h
deleted file mode 100644
index caa20e5..0000000
--- a/arch/arm/mach-bcmring/include/csp/cache.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-#ifndef CSP_CACHE_H
-#define CSP_CACHE_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#include <csp/stdint.h>
-
-/* ---- Public Constants and Types --------------------------------------- */
-
-#if defined(__KERNEL__) && !defined(STANDALONE)
-#include <asm/cacheflush.h>
-
-#define CSP_CACHE_FLUSH_ALL      flush_cache_all()
-
-#else
-
-#define CSP_CACHE_FLUSH_ALL
-
-#endif
-
-#endif /* CSP_CACHE_H */
diff --git a/arch/arm/mach-bcmring/include/csp/delay.h b/arch/arm/mach-bcmring/include/csp/delay.h
deleted file mode 100644
index 8b3d803..0000000
--- a/arch/arm/mach-bcmring/include/csp/delay.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-
-#ifndef CSP_DELAY_H
-#define CSP_DELAY_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-/* Some CSP routines require use of the following delay routines. Use the OS */
-/* version if available, otherwise use a CSP specific definition. */
-/* void udelay(unsigned long usecs); */
-/* void mdelay(unsigned long msecs); */
-
-#if defined(__KERNEL__) && !defined(STANDALONE)
-   #include <linux/delay.h>
-#else
-   #include <mach/csp/delay.h>
-#endif
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-
-#endif /*  CSP_DELAY_H */
diff --git a/arch/arm/mach-bcmring/include/csp/dmacHw.h b/arch/arm/mach-bcmring/include/csp/dmacHw.h
deleted file mode 100644
index e6a1dc4..0000000
--- a/arch/arm/mach-bcmring/include/csp/dmacHw.h
+++ /dev/null
@@ -1,596 +0,0 @@
-/*****************************************************************************
-* Copyright 2004 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-/****************************************************************************/
-/**
-*  @file    dmacHw.h
-*
-*  @brief   API definitions for low level DMA controller driver
-*
-*/
-/****************************************************************************/
-#ifndef _DMACHW_H
-#define _DMACHW_H
-
-#include <stddef.h>
-
-#include <csp/stdint.h>
-#include <mach/csp/dmacHw_reg.h>
-
-/* Define DMA Channel ID using DMA controller number (m) and channel number (c).
-
-   System specific channel ID should be defined as follows
-
-   For example:
-
-   #include <dmacHw.h>
-   ...
-   #define systemHw_LCD_CHANNEL_ID                dmacHw_MAKE_CHANNEL_ID(0,5)
-   #define systemHw_SWITCH_RX_CHANNEL_ID          dmacHw_MAKE_CHANNEL_ID(0,0)
-   #define systemHw_SWITCH_TX_CHANNEL_ID          dmacHw_MAKE_CHANNEL_ID(0,1)
-   #define systemHw_APM_RX_CHANNEL_ID             dmacHw_MAKE_CHANNEL_ID(0,3)
-   #define systemHw_APM_TX_CHANNEL_ID             dmacHw_MAKE_CHANNEL_ID(0,4)
-   ...
-   #define systemHw_SHARED1_CHANNEL_ID            dmacHw_MAKE_CHANNEL_ID(1,4)
-   #define systemHw_SHARED2_CHANNEL_ID            dmacHw_MAKE_CHANNEL_ID(1,5)
-   #define systemHw_SHARED3_CHANNEL_ID            dmacHw_MAKE_CHANNEL_ID(0,6)
-   ...
-*/
-#define dmacHw_MAKE_CHANNEL_ID(m, c)         (m << 8 | c)
-
-typedef enum {
-	dmacHw_CHANNEL_PRIORITY_0 = dmacHw_REG_CFG_LO_CH_PRIORITY_0,	/* Channel priority 0. Lowest priority DMA channel */
-	dmacHw_CHANNEL_PRIORITY_1 = dmacHw_REG_CFG_LO_CH_PRIORITY_1,	/* Channel priority 1 */
-	dmacHw_CHANNEL_PRIORITY_2 = dmacHw_REG_CFG_LO_CH_PRIORITY_2,	/* Channel priority 2 */
-	dmacHw_CHANNEL_PRIORITY_3 = dmacHw_REG_CFG_LO_CH_PRIORITY_3,	/* Channel priority 3 */
-	dmacHw_CHANNEL_PRIORITY_4 = dmacHw_REG_CFG_LO_CH_PRIORITY_4,	/* Channel priority 4 */
-	dmacHw_CHANNEL_PRIORITY_5 = dmacHw_REG_CFG_LO_CH_PRIORITY_5,	/* Channel priority 5 */
-	dmacHw_CHANNEL_PRIORITY_6 = dmacHw_REG_CFG_LO_CH_PRIORITY_6,	/* Channel priority 6 */
-	dmacHw_CHANNEL_PRIORITY_7 = dmacHw_REG_CFG_LO_CH_PRIORITY_7	/* Channel priority 7. Highest priority DMA channel */
-} dmacHw_CHANNEL_PRIORITY_e;
-
-/* Source destination master interface */
-typedef enum {
-	dmacHw_SRC_MASTER_INTERFACE_1 = dmacHw_REG_CTL_SMS_1,	/* Source DMA master interface 1 */
-	dmacHw_SRC_MASTER_INTERFACE_2 = dmacHw_REG_CTL_SMS_2,	/* Source DMA master interface 2 */
-	dmacHw_DST_MASTER_INTERFACE_1 = dmacHw_REG_CTL_DMS_1,	/* Destination DMA master interface 1 */
-	dmacHw_DST_MASTER_INTERFACE_2 = dmacHw_REG_CTL_DMS_2	/* Destination DMA master interface 2 */
-} dmacHw_MASTER_INTERFACE_e;
-
-typedef enum {
-	dmacHw_SRC_TRANSACTION_WIDTH_8 = dmacHw_REG_CTL_SRC_TR_WIDTH_8,	/* Source 8 bit  (1 byte) per transaction */
-	dmacHw_SRC_TRANSACTION_WIDTH_16 = dmacHw_REG_CTL_SRC_TR_WIDTH_16,	/* Source 16 bit (2 byte) per transaction */
-	dmacHw_SRC_TRANSACTION_WIDTH_32 = dmacHw_REG_CTL_SRC_TR_WIDTH_32,	/* Source 32 bit (4 byte) per transaction */
-	dmacHw_SRC_TRANSACTION_WIDTH_64 = dmacHw_REG_CTL_SRC_TR_WIDTH_64,	/* Source 64 bit (8 byte) per transaction */
-	dmacHw_DST_TRANSACTION_WIDTH_8 = dmacHw_REG_CTL_DST_TR_WIDTH_8,	/* Destination 8 bit  (1 byte) per transaction */
-	dmacHw_DST_TRANSACTION_WIDTH_16 = dmacHw_REG_CTL_DST_TR_WIDTH_16,	/* Destination 16 bit (2 byte) per transaction */
-	dmacHw_DST_TRANSACTION_WIDTH_32 = dmacHw_REG_CTL_DST_TR_WIDTH_32,	/* Destination 32 bit (4 byte) per transaction */
-	dmacHw_DST_TRANSACTION_WIDTH_64 = dmacHw_REG_CTL_DST_TR_WIDTH_64	/* Destination 64 bit (8 byte) per transaction */
-} dmacHw_TRANSACTION_WIDTH_e;
-
-typedef enum {
-	dmacHw_SRC_BURST_WIDTH_0 = dmacHw_REG_CTL_SRC_MSIZE_0,	/* Source No burst */
-	dmacHw_SRC_BURST_WIDTH_4 = dmacHw_REG_CTL_SRC_MSIZE_4,	/* Source 4  X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
-	dmacHw_SRC_BURST_WIDTH_8 = dmacHw_REG_CTL_SRC_MSIZE_8,	/* Source 8  X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
-	dmacHw_SRC_BURST_WIDTH_16 = dmacHw_REG_CTL_SRC_MSIZE_16,	/* Source 16 X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
-	dmacHw_DST_BURST_WIDTH_0 = dmacHw_REG_CTL_DST_MSIZE_0,	/* Destination No burst */
-	dmacHw_DST_BURST_WIDTH_4 = dmacHw_REG_CTL_DST_MSIZE_4,	/* Destination 4  X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
-	dmacHw_DST_BURST_WIDTH_8 = dmacHw_REG_CTL_DST_MSIZE_8,	/* Destination 8  X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
-	dmacHw_DST_BURST_WIDTH_16 = dmacHw_REG_CTL_DST_MSIZE_16	/* Destination 16 X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
-} dmacHw_BURST_WIDTH_e;
-
-typedef enum {
-	dmacHw_TRANSFER_TYPE_MEM_TO_MEM = dmacHw_REG_CTL_TTFC_MM_DMAC,	/* Memory to memory transfer */
-	dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM = dmacHw_REG_CTL_TTFC_PM_DMAC,	/* Peripheral to memory transfer */
-	dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL = dmacHw_REG_CTL_TTFC_MP_DMAC,	/* Memory to peripheral transfer */
-	dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_PERIPHERAL = dmacHw_REG_CTL_TTFC_PP_DMAC	/* Peripheral to peripheral transfer */
-} dmacHw_TRANSFER_TYPE_e;
-
-typedef enum {
-	dmacHw_TRANSFER_MODE_PERREQUEST,	/* Block transfer per DMA request */
-	dmacHw_TRANSFER_MODE_CONTINUOUS,	/* Continuous transfer of streaming data */
-	dmacHw_TRANSFER_MODE_PERIODIC	/* Periodic transfer of streaming data */
-} dmacHw_TRANSFER_MODE_e;
-
-typedef enum {
-	dmacHw_SRC_ADDRESS_UPDATE_MODE_INC = dmacHw_REG_CTL_SINC_INC,	/* Increment source address after every transaction */
-	dmacHw_SRC_ADDRESS_UPDATE_MODE_DEC = dmacHw_REG_CTL_SINC_DEC,	/* Decrement source address after every transaction */
-	dmacHw_DST_ADDRESS_UPDATE_MODE_INC = dmacHw_REG_CTL_DINC_INC,	/* Increment destination address after every transaction */
-	dmacHw_DST_ADDRESS_UPDATE_MODE_DEC = dmacHw_REG_CTL_DINC_DEC,	/* Decrement destination address after every transaction */
-	dmacHw_SRC_ADDRESS_UPDATE_MODE_NC = dmacHw_REG_CTL_SINC_NC,	/* No change in source address after every transaction */
-	dmacHw_DST_ADDRESS_UPDATE_MODE_NC = dmacHw_REG_CTL_DINC_NC	/* No change in destination address after every transaction */
-} dmacHw_ADDRESS_UPDATE_MODE_e;
-
-typedef enum {
-	dmacHw_FLOW_CONTROL_DMA,	/* DMA working as flow controller (default) */
-	dmacHw_FLOW_CONTROL_PERIPHERAL	/* Peripheral working as flow controller */
-} dmacHw_FLOW_CONTROL_e;
-
-typedef enum {
-	dmacHw_TRANSFER_STATUS_BUSY,	/* DMA Transfer ongoing */
-	dmacHw_TRANSFER_STATUS_DONE,	/* DMA Transfer completed */
-	dmacHw_TRANSFER_STATUS_ERROR	/* DMA Transfer error */
-} dmacHw_TRANSFER_STATUS_e;
-
-typedef enum {
-	dmacHw_INTERRUPT_DISABLE,	/* Interrupt disable  */
-	dmacHw_INTERRUPT_ENABLE	/* Interrupt enable */
-} dmacHw_INTERRUPT_e;
-
-typedef enum {
-	dmacHw_INTERRUPT_STATUS_NONE = 0x0,	/* No DMA interrupt */
-	dmacHw_INTERRUPT_STATUS_TRANS = 0x1,	/* End of DMA transfer interrupt */
-	dmacHw_INTERRUPT_STATUS_BLOCK = 0x2,	/* End of block transfer interrupt */
-	dmacHw_INTERRUPT_STATUS_ERROR = 0x4	/* Error interrupt */
-} dmacHw_INTERRUPT_STATUS_e;
-
-typedef enum {
-	dmacHw_CONTROLLER_ATTRIB_CHANNEL_NUM,	/* Number of DMA channel */
-	dmacHw_CONTROLLER_ATTRIB_CHANNEL_MAX_BLOCK_SIZE,	/* Maximum channel burst size */
-	dmacHw_CONTROLLER_ATTRIB_MASTER_INTF_NUM,	/* Number of DMA master interface */
-	dmacHw_CONTROLLER_ATTRIB_CHANNEL_BUS_WIDTH,	/* Channel Data bus width */
-	dmacHw_CONTROLLER_ATTRIB_CHANNEL_FIFO_SIZE	/* Channel FIFO size */
-} dmacHw_CONTROLLER_ATTRIB_e;
-
-typedef unsigned long dmacHw_HANDLE_t;	/* DMA channel handle */
-typedef uint32_t dmacHw_ID_t;	/* DMA channel Id.  Must be created using
-				   "dmacHw_MAKE_CHANNEL_ID" macro
-				 */
-/* DMA channel configuration parameters */
-typedef struct {
-	uint32_t srcPeripheralPort;	/* Source peripheral port */
-	uint32_t dstPeripheralPort;	/* Destination peripheral port */
-	uint32_t srcStatusRegisterAddress;	/* Source status register address */
-	uint32_t dstStatusRegisterAddress;	/* Destination status register address of type  */
-
-	uint32_t srcGatherWidth;	/* Number of bytes gathered before successive gather opearation */
-	uint32_t srcGatherJump;	/* Number of bytes jumpped before successive gather opearation */
-	uint32_t dstScatterWidth;	/* Number of bytes sacattered before successive scatter opearation */
-	uint32_t dstScatterJump;	/* Number of bytes jumpped  before successive scatter opearation */
-	uint32_t maxDataPerBlock;	/* Maximum number of bytes to be transferred per block/descrptor.
-					   0 = Maximum possible.
-					 */
-
-	dmacHw_ADDRESS_UPDATE_MODE_e srcUpdate;	/* Source address update mode */
-	dmacHw_ADDRESS_UPDATE_MODE_e dstUpdate;	/* Destination address update mode */
-	dmacHw_TRANSFER_TYPE_e transferType;	/* DMA transfer type  */
-	dmacHw_TRANSFER_MODE_e transferMode;	/* DMA transfer mode */
-	dmacHw_MASTER_INTERFACE_e srcMasterInterface;	/* DMA source interface  */
-	dmacHw_MASTER_INTERFACE_e dstMasterInterface;	/* DMA destination interface */
-	dmacHw_TRANSACTION_WIDTH_e srcMaxTransactionWidth;	/* Source transaction width   */
-	dmacHw_TRANSACTION_WIDTH_e dstMaxTransactionWidth;	/* Destination transaction width */
-	dmacHw_BURST_WIDTH_e srcMaxBurstWidth;	/* Source burst width */
-	dmacHw_BURST_WIDTH_e dstMaxBurstWidth;	/* Destination burst width */
-	dmacHw_INTERRUPT_e blockTransferInterrupt;	/* Block trsnafer interrupt */
-	dmacHw_INTERRUPT_e completeTransferInterrupt;	/* Complete DMA trsnafer interrupt */
-	dmacHw_INTERRUPT_e errorInterrupt;	/* Error interrupt */
-	dmacHw_CHANNEL_PRIORITY_e channelPriority;	/* Channel priority */
-	dmacHw_FLOW_CONTROL_e flowControler;	/* Data flow controller */
-} dmacHw_CONFIG_t;
-
-/****************************************************************************/
-/**
-*  @brief   Initializes DMA
-*
-*  This function initializes DMA CSP driver
-*
-*  @note
-*     Must be called before using any DMA channel
-*/
-/****************************************************************************/
-void dmacHw_initDma(void);
-
-/****************************************************************************/
-/**
-*  @brief   Exit function for  DMA
-*
-*  This function isolates DMA from the system
-*
-*/
-/****************************************************************************/
-void dmacHw_exitDma(void);
-
-/****************************************************************************/
-/**
-*  @brief   Gets a handle to a DMA channel
-*
-*  This function returns a handle, representing a control block of a particular DMA channel
-*
-*  @return  -1       - On Failure
-*            handle  - On Success, representing a channel control block
-*
-*  @note
-*     None  Channel ID must be created using "dmacHw_MAKE_CHANNEL_ID" macro
-*/
-/****************************************************************************/
-dmacHw_HANDLE_t dmacHw_getChannelHandle(dmacHw_ID_t channelId	/* [ IN ] DMA Channel Id */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Initializes a DMA channel for use
-*
-*  This function initializes and resets a DMA channel for use
-*
-*  @return  -1     - On Failure
-*            0     - On Success
-*
-*  @note
-*     None
-*/
-/****************************************************************************/
-int dmacHw_initChannel(dmacHw_HANDLE_t handle	/*  [ IN ] DMA Channel handle  */
-    );
-
-/****************************************************************************/
-/**
-*  @brief  Estimates number of descriptor needed to perform certain DMA transfer
-*
-*
-*  @return  On failure : -1
-*           On success : Number of descriptor count
-*
-*
-*/
-/****************************************************************************/
-int dmacHw_calculateDescriptorCount(dmacHw_CONFIG_t *pConfig,	/*   [ IN ] Configuration settings */
-				    void *pSrcAddr,	/*   [ IN ] Source (Peripheral/Memory) address */
-				    void *pDstAddr,	/*   [ IN ] Destination (Peripheral/Memory) address */
-				    size_t dataLen	/*   [ IN ] Data length in bytes */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Initializes descriptor ring
-*
-*  This function will initializes the descriptor ring of a DMA channel
-*
-*
-*  @return   -1 - On failure
-*             0 - On success
-*  @note
-*     - "len" parameter should be obtained from "dmacHw_descriptorLen"
-*     - Descriptor buffer MUST be 32 bit aligned and uncached as it
-*       is accessed by ARM and DMA
-*/
-/****************************************************************************/
-int dmacHw_initDescriptor(void *pDescriptorVirt,	/*  [ IN ] Virtual address of uncahced buffer allocated to form descriptor ring */
-			  uint32_t descriptorPhyAddr,	/*  [ IN ] Physical address of pDescriptorVirt (descriptor buffer) */
-			  uint32_t len,	/*  [ IN ] Size of the pBuf */
-			  uint32_t num	/*  [ IN ] Number of descriptor in the ring */
-    );
-
-/****************************************************************************/
-/**
-*  @brief  Finds amount of memory required to form a descriptor ring
-*
-*
-*  @return   Number of bytes required to form a descriptor ring
-*
-*
-*  @note
-*     None
-*/
-/****************************************************************************/
-uint32_t dmacHw_descriptorLen(uint32_t descCnt	/*  [ IN ] Number of descriptor in the ring */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Configure DMA channel
-*
-*  @return  0  : On success
-*           -1 : On failure
-*/
-/****************************************************************************/
-int dmacHw_configChannel(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle  */
-			 dmacHw_CONFIG_t *pConfig	/*   [ IN ] Configuration settings */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Set descriptors for known data length
-*
-*  When DMA has to work as a flow controller, this function prepares the
-*  descriptor chain to transfer data
-*
-*  from:
-*          - Memory to memory
-*          - Peripheral to memory
-*          - Memory to Peripheral
-*          - Peripheral to Peripheral
-*
-*  @return   -1 - On failure
-*             0 - On success
-*
-*/
-/****************************************************************************/
-int dmacHw_setDataDescriptor(dmacHw_CONFIG_t *pConfig,	/*  [ IN ] Configuration settings */
-			     void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
-			     void *pSrcAddr,	/*  [ IN ] Source (Peripheral/Memory) address */
-			     void *pDstAddr,	/*  [ IN ] Destination (Peripheral/Memory) address */
-			     size_t dataLen	/*  [ IN ] Length in bytes   */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Indicates whether DMA transfer is in progress or completed
-*
-*  @return   DMA transfer status
-*          dmacHw_TRANSFER_STATUS_BUSY:         DMA Transfer ongoing
-*          dmacHw_TRANSFER_STATUS_DONE:         DMA Transfer completed
-*          dmacHw_TRANSFER_STATUS_ERROR:        DMA Transfer error
-*
-*/
-/****************************************************************************/
-dmacHw_TRANSFER_STATUS_e dmacHw_transferCompleted(dmacHw_HANDLE_t handle	/*   [ IN ] DMA Channel handle  */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Set descriptor carrying control information
-*
-*  This function will be used to send specific control information to the device
-*  using the DMA channel
-*
-*
-*  @return  -1 - On failure
-*            0 - On success
-*
-*  @note
-*     None
-*/
-/****************************************************************************/
-int dmacHw_setControlDescriptor(dmacHw_CONFIG_t *pConfig,	/*  [ IN ] Configuration settings */
-				void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
-				uint32_t ctlAddress,	/*  [ IN ] Address of the device control register  */
-				uint32_t control	/*  [ IN ] Device control information */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Read data DMA transferred to memory
-*
-*  This function will read data that has been DMAed to memory while transferring from:
-*          - Memory to memory
-*          - Peripheral to memory
-*
-*  @return  0 - No more data is available to read
-*           1 - More data might be available to read
-*
-*/
-/****************************************************************************/
-int dmacHw_readTransferredData(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle    */
-			       dmacHw_CONFIG_t *pConfig,	/*  [ IN ]  Configuration settings */
-			       void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
-			       void **ppBbuf,	/*  [ OUT ] Data received */
-			       size_t *pLlen	/*  [ OUT ] Length of the data received */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Prepares descriptor ring, when source peripheral working as a flow controller
-*
-*  This function will form the descriptor ring by allocating buffers, when source peripheral
-*  has to work as a flow controller to transfer data from:
-*           - Peripheral to memory.
-*
-*  @return  -1 - On failure
-*            0 - On success
-*
-*
-*  @note
-*     None
-*/
-/****************************************************************************/
-int dmacHw_setVariableDataDescriptor(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle   */
-				     dmacHw_CONFIG_t *pConfig,	/*  [ IN ] Configuration settings */
-				     void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
-				     uint32_t srcAddr,	/*  [ IN ] Source peripheral address */
-				     void *(*fpAlloc) (int len),	/*  [ IN ] Function pointer  that provides destination memory */
-				     int len,	/*  [ IN ] Number of bytes "fpAlloc" will allocate for destination */
-				     int num	/*  [ IN ] Number of descriptor to set */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Program channel register to initiate transfer
-*
-*  @return  void
-*
-*
-*  @note
-*     - Descriptor buffer MUST ALWAYS be flushed before calling this function
-*     - This function should also be called from ISR to program the channel with
-*       pending descriptors
-*/
-/****************************************************************************/
-void dmacHw_initiateTransfer(dmacHw_HANDLE_t handle,	/*   [ IN ] DMA Channel handle */
-			     dmacHw_CONFIG_t *pConfig,	/*   [ IN ] Configuration settings */
-			     void *pDescriptor	/*   [ IN ] Descriptor buffer  */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Resets descriptor control information
-*
-*  @return  void
-*/
-/****************************************************************************/
-void dmacHw_resetDescriptorControl(void *pDescriptor	/*   [ IN ] Descriptor buffer  */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Program channel register to stop transfer
-*
-*  Ensures the channel is not doing any transfer after calling this function
-*
-*  @return  void
-*
-*/
-/****************************************************************************/
-void dmacHw_stopTransfer(dmacHw_HANDLE_t handle	/*   [ IN ] DMA Channel handle */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Check the existence of pending descriptor
-*
-*  This function confirmes if there is any pending descriptor in the chain
-*  to program the channel
-*
-*  @return  1 : Channel need to be programmed with pending descriptor
-*           0 : No more pending descriptor to programe the channel
-*
-*  @note
-*     - This function should be called from ISR in case there are pending
-*       descriptor to program the channel.
-*
-*     Example:
-*
-*     dmac_isr ()
-*     {
-*         ...
-*         if (dmacHw_descriptorPending (handle))
-*         {
-*            dmacHw_initiateTransfer (handle);
-*         }
-*     }
-*
-*/
-/****************************************************************************/
-uint32_t dmacHw_descriptorPending(dmacHw_HANDLE_t handle,	/*   [ IN ] DMA Channel handle */
-				  void *pDescriptor	/*   [ IN ] Descriptor buffer */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Deallocates source or destination memory, allocated
-*
-*  This function can be called to deallocate data memory that was DMAed successfully
-*
-*  @return  -1  - On failure
-*            0  - On success
-*
-*  @note
-*     This function will be called ONLY, when source OR destination address is pointing
-*     to dynamic memory
-*/
-/****************************************************************************/
-int dmacHw_freeMem(dmacHw_CONFIG_t *pConfig,	/*  [ IN ] Configuration settings */
-		   void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
-		   void (*fpFree) (void *)	/*  [ IN ] Function pointer to free data memory */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Clears the interrupt
-*
-*  This function clears the DMA channel specific interrupt
-*
-*  @return   N/A
-*
-*  @note
-*     Must be called under the context of ISR
-*/
-/****************************************************************************/
-void dmacHw_clearInterrupt(dmacHw_HANDLE_t handle	/*  [ IN ] DMA Channel handle  */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Returns the cause of channel specific DMA interrupt
-*
-*  This function returns the cause of interrupt
-*
-*  @return  Interrupt status, each bit representing a specific type of interrupt
-*           of type dmacHw_INTERRUPT_STATUS_e
-*  @note
-*           This function should be called under the context of ISR
-*/
-/****************************************************************************/
-dmacHw_INTERRUPT_STATUS_e dmacHw_getInterruptStatus(dmacHw_HANDLE_t handle	/*  [ IN ] DMA Channel handle  */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Indentifies a DMA channel causing interrupt
-*
-*  This functions returns a channel causing interrupt of type dmacHw_INTERRUPT_STATUS_e
-*
-*  @return  NULL   : No channel causing DMA interrupt
-*           ! NULL : Handle to a channel causing DMA interrupt
-*  @note
-*     dmacHw_clearInterrupt() must be called with a valid handle after calling this function
-*/
-/****************************************************************************/
-dmacHw_HANDLE_t dmacHw_getInterruptSource(void);
-
-/****************************************************************************/
-/**
-*  @brief   Sets channel specific user data
-*
-*  This function associates user data to a specific DMA channel
-*
-*/
-/****************************************************************************/
-void dmacHw_setChannelUserData(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle  */
-			       void *userData	/*  [ IN ] User data  */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Gets channel specific user data
-*
-*  This function returns user data specific to a DMA channel
-*
-*  @return   user data
-*/
-/****************************************************************************/
-void *dmacHw_getChannelUserData(dmacHw_HANDLE_t handle	/*  [ IN ] DMA Channel handle  */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Displays channel specific registers and other control parameters
-*
-*
-*  @return  void
-*
-*  @note
-*     None
-*/
-/****************************************************************************/
-void dmacHw_printDebugInfo(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle  */
-			   void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
-			   int (*fpPrint) (const char *, ...)	/*  [ IN ] Print callback function */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Provides DMA controller attributes
-*
-*
-*  @return  DMA controller attributes
-*
-*  @note
-*     None
-*/
-/****************************************************************************/
-uint32_t dmacHw_getDmaControllerAttribute(dmacHw_HANDLE_t handle,	/*  [ IN ]  DMA Channel handle  */
-					  dmacHw_CONTROLLER_ATTRIB_e attr	/*  [ IN ]  DMA Controller attribute of type  dmacHw_CONTROLLER_ATTRIB_e */
-    );
-
-#endif /* _DMACHW_H */
diff --git a/arch/arm/mach-bcmring/include/csp/errno.h b/arch/arm/mach-bcmring/include/csp/errno.h
deleted file mode 100644
index 51357dd..0000000
--- a/arch/arm/mach-bcmring/include/csp/errno.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-#ifndef CSP_ERRNO_H
-#define CSP_ERRNO_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#if   defined(__KERNEL__)
-#include <linux/errno.h>
-#elif defined(CSP_SIMULATION)
-#include <asm-generic/errno.h>
-#else
-#include <errno.h>
-#endif
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-
-#endif /* CSP_ERRNO_H */
diff --git a/arch/arm/mach-bcmring/include/csp/intcHw.h b/arch/arm/mach-bcmring/include/csp/intcHw.h
deleted file mode 100644
index 1c639c8..0000000
--- a/arch/arm/mach-bcmring/include/csp/intcHw.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-
-/****************************************************************************/
-/**
-*  @file    intcHw.h
-*
-*  @brief   generic interrupt controller API
-*
-*  @note
-*     None
-*/
-/****************************************************************************/
-
-#ifndef _INTCHW_H
-#define _INTCHW_H
-
-/* ---- Include Files ---------------------------------------------------- */
-#include <mach/csp/intcHw_reg.h>
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-static inline void intcHw_irq_disable(void *basep, uint32_t mask);
-static inline void intcHw_irq_enable(void *basep, uint32_t mask);
-
-#endif /* _INTCHW_H */
-
diff --git a/arch/arm/mach-bcmring/include/csp/module.h b/arch/arm/mach-bcmring/include/csp/module.h
deleted file mode 100644
index c30d2a5..0000000
--- a/arch/arm/mach-bcmring/include/csp/module.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-
-#ifndef CSP_MODULE_H
-#define CSP_MODULE_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#ifdef __KERNEL__
-    #include <linux/module.h>
-#else
-    #define EXPORT_SYMBOL(symbol)
-#endif
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-
-
-#endif /* CSP_MODULE_H */
diff --git a/arch/arm/mach-bcmring/include/csp/reg.h b/arch/arm/mach-bcmring/include/csp/reg.h
deleted file mode 100644
index 56654d2..0000000
--- a/arch/arm/mach-bcmring/include/csp/reg.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-/****************************************************************************/
-/**
-*  @file    reg.h
-*
-*  @brief   Generic register definitions used in CSP
-*/
-/****************************************************************************/
-
-#ifndef CSP_REG_H
-#define CSP_REG_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#include <csp/stdint.h>
-
-/* ---- Public Constants and Types --------------------------------------- */
-
-#define __REG32(x)      (*((volatile uint32_t *)(x)))
-#define __REG16(x)      (*((volatile uint16_t *)(x)))
-#define __REG8(x)       (*((volatile uint8_t *) (x)))
-
-/* Macros used to define a sequence of reserved registers. The start / end */
-/* are byte offsets in the particular register definition, with the "end" */
-/* being the offset of the next un-reserved register. E.g. if offsets */
-/* 0x10 through to 0x1f are reserved, then this reserved area could be */
-/* specified as follows. */
-/*  typedef struct */
-/*  { */
-/*      uint32_t reg1;           offset 0x00 */
-/*      uint32_t reg2;           offset 0x04 */
-/*      uint32_t reg3;           offset 0x08 */
-/*      uint32_t reg4;           offset 0x0c */
-/*      REG32_RSVD(0x10, 0x20); */
-/*      uint32_t reg5;           offset 0x20 */
-/*      ... */
-/*  } EXAMPLE_REG_t; */
-#define REG8_RSVD(start, end)   uint8_t rsvd_##start[(end - start) / sizeof(uint8_t)]
-#define REG16_RSVD(start, end)  uint16_t rsvd_##start[(end - start) / sizeof(uint16_t)]
-#define REG32_RSVD(start, end)  uint32_t rsvd_##start[(end - start) / sizeof(uint32_t)]
-
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-
-/* Note: When protecting multiple statements, the REG_LOCAL_IRQ_SAVE and */
-/* REG_LOCAL_IRQ_RESTORE must be enclosed in { } to allow the  */
-/* flags variable to be declared locally. */
-/* e.g. */
-/*    statement1; */
-/*    { */
-/*       REG_LOCAL_IRQ_SAVE; */
-/*       <multiple statements here> */
-/*       REG_LOCAL_IRQ_RESTORE; */
-/*    } */
-/*    statement2; */
-/*  */
-
-#if defined(__KERNEL__) && !defined(STANDALONE)
-#include <mach/hardware.h>
-#include <linux/interrupt.h>
-
-#define REG_LOCAL_IRQ_SAVE      HW_DECLARE_SPINLOCK(reg32) \
-	unsigned long flags; HW_IRQ_SAVE(reg32, flags)
-
-#define REG_LOCAL_IRQ_RESTORE   HW_IRQ_RESTORE(reg32, flags)
-
-#else
-
-#define REG_LOCAL_IRQ_SAVE
-#define REG_LOCAL_IRQ_RESTORE
-
-#endif
-
-static inline void reg32_modify_and(volatile uint32_t *reg, uint32_t value)
-{
-	REG_LOCAL_IRQ_SAVE;
-	*reg &= value;
-	REG_LOCAL_IRQ_RESTORE;
-}
-
-static inline void reg32_modify_or(volatile uint32_t *reg, uint32_t value)
-{
-	REG_LOCAL_IRQ_SAVE;
-	*reg |= value;
-	REG_LOCAL_IRQ_RESTORE;
-}
-
-static inline void reg32_modify_mask(volatile uint32_t *reg, uint32_t mask,
-				     uint32_t value)
-{
-	REG_LOCAL_IRQ_SAVE;
-	*reg = (*reg & mask) | value;
-	REG_LOCAL_IRQ_RESTORE;
-}
-
-static inline void reg32_write(volatile uint32_t *reg, uint32_t value)
-{
-	*reg = value;
-}
-
-#endif /* CSP_REG_H */
diff --git a/arch/arm/mach-bcmring/include/csp/secHw.h b/arch/arm/mach-bcmring/include/csp/secHw.h
deleted file mode 100644
index b9d7e07..0000000
--- a/arch/arm/mach-bcmring/include/csp/secHw.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*****************************************************************************
-* Copyright 2004 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-/****************************************************************************/
-/**
-*  @file    secHw.h
-*
-*  @brief   Definitions for accessing low level security features
-*
-*/
-/****************************************************************************/
-#ifndef SECHW_H
-#define SECHW_H
-
-typedef void (*secHw_FUNC_t) (void);
-
-typedef enum {
-	secHw_MODE_SECURE = 0x0,	/* Switches processor into secure mode */
-	secHw_MODE_NONSECURE = 0x1	/* Switches processor into non-secure mode */
-} secHw_MODE;
-
-/****************************************************************************/
-/**
-*  @brief   Requesting to execute the function in secure mode
-*
-*  This function requests the given function to run in secure mode
-*
-*/
-/****************************************************************************/
-void secHw_RunSecure(secHw_FUNC_t	/* Function to run in secure mode */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Sets the  mode
-*
-*  his function sets the processor mode (secure/non-secure)
-*
-*/
-/****************************************************************************/
-void secHw_SetMode(secHw_MODE	/* Processor mode */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Get the current mode
-*
-*  This function retieves the processor mode (secure/non-secure)
-*
-*/
-/****************************************************************************/
-void secHw_GetMode(secHw_MODE *);
-
-#endif /* SECHW_H */
diff --git a/arch/arm/mach-bcmring/include/csp/stdint.h b/arch/arm/mach-bcmring/include/csp/stdint.h
deleted file mode 100644
index 3a8718b..0000000
--- a/arch/arm/mach-bcmring/include/csp/stdint.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-#ifndef CSP_STDINT_H
-#define CSP_STDINT_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#ifdef __KERNEL__
-#include <linux/types.h>
-#else
-#include <stdint.h>
-#endif
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-
-#endif /* CSP_STDINT_H */
diff --git a/arch/arm/mach-bcmring/include/csp/string.h b/arch/arm/mach-bcmring/include/csp/string.h
deleted file mode 100644
index ad9e400..0000000
--- a/arch/arm/mach-bcmring/include/csp/string.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-
-
-#ifndef CSP_STRING_H
-#define CSP_STRING_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#ifdef __KERNEL__
-   #include <linux/string.h>
-#else
-   #include <string.h>
-#endif
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-
-
-#endif /* CSP_STRING_H */
-
diff --git a/arch/arm/mach-bcmring/include/csp/tmrHw.h b/arch/arm/mach-bcmring/include/csp/tmrHw.h
deleted file mode 100644
index 2cbb530..0000000
--- a/arch/arm/mach-bcmring/include/csp/tmrHw.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/*****************************************************************************
-* Copyright 2004 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-/****************************************************************************/
-/**
-*  @file    tmrHw.h
-*
-*  @brief   API definitions for low level Timer driver
-*
-*/
-/****************************************************************************/
-#ifndef _TMRHW_H
-#define _TMRHW_H
-
-#include <csp/stdint.h>
-
-typedef uint32_t tmrHw_ID_t;	/* Timer ID */
-typedef uint32_t tmrHw_COUNT_t;	/* Timer count */
-typedef uint32_t tmrHw_INTERVAL_t;	/* Timer interval */
-typedef uint32_t tmrHw_RATE_t;	/* Timer event (count/interrupt) rate */
-
-typedef enum {
-	tmrHw_INTERRUPT_STATUS_SET,	/* Interrupted  */
-	tmrHw_INTERRUPT_STATUS_UNSET	/* No Interrupt */
-} tmrHw_INTERRUPT_STATUS_e;
-
-typedef enum {
-	tmrHw_CAPABILITY_CLOCK,	/* Clock speed in HHz */
-	tmrHw_CAPABILITY_RESOLUTION	/* Timer resolution in bits */
-} tmrHw_CAPABILITY_e;
-
-/****************************************************************************/
-/**
-*  @brief   Get timer capability
-*
-*  This function returns various capabilities/attributes of a timer
-*
-*  @return  Numeric capability
-*
-*/
-/****************************************************************************/
-uint32_t tmrHw_getTimerCapability(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
-				  tmrHw_CAPABILITY_e capability	/*  [ IN ] Timer capability */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Configures a periodic timer in terms of timer interrupt rate
-*
-*  This function initializes a periodic timer to generate specific number of
-*  timer interrupt per second
-*
-*  @return   On success: Effective timer frequency
-*            On failure: 0
-*
-*/
-/****************************************************************************/
-tmrHw_RATE_t tmrHw_setPeriodicTimerRate(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
-					tmrHw_RATE_t rate	/*  [ IN ] Number of timer interrupt per second */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Configures a periodic timer to generate timer interrupt after
-*           certain time interval
-*
-*  This function initializes a periodic timer to generate timer interrupt
-*  after every time interval in millisecond
-*
-*  @return   On success: Effective interval set in mili-second
-*            On failure: 0
-*
-*/
-/****************************************************************************/
-tmrHw_INTERVAL_t tmrHw_setPeriodicTimerInterval(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
-						tmrHw_INTERVAL_t msec	/*  [ IN ] Interval in mili-second */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Configures a periodic timer to generate timer interrupt just once
-*           after certain time interval
-*
-*  This function initializes a periodic timer to generate a single ticks after
-*  certain time interval in millisecond
-*
-*  @return   On success: Effective interval set in mili-second
-*            On failure: 0
-*
-*/
-/****************************************************************************/
-tmrHw_INTERVAL_t tmrHw_setOneshotTimerInterval(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
-					       tmrHw_INTERVAL_t msec	/*  [ IN ] Interval in mili-second */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Configures a timer to run as a free running timer
-*
-*  This function initializes a timer to run as a free running timer
-*
-*  @return   Timer resolution (count / sec)
-*
-*/
-/****************************************************************************/
-tmrHw_RATE_t tmrHw_setFreeRunningTimer(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
-				       uint32_t divider	/*  [ IN ] Dividing the clock frequency */
-) __attribute__ ((section(".aramtext")));
-
-/****************************************************************************/
-/**
-*  @brief   Starts a timer
-*
-*  This function starts a preconfigured timer
-*
-*  @return  -1     - On Failure
-*            0     - On Success
-*/
-/****************************************************************************/
-int tmrHw_startTimer(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
-) __attribute__ ((section(".aramtext")));
-
-/****************************************************************************/
-/**
-*  @brief   Stops a timer
-*
-*  This function stops a running timer
-*
-*  @return  -1     - On Failure
-*            0     - On Success
-*/
-/****************************************************************************/
-int tmrHw_stopTimer(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Gets current timer count
-*
-*  This function returns the current timer value
-*
-*  @return  Current downcounting timer value
-*
-*/
-/****************************************************************************/
-tmrHw_COUNT_t tmrHw_GetCurrentCount(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
-) __attribute__ ((section(".aramtext")));
-
-/****************************************************************************/
-/**
-*  @brief   Gets timer count rate
-*
-*  This function returns the number of counts per second
-*
-*  @return  Count rate
-*
-*/
-/****************************************************************************/
-tmrHw_RATE_t tmrHw_getCountRate(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
-) __attribute__ ((section(".aramtext")));
-
-/****************************************************************************/
-/**
-*  @brief   Enables timer interrupt
-*
-*  This function enables the timer interrupt
-*
-*  @return   N/A
-*
-*/
-/****************************************************************************/
-void tmrHw_enableInterrupt(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Disables timer interrupt
-*
-*  This function disable the timer interrupt
-*
-*  @return   N/A
-*/
-/****************************************************************************/
-void tmrHw_disableInterrupt(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Clears the interrupt
-*
-*  This function clears the timer interrupt
-*
-*  @return   N/A
-*
-*  @note
-*     Must be called under the context of ISR
-*/
-/****************************************************************************/
-void tmrHw_clearInterrupt(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Gets the interrupt status
-*
-*  This function returns timer interrupt status
-*
-*  @return   Interrupt status
-*/
-/****************************************************************************/
-tmrHw_INTERRUPT_STATUS_e tmrHw_getInterruptStatus(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Indentifies a timer causing interrupt
-*
-*  This functions returns a timer causing interrupt
-*
-*  @return  0xFFFFFFFF   : No timer causing an interrupt
-*           ! 0xFFFFFFFF : timer causing an interrupt
-*  @note
-*     tmrHw_clearIntrrupt() must be called with a valid timer id after calling this function
-*/
-/****************************************************************************/
-tmrHw_ID_t tmrHw_getInterruptSource(void);
-
-/****************************************************************************/
-/**
-*  @brief   Displays specific timer registers
-*
-*
-*  @return  void
-*
-*/
-/****************************************************************************/
-void tmrHw_printDebugInfo(tmrHw_ID_t timerId,	/*  [ IN ] Timer id */
-			  int (*fpPrint) (const char *, ...)	/*  [ IN ] Print callback function */
-);
-
-/****************************************************************************/
-/**
-*  @brief   Use a timer to perform a busy wait delay for a number of usecs.
-*
-*  @return   N/A
-*/
-/****************************************************************************/
-void tmrHw_udelay(tmrHw_ID_t timerId,	/*  [ IN ] Timer id */
-		  unsigned long usecs	/*  [ IN ] usec to delay */
-) __attribute__ ((section(".aramtext")));
-
-#endif /* _TMRHW_H */
diff --git a/arch/arm/mach-bcmring/include/mach/cfg_global.h b/arch/arm/mach-bcmring/include/mach/cfg_global.h
new file mode 100644
index 0000000..449133e
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/cfg_global.h
@@ -0,0 +1,51 @@
+/*****************************************************************************
+* Copyright 2006 - 2008 Broadcom Corporation.  All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+#ifndef CFG_GLOBAL_DEFINES_H
+#define CFG_GLOBAL_DEFINES_H
+
+/* CHIP */
+#define BCM1103 1
+
+#define BCM1191 4
+#define BCM2153 5
+#define BCM2820 6
+
+#define BCM2826 8
+#define FPGA11107 9
+#define BCM11107   10
+#define BCM11109   11
+#define BCM11170   12
+#define BCM11110   13
+#define BCM11211   14
+
+/* CFG_GLOBAL_CHIP_FAMILY types */
+#define CFG_GLOBAL_CHIP_FAMILY_NONE        0
+#define CFG_GLOBAL_CHIP_FAMILY_BCM116X     2
+#define CFG_GLOBAL_CHIP_FAMILY_BCMRING     4
+#define CFG_GLOBAL_CHIP_FAMILY_BCM1103     8
+
+#define IMAGE_HEADER_SIZE_CHECKSUM    4
+#endif
+#ifndef _CFG_GLOBAL_H_
+#define _CFG_GLOBAL_H_
+
+#define CFG_GLOBAL_CHIP                         BCM11107
+#define CFG_GLOBAL_CHIP_FAMILY                  CFG_GLOBAL_CHIP_FAMILY_BCMRING
+#define CFG_GLOBAL_CHIP_REV                     0xB0
+#define CFG_GLOBAL_RAM_SIZE                     0x10000000
+#define CFG_GLOBAL_RAM_BASE                     0x00000000
+#define CFG_GLOBAL_RAM_RESERVED_SIZE            0x000000
+
+#endif /* _CFG_GLOBAL_H_ */
diff --git a/arch/arm/mach-bcmring/include/mach/csp/cap_inline.h b/arch/arm/mach-bcmring/include/mach/csp/cap_inline.h
index 933ce68..0a89e0c 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/cap_inline.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/cap_inline.h
@@ -17,7 +17,7 @@
 
 /* ---- Include Files ---------------------------------------------------- */
 #include <mach/csp/cap.h>
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 
 /* ---- Public Constants and Types --------------------------------------- */
 #define CAP_CONFIG0_VPM_DIS          0x00000001
diff --git a/arch/arm/mach-bcmring/include/mach/csp/chipcHw_def.h b/arch/arm/mach-bcmring/include/mach/csp/chipcHw_def.h
index 1619733..39f09cb 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/chipcHw_def.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/chipcHw_def.h
@@ -17,9 +17,9 @@
 
 /* ---- Include Files ----------------------------------------------------- */
 
-#include <csp/stdint.h>
-#include <csp/errno.h>
-#include <csp/reg.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <mach/csp/reg.h>
 #include <mach/csp/chipcHw_reg.h>
 
 /* ---- Public Constants and Types ---------------------------------------- */
diff --git a/arch/arm/mach-bcmring/include/mach/csp/chipcHw_inline.h b/arch/arm/mach-bcmring/include/mach/csp/chipcHw_inline.h
index 03238c2..a66f3f7 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/chipcHw_inline.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/chipcHw_inline.h
@@ -17,8 +17,8 @@
 
 /* ---- Include Files ----------------------------------------------------- */
 
-#include <csp/errno.h>
-#include <csp/reg.h>
+#include <linux/errno.h>
+#include <mach/csp/reg.h>
 #include <mach/csp/chipcHw_reg.h>
 #include <mach/csp/chipcHw_def.h>
 
@@ -47,7 +47,7 @@ static inline void chipcHw_setClock(chipcHw_CLOCK_e clock,
 /****************************************************************************/
 static inline uint32_t chipcHw_getChipId(void)
 {
-	return pChipcHw->ChipId;
+	return readl(&pChipcHw->ChipId);
 }
 
 /****************************************************************************/
@@ -59,15 +59,16 @@ static inline uint32_t chipcHw_getChipId(void)
 /****************************************************************************/
 static inline void chipcHw_enableSpreadSpectrum(void)
 {
-	if ((pChipcHw->
-	     PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) !=
+	if ((readl(&pChipcHw->
+	     PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) !=
 	    chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
-		ddrcReg_PHY_ADDR_CTL_REGP->ssCfg =
-		    (0xFFFF << ddrcReg_PHY_ADDR_SS_CFG_NDIV_AMPLITUDE_SHIFT) |
+		writel((0xFFFF << ddrcReg_PHY_ADDR_SS_CFG_NDIV_AMPLITUDE_SHIFT) |
 		    (ddrcReg_PHY_ADDR_SS_CFG_MIN_CYCLE_PER_TICK <<
-		     ddrcReg_PHY_ADDR_SS_CFG_CYCLE_PER_TICK_SHIFT);
-		ddrcReg_PHY_ADDR_CTL_REGP->ssCtl |=
-		    ddrcReg_PHY_ADDR_SS_CTRL_ENABLE;
+		     ddrcReg_PHY_ADDR_SS_CFG_CYCLE_PER_TICK_SHIFT),
+		     &ddrcReg_PHY_ADDR_CTL_REGP->ssCfg);
+		writel(readl(&ddrcReg_PHY_ADDR_CTL_REGP->ssCtl) |
+		    ddrcReg_PHY_ADDR_SS_CTRL_ENABLE,
+		    &ddrcReg_PHY_ADDR_CTL_REGP->ssCtl);
 	}
 }
 
@@ -93,8 +94,8 @@ static inline void chipcHw_disableSpreadSpectrum(void)
 /****************************************************************************/
 static inline uint32_t chipcHw_getChipProductId(void)
 {
-	return (pChipcHw->
-		 ChipId & chipcHw_REG_CHIPID_BASE_MASK) >>
+	return (readl(&pChipcHw->
+		 ChipId) & chipcHw_REG_CHIPID_BASE_MASK) >>
 		chipcHw_REG_CHIPID_BASE_SHIFT;
 }
 
@@ -109,7 +110,7 @@ static inline uint32_t chipcHw_getChipProductId(void)
 /****************************************************************************/
 static inline chipcHw_REV_NUMBER_e chipcHw_getChipRevisionNumber(void)
 {
-	return pChipcHw->ChipId & chipcHw_REG_CHIPID_REV_MASK;
+	return readl(&pChipcHw->ChipId) & chipcHw_REG_CHIPID_REV_MASK;
 }
 
 /****************************************************************************/
@@ -156,7 +157,7 @@ static inline void chipcHw_busInterfaceClockDisable(uint32_t mask)
 /****************************************************************************/
 static inline uint32_t chipcHw_getBusInterfaceClockStatus(void)
 {
-	return pChipcHw->BusIntfClock;
+	return readl(&pChipcHw->BusIntfClock);
 }
 
 /****************************************************************************/
@@ -215,8 +216,9 @@ static inline void chipcHw_softResetDisable(uint64_t mask)
 
 	/* Deassert module soft reset */
 	REG_LOCAL_IRQ_SAVE;
-	pChipcHw->SoftReset1 ^= ctrl1;
-	pChipcHw->SoftReset2 ^= (ctrl2 & (~chipcHw_REG_SOFT_RESET_UNHOLD_MASK));
+	writel(readl(&pChipcHw->SoftReset1) ^ ctrl1, &pChipcHw->SoftReset1);
+	writel(readl(&pChipcHw->SoftReset2) ^ (ctrl2 &
+		(~chipcHw_REG_SOFT_RESET_UNHOLD_MASK)), &pChipcHw->SoftReset2);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -227,9 +229,10 @@ static inline void chipcHw_softResetEnable(uint64_t mask)
 	uint32_t unhold = 0;
 
 	REG_LOCAL_IRQ_SAVE;
-	pChipcHw->SoftReset1 |= ctrl1;
+	writel(readl(&pChipcHw->SoftReset1) | ctrl1, &pChipcHw->SoftReset1);
 	/* Mask out unhold request bits */
-	pChipcHw->SoftReset2 |= (ctrl2 & (~chipcHw_REG_SOFT_RESET_UNHOLD_MASK));
+	writel(readl(&pChipcHw->SoftReset2) | (ctrl2 &
+		(~chipcHw_REG_SOFT_RESET_UNHOLD_MASK)), &pChipcHw->SoftReset2);
 
 	/* Process unhold requests */
 	if (ctrl2 & chipcHw_REG_SOFT_RESET_VPM_GLOBAL_UNHOLD) {
@@ -246,7 +249,7 @@ static inline void chipcHw_softResetEnable(uint64_t mask)
 
 	if (unhold) {
 		/* Make sure unhold request is effective */
-		pChipcHw->SoftReset1 &= ~unhold;
+		writel(readl(&pChipcHw->SoftReset1) & ~unhold, &pChipcHw->SoftReset1);
 	}
 	REG_LOCAL_IRQ_RESTORE;
 }
@@ -307,7 +310,7 @@ static inline void chipcHw_setOTPOption(uint64_t mask)
 /****************************************************************************/
 static inline uint32_t chipcHw_getStickyBits(void)
 {
-	return pChipcHw->Sticky;
+	return readl(&pChipcHw->Sticky);
 }
 
 /****************************************************************************/
@@ -328,7 +331,7 @@ static inline void chipcHw_setStickyBits(uint32_t mask)
 		bits |= chipcHw_REG_STICKY_POR_BROM;
 	} else {
 		uint32_t sticky;
-		sticky = pChipcHw->Sticky;
+		sticky = readl(pChipcHw->Sticky);
 
 		if ((mask & chipcHw_REG_STICKY_BOOT_DONE)
 		    && (sticky & chipcHw_REG_STICKY_BOOT_DONE) == 0) {
@@ -355,7 +358,7 @@ static inline void chipcHw_setStickyBits(uint32_t mask)
 			bits |= chipcHw_REG_STICKY_GENERAL_5;
 		}
 	}
-	pChipcHw->Sticky = bits;
+	writel(bits, pChipcHw->Sticky);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -377,7 +380,7 @@ static inline void chipcHw_clearStickyBits(uint32_t mask)
 	    (chipcHw_REG_STICKY_BOOT_DONE | chipcHw_REG_STICKY_GENERAL_1 |
 	     chipcHw_REG_STICKY_GENERAL_2 | chipcHw_REG_STICKY_GENERAL_3 |
 	     chipcHw_REG_STICKY_GENERAL_4 | chipcHw_REG_STICKY_GENERAL_5)) {
-		uint32_t sticky = pChipcHw->Sticky;
+		uint32_t sticky = readl(&pChipcHw->Sticky);
 
 		if ((mask & chipcHw_REG_STICKY_BOOT_DONE)
 		    && (sticky & chipcHw_REG_STICKY_BOOT_DONE)) {
@@ -410,7 +413,7 @@ static inline void chipcHw_clearStickyBits(uint32_t mask)
 			mask &= ~chipcHw_REG_STICKY_GENERAL_5;
 		}
 	}
-	pChipcHw->Sticky = bits | mask;
+	writel(bits | mask, &pChipcHw->Sticky);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -426,7 +429,7 @@ static inline void chipcHw_clearStickyBits(uint32_t mask)
 /****************************************************************************/
 static inline uint32_t chipcHw_getSoftStraps(void)
 {
-	return pChipcHw->SoftStraps;
+	return readl(&pChipcHw->SoftStraps);
 }
 
 /****************************************************************************/
@@ -456,7 +459,7 @@ static inline void chipcHw_setSoftStraps(uint32_t strapOptions)
 /****************************************************************************/
 static inline uint32_t chipcHw_getPinStraps(void)
 {
-	return pChipcHw->PinStraps;
+	return readl(&pChipcHw->PinStraps);
 }
 
 /****************************************************************************/
@@ -671,9 +674,9 @@ static inline void chipcHw_selectGE3(void)
 /****************************************************************************/
 static inline chipcHw_GPIO_FUNCTION_e chipcHw_getGpioPinFunction(int pin)
 {
-	return (*((uint32_t *) chipcHw_REG_GPIO_MUX(pin)) &
+	return (readl(chipcHw_REG_GPIO_MUX(pin))) &
 		(chipcHw_REG_GPIO_MUX_MASK <<
-		 chipcHw_REG_GPIO_MUX_POSITION(pin))) >>
+		 chipcHw_REG_GPIO_MUX_POSITION(pin)) >>
 	    chipcHw_REG_GPIO_MUX_POSITION(pin);
 }
 
@@ -841,8 +844,8 @@ static inline void chipcHw_setUsbDevice(void)
 static inline void chipcHw_setClock(chipcHw_CLOCK_e clock,
 				    chipcHw_OPTYPE_e type, int mode)
 {
-	volatile uint32_t *pPLLReg = (uint32_t *) 0x0;
-	volatile uint32_t *pClockCtrl = (uint32_t *) 0x0;
+	uint32_t __iomem *pPLLReg = NULL;
+	uint32_t __iomem *pClockCtrl = NULL;
 
 	switch (clock) {
 	case chipcHw_CLOCK_DDR:
@@ -1071,7 +1074,7 @@ static inline void chipcHw_bypassClockDisable(chipcHw_CLOCK_e clock)
 /****************************************************************************/
 static inline int chipcHw_isSoftwareStrapsEnable(void)
 {
-	return pChipcHw->SoftStraps & 0x00000001;
+	return readl(&pChipcHw->SoftStraps) & 0x00000001;
 }
 
 /****************************************************************************/
@@ -1138,7 +1141,7 @@ static inline void chipcHw_pll2TestDisable(void)
 /****************************************************************************/
 static inline int chipcHw_isPllTestEnable(void)
 {
-	return pChipcHw->PLLConfig & chipcHw_REG_PLL_CONFIG_TEST_ENABLE;
+	return readl(&pChipcHw->PLLConfig) & chipcHw_REG_PLL_CONFIG_TEST_ENABLE;
 }
 
 /****************************************************************************/
@@ -1147,7 +1150,7 @@ static inline int chipcHw_isPllTestEnable(void)
 /****************************************************************************/
 static inline int chipcHw_isPll2TestEnable(void)
 {
-	return pChipcHw->PLLConfig2 & chipcHw_REG_PLL_CONFIG_TEST_ENABLE;
+	return readl(&pChipcHw->PLLConfig2) & chipcHw_REG_PLL_CONFIG_TEST_ENABLE;
 }
 
 /****************************************************************************/
@@ -1183,8 +1186,8 @@ static inline void chipcHw_pll2TestSelect(uint32_t val)
 /****************************************************************************/
 static inline uint8_t chipcHw_getPllTestSelected(void)
 {
-	return (uint8_t) ((pChipcHw->
-			   PLLConfig & chipcHw_REG_PLL_CONFIG_TEST_SELECT_MASK)
+	return (uint8_t) ((readl(&pChipcHw->
+			   PLLConfig) & chipcHw_REG_PLL_CONFIG_TEST_SELECT_MASK)
 			  >> chipcHw_REG_PLL_CONFIG_TEST_SELECT_SHIFT);
 }
 
@@ -1194,8 +1197,8 @@ static inline uint8_t chipcHw_getPllTestSelected(void)
 /****************************************************************************/
 static inline uint8_t chipcHw_getPll2TestSelected(void)
 {
-	return (uint8_t) ((pChipcHw->
-			   PLLConfig2 & chipcHw_REG_PLL_CONFIG_TEST_SELECT_MASK)
+	return (uint8_t) ((readl(&pChipcHw->
+			   PLLConfig2) & chipcHw_REG_PLL_CONFIG_TEST_SELECT_MASK)
 			  >> chipcHw_REG_PLL_CONFIG_TEST_SELECT_SHIFT);
 }
 
@@ -1208,7 +1211,8 @@ static inline uint8_t chipcHw_getPll2TestSelected(void)
 static inline void chipcHw_pll1Disable(void)
 {
 	REG_LOCAL_IRQ_SAVE;
-	pChipcHw->PLLConfig |= chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+	writel(readl(&pChipcHw->PLLConfig) | chipcHw_REG_PLL_CONFIG_POWER_DOWN,
+		&pChipcHw->PLLConfig);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1221,7 +1225,8 @@ static inline void chipcHw_pll1Disable(void)
 static inline void chipcHw_pll2Disable(void)
 {
 	REG_LOCAL_IRQ_SAVE;
-	pChipcHw->PLLConfig2 |= chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+	writel(readl(&pChipcHw->PLLConfig2) | chipcHw_REG_PLL_CONFIG_POWER_DOWN,
+		&pChipcHw->PLLConfig2);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1233,7 +1238,8 @@ static inline void chipcHw_pll2Disable(void)
 static inline void chipcHw_ddrPhaseAlignInterruptEnable(void)
 {
 	REG_LOCAL_IRQ_SAVE;
-	pChipcHw->Spare1 |= chipcHw_REG_SPARE1_DDR_PHASE_INTR_ENABLE;
+	writel(readl(&pChipcHw->Spare1) | chipcHw_REG_SPARE1_DDR_PHASE_INTR_ENABLE,
+		&pChipcHw->Spare1);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1245,7 +1251,8 @@ static inline void chipcHw_ddrPhaseAlignInterruptEnable(void)
 static inline void chipcHw_ddrPhaseAlignInterruptDisable(void)
 {
 	REG_LOCAL_IRQ_SAVE;
-	pChipcHw->Spare1 &= ~chipcHw_REG_SPARE1_DDR_PHASE_INTR_ENABLE;
+	writel(readl(&pChipcHw->Spare1) & ~chipcHw_REG_SPARE1_DDR_PHASE_INTR_ENABLE,
+		&pChipcHw->Spare1);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1333,7 +1340,8 @@ static inline void chipcHw_ddrHwPhaseAlignDisable(void)
 static inline void chipcHw_vpmSwPhaseAlignEnable(void)
 {
 	REG_LOCAL_IRQ_SAVE;
-	pChipcHw->VPMPhaseCtrl1 |= chipcHw_REG_VPM_SW_PHASE_CTRL_ENABLE;
+	writel(readl(&pChipcHw->VPMPhaseCtrl1) | chipcHw_REG_VPM_SW_PHASE_CTRL_ENABLE,
+			&pChipcHw->VPMPhaseCtrl1);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1372,7 +1380,8 @@ static inline void chipcHw_vpmHwPhaseAlignEnable(void)
 static inline void chipcHw_vpmHwPhaseAlignDisable(void)
 {
 	REG_LOCAL_IRQ_SAVE;
-	pChipcHw->VPMPhaseCtrl1 &= ~chipcHw_REG_VPM_HW_PHASE_CTRL_ENABLE;
+	writel(readl(&pChipcHw->VPMPhaseCtrl1) & ~chipcHw_REG_VPM_HW_PHASE_CTRL_ENABLE,
+		&pChipcHw->VPMPhaseCtrl1);
 	REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1474,8 +1483,8 @@ chipcHw_setVpmHwPhaseAlignMargin(chipcHw_VPM_HW_PHASE_MARGIN_e margin)
 /****************************************************************************/
 static inline uint32_t chipcHw_isDdrHwPhaseAligned(void)
 {
-	return (pChipcHw->
-		PhaseAlignStatus & chipcHw_REG_DDR_PHASE_ALIGNED) ? 1 : 0;
+	return (readl(&pChipcHw->
+		PhaseAlignStatus) & chipcHw_REG_DDR_PHASE_ALIGNED) ? 1 : 0;
 }
 
 /****************************************************************************/
@@ -1488,8 +1497,8 @@ static inline uint32_t chipcHw_isDdrHwPhaseAligned(void)
 /****************************************************************************/
 static inline uint32_t chipcHw_isVpmHwPhaseAligned(void)
 {
-	return (pChipcHw->
-		PhaseAlignStatus & chipcHw_REG_VPM_PHASE_ALIGNED) ? 1 : 0;
+	return (readl(&pChipcHw->
+		PhaseAlignStatus) & chipcHw_REG_VPM_PHASE_ALIGNED) ? 1 : 0;
 }
 
 /****************************************************************************/
@@ -1500,8 +1509,8 @@ static inline uint32_t chipcHw_isVpmHwPhaseAligned(void)
 /****************************************************************************/
 static inline uint32_t chipcHw_getDdrHwPhaseAlignStatus(void)
 {
-	return (pChipcHw->
-		PhaseAlignStatus & chipcHw_REG_DDR_PHASE_STATUS_MASK) >>
+	return (readl(&pChipcHw->
+		PhaseAlignStatus) & chipcHw_REG_DDR_PHASE_STATUS_MASK) >>
 	    chipcHw_REG_DDR_PHASE_STATUS_SHIFT;
 }
 
@@ -1513,8 +1522,8 @@ static inline uint32_t chipcHw_getDdrHwPhaseAlignStatus(void)
 /****************************************************************************/
 static inline uint32_t chipcHw_getVpmHwPhaseAlignStatus(void)
 {
-	return (pChipcHw->
-		PhaseAlignStatus & chipcHw_REG_VPM_PHASE_STATUS_MASK) >>
+	return (readl(&pChipcHw->
+		PhaseAlignStatus) & chipcHw_REG_VPM_PHASE_STATUS_MASK) >>
 	    chipcHw_REG_VPM_PHASE_STATUS_SHIFT;
 }
 
@@ -1526,8 +1535,8 @@ static inline uint32_t chipcHw_getVpmHwPhaseAlignStatus(void)
 /****************************************************************************/
 static inline uint32_t chipcHw_getDdrPhaseControl(void)
 {
-	return (pChipcHw->
-		PhaseAlignStatus & chipcHw_REG_DDR_PHASE_CTRL_MASK) >>
+	return (readl(&pChipcHw->
+		PhaseAlignStatus) & chipcHw_REG_DDR_PHASE_CTRL_MASK) >>
 	    chipcHw_REG_DDR_PHASE_CTRL_SHIFT;
 }
 
@@ -1539,8 +1548,8 @@ static inline uint32_t chipcHw_getDdrPhaseControl(void)
 /****************************************************************************/
 static inline uint32_t chipcHw_getVpmPhaseControl(void)
 {
-	return (pChipcHw->
-		PhaseAlignStatus & chipcHw_REG_VPM_PHASE_CTRL_MASK) >>
+	return (readl(&pChipcHw->
+		PhaseAlignStatus) & chipcHw_REG_VPM_PHASE_CTRL_MASK) >>
 	    chipcHw_REG_VPM_PHASE_CTRL_SHIFT;
 }
 
diff --git a/arch/arm/mach-bcmring/include/mach/csp/chipcHw_reg.h b/arch/arm/mach-bcmring/include/mach/csp/chipcHw_reg.h
index b162448..26f5d0e 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/chipcHw_reg.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/chipcHw_reg.h
@@ -24,7 +24,7 @@
 #define CHIPCHW_REG_H
 
 #include <mach/csp/mm_io.h>
-#include <csp/reg.h>
+#include <mach/csp/reg.h>
 #include <mach/csp/ddrcReg.h>
 
 #define chipcHw_BASE_ADDRESS    MM_IO_BASE_CHIPC
@@ -131,8 +131,8 @@ typedef struct {
 	uint32_t MiscInput_0_15;	/* Input type for MISC 0 - 16 */
 } chipcHw_REG_t;
 
-#define pChipcHw  ((volatile chipcHw_REG_t *) chipcHw_BASE_ADDRESS)
-#define pChipcPhysical  ((volatile chipcHw_REG_t *) MM_ADDR_IO_CHIPC)
+#define pChipcHw  ((chipcHw_REG_t __iomem *) chipcHw_BASE_ADDRESS)
+#define pChipcPhysical  (MM_ADDR_IO_CHIPC)
 
 #define chipcHw_REG_CHIPID_BASE_MASK                    0xFFFFF000
 #define chipcHw_REG_CHIPID_BASE_SHIFT                   12
diff --git a/arch/arm/mach-bcmring/include/mach/csp/ddrcReg.h b/arch/arm/mach-bcmring/include/mach/csp/ddrcReg.h
index f1b68e2..39da2c1 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/ddrcReg.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/ddrcReg.h
@@ -30,8 +30,8 @@ extern "C" {
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <csp/reg.h>
-#include <csp/stdint.h>
+#include <mach/csp/reg.h>
+#include <linux/types.h>
 
 #include <mach/csp/mm_io.h>
 
@@ -416,7 +416,7 @@ extern "C" {
 	} ddrcReg_PHY_ADDR_CTL_REG_t;
 
 #define ddrcReg_PHY_ADDR_CTL_REG_OFFSET                 0x0400
-#define ddrcReg_PHY_ADDR_CTL_REGP                       ((volatile ddrcReg_PHY_ADDR_CTL_REG_t *) (MM_IO_BASE_DDRC + ddrcReg_PHY_ADDR_CTL_REG_OFFSET))
+#define ddrcReg_PHY_ADDR_CTL_REGP                       ((volatile ddrcReg_PHY_ADDR_CTL_REG_t __iomem*) (MM_IO_BASE_DDRC + ddrcReg_PHY_ADDR_CTL_REG_OFFSET))
 
 /* @todo These SS definitions are duplicates of ones below */
 
diff --git a/arch/arm/mach-bcmring/include/mach/csp/dmacHw.h b/arch/arm/mach-bcmring/include/mach/csp/dmacHw.h
new file mode 100644
index 0000000..9dc90f4
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/csp/dmacHw.h
@@ -0,0 +1,596 @@
+/*****************************************************************************
+* Copyright 2004 - 2008 Broadcom Corporation.  All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+/****************************************************************************/
+/**
+*  @file    dmacHw.h
+*
+*  @brief   API definitions for low level DMA controller driver
+*
+*/
+/****************************************************************************/
+#ifndef _DMACHW_H
+#define _DMACHW_H
+
+#include <linux/stddef.h>
+
+#include <linux/types.h>
+#include <mach/csp/dmacHw_reg.h>
+
+/* Define DMA Channel ID using DMA controller number (m) and channel number (c).
+
+   System specific channel ID should be defined as follows
+
+   For example:
+
+   #include <dmacHw.h>
+   ...
+   #define systemHw_LCD_CHANNEL_ID                dmacHw_MAKE_CHANNEL_ID(0,5)
+   #define systemHw_SWITCH_RX_CHANNEL_ID          dmacHw_MAKE_CHANNEL_ID(0,0)
+   #define systemHw_SWITCH_TX_CHANNEL_ID          dmacHw_MAKE_CHANNEL_ID(0,1)
+   #define systemHw_APM_RX_CHANNEL_ID             dmacHw_MAKE_CHANNEL_ID(0,3)
+   #define systemHw_APM_TX_CHANNEL_ID             dmacHw_MAKE_CHANNEL_ID(0,4)
+   ...
+   #define systemHw_SHARED1_CHANNEL_ID            dmacHw_MAKE_CHANNEL_ID(1,4)
+   #define systemHw_SHARED2_CHANNEL_ID            dmacHw_MAKE_CHANNEL_ID(1,5)
+   #define systemHw_SHARED3_CHANNEL_ID            dmacHw_MAKE_CHANNEL_ID(0,6)
+   ...
+*/
+#define dmacHw_MAKE_CHANNEL_ID(m, c)         (m << 8 | c)
+
+typedef enum {
+	dmacHw_CHANNEL_PRIORITY_0 = dmacHw_REG_CFG_LO_CH_PRIORITY_0,	/* Channel priority 0. Lowest priority DMA channel */
+	dmacHw_CHANNEL_PRIORITY_1 = dmacHw_REG_CFG_LO_CH_PRIORITY_1,	/* Channel priority 1 */
+	dmacHw_CHANNEL_PRIORITY_2 = dmacHw_REG_CFG_LO_CH_PRIORITY_2,	/* Channel priority 2 */
+	dmacHw_CHANNEL_PRIORITY_3 = dmacHw_REG_CFG_LO_CH_PRIORITY_3,	/* Channel priority 3 */
+	dmacHw_CHANNEL_PRIORITY_4 = dmacHw_REG_CFG_LO_CH_PRIORITY_4,	/* Channel priority 4 */
+	dmacHw_CHANNEL_PRIORITY_5 = dmacHw_REG_CFG_LO_CH_PRIORITY_5,	/* Channel priority 5 */
+	dmacHw_CHANNEL_PRIORITY_6 = dmacHw_REG_CFG_LO_CH_PRIORITY_6,	/* Channel priority 6 */
+	dmacHw_CHANNEL_PRIORITY_7 = dmacHw_REG_CFG_LO_CH_PRIORITY_7	/* Channel priority 7. Highest priority DMA channel */
+} dmacHw_CHANNEL_PRIORITY_e;
+
+/* Source destination master interface */
+typedef enum {
+	dmacHw_SRC_MASTER_INTERFACE_1 = dmacHw_REG_CTL_SMS_1,	/* Source DMA master interface 1 */
+	dmacHw_SRC_MASTER_INTERFACE_2 = dmacHw_REG_CTL_SMS_2,	/* Source DMA master interface 2 */
+	dmacHw_DST_MASTER_INTERFACE_1 = dmacHw_REG_CTL_DMS_1,	/* Destination DMA master interface 1 */
+	dmacHw_DST_MASTER_INTERFACE_2 = dmacHw_REG_CTL_DMS_2	/* Destination DMA master interface 2 */
+} dmacHw_MASTER_INTERFACE_e;
+
+typedef enum {
+	dmacHw_SRC_TRANSACTION_WIDTH_8 = dmacHw_REG_CTL_SRC_TR_WIDTH_8,	/* Source 8 bit  (1 byte) per transaction */
+	dmacHw_SRC_TRANSACTION_WIDTH_16 = dmacHw_REG_CTL_SRC_TR_WIDTH_16,	/* Source 16 bit (2 byte) per transaction */
+	dmacHw_SRC_TRANSACTION_WIDTH_32 = dmacHw_REG_CTL_SRC_TR_WIDTH_32,	/* Source 32 bit (4 byte) per transaction */
+	dmacHw_SRC_TRANSACTION_WIDTH_64 = dmacHw_REG_CTL_SRC_TR_WIDTH_64,	/* Source 64 bit (8 byte) per transaction */
+	dmacHw_DST_TRANSACTION_WIDTH_8 = dmacHw_REG_CTL_DST_TR_WIDTH_8,	/* Destination 8 bit  (1 byte) per transaction */
+	dmacHw_DST_TRANSACTION_WIDTH_16 = dmacHw_REG_CTL_DST_TR_WIDTH_16,	/* Destination 16 bit (2 byte) per transaction */
+	dmacHw_DST_TRANSACTION_WIDTH_32 = dmacHw_REG_CTL_DST_TR_WIDTH_32,	/* Destination 32 bit (4 byte) per transaction */
+	dmacHw_DST_TRANSACTION_WIDTH_64 = dmacHw_REG_CTL_DST_TR_WIDTH_64	/* Destination 64 bit (8 byte) per transaction */
+} dmacHw_TRANSACTION_WIDTH_e;
+
+typedef enum {
+	dmacHw_SRC_BURST_WIDTH_0 = dmacHw_REG_CTL_SRC_MSIZE_0,	/* Source No burst */
+	dmacHw_SRC_BURST_WIDTH_4 = dmacHw_REG_CTL_SRC_MSIZE_4,	/* Source 4  X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
+	dmacHw_SRC_BURST_WIDTH_8 = dmacHw_REG_CTL_SRC_MSIZE_8,	/* Source 8  X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
+	dmacHw_SRC_BURST_WIDTH_16 = dmacHw_REG_CTL_SRC_MSIZE_16,	/* Source 16 X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
+	dmacHw_DST_BURST_WIDTH_0 = dmacHw_REG_CTL_DST_MSIZE_0,	/* Destination No burst */
+	dmacHw_DST_BURST_WIDTH_4 = dmacHw_REG_CTL_DST_MSIZE_4,	/* Destination 4  X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
+	dmacHw_DST_BURST_WIDTH_8 = dmacHw_REG_CTL_DST_MSIZE_8,	/* Destination 8  X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
+	dmacHw_DST_BURST_WIDTH_16 = dmacHw_REG_CTL_DST_MSIZE_16	/* Destination 16 X dmacHw_TRANSACTION_WIDTH_xxx bytes per burst */
+} dmacHw_BURST_WIDTH_e;
+
+typedef enum {
+	dmacHw_TRANSFER_TYPE_MEM_TO_MEM = dmacHw_REG_CTL_TTFC_MM_DMAC,	/* Memory to memory transfer */
+	dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM = dmacHw_REG_CTL_TTFC_PM_DMAC,	/* Peripheral to memory transfer */
+	dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL = dmacHw_REG_CTL_TTFC_MP_DMAC,	/* Memory to peripheral transfer */
+	dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_PERIPHERAL = dmacHw_REG_CTL_TTFC_PP_DMAC	/* Peripheral to peripheral transfer */
+} dmacHw_TRANSFER_TYPE_e;
+
+typedef enum {
+	dmacHw_TRANSFER_MODE_PERREQUEST,	/* Block transfer per DMA request */
+	dmacHw_TRANSFER_MODE_CONTINUOUS,	/* Continuous transfer of streaming data */
+	dmacHw_TRANSFER_MODE_PERIODIC	/* Periodic transfer of streaming data */
+} dmacHw_TRANSFER_MODE_e;
+
+typedef enum {
+	dmacHw_SRC_ADDRESS_UPDATE_MODE_INC = dmacHw_REG_CTL_SINC_INC,	/* Increment source address after every transaction */
+	dmacHw_SRC_ADDRESS_UPDATE_MODE_DEC = dmacHw_REG_CTL_SINC_DEC,	/* Decrement source address after every transaction */
+	dmacHw_DST_ADDRESS_UPDATE_MODE_INC = dmacHw_REG_CTL_DINC_INC,	/* Increment destination address after every transaction */
+	dmacHw_DST_ADDRESS_UPDATE_MODE_DEC = dmacHw_REG_CTL_DINC_DEC,	/* Decrement destination address after every transaction */
+	dmacHw_SRC_ADDRESS_UPDATE_MODE_NC = dmacHw_REG_CTL_SINC_NC,	/* No change in source address after every transaction */
+	dmacHw_DST_ADDRESS_UPDATE_MODE_NC = dmacHw_REG_CTL_DINC_NC	/* No change in destination address after every transaction */
+} dmacHw_ADDRESS_UPDATE_MODE_e;
+
+typedef enum {
+	dmacHw_FLOW_CONTROL_DMA,	/* DMA working as flow controller (default) */
+	dmacHw_FLOW_CONTROL_PERIPHERAL	/* Peripheral working as flow controller */
+} dmacHw_FLOW_CONTROL_e;
+
+typedef enum {
+	dmacHw_TRANSFER_STATUS_BUSY,	/* DMA Transfer ongoing */
+	dmacHw_TRANSFER_STATUS_DONE,	/* DMA Transfer completed */
+	dmacHw_TRANSFER_STATUS_ERROR	/* DMA Transfer error */
+} dmacHw_TRANSFER_STATUS_e;
+
+typedef enum {
+	dmacHw_INTERRUPT_DISABLE,	/* Interrupt disable  */
+	dmacHw_INTERRUPT_ENABLE	/* Interrupt enable */
+} dmacHw_INTERRUPT_e;
+
+typedef enum {
+	dmacHw_INTERRUPT_STATUS_NONE = 0x0,	/* No DMA interrupt */
+	dmacHw_INTERRUPT_STATUS_TRANS = 0x1,	/* End of DMA transfer interrupt */
+	dmacHw_INTERRUPT_STATUS_BLOCK = 0x2,	/* End of block transfer interrupt */
+	dmacHw_INTERRUPT_STATUS_ERROR = 0x4	/* Error interrupt */
+} dmacHw_INTERRUPT_STATUS_e;
+
+typedef enum {
+	dmacHw_CONTROLLER_ATTRIB_CHANNEL_NUM,	/* Number of DMA channel */
+	dmacHw_CONTROLLER_ATTRIB_CHANNEL_MAX_BLOCK_SIZE,	/* Maximum channel burst size */
+	dmacHw_CONTROLLER_ATTRIB_MASTER_INTF_NUM,	/* Number of DMA master interface */
+	dmacHw_CONTROLLER_ATTRIB_CHANNEL_BUS_WIDTH,	/* Channel Data bus width */
+	dmacHw_CONTROLLER_ATTRIB_CHANNEL_FIFO_SIZE	/* Channel FIFO size */
+} dmacHw_CONTROLLER_ATTRIB_e;
+
+typedef unsigned long dmacHw_HANDLE_t;	/* DMA channel handle */
+typedef uint32_t dmacHw_ID_t;	/* DMA channel Id.  Must be created using
+				   "dmacHw_MAKE_CHANNEL_ID" macro
+				 */
+/* DMA channel configuration parameters */
+typedef struct {
+	uint32_t srcPeripheralPort;	/* Source peripheral port */
+	uint32_t dstPeripheralPort;	/* Destination peripheral port */
+	uint32_t srcStatusRegisterAddress;	/* Source status register address */
+	uint32_t dstStatusRegisterAddress;	/* Destination status register address of type  */
+
+	uint32_t srcGatherWidth;	/* Number of bytes gathered before successive gather opearation */
+	uint32_t srcGatherJump;	/* Number of bytes jumpped before successive gather opearation */
+	uint32_t dstScatterWidth;	/* Number of bytes sacattered before successive scatter opearation */
+	uint32_t dstScatterJump;	/* Number of bytes jumpped  before successive scatter opearation */
+	uint32_t maxDataPerBlock;	/* Maximum number of bytes to be transferred per block/descrptor.
+					   0 = Maximum possible.
+					 */
+
+	dmacHw_ADDRESS_UPDATE_MODE_e srcUpdate;	/* Source address update mode */
+	dmacHw_ADDRESS_UPDATE_MODE_e dstUpdate;	/* Destination address update mode */
+	dmacHw_TRANSFER_TYPE_e transferType;	/* DMA transfer type  */
+	dmacHw_TRANSFER_MODE_e transferMode;	/* DMA transfer mode */
+	dmacHw_MASTER_INTERFACE_e srcMasterInterface;	/* DMA source interface  */
+	dmacHw_MASTER_INTERFACE_e dstMasterInterface;	/* DMA destination interface */
+	dmacHw_TRANSACTION_WIDTH_e srcMaxTransactionWidth;	/* Source transaction width   */
+	dmacHw_TRANSACTION_WIDTH_e dstMaxTransactionWidth;	/* Destination transaction width */
+	dmacHw_BURST_WIDTH_e srcMaxBurstWidth;	/* Source burst width */
+	dmacHw_BURST_WIDTH_e dstMaxBurstWidth;	/* Destination burst width */
+	dmacHw_INTERRUPT_e blockTransferInterrupt;	/* Block trsnafer interrupt */
+	dmacHw_INTERRUPT_e completeTransferInterrupt;	/* Complete DMA trsnafer interrupt */
+	dmacHw_INTERRUPT_e errorInterrupt;	/* Error interrupt */
+	dmacHw_CHANNEL_PRIORITY_e channelPriority;	/* Channel priority */
+	dmacHw_FLOW_CONTROL_e flowControler;	/* Data flow controller */
+} dmacHw_CONFIG_t;
+
+/****************************************************************************/
+/**
+*  @brief   Initializes DMA
+*
+*  This function initializes DMA CSP driver
+*
+*  @note
+*     Must be called before using any DMA channel
+*/
+/****************************************************************************/
+void dmacHw_initDma(void);
+
+/****************************************************************************/
+/**
+*  @brief   Exit function for  DMA
+*
+*  This function isolates DMA from the system
+*
+*/
+/****************************************************************************/
+void dmacHw_exitDma(void);
+
+/****************************************************************************/
+/**
+*  @brief   Gets a handle to a DMA channel
+*
+*  This function returns a handle, representing a control block of a particular DMA channel
+*
+*  @return  -1       - On Failure
+*            handle  - On Success, representing a channel control block
+*
+*  @note
+*     None  Channel ID must be created using "dmacHw_MAKE_CHANNEL_ID" macro
+*/
+/****************************************************************************/
+dmacHw_HANDLE_t dmacHw_getChannelHandle(dmacHw_ID_t channelId	/* [ IN ] DMA Channel Id */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Initializes a DMA channel for use
+*
+*  This function initializes and resets a DMA channel for use
+*
+*  @return  -1     - On Failure
+*            0     - On Success
+*
+*  @note
+*     None
+*/
+/****************************************************************************/
+int dmacHw_initChannel(dmacHw_HANDLE_t handle	/*  [ IN ] DMA Channel handle  */
+    );
+
+/****************************************************************************/
+/**
+*  @brief  Estimates number of descriptor needed to perform certain DMA transfer
+*
+*
+*  @return  On failure : -1
+*           On success : Number of descriptor count
+*
+*
+*/
+/****************************************************************************/
+int dmacHw_calculateDescriptorCount(dmacHw_CONFIG_t *pConfig,	/*   [ IN ] Configuration settings */
+				    void *pSrcAddr,	/*   [ IN ] Source (Peripheral/Memory) address */
+				    void *pDstAddr,	/*   [ IN ] Destination (Peripheral/Memory) address */
+				    size_t dataLen	/*   [ IN ] Data length in bytes */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Initializes descriptor ring
+*
+*  This function will initializes the descriptor ring of a DMA channel
+*
+*
+*  @return   -1 - On failure
+*             0 - On success
+*  @note
+*     - "len" parameter should be obtained from "dmacHw_descriptorLen"
+*     - Descriptor buffer MUST be 32 bit aligned and uncached as it
+*       is accessed by ARM and DMA
+*/
+/****************************************************************************/
+int dmacHw_initDescriptor(void *pDescriptorVirt,	/*  [ IN ] Virtual address of uncahced buffer allocated to form descriptor ring */
+			  uint32_t descriptorPhyAddr,	/*  [ IN ] Physical address of pDescriptorVirt (descriptor buffer) */
+			  uint32_t len,	/*  [ IN ] Size of the pBuf */
+			  uint32_t num	/*  [ IN ] Number of descriptor in the ring */
+    );
+
+/****************************************************************************/
+/**
+*  @brief  Finds amount of memory required to form a descriptor ring
+*
+*
+*  @return   Number of bytes required to form a descriptor ring
+*
+*
+*  @note
+*     None
+*/
+/****************************************************************************/
+uint32_t dmacHw_descriptorLen(uint32_t descCnt	/*  [ IN ] Number of descriptor in the ring */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Configure DMA channel
+*
+*  @return  0  : On success
+*           -1 : On failure
+*/
+/****************************************************************************/
+int dmacHw_configChannel(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle  */
+			 dmacHw_CONFIG_t *pConfig	/*   [ IN ] Configuration settings */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Set descriptors for known data length
+*
+*  When DMA has to work as a flow controller, this function prepares the
+*  descriptor chain to transfer data
+*
+*  from:
+*          - Memory to memory
+*          - Peripheral to memory
+*          - Memory to Peripheral
+*          - Peripheral to Peripheral
+*
+*  @return   -1 - On failure
+*             0 - On success
+*
+*/
+/****************************************************************************/
+int dmacHw_setDataDescriptor(dmacHw_CONFIG_t *pConfig,	/*  [ IN ] Configuration settings */
+			     void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
+			     void *pSrcAddr,	/*  [ IN ] Source (Peripheral/Memory) address */
+			     void *pDstAddr,	/*  [ IN ] Destination (Peripheral/Memory) address */
+			     size_t dataLen	/*  [ IN ] Length in bytes   */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Indicates whether DMA transfer is in progress or completed
+*
+*  @return   DMA transfer status
+*          dmacHw_TRANSFER_STATUS_BUSY:         DMA Transfer ongoing
+*          dmacHw_TRANSFER_STATUS_DONE:         DMA Transfer completed
+*          dmacHw_TRANSFER_STATUS_ERROR:        DMA Transfer error
+*
+*/
+/****************************************************************************/
+dmacHw_TRANSFER_STATUS_e dmacHw_transferCompleted(dmacHw_HANDLE_t handle	/*   [ IN ] DMA Channel handle  */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Set descriptor carrying control information
+*
+*  This function will be used to send specific control information to the device
+*  using the DMA channel
+*
+*
+*  @return  -1 - On failure
+*            0 - On success
+*
+*  @note
+*     None
+*/
+/****************************************************************************/
+int dmacHw_setControlDescriptor(dmacHw_CONFIG_t *pConfig,	/*  [ IN ] Configuration settings */
+				void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
+				uint32_t ctlAddress,	/*  [ IN ] Address of the device control register  */
+				uint32_t control	/*  [ IN ] Device control information */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Read data DMA transferred to memory
+*
+*  This function will read data that has been DMAed to memory while transferring from:
+*          - Memory to memory
+*          - Peripheral to memory
+*
+*  @return  0 - No more data is available to read
+*           1 - More data might be available to read
+*
+*/
+/****************************************************************************/
+int dmacHw_readTransferredData(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle    */
+			       dmacHw_CONFIG_t *pConfig,	/*  [ IN ]  Configuration settings */
+			       void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
+			       void **ppBbuf,	/*  [ OUT ] Data received */
+			       size_t *pLlen	/*  [ OUT ] Length of the data received */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Prepares descriptor ring, when source peripheral working as a flow controller
+*
+*  This function will form the descriptor ring by allocating buffers, when source peripheral
+*  has to work as a flow controller to transfer data from:
+*           - Peripheral to memory.
+*
+*  @return  -1 - On failure
+*            0 - On success
+*
+*
+*  @note
+*     None
+*/
+/****************************************************************************/
+int dmacHw_setVariableDataDescriptor(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle   */
+				     dmacHw_CONFIG_t *pConfig,	/*  [ IN ] Configuration settings */
+				     void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
+				     uint32_t srcAddr,	/*  [ IN ] Source peripheral address */
+				     void *(*fpAlloc) (int len),	/*  [ IN ] Function pointer  that provides destination memory */
+				     int len,	/*  [ IN ] Number of bytes "fpAlloc" will allocate for destination */
+				     int num	/*  [ IN ] Number of descriptor to set */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Program channel register to initiate transfer
+*
+*  @return  void
+*
+*
+*  @note
+*     - Descriptor buffer MUST ALWAYS be flushed before calling this function
+*     - This function should also be called from ISR to program the channel with
+*       pending descriptors
+*/
+/****************************************************************************/
+void dmacHw_initiateTransfer(dmacHw_HANDLE_t handle,	/*   [ IN ] DMA Channel handle */
+			     dmacHw_CONFIG_t *pConfig,	/*   [ IN ] Configuration settings */
+			     void *pDescriptor	/*   [ IN ] Descriptor buffer  */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Resets descriptor control information
+*
+*  @return  void
+*/
+/****************************************************************************/
+void dmacHw_resetDescriptorControl(void *pDescriptor	/*   [ IN ] Descriptor buffer  */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Program channel register to stop transfer
+*
+*  Ensures the channel is not doing any transfer after calling this function
+*
+*  @return  void
+*
+*/
+/****************************************************************************/
+void dmacHw_stopTransfer(dmacHw_HANDLE_t handle	/*   [ IN ] DMA Channel handle */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Check the existence of pending descriptor
+*
+*  This function confirmes if there is any pending descriptor in the chain
+*  to program the channel
+*
+*  @return  1 : Channel need to be programmed with pending descriptor
+*           0 : No more pending descriptor to programe the channel
+*
+*  @note
+*     - This function should be called from ISR in case there are pending
+*       descriptor to program the channel.
+*
+*     Example:
+*
+*     dmac_isr ()
+*     {
+*         ...
+*         if (dmacHw_descriptorPending (handle))
+*         {
+*            dmacHw_initiateTransfer (handle);
+*         }
+*     }
+*
+*/
+/****************************************************************************/
+uint32_t dmacHw_descriptorPending(dmacHw_HANDLE_t handle,	/*   [ IN ] DMA Channel handle */
+				  void *pDescriptor	/*   [ IN ] Descriptor buffer */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Deallocates source or destination memory, allocated
+*
+*  This function can be called to deallocate data memory that was DMAed successfully
+*
+*  @return  -1  - On failure
+*            0  - On success
+*
+*  @note
+*     This function will be called ONLY, when source OR destination address is pointing
+*     to dynamic memory
+*/
+/****************************************************************************/
+int dmacHw_freeMem(dmacHw_CONFIG_t *pConfig,	/*  [ IN ] Configuration settings */
+		   void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
+		   void (*fpFree) (void *)	/*  [ IN ] Function pointer to free data memory */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Clears the interrupt
+*
+*  This function clears the DMA channel specific interrupt
+*
+*  @return   N/A
+*
+*  @note
+*     Must be called under the context of ISR
+*/
+/****************************************************************************/
+void dmacHw_clearInterrupt(dmacHw_HANDLE_t handle	/*  [ IN ] DMA Channel handle  */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Returns the cause of channel specific DMA interrupt
+*
+*  This function returns the cause of interrupt
+*
+*  @return  Interrupt status, each bit representing a specific type of interrupt
+*           of type dmacHw_INTERRUPT_STATUS_e
+*  @note
+*           This function should be called under the context of ISR
+*/
+/****************************************************************************/
+dmacHw_INTERRUPT_STATUS_e dmacHw_getInterruptStatus(dmacHw_HANDLE_t handle	/*  [ IN ] DMA Channel handle  */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Indentifies a DMA channel causing interrupt
+*
+*  This functions returns a channel causing interrupt of type dmacHw_INTERRUPT_STATUS_e
+*
+*  @return  NULL   : No channel causing DMA interrupt
+*           ! NULL : Handle to a channel causing DMA interrupt
+*  @note
+*     dmacHw_clearInterrupt() must be called with a valid handle after calling this function
+*/
+/****************************************************************************/
+dmacHw_HANDLE_t dmacHw_getInterruptSource(void);
+
+/****************************************************************************/
+/**
+*  @brief   Sets channel specific user data
+*
+*  This function associates user data to a specific DMA channel
+*
+*/
+/****************************************************************************/
+void dmacHw_setChannelUserData(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle  */
+			       void *userData	/*  [ IN ] User data  */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Gets channel specific user data
+*
+*  This function returns user data specific to a DMA channel
+*
+*  @return   user data
+*/
+/****************************************************************************/
+void *dmacHw_getChannelUserData(dmacHw_HANDLE_t handle	/*  [ IN ] DMA Channel handle  */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Displays channel specific registers and other control parameters
+*
+*
+*  @return  void
+*
+*  @note
+*     None
+*/
+/****************************************************************************/
+void dmacHw_printDebugInfo(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle  */
+			   void *pDescriptor,	/*  [ IN ] Descriptor buffer  */
+			   int (*fpPrint) (const char *, ...)	/*  [ IN ] Print callback function */
+    );
+
+/****************************************************************************/
+/**
+*  @brief   Provides DMA controller attributes
+*
+*
+*  @return  DMA controller attributes
+*
+*  @note
+*     None
+*/
+/****************************************************************************/
+uint32_t dmacHw_getDmaControllerAttribute(dmacHw_HANDLE_t handle,	/*  [ IN ]  DMA Channel handle  */
+					  dmacHw_CONTROLLER_ATTRIB_e attr	/*  [ IN ]  DMA Controller attribute of type  dmacHw_CONTROLLER_ATTRIB_e */
+    );
+
+#endif /* _DMACHW_H */
diff --git a/arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h b/arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h
index d67e2f8..9d9455e 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h
@@ -24,7 +24,7 @@
 #ifndef _DMACHW_PRIV_H
 #define _DMACHW_PRIV_H
 
-#include <csp/stdint.h>
+#include <linux/types.h>
 
 /* Data type for DMA Link List Item */
 typedef struct {
diff --git a/arch/arm/mach-bcmring/include/mach/csp/dmacHw_reg.h b/arch/arm/mach-bcmring/include/mach/csp/dmacHw_reg.h
index f1ecf96..7cd0aaf 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/dmacHw_reg.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/dmacHw_reg.h
@@ -24,7 +24,7 @@
 #ifndef _DMACHW_REG_H
 #define _DMACHW_REG_H
 
-#include <csp/stdint.h>
+#include <linux/types.h>
 #include <mach/csp/mm_io.h>
 
 /* Data type for 64 bit little endian register */
@@ -121,75 +121,75 @@ typedef struct {
 } dmacHw_MISC_t;
 
 /* Base registers */
-#define dmacHw_0_MODULE_BASE_ADDR        (char *) MM_IO_BASE_DMA0	/* DMAC 0 module's base address */
-#define dmacHw_1_MODULE_BASE_ADDR        (char *) MM_IO_BASE_DMA1	/* DMAC 1 module's base address */
+#define dmacHw_0_MODULE_BASE_ADDR        (char __iomem*) MM_IO_BASE_DMA0	/* DMAC 0 module's base address */
+#define dmacHw_1_MODULE_BASE_ADDR        (char __iomem*) MM_IO_BASE_DMA1	/* DMAC 1 module's base address */
 
 extern uint32_t dmaChannelCount_0;
 extern uint32_t dmaChannelCount_1;
 
 /* Define channel specific registers */
-#define dmacHw_CHAN_BASE(module, chan)          ((dmacHw_CH_REG_t *) ((char *)((module) ? dmacHw_1_MODULE_BASE_ADDR : dmacHw_0_MODULE_BASE_ADDR) + ((chan) * sizeof(dmacHw_CH_REG_t))))
+#define dmacHw_CHAN_BASE(module, chan)          ((dmacHw_CH_REG_t __iomem*) ((char __iomem*)((module) ? dmacHw_1_MODULE_BASE_ADDR : dmacHw_0_MODULE_BASE_ADDR) + ((chan) * sizeof(dmacHw_CH_REG_t))))
 
 /* Raw interrupt status registers */
-#define dmacHw_REG_INT_RAW_BASE(module)         ((char *)dmacHw_CHAN_BASE((module), ((module) ? dmaChannelCount_1 : dmaChannelCount_0)))
-#define dmacHw_REG_INT_RAW_TRAN(module)         (((dmacHw_INT_RAW_t *) dmacHw_REG_INT_RAW_BASE((module)))->RawTfr.lo)
-#define dmacHw_REG_INT_RAW_BLOCK(module)        (((dmacHw_INT_RAW_t *) dmacHw_REG_INT_RAW_BASE((module)))->RawBlock.lo)
-#define dmacHw_REG_INT_RAW_STRAN(module)        (((dmacHw_INT_RAW_t *) dmacHw_REG_INT_RAW_BASE((module)))->RawSrcTran.lo)
-#define dmacHw_REG_INT_RAW_DTRAN(module)        (((dmacHw_INT_RAW_t *) dmacHw_REG_INT_RAW_BASE((module)))->RawDstTran.lo)
-#define dmacHw_REG_INT_RAW_ERROR(module)        (((dmacHw_INT_RAW_t *) dmacHw_REG_INT_RAW_BASE((module)))->RawErr.lo)
+#define dmacHw_REG_INT_RAW_BASE(module)         ((char __iomem *)dmacHw_CHAN_BASE((module), ((module) ? dmaChannelCount_1 : dmaChannelCount_0)))
+#define dmacHw_REG_INT_RAW_TRAN(module)         (((dmacHw_INT_RAW_t __iomem *) dmacHw_REG_INT_RAW_BASE((module)))->RawTfr.lo)
+#define dmacHw_REG_INT_RAW_BLOCK(module)        (((dmacHw_INT_RAW_t __iomem *) dmacHw_REG_INT_RAW_BASE((module)))->RawBlock.lo)
+#define dmacHw_REG_INT_RAW_STRAN(module)        (((dmacHw_INT_RAW_t __iomem *) dmacHw_REG_INT_RAW_BASE((module)))->RawSrcTran.lo)
+#define dmacHw_REG_INT_RAW_DTRAN(module)        (((dmacHw_INT_RAW_t __iomem *) dmacHw_REG_INT_RAW_BASE((module)))->RawDstTran.lo)
+#define dmacHw_REG_INT_RAW_ERROR(module)        (((dmacHw_INT_RAW_t __iomem *) dmacHw_REG_INT_RAW_BASE((module)))->RawErr.lo)
 
 /* Interrupt status registers */
-#define dmacHw_REG_INT_STAT_BASE(module)        ((char *)(dmacHw_REG_INT_RAW_BASE((module)) + sizeof(dmacHw_INT_RAW_t)))
-#define dmacHw_REG_INT_STAT_TRAN(module)        (((dmacHw_INT_STATUS_t *) dmacHw_REG_INT_STAT_BASE((module)))->StatusTfr.lo)
-#define dmacHw_REG_INT_STAT_BLOCK(module)       (((dmacHw_INT_STATUS_t *) dmacHw_REG_INT_STAT_BASE((module)))->StatusBlock.lo)
-#define dmacHw_REG_INT_STAT_STRAN(module)       (((dmacHw_INT_STATUS_t *) dmacHw_REG_INT_STAT_BASE((module)))->StatusSrcTran.lo)
-#define dmacHw_REG_INT_STAT_DTRAN(module)       (((dmacHw_INT_STATUS_t *) dmacHw_REG_INT_STAT_BASE((module)))->StatusDstTran.lo)
-#define dmacHw_REG_INT_STAT_ERROR(module)       (((dmacHw_INT_STATUS_t *) dmacHw_REG_INT_STAT_BASE((module)))->StatusErr.lo)
+#define dmacHw_REG_INT_STAT_BASE(module)        ((char __iomem*)(dmacHw_REG_INT_RAW_BASE((module)) + sizeof(dmacHw_INT_RAW_t)))
+#define dmacHw_REG_INT_STAT_TRAN(module)        (((dmacHw_INT_STATUS_t __iomem *) dmacHw_REG_INT_STAT_BASE((module)))->StatusTfr.lo)
+#define dmacHw_REG_INT_STAT_BLOCK(module)       (((dmacHw_INT_STATUS_t __iomem *) dmacHw_REG_INT_STAT_BASE((module)))->StatusBlock.lo)
+#define dmacHw_REG_INT_STAT_STRAN(module)       (((dmacHw_INT_STATUS_t __iomem *) dmacHw_REG_INT_STAT_BASE((module)))->StatusSrcTran.lo)
+#define dmacHw_REG_INT_STAT_DTRAN(module)       (((dmacHw_INT_STATUS_t __iomem *) dmacHw_REG_INT_STAT_BASE((module)))->StatusDstTran.lo)
+#define dmacHw_REG_INT_STAT_ERROR(module)       (((dmacHw_INT_STATUS_t __iomem *) dmacHw_REG_INT_STAT_BASE((module)))->StatusErr.lo)
 
 /* Interrupt status registers */
-#define dmacHw_REG_INT_MASK_BASE(module)        ((char *)(dmacHw_REG_INT_STAT_BASE((module)) + sizeof(dmacHw_INT_STATUS_t)))
-#define dmacHw_REG_INT_MASK_TRAN(module)        (((dmacHw_INT_MASK_t *) dmacHw_REG_INT_MASK_BASE((module)))->MaskTfr.lo)
-#define dmacHw_REG_INT_MASK_BLOCK(module)       (((dmacHw_INT_MASK_t *) dmacHw_REG_INT_MASK_BASE((module)))->MaskBlock.lo)
-#define dmacHw_REG_INT_MASK_STRAN(module)       (((dmacHw_INT_MASK_t *) dmacHw_REG_INT_MASK_BASE((module)))->MaskSrcTran.lo)
-#define dmacHw_REG_INT_MASK_DTRAN(module)       (((dmacHw_INT_MASK_t *) dmacHw_REG_INT_MASK_BASE((module)))->MaskDstTran.lo)
-#define dmacHw_REG_INT_MASK_ERROR(module)       (((dmacHw_INT_MASK_t *) dmacHw_REG_INT_MASK_BASE((module)))->MaskErr.lo)
+#define dmacHw_REG_INT_MASK_BASE(module)        ((char __iomem*)(dmacHw_REG_INT_STAT_BASE((module)) + sizeof(dmacHw_INT_STATUS_t)))
+#define dmacHw_REG_INT_MASK_TRAN(module)        (((dmacHw_INT_MASK_t __iomem *) dmacHw_REG_INT_MASK_BASE((module)))->MaskTfr.lo)
+#define dmacHw_REG_INT_MASK_BLOCK(module)       (((dmacHw_INT_MASK_t __iomem *) dmacHw_REG_INT_MASK_BASE((module)))->MaskBlock.lo)
+#define dmacHw_REG_INT_MASK_STRAN(module)       (((dmacHw_INT_MASK_t __iomem *) dmacHw_REG_INT_MASK_BASE((module)))->MaskSrcTran.lo)
+#define dmacHw_REG_INT_MASK_DTRAN(module)       (((dmacHw_INT_MASK_t __iomem *) dmacHw_REG_INT_MASK_BASE((module)))->MaskDstTran.lo)
+#define dmacHw_REG_INT_MASK_ERROR(module)       (((dmacHw_INT_MASK_t __iomem *) dmacHw_REG_INT_MASK_BASE((module)))->MaskErr.lo)
 
 /* Interrupt clear registers */
-#define dmacHw_REG_INT_CLEAR_BASE(module)       ((char *)(dmacHw_REG_INT_MASK_BASE((module)) + sizeof(dmacHw_INT_MASK_t)))
-#define dmacHw_REG_INT_CLEAR_TRAN(module)       (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearTfr.lo)
-#define dmacHw_REG_INT_CLEAR_BLOCK(module)      (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearBlock.lo)
-#define dmacHw_REG_INT_CLEAR_STRAN(module)      (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearSrcTran.lo)
-#define dmacHw_REG_INT_CLEAR_DTRAN(module)      (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearDstTran.lo)
-#define dmacHw_REG_INT_CLEAR_ERROR(module)      (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearErr.lo)
-#define dmacHw_REG_INT_STATUS(module)           (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->StatusInt.lo)
+#define dmacHw_REG_INT_CLEAR_BASE(module)       ((char __iomem*)(dmacHw_REG_INT_MASK_BASE((module)) + sizeof(dmacHw_INT_MASK_t)))
+#define dmacHw_REG_INT_CLEAR_TRAN(module)       (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearTfr.lo)
+#define dmacHw_REG_INT_CLEAR_BLOCK(module)      (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearBlock.lo)
+#define dmacHw_REG_INT_CLEAR_STRAN(module)      (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearSrcTran.lo)
+#define dmacHw_REG_INT_CLEAR_DTRAN(module)      (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearDstTran.lo)
+#define dmacHw_REG_INT_CLEAR_ERROR(module)      (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearErr.lo)
+#define dmacHw_REG_INT_STATUS(module)           (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->StatusInt.lo)
 
 /* Software handshaking registers */
-#define dmacHw_REG_SW_HS_BASE(module)           ((char *)(dmacHw_REG_INT_CLEAR_BASE((module)) + sizeof(dmacHw_INT_CLEAR_t)))
-#define dmacHw_REG_SW_HS_SRC_REQ(module)        (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->ReqSrcReg.lo)
-#define dmacHw_REG_SW_HS_DST_REQ(module)        (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->ReqDstReg.lo)
-#define dmacHw_REG_SW_HS_SRC_SGL_REQ(module)    (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->SglReqSrcReg.lo)
-#define dmacHw_REG_SW_HS_DST_SGL_REQ(module)    (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->SglReqDstReg.lo)
-#define dmacHw_REG_SW_HS_SRC_LST_REQ(module)    (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->LstSrcReg.lo)
-#define dmacHw_REG_SW_HS_DST_LST_REQ(module)    (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->LstDstReg.lo)
+#define dmacHw_REG_SW_HS_BASE(module)           ((char __iomem*)(dmacHw_REG_INT_CLEAR_BASE((module)) + sizeof(dmacHw_INT_CLEAR_t)))
+#define dmacHw_REG_SW_HS_SRC_REQ(module)        (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->ReqSrcReg.lo)
+#define dmacHw_REG_SW_HS_DST_REQ(module)        (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->ReqDstReg.lo)
+#define dmacHw_REG_SW_HS_SRC_SGL_REQ(module)    (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->SglReqSrcReg.lo)
+#define dmacHw_REG_SW_HS_DST_SGL_REQ(module)    (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->SglReqDstReg.lo)
+#define dmacHw_REG_SW_HS_SRC_LST_REQ(module)    (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->LstSrcReg.lo)
+#define dmacHw_REG_SW_HS_DST_LST_REQ(module)    (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->LstDstReg.lo)
 
 /* Miscellaneous registers */
-#define dmacHw_REG_MISC_BASE(module)            ((char *)(dmacHw_REG_SW_HS_BASE((module)) + sizeof(dmacHw_SW_HANDSHAKE_t)))
-#define dmacHw_REG_MISC_CFG(module)             (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->DmaCfgReg.lo)
-#define dmacHw_REG_MISC_CH_ENABLE(module)       (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->ChEnReg.lo)
-#define dmacHw_REG_MISC_ID(module)              (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->DmaIdReg.lo)
-#define dmacHw_REG_MISC_TEST(module)            (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->DmaTestReg.lo)
-#define dmacHw_REG_MISC_COMP_PARAM1_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm1.lo)
-#define dmacHw_REG_MISC_COMP_PARAM1_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm1.hi)
-#define dmacHw_REG_MISC_COMP_PARAM2_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm2.lo)
-#define dmacHw_REG_MISC_COMP_PARAM2_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm2.hi)
-#define dmacHw_REG_MISC_COMP_PARAM3_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm3.lo)
-#define dmacHw_REG_MISC_COMP_PARAM3_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm3.hi)
-#define dmacHw_REG_MISC_COMP_PARAM4_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm4.lo)
-#define dmacHw_REG_MISC_COMP_PARAM4_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm4.hi)
-#define dmacHw_REG_MISC_COMP_PARAM5_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm5.lo)
-#define dmacHw_REG_MISC_COMP_PARAM5_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm5.hi)
-#define dmacHw_REG_MISC_COMP_PARAM6_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm6.lo)
-#define dmacHw_REG_MISC_COMP_PARAM6_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm6.hi)
+#define dmacHw_REG_MISC_BASE(module)            ((char __iomem*)(dmacHw_REG_SW_HS_BASE((module)) + sizeof(dmacHw_SW_HANDSHAKE_t)))
+#define dmacHw_REG_MISC_CFG(module)             (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->DmaCfgReg.lo)
+#define dmacHw_REG_MISC_CH_ENABLE(module)       (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->ChEnReg.lo)
+#define dmacHw_REG_MISC_ID(module)              (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->DmaIdReg.lo)
+#define dmacHw_REG_MISC_TEST(module)            (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->DmaTestReg.lo)
+#define dmacHw_REG_MISC_COMP_PARAM1_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm1.lo)
+#define dmacHw_REG_MISC_COMP_PARAM1_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm1.hi)
+#define dmacHw_REG_MISC_COMP_PARAM2_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm2.lo)
+#define dmacHw_REG_MISC_COMP_PARAM2_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm2.hi)
+#define dmacHw_REG_MISC_COMP_PARAM3_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm3.lo)
+#define dmacHw_REG_MISC_COMP_PARAM3_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm3.hi)
+#define dmacHw_REG_MISC_COMP_PARAM4_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm4.lo)
+#define dmacHw_REG_MISC_COMP_PARAM4_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm4.hi)
+#define dmacHw_REG_MISC_COMP_PARAM5_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm5.lo)
+#define dmacHw_REG_MISC_COMP_PARAM5_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm5.hi)
+#define dmacHw_REG_MISC_COMP_PARAM6_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm6.lo)
+#define dmacHw_REG_MISC_COMP_PARAM6_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm6.hi)
 
 /* Channel control registers */
 #define dmacHw_REG_SAR(module, chan)            (dmacHw_CHAN_BASE((module), (chan))->ChannelSar.lo)
diff --git a/arch/arm/mach-bcmring/include/mach/csp/hw_cfg.h b/arch/arm/mach-bcmring/include/mach/csp/hw_cfg.h
index cfa91be..27f59dd 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/hw_cfg.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/hw_cfg.h
@@ -18,7 +18,7 @@
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 #include <mach/csp/cap_inline.h>
 
 #if defined(__KERNEL__)
diff --git a/arch/arm/mach-bcmring/include/mach/csp/intcHw_reg.h b/arch/arm/mach-bcmring/include/mach/csp/intcHw_reg.h
index 0aeb6a6..f59db25 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/intcHw_reg.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/intcHw_reg.h
@@ -27,8 +27,8 @@
 #define _INTCHW_REG_H
 
 /* ---- Include Files ---------------------------------------------------- */
-#include <csp/stdint.h>
-#include <csp/reg.h>
+#include <linux/types.h>
+#include <mach/csp/reg.h>
 #include <mach/csp/mm_io.h>
 
 /* ---- Public Constants and Types --------------------------------------- */
@@ -37,9 +37,9 @@
 #define INTCHW_NUM_INTC           3
 
 /* Defines for interrupt controllers. This simplifies and cleans up the function calls. */
-#define INTCHW_INTC0    ((void *)MM_IO_BASE_INTC0)
-#define INTCHW_INTC1    ((void *)MM_IO_BASE_INTC1)
-#define INTCHW_SINTC    ((void *)MM_IO_BASE_SINTC)
+#define INTCHW_INTC0    (MM_IO_BASE_INTC0)
+#define INTCHW_INTC1    (MM_IO_BASE_INTC1)
+#define INTCHW_SINTC    (MM_IO_BASE_SINTC)
 
 /* INTC0 - interrupt controller 0 */
 #define INTCHW_INTC0_PIF_BITNUM           31	/* Peripheral interface interrupt */
@@ -232,15 +232,15 @@
 /* ---- Public Variable Externs ------------------------------------------ */
 /* ---- Public Function Prototypes --------------------------------------- */
 /* Clear one or more IRQ interrupts. */
-static inline void intcHw_irq_disable(void *basep, uint32_t mask)
+static inline void intcHw_irq_disable(void __iomem *basep, uint32_t mask)
 {
-	__REG32(basep + INTCHW_INTENCLEAR) = mask;
+	writel(mask, basep + INTCHW_INTENCLEAR);
 }
 
 /* Enables one or more IRQ interrupts. */
-static inline void intcHw_irq_enable(void *basep, uint32_t mask)
+static inline void intcHw_irq_enable(void __iomem *basep, uint32_t mask)
 {
-	__REG32(basep + INTCHW_INTENABLE) = mask;
+	writel(mask, basep + INTCHW_INTENABLE);
 }
 
 #endif /* _INTCHW_REG_H */
diff --git a/arch/arm/mach-bcmring/include/mach/csp/mm_addr.h b/arch/arm/mach-bcmring/include/mach/csp/mm_addr.h
index ad58cf8..d571962 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/mm_addr.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/mm_addr.h
@@ -29,7 +29,7 @@
 /* ---- Include Files ---------------------------------------------------- */
 
 #if !defined(CSP_SIMULATION)
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 #endif
 
 /* ---- Public Constants and Types --------------------------------------- */
diff --git a/arch/arm/mach-bcmring/include/mach/csp/mm_io.h b/arch/arm/mach-bcmring/include/mach/csp/mm_io.h
index de92ec6..47450c2 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/mm_io.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/mm_io.h
@@ -30,7 +30,7 @@
 #include <mach/csp/mm_addr.h>
 
 #if !defined(CSP_SIMULATION)
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 #endif
 
 /* ---- Public Constants and Types --------------------------------------- */
@@ -49,7 +49,7 @@
 #ifdef __ASSEMBLY__
 #define MM_IO_PHYS_TO_VIRT(phys)       (0xF0000000 | (((phys) >> 4) & 0x0F000000) | ((phys) & 0xFFFFFF))
 #else
-#define MM_IO_PHYS_TO_VIRT(phys)       (((phys) == MM_ADDR_IO_VPM_EXTMEM_RSVD) ? 0xF0000000 : \
+#define MM_IO_PHYS_TO_VIRT(phys)       (void __iomem *)(((phys) == MM_ADDR_IO_VPM_EXTMEM_RSVD) ? 0xF0000000 : \
 			(0xF0000000 | (((phys) >> 4) & 0x0F000000) | ((phys) & 0xFFFFFF)))
 #endif
 #endif
@@ -60,8 +60,8 @@
 #ifdef __ASSEMBLY__
 #define MM_IO_VIRT_TO_PHYS(virt)       ((((virt) & 0x0F000000) << 4) | ((virt) & 0xFFFFFF))
 #else
-#define MM_IO_VIRT_TO_PHYS(virt)       (((virt) == 0xF0000000) ? MM_ADDR_IO_VPM_EXTMEM_RSVD : \
-			((((virt) & 0x0F000000) << 4) | ((virt) & 0xFFFFFF)))
+#define MM_IO_VIRT_TO_PHYS(virt)       (((unsigned long)(virt) == 0xF0000000) ? MM_ADDR_IO_VPM_EXTMEM_RSVD : \
+			((((unsigned long)(virt) & 0x0F000000) << 4) | ((unsigned long)(virt) & 0xFFFFFF)))
 #endif
 #endif
 
diff --git a/arch/arm/mach-bcmring/include/mach/csp/reg.h b/arch/arm/mach-bcmring/include/mach/csp/reg.h
new file mode 100644
index 0000000..d9cbdca
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/csp/reg.h
@@ -0,0 +1,115 @@
+/*****************************************************************************
+* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+/****************************************************************************/
+/**
+*  @file    reg.h
+*
+*  @brief   Generic register definitions used in CSP
+*/
+/****************************************************************************/
+
+#ifndef CSP_REG_H
+#define CSP_REG_H
+
+/* ---- Include Files ---------------------------------------------------- */
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+/* ---- Public Constants and Types --------------------------------------- */
+
+#define __REG32(x)      (*((volatile uint32_t __iomem *)(x)))
+#define __REG16(x)      (*((volatile uint16_t __iomem *)(x)))
+#define __REG8(x)       (*((volatile uint8_t __iomem *) (x)))
+
+/* Macros used to define a sequence of reserved registers. The start / end */
+/* are byte offsets in the particular register definition, with the "end" */
+/* being the offset of the next un-reserved register. E.g. if offsets */
+/* 0x10 through to 0x1f are reserved, then this reserved area could be */
+/* specified as follows. */
+/*  typedef struct */
+/*  { */
+/*      uint32_t reg1;           offset 0x00 */
+/*      uint32_t reg2;           offset 0x04 */
+/*      uint32_t reg3;           offset 0x08 */
+/*      uint32_t reg4;           offset 0x0c */
+/*      REG32_RSVD(0x10, 0x20); */
+/*      uint32_t reg5;           offset 0x20 */
+/*      ... */
+/*  } EXAMPLE_REG_t; */
+#define REG8_RSVD(start, end)   uint8_t rsvd_##start[(end - start) / sizeof(uint8_t)]
+#define REG16_RSVD(start, end)  uint16_t rsvd_##start[(end - start) / sizeof(uint16_t)]
+#define REG32_RSVD(start, end)  uint32_t rsvd_##start[(end - start) / sizeof(uint32_t)]
+
+/* ---- Public Variable Externs ------------------------------------------ */
+/* ---- Public Function Prototypes --------------------------------------- */
+
+/* Note: When protecting multiple statements, the REG_LOCAL_IRQ_SAVE and */
+/* REG_LOCAL_IRQ_RESTORE must be enclosed in { } to allow the  */
+/* flags variable to be declared locally. */
+/* e.g. */
+/*    statement1; */
+/*    { */
+/*       REG_LOCAL_IRQ_SAVE; */
+/*       <multiple statements here> */
+/*       REG_LOCAL_IRQ_RESTORE; */
+/*    } */
+/*    statement2; */
+/*  */
+
+#if defined(__KERNEL__) && !defined(STANDALONE)
+#include <mach/hardware.h>
+#include <linux/interrupt.h>
+
+#define REG_LOCAL_IRQ_SAVE      HW_DECLARE_SPINLOCK(reg32) \
+	unsigned long flags; HW_IRQ_SAVE(reg32, flags)
+
+#define REG_LOCAL_IRQ_RESTORE   HW_IRQ_RESTORE(reg32, flags)
+
+#else
+
+#define REG_LOCAL_IRQ_SAVE
+#define REG_LOCAL_IRQ_RESTORE
+
+#endif
+
+static inline void reg32_modify_and(volatile uint32_t __iomem *reg, uint32_t value)
+{
+	REG_LOCAL_IRQ_SAVE;
+	__raw_writel(__raw_readl(reg) & value, reg);
+	REG_LOCAL_IRQ_RESTORE;
+}
+
+static inline void reg32_modify_or(volatile uint32_t __iomem *reg, uint32_t value)
+{
+	REG_LOCAL_IRQ_SAVE;
+	__raw_writel(__raw_readl(reg) | value, reg);
+	REG_LOCAL_IRQ_RESTORE;
+}
+
+static inline void reg32_modify_mask(volatile uint32_t __iomem *reg, uint32_t mask,
+				     uint32_t value)
+{
+	REG_LOCAL_IRQ_SAVE;
+	__raw_writel((__raw_readl(reg) & mask) | value, reg);
+	REG_LOCAL_IRQ_RESTORE;
+}
+
+static inline void reg32_write(volatile uint32_t __iomem *reg, uint32_t value)
+{
+	__raw_writel(value, reg);
+}
+
+#endif /* CSP_REG_H */
diff --git a/arch/arm/mach-bcmring/include/mach/csp/secHw_inline.h b/arch/arm/mach-bcmring/include/mach/csp/secHw_inline.h
index 9cd6a03..55d3cd4 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/secHw_inline.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/secHw_inline.h
@@ -34,7 +34,7 @@
 /****************************************************************************/
 static inline void secHw_setSecure(uint32_t mask	/*  mask of type secHw_BLK_MASK_XXXXXX */
     ) {
-	secHw_REGS_t *regp = (secHw_REGS_t *) MM_IO_BASE_TZPC;
+	secHw_REGS_t __iomem *regp = MM_IO_BASE_TZPC;
 
 	if (mask & 0x0000FFFF) {
 		regp->reg[secHw_IDX_LS].setSecure = mask & 0x0000FFFF;
@@ -53,13 +53,13 @@ static inline void secHw_setSecure(uint32_t mask	/*  mask of type secHw_BLK_MASK
 /****************************************************************************/
 static inline void secHw_setUnsecure(uint32_t mask	/*  mask of type secHw_BLK_MASK_XXXXXX */
     ) {
-	secHw_REGS_t *regp = (secHw_REGS_t *) MM_IO_BASE_TZPC;
+	secHw_REGS_t __iomem *regp = MM_IO_BASE_TZPC;
 
 	if (mask & 0x0000FFFF) {
-		regp->reg[secHw_IDX_LS].setUnsecure = mask & 0x0000FFFF;
+		writel(mask & 0x0000FFFF, &regp->reg[secHw_IDX_LS].setUnsecure);
 	}
 	if (mask & 0xFFFF0000) {
-		regp->reg[secHw_IDX_MS].setUnsecure = mask >> 16;
+		writel(mask >> 16, &regp->reg[secHw_IDX_MS].setUnsecure);
 	}
 }
 
@@ -71,7 +71,7 @@ static inline void secHw_setUnsecure(uint32_t mask	/*  mask of type secHw_BLK_MA
 /****************************************************************************/
 static inline uint32_t secHw_getStatus(void)
 {
-	secHw_REGS_t *regp = (secHw_REGS_t *) MM_IO_BASE_TZPC;
+	secHw_REGS_t __iomem *regp = MM_IO_BASE_TZPC;
 
 	return (regp->reg[1].status << 16) + regp->reg[0].status;
 }
diff --git a/arch/arm/mach-bcmring/include/mach/csp/tmrHw.h b/arch/arm/mach-bcmring/include/mach/csp/tmrHw.h
new file mode 100644
index 0000000..1cc882a
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/csp/tmrHw.h
@@ -0,0 +1,263 @@
+/*****************************************************************************
+* Copyright 2004 - 2008 Broadcom Corporation.  All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+/****************************************************************************/
+/**
+*  @file    tmrHw.h
+*
+*  @brief   API definitions for low level Timer driver
+*
+*/
+/****************************************************************************/
+#ifndef _TMRHW_H
+#define _TMRHW_H
+
+#include <linux/types.h>
+
+typedef uint32_t tmrHw_ID_t;	/* Timer ID */
+typedef uint32_t tmrHw_COUNT_t;	/* Timer count */
+typedef uint32_t tmrHw_INTERVAL_t;	/* Timer interval */
+typedef uint32_t tmrHw_RATE_t;	/* Timer event (count/interrupt) rate */
+
+typedef enum {
+	tmrHw_INTERRUPT_STATUS_SET,	/* Interrupted  */
+	tmrHw_INTERRUPT_STATUS_UNSET	/* No Interrupt */
+} tmrHw_INTERRUPT_STATUS_e;
+
+typedef enum {
+	tmrHw_CAPABILITY_CLOCK,	/* Clock speed in HHz */
+	tmrHw_CAPABILITY_RESOLUTION	/* Timer resolution in bits */
+} tmrHw_CAPABILITY_e;
+
+/****************************************************************************/
+/**
+*  @brief   Get timer capability
+*
+*  This function returns various capabilities/attributes of a timer
+*
+*  @return  Numeric capability
+*
+*/
+/****************************************************************************/
+uint32_t tmrHw_getTimerCapability(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
+				  tmrHw_CAPABILITY_e capability	/*  [ IN ] Timer capability */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Configures a periodic timer in terms of timer interrupt rate
+*
+*  This function initializes a periodic timer to generate specific number of
+*  timer interrupt per second
+*
+*  @return   On success: Effective timer frequency
+*            On failure: 0
+*
+*/
+/****************************************************************************/
+tmrHw_RATE_t tmrHw_setPeriodicTimerRate(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
+					tmrHw_RATE_t rate	/*  [ IN ] Number of timer interrupt per second */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Configures a periodic timer to generate timer interrupt after
+*           certain time interval
+*
+*  This function initializes a periodic timer to generate timer interrupt
+*  after every time interval in millisecond
+*
+*  @return   On success: Effective interval set in mili-second
+*            On failure: 0
+*
+*/
+/****************************************************************************/
+tmrHw_INTERVAL_t tmrHw_setPeriodicTimerInterval(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
+						tmrHw_INTERVAL_t msec	/*  [ IN ] Interval in mili-second */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Configures a periodic timer to generate timer interrupt just once
+*           after certain time interval
+*
+*  This function initializes a periodic timer to generate a single ticks after
+*  certain time interval in millisecond
+*
+*  @return   On success: Effective interval set in mili-second
+*            On failure: 0
+*
+*/
+/****************************************************************************/
+tmrHw_INTERVAL_t tmrHw_setOneshotTimerInterval(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
+					       tmrHw_INTERVAL_t msec	/*  [ IN ] Interval in mili-second */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Configures a timer to run as a free running timer
+*
+*  This function initializes a timer to run as a free running timer
+*
+*  @return   Timer resolution (count / sec)
+*
+*/
+/****************************************************************************/
+tmrHw_RATE_t tmrHw_setFreeRunningTimer(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
+				       uint32_t divider	/*  [ IN ] Dividing the clock frequency */
+) __attribute__ ((section(".aramtext")));
+
+/****************************************************************************/
+/**
+*  @brief   Starts a timer
+*
+*  This function starts a preconfigured timer
+*
+*  @return  -1     - On Failure
+*            0     - On Success
+*/
+/****************************************************************************/
+int tmrHw_startTimer(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
+) __attribute__ ((section(".aramtext")));
+
+/****************************************************************************/
+/**
+*  @brief   Stops a timer
+*
+*  This function stops a running timer
+*
+*  @return  -1     - On Failure
+*            0     - On Success
+*/
+/****************************************************************************/
+int tmrHw_stopTimer(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Gets current timer count
+*
+*  This function returns the current timer value
+*
+*  @return  Current downcounting timer value
+*
+*/
+/****************************************************************************/
+tmrHw_COUNT_t tmrHw_GetCurrentCount(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
+) __attribute__ ((section(".aramtext")));
+
+/****************************************************************************/
+/**
+*  @brief   Gets timer count rate
+*
+*  This function returns the number of counts per second
+*
+*  @return  Count rate
+*
+*/
+/****************************************************************************/
+tmrHw_RATE_t tmrHw_getCountRate(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
+) __attribute__ ((section(".aramtext")));
+
+/****************************************************************************/
+/**
+*  @brief   Enables timer interrupt
+*
+*  This function enables the timer interrupt
+*
+*  @return   N/A
+*
+*/
+/****************************************************************************/
+void tmrHw_enableInterrupt(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Disables timer interrupt
+*
+*  This function disable the timer interrupt
+*
+*  @return   N/A
+*/
+/****************************************************************************/
+void tmrHw_disableInterrupt(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Clears the interrupt
+*
+*  This function clears the timer interrupt
+*
+*  @return   N/A
+*
+*  @note
+*     Must be called under the context of ISR
+*/
+/****************************************************************************/
+void tmrHw_clearInterrupt(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Gets the interrupt status
+*
+*  This function returns timer interrupt status
+*
+*  @return   Interrupt status
+*/
+/****************************************************************************/
+tmrHw_INTERRUPT_STATUS_e tmrHw_getInterruptStatus(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Indentifies a timer causing interrupt
+*
+*  This functions returns a timer causing interrupt
+*
+*  @return  0xFFFFFFFF   : No timer causing an interrupt
+*           ! 0xFFFFFFFF : timer causing an interrupt
+*  @note
+*     tmrHw_clearIntrrupt() must be called with a valid timer id after calling this function
+*/
+/****************************************************************************/
+tmrHw_ID_t tmrHw_getInterruptSource(void);
+
+/****************************************************************************/
+/**
+*  @brief   Displays specific timer registers
+*
+*
+*  @return  void
+*
+*/
+/****************************************************************************/
+void tmrHw_printDebugInfo(tmrHw_ID_t timerId,	/*  [ IN ] Timer id */
+			  int (*fpPrint) (const char *, ...)	/*  [ IN ] Print callback function */
+);
+
+/****************************************************************************/
+/**
+*  @brief   Use a timer to perform a busy wait delay for a number of usecs.
+*
+*  @return   N/A
+*/
+/****************************************************************************/
+void tmrHw_udelay(tmrHw_ID_t timerId,	/*  [ IN ] Timer id */
+		  unsigned long usecs	/*  [ IN ] usec to delay */
+) __attribute__ ((section(".aramtext")));
+
+#endif /* _TMRHW_H */
diff --git a/arch/arm/mach-bcmring/include/mach/dma.h b/arch/arm/mach-bcmring/include/mach/dma.h
index 7254378..13e0138 100644
--- a/arch/arm/mach-bcmring/include/mach/dma.h
+++ b/arch/arm/mach-bcmring/include/mach/dma.h
@@ -27,7 +27,7 @@
 
 #include <linux/kernel.h>
 #include <linux/semaphore.h>
-#include <csp/dmacHw.h>
+#include <mach/csp/dmacHw.h>
 #include <mach/timer.h>
 
 /* ---- Constants and Types ---------------------------------------------- */
diff --git a/arch/arm/mach-bcmring/include/mach/hardware.h b/arch/arm/mach-bcmring/include/mach/hardware.h
index 6ae20a6..a0c92b4 100644
--- a/arch/arm/mach-bcmring/include/mach/hardware.h
+++ b/arch/arm/mach-bcmring/include/mach/hardware.h
@@ -22,7 +22,7 @@
 #define __ASM_ARCH_HARDWARE_H
 
 #include <asm/sizes.h>
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 #include <mach/csp/mm_io.h>
 
 /* Hardware addresses of major areas.
diff --git a/arch/arm/mach-bcmring/include/mach/reg_nand.h b/arch/arm/mach-bcmring/include/mach/reg_nand.h
index 387376f..f8d51a8 100644
--- a/arch/arm/mach-bcmring/include/mach/reg_nand.h
+++ b/arch/arm/mach-bcmring/include/mach/reg_nand.h
@@ -30,7 +30,7 @@
 #define __ASM_ARCH_REG_NAND_H
 
 /* ---- Include Files ---------------------------------------------------- */
-#include <csp/reg.h>
+#include <mach/csp/reg.h>
 #include <mach/reg_umi.h>
 
 /* ---- Constants and Types ---------------------------------------------- */
diff --git a/arch/arm/mach-bcmring/include/mach/reg_umi.h b/arch/arm/mach-bcmring/include/mach/reg_umi.h
index 0992842..56dd9de 100644
--- a/arch/arm/mach-bcmring/include/mach/reg_umi.h
+++ b/arch/arm/mach-bcmring/include/mach/reg_umi.h
@@ -30,7 +30,7 @@
 #define __ASM_ARCH_REG_UMI_H
 
 /* ---- Include Files ---------------------------------------------------- */
-#include <csp/reg.h>
+#include <mach/csp/reg.h>
 #include <mach/csp/mm_io.h>
 
 /* ---- Constants and Types ---------------------------------------------- */
@@ -233,5 +233,5 @@
 #define REG_UMI_BCH_ERR_LOC_WORD              0x00000018
 /* location within a page (512 byte) */
 #define REG_UMI_BCH_ERR_LOC_PAGE              0x00001FE0
-#define REG_UMI_BCH_ERR_LOC_ADDR(index)     (__REG32(HW_UMI_BASE + 0x64 + (index / 2)*4) >> ((index % 2) * 16))
+#define REG_UMI_BCH_ERR_LOC_ADDR(index)     (readl(HW_UMI_BASE + 0x64 + (index / 2)*4) >> ((index % 2) * 16))
 #endif
diff --git a/arch/arm/mach-bcmring/mm.c b/arch/arm/mach-bcmring/mm.c
index 1adec78e..33824a8 100644
--- a/arch/arm/mach-bcmring/mm.c
+++ b/arch/arm/mach-bcmring/mm.c
@@ -20,12 +20,12 @@
 #include <mach/hardware.h>
 #include <mach/csp/mm_io.h>
 
-#define IO_DESC(va, sz) { .virtual = va, \
+#define IO_DESC(va, sz) { .virtual = (unsigned long)va, \
 	.pfn = __phys_to_pfn(HW_IO_VIRT_TO_PHYS(va)), \
 	.length = sz, \
 	.type = MT_DEVICE }
 
-#define MEM_DESC(va, sz) { .virtual = va, \
+#define MEM_DESC(va, sz) { .virtual = (unsigned long)va, \
 	.pfn = __phys_to_pfn(HW_IO_VIRT_TO_PHYS(va)), \
 	.length = sz, \
 	.type = MT_MEMORY }
diff --git a/arch/arm/mach-bcmring/timer.c b/arch/arm/mach-bcmring/timer.c
index af9c3d7..5941290 100644
--- a/arch/arm/mach-bcmring/timer.c
+++ b/arch/arm/mach-bcmring/timer.c
@@ -14,7 +14,7 @@
 
 #include <linux/types.h>
 #include <linux/module.h>
-#include <csp/tmrHw.h>
+#include <mach/csp/tmrHw.h>
 
 #include <mach/timer.h>
 /* The core.c file initializes timers 1 and 3 as a linux clocksource. */
diff --git a/arch/arm/mach-clps711x/Makefile b/arch/arm/mach-clps711x/Makefile
index f2f0256..5872b49 100644
--- a/arch/arm/mach-clps711x/Makefile
+++ b/arch/arm/mach-clps711x/Makefile
@@ -16,5 +16,3 @@ obj-$(CONFIG_ARCH_CLEP7312) += clep7312.o
 obj-$(CONFIG_ARCH_EDB7211)  += edb7211-arch.o edb7211-mm.o
 obj-$(CONFIG_ARCH_FORTUNET) += fortunet.o
 obj-$(CONFIG_ARCH_P720T)    += p720t.o
-leds-$(CONFIG_ARCH_P720T)   += p720t-leds.o
-obj-$(CONFIG_LEDS)          += $(leds-y)
diff --git a/arch/arm/mach-clps711x/autcpu12.c b/arch/arm/mach-clps711x/autcpu12.c
index 3fb79a1..3287191 100644
--- a/arch/arm/mach-clps711x/autcpu12.c
+++ b/arch/arm/mach-clps711x/autcpu12.c
@@ -23,6 +23,8 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
 
 #include <mach/hardware.h>
 #include <asm/sizes.h>
@@ -62,9 +64,26 @@ void __init autcpu12_map_io(void)
         iotable_init(autcpu12_io_desc, ARRAY_SIZE(autcpu12_io_desc));
 }
 
+static struct resource autcpu12_nvram_resource[] __initdata = {
+	DEFINE_RES_MEM_NAMED(AUTCPU12_PHYS_NVRAM, SZ_128K, "SRAM"),
+};
+
+static struct platform_device autcpu12_nvram_pdev __initdata = {
+	.name		= "autcpu12_nvram",
+	.id		= -1,
+	.resource	= autcpu12_nvram_resource,
+	.num_resources	= ARRAY_SIZE(autcpu12_nvram_resource),
+};
+
+static void __init autcpu12_init(void)
+{
+	platform_device_register(&autcpu12_nvram_pdev);
+}
+
 MACHINE_START(AUTCPU12, "autronix autcpu12")
 	/* Maintainer: Thomas Gleixner */
 	.atag_offset	= 0x20000,
+	.init_machine	= autcpu12_init,
 	.map_io		= autcpu12_map_io,
 	.init_irq	= clps711x_init_irq,
 	.timer		= &clps711x_timer,
diff --git a/arch/arm/mach-clps711x/common.c b/arch/arm/mach-clps711x/common.c
index f15293b..3a4af00 100644
--- a/arch/arm/mach-clps711x/common.c
+++ b/arch/arm/mach-clps711x/common.c
@@ -30,7 +30,6 @@
 #include <asm/sizes.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/mach/map.h>
diff --git a/arch/arm/mach-clps711x/p720t-leds.c b/arch/arm/mach-clps711x/p720t-leds.c
deleted file mode 100644
index bbc449f..0000000
--- a/arch/arm/mach-clps711x/p720t-leds.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- *  linux/arch/arm/mach-clps711x/leds.c
- *
- *  Integrator LED control routines
- *
- *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-static void p720t_leds_event(led_event_t ledevt)
-{
-	unsigned long flags;
-	u32 pddr;
-
-	local_irq_save(flags);
-	switch(ledevt) {
-	case led_idle_start:
-		break;
-
-	case led_idle_end:
-		break;
-
-	case led_timer:
-		pddr = clps_readb(PDDR);
-		clps_writeb(pddr ^ 1, PDDR);
-		break;
-
-	default:
-		break;
-	}
-
-	local_irq_restore(flags);
-}
-
-static int __init leds_init(void)
-{
-	if (machine_is_p720t())
-		leds_event = p720t_leds_event;
-
-	return 0;
-}
-
-arch_initcall(leds_init);
diff --git a/arch/arm/mach-clps711x/p720t.c b/arch/arm/mach-clps711x/p720t.c
index f266d90..b752b58 100644
--- a/arch/arm/mach-clps711x/p720t.c
+++ b/arch/arm/mach-clps711x/p720t.c
@@ -23,6 +23,8 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
 #include <mach/hardware.h>
 #include <asm/pgtable.h>
@@ -34,6 +36,8 @@
 #include <asm/mach/map.h>
 #include <mach/syspld.h>
 
+#include <asm/hardware/clps7111.h>
+
 #include "common.h"
 
 /*
@@ -107,6 +111,64 @@ static void __init p720t_init_early(void)
 	}
 }
 
+/*
+ * LED controled by CPLD
+ */
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+static void p720t_led_set(struct led_classdev *cdev,
+			      enum led_brightness b)
+{
+	u8 reg = clps_readb(PDDR);
+
+	if (b != LED_OFF)
+		reg |= 0x1;
+	else
+		reg &= ~0x1;
+
+	clps_writeb(reg, PDDR);
+}
+
+static enum led_brightness p720t_led_get(struct led_classdev *cdev)
+{
+	u8 reg = clps_readb(PDDR);
+
+	return (reg & 0x1) ? LED_FULL : LED_OFF;
+}
+
+static int __init p720t_leds_init(void)
+{
+
+	struct led_classdev *cdev;
+	int ret;
+
+	if (!machine_is_p720t())
+		return -ENODEV;
+
+	cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+	if (!cdev)
+		return -ENOMEM;
+
+	cdev->name = "p720t:0";
+	cdev->brightness_set = p720t_led_set;
+	cdev->brightness_get = p720t_led_get;
+	cdev->default_trigger = "heartbeat";
+
+	ret = led_classdev_register(NULL, cdev);
+	if (ret	< 0) {
+		kfree(cdev);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(p720t_leds_init);
+#endif
+
 MACHINE_START(P720T, "ARM-Prospector720T")
 	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
 	.atag_offset	= 0x100,
diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c
index 4db5de5..bd54d7b 100644
--- a/arch/arm/mach-dove/common.c
+++ b/arch/arm/mach-dove/common.c
@@ -49,16 +49,6 @@ static struct map_desc dove_io_desc[] __initdata = {
 		.pfn		= __phys_to_pfn(DOVE_NB_REGS_PHYS_BASE),
 		.length		= DOVE_NB_REGS_SIZE,
 		.type		= MT_DEVICE,
-	}, {
-		.virtual	= DOVE_PCIE0_IO_VIRT_BASE,
-		.pfn		= __phys_to_pfn(DOVE_PCIE0_IO_PHYS_BASE),
-		.length		= DOVE_PCIE0_IO_SIZE,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= DOVE_PCIE1_IO_VIRT_BASE,
-		.pfn		= __phys_to_pfn(DOVE_PCIE1_IO_PHYS_BASE),
-		.length		= DOVE_PCIE1_IO_SIZE,
-		.type		= MT_DEVICE,
 	},
 };
 
@@ -102,7 +92,8 @@ void __init dove_ehci1_init(void)
 void __init dove_ge00_init(struct mv643xx_eth_platform_data *eth_data)
 {
 	orion_ge00_init(eth_data, DOVE_GE00_PHYS_BASE,
-			IRQ_DOVE_GE00_SUM, IRQ_DOVE_GE00_ERR);
+			IRQ_DOVE_GE00_SUM, IRQ_DOVE_GE00_ERR,
+			1600);
 }
 
 /*****************************************************************************
@@ -288,7 +279,7 @@ void __init dove_init(void)
 	printk(KERN_INFO "TCLK = %dMHz\n", (get_tclk() + 499999) / 1000000);
 
 #ifdef CONFIG_CACHE_TAUROS2
-	tauros2_init();
+	tauros2_init(0);
 #endif
 	dove_setup_cpu_mbus();
 
diff --git a/arch/arm/mach-dove/include/mach/dove.h b/arch/arm/mach-dove/include/mach/dove.h
index d52b0ef..c91e300 100644
--- a/arch/arm/mach-dove/include/mach/dove.h
+++ b/arch/arm/mach-dove/include/mach/dove.h
@@ -50,14 +50,12 @@
 #define DOVE_NB_REGS_SIZE		SZ_8M
 
 #define DOVE_PCIE0_IO_PHYS_BASE		0xf2000000
-#define DOVE_PCIE0_IO_VIRT_BASE		0xfee00000
 #define DOVE_PCIE0_IO_BUS_BASE		0x00000000
-#define DOVE_PCIE0_IO_SIZE		SZ_1M
+#define DOVE_PCIE0_IO_SIZE		SZ_64K
 
 #define DOVE_PCIE1_IO_PHYS_BASE		0xf2100000
-#define DOVE_PCIE1_IO_VIRT_BASE		0xfef00000
-#define DOVE_PCIE1_IO_BUS_BASE		0x00100000
-#define DOVE_PCIE1_IO_SIZE		SZ_1M
+#define DOVE_PCIE1_IO_BUS_BASE		0x00010000
+#define DOVE_PCIE1_IO_SIZE		SZ_64K
 
 /*
  * Dove Core Registers Map
diff --git a/arch/arm/mach-dove/include/mach/io.h b/arch/arm/mach-dove/include/mach/io.h
deleted file mode 100644
index 29c8b85..0000000
--- a/arch/arm/mach-dove/include/mach/io.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-dove/include/mach/io.h
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#include "dove.h"
-
-#define IO_SPACE_LIMIT		0xffffffff
-
-#define __io(a)  	((void __iomem *)(((a) - DOVE_PCIE0_IO_BUS_BASE) + \
-						 DOVE_PCIE0_IO_VIRT_BASE))
-
-#endif
diff --git a/arch/arm/mach-dove/pcie.c b/arch/arm/mach-dove/pcie.c
index 47921b0..355332d 100644
--- a/arch/arm/mach-dove/pcie.c
+++ b/arch/arm/mach-dove/pcie.c
@@ -26,9 +26,8 @@ struct pcie_port {
 	u8			root_bus_nr;
 	void __iomem		*base;
 	spinlock_t		conf_lock;
-	char			io_space_name[16];
 	char			mem_space_name[16];
-	struct resource		res[2];
+	struct resource		res;
 };
 
 static struct pcie_port pcie_port[2];
@@ -53,24 +52,10 @@ static int __init dove_pcie_setup(int nr, struct pci_sys_data *sys)
 
 	orion_pcie_setup(pp->base);
 
-	/*
-	 * IORESOURCE_IO
-	 */
-	snprintf(pp->io_space_name, sizeof(pp->io_space_name),
-		 "PCIe %d I/O", pp->index);
-	pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0;
-	pp->res[0].name = pp->io_space_name;
-	if (pp->index == 0) {
-		pp->res[0].start = DOVE_PCIE0_IO_PHYS_BASE;
-		pp->res[0].end = pp->res[0].start + DOVE_PCIE0_IO_SIZE - 1;
-	} else {
-		pp->res[0].start = DOVE_PCIE1_IO_PHYS_BASE;
-		pp->res[0].end = pp->res[0].start + DOVE_PCIE1_IO_SIZE - 1;
-	}
-	pp->res[0].flags = IORESOURCE_IO;
-	if (request_resource(&ioport_resource, &pp->res[0]))
-		panic("Request PCIe IO resource failed\n");
-	pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
+	if (pp->index == 0)
+		pci_ioremap_io(sys->busnr * SZ_64K, DOVE_PCIE0_IO_PHYS_BASE);
+	else
+		pci_ioremap_io(sys->busnr * SZ_64K, DOVE_PCIE1_IO_PHYS_BASE);
 
 	/*
 	 * IORESOURCE_MEM
@@ -78,18 +63,18 @@ static int __init dove_pcie_setup(int nr, struct pci_sys_data *sys)
 	snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
 		 "PCIe %d MEM", pp->index);
 	pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
-	pp->res[1].name = pp->mem_space_name;
+	pp->res.name = pp->mem_space_name;
 	if (pp->index == 0) {
-		pp->res[1].start = DOVE_PCIE0_MEM_PHYS_BASE;
-		pp->res[1].end = pp->res[1].start + DOVE_PCIE0_MEM_SIZE - 1;
+		pp->res.start = DOVE_PCIE0_MEM_PHYS_BASE;
+		pp->res.end = pp->res.start + DOVE_PCIE0_MEM_SIZE - 1;
 	} else {
-		pp->res[1].start = DOVE_PCIE1_MEM_PHYS_BASE;
-		pp->res[1].end = pp->res[1].start + DOVE_PCIE1_MEM_SIZE - 1;
+		pp->res.start = DOVE_PCIE1_MEM_PHYS_BASE;
+		pp->res.end = pp->res.start + DOVE_PCIE1_MEM_SIZE - 1;
 	}
-	pp->res[1].flags = IORESOURCE_MEM;
-	if (request_resource(&iomem_resource, &pp->res[1]))
+	pp->res.flags = IORESOURCE_MEM;
+	if (request_resource(&iomem_resource, &pp->res))
 		panic("Request PCIe Memory resource failed\n");
-	pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, &pp->res, sys->mem_offset);
 
 	return 1;
 }
@@ -210,7 +195,7 @@ static void __init add_pcie_port(int index, unsigned long base)
 		pp->root_bus_nr = -1;
 		pp->base = (void __iomem *)base;
 		spin_lock_init(&pp->conf_lock);
-		memset(pp->res, 0, sizeof(pp->res));
+		memset(&pp->res, 0, sizeof(pp->res));
 	} else {
 		printk(KERN_INFO "link down, ignoring\n");
 	}
diff --git a/arch/arm/mach-ebsa110/Makefile b/arch/arm/mach-ebsa110/Makefile
index 6520ac8..935e4af 100644
--- a/arch/arm/mach-ebsa110/Makefile
+++ b/arch/arm/mach-ebsa110/Makefile
@@ -4,9 +4,7 @@
 
 # Object file lists.
 
-obj-y			:= core.o io.o
+obj-y			:= core.o io.o leds.o
 obj-m			:=
 obj-n			:=
 obj-			:=
-
-obj-$(CONFIG_LEDS)	+= leds.o
diff --git a/arch/arm/mach-ebsa110/leds.c b/arch/arm/mach-ebsa110/leds.c
index 99e14e3..0398258 100644
--- a/arch/arm/mach-ebsa110/leds.c
+++ b/arch/arm/mach-ebsa110/leds.c
@@ -1,52 +1,71 @@
 /*
- *  linux/arch/arm/mach-ebsa110/leds.c
+ * Driver for the LED found on the EBSA110 machine
+ * Based on Versatile and RealView machine LED code
  *
- *  Copyright (C) 1998 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  EBSA-110 LED control routines.  We use the led as follows:
- *
- *   - Red - toggles state every 50 timer interrupts
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Bryan Wu <bryan.wu@canonical.com>
  */
-#include <linux/module.h>
-#include <linux/spinlock.h>
+#include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
-#include <mach/hardware.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 
 #include "core.h"
 
-static spinlock_t leds_lock;
-
-static void ebsa110_leds_event(led_event_t ledevt)
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+static void ebsa110_led_set(struct led_classdev *cdev,
+			      enum led_brightness b)
 {
-	unsigned long flags;
+	u8 reg = __raw_readb(SOFT_BASE);
 
-	spin_lock_irqsave(&leds_lock, flags);
+	if (b != LED_OFF)
+		reg |= 0x80;
+	else
+		reg &= ~0x80;
 
-	switch(ledevt) {
-	case led_timer:
-		*(volatile unsigned char *)SOFT_BASE ^= 128;
-		break;
+	__raw_writeb(reg, SOFT_BASE);
+}
 
-	default:
-		break;
-	}
+static enum led_brightness ebsa110_led_get(struct led_classdev *cdev)
+{
+	u8 reg = __raw_readb(SOFT_BASE);
 
-	spin_unlock_irqrestore(&leds_lock, flags);
+	return (reg & 0x80) ? LED_FULL : LED_OFF;
 }
 
-static int __init leds_init(void)
+static int __init ebsa110_leds_init(void)
 {
-	if (machine_is_ebsa110())
-		leds_event = ebsa110_leds_event;
+
+	struct led_classdev *cdev;
+	int ret;
+
+	if (!machine_is_ebsa110())
+		return -ENODEV;
+
+	cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+	if (!cdev)
+		return -ENOMEM;
+
+	cdev->name = "ebsa110:0";
+	cdev->brightness_set = ebsa110_led_set;
+	cdev->brightness_get = ebsa110_led_get;
+	cdev->default_trigger = "heartbeat";
+
+	ret = led_classdev_register(NULL, cdev);
+	if (ret	< 0) {
+		kfree(cdev);
+		return ret;
+	}
 
 	return 0;
 }
 
-__initcall(leds_init);
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(ebsa110_leds_init);
+#endif
diff --git a/arch/arm/mach-exynos/clock-exynos5.c b/arch/arm/mach-exynos/clock-exynos5.c
index 774533c..3b00e29 100644
--- a/arch/arm/mach-exynos/clock-exynos5.c
+++ b/arch/arm/mach-exynos/clock-exynos5.c
@@ -166,11 +166,6 @@ static int exynos5_clk_ip_gen_ctrl(struct clk *clk, int enable)
 	return s5p_gatectrl(EXYNOS5_CLKGATE_IP_GEN, clk, enable);
 }
 
-static int exynos5_clk_ip_gps_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(EXYNOS5_CLKGATE_IP_GPS, clk, enable);
-}
-
 static int exynos5_clk_ip_mfc_ctrl(struct clk *clk, int enable)
 {
 	return s5p_gatectrl(EXYNOS5_CLKGATE_IP_MFC, clk, enable);
@@ -672,10 +667,6 @@ static struct clk exynos5_init_clocks_off[] = {
 		.enable		= exynos5_clk_ip_fsys_ctrl,
 		.ctrlbit	= (1 << 7),
 	}, {
-		.name		= "gps",
-		.enable		= exynos5_clk_ip_gps_ctrl,
-		.ctrlbit	= ((1 << 3) | (1 << 2) | (1 << 0)),
-	}, {
 		.name		= "nfcon",
 		.enable		= exynos5_clk_ip_fsys_ctrl,
 		.ctrlbit	= (1 << 22),
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index c72b675..9d1f3ac 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -131,7 +131,6 @@
 #define EXYNOS5_PA_SYSMMU_JPEG		0x11F20000
 #define EXYNOS5_PA_SYSMMU_IOP		0x12360000
 #define EXYNOS5_PA_SYSMMU_RTIC		0x12370000
-#define EXYNOS5_PA_SYSMMU_GPS		0x12630000
 #define EXYNOS5_PA_SYSMMU_ISP		0x13260000
 #define EXYNOS5_PA_SYSMMU_DRC		0x12370000
 #define EXYNOS5_PA_SYSMMU_SCALERC	0x13280000
diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
index ea785fc..90d8daa 100644
--- a/arch/arm/mach-exynos/mach-nuri.c
+++ b/arch/arm/mach-exynos/mach-nuri.c
@@ -29,6 +29,7 @@
 #include <drm/exynos_drm.h>
 
 #include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
 #include <media/m5mols.h>
 #include <media/s5k6aa.h>
 #include <media/s5p_fimc.h>
@@ -39,7 +40,6 @@
 #include <asm/mach-types.h>
 
 #include <plat/adc.h>
-#include <plat/regs-fb-v4.h>
 #include <plat/regs-serial.h>
 #include <plat/cpu.h>
 #include <plat/devs.h>
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
index 5ca8030..5ec563b 100644
--- a/arch/arm/mach-exynos/mach-origen.c
+++ b/arch/arm/mach-exynos/mach-origen.c
@@ -29,9 +29,9 @@
 #include <asm/mach-types.h>
 
 #include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
 
 #include <plat/regs-serial.h>
-#include <plat/regs-fb-v4.h>
 #include <plat/cpu.h>
 #include <plat/devs.h>
 #include <plat/sdhci.h>
@@ -42,6 +42,7 @@
 #include <plat/backlight.h>
 #include <plat/fb.h>
 #include <plat/mfc.h>
+#include <plat/hdmi.h>
 
 #include <mach/ohci.h>
 #include <mach/map.h>
@@ -734,6 +735,11 @@ static void __init origen_bt_setup(void)
 	s3c_gpio_setpull(EXYNOS4_GPX2(2), S3C_GPIO_PULL_NONE);
 }
 
+/* I2C module and id for HDMIPHY */
+static struct i2c_board_info hdmiphy_info = {
+	I2C_BOARD_INFO("hdmiphy-exynos4210", 0x38),
+};
+
 static void s5p_tv_setup(void)
 {
 	/* Direct HPD to HDMI chip */
@@ -781,6 +787,7 @@ static void __init origen_machine_init(void)
 
 	s5p_tv_setup();
 	s5p_i2c_hdmiphy_set_platdata(NULL);
+	s5p_hdmi_set_platdata(&hdmiphy_info, NULL, 0);
 
 #ifdef CONFIG_DRM_EXYNOS
 	s5p_device_fimd0.dev.platform_data = &drm_fimd_pdata;
diff --git a/arch/arm/mach-exynos/mach-smdk4x12.c b/arch/arm/mach-exynos/mach-smdk4x12.c
index b26beb1..ee069b4 100644
--- a/arch/arm/mach-exynos/mach-smdk4x12.c
+++ b/arch/arm/mach-exynos/mach-smdk4x12.c
@@ -26,6 +26,7 @@
 #include <asm/hardware/gic.h>
 #include <asm/mach-types.h>
 
+#include <video/samsung_fimd.h>
 #include <plat/backlight.h>
 #include <plat/clock.h>
 #include <plat/cpu.h>
@@ -35,7 +36,6 @@
 #include <plat/iic.h>
 #include <plat/keypad.h>
 #include <plat/mfc.h>
-#include <plat/regs-fb.h>
 #include <plat/regs-serial.h>
 #include <plat/sdhci.h>
 
diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c
index 3cfa688..208aa62 100644
--- a/arch/arm/mach-exynos/mach-smdkv310.c
+++ b/arch/arm/mach-exynos/mach-smdkv310.c
@@ -26,9 +26,9 @@
 #include <asm/mach-types.h>
 
 #include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
 #include <plat/regs-serial.h>
 #include <plat/regs-srom.h>
-#include <plat/regs-fb-v4.h>
 #include <plat/cpu.h>
 #include <plat/devs.h>
 #include <plat/fb.h>
@@ -40,6 +40,7 @@
 #include <plat/mfc.h>
 #include <plat/ehci.h>
 #include <plat/clock.h>
+#include <plat/hdmi.h>
 
 #include <mach/map.h>
 #include <mach/ohci.h>
@@ -354,6 +355,11 @@ static struct platform_pwm_backlight_data smdkv310_bl_data = {
 	.pwm_period_ns  = 1000,
 };
 
+/* I2C module and id for HDMIPHY */
+static struct i2c_board_info hdmiphy_info = {
+	I2C_BOARD_INFO("hdmiphy-exynos4210", 0x38),
+};
+
 static void s5p_tv_setup(void)
 {
 	/* direct HPD to HDMI chip */
@@ -388,6 +394,7 @@ static void __init smdkv310_machine_init(void)
 
 	s5p_tv_setup();
 	s5p_i2c_hdmiphy_set_platdata(NULL);
+	s5p_hdmi_set_platdata(&hdmiphy_info, NULL, 0);
 
 	samsung_keypad_set_platdata(&smdkv310_keypad_data);
 
diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c
index 4d1f40d..8139cd2 100644
--- a/arch/arm/mach-exynos/mach-universal_c210.c
+++ b/arch/arm/mach-exynos/mach-universal_c210.c
@@ -30,6 +30,7 @@
 #include <asm/hardware/gic.h>
 #include <asm/mach-types.h>
 
+#include <video/samsung_fimd.h>
 #include <plat/regs-serial.h>
 #include <plat/clock.h>
 #include <plat/cpu.h>
@@ -39,7 +40,6 @@
 #include <plat/fb.h>
 #include <plat/mfc.h>
 #include <plat/sdhci.h>
-#include <plat/regs-fb-v4.h>
 #include <plat/fimc-core.h>
 #include <plat/s5p-time.h>
 #include <plat/camport.h>
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index 36c3984..090e32b 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -139,7 +139,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 
 		__raw_writel(virt_to_phys(exynos4_secondary_startup),
 			CPU1_BOOT_REG);
-		gic_raise_softirq(cpumask_of(cpu), 1);
+		gic_raise_softirq(cpumask_of(cpu), 0);
 
 		if (pen_release == -1)
 			break;
diff --git a/arch/arm/mach-exynos/setup-fimd0.c b/arch/arm/mach-exynos/setup-fimd0.c
index 07a6dbe..5665bb4 100644
--- a/arch/arm/mach-exynos/setup-fimd0.c
+++ b/arch/arm/mach-exynos/setup-fimd0.c
@@ -13,8 +13,8 @@
 #include <linux/fb.h>
 #include <linux/gpio.h>
 
+#include <video/samsung_fimd.h>
 #include <plat/gpio-cfg.h>
-#include <plat/regs-fb-v4.h>
 
 #include <mach/map.h>
 
diff --git a/arch/arm/mach-footbridge/Makefile b/arch/arm/mach-footbridge/Makefile
index 3afb1b2..0b64dd4 100644
--- a/arch/arm/mach-footbridge/Makefile
+++ b/arch/arm/mach-footbridge/Makefile
@@ -14,15 +14,11 @@ pci-$(CONFIG_ARCH_EBSA285_HOST) += ebsa285-pci.o
 pci-$(CONFIG_ARCH_NETWINDER) += netwinder-pci.o
 pci-$(CONFIG_ARCH_PERSONAL_SERVER) += personal-pci.o
 
-leds-$(CONFIG_ARCH_EBSA285) += ebsa285-leds.o
-leds-$(CONFIG_ARCH_NETWINDER) += netwinder-leds.o
-
 obj-$(CONFIG_ARCH_CATS) += cats-hw.o isa-timer.o
 obj-$(CONFIG_ARCH_EBSA285) += ebsa285.o dc21285-timer.o
 obj-$(CONFIG_ARCH_NETWINDER) += netwinder-hw.o isa-timer.o
 obj-$(CONFIG_ARCH_PERSONAL_SERVER) += personal.o dc21285-timer.o
 
 obj-$(CONFIG_PCI)	+=$(pci-y)
-obj-$(CONFIG_LEDS)	+=$(leds-y)
 
 obj-$(CONFIG_ISA)	+= isa.o isa-rtc.o
diff --git a/arch/arm/mach-footbridge/common.c b/arch/arm/mach-footbridge/common.c
index 3e6aaa6..a42b369 100644
--- a/arch/arm/mach-footbridge/common.c
+++ b/arch/arm/mach-footbridge/common.c
@@ -15,7 +15,7 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/spinlock.h>
- 
+
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/irq.h>
@@ -26,6 +26,7 @@
 
 #include <asm/mach/irq.h>
 #include <asm/mach/map.h>
+#include <asm/mach/pci.h>
 
 #include "common.h"
 
@@ -175,11 +176,6 @@ static struct map_desc ebsa285_host_io_desc[] __initdata = {
 		.pfn		= __phys_to_pfn(DC21285_PCI_IACK),
 		.length		= PCIIACK_SIZE,
 		.type		= MT_DEVICE,
-	}, {
-		.virtual	= PCIO_BASE,
-		.pfn		= __phys_to_pfn(DC21285_PCI_IO),
-		.length		= PCIO_SIZE,
-		.type		= MT_DEVICE,
 	},
 #endif
 };
@@ -196,8 +192,10 @@ void __init footbridge_map_io(void)
 	 * Now, work out what we've got to map in addition on this
 	 * platform.
 	 */
-	if (footbridge_cfn_mode())
+	if (footbridge_cfn_mode()) {
 		iotable_init(ebsa285_host_io_desc, ARRAY_SIZE(ebsa285_host_io_desc));
+		pci_map_io_early(__phys_to_pfn(DC21285_PCI_IO));
+	}
 }
 
 void footbridge_restart(char mode, const char *cmd)
diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c
index 9d62e33..a7cd2cf 100644
--- a/arch/arm/mach-footbridge/dc21285.c
+++ b/arch/arm/mach-footbridge/dc21285.c
@@ -276,8 +276,8 @@ int __init dc21285_setup(int nr, struct pci_sys_data *sys)
 
 	sys->mem_offset  = DC21285_PCI_MEM;
 
-	pci_add_resource_offset(&sys->resources,
-				&ioport_resource, sys->io_offset);
+	pci_ioremap_io(0, DC21285_PCI_IO);
+
 	pci_add_resource_offset(&sys->resources, &res[0], sys->mem_offset);
 	pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
 
@@ -298,7 +298,7 @@ void __init dc21285_preinit(void)
 	mem_size = (unsigned int)high_memory - PAGE_OFFSET;
 	for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1)
 		if (mem_mask >= mem_size)
-			break;		
+			break;
 
 	/*
 	 * These registers need to be set up whether we're the
@@ -350,14 +350,6 @@ void __init dc21285_preinit(void)
 			    "PCI data parity", NULL);
 
 	if (cfn_mode) {
-		static struct resource csrio;
-
-		csrio.flags  = IORESOURCE_IO;
-		csrio.name   = "Footbridge";
-
-		allocate_resource(&ioport_resource, &csrio, 128,
-				  0xff00, 0xffff, 128, NULL, NULL);
-
 		/*
 		 * Map our SDRAM at a known address in PCI space, just in case
 		 * the firmware had other ideas.  Using a nonzero base is
@@ -365,7 +357,7 @@ void __init dc21285_preinit(void)
 		 * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards).
 		 */
 		*CSR_PCICSRBASE       = 0xf4000000;
-		*CSR_PCICSRIOBASE     = csrio.start;
+		*CSR_PCICSRIOBASE     = 0;
 		*CSR_PCISDRAMBASE     = __virt_to_bus(PAGE_OFFSET);
 		*CSR_PCIROMBASE       = 0;
 		*CSR_PCICMD = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
diff --git a/arch/arm/mach-footbridge/ebsa285-leds.c b/arch/arm/mach-footbridge/ebsa285-leds.c
deleted file mode 100644
index 5bd2667..0000000
--- a/arch/arm/mach-footbridge/ebsa285-leds.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- *  linux/arch/arm/mach-footbridge/ebsa285-leds.c
- *
- *  Copyright (C) 1998-1999 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- * EBSA-285 control routines.
- *
- * The EBSA-285 uses the leds as follows:
- *  - Green - toggles state every 50 timer interrupts
- *  - Amber - On if system is not idle
- *  - Red   - currently unused
- *
- * Changelog:
- *   02-05-1999	RMK	Various cleanups
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-static char led_state;
-static char hw_led_state;
-
-static DEFINE_SPINLOCK(leds_lock);
-
-static void ebsa285_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&leds_lock, flags);
-
-	switch (evt) {
-	case led_start:
-		hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN;
-#ifndef CONFIG_LEDS_CPU
-		hw_led_state |= XBUS_LED_AMBER;
-#endif
-		led_state |= LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state ^= XBUS_LED_GREEN;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= XBUS_LED_AMBER;
-		break;
-
-	case led_idle_end:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~XBUS_LED_AMBER;
-		break;
-#endif
-
-	case led_halted:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~XBUS_LED_RED;
-		break;
-
-	case led_green_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~XBUS_LED_GREEN;
-		break;
-
-	case led_green_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= XBUS_LED_GREEN;
-		break;
-
-	case led_amber_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~XBUS_LED_AMBER;
-		break;
-
-	case led_amber_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= XBUS_LED_AMBER;
-		break;
-
-	case led_red_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~XBUS_LED_RED;
-		break;
-
-	case led_red_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= XBUS_LED_RED;
-		break;
-
-	default:
-		break;
-	}
-
-	if  (led_state & LED_STATE_ENABLED)
-		*XBUS_LEDS = hw_led_state;
-
-	spin_unlock_irqrestore(&leds_lock, flags);
-}
-
-static int __init leds_init(void)
-{
-	if (machine_is_ebsa285())
-		leds_event = ebsa285_leds_event;
-
-	leds_event(led_start);
-
-	return 0;
-}
-
-__initcall(leds_init);
diff --git a/arch/arm/mach-footbridge/ebsa285.c b/arch/arm/mach-footbridge/ebsa285.c
index 27716a7..b09551e 100644
--- a/arch/arm/mach-footbridge/ebsa285.c
+++ b/arch/arm/mach-footbridge/ebsa285.c
@@ -5,6 +5,8 @@
  */
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
 #include <asm/hardware/dec21285.h>
 #include <asm/mach-types.h>
@@ -13,6 +15,85 @@
 
 #include "common.h"
 
+/* LEDs */
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct ebsa285_led {
+	struct led_classdev     cdev;
+	u8                      mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+	const char *name;
+	const char *trigger;
+} ebsa285_leds[] = {
+	{ "ebsa285:amber", "heartbeat", },
+	{ "ebsa285:green", "cpu0", },
+	{ "ebsa285:red",},
+};
+
+static void ebsa285_led_set(struct led_classdev *cdev,
+		enum led_brightness b)
+{
+	struct ebsa285_led *led = container_of(cdev,
+			struct ebsa285_led, cdev);
+
+	if (b != LED_OFF)
+		*XBUS_LEDS |= led->mask;
+	else
+		*XBUS_LEDS &= ~led->mask;
+}
+
+static enum led_brightness ebsa285_led_get(struct led_classdev *cdev)
+{
+	struct ebsa285_led *led = container_of(cdev,
+			struct ebsa285_led, cdev);
+
+	return (*XBUS_LEDS & led->mask) ? LED_FULL : LED_OFF;
+}
+
+static int __init ebsa285_leds_init(void)
+{
+	int i;
+
+	if (machine_is_ebsa285())
+		return -ENODEV;
+
+	/* 3 LEDS All ON */
+	*XBUS_LEDS |= XBUS_LED_AMBER | XBUS_LED_GREEN | XBUS_LED_RED;
+
+	for (i = 0; i < ARRAY_SIZE(ebsa285_leds); i++) {
+		struct ebsa285_led *led;
+
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
+
+		led->cdev.name = ebsa285_leds[i].name;
+		led->cdev.brightness_set = ebsa285_led_set;
+		led->cdev.brightness_get = ebsa285_led_get;
+		led->cdev.default_trigger = ebsa285_leds[i].trigger;
+		led->mask = BIT(i);
+
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(ebsa285_leds_init);
+#endif
+
 MACHINE_START(EBSA285, "EBSA285")
 	/* Maintainer: Russell King */
 	.atag_offset	= 0x100,
diff --git a/arch/arm/mach-footbridge/include/mach/debug-macro.S b/arch/arm/mach-footbridge/include/mach/debug-macro.S
index e5acde2..c169f0c 100644
--- a/arch/arm/mach-footbridge/include/mach/debug-macro.S
+++ b/arch/arm/mach-footbridge/include/mach/debug-macro.S
@@ -17,7 +17,8 @@
 	/* For NetWinder debugging */
 		.macro	addruart, rp, rv, tmp
 		mov	\rp, #0x000003f8
-		orr	\rv, \rp, #0xff000000	@ virtual
+		orr	\rv, \rp, #0xfe000000	@ virtual
+		orr	\rv, \rv, #0x00e00000	@ virtual
 		orr	\rp, \rp, #0x7c000000	@ physical
 		.endm
 
diff --git a/arch/arm/mach-footbridge/include/mach/io.h b/arch/arm/mach-footbridge/include/mach/io.h
index aba531ee..aba4638 100644
--- a/arch/arm/mach-footbridge/include/mach/io.h
+++ b/arch/arm/mach-footbridge/include/mach/io.h
@@ -14,18 +14,10 @@
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
 
-#ifdef CONFIG_MMU
-#define MMU_IO(a, b)	(a)
-#else
-#define MMU_IO(a, b)	(b)
-#endif
-
-#define PCIO_SIZE       0x00100000
-#define PCIO_BASE       MMU_IO(0xff000000, 0x7c000000)
-
 /*
- * Translation of various region addresses to virtual addresses
+ * Translation of various i/o addresses to host addresses for !CONFIG_MMU
  */
+#define PCIO_BASE       0x7c000000
 #define __io(a)			((void __iomem *)(PCIO_BASE + (a)))
 
 #endif
diff --git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c
index cac9f67..d2d1433 100644
--- a/arch/arm/mach-footbridge/netwinder-hw.c
+++ b/arch/arm/mach-footbridge/netwinder-hw.c
@@ -12,9 +12,10 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
 #include <asm/hardware/dec21285.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
 #include <asm/system_misc.h>
@@ -27,13 +28,6 @@
 #define GP1_IO_BASE		0x338
 #define GP2_IO_BASE		0x33a
 
-
-#ifdef CONFIG_LEDS
-#define DEFAULT_LEDS	0
-#else
-#define DEFAULT_LEDS	GPIO_GREEN_LED
-#endif
-
 /*
  * Winbond WB83977F accessibility stuff
  */
@@ -611,15 +605,9 @@ static void __init rwa010_init(void)
 static int __init nw_hw_init(void)
 {
 	if (machine_is_netwinder()) {
-		unsigned long flags;
-
 		wb977_init();
 		cpld_init();
 		rwa010_init();
-
-		raw_spin_lock_irqsave(&nw_gpio_lock, flags);
-		nw_gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS);
-		raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
 	}
 	return 0;
 }
@@ -672,6 +660,102 @@ static void netwinder_restart(char mode, const char *cmd)
 	}
 }
 
+/* LEDs */
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct netwinder_led {
+	struct led_classdev     cdev;
+	u8                      mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+	const char *name;
+	const char *trigger;
+} netwinder_leds[] = {
+	{ "netwinder:green", "heartbeat", },
+	{ "netwinder:red", "cpu0", },
+};
+
+/*
+ * The LED control in Netwinder is reversed:
+ *  - setting bit means turn off LED
+ *  - clearing bit means turn on LED
+ */
+static void netwinder_led_set(struct led_classdev *cdev,
+		enum led_brightness b)
+{
+	struct netwinder_led *led = container_of(cdev,
+			struct netwinder_led, cdev);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&nw_gpio_lock, flags);
+	reg = nw_gpio_read();
+	if (b != LED_OFF)
+		reg &= ~led->mask;
+	else
+		reg |= led->mask;
+	nw_gpio_modify_op(led->mask, reg);
+	spin_unlock_irqrestore(&nw_gpio_lock, flags);
+}
+
+static enum led_brightness netwinder_led_get(struct led_classdev *cdev)
+{
+	struct netwinder_led *led = container_of(cdev,
+			struct netwinder_led, cdev);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&nw_gpio_lock, flags);
+	reg = nw_gpio_read();
+	spin_unlock_irqrestore(&nw_gpio_lock, flags);
+
+	return (reg & led->mask) ? LED_OFF : LED_FULL;
+}
+
+static int __init netwinder_leds_init(void)
+{
+	int i;
+
+	if (!machine_is_netwinder())
+		return -ENODEV;
+
+	for (i = 0; i < ARRAY_SIZE(netwinder_leds); i++) {
+		struct netwinder_led *led;
+
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
+
+		led->cdev.name = netwinder_leds[i].name;
+		led->cdev.brightness_set = netwinder_led_set;
+		led->cdev.brightness_get = netwinder_led_get;
+		led->cdev.default_trigger = netwinder_leds[i].trigger;
+
+		if (i == 0)
+			led->mask = GPIO_GREEN_LED;
+		else
+			led->mask = GPIO_RED_LED;
+
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(netwinder_leds_init);
+#endif
+
 MACHINE_START(NETWINDER, "Rebel-NetWinder")
 	/* Maintainer: Russell King/Rebel.com */
 	.atag_offset	= 0x100,
diff --git a/arch/arm/mach-footbridge/netwinder-leds.c b/arch/arm/mach-footbridge/netwinder-leds.c
deleted file mode 100644
index 5a2bd89..0000000
--- a/arch/arm/mach-footbridge/netwinder-leds.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- *  linux/arch/arm/mach-footbridge/netwinder-leds.c
- *
- *  Copyright (C) 1998-1999 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * NetWinder LED control routines.
- *
- * The Netwinder uses the leds as follows:
- *  - Green - toggles state every 50 timer interrupts
- *  - Red   - On if the system is not idle
- *
- * Changelog:
- *   02-05-1999	RMK	Various cleanups
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-static char led_state;
-static char hw_led_state;
-
-static DEFINE_RAW_SPINLOCK(leds_lock);
-
-static void netwinder_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	raw_spin_lock_irqsave(&leds_lock, flags);
-
-	switch (evt) {
-	case led_start:
-		led_state |= LED_STATE_ENABLED;
-		hw_led_state = GPIO_GREEN_LED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state ^= GPIO_GREEN_LED;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~GPIO_RED_LED;
-		break;
-
-	case led_idle_end:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= GPIO_RED_LED;
-		break;
-#endif
-
-	case led_halted:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= GPIO_RED_LED;
-		break;
-
-	case led_green_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= GPIO_GREEN_LED;
-		break;
-
-	case led_green_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~GPIO_GREEN_LED;
-		break;
-
-	case led_amber_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= GPIO_GREEN_LED | GPIO_RED_LED;
-		break;
-
-	case led_amber_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~(GPIO_GREEN_LED | GPIO_RED_LED);
-		break;
-
-	case led_red_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= GPIO_RED_LED;
-		break;
-
-	case led_red_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~GPIO_RED_LED;
-		break;
-
-	default:
-		break;
-	}
-
-	raw_spin_unlock_irqrestore(&leds_lock, flags);
-
-	if  (led_state & LED_STATE_ENABLED) {
-		raw_spin_lock_irqsave(&nw_gpio_lock, flags);
-		nw_gpio_modify_op(GPIO_RED_LED | GPIO_GREEN_LED, hw_led_state);
-		raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
-	}
-}
-
-static int __init leds_init(void)
-{
-	if (machine_is_netwinder())
-		leds_event = netwinder_leds_event;
-
-	leds_event(led_start);
-
-	return 0;
-}
-
-__initcall(leds_init);
diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c
index f69ca46..3b6b640 100644
--- a/arch/arm/mach-imx/clk-imx27.c
+++ b/arch/arm/mach-imx/clk-imx27.c
@@ -239,8 +239,8 @@ int __init mx27_clocks_init(unsigned long fref)
 	clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "imx-ssi.0");
 	clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "imx-ssi.1");
 	clk_register_clkdev(clk[nfc_baud_gate], NULL, "mxc_nand.0");
-	clk_register_clkdev(clk[vpu_baud_gate], "per", "imx-vpu");
-	clk_register_clkdev(clk[vpu_ahb_gate], "ahb", "imx-vpu");
+	clk_register_clkdev(clk[vpu_baud_gate], "per", "coda-imx27.0");
+	clk_register_clkdev(clk[vpu_ahb_gate], "ahb", "coda-imx27.0");
 	clk_register_clkdev(clk[dma_ahb_gate], "ahb", "imx-dma");
 	clk_register_clkdev(clk[dma_ipg_gate], "ipg", "imx-dma");
 	clk_register_clkdev(clk[fec_ipg_gate], "ipg", "imx27-fec.0");
diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c
index 4bdcaa9..e81f17a 100644
--- a/arch/arm/mach-imx/clk-imx51-imx53.c
+++ b/arch/arm/mach-imx/clk-imx51-imx53.c
@@ -367,6 +367,7 @@ int __init mx51_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,
 	clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "83fcc000.ssi");
 	clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "70014000.ssi");
 	clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "83fe8000.ssi");
+	clk_register_clkdev(clk[nfc_gate], NULL, "83fdb000.nand");
 
 	/* set the usboh3 parent to pll2_sw */
 	clk_set_parent(clk[usboh3_sel], clk[pll2_sw]);
@@ -455,6 +456,7 @@ int __init mx53_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,
 	clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "63fcc000.ssi");
 	clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "50014000.ssi");
 	clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "63fd0000.ssi");
+	clk_register_clkdev(clk[nfc_gate], NULL, "63fdb000.nand");
 
 	/* set SDHC root clock to 200MHZ*/
 	clk_set_rate(clk[esdhc_a_podf], 200000000);
diff --git a/arch/arm/mach-imx/devices-imx27.h b/arch/arm/mach-imx/devices-imx27.h
index 436c572..0482293 100644
--- a/arch/arm/mach-imx/devices-imx27.h
+++ b/arch/arm/mach-imx/devices-imx27.h
@@ -17,6 +17,10 @@ extern const struct imx_fsl_usb2_udc_data imx27_fsl_usb2_udc_data;
 #define imx27_add_fsl_usb2_udc(pdata)	\
 	imx_add_fsl_usb2_udc(&imx27_fsl_usb2_udc_data, pdata)
 
+extern const struct imx_imx27_coda_data imx27_coda_data;
+#define imx27_add_coda()	\
+	imx_add_imx27_coda(&imx27_coda_data)
+
 extern const struct imx_imx2_wdt_data imx27_imx2_wdt_data;
 #define imx27_add_imx2_wdt()	\
 	imx_add_imx2_wdt(&imx27_imx2_wdt_data)
diff --git a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
index f264ddd..821d6aa 100644
--- a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
+++ b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
@@ -32,13 +32,13 @@
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/leds.h>
-#include <linux/memblock.h>
 #include <media/soc_camera.h>
 #include <sound/tlv320aic32x4.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/system_info.h>
+#include <asm/memblock.h>
 #include <mach/common.h>
 #include <mach/hardware.h>
 #include <mach/iomux-mx27.h>
@@ -233,10 +233,8 @@ static void __init visstrim_camera_init(void)
 static void __init visstrim_reserve(void)
 {
 	/* reserve 4 MiB for mx2-camera */
-	mx2_camera_base = memblock_alloc(MX2_CAMERA_BUF_SIZE,
+	mx2_camera_base = arm_memblock_steal(3 * MX2_CAMERA_BUF_SIZE,
 			MX2_CAMERA_BUF_SIZE);
-	memblock_free(mx2_camera_base, MX2_CAMERA_BUF_SIZE);
-	memblock_remove(mx2_camera_base, MX2_CAMERA_BUF_SIZE);
 }
 
 /* GPIOs used as events for applications */
@@ -405,6 +403,47 @@ static const struct imx_ssi_platform_data visstrim_m10_ssi_pdata __initconst = {
 	.flags			= IMX_SSI_DMA | IMX_SSI_SYN,
 };
 
+/* coda */
+
+static void __init visstrim_coda_init(void)
+{
+	struct platform_device *pdev;
+	int dma;
+
+	pdev = imx27_add_coda();
+	dma = dma_declare_coherent_memory(&pdev->dev,
+					  mx2_camera_base + MX2_CAMERA_BUF_SIZE,
+					  mx2_camera_base + MX2_CAMERA_BUF_SIZE,
+					  MX2_CAMERA_BUF_SIZE,
+					  DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
+	if (!(dma & DMA_MEMORY_MAP))
+		return;
+}
+
+/* DMA deinterlace */
+static struct platform_device visstrim_deinterlace = {
+	.name = "m2m-deinterlace",
+	.id = 0,
+};
+
+static void __init visstrim_deinterlace_init(void)
+{
+	int ret = -ENOMEM;
+	struct platform_device *pdev = &visstrim_deinterlace;
+	int dma;
+
+	ret = platform_device_register(pdev);
+
+	dma = dma_declare_coherent_memory(&pdev->dev,
+					  mx2_camera_base + 2 * MX2_CAMERA_BUF_SIZE,
+					  mx2_camera_base + 2 * MX2_CAMERA_BUF_SIZE,
+					  MX2_CAMERA_BUF_SIZE,
+					  DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
+	if (!(dma & DMA_MEMORY_MAP))
+		return;
+}
+
+
 static void __init visstrim_m10_revision(void)
 {
 	int exp_version = 0;
@@ -467,7 +506,9 @@ static void __init visstrim_m10_board_init(void)
 	platform_device_register_resndata(NULL, "soc-camera-pdrv", 0, NULL, 0,
 				      &iclink_tvp5150, sizeof(iclink_tvp5150));
 	gpio_led_register_device(0, &visstrim_m10_led_data);
+	visstrim_deinterlace_init();
 	visstrim_camera_init();
+	visstrim_coda_init();
 }
 
 static void __init visstrim_m10_timer_init(void)
diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile
index ebeef96..5521d18 100644
--- a/arch/arm/mach-integrator/Makefile
+++ b/arch/arm/mach-integrator/Makefile
@@ -4,11 +4,10 @@
 
 # Object file lists.
 
-obj-y					:= core.o lm.o
+obj-y					:= core.o lm.o leds.o
 obj-$(CONFIG_ARCH_INTEGRATOR_AP)	+= integrator_ap.o
 obj-$(CONFIG_ARCH_INTEGRATOR_CP)	+= integrator_cp.o
 
-obj-$(CONFIG_LEDS)			+= leds.o
 obj-$(CONFIG_PCI)			+= pci_v3.o pci.o
 obj-$(CONFIG_CPU_FREQ_INTEGRATOR)	+= cpu.o
 obj-$(CONFIG_INTEGRATOR_IMPD1)		+= impd1.o
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index 3fa6c51..2af5034 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -28,7 +28,6 @@
 #include <mach/cm.h>
 #include <mach/irqs.h>
 
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/mach/time.h>
 #include <asm/pgtable.h>
@@ -128,8 +127,6 @@ static struct amba_pl010_data integrator_uart_data = {
 	.set_mctrl = integrator_uart_set_mctrl,
 };
 
-#define CM_CTRL	IO_ADDRESS(INTEGRATOR_HDR_CTRL)
-
 static DEFINE_RAW_SPINLOCK(cm_lock);
 
 /**
diff --git a/arch/arm/mach-integrator/include/mach/cm.h b/arch/arm/mach-integrator/include/mach/cm.h
index 445d57a..1a78692e 100644
--- a/arch/arm/mach-integrator/include/mach/cm.h
+++ b/arch/arm/mach-integrator/include/mach/cm.h
@@ -3,6 +3,8 @@
  */
 void cm_control(u32, u32);
 
+#define CM_CTRL	IO_ADDRESS(INTEGRATOR_HDR_CTRL)
+
 #define CM_CTRL_LED			(1 << 0)
 #define CM_CTRL_nMBDET			(1 << 1)
 #define CM_CTRL_REMAP			(1 << 2)
diff --git a/arch/arm/mach-integrator/include/mach/io.h b/arch/arm/mach-integrator/include/mach/io.h
deleted file mode 100644
index 8de70de..0000000
--- a/arch/arm/mach-integrator/include/mach/io.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *  arch/arm/mach-integrator/include/mach/io.h
- *
- *  Copyright (C) 1999 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/*
- * WARNING: this has to mirror definitions in platform.h
- */
-#define PCI_MEMORY_VADDR        0xe8000000
-#define PCI_CONFIG_VADDR        0xec000000
-#define PCI_V3_VADDR            0xed000000
-#define PCI_IO_VADDR            0xee000000
-
-#define __io(a)			((void __iomem *)(PCI_IO_VADDR + (a)))
-
-#endif
diff --git a/arch/arm/mach-integrator/include/mach/platform.h b/arch/arm/mach-integrator/include/mach/platform.h
index ec467ba..4c03475 100644
--- a/arch/arm/mach-integrator/include/mach/platform.h
+++ b/arch/arm/mach-integrator/include/mach/platform.h
@@ -324,6 +324,10 @@
  */
 #define PHYS_PCI_V3_BASE                0x62000000
 
+#define PCI_MEMORY_VADDR		0xe8000000
+#define PCI_CONFIG_VADDR		0xec000000
+#define PCI_V3_VADDR			0xed000000
+
 /* ------------------------------------------------------------------------
  *  Integrator Interrupt Controllers
  * ------------------------------------------------------------------------
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 3b22675..fd3ef28 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -50,6 +50,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/map.h>
+#include <asm/mach/pci.h>
 #include <asm/mach/time.h>
 
 #include <plat/fpga-irq.h>
@@ -73,7 +74,7 @@
  * e8000000	40000000	PCI memory		PHYS_PCI_MEM_BASE	(max 512M)
  * ec000000	61000000	PCI config space	PHYS_PCI_CONFIG_BASE	(max 16M)
  * ed000000	62000000	PCI V3 regs		PHYS_PCI_V3_BASE	(max 64k)
- * ee000000	60000000	PCI IO			PHYS_PCI_IO_BASE	(max 16M)
+ * fee00000	60000000	PCI IO			PHYS_PCI_IO_BASE	(max 16M)
  * ef000000			Cache flush
  * f1000000	10000000	Core module registers
  * f1100000	11000000	System controller registers
@@ -147,11 +148,6 @@ static struct map_desc ap_io_desc[] __initdata = {
 		.pfn		= __phys_to_pfn(PHYS_PCI_V3_BASE),
 		.length		= SZ_64K,
 		.type		= MT_DEVICE
-	}, {
-		.virtual	= PCI_IO_VADDR,
-		.pfn		= __phys_to_pfn(PHYS_PCI_IO_BASE),
-		.length		= SZ_64K,
-		.type		= MT_DEVICE
 	}
 };
 
@@ -159,6 +155,7 @@ static void __init ap_map_io(void)
 {
 	iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc));
 	vga_base = PCI_MEMORY_VADDR;
+	pci_map_io_early(__phys_to_pfn(PHYS_PCI_IO_BASE));
 }
 
 #define INTEGRATOR_SC_VALID_INT	0x003fffff
diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c
index 466defa..7a7f6d3 100644
--- a/arch/arm/mach-integrator/leds.c
+++ b/arch/arm/mach-integrator/leds.c
@@ -1,90 +1,125 @@
 /*
- *  linux/arch/arm/mach-integrator/leds.c
+ * Driver for the 4 user LEDs found on the Integrator AP/CP baseboard
+ * Based on Versatile and RealView machine LED code
  *
- *  Integrator/AP and Integrator/CP LED control routines
- *
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Bryan Wu <bryan.wu@canonical.com>
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/spinlock.h>
 #include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
+#include <mach/cm.h>
 #include <mach/hardware.h>
 #include <mach/platform.h>
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-#include <mach/cm.h>
 
-static int saved_leds;
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+
+#define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE)
+#define LEDREG	(__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET)
 
-static void integrator_leds_event(led_event_t ledevt)
+struct integrator_led {
+	struct led_classdev	cdev;
+	u8			mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+	const char *name;
+	const char *trigger;
+} integrator_leds[] = {
+	{ "integrator:green0", "heartbeat", },
+	{ "integrator:yellow", },
+	{ "integrator:red", },
+	{ "integrator:green1", },
+	{ "integrator:core_module", "cpu0", },
+};
+
+static void integrator_led_set(struct led_classdev *cdev,
+			      enum led_brightness b)
 {
-	unsigned long flags;
-	const unsigned int dbg_base = IO_ADDRESS(INTEGRATOR_DBG_BASE);
-	unsigned int update_alpha_leds;
+	struct integrator_led *led = container_of(cdev,
+						 struct integrator_led, cdev);
+	u32 reg = __raw_readl(LEDREG);
 
-	// yup, change the LEDs
-	local_irq_save(flags);
-	update_alpha_leds = 0;
+	if (b != LED_OFF)
+		reg |= led->mask;
+	else
+		reg &= ~led->mask;
 
-	switch(ledevt) {
-	case led_idle_start:
-		cm_control(CM_CTRL_LED, 0);
-		break;
+	while (__raw_readl(ALPHA_REG) & 1)
+		cpu_relax();
 
-	case led_idle_end:
-		cm_control(CM_CTRL_LED, CM_CTRL_LED);
-		break;
+	__raw_writel(reg, LEDREG);
+}
 
-	case led_timer:
-		saved_leds ^= GREEN_LED;
-		update_alpha_leds = 1;
-		break;
+static enum led_brightness integrator_led_get(struct led_classdev *cdev)
+{
+	struct integrator_led *led = container_of(cdev,
+						 struct integrator_led, cdev);
+	u32 reg = __raw_readl(LEDREG);
 
-	case led_red_on:
-		saved_leds |= RED_LED;
-		update_alpha_leds = 1;
-		break;
+	return (reg & led->mask) ? LED_FULL : LED_OFF;
+}
 
-	case led_red_off:
-		saved_leds &= ~RED_LED;
-		update_alpha_leds = 1;
-		break;
+static void cm_led_set(struct led_classdev *cdev,
+			      enum led_brightness b)
+{
+	if (b != LED_OFF)
+		cm_control(CM_CTRL_LED, CM_CTRL_LED);
+	else
+		cm_control(CM_CTRL_LED, 0);
+}
 
-	default:
-		break;
-	}
+static enum led_brightness cm_led_get(struct led_classdev *cdev)
+{
+	u32 reg = readl(CM_CTRL);
 
-	if (update_alpha_leds) {
-		while (__raw_readl(dbg_base + INTEGRATOR_DBG_ALPHA_OFFSET) & 1);
-		__raw_writel(saved_leds, dbg_base + INTEGRATOR_DBG_LEDS_OFFSET);
-	}
-	local_irq_restore(flags);
+	return (reg & CM_CTRL_LED) ? LED_FULL : LED_OFF;
 }
 
-static int __init leds_init(void)
+static int __init integrator_leds_init(void)
 {
-	if (machine_is_integrator() || machine_is_cintegrator())
-		leds_event = integrator_leds_event;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(integrator_leds); i++) {
+		struct integrator_led *led;
+
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
+
+
+		led->cdev.name = integrator_leds[i].name;
+
+		if (i == 4) { /* Setting for LED in core module */
+			led->cdev.brightness_set = cm_led_set;
+			led->cdev.brightness_get = cm_led_get;
+		} else {
+			led->cdev.brightness_set = integrator_led_set;
+			led->cdev.brightness_get = integrator_led_get;
+		}
+
+		led->cdev.default_trigger = integrator_leds[i].trigger;
+		led->mask = BIT(i);
+
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
+	}
 
 	return 0;
 }
 
-core_initcall(leds_init);
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(integrator_leds_init);
+#endif
diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
index b866880..495f181 100644
--- a/arch/arm/mach-integrator/pci_v3.c
+++ b/arch/arm/mach-integrator/pci_v3.c
@@ -41,61 +41,61 @@
 /*
  * The V3 PCI interface chip in Integrator provides several windows from
  * local bus memory into the PCI memory areas.   Unfortunately, there
- * are not really enough windows for our usage, therefore we reuse 
+ * are not really enough windows for our usage, therefore we reuse
  * one of the windows for access to PCI configuration space.  The
  * memory map is as follows:
- * 
+ *
  * Local Bus Memory         Usage
- * 
+ *
  * 40000000 - 4FFFFFFF      PCI memory.  256M non-prefetchable
  * 50000000 - 5FFFFFFF      PCI memory.  256M prefetchable
  * 60000000 - 60FFFFFF      PCI IO.  16M
  * 61000000 - 61FFFFFF      PCI Configuration. 16M
- * 
+ *
  * There are three V3 windows, each described by a pair of V3 registers.
  * These are LB_BASE0/LB_MAP0, LB_BASE1/LB_MAP1 and LB_BASE2/LB_MAP2.
  * Base0 and Base1 can be used for any type of PCI memory access.   Base2
  * can be used either for PCI I/O or for I20 accesses.  By default, uHAL
  * uses this only for PCI IO space.
- * 
+ *
  * Normally these spaces are mapped using the following base registers:
- * 
+ *
  * Usage Local Bus Memory         Base/Map registers used
- * 
+ *
  * Mem   40000000 - 4FFFFFFF      LB_BASE0/LB_MAP0
  * Mem   50000000 - 5FFFFFFF      LB_BASE1/LB_MAP1
  * IO    60000000 - 60FFFFFF      LB_BASE2/LB_MAP2
  * Cfg   61000000 - 61FFFFFF
- * 
+ *
  * This means that I20 and PCI configuration space accesses will fail.
- * When PCI configuration accesses are needed (via the uHAL PCI 
+ * When PCI configuration accesses are needed (via the uHAL PCI
  * configuration space primitives) we must remap the spaces as follows:
- * 
+ *
  * Usage Local Bus Memory         Base/Map registers used
- * 
+ *
  * Mem   40000000 - 4FFFFFFF      LB_BASE0/LB_MAP0
  * Mem   50000000 - 5FFFFFFF      LB_BASE0/LB_MAP0
  * IO    60000000 - 60FFFFFF      LB_BASE2/LB_MAP2
  * Cfg   61000000 - 61FFFFFF      LB_BASE1/LB_MAP1
- * 
+ *
  * To make this work, the code depends on overlapping windows working.
- * The V3 chip translates an address by checking its range within 
+ * The V3 chip translates an address by checking its range within
  * each of the BASE/MAP pairs in turn (in ascending register number
  * order).  It will use the first matching pair.   So, for example,
  * if the same address is mapped by both LB_BASE0/LB_MAP0 and
- * LB_BASE1/LB_MAP1, the V3 will use the translation from 
+ * LB_BASE1/LB_MAP1, the V3 will use the translation from
  * LB_BASE0/LB_MAP0.
- * 
+ *
  * To allow PCI Configuration space access, the code enlarges the
  * window mapped by LB_BASE0/LB_MAP0 from 256M to 512M.  This occludes
  * the windows currently mapped by LB_BASE1/LB_MAP1 so that it can
  * be remapped for use by configuration cycles.
- * 
- * At the end of the PCI Configuration space accesses, 
+ *
+ * At the end of the PCI Configuration space accesses,
  * LB_BASE1/LB_MAP1 is reset to map PCI Memory.  Finally the window
  * mapped by LB_BASE0/LB_MAP0 is reduced in size from 512M to 256M to
  * reveal the now restored LB_BASE1/LB_MAP1 window.
- * 
+ *
  * NOTE: We do not set up I2O mapping.  I suspect that this is only
  * for an intelligent (target) device.  Using I2O disables most of
  * the mappings into PCI memory.
@@ -127,8 +127,8 @@
  *
  * returns:	configuration address to play on the PCI bus
  *
- * To generate the appropriate PCI configuration cycles in the PCI 
- * configuration address space, you present the V3 with the following pattern 
+ * To generate the appropriate PCI configuration cycles in the PCI
+ * configuration address space, you present the V3 with the following pattern
  * (which is very nearly a type 1 (except that the lower two bits are 00 and
  * not 01).   In order for this mapping to work you need to set up one of
  * the local to PCI aperatures to 16Mbytes in length translating to
@@ -138,7 +138,7 @@
  *
  * Type 0:
  *
- *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
  *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
@@ -150,7 +150,7 @@
  *
  * Type 1:
  *
- *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
  *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
@@ -161,7 +161,7 @@
  *	15:11	Device number (5 bits)
  *	10:8	function number
  *	 7:2	register number
- *  
+ *
  */
 static DEFINE_RAW_SPINLOCK(v3_lock);
 
@@ -374,12 +374,9 @@ static int __init pci_v3_setup_resources(struct pci_sys_data *sys)
 	}
 
 	/*
-	 * the IO resource for this bus
 	 * the mem resource for this bus
 	 * the prefetch mem resource for this bus
 	 */
-	pci_add_resource_offset(&sys->resources,
-				&ioport_resource, sys->io_offset);
 	pci_add_resource_offset(&sys->resources, &non_mem, sys->mem_offset);
 	pci_add_resource_offset(&sys->resources, &pre_mem, sys->mem_offset);
 
@@ -498,7 +495,6 @@ void __init pci_v3_preinit(void)
 	unsigned int temp;
 	int ret;
 
-	pcibios_min_io = 0x6000;
 	pcibios_min_mem = 0x00100000;
 
 	/*
diff --git a/arch/arm/mach-iop13xx/include/mach/io.h b/arch/arm/mach-iop13xx/include/mach/io.h
deleted file mode 100644
index f131885..0000000
--- a/arch/arm/mach-iop13xx/include/mach/io.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * iop13xx custom ioremap implementation
- * Copyright (c) 2005-2006, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(a) __iop13xx_io(a)
-
-extern void __iomem * __iop13xx_io(unsigned long io_addr);
-
-#endif
diff --git a/arch/arm/mach-iop13xx/include/mach/iop13xx.h b/arch/arm/mach-iop13xx/include/mach/iop13xx.h
index e190dcd..e10e101 100644
--- a/arch/arm/mach-iop13xx/include/mach/iop13xx.h
+++ b/arch/arm/mach-iop13xx/include/mach/iop13xx.h
@@ -69,21 +69,11 @@ extern unsigned long get_iop_tick_rate(void);
  * 0x8000.0000 + 928M	0x2.8000.0000   (ioremap)	PCIE outbound memory window
  *
  * IO MAP
- * 0x1000 + 64K	0x0.fffb.1000	0xfec6.1000	PCIX outbound i/o window
- * 0x1000 + 64K	0x0.fffd.1000	0xfed7.1000	PCIE outbound i/o window
+ * 0x00000 + 64K	0x0.fffb.0000	0xfee0.0000	PCIX outbound i/o window
+ * 0x10000 + 64K	0x0.fffd.0000	0xfee1.0000	PCIE outbound i/o window
  */
-#define IOP13XX_PCIX_IO_WINDOW_SIZE   0x10000UL
 #define IOP13XX_PCIX_LOWER_IO_PA      0xfffb0000UL
-#define IOP13XX_PCIX_LOWER_IO_VA      0xfec60000UL
 #define IOP13XX_PCIX_LOWER_IO_BA      0x0UL /* OIOTVR */
-#define IOP13XX_PCIX_IO_BUS_OFFSET    0x1000UL
-#define IOP13XX_PCIX_UPPER_IO_PA      (IOP13XX_PCIX_LOWER_IO_PA +\
-				       IOP13XX_PCIX_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIX_UPPER_IO_VA      (IOP13XX_PCIX_LOWER_IO_VA +\
-				       IOP13XX_PCIX_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIX_IO_PHYS_TO_VIRT(addr) (u32) ((u32) addr -\
-					   (IOP13XX_PCIX_LOWER_IO_PA\
-					   - IOP13XX_PCIX_LOWER_IO_VA))
 
 #define IOP13XX_PCIX_MEM_PHYS_OFFSET  0x100000000ULL
 #define IOP13XX_PCIX_MEM_WINDOW_SIZE  0x3a000000UL
@@ -103,20 +93,8 @@ extern unsigned long get_iop_tick_rate(void);
 					IOP13XX_PCIX_LOWER_MEM_BA)
 
 /* PCI-E ranges */
-#define IOP13XX_PCIE_IO_WINDOW_SIZE   	 0x10000UL
 #define IOP13XX_PCIE_LOWER_IO_PA      	 0xfffd0000UL
-#define IOP13XX_PCIE_LOWER_IO_VA      	 0xfed70000UL
-#define IOP13XX_PCIE_LOWER_IO_BA      	 0x0UL  /* OIOTVR */
-#define IOP13XX_PCIE_IO_BUS_OFFSET	 0x1000UL
-#define IOP13XX_PCIE_UPPER_IO_PA      	 (IOP13XX_PCIE_LOWER_IO_PA +\
-					 IOP13XX_PCIE_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIE_UPPER_IO_VA      	 (IOP13XX_PCIE_LOWER_IO_VA +\
-					 IOP13XX_PCIE_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIE_UPPER_IO_BA      	 (IOP13XX_PCIE_LOWER_IO_BA +\
-					 IOP13XX_PCIE_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIE_IO_PHYS_TO_VIRT(addr) (u32) ((u32) addr -\
-					   (IOP13XX_PCIE_LOWER_IO_PA\
-					   - IOP13XX_PCIE_LOWER_IO_VA))
+#define IOP13XX_PCIE_LOWER_IO_BA	 0x10000UL  /* OIOTVR */
 
 #define IOP13XX_PCIE_MEM_PHYS_OFFSET  	 0x200000000ULL
 #define IOP13XX_PCIE_MEM_WINDOW_SIZE  	 0x3a000000UL
diff --git a/arch/arm/mach-iop13xx/io.c b/arch/arm/mach-iop13xx/io.c
index 3c36419..851dc8f 100644
--- a/arch/arm/mach-iop13xx/io.c
+++ b/arch/arm/mach-iop13xx/io.c
@@ -23,25 +23,6 @@
 
 #include "pci.h"
 
-void * __iomem __iop13xx_io(unsigned long io_addr)
-{
-	void __iomem * io_virt;
-
-	switch (io_addr) {
-	case IOP13XX_PCIE_LOWER_IO_PA ... IOP13XX_PCIE_UPPER_IO_PA:
-		io_virt = (void *) IOP13XX_PCIE_IO_PHYS_TO_VIRT(io_addr);
-		break;
-	case IOP13XX_PCIX_LOWER_IO_PA ... IOP13XX_PCIX_UPPER_IO_PA:
-		io_virt = (void *) IOP13XX_PCIX_IO_PHYS_TO_VIRT(io_addr);
-		break;
-	default:
-		BUG();
-	}
-
-	return io_virt;
-}
-EXPORT_SYMBOL(__iop13xx_io);
-
 static void __iomem *__iop13xx_ioremap_caller(unsigned long cookie,
 	size_t size, unsigned int mtype, void *caller)
 {
@@ -67,12 +48,6 @@ static void __iomem *__iop13xx_ioremap_caller(unsigned long cookie,
 				       (cookie - IOP13XX_PBI_LOWER_MEM_RA),
 				       size, mtype, __builtin_return_address(0));
 		break;
-	case IOP13XX_PCIE_LOWER_IO_PA ... IOP13XX_PCIE_UPPER_IO_PA:
-		retval = (void *) IOP13XX_PCIE_IO_PHYS_TO_VIRT(cookie);
-		break;
-	case IOP13XX_PCIX_LOWER_IO_PA ... IOP13XX_PCIX_UPPER_IO_PA:
-		retval = (void *) IOP13XX_PCIX_IO_PHYS_TO_VIRT(cookie);
-		break;
 	case IOP13XX_PMMR_PHYS_MEM_BASE ... IOP13XX_PMMR_UPPER_MEM_PA:
 		retval = (void *) IOP13XX_PMMR_PHYS_TO_VIRT(cookie);
 		break;
@@ -99,8 +74,6 @@ static void __iop13xx_iounmap(volatile void __iomem *addr)
 		    goto skip;
 
 	switch ((u32) addr) {
-	case IOP13XX_PCIE_LOWER_IO_VA ... IOP13XX_PCIE_UPPER_IO_VA:
-	case IOP13XX_PCIX_LOWER_IO_VA ... IOP13XX_PCIX_UPPER_IO_VA:
 	case IOP13XX_PMMR_VIRT_MEM_BASE ... IOP13XX_PMMR_UPPER_MEM_VA:
 		goto skip;
 	}
diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c
index 861cb12..91f731a 100644
--- a/arch/arm/mach-iop13xx/pci.c
+++ b/arch/arm/mach-iop13xx/pci.c
@@ -970,7 +970,6 @@ void __init iop13xx_pci_init(void)
 	__raw_writel(__raw_readl(IOP13XX_XBG_BECSR) & 3, IOP13XX_XBG_BECSR);
 
 	/* Setup the Min Address for PCI memory... */
-	pcibios_min_io = 0;
 	pcibios_min_mem = IOP13XX_PCIX_LOWER_MEM_BA;
 
 	/* if Linux is given control of an ATU
@@ -1003,7 +1002,7 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
 	if (nr > 1)
 		return 0;
 
-	res = kcalloc(2, sizeof(struct resource), GFP_KERNEL);
+	res = kzalloc(sizeof(struct resource), GFP_KERNEL);
 	if (!res)
 		panic("PCI: unable to alloc resources");
 
@@ -1042,17 +1041,13 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
 				  << IOP13XX_ATUX_PCIXSR_FUNC_NUM;
 		__raw_writel(pcixsr, IOP13XX_ATUX_PCIXSR);
 
-		res[0].start = IOP13XX_PCIX_LOWER_IO_PA + IOP13XX_PCIX_IO_BUS_OFFSET;
-		res[0].end   = IOP13XX_PCIX_UPPER_IO_PA;
-		res[0].name  = "IQ81340 ATUX PCI I/O Space";
-		res[0].flags = IORESOURCE_IO;
+		pci_ioremap_io(0, IOP13XX_PCIX_LOWER_IO_PA);
 
-		res[1].start = IOP13XX_PCIX_LOWER_MEM_RA;
-		res[1].end   = IOP13XX_PCIX_UPPER_MEM_RA;
-		res[1].name  = "IQ81340 ATUX PCI Memory Space";
-		res[1].flags = IORESOURCE_MEM;
+		res->start = IOP13XX_PCIX_LOWER_MEM_RA;
+		res->end   = IOP13XX_PCIX_UPPER_MEM_RA;
+		res->name  = "IQ81340 ATUX PCI Memory Space";
+		res->flags = IORESOURCE_MEM;
 		sys->mem_offset = IOP13XX_PCIX_MEM_OFFSET;
-		sys->io_offset = IOP13XX_PCIX_LOWER_IO_PA;
 		break;
 	case IOP13XX_INIT_ATU_ATUE:
 		/* Note: the function number field in the PCSR is ro */
@@ -1063,17 +1058,13 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
 
 		__raw_writel(pcsr, IOP13XX_ATUE_PCSR);
 
-		res[0].start = IOP13XX_PCIE_LOWER_IO_PA + IOP13XX_PCIE_IO_BUS_OFFSET;
-		res[0].end   = IOP13XX_PCIE_UPPER_IO_PA;
-		res[0].name  = "IQ81340 ATUE PCI I/O Space";
-		res[0].flags = IORESOURCE_IO;
+		pci_ioremap_io(SZ_64K, IOP13XX_PCIE_LOWER_IO_PA);
 
-		res[1].start = IOP13XX_PCIE_LOWER_MEM_RA;
-		res[1].end   = IOP13XX_PCIE_UPPER_MEM_RA;
-		res[1].name  = "IQ81340 ATUE PCI Memory Space";
-		res[1].flags = IORESOURCE_MEM;
+		res->start = IOP13XX_PCIE_LOWER_MEM_RA;
+		res->end   = IOP13XX_PCIE_UPPER_MEM_RA;
+		res->name  = "IQ81340 ATUE PCI Memory Space";
+		res->flags = IORESOURCE_MEM;
 		sys->mem_offset = IOP13XX_PCIE_MEM_OFFSET;
-		sys->io_offset = IOP13XX_PCIE_LOWER_IO_PA;
 		sys->map_irq = iop13xx_pcie_map_irq;
 		break;
 	default:
@@ -1081,11 +1072,9 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
 		return 0;
 	}
 
-	request_resource(&ioport_resource, &res[0]);
-	request_resource(&iomem_resource, &res[1]);
+	request_resource(&iomem_resource, res);
 
-	pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
-	pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, res, sys->mem_offset);
 
 	return 1;
 }
diff --git a/arch/arm/mach-iop13xx/setup.c b/arch/arm/mach-iop13xx/setup.c
index daabb1f..4a7f20d 100644
--- a/arch/arm/mach-iop13xx/setup.c
+++ b/arch/arm/mach-iop13xx/setup.c
@@ -40,16 +40,6 @@ static struct map_desc iop13xx_std_desc[] __initdata = {
 		.pfn 	 = __phys_to_pfn(IOP13XX_PMMR_PHYS_MEM_BASE),
 		.length  = IOP13XX_PMMR_SIZE,
 		.type	 = MT_DEVICE,
-	}, { /* PCIE IO space */
-		.virtual = IOP13XX_PCIE_LOWER_IO_VA,
-		.pfn 	 = __phys_to_pfn(IOP13XX_PCIE_LOWER_IO_PA),
-		.length  = IOP13XX_PCIX_IO_WINDOW_SIZE,
-		.type	 = MT_DEVICE,
-	}, { /* PCIX IO space */
-		.virtual = IOP13XX_PCIX_LOWER_IO_VA,
-		.pfn 	 = __phys_to_pfn(IOP13XX_PCIX_LOWER_IO_PA),
-		.length  = IOP13XX_PCIX_IO_WINDOW_SIZE,
-		.type	 = MT_DEVICE,
 	},
 };
 
diff --git a/arch/arm/mach-iop32x/include/mach/io.h b/arch/arm/mach-iop32x/include/mach/io.h
deleted file mode 100644
index e2ada26..0000000
--- a/arch/arm/mach-iop32x/include/mach/io.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-iop32x/include/mach/io.h
- *
- * Copyright (C) 2001 MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __IO_H
-#define __IO_H
-
-#include <asm/hardware/iop3xx.h>
-
-#define IO_SPACE_LIMIT		0xffffffff
-#define __io(p)		((void __iomem *)IOP3XX_PCI_IO_PHYS_TO_VIRT(p))
-
-#endif
diff --git a/arch/arm/mach-iop33x/include/mach/io.h b/arch/arm/mach-iop33x/include/mach/io.h
deleted file mode 100644
index f7c1b65..0000000
--- a/arch/arm/mach-iop33x/include/mach/io.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-iop33x/include/mach/io.h
- *
- * Copyright (C) 2001  MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __IO_H
-#define __IO_H
-
-#include <asm/hardware/iop3xx.h>
-
-#define IO_SPACE_LIMIT		0xffffffff
-#define __io(p)		((void __iomem *)IOP3XX_PCI_IO_PHYS_TO_VIRT(p))
-
-#endif
diff --git a/arch/arm/mach-kirkwood/Makefile.boot b/arch/arm/mach-kirkwood/Makefile.boot
index a571755..a13299d 100644
--- a/arch/arm/mach-kirkwood/Makefile.boot
+++ b/arch/arm/mach-kirkwood/Makefile.boot
@@ -7,7 +7,8 @@ dtb-$(CONFIG_MACH_DLINK_KIRKWOOD_DT) += kirkwood-dns320.dtb
 dtb-$(CONFIG_MACH_DLINK_KIRKWOOD_DT) += kirkwood-dns325.dtb
 dtb-$(CONFIG_MACH_ICONNECT_DT) += kirkwood-iconnect.dtb
 dtb-$(CONFIG_MACH_IB62X0_DT) += kirkwood-ib62x0.dtb
-dtb-$(CONFIG_MACH_TS219_DT)	+= kirkwood-qnap-ts219.dtb
+dtb-$(CONFIG_MACH_TS219_DT)	+= kirkwood-ts219-6281.dtb
+dtb-$(CONFIG_MACH_TS219_DT)	+= kirkwood-ts219-6282.dtb
 dtb-$(CONFIG_MACH_GOFLEXNET_DT) += kirkwood-goflexnet.dtb
 dtb-$(CONFIG_MACH_LSXL_DT) += kirkwood-lschlv2.dtb
 dtb-$(CONFIG_MACH_LSXL_DT) += kirkwood-lsxhl.dtb
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index c4b64ad..936b31d 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -42,16 +42,6 @@
  ****************************************************************************/
 static struct map_desc kirkwood_io_desc[] __initdata = {
 	{
-		.virtual	= KIRKWOOD_PCIE_IO_VIRT_BASE,
-		.pfn		= __phys_to_pfn(KIRKWOOD_PCIE_IO_PHYS_BASE),
-		.length		= KIRKWOOD_PCIE_IO_SIZE,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= KIRKWOOD_PCIE1_IO_VIRT_BASE,
-		.pfn		= __phys_to_pfn(KIRKWOOD_PCIE1_IO_PHYS_BASE),
-		.length		= KIRKWOOD_PCIE1_IO_SIZE,
-		.type		= MT_DEVICE,
-	}, {
 		.virtual	= KIRKWOOD_REGS_VIRT_BASE,
 		.pfn		= __phys_to_pfn(KIRKWOOD_REGS_PHYS_BASE),
 		.length		= KIRKWOOD_REGS_SIZE,
@@ -301,7 +291,7 @@ void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data)
 {
 	orion_ge00_init(eth_data,
 			GE00_PHYS_BASE, IRQ_KIRKWOOD_GE00_SUM,
-			IRQ_KIRKWOOD_GE00_ERR);
+			IRQ_KIRKWOOD_GE00_ERR, 1600);
 	/* The interface forgets the MAC address assigned by u-boot if
 	the clock is turned off, so claim the clk now. */
 	clk_prepare_enable(ge0);
@@ -315,7 +305,7 @@ void __init kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data)
 {
 	orion_ge01_init(eth_data,
 			GE01_PHYS_BASE, IRQ_KIRKWOOD_GE01_SUM,
-			IRQ_KIRKWOOD_GE01_ERR);
+			IRQ_KIRKWOOD_GE01_ERR, 1600);
 	clk_prepare_enable(ge1);
 }
 
diff --git a/arch/arm/mach-kirkwood/include/mach/io.h b/arch/arm/mach-kirkwood/include/mach/io.h
deleted file mode 100644
index 5d0ab61..0000000
--- a/arch/arm/mach-kirkwood/include/mach/io.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * arch/arm/mach-kirkwood/include/mach/io.h
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#include "kirkwood.h"
-
-#define IO_SPACE_LIMIT		0xffffffff
-
-static inline void __iomem *__io(unsigned long addr)
-{
-	return (void __iomem *)((addr - KIRKWOOD_PCIE_IO_BUS_BASE)
-					+ KIRKWOOD_PCIE_IO_VIRT_BASE);
-}
-
-#define __io(a)			__io(a)
-
-#endif
diff --git a/arch/arm/mach-kirkwood/include/mach/kirkwood.h b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
index c5b6851..af4f000 100644
--- a/arch/arm/mach-kirkwood/include/mach/kirkwood.h
+++ b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
@@ -37,14 +37,12 @@
 #define KIRKWOOD_NAND_MEM_SIZE		SZ_1K
 
 #define KIRKWOOD_PCIE1_IO_PHYS_BASE	0xf3000000
-#define KIRKWOOD_PCIE1_IO_VIRT_BASE	0xfef00000
-#define KIRKWOOD_PCIE1_IO_BUS_BASE	0x00100000
-#define KIRKWOOD_PCIE1_IO_SIZE		SZ_1M
+#define KIRKWOOD_PCIE1_IO_BUS_BASE	0x00010000
+#define KIRKWOOD_PCIE1_IO_SIZE		SZ_64K
 
 #define KIRKWOOD_PCIE_IO_PHYS_BASE	0xf2000000
-#define KIRKWOOD_PCIE_IO_VIRT_BASE	0xfee00000
 #define KIRKWOOD_PCIE_IO_BUS_BASE	0x00000000
-#define KIRKWOOD_PCIE_IO_SIZE		SZ_1M
+#define KIRKWOOD_PCIE_IO_SIZE		SZ_64K
 
 #define KIRKWOOD_REGS_PHYS_BASE		0xf1000000
 #define KIRKWOOD_REGS_VIRT_BASE		0xfed00000
diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c
index 6e8b2ef..532d8ac 100644
--- a/arch/arm/mach-kirkwood/pcie.c
+++ b/arch/arm/mach-kirkwood/pcie.c
@@ -56,7 +56,7 @@ struct pcie_port {
 	void __iomem		*base;
 	spinlock_t		conf_lock;
 	int			irq;
-	struct resource		res[2];
+	struct resource		res;
 };
 
 static int pcie_port_map[2];
@@ -137,20 +137,12 @@ static void __init pcie0_ioresources_init(struct pcie_port *pp)
 	pp->irq	= IRQ_KIRKWOOD_PCIE;
 
 	/*
-	 * IORESOURCE_IO
-	 */
-	pp->res[0].name = "PCIe 0 I/O Space";
-	pp->res[0].start = KIRKWOOD_PCIE_IO_BUS_BASE;
-	pp->res[0].end = pp->res[0].start + KIRKWOOD_PCIE_IO_SIZE - 1;
-	pp->res[0].flags = IORESOURCE_IO;
-
-	/*
 	 * IORESOURCE_MEM
 	 */
-	pp->res[1].name = "PCIe 0 MEM";
-	pp->res[1].start = KIRKWOOD_PCIE_MEM_PHYS_BASE;
-	pp->res[1].end = pp->res[1].start + KIRKWOOD_PCIE_MEM_SIZE - 1;
-	pp->res[1].flags = IORESOURCE_MEM;
+	pp->res.name = "PCIe 0 MEM";
+	pp->res.start = KIRKWOOD_PCIE_MEM_PHYS_BASE;
+	pp->res.end = pp->res.start + KIRKWOOD_PCIE_MEM_SIZE - 1;
+	pp->res.flags = IORESOURCE_MEM;
 }
 
 static void __init pcie1_ioresources_init(struct pcie_port *pp)
@@ -159,20 +151,12 @@ static void __init pcie1_ioresources_init(struct pcie_port *pp)
 	pp->irq	= IRQ_KIRKWOOD_PCIE1;
 
 	/*
-	 * IORESOURCE_IO
-	 */
-	pp->res[0].name = "PCIe 1 I/O Space";
-	pp->res[0].start = KIRKWOOD_PCIE1_IO_BUS_BASE;
-	pp->res[0].end = pp->res[0].start + KIRKWOOD_PCIE1_IO_SIZE - 1;
-	pp->res[0].flags = IORESOURCE_IO;
-
-	/*
 	 * IORESOURCE_MEM
 	 */
-	pp->res[1].name = "PCIe 1 MEM";
-	pp->res[1].start = KIRKWOOD_PCIE1_MEM_PHYS_BASE;
-	pp->res[1].end = pp->res[1].start + KIRKWOOD_PCIE1_MEM_SIZE - 1;
-	pp->res[1].flags = IORESOURCE_MEM;
+	pp->res.name = "PCIe 1 MEM";
+	pp->res.start = KIRKWOOD_PCIE1_MEM_PHYS_BASE;
+	pp->res.end = pp->res.start + KIRKWOOD_PCIE1_MEM_SIZE - 1;
+	pp->res.flags = IORESOURCE_MEM;
 }
 
 static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
@@ -197,23 +181,21 @@ static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
 	case 0:
 		kirkwood_enable_pcie_clk("0");
 		pcie0_ioresources_init(pp);
+		pci_ioremap_io(SZ_64K * sys->busnr, KIRKWOOD_PCIE_IO_PHYS_BASE);
 		break;
 	case 1:
 		kirkwood_enable_pcie_clk("1");
 		pcie1_ioresources_init(pp);
+		pci_ioremap_io(SZ_64K * sys->busnr, KIRKWOOD_PCIE1_IO_PHYS_BASE);
 		break;
 	default:
 		panic("PCIe setup: invalid controller %d", index);
 	}
 
-	if (request_resource(&ioport_resource, &pp->res[0]))
-		panic("Request PCIe%d IO resource failed\n", index);
-	if (request_resource(&iomem_resource, &pp->res[1]))
+	if (request_resource(&iomem_resource, &pp->res))
 		panic("Request PCIe%d Memory resource failed\n", index);
 
-	sys->io_offset = 0;
-	pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
-	pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, &pp->res, sys->mem_offset);
 
 	/*
 	 * Generic PCIe unit setup.
diff --git a/arch/arm/mach-ks8695/Makefile b/arch/arm/mach-ks8695/Makefile
index 853efd9..9324ef9 100644
--- a/arch/arm/mach-ks8695/Makefile
+++ b/arch/arm/mach-ks8695/Makefile
@@ -11,9 +11,6 @@ obj-				:=
 # PCI support is optional
 obj-$(CONFIG_PCI)		+= pci.o
 
-# LEDs
-obj-$(CONFIG_LEDS)		+= leds.o
-
 # Board-specific support
 obj-$(CONFIG_MACH_KS8695)	+= board-micrel.o
 obj-$(CONFIG_MACH_DSM320)	+= board-dsm320.o
diff --git a/arch/arm/mach-ks8695/devices.c b/arch/arm/mach-ks8695/devices.c
index 73bd638..47399bc 100644
--- a/arch/arm/mach-ks8695/devices.c
+++ b/arch/arm/mach-ks8695/devices.c
@@ -182,27 +182,6 @@ static void __init ks8695_add_device_watchdog(void)
 }
 
 
-/* --------------------------------------------------------------------
- *  LEDs
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_LEDS)
-short ks8695_leds_cpu = -1;
-short ks8695_leds_timer = -1;
-
-void __init ks8695_init_leds(u8 cpu_led, u8 timer_led)
-{
-	/* Enable GPIO to access the LEDs */
-	gpio_direction_output(cpu_led, 1);
-	gpio_direction_output(timer_led, 1);
-
-	ks8695_leds_cpu	  = cpu_led;
-	ks8695_leds_timer = timer_led;
-}
-#else
-void __init ks8695_init_leds(u8 cpu_led, u8 timer_led) {}
-#endif
-
 /* -------------------------------------------------------------------- */
 
 /*
diff --git a/arch/arm/mach-ks8695/include/mach/devices.h b/arch/arm/mach-ks8695/include/mach/devices.h
index 85a3c9a..1e6594a 100644
--- a/arch/arm/mach-ks8695/include/mach/devices.h
+++ b/arch/arm/mach-ks8695/include/mach/devices.h
@@ -18,11 +18,6 @@ extern void __init ks8695_add_device_wan(void);
 extern void __init ks8695_add_device_lan(void);
 extern void __init ks8695_add_device_hpna(void);
 
- /* LEDs */
-extern short ks8695_leds_cpu;
-extern short ks8695_leds_timer;
-extern void __init ks8695_init_leds(u8 cpu_led, u8 timer_led);
-
  /* PCI */
 #define KS8695_MODE_PCI		0
 #define KS8695_MODE_MINIPCI	1
diff --git a/arch/arm/mach-ks8695/leds.c b/arch/arm/mach-ks8695/leds.c
deleted file mode 100644
index 4bd7075..0000000
--- a/arch/arm/mach-ks8695/leds.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * LED driver for KS8695-based boards.
- *
- * Copyright (C) Andrew Victor
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/gpio.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <asm/leds.h>
-#include <mach/devices.h>
-
-
-static inline void ks8695_led_on(unsigned int led)
-{
-	gpio_set_value(led, 0);
-}
-
-static inline void ks8695_led_off(unsigned int led)
-{
-	gpio_set_value(led, 1);
-}
-
-static inline void ks8695_led_toggle(unsigned int led)
-{
-	unsigned long is_off = gpio_get_value(led);
-	if (is_off)
-		ks8695_led_on(led);
-	else
-		ks8695_led_off(led);
-}
-
-
-/*
- * Handle LED events.
- */
-static void ks8695_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch(evt) {
-	case led_start:		/* System startup */
-		ks8695_led_on(ks8695_leds_cpu);
-		break;
-
-	case led_stop:		/* System stop / suspend */
-		ks8695_led_off(ks8695_leds_cpu);
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:		/* Every 50 timer ticks */
-		ks8695_led_toggle(ks8695_leds_timer);
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:	/* Entering idle state */
-		ks8695_led_off(ks8695_leds_cpu);
-		break;
-
-	case led_idle_end:	/* Exit idle state */
-		ks8695_led_on(ks8695_leds_cpu);
-		break;
-#endif
-
-	default:
-		break;
-	}
-
-	local_irq_restore(flags);
-}
-
-
-static int __init leds_init(void)
-{
-	if ((ks8695_leds_timer == -1) || (ks8695_leds_cpu == -1))
-		return -ENODEV;
-
-	leds_event = ks8695_leds_event;
-
-	leds_event(led_start);
-	return 0;
-}
-
-__initcall(leds_init);
diff --git a/arch/arm/mach-mmp/mmp2.c b/arch/arm/mach-mmp/mmp2.c
index c709a24..c2bb95c 100644
--- a/arch/arm/mach-mmp/mmp2.c
+++ b/arch/arm/mach-mmp/mmp2.c
@@ -163,7 +163,7 @@ static int __init mmp2_init(void)
 {
 	if (cpu_is_mmp2()) {
 #ifdef CONFIG_CACHE_TAUROS2
-		tauros2_init();
+		tauros2_init(0);
 #endif
 		mfp_init_base(MFPR_VIRT_BASE);
 		mfp_init_addr(mmp2_addr_map);
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index 6da52e9..51ac8d1 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -14,6 +14,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 
+#include <asm/hardware/cache-tauros2.h>
 #include <asm/mach/time.h>
 #include <mach/addr-map.h>
 #include <mach/regs-apbc.h>
@@ -116,6 +117,9 @@ static struct clk_lookup pxa910_clkregs[] = {
 static int __init pxa910_init(void)
 {
 	if (cpu_is_pxa910()) {
+#ifdef CONFIG_CACHE_TAUROS2
+		tauros2_init(0);
+#endif
 		mfp_init_base(MFPR_VIRT_BASE);
 		mfp_init_addr(pxa910_mfp_addr_map);
 		pxa_init_dma(IRQ_PXA910_DMA_INT0, 32);
diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
index 7a7de2b..ce55fd8 100644
--- a/arch/arm/mach-mmp/ttc_dkb.c
+++ b/arch/arm/mach-mmp/ttc_dkb.c
@@ -177,12 +177,22 @@ static struct mv_usb_platform_data ttc_usb_pdata = {
 #endif
 #endif
 
+#ifdef CONFIG_MTD_NAND_PXA3xx
+static struct pxa3xx_nand_platform_data dkb_nand_info = {
+	.enable_arbiter = 1,
+	.num_cs = 1,
+};
+#endif
+
 static void __init ttc_dkb_init(void)
 {
 	mfp_config(ARRAY_AND_SIZE(ttc_dkb_pin_config));
 
 	/* on-chip devices */
 	pxa910_add_uart(1);
+#ifdef CONFIG_MTD_NAND_PXA3xx
+	pxa910_add_nand(&dkb_nand_info);
+#endif
 
 	/* off-chip devices */
 	pxa910_add_twsi(0, NULL, ARRAY_AND_SIZE(ttc_dkb_i2c_info));
diff --git a/arch/arm/mach-mv78xx0/addr-map.c b/arch/arm/mach-mv78xx0/addr-map.c
index 62b53d7..137e479 100644
--- a/arch/arm/mach-mv78xx0/addr-map.c
+++ b/arch/arm/mach-mv78xx0/addr-map.c
@@ -13,6 +13,7 @@
 #include <linux/mbus.h>
 #include <linux/io.h>
 #include <plat/addr-map.h>
+#include <mach/mv78xx0.h>
 #include "common.h"
 
 /*
@@ -37,7 +38,7 @@
 #define WIN0_OFF(n)		(BRIDGE_VIRT_BASE + 0x0000 + ((n) << 4))
 #define WIN8_OFF(n)		(BRIDGE_VIRT_BASE + 0x0900 + (((n) - 8) << 4))
 
-static void __init __iomem *win_cfg_base(int win)
+static void __init __iomem *win_cfg_base(const struct orion_addr_map_cfg *cfg, int win)
 {
 	/*
 	 * Find the control register base address for this window.
@@ -81,7 +82,7 @@ void __init mv78xx0_setup_pcie_io_win(int window, u32 base, u32 size,
 				      int maj, int min)
 {
 	orion_setup_cpu_win(&addr_map_cfg, window, base, size,
-			    TARGET_PCIE(maj), ATTR_PCIE_IO(min), -1);
+			    TARGET_PCIE(maj), ATTR_PCIE_IO(min), 0);
 }
 
 void __init mv78xx0_setup_pcie_mem_win(int window, u32 base, u32 size,
diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c
index b4c53b8..6b0c387 100644
--- a/arch/arm/mach-mv78xx0/common.c
+++ b/arch/arm/mach-mv78xx0/common.c
@@ -135,11 +135,6 @@ static struct map_desc mv78xx0_io_desc[] __initdata = {
 		.length		= MV78XX0_CORE_REGS_SIZE,
 		.type		= MT_DEVICE,
 	}, {
-		.virtual	= MV78XX0_PCIE_IO_VIRT_BASE(0),
-		.pfn		= __phys_to_pfn(MV78XX0_PCIE_IO_PHYS_BASE(0)),
-		.length		= MV78XX0_PCIE_IO_SIZE * 8,
-		.type		= MT_DEVICE,
-	}, {
 		.virtual	= MV78XX0_REGS_VIRT_BASE,
 		.pfn		= __phys_to_pfn(MV78XX0_REGS_PHYS_BASE),
 		.length		= MV78XX0_REGS_SIZE,
@@ -213,7 +208,8 @@ void __init mv78xx0_ge00_init(struct mv643xx_eth_platform_data *eth_data)
 {
 	orion_ge00_init(eth_data,
 			GE00_PHYS_BASE, IRQ_MV78XX0_GE00_SUM,
-			IRQ_MV78XX0_GE_ERR);
+			IRQ_MV78XX0_GE_ERR,
+			MV643XX_TX_CSUM_DEFAULT_LIMIT);
 }
 
 
@@ -224,7 +220,8 @@ void __init mv78xx0_ge01_init(struct mv643xx_eth_platform_data *eth_data)
 {
 	orion_ge01_init(eth_data,
 			GE01_PHYS_BASE, IRQ_MV78XX0_GE01_SUM,
-			NO_IRQ);
+			NO_IRQ,
+			MV643XX_TX_CSUM_DEFAULT_LIMIT);
 }
 
 
diff --git a/arch/arm/mach-mv78xx0/include/mach/io.h b/arch/arm/mach-mv78xx0/include/mach/io.h
deleted file mode 100644
index c7d9d00..0000000
--- a/arch/arm/mach-mv78xx0/include/mach/io.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * arch/arm/mach-mv78xx0/include/mach/io.h
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#include "mv78xx0.h"
-
-#define IO_SPACE_LIMIT		0xffffffff
-
-static inline void __iomem *__io(unsigned long addr)
-{
-	return (void __iomem *)((addr - MV78XX0_PCIE_IO_PHYS_BASE(0))
-					+ MV78XX0_PCIE_IO_VIRT_BASE(0));
-}
-
-#define __io(a)			__io(a)
-
-#endif
diff --git a/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h b/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
index e807c4c..bd03fed 100644
--- a/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
+++ b/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
@@ -29,15 +29,15 @@
  *
  * virt		phys		size
  * fe400000	f102x000	16K	core-specific peripheral registers
- * fe700000	f0800000	1M	PCIe #0 I/O space
- * fe800000	f0900000	1M	PCIe #1 I/O space
- * fe900000	f0a00000	1M	PCIe #2 I/O space
- * fea00000	f0b00000	1M	PCIe #3 I/O space
- * feb00000	f0c00000	1M	PCIe #4 I/O space
- * fec00000	f0d00000	1M	PCIe #5 I/O space
- * fed00000	f0e00000	1M	PCIe #6 I/O space
- * fee00000	f0f00000	1M	PCIe #7 I/O space
- * fef00000	f1000000	1M	on-chip peripheral registers
+ * fee00000	f0800000	64K	PCIe #0 I/O space
+ * fee10000	f0900000	64K	PCIe #1 I/O space
+ * fee20000	f0a00000	64K	PCIe #2 I/O space
+ * fee30000	f0b00000	64K	PCIe #3 I/O space
+ * fee40000	f0c00000	64K	PCIe #4 I/O space
+ * fee50000	f0d00000	64K	PCIe #5 I/O space
+ * fee60000	f0e00000	64K	PCIe #6 I/O space
+ * fee70000	f0f00000	64K	PCIe #7 I/O space
+ * fd000000	f1000000	1M	on-chip peripheral registers
  */
 #define MV78XX0_CORE0_REGS_PHYS_BASE	0xf1020000
 #define MV78XX0_CORE1_REGS_PHYS_BASE	0xf1024000
@@ -46,11 +46,10 @@
 #define MV78XX0_CORE_REGS_SIZE		SZ_16K
 
 #define MV78XX0_PCIE_IO_PHYS_BASE(i)	(0xf0800000 + ((i) << 20))
-#define MV78XX0_PCIE_IO_VIRT_BASE(i)	(0xfe700000 + ((i) << 20))
 #define MV78XX0_PCIE_IO_SIZE		SZ_1M
 
 #define MV78XX0_REGS_PHYS_BASE		0xf1000000
-#define MV78XX0_REGS_VIRT_BASE		0xfef00000
+#define MV78XX0_REGS_VIRT_BASE		0xfd000000
 #define MV78XX0_REGS_SIZE		SZ_1M
 
 #define MV78XX0_PCIE_MEM_PHYS_BASE	0xc0000000
diff --git a/arch/arm/mach-mv78xx0/pcie.c b/arch/arm/mach-mv78xx0/pcie.c
index 2e56e86..26a059b 100644
--- a/arch/arm/mach-mv78xx0/pcie.c
+++ b/arch/arm/mach-mv78xx0/pcie.c
@@ -15,6 +15,7 @@
 #include <asm/mach/pci.h>
 #include <plat/pcie.h>
 #include <plat/addr-map.h>
+#include <mach/mv78xx0.h>
 #include "common.h"
 
 struct pcie_port {
@@ -23,16 +24,13 @@ struct pcie_port {
 	u8			root_bus_nr;
 	void __iomem		*base;
 	spinlock_t		conf_lock;
-	char			io_space_name[16];
 	char			mem_space_name[16];
-	struct resource		res[2];
+	struct resource		res;
 };
 
 static struct pcie_port pcie_port[8];
 static int num_pcie_ports;
 static struct resource pcie_io_space;
-static struct resource pcie_mem_space;
-
 
 void __init mv78xx0_pcie_id(u32 *dev, u32 *rev)
 {
@@ -40,102 +38,59 @@ void __init mv78xx0_pcie_id(u32 *dev, u32 *rev)
 	*rev = orion_pcie_rev((void __iomem *)PCIE00_VIRT_BASE);
 }
 
+u32 pcie_port_size[8] = {
+	0,
+	0x30000000,
+	0x10000000,
+	0x10000000,
+	0x08000000,
+	0x08000000,
+	0x08000000,
+	0x04000000,
+};
+
 static void __init mv78xx0_pcie_preinit(void)
 {
 	int i;
 	u32 size_each;
 	u32 start;
-	int win;
+	int win = 0;
 
 	pcie_io_space.name = "PCIe I/O Space";
 	pcie_io_space.start = MV78XX0_PCIE_IO_PHYS_BASE(0);
 	pcie_io_space.end =
 		MV78XX0_PCIE_IO_PHYS_BASE(0) + MV78XX0_PCIE_IO_SIZE * 8 - 1;
-	pcie_io_space.flags = IORESOURCE_IO;
+	pcie_io_space.flags = IORESOURCE_MEM;
 	if (request_resource(&iomem_resource, &pcie_io_space))
 		panic("can't allocate PCIe I/O space");
 
-	pcie_mem_space.name = "PCIe MEM Space";
-	pcie_mem_space.start = MV78XX0_PCIE_MEM_PHYS_BASE;
-	pcie_mem_space.end =
-		MV78XX0_PCIE_MEM_PHYS_BASE + MV78XX0_PCIE_MEM_SIZE - 1;
-	pcie_mem_space.flags = IORESOURCE_MEM;
-	if (request_resource(&iomem_resource, &pcie_mem_space))
-		panic("can't allocate PCIe MEM space");
+	if (num_pcie_ports > 7)
+		panic("invalid number of PCIe ports");
+
+	size_each = pcie_port_size[num_pcie_ports];
 
+	start = MV78XX0_PCIE_MEM_PHYS_BASE;
 	for (i = 0; i < num_pcie_ports; i++) {
 		struct pcie_port *pp = pcie_port + i;
 
-		snprintf(pp->io_space_name, sizeof(pp->io_space_name),
-			"PCIe %d.%d I/O", pp->maj, pp->min);
-		pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0;
-		pp->res[0].name = pp->io_space_name;
-		pp->res[0].start = MV78XX0_PCIE_IO_PHYS_BASE(i);
-		pp->res[0].end = pp->res[0].start + MV78XX0_PCIE_IO_SIZE - 1;
-		pp->res[0].flags = IORESOURCE_IO;
-
 		snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
 			"PCIe %d.%d MEM", pp->maj, pp->min);
 		pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
-		pp->res[1].name = pp->mem_space_name;
-		pp->res[1].flags = IORESOURCE_MEM;
-	}
-
-	switch (num_pcie_ports) {
-	case 0:
-		size_each = 0;
-		break;
-
-	case 1:
-		size_each = 0x30000000;
-		break;
-
-	case 2 ... 3:
-		size_each = 0x10000000;
-		break;
-
-	case 4 ... 6:
-		size_each = 0x08000000;
-		break;
-
-	case 7:
-		size_each = 0x04000000;
-		break;
-
-	default:
-		panic("invalid number of PCIe ports");
-	}
-
-	start = MV78XX0_PCIE_MEM_PHYS_BASE;
-	for (i = 0; i < num_pcie_ports; i++) {
-		struct pcie_port *pp = pcie_port + i;
-
-		pp->res[1].start = start;
-		pp->res[1].end = start + size_each - 1;
+		pp->res.name = pp->mem_space_name;
+		pp->res.flags = IORESOURCE_MEM;
+		pp->res.start = start;
+		pp->res.end = start + size_each - 1;
 		start += size_each;
-	}
-
-	for (i = 0; i < num_pcie_ports; i++) {
-		struct pcie_port *pp = pcie_port + i;
 
-		if (request_resource(&pcie_io_space, &pp->res[0]))
-			panic("can't allocate PCIe I/O sub-space");
-
-		if (request_resource(&pcie_mem_space, &pp->res[1]))
+		if (request_resource(&iomem_resource, &pp->res))
 			panic("can't allocate PCIe MEM sub-space");
-	}
 
-	win = 0;
-	for (i = 0; i < num_pcie_ports; i++) {
-		struct pcie_port *pp = pcie_port + i;
+		mv78xx0_setup_pcie_mem_win(win + i + 8, pp->res.start,
+					   resource_size(&pp->res),
+					   pp->maj, pp->min);
 
-		mv78xx0_setup_pcie_io_win(win++, pp->res[0].start,
-					  resource_size(&pp->res[0]),
+		mv78xx0_setup_pcie_io_win(win + i, i * SZ_64K, SZ_64K,
 					  pp->maj, pp->min);
-
-		mv78xx0_setup_pcie_mem_win(win++, pp->res[1].start,
-					   resource_size(&pp->res[1]),
-					   pp->maj, pp->min);
 	}
 }
 
@@ -156,8 +111,9 @@ static int __init mv78xx0_pcie_setup(int nr, struct pci_sys_data *sys)
 	orion_pcie_set_local_bus_nr(pp->base, sys->busnr);
 	orion_pcie_setup(pp->base);
 
-	pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
-	pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
+	pci_ioremap_io(nr * SZ_64K, MV78XX0_PCIE_IO_PHYS_BASE(nr));
+
+	pci_add_resource_offset(&sys->resources, &pp->res, sys->mem_offset);
 
 	return 1;
 }
@@ -281,7 +237,7 @@ static void __init add_pcie_port(int maj, int min, unsigned long base)
 		pp->root_bus_nr = -1;
 		pp->base = (void __iomem *)base;
 		spin_lock_init(&pp->conf_lock);
-		memset(pp->res, 0, sizeof(pp->res));
+		memset(&pp->res, 0, sizeof(pp->res));
 	} else {
 		printk("link down, ignoring\n");
 	}
diff --git a/arch/arm/mach-nomadik/board-nhk8815.c b/arch/arm/mach-nomadik/board-nhk8815.c
index f4535a7..66862fb 100644
--- a/arch/arm/mach-nomadik/board-nhk8815.c
+++ b/arch/arm/mach-nomadik/board-nhk8815.c
@@ -23,6 +23,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/i2c.h>
 #include <linux/io.h>
+#include <linux/pinctrl/machine.h>
 #include <asm/hardware/vic.h>
 #include <asm/sizes.h>
 #include <asm/mach-types.h>
@@ -33,6 +34,7 @@
 
 #include <plat/gpio-nomadik.h>
 #include <plat/mtu.h>
+#include <plat/pincfg.h>
 
 #include <mach/nand.h>
 #include <mach/fsmc.h>
@@ -291,8 +293,42 @@ static struct i2c_board_info __initdata nhk8815_i2c2_devices[] = {
 	},
 };
 
+static unsigned long out_low[] = { PIN_OUTPUT_LOW };
+static unsigned long out_high[] = { PIN_OUTPUT_HIGH };
+static unsigned long in_nopull[] = { PIN_INPUT_NOPULL };
+static unsigned long in_pullup[] = { PIN_INPUT_PULLUP };
+
+static struct pinctrl_map __initdata nhk8815_pinmap[] = {
+	PIN_MAP_MUX_GROUP_DEFAULT("uart0", "pinctrl-stn8815", "u0_a_1", "u0"),
+	PIN_MAP_MUX_GROUP_DEFAULT("uart1", "pinctrl-stn8815", "u1_a_1", "u1"),
+	/* Hog in MMC/SD card mux */
+	PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-stn8815", "mmcsd_a_1", "mmcsd"),
+	/* MCCLK */
+	PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO8_B10", out_low),
+	/* MCCMD */
+	PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO9_A10", in_pullup),
+	/* MCCMDDIR */
+	PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO10_C11", out_high),
+	/* MCDAT3-0 */
+	PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO11_B11", in_pullup),
+	PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO12_A11", in_pullup),
+	PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO13_C12", in_pullup),
+	PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO14_B12", in_pullup),
+	/* MCDAT0DIR */
+	PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO15_A12", out_high),
+	/* MCDAT31DIR */
+	PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO16_C13", out_high),
+	/* MCMSFBCLK */
+	PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO24_C15", in_pullup),
+	/* CD input GPIO */
+	PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO111_H21", in_nopull),
+	/* CD bias drive */
+	PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO112_J21", out_low),
+};
+
 static void __init nhk8815_platform_init(void)
 {
+	pinctrl_register_mappings(nhk8815_pinmap, ARRAY_SIZE(nhk8815_pinmap));
 	cpu8815_platform_init();
 	nhk8815_onenand_init();
 	platform_add_devices(nhk8815_platform_devices,
diff --git a/arch/arm/mach-nomadik/cpu-8815.c b/arch/arm/mach-nomadik/cpu-8815.c
index 6fd8e46..b617eae 100644
--- a/arch/arm/mach-nomadik/cpu-8815.c
+++ b/arch/arm/mach-nomadik/cpu-8815.c
@@ -83,6 +83,18 @@ void cpu8815_add_gpios(resource_size_t *base, int num, int irq,
 	}
 }
 
+static inline void
+cpu8815_add_pinctrl(struct device *parent, const char *name)
+{
+	struct platform_device_info pdevinfo = {
+		.parent = parent,
+		.name = name,
+		.id = -1,
+	};
+
+	platform_device_register_full(&pdevinfo);
+}
+
 static int __init cpu8815_init(void)
 {
 	struct nmk_gpio_platform_data pdata = {
@@ -91,6 +103,7 @@ static int __init cpu8815_init(void)
 
 	cpu8815_add_gpios(cpu8815_gpio_base, ARRAY_SIZE(cpu8815_gpio_base),
 			  IRQ_GPIO0, &pdata);
+	cpu8815_add_pinctrl(NULL, "pinctrl-stn8815");
 	amba_apb_device_add(NULL, "rng", NOMADIK_RNG_BASE, SZ_4K, 0, 0, NULL, 0);
 	amba_apb_device_add(NULL, "rtc-pl031", NOMADIK_RTC_BASE, SZ_4K, IRQ_RTC_RTT, 0, NULL, 0);
 	return 0;
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index 398e9e5..cd169c3 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -61,14 +61,6 @@ obj-$(CONFIG_ARCH_OMAP850)		+= gpio7xx.o
 obj-$(CONFIG_ARCH_OMAP15XX)		+= gpio15xx.o
 obj-$(CONFIG_ARCH_OMAP16XX)		+= gpio16xx.o
 
-# LEDs support
-led-$(CONFIG_MACH_OMAP_H2)		+= leds-h2p2-debug.o
-led-$(CONFIG_MACH_OMAP_H3)		+= leds-h2p2-debug.o
-led-$(CONFIG_MACH_OMAP_INNOVATOR)	+= leds-innovator.o
-led-$(CONFIG_MACH_OMAP_PERSEUS2)	+= leds-h2p2-debug.o
-led-$(CONFIG_MACH_OMAP_OSK)		+= leds-osk.o
-obj-$(CONFIG_LEDS)			+= $(led-y)
-
 ifneq ($(CONFIG_FB_OMAP),)
 obj-y += lcd_dma.o
 endif
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index 44a4ab1..cd8836f 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -31,6 +31,7 @@
 #include <linux/i2c/tps65010.h>
 #include <linux/smc91x.h>
 #include <linux/omapfb.h>
+#include <linux/leds.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -306,12 +307,39 @@ static struct platform_device h2_irda_device = {
 	.resource	= h2_irda_resources,
 };
 
+static struct gpio_led h2_gpio_led_pins[] = {
+	{
+		.name		= "h2:red",
+		.default_trigger = "heartbeat",
+		.gpio		= 3,
+	},
+	{
+		.name		= "h2:green",
+		.default_trigger = "cpu0",
+		.gpio		= OMAP_MPUIO(4),
+	},
+};
+
+static struct gpio_led_platform_data h2_gpio_led_data = {
+	.leds		= h2_gpio_led_pins,
+	.num_leds	= ARRAY_SIZE(h2_gpio_led_pins),
+};
+
+static struct platform_device h2_gpio_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &h2_gpio_led_data,
+	},
+};
+
 static struct platform_device *h2_devices[] __initdata = {
 	&h2_nor_device,
 	&h2_nand_device,
 	&h2_smc91x_device,
 	&h2_irda_device,
 	&h2_kp_device,
+	&h2_gpio_leds,
 };
 
 static void __init h2_init_smc91x(void)
@@ -406,6 +434,10 @@ static void __init h2_init(void)
 	omap_cfg_reg(E19_1610_KBR4);
 	omap_cfg_reg(N19_1610_KBR5);
 
+	/* GPIO based LEDs */
+	omap_cfg_reg(P18_1610_GPIO3);
+	omap_cfg_reg(MPUIO4);
+
 	h2_smc91x_resources[1].start = gpio_to_irq(0);
 	h2_smc91x_resources[1].end = gpio_to_irq(0);
 	platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 86cb5a0..1fa9c45 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -31,6 +31,7 @@
 #include <linux/i2c/tps65010.h>
 #include <linux/smc91x.h>
 #include <linux/omapfb.h>
+#include <linux/leds.h>
 
 #include <asm/setup.h>
 #include <asm/page.h>
@@ -324,6 +325,32 @@ static struct spi_board_info h3_spi_board_info[] __initdata = {
 	},
 };
 
+static struct gpio_led h3_gpio_led_pins[] = {
+	{
+		.name		= "h3:red",
+		.default_trigger = "heartbeat",
+		.gpio		= 3,
+	},
+	{
+		.name		= "h3:green",
+		.default_trigger = "cpu0",
+		.gpio		= OMAP_MPUIO(4),
+	},
+};
+
+static struct gpio_led_platform_data h3_gpio_led_data = {
+	.leds		= h3_gpio_led_pins,
+	.num_leds	= ARRAY_SIZE(h3_gpio_led_pins),
+};
+
+static struct platform_device h3_gpio_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &h3_gpio_led_data,
+	},
+};
+
 static struct platform_device *devices[] __initdata = {
 	&nor_device,
 	&nand_device,
@@ -331,6 +358,7 @@ static struct platform_device *devices[] __initdata = {
 	&intlat_device,
 	&h3_kp_device,
 	&h3_lcd_device,
+	&h3_gpio_leds,
 };
 
 static struct omap_usb_config h3_usb_config __initdata = {
@@ -398,6 +426,10 @@ static void __init h3_init(void)
 	omap_cfg_reg(E19_1610_KBR4);
 	omap_cfg_reg(N19_1610_KBR5);
 
+	/* GPIO based LEDs */
+	omap_cfg_reg(P18_1610_GPIO3);
+	omap_cfg_reg(MPUIO4);
+
 	smc91x_resources[1].start = gpio_to_irq(40);
 	smc91x_resources[1].end = gpio_to_irq(40);
 	platform_add_devices(devices, ARRAY_SIZE(devices));
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index 8784705..7ee1c1e 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -380,10 +380,37 @@ static struct platform_device osk5912_lcd_device = {
 	.id		= -1,
 };
 
+static struct gpio_led mistral_gpio_led_pins[] = {
+	{
+		.name		= "mistral:red",
+		.default_trigger = "heartbeat",
+		.gpio		= 3,
+	},
+	{
+		.name		= "mistral:green",
+		.default_trigger = "cpu0",
+		.gpio		= OMAP_MPUIO(4),
+	},
+};
+
+static struct gpio_led_platform_data mistral_gpio_led_data = {
+	.leds		= mistral_gpio_led_pins,
+	.num_leds	= ARRAY_SIZE(mistral_gpio_led_pins),
+};
+
+static struct platform_device mistral_gpio_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &mistral_gpio_led_data,
+	},
+};
+
 static struct platform_device *mistral_devices[] __initdata = {
 	&osk5912_kp_device,
 	&mistral_bl_device,
 	&osk5912_lcd_device,
+	&mistral_gpio_leds,
 };
 
 static int mistral_get_pendown_state(void)
@@ -508,6 +535,12 @@ static void __init osk_mistral_init(void)
 	if (gpio_request(2, "lcd_pwr") == 0)
 		gpio_direction_output(2, 1);
 
+	/*
+	 * GPIO based LEDs
+	 */
+	omap_cfg_reg(P18_1610_GPIO3);
+	omap_cfg_reg(MPUIO4);
+
 	i2c_register_board_info(1, mistral_i2c_board_info,
 			ARRAY_SIZE(mistral_i2c_board_info));
 
diff --git a/arch/arm/mach-omap1/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c
deleted file mode 100644
index f6b14a1..0000000
--- a/arch/arm/mach-omap1/leds-h2p2-debug.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * linux/arch/arm/mach-omap1/leds-h2p2-debug.c
- *
- * Copyright 2003 by Texas Instruments Incorporated
- *
- * There are 16 LEDs on the debug board (all green); four may be used
- * for logical 'green', 'amber', 'red', and 'blue' (after "claiming").
- *
- * The "surfer" expansion board and H2 sample board also have two-color
- * green+red LEDs (in parallel), used here for timer and idle indicators.
- */
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/sched.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#include <plat/fpga.h>
-
-#include "leds.h"
-
-
-#define GPIO_LED_RED		3
-#define GPIO_LED_GREEN		OMAP_MPUIO(4)
-
-
-#define LED_STATE_ENABLED	0x01
-#define LED_STATE_CLAIMED	0x02
-#define LED_TIMER_ON		0x04
-
-#define GPIO_IDLE		GPIO_LED_GREEN
-#define GPIO_TIMER		GPIO_LED_RED
-
-
-void h2p2_dbg_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	static struct h2p2_dbg_fpga __iomem *fpga;
-	static u16 led_state, hw_led_state;
-
-	local_irq_save(flags);
-
-	if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
-		goto done;
-
-	switch (evt) {
-	case led_start:
-		if (!fpga)
-			fpga = ioremap(H2P2_DBG_FPGA_START,
-						H2P2_DBG_FPGA_SIZE);
-		if (fpga) {
-			led_state |= LED_STATE_ENABLED;
-			__raw_writew(~0, &fpga->leds);
-		}
-		break;
-
-	case led_stop:
-	case led_halted:
-		/* all leds off during suspend or shutdown */
-
-		if (! machine_is_omap_perseus2()) {
-			gpio_set_value(GPIO_TIMER, 0);
-			gpio_set_value(GPIO_IDLE, 0);
-		}
-
-		__raw_writew(~0, &fpga->leds);
-		led_state &= ~LED_STATE_ENABLED;
-		if (evt == led_halted) {
-			iounmap(fpga);
-			fpga = NULL;
-		}
-
-		goto done;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		led_state ^= LED_TIMER_ON;
-
-		if (machine_is_omap_perseus2())
-			hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER;
-		else {
-			gpio_set_value(GPIO_TIMER, led_state & LED_TIMER_ON);
-			goto done;
-		}
-
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		if (machine_is_omap_perseus2())
-			hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE;
-		else {
-			gpio_set_value(GPIO_IDLE, 1);
-			goto done;
-		}
-
-		break;
-
-	case led_idle_end:
-		if (machine_is_omap_perseus2())
-			hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE;
-		else {
-			gpio_set_value(GPIO_IDLE, 0);
-			goto done;
-		}
-
-		break;
-#endif
-
-	case led_green_on:
-		hw_led_state |= H2P2_DBG_FPGA_LED_GREEN;
-		break;
-	case led_green_off:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN;
-		break;
-
-	case led_amber_on:
-		hw_led_state |= H2P2_DBG_FPGA_LED_AMBER;
-		break;
-	case led_amber_off:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER;
-		break;
-
-	case led_red_on:
-		hw_led_state |= H2P2_DBG_FPGA_LED_RED;
-		break;
-	case led_red_off:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_RED;
-		break;
-
-	case led_blue_on:
-		hw_led_state |= H2P2_DBG_FPGA_LED_BLUE;
-		break;
-	case led_blue_off:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE;
-		break;
-
-	default:
-		break;
-	}
-
-
-	/*
-	 *  Actually burn the LEDs
-	 */
-	if (led_state & LED_STATE_ENABLED)
-		__raw_writew(~hw_led_state, &fpga->leds);
-
-done:
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-omap1/leds-innovator.c b/arch/arm/mach-omap1/leds-innovator.c
deleted file mode 100644
index 3a066ee..0000000
--- a/arch/arm/mach-omap1/leds-innovator.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * linux/arch/arm/mach-omap1/leds-innovator.c
- */
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-void innovator_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch (evt) {
-	case led_start:
-		hw_led_state = 0;
-		led_state = LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		hw_led_state = 0;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state ^= 0;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= 0;
-		break;
-
-	case led_idle_end:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~0;
-		break;
-#endif
-
-	case led_halted:
-		break;
-
-	case led_green_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~0;
-		break;
-
-	case led_green_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= 0;
-		break;
-
-	case led_amber_on:
-		break;
-
-	case led_amber_off:
-		break;
-
-	case led_red_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~0;
-		break;
-
-	case led_red_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= 0;
-		break;
-
-	default:
-		break;
-	}
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-omap1/leds-osk.c b/arch/arm/mach-omap1/leds-osk.c
deleted file mode 100644
index 936ed42..0000000
--- a/arch/arm/mach-omap1/leds-osk.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * linux/arch/arm/mach-omap1/leds-osk.c
- *
- * LED driver for OSK with optional Mistral QVGA board
- */
-#include <linux/gpio.h>
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED	(1 << 0)
-#define LED_STATE_CLAIMED	(1 << 1)
-static u8 led_state;
-
-#define	TIMER_LED		(1 << 3)	/* Mistral board */
-#define	IDLE_LED		(1 << 4)	/* Mistral board */
-static u8 hw_led_state;
-
-
-#ifdef	CONFIG_OMAP_OSK_MISTRAL
-
-/* For now, all system indicators require the Mistral board, since that
- * LED can be manipulated without a task context.  This LED is either red,
- * or green, but not both; it can't give the full "disco led" effect.
- */
-
-#define GPIO_LED_RED		3
-#define GPIO_LED_GREEN		OMAP_MPUIO(4)
-
-static void mistral_setled(void)
-{
-	int	red = 0;
-	int	green = 0;
-
-	if (hw_led_state & TIMER_LED)
-		red = 1;
-	else if (hw_led_state & IDLE_LED)
-		green = 1;
-	/* else both sides are disabled */
-
-	gpio_set_value(GPIO_LED_GREEN, green);
-	gpio_set_value(GPIO_LED_RED, red);
-}
-
-#endif
-
-void osk_leds_event(led_event_t evt)
-{
-	unsigned long	flags;
-	u16		leds;
-
-	local_irq_save(flags);
-
-	if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
-		goto done;
-
-	leds = hw_led_state;
-	switch (evt) {
-	case led_start:
-		led_state |= LED_STATE_ENABLED;
-		hw_led_state = 0;
-		leds = ~0;
-		break;
-
-	case led_halted:
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		hw_led_state = 0;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		leds = ~0;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-#ifdef	CONFIG_OMAP_OSK_MISTRAL
-
-	case led_timer:
-		hw_led_state ^= TIMER_LED;
-		mistral_setled();
-		break;
-
-	case led_idle_start:	/* idle == off */
-		hw_led_state &= ~IDLE_LED;
-		mistral_setled();
-		break;
-
-	case led_idle_end:
-		hw_led_state |= IDLE_LED;
-		mistral_setled();
-		break;
-
-#endif	/* CONFIG_OMAP_OSK_MISTRAL */
-
-	default:
-		break;
-	}
-
-	leds ^= hw_led_state;
-
-done:
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-omap1/leds.c b/arch/arm/mach-omap1/leds.c
deleted file mode 100644
index ae6dd93..0000000
--- a/arch/arm/mach-omap1/leds.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * linux/arch/arm/mach-omap1/leds.c
- *
- * OMAP LEDs dispatcher
- */
-#include <linux/gpio.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#include <plat/mux.h>
-
-#include "leds.h"
-
-static int __init
-omap_leds_init(void)
-{
-	if (!cpu_class_is_omap1())
-		return -ENODEV;
-
-	if (machine_is_omap_innovator())
-		leds_event = innovator_leds_event;
-
-	else if (machine_is_omap_h2()
-			|| machine_is_omap_h3()
-			|| machine_is_omap_perseus2())
-		leds_event = h2p2_dbg_leds_event;
-
-	else if (machine_is_omap_osk())
-		leds_event = osk_leds_event;
-
-	else
-		return -1;
-
-	if (machine_is_omap_h2()
-			|| machine_is_omap_h3()
-#ifdef	CONFIG_OMAP_OSK_MISTRAL
-			|| machine_is_omap_osk()
-#endif
-			) {
-
-		/* LED1/LED2 pins can be used as GPIO (as done here), or by
-		 * the LPG (works even in deep sleep!), to drive a bicolor
-		 * LED on the H2 sample board, and another on the H2/P2
-		 * "surfer" expansion board.
-		 *
-		 * The same pins drive a LED on the OSK Mistral board, but
-		 * that's a different kind of LED (just one color at a time).
-		 */
-		omap_cfg_reg(P18_1610_GPIO3);
-		if (gpio_request(3, "LED red") == 0)
-			gpio_direction_output(3, 1);
-		else
-			printk(KERN_WARNING "LED: can't get GPIO3/red?\n");
-
-		omap_cfg_reg(MPUIO4);
-		if (gpio_request(OMAP_MPUIO(4), "LED green") == 0)
-			gpio_direction_output(OMAP_MPUIO(4), 1);
-		else
-			printk(KERN_WARNING "LED: can't get MPUIO4/green?\n");
-	}
-
-	leds_event(led_start);
-	return 0;
-}
-
-__initcall(omap_leds_init);
diff --git a/arch/arm/mach-omap1/leds.h b/arch/arm/mach-omap1/leds.h
deleted file mode 100644
index a1e9fed..0000000
--- a/arch/arm/mach-omap1/leds.h
+++ /dev/null
@@ -1,3 +0,0 @@
-extern void innovator_leds_event(led_event_t evt);
-extern void h2p2_dbg_leds_event(led_event_t evt);
-extern void osk_leds_event(led_event_t evt);
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index 4062480..4d4816f 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -44,7 +44,6 @@
 #include <linux/clockchips.h>
 #include <linux/io.h>
 
-#include <asm/leds.h>
 #include <asm/irq.h>
 #include <asm/sched_clock.h>
 
diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c
index eae49c3..7452954 100644
--- a/arch/arm/mach-omap1/timer32k.c
+++ b/arch/arm/mach-omap1/timer32k.c
@@ -46,7 +46,6 @@
 #include <linux/clockchips.h>
 #include <linux/io.h>
 
-#include <asm/leds.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index dd2db02..4a4d058 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -69,6 +69,7 @@ config SOC_OMAP5
 	select CPU_V7
 	select ARM_GIC
 	select HAVE_SMP
+	select ARM_CPU_SUSPEND if PM
 
 comment "OMAP Core Type"
 	depends on ARCH_OMAP2
diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index 97d7190..188cc4e 100644
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -731,6 +731,7 @@ static void __init cm_t3x_common_init(void)
 	cm_t35_init_ethernet();
 	cm_t35_init_led();
 	cm_t35_init_display();
+	omap_twl4030_audio_init("cm-t3x");
 
 	usb_musb_init(NULL);
 	cm_t35_init_usbh();
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index 6567c1c..4cd804f 100644
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -630,6 +630,7 @@ static void __init devkit8000_init(void)
 	usbhs_init(&usbhs_bdata);
 	omap_nand_flash_init(NAND_BUSWIDTH_16, devkit8000_nand_partitions,
 			     ARRAY_SIZE(devkit8000_nand_partitions));
+	omap_twl4030_audio_init("omap3beagle");
 
 	/* Ensure SDRC pins are mux'd for self-refresh */
 	omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c
index 7491529..3613d14 100644
--- a/arch/arm/mach-omap2/board-igep0020.c
+++ b/arch/arm/mach-omap2/board-igep0020.c
@@ -554,6 +554,8 @@ static const struct usbhs_omap_board_data igep3_usbhs_bdata __initconst = {
 
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
+	/* SMSC9221 LAN Controller ETH IRQ (GPIO_176) */
+	OMAP3_MUX(MCSPI1_CS2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
 	{ .reg_offset = OMAP_MUX_TERMINATOR },
 };
 #endif
@@ -626,6 +628,7 @@ static void __init igep_init(void)
 
 	igep_flash_init();
 	igep_leds_init();
+	omap_twl4030_audio_init("igep2");
 
 	/*
 	 * WLAN-BT combo module from MuRata which has a Marvell WLAN
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 6202fc7..3ccfa5b 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -519,6 +519,7 @@ static void __init omap3_beagle_init(void)
 	usbhs_init(&usbhs_bdata);
 	omap_nand_flash_init(NAND_BUSWIDTH_16, omap3beagle_nand_partitions,
 			     ARRAY_SIZE(omap3beagle_nand_partitions));
+	omap_twl4030_audio_init("omap3beagle");
 
 	/* Ensure msecure is mux'd to be able to set the RTC. */
 	omap_mux_init_signal("sys_drm_msecure", OMAP_PIN_OFF_OUTPUT_HIGH);
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index ef230a0..1645700 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -58,6 +58,7 @@
 #include "hsmmc.h"
 #include "common-board-devices.h"
 
+#define OMAP3_EVM_TS_GPIO	175
 #define OMAP3_EVM_EHCI_VBUS	22
 #define OMAP3_EVM_EHCI_SELECT	61
 
@@ -736,6 +737,7 @@ static void __init omap3_evm_init(void)
 	omap3evm_init_smsc911x();
 	omap3_evm_display_init();
 	omap3_evm_wl12xx_init();
+	omap_twl4030_audio_init("omap3evm");
 }
 
 MACHINE_START(OMAP3EVM, "OMAP3 EVM")
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 779734d..fe674d0 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -509,6 +509,7 @@ static void __init overo_init(void)
 	overo_display_init();
 	overo_init_led();
 	overo_init_keys();
+	omap_twl4030_audio_init("overo");
 
 	/* Ensure SDRC pins are mux'd for self-refresh */
 	omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index df2534d..ca07264 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -34,6 +34,7 @@
 #include <plat/gpmc.h>
 #include <plat/onenand.h>
 #include <plat/gpmc-smc91x.h>
+#include <plat/omap-pm.h>
 
 #include <mach/board-rx51.h>
 
@@ -46,6 +47,10 @@
 #include <../drivers/staging/iio/light/tsl2563.h>
 #include <linux/lis3lv02d.h>
 
+#if defined(CONFIG_IR_RX51) || defined(CONFIG_IR_RX51_MODULE)
+#include <media/ir-rx51.h>
+#endif
+
 #include "mux.h"
 #include "hsmmc.h"
 #include "common-board-devices.h"
@@ -1220,6 +1225,30 @@ static void __init rx51_init_tsc2005(void)
 				gpio_to_irq(RX51_TSC2005_IRQ_GPIO);
 }
 
+#if defined(CONFIG_IR_RX51) || defined(CONFIG_IR_RX51_MODULE)
+static struct lirc_rx51_platform_data rx51_lirc_data = {
+	.set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat,
+	.pwm_timer = 9, /* Use GPT 9 for CIR */
+};
+
+static struct platform_device rx51_lirc_device = {
+	.name           = "lirc_rx51",
+	.id             = -1,
+	.dev            = {
+		.platform_data = &rx51_lirc_data,
+	},
+};
+
+static void __init rx51_init_lirc(void)
+{
+	platform_device_register(&rx51_lirc_device);
+}
+#else
+static void __init rx51_init_lirc(void)
+{
+}
+#endif
+
 void __init rx51_peripherals_init(void)
 {
 	rx51_i2c_init();
@@ -1230,6 +1259,7 @@ void __init rx51_peripherals_init(void)
 	rx51_init_wl1251();
 	rx51_init_tsc2005();
 	rx51_init_si4713();
+	rx51_init_lirc();
 	spi_register_board_info(rx51_peripherals_spi_board_info,
 				ARRAY_SIZE(rx51_peripherals_spi_board_info));
 
diff --git a/arch/arm/mach-omap2/common-board-devices.c b/arch/arm/mach-omap2/common-board-devices.c
index 1473474..c187586 100644
--- a/arch/arm/mach-omap2/common-board-devices.c
+++ b/arch/arm/mach-omap2/common-board-devices.c
@@ -35,16 +35,6 @@ static struct omap2_mcspi_device_config ads7846_mcspi_config = {
 	.turbo_mode	= 0,
 };
 
-/*
- * ADS7846 driver maybe request a gpio according to the value
- * of pdata->get_pendown_state, but we have done this. So set
- * get_pendown_state to avoid twice gpio requesting.
- */
-static int omap3_get_pendown_state(void)
-{
-	return !gpio_get_value(OMAP3_EVM_TS_GPIO);
-}
-
 static struct ads7846_platform_data ads7846_config = {
 	.x_max			= 0x0fff,
 	.y_max			= 0x0fff,
@@ -55,7 +45,6 @@ static struct ads7846_platform_data ads7846_config = {
 	.debounce_rep		= 1,
 	.gpio_pendown		= -EINVAL,
 	.keep_vref_on		= 1,
-	.get_pendown_state	= &omap3_get_pendown_state,
 };
 
 static struct spi_board_info ads7846_spi_board_info __initdata = {
diff --git a/arch/arm/mach-omap2/common-board-devices.h b/arch/arm/mach-omap2/common-board-devices.h
index 4c4ef6a..a0b4a428 100644
--- a/arch/arm/mach-omap2/common-board-devices.h
+++ b/arch/arm/mach-omap2/common-board-devices.h
@@ -4,7 +4,6 @@
 #include "twl-common.h"
 
 #define NAND_BLOCK_SIZE	SZ_128K
-#define OMAP3_EVM_TS_GPIO	175
 
 struct mtd_partition;
 struct ads7846_platform_data;
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index c00c689..02b9478 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -23,7 +23,6 @@
 #include <mach/irqs.h>
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
-#include <asm/pmu.h>
 
 #include "iomap.h"
 #include <plat/board.h>
@@ -448,7 +447,7 @@ static struct resource omap3_pmu_resource = {
 
 static struct platform_device omap_pmu_device = {
 	.name		= "arm-pmu",
-	.id		= ARM_PMU_DEVICE_CPU,
+	.id		= -1,
 	.num_resources	= 1,
 };
 
diff --git a/arch/arm/mach-omap2/mux.h b/arch/arm/mach-omap2/mux.h
index 471e62a..76f9b3c 100644
--- a/arch/arm/mach-omap2/mux.h
+++ b/arch/arm/mach-omap2/mux.h
@@ -127,7 +127,6 @@ struct omap_mux_partition {
  * @gpio:	GPIO number
  * @muxnames:	available signal modes for a ball
  * @balls:	available balls on the package
- * @partition:	mux partition
  */
 struct omap_mux {
 	u16	reg_offset;
diff --git a/arch/arm/mach-omap2/opp4xxx_data.c b/arch/arm/mach-omap2/opp4xxx_data.c
index 2293ba2..c95415d 100644
--- a/arch/arm/mach-omap2/opp4xxx_data.c
+++ b/arch/arm/mach-omap2/opp4xxx_data.c
@@ -94,7 +94,7 @@ int __init omap4_opp_init(void)
 {
 	int r = -ENODEV;
 
-	if (!cpu_is_omap44xx())
+	if (!cpu_is_omap443x())
 		return r;
 
 	r = omap_init_opp_table(omap44xx_opp_def_list,
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index e4fc88c..05bd8f0 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -272,21 +272,16 @@ void omap_sram_idle(void)
 	per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
 	core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
 
-	if (mpu_next_state < PWRDM_POWER_ON) {
-		pwrdm_pre_transition(mpu_pwrdm);
-		pwrdm_pre_transition(neon_pwrdm);
-	}
+	pwrdm_pre_transition(NULL);
 
 	/* PER */
 	if (per_next_state < PWRDM_POWER_ON) {
-		pwrdm_pre_transition(per_pwrdm);
 		per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;
 		omap2_gpio_prepare_for_idle(per_going_off);
 	}
 
 	/* CORE */
 	if (core_next_state < PWRDM_POWER_ON) {
-		pwrdm_pre_transition(core_pwrdm);
 		if (core_next_state == PWRDM_POWER_OFF) {
 			omap3_core_save_context();
 			omap3_cm_save_context();
@@ -339,20 +334,14 @@ void omap_sram_idle(void)
 			omap2_prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF_MASK,
 					       OMAP3430_GR_MOD,
 					       OMAP3_PRM_VOLTCTRL_OFFSET);
-		pwrdm_post_transition(core_pwrdm);
 	}
 	omap3_intc_resume_idle();
 
+	pwrdm_post_transition(NULL);
+
 	/* PER */
-	if (per_next_state < PWRDM_POWER_ON) {
+	if (per_next_state < PWRDM_POWER_ON)
 		omap2_gpio_resume_after_idle();
-		pwrdm_post_transition(per_pwrdm);
-	}
-
-	if (mpu_next_state < PWRDM_POWER_ON) {
-		pwrdm_post_transition(mpu_pwrdm);
-		pwrdm_post_transition(neon_pwrdm);
-	}
 }
 
 static void omap3_pm_idle(void)
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index c1b93c7..25d53b2 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -304,6 +304,9 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
 	omap_up.dma_rx_timeout = info->dma_rx_timeout;
 	omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate;
 	omap_up.autosuspend_timeout = info->autosuspend_timeout;
+	omap_up.DTR_gpio = info->DTR_gpio;
+	omap_up.DTR_inverted = info->DTR_inverted;
+	omap_up.DTR_present = info->DTR_present;
 
 	pdata = &omap_up;
 	pdata_size = sizeof(struct omap_uart_port_info);
diff --git a/arch/arm/mach-omap2/sleep44xx.S b/arch/arm/mach-omap2/sleep44xx.S
index 9f6b83d..91e71d8 100644
--- a/arch/arm/mach-omap2/sleep44xx.S
+++ b/arch/arm/mach-omap2/sleep44xx.S
@@ -56,9 +56,13 @@ ppa_por_params:
  * The restore function pointer is stored at CPUx_WAKEUP_NS_PA_ADDR_OFFSET.
  * It returns to the caller for CPU INACTIVE and ON power states or in case
  * CPU failed to transition to targeted OFF/DORMANT state.
+ *
+ * omap4_finish_suspend() calls v7_flush_dcache_all() which doesn't save
+ * stack frame and it expects the caller to take care of it. Hence the entire
+ * stack frame is saved to avoid possible stack corruption.
  */
 ENTRY(omap4_finish_suspend)
-	stmfd	sp!, {lr}
+	stmfd	sp!, {r4-r12, lr}
 	cmp	r0, #0x0
 	beq	do_WFI				@ No lowpower state, jump to WFI
 
@@ -226,7 +230,7 @@ scu_gp_clear:
 skip_scu_gp_clear:
 	isb
 	dsb
-	ldmfd	sp!, {pc}
+	ldmfd	sp!, {r4-r12, pc}
 ENDPROC(omap4_finish_suspend)
 
 /*
diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c
index de47f17..6eb2f60 100644
--- a/arch/arm/mach-omap2/twl-common.c
+++ b/arch/arm/mach-omap2/twl-common.c
@@ -67,6 +67,7 @@ void __init omap_pmic_init(int bus, u32 clkrate,
 			   const char *pmic_type, int pmic_irq,
 			   struct twl4030_platform_data *pmic_data)
 {
+	omap_mux_init_signal("sys_nirq", OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE);
 	strncpy(pmic_i2c_board_info.type, pmic_type,
 		sizeof(pmic_i2c_board_info.type));
 	pmic_i2c_board_info.irq = pmic_irq;
@@ -537,3 +538,30 @@ void __init omap4_pmic_get_config(struct twl4030_platform_data *pmic_data,
 		pmic_data->v2v1 = &omap4_v2v1_idata;
 }
 #endif /* CONFIG_ARCH_OMAP4 */
+
+#if defined(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) || \
+	defined(CONFIG_SND_OMAP_SOC_OMAP_TWL4030_MODULE)
+#include <linux/platform_data/omap-twl4030.h>
+
+static struct omap_tw4030_pdata omap_twl4030_audio_data;
+
+static struct platform_device audio_device = {
+	.name		= "omap-twl4030",
+	.id		= -1,
+	.dev = {
+		.platform_data = &omap_twl4030_audio_data,
+	},
+};
+
+void __init omap_twl4030_audio_init(char *card_name)
+{
+	omap_twl4030_audio_data.card_name = card_name;
+	platform_device_register(&audio_device);
+}
+
+#else /* SOC_OMAP_TWL4030 */
+void __init omap_twl4030_audio_init(char *card_name, int codec_sysclk)
+{
+	return;
+}
+#endif /* SOC_OMAP_TWL4030 */
diff --git a/arch/arm/mach-omap2/twl-common.h b/arch/arm/mach-omap2/twl-common.h
index 8fe71cf..cb25b43 100644
--- a/arch/arm/mach-omap2/twl-common.h
+++ b/arch/arm/mach-omap2/twl-common.h
@@ -59,4 +59,6 @@ void omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
 void omap4_pmic_get_config(struct twl4030_platform_data *pmic_data,
 			   u32 pdata_flags, u32 regulators_flags);
 
+void omap_twl4030_audio_init(char *card_name);
+
 #endif /* __OMAP_PMIC_COMMON__ */
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index 9148b22..87a6cda 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -47,16 +47,6 @@ static struct map_desc orion5x_io_desc[] __initdata = {
 		.length		= ORION5X_REGS_SIZE,
 		.type		= MT_DEVICE,
 	}, {
-		.virtual	= ORION5X_PCIE_IO_VIRT_BASE,
-		.pfn		= __phys_to_pfn(ORION5X_PCIE_IO_PHYS_BASE),
-		.length		= ORION5X_PCIE_IO_SIZE,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= ORION5X_PCI_IO_VIRT_BASE,
-		.pfn		= __phys_to_pfn(ORION5X_PCI_IO_PHYS_BASE),
-		.length		= ORION5X_PCI_IO_SIZE,
-		.type		= MT_DEVICE,
-	}, {
 		.virtual	= ORION5X_PCIE_WA_VIRT_BASE,
 		.pfn		= __phys_to_pfn(ORION5X_PCIE_WA_PHYS_BASE),
 		.length		= ORION5X_PCIE_WA_SIZE,
@@ -109,7 +99,8 @@ void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data)
 {
 	orion_ge00_init(eth_data,
 			ORION5X_ETH_PHYS_BASE, IRQ_ORION5X_ETH_SUM,
-			IRQ_ORION5X_ETH_ERR);
+			IRQ_ORION5X_ETH_ERR,
+			MV643XX_TX_CSUM_DEFAULT_LIMIT);
 }
 
 
diff --git a/arch/arm/mach-orion5x/include/mach/io.h b/arch/arm/mach-orion5x/include/mach/io.h
deleted file mode 100644
index 1aa5d0a..0000000
--- a/arch/arm/mach-orion5x/include/mach/io.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * arch/arm/mach-orion5x/include/mach/io.h
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#include <mach/orion5x.h>
-#include <asm/sizes.h>
-
-#define IO_SPACE_LIMIT		SZ_2M
-static inline void __iomem *__io(unsigned long addr)
-{
-	return (void __iomem *)(addr + ORION5X_PCIE_IO_VIRT_BASE);
-}
-
-#define __io(a)			 __io(a)
-#endif
diff --git a/arch/arm/mach-orion5x/include/mach/orion5x.h b/arch/arm/mach-orion5x/include/mach/orion5x.h
index 683e085..1b60131 100644
--- a/arch/arm/mach-orion5x/include/mach/orion5x.h
+++ b/arch/arm/mach-orion5x/include/mach/orion5x.h
@@ -31,31 +31,29 @@
  * fc000000	device bus mappings (cs0/cs1)
  *
  * virt		phys		size
- * fdd00000	f1000000	1M	on-chip peripheral registers
- * fde00000	f2000000	1M	PCIe I/O space
- * fdf00000	f2100000	1M	PCI I/O space
- * fe000000	f0000000	16M	PCIe WA space (Orion-1/Orion-NAS only)
+ * fe000000	f1000000	1M	on-chip peripheral registers
+ * fee00000	f2000000	64K	PCIe I/O space
+ * fee10000	f2100000	64K	PCI I/O space
+ * fd000000	f0000000	16M	PCIe WA space (Orion-1/Orion-NAS only)
  ****************************************************************************/
 #define ORION5X_REGS_PHYS_BASE		0xf1000000
-#define ORION5X_REGS_VIRT_BASE		0xfdd00000
+#define ORION5X_REGS_VIRT_BASE		0xfe000000
 #define ORION5X_REGS_SIZE		SZ_1M
 
 #define ORION5X_PCIE_IO_PHYS_BASE	0xf2000000
-#define ORION5X_PCIE_IO_VIRT_BASE	0xfde00000
 #define ORION5X_PCIE_IO_BUS_BASE	0x00000000
-#define ORION5X_PCIE_IO_SIZE		SZ_1M
+#define ORION5X_PCIE_IO_SIZE		SZ_64K
 
 #define ORION5X_PCI_IO_PHYS_BASE	0xf2100000
-#define ORION5X_PCI_IO_VIRT_BASE	0xfdf00000
-#define ORION5X_PCI_IO_BUS_BASE		0x00100000
-#define ORION5X_PCI_IO_SIZE		SZ_1M
+#define ORION5X_PCI_IO_BUS_BASE		0x00010000
+#define ORION5X_PCI_IO_SIZE		SZ_64K
 
 #define ORION5X_SRAM_PHYS_BASE		(0xf2200000)
 #define ORION5X_SRAM_SIZE		SZ_8K
 
 /* Relevant only for Orion-1/Orion-NAS */
 #define ORION5X_PCIE_WA_PHYS_BASE	0xf0000000
-#define ORION5X_PCIE_WA_VIRT_BASE	0xfe000000
+#define ORION5X_PCIE_WA_VIRT_BASE	0xfd000000
 #define ORION5X_PCIE_WA_SIZE		SZ_16M
 
 #define ORION5X_PCIE_MEM_PHYS_BASE	0xe0000000
diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c
index cb19e16..6921d49 100644
--- a/arch/arm/mach-orion5x/pci.c
+++ b/arch/arm/mach-orion5x/pci.c
@@ -162,35 +162,25 @@ static int __init pcie_setup(struct pci_sys_data *sys)
 		pcie_ops.read = pcie_rd_conf_wa;
 	}
 
+	pci_ioremap_io(sys->busnr * SZ_64K, ORION5X_PCIE_IO_PHYS_BASE);
+
 	/*
 	 * Request resources.
 	 */
-	res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+	res = kzalloc(sizeof(struct resource), GFP_KERNEL);
 	if (!res)
 		panic("pcie_setup unable to alloc resources");
 
 	/*
-	 * IORESOURCE_IO
-	 */
-	sys->io_offset = 0;
-	res[0].name = "PCIe I/O Space";
-	res[0].flags = IORESOURCE_IO;
-	res[0].start = ORION5X_PCIE_IO_BUS_BASE;
-	res[0].end = res[0].start + ORION5X_PCIE_IO_SIZE - 1;
-	if (request_resource(&ioport_resource, &res[0]))
-		panic("Request PCIe IO resource failed\n");
-	pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
-
-	/*
 	 * IORESOURCE_MEM
 	 */
-	res[1].name = "PCIe Memory Space";
-	res[1].flags = IORESOURCE_MEM;
-	res[1].start = ORION5X_PCIE_MEM_PHYS_BASE;
-	res[1].end = res[1].start + ORION5X_PCIE_MEM_SIZE - 1;
-	if (request_resource(&iomem_resource, &res[1]))
+	res->name = "PCIe Memory Space";
+	res->flags = IORESOURCE_MEM;
+	res->start = ORION5X_PCIE_MEM_PHYS_BASE;
+	res->end = res->start + ORION5X_PCIE_MEM_SIZE - 1;
+	if (request_resource(&iomem_resource, res))
 		panic("Request PCIe Memory resource failed\n");
-	pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, res, sys->mem_offset);
 
 	return 1;
 }
@@ -489,35 +479,25 @@ static int __init pci_setup(struct pci_sys_data *sys)
 	 */
 	orion5x_setbits(PCI_CMD, PCI_CMD_HOST_REORDER);
 
+	pci_ioremap_io(sys->busnr * SZ_64K, ORION5X_PCI_IO_PHYS_BASE);
+
 	/*
 	 * Request resources
 	 */
-	res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+	res = kzalloc(sizeof(struct resource), GFP_KERNEL);
 	if (!res)
 		panic("pci_setup unable to alloc resources");
 
 	/*
-	 * IORESOURCE_IO
-	 */
-	sys->io_offset = 0;
-	res[0].name = "PCI I/O Space";
-	res[0].flags = IORESOURCE_IO;
-	res[0].start = ORION5X_PCI_IO_BUS_BASE;
-	res[0].end = res[0].start + ORION5X_PCI_IO_SIZE - 1;
-	if (request_resource(&ioport_resource, &res[0]))
-		panic("Request PCI IO resource failed\n");
-	pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
-
-	/*
 	 * IORESOURCE_MEM
 	 */
-	res[1].name = "PCI Memory Space";
-	res[1].flags = IORESOURCE_MEM;
-	res[1].start = ORION5X_PCI_MEM_PHYS_BASE;
-	res[1].end = res[1].start + ORION5X_PCI_MEM_SIZE - 1;
-	if (request_resource(&iomem_resource, &res[1]))
+	res->name = "PCI Memory Space";
+	res->flags = IORESOURCE_MEM;
+	res->start = ORION5X_PCI_MEM_PHYS_BASE;
+	res->end = res->start + ORION5X_PCI_MEM_SIZE - 1;
+	if (request_resource(&iomem_resource, res))
 		panic("Request PCI Memory resource failed\n");
-	pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, res, sys->mem_offset);
 
 	return 1;
 }
diff --git a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
index 78a6a11..9b1c953 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
@@ -18,7 +18,6 @@
 #include <linux/ethtool.h>
 #include <net/dsa.h>
 #include <asm/mach-types.h>
-#include <asm/leds.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/pci.h>
 #include <mach/orion5x.h>
diff --git a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
index 2f5dc54..51ba2b8 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
@@ -19,7 +19,6 @@
 #include <linux/i2c.h>
 #include <net/dsa.h>
 #include <asm/mach-types.h>
-#include <asm/leds.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/pci.h>
 #include <mach/orion5x.h>
diff --git a/arch/arm/mach-orion5x/rd88f5182-setup.c b/arch/arm/mach-orion5x/rd88f5182-setup.c
index 399130f..0a56b94 100644
--- a/arch/arm/mach-orion5x/rd88f5182-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5182-setup.c
@@ -19,8 +19,8 @@
 #include <linux/mv643xx_eth.h>
 #include <linux/ata_platform.h>
 #include <linux/i2c.h>
+#include <linux/leds.h>
 #include <asm/mach-types.h>
-#include <asm/leds.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/pci.h>
 #include <mach/orion5x.h>
@@ -53,12 +53,6 @@
 #define RD88F5182_PCI_SLOT0_IRQ_A_PIN	7
 #define RD88F5182_PCI_SLOT0_IRQ_B_PIN	6
 
-/*
- * GPIO Debug LED
- */
-
-#define RD88F5182_GPIO_DBG_LED		0
-
 /*****************************************************************************
  * 16M NOR Flash on Device bus CS1
  ****************************************************************************/
@@ -83,55 +77,32 @@ static struct platform_device rd88f5182_nor_flash = {
 	.resource		= &rd88f5182_nor_flash_resource,
 };
 
-#ifdef CONFIG_LEDS
-
 /*****************************************************************************
- * Use GPIO debug led as CPU active indication
+ * Use GPIO LED as CPU active indication
  ****************************************************************************/
 
-static void rd88f5182_dbgled_event(led_event_t evt)
-{
-	int val;
-
-	if (evt == led_idle_end)
-		val = 1;
-	else if (evt == led_idle_start)
-		val = 0;
-	else
-		return;
-
-	gpio_set_value(RD88F5182_GPIO_DBG_LED, val);
-}
-
-static int __init rd88f5182_dbgled_init(void)
-{
-	int pin;
-
-	if (machine_is_rd88f5182()) {
-		pin = RD88F5182_GPIO_DBG_LED;
+#define RD88F5182_GPIO_LED		0
 
-		if (gpio_request(pin, "DBGLED") == 0) {
-			if (gpio_direction_output(pin, 0) != 0) {
-				printk(KERN_ERR "rd88f5182_dbgled_init failed "
-						"to set output pin %d\n", pin);
-				gpio_free(pin);
-				return 0;
-			}
-		} else {
-			printk(KERN_ERR "rd88f5182_dbgled_init failed "
-					"to request gpio %d\n", pin);
-			return 0;
-		}
-
-		leds_event = rd88f5182_dbgled_event;
-	}
-
-	return 0;
-}
+static struct gpio_led rd88f5182_gpio_led_pins[] = {
+	{
+		.name		= "rd88f5182:cpu",
+		.default_trigger = "cpu0",
+		.gpio		= RD88F5182_GPIO_LED,
+	},
+};
 
-__initcall(rd88f5182_dbgled_init);
+static struct gpio_led_platform_data rd88f5182_gpio_led_data = {
+	.leds		= rd88f5182_gpio_led_pins,
+	.num_leds	= ARRAY_SIZE(rd88f5182_gpio_led_pins),
+};
 
-#endif
+static struct platform_device rd88f5182_gpio_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &rd88f5182_gpio_led_data,
+	},
+};
 
 /*****************************************************************************
  * PCI
@@ -298,6 +269,7 @@ static void __init rd88f5182_init(void)
 
 	orion5x_setup_dev1_win(RD88F5182_NOR_BASE, RD88F5182_NOR_SIZE);
 	platform_device_register(&rd88f5182_nor_flash);
+	platform_device_register(&rd88f5182_gpio_leds);
 
 	i2c_register_board_info(0, &rd88f5182_i2c_rtc, 1);
 }
diff --git a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
index 92df49c..ed50910 100644
--- a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
@@ -20,7 +20,6 @@
 #include <linux/ethtool.h>
 #include <net/dsa.h>
 #include <asm/mach-types.h>
-#include <asm/leds.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/pci.h>
 #include <mach/orion5x.h>
diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c
index 0cfe8af..47a7ae9 100644
--- a/arch/arm/mach-pnx4008/time.c
+++ b/arch/arm/mach-pnx4008/time.c
@@ -25,7 +25,6 @@
 #include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/leds.h>
 #include <asm/mach/time.h>
 #include <asm/errno.h>
 
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index fe2d1f8..8e6288d 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -25,6 +25,18 @@ config PXA_V7_MACH_AUTO
 if !ARCH_PXA_V7
 comment "Intel/Marvell Dev Platforms (sorted by hardware release time)"
 
+config MACH_PXA3XX_DT
+	bool "Support PXA3xx platforms from device tree"
+	select PXA3xx
+	select CPU_PXA300
+	select POWER_SUPPLY
+	select HAVE_PWM
+	select USE_OF
+	help
+	  Include support for Marvell PXA3xx based platforms using
+	  the device tree. Needn't select any other machine while
+	  MACH_PXA3XX_DT is enabled.
+
 config ARCH_LUBBOCK
 	bool "Intel DBPXA250 Development Platform (aka Lubbock)"
 	select PXA25x
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index be0f7df..ee88d6e 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -26,6 +26,9 @@ obj-$(CONFIG_CPU_PXA930)	+= pxa930.o
 
 # NOTE: keep the order of boards in accordance to their order in Kconfig
 
+# Device Tree support
+obj-$(CONFIG_MACH_PXA3XX_DT)	+= pxa-dt.o
+
 # Intel/Marvell Dev Platforms
 obj-$(CONFIG_ARCH_LUBBOCK)	+= lubbock.o
 obj-$(CONFIG_MACH_MAINSTONE)	+= mainstone.o
@@ -95,12 +98,4 @@ obj-$(CONFIG_MACH_RAUMFELD_CONNECTOR)	+= raumfeld.o
 obj-$(CONFIG_MACH_RAUMFELD_SPEAKER)	+= raumfeld.o
 obj-$(CONFIG_MACH_ZIPIT2)	+= z2.o
 
-# Support for blinky lights
-led-y := leds.o
-led-$(CONFIG_ARCH_LUBBOCK)	+= leds-lubbock.o
-led-$(CONFIG_MACH_MAINSTONE)	+= leds-mainstone.o
-led-$(CONFIG_ARCH_PXA_IDP)	+= leds-idp.o
-
-obj-$(CONFIG_LEDS)		+= $(led-y)
-
 obj-$(CONFIG_TOSA_BT)		+= tosa-bt.o
diff --git a/arch/arm/mach-pxa/clock-pxa3xx.c b/arch/arm/mach-pxa/clock-pxa3xx.c
index 2a37a9a..d4e9499 100644
--- a/arch/arm/mach-pxa/clock-pxa3xx.c
+++ b/arch/arm/mach-pxa/clock-pxa3xx.c
@@ -127,8 +127,10 @@ void clk_pxa3xx_cken_enable(struct clk *clk)
 
 	if (clk->cken < 32)
 		CKENA |= mask;
-	else
+	else if (clk->cken < 64)
 		CKENB |= mask;
+	else
+		CKENC |= mask;
 }
 
 void clk_pxa3xx_cken_disable(struct clk *clk)
@@ -137,8 +139,10 @@ void clk_pxa3xx_cken_disable(struct clk *clk)
 
 	if (clk->cken < 32)
 		CKENA &= ~mask;
-	else
+	else if (clk->cken < 64)
 		CKENB &= ~mask;
+	else
+		CKENC &= ~mask;
 }
 
 const struct clkops clk_pxa3xx_cken_ops = {
diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
index 166eee5..c1f3b12 100644
--- a/arch/arm/mach-pxa/devices.c
+++ b/arch/arm/mach-pxa/devices.c
@@ -6,7 +6,6 @@
 #include <linux/spi/pxa2xx_spi.h>
 #include <linux/i2c/pxa-i2c.h>
 
-#include <asm/pmu.h>
 #include <mach/udc.h>
 #include <mach/pxa3xx-u2d.h>
 #include <mach/pxafb.h>
@@ -42,7 +41,7 @@ static struct resource pxa_resource_pmu = {
 
 struct platform_device pxa_device_pmu = {
 	.name		= "arm-pmu",
-	.id		= ARM_PMU_DEVICE_CPU,
+	.id		= -1,
 	.resource	= &pxa_resource_pmu,
 	.num_resources	= 1,
 };
diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
index 6ff466b..ae1e997 100644
--- a/arch/arm/mach-pxa/idp.c
+++ b/arch/arm/mach-pxa/idp.c
@@ -191,6 +191,87 @@ static void __init idp_map_io(void)
 	iotable_init(idp_io_desc, ARRAY_SIZE(idp_io_desc));
 }
 
+/* LEDs */
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct idp_led {
+	struct led_classdev     cdev;
+	u8                      mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+	const char *name;
+	const char *trigger;
+} idp_leds[] = {
+	{ "idp:green", "heartbeat", },
+	{ "idp:red", "cpu0", },
+};
+
+static void idp_led_set(struct led_classdev *cdev,
+		enum led_brightness b)
+{
+	struct idp_led *led = container_of(cdev,
+			struct idp_led, cdev);
+	u32 reg = IDP_CPLD_LED_CONTROL;
+
+	if (b != LED_OFF)
+		reg &= ~led->mask;
+	else
+		reg |= led->mask;
+
+	IDP_CPLD_LED_CONTROL = reg;
+}
+
+static enum led_brightness idp_led_get(struct led_classdev *cdev)
+{
+	struct idp_led *led = container_of(cdev,
+			struct idp_led, cdev);
+
+	return (IDP_CPLD_LED_CONTROL & led->mask) ? LED_OFF : LED_FULL;
+}
+
+static int __init idp_leds_init(void)
+{
+	int i;
+
+	if (!machine_is_pxa_idp())
+		return -ENODEV;
+
+	for (i = 0; i < ARRAY_SIZE(idp_leds); i++) {
+		struct idp_led *led;
+
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
+
+		led->cdev.name = idp_leds[i].name;
+		led->cdev.brightness_set = idp_led_set;
+		led->cdev.brightness_get = idp_led_get;
+		led->cdev.default_trigger = idp_leds[i].trigger;
+
+		if (i == 0)
+			led->mask = IDP_HB_LED;
+		else
+			led->mask = IDP_BUSY_LED;
+
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(idp_leds_init);
+#endif
 
 MACHINE_START(PXA_IDP, "Vibren PXA255 IDP")
 	/* Maintainer: Vibren Technologies */
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index 5dae15e..b6cc181 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -17,6 +17,8 @@
 #include <linux/syscore_ops.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 
 #include <asm/exception.h>
 
@@ -25,8 +27,6 @@
 
 #include "generic.h"
 
-#define IRQ_BASE		io_p2v(0x40d00000)
-
 #define ICIP			(0x000)
 #define ICMR			(0x004)
 #define ICLR			(0x008)
@@ -48,22 +48,19 @@
  * This is for peripheral IRQs internal to the PXA chip.
  */
 
+static void __iomem *pxa_irq_base;
 static int pxa_internal_irq_nr;
-
-static inline int cpu_has_ipr(void)
-{
-	return !cpu_is_pxa25x();
-}
+static bool cpu_has_ipr;
 
 static inline void __iomem *irq_base(int i)
 {
-	static unsigned long phys_base[] = {
-		0x40d00000,
-		0x40d0009c,
-		0x40d00130,
+	static unsigned long phys_base_offset[] = {
+		0x0,
+		0x9c,
+		0x130,
 	};
 
-	return io_p2v(phys_base[i]);
+	return pxa_irq_base + phys_base_offset[i];
 }
 
 void pxa_mask_irq(struct irq_data *d)
@@ -96,8 +93,8 @@ asmlinkage void __exception_irq_entry icip_handle_irq(struct pt_regs *regs)
 	uint32_t icip, icmr, mask;
 
 	do {
-		icip = __raw_readl(IRQ_BASE + ICIP);
-		icmr = __raw_readl(IRQ_BASE + ICMR);
+		icip = __raw_readl(pxa_irq_base + ICIP);
+		icmr = __raw_readl(pxa_irq_base + ICMR);
 		mask = icip & icmr;
 
 		if (mask == 0)
@@ -128,6 +125,8 @@ void __init pxa_init_irq(int irq_nr, int (*fn)(struct irq_data *, unsigned int))
 	BUG_ON(irq_nr > MAX_INTERNAL_IRQS);
 
 	pxa_internal_irq_nr = irq_nr;
+	cpu_has_ipr = !cpu_is_pxa25x();
+	pxa_irq_base = io_p2v(0x40d00000);
 
 	for (n = 0; n < irq_nr; n += 32) {
 		void __iomem *base = irq_base(n >> 5);
@@ -136,8 +135,8 @@ void __init pxa_init_irq(int irq_nr, int (*fn)(struct irq_data *, unsigned int))
 		__raw_writel(0, base + ICLR);	/* all IRQs are IRQ, not FIQ */
 		for (i = n; (i < (n + 32)) && (i < irq_nr); i++) {
 			/* initialize interrupt priority */
-			if (cpu_has_ipr())
-				__raw_writel(i | IPR_VALID, IRQ_BASE + IPR(i));
+			if (cpu_has_ipr)
+				__raw_writel(i | IPR_VALID, pxa_irq_base + IPR(i));
 
 			irq = PXA_IRQ(i);
 			irq_set_chip_and_handler(irq, &pxa_internal_irq_chip,
@@ -168,9 +167,9 @@ static int pxa_irq_suspend(void)
 		__raw_writel(0, base + ICMR);
 	}
 
-	if (cpu_has_ipr()) {
+	if (cpu_has_ipr) {
 		for (i = 0; i < pxa_internal_irq_nr; i++)
-			saved_ipr[i] = __raw_readl(IRQ_BASE + IPR(i));
+			saved_ipr[i] = __raw_readl(pxa_irq_base + IPR(i));
 	}
 
 	return 0;
@@ -187,11 +186,11 @@ static void pxa_irq_resume(void)
 		__raw_writel(0, base + ICLR);
 	}
 
-	if (cpu_has_ipr())
+	if (cpu_has_ipr)
 		for (i = 0; i < pxa_internal_irq_nr; i++)
-			__raw_writel(saved_ipr[i], IRQ_BASE + IPR(i));
+			__raw_writel(saved_ipr[i], pxa_irq_base + IPR(i));
 
-	__raw_writel(1, IRQ_BASE + ICCR);
+	__raw_writel(1, pxa_irq_base + ICCR);
 }
 #else
 #define pxa_irq_suspend		NULL
@@ -202,3 +201,93 @@ struct syscore_ops pxa_irq_syscore_ops = {
 	.suspend	= pxa_irq_suspend,
 	.resume		= pxa_irq_resume,
 };
+
+#ifdef CONFIG_OF
+static struct irq_domain *pxa_irq_domain;
+
+static int pxa_irq_map(struct irq_domain *h, unsigned int virq,
+		       irq_hw_number_t hw)
+{
+	void __iomem *base = irq_base(hw / 32);
+
+	/* initialize interrupt priority */
+	if (cpu_has_ipr)
+		__raw_writel(hw | IPR_VALID, pxa_irq_base + IPR(hw));
+
+	irq_set_chip_and_handler(hw, &pxa_internal_irq_chip,
+				 handle_level_irq);
+	irq_set_chip_data(hw, base);
+	set_irq_flags(hw, IRQF_VALID);
+
+	return 0;
+}
+
+static struct irq_domain_ops pxa_irq_ops = {
+	.map    = pxa_irq_map,
+	.xlate  = irq_domain_xlate_onecell,
+};
+
+static const struct of_device_id intc_ids[] __initconst = {
+	{ .compatible = "marvell,pxa-intc", },
+	{}
+};
+
+void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int))
+{
+	struct device_node *node;
+	const struct of_device_id *of_id;
+	struct pxa_intc_conf *conf;
+	struct resource res;
+	int n, ret;
+
+	node = of_find_matching_node(NULL, intc_ids);
+	if (!node) {
+		pr_err("Failed to find interrupt controller in arch-pxa\n");
+		return;
+	}
+	of_id = of_match_node(intc_ids, node);
+	conf = of_id->data;
+
+	ret = of_property_read_u32(node, "marvell,intc-nr-irqs",
+				   &pxa_internal_irq_nr);
+	if (ret) {
+		pr_err("Not found marvell,intc-nr-irqs property\n");
+		return;
+	}
+
+	ret = of_address_to_resource(node, 0, &res);
+	if (ret < 0) {
+		pr_err("No registers defined for node\n");
+		return;
+	}
+	pxa_irq_base = io_p2v(res.start);
+
+	if (of_find_property(node, "marvell,intc-priority", NULL))
+		cpu_has_ipr = 1;
+
+	ret = irq_alloc_descs(-1, 0, pxa_internal_irq_nr, 0);
+	if (ret < 0) {
+		pr_err("Failed to allocate IRQ numbers\n");
+		return;
+	}
+
+	pxa_irq_domain = irq_domain_add_legacy(node, pxa_internal_irq_nr, 0, 0,
+					       &pxa_irq_ops, NULL);
+	if (!pxa_irq_domain)
+		panic("Unable to add PXA IRQ domain\n");
+
+	irq_set_default_host(pxa_irq_domain);
+
+	for (n = 0; n < pxa_internal_irq_nr; n += 32) {
+		void __iomem *base = irq_base(n >> 5);
+
+		__raw_writel(0, base + ICMR);	/* disable all IRQs */
+		__raw_writel(0, base + ICLR);	/* all IRQs are IRQ, not FIQ */
+	}
+
+	/* only unmasked interrupts kick us out of idle */
+	__raw_writel(1, irq_base(0) + ICCR);
+
+	pxa_internal_irq_chip.irq_set_wake = fn;
+}
+#endif /* CONFIG_OF */
diff --git a/arch/arm/mach-pxa/leds-idp.c b/arch/arm/mach-pxa/leds-idp.c
deleted file mode 100644
index 06b0600..0000000
--- a/arch/arm/mach-pxa/leds-idp.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/leds-idp.c
- *
- * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
- *
- * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com>
- *
- * Original (leds-footbridge.c) by Russell King
- *
- * Macros for actual LED manipulation should be in machine specific
- * files in this 'mach' directory.
- */
-
-
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include <mach/pxa25x.h>
-#include <mach/idp.h>
-
-#include "leds.h"
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-void idp_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch (evt) {
-	case led_start:
-		hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
-		led_state = LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state ^= IDP_HB_LED;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~IDP_BUSY_LED;
-		break;
-
-	case led_idle_end:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= IDP_BUSY_LED;
-		break;
-#endif
-
-	case led_halted:
-		break;
-
-	case led_green_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= IDP_HB_LED;
-		break;
-
-	case led_green_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~IDP_HB_LED;
-		break;
-
-	case led_amber_on:
-		break;
-
-	case led_amber_off:
-		break;
-
-	case led_red_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= IDP_BUSY_LED;
-		break;
-
-	case led_red_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~IDP_BUSY_LED;
-		break;
-
-	default:
-		break;
-	}
-
-	if  (led_state & LED_STATE_ENABLED)
-		IDP_CPLD_LED_CONTROL = ( (IDP_CPLD_LED_CONTROL | IDP_LEDS_MASK) & ~hw_led_state);
-	else
-		IDP_CPLD_LED_CONTROL |= IDP_LEDS_MASK;
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-pxa/leds-lubbock.c b/arch/arm/mach-pxa/leds-lubbock.c
deleted file mode 100644
index 0bd85c8..0000000
--- a/arch/arm/mach-pxa/leds-lubbock.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/leds-lubbock.c
- *
- * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
- *
- * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com>
- *
- * Original (leds-footbridge.c) by Russell King
- *
- * Major surgery on April 2004 by Nicolas Pitre for less global
- * namespace collision.  Mostly adapted the Mainstone version.
- */
-
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <mach/pxa25x.h>
-#include <mach/lubbock.h>
-
-#include "leds.h"
-
-/*
- * 8 discrete leds available for general use:
- *
- * Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays
- * so be sure to not monkey with them here.
- */
-
-#define D28			(1 << 0)
-#define D27			(1 << 1)
-#define D26			(1 << 2)
-#define D25			(1 << 3)
-#define D24			(1 << 4)
-#define D23			(1 << 5)
-#define D22			(1 << 6)
-#define D21			(1 << 7)
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-void lubbock_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch (evt) {
-	case led_start:
-		hw_led_state = 0;
-		led_state = LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		hw_led_state ^= D26;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		hw_led_state &= ~D27;
-		break;
-
-	case led_idle_end:
-		hw_led_state |= D27;
-		break;
-#endif
-
-	case led_halted:
-		break;
-
-	case led_green_on:
-		hw_led_state |= D21;
-		break;
-
-	case led_green_off:
-		hw_led_state &= ~D21;
-		break;
-
-	case led_amber_on:
-		hw_led_state |= D22;
-		break;
-
-	case led_amber_off:
-		hw_led_state &= ~D22;
-		break;
-
-	case led_red_on:
-		hw_led_state |= D23;
-		break;
-
-	case led_red_off:
-		hw_led_state &= ~D23;
-		break;
-
-	default:
-		break;
-	}
-
-	if  (led_state & LED_STATE_ENABLED)
-		LUB_DISC_BLNK_LED = (LUB_DISC_BLNK_LED | 0xff) & ~hw_led_state;
-	else
-		LUB_DISC_BLNK_LED |= 0xff;
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-pxa/leds-mainstone.c b/arch/arm/mach-pxa/leds-mainstone.c
deleted file mode 100644
index 4058ab3..0000000
--- a/arch/arm/mach-pxa/leds-mainstone.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/leds-mainstone.c
- *
- * Author:     Nicolas Pitre
- * Created:    Nov 05, 2002
- * Copyright:  MontaVista Software Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include <mach/pxa27x.h>
-#include <mach/mainstone.h>
-
-#include "leds.h"
-
-
-/* 8 discrete leds available for general use: */
-#define D28			(1 << 0)
-#define D27			(1 << 1)
-#define D26			(1 << 2)
-#define D25			(1 << 3)
-#define D24			(1 << 4)
-#define D23			(1 << 5)
-#define D22			(1 << 6)
-#define D21			(1 << 7)
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-void mainstone_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch (evt) {
-	case led_start:
-		hw_led_state = 0;
-		led_state = LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		hw_led_state ^= D26;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		hw_led_state &= ~D27;
-		break;
-
-	case led_idle_end:
-		hw_led_state |= D27;
-		break;
-#endif
-
-	case led_halted:
-		break;
-
-	case led_green_on:
-		hw_led_state |= D21;
-		break;
-
-	case led_green_off:
-		hw_led_state &= ~D21;
-		break;
-
-	case led_amber_on:
-		hw_led_state |= D22;
-		break;
-
-	case led_amber_off:
-		hw_led_state &= ~D22;
-		break;
-
-	case led_red_on:
-		hw_led_state |= D23;
-		break;
-
-	case led_red_off:
-		hw_led_state &= ~D23;
-		break;
-
-	default:
-		break;
-	}
-
-	if  (led_state & LED_STATE_ENABLED)
-		MST_LEDCTRL = (MST_LEDCTRL | 0xff) & ~hw_led_state;
-	else
-		MST_LEDCTRL |= 0xff;
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-pxa/leds.c b/arch/arm/mach-pxa/leds.c
deleted file mode 100644
index bbe4d5f..0000000
--- a/arch/arm/mach-pxa/leds.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/leds.c
- *
- * xscale LEDs dispatcher
- *
- * Copyright (C) 2001 Nicolas Pitre
- *
- * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc.
- */
-#include <linux/compiler.h>
-#include <linux/init.h>
-
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#include "leds.h"
-
-static int __init
-pxa_leds_init(void)
-{
-	if (machine_is_lubbock())
-		leds_event = lubbock_leds_event;
-	if (machine_is_mainstone())
-		leds_event = mainstone_leds_event;
-	if (machine_is_pxa_idp())
-		leds_event = idp_leds_event;
-
-	leds_event(led_start);
-	return 0;
-}
-
-core_initcall(pxa_leds_init);
diff --git a/arch/arm/mach-pxa/leds.h b/arch/arm/mach-pxa/leds.h
deleted file mode 100644
index 7f0dfe0..0000000
--- a/arch/arm/mach-pxa/leds.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/arm/mach-pxa/leds.h
- *
- * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc.
- *
- * blinky lights for various PXA-based systems:
- *
- */
-
-extern void idp_leds_event(led_event_t evt);
-extern void lubbock_leds_event(led_event_t evt);
-extern void mainstone_leds_event(led_event_t evt);
-extern void trizeps4_leds_event(led_event_t evt);
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 0ca0db7..3c48035 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/syscore_ops.h>
 #include <linux/major.h>
@@ -23,6 +24,8 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/smc91x.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
@@ -549,6 +552,98 @@ static void __init lubbock_map_io(void)
 	PCFR |= PCFR_OPDE;
 }
 
+/*
+ * Driver for the 8 discrete LEDs available for general use:
+ * Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays
+ * so be sure to not monkey with them here.
+ */
+
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct lubbock_led {
+	struct led_classdev	cdev;
+	u8			mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+	const char *name;
+	const char *trigger;
+} lubbock_leds[] = {
+	{ "lubbock:D28", "default-on", },
+	{ "lubbock:D27", "cpu0", },
+	{ "lubbock:D26", "heartbeat" },
+	{ "lubbock:D25", },
+	{ "lubbock:D24", },
+	{ "lubbock:D23", },
+	{ "lubbock:D22", },
+	{ "lubbock:D21", },
+};
+
+static void lubbock_led_set(struct led_classdev *cdev,
+			      enum led_brightness b)
+{
+	struct lubbock_led *led = container_of(cdev,
+					 struct lubbock_led, cdev);
+	u32 reg = LUB_DISC_BLNK_LED;
+
+	if (b != LED_OFF)
+		reg |= led->mask;
+	else
+		reg &= ~led->mask;
+
+	LUB_DISC_BLNK_LED = reg;
+}
+
+static enum led_brightness lubbock_led_get(struct led_classdev *cdev)
+{
+	struct lubbock_led *led = container_of(cdev,
+					 struct lubbock_led, cdev);
+	u32 reg = LUB_DISC_BLNK_LED;
+
+	return (reg & led->mask) ? LED_FULL : LED_OFF;
+}
+
+static int __init lubbock_leds_init(void)
+{
+	int i;
+
+	if (!machine_is_lubbock())
+		return -ENODEV;
+
+	/* All ON */
+	LUB_DISC_BLNK_LED |= 0xff;
+	for (i = 0; i < ARRAY_SIZE(lubbock_leds); i++) {
+		struct lubbock_led *led;
+
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
+
+		led->cdev.name = lubbock_leds[i].name;
+		led->cdev.brightness_set = lubbock_led_set;
+		led->cdev.brightness_get = lubbock_led_get;
+		led->cdev.default_trigger = lubbock_leds[i].trigger;
+		led->mask = BIT(i);
+
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(lubbock_leds_init);
+#endif
+
 MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)")
 	/* Maintainer: MontaVista Software Inc. */
 	.map_io		= lubbock_map_io,
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index 1aebaf7..bdc6c33 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -28,6 +28,8 @@
 #include <linux/pwm_backlight.h>
 #include <linux/smc91x.h>
 #include <linux/i2c/pxa-i2c.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -613,6 +615,98 @@ static void __init mainstone_map_io(void)
  	PCFR = 0x66;
 }
 
+/*
+ * Driver for the 8 discrete LEDs available for general use:
+ * Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays
+ * so be sure to not monkey with them here.
+ */
+
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct mainstone_led {
+	struct led_classdev	cdev;
+	u8			mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+	const char *name;
+	const char *trigger;
+} mainstone_leds[] = {
+	{ "mainstone:D28", "default-on", },
+	{ "mainstone:D27", "cpu0", },
+	{ "mainstone:D26", "heartbeat" },
+	{ "mainstone:D25", },
+	{ "mainstone:D24", },
+	{ "mainstone:D23", },
+	{ "mainstone:D22", },
+	{ "mainstone:D21", },
+};
+
+static void mainstone_led_set(struct led_classdev *cdev,
+			      enum led_brightness b)
+{
+	struct mainstone_led *led = container_of(cdev,
+					 struct mainstone_led, cdev);
+	u32 reg = MST_LEDCTRL;
+
+	if (b != LED_OFF)
+		reg |= led->mask;
+	else
+		reg &= ~led->mask;
+
+	MST_LEDCTRL = reg;
+}
+
+static enum led_brightness mainstone_led_get(struct led_classdev *cdev)
+{
+	struct mainstone_led *led = container_of(cdev,
+					 struct mainstone_led, cdev);
+	u32 reg = MST_LEDCTRL;
+
+	return (reg & led->mask) ? LED_FULL : LED_OFF;
+}
+
+static int __init mainstone_leds_init(void)
+{
+	int i;
+
+	if (!machine_is_mainstone())
+		return -ENODEV;
+
+	/* All ON */
+	MST_LEDCTRL |= 0xff;
+	for (i = 0; i < ARRAY_SIZE(mainstone_leds); i++) {
+		struct mainstone_led *led;
+
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
+
+		led->cdev.name = mainstone_leds[i].name;
+		led->cdev.brightness_set = mainstone_led_set;
+		led->cdev.brightness_get = mainstone_led_get;
+		led->cdev.default_trigger = mainstone_leds[i].trigger;
+		led->mask = BIT(i);
+
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(mainstone_leds_init);
+#endif
+
 MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)")
 	/* Maintainer: MontaVista Software Inc. */
 	.atag_offset	= 0x100,	/* BLOB boot parameter setting */
diff --git a/arch/arm/mach-pxa/pxa-dt.c b/arch/arm/mach-pxa/pxa-dt.c
new file mode 100644
index 0000000..c9192ce
--- /dev/null
+++ b/arch/arm/mach-pxa/pxa-dt.c
@@ -0,0 +1,63 @@
+/*
+ *  linux/arch/arm/mach-pxa/pxa-dt.c
+ *
+ *  Copyright (C) 2012 Daniel Mack
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  publishhed by the Free Software Foundation.
+ */
+
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/irqs.h>
+#include <mach/pxa3xx.h>
+
+#include "generic.h"
+
+#ifdef CONFIG_PXA3xx
+extern void __init pxa3xx_dt_init_irq(void);
+
+static const struct of_dev_auxdata pxa3xx_auxdata_lookup[] __initconst = {
+	OF_DEV_AUXDATA("mrvl,pxa-uart",		0x40100000, "pxa2xx-uart.0", NULL),
+	OF_DEV_AUXDATA("mrvl,pxa-uart",		0x40200000, "pxa2xx-uart.1", NULL),
+	OF_DEV_AUXDATA("mrvl,pxa-uart",		0x40700000, "pxa2xx-uart.2", NULL),
+	OF_DEV_AUXDATA("mrvl,pxa-uart",		0x41600000, "pxa2xx-uart.3", NULL),
+	OF_DEV_AUXDATA("marvell,pxa-mmc",	0x41100000, "pxa2xx-mci.0", NULL),
+	OF_DEV_AUXDATA("mrvl,pxa-gpio",		0x40e00000, "pxa-gpio", NULL),
+	OF_DEV_AUXDATA("marvell,pxa-ohci",	0x4c000000, "pxa27x-ohci", NULL),
+	OF_DEV_AUXDATA("mrvl,pxa-i2c",		0x40301680, "pxa2xx-i2c.0", NULL),
+	OF_DEV_AUXDATA("mrvl,pwri2c",		0x40f500c0, "pxa3xx-i2c.1", NULL),
+	OF_DEV_AUXDATA("marvell,pxa3xx-nand",	0x43100000, "pxa3xx-nand", NULL),
+	{}
+};
+
+static void __init pxa3xx_dt_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table,
+			     pxa3xx_auxdata_lookup, NULL);
+}
+
+static const char *pxa3xx_dt_board_compat[] __initdata = {
+	"marvell,pxa300",
+	"marvell,pxa310",
+	"marvell,pxa320",
+	NULL,
+};
+#endif
+
+#ifdef CONFIG_PXA3xx
+DT_MACHINE_START(PXA_DT, "Marvell PXA3xx (Device Tree Support)")
+	.map_io		= pxa3xx_map_io,
+	.init_irq	= pxa3xx_dt_init_irq,
+	.handle_irq	= pxa3xx_handle_irq,
+	.timer		= &pxa_timer,
+	.restart	= pxa_restart,
+	.init_machine	= pxa3xx_dt_init,
+	.dt_compat	= pxa3xx_dt_board_compat,
+MACHINE_END
+#endif
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index dffb7e8..4a9d04a 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/of.h>
 #include <linux/syscore_ops.h>
 #include <linux/i2c/pxa-i2c.h>
 
@@ -40,6 +41,8 @@
 #define PECR_IE(n)	((1 << ((n) * 2)) << 28)
 #define PECR_IS(n)	((1 << ((n) * 2)) << 29)
 
+extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int));
+
 static DEFINE_PXA3_CKEN(pxa3xx_ffuart, FFUART, 14857000, 1);
 static DEFINE_PXA3_CKEN(pxa3xx_btuart, BTUART, 14857000, 1);
 static DEFINE_PXA3_CKEN(pxa3xx_stuart, STUART, 14857000, 1);
@@ -382,7 +385,7 @@ static void __init pxa_init_ext_wakeup_irq(int (*fn)(struct irq_data *,
 	pxa_ext_wakeup_chip.irq_set_wake = fn;
 }
 
-void __init pxa3xx_init_irq(void)
+static void __init __pxa3xx_init_irq(void)
 {
 	/* enable CP6 access */
 	u32 value;
@@ -390,10 +393,21 @@ void __init pxa3xx_init_irq(void)
 	value |= (1 << 6);
 	__asm__ __volatile__("mcr p15, 0, %0, c15, c1, 0\n": :"r"(value));
 
-	pxa_init_irq(56, pxa3xx_set_wake);
 	pxa_init_ext_wakeup_irq(pxa3xx_set_wake);
 }
 
+void __init pxa3xx_init_irq(void)
+{
+	__pxa3xx_init_irq();
+	pxa_init_irq(56, pxa3xx_set_wake);
+}
+
+void __init pxa3xx_dt_init_irq(void)
+{
+	__pxa3xx_init_irq();
+	pxa_dt_irq_init(pxa3xx_set_wake);
+}
+
 static struct map_desc pxa3xx_io_desc[] __initdata = {
 	{	/* Mem Ctl */
 		.virtual	= (unsigned long)SMEMC_VIRT,
@@ -466,7 +480,8 @@ static int __init pxa3xx_init(void)
 		register_syscore_ops(&pxa3xx_mfp_syscore_ops);
 		register_syscore_ops(&pxa3xx_clock_syscore_ops);
 
-		ret = platform_add_devices(devices, ARRAY_SIZE(devices));
+		if (!of_have_populated_dt())
+			ret = platform_add_devices(devices, ARRAY_SIZE(devices));
 	}
 
 	return ret;
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 45868bb..d22dee9 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -35,7 +35,6 @@
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/icst.h>
@@ -436,44 +435,6 @@ struct clcd_board clcd_plat_data = {
 	.remove		= versatile_clcd_remove_dma,
 };
 
-#ifdef CONFIG_LEDS
-#define VA_LEDS_BASE (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LED_OFFSET)
-
-void realview_leds_event(led_event_t ledevt)
-{
-	unsigned long flags;
-	u32 val;
-	u32 led = 1 << smp_processor_id();
-
-	local_irq_save(flags);
-	val = readl(VA_LEDS_BASE);
-
-	switch (ledevt) {
-	case led_idle_start:
-		val = val & ~led;
-		break;
-
-	case led_idle_end:
-		val = val | led;
-		break;
-
-	case led_timer:
-		val = val ^ REALVIEW_SYS_LED7;
-		break;
-
-	case led_halted:
-		val = 0;
-		break;
-
-	default:
-		break;
-	}
-
-	writel(val, VA_LEDS_BASE);
-	local_irq_restore(flags);
-}
-#endif	/* CONFIG_LEDS */
-
 /*
  * Where is the timer (VA)?
  */
diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h
index f8f2c0a..f2141ae 100644
--- a/arch/arm/mach-realview/core.h
+++ b/arch/arm/mach-realview/core.h
@@ -26,7 +26,6 @@
 #include <linux/io.h>
 
 #include <asm/setup.h>
-#include <asm/leds.h>
 
 #define APB_DEVICE(name, busid, base, plat)			\
 static AMBA_APB_DEVICE(name, busid, 0, REALVIEW_##base##_BASE, base##_IRQ, plat)
@@ -47,7 +46,6 @@ extern void __iomem *timer1_va_base;
 extern void __iomem *timer2_va_base;
 extern void __iomem *timer3_va_base;
 
-extern void realview_leds_event(led_event_t ledevt);
 extern void realview_timer_init(unsigned int timer_irq);
 extern int realview_flash_register(struct resource *res, u32 num);
 extern int realview_eth_register(const char *name, struct resource *res);
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index baf382c..36f5d29 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -30,9 +30,7 @@
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/pmu.h>
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -297,7 +295,7 @@ static struct resource pmu_resources[] = {
 
 static struct platform_device pmu_device = {
 	.name			= "arm-pmu",
-	.id			= ARM_PMU_DEVICE_CPU,
+	.id			= -1,
 	.num_resources		= ARRAY_SIZE(pmu_resources),
 	.resource		= pmu_resources,
 };
@@ -462,10 +460,6 @@ static void __init realview_eb_init(void)
 		struct amba_device *d = amba_devs[i];
 		amba_device_register(d, &iomem_resource);
 	}
-
-#ifdef CONFIG_LEDS
-	leds_event = realview_leds_event;
-#endif
 }
 
 MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index b1d7caf..049c373 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -32,9 +32,7 @@
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/pmu.h>
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -280,7 +278,7 @@ static struct resource pmu_resource = {
 
 static struct platform_device pmu_device = {
 	.name			= "arm-pmu",
-	.id			= ARM_PMU_DEVICE_CPU,
+	.id			= -1,
 	.num_resources		= 1,
 	.resource		= &pmu_resource,
 };
@@ -375,10 +373,6 @@ static void __init realview_pb1176_init(void)
 		struct amba_device *d = amba_devs[i];
 		amba_device_register(d, &iomem_resource);
 	}
-
-#ifdef CONFIG_LEDS
-	leds_event = realview_leds_event;
-#endif
 }
 
 MACHINE_START(REALVIEW_PB1176, "ARM-RealView PB1176")
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index a98c536..9966672 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -30,9 +30,7 @@
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/pmu.h>
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -263,7 +261,7 @@ static struct resource pmu_resources[] = {
 
 static struct platform_device pmu_device = {
 	.name			= "arm-pmu",
-	.id			= ARM_PMU_DEVICE_CPU,
+	.id			= -1,
 	.num_resources		= ARRAY_SIZE(pmu_resources),
 	.resource		= pmu_resources,
 };
@@ -357,10 +355,6 @@ static void __init realview_pb11mp_init(void)
 		struct amba_device *d = amba_devs[i];
 		amba_device_register(d, &iomem_resource);
 	}
-
-#ifdef CONFIG_LEDS
-	leds_event = realview_leds_event;
-#endif
 }
 
 MACHINE_START(REALVIEW_PB11MP, "ARM-RealView PB11MPCore")
diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c
index 5965017..25fdc6b 100644
--- a/arch/arm/mach-realview/realview_pba8.c
+++ b/arch/arm/mach-realview/realview_pba8.c
@@ -29,9 +29,7 @@
 #include <linux/io.h>
 
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/pmu.h>
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 
@@ -241,7 +239,7 @@ static struct resource pmu_resource = {
 
 static struct platform_device pmu_device = {
 	.name			= "arm-pmu",
-	.id			= ARM_PMU_DEVICE_CPU,
+	.id			= -1,
 	.num_resources		= 1,
 	.resource		= &pmu_resource,
 };
@@ -299,10 +297,6 @@ static void __init realview_pba8_init(void)
 		struct amba_device *d = amba_devs[i];
 		amba_device_register(d, &iomem_resource);
 	}
-
-#ifdef CONFIG_LEDS
-	leds_event = realview_leds_event;
-#endif
 }
 
 MACHINE_START(REALVIEW_PBA8, "ARM-RealView PB-A8")
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index 3f2f605..05f28d8 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -28,9 +28,7 @@
 #include <linux/io.h>
 
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/pmu.h>
 #include <asm/smp_twd.h>
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
@@ -280,7 +278,7 @@ static struct resource pmu_resources[] = {
 
 static struct platform_device pmu_device = {
 	.name			= "arm-pmu",
-	.id			= ARM_PMU_DEVICE_CPU,
+	.id			= -1,
 	.num_resources		= ARRAY_SIZE(pmu_resources),
 	.resource		= pmu_resources,
 };
@@ -394,10 +392,6 @@ static void __init realview_pbx_init(void)
 		struct amba_device *d = amba_devs[i];
 		amba_device_register(d, &iomem_resource);
 	}
-
-#ifdef CONFIG_LEDS
-	leds_event = realview_leds_event;
-#endif
 }
 
 MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX")
diff --git a/arch/arm/mach-s3c24xx/include/mach/dma.h b/arch/arm/mach-s3c24xx/include/mach/dma.h
index 454831b..ee99fd5 100644
--- a/arch/arm/mach-s3c24xx/include/mach/dma.h
+++ b/arch/arm/mach-s3c24xx/include/mach/dma.h
@@ -24,7 +24,8 @@
 */
 
 enum dma_ch {
-	DMACH_XD0,
+	DMACH_DT_PROP = -1,	/* not yet supported, do not use */
+	DMACH_XD0 = 0,
 	DMACH_XD1,
 	DMACH_SDI,
 	DMACH_SPI0,
diff --git a/arch/arm/mach-s3c24xx/mach-smdk2416.c b/arch/arm/mach-s3c24xx/mach-smdk2416.c
index c3100a0..96478f0 100644
--- a/arch/arm/mach-s3c24xx/mach-smdk2416.c
+++ b/arch/arm/mach-s3c24xx/mach-smdk2416.c
@@ -29,6 +29,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <video/samsung_fimd.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
@@ -52,7 +53,6 @@
 #include <plat/udc.h>
 #include <linux/platform_data/s3c-hsudc.h>
 
-#include <plat/regs-fb-v4.h>
 #include <plat/fb.h>
 
 #include <plat/common-smdk.h>
diff --git a/arch/arm/mach-s3c64xx/mach-anw6410.c b/arch/arm/mach-s3c64xx/mach-anw6410.c
index ffa29dd..f7a108b 100644
--- a/arch/arm/mach-s3c64xx/mach-anw6410.c
+++ b/arch/arm/mach-s3c64xx/mach-anw6410.c
@@ -29,6 +29,7 @@
 #include <linux/dm9000.h>
 
 #include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
 
 #include <asm/hardware/vic.h>
 #include <asm/mach/arch.h>
@@ -44,7 +45,6 @@
 #include <plat/regs-serial.h>
 #include <plat/iic.h>
 #include <plat/fb.h>
-#include <plat/regs-fb-v4.h>
 
 #include <plat/clock.h>
 #include <plat/devs.h>
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410-module.c b/arch/arm/mach-s3c64xx/mach-crag6410-module.c
index 9e382e7..7f4f9eb 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410-module.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410-module.c
@@ -16,6 +16,7 @@
 #include <linux/mfd/wm831x/irq.h>
 #include <linux/mfd/wm831x/gpio.h>
 #include <linux/mfd/wm8994/pdata.h>
+#include <linux/mfd/arizona/pdata.h>
 
 #include <linux/regulator/machine.h>
 
@@ -181,9 +182,33 @@ static const struct i2c_board_info wm1277_devs[] = {
 	},
 };
 
-static const struct i2c_board_info wm5102_devs[] = {
-	{ I2C_BOARD_INFO("wm5102", 0x1a),
-	  .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, },
+static struct arizona_pdata wm5102_pdata = {
+	.ldoena = S3C64XX_GPN(7),
+	.gpio_base = CODEC_GPIO_BASE,
+	.irq_active_high = true,
+	.micd_pol_gpio = CODEC_GPIO_BASE + 4,
+	.gpio_defaults = {
+		[2] = 0x10000, /* AIF3TXLRCLK */
+		[3] = 0x4,     /* OPCLK */
+	},
+};
+
+static struct s3c64xx_spi_csinfo wm5102_spi_csinfo = {
+	.line = S3C64XX_GPN(5),
+};
+
+static struct spi_board_info wm5102_spi_devs[] = {
+	[0] = {
+		.modalias	= "wm5102",
+		.max_speed_hz	= 10 * 1000 * 1000,
+		.bus_num	= 0,
+		.chip_select	= 0,
+		.mode		= SPI_MODE_0,
+		.irq		= GLENFARCLAS_PMIC_IRQ_BASE +
+				  WM831X_IRQ_GPIO_2,
+		.controller_data = &wm5102_spi_csinfo,
+		.platform_data = &wm5102_pdata,
+	},
 };
 
 static const struct i2c_board_info wm6230_i2c_devs[] = {
@@ -223,8 +248,9 @@ static __devinitdata const struct {
 	{ .id = 0x3c, .name = "1273-EV1 Longmorn" },
 	{ .id = 0x3d, .name = "1277-EV1 Littlemill",
 	  .i2c_devs = wm1277_devs, .num_i2c_devs = ARRAY_SIZE(wm1277_devs) },
-	{ .id = 0x3e, .name = "WM5102-6271-EV1-CS127",
-	  .i2c_devs = wm5102_devs, .num_i2c_devs = ARRAY_SIZE(wm5102_devs) },
+	{ .id = 0x3e, .name = "WM5102-6271-EV1-CS127 Amrut",
+	  .spi_devs = wm5102_spi_devs,
+	  .num_spi_devs = ARRAY_SIZE(wm5102_spi_devs) },
 };
 
 static __devinit int wlf_gf_module_probe(struct i2c_client *i2c,
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c
index 09cd812..c4b4198 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410.c
@@ -46,6 +46,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
 
+#include <video/samsung_fimd.h>
 #include <mach/hardware.h>
 #include <mach/map.h>
 
@@ -57,7 +58,6 @@
 #include <mach/regs-gpio-memport.h>
 
 #include <plat/regs-serial.h>
-#include <plat/regs-fb-v4.h>
 #include <plat/fb.h>
 #include <plat/sdhci.h>
 #include <plat/gpio-cfg.h>
@@ -287,6 +287,16 @@ static struct platform_device littlemill_device = {
 	.id		= -1,
 };
 
+static struct platform_device bells_wm5102_device = {
+	.name		= "bells",
+	.id		= 0,
+};
+
+static struct platform_device bells_wm5110_device = {
+	.name		= "bells",
+	.id		= 1,
+};
+
 static struct regulator_consumer_supply wallvdd_consumers[] = {
 	REGULATOR_SUPPLY("SPKVDD", "1-001a"),
 	REGULATOR_SUPPLY("SPKVDD1", "1-001a"),
@@ -359,6 +369,8 @@ static struct platform_device *crag6410_devices[] __initdata = {
 	&tobermory_device,
 	&littlemill_device,
 	&lowland_device,
+	&bells_wm5102_device,
+	&bells_wm5110_device,
 	&wallvdd_device,
 };
 
diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c
index 6890881..8ad0bfc 100644
--- a/arch/arm/mach-s3c64xx/mach-hmt.c
+++ b/arch/arm/mach-s3c64xx/mach-hmt.c
@@ -26,6 +26,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <video/samsung_fimd.h>
 #include <mach/hardware.h>
 #include <mach/map.h>
 
@@ -41,7 +42,6 @@
 #include <plat/clock.h>
 #include <plat/devs.h>
 #include <plat/cpu.h>
-#include <plat/regs-fb-v4.h>
 
 #include "common.h"
 
diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c
index 5539a255..96ebcc5 100644
--- a/arch/arm/mach-s3c64xx/mach-mini6410.c
+++ b/arch/arm/mach-s3c64xx/mach-mini6410.c
@@ -41,9 +41,9 @@
 #include <plat/nand.h>
 #include <plat/regs-serial.h>
 #include <plat/ts.h>
-#include <plat/regs-fb-v4.h>
 
 #include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
 
 #include "common.h"
 
diff --git a/arch/arm/mach-s3c64xx/mach-ncp.c b/arch/arm/mach-s3c64xx/mach-ncp.c
index cad2e05..48599bc 100644
--- a/arch/arm/mach-s3c64xx/mach-ncp.c
+++ b/arch/arm/mach-s3c64xx/mach-ncp.c
@@ -24,6 +24,7 @@
 #include <linux/delay.h>
 
 #include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
 
 #include <asm/hardware/vic.h>
 #include <asm/mach/arch.h>
@@ -43,7 +44,6 @@
 #include <plat/clock.h>
 #include <plat/devs.h>
 #include <plat/cpu.h>
-#include <plat/regs-fb-v4.h>
 
 #include "common.h"
 
diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c
index 326b216..76d3ffb 100644
--- a/arch/arm/mach-s3c64xx/mach-real6410.c
+++ b/arch/arm/mach-s3c64xx/mach-real6410.c
@@ -42,9 +42,9 @@
 #include <plat/nand.h>
 #include <plat/regs-serial.h>
 #include <plat/ts.h>
-#include <plat/regs-fb-v4.h>
 
 #include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
 
 #include "common.h"
 
diff --git a/arch/arm/mach-s3c64xx/mach-smartq5.c b/arch/arm/mach-s3c64xx/mach-smartq5.c
index d6266d8..96d6da2 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq5.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq5.c
@@ -21,6 +21,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+#include <video/samsung_fimd.h>
 #include <mach/map.h>
 #include <mach/regs-gpio.h>
 
@@ -28,7 +29,6 @@
 #include <plat/devs.h>
 #include <plat/fb.h>
 #include <plat/gpio-cfg.h>
-#include <plat/regs-fb-v4.h>
 
 #include "common.h"
 #include "mach-smartq.h"
diff --git a/arch/arm/mach-s3c64xx/mach-smartq7.c b/arch/arm/mach-s3c64xx/mach-smartq7.c
index 0957d2a..7d1167b 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq7.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq7.c
@@ -21,6 +21,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+#include <video/samsung_fimd.h>
 #include <mach/map.h>
 #include <mach/regs-gpio.h>
 
@@ -28,7 +29,6 @@
 #include <plat/devs.h>
 #include <plat/fb.h>
 #include <plat/gpio-cfg.h>
-#include <plat/regs-fb-v4.h>
 
 #include "common.h"
 #include "mach-smartq.h"
diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c
index 0fe4f15..d1378d7 100644
--- a/arch/arm/mach-s3c64xx/mach-smdk6410.c
+++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c
@@ -43,6 +43,7 @@
 #endif
 
 #include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
 
 #include <asm/hardware/vic.h>
 #include <asm/mach/arch.h>
@@ -72,7 +73,6 @@
 #include <plat/ts.h>
 #include <plat/keypad.h>
 #include <plat/backlight.h>
-#include <plat/regs-fb-v4.h>
 
 #include "common.h"
 
diff --git a/arch/arm/mach-s5p64x0/mach-smdk6440.c b/arch/arm/mach-s5p64x0/mach-smdk6440.c
index 92fefad..5d0b36e 100644
--- a/arch/arm/mach-s5p64x0/mach-smdk6440.c
+++ b/arch/arm/mach-s5p64x0/mach-smdk6440.c
@@ -27,6 +27,7 @@
 #include <linux/mmc/host.h>
 
 #include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
 
 #include <asm/hardware/vic.h>
 #include <asm/mach/arch.h>
@@ -52,7 +53,6 @@
 #include <plat/s5p-time.h>
 #include <plat/backlight.h>
 #include <plat/fb.h>
-#include <plat/regs-fb.h>
 #include <plat/sdhci.h>
 
 #include "common.h"
diff --git a/arch/arm/mach-s5p64x0/mach-smdk6450.c b/arch/arm/mach-s5p64x0/mach-smdk6450.c
index e2335ec..7522fb9 100644
--- a/arch/arm/mach-s5p64x0/mach-smdk6450.c
+++ b/arch/arm/mach-s5p64x0/mach-smdk6450.c
@@ -27,6 +27,7 @@
 #include <linux/mmc/host.h>
 
 #include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
 
 #include <asm/hardware/vic.h>
 #include <asm/mach/arch.h>
@@ -52,7 +53,6 @@
 #include <plat/s5p-time.h>
 #include <plat/backlight.h>
 #include <plat/fb.h>
-#include <plat/regs-fb.h>
 #include <plat/sdhci.h>
 
 #include "common.h"
diff --git a/arch/arm/mach-s5pc100/mach-smdkc100.c b/arch/arm/mach-s5pc100/mach-smdkc100.c
index 0c3ae38..c3dcafa 100644
--- a/arch/arm/mach-s5pc100/mach-smdkc100.c
+++ b/arch/arm/mach-s5pc100/mach-smdkc100.c
@@ -33,6 +33,7 @@
 #include <mach/regs-gpio.h>
 
 #include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
 
 #include <asm/irq.h>
 #include <asm/mach-types.h>
@@ -51,7 +52,6 @@
 #include <plat/ts.h>
 #include <plat/audio.h>
 #include <plat/backlight.h>
-#include <plat/regs-fb-v4.h>
 
 #include "common.h"
 
diff --git a/arch/arm/mach-s5pv210/mach-aquila.c b/arch/arm/mach-s5pv210/mach-aquila.c
index 78028df..ee9fa5c 100644
--- a/arch/arm/mach-s5pv210/mach-aquila.c
+++ b/arch/arm/mach-s5pv210/mach-aquila.c
@@ -28,6 +28,7 @@
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 
+#include <video/samsung_fimd.h>
 #include <mach/map.h>
 #include <mach/regs-clock.h>
 
@@ -39,7 +40,6 @@
 #include <plat/fimc-core.h>
 #include <plat/sdhci.h>
 #include <plat/s5p-time.h>
-#include <plat/regs-fb-v4.h>
 
 #include "common.h"
 
diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c
index 822a559..c552581 100644
--- a/arch/arm/mach-s5pv210/mach-goni.c
+++ b/arch/arm/mach-s5pv210/mach-goni.c
@@ -35,6 +35,7 @@
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 
+#include <video/samsung_fimd.h>
 #include <mach/map.h>
 #include <mach/regs-clock.h>
 
@@ -49,7 +50,6 @@
 #include <plat/clock.h>
 #include <plat/s5p-time.h>
 #include <plat/mfc.h>
-#include <plat/regs-fb-v4.h>
 #include <plat/camport.h>
 
 #include <media/v4l2-mediabus.h>
diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c
index 918b23d..9bfbedf 100644
--- a/arch/arm/mach-s5pv210/mach-smdkv210.c
+++ b/arch/arm/mach-s5pv210/mach-smdkv210.c
@@ -28,6 +28,7 @@
 #include <asm/mach-types.h>
 
 #include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
 
 #include <mach/map.h>
 #include <mach/regs-clock.h>
@@ -46,7 +47,6 @@
 #include <plat/fb.h>
 #include <plat/s5p-time.h>
 #include <plat/backlight.h>
-#include <plat/regs-fb-v4.h>
 #include <plat/mfc.h>
 #include <plat/clock.h>
 
diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile
index 60b97ec..1aed9e7 100644
--- a/arch/arm/mach-sa1100/Makefile
+++ b/arch/arm/mach-sa1100/Makefile
@@ -7,21 +7,17 @@ obj-y := clock.o generic.o irq.o time.o #nmi-oopser.o
 obj-m :=
 obj-n :=
 obj-  :=
-led-y := leds.o
 
 obj-$(CONFIG_CPU_FREQ_SA1100)		+= cpu-sa1100.o
 obj-$(CONFIG_CPU_FREQ_SA1110)		+= cpu-sa1110.o
 
 # Specific board support
 obj-$(CONFIG_SA1100_ASSABET)		+= assabet.o
-led-$(CONFIG_SA1100_ASSABET)		+= leds-assabet.o
 obj-$(CONFIG_ASSABET_NEPONSET)		+= neponset.o
 
 obj-$(CONFIG_SA1100_BADGE4)		+= badge4.o
-led-$(CONFIG_SA1100_BADGE4)		+= leds-badge4.o
 
 obj-$(CONFIG_SA1100_CERF)		+= cerf.o
-led-$(CONFIG_SA1100_CERF)		+= leds-cerf.o
 
 obj-$(CONFIG_SA1100_COLLIE)		+= collie.o
 
@@ -29,13 +25,11 @@ obj-$(CONFIG_SA1100_H3100)		+= h3100.o h3xxx.o
 obj-$(CONFIG_SA1100_H3600)		+= h3600.o h3xxx.o
 
 obj-$(CONFIG_SA1100_HACKKIT)		+= hackkit.o
-led-$(CONFIG_SA1100_HACKKIT)		+= leds-hackkit.o
 
 obj-$(CONFIG_SA1100_JORNADA720)		+= jornada720.o
 obj-$(CONFIG_SA1100_JORNADA720_SSP)	+= jornada720_ssp.o
 
 obj-$(CONFIG_SA1100_LART)		+= lart.o
-led-$(CONFIG_SA1100_LART)		+= leds-lart.o
 
 obj-$(CONFIG_SA1100_NANOENGINE)		+= nanoengine.o
 obj-$(CONFIG_PCI_NANOENGINE)		+= pci-nanoengine.o
@@ -46,9 +40,6 @@ obj-$(CONFIG_SA1100_SHANNON)		+= shannon.o
 
 obj-$(CONFIG_SA1100_SIMPAD)		+= simpad.o
 
-# LEDs support
-obj-$(CONFIG_LEDS) += $(led-y)
-
 # Miscellaneous functions
 obj-$(CONFIG_PM)			+= pm.o sleep.o
 obj-$(CONFIG_SA1100_SSP)		+= ssp.o
diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index d673211..1710ed1 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -20,6 +20,8 @@
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
 
 #include <video/sa1100fb.h>
 
@@ -529,6 +531,89 @@ static void __init assabet_map_io(void)
 	sa1100_register_uart(2, 3);
 }
 
+/* LEDs */
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct assabet_led {
+	struct led_classdev cdev;
+	u32 mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+	const char *name;
+	const char *trigger;
+} assabet_leds[] = {
+	{ "assabet:red", "cpu0",},
+	{ "assabet:green", "heartbeat", },
+};
+
+/*
+ * The LED control in Assabet is reversed:
+ *  - setting bit means turn off LED
+ *  - clearing bit means turn on LED
+ */
+static void assabet_led_set(struct led_classdev *cdev,
+		enum led_brightness b)
+{
+	struct assabet_led *led = container_of(cdev,
+			struct assabet_led, cdev);
+
+	if (b != LED_OFF)
+		ASSABET_BCR_clear(led->mask);
+	else
+		ASSABET_BCR_set(led->mask);
+}
+
+static enum led_brightness assabet_led_get(struct led_classdev *cdev)
+{
+	struct assabet_led *led = container_of(cdev,
+			struct assabet_led, cdev);
+
+	return (ASSABET_BCR & led->mask) ? LED_OFF : LED_FULL;
+}
+
+static int __init assabet_leds_init(void)
+{
+	int i;
+
+	if (!machine_is_assabet())
+		return -ENODEV;
+
+	for (i = 0; i < ARRAY_SIZE(assabet_leds); i++) {
+		struct assabet_led *led;
+
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
+
+		led->cdev.name = assabet_leds[i].name;
+		led->cdev.brightness_set = assabet_led_set;
+		led->cdev.brightness_get = assabet_led_get;
+		led->cdev.default_trigger = assabet_leds[i].trigger;
+
+		if (!i)
+			led->mask = ASSABET_BCR_LED_RED;
+		else
+			led->mask = ASSABET_BCR_LED_GREEN;
+
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(assabet_leds_init);
+#endif
 
 MACHINE_START(ASSABET, "Intel-Assabet")
 	.atag_offset	= 0x100,
diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
index b30fb99..038df48 100644
--- a/arch/arm/mach-sa1100/badge4.c
+++ b/arch/arm/mach-sa1100/badge4.c
@@ -22,6 +22,8 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -76,8 +78,36 @@ static struct platform_device sa1111_device = {
 	.resource	= sa1111_resources,
 };
 
+/* LEDs */
+struct gpio_led badge4_gpio_leds[] = {
+	{
+		.name			= "badge4:red",
+		.default_trigger	= "heartbeat",
+		.gpio			= 7,
+	},
+	{
+		.name			= "badge4:green",
+		.default_trigger	= "cpu0",
+		.gpio			= 9,
+	},
+};
+
+static struct gpio_led_platform_data badge4_gpio_led_info = {
+	.leds		= badge4_gpio_leds,
+	.num_leds	= ARRAY_SIZE(badge4_gpio_leds),
+};
+
+static struct platform_device badge4_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &badge4_gpio_led_info,
+	}
+};
+
 static struct platform_device *devices[] __initdata = {
 	&sa1111_device,
+	&badge4_leds,
 };
 
 static int __init badge4_sa1111_init(void)
diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c
index 09d7f4b..5240f10 100644
--- a/arch/arm/mach-sa1100/cerf.c
+++ b/arch/arm/mach-sa1100/cerf.c
@@ -17,6 +17,8 @@
 #include <linux/irq.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
 
 #include <mach/hardware.h>
 #include <asm/setup.h>
@@ -43,8 +45,48 @@ static struct platform_device cerfuart2_device = {
 	.resource	= cerfuart2_resources,
 };
 
+/* LEDs */
+struct gpio_led cerf_gpio_leds[] = {
+	{
+		.name			= "cerf:d0",
+		.default_trigger	= "heartbeat",
+		.gpio			= 0,
+	},
+	{
+		.name			= "cerf:d1",
+		.default_trigger	= "cpu0",
+		.gpio			= 1,
+	},
+	{
+		.name			= "cerf:d2",
+		.default_trigger	= "default-on",
+		.gpio			= 2,
+	},
+	{
+		.name			= "cerf:d3",
+		.default_trigger	= "default-on",
+		.gpio			= 3,
+	},
+
+};
+
+static struct gpio_led_platform_data cerf_gpio_led_info = {
+	.leds		= cerf_gpio_leds,
+	.num_leds	= ARRAY_SIZE(cerf_gpio_leds),
+};
+
+static struct platform_device cerf_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &cerf_gpio_led_info,
+	}
+};
+
+
 static struct platform_device *cerf_devices[] __initdata = {
 	&cerfuart2_device,
+	&cerf_leds,
 };
 
 #ifdef CONFIG_SA1100_CERF_FLASH_32MB
diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c
index 7f86bd9..fc106aa 100644
--- a/arch/arm/mach-sa1100/hackkit.c
+++ b/arch/arm/mach-sa1100/hackkit.c
@@ -21,6 +21,10 @@
 #include <linux/serial_core.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/tty.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
 
 #include <asm/mach-types.h>
 #include <asm/setup.h>
@@ -183,9 +187,37 @@ static struct flash_platform_data hackkit_flash_data = {
 static struct resource hackkit_flash_resource =
 	DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
 
+/* LEDs */
+struct gpio_led hackkit_gpio_leds[] = {
+	{
+		.name			= "hackkit:red",
+		.default_trigger	= "cpu0",
+		.gpio			= 22,
+	},
+	{
+		.name			= "hackkit:green",
+		.default_trigger	= "heartbeat",
+		.gpio			= 23,
+	},
+};
+
+static struct gpio_led_platform_data hackkit_gpio_led_info = {
+	.leds		= hackkit_gpio_leds,
+	.num_leds	= ARRAY_SIZE(hackkit_gpio_leds),
+};
+
+static struct platform_device hackkit_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &hackkit_gpio_led_info,
+	}
+};
+
 static void __init hackkit_init(void)
 {
 	sa11x0_register_mtd(&hackkit_flash_data, &hackkit_flash_resource, 1);
+	platform_device_register(&hackkit_leds);
 }
 
 /**********************************************************************
diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c
index b775a0a..b2ce04b 100644
--- a/arch/arm/mach-sa1100/lart.c
+++ b/arch/arm/mach-sa1100/lart.c
@@ -5,6 +5,9 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/tty.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
 
 #include <video/sa1100fb.h>
 
@@ -126,6 +129,27 @@ static struct map_desc lart_io_desc[] __initdata = {
 	}
 };
 
+/* LEDs */
+struct gpio_led lart_gpio_leds[] = {
+	{
+		.name			= "lart:red",
+		.default_trigger	= "cpu0",
+		.gpio			= 23,
+	},
+};
+
+static struct gpio_led_platform_data lart_gpio_led_info = {
+	.leds		= lart_gpio_leds,
+	.num_leds	= ARRAY_SIZE(lart_gpio_leds),
+};
+
+static struct platform_device lart_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &lart_gpio_led_info,
+	}
+};
 static void __init lart_map_io(void)
 {
 	sa1100_map_io();
@@ -139,6 +163,8 @@ static void __init lart_map_io(void)
 	GPDR |= GPIO_UART_TXD;
 	GPDR &= ~GPIO_UART_RXD;
 	PPAR |= PPAR_UPR;
+
+	platform_device_register(&lart_leds);
 }
 
 MACHINE_START(LART, "LART")
diff --git a/arch/arm/mach-sa1100/leds-assabet.c b/arch/arm/mach-sa1100/leds-assabet.c
deleted file mode 100644
index 3699176..0000000
--- a/arch/arm/mach-sa1100/leds-assabet.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds-assabet.c
- *
- * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
- *
- * Original (leds-footbridge.c) by Russell King
- *
- * Assabet uses the LEDs as follows:
- *   - Green - toggles state every 50 timer interrupts
- *   - Red   - on if system is not idle
- */
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <mach/assabet.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-#define ASSABET_BCR_LED_MASK	(ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED)
-
-void assabet_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch (evt) {
-	case led_start:
-		hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN;
-		led_state = LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN;
-		ASSABET_BCR_frob(ASSABET_BCR_LED_MASK, hw_led_state);
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state ^= ASSABET_BCR_LED_GREEN;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= ASSABET_BCR_LED_RED;
-		break;
-
-	case led_idle_end:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~ASSABET_BCR_LED_RED;
-		break;
-#endif
-
-	case led_halted:
-		break;
-
-	case led_green_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~ASSABET_BCR_LED_GREEN;
-		break;
-
-	case led_green_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= ASSABET_BCR_LED_GREEN;
-		break;
-
-	case led_amber_on:
-		break;
-
-	case led_amber_off:
-		break;
-
-	case led_red_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~ASSABET_BCR_LED_RED;
-		break;
-
-	case led_red_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= ASSABET_BCR_LED_RED;
-		break;
-
-	default:
-		break;
-	}
-
-	if  (led_state & LED_STATE_ENABLED)
-		ASSABET_BCR_frob(ASSABET_BCR_LED_MASK, hw_led_state);
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-sa1100/leds-badge4.c b/arch/arm/mach-sa1100/leds-badge4.c
deleted file mode 100644
index f99fac3..0000000
--- a/arch/arm/mach-sa1100/leds-badge4.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds-badge4.c
- *
- * Author: Christopher Hoover <ch@hpl.hp.com>
- * Copyright (C) 2002 Hewlett-Packard Company
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-#define LED_RED		GPIO_GPIO(7)
-#define LED_GREEN       GPIO_GPIO(9)
-#define LED_MASK	(LED_RED|LED_GREEN)
-
-#define LED_IDLE	LED_GREEN
-#define LED_TIMER	LED_RED
-
-void badge4_leds_event(led_event_t evt)
-{
-        unsigned long flags;
-
-	local_irq_save(flags);
-
-        switch (evt) {
-        case led_start:
-		GPDR |= LED_MASK;
-                hw_led_state = LED_MASK;
-                led_state = LED_STATE_ENABLED;
-                break;
-
-        case led_stop:
-                led_state &= ~LED_STATE_ENABLED;
-                break;
-
-        case led_claim:
-                led_state |= LED_STATE_CLAIMED;
-                hw_led_state = LED_MASK;
-                break;
-
-        case led_release:
-                led_state &= ~LED_STATE_CLAIMED;
-                hw_led_state = LED_MASK;
-                break;
-
-#ifdef CONFIG_LEDS_TIMER
-        case led_timer:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state ^= LED_TIMER;
-                break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-        case led_idle_start:
-		/* LED off when system is idle */
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_IDLE;
-                break;
-
-        case led_idle_end:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_IDLE;
-                break;
-#endif
-
-        case led_red_on:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_RED;
-                break;
-
-        case led_red_off:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_RED;
-                break;
-
-        case led_green_on:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_GREEN;
-                break;
-
-        case led_green_off:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_GREEN;
-                break;
-
-	default:
-		break;
-        }
-
-        if  (led_state & LED_STATE_ENABLED) {
-                GPSR = hw_led_state;
-                GPCR = hw_led_state ^ LED_MASK;
-        }
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-sa1100/leds-cerf.c b/arch/arm/mach-sa1100/leds-cerf.c
deleted file mode 100644
index 30fc3b2..0000000
--- a/arch/arm/mach-sa1100/leds-cerf.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds-cerf.c
- *
- * Author: ???
- */
-#include <linux/init.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-#define LED_D0          GPIO_GPIO(0)
-#define LED_D1          GPIO_GPIO(1)
-#define LED_D2          GPIO_GPIO(2)
-#define LED_D3          GPIO_GPIO(3)
-#define LED_MASK        (LED_D0|LED_D1|LED_D2|LED_D3)
-
-void cerf_leds_event(led_event_t evt)
-{
-        unsigned long flags;
-
-	local_irq_save(flags);
-
-        switch (evt) {
-        case led_start:
-                hw_led_state = LED_MASK;
-                led_state = LED_STATE_ENABLED;
-                break;
-
-        case led_stop:
-                led_state &= ~LED_STATE_ENABLED;
-                break;
-
-        case led_claim:
-                led_state |= LED_STATE_CLAIMED;
-                hw_led_state = LED_MASK;
-                break;
-        case led_release:
-                led_state &= ~LED_STATE_CLAIMED;
-                hw_led_state = LED_MASK;
-                break;
-
-#ifdef CONFIG_LEDS_TIMER
-        case led_timer:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state ^= LED_D0;
-                break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-        case led_idle_start:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_D1;
-                break;
-
-        case led_idle_end:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_D1;
-                break;
-#endif
-        case led_green_on:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_D2;
-                break;
-
-        case led_green_off:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_D2;
-                break;
-
-        case led_amber_on:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_D3;
-                break;
-
-        case led_amber_off:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_D3;
-                break;
-
-        case led_red_on:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_D1;
-                break;
-
-        case led_red_off:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_D1;
-                break;
-
-        default:
-                break;
-        }
-
-        if  (led_state & LED_STATE_ENABLED) {
-                GPSR = hw_led_state;
-                GPCR = hw_led_state ^ LED_MASK;
-        }
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-sa1100/leds-hackkit.c b/arch/arm/mach-sa1100/leds-hackkit.c
deleted file mode 100644
index f8e4723..0000000
--- a/arch/arm/mach-sa1100/leds-hackkit.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds-hackkit.c
- *
- * based on leds-lart.c
- *
- * (C) Erik Mouw (J.A.K.Mouw@its.tudelft.nl), April 21, 2000
- * (C) Stefan Eletzhofer <stefan.eletzhofer@eletztrick.de>, 2002
- *
- * The HackKit has two leds (GPIO 22/23). The red led (gpio 22) is used
- * as cpu led, the green one is used as timer led.
- */
-#include <linux/init.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-#define LED_GREEN    GPIO_GPIO23
-#define LED_RED    GPIO_GPIO22
-#define LED_MASK  (LED_RED | LED_GREEN)
-
-void hackkit_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch(evt) {
-		case led_start:
-			/* pin 22/23 are outputs */
-			GPDR |= LED_MASK;
-			hw_led_state = LED_MASK;
-			led_state = LED_STATE_ENABLED;
-			break;
-
-		case led_stop:
-			led_state &= ~LED_STATE_ENABLED;
-			break;
-
-		case led_claim:
-			led_state |= LED_STATE_CLAIMED;
-			hw_led_state = LED_MASK;
-			break;
-
-		case led_release:
-			led_state &= ~LED_STATE_CLAIMED;
-			hw_led_state = LED_MASK;
-			break;
-
-#ifdef CONFIG_LEDS_TIMER
-		case led_timer:
-			if (!(led_state & LED_STATE_CLAIMED))
-				hw_led_state ^= LED_GREEN;
-			break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-		case led_idle_start:
-			/* The LART people like the LED to be off when the
-			   system is idle... */
-			if (!(led_state & LED_STATE_CLAIMED))
-				hw_led_state &= ~LED_RED;
-			break;
-
-		case led_idle_end:
-			/* ... and on if the system is not idle */
-			if (!(led_state & LED_STATE_CLAIMED))
-				hw_led_state |= LED_RED;
-			break;
-#endif
-
-		case led_red_on:
-			if (led_state & LED_STATE_CLAIMED)
-				hw_led_state &= ~LED_RED;
-			break;
-
-		case led_red_off:
-			if (led_state & LED_STATE_CLAIMED)
-				hw_led_state |= LED_RED;
-			break;
-
-		case led_green_on:
-			if (led_state & LED_STATE_CLAIMED)
-				hw_led_state &= ~LED_GREEN;
-			break;
-
-		case led_green_off:
-			if (led_state & LED_STATE_CLAIMED)
-				hw_led_state |= LED_GREEN;
-			break;
-
-		default:
-			break;
-	}
-
-	/* Now set the GPIO state, or nothing will happen at all */
-	if (led_state & LED_STATE_ENABLED) {
-		GPSR = hw_led_state;
-		GPCR = hw_led_state ^ LED_MASK;
-	}
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-sa1100/leds-lart.c b/arch/arm/mach-sa1100/leds-lart.c
deleted file mode 100644
index 50a5b14..0000000
--- a/arch/arm/mach-sa1100/leds-lart.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds-lart.c
- *
- * (C) Erik Mouw (J.A.K.Mouw@its.tudelft.nl), April 21, 2000
- *
- * LART uses the LED as follows:
- *   - GPIO23 is the LED, on if system is not idle
- *  You can use both CONFIG_LEDS_CPU and CONFIG_LEDS_TIMER at the same
- *  time, but in that case the timer events will still dictate the
- *  pace of the LED.
- */
-#include <linux/init.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-#define LED_23    GPIO_GPIO23
-#define LED_MASK  (LED_23)
-
-void lart_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch(evt) {
-	case led_start:
-		/* pin 23 is output pin */
-		GPDR |= LED_23;
-		hw_led_state = LED_MASK;
-		led_state = LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		led_state &= ~LED_STATE_ENABLED;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = LED_MASK;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = LED_MASK;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state ^= LED_23;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		/* The LART people like the LED to be off when the
-                   system is idle... */
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~LED_23;
-		break;
-
-	case led_idle_end:
-		/* ... and on if the system is not idle */
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= LED_23;
-		break;
-#endif
-
-	case led_red_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~LED_23;
-		break;
-
-	case led_red_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= LED_23;
-		break;
-
-	default:
-		break;
-	}
-
-	/* Now set the GPIO state, or nothing will happen at all */
-	if (led_state & LED_STATE_ENABLED) {
-		GPSR = hw_led_state;
-		GPCR = hw_led_state ^ LED_MASK;
-	}
-
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-sa1100/leds.c b/arch/arm/mach-sa1100/leds.c
deleted file mode 100644
index 5fe71a0..0000000
--- a/arch/arm/mach-sa1100/leds.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds.c
- *
- * SA1100 LEDs dispatcher
- *
- * Copyright (C) 2001 Nicolas Pitre
- */
-#include <linux/compiler.h>
-#include <linux/init.h>
-
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#include "leds.h"
-
-static int __init
-sa1100_leds_init(void)
-{
-	if (machine_is_assabet())
-		leds_event = assabet_leds_event;
-	if (machine_is_consus())
-		leds_event = consus_leds_event;
-	if (machine_is_badge4())
-		leds_event = badge4_leds_event;
-	if (machine_is_brutus())
-		leds_event = brutus_leds_event;
-	if (machine_is_cerf())
-		leds_event = cerf_leds_event;
-	if (machine_is_flexanet())
-		leds_event = flexanet_leds_event;
-	if (machine_is_graphicsclient())
-		leds_event = graphicsclient_leds_event;
-	if (machine_is_hackkit())
-		leds_event = hackkit_leds_event;
-	if (machine_is_lart())
-		leds_event = lart_leds_event;
-	if (machine_is_pfs168())
-		leds_event = pfs168_leds_event;
-	if (machine_is_graphicsmaster())
-		leds_event = graphicsmaster_leds_event;
-	if (machine_is_adsbitsy())
-		leds_event = adsbitsy_leds_event;
-	if (machine_is_pt_system3())
-		leds_event = system3_leds_event;
-
-	leds_event(led_start);
-	return 0;
-}
-
-core_initcall(sa1100_leds_init);
diff --git a/arch/arm/mach-sa1100/leds.h b/arch/arm/mach-sa1100/leds.h
deleted file mode 100644
index 776b602..0000000
--- a/arch/arm/mach-sa1100/leds.h
+++ /dev/null
@@ -1,13 +0,0 @@
-extern void assabet_leds_event(led_event_t evt);
-extern void badge4_leds_event(led_event_t evt);
-extern void consus_leds_event(led_event_t evt);
-extern void brutus_leds_event(led_event_t evt);
-extern void cerf_leds_event(led_event_t evt);
-extern void flexanet_leds_event(led_event_t evt);
-extern void graphicsclient_leds_event(led_event_t evt);
-extern void hackkit_leds_event(led_event_t evt);
-extern void lart_leds_event(led_event_t evt);
-extern void pfs168_leds_event(led_event_t evt);
-extern void graphicsmaster_leds_event(led_event_t evt);
-extern void adsbitsy_leds_event(led_event_t evt);
-extern void system3_leds_event(led_event_t evt);
diff --git a/arch/arm/mach-shark/Makefile b/arch/arm/mach-shark/Makefile
index 45be9b0..2965718 100644
--- a/arch/arm/mach-shark/Makefile
+++ b/arch/arm/mach-shark/Makefile
@@ -4,9 +4,7 @@
 
 # Object file lists.
 
-obj-y			:= core.o dma.o irq.o pci.o
+obj-y			:= core.o dma.o irq.o pci.o leds.o
 obj-m			:=
 obj-n			:=
 obj-			:=
-
-obj-$(CONFIG_LEDS)	+= leds.o
diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
index 2704bcd..9ad2e97 100644
--- a/arch/arm/mach-shark/core.c
+++ b/arch/arm/mach-shark/core.c
@@ -13,7 +13,6 @@
 
 #include <asm/setup.h>
 #include <asm/mach-types.h>
-#include <asm/leds.h>
 #include <asm/param.h>
 #include <asm/system_misc.h>
 
@@ -21,9 +20,6 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 
-#define IO_BASE                 0xe0000000
-#define IO_SIZE                 0x08000000
-#define IO_START                0x40000000
 #define ROMCARD_SIZE            0x08000000
 #define ROMCARD_START           0x10000000
 
@@ -104,20 +100,6 @@ arch_initcall(shark_init);
 
 extern void shark_init_irq(void);
 
-static struct map_desc shark_io_desc[] __initdata = {
-	{
-		.virtual	= IO_BASE,
-		.pfn		= __phys_to_pfn(IO_START),
-		.length		= IO_SIZE,
-		.type		= MT_DEVICE
-	}
-};
-
-static void __init shark_map_io(void)
-{
-	iotable_init(shark_io_desc, ARRAY_SIZE(shark_io_desc));
-}
-
 #define IRQ_TIMER 0
 #define HZ_TIME ((1193180 + HZ/2) / HZ)
 
@@ -158,7 +140,6 @@ static void shark_init_early(void)
 MACHINE_START(SHARK, "Shark")
 	/* Maintainer: Alexander Schulz */
 	.atag_offset	= 0x3000,
-	.map_io		= shark_map_io,
 	.init_early	= shark_init_early,
 	.init_irq	= shark_init_irq,
 	.timer		= &shark_timer,
diff --git a/arch/arm/mach-shark/include/mach/debug-macro.S b/arch/arm/mach-shark/include/mach/debug-macro.S
index 20eb2bf..d129119 100644
--- a/arch/arm/mach-shark/include/mach/debug-macro.S
+++ b/arch/arm/mach-shark/include/mach/debug-macro.S
@@ -12,9 +12,10 @@
 */
 
 		.macro	addruart, rp, rv, tmp
-		mov	\rp, #0xe0000000
-		orr	\rp, \rp, #0x000003f8
-		mov	\rv, \rp
+		mov	\rp, #0x3f8
+		orr	\rv, \rp, #0xfe000000
+		orr	\rv, \rv, #0x00e00000
+		orr	\rp, \rp, #0x40000000
 		.endm
 
 		.macro	senduart,rd,rx
diff --git a/arch/arm/mach-shark/include/mach/entry-macro.S b/arch/arm/mach-shark/include/mach/entry-macro.S
index 5901b09..c9e49f0 100644
--- a/arch/arm/mach-shark/include/mach/entry-macro.S
+++ b/arch/arm/mach-shark/include/mach/entry-macro.S
@@ -8,7 +8,8 @@
  * warranty of any kind, whether express or implied.
  */
 		.macro  get_irqnr_preamble, base, tmp
-		mov	\base, #0xe0000000
+		mov	\base, #0xfe000000
+		orr	\base, \base, #0x00e00000
 		.endm
 
 		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
diff --git a/arch/arm/mach-shark/include/mach/io.h b/arch/arm/mach-shark/include/mach/io.h
deleted file mode 100644
index 1a45fc0..0000000
--- a/arch/arm/mach-shark/include/mach/io.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * arch/arm/mach-shark/include/mach/io.h
- *
- * by Alexander Schulz
- *
- * derived from:
- * arch/arm/mach-ebsa110/include/mach/io.h
- * Copyright (C) 1997,1998 Russell King
- */
-
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(a)                 ((void __iomem *)(0xe0000000 + (a)))
-
-#endif
diff --git a/arch/arm/mach-shark/leds.c b/arch/arm/mach-shark/leds.c
index 2560907..081c778 100644
--- a/arch/arm/mach-shark/leds.c
+++ b/arch/arm/mach-shark/leds.c
@@ -1,165 +1,117 @@
 /*
- * arch/arm/mach-shark/leds.c
- * by Alexander Schulz
- *
- * derived from:
- * arch/arm/kernel/leds-footbridge.c
- * Copyright (C) 1998-1999 Russell King
- *
  * DIGITAL Shark LED control routines.
  *
- * The leds use is as follows:
- *  - Green front - toggles state every 50 timer interrupts
- *  - Amber front - Unused, this is a dual color led (Amber/Green)
- *  - Amber back  - On if system is not idle
+ * Driver for the 3 user LEDs found on the Shark
+ * Based on Versatile and RealView machine LED code
  *
- * Changelog:
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Bryan Wu <bryan.wu@canonical.com>
  */
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/ioport.h>
 #include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
-#include <asm/leds.h>
+#include <asm/mach-types.h>
 
-#define LED_STATE_ENABLED	1
-#define LED_STATE_CLAIMED	2
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct shark_led {
+	struct led_classdev cdev;
+	u8 mask;
+};
 
-#define SEQUOIA_LED_GREEN       (1<<6)
-#define SEQUOIA_LED_AMBER       (1<<5)
-#define SEQUOIA_LED_BACK        (1<<7)
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+	const char *name;
+	const char *trigger;
+} shark_leds[] = {
+	{ "shark:amber0", "default-on", },	/* Bit 5 */
+	{ "shark:green", "heartbeat", },	/* Bit 6 */
+	{ "shark:amber1", "cpu0" },		/* Bit 7 */
+};
+
+static u16 led_reg_read(void)
+{
+	outw(0x09, 0x24);
+	return inw(0x26);
+}
 
-static char led_state;
-static short hw_led_state;
-static short saved_state;
+static void led_reg_write(u16 value)
+{
+	outw(0x09, 0x24);
+	outw(value, 0x26);
+}
 
-static DEFINE_RAW_SPINLOCK(leds_lock);
+static void shark_led_set(struct led_classdev *cdev,
+			      enum led_brightness b)
+{
+	struct shark_led *led = container_of(cdev,
+						 struct shark_led, cdev);
+	u16 reg = led_reg_read();
 
-short sequoia_read(int addr) {
-  outw(addr,0x24);
-  return inw(0x26);
-}
+	if (b != LED_OFF)
+		reg |= led->mask;
+	else
+		reg &= ~led->mask;
 
-void sequoia_write(short value,short addr) {
-  outw(addr,0x24);
-  outw(value,0x26);
+	led_reg_write(reg);
 }
 
-static void sequoia_leds_event(led_event_t evt)
+static enum led_brightness shark_led_get(struct led_classdev *cdev)
 {
-	unsigned long flags;
-
-	raw_spin_lock_irqsave(&leds_lock, flags);
+	struct shark_led *led = container_of(cdev,
+						 struct shark_led, cdev);
+	u16 reg = led_reg_read();
 
-	hw_led_state = sequoia_read(0x09);
+	return (reg & led->mask) ? LED_FULL : LED_OFF;
+}
 
-	switch (evt) {
-	case led_start:
-		hw_led_state |= SEQUOIA_LED_GREEN;
-		hw_led_state |= SEQUOIA_LED_AMBER;
-#ifdef CONFIG_LEDS_CPU
-		hw_led_state |= SEQUOIA_LED_BACK;
-#else
-		hw_led_state &= ~SEQUOIA_LED_BACK;
-#endif
-		led_state |= LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-		hw_led_state &= ~SEQUOIA_LED_BACK;
-		hw_led_state |= SEQUOIA_LED_GREEN;
-		hw_led_state |= SEQUOIA_LED_AMBER;
-		led_state &= ~LED_STATE_ENABLED;
-		break;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		saved_state = hw_led_state;
-		hw_led_state &= ~SEQUOIA_LED_BACK;
-		hw_led_state |= SEQUOIA_LED_GREEN;
-		hw_led_state |= SEQUOIA_LED_AMBER;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		hw_led_state = saved_state;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state ^= SEQUOIA_LED_GREEN;
-		break;
-#endif
+static int __init shark_leds_init(void)
+{
+	int i;
+	u16 reg;
 
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state &= ~SEQUOIA_LED_BACK;
-		break;
+	if (!machine_is_shark())
+		return -ENODEV;
 
-	case led_idle_end:
-		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_state |= SEQUOIA_LED_BACK;
-		break;
-#endif
+	for (i = 0; i < ARRAY_SIZE(shark_leds); i++) {
+		struct shark_led *led;
 
-	case led_green_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~SEQUOIA_LED_GREEN;
-		break;
-
-	case led_green_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= SEQUOIA_LED_GREEN;
-		break;
-
-	case led_amber_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~SEQUOIA_LED_AMBER;
-		break;
-
-	case led_amber_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= SEQUOIA_LED_AMBER;
-		break;
-
-	case led_red_on:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state |= SEQUOIA_LED_BACK;
-		break;
-
-	case led_red_off:
-		if (led_state & LED_STATE_CLAIMED)
-			hw_led_state &= ~SEQUOIA_LED_BACK;
-		break;
-
-	default:
-		break;
-	}
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
 
-	if  (led_state & LED_STATE_ENABLED)
-		sequoia_write(hw_led_state,0x09);
+		led->cdev.name = shark_leds[i].name;
+		led->cdev.brightness_set = shark_led_set;
+		led->cdev.brightness_get = shark_led_get;
+		led->cdev.default_trigger = shark_leds[i].trigger;
 
-	raw_spin_unlock_irqrestore(&leds_lock, flags);
-}
+		/* Count in 5 bits offset */
+		led->mask = BIT(i + 5);
 
-static int __init leds_init(void)
-{
-	extern void (*leds_event)(led_event_t);
-	short temp;
-	
-	leds_event = sequoia_leds_event;
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
+	}
 
 	/* Make LEDs independent of power-state */
-	request_region(0x24,4,"sequoia");
-	temp = sequoia_read(0x09);
-	temp |= 1<<10;
-	sequoia_write(temp,0x09);
-	leds_event(led_start);
+	request_region(0x24, 4, "led_reg");
+	reg = led_reg_read();
+	reg |= 1 << 10;
+	led_reg_write(reg);
+
 	return 0;
 }
 
-__initcall(leds_init);
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(shark_leds_init);
+#endif
diff --git a/arch/arm/mach-shark/pci.c b/arch/arm/mach-shark/pci.c
index 9089407..b8b4ab3 100644
--- a/arch/arm/mach-shark/pci.c
+++ b/arch/arm/mach-shark/pci.c
@@ -8,12 +8,15 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <video/vga.h>
 
 #include <asm/irq.h>
 #include <asm/mach/pci.h>
 #include <asm/mach-types.h>
 
+#define IO_START	0x40000000
+
 static int __init shark_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
 	if (dev->bus->number == 0)
@@ -44,6 +47,8 @@ static int __init shark_pci_init(void)
 	pcibios_min_mem = 0x50000000;
 	vga_base = 0xe8000000;
 
+	pci_ioremap_io(0, IO_START);
+
 	pci_common_init(&shark_pci);
 
 	return 0;
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
index 0df5ae6..fe2c97c 100644
--- a/arch/arm/mach-shmobile/Makefile
+++ b/arch/arm/mach-shmobile/Makefile
@@ -3,7 +3,7 @@
 #
 
 # Common objects
-obj-y				:= timer.o console.o clock.o common.o
+obj-y				:= timer.o console.o clock.o
 
 # CPU objects
 obj-$(CONFIG_ARCH_SH7367)	+= setup-sh7367.o clock-sh7367.o intc-sh7367.o
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index f172ca8..5168a03 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -1229,6 +1229,15 @@ static struct i2c_board_info i2c1_devices[] = {
 #define USCCR1		0xE6058144
 static void __init ap4evb_init(void)
 {
+	struct pm_domain_device domain_devices[] = {
+		{ "A4LC", &lcdc1_device, },
+		{ "A4LC", &lcdc_device, },
+		{ "A4MP", &fsi_device, },
+		{ "A3SP", &sh_mmcif_device, },
+		{ "A3SP", &sdhi0_device, },
+		{ "A3SP", &sdhi1_device, },
+		{ "A4R", &ceu_device, },
+	};
 	u32 srcr4;
 	struct clk *clk;
 
@@ -1461,14 +1470,8 @@ static void __init ap4evb_init(void)
 
 	platform_add_devices(ap4evb_devices, ARRAY_SIZE(ap4evb_devices));
 
-	rmobile_add_device_to_domain(&sh7372_pd_a4lc, &lcdc1_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a4lc, &lcdc_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a4mp, &fsi_device);
-
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sh_mmcif_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi0_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi1_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a4r, &ceu_device);
+	rmobile_add_devices_to_domains(domain_devices,
+				       ARRAY_SIZE(domain_devices));
 
 	hdmi_init_pm_clock();
 	fsi_init_pm_clock();
diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c
index cf10f92..28e6e1d 100644
--- a/arch/arm/mach-shmobile/board-armadillo800eva.c
+++ b/arch/arm/mach-shmobile/board-armadillo800eva.c
@@ -1181,10 +1181,10 @@ static void __init eva_init(void)
 
 	eva_clock_init();
 
-	rmobile_add_device_to_domain(&r8a7740_pd_a4lc, &lcdc0_device);
-	rmobile_add_device_to_domain(&r8a7740_pd_a4lc, &hdmi_lcdc_device);
+	rmobile_add_device_to_domain("A4LC", &lcdc0_device);
+	rmobile_add_device_to_domain("A4LC", &hdmi_lcdc_device);
 	if (usb)
-		rmobile_add_device_to_domain(&r8a7740_pd_a3sp, usb);
+		rmobile_add_device_to_domain("A3SP", usb);
 }
 
 static void __init eva_earlytimer_init(void)
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index 7ea2b31..d1e8fe8 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -1409,6 +1409,22 @@ static struct i2c_board_info i2c1_devices[] = {
 #define USCCR1		0xE6058144
 static void __init mackerel_init(void)
 {
+	struct pm_domain_device domain_devices[] = {
+		{ "A4LC", &lcdc_device, },
+		{ "A4LC", &hdmi_lcdc_device, },
+		{ "A4LC", &meram_device, },
+		{ "A4MP", &fsi_device, },
+		{ "A3SP", &usbhs0_device, },
+		{ "A3SP", &usbhs1_device, },
+		{ "A3SP", &nand_flash_device, },
+		{ "A3SP", &sh_mmcif_device, },
+		{ "A3SP", &sdhi0_device, },
+#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
+		{ "A3SP", &sdhi1_device, },
+#endif
+		{ "A3SP", &sdhi2_device, },
+		{ "A4R", &ceu_device, },
+	};
 	u32 srcr4;
 	struct clk *clk;
 
@@ -1623,20 +1639,8 @@ static void __init mackerel_init(void)
 
 	platform_add_devices(mackerel_devices, ARRAY_SIZE(mackerel_devices));
 
-	rmobile_add_device_to_domain(&sh7372_pd_a4lc, &lcdc_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a4lc, &hdmi_lcdc_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a4lc, &meram_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a4mp, &fsi_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &usbhs0_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &usbhs1_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &nand_flash_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sh_mmcif_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi0_device);
-#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi1_device);
-#endif
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi2_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a4r, &ceu_device);
+	rmobile_add_devices_to_domains(domain_devices,
+				       ARRAY_SIZE(domain_devices));
 
 	hdmi_init_pm_clock();
 	sh7372_pm_init();
diff --git a/arch/arm/mach-shmobile/common.c b/arch/arm/mach-shmobile/common.c
deleted file mode 100644
index 608aba9..0000000
--- a/arch/arm/mach-shmobile/common.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <mach/common.h>
-
-void __init shmobile_init_late(void)
-{
-	shmobile_suspend_init();
-	shmobile_cpuidle_init();
-}
diff --git a/arch/arm/mach-shmobile/cpuidle.c b/arch/arm/mach-shmobile/cpuidle.c
index 7b541e9..9e05026 100644
--- a/arch/arm/mach-shmobile/cpuidle.c
+++ b/arch/arm/mach-shmobile/cpuidle.c
@@ -16,51 +16,38 @@
 #include <asm/cpuidle.h>
 #include <asm/io.h>
 
-static void shmobile_enter_wfi(void)
+int shmobile_enter_wfi(struct cpuidle_device *dev, struct cpuidle_driver *drv,
+		       int index)
 {
 	cpu_do_idle();
-}
-
-void (*shmobile_cpuidle_modes[CPUIDLE_STATE_MAX])(void) = {
-	shmobile_enter_wfi, /* regular sleep mode */
-};
-
-static int shmobile_cpuidle_enter(struct cpuidle_device *dev,
-				  struct cpuidle_driver *drv,
-				  int index)
-{
-	shmobile_cpuidle_modes[index]();
-
-	return index;
+	return 0;
 }
 
 static struct cpuidle_device shmobile_cpuidle_dev;
-static struct cpuidle_driver shmobile_cpuidle_driver = {
+static struct cpuidle_driver shmobile_cpuidle_default_driver = {
 	.name			= "shmobile_cpuidle",
 	.owner			= THIS_MODULE,
 	.en_core_tk_irqen	= 1,
 	.states[0]		= ARM_CPUIDLE_WFI_STATE,
+	.states[0].enter	= shmobile_enter_wfi,
 	.safe_state_index	= 0, /* C1 */
 	.state_count		= 1,
 };
 
-void (*shmobile_cpuidle_setup)(struct cpuidle_driver *drv);
+static struct cpuidle_driver *cpuidle_drv = &shmobile_cpuidle_default_driver;
+
+void shmobile_cpuidle_set_driver(struct cpuidle_driver *drv)
+{
+	cpuidle_drv = drv;
+}
 
 int shmobile_cpuidle_init(void)
 {
 	struct cpuidle_device *dev = &shmobile_cpuidle_dev;
-	struct cpuidle_driver *drv = &shmobile_cpuidle_driver;
-	int i;
-
-	for (i = 0; i < CPUIDLE_STATE_MAX; i++)
-		drv->states[i].enter = shmobile_cpuidle_enter;
-
-	if (shmobile_cpuidle_setup)
-		shmobile_cpuidle_setup(drv);
 
-	cpuidle_register_driver(drv);
+	cpuidle_register_driver(cpuidle_drv);
 
-	dev->state_count = drv->state_count;
+	dev->state_count = cpuidle_drv->state_count;
 	cpuidle_register_device(dev);
 
 	return 0;
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h
index 45e61da..eb89293 100644
--- a/arch/arm/mach-shmobile/include/mach/common.h
+++ b/arch/arm/mach-shmobile/include/mach/common.h
@@ -14,8 +14,10 @@ extern int shmobile_clk_init(void);
 extern void shmobile_handle_irq_intc(struct pt_regs *);
 extern struct platform_suspend_ops shmobile_suspend_ops;
 struct cpuidle_driver;
-extern void (*shmobile_cpuidle_modes[])(void);
-extern void (*shmobile_cpuidle_setup)(struct cpuidle_driver *drv);
+struct cpuidle_device;
+extern int shmobile_enter_wfi(struct cpuidle_device *dev,
+			      struct cpuidle_driver *drv, int index);
+extern void shmobile_cpuidle_set_driver(struct cpuidle_driver *drv);
 
 extern void sh7367_init_irq(void);
 extern void sh7367_map_io(void);
@@ -86,8 +88,6 @@ extern int r8a7779_boot_secondary(unsigned int cpu);
 extern void r8a7779_smp_prepare_cpus(void);
 extern void r8a7779_register_twd(void);
 
-extern void shmobile_init_late(void);
-
 #ifdef CONFIG_SUSPEND
 int shmobile_suspend_init(void);
 #else
@@ -100,4 +100,10 @@ int shmobile_cpuidle_init(void);
 static inline int shmobile_cpuidle_init(void) { return 0; }
 #endif
 
+static inline void shmobile_init_late(void)
+{
+	shmobile_suspend_init();
+	shmobile_cpuidle_init();
+}
+
 #endif /* __ARCH_MACH_COMMON_H */
diff --git a/arch/arm/mach-shmobile/include/mach/pm-rmobile.h b/arch/arm/mach-shmobile/include/mach/pm-rmobile.h
index 5a40284..690553a 100644
--- a/arch/arm/mach-shmobile/include/mach/pm-rmobile.h
+++ b/arch/arm/mach-shmobile/include/mach/pm-rmobile.h
@@ -12,6 +12,8 @@
 
 #include <linux/pm_domain.h>
 
+#define DEFAULT_DEV_LATENCY_NS	250000
+
 struct platform_device;
 
 struct rmobile_pm_domain {
@@ -29,16 +31,33 @@ struct rmobile_pm_domain *to_rmobile_pd(struct generic_pm_domain *d)
 	return container_of(d, struct rmobile_pm_domain, genpd);
 }
 
+struct pm_domain_device {
+	const char *domain_name;
+	struct platform_device *pdev;
+};
+
 #ifdef CONFIG_PM
-extern void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd);
-extern void rmobile_add_device_to_domain(struct rmobile_pm_domain *rmobile_pd,
-					struct platform_device *pdev);
-extern void rmobile_pm_add_subdomain(struct rmobile_pm_domain *rmobile_pd,
-				    struct rmobile_pm_domain *rmobile_sd);
+extern void rmobile_init_domains(struct rmobile_pm_domain domains[], int num);
+extern void rmobile_add_device_to_domain_td(const char *domain_name,
+					    struct platform_device *pdev,
+					    struct gpd_timing_data *td);
+
+static inline void rmobile_add_device_to_domain(const char *domain_name,
+						struct platform_device *pdev)
+{
+	rmobile_add_device_to_domain_td(domain_name, pdev, NULL);
+}
+
+extern void rmobile_add_devices_to_domains(struct pm_domain_device data[],
+					   int size);
 #else
-#define rmobile_init_pm_domain(pd) do { } while (0)
-#define rmobile_add_device_to_domain(pd, pdev) do { } while (0)
-#define rmobile_pm_add_subdomain(pd, sd) do { } while (0)
+
+#define rmobile_init_domains(domains, num) do { } while (0)
+#define rmobile_add_device_to_domain_td(name, pdev, td) do { } while (0)
+#define rmobile_add_device_to_domain(name, pdev) do { } while (0)
+
+static inline void rmobile_add_devices_to_domains(struct pm_domain_device d[],
+						  int size) {}
 #endif /* CONFIG_PM */
 
 #endif /* PM_RMOBILE_H */
diff --git a/arch/arm/mach-shmobile/include/mach/r8a7740.h b/arch/arm/mach-shmobile/include/mach/r8a7740.h
index 7143147..59d252f 100644
--- a/arch/arm/mach-shmobile/include/mach/r8a7740.h
+++ b/arch/arm/mach-shmobile/include/mach/r8a7740.h
@@ -607,9 +607,9 @@ enum {
 };
 
 #ifdef CONFIG_PM
-extern struct rmobile_pm_domain r8a7740_pd_a4s;
-extern struct rmobile_pm_domain r8a7740_pd_a3sp;
-extern struct rmobile_pm_domain r8a7740_pd_a4lc;
+extern void __init r8a7740_init_pm_domains(void);
+#else
+static inline void r8a7740_init_pm_domains(void) {}
 #endif /* CONFIG_PM */
 
 #endif /* __ASM_R8A7740_H__ */
diff --git a/arch/arm/mach-shmobile/include/mach/r8a7779.h b/arch/arm/mach-shmobile/include/mach/r8a7779.h
index b07ad31..7ad4797 100644
--- a/arch/arm/mach-shmobile/include/mach/r8a7779.h
+++ b/arch/arm/mach-shmobile/include/mach/r8a7779.h
@@ -347,17 +347,9 @@ extern int r8a7779_sysc_power_down(struct r8a7779_pm_ch *r8a7779_ch);
 extern int r8a7779_sysc_power_up(struct r8a7779_pm_ch *r8a7779_ch);
 
 #ifdef CONFIG_PM
-extern struct r8a7779_pm_domain r8a7779_sh4a;
-extern struct r8a7779_pm_domain r8a7779_sgx;
-extern struct r8a7779_pm_domain r8a7779_vdp1;
-extern struct r8a7779_pm_domain r8a7779_impx3;
-
-extern void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd);
-extern void r8a7779_add_device_to_domain(struct r8a7779_pm_domain *r8a7779_pd,
-					struct platform_device *pdev);
+extern void __init r8a7779_init_pm_domains(void);
 #else
-#define r8a7779_init_pm_domain(pd) do { } while (0)
-#define r8a7779_add_device_to_domain(pd, pdev) do { } while (0)
+static inline void r8a7779_init_pm_domains(void) {}
 #endif /* CONFIG_PM */
 
 #endif /* __ASM_R8A7779_H__ */
diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h
index b59048e..40beb79 100644
--- a/arch/arm/mach-shmobile/include/mach/sh7372.h
+++ b/arch/arm/mach-shmobile/include/mach/sh7372.h
@@ -478,21 +478,15 @@ extern struct clk sh7372_fsibck_clk;
 extern struct clk sh7372_fsidiva_clk;
 extern struct clk sh7372_fsidivb_clk;
 
-#ifdef CONFIG_PM
-extern struct rmobile_pm_domain sh7372_pd_a4lc;
-extern struct rmobile_pm_domain sh7372_pd_a4mp;
-extern struct rmobile_pm_domain sh7372_pd_d4;
-extern struct rmobile_pm_domain sh7372_pd_a4r;
-extern struct rmobile_pm_domain sh7372_pd_a3rv;
-extern struct rmobile_pm_domain sh7372_pd_a3ri;
-extern struct rmobile_pm_domain sh7372_pd_a4s;
-extern struct rmobile_pm_domain sh7372_pd_a3sp;
-extern struct rmobile_pm_domain sh7372_pd_a3sg;
-#endif /* CONFIG_PM */
-
 extern void sh7372_intcs_suspend(void);
 extern void sh7372_intcs_resume(void);
 extern void sh7372_intca_suspend(void);
 extern void sh7372_intca_resume(void);
 
+#ifdef CONFIG_PM
+extern void __init sh7372_init_pm_domains(void);
+#else
+static inline void sh7372_init_pm_domains(void) {}
+#endif
+
 #endif /* __ASM_SH7372_H__ */
diff --git a/arch/arm/mach-shmobile/pm-r8a7740.c b/arch/arm/mach-shmobile/pm-r8a7740.c
index 893504d..21e5316d 100644
--- a/arch/arm/mach-shmobile/pm-r8a7740.c
+++ b/arch/arm/mach-shmobile/pm-r8a7740.c
@@ -21,14 +21,6 @@ static int r8a7740_pd_a4s_suspend(void)
 	return -EBUSY;
 }
 
-struct rmobile_pm_domain r8a7740_pd_a4s = {
-	.genpd.name	= "A4S",
-	.bit_shift	= 10,
-	.gov		= &pm_domain_always_on_gov,
-	.no_debug	= true,
-	.suspend	= r8a7740_pd_a4s_suspend,
-};
-
 static int r8a7740_pd_a3sp_suspend(void)
 {
 	/*
@@ -38,17 +30,31 @@ static int r8a7740_pd_a3sp_suspend(void)
 	return console_suspend_enabled ? 0 : -EBUSY;
 }
 
-struct rmobile_pm_domain r8a7740_pd_a3sp = {
-	.genpd.name	= "A3SP",
-	.bit_shift	= 11,
-	.gov		= &pm_domain_always_on_gov,
-	.no_debug	= true,
-	.suspend	= r8a7740_pd_a3sp_suspend,
+static struct rmobile_pm_domain r8a7740_pm_domains[] = {
+	{
+		.genpd.name	= "A4S",
+		.bit_shift	= 10,
+		.gov		= &pm_domain_always_on_gov,
+		.no_debug	= true,
+		.suspend	= r8a7740_pd_a4s_suspend,
+	},
+	{
+		.genpd.name	= "A3SP",
+		.bit_shift	= 11,
+		.gov		= &pm_domain_always_on_gov,
+		.no_debug	= true,
+		.suspend	= r8a7740_pd_a3sp_suspend,
+	},
+	{
+		.genpd.name	= "A4LC",
+		.bit_shift	= 1,
+	},
 };
 
-struct rmobile_pm_domain r8a7740_pd_a4lc = {
-	.genpd.name	= "A4LC",
-	.bit_shift	= 1,
-};
+void __init r8a7740_init_pm_domains(void)
+{
+	rmobile_init_domains(r8a7740_pm_domains, ARRAY_SIZE(r8a7740_pm_domains));
+	pm_genpd_add_subdomain_names("A4S", "A3SP");
+}
 
 #endif /* CONFIG_PM */
diff --git a/arch/arm/mach-shmobile/pm-r8a7779.c b/arch/arm/mach-shmobile/pm-r8a7779.c
index a18a4ae..d50a8e9 100644
--- a/arch/arm/mach-shmobile/pm-r8a7779.c
+++ b/arch/arm/mach-shmobile/pm-r8a7779.c
@@ -183,7 +183,7 @@ static bool pd_active_wakeup(struct device *dev)
 	return true;
 }
 
-void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd)
+static void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd)
 {
 	struct generic_pm_domain *genpd = &r8a7779_pd->genpd;
 
@@ -199,43 +199,44 @@ void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd)
 		pd_power_up(&r8a7779_pd->genpd);
 }
 
-void r8a7779_add_device_to_domain(struct r8a7779_pm_domain *r8a7779_pd,
-				 struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-
-	pm_genpd_add_device(&r8a7779_pd->genpd, dev);
-	if (pm_clk_no_clocks(dev))
-		pm_clk_add(dev, NULL);
-}
-
-struct r8a7779_pm_domain r8a7779_sh4a = {
-	.ch = {
-		.chan_offs = 0x80, /* PWRSR1 .. PWRER1 */
-		.isr_bit = 16, /* SH4A */
-	}
-};
-
-struct r8a7779_pm_domain r8a7779_sgx = {
-	.ch = {
-		.chan_offs = 0xc0, /* PWRSR2 .. PWRER2 */
-		.isr_bit = 20, /* SGX */
-	}
+static struct r8a7779_pm_domain r8a7779_pm_domains[] = {
+	{
+		.genpd.name = "SH4A",
+		.ch = {
+			.chan_offs = 0x80, /* PWRSR1 .. PWRER1 */
+			.isr_bit = 16, /* SH4A */
+		},
+	},
+	{
+		.genpd.name = "SGX",
+		.ch = {
+			.chan_offs = 0xc0, /* PWRSR2 .. PWRER2 */
+			.isr_bit = 20, /* SGX */
+		},
+	},
+	{
+		.genpd.name = "VDP1",
+		.ch = {
+			.chan_offs = 0x100, /* PWRSR3 .. PWRER3 */
+			.isr_bit = 21, /* VDP */
+		},
+	},
+	{
+		.genpd.name = "IMPX3",
+		.ch = {
+			.chan_offs = 0x140, /* PWRSR4 .. PWRER4 */
+			.isr_bit = 24, /* IMP */
+		},
+	},
 };
 
-struct r8a7779_pm_domain r8a7779_vdp1 = {
-	.ch = {
-		.chan_offs = 0x100, /* PWRSR3 .. PWRER3 */
-		.isr_bit = 21, /* VDP */
-	}
-};
+void __init r8a7779_init_pm_domains(void)
+{
+	int j;
 
-struct r8a7779_pm_domain r8a7779_impx3 = {
-	.ch = {
-		.chan_offs = 0x140, /* PWRSR4 .. PWRER4 */
-		.isr_bit = 24, /* IMP */
-	}
-};
+	for (j = 0; j < ARRAY_SIZE(r8a7779_pm_domains); j++)
+		r8a7779_init_pm_domain(&r8a7779_pm_domains[j]);
+}
 
 #endif /* CONFIG_PM */
 
diff --git a/arch/arm/mach-shmobile/pm-rmobile.c b/arch/arm/mach-shmobile/pm-rmobile.c
index a856254..d37d368 100644
--- a/arch/arm/mach-shmobile/pm-rmobile.c
+++ b/arch/arm/mach-shmobile/pm-rmobile.c
@@ -134,7 +134,7 @@ static int rmobile_pd_start_dev(struct device *dev)
 	return ret;
 }
 
-void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
+static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
 {
 	struct generic_pm_domain *genpd = &rmobile_pd->genpd;
 	struct dev_power_governor *gov = rmobile_pd->gov;
@@ -149,19 +149,38 @@ void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
 	__rmobile_pd_power_up(rmobile_pd, false);
 }
 
-void rmobile_add_device_to_domain(struct rmobile_pm_domain *rmobile_pd,
-				 struct platform_device *pdev)
+void rmobile_init_domains(struct rmobile_pm_domain domains[], int num)
+{
+	int j;
+
+	for (j = 0; j < num; j++)
+		rmobile_init_pm_domain(&domains[j]);
+}
+
+void rmobile_add_device_to_domain_td(const char *domain_name,
+				     struct platform_device *pdev,
+				     struct gpd_timing_data *td)
 {
 	struct device *dev = &pdev->dev;
 
-	pm_genpd_add_device(&rmobile_pd->genpd, dev);
+	__pm_genpd_name_add_device(domain_name, dev, td);
 	if (pm_clk_no_clocks(dev))
 		pm_clk_add(dev, NULL);
 }
 
-void rmobile_pm_add_subdomain(struct rmobile_pm_domain *rmobile_pd,
-			     struct rmobile_pm_domain *rmobile_sd)
+void rmobile_add_devices_to_domains(struct pm_domain_device data[],
+				    int size)
 {
-	pm_genpd_add_subdomain(&rmobile_pd->genpd, &rmobile_sd->genpd);
+	struct gpd_timing_data latencies = {
+		.stop_latency_ns = DEFAULT_DEV_LATENCY_NS,
+		.start_latency_ns = DEFAULT_DEV_LATENCY_NS,
+		.save_state_latency_ns = DEFAULT_DEV_LATENCY_NS,
+		.restore_state_latency_ns = DEFAULT_DEV_LATENCY_NS,
+	};
+	int j;
+
+	for (j = 0; j < size; j++)
+		rmobile_add_device_to_domain_td(data[j].domain_name,
+						data[j].pdev, &latencies);
 }
 #endif /* CONFIG_PM */
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c
index 7920370..5cafd35 100644
--- a/arch/arm/mach-shmobile/pm-sh7372.c
+++ b/arch/arm/mach-shmobile/pm-sh7372.c
@@ -21,6 +21,7 @@
 #include <linux/irq.h>
 #include <linux/bitrev.h>
 #include <linux/console.h>
+#include <asm/cpuidle.h>
 #include <asm/io.h>
 #include <asm/tlbflush.h>
 #include <asm/suspend.h>
@@ -71,20 +72,7 @@
 
 #ifdef CONFIG_PM
 
-struct rmobile_pm_domain sh7372_pd_a4lc = {
-	.genpd.name = "A4LC",
-	.bit_shift = 1,
-};
-
-struct rmobile_pm_domain sh7372_pd_a4mp = {
-	.genpd.name = "A4MP",
-	.bit_shift = 2,
-};
-
-struct rmobile_pm_domain sh7372_pd_d4 = {
-	.genpd.name = "D4",
-	.bit_shift = 3,
-};
+#define PM_DOMAIN_ON_OFF_LATENCY_NS	250000
 
 static int sh7372_a4r_pd_suspend(void)
 {
@@ -93,39 +81,25 @@ static int sh7372_a4r_pd_suspend(void)
 	return 0;
 }
 
-struct rmobile_pm_domain sh7372_pd_a4r = {
-	.genpd.name = "A4R",
-	.bit_shift = 5,
-	.suspend = sh7372_a4r_pd_suspend,
-	.resume = sh7372_intcs_resume,
-};
-
-struct rmobile_pm_domain sh7372_pd_a3rv = {
-	.genpd.name = "A3RV",
-	.bit_shift = 6,
-};
-
-struct rmobile_pm_domain sh7372_pd_a3ri = {
-	.genpd.name = "A3RI",
-	.bit_shift = 8,
-};
+static bool a4s_suspend_ready;
 
-static int sh7372_pd_a4s_suspend(void)
+static int sh7372_a4s_pd_suspend(void)
 {
 	/*
 	 * The A4S domain contains the CPU core and therefore it should
-	 * only be turned off if the CPU is in use.
+	 * only be turned off if the CPU is not in use.  This may happen
+	 * during system suspend, when SYSC is going to be used for generating
+	 * resume signals and a4s_suspend_ready is set to let
+	 * sh7372_enter_suspend() know that it can turn A4S off.
 	 */
+	a4s_suspend_ready = true;
 	return -EBUSY;
 }
 
-struct rmobile_pm_domain sh7372_pd_a4s = {
-	.genpd.name = "A4S",
-	.bit_shift = 10,
-	.gov = &pm_domain_always_on_gov,
-	.no_debug = true,
-	.suspend = sh7372_pd_a4s_suspend,
-};
+static void sh7372_a4s_pd_resume(void)
+{
+	a4s_suspend_ready = false;
+}
 
 static int sh7372_a3sp_pd_suspend(void)
 {
@@ -136,18 +110,80 @@ static int sh7372_a3sp_pd_suspend(void)
 	return console_suspend_enabled ? 0 : -EBUSY;
 }
 
-struct rmobile_pm_domain sh7372_pd_a3sp = {
-	.genpd.name = "A3SP",
-	.bit_shift = 11,
-	.gov = &pm_domain_always_on_gov,
-	.no_debug = true,
-	.suspend = sh7372_a3sp_pd_suspend,
+static struct rmobile_pm_domain sh7372_pm_domains[] = {
+	{
+		.genpd.name = "A4LC",
+		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.bit_shift = 1,
+	},
+	{
+		.genpd.name = "A4MP",
+		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.bit_shift = 2,
+	},
+	{
+		.genpd.name = "D4",
+		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.bit_shift = 3,
+	},
+	{
+		.genpd.name = "A4R",
+		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.bit_shift = 5,
+		.suspend = sh7372_a4r_pd_suspend,
+		.resume = sh7372_intcs_resume,
+	},
+	{
+		.genpd.name = "A3RV",
+		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.bit_shift = 6,
+	},
+	{
+		.genpd.name = "A3RI",
+		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.bit_shift = 8,
+	},
+	{
+		.genpd.name = "A4S",
+		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.bit_shift = 10,
+		.gov = &pm_domain_always_on_gov,
+		.no_debug = true,
+		.suspend = sh7372_a4s_pd_suspend,
+		.resume = sh7372_a4s_pd_resume,
+	},
+	{
+		.genpd.name = "A3SP",
+		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.bit_shift = 11,
+		.gov = &pm_domain_always_on_gov,
+		.no_debug = true,
+		.suspend = sh7372_a3sp_pd_suspend,
+	},
+	{
+		.genpd.name = "A3SG",
+		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.bit_shift = 13,
+	},
 };
 
-struct rmobile_pm_domain sh7372_pd_a3sg = {
-	.genpd.name = "A3SG",
-	.bit_shift = 13,
-};
+void __init sh7372_init_pm_domains(void)
+{
+	rmobile_init_domains(sh7372_pm_domains, ARRAY_SIZE(sh7372_pm_domains));
+	pm_genpd_add_subdomain_names("A4LC", "A3RV");
+	pm_genpd_add_subdomain_names("A4R", "A4LC");
+	pm_genpd_add_subdomain_names("A4S", "A3SG");
+	pm_genpd_add_subdomain_names("A4S", "A3SP");
+}
 
 #endif /* CONFIG_PM */
 
@@ -312,7 +348,8 @@ static int sh7372_do_idle_core_standby(unsigned long unused)
 	return 0;
 }
 
-static void sh7372_enter_core_standby(void)
+static int sh7372_enter_core_standby(struct cpuidle_device *dev,
+				     struct cpuidle_driver *drv, int index)
 {
 	sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc));
 
@@ -323,52 +360,61 @@ static void sh7372_enter_core_standby(void)
 
 	 /* disable reset vector translation */
 	__raw_writel(0, SBAR);
+
+	return 1;
 }
 
-static void sh7372_enter_a3sm_pll_on(void)
+static int sh7372_enter_a3sm_pll_on(struct cpuidle_device *dev,
+				    struct cpuidle_driver *drv, int index)
 {
 	sh7372_enter_a3sm_common(1);
+	return 2;
 }
 
-static void sh7372_enter_a3sm_pll_off(void)
+static int sh7372_enter_a3sm_pll_off(struct cpuidle_device *dev,
+				     struct cpuidle_driver *drv, int index)
 {
 	sh7372_enter_a3sm_common(0);
+	return 3;
 }
 
-static void sh7372_cpuidle_setup(struct cpuidle_driver *drv)
-{
-	struct cpuidle_state *state = &drv->states[drv->state_count];
-
-	snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
-	strncpy(state->desc, "Core Standby Mode", CPUIDLE_DESC_LEN);
-	state->exit_latency = 10;
-	state->target_residency = 20 + 10;
-	state->flags = CPUIDLE_FLAG_TIME_VALID;
-	shmobile_cpuidle_modes[drv->state_count] = sh7372_enter_core_standby;
-	drv->state_count++;
-
-	state = &drv->states[drv->state_count];
-	snprintf(state->name, CPUIDLE_NAME_LEN, "C3");
-	strncpy(state->desc, "A3SM PLL ON", CPUIDLE_DESC_LEN);
-	state->exit_latency = 20;
-	state->target_residency = 30 + 20;
-	state->flags = CPUIDLE_FLAG_TIME_VALID;
-	shmobile_cpuidle_modes[drv->state_count] = sh7372_enter_a3sm_pll_on;
-	drv->state_count++;
-
-	state = &drv->states[drv->state_count];
-	snprintf(state->name, CPUIDLE_NAME_LEN, "C4");
-	strncpy(state->desc, "A3SM PLL OFF", CPUIDLE_DESC_LEN);
-	state->exit_latency = 120;
-	state->target_residency = 30 + 120;
-	state->flags = CPUIDLE_FLAG_TIME_VALID;
-	shmobile_cpuidle_modes[drv->state_count] = sh7372_enter_a3sm_pll_off;
-	drv->state_count++;
-}
+static struct cpuidle_driver sh7372_cpuidle_driver = {
+	.name			= "sh7372_cpuidle",
+	.owner			= THIS_MODULE,
+	.en_core_tk_irqen	= 1,
+	.state_count		= 4,
+	.safe_state_index	= 0, /* C1 */
+	.states[0] = ARM_CPUIDLE_WFI_STATE,
+	.states[0].enter = shmobile_enter_wfi,
+	.states[1] = {
+		.name = "C2",
+		.desc = "Core Standby Mode",
+		.exit_latency = 10,
+		.target_residency = 20 + 10,
+		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.enter = sh7372_enter_core_standby,
+	},
+	.states[2] = {
+		.name = "C3",
+		.desc = "A3SM PLL ON",
+		.exit_latency = 20,
+		.target_residency = 30 + 20,
+		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.enter = sh7372_enter_a3sm_pll_on,
+	},
+	.states[3] = {
+		.name = "C4",
+		.desc = "A3SM PLL OFF",
+		.exit_latency = 120,
+		.target_residency = 30 + 120,
+		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.enter = sh7372_enter_a3sm_pll_off,
+	},
+};
 
 static void sh7372_cpuidle_init(void)
 {
-	shmobile_cpuidle_setup = sh7372_cpuidle_setup;
+	shmobile_cpuidle_set_driver(&sh7372_cpuidle_driver);
 }
 #else
 static void sh7372_cpuidle_init(void) {}
@@ -389,17 +435,14 @@ static int sh7372_enter_suspend(suspend_state_t suspend_state)
 	unsigned long msk, msk2;
 
 	/* check active clocks to determine potential wakeup sources */
-	if (sh7372_sysc_valid(&msk, &msk2)) {
-		if (!console_suspend_enabled &&
-		    sh7372_pd_a4s.genpd.status == GPD_STATE_POWER_OFF) {
-			/* convert INTC mask/sense to SYSC mask/sense */
-			sh7372_setup_sysc(msk, msk2);
-
-			/* enter A4S sleep with PLLC0 off */
-			pr_debug("entering A4S\n");
-			sh7372_enter_a4s_common(0);
-			return 0;
-		}
+	if (sh7372_sysc_valid(&msk, &msk2) && a4s_suspend_ready) {
+		/* convert INTC mask/sense to SYSC mask/sense */
+		sh7372_setup_sysc(msk, msk2);
+
+		/* enter A4S sleep with PLLC0 off */
+		pr_debug("entering A4S\n");
+		sh7372_enter_a4s_common(0);
+		return 0;
 	}
 
 	/* default to enter A3SM sleep with PLLC0 off */
@@ -425,7 +468,7 @@ static int sh7372_pm_notifier_fn(struct notifier_block *notifier,
 		 * executed during system suspend and resume, respectively, so
 		 * that those functions don't crash while accessing the INTCS.
 		 */
-		pm_genpd_poweron(&sh7372_pd_a4r.genpd);
+		pm_genpd_name_poweron("A4R");
 		break;
 	case PM_POST_SUSPEND:
 		pm_genpd_poweroff_unused();
diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c
index 78948a9..11bb1d9 100644
--- a/arch/arm/mach-shmobile/setup-r8a7740.c
+++ b/arch/arm/mach-shmobile/setup-r8a7740.c
@@ -673,12 +673,7 @@ void __init r8a7740_add_standard_devices(void)
 	r8a7740_i2c_workaround(&i2c0_device);
 	r8a7740_i2c_workaround(&i2c1_device);
 
-	/* PM domain */
-	rmobile_init_pm_domain(&r8a7740_pd_a4s);
-	rmobile_init_pm_domain(&r8a7740_pd_a3sp);
-	rmobile_init_pm_domain(&r8a7740_pd_a4lc);
-
-	rmobile_pm_add_subdomain(&r8a7740_pd_a4s, &r8a7740_pd_a3sp);
+	r8a7740_init_pm_domains();
 
 	/* add devices */
 	platform_add_devices(r8a7740_early_devices,
@@ -688,16 +683,16 @@ void __init r8a7740_add_standard_devices(void)
 
 	/* add devices to PM domain  */
 
-	rmobile_add_device_to_domain(&r8a7740_pd_a3sp,	&scif0_device);
-	rmobile_add_device_to_domain(&r8a7740_pd_a3sp,	&scif1_device);
-	rmobile_add_device_to_domain(&r8a7740_pd_a3sp,	&scif2_device);
-	rmobile_add_device_to_domain(&r8a7740_pd_a3sp,	&scif3_device);
-	rmobile_add_device_to_domain(&r8a7740_pd_a3sp,	&scif4_device);
-	rmobile_add_device_to_domain(&r8a7740_pd_a3sp,	&scif5_device);
-	rmobile_add_device_to_domain(&r8a7740_pd_a3sp,	&scif6_device);
-	rmobile_add_device_to_domain(&r8a7740_pd_a3sp,	&scif7_device);
-	rmobile_add_device_to_domain(&r8a7740_pd_a3sp,	&scifb_device);
-	rmobile_add_device_to_domain(&r8a7740_pd_a3sp,	&i2c1_device);
+	rmobile_add_device_to_domain("A3SP",	&scif0_device);
+	rmobile_add_device_to_domain("A3SP",	&scif1_device);
+	rmobile_add_device_to_domain("A3SP",	&scif2_device);
+	rmobile_add_device_to_domain("A3SP",	&scif3_device);
+	rmobile_add_device_to_domain("A3SP",	&scif4_device);
+	rmobile_add_device_to_domain("A3SP",	&scif5_device);
+	rmobile_add_device_to_domain("A3SP",	&scif6_device);
+	rmobile_add_device_to_domain("A3SP",	&scif7_device);
+	rmobile_add_device_to_domain("A3SP",	&scifb_device);
+	rmobile_add_device_to_domain("A3SP",	&i2c1_device);
 }
 
 static void __init r8a7740_earlytimer_init(void)
diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c
index e98e46f..2917668 100644
--- a/arch/arm/mach-shmobile/setup-r8a7779.c
+++ b/arch/arm/mach-shmobile/setup-r8a7779.c
@@ -251,10 +251,7 @@ void __init r8a7779_add_standard_devices(void)
 #endif
 	r8a7779_pm_init();
 
-	r8a7779_init_pm_domain(&r8a7779_sh4a);
-	r8a7779_init_pm_domain(&r8a7779_sgx);
-	r8a7779_init_pm_domain(&r8a7779_vdp1);
-	r8a7779_init_pm_domain(&r8a7779_impx3);
+	r8a7779_init_pm_domains();
 
 	platform_add_devices(r8a7779_early_devices,
 			    ARRAY_SIZE(r8a7779_early_devices));
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c
index 838a87b..a07954f 100644
--- a/arch/arm/mach-shmobile/setup-sh7372.c
+++ b/arch/arm/mach-shmobile/setup-sh7372.c
@@ -1001,21 +1001,34 @@ static struct platform_device *sh7372_late_devices[] __initdata = {
 
 void __init sh7372_add_standard_devices(void)
 {
-	rmobile_init_pm_domain(&sh7372_pd_a4lc);
-	rmobile_init_pm_domain(&sh7372_pd_a4mp);
-	rmobile_init_pm_domain(&sh7372_pd_d4);
-	rmobile_init_pm_domain(&sh7372_pd_a4r);
-	rmobile_init_pm_domain(&sh7372_pd_a3rv);
-	rmobile_init_pm_domain(&sh7372_pd_a3ri);
-	rmobile_init_pm_domain(&sh7372_pd_a4s);
-	rmobile_init_pm_domain(&sh7372_pd_a3sp);
-	rmobile_init_pm_domain(&sh7372_pd_a3sg);
-
-	rmobile_pm_add_subdomain(&sh7372_pd_a4lc, &sh7372_pd_a3rv);
-	rmobile_pm_add_subdomain(&sh7372_pd_a4r, &sh7372_pd_a4lc);
-
-	rmobile_pm_add_subdomain(&sh7372_pd_a4s, &sh7372_pd_a3sg);
-	rmobile_pm_add_subdomain(&sh7372_pd_a4s, &sh7372_pd_a3sp);
+	struct pm_domain_device domain_devices[] = {
+		{ "A3RV", &vpu_device, },
+		{ "A4MP", &spu0_device, },
+		{ "A4MP", &spu1_device, },
+		{ "A3SP", &scif0_device, },
+		{ "A3SP", &scif1_device, },
+		{ "A3SP", &scif2_device, },
+		{ "A3SP", &scif3_device, },
+		{ "A3SP", &scif4_device, },
+		{ "A3SP", &scif5_device, },
+		{ "A3SP", &scif6_device, },
+		{ "A3SP", &iic1_device, },
+		{ "A3SP", &dma0_device, },
+		{ "A3SP", &dma1_device, },
+		{ "A3SP", &dma2_device, },
+		{ "A3SP", &usb_dma0_device, },
+		{ "A3SP", &usb_dma1_device, },
+		{ "A4R", &iic0_device, },
+		{ "A4R", &veu0_device, },
+		{ "A4R", &veu1_device, },
+		{ "A4R", &veu2_device, },
+		{ "A4R", &veu3_device, },
+		{ "A4R", &jpu_device, },
+		{ "A4R", &tmu00_device, },
+		{ "A4R", &tmu01_device, },
+	};
+
+	sh7372_init_pm_domains();
 
 	platform_add_devices(sh7372_early_devices,
 			    ARRAY_SIZE(sh7372_early_devices));
@@ -1023,30 +1036,8 @@ void __init sh7372_add_standard_devices(void)
 	platform_add_devices(sh7372_late_devices,
 			    ARRAY_SIZE(sh7372_late_devices));
 
-	rmobile_add_device_to_domain(&sh7372_pd_a3rv, &vpu_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a4mp, &spu0_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a4mp, &spu1_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif0_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif1_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif2_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif3_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif4_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif5_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif6_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &iic1_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &dma0_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &dma1_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &dma2_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &usb_dma0_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a3sp, &usb_dma1_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a4r, &iic0_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a4r, &veu0_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a4r, &veu1_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a4r, &veu2_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a4r, &veu3_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a4r, &jpu_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a4r, &tmu00_device);
-	rmobile_add_device_to_domain(&sh7372_pd_a4r, &tmu01_device);
+	rmobile_add_devices_to_domains(domain_devices,
+				       ARRAY_SIZE(domain_devices));
 }
 
 static void __init sh7372_earlytimer_init(void)
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 9077aaa..f6e79ed 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -66,19 +66,6 @@ config MACH_HARMONY
        help
          Support for nVidia Harmony development platform
 
-config MACH_PAZ00
-       bool "Paz00 board"
-       depends on ARCH_TEGRA_2x_SOC
-       help
-         Support for the Toshiba AC100/Dynabook AZ netbook
-
-config MACH_TRIMSLICE
-       bool "TrimSlice board"
-       depends on ARCH_TEGRA_2x_SOC
-       select TEGRA_PCI
-       help
-         Support for CompuLab TrimSlice platform
-
 choice
         prompt "Default low-level debug console UART"
         default TEGRA_DEBUG_UART_NONE
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index c3d7303..959a429 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -12,9 +12,13 @@ obj-y					+= powergate.o
 obj-y					+= apbio.o
 obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
 obj-$(CONFIG_CPU_IDLE)			+= sleep.o
-obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra2_clocks.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra20_clocks.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra20_clocks_data.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= tegra2_emc.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= sleep-t20.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_clocks.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_clocks_data.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= sleep-t30.o
 obj-$(CONFIG_SMP)			+= platsmp.o headsmp.o
 obj-$(CONFIG_SMP)                       += reset.o
 obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
@@ -31,8 +35,4 @@ obj-$(CONFIG_MACH_HARMONY)              += board-harmony-pinmux.o
 obj-$(CONFIG_MACH_HARMONY)              += board-harmony-pcie.o
 obj-$(CONFIG_MACH_HARMONY)              += board-harmony-power.o
 
-obj-$(CONFIG_MACH_PAZ00)		+= board-paz00.o
-obj-$(CONFIG_MACH_PAZ00)		+= board-paz00-pinmux.o
-
-obj-$(CONFIG_MACH_TRIMSLICE)            += board-trimslice.o
-obj-$(CONFIG_MACH_TRIMSLICE)            += board-trimslice-pinmux.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= board-paz00.o
diff --git a/arch/arm/mach-tegra/Makefile.boot b/arch/arm/mach-tegra/Makefile.boot
index 7a1bb62..6e35207 100644
--- a/arch/arm/mach-tegra/Makefile.boot
+++ b/arch/arm/mach-tegra/Makefile.boot
@@ -8,4 +8,5 @@ dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20-seaboard.dtb
 dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20-trimslice.dtb
 dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20-ventana.dtb
 dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20-whistler.dtb
-dtb-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30-cardhu.dtb
+dtb-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30-cardhu-a02.dtb
+dtb-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30-cardhu-a04.dtb
diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c
index dc0fe38..643a378 100644
--- a/arch/arm/mach-tegra/apbio.c
+++ b/arch/arm/mach-tegra/apbio.c
@@ -293,12 +293,12 @@ static apbio_write_fptr apbio_write;
 
 static u32 tegra_apb_readl_direct(unsigned long offset)
 {
-	return readl(IO_TO_VIRT(offset));
+	return readl(IO_ADDRESS(offset));
 }
 
 static void tegra_apb_writel_direct(u32 value, unsigned long offset)
 {
-	writel(value, IO_TO_VIRT(offset));
+	writel(value, IO_ADDRESS(offset));
 }
 
 void tegra_apb_io_init(void)
diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c
index c099963..1d6c9df 100644
--- a/arch/arm/mach-tegra/board-dt-tegra20.c
+++ b/arch/arm/mach-tegra/board-dt-tegra20.c
@@ -71,6 +71,7 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
 
 static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
 	/* name		parent		rate		enabled */
+	{ "uarta",	"pll_p",	216000000,	true },
 	{ "uartd",	"pll_p",	216000000,	true },
 	{ "usbd",	"clk_m",	12000000,	false },
 	{ "usb2",	"clk_m",	12000000,	false },
@@ -95,16 +96,16 @@ static void __init tegra_dt_init(void)
 				tegra20_auxdata_lookup, NULL);
 }
 
-#ifdef CONFIG_MACH_TRIMSLICE
 static void __init trimslice_init(void)
 {
+#ifdef CONFIG_TEGRA_PCI
 	int ret;
 
 	ret = tegra_pcie_init(true, true);
 	if (ret)
 		pr_err("tegra_pci_init() failed: %d\n", ret);
-}
 #endif
+}
 
 #ifdef CONFIG_MACH_HARMONY
 static void __init harmony_init(void)
@@ -123,26 +124,20 @@ static void __init harmony_init(void)
 }
 #endif
 
-#ifdef CONFIG_MACH_PAZ00
 static void __init paz00_init(void)
 {
 	tegra_paz00_wifikill_init();
 }
-#endif
 
 static struct {
 	char *machine;
 	void (*init)(void);
 } board_init_funcs[] = {
-#ifdef CONFIG_MACH_TRIMSLICE
 	{ "compulab,trimslice", trimslice_init },
-#endif
 #ifdef CONFIG_MACH_HARMONY
 	{ "nvidia,harmony", harmony_init },
 #endif
-#ifdef CONFIG_MACH_PAZ00
 	{ "compal,paz00", paz00_init },
-#endif
 };
 
 static void __init tegra_dt_init_late(void)
diff --git a/arch/arm/mach-tegra/board-paz00-pinmux.c b/arch/arm/mach-tegra/board-paz00-pinmux.c
deleted file mode 100644
index 6f1111b..0000000
--- a/arch/arm/mach-tegra/board-paz00-pinmux.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * arch/arm/mach-tegra/board-paz00-pinmux.c
- *
- * Copyright (C) 2010 Marc Dietrich <marvin24@gmx.de>
- * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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 "board-paz00.h"
-#include "board-pinmux.h"
-
-static struct pinctrl_map paz00_map[] = {
-	TEGRA_MAP_MUXCONF("ata",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("atb",   "sdio4",         none, driven),
-	TEGRA_MAP_MUXCONF("atc",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("atd",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("ate",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("cdev1", "plla_out",      none, driven),
-	TEGRA_MAP_MUXCONF("cdev2", "pllp_out4",     down, driven),
-	TEGRA_MAP_MUXCONF("crtp",  "crt",           none, tristate),
-	TEGRA_MAP_MUXCONF("csus",  "pllc_out1",     down, tristate),
-	TEGRA_MAP_MUXCONF("dap1",  "dap1",          none, driven),
-	TEGRA_MAP_MUXCONF("dap2",  "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("dap3",  "dap3",          none, tristate),
-	TEGRA_MAP_MUXCONF("dap4",  "dap4",          none, tristate),
-	TEGRA_MAP_MUXCONF("ddc",   "i2c2",          up,   driven),
-	TEGRA_MAP_MUXCONF("dta",   "rsvd1",         up,   tristate),
-	TEGRA_MAP_MUXCONF("dtb",   "rsvd1",         none, tristate),
-	TEGRA_MAP_MUXCONF("dtc",   "rsvd1",         none, tristate),
-	TEGRA_MAP_MUXCONF("dtd",   "rsvd1",         up,   tristate),
-	TEGRA_MAP_MUXCONF("dte",   "rsvd1",         none, tristate),
-	TEGRA_MAP_MUXCONF("dtf",   "i2c3",          none, driven),
-	TEGRA_MAP_MUXCONF("gma",   "sdio4",         none, driven),
-	TEGRA_MAP_MUXCONF("gmb",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("gmc",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("gmd",   "gmi",           none, driven),
-	TEGRA_MAP_MUXCONF("gme",   "sdio4",         none, driven),
-	TEGRA_MAP_MUXCONF("gpu",   "pwm",           none, driven),
-	TEGRA_MAP_MUXCONF("gpu7",  "rtck",          none, driven),
-	TEGRA_MAP_MUXCONF("gpv",   "pcie",          none, driven),
-	TEGRA_MAP_MUXCONF("hdint", "hdmi",          na,   driven),
-	TEGRA_MAP_MUXCONF("i2cp",  "i2cp",          none, driven),
-	TEGRA_MAP_MUXCONF("irrx",  "uarta",         up,   driven),
-	TEGRA_MAP_MUXCONF("irtx",  "uarta",         up,   driven),
-	TEGRA_MAP_MUXCONF("kbca",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("kbcb",  "sdio2",         up,   driven),
-	TEGRA_MAP_MUXCONF("kbcc",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("kbcd",  "sdio2",         up,   driven),
-	TEGRA_MAP_MUXCONF("kbce",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("kbcf",  "kbc",           up,   driven),
-	TEGRA_MAP_MUXCONF("lcsn",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("ld0",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld1",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld10",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld11",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld12",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld13",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld14",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld15",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld16",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld17",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld2",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld3",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld4",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld5",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld6",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld7",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld8",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld9",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ldc",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ldi",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhp0",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lhp1",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lhp2",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lhs",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lm0",   "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lm1",   "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lpp",   "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lpw0",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lpw1",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lpw2",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsc0",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lsc1",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsck",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsda",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsdi",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lspi",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lvp0",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lvp1",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lvs",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("owc",   "owr",           up,   tristate),
-	TEGRA_MAP_MUXCONF("pmc",   "pwr_on",        na,   driven),
-	TEGRA_MAP_MUXCONF("pta",   "hdmi",          none, driven),
-	TEGRA_MAP_MUXCONF("rm",    "i2c1",          none, driven),
-	TEGRA_MAP_MUXCONF("sdb",   "pwm",           na,   tristate),
-	TEGRA_MAP_MUXCONF("sdc",   "twc",           up,   tristate),
-	TEGRA_MAP_MUXCONF("sdd",   "pwm",           up,   tristate),
-	TEGRA_MAP_MUXCONF("sdio1", "sdio1",         none, driven),
-	TEGRA_MAP_MUXCONF("slxa",  "pcie",          none, tristate),
-	TEGRA_MAP_MUXCONF("slxc",  "spi4",          none, tristate),
-	TEGRA_MAP_MUXCONF("slxd",  "spi4",          none, tristate),
-	TEGRA_MAP_MUXCONF("slxk",  "pcie",          none, driven),
-	TEGRA_MAP_MUXCONF("spdi",  "rsvd2",         none, tristate),
-	TEGRA_MAP_MUXCONF("spdo",  "rsvd2",         none, driven),
-	TEGRA_MAP_MUXCONF("spia",  "gmi",           down, tristate),
-	TEGRA_MAP_MUXCONF("spib",  "gmi",           down, tristate),
-	TEGRA_MAP_MUXCONF("spic",  "gmi",           up,   driven),
-	TEGRA_MAP_MUXCONF("spid",  "gmi",           down, tristate),
-	TEGRA_MAP_MUXCONF("spie",  "gmi",           up,   tristate),
-	TEGRA_MAP_MUXCONF("spif",  "rsvd4",         down, tristate),
-	TEGRA_MAP_MUXCONF("spig",  "spi2_alt",      up,   driven),
-	TEGRA_MAP_MUXCONF("spih",  "spi2_alt",      up,   tristate),
-	TEGRA_MAP_MUXCONF("uaa",   "ulpi",          up,   driven),
-	TEGRA_MAP_MUXCONF("uab",   "ulpi",          up,   driven),
-	TEGRA_MAP_MUXCONF("uac",   "rsvd4",         none, driven),
-	TEGRA_MAP_MUXCONF("uad",   "spdif",         up,   tristate),
-	TEGRA_MAP_MUXCONF("uca",   "uartc",         up,   tristate),
-	TEGRA_MAP_MUXCONF("ucb",   "uartc",         up,   tristate),
-	TEGRA_MAP_MUXCONF("uda",   "ulpi",          none, driven),
-	TEGRA_MAP_CONF("ck32",    none, na),
-	TEGRA_MAP_CONF("ddrc",    none, na),
-	TEGRA_MAP_CONF("pmca",    none, na),
-	TEGRA_MAP_CONF("pmcb",    none, na),
-	TEGRA_MAP_CONF("pmcc",    none, na),
-	TEGRA_MAP_CONF("pmcd",    none, na),
-	TEGRA_MAP_CONF("pmce",    none, na),
-	TEGRA_MAP_CONF("xm2c",    none, na),
-	TEGRA_MAP_CONF("xm2d",    none, na),
-	TEGRA_MAP_CONF("ls",      up,   na),
-	TEGRA_MAP_CONF("lc",      up,   na),
-	TEGRA_MAP_CONF("ld17_0",  down, na),
-	TEGRA_MAP_CONF("ld19_18", down, na),
-	TEGRA_MAP_CONF("ld21_20", down, na),
-	TEGRA_MAP_CONF("ld23_22", down, na),
-};
-
-static struct tegra_board_pinmux_conf conf = {
-	.maps = paz00_map,
-	.map_count = ARRAY_SIZE(paz00_map),
-};
-
-void paz00_pinmux_init(void)
-{
-	tegra_board_pinmux_init(&conf, NULL);
-}
diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c
index 4b64af5..5930551 100644
--- a/arch/arm/mach-tegra/board-paz00.c
+++ b/arch/arm/mach-tegra/board-paz00.c
@@ -17,72 +17,10 @@
  *
  */
 
-#include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/serial_8250.h>
-#include <linux/of_serial.h>
-#include <linux/clk.h>
-#include <linux/dma-mapping.h>
-#include <linux/gpio_keys.h>
-#include <linux/pda_power.h>
-#include <linux/io.h>
-#include <linux/input.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
 #include <linux/rfkill-gpio.h>
 
-#include <asm/hardware/gic.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-#include <asm/setup.h>
-
-#include <mach/iomap.h>
-#include <mach/irqs.h>
-#include <mach/sdhci.h>
-
-#include "board.h"
 #include "board-paz00.h"
-#include "clock.h"
-#include "devices.h"
-#include "gpio-names.h"
-
-static struct plat_serial8250_port debug_uart_platform_data[] = {
-	{
-		/* serial port on JP1 */
-		.membase	= IO_ADDRESS(TEGRA_UARTA_BASE),
-		.mapbase	= TEGRA_UARTA_BASE,
-		.irq		= INT_UARTA,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
-		.type		= PORT_TEGRA,
-		.handle_break	= tegra_serial_handle_break,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= 216000000,
-	}, {
-		/* serial port on mini-pcie */
-		.membase	= IO_ADDRESS(TEGRA_UARTC_BASE),
-		.mapbase	= TEGRA_UARTC_BASE,
-		.irq		= INT_UARTC,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
-		.type		= PORT_TEGRA,
-		.handle_break	= tegra_serial_handle_break,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= 216000000,
-	}, {
-		.flags		= 0
-	}
-};
-
-static struct platform_device debug_uart = {
-	.name = "serial8250",
-	.id = PLAT8250_DEV_PLATFORM,
-	.dev = {
-		.platform_data = debug_uart_platform_data,
-	},
-};
 
 static struct rfkill_gpio_platform_data wifi_rfkill_platform_data = {
 	.name		= "wifi_rfkill",
@@ -99,137 +37,7 @@ static struct platform_device wifi_rfkill_device = {
 	},
 };
 
-static struct gpio_led gpio_leds[] = {
-	{
-		.name			= "wifi-led",
-		.default_trigger	= "rfkill0",
-		.gpio			= TEGRA_WIFI_LED,
-	},
-};
-
-static struct gpio_led_platform_data gpio_led_info = {
-	.leds		= gpio_leds,
-	.num_leds	= ARRAY_SIZE(gpio_leds),
-};
-
-static struct platform_device leds_gpio = {
-	.name	= "leds-gpio",
-	.id	= -1,
-	.dev	= {
-		.platform_data = &gpio_led_info,
-        },
-};
-
-static struct gpio_keys_button paz00_gpio_keys_buttons[] = {
-	{
-		.code		= KEY_POWER,
-		.gpio		= TEGRA_GPIO_POWERKEY,
-		.active_low	= 1,
-		.desc		= "Power",
-		.type		= EV_KEY,
-		.wakeup		= 1,
-	},
-};
-
-static struct gpio_keys_platform_data paz00_gpio_keys = {
-	.buttons	= paz00_gpio_keys_buttons,
-	.nbuttons	= ARRAY_SIZE(paz00_gpio_keys_buttons),
-};
-
-static struct platform_device gpio_keys_device = {
-	.name	= "gpio-keys",
-	.id	= -1,
-	.dev	= {
-		.platform_data = &paz00_gpio_keys,
-	},
-};
-
-static struct platform_device *paz00_devices[] __initdata = {
-	&debug_uart,
-	&tegra_sdhci_device4,
-	&tegra_sdhci_device1,
-	&leds_gpio,
-	&gpio_keys_device,
-};
-
-static void paz00_i2c_init(void)
-{
-	platform_device_register(&tegra_i2c_device1);
-	platform_device_register(&tegra_i2c_device2);
-	platform_device_register(&tegra_i2c_device4);
-}
-
-static void paz00_usb_init(void)
-{
-	tegra_ehci2_ulpi_phy_config.reset_gpio = TEGRA_ULPI_RST;
-
-	platform_device_register(&tegra_ehci2_device);
-	platform_device_register(&tegra_ehci3_device);
-}
-
-static void __init tegra_paz00_fixup(struct tag *tags, char **cmdline,
-	struct meminfo *mi)
-{
-	mi->nr_banks = 1;
-	mi->bank[0].start = PHYS_OFFSET;
-	mi->bank[0].size = 448 * SZ_1M;
-}
-
-static __initdata struct tegra_clk_init_table paz00_clk_init_table[] = {
-	/* name		parent		rate		enabled */
-	{ "uarta",	"pll_p",	216000000,	true },
-	{ "uartc",	"pll_p",	216000000,	true },
-
-	{ "usbd",	"clk_m",	12000000,	false },
-	{ "usb2",	"clk_m",	12000000,	false },
-	{ "usb3",	"clk_m",	12000000,	false },
-
-	{ NULL,		NULL,		0,		0},
-};
-
-static struct tegra_sdhci_platform_data sdhci_pdata1 = {
-	.cd_gpio	= TEGRA_GPIO_SD1_CD,
-	.wp_gpio	= TEGRA_GPIO_SD1_WP,
-	.power_gpio	= TEGRA_GPIO_SD1_POWER,
-};
-
-static struct tegra_sdhci_platform_data sdhci_pdata4 = {
-	.cd_gpio	= -1,
-	.wp_gpio	= -1,
-	.power_gpio	= -1,
-	.is_8bit	= 1,
-};
-
 void __init tegra_paz00_wifikill_init(void)
 {
 	platform_device_register(&wifi_rfkill_device);
 }
-
-static void __init tegra_paz00_init(void)
-{
-	tegra_clk_init_from_table(paz00_clk_init_table);
-
-	paz00_pinmux_init();
-
-	tegra_sdhci_device1.dev.platform_data = &sdhci_pdata1;
-	tegra_sdhci_device4.dev.platform_data = &sdhci_pdata4;
-
-	platform_add_devices(paz00_devices, ARRAY_SIZE(paz00_devices));
-	tegra_paz00_wifikill_init();
-
-	paz00_i2c_init();
-	paz00_usb_init();
-}
-
-MACHINE_START(PAZ00, "Toshiba AC100 / Dynabook AZ")
-	.atag_offset	= 0x100,
-	.fixup		= tegra_paz00_fixup,
-	.map_io         = tegra_map_common_io,
-	.init_early	= tegra20_init_early,
-	.init_irq       = tegra_init_irq,
-	.handle_irq	= gic_handle_irq,
-	.timer          = &tegra_timer,
-	.init_machine   = tegra_paz00_init,
-	.init_late	= tegra_init_late,
-	.restart	= tegra_assert_system_reset,
-MACHINE_END
diff --git a/arch/arm/mach-tegra/board-paz00.h b/arch/arm/mach-tegra/board-paz00.h
index 3c9f8da..25c08ec 100644
--- a/arch/arm/mach-tegra/board-paz00.h
+++ b/arch/arm/mach-tegra/board-paz00.h
@@ -17,24 +17,9 @@
 #ifndef _MACH_TEGRA_BOARD_PAZ00_H
 #define _MACH_TEGRA_BOARD_PAZ00_H
 
-#include <mach/gpio-tegra.h>
+#include "gpio-names.h"
 
-/* SDCARD */
-#define TEGRA_GPIO_SD1_CD		TEGRA_GPIO_PV5
-#define TEGRA_GPIO_SD1_WP		TEGRA_GPIO_PH1
-#define TEGRA_GPIO_SD1_POWER		TEGRA_GPIO_PV1
-
-/* ULPI */
-#define TEGRA_ULPI_RST			TEGRA_GPIO_PV0
-
-/* WIFI */
 #define TEGRA_WIFI_PWRN			TEGRA_GPIO_PK5
 #define TEGRA_WIFI_RST			TEGRA_GPIO_PD1
-#define TEGRA_WIFI_LED			TEGRA_GPIO_PD0
-
-/* WakeUp */
-#define TEGRA_GPIO_POWERKEY	TEGRA_GPIO_PJ7
-
-void paz00_pinmux_init(void);
 
 #endif
diff --git a/arch/arm/mach-tegra/board-trimslice-pinmux.c b/arch/arm/mach-tegra/board-trimslice-pinmux.c
deleted file mode 100644
index 7b39511..0000000
--- a/arch/arm/mach-tegra/board-trimslice-pinmux.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * arch/arm/mach-tegra/board-trimslice-pinmux.c
- *
- * Copyright (C) 2011 CompuLab, Ltd.
- * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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 "board-trimslice.h"
-#include "board-pinmux.h"
-
-static struct pinctrl_map trimslice_map[] = {
-	TEGRA_MAP_MUXCONF("ata",   "ide",           none, tristate),
-	TEGRA_MAP_MUXCONF("atb",   "sdio4",         none, driven),
-	TEGRA_MAP_MUXCONF("atc",   "nand",          none, tristate),
-	TEGRA_MAP_MUXCONF("atd",   "gmi",           none, tristate),
-	TEGRA_MAP_MUXCONF("ate",   "gmi",           none, tristate),
-	TEGRA_MAP_MUXCONF("cdev1", "plla_out",      none, driven),
-	TEGRA_MAP_MUXCONF("cdev2", "pllp_out4",     down, tristate),
-	TEGRA_MAP_MUXCONF("crtp",  "crt",           none, tristate),
-	TEGRA_MAP_MUXCONF("csus",  "vi_sensor_clk", down, tristate),
-	TEGRA_MAP_MUXCONF("dap1",  "dap1",          none, driven),
-	TEGRA_MAP_MUXCONF("dap2",  "dap2",          none, tristate),
-	TEGRA_MAP_MUXCONF("dap3",  "dap3",          none, tristate),
-	TEGRA_MAP_MUXCONF("dap4",  "dap4",          none, tristate),
-	TEGRA_MAP_MUXCONF("ddc",   "i2c2",          up,   driven),
-	TEGRA_MAP_MUXCONF("dta",   "vi",            none, tristate),
-	TEGRA_MAP_MUXCONF("dtb",   "vi",            none, tristate),
-	TEGRA_MAP_MUXCONF("dtc",   "vi",            none, tristate),
-	TEGRA_MAP_MUXCONF("dtd",   "vi",            none, tristate),
-	TEGRA_MAP_MUXCONF("dte",   "vi",            none, tristate),
-	TEGRA_MAP_MUXCONF("dtf",   "i2c3",          up,   driven),
-	TEGRA_MAP_MUXCONF("gma",   "sdio4",         none, driven),
-	TEGRA_MAP_MUXCONF("gmb",   "nand",          none, tristate),
-	TEGRA_MAP_MUXCONF("gmc",   "sflash",        none, driven),
-	TEGRA_MAP_MUXCONF("gmd",   "sflash",        none, driven),
-	TEGRA_MAP_MUXCONF("gme",   "gmi",           none, tristate),
-	TEGRA_MAP_MUXCONF("gpu",   "uarta",         none, driven),
-	TEGRA_MAP_MUXCONF("gpu7",  "rtck",          none, driven),
-	TEGRA_MAP_MUXCONF("gpv",   "pcie",          none, driven),
-	TEGRA_MAP_MUXCONF("hdint", "hdmi",          na,   tristate),
-	TEGRA_MAP_MUXCONF("i2cp",  "i2cp",          none, tristate),
-	TEGRA_MAP_MUXCONF("irrx",  "uartb",         up,   tristate),
-	TEGRA_MAP_MUXCONF("irtx",  "uartb",         up,   tristate),
-	TEGRA_MAP_MUXCONF("kbca",  "kbc",           up,   tristate),
-	TEGRA_MAP_MUXCONF("kbcb",  "kbc",           up,   tristate),
-	TEGRA_MAP_MUXCONF("kbcc",  "kbc",           up,   tristate),
-	TEGRA_MAP_MUXCONF("kbcd",  "kbc",           up,   tristate),
-	TEGRA_MAP_MUXCONF("kbce",  "kbc",           up,   tristate),
-	TEGRA_MAP_MUXCONF("kbcf",  "kbc",           up,   tristate),
-	TEGRA_MAP_MUXCONF("lcsn",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("ld0",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld1",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld10",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld11",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld12",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld13",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld14",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld15",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld16",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld17",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld2",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld3",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld4",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld5",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld6",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld7",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld8",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ld9",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("ldc",   "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("ldi",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhp0",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhp1",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhp2",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lhs",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lm0",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lm1",   "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lpp",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lpw0",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lpw1",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lpw2",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lsc0",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lsc1",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsck",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsda",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lsdi",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lspi",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lvp0",  "displaya",      na,   tristate),
-	TEGRA_MAP_MUXCONF("lvp1",  "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("lvs",   "displaya",      na,   driven),
-	TEGRA_MAP_MUXCONF("owc",   "rsvd2",         up,   tristate),
-	TEGRA_MAP_MUXCONF("pmc",   "pwr_on",        na,   tristate),
-	TEGRA_MAP_MUXCONF("pta",   "gmi",           none, tristate),
-	TEGRA_MAP_MUXCONF("rm",    "i2c1",          up,   driven),
-	TEGRA_MAP_MUXCONF("sdb",   "pwm",           na,   driven),
-	TEGRA_MAP_MUXCONF("sdc",   "pwm",           up,   driven),
-	TEGRA_MAP_MUXCONF("sdd",   "pwm",           up,   driven),
-	TEGRA_MAP_MUXCONF("sdio1", "sdio1",         none, driven),
-	TEGRA_MAP_MUXCONF("slxa",  "pcie",          none, driven),
-	TEGRA_MAP_MUXCONF("slxc",  "sdio3",         none, tristate),
-	TEGRA_MAP_MUXCONF("slxd",  "sdio3",         none, tristate),
-	TEGRA_MAP_MUXCONF("slxk",  "pcie",          none, driven),
-	TEGRA_MAP_MUXCONF("spdi",  "spdif",         none, tristate),
-	TEGRA_MAP_MUXCONF("spdo",  "spdif",         none, tristate),
-	TEGRA_MAP_MUXCONF("spia",  "spi2",          down, tristate),
-	TEGRA_MAP_MUXCONF("spib",  "spi2",          down, tristate),
-	TEGRA_MAP_MUXCONF("spic",  "spi2",          up,   tristate),
-	TEGRA_MAP_MUXCONF("spid",  "spi1",          down, tristate),
-	TEGRA_MAP_MUXCONF("spie",  "spi1",          up,   tristate),
-	TEGRA_MAP_MUXCONF("spif",  "spi1",          down, tristate),
-	TEGRA_MAP_MUXCONF("spig",  "spi2_alt",      up,   tristate),
-	TEGRA_MAP_MUXCONF("spih",  "spi2_alt",      up,   tristate),
-	TEGRA_MAP_MUXCONF("uaa",   "ulpi",          up,   tristate),
-	TEGRA_MAP_MUXCONF("uab",   "ulpi",          up,   tristate),
-	TEGRA_MAP_MUXCONF("uac",   "rsvd2",         none, driven),
-	TEGRA_MAP_MUXCONF("uad",   "irda",          up,   tristate),
-	TEGRA_MAP_MUXCONF("uca",   "uartc",         up,   tristate),
-	TEGRA_MAP_MUXCONF("ucb",   "uartc",         up,   tristate),
-	TEGRA_MAP_MUXCONF("uda",   "ulpi",          none, tristate),
-	TEGRA_MAP_CONF("ck32",    none, na),
-	TEGRA_MAP_CONF("ddrc",    none, na),
-	TEGRA_MAP_CONF("pmca",    none, na),
-	TEGRA_MAP_CONF("pmcb",    none, na),
-	TEGRA_MAP_CONF("pmcc",    none, na),
-	TEGRA_MAP_CONF("pmcd",    none, na),
-	TEGRA_MAP_CONF("pmce",    none, na),
-	TEGRA_MAP_CONF("xm2c",    none, na),
-	TEGRA_MAP_CONF("xm2d",    none, na),
-	TEGRA_MAP_CONF("ls",      up,   na),
-	TEGRA_MAP_CONF("lc",      up,   na),
-	TEGRA_MAP_CONF("ld17_0",  down, na),
-	TEGRA_MAP_CONF("ld19_18", down, na),
-	TEGRA_MAP_CONF("ld21_20", down, na),
-	TEGRA_MAP_CONF("ld23_22", down, na),
-};
-
-static struct tegra_board_pinmux_conf conf = {
-	.maps = trimslice_map,
-	.map_count = ARRAY_SIZE(trimslice_map),
-};
-
-void trimslice_pinmux_init(void)
-{
-	tegra_board_pinmux_init(&conf, NULL);
-}
diff --git a/arch/arm/mach-tegra/board-trimslice.c b/arch/arm/mach-tegra/board-trimslice.c
deleted file mode 100644
index 776aa95..0000000
--- a/arch/arm/mach-tegra/board-trimslice.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * arch/arm/mach-tegra/board-trimslice.c
- *
- * Copyright (C) 2011 CompuLab, Ltd.
- * Author: Mike Rapoport <mike@compulab.co.il>
- *
- * Based on board-harmony.c
- * Copyright (C) 2010 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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/init.h>
-#include <linux/platform_device.h>
-#include <linux/serial_8250.h>
-#include <linux/of_serial.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/platform_data/tegra_usb.h>
-
-#include <asm/hardware/gic.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/setup.h>
-
-#include <mach/iomap.h>
-#include <mach/sdhci.h>
-
-#include "board.h"
-#include "clock.h"
-#include "devices.h"
-#include "gpio-names.h"
-
-#include "board-trimslice.h"
-
-static struct plat_serial8250_port debug_uart_platform_data[] = {
-	{
-		.membase	= IO_ADDRESS(TEGRA_UARTA_BASE),
-		.mapbase	= TEGRA_UARTA_BASE,
-		.irq		= INT_UARTA,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
-		.type		= PORT_TEGRA,
-		.handle_break	= tegra_serial_handle_break,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= 216000000,
-	}, {
-		.flags		= 0
-	}
-};
-
-static struct platform_device debug_uart = {
-	.name	= "serial8250",
-	.id	= PLAT8250_DEV_PLATFORM,
-	.dev	= {
-		.platform_data	= debug_uart_platform_data,
-	},
-};
-static struct tegra_sdhci_platform_data sdhci_pdata1 = {
-	.cd_gpio	= -1,
-	.wp_gpio	= -1,
-	.power_gpio	= -1,
-};
-
-static struct tegra_sdhci_platform_data sdhci_pdata4 = {
-	.cd_gpio	= TRIMSLICE_GPIO_SD4_CD,
-	.wp_gpio	= TRIMSLICE_GPIO_SD4_WP,
-	.power_gpio	= -1,
-};
-
-static struct platform_device trimslice_audio_device = {
-	.name	= "tegra-snd-trimslice",
-	.id	= 0,
-};
-
-static struct platform_device *trimslice_devices[] __initdata = {
-	&debug_uart,
-	&tegra_sdhci_device1,
-	&tegra_sdhci_device4,
-	&tegra_i2s_device1,
-	&tegra_das_device,
-	&trimslice_audio_device,
-};
-
-static struct i2c_board_info trimslice_i2c3_board_info[] = {
-	{
-		I2C_BOARD_INFO("tlv320aic23", 0x1a),
-	},
-	{
-		I2C_BOARD_INFO("em3027", 0x56),
-	},
-};
-
-static void trimslice_i2c_init(void)
-{
-	platform_device_register(&tegra_i2c_device1);
-	platform_device_register(&tegra_i2c_device2);
-	platform_device_register(&tegra_i2c_device3);
-
-	i2c_register_board_info(2, trimslice_i2c3_board_info,
-				ARRAY_SIZE(trimslice_i2c3_board_info));
-}
-
-static void trimslice_usb_init(void)
-{
-	struct tegra_ehci_platform_data *pdata;
-
-	pdata = tegra_ehci1_device.dev.platform_data;
-	pdata->vbus_gpio = TRIMSLICE_GPIO_USB1_MODE;
-
-	tegra_ehci2_ulpi_phy_config.reset_gpio = TEGRA_GPIO_PV0;
-
-	platform_device_register(&tegra_ehci3_device);
-	platform_device_register(&tegra_ehci2_device);
-	platform_device_register(&tegra_ehci1_device);
-}
-
-static void __init tegra_trimslice_fixup(struct tag *tags, char **cmdline,
-	struct meminfo *mi)
-{
-	mi->nr_banks = 2;
-	mi->bank[0].start = PHYS_OFFSET;
-	mi->bank[0].size = 448 * SZ_1M;
-	mi->bank[1].start = SZ_512M;
-	mi->bank[1].size = SZ_512M;
-}
-
-static __initdata struct tegra_clk_init_table trimslice_clk_init_table[] = {
-	/* name		parent		rate		enabled */
-	{ "uarta",	"pll_p",	216000000,	true },
-	{ "pll_a",	"pll_p_out1",	56448000,	true },
-	{ "pll_a_out0",	"pll_a",	11289600,	true },
-	{ "cdev1",	NULL,		0,		true },
-	{ "i2s1",	"pll_a_out0",	11289600,	false},
-	{ NULL,		NULL,		0,		0},
-};
-
-static int __init tegra_trimslice_pci_init(void)
-{
-	if (!machine_is_trimslice())
-		return 0;
-
-	return tegra_pcie_init(true, true);
-}
-subsys_initcall(tegra_trimslice_pci_init);
-
-static void __init tegra_trimslice_init(void)
-{
-	tegra_clk_init_from_table(trimslice_clk_init_table);
-
-	trimslice_pinmux_init();
-
-	tegra_sdhci_device1.dev.platform_data = &sdhci_pdata1;
-	tegra_sdhci_device4.dev.platform_data = &sdhci_pdata4;
-
-	platform_add_devices(trimslice_devices, ARRAY_SIZE(trimslice_devices));
-
-	trimslice_i2c_init();
-	trimslice_usb_init();
-}
-
-MACHINE_START(TRIMSLICE, "trimslice")
-	.atag_offset	= 0x100,
-	.fixup		= tegra_trimslice_fixup,
-	.map_io         = tegra_map_common_io,
-	.init_early	= tegra20_init_early,
-	.init_irq       = tegra_init_irq,
-	.handle_irq	= gic_handle_irq,
-	.timer          = &tegra_timer,
-	.init_machine   = tegra_trimslice_init,
-	.init_late	= tegra_init_late,
-	.restart	= tegra_assert_system_reset,
-MACHINE_END
diff --git a/arch/arm/mach-tegra/board-trimslice.h b/arch/arm/mach-tegra/board-trimslice.h
deleted file mode 100644
index 50f128d..0000000
--- a/arch/arm/mach-tegra/board-trimslice.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * arch/arm/mach-tegra/board-trimslice.h
- *
- * Copyright (C) 2011 CompuLab, Ltd.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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 _MACH_TEGRA_BOARD_TRIMSLICE_H
-#define _MACH_TEGRA_BOARD_TRIMSLICE_H
-
-#include <mach/gpio-tegra.h>
-
-#define TRIMSLICE_GPIO_SD4_CD	TEGRA_GPIO_PP1	/* mmc4 cd */
-#define TRIMSLICE_GPIO_SD4_WP	TEGRA_GPIO_PP2	/* mmc4 wp */
-
-#define TRIMSLICE_GPIO_USB1_MODE	TEGRA_GPIO_PV2 /* USB1 mode */
-#define TRIMSLICE_GPIO_USB2_RST		TEGRA_GPIO_PV0 /* USB2 PHY reset */
-
-void trimslice_pinmux_init(void);
-
-#endif
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 58f981c..fd82085 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -1,6 +1,7 @@
 /*
  *
  * Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2012 NVIDIA CORPORATION.  All rights reserved.
  *
  * Author:
  *	Colin Cross <ccross@google.com>
@@ -19,8 +20,6 @@
 #include <linux/kernel.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
-#include <linux/debugfs.h>
-#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
@@ -32,325 +31,75 @@
 
 #include "board.h"
 #include "clock.h"
+#include "tegra_cpu_car.h"
+
+/* Global data of Tegra CPU CAR ops */
+struct tegra_cpu_car_ops *tegra_cpu_car_ops;
 
 /*
  * Locking:
  *
- * Each struct clk has a spinlock.
- *
- * To avoid AB-BA locking problems, locks must always be traversed from child
- * clock to parent clock.  For example, when enabling a clock, the clock's lock
- * is taken, and then clk_enable is called on the parent, which take's the
- * parent clock's lock.  There is one exceptions to this ordering: When dumping
- * the clock tree through debugfs.  In this case, clk_lock_all is called,
- * which attemps to iterate through the entire list of clocks and take every
- * clock lock.  If any call to spin_trylock fails, all locked clocks are
- * unlocked, and the process is retried.  When all the locks are held,
- * the only clock operation that can be called is clk_get_rate_all_locked.
- *
- * Within a single clock, no clock operation can call another clock operation
- * on itself, except for clk_get_rate_locked and clk_set_rate_locked.  Any
- * clock operation can call any other clock operation on any of it's possible
- * parents.
- *
  * An additional mutex, clock_list_lock, is used to protect the list of all
  * clocks.
  *
- * The clock operations must lock internally to protect against
- * read-modify-write on registers that are shared by multiple clocks
  */
 static DEFINE_MUTEX(clock_list_lock);
 static LIST_HEAD(clocks);
 
-struct clk *tegra_get_clock_by_name(const char *name)
-{
-	struct clk *c;
-	struct clk *ret = NULL;
-	mutex_lock(&clock_list_lock);
-	list_for_each_entry(c, &clocks, node) {
-		if (strcmp(c->name, name) == 0) {
-			ret = c;
-			break;
-		}
-	}
-	mutex_unlock(&clock_list_lock);
-	return ret;
-}
-
-/* Must be called with c->spinlock held */
-static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p)
-{
-	u64 rate;
-
-	rate = clk_get_rate(p);
-
-	if (c->mul != 0 && c->div != 0) {
-		rate *= c->mul;
-		rate += c->div - 1; /* round up */
-		do_div(rate, c->div);
-	}
-
-	return rate;
-}
-
-/* Must be called with c->spinlock held */
-unsigned long clk_get_rate_locked(struct clk *c)
-{
-	unsigned long rate;
-
-	if (c->parent)
-		rate = clk_predict_rate_from_parent(c, c->parent);
-	else
-		rate = c->rate;
-
-	return rate;
-}
-
-unsigned long clk_get_rate(struct clk *c)
+void tegra_clk_add(struct clk *clk)
 {
-	unsigned long flags;
-	unsigned long rate;
-
-	spin_lock_irqsave(&c->spinlock, flags);
-
-	rate = clk_get_rate_locked(c);
-
-	spin_unlock_irqrestore(&c->spinlock, flags);
-
-	return rate;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-int clk_reparent(struct clk *c, struct clk *parent)
-{
-	c->parent = parent;
-	return 0;
-}
-
-void clk_init(struct clk *c)
-{
-	spin_lock_init(&c->spinlock);
-
-	if (c->ops && c->ops->init)
-		c->ops->init(c);
-
-	if (!c->ops || !c->ops->enable) {
-		c->refcnt++;
-		c->set = true;
-		if (c->parent)
-			c->state = c->parent->state;
-		else
-			c->state = ON;
-	}
+	struct clk_tegra *c = to_clk_tegra(__clk_get_hw(clk));
 
 	mutex_lock(&clock_list_lock);
 	list_add(&c->node, &clocks);
 	mutex_unlock(&clock_list_lock);
 }
 
-int clk_enable(struct clk *c)
-{
-	int ret = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&c->spinlock, flags);
-
-	if (c->refcnt == 0) {
-		if (c->parent) {
-			ret = clk_enable(c->parent);
-			if (ret)
-				goto out;
-		}
-
-		if (c->ops && c->ops->enable) {
-			ret = c->ops->enable(c);
-			if (ret) {
-				if (c->parent)
-					clk_disable(c->parent);
-				goto out;
-			}
-			c->state = ON;
-			c->set = true;
-		}
-	}
-	c->refcnt++;
-out:
-	spin_unlock_irqrestore(&c->spinlock, flags);
-	return ret;
-}
-EXPORT_SYMBOL(clk_enable);
-
-void clk_disable(struct clk *c)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&c->spinlock, flags);
-
-	if (c->refcnt == 0) {
-		WARN(1, "Attempting to disable clock %s with refcnt 0", c->name);
-		spin_unlock_irqrestore(&c->spinlock, flags);
-		return;
-	}
-	if (c->refcnt == 1) {
-		if (c->ops && c->ops->disable)
-			c->ops->disable(c);
-
-		if (c->parent)
-			clk_disable(c->parent);
-
-		c->state = OFF;
-	}
-	c->refcnt--;
-
-	spin_unlock_irqrestore(&c->spinlock, flags);
-}
-EXPORT_SYMBOL(clk_disable);
-
-int clk_set_parent(struct clk *c, struct clk *parent)
-{
-	int ret;
-	unsigned long flags;
-	unsigned long new_rate;
-	unsigned long old_rate;
-
-	spin_lock_irqsave(&c->spinlock, flags);
-
-	if (!c->ops || !c->ops->set_parent) {
-		ret = -ENOSYS;
-		goto out;
-	}
-
-	new_rate = clk_predict_rate_from_parent(c, parent);
-	old_rate = clk_get_rate_locked(c);
-
-	ret = c->ops->set_parent(c, parent);
-	if (ret)
-		goto out;
-
-out:
-	spin_unlock_irqrestore(&c->spinlock, flags);
-	return ret;
-}
-EXPORT_SYMBOL(clk_set_parent);
-
-struct clk *clk_get_parent(struct clk *c)
-{
-	return c->parent;
-}
-EXPORT_SYMBOL(clk_get_parent);
-
-int clk_set_rate_locked(struct clk *c, unsigned long rate)
-{
-	long new_rate;
-
-	if (!c->ops || !c->ops->set_rate)
-		return -ENOSYS;
-
-	if (rate > c->max_rate)
-		rate = c->max_rate;
-
-	if (c->ops && c->ops->round_rate) {
-		new_rate = c->ops->round_rate(c, rate);
-
-		if (new_rate < 0)
-			return new_rate;
-
-		rate = new_rate;
-	}
-
-	return c->ops->set_rate(c, rate);
-}
-
-int clk_set_rate(struct clk *c, unsigned long rate)
-{
-	int ret;
-	unsigned long flags;
-
-	spin_lock_irqsave(&c->spinlock, flags);
-
-	ret = clk_set_rate_locked(c, rate);
-
-	spin_unlock_irqrestore(&c->spinlock, flags);
-
-	return ret;
-}
-EXPORT_SYMBOL(clk_set_rate);
-
-
-/* Must be called with clocks lock and all indvidual clock locks held */
-unsigned long clk_get_rate_all_locked(struct clk *c)
+struct clk *tegra_get_clock_by_name(const char *name)
 {
-	u64 rate;
-	int mul = 1;
-	int div = 1;
-	struct clk *p = c;
-
-	while (p) {
-		c = p;
-		if (c->mul != 0 && c->div != 0) {
-			mul *= c->mul;
-			div *= c->div;
+	struct clk_tegra *c;
+	struct clk *ret = NULL;
+	mutex_lock(&clock_list_lock);
+	list_for_each_entry(c, &clocks, node) {
+		if (strcmp(__clk_get_name(c->hw.clk), name) == 0) {
+			ret = c->hw.clk;
+			break;
 		}
-		p = c->parent;
-	}
-
-	rate = c->rate;
-	rate *= mul;
-	do_div(rate, div);
-
-	return rate;
-}
-
-long clk_round_rate(struct clk *c, unsigned long rate)
-{
-	unsigned long flags;
-	long ret;
-
-	spin_lock_irqsave(&c->spinlock, flags);
-
-	if (!c->ops || !c->ops->round_rate) {
-		ret = -ENOSYS;
-		goto out;
 	}
-
-	if (rate > c->max_rate)
-		rate = c->max_rate;
-
-	ret = c->ops->round_rate(c, rate);
-
-out:
-	spin_unlock_irqrestore(&c->spinlock, flags);
+	mutex_unlock(&clock_list_lock);
 	return ret;
 }
-EXPORT_SYMBOL(clk_round_rate);
 
 static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table)
 {
 	struct clk *c;
 	struct clk *p;
+	struct clk *parent;
 
 	int ret = 0;
 
 	c = tegra_get_clock_by_name(table->name);
 
 	if (!c) {
-		pr_warning("Unable to initialize clock %s\n",
+		pr_warn("Unable to initialize clock %s\n",
 			table->name);
 		return -ENODEV;
 	}
 
+	parent = clk_get_parent(c);
+
 	if (table->parent) {
 		p = tegra_get_clock_by_name(table->parent);
 		if (!p) {
-			pr_warning("Unable to find parent %s of clock %s\n",
+			pr_warn("Unable to find parent %s of clock %s\n",
 				table->parent, table->name);
 			return -ENODEV;
 		}
 
-		if (c->parent != p) {
+		if (parent != p) {
 			ret = clk_set_parent(c, p);
 			if (ret) {
-				pr_warning("Unable to set parent %s of clock %s: %d\n",
+				pr_warn("Unable to set parent %s of clock %s: %d\n",
 					table->parent, table->name, ret);
 				return -EINVAL;
 			}
@@ -360,16 +109,16 @@ static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table)
 	if (table->rate && table->rate != clk_get_rate(c)) {
 		ret = clk_set_rate(c, table->rate);
 		if (ret) {
-			pr_warning("Unable to set clock %s to rate %lu: %d\n",
+			pr_warn("Unable to set clock %s to rate %lu: %d\n",
 				table->name, table->rate, ret);
 			return -EINVAL;
 		}
 	}
 
 	if (table->enabled) {
-		ret = clk_enable(c);
+		ret = clk_prepare_enable(c);
 		if (ret) {
-			pr_warning("Unable to enable clock %s: %d\n",
+			pr_warn("Unable to enable clock %s: %d\n",
 				table->name, ret);
 			return -EINVAL;
 		}
@@ -383,19 +132,20 @@ void tegra_clk_init_from_table(struct tegra_clk_init_table *table)
 	for (; table->name; table++)
 		tegra_clk_init_one_from_table(table);
 }
-EXPORT_SYMBOL(tegra_clk_init_from_table);
 
 void tegra_periph_reset_deassert(struct clk *c)
 {
-	BUG_ON(!c->ops->reset);
-	c->ops->reset(c, false);
+	struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
+	BUG_ON(!clk->reset);
+	clk->reset(__clk_get_hw(c), false);
 }
 EXPORT_SYMBOL(tegra_periph_reset_deassert);
 
 void tegra_periph_reset_assert(struct clk *c)
 {
-	BUG_ON(!c->ops->reset);
-	c->ops->reset(c, true);
+	struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
+	BUG_ON(!clk->reset);
+	clk->reset(__clk_get_hw(c), true);
 }
 EXPORT_SYMBOL(tegra_periph_reset_assert);
 
@@ -405,268 +155,14 @@ EXPORT_SYMBOL(tegra_periph_reset_assert);
 int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
 {
 	int ret = 0;
-	unsigned long flags;
+	struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
 
-	spin_lock_irqsave(&c->spinlock, flags);
-
-	if (!c->ops || !c->ops->clk_cfg_ex) {
+	if (!clk->clk_cfg_ex) {
 		ret = -ENOSYS;
 		goto out;
 	}
-	ret = c->ops->clk_cfg_ex(c, p, setting);
+	ret = clk->clk_cfg_ex(__clk_get_hw(c), p, setting);
 
 out:
-	spin_unlock_irqrestore(&c->spinlock, flags);
-
 	return ret;
 }
-
-#ifdef CONFIG_DEBUG_FS
-
-static int __clk_lock_all_spinlocks(void)
-{
-	struct clk *c;
-
-	list_for_each_entry(c, &clocks, node)
-		if (!spin_trylock(&c->spinlock))
-			goto unlock_spinlocks;
-
-	return 0;
-
-unlock_spinlocks:
-	list_for_each_entry_continue_reverse(c, &clocks, node)
-		spin_unlock(&c->spinlock);
-
-	return -EAGAIN;
-}
-
-static void __clk_unlock_all_spinlocks(void)
-{
-	struct clk *c;
-
-	list_for_each_entry_reverse(c, &clocks, node)
-		spin_unlock(&c->spinlock);
-}
-
-/*
- * This function retries until it can take all locks, and may take
- * an arbitrarily long time to complete.
- * Must be called with irqs enabled, returns with irqs disabled
- * Must be called with clock_list_lock held
- */
-static void clk_lock_all(void)
-{
-	int ret;
-retry:
-	local_irq_disable();
-
-	ret = __clk_lock_all_spinlocks();
-	if (ret)
-		goto failed_spinlocks;
-
-	/* All locks taken successfully, return */
-	return;
-
-failed_spinlocks:
-	local_irq_enable();
-	yield();
-	goto retry;
-}
-
-/*
- * Unlocks all clocks after a clk_lock_all
- * Must be called with irqs disabled, returns with irqs enabled
- * Must be called with clock_list_lock held
- */
-static void clk_unlock_all(void)
-{
-	__clk_unlock_all_spinlocks();
-
-	local_irq_enable();
-}
-
-static struct dentry *clk_debugfs_root;
-
-
-static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
-{
-	struct clk *child;
-	const char *state = "uninit";
-	char div[8] = {0};
-
-	if (c->state == ON)
-		state = "on";
-	else if (c->state == OFF)
-		state = "off";
-
-	if (c->mul != 0 && c->div != 0) {
-		if (c->mul > c->div) {
-			int mul = c->mul / c->div;
-			int mul2 = (c->mul * 10 / c->div) % 10;
-			int mul3 = (c->mul * 10) % c->div;
-			if (mul2 == 0 && mul3 == 0)
-				snprintf(div, sizeof(div), "x%d", mul);
-			else if (mul3 == 0)
-				snprintf(div, sizeof(div), "x%d.%d", mul, mul2);
-			else
-				snprintf(div, sizeof(div), "x%d.%d..", mul, mul2);
-		} else {
-			snprintf(div, sizeof(div), "%d%s", c->div / c->mul,
-				(c->div % c->mul) ? ".5" : "");
-		}
-	}
-
-	seq_printf(s, "%*s%c%c%-*s %-6s %-3d %-8s %-10lu\n",
-		level * 3 + 1, "",
-		c->rate > c->max_rate ? '!' : ' ',
-		!c->set ? '*' : ' ',
-		30 - level * 3, c->name,
-		state, c->refcnt, div, clk_get_rate_all_locked(c));
-
-	list_for_each_entry(child, &clocks, node) {
-		if (child->parent != c)
-			continue;
-
-		clock_tree_show_one(s, child, level + 1);
-	}
-}
-
-static int clock_tree_show(struct seq_file *s, void *data)
-{
-	struct clk *c;
-	seq_printf(s, "   clock                          state  ref div      rate\n");
-	seq_printf(s, "--------------------------------------------------------------\n");
-
-	mutex_lock(&clock_list_lock);
-
-	clk_lock_all();
-
-	list_for_each_entry(c, &clocks, node)
-		if (c->parent == NULL)
-			clock_tree_show_one(s, c, 0);
-
-	clk_unlock_all();
-
-	mutex_unlock(&clock_list_lock);
-	return 0;
-}
-
-static int clock_tree_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, clock_tree_show, inode->i_private);
-}
-
-static const struct file_operations clock_tree_fops = {
-	.open		= clock_tree_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int possible_parents_show(struct seq_file *s, void *data)
-{
-	struct clk *c = s->private;
-	int i;
-
-	for (i = 0; c->inputs[i].input; i++) {
-		char *first = (i == 0) ? "" : " ";
-		seq_printf(s, "%s%s", first, c->inputs[i].input->name);
-	}
-	seq_printf(s, "\n");
-	return 0;
-}
-
-static int possible_parents_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, possible_parents_show, inode->i_private);
-}
-
-static const struct file_operations possible_parents_fops = {
-	.open		= possible_parents_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int clk_debugfs_register_one(struct clk *c)
-{
-	struct dentry *d;
-
-	d = debugfs_create_dir(c->name, clk_debugfs_root);
-	if (!d)
-		return -ENOMEM;
-	c->dent = d;
-
-	d = debugfs_create_u8("refcnt", S_IRUGO, c->dent, (u8 *)&c->refcnt);
-	if (!d)
-		goto err_out;
-
-	d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
-	if (!d)
-		goto err_out;
-
-	d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
-	if (!d)
-		goto err_out;
-
-	if (c->inputs) {
-		d = debugfs_create_file("possible_parents", S_IRUGO, c->dent,
-			c, &possible_parents_fops);
-		if (!d)
-			goto err_out;
-	}
-
-	return 0;
-
-err_out:
-	debugfs_remove_recursive(c->dent);
-	return -ENOMEM;
-}
-
-static int clk_debugfs_register(struct clk *c)
-{
-	int err;
-	struct clk *pa = c->parent;
-
-	if (pa && !pa->dent) {
-		err = clk_debugfs_register(pa);
-		if (err)
-			return err;
-	}
-
-	if (!c->dent) {
-		err = clk_debugfs_register_one(c);
-		if (err)
-			return err;
-	}
-	return 0;
-}
-
-int __init tegra_clk_debugfs_init(void)
-{
-	struct clk *c;
-	struct dentry *d;
-	int err = -ENOMEM;
-
-	d = debugfs_create_dir("clock", NULL);
-	if (!d)
-		return -ENOMEM;
-	clk_debugfs_root = d;
-
-	d = debugfs_create_file("clock_tree", S_IRUGO, clk_debugfs_root, NULL,
-		&clock_tree_fops);
-	if (!d)
-		goto err_out;
-
-	list_for_each_entry(c, &clocks, node) {
-		err = clk_debugfs_register(c);
-		if (err)
-			goto err_out;
-	}
-	return 0;
-err_out:
-	debugfs_remove_recursive(clk_debugfs_root);
-	return err;
-}
-
-#endif
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index bc30065..2aa37f5 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -2,6 +2,7 @@
  * arch/arm/mach-tegra/include/mach/clock.h
  *
  * Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2012 NVIDIA CORPORATION.  All rights reserved.
  *
  * Author:
  *	Colin Cross <ccross@google.com>
@@ -20,9 +21,9 @@
 #ifndef __MACH_TEGRA_CLOCK_H
 #define __MACH_TEGRA_CLOCK_H
 
+#include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/list.h>
-#include <linux/spinlock.h>
 
 #include <mach/clk.h>
 
@@ -52,7 +53,8 @@
 #define ENABLE_ON_INIT		(1 << 28)
 #define PERIPH_ON_APB           (1 << 29)
 
-struct clk;
+struct clk_tegra;
+#define to_clk_tegra(_hw) container_of(_hw, struct clk_tegra, hw)
 
 struct clk_mux_sel {
 	struct clk	*input;
@@ -68,47 +70,29 @@ struct clk_pll_freq_table {
 	u8		cpcon;
 };
 
-struct clk_ops {
-	void		(*init)(struct clk *);
-	int		(*enable)(struct clk *);
-	void		(*disable)(struct clk *);
-	int		(*set_parent)(struct clk *, struct clk *);
-	int		(*set_rate)(struct clk *, unsigned long);
-	long		(*round_rate)(struct clk *, unsigned long);
-	void		(*reset)(struct clk *, bool);
-	int		(*clk_cfg_ex)(struct clk *,
-				enum tegra_clk_ex_param, u32);
-};
-
 enum clk_state {
 	UNINITIALIZED = 0,
 	ON,
 	OFF,
 };
 
-struct clk {
+struct clk_tegra {
 	/* node for master clocks list */
-	struct list_head	node;		/* node for list of all clocks */
+	struct list_head	node;	/* node for list of all clocks */
 	struct clk_lookup	lookup;
+	struct clk_hw		hw;
 
-#ifdef CONFIG_DEBUG_FS
-	struct dentry		*dent;
-#endif
 	bool			set;
-	struct clk_ops		*ops;
-	unsigned long		rate;
+	unsigned long		fixed_rate;
 	unsigned long		max_rate;
 	unsigned long		min_rate;
 	u32			flags;
 	const char		*name;
 
-	u32			refcnt;
 	enum clk_state		state;
-	struct clk		*parent;
 	u32			div;
 	u32			mul;
 
-	const struct clk_mux_sel	*inputs;
 	u32				reg;
 	u32				reg_shift;
 
@@ -144,7 +128,8 @@ struct clk {
 		} shared_bus_user;
 	} u;
 
-	spinlock_t spinlock;
+	void (*reset)(struct clk_hw *, bool);
+	int (*clk_cfg_ex)(struct clk_hw *, enum tegra_clk_ex_param, u32);
 };
 
 struct clk_duplicate {
@@ -159,13 +144,10 @@ struct tegra_clk_init_table {
 	bool enabled;
 };
 
+void tegra_clk_add(struct clk *c);
 void tegra2_init_clocks(void);
 void tegra30_init_clocks(void);
-void clk_init(struct clk *clk);
 struct clk *tegra_get_clock_by_name(const char *name);
-int clk_reparent(struct clk *c, struct clk *parent);
 void tegra_clk_init_from_table(struct tegra_clk_init_table *table);
-unsigned long clk_get_rate_locked(struct clk *c);
-int clk_set_rate_locked(struct clk *c, unsigned long rate);
 
 #endif
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 96fef6b..0560538 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -34,6 +34,7 @@
 #include "fuse.h"
 #include "pmc.h"
 #include "apbio.h"
+#include "sleep.h"
 
 /*
  * Storage for debug-macro.S's state.
@@ -135,6 +136,7 @@ void __init tegra20_init_early(void)
 	tegra_init_cache(0x331, 0x441);
 	tegra_pmc_init();
 	tegra_powergate_init();
+	tegra20_hotplug_init();
 }
 #endif
 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
@@ -147,11 +149,11 @@ void __init tegra30_init_early(void)
 	tegra_init_cache(0x441, 0x551);
 	tegra_pmc_init();
 	tegra_powergate_init();
+	tegra30_hotplug_init();
 }
 #endif
 
 void __init tegra_init_late(void)
 {
-	tegra_clk_debugfs_init();
 	tegra_powergate_debugfs_init();
 }
diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c
index c70e65f..61e9603 100644
--- a/arch/arm/mach-tegra/devices.c
+++ b/arch/arm/mach-tegra/devices.c
@@ -23,7 +23,6 @@
 #include <linux/fsl_devices.h>
 #include <linux/serial_8250.h>
 #include <linux/i2c-tegra.h>
-#include <asm/pmu.h>
 #include <mach/irqs.h>
 #include <mach/iomap.h>
 #include <mach/dma.h>
@@ -516,7 +515,7 @@ static struct resource tegra_pmu_resources[] = {
 
 struct platform_device tegra_pmu_device = {
 	.name		= "arm-pmu",
-	.id		= ARM_PMU_DEVICE_CPU,
+	.id		= -1,
 	.num_resources	= ARRAY_SIZE(tegra_pmu_resources),
 	.resource	= tegra_pmu_resources,
 };
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index f946d12..0b7db17 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -93,9 +93,9 @@ void tegra_init_fuse(void)
 {
 	u32 id;
 
-	u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
+	u32 reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48));
 	reg |= 1 << 28;
-	writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
+	writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48));
 
 	reg = tegra_fuse_readl(FUSE_SKU_INFO);
 	tegra_sku_id = reg & 0xFF;
diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S
index fef9c2c..6addc78 100644
--- a/arch/arm/mach-tegra/headsmp.S
+++ b/arch/arm/mach-tegra/headsmp.S
@@ -7,17 +7,13 @@
 
 #include "flowctrl.h"
 #include "reset.h"
+#include "sleep.h"
 
 #define APB_MISC_GP_HIDREV	0x804
 #define PMC_SCRATCH41	0x140
 
 #define RESET_DATA(x)	((TEGRA_RESET_##x)*4)
 
-	.macro mov32, reg, val
-	movw	\reg, #:lower16:\val
-	movt	\reg, #:upper16:\val
-	.endm
-
         .section ".text.head", "ax"
 	__CPUINIT
 
diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c
index d8dc9dd..d02a354 100644
--- a/arch/arm/mach-tegra/hotplug.c
+++ b/arch/arm/mach-tegra/hotplug.c
@@ -1,91 +1,23 @@
 /*
- *  linux/arch/arm/mach-realview/hotplug.c
  *
  *  Copyright (C) 2002 ARM Ltd.
  *  All Rights Reserved
+ *  Copyright (c) 2010, 2012 NVIDIA Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
 #include <linux/kernel.h>
-#include <linux/errno.h>
 #include <linux/smp.h>
 
 #include <asm/cacheflush.h>
-#include <asm/cp15.h>
+#include <asm/smp_plat.h>
 
-static inline void cpu_enter_lowpower(void)
-{
-	unsigned int v;
-
-	flush_cache_all();
-	asm volatile(
-	"	mcr	p15, 0, %1, c7, c5, 0\n"
-	"	mcr	p15, 0, %1, c7, c10, 4\n"
-	/*
-	 * Turn off coherency
-	 */
-	"	mrc	p15, 0, %0, c1, c0, 1\n"
-	"	bic	%0, %0, #0x20\n"
-	"	mcr	p15, 0, %0, c1, c0, 1\n"
-	"	mrc	p15, 0, %0, c1, c0, 0\n"
-	"	bic	%0, %0, %2\n"
-	"	mcr	p15, 0, %0, c1, c0, 0\n"
-	  : "=&r" (v)
-	  : "r" (0), "Ir" (CR_C)
-	  : "cc");
-}
-
-static inline void cpu_leave_lowpower(void)
-{
-	unsigned int v;
-
-	asm volatile(
-	"mrc	p15, 0, %0, c1, c0, 0\n"
-	"	orr	%0, %0, %1\n"
-	"	mcr	p15, 0, %0, c1, c0, 0\n"
-	"	mrc	p15, 0, %0, c1, c0, 1\n"
-	"	orr	%0, %0, #0x20\n"
-	"	mcr	p15, 0, %0, c1, c0, 1\n"
-	  : "=&r" (v)
-	  : "Ir" (CR_C)
-	  : "cc");
-}
-
-static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
-{
-	/*
-	 * there is no power-control hardware on this platform, so all
-	 * we can do is put the core into WFI; this is safe as the calling
-	 * code will have already disabled interrupts
-	 */
-	for (;;) {
-		/*
-		 * here's the WFI
-		 */
-		asm(".word	0xe320f003\n"
-		    :
-		    :
-		    : "memory", "cc");
+#include "sleep.h"
+#include "tegra_cpu_car.h"
 
-		/*if (pen_release == cpu) {*/
-			/*
-			 * OK, proper wakeup, we're done
-			 */
-			break;
-		/*}*/
-
-		/*
-		 * Getting here, means that we have come out of WFI without
-		 * having been woken up - this shouldn't happen
-		 *
-		 * Just note it happening - when we're woken, we can report
-		 * its occurrence.
-		 */
-		(*spurious)++;
-	}
-}
+static void (*tegra_hotplug_shutdown)(void);
 
 int platform_cpu_kill(unsigned int cpu)
 {
@@ -99,22 +31,20 @@ int platform_cpu_kill(unsigned int cpu)
  */
 void platform_cpu_die(unsigned int cpu)
 {
-	int spurious = 0;
+	cpu = cpu_logical_map(cpu);
 
-	/*
-	 * we're ready for shutdown now, so do it
-	 */
-	cpu_enter_lowpower();
-	platform_do_lowpower(cpu, &spurious);
+	/* Flush the L1 data cache. */
+	flush_cache_all();
 
-	/*
-	 * bring this CPU back into the world of cache
-	 * coherency, and then restore interrupts
-	 */
-	cpu_leave_lowpower();
+	/* Shut down the current CPU. */
+	tegra_hotplug_shutdown();
 
-	if (spurious)
-		pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
+	/* Clock gate the CPU */
+	tegra_wait_cpu_in_reset(cpu);
+	tegra_disable_cpu_clock(cpu);
+
+	/* Should never return here. */
+	BUG();
 }
 
 int platform_cpu_disable(unsigned int cpu)
@@ -125,3 +55,19 @@ int platform_cpu_disable(unsigned int cpu)
 	 */
 	return cpu == 0 ? -EPERM : 0;
 }
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+extern void tegra20_hotplug_shutdown(void);
+void __init tegra20_hotplug_init(void)
+{
+	tegra_hotplug_shutdown = tegra20_hotplug_shutdown;
+}
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+extern void tegra30_hotplug_shutdown(void);
+void __init tegra30_hotplug_init(void)
+{
+	tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
+}
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h
index d97e403..95f3a54 100644
--- a/arch/arm/mach-tegra/include/mach/clk.h
+++ b/arch/arm/mach-tegra/include/mach/clk.h
@@ -34,7 +34,10 @@ enum tegra_clk_ex_param {
 void tegra_periph_reset_deassert(struct clk *c);
 void tegra_periph_reset_assert(struct clk *c);
 
+#ifndef CONFIG_COMMON_CLK
 unsigned long clk_get_rate_all_locked(struct clk *c);
+#endif
+
 void tegra2_sdmmc_tap_delay(struct clk *c, int delay);
 int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting);
 
diff --git a/arch/arm/mach-tegra/include/mach/io.h b/arch/arm/mach-tegra/include/mach/io.h
deleted file mode 100644
index fe700f9..0000000
--- a/arch/arm/mach-tegra/include/mach/io.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * arch/arm/mach-tegra/include/mach/io.h
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- *	Colin Cross <ccross@google.com>
- *	Erik Gilling <konkers@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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 __MACH_TEGRA_IO_H
-#define __MACH_TEGRA_IO_H
-
-#define IO_SPACE_LIMIT 0xffff
-
-#ifndef __ASSEMBLER__
-
-#ifdef CONFIG_TEGRA_PCI
-extern void __iomem *tegra_pcie_io_base;
-
-static inline void __iomem *__io(unsigned long addr)
-{
-	return tegra_pcie_io_base + (addr & IO_SPACE_LIMIT);
-}
-#else
-static inline void __iomem *__io(unsigned long addr)
-{
-	return (void __iomem *)addr;
-}
-#endif
-
-#define __io(a)         __io(a)
-
-#endif
-
-#endif
diff --git a/arch/arm/mach-tegra/include/mach/iomap.h b/arch/arm/mach-tegra/include/mach/iomap.h
index 7e76da7..fee3a94 100644
--- a/arch/arm/mach-tegra/include/mach/iomap.h
+++ b/arch/arm/mach-tegra/include/mach/iomap.h
@@ -303,6 +303,9 @@
 #define IO_APB_VIRT	IOMEM(0xFE300000)
 #define IO_APB_SIZE	SZ_1M
 
+#define TEGRA_PCIE_BASE		0x80000000
+#define TEGRA_PCIE_IO_BASE	(TEGRA_PCIE_BASE + SZ_4M)
+
 #define IO_TO_VIRT_BETWEEN(p, st, sz)	((p) >= (st) && (p) < ((st) + (sz)))
 #define IO_TO_VIRT_XLATE(p, pst, vst)	(((p) - (pst) + (vst)))
 
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index d3ad515..3463fb5 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -171,8 +171,6 @@ static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
  * 0x90000000 - 0x9fffffff - non-prefetchable memory
  * 0xa0000000 - 0xbfffffff - prefetchable memory
  */
-#define TEGRA_PCIE_BASE		0x80000000
-
 #define PCIE_REGS_SZ		SZ_16K
 #define PCIE_CFG_OFF		PCIE_REGS_SZ
 #define PCIE_CFG_SZ		SZ_1M
@@ -180,8 +178,6 @@ static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
 #define PCIE_EXT_CFG_SZ		SZ_1M
 #define PCIE_IOMAP_SZ		(PCIE_REGS_SZ + PCIE_CFG_SZ + PCIE_EXT_CFG_SZ)
 
-#define MMIO_BASE		(TEGRA_PCIE_BASE + SZ_4M)
-#define MMIO_SIZE		SZ_64K
 #define MEM_BASE_0		(TEGRA_PCIE_BASE + SZ_256M)
 #define MEM_SIZE_0		SZ_128M
 #define MEM_BASE_1		(MEM_BASE_0 + MEM_SIZE_0)
@@ -204,10 +200,9 @@ struct tegra_pcie_port {
 
 	bool			link_up;
 
-	char			io_space_name[16];
 	char			mem_space_name[16];
 	char			prefetch_space_name[20];
-	struct resource		res[3];
+	struct resource		res[2];
 };
 
 struct tegra_pcie_info {
@@ -223,17 +218,7 @@ struct tegra_pcie_info {
 	struct clk		*pll_e;
 };
 
-static struct tegra_pcie_info tegra_pcie = {
-	.res_mmio = {
-		.name = "PCI IO",
-		.start = MMIO_BASE,
-		.end = MMIO_BASE + MMIO_SIZE - 1,
-		.flags = IORESOURCE_MEM,
-	},
-};
-
-void __iomem *tegra_pcie_io_base;
-EXPORT_SYMBOL(tegra_pcie_io_base);
+static struct tegra_pcie_info tegra_pcie;
 
 static inline void afi_writel(u32 value, unsigned long offset)
 {
@@ -391,24 +376,7 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
 	pp = tegra_pcie.port + nr;
 	pp->root_bus_nr = sys->busnr;
 
-	/*
-	 * IORESOURCE_IO
-	 */
-	snprintf(pp->io_space_name, sizeof(pp->io_space_name),
-		 "PCIe %d I/O", pp->index);
-	pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0;
-	pp->res[0].name = pp->io_space_name;
-	if (pp->index == 0) {
-		pp->res[0].start = PCIBIOS_MIN_IO;
-		pp->res[0].end = pp->res[0].start + SZ_32K - 1;
-	} else {
-		pp->res[0].start = PCIBIOS_MIN_IO + SZ_32K;
-		pp->res[0].end = IO_SPACE_LIMIT;
-	}
-	pp->res[0].flags = IORESOURCE_IO;
-	if (request_resource(&ioport_resource, &pp->res[0]))
-		panic("Request PCIe IO resource failed\n");
-	pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
+	pci_ioremap_io(nr * SZ_64K, TEGRA_PCIE_IO_BASE);
 
 	/*
 	 * IORESOURCE_MEM
@@ -416,18 +384,18 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
 	snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
 		 "PCIe %d MEM", pp->index);
 	pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
-	pp->res[1].name = pp->mem_space_name;
+	pp->res[0].name = pp->mem_space_name;
 	if (pp->index == 0) {
-		pp->res[1].start = MEM_BASE_0;
-		pp->res[1].end = pp->res[1].start + MEM_SIZE_0 - 1;
+		pp->res[0].start = MEM_BASE_0;
+		pp->res[0].end = pp->res[0].start + MEM_SIZE_0 - 1;
 	} else {
-		pp->res[1].start = MEM_BASE_1;
-		pp->res[1].end = pp->res[1].start + MEM_SIZE_1 - 1;
+		pp->res[0].start = MEM_BASE_1;
+		pp->res[0].end = pp->res[0].start + MEM_SIZE_1 - 1;
 	}
-	pp->res[1].flags = IORESOURCE_MEM;
-	if (request_resource(&iomem_resource, &pp->res[1]))
+	pp->res[0].flags = IORESOURCE_MEM;
+	if (request_resource(&iomem_resource, &pp->res[0]))
 		panic("Request PCIe Memory resource failed\n");
-	pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, &pp->res[0], sys->mem_offset);
 
 	/*
 	 * IORESOURCE_MEM | IORESOURCE_PREFETCH
@@ -435,18 +403,18 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
 	snprintf(pp->prefetch_space_name, sizeof(pp->prefetch_space_name),
 		 "PCIe %d PREFETCH MEM", pp->index);
 	pp->prefetch_space_name[sizeof(pp->prefetch_space_name) - 1] = 0;
-	pp->res[2].name = pp->prefetch_space_name;
+	pp->res[1].name = pp->prefetch_space_name;
 	if (pp->index == 0) {
-		pp->res[2].start = PREFETCH_MEM_BASE_0;
-		pp->res[2].end = pp->res[2].start + PREFETCH_MEM_SIZE_0 - 1;
+		pp->res[1].start = PREFETCH_MEM_BASE_0;
+		pp->res[1].end = pp->res[1].start + PREFETCH_MEM_SIZE_0 - 1;
 	} else {
-		pp->res[2].start = PREFETCH_MEM_BASE_1;
-		pp->res[2].end = pp->res[2].start + PREFETCH_MEM_SIZE_1 - 1;
+		pp->res[1].start = PREFETCH_MEM_BASE_1;
+		pp->res[1].end = pp->res[1].start + PREFETCH_MEM_SIZE_1 - 1;
 	}
-	pp->res[2].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
-	if (request_resource(&iomem_resource, &pp->res[2]))
+	pp->res[1].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+	if (request_resource(&iomem_resource, &pp->res[1]))
 		panic("Request PCIe Prefetch Memory resource failed\n");
-	pci_add_resource_offset(&sys->resources, &pp->res[2], sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
 
 	return 1;
 }
@@ -541,8 +509,8 @@ static void tegra_pcie_setup_translations(void)
 
 	/* Bar 2: downstream IO bar */
 	fpci_bar = ((__u32)0xfdfc << 16);
-	size = MMIO_SIZE;
-	axi_address = MMIO_BASE;
+	size = SZ_128K;
+	axi_address = TEGRA_PCIE_IO_BASE;
 	afi_writel(axi_address, AFI_AXI_BAR2_START);
 	afi_writel(size >> 12, AFI_AXI_BAR2_SZ);
 	afi_writel(fpci_bar, AFI_FPCI_BAR2);
@@ -776,7 +744,6 @@ static void tegra_pcie_clocks_put(void)
 
 static int __init tegra_pcie_get_resources(void)
 {
-	struct resource *res_mmio = &tegra_pcie.res_mmio;
 	int err;
 
 	err = tegra_pcie_clocks_get();
@@ -798,34 +765,16 @@ static int __init tegra_pcie_get_resources(void)
 		goto err_map_reg;
 	}
 
-	err = request_resource(&iomem_resource, res_mmio);
-	if (err) {
-		pr_err("PCIE: Failed to request resources: %d\n", err);
-		goto err_req_io;
-	}
-
-	tegra_pcie_io_base = ioremap_nocache(res_mmio->start,
-					     resource_size(res_mmio));
-	if (tegra_pcie_io_base == NULL) {
-		pr_err("PCIE: Failed to map IO\n");
-		err = -ENOMEM;
-		goto err_map_io;
-	}
-
 	err = request_irq(INT_PCIE_INTR, tegra_pcie_isr,
 			  IRQF_SHARED, "PCIE", &tegra_pcie);
 	if (err) {
 		pr_err("PCIE: Failed to register IRQ: %d\n", err);
-		goto err_irq;
+		goto err_req_io;
 	}
 	set_irq_flags(INT_PCIE_INTR, IRQF_VALID);
 
 	return 0;
 
-err_irq:
-	iounmap(tegra_pcie_io_base);
-err_map_io:
-	release_resource(&tegra_pcie.res_mmio);
 err_req_io:
 	iounmap(tegra_pcie.regs);
 err_map_reg:
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 1a208db..96ed171 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -31,6 +31,7 @@
 #include "fuse.h"
 #include "flowctrl.h"
 #include "reset.h"
+#include "tegra_cpu_car.h"
 
 extern void tegra_secondary_startup(void);
 
@@ -38,17 +39,6 @@ static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE);
 
 #define EVP_CPU_RESET_VECTOR \
 	(IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100)
-#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX \
-	(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x4c)
-#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET \
-	(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x340)
-#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR \
-	(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x344)
-#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR \
-	(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x34c)
-
-#define CPU_CLOCK(cpu)	(0x1<<(8+cpu))
-#define CPU_RESET(cpu)	(0x1111ul<<(cpu))
 
 void __cpuinit platform_secondary_init(unsigned int cpu)
 {
@@ -63,13 +53,8 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
 
 static int tegra20_power_up_cpu(unsigned int cpu)
 {
-	u32 reg;
-
 	/* Enable the CPU clock. */
-	reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
-	writel(reg & ~CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
-	barrier();
-	reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+	tegra_enable_cpu_clock(cpu);
 
 	/* Clear flow controller CSR. */
 	flowctrl_write_cpu_csr(cpu, 0);
@@ -79,7 +64,6 @@ static int tegra20_power_up_cpu(unsigned int cpu)
 
 static int tegra30_power_up_cpu(unsigned int cpu)
 {
-	u32 reg;
 	int ret, pwrgateid;
 	unsigned long timeout;
 
@@ -103,8 +87,7 @@ static int tegra30_power_up_cpu(unsigned int cpu)
 	}
 
 	/* CPU partition is powered. Enable the CPU clock. */
-	writel(CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
-	reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
+	tegra_enable_cpu_clock(cpu);
 	udelay(10);
 
 	/* Remove I/O clamps. */
@@ -128,8 +111,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 	 * via the flow controller). This will have no effect on first boot
 	 * of the CPU since it should already be in reset.
 	 */
-	writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
-	dmb();
+	tegra_put_cpu_in_reset(cpu);
 
 	/*
 	 * Unhalt the CPU. If the flow controller was used to power-gate the
@@ -155,8 +137,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 		goto done;
 
 	/* Take the CPU out of reset. */
-	writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
-	wmb();
+	tegra_cpu_out_of_reset(cpu);
 done:
 	return status;
 }
diff --git a/arch/arm/mach-tegra/sleep-t20.S b/arch/arm/mach-tegra/sleep-t20.S
new file mode 100644
index 0000000..a36ae41
--- /dev/null
+++ b/arch/arm/mach-tegra/sleep-t20.S
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2011, Google, Inc.
+ *
+ * Author: Colin Cross <ccross@android.com>
+ *         Gary King <gking@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/assembler.h>
+
+#include <mach/iomap.h>
+
+#include "sleep.h"
+#include "flowctrl.h"
+
+#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
+/*
+ * tegra20_hotplug_shutdown(void)
+ *
+ * puts the current cpu in reset
+ * should never return
+ */
+ENTRY(tegra20_hotplug_shutdown)
+	/* Turn off SMP coherency */
+	exit_smp r4, r5
+
+	/* Put this CPU down */
+	cpu_id	r0
+	bl	tegra20_cpu_shutdown
+	mov	pc, lr			@ should never get here
+ENDPROC(tegra20_hotplug_shutdown)
+
+/*
+ * tegra20_cpu_shutdown(int cpu)
+ *
+ * r0 is cpu to reset
+ *
+ * puts the specified CPU in wait-for-event mode on the flow controller
+ * and puts the CPU in reset
+ * can be called on the current cpu or another cpu
+ * if called on the current cpu, does not return
+ * MUST NOT BE CALLED FOR CPU 0.
+ *
+ * corrupts r0-r3, r12
+ */
+ENTRY(tegra20_cpu_shutdown)
+	cmp	r0, #0
+	moveq	pc, lr			@ must not be called for CPU 0
+
+	cpu_to_halt_reg r1, r0
+	ldr	r3, =TEGRA_FLOW_CTRL_VIRT
+	mov	r2, #FLOW_CTRL_WAITEVENT | FLOW_CTRL_JTAG_RESUME
+	str	r2, [r3, r1]		@ put flow controller in wait event mode
+	ldr	r2, [r3, r1]
+	isb
+	dsb
+	movw	r1, 0x1011
+	mov	r1, r1, lsl r0
+	ldr	r3, =TEGRA_CLK_RESET_VIRT
+	str	r1, [r3, #0x340]	@ put slave CPU in reset
+	isb
+	dsb
+	cpu_id	r3
+	cmp	r3, r0
+	beq	.
+	mov	pc, lr
+ENDPROC(tegra20_cpu_shutdown)
+#endif
diff --git a/arch/arm/mach-tegra/sleep-t30.S b/arch/arm/mach-tegra/sleep-t30.S
new file mode 100644
index 0000000..777d9ce
--- /dev/null
+++ b/arch/arm/mach-tegra/sleep-t30.S
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2012, NVIDIA Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/assembler.h>
+
+#include <mach/iomap.h>
+
+#include "sleep.h"
+#include "flowctrl.h"
+
+#define TEGRA30_POWER_HOTPLUG_SHUTDOWN	(1 << 27) /* Hotplug shutdown */
+
+#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
+/*
+ * tegra30_hotplug_shutdown(void)
+ *
+ * Powergates the current CPU.
+ * Should never return.
+ */
+ENTRY(tegra30_hotplug_shutdown)
+	/* Turn off SMP coherency */
+	exit_smp r4, r5
+
+	/* Powergate this CPU */
+	mov	r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN
+	bl	tegra30_cpu_shutdown
+	mov	pc, lr			@ should never get here
+ENDPROC(tegra30_hotplug_shutdown)
+
+/*
+ * tegra30_cpu_shutdown(unsigned long flags)
+ *
+ * Puts the current CPU in wait-for-event mode on the flow controller
+ * and powergates it -- flags (in R0) indicate the request type.
+ * Must never be called for CPU 0.
+ *
+ * corrupts r0-r4, r12
+ */
+ENTRY(tegra30_cpu_shutdown)
+	cpu_id	r3
+	cmp	r3, #0
+	moveq	pc, lr		@ Must never be called for CPU 0
+
+	ldr	r12, =TEGRA_FLOW_CTRL_VIRT
+	cpu_to_csr_reg r1, r3
+	add	r1, r1, r12	@ virtual CSR address for this CPU
+	cpu_to_halt_reg r2, r3
+	add	r2, r2, r12	@ virtual HALT_EVENTS address for this CPU
+
+	/*
+	 * Clear this CPU's "event" and "interrupt" flags and power gate
+	 * it when halting but not before it is in the "WFE" state.
+	 */
+	movw	r12, \
+		FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | \
+		FLOW_CTRL_CSR_ENABLE
+	mov	r4, #(1 << 4)
+	orr	r12, r12, r4, lsl r3
+	str	r12, [r1]
+
+	/* Halt this CPU. */
+	mov	r3, #0x400
+delay_1:
+	subs	r3, r3, #1			@ delay as a part of wfe war.
+	bge	delay_1;
+	cpsid	a				@ disable imprecise aborts.
+	ldr	r3, [r1]			@ read CSR
+	str	r3, [r1]			@ clear CSR
+	tst	r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN
+	movne	r3, #FLOW_CTRL_WAITEVENT		@ For hotplug
+	str	r3, [r2]
+	ldr	r0, [r2]
+	b	wfe_war
+
+__cpu_reset_again:
+	dsb
+	.align 5
+	wfe					@ CPU should be power gated here
+wfe_war:
+	b	__cpu_reset_again
+
+	/*
+	 * 38 nop's, which fills reset of wfe cache line and
+	 * 4 more cachelines with nop
+	 */
+	.rept 38
+	nop
+	.endr
+	b	.				@ should never get here
+
+ENDPROC(tegra30_cpu_shutdown)
+#endif
diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S
index d29b156..ea81554 100644
--- a/arch/arm/mach-tegra/sleep.S
+++ b/arch/arm/mach-tegra/sleep.S
@@ -29,36 +29,5 @@
 #include <mach/iomap.h>
 
 #include "flowctrl.h"
+#include "sleep.h"
 
-#define TEGRA_FLOW_CTRL_VIRT (TEGRA_FLOW_CTRL_BASE - IO_PPSB_PHYS \
-					+ IO_PPSB_VIRT)
-
-/* returns the offset of the flow controller halt register for a cpu */
-.macro cpu_to_halt_reg rd, rcpu
-	cmp	\rcpu, #0
-	subne	\rd, \rcpu, #1
-	movne	\rd, \rd, lsl #3
-	addne	\rd, \rd, #0x14
-	moveq	\rd, #0
-.endm
-
-/* returns the offset of the flow controller csr register for a cpu */
-.macro cpu_to_csr_reg rd, rcpu
-	cmp	\rcpu, #0
-	subne	\rd, \rcpu, #1
-	movne	\rd, \rd, lsl #3
-	addne	\rd, \rd, #0x18
-	moveq	\rd, #8
-.endm
-
-/* returns the ID of the current processor */
-.macro cpu_id, rd
-	mrc	p15, 0, \rd, c0, c0, 5
-	and	\rd, \rd, #0xF
-.endm
-
-/* loads a 32-bit value into a register without a data access */
-.macro mov32, reg, val
-	movw	\reg, #:lower16:\val
-	movt	\reg, #:upper16:\val
-.endm
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
new file mode 100644
index 0000000..e25a7cd
--- /dev/null
+++ b/arch/arm/mach-tegra/sleep.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MACH_TEGRA_SLEEP_H
+#define __MACH_TEGRA_SLEEP_H
+
+#include <mach/iomap.h>
+
+#define TEGRA_ARM_PERIF_VIRT (TEGRA_ARM_PERIF_BASE - IO_CPU_PHYS \
+					+ IO_CPU_VIRT)
+#define TEGRA_FLOW_CTRL_VIRT (TEGRA_FLOW_CTRL_BASE - IO_PPSB_PHYS \
+					+ IO_PPSB_VIRT)
+#define TEGRA_CLK_RESET_VIRT (TEGRA_CLK_RESET_BASE - IO_PPSB_PHYS \
+					+ IO_PPSB_VIRT)
+
+#ifdef __ASSEMBLY__
+/* returns the offset of the flow controller halt register for a cpu */
+.macro cpu_to_halt_reg rd, rcpu
+	cmp	\rcpu, #0
+	subne	\rd, \rcpu, #1
+	movne	\rd, \rd, lsl #3
+	addne	\rd, \rd, #0x14
+	moveq	\rd, #0
+.endm
+
+/* returns the offset of the flow controller csr register for a cpu */
+.macro cpu_to_csr_reg rd, rcpu
+	cmp	\rcpu, #0
+	subne	\rd, \rcpu, #1
+	movne	\rd, \rd, lsl #3
+	addne	\rd, \rd, #0x18
+	moveq	\rd, #8
+.endm
+
+/* returns the ID of the current processor */
+.macro cpu_id, rd
+	mrc	p15, 0, \rd, c0, c0, 5
+	and	\rd, \rd, #0xF
+.endm
+
+/* loads a 32-bit value into a register without a data access */
+.macro mov32, reg, val
+	movw	\reg, #:lower16:\val
+	movt	\reg, #:upper16:\val
+.endm
+
+/* Macro to exit SMP coherency. */
+.macro exit_smp, tmp1, tmp2
+	mrc	p15, 0, \tmp1, c1, c0, 1	@ ACTLR
+	bic	\tmp1, \tmp1, #(1<<6) | (1<<0)	@ clear ACTLR.SMP | ACTLR.FW
+	mcr	p15, 0, \tmp1, c1, c0, 1	@ ACTLR
+	isb
+	cpu_id	\tmp1
+	mov	\tmp1, \tmp1, lsl #2
+	mov	\tmp2, #0xf
+	mov	\tmp2, \tmp2, lsl \tmp1
+	mov32	\tmp1, TEGRA_ARM_PERIF_VIRT + 0xC
+	str	\tmp2, [\tmp1]			@ invalidate SCU tags for CPU
+	dsb
+.endm
+#else
+
+#ifdef CONFIG_HOTPLUG_CPU
+void tegra20_hotplug_init(void);
+void tegra30_hotplug_init(void);
+#else
+static inline void tegra20_hotplug_init(void) {}
+static inline void tegra30_hotplug_init(void) {}
+#endif
+
+#endif
+#endif
diff --git a/arch/arm/mach-tegra/tegra20_clocks.c b/arch/arm/mach-tegra/tegra20_clocks.c
new file mode 100644
index 0000000..ee6922b
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20_clocks.c
@@ -0,0 +1,1606 @@
+/*
+ * arch/arm/mach-tegra/tegra20_clocks.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2010-2012 NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Author:
+ *	Colin Cross <ccross@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/list.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
+#include <linux/clk.h>
+
+#include <mach/iomap.h>
+#include <mach/suspend.h>
+
+#include "clock.h"
+#include "fuse.h"
+#include "tegra2_emc.h"
+#include "tegra_cpu_car.h"
+
+#define RST_DEVICES			0x004
+#define RST_DEVICES_SET			0x300
+#define RST_DEVICES_CLR			0x304
+#define RST_DEVICES_NUM			3
+
+#define CLK_OUT_ENB			0x010
+#define CLK_OUT_ENB_SET			0x320
+#define CLK_OUT_ENB_CLR			0x324
+#define CLK_OUT_ENB_NUM			3
+
+#define CLK_MASK_ARM			0x44
+#define MISC_CLK_ENB			0x48
+
+#define OSC_CTRL			0x50
+#define OSC_CTRL_OSC_FREQ_MASK		(3<<30)
+#define OSC_CTRL_OSC_FREQ_13MHZ		(0<<30)
+#define OSC_CTRL_OSC_FREQ_19_2MHZ	(1<<30)
+#define OSC_CTRL_OSC_FREQ_12MHZ		(2<<30)
+#define OSC_CTRL_OSC_FREQ_26MHZ		(3<<30)
+#define OSC_CTRL_MASK			(0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
+
+#define OSC_FREQ_DET			0x58
+#define OSC_FREQ_DET_TRIG		(1<<31)
+
+#define OSC_FREQ_DET_STATUS		0x5C
+#define OSC_FREQ_DET_BUSY		(1<<31)
+#define OSC_FREQ_DET_CNT_MASK		0xFFFF
+
+#define PERIPH_CLK_SOURCE_I2S1		0x100
+#define PERIPH_CLK_SOURCE_EMC		0x19c
+#define PERIPH_CLK_SOURCE_OSC		0x1fc
+#define PERIPH_CLK_SOURCE_NUM \
+	((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
+
+#define PERIPH_CLK_SOURCE_MASK		(3<<30)
+#define PERIPH_CLK_SOURCE_SHIFT		30
+#define PERIPH_CLK_SOURCE_PWM_MASK	(7<<28)
+#define PERIPH_CLK_SOURCE_PWM_SHIFT	28
+#define PERIPH_CLK_SOURCE_ENABLE	(1<<28)
+#define PERIPH_CLK_SOURCE_DIVU71_MASK	0xFF
+#define PERIPH_CLK_SOURCE_DIVU16_MASK	0xFFFF
+#define PERIPH_CLK_SOURCE_DIV_SHIFT	0
+
+#define SDMMC_CLK_INT_FB_SEL		(1 << 23)
+#define SDMMC_CLK_INT_FB_DLY_SHIFT	16
+#define SDMMC_CLK_INT_FB_DLY_MASK	(0xF << SDMMC_CLK_INT_FB_DLY_SHIFT)
+
+#define PLL_BASE			0x0
+#define PLL_BASE_BYPASS			(1<<31)
+#define PLL_BASE_ENABLE			(1<<30)
+#define PLL_BASE_REF_ENABLE		(1<<29)
+#define PLL_BASE_OVERRIDE		(1<<28)
+#define PLL_BASE_DIVP_MASK		(0x7<<20)
+#define PLL_BASE_DIVP_SHIFT		20
+#define PLL_BASE_DIVN_MASK		(0x3FF<<8)
+#define PLL_BASE_DIVN_SHIFT		8
+#define PLL_BASE_DIVM_MASK		(0x1F)
+#define PLL_BASE_DIVM_SHIFT		0
+
+#define PLL_OUT_RATIO_MASK		(0xFF<<8)
+#define PLL_OUT_RATIO_SHIFT		8
+#define PLL_OUT_OVERRIDE		(1<<2)
+#define PLL_OUT_CLKEN			(1<<1)
+#define PLL_OUT_RESET_DISABLE		(1<<0)
+
+#define PLL_MISC(c) (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
+
+#define PLL_MISC_DCCON_SHIFT		20
+#define PLL_MISC_CPCON_SHIFT		8
+#define PLL_MISC_CPCON_MASK		(0xF<<PLL_MISC_CPCON_SHIFT)
+#define PLL_MISC_LFCON_SHIFT		4
+#define PLL_MISC_LFCON_MASK		(0xF<<PLL_MISC_LFCON_SHIFT)
+#define PLL_MISC_VCOCON_SHIFT		0
+#define PLL_MISC_VCOCON_MASK		(0xF<<PLL_MISC_VCOCON_SHIFT)
+
+#define PLLU_BASE_POST_DIV		(1<<20)
+
+#define PLLD_MISC_CLKENABLE		(1<<30)
+#define PLLD_MISC_DIV_RST		(1<<23)
+#define PLLD_MISC_DCCON_SHIFT		12
+
+#define PLLE_MISC_READY			(1 << 15)
+
+#define PERIPH_CLK_TO_ENB_REG(c)	((c->u.periph.clk_num / 32) * 4)
+#define PERIPH_CLK_TO_ENB_SET_REG(c)	((c->u.periph.clk_num / 32) * 8)
+#define PERIPH_CLK_TO_ENB_BIT(c)	(1 << (c->u.periph.clk_num % 32))
+
+#define SUPER_CLK_MUX			0x00
+#define SUPER_STATE_SHIFT		28
+#define SUPER_STATE_MASK		(0xF << SUPER_STATE_SHIFT)
+#define SUPER_STATE_STANDBY		(0x0 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_IDLE		(0x1 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_RUN			(0x2 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_IRQ			(0x3 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_FIQ			(0x4 << SUPER_STATE_SHIFT)
+#define SUPER_SOURCE_MASK		0xF
+#define	SUPER_FIQ_SOURCE_SHIFT		12
+#define	SUPER_IRQ_SOURCE_SHIFT		8
+#define	SUPER_RUN_SOURCE_SHIFT		4
+#define	SUPER_IDLE_SOURCE_SHIFT		0
+
+#define SUPER_CLK_DIVIDER		0x04
+
+#define BUS_CLK_DISABLE			(1<<3)
+#define BUS_CLK_DIV_MASK		0x3
+
+#define PMC_CTRL			0x0
+ #define PMC_CTRL_BLINK_ENB		(1 << 7)
+
+#define PMC_DPD_PADS_ORIDE		0x1c
+ #define PMC_DPD_PADS_ORIDE_BLINK_ENB	(1 << 20)
+
+#define PMC_BLINK_TIMER_DATA_ON_SHIFT	0
+#define PMC_BLINK_TIMER_DATA_ON_MASK	0x7fff
+#define PMC_BLINK_TIMER_ENB		(1 << 15)
+#define PMC_BLINK_TIMER_DATA_OFF_SHIFT	16
+#define PMC_BLINK_TIMER_DATA_OFF_MASK	0xffff
+
+/* Tegra CPU clock and reset control regs */
+#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX		0x4c
+#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET	0x340
+#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR	0x344
+
+#define CPU_CLOCK(cpu)	(0x1 << (8 + cpu))
+#define CPU_RESET(cpu)	(0x1111ul << (cpu))
+
+static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
+static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+
+/*
+ * Some clocks share a register with other clocks.  Any clock op that
+ * non-atomically modifies a register used by another clock must lock
+ * clock_register_lock first.
+ */
+static DEFINE_SPINLOCK(clock_register_lock);
+
+/*
+ * Some peripheral clocks share an enable bit, so refcount the enable bits
+ * in registers CLK_ENABLE_L, CLK_ENABLE_H, and CLK_ENABLE_U
+ */
+static int tegra_periph_clk_enable_refcount[3 * 32];
+
+#define clk_writel(value, reg) \
+	__raw_writel(value, reg_clk_base + (reg))
+#define clk_readl(reg) \
+	__raw_readl(reg_clk_base + (reg))
+#define pmc_writel(value, reg) \
+	__raw_writel(value, reg_pmc_base + (reg))
+#define pmc_readl(reg) \
+	__raw_readl(reg_pmc_base + (reg))
+
+static unsigned long clk_measure_input_freq(void)
+{
+	u32 clock_autodetect;
+	clk_writel(OSC_FREQ_DET_TRIG | 1, OSC_FREQ_DET);
+	do {} while (clk_readl(OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY);
+	clock_autodetect = clk_readl(OSC_FREQ_DET_STATUS);
+	if (clock_autodetect >= 732 - 3 && clock_autodetect <= 732 + 3) {
+		return 12000000;
+	} else if (clock_autodetect >= 794 - 3 && clock_autodetect <= 794 + 3) {
+		return 13000000;
+	} else if (clock_autodetect >= 1172 - 3 && clock_autodetect <= 1172 + 3) {
+		return 19200000;
+	} else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) {
+		return 26000000;
+	} else {
+		pr_err("%s: Unexpected clock autodetect value %d",
+						__func__, clock_autodetect);
+		BUG();
+		return 0;
+	}
+}
+
+static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate)
+{
+	s64 divider_u71 = parent_rate * 2;
+	divider_u71 += rate - 1;
+	do_div(divider_u71, rate);
+
+	if (divider_u71 - 2 < 0)
+		return 0;
+
+	if (divider_u71 - 2 > 255)
+		return -EINVAL;
+
+	return divider_u71 - 2;
+}
+
+static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
+{
+	s64 divider_u16;
+
+	divider_u16 = parent_rate;
+	divider_u16 += rate - 1;
+	do_div(divider_u16, rate);
+
+	if (divider_u16 - 1 < 0)
+		return 0;
+
+	if (divider_u16 - 1 > 0xFFFF)
+		return -EINVAL;
+
+	return divider_u16 - 1;
+}
+
+static unsigned long tegra_clk_fixed_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	return to_clk_tegra(hw)->fixed_rate;
+}
+
+struct clk_ops tegra_clk_32k_ops = {
+	.recalc_rate = tegra_clk_fixed_recalc_rate,
+};
+
+/* clk_m functions */
+static unsigned long tegra20_clk_m_recalc_rate(struct clk_hw *hw,
+			unsigned long prate)
+{
+	if (!to_clk_tegra(hw)->fixed_rate)
+		to_clk_tegra(hw)->fixed_rate = clk_measure_input_freq();
+	return to_clk_tegra(hw)->fixed_rate;
+}
+
+static void tegra20_clk_m_init(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 osc_ctrl = clk_readl(OSC_CTRL);
+	u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK;
+
+	switch (c->fixed_rate) {
+	case 12000000:
+		auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
+		break;
+	case 13000000:
+		auto_clock_control |= OSC_CTRL_OSC_FREQ_13MHZ;
+		break;
+	case 19200000:
+		auto_clock_control |= OSC_CTRL_OSC_FREQ_19_2MHZ;
+		break;
+	case 26000000:
+		auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ;
+		break;
+	default:
+		BUG();
+	}
+	clk_writel(auto_clock_control, OSC_CTRL);
+}
+
+struct clk_ops tegra_clk_m_ops = {
+	.init = tegra20_clk_m_init,
+	.recalc_rate = tegra20_clk_m_recalc_rate,
+};
+
+/* super clock functions */
+/* "super clocks" on tegra have two-stage muxes and a clock skipping
+ * super divider.  We will ignore the clock skipping divider, since we
+ * can't lower the voltage when using the clock skip, but we can if we
+ * lower the PLL frequency.
+ */
+static int tegra20_super_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+
+	val = clk_readl(c->reg + SUPER_CLK_MUX);
+	BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
+		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
+	c->state = ON;
+	return c->state;
+}
+
+static int tegra20_super_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
+	return 0;
+}
+
+static void tegra20_super_clk_disable(struct clk_hw *hw)
+{
+	pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+	/* oops - don't disable the CPU clock! */
+	BUG();
+}
+
+static u8 tegra20_super_clk_get_parent(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	int val = clk_readl(c->reg + SUPER_CLK_MUX);
+	int source;
+	int shift;
+
+	BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
+		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
+	shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
+		SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
+	source = (val >> shift) & SUPER_SOURCE_MASK;
+	return source;
+}
+
+static int tegra20_super_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg + SUPER_CLK_MUX);
+	int shift;
+
+	BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
+		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
+	shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
+		SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
+	val &= ~(SUPER_SOURCE_MASK << shift);
+	val |= index << shift;
+
+	clk_writel(val, c->reg);
+
+	return 0;
+}
+
+/* FIX ME: Need to switch parents to change the source PLL rate */
+static unsigned long tegra20_super_clk_recalc_rate(struct clk_hw *hw,
+			unsigned long prate)
+{
+	return prate;
+}
+
+static long tegra20_super_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	return *prate;
+}
+
+static int tegra20_super_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	return 0;
+}
+
+struct clk_ops tegra_super_ops = {
+	.is_enabled = tegra20_super_clk_is_enabled,
+	.enable = tegra20_super_clk_enable,
+	.disable = tegra20_super_clk_disable,
+	.set_parent = tegra20_super_clk_set_parent,
+	.get_parent = tegra20_super_clk_get_parent,
+	.set_rate = tegra20_super_clk_set_rate,
+	.round_rate = tegra20_super_clk_round_rate,
+	.recalc_rate = tegra20_super_clk_recalc_rate,
+};
+
+static u8 tegra20_cop_clk_get_parent(struct clk_hw *hw)
+{
+	return 0;
+}
+
+struct clk_ops tegra_cop_ops = {
+	.get_parent = tegra20_cop_clk_get_parent,
+};
+
+/* virtual cop clock functions. Used to acquire the fake 'cop' clock to
+ * reset the COP block (i.e. AVP) */
+void tegra2_cop_clk_reset(struct clk_hw *hw, bool assert)
+{
+	unsigned long reg = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
+
+	pr_debug("%s %s\n", __func__, assert ? "assert" : "deassert");
+	clk_writel(1 << 1, reg);
+}
+
+/* bus clock functions */
+static int tegra20_bus_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg);
+
+	c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON;
+	return c->state;
+}
+
+static int tegra20_bus_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&clock_register_lock, flags);
+
+	val = clk_readl(c->reg);
+	val &= ~(BUS_CLK_DISABLE << c->reg_shift);
+	clk_writel(val, c->reg);
+
+	spin_unlock_irqrestore(&clock_register_lock, flags);
+
+	return 0;
+}
+
+static void tegra20_bus_clk_disable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&clock_register_lock, flags);
+
+	val = clk_readl(c->reg);
+	val |= BUS_CLK_DISABLE << c->reg_shift;
+	clk_writel(val, c->reg);
+
+	spin_unlock_irqrestore(&clock_register_lock, flags);
+}
+
+static unsigned long tegra20_bus_clk_recalc_rate(struct clk_hw *hw,
+			unsigned long prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg);
+	u64 rate = prate;
+
+	c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1;
+	c->mul = 1;
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+	return rate;
+}
+
+static int tegra20_bus_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	int ret = -EINVAL;
+	unsigned long flags;
+	u32 val;
+	int i;
+
+	spin_lock_irqsave(&clock_register_lock, flags);
+
+	val = clk_readl(c->reg);
+	for (i = 1; i <= 4; i++) {
+		if (rate == parent_rate / i) {
+			val &= ~(BUS_CLK_DIV_MASK << c->reg_shift);
+			val |= (i - 1) << c->reg_shift;
+			clk_writel(val, c->reg);
+			c->div = i;
+			c->mul = 1;
+			ret = 0;
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&clock_register_lock, flags);
+
+	return ret;
+}
+
+static long tegra20_bus_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	unsigned long parent_rate = *prate;
+	s64 divider;
+
+	if (rate >= parent_rate)
+		return rate;
+
+	divider = parent_rate;
+	divider += rate - 1;
+	do_div(divider, rate);
+
+	if (divider < 0)
+		return divider;
+
+	if (divider > 4)
+		divider = 4;
+	do_div(parent_rate, divider);
+
+	return parent_rate;
+}
+
+struct clk_ops tegra_bus_ops = {
+	.is_enabled = tegra20_bus_clk_is_enabled,
+	.enable = tegra20_bus_clk_enable,
+	.disable = tegra20_bus_clk_disable,
+	.set_rate = tegra20_bus_clk_set_rate,
+	.round_rate = tegra20_bus_clk_round_rate,
+	.recalc_rate = tegra20_bus_clk_recalc_rate,
+};
+
+/* Blink output functions */
+static int tegra20_blink_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+
+	val = pmc_readl(PMC_CTRL);
+	c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF;
+	return c->state;
+}
+
+static unsigned long tegra20_blink_clk_recalc_rate(struct clk_hw *hw,
+			unsigned long prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = prate;
+	u32 val;
+
+	c->mul = 1;
+	val = pmc_readl(c->reg);
+
+	if (val & PMC_BLINK_TIMER_ENB) {
+		unsigned int on_off;
+
+		on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
+			PMC_BLINK_TIMER_DATA_ON_MASK;
+		val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
+		val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
+		on_off += val;
+		/* each tick in the blink timer is 4 32KHz clocks */
+		c->div = on_off * 4;
+	} else {
+		c->div = 1;
+	}
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+	return rate;
+}
+
+static int tegra20_blink_clk_enable(struct clk_hw *hw)
+{
+	u32 val;
+
+	val = pmc_readl(PMC_DPD_PADS_ORIDE);
+	pmc_writel(val | PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
+
+	val = pmc_readl(PMC_CTRL);
+	pmc_writel(val | PMC_CTRL_BLINK_ENB, PMC_CTRL);
+
+	return 0;
+}
+
+static void tegra20_blink_clk_disable(struct clk_hw *hw)
+{
+	u32 val;
+
+	val = pmc_readl(PMC_CTRL);
+	pmc_writel(val & ~PMC_CTRL_BLINK_ENB, PMC_CTRL);
+
+	val = pmc_readl(PMC_DPD_PADS_ORIDE);
+	pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
+}
+
+static int tegra20_blink_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+
+	if (rate >= parent_rate) {
+		c->div = 1;
+		pmc_writel(0, c->reg);
+	} else {
+		unsigned int on_off;
+		u32 val;
+
+		on_off = DIV_ROUND_UP(parent_rate / 8, rate);
+		c->div = on_off * 8;
+
+		val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) <<
+			PMC_BLINK_TIMER_DATA_ON_SHIFT;
+		on_off &= PMC_BLINK_TIMER_DATA_OFF_MASK;
+		on_off <<= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
+		val |= on_off;
+		val |= PMC_BLINK_TIMER_ENB;
+		pmc_writel(val, c->reg);
+	}
+
+	return 0;
+}
+
+static long tegra20_blink_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	int div;
+	int mul;
+	long round_rate = *prate;
+
+	mul = 1;
+
+	if (rate >= *prate) {
+		div = 1;
+	} else {
+		div = DIV_ROUND_UP(*prate / 8, rate);
+		div *= 8;
+	}
+
+	round_rate *= mul;
+	round_rate += div - 1;
+	do_div(round_rate, div);
+
+	return round_rate;
+}
+
+struct clk_ops tegra_blink_clk_ops = {
+	.is_enabled = tegra20_blink_clk_is_enabled,
+	.enable = tegra20_blink_clk_enable,
+	.disable = tegra20_blink_clk_disable,
+	.set_rate = tegra20_blink_clk_set_rate,
+	.round_rate = tegra20_blink_clk_round_rate,
+	.recalc_rate = tegra20_blink_clk_recalc_rate,
+};
+
+/* PLL Functions */
+static int tegra20_pll_clk_wait_for_lock(struct clk_tegra *c)
+{
+	udelay(c->u.pll.lock_delay);
+	return 0;
+}
+
+static int tegra20_pll_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg + PLL_BASE);
+
+	c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
+	return c->state;
+}
+
+static unsigned long tegra20_pll_clk_recalc_rate(struct clk_hw *hw,
+				unsigned long prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg + PLL_BASE);
+	u64 rate = prate;
+
+	if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
+		const struct clk_pll_freq_table *sel;
+		for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+			if (sel->input_rate == prate &&
+				sel->output_rate == c->u.pll.fixed_rate) {
+				c->mul = sel->n;
+				c->div = sel->m * sel->p;
+				break;
+			}
+		}
+		pr_err("Clock %s has unknown fixed frequency\n",
+			__clk_get_name(hw->clk));
+		BUG();
+	} else if (val & PLL_BASE_BYPASS) {
+		c->mul = 1;
+		c->div = 1;
+	} else {
+		c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
+		c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
+		if (c->flags & PLLU)
+			c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
+		else
+			c->div *= (val & PLL_BASE_DIVP_MASK) ? 2 : 1;
+	}
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+	return rate;
+}
+
+static int tegra20_pll_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+	pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+	val = clk_readl(c->reg + PLL_BASE);
+	val &= ~PLL_BASE_BYPASS;
+	val |= PLL_BASE_ENABLE;
+	clk_writel(val, c->reg + PLL_BASE);
+
+	tegra20_pll_clk_wait_for_lock(c);
+
+	return 0;
+}
+
+static void tegra20_pll_clk_disable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+	pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+	val = clk_readl(c->reg);
+	val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
+	clk_writel(val, c->reg);
+}
+
+static int tegra20_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long input_rate = parent_rate;
+	const struct clk_pll_freq_table *sel;
+	u32 val;
+
+	pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
+
+	if (c->flags & PLL_FIXED) {
+		int ret = 0;
+		if (rate != c->u.pll.fixed_rate) {
+			pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
+				__func__, __clk_get_name(hw->clk),
+				c->u.pll.fixed_rate, rate);
+			ret = -EINVAL;
+		}
+		return ret;
+	}
+
+	for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+		if (sel->input_rate == input_rate && sel->output_rate == rate) {
+			c->mul = sel->n;
+			c->div = sel->m * sel->p;
+
+			val = clk_readl(c->reg + PLL_BASE);
+			if (c->flags & PLL_FIXED)
+				val |= PLL_BASE_OVERRIDE;
+			val &= ~(PLL_BASE_DIVP_MASK | PLL_BASE_DIVN_MASK |
+				 PLL_BASE_DIVM_MASK);
+			val |= (sel->m << PLL_BASE_DIVM_SHIFT) |
+				(sel->n << PLL_BASE_DIVN_SHIFT);
+			BUG_ON(sel->p < 1 || sel->p > 2);
+			if (c->flags & PLLU) {
+				if (sel->p == 1)
+					val |= PLLU_BASE_POST_DIV;
+			} else {
+				if (sel->p == 2)
+					val |= 1 << PLL_BASE_DIVP_SHIFT;
+			}
+			clk_writel(val, c->reg + PLL_BASE);
+
+			if (c->flags & PLL_HAS_CPCON) {
+				val = clk_readl(c->reg + PLL_MISC(c));
+				val &= ~PLL_MISC_CPCON_MASK;
+				val |= sel->cpcon << PLL_MISC_CPCON_SHIFT;
+				clk_writel(val, c->reg + PLL_MISC(c));
+			}
+
+			if (c->state == ON)
+				tegra20_pll_clk_enable(hw);
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static long tegra20_pll_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	const struct clk_pll_freq_table *sel;
+	unsigned long input_rate = *prate;
+	unsigned long output_rate = *prate;
+	int mul;
+	int div;
+
+	if (c->flags & PLL_FIXED)
+		return c->u.pll.fixed_rate;
+
+	for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++)
+		if (sel->input_rate == input_rate && sel->output_rate == rate) {
+			mul = sel->n;
+			div = sel->m * sel->p;
+			break;
+		}
+
+	if (sel->input_rate == 0)
+		return -EINVAL;
+
+	output_rate *= mul;
+	output_rate += div - 1; /* round up */
+	do_div(output_rate, div);
+
+	return output_rate;
+}
+
+struct clk_ops tegra_pll_ops = {
+	.is_enabled = tegra20_pll_clk_is_enabled,
+	.enable = tegra20_pll_clk_enable,
+	.disable = tegra20_pll_clk_disable,
+	.set_rate = tegra20_pll_clk_set_rate,
+	.recalc_rate = tegra20_pll_clk_recalc_rate,
+	.round_rate = tegra20_pll_clk_round_rate,
+};
+
+static void tegra20_pllx_clk_init(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+
+	if (tegra_sku_id == 7)
+		c->max_rate = 750000000;
+}
+
+struct clk_ops tegra_pllx_ops = {
+	.init = tegra20_pllx_clk_init,
+	.is_enabled = tegra20_pll_clk_is_enabled,
+	.enable = tegra20_pll_clk_enable,
+	.disable = tegra20_pll_clk_disable,
+	.set_rate = tegra20_pll_clk_set_rate,
+	.recalc_rate = tegra20_pll_clk_recalc_rate,
+	.round_rate = tegra20_pll_clk_round_rate,
+};
+
+static int tegra20_plle_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+
+	pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+	mdelay(1);
+
+	val = clk_readl(c->reg + PLL_BASE);
+	if (!(val & PLLE_MISC_READY))
+		return -EBUSY;
+
+	val = clk_readl(c->reg + PLL_BASE);
+	val |= PLL_BASE_ENABLE | PLL_BASE_BYPASS;
+	clk_writel(val, c->reg + PLL_BASE);
+
+	return 0;
+}
+
+struct clk_ops tegra_plle_ops = {
+	.is_enabled = tegra20_pll_clk_is_enabled,
+	.enable = tegra20_plle_clk_enable,
+	.set_rate = tegra20_pll_clk_set_rate,
+	.recalc_rate = tegra20_pll_clk_recalc_rate,
+	.round_rate = tegra20_pll_clk_round_rate,
+};
+
+/* Clock divider ops */
+static int tegra20_pll_div_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg);
+
+	val >>= c->reg_shift;
+	c->state = (val & PLL_OUT_CLKEN) ? ON : OFF;
+	if (!(val & PLL_OUT_RESET_DISABLE))
+		c->state = OFF;
+	return c->state;
+}
+
+static unsigned long tegra20_pll_div_clk_recalc_rate(struct clk_hw *hw,
+			unsigned long prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = prate;
+	u32 val = clk_readl(c->reg);
+	u32 divu71;
+
+	val >>= c->reg_shift;
+
+	if (c->flags & DIV_U71) {
+		divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
+		c->div = (divu71 + 2);
+		c->mul = 2;
+	} else if (c->flags & DIV_2) {
+		c->div = 2;
+		c->mul = 1;
+	} else {
+		c->div = 1;
+		c->mul = 1;
+	}
+
+	rate *= c->mul;
+	rate += c->div - 1; /* round up */
+	do_div(rate, c->div);
+
+	return rate;
+}
+
+static int tegra20_pll_div_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long flags;
+	u32 new_val;
+	u32 val;
+
+	pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
+
+	if (c->flags & DIV_U71) {
+		spin_lock_irqsave(&clock_register_lock, flags);
+		val = clk_readl(c->reg);
+		new_val = val >> c->reg_shift;
+		new_val &= 0xFFFF;
+
+		new_val |= PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE;
+
+		val &= ~(0xFFFF << c->reg_shift);
+		val |= new_val << c->reg_shift;
+		clk_writel(val, c->reg);
+		spin_unlock_irqrestore(&clock_register_lock, flags);
+		return 0;
+	} else if (c->flags & DIV_2) {
+		BUG_ON(!(c->flags & PLLD));
+		spin_lock_irqsave(&clock_register_lock, flags);
+		val = clk_readl(c->reg);
+		val &= ~PLLD_MISC_DIV_RST;
+		clk_writel(val, c->reg);
+		spin_unlock_irqrestore(&clock_register_lock, flags);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static void tegra20_pll_div_clk_disable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long flags;
+	u32 new_val;
+	u32 val;
+
+	pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
+
+	if (c->flags & DIV_U71) {
+		spin_lock_irqsave(&clock_register_lock, flags);
+		val = clk_readl(c->reg);
+		new_val = val >> c->reg_shift;
+		new_val &= 0xFFFF;
+
+		new_val &= ~(PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE);
+
+		val &= ~(0xFFFF << c->reg_shift);
+		val |= new_val << c->reg_shift;
+		clk_writel(val, c->reg);
+		spin_unlock_irqrestore(&clock_register_lock, flags);
+	} else if (c->flags & DIV_2) {
+		BUG_ON(!(c->flags & PLLD));
+		spin_lock_irqsave(&clock_register_lock, flags);
+		val = clk_readl(c->reg);
+		val |= PLLD_MISC_DIV_RST;
+		clk_writel(val, c->reg);
+		spin_unlock_irqrestore(&clock_register_lock, flags);
+	}
+}
+
+static int tegra20_pll_div_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long flags;
+	int divider_u71;
+	u32 new_val;
+	u32 val;
+
+	pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
+
+	if (c->flags & DIV_U71) {
+		divider_u71 = clk_div71_get_divider(parent_rate, rate);
+		if (divider_u71 >= 0) {
+			spin_lock_irqsave(&clock_register_lock, flags);
+			val = clk_readl(c->reg);
+			new_val = val >> c->reg_shift;
+			new_val &= 0xFFFF;
+			if (c->flags & DIV_U71_FIXED)
+				new_val |= PLL_OUT_OVERRIDE;
+			new_val &= ~PLL_OUT_RATIO_MASK;
+			new_val |= divider_u71 << PLL_OUT_RATIO_SHIFT;
+
+			val &= ~(0xFFFF << c->reg_shift);
+			val |= new_val << c->reg_shift;
+			clk_writel(val, c->reg);
+			c->div = divider_u71 + 2;
+			c->mul = 2;
+			spin_unlock_irqrestore(&clock_register_lock, flags);
+			return 0;
+		}
+	} else if (c->flags & DIV_2) {
+		if (parent_rate == rate * 2)
+			return 0;
+	}
+	return -EINVAL;
+}
+
+static long tegra20_pll_div_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long parent_rate = *prate;
+	int divider;
+
+	pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
+
+	if (c->flags & DIV_U71) {
+		divider = clk_div71_get_divider(parent_rate, rate);
+		if (divider < 0)
+			return divider;
+		return DIV_ROUND_UP(parent_rate * 2, divider + 2);
+	} else if (c->flags & DIV_2) {
+		return DIV_ROUND_UP(parent_rate, 2);
+	}
+	return -EINVAL;
+}
+
+struct clk_ops tegra_pll_div_ops = {
+	.is_enabled = tegra20_pll_div_clk_is_enabled,
+	.enable = tegra20_pll_div_clk_enable,
+	.disable = tegra20_pll_div_clk_disable,
+	.set_rate = tegra20_pll_div_clk_set_rate,
+	.round_rate = tegra20_pll_div_clk_round_rate,
+	.recalc_rate = tegra20_pll_div_clk_recalc_rate,
+};
+
+/* Periph clk ops */
+
+static int tegra20_periph_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+
+	c->state = ON;
+
+	if (!c->u.periph.clk_num)
+		goto out;
+
+	if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
+			PERIPH_CLK_TO_ENB_BIT(c)))
+		c->state = OFF;
+
+	if (!(c->flags & PERIPH_NO_RESET))
+		if (clk_readl(RST_DEVICES + PERIPH_CLK_TO_ENB_REG(c)) &
+				PERIPH_CLK_TO_ENB_BIT(c))
+			c->state = OFF;
+
+out:
+	return c->state;
+}
+
+static int tegra20_periph_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long flags;
+	u32 val;
+
+	pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+	if (!c->u.periph.clk_num)
+		return 0;
+
+	tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
+	if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1)
+		return 0;
+
+	spin_lock_irqsave(&clock_register_lock, flags);
+
+	clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+		CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
+	if (!(c->flags & PERIPH_NO_RESET) && !(c->flags & PERIPH_MANUAL_RESET))
+		clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+			RST_DEVICES_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
+	if (c->flags & PERIPH_EMC_ENB) {
+		/* The EMC peripheral clock has 2 extra enable bits */
+		/* FIXME: Do they need to be disabled? */
+		val = clk_readl(c->reg);
+		val |= 0x3 << 24;
+		clk_writel(val, c->reg);
+	}
+
+	spin_unlock_irqrestore(&clock_register_lock, flags);
+
+	return 0;
+}
+
+static void tegra20_periph_clk_disable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long flags;
+
+	pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+	if (!c->u.periph.clk_num)
+		return;
+
+	tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
+
+	if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 0)
+		return;
+
+	spin_lock_irqsave(&clock_register_lock, flags);
+
+	clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+		CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
+
+	spin_unlock_irqrestore(&clock_register_lock, flags);
+}
+
+void tegra2_periph_clk_reset(struct clk_hw *hw, bool assert)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long base = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
+
+	pr_debug("%s %s on clock %s\n", __func__,
+		assert ? "assert" : "deassert", __clk_get_name(hw->clk));
+
+	BUG_ON(!c->u.periph.clk_num);
+
+	if (!(c->flags & PERIPH_NO_RESET))
+		clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+			   base + PERIPH_CLK_TO_ENB_SET_REG(c));
+}
+
+static int tegra20_periph_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+	u32 mask;
+	u32 shift;
+
+	pr_debug("%s: %s %d\n", __func__, __clk_get_name(hw->clk), index);
+
+	if (c->flags & MUX_PWM) {
+		shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
+		mask = PERIPH_CLK_SOURCE_PWM_MASK;
+	} else {
+		shift = PERIPH_CLK_SOURCE_SHIFT;
+		mask = PERIPH_CLK_SOURCE_MASK;
+	}
+
+	val = clk_readl(c->reg);
+	val &= ~mask;
+	val |= (index) << shift;
+
+	clk_writel(val, c->reg);
+
+	return 0;
+}
+
+static u8 tegra20_periph_clk_get_parent(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg);
+	u32 mask;
+	u32 shift;
+
+	if (c->flags & MUX_PWM) {
+		shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
+		mask = PERIPH_CLK_SOURCE_PWM_MASK;
+	} else {
+		shift = PERIPH_CLK_SOURCE_SHIFT;
+		mask = PERIPH_CLK_SOURCE_MASK;
+	}
+
+	if (c->flags & MUX)
+		return (val & mask) >> shift;
+	else
+		return 0;
+}
+
+static unsigned long tegra20_periph_clk_recalc_rate(struct clk_hw *hw,
+			unsigned long prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long rate = prate;
+	u32 val = clk_readl(c->reg);
+
+	if (c->flags & DIV_U71) {
+		u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
+		c->div = divu71 + 2;
+		c->mul = 2;
+	} else if (c->flags & DIV_U16) {
+		u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
+		c->div = divu16 + 1;
+		c->mul = 1;
+	} else {
+		c->div = 1;
+		c->mul = 1;
+		return rate;
+	}
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+
+	return rate;
+}
+
+static int tegra20_periph_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+	int divider;
+
+	val = clk_readl(c->reg);
+
+	if (c->flags & DIV_U71) {
+		divider = clk_div71_get_divider(parent_rate, rate);
+
+		if (divider >= 0) {
+			val = clk_readl(c->reg);
+			val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
+			val |= divider;
+			clk_writel(val, c->reg);
+			c->div = divider + 2;
+			c->mul = 2;
+			return 0;
+		}
+	} else if (c->flags & DIV_U16) {
+		divider = clk_div16_get_divider(parent_rate, rate);
+		if (divider >= 0) {
+			val = clk_readl(c->reg);
+			val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
+			val |= divider;
+			clk_writel(val, c->reg);
+			c->div = divider + 1;
+			c->mul = 1;
+			return 0;
+		}
+	} else if (parent_rate <= rate) {
+		c->div = 1;
+		c->mul = 1;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static long tegra20_periph_clk_round_rate(struct clk_hw *hw,
+	unsigned long rate, unsigned long *prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
+	int divider;
+
+	pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
+
+	if (prate)
+		parent_rate = *prate;
+
+	if (c->flags & DIV_U71) {
+		divider = clk_div71_get_divider(parent_rate, rate);
+		if (divider < 0)
+			return divider;
+
+		return DIV_ROUND_UP(parent_rate * 2, divider + 2);
+	} else if (c->flags & DIV_U16) {
+		divider = clk_div16_get_divider(parent_rate, rate);
+		if (divider < 0)
+			return divider;
+		return DIV_ROUND_UP(parent_rate, divider + 1);
+	}
+	return -EINVAL;
+}
+
+struct clk_ops tegra_periph_clk_ops = {
+	.is_enabled = tegra20_periph_clk_is_enabled,
+	.enable = tegra20_periph_clk_enable,
+	.disable = tegra20_periph_clk_disable,
+	.set_parent = tegra20_periph_clk_set_parent,
+	.get_parent = tegra20_periph_clk_get_parent,
+	.set_rate = tegra20_periph_clk_set_rate,
+	.round_rate = tegra20_periph_clk_round_rate,
+	.recalc_rate = tegra20_periph_clk_recalc_rate,
+};
+
+/* External memory controller clock ops */
+static void tegra20_emc_clk_init(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	c->max_rate = __clk_get_rate(hw->clk);
+}
+
+static long tegra20_emc_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	long emc_rate;
+	long clk_rate;
+
+	/*
+	 * The slowest entry in the EMC clock table that is at least as
+	 * fast as rate.
+	 */
+	emc_rate = tegra_emc_round_rate(rate);
+	if (emc_rate < 0)
+		return c->max_rate;
+
+	/*
+	 * The fastest rate the PLL will generate that is at most the
+	 * requested rate.
+	 */
+	clk_rate = tegra20_periph_clk_round_rate(hw, emc_rate, NULL);
+
+	/*
+	 * If this fails, and emc_rate > clk_rate, it's because the maximum
+	 * rate in the EMC tables is larger than the maximum rate of the EMC
+	 * clock. The EMC clock's max rate is the rate it was running when the
+	 * kernel booted. Such a mismatch is probably due to using the wrong
+	 * BCT, i.e. using a Tegra20 BCT with an EMC table written for Tegra25.
+	 */
+	WARN_ONCE(emc_rate != clk_rate,
+		"emc_rate %ld != clk_rate %ld",
+		emc_rate, clk_rate);
+
+	return emc_rate;
+}
+
+static int tegra20_emc_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	int ret;
+
+	/*
+	 * The Tegra2 memory controller has an interlock with the clock
+	 * block that allows memory shadowed registers to be updated,
+	 * and then transfer them to the main registers at the same
+	 * time as the clock update without glitches.
+	 */
+	ret = tegra_emc_set_rate(rate);
+	if (ret < 0)
+		return ret;
+
+	ret = tegra20_periph_clk_set_rate(hw, rate, parent_rate);
+	udelay(1);
+
+	return ret;
+}
+
+struct clk_ops tegra_emc_clk_ops = {
+	.init = tegra20_emc_clk_init,
+	.is_enabled = tegra20_periph_clk_is_enabled,
+	.enable = tegra20_periph_clk_enable,
+	.disable = tegra20_periph_clk_disable,
+	.set_parent = tegra20_periph_clk_set_parent,
+	.get_parent = tegra20_periph_clk_get_parent,
+	.set_rate = tegra20_emc_clk_set_rate,
+	.round_rate = tegra20_emc_clk_round_rate,
+	.recalc_rate = tegra20_periph_clk_recalc_rate,
+};
+
+/* Clock doubler ops */
+static int tegra20_clk_double_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+
+	c->state = ON;
+
+	if (!c->u.periph.clk_num)
+		goto out;
+
+	if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
+			PERIPH_CLK_TO_ENB_BIT(c)))
+		c->state = OFF;
+
+out:
+	return c->state;
+};
+
+static unsigned long tegra20_clk_double_recalc_rate(struct clk_hw *hw,
+			unsigned long prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = prate;
+
+	c->mul = 2;
+	c->div = 1;
+
+	rate *= c->mul;
+	rate += c->div - 1; /* round up */
+	do_div(rate, c->div);
+
+	return rate;
+}
+
+static long tegra20_clk_double_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	unsigned long output_rate = *prate;
+
+	do_div(output_rate, 2);
+	return output_rate;
+}
+
+static int tegra20_clk_double_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	if (rate != 2 * parent_rate)
+		return -EINVAL;
+	return 0;
+}
+
+struct clk_ops tegra_clk_double_ops = {
+	.is_enabled = tegra20_clk_double_is_enabled,
+	.enable = tegra20_periph_clk_enable,
+	.disable = tegra20_periph_clk_disable,
+	.set_rate = tegra20_clk_double_set_rate,
+	.recalc_rate = tegra20_clk_double_recalc_rate,
+	.round_rate = tegra20_clk_double_round_rate,
+};
+
+/* Audio sync clock ops */
+static int tegra20_audio_sync_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg);
+
+	c->state = (val & (1<<4)) ? OFF : ON;
+	return c->state;
+}
+
+static int tegra20_audio_sync_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+
+	clk_writel(0, c->reg);
+	return 0;
+}
+
+static void tegra20_audio_sync_clk_disable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	clk_writel(1, c->reg);
+}
+
+static u8 tegra20_audio_sync_clk_get_parent(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg);
+	int source;
+
+	source = val & 0xf;
+	return source;
+}
+
+static int tegra20_audio_sync_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+
+	val = clk_readl(c->reg);
+	val &= ~0xf;
+	val |= index;
+
+	clk_writel(val, c->reg);
+
+	return 0;
+}
+
+struct clk_ops tegra_audio_sync_clk_ops = {
+	.is_enabled = tegra20_audio_sync_clk_is_enabled,
+	.enable = tegra20_audio_sync_clk_enable,
+	.disable = tegra20_audio_sync_clk_disable,
+	.set_parent = tegra20_audio_sync_clk_set_parent,
+	.get_parent = tegra20_audio_sync_clk_get_parent,
+};
+
+/* cdev1 and cdev2 (dap_mclk1 and dap_mclk2) ops */
+
+static int tegra20_cdev_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	/* We could un-tristate the cdev1 or cdev2 pingroup here; this is
+	 * currently done in the pinmux code. */
+	c->state = ON;
+
+	BUG_ON(!c->u.periph.clk_num);
+
+	if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
+			PERIPH_CLK_TO_ENB_BIT(c)))
+		c->state = OFF;
+	return c->state;
+}
+
+static int tegra20_cdev_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	BUG_ON(!c->u.periph.clk_num);
+
+	clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+		CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
+	return 0;
+}
+
+static void tegra20_cdev_clk_disable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	BUG_ON(!c->u.periph.clk_num);
+
+	clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+		CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
+}
+
+static unsigned long tegra20_cdev_recalc_rate(struct clk_hw *hw,
+			unsigned long prate)
+{
+	return to_clk_tegra(hw)->fixed_rate;
+}
+
+struct clk_ops tegra_cdev_clk_ops = {
+	.is_enabled = tegra20_cdev_clk_is_enabled,
+	.enable = tegra20_cdev_clk_enable,
+	.disable = tegra20_cdev_clk_disable,
+	.recalc_rate = tegra20_cdev_recalc_rate,
+};
+
+/* Tegra20 CPU clock and reset control functions */
+static void tegra20_wait_cpu_in_reset(u32 cpu)
+{
+	unsigned int reg;
+
+	do {
+		reg = readl(reg_clk_base +
+			    TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
+		cpu_relax();
+	} while (!(reg & (1 << cpu)));	/* check CPU been reset or not */
+
+	return;
+}
+
+static void tegra20_put_cpu_in_reset(u32 cpu)
+{
+	writel(CPU_RESET(cpu),
+	       reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
+	dmb();
+}
+
+static void tegra20_cpu_out_of_reset(u32 cpu)
+{
+	writel(CPU_RESET(cpu),
+	       reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
+	wmb();
+}
+
+static void tegra20_enable_cpu_clock(u32 cpu)
+{
+	unsigned int reg;
+
+	reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+	writel(reg & ~CPU_CLOCK(cpu),
+	       reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+	barrier();
+	reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+}
+
+static void tegra20_disable_cpu_clock(u32 cpu)
+{
+	unsigned int reg;
+
+	reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+	writel(reg | CPU_CLOCK(cpu),
+	       reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+}
+
+static struct tegra_cpu_car_ops tegra20_cpu_car_ops = {
+	.wait_for_reset	= tegra20_wait_cpu_in_reset,
+	.put_in_reset	= tegra20_put_cpu_in_reset,
+	.out_of_reset	= tegra20_cpu_out_of_reset,
+	.enable_clock	= tegra20_enable_cpu_clock,
+	.disable_clock	= tegra20_disable_cpu_clock,
+};
+
+void __init tegra20_cpu_car_ops_init(void)
+{
+	tegra_cpu_car_ops = &tegra20_cpu_car_ops;
+}
diff --git a/arch/arm/mach-tegra/tegra20_clocks.h b/arch/arm/mach-tegra/tegra20_clocks.h
new file mode 100644
index 0000000..0e42ec0
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20_clocks.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MACH_TEGRA20_CLOCK_H
+#define __MACH_TEGRA20_CLOCK_H
+
+extern struct clk_ops tegra_clk_32k_ops;
+extern struct clk_ops tegra_pll_ops;
+extern struct clk_ops tegra_clk_m_ops;
+extern struct clk_ops tegra_pll_div_ops;
+extern struct clk_ops tegra_pllx_ops;
+extern struct clk_ops tegra_plle_ops;
+extern struct clk_ops tegra_clk_double_ops;
+extern struct clk_ops tegra_cdev_clk_ops;
+extern struct clk_ops tegra_audio_sync_clk_ops;
+extern struct clk_ops tegra_super_ops;
+extern struct clk_ops tegra_cpu_ops;
+extern struct clk_ops tegra_cop_ops;
+extern struct clk_ops tegra_bus_ops;
+extern struct clk_ops tegra_blink_clk_ops;
+extern struct clk_ops tegra_emc_clk_ops;
+extern struct clk_ops tegra_periph_clk_ops;
+extern struct clk_ops tegra_clk_shared_bus_ops;
+
+void tegra2_periph_clk_reset(struct clk_hw *hw, bool assert);
+void tegra2_cop_clk_reset(struct clk_hw *hw, bool assert);
+
+#endif
diff --git a/arch/arm/mach-tegra/tegra20_clocks_data.c b/arch/arm/mach-tegra/tegra20_clocks_data.c
new file mode 100644
index 0000000..b9cb82b
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20_clocks_data.c
@@ -0,0 +1,1111 @@
+/*
+ * arch/arm/mach-tegra/tegra2_clocks.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2012 NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Author:
+ *	Colin Cross <ccross@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/clk-private.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <mach/iomap.h>
+#include <mach/suspend.h>
+
+#include "clock.h"
+#include "fuse.h"
+#include "tegra2_emc.h"
+#include "tegra20_clocks.h"
+#include "tegra_cpu_car.h"
+
+/* Clock definitions */
+
+#define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags,		\
+		   _parent_names, _parents, _parent)		\
+	static struct clk tegra_##_name = {			\
+		.hw = &tegra_##_name##_hw.hw,			\
+		.name = #_name,					\
+		.rate = _rate,					\
+		.ops = _ops,					\
+		.flags = _flags,				\
+		.parent_names = _parent_names,			\
+		.parents = _parents,				\
+		.num_parents = ARRAY_SIZE(_parent_names),	\
+		.parent = _parent,				\
+	};
+
+static struct clk tegra_clk_32k;
+static struct clk_tegra tegra_clk_32k_hw = {
+	.hw = {
+		.clk = &tegra_clk_32k,
+	},
+	.fixed_rate = 32768,
+};
+
+static struct clk tegra_clk_32k = {
+	.name = "clk_32k",
+	.rate = 32768,
+	.ops = &tegra_clk_32k_ops,
+	.hw = &tegra_clk_32k_hw.hw,
+	.flags = CLK_IS_ROOT,
+};
+
+static struct clk tegra_clk_m;
+static struct clk_tegra tegra_clk_m_hw = {
+	.hw = {
+		.clk = &tegra_clk_m,
+	},
+	.flags = ENABLE_ON_INIT,
+	.reg = 0x1fc,
+	.reg_shift = 28,
+	.max_rate = 26000000,
+	.fixed_rate = 0,
+};
+
+static struct clk tegra_clk_m = {
+	.name = "clk_m",
+	.ops = &tegra_clk_m_ops,
+	.hw = &tegra_clk_m_hw.hw,
+	.flags = CLK_IS_ROOT,
+};
+
+#define DEFINE_PLL(_name, _flags, _reg, _max_rate, _input_min,	\
+		   _input_max, _cf_min, _cf_max, _vco_min,	\
+		   _vco_max, _freq_table, _lock_delay, _ops,	\
+		   _fixed_rate, _parent)			\
+	static const char *tegra_##_name##_parent_names[] = {	\
+		#_parent,					\
+	};							\
+	static struct clk *tegra_##_name##_parents[] = {	\
+		&tegra_##_parent,				\
+	};							\
+	static struct clk tegra_##_name;			\
+	static struct clk_tegra tegra_##_name##_hw = {		\
+		.hw = {						\
+			.clk = &tegra_##_name,			\
+		},						\
+		.flags = _flags,				\
+		.reg = _reg,					\
+		.max_rate = _max_rate,				\
+		.u.pll = {					\
+			.input_min = _input_min,		\
+			.input_max = _input_max,		\
+			.cf_min = _cf_min,			\
+			.cf_max = _cf_max,			\
+			.vco_min = _vco_min,			\
+			.vco_max = _vco_max,			\
+			.freq_table = _freq_table,		\
+			.lock_delay = _lock_delay,		\
+			.fixed_rate = _fixed_rate,		\
+		},						\
+	};							\
+	static struct clk tegra_##_name = {			\
+		.name = #_name,					\
+		.ops = &_ops,					\
+		.hw = &tegra_##_name##_hw.hw,			\
+		.parent = &tegra_##_parent,			\
+		.parent_names = tegra_##_name##_parent_names,	\
+		.parents = tegra_##_name##_parents,		\
+		.num_parents = 1,				\
+	};
+
+#define DEFINE_PLL_OUT(_name, _flags, _reg, _reg_shift,		\
+		_max_rate, _ops, _parent, _clk_flags)		\
+	static const char *tegra_##_name##_parent_names[] = {	\
+		#_parent,					\
+	};							\
+	static struct clk *tegra_##_name##_parents[] = {	\
+		&tegra_##_parent,				\
+	};							\
+	static struct clk tegra_##_name;			\
+	static struct clk_tegra tegra_##_name##_hw = {		\
+		.hw = {						\
+			.clk = &tegra_##_name,			\
+		},						\
+		.flags = _flags,				\
+		.reg = _reg,					\
+		.max_rate = _max_rate,				\
+		.reg_shift = _reg_shift,			\
+	};							\
+	static struct clk tegra_##_name = {			\
+		.name = #_name,					\
+		.ops = &tegra_pll_div_ops,			\
+		.hw = &tegra_##_name##_hw.hw,			\
+		.parent = &tegra_##_parent,			\
+		.parent_names = tegra_##_name##_parent_names,	\
+		.parents = tegra_##_name##_parents,		\
+		.num_parents = 1,				\
+		.flags = _clk_flags,				\
+	};
+
+
+static struct clk_pll_freq_table tegra_pll_s_freq_table[] = {
+	{32768, 12000000, 366, 1, 1, 0},
+	{32768, 13000000, 397, 1, 1, 0},
+	{32768, 19200000, 586, 1, 1, 0},
+	{32768, 26000000, 793, 1, 1, 0},
+	{0, 0, 0, 0, 0, 0},
+};
+
+DEFINE_PLL(pll_s, PLL_ALT_MISC_REG, 0xf0, 26000000, 32768, 32768, 0,
+		0, 12000000, 26000000, tegra_pll_s_freq_table, 300,
+		tegra_pll_ops, 0, clk_32k);
+
+static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
+	{ 12000000, 600000000, 600, 12, 1, 8 },
+	{ 13000000, 600000000, 600, 13, 1, 8 },
+	{ 19200000, 600000000, 500, 16, 1, 6 },
+	{ 26000000, 600000000, 600, 26, 1, 8 },
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_c, PLL_HAS_CPCON, 0x80, 600000000, 2000000, 31000000, 1000000,
+		6000000, 20000000, 1400000000, tegra_pll_c_freq_table, 300,
+		tegra_pll_ops, 0, clk_m);
+
+DEFINE_PLL_OUT(pll_c_out1, DIV_U71, 0x84, 0, 600000000,
+		tegra_pll_div_ops, pll_c, 0);
+
+static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
+	{ 12000000, 666000000, 666, 12, 1, 8},
+	{ 13000000, 666000000, 666, 13, 1, 8},
+	{ 19200000, 666000000, 555, 16, 1, 8},
+	{ 26000000, 666000000, 666, 26, 1, 8},
+	{ 12000000, 600000000, 600, 12, 1, 8},
+	{ 13000000, 600000000, 600, 13, 1, 8},
+	{ 19200000, 600000000, 375, 12, 1, 6},
+	{ 26000000, 600000000, 600, 26, 1, 8},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_m, PLL_HAS_CPCON, 0x90, 800000000, 2000000, 31000000, 1000000,
+		6000000, 20000000, 1200000000, tegra_pll_m_freq_table, 300,
+		tegra_pll_ops, 0, clk_m);
+
+DEFINE_PLL_OUT(pll_m_out1, DIV_U71, 0x94, 0, 600000000,
+		tegra_pll_div_ops, pll_m, 0);
+
+static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
+	{ 12000000, 216000000, 432, 12, 2, 8},
+	{ 13000000, 216000000, 432, 13, 2, 8},
+	{ 19200000, 216000000, 90,   4, 2, 1},
+	{ 26000000, 216000000, 432, 26, 2, 8},
+	{ 12000000, 432000000, 432, 12, 1, 8},
+	{ 13000000, 432000000, 432, 13, 1, 8},
+	{ 19200000, 432000000, 90,   4, 1, 1},
+	{ 26000000, 432000000, 432, 26, 1, 8},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+
+DEFINE_PLL(pll_p, ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON, 0xa0, 432000000,
+		2000000, 31000000, 1000000, 6000000, 20000000, 1400000000,
+		tegra_pll_p_freq_table, 300, tegra_pll_ops, 216000000, clk_m);
+
+DEFINE_PLL_OUT(pll_p_out1, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, 0,
+		432000000, tegra_pll_div_ops, pll_p, 0);
+DEFINE_PLL_OUT(pll_p_out2, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, 16,
+		432000000, tegra_pll_div_ops, pll_p, 0);
+DEFINE_PLL_OUT(pll_p_out3, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, 0,
+		432000000, tegra_pll_div_ops, pll_p, 0);
+DEFINE_PLL_OUT(pll_p_out4, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, 16,
+		432000000, tegra_pll_div_ops, pll_p, 0);
+
+static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
+	{ 28800000, 56448000, 49, 25, 1, 1},
+	{ 28800000, 73728000, 64, 25, 1, 1},
+	{ 28800000, 24000000,  5,  6, 1, 1},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_a, PLL_HAS_CPCON, 0xb0, 73728000, 2000000, 31000000, 1000000,
+		6000000, 20000000, 1400000000, tegra_pll_a_freq_table, 300,
+		tegra_pll_ops, 0, pll_p_out1);
+
+DEFINE_PLL_OUT(pll_a_out0, DIV_U71, 0xb4, 0, 73728000,
+		tegra_pll_div_ops, pll_a, 0);
+
+static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
+	{ 12000000, 216000000, 216, 12, 1, 4},
+	{ 13000000, 216000000, 216, 13, 1, 4},
+	{ 19200000, 216000000, 135, 12, 1, 3},
+	{ 26000000, 216000000, 216, 26, 1, 4},
+
+	{ 12000000, 594000000, 594, 12, 1, 8},
+	{ 13000000, 594000000, 594, 13, 1, 8},
+	{ 19200000, 594000000, 495, 16, 1, 8},
+	{ 26000000, 594000000, 594, 26, 1, 8},
+
+	{ 12000000, 1000000000, 1000, 12, 1, 12},
+	{ 13000000, 1000000000, 1000, 13, 1, 12},
+	{ 19200000, 1000000000, 625,  12, 1, 8},
+	{ 26000000, 1000000000, 1000, 26, 1, 12},
+
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_d, PLL_HAS_CPCON | PLLD, 0xd0, 1000000000, 2000000, 40000000,
+		1000000, 6000000, 40000000, 1000000000, tegra_pll_d_freq_table,
+		1000, tegra_pll_ops, 0, clk_m);
+
+DEFINE_PLL_OUT(pll_d_out0, DIV_2 | PLLD, 0, 0, 500000000,
+		tegra_pll_div_ops, pll_d, CLK_SET_RATE_PARENT);
+
+static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
+	{ 12000000, 480000000, 960, 12, 2, 0},
+	{ 13000000, 480000000, 960, 13, 2, 0},
+	{ 19200000, 480000000, 200, 4,  2, 0},
+	{ 26000000, 480000000, 960, 26, 2, 0},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_u, PLLU, 0xc0, 480000000, 2000000, 40000000, 1000000, 6000000,
+		48000000, 960000000, tegra_pll_u_freq_table, 1000,
+		tegra_pll_ops, 0, clk_m);
+
+static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
+	/* 1 GHz */
+	{ 12000000, 1000000000, 1000, 12, 1, 12},
+	{ 13000000, 1000000000, 1000, 13, 1, 12},
+	{ 19200000, 1000000000, 625,  12, 1, 8},
+	{ 26000000, 1000000000, 1000, 26, 1, 12},
+
+	/* 912 MHz */
+	{ 12000000, 912000000,  912,  12, 1, 12},
+	{ 13000000, 912000000,  912,  13, 1, 12},
+	{ 19200000, 912000000,  760,  16, 1, 8},
+	{ 26000000, 912000000,  912,  26, 1, 12},
+
+	/* 816 MHz */
+	{ 12000000, 816000000,  816,  12, 1, 12},
+	{ 13000000, 816000000,  816,  13, 1, 12},
+	{ 19200000, 816000000,  680,  16, 1, 8},
+	{ 26000000, 816000000,  816,  26, 1, 12},
+
+	/* 760 MHz */
+	{ 12000000, 760000000,  760,  12, 1, 12},
+	{ 13000000, 760000000,  760,  13, 1, 12},
+	{ 19200000, 760000000,  950,  24, 1, 8},
+	{ 26000000, 760000000,  760,  26, 1, 12},
+
+	/* 750 MHz */
+	{ 12000000, 750000000,  750,  12, 1, 12},
+	{ 13000000, 750000000,  750,  13, 1, 12},
+	{ 19200000, 750000000,  625,  16, 1, 8},
+	{ 26000000, 750000000,  750,  26, 1, 12},
+
+	/* 608 MHz */
+	{ 12000000, 608000000,  608,  12, 1, 12},
+	{ 13000000, 608000000,  608,  13, 1, 12},
+	{ 19200000, 608000000,  380,  12, 1, 8},
+	{ 26000000, 608000000,  608,  26, 1, 12},
+
+	/* 456 MHz */
+	{ 12000000, 456000000,  456,  12, 1, 12},
+	{ 13000000, 456000000,  456,  13, 1, 12},
+	{ 19200000, 456000000,  380,  16, 1, 8},
+	{ 26000000, 456000000,  456,  26, 1, 12},
+
+	/* 312 MHz */
+	{ 12000000, 312000000,  312,  12, 1, 12},
+	{ 13000000, 312000000,  312,  13, 1, 12},
+	{ 19200000, 312000000,  260,  16, 1, 8},
+	{ 26000000, 312000000,  312,  26, 1, 12},
+
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_x, PLL_HAS_CPCON | PLL_ALT_MISC_REG, 0xe0, 1000000000, 2000000,
+		31000000, 1000000, 6000000, 20000000, 1200000000,
+		tegra_pll_x_freq_table, 300, tegra_pllx_ops, 0, clk_m);
+
+static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
+	{ 12000000, 100000000,  200,  24, 1, 0 },
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_e, PLL_ALT_MISC_REG, 0xe8, 100000000, 12000000, 12000000, 0, 0,
+		0, 0, tegra_pll_e_freq_table, 0, tegra_plle_ops, 0, clk_m);
+
+static const char *tegra_common_parent_names[] = {
+	"clk_m",
+};
+
+static struct clk *tegra_common_parents[] = {
+	&tegra_clk_m,
+};
+
+static struct clk tegra_clk_d;
+static struct clk_tegra tegra_clk_d_hw = {
+	.hw = {
+		.clk = &tegra_clk_d,
+	},
+	.flags = PERIPH_NO_RESET,
+	.reg = 0x34,
+	.reg_shift = 12,
+	.max_rate = 52000000,
+	.u.periph = {
+		.clk_num = 90,
+	},
+};
+
+static struct clk tegra_clk_d = {
+	.name = "clk_d",
+	.hw = &tegra_clk_d_hw.hw,
+	.ops = &tegra_clk_double_ops,
+	.parent = &tegra_clk_m,
+	.parent_names = tegra_common_parent_names,
+	.parents = tegra_common_parents,
+	.num_parents = ARRAY_SIZE(tegra_common_parent_names),
+};
+
+static struct clk tegra_cdev1;
+static struct clk_tegra tegra_cdev1_hw = {
+	.hw = {
+		.clk = &tegra_cdev1,
+	},
+	.fixed_rate = 26000000,
+	.u.periph = {
+		.clk_num = 94,
+	},
+};
+static struct clk tegra_cdev1 = {
+	.name = "cdev1",
+	.hw = &tegra_cdev1_hw.hw,
+	.ops = &tegra_cdev_clk_ops,
+	.flags = CLK_IS_ROOT,
+};
+
+/* dap_mclk2, belongs to the cdev2 pingroup. */
+static struct clk tegra_cdev2;
+static struct clk_tegra tegra_cdev2_hw = {
+	.hw = {
+		.clk = &tegra_cdev2,
+	},
+	.fixed_rate = 26000000,
+	.u.periph = {
+		.clk_num  = 93,
+	},
+};
+static struct clk tegra_cdev2 = {
+	.name = "cdev2",
+	.hw = &tegra_cdev2_hw.hw,
+	.ops = &tegra_cdev_clk_ops,
+	.flags = CLK_IS_ROOT,
+};
+
+/* initialized before peripheral clocks */
+static struct clk_mux_sel mux_audio_sync_clk[8+1];
+static const struct audio_sources {
+	const char *name;
+	int value;
+} mux_audio_sync_clk_sources[] = {
+	{ .name = "spdif_in", .value = 0 },
+	{ .name = "i2s1", .value = 1 },
+	{ .name = "i2s2", .value = 2 },
+	{ .name = "pll_a_out0", .value = 4 },
+#if 0 /* FIXME: not implemented */
+	{ .name = "ac97", .value = 3 },
+	{ .name = "ext_audio_clk2", .value = 5 },
+	{ .name = "ext_audio_clk1", .value = 6 },
+	{ .name = "ext_vimclk", .value = 7 },
+#endif
+	{ NULL, 0 }
+};
+
+static const char *audio_parent_names[] = {
+	"spdif_in",
+	"i2s1",
+	"i2s2",
+	"dummy",
+	"pll_a_out0",
+	"dummy",
+	"dummy",
+	"dummy",
+};
+
+static struct clk *audio_parents[] = {
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+};
+
+static struct clk tegra_audio;
+static struct clk_tegra tegra_audio_hw = {
+	.hw = {
+		.clk = &tegra_audio,
+	},
+	.reg = 0x38,
+	.max_rate = 73728000,
+};
+DEFINE_CLK_TEGRA(audio, 0, &tegra_audio_sync_clk_ops, 0, audio_parent_names,
+		audio_parents, NULL);
+
+static const char *audio_2x_parent_names[] = {
+	"audio",
+};
+
+static struct clk *audio_2x_parents[] = {
+	&tegra_audio,
+};
+
+static struct clk tegra_audio_2x;
+static struct clk_tegra tegra_audio_2x_hw = {
+	.hw = {
+		.clk = &tegra_audio_2x,
+	},
+	.flags = PERIPH_NO_RESET,
+	.max_rate = 48000000,
+	.reg = 0x34,
+	.reg_shift = 8,
+	.u.periph = {
+		.clk_num = 89,
+	},
+};
+DEFINE_CLK_TEGRA(audio_2x, 0, &tegra_clk_double_ops, 0, audio_2x_parent_names,
+		audio_2x_parents, &tegra_audio);
+
+static struct clk_lookup tegra_audio_clk_lookups[] = {
+	{ .con_id = "audio", .clk = &tegra_audio },
+	{ .con_id = "audio_2x", .clk = &tegra_audio_2x }
+};
+
+/* This is called after peripheral clocks are initialized, as the
+ * audio_sync clock depends on some of the peripheral clocks.
+ */
+
+static void init_audio_sync_clock_mux(void)
+{
+	int i;
+	struct clk_mux_sel *sel = mux_audio_sync_clk;
+	const struct audio_sources *src = mux_audio_sync_clk_sources;
+	struct clk_lookup *lookup;
+
+	for (i = 0; src->name; i++, sel++, src++) {
+		sel->input = tegra_get_clock_by_name(src->name);
+		if (!sel->input)
+			pr_err("%s: could not find clk %s\n", __func__,
+				src->name);
+		audio_parents[src->value] = sel->input;
+		sel->value = src->value;
+	}
+
+	lookup = tegra_audio_clk_lookups;
+	for (i = 0; i < ARRAY_SIZE(tegra_audio_clk_lookups); i++, lookup++) {
+		struct clk *c = lookup->clk;
+		struct clk_tegra *clk = to_clk_tegra(c->hw);
+		__clk_init(NULL, c);
+		INIT_LIST_HEAD(&clk->shared_bus_list);
+		clk->lookup.con_id = lookup->con_id;
+		clk->lookup.clk = c;
+		clkdev_add(&clk->lookup);
+		tegra_clk_add(c);
+	}
+}
+
+static const char *mux_cclk[] = {
+	"clk_m",
+	"pll_c",
+	"clk_32k",
+	"pll_m",
+	"pll_p",
+	"pll_p_out4",
+	"pll_p_out3",
+	"clk_d",
+	"pll_x",
+};
+
+
+static struct clk *mux_cclk_p[] = {
+	&tegra_clk_m,
+	&tegra_pll_c,
+	&tegra_clk_32k,
+	&tegra_pll_m,
+	&tegra_pll_p,
+	&tegra_pll_p_out4,
+	&tegra_pll_p_out3,
+	&tegra_clk_d,
+	&tegra_pll_x,
+};
+
+static const char *mux_sclk[] = {
+	"clk_m",
+	"pll_c_out1",
+	"pll_p_out4",
+	"pllp_p_out3",
+	"pll_p_out2",
+	"clk_d",
+	"clk_32k",
+	"pll_m_out1",
+};
+
+static struct clk *mux_sclk_p[] = {
+	&tegra_clk_m,
+	&tegra_pll_c_out1,
+	&tegra_pll_p_out4,
+	&tegra_pll_p_out3,
+	&tegra_pll_p_out2,
+	&tegra_clk_d,
+	&tegra_clk_32k,
+	&tegra_pll_m_out1,
+};
+
+static struct clk tegra_cclk;
+static struct clk_tegra tegra_cclk_hw = {
+	.hw = {
+		.clk = &tegra_cclk,
+	},
+	.reg = 0x20,
+	.max_rate = 1000000000,
+};
+DEFINE_CLK_TEGRA(cclk, 0, &tegra_super_ops, 0, mux_cclk,
+		mux_cclk_p, NULL);
+
+static struct clk tegra_sclk;
+static struct clk_tegra tegra_sclk_hw = {
+	.hw = {
+		.clk = &tegra_sclk,
+	},
+	.reg = 0x28,
+	.max_rate = 240000000,
+	.min_rate = 120000000,
+};
+DEFINE_CLK_TEGRA(sclk, 0, &tegra_super_ops, 0, mux_sclk,
+		mux_sclk_p, NULL);
+
+static const char *tegra_cop_parent_names[] = {
+	"tegra_sclk",
+};
+
+static struct clk *tegra_cop_parents[] = {
+	&tegra_sclk,
+};
+
+static struct clk tegra_cop;
+static struct clk_tegra tegra_cop_hw = {
+	.hw = {
+		.clk = &tegra_cop,
+	},
+	.max_rate  = 240000000,
+	.reset = &tegra2_cop_clk_reset,
+};
+DEFINE_CLK_TEGRA(cop, 0, &tegra_cop_ops, CLK_SET_RATE_PARENT,
+		tegra_cop_parent_names, tegra_cop_parents, &tegra_sclk);
+
+static const char *tegra_hclk_parent_names[] = {
+	"tegra_sclk",
+};
+
+static struct clk *tegra_hclk_parents[] = {
+	&tegra_sclk,
+};
+
+static struct clk tegra_hclk;
+static struct clk_tegra tegra_hclk_hw = {
+	.hw = {
+		.clk = &tegra_hclk,
+	},
+	.flags = DIV_BUS,
+	.reg = 0x30,
+	.reg_shift = 4,
+	.max_rate = 240000000,
+};
+DEFINE_CLK_TEGRA(hclk, 0, &tegra_bus_ops, 0, tegra_hclk_parent_names,
+		tegra_hclk_parents, &tegra_sclk);
+
+static const char *tegra_pclk_parent_names[] = {
+	"tegra_hclk",
+};
+
+static struct clk *tegra_pclk_parents[] = {
+	&tegra_hclk,
+};
+
+static struct clk tegra_pclk;
+static struct clk_tegra tegra_pclk_hw = {
+	.hw = {
+		.clk = &tegra_pclk,
+	},
+	.flags = DIV_BUS,
+	.reg = 0x30,
+	.reg_shift = 0,
+	.max_rate = 120000000,
+};
+DEFINE_CLK_TEGRA(pclk, 0, &tegra_bus_ops, 0, tegra_pclk_parent_names,
+		tegra_pclk_parents, &tegra_hclk);
+
+static const char *tegra_blink_parent_names[] = {
+	"clk_32k",
+};
+
+static struct clk *tegra_blink_parents[] = {
+	&tegra_clk_32k,
+};
+
+static struct clk tegra_blink;
+static struct clk_tegra tegra_blink_hw = {
+	.hw = {
+		.clk = &tegra_blink,
+	},
+	.reg = 0x40,
+	.max_rate = 32768,
+};
+DEFINE_CLK_TEGRA(blink, 0, &tegra_blink_clk_ops, 0, tegra_blink_parent_names,
+		tegra_blink_parents, &tegra_clk_32k);
+
+static const char *mux_pllm_pllc_pllp_plla[] = {
+	"pll_m",
+	"pll_c",
+	"pll_p",
+	"pll_a_out0",
+};
+
+static struct clk *mux_pllm_pllc_pllp_plla_p[] = {
+	&tegra_pll_m,
+	&tegra_pll_c,
+	&tegra_pll_p,
+	&tegra_pll_a_out0,
+};
+
+static const char *mux_pllm_pllc_pllp_clkm[] = {
+	"pll_m",
+	"pll_c",
+	"pll_p",
+	"clk_m",
+};
+
+static struct clk *mux_pllm_pllc_pllp_clkm_p[] = {
+	&tegra_pll_m,
+	&tegra_pll_c,
+	&tegra_pll_p,
+	&tegra_clk_m,
+};
+
+static const char *mux_pllp_pllc_pllm_clkm[] = {
+	"pll_p",
+	"pll_c",
+	"pll_m",
+	"clk_m",
+};
+
+static struct clk *mux_pllp_pllc_pllm_clkm_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_c,
+	&tegra_pll_m,
+	&tegra_clk_m,
+};
+
+static const char *mux_pllaout0_audio2x_pllp_clkm[] = {
+	"pll_a_out0",
+	"audio_2x",
+	"pll_p",
+	"clk_m",
+};
+
+static struct clk *mux_pllaout0_audio2x_pllp_clkm_p[] = {
+	&tegra_pll_a_out0,
+	&tegra_audio_2x,
+	&tegra_pll_p,
+	&tegra_clk_m,
+};
+
+static const char *mux_pllp_plld_pllc_clkm[] = {
+	"pllp",
+	"pll_d_out0",
+	"pll_c",
+	"clk_m",
+};
+
+static struct clk *mux_pllp_plld_pllc_clkm_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_d_out0,
+	&tegra_pll_c,
+	&tegra_clk_m,
+};
+
+static const char *mux_pllp_pllc_audio_clkm_clk32[] = {
+	"pll_p",
+	"pll_c",
+	"audio",
+	"clk_m",
+	"clk_32k",
+};
+
+static struct clk *mux_pllp_pllc_audio_clkm_clk32_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_c,
+	&tegra_audio,
+	&tegra_clk_m,
+	&tegra_clk_32k,
+};
+
+static const char *mux_pllp_pllc_pllm[] = {
+	"pll_p",
+	"pll_c",
+	"pll_m"
+};
+
+static struct clk *mux_pllp_pllc_pllm_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_c,
+	&tegra_pll_m,
+};
+
+static const char *mux_clk_m[] = {
+	"clk_m",
+};
+
+static struct clk *mux_clk_m_p[] = {
+	&tegra_clk_m,
+};
+
+static const char *mux_pllp_out3[] = {
+	"pll_p_out3",
+};
+
+static struct clk *mux_pllp_out3_p[] = {
+	&tegra_pll_p_out3,
+};
+
+static const char *mux_plld[] = {
+	"pll_d",
+};
+
+static struct clk *mux_plld_p[] = {
+	&tegra_pll_d,
+};
+
+static const char *mux_clk_32k[] = {
+	"clk_32k",
+};
+
+static struct clk *mux_clk_32k_p[] = {
+	&tegra_clk_32k,
+};
+
+static const char *mux_pclk[] = {
+	"pclk",
+};
+
+static struct clk *mux_pclk_p[] = {
+	&tegra_pclk,
+};
+
+static struct clk tegra_emc;
+static struct clk_tegra tegra_emc_hw = {
+	.hw = {
+		.clk = &tegra_emc,
+	},
+	.reg = 0x19c,
+	.max_rate = 800000000,
+	.flags = MUX | DIV_U71 | PERIPH_EMC_ENB,
+	.reset = &tegra2_periph_clk_reset,
+	.u.periph = {
+		.clk_num = 57,
+	},
+};
+DEFINE_CLK_TEGRA(emc, 0, &tegra_emc_clk_ops, 0, mux_pllm_pllc_pllp_clkm,
+		mux_pllm_pllc_pllp_clkm_p, NULL);
+
+#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg,	\
+		_max, _inputs, _flags) 			\
+	static struct clk tegra_##_name;		\
+	static struct clk_tegra tegra_##_name##_hw = {	\
+		.hw = {					\
+			.clk = &tegra_##_name,		\
+		},					\
+		.lookup = {				\
+			.dev_id = _dev,			\
+			.con_id = _con,			\
+		},					\
+		.reg = _reg,				\
+		.flags = _flags,			\
+		.max_rate = _max,			\
+		.u.periph = {				\
+			.clk_num = _clk_num,		\
+		},					\
+		.reset = tegra2_periph_clk_reset,	\
+	};						\
+	static struct clk tegra_##_name = {		\
+		.name = #_name,				\
+		.ops = &tegra_periph_clk_ops,		\
+		.hw = &tegra_##_name##_hw.hw,		\
+		.parent_names = _inputs,		\
+		.parents = _inputs##_p,			\
+		.num_parents = ARRAY_SIZE(_inputs),	\
+	};
+
+PERIPH_CLK(apbdma,	"tegra-apbdma",		NULL,	34,	0,	108000000, mux_pclk,			0);
+PERIPH_CLK(rtc,		"rtc-tegra",		NULL,	4,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET);
+PERIPH_CLK(timer,	"timer",		NULL,	5,	0,	26000000,  mux_clk_m,			0);
+PERIPH_CLK(i2s1,	"tegra20-i2s.0",	NULL,	11,	0x100,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71);
+PERIPH_CLK(i2s2,	"tegra20-i2s.1",	NULL,	18,	0x104,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71);
+PERIPH_CLK(spdif_out,	"spdif_out",		NULL,	10,	0x108,	100000000, mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71);
+PERIPH_CLK(spdif_in,	"spdif_in",		NULL,	10,	0x10c,	100000000, mux_pllp_pllc_pllm,		MUX | DIV_U71);
+PERIPH_CLK(pwm,		"tegra-pwm",		NULL,	17,	0x110,	432000000, mux_pllp_pllc_audio_clkm_clk32,	MUX | DIV_U71 | MUX_PWM);
+PERIPH_CLK(spi,		"spi",			NULL,	43,	0x114,	40000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(xio,		"xio",			NULL,	45,	0x120,	150000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(twc,		"twc",			NULL,	16,	0x12c,	150000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(sbc1,	"spi_tegra.0",		NULL,	41,	0x134,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(sbc2,	"spi_tegra.1",		NULL,	44,	0x118,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(sbc3,	"spi_tegra.2",		NULL,	46,	0x11c,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(sbc4,	"spi_tegra.3",		NULL,	68,	0x1b4,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(ide,		"ide",			NULL,	25,	0x144,	100000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(ndflash,	"tegra_nand",		NULL,	13,	0x160,	164000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(vfir,	"vfir",			NULL,	7,	0x168,	72000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(sdmmc1,	"sdhci-tegra.0",	NULL,	14,	0x150,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc2,	"sdhci-tegra.1",	NULL,	9,	0x154,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc3,	"sdhci-tegra.2",	NULL,	69,	0x1bc,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc4,	"sdhci-tegra.3",	NULL,	15,	0x164,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(vcp,		"tegra-avp",		"vcp",	29,	0,	250000000, mux_clk_m,			0);
+PERIPH_CLK(bsea,	"tegra-avp",		"bsea",	62,	0,	250000000, mux_clk_m,			0);
+PERIPH_CLK(bsev,	"tegra-aes",		"bsev",	63,	0,	250000000, mux_clk_m,			0);
+PERIPH_CLK(vde,		"tegra-avp",		"vde",	61,	0x1c8,	250000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(csite,	"csite",		NULL,	73,	0x1d4,	144000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* max rate ??? */
+/* FIXME: what is la? */
+PERIPH_CLK(la,		"la",			NULL,	76,	0x1f8,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(owr,		"tegra_w1",		NULL,	71,	0x1cc,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(nor,		"nor",			NULL,	42,	0x1d0,	92000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(mipi,	"mipi",			NULL,	50,	0x174,	60000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(i2c1,	"tegra-i2c.0",		"div-clk", 12,	0x124,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16);
+PERIPH_CLK(i2c2,	"tegra-i2c.1",		"div-clk", 54,	0x198,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16);
+PERIPH_CLK(i2c3,	"tegra-i2c.2",		"div-clk", 67,	0x1b8,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16);
+PERIPH_CLK(dvc,		"tegra-i2c.3",		"div-clk", 47,	0x128,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16);
+PERIPH_CLK(uarta,	"tegra-uart.0",		NULL,	6,	0x178,	600000000, mux_pllp_pllc_pllm_clkm,	MUX);
+PERIPH_CLK(uartb,	"tegra-uart.1",		NULL,	7,	0x17c,	600000000, mux_pllp_pllc_pllm_clkm,	MUX);
+PERIPH_CLK(uartc,	"tegra-uart.2",		NULL,	55,	0x1a0,	600000000, mux_pllp_pllc_pllm_clkm,	MUX);
+PERIPH_CLK(uartd,	"tegra-uart.3",		NULL,	65,	0x1c0,	600000000, mux_pllp_pllc_pllm_clkm,	MUX);
+PERIPH_CLK(uarte,	"tegra-uart.4",		NULL,	66,	0x1c4,	600000000, mux_pllp_pllc_pllm_clkm,	MUX);
+PERIPH_CLK(3d,		"3d",			NULL,	24,	0x158,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | PERIPH_MANUAL_RESET); /* scales with voltage and process_id */
+PERIPH_CLK(2d,		"2d",			NULL,	21,	0x15c,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(vi,		"tegra_camera",		"vi",	20,	0x148,	150000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(vi_sensor,	"tegra_camera",		"vi_sensor",	20,	0x1a8,	150000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | PERIPH_NO_RESET); /* scales with voltage and process_id */
+PERIPH_CLK(epp,		"epp",			NULL,	19,	0x16c,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(mpe,		"mpe",			NULL,	60,	0x170,	250000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(host1x,	"host1x",		NULL,	28,	0x180,	166000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(cve,		"cve",			NULL,	49,	0x140,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(tvo,		"tvo",			NULL,	49,	0x188,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(hdmi,	"hdmi",			NULL,	51,	0x18c,	600000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(tvdac,	"tvdac",		NULL,	53,	0x194,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(disp1,	"tegradc.0",		NULL,	27,	0x138,	600000000, mux_pllp_plld_pllc_clkm,	MUX); /* scales with voltage and process_id */
+PERIPH_CLK(disp2,	"tegradc.1",		NULL,	26,	0x13c,	600000000, mux_pllp_plld_pllc_clkm,	MUX); /* scales with voltage and process_id */
+PERIPH_CLK(usbd,	"fsl-tegra-udc",	NULL,	22,	0,	480000000, mux_clk_m,			0); /* requires min voltage */
+PERIPH_CLK(usb2,	"tegra-ehci.1",		NULL,	58,	0,	480000000, mux_clk_m,			0); /* requires min voltage */
+PERIPH_CLK(usb3,	"tegra-ehci.2",		NULL,	59,	0,	480000000, mux_clk_m,			0); /* requires min voltage */
+PERIPH_CLK(dsi,		"dsi",			NULL,	48,	0,	500000000, mux_plld,			0); /* scales with voltage */
+PERIPH_CLK(csi,		"tegra_camera",		"csi",	52,	0,	72000000,  mux_pllp_out3,		0);
+PERIPH_CLK(isp,		"tegra_camera",		"isp",	23,	0,	150000000, mux_clk_m,			0); /* same frequency as VI */
+PERIPH_CLK(csus,	"tegra_camera",		"csus",	92,	0,	150000000, mux_clk_m,			PERIPH_NO_RESET);
+PERIPH_CLK(pex,		NULL,			"pex",  70,     0,	26000000,  mux_clk_m,			PERIPH_MANUAL_RESET);
+PERIPH_CLK(afi,		NULL,			"afi",  72,     0,	26000000,  mux_clk_m,			PERIPH_MANUAL_RESET);
+PERIPH_CLK(pcie_xclk,	NULL,		  "pcie_xclk",  74,     0,	26000000,  mux_clk_m,			PERIPH_MANUAL_RESET);
+
+static struct clk *tegra_list_clks[] = {
+	&tegra_apbdma,
+	&tegra_rtc,
+	&tegra_timer,
+	&tegra_i2s1,
+	&tegra_i2s2,
+	&tegra_spdif_out,
+	&tegra_spdif_in,
+	&tegra_pwm,
+	&tegra_spi,
+	&tegra_xio,
+	&tegra_twc,
+	&tegra_sbc1,
+	&tegra_sbc2,
+	&tegra_sbc3,
+	&tegra_sbc4,
+	&tegra_ide,
+	&tegra_ndflash,
+	&tegra_vfir,
+	&tegra_sdmmc1,
+	&tegra_sdmmc2,
+	&tegra_sdmmc3,
+	&tegra_sdmmc4,
+	&tegra_vcp,
+	&tegra_bsea,
+	&tegra_bsev,
+	&tegra_vde,
+	&tegra_csite,
+	&tegra_la,
+	&tegra_owr,
+	&tegra_nor,
+	&tegra_mipi,
+	&tegra_i2c1,
+	&tegra_i2c2,
+	&tegra_i2c3,
+	&tegra_dvc,
+	&tegra_uarta,
+	&tegra_uartb,
+	&tegra_uartc,
+	&tegra_uartd,
+	&tegra_uarte,
+	&tegra_3d,
+	&tegra_2d,
+	&tegra_vi,
+	&tegra_vi_sensor,
+	&tegra_epp,
+	&tegra_mpe,
+	&tegra_host1x,
+	&tegra_cve,
+	&tegra_tvo,
+	&tegra_hdmi,
+	&tegra_tvdac,
+	&tegra_disp1,
+	&tegra_disp2,
+	&tegra_usbd,
+	&tegra_usb2,
+	&tegra_usb3,
+	&tegra_dsi,
+	&tegra_csi,
+	&tegra_isp,
+	&tegra_csus,
+	&tegra_pex,
+	&tegra_afi,
+	&tegra_pcie_xclk,
+};
+
+#define CLK_DUPLICATE(_name, _dev, _con)	\
+	{					\
+		.name	= _name,		\
+		.lookup	= {			\
+			.dev_id	= _dev,		\
+			.con_id	= _con,		\
+		},				\
+	}
+
+/* Some clocks may be used by different drivers depending on the board
+ * configuration.  List those here to register them twice in the clock lookup
+ * table under two names.
+ */
+static struct clk_duplicate tegra_clk_duplicates[] = {
+	CLK_DUPLICATE("uarta",	"serial8250.0",	NULL),
+	CLK_DUPLICATE("uartb",	"serial8250.1",	NULL),
+	CLK_DUPLICATE("uartc",	"serial8250.2",	NULL),
+	CLK_DUPLICATE("uartd",	"serial8250.3",	NULL),
+	CLK_DUPLICATE("uarte",	"serial8250.4",	NULL),
+	CLK_DUPLICATE("usbd",	"utmip-pad",	NULL),
+	CLK_DUPLICATE("usbd",	"tegra-ehci.0",	NULL),
+	CLK_DUPLICATE("usbd",	"tegra-otg",	NULL),
+	CLK_DUPLICATE("hdmi",	"tegradc.0",	"hdmi"),
+	CLK_DUPLICATE("hdmi",	"tegradc.1",	"hdmi"),
+	CLK_DUPLICATE("host1x",	"tegra_grhost",	"host1x"),
+	CLK_DUPLICATE("2d",	"tegra_grhost",	"gr2d"),
+	CLK_DUPLICATE("3d",	"tegra_grhost",	"gr3d"),
+	CLK_DUPLICATE("epp",	"tegra_grhost",	"epp"),
+	CLK_DUPLICATE("mpe",	"tegra_grhost",	"mpe"),
+	CLK_DUPLICATE("cop",	"tegra-avp",	"cop"),
+	CLK_DUPLICATE("vde",	"tegra-aes",	"vde"),
+	CLK_DUPLICATE("cclk",	NULL,		"cpu"),
+	CLK_DUPLICATE("pll_p_out3", "tegra-i2c.0", "fast-clk"),
+	CLK_DUPLICATE("pll_p_out3", "tegra-i2c.1", "fast-clk"),
+	CLK_DUPLICATE("pll_p_out3", "tegra-i2c.2", "fast-clk"),
+	CLK_DUPLICATE("pll_p_out3", "tegra-i2c.3", "fast-clk"),
+};
+
+#define CLK(dev, con, ck)	\
+	{			\
+		.dev_id	= dev,	\
+		.con_id	= con,	\
+		.clk	= ck,	\
+	}
+
+static struct clk *tegra_ptr_clks[] = {
+	&tegra_clk_32k,
+	&tegra_pll_s,
+	&tegra_clk_m,
+	&tegra_pll_m,
+	&tegra_pll_m_out1,
+	&tegra_pll_c,
+	&tegra_pll_c_out1,
+	&tegra_pll_p,
+	&tegra_pll_p_out1,
+	&tegra_pll_p_out2,
+	&tegra_pll_p_out3,
+	&tegra_pll_p_out4,
+	&tegra_pll_a,
+	&tegra_pll_a_out0,
+	&tegra_pll_d,
+	&tegra_pll_d_out0,
+	&tegra_pll_u,
+	&tegra_pll_x,
+	&tegra_pll_e,
+	&tegra_cclk,
+	&tegra_sclk,
+	&tegra_hclk,
+	&tegra_pclk,
+	&tegra_clk_d,
+	&tegra_cdev1,
+	&tegra_cdev2,
+	&tegra_blink,
+	&tegra_cop,
+	&tegra_emc,
+};
+
+static void tegra2_init_one_clock(struct clk *c)
+{
+	struct clk_tegra *clk = to_clk_tegra(c->hw);
+	int ret;
+
+	ret = __clk_init(NULL, c);
+	if (ret)
+		pr_err("clk init failed %s\n", __clk_get_name(c));
+
+	INIT_LIST_HEAD(&clk->shared_bus_list);
+	if (!clk->lookup.dev_id && !clk->lookup.con_id)
+		clk->lookup.con_id = c->name;
+	clk->lookup.clk = c;
+	clkdev_add(&clk->lookup);
+	tegra_clk_add(c);
+}
+
+void __init tegra2_init_clocks(void)
+{
+	int i;
+	struct clk *c;
+
+	for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
+		tegra2_init_one_clock(tegra_ptr_clks[i]);
+
+	for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
+		tegra2_init_one_clock(tegra_list_clks[i]);
+
+	for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
+		c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
+		if (!c) {
+			pr_err("%s: Unknown duplicate clock %s\n", __func__,
+				tegra_clk_duplicates[i].name);
+			continue;
+		}
+
+		tegra_clk_duplicates[i].lookup.clk = c;
+		clkdev_add(&tegra_clk_duplicates[i].lookup);
+	}
+
+	init_audio_sync_clock_mux();
+	tegra20_cpu_car_ops_init();
+}
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
deleted file mode 100644
index a703844..0000000
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ /dev/null
@@ -1,2484 +0,0 @@
-/*
- * arch/arm/mach-tegra/tegra2_clocks.c
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- *	Colin Cross <ccross@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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/list.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/clkdev.h>
-#include <linux/clk.h>
-
-#include <mach/iomap.h>
-#include <mach/suspend.h>
-
-#include "clock.h"
-#include "fuse.h"
-#include "tegra2_emc.h"
-
-#define RST_DEVICES			0x004
-#define RST_DEVICES_SET			0x300
-#define RST_DEVICES_CLR			0x304
-#define RST_DEVICES_NUM			3
-
-#define CLK_OUT_ENB			0x010
-#define CLK_OUT_ENB_SET			0x320
-#define CLK_OUT_ENB_CLR			0x324
-#define CLK_OUT_ENB_NUM			3
-
-#define CLK_MASK_ARM			0x44
-#define MISC_CLK_ENB			0x48
-
-#define OSC_CTRL			0x50
-#define OSC_CTRL_OSC_FREQ_MASK		(3<<30)
-#define OSC_CTRL_OSC_FREQ_13MHZ		(0<<30)
-#define OSC_CTRL_OSC_FREQ_19_2MHZ	(1<<30)
-#define OSC_CTRL_OSC_FREQ_12MHZ		(2<<30)
-#define OSC_CTRL_OSC_FREQ_26MHZ		(3<<30)
-#define OSC_CTRL_MASK			(0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
-
-#define OSC_FREQ_DET			0x58
-#define OSC_FREQ_DET_TRIG		(1<<31)
-
-#define OSC_FREQ_DET_STATUS		0x5C
-#define OSC_FREQ_DET_BUSY		(1<<31)
-#define OSC_FREQ_DET_CNT_MASK		0xFFFF
-
-#define PERIPH_CLK_SOURCE_I2S1		0x100
-#define PERIPH_CLK_SOURCE_EMC		0x19c
-#define PERIPH_CLK_SOURCE_OSC		0x1fc
-#define PERIPH_CLK_SOURCE_NUM \
-	((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
-
-#define PERIPH_CLK_SOURCE_MASK		(3<<30)
-#define PERIPH_CLK_SOURCE_SHIFT		30
-#define PERIPH_CLK_SOURCE_PWM_MASK	(7<<28)
-#define PERIPH_CLK_SOURCE_PWM_SHIFT	28
-#define PERIPH_CLK_SOURCE_ENABLE	(1<<28)
-#define PERIPH_CLK_SOURCE_DIVU71_MASK	0xFF
-#define PERIPH_CLK_SOURCE_DIVU16_MASK	0xFFFF
-#define PERIPH_CLK_SOURCE_DIV_SHIFT	0
-
-#define SDMMC_CLK_INT_FB_SEL		(1 << 23)
-#define SDMMC_CLK_INT_FB_DLY_SHIFT	16
-#define SDMMC_CLK_INT_FB_DLY_MASK	(0xF << SDMMC_CLK_INT_FB_DLY_SHIFT)
-
-#define PLL_BASE			0x0
-#define PLL_BASE_BYPASS			(1<<31)
-#define PLL_BASE_ENABLE			(1<<30)
-#define PLL_BASE_REF_ENABLE		(1<<29)
-#define PLL_BASE_OVERRIDE		(1<<28)
-#define PLL_BASE_DIVP_MASK		(0x7<<20)
-#define PLL_BASE_DIVP_SHIFT		20
-#define PLL_BASE_DIVN_MASK		(0x3FF<<8)
-#define PLL_BASE_DIVN_SHIFT		8
-#define PLL_BASE_DIVM_MASK		(0x1F)
-#define PLL_BASE_DIVM_SHIFT		0
-
-#define PLL_OUT_RATIO_MASK		(0xFF<<8)
-#define PLL_OUT_RATIO_SHIFT		8
-#define PLL_OUT_OVERRIDE		(1<<2)
-#define PLL_OUT_CLKEN			(1<<1)
-#define PLL_OUT_RESET_DISABLE		(1<<0)
-
-#define PLL_MISC(c)			(((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
-
-#define PLL_MISC_DCCON_SHIFT		20
-#define PLL_MISC_CPCON_SHIFT		8
-#define PLL_MISC_CPCON_MASK		(0xF<<PLL_MISC_CPCON_SHIFT)
-#define PLL_MISC_LFCON_SHIFT		4
-#define PLL_MISC_LFCON_MASK		(0xF<<PLL_MISC_LFCON_SHIFT)
-#define PLL_MISC_VCOCON_SHIFT		0
-#define PLL_MISC_VCOCON_MASK		(0xF<<PLL_MISC_VCOCON_SHIFT)
-
-#define PLLU_BASE_POST_DIV		(1<<20)
-
-#define PLLD_MISC_CLKENABLE		(1<<30)
-#define PLLD_MISC_DIV_RST		(1<<23)
-#define PLLD_MISC_DCCON_SHIFT		12
-
-#define PLLE_MISC_READY			(1 << 15)
-
-#define PERIPH_CLK_TO_ENB_REG(c)	((c->u.periph.clk_num / 32) * 4)
-#define PERIPH_CLK_TO_ENB_SET_REG(c)	((c->u.periph.clk_num / 32) * 8)
-#define PERIPH_CLK_TO_ENB_BIT(c)	(1 << (c->u.periph.clk_num % 32))
-
-#define SUPER_CLK_MUX			0x00
-#define SUPER_STATE_SHIFT		28
-#define SUPER_STATE_MASK		(0xF << SUPER_STATE_SHIFT)
-#define SUPER_STATE_STANDBY		(0x0 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_IDLE		(0x1 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_RUN			(0x2 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_IRQ			(0x3 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_FIQ			(0x4 << SUPER_STATE_SHIFT)
-#define SUPER_SOURCE_MASK		0xF
-#define	SUPER_FIQ_SOURCE_SHIFT		12
-#define	SUPER_IRQ_SOURCE_SHIFT		8
-#define	SUPER_RUN_SOURCE_SHIFT		4
-#define	SUPER_IDLE_SOURCE_SHIFT		0
-
-#define SUPER_CLK_DIVIDER		0x04
-
-#define BUS_CLK_DISABLE			(1<<3)
-#define BUS_CLK_DIV_MASK		0x3
-
-#define PMC_CTRL			0x0
- #define PMC_CTRL_BLINK_ENB		(1 << 7)
-
-#define PMC_DPD_PADS_ORIDE		0x1c
- #define PMC_DPD_PADS_ORIDE_BLINK_ENB	(1 << 20)
-
-#define PMC_BLINK_TIMER_DATA_ON_SHIFT	0
-#define PMC_BLINK_TIMER_DATA_ON_MASK	0x7fff
-#define PMC_BLINK_TIMER_ENB		(1 << 15)
-#define PMC_BLINK_TIMER_DATA_OFF_SHIFT	16
-#define PMC_BLINK_TIMER_DATA_OFF_MASK	0xffff
-
-static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
-static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
-
-/*
- * Some clocks share a register with other clocks.  Any clock op that
- * non-atomically modifies a register used by another clock must lock
- * clock_register_lock first.
- */
-static DEFINE_SPINLOCK(clock_register_lock);
-
-/*
- * Some peripheral clocks share an enable bit, so refcount the enable bits
- * in registers CLK_ENABLE_L, CLK_ENABLE_H, and CLK_ENABLE_U
- */
-static int tegra_periph_clk_enable_refcount[3 * 32];
-
-#define clk_writel(value, reg) \
-	__raw_writel(value, reg_clk_base + (reg))
-#define clk_readl(reg) \
-	__raw_readl(reg_clk_base + (reg))
-#define pmc_writel(value, reg) \
-	__raw_writel(value, reg_pmc_base + (reg))
-#define pmc_readl(reg) \
-	__raw_readl(reg_pmc_base + (reg))
-
-static unsigned long clk_measure_input_freq(void)
-{
-	u32 clock_autodetect;
-	clk_writel(OSC_FREQ_DET_TRIG | 1, OSC_FREQ_DET);
-	do {} while (clk_readl(OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY);
-	clock_autodetect = clk_readl(OSC_FREQ_DET_STATUS);
-	if (clock_autodetect >= 732 - 3 && clock_autodetect <= 732 + 3) {
-		return 12000000;
-	} else if (clock_autodetect >= 794 - 3 && clock_autodetect <= 794 + 3) {
-		return 13000000;
-	} else if (clock_autodetect >= 1172 - 3 && clock_autodetect <= 1172 + 3) {
-		return 19200000;
-	} else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) {
-		return 26000000;
-	} else {
-		pr_err("%s: Unexpected clock autodetect value %d", __func__, clock_autodetect);
-		BUG();
-		return 0;
-	}
-}
-
-static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate)
-{
-	s64 divider_u71 = parent_rate * 2;
-	divider_u71 += rate - 1;
-	do_div(divider_u71, rate);
-
-	if (divider_u71 - 2 < 0)
-		return 0;
-
-	if (divider_u71 - 2 > 255)
-		return -EINVAL;
-
-	return divider_u71 - 2;
-}
-
-static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
-{
-	s64 divider_u16;
-
-	divider_u16 = parent_rate;
-	divider_u16 += rate - 1;
-	do_div(divider_u16, rate);
-
-	if (divider_u16 - 1 < 0)
-		return 0;
-
-	if (divider_u16 - 1 > 255)
-		return -EINVAL;
-
-	return divider_u16 - 1;
-}
-
-/* clk_m functions */
-static unsigned long tegra2_clk_m_autodetect_rate(struct clk *c)
-{
-	u32 auto_clock_control = clk_readl(OSC_CTRL) & ~OSC_CTRL_OSC_FREQ_MASK;
-
-	c->rate = clk_measure_input_freq();
-	switch (c->rate) {
-	case 12000000:
-		auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
-		break;
-	case 13000000:
-		auto_clock_control |= OSC_CTRL_OSC_FREQ_13MHZ;
-		break;
-	case 19200000:
-		auto_clock_control |= OSC_CTRL_OSC_FREQ_19_2MHZ;
-		break;
-	case 26000000:
-		auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ;
-		break;
-	default:
-		pr_err("%s: Unexpected clock rate %ld", __func__, c->rate);
-		BUG();
-	}
-	clk_writel(auto_clock_control, OSC_CTRL);
-	return c->rate;
-}
-
-static void tegra2_clk_m_init(struct clk *c)
-{
-	pr_debug("%s on clock %s\n", __func__, c->name);
-	tegra2_clk_m_autodetect_rate(c);
-}
-
-static int tegra2_clk_m_enable(struct clk *c)
-{
-	pr_debug("%s on clock %s\n", __func__, c->name);
-	return 0;
-}
-
-static void tegra2_clk_m_disable(struct clk *c)
-{
-	pr_debug("%s on clock %s\n", __func__, c->name);
-	BUG();
-}
-
-static struct clk_ops tegra_clk_m_ops = {
-	.init		= tegra2_clk_m_init,
-	.enable		= tegra2_clk_m_enable,
-	.disable	= tegra2_clk_m_disable,
-};
-
-/* super clock functions */
-/* "super clocks" on tegra have two-stage muxes and a clock skipping
- * super divider.  We will ignore the clock skipping divider, since we
- * can't lower the voltage when using the clock skip, but we can if we
- * lower the PLL frequency.
- */
-static void tegra2_super_clk_init(struct clk *c)
-{
-	u32 val;
-	int source;
-	int shift;
-	const struct clk_mux_sel *sel;
-	val = clk_readl(c->reg + SUPER_CLK_MUX);
-	c->state = ON;
-	BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
-		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
-	shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
-		SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
-	source = (val >> shift) & SUPER_SOURCE_MASK;
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->value == source)
-			break;
-	}
-	BUG_ON(sel->input == NULL);
-	c->parent = sel->input;
-}
-
-static int tegra2_super_clk_enable(struct clk *c)
-{
-	clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
-	return 0;
-}
-
-static void tegra2_super_clk_disable(struct clk *c)
-{
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
-	/* oops - don't disable the CPU clock! */
-	BUG();
-}
-
-static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p)
-{
-	u32 val;
-	const struct clk_mux_sel *sel;
-	int shift;
-
-	val = clk_readl(c->reg + SUPER_CLK_MUX);
-	BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
-		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
-	shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
-		SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->input == p) {
-			val &= ~(SUPER_SOURCE_MASK << shift);
-			val |= sel->value << shift;
-
-			if (c->refcnt)
-				clk_enable(p);
-
-			clk_writel(val, c->reg);
-
-			if (c->refcnt && c->parent)
-				clk_disable(c->parent);
-
-			clk_reparent(c, p);
-			return 0;
-		}
-	}
-	return -EINVAL;
-}
-
-/*
- * Super clocks have "clock skippers" instead of dividers.  Dividing using
- * a clock skipper does not allow the voltage to be scaled down, so instead
- * adjust the rate of the parent clock.  This requires that the parent of a
- * super clock have no other children, otherwise the rate will change
- * underneath the other children.
- */
-static int tegra2_super_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	return clk_set_rate(c->parent, rate);
-}
-
-static struct clk_ops tegra_super_ops = {
-	.init			= tegra2_super_clk_init,
-	.enable			= tegra2_super_clk_enable,
-	.disable		= tegra2_super_clk_disable,
-	.set_parent		= tegra2_super_clk_set_parent,
-	.set_rate		= tegra2_super_clk_set_rate,
-};
-
-/* virtual cpu clock functions */
-/* some clocks can not be stopped (cpu, memory bus) while the SoC is running.
-   To change the frequency of these clocks, the parent pll may need to be
-   reprogrammed, so the clock must be moved off the pll, the pll reprogrammed,
-   and then the clock moved back to the pll.  To hide this sequence, a virtual
-   clock handles it.
- */
-static void tegra2_cpu_clk_init(struct clk *c)
-{
-}
-
-static int tegra2_cpu_clk_enable(struct clk *c)
-{
-	return 0;
-}
-
-static void tegra2_cpu_clk_disable(struct clk *c)
-{
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
-	/* oops - don't disable the CPU clock! */
-	BUG();
-}
-
-static int tegra2_cpu_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	int ret;
-	/*
-	 * Take an extra reference to the main pll so it doesn't turn
-	 * off when we move the cpu off of it
-	 */
-	clk_enable(c->u.cpu.main);
-
-	ret = clk_set_parent(c->parent, c->u.cpu.backup);
-	if (ret) {
-		pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.backup->name);
-		goto out;
-	}
-
-	if (rate == clk_get_rate(c->u.cpu.backup))
-		goto out;
-
-	ret = clk_set_rate(c->u.cpu.main, rate);
-	if (ret) {
-		pr_err("Failed to change cpu pll to %lu\n", rate);
-		goto out;
-	}
-
-	ret = clk_set_parent(c->parent, c->u.cpu.main);
-	if (ret) {
-		pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.main->name);
-		goto out;
-	}
-
-out:
-	clk_disable(c->u.cpu.main);
-	return ret;
-}
-
-static struct clk_ops tegra_cpu_ops = {
-	.init     = tegra2_cpu_clk_init,
-	.enable   = tegra2_cpu_clk_enable,
-	.disable  = tegra2_cpu_clk_disable,
-	.set_rate = tegra2_cpu_clk_set_rate,
-};
-
-/* virtual cop clock functions. Used to acquire the fake 'cop' clock to
- * reset the COP block (i.e. AVP) */
-static void tegra2_cop_clk_reset(struct clk *c, bool assert)
-{
-	unsigned long reg = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
-
-	pr_debug("%s %s\n", __func__, assert ? "assert" : "deassert");
-	clk_writel(1 << 1, reg);
-}
-
-static struct clk_ops tegra_cop_ops = {
-	.reset    = tegra2_cop_clk_reset,
-};
-
-/* bus clock functions */
-static void tegra2_bus_clk_init(struct clk *c)
-{
-	u32 val = clk_readl(c->reg);
-	c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON;
-	c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1;
-	c->mul = 1;
-}
-
-static int tegra2_bus_clk_enable(struct clk *c)
-{
-	u32 val;
-	unsigned long flags;
-
-	spin_lock_irqsave(&clock_register_lock, flags);
-
-	val = clk_readl(c->reg);
-	val &= ~(BUS_CLK_DISABLE << c->reg_shift);
-	clk_writel(val, c->reg);
-
-	spin_unlock_irqrestore(&clock_register_lock, flags);
-
-	return 0;
-}
-
-static void tegra2_bus_clk_disable(struct clk *c)
-{
-	u32 val;
-	unsigned long flags;
-
-	spin_lock_irqsave(&clock_register_lock, flags);
-
-	val = clk_readl(c->reg);
-	val |= BUS_CLK_DISABLE << c->reg_shift;
-	clk_writel(val, c->reg);
-
-	spin_unlock_irqrestore(&clock_register_lock, flags);
-}
-
-static int tegra2_bus_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	u32 val;
-	unsigned long parent_rate = clk_get_rate(c->parent);
-	unsigned long flags;
-	int ret = -EINVAL;
-	int i;
-
-	spin_lock_irqsave(&clock_register_lock, flags);
-
-	val = clk_readl(c->reg);
-	for (i = 1; i <= 4; i++) {
-		if (rate == parent_rate / i) {
-			val &= ~(BUS_CLK_DIV_MASK << c->reg_shift);
-			val |= (i - 1) << c->reg_shift;
-			clk_writel(val, c->reg);
-			c->div = i;
-			c->mul = 1;
-			ret = 0;
-			break;
-		}
-	}
-
-	spin_unlock_irqrestore(&clock_register_lock, flags);
-
-	return ret;
-}
-
-static struct clk_ops tegra_bus_ops = {
-	.init			= tegra2_bus_clk_init,
-	.enable			= tegra2_bus_clk_enable,
-	.disable		= tegra2_bus_clk_disable,
-	.set_rate		= tegra2_bus_clk_set_rate,
-};
-
-/* Blink output functions */
-
-static void tegra2_blink_clk_init(struct clk *c)
-{
-	u32 val;
-
-	val = pmc_readl(PMC_CTRL);
-	c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF;
-	c->mul = 1;
-	val = pmc_readl(c->reg);
-
-	if (val & PMC_BLINK_TIMER_ENB) {
-		unsigned int on_off;
-
-		on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
-			PMC_BLINK_TIMER_DATA_ON_MASK;
-		val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
-		val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
-		on_off += val;
-		/* each tick in the blink timer is 4 32KHz clocks */
-		c->div = on_off * 4;
-	} else {
-		c->div = 1;
-	}
-}
-
-static int tegra2_blink_clk_enable(struct clk *c)
-{
-	u32 val;
-
-	val = pmc_readl(PMC_DPD_PADS_ORIDE);
-	pmc_writel(val | PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
-
-	val = pmc_readl(PMC_CTRL);
-	pmc_writel(val | PMC_CTRL_BLINK_ENB, PMC_CTRL);
-
-	return 0;
-}
-
-static void tegra2_blink_clk_disable(struct clk *c)
-{
-	u32 val;
-
-	val = pmc_readl(PMC_CTRL);
-	pmc_writel(val & ~PMC_CTRL_BLINK_ENB, PMC_CTRL);
-
-	val = pmc_readl(PMC_DPD_PADS_ORIDE);
-	pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
-}
-
-static int tegra2_blink_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	unsigned long parent_rate = clk_get_rate(c->parent);
-	if (rate >= parent_rate) {
-		c->div = 1;
-		pmc_writel(0, c->reg);
-	} else {
-		unsigned int on_off;
-		u32 val;
-
-		on_off = DIV_ROUND_UP(parent_rate / 8, rate);
-		c->div = on_off * 8;
-
-		val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) <<
-			PMC_BLINK_TIMER_DATA_ON_SHIFT;
-		on_off &= PMC_BLINK_TIMER_DATA_OFF_MASK;
-		on_off <<= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
-		val |= on_off;
-		val |= PMC_BLINK_TIMER_ENB;
-		pmc_writel(val, c->reg);
-	}
-
-	return 0;
-}
-
-static struct clk_ops tegra_blink_clk_ops = {
-	.init			= &tegra2_blink_clk_init,
-	.enable			= &tegra2_blink_clk_enable,
-	.disable		= &tegra2_blink_clk_disable,
-	.set_rate		= &tegra2_blink_clk_set_rate,
-};
-
-/* PLL Functions */
-static int tegra2_pll_clk_wait_for_lock(struct clk *c)
-{
-	udelay(c->u.pll.lock_delay);
-
-	return 0;
-}
-
-static void tegra2_pll_clk_init(struct clk *c)
-{
-	u32 val = clk_readl(c->reg + PLL_BASE);
-
-	c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
-
-	if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
-		pr_warning("Clock %s has unknown fixed frequency\n", c->name);
-		c->mul = 1;
-		c->div = 1;
-	} else if (val & PLL_BASE_BYPASS) {
-		c->mul = 1;
-		c->div = 1;
-	} else {
-		c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
-		c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
-		if (c->flags & PLLU)
-			c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
-		else
-			c->div *= (val & PLL_BASE_DIVP_MASK) ? 2 : 1;
-	}
-}
-
-static int tegra2_pll_clk_enable(struct clk *c)
-{
-	u32 val;
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
-	val = clk_readl(c->reg + PLL_BASE);
-	val &= ~PLL_BASE_BYPASS;
-	val |= PLL_BASE_ENABLE;
-	clk_writel(val, c->reg + PLL_BASE);
-
-	tegra2_pll_clk_wait_for_lock(c);
-
-	return 0;
-}
-
-static void tegra2_pll_clk_disable(struct clk *c)
-{
-	u32 val;
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
-	val = clk_readl(c->reg);
-	val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
-	clk_writel(val, c->reg);
-}
-
-static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	u32 val;
-	unsigned long input_rate;
-	const struct clk_pll_freq_table *sel;
-
-	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
-
-	input_rate = clk_get_rate(c->parent);
-	for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
-		if (sel->input_rate == input_rate && sel->output_rate == rate) {
-			c->mul = sel->n;
-			c->div = sel->m * sel->p;
-
-			val = clk_readl(c->reg + PLL_BASE);
-			if (c->flags & PLL_FIXED)
-				val |= PLL_BASE_OVERRIDE;
-			val &= ~(PLL_BASE_DIVP_MASK | PLL_BASE_DIVN_MASK |
-				 PLL_BASE_DIVM_MASK);
-			val |= (sel->m << PLL_BASE_DIVM_SHIFT) |
-				(sel->n << PLL_BASE_DIVN_SHIFT);
-			BUG_ON(sel->p < 1 || sel->p > 2);
-			if (c->flags & PLLU) {
-				if (sel->p == 1)
-					val |= PLLU_BASE_POST_DIV;
-			} else {
-				if (sel->p == 2)
-					val |= 1 << PLL_BASE_DIVP_SHIFT;
-			}
-			clk_writel(val, c->reg + PLL_BASE);
-
-			if (c->flags & PLL_HAS_CPCON) {
-				val = clk_readl(c->reg + PLL_MISC(c));
-				val &= ~PLL_MISC_CPCON_MASK;
-				val |= sel->cpcon << PLL_MISC_CPCON_SHIFT;
-				clk_writel(val, c->reg + PLL_MISC(c));
-			}
-
-			if (c->state == ON)
-				tegra2_pll_clk_enable(c);
-
-			return 0;
-		}
-	}
-	return -EINVAL;
-}
-
-static struct clk_ops tegra_pll_ops = {
-	.init			= tegra2_pll_clk_init,
-	.enable			= tegra2_pll_clk_enable,
-	.disable		= tegra2_pll_clk_disable,
-	.set_rate		= tegra2_pll_clk_set_rate,
-};
-
-static void tegra2_pllx_clk_init(struct clk *c)
-{
-	tegra2_pll_clk_init(c);
-
-	if (tegra_sku_id == 7)
-		c->max_rate = 750000000;
-}
-
-static struct clk_ops tegra_pllx_ops = {
-	.init     = tegra2_pllx_clk_init,
-	.enable   = tegra2_pll_clk_enable,
-	.disable  = tegra2_pll_clk_disable,
-	.set_rate = tegra2_pll_clk_set_rate,
-};
-
-static int tegra2_plle_clk_enable(struct clk *c)
-{
-	u32 val;
-
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
-	mdelay(1);
-
-	val = clk_readl(c->reg + PLL_BASE);
-	if (!(val & PLLE_MISC_READY))
-		return -EBUSY;
-
-	val = clk_readl(c->reg + PLL_BASE);
-	val |= PLL_BASE_ENABLE | PLL_BASE_BYPASS;
-	clk_writel(val, c->reg + PLL_BASE);
-
-	return 0;
-}
-
-static struct clk_ops tegra_plle_ops = {
-	.init       = tegra2_pll_clk_init,
-	.enable     = tegra2_plle_clk_enable,
-	.set_rate   = tegra2_pll_clk_set_rate,
-};
-
-/* Clock divider ops */
-static void tegra2_pll_div_clk_init(struct clk *c)
-{
-	u32 val = clk_readl(c->reg);
-	u32 divu71;
-	val >>= c->reg_shift;
-	c->state = (val & PLL_OUT_CLKEN) ? ON : OFF;
-	if (!(val & PLL_OUT_RESET_DISABLE))
-		c->state = OFF;
-
-	if (c->flags & DIV_U71) {
-		divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
-		c->div = (divu71 + 2);
-		c->mul = 2;
-	} else if (c->flags & DIV_2) {
-		c->div = 2;
-		c->mul = 1;
-	} else {
-		c->div = 1;
-		c->mul = 1;
-	}
-}
-
-static int tegra2_pll_div_clk_enable(struct clk *c)
-{
-	u32 val;
-	u32 new_val;
-	unsigned long flags;
-
-	pr_debug("%s: %s\n", __func__, c->name);
-	if (c->flags & DIV_U71) {
-		spin_lock_irqsave(&clock_register_lock, flags);
-		val = clk_readl(c->reg);
-		new_val = val >> c->reg_shift;
-		new_val &= 0xFFFF;
-
-		new_val |= PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE;
-
-		val &= ~(0xFFFF << c->reg_shift);
-		val |= new_val << c->reg_shift;
-		clk_writel(val, c->reg);
-		spin_unlock_irqrestore(&clock_register_lock, flags);
-		return 0;
-	} else if (c->flags & DIV_2) {
-		BUG_ON(!(c->flags & PLLD));
-		spin_lock_irqsave(&clock_register_lock, flags);
-		val = clk_readl(c->reg);
-		val &= ~PLLD_MISC_DIV_RST;
-		clk_writel(val, c->reg);
-		spin_unlock_irqrestore(&clock_register_lock, flags);
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static void tegra2_pll_div_clk_disable(struct clk *c)
-{
-	u32 val;
-	u32 new_val;
-	unsigned long flags;
-
-	pr_debug("%s: %s\n", __func__, c->name);
-	if (c->flags & DIV_U71) {
-		spin_lock_irqsave(&clock_register_lock, flags);
-		val = clk_readl(c->reg);
-		new_val = val >> c->reg_shift;
-		new_val &= 0xFFFF;
-
-		new_val &= ~(PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE);
-
-		val &= ~(0xFFFF << c->reg_shift);
-		val |= new_val << c->reg_shift;
-		clk_writel(val, c->reg);
-		spin_unlock_irqrestore(&clock_register_lock, flags);
-	} else if (c->flags & DIV_2) {
-		BUG_ON(!(c->flags & PLLD));
-		spin_lock_irqsave(&clock_register_lock, flags);
-		val = clk_readl(c->reg);
-		val |= PLLD_MISC_DIV_RST;
-		clk_writel(val, c->reg);
-		spin_unlock_irqrestore(&clock_register_lock, flags);
-	}
-}
-
-static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	u32 val;
-	u32 new_val;
-	int divider_u71;
-	unsigned long parent_rate = clk_get_rate(c->parent);
-	unsigned long flags;
-
-	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
-	if (c->flags & DIV_U71) {
-		divider_u71 = clk_div71_get_divider(parent_rate, rate);
-		if (divider_u71 >= 0) {
-			spin_lock_irqsave(&clock_register_lock, flags);
-			val = clk_readl(c->reg);
-			new_val = val >> c->reg_shift;
-			new_val &= 0xFFFF;
-			if (c->flags & DIV_U71_FIXED)
-				new_val |= PLL_OUT_OVERRIDE;
-			new_val &= ~PLL_OUT_RATIO_MASK;
-			new_val |= divider_u71 << PLL_OUT_RATIO_SHIFT;
-
-			val &= ~(0xFFFF << c->reg_shift);
-			val |= new_val << c->reg_shift;
-			clk_writel(val, c->reg);
-			c->div = divider_u71 + 2;
-			c->mul = 2;
-			spin_unlock_irqrestore(&clock_register_lock, flags);
-			return 0;
-		}
-	} else if (c->flags & DIV_2) {
-		if (parent_rate == rate * 2)
-			return 0;
-	}
-	return -EINVAL;
-}
-
-static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
-{
-	int divider;
-	unsigned long parent_rate = clk_get_rate(c->parent);
-	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
-
-	if (c->flags & DIV_U71) {
-		divider = clk_div71_get_divider(parent_rate, rate);
-		if (divider < 0)
-			return divider;
-		return DIV_ROUND_UP(parent_rate * 2, divider + 2);
-	} else if (c->flags & DIV_2) {
-		return DIV_ROUND_UP(parent_rate, 2);
-	}
-	return -EINVAL;
-}
-
-static struct clk_ops tegra_pll_div_ops = {
-	.init			= tegra2_pll_div_clk_init,
-	.enable			= tegra2_pll_div_clk_enable,
-	.disable		= tegra2_pll_div_clk_disable,
-	.set_rate		= tegra2_pll_div_clk_set_rate,
-	.round_rate		= tegra2_pll_div_clk_round_rate,
-};
-
-/* Periph clk ops */
-
-static void tegra2_periph_clk_init(struct clk *c)
-{
-	u32 val = clk_readl(c->reg);
-	const struct clk_mux_sel *mux = NULL;
-	const struct clk_mux_sel *sel;
-	u32 shift;
-	u32 mask;
-
-	if (c->flags & MUX_PWM) {
-		shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
-		mask = PERIPH_CLK_SOURCE_PWM_MASK;
-	} else {
-		shift = PERIPH_CLK_SOURCE_SHIFT;
-		mask = PERIPH_CLK_SOURCE_MASK;
-	}
-
-	if (c->flags & MUX) {
-		for (sel = c->inputs; sel->input != NULL; sel++) {
-			if ((val & mask) >> shift == sel->value)
-				mux = sel;
-		}
-		BUG_ON(!mux);
-
-		c->parent = mux->input;
-	} else {
-		c->parent = c->inputs[0].input;
-	}
-
-	if (c->flags & DIV_U71) {
-		u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
-		c->div = divu71 + 2;
-		c->mul = 2;
-	} else if (c->flags & DIV_U16) {
-		u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
-		c->div = divu16 + 1;
-		c->mul = 1;
-	} else {
-		c->div = 1;
-		c->mul = 1;
-	}
-
-	c->state = ON;
-
-	if (!c->u.periph.clk_num)
-		return;
-
-	if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
-			PERIPH_CLK_TO_ENB_BIT(c)))
-		c->state = OFF;
-
-	if (!(c->flags & PERIPH_NO_RESET))
-		if (clk_readl(RST_DEVICES + PERIPH_CLK_TO_ENB_REG(c)) &
-				PERIPH_CLK_TO_ENB_BIT(c))
-			c->state = OFF;
-}
-
-static int tegra2_periph_clk_enable(struct clk *c)
-{
-	u32 val;
-	unsigned long flags;
-	int refcount;
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
-	if (!c->u.periph.clk_num)
-		return 0;
-
-	spin_lock_irqsave(&clock_register_lock, flags);
-
-	refcount = tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
-
-	if (refcount > 1)
-		goto out;
-
-	clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
-		CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
-	if (!(c->flags & PERIPH_NO_RESET) && !(c->flags & PERIPH_MANUAL_RESET))
-		clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
-			RST_DEVICES_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
-	if (c->flags & PERIPH_EMC_ENB) {
-		/* The EMC peripheral clock has 2 extra enable bits */
-		/* FIXME: Do they need to be disabled? */
-		val = clk_readl(c->reg);
-		val |= 0x3 << 24;
-		clk_writel(val, c->reg);
-	}
-
-out:
-	spin_unlock_irqrestore(&clock_register_lock, flags);
-
-	return 0;
-}
-
-static void tegra2_periph_clk_disable(struct clk *c)
-{
-	unsigned long flags;
-
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
-	if (!c->u.periph.clk_num)
-		return;
-
-	spin_lock_irqsave(&clock_register_lock, flags);
-
-	if (c->refcnt)
-		tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
-
-	if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] == 0)
-		clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
-			CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
-
-	spin_unlock_irqrestore(&clock_register_lock, flags);
-}
-
-static void tegra2_periph_clk_reset(struct clk *c, bool assert)
-{
-	unsigned long base = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
-
-	pr_debug("%s %s on clock %s\n", __func__,
-		 assert ? "assert" : "deassert", c->name);
-
-	BUG_ON(!c->u.periph.clk_num);
-
-	if (!(c->flags & PERIPH_NO_RESET))
-		clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
-			   base + PERIPH_CLK_TO_ENB_SET_REG(c));
-}
-
-static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p)
-{
-	u32 val;
-	const struct clk_mux_sel *sel;
-	u32 mask, shift;
-
-	pr_debug("%s: %s %s\n", __func__, c->name, p->name);
-
-	if (c->flags & MUX_PWM) {
-		shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
-		mask = PERIPH_CLK_SOURCE_PWM_MASK;
-	} else {
-		shift = PERIPH_CLK_SOURCE_SHIFT;
-		mask = PERIPH_CLK_SOURCE_MASK;
-	}
-
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->input == p) {
-			val = clk_readl(c->reg);
-			val &= ~mask;
-			val |= (sel->value) << shift;
-
-			if (c->refcnt)
-				clk_enable(p);
-
-			clk_writel(val, c->reg);
-
-			if (c->refcnt && c->parent)
-				clk_disable(c->parent);
-
-			clk_reparent(c, p);
-			return 0;
-		}
-	}
-
-	return -EINVAL;
-}
-
-static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	u32 val;
-	int divider;
-	unsigned long parent_rate = clk_get_rate(c->parent);
-
-	if (c->flags & DIV_U71) {
-		divider = clk_div71_get_divider(parent_rate, rate);
-		if (divider >= 0) {
-			val = clk_readl(c->reg);
-			val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
-			val |= divider;
-			clk_writel(val, c->reg);
-			c->div = divider + 2;
-			c->mul = 2;
-			return 0;
-		}
-	} else if (c->flags & DIV_U16) {
-		divider = clk_div16_get_divider(parent_rate, rate);
-		if (divider >= 0) {
-			val = clk_readl(c->reg);
-			val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
-			val |= divider;
-			clk_writel(val, c->reg);
-			c->div = divider + 1;
-			c->mul = 1;
-			return 0;
-		}
-	} else if (parent_rate <= rate) {
-		c->div = 1;
-		c->mul = 1;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static long tegra2_periph_clk_round_rate(struct clk *c,
-	unsigned long rate)
-{
-	int divider;
-	unsigned long parent_rate = clk_get_rate(c->parent);
-	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
-
-	if (c->flags & DIV_U71) {
-		divider = clk_div71_get_divider(parent_rate, rate);
-		if (divider < 0)
-			return divider;
-
-		return DIV_ROUND_UP(parent_rate * 2, divider + 2);
-	} else if (c->flags & DIV_U16) {
-		divider = clk_div16_get_divider(parent_rate, rate);
-		if (divider < 0)
-			return divider;
-		return DIV_ROUND_UP(parent_rate, divider + 1);
-	}
-	return -EINVAL;
-}
-
-static struct clk_ops tegra_periph_clk_ops = {
-	.init			= &tegra2_periph_clk_init,
-	.enable			= &tegra2_periph_clk_enable,
-	.disable		= &tegra2_periph_clk_disable,
-	.set_parent		= &tegra2_periph_clk_set_parent,
-	.set_rate		= &tegra2_periph_clk_set_rate,
-	.round_rate		= &tegra2_periph_clk_round_rate,
-	.reset			= &tegra2_periph_clk_reset,
-};
-
-/* The SDMMC controllers have extra bits in the clock source register that
- * adjust the delay between the clock and data to compenstate for delays
- * on the PCB. */
-void tegra2_sdmmc_tap_delay(struct clk *c, int delay)
-{
-	u32 reg;
-	unsigned long flags;
-
-	spin_lock_irqsave(&c->spinlock, flags);
-
-	delay = clamp(delay, 0, 15);
-	reg = clk_readl(c->reg);
-	reg &= ~SDMMC_CLK_INT_FB_DLY_MASK;
-	reg |= SDMMC_CLK_INT_FB_SEL;
-	reg |= delay << SDMMC_CLK_INT_FB_DLY_SHIFT;
-	clk_writel(reg, c->reg);
-
-	spin_unlock_irqrestore(&c->spinlock, flags);
-}
-
-/* External memory controller clock ops */
-static void tegra2_emc_clk_init(struct clk *c)
-{
-	tegra2_periph_clk_init(c);
-	c->max_rate = clk_get_rate_locked(c);
-}
-
-static long tegra2_emc_clk_round_rate(struct clk *c, unsigned long rate)
-{
-	long emc_rate;
-	long clk_rate;
-
-	/*
-	 * The slowest entry in the EMC clock table that is at least as
-	 * fast as rate.
-	 */
-	emc_rate = tegra_emc_round_rate(rate);
-	if (emc_rate < 0)
-		return c->max_rate;
-
-	/*
-	 * The fastest rate the PLL will generate that is at most the
-	 * requested rate.
-	 */
-	clk_rate = tegra2_periph_clk_round_rate(c, emc_rate);
-
-	/*
-	 * If this fails, and emc_rate > clk_rate, it's because the maximum
-	 * rate in the EMC tables is larger than the maximum rate of the EMC
-	 * clock. The EMC clock's max rate is the rate it was running when the
-	 * kernel booted. Such a mismatch is probably due to using the wrong
-	 * BCT, i.e. using a Tegra20 BCT with an EMC table written for Tegra25.
-	 */
-	WARN_ONCE(emc_rate != clk_rate,
-		"emc_rate %ld != clk_rate %ld",
-		emc_rate, clk_rate);
-
-	return emc_rate;
-}
-
-static int tegra2_emc_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	int ret;
-	/*
-	 * The Tegra2 memory controller has an interlock with the clock
-	 * block that allows memory shadowed registers to be updated,
-	 * and then transfer them to the main registers at the same
-	 * time as the clock update without glitches.
-	 */
-	ret = tegra_emc_set_rate(rate);
-	if (ret < 0)
-		return ret;
-
-	ret = tegra2_periph_clk_set_rate(c, rate);
-	udelay(1);
-
-	return ret;
-}
-
-static struct clk_ops tegra_emc_clk_ops = {
-	.init			= &tegra2_emc_clk_init,
-	.enable			= &tegra2_periph_clk_enable,
-	.disable		= &tegra2_periph_clk_disable,
-	.set_parent		= &tegra2_periph_clk_set_parent,
-	.set_rate		= &tegra2_emc_clk_set_rate,
-	.round_rate		= &tegra2_emc_clk_round_rate,
-	.reset			= &tegra2_periph_clk_reset,
-};
-
-/* Clock doubler ops */
-static void tegra2_clk_double_init(struct clk *c)
-{
-	c->mul = 2;
-	c->div = 1;
-	c->state = ON;
-
-	if (!c->u.periph.clk_num)
-		return;
-
-	if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
-			PERIPH_CLK_TO_ENB_BIT(c)))
-		c->state = OFF;
-};
-
-static int tegra2_clk_double_set_rate(struct clk *c, unsigned long rate)
-{
-	if (rate != 2 * clk_get_rate(c->parent))
-		return -EINVAL;
-	c->mul = 2;
-	c->div = 1;
-	return 0;
-}
-
-static struct clk_ops tegra_clk_double_ops = {
-	.init			= &tegra2_clk_double_init,
-	.enable			= &tegra2_periph_clk_enable,
-	.disable		= &tegra2_periph_clk_disable,
-	.set_rate		= &tegra2_clk_double_set_rate,
-};
-
-/* Audio sync clock ops */
-static void tegra2_audio_sync_clk_init(struct clk *c)
-{
-	int source;
-	const struct clk_mux_sel *sel;
-	u32 val = clk_readl(c->reg);
-	c->state = (val & (1<<4)) ? OFF : ON;
-	source = val & 0xf;
-	for (sel = c->inputs; sel->input != NULL; sel++)
-		if (sel->value == source)
-			break;
-	BUG_ON(sel->input == NULL);
-	c->parent = sel->input;
-}
-
-static int tegra2_audio_sync_clk_enable(struct clk *c)
-{
-	clk_writel(0, c->reg);
-	return 0;
-}
-
-static void tegra2_audio_sync_clk_disable(struct clk *c)
-{
-	clk_writel(1, c->reg);
-}
-
-static int tegra2_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
-{
-	u32 val;
-	const struct clk_mux_sel *sel;
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->input == p) {
-			val = clk_readl(c->reg);
-			val &= ~0xf;
-			val |= sel->value;
-
-			if (c->refcnt)
-				clk_enable(p);
-
-			clk_writel(val, c->reg);
-
-			if (c->refcnt && c->parent)
-				clk_disable(c->parent);
-
-			clk_reparent(c, p);
-			return 0;
-		}
-	}
-
-	return -EINVAL;
-}
-
-static struct clk_ops tegra_audio_sync_clk_ops = {
-	.init       = tegra2_audio_sync_clk_init,
-	.enable     = tegra2_audio_sync_clk_enable,
-	.disable    = tegra2_audio_sync_clk_disable,
-	.set_parent = tegra2_audio_sync_clk_set_parent,
-};
-
-/* cdev1 and cdev2 (dap_mclk1 and dap_mclk2) ops */
-
-static void tegra2_cdev_clk_init(struct clk *c)
-{
-	/* We could un-tristate the cdev1 or cdev2 pingroup here; this is
-	 * currently done in the pinmux code. */
-	c->state = ON;
-
-	BUG_ON(!c->u.periph.clk_num);
-
-	if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
-			PERIPH_CLK_TO_ENB_BIT(c)))
-		c->state = OFF;
-}
-
-static int tegra2_cdev_clk_enable(struct clk *c)
-{
-	BUG_ON(!c->u.periph.clk_num);
-
-	clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
-		CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
-	return 0;
-}
-
-static void tegra2_cdev_clk_disable(struct clk *c)
-{
-	BUG_ON(!c->u.periph.clk_num);
-
-	clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
-		CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
-}
-
-static struct clk_ops tegra_cdev_clk_ops = {
-	.init			= &tegra2_cdev_clk_init,
-	.enable			= &tegra2_cdev_clk_enable,
-	.disable		= &tegra2_cdev_clk_disable,
-};
-
-/* shared bus ops */
-/*
- * Some clocks may have multiple downstream users that need to request a
- * higher clock rate.  Shared bus clocks provide a unique shared_bus_user
- * clock to each user.  The frequency of the bus is set to the highest
- * enabled shared_bus_user clock, with a minimum value set by the
- * shared bus.
- */
-static int tegra_clk_shared_bus_update(struct clk *bus)
-{
-	struct clk *c;
-	unsigned long rate = bus->min_rate;
-
-	list_for_each_entry(c, &bus->shared_bus_list, u.shared_bus_user.node)
-		if (c->u.shared_bus_user.enabled)
-			rate = max(c->u.shared_bus_user.rate, rate);
-
-	if (rate == clk_get_rate_locked(bus))
-		return 0;
-
-	return clk_set_rate_locked(bus, rate);
-};
-
-static void tegra_clk_shared_bus_init(struct clk *c)
-{
-	unsigned long flags;
-
-	c->max_rate = c->parent->max_rate;
-	c->u.shared_bus_user.rate = c->parent->max_rate;
-	c->state = OFF;
-	c->set = true;
-
-	spin_lock_irqsave(&c->parent->spinlock, flags);
-
-	list_add_tail(&c->u.shared_bus_user.node,
-		&c->parent->shared_bus_list);
-
-	spin_unlock_irqrestore(&c->parent->spinlock, flags);
-}
-
-static int tegra_clk_shared_bus_set_rate(struct clk *c, unsigned long rate)
-{
-	unsigned long flags;
-	int ret;
-	long new_rate = rate;
-
-	new_rate = clk_round_rate(c->parent, new_rate);
-	if (new_rate < 0)
-		return new_rate;
-
-	spin_lock_irqsave(&c->parent->spinlock, flags);
-
-	c->u.shared_bus_user.rate = new_rate;
-	ret = tegra_clk_shared_bus_update(c->parent);
-
-	spin_unlock_irqrestore(&c->parent->spinlock, flags);
-
-	return ret;
-}
-
-static long tegra_clk_shared_bus_round_rate(struct clk *c, unsigned long rate)
-{
-	return clk_round_rate(c->parent, rate);
-}
-
-static int tegra_clk_shared_bus_enable(struct clk *c)
-{
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(&c->parent->spinlock, flags);
-
-	c->u.shared_bus_user.enabled = true;
-	ret = tegra_clk_shared_bus_update(c->parent);
-
-	spin_unlock_irqrestore(&c->parent->spinlock, flags);
-
-	return ret;
-}
-
-static void tegra_clk_shared_bus_disable(struct clk *c)
-{
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(&c->parent->spinlock, flags);
-
-	c->u.shared_bus_user.enabled = false;
-	ret = tegra_clk_shared_bus_update(c->parent);
-	WARN_ON_ONCE(ret);
-
-	spin_unlock_irqrestore(&c->parent->spinlock, flags);
-}
-
-static struct clk_ops tegra_clk_shared_bus_ops = {
-	.init = tegra_clk_shared_bus_init,
-	.enable = tegra_clk_shared_bus_enable,
-	.disable = tegra_clk_shared_bus_disable,
-	.set_rate = tegra_clk_shared_bus_set_rate,
-	.round_rate = tegra_clk_shared_bus_round_rate,
-};
-
-
-/* Clock definitions */
-static struct clk tegra_clk_32k = {
-	.name = "clk_32k",
-	.rate = 32768,
-	.ops  = NULL,
-	.max_rate = 32768,
-};
-
-static struct clk_pll_freq_table tegra_pll_s_freq_table[] = {
-	{32768, 12000000, 366, 1, 1, 0},
-	{32768, 13000000, 397, 1, 1, 0},
-	{32768, 19200000, 586, 1, 1, 0},
-	{32768, 26000000, 793, 1, 1, 0},
-	{0, 0, 0, 0, 0, 0},
-};
-
-static struct clk tegra_pll_s = {
-	.name      = "pll_s",
-	.flags     = PLL_ALT_MISC_REG,
-	.ops       = &tegra_pll_ops,
-	.parent    = &tegra_clk_32k,
-	.max_rate  = 26000000,
-	.reg       = 0xf0,
-	.u.pll = {
-		.input_min = 32768,
-		.input_max = 32768,
-		.cf_min    = 0, /* FIXME */
-		.cf_max    = 0, /* FIXME */
-		.vco_min   = 12000000,
-		.vco_max   = 26000000,
-		.freq_table = tegra_pll_s_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk_mux_sel tegra_clk_m_sel[] = {
-	{ .input = &tegra_clk_32k, .value = 0},
-	{ .input = &tegra_pll_s,  .value = 1},
-	{ NULL , 0},
-};
-
-static struct clk tegra_clk_m = {
-	.name      = "clk_m",
-	.flags     = ENABLE_ON_INIT,
-	.ops       = &tegra_clk_m_ops,
-	.inputs    = tegra_clk_m_sel,
-	.reg       = 0x1fc,
-	.reg_shift = 28,
-	.max_rate  = 26000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
-	{ 12000000, 600000000, 600, 12, 1, 8 },
-	{ 13000000, 600000000, 600, 13, 1, 8 },
-	{ 19200000, 600000000, 500, 16, 1, 6 },
-	{ 26000000, 600000000, 600, 26, 1, 8 },
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_c = {
-	.name      = "pll_c",
-	.flags	   = PLL_HAS_CPCON,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0x80,
-	.parent    = &tegra_clk_m,
-	.max_rate  = 600000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1400000000,
-		.freq_table = tegra_pll_c_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk tegra_pll_c_out1 = {
-	.name      = "pll_c_out1",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_U71,
-	.parent    = &tegra_pll_c,
-	.reg       = 0x84,
-	.reg_shift = 0,
-	.max_rate  = 600000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
-	{ 12000000, 666000000, 666, 12, 1, 8},
-	{ 13000000, 666000000, 666, 13, 1, 8},
-	{ 19200000, 666000000, 555, 16, 1, 8},
-	{ 26000000, 666000000, 666, 26, 1, 8},
-	{ 12000000, 600000000, 600, 12, 1, 8},
-	{ 13000000, 600000000, 600, 13, 1, 8},
-	{ 19200000, 600000000, 375, 12, 1, 6},
-	{ 26000000, 600000000, 600, 26, 1, 8},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_m = {
-	.name      = "pll_m",
-	.flags     = PLL_HAS_CPCON,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0x90,
-	.parent    = &tegra_clk_m,
-	.max_rate  = 800000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1200000000,
-		.freq_table = tegra_pll_m_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk tegra_pll_m_out1 = {
-	.name      = "pll_m_out1",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_U71,
-	.parent    = &tegra_pll_m,
-	.reg       = 0x94,
-	.reg_shift = 0,
-	.max_rate  = 600000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
-	{ 12000000, 216000000, 432, 12, 2, 8},
-	{ 13000000, 216000000, 432, 13, 2, 8},
-	{ 19200000, 216000000, 90,   4, 2, 1},
-	{ 26000000, 216000000, 432, 26, 2, 8},
-	{ 12000000, 432000000, 432, 12, 1, 8},
-	{ 13000000, 432000000, 432, 13, 1, 8},
-	{ 19200000, 432000000, 90,   4, 1, 1},
-	{ 26000000, 432000000, 432, 26, 1, 8},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_p = {
-	.name      = "pll_p",
-	.flags     = ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0xa0,
-	.parent    = &tegra_clk_m,
-	.max_rate  = 432000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1400000000,
-		.freq_table = tegra_pll_p_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk tegra_pll_p_out1 = {
-	.name      = "pll_p_out1",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
-	.parent    = &tegra_pll_p,
-	.reg       = 0xa4,
-	.reg_shift = 0,
-	.max_rate  = 432000000,
-};
-
-static struct clk tegra_pll_p_out2 = {
-	.name      = "pll_p_out2",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
-	.parent    = &tegra_pll_p,
-	.reg       = 0xa4,
-	.reg_shift = 16,
-	.max_rate  = 432000000,
-};
-
-static struct clk tegra_pll_p_out3 = {
-	.name      = "pll_p_out3",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
-	.parent    = &tegra_pll_p,
-	.reg       = 0xa8,
-	.reg_shift = 0,
-	.max_rate  = 432000000,
-};
-
-static struct clk tegra_pll_p_out4 = {
-	.name      = "pll_p_out4",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
-	.parent    = &tegra_pll_p,
-	.reg       = 0xa8,
-	.reg_shift = 16,
-	.max_rate  = 432000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
-	{ 28800000, 56448000, 49, 25, 1, 1},
-	{ 28800000, 73728000, 64, 25, 1, 1},
-	{ 28800000, 24000000,  5,  6, 1, 1},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_a = {
-	.name      = "pll_a",
-	.flags     = PLL_HAS_CPCON,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0xb0,
-	.parent    = &tegra_pll_p_out1,
-	.max_rate  = 73728000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1400000000,
-		.freq_table = tegra_pll_a_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk tegra_pll_a_out0 = {
-	.name      = "pll_a_out0",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_U71,
-	.parent    = &tegra_pll_a,
-	.reg       = 0xb4,
-	.reg_shift = 0,
-	.max_rate  = 73728000,
-};
-
-static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
-	{ 12000000, 216000000, 216, 12, 1, 4},
-	{ 13000000, 216000000, 216, 13, 1, 4},
-	{ 19200000, 216000000, 135, 12, 1, 3},
-	{ 26000000, 216000000, 216, 26, 1, 4},
-
-	{ 12000000, 594000000, 594, 12, 1, 8},
-	{ 13000000, 594000000, 594, 13, 1, 8},
-	{ 19200000, 594000000, 495, 16, 1, 8},
-	{ 26000000, 594000000, 594, 26, 1, 8},
-
-	{ 12000000, 1000000000, 1000, 12, 1, 12},
-	{ 13000000, 1000000000, 1000, 13, 1, 12},
-	{ 19200000, 1000000000, 625,  12, 1, 8},
-	{ 26000000, 1000000000, 1000, 26, 1, 12},
-
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_d = {
-	.name      = "pll_d",
-	.flags     = PLL_HAS_CPCON | PLLD,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0xd0,
-	.parent    = &tegra_clk_m,
-	.max_rate  = 1000000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 40000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 40000000,
-		.vco_max   = 1000000000,
-		.freq_table = tegra_pll_d_freq_table,
-		.lock_delay = 1000,
-	},
-};
-
-static struct clk tegra_pll_d_out0 = {
-	.name      = "pll_d_out0",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_2 | PLLD,
-	.parent    = &tegra_pll_d,
-	.max_rate  = 500000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
-	{ 12000000, 480000000, 960, 12, 2, 0},
-	{ 13000000, 480000000, 960, 13, 2, 0},
-	{ 19200000, 480000000, 200, 4,  2, 0},
-	{ 26000000, 480000000, 960, 26, 2, 0},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_u = {
-	.name      = "pll_u",
-	.flags     = PLLU,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0xc0,
-	.parent    = &tegra_clk_m,
-	.max_rate  = 480000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 40000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 480000000,
-		.vco_max   = 960000000,
-		.freq_table = tegra_pll_u_freq_table,
-		.lock_delay = 1000,
-	},
-};
-
-static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
-	/* 1 GHz */
-	{ 12000000, 1000000000, 1000, 12, 1, 12},
-	{ 13000000, 1000000000, 1000, 13, 1, 12},
-	{ 19200000, 1000000000, 625,  12, 1, 8},
-	{ 26000000, 1000000000, 1000, 26, 1, 12},
-
-	/* 912 MHz */
-	{ 12000000, 912000000,  912,  12, 1, 12},
-	{ 13000000, 912000000,  912,  13, 1, 12},
-	{ 19200000, 912000000,  760,  16, 1, 8},
-	{ 26000000, 912000000,  912,  26, 1, 12},
-
-	/* 816 MHz */
-	{ 12000000, 816000000,  816,  12, 1, 12},
-	{ 13000000, 816000000,  816,  13, 1, 12},
-	{ 19200000, 816000000,  680,  16, 1, 8},
-	{ 26000000, 816000000,  816,  26, 1, 12},
-
-	/* 760 MHz */
-	{ 12000000, 760000000,  760,  12, 1, 12},
-	{ 13000000, 760000000,  760,  13, 1, 12},
-	{ 19200000, 760000000,  950,  24, 1, 8},
-	{ 26000000, 760000000,  760,  26, 1, 12},
-
-	/* 750 MHz */
-	{ 12000000, 750000000,  750,  12, 1, 12},
-	{ 13000000, 750000000,  750,  13, 1, 12},
-	{ 19200000, 750000000,  625,  16, 1, 8},
-	{ 26000000, 750000000,  750,  26, 1, 12},
-
-	/* 608 MHz */
-	{ 12000000, 608000000,  608,  12, 1, 12},
-	{ 13000000, 608000000,  608,  13, 1, 12},
-	{ 19200000, 608000000,  380,  12, 1, 8},
-	{ 26000000, 608000000,  608,  26, 1, 12},
-
-	/* 456 MHz */
-	{ 12000000, 456000000,  456,  12, 1, 12},
-	{ 13000000, 456000000,  456,  13, 1, 12},
-	{ 19200000, 456000000,  380,  16, 1, 8},
-	{ 26000000, 456000000,  456,  26, 1, 12},
-
-	/* 312 MHz */
-	{ 12000000, 312000000,  312,  12, 1, 12},
-	{ 13000000, 312000000,  312,  13, 1, 12},
-	{ 19200000, 312000000,  260,  16, 1, 8},
-	{ 26000000, 312000000,  312,  26, 1, 12},
-
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_x = {
-	.name      = "pll_x",
-	.flags     = PLL_HAS_CPCON | PLL_ALT_MISC_REG,
-	.ops       = &tegra_pllx_ops,
-	.reg       = 0xe0,
-	.parent    = &tegra_clk_m,
-	.max_rate  = 1000000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1200000000,
-		.freq_table = tegra_pll_x_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
-	{ 12000000, 100000000,  200,  24, 1, 0 },
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_e = {
-	.name      = "pll_e",
-	.flags	   = PLL_ALT_MISC_REG,
-	.ops       = &tegra_plle_ops,
-	.parent    = &tegra_clk_m,
-	.reg       = 0xe8,
-	.max_rate  = 100000000,
-	.u.pll = {
-		.input_min = 12000000,
-		.input_max = 12000000,
-		.freq_table = tegra_pll_e_freq_table,
-	},
-};
-
-static struct clk tegra_clk_d = {
-	.name      = "clk_d",
-	.flags     = PERIPH_NO_RESET,
-	.ops       = &tegra_clk_double_ops,
-	.reg       = 0x34,
-	.reg_shift = 12,
-	.parent    = &tegra_clk_m,
-	.max_rate  = 52000000,
-	.u.periph  = {
-		.clk_num = 90,
-	},
-};
-
-/* dap_mclk1, belongs to the cdev1 pingroup. */
-static struct clk tegra_clk_cdev1 = {
-	.name      = "cdev1",
-	.ops       = &tegra_cdev_clk_ops,
-	.rate      = 26000000,
-	.max_rate  = 26000000,
-	.u.periph  = {
-		.clk_num = 94,
-	},
-};
-
-/* dap_mclk2, belongs to the cdev2 pingroup. */
-static struct clk tegra_clk_cdev2 = {
-	.name      = "cdev2",
-	.ops       = &tegra_cdev_clk_ops,
-	.rate      = 26000000,
-	.max_rate  = 26000000,
-	.u.periph  = {
-		.clk_num   = 93,
-	},
-};
-
-/* initialized before peripheral clocks */
-static struct clk_mux_sel mux_audio_sync_clk[8+1];
-static const struct audio_sources {
-	const char *name;
-	int value;
-} mux_audio_sync_clk_sources[] = {
-	{ .name = "spdif_in", .value = 0 },
-	{ .name = "i2s1", .value = 1 },
-	{ .name = "i2s2", .value = 2 },
-	{ .name = "pll_a_out0", .value = 4 },
-#if 0 /* FIXME: not implemented */
-	{ .name = "ac97", .value = 3 },
-	{ .name = "ext_audio_clk2", .value = 5 },
-	{ .name = "ext_audio_clk1", .value = 6 },
-	{ .name = "ext_vimclk", .value = 7 },
-#endif
-	{ NULL, 0 }
-};
-
-static struct clk tegra_clk_audio = {
-	.name      = "audio",
-	.inputs    = mux_audio_sync_clk,
-	.reg       = 0x38,
-	.max_rate  = 73728000,
-	.ops       = &tegra_audio_sync_clk_ops
-};
-
-static struct clk tegra_clk_audio_2x = {
-	.name      = "audio_2x",
-	.flags     = PERIPH_NO_RESET,
-	.max_rate  = 48000000,
-	.ops       = &tegra_clk_double_ops,
-	.reg       = 0x34,
-	.reg_shift = 8,
-	.parent    = &tegra_clk_audio,
-	.u.periph = {
-		.clk_num = 89,
-	},
-};
-
-static struct clk_lookup tegra_audio_clk_lookups[] = {
-	{ .con_id = "audio", .clk = &tegra_clk_audio },
-	{ .con_id = "audio_2x", .clk = &tegra_clk_audio_2x }
-};
-
-/* This is called after peripheral clocks are initialized, as the
- * audio_sync clock depends on some of the peripheral clocks.
- */
-
-static void init_audio_sync_clock_mux(void)
-{
-	int i;
-	struct clk_mux_sel *sel = mux_audio_sync_clk;
-	const struct audio_sources *src = mux_audio_sync_clk_sources;
-	struct clk_lookup *lookup;
-
-	for (i = 0; src->name; i++, sel++, src++) {
-		sel->input = tegra_get_clock_by_name(src->name);
-		if (!sel->input)
-			pr_err("%s: could not find clk %s\n", __func__,
-				src->name);
-		sel->value = src->value;
-	}
-
-	lookup = tegra_audio_clk_lookups;
-	for (i = 0; i < ARRAY_SIZE(tegra_audio_clk_lookups); i++, lookup++) {
-		clk_init(lookup->clk);
-		clkdev_add(lookup);
-	}
-}
-
-static struct clk_mux_sel mux_cclk[] = {
-	{ .input = &tegra_clk_m,	.value = 0},
-	{ .input = &tegra_pll_c,	.value = 1},
-	{ .input = &tegra_clk_32k,	.value = 2},
-	{ .input = &tegra_pll_m,	.value = 3},
-	{ .input = &tegra_pll_p,	.value = 4},
-	{ .input = &tegra_pll_p_out4,	.value = 5},
-	{ .input = &tegra_pll_p_out3,	.value = 6},
-	{ .input = &tegra_clk_d,	.value = 7},
-	{ .input = &tegra_pll_x,	.value = 8},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_sclk[] = {
-	{ .input = &tegra_clk_m,	.value = 0},
-	{ .input = &tegra_pll_c_out1,	.value = 1},
-	{ .input = &tegra_pll_p_out4,	.value = 2},
-	{ .input = &tegra_pll_p_out3,	.value = 3},
-	{ .input = &tegra_pll_p_out2,	.value = 4},
-	{ .input = &tegra_clk_d,	.value = 5},
-	{ .input = &tegra_clk_32k,	.value = 6},
-	{ .input = &tegra_pll_m_out1,	.value = 7},
-	{ NULL, 0},
-};
-
-static struct clk tegra_clk_cclk = {
-	.name	= "cclk",
-	.inputs	= mux_cclk,
-	.reg	= 0x20,
-	.ops	= &tegra_super_ops,
-	.max_rate = 1000000000,
-};
-
-static struct clk tegra_clk_sclk = {
-	.name	= "sclk",
-	.inputs	= mux_sclk,
-	.reg	= 0x28,
-	.ops	= &tegra_super_ops,
-	.max_rate = 240000000,
-	.min_rate = 120000000,
-};
-
-static struct clk tegra_clk_virtual_cpu = {
-	.name      = "cpu",
-	.parent    = &tegra_clk_cclk,
-	.ops       = &tegra_cpu_ops,
-	.max_rate  = 1000000000,
-	.u.cpu = {
-		.main      = &tegra_pll_x,
-		.backup    = &tegra_pll_p,
-	},
-};
-
-static struct clk tegra_clk_cop = {
-	.name      = "cop",
-	.parent    = &tegra_clk_sclk,
-	.ops       = &tegra_cop_ops,
-	.max_rate  = 240000000,
-};
-
-static struct clk tegra_clk_hclk = {
-	.name		= "hclk",
-	.flags		= DIV_BUS,
-	.parent		= &tegra_clk_sclk,
-	.reg		= 0x30,
-	.reg_shift	= 4,
-	.ops		= &tegra_bus_ops,
-	.max_rate       = 240000000,
-};
-
-static struct clk tegra_clk_pclk = {
-	.name		= "pclk",
-	.flags		= DIV_BUS,
-	.parent		= &tegra_clk_hclk,
-	.reg		= 0x30,
-	.reg_shift	= 0,
-	.ops		= &tegra_bus_ops,
-	.max_rate       = 120000000,
-};
-
-static struct clk tegra_clk_blink = {
-	.name		= "blink",
-	.parent		= &tegra_clk_32k,
-	.reg		= 0x40,
-	.ops		= &tegra_blink_clk_ops,
-	.max_rate	= 32768,
-};
-
-static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = {
-	{ .input = &tegra_pll_m, .value = 0},
-	{ .input = &tegra_pll_c, .value = 1},
-	{ .input = &tegra_pll_p, .value = 2},
-	{ .input = &tegra_pll_a_out0, .value = 3},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllm_pllc_pllp_clkm[] = {
-	{ .input = &tegra_pll_m, .value = 0},
-	{ .input = &tegra_pll_c, .value = 1},
-	{ .input = &tegra_pll_p, .value = 2},
-	{ .input = &tegra_clk_m, .value = 3},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_pllm_clkm[] = {
-	{ .input = &tegra_pll_p, .value = 0},
-	{ .input = &tegra_pll_c, .value = 1},
-	{ .input = &tegra_pll_m, .value = 2},
-	{ .input = &tegra_clk_m, .value = 3},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllaout0_audio2x_pllp_clkm[] = {
-	{.input = &tegra_pll_a_out0, .value = 0},
-	{.input = &tegra_clk_audio_2x, .value = 1},
-	{.input = &tegra_pll_p, .value = 2},
-	{.input = &tegra_clk_m, .value = 3},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllp_plld_pllc_clkm[] = {
-	{.input = &tegra_pll_p, .value = 0},
-	{.input = &tegra_pll_d_out0, .value = 1},
-	{.input = &tegra_pll_c, .value = 2},
-	{.input = &tegra_clk_m, .value = 3},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_audio_clkm_clk32[] = {
-	{.input = &tegra_pll_p,     .value = 0},
-	{.input = &tegra_pll_c,     .value = 1},
-	{.input = &tegra_clk_audio,     .value = 2},
-	{.input = &tegra_clk_m,     .value = 3},
-	{.input = &tegra_clk_32k,   .value = 4},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_pllm[] = {
-	{.input = &tegra_pll_p,     .value = 0},
-	{.input = &tegra_pll_c,     .value = 1},
-	{.input = &tegra_pll_m,     .value = 2},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_clk_m[] = {
-	{ .input = &tegra_clk_m, .value = 0},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllp_out3[] = {
-	{ .input = &tegra_pll_p_out3, .value = 0},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_plld[] = {
-	{ .input = &tegra_pll_d, .value = 0},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_clk_32k[] = {
-	{ .input = &tegra_clk_32k, .value = 0},
-	{ NULL, 0},
-};
-
-static struct clk_mux_sel mux_pclk[] = {
-	{ .input = &tegra_clk_pclk, .value = 0},
-	{ NULL, 0},
-};
-
-static struct clk tegra_clk_emc = {
-	.name = "emc",
-	.ops = &tegra_emc_clk_ops,
-	.reg = 0x19c,
-	.max_rate = 800000000,
-	.inputs = mux_pllm_pllc_pllp_clkm,
-	.flags = MUX | DIV_U71 | PERIPH_EMC_ENB,
-	.u.periph = {
-		.clk_num = 57,
-	},
-};
-
-#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
-	{						\
-		.name      = _name,			\
-		.lookup    = {				\
-			.dev_id    = _dev,		\
-			.con_id	   = _con,		\
-		},					\
-		.ops       = &tegra_periph_clk_ops,	\
-		.reg       = _reg,			\
-		.inputs    = _inputs,			\
-		.flags     = _flags,			\
-		.max_rate  = _max,			\
-		.u.periph = {				\
-			.clk_num   = _clk_num,		\
-		},					\
-	}
-
-#define SHARED_CLK(_name, _dev, _con, _parent)		\
-	{						\
-		.name      = _name,			\
-		.lookup    = {				\
-			.dev_id    = _dev,		\
-			.con_id    = _con,		\
-		},					\
-		.ops       = &tegra_clk_shared_bus_ops,	\
-		.parent = _parent,			\
-	}
-
-static struct clk tegra_list_clks[] = {
-	PERIPH_CLK("apbdma",	"tegra-apbdma",		NULL,	34,	0,	108000000, mux_pclk,			0),
-	PERIPH_CLK("rtc",	"rtc-tegra",		NULL,	4,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET),
-	PERIPH_CLK("timer",	"timer",		NULL,	5,	0,	26000000,  mux_clk_m,			0),
-	PERIPH_CLK("i2s1",	"tegra20-i2s.0",	NULL,	11,	0x100,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("i2s2",	"tegra20-i2s.1",	NULL,	18,	0x104,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("spdif_out",	"spdif_out",		NULL,	10,	0x108,	100000000, mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("spdif_in",	"spdif_in",		NULL,	10,	0x10c,	100000000, mux_pllp_pllc_pllm,		MUX | DIV_U71),
-	PERIPH_CLK("pwm",	"tegra-pwm",		NULL,	17,	0x110,	432000000, mux_pllp_pllc_audio_clkm_clk32,	MUX | DIV_U71 | MUX_PWM),
-	PERIPH_CLK("spi",	"spi",			NULL,	43,	0x114,	40000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("xio",	"xio",			NULL,	45,	0x120,	150000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("twc",	"twc",			NULL,	16,	0x12c,	150000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sbc1",	"spi_tegra.0",		NULL,	41,	0x134,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sbc2",	"spi_tegra.1",		NULL,	44,	0x118,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sbc3",	"spi_tegra.2",		NULL,	46,	0x11c,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sbc4",	"spi_tegra.3",		NULL,	68,	0x1b4,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("ide",	"ide",			NULL,	25,	0x144,	100000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("ndflash",	"tegra_nand",		NULL,	13,	0x160,	164000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("vfir",	"vfir",			NULL,	7,	0x168,	72000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sdmmc1",	"sdhci-tegra.0",	NULL,	14,	0x150,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("sdmmc2",	"sdhci-tegra.1",	NULL,	9,	0x154,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("sdmmc3",	"sdhci-tegra.2",	NULL,	69,	0x1bc,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("sdmmc4",	"sdhci-tegra.3",	NULL,	15,	0x164,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("vcp",	"tegra-avp",		"vcp",	29,	0,	250000000, mux_clk_m,			0),
-	PERIPH_CLK("bsea",	"tegra-avp",		"bsea",	62,	0,	250000000, mux_clk_m,			0),
-	PERIPH_CLK("bsev",	"tegra-aes",		"bsev",	63,	0,	250000000, mux_clk_m,			0),
-	PERIPH_CLK("vde",	"tegra-avp",		"vde",	61,	0x1c8,	250000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage and process_id */
-	PERIPH_CLK("csite",	"csite",		NULL,	73,	0x1d4,	144000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* max rate ??? */
-	/* FIXME: what is la? */
-	PERIPH_CLK("la",	"la",			NULL,	76,	0x1f8,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("owr",	"tegra_w1",		NULL,	71,	0x1cc,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("nor",	"nor",			NULL,	42,	0x1d0,	92000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("mipi",	"mipi",			NULL,	50,	0x174,	60000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("i2c1",	"tegra-i2c.0",		NULL,	12,	0x124,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16),
-	PERIPH_CLK("i2c2",	"tegra-i2c.1",		NULL,	54,	0x198,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16),
-	PERIPH_CLK("i2c3",	"tegra-i2c.2",		NULL,	67,	0x1b8,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16),
-	PERIPH_CLK("dvc",	"tegra-i2c.3",		NULL,	47,	0x128,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16),
-	PERIPH_CLK("i2c1_i2c",	"tegra-i2c.0",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0),
-	PERIPH_CLK("i2c2_i2c",	"tegra-i2c.1",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0),
-	PERIPH_CLK("i2c3_i2c",	"tegra-i2c.2",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0),
-	PERIPH_CLK("dvc_i2c",	"tegra-i2c.3",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0),
-	PERIPH_CLK("uarta",	"tegra-uart.0",		NULL,	6,	0x178,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
-	PERIPH_CLK("uartb",	"tegra-uart.1",		NULL,	7,	0x17c,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
-	PERIPH_CLK("uartc",	"tegra-uart.2",		NULL,	55,	0x1a0,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
-	PERIPH_CLK("uartd",	"tegra-uart.3",		NULL,	65,	0x1c0,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
-	PERIPH_CLK("uarte",	"tegra-uart.4",		NULL,	66,	0x1c4,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),
-	PERIPH_CLK("3d",	"3d",			NULL,	24,	0x158,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | PERIPH_MANUAL_RESET), /* scales with voltage and process_id */
-	PERIPH_CLK("2d",	"2d",			NULL,	21,	0x15c,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */
-	PERIPH_CLK("vi",	"tegra_camera",		"vi",	20,	0x148,	150000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */
-	PERIPH_CLK("vi_sensor",	"tegra_camera",		"vi_sensor",	20,	0x1a8,	150000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | PERIPH_NO_RESET), /* scales with voltage and process_id */
-	PERIPH_CLK("epp",	"epp",			NULL,	19,	0x16c,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */
-	PERIPH_CLK("mpe",	"mpe",			NULL,	60,	0x170,	250000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */
-	PERIPH_CLK("host1x",	"host1x",		NULL,	28,	0x180,	166000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */
-	PERIPH_CLK("cve",	"cve",			NULL,	49,	0x140,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("tvo",	"tvo",			NULL,	49,	0x188,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("hdmi",	"hdmi",			NULL,	51,	0x18c,	600000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("tvdac",	"tvdac",		NULL,	53,	0x194,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("disp1",	"tegradc.0",		NULL,	27,	0x138,	600000000, mux_pllp_plld_pllc_clkm,	MUX), /* scales with voltage and process_id */
-	PERIPH_CLK("disp2",	"tegradc.1",		NULL,	26,	0x13c,	600000000, mux_pllp_plld_pllc_clkm,	MUX), /* scales with voltage and process_id */
-	PERIPH_CLK("usbd",	"fsl-tegra-udc",	NULL,	22,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
-	PERIPH_CLK("usb2",	"tegra-ehci.1",		NULL,	58,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
-	PERIPH_CLK("usb3",	"tegra-ehci.2",		NULL,	59,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
-	PERIPH_CLK("dsi",	"dsi",			NULL,	48,	0,	500000000, mux_plld,			0), /* scales with voltage */
-	PERIPH_CLK("csi",	"tegra_camera",		"csi",	52,	0,	72000000,  mux_pllp_out3,		0),
-	PERIPH_CLK("isp",	"tegra_camera",		"isp",	23,	0,	150000000, mux_clk_m,			0), /* same frequency as VI */
-	PERIPH_CLK("csus",	"tegra_camera",		"csus",	92,	0,	150000000, mux_clk_m,			PERIPH_NO_RESET),
-	PERIPH_CLK("pex",       NULL,			"pex",  70,     0,	26000000,  mux_clk_m,			PERIPH_MANUAL_RESET),
-	PERIPH_CLK("afi",       NULL,			"afi",  72,     0,	26000000,  mux_clk_m,			PERIPH_MANUAL_RESET),
-	PERIPH_CLK("pcie_xclk", NULL,		  "pcie_xclk",  74,     0,	26000000,  mux_clk_m,			PERIPH_MANUAL_RESET),
-
-	SHARED_CLK("avp.sclk",	"tegra-avp",		"sclk",	&tegra_clk_sclk),
-	SHARED_CLK("avp.emc",	"tegra-avp",		"emc",	&tegra_clk_emc),
-	SHARED_CLK("cpu.emc",	"cpu",			"emc",	&tegra_clk_emc),
-	SHARED_CLK("disp1.emc",	"tegradc.0",		"emc",	&tegra_clk_emc),
-	SHARED_CLK("disp2.emc",	"tegradc.1",		"emc",	&tegra_clk_emc),
-	SHARED_CLK("hdmi.emc",	"hdmi",			"emc",	&tegra_clk_emc),
-	SHARED_CLK("host.emc",	"tegra_grhost",		"emc",	&tegra_clk_emc),
-	SHARED_CLK("usbd.emc",	"fsl-tegra-udc",	"emc",	&tegra_clk_emc),
-	SHARED_CLK("usb1.emc",	"tegra-ehci.0",		"emc",	&tegra_clk_emc),
-	SHARED_CLK("usb2.emc",	"tegra-ehci.1",		"emc",	&tegra_clk_emc),
-	SHARED_CLK("usb3.emc",	"tegra-ehci.2",		"emc",	&tegra_clk_emc),
-};
-
-#define CLK_DUPLICATE(_name, _dev, _con)		\
-	{						\
-		.name	= _name,			\
-		.lookup	= {				\
-			.dev_id	= _dev,			\
-			.con_id		= _con,		\
-		},					\
-	}
-
-/* Some clocks may be used by different drivers depending on the board
- * configuration.  List those here to register them twice in the clock lookup
- * table under two names.
- */
-static struct clk_duplicate tegra_clk_duplicates[] = {
-	CLK_DUPLICATE("uarta",  "serial8250.0", NULL),
-	CLK_DUPLICATE("uartb",  "serial8250.1", NULL),
-	CLK_DUPLICATE("uartc",  "serial8250.2", NULL),
-	CLK_DUPLICATE("uartd",  "serial8250.3", NULL),
-	CLK_DUPLICATE("uarte",  "serial8250.4", NULL),
-	CLK_DUPLICATE("usbd", "utmip-pad", NULL),
-	CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
-	CLK_DUPLICATE("usbd", "tegra-otg", NULL),
-	CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
-	CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
-	CLK_DUPLICATE("host1x", "tegra_grhost", "host1x"),
-	CLK_DUPLICATE("2d", "tegra_grhost", "gr2d"),
-	CLK_DUPLICATE("3d", "tegra_grhost", "gr3d"),
-	CLK_DUPLICATE("epp", "tegra_grhost", "epp"),
-	CLK_DUPLICATE("mpe", "tegra_grhost", "mpe"),
-	CLK_DUPLICATE("cop", "tegra-avp", "cop"),
-	CLK_DUPLICATE("vde", "tegra-aes", "vde"),
-};
-
-#define CLK(dev, con, ck)	\
-	{			\
-		.dev_id = dev,	\
-		.con_id = con,	\
-		.clk = ck,	\
-	}
-
-static struct clk *tegra_ptr_clks[] = {
-	&tegra_clk_32k,
-	&tegra_pll_s,
-	&tegra_clk_m,
-	&tegra_pll_m,
-	&tegra_pll_m_out1,
-	&tegra_pll_c,
-	&tegra_pll_c_out1,
-	&tegra_pll_p,
-	&tegra_pll_p_out1,
-	&tegra_pll_p_out2,
-	&tegra_pll_p_out3,
-	&tegra_pll_p_out4,
-	&tegra_pll_a,
-	&tegra_pll_a_out0,
-	&tegra_pll_d,
-	&tegra_pll_d_out0,
-	&tegra_pll_u,
-	&tegra_pll_x,
-	&tegra_pll_e,
-	&tegra_clk_cclk,
-	&tegra_clk_sclk,
-	&tegra_clk_hclk,
-	&tegra_clk_pclk,
-	&tegra_clk_d,
-	&tegra_clk_cdev1,
-	&tegra_clk_cdev2,
-	&tegra_clk_virtual_cpu,
-	&tegra_clk_blink,
-	&tegra_clk_cop,
-	&tegra_clk_emc,
-};
-
-static void tegra2_init_one_clock(struct clk *c)
-{
-	clk_init(c);
-	INIT_LIST_HEAD(&c->shared_bus_list);
-	if (!c->lookup.dev_id && !c->lookup.con_id)
-		c->lookup.con_id = c->name;
-	c->lookup.clk = c;
-	clkdev_add(&c->lookup);
-}
-
-void __init tegra2_init_clocks(void)
-{
-	int i;
-	struct clk *c;
-
-	for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
-		tegra2_init_one_clock(tegra_ptr_clks[i]);
-
-	for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
-		tegra2_init_one_clock(&tegra_list_clks[i]);
-
-	for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
-		c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
-		if (!c) {
-			pr_err("%s: Unknown duplicate clock %s\n", __func__,
-				tegra_clk_duplicates[i].name);
-			continue;
-		}
-
-		tegra_clk_duplicates[i].lookup.clk = c;
-		clkdev_add(&tegra_clk_duplicates[i].lookup);
-	}
-
-	init_audio_sync_clock_mux();
-}
-
-#ifdef CONFIG_PM
-static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM +
-			   PERIPH_CLK_SOURCE_NUM + 22];
-
-void tegra_clk_suspend(void)
-{
-	unsigned long off, i;
-	u32 *ctx = clk_rst_suspend;
-
-	*ctx++ = clk_readl(OSC_CTRL) & OSC_CTRL_MASK;
-	*ctx++ = clk_readl(tegra_pll_c.reg + PLL_BASE);
-	*ctx++ = clk_readl(tegra_pll_c.reg + PLL_MISC(&tegra_pll_c));
-	*ctx++ = clk_readl(tegra_pll_a.reg + PLL_BASE);
-	*ctx++ = clk_readl(tegra_pll_a.reg + PLL_MISC(&tegra_pll_a));
-	*ctx++ = clk_readl(tegra_pll_s.reg + PLL_BASE);
-	*ctx++ = clk_readl(tegra_pll_s.reg + PLL_MISC(&tegra_pll_s));
-	*ctx++ = clk_readl(tegra_pll_d.reg + PLL_BASE);
-	*ctx++ = clk_readl(tegra_pll_d.reg + PLL_MISC(&tegra_pll_d));
-	*ctx++ = clk_readl(tegra_pll_u.reg + PLL_BASE);
-	*ctx++ = clk_readl(tegra_pll_u.reg + PLL_MISC(&tegra_pll_u));
-
-	*ctx++ = clk_readl(tegra_pll_m_out1.reg);
-	*ctx++ = clk_readl(tegra_pll_a_out0.reg);
-	*ctx++ = clk_readl(tegra_pll_c_out1.reg);
-
-	*ctx++ = clk_readl(tegra_clk_cclk.reg);
-	*ctx++ = clk_readl(tegra_clk_cclk.reg + SUPER_CLK_DIVIDER);
-
-	*ctx++ = clk_readl(tegra_clk_sclk.reg);
-	*ctx++ = clk_readl(tegra_clk_sclk.reg + SUPER_CLK_DIVIDER);
-	*ctx++ = clk_readl(tegra_clk_pclk.reg);
-
-	*ctx++ = clk_readl(tegra_clk_audio.reg);
-
-	for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC;
-			off += 4) {
-		if (off == PERIPH_CLK_SOURCE_EMC)
-			continue;
-		*ctx++ = clk_readl(off);
-	}
-
-	off = RST_DEVICES;
-	for (i = 0; i < RST_DEVICES_NUM; i++, off += 4)
-		*ctx++ = clk_readl(off);
-
-	off = CLK_OUT_ENB;
-	for (i = 0; i < CLK_OUT_ENB_NUM; i++, off += 4)
-		*ctx++ = clk_readl(off);
-
-	*ctx++ = clk_readl(MISC_CLK_ENB);
-	*ctx++ = clk_readl(CLK_MASK_ARM);
-
-	BUG_ON(ctx - clk_rst_suspend != ARRAY_SIZE(clk_rst_suspend));
-}
-
-void tegra_clk_resume(void)
-{
-	unsigned long off, i;
-	const u32 *ctx = clk_rst_suspend;
-	u32 val;
-
-	val = clk_readl(OSC_CTRL) & ~OSC_CTRL_MASK;
-	val |= *ctx++;
-	clk_writel(val, OSC_CTRL);
-
-	clk_writel(*ctx++, tegra_pll_c.reg + PLL_BASE);
-	clk_writel(*ctx++, tegra_pll_c.reg + PLL_MISC(&tegra_pll_c));
-	clk_writel(*ctx++, tegra_pll_a.reg + PLL_BASE);
-	clk_writel(*ctx++, tegra_pll_a.reg + PLL_MISC(&tegra_pll_a));
-	clk_writel(*ctx++, tegra_pll_s.reg + PLL_BASE);
-	clk_writel(*ctx++, tegra_pll_s.reg + PLL_MISC(&tegra_pll_s));
-	clk_writel(*ctx++, tegra_pll_d.reg + PLL_BASE);
-	clk_writel(*ctx++, tegra_pll_d.reg + PLL_MISC(&tegra_pll_d));
-	clk_writel(*ctx++, tegra_pll_u.reg + PLL_BASE);
-	clk_writel(*ctx++, tegra_pll_u.reg + PLL_MISC(&tegra_pll_u));
-	udelay(1000);
-
-	clk_writel(*ctx++, tegra_pll_m_out1.reg);
-	clk_writel(*ctx++, tegra_pll_a_out0.reg);
-	clk_writel(*ctx++, tegra_pll_c_out1.reg);
-
-	clk_writel(*ctx++, tegra_clk_cclk.reg);
-	clk_writel(*ctx++, tegra_clk_cclk.reg + SUPER_CLK_DIVIDER);
-
-	clk_writel(*ctx++, tegra_clk_sclk.reg);
-	clk_writel(*ctx++, tegra_clk_sclk.reg + SUPER_CLK_DIVIDER);
-	clk_writel(*ctx++, tegra_clk_pclk.reg);
-
-	clk_writel(*ctx++, tegra_clk_audio.reg);
-
-	/* enable all clocks before configuring clock sources */
-	clk_writel(0xbffffff9ul, CLK_OUT_ENB);
-	clk_writel(0xfefffff7ul, CLK_OUT_ENB + 4);
-	clk_writel(0x77f01bfful, CLK_OUT_ENB + 8);
-	wmb();
-
-	for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC;
-			off += 4) {
-		if (off == PERIPH_CLK_SOURCE_EMC)
-			continue;
-		clk_writel(*ctx++, off);
-	}
-	wmb();
-
-	off = RST_DEVICES;
-	for (i = 0; i < RST_DEVICES_NUM; i++, off += 4)
-		clk_writel(*ctx++, off);
-	wmb();
-
-	off = CLK_OUT_ENB;
-	for (i = 0; i < CLK_OUT_ENB_NUM; i++, off += 4)
-		clk_writel(*ctx++, off);
-	wmb();
-
-	clk_writel(*ctx++, MISC_CLK_ENB);
-	clk_writel(*ctx++, CLK_MASK_ARM);
-}
-#endif
diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c
index 6674f10..7dad44d 100644
--- a/arch/arm/mach-tegra/tegra30_clocks.c
+++ b/arch/arm/mach-tegra/tegra30_clocks.c
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-tegra/tegra30_clocks.c
  *
- * Copyright (c) 2010-2011 NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2010-2012 NVIDIA CORPORATION.  All rights reserved.
  *
  * 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
@@ -35,6 +35,7 @@
 
 #include "clock.h"
 #include "fuse.h"
+#include "tegra_cpu_car.h"
 
 #define USE_PLL_LOCK_BITS 0
 
@@ -299,6 +300,16 @@
 /* FIXME: recommended safety delay after lock is detected */
 #define PLL_POST_LOCK_DELAY		100
 
+/* Tegra CPU clock and reset control regs */
+#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX		0x4c
+#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET	0x340
+#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR	0x344
+#define TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR	0x34c
+#define TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS	0x470
+
+#define CPU_CLOCK(cpu)	(0x1 << (8 + cpu))
+#define CPU_RESET(cpu)	(0x1111ul << (cpu))
+
 /**
 * Structure defining the fields for USB UTMI clocks Parameters.
 */
@@ -381,14 +392,16 @@ static int tegra_periph_clk_enable_refcount[CLK_OUT_ENB_NUM * 32];
 		udelay(2);						\
 	} while (0)
 
-
-static inline int clk_set_div(struct clk *c, u32 n)
+static inline int clk_set_div(struct clk_tegra *c, u32 n)
 {
-	return clk_set_rate(c, (clk_get_rate(c->parent) + n-1) / n);
+	struct clk *clk = c->hw.clk;
+
+	return clk_set_rate(clk,
+			(__clk_get_rate(__clk_get_parent(clk)) + n - 1) / n);
 }
 
 static inline u32 periph_clk_to_reg(
-	struct clk *c, u32 reg_L, u32 reg_V, int offs)
+	struct clk_tegra *c, u32 reg_L, u32 reg_V, int offs)
 {
 	u32 reg = c->u.periph.clk_num / 32;
 	BUG_ON(reg >= RST_DEVICES_NUM);
@@ -470,15 +483,32 @@ static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
 	return divider_u16 - 1;
 }
 
+static unsigned long tegra30_clk_fixed_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	return to_clk_tegra(hw)->fixed_rate;
+}
+
+struct clk_ops tegra30_clk_32k_ops = {
+	.recalc_rate = tegra30_clk_fixed_recalc_rate,
+};
+
 /* clk_m functions */
-static unsigned long tegra30_clk_m_autodetect_rate(struct clk *c)
+static unsigned long tegra30_clk_m_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	if (!to_clk_tegra(hw)->fixed_rate)
+		to_clk_tegra(hw)->fixed_rate = clk_measure_input_freq();
+	return to_clk_tegra(hw)->fixed_rate;
+}
+
+static void tegra30_clk_m_init(struct clk_hw *hw)
 {
 	u32 osc_ctrl = clk_readl(OSC_CTRL);
 	u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK;
 	u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK;
 
-	c->rate = clk_measure_input_freq();
-	switch (c->rate) {
+	switch (to_clk_tegra(hw)->fixed_rate) {
 	case 12000000:
 		auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
 		BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
@@ -508,46 +538,44 @@ static unsigned long tegra30_clk_m_autodetect_rate(struct clk *c)
 		BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_4);
 		break;
 	default:
-		pr_err("%s: Unexpected clock rate %ld", __func__, c->rate);
+		pr_err("%s: Unexpected clock rate %ld", __func__,
+				to_clk_tegra(hw)->fixed_rate);
 		BUG();
 	}
 	clk_writel(auto_clock_control, OSC_CTRL);
-	return c->rate;
 }
 
-static void tegra30_clk_m_init(struct clk *c)
-{
-	pr_debug("%s on clock %s\n", __func__, c->name);
-	tegra30_clk_m_autodetect_rate(c);
-}
+struct clk_ops tegra30_clk_m_ops = {
+	.init = tegra30_clk_m_init,
+	.recalc_rate = tegra30_clk_m_recalc_rate,
+};
 
-static int tegra30_clk_m_enable(struct clk *c)
+static unsigned long tegra30_clk_m_div_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
 {
-	pr_debug("%s on clock %s\n", __func__, c->name);
-	return 0;
-}
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = parent_rate;
 
-static void tegra30_clk_m_disable(struct clk *c)
-{
-	pr_debug("%s on clock %s\n", __func__, c->name);
-	WARN(1, "Attempting to disable main SoC clock\n");
-}
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
 
-static struct clk_ops tegra_clk_m_ops = {
-	.init		= tegra30_clk_m_init,
-	.enable		= tegra30_clk_m_enable,
-	.disable	= tegra30_clk_m_disable,
-};
+	return rate;
+}
 
-static struct clk_ops tegra_clk_m_div_ops = {
-	.enable		= tegra30_clk_m_enable,
+struct clk_ops tegra_clk_m_div_ops = {
+	.recalc_rate = tegra30_clk_m_div_recalc_rate,
 };
 
 /* PLL reference divider functions */
-static void tegra30_pll_ref_init(struct clk *c)
+static unsigned long tegra30_pll_ref_recalc_rate(struct clk_hw *hw,
+			unsigned long parent_rate)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long rate = parent_rate;
 	u32 pll_ref_div = clk_readl(OSC_CTRL) & OSC_CTRL_PLL_REF_DIV_MASK;
-	pr_debug("%s on clock %s\n", __func__, c->name);
 
 	switch (pll_ref_div) {
 	case OSC_CTRL_PLL_REF_DIV_1:
@@ -564,13 +592,18 @@ static void tegra30_pll_ref_init(struct clk *c)
 		BUG();
 	}
 	c->mul = 1;
-	c->state = ON;
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+
+	return rate;
 }
 
-static struct clk_ops tegra_pll_ref_ops = {
-	.init		= tegra30_pll_ref_init,
-	.enable		= tegra30_clk_m_enable,
-	.disable	= tegra30_clk_m_disable,
+struct clk_ops tegra_pll_ref_ops = {
+	.recalc_rate = tegra30_pll_ref_recalc_rate,
 };
 
 /* super clock functions */
@@ -581,56 +614,50 @@ static struct clk_ops tegra_pll_ref_ops = {
  * only when its parent is a fixed rate PLL, since we can't change PLL rate
  * in this case.
  */
-static void tegra30_super_clk_init(struct clk *c)
+static void tegra30_super_clk_init(struct clk_hw *hw)
 {
-	u32 val;
-	int source;
-	int shift;
-	const struct clk_mux_sel *sel;
-	val = clk_readl(c->reg + SUPER_CLK_MUX);
-	c->state = ON;
-	BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
-		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
-	shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
-		SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
-	source = (val >> shift) & SUPER_SOURCE_MASK;
-	if (c->flags & DIV_2)
-		source |= val & SUPER_LP_DIV2_BYPASS;
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->value == source)
-			break;
-	}
-	BUG_ON(sel->input == NULL);
-	c->parent = sel->input;
+	struct clk_tegra *c = to_clk_tegra(hw);
+	struct clk_tegra *p =
+			to_clk_tegra(__clk_get_hw(__clk_get_parent(hw->clk)));
 
+	c->state = ON;
 	if (c->flags & DIV_U71) {
 		/* Init safe 7.1 divider value (does not affect PLLX path) */
 		clk_writel(SUPER_CLOCK_DIV_U71_MIN << SUPER_CLOCK_DIV_U71_SHIFT,
 			   c->reg + SUPER_CLK_DIVIDER);
 		c->mul = 2;
 		c->div = 2;
-		if (!(c->parent->flags & PLLX))
+		if (!(p->flags & PLLX))
 			c->div += SUPER_CLOCK_DIV_U71_MIN;
 	} else
 		clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
 }
 
-static int tegra30_super_clk_enable(struct clk *c)
+static u8 tegra30_super_clk_get_parent(struct clk_hw *hw)
 {
-	return 0;
-}
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+	int source;
+	int shift;
 
-static void tegra30_super_clk_disable(struct clk *c)
-{
-	/* since tegra 3 has 2 CPU super clocks - low power lp-mode clock and
-	   geared up g-mode super clock - mode switch may request to disable
-	   either of them; accept request with no affect on h/w */
+	val = clk_readl(c->reg + SUPER_CLK_MUX);
+	BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
+		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
+	shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
+		SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
+	source = (val >> shift) & SUPER_SOURCE_MASK;
+	if (c->flags & DIV_2)
+		source |= val & SUPER_LP_DIV2_BYPASS;
+
+	return source;
 }
 
-static int tegra30_super_clk_set_parent(struct clk *c, struct clk *p)
+static int tegra30_super_clk_set_parent(struct clk_hw *hw, u8 index)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+	struct clk_tegra *p =
+			to_clk_tegra(__clk_get_hw(clk_get_parent(hw->clk)));
 	u32 val;
-	const struct clk_mux_sel *sel;
 	int shift;
 
 	val = clk_readl(c->reg + SUPER_CLK_MUX);
@@ -638,48 +665,36 @@ static int tegra30_super_clk_set_parent(struct clk *c, struct clk *p)
 		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
 	shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
 		SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->input == p) {
-			/* For LP mode super-clock switch between PLLX direct
-			   and divided-by-2 outputs is allowed only when other
-			   than PLLX clock source is current parent */
-			if ((c->flags & DIV_2) && (p->flags & PLLX) &&
-			    ((sel->value ^ val) & SUPER_LP_DIV2_BYPASS)) {
-				if (c->parent->flags & PLLX)
-					return -EINVAL;
-				val ^= SUPER_LP_DIV2_BYPASS;
-				clk_writel_delay(val, c->reg);
-			}
-			val &= ~(SUPER_SOURCE_MASK << shift);
-			val |= (sel->value & SUPER_SOURCE_MASK) << shift;
-
-			/* 7.1 divider for CPU super-clock does not affect
-			   PLLX path */
-			if (c->flags & DIV_U71) {
-				u32 div = 0;
-				if (!(p->flags & PLLX)) {
-					div = clk_readl(c->reg +
-							SUPER_CLK_DIVIDER);
-					div &= SUPER_CLOCK_DIV_U71_MASK;
-					div >>= SUPER_CLOCK_DIV_U71_SHIFT;
-				}
-				c->div = div + 2;
-				c->mul = 2;
-			}
-
-			if (c->refcnt)
-				clk_enable(p);
-
-			clk_writel_delay(val, c->reg);
 
-			if (c->refcnt && c->parent)
-				clk_disable(c->parent);
+	/* For LP mode super-clock switch between PLLX direct
+	   and divided-by-2 outputs is allowed only when other
+	   than PLLX clock source is current parent */
+	if ((c->flags & DIV_2) && (p->flags & PLLX) &&
+	    ((index ^ val) & SUPER_LP_DIV2_BYPASS)) {
+		if (p->flags & PLLX)
+			return -EINVAL;
+		val ^= SUPER_LP_DIV2_BYPASS;
+		clk_writel_delay(val, c->reg);
+	}
+	val &= ~(SUPER_SOURCE_MASK << shift);
+	val |= (index & SUPER_SOURCE_MASK) << shift;
 
-			clk_reparent(c, p);
-			return 0;
+	/* 7.1 divider for CPU super-clock does not affect
+	   PLLX path */
+	if (c->flags & DIV_U71) {
+		u32 div = 0;
+		if (!(p->flags & PLLX)) {
+			div = clk_readl(c->reg +
+					SUPER_CLK_DIVIDER);
+			div &= SUPER_CLOCK_DIV_U71_MASK;
+			div >>= SUPER_CLOCK_DIV_U71_SHIFT;
 		}
+		c->div = div + 2;
+		c->mul = 2;
 	}
-	return -EINVAL;
+	clk_writel_delay(val, c->reg);
+
+	return 0;
 }
 
 /*
@@ -691,10 +706,15 @@ static int tegra30_super_clk_set_parent(struct clk *c, struct clk *p)
  * rate of this PLL can't be changed, and it has many other children. In
  * this case use 7.1 fractional divider to adjust the super clock rate.
  */
-static int tegra30_super_clk_set_rate(struct clk *c, unsigned long rate)
+static int tegra30_super_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
 {
-	if ((c->flags & DIV_U71) && (c->parent->flags & PLL_FIXED)) {
-		int div = clk_div71_get_divider(c->parent->u.pll.fixed_rate,
+	struct clk_tegra *c = to_clk_tegra(hw);
+	struct clk *parent = __clk_get_parent(hw->clk);
+	struct clk_tegra *cparent = to_clk_tegra(__clk_get_hw(parent));
+
+	if ((c->flags & DIV_U71) && (cparent->flags & PLL_FIXED)) {
+		int div = clk_div71_get_divider(parent_rate,
 					rate, c->flags, ROUND_DIVIDER_DOWN);
 		div = max(div, SUPER_CLOCK_DIV_U71_MIN);
 
@@ -704,55 +724,86 @@ static int tegra30_super_clk_set_rate(struct clk *c, unsigned long rate)
 		c->mul = 2;
 		return 0;
 	}
-	return clk_set_rate(c->parent, rate);
+	return 0;
+}
+
+static unsigned long tegra30_super_clk_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = parent_rate;
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+
+	return rate;
+}
+
+static long tegra30_super_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	struct clk *parent = __clk_get_parent(hw->clk);
+	struct clk_tegra *cparent = to_clk_tegra(__clk_get_hw(parent));
+	int mul = 2;
+	int div;
+
+	if ((c->flags & DIV_U71) && (cparent->flags & PLL_FIXED)) {
+		div = clk_div71_get_divider(*prate,
+				rate, c->flags, ROUND_DIVIDER_DOWN);
+		div = max(div, SUPER_CLOCK_DIV_U71_MIN) + 2;
+		rate = *prate * mul;
+		rate += div - 1; /* round up */
+		do_div(rate, c->div);
+
+		return rate;
+	}
+	return *prate;
 }
 
-static struct clk_ops tegra_super_ops = {
-	.init			= tegra30_super_clk_init,
-	.enable			= tegra30_super_clk_enable,
-	.disable		= tegra30_super_clk_disable,
-	.set_parent		= tegra30_super_clk_set_parent,
-	.set_rate		= tegra30_super_clk_set_rate,
+struct clk_ops tegra30_super_ops = {
+	.init = tegra30_super_clk_init,
+	.set_parent = tegra30_super_clk_set_parent,
+	.get_parent = tegra30_super_clk_get_parent,
+	.recalc_rate = tegra30_super_clk_recalc_rate,
+	.round_rate = tegra30_super_clk_round_rate,
+	.set_rate = tegra30_super_clk_set_rate,
 };
 
-static int tegra30_twd_clk_set_rate(struct clk *c, unsigned long rate)
+static unsigned long tegra30_twd_clk_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
 {
-	/* The input value 'rate' is the clock rate of the CPU complex. */
-	c->rate = (rate * c->mul) / c->div;
-	return 0;
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = parent_rate;
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+
+	return rate;
 }
 
-static struct clk_ops tegra30_twd_ops = {
-	.set_rate	= tegra30_twd_clk_set_rate,
+struct clk_ops tegra30_twd_ops = {
+	.recalc_rate = tegra30_twd_clk_recalc_rate,
 };
 
 /* Blink output functions */
-
-static void tegra30_blink_clk_init(struct clk *c)
+static int tegra30_blink_clk_is_enabled(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 
 	val = pmc_readl(PMC_CTRL);
 	c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF;
-	c->mul = 1;
-	val = pmc_readl(c->reg);
-
-	if (val & PMC_BLINK_TIMER_ENB) {
-		unsigned int on_off;
-
-		on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
-			PMC_BLINK_TIMER_DATA_ON_MASK;
-		val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
-		val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
-		on_off += val;
-		/* each tick in the blink timer is 4 32KHz clocks */
-		c->div = on_off * 4;
-	} else {
-		c->div = 1;
-	}
+	return c->state;
 }
 
-static int tegra30_blink_clk_enable(struct clk *c)
+static int tegra30_blink_clk_enable(struct clk_hw *hw)
 {
 	u32 val;
 
@@ -765,7 +816,7 @@ static int tegra30_blink_clk_enable(struct clk *c)
 	return 0;
 }
 
-static void tegra30_blink_clk_disable(struct clk *c)
+static void tegra30_blink_clk_disable(struct clk_hw *hw)
 {
 	u32 val;
 
@@ -776,9 +827,11 @@ static void tegra30_blink_clk_disable(struct clk *c)
 	pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
 }
 
-static int tegra30_blink_clk_set_rate(struct clk *c, unsigned long rate)
+static int tegra30_blink_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
 {
-	unsigned long parent_rate = clk_get_rate(c->parent);
+	struct clk_tegra *c = to_clk_tegra(hw);
+
 	if (rate >= parent_rate) {
 		c->div = 1;
 		pmc_writel(0, c->reg);
@@ -801,41 +854,77 @@ static int tegra30_blink_clk_set_rate(struct clk *c, unsigned long rate)
 	return 0;
 }
 
-static struct clk_ops tegra_blink_clk_ops = {
-	.init			= &tegra30_blink_clk_init,
-	.enable			= &tegra30_blink_clk_enable,
-	.disable		= &tegra30_blink_clk_disable,
-	.set_rate		= &tegra30_blink_clk_set_rate,
-};
+static unsigned long tegra30_blink_clk_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = parent_rate;
+	u32 val;
+	u32 mul;
+	u32 div;
+	u32 on_off;
 
-/* PLL Functions */
-static int tegra30_pll_clk_wait_for_lock(struct clk *c, u32 lock_reg,
-					 u32 lock_bit)
+	mul = 1;
+	val = pmc_readl(c->reg);
+
+	if (val & PMC_BLINK_TIMER_ENB) {
+		on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
+			PMC_BLINK_TIMER_DATA_ON_MASK;
+		val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
+		val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
+		on_off += val;
+		/* each tick in the blink timer is 4 32KHz clocks */
+		div = on_off * 4;
+	} else {
+		div = 1;
+	}
+
+	if (mul != 0 && div != 0) {
+		rate *= mul;
+		rate += div - 1; /* round up */
+		do_div(rate, div);
+	}
+	return rate;
+}
+
+static long tegra30_blink_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
 {
-#if USE_PLL_LOCK_BITS
-	int i;
-	for (i = 0; i < c->u.pll.lock_delay; i++) {
-		if (clk_readl(lock_reg) & lock_bit) {
-			udelay(PLL_POST_LOCK_DELAY);
-			return 0;
-		}
-		udelay(2);		/* timeout = 2 * lock time */
+	int div;
+	int mul;
+	long round_rate = *prate;
+
+	mul = 1;
+
+	if (rate >= *prate) {
+		div = 1;
+	} else {
+		div = DIV_ROUND_UP(*prate / 8, rate);
+		div *= 8;
 	}
-	pr_err("Timed out waiting for lock bit on pll %s", c->name);
-	return -1;
-#endif
-	udelay(c->u.pll.lock_delay);
 
-	return 0;
+	round_rate *= mul;
+	round_rate += div - 1;
+	do_div(round_rate, div);
+
+	return round_rate;
 }
 
+struct clk_ops tegra30_blink_clk_ops = {
+	.is_enabled = tegra30_blink_clk_is_enabled,
+	.enable = tegra30_blink_clk_enable,
+	.disable = tegra30_blink_clk_disable,
+	.recalc_rate = tegra30_blink_clk_recalc_rate,
+	.round_rate = tegra30_blink_clk_round_rate,
+	.set_rate = tegra30_blink_clk_set_rate,
+};
 
-static void tegra30_utmi_param_configure(struct clk *c)
+static void tegra30_utmi_param_configure(struct clk_hw *hw)
 {
+	unsigned long main_rate =
+		__clk_get_rate(__clk_get_parent(__clk_get_parent(hw->clk)));
 	u32 reg;
 	int i;
-	unsigned long main_rate =
-		clk_get_rate(c->parent->parent);
 
 	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
 		if (main_rate == utmi_parameters[i].osc_frequency)
@@ -886,50 +975,52 @@ static void tegra30_utmi_param_configure(struct clk *c)
 	clk_writel(reg, UTMIP_PLL_CFG1);
 }
 
-static void tegra30_pll_clk_init(struct clk *c)
+/* PLL Functions */
+static int tegra30_pll_clk_wait_for_lock(struct clk_tegra *c, u32 lock_reg,
+					 u32 lock_bit)
+{
+	int ret = 0;
+
+#if USE_PLL_LOCK_BITS
+	int i;
+	for (i = 0; i < c->u.pll.lock_delay; i++) {
+		if (clk_readl(lock_reg) & lock_bit) {
+			udelay(PLL_POST_LOCK_DELAY);
+			return 0;
+		}
+		udelay(2);	/* timeout = 2 * lock time */
+	}
+	pr_err("Timed out waiting for lock bit on pll %s",
+					__clk_get_name(hw->clk));
+	ret = -1;
+#else
+	udelay(c->u.pll.lock_delay);
+#endif
+	return ret;
+}
+
+static int tegra30_pll_clk_is_enabled(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val = clk_readl(c->reg + PLL_BASE);
 
 	c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
+	return c->state;
+}
 
-	if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
-		const struct clk_pll_freq_table *sel;
-		unsigned long input_rate = clk_get_rate(c->parent);
-		for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
-			if (sel->input_rate == input_rate &&
-				sel->output_rate == c->u.pll.fixed_rate) {
-				c->mul = sel->n;
-				c->div = sel->m * sel->p;
-				return;
-			}
-		}
-		pr_err("Clock %s has unknown fixed frequency\n", c->name);
-		BUG();
-	} else if (val & PLL_BASE_BYPASS) {
-		c->mul = 1;
-		c->div = 1;
-	} else {
-		c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
-		c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
-		if (c->flags & PLLU)
-			c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
-		else
-			c->div *= (0x1 << ((val & PLL_BASE_DIVP_MASK) >>
-					PLL_BASE_DIVP_SHIFT));
-		if (c->flags & PLL_FIXED) {
-			unsigned long rate = clk_get_rate_locked(c);
-			BUG_ON(rate != c->u.pll.fixed_rate);
-		}
-	}
+static void tegra30_pll_clk_init(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
 
 	if (c->flags & PLLU)
-		tegra30_utmi_param_configure(c);
+		tegra30_utmi_param_configure(hw);
 }
 
-static int tegra30_pll_clk_enable(struct clk *c)
+static int tegra30_pll_clk_enable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
-	pr_debug("%s on clock %s\n", __func__, c->name);
+	pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
 
 #if USE_PLL_LOCK_BITS
 	val = clk_readl(c->reg + PLL_MISC(c));
@@ -952,10 +1043,11 @@ static int tegra30_pll_clk_enable(struct clk *c)
 	return 0;
 }
 
-static void tegra30_pll_clk_disable(struct clk *c)
+static void tegra30_pll_clk_disable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
-	pr_debug("%s on clock %s\n", __func__, c->name);
+	pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
 
 	val = clk_readl(c->reg);
 	val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
@@ -968,36 +1060,36 @@ static void tegra30_pll_clk_disable(struct clk *c)
 	}
 }
 
-static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate)
+static int tegra30_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val, p_div, old_base;
 	unsigned long input_rate;
 	const struct clk_pll_freq_table *sel;
 	struct clk_pll_freq_table cfg;
 
-	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
-
 	if (c->flags & PLL_FIXED) {
 		int ret = 0;
 		if (rate != c->u.pll.fixed_rate) {
 			pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
-			       __func__, c->name, c->u.pll.fixed_rate, rate);
+			       __func__, __clk_get_name(hw->clk),
+				c->u.pll.fixed_rate, rate);
 			ret = -EINVAL;
 		}
 		return ret;
 	}
 
 	if (c->flags & PLLM) {
-		if (rate != clk_get_rate_locked(c)) {
+		if (rate != __clk_get_rate(hw->clk)) {
 			pr_err("%s: Can not change memory %s rate in flight\n",
-			       __func__, c->name);
+				__func__, __clk_get_name(hw->clk));
 			return -EINVAL;
 		}
-		return 0;
 	}
 
 	p_div = 0;
-	input_rate = clk_get_rate(c->parent);
+	input_rate = parent_rate;
 
 	/* Check if the target rate is tabulated */
 	for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
@@ -1055,7 +1147,7 @@ static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate)
 		    (p_div > (PLL_BASE_DIVP_MASK >> PLL_BASE_DIVP_SHIFT)) ||
 		    (cfg.output_rate > c->u.pll.vco_max)) {
 			pr_err("%s: Failed to set %s out-of-table rate %lu\n",
-			       __func__, c->name, rate);
+			       __func__, __clk_get_name(hw->clk), rate);
 			return -EINVAL;
 		}
 		p_div <<= PLL_BASE_DIVP_SHIFT;
@@ -1073,7 +1165,7 @@ static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate)
 		return 0;
 
 	if (c->state == ON) {
-		tegra30_pll_clk_disable(c);
+		tegra30_pll_clk_disable(hw);
 		val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
 	}
 	clk_writel(val, c->reg + PLL_BASE);
@@ -1095,87 +1187,201 @@ static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate)
 	}
 
 	if (c->state == ON)
-		tegra30_pll_clk_enable(c);
-
-	return 0;
-}
-
-static struct clk_ops tegra_pll_ops = {
-	.init			= tegra30_pll_clk_init,
-	.enable			= tegra30_pll_clk_enable,
-	.disable		= tegra30_pll_clk_disable,
-	.set_rate		= tegra30_pll_clk_set_rate,
-};
-
-static int
-tegra30_plld_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
-{
-	u32 val, mask, reg;
+		tegra30_pll_clk_enable(hw);
 
-	switch (p) {
-	case TEGRA_CLK_PLLD_CSI_OUT_ENB:
-		mask = PLLD_BASE_CSI_CLKENABLE;
-		reg = c->reg + PLL_BASE;
-		break;
-	case TEGRA_CLK_PLLD_DSI_OUT_ENB:
-		mask = PLLD_MISC_DSI_CLKENABLE;
-		reg = c->reg + PLL_MISC(c);
-		break;
-	case TEGRA_CLK_PLLD_MIPI_MUX_SEL:
-		if (!(c->flags & PLL_ALT_MISC_REG)) {
-			mask = PLLD_BASE_DSIB_MUX_MASK;
-			reg = c->reg + PLL_BASE;
-			break;
-		}
-	/* fall through - error since PLLD2 does not have MUX_SEL control */
-	default:
-		return -EINVAL;
-	}
+	c->u.pll.fixed_rate = rate;
 
-	val = clk_readl(reg);
-	if (setting)
-		val |= mask;
-	else
-		val &= ~mask;
-	clk_writel(val, reg);
 	return 0;
 }
 
-static struct clk_ops tegra_plld_ops = {
-	.init			= tegra30_pll_clk_init,
-	.enable			= tegra30_pll_clk_enable,
-	.disable		= tegra30_pll_clk_disable,
-	.set_rate		= tegra30_pll_clk_set_rate,
-	.clk_cfg_ex		= tegra30_plld_clk_cfg_ex,
-};
-
-static void tegra30_plle_clk_init(struct clk *c)
+static long tegra30_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long input_rate = *prate;
+	unsigned long output_rate = *prate;
+	const struct clk_pll_freq_table *sel;
+	struct clk_pll_freq_table cfg;
+	int mul;
+	int div;
+	u32 p_div;
 	u32 val;
 
-	val = clk_readl(PLLE_AUX);
-	c->parent = (val & PLLE_AUX_PLLP_SEL) ?
-		tegra_get_clock_by_name("pll_p") :
-		tegra_get_clock_by_name("pll_ref");
+	if (c->flags & PLL_FIXED)
+		return c->u.pll.fixed_rate;
 
-	val = clk_readl(c->reg + PLL_BASE);
-	c->state = (val & PLLE_BASE_ENABLE) ? ON : OFF;
-	c->mul = (val & PLLE_BASE_DIVN_MASK) >> PLLE_BASE_DIVN_SHIFT;
-	c->div = (val & PLLE_BASE_DIVM_MASK) >> PLLE_BASE_DIVM_SHIFT;
-	c->div *= (val & PLLE_BASE_DIVP_MASK) >> PLLE_BASE_DIVP_SHIFT;
-}
+	if (c->flags & PLLM)
+		return __clk_get_rate(hw->clk);
 
-static void tegra30_plle_clk_disable(struct clk *c)
-{
-	u32 val;
-	pr_debug("%s on clock %s\n", __func__, c->name);
+	p_div = 0;
+	/* Check if the target rate is tabulated */
+	for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+		if (sel->input_rate == input_rate && sel->output_rate == rate) {
+			if (c->flags & PLLU) {
+				BUG_ON(sel->p < 1 || sel->p > 2);
+				if (sel->p == 1)
+					p_div = PLLU_BASE_POST_DIV;
+			} else {
+				BUG_ON(sel->p < 1);
+				for (val = sel->p; val > 1; val >>= 1)
+					p_div++;
+				p_div <<= PLL_BASE_DIVP_SHIFT;
+			}
+			break;
+		}
+	}
 
-	val = clk_readl(c->reg + PLL_BASE);
-	val &= ~(PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE);
-	clk_writel(val, c->reg + PLL_BASE);
-}
+	if (sel->input_rate == 0) {
+		unsigned long cfreq;
+		BUG_ON(c->flags & PLLU);
+		sel = &cfg;
 
-static void tegra30_plle_training(struct clk *c)
+		switch (input_rate) {
+		case 12000000:
+		case 26000000:
+			cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000;
+			break;
+		case 13000000:
+			cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000;
+			break;
+		case 16800000:
+		case 19200000:
+			cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000;
+			break;
+		default:
+			pr_err("%s: Unexpected reference rate %lu\n",
+			       __func__, input_rate);
+			BUG();
+		}
+
+		/* Raise VCO to guarantee 0.5% accuracy */
+		for (cfg.output_rate = rate; cfg.output_rate < 200 * cfreq;
+		      cfg.output_rate <<= 1)
+			p_div++;
+
+		cfg.p = 0x1 << p_div;
+		cfg.m = input_rate / cfreq;
+		cfg.n = cfg.output_rate / cfreq;
+	}
+
+	mul = sel->n;
+	div = sel->m * sel->p;
+
+	output_rate *= mul;
+	output_rate += div - 1; /* round up */
+	do_div(output_rate, div);
+
+	return output_rate;
+}
+
+static unsigned long tegra30_pll_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = parent_rate;
+	u32 val = clk_readl(c->reg + PLL_BASE);
+
+	if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
+		const struct clk_pll_freq_table *sel;
+		for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+			if (sel->input_rate == parent_rate &&
+				sel->output_rate == c->u.pll.fixed_rate) {
+				c->mul = sel->n;
+				c->div = sel->m * sel->p;
+				break;
+			}
+		}
+		pr_err("Clock %s has unknown fixed frequency\n",
+						__clk_get_name(hw->clk));
+		BUG();
+	} else if (val & PLL_BASE_BYPASS) {
+		c->mul = 1;
+		c->div = 1;
+	} else {
+		c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
+		c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
+		if (c->flags & PLLU)
+			c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
+		else
+			c->div *= (0x1 << ((val & PLL_BASE_DIVP_MASK) >>
+					PLL_BASE_DIVP_SHIFT));
+	}
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+
+	return rate;
+}
+
+struct clk_ops tegra30_pll_ops = {
+	.is_enabled = tegra30_pll_clk_is_enabled,
+	.init = tegra30_pll_clk_init,
+	.enable = tegra30_pll_clk_enable,
+	.disable = tegra30_pll_clk_disable,
+	.recalc_rate = tegra30_pll_recalc_rate,
+	.round_rate = tegra30_pll_round_rate,
+	.set_rate = tegra30_pll_clk_set_rate,
+};
+
+int tegra30_plld_clk_cfg_ex(struct clk_hw *hw,
+				enum tegra_clk_ex_param p, u32 setting)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val, mask, reg;
+
+	switch (p) {
+	case TEGRA_CLK_PLLD_CSI_OUT_ENB:
+		mask = PLLD_BASE_CSI_CLKENABLE;
+		reg = c->reg + PLL_BASE;
+		break;
+	case TEGRA_CLK_PLLD_DSI_OUT_ENB:
+		mask = PLLD_MISC_DSI_CLKENABLE;
+		reg = c->reg + PLL_MISC(c);
+		break;
+	case TEGRA_CLK_PLLD_MIPI_MUX_SEL:
+		if (!(c->flags & PLL_ALT_MISC_REG)) {
+			mask = PLLD_BASE_DSIB_MUX_MASK;
+			reg = c->reg + PLL_BASE;
+			break;
+		}
+	/* fall through - error since PLLD2 does not have MUX_SEL control */
+	default:
+		return -EINVAL;
+	}
+
+	val = clk_readl(reg);
+	if (setting)
+		val |= mask;
+	else
+		val &= ~mask;
+	clk_writel(val, reg);
+	return 0;
+}
+
+static int tegra30_plle_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+
+	val = clk_readl(c->reg + PLL_BASE);
+	c->state = (val & PLLE_BASE_ENABLE) ? ON : OFF;
+	return c->state;
+}
+
+static void tegra30_plle_clk_disable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val;
+
+	val = clk_readl(c->reg + PLL_BASE);
+	val &= ~(PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE);
+	clk_writel(val, c->reg + PLL_BASE);
+}
+
+static void tegra30_plle_training(struct clk_tegra *c)
 {
 	u32 val;
 
@@ -1198,12 +1404,15 @@ static void tegra30_plle_training(struct clk *c)
 	} while (!(val & PLLE_MISC_READY));
 }
 
-static int tegra30_plle_configure(struct clk *c, bool force_training)
+static int tegra30_plle_configure(struct clk_hw *hw, bool force_training)
 {
-	u32 val;
+	struct clk_tegra *c = to_clk_tegra(hw);
+	struct clk *parent = __clk_get_parent(hw->clk);
 	const struct clk_pll_freq_table *sel;
+	u32 val;
+
 	unsigned long rate = c->u.pll.fixed_rate;
-	unsigned long input_rate = clk_get_rate(c->parent);
+	unsigned long input_rate = __clk_get_rate(parent);
 
 	for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
 		if (sel->input_rate == input_rate && sel->output_rate == rate)
@@ -1214,7 +1423,7 @@ static int tegra30_plle_configure(struct clk *c, bool force_training)
 		return -ENOSYS;
 
 	/* disable PLLE, clear setup fiels */
-	tegra30_plle_clk_disable(c);
+	tegra30_plle_clk_disable(hw);
 
 	val = clk_readl(c->reg + PLL_MISC(c));
 	val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK);
@@ -1252,52 +1461,64 @@ static int tegra30_plle_configure(struct clk *c, bool force_training)
 	return 0;
 }
 
-static int tegra30_plle_clk_enable(struct clk *c)
+static int tegra30_plle_clk_enable(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+
+	return tegra30_plle_configure(hw, !c->set);
+}
+
+static unsigned long tegra30_plle_clk_recalc_rate(struct clk_hw *hw,
+			unsigned long parent_rate)
 {
-	pr_debug("%s on clock %s\n", __func__, c->name);
-	return tegra30_plle_configure(c, !c->set);
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long rate = parent_rate;
+	u32 val;
+
+	val = clk_readl(c->reg + PLL_BASE);
+	c->mul = (val & PLLE_BASE_DIVN_MASK) >> PLLE_BASE_DIVN_SHIFT;
+	c->div = (val & PLLE_BASE_DIVM_MASK) >> PLLE_BASE_DIVM_SHIFT;
+	c->div *= (val & PLLE_BASE_DIVP_MASK) >> PLLE_BASE_DIVP_SHIFT;
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+	return rate;
 }
 
-static struct clk_ops tegra_plle_ops = {
-	.init			= tegra30_plle_clk_init,
-	.enable			= tegra30_plle_clk_enable,
-	.disable		= tegra30_plle_clk_disable,
+struct clk_ops tegra30_plle_ops = {
+	.is_enabled = tegra30_plle_clk_is_enabled,
+	.enable = tegra30_plle_clk_enable,
+	.disable = tegra30_plle_clk_disable,
+	.recalc_rate = tegra30_plle_clk_recalc_rate,
 };
 
 /* Clock divider ops */
-static void tegra30_pll_div_clk_init(struct clk *c)
+static int tegra30_pll_div_clk_is_enabled(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+
 	if (c->flags & DIV_U71) {
-		u32 divu71;
 		u32 val = clk_readl(c->reg);
 		val >>= c->reg_shift;
 		c->state = (val & PLL_OUT_CLKEN) ? ON : OFF;
 		if (!(val & PLL_OUT_RESET_DISABLE))
 			c->state = OFF;
-
-		divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
-		c->div = (divu71 + 2);
-		c->mul = 2;
-	} else if (c->flags & DIV_2) {
-		c->state = ON;
-		if (c->flags & (PLLD | PLLX)) {
-			c->div = 2;
-			c->mul = 1;
-		} else
-			BUG();
 	} else {
 		c->state = ON;
-		c->div = 1;
-		c->mul = 1;
 	}
+	return c->state;
 }
 
-static int tegra30_pll_div_clk_enable(struct clk *c)
+static int tegra30_pll_div_clk_enable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 	u32 new_val;
 
-	pr_debug("%s: %s\n", __func__, c->name);
+	pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
 	if (c->flags & DIV_U71) {
 		val = clk_readl(c->reg);
 		new_val = val >> c->reg_shift;
@@ -1315,12 +1536,13 @@ static int tegra30_pll_div_clk_enable(struct clk *c)
 	return -EINVAL;
 }
 
-static void tegra30_pll_div_clk_disable(struct clk *c)
+static void tegra30_pll_div_clk_disable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 	u32 new_val;
 
-	pr_debug("%s: %s\n", __func__, c->name);
+	pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
 	if (c->flags & DIV_U71) {
 		val = clk_readl(c->reg);
 		new_val = val >> c->reg_shift;
@@ -1334,14 +1556,14 @@ static void tegra30_pll_div_clk_disable(struct clk *c)
 	}
 }
 
-static int tegra30_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
+static int tegra30_pll_div_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 	u32 new_val;
 	int divider_u71;
-	unsigned long parent_rate = clk_get_rate(c->parent);
 
-	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
 	if (c->flags & DIV_U71) {
 		divider_u71 = clk_div71_get_divider(
 			parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
@@ -1359,19 +1581,59 @@ static int tegra30_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
 			clk_writel_delay(val, c->reg);
 			c->div = divider_u71 + 2;
 			c->mul = 2;
+			c->fixed_rate = rate;
 			return 0;
 		}
-	} else if (c->flags & DIV_2)
-		return clk_set_rate(c->parent, rate * 2);
+	} else if (c->flags & DIV_2) {
+		c->fixed_rate = rate;
+		return 0;
+	}
 
 	return -EINVAL;
 }
 
-static long tegra30_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
+static unsigned long tegra30_pll_div_clk_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = parent_rate;
+
+	if (c->flags & DIV_U71) {
+		u32 divu71;
+		u32 val = clk_readl(c->reg);
+		val >>= c->reg_shift;
+
+		divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
+		c->div = (divu71 + 2);
+		c->mul = 2;
+	} else if (c->flags & DIV_2) {
+		if (c->flags & (PLLD | PLLX)) {
+			c->div = 2;
+			c->mul = 1;
+		} else
+			BUG();
+	} else {
+		c->div = 1;
+		c->mul = 1;
+	}
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+
+	return rate;
+}
+
+static long tegra30_pll_div_clk_round_rate(struct clk_hw *hw,
+				unsigned long rate, unsigned long *prate)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
 	int divider;
-	unsigned long parent_rate = clk_get_rate(c->parent);
-	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+	if (prate)
+		parent_rate = *prate;
 
 	if (c->flags & DIV_U71) {
 		divider = clk_div71_get_divider(
@@ -1379,23 +1641,25 @@ static long tegra30_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
 		if (divider < 0)
 			return divider;
 		return DIV_ROUND_UP(parent_rate * 2, divider + 2);
-	} else if (c->flags & DIV_2)
-		/* no rounding - fixed DIV_2 dividers pass rate to parent PLL */
+	} else if (c->flags & DIV_2) {
+		*prate = rate * 2;
 		return rate;
+	}
 
 	return -EINVAL;
 }
 
-static struct clk_ops tegra_pll_div_ops = {
-	.init			= tegra30_pll_div_clk_init,
-	.enable			= tegra30_pll_div_clk_enable,
-	.disable		= tegra30_pll_div_clk_disable,
-	.set_rate		= tegra30_pll_div_clk_set_rate,
-	.round_rate		= tegra30_pll_div_clk_round_rate,
+struct clk_ops tegra30_pll_div_ops = {
+	.is_enabled = tegra30_pll_div_clk_is_enabled,
+	.enable = tegra30_pll_div_clk_enable,
+	.disable = tegra30_pll_div_clk_disable,
+	.set_rate = tegra30_pll_div_clk_set_rate,
+	.recalc_rate = tegra30_pll_div_clk_recalc_rate,
+	.round_rate = tegra30_pll_div_clk_round_rate,
 };
 
 /* Periph clk ops */
-static inline u32 periph_clk_source_mask(struct clk *c)
+static inline u32 periph_clk_source_mask(struct clk_tegra *c)
 {
 	if (c->flags & MUX8)
 		return 7 << 29;
@@ -1409,7 +1673,7 @@ static inline u32 periph_clk_source_mask(struct clk *c)
 		return 3 << 30;
 }
 
-static inline u32 periph_clk_source_shift(struct clk *c)
+static inline u32 periph_clk_source_shift(struct clk_tegra *c)
 {
 	if (c->flags & MUX8)
 		return 29;
@@ -1423,47 +1687,9 @@ static inline u32 periph_clk_source_shift(struct clk *c)
 		return 30;
 }
 
-static void tegra30_periph_clk_init(struct clk *c)
+static int tegra30_periph_clk_is_enabled(struct clk_hw *hw)
 {
-	u32 val = clk_readl(c->reg);
-	const struct clk_mux_sel *mux = 0;
-	const struct clk_mux_sel *sel;
-	if (c->flags & MUX) {
-		for (sel = c->inputs; sel->input != NULL; sel++) {
-			if (((val & periph_clk_source_mask(c)) >>
-			    periph_clk_source_shift(c)) == sel->value)
-				mux = sel;
-		}
-		BUG_ON(!mux);
-
-		c->parent = mux->input;
-	} else {
-		c->parent = c->inputs[0].input;
-	}
-
-	if (c->flags & DIV_U71) {
-		u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
-		if ((c->flags & DIV_U71_UART) &&
-		    (!(val & PERIPH_CLK_UART_DIV_ENB))) {
-			divu71 = 0;
-		}
-		if (c->flags & DIV_U71_IDLE) {
-			val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK <<
-				PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
-			val |= (PERIPH_CLK_SOURCE_DIVIDLE_VAL <<
-				PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
-			clk_writel(val, c->reg);
-		}
-		c->div = divu71 + 2;
-		c->mul = 2;
-	} else if (c->flags & DIV_U16) {
-		u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
-		c->div = divu16 + 1;
-		c->mul = 1;
-	} else {
-		c->div = 1;
-		c->mul = 1;
-	}
+	struct clk_tegra *c = to_clk_tegra(hw);
 
 	c->state = ON;
 	if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
@@ -1471,11 +1697,12 @@ static void tegra30_periph_clk_init(struct clk *c)
 	if (!(c->flags & PERIPH_NO_RESET))
 		if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) & PERIPH_CLK_TO_BIT(c))
 			c->state = OFF;
+	return c->state;
 }
 
-static int tegra30_periph_clk_enable(struct clk *c)
+static int tegra30_periph_clk_enable(struct clk_hw *hw)
 {
-	pr_debug("%s on clock %s\n", __func__, c->name);
+	struct clk_tegra *c = to_clk_tegra(hw);
 
 	tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
 	if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1)
@@ -1494,31 +1721,29 @@ static int tegra30_periph_clk_enable(struct clk *c)
 	return 0;
 }
 
-static void tegra30_periph_clk_disable(struct clk *c)
+static void tegra30_periph_clk_disable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	unsigned long val;
-	pr_debug("%s on clock %s\n", __func__, c->name);
 
-	if (c->refcnt)
-		tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
+	tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
+
+	if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 0)
+		return;
 
-	if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] == 0) {
-		/* If peripheral is in the APB bus then read the APB bus to
-		 * flush the write operation in apb bus. This will avoid the
-		 * peripheral access after disabling clock*/
-		if (c->flags & PERIPH_ON_APB)
-			val = chipid_readl();
+	/* If peripheral is in the APB bus then read the APB bus to
+	 * flush the write operation in apb bus. This will avoid the
+	 * peripheral access after disabling clock*/
+	if (c->flags & PERIPH_ON_APB)
+		val = chipid_readl();
 
-		clk_writel_delay(
-			PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_CLR_REG(c));
-	}
+	clk_writel_delay(PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_CLR_REG(c));
 }
 
-static void tegra30_periph_clk_reset(struct clk *c, bool assert)
+void tegra30_periph_clk_reset(struct clk_hw *hw, bool assert)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	unsigned long val;
-	pr_debug("%s %s on clock %s\n", __func__,
-		 assert ? "assert" : "deassert", c->name);
 
 	if (!(c->flags & PERIPH_NO_RESET)) {
 		if (assert) {
@@ -1537,42 +1762,40 @@ static void tegra30_periph_clk_reset(struct clk *c, bool assert)
 	}
 }
 
-static int tegra30_periph_clk_set_parent(struct clk *c, struct clk *p)
+static int tegra30_periph_clk_set_parent(struct clk_hw *hw, u8 index)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
-	const struct clk_mux_sel *sel;
-	pr_debug("%s: %s %s\n", __func__, c->name, p->name);
 
 	if (!(c->flags & MUX))
-		return (p == c->parent) ? 0 : (-EINVAL);
-
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->input == p) {
-			val = clk_readl(c->reg);
-			val &= ~periph_clk_source_mask(c);
-			val |= (sel->value << periph_clk_source_shift(c));
+		return (index == 0) ? 0 : (-EINVAL);
 
-			if (c->refcnt)
-				clk_enable(p);
-
-			clk_writel_delay(val, c->reg);
+	val = clk_readl(c->reg);
+	val &= ~periph_clk_source_mask(c);
+	val |= (index << periph_clk_source_shift(c));
+	clk_writel_delay(val, c->reg);
+	return 0;
+}
 
-			if (c->refcnt && c->parent)
-				clk_disable(c->parent);
+static u8 tegra30_periph_clk_get_parent(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg);
+	int source  = (val & periph_clk_source_mask(c)) >>
+					periph_clk_source_shift(c);
 
-			clk_reparent(c, p);
-			return 0;
-		}
-	}
+	if (!(c->flags & MUX))
+		return 0;
 
-	return -EINVAL;
+	return source;
 }
 
-static int tegra30_periph_clk_set_rate(struct clk *c, unsigned long rate)
+static int tegra30_periph_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 	int divider;
-	unsigned long parent_rate = clk_get_rate(c->parent);
 
 	if (c->flags & DIV_U71) {
 		divider = clk_div71_get_divider(
@@ -1611,12 +1834,15 @@ static int tegra30_periph_clk_set_rate(struct clk *c, unsigned long rate)
 	return -EINVAL;
 }
 
-static long tegra30_periph_clk_round_rate(struct clk *c,
-	unsigned long rate)
+static long tegra30_periph_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+	unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
 	int divider;
-	unsigned long parent_rate = clk_get_rate(c->parent);
-	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+	if (prate)
+		parent_rate = *prate;
 
 	if (c->flags & DIV_U71) {
 		divider = clk_div71_get_divider(
@@ -1634,21 +1860,85 @@ static long tegra30_periph_clk_round_rate(struct clk *c,
 	return -EINVAL;
 }
 
-static struct clk_ops tegra_periph_clk_ops = {
-	.init			= &tegra30_periph_clk_init,
+static unsigned long tegra30_periph_clk_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = parent_rate;
+	u32 val = clk_readl(c->reg);
+
+	if (c->flags & DIV_U71) {
+		u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
+		if ((c->flags & DIV_U71_UART) &&
+		    (!(val & PERIPH_CLK_UART_DIV_ENB))) {
+			divu71 = 0;
+		}
+		if (c->flags & DIV_U71_IDLE) {
+			val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK <<
+				PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
+			val |= (PERIPH_CLK_SOURCE_DIVIDLE_VAL <<
+				PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
+			clk_writel(val, c->reg);
+		}
+		c->div = divu71 + 2;
+		c->mul = 2;
+	} else if (c->flags & DIV_U16) {
+		u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
+		c->div = divu16 + 1;
+		c->mul = 1;
+	} else {
+		c->div = 1;
+		c->mul = 1;
+	}
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+	return rate;
+}
+
+struct clk_ops tegra30_periph_clk_ops = {
+	.is_enabled = tegra30_periph_clk_is_enabled,
+	.enable = tegra30_periph_clk_enable,
+	.disable = tegra30_periph_clk_disable,
+	.set_parent = tegra30_periph_clk_set_parent,
+	.get_parent = tegra30_periph_clk_get_parent,
+	.set_rate = tegra30_periph_clk_set_rate,
+	.round_rate = tegra30_periph_clk_round_rate,
+	.recalc_rate = tegra30_periph_clk_recalc_rate,
+};
+
+static int tegra30_dsib_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk *d = clk_get_sys(NULL, "pll_d");
+	/* The DSIB parent selection bit is in PLLD base
+	   register - can not do direct r-m-w, must be
+	   protected by PLLD lock */
+	tegra_clk_cfg_ex(
+		d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, index);
+
+	return 0;
+}
+
+struct clk_ops tegra30_dsib_clk_ops = {
+	.is_enabled = tegra30_periph_clk_is_enabled,
 	.enable			= &tegra30_periph_clk_enable,
 	.disable		= &tegra30_periph_clk_disable,
-	.set_parent		= &tegra30_periph_clk_set_parent,
+	.set_parent		= &tegra30_dsib_clk_set_parent,
+	.get_parent		= &tegra30_periph_clk_get_parent,
 	.set_rate		= &tegra30_periph_clk_set_rate,
 	.round_rate		= &tegra30_periph_clk_round_rate,
-	.reset			= &tegra30_periph_clk_reset,
+	.recalc_rate		= &tegra30_periph_clk_recalc_rate,
 };
 
-
 /* Periph extended clock configuration ops */
-static int
-tegra30_vi_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+int tegra30_vi_clk_cfg_ex(struct clk_hw *hw,
+				enum tegra_clk_ex_param p, u32 setting)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+
 	if (p == TEGRA_CLK_VI_INP_SEL) {
 		u32 val = clk_readl(c->reg);
 		val &= ~PERIPH_CLK_VI_SEL_EX_MASK;
@@ -1660,20 +1950,11 @@ tegra30_vi_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
 	return -EINVAL;
 }
 
-static struct clk_ops tegra_vi_clk_ops = {
-	.init			= &tegra30_periph_clk_init,
-	.enable			= &tegra30_periph_clk_enable,
-	.disable		= &tegra30_periph_clk_disable,
-	.set_parent		= &tegra30_periph_clk_set_parent,
-	.set_rate		= &tegra30_periph_clk_set_rate,
-	.round_rate		= &tegra30_periph_clk_round_rate,
-	.clk_cfg_ex		= &tegra30_vi_clk_cfg_ex,
-	.reset			= &tegra30_periph_clk_reset,
-};
-
-static int
-tegra30_nand_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+int tegra30_nand_clk_cfg_ex(struct clk_hw *hw,
+				enum tegra_clk_ex_param p, u32 setting)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+
 	if (p == TEGRA_CLK_NAND_PAD_DIV2_ENB) {
 		u32 val = clk_readl(c->reg);
 		if (setting)
@@ -1686,21 +1967,11 @@ tegra30_nand_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
 	return -EINVAL;
 }
 
-static struct clk_ops tegra_nand_clk_ops = {
-	.init			= &tegra30_periph_clk_init,
-	.enable			= &tegra30_periph_clk_enable,
-	.disable		= &tegra30_periph_clk_disable,
-	.set_parent		= &tegra30_periph_clk_set_parent,
-	.set_rate		= &tegra30_periph_clk_set_rate,
-	.round_rate		= &tegra30_periph_clk_round_rate,
-	.clk_cfg_ex		= &tegra30_nand_clk_cfg_ex,
-	.reset			= &tegra30_periph_clk_reset,
-};
-
-
-static int
-tegra30_dtv_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+int tegra30_dtv_clk_cfg_ex(struct clk_hw *hw,
+				enum tegra_clk_ex_param p, u32 setting)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+
 	if (p == TEGRA_CLK_DTV_INVERT) {
 		u32 val = clk_readl(c->reg);
 		if (setting)
@@ -1713,91 +1984,27 @@ tegra30_dtv_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
 	return -EINVAL;
 }
 
-static struct clk_ops tegra_dtv_clk_ops = {
-	.init			= &tegra30_periph_clk_init,
-	.enable			= &tegra30_periph_clk_enable,
-	.disable		= &tegra30_periph_clk_disable,
-	.set_parent		= &tegra30_periph_clk_set_parent,
-	.set_rate		= &tegra30_periph_clk_set_rate,
-	.round_rate		= &tegra30_periph_clk_round_rate,
-	.clk_cfg_ex		= &tegra30_dtv_clk_cfg_ex,
-	.reset			= &tegra30_periph_clk_reset,
-};
-
-static int tegra30_dsib_clk_set_parent(struct clk *c, struct clk *p)
-{
-	const struct clk_mux_sel *sel;
-	struct clk *d = tegra_get_clock_by_name("pll_d");
-
-	pr_debug("%s: %s %s\n", __func__, c->name, p->name);
-
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->input == p) {
-			if (c->refcnt)
-				clk_enable(p);
-
-			/* The DSIB parent selection bit is in PLLD base
-			   register - can not do direct r-m-w, must be
-			   protected by PLLD lock */
-			tegra_clk_cfg_ex(
-				d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, sel->value);
-
-			if (c->refcnt && c->parent)
-				clk_disable(c->parent);
-
-			clk_reparent(c, p);
-			return 0;
-		}
-	}
-
-	return -EINVAL;
-}
-
-static struct clk_ops tegra_dsib_clk_ops = {
-	.init			= &tegra30_periph_clk_init,
-	.enable			= &tegra30_periph_clk_enable,
-	.disable		= &tegra30_periph_clk_disable,
-	.set_parent		= &tegra30_dsib_clk_set_parent,
-	.set_rate		= &tegra30_periph_clk_set_rate,
-	.round_rate		= &tegra30_periph_clk_round_rate,
-	.reset			= &tegra30_periph_clk_reset,
-};
-
-/* pciex clock support only reset function */
-static struct clk_ops tegra_pciex_clk_ops = {
-	.reset    = tegra30_periph_clk_reset,
-};
-
 /* Output clock ops */
 
 static DEFINE_SPINLOCK(clk_out_lock);
 
-static void tegra30_clk_out_init(struct clk *c)
+static int tegra30_clk_out_is_enabled(struct clk_hw *hw)
 {
-	const struct clk_mux_sel *mux = 0;
-	const struct clk_mux_sel *sel;
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val = pmc_readl(c->reg);
 
 	c->state = (val & (0x1 << c->u.periph.clk_num)) ? ON : OFF;
 	c->mul = 1;
 	c->div = 1;
-
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (((val & periph_clk_source_mask(c)) >>
-		     periph_clk_source_shift(c)) == sel->value)
-			mux = sel;
-	}
-	BUG_ON(!mux);
-	c->parent = mux->input;
+	return c->state;
 }
 
-static int tegra30_clk_out_enable(struct clk *c)
+static int tegra30_clk_out_enable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 	unsigned long flags;
 
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
 	spin_lock_irqsave(&clk_out_lock, flags);
 	val = pmc_readl(c->reg);
 	val |= (0x1 << c->u.periph.clk_num);
@@ -1807,13 +2014,12 @@ static int tegra30_clk_out_enable(struct clk *c)
 	return 0;
 }
 
-static void tegra30_clk_out_disable(struct clk *c)
+static void tegra30_clk_out_disable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 	unsigned long flags;
 
-	pr_debug("%s on clock %s\n", __func__, c->name);
-
 	spin_lock_irqsave(&clk_out_lock, flags);
 	val = pmc_readl(c->reg);
 	val &= ~(0x1 << c->u.periph.clk_num);
@@ -1821,59 +2027,59 @@ static void tegra30_clk_out_disable(struct clk *c)
 	spin_unlock_irqrestore(&clk_out_lock, flags);
 }
 
-static int tegra30_clk_out_set_parent(struct clk *c, struct clk *p)
+static int tegra30_clk_out_set_parent(struct clk_hw *hw, u8 index)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
 	unsigned long flags;
-	const struct clk_mux_sel *sel;
-
-	pr_debug("%s: %s %s\n", __func__, c->name, p->name);
 
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->input == p) {
-			if (c->refcnt)
-				clk_enable(p);
+	spin_lock_irqsave(&clk_out_lock, flags);
+	val = pmc_readl(c->reg);
+	val &= ~periph_clk_source_mask(c);
+	val |= (index << periph_clk_source_shift(c));
+	pmc_writel(val, c->reg);
+	spin_unlock_irqrestore(&clk_out_lock, flags);
 
-			spin_lock_irqsave(&clk_out_lock, flags);
-			val = pmc_readl(c->reg);
-			val &= ~periph_clk_source_mask(c);
-			val |= (sel->value << periph_clk_source_shift(c));
-			pmc_writel(val, c->reg);
-			spin_unlock_irqrestore(&clk_out_lock, flags);
+	return 0;
+}
 
-			if (c->refcnt && c->parent)
-				clk_disable(c->parent);
+static u8 tegra30_clk_out_get_parent(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = pmc_readl(c->reg);
+	int source;
 
-			clk_reparent(c, p);
-			return 0;
-		}
-	}
-	return -EINVAL;
+	source = (val & periph_clk_source_mask(c)) >>
+				periph_clk_source_shift(c);
+	return source;
 }
 
-static struct clk_ops tegra_clk_out_ops = {
-	.init			= &tegra30_clk_out_init,
-	.enable			= &tegra30_clk_out_enable,
-	.disable		= &tegra30_clk_out_disable,
-	.set_parent		= &tegra30_clk_out_set_parent,
+struct clk_ops tegra_clk_out_ops = {
+	.is_enabled = tegra30_clk_out_is_enabled,
+	.enable = tegra30_clk_out_enable,
+	.disable = tegra30_clk_out_disable,
+	.set_parent = tegra30_clk_out_set_parent,
+	.get_parent = tegra30_clk_out_get_parent,
+	.recalc_rate = tegra30_clk_fixed_recalc_rate,
 };
 
-
 /* Clock doubler ops */
-static void tegra30_clk_double_init(struct clk *c)
+static int tegra30_clk_double_is_enabled(struct clk_hw *hw)
 {
-	u32 val = clk_readl(c->reg);
-	c->mul = val & (0x1 << c->reg_shift) ? 1 : 2;
-	c->div = 1;
+	struct clk_tegra *c = to_clk_tegra(hw);
+
 	c->state = ON;
 	if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
 		c->state = OFF;
+	return c->state;
 };
 
-static int tegra30_clk_double_set_rate(struct clk *c, unsigned long rate)
+static int tegra30_clk_double_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
-	unsigned long parent_rate = clk_get_rate(c->parent);
+
 	if (rate == parent_rate) {
 		val = clk_readl(c->reg) | (0x1 << c->reg_shift);
 		clk_writel(val, c->reg);
@@ -1890,1215 +2096,200 @@ static int tegra30_clk_double_set_rate(struct clk *c, unsigned long rate)
 	return -EINVAL;
 }
 
-static struct clk_ops tegra_clk_double_ops = {
-	.init			= &tegra30_clk_double_init,
-	.enable			= &tegra30_periph_clk_enable,
-	.disable		= &tegra30_periph_clk_disable,
-	.set_rate		= &tegra30_clk_double_set_rate,
-};
+static unsigned long tegra30_clk_double_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u64 rate = parent_rate;
 
-/* Audio sync clock ops */
-static int tegra30_sync_source_set_rate(struct clk *c, unsigned long rate)
+	u32 val = clk_readl(c->reg);
+	c->mul = val & (0x1 << c->reg_shift) ? 1 : 2;
+	c->div = 1;
+
+	if (c->mul != 0 && c->div != 0) {
+		rate *= c->mul;
+		rate += c->div - 1; /* round up */
+		do_div(rate, c->div);
+	}
+
+	return rate;
+}
+
+static long tegra30_clk_double_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
 {
-	c->rate = rate;
-	return 0;
+	unsigned long output_rate = *prate;
+
+	do_div(output_rate, 2);
+	return output_rate;
 }
 
-static struct clk_ops tegra_sync_source_ops = {
-	.set_rate		= &tegra30_sync_source_set_rate,
+struct clk_ops tegra30_clk_double_ops = {
+	.is_enabled = tegra30_clk_double_is_enabled,
+	.enable = tegra30_periph_clk_enable,
+	.disable = tegra30_periph_clk_disable,
+	.recalc_rate = tegra30_clk_double_recalc_rate,
+	.round_rate = tegra30_clk_double_round_rate,
+	.set_rate = tegra30_clk_double_set_rate,
+};
+
+/* Audio sync clock ops */
+struct clk_ops tegra_sync_source_ops = {
+	.recalc_rate = tegra30_clk_fixed_recalc_rate,
 };
 
-static void tegra30_audio_sync_clk_init(struct clk *c)
+static int tegra30_audio_sync_clk_is_enabled(struct clk_hw *hw)
 {
-	int source;
-	const struct clk_mux_sel *sel;
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val = clk_readl(c->reg);
 	c->state = (val & AUDIO_SYNC_DISABLE_BIT) ? OFF : ON;
-	source = val & AUDIO_SYNC_SOURCE_MASK;
-	for (sel = c->inputs; sel->input != NULL; sel++)
-		if (sel->value == source)
-			break;
-	BUG_ON(sel->input == NULL);
-	c->parent = sel->input;
+	return c->state;
 }
 
-static int tegra30_audio_sync_clk_enable(struct clk *c)
+static int tegra30_audio_sync_clk_enable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val = clk_readl(c->reg);
 	clk_writel((val & (~AUDIO_SYNC_DISABLE_BIT)), c->reg);
 	return 0;
 }
 
-static void tegra30_audio_sync_clk_disable(struct clk *c)
+static void tegra30_audio_sync_clk_disable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val = clk_readl(c->reg);
 	clk_writel((val | AUDIO_SYNC_DISABLE_BIT), c->reg);
 }
 
-static int tegra30_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
+static int tegra30_audio_sync_clk_set_parent(struct clk_hw *hw, u8 index)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val;
-	const struct clk_mux_sel *sel;
-	for (sel = c->inputs; sel->input != NULL; sel++) {
-		if (sel->input == p) {
-			val = clk_readl(c->reg);
-			val &= ~AUDIO_SYNC_SOURCE_MASK;
-			val |= sel->value;
 
-			if (c->refcnt)
-				clk_enable(p);
-
-			clk_writel(val, c->reg);
+	val = clk_readl(c->reg);
+	val &= ~AUDIO_SYNC_SOURCE_MASK;
+	val |= index;
 
-			if (c->refcnt && c->parent)
-				clk_disable(c->parent);
+	clk_writel(val, c->reg);
+	return 0;
+}
 
-			clk_reparent(c, p);
-			return 0;
-		}
-	}
+static u8 tegra30_audio_sync_clk_get_parent(struct clk_hw *hw)
+{
+	struct clk_tegra *c = to_clk_tegra(hw);
+	u32 val = clk_readl(c->reg);
+	int source;
 
-	return -EINVAL;
+	source = val & AUDIO_SYNC_SOURCE_MASK;
+	return source;
 }
 
-static struct clk_ops tegra_audio_sync_clk_ops = {
-	.init       = tegra30_audio_sync_clk_init,
-	.enable     = tegra30_audio_sync_clk_enable,
-	.disable    = tegra30_audio_sync_clk_disable,
+struct clk_ops tegra30_audio_sync_clk_ops = {
+	.is_enabled = tegra30_audio_sync_clk_is_enabled,
+	.enable = tegra30_audio_sync_clk_enable,
+	.disable = tegra30_audio_sync_clk_disable,
 	.set_parent = tegra30_audio_sync_clk_set_parent,
+	.get_parent = tegra30_audio_sync_clk_get_parent,
+	.recalc_rate = tegra30_clk_fixed_recalc_rate,
 };
 
 /* cml0 (pcie), and cml1 (sata) clock ops */
-static void tegra30_cml_clk_init(struct clk *c)
+static int tegra30_cml_clk_is_enabled(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
 	u32 val = clk_readl(c->reg);
 	c->state = val & (0x1 << c->u.periph.clk_num) ? ON : OFF;
+	return c->state;
 }
 
-static int tegra30_cml_clk_enable(struct clk *c)
+static int tegra30_cml_clk_enable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+
 	u32 val = clk_readl(c->reg);
 	val |= (0x1 << c->u.periph.clk_num);
 	clk_writel(val, c->reg);
+
 	return 0;
 }
 
-static void tegra30_cml_clk_disable(struct clk *c)
+static void tegra30_cml_clk_disable(struct clk_hw *hw)
 {
+	struct clk_tegra *c = to_clk_tegra(hw);
+
 	u32 val = clk_readl(c->reg);
 	val &= ~(0x1 << c->u.periph.clk_num);
 	clk_writel(val, c->reg);
 }
 
-static struct clk_ops tegra_cml_clk_ops = {
-	.init			= &tegra30_cml_clk_init,
-	.enable			= &tegra30_cml_clk_enable,
-	.disable		= &tegra30_cml_clk_disable,
-};
-
-/* Clock definitions */
-static struct clk tegra_clk_32k = {
-	.name = "clk_32k",
-	.rate = 32768,
-	.ops  = NULL,
-	.max_rate = 32768,
-};
-
-static struct clk tegra_clk_m = {
-	.name      = "clk_m",
-	.flags     = ENABLE_ON_INIT,
-	.ops       = &tegra_clk_m_ops,
-	.reg       = 0x1fc,
-	.reg_shift = 28,
-	.max_rate  = 48000000,
-};
-
-static struct clk tegra_clk_m_div2 = {
-	.name      = "clk_m_div2",
-	.ops       = &tegra_clk_m_div_ops,
-	.parent    = &tegra_clk_m,
-	.mul       = 1,
-	.div       = 2,
-	.state     = ON,
-	.max_rate  = 24000000,
-};
-
-static struct clk tegra_clk_m_div4 = {
-	.name      = "clk_m_div4",
-	.ops       = &tegra_clk_m_div_ops,
-	.parent    = &tegra_clk_m,
-	.mul       = 1,
-	.div       = 4,
-	.state     = ON,
-	.max_rate  = 12000000,
-};
-
-static struct clk tegra_pll_ref = {
-	.name      = "pll_ref",
-	.flags     = ENABLE_ON_INIT,
-	.ops       = &tegra_pll_ref_ops,
-	.parent    = &tegra_clk_m,
-	.max_rate  = 26000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
-	{ 12000000, 1040000000, 520,  6, 1, 8},
-	{ 13000000, 1040000000, 480,  6, 1, 8},
-	{ 16800000, 1040000000, 495,  8, 1, 8},		/* actual: 1039.5 MHz */
-	{ 19200000, 1040000000, 325,  6, 1, 6},
-	{ 26000000, 1040000000, 520, 13, 1, 8},
-
-	{ 12000000, 832000000, 416,  6, 1, 8},
-	{ 13000000, 832000000, 832, 13, 1, 8},
-	{ 16800000, 832000000, 396,  8, 1, 8},		/* actual: 831.6 MHz */
-	{ 19200000, 832000000, 260,  6, 1, 8},
-	{ 26000000, 832000000, 416, 13, 1, 8},
-
-	{ 12000000, 624000000, 624, 12, 1, 8},
-	{ 13000000, 624000000, 624, 13, 1, 8},
-	{ 16800000, 600000000, 520, 14, 1, 8},
-	{ 19200000, 624000000, 520, 16, 1, 8},
-	{ 26000000, 624000000, 624, 26, 1, 8},
-
-	{ 12000000, 600000000, 600, 12, 1, 8},
-	{ 13000000, 600000000, 600, 13, 1, 8},
-	{ 16800000, 600000000, 500, 14, 1, 8},
-	{ 19200000, 600000000, 375, 12, 1, 6},
-	{ 26000000, 600000000, 600, 26, 1, 8},
-
-	{ 12000000, 520000000, 520, 12, 1, 8},
-	{ 13000000, 520000000, 520, 13, 1, 8},
-	{ 16800000, 520000000, 495, 16, 1, 8},		/* actual: 519.75 MHz */
-	{ 19200000, 520000000, 325, 12, 1, 6},
-	{ 26000000, 520000000, 520, 26, 1, 8},
-
-	{ 12000000, 416000000, 416, 12, 1, 8},
-	{ 13000000, 416000000, 416, 13, 1, 8},
-	{ 16800000, 416000000, 396, 16, 1, 8},		/* actual: 415.8 MHz */
-	{ 19200000, 416000000, 260, 12, 1, 6},
-	{ 26000000, 416000000, 416, 26, 1, 8},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_c = {
-	.name      = "pll_c",
-	.flags	   = PLL_HAS_CPCON,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0x80,
-	.parent    = &tegra_pll_ref,
-	.max_rate  = 1400000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1400000000,
-		.freq_table = tegra_pll_c_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk tegra_pll_c_out1 = {
-	.name      = "pll_c_out1",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_U71,
-	.parent    = &tegra_pll_c,
-	.reg       = 0x84,
-	.reg_shift = 0,
-	.max_rate  = 700000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
-	{ 12000000, 666000000, 666, 12, 1, 8},
-	{ 13000000, 666000000, 666, 13, 1, 8},
-	{ 16800000, 666000000, 555, 14, 1, 8},
-	{ 19200000, 666000000, 555, 16, 1, 8},
-	{ 26000000, 666000000, 666, 26, 1, 8},
-	{ 12000000, 600000000, 600, 12, 1, 8},
-	{ 13000000, 600000000, 600, 13, 1, 8},
-	{ 16800000, 600000000, 500, 14, 1, 8},
-	{ 19200000, 600000000, 375, 12, 1, 6},
-	{ 26000000, 600000000, 600, 26, 1, 8},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_m = {
-	.name      = "pll_m",
-	.flags     = PLL_HAS_CPCON | PLLM,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0x90,
-	.parent    = &tegra_pll_ref,
-	.max_rate  = 800000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1200000000,
-		.freq_table = tegra_pll_m_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk tegra_pll_m_out1 = {
-	.name      = "pll_m_out1",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_U71,
-	.parent    = &tegra_pll_m,
-	.reg       = 0x94,
-	.reg_shift = 0,
-	.max_rate  = 600000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
-	{ 12000000, 216000000, 432, 12, 2, 8},
-	{ 13000000, 216000000, 432, 13, 2, 8},
-	{ 16800000, 216000000, 360, 14, 2, 8},
-	{ 19200000, 216000000, 360, 16, 2, 8},
-	{ 26000000, 216000000, 432, 26, 2, 8},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_p = {
-	.name      = "pll_p",
-	.flags     = ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0xa0,
-	.parent    = &tegra_pll_ref,
-	.max_rate  = 432000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1400000000,
-		.freq_table = tegra_pll_p_freq_table,
-		.lock_delay = 300,
-		.fixed_rate = 408000000,
-	},
-};
-
-static struct clk tegra_pll_p_out1 = {
-	.name      = "pll_p_out1",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
-	.parent    = &tegra_pll_p,
-	.reg       = 0xa4,
-	.reg_shift = 0,
-	.max_rate  = 432000000,
-};
-
-static struct clk tegra_pll_p_out2 = {
-	.name      = "pll_p_out2",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
-	.parent    = &tegra_pll_p,
-	.reg       = 0xa4,
-	.reg_shift = 16,
-	.max_rate  = 432000000,
-};
-
-static struct clk tegra_pll_p_out3 = {
-	.name      = "pll_p_out3",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
-	.parent    = &tegra_pll_p,
-	.reg       = 0xa8,
-	.reg_shift = 0,
-	.max_rate  = 432000000,
-};
-
-static struct clk tegra_pll_p_out4 = {
-	.name      = "pll_p_out4",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
-	.parent    = &tegra_pll_p,
-	.reg       = 0xa8,
-	.reg_shift = 16,
-	.max_rate  = 432000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
-	{ 9600000, 564480000, 294, 5, 1, 4},
-	{ 9600000, 552960000, 288, 5, 1, 4},
-	{ 9600000, 24000000,  5,   2, 1, 1},
-
-	{ 28800000, 56448000, 49, 25, 1, 1},
-	{ 28800000, 73728000, 64, 25, 1, 1},
-	{ 28800000, 24000000,  5,  6, 1, 1},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_a = {
-	.name      = "pll_a",
-	.flags     = PLL_HAS_CPCON,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0xb0,
-	.parent    = &tegra_pll_p_out1,
-	.max_rate  = 700000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1400000000,
-		.freq_table = tegra_pll_a_freq_table,
-		.lock_delay = 300,
-	},
+struct clk_ops tegra_cml_clk_ops = {
+	.is_enabled = tegra30_cml_clk_is_enabled,
+	.enable = tegra30_cml_clk_enable,
+	.disable = tegra30_cml_clk_disable,
+	.recalc_rate = tegra30_clk_fixed_recalc_rate,
 };
 
-static struct clk tegra_pll_a_out0 = {
-	.name      = "pll_a_out0",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_U71,
-	.parent    = &tegra_pll_a,
-	.reg       = 0xb4,
-	.reg_shift = 0,
-	.max_rate  = 100000000,
+struct clk_ops tegra_pciex_clk_ops = {
+	.recalc_rate = tegra30_clk_fixed_recalc_rate,
 };
 
-static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
-	{ 12000000, 216000000, 216, 12, 1, 4},
-	{ 13000000, 216000000, 216, 13, 1, 4},
-	{ 16800000, 216000000, 180, 14, 1, 4},
-	{ 19200000, 216000000, 180, 16, 1, 4},
-	{ 26000000, 216000000, 216, 26, 1, 4},
-
-	{ 12000000, 594000000, 594, 12, 1, 8},
-	{ 13000000, 594000000, 594, 13, 1, 8},
-	{ 16800000, 594000000, 495, 14, 1, 8},
-	{ 19200000, 594000000, 495, 16, 1, 8},
-	{ 26000000, 594000000, 594, 26, 1, 8},
-
-	{ 12000000, 1000000000, 1000, 12, 1, 12},
-	{ 13000000, 1000000000, 1000, 13, 1, 12},
-	{ 19200000, 1000000000, 625,  12, 1, 8},
-	{ 26000000, 1000000000, 1000, 26, 1, 12},
-
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_d = {
-	.name      = "pll_d",
-	.flags     = PLL_HAS_CPCON | PLLD,
-	.ops       = &tegra_plld_ops,
-	.reg       = 0xd0,
-	.parent    = &tegra_pll_ref,
-	.max_rate  = 1000000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 40000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 40000000,
-		.vco_max   = 1000000000,
-		.freq_table = tegra_pll_d_freq_table,
-		.lock_delay = 1000,
-	},
-};
-
-static struct clk tegra_pll_d_out0 = {
-	.name      = "pll_d_out0",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_2 | PLLD,
-	.parent    = &tegra_pll_d,
-	.max_rate  = 500000000,
-};
-
-static struct clk tegra_pll_d2 = {
-	.name      = "pll_d2",
-	.flags     = PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLD,
-	.ops       = &tegra_plld_ops,
-	.reg       = 0x4b8,
-	.parent    = &tegra_pll_ref,
-	.max_rate  = 1000000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 40000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 40000000,
-		.vco_max   = 1000000000,
-		.freq_table = tegra_pll_d_freq_table,
-		.lock_delay = 1000,
-	},
-};
-
-static struct clk tegra_pll_d2_out0 = {
-	.name      = "pll_d2_out0",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_2 | PLLD,
-	.parent    = &tegra_pll_d2,
-	.max_rate  = 500000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
-	{ 12000000, 480000000, 960, 12, 2, 12},
-	{ 13000000, 480000000, 960, 13, 2, 12},
-	{ 16800000, 480000000, 400, 7,  2, 5},
-	{ 19200000, 480000000, 200, 4,  2, 3},
-	{ 26000000, 480000000, 960, 26, 2, 12},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_u = {
-	.name      = "pll_u",
-	.flags     = PLL_HAS_CPCON | PLLU,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0xc0,
-	.parent    = &tegra_pll_ref,
-	.max_rate  = 480000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 40000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 480000000,
-		.vco_max   = 960000000,
-		.freq_table = tegra_pll_u_freq_table,
-		.lock_delay = 1000,
-	},
-};
-
-static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
-	/* 1.7 GHz */
-	{ 12000000, 1700000000, 850,  6,  1, 8},
-	{ 13000000, 1700000000, 915,  7,  1, 8},	/* actual: 1699.2 MHz */
-	{ 16800000, 1700000000, 708,  7,  1, 8},	/* actual: 1699.2 MHz */
-	{ 19200000, 1700000000, 885,  10, 1, 8},	/* actual: 1699.2 MHz */
-	{ 26000000, 1700000000, 850,  13, 1, 8},
-
-	/* 1.6 GHz */
-	{ 12000000, 1600000000, 800,  6,  1, 8},
-	{ 13000000, 1600000000, 738,  6,  1, 8},	/* actual: 1599.0 MHz */
-	{ 16800000, 1600000000, 857,  9,  1, 8},	/* actual: 1599.7 MHz */
-	{ 19200000, 1600000000, 500,  6,  1, 8},
-	{ 26000000, 1600000000, 800,  13, 1, 8},
-
-	/* 1.5 GHz */
-	{ 12000000, 1500000000, 750,  6,  1, 8},
-	{ 13000000, 1500000000, 923,  8,  1, 8},	/* actual: 1499.8 MHz */
-	{ 16800000, 1500000000, 625,  7,  1, 8},
-	{ 19200000, 1500000000, 625,  8,  1, 8},
-	{ 26000000, 1500000000, 750,  13, 1, 8},
-
-	/* 1.4 GHz */
-	{ 12000000, 1400000000, 700,  6,  1, 8},
-	{ 13000000, 1400000000, 969,  9,  1, 8},	/* actual: 1399.7 MHz */
-	{ 16800000, 1400000000, 1000, 12, 1, 8},
-	{ 19200000, 1400000000, 875,  12, 1, 8},
-	{ 26000000, 1400000000, 700,  13, 1, 8},
-
-	/* 1.3 GHz */
-	{ 12000000, 1300000000, 975,  9,  1, 8},
-	{ 13000000, 1300000000, 1000, 10, 1, 8},
-	{ 16800000, 1300000000, 928,  12, 1, 8},	/* actual: 1299.2 MHz */
-	{ 19200000, 1300000000, 812,  12, 1, 8},	/* actual: 1299.2 MHz */
-	{ 26000000, 1300000000, 650,  13, 1, 8},
-
-	/* 1.2 GHz */
-	{ 12000000, 1200000000, 1000, 10, 1, 8},
-	{ 13000000, 1200000000, 923,  10, 1, 8},	/* actual: 1199.9 MHz */
-	{ 16800000, 1200000000, 1000, 14, 1, 8},
-	{ 19200000, 1200000000, 1000, 16, 1, 8},
-	{ 26000000, 1200000000, 600,  13, 1, 8},
-
-	/* 1.1 GHz */
-	{ 12000000, 1100000000, 825,  9,  1, 8},
-	{ 13000000, 1100000000, 846,  10, 1, 8},	/* actual: 1099.8 MHz */
-	{ 16800000, 1100000000, 982,  15, 1, 8},	/* actual: 1099.8 MHz */
-	{ 19200000, 1100000000, 859,  15, 1, 8},	/* actual: 1099.5 MHz */
-	{ 26000000, 1100000000, 550,  13, 1, 8},
-
-	/* 1 GHz */
-	{ 12000000, 1000000000, 1000, 12, 1, 8},
-	{ 13000000, 1000000000, 1000, 13, 1, 8},
-	{ 16800000, 1000000000, 833,  14, 1, 8},	/* actual: 999.6 MHz */
-	{ 19200000, 1000000000, 625,  12, 1, 8},
-	{ 26000000, 1000000000, 1000, 26, 1, 8},
-
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_x = {
-	.name      = "pll_x",
-	.flags     = PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLX,
-	.ops       = &tegra_pll_ops,
-	.reg       = 0xe0,
-	.parent    = &tegra_pll_ref,
-	.max_rate  = 1700000000,
-	.u.pll = {
-		.input_min = 2000000,
-		.input_max = 31000000,
-		.cf_min    = 1000000,
-		.cf_max    = 6000000,
-		.vco_min   = 20000000,
-		.vco_max   = 1700000000,
-		.freq_table = tegra_pll_x_freq_table,
-		.lock_delay = 300,
-	},
-};
-
-static struct clk tegra_pll_x_out0 = {
-	.name      = "pll_x_out0",
-	.ops       = &tegra_pll_div_ops,
-	.flags     = DIV_2 | PLLX,
-	.parent    = &tegra_pll_x,
-	.max_rate  = 850000000,
-};
-
-
-static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
-	/* PLLE special case: use cpcon field to store cml divider value */
-	{ 12000000,  100000000, 150, 1,  18, 11},
-	{ 216000000, 100000000, 200, 18, 24, 13},
-	{ 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_e = {
-	.name      = "pll_e",
-	.flags     = PLL_ALT_MISC_REG,
-	.ops       = &tegra_plle_ops,
-	.reg       = 0xe8,
-	.max_rate  = 100000000,
-	.u.pll = {
-		.input_min = 12000000,
-		.input_max = 216000000,
-		.cf_min    = 12000000,
-		.cf_max    = 12000000,
-		.vco_min   = 1200000000,
-		.vco_max   = 2400000000U,
-		.freq_table = tegra_pll_e_freq_table,
-		.lock_delay = 300,
-		.fixed_rate = 100000000,
-	},
-};
-
-static struct clk tegra_cml0_clk = {
-	.name      = "cml0",
-	.parent    = &tegra_pll_e,
-	.ops       = &tegra_cml_clk_ops,
-	.reg       = PLLE_AUX,
-	.max_rate  = 100000000,
-	.u.periph  = {
-		.clk_num = 0,
-	},
-};
-
-static struct clk tegra_cml1_clk = {
-	.name      = "cml1",
-	.parent    = &tegra_pll_e,
-	.ops       = &tegra_cml_clk_ops,
-	.reg       = PLLE_AUX,
-	.max_rate  = 100000000,
-	.u.periph  = {
-		.clk_num   = 1,
-	},
-};
-
-static struct clk tegra_pciex_clk = {
-	.name      = "pciex",
-	.parent    = &tegra_pll_e,
-	.ops       = &tegra_pciex_clk_ops,
-	.max_rate  = 100000000,
-	.u.periph  = {
-		.clk_num   = 74,
-	},
-};
-
-/* Audio sync clocks */
-#define SYNC_SOURCE(_id)				\
-	{						\
-		.name      = #_id "_sync",		\
-		.rate      = 24000000,			\
-		.max_rate  = 24000000,			\
-		.ops       = &tegra_sync_source_ops	\
-	}
-static struct clk tegra_sync_source_list[] = {
-	SYNC_SOURCE(spdif_in),
-	SYNC_SOURCE(i2s0),
-	SYNC_SOURCE(i2s1),
-	SYNC_SOURCE(i2s2),
-	SYNC_SOURCE(i2s3),
-	SYNC_SOURCE(i2s4),
-	SYNC_SOURCE(vimclk),
-};
-
-static struct clk_mux_sel mux_audio_sync_clk[] = {
-	{ .input = &tegra_sync_source_list[0],	.value = 0},
-	{ .input = &tegra_sync_source_list[1],	.value = 1},
-	{ .input = &tegra_sync_source_list[2],	.value = 2},
-	{ .input = &tegra_sync_source_list[3],	.value = 3},
-	{ .input = &tegra_sync_source_list[4],	.value = 4},
-	{ .input = &tegra_sync_source_list[5],	.value = 5},
-	{ .input = &tegra_pll_a_out0,		.value = 6},
-	{ .input = &tegra_sync_source_list[6],	.value = 7},
-	{ 0, 0 }
-};
-
-#define AUDIO_SYNC_CLK(_id, _index)			\
-	{						\
-		.name      = #_id,			\
-		.inputs    = mux_audio_sync_clk,	\
-		.reg       = 0x4A0 + (_index) * 4,	\
-		.max_rate  = 24000000,			\
-		.ops       = &tegra_audio_sync_clk_ops	\
-	}
-static struct clk tegra_clk_audio_list[] = {
-	AUDIO_SYNC_CLK(audio0, 0),
-	AUDIO_SYNC_CLK(audio1, 1),
-	AUDIO_SYNC_CLK(audio2, 2),
-	AUDIO_SYNC_CLK(audio3, 3),
-	AUDIO_SYNC_CLK(audio4, 4),
-	AUDIO_SYNC_CLK(audio, 5),	/* SPDIF */
-};
-
-#define AUDIO_SYNC_2X_CLK(_id, _index)				\
-	{							\
-		.name      = #_id "_2x",			\
-		.flags     = PERIPH_NO_RESET,			\
-		.max_rate  = 48000000,				\
-		.ops       = &tegra_clk_double_ops,		\
-		.reg       = 0x49C,				\
-		.reg_shift = 24 + (_index),			\
-		.parent    = &tegra_clk_audio_list[(_index)],	\
-		.u.periph = {					\
-			.clk_num = 113 + (_index),		\
-		},						\
-	}
-static struct clk tegra_clk_audio_2x_list[] = {
-	AUDIO_SYNC_2X_CLK(audio0, 0),
-	AUDIO_SYNC_2X_CLK(audio1, 1),
-	AUDIO_SYNC_2X_CLK(audio2, 2),
-	AUDIO_SYNC_2X_CLK(audio3, 3),
-	AUDIO_SYNC_2X_CLK(audio4, 4),
-	AUDIO_SYNC_2X_CLK(audio, 5),	/* SPDIF */
-};
+/* Tegra30 CPU clock and reset control functions */
+static void tegra30_wait_cpu_in_reset(u32 cpu)
+{
+	unsigned int reg;
 
-#define MUX_I2S_SPDIF(_id, _index)					\
-static struct clk_mux_sel mux_pllaout0_##_id##_2x_pllp_clkm[] = {	\
-	{.input = &tegra_pll_a_out0, .value = 0},			\
-	{.input = &tegra_clk_audio_2x_list[(_index)], .value = 1},	\
-	{.input = &tegra_pll_p, .value = 2},				\
-	{.input = &tegra_clk_m, .value = 3},				\
-	{ 0, 0},							\
-}
-MUX_I2S_SPDIF(audio0, 0);
-MUX_I2S_SPDIF(audio1, 1);
-MUX_I2S_SPDIF(audio2, 2);
-MUX_I2S_SPDIF(audio3, 3);
-MUX_I2S_SPDIF(audio4, 4);
-MUX_I2S_SPDIF(audio, 5);		/* SPDIF */
-
-/* External clock outputs (through PMC) */
-#define MUX_EXTERN_OUT(_id)						\
-static struct clk_mux_sel mux_clkm_clkm2_clkm4_extern##_id[] = {	\
-	{.input = &tegra_clk_m,		.value = 0},			\
-	{.input = &tegra_clk_m_div2,	.value = 1},			\
-	{.input = &tegra_clk_m_div4,	.value = 2},			\
-	{.input = NULL,			.value = 3}, /* placeholder */	\
-	{ 0, 0},							\
-}
-MUX_EXTERN_OUT(1);
-MUX_EXTERN_OUT(2);
-MUX_EXTERN_OUT(3);
-
-static struct clk_mux_sel *mux_extern_out_list[] = {
-	mux_clkm_clkm2_clkm4_extern1,
-	mux_clkm_clkm2_clkm4_extern2,
-	mux_clkm_clkm2_clkm4_extern3,
-};
+	do {
+		reg = readl(reg_clk_base +
+			    TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS);
+		cpu_relax();
+	} while (!(reg & (1 << cpu)));	/* check CPU been reset or not */
 
-#define CLK_OUT_CLK(_id)					\
-	{							\
-		.name      = "clk_out_" #_id,			\
-		.lookup    = {					\
-			.dev_id    = "clk_out_" #_id,		\
-			.con_id	   = "extern" #_id,		\
-		},						\
-		.ops       = &tegra_clk_out_ops,		\
-		.reg       = 0x1a8,				\
-		.inputs    = mux_clkm_clkm2_clkm4_extern##_id,	\
-		.flags     = MUX_CLK_OUT,			\
-		.max_rate  = 216000000,				\
-		.u.periph = {					\
-			.clk_num   = (_id - 1) * 8 + 2,		\
-		},						\
-	}
-static struct clk tegra_clk_out_list[] = {
-	CLK_OUT_CLK(1),
-	CLK_OUT_CLK(2),
-	CLK_OUT_CLK(3),
-};
+	return;
+}
 
-/* called after peripheral external clocks are initialized */
-static void init_clk_out_mux(void)
+static void tegra30_put_cpu_in_reset(u32 cpu)
 {
-	int i;
-	struct clk *c;
-
-	/* output clock con_id is the name of peripheral
-	   external clock connected to input 3 of the output mux */
-	for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++) {
-		c = tegra_get_clock_by_name(
-			tegra_clk_out_list[i].lookup.con_id);
-		if (!c)
-			pr_err("%s: could not find clk %s\n", __func__,
-			       tegra_clk_out_list[i].lookup.con_id);
-		mux_extern_out_list[i][3].input = c;
-	}
+	writel(CPU_RESET(cpu),
+	       reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
+	dmb();
 }
 
-/* Peripheral muxes */
-static struct clk_mux_sel mux_sclk[] = {
-	{ .input = &tegra_clk_m,	.value = 0},
-	{ .input = &tegra_pll_c_out1,	.value = 1},
-	{ .input = &tegra_pll_p_out4,	.value = 2},
-	{ .input = &tegra_pll_p_out3,	.value = 3},
-	{ .input = &tegra_pll_p_out2,	.value = 4},
-	/* { .input = &tegra_clk_d,	.value = 5}, - no use on tegra30 */
-	{ .input = &tegra_clk_32k,	.value = 6},
-	{ .input = &tegra_pll_m_out1,	.value = 7},
-	{ 0, 0},
-};
-
-static struct clk tegra_clk_sclk = {
-	.name	= "sclk",
-	.inputs	= mux_sclk,
-	.reg	= 0x28,
-	.ops	= &tegra_super_ops,
-	.max_rate = 334000000,
-	.min_rate = 40000000,
-};
-
-static struct clk tegra_clk_blink = {
-	.name		= "blink",
-	.parent		= &tegra_clk_32k,
-	.reg		= 0x40,
-	.ops		= &tegra_blink_clk_ops,
-	.max_rate	= 32768,
-};
-
-static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = {
-	{ .input = &tegra_pll_m, .value = 0},
-	{ .input = &tegra_pll_c, .value = 1},
-	{ .input = &tegra_pll_p, .value = 2},
-	{ .input = &tegra_pll_a_out0, .value = 3},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_pllm_clkm[] = {
-	{ .input = &tegra_pll_p, .value = 0},
-	{ .input = &tegra_pll_c, .value = 1},
-	{ .input = &tegra_pll_m, .value = 2},
-	{ .input = &tegra_clk_m, .value = 3},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_clkm[] = {
-	{ .input = &tegra_pll_p, .value = 0},
-	{ .input = &tegra_clk_m, .value = 3},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_plld_pllc_clkm[] = {
-	{.input = &tegra_pll_p, .value = 0},
-	{.input = &tegra_pll_d_out0, .value = 1},
-	{.input = &tegra_pll_c, .value = 2},
-	{.input = &tegra_clk_m, .value = 3},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = {
-	{.input = &tegra_pll_p, .value = 0},
-	{.input = &tegra_pll_m, .value = 1},
-	{.input = &tegra_pll_d_out0, .value = 2},
-	{.input = &tegra_pll_a_out0, .value = 3},
-	{.input = &tegra_pll_c, .value = 4},
-	{.input = &tegra_pll_d2_out0, .value = 5},
-	{.input = &tegra_clk_m, .value = 6},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_plla_pllc_pllp_clkm[] = {
-	{ .input = &tegra_pll_a_out0, .value = 0},
-	/* { .input = &tegra_pll_c, .value = 1}, no use on tegra30 */
-	{ .input = &tegra_pll_p, .value = 2},
-	{ .input = &tegra_clk_m, .value = 3},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_clk32_clkm[] = {
-	{.input = &tegra_pll_p,     .value = 0},
-	{.input = &tegra_pll_c,     .value = 1},
-	{.input = &tegra_clk_32k,   .value = 2},
-	{.input = &tegra_clk_m,     .value = 3},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_clkm_clk32[] = {
-	{.input = &tegra_pll_p,     .value = 0},
-	{.input = &tegra_pll_c,     .value = 1},
-	{.input = &tegra_clk_m,     .value = 2},
-	{.input = &tegra_clk_32k,   .value = 3},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_pllm[] = {
-	{.input = &tegra_pll_p,     .value = 0},
-	{.input = &tegra_pll_c,     .value = 1},
-	{.input = &tegra_pll_m,     .value = 2},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_clk_m[] = {
-	{ .input = &tegra_clk_m, .value = 0},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_out3[] = {
-	{ .input = &tegra_pll_p_out3, .value = 0},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_plld_out0[] = {
-	{ .input = &tegra_pll_d_out0, .value = 0},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_plld_out0_plld2_out0[] = {
-	{ .input = &tegra_pll_d_out0,  .value = 0},
-	{ .input = &tegra_pll_d2_out0, .value = 1},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_clk_32k[] = {
-	{ .input = &tegra_clk_32k, .value = 0},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_plla_clk32_pllp_clkm_plle[] = {
-	{ .input = &tegra_pll_a_out0, .value = 0},
-	{ .input = &tegra_clk_32k,    .value = 1},
-	{ .input = &tegra_pll_p,      .value = 2},
-	{ .input = &tegra_clk_m,      .value = 3},
-	{ .input = &tegra_pll_e,      .value = 4},
-	{ 0, 0},
-};
-
-static struct clk_mux_sel mux_cclk_g[] = {
-	{ .input = &tegra_clk_m,        .value = 0},
-	{ .input = &tegra_pll_c,        .value = 1},
-	{ .input = &tegra_clk_32k,      .value = 2},
-	{ .input = &tegra_pll_m,        .value = 3},
-	{ .input = &tegra_pll_p,        .value = 4},
-	{ .input = &tegra_pll_p_out4,   .value = 5},
-	{ .input = &tegra_pll_p_out3,   .value = 6},
-	{ .input = &tegra_pll_x,        .value = 8},
-	{ 0, 0},
-};
-
-static struct clk tegra_clk_cclk_g = {
-	.name	= "cclk_g",
-	.flags	= DIV_U71 | DIV_U71_INT,
-	.inputs = mux_cclk_g,
-	.reg	= 0x368,
-	.ops	= &tegra_super_ops,
-	.max_rate = 1700000000,
-};
-
-static struct clk tegra30_clk_twd = {
-	.parent	  = &tegra_clk_cclk_g,
-	.name     = "twd",
-	.ops      = &tegra30_twd_ops,
-	.max_rate = 1400000000,	/* Same as tegra_clk_cpu_cmplx.max_rate */
-	.mul      = 1,
-	.div      = 2,
-};
-
-#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
-	{						\
-		.name      = _name,			\
-		.lookup    = {				\
-			.dev_id    = _dev,		\
-			.con_id	   = _con,		\
-		},					\
-		.ops       = &tegra_periph_clk_ops,	\
-		.reg       = _reg,			\
-		.inputs    = _inputs,			\
-		.flags     = _flags,			\
-		.max_rate  = _max,			\
-		.u.periph = {				\
-			.clk_num   = _clk_num,		\
-		},					\
-	}
-
-#define PERIPH_CLK_EX(_name, _dev, _con, _clk_num, _reg, _max, _inputs,	\
-			_flags, _ops)					\
-	{						\
-		.name      = _name,			\
-		.lookup    = {				\
-			.dev_id    = _dev,		\
-			.con_id	   = _con,		\
-		},					\
-		.ops       = _ops,			\
-		.reg       = _reg,			\
-		.inputs    = _inputs,			\
-		.flags     = _flags,			\
-		.max_rate  = _max,			\
-		.u.periph = {				\
-			.clk_num   = _clk_num,		\
-		},					\
-	}
-
-#define SHARED_CLK(_name, _dev, _con, _parent, _id, _div, _mode)\
-	{						\
-		.name      = _name,			\
-		.lookup    = {				\
-			.dev_id    = _dev,		\
-			.con_id    = _con,		\
-		},					\
-		.ops       = &tegra_clk_shared_bus_ops,	\
-		.parent = _parent,			\
-		.u.shared_bus_user = {			\
-			.client_id = _id,		\
-			.client_div = _div,		\
-			.mode = _mode,			\
-		},					\
-	}
-struct clk tegra_list_clks[] = {
-	PERIPH_CLK("apbdma",	"tegra-apbdma",		NULL,	34,	0,	26000000,  mux_clk_m,			0),
-	PERIPH_CLK("rtc",	"rtc-tegra",		NULL,	4,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET | PERIPH_ON_APB),
-	PERIPH_CLK("kbc",	"tegra-kbc",		NULL,	36,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET | PERIPH_ON_APB),
-	PERIPH_CLK("timer",	"timer",		NULL,	5,	0,	26000000,  mux_clk_m,			0),
-	PERIPH_CLK("kfuse",	"kfuse-tegra",		NULL,	40,	0,	26000000,  mux_clk_m,			0),
-	PERIPH_CLK("fuse",	"fuse-tegra",		"fuse",	39,	0,	26000000,  mux_clk_m,			PERIPH_ON_APB),
-	PERIPH_CLK("fuse_burn",	"fuse-tegra",		"fuse_burn",	39,	0,	26000000,  mux_clk_m,		PERIPH_ON_APB),
-	PERIPH_CLK("apbif",	"tegra30-ahub",		"apbif", 107,	0,	26000000,  mux_clk_m,			0),
-	PERIPH_CLK("i2s0",	"tegra30-i2s.0",	NULL,	30,	0x1d8,	26000000,  mux_pllaout0_audio0_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("i2s1",	"tegra30-i2s.1",	NULL,	11,	0x100,	26000000,  mux_pllaout0_audio1_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("i2s2",	"tegra30-i2s.2",	NULL,	18,	0x104,	26000000,  mux_pllaout0_audio2_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("i2s3",	"tegra30-i2s.3",	NULL,	101,	0x3bc,	26000000,  mux_pllaout0_audio3_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("i2s4",	"tegra30-i2s.4",	NULL,	102,	0x3c0,	26000000,  mux_pllaout0_audio4_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("spdif_out",	"tegra30-spdif",	"spdif_out",	10,	0x108,	100000000, mux_pllaout0_audio_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("spdif_in",	"tegra30-spdif",	"spdif_in",	10,	0x10c,	100000000, mux_pllp_pllc_pllm,		MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("pwm",	"tegra-pwm",		NULL,	17,	0x110,	432000000, mux_pllp_pllc_clk32_clkm,	MUX | MUX_PWM | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("d_audio",	"tegra30-ahub",		"d_audio", 106,	0x3d0,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("dam0",	"tegra30-dam.0",	NULL,   108,	0x3d8,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("dam1",	"tegra30-dam.1",	NULL,   109,	0x3dc,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("dam2",	"tegra30-dam.2",	NULL,   110,	0x3e0,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("hda",	"tegra30-hda",		"hda",   125,	0x428,	108000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("hda2codec_2x",	"tegra30-hda",	"hda2codec",   111,	0x3e4,	48000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("hda2hdmi",	"tegra30-hda",		"hda2hdmi",	128,	0,	48000000,  mux_clk_m,			0),
-	PERIPH_CLK("sbc1",	"spi_tegra.0",		NULL,	41,	0x134,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("sbc2",	"spi_tegra.1",		NULL,	44,	0x118,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("sbc3",	"spi_tegra.2",		NULL,	46,	0x11c,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("sbc4",	"spi_tegra.3",		NULL,	68,	0x1b4,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("sbc5",	"spi_tegra.4",		NULL,	104,	0x3c8,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("sbc6",	"spi_tegra.5",		NULL,	105,	0x3cc,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("sata_oob",	"tegra_sata_oob",	NULL,	123,	0x420,	216000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sata",	"tegra_sata",		NULL,	124,	0x424,	216000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sata_cold",	"tegra_sata_cold",	NULL,	129,	0,	48000000,  mux_clk_m,			0),
-	PERIPH_CLK_EX("ndflash", "tegra_nand",		NULL,	13,	0x160,	240000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71,	&tegra_nand_clk_ops),
-	PERIPH_CLK("ndspeed",	"tegra_nand_speed",	NULL,	80,	0x3f8,	240000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("vfir",	"vfir",			NULL,	7,	0x168,	72000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("sdmmc1",	"sdhci-tegra.0",	NULL,	14,	0x150,	208000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("sdmmc2",	"sdhci-tegra.1",	NULL,	9,	0x154,	104000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("sdmmc3",	"sdhci-tegra.2",	NULL,	69,	0x1bc,	208000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("sdmmc4",	"sdhci-tegra.3",	NULL,	15,	0x164,	104000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
-	PERIPH_CLK("vcp",	"tegra-avp",		"vcp",	29,	0,	250000000, mux_clk_m,			0),
-	PERIPH_CLK("bsea",	"tegra-avp",		"bsea",	62,	0,	250000000, mux_clk_m,			0),
-	PERIPH_CLK("bsev",	"tegra-aes",		"bsev",	63,	0,	250000000, mux_clk_m,			0),
-	PERIPH_CLK("vde",	"vde",			NULL,	61,	0x1c8,	520000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_INT),
-	PERIPH_CLK("csite",	"csite",		NULL,	73,	0x1d4,	144000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* max rate ??? */
-	PERIPH_CLK("la",	"la",			NULL,	76,	0x1f8,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("owr",	"tegra_w1",		NULL,	71,	0x1cc,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("nor",	"nor",			NULL,	42,	0x1d0,	127000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("mipi",	"mipi",			NULL,	50,	0x174,	60000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB), /* scales with voltage */
-	PERIPH_CLK("i2c1",	"tegra-i2c.0",		NULL,	12,	0x124,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
-	PERIPH_CLK("i2c2",	"tegra-i2c.1",		NULL,	54,	0x198,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
-	PERIPH_CLK("i2c3",	"tegra-i2c.2",		NULL,	67,	0x1b8,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
-	PERIPH_CLK("i2c4",	"tegra-i2c.3",		NULL,	103,	0x3c4,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
-	PERIPH_CLK("i2c5",	"tegra-i2c.4",		NULL,	47,	0x128,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
-	PERIPH_CLK("uarta",	"tegra-uart.0",		NULL,	6,	0x178,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK("uartb",	"tegra-uart.1",		NULL,	7,	0x17c,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK("uartc",	"tegra-uart.2",		NULL,	55,	0x1a0,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK("uartd",	"tegra-uart.3",		NULL,	65,	0x1c0,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK("uarte",	"tegra-uart.4",		NULL,	66,	0x1c4,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
-	PERIPH_CLK_EX("vi",	"tegra_camera",		"vi",	20,	0x148,	425000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT,	&tegra_vi_clk_ops),
-	PERIPH_CLK("3d",	"3d",			NULL,	24,	0x158,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET),
-	PERIPH_CLK("3d2",       "3d2",			NULL,	98,	0x3b0,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET),
-	PERIPH_CLK("2d",	"2d",			NULL,	21,	0x15c,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE),
-	PERIPH_CLK("vi_sensor",	"tegra_camera",		"vi_sensor",	20,	0x1a8,	150000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | PERIPH_NO_RESET),
-	PERIPH_CLK("epp",	"epp",			NULL,	19,	0x16c,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT),
-	PERIPH_CLK("mpe",	"mpe",			NULL,	60,	0x170,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT),
-	PERIPH_CLK("host1x",	"host1x",		NULL,	28,	0x180,	260000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT),
-	PERIPH_CLK("cve",	"cve",			NULL,	49,	0x140,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("tvo",	"tvo",			NULL,	49,	0x188,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK_EX("dtv",	"dtv",			NULL,	79,	0x1dc,	250000000, mux_clk_m,			0,		&tegra_dtv_clk_ops),
-	PERIPH_CLK("hdmi",	"hdmi",			NULL,	51,	0x18c,	148500000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,	MUX | MUX8 | DIV_U71),
-	PERIPH_CLK("tvdac",	"tvdac",		NULL,	53,	0x194,	220000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
-	PERIPH_CLK("disp1",	"tegradc.0",		NULL,	27,	0x138,	600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,	MUX | MUX8),
-	PERIPH_CLK("disp2",	"tegradc.1",		NULL,	26,	0x13c,	600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,	MUX | MUX8),
-	PERIPH_CLK("usbd",	"fsl-tegra-udc",	NULL,	22,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
-	PERIPH_CLK("usb2",	"tegra-ehci.1",		NULL,	58,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
-	PERIPH_CLK("usb3",	"tegra-ehci.2",		NULL,	59,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
-	PERIPH_CLK("dsia",	"tegradc.0",		"dsia",	48,	0,	500000000, mux_plld_out0,		0),
-	PERIPH_CLK_EX("dsib",	"tegradc.1",		"dsib",	82,	0xd0,	500000000, mux_plld_out0_plld2_out0,	MUX | PLLD,	&tegra_dsib_clk_ops),
-	PERIPH_CLK("csi",	"tegra_camera",		"csi",	52,	0,	102000000, mux_pllp_out3,		0),
-	PERIPH_CLK("isp",	"tegra_camera",		"isp",	23,	0,	150000000, mux_clk_m,			0), /* same frequency as VI */
-	PERIPH_CLK("csus",	"tegra_camera",		"csus",	92,	0,	150000000, mux_clk_m,			PERIPH_NO_RESET),
-
-	PERIPH_CLK("tsensor",	"tegra-tsensor",	NULL,	100,	0x3b8,	216000000, mux_pllp_pllc_clkm_clk32,	MUX | DIV_U71),
-	PERIPH_CLK("actmon",	"actmon",		NULL,	119,	0x3e8,	216000000, mux_pllp_pllc_clk32_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("extern1",	"extern1",		NULL,	120,	0x3ec,	216000000, mux_plla_clk32_pllp_clkm_plle,	MUX | MUX8 | DIV_U71),
-	PERIPH_CLK("extern2",	"extern2",		NULL,	121,	0x3f0,	216000000, mux_plla_clk32_pllp_clkm_plle,	MUX | MUX8 | DIV_U71),
-	PERIPH_CLK("extern3",	"extern3",		NULL,	122,	0x3f4,	216000000, mux_plla_clk32_pllp_clkm_plle,	MUX | MUX8 | DIV_U71),
-	PERIPH_CLK("i2cslow",	"i2cslow",		NULL,	81,	0x3fc,	26000000,  mux_pllp_pllc_clk32_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
-	PERIPH_CLK("pcie",	"tegra-pcie",		"pcie",	70,	0,	250000000, mux_clk_m,			0),
-	PERIPH_CLK("afi",	"tegra-pcie",		"afi",	72,	0,	250000000, mux_clk_m,			0),
-	PERIPH_CLK("se",	"se",			NULL,	127,	0x42c,	520000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_INT),
-};
-
-#define CLK_DUPLICATE(_name, _dev, _con)		\
-	{						\
-		.name	= _name,			\
-		.lookup	= {				\
-			.dev_id	= _dev,			\
-			.con_id		= _con,		\
-		},					\
-	}
-
-/* Some clocks may be used by different drivers depending on the board
- * configuration.  List those here to register them twice in the clock lookup
- * table under two names.
- */
-struct clk_duplicate tegra_clk_duplicates[] = {
-	CLK_DUPLICATE("uarta",  "serial8250.0", NULL),
-	CLK_DUPLICATE("uartb",  "serial8250.1", NULL),
-	CLK_DUPLICATE("uartc",  "serial8250.2", NULL),
-	CLK_DUPLICATE("uartd",  "serial8250.3", NULL),
-	CLK_DUPLICATE("uarte",  "serial8250.4", NULL),
-	CLK_DUPLICATE("usbd", "utmip-pad", NULL),
-	CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
-	CLK_DUPLICATE("usbd", "tegra-otg", NULL),
-	CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
-	CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
-	CLK_DUPLICATE("dsib", "tegradc.0", "dsib"),
-	CLK_DUPLICATE("dsia", "tegradc.1", "dsia"),
-	CLK_DUPLICATE("bsev", "tegra-avp", "bsev"),
-	CLK_DUPLICATE("bsev", "nvavp", "bsev"),
-	CLK_DUPLICATE("vde", "tegra-aes", "vde"),
-	CLK_DUPLICATE("bsea", "tegra-aes", "bsea"),
-	CLK_DUPLICATE("bsea", "nvavp", "bsea"),
-	CLK_DUPLICATE("cml1", "tegra_sata_cml", NULL),
-	CLK_DUPLICATE("cml0", "tegra_pcie", "cml"),
-	CLK_DUPLICATE("pciex", "tegra_pcie", "pciex"),
-	CLK_DUPLICATE("i2c1", "tegra-i2c-slave.0", NULL),
-	CLK_DUPLICATE("i2c2", "tegra-i2c-slave.1", NULL),
-	CLK_DUPLICATE("i2c3", "tegra-i2c-slave.2", NULL),
-	CLK_DUPLICATE("i2c4", "tegra-i2c-slave.3", NULL),
-	CLK_DUPLICATE("i2c5", "tegra-i2c-slave.4", NULL),
-	CLK_DUPLICATE("sbc1", "spi_slave_tegra.0", NULL),
-	CLK_DUPLICATE("sbc2", "spi_slave_tegra.1", NULL),
-	CLK_DUPLICATE("sbc3", "spi_slave_tegra.2", NULL),
-	CLK_DUPLICATE("sbc4", "spi_slave_tegra.3", NULL),
-	CLK_DUPLICATE("sbc5", "spi_slave_tegra.4", NULL),
-	CLK_DUPLICATE("sbc6", "spi_slave_tegra.5", NULL),
-	CLK_DUPLICATE("twd", "smp_twd", NULL),
-	CLK_DUPLICATE("vcp", "nvavp", "vcp"),
-	CLK_DUPLICATE("i2s0", NULL, "i2s0"),
-	CLK_DUPLICATE("i2s1", NULL, "i2s1"),
-	CLK_DUPLICATE("i2s2", NULL, "i2s2"),
-	CLK_DUPLICATE("i2s3", NULL, "i2s3"),
-	CLK_DUPLICATE("i2s4", NULL, "i2s4"),
-	CLK_DUPLICATE("dam0", NULL, "dam0"),
-	CLK_DUPLICATE("dam1", NULL, "dam1"),
-	CLK_DUPLICATE("dam2", NULL, "dam2"),
-	CLK_DUPLICATE("spdif_in", NULL, "spdif_in"),
-};
-
-struct clk *tegra_ptr_clks[] = {
-	&tegra_clk_32k,
-	&tegra_clk_m,
-	&tegra_clk_m_div2,
-	&tegra_clk_m_div4,
-	&tegra_pll_ref,
-	&tegra_pll_m,
-	&tegra_pll_m_out1,
-	&tegra_pll_c,
-	&tegra_pll_c_out1,
-	&tegra_pll_p,
-	&tegra_pll_p_out1,
-	&tegra_pll_p_out2,
-	&tegra_pll_p_out3,
-	&tegra_pll_p_out4,
-	&tegra_pll_a,
-	&tegra_pll_a_out0,
-	&tegra_pll_d,
-	&tegra_pll_d_out0,
-	&tegra_pll_d2,
-	&tegra_pll_d2_out0,
-	&tegra_pll_u,
-	&tegra_pll_x,
-	&tegra_pll_x_out0,
-	&tegra_pll_e,
-	&tegra_clk_cclk_g,
-	&tegra_cml0_clk,
-	&tegra_cml1_clk,
-	&tegra_pciex_clk,
-	&tegra_clk_sclk,
-	&tegra_clk_blink,
-	&tegra30_clk_twd,
-};
-
-
-static void tegra30_init_one_clock(struct clk *c)
+static void tegra30_cpu_out_of_reset(u32 cpu)
 {
-	clk_init(c);
-	INIT_LIST_HEAD(&c->shared_bus_list);
-	if (!c->lookup.dev_id && !c->lookup.con_id)
-		c->lookup.con_id = c->name;
-	c->lookup.clk = c;
-	clkdev_add(&c->lookup);
+	writel(CPU_RESET(cpu),
+	       reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
+	wmb();
 }
 
-void __init tegra30_init_clocks(void)
+static void tegra30_enable_cpu_clock(u32 cpu)
 {
-	int i;
-	struct clk *c;
+	unsigned int reg;
 
-	for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
-		tegra30_init_one_clock(tegra_ptr_clks[i]);
-
-	for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
-		tegra30_init_one_clock(&tegra_list_clks[i]);
+	writel(CPU_CLOCK(cpu),
+	       reg_clk_base + TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
+	reg = readl(reg_clk_base +
+		    TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
+}
 
-	for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
-		c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
-		if (!c) {
-			pr_err("%s: Unknown duplicate clock %s\n", __func__,
-				tegra_clk_duplicates[i].name);
-			continue;
-		}
+static void tegra30_disable_cpu_clock(u32 cpu)
+{
 
-		tegra_clk_duplicates[i].lookup.clk = c;
-		clkdev_add(&tegra_clk_duplicates[i].lookup);
-	}
+	unsigned int reg;
 
-	for (i = 0; i < ARRAY_SIZE(tegra_sync_source_list); i++)
-		tegra30_init_one_clock(&tegra_sync_source_list[i]);
-	for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_list); i++)
-		tegra30_init_one_clock(&tegra_clk_audio_list[i]);
-	for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_2x_list); i++)
-		tegra30_init_one_clock(&tegra_clk_audio_2x_list[i]);
+	reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+	writel(reg | CPU_CLOCK(cpu),
+	       reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+}
 
-	init_clk_out_mux();
-	for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++)
-		tegra30_init_one_clock(&tegra_clk_out_list[i]);
+static struct tegra_cpu_car_ops tegra30_cpu_car_ops = {
+	.wait_for_reset	= tegra30_wait_cpu_in_reset,
+	.put_in_reset	= tegra30_put_cpu_in_reset,
+	.out_of_reset	= tegra30_cpu_out_of_reset,
+	.enable_clock	= tegra30_enable_cpu_clock,
+	.disable_clock	= tegra30_disable_cpu_clock,
+};
 
+void __init tegra30_cpu_car_ops_init(void)
+{
+	tegra_cpu_car_ops = &tegra30_cpu_car_ops;
 }
diff --git a/arch/arm/mach-tegra/tegra30_clocks.h b/arch/arm/mach-tegra/tegra30_clocks.h
new file mode 100644
index 0000000..f2f88fe
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30_clocks.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MACH_TEGRA30_CLOCK_H
+#define __MACH_TEGRA30_CLOCK_H
+
+extern struct clk_ops tegra30_clk_32k_ops;
+extern struct clk_ops tegra30_clk_m_ops;
+extern struct clk_ops tegra_clk_m_div_ops;
+extern struct clk_ops tegra_pll_ref_ops;
+extern struct clk_ops tegra30_pll_ops;
+extern struct clk_ops tegra30_pll_div_ops;
+extern struct clk_ops tegra_plld_ops;
+extern struct clk_ops tegra30_plle_ops;
+extern struct clk_ops tegra_cml_clk_ops;
+extern struct clk_ops tegra_pciex_clk_ops;
+extern struct clk_ops tegra_sync_source_ops;
+extern struct clk_ops tegra30_audio_sync_clk_ops;
+extern struct clk_ops tegra30_clk_double_ops;
+extern struct clk_ops tegra_clk_out_ops;
+extern struct clk_ops tegra30_super_ops;
+extern struct clk_ops tegra30_blink_clk_ops;
+extern struct clk_ops tegra30_twd_ops;
+extern struct clk_ops tegra30_periph_clk_ops;
+extern struct clk_ops tegra30_dsib_clk_ops;
+extern struct clk_ops tegra_nand_clk_ops;
+extern struct clk_ops tegra_vi_clk_ops;
+extern struct clk_ops tegra_dtv_clk_ops;
+extern struct clk_ops tegra_clk_shared_bus_ops;
+
+int tegra30_plld_clk_cfg_ex(struct clk_hw *hw,
+				enum tegra_clk_ex_param p, u32 setting);
+void tegra30_periph_clk_reset(struct clk_hw *hw, bool assert);
+int tegra30_vi_clk_cfg_ex(struct clk_hw *hw,
+				enum tegra_clk_ex_param p, u32 setting);
+int tegra30_nand_clk_cfg_ex(struct clk_hw *hw,
+				enum tegra_clk_ex_param p, u32 setting);
+int tegra30_dtv_clk_cfg_ex(struct clk_hw *hw,
+				enum tegra_clk_ex_param p, u32 setting);
+#endif
diff --git a/arch/arm/mach-tegra/tegra30_clocks_data.c b/arch/arm/mach-tegra/tegra30_clocks_data.c
new file mode 100644
index 0000000..3d2e553
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30_clocks_data.c
@@ -0,0 +1,1378 @@
+/*
+ * arch/arm/mach-tegra/tegra30_clocks.c
+ *
+ * Copyright (c) 2010-2012 NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include <linux/clk-private.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+
+#include "clock.h"
+#include "fuse.h"
+#include "tegra30_clocks.h"
+#include "tegra_cpu_car.h"
+
+#define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags,		\
+		   _parent_names, _parents, _parent)		\
+	static struct clk tegra_##_name = {			\
+		.hw = &tegra_##_name##_hw.hw,			\
+		.name = #_name,					\
+		.rate = _rate,					\
+		.ops = _ops,					\
+		.flags = _flags,				\
+		.parent_names = _parent_names,			\
+		.parents = _parents,				\
+		.num_parents = ARRAY_SIZE(_parent_names),	\
+		.parent	= _parent,				\
+	};
+
+static struct clk tegra_clk_32k;
+static struct clk_tegra tegra_clk_32k_hw = {
+	.hw = {
+		.clk = &tegra_clk_32k,
+	},
+	.fixed_rate = 32768,
+};
+static struct clk tegra_clk_32k = {
+	.name = "clk_32k",
+	.hw = &tegra_clk_32k_hw.hw,
+	.ops = &tegra30_clk_32k_ops,
+	.flags = CLK_IS_ROOT,
+};
+
+static struct clk tegra_clk_m;
+static struct clk_tegra tegra_clk_m_hw = {
+	.hw = {
+		.clk = &tegra_clk_m,
+	},
+	.flags = ENABLE_ON_INIT,
+	.reg = 0x1fc,
+	.reg_shift = 28,
+	.max_rate = 48000000,
+};
+static struct clk tegra_clk_m = {
+	.name = "clk_m",
+	.hw = &tegra_clk_m_hw.hw,
+	.ops = &tegra30_clk_m_ops,
+	.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED,
+};
+
+static const char *clk_m_div_parent_names[] = {
+	"clk_m",
+};
+
+static struct clk *clk_m_div_parents[] = {
+	&tegra_clk_m,
+};
+
+static struct clk tegra_clk_m_div2;
+static struct clk_tegra tegra_clk_m_div2_hw = {
+	.hw = {
+		.clk = &tegra_clk_m_div2,
+	},
+	.mul = 1,
+	.div = 2,
+	.max_rate = 24000000,
+};
+DEFINE_CLK_TEGRA(clk_m_div2, 0, &tegra_clk_m_div_ops, 0,
+		clk_m_div_parent_names, clk_m_div_parents, &tegra_clk_m);
+
+static struct clk tegra_clk_m_div4;
+static struct clk_tegra tegra_clk_m_div4_hw = {
+	.hw = {
+		.clk = &tegra_clk_m_div4,
+	},
+	.mul = 1,
+	.div = 4,
+	.max_rate = 12000000,
+};
+DEFINE_CLK_TEGRA(clk_m_div4, 0, &tegra_clk_m_div_ops, 0,
+		clk_m_div_parent_names, clk_m_div_parents, &tegra_clk_m);
+
+static struct clk tegra_pll_ref;
+static struct clk_tegra tegra_pll_ref_hw = {
+	.hw = {
+		.clk = &tegra_pll_ref,
+	},
+	.flags = ENABLE_ON_INIT,
+	.max_rate = 26000000,
+};
+DEFINE_CLK_TEGRA(pll_ref, 0, &tegra_pll_ref_ops, 0, clk_m_div_parent_names,
+		clk_m_div_parents, &tegra_clk_m);
+
+#define DEFINE_PLL(_name, _flags, _reg, _max_rate, _input_min,	\
+		   _input_max, _cf_min, _cf_max, _vco_min,	\
+		   _vco_max, _freq_table, _lock_delay, _ops,	\
+		   _fixed_rate, _clk_cfg_ex, _parent)		\
+	static struct clk tegra_##_name;			\
+	static const char *_name##_parent_names[] = {		\
+		#_parent,					\
+	};							\
+	static struct clk *_name##_parents[] = {		\
+		&tegra_##_parent,				\
+	};							\
+	static struct clk_tegra tegra_##_name##_hw = {		\
+		.hw = {						\
+			.clk = &tegra_##_name,			\
+		},						\
+		.flags = _flags,				\
+		.reg = _reg,					\
+		.max_rate = _max_rate,				\
+		.u.pll = {					\
+			.input_min = _input_min,		\
+			.input_max = _input_max,		\
+			.cf_min = _cf_min,			\
+			.cf_max = _cf_max,			\
+			.vco_min = _vco_min,			\
+			.vco_max = _vco_max,			\
+			.freq_table = _freq_table,		\
+			.lock_delay = _lock_delay,		\
+			.fixed_rate = _fixed_rate,		\
+		},						\
+		.clk_cfg_ex = _clk_cfg_ex,			\
+	};							\
+	DEFINE_CLK_TEGRA(_name, 0, &_ops, CLK_IGNORE_UNUSED,	\
+			 _name##_parent_names, _name##_parents,	\
+			&tegra_##_parent);
+
+#define DEFINE_PLL_OUT(_name, _flags, _reg, _reg_shift,		\
+		_max_rate, _ops, _parent, _clk_flags)		\
+	static const char *_name##_parent_names[] = {		\
+		#_parent,					\
+	};							\
+	static struct clk *_name##_parents[] = {		\
+		&tegra_##_parent,				\
+	};							\
+	static struct clk tegra_##_name;			\
+	static struct clk_tegra tegra_##_name##_hw = {		\
+		.hw = {						\
+			.clk = &tegra_##_name,			\
+		},						\
+		.flags = _flags,				\
+		.reg = _reg,					\
+		.max_rate = _max_rate,				\
+		.reg_shift = _reg_shift,			\
+	};							\
+	DEFINE_CLK_TEGRA(_name, 0, &tegra30_pll_div_ops,	\
+		_clk_flags,  _name##_parent_names,		\
+		_name##_parents, &tegra_##_parent);
+
+static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
+	{ 12000000, 1040000000, 520,  6, 1, 8},
+	{ 13000000, 1040000000, 480,  6, 1, 8},
+	{ 16800000, 1040000000, 495,  8, 1, 8},	/* actual: 1039.5 MHz */
+	{ 19200000, 1040000000, 325,  6, 1, 6},
+	{ 26000000, 1040000000, 520, 13, 1, 8},
+
+	{ 12000000, 832000000, 416,  6, 1, 8},
+	{ 13000000, 832000000, 832, 13, 1, 8},
+	{ 16800000, 832000000, 396,  8, 1, 8},	/* actual: 831.6 MHz */
+	{ 19200000, 832000000, 260,  6, 1, 8},
+	{ 26000000, 832000000, 416, 13, 1, 8},
+
+	{ 12000000, 624000000, 624, 12, 1, 8},
+	{ 13000000, 624000000, 624, 13, 1, 8},
+	{ 16800000, 600000000, 520, 14, 1, 8},
+	{ 19200000, 624000000, 520, 16, 1, 8},
+	{ 26000000, 624000000, 624, 26, 1, 8},
+
+	{ 12000000, 600000000, 600, 12, 1, 8},
+	{ 13000000, 600000000, 600, 13, 1, 8},
+	{ 16800000, 600000000, 500, 14, 1, 8},
+	{ 19200000, 600000000, 375, 12, 1, 6},
+	{ 26000000, 600000000, 600, 26, 1, 8},
+
+	{ 12000000, 520000000, 520, 12, 1, 8},
+	{ 13000000, 520000000, 520, 13, 1, 8},
+	{ 16800000, 520000000, 495, 16, 1, 8},	/* actual: 519.75 MHz */
+	{ 19200000, 520000000, 325, 12, 1, 6},
+	{ 26000000, 520000000, 520, 26, 1, 8},
+
+	{ 12000000, 416000000, 416, 12, 1, 8},
+	{ 13000000, 416000000, 416, 13, 1, 8},
+	{ 16800000, 416000000, 396, 16, 1, 8},	/* actual: 415.8 MHz */
+	{ 19200000, 416000000, 260, 12, 1, 6},
+	{ 26000000, 416000000, 416, 26, 1, 8},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_c, PLL_HAS_CPCON, 0x80, 1400000000, 2000000, 31000000, 1000000,
+		6000000, 20000000, 1400000000, tegra_pll_c_freq_table, 300,
+		tegra30_pll_ops, 0, NULL, pll_ref);
+
+DEFINE_PLL_OUT(pll_c_out1, DIV_U71, 0x84, 0, 700000000,
+		tegra30_pll_div_ops, pll_c, CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
+	{ 12000000, 666000000, 666, 12, 1, 8},
+	{ 13000000, 666000000, 666, 13, 1, 8},
+	{ 16800000, 666000000, 555, 14, 1, 8},
+	{ 19200000, 666000000, 555, 16, 1, 8},
+	{ 26000000, 666000000, 666, 26, 1, 8},
+	{ 12000000, 600000000, 600, 12, 1, 8},
+	{ 13000000, 600000000, 600, 13, 1, 8},
+	{ 16800000, 600000000, 500, 14, 1, 8},
+	{ 19200000, 600000000, 375, 12, 1, 6},
+	{ 26000000, 600000000, 600, 26, 1, 8},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_m, PLL_HAS_CPCON | PLLM, 0x90, 800000000, 2000000, 31000000,
+		1000000, 6000000, 20000000, 1200000000, tegra_pll_m_freq_table,
+		300, tegra30_pll_ops, 0, NULL, pll_ref);
+
+DEFINE_PLL_OUT(pll_m_out1, DIV_U71, 0x94, 0, 600000000,
+		tegra30_pll_div_ops, pll_m, CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
+	{ 12000000, 216000000, 432, 12, 2, 8},
+	{ 13000000, 216000000, 432, 13, 2, 8},
+	{ 16800000, 216000000, 360, 14, 2, 8},
+	{ 19200000, 216000000, 360, 16, 2, 8},
+	{ 26000000, 216000000, 432, 26, 2, 8},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_p, ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON, 0xa0, 432000000,
+		2000000, 31000000, 1000000, 6000000, 20000000, 1400000000,
+		tegra_pll_p_freq_table, 300, tegra30_pll_ops, 408000000, NULL,
+		pll_ref);
+
+DEFINE_PLL_OUT(pll_p_out1, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4,
+		0, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
+DEFINE_PLL_OUT(pll_p_out2, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4,
+		16, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
+DEFINE_PLL_OUT(pll_p_out3, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8,
+		0, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
+DEFINE_PLL_OUT(pll_p_out4, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8,
+		16, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
+	{ 9600000, 564480000, 294, 5, 1, 4},
+	{ 9600000, 552960000, 288, 5, 1, 4},
+	{ 9600000, 24000000,  5,   2, 1, 1},
+
+	{ 28800000, 56448000, 49, 25, 1, 1},
+	{ 28800000, 73728000, 64, 25, 1, 1},
+	{ 28800000, 24000000,  5,  6, 1, 1},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_a, PLL_HAS_CPCON, 0xb0, 700000000, 2000000, 31000000, 1000000,
+		6000000, 20000000, 1400000000, tegra_pll_a_freq_table,
+		300, tegra30_pll_ops, 0, NULL, pll_p_out1);
+
+DEFINE_PLL_OUT(pll_a_out0, DIV_U71, 0xb4, 0, 100000000, tegra30_pll_div_ops,
+		pll_a, CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
+	{ 12000000, 216000000, 216, 12, 1, 4},
+	{ 13000000, 216000000, 216, 13, 1, 4},
+	{ 16800000, 216000000, 180, 14, 1, 4},
+	{ 19200000, 216000000, 180, 16, 1, 4},
+	{ 26000000, 216000000, 216, 26, 1, 4},
+
+	{ 12000000, 594000000, 594, 12, 1, 8},
+	{ 13000000, 594000000, 594, 13, 1, 8},
+	{ 16800000, 594000000, 495, 14, 1, 8},
+	{ 19200000, 594000000, 495, 16, 1, 8},
+	{ 26000000, 594000000, 594, 26, 1, 8},
+
+	{ 12000000, 1000000000, 1000, 12, 1, 12},
+	{ 13000000, 1000000000, 1000, 13, 1, 12},
+	{ 19200000, 1000000000, 625,  12, 1, 8},
+	{ 26000000, 1000000000, 1000, 26, 1, 12},
+
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_d, PLL_HAS_CPCON | PLLD, 0xd0, 1000000000, 2000000, 40000000,
+		1000000, 6000000, 40000000, 1000000000, tegra_pll_d_freq_table,
+		1000, tegra30_pll_ops, 0, tegra30_plld_clk_cfg_ex, pll_ref);
+
+DEFINE_PLL_OUT(pll_d_out0, DIV_2 | PLLD, 0, 0, 500000000, tegra30_pll_div_ops,
+		pll_d, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
+
+DEFINE_PLL(pll_d2, PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLD, 0x4b8, 1000000000,
+		2000000, 40000000, 1000000, 6000000, 40000000, 1000000000,
+		tegra_pll_d_freq_table, 1000, tegra30_pll_ops, 0, NULL,
+		pll_ref);
+
+DEFINE_PLL_OUT(pll_d2_out0, DIV_2 | PLLD, 0, 0, 500000000, tegra30_pll_div_ops,
+		pll_d2, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
+	{ 12000000, 480000000, 960, 12, 2, 12},
+	{ 13000000, 480000000, 960, 13, 2, 12},
+	{ 16800000, 480000000, 400, 7,  2, 5},
+	{ 19200000, 480000000, 200, 4,  2, 3},
+	{ 26000000, 480000000, 960, 26, 2, 12},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_u, PLL_HAS_CPCON | PLLU, 0xc0, 480000000, 2000000, 40000000,
+		1000000, 6000000, 48000000, 960000000, tegra_pll_u_freq_table,
+		1000, tegra30_pll_ops, 0, NULL, pll_ref);
+
+static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
+	/* 1.7 GHz */
+	{ 12000000, 1700000000, 850,  6,  1, 8},
+	{ 13000000, 1700000000, 915,  7,  1, 8},	/* actual: 1699.2 MHz */
+	{ 16800000, 1700000000, 708,  7,  1, 8},	/* actual: 1699.2 MHz */
+	{ 19200000, 1700000000, 885,  10, 1, 8},	/* actual: 1699.2 MHz */
+	{ 26000000, 1700000000, 850,  13, 1, 8},
+
+	/* 1.6 GHz */
+	{ 12000000, 1600000000, 800,  6,  1, 8},
+	{ 13000000, 1600000000, 738,  6,  1, 8},	/* actual: 1599.0 MHz */
+	{ 16800000, 1600000000, 857,  9,  1, 8},	/* actual: 1599.7 MHz */
+	{ 19200000, 1600000000, 500,  6,  1, 8},
+	{ 26000000, 1600000000, 800,  13, 1, 8},
+
+	/* 1.5 GHz */
+	{ 12000000, 1500000000, 750,  6,  1, 8},
+	{ 13000000, 1500000000, 923,  8,  1, 8},	/* actual: 1499.8 MHz */
+	{ 16800000, 1500000000, 625,  7,  1, 8},
+	{ 19200000, 1500000000, 625,  8,  1, 8},
+	{ 26000000, 1500000000, 750,  13, 1, 8},
+
+	/* 1.4 GHz */
+	{ 12000000, 1400000000, 700,  6,  1, 8},
+	{ 13000000, 1400000000, 969,  9,  1, 8},	/* actual: 1399.7 MHz */
+	{ 16800000, 1400000000, 1000, 12, 1, 8},
+	{ 19200000, 1400000000, 875,  12, 1, 8},
+	{ 26000000, 1400000000, 700,  13, 1, 8},
+
+	/* 1.3 GHz */
+	{ 12000000, 1300000000, 975,  9,  1, 8},
+	{ 13000000, 1300000000, 1000, 10, 1, 8},
+	{ 16800000, 1300000000, 928,  12, 1, 8},	/* actual: 1299.2 MHz */
+	{ 19200000, 1300000000, 812,  12, 1, 8},	/* actual: 1299.2 MHz */
+	{ 26000000, 1300000000, 650,  13, 1, 8},
+
+	/* 1.2 GHz */
+	{ 12000000, 1200000000, 1000, 10, 1, 8},
+	{ 13000000, 1200000000, 923,  10, 1, 8},	/* actual: 1199.9 MHz */
+	{ 16800000, 1200000000, 1000, 14, 1, 8},
+	{ 19200000, 1200000000, 1000, 16, 1, 8},
+	{ 26000000, 1200000000, 600,  13, 1, 8},
+
+	/* 1.1 GHz */
+	{ 12000000, 1100000000, 825,  9,  1, 8},
+	{ 13000000, 1100000000, 846,  10, 1, 8},	/* actual: 1099.8 MHz */
+	{ 16800000, 1100000000, 982,  15, 1, 8},	/* actual: 1099.8 MHz */
+	{ 19200000, 1100000000, 859,  15, 1, 8},	/* actual: 1099.5 MHz */
+	{ 26000000, 1100000000, 550,  13, 1, 8},
+
+	/* 1 GHz */
+	{ 12000000, 1000000000, 1000, 12, 1, 8},
+	{ 13000000, 1000000000, 1000, 13, 1, 8},
+	{ 16800000, 1000000000, 833,  14, 1, 8},	/* actual: 999.6 MHz */
+	{ 19200000, 1000000000, 625,  12, 1, 8},
+	{ 26000000, 1000000000, 1000, 26, 1, 8},
+
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_x, PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLX, 0xe0, 1700000000,
+		2000000, 31000000, 1000000, 6000000, 20000000, 1700000000,
+		tegra_pll_x_freq_table, 300, tegra30_pll_ops, 0, NULL, pll_ref);
+
+DEFINE_PLL_OUT(pll_x_out0, DIV_2 | PLLX, 0, 0, 850000000, tegra30_pll_div_ops,
+		pll_x, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
+	/* PLLE special case: use cpcon field to store cml divider value */
+	{ 12000000,  100000000, 150, 1,  18, 11},
+	{ 216000000, 100000000, 200, 18, 24, 13},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_e, PLL_ALT_MISC_REG, 0xe8, 100000000, 2000000, 216000000,
+		12000000, 12000000, 1200000000, 2400000000U,
+		tegra_pll_e_freq_table, 300, tegra30_plle_ops, 100000000, NULL,
+		pll_ref);
+
+static const char *mux_plle[] = {
+	"pll_e",
+};
+
+static struct clk *mux_plle_p[] = {
+	&tegra_pll_e,
+};
+
+static struct clk tegra_cml0;
+static struct clk_tegra tegra_cml0_hw = {
+	.hw = {
+		.clk = &tegra_cml0,
+	},
+	.reg = 0x48c,
+	.fixed_rate = 100000000,
+	.u.periph = {
+		.clk_num = 0,
+	},
+};
+DEFINE_CLK_TEGRA(cml0, 0, &tegra_cml_clk_ops, 0, mux_plle,
+		mux_plle_p, &tegra_pll_e);
+
+static struct clk tegra_cml1;
+static struct clk_tegra tegra_cml1_hw = {
+	.hw = {
+		.clk = &tegra_cml1,
+	},
+	.reg = 0x48c,
+	.fixed_rate = 100000000,
+	.u.periph = {
+		.clk_num = 1,
+	},
+};
+DEFINE_CLK_TEGRA(cml1, 0, &tegra_cml_clk_ops, 0, mux_plle,
+		mux_plle_p, &tegra_pll_e);
+
+static struct clk tegra_pciex;
+static struct clk_tegra tegra_pciex_hw = {
+	.hw = {
+		.clk = &tegra_pciex,
+	},
+	.reg = 0x48c,
+	.fixed_rate = 100000000,
+	.reset = tegra30_periph_clk_reset,
+	.u.periph = {
+		.clk_num = 74,
+	},
+};
+DEFINE_CLK_TEGRA(pciex, 0, &tegra_pciex_clk_ops, 0, mux_plle,
+		mux_plle_p, &tegra_pll_e);
+
+#define SYNC_SOURCE(_name)					\
+	static struct clk tegra_##_name##_sync;			\
+	static struct clk_tegra tegra_##_name##_sync_hw = {	\
+		.hw = {						\
+			.clk = &tegra_##_name##_sync,		\
+		},						\
+		.max_rate = 24000000,				\
+		.fixed_rate = 24000000,				\
+	};							\
+	static struct clk tegra_##_name##_sync = {		\
+		.name = #_name "_sync",				\
+		.hw = &tegra_##_name##_sync_hw.hw,		\
+		.ops = &tegra_sync_source_ops,			\
+		.flags = CLK_IS_ROOT,				\
+	};
+
+SYNC_SOURCE(spdif_in);
+SYNC_SOURCE(i2s0);
+SYNC_SOURCE(i2s1);
+SYNC_SOURCE(i2s2);
+SYNC_SOURCE(i2s3);
+SYNC_SOURCE(i2s4);
+SYNC_SOURCE(vimclk);
+
+static struct clk *tegra_sync_source_list[] = {
+	&tegra_spdif_in_sync,
+	&tegra_i2s0_sync,
+	&tegra_i2s1_sync,
+	&tegra_i2s2_sync,
+	&tegra_i2s3_sync,
+	&tegra_i2s4_sync,
+	&tegra_vimclk_sync,
+};
+
+static const char *mux_audio_sync_clk[] = {
+	"spdif_in_sync",
+	"i2s0_sync",
+	"i2s1_sync",
+	"i2s2_sync",
+	"i2s3_sync",
+	"i2s4_sync",
+	"vimclk_sync",
+};
+
+#define AUDIO_SYNC_CLK(_name, _index)				\
+	static struct clk tegra_##_name;			\
+	static struct clk_tegra tegra_##_name##_hw = {		\
+		.hw = {						\
+			.clk = &tegra_##_name,			\
+		},						\
+		.max_rate = 24000000,				\
+		.reg = 0x4A0 + (_index) * 4,			\
+	};							\
+	static struct clk tegra_##_name = {			\
+		.name = #_name,					\
+		.ops = &tegra30_audio_sync_clk_ops,		\
+		.hw = &tegra_##_name##_hw.hw,			\
+		.parent_names = mux_audio_sync_clk,		\
+		.parents = tegra_sync_source_list,		\
+		.num_parents = ARRAY_SIZE(mux_audio_sync_clk),	\
+	};
+
+AUDIO_SYNC_CLK(audio0, 0);
+AUDIO_SYNC_CLK(audio1, 1);
+AUDIO_SYNC_CLK(audio2, 2);
+AUDIO_SYNC_CLK(audio3, 3);
+AUDIO_SYNC_CLK(audio4, 4);
+AUDIO_SYNC_CLK(audio5, 5);
+
+static struct clk *tegra_clk_audio_list[] = {
+	&tegra_audio0,
+	&tegra_audio1,
+	&tegra_audio2,
+	&tegra_audio3,
+	&tegra_audio4,
+	&tegra_audio5,	/* SPDIF */
+};
+
+#define AUDIO_SYNC_2X_CLK(_name, _index)			\
+	static const char *_name##_parent_names[] = {		\
+		"tegra_" #_name,				\
+	};							\
+	static struct clk *_name##_parents[] = {		\
+		&tegra_##_name,					\
+	};							\
+	static struct clk tegra_##_name##_2x;			\
+	static struct clk_tegra tegra_##_name##_2x_hw = {	\
+		.hw = {						\
+			.clk = &tegra_##_name##_2x,		\
+		},						\
+		.flags = PERIPH_NO_RESET,			\
+		.max_rate = 48000000,				\
+		.reg = 0x49C,					\
+		.reg_shift = 24 + (_index),			\
+		.u.periph = {					\
+			.clk_num = 113 + (_index),		\
+		},						\
+	};							\
+	static struct clk tegra_##_name##_2x = {		\
+		.name = #_name "_2x",				\
+		.ops = &tegra30_clk_double_ops,			\
+		.hw = &tegra_##_name##_2x_hw.hw,		\
+		.parent_names = _name##_parent_names,		\
+		.parents = _name##_parents,			\
+		.parent = &tegra_##_name,			\
+		.num_parents = 1,				\
+	};
+
+AUDIO_SYNC_2X_CLK(audio0, 0);
+AUDIO_SYNC_2X_CLK(audio1, 1);
+AUDIO_SYNC_2X_CLK(audio2, 2);
+AUDIO_SYNC_2X_CLK(audio3, 3);
+AUDIO_SYNC_2X_CLK(audio4, 4);
+AUDIO_SYNC_2X_CLK(audio5, 5);	/* SPDIF */
+
+static struct clk *tegra_clk_audio_2x_list[] = {
+	&tegra_audio0_2x,
+	&tegra_audio1_2x,
+	&tegra_audio2_2x,
+	&tegra_audio3_2x,
+	&tegra_audio4_2x,
+	&tegra_audio5_2x,	/* SPDIF */
+};
+
+#define MUX_I2S_SPDIF(_id)					\
+static const char *mux_pllaout0_##_id##_2x_pllp_clkm[] = {	\
+	"pll_a_out0",						\
+	#_id "_2x",						\
+	"pll_p",						\
+	"clk_m",						\
+};								\
+static struct clk *mux_pllaout0_##_id##_2x_pllp_clkm_p[] = {	\
+	&tegra_pll_a_out0,					\
+	&tegra_##_id##_2x,					\
+	&tegra_pll_p,						\
+	&tegra_clk_m,						\
+};
+
+MUX_I2S_SPDIF(audio0);
+MUX_I2S_SPDIF(audio1);
+MUX_I2S_SPDIF(audio2);
+MUX_I2S_SPDIF(audio3);
+MUX_I2S_SPDIF(audio4);
+MUX_I2S_SPDIF(audio5);		/* SPDIF */
+
+static struct clk tegra_extern1;
+static struct clk tegra_extern2;
+static struct clk tegra_extern3;
+
+/* External clock outputs (through PMC) */
+#define MUX_EXTERN_OUT(_id)					\
+static const char *mux_clkm_clkm2_clkm4_extern##_id[] = {	\
+	"clk_m",						\
+	"clk_m_div2",						\
+	"clk_m_div4",						\
+	"extern" #_id,						\
+};								\
+static struct clk *mux_clkm_clkm2_clkm4_extern##_id##_p[] = {	\
+	&tegra_clk_m,						\
+	&tegra_clk_m_div2,					\
+	&tegra_clk_m_div4,					\
+	&tegra_extern##_id,					\
+};
+
+MUX_EXTERN_OUT(1);
+MUX_EXTERN_OUT(2);
+MUX_EXTERN_OUT(3);
+
+#define CLK_OUT_CLK(_name, _index)					\
+	static struct clk tegra_##_name;				\
+	static struct clk_tegra tegra_##_name##_hw = {			\
+		.hw = {							\
+			.clk = &tegra_##_name,				\
+		},							\
+		.lookup = {						\
+			.dev_id	= #_name,				\
+			.con_id	= "extern" #_index,			\
+		},							\
+		.flags = MUX_CLK_OUT,					\
+		.fixed_rate = 216000000,					\
+		.reg = 0x1a8,						\
+		.u.periph = {						\
+			.clk_num = (_index - 1) * 8 + 2,		\
+		},							\
+	};								\
+	static struct clk tegra_##_name = {				\
+		.name = #_name,						\
+		.ops = &tegra_clk_out_ops,				\
+		.hw = &tegra_##_name##_hw.hw,				\
+		.parent_names = mux_clkm_clkm2_clkm4_extern##_index,	\
+		.parents = mux_clkm_clkm2_clkm4_extern##_index##_p,	\
+		.num_parents = ARRAY_SIZE(mux_clkm_clkm2_clkm4_extern##_index),\
+	};
+
+CLK_OUT_CLK(clk_out_1, 1);
+CLK_OUT_CLK(clk_out_2, 2);
+CLK_OUT_CLK(clk_out_3, 3);
+
+static struct clk *tegra_clk_out_list[] = {
+	&tegra_clk_out_1,
+	&tegra_clk_out_2,
+	&tegra_clk_out_3,
+};
+
+static const char *mux_sclk[] = {
+	"clk_m",
+	"pll_c_out1",
+	"pll_p_out4",
+	"pll_p_out3",
+	"pll_p_out2",
+	"dummy",
+	"clk_32k",
+	"pll_m_out1",
+};
+
+static struct clk *mux_sclk_p[] = {
+	&tegra_clk_m,
+	&tegra_pll_c_out1,
+	&tegra_pll_p_out4,
+	&tegra_pll_p_out3,
+	&tegra_pll_p_out2,
+	NULL,
+	&tegra_clk_32k,
+	&tegra_pll_m_out1,
+};
+
+static struct clk tegra_clk_sclk;
+static struct clk_tegra tegra_clk_sclk_hw = {
+	.hw = {
+		.clk = &tegra_clk_sclk,
+	},
+	.reg = 0x28,
+	.max_rate = 334000000,
+	.min_rate = 40000000,
+};
+
+static struct clk tegra_clk_sclk = {
+	.name = "sclk",
+	.ops = &tegra30_super_ops,
+	.hw = &tegra_clk_sclk_hw.hw,
+	.parent_names = mux_sclk,
+	.parents = mux_sclk_p,
+	.num_parents = ARRAY_SIZE(mux_sclk),
+};
+
+static const char *mux_blink[] = {
+	"clk_32k",
+};
+
+static struct clk *mux_blink_p[] = {
+	&tegra_clk_32k,
+};
+
+static struct clk tegra_clk_blink;
+static struct clk_tegra tegra_clk_blink_hw = {
+	.hw = {
+		.clk = &tegra_clk_blink,
+	},
+	.reg = 0x40,
+	.max_rate = 32768,
+};
+static struct clk tegra_clk_blink = {
+	.name = "blink",
+	.ops = &tegra30_blink_clk_ops,
+	.hw = &tegra_clk_blink_hw.hw,
+	.parent = &tegra_clk_32k,
+	.parent_names = mux_blink,
+	.parents = mux_blink_p,
+	.num_parents = ARRAY_SIZE(mux_blink),
+};
+
+static const char *mux_pllm_pllc_pllp_plla[] = {
+	"pll_m",
+	"pll_c",
+	"pll_p",
+	"pll_a_out0",
+};
+
+static const char *mux_pllp_pllc_pllm_clkm[] = {
+	"pll_p",
+	"pll_c",
+	"pll_m",
+	"clk_m",
+};
+
+static const char *mux_pllp_clkm[] = {
+	"pll_p",
+	"dummy",
+	"dummy",
+	"clk_m",
+};
+
+static const char *mux_pllp_plld_pllc_clkm[] = {
+	"pll_p",
+	"pll_d_out0",
+	"pll_c",
+	"clk_m",
+};
+
+static const char *mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = {
+	"pll_p",
+	"pll_m",
+	"pll_d_out0",
+	"pll_a_out0",
+	"pll_c",
+	"pll_d2_out0",
+	"clk_m",
+};
+
+static const char *mux_plla_pllc_pllp_clkm[] = {
+	"pll_a_out0",
+	"dummy",
+	"pll_p",
+	"clk_m"
+};
+
+static const char *mux_pllp_pllc_clk32_clkm[] = {
+	"pll_p",
+	"pll_c",
+	"clk_32k",
+	"clk_m",
+};
+
+static const char *mux_pllp_pllc_clkm_clk32[] = {
+	"pll_p",
+	"pll_c",
+	"clk_m",
+	"clk_32k",
+};
+
+static const char *mux_pllp_pllc_pllm[] = {
+	"pll_p",
+	"pll_c",
+	"pll_m",
+};
+
+static const char *mux_clk_m[] = {
+	"clk_m",
+};
+
+static const char *mux_pllp_out3[] = {
+	"pll_p_out3",
+};
+
+static const char *mux_plld_out0[] = {
+	"pll_d_out0",
+};
+
+static const char *mux_plld_out0_plld2_out0[] = {
+	"pll_d_out0",
+	"pll_d2_out0",
+};
+
+static const char *mux_clk_32k[] = {
+	"clk_32k",
+};
+
+static const char *mux_plla_clk32_pllp_clkm_plle[] = {
+	"pll_a_out0",
+	"clk_32k",
+	"pll_p",
+	"clk_m",
+	"pll_e",
+};
+
+static const char *mux_cclk_g[] = {
+	"clk_m",
+	"pll_c",
+	"clk_32k",
+	"pll_m",
+	"pll_p",
+	"pll_p_out4",
+	"pll_p_out3",
+	"dummy",
+	"pll_x",
+};
+
+static struct clk *mux_pllm_pllc_pllp_plla_p[] = {
+	&tegra_pll_m,
+	&tegra_pll_c,
+	&tegra_pll_p,
+	&tegra_pll_a_out0,
+};
+
+static struct clk *mux_pllp_pllc_pllm_clkm_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_c,
+	&tegra_pll_m,
+	&tegra_clk_m,
+};
+
+static struct clk *mux_pllp_clkm_p[] = {
+	&tegra_pll_p,
+	NULL,
+	NULL,
+	&tegra_clk_m,
+};
+
+static struct clk *mux_pllp_plld_pllc_clkm_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_d_out0,
+	&tegra_pll_c,
+	&tegra_clk_m,
+};
+
+static struct clk *mux_pllp_pllm_plld_plla_pllc_plld2_clkm_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_m,
+	&tegra_pll_d_out0,
+	&tegra_pll_a_out0,
+	&tegra_pll_c,
+	&tegra_pll_d2_out0,
+	&tegra_clk_m,
+};
+
+static struct clk *mux_plla_pllc_pllp_clkm_p[] = {
+	&tegra_pll_a_out0,
+	NULL,
+	&tegra_pll_p,
+	&tegra_clk_m,
+};
+
+static struct clk *mux_pllp_pllc_clk32_clkm_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_c,
+	&tegra_clk_32k,
+	&tegra_clk_m,
+};
+
+static struct clk *mux_pllp_pllc_clkm_clk32_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_c,
+	&tegra_clk_m,
+	&tegra_clk_32k,
+};
+
+static struct clk *mux_pllp_pllc_pllm_p[] = {
+	&tegra_pll_p,
+	&tegra_pll_c,
+	&tegra_pll_m,
+};
+
+static struct clk *mux_clk_m_p[] = {
+	&tegra_clk_m,
+};
+
+static struct clk *mux_pllp_out3_p[] = {
+	&tegra_pll_p_out3,
+};
+
+static struct clk *mux_plld_out0_p[] = {
+	&tegra_pll_d_out0,
+};
+
+static struct clk *mux_plld_out0_plld2_out0_p[] = {
+	&tegra_pll_d_out0,
+	&tegra_pll_d2_out0,
+};
+
+static struct clk *mux_clk_32k_p[] = {
+	&tegra_clk_32k,
+};
+
+static struct clk *mux_plla_clk32_pllp_clkm_plle_p[] = {
+	&tegra_pll_a_out0,
+	&tegra_clk_32k,
+	&tegra_pll_p,
+	&tegra_clk_m,
+	&tegra_pll_e,
+};
+
+static struct clk *mux_cclk_g_p[] = {
+	&tegra_clk_m,
+	&tegra_pll_c,
+	&tegra_clk_32k,
+	&tegra_pll_m,
+	&tegra_pll_p,
+	&tegra_pll_p_out4,
+	&tegra_pll_p_out3,
+	NULL,
+	&tegra_pll_x,
+};
+
+static struct clk tegra_clk_cclk_g;
+static struct clk_tegra tegra_clk_cclk_g_hw = {
+	.hw = {
+		.clk = &tegra_clk_cclk_g,
+	},
+	.flags = DIV_U71 | DIV_U71_INT,
+	.reg = 0x368,
+	.max_rate = 1700000000,
+};
+static struct clk tegra_clk_cclk_g = {
+	.name = "cclk_g",
+	.ops = &tegra30_super_ops,
+	.hw = &tegra_clk_cclk_g_hw.hw,
+	.parent_names = mux_cclk_g,
+	.parents = mux_cclk_g_p,
+	.num_parents = ARRAY_SIZE(mux_cclk_g),
+};
+
+static const char *mux_twd[] = {
+	"cclk_g",
+};
+
+static struct clk *mux_twd_p[] = {
+	&tegra_clk_cclk_g,
+};
+
+static struct clk tegra30_clk_twd;
+static struct clk_tegra tegra30_clk_twd_hw = {
+	.hw = {
+		.clk = &tegra30_clk_twd,
+	},
+	.max_rate = 1400000000,
+	.mul = 1,
+	.div = 2,
+};
+
+static struct clk tegra30_clk_twd = {
+	.name = "twd",
+	.ops = &tegra30_twd_ops,
+	.hw = &tegra30_clk_twd_hw.hw,
+	.parent = &tegra_clk_cclk_g,
+	.parent_names = mux_twd,
+	.parents = mux_twd_p,
+	.num_parents = ARRAY_SIZE(mux_twd),
+};
+
+#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg,	\
+		_max, _inputs, _flags)	 		\
+	static struct clk tegra_##_name;		\
+	static struct clk_tegra tegra_##_name##_hw = {	\
+		.hw = {					\
+			.clk = &tegra_##_name,		\
+		},					\
+		.lookup = {				\
+			.dev_id	= _dev,			\
+			.con_id	= _con,			\
+		},					\
+		.reg = _reg,				\
+		.flags = _flags,			\
+		.max_rate = _max,			\
+		.u.periph = {				\
+			.clk_num = _clk_num,		\
+		},					\
+		.reset = &tegra30_periph_clk_reset,	\
+	};						\
+	static struct clk tegra_##_name = {		\
+		.name = #_name,				\
+		.ops = &tegra30_periph_clk_ops,		\
+		.hw = &tegra_##_name##_hw.hw,		\
+		.parent_names = _inputs,		\
+		.parents = _inputs##_p,			\
+		.num_parents = ARRAY_SIZE(_inputs),	\
+	};
+
+PERIPH_CLK(apbdma,	"tegra-apbdma",		NULL,	34,	0,	26000000,  mux_clk_m,			0);
+PERIPH_CLK(rtc,		"rtc-tegra",		NULL,	4,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET | PERIPH_ON_APB);
+PERIPH_CLK(kbc,		"tegra-kbc",		NULL,	36,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET | PERIPH_ON_APB);
+PERIPH_CLK(timer,	"timer",		NULL,	5,	0,	26000000,  mux_clk_m,			0);
+PERIPH_CLK(kfuse,	"kfuse-tegra",		NULL,	40,	0,	26000000,  mux_clk_m,			0);
+PERIPH_CLK(fuse,	"fuse-tegra",		"fuse",	39,	0,	26000000,  mux_clk_m,			PERIPH_ON_APB);
+PERIPH_CLK(fuse_burn,	"fuse-tegra",		"fuse_burn",	39,	0,	26000000,  mux_clk_m,		PERIPH_ON_APB);
+PERIPH_CLK(apbif,	"tegra30-ahub",		"apbif", 107,	0,	26000000,  mux_clk_m,			0);
+PERIPH_CLK(i2s0,	"tegra30-i2s.0",	NULL,	30,	0x1d8,	26000000,  mux_pllaout0_audio0_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(i2s1,	"tegra30-i2s.1",	NULL,	11,	0x100,	26000000,  mux_pllaout0_audio1_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(i2s2,	"tegra30-i2s.2",	NULL,	18,	0x104,	26000000,  mux_pllaout0_audio2_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(i2s3,	"tegra30-i2s.3",	NULL,	101,	0x3bc,	26000000,  mux_pllaout0_audio3_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(i2s4,	"tegra30-i2s.4",	NULL,	102,	0x3c0,	26000000,  mux_pllaout0_audio4_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(spdif_out,	"tegra30-spdif",	"spdif_out",	10,	0x108,	100000000, mux_pllaout0_audio5_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(spdif_in,	"tegra30-spdif",	"spdif_in",	10,	0x10c,	100000000, mux_pllp_pllc_pllm,		MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(pwm,		"tegra-pwm",		NULL,	17,	0x110,	432000000, mux_pllp_pllc_clk32_clkm,	MUX | MUX_PWM | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(d_audio,	"tegra30-ahub",		"d_audio", 106,	0x3d0,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71);
+PERIPH_CLK(dam0,	"tegra30-dam.0",	NULL,	108,	0x3d8,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71);
+PERIPH_CLK(dam1,	"tegra30-dam.1",	NULL,	109,	0x3dc,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71);
+PERIPH_CLK(dam2,	"tegra30-dam.2",	NULL,	110,	0x3e0,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71);
+PERIPH_CLK(hda,		"tegra30-hda",		"hda",	125,	0x428,	108000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(hda2codec_2x,	"tegra30-hda",	"hda2codec",	111,	0x3e4,	48000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(hda2hdmi,	"tegra30-hda",		"hda2hdmi",	128,	0,	48000000,  mux_clk_m,			0);
+PERIPH_CLK(sbc1,	"spi_tegra.0",		NULL,	41,	0x134,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sbc2,	"spi_tegra.1",		NULL,	44,	0x118,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sbc3,	"spi_tegra.2",		NULL,	46,	0x11c,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sbc4,	"spi_tegra.3",		NULL,	68,	0x1b4,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sbc5,	"spi_tegra.4",		NULL,	104,	0x3c8,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sbc6,	"spi_tegra.5",		NULL,	105,	0x3cc,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sata_oob,	"tegra_sata_oob",	NULL,	123,	0x420,	216000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(sata,	"tegra_sata",		NULL,	124,	0x424,	216000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(sata_cold,	"tegra_sata_cold",	NULL,	129,	0,	48000000,  mux_clk_m,			0);
+PERIPH_CLK(ndflash,	"tegra_nand",		NULL,	13,	0x160,	240000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(ndspeed,	"tegra_nand_speed",	NULL,	80,	0x3f8,	240000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(vfir,	"vfir",			NULL,	7,	0x168,	72000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sdmmc1,	"sdhci-tegra.0",	NULL,	14,	0x150,	208000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc2,	"sdhci-tegra.1",	NULL,	9,	0x154,	104000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc3,	"sdhci-tegra.2",	NULL,	69,	0x1bc,	208000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc4,	"sdhci-tegra.3",	NULL,	15,	0x164,	104000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(vcp,		"tegra-avp",		"vcp",	29,	0,	250000000, mux_clk_m,			0);
+PERIPH_CLK(bsea,	"tegra-avp",		"bsea",	62,	0,	250000000, mux_clk_m,			0);
+PERIPH_CLK(bsev,	"tegra-aes",		"bsev",	63,	0,	250000000, mux_clk_m,			0);
+PERIPH_CLK(vde,		"vde",			NULL,	61,	0x1c8,	520000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_INT);
+PERIPH_CLK(csite,	"csite",		NULL,	73,	0x1d4,	144000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* max rate ??? */
+PERIPH_CLK(la,		"la",			NULL,	76,	0x1f8,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71);
+PERIPH_CLK(owr,		"tegra_w1",		NULL,	71,	0x1cc,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(nor,		"nor",			NULL,	42,	0x1d0,	127000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(mipi,	"mipi",			NULL,	50,	0x174,	60000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB); /* scales with voltage */
+PERIPH_CLK(i2c1,	"tegra-i2c.0",		"div-clk", 12,	0x124,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB);
+PERIPH_CLK(i2c2,	"tegra-i2c.1",		"div-clk", 54,	0x198,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB);
+PERIPH_CLK(i2c3,	"tegra-i2c.2",		"div-clk", 67,	0x1b8,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB);
+PERIPH_CLK(i2c4,	"tegra-i2c.3",		"div-clk", 103,	0x3c4,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB);
+PERIPH_CLK(i2c5,	"tegra-i2c.4",		"div-clk", 47,	0x128,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB);
+PERIPH_CLK(uarta,	"tegra-uart.0",		NULL,	6,	0x178,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
+PERIPH_CLK(uartb,	"tegra-uart.1",		NULL,	7,	0x17c,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
+PERIPH_CLK(uartc,	"tegra-uart.2",		NULL,	55,	0x1a0,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
+PERIPH_CLK(uartd,	"tegra-uart.3",		NULL,	65,	0x1c0,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
+PERIPH_CLK(uarte,	"tegra-uart.4",		NULL,	66,	0x1c4,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
+PERIPH_CLK(vi,		"tegra_camera",		"vi",	20,	0x148,	425000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT);
+PERIPH_CLK(3d,		"3d",			NULL,	24,	0x158,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET);
+PERIPH_CLK(3d2,		"3d2",			NULL,	98,	0x3b0,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET);
+PERIPH_CLK(2d,		"2d",			NULL,	21,	0x15c,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE);
+PERIPH_CLK(vi_sensor,	"tegra_camera",		"vi_sensor",	20,	0x1a8,	150000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | PERIPH_NO_RESET);
+PERIPH_CLK(epp,		"epp",			NULL,	19,	0x16c,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT);
+PERIPH_CLK(mpe,		"mpe",			NULL,	60,	0x170,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT);
+PERIPH_CLK(host1x,	"host1x",		NULL,	28,	0x180,	260000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT);
+PERIPH_CLK(cve,		"cve",			NULL,	49,	0x140,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(tvo,		"tvo",			NULL,	49,	0x188,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(dtv,		"dtv",			NULL,	79,	0x1dc,	250000000, mux_clk_m,			0);
+PERIPH_CLK(hdmi,	"hdmi",			NULL,	51,	0x18c,	148500000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,	MUX | MUX8 | DIV_U71);
+PERIPH_CLK(tvdac,	"tvdac",		NULL,	53,	0x194,	220000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(disp1,	"tegradc.0",		NULL,	27,	0x138,	600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,	MUX | MUX8);
+PERIPH_CLK(disp2,	"tegradc.1",		NULL,	26,	0x13c,	600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,	MUX | MUX8);
+PERIPH_CLK(usbd,	"fsl-tegra-udc",	NULL,	22,	0,	480000000, mux_clk_m,			0); /* requires min voltage */
+PERIPH_CLK(usb2,	"tegra-ehci.1",		NULL,	58,	0,	480000000, mux_clk_m,			0); /* requires min voltage */
+PERIPH_CLK(usb3,	"tegra-ehci.2",		NULL,	59,	0,	480000000, mux_clk_m,			0); /* requires min voltage */
+PERIPH_CLK(dsia,	"tegradc.0",		"dsia",	48,	0,	500000000, mux_plld_out0,		0);
+PERIPH_CLK(csi,		"tegra_camera",		"csi",	52,	0,	102000000, mux_pllp_out3,		0);
+PERIPH_CLK(isp,		"tegra_camera",		"isp",	23,	0,	150000000, mux_clk_m,			0); /* same frequency as VI */
+PERIPH_CLK(csus,	"tegra_camera",		"csus",	92,	0,	150000000, mux_clk_m,			PERIPH_NO_RESET);
+PERIPH_CLK(tsensor,	"tegra-tsensor",	NULL,	100,	0x3b8,	216000000, mux_pllp_pllc_clkm_clk32,	MUX | DIV_U71);
+PERIPH_CLK(actmon,	"actmon",		NULL,	119,	0x3e8,	216000000, mux_pllp_pllc_clk32_clkm,	MUX | DIV_U71);
+PERIPH_CLK(extern1,	"extern1",		NULL,	120,	0x3ec,	216000000, mux_plla_clk32_pllp_clkm_plle,	MUX | MUX8 | DIV_U71);
+PERIPH_CLK(extern2,	"extern2",		NULL,	121,	0x3f0,	216000000, mux_plla_clk32_pllp_clkm_plle,	MUX | MUX8 | DIV_U71);
+PERIPH_CLK(extern3,	"extern3",		NULL,	122,	0x3f4,	216000000, mux_plla_clk32_pllp_clkm_plle,	MUX | MUX8 | DIV_U71);
+PERIPH_CLK(i2cslow,	"i2cslow",		NULL,	81,	0x3fc,	26000000,  mux_pllp_pllc_clk32_clkm,	MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(pcie,	"tegra-pcie",		"pcie",	70,	0,	250000000, mux_clk_m,			0);
+PERIPH_CLK(afi,		"tegra-pcie",		"afi",	72,	0,	250000000, mux_clk_m,			0);
+PERIPH_CLK(se,		"se",			NULL,	127,	0x42c,	520000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_INT);
+
+static struct clk tegra_dsib;
+static struct clk_tegra tegra_dsib_hw = {
+	.hw = {
+		.clk = &tegra_dsib,
+	},
+	.lookup = {
+		.dev_id	= "tegradc.1",
+		.con_id	= "dsib",
+	},
+	.reg = 0xd0,
+	.flags = MUX | PLLD,
+	.max_rate = 500000000,
+	.u.periph = {
+		.clk_num = 82,
+	},
+	.reset = &tegra30_periph_clk_reset,
+};
+static struct clk tegra_dsib = {
+	.name = "dsib",
+	.ops = &tegra30_dsib_clk_ops,
+	.hw = &tegra_dsib_hw.hw,
+	.parent_names = mux_plld_out0_plld2_out0,
+	.parents = mux_plld_out0_plld2_out0_p,
+	.num_parents = ARRAY_SIZE(mux_plld_out0_plld2_out0),
+};
+
+struct clk *tegra_list_clks[] = {
+	&tegra_apbdma,
+	&tegra_rtc,
+	&tegra_kbc,
+	&tegra_timer,
+	&tegra_kfuse,
+	&tegra_fuse,
+	&tegra_fuse_burn,
+	&tegra_apbif,
+	&tegra_i2s0,
+	&tegra_i2s1,
+	&tegra_i2s2,
+	&tegra_i2s3,
+	&tegra_i2s4,
+	&tegra_spdif_out,
+	&tegra_spdif_in,
+	&tegra_pwm,
+	&tegra_d_audio,
+	&tegra_dam0,
+	&tegra_dam1,
+	&tegra_dam2,
+	&tegra_hda,
+	&tegra_hda2codec_2x,
+	&tegra_hda2hdmi,
+	&tegra_sbc1,
+	&tegra_sbc2,
+	&tegra_sbc3,
+	&tegra_sbc4,
+	&tegra_sbc5,
+	&tegra_sbc6,
+	&tegra_sata_oob,
+	&tegra_sata,
+	&tegra_sata_cold,
+	&tegra_ndflash,
+	&tegra_ndspeed,
+	&tegra_vfir,
+	&tegra_sdmmc1,
+	&tegra_sdmmc2,
+	&tegra_sdmmc3,
+	&tegra_sdmmc4,
+	&tegra_vcp,
+	&tegra_bsea,
+	&tegra_bsev,
+	&tegra_vde,
+	&tegra_csite,
+	&tegra_la,
+	&tegra_owr,
+	&tegra_nor,
+	&tegra_mipi,
+	&tegra_i2c1,
+	&tegra_i2c2,
+	&tegra_i2c3,
+	&tegra_i2c4,
+	&tegra_i2c5,
+	&tegra_uarta,
+	&tegra_uartb,
+	&tegra_uartc,
+	&tegra_uartd,
+	&tegra_uarte,
+	&tegra_vi,
+	&tegra_3d,
+	&tegra_3d2,
+	&tegra_2d,
+	&tegra_vi_sensor,
+	&tegra_epp,
+	&tegra_mpe,
+	&tegra_host1x,
+	&tegra_cve,
+	&tegra_tvo,
+	&tegra_dtv,
+	&tegra_hdmi,
+	&tegra_tvdac,
+	&tegra_disp1,
+	&tegra_disp2,
+	&tegra_usbd,
+	&tegra_usb2,
+	&tegra_usb3,
+	&tegra_dsia,
+	&tegra_dsib,
+	&tegra_csi,
+	&tegra_isp,
+	&tegra_csus,
+	&tegra_tsensor,
+	&tegra_actmon,
+	&tegra_extern1,
+	&tegra_extern2,
+	&tegra_extern3,
+	&tegra_i2cslow,
+	&tegra_pcie,
+	&tegra_afi,
+	&tegra_se,
+};
+
+#define CLK_DUPLICATE(_name, _dev, _con)	\
+	{					\
+		.name	= _name,		\
+		.lookup	= {			\
+			.dev_id	= _dev,		\
+			.con_id	= _con,		\
+		},				\
+	}
+
+/* Some clocks may be used by different drivers depending on the board
+ * configuration.  List those here to register them twice in the clock lookup
+ * table under two names.
+ */
+struct clk_duplicate tegra_clk_duplicates[] = {
+	CLK_DUPLICATE("uarta",  "serial8250.0", NULL),
+	CLK_DUPLICATE("uartb",  "serial8250.1", NULL),
+	CLK_DUPLICATE("uartc",  "serial8250.2", NULL),
+	CLK_DUPLICATE("uartd",  "serial8250.3", NULL),
+	CLK_DUPLICATE("uarte",  "serial8250.4", NULL),
+	CLK_DUPLICATE("usbd", "utmip-pad", NULL),
+	CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
+	CLK_DUPLICATE("usbd", "tegra-otg", NULL),
+	CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
+	CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
+	CLK_DUPLICATE("dsib", "tegradc.0", "dsib"),
+	CLK_DUPLICATE("dsia", "tegradc.1", "dsia"),
+	CLK_DUPLICATE("bsev", "tegra-avp", "bsev"),
+	CLK_DUPLICATE("bsev", "nvavp", "bsev"),
+	CLK_DUPLICATE("vde", "tegra-aes", "vde"),
+	CLK_DUPLICATE("bsea", "tegra-aes", "bsea"),
+	CLK_DUPLICATE("bsea", "nvavp", "bsea"),
+	CLK_DUPLICATE("cml1", "tegra_sata_cml", NULL),
+	CLK_DUPLICATE("cml0", "tegra_pcie", "cml"),
+	CLK_DUPLICATE("pciex", "tegra_pcie", "pciex"),
+	CLK_DUPLICATE("i2c1", "tegra-i2c-slave.0", NULL),
+	CLK_DUPLICATE("i2c2", "tegra-i2c-slave.1", NULL),
+	CLK_DUPLICATE("i2c3", "tegra-i2c-slave.2", NULL),
+	CLK_DUPLICATE("i2c4", "tegra-i2c-slave.3", NULL),
+	CLK_DUPLICATE("i2c5", "tegra-i2c-slave.4", NULL),
+	CLK_DUPLICATE("sbc1", "spi_slave_tegra.0", NULL),
+	CLK_DUPLICATE("sbc2", "spi_slave_tegra.1", NULL),
+	CLK_DUPLICATE("sbc3", "spi_slave_tegra.2", NULL),
+	CLK_DUPLICATE("sbc4", "spi_slave_tegra.3", NULL),
+	CLK_DUPLICATE("sbc5", "spi_slave_tegra.4", NULL),
+	CLK_DUPLICATE("sbc6", "spi_slave_tegra.5", NULL),
+	CLK_DUPLICATE("twd", "smp_twd", NULL),
+	CLK_DUPLICATE("vcp", "nvavp", "vcp"),
+	CLK_DUPLICATE("i2s0", NULL, "i2s0"),
+	CLK_DUPLICATE("i2s1", NULL, "i2s1"),
+	CLK_DUPLICATE("i2s2", NULL, "i2s2"),
+	CLK_DUPLICATE("i2s3", NULL, "i2s3"),
+	CLK_DUPLICATE("i2s4", NULL, "i2s4"),
+	CLK_DUPLICATE("dam0", NULL, "dam0"),
+	CLK_DUPLICATE("dam1", NULL, "dam1"),
+	CLK_DUPLICATE("dam2", NULL, "dam2"),
+	CLK_DUPLICATE("spdif_in", NULL, "spdif_in"),
+	CLK_DUPLICATE("pll_p_out3", "tegra-i2c.0", "fast-clk"),
+	CLK_DUPLICATE("pll_p_out3", "tegra-i2c.1", "fast-clk"),
+	CLK_DUPLICATE("pll_p_out3", "tegra-i2c.2", "fast-clk"),
+	CLK_DUPLICATE("pll_p_out3", "tegra-i2c.3", "fast-clk"),
+	CLK_DUPLICATE("pll_p_out3", "tegra-i2c.4", "fast-clk"),
+};
+
+struct clk *tegra_ptr_clks[] = {
+	&tegra_clk_32k,
+	&tegra_clk_m,
+	&tegra_clk_m_div2,
+	&tegra_clk_m_div4,
+	&tegra_pll_ref,
+	&tegra_pll_m,
+	&tegra_pll_m_out1,
+	&tegra_pll_c,
+	&tegra_pll_c_out1,
+	&tegra_pll_p,
+	&tegra_pll_p_out1,
+	&tegra_pll_p_out2,
+	&tegra_pll_p_out3,
+	&tegra_pll_p_out4,
+	&tegra_pll_a,
+	&tegra_pll_a_out0,
+	&tegra_pll_d,
+	&tegra_pll_d_out0,
+	&tegra_pll_d2,
+	&tegra_pll_d2_out0,
+	&tegra_pll_u,
+	&tegra_pll_x,
+	&tegra_pll_x_out0,
+	&tegra_pll_e,
+	&tegra_clk_cclk_g,
+	&tegra_cml0,
+	&tegra_cml1,
+	&tegra_pciex,
+	&tegra_clk_sclk,
+	&tegra_clk_blink,
+	&tegra30_clk_twd,
+};
+
+static void tegra30_init_one_clock(struct clk *c)
+{
+	struct clk_tegra *clk = to_clk_tegra(c->hw);
+	__clk_init(NULL, c);
+	INIT_LIST_HEAD(&clk->shared_bus_list);
+	if (!clk->lookup.dev_id && !clk->lookup.con_id)
+		clk->lookup.con_id = c->name;
+	clk->lookup.clk = c;
+	clkdev_add(&clk->lookup);
+	tegra_clk_add(c);
+}
+
+void __init tegra30_init_clocks(void)
+{
+	int i;
+	struct clk *c;
+
+	for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
+		tegra30_init_one_clock(tegra_ptr_clks[i]);
+
+	for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
+		tegra30_init_one_clock(tegra_list_clks[i]);
+
+	for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
+		c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
+		if (!c) {
+			pr_err("%s: Unknown duplicate clock %s\n", __func__,
+				tegra_clk_duplicates[i].name);
+			continue;
+		}
+
+		tegra_clk_duplicates[i].lookup.clk = c;
+		clkdev_add(&tegra_clk_duplicates[i].lookup);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(tegra_sync_source_list); i++)
+		tegra30_init_one_clock(tegra_sync_source_list[i]);
+	for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_list); i++)
+		tegra30_init_one_clock(tegra_clk_audio_list[i]);
+	for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_2x_list); i++)
+		tegra30_init_one_clock(tegra_clk_audio_2x_list[i]);
+
+	for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++)
+		tegra30_init_one_clock(tegra_clk_out_list[i]);
+
+	tegra30_cpu_car_ops_init();
+}
diff --git a/arch/arm/mach-tegra/tegra_cpu_car.h b/arch/arm/mach-tegra/tegra_cpu_car.h
new file mode 100644
index 0000000..30d063a
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra_cpu_car.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MACH_TEGRA_CPU_CAR_H
+#define __MACH_TEGRA_CPU_CAR_H
+
+/*
+ * Tegra CPU clock and reset control ops
+ *
+ * wait_for_reset:
+ *	keep waiting until the CPU in reset state
+ * put_in_reset:
+ *	put the CPU in reset state
+ * out_of_reset:
+ *	release the CPU from reset state
+ * enable_clock:
+ *	CPU clock un-gate
+ * disable_clock:
+ *	CPU clock gate
+ */
+struct tegra_cpu_car_ops {
+	void (*wait_for_reset)(u32 cpu);
+	void (*put_in_reset)(u32 cpu);
+	void (*out_of_reset)(u32 cpu);
+	void (*enable_clock)(u32 cpu);
+	void (*disable_clock)(u32 cpu);
+};
+
+extern struct tegra_cpu_car_ops *tegra_cpu_car_ops;
+
+static inline void tegra_wait_cpu_in_reset(u32 cpu)
+{
+	if (WARN_ON(!tegra_cpu_car_ops->wait_for_reset))
+		return;
+
+	tegra_cpu_car_ops->wait_for_reset(cpu);
+}
+
+static inline void tegra_put_cpu_in_reset(u32 cpu)
+{
+	if (WARN_ON(!tegra_cpu_car_ops->put_in_reset))
+		return;
+
+	tegra_cpu_car_ops->put_in_reset(cpu);
+}
+
+static inline void tegra_cpu_out_of_reset(u32 cpu)
+{
+	if (WARN_ON(!tegra_cpu_car_ops->out_of_reset))
+		return;
+
+	tegra_cpu_car_ops->out_of_reset(cpu);
+}
+
+static inline void tegra_enable_cpu_clock(u32 cpu)
+{
+	if (WARN_ON(!tegra_cpu_car_ops->enable_clock))
+		return;
+
+	tegra_cpu_car_ops->enable_clock(cpu);
+}
+
+static inline void tegra_disable_cpu_clock(u32 cpu)
+{
+	if (WARN_ON(!tegra_cpu_car_ops->disable_clock))
+		return;
+
+	tegra_cpu_car_ops->disable_clock(cpu);
+}
+
+void tegra20_cpu_car_ops_init(void);
+void tegra30_cpu_car_ops_init(void);
+
+#endif /* __MACH_TEGRA_CPU_CAR_H */
diff --git a/arch/arm/mach-u300/Kconfig b/arch/arm/mach-u300/Kconfig
index 54d8f34..f7e12ed 100644
--- a/arch/arm/mach-u300/Kconfig
+++ b/arch/arm/mach-u300/Kconfig
@@ -1,6 +1,6 @@
 if ARCH_U300
 
-menu "ST-Ericsson AB U300/U330/U335/U365 Platform"
+menu "ST-Ericsson AB U300/U335 Platform"
 
 comment "ST-Ericsson Mobile Platform Products"
 
@@ -10,46 +10,7 @@ config MACH_U300
 	select PINCTRL_U300
 	select PINCTRL_COH901
 
-comment "ST-Ericsson U300/U330/U335/U365 Feature Selections"
-
-choice
-	prompt "U300/U330/U335/U365 system type"
-	default MACH_U300_BS2X
-	---help---
-	You need to select the target system, i.e. the
-	U300/U330/U335/U365 board that you want to compile your kernel
-	for.
-
-config MACH_U300_BS2X
-	bool "S26/S26/B25/B26 Test Products"
-	depends on MACH_U300
-	help
-		Select this if you're developing on the
-		S26/S25 test products. (Also works on
-		B26/B25 big boards.)
-
-config MACH_U300_BS330
-	bool "S330/B330 Test Products"
-	depends on MACH_U300
-	help
-		Select this if you're developing on the
-		S330/B330 test products.
-
-config MACH_U300_BS335
-	bool "S335/B335 Test Products"
-	depends on MACH_U300
-	help
-		Select this if you're developing on the
-		S335/B335 test products.
-
-config MACH_U300_BS365
-	bool "S365/B365 Test Products"
-	depends on MACH_U300
-	help
-		Select this if you're developing on the
-		S365/B365 test products.
-
-endchoice
+comment "ST-Ericsson U300/U335 Feature Selections"
 
 config U300_DEBUG
 	bool "Debug support for U300"
diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile
index 7e47d37..5a86c58 100644
--- a/arch/arm/mach-u300/Makefile
+++ b/arch/arm/mach-u300/Makefile
@@ -7,7 +7,6 @@ obj-m		:=
 obj-n		:=
 obj-		:=
 
-obj-$(CONFIG_ARCH_U300)	          += u300.o
 obj-$(CONFIG_SPI_PL022)           += spi.o
 obj-$(CONFIG_MACH_U300_SPIDUMMY)  += dummyspichip.o
 obj-$(CONFIG_I2C_STU300)          += i2c.o
diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c
index 03acf18..ef6f602 100644
--- a/arch/arm/mach-u300/core.c
+++ b/arch/arm/mach-u300/core.c
@@ -3,7 +3,7 @@
  * arch/arm/mach-u300/core.c
  *
  *
- * Copyright (C) 2007-2010 ST-Ericsson SA
+ * Copyright (C) 2007-2012 ST-Ericsson SA
  * License terms: GNU General Public License (GPL) version 2
  * Core platform support, IRQ handling and device definitions.
  * Author: Linus Walleij <linus.walleij@stericsson.com>
@@ -31,23 +31,26 @@
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_data/clk-u300.h>
+#include <linux/platform_data/pinctrl-coh901.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
 #include <asm/memory.h>
 #include <asm/hardware/vic.h>
 #include <asm/mach/map.h>
-#include <asm/mach/irq.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
 
 #include <mach/coh901318.h>
 #include <mach/hardware.h>
 #include <mach/syscon.h>
-#include <mach/dma_channels.h>
-#include <mach/gpio-u300.h>
+#include <mach/irqs.h>
 
+#include "timer.h"
 #include "spi.h"
 #include "i2c.h"
 #include "u300-gpio.h"
+#include "dma_channels.h"
 
 /*
  * Static I/O mappings that are needed for booting the U300 platforms. The
@@ -76,7 +79,7 @@ static struct map_desc u300_io_desc[] __initdata = {
 	},
 };
 
-void __init u300_map_io(void)
+static void __init u300_map_io(void)
 {
 	iotable_init(u300_io_desc, ARRAY_SIZE(u300_io_desc));
 	/* We enable a real big DMA buffer if need be. */
@@ -101,7 +104,6 @@ static AMBA_APB_DEVICE(uart0, "uart0", 0, U300_UART0_BASE,
 	{ IRQ_U300_UART0 }, &uart0_plat_data);
 
 /* The U335 have an additional UART1 on the APP CPU */
-#ifdef CONFIG_MACH_U300_BS335
 static struct amba_pl011_data uart1_plat_data = {
 #ifdef CONFIG_COH901318
 	.dma_filter = coh901318_filter_id,
@@ -113,7 +115,6 @@ static struct amba_pl011_data uart1_plat_data = {
 /* Fast device at 0x7000 offset */
 static AMBA_APB_DEVICE(uart1, "uart1", 0, U300_UART1_BASE,
 	{ IRQ_U300_UART1 }, &uart1_plat_data);
-#endif
 
 /* AHB device at 0x4000 offset */
 static AMBA_APB_DEVICE(pl172, "pl172", 0, U300_EMIF_CFG_BASE, { }, NULL);
@@ -152,9 +153,7 @@ static AMBA_APB_DEVICE(mmcsd, "mmci", 0, U300_MMCSD_BASE,
  */
 static struct amba_device *amba_devs[] __initdata = {
 	&uart0_device,
-#ifdef CONFIG_MACH_U300_BS335
 	&uart1_device,
-#endif
 	&pl022_device,
 	&pl172_device,
 	&mmcsd_device,
@@ -188,7 +187,6 @@ static struct resource gpio_resources[] = {
 		.end   = IRQ_U300_GPIO_PORT2,
 		.flags = IORESOURCE_IRQ,
 	},
-#if defined(CONFIG_MACH_U300_BS365) || defined(CONFIG_MACH_U300_BS335)
 	{
 		.name  = "gpio3",
 		.start = IRQ_U300_GPIO_PORT3,
@@ -201,8 +199,6 @@ static struct resource gpio_resources[] = {
 		.end   = IRQ_U300_GPIO_PORT4,
 		.flags = IORESOURCE_IRQ,
 	},
-#endif
-#ifdef CONFIG_MACH_U300_BS335
 	{
 		.name  = "gpio5",
 		.start = IRQ_U300_GPIO_PORT5,
@@ -215,7 +211,6 @@ static struct resource gpio_resources[] = {
 		.end   = IRQ_U300_GPIO_PORT6,
 		.flags = IORESOURCE_IRQ,
 	},
-#endif /* CONFIG_MACH_U300_BS335 */
 };
 
 static struct resource keypad_resources[] = {
@@ -323,7 +318,6 @@ static struct resource dma_resource[] = {
 	}
 };
 
-#ifdef CONFIG_MACH_U300_BS335
 /* points out all dma slave channels.
  * Syntax is [A1, B1, A2, B2, .... ,-1,-1]
  * Select all channels from A to B, end of list is marked with -1,-1
@@ -336,14 +330,6 @@ static int dma_slave_channels[] = {
 static int dma_memcpy_channels[] = {
 	U300_DMA_GENERAL_PURPOSE_0, U300_DMA_GENERAL_PURPOSE_8, -1, -1};
 
-#else /* CONFIG_MACH_U300_BS335 */
-
-static int dma_slave_channels[] = {U300_DMA_MSL_TX_0, U300_DMA_SPI_RX, -1, -1};
-static int dma_memcpy_channels[] = {
-	U300_DMA_GENERAL_PURPOSE_0, U300_DMA_GENERAL_PURPOSE_10, -1, -1};
-
-#endif
-
 /** register dma for memory access
  *
  * active  1 means dma intends to access memory
@@ -1395,7 +1381,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = {
 		.param.ctrl_lli = flags_memcpy_lli,
 		.param.ctrl_lli_last = flags_memcpy_lli_last,
 	},
-#ifdef CONFIG_MACH_U300_BS335
 	{
 		.number = U300_DMA_UART1_TX,
 		.name = "UART1 TX",
@@ -1406,28 +1391,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = {
 		.name = "UART1 RX",
 		.priority_high = 0,
 	}
-#else
-	{
-		.number = U300_DMA_GENERAL_PURPOSE_9,
-		.name = "GENERAL 09",
-		.priority_high = 0,
-
-		.param.config = flags_memcpy_config,
-		.param.ctrl_lli_chained = flags_memcpy_lli_chained,
-		.param.ctrl_lli = flags_memcpy_lli,
-		.param.ctrl_lli_last = flags_memcpy_lli_last,
-	},
-	{
-		.number = U300_DMA_GENERAL_PURPOSE_10,
-		.name = "GENERAL 10",
-		.priority_high = 0,
-
-		.param.config = flags_memcpy_config,
-		.param.ctrl_lli_chained = flags_memcpy_lli_chained,
-		.param.ctrl_lli = flags_memcpy_lli,
-		.param.ctrl_lli_last = flags_memcpy_lli_last,
-	}
-#endif
 };
 
 
@@ -1480,18 +1443,7 @@ static struct platform_device pinctrl_device = {
  * GPIO block, with different number of ports.
  */
 static struct u300_gpio_platform u300_gpio_plat = {
-#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330)
-	.variant = U300_GPIO_COH901335,
-	.ports = 3,
-#endif
-#ifdef CONFIG_MACH_U300_BS335
-	.variant = U300_GPIO_COH901571_3_BS335,
 	.ports = 7,
-#endif
-#ifdef CONFIG_MACH_U300_BS365
-	.variant = U300_GPIO_COH901571_3_BS365,
-	.ports = 5,
-#endif
 	.gpio_base = 0,
 	.gpio_irq_base = IRQ_U300_GPIO_BASE,
 	.pinctrl_device = &pinctrl_device,
@@ -1651,7 +1603,7 @@ static struct platform_device *platform_devs[] __initdata = {
  * together so some interrupts are connected to the first one and some
  * to the second one.
  */
-void __init u300_init_irq(void)
+static void __init u300_init_irq(void)
 {
 	u32 mask[2] = {0, 0};
 	struct clk *clk;
@@ -1756,29 +1708,11 @@ static void __init u300_init_check_chip(void)
 	printk(KERN_INFO "Initializing U300 system on %s baseband chip " \
 	       "(chip ID 0x%04x)\n", chipname, val);
 
-#ifdef CONFIG_MACH_U300_BS330
-	if ((val & 0xFF00U) != 0xd800) {
-		printk(KERN_ERR "Platform configured for BS330 " \
-		       "with DB3200 but %s detected, expect problems!",
-		       chipname);
-	}
-#endif
-#ifdef CONFIG_MACH_U300_BS335
 	if ((val & 0xFF00U) != 0xf000 && (val & 0xFF00U) != 0xf100) {
 		printk(KERN_ERR "Platform configured for BS335 " \
 		       " with DB3350 but %s detected, expect problems!",
 		       chipname);
 	}
-#endif
-#ifdef CONFIG_MACH_U300_BS365
-	if ((val & 0xFF00U) != 0xe800) {
-		printk(KERN_ERR "Platform configured for BS365 " \
-		       "with DB3210 but %s detected, expect problems!",
-		       chipname);
-	}
-#endif
-
-
 }
 
 /*
@@ -1811,7 +1745,7 @@ static void __init u300_assign_physmem(void)
 	}
 }
 
-void __init u300_init_devices(void)
+static void __init u300_init_machine(void)
 {
 	int i;
 	u16 val;
@@ -1852,7 +1786,7 @@ void __init u300_init_devices(void)
 /* Forward declare this function from the watchdog */
 void coh901327_watchdog_reset(void);
 
-void u300_restart(char mode, const char *cmd)
+static void u300_restart(char mode, const char *cmd)
 {
 	switch (mode) {
 	case 's':
@@ -1868,3 +1802,15 @@ void u300_restart(char mode, const char *cmd)
 	/* Wait for system do die/reset. */
 	while (1);
 }
+
+MACHINE_START(U300, "Ericsson AB U335 S335/B335 Prototype Board")
+	/* Maintainer: Linus Walleij <linus.walleij@stericsson.com> */
+	.atag_offset	= 0x100,
+	.map_io		= u300_map_io,
+	.nr_irqs	= NR_IRQS_U300,
+	.init_irq	= u300_init_irq,
+	.handle_irq	= vic_handle_irq,
+	.timer		= &u300_timer,
+	.init_machine	= u300_init_machine,
+	.restart	= u300_restart,
+MACHINE_END
diff --git a/arch/arm/mach-u300/dma_channels.h b/arch/arm/mach-u300/dma_channels.h
new file mode 100644
index 0000000..4e8a88f
--- /dev/null
+++ b/arch/arm/mach-u300/dma_channels.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/dma_channels.h
+ *
+ *
+ * Copyright (C) 2007-2012 ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ * Map file for the U300 dma driver.
+ * Author: Per Friden <per.friden@stericsson.com>
+ */
+
+#ifndef DMA_CHANNELS_H
+#define DMA_CHANNELS_H
+
+#define U300_DMA_MSL_TX_0             0
+#define U300_DMA_MSL_TX_1             1
+#define U300_DMA_MSL_TX_2             2
+#define U300_DMA_MSL_TX_3             3
+#define U300_DMA_MSL_TX_4             4
+#define U300_DMA_MSL_TX_5             5
+#define U300_DMA_MSL_TX_6             6
+#define U300_DMA_MSL_RX_0             7
+#define U300_DMA_MSL_RX_1             8
+#define U300_DMA_MSL_RX_2             9
+#define U300_DMA_MSL_RX_3             10
+#define U300_DMA_MSL_RX_4             11
+#define U300_DMA_MSL_RX_5             12
+#define U300_DMA_MSL_RX_6             13
+#define U300_DMA_MMCSD_RX_TX          14
+#define U300_DMA_MSPRO_TX             15
+#define U300_DMA_MSPRO_RX             16
+#define U300_DMA_UART0_TX             17
+#define U300_DMA_UART0_RX             18
+#define U300_DMA_APEX_TX              19
+#define U300_DMA_APEX_RX              20
+#define U300_DMA_PCM_I2S0_TX          21
+#define U300_DMA_PCM_I2S0_RX          22
+#define U300_DMA_PCM_I2S1_TX          23
+#define U300_DMA_PCM_I2S1_RX          24
+#define U300_DMA_XGAM_CDI             25
+#define U300_DMA_XGAM_PDI             26
+#define U300_DMA_SPI_TX               27
+#define U300_DMA_SPI_RX               28
+#define U300_DMA_GENERAL_PURPOSE_0    29
+#define U300_DMA_GENERAL_PURPOSE_1    30
+#define U300_DMA_GENERAL_PURPOSE_2    31
+#define U300_DMA_GENERAL_PURPOSE_3    32
+#define U300_DMA_GENERAL_PURPOSE_4    33
+#define U300_DMA_GENERAL_PURPOSE_5    34
+#define U300_DMA_GENERAL_PURPOSE_6    35
+#define U300_DMA_GENERAL_PURPOSE_7    36
+#define U300_DMA_GENERAL_PURPOSE_8    37
+#define U300_DMA_UART1_TX             38
+#define U300_DMA_UART1_RX             39
+
+#define U300_DMA_DEVICE_CHANNELS      32
+#define U300_DMA_CHANNELS             40
+
+
+#endif /* DMA_CHANNELS_H */
diff --git a/arch/arm/mach-u300/i2c.c b/arch/arm/mach-u300/i2c.c
index cb04bd6..0d4620e 100644
--- a/arch/arm/mach-u300/i2c.c
+++ b/arch/arm/mach-u300/i2c.c
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-u300/i2c.c
  *
- * Copyright (C) 2009 ST-Ericsson AB
+ * Copyright (C) 2009-2012 ST-Ericsson AB
  * License terms: GNU General Public License (GPL) version 2
  *
  * Register board i2c devices
@@ -261,7 +261,6 @@ static struct i2c_board_info __initdata bus0_i2c_board_info[] = {
 };
 
 static struct i2c_board_info __initdata bus1_i2c_board_info[] = {
-#ifdef CONFIG_MACH_U300_BS335
 	{
 		.type = "fwcam",
 		.addr = 0x10,
@@ -270,9 +269,6 @@ static struct i2c_board_info __initdata bus1_i2c_board_info[] = {
 		.type = "fwcam",
 		.addr = 0x5d,
 	},
-#else
-	{ },
-#endif
 };
 
 void __init u300_i2c_register_board_devices(void)
diff --git a/arch/arm/mach-u300/include/mach/clkdev.h b/arch/arm/mach-u300/include/mach/clkdev.h
deleted file mode 100644
index 92e3cc8..0000000
--- a/arch/arm/mach-u300/include/mach/clkdev.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __MACH_CLKDEV_H
-#define __MACH_CLKDEV_H
-
-int __clk_get(struct clk *clk);
-void __clk_put(struct clk *clk);
-
-#endif
diff --git a/arch/arm/mach-u300/include/mach/dma_channels.h b/arch/arm/mach-u300/include/mach/dma_channels.h
deleted file mode 100644
index b239149..0000000
--- a/arch/arm/mach-u300/include/mach/dma_channels.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/include/mach/dma_channels.h
- *
- *
- * Copyright (C) 2007-2009 ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- * Map file for the U300 dma driver.
- * Author: Per Friden <per.friden@stericsson.com>
- */
-
-#ifndef DMA_CHANNELS_H
-#define DMA_CHANNELS_H
-
-#define U300_DMA_MSL_TX_0             0
-#define U300_DMA_MSL_TX_1             1
-#define U300_DMA_MSL_TX_2             2
-#define U300_DMA_MSL_TX_3             3
-#define U300_DMA_MSL_TX_4             4
-#define U300_DMA_MSL_TX_5             5
-#define U300_DMA_MSL_TX_6             6
-#define U300_DMA_MSL_RX_0             7
-#define U300_DMA_MSL_RX_1             8
-#define U300_DMA_MSL_RX_2             9
-#define U300_DMA_MSL_RX_3             10
-#define U300_DMA_MSL_RX_4             11
-#define U300_DMA_MSL_RX_5             12
-#define U300_DMA_MSL_RX_6             13
-#define U300_DMA_MMCSD_RX_TX          14
-#define U300_DMA_MSPRO_TX             15
-#define U300_DMA_MSPRO_RX             16
-#define U300_DMA_UART0_TX             17
-#define U300_DMA_UART0_RX             18
-#define U300_DMA_APEX_TX              19
-#define U300_DMA_APEX_RX              20
-#define U300_DMA_PCM_I2S0_TX          21
-#define U300_DMA_PCM_I2S0_RX          22
-#define U300_DMA_PCM_I2S1_TX          23
-#define U300_DMA_PCM_I2S1_RX          24
-#define U300_DMA_XGAM_CDI             25
-#define U300_DMA_XGAM_PDI             26
-#define U300_DMA_SPI_TX               27
-#define U300_DMA_SPI_RX               28
-#define U300_DMA_GENERAL_PURPOSE_0    29
-#define U300_DMA_GENERAL_PURPOSE_1    30
-#define U300_DMA_GENERAL_PURPOSE_2    31
-#define U300_DMA_GENERAL_PURPOSE_3    32
-#define U300_DMA_GENERAL_PURPOSE_4    33
-#define U300_DMA_GENERAL_PURPOSE_5    34
-#define U300_DMA_GENERAL_PURPOSE_6    35
-#define U300_DMA_GENERAL_PURPOSE_7    36
-#define U300_DMA_GENERAL_PURPOSE_8    37
-#ifdef CONFIG_MACH_U300_BS335
-#define U300_DMA_UART1_TX             38
-#define U300_DMA_UART1_RX             39
-#else
-#define U300_DMA_GENERAL_PURPOSE_9    38
-#define U300_DMA_GENERAL_PURPOSE_10   39
-#endif
-
-#ifdef CONFIG_MACH_U300_BS335
-#define U300_DMA_DEVICE_CHANNELS      32
-#else
-#define U300_DMA_DEVICE_CHANNELS      30
-#endif
-#define U300_DMA_CHANNELS             40
-
-
-#endif /* DMA_CHANNELS_H */
diff --git a/arch/arm/mach-u300/include/mach/gpio-u300.h b/arch/arm/mach-u300/include/mach/gpio-u300.h
deleted file mode 100644
index e81400c..0000000
--- a/arch/arm/mach-u300/include/mach/gpio-u300.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2007-2011 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * GPIO block resgister definitions and inline macros for
- * U300 GPIO COH 901 335 or COH 901 571/3
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- */
-
-#ifndef __MACH_U300_GPIO_U300_H
-#define __MACH_U300_GPIO_U300_H
-
-/**
- * enum u300_gpio_variant - the type of U300 GPIO employed
- */
-enum u300_gpio_variant {
-	U300_GPIO_COH901335,
-	U300_GPIO_COH901571_3_BS335,
-	U300_GPIO_COH901571_3_BS365,
-};
-
-/**
- * struct u300_gpio_platform - U300 GPIO platform data
- * @variant: IP block variant
- * @ports: number of GPIO block ports
- * @gpio_base: first GPIO number for this block (use a free range)
- * @gpio_irq_base: first GPIO IRQ number for this block (use a free range)
- * @pinctrl_device: pin control device to spawn as child
- */
-struct u300_gpio_platform {
-	enum u300_gpio_variant variant;
-	u8 ports;
-	int gpio_base;
-	int gpio_irq_base;
-	struct platform_device *pinctrl_device;
-};
-
-#endif /* __MACH_U300_GPIO_U300_H */
diff --git a/arch/arm/mach-u300/include/mach/irqs.h b/arch/arm/mach-u300/include/mach/irqs.h
index ec09c1e..e27425a 100644
--- a/arch/arm/mach-u300/include/mach/irqs.h
+++ b/arch/arm/mach-u300/include/mach/irqs.h
@@ -3,7 +3,7 @@
  * arch/arm/mach-u300/include/mach/irqs.h
  *
  *
- * Copyright (C) 2006-2009 ST-Ericsson AB
+ * Copyright (C) 2006-2012 ST-Ericsson AB
  * License terms: GNU General Public License (GPL) version 2
  * IRQ channel definitions for the U300 platforms.
  * Author: Linus Walleij <linus.walleij@stericsson.com>
@@ -31,10 +31,6 @@
 #define IRQ_U300_XGAM_GAMCON		14
 #define IRQ_U300_XGAM_CDI		15
 #define IRQ_U300_XGAM_CDICON		16
-#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330)
-/* MMIACC not used on the DB3210 or DB3350 chips */
-#define IRQ_U300_XGAM_MMIACC		17
-#endif
 #define IRQ_U300_XGAM_PDI		18
 #define IRQ_U300_XGAM_PDICON		19
 #define IRQ_U300_XGAM_GAMEACC		20
@@ -55,8 +51,6 @@
 #define IRQ_U300_GPIO_PORT1		34
 #define IRQ_U300_GPIO_PORT2		35
 
-#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330) || \
-    defined(CONFIG_MACH_U300_BS335)
 /* These are for DB3150, DB3200 and DB3350 */
 #define IRQ_U300_WDOG			36
 #define IRQ_U300_EVHIST			37
@@ -68,15 +62,8 @@
 #define IRQ_U300_RTC			43
 #define IRQ_U300_NFIF			44
 #define IRQ_U300_NFIF2			45
-#endif
-
-/* DB3150 and DB3200 have only 45 IRQs */
-#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330)
-#define U300_VIC_IRQS_END		46
-#endif
 
 /* The DB3350-specific interrupt lines */
-#ifdef CONFIG_MACH_U300_BS335
 #define IRQ_U300_ISP_F0			46
 #define IRQ_U300_ISP_F1			47
 #define IRQ_U300_ISP_F2			48
@@ -89,25 +76,6 @@
 #define IRQ_U300_GPIO_PORT5		55
 #define IRQ_U300_GPIO_PORT6		56
 #define U300_VIC_IRQS_END		57
-#endif
-
-/* The DB3210-specific interrupt lines */
-#ifdef CONFIG_MACH_U300_BS365
-#define IRQ_U300_GPIO_PORT3		36
-#define IRQ_U300_GPIO_PORT4		37
-#define IRQ_U300_WDOG			38
-#define IRQ_U300_EVHIST			39
-#define IRQ_U300_MSPRO			40
-#define IRQ_U300_MMCSD_MCIINTR0		41
-#define IRQ_U300_MMCSD_MCIINTR1		42
-#define IRQ_U300_I2C0			43
-#define IRQ_U300_I2C1			44
-#define IRQ_U300_RTC			45
-#define IRQ_U300_NFIF			46
-#define IRQ_U300_NFIF2			47
-#define IRQ_U300_SYSCON_PLL_LOCK	48
-#define U300_VIC_IRQS_END		49
-#endif
 
 /* Maximum 8*7 GPIO lines */
 #ifdef CONFIG_PINCTRL_COH901
@@ -117,6 +85,6 @@
 #define IRQ_U300_GPIO_END		(U300_VIC_IRQS_END)
 #endif
 
-#define NR_IRQS				(IRQ_U300_GPIO_END - IRQ_U300_INTCON0_START)
+#define NR_IRQS_U300			(IRQ_U300_GPIO_END - IRQ_U300_INTCON0_START)
 
 #endif
diff --git a/arch/arm/mach-u300/include/mach/platform.h b/arch/arm/mach-u300/include/mach/platform.h
deleted file mode 100644
index 096333f..0000000
--- a/arch/arm/mach-u300/include/mach/platform.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/include/mach/platform.h
- *
- *
- * Copyright (C) 2006-2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * Basic platform init and mapping functions.
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- */
-
-#ifndef __ASSEMBLY__
-
-void u300_map_io(void);
-void u300_init_irq(void);
-void u300_init_devices(void);
-void u300_restart(char, const char *);
-extern struct sys_timer u300_timer;
-
-#endif
diff --git a/arch/arm/mach-u300/include/mach/syscon.h b/arch/arm/mach-u300/include/mach/syscon.h
index 6e84f07..10bdd0b 100644
--- a/arch/arm/mach-u300/include/mach/syscon.h
+++ b/arch/arm/mach-u300/include/mach/syscon.h
@@ -3,7 +3,7 @@
  * arch/arm/mach-u300/include/mach/syscon.h
  *
  *
- * Copyright (C) 2008 ST-Ericsson AB
+ * Copyright (C) 2008-2012 ST-Ericsson AB
  *
  * Author: Rickard Andersson <rickard.andersson@stericsson.com>
  */
@@ -36,9 +36,7 @@
 #define U300_SYSCON_CSR_PLL13_LOCK_IND				(0x0001)
 /* Reset lines for SLOW devices 16bit (R/W) */
 #define U300_SYSCON_RSR						(0x0014)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_RSR_PPM_RESET_EN				(0x0200)
-#endif
 #define U300_SYSCON_RSR_ACC_TMR_RESET_EN			(0x0100)
 #define U300_SYSCON_RSR_APP_TMR_RESET_EN			(0x0080)
 #define U300_SYSCON_RSR_RTC_RESET_EN				(0x0040)
@@ -50,9 +48,7 @@
 #define U300_SYSCON_RSR_SLOW_BRIDGE_RESET_EN			(0x0001)
 /* Reset lines for FAST devices 16bit (R/W) */
 #define U300_SYSCON_RFR						(0x0018)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_RFR_UART1_RESET_ENABLE			(0x0080)
-#endif
 #define U300_SYSCON_RFR_SPI_RESET_ENABLE			(0x0040)
 #define U300_SYSCON_RFR_MMC_RESET_ENABLE			(0x0020)
 #define U300_SYSCON_RFR_PCM_I2S1_RESET_ENABLE			(0x0010)
@@ -62,10 +58,8 @@
 #define U300_SYSCON_RFR_FAST_BRIDGE_RESET_ENABLE		(0x0001)
 /* Reset lines for the rest of the peripherals 16bit (R/W) */
 #define U300_SYSCON_RRR						(0x001c)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_RRR_CDS_RESET_EN				(0x4000)
 #define U300_SYSCON_RRR_ISP_RESET_EN				(0x2000)
-#endif
 #define U300_SYSCON_RRR_INTCON_RESET_EN				(0x1000)
 #define U300_SYSCON_RRR_MSPRO_RESET_EN				(0x0800)
 #define U300_SYSCON_RRR_XGAM_RESET_EN				(0x0100)
@@ -79,9 +73,7 @@
 #define U300_SYSCON_RRR_AAIF_RESET_EN				(0x0001)
 /* Clock enable for SLOW peripherals 16bit (R/W) */
 #define U300_SYSCON_CESR					(0x0020)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_CESR_PPM_CLK_EN				(0x0200)
-#endif
 #define U300_SYSCON_CESR_ACC_TMR_CLK_EN				(0x0100)
 #define U300_SYSCON_CESR_APP_TMR_CLK_EN				(0x0080)
 #define U300_SYSCON_CESR_KEYPAD_CLK_EN				(0x0040)
@@ -92,24 +84,20 @@
 #define U300_SYSCON_CESR_SLOW_BRIDGE_CLK_EN			(0x0001)
 /* Clock enable for FAST peripherals 16bit (R/W) */
 #define U300_SYSCON_CEFR					(0x0024)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_CEFR_UART1_CLK_EN				(0x0200)
-#endif
 #define U300_SYSCON_CEFR_I2S1_CORE_CLK_EN			(0x0100)
 #define U300_SYSCON_CEFR_I2S0_CORE_CLK_EN			(0x0080)
 #define U300_SYSCON_CEFR_SPI_CLK_EN				(0x0040)
 #define U300_SYSCON_CEFR_MMC_CLK_EN				(0x0020)
-#define U300_SYSCON_CEFR_I2S1_CLK_EN    			(0x0010)
-#define U300_SYSCON_CEFR_I2S0_CLK_EN     			(0x0008)
-#define U300_SYSCON_CEFR_I2C1_CLK_EN     			(0x0004)
-#define U300_SYSCON_CEFR_I2C0_CLK_EN     			(0x0002)
+#define U300_SYSCON_CEFR_I2S1_CLK_EN				(0x0010)
+#define U300_SYSCON_CEFR_I2S0_CLK_EN				(0x0008)
+#define U300_SYSCON_CEFR_I2C1_CLK_EN				(0x0004)
+#define U300_SYSCON_CEFR_I2C0_CLK_EN				(0x0002)
 #define U300_SYSCON_CEFR_FAST_BRIDGE_CLK_EN			(0x0001)
 /* Clock enable for the rest of the peripherals 16bit (R/W) */
 #define U300_SYSCON_CERR					(0x0028)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_CERR_CDS_CLK_EN				(0x2000)
 #define U300_SYSCON_CERR_ISP_CLK_EN				(0x1000)
-#endif
 #define U300_SYSCON_CERR_MSPRO_CLK_EN				(0x0800)
 #define U300_SYSCON_CERR_AHB_SUBSYS_BRIDGE_CLK_EN		(0x0400)
 #define U300_SYSCON_CERR_SEMI_CLK_EN				(0x0200)
@@ -124,9 +112,7 @@
 #define U300_SYSCON_CERR_AAIF_CLK_EN				(0x0001)
 /* Single block clock enable 16bit (-/W) */
 #define U300_SYSCON_SBCER					(0x002c)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_SBCER_PPM_CLK_EN				(0x0009)
-#endif
 #define U300_SYSCON_SBCER_ACC_TMR_CLK_EN			(0x0008)
 #define U300_SYSCON_SBCER_APP_TMR_CLK_EN			(0x0007)
 #define U300_SYSCON_SBCER_KEYPAD_CLK_EN				(0x0006)
@@ -135,9 +121,7 @@
 #define U300_SYSCON_SBCER_BTR_CLK_EN				(0x0002)
 #define U300_SYSCON_SBCER_UART_CLK_EN				(0x0001)
 #define U300_SYSCON_SBCER_SLOW_BRIDGE_CLK_EN			(0x0000)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_SBCER_UART1_CLK_EN				(0x0019)
-#endif
 #define U300_SYSCON_SBCER_I2S1_CORE_CLK_EN			(0x0018)
 #define U300_SYSCON_SBCER_I2S0_CORE_CLK_EN			(0x0017)
 #define U300_SYSCON_SBCER_SPI_CLK_EN				(0x0016)
@@ -147,10 +131,8 @@
 #define U300_SYSCON_SBCER_I2C1_CLK_EN				(0x0012)
 #define U300_SYSCON_SBCER_I2C0_CLK_EN				(0x0011)
 #define U300_SYSCON_SBCER_FAST_BRIDGE_CLK_EN			(0x0010)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_SBCER_CDS_CLK_EN				(0x002D)
 #define U300_SYSCON_SBCER_ISP_CLK_EN				(0x002C)
-#endif
 #define U300_SYSCON_SBCER_MSPRO_CLK_EN				(0x002B)
 #define U300_SYSCON_SBCER_AHB_SUBSYS_BRIDGE_CLK_EN		(0x002A)
 #define U300_SYSCON_SBCER_SEMI_CLK_EN				(0x0029)
@@ -168,9 +150,7 @@
 /* Same values as above for SBCER */
 /* Clock force SLOW peripherals 16bit (R/W) */
 #define U300_SYSCON_CFSR					(0x003c)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_CFSR_PPM_CLK_FORCE_EN			(0x0200)
-#endif
 #define U300_SYSCON_CFSR_ACC_TMR_CLK_FORCE_EN			(0x0100)
 #define U300_SYSCON_CFSR_APP_TMR_CLK_FORCE_EN			(0x0080)
 #define U300_SYSCON_CFSR_KEYPAD_CLK_FORCE_EN			(0x0020)
@@ -184,10 +164,8 @@
 /* Values not defined. Define if you want to use them. */
 /* Clock force the rest of the peripherals 16bit (R/W) */
 #define U300_SYSCON_CFRR					(0x44)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_CFRR_CDS_CLK_FORCE_EN			(0x2000)
 #define U300_SYSCON_CFRR_ISP_CLK_FORCE_EN			(0x1000)
-#endif
 #define U300_SYSCON_CFRR_MSPRO_CLK_FORCE_EN			(0x0800)
 #define U300_SYSCON_CFRR_AHB_SUBSYS_BRIDGE_CLK_FORCE_EN		(0x0400)
 #define U300_SYSCON_CFRR_SEMI_CLK_FORCE_EN			(0x0200)
diff --git a/arch/arm/mach-u300/include/mach/u300-regs.h b/arch/arm/mach-u300/include/mach/u300-regs.h
index 65f87c5..1e49d90 100644
--- a/arch/arm/mach-u300/include/mach/u300-regs.h
+++ b/arch/arm/mach-u300/include/mach/u300-regs.h
@@ -28,7 +28,6 @@
 #define PLAT_NAND_CLE			(1 << 16)
 #define PLAT_NAND_ALE			(1 << 17)
 
-
 /* AHB Peripherals */
 #define U300_AHB_PER_PHYS_BASE		0xa0000000
 #define U300_AHB_PER_VIRT_BASE		0xff010000
@@ -46,11 +45,7 @@
 #define U300_BOOTROM_VIRT_BASE		0xffff0000
 
 /* SEMI config base */
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SEMI_CONFIG_BASE		0x2FFE0000
-#else
-#define U300_SEMI_CONFIG_BASE		0x30000000
-#endif
 
 /*
  * AHB peripherals
@@ -99,10 +94,8 @@
 /* SPI controller */
 #define U300_SPI_BASE			(U300_FAST_PER_PHYS_BASE+0x6000)
 
-#ifdef CONFIG_MACH_U300_BS335
 /* Fast UART1 on U335 only */
 #define U300_UART1_BASE			(U300_SLOW_PER_PHYS_BASE+0x7000)
-#endif
 
 /*
  * SLOW peripherals
@@ -151,10 +144,8 @@
  * REST peripherals
  */
 
-/* ISP (image signal processor) is only available in U335 */
-#ifdef CONFIG_MACH_U300_BS335
+/* ISP (image signal processor) */
 #define U300_ISP_BASE			(0xA0008000)
-#endif
 
 /* DMA Controller base */
 #define U300_DMAC_BASE			(0xC0020000)
@@ -166,17 +157,9 @@
 #define U300_APEX_BASE			(0xc0030000)
 
 /* Video Encoder Base */
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_VIDEOENC_BASE		(0xc0080000)
-#else
-#define U300_VIDEOENC_BASE		(0xc0040000)
-#endif
 
 /* XGAM Base */
 #define U300_XGAM_BASE			(0xd0000000)
 
-/*
- * Virtual accessor macros for static devices
- */
-
 #endif
diff --git a/arch/arm/mach-u300/spi.c b/arch/arm/mach-u300/spi.c
index a1affac..02e6659 100644
--- a/arch/arm/mach-u300/spi.c
+++ b/arch/arm/mach-u300/spi.c
@@ -12,7 +12,7 @@
 #include <linux/amba/pl022.h>
 #include <linux/err.h>
 #include <mach/coh901318.h>
-#include <mach/dma_channels.h>
+#include "dma_channels.h"
 
 /*
  * The following is for the actual devices on the SSP/SPI bus
diff --git a/arch/arm/mach-u300/timer.c b/arch/arm/mach-u300/timer.c
index 56ac06d..1da10e2 100644
--- a/arch/arm/mach-u300/timer.c
+++ b/arch/arm/mach-u300/timer.c
@@ -17,14 +17,17 @@
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <linux/irq.h>
 
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 
 /* Generic stuff */
 #include <asm/sched_clock.h>
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
-#include <asm/mach/irq.h>
+
+#include "timer.h"
 
 /*
  * APP side special timer registers
diff --git a/arch/arm/mach-u300/timer.h b/arch/arm/mach-u300/timer.h
new file mode 100644
index 0000000..b5e9791
--- /dev/null
+++ b/arch/arm/mach-u300/timer.h
@@ -0,0 +1 @@
+extern struct sys_timer u300_timer;
diff --git a/arch/arm/mach-u300/u300-gpio.h b/arch/arm/mach-u300/u300-gpio.h
index 847dc25..83f5077 100644
--- a/arch/arm/mach-u300/u300-gpio.h
+++ b/arch/arm/mach-u300/u300-gpio.h
@@ -1,50 +1,11 @@
 /*
- * Individual pin assignments for the B26/S26. Notice that the
- * actual usage of these pins depends on the PAD MUX settings, that
- * is why the same number can potentially appear several times.
- * In the reference design each pin is only used for one purpose.
- * These were determined by inspecting the B26/S26 schematic:
- * 2/1911-ROA 128 1603
- */
-#ifdef CONFIG_MACH_U300_BS2X
-#define U300_GPIO_PIN_UART_RX		0
-#define U300_GPIO_PIN_UART_TX		1
-#define U300_GPIO_PIN_GPIO02		2  /* Unrouted */
-#define U300_GPIO_PIN_GPIO03		3  /* Unrouted */
-#define U300_GPIO_PIN_CAM_SLEEP		4
-#define U300_GPIO_PIN_CAM_REG_EN	5
-#define U300_GPIO_PIN_GPIO06		6  /* Unrouted */
-#define U300_GPIO_PIN_GPIO07		7  /* Unrouted */
-
-#define U300_GPIO_PIN_GPIO08		8  /* Service point SP2321 */
-#define U300_GPIO_PIN_GPIO09		9  /* Service point SP2322 */
-#define U300_GPIO_PIN_PHFSENSE		10 /* Headphone jack sensing */
-#define U300_GPIO_PIN_MMC_CLKRET	11 /* Clock return from MMC/SD card */
-#define U300_GPIO_PIN_MMC_CD		12 /* MMC Card insertion detection */
-#define U300_GPIO_PIN_FLIPSENSE		13 /* Mechanical flip sensing */
-#define U300_GPIO_PIN_GPIO14		14 /* DSP JTAG Port RTCK */
-#define U300_GPIO_PIN_GPIO15		15 /* Unrouted */
-
-#define U300_GPIO_PIN_GPIO16		16 /* Unrouted */
-#define U300_GPIO_PIN_GPIO17		17 /* Unrouted */
-#define U300_GPIO_PIN_GPIO18		18 /* Unrouted */
-#define U300_GPIO_PIN_GPIO19		19 /* Unrouted */
-#define U300_GPIO_PIN_GPIO20		20 /* Unrouted */
-#define U300_GPIO_PIN_GPIO21		21 /* Unrouted */
-#define U300_GPIO_PIN_GPIO22		22 /* Unrouted */
-#define U300_GPIO_PIN_GPIO23		23 /* Unrouted */
-#endif
-
-/*
- * Individual pin assignments for the B330/S330 and B365/S365.
+ * Individual pin assignments for the B335/S335.
  * Notice that the actual usage of these pins depends on the
  * PAD MUX settings, that is why the same number can potentially
  * appear several times. In the reference design each pin is only
  * used for one purpose. These were determined by inspecting the
  * S365 schematic.
  */
-#if defined(CONFIG_MACH_U300_BS330) || defined(CONFIG_MACH_U300_BS365) || \
-    defined(CONFIG_MACH_U300_BS335)
 #define U300_GPIO_PIN_UART_RX		0
 #define U300_GPIO_PIN_UART_TX		1
 #define U300_GPIO_PIN_UART_CTS		2
@@ -90,8 +51,6 @@
 #define U300_GPIO_PIN_GPIO38		38 /* Unrouted */
 #define U300_GPIO_PIN_GPIO39		39 /* Unrouted */
 
-#ifdef CONFIG_MACH_U300_BS335
-
 #define U300_GPIO_PIN_GPIO40		40 /* Unrouted */
 #define U300_GPIO_PIN_GPIO41		41 /* Unrouted */
 #define U300_GPIO_PIN_GPIO42		42 /* Unrouted */
@@ -109,6 +68,3 @@
 #define U300_GPIO_PIN_GPIO53		53 /* Unrouted */
 #define U300_GPIO_PIN_GPIO54		54 /* Unrouted */
 #define U300_GPIO_PIN_GPIO55		55 /* Unrouted */
-#endif
-
-#endif
diff --git a/arch/arm/mach-u300/u300.c b/arch/arm/mach-u300/u300.c
deleted file mode 100644
index f30c69d..0000000
--- a/arch/arm/mach-u300/u300.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/u300.c
- *
- *
- * Copyright (C) 2006-2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * Platform machine definition.
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/memblock.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <mach/hardware.h>
-#include <mach/platform.h>
-#include <asm/hardware/vic.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/memory.h>
-
-static void __init u300_init_machine(void)
-{
-	u300_init_devices();
-}
-
-#ifdef CONFIG_MACH_U300_BS2X
-#define MACH_U300_STRING "Ericsson AB U300 S25/S26/B25/B26 Prototype Board"
-#endif
-
-#ifdef CONFIG_MACH_U300_BS330
-#define MACH_U300_STRING "Ericsson AB U330 S330/B330 Prototype Board"
-#endif
-
-#ifdef CONFIG_MACH_U300_BS335
-#define MACH_U300_STRING "Ericsson AB U335 S335/B335 Prototype Board"
-#endif
-
-#ifdef CONFIG_MACH_U300_BS365
-#define MACH_U300_STRING "Ericsson AB U365 S365/B365 Prototype Board"
-#endif
-
-MACHINE_START(U300, MACH_U300_STRING)
-	/* Maintainer: Linus Walleij <linus.walleij@stericsson.com> */
-	.atag_offset	= 0x100,
-	.map_io		= u300_map_io,
-	.init_irq	= u300_init_irq,
-	.handle_irq	= vic_handle_irq,
-	.timer		= &u300_timer,
-	.init_machine	= u300_init_machine,
-	.restart	= u300_restart,
-MACHINE_END
diff --git a/arch/arm/mach-ux500/cache-l2x0.c b/arch/arm/mach-ux500/cache-l2x0.c
index dc12394..75d5b51 100644
--- a/arch/arm/mach-ux500/cache-l2x0.c
+++ b/arch/arm/mach-ux500/cache-l2x0.c
@@ -38,7 +38,7 @@ static int __init ux500_l2x0_init(void)
 {
 	u32 aux_val = 0x3e000000;
 
-	if (cpu_is_u8500_family())
+	if (cpu_is_u8500_family() || cpu_is_ux540_family())
 		l2x0_base = __io_address(U8500_L2CC_BASE);
 	else
 		ux500_unknown_soc();
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index db3c52d..8169f2c 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -19,7 +19,6 @@
 #include <linux/mfd/abx500/ab8500.h>
 
 #include <asm/mach/map.h>
-#include <asm/pmu.h>
 #include <plat/gpio-nomadik.h>
 #include <mach/hardware.h>
 #include <mach/setup.h>
@@ -80,7 +79,7 @@ void __init u8500_map_io(void)
 
 	iotable_init(u8500_common_io_desc, ARRAY_SIZE(u8500_common_io_desc));
 
-	if (cpu_is_u9540())
+	if (cpu_is_ux540_family())
 		iotable_init(u9540_io_desc, ARRAY_SIZE(u9540_io_desc));
 	else
 		iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc));
@@ -122,7 +121,7 @@ struct arm_pmu_platdata db8500_pmu_platdata = {
 
 static struct platform_device db8500_pmu_device = {
 	.name			= "arm-pmu",
-	.id			= ARM_PMU_DEVICE_CPU,
+	.id			= -1,
 	.num_resources		= ARRAY_SIZE(db8500_pmu_resources),
 	.resource		= db8500_pmu_resources,
 	.dev.platform_data	= &db8500_pmu_platdata,
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c
index e2360e7..4b0a9b3 100644
--- a/arch/arm/mach-ux500/cpu.c
+++ b/arch/arm/mach-ux500/cpu.c
@@ -51,7 +51,7 @@ void __init ux500_init_irq(void)
 	void __iomem *dist_base;
 	void __iomem *cpu_base;
 
-	if (cpu_is_u8500_family()) {
+	if (cpu_is_u8500_family() || cpu_is_ux540_family()) {
 		dist_base = __io_address(U8500_GIC_DIST_BASE);
 		cpu_base = __io_address(U8500_GIC_CPU_BASE);
 	} else
diff --git a/arch/arm/mach-ux500/include/mach/id.h b/arch/arm/mach-ux500/include/mach/id.h
index c6e2db9..9c42642 100644
--- a/arch/arm/mach-ux500/include/mach/id.h
+++ b/arch/arm/mach-ux500/include/mach/id.h
@@ -41,43 +41,29 @@ static inline bool __attribute_const__ cpu_is_u8500(void)
 	return dbx500_partnumber() == 0x8500;
 }
 
-static inline bool __attribute_const__ cpu_is_u9540(void)
+static inline bool __attribute_const__ cpu_is_u8520(void)
 {
-	return dbx500_partnumber() == 0x9540;
+	return dbx500_partnumber() == 0x8520;
 }
 
 static inline bool cpu_is_u8500_family(void)
 {
-	return cpu_is_u8500() || cpu_is_u9540();
-}
-
-static inline bool __attribute_const__ cpu_is_u5500(void)
-{
-	return dbx500_partnumber() == 0x5500;
-}
-
-/*
- * 5500 revisions
- */
-
-static inline bool __attribute_const__ cpu_is_u5500v1(void)
-{
-	return cpu_is_u5500() && (dbx500_revision() & 0xf0) == 0xA0;
+	return cpu_is_u8500() || cpu_is_u8520();
 }
 
-static inline bool __attribute_const__ cpu_is_u5500v2(void)
+static inline bool __attribute_const__ cpu_is_u9540(void)
 {
-	return (dbx500_id.revision & 0xf0) == 0xB0;
+	return dbx500_partnumber() == 0x9540;
 }
 
-static inline bool __attribute_const__ cpu_is_u5500v20(void)
+static inline bool __attribute_const__ cpu_is_u8540(void)
 {
-	return cpu_is_u5500() && ((dbx500_revision() & 0xf0) == 0xB0);
+	return dbx500_partnumber() == 0x8540;
 }
 
-static inline bool __attribute_const__ cpu_is_u5500v21(void)
+static inline bool cpu_is_ux540_family(void)
 {
-	return cpu_is_u5500() && (dbx500_revision() == 0xB1);
+	return cpu_is_u9540() || cpu_is_u8540();
 }
 
 /*
@@ -119,14 +105,14 @@ static inline bool cpu_is_u8500v21(void)
 	return cpu_is_u8500() && (dbx500_revision() == 0xB1);
 }
 
+static inline bool cpu_is_u8500v22(void)
+{
+	return cpu_is_u8500() && (dbx500_revision() == 0xB2);
+}
+
 static inline bool cpu_is_u8500v20_or_later(void)
 {
-	/*
-	 * U9540 has so much in common with U8500 that is is considered a
-	 * U8500 variant.
-	 */
-	return cpu_is_u9540() ||
-		(cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11());
+	return (cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11());
 }
 
 static inline bool ux500_is_svp(void)
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c
index da1d5ad..cb35897 100644
--- a/arch/arm/mach-ux500/platsmp.c
+++ b/arch/arm/mach-ux500/platsmp.c
@@ -48,7 +48,7 @@ static void write_pen_release(int val)
 
 static void __iomem *scu_base_addr(void)
 {
-	if (cpu_is_u8500_family())
+	if (cpu_is_u8500_family() || cpu_is_ux540_family())
 		return __io_address(U8500_SCU_BASE);
 	else
 		ux500_unknown_soc();
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index cd8ea35..5b5c1ee 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -37,7 +37,6 @@
 #include <linux/mtd/physmap.h>
 
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/icst.h>
 #include <asm/hardware/vic.h>
@@ -169,11 +168,6 @@ static struct map_desc versatile_io_desc[] __initdata = {
 		.pfn		= __phys_to_pfn(VERSATILE_PCI_CFG_BASE),
 		.length		= VERSATILE_PCI_CFG_BASE_SIZE,
 		.type		= MT_DEVICE
-	}, {
-		.virtual	=  (unsigned long)VERSATILE_PCI_VIRT_MEM_BASE0,
-		.pfn		= __phys_to_pfn(VERSATILE_PCI_MEM_BASE0),
-		.length		= IO_SPACE_LIMIT,
-		.type		= MT_DEVICE
 	},
 #endif
 };
@@ -763,10 +757,6 @@ void __init versatile_init(void)
 		struct amba_device *d = amba_devs[i];
 		amba_device_register(d, &iomem_resource);
 	}
-
-#ifdef CONFIG_LEDS
-	leds_event = versatile_leds_event;
-#endif
 }
 
 /*
diff --git a/arch/arm/mach-versatile/include/mach/hardware.h b/arch/arm/mach-versatile/include/mach/hardware.h
index 408e58d..3e5d425 100644
--- a/arch/arm/mach-versatile/include/mach/hardware.h
+++ b/arch/arm/mach-versatile/include/mach/hardware.h
@@ -29,7 +29,6 @@
  */
 #define VERSATILE_PCI_VIRT_BASE		(void __iomem *)0xe8000000ul
 #define VERSATILE_PCI_CFG_VIRT_BASE	(void __iomem *)0xe9000000ul
-#define VERSATILE_PCI_VIRT_MEM_BASE0	(void __iomem *)PCIO_BASE
 
 /* macro to get at MMIO space when running virtually */
 #define IO_ADDRESS(x)		(((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000)
diff --git a/arch/arm/mach-versatile/include/mach/io.h b/arch/arm/mach-versatile/include/mach/io.h
deleted file mode 100644
index 0406513..0000000
--- a/arch/arm/mach-versatile/include/mach/io.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- *  arch/arm/mach-versatile/include/mach/io.h
- *
- *  Copyright (C) 2003 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define PCIO_BASE	0xeb000000ul
-
-#define __io(a)		((a) + PCIO_BASE)
-
-#endif
diff --git a/arch/arm/mach-versatile/pci.c b/arch/arm/mach-versatile/pci.c
index e95bf84..2f84f40 100644
--- a/arch/arm/mach-versatile/pci.c
+++ b/arch/arm/mach-versatile/pci.c
@@ -169,13 +169,6 @@ static struct pci_ops pci_versatile_ops = {
 	.write	= versatile_write_config,
 };
 
-static struct resource io_port = {
-	.name	= "PCI",
-	.start	= 0,
-	.end	= IO_SPACE_LIMIT,
-	.flags	= IORESOURCE_IO,
-};
-
 static struct resource io_mem = {
 	.name	= "PCI I/O space",
 	.start	= VERSATILE_PCI_MEM_BASE0,
@@ -207,12 +200,6 @@ static int __init pci_versatile_setup_resources(struct pci_sys_data *sys)
 		       "memory region (%d)\n", ret);
 		goto out;
 	}
-	ret = request_resource(&ioport_resource, &io_port);
-	if (ret) {
-		printk(KERN_ERR "PCI: unable to allocate I/O "
-		       "port region (%d)\n", ret);
-		goto out;
-	}
 	ret = request_resource(&iomem_resource, &non_mem);
 	if (ret) {
 		printk(KERN_ERR "PCI: unable to allocate non-prefetchable "
@@ -227,11 +214,9 @@ static int __init pci_versatile_setup_resources(struct pci_sys_data *sys)
 	}
 
 	/*
-	 * the IO resource for this bus
 	 * the mem resource for this bus
 	 * the prefetch mem resource for this bus
 	 */
-	pci_add_resource_offset(&sys->resources, &io_port, sys->io_offset);
 	pci_add_resource_offset(&sys->resources, &non_mem, sys->mem_offset);
 	pci_add_resource_offset(&sys->resources, &pre_mem, sys->mem_offset);
 
@@ -260,9 +245,11 @@ int __init pci_versatile_setup(int nr, struct pci_sys_data *sys)
 		goto out;
 	}
 
+	ret = pci_ioremap_io(0, VERSATILE_PCI_MEM_BASE0);
+	if (ret)
+		goto out;
+
 	if (nr == 0) {
-		sys->mem_offset = 0;
-		sys->io_offset = 0;
 		ret = pci_versatile_setup_resources(sys);
 		if (ret < 0) {
 			printk("pci_versatile_setup: resources... oops?\n");
@@ -319,7 +306,6 @@ int __init pci_versatile_setup(int nr, struct pci_sys_data *sys)
 
 void __init pci_versatile_preinit(void)
 {
-	pcibios_min_io = 0x44000000;
 	pcibios_min_mem = 0x50000000;
 
 	__raw_writel(VERSATILE_PCI_MEM_BASE0 >> 28, PCI_IMAP0);
diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
index 61c4924..e4073a6 100644
--- a/arch/arm/mach-vexpress/ct-ca9x4.c
+++ b/arch/arm/mach-vexpress/ct-ca9x4.c
@@ -13,7 +13,6 @@
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/hardware/gic.h>
-#include <asm/pmu.h>
 #include <asm/smp_scu.h>
 #include <asm/smp_twd.h>
 
@@ -144,7 +143,7 @@ static struct resource pmu_resources[] = {
 
 static struct platform_device pmu_device = {
 	.name		= "arm-pmu",
-	.id		= ARM_PMU_DEVICE_CPU,
+	.id		= -1,
 	.num_resources	= ARRAY_SIZE(pmu_resources),
 	.resource	= pmu_resources,
 };
diff --git a/arch/arm/mach-vt8500/bv07.c b/arch/arm/mach-vt8500/bv07.c
index f9fbeb2..6fd9d60 100644
--- a/arch/arm/mach-vt8500/bv07.c
+++ b/arch/arm/mach-vt8500/bv07.c
@@ -33,6 +33,7 @@ static struct platform_device *devices[] __initdata = {
 	&vt8500_device_uart0,
 	&vt8500_device_lcdc,
 	&vt8500_device_ehci,
+	&vt8500_device_uhci,
 	&vt8500_device_ge_rops,
 	&vt8500_device_pwm,
 	&vt8500_device_pwmbl,
diff --git a/arch/arm/mach-vt8500/devices-vt8500.c b/arch/arm/mach-vt8500/devices-vt8500.c
index 19519ae..def7fe3 100644
--- a/arch/arm/mach-vt8500/devices-vt8500.c
+++ b/arch/arm/mach-vt8500/devices-vt8500.c
@@ -48,6 +48,11 @@ void __init vt8500_set_resources(void)
 	tmp[1] = wmt_irq_res(IRQ_EHCI);
 	wmt_res_add(&vt8500_device_ehci, tmp, 2);
 
+	/* vt8500 uses a single IRQ for both EHCI and UHCI controllers */
+	tmp[0] = wmt_mmio_res(VT8500_UHCI_BASE, SZ_512);
+	tmp[1] = wmt_irq_res(IRQ_EHCI);
+	wmt_res_add(&vt8500_device_uhci, tmp, 2);
+
 	tmp[0] = wmt_mmio_res(VT8500_GEGEA_BASE, SZ_256);
 	wmt_res_add(&vt8500_device_ge_rops, tmp, 1);
 
diff --git a/arch/arm/mach-vt8500/devices-wm8505.c b/arch/arm/mach-vt8500/devices-wm8505.c
index db4594e..c810454 100644
--- a/arch/arm/mach-vt8500/devices-wm8505.c
+++ b/arch/arm/mach-vt8500/devices-wm8505.c
@@ -55,6 +55,10 @@ void __init wm8505_set_resources(void)
 	tmp[1] = wmt_irq_res(IRQ_EHCI);
 	wmt_res_add(&vt8500_device_ehci, tmp, 2);
 
+	tmp[0] = wmt_mmio_res(WM8505_UHCI_BASE, SZ_512);
+	tmp[1] = wmt_irq_res(IRQ_UHCI);
+	wmt_res_add(&vt8500_device_uhci, tmp, 2);
+
 	tmp[0] = wmt_mmio_res(WM8505_GEGEA_BASE, SZ_256);
 	wmt_res_add(&vt8500_device_ge_rops, tmp, 1);
 
diff --git a/arch/arm/mach-vt8500/devices.c b/arch/arm/mach-vt8500/devices.c
index 1fcdc36..46ff82d 100644
--- a/arch/arm/mach-vt8500/devices.c
+++ b/arch/arm/mach-vt8500/devices.c
@@ -204,6 +204,17 @@ struct platform_device vt8500_device_ehci = {
 	},
 };
 
+static u64 uhci_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device vt8500_device_uhci = {
+	.name		= "platform-uhci",
+	.id		= 0,
+	.dev		= {
+		.dma_mask	= &uhci_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
 struct platform_device vt8500_device_ge_rops = {
 	.name		= "wmt_ge_rops",
 	.id		= -1,
diff --git a/arch/arm/mach-vt8500/devices.h b/arch/arm/mach-vt8500/devices.h
index 188d4e1..0e6d9f9 100644
--- a/arch/arm/mach-vt8500/devices.h
+++ b/arch/arm/mach-vt8500/devices.h
@@ -81,6 +81,7 @@ extern struct platform_device vt8500_device_uart5;
 extern struct platform_device vt8500_device_lcdc;
 extern struct platform_device vt8500_device_wm8505_fb;
 extern struct platform_device vt8500_device_ehci;
+extern struct platform_device vt8500_device_uhci;
 extern struct platform_device vt8500_device_ge_rops;
 extern struct platform_device vt8500_device_pwm;
 extern struct platform_device vt8500_device_pwmbl;
diff --git a/arch/arm/mach-vt8500/wm8505_7in.c b/arch/arm/mach-vt8500/wm8505_7in.c
index db19886..4804e2a 100644
--- a/arch/arm/mach-vt8500/wm8505_7in.c
+++ b/arch/arm/mach-vt8500/wm8505_7in.c
@@ -32,6 +32,7 @@ static void __iomem *pmc_hiber;
 static struct platform_device *devices[] __initdata = {
 	&vt8500_device_uart0,
 	&vt8500_device_ehci,
+	&vt8500_device_uhci,
 	&vt8500_device_wm8505_fb,
 	&vt8500_device_ge_rops,
 	&vt8500_device_pwm,
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 2a8e380..577baf7 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -554,7 +554,7 @@ static const struct of_device_id l2x0_ids[] __initconst = {
 int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
 {
 	struct device_node *np;
-	struct l2x0_of_data *data;
+	const struct l2x0_of_data *data;
 	struct resource res;
 
 	np = of_find_matching_node(NULL, l2x0_ids);
diff --git a/arch/arm/mm/cache-tauros2.c b/arch/arm/mm/cache-tauros2.c
index 23a7643..1be0f4e 100644
--- a/arch/arm/mm/cache-tauros2.c
+++ b/arch/arm/mm/cache-tauros2.c
@@ -15,8 +15,11 @@
  */
 
 #include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
+#include <asm/cputype.h>
 #include <asm/hardware/cache-tauros2.h>
 
 
@@ -144,25 +147,8 @@ static inline void __init write_extra_features(u32 u)
 	__asm__("mcr p15, 1, %0, c15, c1, 0" : : "r" (u));
 }
 
-static void __init disable_l2_prefetch(void)
-{
-	u32 u;
-
-	/*
-	 * Read the CPU Extra Features register and verify that the
-	 * Disable L2 Prefetch bit is set.
-	 */
-	u = read_extra_features();
-	if (!(u & 0x01000000)) {
-		printk(KERN_INFO "Tauros2: Disabling L2 prefetch.\n");
-		write_extra_features(u | 0x01000000);
-	}
-}
-
 static inline int __init cpuid_scheme(void)
 {
-	extern int processor_id;
-
 	return !!((processor_id & 0x000f0000) == 0x000f0000);
 }
 
@@ -189,12 +175,36 @@ static inline void __init write_actlr(u32 actlr)
 	__asm__("mcr p15, 0, %0, c1, c0, 1\n" : : "r" (actlr));
 }
 
-void __init tauros2_init(void)
+static void enable_extra_feature(unsigned int features)
+{
+	u32 u;
+
+	u = read_extra_features();
+
+	if (features & CACHE_TAUROS2_PREFETCH_ON)
+		u &= ~0x01000000;
+	else
+		u |= 0x01000000;
+	printk(KERN_INFO "Tauros2: %s L2 prefetch.\n",
+			(features & CACHE_TAUROS2_PREFETCH_ON)
+			? "Enabling" : "Disabling");
+
+	if (features & CACHE_TAUROS2_LINEFILL_BURST8)
+		u |= 0x00100000;
+	else
+		u &= ~0x00100000;
+	printk(KERN_INFO "Tauros2: %s line fill burt8.\n",
+			(features & CACHE_TAUROS2_LINEFILL_BURST8)
+			? "Enabling" : "Disabling");
+
+	write_extra_features(u);
+}
+
+static void __init tauros2_internal_init(unsigned int features)
 {
-	extern int processor_id;
-	char *mode;
+	char *mode = NULL;
 
-	disable_l2_prefetch();
+	enable_extra_feature(features);
 
 #ifdef CONFIG_CPU_32v5
 	if ((processor_id & 0xff0f0000) == 0x56050000) {
@@ -286,3 +296,34 @@ void __init tauros2_init(void)
 	printk(KERN_INFO "Tauros2: L2 cache support initialised "
 			 "in %s mode.\n", mode);
 }
+
+#ifdef CONFIG_OF
+static const struct of_device_id tauros2_ids[] __initconst = {
+	{ .compatible = "marvell,tauros2-cache"},
+	{}
+};
+#endif
+
+void __init tauros2_init(unsigned int features)
+{
+#ifdef CONFIG_OF
+	struct device_node *node;
+	int ret;
+	unsigned int f;
+
+	node = of_find_matching_node(NULL, tauros2_ids);
+	if (!node) {
+		pr_info("Not found marvell,tauros2-cache, disable it\n");
+		return;
+	}
+
+	ret = of_property_read_u32(node, "marvell,tauros2-cache-features", &f);
+	if (ret) {
+		pr_info("Not found marvell,tauros-cache-features property, "
+			"disable extra features\n");
+		features = 0;
+	} else
+		features = f;
+#endif
+	tauros2_internal_init(features);
+}
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 7745854..40ca11e 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -231,8 +231,6 @@ void __sync_icache_dcache(pte_t pteval)
 	struct page *page;
 	struct address_space *mapping;
 
-	if (!pte_present_user(pteval))
-		return;
 	if (cache_is_vipt_nonaliasing() && !pte_exec(pteval))
 		/* only flush non-aliasing VIPT caches for exec mappings */
 		return;
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 9aec41f..ad722f1 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -324,7 +324,7 @@ phys_addr_t __init arm_memblock_steal(phys_addr_t size, phys_addr_t align)
 
 	BUG_ON(!arm_memblock_steal_permitted);
 
-	phys = memblock_alloc(size, align);
+	phys = memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ANYWHERE);
 	memblock_free(phys, size);
 	memblock_remove(phys, size);
 
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 566750f..9d869f9 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -36,6 +36,7 @@
 #include <asm/system_info.h>
 
 #include <asm/mach/map.h>
+#include <asm/mach/pci.h>
 #include "mm.h"
 
 int ioremap_page(unsigned long virt, unsigned long phys,
@@ -383,3 +384,16 @@ void __arm_iounmap(volatile void __iomem *io_addr)
 	arch_iounmap(io_addr);
 }
 EXPORT_SYMBOL(__arm_iounmap);
+
+#ifdef CONFIG_PCI
+int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr)
+{
+	BUG_ON(offset + SZ_64K > IO_SPACE_LIMIT);
+
+	return ioremap_page_range(PCI_IO_VIRT_BASE + offset,
+				  PCI_IO_VIRT_BASE + offset + SZ_64K,
+				  phys_addr,
+				  __pgprot(get_mem_type(MT_DEVICE)->prot_pte));
+}
+EXPORT_SYMBOL_GPL(pci_ioremap_io);
+#endif
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 4c2d045..512b2c0 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -31,6 +31,7 @@
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/mach/pci.h>
 
 #include "mm.h"
 
@@ -216,7 +217,7 @@ static struct mem_type mem_types[] = {
 		.prot_l1	= PMD_TYPE_TABLE,
 		.prot_sect	= PROT_SECT_DEVICE | PMD_SECT_WB,
 		.domain		= DOMAIN_IO,
-	},	
+	},
 	[MT_DEVICE_WC] = {	/* ioremap_wc */
 		.prot_pte	= PROT_PTE_DEVICE | L_PTE_MT_DEV_WC,
 		.prot_l1	= PMD_TYPE_TABLE,
@@ -777,14 +778,27 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
 		create_mapping(md);
 		vm->addr = (void *)(md->virtual & PAGE_MASK);
 		vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
-		vm->phys_addr = __pfn_to_phys(md->pfn); 
-		vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING; 
+		vm->phys_addr = __pfn_to_phys(md->pfn);
+		vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
 		vm->flags |= VM_ARM_MTYPE(md->type);
 		vm->caller = iotable_init;
 		vm_area_add_early(vm++);
 	}
 }
 
+void __init vm_reserve_area_early(unsigned long addr, unsigned long size,
+				  void *caller)
+{
+	struct vm_struct *vm;
+
+	vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm));
+	vm->addr = (void *)addr;
+	vm->size = size;
+	vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
+	vm->caller = caller;
+	vm_area_add_early(vm);
+}
+
 #ifndef CONFIG_ARM_LPAE
 
 /*
@@ -802,14 +816,7 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
 
 static void __init pmd_empty_section_gap(unsigned long addr)
 {
-	struct vm_struct *vm;
-
-	vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm));
-	vm->addr = (void *)addr;
-	vm->size = SECTION_SIZE;
-	vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
-	vm->caller = pmd_empty_section_gap;
-	vm_area_add_early(vm);
+	vm_reserve_area_early(addr, SECTION_SIZE, pmd_empty_section_gap);
 }
 
 static void __init fill_pmd_gaps(void)
@@ -858,6 +865,28 @@ static void __init fill_pmd_gaps(void)
 #define fill_pmd_gaps() do { } while (0)
 #endif
 
+#if defined(CONFIG_PCI) && !defined(CONFIG_NEED_MACH_IO_H)
+static void __init pci_reserve_io(void)
+{
+	struct vm_struct *vm;
+	unsigned long addr;
+
+	/* we're still single threaded hence no lock needed here */
+	for (vm = vmlist; vm; vm = vm->next) {
+		if (!(vm->flags & VM_ARM_STATIC_MAPPING))
+			continue;
+		addr = (unsigned long)vm->addr;
+		addr &= ~(SZ_2M - 1);
+		if (addr == PCI_IO_VIRT_BASE)
+			return;
+
+	}
+	vm_reserve_area_early(PCI_IO_VIRT_BASE, SZ_2M, pci_reserve_io);
+}
+#else
+#define pci_reserve_io() do { } while (0)
+#endif
+
 static void * __initdata vmalloc_min =
 	(void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET);
 
@@ -1141,6 +1170,9 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
 		mdesc->map_io();
 	fill_pmd_gaps();
 
+	/* Reserve fixed i/o space in VMALLOC region */
+	pci_reserve_io();
+
 	/*
 	 * Finally flush the caches and tlb to ensure that we're in a
 	 * consistent state wrt the writebuffer.  This also ensures that
diff --git a/arch/arm/mm/tlb-v7.S b/arch/arm/mm/tlb-v7.S
index c202113..ea94765 100644
--- a/arch/arm/mm/tlb-v7.S
+++ b/arch/arm/mm/tlb-v7.S
@@ -38,10 +38,10 @@ ENTRY(v7wbi_flush_user_tlb_range)
 	dsb
 	mov	r0, r0, lsr #PAGE_SHIFT		@ align address
 	mov	r1, r1, lsr #PAGE_SHIFT
-#ifdef CONFIG_ARM_ERRATA_720789
-	mov	r3, #0
-#else
 	asid	r3, r3				@ mask ASID
+#ifdef CONFIG_ARM_ERRATA_720789
+	ALT_SMP(W(mov)	r3, #0	)
+	ALT_UP(W(nop)		)
 #endif
 	orr	r0, r3, r0, lsl #PAGE_SHIFT	@ Create initial MVA
 	mov	r1, r1, lsl #PAGE_SHIFT
diff --git a/arch/arm/plat-iop/pci.c b/arch/arm/plat-iop/pci.c
index 8daae9b..362474b 100644
--- a/arch/arm/plat-iop/pci.c
+++ b/arch/arm/plat-iop/pci.c
@@ -192,30 +192,24 @@ int iop3xx_pci_setup(int nr, struct pci_sys_data *sys)
 	if (nr != 0)
 		return 0;
 
-	res = kzalloc(2 * sizeof(struct resource), GFP_KERNEL);
+	res = kzalloc(sizeof(struct resource), GFP_KERNEL);
 	if (!res)
 		panic("PCI: unable to alloc resources");
 
-	res[0].start = IOP3XX_PCI_LOWER_IO_PA;
-	res[0].end   = IOP3XX_PCI_LOWER_IO_PA + IOP3XX_PCI_IO_WINDOW_SIZE - 1;
-	res[0].name  = "IOP3XX PCI I/O Space";
-	res[0].flags = IORESOURCE_IO;
-	request_resource(&ioport_resource, &res[0]);
-
-	res[1].start = IOP3XX_PCI_LOWER_MEM_PA;
-	res[1].end   = IOP3XX_PCI_LOWER_MEM_PA + IOP3XX_PCI_MEM_WINDOW_SIZE - 1;
-	res[1].name  = "IOP3XX PCI Memory Space";
-	res[1].flags = IORESOURCE_MEM;
-	request_resource(&iomem_resource, &res[1]);
+	res->start = IOP3XX_PCI_LOWER_MEM_PA;
+	res->end   = IOP3XX_PCI_LOWER_MEM_PA + IOP3XX_PCI_MEM_WINDOW_SIZE - 1;
+	res->name  = "IOP3XX PCI Memory Space";
+	res->flags = IORESOURCE_MEM;
+	request_resource(&iomem_resource, res);
 
 	/*
 	 * Use whatever translation is already setup.
 	 */
 	sys->mem_offset = IOP3XX_PCI_LOWER_MEM_PA - *IOP3XX_OMWTVR0;
-	sys->io_offset  = IOP3XX_PCI_LOWER_IO_PA - *IOP3XX_OIOWTVR;
 
-	pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
-	pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, res, sys->mem_offset);
+
+	pci_ioremap_io(0, IOP3XX_PCI_LOWER_IO_PA);
 
 	return 1;
 }
@@ -367,7 +361,6 @@ void __init iop3xx_pci_preinit_cond(void)
 
 void __init iop3xx_pci_preinit(void)
 {
-	pcibios_min_io = 0;
 	pcibios_min_mem = 0;
 
 	iop3xx_atu_disable();
diff --git a/arch/arm/plat-iop/pmu.c b/arch/arm/plat-iop/pmu.c
index a2024b8..ad9f974 100644
--- a/arch/arm/plat-iop/pmu.c
+++ b/arch/arm/plat-iop/pmu.c
@@ -9,7 +9,6 @@
  */
 
 #include <linux/platform_device.h>
-#include <asm/pmu.h>
 #include <mach/irqs.h>
 
 static struct resource pmu_resource = {
@@ -26,7 +25,7 @@ static struct resource pmu_resource = {
 
 static struct platform_device pmu_device = {
 	.name		= "arm-pmu",
-	.id		= ARM_PMU_DEVICE_CPU,
+	.id		= -1,
 	.resource	= &pmu_resource,
 	.num_resources	= 1,
 };
diff --git a/arch/arm/plat-iop/setup.c b/arch/arm/plat-iop/setup.c
index bade586..5b217f4 100644
--- a/arch/arm/plat-iop/setup.c
+++ b/arch/arm/plat-iop/setup.c
@@ -25,11 +25,6 @@ static struct map_desc iop3xx_std_desc[] __initdata = {
 		.pfn		= __phys_to_pfn(IOP3XX_PERIPHERAL_PHYS_BASE),
 		.length		= IOP3XX_PERIPHERAL_SIZE,
 		.type		= MT_UNCACHED,
-	 }, {	/* PCI IO space */
-		.virtual	= IOP3XX_PCI_LOWER_IO_VA,
-		.pfn		= __phys_to_pfn(IOP3XX_PCI_LOWER_IO_PA),
-		.length		= IOP3XX_PCI_IO_WINDOW_SIZE,
-		.type		= MT_DEVICE,
 	 },
 };
 
diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig
index cb3e3ee..6b46cee 100644
--- a/arch/arm/plat-mxc/devices/Kconfig
+++ b/arch/arm/plat-mxc/devices/Kconfig
@@ -15,7 +15,11 @@ config IMX_HAVE_PLATFORM_GPIO_KEYS
 
 config IMX_HAVE_PLATFORM_IMX21_HCD
 	bool
-	
+
+config IMX_HAVE_PLATFORM_IMX27_CODA
+	bool
+	default y if SOC_IMX27
+
 config IMX_HAVE_PLATFORM_IMX2_WDT
 	bool
 
diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile
index c11ac84..76f3195 100644
--- a/arch/arm/plat-mxc/devices/Makefile
+++ b/arch/arm/plat-mxc/devices/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_FSL_USB2_UDC) += platform-fsl-usb2-udc.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_GPIO_KEYS) += platform-gpio_keys.o
 obj-y += platform-gpio-mxc.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX21_HCD) += platform-imx21-hcd.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX27_CODA) += platform-imx27-coda.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX2_WDT) += platform-imx2-wdt.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_IMXDI_RTC) += platform-imxdi_rtc.o
 obj-y += platform-imx-dma.o
diff --git a/arch/arm/plat-mxc/devices/platform-imx27-coda.c b/arch/arm/plat-mxc/devices/platform-imx27-coda.c
new file mode 100644
index 0000000..8b12aac
--- /dev/null
+++ b/arch/arm/plat-mxc/devices/platform-imx27-coda.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 Vista Silicon
+ * Javier Martin <javier.martin@vista-silicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+
+#ifdef CONFIG_SOC_IMX27
+const struct imx_imx27_coda_data imx27_coda_data __initconst = {
+	.iobase = MX27_VPU_BASE_ADDR,
+	.iosize = SZ_512,
+	.irq = MX27_INT_VPU,
+};
+#endif
+
+struct platform_device *__init imx_add_imx27_coda(
+		const struct imx_imx27_coda_data *data)
+{
+	struct resource res[] = {
+		{
+			.start = data->iobase,
+			.end = data->iobase + data->iosize - 1,
+			.flags = IORESOURCE_MEM,
+		}, {
+			.start = data->irq,
+			.end = data->irq,
+			.flags = IORESOURCE_IRQ,
+		},
+	};
+	return imx_add_platform_device_dmamask("coda-imx27", 0, res, 2, NULL,
+					0, DMA_BIT_MASK(32));
+}
diff --git a/arch/arm/plat-mxc/devices/platform-mxc_nand.c b/arch/arm/plat-mxc/devices/platform-mxc_nand.c
index 1568f39..95b75cc 100644
--- a/arch/arm/plat-mxc/devices/platform-mxc_nand.c
+++ b/arch/arm/plat-mxc/devices/platform-mxc_nand.c
@@ -63,10 +63,6 @@ struct platform_device *__init imx_add_mxc_nand(
 	/* AXI has to come first, that's how the mxc_nand driver expect it */
 	struct resource res[] = {
 		{
-			.start = data->axibase,
-			.end = data->axibase + SZ_16K - 1,
-			.flags = IORESOURCE_MEM,
-		}, {
 			.start = data->iobase,
 			.end = data->iobase + data->iosize - 1,
 			.flags = IORESOURCE_MEM,
@@ -74,10 +70,13 @@ struct platform_device *__init imx_add_mxc_nand(
 			.start = data->irq,
 			.end = data->irq,
 			.flags = IORESOURCE_IRQ,
+		}, {
+			.start = data->axibase,
+			.end = data->axibase + SZ_16K - 1,
+			.flags = IORESOURCE_MEM,
 		},
 	};
 	return imx_add_platform_device("mxc_nand", data->id,
-			res + !data->axibase,
-			ARRAY_SIZE(res) - !data->axibase,
+			res, ARRAY_SIZE(res) - !data->axibase,
 			pdata, sizeof(*pdata));
 }
diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h
index a7f5bb1..762780c 100644
--- a/arch/arm/plat-mxc/include/mach/devices-common.h
+++ b/arch/arm/plat-mxc/include/mach/devices-common.h
@@ -83,6 +83,14 @@ struct platform_device *__init imx_add_imx21_hcd(
 		const struct imx_imx21_hcd_data *data,
 		const struct mx21_usbh_platform_data *pdata);
 
+struct imx_imx27_coda_data {
+	resource_size_t iobase;
+	resource_size_t iosize;
+	resource_size_t irq;
+};
+struct platform_device *__init imx_add_imx27_coda(
+		const struct imx_imx27_coda_data *data);
+
 struct imx_imx2_wdt_data {
 	int id;
 	resource_size_t iobase;
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index dd36eba..13910ba 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -41,9 +41,8 @@ config OMAP_DEBUG_DEVICES
 	  For debug cards on TI reference boards.
 
 config OMAP_DEBUG_LEDS
-	bool
+	def_bool y if NEW_LEDS
 	depends on OMAP_DEBUG_DEVICES
-	default y if LEDS_CLASS
 
 config POWER_AVS_OMAP
 	bool "AVS(Adaptive Voltage Scaling) support for OMAP IP versions 1&2"
diff --git a/arch/arm/plat-omap/debug-leds.c b/arch/arm/plat-omap/debug-leds.c
index 39407cb..24e23f3 100644
--- a/arch/arm/plat-omap/debug-leds.c
+++ b/arch/arm/plat-omap/debug-leds.c
@@ -1,279 +1,118 @@
 /*
  * linux/arch/arm/plat-omap/debug-leds.c
  *
+ * Copyright 2011 by Bryan Wu <bryan.wu@canonical.com>
  * Copyright 2003 by Texas Instruments Incorporated
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/gpio.h>
+
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
 #include <linux/io.h>
+#include <linux/slab.h>
 
 #include <mach/hardware.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 
 #include <plat/fpga.h>
 
-
 /* Many OMAP development platforms reuse the same "debug board"; these
  * platforms include H2, H3, H4, and Perseus2.  There are 16 LEDs on the
  * debug board (all green), accessed through FPGA registers.
- *
- * The "surfer" expansion board and H2 sample board also have two-color
- * green+red LEDs (in parallel), used here for timer and idle indicators
- * in preference to the ones on the debug board, for a "Disco LED" effect.
- *
- * This driver exports either the original ARM LED API, the new generic
- * one, or both.
- */
-
-static spinlock_t			lock;
-static struct h2p2_dbg_fpga __iomem	*fpga;
-static u16				led_state, hw_led_state;
-
-
-#ifdef	CONFIG_OMAP_DEBUG_LEDS
-#define new_led_api()	1
-#else
-#define new_led_api()	0
-#endif
-
-
-/*-------------------------------------------------------------------------*/
-
-/* original ARM debug LED API:
- *  - timer and idle leds (some boards use non-FPGA leds here);
- *  - up to 4 generic leds, easily accessed in-kernel (any context)
  */
 
-#define GPIO_LED_RED		3
-#define GPIO_LED_GREEN		OMAP_MPUIO(4)
-
-#define LED_STATE_ENABLED	0x01
-#define LED_STATE_CLAIMED	0x02
-#define LED_TIMER_ON		0x04
-
-#define GPIO_IDLE		GPIO_LED_GREEN
-#define GPIO_TIMER		GPIO_LED_RED
-
-static void h2p2_dbg_leds_event(led_event_t evt)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&lock, flags);
-
-	if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
-		goto done;
-
-	switch (evt) {
-	case led_start:
-		if (fpga)
-			led_state |= LED_STATE_ENABLED;
-		break;
-
-	case led_stop:
-	case led_halted:
-		/* all leds off during suspend or shutdown */
-
-		if (!(machine_is_omap_perseus2() || machine_is_omap_h4())) {
-			gpio_set_value(GPIO_TIMER, 0);
-			gpio_set_value(GPIO_IDLE, 0);
-		}
-
-		__raw_writew(~0, &fpga->leds);
-		led_state &= ~LED_STATE_ENABLED;
-		goto done;
-
-	case led_claim:
-		led_state |= LED_STATE_CLAIMED;
-		hw_led_state = 0;
-		break;
-
-	case led_release:
-		led_state &= ~LED_STATE_CLAIMED;
-		break;
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		led_state ^= LED_TIMER_ON;
-
-		if (machine_is_omap_perseus2() || machine_is_omap_h4())
-			hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER;
-		else {
-			gpio_set_value(GPIO_TIMER,
-					led_state & LED_TIMER_ON);
-			goto done;
-		}
-
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-	/* LED lit iff busy */
-	case led_idle_start:
-		if (machine_is_omap_perseus2() || machine_is_omap_h4())
-			hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE;
-		else {
-			gpio_set_value(GPIO_IDLE, 1);
-			goto done;
-		}
-
-		break;
+static struct h2p2_dbg_fpga __iomem *fpga;
 
-	case led_idle_end:
-		if (machine_is_omap_perseus2() || machine_is_omap_h4())
-			hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE;
-		else {
-			gpio_set_value(GPIO_IDLE, 0);
-			goto done;
-		}
-
-		break;
-#endif
-
-	case led_green_on:
-		hw_led_state |= H2P2_DBG_FPGA_LED_GREEN;
-		break;
-	case led_green_off:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN;
-		break;
-
-	case led_amber_on:
-		hw_led_state |= H2P2_DBG_FPGA_LED_AMBER;
-		break;
-	case led_amber_off:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER;
-		break;
-
-	case led_red_on:
-		hw_led_state |= H2P2_DBG_FPGA_LED_RED;
-		break;
-	case led_red_off:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_RED;
-		break;
-
-	case led_blue_on:
-		hw_led_state |= H2P2_DBG_FPGA_LED_BLUE;
-		break;
-	case led_blue_off:
-		hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE;
-		break;
-
-	default:
-		break;
-	}
-
-
-	/*
-	 *  Actually burn the LEDs
-	 */
-	if (led_state & LED_STATE_ENABLED)
-		__raw_writew(~hw_led_state, &fpga->leds);
-
-done:
-	spin_unlock_irqrestore(&lock, flags);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* "new" LED API
- *  - with syfs access and generic triggering
- *  - not readily accessible to in-kernel drivers
- */
+static u16 fpga_led_state;
 
 struct dbg_led {
 	struct led_classdev	cdev;
 	u16			mask;
 };
 
-static struct dbg_led dbg_leds[] = {
-	/* REVISIT at least H2 uses different timer & cpu leds... */
-#ifndef CONFIG_LEDS_TIMER
-	{ .mask = 1 << 0,  .cdev.name =  "d4:green",
-		.cdev.default_trigger = "heartbeat", },
-#endif
-#ifndef CONFIG_LEDS_CPU
-	{ .mask = 1 << 1,  .cdev.name =  "d5:green", },		/* !idle */
-#endif
-	{ .mask = 1 << 2,  .cdev.name =  "d6:green", },
-	{ .mask = 1 << 3,  .cdev.name =  "d7:green", },
-
-	{ .mask = 1 << 4,  .cdev.name =  "d8:green", },
-	{ .mask = 1 << 5,  .cdev.name =  "d9:green", },
-	{ .mask = 1 << 6,  .cdev.name = "d10:green", },
-	{ .mask = 1 << 7,  .cdev.name = "d11:green", },
-
-	{ .mask = 1 << 8,  .cdev.name = "d12:green", },
-	{ .mask = 1 << 9,  .cdev.name = "d13:green", },
-	{ .mask = 1 << 10, .cdev.name = "d14:green", },
-	{ .mask = 1 << 11, .cdev.name = "d15:green", },
-
-#ifndef	CONFIG_LEDS
-	{ .mask = 1 << 12, .cdev.name = "d16:green", },
-	{ .mask = 1 << 13, .cdev.name = "d17:green", },
-	{ .mask = 1 << 14, .cdev.name = "d18:green", },
-	{ .mask = 1 << 15, .cdev.name = "d19:green", },
-#endif
+static const struct {
+	const char *name;
+	const char *trigger;
+} dbg_leds[] = {
+	{ "dbg:d4", "heartbeat", },
+	{ "dbg:d5", "cpu0", },
+	{ "dbg:d6", "default-on", },
+	{ "dbg:d7", },
+	{ "dbg:d8", },
+	{ "dbg:d9", },
+	{ "dbg:d10", },
+	{ "dbg:d11", },
+	{ "dbg:d12", },
+	{ "dbg:d13", },
+	{ "dbg:d14", },
+	{ "dbg:d15", },
+	{ "dbg:d16", },
+	{ "dbg:d17", },
+	{ "dbg:d18", },
+	{ "dbg:d19", },
 };
 
-static void
-fpga_led_set(struct led_classdev *cdev, enum led_brightness value)
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static void dbg_led_set(struct led_classdev *cdev,
+			      enum led_brightness b)
 {
-	struct dbg_led	*led = container_of(cdev, struct dbg_led, cdev);
-	unsigned long	flags;
+	struct dbg_led *led = container_of(cdev, struct dbg_led, cdev);
+	u16 reg;
 
-	spin_lock_irqsave(&lock, flags);
-	if (value == LED_OFF)
-		hw_led_state &= ~led->mask;
+	reg = __raw_readw(&fpga->leds);
+	if (b != LED_OFF)
+		reg |= led->mask;
 	else
-		hw_led_state |= led->mask;
-	__raw_writew(~hw_led_state, &fpga->leds);
-	spin_unlock_irqrestore(&lock, flags);
+		reg &= ~led->mask;
+	__raw_writew(reg, &fpga->leds);
 }
 
-static void __init newled_init(struct device *dev)
+static enum led_brightness dbg_led_get(struct led_classdev *cdev)
 {
-	unsigned	i;
-	struct dbg_led	*led;
-	int		status;
+	struct dbg_led *led = container_of(cdev, struct dbg_led, cdev);
+	u16 reg;
 
-	for (i = 0, led = dbg_leds; i < ARRAY_SIZE(dbg_leds); i++, led++) {
-		led->cdev.brightness_set = fpga_led_set;
-		status = led_classdev_register(dev, &led->cdev);
-		if (status < 0)
-			break;
-	}
-	return;
+	reg = __raw_readw(&fpga->leds);
+	return (reg & led->mask) ? LED_FULL : LED_OFF;
 }
 
-
-/*-------------------------------------------------------------------------*/
-
-static int /* __init */ fpga_probe(struct platform_device *pdev)
+static int fpga_probe(struct platform_device *pdev)
 {
 	struct resource	*iomem;
-
-	spin_lock_init(&lock);
+	int i;
 
 	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!iomem)
 		return -ENODEV;
 
 	fpga = ioremap(iomem->start, H2P2_DBG_FPGA_SIZE);
-	__raw_writew(~0, &fpga->leds);
+	__raw_writew(0xff, &fpga->leds);
+
+	for (i = 0; i < ARRAY_SIZE(dbg_leds); i++) {
+		struct dbg_led *led;
+
+		led = kzalloc(sizeof(*led), GFP_KERNEL);
+		if (!led)
+			break;
 
-#ifdef	CONFIG_LEDS
-	leds_event = h2p2_dbg_leds_event;
-	leds_event(led_start);
-#endif
+		led->cdev.name = dbg_leds[i].name;
+		led->cdev.brightness_set = dbg_led_set;
+		led->cdev.brightness_get = dbg_led_get;
+		led->cdev.default_trigger = dbg_leds[i].trigger;
+		led->mask = BIT(i);
 
-	if (new_led_api()) {
-		newled_init(&pdev->dev);
+		if (led_classdev_register(NULL, &led->cdev) < 0) {
+			kfree(led);
+			break;
+		}
 	}
 
 	return 0;
@@ -281,13 +120,15 @@ static int /* __init */ fpga_probe(struct platform_device *pdev)
 
 static int fpga_suspend_noirq(struct device *dev)
 {
-	__raw_writew(~0, &fpga->leds);
+	fpga_led_state = __raw_readw(&fpga->leds);
+	__raw_writew(0xff, &fpga->leds);
+
 	return 0;
 }
 
 static int fpga_resume_noirq(struct device *dev)
 {
-	__raw_writew(~hw_led_state, &fpga->leds);
+	__raw_writew(~fpga_led_state, &fpga->leds);
 	return 0;
 }
 
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 626ad8c..938b50a 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -189,6 +189,7 @@ struct omap_dm_timer *omap_dm_timer_request(void)
 		timer->reserved = 1;
 		break;
 	}
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
 	if (timer) {
 		ret = omap_dm_timer_prepare(timer);
@@ -197,7 +198,6 @@ struct omap_dm_timer *omap_dm_timer_request(void)
 			timer = NULL;
 		}
 	}
-	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
 	if (!timer)
 		pr_debug("%s: timer request failed!\n", __func__);
@@ -220,6 +220,7 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
 			break;
 		}
 	}
+	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
 	if (timer) {
 		ret = omap_dm_timer_prepare(timer);
@@ -228,7 +229,6 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
 			timer = NULL;
 		}
 	}
-	spin_unlock_irqrestore(&dm_timer_lock, flags);
 
 	if (!timer)
 		pr_debug("%s: timer%d request failed!\n", __func__, id);
@@ -258,7 +258,7 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
 
 void omap_dm_timer_disable(struct omap_dm_timer *timer)
 {
-	pm_runtime_put(&timer->pdev->dev);
+	pm_runtime_put_sync(&timer->pdev->dev);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
 
diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h
index 68b180e..bb5d08a 100644
--- a/arch/arm/plat-omap/include/plat/cpu.h
+++ b/arch/arm/plat-omap/include/plat/cpu.h
@@ -372,7 +372,8 @@ IS_OMAP_TYPE(3430, 0x3430)
 #define cpu_class_is_omap1()	(cpu_is_omap7xx() || cpu_is_omap15xx() || \
 				cpu_is_omap16xx())
 #define cpu_class_is_omap2()	(cpu_is_omap24xx() || cpu_is_omap34xx() || \
-				cpu_is_omap44xx() || soc_is_omap54xx())
+				cpu_is_omap44xx() || soc_is_omap54xx() || \
+				soc_is_am33xx())
 
 /* Various silicon revisions for omap2 */
 #define OMAP242X_CLASS		0x24200024
diff --git a/arch/arm/plat-omap/include/plat/multi.h b/arch/arm/plat-omap/include/plat/multi.h
index 045e320..324d31b 100644
--- a/arch/arm/plat-omap/include/plat/multi.h
+++ b/arch/arm/plat-omap/include/plat/multi.h
@@ -108,4 +108,13 @@
 # endif
 #endif
 
+#ifdef CONFIG_SOC_AM33XX
+# ifdef OMAP_NAME
+#  undef  MULTI_OMAP2
+#  define MULTI_OMAP2
+# else
+#  define OMAP_NAME am33xx
+# endif
+#endif
+
 #endif	/* __PLAT_OMAP_MULTI_H */
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index 1a52725..52d3de4 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -69,6 +69,9 @@ struct omap_uart_port_info {
 	unsigned int		dma_rx_timeout;
 	unsigned int		autosuspend_timeout;
 	unsigned int		dma_rx_poll_rate;
+	int			DTR_gpio;
+	int			DTR_inverted;
+	int			DTR_present;
 
 	int (*get_context_loss_count)(struct device *);
 	void (*set_forceidle)(struct platform_device *);
@@ -131,6 +134,10 @@ struct uart_omap_port {
 	u32			errata;
 	u8			wakeups_enabled;
 
+	int			DTR_gpio;
+	int			DTR_inverted;
+	int			DTR_active;
+
 	struct pm_qos_request	pm_qos_request;
 	u32			latency;
 	u32			calc_latency;
diff --git a/arch/arm/plat-omap/include/plat/uncompress.h b/arch/arm/plat-omap/include/plat/uncompress.h
index b8d19a1..7f7b112 100644
--- a/arch/arm/plat-omap/include/plat/uncompress.h
+++ b/arch/arm/plat-omap/include/plat/uncompress.h
@@ -110,7 +110,7 @@ static inline void flush(void)
 	_DEBUG_LL_ENTRY(mach, AM33XX_UART##p##_BASE, OMAP_PORT_SHIFT,	\
 		AM33XXUART##p)
 
-static inline void __arch_decomp_setup(unsigned long arch_id)
+static inline void arch_decomp_setup(void)
 {
 	int port = 0;
 
@@ -198,8 +198,6 @@ static inline void __arch_decomp_setup(unsigned long arch_id)
 	} while (0);
 }
 
-#define arch_decomp_setup()	__arch_decomp_setup(arch_id)
-
 /*
  * nothing to do
  */
diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c
index d245a87..b8b747a 100644
--- a/arch/arm/plat-orion/common.c
+++ b/arch/arm/plat-orion/common.c
@@ -291,10 +291,12 @@ static struct platform_device orion_ge00 = {
 void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data,
 			    unsigned long mapbase,
 			    unsigned long irq,
-			    unsigned long irq_err)
+			    unsigned long irq_err,
+			    unsigned int tx_csum_limit)
 {
 	fill_resources(&orion_ge00_shared, orion_ge00_shared_resources,
 		       mapbase + 0x2000, SZ_16K - 1, irq_err);
+	orion_ge00_shared_data.tx_csum_limit = tx_csum_limit;
 	ge_complete(&orion_ge00_shared_data,
 		    orion_ge00_resources, irq, &orion_ge00_shared,
 		    eth_data, &orion_ge00);
@@ -343,10 +345,12 @@ static struct platform_device orion_ge01 = {
 void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data,
 			    unsigned long mapbase,
 			    unsigned long irq,
-			    unsigned long irq_err)
+			    unsigned long irq_err,
+			    unsigned int tx_csum_limit)
 {
 	fill_resources(&orion_ge01_shared, orion_ge01_shared_resources,
 		       mapbase + 0x2000, SZ_16K - 1, irq_err);
+	orion_ge01_shared_data.tx_csum_limit = tx_csum_limit;
 	ge_complete(&orion_ge01_shared_data,
 		    orion_ge01_resources, irq, &orion_ge01_shared,
 		    eth_data, &orion_ge01);
diff --git a/arch/arm/plat-orion/include/plat/common.h b/arch/arm/plat-orion/include/plat/common.h
index e00fdb2..ae2377e 100644
--- a/arch/arm/plat-orion/include/plat/common.h
+++ b/arch/arm/plat-orion/include/plat/common.h
@@ -39,12 +39,14 @@ void __init orion_rtc_init(unsigned long mapbase,
 void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data,
 			    unsigned long mapbase,
 			    unsigned long irq,
-			    unsigned long irq_err);
+			    unsigned long irq_err,
+			    unsigned int tx_csum_limit);
 
 void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data,
 			    unsigned long mapbase,
 			    unsigned long irq,
-			    unsigned long irq_err);
+			    unsigned long irq_err,
+			    unsigned int tx_csum_limit);
 
 void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data,
 			    unsigned long mapbase,
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index 28f898f..db98e70 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -430,7 +430,7 @@ s3c2410_dma_canload(struct s3c2410_dma_chan *chan)
  * when necessary.
 */
 
-int s3c2410_dma_enqueue(unsigned int channel, void *id,
+int s3c2410_dma_enqueue(enum dma_ch channel, void *id,
 			dma_addr_t data, int size)
 {
 	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index 74e31ce..6ff45d5 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -32,8 +32,9 @@
 #include <linux/platform_data/s3c-hsudc.h>
 #include <linux/platform_data/s3c-hsotg.h>
 
+#include <media/s5p_hdmi.h>
+
 #include <asm/irq.h>
-#include <asm/pmu.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
@@ -748,7 +749,8 @@ void __init s5p_i2c_hdmiphy_set_platdata(struct s3c2410_platform_i2c *pd)
 	if (!pd) {
 		pd = &default_i2c_data;
 
-		if (soc_is_exynos4210())
+		if (soc_is_exynos4210() ||
+		    soc_is_exynos4212() || soc_is_exynos4412())
 			pd->bus_num = 8;
 		else if (soc_is_s5pv210())
 			pd->bus_num = 3;
@@ -759,6 +761,30 @@ void __init s5p_i2c_hdmiphy_set_platdata(struct s3c2410_platform_i2c *pd)
 	npd = s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c),
 			       &s5p_device_i2c_hdmiphy);
 }
+
+struct s5p_hdmi_platform_data s5p_hdmi_def_platdata;
+
+void __init s5p_hdmi_set_platdata(struct i2c_board_info *hdmiphy_info,
+				  struct i2c_board_info *mhl_info, int mhl_bus)
+{
+	struct s5p_hdmi_platform_data *pd = &s5p_hdmi_def_platdata;
+
+	if (soc_is_exynos4210() ||
+	    soc_is_exynos4212() || soc_is_exynos4412())
+		pd->hdmiphy_bus = 8;
+	else if (soc_is_s5pv210())
+		pd->hdmiphy_bus = 3;
+	else
+		pd->hdmiphy_bus = 0;
+
+	pd->hdmiphy_info = hdmiphy_info;
+	pd->mhl_info = mhl_info;
+	pd->mhl_bus = mhl_bus;
+
+	s3c_set_platdata(pd, sizeof(struct s5p_hdmi_platform_data),
+			 &s5p_device_hdmi);
+}
+
 #endif /* CONFIG_S5P_DEV_I2C_HDMIPHY */
 
 /* I2S */
@@ -1105,7 +1131,7 @@ static struct resource s5p_pmu_resource[] = {
 
 static struct platform_device s5p_device_pmu = {
 	.name		= "arm-pmu",
-	.id		= ARM_PMU_DEVICE_CPU,
+	.id		= -1,
 	.num_resources	= ARRAY_SIZE(s5p_pmu_resource),
 	.resource	= s5p_pmu_resource,
 };
diff --git a/arch/arm/plat-samsung/include/plat/hdmi.h b/arch/arm/plat-samsung/include/plat/hdmi.h
new file mode 100644
index 0000000..331d046
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/hdmi.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *
+ * 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.
+ */
+
+#ifndef __PLAT_SAMSUNG_HDMI_H
+#define __PLAT_SAMSUNG_HDMI_H __FILE__
+
+extern void s5p_hdmi_set_platdata(struct i2c_board_info *hdmiphy_info,
+				  struct i2c_board_info *mhl_info, int mhl_bus);
+
+#endif /* __PLAT_SAMSUNG_HDMI_H */
diff --git a/arch/arm/plat-samsung/include/plat/regs-fb-v4.h b/arch/arm/plat-samsung/include/plat/regs-fb-v4.h
deleted file mode 100644
index 4c3647f..0000000
--- a/arch/arm/plat-samsung/include/plat/regs-fb-v4.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/* arch/arm/plat-samsung/include/plat/regs-fb-v4.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *      http://armlinux.simtec.co.uk/
- *      Ben Dooks <ben@simtec.co.uk>
- *
- * S3C64XX - new-style framebuffer register definitions
- *
- * This is the register set for the new style framebuffer interface
- * found from the S3C2443 onwards and specifically the S3C64XX series
- * S3C6400 and S3C6410.
- *
- * The file contains the cpu specific items which change between whichever
- * architecture is selected. See <plat/regs-fb.h> for the core definitions
- * that are the same.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-/* include the core definitions here, in case we really do need to
- * override them at a later date.
-*/
-
-#include <plat/regs-fb.h>
-
-#define S3C_FB_MAX_WIN (5)  /* number of hardware windows available. */
-#define VIDCON1_FSTATUS_EVEN	(1 << 15)
-
-/* Video timing controls */
-#define VIDTCON0				(0x10)
-#define VIDTCON1				(0x14)
-#define VIDTCON2				(0x18)
-
-/* Window position controls */
-
-#define WINCON(_win)				(0x20 + ((_win) * 4))
-
-/* OSD1 and OSD4 do not have register D */
-
-#define VIDOSD_BASE				(0x40)
-
-#define VIDINTCON0				(0x130)
-
-/* WINCONx */
-
-#define WINCONx_CSCWIDTH_MASK			(0x3 << 26)
-#define WINCONx_CSCWIDTH_SHIFT			(26)
-#define WINCONx_CSCWIDTH_WIDE			(0x0 << 26)
-#define WINCONx_CSCWIDTH_NARROW			(0x3 << 26)
-
-#define WINCONx_ENLOCAL				(1 << 22)
-#define WINCONx_BUFSTATUS			(1 << 21)
-#define WINCONx_BUFSEL				(1 << 20)
-#define WINCONx_BUFAUTOEN			(1 << 19)
-#define WINCONx_YCbCr				(1 << 13)
-
-#define WINCON1_LOCALSEL_CAMIF			(1 << 23)
-
-#define WINCON2_LOCALSEL_CAMIF			(1 << 23)
-#define WINCON2_BLD_PIX				(1 << 6)
-
-#define WINCON2_ALPHA_SEL			(1 << 1)
-#define WINCON2_BPPMODE_MASK			(0xf << 2)
-#define WINCON2_BPPMODE_SHIFT			(2)
-#define WINCON2_BPPMODE_1BPP			(0x0 << 2)
-#define WINCON2_BPPMODE_2BPP			(0x1 << 2)
-#define WINCON2_BPPMODE_4BPP			(0x2 << 2)
-#define WINCON2_BPPMODE_8BPP_1232		(0x4 << 2)
-#define WINCON2_BPPMODE_16BPP_565		(0x5 << 2)
-#define WINCON2_BPPMODE_16BPP_A1555		(0x6 << 2)
-#define WINCON2_BPPMODE_16BPP_I1555		(0x7 << 2)
-#define WINCON2_BPPMODE_18BPP_666		(0x8 << 2)
-#define WINCON2_BPPMODE_18BPP_A1665		(0x9 << 2)
-#define WINCON2_BPPMODE_19BPP_A1666		(0xa << 2)
-#define WINCON2_BPPMODE_24BPP_888		(0xb << 2)
-#define WINCON2_BPPMODE_24BPP_A1887		(0xc << 2)
-#define WINCON2_BPPMODE_25BPP_A1888		(0xd << 2)
-#define WINCON2_BPPMODE_28BPP_A4888		(0xd << 2)
-
-#define WINCON3_BLD_PIX				(1 << 6)
-
-#define WINCON3_ALPHA_SEL			(1 << 1)
-#define WINCON3_BPPMODE_MASK			(0xf << 2)
-#define WINCON3_BPPMODE_SHIFT			(2)
-#define WINCON3_BPPMODE_1BPP			(0x0 << 2)
-#define WINCON3_BPPMODE_2BPP			(0x1 << 2)
-#define WINCON3_BPPMODE_4BPP			(0x2 << 2)
-#define WINCON3_BPPMODE_16BPP_565		(0x5 << 2)
-#define WINCON3_BPPMODE_16BPP_A1555		(0x6 << 2)
-#define WINCON3_BPPMODE_16BPP_I1555		(0x7 << 2)
-#define WINCON3_BPPMODE_18BPP_666		(0x8 << 2)
-#define WINCON3_BPPMODE_18BPP_A1665		(0x9 << 2)
-#define WINCON3_BPPMODE_19BPP_A1666		(0xa << 2)
-#define WINCON3_BPPMODE_24BPP_888		(0xb << 2)
-#define WINCON3_BPPMODE_24BPP_A1887		(0xc << 2)
-#define WINCON3_BPPMODE_25BPP_A1888		(0xd << 2)
-#define WINCON3_BPPMODE_28BPP_A4888		(0xd << 2)
-
-#define VIDINTCON0_FIFIOSEL_WINDOW2		(0x10 << 5)
-#define VIDINTCON0_FIFIOSEL_WINDOW3		(0x20 << 5)
-#define VIDINTCON0_FIFIOSEL_WINDOW4		(0x40 << 5)
-
-#define DITHMODE				(0x170)
-#define WINxMAP(_win)				(0x180 + ((_win) * 4))
-
-
-#define DITHMODE_R_POS_MASK			(0x3 << 5)
-#define DITHMODE_R_POS_SHIFT			(5)
-#define DITHMODE_R_POS_8BIT			(0x0 << 5)
-#define DITHMODE_R_POS_6BIT			(0x1 << 5)
-#define DITHMODE_R_POS_5BIT			(0x2 << 5)
-
-#define DITHMODE_G_POS_MASK			(0x3 << 3)
-#define DITHMODE_G_POS_SHIFT			(3)
-#define DITHMODE_G_POS_8BIT			(0x0 << 3)
-#define DITHMODE_G_POS_6BIT			(0x1 << 3)
-#define DITHMODE_G_POS_5BIT			(0x2 << 3)
-
-#define DITHMODE_B_POS_MASK			(0x3 << 1)
-#define DITHMODE_B_POS_SHIFT			(1)
-#define DITHMODE_B_POS_8BIT			(0x0 << 1)
-#define DITHMODE_B_POS_6BIT			(0x1 << 1)
-#define DITHMODE_B_POS_5BIT			(0x2 << 1)
-
-#define DITHMODE_DITH_EN			(1 << 0)
-
-#define WPALCON					(0x1A0)
-
-/* Palette control */
-/* Note for S5PC100: you can still use those macros on WPALCON (aka WPALCON_L),
- * but make sure that WPALCON_H W2PAL-W4PAL entries are zeroed out */
-#define WPALCON_W4PAL_16BPP_A555		(1 << 8)
-#define WPALCON_W3PAL_16BPP_A555		(1 << 7)
-#define WPALCON_W2PAL_16BPP_A555		(1 << 6)
-
-
-/* Notes on per-window bpp settings
- *
- * Value	Win0	 Win1	  Win2	   Win3	    Win 4
- * 0000		1(P)	 1(P)	  1(P)	   1(P)	    1(P)
- * 0001		2(P)	 2(P)     2(P)	   2(P)	    2(P)
- * 0010		4(P)	 4(P)     4(P)	   4(P)     -none-
- * 0011		8(P)	 8(P)     -none-   -none-   -none-
- * 0100		-none-	 8(A232)  8(A232)  -none-   -none-
- * 0101		16(565)	 16(565)  16(565)  16(565)   16(565)
- * 0110		-none-	 16(A555) 16(A555) 16(A555)  16(A555)
- * 0111		16(I555) 16(I565) 16(I555) 16(I555)  16(I555)
- * 1000		18(666)	 18(666)  18(666)  18(666)   18(666)
- * 1001		-none-	 18(A665) 18(A665) 18(A665)  16(A665)
- * 1010		-none-	 19(A666) 19(A666) 19(A666)  19(A666)
- * 1011		24(888)	 24(888)  24(888)  24(888)   24(888)
- * 1100		-none-	 24(A887) 24(A887) 24(A887)  24(A887)
- * 1101		-none-	 25(A888) 25(A888) 25(A888)  25(A888)
- * 1110		-none-	 -none-	  -none-   -none-    -none-
- * 1111		-none-	 -none-   -none-   -none-    -none-
-*/
diff --git a/arch/arm/plat-samsung/include/plat/regs-fb.h b/arch/arm/plat-samsung/include/plat/regs-fb.h
deleted file mode 100644
index 9a78012..0000000
--- a/arch/arm/plat-samsung/include/plat/regs-fb.h
+++ /dev/null
@@ -1,403 +0,0 @@
-/* arch/arm/plat-samsung/include/plat/regs-fb.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *      http://armlinux.simtec.co.uk/
- *      Ben Dooks <ben@simtec.co.uk>
- *
- * S3C Platform - new-style framebuffer register definitions
- *
- * This is the register set for the new style framebuffer interface
- * found from the S3C2443 onwards into the S3C2416, S3C2450 and the
- * S3C64XX series such as the S3C6400 and S3C6410.
- *
- * The file does not contain the cpu specific items which are based on
- * whichever architecture is selected, it only contains the core of the
- * register set. See <mach/regs-fb.h> to get the specifics.
- *
- * Note, we changed to using regs-fb.h as it avoids any clashes with
- * the original regs-lcd.h so out of the way of regs-lcd.h as well as
- * indicating the newer block is much more than just an LCD interface.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-/* Please do not include this file directly, use <mach/regs-fb.h> to
- * ensure all the localised SoC support is included as necessary.
-*/
-
-/* VIDCON0 */
-
-#define VIDCON0					(0x00)
-#define VIDCON0_INTERLACE			(1 << 29)
-#define VIDCON0_VIDOUT_MASK			(0x3 << 26)
-#define VIDCON0_VIDOUT_SHIFT			(26)
-#define VIDCON0_VIDOUT_RGB			(0x0 << 26)
-#define VIDCON0_VIDOUT_TV			(0x1 << 26)
-#define VIDCON0_VIDOUT_I80_LDI0			(0x2 << 26)
-#define VIDCON0_VIDOUT_I80_LDI1			(0x3 << 26)
-
-#define VIDCON0_L1_DATA_MASK			(0x7 << 23)
-#define VIDCON0_L1_DATA_SHIFT			(23)
-#define VIDCON0_L1_DATA_16BPP			(0x0 << 23)
-#define VIDCON0_L1_DATA_18BPP16			(0x1 << 23)
-#define VIDCON0_L1_DATA_18BPP9			(0x2 << 23)
-#define VIDCON0_L1_DATA_24BPP			(0x3 << 23)
-#define VIDCON0_L1_DATA_18BPP			(0x4 << 23)
-#define VIDCON0_L1_DATA_16BPP8			(0x5 << 23)
-
-#define VIDCON0_L0_DATA_MASK			(0x7 << 20)
-#define VIDCON0_L0_DATA_SHIFT			(20)
-#define VIDCON0_L0_DATA_16BPP			(0x0 << 20)
-#define VIDCON0_L0_DATA_18BPP16			(0x1 << 20)
-#define VIDCON0_L0_DATA_18BPP9			(0x2 << 20)
-#define VIDCON0_L0_DATA_24BPP			(0x3 << 20)
-#define VIDCON0_L0_DATA_18BPP			(0x4 << 20)
-#define VIDCON0_L0_DATA_16BPP8			(0x5 << 20)
-
-#define VIDCON0_PNRMODE_MASK			(0x3 << 17)
-#define VIDCON0_PNRMODE_SHIFT			(17)
-#define VIDCON0_PNRMODE_RGB			(0x0 << 17)
-#define VIDCON0_PNRMODE_BGR			(0x1 << 17)
-#define VIDCON0_PNRMODE_SERIAL_RGB		(0x2 << 17)
-#define VIDCON0_PNRMODE_SERIAL_BGR		(0x3 << 17)
-
-#define VIDCON0_CLKVALUP			(1 << 16)
-#define VIDCON0_CLKVAL_F_MASK			(0xff << 6)
-#define VIDCON0_CLKVAL_F_SHIFT			(6)
-#define VIDCON0_CLKVAL_F_LIMIT			(0xff)
-#define VIDCON0_CLKVAL_F(_x)			((_x) << 6)
-#define VIDCON0_VLCKFREE			(1 << 5)
-#define VIDCON0_CLKDIR				(1 << 4)
-
-#define VIDCON0_CLKSEL_MASK			(0x3 << 2)
-#define VIDCON0_CLKSEL_SHIFT			(2)
-#define VIDCON0_CLKSEL_HCLK			(0x0 << 2)
-#define VIDCON0_CLKSEL_LCD			(0x1 << 2)
-#define VIDCON0_CLKSEL_27M			(0x3 << 2)
-
-#define VIDCON0_ENVID				(1 << 1)
-#define VIDCON0_ENVID_F				(1 << 0)
-
-#define VIDCON1					(0x04)
-#define VIDCON1_LINECNT_MASK			(0x7ff << 16)
-#define VIDCON1_LINECNT_SHIFT			(16)
-#define VIDCON1_LINECNT_GET(_v)			(((_v) >> 16) & 0x7ff)
-#define VIDCON1_VSTATUS_MASK			(0x3 << 13)
-#define VIDCON1_VSTATUS_SHIFT			(13)
-#define VIDCON1_VSTATUS_VSYNC			(0x0 << 13)
-#define VIDCON1_VSTATUS_BACKPORCH		(0x1 << 13)
-#define VIDCON1_VSTATUS_ACTIVE			(0x2 << 13)
-#define VIDCON1_VSTATUS_FRONTPORCH		(0x0 << 13)
-#define VIDCON1_VCLK_MASK			(0x3 << 9)
-#define VIDCON1_VCLK_HOLD			(0x0 << 9)
-#define VIDCON1_VCLK_RUN			(0x1 << 9)
-
-#define VIDCON1_INV_VCLK			(1 << 7)
-#define VIDCON1_INV_HSYNC			(1 << 6)
-#define VIDCON1_INV_VSYNC			(1 << 5)
-#define VIDCON1_INV_VDEN			(1 << 4)
-
-/* VIDCON2 */
-
-#define VIDCON2					(0x08)
-#define VIDCON2_EN601				(1 << 23)
-#define VIDCON2_TVFMTSEL_SW			(1 << 14)
-
-#define VIDCON2_TVFMTSEL1_MASK			(0x3 << 12)
-#define VIDCON2_TVFMTSEL1_SHIFT			(12)
-#define VIDCON2_TVFMTSEL1_RGB			(0x0 << 12)
-#define VIDCON2_TVFMTSEL1_YUV422		(0x1 << 12)
-#define VIDCON2_TVFMTSEL1_YUV444		(0x2 << 12)
-
-#define VIDCON2_ORGYCbCr			(1 << 8)
-#define VIDCON2_YUVORDCrCb			(1 << 7)
-
-/* PRTCON (S3C6410, S5PC100)
- * Might not be present in the S3C6410 documentation,
- * but tests prove it's there almost for sure; shouldn't hurt in any case.
- */
-#define PRTCON					(0x0c)
-#define PRTCON_PROTECT				(1 << 11)
-
-/* VIDTCON0 */
-
-#define VIDTCON0_VBPDE_MASK			(0xff << 24)
-#define VIDTCON0_VBPDE_SHIFT			(24)
-#define VIDTCON0_VBPDE_LIMIT			(0xff)
-#define VIDTCON0_VBPDE(_x)			((_x) << 24)
-
-#define VIDTCON0_VBPD_MASK			(0xff << 16)
-#define VIDTCON0_VBPD_SHIFT			(16)
-#define VIDTCON0_VBPD_LIMIT			(0xff)
-#define VIDTCON0_VBPD(_x)			((_x) << 16)
-
-#define VIDTCON0_VFPD_MASK			(0xff << 8)
-#define VIDTCON0_VFPD_SHIFT			(8)
-#define VIDTCON0_VFPD_LIMIT			(0xff)
-#define VIDTCON0_VFPD(_x)			((_x) << 8)
-
-#define VIDTCON0_VSPW_MASK			(0xff << 0)
-#define VIDTCON0_VSPW_SHIFT			(0)
-#define VIDTCON0_VSPW_LIMIT			(0xff)
-#define VIDTCON0_VSPW(_x)			((_x) << 0)
-
-/* VIDTCON1 */
-
-#define VIDTCON1_VFPDE_MASK			(0xff << 24)
-#define VIDTCON1_VFPDE_SHIFT			(24)
-#define VIDTCON1_VFPDE_LIMIT			(0xff)
-#define VIDTCON1_VFPDE(_x)			((_x) << 24)
-
-#define VIDTCON1_HBPD_MASK			(0xff << 16)
-#define VIDTCON1_HBPD_SHIFT			(16)
-#define VIDTCON1_HBPD_LIMIT			(0xff)
-#define VIDTCON1_HBPD(_x)			((_x) << 16)
-
-#define VIDTCON1_HFPD_MASK			(0xff << 8)
-#define VIDTCON1_HFPD_SHIFT			(8)
-#define VIDTCON1_HFPD_LIMIT			(0xff)
-#define VIDTCON1_HFPD(_x)			((_x) << 8)
-
-#define VIDTCON1_HSPW_MASK			(0xff << 0)
-#define VIDTCON1_HSPW_SHIFT			(0)
-#define VIDTCON1_HSPW_LIMIT			(0xff)
-#define VIDTCON1_HSPW(_x)			((_x) << 0)
-
-#define VIDTCON2				(0x18)
-#define VIDTCON2_LINEVAL_E(_x)			((((_x) & 0x800) >> 11) << 23)
-#define VIDTCON2_LINEVAL_MASK			(0x7ff << 11)
-#define VIDTCON2_LINEVAL_SHIFT			(11)
-#define VIDTCON2_LINEVAL_LIMIT			(0x7ff)
-#define VIDTCON2_LINEVAL(_x)			(((_x) & 0x7ff) << 11)
-
-#define VIDTCON2_HOZVAL_E(_x)			((((_x) & 0x800) >> 11) << 22)
-#define VIDTCON2_HOZVAL_MASK			(0x7ff << 0)
-#define VIDTCON2_HOZVAL_SHIFT			(0)
-#define VIDTCON2_HOZVAL_LIMIT			(0x7ff)
-#define VIDTCON2_HOZVAL(_x)			(((_x) & 0x7ff) << 0)
-
-/* WINCONx */
-
-
-#define WINCONx_BITSWP				(1 << 18)
-#define WINCONx_BYTSWP				(1 << 17)
-#define WINCONx_HAWSWP				(1 << 16)
-#define WINCONx_WSWP				(1 << 15)
-#define WINCONx_BURSTLEN_MASK			(0x3 << 9)
-#define WINCONx_BURSTLEN_SHIFT			(9)
-#define WINCONx_BURSTLEN_16WORD			(0x0 << 9)
-#define WINCONx_BURSTLEN_8WORD			(0x1 << 9)
-#define WINCONx_BURSTLEN_4WORD			(0x2 << 9)
-
-#define WINCONx_ENWIN				(1 << 0)
-#define WINCON0_BPPMODE_MASK			(0xf << 2)
-#define WINCON0_BPPMODE_SHIFT			(2)
-#define WINCON0_BPPMODE_1BPP			(0x0 << 2)
-#define WINCON0_BPPMODE_2BPP			(0x1 << 2)
-#define WINCON0_BPPMODE_4BPP			(0x2 << 2)
-#define WINCON0_BPPMODE_8BPP_PALETTE		(0x3 << 2)
-#define WINCON0_BPPMODE_16BPP_565		(0x5 << 2)
-#define WINCON0_BPPMODE_16BPP_1555		(0x7 << 2)
-#define WINCON0_BPPMODE_18BPP_666		(0x8 << 2)
-#define WINCON0_BPPMODE_24BPP_888		(0xb << 2)
-
-#define WINCON1_BLD_PIX				(1 << 6)
-
-#define WINCON1_ALPHA_SEL			(1 << 1)
-#define WINCON1_BPPMODE_MASK			(0xf << 2)
-#define WINCON1_BPPMODE_SHIFT			(2)
-#define WINCON1_BPPMODE_1BPP			(0x0 << 2)
-#define WINCON1_BPPMODE_2BPP			(0x1 << 2)
-#define WINCON1_BPPMODE_4BPP			(0x2 << 2)
-#define WINCON1_BPPMODE_8BPP_PALETTE		(0x3 << 2)
-#define WINCON1_BPPMODE_8BPP_1232		(0x4 << 2)
-#define WINCON1_BPPMODE_16BPP_565		(0x5 << 2)
-#define WINCON1_BPPMODE_16BPP_A1555		(0x6 << 2)
-#define WINCON1_BPPMODE_16BPP_I1555		(0x7 << 2)
-#define WINCON1_BPPMODE_18BPP_666		(0x8 << 2)
-#define WINCON1_BPPMODE_18BPP_A1665		(0x9 << 2)
-#define WINCON1_BPPMODE_19BPP_A1666		(0xa << 2)
-#define WINCON1_BPPMODE_24BPP_888		(0xb << 2)
-#define WINCON1_BPPMODE_24BPP_A1887		(0xc << 2)
-#define WINCON1_BPPMODE_25BPP_A1888		(0xd << 2)
-#define WINCON1_BPPMODE_28BPP_A4888		(0xd << 2)
-
-/* S5PV210 */
-#define SHADOWCON				(0x34)
-#define SHADOWCON_WINx_PROTECT(_win)		(1 << (10 + (_win)))
-/* DMA channels (all windows) */
-#define SHADOWCON_CHx_ENABLE(_win)		(1 << (_win))
-/* Local input channels (windows 0-2) */
-#define SHADOWCON_CHx_LOCAL_ENABLE(_win)	(1 << (5 + (_win)))
-
-#define VIDOSDxA_TOPLEFT_X_E(_x)		((((_x) & 0x800) >> 11) << 23)
-#define VIDOSDxA_TOPLEFT_X_MASK			(0x7ff << 11)
-#define VIDOSDxA_TOPLEFT_X_SHIFT		(11)
-#define VIDOSDxA_TOPLEFT_X_LIMIT		(0x7ff)
-#define VIDOSDxA_TOPLEFT_X(_x)			(((_x) & 0x7ff) << 11)
-
-#define VIDOSDxA_TOPLEFT_Y_E(_x)		((((_x) & 0x800) >> 11) << 22)
-#define VIDOSDxA_TOPLEFT_Y_MASK			(0x7ff << 0)
-#define VIDOSDxA_TOPLEFT_Y_SHIFT		(0)
-#define VIDOSDxA_TOPLEFT_Y_LIMIT		(0x7ff)
-#define VIDOSDxA_TOPLEFT_Y(_x)			(((_x) & 0x7ff) << 0)
-
-#define VIDOSDxB_BOTRIGHT_X_E(_x)		((((_x) & 0x800) >> 11) << 23)
-#define VIDOSDxB_BOTRIGHT_X_MASK		(0x7ff << 11)
-#define VIDOSDxB_BOTRIGHT_X_SHIFT		(11)
-#define VIDOSDxB_BOTRIGHT_X_LIMIT		(0x7ff)
-#define VIDOSDxB_BOTRIGHT_X(_x)			(((_x) & 0x7ff) << 11)
-
-#define VIDOSDxB_BOTRIGHT_Y_E(_x)		((((_x) & 0x800) >> 11) << 22)
-#define VIDOSDxB_BOTRIGHT_Y_MASK		(0x7ff << 0)
-#define VIDOSDxB_BOTRIGHT_Y_SHIFT		(0)
-#define VIDOSDxB_BOTRIGHT_Y_LIMIT		(0x7ff)
-#define VIDOSDxB_BOTRIGHT_Y(_x)			(((_x) & 0x7ff) << 0)
-
-/* For VIDOSD[1..4]C */
-#define VIDISD14C_ALPHA0_R(_x)			((_x) << 20)
-#define VIDISD14C_ALPHA0_G_MASK			(0xf << 16)
-#define VIDISD14C_ALPHA0_G_SHIFT		(16)
-#define VIDISD14C_ALPHA0_G_LIMIT		(0xf)
-#define VIDISD14C_ALPHA0_G(_x)			((_x) << 16)
-#define VIDISD14C_ALPHA0_B_MASK			(0xf << 12)
-#define VIDISD14C_ALPHA0_B_SHIFT		(12)
-#define VIDISD14C_ALPHA0_B_LIMIT		(0xf)
-#define VIDISD14C_ALPHA0_B(_x)			((_x) << 12)
-#define VIDISD14C_ALPHA1_R_MASK			(0xf << 8)
-#define VIDISD14C_ALPHA1_R_SHIFT		(8)
-#define VIDISD14C_ALPHA1_R_LIMIT		(0xf)
-#define VIDISD14C_ALPHA1_R(_x)			((_x) << 8)
-#define VIDISD14C_ALPHA1_G_MASK			(0xf << 4)
-#define VIDISD14C_ALPHA1_G_SHIFT		(4)
-#define VIDISD14C_ALPHA1_G_LIMIT		(0xf)
-#define VIDISD14C_ALPHA1_G(_x)			((_x) << 4)
-#define VIDISD14C_ALPHA1_B_MASK			(0xf << 0)
-#define VIDISD14C_ALPHA1_B_SHIFT		(0)
-#define VIDISD14C_ALPHA1_B_LIMIT		(0xf)
-#define VIDISD14C_ALPHA1_B(_x)			((_x) << 0)
-
-/* Video buffer addresses */
-#define VIDW_BUF_START(_buff)			(0xA0 + ((_buff) * 8))
-#define VIDW_BUF_START1(_buff)			(0xA4 + ((_buff) * 8))
-#define VIDW_BUF_END(_buff)			(0xD0 + ((_buff) * 8))
-#define VIDW_BUF_END1(_buff)			(0xD4 + ((_buff) * 8))
-#define VIDW_BUF_SIZE(_buff)			(0x100 + ((_buff) * 4))
-
-#define VIDW_BUF_SIZE_OFFSET_E(_x)		((((_x) & 0x2000) >> 13) << 27)
-#define VIDW_BUF_SIZE_OFFSET_MASK		(0x1fff << 13)
-#define VIDW_BUF_SIZE_OFFSET_SHIFT		(13)
-#define VIDW_BUF_SIZE_OFFSET_LIMIT		(0x1fff)
-#define VIDW_BUF_SIZE_OFFSET(_x)		(((_x) & 0x1fff) << 13)
-
-#define VIDW_BUF_SIZE_PAGEWIDTH_E(_x)		((((_x) & 0x2000) >> 13) << 26)
-#define VIDW_BUF_SIZE_PAGEWIDTH_MASK		(0x1fff << 0)
-#define VIDW_BUF_SIZE_PAGEWIDTH_SHIFT		(0)
-#define VIDW_BUF_SIZE_PAGEWIDTH_LIMIT		(0x1fff)
-#define VIDW_BUF_SIZE_PAGEWIDTH(_x)		(((_x) & 0x1fff) << 0)
-
-/* Interrupt controls and status */
-
-#define VIDINTCON0_FIFOINTERVAL_MASK		(0x3f << 20)
-#define VIDINTCON0_FIFOINTERVAL_SHIFT		(20)
-#define VIDINTCON0_FIFOINTERVAL_LIMIT		(0x3f)
-#define VIDINTCON0_FIFOINTERVAL(_x)		((_x) << 20)
-
-#define VIDINTCON0_INT_SYSMAINCON		(1 << 19)
-#define VIDINTCON0_INT_SYSSUBCON		(1 << 18)
-#define VIDINTCON0_INT_I80IFDONE		(1 << 17)
-
-#define VIDINTCON0_FRAMESEL0_MASK		(0x3 << 15)
-#define VIDINTCON0_FRAMESEL0_SHIFT		(15)
-#define VIDINTCON0_FRAMESEL0_BACKPORCH		(0x0 << 15)
-#define VIDINTCON0_FRAMESEL0_VSYNC		(0x1 << 15)
-#define VIDINTCON0_FRAMESEL0_ACTIVE		(0x2 << 15)
-#define VIDINTCON0_FRAMESEL0_FRONTPORCH		(0x3 << 15)
-
-#define VIDINTCON0_FRAMESEL1			(1 << 13)
-#define VIDINTCON0_FRAMESEL1_MASK		(0x3 << 13)
-#define VIDINTCON0_FRAMESEL1_NONE		(0x0 << 13)
-#define VIDINTCON0_FRAMESEL1_BACKPORCH		(0x1 << 13)
-#define VIDINTCON0_FRAMESEL1_VSYNC		(0x2 << 13)
-#define VIDINTCON0_FRAMESEL1_FRONTPORCH		(0x3 << 13)
-
-#define VIDINTCON0_INT_FRAME			(1 << 12)
-#define VIDINTCON0_FIFIOSEL_MASK		(0x7f << 5)
-#define VIDINTCON0_FIFIOSEL_SHIFT		(5)
-#define VIDINTCON0_FIFIOSEL_WINDOW0		(0x1 << 5)
-#define VIDINTCON0_FIFIOSEL_WINDOW1		(0x2 << 5)
-
-#define VIDINTCON0_FIFOLEVEL_MASK		(0x7 << 2)
-#define VIDINTCON0_FIFOLEVEL_SHIFT		(2)
-#define VIDINTCON0_FIFOLEVEL_TO25PC		(0x0 << 2)
-#define VIDINTCON0_FIFOLEVEL_TO50PC		(0x1 << 2)
-#define VIDINTCON0_FIFOLEVEL_TO75PC		(0x2 << 2)
-#define VIDINTCON0_FIFOLEVEL_EMPTY		(0x3 << 2)
-#define VIDINTCON0_FIFOLEVEL_FULL		(0x4 << 2)
-
-#define VIDINTCON0_INT_FIFO_MASK		(0x3 << 0)
-#define VIDINTCON0_INT_FIFO_SHIFT		(0)
-#define VIDINTCON0_INT_ENABLE			(1 << 0)
-
-#define VIDINTCON1				(0x134)
-#define VIDINTCON1_INT_I180			(1 << 2)
-#define VIDINTCON1_INT_FRAME			(1 << 1)
-#define VIDINTCON1_INT_FIFO			(1 << 0)
-
-/* Window colour-key control registers */
-#define WKEYCON					(0x140)	/* 6410,V210 */
-
-#define WKEYCON0				(0x00)
-#define WKEYCON1				(0x04)
-
-#define WxKEYCON0_KEYBL_EN			(1 << 26)
-#define WxKEYCON0_KEYEN_F			(1 << 25)
-#define WxKEYCON0_DIRCON			(1 << 24)
-#define WxKEYCON0_COMPKEY_MASK			(0xffffff << 0)
-#define WxKEYCON0_COMPKEY_SHIFT			(0)
-#define WxKEYCON0_COMPKEY_LIMIT			(0xffffff)
-#define WxKEYCON0_COMPKEY(_x)			((_x) << 0)
-#define WxKEYCON1_COLVAL_MASK			(0xffffff << 0)
-#define WxKEYCON1_COLVAL_SHIFT			(0)
-#define WxKEYCON1_COLVAL_LIMIT			(0xffffff)
-#define WxKEYCON1_COLVAL(_x)			((_x) << 0)
-
-
-/* Window blanking (MAP) */
-
-#define WINxMAP_MAP				(1 << 24)
-#define WINxMAP_MAP_COLOUR_MASK			(0xffffff << 0)
-#define WINxMAP_MAP_COLOUR_SHIFT		(0)
-#define WINxMAP_MAP_COLOUR_LIMIT		(0xffffff)
-#define WINxMAP_MAP_COLOUR(_x)			((_x) << 0)
-
-#define WPALCON_PAL_UPDATE			(1 << 9)
-#define WPALCON_W1PAL_MASK			(0x7 << 3)
-#define WPALCON_W1PAL_SHIFT			(3)
-#define WPALCON_W1PAL_25BPP_A888		(0x0 << 3)
-#define WPALCON_W1PAL_24BPP			(0x1 << 3)
-#define WPALCON_W1PAL_19BPP_A666		(0x2 << 3)
-#define WPALCON_W1PAL_18BPP_A665		(0x3 << 3)
-#define WPALCON_W1PAL_18BPP			(0x4 << 3)
-#define WPALCON_W1PAL_16BPP_A555		(0x5 << 3)
-#define WPALCON_W1PAL_16BPP_565			(0x6 << 3)
-
-#define WPALCON_W0PAL_MASK			(0x7 << 0)
-#define WPALCON_W0PAL_SHIFT			(0)
-#define WPALCON_W0PAL_25BPP_A888		(0x0 << 0)
-#define WPALCON_W0PAL_24BPP			(0x1 << 0)
-#define WPALCON_W0PAL_19BPP_A666		(0x2 << 0)
-#define WPALCON_W0PAL_18BPP_A665		(0x3 << 0)
-#define WPALCON_W0PAL_18BPP			(0x4 << 0)
-#define WPALCON_W0PAL_16BPP_A555		(0x5 << 0)
-#define WPALCON_W0PAL_16BPP_565			(0x6 << 0)
-
-/* Blending equation control */
-#define BLENDCON				(0x260)
-#define BLENDCON_NEW_MASK			(1 << 0)
-#define BLENDCON_NEW_8BIT_ALPHA_VALUE		(1 << 0)
-#define BLENDCON_NEW_4BIT_ALPHA_VALUE		(0 << 0)
-
diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c
index 64ab65f..1507028 100644
--- a/arch/arm/plat-samsung/pm.c
+++ b/arch/arm/plat-samsung/pm.c
@@ -74,7 +74,7 @@ unsigned char pm_uart_udivslot;
 
 #ifdef CONFIG_SAMSUNG_PM_DEBUG
 
-struct pm_uart_save uart_save[CONFIG_SERIAL_SAMSUNG_UARTS];
+static struct pm_uart_save uart_save[CONFIG_SERIAL_SAMSUNG_UARTS];
 
 static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save)
 {
diff --git a/arch/arm/plat-samsung/time.c b/arch/arm/plat-samsung/time.c
index 4dcb11c..60552e2 100644
--- a/arch/arm/plat-samsung/time.c
+++ b/arch/arm/plat-samsung/time.c
@@ -28,7 +28,6 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 
 #include <asm/irq.h>
diff --git a/arch/arm/plat-versatile/Kconfig b/arch/arm/plat-versatile/Kconfig
index 8d5c10a..2a4ae8a 100644
--- a/arch/arm/plat-versatile/Kconfig
+++ b/arch/arm/plat-versatile/Kconfig
@@ -16,8 +16,10 @@ config PLAT_VERSATILE_FPGA_IRQ_NR
        depends on PLAT_VERSATILE_FPGA_IRQ
 
 config PLAT_VERSATILE_LEDS
-	def_bool y if LEDS_CLASS
+	def_bool y if NEW_LEDS
 	depends on ARCH_REALVIEW || ARCH_VERSATILE
+	select LEDS_CLASS
+	select LEDS_TRIGGER
 
 config PLAT_VERSATILE_SCHED_CLOCK
 	def_bool y
diff --git a/arch/arm/plat-versatile/leds.c b/arch/arm/plat-versatile/leds.c
index 3169fa5..d2490d0 100644
--- a/arch/arm/plat-versatile/leds.c
+++ b/arch/arm/plat-versatile/leds.c
@@ -37,10 +37,10 @@ static const struct {
 } versatile_leds[] = {
 	{ "versatile:0", "heartbeat", },
 	{ "versatile:1", "mmc0", },
-	{ "versatile:2", },
-	{ "versatile:3", },
-	{ "versatile:4", },
-	{ "versatile:5", },
+	{ "versatile:2", "cpu0" },
+	{ "versatile:3", "cpu1" },
+	{ "versatile:4", "cpu2" },
+	{ "versatile:5", "cpu3" },
 	{ "versatile:6", },
 	{ "versatile:7", },
 };
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index fb849d0..c834b32 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -719,8 +719,10 @@ static int __init vfp_init(void)
 			if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100)
 				elf_hwcap |= HWCAP_NEON;
 #endif
+#ifdef CONFIG_VFPv3
 			if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000)
 				elf_hwcap |= HWCAP_VFPv4;
+#endif
 		}
 	}
 	return 0;
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
index 5ade51c..06e73bf 100644
--- a/arch/avr32/Kconfig
+++ b/arch/avr32/Kconfig
@@ -15,6 +15,8 @@ config AVR32
 	select ARCH_WANT_IPC_PARSE_VERSION
 	select ARCH_HAVE_NMI_SAFE_CMPXCHG
 	select GENERIC_CLOCKEVENTS
+	select HAVE_MOD_ARCH_SPECIFIC
+	select MODULES_USE_ELF_RELA
 	help
 	  AVR32 is a high-performance 32-bit RISC microprocessor core,
 	  designed for cost-sensitive embedded applications, with particular
diff --git a/arch/avr32/include/asm/module.h b/arch/avr32/include/asm/module.h
index 4514445..3f083d3 100644
--- a/arch/avr32/include/asm/module.h
+++ b/arch/avr32/include/asm/module.h
@@ -1,6 +1,8 @@
 #ifndef __ASM_AVR32_MODULE_H
 #define __ASM_AVR32_MODULE_H
 
+#include <asm-generic/module.h>
+
 struct mod_arch_syminfo {
 	unsigned long got_offset;
 	int got_initialized;
@@ -17,10 +19,6 @@ struct mod_arch_specific {
 	struct mod_arch_syminfo *syminfo;
 };
 
-#define Elf_Shdr		Elf32_Shdr
-#define Elf_Sym			Elf32_Sym
-#define Elf_Ehdr		Elf32_Ehdr
-
 #define MODULE_PROC_FAMILY "AVR32v1"
 
 #define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY
diff --git a/arch/avr32/include/asm/thread_info.h b/arch/avr32/include/asm/thread_info.h
index e5deda4..2f0c412 100644
--- a/arch/avr32/include/asm/thread_info.h
+++ b/arch/avr32/include/asm/thread_info.h
@@ -77,8 +77,6 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SYSCALL_TRACE       0       /* syscall trace active */
 #define TIF_SIGPENDING          1       /* signal pending */
 #define TIF_NEED_RESCHED        2       /* rescheduling necessary */
-#define TIF_POLLING_NRFLAG      3       /* true if poll_idle() is polling
-					   TIF_NEED_RESCHED */
 #define TIF_BREAKPOINT		4	/* enter monitor mode on return */
 #define TIF_SINGLE_STEP		5	/* single step in progress */
 #define TIF_MEMDIE		6	/* is terminating due to OOM killer */
@@ -91,10 +89,8 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
-#define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 #define _TIF_SINGLE_STEP	(1 << TIF_SINGLE_STEP)
 #define _TIF_MEMDIE		(1 << TIF_MEMDIE)
-#define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
 #define _TIF_CPU_GOING_TO_SLEEP (1 << TIF_CPU_GOING_TO_SLEEP)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 
@@ -102,17 +98,14 @@ static inline struct thread_info *current_thread_info(void)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK				\
-	((1 << TIF_SIGPENDING)			\
+	(_TIF_SIGPENDING			\
 	 | _TIF_NOTIFY_RESUME			\
-	 | (1 << TIF_NEED_RESCHED)		\
-	 | (1 << TIF_POLLING_NRFLAG)		\
-	 | (1 << TIF_BREAKPOINT)		\
-	 | (1 << TIF_RESTORE_SIGMASK))
+	 | _TIF_NEED_RESCHED			\
+	 | _TIF_BREAKPOINT)
 
 /* work to do on any return to userspace */
-#define _TIF_ALLWORK_MASK	(_TIF_WORK_MASK | (1 << TIF_SYSCALL_TRACE) | \
-				 _TIF_NOTIFY_RESUME)
+#define _TIF_ALLWORK_MASK	(_TIF_WORK_MASK | _TIF_SYSCALL_TRACE)
 /* work to do on return from debug mode */
-#define _TIF_DBGWORK_MASK	(_TIF_WORK_MASK & ~(1 << TIF_BREAKPOINT))
+#define _TIF_DBGWORK_MASK	(_TIF_WORK_MASK & ~_TIF_BREAKPOINT)
 
 #endif /* __ASM_AVR32_THREAD_INFO_H */
diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c
index d552a85..5e01c3a 100644
--- a/arch/avr32/kernel/signal.c
+++ b/arch/avr32/kernel/signal.c
@@ -15,7 +15,6 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
-#include <linux/freezer.h>
 #include <linux/tracehook.h>
 
 #include <asm/uaccess.h>
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index f348619..a48d8be 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -41,6 +41,8 @@ config BLACKFIN
 	select HAVE_NMI_WATCHDOG if NMI_WATCHDOG
 	select GENERIC_SMP_IDLE_THREAD
 	select ARCH_USES_GETTIMEOFFSET if !GENERIC_CLOCKEVENTS
+	select HAVE_MOD_ARCH_SPECIFIC
+	select MODULES_USE_ELF_RELA
 
 config GENERIC_CSUM
 	def_bool y
diff --git a/arch/blackfin/include/asm/module.h b/arch/blackfin/include/asm/module.h
index ed5689b..231a149 100644
--- a/arch/blackfin/include/asm/module.h
+++ b/arch/blackfin/include/asm/module.h
@@ -7,9 +7,7 @@
 #ifndef _ASM_BFIN_MODULE_H
 #define _ASM_BFIN_MODULE_H
 
-#define Elf_Shdr        Elf32_Shdr
-#define Elf_Sym         Elf32_Sym
-#define Elf_Ehdr        Elf32_Ehdr
+#include <asm-generic/module.h>
 
 struct mod_arch_specific {
 	Elf_Shdr	*text_l1;
diff --git a/arch/blackfin/include/asm/thread_info.h b/arch/blackfin/include/asm/thread_info.h
index 53ad100..3894005 100644
--- a/arch/blackfin/include/asm/thread_info.h
+++ b/arch/blackfin/include/asm/thread_info.h
@@ -96,8 +96,6 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SYSCALL_TRACE	0	/* syscall trace active */
 #define TIF_SIGPENDING		1	/* signal pending */
 #define TIF_NEED_RESCHED	2	/* rescheduling necessary */
-#define TIF_POLLING_NRFLAG	3	/* true if poll_idle() is polling
-					   TIF_NEED_RESCHED */
 #define TIF_MEMDIE		4	/* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK	5	/* restore signal mask in do_signal() */
 #define TIF_IRQ_SYNC		7	/* sync pipeline stage */
@@ -108,8 +106,6 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_IRQ_SYNC		(1<<TIF_IRQ_SYNC)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c
index 6682b73..6ed20a1 100644
--- a/arch/blackfin/kernel/signal.c
+++ b/arch/blackfin/kernel/signal.c
@@ -10,7 +10,6 @@
 #include <linux/tty.h>
 #include <linux/personality.h>
 #include <linux/binfmts.h>
-#include <linux/freezer.h>
 #include <linux/uaccess.h>
 #include <linux/tracehook.h>
 
diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig
index 052f81a..f6a3648 100644
--- a/arch/c6x/Kconfig
+++ b/arch/c6x/Kconfig
@@ -6,6 +6,7 @@
 config C6X
 	def_bool y
 	select CLKDEV_LOOKUP
+	select GENERIC_ATOMIC64
 	select GENERIC_IRQ_SHOW
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_DMA_API_DEBUG
@@ -16,6 +17,7 @@ config C6X
 	select OF
 	select OF_EARLY_FLATTREE
 	select GENERIC_CLOCKEVENTS
+	select MODULES_USE_ELF_RELA
 
 config MMU
 	def_bool n
diff --git a/arch/c6x/include/asm/cache.h b/arch/c6x/include/asm/cache.h
index 6d521d9..09c5a0f 100644
--- a/arch/c6x/include/asm/cache.h
+++ b/arch/c6x/include/asm/cache.h
@@ -1,7 +1,7 @@
 /*
  *  Port on Texas Instruments TMS320C6x architecture
  *
- *  Copyright (C) 2005, 2006, 2009, 2010 Texas Instruments Incorporated
+ *  Copyright (C) 2005, 2006, 2009, 2010, 2012 Texas Instruments Incorporated
  *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -16,9 +16,14 @@
 /*
  * Cache line size
  */
-#define L1D_CACHE_BYTES   64
-#define L1P_CACHE_BYTES   32
-#define L2_CACHE_BYTES	  128
+#define L1D_CACHE_SHIFT   6
+#define L1D_CACHE_BYTES   (1 << L1D_CACHE_SHIFT)
+
+#define L1P_CACHE_SHIFT   5
+#define L1P_CACHE_BYTES   (1 << L1P_CACHE_SHIFT)
+
+#define L2_CACHE_SHIFT    7
+#define L2_CACHE_BYTES    (1 << L2_CACHE_SHIFT)
 
 /*
  * L2 used as cache
@@ -29,7 +34,8 @@
  * For practical reasons the L1_CACHE_BYTES defines should not be smaller than
  * the L2 line size
  */
-#define L1_CACHE_BYTES        L2_CACHE_BYTES
+#define L1_CACHE_SHIFT        L2_CACHE_SHIFT
+#define L1_CACHE_BYTES        (1 << L1_CACHE_SHIFT)
 
 #define L2_CACHE_ALIGN_LOW(x) \
 	(((x) & ~(L2_CACHE_BYTES - 1)))
diff --git a/arch/c6x/include/asm/module.h b/arch/c6x/include/asm/module.h
index a453f97..5c7269c 100644
--- a/arch/c6x/include/asm/module.h
+++ b/arch/c6x/include/asm/module.h
@@ -13,17 +13,7 @@
 #ifndef _ASM_C6X_MODULE_H
 #define _ASM_C6X_MODULE_H
 
-#define Elf_Shdr	Elf32_Shdr
-#define Elf_Sym		Elf32_Sym
-#define Elf_Ehdr	Elf32_Ehdr
-#define Elf_Addr	Elf32_Addr
-#define Elf_Word	Elf32_Word
-
-/*
- * This file contains the C6x architecture specific module code.
- */
-struct mod_arch_specific {
-};
+#include <asm-generic/module.h>
 
 struct loaded_sections {
 	unsigned int new_vaddr;
diff --git a/arch/c6x/include/asm/thread_info.h b/arch/c6x/include/asm/thread_info.h
index 1710bcb..4c8dc56 100644
--- a/arch/c6x/include/asm/thread_info.h
+++ b/arch/c6x/include/asm/thread_info.h
@@ -97,7 +97,6 @@ struct thread_info *current_thread_info(void)
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_RESTORE_SIGMASK	4	/* restore signal mask in do_signal() */
 
-#define TIF_POLLING_NRFLAG	16	/* true if polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		17	/* OOM killer killed process */
 
 #define TIF_WORK_MASK		0x00007FFE /* work on irq/exception return */
diff --git a/arch/c6x/kernel/asm-offsets.c b/arch/c6x/kernel/asm-offsets.c
index 759ad6d..60f1e43 100644
--- a/arch/c6x/kernel/asm-offsets.c
+++ b/arch/c6x/kernel/asm-offsets.c
@@ -116,7 +116,6 @@ void foo(void)
 	DEFINE(_TIF_NOTIFY_RESUME, (1<<TIF_NOTIFY_RESUME));
 	DEFINE(_TIF_SIGPENDING, (1<<TIF_SIGPENDING));
 	DEFINE(_TIF_NEED_RESCHED, (1<<TIF_NEED_RESCHED));
-	DEFINE(_TIF_POLLING_NRFLAG, (1<<TIF_POLLING_NRFLAG));
 
 	DEFINE(_TIF_ALLWORK_MASK, TIF_ALLWORK_MASK);
 	DEFINE(_TIF_WORK_MASK, TIF_WORK_MASK);
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index e922154..26160e2 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -47,6 +47,7 @@ config CRIS
 	select GENERIC_IOMAP
 	select GENERIC_SMP_IDLE_THREAD if ETRAX_ARCH_V32
 	select GENERIC_CMOS_UPDATE
+	select MODULES_USE_ELF_RELA
 
 config HZ
 	int
@@ -138,11 +139,6 @@ config CRIS_MACH_ARTPEC3
 
 endchoice
 
-config ETRAX_VCS_SIM
-	bool "VCS Simulator"
-	help
-	  Setup hardware to be run in the VCS simulator.
-
 config ETRAX_ARCH_V10
        bool
        default y if ETRAX100LX || ETRAX100LX_V2
diff --git a/arch/cris/arch-v32/drivers/axisflashmap.c b/arch/cris/arch-v32/drivers/axisflashmap.c
index b34438e..1b6ad62 100644
--- a/arch/cris/arch-v32/drivers/axisflashmap.c
+++ b/arch/cris/arch-v32/drivers/axisflashmap.c
@@ -329,7 +329,6 @@ static int __init init_axis_flash(void)
 	}
 #endif
 
-#ifndef CONFIG_ETRAX_VCS_SIM
 	main_mtd = flash_probe();
 	if (main_mtd)
 		printk(KERN_INFO "%s: 0x%08x bytes of NOR flash memory.\n",
@@ -603,34 +602,7 @@ static int __init init_axis_flash(void)
 					"partition %d\n", part);
 		}
 	}
-#endif /* CONFIG_EXTRAX_VCS_SIM */
 
-#ifdef CONFIG_ETRAX_VCS_SIM
-	/* For simulator, always use a RAM partition.
-	 * The rootfs will be found after the kernel in RAM,
-	 * with romfs_start and romfs_end indicating location and size.
-	 */
-	struct mtd_info *mtd_ram;
-
-	mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-	if (!mtd_ram) {
-		panic("axisflashmap: Couldn't allocate memory for "
-		      "mtd_info!\n");
-	}
-
-	printk(KERN_INFO "axisflashmap: Adding RAM partition for romfs, "
-	       "at %u, size %u\n",
-	       (unsigned) romfs_start, (unsigned) romfs_length);
-
-	err = mtdram_init_device(mtd_ram, (void *)romfs_start,
-				 romfs_length, "romfs");
-	if (err) {
-		panic("axisflashmap: Could not initialize MTD RAM "
-		      "device!\n");
-	}
-#endif /* CONFIG_EXTRAX_VCS_SIM */
-
-#ifndef CONFIG_ETRAX_VCS_SIM
 	if (aux_mtd) {
 		aux_partition.size = aux_mtd->size;
 		err = mtd_device_register(aux_mtd, &aux_partition, 1);
@@ -639,7 +611,6 @@ static int __init init_axis_flash(void)
 			      "aux mtd device!\n");
 
 	}
-#endif /* CONFIG_EXTRAX_VCS_SIM */
 
 	return err;
 }
diff --git a/arch/cris/arch-v32/drivers/pci/bios.c b/arch/cris/arch-v32/drivers/pci/bios.c
index 5b1ee82..e3dfc72 100644
--- a/arch/cris/arch-v32/drivers/pci/bios.c
+++ b/arch/cris/arch-v32/drivers/pci/bios.c
@@ -97,28 +97,3 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
 		pcibios_enable_irq(dev);
 	return 0;
 }
-
-int pcibios_assign_resources(void)
-{
-	struct pci_dev *dev = NULL;
-	int idx;
-	struct resource *r;
-
-	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-		int class = dev->class >> 8;
-
-		/* Don't touch classless devices and host bridges */
-		if (!class || class == PCI_CLASS_BRIDGE_HOST)
-			continue;
-
-		for(idx=0; idx<6; idx++) {
-			r = &dev->resource[idx];
-
-			if (!r->start && r->end)
-				pci_assign_resource(dev, idx);
-		}
-	}
-	return 0;
-}
-
-EXPORT_SYMBOL(pcibios_assign_resources);
diff --git a/arch/cris/arch-v32/kernel/head.S b/arch/cris/arch-v32/kernel/head.S
index 5d502b9..51e3416 100644
--- a/arch/cris/arch-v32/kernel/head.S
+++ b/arch/cris/arch-v32/kernel/head.S
@@ -36,13 +36,6 @@
 	.global nand_boot
 	.global swapper_pg_dir
 
-	;; Dummy section to make it bootable with current VCS simulator
-#ifdef CONFIG_ETRAX_VCS_SIM
-	.section ".boot", "ax"
-	ba tstart
-	nop
-#endif
-
 	.text
 tstart:
 	;; This is the entry point of the kernel. The CPU is currently in
@@ -75,17 +68,10 @@ secondary_cpu_entry: /* Entry point for secondary CPUs */
 		| REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4)	\
 		| REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 5)     \
 		| REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0
-#elif !defined(CONFIG_ETRAX_VCS_SIM)
-	move.d	REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8)	\
-		| REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4)	\
-		| REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0
 #else
-	;; Map the virtual DRAM to the RW eprom area at address 0.
-	;; Also map 0xa for the hook calls,
 	move.d	REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8)	\
 		| REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4)	\
-		| REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb)   \
-		| REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa), $r0
+		| REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0
 #endif
 
 	;; Temporary map of 0x40 -> 0x40 and 0x00 -> 0x00.
@@ -126,27 +112,6 @@ secondary_cpu_entry: /* Entry point for secondary CPUs */
 		| REG_STATE(mmu, rw_mm_cfg, seg_2, page)	\
 		| REG_STATE(mmu, rw_mm_cfg, seg_1, page)	\
 		| REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2
-#elif !defined(CONFIG_ETRAX_VCS_SIM)
-	move.d	REG_STATE(mmu, rw_mm_cfg, we, on)		\
-		| REG_STATE(mmu, rw_mm_cfg, acc, on)		\
-		| REG_STATE(mmu, rw_mm_cfg, ex, on)		\
-		| REG_STATE(mmu, rw_mm_cfg, inv, on)		\
-		| REG_STATE(mmu, rw_mm_cfg, seg_f, linear)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_e, linear)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_d, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_c, linear)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_b, linear)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_a, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_9, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_8, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_7, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_6, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_5, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_4, linear)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_3, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_2, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_1, page)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2
 #else
 	move.d	REG_STATE(mmu, rw_mm_cfg, we, on)		\
 		| REG_STATE(mmu, rw_mm_cfg, acc, on)		\
@@ -157,7 +122,7 @@ secondary_cpu_entry: /* Entry point for secondary CPUs */
 		| REG_STATE(mmu, rw_mm_cfg, seg_d, page)	\
 		| REG_STATE(mmu, rw_mm_cfg, seg_c, linear)	\
 		| REG_STATE(mmu, rw_mm_cfg, seg_b, linear)	\
-		| REG_STATE(mmu, rw_mm_cfg, seg_a, linear)	\
+		| REG_STATE(mmu, rw_mm_cfg, seg_a, page)	\
 		| REG_STATE(mmu, rw_mm_cfg, seg_9, page)	\
 		| REG_STATE(mmu, rw_mm_cfg, seg_8, page)	\
 		| REG_STATE(mmu, rw_mm_cfg, seg_7, page)	\
@@ -226,7 +191,6 @@ master_cpu:
 	move.d secondary_cpu_entry, $r1
 	move.d $r1, [$r0]
 #endif
-#ifndef CONFIG_ETRAX_VCS_SIM
 	; Check if starting from DRAM (network->RAM boot or unpacked
 	; compressed kernel), or directly from flash.
 	lapcq	., $r0
@@ -234,7 +198,6 @@ master_cpu:
 	cmp.d	0x10000, $r0	; Arbitrary, something above this code.
 	blo	_inflash0
 	nop
-#endif
 
 	jump	_inram		; Jump to cached RAM.
 	nop
@@ -326,7 +289,6 @@ move_cramfs:
 	move.d	romfs_length, $r1
 	move.d	$r0, [$r1]
 
-#ifndef CONFIG_ETRAX_VCS_SIM
 	;; The kernel could have been unpacked to DRAM by the loader, but
 	;; the cramfs image could still be in the flash immediately
 	;; following the compressed kernel image. The loader passes the address
@@ -335,10 +297,6 @@ move_cramfs:
 	cmp.d	0x0ffffff8, $r9
 	bhs	_no_romfs_in_flash ; R9 points outside the flash area.
 	nop
-#else
-	ba _no_romfs_in_flash
-	nop
-#endif
 	;; cramfs rootfs might to be in flash. Check for it.
 	move.d	[$r9], $r0	; cramfs_super.magic
 	cmp.d	CRAMFS_MAGIC, $r0
@@ -396,7 +354,6 @@ _no_romfs_in_flash:
 	move.d	romfs_length, $r3
 	move.d	$r2, [$r3]	; store size at romfs_length
 
-#ifndef CONFIG_ETRAX_VCS_SIM
 	add.d	$r2, $r0	; copy from end and downwards
 	add.d	$r2, $r1
 
@@ -410,7 +367,6 @@ _no_romfs_in_flash:
 	subq	1, $r2
 	bne	1b
 	nop
-#endif
 
 4:
 	;; BSS move done.
@@ -455,7 +411,6 @@ no_command_line:
 	move.d	etrax_irv, $r1	; Set the exception base register and pointer.
 	move.d	$r0, [$r1]
 
-#ifndef CONFIG_ETRAX_VCS_SIM
 	;; Clear the BSS region from _bss_start to _end.
 	move.d	__bss_start, $r0
 	move.d	_end, $r1
@@ -463,15 +418,6 @@ no_command_line:
 	cmp.d	$r1, $r0
 	blo 1b
 	nop
-#endif
-
-#ifdef CONFIG_ETRAX_VCS_SIM
-	/* Set the watchdog timeout to something big. Will be removed when */
-	/* watchdog can be disabled with command line option */
-	move.d  0x7fffffff, $r10
-	jsr     CPU_WATCHDOG_TIMEOUT
-	nop
-#endif
 
 	; Initialize registers to increase determinism
 	move.d __bss_start, $r0
diff --git a/arch/cris/arch-v32/kernel/kgdb.c b/arch/cris/arch-v32/kernel/kgdb.c
index 8c1d35c..b06813a 100644
--- a/arch/cris/arch-v32/kernel/kgdb.c
+++ b/arch/cris/arch-v32/kernel/kgdb.c
@@ -381,23 +381,9 @@ static int read_register(char regno, unsigned int *valptr);
 /* Serial port, reads one character. ETRAX 100 specific. from debugport.c */
 int getDebugChar(void);
 
-#ifdef CONFIG_ETRAX_VCS_SIM
-int getDebugChar(void)
-{
-  return socketread();
-}
-#endif
-
 /* Serial port, writes one character. ETRAX 100 specific. from debugport.c */
 void putDebugChar(int val);
 
-#ifdef CONFIG_ETRAX_VCS_SIM
-void putDebugChar(int val)
-{
-  socketwrite((char *)&val, 1);
-}
-#endif
-
 /* Returns the integer equivalent of a hexadecimal character. */
 static int hex(char ch);
 
diff --git a/arch/cris/arch-v32/mach-a3/Makefile b/arch/cris/arch-v32/mach-a3/Makefile
index 41fa6a6..d366e08 100644
--- a/arch/cris/arch-v32/mach-a3/Makefile
+++ b/arch/cris/arch-v32/mach-a3/Makefile
@@ -1,10 +1,8 @@
-# $Id: Makefile,v 1.3 2007/03/13 11:57:46 starvik Exp $
 #
 # Makefile for the linux kernel.
 #
 
 obj-y   := dma.o pinmux.o io.o arbiter.o
-obj-$(CONFIG_ETRAX_VCS_SIM) += vcs_hook.o
 obj-$(CONFIG_CPU_FREQ)   += cpufreq.o
 
 clean:
diff --git a/arch/cris/arch-v32/mach-a3/vcs_hook.c b/arch/cris/arch-v32/mach-a3/vcs_hook.c
deleted file mode 100644
index 58b1a54..0000000
--- a/arch/cris/arch-v32/mach-a3/vcs_hook.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Simulator hook mechanism
- */
-
-#include "vcs_hook.h"
-#include <asm/io.h>
-#include <stdarg.h>
-
-#define HOOK_TRIG_ADDR      0xb7000000
-#define HOOK_MEM_BASE_ADDR  0xce000000
-
-static volatile unsigned *hook_base;
-
-#define HOOK_DATA(offset) hook_base[offset]
-#define VHOOK_DATA(offset) hook_base[offset]
-#define HOOK_TRIG(funcid) \
-	do { \
-		*((unsigned *) HOOK_TRIG_ADDR) = funcid; \
-	} while (0)
-#define HOOK_DATA_BYTE(offset) ((unsigned char *)hook_base)[offset]
-
-static void hook_init(void)
-{
-	static int first = 1;
-	if (first) {
-		first = 0;
-		hook_base = ioremap(HOOK_MEM_BASE_ADDR, 8192);
-	}
-}
-
-static unsigned hook_trig(unsigned id)
-{
-	unsigned ret;
-
-	/* preempt_disable(); */
-
-	/* Dummy read from mem to make sure data has propagated to memory
-	 * before trigging */
-	ret = *hook_base;
-
-	/* trigger hook */
-	HOOK_TRIG(id);
-
-	/* wait for call to finish */
-	while (VHOOK_DATA(0) > 0) ;
-
-	/* extract return value */
-
-	ret = VHOOK_DATA(1);
-
-	return ret;
-}
-
-int hook_call(unsigned id, unsigned pcnt, ...)
-{
-	va_list ap;
-	int i;
-	unsigned ret;
-
-	hook_init();
-
-	HOOK_DATA(0) = id;
-
-	va_start(ap, pcnt);
-	for (i = 1; i <= pcnt; i++)
-		HOOK_DATA(i) = va_arg(ap, unsigned);
-	va_end(ap);
-
-	ret = hook_trig(id);
-
-	return ret;
-}
-
-int hook_call_str(unsigned id, unsigned size, const char *str)
-{
-	int i;
-	unsigned ret;
-
-	hook_init();
-
-	HOOK_DATA(0) = id;
-	HOOK_DATA(1) = size;
-
-	for (i = 0; i < size; i++)
-		HOOK_DATA_BYTE(8 + i) = str[i];
-	HOOK_DATA_BYTE(8 + i) = 0;
-
-	ret = hook_trig(id);
-
-	return ret;
-}
-
-void print_str(const char *str)
-{
-	int i;
-	/* find null at end of string */
-	for (i = 1; str[i]; i++) ;
-	hook_call(hook_print_str, i, str);
-}
-
-void CPU_WATCHDOG_TIMEOUT(unsigned t)
-{
-}
diff --git a/arch/cris/arch-v32/mach-a3/vcs_hook.h b/arch/cris/arch-v32/mach-a3/vcs_hook.h
deleted file mode 100644
index 8b73d0e..0000000
--- a/arch/cris/arch-v32/mach-a3/vcs_hook.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Simulator hook call mechanism
- */
-
-#ifndef __hook_h__
-#define __hook_h__
-
-int hook_call(unsigned id, unsigned pcnt, ...);
-int hook_call_str(unsigned id, unsigned size, const char *str);
-
-enum hook_ids {
-  hook_debug_on = 1,
-  hook_debug_off,
-  hook_stop_sim_ok,
-  hook_stop_sim_fail,
-  hook_alloc_shared,
-  hook_ptr_shared,
-  hook_free_shared,
-  hook_file2shared,
-  hook_cmp_shared,
-  hook_print_params,
-  hook_sim_time,
-  hook_stop_sim,
-  hook_kick_dog,
-  hook_dog_timeout,
-  hook_rand,
-  hook_srand,
-  hook_rand_range,
-  hook_print_str,
-  hook_print_hex,
-  hook_cmp_offset_shared,
-  hook_fill_random_shared,
-  hook_alloc_random_data,
-  hook_calloc_random_data,
-  hook_print_int,
-  hook_print_uint,
-  hook_fputc,
-  hook_init_fd,
-  hook_sbrk,
-  hook_print_context_descr,
-  hook_print_data_descr,
-  hook_print_group_descr,
-  hook_fill_shared,
-  hook_sl_srand,
-  hook_sl_rand_irange,
-  hook_sl_rand_urange,
-  hook_sl_sh_malloc_aligned,
-  hook_sl_sh_calloc_aligned,
-  hook_sl_sh_alloc_random_data,
-  hook_sl_sh_file2mem,
-  hook_sl_vera_mbox_handle,
-  hook_sl_vera_mbox_put,
-  hook_sl_vera_mbox_get,
-  hook_sl_system,
-  hook_sl_sh_hexdump
-};
-
-#endif
diff --git a/arch/cris/arch-v32/mach-fs/Makefile b/arch/cris/arch-v32/mach-fs/Makefile
index 41fa6a6..d366e08 100644
--- a/arch/cris/arch-v32/mach-fs/Makefile
+++ b/arch/cris/arch-v32/mach-fs/Makefile
@@ -1,10 +1,8 @@
-# $Id: Makefile,v 1.3 2007/03/13 11:57:46 starvik Exp $
 #
 # Makefile for the linux kernel.
 #
 
 obj-y   := dma.o pinmux.o io.o arbiter.o
-obj-$(CONFIG_ETRAX_VCS_SIM) += vcs_hook.o
 obj-$(CONFIG_CPU_FREQ)   += cpufreq.o
 
 clean:
diff --git a/arch/cris/arch-v32/mach-fs/vcs_hook.c b/arch/cris/arch-v32/mach-fs/vcs_hook.c
deleted file mode 100644
index b11594a..0000000
--- a/arch/cris/arch-v32/mach-fs/vcs_hook.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Call simulator hook. This is the part running in the
- * simulated program.
- */
-
-#include "vcs_hook.h"
-#include <stdarg.h>
-#include <arch-v32/hwregs/reg_map.h>
-#include <arch-v32/hwregs/intr_vect_defs.h>
-
-#define HOOK_TRIG_ADDR     0xb7000000	/* hook cvlog model reg address */
-#define HOOK_MEM_BASE_ADDR 0xa0000000	/* csp4 (shared mem) base addr */
-
-#define HOOK_DATA(offset) ((unsigned *)HOOK_MEM_BASE_ADDR)[offset]
-#define VHOOK_DATA(offset) ((volatile unsigned *)HOOK_MEM_BASE_ADDR)[offset]
-#define HOOK_TRIG(funcid) \
-	do { \
-		*((unsigned *) HOOK_TRIG_ADDR) = funcid; \
-	} while (0)
-#define HOOK_DATA_BYTE(offset) ((unsigned char *)HOOK_MEM_BASE_ADDR)[offset]
-
-int hook_call(unsigned id, unsigned pcnt, ...)
-{
-	va_list ap;
-	unsigned i;
-	unsigned ret;
-#ifdef USING_SOS
-	PREEMPT_OFF_SAVE();
-#endif
-
-	/* pass parameters */
-	HOOK_DATA(0) = id;
-
-	/* Have to make hook_print_str a special case since we call with a
-	 * parameter of byte type. Should perhaps be a separate
-	 * hook_call. */
-
-	if (id == hook_print_str) {
-		int i;
-		char *str;
-
-		HOOK_DATA(1) = pcnt;
-
-		va_start(ap, pcnt);
-		str = (char *)va_arg(ap, unsigned);
-
-		for (i = 0; i != pcnt; i++)
-			HOOK_DATA_BYTE(8 + i) = str[i];
-
-		HOOK_DATA_BYTE(8 + i) = 0;	/* null byte */
-	} else {
-		va_start(ap, pcnt);
-		for (i = 1; i <= pcnt; i++)
-			HOOK_DATA(i) = va_arg(ap, unsigned);
-		va_end(ap);
-	}
-
-	/* read from mem to make sure data has propagated to memory before
-	 * trigging */
-	ret = *((volatile unsigned *)HOOK_MEM_BASE_ADDR);
-
-	/* trigger hook */
-	HOOK_TRIG(id);
-
-	/* wait for call to finish */
-	while (VHOOK_DATA(0) > 0) ;
-
-	/* extract return value */
-
-	ret = VHOOK_DATA(1);
-
-#ifdef USING_SOS
-	PREEMPT_RESTORE();
-#endif
-	return ret;
-}
-
-unsigned hook_buf(unsigned i)
-{
-	return (HOOK_DATA(i));
-}
-
-void print_str(const char *str)
-{
-	int i;
-	/* find null at end of string */
-	for (i = 1; str[i]; i++) ;
-	hook_call(hook_print_str, i, str);
-}
-
-void CPU_KICK_DOG(void)
-{
-	(void)hook_call(hook_kick_dog, 0);
-}
-
-void CPU_WATCHDOG_TIMEOUT(unsigned t)
-{
-	(void)hook_call(hook_dog_timeout, 1, t);
-}
-
diff --git a/arch/cris/arch-v32/mach-fs/vcs_hook.h b/arch/cris/arch-v32/mach-fs/vcs_hook.h
deleted file mode 100644
index c000b9f..0000000
--- a/arch/cris/arch-v32/mach-fs/vcs_hook.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Call simulator hook functions
- */
-
-#ifndef HOOK_H
-#define HOOK_H
-
-int hook_call(unsigned id, unsigned pcnt, ...);
-
-enum hook_ids {
-  hook_debug_on = 1,
-  hook_debug_off,
-  hook_stop_sim_ok,
-  hook_stop_sim_fail,
-  hook_alloc_shared,
-  hook_ptr_shared,
-  hook_free_shared,
-  hook_file2shared,
-  hook_cmp_shared,
-  hook_print_params,
-  hook_sim_time,
-  hook_stop_sim,
-  hook_kick_dog,
-  hook_dog_timeout,
-  hook_rand,
-  hook_srand,
-  hook_rand_range,
-  hook_print_str,
-  hook_print_hex,
-  hook_cmp_offset_shared,
-  hook_fill_random_shared,
-  hook_alloc_random_data,
-  hook_calloc_random_data,
-  hook_print_int,
-  hook_print_uint,
-  hook_fputc,
-  hook_init_fd,
-  hook_sbrk
-
-};
-
-#endif
diff --git a/arch/cris/arch-v32/mm/init.c b/arch/cris/arch-v32/mm/init.c
index 0768bc4..3deca52 100644
--- a/arch/cris/arch-v32/mm/init.c
+++ b/arch/cris/arch-v32/mm/init.c
@@ -73,11 +73,7 @@ void __init cris_mmu_init(void)
 #endif
 		       REG_STATE(mmu, rw_mm_cfg, seg_c, linear) |
 		       REG_STATE(mmu, rw_mm_cfg, seg_b, linear) |
-#ifndef CONFIG_ETRAX_VCS_SIM
                        REG_STATE(mmu, rw_mm_cfg, seg_a, page)   |
-#else
-		       REG_STATE(mmu, rw_mm_cfg, seg_a, linear) |
-#endif
 		       REG_STATE(mmu, rw_mm_cfg, seg_9, page)   |
 		       REG_STATE(mmu, rw_mm_cfg, seg_8, page)   |
 		       REG_STATE(mmu, rw_mm_cfg, seg_7, page)   |
@@ -100,11 +96,7 @@ void __init cris_mmu_init(void)
 #endif
                          REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0x4) |
 			 REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) |
-#ifndef CONFIG_ETRAX_VCS_SIM
 			 REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0x0) |
-#else
-                         REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa) |
-#endif
 			 REG_FIELD(mmu, rw_mm_kbase_hi, base_9, 0x0) |
 			 REG_FIELD(mmu, rw_mm_kbase_hi, base_8, 0x0));
 
diff --git a/arch/cris/include/arch-v32/arch/page.h b/arch/cris/include/arch-v32/arch/page.h
index 20f1b48..e5b5aab 100644
--- a/arch/cris/include/arch-v32/arch/page.h
+++ b/arch/cris/include/arch-v32/arch/page.h
@@ -11,13 +11,8 @@
  * selected bit it's possible to convert between KSEG_x and 0x40000000 where the
  * DRAM really resides. DRAM is virtually at 0xc.
  */
-#ifndef CONFIG_ETRAX_VCS_SIM
 #define __pa(x) ((unsigned long)(x) & 0x7fffffff)
 #define __va(x) ((void *)((unsigned long)(x) | 0x80000000))
-#else
-#define __pa(x) ((unsigned long)(x) & 0x3fffffff)
-#define __va(x) ((void *)((unsigned long)(x) | 0xc0000000))
-#endif
 
 #define VM_STACK_DEFAULT_FLAGS	(VM_READ | VM_WRITE | \
 				 VM_MAYREAD | VM_MAYWRITE)
diff --git a/arch/cris/include/arch-v32/arch/processor.h b/arch/cris/include/arch-v32/arch/processor.h
index 9603c90..a024b7d 100644
--- a/arch/cris/include/arch-v32/arch/processor.h
+++ b/arch/cris/include/arch-v32/arch/processor.h
@@ -21,13 +21,9 @@ struct thread_struct {
 
 /*
  * User-space process size. This is hardcoded into a few places, so don't
- * changed it unless everything's clear!
+ * change it unless everything's clear!
  */
-#ifndef CONFIG_ETRAX_VCS_SIM
 #define TASK_SIZE	(0xB0000000UL)
-#else
-#define TASK_SIZE	(0xA0000000UL)
-#endif
 
 /* CCS I=1, enable interrupts. */
 #define INIT_THREAD { 0, 0, (1 << I_CCS_BITNR) }
diff --git a/arch/cris/include/arch-v32/mach-fs/mach/startup.inc b/arch/cris/include/arch-v32/mach-fs/mach/startup.inc
index dd1abbd..96c3b0f 100644
--- a/arch/cris/include/arch-v32/mach-fs/mach/startup.inc
+++ b/arch/cris/include/arch-v32/mach-fs/mach/startup.inc
@@ -71,12 +71,6 @@
 	move.d   REG_ADDR(bif_core, regi_bif_core, rw_grp4_cfg), $r0
 	move.d   CONFIG_ETRAX_MEM_GRP4_CONFIG, $r1
 	move.d   $r1, [$r0]
-#ifdef CONFIG_ETRAX_VCS_SIM
-	;; Set up minimal flash waitstates
-	move.d 0, $r10
-	move.d REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r11
-	move.d $r10, [$r11]
-#endif
 	.endm
 
 #endif
diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild
index 04d02a5..28b690d 100644
--- a/arch/cris/include/asm/Kbuild
+++ b/arch/cris/include/asm/Kbuild
@@ -7,3 +7,5 @@ header-y += ethernet.h
 header-y += etraxgpio.h
 header-y += rs485.h
 header-y += sync_serial.h
+
+generic-y += module.h
diff --git a/arch/cris/include/asm/module.h b/arch/cris/include/asm/module.h
deleted file mode 100644
index 7ee7231..0000000
--- a/arch/cris/include/asm/module.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _ASM_CRIS_MODULE_H
-#define _ASM_CRIS_MODULE_H
-/* cris is simple */
-struct mod_arch_specific { };
-
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
-#endif /* _ASM_CRIS_MODULE_H */
diff --git a/arch/cris/include/asm/pci.h b/arch/cris/include/asm/pci.h
index 9f1cd56..146da90 100644
--- a/arch/cris/include/asm/pci.h
+++ b/arch/cris/include/asm/pci.h
@@ -19,7 +19,6 @@ extern unsigned long pci_mem_start;
 
 void pcibios_config_init(void);
 struct pci_bus * pcibios_scan_root(int bus);
-int pcibios_assign_resources(void);
 
 void pcibios_set_master(struct pci_dev *dev);
 void pcibios_penalize_isa_irq(int irq);
diff --git a/arch/cris/include/asm/thread_info.h b/arch/cris/include/asm/thread_info.h
index 5b1c448..07c8c40 100644
--- a/arch/cris/include/asm/thread_info.h
+++ b/arch/cris/include/asm/thread_info.h
@@ -78,15 +78,12 @@ struct thread_info {
 #define TIF_SIGPENDING		2	/* signal pending */
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_RESTORE_SIGMASK	9	/* restore signal mask in do_signal() */
-#define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		17	/* is terminating due to OOM killer */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
 #define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
 #define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
diff --git a/arch/frv/include/asm/module.h b/arch/frv/include/asm/module.h
index 3d5c636..a8848f0 100644
--- a/arch/frv/include/asm/module.h
+++ b/arch/frv/include/asm/module.h
@@ -11,13 +11,7 @@
 #ifndef _ASM_MODULE_H
 #define _ASM_MODULE_H
 
-struct mod_arch_specific
-{
-};
-
-#define Elf_Shdr	Elf32_Shdr
-#define Elf_Sym		Elf32_Sym
-#define Elf_Ehdr	Elf32_Ehdr
+#include <asm-generic/module.h>
 
 /*
  * Include the architecture version.
diff --git a/arch/frv/include/asm/thread_info.h b/arch/frv/include/asm/thread_info.h
index 0ff03a3..bebd7ea 100644
--- a/arch/frv/include/asm/thread_info.h
+++ b/arch/frv/include/asm/thread_info.h
@@ -94,7 +94,6 @@ register struct thread_info *__current_thread_info asm("gr15");
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_SINGLESTEP		4	/* restore singlestep on return to user mode */
 #define TIF_RESTORE_SIGMASK	5	/* restore signal mask in do_signal() */
-#define TIF_POLLING_NRFLAG	6	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		7	/* is terminating due to OOM killer */
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
@@ -102,8 +101,6 @@ register struct thread_info *__current_thread_info asm("gr15");
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
-#define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
-#define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK		\
diff --git a/arch/frv/kernel/pm.c b/arch/frv/kernel/pm.c
index 5fa3889..0b57992 100644
--- a/arch/frv/kernel/pm.c
+++ b/arch/frv/kernel/pm.c
@@ -153,23 +153,22 @@ static int user_atoi(char __user *ubuf, size_t len)
 static int sysctl_pm_do_suspend(ctl_table *ctl, int write,
 				void __user *buffer, size_t *lenp, loff_t *fpos)
 {
-	int retval, mode;
+	int mode;
 
 	if (*lenp <= 0)
 		return -EIO;
 
 	mode = user_atoi(buffer, *lenp);
-	if ((mode != 1) && (mode != 5))
-		return -EINVAL;
+	switch (mode) {
+	case 1:
+	    return pm_do_suspend();
 
-	if (retval == 0) {
-		if (mode == 5)
-		    retval = pm_do_bus_sleep();
-		else
-		    retval = pm_do_suspend();
-	}
+	case 5:
+	    return pm_do_bus_sleep();
 
-	return retval;
+	default:
+	    return -EINVAL;
+	}
 }
 
 static int try_set_cmode(int new_cmode)
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
index 864c2f0..535810a 100644
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -20,7 +20,6 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/personality.h>
-#include <linux/freezer.h>
 #include <linux/tracehook.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
@@ -298,10 +297,6 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set)
 	__frame->lr   = (unsigned long) &frame->retcode;
 	__frame->gr8  = sig;
 
-	/* the tracer may want to single-step inside the handler */
-	if (test_thread_flag(TIF_SINGLESTEP))
-		ptrace_notify(SIGTRAP);
-
 #if DEBUG_SIG
 	printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
 	       sig, current->comm, current->pid, frame, __frame->pc,
@@ -400,10 +395,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 	__frame->gr8 = sig;
 	__frame->gr9 = (unsigned long) &frame->info;
 
-	/* the tracer may want to single-step inside the handler */
-	if (test_thread_flag(TIF_SINGLESTEP))
-		ptrace_notify(SIGTRAP);
-
 #if DEBUG_SIG
 	printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
 	       sig, current->comm, current->pid, frame, __frame->pc,
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 5e8a0d9..c149d3b29 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -6,6 +6,7 @@ config H8300
 	select ARCH_WANT_IPC_PARSE_VERSION
 	select GENERIC_IRQ_SHOW
 	select GENERIC_CPU_DEVICES
+	select MODULES_USE_ELF_RELA
 
 config SYMBOL_PREFIX
 	string
diff --git a/arch/h8300/include/asm/Kbuild b/arch/h8300/include/asm/Kbuild
index c68e168..871382d 100644
--- a/arch/h8300/include/asm/Kbuild
+++ b/arch/h8300/include/asm/Kbuild
@@ -1 +1,3 @@
 include include/asm-generic/Kbuild.asm
+
+generic-y	+= module.h
diff --git a/arch/h8300/include/asm/module.h b/arch/h8300/include/asm/module.h
deleted file mode 100644
index 8e46724..0000000
--- a/arch/h8300/include/asm/module.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef _ASM_H8300_MODULE_H
-#define _ASM_H8300_MODULE_H
-/*
- * This file contains the H8/300 architecture specific module code.
- */
-struct mod_arch_specific { };
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
-
-#endif /* _ASM_H8/300_MODULE_H */
diff --git a/arch/h8300/include/asm/thread_info.h b/arch/h8300/include/asm/thread_info.h
index 9c126e0..ec2f777 100644
--- a/arch/h8300/include/asm/thread_info.h
+++ b/arch/h8300/include/asm/thread_info.h
@@ -85,8 +85,6 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SYSCALL_TRACE	0	/* syscall trace active */
 #define TIF_SIGPENDING		1	/* signal pending */
 #define TIF_NEED_RESCHED	2	/* rescheduling necessary */
-#define TIF_POLLING_NRFLAG	3	/* true if poll_idle() is polling
-					   TIF_NEED_RESCHED */
 #define TIF_MEMDIE		4	/* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK	5	/* restore signal mask in do_signal() */
 #define TIF_NOTIFY_RESUME	6	/* callback before returning to user */
@@ -95,11 +93,10 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 
-#define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
+#define _TIF_WORK_MASK		(_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+				 _TIF_NOTIFY_RESUME)
 
 #endif /* __KERNEL__ */
 
diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c
index 5adaada..0e81b96 100644
--- a/arch/h8300/kernel/signal.c
+++ b/arch/h8300/kernel/signal.c
@@ -38,7 +38,6 @@
 #include <linux/personality.h>
 #include <linux/tty.h>
 #include <linux/binfmts.h>
-#include <linux/freezer.h>
 #include <linux/tracehook.h>
 
 #include <asm/setup.h>
diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig
index b2fdfb7..0744f7d 100644
--- a/arch/hexagon/Kconfig
+++ b/arch/hexagon/Kconfig
@@ -30,6 +30,7 @@ config HEXAGON
 	select KTIME_SCALAR
 	select GENERIC_CLOCKEVENTS
 	select GENERIC_CLOCKEVENTS_BROADCAST
+	select MODULES_USE_ELF_RELA
 	---help---
 	  Qualcomm Hexagon is a processor architecture designed for high
 	  performance and low power across a wide variety of applications.
diff --git a/arch/hexagon/include/asm/thread_info.h b/arch/hexagon/include/asm/thread_info.h
index 4f936a7..e4a0aad 100644
--- a/arch/hexagon/include/asm/thread_info.h
+++ b/arch/hexagon/include/asm/thread_info.h
@@ -120,10 +120,8 @@ register struct thread_info *__current_thread_info asm(QUOTED_THREADINFO_REG);
 #define TIF_SIGPENDING          2       /* signal pending */
 #define TIF_NEED_RESCHED        3       /* rescheduling necessary */
 #define TIF_SINGLESTEP          4       /* restore ss @ return to usr mode */
-#define TIF_IRET                5       /* return with iret */
 #define TIF_RESTORE_SIGMASK     6       /* restore sig mask in do_signal() */
 /* true if poll_idle() is polling TIF_NEED_RESCHED */
-#define TIF_POLLING_NRFLAG      16
 #define TIF_MEMDIE              17      /* OOM killer killed process */
 
 #define _TIF_SYSCALL_TRACE      (1 << TIF_SYSCALL_TRACE)
@@ -131,9 +129,6 @@ register struct thread_info *__current_thread_info asm(QUOTED_THREADINFO_REG);
 #define _TIF_SIGPENDING         (1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED       (1 << TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP         (1 << TIF_SINGLESTEP)
-#define _TIF_IRET               (1 << TIF_IRET)
-#define _TIF_RESTORE_SIGMASK    (1 << TIF_RESTORE_SIGMASK)
-#define _TIF_POLLING_NRFLAG     (1 << TIF_POLLING_NRFLAG)
 
 /* work to do on interrupt/exception return - All but TIF_SYSCALL_TRACE */
 #define _TIF_WORK_MASK          (0x0000FFFF & ~_TIF_SYSCALL_TRACE)
diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c
index 304b0808..1ea16be 100644
--- a/arch/hexagon/kernel/signal.c
+++ b/arch/hexagon/kernel/signal.c
@@ -20,7 +20,6 @@
 
 #include <linux/linkage.h>
 #include <linux/syscalls.h>
-#include <linux/freezer.h>
 #include <linux/tracehook.h>
 #include <asm/registers.h>
 #include <asm/thread_info.h>
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 310cf57..6881464 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -39,6 +39,8 @@ config IA64
 	select ARCH_THREAD_INFO_ALLOCATOR
 	select ARCH_CLOCKSOURCE_DATA
 	select GENERIC_TIME_VSYSCALL
+	select HAVE_MOD_ARCH_SPECIFIC
+	select MODULES_USE_ELF_RELA
 	default y
 	help
 	  The Itanium Processor Family is Intel's 64-bit successor to
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
index c34785d..ec536e4 100644
--- a/arch/ia64/hp/sim/simserial.c
+++ b/arch/ia64/hp/sim/simserial.c
@@ -338,7 +338,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 {
 	/* Handle turning off CRTSCTS */
 	if ((old_termios->c_cflag & CRTSCTS) &&
-	    !(tty->termios->c_cflag & CRTSCTS)) {
+	    !(tty->termios.c_cflag & CRTSCTS)) {
 		tty->hw_stopped = 0;
 	}
 }
@@ -545,6 +545,7 @@ static int __init simrs_init(void)
 	/* the port is imaginary */
 	printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq);
 
+	tty_port_link_device(&state->port, hp_simserial_driver, 0);
 	retval = tty_register_driver(hp_simserial_driver);
 	if (retval) {
 		printk(KERN_ERR "Couldn't register simserial driver\n");
diff --git a/arch/ia64/include/asm/module.h b/arch/ia64/include/asm/module.h
index 908eaef..dfba22a 100644
--- a/arch/ia64/include/asm/module.h
+++ b/arch/ia64/include/asm/module.h
@@ -1,6 +1,8 @@
 #ifndef _ASM_IA64_MODULE_H
 #define _ASM_IA64_MODULE_H
 
+#include <asm-generic/module.h>
+
 /*
  * IA-64-specific support for kernel module loader.
  *
@@ -29,10 +31,6 @@ struct mod_arch_specific {
 	unsigned int next_got_entry;	/* index of next available got entry */
 };
 
-#define Elf_Shdr	Elf64_Shdr
-#define Elf_Sym		Elf64_Sym
-#define Elf_Ehdr	Elf64_Ehdr
-
 #define MODULE_PROC_FAMILY	"ia64"
 #define MODULE_ARCH_VERMAGIC	MODULE_PROC_FAMILY \
 	"gcc-" __stringify(__GNUC__) "." __stringify(__GNUC_MINOR__)
diff --git a/arch/ia64/include/asm/thread_info.h b/arch/ia64/include/asm/thread_info.h
index f7ee853..ff2ae41 100644
--- a/arch/ia64/include/asm/thread_info.h
+++ b/arch/ia64/include/asm/thread_info.h
@@ -106,7 +106,6 @@ struct thread_info {
 #define TIF_SYSCALL_AUDIT	3	/* syscall auditing active */
 #define TIF_SINGLESTEP		4	/* restore singlestep on return to user mode */
 #define TIF_NOTIFY_RESUME	6	/* resumption notification requested */
-#define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		17	/* is terminating due to OOM killer */
 #define TIF_MCA_INIT		18	/* this task is processing MCA or INIT */
 #define TIF_DB_DISABLED		19	/* debug trap disabled for fsyscall */
@@ -119,7 +118,6 @@ struct thread_info {
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
-#define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 #define _TIF_MCA_INIT		(1 << TIF_MCA_INIT)
 #define _TIF_DB_DISABLED	(1 << TIF_DB_DISABLED)
 #define _TIF_RESTORE_RSE	(1 << TIF_RESTORE_RSE)
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 3fa4bc5..2eae90e 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -2307,7 +2307,7 @@ pfm_smpl_buffer_alloc(struct task_struct *task, struct file *filp, pfm_context_t
 	 */
 	vma->vm_mm	     = mm;
 	vma->vm_file	     = filp;
-	vma->vm_flags	     = VM_READ| VM_MAYREAD |VM_RESERVED;
+	vma->vm_flags	     = VM_READ | VM_MAYREAD | VM_DONTEXPAND | VM_DONTDUMP;
 	vma->vm_page_prot    = PAGE_READONLY; /* XXX may need to change */
 
 	/*
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index a199be1..19f89c0 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -438,14 +438,6 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall)
 	long errno = scr->pt.r8;
 
 	/*
-	 * In the ia64_leave_kernel code path, we want the common case to go fast, which
-	 * is why we may in certain cases get here from kernel mode. Just return without
-	 * doing anything if so.
-	 */
-	if (!user_mode(&scr->pt))
-		return;
-
-	/*
 	 * This only loops in the rare cases of handle_signal() failing, in which case we
 	 * need to push through a forced SIGSEGV.
 	 */
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index bd77cb5..eac6538 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -924,6 +924,16 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 	return 0;
 }
 
+int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event)
+{
+	if (!irqchip_in_kernel(kvm))
+		return -ENXIO;
+
+	irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
+					irq_event->irq, irq_event->level);
+	return 0;
+}
+
 long kvm_arch_vm_ioctl(struct file *filp,
 		unsigned int ioctl, unsigned long arg)
 {
@@ -963,29 +973,6 @@ long kvm_arch_vm_ioctl(struct file *filp,
 			goto out;
 		}
 		break;
-	case KVM_IRQ_LINE_STATUS:
-	case KVM_IRQ_LINE: {
-		struct kvm_irq_level irq_event;
-
-		r = -EFAULT;
-		if (copy_from_user(&irq_event, argp, sizeof irq_event))
-			goto out;
-		r = -ENXIO;
-		if (irqchip_in_kernel(kvm)) {
-			__s32 status;
-			status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
-				    irq_event.irq, irq_event.level);
-			if (ioctl == KVM_IRQ_LINE_STATUS) {
-				r = -EFAULT;
-				irq_event.status = status;
-				if (copy_to_user(argp, &irq_event,
-							sizeof irq_event))
-					goto out;
-			}
-			r = 0;
-		}
-		break;
-		}
 	case KVM_GET_IRQCHIP: {
 		/* 0: PIC master, 1: PIC slave, 2: IOAPIC */
 		struct kvm_irqchip chip;
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 0eab454..082e383 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -138,7 +138,8 @@ ia64_init_addr_space (void)
 			vma->vm_mm = current->mm;
 			vma->vm_end = PAGE_SIZE;
 			vma->vm_page_prot = __pgprot(pgprot_val(PAGE_READONLY) | _PAGE_MA_NAT);
-			vma->vm_flags = VM_READ | VM_MAYREAD | VM_IO | VM_RESERVED;
+			vma->vm_flags = VM_READ | VM_MAYREAD | VM_IO |
+					VM_DONTEXPAND | VM_DONTDUMP;
 			down_write(&current->mm->mmap_sem);
 			if (insert_vm_struct(current->mm, vma)) {
 				up_write(&current->mm->mmap_sem);
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index 49498bb..fc61533 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -13,6 +13,7 @@ config M32R
 	select GENERIC_IRQ_SHOW
 	select GENERIC_ATOMIC64
 	select ARCH_USES_GETTIMEOFFSET
+	select MODULES_USE_ELF_RELA
 
 config SBUS
 	bool
diff --git a/arch/m32r/include/asm/Kbuild b/arch/m32r/include/asm/Kbuild
index c68e168..871382d 100644
--- a/arch/m32r/include/asm/Kbuild
+++ b/arch/m32r/include/asm/Kbuild
@@ -1 +1,3 @@
 include include/asm-generic/Kbuild.asm
+
+generic-y	+= module.h
diff --git a/arch/m32r/include/asm/module.h b/arch/m32r/include/asm/module.h
deleted file mode 100644
index eb73ee0..0000000
--- a/arch/m32r/include/asm/module.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _ASM_M32R_MODULE_H
-#define _ASM_M32R_MODULE_H
-
-struct mod_arch_specific { };
-
-#define Elf_Shdr	Elf32_Shdr
-#define Elf_Sym		Elf32_Sym
-#define Elf_Ehdr	Elf32_Ehdr
-
-#endif /* _ASM_M32R_MODULE_H */
diff --git a/arch/m32r/include/asm/thread_info.h b/arch/m32r/include/asm/thread_info.h
index c083f60..c074f4c 100644
--- a/arch/m32r/include/asm/thread_info.h
+++ b/arch/m32r/include/asm/thread_info.h
@@ -119,25 +119,20 @@ static inline unsigned int get_thread_fault_code(void)
 #define TIF_SIGPENDING		1	/* signal pending */
 #define TIF_NEED_RESCHED	2	/* rescheduling necessary */
 #define TIF_SINGLESTEP		3	/* restore singlestep on return to user mode */
-#define TIF_IRET		4	/* return with iret */
 #define TIF_NOTIFY_RESUME	5	/* callback before returning to user */
 #define TIF_RESTORE_SIGMASK	8	/* restore signal mask in do_signal() */
 #define TIF_USEDFPU		16	/* FPU was used by this task this quantum (SMP) */
-#define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		18	/* is terminating due to OOM killer */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
-#define _TIF_IRET		(1<<TIF_IRET)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_USEDFPU		(1<<TIF_USEDFPU)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
-#define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
-#define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
+#define _TIF_WORK_MASK		(_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_NOTIFY_RESUME)
+#define _TIF_ALLWORK_MASK	(_TIF_WORK_MASK | _TIF_SYSCALL_TRACE)
 
 /*
  * Thread-synchronous status.
diff --git a/arch/m32r/kernel/module.c b/arch/m32r/kernel/module.c
index 3071fe8..38233b6 100644
--- a/arch/m32r/kernel/module.c
+++ b/arch/m32r/kernel/module.c
@@ -201,18 +201,3 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
 	}
 	return 0;
 }
-
-int apply_relocate(Elf32_Shdr *sechdrs,
-		       const char *strtab,
-		       unsigned int symindex,
-		       unsigned int relsec,
-		       struct module *me)
-{
-#if 0
-	printk(KERN_ERR "module %s: REL RELOCATION unsupported\n",
-	       me->name);
-	return -ENOEXEC;
-#endif
-	return 0;
-
-}
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c
index d0f60b9..6e3c26a 100644
--- a/arch/m32r/kernel/signal.c
+++ b/arch/m32r/kernel/signal.c
@@ -20,7 +20,6 @@
 #include <linux/unistd.h>
 #include <linux/stddef.h>
 #include <linux/personality.h>
-#include <linux/freezer.h>
 #include <linux/tracehook.h>
 #include <asm/cacheflush.h>
 #include <asm/ucontext.h>
@@ -366,6 +365,4 @@ void do_notify_resume(struct pt_regs *regs, __u32 thread_info_flags)
 		clear_thread_flag(TIF_NOTIFY_RESUME);
 		tracehook_notify_resume(regs);
 	}
-
-	clear_thread_flag(TIF_IRET);
 }
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 4a46990..0df07ce 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -5,6 +5,7 @@ config M68K
 	select HAVE_AOUT if MMU
 	select HAVE_GENERIC_HARDIRQS
 	select GENERIC_IRQ_SHOW
+	select GENERIC_ATOMIC64
 	select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS
 	select GENERIC_CPU_DEVICES
 	select GENERIC_STRNCPY_FROM_USER if MMU
@@ -12,6 +13,9 @@ config M68K
 	select FPU if MMU
 	select ARCH_WANT_IPC_PARSE_VERSION
 	select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE
+	select HAVE_MOD_ARCH_SPECIFIC
+	select MODULES_USE_ELF_REL
+	select MODULES_USE_ELF_RELA
 
 config RWSEM_GENERIC_SPINLOCK
 	bool
diff --git a/arch/m68k/Kconfig.cpu b/arch/m68k/Kconfig.cpu
index 8206834..c4eb79e 100644
--- a/arch/m68k/Kconfig.cpu
+++ b/arch/m68k/Kconfig.cpu
@@ -28,6 +28,7 @@ config COLDFIRE
 	select CPU_HAS_NO_BITFIELDS
 	select CPU_HAS_NO_MULDIV64
 	select GENERIC_CSUM
+	select HAVE_CLK
 
 endchoice
 
@@ -58,7 +59,6 @@ config MCPU32
 config M68020
 	bool "68020 support"
 	depends on MMU
-	select GENERIC_ATOMIC64
 	select CPU_HAS_ADDRESS_SPACES
 	help
 	  If you anticipate running this kernel on a computer with a MC68020
@@ -69,7 +69,6 @@ config M68020
 config M68030
 	bool "68030 support"
 	depends on MMU && !MMU_SUN3
-	select GENERIC_ATOMIC64
 	select CPU_HAS_ADDRESS_SPACES
 	help
 	  If you anticipate running this kernel on a computer with a MC68030
@@ -79,7 +78,6 @@ config M68030
 config M68040
 	bool "68040 support"
 	depends on MMU && !MMU_SUN3
-	select GENERIC_ATOMIC64
 	select CPU_HAS_ADDRESS_SPACES
 	help
 	  If you anticipate running this kernel on a computer with a MC68LC040
@@ -90,7 +88,6 @@ config M68040
 config M68060
 	bool "68060 support"
 	depends on MMU && !MMU_SUN3
-	select GENERIC_ATOMIC64
 	select CPU_HAS_ADDRESS_SPACES
 	help
 	  If you anticipate running this kernel on a computer with a MC68060
diff --git a/arch/m68k/amiga/platform.c b/arch/m68k/amiga/platform.c
index 80076d3..6083088 100644
--- a/arch/m68k/amiga/platform.c
+++ b/arch/m68k/amiga/platform.c
@@ -56,10 +56,7 @@ static int __init amiga_init_bus(void)
 	n = AMIGAHW_PRESENT(ZORRO3) ? 4 : 2;
 	pdev = platform_device_register_simple("amiga-zorro", -1,
 					       zorro_resources, n);
-	if (IS_ERR(pdev))
-		return PTR_ERR(pdev);
-
-	return 0;
+	return PTR_RET(pdev);
 }
 
 subsys_initcall(amiga_init_bus);
diff --git a/arch/m68k/emu/nfcon.c b/arch/m68k/emu/nfcon.c
index 8db25e8..16d170f 100644
--- a/arch/m68k/emu/nfcon.c
+++ b/arch/m68k/emu/nfcon.c
@@ -19,6 +19,7 @@
 #include <asm/natfeat.h>
 
 static int stderr_id;
+static struct tty_port nfcon_tty_port;
 static struct tty_driver *nfcon_tty_driver;
 
 static void nfputs(const char *str, unsigned int count)
@@ -119,6 +120,8 @@ static int __init nfcon_init(void)
 {
 	int res;
 
+	tty_port_init(&nfcon_tty_port);
+
 	stderr_id = nf_get_id("NF_STDERR");
 	if (!stderr_id)
 		return -ENODEV;
@@ -135,6 +138,7 @@ static int __init nfcon_init(void)
 	nfcon_tty_driver->flags = TTY_DRIVER_REAL_RAW;
 
 	tty_set_operations(nfcon_tty_driver, &nfcon_tty_ops);
+	tty_port_link_device(&nfcon_tty_port, nfcon_tty_driver, 0);
 	res = tty_register_driver(nfcon_tty_driver);
 	if (res) {
 		pr_err("failed to register nfcon tty driver\n");
diff --git a/arch/m68k/include/asm/apollohw.h b/arch/m68k/include/asm/apollohw.h
index 635ef4f..6c19e0c 100644
--- a/arch/m68k/include/asm/apollohw.h
+++ b/arch/m68k/include/asm/apollohw.h
@@ -46,18 +46,6 @@ struct SCN2681 {
 
 };
 
-#if 0
-struct mc146818 {
-
-	unsigned int second1:4, second2:4, alarm_second1:4, alarm_second2:4,
-		     minute1:4, minute2:4, alarm_minute1:4, alarm_minute2:4;
-	unsigned int hours1:4, hours2:4, alarm_hours1:4, alarm_hours2:4,
-		     day_of_week1:4, day_of_week2:4, day_of_month1:4, day_of_month2:4;
-	unsigned int month1:4, month2:4, year1:4, year2:4, :16;
-
-};
-#endif
-
 struct mc146818 {
         unsigned char second, alarm_second;
         unsigned char minute, alarm_minute;
diff --git a/arch/m68k/include/asm/module.h b/arch/m68k/include/asm/module.h
index edffe66..8b58fce 100644
--- a/arch/m68k/include/asm/module.h
+++ b/arch/m68k/include/asm/module.h
@@ -1,6 +1,8 @@
 #ifndef _ASM_M68K_MODULE_H
 #define _ASM_M68K_MODULE_H
 
+#include <asm-generic/module.h>
+
 enum m68k_fixup_type {
 	m68k_fixup_memoffset,
 	m68k_fixup_vnode_shift,
@@ -36,8 +38,4 @@ struct module;
 extern void module_fixup(struct module *mod, struct m68k_fixup_info *start,
 			 struct m68k_fixup_info *end);
 
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
-
 #endif /* _ASM_M68K_MODULE_H */
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index 707f057..5d0bcaa 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -100,10 +100,7 @@ static int __init rtc_init(void)
 		return -ENODEV;
 
 	pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
-	if (IS_ERR(pdev))
-		return PTR_ERR(pdev);
-
-	return 0;
+	return PTR_RET(pdev);
 }
 
 module_init(rtc_init);
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
index 8a1ce32..1adb5b7 100644
--- a/arch/m68k/q40/config.c
+++ b/arch/m68k/q40/config.c
@@ -338,9 +338,6 @@ static __init int q40_add_kbd_device(void)
 		return -ENODEV;
 
 	pdev = platform_device_register_simple("q40kbd", -1, NULL, 0);
-	if (IS_ERR(pdev))
-		return PTR_ERR(pdev);
-
-	return 0;
+	return PTR_RET(pdev);
 }
 arch_initcall(q40_add_kbd_device);
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index ab9afca..b4f409f 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -24,6 +24,7 @@ config MICROBLAZE
 	select GENERIC_CPU_DEVICES
 	select GENERIC_ATOMIC64
 	select GENERIC_CLOCKEVENTS
+	select MODULES_USE_ELF_RELA
 
 config SWAP
 	def_bool n
diff --git a/arch/microblaze/include/asm/thread_info.h b/arch/microblaze/include/asm/thread_info.h
index 6c610234..008f304 100644
--- a/arch/microblaze/include/asm/thread_info.h
+++ b/arch/microblaze/include/asm/thread_info.h
@@ -121,7 +121,6 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_NEED_RESCHED	3 /* rescheduling necessary */
 /* restore singlestep on return to user mode */
 #define TIF_SINGLESTEP		4
-#define TIF_IRET		5 /* return with iret */
 #define TIF_MEMDIE		6	/* is terminating due to OOM killer */
 #define TIF_SYSCALL_AUDIT	9       /* syscall auditing active */
 #define TIF_SECCOMP		10      /* secure computing */
@@ -134,7 +133,6 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
-#define _TIF_IRET		(1 << TIF_IRET)
 #define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP		(1 << TIF_SECCOMP)
@@ -184,6 +182,7 @@ static inline bool test_and_clear_restore_sigmask(void)
 	ti->status &= ~TS_RESTORE_SIGMASK;
 	return true;
 }
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
 #endif
 
 #endif /* __KERNEL__ */
diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S
index 75c3ea1..4c3815f 100644
--- a/arch/microblaze/kernel/entry-nommu.S
+++ b/arch/microblaze/kernel/entry-nommu.S
@@ -124,6 +124,7 @@ ret_from_intr:
 	lwi	r11, r1, PT_MODE
 	bneid	r11, no_intr_resched
 
+3:
 	lwi	r6, r31, TS_THREAD_INFO	/* get thread info */
 	lwi	r19, r6, TI_FLAGS	/* get flags in thread info */
 				/* do an extra work if any bits are set */
@@ -132,11 +133,13 @@ ret_from_intr:
 	beqi	r11, 1f
 	bralid	r15, schedule
 	nop
+	bri	3b
 1:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
 	beqid	r11, no_intr_resched
 	addk	r5, r1, r0
 	bralid	r15, do_notify_resume
 	addk	r6, r0, r0
+	bri	3b
 
 no_intr_resched:
 	/* Disable interrupts, we are now committed to the state restore */
@@ -280,6 +283,7 @@ ENTRY(_user_exception)
 	/* Figure out which function to use for this system call. */
 	/* Note Microblaze barrel shift is optional, so don't rely on it */
 	add	r12, r12, r12			/* convert num -> ptr */
+	addik	r30, r0, 1			/* restarts allowed */
 	add	r12, r12, r12
 	lwi	r12, r12, sys_call_table	/* Get function pointer */
 	addik	r15, r0, ret_to_user-8		/* set return address */
@@ -369,6 +373,7 @@ ENTRY(_debug_exception)
 	bralid	r15, send_sig
 	add	r7, r0, r0			/* 3rd param zero */
 
+	addik	r30, r0, 1			/* restarts allowed ??? */
 	/* Restore r3/r4 to work around how ret_to_user works */
 	lwi	r3, r1, PT_R3
 	lwi	r4, r1, PT_R4
@@ -475,18 +480,26 @@ ENTRY(ret_from_fork)
 	nop
 
 work_pending:
+	lwi	r11, r1, PT_MODE
+	bneid	r11, 2f
+3:
 	enable_irq
-
 	andi	r11, r19, _TIF_NEED_RESCHED
 	beqi	r11, 1f
 	bralid	r15, schedule
 	nop
+	bri	4f
 1:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
 	beqi	r11, no_work_pending
-	addk	r5, r1, r0
+	addk	r5, r30, r0
 	bralid	r15, do_notify_resume
 	addik	r6, r0, 1
-	bri	no_work_pending
+	addk	r30, r0, r0	/* no restarts from now on */
+4:
+	disable_irq
+	lwi	r6, r31, TS_THREAD_INFO /* get thread info */
+	lwi	r19, r6, TI_FLAGS /* get flags in thread info */
+	bri	3b
 
 ENTRY(ret_to_user)
 	disable_irq
@@ -500,6 +513,7 @@ ENTRY(ret_to_user)
 no_work_pending:
 	disable_irq
 
+2:
 	/* save r31 */
 	swi	r31, r0, PER_CPU(CURRENT_SAVE)
 	/* save mode indicator */
@@ -564,6 +578,7 @@ sys_execve:
 	addk	r8, r1, r0
 
 sys_rt_sigreturn_wrapper:
+	addk	r30, r0, r0		/* no restarts for this one */
 	brid	sys_rt_sigreturn
 	addk	r5, r1, r0
 
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S
index 03f7b8c..82ed20d 100644
--- a/arch/microblaze/kernel/entry.S
+++ b/arch/microblaze/kernel/entry.S
@@ -371,6 +371,7 @@ C_ENTRY(_user_exception):
 	/* Figure out which function to use for this system call.  */
 	/* Note Microblaze barrel shift is optional, so don't rely on it */
 	add	r12, r12, r12;			/* convert num -> ptr */
+	addi	r30, r0, 1			/* restarts allowed */
 	add	r12, r12, r12;
 
 #ifdef DEBUG
@@ -419,26 +420,27 @@ C_ENTRY(ret_from_trap):
 	 * trigger rescheduling. */
 	/* get thread info from current task */
 	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;
-	lwi	r11, r11, TI_FLAGS;		/* get flags in thread info */
-	andi	r11, r11, _TIF_NEED_RESCHED;
+	lwi	r19, r11, TI_FLAGS;		/* get flags in thread info */
+	andi	r11, r19, _TIF_NEED_RESCHED;
 	beqi	r11, 5f;
 
 	bralid	r15, schedule;	/* Call scheduler */
 	nop;				/* delay slot */
+	bri	1b
 
 	/* Maybe handle a signal */
-5:	/* get thread info from current task*/
-	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;
-	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
-	beqi	r11, 1f;		/* Signals to handle, handle them */
+5:	
+	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+	beqi	r11, 4f;		/* Signals to handle, handle them */
 
 	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
 	bralid	r15, do_notify_resume;	/* Handle any signals */
-	addi	r6, r0, 1;		/* Arg 2: int in_syscall */
+	add	r6, r30, r0;		/* Arg 2: int in_syscall */
+	add	r30, r0, r0		/* no more restarts */
+	bri	1b
 
 /* Finally, return to user state.  */
-1:	set_bip;			/*  Ints masked for state restore */
+4:	set_bip;			/*  Ints masked for state restore */
 	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
 	VM_OFF;
 	tophys(r1,r1);
@@ -503,6 +505,7 @@ C_ENTRY(sys_execve):
 	addik	r8, r1, 0;		/* add user context as 4th arg */
 
 C_ENTRY(sys_rt_sigreturn_wrapper):
+	addik	r30, r0, r0		/* no restarts */
 	brid	sys_rt_sigreturn	/* Do real work */
 	addik	r5, r1, 0;		/* add user context as 1st arg */
 
@@ -610,20 +613,20 @@ C_ENTRY(ret_from_exc):
 
 	/* We're returning to user mode, so check for various conditions that
 	   trigger rescheduling. */
+1:
 	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
-	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_NEED_RESCHED;
+	lwi	r19, r11, TI_FLAGS;	/* get flags in thread info */
+	andi	r11, r19, _TIF_NEED_RESCHED;
 	beqi	r11, 5f;
 
 /* Call the scheduler before returning from a syscall/trap. */
 	bralid	r15, schedule;	/* Call scheduler */
 	nop;				/* delay slot */
+	bri	1b
 
 	/* Maybe handle a signal */
-5:	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
-	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
-	beqi	r11, 1f;		/* Signals to handle, handle them */
+5:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+	beqi	r11, 4f;		/* Signals to handle, handle them */
 
 	/*
 	 * Handle a signal return; Pending signals should be in r18.
@@ -639,9 +642,10 @@ C_ENTRY(ret_from_exc):
 	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
 	bralid	r15, do_notify_resume;	/* Handle any signals */
 	addi	r6, r0, 0;		/* Arg 2: int in_syscall */
+	bri	1b
 
 /* Finally, return to user state.  */
-1:	set_bip;			/* Ints masked for state restore */
+4:	set_bip;			/* Ints masked for state restore */
 	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
 	VM_OFF;
 	tophys(r1,r1);
@@ -721,22 +725,23 @@ ret_from_irq:
 	lwi	r11, r1, PT_MODE;
 	bnei	r11, 2f;
 
+1:
 	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;
-	lwi	r11, r11, TI_FLAGS; /* MS: get flags from thread info */
-	andi	r11, r11, _TIF_NEED_RESCHED;
+	lwi	r19, r11, TI_FLAGS; /* MS: get flags from thread info */
+	andi	r11, r19, _TIF_NEED_RESCHED;
 	beqi	r11, 5f
 	bralid	r15, schedule;
 	nop; /* delay slot */
+	bri	1b
 
     /* Maybe handle a signal */
-5:	lwi	r11, CURRENT_TASK, TS_THREAD_INFO; /* MS: get thread info */
-	lwi	r11, r11, TI_FLAGS; /* get flags in thread info */
-	andi	r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+5:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
 	beqid	r11, no_intr_resched
 /* Handle a signal return; Pending signals should be in r18. */
 	addik	r5, r1, 0; /* Arg 1: struct pt_regs *regs */
 	bralid	r15, do_notify_resume;	/* Handle any signals */
 	addi	r6, r0, 0; /* Arg 2: int in_syscall */
+	bri	1b
 
 /* Finally, return to user state. */
 no_intr_resched:
@@ -854,28 +859,29 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
 	lwi	r11, r1, PT_MODE;
 	bnei	r11, 2f;
 /* MS: Return to user space - gdb */
+1:
 	/* Get current task ptr into r11 */
 	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
-	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_NEED_RESCHED;
+	lwi	r19, r11, TI_FLAGS;	/* get flags in thread info */
+	andi	r11, r19, _TIF_NEED_RESCHED;
 	beqi	r11, 5f;
 
 	/* Call the scheduler before returning from a syscall/trap. */
 	bralid	r15, schedule;	/* Call scheduler */
 	nop;				/* delay slot */
+	bri	1b
 
 	/* Maybe handle a signal */
-5:	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
-	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
-	beqi	r11, 1f;		/* Signals to handle, handle them */
+5:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+	beqi	r11, 4f;		/* Signals to handle, handle them */
 
 	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
 	bralid	r15, do_notify_resume;	/* Handle any signals */
 	addi  r6, r0, 0;	/* Arg 2: int in_syscall */
+	bri	1b
 
 /* Finally, return to user state.  */
-1:	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
+4:	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
 	VM_OFF;
 	tophys(r1,r1);
 	/* MS: Restore all regs */
diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c
index 76b9722..a7a501e 100644
--- a/arch/microblaze/kernel/signal.c
+++ b/arch/microblaze/kernel/signal.c
@@ -254,10 +254,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 
 	set_fs(USER_DS);
 
-	/* the tracer may want to single-step inside the handler */
-	if (test_thread_flag(TIF_SINGLESTEP))
-		ptrace_notify(SIGTRAP);
-
 #ifdef DEBUG_SIG
 	printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n",
 		current->comm, current->pid, frame, regs->pc);
@@ -323,7 +319,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
 	if (ret)
 		return;
 
-	signal_delivered(sig, info, ka, regs, 0);
+	signal_delivered(sig, info, ka, regs,
+			test_thread_flag(TIF_SINGLESTEP));
 }
 
 /*
@@ -367,15 +364,6 @@ static void do_signal(struct pt_regs *regs, int in_syscall)
 
 void do_notify_resume(struct pt_regs *regs, int in_syscall)
 {
-	/*
-	 * We want the common case to go fast, which
-	 * is why we may in certain cases get here from
-	 * kernel mode. Just return without doing anything
-	 * if so.
-	 */
-	if (kernel_mode(regs))
-		return;
-
 	if (test_thread_flag(TIF_SIGPENDING))
 		do_signal(regs, in_syscall);
 
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 331d574..8a75c24 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -8,6 +8,8 @@ config MIPS
 	select HAVE_PERF_EVENTS
 	select PERF_USE_VMALLOC
 	select HAVE_ARCH_KGDB
+	select HAVE_ARCH_SECCOMP_FILTER
+	select HAVE_ARCH_TRACEHOOK
 	select ARCH_HAVE_CUSTOM_GPIO_H
 	select HAVE_FUNCTION_TRACER
 	select HAVE_FUNCTION_TRACE_MCOUNT_TEST
@@ -17,6 +19,7 @@ config MIPS
 	select HAVE_FUNCTION_GRAPH_TRACER
 	select HAVE_KPROBES
 	select HAVE_KRETPROBES
+	select HAVE_SYSCALL_TRACEPOINTS
 	select ARCH_BINFMT_ELF_RANDOMIZE_PIE
 	select RTC_LIB if !MACH_LOONGSON
 	select GENERIC_ATOMIC64 if !64BIT
@@ -36,6 +39,9 @@ config MIPS
 	select BUILDTIME_EXTABLE_SORT
 	select GENERIC_CLOCKEVENTS
 	select GENERIC_CMOS_UPDATE
+	select HAVE_MOD_ARCH_SPECIFIC
+	select MODULES_USE_ELF_REL
+	select MODULES_USE_ELF_RELA if 64BIT
 
 menu "Machine selection"
 
@@ -89,6 +95,7 @@ config ATH79
 	select CEVT_R4K
 	select CSRC_R4K
 	select DMA_NONCOHERENT
+	select HAVE_CLK
 	select IRQ_CPU
 	select MIPS_MACHINE
 	select SYS_HAS_CPU_MIPS32_R2
@@ -1901,6 +1908,7 @@ config MIPS_MT_SMP
 	select SYS_SUPPORTS_SCHED_SMT if SMP
 	select SYS_SUPPORTS_SMP
 	select SMP_UP
+	select MIPS_PERF_SHARED_TC_COUNTERS
 	help
 	  This is a kernel model which is known a VSMP but lately has been
 	  marketesed into SMVP.
@@ -2251,6 +2259,9 @@ config NR_CPUS
 	  performance should round up your number of processors to the next
 	  power of two.
 
+config MIPS_PERF_SHARED_TC_COUNTERS
+	bool
+
 #
 # Timer Interrupt Frequency Configuration
 #
diff --git a/arch/mips/alchemy/board-mtx1.c b/arch/mips/alchemy/board-mtx1.c
index 9996948..a124c25 100644
--- a/arch/mips/alchemy/board-mtx1.c
+++ b/arch/mips/alchemy/board-mtx1.c
@@ -228,6 +228,8 @@ static int mtx1_pci_idsel(unsigned int devsel, int assert)
 	 * adapter on the mtx-1 "singleboard" variant. It triggers a custom
 	 * logic chip connected to EXT_IO3 (GPIO1) to suppress IDSEL signals.
 	 */
+	udelay(1);
+
 	if (assert && devsel != 0)
 		/* Suppress signal to Cardbus */
 		alchemy_gpio_set_value(1, 0);	/* set EXT_IO3 OFF */
diff --git a/arch/mips/ath79/dev-usb.c b/arch/mips/ath79/dev-usb.c
index 36e9570..b2a2311 100644
--- a/arch/mips/ath79/dev-usb.c
+++ b/arch/mips/ath79/dev-usb.c
@@ -145,6 +145,8 @@ static void __init ar7240_usb_setup(void)
 
 	ath79_ohci_resources[0].start = AR7240_OHCI_BASE;
 	ath79_ohci_resources[0].end = AR7240_OHCI_BASE + AR7240_OHCI_SIZE - 1;
+	ath79_ohci_resources[1].start = ATH79_CPU_IRQ_USB;
+	ath79_ohci_resources[1].end = ATH79_CPU_IRQ_USB;
 	platform_device_register(&ath79_ohci_device);
 }
 
diff --git a/arch/mips/ath79/gpio.c b/arch/mips/ath79/gpio.c
index 29054f2..48fe762 100644
--- a/arch/mips/ath79/gpio.c
+++ b/arch/mips/ath79/gpio.c
@@ -188,8 +188,10 @@ void __init ath79_gpio_init(void)
 
 	if (soc_is_ar71xx())
 		ath79_gpio_count = AR71XX_GPIO_COUNT;
-	else if (soc_is_ar724x())
-		ath79_gpio_count = AR724X_GPIO_COUNT;
+	else if (soc_is_ar7240())
+		ath79_gpio_count = AR7240_GPIO_COUNT;
+	else if (soc_is_ar7241() || soc_is_ar7242())
+		ath79_gpio_count = AR7241_GPIO_COUNT;
 	else if (soc_is_ar913x())
 		ath79_gpio_count = AR913X_GPIO_COUNT;
 	else if (soc_is_ar933x())
diff --git a/arch/mips/bcm63xx/dev-spi.c b/arch/mips/bcm63xx/dev-spi.c
index e39f730..f1c9c3e 100644
--- a/arch/mips/bcm63xx/dev-spi.c
+++ b/arch/mips/bcm63xx/dev-spi.c
@@ -106,11 +106,15 @@ int __init bcm63xx_spi_register(void)
 	if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) {
 		spi_resources[0].end += BCM_6338_RSET_SPI_SIZE - 1;
 		spi_pdata.fifo_size = SPI_6338_MSG_DATA_SIZE;
+		spi_pdata.msg_type_shift = SPI_6338_MSG_TYPE_SHIFT;
+		spi_pdata.msg_ctl_width = SPI_6338_MSG_CTL_WIDTH;
 	}
 
 	if (BCMCPU_IS_6358() || BCMCPU_IS_6368()) {
 		spi_resources[0].end += BCM_6358_RSET_SPI_SIZE - 1;
 		spi_pdata.fifo_size = SPI_6358_MSG_DATA_SIZE;
+		spi_pdata.msg_type_shift = SPI_6358_MSG_TYPE_SHIFT;
+		spi_pdata.msg_ctl_width = SPI_6358_MSG_CTL_WIDTH;
 	}
 
 	bcm63xx_spi_regs_init();
diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c
index 7fb1f22..274cd4f 100644
--- a/arch/mips/cavium-octeon/octeon-irq.c
+++ b/arch/mips/cavium-octeon/octeon-irq.c
@@ -61,6 +61,12 @@ static void octeon_irq_set_ciu_mapping(int irq, int line, int bit,
 	octeon_irq_ciu_to_irq[line][bit] = irq;
 }
 
+static void octeon_irq_force_ciu_mapping(struct irq_domain *domain,
+					 int irq, int line, int bit)
+{
+	irq_domain_associate(domain, irq, line << 6 | bit);
+}
+
 static int octeon_coreid_for_cpu(int cpu)
 {
 #ifdef CONFIG_SMP
@@ -183,19 +189,9 @@ static void __init octeon_irq_init_core(void)
 		mutex_init(&cd->core_irq_mutex);
 
 		irq = OCTEON_IRQ_SW0 + i;
-		switch (irq) {
-		case OCTEON_IRQ_TIMER:
-		case OCTEON_IRQ_SW0:
-		case OCTEON_IRQ_SW1:
-		case OCTEON_IRQ_5:
-		case OCTEON_IRQ_PERF:
-			irq_set_chip_data(irq, cd);
-			irq_set_chip_and_handler(irq, &octeon_irq_chip_core,
-						 handle_percpu_irq);
-			break;
-		default:
-			break;
-		}
+		irq_set_chip_data(irq, cd);
+		irq_set_chip_and_handler(irq, &octeon_irq_chip_core,
+					 handle_percpu_irq);
 	}
 }
 
@@ -890,7 +886,6 @@ static int octeon_irq_gpio_xlat(struct irq_domain *d,
 	unsigned int type;
 	unsigned int pin;
 	unsigned int trigger;
-	struct octeon_irq_gpio_domain_data *gpiod;
 
 	if (d->of_node != node)
 		return -EINVAL;
@@ -925,8 +920,7 @@ static int octeon_irq_gpio_xlat(struct irq_domain *d,
 		break;
 	}
 	*out_type = type;
-	gpiod = d->host_data;
-	*out_hwirq = gpiod->base_hwirq + pin;
+	*out_hwirq = pin;
 
 	return 0;
 }
@@ -996,19 +990,21 @@ static int octeon_irq_ciu_map(struct irq_domain *d,
 static int octeon_irq_gpio_map(struct irq_domain *d,
 			       unsigned int virq, irq_hw_number_t hw)
 {
-	unsigned int line = hw >> 6;
-	unsigned int bit = hw & 63;
+	struct octeon_irq_gpio_domain_data *gpiod = d->host_data;
+	unsigned int line, bit;
 
 	if (!octeon_irq_virq_in_range(virq))
 		return -EINVAL;
 
+	hw += gpiod->base_hwirq;
+	line = hw >> 6;
+	bit = hw & 63;
 	if (line > 1 || octeon_irq_ciu_to_irq[line][bit] != 0)
 		return -EINVAL;
 
 	octeon_irq_set_ciu_mapping(virq, line, bit,
 				   octeon_irq_gpio_chip,
 				   octeon_irq_handle_gpio);
-
 	return 0;
 }
 
@@ -1149,6 +1145,7 @@ static void __init octeon_irq_init_ciu(void)
 	struct irq_chip *chip_wd;
 	struct device_node *gpio_node;
 	struct device_node *ciu_node;
+	struct irq_domain *ciu_domain = NULL;
 
 	octeon_irq_init_ciu_percpu();
 	octeon_irq_setup_secondary = octeon_irq_setup_secondary_ciu;
@@ -1177,31 +1174,6 @@ static void __init octeon_irq_init_ciu(void)
 	/* Mips internal */
 	octeon_irq_init_core();
 
-	/* CIU_0 */
-	for (i = 0; i < 16; i++)
-		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WORKQ0, 0, i + 0, chip, handle_level_irq);
-
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX0, 0, 32, chip_mbox, handle_percpu_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX1, 0, 33, chip_mbox, handle_percpu_irq);
-
-	for (i = 0; i < 4; i++)
-		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_PCI_INT0, 0, i + 36, chip, handle_level_irq);
-	for (i = 0; i < 4; i++)
-		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_PCI_MSI0, 0, i + 40, chip, handle_level_irq);
-
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_RML, 0, 46, chip, handle_level_irq);
-	for (i = 0; i < 4; i++)
-		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_TIMER0, 0, i + 52, chip, handle_edge_irq);
-
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB0, 0, 56, chip, handle_level_irq);
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_BOOTDMA, 0, 63, chip, handle_level_irq);
-
-	/* CIU_1 */
-	for (i = 0; i < 16; i++)
-		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WDOG0, 1, i + 0, chip_wd, handle_level_irq);
-
-	octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB1, 1, 17, chip, handle_level_irq);
-
 	gpio_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-gpio");
 	if (gpio_node) {
 		struct octeon_irq_gpio_domain_data *gpiod;
@@ -1219,10 +1191,35 @@ static void __init octeon_irq_init_ciu(void)
 
 	ciu_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-ciu");
 	if (ciu_node) {
-		irq_domain_add_tree(ciu_node, &octeon_irq_domain_ciu_ops, NULL);
+		ciu_domain = irq_domain_add_tree(ciu_node, &octeon_irq_domain_ciu_ops, NULL);
 		of_node_put(ciu_node);
 	} else
-		pr_warn("Cannot find device node for cavium,octeon-3860-ciu.\n");
+		panic("Cannot find device node for cavium,octeon-3860-ciu.");
+
+	/* CIU_0 */
+	for (i = 0; i < 16; i++)
+		octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_WORKQ0, 0, i + 0);
+
+	octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX0, 0, 32, chip_mbox, handle_percpu_irq);
+	octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX1, 0, 33, chip_mbox, handle_percpu_irq);
+
+	for (i = 0; i < 4; i++)
+		octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_PCI_INT0, 0, i + 36);
+	for (i = 0; i < 4; i++)
+		octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_PCI_MSI0, 0, i + 40);
+
+	octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_RML, 0, 46);
+	for (i = 0; i < 4; i++)
+		octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_TIMER0, 0, i + 52);
+
+	octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_USB0, 0, 56);
+	octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_BOOTDMA, 0, 63);
+
+	/* CIU_1 */
+	for (i = 0; i < 16; i++)
+		octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WDOG0, 1, i + 0, chip_wd, handle_level_irq);
+
+	octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_USB1, 1, 17);
 
 	/* Enable the CIU lines */
 	set_c0_status(STATUSF_IP3 | STATUSF_IP2);
diff --git a/arch/mips/cavium-octeon/serial.c b/arch/mips/cavium-octeon/serial.c
index 138b221..569f41b 100644
--- a/arch/mips/cavium-octeon/serial.c
+++ b/arch/mips/cavium-octeon/serial.c
@@ -47,40 +47,40 @@ static int __devinit octeon_serial_probe(struct platform_device *pdev)
 {
 	int irq, res;
 	struct resource *res_mem;
-	struct uart_port port;
+	struct uart_8250_port up;
 
 	/* All adaptors have an irq.  */
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
 		return irq;
 
-	memset(&port, 0, sizeof(port));
+	memset(&up, 0, sizeof(up));
 
-	port.flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
-	port.type = PORT_OCTEON;
-	port.iotype = UPIO_MEM;
-	port.regshift = 3;
-	port.dev = &pdev->dev;
+	up.port.flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
+	up.port.type = PORT_OCTEON;
+	up.port.iotype = UPIO_MEM;
+	up.port.regshift = 3;
+	up.port.dev = &pdev->dev;
 
 	if (octeon_is_simulation())
 		/* Make simulator output fast*/
-		port.uartclk = 115200 * 16;
+		up.port.uartclk = 115200 * 16;
 	else
-		port.uartclk = octeon_get_io_clock_rate();
+		up.port.uartclk = octeon_get_io_clock_rate();
 
-	port.serial_in = octeon_serial_in;
-	port.serial_out = octeon_serial_out;
-	port.irq = irq;
+	up.port.serial_in = octeon_serial_in;
+	up.port.serial_out = octeon_serial_out;
+	up.port.irq = irq;
 
 	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res_mem == NULL) {
 		dev_err(&pdev->dev, "found no memory resource\n");
 		return -ENXIO;
 	}
-	port.mapbase = res_mem->start;
-	port.membase = ioremap(res_mem->start, resource_size(res_mem));
+	up.port.mapbase = res_mem->start;
+	up.port.membase = ioremap(res_mem->start, resource_size(res_mem));
 
-	res = serial8250_register_port(&port);
+	res = serial8250_register_8250_port(&up);
 
 	return res >= 0 ? 0 : res;
 }
diff --git a/arch/mips/configs/ath79_defconfig b/arch/mips/configs/ath79_defconfig
new file mode 100644
index 0000000..ea87d43
--- /dev/null
+++ b/arch/mips/configs/ath79_defconfig
@@ -0,0 +1,111 @@
+CONFIG_ATH79=y
+CONFIG_ATH79_MACH_AP121=y
+CONFIG_ATH79_MACH_AP81=y
+CONFIG_ATH79_MACH_DB120=y
+CONFIG_ATH79_MACH_PB44=y
+CONFIG_ATH79_MACH_UBNT_XM=y
+CONFIG_HZ_100=y
+# CONFIG_SECCOMP is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_GZIP is not set
+CONFIG_RD_LZMA=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_AIO is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_PCI=y
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_IPV6 is not set
+CONFIG_CFG80211=m
+CONFIG_MAC80211=m
+CONFIG_MAC80211_DEBUGFS=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_MTD=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-2
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_M25P80=y
+# CONFIG_M25PXX_USE_FAST_READ is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_PACKET_ENGINE is not set
+CONFIG_ATH_COMMON=m
+CONFIG_ATH9K=m
+CONFIG_ATH9K_AHB=y
+CONFIG_INPUT=m
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO_POLLED=m
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=1
+CONFIG_SERIAL_AR933X=y
+CONFIG_SERIAL_AR933X_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+# CONFIG_I2C_COMPAT is not set
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_GPIO=y
+CONFIG_SPI=y
+CONFIG_SPI_ATH79=y
+CONFIG_SPI_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_PCF857X=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_ATH79_WDT=y
+# CONFIG_VGA_ARB is not set
+# CONFIG_HID is not set
+# CONFIG_USB_HID is not set
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_PROC_PAGE_MONITOR is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_DEBUG_FS=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_FTRACE is not set
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRC_ITU_T=m
diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h
index 3f4c5cb..01cc6ba 100644
--- a/arch/mips/include/asm/atomic.h
+++ b/arch/mips/include/asm/atomic.h
@@ -59,8 +59,8 @@ static __inline__ void atomic_add(int i, atomic_t * v)
 		"	sc	%0, %1					\n"
 		"	beqzl	%0, 1b					\n"
 		"	.set	mips0					\n"
-		: "=&r" (temp), "=m" (v->counter)
-		: "Ir" (i), "m" (v->counter));
+		: "=&r" (temp), "+m" (v->counter)
+		: "Ir" (i));
 	} else if (kernel_uses_llsc) {
 		int temp;
 
@@ -71,8 +71,8 @@ static __inline__ void atomic_add(int i, atomic_t * v)
 			"	addu	%0, %2				\n"
 			"	sc	%0, %1				\n"
 			"	.set	mips0				\n"
-			: "=&r" (temp), "=m" (v->counter)
-			: "Ir" (i), "m" (v->counter));
+			: "=&r" (temp), "+m" (v->counter)
+			: "Ir" (i));
 		} while (unlikely(!temp));
 	} else {
 		unsigned long flags;
@@ -102,8 +102,8 @@ static __inline__ void atomic_sub(int i, atomic_t * v)
 		"	sc	%0, %1					\n"
 		"	beqzl	%0, 1b					\n"
 		"	.set	mips0					\n"
-		: "=&r" (temp), "=m" (v->counter)
-		: "Ir" (i), "m" (v->counter));
+		: "=&r" (temp), "+m" (v->counter)
+		: "Ir" (i));
 	} else if (kernel_uses_llsc) {
 		int temp;
 
@@ -114,8 +114,8 @@ static __inline__ void atomic_sub(int i, atomic_t * v)
 			"	subu	%0, %2				\n"
 			"	sc	%0, %1				\n"
 			"	.set	mips0				\n"
-			: "=&r" (temp), "=m" (v->counter)
-			: "Ir" (i), "m" (v->counter));
+			: "=&r" (temp), "+m" (v->counter)
+			: "Ir" (i));
 		} while (unlikely(!temp));
 	} else {
 		unsigned long flags;
@@ -146,9 +146,8 @@ static __inline__ int atomic_add_return(int i, atomic_t * v)
 		"	beqzl	%0, 1b					\n"
 		"	addu	%0, %1, %3				\n"
 		"	.set	mips0					\n"
-		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
-		: "Ir" (i), "m" (v->counter)
-		: "memory");
+		: "=&r" (result), "=&r" (temp), "+m" (v->counter)
+		: "Ir" (i));
 	} else if (kernel_uses_llsc) {
 		int temp;
 
@@ -159,9 +158,8 @@ static __inline__ int atomic_add_return(int i, atomic_t * v)
 			"	addu	%0, %1, %3			\n"
 			"	sc	%0, %2				\n"
 			"	.set	mips0				\n"
-			: "=&r" (result), "=&r" (temp), "=m" (v->counter)
-			: "Ir" (i), "m" (v->counter)
-			: "memory");
+			: "=&r" (result), "=&r" (temp), "+m" (v->counter)
+			: "Ir" (i));
 		} while (unlikely(!result));
 
 		result = temp + i;
@@ -212,9 +210,8 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v)
 			"	subu	%0, %1, %3			\n"
 			"	sc	%0, %2				\n"
 			"	.set	mips0				\n"
-			: "=&r" (result), "=&r" (temp), "=m" (v->counter)
-			: "Ir" (i), "m" (v->counter)
-			: "memory");
+			: "=&r" (result), "=&r" (temp), "+m" (v->counter)
+			: "Ir" (i));
 		} while (unlikely(!result));
 
 		result = temp - i;
@@ -262,7 +259,7 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
 		"	.set	reorder					\n"
 		"1:							\n"
 		"	.set	mips0					\n"
-		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
+		: "=&r" (result), "=&r" (temp), "+m" (v->counter)
 		: "Ir" (i), "m" (v->counter)
 		: "memory");
 	} else if (kernel_uses_llsc) {
@@ -280,9 +277,8 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
 		"	.set	reorder					\n"
 		"1:							\n"
 		"	.set	mips0					\n"
-		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
-		: "Ir" (i), "m" (v->counter)
-		: "memory");
+		: "=&r" (result), "=&r" (temp), "+m" (v->counter)
+		: "Ir" (i));
 	} else {
 		unsigned long flags;
 
@@ -430,8 +426,8 @@ static __inline__ void atomic64_add(long i, atomic64_t * v)
 		"	scd	%0, %1					\n"
 		"	beqzl	%0, 1b					\n"
 		"	.set	mips0					\n"
-		: "=&r" (temp), "=m" (v->counter)
-		: "Ir" (i), "m" (v->counter));
+		: "=&r" (temp), "+m" (v->counter)
+		: "Ir" (i));
 	} else if (kernel_uses_llsc) {
 		long temp;
 
@@ -442,8 +438,8 @@ static __inline__ void atomic64_add(long i, atomic64_t * v)
 			"	daddu	%0, %2				\n"
 			"	scd	%0, %1				\n"
 			"	.set	mips0				\n"
-			: "=&r" (temp), "=m" (v->counter)
-			: "Ir" (i), "m" (v->counter));
+			: "=&r" (temp), "+m" (v->counter)
+			: "Ir" (i));
 		} while (unlikely(!temp));
 	} else {
 		unsigned long flags;
@@ -473,8 +469,8 @@ static __inline__ void atomic64_sub(long i, atomic64_t * v)
 		"	scd	%0, %1					\n"
 		"	beqzl	%0, 1b					\n"
 		"	.set	mips0					\n"
-		: "=&r" (temp), "=m" (v->counter)
-		: "Ir" (i), "m" (v->counter));
+		: "=&r" (temp), "+m" (v->counter)
+		: "Ir" (i));
 	} else if (kernel_uses_llsc) {
 		long temp;
 
@@ -485,8 +481,8 @@ static __inline__ void atomic64_sub(long i, atomic64_t * v)
 			"	dsubu	%0, %2				\n"
 			"	scd	%0, %1				\n"
 			"	.set	mips0				\n"
-			: "=&r" (temp), "=m" (v->counter)
-			: "Ir" (i), "m" (v->counter));
+			: "=&r" (temp), "+m" (v->counter)
+			: "Ir" (i));
 		} while (unlikely(!temp));
 	} else {
 		unsigned long flags;
@@ -517,9 +513,8 @@ static __inline__ long atomic64_add_return(long i, atomic64_t * v)
 		"	beqzl	%0, 1b					\n"
 		"	daddu	%0, %1, %3				\n"
 		"	.set	mips0					\n"
-		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
-		: "Ir" (i), "m" (v->counter)
-		: "memory");
+		: "=&r" (result), "=&r" (temp), "+m" (v->counter)
+		: "Ir" (i));
 	} else if (kernel_uses_llsc) {
 		long temp;
 
@@ -649,9 +644,8 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
 		"	.set	reorder					\n"
 		"1:							\n"
 		"	.set	mips0					\n"
-		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
-		: "Ir" (i), "m" (v->counter)
-		: "memory");
+		: "=&r" (result), "=&r" (temp), "+m" (v->counter)
+		: "Ir" (i));
 	} else {
 		unsigned long flags;
 
diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h
index ca400f7..55db8e1 100644
--- a/arch/mips/include/asm/cpu-features.h
+++ b/arch/mips/include/asm/cpu-features.h
@@ -252,4 +252,8 @@
 #define cpu_hwrena_impl_bits		0
 #endif
 
+#ifndef cpu_has_perf_cntr_intr_bit
+#define cpu_has_perf_cntr_intr_bit	(cpu_data[0].options & MIPS_CPU_PCI)
+#endif
+
 #endif /* __ASM_CPU_FEATURES_H */
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index f21b7c0..783e598 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -319,6 +319,7 @@ enum cpu_type_enum {
 #define MIPS_CPU_VINT		0x00080000 /* CPU supports MIPSR2 vectored interrupts */
 #define MIPS_CPU_VEIC		0x00100000 /* CPU supports MIPSR2 external interrupt controller mode */
 #define MIPS_CPU_ULRI		0x00200000 /* CPU has ULRI feature */
+#define MIPS_CPU_PCI		0x00400000 /* CPU has Perf Ctr Int indicator */
 
 /*
  * CPU ASE encodings
diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h
index 455c0ac..aec5163 100644
--- a/arch/mips/include/asm/elf.h
+++ b/arch/mips/include/asm/elf.h
@@ -331,6 +331,7 @@ extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *);
 #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs)			\
 	dump_task_fpu(tsk, elf_fpregs)
 
+#define CORE_DUMP_USE_REGSET
 #define ELF_EXEC_PAGESIZE	PAGE_SIZE
 
 /* This yields a mask that user programs can use to figure out what
diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
index 1caa78a..dde5044 100644
--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
@@ -393,7 +393,8 @@
 #define AR71XX_GPIO_REG_FUNC		0x28
 
 #define AR71XX_GPIO_COUNT		16
-#define AR724X_GPIO_COUNT		18
+#define AR7240_GPIO_COUNT		18
+#define AR7241_GPIO_COUNT		20
 #define AR913X_GPIO_COUNT		22
 #define AR933X_GPIO_COUNT		30
 #define AR934X_GPIO_COUNT		23
diff --git a/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h
index 4476fa0..6ddae92 100644
--- a/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h
+++ b/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h
@@ -42,7 +42,6 @@
 #define cpu_has_mips64r1	0
 #define cpu_has_mips64r2	0
 
-#define cpu_has_dsp		0
 #define cpu_has_mipsmt		0
 
 #define cpu_has_64bits		0
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h
index 7d98dbe..c9bae13 100644
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h
@@ -9,6 +9,8 @@ int __init bcm63xx_spi_register(void);
 
 struct bcm63xx_spi_pdata {
 	unsigned int	fifo_size;
+	unsigned int	msg_type_shift;
+	unsigned int	msg_ctl_width;
 	int		bus_num;
 	int		num_chipselect;
 	u32		speed_hz;
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
index 4ccc2a7..61f2a2a 100644
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
@@ -1054,7 +1054,8 @@
 #define SPI_6338_FILL_BYTE		0x07
 #define SPI_6338_MSG_TAIL		0x09
 #define SPI_6338_RX_TAIL		0x0b
-#define SPI_6338_MSG_CTL		0x40
+#define SPI_6338_MSG_CTL		0x40	/* 8-bits register */
+#define SPI_6338_MSG_CTL_WIDTH		8
 #define SPI_6338_MSG_DATA		0x41
 #define SPI_6338_MSG_DATA_SIZE		0x3f
 #define SPI_6338_RX_DATA		0x80
@@ -1070,7 +1071,8 @@
 #define SPI_6348_FILL_BYTE		0x07
 #define SPI_6348_MSG_TAIL		0x09
 #define SPI_6348_RX_TAIL		0x0b
-#define SPI_6348_MSG_CTL		0x40
+#define SPI_6348_MSG_CTL		0x40	/* 8-bits register */
+#define SPI_6348_MSG_CTL_WIDTH		8
 #define SPI_6348_MSG_DATA		0x41
 #define SPI_6348_MSG_DATA_SIZE		0x3f
 #define SPI_6348_RX_DATA		0x80
@@ -1078,6 +1080,7 @@
 
 /* BCM 6358 SPI core */
 #define SPI_6358_MSG_CTL		0x00	/* 16-bits register */
+#define SPI_6358_MSG_CTL_WIDTH		16
 #define SPI_6358_MSG_DATA		0x02
 #define SPI_6358_MSG_DATA_SIZE		0x21e
 #define SPI_6358_RX_DATA		0x400
@@ -1094,6 +1097,7 @@
 
 /* BCM 6358 SPI core */
 #define SPI_6368_MSG_CTL		0x00	/* 16-bits register */
+#define SPI_6368_MSG_CTL_WIDTH		16
 #define SPI_6368_MSG_DATA		0x02
 #define SPI_6368_MSG_DATA_SIZE		0x21e
 #define SPI_6368_RX_DATA		0x400
@@ -1115,7 +1119,10 @@
 #define SPI_HD_W			0x01
 #define SPI_HD_R			0x02
 #define SPI_BYTE_CNT_SHIFT		0
-#define SPI_MSG_TYPE_SHIFT		14
+#define SPI_6338_MSG_TYPE_SHIFT		6
+#define SPI_6348_MSG_TYPE_SHIFT		6
+#define SPI_6358_MSG_TYPE_SHIFT		14
+#define SPI_6368_MSG_TYPE_SHIFT		14
 
 /* Command */
 #define SPI_CMD_NOOP			0x00
diff --git a/arch/mips/include/asm/mach-cavium-octeon/irq.h b/arch/mips/include/asm/mach-cavium-octeon/irq.h
index 4189920..c22a307 100644
--- a/arch/mips/include/asm/mach-cavium-octeon/irq.h
+++ b/arch/mips/include/asm/mach-cavium-octeon/irq.h
@@ -21,14 +21,10 @@ enum octeon_irq {
 	OCTEON_IRQ_TIMER,
 /* sources in CIU_INTX_EN0 */
 	OCTEON_IRQ_WORKQ0,
-	OCTEON_IRQ_GPIO0 = OCTEON_IRQ_WORKQ0 + 16,
-	OCTEON_IRQ_WDOG0 = OCTEON_IRQ_GPIO0 + 16,
+	OCTEON_IRQ_WDOG0 = OCTEON_IRQ_WORKQ0 + 16,
 	OCTEON_IRQ_WDOG15 = OCTEON_IRQ_WDOG0 + 15,
 	OCTEON_IRQ_MBOX0 = OCTEON_IRQ_WDOG0 + 16,
 	OCTEON_IRQ_MBOX1,
-	OCTEON_IRQ_UART0,
-	OCTEON_IRQ_UART1,
-	OCTEON_IRQ_UART2,
 	OCTEON_IRQ_PCI_INT0,
 	OCTEON_IRQ_PCI_INT1,
 	OCTEON_IRQ_PCI_INT2,
@@ -38,8 +34,6 @@ enum octeon_irq {
 	OCTEON_IRQ_PCI_MSI2,
 	OCTEON_IRQ_PCI_MSI3,
 
-	OCTEON_IRQ_TWSI,
-	OCTEON_IRQ_TWSI2,
 	OCTEON_IRQ_RML,
 	OCTEON_IRQ_TIMER0,
 	OCTEON_IRQ_TIMER1,
@@ -47,8 +41,6 @@ enum octeon_irq {
 	OCTEON_IRQ_TIMER3,
 	OCTEON_IRQ_USB0,
 	OCTEON_IRQ_USB1,
-	OCTEON_IRQ_MII0,
-	OCTEON_IRQ_MII1,
 	OCTEON_IRQ_BOOTDMA,
 #ifndef CONFIG_PCI_MSI
 	OCTEON_IRQ_LAST = 127
diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
index 6a2df70..1de5d82 100644
--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
@@ -87,5 +87,8 @@ extern __iomem void *ltq_cgu_membase;
 extern void ltq_pmu_enable(unsigned int module);
 extern void ltq_pmu_disable(unsigned int module);
 
+/* allow pci driver to set the pci clk delay */
+void ltq_pci_set_delay(u8 delay);
+
 #endif /* CONFIG_SOC_TYPE_XWAY */
 #endif /* _LTQ_XWAY_H__ */
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
index 7f87d82..2b83c36 100644
--- a/arch/mips/include/asm/mipsregs.h
+++ b/arch/mips/include/asm/mipsregs.h
@@ -458,6 +458,8 @@
 #define  CAUSEF_IP7		(_ULCAST_(1)   << 15)
 #define  CAUSEB_IV		23
 #define  CAUSEF_IV		(_ULCAST_(1)   << 23)
+#define  CAUSEB_PCI		26
+#define  CAUSEF_PCI		(_ULCAST_(1)   << 26)
 #define  CAUSEB_CE		28
 #define  CAUSEF_CE		(_ULCAST_(3)   << 28)
 #define  CAUSEB_TI		30
diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h
index 7531ecd..26137da 100644
--- a/arch/mips/include/asm/module.h
+++ b/arch/mips/include/asm/module.h
@@ -10,6 +10,7 @@ struct mod_arch_specific {
 	struct list_head dbe_list;
 	const struct exception_table_entry *dbe_start;
 	const struct exception_table_entry *dbe_end;
+	struct mips_hi16 *r_mips_hi16_list;
 };
 
 typedef uint8_t Elf64_Byte;		/* Type for a 8-bit quantity.  */
@@ -34,11 +35,14 @@ typedef struct {
 } Elf64_Mips_Rela;
 
 #ifdef CONFIG_32BIT
-
 #define Elf_Shdr	Elf32_Shdr
 #define Elf_Sym		Elf32_Sym
 #define Elf_Ehdr	Elf32_Ehdr
 #define Elf_Addr	Elf32_Addr
+#define Elf_Rel		Elf32_Rel
+#define Elf_Rela	Elf32_Rela
+#define ELF_R_TYPE(X)	ELF32_R_TYPE(X)
+#define ELF_R_SYM(X)	ELF32_R_SYM(X)
 
 #define Elf_Mips_Rel	Elf32_Rel
 #define Elf_Mips_Rela	Elf32_Rela
@@ -49,11 +53,14 @@ typedef struct {
 #endif
 
 #ifdef CONFIG_64BIT
-
 #define Elf_Shdr	Elf64_Shdr
 #define Elf_Sym		Elf64_Sym
 #define Elf_Ehdr	Elf64_Ehdr
 #define Elf_Addr	Elf64_Addr
+#define Elf_Rel		Elf64_Rel
+#define Elf_Rela	Elf64_Rela
+#define ELF_R_TYPE(X)	ELF64_R_TYPE(X)
+#define ELF_R_SYM(X)	ELF64_R_SYM(X)
 
 #define Elf_Mips_Rel	Elf64_Mips_Rel
 #define Elf_Mips_Rela	Elf64_Mips_Rela
diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h
index 4b7f525..8db2098 100644
--- a/arch/mips/include/asm/ptrace.h
+++ b/arch/mips/include/asm/ptrace.h
@@ -153,7 +153,7 @@ static inline long regs_return_value(struct pt_regs *regs)
 #define instruction_pointer(regs) ((regs)->cp0_epc)
 #define profile_pc(regs) instruction_pointer(regs)
 
-extern asmlinkage void syscall_trace_enter(struct pt_regs *regs);
+extern asmlinkage long syscall_trace_enter(struct pt_regs *regs);
 extern asmlinkage void syscall_trace_leave(struct pt_regs *regs);
 
 extern void die(const char *, struct pt_regs *) __noreturn;
@@ -164,6 +164,19 @@ static inline void die_if_kernel(const char *str, struct pt_regs *regs)
 		die(str, regs);
 }
 
-#endif
+/* Helpers for working with the user stack pointer */
+
+static inline unsigned long user_stack_pointer(struct pt_regs *regs)
+{
+	return regs->regs[29];
+}
+
+static inline void user_stack_pointer_set(struct pt_regs *regs,
+	unsigned long val)
+{
+	regs->regs[29] = val;
+}
+
+#endif /* __KERNEL__ */
 
 #endif /* _ASM_PTRACE_H */
diff --git a/arch/mips/include/asm/r4k-timer.h b/arch/mips/include/asm/r4k-timer.h
index a37d12b..afe9e0e 100644
--- a/arch/mips/include/asm/r4k-timer.h
+++ b/arch/mips/include/asm/r4k-timer.h
@@ -12,16 +12,16 @@
 
 #ifdef CONFIG_SYNC_R4K
 
-extern void synchronise_count_master(void);
-extern void synchronise_count_slave(void);
+extern void synchronise_count_master(int cpu);
+extern void synchronise_count_slave(int cpu);
 
 #else
 
-static inline void synchronise_count_master(void)
+static inline void synchronise_count_master(int cpu)
 {
 }
 
-static inline void synchronise_count_slave(void)
+static inline void synchronise_count_slave(int cpu)
 {
 }
 
diff --git a/arch/mips/include/asm/siginfo.h b/arch/mips/include/asm/siginfo.h
index 20ebeb8..5fad4f6 100644
--- a/arch/mips/include/asm/siginfo.h
+++ b/arch/mips/include/asm/siginfo.h
@@ -32,6 +32,8 @@ struct siginfo;
 #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
 #endif
 
+#define __ARCH_SIGSYS
+
 #include <asm-generic/siginfo.h>
 
 typedef struct siginfo {
@@ -96,6 +98,13 @@ typedef struct siginfo {
 			__ARCH_SI_BAND_T _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
 			int _fd;
 		} _sigpoll;
+
+		/* SIGSYS */
+		struct {
+			void __user *_call_addr; /* calling user insn */
+			int _syscall;   /* triggering system call number */
+			unsigned int _arch;     /* AUDIT_ARCH_* of syscall */
+		} _sigsys;
 	} _sifields;
 } siginfo_t;
 
diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h
new file mode 100644
index 0000000..b80936d
--- /dev/null
+++ b/arch/mips/include/asm/syscall.h
@@ -0,0 +1,183 @@
+/*
+ * Access to user system call parameters and results
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * See asm-generic/syscall.h for descriptions of what we must do here.
+ *
+ * Copyright (C) 2012 Ralf Baechle <ralf@linux-mips.org>
+ */
+
+#ifndef __ASM_MIPS_SYSCALL_H
+#define __ASM_MIPS_SYSCALL_H
+
+#include <linux/audit.h>
+#include <linux/elf-em.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <asm/ptrace.h>
+
+static inline long syscall_get_nr(struct task_struct *task,
+				  struct pt_regs *regs)
+{
+	return regs->regs[2];
+}
+
+static inline void syscall_rollback(struct task_struct *task,
+				    struct pt_regs *regs)
+{
+	regs->regs[7] = regs->regs[26];
+	regs->regs[2] = regs->regs[0];
+}
+
+static inline long syscall_get_error(struct task_struct *task,
+				     struct pt_regs *regs)
+{
+	return regs->regs[7] ? regs->regs[2] : 0;
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+					    struct pt_regs *regs)
+{
+	return regs->regs[2];
+}
+
+static inline void syscall_set_return_value(struct task_struct *task,
+					    struct pt_regs *regs,
+					    int error, long val)
+{
+	if (error) {
+		regs->regs[2] = -error;
+		regs->regs[7] = 1;
+	} else {
+		regs->regs[2] = val;
+		regs->regs[7] = 0;
+	}
+}
+
+static inline unsigned long mips_get_syscall_arg(unsigned long *arg,
+	struct task_struct *task, struct pt_regs *regs, unsigned int n)
+{
+	unsigned long usp = regs->regs[29];
+
+	switch (n) {
+	case 0: case 1: case 2: case 3:
+		*arg = regs->regs[4 + n];
+
+		return 0;
+
+#ifdef CONFIG_32BIT
+	case 4: case 5: case 6: case 7:
+		return get_user(*arg, (int *)usp + 4 * n);
+#endif
+
+#ifdef CONFIG_64BIT
+	case 4: case 5: case 6: case 7:
+#ifdef CONFIG_MIPS32_O32
+		if (test_thread_flag(TIF_32BIT_REGS))
+			return get_user(*arg, (int *)usp + 4 * n);
+		else
+#endif
+			*arg = regs->regs[4 + n];
+
+		return 0;
+#endif
+
+	default:
+		BUG();
+	}
+}
+
+static inline int mips_set_syscall_arg(struct task_struct *task,
+	struct pt_regs *regs, unsigned int n, unsigned long val)
+{
+	unsigned long usp = regs->regs[29];
+
+	switch (n) {
+	case 0: case 1: case 2: case 3:
+
+#ifdef CONFIG_32BIT
+	case 4: case 5: case 6: case 7:
+		return put_user(val, (long *)usp + (4 * n));
+#endif
+
+#ifdef CONFIG_64BIT
+	case 4: case 5: case 6: case 7:
+#ifdef CONFIG_MIPS32_O32
+		if (test_thread_flag(TIF_32BIT_REGS))
+			return put_user(val, (long *)usp + (4 * n));
+		else
+#endif
+			regs->regs[4 + n] = val;
+
+		return 0;
+#endif
+
+	default:
+		BUG();
+	}
+}
+
+static inline void syscall_get_arguments(struct task_struct *task,
+					 struct pt_regs *regs,
+					 unsigned int i, unsigned int n,
+					 unsigned long *args)
+{
+	unsigned long arg;
+	int ret;
+
+	while (n--)
+		ret |= mips_get_syscall_arg(&arg, task, regs, i++);
+
+	/*
+	 * No way to communicate an error because this is a void function.
+	 */
+#if 0
+	return ret;
+#endif
+}
+
+static inline void syscall_set_arguments(struct task_struct *task,
+					 struct pt_regs *regs,
+					 unsigned int i, unsigned int n,
+					 const unsigned long *args)
+{
+	int ret;
+
+	while (n--)
+		ret |= mips_set_syscall_arg(task, regs, i++, *args++);
+
+	/*
+	 * No way to communicate an error because this is a void function.
+	 */
+#if 0
+	return ret;
+#endif
+}
+
+extern const unsigned long sys_call_table[];
+extern const unsigned long sys32_call_table[];
+extern const unsigned long sysn32_call_table[];
+
+static inline int __syscall_get_arch(void)
+{
+	int arch = EM_MIPS;
+#ifdef CONFIG_64BIT
+	arch |=  __AUDIT_ARCH_64BIT;
+#endif
+#if defined(__LITTLE_ENDIAN)
+	arch |=  __AUDIT_ARCH_LE;
+#endif
+	return arch;
+}
+
+static inline int syscall_get_arch(struct task_struct *task,
+				   struct pt_regs *regs)
+{
+	return __syscall_get_arch();
+}
+
+#endif	/* __ASM_MIPS_SYSCALL_H */
diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h
index ca97e0e..7ab4d51 100644
--- a/arch/mips/include/asm/thread_info.h
+++ b/arch/mips/include/asm/thread_info.h
@@ -103,7 +103,6 @@ register struct thread_info *__current_thread_info __asm__("$28");
 #define TIF_NOTIFY_RESUME	5	/* callback before returning to user */
 #define TIF_RESTORE_SIGMASK	9	/* restore signal mask in do_signal() */
 #define TIF_USEDFPU		16	/* FPU was used by this task this quantum (SMP) */
-#define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		18	/* is terminating due to OOM killer */
 #define TIF_FIXADE		20	/* Fix address errors in software */
 #define TIF_LOGADE		21	/* Log address errors to syslog */
@@ -111,6 +110,7 @@ register struct thread_info *__current_thread_info __asm__("$28");
 #define TIF_32BIT_ADDR		23	/* 32-bit address space (o32/n32) */
 #define TIF_FPUBOUND		24	/* thread bound to FPU-full CPU set */
 #define TIF_LOAD_WATCH		25	/* If set, load watch registers */
+#define TIF_SYSCALL_TRACEPOINT	26	/* syscall tracepoint instrumentation */
 #define TIF_SYSCALL_TRACE	31	/* syscall trace active */
 
 #ifdef CONFIG_MIPS32_O32
@@ -125,24 +125,28 @@ register struct thread_info *__current_thread_info __asm__("$28");
 #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP		(1<<TIF_SECCOMP)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_USEDFPU		(1<<TIF_USEDFPU)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 #define _TIF_FIXADE		(1<<TIF_FIXADE)
 #define _TIF_LOGADE		(1<<TIF_LOGADE)
 #define _TIF_32BIT_REGS		(1<<TIF_32BIT_REGS)
 #define _TIF_32BIT_ADDR		(1<<TIF_32BIT_ADDR)
 #define _TIF_FPUBOUND		(1<<TIF_FPUBOUND)
 #define _TIF_LOAD_WATCH		(1<<TIF_LOAD_WATCH)
+#define _TIF_SYSCALL_TRACEPOINT	(1<<TIF_SYSCALL_TRACEPOINT)
+
+/* work to do in syscall_trace_enter() */
+#define _TIF_WORK_SYSCALL_ENTRY						\
+	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP |	\
+	 _TIF_SYSCALL_TRACEPOINT)
 
 /* work to do in syscall_trace_leave() */
 #define _TIF_WORK_SYSCALL_EXIT	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
 
 /* work to do on interrupt/exception return */
-#define _TIF_WORK_MASK		(0x0000ffef &				\
-					~(_TIF_SECCOMP | _TIF_SYSCALL_AUDIT))
+#define _TIF_WORK_MASK		\
+	(_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_NOTIFY_RESUME)
 /* work to do on any return to u-space */
-#define _TIF_ALLWORK_MASK	(0x8000ffff & ~_TIF_SECCOMP)
+#define _TIF_ALLWORK_MASK	(_TIF_WORK_MASK | _TIF_WORK_SYSCALL_EXIT)
 
 #endif /* __KERNEL__ */
 
diff --git a/arch/mips/include/asm/unistd.h b/arch/mips/include/asm/unistd.h
index bebbde0..6b01e67 100644
--- a/arch/mips/include/asm/unistd.h
+++ b/arch/mips/include/asm/unistd.h
@@ -1086,5 +1086,16 @@
  */
 #define cond_syscall(x) asm(".weak\t" #x "\n" #x "\t=\tsys_ni_syscall")
 
+#ifdef CONFIG_32BIT
+# define NR_syscalls	(__NR_O32_Linux + __NR_O32_Linux_syscalls)
+#endif /* CONFIG_32BIT */
+#ifdef CONFIG_64BIT
+# ifdef CONFIG_MIPS32_N32
+#  define NR_syscalls	(__NR_N32_Linux + __NR_N32_Linux_syscalls)
+#else
+#  define NR_syscalls	(__NR_64_Linux + __NR_64_Linux_syscalls)
+# endif
+#endif /* CONFIG_64BIT */
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_UNISTD_H */
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index fdaf65e..74316dc 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_SYNC_R4K)		+= sync-r4k.o
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-$(CONFIG_MODULES)		+= mips_ksyms.o module.o
 
+obj-$(CONFIG_FTRACE_SYSCALLS)	+= ftrace.o
 obj-$(CONFIG_FUNCTION_TRACER)	+= mcount.o ftrace.o
 
 obj-$(CONFIG_CPU_LOONGSON2)	+= r4k_fpu.o r4k_switch.o
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 1b51046..7ae3895 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -1186,8 +1186,11 @@ __cpuinit void cpu_probe(void)
 		}
 	}
 
-	if (cpu_has_mips_r2)
+	if (cpu_has_mips_r2) {
 		c->srsets = ((read_c0_srsctl() >> 26) & 0x0f) + 1;
+		/* R2 has Performance Counter Interrupt indicator */
+		c->options |= MIPS_CPU_PCI;
+	}
 	else
 		c->srsets = 1;
 
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index 37acfa0..a6c1332 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -77,7 +77,7 @@ FEXPORT(syscall_exit)
 	and	t0, a2, t0
 	bnez	t0, syscall_exit_work
 
-FEXPORT(restore_all)			# restore full frame
+restore_all:				# restore full frame
 #ifdef CONFIG_MIPS_MT_SMTC
 #ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP
 /* Re-arm any temporarily masked interrupts not explicitly "acked" */
@@ -117,7 +117,7 @@ FEXPORT(restore_all)			# restore full frame
 	RESTORE_TEMP
 	RESTORE_AT
 	RESTORE_STATIC
-FEXPORT(restore_partial)		# restore partial frame
+restore_partial:		# restore partial frame
 #ifdef CONFIG_TRACE_IRQFLAGS
 	SAVE_STATIC
 	SAVE_AT
@@ -164,9 +164,18 @@ work_notifysig:				# deal with pending signals and
 	jal	do_notify_resume	# a2 already loaded
 	j	resume_userspace
 
-FEXPORT(syscall_exit_work_partial)
+FEXPORT(syscall_exit_partial)
+	local_irq_disable		# make sure need_resched doesn't
+					# change between and return
+	LONG_L	a2, TI_FLAGS($28)	# current->work
+	li	t0, _TIF_ALLWORK_MASK
+	and	t0, a2
+	beqz	t0, restore_partial
 	SAVE_STATIC
 syscall_exit_work:
+	LONG_L	t0, PT_STATUS(sp)		# returning to kernel mode?
+	andi	t0, t0, KU_USER
+	beqz	t0, resume_kernel
 	li	t0, _TIF_WORK_SYSCALL_EXIT
 	and	t0, a2			# a2 is preloaded with TI_FLAGS
 	beqz	t0, work_pending	# trace bit set?
diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c
index 6a2d758..dfc7441 100644
--- a/arch/mips/kernel/ftrace.c
+++ b/arch/mips/kernel/ftrace.c
@@ -11,11 +11,14 @@
 #include <linux/uaccess.h>
 #include <linux/init.h>
 #include <linux/ftrace.h>
+#include <linux/syscalls.h>
 
 #include <asm/asm.h>
 #include <asm/asm-offsets.h>
 #include <asm/cacheflush.h>
+#include <asm/syscall.h>
 #include <asm/uasm.h>
+#include <asm/unistd.h>
 
 #include <asm-generic/sections.h>
 
@@ -326,3 +329,33 @@ out:
 	WARN_ON(1);
 }
 #endif	/* CONFIG_FUNCTION_GRAPH_TRACER */
+
+#ifdef CONFIG_FTRACE_SYSCALLS
+
+#ifdef CONFIG_32BIT
+unsigned long __init arch_syscall_addr(int nr)
+{
+	return (unsigned long)sys_call_table[nr - __NR_O32_Linux];
+}
+#endif
+
+#ifdef CONFIG_64BIT
+
+unsigned long __init arch_syscall_addr(int nr)
+{
+#ifdef CONFIG_MIPS32_N32
+	if (nr >= __NR_N32_Linux && nr <= __NR_N32_Linux + __NR_N32_Linux_syscalls)
+		return (unsigned long)sysn32_call_table[nr - __NR_N32_Linux];
+#endif
+	if (nr >= __NR_64_Linux  && nr <= __NR_64_Linux + __NR_64_Linux_syscalls)
+		return (unsigned long)sys_call_table[nr - __NR_64_Linux];
+#ifdef CONFIG_MIPS32_O32
+	if (nr >= __NR_O32_Linux && nr <= __NR_O32_Linux + __NR_O32_Linux_syscalls)
+		return (unsigned long)sys32_call_table[nr - __NR_O32_Linux];
+#endif
+
+	return (unsigned long) &sys_ni_syscall;
+}
+#endif
+
+#endif /* CONFIG_FTRACE_SYSCALLS */
diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c
index f4546e9..23817a6 100644
--- a/arch/mips/kernel/kgdb.c
+++ b/arch/mips/kernel/kgdb.c
@@ -283,6 +283,15 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
 	struct pt_regs *regs = args->regs;
 	int trap = (regs->cp0_cause & 0x7c) >> 2;
 
+#ifdef CONFIG_KPROBES
+	/*
+	 * Return immediately if the kprobes fault notifier has set
+	 * DIE_PAGE_FAULT.
+	 */
+	if (cmd == DIE_PAGE_FAULT)
+		return NOTIFY_DONE;
+#endif /* CONFIG_KPROBES */
+
 	/* Userspace events, ignore. */
 	if (user_mode(regs))
 		return NOTIFY_DONE;
diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c
index a5066b1..9f102cf 100644
--- a/arch/mips/kernel/module.c
+++ b/arch/mips/kernel/module.c
@@ -39,8 +39,6 @@ struct mips_hi16 {
 	Elf_Addr value;
 };
 
-static struct mips_hi16 *mips_hi16_list;
-
 static LIST_HEAD(dbe_list);
 static DEFINE_SPINLOCK(dbe_lock);
 
@@ -128,8 +126,8 @@ static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v)
 
 	n->addr = (Elf_Addr *)location;
 	n->value = v;
-	n->next = mips_hi16_list;
-	mips_hi16_list = n;
+	n->next = me->arch.r_mips_hi16_list;
+	me->arch.r_mips_hi16_list = n;
 
 	return 0;
 }
@@ -142,18 +140,28 @@ static int apply_r_mips_hi16_rela(struct module *me, u32 *location, Elf_Addr v)
 	return 0;
 }
 
+static void free_relocation_chain(struct mips_hi16 *l)
+{
+	struct mips_hi16 *next;
+
+	while (l) {
+		next = l->next;
+		kfree(l);
+		l = next;
+	}
+}
+
 static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
 {
 	unsigned long insnlo = *location;
+	struct mips_hi16 *l;
 	Elf_Addr val, vallo;
 
 	/* Sign extend the addend we extract from the lo insn.  */
 	vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
 
-	if (mips_hi16_list != NULL) {
-		struct mips_hi16 *l;
-
-		l = mips_hi16_list;
+	if (me->arch.r_mips_hi16_list != NULL) {
+		l = me->arch.r_mips_hi16_list;
 		while (l != NULL) {
 			struct mips_hi16 *next;
 			unsigned long insn;
@@ -188,7 +196,7 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
 			l = next;
 		}
 
-		mips_hi16_list = NULL;
+		me->arch.r_mips_hi16_list = NULL;
 	}
 
 	/*
@@ -201,6 +209,9 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
 	return 0;
 
 out_danger:
+	free_relocation_chain(l);
+	me->arch.r_mips_hi16_list = NULL;
+
 	pr_err("module %s: dangerous R_MIPS_LO16 REL relocation\n", me->name);
 
 	return -ENOEXEC;
@@ -273,6 +284,7 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
 	pr_debug("Applying relocate section %u to %u\n", relsec,
 	       sechdrs[relsec].sh_info);
 
+	me->arch.r_mips_hi16_list = NULL;
 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
 		/* This is where to make the change */
 		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
@@ -296,9 +308,23 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
 			return res;
 	}
 
+	/*
+	 * Normally the hi16 list should be deallocated at this point.  A
+	 * malformed binary however could contain a series of R_MIPS_HI16
+	 * relocations not followed by a R_MIPS_LO16 relocation.  In that
+	 * case, free up the list and return an error.
+	 */
+	if (me->arch.r_mips_hi16_list) {
+		free_relocation_chain(me->arch.r_mips_hi16_list);
+		me->arch.r_mips_hi16_list = NULL;
+
+		return -ENOEXEC;
+	}
+
 	return 0;
 }
 
+#ifdef CONFIG_MODULES_USE_ELF_RELA
 int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
 		       unsigned int symindex, unsigned int relsec,
 		       struct module *me)
@@ -338,6 +364,7 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
 
 	return 0;
 }
+#endif
 
 /* Given an address, look for it in the module exception tables. */
 const struct exception_table_entry *search_module_dbetables(unsigned long addr)
diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c
index 2f28d3b..a9b995d 100644
--- a/arch/mips/kernel/perf_event_mipsxx.c
+++ b/arch/mips/kernel/perf_event_mipsxx.c
@@ -28,6 +28,8 @@
 #include <asm/time.h> /* For perf_irq */
 
 #define MIPS_MAX_HWEVENTS 4
+#define MIPS_TCS_PER_COUNTER 2
+#define MIPS_CPUID_TO_COUNTER_MASK (MIPS_TCS_PER_COUNTER - 1)
 
 struct cpu_hw_events {
 	/* Array of events on this cpu. */
@@ -78,7 +80,6 @@ struct mips_perf_event {
 static struct mips_perf_event raw_event;
 static DEFINE_MUTEX(raw_event_mutex);
 
-#define UNSUPPORTED_PERF_EVENT_ID 0xffffffff
 #define C(x) PERF_COUNT_HW_CACHE_##x
 
 struct mips_pmu {
@@ -109,13 +110,20 @@ static struct mips_pmu mipspmu;
 #define M_PERFCTL_INTERRUPT_ENABLE	(1      <<  4)
 #define M_PERFCTL_EVENT(event)		(((event) & 0x3ff)  << 5)
 #define M_PERFCTL_VPEID(vpe)		((vpe)    << 16)
+
+#ifdef CONFIG_CPU_BMIPS5000
+#define M_PERFCTL_MT_EN(filter)		0
+#else /* !CONFIG_CPU_BMIPS5000 */
 #define M_PERFCTL_MT_EN(filter)		((filter) << 20)
+#endif /* CONFIG_CPU_BMIPS5000 */
+
 #define    M_TC_EN_ALL			M_PERFCTL_MT_EN(0)
 #define    M_TC_EN_VPE			M_PERFCTL_MT_EN(1)
 #define    M_TC_EN_TC			M_PERFCTL_MT_EN(2)
 #define M_PERFCTL_TCID(tcid)		((tcid)   << 22)
 #define M_PERFCTL_WIDE			(1      << 30)
 #define M_PERFCTL_MORE			(1      << 31)
+#define M_PERFCTL_TC			(1      << 30)
 
 #define M_PERFCTL_COUNT_EVENT_WHENEVER	(M_PERFCTL_EXL |		\
 					M_PERFCTL_KERNEL |		\
@@ -131,21 +139,21 @@ static struct mips_pmu mipspmu;
 #define M_PERFCTL_EVENT_MASK		0xfe0
 
 
-#ifdef CONFIG_MIPS_MT_SMP
+#ifdef CONFIG_MIPS_PERF_SHARED_TC_COUNTERS
 static int cpu_has_mipsmt_pertccounters;
 
 static DEFINE_RWLOCK(pmuint_rwlock);
 
+#if defined(CONFIG_CPU_BMIPS5000)
+#define vpe_id()	(cpu_has_mipsmt_pertccounters ? \
+			 0 : (smp_processor_id() & MIPS_CPUID_TO_COUNTER_MASK))
+#else
 /*
  * FIXME: For VSMP, vpe_id() is redefined for Perf-events, because
  * cpu_data[cpuid].vpe_id reports 0 for _both_ CPUs.
  */
-#if defined(CONFIG_HW_PERF_EVENTS)
-#define vpe_id()	(cpu_has_mipsmt_pertccounters ? \
-			0 : smp_processor_id())
-#else
 #define vpe_id()	(cpu_has_mipsmt_pertccounters ? \
-			0 : cpu_data[smp_processor_id()].vpe_id)
+			 0 : smp_processor_id())
 #endif
 
 /* Copied from op_model_mipsxx.c */
@@ -162,10 +170,10 @@ static unsigned int counters_total_to_per_cpu(unsigned int counters)
 	return counters >> vpe_shift();
 }
 
-#else /* !CONFIG_MIPS_MT_SMP */
+#else /* !CONFIG_MIPS_PERF_SHARED_TC_COUNTERS */
 #define vpe_id()	0
 
-#endif /* CONFIG_MIPS_MT_SMP */
+#endif /* CONFIG_MIPS_PERF_SHARED_TC_COUNTERS */
 
 static void resume_local_counters(void);
 static void pause_local_counters(void);
@@ -340,6 +348,11 @@ static void mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx)
 		(evt->config_base & M_PERFCTL_CONFIG_MASK) |
 		/* Make sure interrupt enabled. */
 		M_PERFCTL_INTERRUPT_ENABLE;
+	if (IS_ENABLED(CONFIG_CPU_BMIPS5000))
+		/* enable the counter for the calling thread */
+		cpuc->saved_ctrl[idx] |=
+			(1 << (12 + vpe_id())) | M_PERFCTL_TC;
+
 	/*
 	 * We do not actually let the counter run. Leave it until start().
 	 */
@@ -509,7 +522,7 @@ static void mipspmu_read(struct perf_event *event)
 
 static void mipspmu_enable(struct pmu *pmu)
 {
-#ifdef CONFIG_MIPS_MT_SMP
+#ifdef CONFIG_MIPS_PERF_SHARED_TC_COUNTERS
 	write_unlock(&pmuint_rwlock);
 #endif
 	resume_local_counters();
@@ -529,7 +542,7 @@ static void mipspmu_enable(struct pmu *pmu)
 static void mipspmu_disable(struct pmu *pmu)
 {
 	pause_local_counters();
-#ifdef CONFIG_MIPS_MT_SMP
+#ifdef CONFIG_MIPS_PERF_SHARED_TC_COUNTERS
 	write_lock(&pmuint_rwlock);
 #endif
 }
@@ -664,13 +677,10 @@ static unsigned int mipspmu_perf_event_encode(const struct mips_perf_event *pev)
 
 static const struct mips_perf_event *mipspmu_map_general_event(int idx)
 {
-	const struct mips_perf_event *pev;
-
-	pev = ((*mipspmu.general_event_map)[idx].event_id ==
-		UNSUPPORTED_PERF_EVENT_ID ? ERR_PTR(-EOPNOTSUPP) :
-		&(*mipspmu.general_event_map)[idx]);
 
-	return pev;
+	if ((*mipspmu.general_event_map)[idx].cntr_mask == 0)
+		return ERR_PTR(-EOPNOTSUPP);
+	return &(*mipspmu.general_event_map)[idx];
 }
 
 static const struct mips_perf_event *mipspmu_map_cache_event(u64 config)
@@ -695,7 +705,7 @@ static const struct mips_perf_event *mipspmu_map_cache_event(u64 config)
 					[cache_op]
 					[cache_result]);
 
-	if (pev->event_id == UNSUPPORTED_PERF_EVENT_ID)
+	if (pev->cntr_mask == 0)
 		return ERR_PTR(-EOPNOTSUPP);
 
 	return pev;
@@ -800,11 +810,8 @@ static const struct mips_perf_event mipsxxcore_event_map
 				[PERF_COUNT_HW_MAX] = {
 	[PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN | CNTR_ODD, P },
 	[PERF_COUNT_HW_INSTRUCTIONS] = { 0x01, CNTR_EVEN | CNTR_ODD, T },
-	[PERF_COUNT_HW_CACHE_REFERENCES] = { UNSUPPORTED_PERF_EVENT_ID },
-	[PERF_COUNT_HW_CACHE_MISSES] = { UNSUPPORTED_PERF_EVENT_ID },
 	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = { 0x02, CNTR_EVEN, T },
 	[PERF_COUNT_HW_BRANCH_MISSES] = { 0x02, CNTR_ODD, T },
-	[PERF_COUNT_HW_BUS_CYCLES] = { UNSUPPORTED_PERF_EVENT_ID },
 };
 
 /* 74K core has different branch event code. */
@@ -812,11 +819,8 @@ static const struct mips_perf_event mipsxx74Kcore_event_map
 				[PERF_COUNT_HW_MAX] = {
 	[PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN | CNTR_ODD, P },
 	[PERF_COUNT_HW_INSTRUCTIONS] = { 0x01, CNTR_EVEN | CNTR_ODD, T },
-	[PERF_COUNT_HW_CACHE_REFERENCES] = { UNSUPPORTED_PERF_EVENT_ID },
-	[PERF_COUNT_HW_CACHE_MISSES] = { UNSUPPORTED_PERF_EVENT_ID },
 	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = { 0x27, CNTR_EVEN, T },
 	[PERF_COUNT_HW_BRANCH_MISSES] = { 0x27, CNTR_ODD, T },
-	[PERF_COUNT_HW_BUS_CYCLES] = { UNSUPPORTED_PERF_EVENT_ID },
 };
 
 static const struct mips_perf_event octeon_event_map[PERF_COUNT_HW_MAX] = {
@@ -829,6 +833,13 @@ static const struct mips_perf_event octeon_event_map[PERF_COUNT_HW_MAX] = {
 	[PERF_COUNT_HW_BUS_CYCLES] = { 0x25, CNTR_ALL },
 };
 
+static const struct mips_perf_event bmips5000_event_map
+				[PERF_COUNT_HW_MAX] = {
+	[PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN | CNTR_ODD, T },
+	[PERF_COUNT_HW_INSTRUCTIONS] = { 0x01, CNTR_EVEN | CNTR_ODD, T },
+	[PERF_COUNT_HW_BRANCH_MISSES] = { 0x02, CNTR_ODD, T },
+};
+
 /* 24K/34K/1004K cores can share the same cache event map. */
 static const struct mips_perf_event mipsxxcore_cache_map
 				[PERF_COUNT_HW_CACHE_MAX]
@@ -849,10 +860,6 @@ static const struct mips_perf_event mipsxxcore_cache_map
 		[C(RESULT_ACCESS)]	= { 0x0a, CNTR_EVEN, T },
 		[C(RESULT_MISS)]	= { 0x0b, CNTR_EVEN | CNTR_ODD, T },
 	},
-	[C(OP_PREFETCH)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
 },
 [C(L1I)] = {
 	[C(OP_READ)] = {
@@ -869,7 +876,6 @@ static const struct mips_perf_event mipsxxcore_cache_map
 		 * Note that MIPS has only "hit" events countable for
 		 * the prefetch operation.
 		 */
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
 	},
 },
 [C(LL)] = {
@@ -881,10 +887,6 @@ static const struct mips_perf_event mipsxxcore_cache_map
 		[C(RESULT_ACCESS)]	= { 0x15, CNTR_ODD, P },
 		[C(RESULT_MISS)]	= { 0x16, CNTR_EVEN, P },
 	},
-	[C(OP_PREFETCH)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
 },
 [C(DTLB)] = {
 	[C(OP_READ)] = {
@@ -895,10 +897,6 @@ static const struct mips_perf_event mipsxxcore_cache_map
 		[C(RESULT_ACCESS)]	= { 0x06, CNTR_EVEN, T },
 		[C(RESULT_MISS)]	= { 0x06, CNTR_ODD, T },
 	},
-	[C(OP_PREFETCH)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
 },
 [C(ITLB)] = {
 	[C(OP_READ)] = {
@@ -909,10 +907,6 @@ static const struct mips_perf_event mipsxxcore_cache_map
 		[C(RESULT_ACCESS)]	= { 0x05, CNTR_EVEN, T },
 		[C(RESULT_MISS)]	= { 0x05, CNTR_ODD, T },
 	},
-	[C(OP_PREFETCH)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
 },
 [C(BPU)] = {
 	/* Using the same code for *HW_BRANCH* */
@@ -924,24 +918,6 @@ static const struct mips_perf_event mipsxxcore_cache_map
 		[C(RESULT_ACCESS)]	= { 0x02, CNTR_EVEN, T },
 		[C(RESULT_MISS)]	= { 0x02, CNTR_ODD, T },
 	},
-	[C(OP_PREFETCH)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
-},
-[C(NODE)] = {
-	[C(OP_READ)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
-	[C(OP_WRITE)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
-	[C(OP_PREFETCH)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
 },
 };
 
@@ -965,10 +941,6 @@ static const struct mips_perf_event mipsxx74Kcore_cache_map
 		[C(RESULT_ACCESS)]	= { 0x17, CNTR_ODD, T },
 		[C(RESULT_MISS)]	= { 0x18, CNTR_ODD, T },
 	},
-	[C(OP_PREFETCH)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
 },
 [C(L1I)] = {
 	[C(OP_READ)] = {
@@ -985,7 +957,6 @@ static const struct mips_perf_event mipsxx74Kcore_cache_map
 		 * Note that MIPS has only "hit" events countable for
 		 * the prefetch operation.
 		 */
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
 	},
 },
 [C(LL)] = {
@@ -997,25 +968,6 @@ static const struct mips_perf_event mipsxx74Kcore_cache_map
 		[C(RESULT_ACCESS)]	= { 0x1c, CNTR_ODD, P },
 		[C(RESULT_MISS)]	= { 0x1d, CNTR_EVEN | CNTR_ODD, P },
 	},
-	[C(OP_PREFETCH)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
-},
-[C(DTLB)] = {
-	/* 74K core does not have specific DTLB events. */
-	[C(OP_READ)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
-	[C(OP_WRITE)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
-	[C(OP_PREFETCH)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
 },
 [C(ITLB)] = {
 	[C(OP_READ)] = {
@@ -1026,10 +978,6 @@ static const struct mips_perf_event mipsxx74Kcore_cache_map
 		[C(RESULT_ACCESS)]	= { 0x04, CNTR_EVEN, T },
 		[C(RESULT_MISS)]	= { 0x04, CNTR_ODD, T },
 	},
-	[C(OP_PREFETCH)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
 },
 [C(BPU)] = {
 	/* Using the same code for *HW_BRANCH* */
@@ -1041,23 +989,64 @@ static const struct mips_perf_event mipsxx74Kcore_cache_map
 		[C(RESULT_ACCESS)]	= { 0x27, CNTR_EVEN, T },
 		[C(RESULT_MISS)]	= { 0x27, CNTR_ODD, T },
 	},
-	[C(OP_PREFETCH)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+},
+};
+
+/* BMIPS5000 */
+static const struct mips_perf_event bmips5000_cache_map
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+[C(L1D)] = {
+	/*
+	 * Like some other architectures (e.g. ARM), the performance
+	 * counters don't differentiate between read and write
+	 * accesses/misses, so this isn't strictly correct, but it's the
+	 * best we can do. Writes and reads get combined.
+	 */
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { 12, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 12, CNTR_ODD, T },
+	},
+	[C(OP_WRITE)] = {
+		[C(RESULT_ACCESS)]	= { 12, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 12, CNTR_ODD, T },
 	},
 },
-[C(NODE)] = {
+[C(L1I)] = {
 	[C(OP_READ)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+		[C(RESULT_ACCESS)]	= { 10, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 10, CNTR_ODD, T },
 	},
 	[C(OP_WRITE)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+		[C(RESULT_ACCESS)]	= { 10, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 10, CNTR_ODD, T },
 	},
 	[C(OP_PREFETCH)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+		[C(RESULT_ACCESS)]	= { 23, CNTR_EVEN, T },
+		/*
+		 * Note that MIPS has only "hit" events countable for
+		 * the prefetch operation.
+		 */
+	},
+},
+[C(LL)] = {
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { 28, CNTR_EVEN, P },
+		[C(RESULT_MISS)]	= { 28, CNTR_ODD, P },
+	},
+	[C(OP_WRITE)] = {
+		[C(RESULT_ACCESS)]	= { 28, CNTR_EVEN, P },
+		[C(RESULT_MISS)]	= { 28, CNTR_ODD, P },
+	},
+},
+[C(BPU)] = {
+	/* Using the same code for *HW_BRANCH* */
+	[C(OP_READ)] = {
+		[C(RESULT_MISS)]	= { 0x02, CNTR_ODD, T },
+	},
+	[C(OP_WRITE)] = {
+		[C(RESULT_MISS)]	= { 0x02, CNTR_ODD, T },
 	},
 },
 };
@@ -1074,39 +1063,14 @@ static const struct mips_perf_event octeon_cache_map
 	},
 	[C(OP_WRITE)] = {
 		[C(RESULT_ACCESS)]	= { 0x30, CNTR_ALL },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
-	[C(OP_PREFETCH)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
 	},
 },
 [C(L1I)] = {
 	[C(OP_READ)] = {
 		[C(RESULT_ACCESS)]	= { 0x18, CNTR_ALL },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
-	[C(OP_WRITE)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
 	},
 	[C(OP_PREFETCH)] = {
 		[C(RESULT_ACCESS)]	= { 0x19, CNTR_ALL },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
-},
-[C(LL)] = {
-	[C(OP_READ)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
-	[C(OP_WRITE)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
-	[C(OP_PREFETCH)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
 	},
 },
 [C(DTLB)] = {
@@ -1115,46 +1079,16 @@ static const struct mips_perf_event octeon_cache_map
 	 * read and write.
 	 */
 	[C(OP_READ)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
 		[C(RESULT_MISS)]	= { 0x35, CNTR_ALL },
 	},
 	[C(OP_WRITE)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
 		[C(RESULT_MISS)]	= { 0x35, CNTR_ALL },
 	},
-	[C(OP_PREFETCH)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
 },
 [C(ITLB)] = {
 	[C(OP_READ)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
 		[C(RESULT_MISS)]	= { 0x37, CNTR_ALL },
 	},
-	[C(OP_WRITE)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
-	[C(OP_PREFETCH)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
-},
-[C(BPU)] = {
-	/* Using the same code for *HW_BRANCH* */
-	[C(OP_READ)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
-	[C(OP_WRITE)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
-	[C(OP_PREFETCH)] = {
-		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
-	},
 },
 };
 
@@ -1304,7 +1238,7 @@ static int mipsxx_pmu_handle_shared_irq(void)
 	int handled = IRQ_NONE;
 	struct pt_regs *regs;
 
-	if (cpu_has_mips_r2 && !(read_c0_cause() & (1 << 26)))
+	if (cpu_has_perf_cntr_intr_bit && !(read_c0_cause() & CAUSEF_PCI))
 		return handled;
 	/*
 	 * First we pause the local counters, so that when we are locked
@@ -1314,7 +1248,7 @@ static int mipsxx_pmu_handle_shared_irq(void)
 	 * See also mipsxx_pmu_start().
 	 */
 	pause_local_counters();
-#ifdef CONFIG_MIPS_MT_SMP
+#ifdef CONFIG_MIPS_PERF_SHARED_TC_COUNTERS
 	read_lock(&pmuint_rwlock);
 #endif
 
@@ -1346,7 +1280,7 @@ static int mipsxx_pmu_handle_shared_irq(void)
 	if (handled == IRQ_HANDLED)
 		irq_work_run();
 
-#ifdef CONFIG_MIPS_MT_SMP
+#ifdef CONFIG_MIPS_PERF_SHARED_TC_COUNTERS
 	read_unlock(&pmuint_rwlock);
 #endif
 	resume_local_counters();
@@ -1391,6 +1325,11 @@ static irqreturn_t mipsxx_pmu_handle_irq(int irq, void *dev)
 #define IS_RANGE_V_1004K_EVENT(r)	((r) == 47)
 #endif
 
+/* BMIPS5000 */
+#define IS_BOTH_COUNTERS_BMIPS5000_EVENT(b)				\
+	((b) == 0 || (b) == 1)
+
+
 /*
  * User can use 0-255 raw events, where 0-127 for the events of even
  * counters, and 128-255 for odd counters. Note that bit 7 is used to
@@ -1461,6 +1400,12 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config)
 			raw_event.range = T;
 #endif
 		break;
+	case CPU_BMIPS5000:
+		if (IS_BOTH_COUNTERS_BMIPS5000_EVENT(base_id))
+			raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
+		else
+			raw_event.cntr_mask =
+				raw_id > 127 ? CNTR_ODD : CNTR_EVEN;
 	}
 
 	return &raw_event;
@@ -1513,7 +1458,7 @@ init_hw_perf_events(void)
 		return -ENODEV;
 	}
 
-#ifdef CONFIG_MIPS_MT_SMP
+#ifdef CONFIG_MIPS_PERF_SHARED_TC_COUNTERS
 	cpu_has_mipsmt_pertccounters = read_c0_config7() & (1<<19);
 	if (!cpu_has_mipsmt_pertccounters)
 		counters = counters_total_to_per_cpu(counters);
@@ -1572,6 +1517,11 @@ init_hw_perf_events(void)
 		mipspmu.cache_event_map = &octeon_cache_map;
 		mipspmu.map_raw_event = octeon_pmu_map_raw_event;
 		break;
+	case CPU_BMIPS5000:
+		mipspmu.name = "BMIPS5000";
+		mipspmu.general_event_map = &bmips5000_event_map;
+		mipspmu.cache_event_map = &bmips5000_cache_map;
+		break;
 	default:
 		pr_cont("Either hardware does not support performance "
 			"counters, or not yet implemented.\n");
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 4812c6d..a37bc88 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -15,17 +15,23 @@
  * binaries.
  */
 #include <linux/compiler.h>
+#include <linux/elf.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
+#include <linux/regset.h>
 #include <linux/smp.h>
 #include <linux/user.h>
 #include <linux/security.h>
+#include <linux/tracehook.h>
 #include <linux/audit.h>
 #include <linux/seccomp.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/syscalls.h>
+
 #include <asm/byteorder.h>
 #include <asm/cpu.h>
 #include <asm/dsp.h>
@@ -36,6 +42,7 @@
 #include <asm/page.h>
 #include <asm/uaccess.h>
 #include <asm/bootinfo.h>
+#include <asm/syscall.h>
 #include <asm/reg.h>
 
 /*
@@ -254,6 +261,133 @@ int ptrace_set_watch_regs(struct task_struct *child,
 	return 0;
 }
 
+/* regset get/set implementations */
+
+static int gpr_get(struct task_struct *target,
+		   const struct user_regset *regset,
+		   unsigned int pos, unsigned int count,
+		   void *kbuf, void __user *ubuf)
+{
+	struct pt_regs *regs = task_pt_regs(target);
+
+	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				   regs, 0, sizeof(*regs));
+}
+
+static int gpr_set(struct task_struct *target,
+		   const struct user_regset *regset,
+		   unsigned int pos, unsigned int count,
+		   const void *kbuf, const void __user *ubuf)
+{
+	struct pt_regs newregs;
+	int ret;
+
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				 &newregs,
+				 0, sizeof(newregs));
+	if (ret)
+		return ret;
+
+	*task_pt_regs(target) = newregs;
+
+	return 0;
+}
+
+static int fpr_get(struct task_struct *target,
+		   const struct user_regset *regset,
+		   unsigned int pos, unsigned int count,
+		   void *kbuf, void __user *ubuf)
+{
+	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				   &target->thread.fpu,
+				   0, sizeof(elf_fpregset_t));
+	/* XXX fcr31  */
+}
+
+static int fpr_set(struct task_struct *target,
+		   const struct user_regset *regset,
+		   unsigned int pos, unsigned int count,
+		   const void *kbuf, const void __user *ubuf)
+{
+	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				  &target->thread.fpu,
+				  0, sizeof(elf_fpregset_t));
+	/* XXX fcr31  */
+}
+
+enum mips_regset {
+	REGSET_GPR,
+	REGSET_FPR,
+};
+
+static const struct user_regset mips_regsets[] = {
+	[REGSET_GPR] = {
+		.core_note_type	= NT_PRSTATUS,
+		.n		= ELF_NGREG,
+		.size		= sizeof(unsigned int),
+		.align		= sizeof(unsigned int),
+		.get		= gpr_get,
+		.set		= gpr_set,
+	},
+	[REGSET_FPR] = {
+		.core_note_type	= NT_PRFPREG,
+		.n		= ELF_NFPREG,
+		.size		= sizeof(elf_fpreg_t),
+		.align		= sizeof(elf_fpreg_t),
+		.get		= fpr_get,
+		.set		= fpr_set,
+	},
+};
+
+static const struct user_regset_view user_mips_view = {
+	.name		= "mips",
+	.e_machine	= ELF_ARCH,
+	.ei_osabi	= ELF_OSABI,
+	.regsets	= mips_regsets,
+	.n		= ARRAY_SIZE(mips_regsets),
+};
+
+static const struct user_regset mips64_regsets[] = {
+	[REGSET_GPR] = {
+		.core_note_type	= NT_PRSTATUS,
+		.n		= ELF_NGREG,
+		.size		= sizeof(unsigned long),
+		.align		= sizeof(unsigned long),
+		.get		= gpr_get,
+		.set		= gpr_set,
+	},
+	[REGSET_FPR] = {
+		.core_note_type	= NT_PRFPREG,
+		.n		= ELF_NFPREG,
+		.size		= sizeof(elf_fpreg_t),
+		.align		= sizeof(elf_fpreg_t),
+		.get		= fpr_get,
+		.set		= fpr_set,
+	},
+};
+
+static const struct user_regset_view user_mips64_view = {
+	.name		= "mips",
+	.e_machine	= ELF_ARCH,
+	.ei_osabi	= ELF_OSABI,
+	.regsets	= mips64_regsets,
+	.n		= ARRAY_SIZE(mips_regsets),
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+#ifdef CONFIG_32BIT
+	return &user_mips_view;
+#endif
+
+#ifdef CONFIG_MIPS32_O32
+		if (test_thread_flag(TIF_32BIT_REGS))
+			return &user_mips_view;
+#endif
+
+	return &user_mips64_view;
+}
+
 long arch_ptrace(struct task_struct *child, long request,
 		 unsigned long addr, unsigned long data)
 {
@@ -516,52 +650,35 @@ long arch_ptrace(struct task_struct *child, long request,
 	return ret;
 }
 
-static inline int audit_arch(void)
-{
-	int arch = EM_MIPS;
-#ifdef CONFIG_64BIT
-	arch |=  __AUDIT_ARCH_64BIT;
-#endif
-#if defined(__LITTLE_ENDIAN)
-	arch |=  __AUDIT_ARCH_LE;
-#endif
-	return arch;
-}
-
 /*
  * Notification of system call entry/exit
  * - triggered by current->work.syscall_trace
  */
-asmlinkage void syscall_trace_enter(struct pt_regs *regs)
+asmlinkage long syscall_trace_enter(struct pt_regs *regs)
 {
-	/* do the secure computing check first */
-	secure_computing_strict(regs->regs[2]);
+	long ret = 0;
 
-	if (!(current->ptrace & PT_PTRACED))
+	/* do the secure computing check first */
+	if (secure_computing(regs->regs[2])) {
+		/* seccomp failures shouldn't expose any additional code. */
+		ret = -1;
 		goto out;
+	}
 
-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
-		goto out;
+	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
+	    tracehook_report_syscall_entry(regs))
+		ret = -1;
 
-	/* The 0x80 provides a way for the tracing parent to distinguish
-	   between a syscall stop and SIGTRAP delivery */
-	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ?
-	                         0x80 : 0));
-
-	/*
-	 * this isn't the same as continuing with a signal, but it will do
-	 * for normal use.  strace only continues with a signal if the
-	 * stopping signal is not SIGTRAP.  -brl
-	 */
-	if (current->exit_code) {
-		send_sig(current->exit_code, current, 1);
-		current->exit_code = 0;
-	}
+	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
+		trace_sys_enter(regs, regs->regs[2]);
 
-out:
-	audit_syscall_entry(audit_arch(), regs->regs[2],
+	audit_syscall_entry(__syscall_get_arch(),
+			    regs->regs[2],
 			    regs->regs[4], regs->regs[5],
 			    regs->regs[6], regs->regs[7]);
+
+out:
+	return ret ?: regs->regs[2];
 }
 
 /*
@@ -572,24 +689,9 @@ asmlinkage void syscall_trace_leave(struct pt_regs *regs)
 {
 	audit_syscall_exit(regs);
 
-	if (!(current->ptrace & PT_PTRACED))
-		return;
-
-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
-		return;
-
-	/* The 0x80 provides a way for the tracing parent to distinguish
-	   between a syscall stop and SIGTRAP delivery */
-	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ?
-	                         0x80 : 0));
-
-	/*
-	 * this isn't the same as continuing with a signal, but it will do
-	 * for normal use.  strace only continues with a signal if the
-	 * stopping signal is not SIGTRAP.  -brl
-	 */
-	if (current->exit_code) {
-		send_sig(current->exit_code, current, 1);
-		current->exit_code = 0;
-	}
+	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
+		trace_sys_exit(regs, regs->regs[2]);
+
+	if (test_thread_flag(TIF_SYSCALL_TRACE))
+		tracehook_report_syscall_exit(regs, 0);
 }
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index a632bc1..def3a2b 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -32,29 +32,64 @@ NESTED(handle_sys, PT_SIZE, sp)
 	STI
 	.set	at
 
-	lw	t1, PT_EPC(sp)		# skip syscall on return
+	/*
+	 * We intentionally keep the kernel stack a little below the top of
+	 * userspace so we don't have to do a slower byte accurate check here.
+	 */
+	lw	t0, PT_R29(sp)		# get user stack pointer
+	lw	t1, TI_ADDR_LIMIT($28)
+	addu	t2, t0, 16
+	addu	t3, t0, 32
+	or	t2, t3
+	and	t2, t1
+	bltz	t2, bad_stack		# -> sp is bad
 
-	subu	v0, v0, __NR_O32_Linux	# check syscall number
-	sltiu	t0, v0, __NR_O32_Linux_syscalls + 1
-	addiu	t1, 4			# skip to next instruction
-	sw	t1, PT_EPC(sp)
-	beqz	t0, illegal_syscall
+	/*
+	 * Ok, copy the args from the luser stack to the kernel stack.
+	 * t3 is the precomputed number of instruction bytes needed to
+	 * load or store arguments 6-8.
+	 */
 
-	sll	t0, v0, 3
-	la	t1, sys_call_table
-	addu	t1, t0
-	lw	t2, (t1)		# syscall routine
-	lw	t3, 4(t1)		# >= 0 if we need stack arguments
-	beqz	t2, illegal_syscall
+	.set    push
+	.set    noreorder
+	.set	nomacro
 
-	sw	a3, PT_R26(sp)		# save a3 for syscall restarting
-	bgez	t3, stackargs
+1:	lw	t5, 16(t0)		# argument #5 from usp
+4:	lw	t6, 20(t0)		# argument #6 from usp
+3:	lw	t7, 24(t0)		# argument #7 from usp
+2:	lw	t8, 28(t0)		# argument #8 from usp
+
+	sw	t5, 16(sp)		# argument #5 to ksp
+	sw	t6, 20(sp)		# argument #6 to ksp
+	sw	t7, 24(sp)		# argument #7 to ksp
+	sw	t8, 28(sp)		# argument #8 to ksp
+
+	.set	pop
+
+	.section __ex_table,"a"
+	PTR	1b, bad_stack
+	PTR	2b, bad_stack
+	PTR	3b, bad_stack
+	PTR	4b, bad_stack
+	.previous
+
+	lw	t0, PT_EPC(sp)		# skip syscall on return
+	addiu	t0, 4			# skip to next instruction
+	sw	t0, PT_EPC(sp)
 
-stack_done:
 	lw	t0, TI_FLAGS($28)	# syscall tracing enabled?
-	li	t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+	li	t1, _TIF_WORK_SYSCALL_ENTRY
 	and	t0, t1
-	bnez	t0, syscall_trace_entry	# -> yes
+	bnez	t0, syscall_trace_entry
+
+syscall_call:
+	subu	v0, v0, __NR_O32_Linux	# check syscall number
+	sltiu	t0, v0, __NR_O32_Linux_syscalls + 1
+	beqz	t0, illegal_syscall
+
+	sll	t0, v0, 2
+	lw	t2, sys_call_table(t0)
+	sw	a3, PT_R26(sp)		# save a3 for syscall restarting
 
 	jalr	t2			# Do The Real Thing (TM)
 
@@ -69,101 +104,26 @@ stack_done:
 1:	sw	v0, PT_R2(sp)		# result
 
 o32_syscall_exit:
-	local_irq_disable		# make sure need_resched and
-					# signals dont change between
-					# sampling and return
-	lw	a2, TI_FLAGS($28)	# current->work
-	li	t0, _TIF_ALLWORK_MASK
-	and	t0, a2
-	bnez	t0, o32_syscall_exit_work
-
-	j	restore_partial
-
-o32_syscall_exit_work:
-	j	syscall_exit_work_partial
+	j	syscall_exit_partial
 
 /* ------------------------------------------------------------------------ */
 
 syscall_trace_entry:
 	SAVE_STATIC
-	move	s0, t2
 	move	a0, sp
 	jal	syscall_trace_enter
 
-	move	t0, s0
-	RESTORE_STATIC
-	lw	a0, PT_R4(sp)		# Restore argument registers
+	lw	a0, PT_R4(sp)			# Restore argument registers
 	lw	a1, PT_R5(sp)
 	lw	a2, PT_R6(sp)
 	lw	a3, PT_R7(sp)
-	jalr	t0
-
-	li	t0, -EMAXERRNO - 1	# error?
-	sltu	t0, t0, v0
-	sw	t0, PT_R7(sp)		# set error flag
-	beqz	t0, 1f
-
-	lw	t1, PT_R2(sp)		# syscall number
-	negu	v0			# error
-	sw	t1, PT_R0(sp)		# save it for syscall restarting
-1:	sw	v0, PT_R2(sp)		# result
 
-	j	syscall_exit
+	bgez	v0, syscall_call
+	j	o32_syscall_exit
 
 /* ------------------------------------------------------------------------ */
 
 	/*
-	 * More than four arguments.  Try to deal with it by copying the
-	 * stack arguments from the user stack to the kernel stack.
-	 * This Sucks (TM).
-	 */
-stackargs:
-	lw	t0, PT_R29(sp)		# get old user stack pointer
-
-	/*
-	 * We intentionally keep the kernel stack a little below the top of
-	 * userspace so we don't have to do a slower byte accurate check here.
-	 */
-	lw	t5, TI_ADDR_LIMIT($28)
-	addu	t4, t0, 32
-	and	t5, t4
-	bltz	t5, bad_stack		# -> sp is bad
-
-	/* Ok, copy the args from the luser stack to the kernel stack.
-	 * t3 is the precomputed number of instruction bytes needed to
-	 * load or store arguments 6-8.
-	 */
-
-	la	t1, 5f			# load up to 3 arguments
-	subu	t1, t3
-1:	lw	t5, 16(t0)		# argument #5 from usp
-	.set    push
-	.set    noreorder
-	.set	nomacro
-	jr	t1
-	 addiu	t1, 6f - 5f
-
-2:	lw	t8, 28(t0)		# argument #8 from usp
-3:	lw	t7, 24(t0)		# argument #7 from usp
-4:	lw	t6, 20(t0)		# argument #6 from usp
-5:	jr	t1
-	 sw	t5, 16(sp)		# argument #5 to ksp
-
-	sw	t8, 28(sp)		# argument #8 to ksp
-	sw	t7, 24(sp)		# argument #7 to ksp
-	sw	t6, 20(sp)		# argument #6 to ksp
-6:	j	stack_done		# go back
-	 nop
-	.set	pop
-
-	.section __ex_table,"a"
-	PTR	1b,bad_stack
-	PTR	2b,bad_stack
-	PTR	3b,bad_stack
-	PTR	4b,bad_stack
-	.previous
-
-	/*
 	 * The stackpointer for a call with more than 4 arguments is bad.
 	 * We probably should handle this case a bit more drastic.
 	 */
@@ -185,18 +145,20 @@ illegal_syscall:
 	j	o32_syscall_exit
 	END(handle_sys)
 
-	LEAF(sys_syscall)
-	subu	t0, a0, __NR_O32_Linux	# check syscall number
+LEAF(sys_syscall)
+	subu	t0, a0, __NR_O32_Linux		# check syscall number
 	sltiu	v0, t0, __NR_O32_Linux_syscalls + 1
-	beqz	t0, einval		# do not recurse
-	sll	t1, t0, 3
+	beqz	t0, einval			# do not recurse
+	sll	t1, t0, 2
 	beqz	v0, einval
 	lw	t2, sys_call_table(t1)		# syscall routine
 
-	/* Some syscalls like execve get their arguments from struct pt_regs
-	   and claim zero arguments in the syscall table. Thus we have to
-	   assume the worst case and shuffle around all potential arguments.
-	   If you want performance, don't use indirect syscalls. */
+	/*
+	 * Some syscalls like execve get their arguments from struct pt_regs
+	 * and claim zero arguments in the syscall table. Thus we have to
+	 * assume the worst case and shuffle around all potential arguments.
+	 * If you want performance, don't use indirect syscalls.
+	 */
 
 	move	a0, a1				# shift argument registers
 	move	a1, a2
@@ -220,260 +182,248 @@ einval:	li	v0, -ENOSYS
 	jr	ra
 	END(sys_syscall)
 
-	.macro	fifty ptr, nargs, from=1, to=50
-	sys	\ptr		\nargs
-	.if	\to-\from
-	fifty	\ptr,\nargs,"(\from+1)",\to
-	.endif
-	.endm
-
-	.macro	mille ptr, nargs, from=1, to=20
-	fifty	\ptr,\nargs
-	.if	\to-\from
-	mille	\ptr,\nargs,"(\from+1)",\to
-	.endif
-	.endm
-
-	.macro	syscalltable
-	sys	sys_syscall		8	/* 4000 */
-	sys	sys_exit		1
-	sys	sys_fork		0
-	sys	sys_read		3
-	sys	sys_write		3
-	sys	sys_open		3	/* 4005 */
-	sys	sys_close		1
-	sys	sys_waitpid		3
-	sys	sys_creat		2
-	sys	sys_link		2
-	sys	sys_unlink		1	/* 4010 */
-	sys	sys_execve		0
-	sys	sys_chdir		1
-	sys	sys_time		1
-	sys	sys_mknod		3
-	sys	sys_chmod		2	/* 4015 */
-	sys	sys_lchown		3
-	sys	sys_ni_syscall		0
-	sys	sys_ni_syscall		0	/* was sys_stat */
-	sys	sys_lseek		3
-	sys	sys_getpid		0	/* 4020 */
-	sys	sys_mount		5
-	sys	sys_oldumount		1
-	sys	sys_setuid		1
-	sys	sys_getuid		0
-	sys	sys_stime		1	/* 4025 */
-	sys	sys_ptrace		4
-	sys	sys_alarm		1
-	sys	sys_ni_syscall		0	/* was sys_fstat */
-	sys	sys_pause		0
-	sys	sys_utime		2	/* 4030 */
-	sys	sys_ni_syscall		0
-	sys	sys_ni_syscall		0
-	sys	sys_access		2
-	sys	sys_nice		1
-	sys	sys_ni_syscall		0	/* 4035 */
-	sys	sys_sync		0
-	sys	sys_kill		2
-	sys	sys_rename		2
-	sys	sys_mkdir		2
-	sys	sys_rmdir		1	/* 4040 */
-	sys	sys_dup			1
-	sys	sysm_pipe		0
-	sys	sys_times		1
-	sys	sys_ni_syscall		0
-	sys	sys_brk			1	/* 4045 */
-	sys	sys_setgid		1
-	sys	sys_getgid		0
-	sys	sys_ni_syscall		0	/* was signal(2) */
-	sys	sys_geteuid		0
-	sys	sys_getegid		0	/* 4050 */
-	sys	sys_acct		1
-	sys	sys_umount		2
-	sys	sys_ni_syscall		0
-	sys	sys_ioctl		3
-	sys	sys_fcntl		3	/* 4055 */
-	sys	sys_ni_syscall		2
-	sys	sys_setpgid		2
-	sys	sys_ni_syscall		0
-	sys	sys_olduname		1
-	sys	sys_umask		1	/* 4060 */
-	sys	sys_chroot		1
-	sys	sys_ustat		2
-	sys	sys_dup2		2
-	sys	sys_getppid		0
-	sys	sys_getpgrp		0	/* 4065 */
-	sys	sys_setsid		0
-	sys	sys_sigaction		3
-	sys	sys_sgetmask		0
-	sys	sys_ssetmask		1
-	sys	sys_setreuid		2	/* 4070 */
-	sys	sys_setregid		2
-	sys	sys_sigsuspend		0
-	sys	sys_sigpending		1
-	sys	sys_sethostname		2
-	sys	sys_setrlimit		2	/* 4075 */
-	sys	sys_getrlimit		2
-	sys	sys_getrusage		2
-	sys	sys_gettimeofday	2
-	sys	sys_settimeofday	2
-	sys	sys_getgroups		2	/* 4080 */
-	sys	sys_setgroups		2
-	sys	sys_ni_syscall		0	/* old_select */
-	sys	sys_symlink		2
-	sys	sys_ni_syscall		0	/* was sys_lstat */
-	sys	sys_readlink		3	/* 4085 */
-	sys	sys_uselib		1
-	sys	sys_swapon		2
-	sys	sys_reboot		3
-	sys	sys_old_readdir		3
-	sys	sys_mips_mmap		6	/* 4090 */
-	sys	sys_munmap		2
-	sys	sys_truncate		2
-	sys	sys_ftruncate		2
-	sys	sys_fchmod		2
-	sys	sys_fchown		3	/* 4095 */
-	sys	sys_getpriority		2
-	sys	sys_setpriority		3
-	sys	sys_ni_syscall		0
-	sys	sys_statfs		2
-	sys	sys_fstatfs		2	/* 4100 */
-	sys	sys_ni_syscall		0	/* was ioperm(2) */
-	sys	sys_socketcall		2
-	sys	sys_syslog		3
-	sys	sys_setitimer		3
-	sys	sys_getitimer		2	/* 4105 */
-	sys	sys_newstat		2
-	sys	sys_newlstat		2
-	sys	sys_newfstat		2
-	sys	sys_uname		1
-	sys	sys_ni_syscall		0	/* 4110 was iopl(2) */
-	sys	sys_vhangup		0
-	sys	sys_ni_syscall		0	/* was sys_idle() */
-	sys	sys_ni_syscall		0	/* was sys_vm86 */
-	sys	sys_wait4		4
-	sys	sys_swapoff		1	/* 4115 */
-	sys	sys_sysinfo		1
-	sys	sys_ipc			6
-	sys	sys_fsync		1
-	sys	sys_sigreturn		0
-	sys	sys_clone		0	/* 4120 */
-	sys	sys_setdomainname	2
-	sys	sys_newuname		1
-	sys	sys_ni_syscall		0	/* sys_modify_ldt */
-	sys	sys_adjtimex		1
-	sys	sys_mprotect		3	/* 4125 */
-	sys	sys_sigprocmask		3
-	sys	sys_ni_syscall		0	/* was create_module */
-	sys	sys_init_module		5
-	sys	sys_delete_module	1
-	sys	sys_ni_syscall		0	/* 4130	was get_kernel_syms */
-	sys	sys_quotactl		4
-	sys	sys_getpgid		1
-	sys	sys_fchdir		1
-	sys	sys_bdflush		2
-	sys	sys_sysfs		3	/* 4135 */
-	sys	sys_personality		1
-	sys	sys_ni_syscall		0	/* for afs_syscall */
-	sys	sys_setfsuid		1
-	sys	sys_setfsgid		1
-	sys	sys_llseek		5	/* 4140 */
-	sys	sys_getdents		3
-	sys	sys_select		5
-	sys	sys_flock		2
-	sys	sys_msync		3
-	sys	sys_readv		3	/* 4145 */
-	sys	sys_writev		3
-	sys	sys_cacheflush		3
-	sys	sys_cachectl		3
-	sys	sys_sysmips		4
-	sys	sys_ni_syscall		0	/* 4150 */
-	sys	sys_getsid		1
-	sys	sys_fdatasync		1
-	sys	sys_sysctl		1
-	sys	sys_mlock		2
-	sys	sys_munlock		2	/* 4155 */
-	sys	sys_mlockall		1
-	sys	sys_munlockall		0
-	sys	sys_sched_setparam	2
-	sys	sys_sched_getparam	2
-	sys	sys_sched_setscheduler	3	/* 4160 */
-	sys	sys_sched_getscheduler	1
-	sys	sys_sched_yield		0
-	sys	sys_sched_get_priority_max 1
-	sys	sys_sched_get_priority_min 1
-	sys	sys_sched_rr_get_interval 2	/* 4165 */
-	sys	sys_nanosleep,		2
-	sys	sys_mremap,		5
-	sys	sys_accept		3
-	sys	sys_bind		3
-	sys	sys_connect		3	/* 4170 */
-	sys	sys_getpeername		3
-	sys	sys_getsockname		3
-	sys	sys_getsockopt		5
-	sys	sys_listen		2
-	sys	sys_recv		4	/* 4175 */
-	sys	sys_recvfrom		6
-	sys	sys_recvmsg		3
-	sys	sys_send		4
-	sys	sys_sendmsg		3
-	sys	sys_sendto		6	/* 4180 */
-	sys	sys_setsockopt		5
-	sys	sys_shutdown		2
-	sys	sys_socket		3
-	sys	sys_socketpair		4
-	sys	sys_setresuid		3	/* 4185 */
-	sys	sys_getresuid		3
-	sys	sys_ni_syscall		0	/* was sys_query_module */
-	sys	sys_poll		3
-	sys	sys_ni_syscall		0	/* was nfsservctl */
-	sys	sys_setresgid		3	/* 4190 */
-	sys	sys_getresgid		3
-	sys	sys_prctl		5
-	sys	sys_rt_sigreturn	0
-	sys	sys_rt_sigaction	4
-	sys	sys_rt_sigprocmask	4	/* 4195 */
-	sys	sys_rt_sigpending	2
-	sys	sys_rt_sigtimedwait	4
-	sys	sys_rt_sigqueueinfo	3
-	sys	sys_rt_sigsuspend	0
-	sys	sys_pread64		6	/* 4200 */
-	sys	sys_pwrite64		6
-	sys	sys_chown		3
-	sys	sys_getcwd		2
-	sys	sys_capget		2
-	sys	sys_capset		2	/* 4205 */
-	sys	sys_sigaltstack		0
-	sys	sys_sendfile		4
-	sys	sys_ni_syscall		0
-	sys	sys_ni_syscall		0
-	sys	sys_mips_mmap2		6	/* 4210 */
-	sys	sys_truncate64		4
-	sys	sys_ftruncate64		4
-	sys	sys_stat64		2
-	sys	sys_lstat64		2
-	sys	sys_fstat64		2	/* 4215 */
-	sys	sys_pivot_root		2
-	sys	sys_mincore		3
-	sys	sys_madvise		3
-	sys	sys_getdents64		3
-	sys	sys_fcntl64		3	/* 4220 */
-	sys	sys_ni_syscall		0
-	sys	sys_gettid		0
-	sys	sys_readahead		5
-	sys	sys_setxattr		5
-	sys	sys_lsetxattr		5	/* 4225 */
-	sys	sys_fsetxattr		5
-	sys	sys_getxattr		4
-	sys	sys_lgetxattr		4
-	sys	sys_fgetxattr		4
-	sys	sys_listxattr		3	/* 4230 */
-	sys	sys_llistxattr		3
-	sys	sys_flistxattr		3
-	sys	sys_removexattr		2
-	sys	sys_lremovexattr	2
-	sys	sys_fremovexattr	2	/* 4235 */
-	sys	sys_tkill		2
-	sys	sys_sendfile64		5
-	sys	sys_futex		6
+	.align	2
+	.type	sys_call_table, @object
+EXPORT(sys_call_table)
+	PTR	sys_syscall			/* 4000 */
+	PTR	sys_exit
+	PTR	sys_fork
+	PTR	sys_read
+	PTR	sys_write
+	PTR	sys_open			/* 4005 */
+	PTR	sys_close
+	PTR	sys_waitpid
+	PTR	sys_creat
+	PTR	sys_link
+	PTR	sys_unlink			/* 4010 */
+	PTR	sys_execve
+	PTR	sys_chdir
+	PTR	sys_time
+	PTR	sys_mknod
+	PTR	sys_chmod			/* 4015 */
+	PTR	sys_lchown
+	PTR	sys_ni_syscall
+	PTR	sys_ni_syscall			/* was sys_stat */
+	PTR	sys_lseek
+	PTR	sys_getpid			/* 4020 */
+	PTR	sys_mount
+	PTR	sys_oldumount
+	PTR	sys_setuid
+	PTR	sys_getuid
+	PTR	sys_stime			/* 4025 */
+	PTR	sys_ptrace
+	PTR	sys_alarm
+	PTR	sys_ni_syscall			/* was sys_fstat */
+	PTR	sys_pause
+	PTR	sys_utime			/* 4030 */
+	PTR	sys_ni_syscall
+	PTR	sys_ni_syscall
+	PTR	sys_access
+	PTR	sys_nice
+	PTR	sys_ni_syscall			/* 4035 */
+	PTR	sys_sync
+	PTR	sys_kill
+	PTR	sys_rename
+	PTR	sys_mkdir
+	PTR	sys_rmdir			/* 4040 */
+	PTR	sys_dup
+	PTR	sysm_pipe
+	PTR	sys_times
+	PTR	sys_ni_syscall
+	PTR	sys_brk				/* 4045 */
+	PTR	sys_setgid
+	PTR	sys_getgid
+	PTR	sys_ni_syscall			/* was signal(2) */
+	PTR	sys_geteuid
+	PTR	sys_getegid			/* 4050 */
+	PTR	sys_acct
+	PTR	sys_umount
+	PTR	sys_ni_syscall
+	PTR	sys_ioctl
+	PTR	sys_fcntl			/* 4055 */
+	PTR	sys_ni_syscall
+	PTR	sys_setpgid
+	PTR	sys_ni_syscall
+	PTR	sys_olduname
+	PTR	sys_umask			/* 4060 */
+	PTR	sys_chroot
+	PTR	sys_ustat
+	PTR	sys_dup2
+	PTR	sys_getppid
+	PTR	sys_getpgrp			/* 4065 */
+	PTR	sys_setsid
+	PTR	sys_sigaction
+	PTR	sys_sgetmask
+	PTR	sys_ssetmask
+	PTR	sys_setreuid			/* 4070 */
+	PTR	sys_setregid
+	PTR	sys_sigsuspend
+	PTR	sys_sigpending
+	PTR	sys_sethostname
+	PTR	sys_setrlimit			/* 4075 */
+	PTR	sys_getrlimit
+	PTR	sys_getrusage
+	PTR	sys_gettimeofday
+	PTR	sys_settimeofday
+	PTR	sys_getgroups			/* 4080 */
+	PTR	sys_setgroups
+	PTR	sys_ni_syscall			/* old_select */
+	PTR	sys_symlink
+	PTR	sys_ni_syscall			/* was sys_lstat */
+	PTR	sys_readlink			/* 4085 */
+	PTR	sys_uselib
+	PTR	sys_swapon
+	PTR	sys_reboot
+	PTR	sys_old_readdir
+	PTR	sys_mips_mmap			/* 4090 */
+	PTR	sys_munmap
+	PTR	sys_truncate
+	PTR	sys_ftruncate
+	PTR	sys_fchmod
+	PTR	sys_fchown			/* 4095 */
+	PTR	sys_getpriority
+	PTR	sys_setpriority
+	PTR	sys_ni_syscall
+	PTR	sys_statfs
+	PTR	sys_fstatfs			/* 4100 */
+	PTR	sys_ni_syscall			/* was ioperm(2) */
+	PTR	sys_socketcall
+	PTR	sys_syslog
+	PTR	sys_setitimer
+	PTR	sys_getitimer			/* 4105 */
+	PTR	sys_newstat
+	PTR	sys_newlstat
+	PTR	sys_newfstat
+	PTR	sys_uname
+	PTR	sys_ni_syscall			/* 4110 was iopl(2) */
+	PTR	sys_vhangup
+	PTR	sys_ni_syscall			/* was sys_idle() */
+	PTR	sys_ni_syscall			/* was sys_vm86 */
+	PTR	sys_wait4
+	PTR	sys_swapoff			/* 4115 */
+	PTR	sys_sysinfo
+	PTR	sys_ipc
+	PTR	sys_fsync
+	PTR	sys_sigreturn
+	PTR	sys_clone			/* 4120 */
+	PTR	sys_setdomainname
+	PTR	sys_newuname
+	PTR	sys_ni_syscall			/* sys_modify_ldt */
+	PTR	sys_adjtimex
+	PTR	sys_mprotect			/* 4125 */
+	PTR	sys_sigprocmask
+	PTR	sys_ni_syscall			/* was create_module */
+	PTR	sys_init_module
+	PTR	sys_delete_module
+	PTR	sys_ni_syscall			/* 4130	was get_kernel_syms */
+	PTR	sys_quotactl
+	PTR	sys_getpgid
+	PTR	sys_fchdir
+	PTR	sys_bdflush
+	PTR	sys_sysfs			/* 4135 */
+	PTR	sys_personality
+	PTR	sys_ni_syscall			/* for afs_syscall */
+	PTR	sys_setfsuid
+	PTR	sys_setfsgid
+	PTR	sys_llseek			/* 4140 */
+	PTR	sys_getdents
+	PTR	sys_select
+	PTR	sys_flock
+	PTR	sys_msync
+	PTR	sys_readv			/* 4145 */
+	PTR	sys_writev
+	PTR	sys_cacheflush
+	PTR	sys_cachectl
+	PTR	sys_sysmips
+	PTR	sys_ni_syscall			/* 4150 */
+	PTR	sys_getsid
+	PTR	sys_fdatasync
+	PTR	sys_sysctl
+	PTR	sys_mlock
+	PTR	sys_munlock			/* 4155 */
+	PTR	sys_mlockall
+	PTR	sys_munlockall
+	PTR	sys_sched_setparam
+	PTR	sys_sched_getparam
+	PTR	sys_sched_setscheduler		/* 4160 */
+	PTR	sys_sched_getscheduler
+	PTR	sys_sched_yield
+	PTR	sys_sched_get_priority_max
+	PTR	sys_sched_get_priority_min
+	PTR	sys_sched_rr_get_interval	/* 4165 */
+	PTR	sys_nanosleep
+	PTR	sys_mremap
+	PTR	sys_accept
+	PTR	sys_bind
+	PTR	sys_connect			/* 4170 */
+	PTR	sys_getpeername
+	PTR	sys_getsockname
+	PTR	sys_getsockopt
+	PTR	sys_listen
+	PTR	sys_recv			/* 4175 */
+	PTR	sys_recvfrom
+	PTR	sys_recvmsg
+	PTR	sys_send
+	PTR	sys_sendmsg
+	PTR	sys_sendto			/* 4180 */
+	PTR	sys_setsockopt
+	PTR	sys_shutdown
+	PTR	sys_socket
+	PTR	sys_socketpair
+	PTR	sys_setresuid			/* 4185 */
+	PTR	sys_getresuid
+	PTR	sys_ni_syscall			/* was sys_query_module */
+	PTR	sys_poll
+	PTR	sys_ni_syscall			/* was nfsservctl */
+	PTR	sys_setresgid			/* 4190 */
+	PTR	sys_getresgid
+	PTR	sys_prctl
+	PTR	sys_rt_sigreturn
+	PTR	sys_rt_sigaction
+	PTR	sys_rt_sigprocmask		/* 4195 */
+	PTR	sys_rt_sigpending
+	PTR	sys_rt_sigtimedwait
+	PTR	sys_rt_sigqueueinfo
+	PTR	sys_rt_sigsuspend
+	PTR	sys_pread64			/* 4200 */
+	PTR	sys_pwrite64
+	PTR	sys_chown
+	PTR	sys_getcwd
+	PTR	sys_capget
+	PTR	sys_capset			/* 4205 */
+	PTR	sys_sigaltstack
+	PTR	sys_sendfile
+	PTR	sys_ni_syscall
+	PTR	sys_ni_syscall
+	PTR	sys_mips_mmap2			/* 4210 */
+	PTR	sys_truncate64
+	PTR	sys_ftruncate64
+	PTR	sys_stat64
+	PTR	sys_lstat64
+	PTR	sys_fstat64			/* 4215 */
+	PTR	sys_pivot_root
+	PTR	sys_mincore
+	PTR	sys_madvise
+	PTR	sys_getdents64
+	PTR	sys_fcntl64			/* 4220 */
+	PTR	sys_ni_syscall
+	PTR	sys_gettid
+	PTR	sys_readahead
+	PTR	sys_setxattr
+	PTR	sys_lsetxattr			/* 4225 */
+	PTR	sys_fsetxattr
+	PTR	sys_getxattr
+	PTR	sys_lgetxattr
+	PTR	sys_fgetxattr
+	PTR	sys_listxattr			/* 4230 */
+	PTR	sys_llistxattr
+	PTR	sys_flistxattr
+	PTR	sys_removexattr
+	PTR	sys_lremovexattr
+	PTR	sys_fremovexattr		/* 4235 */
+	PTR	sys_tkill
+	PTR	sys_sendfile64
+	PTR	sys_futex
 #ifdef CONFIG_MIPS_MT_FPAFF
 	/*
 	 * For FPU affinity scheduling on MIPS MT processors, we need to
@@ -481,130 +431,116 @@ einval:	li	v0, -ENOSYS
 	 * in kernel/sched.c.  Considered only temporary we only support these
 	 * hooks for the 32-bit kernel - there is no MIPS64 MT processor atm.
 	 */
-	sys	mipsmt_sys_sched_setaffinity	3
-	sys	mipsmt_sys_sched_getaffinity	3
+	PTR	mipsmt_sys_sched_setaffinity
+	PTR	mipsmt_sys_sched_getaffinity
 #else
-	sys	sys_sched_setaffinity	3
-	sys	sys_sched_getaffinity	3	/* 4240 */
+	PTR	sys_sched_setaffinity
+	PTR	sys_sched_getaffinity		/* 4240 */
 #endif /* CONFIG_MIPS_MT_FPAFF */
-	sys	sys_io_setup		2
-	sys	sys_io_destroy		1
-	sys	sys_io_getevents	5
-	sys	sys_io_submit		3
-	sys	sys_io_cancel		3	/* 4245 */
-	sys	sys_exit_group		1
-	sys	sys_lookup_dcookie	4
-	sys	sys_epoll_create	1
-	sys	sys_epoll_ctl		4
-	sys	sys_epoll_wait		4	/* 4250 */
-	sys	sys_remap_file_pages	5
-	sys	sys_set_tid_address	1
-	sys	sys_restart_syscall	0
-	sys	sys_fadvise64_64	7
-	sys	sys_statfs64		3	/* 4255 */
-	sys	sys_fstatfs64		2
-	sys	sys_timer_create	3
-	sys	sys_timer_settime	4
-	sys	sys_timer_gettime	2
-	sys	sys_timer_getoverrun	1	/* 4260 */
-	sys	sys_timer_delete	1
-	sys	sys_clock_settime	2
-	sys	sys_clock_gettime	2
-	sys	sys_clock_getres	2
-	sys	sys_clock_nanosleep	4	/* 4265 */
-	sys	sys_tgkill		3
-	sys	sys_utimes		2
-	sys	sys_mbind		4
-	sys	sys_ni_syscall		0	/* sys_get_mempolicy */
-	sys	sys_ni_syscall		0	/* 4270 sys_set_mempolicy */
-	sys	sys_mq_open		4
-	sys	sys_mq_unlink		1
-	sys	sys_mq_timedsend	5
-	sys	sys_mq_timedreceive	5
-	sys	sys_mq_notify		2	/* 4275 */
-	sys	sys_mq_getsetattr	3
-	sys	sys_ni_syscall		0	/* sys_vserver */
-	sys	sys_waitid		5
-	sys	sys_ni_syscall		0	/* available, was setaltroot */
-	sys	sys_add_key		5	/* 4280 */
-	sys	sys_request_key		4
-	sys	sys_keyctl		5
-	sys	sys_set_thread_area	1
-	sys	sys_inotify_init	0
-	sys	sys_inotify_add_watch	3	/* 4285 */
-	sys	sys_inotify_rm_watch	2
-	sys	sys_migrate_pages	4
-	sys	sys_openat		4
-	sys	sys_mkdirat		3
-	sys	sys_mknodat		4	/* 4290 */
-	sys	sys_fchownat		5
-	sys	sys_futimesat		3
-	sys	sys_fstatat64		4
-	sys	sys_unlinkat		3
-	sys	sys_renameat		4	/* 4295 */
-	sys	sys_linkat		5
-	sys	sys_symlinkat		3
-	sys	sys_readlinkat		4
-	sys	sys_fchmodat		3
-	sys	sys_faccessat		3	/* 4300 */
-	sys	sys_pselect6		6
-	sys	sys_ppoll		5
-	sys	sys_unshare		1
-	sys	sys_splice		6
-	sys	sys_sync_file_range	7	/* 4305 */
-	sys	sys_tee			4
-	sys	sys_vmsplice		4
-	sys	sys_move_pages		6
-	sys	sys_set_robust_list	2
-	sys	sys_get_robust_list	3	/* 4310 */
-	sys	sys_kexec_load		4
-	sys	sys_getcpu		3
-	sys	sys_epoll_pwait		6
-	sys	sys_ioprio_set		3
-	sys	sys_ioprio_get		2	/* 4315 */
-	sys	sys_utimensat		4
-	sys	sys_signalfd		3
-	sys	sys_ni_syscall		0	/* was timerfd */
-	sys	sys_eventfd		1
-	sys	sys_fallocate		6	/* 4320 */
-	sys	sys_timerfd_create	2
-	sys	sys_timerfd_gettime	2
-	sys	sys_timerfd_settime	4
-	sys	sys_signalfd4		4
-	sys	sys_eventfd2		2	/* 4325 */
-	sys	sys_epoll_create1	1
-	sys	sys_dup3		3
-	sys	sys_pipe2		2
-	sys	sys_inotify_init1	1
-	sys	sys_preadv		6	/* 4330 */
-	sys	sys_pwritev		6
-	sys	sys_rt_tgsigqueueinfo	4
-	sys	sys_perf_event_open	5
-	sys	sys_accept4		4
-	sys	sys_recvmmsg		5	/* 4335 */
-	sys	sys_fanotify_init	2
-	sys	sys_fanotify_mark	6
-	sys	sys_prlimit64		4
-	sys	sys_name_to_handle_at	5
-	sys	sys_open_by_handle_at	3	/* 4340 */
-	sys	sys_clock_adjtime	2
-	sys	sys_syncfs		1
-	sys	sys_sendmmsg		4
-	sys	sys_setns		2
-	sys	sys_process_vm_readv	6	/* 4345 */
-	sys	sys_process_vm_writev	6
-	.endm
-
-	/* We pre-compute the number of _instruction_ bytes needed to
-	   load or store the arguments 6-8. Negative values are ignored. */
-
-	.macro  sys function, nargs
-	PTR	\function
-	LONG	(\nargs << 2) - (5 << 2)
-	.endm
-
-	.align	3
-	.type	sys_call_table,@object
-EXPORT(sys_call_table)
-	syscalltable
+	PTR	sys_io_setup
+	PTR	sys_io_destroy
+	PTR	sys_io_getevents
+	PTR	sys_io_submit
+	PTR	sys_io_cancel			/* 4245 */
+	PTR	sys_exit_group
+	PTR	sys_lookup_dcookie
+	PTR	sys_epoll_create
+	PTR	sys_epoll_ctl
+	PTR	sys_epoll_wait			/* 4250 */
+	PTR	sys_remap_file_pages
+	PTR	sys_set_tid_address
+	PTR	sys_restart_syscall
+	PTR	sys_fadvise64_64
+	PTR	sys_statfs64			/* 4255 */
+	PTR	sys_fstatfs64
+	PTR	sys_timer_create
+	PTR	sys_timer_settime
+	PTR	sys_timer_gettime
+	PTR	sys_timer_getoverrun		/* 4260 */
+	PTR	sys_timer_delete
+	PTR	sys_clock_settime
+	PTR	sys_clock_gettime
+	PTR	sys_clock_getres
+	PTR	sys_clock_nanosleep		/* 4265 */
+	PTR	sys_tgkill
+	PTR	sys_utimes
+	PTR	sys_mbind
+	PTR	sys_ni_syscall			/* sys_get_mempolicy */
+	PTR	sys_ni_syscall			/* 4270 sys_set_mempolicy */
+	PTR	sys_mq_open
+	PTR	sys_mq_unlink
+	PTR	sys_mq_timedsend
+	PTR	sys_mq_timedreceive
+	PTR	sys_mq_notify			/* 4275 */
+	PTR	sys_mq_getsetattr
+	PTR	sys_ni_syscall			/* sys_vserver */
+	PTR	sys_waitid
+	PTR	sys_ni_syscall			/* available, was setaltroot */
+	PTR	sys_add_key			/* 4280 */
+	PTR	sys_request_key
+	PTR	sys_keyctl
+	PTR	sys_set_thread_area
+	PTR	sys_inotify_init
+	PTR	sys_inotify_add_watch		/* 4285 */
+	PTR	sys_inotify_rm_watch
+	PTR	sys_migrate_pages
+	PTR	sys_openat
+	PTR	sys_mkdirat
+	PTR	sys_mknodat			/* 4290 */
+	PTR	sys_fchownat
+	PTR	sys_futimesat
+	PTR	sys_fstatat64
+	PTR	sys_unlinkat
+	PTR	sys_renameat			/* 4295 */
+	PTR	sys_linkat
+	PTR	sys_symlinkat
+	PTR	sys_readlinkat
+	PTR	sys_fchmodat
+	PTR	sys_faccessat			/* 4300 */
+	PTR	sys_pselect6
+	PTR	sys_ppoll
+	PTR	sys_unshare
+	PTR	sys_splice
+	PTR	sys_sync_file_range		/* 4305 */
+	PTR	sys_tee
+	PTR	sys_vmsplice
+	PTR	sys_move_pages
+	PTR	sys_set_robust_list
+	PTR	sys_get_robust_list		/* 4310 */
+	PTR	sys_kexec_load
+	PTR	sys_getcpu
+	PTR	sys_epoll_pwait
+	PTR	sys_ioprio_set
+	PTR	sys_ioprio_get			/* 4315 */
+	PTR	sys_utimensat
+	PTR	sys_signalfd
+	PTR	sys_ni_syscall			/* was timerfd */
+	PTR	sys_eventfd
+	PTR	sys_fallocate			/* 4320 */
+	PTR	sys_timerfd_create
+	PTR	sys_timerfd_gettime
+	PTR	sys_timerfd_settime
+	PTR	sys_signalfd4
+	PTR	sys_eventfd2			/* 4325 */
+	PTR	sys_epoll_create1
+	PTR	sys_dup3
+	PTR	sys_pipe2
+	PTR	sys_inotify_init1
+	PTR	sys_preadv			/* 4330 */
+	PTR	sys_pwritev
+	PTR	sys_rt_tgsigqueueinfo
+	PTR	sys_perf_event_open
+	PTR	sys_accept4
+	PTR	sys_recvmmsg			/* 4335 */
+	PTR	sys_fanotify_init
+	PTR	sys_fanotify_mark
+	PTR	sys_prlimit64
+	PTR	sys_name_to_handle_at
+	PTR	sys_open_by_handle_at		/* 4340 */
+	PTR	sys_clock_adjtime
+	PTR	sys_syncfs
+	PTR	sys_sendmmsg
+	PTR	sys_setns
+	PTR	sys_process_vm_readv		/* 4345 */
+	PTR	sys_process_vm_writev
 	.size	sys_call_table, . - sys_call_table
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index 3b5a5e9..c32e145 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -39,26 +39,26 @@ NESTED(handle_sys64, PT_SIZE, sp)
 	.set	at
 #endif
 
-	dsubu	t0, v0, __NR_64_Linux	# check syscall number
-	sltiu	t0, t0,	__NR_64_Linux_syscalls + 1
 #if !defined(CONFIG_MIPS32_O32) && !defined(CONFIG_MIPS32_N32)
 	ld	t1, PT_EPC(sp)		# skip syscall on return
 	daddiu	t1, 4			# skip to next instruction
 	sd	t1, PT_EPC(sp)
 #endif
+
+	LONG_L	t0, TI_FLAGS($28)	# syscall tracing enabled?
+	li	t1, _TIF_WORK_SYSCALL_ENTRY
+	and	t0, t1
+	bnez	t0, syscall_trace_entry
+
+syscall_call:
+	dsubu	v0, v0, __NR_64_Linux	# check syscall number
+	sltiu	t0, v0,	__NR_64_Linux_syscalls + 1
 	beqz	t0, illegal_syscall
 
 	dsll	t0, v0, 3		# offset into table
-	ld	t2, (sys_call_table - (__NR_64_Linux * 8))(t0)
-					# syscall routine
-
+	ld	t2, sys_call_table(t0)	# syscall routine
 	sd	a3, PT_R26(sp)		# save a3 for syscall restarting
 
-	li	t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
-	LONG_L	t0, TI_FLAGS($28)	# syscall tracing enabled?
-	and	t0, t1, t0
-	bnez	t0, syscall_trace_entry
-
 	jalr	t2			# Do The Real Thing (TM)
 
 	li	t0, -EMAXERRNO - 1	# error?
@@ -72,47 +72,23 @@ NESTED(handle_sys64, PT_SIZE, sp)
 1:	sd	v0, PT_R2(sp)		# result
 
 n64_syscall_exit:
-	local_irq_disable		# make sure need_resched and
-					# signals dont change between
-					# sampling and return
-	LONG_L	a2, TI_FLAGS($28)	# current->work
-	li	t0, _TIF_ALLWORK_MASK
-	and	t0, a2, t0
-	bnez	t0, n64_syscall_exit_work
-
-	j	restore_partial
-
-n64_syscall_exit_work:
-	j	syscall_exit_work_partial
+	j	syscall_exit_partial
 
 /* ------------------------------------------------------------------------ */
 
 syscall_trace_entry:
 	SAVE_STATIC
-	move	s0, t2
 	move	a0, sp
 	jal	syscall_trace_enter
 
-	move	t0, s0
-	RESTORE_STATIC
-	ld	a0, PT_R4(sp)		# Restore argument registers
+	ld	a0, PT_R4(sp)			# Restore argument registers
 	ld	a1, PT_R5(sp)
 	ld	a2, PT_R6(sp)
 	ld	a3, PT_R7(sp)
 	ld	a4, PT_R8(sp)
 	ld	a5, PT_R9(sp)
-	jalr	t0
-
-	li	t0, -EMAXERRNO - 1	# error?
-	sltu	t0, t0, v0
-	sd	t0, PT_R7(sp)		# set error flag
-	beqz	t0, 1f
-
-	ld	t1, PT_R2(sp)		# syscall number
-	dnegu	v0			# error
-	sd	t1, PT_R0(sp)		# save it for syscall restarting
-1:	sd	v0, PT_R2(sp)		# result
 
+	bgez	v0, syscall_call
 	j	syscall_exit
 
 illegal_syscall:
@@ -125,7 +101,8 @@ illegal_syscall:
 	END(handle_sys64)
 
 	.align	3
-sys_call_table:
+	.type	sys_call_table, @object
+EXPORT(sys_call_table)
 	PTR	sys_read			/* 5000 */
 	PTR	sys_write
 	PTR	sys_open
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 6be6f70..017e5bf 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -17,12 +17,6 @@
 #include <asm/thread_info.h>
 #include <asm/unistd.h>
 
-/* This duplicates the definition from <linux/sched.h> */
-#define PT_TRACESYS	0x00000002	/* tracing system calls */
-
-/* This duplicates the definition from <asm/signal.h> */
-#define SIGILL		4		/* Illegal instruction (ANSI).  */
-
 #ifndef CONFIG_MIPS32_O32
 /* No O32, so define handle_sys here */
 #define handle_sysn32 handle_sys
@@ -38,26 +32,25 @@ NESTED(handle_sysn32, PT_SIZE, sp)
 	.set	at
 #endif
 
-	dsubu	t0, v0, __NR_N32_Linux	# check syscall number
-	sltiu	t0, t0,	__NR_N32_Linux_syscalls + 1
-
 #ifndef CONFIG_MIPS32_O32
 	ld	t1, PT_EPC(sp)		# skip syscall on return
 	daddiu	t1, 4			# skip to next instruction
 	sd	t1, PT_EPC(sp)
 #endif
+	LONG_L	t0, TI_FLAGS($28)	# syscall tracing enabled?
+	li	t1, _TIF_WORK_SYSCALL_ENTRY
+	and	t0, t1
+	bnez	t0, syscall_trace_entry
+
+syscall_call:
+	dsubu	v0, v0, __NR_N32_Linux	# check syscall number
+	sltiu	t0, v0,	__NR_N32_Linux_syscalls + 1
 	beqz	t0, not_n32_scall
 
 	dsll	t0, v0, 3		# offset into table
-	ld	t2, (sysn32_call_table - (__NR_N32_Linux * 8))(t0)
-
+	ld	t2, sysn32_call_table(t0) # syscall routine
 	sd	a3, PT_R26(sp)		# save a3 for syscall restarting
 
-	li	t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
-	LONG_L	t0, TI_FLAGS($28)	# syscall tracing enabled?
-	and	t0, t1, t0
-	bnez	t0, n32_syscall_trace_entry
-
 	jalr	t2			# Do The Real Thing (TM)
 
 	li	t0, -EMAXERRNO - 1	# error?
@@ -70,24 +63,12 @@ NESTED(handle_sysn32, PT_SIZE, sp)
 	sd	t1, PT_R0(sp)		# save it for syscall restarting
 1:	sd	v0, PT_R2(sp)		# result
 
-	local_irq_disable		# make sure need_resched and
-					# signals dont change between
-					# sampling and return
-	LONG_L  a2, TI_FLAGS($28)	# current->work
-	li	t0, _TIF_ALLWORK_MASK
-	and	t0, a2, t0
-	bnez	t0, n32_syscall_exit_work
-
-	j	restore_partial
-
-n32_syscall_exit_work:
-	j	syscall_exit_work_partial
+	j	syscall_exit_partial
 
 /* ------------------------------------------------------------------------ */
 
-n32_syscall_trace_entry:
+syscall_trace_entry:
 	SAVE_STATIC
-	move	s0, t2
 	move	a0, sp
 	jal	syscall_trace_enter
 
@@ -99,27 +80,21 @@ n32_syscall_trace_entry:
 	ld	a3, PT_R7(sp)
 	ld	a4, PT_R8(sp)
 	ld	a5, PT_R9(sp)
-	jalr	t0
-
-	li	t0, -EMAXERRNO - 1	# error?
-	sltu	t0, t0, v0
-	sd	t0, PT_R7(sp)		# set error flag
-	beqz	t0, 1f
-
-	ld	t1, PT_R2(sp)		# syscall number
-	dnegu	v0			# error
-	sd	t1, PT_R0(sp)		# save it for syscall restarting
-1:	sd	v0, PT_R2(sp)		# result
+	ld	a5, PT_R10(sp)
 
+	bgez	v0, syscall_call
 	j	syscall_exit
 
 not_n32_scall:
-	/* This is not an n32 compatibility syscall, pass it on to
-	   the n64 syscall handlers.  */
+	/*
+	 * This is not an N32 compatibility syscall, pass it on to
+	 * the n64 syscall handlers.
+	 */
 	j	handle_sys64
 
 	END(handle_sysn32)
 
+	.type	sysn32_call_table, @object
 EXPORT(sysn32_call_table)
 	PTR	sys_read			/* 6000 */
 	PTR	sys_write
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 5422855..1bfda86 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -32,31 +32,24 @@ NESTED(handle_sys, PT_SIZE, sp)
 	STI
 	.set	at
 	ld	t1, PT_EPC(sp)		# skip syscall on return
-
-	dsubu	t0, v0, __NR_O32_Linux	# check syscall number
-	sltiu	t0, t0, __NR_O32_Linux_syscalls + 1
 	daddiu	t1, 4			# skip to next instruction
 	sd	t1, PT_EPC(sp)
-	beqz	t0, not_o32_scall
-#if 0
- SAVE_ALL
- move a1, v0
- PRINT("Scall %ld\n")
- RESTORE_ALL
-#endif
 
-	/* We don't want to stumble over broken sign extensions from
-	   userland. O32 does never use the upper half. */
+	LONG_L	t0, TI_FLAGS($28)	# syscall tracing enabled?
+	li	t1, _TIF_WORK_SYSCALL_ENTRY
+	and	t0, t1
+	bnez	t0, syscall_trace_entry
+
+syscall_call:
+	/*
+	 * We don't want to stumble over broken sign extensions from
+	 * userland. O32 does never use the upper half.
+	 */
 	sll	a0, a0, 0
 	sll	a1, a1, 0
 	sll	a2, a2, 0
 	sll	a3, a3, 0
 
-	dsll	t0, v0, 3		# offset into table
-	ld	t2, (sys_call_table - (__NR_O32_Linux * 8))(t0)
-
-	sd	a3, PT_R26(sp)		# save a3 for syscall restarting
-
 	/*
 	 * More than four arguments.  Try to deal with it by copying the
 	 * stack arguments from the user stack to the kernel stack.
@@ -81,10 +74,20 @@ NESTED(handle_sys, PT_SIZE, sp)
 	PTR	4b, bad_stack
 	.previous
 
-	li	t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
-	LONG_L	t0, TI_FLAGS($28)	# syscall tracing enabled?
-	and	t0, t1, t0
-	bnez	t0, trace_a_syscall
+#if 0
+ SAVE_ALL
+ move a1, v0
+ PRINT("Scall %ld\n")
+ RESTORE_ALL
+#endif
+
+	dsubu	v0, v0, __NR_O32_Linux	# check syscall number
+	sltiu	t0, v0, __NR_O32_Linux_syscalls + 1
+	beqz	t0, not_o32_scall
+
+	dsll	t0, v0, 3		# offset into table
+	ld	t2, sys32_call_table(t0) # syscall routine
+	sd	a3, PT_R26(sp)		# save a3 for syscall restarting
 
 	jalr	t2			# Do The Real Thing (TM)
 
@@ -99,33 +102,16 @@ NESTED(handle_sys, PT_SIZE, sp)
 1:	sd	v0, PT_R2(sp)		# result
 
 o32_syscall_exit:
-	local_irq_disable		# make need_resched and
-					# signals dont change between
-					# sampling and return
-	LONG_L	a2, TI_FLAGS($28)
-	li	t0, _TIF_ALLWORK_MASK
-	and	t0, a2, t0
-	bnez	t0, o32_syscall_exit_work
-
-	j	restore_partial
-
-o32_syscall_exit_work:
-	j	syscall_exit_work_partial
+	j	syscall_exit_partial
 
 /* ------------------------------------------------------------------------ */
 
-trace_a_syscall:
+syscall_trace_entry:
 	SAVE_STATIC
-	sd	a4, PT_R8(sp)		# Save argument registers
-	sd	a5, PT_R9(sp)
-	sd	a6, PT_R10(sp)
-	sd	a7, PT_R11(sp)		# For indirect syscalls
-
-	move	s0, t2			# Save syscall pointer
 	move	a0, sp
 	jal	syscall_trace_enter
 
-	move	t0, s0
+	sw	a6, PT_R10(sp)
 	RESTORE_STATIC
 	ld	a0, PT_R4(sp)		# Restore argument registers
 	ld	a1, PT_R5(sp)
@@ -133,26 +119,15 @@ trace_a_syscall:
 	ld	a3, PT_R7(sp)
 	ld	a4, PT_R8(sp)
 	ld	a5, PT_R9(sp)
-	ld	a6, PT_R10(sp)
-	ld	a7, PT_R11(sp)		# For indirect syscalls
-	jalr	t0
-
-	li	t0, -EMAXERRNO - 1	# error?
-	sltu	t0, t0, v0
-	sd	t0, PT_R7(sp)		# set error flag
-	beqz	t0, 1f
-
-	ld	t1, PT_R2(sp)		# syscall number
-	dnegu	v0			# error
-	sd	t1, PT_R0(sp)		# save it for syscall restarting
-1:	sd	v0, PT_R2(sp)		# result
+	ld	a6, PT_R10(sp)		# For indirect syscalls
 
+	bgez	v0, syscall_call
 	j	syscall_exit
 
 /* ------------------------------------------------------------------------ */
 
 	/*
-	 * The stackpointer for a call with more than 4 arguments is bad.
+	 * The stackpointer for arguments 5..8 is bad.
 	 */
 bad_stack:
 	li	v0, EFAULT
@@ -163,7 +138,7 @@ bad_stack:
 
 not_o32_scall:
 	/*
-	 * This is not an o32 compatibility syscall, pass it on
+	 * This is not an O32 compatibility syscall, pass it on
 	 * to the 64-bit syscall handlers.
 	 */
 #ifdef CONFIG_MIPS32_N32
@@ -179,7 +154,7 @@ LEAF(sys32_syscall)
 	beqz	t0, einval		# do not recurse
 	dsll	t1, t0, 3
 	beqz	v0, einval
-	ld	t2, sys_call_table(t1)		# syscall routine
+	ld	t2, sys32_call_table(t1)# syscall routine
 
 	move	a0, a1			# shift argument registers
 	move	a1, a2
@@ -201,8 +176,8 @@ einval:	li	v0, -ENOSYS
 	END(sys32_syscall)
 
 	.align	3
-	.type	sys_call_table,@object
-sys_call_table:
+	.type	sys32_call_table,@object
+EXPORT(sys32_call_table)
 	PTR	sys32_syscall			/* 4000 */
 	PTR	sys_exit
 	PTR	sys_fork
@@ -550,4 +525,4 @@ sys_call_table:
 	PTR	sys_setns
 	PTR	compat_sys_process_vm_readv	/* 4345 */
 	PTR	compat_sys_process_vm_writev
-	.size	sys_call_table,.-sys_call_table
+	.size	sys32_call_table,.-sys32_call_table
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index f2c09cf..0e1a5b8 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -560,14 +560,6 @@ static void do_signal(struct pt_regs *regs)
 	siginfo_t info;
 	int signr;
 
-	/*
-	 * We want the common case to go fast, which is why we may in certain
-	 * cases get here from kernel mode. Just return without doing anything
-	 * if so.
-	 */
-	if (!user_mode(regs))
-		return;
-
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 	if (signr > 0) {
 		/* Whee!  Actually deliver the signal.  */
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 31637d8..9005bf9 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -130,7 +130,7 @@ asmlinkage __cpuinit void start_secondary(void)
 
 	cpu_set(cpu, cpu_callin_map);
 
-	synchronise_count_slave();
+	synchronise_count_slave(cpu);
 
 	/*
 	 * irq will be enabled in ->smp_finish(), enabling it too early
@@ -173,7 +173,6 @@ void smp_send_stop(void)
 void __init smp_cpus_done(unsigned int max_cpus)
 {
 	mp_ops->cpus_done();
-	synchronise_count_master();
 }
 
 /* called from main before smp_init() */
@@ -206,6 +205,7 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle)
 	while (!cpu_isset(cpu, cpu_callin_map))
 		udelay(100);
 
+	synchronise_count_master(cpu);
 	return 0;
 }
 
diff --git a/arch/mips/kernel/sync-r4k.c b/arch/mips/kernel/sync-r4k.c
index 842d55e..7f1eca3 100644
--- a/arch/mips/kernel/sync-r4k.c
+++ b/arch/mips/kernel/sync-r4k.c
@@ -28,12 +28,11 @@ static atomic_t __cpuinitdata count_reference = ATOMIC_INIT(0);
 #define COUNTON	100
 #define NR_LOOPS 5
 
-void __cpuinit synchronise_count_master(void)
+void __cpuinit synchronise_count_master(int cpu)
 {
 	int i;
 	unsigned long flags;
 	unsigned int initcount;
-	int nslaves;
 
 #ifdef CONFIG_MIPS_MT_SMTC
 	/*
@@ -43,8 +42,7 @@ void __cpuinit synchronise_count_master(void)
 	return;
 #endif
 
-	printk(KERN_INFO "Synchronize counters across %u CPUs: ",
-	       num_online_cpus());
+	printk(KERN_INFO "Synchronize counters for CPU %u: ", cpu);
 
 	local_irq_save(flags);
 
@@ -52,7 +50,7 @@ void __cpuinit synchronise_count_master(void)
 	 * Notify the slaves that it's time to start
 	 */
 	atomic_set(&count_reference, read_c0_count());
-	atomic_set(&count_start_flag, 1);
+	atomic_set(&count_start_flag, cpu);
 	smp_wmb();
 
 	/* Count will be initialised to current timer for all CPU's */
@@ -69,10 +67,9 @@ void __cpuinit synchronise_count_master(void)
 	 * two CPUs.
 	 */
 
-	nslaves = num_online_cpus()-1;
 	for (i = 0; i < NR_LOOPS; i++) {
-		/* slaves loop on '!= ncpus' */
-		while (atomic_read(&count_count_start) != nslaves)
+		/* slaves loop on '!= 2' */
+		while (atomic_read(&count_count_start) != 1)
 			mb();
 		atomic_set(&count_count_stop, 0);
 		smp_wmb();
@@ -89,7 +86,7 @@ void __cpuinit synchronise_count_master(void)
 		/*
 		 * Wait for all slaves to leave the synchronization point:
 		 */
-		while (atomic_read(&count_count_stop) != nslaves)
+		while (atomic_read(&count_count_stop) != 1)
 			mb();
 		atomic_set(&count_count_start, 0);
 		smp_wmb();
@@ -97,6 +94,7 @@ void __cpuinit synchronise_count_master(void)
 	}
 	/* Arrange for an interrupt in a short while */
 	write_c0_compare(read_c0_count() + COUNTON);
+	atomic_set(&count_start_flag, 0);
 
 	local_irq_restore(flags);
 
@@ -108,11 +106,10 @@ void __cpuinit synchronise_count_master(void)
 	printk("done.\n");
 }
 
-void __cpuinit synchronise_count_slave(void)
+void __cpuinit synchronise_count_slave(int cpu)
 {
 	int i;
 	unsigned int initcount;
-	int ncpus;
 
 #ifdef CONFIG_MIPS_MT_SMTC
 	/*
@@ -127,16 +124,15 @@ void __cpuinit synchronise_count_slave(void)
 	 * so we first wait for the master to say everyone is ready
 	 */
 
-	while (!atomic_read(&count_start_flag))
+	while (atomic_read(&count_start_flag) != cpu)
 		mb();
 
 	/* Count will be initialised to next expire for all CPU's */
 	initcount = atomic_read(&count_reference);
 
-	ncpus = num_online_cpus();
 	for (i = 0; i < NR_LOOPS; i++) {
 		atomic_inc(&count_count_start);
-		while (atomic_read(&count_count_start) != ncpus)
+		while (atomic_read(&count_count_start) != 2)
 			mb();
 
 		/*
@@ -146,7 +142,7 @@ void __cpuinit synchronise_count_slave(void)
 			write_c0_count(initcount);
 
 		atomic_inc(&count_count_stop);
-		while (atomic_read(&count_count_stop) != ncpus)
+		while (atomic_read(&count_count_stop) != 2)
 			mb();
 	}
 	/* Arrange for an interrupt in a short while */
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index df243a6..007ccbe 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -1,6 +1,13 @@
 #include <asm/asm-offsets.h>
 #include <asm/page.h>
 #include <asm/thread_info.h>
+
+/*
+ * Put .bss..swapper_pg_dir as the first thing in .bss. This will
+ * ensure that it has .bss alignment (64K).
+ */
+#define BSS_FIRST_SECTIONS *(.bss..swapper_pg_dir)
+
 #include <asm-generic/vmlinux.lds.h>
 
 #undef mips
@@ -119,11 +126,21 @@ SECTIONS
 	}
 
 	PERCPU_SECTION(1 << CONFIG_MIPS_L1_CACHE_SHIFT)
-	. = ALIGN(PAGE_SIZE);
+	/*
+	 * Align to 64K in attempt to eliminate holes before the
+	 * .bss..swapper_pg_dir section at the start of .bss.  This
+	 * also satisfies PAGE_SIZE alignment as the largest page size
+	 * allowed is 64K.
+	 */
+	. = ALIGN(0x10000);
 	__init_end = .;
 	/* freed after init ends here */
 
-	BSS_SECTION(0, 0, 0)
+	/*
+	 * Force .bss to 64K alignment so that .bss..swapper_pg_dir
+	 * gets that alignment.  .sbss should be empty, so there will be
+	 * no holes after __init_end. */
+	BSS_SECTION(0, 0x10000, 0)
 
 	_end = . ;
 
diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c
index befbb76..79887af 100644
--- a/arch/mips/lantiq/xway/sysctrl.c
+++ b/arch/mips/lantiq/xway/sysctrl.c
@@ -41,6 +41,10 @@
 /* power status register */
 #define PWDSR(x) ((x) ? (PMU_PWDSR1) : (PMU_PWDSR))
 
+/* pci delay is 6 bit wide and 18 bit into the register*/
+#define PCI_DLY_MASK    0x3f
+#define PCI_DLY_SHIFT   18
+
 /* clock gates that we can en/disable */
 #define PMU_USB0_P	BIT(0)
 #define PMU_PCI		BIT(4)
@@ -258,6 +262,16 @@ static void clkdev_add_pci(void)
 	clkdev_add(&clk_ext->cl);
 }
 
+/* allow PCI driver to specify the clock delay. This is a 6 bit value */
+void ltq_pci_set_delay(u8 delay)
+{
+	u32 val = ltq_cgu_r32(pcicr);
+
+	val &= ~(PCI_DLY_MASK << PCI_DLY_SHIFT);
+	val |= ((u32)(delay & PCI_DLY_MASK)) << PCI_DLY_SHIFT;
+	ltq_cgu_w32(val, pcicr);
+}
+
 /* xway socs can generate clocks on gpio pins */
 static unsigned long valid_clkout_rates[4][5] = {
 	{CLOCK_32_768K, CLOCK_1_536M, CLOCK_2_5M, CLOCK_12M, 0},
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 1a85ba9..be9acb2 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -469,19 +469,20 @@ void __init_refok free_initmem(void)
 #ifndef CONFIG_MIPS_PGD_C0_CONTEXT
 unsigned long pgd_current[NR_CPUS];
 #endif
-/*
- * On 64-bit we've got three-level pagetables with a slightly
- * different layout ...
- */
-#define __page_aligned(order) __attribute__((__aligned__(PAGE_SIZE<<order)))
 
 /*
  * gcc 3.3 and older have trouble determining that PTRS_PER_PGD and PGD_ORDER
  * are constants.  So we use the variants from asm-offset.h until that gcc
  * will officially be retired.
+ *
+ * Align swapper_pg_dir in to 64K, allows its address to be loaded
+ * with a single LUI instruction in the TLB handlers.  If we used
+ * __aligned(64K), its size would get rounded up to the alignment
+ * size, and waste space.  So we place it in its own section and align
+ * it in the linker script.
  */
-pgd_t swapper_pg_dir[_PTRS_PER_PGD] __page_aligned(_PGD_ORDER);
+pgd_t swapper_pg_dir[_PTRS_PER_PGD] __section(.bss..swapper_pg_dir);
 #ifndef __PAGETABLE_PMD_FOLDED
-pmd_t invalid_pmd_table[PTRS_PER_PMD] __page_aligned(PMD_ORDER);
+pmd_t invalid_pmd_table[PTRS_PER_PMD] __page_aligned_bss;
 #endif
-pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned(PTE_ORDER);
+pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned_bss;
diff --git a/arch/mips/mti-malta/malta-pci.c b/arch/mips/mti-malta/malta-pci.c
index 284dea5..2147cb3 100644
--- a/arch/mips/mti-malta/malta-pci.c
+++ b/arch/mips/mti-malta/malta-pci.c
@@ -252,16 +252,3 @@ void __init mips_pcibios_init(void)
 
 	register_pci_controller(controller);
 }
-
-/* Enable PCI 2.1 compatibility in PIIX4 */
-static void __devinit quirk_dlcsetup(struct pci_dev *dev)
-{
-	u8 odlc, ndlc;
-	(void) pci_read_config_byte(dev, 0x82, &odlc);
-	/* Enable passive releases and delayed transaction */
-	ndlc = odlc | 7;
-	(void) pci_write_config_byte(dev, 0x82, ndlc);
-}
-
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
-	quirk_dlcsetup);
diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c
index 075d87a..dae4349 100644
--- a/arch/mips/pci/pci-lantiq.c
+++ b/arch/mips/pci/pci-lantiq.c
@@ -98,7 +98,7 @@ static inline u32 ltq_calc_bar11mask(void)
 static int __devinit ltq_pci_startup(struct platform_device *pdev)
 {
 	struct device_node *node = pdev->dev.of_node;
-	const __be32 *req_mask, *bus_clk;
+	const __be32 *req_mask, *bus_clk, *delay;
 	u32 temp_buffer;
 
 	/* get our clocks */
@@ -127,6 +127,11 @@ static int __devinit ltq_pci_startup(struct platform_device *pdev)
 	else
 		clk_disable(clk_external);
 
+	/* pci ckl delay is a 6 bit value */
+	delay = of_get_property(node, "lantiq,delay", NULL);
+	if (delay)
+		ltq_pci_set_delay(*delay);
+
 	/* setup reset gpio used by pci */
 	reset_gpio = of_get_named_gpio(node, "gpio-reset", 0);
 	if (gpio_is_valid(reset_gpio))
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
index 5cfb086..aa03f2e 100644
--- a/arch/mn10300/Kconfig
+++ b/arch/mn10300/Kconfig
@@ -8,6 +8,7 @@ config MN10300
 	select HAVE_ARCH_KGDB
 	select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER
 	select GENERIC_CLOCKEVENTS
+	select MODULES_USE_ELF_RELA
 
 config AM33_2
 	def_bool n
diff --git a/arch/mn10300/Makefile b/arch/mn10300/Makefile
index 33188b6..a3d0fef 100644
--- a/arch/mn10300/Makefile
+++ b/arch/mn10300/Makefile
@@ -26,7 +26,7 @@ CHECKFLAGS	+=
 PROCESSOR	:= unset
 UNIT		:= unset
 
-KBUILD_CFLAGS	+= -mam33 -mmem-funcs -DCPU=AM33
+KBUILD_CFLAGS	+= -mam33 -DCPU=AM33 $(call cc-option,-mmem-funcs,)
 KBUILD_AFLAGS	+= -mam33 -DCPU=AM33
 
 ifeq ($(CONFIG_MN10300_CURRENT_IN_E2),y)
diff --git a/arch/mn10300/include/asm/module.h b/arch/mn10300/include/asm/module.h
index 5d7057d..6571103 100644
--- a/arch/mn10300/include/asm/module.h
+++ b/arch/mn10300/include/asm/module.h
@@ -12,12 +12,7 @@
 #ifndef _ASM_MODULE_H
 #define _ASM_MODULE_H
 
-struct mod_arch_specific {
-};
-
-#define Elf_Shdr	Elf32_Shdr
-#define Elf_Sym		Elf32_Sym
-#define Elf_Ehdr	Elf32_Ehdr
+#include <asm-generic/module.h>
 
 /*
  * Include the MN10300 architecture version.
diff --git a/arch/mn10300/include/asm/thread_info.h b/arch/mn10300/include/asm/thread_info.h
index ac519bb..f90062b 100644
--- a/arch/mn10300/include/asm/thread_info.h
+++ b/arch/mn10300/include/asm/thread_info.h
@@ -160,12 +160,13 @@ void arch_release_thread_info(struct thread_info *ti);
 #define _TIF_SIGPENDING		+(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	+(1 << TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP		+(1 << TIF_SINGLESTEP)
-#define _TIF_RESTORE_SIGMASK	+(1 << TIF_RESTORE_SIGMASK)
 #define _TIF_POLLING_NRFLAG	+(1 << TIF_POLLING_NRFLAG)
 
 #define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
 #define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
 
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_THREAD_INFO_H */
diff --git a/arch/mn10300/kernel/entry.S b/arch/mn10300/kernel/entry.S
index 8e11f9f..976c540 100644
--- a/arch/mn10300/kernel/entry.S
+++ b/arch/mn10300/kernel/entry.S
@@ -94,6 +94,10 @@ restore_all:
 ###############################################################################
 	ALIGN
 syscall_exit_work:
+	mov	(REG_EPSW,fp),d0
+	and	EPSW_nSL,d0
+	beq	resume_kernel		# returning to supervisor mode
+
 	btst	_TIF_SYSCALL_TRACE,d2
 	beq	work_pending
 	LOCAL_IRQ_ENABLE		# could let syscall_trace_exit() call
diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c
index 4d584ae..ad501ee 100644
--- a/arch/mn10300/kernel/signal.c
+++ b/arch/mn10300/kernel/signal.c
@@ -398,10 +398,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 	regs->d0 = sig;
 	regs->d1 = (long) &frame->info;
 
-	/* the tracer may want to single-step inside the handler */
-	if (test_thread_flag(TIF_SINGLESTEP))
-		ptrace_notify(SIGTRAP);
-
 #if DEBUG_SIG
 	printk(KERN_DEBUG "SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
 	       sig, current->comm, current->pid, frame, regs->pc,
@@ -475,11 +471,6 @@ static void do_signal(struct pt_regs *regs)
 	siginfo_t info;
 	int signr;
 
-	/* we want the common case to go fast, which is why we may in certain
-	 * cases get here from kernel mode */
-	if (!user_mode(regs))
-		return;
-
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 	if (signr > 0) {
 		if (handle_signal(signr, &info, &ka, regs) == 0) {
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index 49765b5..05f2ba4 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -21,6 +21,7 @@ config OPENRISC
 	select GENERIC_CLOCKEVENTS
 	select GENERIC_STRNCPY_FROM_USER
 	select GENERIC_STRNLEN_USER
+	select MODULES_USE_ELF_RELA
 
 config MMU
 	def_bool y
diff --git a/arch/openrisc/include/asm/thread_info.h b/arch/openrisc/include/asm/thread_info.h
index 07a8bc0..07f3212 100644
--- a/arch/openrisc/include/asm/thread_info.h
+++ b/arch/openrisc/include/asm/thread_info.h
@@ -121,7 +121,6 @@ register struct thread_info *current_thread_info_reg asm("r10");
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
-#define _TIF_RESTORE_SIGMASK     (1<<TIF_RESTORE_SIGMASK)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
 
@@ -129,6 +128,8 @@ register struct thread_info *current_thread_info_reg asm("r10");
 /* For OpenRISC, this is anything in the LSW other than syscall trace */
 #define _TIF_WORK_MASK (0xff & ~(_TIF_SYSCALL_TRACE|_TIF_SINGLESTEP))
 
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_THREAD_INFO_H */
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index 3ff21b5..166d991 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -19,6 +19,8 @@ config PARISC
 	select ARCH_HAVE_NMI_SAFE_CMPXCHG
 	select GENERIC_SMP_IDLE_THREAD
 	select GENERIC_STRNCPY_FROM_USER
+	select HAVE_MOD_ARCH_SPECIFIC
+	select MODULES_USE_ELF_RELA
 
 	help
 	  The PA-RISC microprocessor is designed by Hewlett-Packard and used
diff --git a/arch/parisc/hpux/gate.S b/arch/parisc/hpux/gate.S
index 38a1c1b..0114688 100644
--- a/arch/parisc/hpux/gate.S
+++ b/arch/parisc/hpux/gate.S
@@ -71,7 +71,7 @@ ENTRY(hpux_gateway_page)
 	STREG	%r26, TASK_PT_GR26(%r1)	 	/* 1st argument */
 	STREG	%r27, TASK_PT_GR27(%r1)		/* user dp */
 	STREG   %r28, TASK_PT_GR28(%r1)         /* return value 0 */
-	STREG   %r28, TASK_PT_ORIG_R28(%r1)     /* return value 0 (saved for signals) */
+	STREG   %r0, TASK_PT_ORIG_R28(%r1)     /* don't prohibit restarts */
 	STREG   %r29, TASK_PT_GR29(%r1)         /* 8th argument */
 	STREG	%r31, TASK_PT_GR31(%r1)		/* preserve syscall return ptr */
 	
diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h
index 6c6defc..af9cf30 100644
--- a/arch/parisc/include/asm/atomic.h
+++ b/arch/parisc/include/asm/atomic.h
@@ -141,7 +141,7 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
 
 #define atomic_sub_and_test(i,v)	(atomic_sub_return((i),(v)) == 0)
 
-#define ATOMIC_INIT(i)	((atomic_t) { (i) })
+#define ATOMIC_INIT(i)	{ (i) }
 
 #define smp_mb__before_atomic_dec()	smp_mb()
 #define smp_mb__after_atomic_dec()	smp_mb()
@@ -150,7 +150,7 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
 
 #ifdef CONFIG_64BIT
 
-#define ATOMIC64_INIT(i) ((atomic64_t) { (i) })
+#define ATOMIC64_INIT(i) { (i) }
 
 static __inline__ s64
 __atomic64_add_return(s64 i, atomic64_t *v)
diff --git a/arch/parisc/include/asm/module.h b/arch/parisc/include/asm/module.h
index 1f41234..bab37e9 100644
--- a/arch/parisc/include/asm/module.h
+++ b/arch/parisc/include/asm/module.h
@@ -1,21 +1,11 @@
 #ifndef _ASM_PARISC_MODULE_H
 #define _ASM_PARISC_MODULE_H
+
+#include <asm-generic/module.h>
+
 /*
  * This file contains the parisc architecture specific module code.
  */
-#ifdef CONFIG_64BIT
-#define Elf_Shdr Elf64_Shdr
-#define Elf_Sym Elf64_Sym
-#define Elf_Ehdr Elf64_Ehdr
-#define Elf_Addr Elf64_Addr
-#define Elf_Rela Elf64_Rela
-#else
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
-#define Elf_Addr Elf32_Addr
-#define Elf_Rela Elf32_Rela
-#endif
 
 struct unwind_table;
 
diff --git a/arch/parisc/include/asm/thread_info.h b/arch/parisc/include/asm/thread_info.h
index 22b4726..d1fb79a 100644
--- a/arch/parisc/include/asm/thread_info.h
+++ b/arch/parisc/include/asm/thread_info.h
@@ -68,13 +68,16 @@ struct thread_info {
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 #define _TIF_32BIT		(1 << TIF_32BIT)
-#define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 #define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
 #define _TIF_BLOCKSTEP		(1 << TIF_BLOCKSTEP)
 
 #define _TIF_USER_WORK_MASK     (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | \
                                  _TIF_NEED_RESCHED)
+#define _TIF_SYSCALL_TRACE_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP |	\
+				 _TIF_BLOCKSTEP)
+
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
 
 #endif /* __KERNEL__ */
 
diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c
index 47341aa..8823863 100644
--- a/arch/parisc/kernel/pdc_cons.c
+++ b/arch/parisc/kernel/pdc_cons.c
@@ -202,6 +202,7 @@ static int __init pdc_console_tty_driver_init(void)
 	pdc_console_tty_driver->flags = TTY_DRIVER_REAL_RAW |
 		TTY_DRIVER_RESET_TERMIOS;
 	tty_set_operations(pdc_console_tty_driver, &pdc_console_tty_ops);
+	tty_port_link_device(&tty_port, pdc_console_tty_driver, 0);
 
 	err = tty_register_driver(pdc_console_tty_driver);
 	if (err) {
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index d4b94b3..2c05a92 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -309,7 +309,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
 		cregs->ksp = (unsigned long)stack
 			+ (pregs->gr[21] & (THREAD_SIZE - 1));
 		cregs->gr[30] = usp;
-		if (p->personality == PER_HPUX) {
+		if (personality(p->personality) == PER_HPUX) {
 #ifdef CONFIG_HPUX
 			cregs->kpc = (unsigned long) &hpux_child_return;
 #else
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 594459b..5379969 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -113,6 +113,8 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
 		(usp - sigframe_size);
 	DBG(2,"sys_rt_sigreturn: frame is %p\n", frame);
 
+	regs->orig_r28 = 1; /* no restarts for sigreturn */
+
 #ifdef CONFIG_64BIT
 	compat_frame = (struct compat_rt_sigframe __user *)frame;
 	
@@ -437,7 +439,7 @@ give_sigsegv:
  * OK, we're invoking a handler.
  */	
 
-static long
+static void
 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 		struct pt_regs *regs, int in_syscall)
 {
@@ -447,7 +449,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 	
 	/* Set up the stack frame */
 	if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall))
-		return 0;
+		return;
 
 	signal_delivered(sig, info, ka, regs, 
 		test_thread_flag(TIF_SINGLESTEP) ||
@@ -455,13 +457,14 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 
 	DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n",
 		regs->gr[28]);
-
-	return 1;
 }
 
 static inline void
 syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
 {
+	if (regs->orig_r28)
+		return;
+	regs->orig_r28 = 1; /* no more restarts */
 	/* Check the return code */
 	switch (regs->gr[28]) {
 	case -ERESTART_RESTARTBLOCK:
@@ -482,8 +485,6 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
 		 * we have to do is fiddle the return pointer.
 		 */
 		regs->gr[31] -= 8; /* delayed branching */
-		/* Preserve original r28. */
-		regs->gr[28] = regs->orig_r28;
 		break;
 	}
 }
@@ -491,6 +492,9 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
 static inline void
 insert_restart_trampoline(struct pt_regs *regs)
 {
+	if (regs->orig_r28)
+		return;
+	regs->orig_r28 = 1; /* no more restarts */
 	switch(regs->gr[28]) {
 	case -ERESTART_RESTARTBLOCK: {
 		/* Restart the system call - no handlers present */
@@ -525,9 +529,6 @@ insert_restart_trampoline(struct pt_regs *regs)
 		flush_user_icache_range(regs->gr[30], regs->gr[30] + 4);
 
 		regs->gr[31] = regs->gr[30] + 8;
-		/* Preserve original r28. */
-		regs->gr[28] = regs->orig_r28;
-
 		return;
 	}
 	case -ERESTARTNOHAND:
@@ -539,9 +540,6 @@ insert_restart_trampoline(struct pt_regs *regs)
 		 * slot of the branch external instruction.
 		 */
 		regs->gr[31] -= 8;
-		/* Preserve original r28. */
-		regs->gr[28] = regs->orig_r28;
-
 		return;
 	}
 	default:
@@ -570,30 +568,17 @@ do_signal(struct pt_regs *regs, long in_syscall)
 	DBG(1,"\ndo_signal: regs=0x%p, sr7 %#lx, in_syscall=%d\n",
 	       regs, regs->sr[7], in_syscall);
 
-	/* Everyone else checks to see if they are in kernel mode at
-	   this point and exits if that's the case.  I'm not sure why
-	   we would be called in that case, but for some reason we
-	   are. */
-
-	/* May need to force signal if handle_signal failed to deliver */
-	while (1) {
-		signr = get_signal_to_deliver(&info, &ka, regs, NULL);
-		DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]); 
+	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+	DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]); 
 	
-		if (signr <= 0)
-		  break;
-		
+	if (signr > 0) {
 		/* Restart a system call if necessary. */
 		if (in_syscall)
 			syscall_restart(regs, &ka);
 
-		/* Whee!  Actually deliver the signal.  If the
-		   delivery failed, we need to continue to iterate in
-		   this loop so we can deliver the SIGSEGV... */
-		if (handle_signal(signr, &info, &ka, regs, in_syscall))
-			return;
+		handle_signal(signr, &info, &ka, regs, in_syscall);
+		return;
 	}
-	/* end of while(1) looping forever if we can't force a signal */
 
 	/* Did we come from a system call? */
 	if (in_syscall)
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
index c9b9322..7426e40 100644
--- a/arch/parisc/kernel/sys_parisc.c
+++ b/arch/parisc/kernel/sys_parisc.c
@@ -225,12 +225,12 @@ long parisc_personality(unsigned long personality)
 	long err;
 
 	if (personality(current->personality) == PER_LINUX32
-	    && personality == PER_LINUX)
-		personality = PER_LINUX32;
+	    && personality(personality) == PER_LINUX)
+		personality = (personality & ~PER_MASK) | PER_LINUX32;
 
 	err = sys_personality(personality);
-	if (err == PER_LINUX32)
-		err = PER_LINUX;
+	if (personality(err) == PER_LINUX32)
+		err = (err & ~PER_MASK) | PER_LINUX;
 
 	return err;
 }
diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S
index 82a52b2..86742df 100644
--- a/arch/parisc/kernel/syscall.S
+++ b/arch/parisc/kernel/syscall.S
@@ -156,7 +156,7 @@ linux_gateway_entry:
 	STREG	%r26, TASK_PT_GR26(%r1)	 	/* 1st argument */
 	STREG	%r27, TASK_PT_GR27(%r1)		/* user dp */
 	STREG   %r28, TASK_PT_GR28(%r1)         /* return value 0 */
-	STREG   %r28, TASK_PT_ORIG_R28(%r1)     /* return value 0 (saved for signals) */
+	STREG   %r0, TASK_PT_ORIG_R28(%r1)      /* don't prohibit restarts */
 	STREG	%r29, TASK_PT_GR29(%r1)		/* return value 1 */
 	STREG	%r31, TASK_PT_GR31(%r1)		/* preserve syscall return ptr */
 	
@@ -180,9 +180,10 @@ linux_gateway_entry:
 
 	/* Are we being ptraced? */
 	mfctl	%cr30, %r1
-	LDREG	TI_TASK(%r1),%r1
-	ldw	TASK_PTRACE(%r1), %r1
-	bb,<,n	%r1,31,.Ltracesys
+	LDREG	TI_FLAGS(%r1),%r1
+	ldi	_TIF_SYSCALL_TRACE_MASK, %r19
+	and,COND(=) %r1, %r19, %r0
+	b,n	.Ltracesys
 	
 	/* Note!  We cannot use the syscall table that is mapped
 	nearby since the gateway page is mapped execute-only. */
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 352f416..58088dd 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -139,6 +139,8 @@ config PPC
 	select GENERIC_CLOCKEVENTS
 	select GENERIC_STRNCPY_FROM_USER
 	select GENERIC_STRNLEN_USER
+	select HAVE_MOD_ARCH_SPECIFIC
+	select MODULES_USE_ELF_RELA
 
 config EARLY_PRINTK
 	bool
@@ -215,7 +217,8 @@ config ARCH_HIBERNATION_POSSIBLE
 config ARCH_SUSPEND_POSSIBLE
 	def_bool y
 	depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \
-		   (PPC_85xx && !SMP) || PPC_86xx || PPC_PSERIES || 44x || 40x
+		   (PPC_85xx && !PPC_E500MC) || PPC_86xx || PPC_PSERIES \
+		   || 44x || 40x
 
 config PPC_DCR_NATIVE
 	bool
@@ -325,7 +328,8 @@ config SWIOTLB
 
 config HOTPLUG_CPU
 	bool "Support for enabling/disabling CPUs"
-	depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC || PPC_POWERNV)
+	depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || \
+	PPC_PMAC || PPC_POWERNV || (PPC_85xx && !PPC_E500MC))
 	---help---
 	  Say Y here to be able to disable and re-enable individual
 	  CPUs at runtime on SMP machines.
diff --git a/arch/powerpc/boot/dts/fsl/e500mc_power_isa.dtsi b/arch/powerpc/boot/dts/fsl/e500mc_power_isa.dtsi
new file mode 100644
index 0000000..870c653
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/e500mc_power_isa.dtsi
@@ -0,0 +1,58 @@
+/*
+ * e500mc Power ISA Device Tree Source (include)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/ {
+	cpus {
+		power-isa-version = "2.06";
+		power-isa-b;		// Base
+		power-isa-e;		// Embedded
+		power-isa-atb;		// Alternate Time Base
+		power-isa-cs;		// Cache Specification
+		power-isa-ds;		// Decorated Storage
+		power-isa-e.ed;		// Embedded.Enhanced Debug
+		power-isa-e.pd;		// Embedded.External PID
+		power-isa-e.hv;		// Embedded.Hypervisor
+		power-isa-e.le;		// Embedded.Little-Endian
+		power-isa-e.pm;		// Embedded.Performance Monitor
+		power-isa-e.pc;		// Embedded.Processor Control
+		power-isa-ecl;		// Embedded Cache Locking
+		power-isa-exp;		// External Proxy
+		power-isa-fp;		// Floating Point
+		power-isa-fp.r;		// Floating Point.Record
+		power-isa-mmc;		// Memory Coherence
+		power-isa-scpm;		// Store Conditional Page Mobility
+		power-isa-wt;		// Wait
+		mmu-type = "power-embedded";
+	};
+};
diff --git a/arch/powerpc/boot/dts/fsl/e500v2_power_isa.dtsi b/arch/powerpc/boot/dts/fsl/e500v2_power_isa.dtsi
new file mode 100644
index 0000000..f492814
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/e500v2_power_isa.dtsi
@@ -0,0 +1,52 @@
+/*
+ * e500v2 Power ISA Device Tree Source (include)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/ {
+	cpus {
+		power-isa-version = "2.03";
+		power-isa-b;		// Base
+		power-isa-e;		// Embedded
+		power-isa-atb;		// Alternate Time Base
+		power-isa-cs;		// Cache Specification
+		power-isa-e.le;		// Embedded.Little-Endian
+		power-isa-e.pm;		// Embedded.Performance Monitor
+		power-isa-ecl;		// Embedded Cache Locking
+		power-isa-mmc;		// Memory Coherence
+		power-isa-sp;		// Signal Processing Engine
+		power-isa-sp.fd;	// SPE.Embedded Float Scalar Double
+		power-isa-sp.fs;	// SPE.Embedded Float Scalar Single
+		power-isa-sp.fv;	// SPE.Embedded Float Vector
+		mmu-type = "power-embedded";
+	};
+};
diff --git a/arch/powerpc/boot/dts/fsl/e5500_power_isa.dtsi b/arch/powerpc/boot/dts/fsl/e5500_power_isa.dtsi
new file mode 100644
index 0000000..3230212
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/e5500_power_isa.dtsi
@@ -0,0 +1,59 @@
+/*
+ * e5500 Power ISA Device Tree Source (include)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/ {
+	cpus {
+		power-isa-version = "2.06";
+		power-isa-b;		// Base
+		power-isa-e;		// Embedded
+		power-isa-atb;		// Alternate Time Base
+		power-isa-cs;		// Cache Specification
+		power-isa-ds;		// Decorated Storage
+		power-isa-e.ed;		// Embedded.Enhanced Debug
+		power-isa-e.pd;		// Embedded.External PID
+		power-isa-e.hv;		// Embedded.Hypervisor
+		power-isa-e.le;		// Embedded.Little-Endian
+		power-isa-e.pm;		// Embedded.Performance Monitor
+		power-isa-e.pc;		// Embedded.Processor Control
+		power-isa-ecl;		// Embedded Cache Locking
+		power-isa-exp;		// External Proxy
+		power-isa-fp;		// Floating Point
+		power-isa-fp.r;		// Floating Point.Record
+		power-isa-mmc;		// Memory Coherence
+		power-isa-scpm;		// Store Conditional Page Mobility
+		power-isa-wt;		// Wait
+		power-isa-64;		// 64-bit
+		mmu-type = "power-embedded";
+	};
+};
diff --git a/arch/powerpc/boot/dts/fsl/mpc8536si-pre.dtsi b/arch/powerpc/boot/dts/fsl/mpc8536si-pre.dtsi
index 7de45a7..152906f 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8536si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8536si-pre.dtsi
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
 	compatible = "fsl,MPC8536";
 	#address-cells = <2>;
diff --git a/arch/powerpc/boot/dts/fsl/mpc8544si-pre.dtsi b/arch/powerpc/boot/dts/fsl/mpc8544si-pre.dtsi
index 8777f92..5a69baf 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8544si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8544si-pre.dtsi
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
 	compatible = "fsl,MPC8544";
 	#address-cells = <2>;
diff --git a/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi b/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi
index 720422d..fc1ce97 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
 	compatible = "fsl,MPC8548";
 	#address-cells = <2>;
diff --git a/arch/powerpc/boot/dts/fsl/mpc8568si-pre.dtsi b/arch/powerpc/boot/dts/fsl/mpc8568si-pre.dtsi
index eacd62c..122ca3b 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8568si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8568si-pre.dtsi
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
 	compatible = "fsl,MPC8568";
 	#address-cells = <2>;
diff --git a/arch/powerpc/boot/dts/fsl/mpc8569si-pre.dtsi b/arch/powerpc/boot/dts/fsl/mpc8569si-pre.dtsi
index b07064d..2cd15a2 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8569si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8569si-pre.dtsi
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
 	compatible = "fsl,MPC8569";
 	#address-cells = <2>;
diff --git a/arch/powerpc/boot/dts/fsl/mpc8572si-pre.dtsi b/arch/powerpc/boot/dts/fsl/mpc8572si-pre.dtsi
index ca18832..28c2a86 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8572si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8572si-pre.dtsi
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
 	compatible = "fsl,MPC8572";
 	#address-cells = <2>;
diff --git a/arch/powerpc/boot/dts/fsl/p1010si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p1010si-pre.dtsi
index 7354a8f..6e76f9b 100644
--- a/arch/powerpc/boot/dts/fsl/p1010si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1010si-pre.dtsi
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
 	compatible = "fsl,P1010";
 	#address-cells = <2>;
diff --git a/arch/powerpc/boot/dts/fsl/p1020si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p1020si-pre.dtsi
index 6f0376e..fed9c4c 100644
--- a/arch/powerpc/boot/dts/fsl/p1020si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1020si-pre.dtsi
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
 	compatible = "fsl,P1020";
 	#address-cells = <2>;
diff --git a/arch/powerpc/boot/dts/fsl/p1021si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p1021si-pre.dtsi
index 4abd54b..36161b5 100644
--- a/arch/powerpc/boot/dts/fsl/p1021si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1021si-pre.dtsi
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
 	compatible = "fsl,P1021";
 	#address-cells = <2>;
diff --git a/arch/powerpc/boot/dts/fsl/p1022si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p1022si-pre.dtsi
index e930f4f..1956dea 100644
--- a/arch/powerpc/boot/dts/fsl/p1022si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1022si-pre.dtsi
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
 	compatible = "fsl,P1022";
 	#address-cells = <2>;
diff --git a/arch/powerpc/boot/dts/fsl/p1023si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p1023si-pre.dtsi
index ac45f6d..132a152 100644
--- a/arch/powerpc/boot/dts/fsl/p1023si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1023si-pre.dtsi
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
 	compatible = "fsl,P1023";
 	#address-cells = <2>;
diff --git a/arch/powerpc/boot/dts/fsl/p2020si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p2020si-pre.dtsi
index 3213288..42bf3c6 100644
--- a/arch/powerpc/boot/dts/fsl/p2020si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2020si-pre.dtsi
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
 	compatible = "fsl,P2020";
 	#address-cells = <2>;
diff --git a/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi
index 2d0a40d..7a2697d 100644
--- a/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500mc_power_isa.dtsi"
+
 / {
 	compatible = "fsl,P2041";
 	#address-cells = <2>;
diff --git a/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi
index 136def3..c9ca2c3 100644
--- a/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500mc_power_isa.dtsi"
+
 / {
 	compatible = "fsl,P3041";
 	#address-cells = <2>;
diff --git a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
index 8d35d2c..4f9c9f6 100644
--- a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
@@ -345,6 +345,13 @@
 /include/ "qoriq-duart-1.dtsi"
 /include/ "qoriq-gpio-0.dtsi"
 /include/ "qoriq-usb2-mph-0.dtsi"
+	usb@210000 {
+		compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
+		port0;
+	};
 /include/ "qoriq-usb2-dr-0.dtsi"
+	usb@211000 {
+		compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
+	};
 /include/ "qoriq-sec4.0-0.dtsi"
 };
diff --git a/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi
index b9556ee..493d9a0 100644
--- a/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500mc_power_isa.dtsi"
+
 / {
 	compatible = "fsl,P4080";
 	#address-cells = <2>;
diff --git a/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi
index ae823a4..0a198b0 100644
--- a/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e5500_power_isa.dtsi"
+
 / {
 	compatible = "fsl,P5020";
 	#address-cells = <2>;
diff --git a/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
new file mode 100644
index 0000000..db2c9a7
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
@@ -0,0 +1,320 @@
+/*
+ * P5040 Silicon/SoC Device Tree Source (post include)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * This software is provided by Freescale Semiconductor "as is" and any
+ * express or implied warranties, including, but not limited to, the implied
+ * warranties of merchantability and fitness for a particular purpose are
+ * disclaimed. In no event shall Freescale Semiconductor be liable for any
+ * direct, indirect, incidental, special, exemplary, or consequential damages
+ * (including, but not limited to, procurement of substitute goods or services;
+ * loss of use, data, or profits; or business interruption) however caused and
+ * on any theory of liability, whether in contract, strict liability, or tort
+ * (including negligence or otherwise) arising in any way out of the use of this
+ * software, even if advised of the possibility of such damage.
+ */
+
+&lbc {
+	compatible = "fsl,p5040-elbc", "fsl,elbc", "simple-bus";
+	interrupts = <25 2 0 0>;
+	#address-cells = <2>;
+	#size-cells = <1>;
+};
+
+/* controller at 0x200000 */
+&pci0 {
+	compatible = "fsl,p5040-pcie", "fsl,qoriq-pcie-v2.4";
+	device_type = "pci";
+	#size-cells = <2>;
+	#address-cells = <3>;
+	bus-range = <0x0 0xff>;
+	clock-frequency = <33333333>;
+	interrupts = <16 2 1 15>;
+	pcie@0 {
+		reg = <0 0 0 0 0>;
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		device_type = "pci";
+		interrupts = <16 2 1 15>;
+		interrupt-map-mask = <0xf800 0 0 7>;
+		interrupt-map = <
+			/* IDSEL 0x0 */
+			0000 0 0 1 &mpic 40 1 0 0
+			0000 0 0 2 &mpic 1 1 0 0
+			0000 0 0 3 &mpic 2 1 0 0
+			0000 0 0 4 &mpic 3 1 0 0
+			>;
+	};
+};
+
+/* controller at 0x201000 */
+&pci1 {
+	compatible = "fsl,p5040-pcie", "fsl,qoriq-pcie-v2.4";
+	device_type = "pci";
+	#size-cells = <2>;
+	#address-cells = <3>;
+	bus-range = <0 0xff>;
+	clock-frequency = <33333333>;
+	interrupts = <16 2 1 14>;
+	pcie@0 {
+		reg = <0 0 0 0 0>;
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		device_type = "pci";
+		interrupts = <16 2 1 14>;
+		interrupt-map-mask = <0xf800 0 0 7>;
+		interrupt-map = <
+			/* IDSEL 0x0 */
+			0000 0 0 1 &mpic 41 1 0 0
+			0000 0 0 2 &mpic 5 1 0 0
+			0000 0 0 3 &mpic 6 1 0 0
+			0000 0 0 4 &mpic 7 1 0 0
+			>;
+	};
+};
+
+/* controller at 0x202000 */
+&pci2 {
+	compatible = "fsl,p5040-pcie", "fsl,qoriq-pcie-v2.4";
+	device_type = "pci";
+	#size-cells = <2>;
+	#address-cells = <3>;
+	bus-range = <0x0 0xff>;
+	clock-frequency = <33333333>;
+	interrupts = <16 2 1 13>;
+	pcie@0 {
+		reg = <0 0 0 0 0>;
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		device_type = "pci";
+		interrupts = <16 2 1 13>;
+		interrupt-map-mask = <0xf800 0 0 7>;
+		interrupt-map = <
+			/* IDSEL 0x0 */
+			0000 0 0 1 &mpic 42 1 0 0
+			0000 0 0 2 &mpic 9 1 0 0
+			0000 0 0 3 &mpic 10 1 0 0
+			0000 0 0 4 &mpic 11 1 0 0
+			>;
+	};
+};
+
+&dcsr {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	compatible = "fsl,dcsr", "simple-bus";
+
+	dcsr-epu@0 {
+		compatible = "fsl,dcsr-epu";
+		interrupts = <52 2 0 0
+			      84 2 0 0
+			      85 2 0 0>;
+		reg = <0x0 0x1000>;
+	};
+	dcsr-npc {
+		compatible = "fsl,dcsr-npc";
+		reg = <0x1000 0x1000 0x1000000 0x8000>;
+	};
+	dcsr-nxc@2000 {
+		compatible = "fsl,dcsr-nxc";
+		reg = <0x2000 0x1000>;
+	};
+	dcsr-corenet {
+		compatible = "fsl,dcsr-corenet";
+		reg = <0x8000 0x1000 0xB0000 0x1000>;
+	};
+	dcsr-dpaa@9000 {
+		compatible = "fsl,p5040-dcsr-dpaa", "fsl,dcsr-dpaa";
+		reg = <0x9000 0x1000>;
+	};
+	dcsr-ocn@11000 {
+		compatible = "fsl,p5040-dcsr-ocn", "fsl,dcsr-ocn";
+		reg = <0x11000 0x1000>;
+	};
+	dcsr-ddr@12000 {
+		compatible = "fsl,dcsr-ddr";
+		dev-handle = <&ddr1>;
+		reg = <0x12000 0x1000>;
+	};
+	dcsr-ddr@13000 {
+		compatible = "fsl,dcsr-ddr";
+		dev-handle = <&ddr2>;
+		reg = <0x13000 0x1000>;
+	};
+	dcsr-nal@18000 {
+		compatible = "fsl,p5040-dcsr-nal", "fsl,dcsr-nal";
+		reg = <0x18000 0x1000>;
+	};
+	dcsr-rcpm@22000 {
+		compatible = "fsl,p5040-dcsr-rcpm", "fsl,dcsr-rcpm";
+		reg = <0x22000 0x1000>;
+	};
+	dcsr-cpu-sb-proxy@40000 {
+		compatible = "fsl,dcsr-e5500-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+		cpu-handle = <&cpu0>;
+		reg = <0x40000 0x1000>;
+	};
+	dcsr-cpu-sb-proxy@41000 {
+		compatible = "fsl,dcsr-e5500-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+		cpu-handle = <&cpu1>;
+		reg = <0x41000 0x1000>;
+	};
+	dcsr-cpu-sb-proxy@42000 {
+		compatible = "fsl,dcsr-e5500-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+		cpu-handle = <&cpu2>;
+		reg = <0x42000 0x1000>;
+	};
+	dcsr-cpu-sb-proxy@43000 {
+		compatible = "fsl,dcsr-e5500-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+		cpu-handle = <&cpu3>;
+		reg = <0x43000 0x1000>;
+	};
+};
+
+&soc {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	device_type = "soc";
+	compatible = "simple-bus";
+
+	soc-sram-error {
+		compatible = "fsl,soc-sram-error";
+		interrupts = <16 2 1 29>;
+	};
+
+	corenet-law@0 {
+		compatible = "fsl,corenet-law";
+		reg = <0x0 0x1000>;
+		fsl,num-laws = <32>;
+	};
+
+	ddr1: memory-controller@8000 {
+		compatible = "fsl,qoriq-memory-controller-v4.5", "fsl,qoriq-memory-controller";
+		reg = <0x8000 0x1000>;
+		interrupts = <16 2 1 23>;
+	};
+
+	ddr2: memory-controller@9000 {
+		compatible = "fsl,qoriq-memory-controller-v4.5","fsl,qoriq-memory-controller";
+		reg = <0x9000 0x1000>;
+		interrupts = <16 2 1 22>;
+	};
+
+	cpc: l3-cache-controller@10000 {
+		compatible = "fsl,p5040-l3-cache-controller", "fsl,p4080-l3-cache-controller", "cache";
+		reg = <0x10000 0x1000
+		       0x11000 0x1000>;
+		interrupts = <16 2 1 27
+			      16 2 1 26>;
+	};
+
+	corenet-cf@18000 {
+		compatible = "fsl,corenet-cf";
+		reg = <0x18000 0x1000>;
+		interrupts = <16 2 1 31>;
+		fsl,ccf-num-csdids = <32>;
+		fsl,ccf-num-snoopids = <32>;
+	};
+
+	iommu@20000 {
+		compatible = "fsl,pamu-v1.0", "fsl,pamu";
+		reg = <0x20000 0x5000>;
+		interrupts = <
+			24 2 0 0
+			16 2 1 30>;
+	};
+
+/include/ "qoriq-mpic.dtsi"
+
+	guts: global-utilities@e0000 {
+		compatible = "fsl,p5040-device-config", "fsl,qoriq-device-config-1.0";
+		reg = <0xe0000 0xe00>;
+		fsl,has-rstcr;
+		#sleep-cells = <1>;
+		fsl,liodn-bits = <12>;
+	};
+
+	pins: global-utilities@e0e00 {
+		compatible = "fsl,p5040-pin-control", "fsl,qoriq-pin-control-1.0";
+		reg = <0xe0e00 0x200>;
+		#sleep-cells = <2>;
+	};
+
+	clockgen: global-utilities@e1000 {
+		compatible = "fsl,p5040-clockgen", "fsl,qoriq-clockgen-1.0";
+		reg = <0xe1000 0x1000>;
+		clock-frequency = <0>;
+	};
+
+	rcpm: global-utilities@e2000 {
+		compatible = "fsl,p5040-rcpm", "fsl,qoriq-rcpm-1.0";
+		reg = <0xe2000 0x1000>;
+		#sleep-cells = <1>;
+	};
+
+	sfp: sfp@e8000 {
+		compatible = "fsl,p5040-sfp", "fsl,qoriq-sfp-1.0";
+		reg	   = <0xe8000 0x1000>;
+	};
+
+	serdes: serdes@ea000 {
+		compatible = "fsl,p5040-serdes";
+		reg	   = <0xea000 0x1000>;
+	};
+
+/include/ "qoriq-dma-0.dtsi"
+/include/ "qoriq-dma-1.dtsi"
+/include/ "qoriq-espi-0.dtsi"
+	spi@110000 {
+		fsl,espi-num-chipselects = <4>;
+	};
+
+/include/ "qoriq-esdhc-0.dtsi"
+	sdhc@114000 {
+		sdhci,auto-cmd12;
+	};
+
+/include/ "qoriq-i2c-0.dtsi"
+/include/ "qoriq-i2c-1.dtsi"
+/include/ "qoriq-duart-0.dtsi"
+/include/ "qoriq-duart-1.dtsi"
+/include/ "qoriq-gpio-0.dtsi"
+/include/ "qoriq-usb2-mph-0.dtsi"
+		usb0: usb@210000 {
+			compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
+			phy_type = "utmi";
+			port0;
+		};
+
+/include/ "qoriq-usb2-dr-0.dtsi"
+		usb1: usb@211000 {
+			compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
+			dr_mode = "host";
+			phy_type = "utmi";
+		};
+
+/include/ "qoriq-sata2-0.dtsi"
+/include/ "qoriq-sata2-1.dtsi"
+/include/ "qoriq-sec5.2-0.dtsi"
+};
diff --git a/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi
new file mode 100644
index 0000000..40ca943
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi
@@ -0,0 +1,114 @@
+/*
+ * P5040 Silicon/SoC Device Tree Source (pre include)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * This software is provided by Freescale Semiconductor "as is" and any
+ * express or implied warranties, including, but not limited to, the implied
+ * warranties of merchantability and fitness for a particular purpose are
+ * disclaimed. In no event shall Freescale Semiconductor be liable for any
+ * direct, indirect, incidental, special, exemplary, or consequential damages
+ * (including, but not limited to, procurement of substitute goods or services;
+ * loss of use, data, or profits; or business interruption) however caused and
+ * on any theory of liability, whether in contract, strict liability, or tort
+ * (including negligence or otherwise) arising in any way out of the use of this
+ * software, even if advised of the possibility of such damage.
+ */
+
+/dts-v1/;
+
+/include/ "e5500_power_isa.dtsi"
+
+/ {
+	compatible = "fsl,P5040";
+	#address-cells = <2>;
+	#size-cells = <2>;
+	interrupt-parent = <&mpic>;
+
+	aliases {
+		ccsr = &soc;
+		dcsr = &dcsr;
+
+		serial0 = &serial0;
+		serial1 = &serial1;
+		serial2 = &serial2;
+		serial3 = &serial3;
+		pci0 = &pci0;
+		pci1 = &pci1;
+		pci2 = &pci2;
+		usb0 = &usb0;
+		usb1 = &usb1;
+		dma0 = &dma0;
+		dma1 = &dma1;
+		sdhc = &sdhc;
+		msi0 = &msi0;
+		msi1 = &msi1;
+		msi2 = &msi2;
+
+		crypto = &crypto;
+		sec_jr0 = &sec_jr0;
+		sec_jr1 = &sec_jr1;
+		sec_jr2 = &sec_jr2;
+		sec_jr3 = &sec_jr3;
+		rtic_a = &rtic_a;
+		rtic_b = &rtic_b;
+		rtic_c = &rtic_c;
+		rtic_d = &rtic_d;
+		sec_mon = &sec_mon;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu0: PowerPC,e5500@0 {
+			device_type = "cpu";
+			reg = <0>;
+			next-level-cache = <&L2_0>;
+			L2_0: l2-cache {
+				next-level-cache = <&cpc>;
+			};
+		};
+		cpu1: PowerPC,e5500@1 {
+			device_type = "cpu";
+			reg = <1>;
+			next-level-cache = <&L2_1>;
+			L2_1: l2-cache {
+				next-level-cache = <&cpc>;
+			};
+		};
+		cpu2: PowerPC,e5500@2 {
+			device_type = "cpu";
+			reg = <2>;
+			next-level-cache = <&L2_2>;
+			L2_2: l2-cache {
+				next-level-cache = <&cpc>;
+			};
+		};
+		cpu3: PowerPC,e5500@3 {
+			device_type = "cpu";
+			reg = <3>;
+			next-level-cache = <&L2_3>;
+			L2_3: l2-cache {
+				next-level-cache = <&cpc>;
+			};
+		};
+	};
+};
diff --git a/arch/powerpc/boot/dts/fsl/qoriq-sec5.2-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-sec5.2-0.dtsi
new file mode 100644
index 0000000..7b2ab8a
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/qoriq-sec5.2-0.dtsi
@@ -0,0 +1,118 @@
+/*
+ * QorIQ Sec/Crypto 5.2 device tree stub [ controller @ offset 0x300000 ]
+ *
+ * Copyright 2011-2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+crypto: crypto@300000 {
+	compatible = "fsl,sec-v5.2", "fsl,sec-v5.0", "fsl,sec-v4.0";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	reg		 = <0x300000 0x10000>;
+	ranges		 = <0 0x300000 0x10000>;
+	interrupts	 = <92 2 0 0>;
+
+	sec_jr0: jr@1000 {
+		compatible = "fsl,sec-v5.2-job-ring",
+			     "fsl,sec-v5.0-job-ring",
+			     "fsl,sec-v4.0-job-ring";
+		reg = <0x1000 0x1000>;
+		interrupts = <88 2 0 0>;
+	};
+
+	sec_jr1: jr@2000 {
+		compatible = "fsl,sec-v5.2-job-ring",
+			     "fsl,sec-v5.0-job-ring",
+			     "fsl,sec-v4.0-job-ring";
+		reg = <0x2000 0x1000>;
+		interrupts = <89 2 0 0>;
+	};
+
+	sec_jr2: jr@3000 {
+		compatible = "fsl,sec-v5.2-job-ring",
+			     "fsl,sec-v5.0-job-ring",
+			     "fsl,sec-v4.0-job-ring";
+		reg = <0x3000 0x1000>;
+		interrupts = <90 2 0 0>;
+	};
+
+	sec_jr3: jr@4000 {
+		compatible = "fsl,sec-v5.2-job-ring",
+			     "fsl,sec-v5.0-job-ring",
+			     "fsl,sec-v4.0-job-ring";
+		reg = <0x4000 0x1000>;
+		interrupts = <91 2 0 0>;
+	};
+
+	rtic@6000 {
+		compatible = "fsl,sec-v5.2-rtic",
+			     "fsl,sec-v5.0-rtic",
+			     "fsl,sec-v4.0-rtic";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x6000 0x100>;
+		ranges = <0x0 0x6100 0xe00>;
+
+		rtic_a: rtic-a@0 {
+			compatible = "fsl,sec-v5.2-rtic-memory",
+				     "fsl,sec-v5.0-rtic-memory",
+				     "fsl,sec-v4.0-rtic-memory";
+			reg = <0x00 0x20 0x100 0x80>;
+		};
+
+		rtic_b: rtic-b@20 {
+			compatible = "fsl,sec-v5.2-rtic-memory",
+				     "fsl,sec-v5.0-rtic-memory",
+				     "fsl,sec-v4.0-rtic-memory";
+			reg = <0x20 0x20 0x200 0x80>;
+		};
+
+		rtic_c: rtic-c@40 {
+			compatible = "fsl,sec-v5.2-rtic-memory",
+				     "fsl,sec-v5.0-rtic-memory",
+				     "fsl,sec-v4.0-rtic-memory";
+			reg = <0x40 0x20 0x300 0x80>;
+		};
+
+		rtic_d: rtic-d@60 {
+			compatible = "fsl,sec-v5.2-rtic-memory",
+				     "fsl,sec-v5.0-rtic-memory",
+				     "fsl,sec-v4.0-rtic-memory";
+			reg = <0x60 0x20 0x500 0x80>;
+		};
+	};
+};
+
+sec_mon: sec_mon@314000 {
+	compatible = "fsl,sec-v5.2-mon", "fsl,sec-v5.0-mon", "fsl,sec-v4.0-mon";
+	reg = <0x314000 0x1000>;
+	interrupts = <93 2 0 0>;
+};
diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts
index f99fb11..2d31863 100644
--- a/arch/powerpc/boot/dts/mpc8540ads.dts
+++ b/arch/powerpc/boot/dts/mpc8540ads.dts
@@ -11,6 +11,8 @@
 
 /dts-v1/;
 
+/include/ "fsl/e500v2_power_isa.dtsi"
+
 / {
 	model = "MPC8540ADS";
 	compatible = "MPC8540ADS", "MPC85xxADS";
diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts
index 0f5e939..1c03c26 100644
--- a/arch/powerpc/boot/dts/mpc8541cds.dts
+++ b/arch/powerpc/boot/dts/mpc8541cds.dts
@@ -11,6 +11,8 @@
 
 /dts-v1/;
 
+/include/ "fsl/e500v2_power_isa.dtsi"
+
 / {
 	model = "MPC8541CDS";
 	compatible = "MPC8541CDS", "MPC85xxCDS";
diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts
index fe10438..36a7ea1 100644
--- a/arch/powerpc/boot/dts/mpc8555cds.dts
+++ b/arch/powerpc/boot/dts/mpc8555cds.dts
@@ -11,6 +11,8 @@
 
 /dts-v1/;
 
+/include/ "fsl/e500v2_power_isa.dtsi"
+
 / {
 	model = "MPC8555CDS";
 	compatible = "MPC8555CDS", "MPC85xxCDS";
diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts
index 6e85e1b..1a43f5a 100644
--- a/arch/powerpc/boot/dts/mpc8560ads.dts
+++ b/arch/powerpc/boot/dts/mpc8560ads.dts
@@ -11,6 +11,8 @@
 
 /dts-v1/;
 
+/include/ "fsl/e500v2_power_isa.dtsi"
+
 / {
 	model = "MPC8560ADS";
 	compatible = "MPC8560ADS", "MPC85xxADS";
diff --git a/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts b/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts
deleted file mode 100644
index 41b4585..0000000
--- a/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * P1020 RDB  Core0 Device Tree Source in CAMP mode.
- *
- * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
- * can be shared, all the other devices must be assigned to one core only.
- * This dts file allows core0 to have memory, l2, i2c, spi, gpio, tdm, dma, usb,
- * eth1, eth2, sdhc, crypto, global-util, message, pci0, pci1, msi.
- *
- * Please note to add "-b 0" for core0's dts compiling.
- *
- * Copyright 2011 Freescale Semiconductor Inc.
- *
- * 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.
- */
-
-/include/ "p1020rdb.dts"
-
-/ {
-	model = "fsl,P1020RDB";
-	compatible = "fsl,P1020RDB", "fsl,MPC85XXRDB-CAMP";
-
-	aliases {
-		ethernet1 = &enet1;
-		ethernet2 = &enet2;
-		serial0 = &serial0;
-		pci0 = &pci0;
-		pci1 = &pci1;
-	};
-
-	cpus {
-		PowerPC,P1020@1 {
-			status = "disabled";
-		};
-	};
-
-	memory {
-		device_type = "memory";
-	};
-
-	localbus@ffe05000 {
-		status = "disabled";
-	};
-
-	soc@ffe00000 {
-		serial1: serial@4600 {
-			status = "disabled";
-		};
-
-		enet0: ethernet@b0000 {
-			status = "disabled";
-		};
-
-		mpic: pic@40000 {
-			protected-sources = <
-			42 29 30 34	/* serial1, enet0-queue-group0 */
-			17 18 24 45	/* enet0-queue-group1, crypto */
-			>;
-		};
-	};
-};
diff --git a/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts b/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts
deleted file mode 100644
index 5174538..0000000
--- a/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * P1020 RDB Core1 Device Tree Source in CAMP mode.
- *
- * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
- * can be shared, all the other devices must be assigned to one core only.
- * This dts allows core1 to have l2, eth0, crypto.
- *
- * Please note to add "-b 1" for core1's dts compiling.
- *
- * Copyright 2011 Freescale Semiconductor Inc.
- *
- * 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.
- */
-
-/include/ "p1020rdb.dts"
-
-/ {
-	model = "fsl,P1020RDB";
-	compatible = "fsl,P1020RDB", "fsl,MPC85XXRDB-CAMP";
-
-	aliases {
-		ethernet0 = &enet0;
-		serial0 = &serial1;
-		};
-
-	cpus {
-		PowerPC,P1020@0 {
-			status = "disabled";
-		};
-	};
-
-	memory {
-		device_type = "memory";
-	};
-
-	localbus@ffe05000 {
-		status = "disabled";
-	};
-
-	soc@ffe00000 {
-		ecm-law@0 {
-			status = "disabled";
-		};
-
-		ecm@1000 {
-			status = "disabled";
-		};
-
-		memory-controller@2000 {
-			status = "disabled";
-		};
-
-		i2c@3000 {
-			status = "disabled";
-		};
-
-		i2c@3100 {
-			status = "disabled";
-		};
-
-		serial0: serial@4500 {
-			status = "disabled";
-		};
-
-		spi@7000 {
-			status = "disabled";
-		};
-
-		gpio: gpio-controller@f000 {
-			status = "disabled";
-		};
-
-		dma@21300 {
-			status = "disabled";
-		};
-
-		mdio@24000 {
-			status = "disabled";
-		};
-
-		mdio@25000 {
-			status = "disabled";
-		};
-
-		enet1: ethernet@b1000 {
-			status = "disabled";
-		};
-
-		enet2: ethernet@b2000 {
-			status = "disabled";
-		};
-
-		usb@22000 {
-			status = "disabled";
-		};
-
-		sdhci@2e000 {
-			status = "disabled";
-		};
-
-		mpic: pic@40000 {
-			protected-sources = <
-			16 		/* ecm, mem, L2, pci0, pci1 */
-			43 42 59	/* i2c, serial0, spi */
-			47 63 62 	/* gpio, tdm */
-			20 21 22 23	/* dma */
-			03 02 		/* mdio */
-			35 36 40	/* enet1-queue-group0 */
-			51 52 67	/* enet1-queue-group1 */
-			31 32 33	/* enet2-queue-group0 */
-			25 26 27	/* enet2-queue-group1 */
-			28 72 58 	/* usb, sdhci, crypto */
-			0xb0 0xb1 0xb2	/* message */
-			0xb3 0xb4 0xb5
-			0xb6 0xb7
-			0xe0 0xe1 0xe2	/* msi */
-			0xe3 0xe4 0xe5
-			0xe6 0xe7		/* sdhci, crypto , pci */
-			>;
-		};
-
-		msi@41600 {
-			status = "disabled";
-		};
-
-		global-utilities@e0000 {	//global utilities block
-			status = "disabled";
-		};
-	};
-
-	pci0: pcie@ffe09000 {
-		status = "disabled";
-	};
-
-	pci1: pcie@ffe0a000 {
-		status = "disabled";
-	};
-};
diff --git a/arch/powerpc/boot/dts/p1022rdk.dts b/arch/powerpc/boot/dts/p1022rdk.dts
new file mode 100644
index 0000000..51d82de
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1022rdk.dts
@@ -0,0 +1,188 @@
+/*
+ * P1022 RDK 32-bit Physical Address Map Device Tree Source
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p1022si-pre.dtsi"
+/ {
+	model = "fsl,P1022RDK";
+	compatible = "fsl,P1022RDK";
+
+	memory {
+		device_type = "memory";
+	};
+
+	board_lbc: lbc: localbus@ffe05000 {
+		/* The P1022 RDK does not have any localbus devices */
+		status = "disabled";
+	};
+
+	board_soc: soc: soc@ffe00000 {
+		ranges = <0x0 0x0 0xffe00000 0x100000>;
+
+		i2c@3100 {
+			wm8960:codec@1a {
+				compatible = "wlf,wm8960";
+				reg = <0x1a>;
+				/* MCLK source is a stand-alone oscillator */
+				clock-frequency = <12288000>;
+			};
+			rtc@68 {
+				compatible = "stm,m41t62";
+				reg = <0x68>;
+			};
+			adt7461@4c{
+				compatible = "adi,adt7461";
+				reg = <0x4c>;
+			};
+			zl6100@21{
+				compatible = "isil,zl6100";
+				reg = <0x21>;
+			};
+			zl6100@24{
+				compatible = "isil,zl6100";
+				reg = <0x24>;
+			};
+			zl6100@26{
+				compatible = "isil,zl6100";
+				reg = <0x26>;
+			};
+			zl6100@29{
+				compatible = "isil,zl6100";
+				reg = <0x29>;
+			};
+		};
+
+		spi@7000 {
+			flash@0 {
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "spansion,m25p80";
+				reg = <0>;
+				spi-max-frequency = <1000000>;
+				partition@0 {
+					label = "full-spi-flash";
+					reg = <0x00000000 0x00100000>;
+				};
+			};
+		};
+
+		ssi@15000 {
+			fsl,mode = "i2s-slave";
+			codec-handle = <&wm8960>;
+		};
+
+		usb@22000 {
+			phy_type = "ulpi";
+		};
+
+		usb@23000 {
+			phy_type = "ulpi";
+		};
+
+		mdio@24000 {
+			phy0: ethernet-phy@0 {
+				interrupts = <3 1 0 0>;
+				reg = <0x1>;
+			};
+			phy1: ethernet-phy@1 {
+				interrupts = <9 1 0 0>;
+				reg = <0x2>;
+			};
+		};
+
+		mdio@25000 {
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		ethernet@b0000 {
+			phy-handle = <&phy0>;
+			phy-connection-type = "rgmii-id";
+		};
+
+		ethernet@b1000 {
+			phy-handle = <&phy1>;
+			tbi-handle = <&tbi0>;
+			phy-connection-type = "sgmii";
+		};
+	};
+
+	pci0: pcie@ffe09000 {
+		ranges = <0x2000000 0x0 0xe0000000 0 0xa0000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+		reg = <0x0 0xffe09000 0 0x1000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci1: pcie@ffe0a000 {
+		ranges = <0x2000000 0x0 0xe0000000 0 0xc0000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>;
+		reg = <0 0xffe0a000 0 0x1000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci2: pcie@ffe0b000 {
+		ranges = <0x2000000 0x0 0xe0000000 0 0x80000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
+		reg = <0 0xffe0b000 0 0x1000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+};
+
+/include/ "fsl/p1022si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts
deleted file mode 100644
index 66aac86..0000000
--- a/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * P2020 RDB  Core0 Device Tree Source in CAMP mode.
- *
- * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
- * can be shared, all the other devices must be assigned to one core only.
- * This dts file allows core0 to have memory, l2, i2c, spi, gpio, dma1, usb,
- * eth1, eth2, sdhc, crypto, global-util, pci0.
- *
- * Copyright 2009-2011 Freescale Semiconductor Inc.
- *
- * 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.
- */
-
-/include/ "p2020rdb.dts"
-
-/ {
-	model = "fsl,P2020RDB";
-	compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP";
-
-	cpus {
-		PowerPC,P2020@1 {
-			status = "disabled";
-		};
-	};
-
-	localbus@ffe05000 {
-		status = "disabled";
-	};
-
-	soc@ffe00000 {
-		serial1: serial@4600 {
-			status = "disabled";
-		};
-
-		dma@c300 {
-			status = "disabled";
-		};
-
-		enet0: ethernet@24000 {
-			status = "disabled";
-		};
-
-		mpic: pic@40000 {
-			protected-sources = <
-			42 76 77 78 79 /* serial1 , dma2 */
-			29 30 34 26 /* enet0, pci1 */
-			0xe0 0xe1 0xe2 0xe3 /* msi */
-			0xe4 0xe5 0xe6 0xe7
-			>;
-		};
-
-		msi@41600 {
-			status = "disabled";
-		};
-	};
-
-	pci0: pcie@ffe08000 {
-		status = "disabled";
-	};
-
-	pci2: pcie@ffe0a000 {
-		status = "disabled";
-	};
-};
diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts
deleted file mode 100644
index 9bd8ef4..0000000
--- a/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * P2020 RDB Core1 Device Tree Source in CAMP mode.
- *
- * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
- * can be shared, all the other devices must be assigned to one core only.
- * This dts allows core1 to have l2, dma2, eth0, pci1, msi.
- *
- * Please note to add "-b 1" for core1's dts compiling.
- *
- * Copyright 2009-2011 Freescale Semiconductor Inc.
- *
- * 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.
- */
-
-/include/ "p2020rdb.dts"
-
-/ {
-	model = "fsl,P2020RDB";
-	compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP";
-
-	cpus {
-		PowerPC,P2020@0 {
-			status = "disabled";
-		};
-	};
-
-	localbus@ffe05000 {
-		status = "disabled";
-	};
-
-	soc@ffe00000 {
-		ecm-law@0 {
-			status = "disabled";
-		};
-
-		ecm@1000 {
-			status = "disabled";
-		};
-
-		memory-controller@2000 {
-			status = "disabled";
-		};
-
-		i2c@3000 {
-			status = "disabled";
-		};
-
-		i2c@3100 {
-			status = "disabled";
-		};
-
-		serial0: serial@4500 {
-			status = "disabled";
-		};
-
-		spi@7000 {
-			status = "disabled";
-		};
-
-		gpio: gpio-controller@f000 {
-			status = "disabled";
-		};
-
-		dma@21300 {
-			status = "disabled";
-		};
-
-		usb@22000 {
-			status = "disabled";
-		};
-
-		mdio@24520 {
-			status = "disabled";
-		};
-
-		mdio@25520 {
-			status = "disabled";
-		};
-
-		mdio@26520 {
-			status = "disabled";
-		};
-
-		enet1: ethernet@25000 {
-			status = "disabled";
-		};
-
-		enet2: ethernet@26000 {
-			status = "disabled";
-		};
-
-		sdhci@2e000 {
-			status = "disabled";
-		};
-
-		crypto@30000 {
-			status = "disabled";
-		};
-
-		mpic: pic@40000 {
-			protected-sources = <
-			17 18 43 42 59 47 /*ecm, mem, i2c, serial0, spi,gpio */
-			16 20 21 22 23 28 	/* L2, dma1, USB */
-			03 35 36 40 31 32 33 	/* mdio, enet1, enet2 */
-			72 45 58 25 		/* sdhci, crypto , pci */
-			>;
-		};
-
-		global-utilities@e0000 {	//global utilities block
-			status = "disabled";
-		};
-
-	};
-
-	pci0: pcie@ffe08000 {
-		status = "disabled";
-	};
-
-	pci1: pcie@ffe09000 {
-		status = "disabled";
-	};
-};
diff --git a/arch/powerpc/boot/dts/p5040ds.dts b/arch/powerpc/boot/dts/p5040ds.dts
new file mode 100644
index 0000000..d86bf2e
--- /dev/null
+++ b/arch/powerpc/boot/dts/p5040ds.dts
@@ -0,0 +1,203 @@
+/*
+ * P5040DS Device Tree Source
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * This software is provided by Freescale Semiconductor "as is" and any
+ * express or implied warranties, including, but not limited to, the implied
+ * warranties of merchantability and fitness for a particular purpose are
+ * disclaimed. In no event shall Freescale Semiconductor be liable for any
+ * direct, indirect, incidental, special, exemplary, or consequential damages
+ * (including, but not limited to, procurement of substitute goods or services;
+ * loss of use, data, or profits; or business interruption) however caused and
+ * on any theory of liability, whether in contract, strict liability, or tort
+ * (including negligence or otherwise) arising in any way out of the use of this
+ * software, even if advised of the possibility of such damage.
+ */
+
+/include/ "fsl/p5040si-pre.dtsi"
+
+/ {
+	model = "fsl,P5040DS";
+	compatible = "fsl,P5040DS";
+	#address-cells = <2>;
+	#size-cells = <2>;
+	interrupt-parent = <&mpic>;
+
+	memory {
+		device_type = "memory";
+	};
+
+	dcsr: dcsr@f00000000 {
+		ranges = <0x00000000 0xf 0x00000000 0x01008000>;
+	};
+
+	soc: soc@ffe000000 {
+		ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
+		reg = <0xf 0xfe000000 0 0x00001000>;
+		spi@110000 {
+			flash@0 {
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "spansion,s25sl12801";
+				reg = <0>;
+				spi-max-frequency = <40000000>; /* input clock */
+				partition@u-boot {
+					label = "u-boot";
+					reg = <0x00000000 0x00100000>;
+				};
+				partition@kernel {
+					label = "kernel";
+					reg = <0x00100000 0x00500000>;
+				};
+				partition@dtb {
+					label = "dtb";
+					reg = <0x00600000 0x00100000>;
+				};
+				partition@fs {
+					label = "file system";
+					reg = <0x00700000 0x00900000>;
+				};
+			};
+		};
+
+		i2c@118100 {
+			eeprom@51 {
+				compatible = "at24,24c256";
+				reg = <0x51>;
+			};
+			eeprom@52 {
+				compatible = "at24,24c256";
+				reg = <0x52>;
+			};
+		};
+
+		i2c@119100 {
+			rtc@68 {
+				compatible = "dallas,ds3232";
+				reg = <0x68>;
+				interrupts = <0x1 0x1 0 0>;
+			};
+		};
+	};
+
+	lbc: localbus@ffe124000 {
+		reg = <0xf 0xfe124000 0 0x1000>;
+		ranges = <0 0 0xf 0xe8000000 0x08000000
+			  2 0 0xf 0xffa00000 0x00040000
+			  3 0 0xf 0xffdf0000 0x00008000>;
+
+		flash@0,0 {
+			compatible = "cfi-flash";
+			reg = <0 0 0x08000000>;
+			bank-width = <2>;
+			device-width = <2>;
+		};
+
+		nand@2,0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "fsl,elbc-fcm-nand";
+			reg = <0x2 0x0 0x40000>;
+
+			partition@0 {
+				label = "NAND U-Boot Image";
+				reg = <0x0 0x02000000>;
+			};
+
+			partition@2000000 {
+				label = "NAND Root File System";
+				reg = <0x02000000 0x10000000>;
+			};
+
+			partition@12000000 {
+				label = "NAND Compressed RFS Image";
+				reg = <0x12000000 0x08000000>;
+			};
+
+			partition@1a000000 {
+				label = "NAND Linux Kernel Image";
+				reg = <0x1a000000 0x04000000>;
+			};
+
+			partition@1e000000 {
+				label = "NAND DTB Image";
+				reg = <0x1e000000 0x01000000>;
+			};
+
+			partition@1f000000 {
+				label = "NAND Writable User area";
+				reg = <0x1f000000 0x01000000>;
+			};
+		};
+
+		board-control@3,0 {
+			compatible = "fsl,p5040ds-fpga", "fsl,fpga-ngpixis";
+			reg = <3 0 0x40>;
+		};
+	};
+
+	pci0: pcie@ffe200000 {
+		reg = <0xf 0xfe200000 0 0x1000>;
+		ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0x0 0x20000000
+			  0x01000000 0 0x00000000 0xf 0xf8000000 0x0 0x00010000>;
+		pcie@0 {
+			ranges = <0x02000000 0 0xe0000000
+				  0x02000000 0 0xe0000000
+				  0 0x20000000
+
+				  0x01000000 0 0x00000000
+				  0x01000000 0 0x00000000
+				  0 0x00010000>;
+		};
+	};
+
+	pci1: pcie@ffe201000 {
+		reg = <0xf 0xfe201000 0 0x1000>;
+		ranges = <0x02000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
+			  0x01000000 0x0 0x00000000 0xf 0xf8010000 0x0 0x00010000>;
+		pcie@0 {
+			ranges = <0x02000000 0 0xe0000000
+				  0x02000000 0 0xe0000000
+				  0 0x20000000
+
+				  0x01000000 0 0x00000000
+				  0x01000000 0 0x00000000
+				  0 0x00010000>;
+		};
+	};
+
+	pci2: pcie@ffe202000 {
+		reg = <0xf 0xfe202000 0 0x1000>;
+		ranges = <0x02000000 0 0xe0000000 0xc 0x40000000 0 0x20000000
+			  0x01000000 0 0x00000000 0xf 0xf8020000 0 0x00010000>;
+		pcie@0 {
+			ranges = <0x02000000 0 0xe0000000
+				  0x02000000 0 0xe0000000
+				  0 0x20000000
+
+				  0x01000000 0 0x00000000
+				  0x01000000 0 0x00000000
+				  0 0x00010000>;
+		};
+	};
+};
+
+/include/ "fsl/p5040si-post.dtsi"
diff --git a/arch/powerpc/configs/corenet32_smp_defconfig b/arch/powerpc/configs/corenet32_smp_defconfig
index cbb98c1..3b40015 100644
--- a/arch/powerpc/configs/corenet32_smp_defconfig
+++ b/arch/powerpc/configs/corenet32_smp_defconfig
@@ -25,6 +25,7 @@ CONFIG_P2041_RDB=y
 CONFIG_P3041_DS=y
 CONFIG_P4080_DS=y
 CONFIG_P5020_DS=y
+CONFIG_P5040_DS=y
 CONFIG_HIGHMEM=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/powerpc/configs/corenet64_smp_defconfig b/arch/powerpc/configs/corenet64_smp_defconfig
index dd89de8..36df45b 100644
--- a/arch/powerpc/configs/corenet64_smp_defconfig
+++ b/arch/powerpc/configs/corenet64_smp_defconfig
@@ -23,6 +23,7 @@ CONFIG_MODVERSIONS=y
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_MAC_PARTITION=y
 CONFIG_P5020_DS=y
+CONFIG_P5040_DS=y
 # CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set
 CONFIG_BINFMT_MISC=m
 CONFIG_IRQ_ALL_CPUS=y
diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
index 03ee911c..627c257 100644
--- a/arch/powerpc/configs/mpc85xx_defconfig
+++ b/arch/powerpc/configs/mpc85xx_defconfig
@@ -26,6 +26,7 @@ CONFIG_MPC85xx_DS=y
 CONFIG_MPC85xx_RDB=y
 CONFIG_P1010_RDB=y
 CONFIG_P1022_DS=y
+CONFIG_P1022_RDK=y
 CONFIG_P1023_RDS=y
 CONFIG_SOCRATES=y
 CONFIG_KSI8560=y
@@ -115,6 +116,7 @@ CONFIG_ATA=y
 CONFIG_SATA_AHCI=y
 CONFIG_SATA_FSL=y
 CONFIG_PATA_ALI=y
+CONFIG_PATA_VIA=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
 CONFIG_FS_ENET=y
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index fdfa84d..8d1c2a4 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -28,6 +28,7 @@ CONFIG_MPC85xx_DS=y
 CONFIG_MPC85xx_RDB=y
 CONFIG_P1010_RDB=y
 CONFIG_P1022_DS=y
+CONFIG_P1022_RDK=y
 CONFIG_P1023_RDS=y
 CONFIG_SOCRATES=y
 CONFIG_KSI8560=y
diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index db27c82..2d9150a1 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -487,7 +487,8 @@ CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
-CONFIG_CRYPTO_DEV_NX=m
+CONFIG_CRYPTO_DEV_NX=y
+CONFIG_CRYPTO_DEV_NX_ENCRYPT=m
 CONFIG_VIRTUALIZATION=y
 CONFIG_KVM_BOOK3S_64=m
 CONFIG_KVM_BOOK3S_64_HV=y
diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index 1f65b3c..9f4a936 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -369,7 +369,8 @@ CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
-CONFIG_CRYPTO_DEV_NX=m
+CONFIG_CRYPTO_DEV_NX=y
+CONFIG_CRYPTO_DEV_NX_ENCRYPT=m
 CONFIG_VIRTUALIZATION=y
 CONFIG_KVM_BOOK3S_64=m
 CONFIG_KVM_BOOK3S_64_HV=y
diff --git a/arch/powerpc/include/asm/Kbuild b/arch/powerpc/include/asm/Kbuild
index 7e313f1..13d6b7b 100644
--- a/arch/powerpc/include/asm/Kbuild
+++ b/arch/powerpc/include/asm/Kbuild
@@ -34,5 +34,6 @@ header-y += termios.h
 header-y += types.h
 header-y += ucontext.h
 header-y += unistd.h
+header-y += epapr_hcalls.h
 
 generic-y += rwsem.h
diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index ab9e402..b843e35 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -30,6 +30,8 @@ extern void flush_dcache_page(struct page *page);
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
 
+extern void __flush_disable_L1(void);
+
 extern void __flush_icache_range(unsigned long, unsigned long);
 static inline void flush_icache_range(unsigned long start, unsigned long stop)
 {
diff --git a/arch/powerpc/include/asm/epapr_hcalls.h b/arch/powerpc/include/asm/epapr_hcalls.h
index bf2c06c..b8d9445 100644
--- a/arch/powerpc/include/asm/epapr_hcalls.h
+++ b/arch/powerpc/include/asm/epapr_hcalls.h
@@ -50,10 +50,6 @@
 #ifndef _EPAPR_HCALLS_H
 #define _EPAPR_HCALLS_H
 
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <asm/byteorder.h>
-
 #define EV_BYTE_CHANNEL_SEND		1
 #define EV_BYTE_CHANNEL_RECEIVE		2
 #define EV_BYTE_CHANNEL_POLL		3
@@ -88,7 +84,8 @@
 #define _EV_HCALL_TOKEN(id, num) (((id) << 16) | (num))
 #define EV_HCALL_TOKEN(hcall_num) _EV_HCALL_TOKEN(EV_EPAPR_VENDOR_ID, hcall_num)
 
-/* epapr error codes */
+/* epapr return codes */
+#define EV_SUCCESS		0
 #define EV_EPERM		1	/* Operation not permitted */
 #define EV_ENOENT		2	/*  Entry Not Found */
 #define EV_EIO			3	/* I/O error occured */
@@ -108,6 +105,11 @@
 #define EV_UNIMPLEMENTED	12	/* Unimplemented hypercall */
 #define EV_BUFFER_OVERFLOW	13	/* Caller-supplied buffer too small */
 
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <asm/byteorder.h>
+
 /*
  * Hypercall register clobber list
  *
@@ -193,7 +195,7 @@ static inline unsigned int ev_int_set_config(unsigned int interrupt,
 	r5  = priority;
 	r6  = destination;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6)
 		: : EV_HCALL_CLOBBERS4
 	);
@@ -222,7 +224,7 @@ static inline unsigned int ev_int_get_config(unsigned int interrupt,
 	r11 = EV_HCALL_TOKEN(EV_INT_GET_CONFIG);
 	r3 = interrupt;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3), "=r" (r4), "=r" (r5), "=r" (r6)
 		: : EV_HCALL_CLOBBERS4
 	);
@@ -252,7 +254,7 @@ static inline unsigned int ev_int_set_mask(unsigned int interrupt,
 	r3 = interrupt;
 	r4 = mask;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3), "+r" (r4)
 		: : EV_HCALL_CLOBBERS2
 	);
@@ -277,7 +279,7 @@ static inline unsigned int ev_int_get_mask(unsigned int interrupt,
 	r11 = EV_HCALL_TOKEN(EV_INT_GET_MASK);
 	r3 = interrupt;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3), "=r" (r4)
 		: : EV_HCALL_CLOBBERS2
 	);
@@ -305,7 +307,7 @@ static inline unsigned int ev_int_eoi(unsigned int interrupt)
 	r11 = EV_HCALL_TOKEN(EV_INT_EOI);
 	r3 = interrupt;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3)
 		: : EV_HCALL_CLOBBERS1
 	);
@@ -344,7 +346,7 @@ static inline unsigned int ev_byte_channel_send(unsigned int handle,
 	r7 = be32_to_cpu(p[2]);
 	r8 = be32_to_cpu(p[3]);
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3),
 		  "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7), "+r" (r8)
 		: : EV_HCALL_CLOBBERS6
@@ -383,7 +385,7 @@ static inline unsigned int ev_byte_channel_receive(unsigned int handle,
 	r3 = handle;
 	r4 = *count;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3), "+r" (r4),
 		  "=r" (r5), "=r" (r6), "=r" (r7), "=r" (r8)
 		: : EV_HCALL_CLOBBERS6
@@ -421,7 +423,7 @@ static inline unsigned int ev_byte_channel_poll(unsigned int handle,
 	r11 = EV_HCALL_TOKEN(EV_BYTE_CHANNEL_POLL);
 	r3 = handle;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3), "=r" (r4), "=r" (r5)
 		: : EV_HCALL_CLOBBERS3
 	);
@@ -454,7 +456,7 @@ static inline unsigned int ev_int_iack(unsigned int handle,
 	r11 = EV_HCALL_TOKEN(EV_INT_IACK);
 	r3 = handle;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3), "=r" (r4)
 		: : EV_HCALL_CLOBBERS2
 	);
@@ -478,7 +480,7 @@ static inline unsigned int ev_doorbell_send(unsigned int handle)
 	r11 = EV_HCALL_TOKEN(EV_DOORBELL_SEND);
 	r3 = handle;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3)
 		: : EV_HCALL_CLOBBERS1
 	);
@@ -498,12 +500,12 @@ static inline unsigned int ev_idle(void)
 
 	r11 = EV_HCALL_TOKEN(EV_IDLE);
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "=r" (r3)
 		: : EV_HCALL_CLOBBERS1
 	);
 
 	return r3;
 }
-
+#endif /* !__ASSEMBLY__ */
 #endif
diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h
index aa4c488..dd5ba2c 100644
--- a/arch/powerpc/include/asm/fsl_guts.h
+++ b/arch/powerpc/include/asm/fsl_guts.h
@@ -48,6 +48,8 @@ struct ccsr_guts {
         __be32  dmuxcr;		/* 0x.0068 - DMA Mux Control Register */
         u8	res06c[0x70 - 0x6c];
 	__be32	devdisr;	/* 0x.0070 - Device Disable Control */
+#define CCSR_GUTS_DEVDISR_TB1	0x00001000
+#define CCSR_GUTS_DEVDISR_TB0	0x00004000
 	__be32	devdisr2;	/* 0x.0074 - Device Disable Control 2 */
 	u8	res078[0x7c - 0x78];
 	__be32  pmjcr;		/* 0x.007c - 4 Power Management Jog Control Register */
diff --git a/arch/powerpc/include/asm/fsl_hcalls.h b/arch/powerpc/include/asm/fsl_hcalls.h
index 922d9b5..3abb583 100644
--- a/arch/powerpc/include/asm/fsl_hcalls.h
+++ b/arch/powerpc/include/asm/fsl_hcalls.h
@@ -96,7 +96,7 @@ static inline unsigned int fh_send_nmi(unsigned int vcpu_mask)
 	r11 = FH_HCALL_TOKEN(FH_SEND_NMI);
 	r3 = vcpu_mask;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3)
 		: : EV_HCALL_CLOBBERS1
 	);
@@ -151,7 +151,7 @@ static inline unsigned int fh_partition_get_dtprop(int handle,
 	r9 = (uint32_t)propvalue_addr;
 	r10 = *propvalue_len;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11),
 		  "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7),
 		  "+r" (r8), "+r" (r9), "+r" (r10)
@@ -205,7 +205,7 @@ static inline unsigned int fh_partition_set_dtprop(int handle,
 	r9 = (uint32_t)propvalue_addr;
 	r10 = propvalue_len;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11),
 		  "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7),
 		  "+r" (r8), "+r" (r9), "+r" (r10)
@@ -229,7 +229,7 @@ static inline unsigned int fh_partition_restart(unsigned int partition)
 	r11 = FH_HCALL_TOKEN(FH_PARTITION_RESTART);
 	r3 = partition;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3)
 		: : EV_HCALL_CLOBBERS1
 	);
@@ -262,7 +262,7 @@ static inline unsigned int fh_partition_get_status(unsigned int partition,
 	r11 = FH_HCALL_TOKEN(FH_PARTITION_GET_STATUS);
 	r3 = partition;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3), "=r" (r4)
 		: : EV_HCALL_CLOBBERS2
 	);
@@ -295,7 +295,7 @@ static inline unsigned int fh_partition_start(unsigned int partition,
 	r4 = entry_point;
 	r5 = load;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3), "+r" (r4), "+r" (r5)
 		: : EV_HCALL_CLOBBERS3
 	);
@@ -317,7 +317,7 @@ static inline unsigned int fh_partition_stop(unsigned int partition)
 	r11 = FH_HCALL_TOKEN(FH_PARTITION_STOP);
 	r3 = partition;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3)
 		: : EV_HCALL_CLOBBERS1
 	);
@@ -376,7 +376,7 @@ static inline unsigned int fh_partition_memcpy(unsigned int source,
 #endif
 	r7 = count;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11),
 		  "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7)
 		: : EV_HCALL_CLOBBERS5
@@ -399,7 +399,7 @@ static inline unsigned int fh_dma_enable(unsigned int liodn)
 	r11 = FH_HCALL_TOKEN(FH_DMA_ENABLE);
 	r3 = liodn;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3)
 		: : EV_HCALL_CLOBBERS1
 	);
@@ -421,7 +421,7 @@ static inline unsigned int fh_dma_disable(unsigned int liodn)
 	r11 = FH_HCALL_TOKEN(FH_DMA_DISABLE);
 	r3 = liodn;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3)
 		: : EV_HCALL_CLOBBERS1
 	);
@@ -447,7 +447,7 @@ static inline unsigned int fh_vmpic_get_msir(unsigned int interrupt,
 	r11 = FH_HCALL_TOKEN(FH_VMPIC_GET_MSIR);
 	r3 = interrupt;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3), "=r" (r4)
 		: : EV_HCALL_CLOBBERS2
 	);
@@ -469,7 +469,7 @@ static inline unsigned int fh_system_reset(void)
 
 	r11 = FH_HCALL_TOKEN(FH_SYSTEM_RESET);
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "=r" (r3)
 		: : EV_HCALL_CLOBBERS1
 	);
@@ -506,7 +506,7 @@ static inline unsigned int fh_err_get_info(int queue, uint32_t *bufsize,
 	r6 = addr_lo;
 	r7 = peek;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6),
 		  "+r" (r7)
 		: : EV_HCALL_CLOBBERS5
@@ -542,7 +542,7 @@ static inline unsigned int fh_get_core_state(unsigned int handle,
 	r3 = handle;
 	r4 = vcpu;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3), "+r" (r4)
 		: : EV_HCALL_CLOBBERS2
 	);
@@ -572,7 +572,7 @@ static inline unsigned int fh_enter_nap(unsigned int handle, unsigned int vcpu)
 	r3 = handle;
 	r4 = vcpu;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3), "+r" (r4)
 		: : EV_HCALL_CLOBBERS2
 	);
@@ -597,7 +597,7 @@ static inline unsigned int fh_exit_nap(unsigned int handle, unsigned int vcpu)
 	r3 = handle;
 	r4 = vcpu;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3), "+r" (r4)
 		: : EV_HCALL_CLOBBERS2
 	);
@@ -618,7 +618,7 @@ static inline unsigned int fh_claim_device(unsigned int handle)
 	r11 = FH_HCALL_TOKEN(FH_CLAIM_DEVICE);
 	r3 = handle;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3)
 		: : EV_HCALL_CLOBBERS1
 	);
@@ -645,7 +645,7 @@ static inline unsigned int fh_partition_stop_dma(unsigned int handle)
 	r11 = FH_HCALL_TOKEN(FH_PARTITION_STOP_DMA);
 	r3 = handle;
 
-	__asm__ __volatile__ ("sc 1"
+	asm volatile("bl	epapr_hypercall_start"
 		: "+r" (r11), "+r" (r3)
 		: : EV_HCALL_CLOBBERS1
 	);
diff --git a/arch/powerpc/include/asm/fsl_ifc.h b/arch/powerpc/include/asm/fsl_ifc.h
index b955012..b8a4b9b 100644
--- a/arch/powerpc/include/asm/fsl_ifc.h
+++ b/arch/powerpc/include/asm/fsl_ifc.h
@@ -768,22 +768,24 @@ struct fsl_ifc_gpcm {
  */
 struct fsl_ifc_regs {
 	__be32 ifc_rev;
-	u32 res1[0x3];
+	u32 res1[0x2];
 	struct {
+		__be32 cspr_ext;
 		__be32 cspr;
-		u32 res2[0x2];
+		u32 res2;
 	} cspr_cs[FSL_IFC_BANK_COUNT];
-	u32 res3[0x18];
+	u32 res3[0x19];
 	struct {
 		__be32 amask;
 		u32 res4[0x2];
 	} amask_cs[FSL_IFC_BANK_COUNT];
-	u32 res5[0x18];
+	u32 res5[0x17];
 	struct {
+		__be32 csor_ext;
 		__be32 csor;
-		u32 res6[0x2];
+		u32 res6;
 	} csor_cs[FSL_IFC_BANK_COUNT];
-	u32 res7[0x18];
+	u32 res7[0x19];
 	struct {
 		__be32 ftim[4];
 		u32 res8[0x8];
diff --git a/arch/powerpc/include/asm/kvm.h b/arch/powerpc/include/asm/kvm.h
index 1bea4d8..3c14202 100644
--- a/arch/powerpc/include/asm/kvm.h
+++ b/arch/powerpc/include/asm/kvm.h
@@ -221,6 +221,12 @@ struct kvm_sregs {
 
 			__u32 dbsr;	/* KVM_SREGS_E_UPDATE_DBSR */
 			__u32 dbcr[3];
+			/*
+			 * iac/dac registers are 64bit wide, while this API
+			 * interface provides only lower 32 bits on 64 bit
+			 * processors. ONE_REG interface is added for 64bit
+			 * iac/dac registers.
+			 */
 			__u32 iac[4];
 			__u32 dac[2];
 			__u32 dvc[2];
@@ -326,5 +332,11 @@ struct kvm_book3e_206_tlb_params {
 };
 
 #define KVM_REG_PPC_HIOR	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1)
+#define KVM_REG_PPC_IAC1	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x2)
+#define KVM_REG_PPC_IAC2	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3)
+#define KVM_REG_PPC_IAC3	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x4)
+#define KVM_REG_PPC_IAC4	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x5)
+#define KVM_REG_PPC_DAC1	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x6)
+#define KVM_REG_PPC_DAC2	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x7)
 
 #endif /* __LINUX_KVM_POWERPC_H */
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 50ea12f..f20a5ef 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -33,6 +33,7 @@
 #include <asm/kvm_asm.h>
 #include <asm/processor.h>
 #include <asm/page.h>
+#include <asm/cacheflush.h>
 
 #define KVM_MAX_VCPUS		NR_CPUS
 #define KVM_MAX_VCORES		NR_CPUS
@@ -45,13 +46,15 @@
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
 #endif
 
-#ifdef CONFIG_KVM_BOOK3S_64_HV
+#if !defined(CONFIG_KVM_440)
 #include <linux/mmu_notifier.h>
 
 #define KVM_ARCH_WANT_MMU_NOTIFIER
 
 struct kvm;
 extern int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
+extern int kvm_unmap_hva_range(struct kvm *kvm,
+			       unsigned long start, unsigned long end);
 extern int kvm_age_hva(struct kvm *kvm, unsigned long hva);
 extern int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
 extern void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
@@ -219,6 +222,7 @@ struct revmap_entry {
 #define KVMPPC_GOT_PAGE		0x80
 
 struct kvm_arch_memory_slot {
+	unsigned long *rmap;
 };
 
 struct kvm_arch {
@@ -342,6 +346,27 @@ struct kvmppc_slb {
 	bool class	: 1;
 };
 
+# ifdef CONFIG_PPC_FSL_BOOK3E
+#define KVMPPC_BOOKE_IAC_NUM	2
+#define KVMPPC_BOOKE_DAC_NUM	2
+# else
+#define KVMPPC_BOOKE_IAC_NUM	4
+#define KVMPPC_BOOKE_DAC_NUM	2
+# endif
+#define KVMPPC_BOOKE_MAX_IAC	4
+#define KVMPPC_BOOKE_MAX_DAC	2
+
+struct kvmppc_booke_debug_reg {
+	u32 dbcr0;
+	u32 dbcr1;
+	u32 dbcr2;
+#ifdef CONFIG_KVM_E500MC
+	u32 dbcr4;
+#endif
+	u64 iac[KVMPPC_BOOKE_MAX_IAC];
+	u64 dac[KVMPPC_BOOKE_MAX_DAC];
+};
+
 struct kvm_vcpu_arch {
 	ulong host_stack;
 	u32 host_pid;
@@ -436,8 +461,6 @@ struct kvm_vcpu_arch {
 
 	u32 ccr0;
 	u32 ccr1;
-	u32 dbcr0;
-	u32 dbcr1;
 	u32 dbsr;
 
 	u64 mmcr[3];
@@ -467,9 +490,12 @@ struct kvm_vcpu_arch {
 	ulong fault_esr;
 	ulong queued_dear;
 	ulong queued_esr;
+	spinlock_t wdt_lock;
+	struct timer_list wdt_timer;
 	u32 tlbcfg[4];
 	u32 mmucfg;
 	u32 epr;
+	struct kvmppc_booke_debug_reg dbg_reg;
 #endif
 	gpa_t paddr_accessed;
 	gva_t vaddr_accessed;
@@ -482,6 +508,7 @@ struct kvm_vcpu_arch {
 	u8 osi_needed;
 	u8 osi_enabled;
 	u8 papr_enabled;
+	u8 watchdog_enabled;
 	u8 sane;
 	u8 cpu_type;
 	u8 hcall_needed;
diff --git a/arch/powerpc/include/asm/kvm_para.h b/arch/powerpc/include/asm/kvm_para.h
index c18916b..a168ce3 100644
--- a/arch/powerpc/include/asm/kvm_para.h
+++ b/arch/powerpc/include/asm/kvm_para.h
@@ -75,9 +75,10 @@ struct kvm_vcpu_arch_shared {
 };
 
 #define KVM_SC_MAGIC_R0		0x4b564d21 /* "KVM!" */
-#define HC_VENDOR_KVM		(42 << 16)
-#define HC_EV_SUCCESS		0
-#define HC_EV_UNIMPLEMENTED	12
+
+#define KVM_HCALL_TOKEN(num)     _EV_HCALL_TOKEN(EV_KVM_VENDOR_ID, num)
+
+#include <asm/epapr_hcalls.h>
 
 #define KVM_FEATURE_MAGIC_PAGE	1
 
@@ -121,7 +122,7 @@ static unsigned long kvm_hypercall(unsigned long *in,
 				   unsigned long *out,
 				   unsigned long nr)
 {
-	return HC_EV_UNIMPLEMENTED;
+	return EV_UNIMPLEMENTED;
 }
 
 #endif
@@ -132,7 +133,7 @@ static inline long kvm_hypercall0_1(unsigned int nr, unsigned long *r2)
 	unsigned long out[8];
 	unsigned long r;
 
-	r = kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+	r = kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
 	*r2 = out[0];
 
 	return r;
@@ -143,7 +144,7 @@ static inline long kvm_hypercall0(unsigned int nr)
 	unsigned long in[8];
 	unsigned long out[8];
 
-	return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+	return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
 }
 
 static inline long kvm_hypercall1(unsigned int nr, unsigned long p1)
@@ -152,7 +153,7 @@ static inline long kvm_hypercall1(unsigned int nr, unsigned long p1)
 	unsigned long out[8];
 
 	in[0] = p1;
-	return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+	return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
 }
 
 static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
@@ -163,7 +164,7 @@ static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
 
 	in[0] = p1;
 	in[1] = p2;
-	return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+	return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
 }
 
 static inline long kvm_hypercall3(unsigned int nr, unsigned long p1,
@@ -175,7 +176,7 @@ static inline long kvm_hypercall3(unsigned int nr, unsigned long p1,
 	in[0] = p1;
 	in[1] = p2;
 	in[2] = p3;
-	return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+	return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
 }
 
 static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
@@ -189,7 +190,7 @@ static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
 	in[1] = p2;
 	in[2] = p3;
 	in[3] = p4;
-	return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+	return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
 }
 
 
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 0124937..c06a64b 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -68,6 +68,8 @@ extern void kvmppc_emulate_dec(struct kvm_vcpu *vcpu);
 extern u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb);
 extern void kvmppc_decrementer_func(unsigned long data);
 extern int kvmppc_sanity_check(struct kvm_vcpu *vcpu);
+extern int kvmppc_subarch_vcpu_init(struct kvm_vcpu *vcpu);
+extern void kvmppc_subarch_vcpu_uninit(struct kvm_vcpu *vcpu);
 
 /* Core-specific hooks */
 
@@ -104,6 +106,7 @@ extern void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
                                        struct kvm_interrupt *irq);
 extern void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu,
                                          struct kvm_interrupt *irq);
+extern void kvmppc_core_flush_tlb(struct kvm_vcpu *vcpu);
 
 extern int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                                   unsigned int op, int *advance);
@@ -111,6 +114,7 @@ extern int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn,
 				     ulong val);
 extern int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn,
 				     ulong *val);
+extern int kvmppc_core_check_requests(struct kvm_vcpu *vcpu);
 
 extern int kvmppc_booke_init(void);
 extern void kvmppc_booke_exit(void);
@@ -149,6 +153,8 @@ extern int kvm_vm_ioctl_get_smmu_info(struct kvm *kvm,
 extern int kvmppc_bookehv_init(void);
 extern void kvmppc_bookehv_exit(void);
 
+extern int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu);
+
 /*
  * Cuts out inst bits with ordering according to spec.
  * That means the leftmost bit is zero. All given bits are included.
@@ -219,4 +225,26 @@ void kvmppc_claim_lpid(long lpid);
 void kvmppc_free_lpid(long lpid);
 void kvmppc_init_lpid(unsigned long nr_lpids);
 
+static inline void kvmppc_mmu_flush_icache(pfn_t pfn)
+{
+	/* Clear i-cache for new pages */
+	struct page *page;
+	page = pfn_to_page(pfn);
+	if (!test_bit(PG_arch_1, &page->flags)) {
+		flush_dcache_icache_page(page);
+		set_bit(PG_arch_1, &page->flags);
+	}
+}
+
+/* Please call after prepare_to_enter. This function puts the lazy ee state
+   back to normal mode, without actually enabling interrupts. */
+static inline void kvmppc_lazy_ee_enable(void)
+{
+#ifdef CONFIG_PPC64
+	/* Only need to enable IRQs by hard enabling them after this */
+	local_paca->irq_happened = 0;
+	local_paca->soft_enabled = 1;
+#endif
+}
+
 #endif /* __POWERPC_KVM_PPC_H__ */
diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h
index 0192a4e..c1df590 100644
--- a/arch/powerpc/include/asm/module.h
+++ b/arch/powerpc/include/asm/module.h
@@ -11,6 +11,7 @@
 
 #include <linux/list.h>
 #include <asm/bug.h>
+#include <asm-generic/module.h>
 
 
 #ifndef __powerpc64__
@@ -60,16 +61,10 @@ struct mod_arch_specific {
  */
 
 #ifdef __powerpc64__
-#    define Elf_Shdr	Elf64_Shdr
-#    define Elf_Sym	Elf64_Sym
-#    define Elf_Ehdr	Elf64_Ehdr
 #    ifdef MODULE
 	asm(".section .stubs,\"ax\",@nobits; .align 3; .previous");
 #    endif
 #else
-#    define Elf_Shdr	Elf32_Shdr
-#    define Elf_Sym	Elf32_Sym
-#    define Elf_Ehdr	Elf32_Ehdr
 #    ifdef MODULE
 	asm(".section .plt,\"ax\",@nobits; .align 3; .previous");
 	asm(".section .init.plt,\"ax\",@nobits; .align 3; .previous");
diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h
index c9f698a..c0f9ef9 100644
--- a/arch/powerpc/include/asm/mpic.h
+++ b/arch/powerpc/include/asm/mpic.h
@@ -63,6 +63,7 @@
  */
 #define MPIC_TIMER_BASE			0x01100
 #define MPIC_TIMER_STRIDE		0x40
+#define MPIC_TIMER_GROUP_STRIDE		0x1000
 
 #define MPIC_TIMER_CURRENT_CNT		0x00000
 #define MPIC_TIMER_BASE_CNT		0x00010
@@ -110,10 +111,16 @@
 #define 	MPIC_VECPRI_SENSE_MASK			0x00400000
 #define MPIC_IRQ_DESTINATION		0x00010
 
+#define MPIC_FSL_BRR1			0x00000
+#define 	MPIC_FSL_BRR1_VER			0x0000ffff
+
 #define MPIC_MAX_IRQ_SOURCES	2048
 #define MPIC_MAX_CPUS		32
 #define MPIC_MAX_ISU		32
 
+#define MPIC_MAX_ERR      32
+#define MPIC_FSL_ERR_INT  16
+
 /*
  * Tsi108 implementation of MPIC has many differences from the original one
  */
@@ -266,6 +273,7 @@ struct mpic
 	struct irq_chip		hc_ipi;
 #endif
 	struct irq_chip		hc_tm;
+	struct irq_chip		hc_err;
 	const char		*name;
 	/* Flags */
 	unsigned int		flags;
@@ -279,6 +287,8 @@ struct mpic
 	/* vector numbers used for internal sources (ipi/timers) */
 	unsigned int		ipi_vecs[4];
 	unsigned int		timer_vecs[8];
+	/* vector numbers used for FSL MPIC error interrupts */
+	unsigned int		err_int_vecs[MPIC_MAX_ERR];
 
 	/* Spurious vector to program into unused sources */
 	unsigned int		spurious_vec;
@@ -296,11 +306,15 @@ struct mpic
 	phys_addr_t paddr;
 
 	/* The various ioremap'ed bases */
+	struct mpic_reg_bank	thiscpuregs;
 	struct mpic_reg_bank	gregs;
 	struct mpic_reg_bank	tmregs;
 	struct mpic_reg_bank	cpuregs[MPIC_MAX_CPUS];
 	struct mpic_reg_bank	isus[MPIC_MAX_ISU];
 
+	/* ioremap'ed base for error interrupt registers */
+	u32 __iomem	*err_regs;
+
 	/* Protected sources */
 	unsigned long		*protected;
 
@@ -365,6 +379,11 @@ struct mpic
 #define MPIC_NO_RESET			0x00004000
 /* Freescale MPIC (compatible includes "fsl,mpic") */
 #define MPIC_FSL			0x00008000
+/* Freescale MPIC supports EIMR (error interrupt mask register).
+ * This flag is set for MPIC version >= 4.1 (version determined
+ * from the BRR1 register).
+*/
+#define MPIC_FSL_HAS_EIMR		0x00010000
 
 /* MPIC HW modification ID */
 #define MPIC_REGSET_MASK		0xf0000000
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index 2d916c4..e07e6af 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -539,6 +539,13 @@
 #define TCR_FIE		0x00800000	/* FIT Interrupt Enable */
 #define TCR_ARE		0x00400000	/* Auto Reload Enable */
 
+#ifdef CONFIG_E500
+#define TCR_GET_WP(tcr)  ((((tcr) & 0xC0000000) >> 30) | \
+			      (((tcr) & 0x1E0000) >> 15))
+#else
+#define TCR_GET_WP(tcr)  (((tcr) & 0xC0000000) >> 30)
+#endif
+
 /* Bit definitions for the TSR. */
 #define TSR_ENW		0x80000000	/* Enable Next Watchdog */
 #define TSR_WIS		0x40000000	/* WDT Interrupt Status */
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index ebc24dc..e807e9d 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -65,6 +65,7 @@ int generic_cpu_disable(void);
 void generic_cpu_die(unsigned int cpu);
 void generic_mach_cpu_die(void);
 void generic_set_cpu_dead(unsigned int cpu);
+void generic_set_cpu_up(unsigned int cpu);
 int generic_check_cpu_restart(unsigned int cpu);
 #endif
 
@@ -190,6 +191,7 @@ extern unsigned long __secondary_hold_spinloop;
 extern unsigned long __secondary_hold_acknowledge;
 extern char __secondary_hold;
 
+extern void __early_start(void);
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/swiotlb.h b/arch/powerpc/include/asm/swiotlb.h
index 8979d4c..de99d6e 100644
--- a/arch/powerpc/include/asm/swiotlb.h
+++ b/arch/powerpc/include/asm/swiotlb.h
@@ -22,4 +22,10 @@ int __init swiotlb_setup_bus_notifier(void);
 
 extern void pci_dma_dev_setup_swiotlb(struct pci_dev *pdev);
 
+#ifdef CONFIG_SWIOTLB
+void swiotlb_detect_4g(void);
+#else
+static inline void swiotlb_detect_4g(void) {}
+#endif
+
 #endif /* __ASM_SWIOTLB_H */
diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h
index faf9352..5b1974f 100644
--- a/arch/powerpc/include/asm/thread_info.h
+++ b/arch/powerpc/include/asm/thread_info.h
@@ -177,6 +177,8 @@ static inline bool test_thread_local_flags(unsigned int flags)
 #define is_32bit_task()	(1)
 #endif
 
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
 #endif	/* !__ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
index 69fdd23..dcd8819 100644
--- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
+++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
@@ -16,6 +16,8 @@
 #include <asm/processor.h>
 #include <asm/cputable.h>
 #include <asm/ppc_asm.h>
+#include <asm/mmu-book3e.h>
+#include <asm/asm-offsets.h>
 
 _GLOBAL(__e500_icache_setup)
 	mfspr	r0, SPRN_L1CSR1
@@ -73,27 +75,81 @@ _GLOBAL(__setup_cpu_e500v2)
 	mtlr	r4
 	blr
 _GLOBAL(__setup_cpu_e500mc)
-	mr	r5, r4
-	mflr	r4
+_GLOBAL(__setup_cpu_e5500)
+	mflr	r5
 	bl	__e500_icache_setup
 	bl	__e500_dcache_setup
 	bl	__setup_e500mc_ivors
-	mtlr	r4
+	/*
+	 * We only want to touch IVOR38-41 if we're running on hardware
+	 * that supports category E.HV.  The architectural way to determine
+	 * this is MMUCFG[LPIDSIZE].
+	 */
+	mfspr	r3, SPRN_MMUCFG
+	rlwinm.	r3, r3, 0, MMUCFG_LPIDSIZE
+	beq	1f
+	bl	__setup_ehv_ivors
+	b	2f
+1:
+	lwz	r3, CPU_SPEC_FEATURES(r4)
+	/* We need this check as cpu_setup is also called for
+	 * the secondary cores. So, if we have already cleared
+	 * the feature on the primary core, avoid doing it on the
+	 * secondary core.
+	 */
+	andis.	r6, r3, CPU_FTR_EMB_HV@h
+	beq	2f
+	rlwinm	r3, r3, 0, ~CPU_FTR_EMB_HV
+	stw	r3, CPU_SPEC_FEATURES(r4)
+2:
+	mtlr	r5
 	blr
 #endif
-/* Right now, restore and setup are the same thing */
+
+#ifdef CONFIG_PPC_BOOK3E_64
 _GLOBAL(__restore_cpu_e5500)
-_GLOBAL(__setup_cpu_e5500)
 	mflr	r4
 	bl	__e500_icache_setup
 	bl	__e500_dcache_setup
-#ifdef CONFIG_PPC_BOOK3E_64
 	bl	.__setup_base_ivors
 	bl	.setup_perfmon_ivor
 	bl	.setup_doorbell_ivors
+	/*
+	 * We only want to touch IVOR38-41 if we're running on hardware
+	 * that supports category E.HV.  The architectural way to determine
+	 * this is MMUCFG[LPIDSIZE].
+	 */
+	mfspr	r10,SPRN_MMUCFG
+	rlwinm.	r10,r10,0,MMUCFG_LPIDSIZE
+	beq	1f
 	bl	.setup_ehv_ivors
-#else
-	bl	__setup_e500mc_ivors
-#endif
+1:
 	mtlr	r4
 	blr
+
+_GLOBAL(__setup_cpu_e5500)
+	mflr	r5
+	bl	__e500_icache_setup
+	bl	__e500_dcache_setup
+	bl	.__setup_base_ivors
+	bl	.setup_perfmon_ivor
+	bl	.setup_doorbell_ivors
+	/*
+	 * We only want to touch IVOR38-41 if we're running on hardware
+	 * that supports category E.HV.  The architectural way to determine
+	 * this is MMUCFG[LPIDSIZE].
+	 */
+	mfspr	r10,SPRN_MMUCFG
+	rlwinm.	r10,r10,0,MMUCFG_LPIDSIZE
+	beq	1f
+	bl	.setup_ehv_ivors
+	b	2f
+1:
+	ld	r10,CPU_SPEC_FEATURES(r4)
+	LOAD_REG_IMMEDIATE(r9,CPU_FTR_EMB_HV)
+	andc	r10,r10,r9
+	std	r10,CPU_SPEC_FEATURES(r4)
+2:
+	mtlr	r5
+	blr
+#endif
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 455faa3..0514c21 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -2016,7 +2016,9 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.oprofile_cpu_type	= "ppc/e500mc",
 		.oprofile_type		= PPC_OPROFILE_FSL_EMB,
 		.cpu_setup		= __setup_cpu_e5500,
+#ifndef CONFIG_PPC32
 		.cpu_restore		= __restore_cpu_e5500,
+#endif
 		.machine_check		= machine_check_e500mc,
 		.platform		= "ppce5500",
 	},
@@ -2034,7 +2036,9 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.oprofile_cpu_type	= "ppc/e6500",
 		.oprofile_type		= PPC_OPROFILE_FSL_EMB,
 		.cpu_setup		= __setup_cpu_e5500,
+#ifndef CONFIG_PPC32
 		.cpu_restore		= __restore_cpu_e5500,
+#endif
 		.machine_check		= machine_check_e500mc,
 		.platform		= "ppce6500",
 	},
diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c
index 4694365..dc5c620 100644
--- a/arch/powerpc/kernel/dma-swiotlb.c
+++ b/arch/powerpc/kernel/dma-swiotlb.c
@@ -105,3 +105,23 @@ int __init swiotlb_setup_bus_notifier(void)
 			      &ppc_swiotlb_plat_bus_notifier);
 	return 0;
 }
+
+void swiotlb_detect_4g(void)
+{
+	if ((memblock_end_of_DRAM() - 1) > 0xffffffff)
+		ppc_swiotlb_enable = 1;
+}
+
+static int __init swiotlb_late_init(void)
+{
+	if (ppc_swiotlb_enable) {
+		swiotlb_print_info();
+		set_pci_dma_ops(&swiotlb_dma_ops);
+		ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
+	} else {
+		swiotlb_free();
+	}
+
+	return 0;
+}
+subsys_initcall(swiotlb_late_init);
diff --git a/arch/powerpc/kernel/epapr_hcalls.S b/arch/powerpc/kernel/epapr_hcalls.S
index 697b390..62c0dc2 100644
--- a/arch/powerpc/kernel/epapr_hcalls.S
+++ b/arch/powerpc/kernel/epapr_hcalls.S
@@ -8,13 +8,41 @@
  */
 
 #include <linux/threads.h>
+#include <asm/epapr_hcalls.h>
 #include <asm/reg.h>
 #include <asm/page.h>
 #include <asm/cputable.h>
 #include <asm/thread_info.h>
 #include <asm/ppc_asm.h>
+#include <asm/asm-compat.h>
 #include <asm/asm-offsets.h>
 
+/* epapr_ev_idle() was derived from e500_idle() */
+_GLOBAL(epapr_ev_idle)
+	CURRENT_THREAD_INFO(r3, r1)
+	PPC_LL	r4, TI_LOCAL_FLAGS(r3)	/* set napping bit */
+	ori	r4, r4,_TLF_NAPPING	/* so when we take an exception */
+	PPC_STL	r4, TI_LOCAL_FLAGS(r3)	/* it will return to our caller */
+
+	wrteei	1
+
+idle_loop:
+	LOAD_REG_IMMEDIATE(r11, EV_HCALL_TOKEN(EV_IDLE))
+
+.global epapr_ev_idle_start
+epapr_ev_idle_start:
+	li	r3, -1
+	nop
+	nop
+	nop
+
+	/*
+	 * Guard against spurious wakeups from a hypervisor --
+	 * only interrupt will cause us to return to LR due to
+	 * _TLF_NAPPING.
+	 */
+	b	idle_loop
+
 /* Hypercall entry point. Will be patched with device tree instructions. */
 .global epapr_hypercall_start
 epapr_hypercall_start:
diff --git a/arch/powerpc/kernel/epapr_paravirt.c b/arch/powerpc/kernel/epapr_paravirt.c
index 028aeae..f3eab85 100644
--- a/arch/powerpc/kernel/epapr_paravirt.c
+++ b/arch/powerpc/kernel/epapr_paravirt.c
@@ -21,6 +21,10 @@
 #include <asm/epapr_hcalls.h>
 #include <asm/cacheflush.h>
 #include <asm/code-patching.h>
+#include <asm/machdep.h>
+
+extern void epapr_ev_idle(void);
+extern u32 epapr_ev_idle_start[];
 
 bool epapr_paravirt_enabled;
 
@@ -41,8 +45,13 @@ static int __init epapr_paravirt_init(void)
 	if (len % 4 || len > (4 * 4))
 		return -ENODEV;
 
-	for (i = 0; i < (len / 4); i++)
+	for (i = 0; i < (len / 4); i++) {
 		patch_instruction(epapr_hypercall_start + i, insts[i]);
+		patch_instruction(epapr_ev_idle_start + i, insts[i]);
+	}
+
+	if (of_get_property(hyper_node, "has-idle", NULL))
+		ppc_md.power_save = epapr_ev_idle;
 
 	epapr_paravirt_enabled = true;
 
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
index 98be7f0..ca0ead8 100644
--- a/arch/powerpc/kernel/exceptions-64e.S
+++ b/arch/powerpc/kernel/exceptions-64e.S
@@ -1302,25 +1302,11 @@ _GLOBAL(setup_perfmon_ivor)
 _GLOBAL(setup_doorbell_ivors)
 	SET_IVOR(36, 0x280) /* Processor Doorbell */
 	SET_IVOR(37, 0x2a0) /* Processor Doorbell Crit */
-
-	/* Check MMUCFG[LPIDSIZE] to determine if we have category E.HV */
-	mfspr	r10,SPRN_MMUCFG
-	rlwinm.	r10,r10,0,MMUCFG_LPIDSIZE
-	beqlr
-
-	SET_IVOR(38, 0x2c0) /* Guest Processor Doorbell */
-	SET_IVOR(39, 0x2e0) /* Guest Processor Doorbell Crit/MC */
 	blr
 
 _GLOBAL(setup_ehv_ivors)
-	/*
-	 * We may be running as a guest and lack E.HV even on a chip
-	 * that normally has it.
-	 */
-	mfspr	r10,SPRN_MMUCFG
-	rlwinm.	r10,r10,0,MMUCFG_LPIDSIZE
-	beqlr
-
 	SET_IVOR(40, 0x300) /* Embedded Hypervisor System Call */
 	SET_IVOR(41, 0x320) /* Embedded Hypervisor Privilege */
+	SET_IVOR(38, 0x2c0) /* Guest Processor Doorbell */
+	SET_IVOR(39, 0x2e0) /* Guest Processor Doorbell Crit/MC */
 	blr
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 0f59863..6f62a73 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -895,15 +895,11 @@ _GLOBAL(__setup_e500mc_ivors)
 	mtspr	SPRN_IVOR36,r3
 	li	r3,CriticalDoorbell@l
 	mtspr	SPRN_IVOR37,r3
+	sync
+	blr
 
-	/*
-	 * We only want to touch IVOR38-41 if we're running on hardware
-	 * that supports category E.HV.  The architectural way to determine
-	 * this is MMUCFG[LPIDSIZE].
-	 */
-	mfspr	r3, SPRN_MMUCFG
-	andis.	r3, r3, MMUCFG_LPIDSIZE@h
-	beq	no_hv
+/* setup ehv ivors for */
+_GLOBAL(__setup_ehv_ivors)
 	li	r3,GuestDoorbell@l
 	mtspr	SPRN_IVOR38,r3
 	li	r3,CriticalGuestDoorbell@l
@@ -912,14 +908,8 @@ _GLOBAL(__setup_e500mc_ivors)
 	mtspr	SPRN_IVOR40,r3
 	li	r3,Ehvpriv@l
 	mtspr	SPRN_IVOR41,r3
-skip_hv_ivors:
 	sync
 	blr
-no_hv:
-	lwz	r3, CPU_SPEC_FEATURES(r5)
-	rlwinm	r3, r3, 0, ~CPU_FTR_EMB_HV
-	stw	r3, CPU_SPEC_FEATURES(r5)
-	b	skip_hv_ivors
 
 #ifdef CONFIG_SPE
 /*
@@ -1043,6 +1033,34 @@ _GLOBAL(flush_dcache_L1)
 
 	blr
 
+/* Flush L1 d-cache, invalidate and disable d-cache and i-cache */
+_GLOBAL(__flush_disable_L1)
+	mflr	r10
+	bl	flush_dcache_L1	/* Flush L1 d-cache */
+	mtlr	r10
+
+	mfspr	r4, SPRN_L1CSR0	/* Invalidate and disable d-cache */
+	li	r5, 2
+	rlwimi	r4, r5, 0, 3
+
+	msync
+	isync
+	mtspr	SPRN_L1CSR0, r4
+	isync
+
+1:	mfspr	r4, SPRN_L1CSR0	/* Wait for the invalidate to finish */
+	andi.	r4, r4, 2
+	bne	1b
+
+	mfspr	r4, SPRN_L1CSR1	/* Invalidate and disable i-cache */
+	li	r5, 2
+	rlwimi	r4, r5, 0, 3
+
+	mtspr	SPRN_L1CSR1, r4
+	isync
+
+	blr
+
 #ifdef CONFIG_SMP
 /* When we get here, r24 needs to hold the CPU # */
 	.globl __secondary_start
diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c
index 867db1d..a61b133 100644
--- a/arch/powerpc/kernel/kvm.c
+++ b/arch/powerpc/kernel/kvm.c
@@ -419,7 +419,7 @@ static void kvm_map_magic_page(void *data)
 	in[0] = KVM_MAGIC_PAGE;
 	in[1] = KVM_MAGIC_PAGE;
 
-	kvm_hypercall(in, out, HC_VENDOR_KVM | KVM_HC_PPC_MAP_MAGIC_PAGE);
+	kvm_hypercall(in, out, KVM_HCALL_TOKEN(KVM_HC_PPC_MAP_MAGIC_PAGE));
 
 	*features = out[0];
 }
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 3e40315..e597dde 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -43,6 +43,7 @@
 #include <asm/dcr.h>
 #include <asm/ftrace.h>
 #include <asm/switch_to.h>
+#include <asm/epapr_hcalls.h>
 
 #ifdef CONFIG_PPC32
 extern void transfer_to_handler(void);
@@ -192,3 +193,7 @@ EXPORT_SYMBOL(__arch_hweight64);
 #ifdef CONFIG_PPC_BOOK3S_64
 EXPORT_SYMBOL_GPL(mmu_psize_defs);
 #endif
+
+#ifdef CONFIG_EPAPR_PARAVIRT
+EXPORT_SYMBOL(epapr_hypercall_start);
+#endif
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 0794a30..9ec5e55 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -705,6 +705,7 @@ static void __init early_cmdline_parse(void)
 #endif
 #define OV5_TYPE1_AFFINITY	0x80	/* Type 1 NUMA affinity */
 #define OV5_PFO_HW_RNG		0x80	/* PFO Random Number Generator */
+#define OV5_PFO_HW_842		0x40	/* PFO Compression Accelerator */
 #define OV5_PFO_HW_ENCR		0x20	/* PFO Encryption Accelerator */
 
 /* Option Vector 6: IBM PAPR hints */
@@ -774,8 +775,7 @@ static unsigned char ibm_architecture_vec[] = {
 	0,
 	0,
 	0,
-	OV5_PFO_HW_RNG | OV5_PFO_HW_ENCR,
-
+	OV5_PFO_HW_RNG | OV5_PFO_HW_ENCR | OV5_PFO_HW_842,
 	/* option vector 6: IBM PAPR hints */
 	4 - 2,				/* length */
 	0,
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 8b4c049..804e323 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -35,7 +35,6 @@
 #include <linux/stddef.h>
 #include <linux/tty.h>
 #include <linux/binfmts.h>
-#include <linux/freezer.h>
 #endif
 
 #include <asm/uaccess.h>
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 0321007..fecb038 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -102,7 +102,7 @@ int __devinit smp_generic_kick_cpu(int nr)
 	 * Ok it's not there, so it might be soft-unplugged, let's
 	 * try to bring it back
 	 */
-	per_cpu(cpu_state, nr) = CPU_UP_PREPARE;
+	generic_set_cpu_up(nr);
 	smp_wmb();
 	smp_send_reschedule(nr);
 #endif /* CONFIG_HOTPLUG_CPU */
@@ -406,6 +406,16 @@ void generic_set_cpu_dead(unsigned int cpu)
 	per_cpu(cpu_state, cpu) = CPU_DEAD;
 }
 
+/*
+ * The cpu_state should be set to CPU_UP_PREPARE in kick_cpu(), otherwise
+ * the cpu_state is always CPU_DEAD after calling generic_set_cpu_dead(),
+ * which makes the delay in generic_cpu_die() not happen.
+ */
+void generic_set_cpu_up(unsigned int cpu)
+{
+	per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
+}
+
 int generic_check_cpu_restart(unsigned int cpu)
 {
 	return per_cpu(cpu_state, cpu) == CPU_UP_PREPARE;
diff --git a/arch/powerpc/kvm/44x.c b/arch/powerpc/kvm/44x.c
index 50e7dbc..3d7fd21 100644
--- a/arch/powerpc/kvm/44x.c
+++ b/arch/powerpc/kvm/44x.c
@@ -83,6 +83,7 @@ int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu)
 		vcpu_44x->shadow_refs[i].gtlb_index = -1;
 
 	vcpu->arch.cpu_type = KVM_CPU_440;
+	vcpu->arch.pvr = mfspr(SPRN_PVR);
 
 	return 0;
 }
diff --git a/arch/powerpc/kvm/44x_emulate.c b/arch/powerpc/kvm/44x_emulate.c
index c8c6157..1a793c4 100644
--- a/arch/powerpc/kvm/44x_emulate.c
+++ b/arch/powerpc/kvm/44x_emulate.c
@@ -27,12 +27,68 @@
 #include "booke.h"
 #include "44x_tlb.h"
 
+#define XOP_MFDCRX  259
 #define XOP_MFDCR   323
+#define XOP_MTDCRX  387
 #define XOP_MTDCR   451
 #define XOP_TLBSX   914
 #define XOP_ICCCI   966
 #define XOP_TLBWE   978
 
+static int emulate_mtdcr(struct kvm_vcpu *vcpu, int rs, int dcrn)
+{
+	/* emulate some access in kernel */
+	switch (dcrn) {
+	case DCRN_CPR0_CONFIG_ADDR:
+		vcpu->arch.cpr0_cfgaddr = kvmppc_get_gpr(vcpu, rs);
+		return EMULATE_DONE;
+	default:
+		vcpu->run->dcr.dcrn = dcrn;
+		vcpu->run->dcr.data = kvmppc_get_gpr(vcpu, rs);
+		vcpu->run->dcr.is_write = 1;
+		vcpu->arch.dcr_needed = 1;
+		kvmppc_account_exit(vcpu, DCR_EXITS);
+		return EMULATE_DO_DCR;
+	}
+}
+
+static int emulate_mfdcr(struct kvm_vcpu *vcpu, int rt, int dcrn)
+{
+	/* The guest may access CPR0 registers to determine the timebase
+	 * frequency, and it must know the real host frequency because it
+	 * can directly access the timebase registers.
+	 *
+	 * It would be possible to emulate those accesses in userspace,
+	 * but userspace can really only figure out the end frequency.
+	 * We could decompose that into the factors that compute it, but
+	 * that's tricky math, and it's easier to just report the real
+	 * CPR0 values.
+	 */
+	switch (dcrn) {
+	case DCRN_CPR0_CONFIG_ADDR:
+		kvmppc_set_gpr(vcpu, rt, vcpu->arch.cpr0_cfgaddr);
+		break;
+	case DCRN_CPR0_CONFIG_DATA:
+		local_irq_disable();
+		mtdcr(DCRN_CPR0_CONFIG_ADDR,
+			  vcpu->arch.cpr0_cfgaddr);
+		kvmppc_set_gpr(vcpu, rt,
+			       mfdcr(DCRN_CPR0_CONFIG_DATA));
+		local_irq_enable();
+		break;
+	default:
+		vcpu->run->dcr.dcrn = dcrn;
+		vcpu->run->dcr.data =  0;
+		vcpu->run->dcr.is_write = 0;
+		vcpu->arch.io_gpr = rt;
+		vcpu->arch.dcr_needed = 1;
+		kvmppc_account_exit(vcpu, DCR_EXITS);
+		return EMULATE_DO_DCR;
+	}
+
+	return EMULATE_DONE;
+}
+
 int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                            unsigned int inst, int *advance)
 {
@@ -50,55 +106,21 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		switch (get_xop(inst)) {
 
 		case XOP_MFDCR:
-			/* The guest may access CPR0 registers to determine the timebase
-			 * frequency, and it must know the real host frequency because it
-			 * can directly access the timebase registers.
-			 *
-			 * It would be possible to emulate those accesses in userspace,
-			 * but userspace can really only figure out the end frequency.
-			 * We could decompose that into the factors that compute it, but
-			 * that's tricky math, and it's easier to just report the real
-			 * CPR0 values.
-			 */
-			switch (dcrn) {
-			case DCRN_CPR0_CONFIG_ADDR:
-				kvmppc_set_gpr(vcpu, rt, vcpu->arch.cpr0_cfgaddr);
-				break;
-			case DCRN_CPR0_CONFIG_DATA:
-				local_irq_disable();
-				mtdcr(DCRN_CPR0_CONFIG_ADDR,
-					  vcpu->arch.cpr0_cfgaddr);
-				kvmppc_set_gpr(vcpu, rt,
-					       mfdcr(DCRN_CPR0_CONFIG_DATA));
-				local_irq_enable();
-				break;
-			default:
-				run->dcr.dcrn = dcrn;
-				run->dcr.data =  0;
-				run->dcr.is_write = 0;
-				vcpu->arch.io_gpr = rt;
-				vcpu->arch.dcr_needed = 1;
-				kvmppc_account_exit(vcpu, DCR_EXITS);
-				emulated = EMULATE_DO_DCR;
-			}
+			emulated = emulate_mfdcr(vcpu, rt, dcrn);
+			break;
 
+		case XOP_MFDCRX:
+			emulated = emulate_mfdcr(vcpu, rt,
+					kvmppc_get_gpr(vcpu, ra));
 			break;
 
 		case XOP_MTDCR:
-			/* emulate some access in kernel */
-			switch (dcrn) {
-			case DCRN_CPR0_CONFIG_ADDR:
-				vcpu->arch.cpr0_cfgaddr = kvmppc_get_gpr(vcpu, rs);
-				break;
-			default:
-				run->dcr.dcrn = dcrn;
-				run->dcr.data = kvmppc_get_gpr(vcpu, rs);
-				run->dcr.is_write = 1;
-				vcpu->arch.dcr_needed = 1;
-				kvmppc_account_exit(vcpu, DCR_EXITS);
-				emulated = EMULATE_DO_DCR;
-			}
+			emulated = emulate_mtdcr(vcpu, rs, dcrn);
+			break;
 
+		case XOP_MTDCRX:
+			emulated = emulate_mtdcr(vcpu, rs,
+					kvmppc_get_gpr(vcpu, ra));
 			break;
 
 		case XOP_TLBWE:
diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c
index 33aa715..5dd3ab4 100644
--- a/arch/powerpc/kvm/44x_tlb.c
+++ b/arch/powerpc/kvm/44x_tlb.c
@@ -319,7 +319,6 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr,
 	if (is_error_page(new_page)) {
 		printk(KERN_ERR "Couldn't get guest page for gfn %llx!\n",
 			(unsigned long long)gfn);
-		kvm_release_page_clean(new_page);
 		return;
 	}
 	hpaddr = page_to_phys(new_page);
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
index f4dacb9..71f0cd9 100644
--- a/arch/powerpc/kvm/Kconfig
+++ b/arch/powerpc/kvm/Kconfig
@@ -36,6 +36,7 @@ config KVM_BOOK3S_64_HANDLER
 config KVM_BOOK3S_PR
 	bool
 	select KVM_MMIO
+	select MMU_NOTIFIER
 
 config KVM_BOOK3S_32
 	tristate "KVM support for PowerPC book3s_32 processors"
@@ -123,6 +124,7 @@ config KVM_E500V2
 	depends on EXPERIMENTAL && E500 && !PPC_E500MC
 	select KVM
 	select KVM_MMIO
+	select MMU_NOTIFIER
 	---help---
 	  Support running unmodified E500 guest kernels in virtual machines on
 	  E500v2 host processors.
@@ -138,6 +140,7 @@ config KVM_E500MC
 	select KVM
 	select KVM_MMIO
 	select KVM_BOOKE_HV
+	select MMU_NOTIFIER
 	---help---
 	  Support running unmodified E500MC/E5500 (32-bit) guest kernels in
 	  virtual machines on E500MC/E5500 host processors.
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index 3f2a836..e946665 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -411,6 +411,15 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
+int kvmppc_subarch_vcpu_init(struct kvm_vcpu *vcpu)
+{
+	return 0;
+}
+
+void kvmppc_subarch_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+}
+
 int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
 	int i;
diff --git a/arch/powerpc/kvm/book3s_32_mmu_host.c b/arch/powerpc/kvm/book3s_32_mmu_host.c
index f922c29..9fac010 100644
--- a/arch/powerpc/kvm/book3s_32_mmu_host.c
+++ b/arch/powerpc/kvm/book3s_32_mmu_host.c
@@ -211,6 +211,9 @@ next_pteg:
 		pteg1 |= PP_RWRX;
 	}
 
+	if (orig_pte->may_execute)
+		kvmppc_mmu_flush_icache(hpaddr >> PAGE_SHIFT);
+
 	local_irq_disable();
 
 	if (pteg[rr]) {
@@ -251,6 +254,7 @@ next_pteg:
 
 	kvmppc_mmu_hpte_cache_map(vcpu, pte);
 
+	kvm_release_pfn_clean(hpaddr >> PAGE_SHIFT);
 out:
 	return r;
 }
diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c
index 10fc8ec..6b2c80e 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_host.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_host.c
@@ -126,6 +126,8 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
 
 	if (!orig_pte->may_execute)
 		rflags |= HPTE_R_N;
+	else
+		kvmppc_mmu_flush_icache(hpaddr >> PAGE_SHIFT);
 
 	hash = hpt_hash(va, PTE_SIZE, MMU_SEGSIZE_256M);
 
@@ -166,6 +168,7 @@ map_again:
 
 		kvmppc_mmu_hpte_cache_map(vcpu, pte);
 	}
+	kvm_release_pfn_clean(hpaddr >> PAGE_SHIFT);
 
 out:
 	return r;
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index d03eb6f..d95d113 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -705,7 +705,7 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		goto out_unlock;
 	hpte[0] = (hpte[0] & ~HPTE_V_ABSENT) | HPTE_V_VALID;
 
-	rmap = &memslot->rmap[gfn - memslot->base_gfn];
+	rmap = &memslot->arch.rmap[gfn - memslot->base_gfn];
 	lock_rmap(rmap);
 
 	/* Check if we might have been invalidated; let the guest retry if so */
@@ -756,9 +756,12 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	goto out_put;
 }
 
-static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
-			  int (*handler)(struct kvm *kvm, unsigned long *rmapp,
-					 unsigned long gfn))
+static int kvm_handle_hva_range(struct kvm *kvm,
+				unsigned long start,
+				unsigned long end,
+				int (*handler)(struct kvm *kvm,
+					       unsigned long *rmapp,
+					       unsigned long gfn))
 {
 	int ret;
 	int retval = 0;
@@ -767,15 +770,25 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
 
 	slots = kvm_memslots(kvm);
 	kvm_for_each_memslot(memslot, slots) {
-		unsigned long start = memslot->userspace_addr;
-		unsigned long end;
+		unsigned long hva_start, hva_end;
+		gfn_t gfn, gfn_end;
 
-		end = start + (memslot->npages << PAGE_SHIFT);
-		if (hva >= start && hva < end) {
-			gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT;
+		hva_start = max(start, memslot->userspace_addr);
+		hva_end = min(end, memslot->userspace_addr +
+					(memslot->npages << PAGE_SHIFT));
+		if (hva_start >= hva_end)
+			continue;
+		/*
+		 * {gfn(page) | page intersects with [hva_start, hva_end)} =
+		 * {gfn, gfn+1, ..., gfn_end-1}.
+		 */
+		gfn = hva_to_gfn_memslot(hva_start, memslot);
+		gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot);
+
+		for (; gfn < gfn_end; ++gfn) {
+			gfn_t gfn_offset = gfn - memslot->base_gfn;
 
-			ret = handler(kvm, &memslot->rmap[gfn_offset],
-				      memslot->base_gfn + gfn_offset);
+			ret = handler(kvm, &memslot->arch.rmap[gfn_offset], gfn);
 			retval |= ret;
 		}
 	}
@@ -783,6 +796,13 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
 	return retval;
 }
 
+static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
+			  int (*handler)(struct kvm *kvm, unsigned long *rmapp,
+					 unsigned long gfn))
+{
+	return kvm_handle_hva_range(kvm, hva, hva + 1, handler);
+}
+
 static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
 			   unsigned long gfn)
 {
@@ -850,6 +870,13 @@ int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
 	return 0;
 }
 
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
+{
+	if (kvm->arch.using_mmu_notifiers)
+		kvm_handle_hva_range(kvm, start, end, kvm_unmap_rmapp);
+	return 0;
+}
+
 static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
 			 unsigned long gfn)
 {
@@ -1009,7 +1036,7 @@ long kvmppc_hv_get_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
 	unsigned long *rmapp, *map;
 
 	preempt_disable();
-	rmapp = memslot->rmap;
+	rmapp = memslot->arch.rmap;
 	map = memslot->dirty_bitmap;
 	for (i = 0; i < memslot->npages; ++i) {
 		if (kvm_test_clear_dirty(kvm, rmapp))
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 83e929e..721d460 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -1183,7 +1183,7 @@ static const struct vm_operations_struct kvm_rma_vm_ops = {
 
 static int kvm_rma_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	vma->vm_flags |= VM_RESERVED;
+	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
 	vma->vm_ops = &kvm_rma_vm_ops;
 	return 0;
 }
diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c
index fb4eac2..ec0a9e5 100644
--- a/arch/powerpc/kvm/book3s_hv_builtin.c
+++ b/arch/powerpc/kvm/book3s_hv_builtin.c
@@ -157,8 +157,8 @@ static void __init kvm_linear_init_one(ulong size, int count, int type)
 	linear_info = alloc_bootmem(count * sizeof(struct kvmppc_linear_info));
 	for (i = 0; i < count; ++i) {
 		linear = alloc_bootmem_align(size, size);
-		pr_info("Allocated KVM %s at %p (%ld MB)\n", typestr, linear,
-			size >> 20);
+		pr_debug("Allocated KVM %s at %p (%ld MB)\n", typestr, linear,
+			 size >> 20);
 		linear_info[i].base_virt = linear;
 		linear_info[i].base_pfn = __pa(linear) >> PAGE_SHIFT;
 		linear_info[i].npages = npages;
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index 5c70d19..56ac1a5 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -84,7 +84,7 @@ static void remove_revmap_chain(struct kvm *kvm, long pte_index,
 	if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID))
 		return;
 
-	rmap = real_vmalloc_addr(&memslot->rmap[gfn - memslot->base_gfn]);
+	rmap = real_vmalloc_addr(&memslot->arch.rmap[gfn - memslot->base_gfn]);
 	lock_rmap(rmap);
 
 	head = *rmap & KVMPPC_RMAP_INDEX;
@@ -180,7 +180,7 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
 	if (!slot_is_aligned(memslot, psize))
 		return H_PARAMETER;
 	slot_fn = gfn - memslot->base_gfn;
-	rmap = &memslot->rmap[slot_fn];
+	rmap = &memslot->arch.rmap[slot_fn];
 
 	if (!kvm->arch.using_mmu_notifiers) {
 		physp = kvm->arch.slot_phys[memslot->id];
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 5a84c8d..44b72fe 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -1421,13 +1421,13 @@ _GLOBAL(kvmppc_h_cede)
 	sync			/* order setting ceded vs. testing prodded */
 	lbz	r5,VCPU_PRODDED(r3)
 	cmpwi	r5,0
-	bne	1f
+	bne	kvm_cede_prodded
 	li	r0,0		/* set trap to 0 to say hcall is handled */
 	stw	r0,VCPU_TRAP(r3)
 	li	r0,H_SUCCESS
 	std	r0,VCPU_GPR(R3)(r3)
 BEGIN_FTR_SECTION
-	b	2f		/* just send it up to host on 970 */
+	b	kvm_cede_exit	/* just send it up to host on 970 */
 END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
 
 	/*
@@ -1446,7 +1446,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
 	or	r4,r4,r0
 	PPC_POPCNTW(R7,R4)
 	cmpw	r7,r8
-	bge	2f
+	bge	kvm_cede_exit
 	stwcx.	r4,0,r6
 	bne	31b
 	li	r0,1
@@ -1555,7 +1555,8 @@ kvm_end_cede:
 	b	hcall_real_fallback
 
 	/* cede when already previously prodded case */
-1:	li	r0,0
+kvm_cede_prodded:
+	li	r0,0
 	stb	r0,VCPU_PRODDED(r3)
 	sync			/* order testing prodded vs. clearing ceded */
 	stb	r0,VCPU_CEDED(r3)
@@ -1563,7 +1564,8 @@ kvm_end_cede:
 	blr
 
 	/* we've ceded but we want to give control to the host */
-2:	li	r3,H_TOO_HARD
+kvm_cede_exit:
+	li	r3,H_TOO_HARD
 	blr
 
 secondary_too_late:
diff --git a/arch/powerpc/kvm/book3s_mmu_hpte.c b/arch/powerpc/kvm/book3s_mmu_hpte.c
index 41cb001..2c86b0d 100644
--- a/arch/powerpc/kvm/book3s_mmu_hpte.c
+++ b/arch/powerpc/kvm/book3s_mmu_hpte.c
@@ -114,11 +114,6 @@ static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
 	hlist_del_init_rcu(&pte->list_vpte);
 	hlist_del_init_rcu(&pte->list_vpte_long);
 
-	if (pte->pte.may_write)
-		kvm_release_pfn_dirty(pte->pfn);
-	else
-		kvm_release_pfn_clean(pte->pfn);
-
 	spin_unlock(&vcpu3s->mmu_lock);
 
 	vcpu3s->hpte_cache_count--;
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index a1baec3..b3c584f 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -52,8 +52,6 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
 #define MSR_USER32 MSR_USER
 #define MSR_USER64 MSR_USER
 #define HW_PAGE_SIZE PAGE_SIZE
-#define __hard_irq_disable local_irq_disable
-#define __hard_irq_enable local_irq_enable
 #endif
 
 void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
@@ -88,6 +86,61 @@ void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
 	kvmppc_giveup_ext(vcpu, MSR_VSX);
 }
 
+int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)
+{
+	int r = 1; /* Indicate we want to get back into the guest */
+
+	/* We misuse TLB_FLUSH to indicate that we want to clear
+	   all shadow cache entries */
+	if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu))
+		kvmppc_mmu_pte_flush(vcpu, 0, 0);
+
+	return r;
+}
+
+/************* MMU Notifiers *************/
+
+int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
+{
+	trace_kvm_unmap_hva(hva);
+
+	/*
+	 * Flush all shadow tlb entries everywhere. This is slow, but
+	 * we are 100% sure that we catch the to be unmapped page
+	 */
+	kvm_flush_remote_tlbs(kvm);
+
+	return 0;
+}
+
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
+{
+	/* kvm_unmap_hva flushes everything anyways */
+	kvm_unmap_hva(kvm, start);
+
+	return 0;
+}
+
+int kvm_age_hva(struct kvm *kvm, unsigned long hva)
+{
+	/* XXX could be more clever ;) */
+	return 0;
+}
+
+int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
+{
+	/* XXX could be more clever ;) */
+	return 0;
+}
+
+void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
+{
+	/* The page will get remapped properly on its next fault */
+	kvm_unmap_hva(kvm, hva);
+}
+
+/*****************************************/
+
 static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu)
 {
 	ulong smsr = vcpu->arch.shared->msr;
@@ -242,10 +295,8 @@ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
 	int i;
 
 	hpage = gfn_to_page(vcpu->kvm, pte->raddr >> PAGE_SHIFT);
-	if (is_error_page(hpage)) {
-		kvm_release_page_clean(hpage);
+	if (is_error_page(hpage))
 		return;
-	}
 
 	hpage_offset = pte->raddr & ~PAGE_MASK;
 	hpage_offset &= ~0xFFFULL;
@@ -542,18 +593,18 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                        unsigned int exit_nr)
 {
 	int r = RESUME_HOST;
+	int s;
 
 	vcpu->stat.sum_exits++;
 
 	run->exit_reason = KVM_EXIT_UNKNOWN;
 	run->ready_for_interrupt_injection = 1;
 
-	/* We get here with MSR.EE=0, so enable it to be a nice citizen */
-	__hard_irq_enable();
+	/* We get here with MSR.EE=1 */
+
+	trace_kvm_exit(exit_nr, vcpu);
+	kvm_guest_exit();
 
-	trace_kvm_book3s_exit(exit_nr, vcpu);
-	preempt_enable();
-	kvm_resched(vcpu);
 	switch (exit_nr) {
 	case BOOK3S_INTERRUPT_INST_STORAGE:
 	{
@@ -804,7 +855,6 @@ program_interrupt:
 	}
 	}
 
-	preempt_disable();
 	if (!(r & RESUME_HOST)) {
 		/* To avoid clobbering exit_reason, only check for signals if
 		 * we aren't already exiting to userspace for some other
@@ -816,20 +866,13 @@ program_interrupt:
 		 * and if we really did time things so badly, then we just exit
 		 * again due to a host external interrupt.
 		 */
-		__hard_irq_disable();
-		if (signal_pending(current)) {
-			__hard_irq_enable();
-#ifdef EXIT_DEBUG
-			printk(KERN_EMERG "KVM: Going back to host\n");
-#endif
-			vcpu->stat.signal_exits++;
-			run->exit_reason = KVM_EXIT_INTR;
-			r = -EINTR;
+		local_irq_disable();
+		s = kvmppc_prepare_to_enter(vcpu);
+		if (s <= 0) {
+			local_irq_enable();
+			r = s;
 		} else {
-			/* In case an interrupt came in that was triggered
-			 * from userspace (like DEC), we need to check what
-			 * to inject now! */
-			kvmppc_core_prepare_to_enter(vcpu);
+			kvmppc_lazy_ee_enable();
 		}
 	}
 
@@ -1022,8 +1065,6 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 #endif
 	ulong ext_msr;
 
-	preempt_disable();
-
 	/* Check if we can run the vcpu at all */
 	if (!vcpu->arch.sane) {
 		kvm_run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
@@ -1031,21 +1072,16 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 		goto out;
 	}
 
-	kvmppc_core_prepare_to_enter(vcpu);
-
 	/*
 	 * Interrupts could be timers for the guest which we have to inject
 	 * again, so let's postpone them until we're in the guest and if we
 	 * really did time things so badly, then we just exit again due to
 	 * a host external interrupt.
 	 */
-	__hard_irq_disable();
-
-	/* No need to go into the guest when all we do is going out */
-	if (signal_pending(current)) {
-		__hard_irq_enable();
-		kvm_run->exit_reason = KVM_EXIT_INTR;
-		ret = -EINTR;
+	local_irq_disable();
+	ret = kvmppc_prepare_to_enter(vcpu);
+	if (ret <= 0) {
+		local_irq_enable();
 		goto out;
 	}
 
@@ -1082,11 +1118,12 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 	if (vcpu->arch.shared->msr & MSR_FP)
 		kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);
 
-	kvm_guest_enter();
+	kvmppc_lazy_ee_enable();
 
 	ret = __kvmppc_vcpu_run(kvm_run, vcpu);
 
-	kvm_guest_exit();
+	/* No need for kvm_guest_exit. It's done in handle_exit.
+	   We also get here with interrupts enabled. */
 
 	current->thread.regs->msr = ext_msr;
 
@@ -1115,7 +1152,7 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 #endif
 
 out:
-	preempt_enable();
+	vcpu->mode = OUTSIDE_GUEST_MODE;
 	return ret;
 }
 
diff --git a/arch/powerpc/kvm/book3s_rmhandlers.S b/arch/powerpc/kvm/book3s_rmhandlers.S
index 9ecf6e3..b2f8258 100644
--- a/arch/powerpc/kvm/book3s_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_rmhandlers.S
@@ -170,20 +170,21 @@ kvmppc_handler_skip_ins:
  * Call kvmppc_handler_trampoline_enter in real mode
  *
  * On entry, r4 contains the guest shadow MSR
+ * MSR.EE has to be 0 when calling this function
  */
 _GLOBAL(kvmppc_entry_trampoline)
 	mfmsr	r5
 	LOAD_REG_ADDR(r7, kvmppc_handler_trampoline_enter)
 	toreal(r7)
 
-	li	r9, MSR_RI
-	ori	r9, r9, MSR_EE
-	andc	r9, r5, r9	/* Clear EE and RI in MSR value */
 	li	r6, MSR_IR | MSR_DR
-	ori	r6, r6, MSR_EE
-	andc	r6, r5, r6	/* Clear EE, DR and IR in MSR value */
-	MTMSR_EERI(r9)		/* Clear EE and RI in MSR */
-	mtsrr0	r7		/* before we set srr0/1 */
+	andc	r6, r5, r6	/* Clear DR and IR in MSR value */
+	/*
+	 * Set EE in HOST_MSR so that it's enabled when we get into our
+	 * C exit handler function
+	 */
+	ori	r5, r5, MSR_EE
+	mtsrr0	r7
 	mtsrr1	r6
 	RFI
 
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index d25a097..5f0476a 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -39,6 +39,7 @@
 
 #include "timing.h"
 #include "booke.h"
+#include "trace.h"
 
 unsigned long kvmppc_booke_handlers;
 
@@ -62,6 +63,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
 	{ "halt_wakeup", VCPU_STAT(halt_wakeup) },
 	{ "doorbell", VCPU_STAT(dbell_exits) },
 	{ "guest doorbell", VCPU_STAT(gdbell_exits) },
+	{ "remote_tlb_flush", VM_STAT(remote_tlb_flush) },
 	{ NULL }
 };
 
@@ -120,6 +122,16 @@ static void kvmppc_vcpu_sync_spe(struct kvm_vcpu *vcpu)
 }
 #endif
 
+static void kvmppc_vcpu_sync_fpu(struct kvm_vcpu *vcpu)
+{
+#if defined(CONFIG_PPC_FPU) && !defined(CONFIG_KVM_BOOKE_HV)
+	/* We always treat the FP bit as enabled from the host
+	   perspective, so only need to adjust the shadow MSR */
+	vcpu->arch.shadow_msr &= ~MSR_FP;
+	vcpu->arch.shadow_msr |= vcpu->arch.shared->msr & MSR_FP;
+#endif
+}
+
 /*
  * Helper function for "full" MSR writes.  No need to call this if only
  * EE/CE/ME/DE/RI are changing.
@@ -136,11 +148,13 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
 
 	kvmppc_mmu_msr_notify(vcpu, old_msr);
 	kvmppc_vcpu_sync_spe(vcpu);
+	kvmppc_vcpu_sync_fpu(vcpu);
 }
 
 static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu,
                                        unsigned int priority)
 {
+	trace_kvm_booke_queue_irqprio(vcpu, priority);
 	set_bit(priority, &vcpu->arch.pending_exceptions);
 }
 
@@ -206,6 +220,16 @@ void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu,
 	clear_bit(BOOKE_IRQPRIO_EXTERNAL_LEVEL, &vcpu->arch.pending_exceptions);
 }
 
+static void kvmppc_core_queue_watchdog(struct kvm_vcpu *vcpu)
+{
+	kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_WATCHDOG);
+}
+
+static void kvmppc_core_dequeue_watchdog(struct kvm_vcpu *vcpu)
+{
+	clear_bit(BOOKE_IRQPRIO_WATCHDOG, &vcpu->arch.pending_exceptions);
+}
+
 static void set_guest_srr(struct kvm_vcpu *vcpu, unsigned long srr0, u32 srr1)
 {
 #ifdef CONFIG_KVM_BOOKE_HV
@@ -325,6 +349,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
 		msr_mask = MSR_CE | MSR_ME | MSR_DE;
 		int_class = INT_CLASS_NONCRIT;
 		break;
+	case BOOKE_IRQPRIO_WATCHDOG:
 	case BOOKE_IRQPRIO_CRITICAL:
 	case BOOKE_IRQPRIO_DBELL_CRIT:
 		allowed = vcpu->arch.shared->msr & MSR_CE;
@@ -404,12 +429,121 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
 	return allowed;
 }
 
+/*
+ * Return the number of jiffies until the next timeout.  If the timeout is
+ * longer than the NEXT_TIMER_MAX_DELTA, then return NEXT_TIMER_MAX_DELTA
+ * because the larger value can break the timer APIs.
+ */
+static unsigned long watchdog_next_timeout(struct kvm_vcpu *vcpu)
+{
+	u64 tb, wdt_tb, wdt_ticks = 0;
+	u64 nr_jiffies = 0;
+	u32 period = TCR_GET_WP(vcpu->arch.tcr);
+
+	wdt_tb = 1ULL << (63 - period);
+	tb = get_tb();
+	/*
+	 * The watchdog timeout will hapeen when TB bit corresponding
+	 * to watchdog will toggle from 0 to 1.
+	 */
+	if (tb & wdt_tb)
+		wdt_ticks = wdt_tb;
+
+	wdt_ticks += wdt_tb - (tb & (wdt_tb - 1));
+
+	/* Convert timebase ticks to jiffies */
+	nr_jiffies = wdt_ticks;
+
+	if (do_div(nr_jiffies, tb_ticks_per_jiffy))
+		nr_jiffies++;
+
+	return min_t(unsigned long long, nr_jiffies, NEXT_TIMER_MAX_DELTA);
+}
+
+static void arm_next_watchdog(struct kvm_vcpu *vcpu)
+{
+	unsigned long nr_jiffies;
+	unsigned long flags;
+
+	/*
+	 * If TSR_ENW and TSR_WIS are not set then no need to exit to
+	 * userspace, so clear the KVM_REQ_WATCHDOG request.
+	 */
+	if ((vcpu->arch.tsr & (TSR_ENW | TSR_WIS)) != (TSR_ENW | TSR_WIS))
+		clear_bit(KVM_REQ_WATCHDOG, &vcpu->requests);
+
+	spin_lock_irqsave(&vcpu->arch.wdt_lock, flags);
+	nr_jiffies = watchdog_next_timeout(vcpu);
+	/*
+	 * If the number of jiffies of watchdog timer >= NEXT_TIMER_MAX_DELTA
+	 * then do not run the watchdog timer as this can break timer APIs.
+	 */
+	if (nr_jiffies < NEXT_TIMER_MAX_DELTA)
+		mod_timer(&vcpu->arch.wdt_timer, jiffies + nr_jiffies);
+	else
+		del_timer(&vcpu->arch.wdt_timer);
+	spin_unlock_irqrestore(&vcpu->arch.wdt_lock, flags);
+}
+
+void kvmppc_watchdog_func(unsigned long data)
+{
+	struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
+	u32 tsr, new_tsr;
+	int final;
+
+	do {
+		new_tsr = tsr = vcpu->arch.tsr;
+		final = 0;
+
+		/* Time out event */
+		if (tsr & TSR_ENW) {
+			if (tsr & TSR_WIS)
+				final = 1;
+			else
+				new_tsr = tsr | TSR_WIS;
+		} else {
+			new_tsr = tsr | TSR_ENW;
+		}
+	} while (cmpxchg(&vcpu->arch.tsr, tsr, new_tsr) != tsr);
+
+	if (new_tsr & TSR_WIS) {
+		smp_wmb();
+		kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu);
+		kvm_vcpu_kick(vcpu);
+	}
+
+	/*
+	 * If this is final watchdog expiry and some action is required
+	 * then exit to userspace.
+	 */
+	if (final && (vcpu->arch.tcr & TCR_WRC_MASK) &&
+	    vcpu->arch.watchdog_enabled) {
+		smp_wmb();
+		kvm_make_request(KVM_REQ_WATCHDOG, vcpu);
+		kvm_vcpu_kick(vcpu);
+	}
+
+	/*
+	 * Stop running the watchdog timer after final expiration to
+	 * prevent the host from being flooded with timers if the
+	 * guest sets a short period.
+	 * Timers will resume when TSR/TCR is updated next time.
+	 */
+	if (!final)
+		arm_next_watchdog(vcpu);
+}
+
 static void update_timer_ints(struct kvm_vcpu *vcpu)
 {
 	if ((vcpu->arch.tcr & TCR_DIE) && (vcpu->arch.tsr & TSR_DIS))
 		kvmppc_core_queue_dec(vcpu);
 	else
 		kvmppc_core_dequeue_dec(vcpu);
+
+	if ((vcpu->arch.tcr & TCR_WIE) && (vcpu->arch.tsr & TSR_WIS))
+		kvmppc_core_queue_watchdog(vcpu);
+	else
+		kvmppc_core_dequeue_watchdog(vcpu);
 }
 
 static void kvmppc_core_check_exceptions(struct kvm_vcpu *vcpu)
@@ -417,13 +551,6 @@ static void kvmppc_core_check_exceptions(struct kvm_vcpu *vcpu)
 	unsigned long *pending = &vcpu->arch.pending_exceptions;
 	unsigned int priority;
 
-	if (vcpu->requests) {
-		if (kvm_check_request(KVM_REQ_PENDING_TIMER, vcpu)) {
-			smp_mb();
-			update_timer_ints(vcpu);
-		}
-	}
-
 	priority = __ffs(*pending);
 	while (priority < BOOKE_IRQPRIO_MAX) {
 		if (kvmppc_booke_irqprio_deliver(vcpu, priority))
@@ -459,37 +586,20 @@ int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
 	return r;
 }
 
-/*
- * Common checks before entering the guest world.  Call with interrupts
- * disabled.
- *
- * returns !0 if a signal is pending and check_signal is true
- */
-static int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
+int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)
 {
-	int r = 0;
-
-	WARN_ON_ONCE(!irqs_disabled());
-	while (true) {
-		if (need_resched()) {
-			local_irq_enable();
-			cond_resched();
-			local_irq_disable();
-			continue;
-		}
-
-		if (signal_pending(current)) {
-			r = 1;
-			break;
-		}
+	int r = 1; /* Indicate we want to get back into the guest */
 
-		if (kvmppc_core_prepare_to_enter(vcpu)) {
-			/* interrupts got enabled in between, so we
-			   are back at square 1 */
-			continue;
-		}
+	if (kvm_check_request(KVM_REQ_PENDING_TIMER, vcpu))
+		update_timer_ints(vcpu);
+#if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC)
+	if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu))
+		kvmppc_core_flush_tlb(vcpu);
+#endif
 
-		break;
+	if (kvm_check_request(KVM_REQ_WATCHDOG, vcpu)) {
+		vcpu->run->exit_reason = KVM_EXIT_WATCHDOG;
+		r = 0;
 	}
 
 	return r;
@@ -497,7 +607,7 @@ static int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
 
 int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 {
-	int ret;
+	int ret, s;
 #ifdef CONFIG_PPC_FPU
 	unsigned int fpscr;
 	int fpexc_mode;
@@ -510,11 +620,13 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 	}
 
 	local_irq_disable();
-	if (kvmppc_prepare_to_enter(vcpu)) {
-		kvm_run->exit_reason = KVM_EXIT_INTR;
-		ret = -EINTR;
+	s = kvmppc_prepare_to_enter(vcpu);
+	if (s <= 0) {
+		local_irq_enable();
+		ret = s;
 		goto out;
 	}
+	kvmppc_lazy_ee_enable();
 
 	kvm_guest_enter();
 
@@ -542,6 +654,9 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
 	ret = __kvmppc_vcpu_run(kvm_run, vcpu);
 
+	/* No need for kvm_guest_exit. It's done in handle_exit.
+	   We also get here with interrupts enabled. */
+
 #ifdef CONFIG_PPC_FPU
 	kvmppc_save_guest_fp(vcpu);
 
@@ -557,10 +672,9 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 	current->thread.fpexc_mode = fpexc_mode;
 #endif
 
-	kvm_guest_exit();
-
 out:
-	local_irq_enable();
+	vcpu->mode = OUTSIDE_GUEST_MODE;
+	smp_wmb();
 	return ret;
 }
 
@@ -668,6 +782,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                        unsigned int exit_nr)
 {
 	int r = RESUME_HOST;
+	int s;
 
 	/* update before a new last_exit_type is rewritten */
 	kvmppc_update_timing_stats(vcpu);
@@ -677,6 +792,9 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 
 	local_irq_enable();
 
+	trace_kvm_exit(exit_nr, vcpu);
+	kvm_guest_exit();
+
 	run->exit_reason = KVM_EXIT_UNKNOWN;
 	run->ready_for_interrupt_injection = 1;
 
@@ -971,10 +1089,12 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	 */
 	if (!(r & RESUME_HOST)) {
 		local_irq_disable();
-		if (kvmppc_prepare_to_enter(vcpu)) {
-			run->exit_reason = KVM_EXIT_INTR;
-			r = (-EINTR << 2) | RESUME_HOST | (r & RESUME_FLAG_NV);
-			kvmppc_account_exit(vcpu, SIGNAL_EXITS);
+		s = kvmppc_prepare_to_enter(vcpu);
+		if (s <= 0) {
+			local_irq_enable();
+			r = (s << 2) | RESUME_HOST | (r & RESUME_FLAG_NV);
+		} else {
+			kvmppc_lazy_ee_enable();
 		}
 	}
 
@@ -1011,6 +1131,21 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 	return r;
 }
 
+int kvmppc_subarch_vcpu_init(struct kvm_vcpu *vcpu)
+{
+	/* setup watchdog timer once */
+	spin_lock_init(&vcpu->arch.wdt_lock);
+	setup_timer(&vcpu->arch.wdt_timer, kvmppc_watchdog_func,
+		    (unsigned long)vcpu);
+
+	return 0;
+}
+
+void kvmppc_subarch_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+	del_timer_sync(&vcpu->arch.wdt_timer);
+}
+
 int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
 	int i;
@@ -1106,7 +1241,13 @@ static int set_sregs_base(struct kvm_vcpu *vcpu,
 	}
 
 	if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_TSR) {
+		u32 old_tsr = vcpu->arch.tsr;
+
 		vcpu->arch.tsr = sregs->u.e.tsr;
+
+		if ((old_tsr ^ vcpu->arch.tsr) & (TSR_ENW | TSR_WIS))
+			arm_next_watchdog(vcpu);
+
 		update_timer_ints(vcpu);
 	}
 
@@ -1221,12 +1362,56 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 
 int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
 {
-	return -EINVAL;
+	int r = -EINVAL;
+
+	switch (reg->id) {
+	case KVM_REG_PPC_IAC1:
+	case KVM_REG_PPC_IAC2:
+	case KVM_REG_PPC_IAC3:
+	case KVM_REG_PPC_IAC4: {
+		int iac = reg->id - KVM_REG_PPC_IAC1;
+		r = copy_to_user((u64 __user *)(long)reg->addr,
+				 &vcpu->arch.dbg_reg.iac[iac], sizeof(u64));
+		break;
+	}
+	case KVM_REG_PPC_DAC1:
+	case KVM_REG_PPC_DAC2: {
+		int dac = reg->id - KVM_REG_PPC_DAC1;
+		r = copy_to_user((u64 __user *)(long)reg->addr,
+				 &vcpu->arch.dbg_reg.dac[dac], sizeof(u64));
+		break;
+	}
+	default:
+		break;
+	}
+	return r;
 }
 
 int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
 {
-	return -EINVAL;
+	int r = -EINVAL;
+
+	switch (reg->id) {
+	case KVM_REG_PPC_IAC1:
+	case KVM_REG_PPC_IAC2:
+	case KVM_REG_PPC_IAC3:
+	case KVM_REG_PPC_IAC4: {
+		int iac = reg->id - KVM_REG_PPC_IAC1;
+		r = copy_from_user(&vcpu->arch.dbg_reg.iac[iac],
+			     (u64 __user *)(long)reg->addr, sizeof(u64));
+		break;
+	}
+	case KVM_REG_PPC_DAC1:
+	case KVM_REG_PPC_DAC2: {
+		int dac = reg->id - KVM_REG_PPC_DAC1;
+		r = copy_from_user(&vcpu->arch.dbg_reg.dac[dac],
+			     (u64 __user *)(long)reg->addr, sizeof(u64));
+		break;
+	}
+	default:
+		break;
+	}
+	return r;
 }
 
 int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
@@ -1267,6 +1452,7 @@ void kvmppc_core_commit_memory_region(struct kvm *kvm,
 void kvmppc_set_tcr(struct kvm_vcpu *vcpu, u32 new_tcr)
 {
 	vcpu->arch.tcr = new_tcr;
+	arm_next_watchdog(vcpu);
 	update_timer_ints(vcpu);
 }
 
@@ -1281,6 +1467,14 @@ void kvmppc_set_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits)
 void kvmppc_clr_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits)
 {
 	clear_bits(tsr_bits, &vcpu->arch.tsr);
+
+	/*
+	 * We may have stopped the watchdog due to
+	 * being stuck on final expiration.
+	 */
+	if (tsr_bits & (TSR_ENW | TSR_WIS))
+		arm_next_watchdog(vcpu);
+
 	update_timer_ints(vcpu);
 }
 
diff --git a/arch/powerpc/kvm/booke_emulate.c b/arch/powerpc/kvm/booke_emulate.c
index 12834bb..514790f 100644
--- a/arch/powerpc/kvm/booke_emulate.c
+++ b/arch/powerpc/kvm/booke_emulate.c
@@ -133,10 +133,10 @@ int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
 		vcpu->arch.csrr1 = spr_val;
 		break;
 	case SPRN_DBCR0:
-		vcpu->arch.dbcr0 = spr_val;
+		vcpu->arch.dbg_reg.dbcr0 = spr_val;
 		break;
 	case SPRN_DBCR1:
-		vcpu->arch.dbcr1 = spr_val;
+		vcpu->arch.dbg_reg.dbcr1 = spr_val;
 		break;
 	case SPRN_DBSR:
 		vcpu->arch.dbsr &= ~spr_val;
@@ -145,6 +145,14 @@ int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
 		kvmppc_clr_tsr_bits(vcpu, spr_val);
 		break;
 	case SPRN_TCR:
+		/*
+		 * WRC is a 2-bit field that is supposed to preserve its
+		 * value once written to non-zero.
+		 */
+		if (vcpu->arch.tcr & TCR_WRC_MASK) {
+			spr_val &= ~TCR_WRC_MASK;
+			spr_val |= vcpu->arch.tcr & TCR_WRC_MASK;
+		}
 		kvmppc_set_tcr(vcpu, spr_val);
 		break;
 
@@ -229,6 +237,9 @@ int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
 	case SPRN_IVOR15:
 		vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG] = spr_val;
 		break;
+	case SPRN_MCSR:
+		vcpu->arch.mcsr &= ~spr_val;
+		break;
 
 	default:
 		emulated = EMULATE_FAIL;
@@ -258,10 +269,10 @@ int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val)
 		*spr_val = vcpu->arch.csrr1;
 		break;
 	case SPRN_DBCR0:
-		*spr_val = vcpu->arch.dbcr0;
+		*spr_val = vcpu->arch.dbg_reg.dbcr0;
 		break;
 	case SPRN_DBCR1:
-		*spr_val = vcpu->arch.dbcr1;
+		*spr_val = vcpu->arch.dbg_reg.dbcr1;
 		break;
 	case SPRN_DBSR:
 		*spr_val = vcpu->arch.dbsr;
@@ -321,6 +332,9 @@ int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val)
 	case SPRN_IVOR15:
 		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG];
 		break;
+	case SPRN_MCSR:
+		*spr_val = vcpu->arch.mcsr;
+		break;
 
 	default:
 		emulated = EMULATE_FAIL;
diff --git a/arch/powerpc/kvm/e500.h b/arch/powerpc/kvm/e500.h
index aa8b814..d162286 100644
--- a/arch/powerpc/kvm/e500.h
+++ b/arch/powerpc/kvm/e500.h
@@ -27,8 +27,7 @@
 #define E500_TLB_NUM   2
 
 #define E500_TLB_VALID 1
-#define E500_TLB_DIRTY 2
-#define E500_TLB_BITMAP 4
+#define E500_TLB_BITMAP 2
 
 struct tlbe_ref {
 	pfn_t pfn;
diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c
index c510fc9..43489a8 100644
--- a/arch/powerpc/kvm/e500_tlb.c
+++ b/arch/powerpc/kvm/e500_tlb.c
@@ -304,17 +304,13 @@ static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
 	ref->flags = E500_TLB_VALID;
 
 	if (tlbe_is_writable(gtlbe))
-		ref->flags |= E500_TLB_DIRTY;
+		kvm_set_pfn_dirty(pfn);
 }
 
 static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref)
 {
 	if (ref->flags & E500_TLB_VALID) {
-		if (ref->flags & E500_TLB_DIRTY)
-			kvm_release_pfn_dirty(ref->pfn);
-		else
-			kvm_release_pfn_clean(ref->pfn);
-
+		trace_kvm_booke206_ref_release(ref->pfn, ref->flags);
 		ref->flags = 0;
 	}
 }
@@ -322,11 +318,11 @@ static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref)
 static void clear_tlb1_bitmap(struct kvmppc_vcpu_e500 *vcpu_e500)
 {
 	if (vcpu_e500->g2h_tlb1_map)
-		memset(vcpu_e500->g2h_tlb1_map,
-		       sizeof(u64) * vcpu_e500->gtlb_params[1].entries, 0);
+		memset(vcpu_e500->g2h_tlb1_map, 0,
+		       sizeof(u64) * vcpu_e500->gtlb_params[1].entries);
 	if (vcpu_e500->h2g_tlb1_rmap)
-		memset(vcpu_e500->h2g_tlb1_rmap,
-		       sizeof(unsigned int) * host_tlb_params[1].entries, 0);
+		memset(vcpu_e500->h2g_tlb1_rmap, 0,
+		       sizeof(unsigned int) * host_tlb_params[1].entries);
 }
 
 static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500)
@@ -357,6 +353,13 @@ static void clear_tlb_refs(struct kvmppc_vcpu_e500 *vcpu_e500)
 	clear_tlb_privs(vcpu_e500);
 }
 
+void kvmppc_core_flush_tlb(struct kvm_vcpu *vcpu)
+{
+	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
+	clear_tlb_refs(vcpu_e500);
+	clear_tlb1_bitmap(vcpu_e500);
+}
+
 static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu,
 		unsigned int eaddr, int as)
 {
@@ -520,11 +523,10 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
 
 	if (likely(!pfnmap)) {
 		unsigned long tsize_pages = 1 << (tsize + 10 - PAGE_SHIFT);
-		pfn = gfn_to_pfn_memslot(vcpu_e500->vcpu.kvm, slot, gfn);
+		pfn = gfn_to_pfn_memslot(slot, gfn);
 		if (is_error_pfn(pfn)) {
 			printk(KERN_ERR "Couldn't get real page for gfn %lx!\n",
 					(long)gfn);
-			kvm_release_pfn_clean(pfn);
 			return;
 		}
 
@@ -539,6 +541,12 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
 
 	kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize,
 				ref, gvaddr, stlbe);
+
+	/* Clear i-cache for new pages */
+	kvmppc_mmu_flush_icache(pfn);
+
+	/* Drop refcount on page, so that mmu notifiers can clear it */
+	kvm_release_pfn_clean(pfn);
 }
 
 /* XXX only map the one-one case, for now use TLB0 */
@@ -1037,8 +1045,12 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
 		sesel = 0; /* unused */
 		priv = &vcpu_e500->gtlb_priv[tlbsel][esel];
 
-		kvmppc_e500_setup_stlbe(vcpu, gtlbe, BOOK3E_PAGESZ_4K,
-					&priv->ref, eaddr, &stlbe);
+		/* Only triggers after clear_tlb_refs */
+		if (unlikely(!(priv->ref.flags & E500_TLB_VALID)))
+			kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe);
+		else
+			kvmppc_e500_setup_stlbe(vcpu, gtlbe, BOOK3E_PAGESZ_4K,
+						&priv->ref, eaddr, &stlbe);
 		break;
 
 	case 1: {
@@ -1058,6 +1070,49 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
 	write_stlbe(vcpu_e500, gtlbe, &stlbe, stlbsel, sesel);
 }
 
+/************* MMU Notifiers *************/
+
+int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
+{
+	trace_kvm_unmap_hva(hva);
+
+	/*
+	 * Flush all shadow tlb entries everywhere. This is slow, but
+	 * we are 100% sure that we catch the to be unmapped page
+	 */
+	kvm_flush_remote_tlbs(kvm);
+
+	return 0;
+}
+
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
+{
+	/* kvm_unmap_hva flushes everything anyways */
+	kvm_unmap_hva(kvm, start);
+
+	return 0;
+}
+
+int kvm_age_hva(struct kvm *kvm, unsigned long hva)
+{
+	/* XXX could be more clever ;) */
+	return 0;
+}
+
+int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
+{
+	/* XXX could be more clever ;) */
+	return 0;
+}
+
+void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
+{
+	/* The page will get remapped properly on its next fault */
+	kvm_unmap_hva(kvm, hva);
+}
+
+/*****************************************/
+
 static void free_gtlb(struct kvmppc_vcpu_e500 *vcpu_e500)
 {
 	int i;
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 87f4dc8..32d217c 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -30,6 +30,7 @@
 #include <asm/kvm_ppc.h>
 #include <asm/tlbflush.h>
 #include <asm/cputhreads.h>
+#include <asm/irqflags.h>
 #include "timing.h"
 #include "../mm/mmu_decl.h"
 
@@ -38,8 +39,7 @@
 
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 {
-	return !(v->arch.shared->msr & MSR_WE) ||
-	       !!(v->arch.pending_exceptions) ||
+	return !!(v->arch.pending_exceptions) ||
 	       v->requests;
 }
 
@@ -48,6 +48,81 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
 	return 1;
 }
 
+#ifndef CONFIG_KVM_BOOK3S_64_HV
+/*
+ * Common checks before entering the guest world.  Call with interrupts
+ * disabled.
+ *
+ * returns:
+ *
+ * == 1 if we're ready to go into guest state
+ * <= 0 if we need to go back to the host with return value
+ */
+int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
+{
+	int r = 1;
+
+	WARN_ON_ONCE(!irqs_disabled());
+	while (true) {
+		if (need_resched()) {
+			local_irq_enable();
+			cond_resched();
+			local_irq_disable();
+			continue;
+		}
+
+		if (signal_pending(current)) {
+			kvmppc_account_exit(vcpu, SIGNAL_EXITS);
+			vcpu->run->exit_reason = KVM_EXIT_INTR;
+			r = -EINTR;
+			break;
+		}
+
+		smp_mb();
+		if (vcpu->requests) {
+			/* Make sure we process requests preemptable */
+			local_irq_enable();
+			trace_kvm_check_requests(vcpu);
+			r = kvmppc_core_check_requests(vcpu);
+			local_irq_disable();
+			if (r > 0)
+				continue;
+			break;
+		}
+
+		if (kvmppc_core_prepare_to_enter(vcpu)) {
+			/* interrupts got enabled in between, so we
+			   are back at square 1 */
+			continue;
+		}
+
+#ifdef CONFIG_PPC64
+		/* lazy EE magic */
+		hard_irq_disable();
+		if (lazy_irq_pending()) {
+			/* Got an interrupt in between, try again */
+			local_irq_enable();
+			local_irq_disable();
+			kvm_guest_exit();
+			continue;
+		}
+
+		trace_hardirqs_on();
+#endif
+
+		kvm_guest_enter();
+
+		/* Going into guest context! Yay! */
+		vcpu->mode = IN_GUEST_MODE;
+		smp_wmb();
+
+		break;
+	}
+
+	return r;
+}
+#endif /* CONFIG_KVM_BOOK3S_64_HV */
+
 int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
 {
 	int nr = kvmppc_get_gpr(vcpu, 11);
@@ -67,18 +142,18 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
 	}
 
 	switch (nr) {
-	case HC_VENDOR_KVM | KVM_HC_PPC_MAP_MAGIC_PAGE:
+	case KVM_HCALL_TOKEN(KVM_HC_PPC_MAP_MAGIC_PAGE):
 	{
 		vcpu->arch.magic_page_pa = param1;
 		vcpu->arch.magic_page_ea = param2;
 
 		r2 = KVM_MAGIC_FEAT_SR | KVM_MAGIC_FEAT_MAS0_TO_SPRG7;
 
-		r = HC_EV_SUCCESS;
+		r = EV_SUCCESS;
 		break;
 	}
-	case HC_VENDOR_KVM | KVM_HC_FEATURES:
-		r = HC_EV_SUCCESS;
+	case KVM_HCALL_TOKEN(KVM_HC_FEATURES):
+		r = EV_SUCCESS;
 #if defined(CONFIG_PPC_BOOK3S) || defined(CONFIG_KVM_E500V2)
 		/* XXX Missing magic page on 44x */
 		r2 |= (1 << KVM_FEATURE_MAGIC_PAGE);
@@ -86,8 +161,13 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
 
 		/* Second return value is in r4 */
 		break;
+	case EV_HCALL_TOKEN(EV_IDLE):
+		r = EV_SUCCESS;
+		kvm_vcpu_block(vcpu);
+		clear_bit(KVM_REQ_UNHALT, &vcpu->requests);
+		break;
 	default:
-		r = HC_EV_UNIMPLEMENTED;
+		r = EV_UNIMPLEMENTED;
 		break;
 	}
 
@@ -220,6 +300,7 @@ int kvm_dev_ioctl_check_extension(long ext)
 	switch (ext) {
 #ifdef CONFIG_BOOKE
 	case KVM_CAP_PPC_BOOKE_SREGS:
+	case KVM_CAP_PPC_BOOKE_WATCHDOG:
 #else
 	case KVM_CAP_PPC_SEGSTATE:
 	case KVM_CAP_PPC_HIOR:
@@ -260,10 +341,16 @@ int kvm_dev_ioctl_check_extension(long ext)
 		if (cpu_has_feature(CPU_FTR_ARCH_201))
 			r = 2;
 		break;
+#endif
 	case KVM_CAP_SYNC_MMU:
+#ifdef CONFIG_KVM_BOOK3S_64_HV
 		r = cpu_has_feature(CPU_FTR_ARCH_206) ? 1 : 0;
-		break;
+#elif defined(KVM_ARCH_WANT_MMU_NOTIFIER)
+		r = 1;
+#else
+		r = 0;
 #endif
+		break;
 	case KVM_CAP_NR_VCPUS:
 		/*
 		 * Recommending a number of CPUs is somewhat arbitrary; we
@@ -302,10 +389,18 @@ long kvm_arch_dev_ioctl(struct file *filp,
 void kvm_arch_free_memslot(struct kvm_memory_slot *free,
 			   struct kvm_memory_slot *dont)
 {
+	if (!dont || free->arch.rmap != dont->arch.rmap) {
+		vfree(free->arch.rmap);
+		free->arch.rmap = NULL;
+	}
 }
 
 int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
 {
+	slot->arch.rmap = vzalloc(npages * sizeof(*slot->arch.rmap));
+	if (!slot->arch.rmap)
+		return -ENOMEM;
+
 	return 0;
 }
 
@@ -378,6 +473,8 @@ enum hrtimer_restart kvmppc_decrementer_wakeup(struct hrtimer *timer)
 
 int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 {
+	int ret;
+
 	hrtimer_init(&vcpu->arch.dec_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
 	tasklet_init(&vcpu->arch.tasklet, kvmppc_decrementer_func, (ulong)vcpu);
 	vcpu->arch.dec_timer.function = kvmppc_decrementer_wakeup;
@@ -386,13 +483,14 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 #ifdef CONFIG_KVM_EXIT_TIMING
 	mutex_init(&vcpu->arch.exit_timing_lock);
 #endif
-
-	return 0;
+	ret = kvmppc_subarch_vcpu_init(vcpu);
+	return ret;
 }
 
 void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
 {
 	kvmppc_mmu_destroy(vcpu);
+	kvmppc_subarch_vcpu_uninit(vcpu);
 }
 
 void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
@@ -637,6 +735,12 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
 		r = 0;
 		vcpu->arch.papr_enabled = true;
 		break;
+#ifdef CONFIG_BOOKE
+	case KVM_CAP_PPC_BOOKE_WATCHDOG:
+		r = 0;
+		vcpu->arch.watchdog_enabled = true;
+		break;
+#endif
 #if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC)
 	case KVM_CAP_SW_TLB: {
 		struct kvm_config_tlb cfg;
@@ -739,9 +843,16 @@ int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
 
 static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)
 {
+	u32 inst_nop = 0x60000000;
+#ifdef CONFIG_KVM_BOOKE_HV
+	u32 inst_sc1 = 0x44000022;
+	pvinfo->hcall[0] = inst_sc1;
+	pvinfo->hcall[1] = inst_nop;
+	pvinfo->hcall[2] = inst_nop;
+	pvinfo->hcall[3] = inst_nop;
+#else
 	u32 inst_lis = 0x3c000000;
 	u32 inst_ori = 0x60000000;
-	u32 inst_nop = 0x60000000;
 	u32 inst_sc = 0x44000002;
 	u32 inst_imm_mask = 0xffff;
 
@@ -758,6 +869,9 @@ static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)
 	pvinfo->hcall[1] = inst_ori | (KVM_SC_MAGIC_R0 & inst_imm_mask);
 	pvinfo->hcall[2] = inst_sc;
 	pvinfo->hcall[3] = inst_nop;
+#endif
+
+	pvinfo->flags = KVM_PPC_PVINFO_FLAGS_EV_IDLE;
 
 	return 0;
 }
diff --git a/arch/powerpc/kvm/trace.h b/arch/powerpc/kvm/trace.h
index 877186b..519aba8 100644
--- a/arch/powerpc/kvm/trace.h
+++ b/arch/powerpc/kvm/trace.h
@@ -31,6 +31,126 @@ TRACE_EVENT(kvm_ppc_instr,
 		  __entry->inst, __entry->pc, __entry->emulate)
 );
 
+#ifdef CONFIG_PPC_BOOK3S
+#define kvm_trace_symbol_exit \
+	{0x100, "SYSTEM_RESET"}, \
+	{0x200, "MACHINE_CHECK"}, \
+	{0x300, "DATA_STORAGE"}, \
+	{0x380, "DATA_SEGMENT"}, \
+	{0x400, "INST_STORAGE"}, \
+	{0x480, "INST_SEGMENT"}, \
+	{0x500, "EXTERNAL"}, \
+	{0x501, "EXTERNAL_LEVEL"}, \
+	{0x502, "EXTERNAL_HV"}, \
+	{0x600, "ALIGNMENT"}, \
+	{0x700, "PROGRAM"}, \
+	{0x800, "FP_UNAVAIL"}, \
+	{0x900, "DECREMENTER"}, \
+	{0x980, "HV_DECREMENTER"}, \
+	{0xc00, "SYSCALL"}, \
+	{0xd00, "TRACE"}, \
+	{0xe00, "H_DATA_STORAGE"}, \
+	{0xe20, "H_INST_STORAGE"}, \
+	{0xe40, "H_EMUL_ASSIST"}, \
+	{0xf00, "PERFMON"}, \
+	{0xf20, "ALTIVEC"}, \
+	{0xf40, "VSX"}
+#else
+#define kvm_trace_symbol_exit \
+	{0, "CRITICAL"}, \
+	{1, "MACHINE_CHECK"}, \
+	{2, "DATA_STORAGE"}, \
+	{3, "INST_STORAGE"}, \
+	{4, "EXTERNAL"}, \
+	{5, "ALIGNMENT"}, \
+	{6, "PROGRAM"}, \
+	{7, "FP_UNAVAIL"}, \
+	{8, "SYSCALL"}, \
+	{9, "AP_UNAVAIL"}, \
+	{10, "DECREMENTER"}, \
+	{11, "FIT"}, \
+	{12, "WATCHDOG"}, \
+	{13, "DTLB_MISS"}, \
+	{14, "ITLB_MISS"}, \
+	{15, "DEBUG"}, \
+	{32, "SPE_UNAVAIL"}, \
+	{33, "SPE_FP_DATA"}, \
+	{34, "SPE_FP_ROUND"}, \
+	{35, "PERFORMANCE_MONITOR"}, \
+	{36, "DOORBELL"}, \
+	{37, "DOORBELL_CRITICAL"}, \
+	{38, "GUEST_DBELL"}, \
+	{39, "GUEST_DBELL_CRIT"}, \
+	{40, "HV_SYSCALL"}, \
+	{41, "HV_PRIV"}
+#endif
+
+TRACE_EVENT(kvm_exit,
+	TP_PROTO(unsigned int exit_nr, struct kvm_vcpu *vcpu),
+	TP_ARGS(exit_nr, vcpu),
+
+	TP_STRUCT__entry(
+		__field(	unsigned int,	exit_nr		)
+		__field(	unsigned long,	pc		)
+		__field(	unsigned long,	msr		)
+		__field(	unsigned long,	dar		)
+#ifdef CONFIG_KVM_BOOK3S_PR
+		__field(	unsigned long,	srr1		)
+#endif
+		__field(	unsigned long,	last_inst	)
+	),
+
+	TP_fast_assign(
+#ifdef CONFIG_KVM_BOOK3S_PR
+		struct kvmppc_book3s_shadow_vcpu *svcpu;
+#endif
+		__entry->exit_nr	= exit_nr;
+		__entry->pc		= kvmppc_get_pc(vcpu);
+		__entry->dar		= kvmppc_get_fault_dar(vcpu);
+		__entry->msr		= vcpu->arch.shared->msr;
+#ifdef CONFIG_KVM_BOOK3S_PR
+		svcpu = svcpu_get(vcpu);
+		__entry->srr1		= svcpu->shadow_srr1;
+		svcpu_put(svcpu);
+#endif
+		__entry->last_inst	= vcpu->arch.last_inst;
+	),
+
+	TP_printk("exit=%s"
+		" | pc=0x%lx"
+		" | msr=0x%lx"
+		" | dar=0x%lx"
+#ifdef CONFIG_KVM_BOOK3S_PR
+		" | srr1=0x%lx"
+#endif
+		" | last_inst=0x%lx"
+		,
+		__print_symbolic(__entry->exit_nr, kvm_trace_symbol_exit),
+		__entry->pc,
+		__entry->msr,
+		__entry->dar,
+#ifdef CONFIG_KVM_BOOK3S_PR
+		__entry->srr1,
+#endif
+		__entry->last_inst
+		)
+);
+
+TRACE_EVENT(kvm_unmap_hva,
+	TP_PROTO(unsigned long hva),
+	TP_ARGS(hva),
+
+	TP_STRUCT__entry(
+		__field(	unsigned long,	hva		)
+	),
+
+	TP_fast_assign(
+		__entry->hva		= hva;
+	),
+
+	TP_printk("unmap hva 0x%lx\n", __entry->hva)
+);
+
 TRACE_EVENT(kvm_stlb_inval,
 	TP_PROTO(unsigned int stlb_index),
 	TP_ARGS(stlb_index),
@@ -98,41 +218,31 @@ TRACE_EVENT(kvm_gtlb_write,
 		__entry->word1, __entry->word2)
 );
 
-
-/*************************************************************************
- *                         Book3S trace points                           *
- *************************************************************************/
-
-#ifdef CONFIG_KVM_BOOK3S_PR
-
-TRACE_EVENT(kvm_book3s_exit,
-	TP_PROTO(unsigned int exit_nr, struct kvm_vcpu *vcpu),
-	TP_ARGS(exit_nr, vcpu),
+TRACE_EVENT(kvm_check_requests,
+	TP_PROTO(struct kvm_vcpu *vcpu),
+	TP_ARGS(vcpu),
 
 	TP_STRUCT__entry(
-		__field(	unsigned int,	exit_nr		)
-		__field(	unsigned long,	pc		)
-		__field(	unsigned long,	msr		)
-		__field(	unsigned long,	dar		)
-		__field(	unsigned long,	srr1		)
+		__field(	__u32,	cpu_nr		)
+		__field(	__u32,	requests	)
 	),
 
 	TP_fast_assign(
-		struct kvmppc_book3s_shadow_vcpu *svcpu;
-		__entry->exit_nr	= exit_nr;
-		__entry->pc		= kvmppc_get_pc(vcpu);
-		__entry->dar		= kvmppc_get_fault_dar(vcpu);
-		__entry->msr		= vcpu->arch.shared->msr;
-		svcpu = svcpu_get(vcpu);
-		__entry->srr1		= svcpu->shadow_srr1;
-		svcpu_put(svcpu);
+		__entry->cpu_nr		= vcpu->vcpu_id;
+		__entry->requests	= vcpu->requests;
 	),
 
-	TP_printk("exit=0x%x | pc=0x%lx | msr=0x%lx | dar=0x%lx | srr1=0x%lx",
-		  __entry->exit_nr, __entry->pc, __entry->msr, __entry->dar,
-		  __entry->srr1)
+	TP_printk("vcpu=%x requests=%x",
+		__entry->cpu_nr, __entry->requests)
 );
 
+
+/*************************************************************************
+ *                         Book3S trace points                           *
+ *************************************************************************/
+
+#ifdef CONFIG_KVM_BOOK3S_PR
+
 TRACE_EVENT(kvm_book3s_reenter,
 	TP_PROTO(int r, struct kvm_vcpu *vcpu),
 	TP_ARGS(r, vcpu),
@@ -395,6 +505,44 @@ TRACE_EVENT(kvm_booke206_gtlb_write,
 		__entry->mas2, __entry->mas7_3)
 );
 
+TRACE_EVENT(kvm_booke206_ref_release,
+	TP_PROTO(__u64 pfn, __u32 flags),
+	TP_ARGS(pfn, flags),
+
+	TP_STRUCT__entry(
+		__field(	__u64,	pfn		)
+		__field(	__u32,	flags		)
+	),
+
+	TP_fast_assign(
+		__entry->pfn		= pfn;
+		__entry->flags		= flags;
+	),
+
+	TP_printk("pfn=%llx flags=%x",
+		__entry->pfn, __entry->flags)
+);
+
+TRACE_EVENT(kvm_booke_queue_irqprio,
+	TP_PROTO(struct kvm_vcpu *vcpu, unsigned int priority),
+	TP_ARGS(vcpu, priority),
+
+	TP_STRUCT__entry(
+		__field(	__u32,	cpu_nr		)
+		__field(	__u32,	priority		)
+		__field(	unsigned long,	pending		)
+	),
+
+	TP_fast_assign(
+		__entry->cpu_nr		= vcpu->vcpu_id;
+		__entry->priority	= priority;
+		__entry->pending	= vcpu->arch.pending_exceptions;
+	),
+
+	TP_printk("vcpu=%x prio=%x pending=%lx",
+		__entry->cpu_nr, __entry->priority, __entry->pending)
+);
+
 #endif
 
 #endif /* _TRACE_KVM_H */
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index baaafde..46814f1 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -300,8 +300,7 @@ void __init mem_init(void)
 	unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize;
 
 #ifdef CONFIG_SWIOTLB
-	if (ppc_swiotlb_enable)
-		swiotlb_init(1);
+	swiotlb_init(0);
 #endif
 
 	num_physpages = memblock_phys_mem_size() >> PAGE_SHIFT;
@@ -469,6 +468,7 @@ void flush_dcache_icache_page(struct page *page)
 	__flush_dcache_icache_phys(page_to_pfn(page) << PAGE_SHIFT);
 #endif
 }
+EXPORT_SYMBOL(flush_dcache_icache_page);
 
 void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
 {
diff --git a/arch/powerpc/oprofile/cell/spu_task_sync.c b/arch/powerpc/oprofile/cell/spu_task_sync.c
index 642fca1..28f1af2 100644
--- a/arch/powerpc/oprofile/cell/spu_task_sync.c
+++ b/arch/powerpc/oprofile/cell/spu_task_sync.c
@@ -304,7 +304,7 @@ static inline unsigned long fast_get_dcookie(struct path *path)
 	return cookie;
 }
 
-/* Look up the dcookie for the task's first VM_EXECUTABLE mapping,
+/* Look up the dcookie for the task's mm->exe_file,
  * which corresponds loosely to "application name". Also, determine
  * the offset for the SPU ELF object.  If computed offset is
  * non-zero, it implies an embedded SPU object; otherwise, it's a
@@ -321,7 +321,6 @@ get_exec_dcookie_and_offset(struct spu *spu, unsigned int *offsetp,
 {
 	unsigned long app_cookie = 0;
 	unsigned int my_offset = 0;
-	struct file *app = NULL;
 	struct vm_area_struct *vma;
 	struct mm_struct *mm = spu->mm;
 
@@ -330,16 +329,10 @@ get_exec_dcookie_and_offset(struct spu *spu, unsigned int *offsetp,
 
 	down_read(&mm->mmap_sem);
 
-	for (vma = mm->mmap; vma; vma = vma->vm_next) {
-		if (!vma->vm_file)
-			continue;
-		if (!(vma->vm_flags & VM_EXECUTABLE))
-			continue;
-		app_cookie = fast_get_dcookie(&vma->vm_file->f_path);
+	if (mm->exe_file) {
+		app_cookie = fast_get_dcookie(&mm->exe_file->f_path);
 		pr_debug("got dcookie for %s\n",
-			 vma->vm_file->f_dentry->d_name.name);
-		app = vma->vm_file;
-		break;
+			 mm->exe_file->f_dentry->d_name.name);
 	}
 
 	for (vma = mm->mmap; vma; vma = vma->vm_next) {
diff --git a/arch/powerpc/platforms/44x/currituck.c b/arch/powerpc/platforms/44x/currituck.c
index 9f6c33d..6bd89a0 100644
--- a/arch/powerpc/platforms/44x/currituck.c
+++ b/arch/powerpc/platforms/44x/currituck.c
@@ -21,7 +21,6 @@
  */
 
 #include <linux/init.h>
-#include <linux/memblock.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/rtc.h>
@@ -159,13 +158,8 @@ static void __init ppc47x_setup_arch(void)
 
 	/* No need to check the DMA config as we /know/ our windows are all of
  	 * RAM.  Lets hope that doesn't change */
-#ifdef CONFIG_SWIOTLB
-	if ((memblock_end_of_DRAM() - 1) > 0xffffffff) {
-		ppc_swiotlb_enable = 1;
-		set_pci_dma_ops(&swiotlb_dma_ops);
-		ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
-	}
-#endif
+	swiotlb_detect_4g();
+
 	ppc47x_smp_init();
 }
 
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index c169998..b62508b 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -2,6 +2,7 @@ config PPC_MPC512x
 	bool "512x-based boards"
 	depends on 6xx
 	select FSL_SOC
+	select FB_FSL_DIU
 	select IPIC
 	select PPC_CLOCK
 	select PPC_PCI_CHOICE
diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c
index 1d8700f..9f771e0 100644
--- a/arch/powerpc/platforms/512x/clock.c
+++ b/arch/powerpc/platforms/512x/clock.c
@@ -54,14 +54,16 @@ static DEFINE_MUTEX(clocks_mutex);
 static struct clk *mpc5121_clk_get(struct device *dev, const char *id)
 {
 	struct clk *p, *clk = ERR_PTR(-ENOENT);
-	int dev_match = 0;
-	int id_match = 0;
+	int dev_match;
+	int id_match;
 
 	if (dev == NULL || id == NULL)
 		return clk;
 
 	mutex_lock(&clocks_mutex);
 	list_for_each_entry(p, &clocks, node) {
+		dev_match = id_match = 0;
+
 		if (dev == p->dev)
 			dev_match++;
 		if (strcmp(id, p->name) == 0)
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index cfe958e..1650e09 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -191,8 +191,6 @@ mpc512x_valid_monitor_port(enum fsl_diu_monitor_port port)
 
 static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb;
 
-#if defined(CONFIG_FB_FSL_DIU) || \
-    defined(CONFIG_FB_FSL_DIU_MODULE)
 static inline void mpc512x_free_bootmem(struct page *page)
 {
 	__ClearPageReserved(page);
@@ -220,7 +218,6 @@ void mpc512x_release_bootmem(void)
 	}
 	diu_ops.release_bootmem	= NULL;
 }
-#endif
 
 /*
  * Check if DIU was pre-initialized. If so, perform steps
@@ -323,15 +320,12 @@ void __init mpc512x_setup_diu(void)
 		}
 	}
 
-#if defined(CONFIG_FB_FSL_DIU) || \
-    defined(CONFIG_FB_FSL_DIU_MODULE)
 	diu_ops.get_pixel_format	= mpc512x_get_pixel_format;
 	diu_ops.set_gamma_table		= mpc512x_set_gamma_table;
 	diu_ops.set_monitor_port	= mpc512x_set_monitor_port;
 	diu_ops.set_pixel_clock		= mpc512x_set_pixel_clock;
 	diu_ops.valid_monitor_port	= mpc512x_valid_monitor_port;
 	diu_ops.release_bootmem		= mpc512x_release_bootmem;
-#endif
 }
 
 void __init mpc512x_init_IRQ(void)
diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c
index 1a04671..1d769a2 100644
--- a/arch/powerpc/platforms/83xx/suspend.c
+++ b/arch/powerpc/platforms/83xx/suspend.c
@@ -326,7 +326,7 @@ static int pmc_probe(struct platform_device *ofdev)
 	const struct of_device_id *match;
 	struct device_node *np = ofdev->dev.of_node;
 	struct resource res;
-	struct pmc_type *type;
+	const struct pmc_type *type;
 	int ret = 0;
 
 	match = of_match_device(pmc_match, &ofdev->dev);
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 159c01e..02d02a0 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -104,6 +104,13 @@ config P1022_DS
 	help
 	  This option enables support for the Freescale P1022DS reference board.
 
+config P1022_RDK
+	bool "Freescale / iVeia P1022 RDK"
+	select DEFAULT_UIMAGE
+	help
+	  This option enables support for the Freescale / iVeia P1022RDK
+	  reference board.
+
 config P1023_RDS
 	bool "Freescale P1023 RDS"
 	select DEFAULT_UIMAGE
@@ -254,6 +261,20 @@ config P5020_DS
 	help
 	  This option enables support for the P5020 DS board
 
+config P5040_DS
+	bool "Freescale P5040 DS"
+	select DEFAULT_UIMAGE
+	select E500
+	select PPC_E500MC
+	select PHYS_64BIT
+	select SWIOTLB
+	select ARCH_REQUIRE_GPIOLIB
+	select GPIO_MPC8XXX
+	select HAS_RAPIDIO
+	select PPC_EPAPR_HV_PIC
+	help
+	  This option enables support for the P5040 DS board
+
 config PPC_QEMU_E500
 	bool "QEMU generic e500 platform"
 	depends on EXPERIMENTAL
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 3dfe811..76f679c 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -15,11 +15,13 @@ obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o
 obj-$(CONFIG_MPC85xx_RDB) += mpc85xx_rdb.o
 obj-$(CONFIG_P1010_RDB)   += p1010rdb.o
 obj-$(CONFIG_P1022_DS)    += p1022_ds.o
+obj-$(CONFIG_P1022_RDK)   += p1022_rdk.o
 obj-$(CONFIG_P1023_RDS)   += p1023_rds.o
 obj-$(CONFIG_P2041_RDB)   += p2041_rdb.o corenet_ds.o
 obj-$(CONFIG_P3041_DS)    += p3041_ds.o corenet_ds.o
 obj-$(CONFIG_P4080_DS)    += p4080_ds.o corenet_ds.o
 obj-$(CONFIG_P5020_DS)    += p5020_ds.o corenet_ds.o
+obj-$(CONFIG_P5040_DS)    += p5040_ds.o corenet_ds.o
 obj-$(CONFIG_STX_GP3)	  += stx_gp3.o
 obj-$(CONFIG_TQM85xx)	  += tqm85xx.o
 obj-$(CONFIG_SBC8548)     += sbc8548.o
diff --git a/arch/powerpc/platforms/85xx/corenet_ds.c b/arch/powerpc/platforms/85xx/corenet_ds.c
index 925b028..473d573 100644
--- a/arch/powerpc/platforms/85xx/corenet_ds.c
+++ b/arch/powerpc/platforms/85xx/corenet_ds.c
@@ -63,7 +63,9 @@ void __init corenet_ds_setup_arch(void)
 #ifdef CONFIG_PCI
 	for_each_node_by_type(np, "pci") {
 		if (of_device_is_compatible(np, "fsl,p4080-pcie") ||
-		    of_device_is_compatible(np, "fsl,qoriq-pcie-v2.2")) {
+		    of_device_is_compatible(np, "fsl,qoriq-pcie-v2.2") ||
+		    of_device_is_compatible(np, "fsl,qoriq-pcie-v2.3") ||
+		    of_device_is_compatible(np, "fsl,qoriq-pcie-v2.4")) {
 			fsl_add_bridge(np, 0);
 			hose = pci_find_hose_for_OF_device(np);
 			max = min(max, hose->dma_window_base_cur +
@@ -99,6 +101,12 @@ static const struct of_device_id of_device_ids[] __devinitconst = {
 	{
 		.compatible	= "fsl,qoriq-pcie-v2.2",
 	},
+	{
+		.compatible	= "fsl,qoriq-pcie-v2.3",
+	},
+	{
+		.compatible	= "fsl,qoriq-pcie-v2.4",
+	},
 	/* The following two are for the Freescale hypervisor */
 	{
 		.name		= "hypervisor",
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
index 6d3265f..56f8c8f 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
@@ -159,6 +159,7 @@ static void __init mpc85xx_ds_setup_arch(void)
 	if (ppc_md.progress)
 		ppc_md.progress("mpc85xx_ds_setup_arch()", 0);
 
+	swiotlb_detect_4g();
 	mpc85xx_ds_pci_init();
 	mpc85xx_smp_init();
 
diff --git a/arch/powerpc/platforms/85xx/p1022_rdk.c b/arch/powerpc/platforms/85xx/p1022_rdk.c
new file mode 100644
index 0000000..b3cf11b
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/p1022_rdk.c
@@ -0,0 +1,195 @@
+/*
+ * P1022 RDK board specific routines
+ *
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Based on p1022_ds.c
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/pci.h>
+#include <linux/of_platform.h>
+#include <linux/memblock.h>
+#include <asm/div64.h>
+#include <asm/mpic.h>
+#include <asm/swiotlb.h>
+
+#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
+#include <asm/udbg.h>
+#include <asm/fsl_guts.h>
+#include "smp.h"
+
+#include "mpc85xx.h"
+
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+
+/* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */
+#define CLKDVDR_PXCKEN		0x80000000
+#define CLKDVDR_PXCKINV		0x10000000
+#define CLKDVDR_PXCKDLY		0x06000000
+#define CLKDVDR_PXCLK_MASK	0x00FF0000
+
+/**
+ * p1022rdk_set_monitor_port: switch the output to a different monitor port
+ */
+static void p1022rdk_set_monitor_port(enum fsl_diu_monitor_port port)
+{
+	if (port != FSL_DIU_PORT_DVI) {
+		pr_err("p1022rdk: unsupported monitor port %i\n", port);
+		return;
+	}
+}
+
+/**
+ * p1022rdk_set_pixel_clock: program the DIU's clock
+ *
+ * @pixclock: the wavelength, in picoseconds, of the clock
+ */
+void p1022rdk_set_pixel_clock(unsigned int pixclock)
+{
+	struct device_node *guts_np = NULL;
+	struct ccsr_guts __iomem *guts;
+	unsigned long freq;
+	u64 temp;
+	u32 pxclk;
+
+	/* Map the global utilities registers. */
+	guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
+	if (!guts_np) {
+		pr_err("p1022rdk: missing global utilties device node\n");
+		return;
+	}
+
+	guts = of_iomap(guts_np, 0);
+	of_node_put(guts_np);
+	if (!guts) {
+		pr_err("p1022rdk: could not map global utilties device\n");
+		return;
+	}
+
+	/* Convert pixclock from a wavelength to a frequency */
+	temp = 1000000000000ULL;
+	do_div(temp, pixclock);
+	freq = temp;
+
+	/*
+	 * 'pxclk' is the ratio of the platform clock to the pixel clock.
+	 * This number is programmed into the CLKDVDR register, and the valid
+	 * range of values is 2-255.
+	 */
+	pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq);
+	pxclk = clamp_t(u32, pxclk, 2, 255);
+
+	/* Disable the pixel clock, and set it to non-inverted and no delay */
+	clrbits32(&guts->clkdvdr,
+		  CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK);
+
+	/* Enable the clock and set the pxclk */
+	setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16));
+
+	iounmap(guts);
+}
+
+/**
+ * p1022rdk_valid_monitor_port: set the monitor port for sysfs
+ */
+enum fsl_diu_monitor_port
+p1022rdk_valid_monitor_port(enum fsl_diu_monitor_port port)
+{
+	return FSL_DIU_PORT_DVI;
+}
+
+#endif
+
+void __init p1022_rdk_pic_init(void)
+{
+	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
+		MPIC_SINGLE_DEST_CPU,
+		0, 256, " OpenPIC  ");
+	BUG_ON(mpic == NULL);
+	mpic_init(mpic);
+}
+
+/*
+ * Setup the architecture
+ */
+static void __init p1022_rdk_setup_arch(void)
+{
+#ifdef CONFIG_PCI
+	struct device_node *np;
+#endif
+	dma_addr_t max = 0xffffffff;
+
+	if (ppc_md.progress)
+		ppc_md.progress("p1022_rdk_setup_arch()", 0);
+
+#ifdef CONFIG_PCI
+	for_each_compatible_node(np, "pci", "fsl,p1022-pcie") {
+		struct resource rsrc;
+		struct pci_controller *hose;
+
+		of_address_to_resource(np, 0, &rsrc);
+
+		if ((rsrc.start & 0xfffff) == 0x8000)
+			fsl_add_bridge(np, 1);
+		else
+			fsl_add_bridge(np, 0);
+
+		hose = pci_find_hose_for_OF_device(np);
+		max = min(max, hose->dma_window_base_cur +
+			  hose->dma_window_size);
+	}
+#endif
+
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+	diu_ops.set_monitor_port	= p1022rdk_set_monitor_port;
+	diu_ops.set_pixel_clock		= p1022rdk_set_pixel_clock;
+	diu_ops.valid_monitor_port	= p1022rdk_valid_monitor_port;
+#endif
+
+	mpc85xx_smp_init();
+
+#ifdef CONFIG_SWIOTLB
+	if ((memblock_end_of_DRAM() - 1) > max) {
+		ppc_swiotlb_enable = 1;
+		set_pci_dma_ops(&swiotlb_dma_ops);
+		ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
+	}
+#endif
+
+	pr_info("Freescale / iVeia P1022 RDK reference board\n");
+}
+
+machine_device_initcall(p1022_rdk, mpc85xx_common_publish_devices);
+
+machine_arch_initcall(p1022_rdk, swiotlb_setup_bus_notifier);
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init p1022_rdk_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	return of_flat_dt_is_compatible(root, "fsl,p1022rdk");
+}
+
+define_machine(p1022_rdk) {
+	.name			= "P1022 RDK",
+	.probe			= p1022_rdk_probe,
+	.setup_arch		= p1022_rdk_setup_arch,
+	.init_IRQ		= p1022_rdk_pic_init,
+#ifdef CONFIG_PCI
+	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
+#endif
+	.get_irq		= mpic_get_irq,
+	.restart		= fsl_rstcr_restart,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= udbg_progress,
+};
diff --git a/arch/powerpc/platforms/85xx/p5040_ds.c b/arch/powerpc/platforms/85xx/p5040_ds.c
new file mode 100644
index 0000000..8e22a34
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/p5040_ds.c
@@ -0,0 +1,89 @@
+/*
+ * P5040 DS Setup
+ *
+ * Copyright 2009-2010 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+#include <asm/machdep.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+
+#include <linux/of_fdt.h>
+
+#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
+#include <asm/ehv_pic.h>
+
+#include "corenet_ds.h"
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init p5040_ds_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+#ifdef CONFIG_SMP
+	extern struct smp_ops_t smp_85xx_ops;
+#endif
+
+	if (of_flat_dt_is_compatible(root, "fsl,P5040DS"))
+		return 1;
+
+	/* Check if we're running under the Freescale hypervisor */
+	if (of_flat_dt_is_compatible(root, "fsl,P5040DS-hv")) {
+		ppc_md.init_IRQ = ehv_pic_init;
+		ppc_md.get_irq = ehv_pic_get_irq;
+		ppc_md.restart = fsl_hv_restart;
+		ppc_md.power_off = fsl_hv_halt;
+		ppc_md.halt = fsl_hv_halt;
+#ifdef CONFIG_SMP
+		/*
+		 * Disable the timebase sync operations because we can't write
+		 * to the timebase registers under the hypervisor.
+		  */
+		smp_85xx_ops.give_timebase = NULL;
+		smp_85xx_ops.take_timebase = NULL;
+#endif
+		return 1;
+	}
+
+	return 0;
+}
+
+define_machine(p5040_ds) {
+	.name			= "P5040 DS",
+	.probe			= p5040_ds_probe,
+	.setup_arch		= corenet_ds_setup_arch,
+	.init_IRQ		= corenet_ds_pic_init,
+#ifdef CONFIG_PCI
+	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
+#endif
+/* coreint doesn't play nice with lazy EE, use legacy mpic for now */
+#ifdef CONFIG_PPC64
+	.get_irq		= mpic_get_irq,
+#else
+	.get_irq		= mpic_get_coreint_irq,
+#endif
+	.restart		= fsl_rstcr_restart,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= udbg_progress,
+#ifdef CONFIG_PPC64
+	.power_save		= book3e_idle,
+#else
+	.power_save		= e500_idle,
+#endif
+};
+
+machine_device_initcall(p5040_ds, corenet_ds_publish_devices);
+
+#ifdef CONFIG_SWIOTLB
+machine_arch_initcall(p5040_ds, swiotlb_setup_bus_notifier);
+#endif
diff --git a/arch/powerpc/platforms/85xx/qemu_e500.c b/arch/powerpc/platforms/85xx/qemu_e500.c
index 95a2e53..3c5490c 100644
--- a/arch/powerpc/platforms/85xx/qemu_e500.c
+++ b/arch/powerpc/platforms/85xx/qemu_e500.c
@@ -42,6 +42,7 @@ static void __init qemu_e500_setup_arch(void)
 	ppc_md.progress("qemu_e500_setup_arch()", 0);
 
 	fsl_pci_init();
+	swiotlb_detect_4g();
 	mpc85xx_smp_init();
 }
 
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index ff42490..6fcfa12 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -2,7 +2,7 @@
  * Author: Andy Fleming <afleming@freescale.com>
  * 	   Kumar Gala <galak@kernel.crashing.org>
  *
- * Copyright 2006-2008, 2011 Freescale Semiconductor Inc.
+ * Copyright 2006-2008, 2011-2012 Freescale Semiconductor Inc.
  *
  * 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
@@ -17,6 +17,7 @@
 #include <linux/of.h>
 #include <linux/kexec.h>
 #include <linux/highmem.h>
+#include <linux/cpu.h>
 
 #include <asm/machdep.h>
 #include <asm/pgtable.h>
@@ -24,33 +25,118 @@
 #include <asm/mpic.h>
 #include <asm/cacheflush.h>
 #include <asm/dbell.h>
+#include <asm/fsl_guts.h>
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/mpic.h>
 #include "smp.h"
 
-extern void __early_start(void);
-
-#define BOOT_ENTRY_ADDR_UPPER	0
-#define BOOT_ENTRY_ADDR_LOWER	1
-#define BOOT_ENTRY_R3_UPPER	2
-#define BOOT_ENTRY_R3_LOWER	3
-#define BOOT_ENTRY_RESV		4
-#define BOOT_ENTRY_PIR		5
-#define BOOT_ENTRY_R6_UPPER	6
-#define BOOT_ENTRY_R6_LOWER	7
-#define NUM_BOOT_ENTRY		8
-#define SIZE_BOOT_ENTRY		(NUM_BOOT_ENTRY * sizeof(u32))
-
-static int __init
-smp_85xx_kick_cpu(int nr)
+struct epapr_spin_table {
+	u32	addr_h;
+	u32	addr_l;
+	u32	r3_h;
+	u32	r3_l;
+	u32	reserved;
+	u32	pir;
+};
+
+static struct ccsr_guts __iomem *guts;
+static u64 timebase;
+static int tb_req;
+static int tb_valid;
+
+static void mpc85xx_timebase_freeze(int freeze)
+{
+	uint32_t mask;
+
+	mask = CCSR_GUTS_DEVDISR_TB0 | CCSR_GUTS_DEVDISR_TB1;
+	if (freeze)
+		setbits32(&guts->devdisr, mask);
+	else
+		clrbits32(&guts->devdisr, mask);
+
+	in_be32(&guts->devdisr);
+}
+
+static void mpc85xx_give_timebase(void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	while (!tb_req)
+		barrier();
+	tb_req = 0;
+
+	mpc85xx_timebase_freeze(1);
+	timebase = get_tb();
+	mb();
+	tb_valid = 1;
+
+	while (tb_valid)
+		barrier();
+
+	mpc85xx_timebase_freeze(0);
+
+	local_irq_restore(flags);
+}
+
+static void mpc85xx_take_timebase(void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	tb_req = 1;
+	while (!tb_valid)
+		barrier();
+
+	set_tb(timebase >> 32, timebase & 0xffffffff);
+	isync();
+	tb_valid = 0;
+
+	local_irq_restore(flags);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static void __cpuinit smp_85xx_mach_cpu_die(void)
+{
+	unsigned int cpu = smp_processor_id();
+	u32 tmp;
+
+	local_irq_disable();
+	idle_task_exit();
+	generic_set_cpu_dead(cpu);
+	mb();
+
+	mtspr(SPRN_TCR, 0);
+
+	__flush_disable_L1();
+	tmp = (mfspr(SPRN_HID0) & ~(HID0_DOZE|HID0_SLEEP)) | HID0_NAP;
+	mtspr(SPRN_HID0, tmp);
+	isync();
+
+	/* Enter NAP mode. */
+	tmp = mfmsr();
+	tmp |= MSR_WE;
+	mb();
+	mtmsr(tmp);
+	isync();
+
+	while (1)
+		;
+}
+#endif
+
+static int __cpuinit smp_85xx_kick_cpu(int nr)
 {
 	unsigned long flags;
 	const u64 *cpu_rel_addr;
-	__iomem u32 *bptr_vaddr;
+	__iomem struct epapr_spin_table *spin_table;
 	struct device_node *np;
-	int n = 0, hw_cpu = get_hard_smp_processor_id(nr);
+	int hw_cpu = get_hard_smp_processor_id(nr);
 	int ioremappable;
+	int ret = 0;
 
 	WARN_ON(nr < 0 || nr >= NR_CPUS);
 	WARN_ON(hw_cpu < 0 || hw_cpu >= NR_CPUS);
@@ -75,46 +161,81 @@ smp_85xx_kick_cpu(int nr)
 
 	/* Map the spin table */
 	if (ioremappable)
-		bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY);
+		spin_table = ioremap(*cpu_rel_addr,
+				sizeof(struct epapr_spin_table));
 	else
-		bptr_vaddr = phys_to_virt(*cpu_rel_addr);
+		spin_table = phys_to_virt(*cpu_rel_addr);
 
 	local_irq_save(flags);
-
-	out_be32(bptr_vaddr + BOOT_ENTRY_PIR, hw_cpu);
 #ifdef CONFIG_PPC32
-	out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start));
+#ifdef CONFIG_HOTPLUG_CPU
+	/* Corresponding to generic_set_cpu_dead() */
+	generic_set_cpu_up(nr);
+
+	if (system_state == SYSTEM_RUNNING) {
+		out_be32(&spin_table->addr_l, 0);
+
+		/*
+		 * We don't set the BPTR register here since it already points
+		 * to the boot page properly.
+		 */
+		mpic_reset_core(hw_cpu);
+
+		/* wait until core is ready... */
+		if (!spin_event_timeout(in_be32(&spin_table->addr_l) == 1,
+						10000, 100)) {
+			pr_err("%s: timeout waiting for core %d to reset\n",
+							__func__, hw_cpu);
+			ret = -ENOENT;
+			goto out;
+		}
+
+		/*  clear the acknowledge status */
+		__secondary_hold_acknowledge = -1;
+	}
+#endif
+	out_be32(&spin_table->pir, hw_cpu);
+	out_be32(&spin_table->addr_l, __pa(__early_start));
 
 	if (!ioremappable)
-		flush_dcache_range((ulong)bptr_vaddr,
-				(ulong)(bptr_vaddr + SIZE_BOOT_ENTRY));
+		flush_dcache_range((ulong)spin_table,
+			(ulong)spin_table + sizeof(struct epapr_spin_table));
 
 	/* Wait a bit for the CPU to ack. */
-	while ((__secondary_hold_acknowledge != hw_cpu) && (++n < 1000))
-		mdelay(1);
+	if (!spin_event_timeout(__secondary_hold_acknowledge == hw_cpu,
+					10000, 100)) {
+		pr_err("%s: timeout waiting for core %d to ack\n",
+						__func__, hw_cpu);
+		ret = -ENOENT;
+		goto out;
+	}
+out:
 #else
 	smp_generic_kick_cpu(nr);
 
-	out_be64((u64 *)(bptr_vaddr + BOOT_ENTRY_ADDR_UPPER),
-		__pa((u64)*((unsigned long long *) generic_secondary_smp_init)));
+	out_be32(&spin_table->pir, hw_cpu);
+	out_be64((u64 *)(&spin_table->addr_h),
+	  __pa((u64)*((unsigned long long *)generic_secondary_smp_init)));
 
 	if (!ioremappable)
-		flush_dcache_range((ulong)bptr_vaddr,
-				(ulong)(bptr_vaddr + SIZE_BOOT_ENTRY));
+		flush_dcache_range((ulong)spin_table,
+			(ulong)spin_table + sizeof(struct epapr_spin_table));
 #endif
 
 	local_irq_restore(flags);
 
 	if (ioremappable)
-		iounmap(bptr_vaddr);
-
-	pr_debug("waited %d msecs for CPU #%d.\n", n, nr);
+		iounmap(spin_table);
 
-	return 0;
+	return ret;
 }
 
 struct smp_ops_t smp_85xx_ops = {
 	.kick_cpu = smp_85xx_kick_cpu,
+#ifdef CONFIG_HOTPLUG_CPU
+	.cpu_disable	= generic_cpu_disable,
+	.cpu_die	= generic_cpu_die,
+#endif
 #ifdef CONFIG_KEXEC
 	.give_timebase	= smp_generic_give_timebase,
 	.take_timebase	= smp_generic_take_timebase,
@@ -218,8 +339,7 @@ static void mpc85xx_smp_machine_kexec(struct kimage *image)
 }
 #endif /* CONFIG_KEXEC */
 
-static void __init
-smp_85xx_setup_cpu(int cpu_nr)
+static void __cpuinit smp_85xx_setup_cpu(int cpu_nr)
 {
 	if (smp_85xx_ops.probe == smp_mpic_probe)
 		mpic_setup_this_cpu();
@@ -228,6 +348,16 @@ smp_85xx_setup_cpu(int cpu_nr)
 		doorbell_setup_this_cpu();
 }
 
+static const struct of_device_id mpc85xx_smp_guts_ids[] = {
+	{ .compatible = "fsl,mpc8572-guts", },
+	{ .compatible = "fsl,p1020-guts", },
+	{ .compatible = "fsl,p1021-guts", },
+	{ .compatible = "fsl,p1022-guts", },
+	{ .compatible = "fsl,p1023-guts", },
+	{ .compatible = "fsl,p2020-guts", },
+	{},
+};
+
 void __init mpc85xx_smp_init(void)
 {
 	struct device_node *np;
@@ -249,6 +379,22 @@ void __init mpc85xx_smp_init(void)
 		smp_85xx_ops.cause_ipi = doorbell_cause_ipi;
 	}
 
+	np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids);
+	if (np) {
+		guts = of_iomap(np, 0);
+		of_node_put(np);
+		if (!guts) {
+			pr_err("%s: Could not map guts node address\n",
+								__func__);
+			return;
+		}
+		smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
+		smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
+#ifdef CONFIG_HOTPLUG_CPU
+		ppc_md.cpu_die = smp_85xx_mach_cpu_die;
+#endif
+	}
+
 	smp_ops = &smp_85xx_ops;
 
 #ifdef CONFIG_KEXEC
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index e7a896a..48a920d 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -90,6 +90,7 @@ config MPIC
 config PPC_EPAPR_HV_PIC
 	bool
 	default n
+	select EPAPR_PARAVIRT
 
 config MPIC_WEIRD
 	bool
diff --git a/arch/powerpc/platforms/cell/celleb_pci.c b/arch/powerpc/platforms/cell/celleb_pci.c
index 5822141..abc8af4 100644
--- a/arch/powerpc/platforms/cell/celleb_pci.c
+++ b/arch/powerpc/platforms/cell/celleb_pci.c
@@ -472,7 +472,7 @@ int __init celleb_setup_phb(struct pci_controller *phb)
 {
 	struct device_node *dev = phb->dn;
 	const struct of_device_id *match;
-	struct celleb_phb_spec *phb_spec;
+	const struct celleb_phb_spec *phb_spec;
 	int rc;
 
 	match = of_match_node(celleb_phb_match, dev);
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 1bd7ecb..a57600b 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -15,7 +15,7 @@ obj-$(CONFIG_PPC_DCR_NATIVE)	+= dcr-low.o
 obj-$(CONFIG_PPC_PMI)		+= pmi.o
 obj-$(CONFIG_U3_DART)		+= dart_iommu.o
 obj-$(CONFIG_MMIO_NVRAM)	+= mmio_nvram.o
-obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
+obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o fsl_mpic_err.o
 obj-$(CONFIG_FSL_PCI)		+= fsl_pci.o $(fsl-msi-obj-y)
 obj-$(CONFIG_FSL_PMC)		+= fsl_pmc.o
 obj-$(CONFIG_FSL_LBC)		+= fsl_lbc.o
diff --git a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
index 68ac3aa..d131c8a 100644
--- a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
+++ b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
@@ -193,6 +193,16 @@ static struct of_device_id mpc85xx_l2ctlr_of_match[] = {
 	{
 		.compatible = "fsl,mpc8548-l2-cache-controller",
 	},
+	{	.compatible = "fsl,mpc8544-l2-cache-controller",},
+	{	.compatible = "fsl,mpc8572-l2-cache-controller",},
+	{	.compatible = "fsl,mpc8536-l2-cache-controller",},
+	{	.compatible = "fsl,p1021-l2-cache-controller",},
+	{	.compatible = "fsl,p1012-l2-cache-controller",},
+	{	.compatible = "fsl,p1025-l2-cache-controller",},
+	{	.compatible = "fsl,p1016-l2-cache-controller",},
+	{	.compatible = "fsl,p1024-l2-cache-controller",},
+	{	.compatible = "fsl,p1015-l2-cache-controller",},
+	{	.compatible = "fsl,p1010-l2-cache-controller",},
 	{},
 };
 
diff --git a/arch/powerpc/sysdev/fsl_mpic_err.c b/arch/powerpc/sysdev/fsl_mpic_err.c
new file mode 100644
index 0000000..b83f325
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_mpic_err.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ *
+ * Author: Varun Sethi <varun.sethi@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mpic.h>
+
+#include "mpic.h"
+
+#define MPIC_ERR_INT_BASE	0x3900
+#define MPIC_ERR_INT_EISR	0x0000
+#define MPIC_ERR_INT_EIMR	0x0010
+
+static inline u32 mpic_fsl_err_read(u32 __iomem *base, unsigned int err_reg)
+{
+	return in_be32(base + (err_reg >> 2));
+}
+
+static inline void mpic_fsl_err_write(u32 __iomem *base, u32 value)
+{
+	out_be32(base + (MPIC_ERR_INT_EIMR >> 2), value);
+}
+
+static void fsl_mpic_mask_err(struct irq_data *d)
+{
+	u32 eimr;
+	struct mpic *mpic = irq_data_get_irq_chip_data(d);
+	unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];
+
+	eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
+	eimr |= (1 << (31 - src));
+	mpic_fsl_err_write(mpic->err_regs, eimr);
+}
+
+static void fsl_mpic_unmask_err(struct irq_data *d)
+{
+	u32 eimr;
+	struct mpic *mpic = irq_data_get_irq_chip_data(d);
+	unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];
+
+	eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
+	eimr &= ~(1 << (31 - src));
+	mpic_fsl_err_write(mpic->err_regs, eimr);
+}
+
+static struct irq_chip fsl_mpic_err_chip = {
+	.irq_disable	= fsl_mpic_mask_err,
+	.irq_mask	= fsl_mpic_mask_err,
+	.irq_unmask	= fsl_mpic_unmask_err,
+};
+
+int mpic_setup_error_int(struct mpic *mpic, int intvec)
+{
+	int i;
+
+	mpic->err_regs = ioremap(mpic->paddr + MPIC_ERR_INT_BASE, 0x1000);
+	if (!mpic->err_regs) {
+		pr_err("could not map mpic error registers\n");
+		return -ENOMEM;
+	}
+	mpic->hc_err = fsl_mpic_err_chip;
+	mpic->hc_err.name = mpic->name;
+	mpic->flags |= MPIC_FSL_HAS_EIMR;
+	/* allocate interrupt vectors for error interrupts */
+	for (i = MPIC_MAX_ERR - 1; i >= 0; i--)
+		mpic->err_int_vecs[i] = --intvec;
+
+	return 0;
+}
+
+int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t  hw)
+{
+	if ((mpic->flags & MPIC_FSL_HAS_EIMR) &&
+	    (hw >= mpic->err_int_vecs[0] &&
+	     hw <= mpic->err_int_vecs[MPIC_MAX_ERR - 1])) {
+		WARN_ON(mpic->flags & MPIC_SECONDARY);
+
+		pr_debug("mpic: mapping as Error Interrupt\n");
+		irq_set_chip_data(virq, mpic);
+		irq_set_chip_and_handler(virq, &mpic->hc_err,
+					 handle_level_irq);
+		return 1;
+	}
+
+	return 0;
+}
+
+static irqreturn_t fsl_error_int_handler(int irq, void *data)
+{
+	struct mpic *mpic = (struct mpic *) data;
+	u32 eisr, eimr;
+	int errint;
+	unsigned int cascade_irq;
+
+	eisr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EISR);
+	eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
+
+	if (!(eisr & ~eimr))
+		return IRQ_NONE;
+
+	while (eisr) {
+		errint = __builtin_clz(eisr);
+		cascade_irq = irq_linear_revmap(mpic->irqhost,
+				 mpic->err_int_vecs[errint]);
+		WARN_ON(cascade_irq == NO_IRQ);
+		if (cascade_irq != NO_IRQ) {
+			generic_handle_irq(cascade_irq);
+		} else {
+			eimr |=  1 << (31 - errint);
+			mpic_fsl_err_write(mpic->err_regs, eimr);
+		}
+		eisr &= ~(1 << (31 - errint));
+	}
+
+	return IRQ_HANDLED;
+}
+
+void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum)
+{
+	unsigned int virq;
+	int ret;
+
+	virq = irq_create_mapping(mpic->irqhost, irqnum);
+	if (virq == NO_IRQ) {
+		pr_err("Error interrupt setup failed\n");
+		return;
+	}
+
+	/* Mask all error interrupts */
+	mpic_fsl_err_write(mpic->err_regs, ~0);
+
+	ret = request_irq(virq, fsl_error_int_handler, IRQF_NO_THREAD,
+		    "mpic-error-int", mpic);
+	if (ret)
+		pr_err("Failed to register error interrupt handler\n");
+}
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index 6e097de..63c5f04 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -236,7 +236,6 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
 	u32 intr_index;
 	u32 have_shift = 0;
 	struct fsl_msi_cascade_data *cascade_data;
-	unsigned int ret;
 
 	cascade_data = irq_get_handler_data(irq);
 	msi_data = cascade_data->msi_data;
@@ -268,7 +267,9 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
 	case FSL_PIC_IP_IPIC:
 		msir_value = fsl_msi_read(msi_data->msi_regs, msir_index * 0x4);
 		break;
-	case FSL_PIC_IP_VMPIC:
+#ifdef CONFIG_EPAPR_PARAVIRT
+	case FSL_PIC_IP_VMPIC: {
+		unsigned int ret;
 		ret = fh_vmpic_get_msir(virq_to_hw(irq), &msir_value);
 		if (ret) {
 			pr_err("fsl-msi: fh_vmpic_get_msir() failed for "
@@ -277,6 +278,8 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
 		}
 		break;
 	}
+#endif
+	}
 
 	while (msir_value) {
 		intr_index = ffs(msir_value) - 1;
@@ -368,7 +371,7 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)
 	int err, i, j, irq_index, count;
 	int rc;
 	const u32 *p;
-	struct fsl_msi_feature *features;
+	const struct fsl_msi_feature *features;
 	int len;
 	u32 offset;
 	static const u32 all_avail[] = { 0, NR_MSI_IRQS };
@@ -502,16 +505,18 @@ static const struct fsl_msi_feature vmpic_msi_feature = {
 static const struct of_device_id fsl_of_msi_ids[] = {
 	{
 		.compatible = "fsl,mpic-msi",
-		.data = (void *)&mpic_msi_feature,
+		.data = &mpic_msi_feature,
 	},
 	{
 		.compatible = "fsl,ipic-msi",
-		.data = (void *)&ipic_msi_feature,
+		.data = &ipic_msi_feature,
 	},
+#ifdef CONFIG_EPAPR_PARAVIRT
 	{
 		.compatible = "fsl,vmpic-msi",
-		.data = (void *)&vmpic_msi_feature,
+		.data = &vmpic_msi_feature,
 	},
+#endif
 	{}
 };
 
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index a7b2a60..da7a3d7 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -465,7 +465,7 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary)
 			iounmap(hose->cfg_data);
 		iounmap(hose->cfg_addr);
 		pcibios_free_controller(hose);
-		return 0;
+		return -ENODEV;
 	}
 
 	setup_pci_cmd(hose);
@@ -818,6 +818,7 @@ static const struct of_device_id pci_ids[] = {
 	{ .compatible = "fsl,p1010-pcie", },
 	{ .compatible = "fsl,p1023-pcie", },
 	{ .compatible = "fsl,p4080-pcie", },
+	{ .compatible = "fsl,qoriq-pcie-v2.4", },
 	{ .compatible = "fsl,qoriq-pcie-v2.3", },
 	{ .compatible = "fsl,qoriq-pcie-v2.2", },
 	{},
@@ -827,6 +828,7 @@ struct device_node *fsl_pci_primary;
 
 void __devinit fsl_pci_init(void)
 {
+	int ret;
 	struct device_node *node;
 	struct pci_controller *hose;
 	dma_addr_t max = 0xffffffff;
@@ -855,10 +857,12 @@ void __devinit fsl_pci_init(void)
 			if (!fsl_pci_primary)
 				fsl_pci_primary = node;
 
-			fsl_add_bridge(node, fsl_pci_primary == node);
-			hose = pci_find_hose_for_OF_device(node);
-			max = min(max, hose->dma_window_base_cur +
-					hose->dma_window_size);
+			ret = fsl_add_bridge(node, fsl_pci_primary == node);
+			if (ret == 0) {
+				hose = pci_find_hose_for_OF_device(node);
+				max = min(max, hose->dma_window_base_cur +
+						hose->dma_window_size);
+			}
 		}
 	}
 
@@ -868,11 +872,8 @@ void __devinit fsl_pci_init(void)
 	 * we need SWIOTLB to handle buffers located outside of
 	 * dma capable memory region
 	 */
-	if (memblock_end_of_DRAM() - 1 > max) {
+	if (memblock_end_of_DRAM() - 1 > max)
 		ppc_swiotlb_enable = 1;
-		set_pci_dma_ops(&swiotlb_dma_ops);
-		ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
-	}
 #endif
 }
 #endif
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index c449dbd..97118dc 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -253,6 +253,7 @@ struct platform_diu_data_ops diu_ops;
 EXPORT_SYMBOL(diu_ops);
 #endif
 
+#ifdef CONFIG_EPAPR_PARAVIRT
 /*
  * Restart the current partition
  *
@@ -278,3 +279,4 @@ void fsl_hv_halt(void)
 	pr_info("hv exit\n");
 	fh_partition_stop(-1);
 }
+#endif
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index bfc6211..9c6e535 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -6,7 +6,7 @@
  *  with various broken implementations of this HW.
  *
  *  Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp.
- *  Copyright 2010-2011 Freescale Semiconductor, Inc.
+ *  Copyright 2010-2012 Freescale Semiconductor, Inc.
  *
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License.  See the file COPYING in the main directory of this archive
@@ -221,24 +221,24 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu
 	_mpic_write(mpic->reg_type, &mpic->gregs, offset, value);
 }
 
-static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm)
+static inline unsigned int mpic_tm_offset(struct mpic *mpic, unsigned int tm)
 {
-	unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) +
-			      ((tm & 3) * MPIC_INFO(TIMER_STRIDE));
+	return (tm >> 2) * MPIC_TIMER_GROUP_STRIDE +
+	       (tm & 3) * MPIC_INFO(TIMER_STRIDE);
+}
 
-	if (tm >= 4)
-		offset += 0x1000 / 4;
+static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm)
+{
+	unsigned int offset = mpic_tm_offset(mpic, tm) +
+			      MPIC_INFO(TIMER_VECTOR_PRI);
 
 	return _mpic_read(mpic->reg_type, &mpic->tmregs, offset);
 }
 
 static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, u32 value)
 {
-	unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) +
-			      ((tm & 3) * MPIC_INFO(TIMER_STRIDE));
-
-	if (tm >= 4)
-		offset += 0x1000 / 4;
+	unsigned int offset = mpic_tm_offset(mpic, tm) +
+			      MPIC_INFO(TIMER_VECTOR_PRI);
 
 	_mpic_write(mpic->reg_type, &mpic->tmregs, offset, value);
 }
@@ -1026,6 +1026,9 @@ static int mpic_host_map(struct irq_domain *h, unsigned int virq,
 		return 0;
 	}
 
+	if (mpic_map_error_int(mpic, virq, hw))
+		return 0;
+
 	if (hw >= mpic->num_sources)
 		return -EINVAL;
 
@@ -1085,7 +1088,16 @@ static int mpic_host_xlate(struct irq_domain *h, struct device_node *ct,
 		 */
 		switch (intspec[2]) {
 		case 0:
-		case 1: /* no EISR/EIMR support for now, treat as shared IRQ */
+			break;
+		case 1:
+			if (!(mpic->flags & MPIC_FSL_HAS_EIMR))
+				break;
+
+			if (intspec[3] >= ARRAY_SIZE(mpic->err_int_vecs))
+				return -EINVAL;
+
+			*out_hwirq = mpic->err_int_vecs[intspec[3]];
+
 			break;
 		case 2:
 			if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs))
@@ -1301,6 +1313,42 @@ struct mpic * __init mpic_alloc(struct device_node *node,
 	mpic_map(mpic, mpic->paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000);
 	mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
 
+	if (mpic->flags & MPIC_FSL) {
+		u32 brr1, version;
+		int ret;
+
+		/*
+		 * Yes, Freescale really did put global registers in the
+		 * magic per-cpu area -- and they don't even show up in the
+		 * non-magic per-cpu copies that this driver normally uses.
+		 */
+		mpic_map(mpic, mpic->paddr, &mpic->thiscpuregs,
+			 MPIC_CPU_THISBASE, 0x1000);
+
+		brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
+				MPIC_FSL_BRR1);
+		version = brr1 & MPIC_FSL_BRR1_VER;
+
+		/* Error interrupt mask register (EIMR) is required for
+		 * handling individual device error interrupts. EIMR
+		 * was added in MPIC version 4.1.
+		 *
+		 * Over here we reserve vector number space for error
+		 * interrupt vectors. This space is stolen from the
+		 * global vector number space, as in case of ipis
+		 * and timer interrupts.
+		 *
+		 * Available vector space = intvec_top - 12, where 12
+		 * is the number of vectors which have been consumed by
+		 * ipis and timer interrupts.
+		 */
+		if (version >= 0x401) {
+			ret = mpic_setup_error_int(mpic, intvec_top - 12);
+			if (ret)
+				return NULL;
+		}
+	}
+
 	/* Reset */
 
 	/* When using a device-node, reset requests are only honored if the MPIC
@@ -1440,6 +1488,7 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
 void __init mpic_init(struct mpic *mpic)
 {
 	int i, cpu;
+	int num_timers = 4;
 
 	BUG_ON(mpic->num_sources == 0);
 
@@ -1448,15 +1497,34 @@ void __init mpic_init(struct mpic *mpic)
 	/* Set current processor priority to max */
 	mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
 
+	if (mpic->flags & MPIC_FSL) {
+		u32 brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
+				      MPIC_FSL_BRR1);
+		u32 version = brr1 & MPIC_FSL_BRR1_VER;
+
+		/*
+		 * Timer group B is present at the latest in MPIC 3.1 (e.g.
+		 * mpc8536).  It is not present in MPIC 2.0 (e.g. mpc8544).
+		 * I don't know about the status of intermediate versions (or
+		 * whether they even exist).
+		 */
+		if (version >= 0x0301)
+			num_timers = 8;
+	}
+
+	/* FSL mpic error interrupt intialization */
+	if (mpic->flags & MPIC_FSL_HAS_EIMR)
+		mpic_err_int_init(mpic, MPIC_FSL_ERR_INT);
+
 	/* Initialize timers to our reserved vectors and mask them for now */
-	for (i = 0; i < 4; i++) {
+	for (i = 0; i < num_timers; i++) {
+		unsigned int offset = mpic_tm_offset(mpic, i);
+
 		mpic_write(mpic->tmregs,
-			   i * MPIC_INFO(TIMER_STRIDE) +
-			   MPIC_INFO(TIMER_DESTINATION),
+			   offset + MPIC_INFO(TIMER_DESTINATION),
 			   1 << hard_smp_processor_id());
 		mpic_write(mpic->tmregs,
-			   i * MPIC_INFO(TIMER_STRIDE) +
-			   MPIC_INFO(TIMER_VECTOR_PRI),
+			   offset + MPIC_INFO(TIMER_VECTOR_PRI),
 			   MPIC_VECPRI_MASK |
 			   (9 << MPIC_VECPRI_PRIORITY_SHIFT) |
 			   (mpic->timer_vecs[0] + i));
diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h
index 13f3e89..24bf07a 100644
--- a/arch/powerpc/sysdev/mpic.h
+++ b/arch/powerpc/sysdev/mpic.h
@@ -40,4 +40,26 @@ extern int mpic_set_affinity(struct irq_data *d,
 			     const struct cpumask *cpumask, bool force);
 extern void mpic_reset_core(int cpu);
 
+#ifdef CONFIG_FSL_SOC
+extern int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t  hw);
+extern void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum);
+extern int mpic_setup_error_int(struct mpic *mpic, int intvec);
+#else
+static inline int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t  hw)
+{
+	return 0;
+}
+
+
+static inline void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum)
+{
+	return;
+}
+
+static inline int mpic_setup_error_int(struct mpic *mpic, int intvec)
+{
+	return -1;
+}
+#endif
+
 #endif /* _POWERPC_SYSDEV_MPIC_H */
diff --git a/arch/s390/Kbuild b/arch/s390/Kbuild
index 9858476..cc45d25 100644
--- a/arch/s390/Kbuild
+++ b/arch/s390/Kbuild
@@ -5,3 +5,4 @@ obj-$(CONFIG_CRYPTO_HW)		+= crypto/
 obj-$(CONFIG_S390_HYPFS_FS)	+= hypfs/
 obj-$(CONFIG_APPLDATA_BASE)	+= appldata/
 obj-$(CONFIG_MATHEMU)		+= math-emu/
+obj-y				+= net/
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 107610e..e9886e2 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -84,6 +84,7 @@ config S390
 	select HAVE_KERNEL_XZ
 	select HAVE_ARCH_MUTEX_CPU_RELAX
 	select HAVE_ARCH_JUMP_LABEL if !MARCH_G5
+	select HAVE_BPF_JIT if 64BIT && PACK_STACK
 	select ARCH_SAVE_PAGE_KEYS if HIBERNATION
 	select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
 	select HAVE_MEMBLOCK
@@ -125,6 +126,8 @@ config S390
 	select GENERIC_CLOCKEVENTS
 	select KTIME_SCALAR if 32BIT
 	select HAVE_ARCH_SECCOMP_FILTER
+	select HAVE_MOD_ARCH_SPECIFIC
+	select MODULES_USE_ELF_RELA
 
 config SCHED_OMIT_FRAME_POINTER
 	def_bool y
diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c
index e402a9d..da3c1a7 100644
--- a/arch/s390/crypto/aes_s390.c
+++ b/arch/s390/crypto/aes_s390.c
@@ -216,7 +216,6 @@ static struct crypto_alg aes_alg = {
 	.cra_blocksize		=	AES_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct s390_aes_ctx),
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(aes_alg.cra_list),
 	.cra_init               =       fallback_init_cip,
 	.cra_exit               =       fallback_exit_cip,
 	.cra_u			=	{
@@ -398,7 +397,6 @@ static struct crypto_alg ecb_aes_alg = {
 	.cra_ctxsize		=	sizeof(struct s390_aes_ctx),
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(ecb_aes_alg.cra_list),
 	.cra_init		=	fallback_init_blk,
 	.cra_exit		=	fallback_exit_blk,
 	.cra_u			=	{
@@ -508,7 +506,6 @@ static struct crypto_alg cbc_aes_alg = {
 	.cra_ctxsize		=	sizeof(struct s390_aes_ctx),
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(cbc_aes_alg.cra_list),
 	.cra_init		=	fallback_init_blk,
 	.cra_exit		=	fallback_exit_blk,
 	.cra_u			=	{
@@ -710,7 +707,6 @@ static struct crypto_alg xts_aes_alg = {
 	.cra_ctxsize		=	sizeof(struct s390_xts_ctx),
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(xts_aes_alg.cra_list),
 	.cra_init		=	xts_fallback_init,
 	.cra_exit		=	xts_fallback_exit,
 	.cra_u			=	{
@@ -832,7 +828,6 @@ static struct crypto_alg ctr_aes_alg = {
 	.cra_ctxsize		=	sizeof(struct s390_aes_ctx),
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(ctr_aes_alg.cra_list),
 	.cra_u			=	{
 		.blkcipher = {
 			.min_keysize		=	AES_MIN_KEY_SIZE,
diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c
index 1eaa371..b49fb96 100644
--- a/arch/s390/crypto/des_s390.c
+++ b/arch/s390/crypto/des_s390.c
@@ -70,7 +70,6 @@ static struct crypto_alg des_alg = {
 	.cra_blocksize		=	DES_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct s390_des_ctx),
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(des_alg.cra_list),
 	.cra_u			=	{
 		.cipher = {
 			.cia_min_keysize	=	DES_KEY_SIZE,
@@ -163,7 +162,6 @@ static struct crypto_alg ecb_des_alg = {
 	.cra_ctxsize		=	sizeof(struct s390_des_ctx),
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(ecb_des_alg.cra_list),
 	.cra_u			=	{
 		.blkcipher = {
 			.min_keysize		=	DES_KEY_SIZE,
@@ -206,7 +204,6 @@ static struct crypto_alg cbc_des_alg = {
 	.cra_ctxsize		=	sizeof(struct s390_des_ctx),
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(cbc_des_alg.cra_list),
 	.cra_u			=	{
 		.blkcipher = {
 			.min_keysize		=	DES_KEY_SIZE,
@@ -271,7 +268,6 @@ static struct crypto_alg des3_alg = {
 	.cra_blocksize		=	DES_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct s390_des_ctx),
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(des3_alg.cra_list),
 	.cra_u			=	{
 		.cipher = {
 			.cia_min_keysize	=	DES3_KEY_SIZE,
@@ -314,8 +310,6 @@ static struct crypto_alg ecb_des3_alg = {
 	.cra_ctxsize		=	sizeof(struct s390_des_ctx),
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(
-						ecb_des3_alg.cra_list),
 	.cra_u			=	{
 		.blkcipher = {
 			.min_keysize		=	DES3_KEY_SIZE,
@@ -358,8 +352,6 @@ static struct crypto_alg cbc_des3_alg = {
 	.cra_ctxsize		=	sizeof(struct s390_des_ctx),
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(
-						cbc_des3_alg.cra_list),
 	.cra_u			=	{
 		.blkcipher = {
 			.min_keysize		=	DES3_KEY_SIZE,
@@ -452,7 +444,6 @@ static struct crypto_alg ctr_des_alg = {
 	.cra_ctxsize		=	sizeof(struct s390_des_ctx),
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(ctr_des_alg.cra_list),
 	.cra_u			=	{
 		.blkcipher = {
 			.min_keysize		=	DES_KEY_SIZE,
@@ -496,7 +487,6 @@ static struct crypto_alg ctr_des3_alg = {
 	.cra_ctxsize		=	sizeof(struct s390_des_ctx),
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(ctr_des3_alg.cra_list),
 	.cra_u			=	{
 		.blkcipher = {
 			.min_keysize		=	DES3_KEY_SIZE,
diff --git a/arch/s390/crypto/ghash_s390.c b/arch/s390/crypto/ghash_s390.c
index b1bd170..1ebd3a1 100644
--- a/arch/s390/crypto/ghash_s390.c
+++ b/arch/s390/crypto/ghash_s390.c
@@ -135,7 +135,6 @@ static struct shash_alg ghash_alg = {
 		.cra_blocksize		= GHASH_BLOCK_SIZE,
 		.cra_ctxsize		= sizeof(struct ghash_ctx),
 		.cra_module		= THIS_MODULE,
-		.cra_list		= LIST_HEAD_INIT(ghash_alg.base.cra_list),
 	},
 };
 
diff --git a/arch/s390/include/asm/module.h b/arch/s390/include/asm/module.h
index f0b6b26..df1f861 100644
--- a/arch/s390/include/asm/module.h
+++ b/arch/s390/include/asm/module.h
@@ -1,5 +1,8 @@
 #ifndef _ASM_S390_MODULE_H
 #define _ASM_S390_MODULE_H
+
+#include <asm-generic/module.h>
+
 /*
  * This file contains the s390 architecture specific module code.
  */
@@ -28,19 +31,4 @@ struct mod_arch_specific
 	struct mod_arch_syminfo *syminfo;
 };
 
-#ifdef CONFIG_64BIT
-#define ElfW(x) Elf64_ ## x
-#define ELFW(x) ELF64_ ## x
-#else
-#define ElfW(x) Elf32_ ## x
-#define ELFW(x) ELF32_ ## x
-#endif
-
-#define Elf_Addr ElfW(Addr)
-#define Elf_Rela ElfW(Rela)
-#define Elf_Shdr ElfW(Shdr)
-#define Elf_Sym ElfW(Sym)
-#define Elf_Ehdr ElfW(Ehdr)
-#define ELF_R_SYM ELFW(R_SYM)
-#define ELF_R_TYPE ELFW(R_TYPE)
 #endif /* _ASM_S390_MODULE_H */
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index 11e4e32..01c97b9 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -140,6 +140,8 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 extern unsigned long thread_saved_pc(struct task_struct *t);
 
 extern void show_code(struct pt_regs *regs);
+extern void print_fn_code(unsigned char *code, unsigned long len);
+extern int insn_to_mnemonic(unsigned char *instruction, char buf[8]);
 
 unsigned long get_wchan(struct task_struct *p);
 #define task_pt_regs(tsk) ((struct pt_regs *) \
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index bb08e2a..9e2cfe0 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -91,8 +91,6 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SYSCALL_AUDIT	9	/* syscall auditing active */
 #define TIF_SECCOMP		10	/* secure computing */
 #define TIF_SYSCALL_TRACEPOINT	11	/* syscall tracepoint instrumentation */
-#define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling
-					   TIF_NEED_RESCHED */
 #define TIF_31BIT		17	/* 32bit process */
 #define TIF_MEMDIE		18	/* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK	19	/* restore signal mask in do_signal() */
@@ -100,7 +98,6 @@ static inline struct thread_info *current_thread_info(void)
 
 #define _TIF_SYSCALL		(1<<TIF_SYSCALL)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_PER_TRAP		(1<<TIF_PER_TRAP)
@@ -109,7 +106,6 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP		(1<<TIF_SECCOMP)
 #define _TIF_SYSCALL_TRACEPOINT	(1<<TIF_SYSCALL_TRACEPOINT)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 #define _TIF_31BIT		(1<<TIF_31BIT)
 #define _TIF_SINGLE_STEP	(1<<TIF_SINGLE_STEP)
 
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
index 619c5d3..266d722 100644
--- a/arch/s390/kernel/dis.c
+++ b/arch/s390/kernel/dis.c
@@ -1468,6 +1468,33 @@ static struct insn *find_insn(unsigned char *code)
 	return NULL;
 }
 
+/**
+ * insn_to_mnemonic - decode an s390 instruction
+ * @instruction: instruction to decode
+ * @buf: buffer to fill with mnemonic
+ *
+ * Decode the instruction at @instruction and store the corresponding
+ * mnemonic into @buf.
+ * @buf is left unchanged if the instruction could not be decoded.
+ * Returns:
+ *  %0 on success, %-ENOENT if the instruction was not found.
+ */
+int insn_to_mnemonic(unsigned char *instruction, char buf[8])
+{
+	struct insn *insn;
+
+	insn = find_insn(instruction);
+	if (!insn)
+		return -ENOENT;
+	if (insn->name[0] == '\0')
+		snprintf(buf, sizeof(buf), "%s",
+			 long_insn_name[(int) insn->name[1]]);
+	else
+		snprintf(buf, sizeof(buf), "%.5s", insn->name);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(insn_to_mnemonic);
+
 static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
 {
 	struct insn *insn;
@@ -1601,3 +1628,26 @@ void show_code(struct pt_regs *regs)
 	}
 	printk("\n");
 }
+
+void print_fn_code(unsigned char *code, unsigned long len)
+{
+	char buffer[64], *ptr;
+	int opsize, i;
+
+	while (len) {
+		ptr = buffer;
+		opsize = insn_length(*code);
+		ptr += sprintf(ptr, "%p: ", code);
+		for (i = 0; i < opsize; i++)
+			ptr += sprintf(ptr, "%02x", code[i]);
+		*ptr++ = '\t';
+		if (i < 4)
+			*ptr++ = '\t';
+		ptr += print_insn(ptr, code, (unsigned long) code);
+		*ptr++ = '\n';
+		*ptr++ = 0;
+		printk(buffer);
+		code += opsize;
+		len -= opsize;
+	}
+}
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig
index 78eb984..a6e2677 100644
--- a/arch/s390/kvm/Kconfig
+++ b/arch/s390/kvm/Kconfig
@@ -21,6 +21,7 @@ config KVM
 	depends on HAVE_KVM && EXPERIMENTAL
 	select PREEMPT_NOTIFIERS
 	select ANON_INODES
+	select HAVE_KVM_CPU_RELAX_INTERCEPT
 	---help---
 	  Support hosting paravirtualized guest machines using the SIE
 	  virtualization capability on the mainframe. This should work
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c
index c88bb77..a390687 100644
--- a/arch/s390/kvm/diag.c
+++ b/arch/s390/kvm/diag.c
@@ -14,6 +14,8 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include "kvm-s390.h"
+#include "trace.h"
+#include "trace-s390.h"
 
 static int diag_release_pages(struct kvm_vcpu *vcpu)
 {
@@ -98,6 +100,7 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
 	vcpu->run->exit_reason = KVM_EXIT_S390_RESET;
 	VCPU_EVENT(vcpu, 3, "requesting userspace resets %llx",
 	  vcpu->run->s390_reset_flags);
+	trace_kvm_s390_request_resets(vcpu->run->s390_reset_flags);
 	return -EREMOTE;
 }
 
@@ -105,6 +108,7 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu)
 {
 	int code = (vcpu->arch.sie_block->ipb & 0xfff0000) >> 16;
 
+	trace_kvm_s390_handle_diag(vcpu, code);
 	switch (code) {
 	case 0x10:
 		return diag_release_pages(vcpu);
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index adae539..22798ec 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -19,6 +19,8 @@
 
 #include "kvm-s390.h"
 #include "gaccess.h"
+#include "trace.h"
+#include "trace-s390.h"
 
 static int handle_lctlg(struct kvm_vcpu *vcpu)
 {
@@ -45,6 +47,7 @@ static int handle_lctlg(struct kvm_vcpu *vcpu)
 
 	VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2,
 		   disp2);
+	trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, useraddr);
 
 	do {
 		rc = get_guest_u64(vcpu, useraddr,
@@ -82,6 +85,7 @@ static int handle_lctl(struct kvm_vcpu *vcpu)
 
 	VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2,
 		   disp2);
+	trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, useraddr);
 
 	reg = reg1;
 	do {
@@ -135,6 +139,8 @@ static int handle_stop(struct kvm_vcpu *vcpu)
 	vcpu->stat.exit_stop_request++;
 	spin_lock_bh(&vcpu->arch.local_int.lock);
 
+	trace_kvm_s390_stop_request(vcpu->arch.local_int.action_bits);
+
 	if (vcpu->arch.local_int.action_bits & ACTION_RELOADVCPU_ON_STOP) {
 		vcpu->arch.local_int.action_bits &= ~ACTION_RELOADVCPU_ON_STOP;
 		rc = SIE_INTERCEPT_RERUNVCPU;
@@ -171,6 +177,7 @@ static int handle_validity(struct kvm_vcpu *vcpu)
 	int rc;
 
 	vcpu->stat.exit_validity++;
+	trace_kvm_s390_intercept_validity(vcpu, viwhy);
 	if (viwhy == 0x37) {
 		vmaddr = gmap_fault(vcpu->arch.sie_block->prefix,
 				    vcpu->arch.gmap);
@@ -213,6 +220,9 @@ static int handle_instruction(struct kvm_vcpu *vcpu)
 	intercept_handler_t handler;
 
 	vcpu->stat.exit_instruction++;
+	trace_kvm_s390_intercept_instruction(vcpu,
+					     vcpu->arch.sie_block->ipa,
+					     vcpu->arch.sie_block->ipb);
 	handler = instruction_handlers[vcpu->arch.sie_block->ipa >> 8];
 	if (handler)
 		return handler(vcpu);
@@ -222,6 +232,7 @@ static int handle_instruction(struct kvm_vcpu *vcpu)
 static int handle_prog(struct kvm_vcpu *vcpu)
 {
 	vcpu->stat.exit_program_interruption++;
+	trace_kvm_s390_intercept_prog(vcpu, vcpu->arch.sie_block->iprcc);
 	return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc);
 }
 
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index b7bc1aa..7556231 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -19,6 +19,7 @@
 #include <asm/uaccess.h>
 #include "kvm-s390.h"
 #include "gaccess.h"
+#include "trace-s390.h"
 
 static int psw_extint_disabled(struct kvm_vcpu *vcpu)
 {
@@ -130,6 +131,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
 	case KVM_S390_INT_EMERGENCY:
 		VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp emerg");
 		vcpu->stat.deliver_emergency_signal++;
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+						 inti->emerg.code, 0);
 		rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1201);
 		if (rc == -EFAULT)
 			exception = 1;
@@ -152,6 +155,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
 	case KVM_S390_INT_EXTERNAL_CALL:
 		VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp ext call");
 		vcpu->stat.deliver_external_call++;
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+						 inti->extcall.code, 0);
 		rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1202);
 		if (rc == -EFAULT)
 			exception = 1;
@@ -175,6 +180,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
 		VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x",
 			   inti->ext.ext_params);
 		vcpu->stat.deliver_service_signal++;
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+						 inti->ext.ext_params, 0);
 		rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2401);
 		if (rc == -EFAULT)
 			exception = 1;
@@ -198,6 +205,9 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
 		VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%llx",
 			   inti->ext.ext_params, inti->ext.ext_params2);
 		vcpu->stat.deliver_virtio_interrupt++;
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+						 inti->ext.ext_params,
+						 inti->ext.ext_params2);
 		rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2603);
 		if (rc == -EFAULT)
 			exception = 1;
@@ -229,6 +239,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
 	case KVM_S390_SIGP_STOP:
 		VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu stop");
 		vcpu->stat.deliver_stop_signal++;
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+						 0, 0);
 		__set_intercept_indicator(vcpu, inti);
 		break;
 
@@ -236,12 +248,16 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
 		VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x",
 			   inti->prefix.address);
 		vcpu->stat.deliver_prefix_signal++;
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+						 inti->prefix.address, 0);
 		kvm_s390_set_prefix(vcpu, inti->prefix.address);
 		break;
 
 	case KVM_S390_RESTART:
 		VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu restart");
 		vcpu->stat.deliver_restart_signal++;
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+						 0, 0);
 		rc = copy_to_guest(vcpu, offsetof(struct _lowcore,
 		  restart_old_psw), &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
 		if (rc == -EFAULT)
@@ -259,6 +275,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
 			   inti->pgm.code,
 			   table[vcpu->arch.sie_block->ipa >> 14]);
 		vcpu->stat.deliver_program_int++;
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+						 inti->pgm.code, 0);
 		rc = put_guest_u16(vcpu, __LC_PGM_INT_CODE, inti->pgm.code);
 		if (rc == -EFAULT)
 			exception = 1;
@@ -515,6 +533,7 @@ int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
 	inti->pgm.code = code;
 
 	VCPU_EVENT(vcpu, 3, "inject: program check %d (from kernel)", code);
+	trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, inti->type, code, 0, 1);
 	spin_lock_bh(&li->lock);
 	list_add(&inti->list, &li->list);
 	atomic_set(&li->active, 1);
@@ -556,6 +575,8 @@ int kvm_s390_inject_vm(struct kvm *kvm,
 		kfree(inti);
 		return -EINVAL;
 	}
+	trace_kvm_s390_inject_vm(s390int->type, s390int->parm, s390int->parm64,
+				 2);
 
 	mutex_lock(&kvm->lock);
 	fi = &kvm->arch.float_int;
@@ -621,6 +642,8 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
 		kfree(inti);
 		return -EINVAL;
 	}
+	trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, s390int->type, s390int->parm,
+				   s390int->parm64, 2);
 
 	mutex_lock(&vcpu->kvm->lock);
 	li = &vcpu->arch.local_int;
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index d470ccb..e83df7f 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -32,6 +32,10 @@
 #include "kvm-s390.h"
 #include "gaccess.h"
 
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+#include "trace-s390.h"
+
 #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
 
 struct kvm_stats_debugfs_item debugfs_entries[] = {
@@ -242,6 +246,7 @@ out_err:
 void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 {
 	VCPU_EVENT(vcpu, 3, "%s", "free cpu");
+	trace_kvm_s390_destroy_vcpu(vcpu->vcpu_id);
 	if (!kvm_is_ucontrol(vcpu->kvm)) {
 		clear_bit(63 - vcpu->vcpu_id,
 			  (unsigned long *) &vcpu->kvm->arch.sca->mcn);
@@ -417,6 +422,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
 		goto out_free_sie_block;
 	VM_EVENT(kvm, 3, "create cpu %d at %p, sie block at %p", id, vcpu,
 		 vcpu->arch.sie_block);
+	trace_kvm_s390_create_vcpu(id, vcpu, vcpu->arch.sie_block);
 
 	return vcpu;
 out_free_sie_block:
@@ -607,18 +613,22 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
 	local_irq_enable();
 	VCPU_EVENT(vcpu, 6, "entering sie flags %x",
 		   atomic_read(&vcpu->arch.sie_block->cpuflags));
+	trace_kvm_s390_sie_enter(vcpu,
+				 atomic_read(&vcpu->arch.sie_block->cpuflags));
 	rc = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs);
 	if (rc) {
 		if (kvm_is_ucontrol(vcpu->kvm)) {
 			rc = SIE_INTERCEPT_UCONTROL;
 		} else {
 			VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction");
+			trace_kvm_s390_sie_fault(vcpu);
 			kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
 			rc = 0;
 		}
 	}
 	VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
 		   vcpu->arch.sie_block->icptcode);
+	trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode);
 	local_irq_disable();
 	kvm_guest_exit();
 	local_irq_enable();
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 60da903..ed256fd 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -20,6 +20,7 @@
 #include <asm/sysinfo.h>
 #include "gaccess.h"
 #include "kvm-s390.h"
+#include "trace.h"
 
 static int handle_set_prefix(struct kvm_vcpu *vcpu)
 {
@@ -59,6 +60,7 @@ static int handle_set_prefix(struct kvm_vcpu *vcpu)
 	kvm_s390_set_prefix(vcpu, address);
 
 	VCPU_EVENT(vcpu, 5, "setting prefix to %x", address);
+	trace_kvm_s390_handle_prefix(vcpu, 1, address);
 out:
 	return 0;
 }
@@ -91,6 +93,7 @@ static int handle_store_prefix(struct kvm_vcpu *vcpu)
 	}
 
 	VCPU_EVENT(vcpu, 5, "storing prefix to %x", address);
+	trace_kvm_s390_handle_prefix(vcpu, 0, address);
 out:
 	return 0;
 }
@@ -119,6 +122,7 @@ static int handle_store_cpu_address(struct kvm_vcpu *vcpu)
 	}
 
 	VCPU_EVENT(vcpu, 5, "storing cpu address to %llx", useraddr);
+	trace_kvm_s390_handle_stap(vcpu, useraddr);
 out:
 	return 0;
 }
@@ -164,9 +168,11 @@ static int handle_stfl(struct kvm_vcpu *vcpu)
 			   &facility_list, sizeof(facility_list));
 	if (rc == -EFAULT)
 		kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
-	else
+	else {
 		VCPU_EVENT(vcpu, 5, "store facility list value %x",
 			   facility_list);
+		trace_kvm_s390_handle_stfl(vcpu, facility_list);
+	}
 	return 0;
 }
 
@@ -278,6 +284,7 @@ static int handle_stsi(struct kvm_vcpu *vcpu)
 		kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
 		goto out_mem;
 	}
+	trace_kvm_s390_handle_stsi(vcpu, fc, sel1, sel2, operand2);
 	free_page(mem);
 	vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
 	vcpu->run->s.regs.gprs[0] = 0;
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index 56f80e1..566ddf6 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -18,6 +18,7 @@
 #include <asm/sigp.h>
 #include "gaccess.h"
 #include "kvm-s390.h"
+#include "trace.h"
 
 static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
 			u64 *reg)
@@ -344,6 +345,7 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
 	else
 		parameter = vcpu->run->s.regs.gprs[r1 + 1];
 
+	trace_kvm_s390_handle_sigp(vcpu, order_code, cpu_addr, parameter);
 	switch (order_code) {
 	case SIGP_SENSE:
 		vcpu->stat.instruction_sigp_sense++;
diff --git a/arch/s390/kvm/trace-s390.h b/arch/s390/kvm/trace-s390.h
new file mode 100644
index 0000000..90fdf85
--- /dev/null
+++ b/arch/s390/kvm/trace-s390.h
@@ -0,0 +1,210 @@
+#if !defined(_TRACE_KVMS390_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_KVMS390_H
+
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kvm-s390
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace-s390
+
+/*
+ * Trace point for the creation of the kvm instance.
+ */
+TRACE_EVENT(kvm_s390_create_vm,
+	    TP_PROTO(unsigned long type),
+	    TP_ARGS(type),
+
+	    TP_STRUCT__entry(
+		    __field(unsigned long, type)
+		    ),
+
+	    TP_fast_assign(
+		    __entry->type = type;
+		    ),
+
+	    TP_printk("create vm%s",
+		      __entry->type & KVM_VM_S390_UCONTROL ? " (UCONTROL)" : "")
+	);
+
+/*
+ * Trace points for creation and destruction of vpcus.
+ */
+TRACE_EVENT(kvm_s390_create_vcpu,
+	    TP_PROTO(unsigned int id, struct kvm_vcpu *vcpu,
+		     struct kvm_s390_sie_block *sie_block),
+	    TP_ARGS(id, vcpu, sie_block),
+
+	    TP_STRUCT__entry(
+		    __field(unsigned int, id)
+		    __field(struct kvm_vcpu *, vcpu)
+		    __field(struct kvm_s390_sie_block *, sie_block)
+		    ),
+
+	    TP_fast_assign(
+		    __entry->id = id;
+		    __entry->vcpu = vcpu;
+		    __entry->sie_block = sie_block;
+		    ),
+
+	    TP_printk("create cpu %d at %p, sie block at %p", __entry->id,
+		      __entry->vcpu, __entry->sie_block)
+	);
+
+TRACE_EVENT(kvm_s390_destroy_vcpu,
+	    TP_PROTO(unsigned int id),
+	    TP_ARGS(id),
+
+	    TP_STRUCT__entry(
+		    __field(unsigned int, id)
+		    ),
+
+	    TP_fast_assign(
+		    __entry->id = id;
+		    ),
+
+	    TP_printk("destroy cpu %d", __entry->id)
+	);
+
+/*
+ * Trace points for injection of interrupts, either per machine or
+ * per vcpu.
+ */
+
+#define kvm_s390_int_type						\
+	{KVM_S390_SIGP_STOP, "sigp stop"},				\
+	{KVM_S390_PROGRAM_INT, "program interrupt"},			\
+	{KVM_S390_SIGP_SET_PREFIX, "sigp set prefix"},			\
+	{KVM_S390_RESTART, "sigp restart"},				\
+	{KVM_S390_INT_VIRTIO, "virtio interrupt"},			\
+	{KVM_S390_INT_SERVICE, "sclp interrupt"},			\
+	{KVM_S390_INT_EMERGENCY, "sigp emergency"},			\
+	{KVM_S390_INT_EXTERNAL_CALL, "sigp ext call"}
+
+TRACE_EVENT(kvm_s390_inject_vm,
+	    TP_PROTO(__u64 type, __u32 parm, __u64 parm64, int who),
+	    TP_ARGS(type, parm, parm64, who),
+
+	    TP_STRUCT__entry(
+		    __field(__u32, inttype)
+		    __field(__u32, parm)
+		    __field(__u64, parm64)
+		    __field(int, who)
+		    ),
+
+	    TP_fast_assign(
+		    __entry->inttype = type & 0x00000000ffffffff;
+		    __entry->parm = parm;
+		    __entry->parm64 = parm64;
+		    __entry->who = who;
+		    ),
+
+	    TP_printk("inject%s: type:%x (%s) parm:%x parm64:%llx",
+		      (__entry->who == 1) ? " (from kernel)" :
+		      (__entry->who == 2) ? " (from user)" : "",
+		      __entry->inttype,
+		      __print_symbolic(__entry->inttype, kvm_s390_int_type),
+		      __entry->parm, __entry->parm64)
+	);
+
+TRACE_EVENT(kvm_s390_inject_vcpu,
+	    TP_PROTO(unsigned int id, __u64 type, __u32 parm, __u64 parm64, \
+		     int who),
+	    TP_ARGS(id, type, parm, parm64, who),
+
+	    TP_STRUCT__entry(
+		    __field(int, id)
+		    __field(__u32, inttype)
+		    __field(__u32, parm)
+		    __field(__u64, parm64)
+		    __field(int, who)
+		    ),
+
+	    TP_fast_assign(
+		    __entry->id = id;
+		    __entry->inttype = type & 0x00000000ffffffff;
+		    __entry->parm = parm;
+		    __entry->parm64 = parm64;
+		    __entry->who = who;
+		    ),
+
+	    TP_printk("inject%s (vcpu %d): type:%x (%s) parm:%x parm64:%llx",
+		      (__entry->who == 1) ? " (from kernel)" :
+		      (__entry->who == 2) ? " (from user)" : "",
+		      __entry->id, __entry->inttype,
+		      __print_symbolic(__entry->inttype, kvm_s390_int_type),
+		      __entry->parm, __entry->parm64)
+	);
+
+/*
+ * Trace point for the actual delivery of interrupts.
+ */
+TRACE_EVENT(kvm_s390_deliver_interrupt,
+	    TP_PROTO(unsigned int id, __u64 type, __u32 data0, __u64 data1),
+	    TP_ARGS(id, type, data0, data1),
+
+	    TP_STRUCT__entry(
+		    __field(int, id)
+		    __field(__u32, inttype)
+		    __field(__u32, data0)
+		    __field(__u64, data1)
+		    ),
+
+	    TP_fast_assign(
+		    __entry->id = id;
+		    __entry->inttype = type & 0x00000000ffffffff;
+		    __entry->data0 = data0;
+		    __entry->data1 = data1;
+		    ),
+
+	    TP_printk("deliver interrupt (vcpu %d): type:%x (%s) "	\
+		      "data:%08x %016llx",
+		      __entry->id, __entry->inttype,
+		      __print_symbolic(__entry->inttype, kvm_s390_int_type),
+		      __entry->data0, __entry->data1)
+	);
+
+/*
+ * Trace point for resets that may be requested from userspace.
+ */
+TRACE_EVENT(kvm_s390_request_resets,
+	    TP_PROTO(__u64 resets),
+	    TP_ARGS(resets),
+
+	    TP_STRUCT__entry(
+		    __field(__u64, resets)
+		    ),
+
+	    TP_fast_assign(
+		    __entry->resets = resets;
+		    ),
+
+	    TP_printk("requesting userspace resets %llx",
+		      __entry->resets)
+	);
+
+/*
+ * Trace point for a vcpu's stop requests.
+ */
+TRACE_EVENT(kvm_s390_stop_request,
+	    TP_PROTO(unsigned int action_bits),
+	    TP_ARGS(action_bits),
+
+	    TP_STRUCT__entry(
+		    __field(unsigned int, action_bits)
+		    ),
+
+	    TP_fast_assign(
+		    __entry->action_bits = action_bits;
+		    ),
+
+	    TP_printk("stop request, action_bits = %08x",
+		      __entry->action_bits)
+	);
+
+
+#endif /* _TRACE_KVMS390_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/arch/s390/kvm/trace.h b/arch/s390/kvm/trace.h
new file mode 100644
index 0000000..2b29e62
--- /dev/null
+++ b/arch/s390/kvm/trace.h
@@ -0,0 +1,341 @@
+#if !defined(_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_KVM_H
+
+#include <linux/tracepoint.h>
+#include <asm/sigp.h>
+#include <asm/debug.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kvm
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+/*
+ * Helpers for vcpu-specific tracepoints containing the same information
+ * as s390dbf VCPU_EVENTs.
+ */
+#define VCPU_PROTO_COMMON struct kvm_vcpu *vcpu
+#define VCPU_ARGS_COMMON vcpu
+#define VCPU_FIELD_COMMON __field(int, id)			\
+	__field(unsigned long, pswmask)				\
+	__field(unsigned long, pswaddr)
+#define VCPU_ASSIGN_COMMON do {						\
+	__entry->id = vcpu->vcpu_id;					\
+	__entry->pswmask = vcpu->arch.sie_block->gpsw.mask;		\
+	__entry->pswaddr = vcpu->arch.sie_block->gpsw.addr;		\
+	} while (0);
+#define VCPU_TP_PRINTK(p_str, p_args...)				\
+	TP_printk("%02d[%016lx-%016lx]: " p_str, __entry->id,		\
+		  __entry->pswmask, __entry->pswaddr, p_args)
+
+/*
+ * Tracepoints for SIE entry and exit.
+ */
+TRACE_EVENT(kvm_s390_sie_enter,
+	    TP_PROTO(VCPU_PROTO_COMMON, int cpuflags),
+	    TP_ARGS(VCPU_ARGS_COMMON, cpuflags),
+
+	    TP_STRUCT__entry(
+		    VCPU_FIELD_COMMON
+		    __field(int, cpuflags)
+		    ),
+
+	    TP_fast_assign(
+		    VCPU_ASSIGN_COMMON
+		    __entry->cpuflags = cpuflags;
+		    ),
+
+	    VCPU_TP_PRINTK("entering sie flags %x", __entry->cpuflags)
+	);
+
+TRACE_EVENT(kvm_s390_sie_fault,
+	    TP_PROTO(VCPU_PROTO_COMMON),
+	    TP_ARGS(VCPU_ARGS_COMMON),
+
+	    TP_STRUCT__entry(
+		    VCPU_FIELD_COMMON
+		    ),
+
+	    TP_fast_assign(
+		    VCPU_ASSIGN_COMMON
+		    ),
+
+	    VCPU_TP_PRINTK("%s", "fault in sie instruction")
+	);
+
+#define sie_intercept_code				\
+	{0x04, "Instruction"},				\
+	{0x08, "Program interruption"},			\
+	{0x0C, "Instruction and program interuption"},	\
+	{0x10, "External request"},			\
+	{0x14, "External interruption"},		\
+	{0x18, "I/O request"},				\
+	{0x1C, "Wait state"},				\
+	{0x20, "Validity"},				\
+	{0x28, "Stop request"}
+
+TRACE_EVENT(kvm_s390_sie_exit,
+	    TP_PROTO(VCPU_PROTO_COMMON, u8 icptcode),
+	    TP_ARGS(VCPU_ARGS_COMMON, icptcode),
+
+	    TP_STRUCT__entry(
+		    VCPU_FIELD_COMMON
+		    __field(u8, icptcode)
+		    ),
+
+	    TP_fast_assign(
+		    VCPU_ASSIGN_COMMON
+		    __entry->icptcode = icptcode;
+		    ),
+
+	    VCPU_TP_PRINTK("exit sie icptcode %d (%s)", __entry->icptcode,
+			   __print_symbolic(__entry->icptcode,
+					    sie_intercept_code))
+	);
+
+/*
+ * Trace point for intercepted instructions.
+ */
+TRACE_EVENT(kvm_s390_intercept_instruction,
+	    TP_PROTO(VCPU_PROTO_COMMON, __u16 ipa, __u32 ipb),
+	    TP_ARGS(VCPU_ARGS_COMMON, ipa, ipb),
+
+	    TP_STRUCT__entry(
+		    VCPU_FIELD_COMMON
+		    __field(__u64, instruction)
+		    __field(char, insn[8])
+		    ),
+
+	    TP_fast_assign(
+		    VCPU_ASSIGN_COMMON
+		    __entry->instruction = ((__u64)ipa << 48) |
+		    ((__u64)ipb << 16);
+		    ),
+
+	    VCPU_TP_PRINTK("intercepted instruction %016llx (%s)",
+			   __entry->instruction,
+			   insn_to_mnemonic((unsigned char *)
+					    &__entry->instruction,
+					 __entry->insn) ?
+			   "unknown" : __entry->insn)
+	);
+
+/*
+ * Trace point for intercepted program interruptions.
+ */
+TRACE_EVENT(kvm_s390_intercept_prog,
+	    TP_PROTO(VCPU_PROTO_COMMON, __u16 code),
+	    TP_ARGS(VCPU_ARGS_COMMON, code),
+
+	    TP_STRUCT__entry(
+		    VCPU_FIELD_COMMON
+		    __field(__u16, code)
+		    ),
+
+	    TP_fast_assign(
+		    VCPU_ASSIGN_COMMON
+		    __entry->code = code;
+		    ),
+
+	    VCPU_TP_PRINTK("intercepted program interruption %04x",
+			   __entry->code)
+	);
+
+/*
+ * Trace point for validity intercepts.
+ */
+TRACE_EVENT(kvm_s390_intercept_validity,
+	    TP_PROTO(VCPU_PROTO_COMMON, __u16 viwhy),
+	    TP_ARGS(VCPU_ARGS_COMMON, viwhy),
+
+	    TP_STRUCT__entry(
+		    VCPU_FIELD_COMMON
+		    __field(__u16, viwhy)
+		    ),
+
+	    TP_fast_assign(
+		    VCPU_ASSIGN_COMMON
+		    __entry->viwhy = viwhy;
+		    ),
+
+	    VCPU_TP_PRINTK("got validity intercept %04x", __entry->viwhy)
+	);
+
+/*
+ * Trace points for instructions that are of special interest.
+ */
+
+#define sigp_order_codes					\
+	{SIGP_SENSE, "sense"},					\
+	{SIGP_EXTERNAL_CALL, "external call"},			\
+	{SIGP_EMERGENCY_SIGNAL, "emergency signal"},		\
+	{SIGP_STOP, "stop"},					\
+	{SIGP_STOP_AND_STORE_STATUS, "stop and store status"},	\
+	{SIGP_SET_ARCHITECTURE, "set architecture"},		\
+	{SIGP_SET_PREFIX, "set prefix"},			\
+	{SIGP_SENSE_RUNNING, "sense running"},			\
+	{SIGP_RESTART, "restart"}
+
+TRACE_EVENT(kvm_s390_handle_sigp,
+	    TP_PROTO(VCPU_PROTO_COMMON, __u8 order_code, __u16 cpu_addr, \
+		     __u32 parameter),
+	    TP_ARGS(VCPU_ARGS_COMMON, order_code, cpu_addr, parameter),
+
+	    TP_STRUCT__entry(
+		    VCPU_FIELD_COMMON
+		    __field(__u8, order_code)
+		    __field(__u16, cpu_addr)
+		    __field(__u32, parameter)
+		    ),
+
+	    TP_fast_assign(
+		    VCPU_ASSIGN_COMMON
+		    __entry->order_code = order_code;
+		    __entry->cpu_addr = cpu_addr;
+		    __entry->parameter = parameter;
+		    ),
+
+	    VCPU_TP_PRINTK("handle sigp order %02x (%s), cpu address %04x, " \
+			   "parameter %08x", __entry->order_code,
+			   __print_symbolic(__entry->order_code,
+					    sigp_order_codes),
+			   __entry->cpu_addr, __entry->parameter)
+	);
+
+#define diagnose_codes				\
+	{0x10, "release pages"},		\
+	{0x44, "time slice end"},		\
+	{0x308, "ipl functions"},		\
+	{0x500, "kvm hypercall"},		\
+	{0x501, "kvm breakpoint"}
+
+TRACE_EVENT(kvm_s390_handle_diag,
+	    TP_PROTO(VCPU_PROTO_COMMON, __u16 code),
+	    TP_ARGS(VCPU_ARGS_COMMON, code),
+
+	    TP_STRUCT__entry(
+		    VCPU_FIELD_COMMON
+		    __field(__u16, code)
+		    ),
+
+	    TP_fast_assign(
+		    VCPU_ASSIGN_COMMON
+		    __entry->code = code;
+		    ),
+
+	    VCPU_TP_PRINTK("handle diagnose call %04x (%s)", __entry->code,
+			   __print_symbolic(__entry->code, diagnose_codes))
+	);
+
+TRACE_EVENT(kvm_s390_handle_lctl,
+	    TP_PROTO(VCPU_PROTO_COMMON, int g, int reg1, int reg3, u64 addr),
+	    TP_ARGS(VCPU_ARGS_COMMON, g, reg1, reg3, addr),
+
+	    TP_STRUCT__entry(
+		    VCPU_FIELD_COMMON
+		    __field(int, g)
+		    __field(int, reg1)
+		    __field(int, reg3)
+		    __field(u64, addr)
+		    ),
+
+	    TP_fast_assign(
+		    VCPU_ASSIGN_COMMON
+		    __entry->g = g;
+		    __entry->reg1 = reg1;
+		    __entry->reg3 = reg3;
+		    __entry->addr = addr;
+		    ),
+
+	    VCPU_TP_PRINTK("%s: loading cr %x-%x from %016llx",
+			   __entry->g ? "lctlg" : "lctl",
+			   __entry->reg1, __entry->reg3, __entry->addr)
+	);
+
+TRACE_EVENT(kvm_s390_handle_prefix,
+	    TP_PROTO(VCPU_PROTO_COMMON, int set, u32 address),
+	    TP_ARGS(VCPU_ARGS_COMMON, set, address),
+
+	    TP_STRUCT__entry(
+		    VCPU_FIELD_COMMON
+		    __field(int, set)
+		    __field(u32, address)
+		    ),
+
+	    TP_fast_assign(
+		    VCPU_ASSIGN_COMMON
+		    __entry->set = set;
+		    __entry->address = address;
+		    ),
+
+	    VCPU_TP_PRINTK("%s prefix to %08x",
+			   __entry->set ? "setting" : "storing",
+			   __entry->address)
+	);
+
+TRACE_EVENT(kvm_s390_handle_stap,
+	    TP_PROTO(VCPU_PROTO_COMMON, u64 address),
+	    TP_ARGS(VCPU_ARGS_COMMON, address),
+
+	    TP_STRUCT__entry(
+		    VCPU_FIELD_COMMON
+		    __field(u64, address)
+		    ),
+
+	    TP_fast_assign(
+		    VCPU_ASSIGN_COMMON
+		    __entry->address = address;
+		    ),
+
+	    VCPU_TP_PRINTK("storing cpu address to %016llx",
+			   __entry->address)
+	);
+
+TRACE_EVENT(kvm_s390_handle_stfl,
+	    TP_PROTO(VCPU_PROTO_COMMON, unsigned int facility_list),
+	    TP_ARGS(VCPU_ARGS_COMMON, facility_list),
+
+	    TP_STRUCT__entry(
+		    VCPU_FIELD_COMMON
+		    __field(unsigned int, facility_list)
+		    ),
+
+	    TP_fast_assign(
+		    VCPU_ASSIGN_COMMON
+		    __entry->facility_list = facility_list;
+		    ),
+
+	    VCPU_TP_PRINTK("store facility list value %08x",
+			   __entry->facility_list)
+	);
+
+TRACE_EVENT(kvm_s390_handle_stsi,
+	    TP_PROTO(VCPU_PROTO_COMMON, int fc, int sel1, int sel2, u64 addr),
+	    TP_ARGS(VCPU_ARGS_COMMON, fc, sel1, sel2, addr),
+
+	    TP_STRUCT__entry(
+		    VCPU_FIELD_COMMON
+		    __field(int, fc)
+		    __field(int, sel1)
+		    __field(int, sel2)
+		    __field(u64, addr)
+		    ),
+
+	    TP_fast_assign(
+		    VCPU_ASSIGN_COMMON
+		    __entry->fc = fc;
+		    __entry->sel1 = sel1;
+		    __entry->sel2 = sel2;
+		    __entry->addr = addr;
+		    ),
+
+	    VCPU_TP_PRINTK("STSI %d.%d.%d information stored to %016llx",
+			   __entry->fc, __entry->sel1, __entry->sel2,
+			   __entry->addr)
+	);
+
+#endif /* _TRACE_KVM_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/arch/s390/net/Makefile b/arch/s390/net/Makefile
new file mode 100644
index 0000000..90568c3
--- /dev/null
+++ b/arch/s390/net/Makefile
@@ -0,0 +1,4 @@
+#
+# Arch-specific network modules
+#
+obj-$(CONFIG_BPF_JIT) += bpf_jit.o bpf_jit_comp.o
diff --git a/arch/s390/net/bpf_jit.S b/arch/s390/net/bpf_jit.S
new file mode 100644
index 0000000..d3fee59
--- /dev/null
+++ b/arch/s390/net/bpf_jit.S
@@ -0,0 +1,130 @@
+/*
+ * BPF Jit compiler for s390, help functions.
+ *
+ * Copyright IBM Corp. 2012
+ *
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+#include <linux/linkage.h>
+
+/*
+ * Calling convention:
+ * registers %r2, %r3, %r6-%r15 are call saved
+ *   %r2: skb pointer
+ *   %r3: offset parameter
+ *   %r5: result in BPF A accumulator
+ *   %r8: return address
+ *   %r9: save register for skb pointer
+ *   %r10: skb->data
+ *   %r11: skb->len - skb->data_len (headlen)
+ *   %r12: BPF X accumulator
+ *
+ * skb_copy_bits takes 4 parameters:
+ *   %r2 = skb pointer
+ *   %r3 = offset into skb data
+ *   %r4 = length to copy
+ *   %r5 = pointer to temp buffer
+ */
+#define SKBDATA	%r8
+
+	/* A = *(u32 *) (skb->data+K+X) */
+ENTRY(sk_load_word_ind)
+	ar	%r3,%r12		# offset += X
+	bmr	%r8			# < 0 -> return with cc
+
+	/* A = *(u32 *) (skb->data+K) */
+ENTRY(sk_load_word)
+	llgfr	%r1,%r3			# extend offset
+	ahi	%r3,4			# offset + 4
+	clr	%r11,%r3		# hlen <= offset + 4 ?
+	jl	sk_load_word_slow
+	l	%r5,0(%r1,%r10)		# get word from skb
+	xr	%r1,%r1			# set cc to zero
+	br	%r8
+
+sk_load_word_slow:
+	lgr	%r9,%r2			# save %r2
+	lhi	%r4,4			# 4 bytes
+	la	%r5,160(%r15)		# pointer to temp buffer
+	brasl	%r14,skb_copy_bits	# get data from skb
+	l	%r5,160(%r15)		# load result from temp buffer
+	ltgr	%r2,%r2			# set cc to (%r2 != 0)
+	lgr	%r2,%r9			# restore %r2
+	br	%r8
+
+	/* A = *(u16 *) (skb->data+K+X) */
+ENTRY(sk_load_half_ind)
+	ar	%r3,%r12		# offset += X
+	bmr	%r8			# < 0 -> return with cc
+
+	/* A = *(u16 *) (skb->data+K) */
+ENTRY(sk_load_half)
+	llgfr	%r1,%r3			# extend offset
+	ahi	%r3,2			# offset + 2
+	clr	%r11,%r3		# hlen <= offset + 2 ?
+	jl	sk_load_half_slow
+	llgh	%r5,0(%r1,%r10)		# get half from skb
+	xr	%r1,%r1			# set cc to zero
+	br	%r8
+
+sk_load_half_slow:
+	lgr	%r9,%r2			# save %r2
+	lhi	%r4,2			# 2 bytes
+	la	%r5,162(%r15)		# pointer to temp buffer
+	brasl	%r14,skb_copy_bits	# get data from skb
+	xc	160(2,%r15),160(%r15)
+	l	%r5,160(%r15)		# load result from temp buffer
+	ltgr	%r2,%r2			# set cc to (%r2 != 0)
+	lgr	%r2,%r9			# restore %r2
+	br	%r8
+
+	/* A = *(u8 *) (skb->data+K+X) */
+ENTRY(sk_load_byte_ind)
+	ar	%r3,%r12		# offset += X
+	bmr	%r8			# < 0 -> return with cc
+
+	/* A = *(u8 *) (skb->data+K) */
+ENTRY(sk_load_byte)
+	llgfr	%r1,%r3			# extend offset
+	clr	%r11,%r3		# hlen < offset ?
+	jle	sk_load_byte_slow
+	lhi	%r5,0
+	ic	%r5,0(%r1,%r10)		# get byte from skb
+	xr	%r1,%r1			# set cc to zero
+	br	%r8
+
+sk_load_byte_slow:
+	lgr	%r9,%r2			# save %r2
+	lhi	%r4,1			# 1 bytes
+	la	%r5,163(%r15)		# pointer to temp buffer
+	brasl	%r14,skb_copy_bits	# get data from skb
+	xc	160(3,%r15),160(%r15)
+	l	%r5,160(%r15)		# load result from temp buffer
+	ltgr	%r2,%r2			# set cc to (%r2 != 0)
+	lgr	%r2,%r9			# restore %r2
+	br	%r8
+
+	/* A = (*(u8 *)(skb->data+K) & 0xf) << 2 */
+ENTRY(sk_load_byte_msh)
+	llgfr	%r1,%r3			# extend offset
+	clr	%r11,%r3		# hlen < offset ?
+	jle	sk_load_byte_slow
+	lhi	%r12,0
+	ic	%r12,0(%r1,%r10)	# get byte from skb
+	nill	%r12,0x0f
+	sll	%r12,2
+	xr	%r1,%r1			# set cc to zero
+	br	%r8
+
+sk_load_byte_msh_slow:
+	lgr	%r9,%r2			# save %r2
+	lhi	%r4,2			# 2 bytes
+	la	%r5,162(%r15)		# pointer to temp buffer
+	brasl	%r14,skb_copy_bits	# get data from skb
+	xc	160(3,%r15),160(%r15)
+	l	%r12,160(%r15)		# load result from temp buffer
+	nill	%r12,0x0f
+	sll	%r12,2
+	ltgr	%r2,%r2			# set cc to (%r2 != 0)
+	lgr	%r2,%r9			# restore %r2
+	br	%r8
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
new file mode 100644
index 0000000..b07aa3d
--- /dev/null
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -0,0 +1,738 @@
+/*
+ * BPF Jit compiler for s390.
+ *
+ * Copyright IBM Corp. 2012
+ *
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+#include <linux/moduleloader.h>
+#include <linux/netdevice.h>
+#include <linux/filter.h>
+#include <asm/cacheflush.h>
+#include <asm/processor.h>
+
+/*
+ * Conventions:
+ *   %r2 = skb pointer
+ *   %r3 = offset parameter
+ *   %r4 = scratch register / length parameter
+ *   %r5 = BPF A accumulator
+ *   %r8 = return address
+ *   %r9 = save register for skb pointer
+ *   %r10 = skb->data
+ *   %r11 = skb->len - skb->data_len (headlen)
+ *   %r12 = BPF X accumulator
+ *   %r13 = literal pool pointer
+ *   0(%r15) - 63(%r15) scratch memory array with BPF_MEMWORDS
+ */
+int bpf_jit_enable __read_mostly;
+
+/*
+ * assembly code in arch/x86/net/bpf_jit.S
+ */
+extern u8 sk_load_word[], sk_load_half[], sk_load_byte[], sk_load_byte_msh[];
+extern u8 sk_load_word_ind[], sk_load_half_ind[], sk_load_byte_ind[];
+
+struct bpf_jit {
+	unsigned int seen;
+	u8 *start;
+	u8 *prg;
+	u8 *mid;
+	u8 *lit;
+	u8 *end;
+	u8 *base_ip;
+	u8 *ret0_ip;
+	u8 *exit_ip;
+	unsigned int off_load_word;
+	unsigned int off_load_half;
+	unsigned int off_load_byte;
+	unsigned int off_load_bmsh;
+	unsigned int off_load_iword;
+	unsigned int off_load_ihalf;
+	unsigned int off_load_ibyte;
+};
+
+#define BPF_SIZE_MAX	4096	/* Max size for program */
+
+#define SEEN_DATAREF	1	/* might call external helpers */
+#define SEEN_XREG	2	/* ebx is used */
+#define SEEN_MEM	4	/* use mem[] for temporary storage */
+#define SEEN_RET0	8	/* pc_ret0 points to a valid return 0 */
+#define SEEN_LITERAL	16	/* code uses literals */
+#define SEEN_LOAD_WORD	32	/* code uses sk_load_word */
+#define SEEN_LOAD_HALF	64	/* code uses sk_load_half */
+#define SEEN_LOAD_BYTE	128	/* code uses sk_load_byte */
+#define SEEN_LOAD_BMSH	256	/* code uses sk_load_byte_msh */
+#define SEEN_LOAD_IWORD	512	/* code uses sk_load_word_ind */
+#define SEEN_LOAD_IHALF	1024	/* code uses sk_load_half_ind */
+#define SEEN_LOAD_IBYTE	2048	/* code uses sk_load_byte_ind */
+
+#define EMIT2(op)					\
+({							\
+	if (jit->prg + 2 <= jit->mid)			\
+		*(u16 *) jit->prg = op;			\
+	jit->prg += 2;					\
+})
+
+#define EMIT4(op)					\
+({							\
+	if (jit->prg + 4 <= jit->mid)			\
+		*(u32 *) jit->prg = op;			\
+	jit->prg += 4;					\
+})
+
+#define EMIT4_DISP(op, disp)				\
+({							\
+	unsigned int __disp = (disp) & 0xfff;		\
+	EMIT4(op | __disp);				\
+})
+
+#define EMIT4_IMM(op, imm)				\
+({							\
+	unsigned int __imm = (imm) & 0xffff;		\
+	EMIT4(op | __imm);				\
+})
+
+#define EMIT4_PCREL(op, pcrel)				\
+({							\
+	long __pcrel = ((pcrel) >> 1) & 0xffff;		\
+	EMIT4(op | __pcrel);				\
+})
+
+#define EMIT6(op1, op2)					\
+({							\
+	if (jit->prg + 6 <= jit->mid) {			\
+		*(u32 *) jit->prg = op1;		\
+		*(u16 *) (jit->prg + 4) = op2;		\
+	}						\
+	jit->prg += 6;					\
+})
+
+#define EMIT6_DISP(op1, op2, disp)			\
+({							\
+	unsigned int __disp = (disp) & 0xfff;		\
+	EMIT6(op1 | __disp, op2);			\
+})
+
+#define EMIT_CONST(val)					\
+({							\
+	unsigned int ret;				\
+	ret = (unsigned int) (jit->lit - jit->base_ip);	\
+	jit->seen |= SEEN_LITERAL;			\
+	if (jit->lit + 4 <= jit->end)			\
+		*(u32 *) jit->lit = val;		\
+	jit->lit += 4;					\
+	ret;						\
+})
+
+#define EMIT_FN_CONST(bit, fn)				\
+({							\
+	unsigned int ret;				\
+	ret = (unsigned int) (jit->lit - jit->base_ip);	\
+	if (jit->seen & bit) {				\
+		jit->seen |= SEEN_LITERAL;		\
+		if (jit->lit + 8 <= jit->end)		\
+			*(void **) jit->lit = fn;	\
+		jit->lit += 8;				\
+	}						\
+	ret;						\
+})
+
+static void bpf_jit_prologue(struct bpf_jit *jit)
+{
+	/* Save registers and create stack frame if necessary */
+	if (jit->seen & SEEN_DATAREF) {
+		/* stmg %r8,%r15,88(%r15) */
+		EMIT6(0xeb8ff058, 0x0024);
+		/* lgr %r14,%r15 */
+		EMIT4(0xb90400ef);
+		/* ahi %r15,<offset> */
+		EMIT4_IMM(0xa7fa0000, (jit->seen & SEEN_MEM) ? -112 : -80);
+		/* stg %r14,152(%r15) */
+		EMIT6(0xe3e0f098, 0x0024);
+	} else if ((jit->seen & SEEN_XREG) && (jit->seen & SEEN_LITERAL))
+		/* stmg %r12,%r13,120(%r15) */
+		EMIT6(0xebcdf078, 0x0024);
+	else if (jit->seen & SEEN_XREG)
+		/* stg %r12,120(%r15) */
+		EMIT6(0xe3c0f078, 0x0024);
+	else if (jit->seen & SEEN_LITERAL)
+		/* stg %r13,128(%r15) */
+		EMIT6(0xe3d0f080, 0x0024);
+
+	/* Setup literal pool */
+	if (jit->seen & SEEN_LITERAL) {
+		/* basr %r13,0 */
+		EMIT2(0x0dd0);
+		jit->base_ip = jit->prg;
+	}
+	jit->off_load_word = EMIT_FN_CONST(SEEN_LOAD_WORD, sk_load_word);
+	jit->off_load_half = EMIT_FN_CONST(SEEN_LOAD_HALF, sk_load_half);
+	jit->off_load_byte = EMIT_FN_CONST(SEEN_LOAD_BYTE, sk_load_byte);
+	jit->off_load_bmsh = EMIT_FN_CONST(SEEN_LOAD_BMSH, sk_load_byte_msh);
+	jit->off_load_iword = EMIT_FN_CONST(SEEN_LOAD_IWORD, sk_load_word_ind);
+	jit->off_load_ihalf = EMIT_FN_CONST(SEEN_LOAD_IHALF, sk_load_half_ind);
+	jit->off_load_ibyte = EMIT_FN_CONST(SEEN_LOAD_IBYTE, sk_load_byte_ind);
+
+	/* Filter needs to access skb data */
+	if (jit->seen & SEEN_DATAREF) {
+		/* l %r11,<len>(%r2) */
+		EMIT4_DISP(0x58b02000, offsetof(struct sk_buff, len));
+		/* s %r11,<data_len>(%r2) */
+		EMIT4_DISP(0x5bb02000, offsetof(struct sk_buff, data_len));
+		/* lg %r10,<data>(%r2) */
+		EMIT6_DISP(0xe3a02000, 0x0004,
+			   offsetof(struct sk_buff, data));
+	}
+}
+
+static void bpf_jit_epilogue(struct bpf_jit *jit)
+{
+	/* Return 0 */
+	if (jit->seen & SEEN_RET0) {
+		jit->ret0_ip = jit->prg;
+		/* lghi %r2,0 */
+		EMIT4(0xa7290000);
+	}
+	jit->exit_ip = jit->prg;
+	/* Restore registers */
+	if (jit->seen & SEEN_DATAREF)
+		/* lmg %r8,%r15,<offset>(%r15) */
+		EMIT6_DISP(0xeb8ff000, 0x0004,
+			   (jit->seen & SEEN_MEM) ? 200 : 168);
+	else if ((jit->seen & SEEN_XREG) && (jit->seen & SEEN_LITERAL))
+		/* lmg %r12,%r13,120(%r15) */
+		EMIT6(0xebcdf078, 0x0004);
+	else if (jit->seen & SEEN_XREG)
+		/* lg %r12,120(%r15) */
+		EMIT6(0xe3c0f078, 0x0004);
+	else if (jit->seen & SEEN_LITERAL)
+		/* lg %r13,128(%r15) */
+		EMIT6(0xe3d0f080, 0x0004);
+	/* br %r14 */
+	EMIT2(0x07fe);
+}
+
+/*
+ * make sure we dont leak kernel information to user
+ */
+static void bpf_jit_noleaks(struct bpf_jit *jit, struct sock_filter *filter)
+{
+	/* Clear temporary memory if (seen & SEEN_MEM) */
+	if (jit->seen & SEEN_MEM)
+		/* xc 0(64,%r15),0(%r15) */
+		EMIT6(0xd73ff000, 0xf000);
+	/* Clear X if (seen & SEEN_XREG) */
+	if (jit->seen & SEEN_XREG)
+		/* lhi %r12,0 */
+		EMIT4(0xa7c80000);
+	/* Clear A if the first register does not set it. */
+	switch (filter[0].code) {
+	case BPF_S_LD_W_ABS:
+	case BPF_S_LD_H_ABS:
+	case BPF_S_LD_B_ABS:
+	case BPF_S_LD_W_LEN:
+	case BPF_S_LD_W_IND:
+	case BPF_S_LD_H_IND:
+	case BPF_S_LD_B_IND:
+	case BPF_S_LDX_B_MSH:
+	case BPF_S_LD_IMM:
+	case BPF_S_LD_MEM:
+	case BPF_S_MISC_TXA:
+	case BPF_S_ANC_PROTOCOL:
+	case BPF_S_ANC_PKTTYPE:
+	case BPF_S_ANC_IFINDEX:
+	case BPF_S_ANC_MARK:
+	case BPF_S_ANC_QUEUE:
+	case BPF_S_ANC_HATYPE:
+	case BPF_S_ANC_RXHASH:
+	case BPF_S_ANC_CPU:
+	case BPF_S_RET_K:
+		/* first instruction sets A register */
+		break;
+	default: /* A = 0 */
+		/* lhi %r5,0 */
+		EMIT4(0xa7580000);
+	}
+}
+
+static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter,
+			unsigned int *addrs, int i, int last)
+{
+	unsigned int K;
+	int offset;
+	unsigned int mask;
+
+	K = filter->k;
+	switch (filter->code) {
+	case BPF_S_ALU_ADD_X: /* A += X */
+		jit->seen |= SEEN_XREG;
+		/* ar %r5,%r12 */
+		EMIT2(0x1a5c);
+		break;
+	case BPF_S_ALU_ADD_K: /* A += K */
+		if (!K)
+			break;
+		if (K <= 16383)
+			/* ahi %r5,<K> */
+			EMIT4_IMM(0xa75a0000, K);
+		else
+			/* a %r5,<d(K)>(%r13) */
+			EMIT4_DISP(0x5a50d000, EMIT_CONST(K));
+		break;
+	case BPF_S_ALU_SUB_X: /* A -= X */
+		jit->seen |= SEEN_XREG;
+		/* sr %r5,%r12 */
+		EMIT2(0x1b5c);
+		break;
+	case BPF_S_ALU_SUB_K: /* A -= K */
+		if (!K)
+			break;
+		if (K <= 16384)
+			/* ahi %r5,-K */
+			EMIT4_IMM(0xa75a0000, -K);
+		else
+			/* s %r5,<d(K)>(%r13) */
+			EMIT4_DISP(0x5b50d000, EMIT_CONST(K));
+		break;
+	case BPF_S_ALU_MUL_X: /* A *= X */
+		jit->seen |= SEEN_XREG;
+		/* msr %r5,%r12 */
+		EMIT4(0xb252005c);
+		break;
+	case BPF_S_ALU_MUL_K: /* A *= K */
+		if (K <= 16383)
+			/* mhi %r5,K */
+			EMIT4_IMM(0xa75c0000, K);
+		else
+			/* ms %r5,<d(K)>(%r13) */
+			EMIT4_DISP(0x7150d000, EMIT_CONST(K));
+		break;
+	case BPF_S_ALU_DIV_X: /* A /= X */
+		jit->seen |= SEEN_XREG | SEEN_RET0;
+		/* ltr %r12,%r12 */
+		EMIT2(0x12cc);
+		/* jz <ret0> */
+		EMIT4_PCREL(0xa7840000, (jit->ret0_ip - jit->prg));
+		/* lhi %r4,0 */
+		EMIT4(0xa7480000);
+		/* dr %r4,%r12 */
+		EMIT2(0x1d4c);
+		break;
+	case BPF_S_ALU_DIV_K: /* A = reciprocal_divide(A, K) */
+		/* m %r4,<d(K)>(%r13) */
+		EMIT4_DISP(0x5c40d000, EMIT_CONST(K));
+		/* lr %r5,%r4 */
+		EMIT2(0x1854);
+		break;
+	case BPF_S_ALU_AND_X: /* A &= X */
+		jit->seen |= SEEN_XREG;
+		/* nr %r5,%r12 */
+		EMIT2(0x145c);
+		break;
+	case BPF_S_ALU_AND_K: /* A &= K */
+		/* n %r5,<d(K)>(%r13) */
+		EMIT4_DISP(0x5450d000, EMIT_CONST(K));
+		break;
+	case BPF_S_ALU_OR_X: /* A |= X */
+		jit->seen |= SEEN_XREG;
+		/* or %r5,%r12 */
+		EMIT2(0x165c);
+		break;
+	case BPF_S_ALU_OR_K: /* A |= K */
+		/* o %r5,<d(K)>(%r13) */
+		EMIT4_DISP(0x5650d000, EMIT_CONST(K));
+		break;
+	case BPF_S_ALU_LSH_X: /* A <<= X; */
+		jit->seen |= SEEN_XREG;
+		/* sll %r5,0(%r12) */
+		EMIT4(0x8950c000);
+		break;
+	case BPF_S_ALU_LSH_K: /* A <<= K */
+		if (K == 0)
+			break;
+		/* sll %r5,K */
+		EMIT4_DISP(0x89500000, K);
+		break;
+	case BPF_S_ALU_RSH_X: /* A >>= X; */
+		jit->seen |= SEEN_XREG;
+		/* srl %r5,0(%r12) */
+		EMIT4(0x8850c000);
+		break;
+	case BPF_S_ALU_RSH_K: /* A >>= K; */
+		if (K == 0)
+			break;
+		/* srl %r5,K */
+		EMIT4_DISP(0x88500000, K);
+		break;
+	case BPF_S_ALU_NEG: /* A = -A */
+		/* lnr %r5,%r5 */
+		EMIT2(0x1155);
+		break;
+	case BPF_S_JMP_JA: /* ip += K */
+		offset = addrs[i + K] + jit->start - jit->prg;
+		EMIT4_PCREL(0xa7f40000, offset);
+		break;
+	case BPF_S_JMP_JGT_K: /* ip += (A > K) ? jt : jf */
+		mask = 0x200000; /* jh */
+		goto kbranch;
+	case BPF_S_JMP_JGE_K: /* ip += (A >= K) ? jt : jf */
+		mask = 0xa00000; /* jhe */
+		goto kbranch;
+	case BPF_S_JMP_JEQ_K: /* ip += (A == K) ? jt : jf */
+		mask = 0x800000; /* je */
+kbranch:	/* Emit compare if the branch targets are different */
+		if (filter->jt != filter->jf) {
+			if (K <= 16383)
+				/* chi %r5,<K> */
+				EMIT4_IMM(0xa75e0000, K);
+			else
+				/* c %r5,<d(K)>(%r13) */
+				EMIT4_DISP(0x5950d000, EMIT_CONST(K));
+		}
+branch:		if (filter->jt == filter->jf) {
+			if (filter->jt == 0)
+				break;
+			/* j <jt> */
+			offset = addrs[i + filter->jt] + jit->start - jit->prg;
+			EMIT4_PCREL(0xa7f40000, offset);
+			break;
+		}
+		if (filter->jt != 0) {
+			/* brc	<mask>,<jt> */
+			offset = addrs[i + filter->jt] + jit->start - jit->prg;
+			EMIT4_PCREL(0xa7040000 | mask, offset);
+		}
+		if (filter->jf != 0) {
+			/* brc	<mask^15>,<jf> */
+			offset = addrs[i + filter->jf] + jit->start - jit->prg;
+			EMIT4_PCREL(0xa7040000 | (mask ^ 0xf00000), offset);
+		}
+		break;
+	case BPF_S_JMP_JSET_K: /* ip += (A & K) ? jt : jf */
+		mask = 0x700000; /* jnz */
+		/* Emit test if the branch targets are different */
+		if (filter->jt != filter->jf) {
+			if (K > 65535) {
+				/* lr %r4,%r5 */
+				EMIT2(0x1845);
+				/* n %r4,<d(K)>(%r13) */
+				EMIT4_DISP(0x5440d000, EMIT_CONST(K));
+			} else
+				/* tmll %r5,K */
+				EMIT4_IMM(0xa7510000, K);
+		}
+		goto branch;
+	case BPF_S_JMP_JGT_X: /* ip += (A > X) ? jt : jf */
+		mask = 0x200000; /* jh */
+		goto xbranch;
+	case BPF_S_JMP_JGE_X: /* ip += (A >= X) ? jt : jf */
+		mask = 0xa00000; /* jhe */
+		goto xbranch;
+	case BPF_S_JMP_JEQ_X: /* ip += (A == X) ? jt : jf */
+		mask = 0x800000; /* je */
+xbranch:	/* Emit compare if the branch targets are different */
+		if (filter->jt != filter->jf) {
+			jit->seen |= SEEN_XREG;
+			/* cr %r5,%r12 */
+			EMIT2(0x195c);
+		}
+		goto branch;
+	case BPF_S_JMP_JSET_X: /* ip += (A & X) ? jt : jf */
+		mask = 0x700000; /* jnz */
+		/* Emit test if the branch targets are different */
+		if (filter->jt != filter->jf) {
+			jit->seen |= SEEN_XREG;
+			/* lr %r4,%r5 */
+			EMIT2(0x1845);
+			/* nr %r4,%r12 */
+			EMIT2(0x144c);
+		}
+		goto branch;
+	case BPF_S_LD_W_ABS: /* A = *(u32 *) (skb->data+K) */
+		jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_WORD;
+		offset = jit->off_load_word;
+		goto load_abs;
+	case BPF_S_LD_H_ABS: /* A = *(u16 *) (skb->data+K) */
+		jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_HALF;
+		offset = jit->off_load_half;
+		goto load_abs;
+	case BPF_S_LD_B_ABS: /* A = *(u8 *) (skb->data+K) */
+		jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_BYTE;
+		offset = jit->off_load_byte;
+load_abs:	if ((int) K < 0)
+			goto out;
+call_fn:	/* lg %r1,<d(function)>(%r13) */
+		EMIT6_DISP(0xe310d000, 0x0004, offset);
+		/* l %r3,<d(K)>(%r13) */
+		EMIT4_DISP(0x5830d000, EMIT_CONST(K));
+		/* basr %r8,%r1 */
+		EMIT2(0x0d81);
+		/* jnz <ret0> */
+		EMIT4_PCREL(0xa7740000, (jit->ret0_ip - jit->prg));
+		break;
+	case BPF_S_LD_W_IND: /* A = *(u32 *) (skb->data+K+X) */
+		jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_IWORD;
+		offset = jit->off_load_iword;
+		goto call_fn;
+	case BPF_S_LD_H_IND: /* A = *(u16 *) (skb->data+K+X) */
+		jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_IHALF;
+		offset = jit->off_load_ihalf;
+		goto call_fn;
+	case BPF_S_LD_B_IND: /* A = *(u8 *) (skb->data+K+X) */
+		jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_IBYTE;
+		offset = jit->off_load_ibyte;
+		goto call_fn;
+	case BPF_S_LDX_B_MSH:
+		/* X = (*(u8 *)(skb->data+K) & 0xf) << 2 */
+		jit->seen |= SEEN_RET0;
+		if ((int) K < 0) {
+			/* j <ret0> */
+			EMIT4_PCREL(0xa7f40000, (jit->ret0_ip - jit->prg));
+			break;
+		}
+		jit->seen |= SEEN_DATAREF | SEEN_LOAD_BMSH;
+		offset = jit->off_load_bmsh;
+		goto call_fn;
+	case BPF_S_LD_W_LEN: /*	A = skb->len; */
+		BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
+		/* l %r5,<d(len)>(%r2) */
+		EMIT4_DISP(0x58502000, offsetof(struct sk_buff, len));
+		break;
+	case BPF_S_LDX_W_LEN: /* X = skb->len; */
+		jit->seen |= SEEN_XREG;
+		/* l %r12,<d(len)>(%r2) */
+		EMIT4_DISP(0x58c02000, offsetof(struct sk_buff, len));
+		break;
+	case BPF_S_LD_IMM: /* A = K */
+		if (K <= 16383)
+			/* lhi %r5,K */
+			EMIT4_IMM(0xa7580000, K);
+		else
+			/* l %r5,<d(K)>(%r13) */
+			EMIT4_DISP(0x5850d000, EMIT_CONST(K));
+		break;
+	case BPF_S_LDX_IMM: /* X = K */
+		jit->seen |= SEEN_XREG;
+		if (K <= 16383)
+			/* lhi %r12,<K> */
+			EMIT4_IMM(0xa7c80000, K);
+		else
+			/* l %r12,<d(K)>(%r13) */
+			EMIT4_DISP(0x58c0d000, EMIT_CONST(K));
+		break;
+	case BPF_S_LD_MEM: /* A = mem[K] */
+		jit->seen |= SEEN_MEM;
+		/* l %r5,<K>(%r15) */
+		EMIT4_DISP(0x5850f000,
+			   (jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4);
+		break;
+	case BPF_S_LDX_MEM: /* X = mem[K] */
+		jit->seen |= SEEN_XREG | SEEN_MEM;
+		/* l %r12,<K>(%r15) */
+		EMIT4_DISP(0x58c0f000,
+			   (jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4);
+		break;
+	case BPF_S_MISC_TAX: /* X = A */
+		jit->seen |= SEEN_XREG;
+		/* lr %r12,%r5 */
+		EMIT2(0x18c5);
+		break;
+	case BPF_S_MISC_TXA: /* A = X */
+		jit->seen |= SEEN_XREG;
+		/* lr %r5,%r12 */
+		EMIT2(0x185c);
+		break;
+	case BPF_S_RET_K:
+		if (K == 0) {
+			jit->seen |= SEEN_RET0;
+			if (last)
+				break;
+			/* j <ret0> */
+			EMIT4_PCREL(0xa7f40000, jit->ret0_ip - jit->prg);
+		} else {
+			if (K <= 16383)
+				/* lghi %r2,K */
+				EMIT4_IMM(0xa7290000, K);
+			else
+				/* llgf %r2,<K>(%r13) */
+				EMIT6_DISP(0xe320d000, 0x0016, EMIT_CONST(K));
+			/* j <exit> */
+			if (last && !(jit->seen & SEEN_RET0))
+				break;
+			EMIT4_PCREL(0xa7f40000, jit->exit_ip - jit->prg);
+		}
+		break;
+	case BPF_S_RET_A:
+		/* llgfr %r2,%r5 */
+		EMIT4(0xb9160025);
+		/* j <exit> */
+		EMIT4_PCREL(0xa7f40000, jit->exit_ip - jit->prg);
+		break;
+	case BPF_S_ST: /* mem[K] = A */
+		jit->seen |= SEEN_MEM;
+		/* st %r5,<K>(%r15) */
+		EMIT4_DISP(0x5050f000,
+			   (jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4);
+		break;
+	case BPF_S_STX: /* mem[K] = X : mov %ebx,off8(%rbp) */
+		jit->seen |= SEEN_XREG | SEEN_MEM;
+		/* st %r12,<K>(%r15) */
+		EMIT4_DISP(0x50c0f000,
+			   (jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4);
+		break;
+	case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */
+		BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2);
+		/* lhi %r5,0 */
+		EMIT4(0xa7580000);
+		/* icm	%r5,3,<d(protocol)>(%r2) */
+		EMIT4_DISP(0xbf532000, offsetof(struct sk_buff, protocol));
+		break;
+	case BPF_S_ANC_IFINDEX:	/* if (!skb->dev) return 0;
+				 * A = skb->dev->ifindex */
+		BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4);
+		jit->seen |= SEEN_RET0;
+		/* lg %r1,<d(dev)>(%r2) */
+		EMIT6_DISP(0xe3102000, 0x0004, offsetof(struct sk_buff, dev));
+		/* ltgr %r1,%r1 */
+		EMIT4(0xb9020011);
+		/* jz <ret0> */
+		EMIT4_PCREL(0xa7840000, jit->ret0_ip - jit->prg);
+		/* l %r5,<d(ifindex)>(%r1) */
+		EMIT4_DISP(0x58501000, offsetof(struct net_device, ifindex));
+		break;
+	case BPF_S_ANC_MARK: /* A = skb->mark */
+		BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
+		/* l %r5,<d(mark)>(%r2) */
+		EMIT4_DISP(0x58502000, offsetof(struct sk_buff, mark));
+		break;
+	case BPF_S_ANC_QUEUE: /* A = skb->queue_mapping */
+		BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, queue_mapping) != 2);
+		/* lhi %r5,0 */
+		EMIT4(0xa7580000);
+		/* icm	%r5,3,<d(queue_mapping)>(%r2) */
+		EMIT4_DISP(0xbf532000, offsetof(struct sk_buff, queue_mapping));
+		break;
+	case BPF_S_ANC_HATYPE:	/* if (!skb->dev) return 0;
+				 * A = skb->dev->type */
+		BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, type) != 2);
+		jit->seen |= SEEN_RET0;
+		/* lg %r1,<d(dev)>(%r2) */
+		EMIT6_DISP(0xe3102000, 0x0004, offsetof(struct sk_buff, dev));
+		/* ltgr %r1,%r1 */
+		EMIT4(0xb9020011);
+		/* jz <ret0> */
+		EMIT4_PCREL(0xa7840000, jit->ret0_ip - jit->prg);
+		/* lhi %r5,0 */
+		EMIT4(0xa7580000);
+		/* icm	%r5,3,<d(type)>(%r1) */
+		EMIT4_DISP(0xbf531000, offsetof(struct net_device, type));
+		break;
+	case BPF_S_ANC_RXHASH: /* A = skb->rxhash */
+		BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
+		/* l %r5,<d(rxhash)>(%r2) */
+		EMIT4_DISP(0x58502000, offsetof(struct sk_buff, rxhash));
+		break;
+	case BPF_S_ANC_CPU: /* A = smp_processor_id() */
+#ifdef CONFIG_SMP
+		/* l %r5,<d(cpu_nr)> */
+		EMIT4_DISP(0x58500000, offsetof(struct _lowcore, cpu_nr));
+#else
+		/* lhi %r5,0 */
+		EMIT4(0xa7580000);
+#endif
+		break;
+	default: /* too complex, give up */
+		goto out;
+	}
+	addrs[i] = jit->prg - jit->start;
+	return 0;
+out:
+	return -1;
+}
+
+void bpf_jit_compile(struct sk_filter *fp)
+{
+	unsigned long size, prg_len, lit_len;
+	struct bpf_jit jit, cjit;
+	unsigned int *addrs;
+	int pass, i;
+
+	if (!bpf_jit_enable)
+		return;
+	addrs = kmalloc(fp->len * sizeof(*addrs), GFP_KERNEL);
+	if (addrs == NULL)
+		return;
+	memset(addrs, 0, fp->len * sizeof(*addrs));
+	memset(&jit, 0, sizeof(cjit));
+	memset(&cjit, 0, sizeof(cjit));
+
+	for (pass = 0; pass < 10; pass++) {
+		jit.prg = jit.start;
+		jit.lit = jit.mid;
+
+		bpf_jit_prologue(&jit);
+		bpf_jit_noleaks(&jit, fp->insns);
+		for (i = 0; i < fp->len; i++) {
+			if (bpf_jit_insn(&jit, fp->insns + i, addrs, i,
+					 i == fp->len - 1))
+				goto out;
+		}
+		bpf_jit_epilogue(&jit);
+		if (jit.start) {
+			WARN_ON(jit.prg > cjit.prg || jit.lit > cjit.lit);
+			if (memcmp(&jit, &cjit, sizeof(jit)) == 0)
+				break;
+		} else if (jit.prg == cjit.prg && jit.lit == cjit.lit) {
+			prg_len = jit.prg - jit.start;
+			lit_len = jit.lit - jit.mid;
+			size = max_t(unsigned long, prg_len + lit_len,
+				     sizeof(struct work_struct));
+			if (size >= BPF_SIZE_MAX)
+				goto out;
+			jit.start = module_alloc(size);
+			if (!jit.start)
+				goto out;
+			jit.prg = jit.mid = jit.start + prg_len;
+			jit.lit = jit.end = jit.start + prg_len + lit_len;
+			jit.base_ip += (unsigned long) jit.start;
+			jit.exit_ip += (unsigned long) jit.start;
+			jit.ret0_ip += (unsigned long) jit.start;
+		}
+		cjit = jit;
+	}
+	if (bpf_jit_enable > 1) {
+		pr_err("flen=%d proglen=%lu pass=%d image=%p\n",
+		       fp->len, jit.end - jit.start, pass, jit.start);
+		if (jit.start) {
+			printk(KERN_ERR "JIT code:\n");
+			print_fn_code(jit.start, jit.mid - jit.start);
+			print_hex_dump(KERN_ERR, "JIT literals:\n",
+				       DUMP_PREFIX_ADDRESS, 16, 1,
+				       jit.mid, jit.end - jit.mid, false);
+		}
+	}
+	if (jit.start)
+		fp->bpf_func = (void *) jit.start;
+out:
+	kfree(addrs);
+}
+
+static void jit_free_defer(struct work_struct *arg)
+{
+	module_free(NULL, arg);
+}
+
+/* run from softirq, we must use a work_struct to call
+ * module_free() from process context
+ */
+void bpf_jit_free(struct sk_filter *fp)
+{
+	struct work_struct *work;
+
+	if (fp->bpf_func == sk_run_filter)
+		return;
+	work = (struct work_struct *)fp->bpf_func;
+	INIT_WORK(work, jit_free_defer);
+	schedule_work(work);
+}
diff --git a/arch/score/Kconfig b/arch/score/Kconfig
index ba0f412..e2c8db4 100644
--- a/arch/score/Kconfig
+++ b/arch/score/Kconfig
@@ -10,6 +10,8 @@ config SCORE
        select ARCH_DISCARD_MEMBLOCK
        select GENERIC_CPU_DEVICES
        select GENERIC_CLOCKEVENTS
+       select HAVE_MOD_ARCH_SPECIFIC
+	select MODULES_USE_ELF_REL
 
 choice
 	prompt "System type"
diff --git a/arch/score/include/asm/module.h b/arch/score/include/asm/module.h
index f0b5dc0..abf395b 100644
--- a/arch/score/include/asm/module.h
+++ b/arch/score/include/asm/module.h
@@ -3,6 +3,7 @@
 
 #include <linux/list.h>
 #include <asm/uaccess.h>
+#include <asm-generic/module.h>
 
 struct mod_arch_specific {
 	/* Data Bus Error exception tables */
@@ -13,11 +14,6 @@ struct mod_arch_specific {
 
 typedef uint8_t Elf64_Byte;		/* Type for a 8-bit quantity. */
 
-#define Elf_Shdr	Elf32_Shdr
-#define Elf_Sym		Elf32_Sym
-#define Elf_Ehdr	Elf32_Ehdr
-#define Elf_Addr	Elf32_Addr
-
 /* Given an address, look for it in the exception tables. */
 #ifdef CONFIG_MODULES
 const struct exception_table_entry *search_module_dbetables(unsigned long addr);
diff --git a/arch/score/include/asm/thread_info.h b/arch/score/include/asm/thread_info.h
index a18006e9..1425cc0 100644
--- a/arch/score/include/asm/thread_info.h
+++ b/arch/score/include/asm/thread_info.h
@@ -86,16 +86,12 @@ register struct thread_info *__current_thread_info __asm__("r28");
 #define TIF_NEED_RESCHED	2	/* rescheduling necessary */
 #define TIF_NOTIFY_RESUME	5	/* callback before returning to user */
 #define TIF_RESTORE_SIGMASK	9	/* restore signal mask in do_signal() */
-#define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling
-						 TIF_NEED_RESCHED */
 #define TIF_MEMDIE		18	/* is terminating due to OOM killer */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
 #define _TIF_WORK_MASK		(0x0000ffff)
 
diff --git a/arch/score/kernel/module.c b/arch/score/kernel/module.c
index 469e3b6..1378d99 100644
--- a/arch/score/kernel/module.c
+++ b/arch/score/kernel/module.c
@@ -125,16 +125,6 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
 	return 0;
 }
 
-int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
-		unsigned int symindex, unsigned int relsec,
-		struct module *me)
-{
-	/* Non-standard return value... most other arch's return -ENOEXEC
-	 * for an unsupported relocation variant
-	 */
-	return 0;
-}
-
 /* Given an address, look for it in the module exception tables. */
 const struct exception_table_entry *search_module_dbetables(unsigned long addr)
 {
diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c
index e382c52..c268bbf 100644
--- a/arch/score/kernel/signal.c
+++ b/arch/score/kernel/signal.c
@@ -174,6 +174,7 @@ score_rt_sigreturn(struct pt_regs *regs)
 	/* It is more difficult to avoid calling this function than to
 	   call it and ignore errors.  */
 	do_sigaltstack((stack_t __user *)&st, NULL, regs->regs[0]);
+	regs->is_syscall = 0;
 
 	__asm__ __volatile__(
 		"mv\tr0, %0\n\t"
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 36f5141..656329a 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -35,6 +35,8 @@ config SUPERH
 	select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST
 	select GENERIC_STRNCPY_FROM_USER
 	select GENERIC_STRNLEN_USER
+	select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER
+	select MODULES_USE_ELF_RELA
 	help
 	  The SuperH is a RISC processor targeted for use in embedded systems
 	  and consumer electronics; it was also used in the Sega Dreamcast
diff --git a/arch/sh/include/asm/module.h b/arch/sh/include/asm/module.h
index b7927de..81300d8b 100644
--- a/arch/sh/include/asm/module.h
+++ b/arch/sh/include/asm/module.h
@@ -1,21 +1,13 @@
 #ifndef _ASM_SH_MODULE_H
 #define _ASM_SH_MODULE_H
 
-struct mod_arch_specific {
+#include <asm-generic/module.h>
+
 #ifdef CONFIG_DWARF_UNWINDER
+struct mod_arch_specific {
 	struct list_head fde_list;
 	struct list_head cie_list;
-#endif
 };
-
-#ifdef CONFIG_64BIT
-#define Elf_Shdr Elf64_Shdr
-#define Elf_Sym Elf64_Sym
-#define Elf_Ehdr Elf64_Ehdr
-#else
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
 #endif
 
 #ifdef CONFIG_CPU_LITTLE_ENDIAN
diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h
index bc13b57..7d5ac4e 100644
--- a/arch/sh/include/asm/thread_info.h
+++ b/arch/sh/include/asm/thread_info.h
@@ -206,6 +206,9 @@ static inline bool test_and_clear_restore_sigmask(void)
 	ti->status &= ~TS_RESTORE_SIGMASK;
 	return true;
 }
+
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
 #endif	/* !__ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S
index b7cf6a5..0170508 100644
--- a/arch/sh/kernel/cpu/sh5/entry.S
+++ b/arch/sh/kernel/cpu/sh5/entry.S
@@ -933,7 +933,7 @@ ret_with_reschedule:
 
 	pta	restore_all, tr1
 
-	movi	_TIF_SIGPENDING, r8
+	movi	_TIF_SIGPENDING|_TIF_NOTIFY_RESUME, r8
 	and	r8, r7, r8
 	pta	work_notifysig, tr0
 	bne	r8, ZERO, tr0
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index f67601c..f4a7a05 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -139,7 +139,7 @@ work_pending:
 	! r8: current_thread_info
 	! t:  result of "tst	#_TIF_NEED_RESCHED, r0"
 	bf/s	work_resched
-	 tst	#_TIF_SIGPENDING, r0
+	 tst	#_TIF_SIGPENDING|_TIF_NOTIFY_RESUME, r0
 work_notifysig:
 	bt/s	__restore_all
 	 mov	r15, r4
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c
index d6b7b61..2f1f653 100644
--- a/arch/sh/kernel/signal_32.c
+++ b/arch/sh/kernel/signal_32.c
@@ -22,7 +22,6 @@
 #include <linux/elf.h>
 #include <linux/personality.h>
 #include <linux/binfmts.h>
-#include <linux/freezer.h>
 #include <linux/io.h>
 #include <linux/tracehook.h>
 #include <asm/ucontext.h>
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c
index 6b5b3df..2385381 100644
--- a/arch/sh/kernel/signal_64.c
+++ b/arch/sh/kernel/signal_64.c
@@ -18,7 +18,6 @@
 #include <linux/errno.h>
 #include <linux/wait.h>
 #include <linux/personality.h>
-#include <linux/freezer.h>
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 67f1f6f..a244e70 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -37,6 +37,7 @@ config SPARC
 	select GENERIC_CLOCKEVENTS
 	select GENERIC_STRNCPY_FROM_USER
 	select GENERIC_STRNLEN_USER
+	select MODULES_USE_ELF_RELA
 
 config SPARC32
 	def_bool !64BIT
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index 67f83e0..fbe1cb5 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -21,4 +21,5 @@ generic-y += div64.h
 generic-y += local64.h
 generic-y += irq_regs.h
 generic-y += local.h
+generic-y += module.h
 generic-y += word-at-a-time.h
diff --git a/arch/sparc/include/asm/module.h b/arch/sparc/include/asm/module.h
deleted file mode 100644
index ff8e02d..0000000
--- a/arch/sparc/include/asm/module.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef __SPARC_MODULE_H
-#define __SPARC_MODULE_H
-struct mod_arch_specific { };
-
-/*
- * Use some preprocessor magic to define the correct symbol
- * for sparc32 and sparc64.
- * Elf_Addr becomes Elf32_Addr for sparc32 and Elf64_Addr for sparc64
- */
-#define ___ELF(a, b, c) a##b##c
-#define __ELF(a, b, c)  ___ELF(a, b, c)
-#define  _Elf(t)        __ELF(Elf, CONFIG_BITS, t)
-#define  _ELF(t)        __ELF(ELF, CONFIG_BITS, t)
-
-#define Elf_Shdr     _Elf(_Shdr)
-#define Elf_Sym      _Elf(_Sym)
-#define Elf_Ehdr     _Elf(_Ehdr)
-#define Elf_Rela     _Elf(_Rela)
-#define Elf_Addr     _Elf(_Addr)
-
-#define ELF_R_SYM    _ELF(_R_SYM)
-#define ELF_R_TYPE   _ELF(_R_TYPE)
-
-#endif /* __SPARC_MODULE_H */
diff --git a/arch/sparc/include/asm/thread_info_32.h b/arch/sparc/include/asm/thread_info_32.h
index e6cd224..25849ae 100644
--- a/arch/sparc/include/asm/thread_info_32.h
+++ b/arch/sparc/include/asm/thread_info_32.h
@@ -126,13 +126,14 @@ register struct thread_info *current_thread_info_reg asm("g6");
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_USEDFPU		(1<<TIF_USEDFPU)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
 #define _TIF_DO_NOTIFY_RESUME_MASK	(_TIF_NOTIFY_RESUME | \
 					 _TIF_SIGPENDING)
 
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_THREAD_INFO_H */
diff --git a/arch/sparc/include/asm/thread_info_64.h b/arch/sparc/include/asm/thread_info_64.h
index cfa8c38..4e22766 100644
--- a/arch/sparc/include/asm/thread_info_64.h
+++ b/arch/sparc/include/asm/thread_info_64.h
@@ -256,6 +256,9 @@ static inline bool test_and_clear_restore_sigmask(void)
 	ti->status &= ~TS_RESTORE_SIGMASK;
 	return true;
 }
+
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
 #endif	/* !__ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 065b88c..1afda82 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -783,7 +783,7 @@ static int __pci_mmap_make_offset(struct pci_dev *pdev,
 static void __pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma,
 					    enum pci_mmap_state mmap_state)
 {
-	vma->vm_flags |= (VM_IO | VM_RESERVED);
+	vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
 }
 
 /* Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index 932e443..1603f30 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -17,6 +17,7 @@ config TILE
 	select SYS_HYPERVISOR
 	select ARCH_HAVE_NMI_SAFE_CMPXCHG
 	select GENERIC_CLOCKEVENTS
+	select MODULES_USE_ELF_RELA
 
 # FIXME: investigate whether we need/want these options.
 #	select HAVE_IOREMAP_PROT
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c
index 474571b..3690f01 100644
--- a/arch/tile/kernel/compat_signal.c
+++ b/arch/tile/kernel/compat_signal.c
@@ -411,15 +411,6 @@ int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 	regs->regs[1] = ptr_to_compat_reg(&frame->info);
 	regs->regs[2] = ptr_to_compat_reg(&frame->uc);
 	regs->flags |= PT_FLAGS_CALLER_SAVES;
-
-	/*
-	 * Notify any tracer that was single-stepping it.
-	 * The tracer may want to single-step inside the
-	 * handler too.
-	 */
-	if (test_thread_flag(TIF_SINGLESTEP))
-		ptrace_notify(SIGTRAP);
-
 	return 0;
 
 give_sigsegv:
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c
index e29b055..67efb65 100644
--- a/arch/tile/kernel/signal.c
+++ b/arch/tile/kernel/signal.c
@@ -219,15 +219,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 	regs->regs[1] = (unsigned long) &frame->info;
 	regs->regs[2] = (unsigned long) &frame->uc;
 	regs->flags |= PT_FLAGS_CALLER_SAVES;
-
-	/*
-	 * Notify any tracer that was single-stepping it.
-	 * The tracer may want to single-step inside the
-	 * handler too.
-	 */
-	if (test_thread_flag(TIF_SINGLESTEP))
-		ptrace_notify(SIGTRAP);
-
 	return 0;
 
 give_sigsegv:
@@ -278,7 +269,8 @@ static void handle_signal(unsigned long sig, siginfo_t *info,
 		ret = setup_rt_frame(sig, ka, info, oldset, regs);
 	if (ret)
 		return;
-	signal_delivered(sig, info, ka, regs, 0);
+	signal_delivered(sig, info, ka, regs,
+			test_thread_flag(TIF_SINGLESTEP));
 }
 
 /*
diff --git a/arch/tile/mm/elf.c b/arch/tile/mm/elf.c
index 758b603..3cfa98b 100644
--- a/arch/tile/mm/elf.c
+++ b/arch/tile/mm/elf.c
@@ -36,19 +36,14 @@ static void sim_notify_exec(const char *binary_name)
 	} while (c);
 }
 
-static int notify_exec(void)
+static int notify_exec(struct mm_struct *mm)
 {
 	int retval = 0;  /* failure */
-	struct vm_area_struct *vma = current->mm->mmap;
-	while (vma) {
-		if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file)
-			break;
-		vma = vma->vm_next;
-	}
-	if (vma) {
+
+	if (mm->exe_file) {
 		char *buf = (char *) __get_free_page(GFP_KERNEL);
 		if (buf) {
-			char *path = d_path(&vma->vm_file->f_path,
+			char *path = d_path(&mm->exe_file->f_path,
 					    buf, PAGE_SIZE);
 			if (!IS_ERR(path)) {
 				sim_notify_exec(path);
@@ -106,16 +101,16 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
 	unsigned long vdso_base;
 	int retval = 0;
 
+	down_write(&mm->mmap_sem);
+
 	/*
 	 * Notify the simulator that an exec just occurred.
 	 * If we can't find the filename of the mapping, just use
 	 * whatever was passed as the linux_binprm filename.
 	 */
-	if (!notify_exec())
+	if (!notify_exec(mm))
 		sim_notify_exec(bprm->filename);
 
-	down_write(&mm->mmap_sem);
-
 	/*
 	 * MAYWRITE to allow gdb to COW and set breakpoints
 	 */
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index bbaf2c5..457475f 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -409,7 +409,8 @@ int setup_one_line(struct line *lines, int n, char *init,
 		line->valid = 1;
 		err = parse_chan_pair(new, line, n, opts, error_out);
 		if (!err) {
-			struct device *d = tty_register_device(driver, n, NULL);
+			struct device *d = tty_port_register_device(&line->port,
+					driver, n, NULL);
 			if (IS_ERR(d)) {
 				*error_out = "Failed to register device";
 				err = PTR_ERR(d);
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index 664a60e..c17de0d 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -705,6 +705,7 @@ static void stack_proc(void *arg)
 	struct task_struct *from = current, *to = arg;
 
 	to->thread.saved_task = from;
+	rcu_switch(from, to);
 	switch_to(from, to, from);
 }
 
diff --git a/arch/um/include/asm/thread_info.h b/arch/um/include/asm/thread_info.h
index c04e5ab..2c8eeb2 100644
--- a/arch/um/include/asm/thread_info.h
+++ b/arch/um/include/asm/thread_info.h
@@ -65,8 +65,6 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SYSCALL_TRACE	0	/* syscall trace active */
 #define TIF_SIGPENDING		1	/* signal pending */
 #define TIF_NEED_RESCHED	2	/* rescheduling necessary */
-#define TIF_POLLING_NRFLAG      3       /* true if poll_idle() is polling
-					 * TIF_NEED_RESCHED */
 #define TIF_RESTART_BLOCK	4
 #define TIF_MEMDIE		5	/* is terminating due to OOM killer */
 #define TIF_SYSCALL_AUDIT	6
@@ -76,7 +74,6 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
-#define _TIF_POLLING_NRFLAG     (1 << TIF_POLLING_NRFLAG)
 #define _TIF_MEMDIE		(1 << TIF_MEMDIE)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
 
diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig
index b0a4743..5d53ffd 100644
--- a/arch/unicore32/Kconfig
+++ b/arch/unicore32/Kconfig
@@ -14,6 +14,7 @@ config UNICORE32
 	select GENERIC_IRQ_SHOW
 	select ARCH_WANT_FRAME_POINTERS
 	select GENERIC_IOMAP
+	select MODULES_USE_ELF_REL
 	help
 	  UniCore-32 is 32-bit Instruction Set Architecture,
 	  including a series of low-power-consumption RISC chip
@@ -65,6 +66,9 @@ config GENERIC_CALIBRATE_DELAY
 config ARCH_MAY_HAVE_PC_FDC
 	bool
 
+config ZONE_DMA
+	def_bool y
+
 config NEED_DMA_MAP_STATE
        def_bool y
 
diff --git a/arch/unicore32/include/asm/bug.h b/arch/unicore32/include/asm/bug.h
index b1ff8ca..93a56f3 100644
--- a/arch/unicore32/include/asm/bug.h
+++ b/arch/unicore32/include/asm/bug.h
@@ -19,9 +19,4 @@ extern void die(const char *msg, struct pt_regs *regs, int err);
 extern void uc32_notify_die(const char *str, struct pt_regs *regs,
 		struct siginfo *info, unsigned long err, unsigned long trap);
 
-extern asmlinkage void __backtrace(void);
-extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
-
-extern void __show_regs(struct pt_regs *);
-
 #endif /* __UNICORE_BUG_H__ */
diff --git a/arch/unicore32/include/asm/cmpxchg.h b/arch/unicore32/include/asm/cmpxchg.h
index df4d5ac..8e797ad 100644
--- a/arch/unicore32/include/asm/cmpxchg.h
+++ b/arch/unicore32/include/asm/cmpxchg.h
@@ -35,7 +35,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
 			: "memory", "cc");
 		break;
 	default:
-		ret = __xchg_bad_pointer();
+		__xchg_bad_pointer();
 	}
 
 	return ret;
diff --git a/arch/unicore32/include/asm/thread_info.h b/arch/unicore32/include/asm/thread_info.h
index 89f7557..818b4a1 100644
--- a/arch/unicore32/include/asm/thread_info.h
+++ b/arch/unicore32/include/asm/thread_info.h
@@ -141,12 +141,12 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
-#define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
 
 /*
  * Change these and you break ASM code in entry-common.S
  */
-#define _TIF_WORK_MASK		0x000000ff
+#define _TIF_WORK_MASK \
+	(_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_NOTIFY_RESUME)
 
 #endif /* __KERNEL__ */
 #endif /* __UNICORE_THREAD_INFO_H__ */
diff --git a/arch/unicore32/kernel/entry.S b/arch/unicore32/kernel/entry.S
index 00a259f..dcb87ab 100644
--- a/arch/unicore32/kernel/entry.S
+++ b/arch/unicore32/kernel/entry.S
@@ -544,8 +544,6 @@ fast_work_pending:
 work_pending:
 	cand.a	r1, #_TIF_NEED_RESCHED
 	bne	work_resched
-	cand.a	r1, #_TIF_SIGPENDING|_TIF_NOTIFY_RESUME
-	beq	no_work_pending
 	mov	r0, sp				@ 'regs'
 	mov	r2, why				@ 'syscall'
 	cand.a	r1, #_TIF_SIGPENDING		@ delivering a signal?
diff --git a/arch/unicore32/kernel/process.c b/arch/unicore32/kernel/process.c
index b6f0458..b008586 100644
--- a/arch/unicore32/kernel/process.c
+++ b/arch/unicore32/kernel/process.c
@@ -380,7 +380,7 @@ int vectors_user_mapping(void)
 	return install_special_mapping(mm, 0xffff0000, PAGE_SIZE,
 				       VM_READ | VM_EXEC |
 				       VM_MAYREAD | VM_MAYEXEC |
-				       VM_RESERVED,
+				       VM_DONTEXPAND | VM_DONTDUMP,
 				       NULL);
 }
 
diff --git a/arch/unicore32/kernel/setup.h b/arch/unicore32/kernel/setup.h
index f239550..30f749d 100644
--- a/arch/unicore32/kernel/setup.h
+++ b/arch/unicore32/kernel/setup.h
@@ -30,4 +30,10 @@ extern char __vectors_start[], __vectors_end[];
 extern void kernel_thread_helper(void);
 
 extern void __init early_signal_init(void);
+
+extern asmlinkage void __backtrace(void);
+extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
+
+extern void __show_regs(struct pt_regs *);
+
 #endif
diff --git a/arch/unicore32/kernel/signal.c b/arch/unicore32/kernel/signal.c
index 8adedb3..b8b2ffd 100644
--- a/arch/unicore32/kernel/signal.c
+++ b/arch/unicore32/kernel/signal.c
@@ -12,7 +12,6 @@
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/personality.h>
-#include <linux/freezer.h>
 #include <linux/uaccess.h>
 #include <linux/tracehook.h>
 #include <linux/elf.h>
diff --git a/arch/unicore32/mm/fault.c b/arch/unicore32/mm/fault.c
index 2eeb9c0..f9b5c10 100644
--- a/arch/unicore32/mm/fault.c
+++ b/arch/unicore32/mm/fault.c
@@ -168,7 +168,7 @@ static inline bool access_error(unsigned int fsr, struct vm_area_struct *vma)
 }
 
 static int __do_pf(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
-		struct task_struct *tsk)
+		unsigned int flags, struct task_struct *tsk)
 {
 	struct vm_area_struct *vma;
 	int fault;
@@ -194,14 +194,7 @@ good_area:
 	 * If for any reason at all we couldn't handle the fault, make
 	 * sure we exit gracefully rather than endlessly redo the fault.
 	 */
-	fault = handle_mm_fault(mm, vma, addr & PAGE_MASK,
-			    (!(fsr ^ 0x12)) ? FAULT_FLAG_WRITE : 0);
-	if (unlikely(fault & VM_FAULT_ERROR))
-		return fault;
-	if (fault & VM_FAULT_MAJOR)
-		tsk->maj_flt++;
-	else
-		tsk->min_flt++;
+	fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, flags);
 	return fault;
 
 check_stack:
@@ -216,6 +209,8 @@ static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 	struct task_struct *tsk;
 	struct mm_struct *mm;
 	int fault, sig, code;
+	unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
+				 ((!(fsr ^ 0x12)) ? FAULT_FLAG_WRITE : 0);
 
 	tsk = current;
 	mm = tsk->mm;
@@ -236,6 +231,7 @@ static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 		if (!user_mode(regs)
 		    && !search_exception_tables(regs->UCreg_pc))
 			goto no_context;
+retry:
 		down_read(&mm->mmap_sem);
 	} else {
 		/*
@@ -251,7 +247,28 @@ static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 #endif
 	}
 
-	fault = __do_pf(mm, addr, fsr, tsk);
+	fault = __do_pf(mm, addr, fsr, flags, tsk);
+
+	/* If we need to retry but a fatal signal is pending, handle the
+	 * signal first. We do not need to release the mmap_sem because
+	 * it would already be released in __lock_page_or_retry in
+	 * mm/filemap.c. */
+	if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+		return 0;
+
+	if (!(fault & VM_FAULT_ERROR) && (flags & FAULT_FLAG_ALLOW_RETRY)) {
+		if (fault & VM_FAULT_MAJOR)
+			tsk->maj_flt++;
+		else
+			tsk->min_flt++;
+		if (fault & VM_FAULT_RETRY) {
+			/* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
+			* of starvation. */
+			flags &= ~FAULT_FLAG_ALLOW_RETRY;
+			goto retry;
+		}
+	}
+
 	up_read(&mm->mmap_sem);
 
 	/*
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 8ec3a1a..e76af9e 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -97,6 +97,9 @@ config X86
 	select KTIME_SCALAR if X86_32
 	select GENERIC_STRNCPY_FROM_USER
 	select GENERIC_STRNLEN_USER
+	select MODULES_USE_ELF_REL if X86_32
+	select MODULES_USE_ELF_RELA if X86_64
+	select HAVE_RCU_USER_QS if X86_64
 
 config INSTRUCTION_DECODER
 	def_bool (KPROBES || PERF_EVENTS || UPROBES)
@@ -549,6 +552,37 @@ config SCHED_OMIT_FRAME_POINTER
 
 	  If in doubt, say "Y".
 
+config KVMTOOL_TEST_ENABLE
+	bool "Enable options to create a bootable tools/kvm/ kernel"
+	select NET
+	select NETDEVICES
+	select PCI
+	select BLOCK
+	select BLK_DEV
+	select NETWORK_FILESYSTEMS
+	select INET
+	select EXPERIMENTAL
+	select SERIAL_8250
+	select SERIAL_8250_CONSOLE
+	select IP_PNP
+	select IP_PNP_DHCP
+	select BINFMT_ELF
+	select PCI_MSI
+	select HAVE_ARCH_KGDB
+	select DEBUG_KERNEL
+	select KGDB
+	select KGDB_SERIAL_CONSOLE
+	select VIRTUALIZATION
+	select VIRTIO
+	select VIRTIO_RING
+	select VIRTIO_PCI
+	select VIRTIO_BLK
+	select VIRTIO_CONSOLE
+	select VIRTIO_NET
+	select 9P_FS
+	select NET_9P
+	select NET_9P_VIRTIO
+
 menuconfig PARAVIRT_GUEST
 	bool "Paravirtualized guest support"
 	---help---
diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile
index e908e5d..5bacb4a 100644
--- a/arch/x86/crypto/Makefile
+++ b/arch/x86/crypto/Makefile
@@ -12,6 +12,8 @@ obj-$(CONFIG_CRYPTO_SERPENT_SSE2_586) += serpent-sse2-i586.o
 
 obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o
 obj-$(CONFIG_CRYPTO_CAMELLIA_X86_64) += camellia-x86_64.o
+obj-$(CONFIG_CRYPTO_CAST5_AVX_X86_64) += cast5-avx-x86_64.o
+obj-$(CONFIG_CRYPTO_CAST6_AVX_X86_64) += cast6-avx-x86_64.o
 obj-$(CONFIG_CRYPTO_BLOWFISH_X86_64) += blowfish-x86_64.o
 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64_3WAY) += twofish-x86_64-3way.o
@@ -32,6 +34,8 @@ serpent-sse2-i586-y := serpent-sse2-i586-asm_32.o serpent_sse2_glue.o
 
 aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o
 camellia-x86_64-y := camellia-x86_64-asm_64.o camellia_glue.o
+cast5-avx-x86_64-y := cast5-avx-x86_64-asm_64.o cast5_avx_glue.o
+cast6-avx-x86_64-y := cast6-avx-x86_64-asm_64.o cast6_avx_glue.o
 blowfish-x86_64-y := blowfish-x86_64-asm_64.o blowfish_glue.o
 twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o
 twofish-x86_64-3way-y := twofish-x86_64-asm_64-3way.o twofish_glue_3way.o
diff --git a/arch/x86/crypto/aes_glue.c b/arch/x86/crypto/aes_glue.c
index 59b37de..aafe8ce 100644
--- a/arch/x86/crypto/aes_glue.c
+++ b/arch/x86/crypto/aes_glue.c
@@ -40,7 +40,6 @@ static struct crypto_alg aes_alg = {
 	.cra_blocksize		= AES_BLOCK_SIZE,
 	.cra_ctxsize		= sizeof(struct crypto_aes_ctx),
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(aes_alg.cra_list),
 	.cra_u	= {
 		.cipher	= {
 			.cia_min_keysize	= AES_MIN_KEY_SIZE,
diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c
index 34fdcff..648347a 100644
--- a/arch/x86/crypto/aesni-intel_glue.c
+++ b/arch/x86/crypto/aesni-intel_glue.c
@@ -1118,7 +1118,7 @@ MODULE_DEVICE_TABLE(x86cpu, aesni_cpu_id);
 
 static int __init aesni_init(void)
 {
-	int err, i;
+	int err;
 
 	if (!x86_match_cpu(aesni_cpu_id))
 		return -ENODEV;
@@ -1127,9 +1127,6 @@ static int __init aesni_init(void)
 	if (err)
 		return err;
 
-	for (i = 0; i < ARRAY_SIZE(aesni_algs); i++)
-		INIT_LIST_HEAD(&aesni_algs[i].cra_list);
-
 	return crypto_register_algs(aesni_algs, ARRAY_SIZE(aesni_algs));
 }
 
diff --git a/arch/x86/crypto/blowfish_glue.c b/arch/x86/crypto/blowfish_glue.c
index 7967474..50ec333 100644
--- a/arch/x86/crypto/blowfish_glue.c
+++ b/arch/x86/crypto/blowfish_glue.c
@@ -367,7 +367,6 @@ static struct crypto_alg bf_algs[4] = { {
 	.cra_ctxsize		= sizeof(struct bf_ctx),
 	.cra_alignmask		= 0,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(bf_algs[0].cra_list),
 	.cra_u = {
 		.cipher = {
 			.cia_min_keysize	= BF_MIN_KEY_SIZE,
@@ -387,7 +386,6 @@ static struct crypto_alg bf_algs[4] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(bf_algs[1].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= BF_MIN_KEY_SIZE,
@@ -407,7 +405,6 @@ static struct crypto_alg bf_algs[4] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(bf_algs[2].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= BF_MIN_KEY_SIZE,
@@ -428,7 +425,6 @@ static struct crypto_alg bf_algs[4] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(bf_algs[3].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= BF_MIN_KEY_SIZE,
diff --git a/arch/x86/crypto/camellia_glue.c b/arch/x86/crypto/camellia_glue.c
index eeb2b3b..7a74d7b 100644
--- a/arch/x86/crypto/camellia_glue.c
+++ b/arch/x86/crypto/camellia_glue.c
@@ -1601,7 +1601,6 @@ static struct crypto_alg camellia_algs[6] = { {
 	.cra_ctxsize		= sizeof(struct camellia_ctx),
 	.cra_alignmask		= 0,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(camellia_algs[0].cra_list),
 	.cra_u			= {
 		.cipher = {
 			.cia_min_keysize = CAMELLIA_MIN_KEY_SIZE,
@@ -1621,7 +1620,6 @@ static struct crypto_alg camellia_algs[6] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(camellia_algs[1].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= CAMELLIA_MIN_KEY_SIZE,
@@ -1641,7 +1639,6 @@ static struct crypto_alg camellia_algs[6] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(camellia_algs[2].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= CAMELLIA_MIN_KEY_SIZE,
@@ -1662,7 +1659,6 @@ static struct crypto_alg camellia_algs[6] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(camellia_algs[3].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= CAMELLIA_MIN_KEY_SIZE,
@@ -1683,7 +1679,6 @@ static struct crypto_alg camellia_algs[6] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(camellia_algs[4].cra_list),
 	.cra_exit		= lrw_exit_tfm,
 	.cra_u = {
 		.blkcipher = {
@@ -1707,7 +1702,6 @@ static struct crypto_alg camellia_algs[6] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(camellia_algs[5].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= CAMELLIA_MIN_KEY_SIZE * 2,
diff --git a/arch/x86/crypto/cast5-avx-x86_64-asm_64.S b/arch/x86/crypto/cast5-avx-x86_64-asm_64.S
new file mode 100644
index 0000000..94693c8
--- /dev/null
+++ b/arch/x86/crypto/cast5-avx-x86_64-asm_64.S
@@ -0,0 +1,322 @@
+/*
+ * Cast5 Cipher 16-way parallel algorithm (AVX/x86_64)
+ *
+ * Copyright (C) 2012 Johannes Goetzfried
+ *     <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ */
+
+.file "cast5-avx-x86_64-asm_64.S"
+.text
+
+.extern cast5_s1
+.extern cast5_s2
+.extern cast5_s3
+.extern cast5_s4
+
+/* structure of crypto context */
+#define km	0
+#define kr	(16*4)
+#define rr	((16*4)+16)
+
+/* s-boxes */
+#define s1	cast5_s1
+#define s2	cast5_s2
+#define s3	cast5_s3
+#define s4	cast5_s4
+
+/**********************************************************************
+  16-way AVX cast5
+ **********************************************************************/
+#define CTX %rdi
+
+#define RL1 %xmm0
+#define RR1 %xmm1
+#define RL2 %xmm2
+#define RR2 %xmm3
+#define RL3 %xmm4
+#define RR3 %xmm5
+#define RL4 %xmm6
+#define RR4 %xmm7
+
+#define RX %xmm8
+
+#define RKM  %xmm9
+#define RKRF %xmm10
+#define RKRR %xmm11
+
+#define RTMP  %xmm12
+#define RMASK %xmm13
+#define R32   %xmm14
+
+#define RID1  %rax
+#define RID1b %al
+#define RID2  %rbx
+#define RID2b %bl
+
+#define RGI1   %rdx
+#define RGI1bl %dl
+#define RGI1bh %dh
+#define RGI2   %rcx
+#define RGI2bl %cl
+#define RGI2bh %ch
+
+#define RFS1  %r8
+#define RFS1d %r8d
+#define RFS2  %r9
+#define RFS2d %r9d
+#define RFS3  %r10
+#define RFS3d %r10d
+
+
+#define lookup_32bit(src, dst, op1, op2, op3) \
+	movb		src ## bl,     RID1b;    \
+	movb		src ## bh,     RID2b;    \
+	movl		s1(, RID1, 4), dst ## d; \
+	op1		s2(, RID2, 4), dst ## d; \
+	shrq $16,	src;                     \
+	movb		src ## bl,     RID1b;    \
+	movb		src ## bh,     RID2b;    \
+	op2		s3(, RID1, 4), dst ## d; \
+	op3		s4(, RID2, 4), dst ## d;
+
+#define F(a, x, op0, op1, op2, op3) \
+	op0	a,	RKM,  x;                 \
+	vpslld  RKRF,	x,    RTMP;              \
+	vpsrld  RKRR,	x,    x;                 \
+	vpor	RTMP,	x,    x;                 \
+	\
+	vpshufb	RMASK,	x,    x;                 \
+	vmovq		x,    RGI1;              \
+	vpsrldq $8,	x,    x;                 \
+	vmovq		x,    RGI2;              \
+	\
+	lookup_32bit(RGI1, RFS1, op1, op2, op3); \
+	shrq $16,	RGI1;                    \
+	lookup_32bit(RGI1, RFS2, op1, op2, op3); \
+	shlq $32,	RFS2;                    \
+	orq		RFS1, RFS2;              \
+	\
+	lookup_32bit(RGI2, RFS1, op1, op2, op3); \
+	shrq $16,	RGI2;                    \
+	lookup_32bit(RGI2, RFS3, op1, op2, op3); \
+	shlq $32,	RFS3;                    \
+	orq		RFS1, RFS3;              \
+	\
+	vmovq		RFS2, x;                 \
+	vpinsrq $1,	RFS3, x, x;
+
+#define F1(b, x) F(b, x, vpaddd, xorl, subl, addl)
+#define F2(b, x) F(b, x, vpxor,  subl, addl, xorl)
+#define F3(b, x) F(b, x, vpsubd, addl, xorl, subl)
+
+#define subround(a, b, x, n, f) \
+	F ## f(b, x);  \
+	vpxor a, x, a;
+
+#define round(l, r, n, f) \
+	vbroadcastss 	(km+(4*n))(CTX), RKM;        \
+	vpinsrb $0,	(kr+n)(CTX),     RKRF, RKRF; \
+	vpsubq		RKRF,            R32,  RKRR; \
+	subround(l ## 1, r ## 1, RX, n, f);          \
+	subround(l ## 2, r ## 2, RX, n, f);          \
+	subround(l ## 3, r ## 3, RX, n, f);          \
+	subround(l ## 4, r ## 4, RX, n, f);
+
+
+#define transpose_2x4(x0, x1, t0, t1) \
+	vpunpckldq		x1, x0, t0; \
+	vpunpckhdq		x1, x0, t1; \
+	\
+	vpunpcklqdq		t1, t0, x0; \
+	vpunpckhqdq		t1, t0, x1;
+
+#define inpack_blocks(in, x0, x1, t0, t1) \
+	vmovdqu (0*4*4)(in),	x0; \
+	vmovdqu (1*4*4)(in),	x1; \
+	vpshufb RMASK, x0,	x0; \
+	vpshufb RMASK, x1,	x1; \
+	\
+	transpose_2x4(x0, x1, t0, t1)
+
+#define outunpack_blocks(out, x0, x1, t0, t1) \
+	transpose_2x4(x0, x1, t0, t1) \
+	\
+	vpshufb RMASK,	x0, x0;           \
+	vpshufb RMASK,	x1, x1;           \
+	vmovdqu 	x0, (0*4*4)(out); \
+	vmovdqu		x1, (1*4*4)(out);
+
+#define outunpack_xor_blocks(out, x0, x1, t0, t1) \
+	transpose_2x4(x0, x1, t0, t1) \
+	\
+	vpshufb RMASK,	x0, x0;               \
+	vpshufb RMASK,	x1, x1;               \
+	vpxor		(0*4*4)(out), x0, x0; \
+	vmovdqu 	x0, (0*4*4)(out);     \
+	vpxor		(1*4*4)(out), x1, x1; \
+	vmovdqu	        x1, (1*4*4)(out);
+
+.align 16
+.Lbswap_mask:
+	.byte 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12
+.L32_mask:
+	.byte 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0
+
+.align 16
+.global __cast5_enc_blk_16way
+.type   __cast5_enc_blk_16way,@function;
+
+__cast5_enc_blk_16way:
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst
+	 *	%rdx: src
+	 *	%rcx: bool, if true: xor output
+	 */
+
+	pushq %rbx;
+	pushq %rcx;
+
+	vmovdqu .Lbswap_mask, RMASK;
+	vmovdqu .L32_mask, R32;
+	vpxor RKRF, RKRF, RKRF;
+
+	inpack_blocks(%rdx, RL1, RR1, RTMP, RX);
+	leaq (2*4*4)(%rdx), %rax;
+	inpack_blocks(%rax, RL2, RR2, RTMP, RX);
+	leaq (2*4*4)(%rax), %rax;
+	inpack_blocks(%rax, RL3, RR3, RTMP, RX);
+	leaq (2*4*4)(%rax), %rax;
+	inpack_blocks(%rax, RL4, RR4, RTMP, RX);
+
+	xorq RID1, RID1;
+	xorq RID2, RID2;
+
+	round(RL, RR, 0, 1);
+	round(RR, RL, 1, 2);
+	round(RL, RR, 2, 3);
+	round(RR, RL, 3, 1);
+	round(RL, RR, 4, 2);
+	round(RR, RL, 5, 3);
+	round(RL, RR, 6, 1);
+	round(RR, RL, 7, 2);
+	round(RL, RR, 8, 3);
+	round(RR, RL, 9, 1);
+	round(RL, RR, 10, 2);
+	round(RR, RL, 11, 3);
+
+	movb rr(CTX), %al;
+	testb %al, %al;
+	jnz __skip_enc;
+
+	round(RL, RR, 12, 1);
+	round(RR, RL, 13, 2);
+	round(RL, RR, 14, 3);
+	round(RR, RL, 15, 1);
+
+__skip_enc:
+	popq %rcx;
+	popq %rbx;
+
+	testb %cl, %cl;
+	jnz __enc_xor16;
+
+	outunpack_blocks(%rsi, RR1, RL1, RTMP, RX);
+	leaq (2*4*4)(%rsi), %rax;
+	outunpack_blocks(%rax, RR2, RL2, RTMP, RX);
+	leaq (2*4*4)(%rax), %rax;
+	outunpack_blocks(%rax, RR3, RL3, RTMP, RX);
+	leaq (2*4*4)(%rax), %rax;
+	outunpack_blocks(%rax, RR4, RL4, RTMP, RX);
+
+	ret;
+
+__enc_xor16:
+	outunpack_xor_blocks(%rsi, RR1, RL1, RTMP, RX);
+	leaq (2*4*4)(%rsi), %rax;
+	outunpack_xor_blocks(%rax, RR2, RL2, RTMP, RX);
+	leaq (2*4*4)(%rax), %rax;
+	outunpack_xor_blocks(%rax, RR3, RL3, RTMP, RX);
+	leaq (2*4*4)(%rax), %rax;
+	outunpack_xor_blocks(%rax, RR4, RL4, RTMP, RX);
+
+	ret;
+
+.align 16
+.global cast5_dec_blk_16way
+.type   cast5_dec_blk_16way,@function;
+
+cast5_dec_blk_16way:
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst
+	 *	%rdx: src
+	 */
+
+	pushq %rbx;
+
+	vmovdqu .Lbswap_mask, RMASK;
+	vmovdqu .L32_mask, R32;
+	vpxor RKRF, RKRF, RKRF;
+
+	inpack_blocks(%rdx, RL1, RR1, RTMP, RX);
+	leaq (2*4*4)(%rdx), %rax;
+	inpack_blocks(%rax, RL2, RR2, RTMP, RX);
+	leaq (2*4*4)(%rax), %rax;
+	inpack_blocks(%rax, RL3, RR3, RTMP, RX);
+	leaq (2*4*4)(%rax), %rax;
+	inpack_blocks(%rax, RL4, RR4, RTMP, RX);
+
+	xorq RID1, RID1;
+	xorq RID2, RID2;
+
+	movb rr(CTX), %al;
+	testb %al, %al;
+	jnz __skip_dec;
+
+	round(RL, RR, 15, 1);
+	round(RR, RL, 14, 3);
+	round(RL, RR, 13, 2);
+	round(RR, RL, 12, 1);
+
+__skip_dec:
+	round(RL, RR, 11, 3);
+	round(RR, RL, 10, 2);
+	round(RL, RR, 9, 1);
+	round(RR, RL, 8, 3);
+	round(RL, RR, 7, 2);
+	round(RR, RL, 6, 1);
+	round(RL, RR, 5, 3);
+	round(RR, RL, 4, 2);
+	round(RL, RR, 3, 1);
+	round(RR, RL, 2, 3);
+	round(RL, RR, 1, 2);
+	round(RR, RL, 0, 1);
+
+	popq %rbx;
+
+	outunpack_blocks(%rsi, RR1, RL1, RTMP, RX);
+	leaq (2*4*4)(%rsi), %rax;
+	outunpack_blocks(%rax, RR2, RL2, RTMP, RX);
+	leaq (2*4*4)(%rax), %rax;
+	outunpack_blocks(%rax, RR3, RL3, RTMP, RX);
+	leaq (2*4*4)(%rax), %rax;
+	outunpack_blocks(%rax, RR4, RL4, RTMP, RX);
+
+	ret;
diff --git a/arch/x86/crypto/cast5_avx_glue.c b/arch/x86/crypto/cast5_avx_glue.c
new file mode 100644
index 0000000..445aab0
--- /dev/null
+++ b/arch/x86/crypto/cast5_avx_glue.c
@@ -0,0 +1,530 @@
+/*
+ * Glue Code for the AVX assembler implemention of the Cast5 Cipher
+ *
+ * Copyright (C) 2012 Johannes Goetzfried
+ *     <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/hardirq.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <crypto/algapi.h>
+#include <crypto/cast5.h>
+#include <crypto/cryptd.h>
+#include <crypto/ctr.h>
+#include <asm/xcr.h>
+#include <asm/xsave.h>
+#include <asm/crypto/ablk_helper.h>
+#include <asm/crypto/glue_helper.h>
+
+#define CAST5_PARALLEL_BLOCKS 16
+
+asmlinkage void __cast5_enc_blk_16way(struct cast5_ctx *ctx, u8 *dst,
+				      const u8 *src, bool xor);
+asmlinkage void cast5_dec_blk_16way(struct cast5_ctx *ctx, u8 *dst,
+				    const u8 *src);
+
+static inline void cast5_enc_blk_xway(struct cast5_ctx *ctx, u8 *dst,
+				      const u8 *src)
+{
+	__cast5_enc_blk_16way(ctx, dst, src, false);
+}
+
+static inline void cast5_enc_blk_xway_xor(struct cast5_ctx *ctx, u8 *dst,
+					  const u8 *src)
+{
+	__cast5_enc_blk_16way(ctx, dst, src, true);
+}
+
+static inline void cast5_dec_blk_xway(struct cast5_ctx *ctx, u8 *dst,
+				      const u8 *src)
+{
+	cast5_dec_blk_16way(ctx, dst, src);
+}
+
+
+static inline bool cast5_fpu_begin(bool fpu_enabled, unsigned int nbytes)
+{
+	return glue_fpu_begin(CAST5_BLOCK_SIZE, CAST5_PARALLEL_BLOCKS,
+			      NULL, fpu_enabled, nbytes);
+}
+
+static inline void cast5_fpu_end(bool fpu_enabled)
+{
+	return glue_fpu_end(fpu_enabled);
+}
+
+static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
+		     bool enc)
+{
+	bool fpu_enabled = false;
+	struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	const unsigned int bsize = CAST5_BLOCK_SIZE;
+	unsigned int nbytes;
+	int err;
+
+	err = blkcipher_walk_virt(desc, walk);
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	while ((nbytes = walk->nbytes)) {
+		u8 *wsrc = walk->src.virt.addr;
+		u8 *wdst = walk->dst.virt.addr;
+
+		fpu_enabled = cast5_fpu_begin(fpu_enabled, nbytes);
+
+		/* Process multi-block batch */
+		if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) {
+			do {
+				if (enc)
+					cast5_enc_blk_xway(ctx, wdst, wsrc);
+				else
+					cast5_dec_blk_xway(ctx, wdst, wsrc);
+
+				wsrc += bsize * CAST5_PARALLEL_BLOCKS;
+				wdst += bsize * CAST5_PARALLEL_BLOCKS;
+				nbytes -= bsize * CAST5_PARALLEL_BLOCKS;
+			} while (nbytes >= bsize * CAST5_PARALLEL_BLOCKS);
+
+			if (nbytes < bsize)
+				goto done;
+		}
+
+		/* Handle leftovers */
+		do {
+			if (enc)
+				__cast5_encrypt(ctx, wdst, wsrc);
+			else
+				__cast5_decrypt(ctx, wdst, wsrc);
+
+			wsrc += bsize;
+			wdst += bsize;
+			nbytes -= bsize;
+		} while (nbytes >= bsize);
+
+done:
+		err = blkcipher_walk_done(desc, walk, nbytes);
+	}
+
+	cast5_fpu_end(fpu_enabled);
+	return err;
+}
+
+static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct blkcipher_walk walk;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	return ecb_crypt(desc, &walk, true);
+}
+
+static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct blkcipher_walk walk;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	return ecb_crypt(desc, &walk, false);
+}
+
+static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
+				  struct blkcipher_walk *walk)
+{
+	struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	const unsigned int bsize = CAST5_BLOCK_SIZE;
+	unsigned int nbytes = walk->nbytes;
+	u64 *src = (u64 *)walk->src.virt.addr;
+	u64 *dst = (u64 *)walk->dst.virt.addr;
+	u64 *iv = (u64 *)walk->iv;
+
+	do {
+		*dst = *src ^ *iv;
+		__cast5_encrypt(ctx, (u8 *)dst, (u8 *)dst);
+		iv = dst;
+
+		src += 1;
+		dst += 1;
+		nbytes -= bsize;
+	} while (nbytes >= bsize);
+
+	*(u64 *)walk->iv ^= *iv;
+	return nbytes;
+}
+
+static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct blkcipher_walk walk;
+	int err;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	err = blkcipher_walk_virt(desc, &walk);
+
+	while ((nbytes = walk.nbytes)) {
+		nbytes = __cbc_encrypt(desc, &walk);
+		err = blkcipher_walk_done(desc, &walk, nbytes);
+	}
+
+	return err;
+}
+
+static unsigned int __cbc_decrypt(struct blkcipher_desc *desc,
+				  struct blkcipher_walk *walk)
+{
+	struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	const unsigned int bsize = CAST5_BLOCK_SIZE;
+	unsigned int nbytes = walk->nbytes;
+	u64 *src = (u64 *)walk->src.virt.addr;
+	u64 *dst = (u64 *)walk->dst.virt.addr;
+	u64 ivs[CAST5_PARALLEL_BLOCKS - 1];
+	u64 last_iv;
+	int i;
+
+	/* Start of the last block. */
+	src += nbytes / bsize - 1;
+	dst += nbytes / bsize - 1;
+
+	last_iv = *src;
+
+	/* Process multi-block batch */
+	if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) {
+		do {
+			nbytes -= bsize * (CAST5_PARALLEL_BLOCKS - 1);
+			src -= CAST5_PARALLEL_BLOCKS - 1;
+			dst -= CAST5_PARALLEL_BLOCKS - 1;
+
+			for (i = 0; i < CAST5_PARALLEL_BLOCKS - 1; i++)
+				ivs[i] = src[i];
+
+			cast5_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src);
+
+			for (i = 0; i < CAST5_PARALLEL_BLOCKS - 1; i++)
+				*(dst + (i + 1)) ^= *(ivs + i);
+
+			nbytes -= bsize;
+			if (nbytes < bsize)
+				goto done;
+
+			*dst ^= *(src - 1);
+			src -= 1;
+			dst -= 1;
+		} while (nbytes >= bsize * CAST5_PARALLEL_BLOCKS);
+
+		if (nbytes < bsize)
+			goto done;
+	}
+
+	/* Handle leftovers */
+	for (;;) {
+		__cast5_decrypt(ctx, (u8 *)dst, (u8 *)src);
+
+		nbytes -= bsize;
+		if (nbytes < bsize)
+			break;
+
+		*dst ^= *(src - 1);
+		src -= 1;
+		dst -= 1;
+	}
+
+done:
+	*dst ^= *(u64 *)walk->iv;
+	*(u64 *)walk->iv = last_iv;
+
+	return nbytes;
+}
+
+static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	bool fpu_enabled = false;
+	struct blkcipher_walk walk;
+	int err;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	err = blkcipher_walk_virt(desc, &walk);
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	while ((nbytes = walk.nbytes)) {
+		fpu_enabled = cast5_fpu_begin(fpu_enabled, nbytes);
+		nbytes = __cbc_decrypt(desc, &walk);
+		err = blkcipher_walk_done(desc, &walk, nbytes);
+	}
+
+	cast5_fpu_end(fpu_enabled);
+	return err;
+}
+
+static void ctr_crypt_final(struct blkcipher_desc *desc,
+			    struct blkcipher_walk *walk)
+{
+	struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	u8 *ctrblk = walk->iv;
+	u8 keystream[CAST5_BLOCK_SIZE];
+	u8 *src = walk->src.virt.addr;
+	u8 *dst = walk->dst.virt.addr;
+	unsigned int nbytes = walk->nbytes;
+
+	__cast5_encrypt(ctx, keystream, ctrblk);
+	crypto_xor(keystream, src, nbytes);
+	memcpy(dst, keystream, nbytes);
+
+	crypto_inc(ctrblk, CAST5_BLOCK_SIZE);
+}
+
+static unsigned int __ctr_crypt(struct blkcipher_desc *desc,
+				struct blkcipher_walk *walk)
+{
+	struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	const unsigned int bsize = CAST5_BLOCK_SIZE;
+	unsigned int nbytes = walk->nbytes;
+	u64 *src = (u64 *)walk->src.virt.addr;
+	u64 *dst = (u64 *)walk->dst.virt.addr;
+	u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv);
+	__be64 ctrblocks[CAST5_PARALLEL_BLOCKS];
+	int i;
+
+	/* Process multi-block batch */
+	if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) {
+		do {
+			/* create ctrblks for parallel encrypt */
+			for (i = 0; i < CAST5_PARALLEL_BLOCKS; i++) {
+				if (dst != src)
+					dst[i] = src[i];
+
+				ctrblocks[i] = cpu_to_be64(ctrblk++);
+			}
+
+			cast5_enc_blk_xway_xor(ctx, (u8 *)dst,
+					       (u8 *)ctrblocks);
+
+			src += CAST5_PARALLEL_BLOCKS;
+			dst += CAST5_PARALLEL_BLOCKS;
+			nbytes -= bsize * CAST5_PARALLEL_BLOCKS;
+		} while (nbytes >= bsize * CAST5_PARALLEL_BLOCKS);
+
+		if (nbytes < bsize)
+			goto done;
+	}
+
+	/* Handle leftovers */
+	do {
+		if (dst != src)
+			*dst = *src;
+
+		ctrblocks[0] = cpu_to_be64(ctrblk++);
+
+		__cast5_encrypt(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks);
+		*dst ^= ctrblocks[0];
+
+		src += 1;
+		dst += 1;
+		nbytes -= bsize;
+	} while (nbytes >= bsize);
+
+done:
+	*(__be64 *)walk->iv = cpu_to_be64(ctrblk);
+	return nbytes;
+}
+
+static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		     struct scatterlist *src, unsigned int nbytes)
+{
+	bool fpu_enabled = false;
+	struct blkcipher_walk walk;
+	int err;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	err = blkcipher_walk_virt_block(desc, &walk, CAST5_BLOCK_SIZE);
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	while ((nbytes = walk.nbytes) >= CAST5_BLOCK_SIZE) {
+		fpu_enabled = cast5_fpu_begin(fpu_enabled, nbytes);
+		nbytes = __ctr_crypt(desc, &walk);
+		err = blkcipher_walk_done(desc, &walk, nbytes);
+	}
+
+	cast5_fpu_end(fpu_enabled);
+
+	if (walk.nbytes) {
+		ctr_crypt_final(desc, &walk);
+		err = blkcipher_walk_done(desc, &walk, 0);
+	}
+
+	return err;
+}
+
+
+static struct crypto_alg cast5_algs[6] = { {
+	.cra_name		= "__ecb-cast5-avx",
+	.cra_driver_name	= "__driver-ecb-cast5-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= CAST5_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct cast5_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= CAST5_MIN_KEY_SIZE,
+			.max_keysize	= CAST5_MAX_KEY_SIZE,
+			.setkey		= cast5_setkey,
+			.encrypt	= ecb_encrypt,
+			.decrypt	= ecb_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "__cbc-cast5-avx",
+	.cra_driver_name	= "__driver-cbc-cast5-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= CAST5_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct cast5_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= CAST5_MIN_KEY_SIZE,
+			.max_keysize	= CAST5_MAX_KEY_SIZE,
+			.setkey		= cast5_setkey,
+			.encrypt	= cbc_encrypt,
+			.decrypt	= cbc_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "__ctr-cast5-avx",
+	.cra_driver_name	= "__driver-ctr-cast5-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= 1,
+	.cra_ctxsize		= sizeof(struct cast5_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= CAST5_MIN_KEY_SIZE,
+			.max_keysize	= CAST5_MAX_KEY_SIZE,
+			.ivsize		= CAST5_BLOCK_SIZE,
+			.setkey		= cast5_setkey,
+			.encrypt	= ctr_crypt,
+			.decrypt	= ctr_crypt,
+		},
+	},
+}, {
+	.cra_name		= "ecb(cast5)",
+	.cra_driver_name	= "ecb-cast5-avx",
+	.cra_priority		= 200,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= CAST5_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_helper_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= CAST5_MIN_KEY_SIZE,
+			.max_keysize	= CAST5_MAX_KEY_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "cbc(cast5)",
+	.cra_driver_name	= "cbc-cast5-avx",
+	.cra_priority		= 200,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= CAST5_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_helper_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= CAST5_MIN_KEY_SIZE,
+			.max_keysize	= CAST5_MAX_KEY_SIZE,
+			.ivsize		= CAST5_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= __ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "ctr(cast5)",
+	.cra_driver_name	= "ctr-cast5-avx",
+	.cra_priority		= 200,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= 1,
+	.cra_ctxsize		= sizeof(struct async_helper_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= CAST5_MIN_KEY_SIZE,
+			.max_keysize	= CAST5_MAX_KEY_SIZE,
+			.ivsize		= CAST5_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_encrypt,
+			.geniv		= "chainiv",
+		},
+	},
+} };
+
+static int __init cast5_init(void)
+{
+	u64 xcr0;
+
+	if (!cpu_has_avx || !cpu_has_osxsave) {
+		pr_info("AVX instructions are not detected.\n");
+		return -ENODEV;
+	}
+
+	xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
+	if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
+		pr_info("AVX detected but unusable.\n");
+		return -ENODEV;
+	}
+
+	return crypto_register_algs(cast5_algs, ARRAY_SIZE(cast5_algs));
+}
+
+static void __exit cast5_exit(void)
+{
+	crypto_unregister_algs(cast5_algs, ARRAY_SIZE(cast5_algs));
+}
+
+module_init(cast5_init);
+module_exit(cast5_exit);
+
+MODULE_DESCRIPTION("Cast5 Cipher Algorithm, AVX optimized");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("cast5");
diff --git a/arch/x86/crypto/cast6-avx-x86_64-asm_64.S b/arch/x86/crypto/cast6-avx-x86_64-asm_64.S
new file mode 100644
index 0000000..d258ce0
--- /dev/null
+++ b/arch/x86/crypto/cast6-avx-x86_64-asm_64.S
@@ -0,0 +1,335 @@
+/*
+ * Cast6 Cipher 8-way parallel algorithm (AVX/x86_64)
+ *
+ * Copyright (C) 2012 Johannes Goetzfried
+ *     <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ */
+
+.file "cast6-avx-x86_64-asm_64.S"
+.text
+
+.extern cast6_s1
+.extern cast6_s2
+.extern cast6_s3
+.extern cast6_s4
+
+/* structure of crypto context */
+#define km	0
+#define kr	(12*4*4)
+
+/* s-boxes */
+#define s1	cast6_s1
+#define s2	cast6_s2
+#define s3	cast6_s3
+#define s4	cast6_s4
+
+/**********************************************************************
+  8-way AVX cast6
+ **********************************************************************/
+#define CTX %rdi
+
+#define RA1 %xmm0
+#define RB1 %xmm1
+#define RC1 %xmm2
+#define RD1 %xmm3
+
+#define RA2 %xmm4
+#define RB2 %xmm5
+#define RC2 %xmm6
+#define RD2 %xmm7
+
+#define RX %xmm8
+
+#define RKM  %xmm9
+#define RKRF %xmm10
+#define RKRR %xmm11
+
+#define RTMP  %xmm12
+#define RMASK %xmm13
+#define R32   %xmm14
+
+#define RID1  %rax
+#define RID1b %al
+#define RID2  %rbx
+#define RID2b %bl
+
+#define RGI1   %rdx
+#define RGI1bl %dl
+#define RGI1bh %dh
+#define RGI2   %rcx
+#define RGI2bl %cl
+#define RGI2bh %ch
+
+#define RFS1  %r8
+#define RFS1d %r8d
+#define RFS2  %r9
+#define RFS2d %r9d
+#define RFS3  %r10
+#define RFS3d %r10d
+
+
+#define lookup_32bit(src, dst, op1, op2, op3) \
+	movb		src ## bl,     RID1b;    \
+	movb		src ## bh,     RID2b;    \
+	movl		s1(, RID1, 4), dst ## d; \
+	op1		s2(, RID2, 4), dst ## d; \
+	shrq $16,	src;                     \
+	movb		src ## bl,     RID1b;    \
+	movb		src ## bh,     RID2b;    \
+	op2		s3(, RID1, 4), dst ## d; \
+	op3		s4(, RID2, 4), dst ## d;
+
+#define F(a, x, op0, op1, op2, op3) \
+	op0	a,	RKM,  x;                 \
+	vpslld  RKRF,	x,    RTMP;              \
+	vpsrld  RKRR,	x,    x;                 \
+	vpor	RTMP,	x,    x;                 \
+	\
+	vpshufb	RMASK,	x,    x;                 \
+	vmovq		x,    RGI1;              \
+	vpsrldq $8,	x,    x;                 \
+	vmovq		x,    RGI2;              \
+	\
+	lookup_32bit(RGI1, RFS1, op1, op2, op3); \
+	shrq $16,	RGI1;                    \
+	lookup_32bit(RGI1, RFS2, op1, op2, op3); \
+	shlq $32,	RFS2;                    \
+	orq		RFS1, RFS2;              \
+	\
+	lookup_32bit(RGI2, RFS1, op1, op2, op3); \
+	shrq $16,	RGI2;                    \
+	lookup_32bit(RGI2, RFS3, op1, op2, op3); \
+	shlq $32,	RFS3;                    \
+	orq		RFS1, RFS3;              \
+	\
+	vmovq		RFS2, x;                 \
+	vpinsrq $1,	RFS3, x, x;
+
+#define F1(b, x) F(b, x, vpaddd, xorl, subl, addl)
+#define F2(b, x) F(b, x, vpxor,  subl, addl, xorl)
+#define F3(b, x) F(b, x, vpsubd, addl, xorl, subl)
+
+#define qop(in, out, x, f) \
+	F ## f(in ## 1, x);          \
+	vpxor out ## 1, x, out ## 1; \
+	F ## f(in ## 2, x);          \
+	vpxor out ## 2, x, out ## 2; \
+
+#define Q(n) \
+	vbroadcastss	(km+(4*(4*n+0)))(CTX), RKM;        \
+	vpinsrb $0,	(kr+(4*n+0))(CTX),     RKRF, RKRF; \
+	vpsubq		RKRF,                  R32,  RKRR; \
+	qop(RD, RC, RX, 1);                                \
+	\
+	vbroadcastss	(km+(4*(4*n+1)))(CTX), RKM;        \
+	vpinsrb $0,	(kr+(4*n+1))(CTX),     RKRF, RKRF; \
+	vpsubq		RKRF,                  R32,  RKRR; \
+	qop(RC, RB, RX, 2);                                \
+	\
+	vbroadcastss	(km+(4*(4*n+2)))(CTX), RKM;        \
+	vpinsrb $0,	(kr+(4*n+2))(CTX),     RKRF, RKRF; \
+	vpsubq		RKRF,                  R32,  RKRR; \
+	qop(RB, RA, RX, 3);                                \
+	\
+	vbroadcastss	(km+(4*(4*n+3)))(CTX), RKM;        \
+	vpinsrb $0,	(kr+(4*n+3))(CTX),     RKRF, RKRF; \
+	vpsubq		RKRF,                  R32,  RKRR; \
+	qop(RA, RD, RX, 1);
+
+#define QBAR(n) \
+	vbroadcastss	(km+(4*(4*n+3)))(CTX), RKM;        \
+	vpinsrb $0,	(kr+(4*n+3))(CTX),     RKRF, RKRF; \
+	vpsubq		RKRF,                  R32,  RKRR; \
+	qop(RA, RD, RX, 1);                                \
+	\
+	vbroadcastss	(km+(4*(4*n+2)))(CTX), RKM;        \
+	vpinsrb $0,	(kr+(4*n+2))(CTX),     RKRF, RKRF; \
+	vpsubq		RKRF,                  R32,  RKRR; \
+	qop(RB, RA, RX, 3);                                \
+	\
+	vbroadcastss	(km+(4*(4*n+1)))(CTX), RKM;        \
+	vpinsrb $0,	(kr+(4*n+1))(CTX),     RKRF, RKRF; \
+	vpsubq		RKRF,                  R32,  RKRR; \
+	qop(RC, RB, RX, 2);                                \
+	\
+	vbroadcastss	(km+(4*(4*n+0)))(CTX), RKM;        \
+	vpinsrb $0,	(kr+(4*n+0))(CTX),     RKRF, RKRF; \
+	vpsubq		RKRF,                  R32,  RKRR; \
+	qop(RD, RC, RX, 1);
+
+
+#define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
+	vpunpckldq		x1, x0, t0; \
+	vpunpckhdq		x1, x0, t2; \
+	vpunpckldq		x3, x2, t1; \
+	vpunpckhdq		x3, x2, x3; \
+	\
+	vpunpcklqdq		t1, t0, x0; \
+	vpunpckhqdq		t1, t0, x1; \
+	vpunpcklqdq		x3, t2, x2; \
+	vpunpckhqdq		x3, t2, x3;
+
+#define inpack_blocks(in, x0, x1, x2, x3, t0, t1, t2) \
+	vmovdqu (0*4*4)(in),	x0; \
+	vmovdqu (1*4*4)(in),	x1; \
+	vmovdqu (2*4*4)(in),	x2; \
+	vmovdqu (3*4*4)(in),	x3; \
+	vpshufb RMASK, x0,	x0; \
+	vpshufb RMASK, x1,	x1; \
+	vpshufb RMASK, x2,	x2; \
+	vpshufb RMASK, x3,	x3; \
+	\
+	transpose_4x4(x0, x1, x2, x3, t0, t1, t2)
+
+#define outunpack_blocks(out, x0, x1, x2, x3, t0, t1, t2) \
+	transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
+	\
+	vpshufb RMASK,		x0, x0;       \
+	vpshufb RMASK,		x1, x1;       \
+	vpshufb RMASK,		x2, x2;       \
+	vpshufb RMASK,		x3, x3;       \
+	vmovdqu x0,		(0*4*4)(out); \
+	vmovdqu	x1,		(1*4*4)(out); \
+	vmovdqu	x2,		(2*4*4)(out); \
+	vmovdqu	x3,		(3*4*4)(out);
+
+#define outunpack_xor_blocks(out, x0, x1, x2, x3, t0, t1, t2) \
+	transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
+	\
+	vpshufb RMASK,		x0, x0;       \
+	vpshufb RMASK,		x1, x1;       \
+	vpshufb RMASK,		x2, x2;       \
+	vpshufb RMASK,		x3, x3;       \
+	vpxor (0*4*4)(out),	x0, x0;       \
+	vmovdqu	x0,		(0*4*4)(out); \
+	vpxor (1*4*4)(out),	x1, x1;       \
+	vmovdqu	x1,		(1*4*4)(out); \
+	vpxor (2*4*4)(out),	x2, x2;       \
+	vmovdqu x2,		(2*4*4)(out); \
+	vpxor (3*4*4)(out),	x3, x3;       \
+	vmovdqu x3,		(3*4*4)(out);
+
+.align 16
+.Lbswap_mask:
+	.byte 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12
+.L32_mask:
+	.byte 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0
+
+.align 16
+.global __cast6_enc_blk_8way
+.type   __cast6_enc_blk_8way,@function;
+
+__cast6_enc_blk_8way:
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst
+	 *	%rdx: src
+	 *	%rcx: bool, if true: xor output
+	 */
+
+	pushq %rbx;
+	pushq %rcx;
+
+	vmovdqu .Lbswap_mask, RMASK;
+	vmovdqu .L32_mask, R32;
+	vpxor RKRF, RKRF, RKRF;
+
+	leaq (4*4*4)(%rdx), %rax;
+	inpack_blocks(%rdx, RA1, RB1, RC1, RD1, RTMP, RX, RKM);
+	inpack_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKM);
+
+	xorq RID1, RID1;
+	xorq RID2, RID2;
+
+	Q(0);
+	Q(1);
+	Q(2);
+	Q(3);
+	Q(4);
+	Q(5);
+	QBAR(6);
+	QBAR(7);
+	QBAR(8);
+	QBAR(9);
+	QBAR(10);
+	QBAR(11);
+
+	popq %rcx;
+	popq %rbx;
+
+	leaq (4*4*4)(%rsi), %rax;
+
+	testb %cl, %cl;
+	jnz __enc_xor8;
+
+	outunpack_blocks(%rsi, RA1, RB1, RC1, RD1, RTMP, RX, RKM);
+	outunpack_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKM);
+
+	ret;
+
+__enc_xor8:
+	outunpack_xor_blocks(%rsi, RA1, RB1, RC1, RD1, RTMP, RX, RKM);
+	outunpack_xor_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKM);
+
+	ret;
+
+.align 16
+.global cast6_dec_blk_8way
+.type   cast6_dec_blk_8way,@function;
+
+cast6_dec_blk_8way:
+	/* input:
+	 *	%rdi: ctx, CTX
+	 *	%rsi: dst
+	 *	%rdx: src
+	 */
+
+	pushq %rbx;
+
+	vmovdqu .Lbswap_mask, RMASK;
+	vmovdqu .L32_mask, R32;
+	vpxor RKRF, RKRF, RKRF;
+
+	leaq (4*4*4)(%rdx), %rax;
+	inpack_blocks(%rdx, RA1, RB1, RC1, RD1, RTMP, RX, RKM);
+	inpack_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKM);
+
+	xorq RID1, RID1;
+	xorq RID2, RID2;
+
+	Q(11);
+	Q(10);
+	Q(9);
+	Q(8);
+	Q(7);
+	Q(6);
+	QBAR(5);
+	QBAR(4);
+	QBAR(3);
+	QBAR(2);
+	QBAR(1);
+	QBAR(0);
+
+	popq %rbx;
+
+	leaq (4*4*4)(%rsi), %rax;
+	outunpack_blocks(%rsi, RA1, RB1, RC1, RD1, RTMP, RX, RKM);
+	outunpack_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKM);
+
+	ret;
diff --git a/arch/x86/crypto/cast6_avx_glue.c b/arch/x86/crypto/cast6_avx_glue.c
new file mode 100644
index 0000000..15e5f85
--- /dev/null
+++ b/arch/x86/crypto/cast6_avx_glue.c
@@ -0,0 +1,648 @@
+/*
+ * Glue Code for the AVX assembler implemention of the Cast6 Cipher
+ *
+ * Copyright (C) 2012 Johannes Goetzfried
+ *     <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/hardirq.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <crypto/algapi.h>
+#include <crypto/cast6.h>
+#include <crypto/cryptd.h>
+#include <crypto/b128ops.h>
+#include <crypto/ctr.h>
+#include <crypto/lrw.h>
+#include <crypto/xts.h>
+#include <asm/xcr.h>
+#include <asm/xsave.h>
+#include <asm/crypto/ablk_helper.h>
+#include <asm/crypto/glue_helper.h>
+
+#define CAST6_PARALLEL_BLOCKS 8
+
+asmlinkage void __cast6_enc_blk_8way(struct cast6_ctx *ctx, u8 *dst,
+				     const u8 *src, bool xor);
+asmlinkage void cast6_dec_blk_8way(struct cast6_ctx *ctx, u8 *dst,
+				   const u8 *src);
+
+static inline void cast6_enc_blk_xway(struct cast6_ctx *ctx, u8 *dst,
+				      const u8 *src)
+{
+	__cast6_enc_blk_8way(ctx, dst, src, false);
+}
+
+static inline void cast6_enc_blk_xway_xor(struct cast6_ctx *ctx, u8 *dst,
+					  const u8 *src)
+{
+	__cast6_enc_blk_8way(ctx, dst, src, true);
+}
+
+static inline void cast6_dec_blk_xway(struct cast6_ctx *ctx, u8 *dst,
+				      const u8 *src)
+{
+	cast6_dec_blk_8way(ctx, dst, src);
+}
+
+
+static void cast6_decrypt_cbc_xway(void *ctx, u128 *dst, const u128 *src)
+{
+	u128 ivs[CAST6_PARALLEL_BLOCKS - 1];
+	unsigned int j;
+
+	for (j = 0; j < CAST6_PARALLEL_BLOCKS - 1; j++)
+		ivs[j] = src[j];
+
+	cast6_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src);
+
+	for (j = 0; j < CAST6_PARALLEL_BLOCKS - 1; j++)
+		u128_xor(dst + (j + 1), dst + (j + 1), ivs + j);
+}
+
+static void cast6_crypt_ctr(void *ctx, u128 *dst, const u128 *src, u128 *iv)
+{
+	be128 ctrblk;
+
+	u128_to_be128(&ctrblk, iv);
+	u128_inc(iv);
+
+	__cast6_encrypt(ctx, (u8 *)&ctrblk, (u8 *)&ctrblk);
+	u128_xor(dst, src, (u128 *)&ctrblk);
+}
+
+static void cast6_crypt_ctr_xway(void *ctx, u128 *dst, const u128 *src,
+				   u128 *iv)
+{
+	be128 ctrblks[CAST6_PARALLEL_BLOCKS];
+	unsigned int i;
+
+	for (i = 0; i < CAST6_PARALLEL_BLOCKS; i++) {
+		if (dst != src)
+			dst[i] = src[i];
+
+		u128_to_be128(&ctrblks[i], iv);
+		u128_inc(iv);
+	}
+
+	cast6_enc_blk_xway_xor(ctx, (u8 *)dst, (u8 *)ctrblks);
+}
+
+static const struct common_glue_ctx cast6_enc = {
+	.num_funcs = 2,
+	.fpu_blocks_limit = CAST6_PARALLEL_BLOCKS,
+
+	.funcs = { {
+		.num_blocks = CAST6_PARALLEL_BLOCKS,
+		.fn_u = { .ecb = GLUE_FUNC_CAST(cast6_enc_blk_xway) }
+	}, {
+		.num_blocks = 1,
+		.fn_u = { .ecb = GLUE_FUNC_CAST(__cast6_encrypt) }
+	} }
+};
+
+static const struct common_glue_ctx cast6_ctr = {
+	.num_funcs = 2,
+	.fpu_blocks_limit = CAST6_PARALLEL_BLOCKS,
+
+	.funcs = { {
+		.num_blocks = CAST6_PARALLEL_BLOCKS,
+		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(cast6_crypt_ctr_xway) }
+	}, {
+		.num_blocks = 1,
+		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(cast6_crypt_ctr) }
+	} }
+};
+
+static const struct common_glue_ctx cast6_dec = {
+	.num_funcs = 2,
+	.fpu_blocks_limit = CAST6_PARALLEL_BLOCKS,
+
+	.funcs = { {
+		.num_blocks = CAST6_PARALLEL_BLOCKS,
+		.fn_u = { .ecb = GLUE_FUNC_CAST(cast6_dec_blk_xway) }
+	}, {
+		.num_blocks = 1,
+		.fn_u = { .ecb = GLUE_FUNC_CAST(__cast6_decrypt) }
+	} }
+};
+
+static const struct common_glue_ctx cast6_dec_cbc = {
+	.num_funcs = 2,
+	.fpu_blocks_limit = CAST6_PARALLEL_BLOCKS,
+
+	.funcs = { {
+		.num_blocks = CAST6_PARALLEL_BLOCKS,
+		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(cast6_decrypt_cbc_xway) }
+	}, {
+		.num_blocks = 1,
+		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(__cast6_decrypt) }
+	} }
+};
+
+static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	return glue_ecb_crypt_128bit(&cast6_enc, desc, dst, src, nbytes);
+}
+
+static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	return glue_ecb_crypt_128bit(&cast6_dec, desc, dst, src, nbytes);
+}
+
+static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(__cast6_encrypt), desc,
+				       dst, src, nbytes);
+}
+
+static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	return glue_cbc_decrypt_128bit(&cast6_dec_cbc, desc, dst, src,
+				       nbytes);
+}
+
+static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		     struct scatterlist *src, unsigned int nbytes)
+{
+	return glue_ctr_crypt_128bit(&cast6_ctr, desc, dst, src, nbytes);
+}
+
+static inline bool cast6_fpu_begin(bool fpu_enabled, unsigned int nbytes)
+{
+	return glue_fpu_begin(CAST6_BLOCK_SIZE, CAST6_PARALLEL_BLOCKS,
+			      NULL, fpu_enabled, nbytes);
+}
+
+static inline void cast6_fpu_end(bool fpu_enabled)
+{
+	glue_fpu_end(fpu_enabled);
+}
+
+struct crypt_priv {
+	struct cast6_ctx *ctx;
+	bool fpu_enabled;
+};
+
+static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+	const unsigned int bsize = CAST6_BLOCK_SIZE;
+	struct crypt_priv *ctx = priv;
+	int i;
+
+	ctx->fpu_enabled = cast6_fpu_begin(ctx->fpu_enabled, nbytes);
+
+	if (nbytes == bsize * CAST6_PARALLEL_BLOCKS) {
+		cast6_enc_blk_xway(ctx->ctx, srcdst, srcdst);
+		return;
+	}
+
+	for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+		__cast6_encrypt(ctx->ctx, srcdst, srcdst);
+}
+
+static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+	const unsigned int bsize = CAST6_BLOCK_SIZE;
+	struct crypt_priv *ctx = priv;
+	int i;
+
+	ctx->fpu_enabled = cast6_fpu_begin(ctx->fpu_enabled, nbytes);
+
+	if (nbytes == bsize * CAST6_PARALLEL_BLOCKS) {
+		cast6_dec_blk_xway(ctx->ctx, srcdst, srcdst);
+		return;
+	}
+
+	for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+		__cast6_decrypt(ctx->ctx, srcdst, srcdst);
+}
+
+struct cast6_lrw_ctx {
+	struct lrw_table_ctx lrw_table;
+	struct cast6_ctx cast6_ctx;
+};
+
+static int lrw_cast6_setkey(struct crypto_tfm *tfm, const u8 *key,
+			      unsigned int keylen)
+{
+	struct cast6_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
+	int err;
+
+	err = __cast6_setkey(&ctx->cast6_ctx, key, keylen - CAST6_BLOCK_SIZE,
+			     &tfm->crt_flags);
+	if (err)
+		return err;
+
+	return lrw_init_table(&ctx->lrw_table, key + keylen - CAST6_BLOCK_SIZE);
+}
+
+static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct cast6_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	be128 buf[CAST6_PARALLEL_BLOCKS];
+	struct crypt_priv crypt_ctx = {
+		.ctx = &ctx->cast6_ctx,
+		.fpu_enabled = false,
+	};
+	struct lrw_crypt_req req = {
+		.tbuf = buf,
+		.tbuflen = sizeof(buf),
+
+		.table_ctx = &ctx->lrw_table,
+		.crypt_ctx = &crypt_ctx,
+		.crypt_fn = encrypt_callback,
+	};
+	int ret;
+
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+	ret = lrw_crypt(desc, dst, src, nbytes, &req);
+	cast6_fpu_end(crypt_ctx.fpu_enabled);
+
+	return ret;
+}
+
+static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct cast6_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	be128 buf[CAST6_PARALLEL_BLOCKS];
+	struct crypt_priv crypt_ctx = {
+		.ctx = &ctx->cast6_ctx,
+		.fpu_enabled = false,
+	};
+	struct lrw_crypt_req req = {
+		.tbuf = buf,
+		.tbuflen = sizeof(buf),
+
+		.table_ctx = &ctx->lrw_table,
+		.crypt_ctx = &crypt_ctx,
+		.crypt_fn = decrypt_callback,
+	};
+	int ret;
+
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+	ret = lrw_crypt(desc, dst, src, nbytes, &req);
+	cast6_fpu_end(crypt_ctx.fpu_enabled);
+
+	return ret;
+}
+
+static void lrw_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct cast6_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	lrw_free_table(&ctx->lrw_table);
+}
+
+struct cast6_xts_ctx {
+	struct cast6_ctx tweak_ctx;
+	struct cast6_ctx crypt_ctx;
+};
+
+static int xts_cast6_setkey(struct crypto_tfm *tfm, const u8 *key,
+			      unsigned int keylen)
+{
+	struct cast6_xts_ctx *ctx = crypto_tfm_ctx(tfm);
+	u32 *flags = &tfm->crt_flags;
+	int err;
+
+	/* key consists of keys of equal size concatenated, therefore
+	 * the length must be even
+	 */
+	if (keylen % 2) {
+		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		return -EINVAL;
+	}
+
+	/* first half of xts-key is for crypt */
+	err = __cast6_setkey(&ctx->crypt_ctx, key, keylen / 2, flags);
+	if (err)
+		return err;
+
+	/* second half of xts-key is for tweak */
+	return __cast6_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2,
+			      flags);
+}
+
+static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct cast6_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	be128 buf[CAST6_PARALLEL_BLOCKS];
+	struct crypt_priv crypt_ctx = {
+		.ctx = &ctx->crypt_ctx,
+		.fpu_enabled = false,
+	};
+	struct xts_crypt_req req = {
+		.tbuf = buf,
+		.tbuflen = sizeof(buf),
+
+		.tweak_ctx = &ctx->tweak_ctx,
+		.tweak_fn = XTS_TWEAK_CAST(__cast6_encrypt),
+		.crypt_ctx = &crypt_ctx,
+		.crypt_fn = encrypt_callback,
+	};
+	int ret;
+
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+	ret = xts_crypt(desc, dst, src, nbytes, &req);
+	cast6_fpu_end(crypt_ctx.fpu_enabled);
+
+	return ret;
+}
+
+static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		       struct scatterlist *src, unsigned int nbytes)
+{
+	struct cast6_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	be128 buf[CAST6_PARALLEL_BLOCKS];
+	struct crypt_priv crypt_ctx = {
+		.ctx = &ctx->crypt_ctx,
+		.fpu_enabled = false,
+	};
+	struct xts_crypt_req req = {
+		.tbuf = buf,
+		.tbuflen = sizeof(buf),
+
+		.tweak_ctx = &ctx->tweak_ctx,
+		.tweak_fn = XTS_TWEAK_CAST(__cast6_encrypt),
+		.crypt_ctx = &crypt_ctx,
+		.crypt_fn = decrypt_callback,
+	};
+	int ret;
+
+	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+	ret = xts_crypt(desc, dst, src, nbytes, &req);
+	cast6_fpu_end(crypt_ctx.fpu_enabled);
+
+	return ret;
+}
+
+static struct crypto_alg cast6_algs[10] = { {
+	.cra_name		= "__ecb-cast6-avx",
+	.cra_driver_name	= "__driver-ecb-cast6-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= CAST6_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct cast6_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= CAST6_MIN_KEY_SIZE,
+			.max_keysize	= CAST6_MAX_KEY_SIZE,
+			.setkey		= cast6_setkey,
+			.encrypt	= ecb_encrypt,
+			.decrypt	= ecb_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "__cbc-cast6-avx",
+	.cra_driver_name	= "__driver-cbc-cast6-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= CAST6_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct cast6_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= CAST6_MIN_KEY_SIZE,
+			.max_keysize	= CAST6_MAX_KEY_SIZE,
+			.setkey		= cast6_setkey,
+			.encrypt	= cbc_encrypt,
+			.decrypt	= cbc_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "__ctr-cast6-avx",
+	.cra_driver_name	= "__driver-ctr-cast6-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= 1,
+	.cra_ctxsize		= sizeof(struct cast6_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= CAST6_MIN_KEY_SIZE,
+			.max_keysize	= CAST6_MAX_KEY_SIZE,
+			.ivsize		= CAST6_BLOCK_SIZE,
+			.setkey		= cast6_setkey,
+			.encrypt	= ctr_crypt,
+			.decrypt	= ctr_crypt,
+		},
+	},
+}, {
+	.cra_name		= "__lrw-cast6-avx",
+	.cra_driver_name	= "__driver-lrw-cast6-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= CAST6_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct cast6_lrw_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_exit		= lrw_exit_tfm,
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= CAST6_MIN_KEY_SIZE +
+					  CAST6_BLOCK_SIZE,
+			.max_keysize	= CAST6_MAX_KEY_SIZE +
+					  CAST6_BLOCK_SIZE,
+			.ivsize		= CAST6_BLOCK_SIZE,
+			.setkey		= lrw_cast6_setkey,
+			.encrypt	= lrw_encrypt,
+			.decrypt	= lrw_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "__xts-cast6-avx",
+	.cra_driver_name	= "__driver-xts-cast6-avx",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		= CAST6_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct cast6_xts_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_blkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_u = {
+		.blkcipher = {
+			.min_keysize	= CAST6_MIN_KEY_SIZE * 2,
+			.max_keysize	= CAST6_MAX_KEY_SIZE * 2,
+			.ivsize		= CAST6_BLOCK_SIZE,
+			.setkey		= xts_cast6_setkey,
+			.encrypt	= xts_encrypt,
+			.decrypt	= xts_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "ecb(cast6)",
+	.cra_driver_name	= "ecb-cast6-avx",
+	.cra_priority		= 200,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= CAST6_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_helper_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= CAST6_MIN_KEY_SIZE,
+			.max_keysize	= CAST6_MAX_KEY_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "cbc(cast6)",
+	.cra_driver_name	= "cbc-cast6-avx",
+	.cra_priority		= 200,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= CAST6_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_helper_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= CAST6_MIN_KEY_SIZE,
+			.max_keysize	= CAST6_MAX_KEY_SIZE,
+			.ivsize		= CAST6_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= __ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "ctr(cast6)",
+	.cra_driver_name	= "ctr-cast6-avx",
+	.cra_priority		= 200,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= 1,
+	.cra_ctxsize		= sizeof(struct async_helper_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= CAST6_MIN_KEY_SIZE,
+			.max_keysize	= CAST6_MAX_KEY_SIZE,
+			.ivsize		= CAST6_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_encrypt,
+			.geniv		= "chainiv",
+		},
+	},
+}, {
+	.cra_name		= "lrw(cast6)",
+	.cra_driver_name	= "lrw-cast6-avx",
+	.cra_priority		= 200,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= CAST6_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_helper_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= CAST6_MIN_KEY_SIZE +
+					  CAST6_BLOCK_SIZE,
+			.max_keysize	= CAST6_MAX_KEY_SIZE +
+					  CAST6_BLOCK_SIZE,
+			.ivsize		= CAST6_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+}, {
+	.cra_name		= "xts(cast6)",
+	.cra_driver_name	= "xts-cast6-avx",
+	.cra_priority		= 200,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= CAST6_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_helper_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= ablk_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= CAST6_MIN_KEY_SIZE * 2,
+			.max_keysize	= CAST6_MAX_KEY_SIZE * 2,
+			.ivsize		= CAST6_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+} };
+
+static int __init cast6_init(void)
+{
+	u64 xcr0;
+
+	if (!cpu_has_avx || !cpu_has_osxsave) {
+		pr_info("AVX instructions are not detected.\n");
+		return -ENODEV;
+	}
+
+	xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
+	if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
+		pr_info("AVX detected but unusable.\n");
+		return -ENODEV;
+	}
+
+	return crypto_register_algs(cast6_algs, ARRAY_SIZE(cast6_algs));
+}
+
+static void __exit cast6_exit(void)
+{
+	crypto_unregister_algs(cast6_algs, ARRAY_SIZE(cast6_algs));
+}
+
+module_init(cast6_init);
+module_exit(cast6_exit);
+
+MODULE_DESCRIPTION("Cast6 Cipher Algorithm, AVX optimized");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("cast6");
diff --git a/arch/x86/crypto/ghash-clmulni-intel_glue.c b/arch/x86/crypto/ghash-clmulni-intel_glue.c
index b4bf0a6..6759dd1 100644
--- a/arch/x86/crypto/ghash-clmulni-intel_glue.c
+++ b/arch/x86/crypto/ghash-clmulni-intel_glue.c
@@ -150,7 +150,6 @@ static struct shash_alg ghash_alg = {
 		.cra_blocksize		= GHASH_BLOCK_SIZE,
 		.cra_ctxsize		= sizeof(struct ghash_ctx),
 		.cra_module		= THIS_MODULE,
-		.cra_list		= LIST_HEAD_INIT(ghash_alg.base.cra_list),
 	},
 };
 
@@ -288,7 +287,6 @@ static struct ahash_alg ghash_async_alg = {
 			.cra_blocksize		= GHASH_BLOCK_SIZE,
 			.cra_type		= &crypto_ahash_type,
 			.cra_module		= THIS_MODULE,
-			.cra_list		= LIST_HEAD_INIT(ghash_async_alg.halg.base.cra_list),
 			.cra_init		= ghash_async_init_tfm,
 			.cra_exit		= ghash_async_exit_tfm,
 		},
diff --git a/arch/x86/crypto/salsa20_glue.c b/arch/x86/crypto/salsa20_glue.c
index bccb76d..a3a3c02 100644
--- a/arch/x86/crypto/salsa20_glue.c
+++ b/arch/x86/crypto/salsa20_glue.c
@@ -97,7 +97,6 @@ static struct crypto_alg alg = {
 	.cra_ctxsize        =   sizeof(struct salsa20_ctx),
 	.cra_alignmask      =	3,
 	.cra_module         =   THIS_MODULE,
-	.cra_list           =   LIST_HEAD_INIT(alg.cra_list),
 	.cra_u              =   {
 		.blkcipher = {
 			.setkey         =   setkey,
diff --git a/arch/x86/crypto/serpent_avx_glue.c b/arch/x86/crypto/serpent_avx_glue.c
index b36bdac..3f543a0 100644
--- a/arch/x86/crypto/serpent_avx_glue.c
+++ b/arch/x86/crypto/serpent_avx_glue.c
@@ -390,7 +390,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[0].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
@@ -410,7 +409,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[1].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
@@ -430,7 +428,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[2].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
@@ -451,7 +448,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[3].cra_list),
 	.cra_exit		= lrw_exit_tfm,
 	.cra_u = {
 		.blkcipher = {
@@ -475,7 +471,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[4].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= SERPENT_MIN_KEY_SIZE * 2,
@@ -496,7 +491,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_ablkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[5].cra_list),
 	.cra_init		= ablk_init,
 	.cra_exit		= ablk_exit,
 	.cra_u = {
@@ -518,7 +512,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_ablkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[6].cra_list),
 	.cra_init		= ablk_init,
 	.cra_exit		= ablk_exit,
 	.cra_u = {
@@ -541,7 +534,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_ablkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[7].cra_list),
 	.cra_init		= ablk_init,
 	.cra_exit		= ablk_exit,
 	.cra_u = {
@@ -565,7 +557,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_ablkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[8].cra_list),
 	.cra_init		= ablk_init,
 	.cra_exit		= ablk_exit,
 	.cra_u = {
@@ -590,7 +581,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_ablkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[9].cra_list),
 	.cra_init		= ablk_init,
 	.cra_exit		= ablk_exit,
 	.cra_u = {
diff --git a/arch/x86/crypto/serpent_sse2_glue.c b/arch/x86/crypto/serpent_sse2_glue.c
index d679c86..9107a99 100644
--- a/arch/x86/crypto/serpent_sse2_glue.c
+++ b/arch/x86/crypto/serpent_sse2_glue.c
@@ -393,7 +393,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[0].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
@@ -413,7 +412,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[1].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
@@ -433,7 +431,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[2].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= SERPENT_MIN_KEY_SIZE,
@@ -454,7 +451,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[3].cra_list),
 	.cra_exit		= lrw_exit_tfm,
 	.cra_u = {
 		.blkcipher = {
@@ -478,7 +474,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[4].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= SERPENT_MIN_KEY_SIZE * 2,
@@ -499,7 +494,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_ablkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[5].cra_list),
 	.cra_init		= ablk_init,
 	.cra_exit		= ablk_exit,
 	.cra_u = {
@@ -521,7 +515,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_ablkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[6].cra_list),
 	.cra_init		= ablk_init,
 	.cra_exit		= ablk_exit,
 	.cra_u = {
@@ -544,7 +537,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_ablkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[7].cra_list),
 	.cra_init		= ablk_init,
 	.cra_exit		= ablk_exit,
 	.cra_u = {
@@ -568,7 +560,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_ablkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[8].cra_list),
 	.cra_init		= ablk_init,
 	.cra_exit		= ablk_exit,
 	.cra_u = {
@@ -593,7 +584,6 @@ static struct crypto_alg serpent_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_ablkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(serpent_algs[9].cra_list),
 	.cra_init		= ablk_init,
 	.cra_exit		= ablk_exit,
 	.cra_u = {
diff --git a/arch/x86/crypto/twofish_avx_glue.c b/arch/x86/crypto/twofish_avx_glue.c
index 782b67d..e7708b5 100644
--- a/arch/x86/crypto/twofish_avx_glue.c
+++ b/arch/x86/crypto/twofish_avx_glue.c
@@ -378,7 +378,6 @@ static struct crypto_alg twofish_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(twofish_algs[0].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= TF_MIN_KEY_SIZE,
@@ -398,7 +397,6 @@ static struct crypto_alg twofish_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(twofish_algs[1].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= TF_MIN_KEY_SIZE,
@@ -418,7 +416,6 @@ static struct crypto_alg twofish_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(twofish_algs[2].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= TF_MIN_KEY_SIZE,
@@ -439,7 +436,6 @@ static struct crypto_alg twofish_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(twofish_algs[3].cra_list),
 	.cra_exit		= lrw_twofish_exit_tfm,
 	.cra_u = {
 		.blkcipher = {
@@ -463,7 +459,6 @@ static struct crypto_alg twofish_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(twofish_algs[4].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= TF_MIN_KEY_SIZE * 2,
@@ -484,7 +479,6 @@ static struct crypto_alg twofish_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_ablkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(twofish_algs[5].cra_list),
 	.cra_init		= ablk_init,
 	.cra_exit		= ablk_exit,
 	.cra_u = {
@@ -506,7 +500,6 @@ static struct crypto_alg twofish_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_ablkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(twofish_algs[6].cra_list),
 	.cra_init		= ablk_init,
 	.cra_exit		= ablk_exit,
 	.cra_u = {
@@ -529,7 +522,6 @@ static struct crypto_alg twofish_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_ablkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(twofish_algs[7].cra_list),
 	.cra_init		= ablk_init,
 	.cra_exit		= ablk_exit,
 	.cra_u = {
@@ -553,7 +545,6 @@ static struct crypto_alg twofish_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_ablkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(twofish_algs[8].cra_list),
 	.cra_init		= ablk_init,
 	.cra_exit		= ablk_exit,
 	.cra_u = {
@@ -578,7 +569,6 @@ static struct crypto_alg twofish_algs[10] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_ablkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(twofish_algs[9].cra_list),
 	.cra_init		= ablk_init,
 	.cra_exit		= ablk_exit,
 	.cra_u = {
diff --git a/arch/x86/crypto/twofish_glue.c b/arch/x86/crypto/twofish_glue.c
index 359ae08..0a52023 100644
--- a/arch/x86/crypto/twofish_glue.c
+++ b/arch/x86/crypto/twofish_glue.c
@@ -70,7 +70,6 @@ static struct crypto_alg alg = {
 	.cra_ctxsize		=	sizeof(struct twofish_ctx),
 	.cra_alignmask		=	0,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(alg.cra_list),
 	.cra_u			=	{
 		.cipher = {
 			.cia_min_keysize	=	TF_MIN_KEY_SIZE,
diff --git a/arch/x86/crypto/twofish_glue_3way.c b/arch/x86/crypto/twofish_glue_3way.c
index 15f9347..aa3eb35 100644
--- a/arch/x86/crypto/twofish_glue_3way.c
+++ b/arch/x86/crypto/twofish_glue_3way.c
@@ -342,7 +342,6 @@ static struct crypto_alg tf_algs[5] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(tf_algs[0].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= TF_MIN_KEY_SIZE,
@@ -362,7 +361,6 @@ static struct crypto_alg tf_algs[5] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(tf_algs[1].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= TF_MIN_KEY_SIZE,
@@ -383,7 +381,6 @@ static struct crypto_alg tf_algs[5] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(tf_algs[2].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= TF_MIN_KEY_SIZE,
@@ -404,7 +401,6 @@ static struct crypto_alg tf_algs[5] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(tf_algs[3].cra_list),
 	.cra_exit		= lrw_twofish_exit_tfm,
 	.cra_u = {
 		.blkcipher = {
@@ -426,7 +422,6 @@ static struct crypto_alg tf_algs[5] = { {
 	.cra_alignmask		= 0,
 	.cra_type		= &crypto_blkcipher_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(tf_algs[4].cra_list),
 	.cra_u = {
 		.blkcipher = {
 			.min_keysize	= TF_MIN_KEY_SIZE * 2,
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 09155d6..fc0e752 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -420,6 +420,8 @@ struct kvm_vcpu_arch {
 	unsigned int hw_tsc_khz;
 	unsigned int time_offset;
 	struct page *time_page;
+	/* set guest stopped flag in pvclock flags field */
+	bool pvclock_set_guest_stopped_request;
 
 	struct {
 		u64 msr_val;
@@ -500,11 +502,11 @@ struct kvm_vcpu_arch {
 };
 
 struct kvm_lpage_info {
-	unsigned long rmap_pde;
 	int write_count;
 };
 
 struct kvm_arch_memory_slot {
+	unsigned long *rmap[KVM_NR_PAGE_SIZES];
 	struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1];
 };
 
@@ -957,6 +959,7 @@ extern bool kvm_rebooting;
 
 #define KVM_ARCH_WANT_MMU_NOTIFIER
 int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end);
 int kvm_age_hva(struct kvm *kvm, unsigned long hva);
 int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
 void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
diff --git a/arch/x86/include/asm/kvm_para.h b/arch/x86/include/asm/kvm_para.h
index 2f7712e..20f5697 100644
--- a/arch/x86/include/asm/kvm_para.h
+++ b/arch/x86/include/asm/kvm_para.h
@@ -116,7 +116,7 @@ static inline bool kvm_check_and_clear_guest_paused(void)
  */
 #define KVM_HYPERCALL ".byte 0x0f,0x01,0xc1"
 
-/* For KVM hypercalls, a three-byte sequence of either the vmrun or the vmmrun
+/* For KVM hypercalls, a three-byte sequence of either the vmcall or the vmmcall
  * instruction.  The hypervisor may replace it with something else but only the
  * instructions are guaranteed to be supported.
  *
diff --git a/arch/x86/include/asm/rcu.h b/arch/x86/include/asm/rcu.h
new file mode 100644
index 0000000..439815b
--- /dev/null
+++ b/arch/x86/include/asm/rcu.h
@@ -0,0 +1,20 @@
+#ifndef _ASM_X86_RCU_H
+#define _ASM_X86_RCU_H
+
+#include <linux/rcupdate.h>
+#include <asm/ptrace.h>
+
+static inline void exception_enter(struct pt_regs *regs)
+{
+	rcu_user_exit();
+}
+
+static inline void exception_exit(struct pt_regs *regs)
+{
+#ifdef CONFIG_RCU_USER_QS
+	if (user_mode(regs))
+		rcu_user_enter();
+#endif
+}
+
+#endif
diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index b315a33..33692ea 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -12,8 +12,7 @@
  * Simple spin lock operations.  There are two variants, one clears IRQ's
  * on the local processor, one does not.
  *
- * These are fair FIFO ticket locks, which are currently limited to 256
- * CPUs.
+ * These are fair FIFO ticket locks, which support up to 2^16 CPUs.
  *
  * (the type definitions are in asm/spinlock_types.h)
  */
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index 89f794f..2d946e6 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -79,7 +79,6 @@ struct thread_info {
 #define TIF_SIGPENDING		2	/* signal pending */
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_SINGLESTEP		4	/* reenable singlestep on user return*/
-#define TIF_IRET		5	/* force IRET */
 #define TIF_SYSCALL_EMU		6	/* syscall emulation active */
 #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
 #define TIF_SECCOMP		8	/* secure computing */
@@ -89,6 +88,7 @@ struct thread_info {
 #define TIF_NOTSC		16	/* TSC is not accessible in userland */
 #define TIF_IA32		17	/* IA32 compatibility process */
 #define TIF_FORK		18	/* ret_from_fork */
+#define TIF_NOHZ		19	/* in adaptive nohz mode */
 #define TIF_MEMDIE		20	/* is terminating due to OOM killer */
 #define TIF_DEBUG		21	/* uses debug registers */
 #define TIF_IO_BITMAP		22	/* uses I/O bitmap */
@@ -104,7 +104,6 @@ struct thread_info {
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
-#define _TIF_IRET		(1 << TIF_IRET)
 #define _TIF_SYSCALL_EMU	(1 << TIF_SYSCALL_EMU)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP		(1 << TIF_SECCOMP)
@@ -114,6 +113,7 @@ struct thread_info {
 #define _TIF_NOTSC		(1 << TIF_NOTSC)
 #define _TIF_IA32		(1 << TIF_IA32)
 #define _TIF_FORK		(1 << TIF_FORK)
+#define _TIF_NOHZ		(1 << TIF_NOHZ)
 #define _TIF_DEBUG		(1 << TIF_DEBUG)
 #define _TIF_IO_BITMAP		(1 << TIF_IO_BITMAP)
 #define _TIF_FORCED_TF		(1 << TIF_FORCED_TF)
@@ -126,12 +126,13 @@ struct thread_info {
 /* work to do in syscall_trace_enter() */
 #define _TIF_WORK_SYSCALL_ENTRY	\
 	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | _TIF_SYSCALL_AUDIT |	\
-	 _TIF_SECCOMP | _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT)
+	 _TIF_SECCOMP | _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT |	\
+	 _TIF_NOHZ)
 
 /* work to do in syscall_trace_leave() */
 #define _TIF_WORK_SYSCALL_EXIT	\
 	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP |	\
-	 _TIF_SYSCALL_TRACEPOINT)
+	 _TIF_SYSCALL_TRACEPOINT | _TIF_NOHZ)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK							\
@@ -141,7 +142,8 @@ struct thread_info {
 
 /* work to do on any return to user space */
 #define _TIF_ALLWORK_MASK						\
-	((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT)
+	((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT |	\
+	_TIF_NOHZ)
 
 /* Only used for 64 bit */
 #define _TIF_DO_NOTIFY_MASK						\
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 9d92e19..f7e98a2 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -737,6 +737,72 @@ static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c,
 }
 #endif
 
+static void __cpuinit cpu_set_tlb_flushall_shift(struct cpuinfo_x86 *c)
+{
+	if (!cpu_has_invlpg)
+		return;
+
+	tlb_flushall_shift = 5;
+
+	if (c->x86 <= 0x11)
+		tlb_flushall_shift = 4;
+}
+
+static void __cpuinit cpu_detect_tlb_amd(struct cpuinfo_x86 *c)
+{
+	u32 ebx, eax, ecx, edx;
+	u16 mask = 0xfff;
+
+	if (c->x86 < 0xf)
+		return;
+
+	if (c->extended_cpuid_level < 0x80000006)
+		return;
+
+	cpuid(0x80000006, &eax, &ebx, &ecx, &edx);
+
+	tlb_lld_4k[ENTRIES] = (ebx >> 16) & mask;
+	tlb_lli_4k[ENTRIES] = ebx & mask;
+
+	/*
+	 * K8 doesn't have 2M/4M entries in the L2 TLB so read out the L1 TLB
+	 * characteristics from the CPUID function 0x80000005 instead.
+	 */
+	if (c->x86 == 0xf) {
+		cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
+		mask = 0xff;
+	}
+
+	/* Handle DTLB 2M and 4M sizes, fall back to L1 if L2 is disabled */
+	if (!((eax >> 16) & mask)) {
+		u32 a, b, c, d;
+
+		cpuid(0x80000005, &a, &b, &c, &d);
+		tlb_lld_2m[ENTRIES] = (a >> 16) & 0xff;
+	} else {
+		tlb_lld_2m[ENTRIES] = (eax >> 16) & mask;
+	}
+
+	/* a 4M entry uses two 2M entries */
+	tlb_lld_4m[ENTRIES] = tlb_lld_2m[ENTRIES] >> 1;
+
+	/* Handle ITLB 2M and 4M sizes, fall back to L1 if L2 is disabled */
+	if (!(eax & mask)) {
+		/* Erratum 658 */
+		if (c->x86 == 0x15 && c->x86_model <= 0x1f) {
+			tlb_lli_2m[ENTRIES] = 1024;
+		} else {
+			cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
+			tlb_lli_2m[ENTRIES] = eax & 0xff;
+		}
+	} else
+		tlb_lli_2m[ENTRIES] = eax & mask;
+
+	tlb_lli_4m[ENTRIES] = tlb_lli_2m[ENTRIES] >> 1;
+
+	cpu_set_tlb_flushall_shift(c);
+}
+
 static const struct cpu_dev __cpuinitconst amd_cpu_dev = {
 	.c_vendor	= "AMD",
 	.c_ident	= { "AuthenticAMD" },
@@ -756,6 +822,7 @@ static const struct cpu_dev __cpuinitconst amd_cpu_dev = {
 	.c_size_cache	= amd_size_cache,
 #endif
 	.c_early_init   = early_init_amd,
+	.c_detect_tlb	= cpu_detect_tlb_amd,
 	.c_bsp_init	= bsp_init_amd,
 	.c_init		= init_amd,
 	.c_x86_vendor	= X86_VENDOR_AMD,
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 46d8786..080f4a7 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -474,7 +474,7 @@ void __cpuinit cpu_detect_tlb(struct cpuinfo_x86 *c)
 
 	printk(KERN_INFO "Last level iTLB entries: 4KB %d, 2MB %d, 4MB %d\n" \
 		"Last level dTLB entries: 4KB %d, 2MB %d, 4MB %d\n"	     \
-		"tlb_flushall_shift is 0x%x\n",
+		"tlb_flushall_shift: %d\n",
 		tlb_lli_4k[ENTRIES], tlb_lli_2m[ENTRIES],
 		tlb_lli_4m[ENTRIES], tlb_lld_4k[ENTRIES],
 		tlb_lld_2m[ENTRIES], tlb_lld_4m[ENTRIES],
@@ -940,8 +940,7 @@ void __init identify_boot_cpu(void)
 #else
 	vgetcpu_set_mode();
 #endif
-	if (boot_cpu_data.cpuid_level >= 2)
-		cpu_detect_tlb(&boot_cpu_data);
+	cpu_detect_tlb(&boot_cpu_data);
 }
 
 void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 0a4ce29..198e019 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -648,6 +648,10 @@ static void __cpuinit intel_detect_tlb(struct cpuinfo_x86 *c)
 	int i, j, n;
 	unsigned int regs[4];
 	unsigned char *desc = (unsigned char *)regs;
+
+	if (c->cpuid_level < 2)
+		return;
+
 	/* Number of times to iterate */
 	n = cpuid_eax(2) & 0xFF;
 
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 623f288..e8310c8 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -612,6 +612,10 @@ work_notifysig:				# deal with pending signals and
 	movl %esp, %eax
 	jne work_notifysig_v86		# returning to kernel-space or
 					# vm86-space
+1:
+#else
+	movl %esp, %eax
+#endif
 	TRACE_IRQS_ON
 	ENABLE_INTERRUPTS(CLBR_NONE)
 	movb PT_CS(%esp), %bl
@@ -622,24 +626,15 @@ work_notifysig:				# deal with pending signals and
 	call do_notify_resume
 	jmp resume_userspace
 
+#ifdef CONFIG_VM86
 	ALIGN
 work_notifysig_v86:
 	pushl_cfi %ecx			# save ti_flags for do_notify_resume
 	call save_v86_state		# %eax contains pt_regs pointer
 	popl_cfi %ecx
 	movl %eax, %esp
-#else
-	movl %esp, %eax
+	jmp 1b
 #endif
-	TRACE_IRQS_ON
-	ENABLE_INTERRUPTS(CLBR_NONE)
-	movb PT_CS(%esp), %bl
-	andb $SEGMENT_RPL_MASK, %bl
-	cmpb $USER_RPL, %bl
-	jb resume_kernel
-	xorl %edx, %edx
-	call do_notify_resume
-	jmp resume_userspace
 END(work_pending)
 
 	# perform syscall exit tracing
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 69babd8..6230487 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -565,7 +565,7 @@ sysret_careful:
 	TRACE_IRQS_ON
 	ENABLE_INTERRUPTS(CLBR_NONE)
 	pushq_cfi %rdi
-	call schedule
+	call schedule_user
 	popq_cfi %rdi
 	jmp sysret_check
 
@@ -678,7 +678,7 @@ int_careful:
 	TRACE_IRQS_ON
 	ENABLE_INTERRUPTS(CLBR_NONE)
 	pushq_cfi %rdi
-	call schedule
+	call schedule_user
 	popq_cfi %rdi
 	DISABLE_INTERRUPTS(CLBR_NONE)
 	TRACE_IRQS_OFF
@@ -974,7 +974,7 @@ retint_careful:
 	TRACE_IRQS_ON
 	ENABLE_INTERRUPTS(CLBR_NONE)
 	pushq_cfi %rdi
-	call  schedule
+	call  schedule_user
 	popq_cfi %rdi
 	GET_THREAD_INFO(%rcx)
 	DISABLE_INTERRUPTS(CLBR_NONE)
@@ -1449,7 +1449,7 @@ paranoid_userspace:
 paranoid_schedule:
 	TRACE_IRQS_ON
 	ENABLE_INTERRUPTS(CLBR_ANY)
-	call schedule
+	call schedule_user
 	DISABLE_INTERRUPTS(CLBR_ANY)
 	TRACE_IRQS_OFF
 	jmp paranoid_userspace
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c
index 3f61904..836f832 100644
--- a/arch/x86/kernel/kgdb.c
+++ b/arch/x86/kernel/kgdb.c
@@ -746,7 +746,9 @@ void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
 int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
 {
 	int err;
+#ifdef CONFIG_DEBUG_RODATA
 	char opc[BREAK_INSTR_SIZE];
+#endif /* CONFIG_DEBUG_RODATA */
 
 	bpt->type = BP_BREAKPOINT;
 	err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr,
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index c1d61ee..1596cc8 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -354,6 +354,7 @@ static void kvm_pv_guest_cpu_reboot(void *unused)
 	if (kvm_para_has_feature(KVM_FEATURE_PV_EOI))
 		wrmsrl(MSR_KVM_PV_EOI_EN, 0);
 	kvm_pv_disable_apf();
+	kvm_disable_steal_time();
 }
 
 static int kvm_pv_reboot_notify(struct notifier_block *nb,
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index ef6a845..b89c39e 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -355,7 +355,7 @@ long sys_execve(const char __user *name,
 #ifdef CONFIG_X86_32
 	if (error == 0) {
 		/* Make sure we don't return using sysenter.. */
-                set_thread_flag(TIF_IRET);
+                set_thread_flag(TIF_NOTIFY_RESUME);
         }
 #endif
 
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index c4c6a5c..9f94f8e 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -21,6 +21,7 @@
 #include <linux/signal.h>
 #include <linux/perf_event.h>
 #include <linux/hw_breakpoint.h>
+#include <linux/rcupdate.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -1463,6 +1464,8 @@ long syscall_trace_enter(struct pt_regs *regs)
 {
 	long ret = 0;
 
+	rcu_user_exit();
+
 	/*
 	 * If we stepped into a sysenter/syscall insn, it trapped in
 	 * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP.
@@ -1526,4 +1529,6 @@ void syscall_trace_leave(struct pt_regs *regs)
 			!test_thread_flag(TIF_SYSCALL_EMU);
 	if (step || test_thread_flag(TIF_SYSCALL_TRACE))
 		tracehook_report_syscall_exit(regs, step);
+
+	rcu_user_enter();
 }
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index b280908..6b18d37 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -779,6 +779,8 @@ static void do_signal(struct pt_regs *regs)
 void
 do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 {
+	rcu_user_exit();
+
 #ifdef CONFIG_X86_MCE
 	/* notify userspace of pending MCEs */
 	if (thread_info_flags & _TIF_MCE_NOTIFY)
@@ -801,9 +803,7 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 	if (thread_info_flags & _TIF_USER_RETURN_NOTIFY)
 		fire_user_return_notifiers();
 
-#ifdef CONFIG_X86_32
-	clear_thread_flag(TIF_IRET);
-#endif /* CONFIG_X86_32 */
+	rcu_user_enter();
 }
 
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index b481341..ab82cbd 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -55,6 +55,7 @@
 #include <asm/i387.h>
 #include <asm/fpu-internal.h>
 #include <asm/mce.h>
+#include <asm/rcu.h>
 
 #include <asm/mach_traps.h>
 
@@ -180,11 +181,15 @@ vm86_trap:
 #define DO_ERROR(trapnr, signr, str, name)				\
 dotraplinkage void do_##name(struct pt_regs *regs, long error_code)	\
 {									\
-	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)	\
-							== NOTIFY_STOP)	\
+	exception_enter(regs);						\
+	if (notify_die(DIE_TRAP, str, regs, error_code,			\
+			trapnr, signr) == NOTIFY_STOP) {		\
+		exception_exit(regs);					\
 		return;							\
+	}								\
 	conditional_sti(regs);						\
 	do_trap(trapnr, signr, str, regs, error_code, NULL);		\
+	exception_exit(regs);						\
 }
 
 #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr)		\
@@ -195,11 +200,15 @@ dotraplinkage void do_##name(struct pt_regs *regs, long error_code)	\
 	info.si_errno = 0;						\
 	info.si_code = sicode;						\
 	info.si_addr = (void __user *)siaddr;				\
-	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)	\
-							== NOTIFY_STOP)	\
+	exception_enter(regs);						\
+	if (notify_die(DIE_TRAP, str, regs, error_code,			\
+			trapnr, signr) == NOTIFY_STOP) {		\
+		exception_exit(regs);					\
 		return;							\
+	}								\
 	conditional_sti(regs);						\
 	do_trap(trapnr, signr, str, regs, error_code, &info);		\
+	exception_exit(regs);						\
 }
 
 DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV,
@@ -312,6 +321,7 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
 	    ftrace_int3_handler(regs))
 		return;
 #endif
+	exception_enter(regs);
 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
 	if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
 				SIGTRAP) == NOTIFY_STOP)
@@ -331,6 +341,7 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
 	do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL);
 	preempt_conditional_cli(regs);
 	debug_stack_usage_dec();
+	exception_exit(regs);
 }
 
 #ifdef CONFIG_X86_64
@@ -391,6 +402,8 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
 	unsigned long dr6;
 	int si_code;
 
+	exception_enter(regs);
+
 	get_debugreg(dr6, 6);
 
 	/* Filter out all the reserved bits which are preset to 1 */
@@ -406,7 +419,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
 
 	/* Catch kmemcheck conditions first of all! */
 	if ((dr6 & DR_STEP) && kmemcheck_trap(regs))
-		return;
+		goto exit;
 
 	/* DR6 may or may not be cleared by the CPU */
 	set_debugreg(0, 6);
@@ -421,7 +434,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
 
 	if (notify_die(DIE_DEBUG, "debug", regs, PTR_ERR(&dr6), error_code,
 							SIGTRAP) == NOTIFY_STOP)
-		return;
+		goto exit;
 
 	/*
 	 * Let others (NMI) know that the debug stack is in use
@@ -437,7 +450,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
 					X86_TRAP_DB);
 		preempt_conditional_cli(regs);
 		debug_stack_usage_dec();
-		return;
+		goto exit;
 	}
 
 	/*
@@ -458,7 +471,8 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
 	preempt_conditional_cli(regs);
 	debug_stack_usage_dec();
 
-	return;
+exit:
+	exception_exit(regs);
 }
 
 /*
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c
index 54abcc0..20245a2 100644
--- a/arch/x86/kernel/vm86_32.c
+++ b/arch/x86/kernel/vm86_32.c
@@ -563,7 +563,7 @@ int handle_vm86_trap(struct kernel_vm86_regs *regs, long error_code, int trapno)
 			/* setting this flag forces the code in entry_32.S to
 			   call save_v86_state() and change the stack pointer
 			   to KVM86->regs32 */
-			set_thread_flag(TIF_IRET);
+			set_thread_flag(TIF_NOTIFY_RESUME);
 			return 0;
 		}
 		do_int(regs, trapno, (unsigned char __user *) (regs->pt.ss << 4), SP(regs));
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index a28f338..45c044f 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -37,6 +37,7 @@ config KVM
 	select TASK_DELAY_ACCT
 	select PERF_EVENTS
 	select HAVE_KVM_MSI
+	select HAVE_KVM_CPU_RELAX_INTERCEPT
 	---help---
 	  Support hosting fully virtualized guest machines using hardware
 	  virtualization extensions.  You will need a fairly recent
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
index 4f579e8..04d3040 100644
--- a/arch/x86/kvm/Makefile
+++ b/arch/x86/kvm/Makefile
@@ -12,7 +12,7 @@ kvm-$(CONFIG_IOMMU_API)	+= $(addprefix ../../../virt/kvm/, iommu.o)
 kvm-$(CONFIG_KVM_ASYNC_PF)	+= $(addprefix ../../../virt/kvm/, async_pf.o)
 
 kvm-y			+= x86.o mmu.o emulate.o i8259.o irq.o lapic.o \
-			   i8254.o timer.o cpuid.o pmu.o
+			   i8254.o cpuid.o pmu.o
 kvm-intel-y		+= vmx.o
 kvm-amd-y		+= svm.o
 
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 0595f13..b496da6 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -316,7 +316,7 @@ static int do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
 	}
 	case 7: {
 		entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
-		/* Mask ebx against host capbability word 9 */
+		/* Mask ebx against host capability word 9 */
 		if (index == 0) {
 			entry->ebx &= kvm_supported_word9_x86_features;
 			cpuid_mask(&entry->ebx, 9);
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 97d9a99..10f0136 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -642,7 +642,7 @@ static int __linearize(struct x86_emulate_ctxt *ctxt,
 			if (addr.ea > lim || (u32)(addr.ea + size - 1) > lim)
 				goto bad;
 		} else {
-			/* exapand-down segment */
+			/* expand-down segment */
 			if (addr.ea <= lim || (u32)(addr.ea + size - 1) <= lim)
 				goto bad;
 			lim = desc.d ? 0xffffffff : 0xffff;
@@ -1166,24 +1166,21 @@ static int read_emulated(struct x86_emulate_ctxt *ctxt,
 	int rc;
 	struct read_cache *mc = &ctxt->mem_read;
 
-	while (size) {
-		int n = min(size, 8u);
-		size -= n;
-		if (mc->pos < mc->end)
-			goto read_cached;
+	if (mc->pos < mc->end)
+		goto read_cached;
 
-		rc = ctxt->ops->read_emulated(ctxt, addr, mc->data + mc->end, n,
-					      &ctxt->exception);
-		if (rc != X86EMUL_CONTINUE)
-			return rc;
-		mc->end += n;
+	WARN_ON((mc->end + size) >= sizeof(mc->data));
 
-	read_cached:
-		memcpy(dest, mc->data + mc->pos, n);
-		mc->pos += n;
-		dest += n;
-		addr += n;
-	}
+	rc = ctxt->ops->read_emulated(ctxt, addr, mc->data + mc->end, size,
+				      &ctxt->exception);
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	mc->end += size;
+
+read_cached:
+	memcpy(dest, mc->data + mc->pos, size);
+	mc->pos += size;
 	return X86EMUL_CONTINUE;
 }
 
@@ -1383,7 +1380,7 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
 	err_code = selector & 0xfffc;
 	err_vec = GP_VECTOR;
 
-	/* can't load system descriptor into segment selecor */
+	/* can't load system descriptor into segment selector */
 	if (seg <= VCPU_SREG_GS && !seg_desc.s)
 		goto exception;
 
@@ -2038,12 +2035,6 @@ static void
 setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
 			struct desc_struct *cs, struct desc_struct *ss)
 {
-	u16 selector;
-
-	memset(cs, 0, sizeof(struct desc_struct));
-	ctxt->ops->get_segment(ctxt, &selector, cs, NULL, VCPU_SREG_CS);
-	memset(ss, 0, sizeof(struct desc_struct));
-
 	cs->l = 0;		/* will be adjusted later */
 	set_desc_base(cs, 0);	/* flat segment */
 	cs->g = 1;		/* 4kb granularity */
@@ -2053,6 +2044,7 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
 	cs->dpl = 0;		/* will be adjusted later */
 	cs->p = 1;
 	cs->d = 1;
+	cs->avl = 0;
 
 	set_desc_base(ss, 0);	/* flat segment */
 	set_desc_limit(ss, 0xfffff);	/* 4GB limit */
@@ -2062,6 +2054,8 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
 	ss->d = 1;		/* 32bit stack segment */
 	ss->dpl = 0;
 	ss->p = 1;
+	ss->l = 0;
+	ss->avl = 0;
 }
 
 static bool vendor_intel(struct x86_emulate_ctxt *ctxt)
@@ -2398,7 +2392,7 @@ static int load_state_from_tss16(struct x86_emulate_ctxt *ctxt,
 	set_segment_selector(ctxt, tss->ds, VCPU_SREG_DS);
 
 	/*
-	 * Now load segment descriptors. If fault happenes at this stage
+	 * Now load segment descriptors. If fault happens at this stage
 	 * it is handled in a context of new task
 	 */
 	ret = load_segment_descriptor(ctxt, tss->ldt, VCPU_SREG_LDTR);
@@ -2640,7 +2634,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
 	 *
 	 * 1. jmp/call/int to task gate: Check against DPL of the task gate
 	 * 2. Exception/IRQ/iret: No check is performed
-	 * 3. jmp/call to TSS: Check agains DPL of the TSS
+	 * 3. jmp/call to TSS: Check against DPL of the TSS
 	 */
 	if (reason == TASK_SWITCH_GATE) {
 		if (idt_index != -1) {
@@ -2681,7 +2675,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
 		ctxt->eflags = ctxt->eflags & ~X86_EFLAGS_NT;
 
 	/* set back link to prev task only if NT bit is set in eflags
-	   note that old_tss_sel is not used afetr this point */
+	   note that old_tss_sel is not used after this point */
 	if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE)
 		old_tss_sel = 0xffff;
 
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index adba28f..11300d2 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -108,7 +108,7 @@ static s64 __kpit_elapsed(struct kvm *kvm)
 	ktime_t remaining;
 	struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state;
 
-	if (!ps->pit_timer.period)
+	if (!ps->period)
 		return 0;
 
 	/*
@@ -120,9 +120,9 @@ static s64 __kpit_elapsed(struct kvm *kvm)
 	 * itself with the initial count and continues counting
 	 * from there.
 	 */
-	remaining = hrtimer_get_remaining(&ps->pit_timer.timer);
-	elapsed = ps->pit_timer.period - ktime_to_ns(remaining);
-	elapsed = mod_64(elapsed, ps->pit_timer.period);
+	remaining = hrtimer_get_remaining(&ps->timer);
+	elapsed = ps->period - ktime_to_ns(remaining);
+	elapsed = mod_64(elapsed, ps->period);
 
 	return elapsed;
 }
@@ -238,12 +238,12 @@ static void kvm_pit_ack_irq(struct kvm_irq_ack_notifier *kian)
 	int value;
 
 	spin_lock(&ps->inject_lock);
-	value = atomic_dec_return(&ps->pit_timer.pending);
+	value = atomic_dec_return(&ps->pending);
 	if (value < 0)
 		/* spurious acks can be generated if, for example, the
 		 * PIC is being reset.  Handle it gracefully here
 		 */
-		atomic_inc(&ps->pit_timer.pending);
+		atomic_inc(&ps->pending);
 	else if (value > 0)
 		/* in this case, we had multiple outstanding pit interrupts
 		 * that we needed to inject.  Reinject
@@ -261,28 +261,17 @@ void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu)
 	if (!kvm_vcpu_is_bsp(vcpu) || !pit)
 		return;
 
-	timer = &pit->pit_state.pit_timer.timer;
+	timer = &pit->pit_state.timer;
 	if (hrtimer_cancel(timer))
 		hrtimer_start_expires(timer, HRTIMER_MODE_ABS);
 }
 
 static void destroy_pit_timer(struct kvm_pit *pit)
 {
-	hrtimer_cancel(&pit->pit_state.pit_timer.timer);
+	hrtimer_cancel(&pit->pit_state.timer);
 	flush_kthread_work(&pit->expired);
 }
 
-static bool kpit_is_periodic(struct kvm_timer *ktimer)
-{
-	struct kvm_kpit_state *ps = container_of(ktimer, struct kvm_kpit_state,
-						 pit_timer);
-	return ps->is_periodic;
-}
-
-static struct kvm_timer_ops kpit_ops = {
-	.is_periodic = kpit_is_periodic,
-};
-
 static void pit_do_work(struct kthread_work *work)
 {
 	struct kvm_pit *pit = container_of(work, struct kvm_pit, expired);
@@ -322,16 +311,16 @@ static void pit_do_work(struct kthread_work *work)
 
 static enum hrtimer_restart pit_timer_fn(struct hrtimer *data)
 {
-	struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer);
-	struct kvm_pit *pt = ktimer->kvm->arch.vpit;
+	struct kvm_kpit_state *ps = container_of(data, struct kvm_kpit_state, timer);
+	struct kvm_pit *pt = ps->kvm->arch.vpit;
 
-	if (ktimer->reinject || !atomic_read(&ktimer->pending)) {
-		atomic_inc(&ktimer->pending);
+	if (ps->reinject || !atomic_read(&ps->pending)) {
+		atomic_inc(&ps->pending);
 		queue_kthread_work(&pt->worker, &pt->expired);
 	}
 
-	if (ktimer->t_ops->is_periodic(ktimer)) {
-		hrtimer_add_expires_ns(&ktimer->timer, ktimer->period);
+	if (ps->is_periodic) {
+		hrtimer_add_expires_ns(&ps->timer, ps->period);
 		return HRTIMER_RESTART;
 	} else
 		return HRTIMER_NORESTART;
@@ -340,7 +329,6 @@ static enum hrtimer_restart pit_timer_fn(struct hrtimer *data)
 static void create_pit_timer(struct kvm *kvm, u32 val, int is_period)
 {
 	struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state;
-	struct kvm_timer *pt = &ps->pit_timer;
 	s64 interval;
 
 	if (!irqchip_in_kernel(kvm) || ps->flags & KVM_PIT_FLAGS_HPET_LEGACY)
@@ -351,19 +339,18 @@ static void create_pit_timer(struct kvm *kvm, u32 val, int is_period)
 	pr_debug("create pit timer, interval is %llu nsec\n", interval);
 
 	/* TODO The new value only affected after the retriggered */
-	hrtimer_cancel(&pt->timer);
+	hrtimer_cancel(&ps->timer);
 	flush_kthread_work(&ps->pit->expired);
-	pt->period = interval;
+	ps->period = interval;
 	ps->is_periodic = is_period;
 
-	pt->timer.function = pit_timer_fn;
-	pt->t_ops = &kpit_ops;
-	pt->kvm = ps->pit->kvm;
+	ps->timer.function = pit_timer_fn;
+	ps->kvm = ps->pit->kvm;
 
-	atomic_set(&pt->pending, 0);
+	atomic_set(&ps->pending, 0);
 	ps->irq_ack = 1;
 
-	hrtimer_start(&pt->timer, ktime_add_ns(ktime_get(), interval),
+	hrtimer_start(&ps->timer, ktime_add_ns(ktime_get(), interval),
 		      HRTIMER_MODE_ABS);
 }
 
@@ -639,7 +626,7 @@ void kvm_pit_reset(struct kvm_pit *pit)
 	}
 	mutex_unlock(&pit->pit_state.lock);
 
-	atomic_set(&pit->pit_state.pit_timer.pending, 0);
+	atomic_set(&pit->pit_state.pending, 0);
 	pit->pit_state.irq_ack = 1;
 }
 
@@ -648,7 +635,7 @@ static void pit_mask_notifer(struct kvm_irq_mask_notifier *kimn, bool mask)
 	struct kvm_pit *pit = container_of(kimn, struct kvm_pit, mask_notifier);
 
 	if (!mask) {
-		atomic_set(&pit->pit_state.pit_timer.pending, 0);
+		atomic_set(&pit->pit_state.pending, 0);
 		pit->pit_state.irq_ack = 1;
 	}
 }
@@ -706,12 +693,11 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
 
 	pit_state = &pit->pit_state;
 	pit_state->pit = pit;
-	hrtimer_init(&pit_state->pit_timer.timer,
-		     CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+	hrtimer_init(&pit_state->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
 	pit_state->irq_ack_notifier.gsi = 0;
 	pit_state->irq_ack_notifier.irq_acked = kvm_pit_ack_irq;
 	kvm_register_irq_ack_notifier(kvm, &pit_state->irq_ack_notifier);
-	pit_state->pit_timer.reinject = true;
+	pit_state->reinject = true;
 	mutex_unlock(&pit->pit_state.lock);
 
 	kvm_pit_reset(pit);
@@ -761,7 +747,7 @@ void kvm_free_pit(struct kvm *kvm)
 		kvm_unregister_irq_ack_notifier(kvm,
 				&kvm->arch.vpit->pit_state.irq_ack_notifier);
 		mutex_lock(&kvm->arch.vpit->pit_state.lock);
-		timer = &kvm->arch.vpit->pit_state.pit_timer.timer;
+		timer = &kvm->arch.vpit->pit_state.timer;
 		hrtimer_cancel(timer);
 		flush_kthread_work(&kvm->arch.vpit->expired);
 		kthread_stop(kvm->arch.vpit->worker_task);
diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h
index fdf4042..dd1b16b 100644
--- a/arch/x86/kvm/i8254.h
+++ b/arch/x86/kvm/i8254.h
@@ -24,8 +24,12 @@ struct kvm_kpit_channel_state {
 struct kvm_kpit_state {
 	struct kvm_kpit_channel_state channels[3];
 	u32 flags;
-	struct kvm_timer pit_timer;
 	bool is_periodic;
+	s64 period; 				/* unit: ns */
+	struct hrtimer timer;
+	atomic_t pending;			/* accumulated triggered timers */
+	bool reinject;
+	struct kvm *kvm;
 	u32    speaker_data_on;
 	struct mutex lock;
 	struct kvm_pit *pit;
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c
index e498b18..90c84f9 100644
--- a/arch/x86/kvm/i8259.c
+++ b/arch/x86/kvm/i8259.c
@@ -190,17 +190,17 @@ void kvm_pic_update_irq(struct kvm_pic *s)
 
 int kvm_pic_set_irq(struct kvm_pic *s, int irq, int irq_source_id, int level)
 {
-	int ret = -1;
+	int ret, irq_level;
+
+	BUG_ON(irq < 0 || irq >= PIC_NUM_PINS);
 
 	pic_lock(s);
-	if (irq >= 0 && irq < PIC_NUM_PINS) {
-		int irq_level = __kvm_irq_line_state(&s->irq_states[irq],
-						     irq_source_id, level);
-		ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, irq_level);
-		pic_update_irq(s);
-		trace_kvm_pic_set_irq(irq >> 3, irq & 7, s->pics[irq >> 3].elcr,
-				      s->pics[irq >> 3].imr, ret == 0);
-	}
+	irq_level = __kvm_irq_line_state(&s->irq_states[irq],
+					 irq_source_id, level);
+	ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, irq_level);
+	pic_update_irq(s);
+	trace_kvm_pic_set_irq(irq >> 3, irq & 7, s->pics[irq >> 3].elcr,
+			      s->pics[irq >> 3].imr, ret == 0);
 	pic_unlock(s);
 
 	return ret;
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
index 2086f2b..2d03568 100644
--- a/arch/x86/kvm/irq.h
+++ b/arch/x86/kvm/irq.h
@@ -70,7 +70,7 @@ struct kvm_pic {
 	struct kvm_io_device dev_slave;
 	struct kvm_io_device dev_eclr;
 	void (*ack_notifier)(void *opaque, int irq);
-	unsigned long irq_states[16];
+	unsigned long irq_states[PIC_NUM_PINS];
 };
 
 struct kvm_pic *kvm_create_pic(struct kvm *kvm);
diff --git a/arch/x86/kvm/kvm_timer.h b/arch/x86/kvm/kvm_timer.h
deleted file mode 100644
index 497dbaa..0000000
--- a/arch/x86/kvm/kvm_timer.h
+++ /dev/null
@@ -1,18 +0,0 @@
-
-struct kvm_timer {
-	struct hrtimer timer;
-	s64 period; 				/* unit: ns */
-	u32 timer_mode_mask;
-	u64 tscdeadline;
-	atomic_t pending;			/* accumulated triggered timers */
-	bool reinject;
-	struct kvm_timer_ops *t_ops;
-	struct kvm *kvm;
-	struct kvm_vcpu *vcpu;
-};
-
-struct kvm_timer_ops {
-	bool (*is_periodic)(struct kvm_timer *);
-};
-
-enum hrtimer_restart kvm_timer_fn(struct hrtimer *data);
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index ce87878..18d149d 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -34,6 +34,7 @@
 #include <asm/current.h>
 #include <asm/apicdef.h>
 #include <linux/atomic.h>
+#include <linux/jump_label.h>
 #include "kvm_cache_regs.h"
 #include "irq.h"
 #include "trace.h"
@@ -72,11 +73,6 @@
 static unsigned int min_timer_period_us = 500;
 module_param(min_timer_period_us, uint, S_IRUGO | S_IWUSR);
 
-static inline u32 apic_get_reg(struct kvm_lapic *apic, int reg_off)
-{
-	return *((u32 *) (apic->regs + reg_off));
-}
-
 static inline void apic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val)
 {
 	*((u32 *) (apic->regs + reg_off)) = val;
@@ -117,19 +113,23 @@ static inline int __apic_test_and_clear_vector(int vec, void *bitmap)
 	return __test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
 }
 
-static inline int apic_hw_enabled(struct kvm_lapic *apic)
-{
-	return (apic)->vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE;
-}
+struct static_key_deferred apic_hw_disabled __read_mostly;
+struct static_key_deferred apic_sw_disabled __read_mostly;
 
-static inline int  apic_sw_enabled(struct kvm_lapic *apic)
+static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val)
 {
-	return apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED;
+	if ((kvm_apic_get_reg(apic, APIC_SPIV) ^ val) & APIC_SPIV_APIC_ENABLED) {
+		if (val & APIC_SPIV_APIC_ENABLED)
+			static_key_slow_dec_deferred(&apic_sw_disabled);
+		else
+			static_key_slow_inc(&apic_sw_disabled.key);
+	}
+	apic_set_reg(apic, APIC_SPIV, val);
 }
 
 static inline int apic_enabled(struct kvm_lapic *apic)
 {
-	return apic_sw_enabled(apic) &&	apic_hw_enabled(apic);
+	return kvm_apic_sw_enabled(apic) &&	kvm_apic_hw_enabled(apic);
 }
 
 #define LVT_MASK	\
@@ -141,34 +141,34 @@ static inline int apic_enabled(struct kvm_lapic *apic)
 
 static inline int kvm_apic_id(struct kvm_lapic *apic)
 {
-	return (apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
+	return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
 }
 
 static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type)
 {
-	return !(apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED);
+	return !(kvm_apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED);
 }
 
 static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type)
 {
-	return apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK;
+	return kvm_apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK;
 }
 
 static inline int apic_lvtt_oneshot(struct kvm_lapic *apic)
 {
-	return ((apic_get_reg(apic, APIC_LVTT) &
+	return ((kvm_apic_get_reg(apic, APIC_LVTT) &
 		apic->lapic_timer.timer_mode_mask) == APIC_LVT_TIMER_ONESHOT);
 }
 
 static inline int apic_lvtt_period(struct kvm_lapic *apic)
 {
-	return ((apic_get_reg(apic, APIC_LVTT) &
+	return ((kvm_apic_get_reg(apic, APIC_LVTT) &
 		apic->lapic_timer.timer_mode_mask) == APIC_LVT_TIMER_PERIODIC);
 }
 
 static inline int apic_lvtt_tscdeadline(struct kvm_lapic *apic)
 {
-	return ((apic_get_reg(apic, APIC_LVTT) &
+	return ((kvm_apic_get_reg(apic, APIC_LVTT) &
 		apic->lapic_timer.timer_mode_mask) ==
 			APIC_LVT_TIMER_TSCDEADLINE);
 }
@@ -184,7 +184,7 @@ void kvm_apic_set_version(struct kvm_vcpu *vcpu)
 	struct kvm_cpuid_entry2 *feat;
 	u32 v = APIC_VERSION;
 
-	if (!irqchip_in_kernel(vcpu->kvm))
+	if (!kvm_vcpu_has_lapic(vcpu))
 		return;
 
 	feat = kvm_find_cpuid_entry(apic->vcpu, 0x1, 0);
@@ -285,7 +285,6 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic)
 
 int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
 {
-	struct kvm_lapic *apic = vcpu->arch.apic;
 	int highest_irr;
 
 	/* This may race with setting of irr in __apic_accept_irq() and
@@ -293,9 +292,9 @@ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
 	 * will cause vmexit immediately and the value will be recalculated
 	 * on the next vmentry.
 	 */
-	if (!apic)
+	if (!kvm_vcpu_has_lapic(vcpu))
 		return 0;
-	highest_irr = apic_find_highest_irr(apic);
+	highest_irr = apic_find_highest_irr(vcpu->arch.apic);
 
 	return highest_irr;
 }
@@ -378,8 +377,8 @@ static void apic_update_ppr(struct kvm_lapic *apic)
 	u32 tpr, isrv, ppr, old_ppr;
 	int isr;
 
-	old_ppr = apic_get_reg(apic, APIC_PROCPRI);
-	tpr = apic_get_reg(apic, APIC_TASKPRI);
+	old_ppr = kvm_apic_get_reg(apic, APIC_PROCPRI);
+	tpr = kvm_apic_get_reg(apic, APIC_TASKPRI);
 	isr = apic_find_highest_isr(apic);
 	isrv = (isr != -1) ? isr : 0;
 
@@ -415,13 +414,13 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
 	u32 logical_id;
 
 	if (apic_x2apic_mode(apic)) {
-		logical_id = apic_get_reg(apic, APIC_LDR);
+		logical_id = kvm_apic_get_reg(apic, APIC_LDR);
 		return logical_id & mda;
 	}
 
-	logical_id = GET_APIC_LOGICAL_ID(apic_get_reg(apic, APIC_LDR));
+	logical_id = GET_APIC_LOGICAL_ID(kvm_apic_get_reg(apic, APIC_LDR));
 
-	switch (apic_get_reg(apic, APIC_DFR)) {
+	switch (kvm_apic_get_reg(apic, APIC_DFR)) {
 	case APIC_DFR_FLAT:
 		if (logical_id & mda)
 			result = 1;
@@ -433,7 +432,7 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
 		break;
 	default:
 		apic_debug("Bad DFR vcpu %d: %08x\n",
-			   apic->vcpu->vcpu_id, apic_get_reg(apic, APIC_DFR));
+			   apic->vcpu->vcpu_id, kvm_apic_get_reg(apic, APIC_DFR));
 		break;
 	}
 
@@ -591,7 +590,7 @@ static int apic_set_eoi(struct kvm_lapic *apic)
 	apic_clear_isr(vector, apic);
 	apic_update_ppr(apic);
 
-	if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) &&
+	if (!(kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) &&
 	    kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) {
 		int trigger_mode;
 		if (apic_test_vector(vector, apic->regs + APIC_TMR))
@@ -606,8 +605,8 @@ static int apic_set_eoi(struct kvm_lapic *apic)
 
 static void apic_send_ipi(struct kvm_lapic *apic)
 {
-	u32 icr_low = apic_get_reg(apic, APIC_ICR);
-	u32 icr_high = apic_get_reg(apic, APIC_ICR2);
+	u32 icr_low = kvm_apic_get_reg(apic, APIC_ICR);
+	u32 icr_high = kvm_apic_get_reg(apic, APIC_ICR2);
 	struct kvm_lapic_irq irq;
 
 	irq.vector = icr_low & APIC_VECTOR_MASK;
@@ -642,7 +641,7 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic)
 	ASSERT(apic != NULL);
 
 	/* if initial count is 0, current count should also be 0 */
-	if (apic_get_reg(apic, APIC_TMICT) == 0)
+	if (kvm_apic_get_reg(apic, APIC_TMICT) == 0)
 		return 0;
 
 	remaining = hrtimer_get_remaining(&apic->lapic_timer.timer);
@@ -696,13 +695,15 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
 
 		val = apic_get_tmcct(apic);
 		break;
-
+	case APIC_PROCPRI:
+		apic_update_ppr(apic);
+		val = kvm_apic_get_reg(apic, offset);
+		break;
 	case APIC_TASKPRI:
 		report_tpr_access(apic, false);
 		/* fall thru */
 	default:
-		apic_update_ppr(apic);
-		val = apic_get_reg(apic, offset);
+		val = kvm_apic_get_reg(apic, offset);
 		break;
 	}
 
@@ -719,7 +720,7 @@ static int apic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
 {
 	unsigned char alignment = offset & 0xf;
 	u32 result;
-	/* this bitmask has a bit cleared for each reserver register */
+	/* this bitmask has a bit cleared for each reserved register */
 	static const u64 rmask = 0x43ff01ffffffe70cULL;
 
 	if ((alignment + len) > 4) {
@@ -754,7 +755,7 @@ static int apic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
 
 static int apic_mmio_in_range(struct kvm_lapic *apic, gpa_t addr)
 {
-	return apic_hw_enabled(apic) &&
+	return kvm_apic_hw_enabled(apic) &&
 	    addr >= apic->base_address &&
 	    addr < apic->base_address + LAPIC_MMIO_LENGTH;
 }
@@ -777,7 +778,7 @@ static void update_divide_count(struct kvm_lapic *apic)
 {
 	u32 tmp1, tmp2, tdcr;
 
-	tdcr = apic_get_reg(apic, APIC_TDCR);
+	tdcr = kvm_apic_get_reg(apic, APIC_TDCR);
 	tmp1 = tdcr & 0xf;
 	tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1;
 	apic->divide_count = 0x1 << (tmp2 & 0x7);
@@ -792,9 +793,9 @@ static void start_apic_timer(struct kvm_lapic *apic)
 	atomic_set(&apic->lapic_timer.pending, 0);
 
 	if (apic_lvtt_period(apic) || apic_lvtt_oneshot(apic)) {
-		/* lapic timer in oneshot or peroidic mode */
+		/* lapic timer in oneshot or periodic mode */
 		now = apic->lapic_timer.timer.base->get_time();
-		apic->lapic_timer.period = (u64)apic_get_reg(apic, APIC_TMICT)
+		apic->lapic_timer.period = (u64)kvm_apic_get_reg(apic, APIC_TMICT)
 			    * APIC_BUS_CYCLE_NS * apic->divide_count;
 
 		if (!apic->lapic_timer.period)
@@ -826,7 +827,7 @@ static void start_apic_timer(struct kvm_lapic *apic)
 			   "timer initial count 0x%x, period %lldns, "
 			   "expire @ 0x%016" PRIx64 ".\n", __func__,
 			   APIC_BUS_CYCLE_NS, ktime_to_ns(now),
-			   apic_get_reg(apic, APIC_TMICT),
+			   kvm_apic_get_reg(apic, APIC_TMICT),
 			   apic->lapic_timer.period,
 			   ktime_to_ns(ktime_add_ns(now,
 					apic->lapic_timer.period)));
@@ -858,7 +859,7 @@ static void start_apic_timer(struct kvm_lapic *apic)
 
 static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val)
 {
-	int nmi_wd_enabled = apic_lvt_nmi_mode(apic_get_reg(apic, APIC_LVT0));
+	int nmi_wd_enabled = apic_lvt_nmi_mode(kvm_apic_get_reg(apic, APIC_LVT0));
 
 	if (apic_lvt_nmi_mode(lvt0_val)) {
 		if (!nmi_wd_enabled) {
@@ -909,15 +910,15 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
 
 	case APIC_SPIV: {
 		u32 mask = 0x3ff;
-		if (apic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI)
+		if (kvm_apic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI)
 			mask |= APIC_SPIV_DIRECTED_EOI;
-		apic_set_reg(apic, APIC_SPIV, val & mask);
+		apic_set_spiv(apic, val & mask);
 		if (!(val & APIC_SPIV_APIC_ENABLED)) {
 			int i;
 			u32 lvt_val;
 
 			for (i = 0; i < APIC_LVT_NUM; i++) {
-				lvt_val = apic_get_reg(apic,
+				lvt_val = kvm_apic_get_reg(apic,
 						       APIC_LVTT + 0x10 * i);
 				apic_set_reg(apic, APIC_LVTT + 0x10 * i,
 					     lvt_val | APIC_LVT_MASKED);
@@ -946,7 +947,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
 	case APIC_LVT1:
 	case APIC_LVTERR:
 		/* TODO: Check vector */
-		if (!apic_sw_enabled(apic))
+		if (!kvm_apic_sw_enabled(apic))
 			val |= APIC_LVT_MASKED;
 
 		val &= apic_lvt_mask[(reg - APIC_LVTT) >> 4];
@@ -955,12 +956,12 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
 		break;
 
 	case APIC_LVTT:
-		if ((apic_get_reg(apic, APIC_LVTT) &
+		if ((kvm_apic_get_reg(apic, APIC_LVTT) &
 		    apic->lapic_timer.timer_mode_mask) !=
 		   (val & apic->lapic_timer.timer_mode_mask))
 			hrtimer_cancel(&apic->lapic_timer.timer);
 
-		if (!apic_sw_enabled(apic))
+		if (!kvm_apic_sw_enabled(apic))
 			val |= APIC_LVT_MASKED;
 		val &= (apic_lvt_mask[0] | apic->lapic_timer.timer_mode_mask);
 		apic_set_reg(apic, APIC_LVTT, val);
@@ -1039,24 +1040,30 @@ static int apic_mmio_write(struct kvm_io_device *this,
 
 void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu)
 {
-	struct kvm_lapic *apic = vcpu->arch.apic;
-
-	if (apic)
+	if (kvm_vcpu_has_lapic(vcpu))
 		apic_reg_write(vcpu->arch.apic, APIC_EOI, 0);
 }
 EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi);
 
 void kvm_free_lapic(struct kvm_vcpu *vcpu)
 {
+	struct kvm_lapic *apic = vcpu->arch.apic;
+
 	if (!vcpu->arch.apic)
 		return;
 
-	hrtimer_cancel(&vcpu->arch.apic->lapic_timer.timer);
+	hrtimer_cancel(&apic->lapic_timer.timer);
+
+	if (!(vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE))
+		static_key_slow_dec_deferred(&apic_hw_disabled);
+
+	if (!(kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED))
+		static_key_slow_dec_deferred(&apic_sw_disabled);
 
-	if (vcpu->arch.apic->regs)
-		free_page((unsigned long)vcpu->arch.apic->regs);
+	if (apic->regs)
+		free_page((unsigned long)apic->regs);
 
-	kfree(vcpu->arch.apic);
+	kfree(apic);
 }
 
 /*
@@ -1068,10 +1075,9 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu)
 u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu)
 {
 	struct kvm_lapic *apic = vcpu->arch.apic;
-	if (!apic)
-		return 0;
 
-	if (apic_lvtt_oneshot(apic) || apic_lvtt_period(apic))
+	if (!kvm_vcpu_has_lapic(vcpu) || apic_lvtt_oneshot(apic) ||
+			apic_lvtt_period(apic))
 		return 0;
 
 	return apic->lapic_timer.tscdeadline;
@@ -1080,10 +1086,9 @@ u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu)
 void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data)
 {
 	struct kvm_lapic *apic = vcpu->arch.apic;
-	if (!apic)
-		return;
 
-	if (apic_lvtt_oneshot(apic) || apic_lvtt_period(apic))
+	if (!kvm_vcpu_has_lapic(vcpu) || apic_lvtt_oneshot(apic) ||
+			apic_lvtt_period(apic))
 		return;
 
 	hrtimer_cancel(&apic->lapic_timer.timer);
@@ -1095,20 +1100,21 @@ void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8)
 {
 	struct kvm_lapic *apic = vcpu->arch.apic;
 
-	if (!apic)
+	if (!kvm_vcpu_has_lapic(vcpu))
 		return;
+
 	apic_set_tpr(apic, ((cr8 & 0x0f) << 4)
-		     | (apic_get_reg(apic, APIC_TASKPRI) & 4));
+		     | (kvm_apic_get_reg(apic, APIC_TASKPRI) & 4));
 }
 
 u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
 {
-	struct kvm_lapic *apic = vcpu->arch.apic;
 	u64 tpr;
 
-	if (!apic)
+	if (!kvm_vcpu_has_lapic(vcpu))
 		return 0;
-	tpr = (u64) apic_get_reg(apic, APIC_TASKPRI);
+
+	tpr = (u64) kvm_apic_get_reg(vcpu->arch.apic, APIC_TASKPRI);
 
 	return (tpr & 0xf0) >> 4;
 }
@@ -1123,6 +1129,14 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
 		return;
 	}
 
+	/* update jump label if enable bit changes */
+	if ((vcpu->arch.apic_base ^ value) & MSR_IA32_APICBASE_ENABLE) {
+		if (value & MSR_IA32_APICBASE_ENABLE)
+			static_key_slow_dec_deferred(&apic_hw_disabled);
+		else
+			static_key_slow_inc(&apic_hw_disabled.key);
+	}
+
 	if (!kvm_vcpu_is_bsp(apic->vcpu))
 		value &= ~MSR_IA32_APICBASE_BSP;
 
@@ -1164,7 +1178,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
 		     SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT));
 
 	apic_set_reg(apic, APIC_DFR, 0xffffffffU);
-	apic_set_reg(apic, APIC_SPIV, 0xff);
+	apic_set_spiv(apic, 0xff);
 	apic_set_reg(apic, APIC_TASKPRI, 0);
 	apic_set_reg(apic, APIC_LDR, 0);
 	apic_set_reg(apic, APIC_ESR, 0);
@@ -1183,7 +1197,8 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
 	update_divide_count(apic);
 	atomic_set(&apic->lapic_timer.pending, 0);
 	if (kvm_vcpu_is_bsp(vcpu))
-		vcpu->arch.apic_base |= MSR_IA32_APICBASE_BSP;
+		kvm_lapic_set_base(vcpu,
+				vcpu->arch.apic_base | MSR_IA32_APICBASE_BSP);
 	vcpu->arch.pv_eoi.msr_val = 0;
 	apic_update_ppr(apic);
 
@@ -1196,45 +1211,34 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
 		   vcpu->arch.apic_base, apic->base_address);
 }
 
-bool kvm_apic_present(struct kvm_vcpu *vcpu)
-{
-	return vcpu->arch.apic && apic_hw_enabled(vcpu->arch.apic);
-}
-
-int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
-{
-	return kvm_apic_present(vcpu) && apic_sw_enabled(vcpu->arch.apic);
-}
-
 /*
  *----------------------------------------------------------------------
  * timer interface
  *----------------------------------------------------------------------
  */
 
-static bool lapic_is_periodic(struct kvm_timer *ktimer)
+static bool lapic_is_periodic(struct kvm_lapic *apic)
 {
-	struct kvm_lapic *apic = container_of(ktimer, struct kvm_lapic,
-					      lapic_timer);
 	return apic_lvtt_period(apic);
 }
 
 int apic_has_pending_timer(struct kvm_vcpu *vcpu)
 {
-	struct kvm_lapic *lapic = vcpu->arch.apic;
+	struct kvm_lapic *apic = vcpu->arch.apic;
 
-	if (lapic && apic_enabled(lapic) && apic_lvt_enabled(lapic, APIC_LVTT))
-		return atomic_read(&lapic->lapic_timer.pending);
+	if (kvm_vcpu_has_lapic(vcpu) && apic_enabled(apic) &&
+			apic_lvt_enabled(apic, APIC_LVTT))
+		return atomic_read(&apic->lapic_timer.pending);
 
 	return 0;
 }
 
 int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type)
 {
-	u32 reg = apic_get_reg(apic, lvt_type);
+	u32 reg = kvm_apic_get_reg(apic, lvt_type);
 	int vector, mode, trig_mode;
 
-	if (apic_hw_enabled(apic) && !(reg & APIC_LVT_MASKED)) {
+	if (kvm_apic_hw_enabled(apic) && !(reg & APIC_LVT_MASKED)) {
 		vector = reg & APIC_VECTOR_MASK;
 		mode = reg & APIC_MODE_MASK;
 		trig_mode = reg & APIC_LVT_LEVEL_TRIGGER;
@@ -1251,15 +1255,40 @@ void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu)
 		kvm_apic_local_deliver(apic, APIC_LVT0);
 }
 
-static struct kvm_timer_ops lapic_timer_ops = {
-	.is_periodic = lapic_is_periodic,
-};
-
 static const struct kvm_io_device_ops apic_mmio_ops = {
 	.read     = apic_mmio_read,
 	.write    = apic_mmio_write,
 };
 
+static enum hrtimer_restart apic_timer_fn(struct hrtimer *data)
+{
+	struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer);
+	struct kvm_lapic *apic = container_of(ktimer, struct kvm_lapic, lapic_timer);
+	struct kvm_vcpu *vcpu = apic->vcpu;
+	wait_queue_head_t *q = &vcpu->wq;
+
+	/*
+	 * There is a race window between reading and incrementing, but we do
+	 * not care about potentially losing timer events in the !reinject
+	 * case anyway. Note: KVM_REQ_PENDING_TIMER is implicitly checked
+	 * in vcpu_enter_guest.
+	 */
+	if (!atomic_read(&ktimer->pending)) {
+		atomic_inc(&ktimer->pending);
+		/* FIXME: this code should not know anything about vcpus */
+		kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu);
+	}
+
+	if (waitqueue_active(q))
+		wake_up_interruptible(q);
+
+	if (lapic_is_periodic(apic)) {
+		hrtimer_add_expires_ns(&ktimer->timer, ktimer->period);
+		return HRTIMER_RESTART;
+	} else
+		return HRTIMER_NORESTART;
+}
+
 int kvm_create_lapic(struct kvm_vcpu *vcpu)
 {
 	struct kvm_lapic *apic;
@@ -1283,14 +1312,17 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu)
 
 	hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC,
 		     HRTIMER_MODE_ABS);
-	apic->lapic_timer.timer.function = kvm_timer_fn;
-	apic->lapic_timer.t_ops = &lapic_timer_ops;
-	apic->lapic_timer.kvm = vcpu->kvm;
-	apic->lapic_timer.vcpu = vcpu;
+	apic->lapic_timer.timer.function = apic_timer_fn;
 
-	apic->base_address = APIC_DEFAULT_PHYS_BASE;
-	vcpu->arch.apic_base = APIC_DEFAULT_PHYS_BASE;
+	/*
+	 * APIC is created enabled. This will prevent kvm_lapic_set_base from
+	 * thinking that APIC satet has changed.
+	 */
+	vcpu->arch.apic_base = MSR_IA32_APICBASE_ENABLE;
+	kvm_lapic_set_base(vcpu,
+			APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE);
 
+	static_key_slow_inc(&apic_sw_disabled.key); /* sw disabled at reset */
 	kvm_lapic_reset(vcpu);
 	kvm_iodevice_init(&apic->dev, &apic_mmio_ops);
 
@@ -1306,23 +1338,23 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
 	struct kvm_lapic *apic = vcpu->arch.apic;
 	int highest_irr;
 
-	if (!apic || !apic_enabled(apic))
+	if (!kvm_vcpu_has_lapic(vcpu) || !apic_enabled(apic))
 		return -1;
 
 	apic_update_ppr(apic);
 	highest_irr = apic_find_highest_irr(apic);
 	if ((highest_irr == -1) ||
-	    ((highest_irr & 0xF0) <= apic_get_reg(apic, APIC_PROCPRI)))
+	    ((highest_irr & 0xF0) <= kvm_apic_get_reg(apic, APIC_PROCPRI)))
 		return -1;
 	return highest_irr;
 }
 
 int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu)
 {
-	u32 lvt0 = apic_get_reg(vcpu->arch.apic, APIC_LVT0);
+	u32 lvt0 = kvm_apic_get_reg(vcpu->arch.apic, APIC_LVT0);
 	int r = 0;
 
-	if (!apic_hw_enabled(vcpu->arch.apic))
+	if (!kvm_apic_hw_enabled(vcpu->arch.apic))
 		r = 1;
 	if ((lvt0 & APIC_LVT_MASKED) == 0 &&
 	    GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT)
@@ -1334,7 +1366,10 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
 {
 	struct kvm_lapic *apic = vcpu->arch.apic;
 
-	if (apic && atomic_read(&apic->lapic_timer.pending) > 0) {
+	if (!kvm_vcpu_has_lapic(vcpu))
+		return;
+
+	if (atomic_read(&apic->lapic_timer.pending) > 0) {
 		if (kvm_apic_local_deliver(apic, APIC_LVTT))
 			atomic_dec(&apic->lapic_timer.pending);
 	}
@@ -1354,12 +1389,15 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
 	return vector;
 }
 
-void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
+void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
+		struct kvm_lapic_state *s)
 {
 	struct kvm_lapic *apic = vcpu->arch.apic;
 
-	apic->base_address = vcpu->arch.apic_base &
-			     MSR_IA32_APICBASE_BASE;
+	kvm_lapic_set_base(vcpu, vcpu->arch.apic_base);
+	/* set SPIV separately to get count of SW disabled APICs right */
+	apic_set_spiv(apic, *((u32 *)(s->regs + APIC_SPIV)));
+	memcpy(vcpu->arch.apic->regs, s->regs, sizeof *s);
 	kvm_apic_set_version(vcpu);
 
 	apic_update_ppr(apic);
@@ -1374,13 +1412,12 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
 
 void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
 {
-	struct kvm_lapic *apic = vcpu->arch.apic;
 	struct hrtimer *timer;
 
-	if (!apic)
+	if (!kvm_vcpu_has_lapic(vcpu))
 		return;
 
-	timer = &apic->lapic_timer.timer;
+	timer = &vcpu->arch.apic->lapic_timer.timer;
 	if (hrtimer_cancel(timer))
 		hrtimer_start_expires(timer, HRTIMER_MODE_ABS);
 }
@@ -1478,7 +1515,7 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu)
 	if (!test_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention))
 		return;
 
-	tpr = apic_get_reg(apic, APIC_TASKPRI) & 0xff;
+	tpr = kvm_apic_get_reg(apic, APIC_TASKPRI) & 0xff;
 	max_irr = apic_find_highest_irr(apic);
 	if (max_irr < 0)
 		max_irr = 0;
@@ -1537,7 +1574,7 @@ int kvm_hv_vapic_msr_write(struct kvm_vcpu *vcpu, u32 reg, u64 data)
 {
 	struct kvm_lapic *apic = vcpu->arch.apic;
 
-	if (!irqchip_in_kernel(vcpu->kvm))
+	if (!kvm_vcpu_has_lapic(vcpu))
 		return 1;
 
 	/* if this is ICR write vector before command */
@@ -1551,7 +1588,7 @@ int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 reg, u64 *data)
 	struct kvm_lapic *apic = vcpu->arch.apic;
 	u32 low, high = 0;
 
-	if (!irqchip_in_kernel(vcpu->kvm))
+	if (!kvm_vcpu_has_lapic(vcpu))
 		return 1;
 
 	if (apic_reg_read(apic, reg, 4, &low))
@@ -1576,3 +1613,10 @@ int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data)
 	return kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.pv_eoi.data,
 					 addr);
 }
+
+void kvm_lapic_init(void)
+{
+	/* do not patch jump label more than once per second */
+	jump_label_rate_limit(&apic_hw_disabled, HZ);
+	jump_label_rate_limit(&apic_sw_disabled, HZ);
+}
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 4af5405..615a8b0 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -2,10 +2,17 @@
 #define __KVM_X86_LAPIC_H
 
 #include "iodev.h"
-#include "kvm_timer.h"
 
 #include <linux/kvm_host.h>
 
+struct kvm_timer {
+	struct hrtimer timer;
+	s64 period; 				/* unit: ns */
+	u32 timer_mode_mask;
+	u64 tscdeadline;
+	atomic_t pending;			/* accumulated triggered timers */
+};
+
 struct kvm_lapic {
 	unsigned long base_address;
 	struct kvm_io_device dev;
@@ -47,9 +54,8 @@ int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type);
 
 u64 kvm_get_apic_base(struct kvm_vcpu *vcpu);
 void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data);
-void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu);
-int kvm_lapic_enabled(struct kvm_vcpu *vcpu);
-bool kvm_apic_present(struct kvm_vcpu *vcpu);
+void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
+		struct kvm_lapic_state *s);
 int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
 
 u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu);
@@ -71,4 +77,48 @@ static inline bool kvm_hv_vapic_assist_page_enabled(struct kvm_vcpu *vcpu)
 }
 
 int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data);
+void kvm_lapic_init(void);
+
+static inline u32 kvm_apic_get_reg(struct kvm_lapic *apic, int reg_off)
+{
+	        return *((u32 *) (apic->regs + reg_off));
+}
+
+extern struct static_key kvm_no_apic_vcpu;
+
+static inline bool kvm_vcpu_has_lapic(struct kvm_vcpu *vcpu)
+{
+	if (static_key_false(&kvm_no_apic_vcpu))
+		return vcpu->arch.apic;
+	return true;
+}
+
+extern struct static_key_deferred apic_hw_disabled;
+
+static inline int kvm_apic_hw_enabled(struct kvm_lapic *apic)
+{
+	if (static_key_false(&apic_hw_disabled.key))
+		return apic->vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE;
+	return MSR_IA32_APICBASE_ENABLE;
+}
+
+extern struct static_key_deferred apic_sw_disabled;
+
+static inline int kvm_apic_sw_enabled(struct kvm_lapic *apic)
+{
+	if (static_key_false(&apic_sw_disabled.key))
+		return kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED;
+	return APIC_SPIV_APIC_ENABLED;
+}
+
+static inline bool kvm_apic_present(struct kvm_vcpu *vcpu)
+{
+	return kvm_vcpu_has_lapic(vcpu) && kvm_apic_hw_enabled(vcpu->arch.apic);
+}
+
+static inline int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
+{
+	return kvm_apic_present(vcpu) && kvm_apic_sw_enabled(vcpu->arch.apic);
+}
+
 #endif
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 01ca004..9651c2c 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -556,6 +556,14 @@ static int mmu_spte_clear_track_bits(u64 *sptep)
 		return 0;
 
 	pfn = spte_to_pfn(old_spte);
+
+	/*
+	 * KVM does not hold the refcount of the page used by
+	 * kvm mmu, before reclaiming the page, we should
+	 * unmap it from mmu first.
+	 */
+	WARN_ON(!kvm_is_mmio_pfn(pfn) && !page_count(pfn_to_page(pfn)));
+
 	if (!shadow_accessed_mask || old_spte & shadow_accessed_mask)
 		kvm_set_pfn_accessed(pfn);
 	if (!shadow_dirty_mask || (old_spte & shadow_dirty_mask))
@@ -960,13 +968,10 @@ static void pte_list_walk(unsigned long *pte_list, pte_list_walk_fn fn)
 static unsigned long *__gfn_to_rmap(gfn_t gfn, int level,
 				    struct kvm_memory_slot *slot)
 {
-	struct kvm_lpage_info *linfo;
-
-	if (likely(level == PT_PAGE_TABLE_LEVEL))
-		return &slot->rmap[gfn - slot->base_gfn];
+	unsigned long idx;
 
-	linfo = lpage_info_slot(gfn, slot, level);
-	return &linfo->rmap_pde;
+	idx = gfn_to_index(gfn, slot->base_gfn, level);
+	return &slot->arch.rmap[level - PT_PAGE_TABLE_LEVEL][idx];
 }
 
 /*
@@ -1173,7 +1178,8 @@ void kvm_mmu_write_protect_pt_masked(struct kvm *kvm,
 	unsigned long *rmapp;
 
 	while (mask) {
-		rmapp = &slot->rmap[gfn_offset + __ffs(mask)];
+		rmapp = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask),
+				      PT_PAGE_TABLE_LEVEL, slot);
 		__rmap_write_protect(kvm, rmapp, PT_PAGE_TABLE_LEVEL, false);
 
 		/* clear the first set bit */
@@ -1200,7 +1206,7 @@ static bool rmap_write_protect(struct kvm *kvm, u64 gfn)
 }
 
 static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
-			   unsigned long data)
+			   struct kvm_memory_slot *slot, unsigned long data)
 {
 	u64 *sptep;
 	struct rmap_iterator iter;
@@ -1218,7 +1224,7 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
 }
 
 static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
-			     unsigned long data)
+			     struct kvm_memory_slot *slot, unsigned long data)
 {
 	u64 *sptep;
 	struct rmap_iterator iter;
@@ -1259,43 +1265,67 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
 	return 0;
 }
 
-static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
-			  unsigned long data,
-			  int (*handler)(struct kvm *kvm, unsigned long *rmapp,
-					 unsigned long data))
+static int kvm_handle_hva_range(struct kvm *kvm,
+				unsigned long start,
+				unsigned long end,
+				unsigned long data,
+				int (*handler)(struct kvm *kvm,
+					       unsigned long *rmapp,
+					       struct kvm_memory_slot *slot,
+					       unsigned long data))
 {
 	int j;
-	int ret;
-	int retval = 0;
+	int ret = 0;
 	struct kvm_memslots *slots;
 	struct kvm_memory_slot *memslot;
 
 	slots = kvm_memslots(kvm);
 
 	kvm_for_each_memslot(memslot, slots) {
-		unsigned long start = memslot->userspace_addr;
-		unsigned long end;
+		unsigned long hva_start, hva_end;
+		gfn_t gfn_start, gfn_end;
+
+		hva_start = max(start, memslot->userspace_addr);
+		hva_end = min(end, memslot->userspace_addr +
+					(memslot->npages << PAGE_SHIFT));
+		if (hva_start >= hva_end)
+			continue;
+		/*
+		 * {gfn(page) | page intersects with [hva_start, hva_end)} =
+		 * {gfn_start, gfn_start+1, ..., gfn_end-1}.
+		 */
+		gfn_start = hva_to_gfn_memslot(hva_start, memslot);
+		gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot);
 
-		end = start + (memslot->npages << PAGE_SHIFT);
-		if (hva >= start && hva < end) {
-			gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT;
-			gfn_t gfn = memslot->base_gfn + gfn_offset;
+		for (j = PT_PAGE_TABLE_LEVEL;
+		     j < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++j) {
+			unsigned long idx, idx_end;
+			unsigned long *rmapp;
 
-			ret = handler(kvm, &memslot->rmap[gfn_offset], data);
+			/*
+			 * {idx(page_j) | page_j intersects with
+			 *  [hva_start, hva_end)} = {idx, idx+1, ..., idx_end}.
+			 */
+			idx = gfn_to_index(gfn_start, memslot->base_gfn, j);
+			idx_end = gfn_to_index(gfn_end - 1, memslot->base_gfn, j);
 
-			for (j = 0; j < KVM_NR_PAGE_SIZES - 1; ++j) {
-				struct kvm_lpage_info *linfo;
+			rmapp = __gfn_to_rmap(gfn_start, j, memslot);
 
-				linfo = lpage_info_slot(gfn, memslot,
-							PT_DIRECTORY_LEVEL + j);
-				ret |= handler(kvm, &linfo->rmap_pde, data);
-			}
-			trace_kvm_age_page(hva, memslot, ret);
-			retval |= ret;
+			for (; idx <= idx_end; ++idx)
+				ret |= handler(kvm, rmapp++, memslot, data);
 		}
 	}
 
-	return retval;
+	return ret;
+}
+
+static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
+			  unsigned long data,
+			  int (*handler)(struct kvm *kvm, unsigned long *rmapp,
+					 struct kvm_memory_slot *slot,
+					 unsigned long data))
+{
+	return kvm_handle_hva_range(kvm, hva, hva + 1, data, handler);
 }
 
 int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
@@ -1303,13 +1333,18 @@ int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
 	return kvm_handle_hva(kvm, hva, 0, kvm_unmap_rmapp);
 }
 
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
+{
+	return kvm_handle_hva_range(kvm, start, end, 0, kvm_unmap_rmapp);
+}
+
 void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
 {
 	kvm_handle_hva(kvm, hva, (unsigned long)&pte, kvm_set_pte_rmapp);
 }
 
 static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
-			 unsigned long data)
+			 struct kvm_memory_slot *slot, unsigned long data)
 {
 	u64 *sptep;
 	struct rmap_iterator uninitialized_var(iter);
@@ -1323,8 +1358,10 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
 	 * This has some overhead, but not as much as the cost of swapping
 	 * out actively used pages or breaking up actively used hugepages.
 	 */
-	if (!shadow_accessed_mask)
-		return kvm_unmap_rmapp(kvm, rmapp, data);
+	if (!shadow_accessed_mask) {
+		young = kvm_unmap_rmapp(kvm, rmapp, slot, data);
+		goto out;
+	}
 
 	for (sptep = rmap_get_first(*rmapp, &iter); sptep;
 	     sptep = rmap_get_next(&iter)) {
@@ -1336,12 +1373,14 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
 				 (unsigned long *)sptep);
 		}
 	}
-
+out:
+	/* @data has hva passed to kvm_age_hva(). */
+	trace_kvm_age_page(data, slot, young);
 	return young;
 }
 
 static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
-			      unsigned long data)
+			      struct kvm_memory_slot *slot, unsigned long data)
 {
 	u64 *sptep;
 	struct rmap_iterator iter;
@@ -1379,13 +1418,13 @@ static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
 
 	rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level);
 
-	kvm_unmap_rmapp(vcpu->kvm, rmapp, 0);
+	kvm_unmap_rmapp(vcpu->kvm, rmapp, NULL, 0);
 	kvm_flush_remote_tlbs(vcpu->kvm);
 }
 
 int kvm_age_hva(struct kvm *kvm, unsigned long hva)
 {
-	return kvm_handle_hva(kvm, hva, 0, kvm_age_rmapp);
+	return kvm_handle_hva(kvm, hva, hva, kvm_age_rmapp);
 }
 
 int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
@@ -2457,7 +2496,9 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
 				rmap_recycle(vcpu, sptep, gfn);
 		}
 	}
-	kvm_release_pfn_clean(pfn);
+
+	if (!is_error_pfn(pfn))
+		kvm_release_pfn_clean(pfn);
 }
 
 static void nonpaging_new_cr3(struct kvm_vcpu *vcpu)
@@ -2472,14 +2513,12 @@ static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn,
 	unsigned long hva;
 
 	slot = gfn_to_memslot_dirty_bitmap(vcpu, gfn, no_dirty_log);
-	if (!slot) {
-		get_page(fault_page);
-		return page_to_pfn(fault_page);
-	}
+	if (!slot)
+		return KVM_PFN_ERR_FAULT;
 
 	hva = gfn_to_hva_memslot(slot, gfn);
 
-	return hva_to_pfn_atomic(vcpu->kvm, hva);
+	return hva_to_pfn_atomic(hva);
 }
 
 static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu,
@@ -2611,8 +2650,7 @@ static void kvm_send_hwpoison_signal(unsigned long address, struct task_struct *
 
 static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, pfn_t pfn)
 {
-	kvm_release_pfn_clean(pfn);
-	if (is_hwpoison_pfn(pfn)) {
+	if (pfn == KVM_PFN_ERR_HWPOISON) {
 		kvm_send_hwpoison_signal(gfn_to_hva(vcpu->kvm, gfn), current);
 		return 0;
 	}
@@ -3236,8 +3274,6 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn,
 	if (!async)
 		return false; /* *pfn has correct page already */
 
-	put_page(pfn_to_page(*pfn));
-
 	if (!prefault && can_do_async_pf(vcpu)) {
 		trace_kvm_try_async_get_page(gva, gfn);
 		if (kvm_find_async_pf_gfn(vcpu, gfn)) {
diff --git a/arch/x86/kvm/mmu_audit.c b/arch/x86/kvm/mmu_audit.c
index 7d7d0b9..daff69e 100644
--- a/arch/x86/kvm/mmu_audit.c
+++ b/arch/x86/kvm/mmu_audit.c
@@ -116,10 +116,8 @@ static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level)
 	gfn = kvm_mmu_page_get_gfn(sp, sptep - sp->spt);
 	pfn = gfn_to_pfn_atomic(vcpu->kvm, gfn);
 
-	if (is_error_pfn(pfn)) {
-		kvm_release_pfn_clean(pfn);
+	if (is_error_pfn(pfn))
 		return;
-	}
 
 	hpa =  pfn << PAGE_SHIFT;
 	if ((*sptep & PT64_BASE_ADDR_MASK) != hpa)
@@ -190,7 +188,6 @@ static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp)
 
 static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp)
 {
-	struct kvm_memory_slot *slot;
 	unsigned long *rmapp;
 	u64 *sptep;
 	struct rmap_iterator iter;
@@ -198,8 +195,7 @@ static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp)
 	if (sp->role.direct || sp->unsync || sp->role.invalid)
 		return;
 
-	slot = gfn_to_memslot(kvm, sp->gfn);
-	rmapp = &slot->rmap[sp->gfn - slot->base_gfn];
+	rmapp = gfn_to_rmap(kvm, sp->gfn, PT_PAGE_TABLE_LEVEL);
 
 	for (sptep = rmap_get_first(*rmapp, &iter); sptep;
 	     sptep = rmap_get_next(&iter)) {
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index bb7cf01..bf8c42b 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -370,10 +370,8 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
 	pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte);
 	pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte, true);
 	pfn = gfn_to_pfn_atomic(vcpu->kvm, gpte_to_gfn(gpte));
-	if (mmu_invalid_pfn(pfn)) {
-		kvm_release_pfn_clean(pfn);
+	if (mmu_invalid_pfn(pfn))
 		return;
-	}
 
 	/*
 	 * we call mmu_set_spte() with host_writable = true because that
@@ -448,10 +446,8 @@ static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw,
 		gfn = gpte_to_gfn(gpte);
 		pfn = pte_prefetch_gfn_to_pfn(vcpu, gfn,
 				      pte_access & ACC_WRITE_MASK);
-		if (mmu_invalid_pfn(pfn)) {
-			kvm_release_pfn_clean(pfn);
+		if (mmu_invalid_pfn(pfn))
 			break;
-		}
 
 		mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0,
 			     NULL, PT_PAGE_TABLE_LEVEL, gfn,
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 9b7ec11..cfc258a 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -1,5 +1,5 @@
 /*
- * Kernel-based Virtual Machine -- Performane Monitoring Unit support
+ * Kernel-based Virtual Machine -- Performance Monitoring Unit support
  *
  * Copyright 2011 Red Hat, Inc. and/or its affiliates.
  *
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index baead95..31be4a5 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -2063,7 +2063,7 @@ static inline bool nested_svm_intr(struct vcpu_svm *svm)
 	if (svm->nested.intercept & 1ULL) {
 		/*
 		 * The #vmexit can't be emulated here directly because this
-		 * code path runs with irqs and preemtion disabled. A
+		 * code path runs with irqs and preemption disabled. A
 		 * #vmexit emulation might sleep. Only signal request for
 		 * the #vmexit here.
 		 */
@@ -2105,7 +2105,6 @@ static void *nested_svm_map(struct vcpu_svm *svm, u64 gpa, struct page **_page)
 	return kmap(page);
 
 error:
-	kvm_release_page_clean(page);
 	kvm_inject_gp(&svm->vcpu, 0);
 
 	return NULL;
@@ -2409,7 +2408,7 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
 {
 	/*
 	 * This function merges the msr permission bitmaps of kvm and the
-	 * nested vmcb. It is omptimized in that it only merges the parts where
+	 * nested vmcb. It is optimized in that it only merges the parts where
 	 * the kvm msr permission bitmap may contain zero bits
 	 */
 	int i;
diff --git a/arch/x86/kvm/timer.c b/arch/x86/kvm/timer.c
deleted file mode 100644
index 6b85cc6..0000000
--- a/arch/x86/kvm/timer.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Kernel-based Virtual Machine driver for Linux
- *
- * This module enables machines with Intel VT-x extensions to run virtual
- * machines without emulation or binary translation.
- *
- * timer support
- *
- * Copyright 2010 Red Hat, Inc. and/or its affiliates.
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- */
-
-#include <linux/kvm_host.h>
-#include <linux/kvm.h>
-#include <linux/hrtimer.h>
-#include <linux/atomic.h>
-#include "kvm_timer.h"
-
-enum hrtimer_restart kvm_timer_fn(struct hrtimer *data)
-{
-	struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer);
-	struct kvm_vcpu *vcpu = ktimer->vcpu;
-	wait_queue_head_t *q = &vcpu->wq;
-
-	/*
-	 * There is a race window between reading and incrementing, but we do
-	 * not care about potentially losing timer events in the !reinject
-	 * case anyway. Note: KVM_REQ_PENDING_TIMER is implicitly checked
-	 * in vcpu_enter_guest.
-	 */
-	if (ktimer->reinject || !atomic_read(&ktimer->pending)) {
-		atomic_inc(&ktimer->pending);
-		/* FIXME: this code should not know anything about vcpus */
-		kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu);
-	}
-
-	if (waitqueue_active(q))
-		wake_up_interruptible(q);
-
-	if (ktimer->t_ops->is_periodic(ktimer)) {
-		hrtimer_add_expires_ns(&ktimer->timer, ktimer->period);
-		return HRTIMER_RESTART;
-	} else
-		return HRTIMER_NORESTART;
-}
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index c00f03d..13e0296 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -596,10 +596,9 @@ static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
 static struct page *nested_get_page(struct kvm_vcpu *vcpu, gpa_t addr)
 {
 	struct page *page = gfn_to_page(vcpu->kvm, addr >> PAGE_SHIFT);
-	if (is_error_page(page)) {
-		kvm_release_page_clean(page);
+	if (is_error_page(page))
 		return NULL;
-	}
+
 	return page;
 }
 
@@ -1343,7 +1342,7 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset)
 	guest_efer = vmx->vcpu.arch.efer;
 
 	/*
-	 * NX is emulated; LMA and LME handled by hardware; SCE meaninless
+	 * NX is emulated; LMA and LME handled by hardware; SCE meaningless
 	 * outside long mode
 	 */
 	ignore_bits = EFER_NX | EFER_SCE;
@@ -1991,7 +1990,7 @@ static __init void nested_vmx_setup_ctls_msrs(void)
 #endif
 		CPU_BASED_MOV_DR_EXITING | CPU_BASED_UNCOND_IO_EXITING |
 		CPU_BASED_USE_IO_BITMAPS | CPU_BASED_MONITOR_EXITING |
-		CPU_BASED_RDPMC_EXITING |
+		CPU_BASED_RDPMC_EXITING | CPU_BASED_RDTSC_EXITING |
 		CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
 	/*
 	 * We can allow some features even when not supported by the
@@ -3254,7 +3253,7 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
 	 * qemu binaries.
 	 *   IA32 arch specifies that at the time of processor reset the
 	 * "Accessed" bit in the AR field of segment registers is 1. And qemu
-	 * is setting it to 0 in the usedland code. This causes invalid guest
+	 * is setting it to 0 in the userland code. This causes invalid guest
 	 * state vmexit when "unrestricted guest" mode is turned on.
 	 *    Fix for this setup issue in cpu_reset is being pushed in the qemu
 	 * tree. Newer qemu binaries with that qemu fix would not need this
@@ -4439,7 +4438,7 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
 	hypercall[2] = 0xc1;
 }
 
-/* called to set cr0 as approriate for a mov-to-cr0 exit. */
+/* called to set cr0 as appropriate for a mov-to-cr0 exit. */
 static int handle_set_cr0(struct kvm_vcpu *vcpu, unsigned long val)
 {
 	if (to_vmx(vcpu)->nested.vmxon &&
@@ -6223,6 +6222,7 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx)
 static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
+	unsigned long debugctlmsr;
 
 	if (is_guest_mode(vcpu) && !vmx->nested.nested_run_pending) {
 		struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
@@ -6262,6 +6262,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
 		vmx_set_interrupt_shadow(vcpu, 0);
 
 	atomic_switch_perf_msrs(vmx);
+	debugctlmsr = get_debugctlmsr();
 
 	vmx->__launched = vmx->loaded_vmcs->launched;
 	asm(
@@ -6363,6 +6364,10 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
 #endif
 	      );
 
+	/* MSR_IA32_DEBUGCTLMSR is zeroed on vmexit. Restore it if needed */
+	if (debugctlmsr)
+		update_debugctlmsr(debugctlmsr);
+
 #ifndef CONFIG_X86_64
 	/*
 	 * The sysexit path does not restore ds/es, so we must set them to
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 42bce48..fb0d937 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -246,20 +246,14 @@ static void drop_user_return_notifiers(void *ignore)
 
 u64 kvm_get_apic_base(struct kvm_vcpu *vcpu)
 {
-	if (irqchip_in_kernel(vcpu->kvm))
-		return vcpu->arch.apic_base;
-	else
-		return vcpu->arch.apic_base;
+	return vcpu->arch.apic_base;
 }
 EXPORT_SYMBOL_GPL(kvm_get_apic_base);
 
 void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data)
 {
 	/* TODO: reserve bits check */
-	if (irqchip_in_kernel(vcpu->kvm))
-		kvm_lapic_set_base(vcpu, data);
-	else
-		vcpu->arch.apic_base = data;
+	kvm_lapic_set_base(vcpu, data);
 }
 EXPORT_SYMBOL_GPL(kvm_set_apic_base);
 
@@ -806,7 +800,7 @@ EXPORT_SYMBOL_GPL(kvm_rdpmc);
  * kvm-specific. Those are put in the beginning of the list.
  */
 
-#define KVM_SAVE_MSRS_BEGIN	9
+#define KVM_SAVE_MSRS_BEGIN	10
 static u32 msrs_to_save[] = {
 	MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
 	MSR_KVM_SYSTEM_TIME_NEW, MSR_KVM_WALL_CLOCK_NEW,
@@ -1097,7 +1091,7 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data)
 		 * For each generation, we track the original measured
 		 * nanosecond time, offset, and write, so if TSCs are in
 		 * sync, we can match exact offset, and if not, we can match
-		 * exact software computaion in compute_guest_tsc()
+		 * exact software computation in compute_guest_tsc()
 		 *
 		 * These values are tracked in kvm->arch.cur_xxx variables.
 		 */
@@ -1140,6 +1134,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
 	unsigned long this_tsc_khz;
 	s64 kernel_ns, max_kernel_ns;
 	u64 tsc_timestamp;
+	u8 pvclock_flags;
 
 	/* Keep irq disabled to prevent changes to the clock */
 	local_irq_save(flags);
@@ -1221,7 +1216,14 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
 	vcpu->hv_clock.system_time = kernel_ns + v->kvm->arch.kvmclock_offset;
 	vcpu->last_kernel_ns = kernel_ns;
 	vcpu->last_guest_tsc = tsc_timestamp;
-	vcpu->hv_clock.flags = 0;
+
+	pvclock_flags = 0;
+	if (vcpu->pvclock_set_guest_stopped_request) {
+		pvclock_flags |= PVCLOCK_GUEST_STOPPED;
+		vcpu->pvclock_set_guest_stopped_request = false;
+	}
+
+	vcpu->hv_clock.flags = pvclock_flags;
 
 	/*
 	 * The interface expects us to write an even number signaling that the
@@ -1504,7 +1506,7 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data)
 {
 	gpa_t gpa = data & ~0x3f;
 
-	/* Bits 2:5 are resrved, Should be zero */
+	/* Bits 2:5 are reserved, Should be zero */
 	if (data & 0x3c)
 		return 1;
 
@@ -1639,10 +1641,9 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 		vcpu->arch.time_page =
 				gfn_to_page(vcpu->kvm, data >> PAGE_SHIFT);
 
-		if (is_error_page(vcpu->arch.time_page)) {
-			kvm_release_page_clean(vcpu->arch.time_page);
+		if (is_error_page(vcpu->arch.time_page))
 			vcpu->arch.time_page = NULL;
-		}
+
 		break;
 	}
 	case MSR_KVM_ASYNC_PF_EN:
@@ -1727,7 +1728,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 		 * Ignore all writes to this no longer documented MSR.
 		 * Writes are only relevant for old K7 processors,
 		 * all pre-dating SVM, but a recommended workaround from
-		 * AMD for these chips. It is possible to speicify the
+		 * AMD for these chips. It is possible to specify the
 		 * affected processor models on the command line, hence
 		 * the need to ignore the workaround.
 		 */
@@ -2355,8 +2356,7 @@ static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
 static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu,
 				    struct kvm_lapic_state *s)
 {
-	memcpy(vcpu->arch.apic->regs, s->regs, sizeof *s);
-	kvm_apic_post_state_restore(vcpu);
+	kvm_apic_post_state_restore(vcpu, s);
 	update_cr8_intercept(vcpu);
 
 	return 0;
@@ -2632,11 +2632,9 @@ static int kvm_vcpu_ioctl_x86_set_xcrs(struct kvm_vcpu *vcpu,
  */
 static int kvm_set_guest_paused(struct kvm_vcpu *vcpu)
 {
-	struct pvclock_vcpu_time_info *src = &vcpu->arch.hv_clock;
 	if (!vcpu->arch.time_page)
 		return -EINVAL;
-	src->flags |= PVCLOCK_GUEST_STOPPED;
-	mark_page_dirty(vcpu->kvm, vcpu->arch.time >> PAGE_SHIFT);
+	vcpu->arch.pvclock_set_guest_stopped_request = true;
 	kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
 	return 0;
 }
@@ -3087,7 +3085,7 @@ static int kvm_vm_ioctl_reinject(struct kvm *kvm,
 	if (!kvm->arch.vpit)
 		return -ENXIO;
 	mutex_lock(&kvm->arch.vpit->pit_state.lock);
-	kvm->arch.vpit->pit_state.pit_timer.reinject = control->pit_reinject;
+	kvm->arch.vpit->pit_state.reinject = control->pit_reinject;
 	mutex_unlock(&kvm->arch.vpit->pit_state.lock);
 	return 0;
 }
@@ -3170,6 +3168,16 @@ out:
 	return r;
 }
 
+int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event)
+{
+	if (!irqchip_in_kernel(kvm))
+		return -ENXIO;
+
+	irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
+					irq_event->irq, irq_event->level);
+	return 0;
+}
+
 long kvm_arch_vm_ioctl(struct file *filp,
 		       unsigned int ioctl, unsigned long arg)
 {
@@ -3276,29 +3284,6 @@ long kvm_arch_vm_ioctl(struct file *filp,
 	create_pit_unlock:
 		mutex_unlock(&kvm->slots_lock);
 		break;
-	case KVM_IRQ_LINE_STATUS:
-	case KVM_IRQ_LINE: {
-		struct kvm_irq_level irq_event;
-
-		r = -EFAULT;
-		if (copy_from_user(&irq_event, argp, sizeof irq_event))
-			goto out;
-		r = -ENXIO;
-		if (irqchip_in_kernel(kvm)) {
-			__s32 status;
-			status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
-					irq_event.irq, irq_event.level);
-			if (ioctl == KVM_IRQ_LINE_STATUS) {
-				r = -EFAULT;
-				irq_event.status = status;
-				if (copy_to_user(argp, &irq_event,
-							sizeof irq_event))
-					goto out;
-			}
-			r = 0;
-		}
-		break;
-	}
 	case KVM_GET_IRQCHIP: {
 		/* 0: PIC master, 1: PIC slave, 2: IOAPIC */
 		struct kvm_irqchip *chip;
@@ -3959,10 +3944,8 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
 		goto emul_write;
 
 	page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
-	if (is_error_page(page)) {
-		kvm_release_page_clean(page);
+	if (is_error_page(page))
 		goto emul_write;
-	}
 
 	kaddr = kmap_atomic(page);
 	kaddr += offset_in_page(gpa);
@@ -4496,7 +4479,7 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t gva)
 
 	/*
 	 * if emulation was due to access to shadowed page table
-	 * and it failed try to unshadow page and re-entetr the
+	 * and it failed try to unshadow page and re-enter the
 	 * guest to let CPU execute the instruction.
 	 */
 	if (kvm_mmu_unprotect_page_virt(vcpu, gva))
@@ -4926,6 +4909,7 @@ int kvm_arch_init(void *opaque)
 	if (cpu_has_xsave)
 		host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
 
+	kvm_lapic_init();
 	return 0;
 
 out:
@@ -5592,7 +5576,7 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 		/*
 		 * We are here if userspace calls get_regs() in the middle of
 		 * instruction emulation. Registers state needs to be copied
-		 * back from emulation context to vcpu. Usrapace shouldn't do
+		 * back from emulation context to vcpu. Userspace shouldn't do
 		 * that usually, but some bad designed PV devices (vmware
 		 * backdoor interface) need this to work
 		 */
@@ -6121,7 +6105,7 @@ int kvm_arch_hardware_enable(void *garbage)
 	 * as we reset last_host_tsc on all VCPUs to stop this from being
 	 * called multiple times (one for each physical CPU bringup).
 	 *
-	 * Platforms with unnreliable TSCs don't have to deal with this, they
+	 * Platforms with unreliable TSCs don't have to deal with this, they
 	 * will be compensated by the logic in vcpu_load, which sets the TSC to
 	 * catchup mode.  This will catchup all VCPUs to real time, but cannot
 	 * guarantee that they stay in perfect synchronization.
@@ -6174,6 +6158,8 @@ bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu)
 	return irqchip_in_kernel(vcpu->kvm) == (vcpu->arch.apic != NULL);
 }
 
+struct static_key kvm_no_apic_vcpu __read_mostly;
+
 int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 {
 	struct page *page;
@@ -6206,7 +6192,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 		r = kvm_create_lapic(vcpu);
 		if (r < 0)
 			goto fail_mmu_destroy;
-	}
+	} else
+		static_key_slow_inc(&kvm_no_apic_vcpu);
 
 	vcpu->arch.mce_banks = kzalloc(KVM_MAX_MCE_BANKS * sizeof(u64) * 4,
 				       GFP_KERNEL);
@@ -6246,6 +6233,8 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
 	kvm_mmu_destroy(vcpu);
 	srcu_read_unlock(&vcpu->kvm->srcu, idx);
 	free_page((unsigned long)vcpu->arch.pio_data);
+	if (!irqchip_in_kernel(vcpu->kvm))
+		static_key_slow_dec(&kvm_no_apic_vcpu);
 }
 
 int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
@@ -6317,10 +6306,18 @@ void kvm_arch_free_memslot(struct kvm_memory_slot *free,
 {
 	int i;
 
-	for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
-		if (!dont || free->arch.lpage_info[i] != dont->arch.lpage_info[i]) {
-			kvm_kvfree(free->arch.lpage_info[i]);
-			free->arch.lpage_info[i] = NULL;
+	for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) {
+		if (!dont || free->arch.rmap[i] != dont->arch.rmap[i]) {
+			kvm_kvfree(free->arch.rmap[i]);
+			free->arch.rmap[i] = NULL;
+		}
+		if (i == 0)
+			continue;
+
+		if (!dont || free->arch.lpage_info[i - 1] !=
+			     dont->arch.lpage_info[i - 1]) {
+			kvm_kvfree(free->arch.lpage_info[i - 1]);
+			free->arch.lpage_info[i - 1] = NULL;
 		}
 	}
 }
@@ -6329,23 +6326,30 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
 {
 	int i;
 
-	for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
+	for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) {
 		unsigned long ugfn;
 		int lpages;
-		int level = i + 2;
+		int level = i + 1;
 
 		lpages = gfn_to_index(slot->base_gfn + npages - 1,
 				      slot->base_gfn, level) + 1;
 
-		slot->arch.lpage_info[i] =
-			kvm_kvzalloc(lpages * sizeof(*slot->arch.lpage_info[i]));
-		if (!slot->arch.lpage_info[i])
+		slot->arch.rmap[i] =
+			kvm_kvzalloc(lpages * sizeof(*slot->arch.rmap[i]));
+		if (!slot->arch.rmap[i])
+			goto out_free;
+		if (i == 0)
+			continue;
+
+		slot->arch.lpage_info[i - 1] = kvm_kvzalloc(lpages *
+					sizeof(*slot->arch.lpage_info[i - 1]));
+		if (!slot->arch.lpage_info[i - 1])
 			goto out_free;
 
 		if (slot->base_gfn & (KVM_PAGES_PER_HPAGE(level) - 1))
-			slot->arch.lpage_info[i][0].write_count = 1;
+			slot->arch.lpage_info[i - 1][0].write_count = 1;
 		if ((slot->base_gfn + npages) & (KVM_PAGES_PER_HPAGE(level) - 1))
-			slot->arch.lpage_info[i][lpages - 1].write_count = 1;
+			slot->arch.lpage_info[i - 1][lpages - 1].write_count = 1;
 		ugfn = slot->userspace_addr >> PAGE_SHIFT;
 		/*
 		 * If the gfn and userspace address are not aligned wrt each
@@ -6357,16 +6361,21 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
 			unsigned long j;
 
 			for (j = 0; j < lpages; ++j)
-				slot->arch.lpage_info[i][j].write_count = 1;
+				slot->arch.lpage_info[i - 1][j].write_count = 1;
 		}
 	}
 
 	return 0;
 
 out_free:
-	for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
-		kvm_kvfree(slot->arch.lpage_info[i]);
-		slot->arch.lpage_info[i] = NULL;
+	for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) {
+		kvm_kvfree(slot->arch.rmap[i]);
+		slot->arch.rmap[i] = NULL;
+		if (i == 0)
+			continue;
+
+		kvm_kvfree(slot->arch.lpage_info[i - 1]);
+		slot->arch.lpage_info[i - 1] = NULL;
 	}
 	return -ENOMEM;
 }
@@ -6385,10 +6394,10 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
 		map_flags = MAP_SHARED | MAP_ANONYMOUS;
 
 	/*To keep backward compatibility with older userspace,
-	 *x86 needs to hanlde !user_alloc case.
+	 *x86 needs to handle !user_alloc case.
 	 */
 	if (!user_alloc) {
-		if (npages && !old.rmap) {
+		if (npages && !old.npages) {
 			unsigned long userspace_addr;
 
 			userspace_addr = vm_mmap(NULL, 0,
@@ -6416,7 +6425,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
 
 	int nr_mmu_pages = 0, npages = mem->memory_size >> PAGE_SHIFT;
 
-	if (!user_alloc && !old.user_alloc && old.rmap && !npages) {
+	if (!user_alloc && !old.user_alloc && old.npages && !npages) {
 		int ret;
 
 		ret = vm_munmap(old.userspace_addr,
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index 3d1134d..2b5219c 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -124,4 +124,5 @@ int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt,
 
 extern u64 host_xcr0;
 
+extern struct static_key kvm_no_apic_vcpu;
 #endif
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 76dcd9d..7dde46d 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -18,6 +18,7 @@
 #include <asm/pgalloc.h>		/* pgd_*(), ...			*/
 #include <asm/kmemcheck.h>		/* kmemcheck_*(), ...		*/
 #include <asm/fixmap.h>			/* VSYSCALL_START		*/
+#include <asm/rcu.h>			/* exception_enter(), ...	*/
 
 /*
  * Page fault error code bits:
@@ -1000,8 +1001,8 @@ static int fault_in_kernel_space(unsigned long address)
  * and the problem, and then passes it off to one of the appropriate
  * routines.
  */
-dotraplinkage void __kprobes
-do_page_fault(struct pt_regs *regs, unsigned long error_code)
+static void __kprobes
+__do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
 	struct vm_area_struct *vma;
 	struct task_struct *tsk;
@@ -1209,3 +1210,11 @@ good_area:
 
 	up_read(&mm->mmap_sem);
 }
+
+dotraplinkage void __kprobes
+do_page_fault(struct pt_regs *regs, unsigned long error_code)
+{
+	exception_enter(regs);
+	__do_page_fault(regs, error_code);
+	exception_exit(regs);
+}
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index 3d68ef6..0eb572e 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -664,20 +664,20 @@ static void free_pfn_range(u64 paddr, unsigned long size)
 }
 
 /*
- * track_pfn_vma_copy is called when vma that is covering the pfnmap gets
+ * track_pfn_copy is called when vma that is covering the pfnmap gets
  * copied through copy_page_range().
  *
  * If the vma has a linear pfn mapping for the entire range, we get the prot
  * from pte and reserve the entire vma range with single reserve_pfn_range call.
  */
-int track_pfn_vma_copy(struct vm_area_struct *vma)
+int track_pfn_copy(struct vm_area_struct *vma)
 {
 	resource_size_t paddr;
 	unsigned long prot;
 	unsigned long vma_size = vma->vm_end - vma->vm_start;
 	pgprot_t pgprot;
 
-	if (is_linear_pfn_mapping(vma)) {
+	if (vma->vm_flags & VM_PAT) {
 		/*
 		 * reserve the whole chunk covered by vma. We need the
 		 * starting address and protection from pte.
@@ -694,31 +694,59 @@ int track_pfn_vma_copy(struct vm_area_struct *vma)
 }
 
 /*
- * track_pfn_vma_new is called when a _new_ pfn mapping is being established
- * for physical range indicated by pfn and size.
- *
  * prot is passed in as a parameter for the new mapping. If the vma has a
  * linear pfn mapping for the entire range reserve the entire vma range with
  * single reserve_pfn_range call.
  */
-int track_pfn_vma_new(struct vm_area_struct *vma, pgprot_t *prot,
-			unsigned long pfn, unsigned long size)
+int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot,
+		    unsigned long pfn, unsigned long addr, unsigned long size)
 {
+	resource_size_t paddr = (resource_size_t)pfn << PAGE_SHIFT;
 	unsigned long flags;
-	resource_size_t paddr;
-	unsigned long vma_size = vma->vm_end - vma->vm_start;
 
-	if (is_linear_pfn_mapping(vma)) {
-		/* reserve the whole chunk starting from vm_pgoff */
-		paddr = (resource_size_t)vma->vm_pgoff << PAGE_SHIFT;
-		return reserve_pfn_range(paddr, vma_size, prot, 0);
+	/* reserve the whole chunk starting from paddr */
+	if (addr == vma->vm_start && size == (vma->vm_end - vma->vm_start)) {
+		int ret;
+
+		ret = reserve_pfn_range(paddr, size, prot, 0);
+		if (!ret)
+			vma->vm_flags |= VM_PAT;
+		return ret;
 	}
 
 	if (!pat_enabled)
 		return 0;
 
-	/* for vm_insert_pfn and friends, we set prot based on lookup */
-	flags = lookup_memtype(pfn << PAGE_SHIFT);
+	/*
+	 * For anything smaller than the vma size we set prot based on the
+	 * lookup.
+	 */
+	flags = lookup_memtype(paddr);
+
+	/* Check memtype for the remaining pages */
+	while (size > PAGE_SIZE) {
+		size -= PAGE_SIZE;
+		paddr += PAGE_SIZE;
+		if (flags != lookup_memtype(paddr))
+			return -EINVAL;
+	}
+
+	*prot = __pgprot((pgprot_val(vma->vm_page_prot) & (~_PAGE_CACHE_MASK)) |
+			 flags);
+
+	return 0;
+}
+
+int track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot,
+		     unsigned long pfn)
+{
+	unsigned long flags;
+
+	if (!pat_enabled)
+		return 0;
+
+	/* Set prot based on lookup */
+	flags = lookup_memtype((resource_size_t)pfn << PAGE_SHIFT);
 	*prot = __pgprot((pgprot_val(vma->vm_page_prot) & (~_PAGE_CACHE_MASK)) |
 			 flags);
 
@@ -726,22 +754,31 @@ int track_pfn_vma_new(struct vm_area_struct *vma, pgprot_t *prot,
 }
 
 /*
- * untrack_pfn_vma is called while unmapping a pfnmap for a region.
+ * untrack_pfn is called while unmapping a pfnmap for a region.
  * untrack can be called for a specific region indicated by pfn and size or
- * can be for the entire vma (in which case size can be zero).
+ * can be for the entire vma (in which case pfn, size are zero).
  */
-void untrack_pfn_vma(struct vm_area_struct *vma, unsigned long pfn,
-			unsigned long size)
+void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn,
+		 unsigned long size)
 {
 	resource_size_t paddr;
-	unsigned long vma_size = vma->vm_end - vma->vm_start;
+	unsigned long prot;
 
-	if (is_linear_pfn_mapping(vma)) {
-		/* free the whole chunk starting from vm_pgoff */
-		paddr = (resource_size_t)vma->vm_pgoff << PAGE_SHIFT;
-		free_pfn_range(paddr, vma_size);
+	if (!(vma->vm_flags & VM_PAT))
 		return;
+
+	/* free the chunk starting from pfn or the whole chunk */
+	paddr = (resource_size_t)pfn << PAGE_SHIFT;
+	if (!paddr && !size) {
+		if (follow_phys(vma, vma->vm_start, 0, &prot, &paddr)) {
+			WARN_ON_ONCE(1);
+			return;
+		}
+
+		size = vma->vm_end - vma->vm_start;
 	}
+	free_pfn_range(paddr, size);
+	vma->vm_flags &= ~VM_PAT;
 }
 
 pgprot_t pgprot_writecombine(pgprot_t prot)
diff --git a/arch/x86/platform/iris/iris.c b/arch/x86/platform/iris/iris.c
index 5917eb5..e6cb80f 100644
--- a/arch/x86/platform/iris/iris.c
+++ b/arch/x86/platform/iris/iris.c
@@ -23,6 +23,7 @@
 
 #include <linux/moduleparam.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
@@ -62,29 +63,75 @@ static void iris_power_off(void)
  * by reading its input port and seeing whether the read value is
  * meaningful.
  */
-static int iris_init(void)
+static int iris_probe(struct platform_device *pdev)
 {
-	unsigned char status;
-	if (force != 1) {
-		printk(KERN_ERR "The force parameter has not been set to 1 so the Iris poweroff handler will not be installed.\n");
-		return -ENODEV;
-	}
-	status = inb(IRIS_GIO_INPUT);
+	unsigned char status = inb(IRIS_GIO_INPUT);
 	if (status == IRIS_GIO_NODEV) {
-		printk(KERN_ERR "This machine does not seem to be an Iris. Power_off handler not installed.\n");
+		printk(KERN_ERR "This machine does not seem to be an Iris. "
+			"Power off handler not installed.\n");
 		return -ENODEV;
 	}
 	old_pm_power_off = pm_power_off;
 	pm_power_off = &iris_power_off;
 	printk(KERN_INFO "Iris power_off handler installed.\n");
-
 	return 0;
 }
 
-static void iris_exit(void)
+static int iris_remove(struct platform_device *pdev)
 {
 	pm_power_off = old_pm_power_off;
 	printk(KERN_INFO "Iris power_off handler uninstalled.\n");
+	return 0;
+}
+
+static struct platform_driver iris_driver = {
+	.driver		= {
+		.name   = "iris",
+		.owner  = THIS_MODULE,
+	},
+	.probe          = iris_probe,
+	.remove         = iris_remove,
+};
+
+static struct resource iris_resources[] = {
+	{
+		.start  = IRIS_GIO_BASE,
+		.end    = IRIS_GIO_OUTPUT,
+		.flags  = IORESOURCE_IO,
+		.name   = "address"
+	}
+};
+
+static struct platform_device *iris_device;
+
+static int iris_init(void)
+{
+	int ret;
+	if (force != 1) {
+		printk(KERN_ERR "The force parameter has not been set to 1."
+			" The Iris poweroff handler will not be installed.\n");
+		return -ENODEV;
+	}
+	ret = platform_driver_register(&iris_driver);
+	if (ret < 0) {
+		printk(KERN_ERR "Failed to register iris platform driver: %d\n",
+			ret);
+		return ret;
+	}
+	iris_device = platform_device_register_simple("iris", (-1),
+				iris_resources, ARRAY_SIZE(iris_resources));
+	if (IS_ERR(iris_device)) {
+		printk(KERN_ERR "Failed to register iris platform device\n");
+		platform_driver_unregister(&iris_driver);
+		return PTR_ERR(iris_device);
+	}
+	return 0;
+}
+
+static void iris_exit(void)
+{
+	platform_device_unregister(iris_device);
+	platform_driver_unregister(&iris_driver);
 }
 
 module_init(iris_init);
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index bf4bda6..9642d4a 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -31,7 +31,6 @@
 #include <linux/pci.h>
 #include <linux/gfp.h>
 #include <linux/memblock.h>
-#include <linux/syscore_ops.h>
 
 #include <xen/xen.h>
 #include <xen/interface/xen.h>
@@ -1470,130 +1469,38 @@ asmlinkage void __init xen_start_kernel(void)
 #endif
 }
 
-#ifdef CONFIG_XEN_PVHVM
-/*
- * The pfn containing the shared_info is located somewhere in RAM. This
- * will cause trouble if the current kernel is doing a kexec boot into a
- * new kernel. The new kernel (and its startup code) can not know where
- * the pfn is, so it can not reserve the page. The hypervisor will
- * continue to update the pfn, and as a result memory corruption occours
- * in the new kernel.
- *
- * One way to work around this issue is to allocate a page in the
- * xen-platform pci device's BAR memory range. But pci init is done very
- * late and the shared_info page is already in use very early to read
- * the pvclock. So moving the pfn from RAM to MMIO is racy because some
- * code paths on other vcpus could access the pfn during the small
- * window when the old pfn is moved to the new pfn. There is even a
- * small window were the old pfn is not backed by a mfn, and during that
- * time all reads return -1.
- *
- * Because it is not known upfront where the MMIO region is located it
- * can not be used right from the start in xen_hvm_init_shared_info.
- *
- * To minimise trouble the move of the pfn is done shortly before kexec.
- * This does not eliminate the race because all vcpus are still online
- * when the syscore_ops will be called. But hopefully there is no work
- * pending at this point in time. Also the syscore_op is run last which
- * reduces the risk further.
- */
-
-static struct shared_info *xen_hvm_shared_info;
-
-static void xen_hvm_connect_shared_info(unsigned long pfn)
+void __ref xen_hvm_init_shared_info(void)
 {
+	int cpu;
 	struct xen_add_to_physmap xatp;
+	static struct shared_info *shared_info_page = 0;
 
+	if (!shared_info_page)
+		shared_info_page = (struct shared_info *)
+			extend_brk(PAGE_SIZE, PAGE_SIZE);
 	xatp.domid = DOMID_SELF;
 	xatp.idx = 0;
 	xatp.space = XENMAPSPACE_shared_info;
-	xatp.gpfn = pfn;
+	xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT;
 	if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
 		BUG();
 
-}
-static void xen_hvm_set_shared_info(struct shared_info *sip)
-{
-	int cpu;
-
-	HYPERVISOR_shared_info = sip;
+	HYPERVISOR_shared_info = (struct shared_info *)shared_info_page;
 
 	/* xen_vcpu is a pointer to the vcpu_info struct in the shared_info
 	 * page, we use it in the event channel upcall and in some pvclock
 	 * related functions. We don't need the vcpu_info placement
 	 * optimizations because we don't use any pv_mmu or pv_irq op on
 	 * HVM.
-	 * When xen_hvm_set_shared_info is run at boot time only vcpu 0 is
-	 * online but xen_hvm_set_shared_info is run at resume time too and
+	 * When xen_hvm_init_shared_info is run at boot time only vcpu 0 is
+	 * online but xen_hvm_init_shared_info is run at resume time too and
 	 * in that case multiple vcpus might be online. */
 	for_each_online_cpu(cpu) {
 		per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
 	}
 }
 
-/* Reconnect the shared_info pfn to a mfn */
-void xen_hvm_resume_shared_info(void)
-{
-	xen_hvm_connect_shared_info(__pa(xen_hvm_shared_info) >> PAGE_SHIFT);
-}
-
-#ifdef CONFIG_KEXEC
-static struct shared_info *xen_hvm_shared_info_kexec;
-static unsigned long xen_hvm_shared_info_pfn_kexec;
-
-/* Remember a pfn in MMIO space for kexec reboot */
-void __devinit xen_hvm_prepare_kexec(struct shared_info *sip, unsigned long pfn)
-{
-	xen_hvm_shared_info_kexec = sip;
-	xen_hvm_shared_info_pfn_kexec = pfn;
-}
-
-static void xen_hvm_syscore_shutdown(void)
-{
-	struct xen_memory_reservation reservation = {
-		.domid = DOMID_SELF,
-		.nr_extents = 1,
-	};
-	unsigned long prev_pfn;
-	int rc;
-
-	if (!xen_hvm_shared_info_kexec)
-		return;
-
-	prev_pfn = __pa(xen_hvm_shared_info) >> PAGE_SHIFT;
-	set_xen_guest_handle(reservation.extent_start, &prev_pfn);
-
-	/* Move pfn to MMIO, disconnects previous pfn from mfn */
-	xen_hvm_connect_shared_info(xen_hvm_shared_info_pfn_kexec);
-
-	/* Update pointers, following hypercall is also a memory barrier */
-	xen_hvm_set_shared_info(xen_hvm_shared_info_kexec);
-
-	/* Allocate new mfn for previous pfn */
-	do {
-		rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation);
-		if (rc == 0)
-			msleep(123);
-	} while (rc == 0);
-
-	/* Make sure the previous pfn is really connected to a (new) mfn */
-	BUG_ON(rc != 1);
-}
-
-static struct syscore_ops xen_hvm_syscore_ops = {
-	.shutdown = xen_hvm_syscore_shutdown,
-};
-#endif
-
-/* Use a pfn in RAM, may move to MMIO before kexec. */
-static void __init xen_hvm_init_shared_info(void)
-{
-	/* Remember pointer for resume */
-	xen_hvm_shared_info = extend_brk(PAGE_SIZE, PAGE_SIZE);
-	xen_hvm_connect_shared_info(__pa(xen_hvm_shared_info) >> PAGE_SHIFT);
-	xen_hvm_set_shared_info(xen_hvm_shared_info);
-}
-
+#ifdef CONFIG_XEN_PVHVM
 static void __init init_hvm_pv_info(void)
 {
 	int major, minor;
@@ -1644,9 +1551,6 @@ static void __init xen_hvm_guest_init(void)
 	init_hvm_pv_info();
 
 	xen_hvm_init_shared_info();
-#ifdef CONFIG_KEXEC
-	register_syscore_ops(&xen_hvm_syscore_ops);
-#endif
 
 	if (xen_feature(XENFEAT_hvm_callback_vector))
 		xen_have_vector_callback = 1;
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index b65a761..4c5a404 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -2339,8 +2339,7 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
 
 	prot = __pgprot(pgprot_val(prot) | _PAGE_IOMAP);
 
-	BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_RESERVED | VM_IO)) ==
-				(VM_PFNMAP | VM_RESERVED | VM_IO)));
+	BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO)));
 
 	rmd.mfn = mfn;
 	rmd.prot = prot;
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
index b2e91d4..d4b2554 100644
--- a/arch/x86/xen/p2m.c
+++ b/arch/x86/xen/p2m.c
@@ -196,9 +196,11 @@ RESERVE_BRK(p2m_mid_identity, PAGE_SIZE * 2 * 3);
 
 /* When we populate back during bootup, the amount of pages can vary. The
  * max we have is seen is 395979, but that does not mean it can't be more.
- * But some machines can have 3GB I/O holes even. So lets reserve enough
- * for 4GB of I/O and E820 holes. */
-RESERVE_BRK(p2m_populated, PMD_SIZE * 4);
+ * Some machines can have 3GB I/O holes even. With early_can_reuse_p2m_middle
+ * it can re-use Xen provided mfn_list array, so we only need to allocate at
+ * most three P2M top nodes. */
+RESERVE_BRK(p2m_populated, PAGE_SIZE * 3);
+
 static inline unsigned p2m_top_index(unsigned long pfn)
 {
 	BUG_ON(pfn >= MAX_P2M_PFN);
@@ -575,12 +577,99 @@ static bool __init early_alloc_p2m(unsigned long pfn)
 	}
 	return true;
 }
+
+/*
+ * Skim over the P2M tree looking at pages that are either filled with
+ * INVALID_P2M_ENTRY or with 1:1 PFNs. If found, re-use that page and
+ * replace the P2M leaf with a p2m_missing or p2m_identity.
+ * Stick the old page in the new P2M tree location.
+ */
+bool __init early_can_reuse_p2m_middle(unsigned long set_pfn, unsigned long set_mfn)
+{
+	unsigned topidx;
+	unsigned mididx;
+	unsigned ident_pfns;
+	unsigned inv_pfns;
+	unsigned long *p2m;
+	unsigned long *mid_mfn_p;
+	unsigned idx;
+	unsigned long pfn;
+
+	/* We only look when this entails a P2M middle layer */
+	if (p2m_index(set_pfn))
+		return false;
+
+	for (pfn = 0; pfn <= MAX_DOMAIN_PAGES; pfn += P2M_PER_PAGE) {
+		topidx = p2m_top_index(pfn);
+
+		if (!p2m_top[topidx])
+			continue;
+
+		if (p2m_top[topidx] == p2m_mid_missing)
+			continue;
+
+		mididx = p2m_mid_index(pfn);
+		p2m = p2m_top[topidx][mididx];
+		if (!p2m)
+			continue;
+
+		if ((p2m == p2m_missing) || (p2m == p2m_identity))
+			continue;
+
+		if ((unsigned long)p2m == INVALID_P2M_ENTRY)
+			continue;
+
+		ident_pfns = 0;
+		inv_pfns = 0;
+		for (idx = 0; idx < P2M_PER_PAGE; idx++) {
+			/* IDENTITY_PFNs are 1:1 */
+			if (p2m[idx] == IDENTITY_FRAME(pfn + idx))
+				ident_pfns++;
+			else if (p2m[idx] == INVALID_P2M_ENTRY)
+				inv_pfns++;
+			else
+				break;
+		}
+		if ((ident_pfns == P2M_PER_PAGE) || (inv_pfns == P2M_PER_PAGE))
+			goto found;
+	}
+	return false;
+found:
+	/* Found one, replace old with p2m_identity or p2m_missing */
+	p2m_top[topidx][mididx] = (ident_pfns ? p2m_identity : p2m_missing);
+	/* And the other for save/restore.. */
+	mid_mfn_p = p2m_top_mfn_p[topidx];
+	/* NOTE: Even if it is a p2m_identity it should still be point to
+	 * a page filled with INVALID_P2M_ENTRY entries. */
+	mid_mfn_p[mididx] = virt_to_mfn(p2m_missing);
+
+	/* Reset where we want to stick the old page in. */
+	topidx = p2m_top_index(set_pfn);
+	mididx = p2m_mid_index(set_pfn);
+
+	/* This shouldn't happen */
+	if (WARN_ON(p2m_top[topidx] == p2m_mid_missing))
+		early_alloc_p2m(set_pfn);
+
+	if (WARN_ON(p2m_top[topidx][mididx] != p2m_missing))
+		return false;
+
+	p2m_init(p2m);
+	p2m_top[topidx][mididx] = p2m;
+	mid_mfn_p = p2m_top_mfn_p[topidx];
+	mid_mfn_p[mididx] = virt_to_mfn(p2m);
+
+	return true;
+}
 bool __init early_set_phys_to_machine(unsigned long pfn, unsigned long mfn)
 {
 	if (unlikely(!__set_phys_to_machine(pfn, mfn)))  {
 		if (!early_alloc_p2m(pfn))
 			return false;
 
+		if (early_can_reuse_p2m_middle(pfn, mfn))
+			return __set_phys_to_machine(pfn, mfn);
+
 		if (!early_alloc_p2m_middle(pfn, false /* boundary crossover OK!*/))
 			return false;
 
diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c
index ae8a00c..45329c8 100644
--- a/arch/x86/xen/suspend.c
+++ b/arch/x86/xen/suspend.c
@@ -30,7 +30,7 @@ void xen_arch_hvm_post_suspend(int suspend_cancelled)
 {
 #ifdef CONFIG_XEN_PVHVM
 	int cpu;
-	xen_hvm_resume_shared_info();
+	xen_hvm_init_shared_info();
 	xen_callback_vector();
 	xen_unplug_emulated_devices();
 	if (xen_feature(XENFEAT_hvm_safe_pvclock)) {
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index 1e4329e..202d4c1 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -41,7 +41,7 @@ void xen_enable_syscall(void);
 void xen_vcpu_restore(void);
 
 void xen_callback_vector(void);
-void xen_hvm_resume_shared_info(void);
+void xen_hvm_init_shared_info(void);
 void xen_unplug_emulated_devices(void);
 
 void __init xen_build_dynamic_phys_to_machine(void);
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index 8ed64cf..8c82cd8 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -11,6 +11,8 @@ config XTENSA
 	select HAVE_GENERIC_HARDIRQS
 	select GENERIC_IRQ_SHOW
 	select GENERIC_CPU_DEVICES
+	select GENERIC_PCI_IOMAP
+	select MODULES_USE_ELF_RELA
 	help
 	  Xtensa processors are 32-bit RISC machines designed by Tensilica
 	  primarily for embedded systems.  These processors are both
@@ -59,6 +61,7 @@ choice
 config XTENSA_VARIANT_FSF
 	bool "fsf - default (not generic) configuration"
 	select MMU
+	select ARCH_WANT_OPTIONAL_GPIOLIB
 
 config XTENSA_VARIANT_DC232B
 	bool "dc232b - Diamond 232L Standard Core Rev.B (LE)"
diff --git a/arch/xtensa/include/asm/io.h b/arch/xtensa/include/asm/io.h
index 4beb43c..c4d8b62 100644
--- a/arch/xtensa/include/asm/io.h
+++ b/arch/xtensa/include/asm/io.h
@@ -16,6 +16,7 @@
 #include <asm/page.h>
 #include <linux/bug.h>
 #include <linux/kernel.h>
+#include <asm-generic/iomap.h>
 
 #include <linux/types.h>
 
@@ -112,6 +113,15 @@ static inline void iounmap(void *addr)
 #define writew(b, addr) (void)((*(volatile unsigned short *)(addr)) = (b))
 #define writel(b, addr) (void)((*(volatile unsigned int *)(addr)) = (b))
 
+#define ioport_map(port, nr) ((void __iomem *)(port))
+
+#define ioread8 read
+#define ioread16 readw
+#define ioread32 readl
+#define iowrite8 writeb
+#define iowrite16 writew
+#define iowrite32 writel
+
 static inline __u8 __raw_readb(const volatile void __iomem *addr)
 {
           return *(__force volatile __u8 *)(addr);
diff --git a/arch/xtensa/include/asm/module.h b/arch/xtensa/include/asm/module.h
index d9b34be..488b40c 100644
--- a/arch/xtensa/include/asm/module.h
+++ b/arch/xtensa/include/asm/module.h
@@ -13,15 +13,8 @@
 #ifndef _XTENSA_MODULE_H
 #define _XTENSA_MODULE_H
 
-struct mod_arch_specific
-{
-	/* No special elements, yet. */
-};
-
 #define MODULE_ARCH_VERMAGIC "xtensa-" __stringify(XCHAL_CORE_ID) " "
 
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
+#include <asm-generic/module.h>
 
 #endif	/* _XTENSA_MODULE_H */
diff --git a/arch/xtensa/include/asm/thread_info.h b/arch/xtensa/include/asm/thread_info.h
index 81abfd5..9481004 100644
--- a/arch/xtensa/include/asm/thread_info.h
+++ b/arch/xtensa/include/asm/thread_info.h
@@ -128,19 +128,14 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SIGPENDING		1	/* signal pending */
 #define TIF_NEED_RESCHED	2	/* rescheduling necessary */
 #define TIF_SINGLESTEP		3	/* restore singlestep on return to user mode */
-#define TIF_IRET		4	/* return with iret */
 #define TIF_MEMDIE		5	/* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK	6	/* restore signal mask in do_signal() */
 #define TIF_NOTIFY_RESUME	7	/* callback before returning to user */
-#define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
-#define _TIF_IRET		(1<<TIF_IRET)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 
 #define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
 #define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
diff --git a/arch/xtensa/kernel/Makefile b/arch/xtensa/kernel/Makefile
index 59fc3fe..0f9f35f 100644
--- a/arch/xtensa/kernel/Makefile
+++ b/arch/xtensa/kernel/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_MODULES) += xtensa_ksyms.o module.o
 # Replicate rules in scripts/Makefile.build
 
 sed-y = -e 's/\*(\(\.[a-z]*it\|\.ref\|\)\.text)/*(\1.literal \1.text)/g'    \
+	-e 's/\.text\.unlikely/.literal.unlikely .text.unlikely/g' \
 	-e 's/\*(\(\.text\.[a-z]*\))/*(\1.literal \1)/g'
 
 quiet_cmd__cpp_lds_S = LDS     $@
diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c
index 4340ee0..98e77c3 100644
--- a/arch/xtensa/kernel/irq.c
+++ b/arch/xtensa/kernel/irq.c
@@ -84,12 +84,12 @@ static void xtensa_irq_unmask(struct irq_data *d)
 static void xtensa_irq_enable(struct irq_data *d)
 {
 	variant_irq_enable(d->irq);
-	xtensa_irq_unmask(d->irq);
+	xtensa_irq_unmask(d);
 }
 
 static void xtensa_irq_disable(struct irq_data *d)
 {
-	xtensa_irq_mask(d->irq);
+	xtensa_irq_mask(d);
 	variant_irq_disable(d->irq);
 }
 
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index 69759e9..96ccf17 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -25,6 +25,7 @@
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/bootmem.h>
+#include <linux/module.h>
 
 #include <asm/pci-bridge.h>
 #include <asm/platform.h>
@@ -341,7 +342,7 @@ __pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
 	int prot = pgprot_val(vma->vm_page_prot);
 
 	/* Set to write-through */
-	prot &= ~_PAGE_NO_CACHE;
+	prot = (prot & _PAGE_CA_MASK) | _PAGE_CA_WT;
 #if 0
 	if (!write_combine)
 		prot |= _PAGE_WRITETHRU;
@@ -376,3 +377,9 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
 
 	return ret;
 }
+
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+{
+	iounmap(addr);
+}
+EXPORT_SYMBOL(pci_iounmap);
diff --git a/arch/xtensa/kernel/platform.c b/arch/xtensa/kernel/platform.c
index 1b91a97..97230e4 100644
--- a/arch/xtensa/kernel/platform.c
+++ b/arch/xtensa/kernel/platform.c
@@ -40,8 +40,8 @@ _F(int,  pcibios_fixup, (void), { return 0; });
 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
 _F(void, calibrate_ccount, (void),
 {
-  printk ("ERROR: Cannot calibrate cpu frequency! Assuming 100MHz.\n");
-  ccount_per_jiffy = 100 * (1000000UL/HZ);
+	pr_err("ERROR: Cannot calibrate cpu frequency! Assuming 10MHz.\n");
+	ccount_per_jiffy = 10 * (1000000UL/HZ);
 });
 #endif
 
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
index efe4e85..63c566f 100644
--- a/arch/xtensa/kernel/signal.c
+++ b/arch/xtensa/kernel/signal.c
@@ -19,7 +19,6 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/personality.h>
-#include <linux/freezer.h>
 #include <linux/tracehook.h>
 
 #include <asm/ucontext.h>
@@ -527,9 +526,6 @@ static void do_signal(struct pt_regs *regs)
 
 void do_notify_resume(struct pt_regs *regs)
 {
-	if (!user_mode(regs))
-		return;
-
 	if (test_thread_flag(TIF_SIGPENDING))
 		do_signal(regs);
 
diff --git a/arch/xtensa/platforms/iss/Makefile b/arch/xtensa/platforms/iss/Makefile
index af96e31..c61dd39 100644
--- a/arch/xtensa/platforms/iss/Makefile
+++ b/arch/xtensa/platforms/iss/Makefile
@@ -4,5 +4,5 @@
 # "prom monitor" library routines under Linux.
 #
 
-obj-y			= io.o console.o setup.o network.o
-
+obj-y			= io.o console.o setup.o
+obj-$(CONFIG_NET)	+= network.o
diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c
index f9726f6..367c2c8 100644
--- a/arch/xtensa/platforms/iss/console.c
+++ b/arch/xtensa/platforms/iss/console.c
@@ -33,7 +33,7 @@
 #endif
 
 #define SERIAL_MAX_NUM_LINES 1
-#define SERIAL_TIMER_VALUE (20 * HZ)
+#define SERIAL_TIMER_VALUE (HZ / 10)
 
 static struct tty_driver *serial_driver;
 static struct tty_port serial_port;
@@ -43,14 +43,22 @@ static DEFINE_SPINLOCK(timer_lock);
 
 int errno;
 
-static int __simc (int a, int b, int c, int d, int e, int f) __attribute__((__noinline__));
 static int __simc (int a, int b, int c, int d, int e, int f)
 {
 	int ret;
-	__asm__ __volatile__ ("simcall\n"
+	register int a1 asm("a2") = a;
+	register int b1 asm("a3") = b;
+	register int c1 asm("a4") = c;
+	register int d1 asm("a5") = d;
+	register int e1 asm("a6") = e;
+	register int f1 asm("a7") = f;
+	__asm__ __volatile__ (
+			"simcall\n"
 			"mov %0, a2\n"
-			"mov %1, a3\n" : "=a" (ret), "=a" (errno)
-			: : "a2", "a3");
+			"mov %1, a3\n"
+			: "=a" (ret), "=a" (errno), "+r"(a1), "+r"(b1)
+			: "r"(c1), "r"(d1), "r"(e1), "r"(f1)
+			: );
 	return ret;
 }
 
@@ -223,6 +231,7 @@ int __init rs_init(void)
 	serial_driver->flags = TTY_DRIVER_REAL_RAW;
 
 	tty_set_operations(serial_driver, &serial_ops);
+	tty_port_link_device(&serial_port, serial_driver, 0);
 
 	if (tty_register_driver(serial_driver))
 		panic("Couldn't register serial driver\n");
diff --git a/arch/xtensa/platforms/iss/setup.c b/arch/xtensa/platforms/iss/setup.c
index f60c8cf..927acf3 100644
--- a/arch/xtensa/platforms/iss/setup.c
+++ b/arch/xtensa/platforms/iss/setup.c
@@ -38,16 +38,22 @@ void __init platform_init(bp_tag_t* bootparam)
 
 }
 
+#ifdef CONFIG_PCI
+void platform_pcibios_init(void)
+{
+}
+#endif
+
 void platform_halt(void)
 {
-	printk (" ** Called platform_halt(), looping forever! **\n");
-	while (1);
+	pr_info(" ** Called platform_halt() **\n");
+	__asm__ __volatile__("movi a2, 1\nsimcall\n");
 }
 
 void platform_power_off(void)
 {
-	printk (" ** Called platform_power_off(), looping forever! **\n");
-	while (1);
+	pr_info(" ** Called platform_power_off() **\n");
+	__asm__ __volatile__("movi a2, 1\nsimcall\n");
 }
 void platform_restart(void)
 {
diff --git a/block/blk-lib.c b/block/blk-lib.c
index 2b461b4..19cc761 100644
--- a/block/blk-lib.c
+++ b/block/blk-lib.c
@@ -44,6 +44,7 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
 	struct request_queue *q = bdev_get_queue(bdev);
 	int type = REQ_WRITE | REQ_DISCARD;
 	unsigned int max_discard_sectors;
+	unsigned int granularity, alignment, mask;
 	struct bio_batch bb;
 	struct bio *bio;
 	int ret = 0;
@@ -54,18 +55,20 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
 	if (!blk_queue_discard(q))
 		return -EOPNOTSUPP;
 
+	/* Zero-sector (unknown) and one-sector granularities are the same.  */
+	granularity = max(q->limits.discard_granularity >> 9, 1U);
+	mask = granularity - 1;
+	alignment = (bdev_discard_alignment(bdev) >> 9) & mask;
+
 	/*
 	 * Ensure that max_discard_sectors is of the proper
-	 * granularity
+	 * granularity, so that requests stay aligned after a split.
 	 */
 	max_discard_sectors = min(q->limits.max_discard_sectors, UINT_MAX >> 9);
+	max_discard_sectors = round_down(max_discard_sectors, granularity);
 	if (unlikely(!max_discard_sectors)) {
 		/* Avoid infinite loop below. Being cautious never hurts. */
 		return -EOPNOTSUPP;
-	} else if (q->limits.discard_granularity) {
-		unsigned int disc_sects = q->limits.discard_granularity >> 9;
-
-		max_discard_sectors &= ~(disc_sects - 1);
 	}
 
 	if (flags & BLKDEV_DISCARD_SECURE) {
@@ -79,25 +82,37 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
 	bb.wait = &wait;
 
 	while (nr_sects) {
+		unsigned int req_sects;
+		sector_t end_sect;
+
 		bio = bio_alloc(gfp_mask, 1);
 		if (!bio) {
 			ret = -ENOMEM;
 			break;
 		}
 
+		req_sects = min_t(sector_t, nr_sects, max_discard_sectors);
+
+		/*
+		 * If splitting a request, and the next starting sector would be
+		 * misaligned, stop the discard at the previous aligned sector.
+		 */
+		end_sect = sector + req_sects;
+		if (req_sects < nr_sects && (end_sect & mask) != alignment) {
+			end_sect =
+				round_down(end_sect - alignment, granularity)
+				+ alignment;
+			req_sects = end_sect - sector;
+		}
+
 		bio->bi_sector = sector;
 		bio->bi_end_io = bio_batch_end_io;
 		bio->bi_bdev = bdev;
 		bio->bi_private = &bb;
 
-		if (nr_sects > max_discard_sectors) {
-			bio->bi_size = max_discard_sectors << 9;
-			nr_sects -= max_discard_sectors;
-			sector += max_discard_sectors;
-		} else {
-			bio->bi_size = nr_sects << 9;
-			nr_sects = 0;
-		}
+		bio->bi_size = req_sects << 9;
+		nr_sects -= req_sects;
+		sector = end_sect;
 
 		atomic_inc(&bb.done);
 		submit_bio(type, bio);
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 160035f..e76279e 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -110,6 +110,49 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
 	return 0;
 }
 
+static void
+__blk_segment_map_sg(struct request_queue *q, struct bio_vec *bvec,
+		     struct scatterlist *sglist, struct bio_vec **bvprv,
+		     struct scatterlist **sg, int *nsegs, int *cluster)
+{
+
+	int nbytes = bvec->bv_len;
+
+	if (*bvprv && *cluster) {
+		if ((*sg)->length + nbytes > queue_max_segment_size(q))
+			goto new_segment;
+
+		if (!BIOVEC_PHYS_MERGEABLE(*bvprv, bvec))
+			goto new_segment;
+		if (!BIOVEC_SEG_BOUNDARY(q, *bvprv, bvec))
+			goto new_segment;
+
+		(*sg)->length += nbytes;
+	} else {
+new_segment:
+		if (!*sg)
+			*sg = sglist;
+		else {
+			/*
+			 * If the driver previously mapped a shorter
+			 * list, we could see a termination bit
+			 * prematurely unless it fully inits the sg
+			 * table on each mapping. We KNOW that there
+			 * must be more entries here or the driver
+			 * would be buggy, so force clear the
+			 * termination bit to avoid doing a full
+			 * sg_init_table() in drivers for each command.
+			 */
+			(*sg)->page_link &= ~0x02;
+			*sg = sg_next(*sg);
+		}
+
+		sg_set_page(*sg, bvec->bv_page, nbytes, bvec->bv_offset);
+		(*nsegs)++;
+	}
+	*bvprv = bvec;
+}
+
 /*
  * map a request to scatterlist, return number of sg entries setup. Caller
  * must make sure sg can hold rq->nr_phys_segments entries
@@ -131,41 +174,8 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq,
 	bvprv = NULL;
 	sg = NULL;
 	rq_for_each_segment(bvec, rq, iter) {
-		int nbytes = bvec->bv_len;
-
-		if (bvprv && cluster) {
-			if (sg->length + nbytes > queue_max_segment_size(q))
-				goto new_segment;
-
-			if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec))
-				goto new_segment;
-			if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bvec))
-				goto new_segment;
-
-			sg->length += nbytes;
-		} else {
-new_segment:
-			if (!sg)
-				sg = sglist;
-			else {
-				/*
-				 * If the driver previously mapped a shorter
-				 * list, we could see a termination bit
-				 * prematurely unless it fully inits the sg
-				 * table on each mapping. We KNOW that there
-				 * must be more entries here or the driver
-				 * would be buggy, so force clear the
-				 * termination bit to avoid doing a full
-				 * sg_init_table() in drivers for each command.
-				 */
-				sg->page_link &= ~0x02;
-				sg = sg_next(sg);
-			}
-
-			sg_set_page(sg, bvec->bv_page, nbytes, bvec->bv_offset);
-			nsegs++;
-		}
-		bvprv = bvec;
+		__blk_segment_map_sg(q, bvec, sglist, &bvprv, &sg,
+				     &nsegs, &cluster);
 	} /* segments in rq */
 
 
@@ -199,6 +209,43 @@ new_segment:
 }
 EXPORT_SYMBOL(blk_rq_map_sg);
 
+/**
+ * blk_bio_map_sg - map a bio to a scatterlist
+ * @q: request_queue in question
+ * @bio: bio being mapped
+ * @sglist: scatterlist being mapped
+ *
+ * Note:
+ *    Caller must make sure sg can hold bio->bi_phys_segments entries
+ *
+ * Will return the number of sg entries setup
+ */
+int blk_bio_map_sg(struct request_queue *q, struct bio *bio,
+		   struct scatterlist *sglist)
+{
+	struct bio_vec *bvec, *bvprv;
+	struct scatterlist *sg;
+	int nsegs, cluster;
+	unsigned long i;
+
+	nsegs = 0;
+	cluster = blk_queue_cluster(q);
+
+	bvprv = NULL;
+	sg = NULL;
+	bio_for_each_segment(bvec, bio, i) {
+		__blk_segment_map_sg(q, bvec, sglist, &bvprv, &sg,
+				     &nsegs, &cluster);
+	} /* segments in bio */
+
+	if (sg)
+		sg_mark_end(sg);
+
+	BUG_ON(bio->bi_phys_segments && nsegs > bio->bi_phys_segments);
+	return nsegs;
+}
+EXPORT_SYMBOL(blk_bio_map_sg);
+
 static inline int ll_new_hw_segment(struct request_queue *q,
 				    struct request *req,
 				    struct bio *bio)
diff --git a/block/genhd.c b/block/genhd.c
index cac7366..41d013e 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -835,7 +835,7 @@ static void disk_seqf_stop(struct seq_file *seqf, void *v)
 
 static void *show_partition_start(struct seq_file *seqf, loff_t *pos)
 {
-	static void *p;
+	void *p;
 
 	p = disk_seqf_start(seqf, pos);
 	if (!IS_ERR_OR_NULL(p) && !*pos)
@@ -1534,10 +1534,8 @@ void disk_flush_events(struct gendisk *disk, unsigned int mask)
 
 	spin_lock_irq(&ev->lock);
 	ev->clearing |= mask;
-	if (!ev->block) {
-		cancel_delayed_work(&ev->dwork);
-		queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0);
-	}
+	if (!ev->block)
+		mod_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0);
 	spin_unlock_irq(&ev->lock);
 }
 
diff --git a/crypto/842.c b/crypto/842.c
new file mode 100644
index 0000000..144767d
--- /dev/null
+++ b/crypto/842.c
@@ -0,0 +1,183 @@
+/*
+ * Cryptographic API for the 842 compression algorithm.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright (C) IBM Corporation, 2011
+ *
+ * Authors: Robert Jennings <rcj@linux.vnet.ibm.com>
+ *          Seth Jennings <sjenning@linux.vnet.ibm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <linux/vmalloc.h>
+#include <linux/nx842.h>
+#include <linux/lzo.h>
+#include <linux/timer.h>
+
+static int nx842_uselzo;
+
+struct nx842_ctx {
+	void *nx842_wmem; /* working memory for 842/lzo */
+};
+
+enum nx842_crypto_type {
+	NX842_CRYPTO_TYPE_842,
+	NX842_CRYPTO_TYPE_LZO
+};
+
+#define NX842_SENTINEL 0xdeadbeef
+
+struct nx842_crypto_header {
+	unsigned int sentinel; /* debug */
+	enum nx842_crypto_type type;
+};
+
+static int nx842_init(struct crypto_tfm *tfm)
+{
+	struct nx842_ctx *ctx = crypto_tfm_ctx(tfm);
+	int wmemsize;
+
+	wmemsize = max_t(int, nx842_get_workmem_size(), LZO1X_MEM_COMPRESS);
+	ctx->nx842_wmem = kmalloc(wmemsize, GFP_NOFS);
+	if (!ctx->nx842_wmem)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void nx842_exit(struct crypto_tfm *tfm)
+{
+	struct nx842_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	kfree(ctx->nx842_wmem);
+}
+
+static void nx842_reset_uselzo(unsigned long data)
+{
+	nx842_uselzo = 0;
+}
+
+static DEFINE_TIMER(failover_timer, nx842_reset_uselzo, 0, 0);
+
+static int nx842_crypto_compress(struct crypto_tfm *tfm, const u8 *src,
+			    unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+	struct nx842_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct nx842_crypto_header *hdr;
+	unsigned int tmp_len = *dlen;
+	size_t lzodlen; /* needed for lzo */
+	int err;
+
+	*dlen = 0;
+	hdr = (struct nx842_crypto_header *)dst;
+	hdr->sentinel = NX842_SENTINEL; /* debug */
+	dst += sizeof(struct nx842_crypto_header);
+	tmp_len -= sizeof(struct nx842_crypto_header);
+	lzodlen = tmp_len;
+
+	if (likely(!nx842_uselzo)) {
+		err = nx842_compress(src, slen, dst, &tmp_len, ctx->nx842_wmem);
+
+		if (likely(!err)) {
+			hdr->type = NX842_CRYPTO_TYPE_842;
+			*dlen = tmp_len + sizeof(struct nx842_crypto_header);
+			return 0;
+		}
+
+		/* hardware failed */
+		nx842_uselzo = 1;
+
+		/* set timer to check for hardware again in 1 second */
+		mod_timer(&failover_timer, jiffies + msecs_to_jiffies(1000));
+	}
+
+	/* no hardware, use lzo */
+	err = lzo1x_1_compress(src, slen, dst, &lzodlen, ctx->nx842_wmem);
+	if (err != LZO_E_OK)
+		return -EINVAL;
+
+	hdr->type = NX842_CRYPTO_TYPE_LZO;
+	*dlen = lzodlen + sizeof(struct nx842_crypto_header);
+	return 0;
+}
+
+static int nx842_crypto_decompress(struct crypto_tfm *tfm, const u8 *src,
+			      unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+	struct nx842_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct nx842_crypto_header *hdr;
+	unsigned int tmp_len = *dlen;
+	size_t lzodlen; /* needed for lzo */
+	int err;
+
+	*dlen = 0;
+	hdr = (struct nx842_crypto_header *)src;
+
+	if (unlikely(hdr->sentinel != NX842_SENTINEL))
+		return -EINVAL;
+
+	src += sizeof(struct nx842_crypto_header);
+	slen -= sizeof(struct nx842_crypto_header);
+
+	if (likely(hdr->type == NX842_CRYPTO_TYPE_842)) {
+		err = nx842_decompress(src, slen, dst, &tmp_len,
+			ctx->nx842_wmem);
+		if (err)
+			return -EINVAL;
+		*dlen = tmp_len;
+	} else if (hdr->type == NX842_CRYPTO_TYPE_LZO) {
+		lzodlen = tmp_len;
+		err = lzo1x_decompress_safe(src, slen, dst, &lzodlen);
+		if (err != LZO_E_OK)
+			return -EINVAL;
+		*dlen = lzodlen;
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+
+static struct crypto_alg alg = {
+	.cra_name		= "842",
+	.cra_flags		= CRYPTO_ALG_TYPE_COMPRESS,
+	.cra_ctxsize		= sizeof(struct nx842_ctx),
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(alg.cra_list),
+	.cra_init		= nx842_init,
+	.cra_exit		= nx842_exit,
+	.cra_u			= { .compress = {
+	.coa_compress		= nx842_crypto_compress,
+	.coa_decompress		= nx842_crypto_decompress } }
+};
+
+static int __init nx842_mod_init(void)
+{
+	del_timer(&failover_timer);
+	return crypto_register_alg(&alg);
+}
+
+static void __exit nx842_mod_exit(void)
+{
+	crypto_unregister_alg(&alg);
+}
+
+module_init(nx842_mod_init);
+module_exit(nx842_mod_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("842 Compression Algorithm");
diff --git a/crypto/Kconfig b/crypto/Kconfig
index a323805..cbcc0e2 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -692,6 +692,20 @@ config CRYPTO_CAST5
 	  The CAST5 encryption algorithm (synonymous with CAST-128) is
 	  described in RFC2144.
 
+config CRYPTO_CAST5_AVX_X86_64
+	tristate "CAST5 (CAST-128) cipher algorithm (x86_64/AVX)"
+	depends on X86 && 64BIT
+	select CRYPTO_ALGAPI
+	select CRYPTO_CRYPTD
+	select CRYPTO_ABLK_HELPER_X86
+	select CRYPTO_CAST5
+	help
+	  The CAST5 encryption algorithm (synonymous with CAST-128) is
+	  described in RFC2144.
+
+	  This module provides the Cast5 cipher algorithm that processes
+	  sixteen blocks parallel using the AVX instruction set.
+
 config CRYPTO_CAST6
 	tristate "CAST6 (CAST-256) cipher algorithm"
 	select CRYPTO_ALGAPI
@@ -699,6 +713,23 @@ config CRYPTO_CAST6
 	  The CAST6 encryption algorithm (synonymous with CAST-256) is
 	  described in RFC2612.
 
+config CRYPTO_CAST6_AVX_X86_64
+	tristate "CAST6 (CAST-256) cipher algorithm (x86_64/AVX)"
+	depends on X86 && 64BIT
+	select CRYPTO_ALGAPI
+	select CRYPTO_CRYPTD
+	select CRYPTO_ABLK_HELPER_X86
+	select CRYPTO_GLUE_HELPER_X86
+	select CRYPTO_CAST6
+	select CRYPTO_LRW
+	select CRYPTO_XTS
+	help
+	  The CAST6 encryption algorithm (synonymous with CAST-256) is
+	  described in RFC2612.
+
+	  This module provides the Cast6 cipher algorithm that processes
+	  eight blocks parallel using the AVX instruction set.
+
 config CRYPTO_DES
 	tristate "DES and Triple DES EDE cipher algorithms"
 	select CRYPTO_ALGAPI
@@ -1008,6 +1039,15 @@ config CRYPTO_LZO
 	help
 	  This is the LZO algorithm.
 
+config CRYPTO_842
+	tristate "842 compression algorithm"
+	depends on CRYPTO_DEV_NX_COMPRESS
+	# 842 uses lzo if the hardware becomes unavailable
+	select LZO_COMPRESS
+	select LZO_DECOMPRESS
+	help
+	  This is the 842 algorithm.
+
 comment "Random Number Generation"
 
 config CRYPTO_ANSI_CPRNG
diff --git a/crypto/Makefile b/crypto/Makefile
index 30f33d6..a301ad2 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -68,8 +68,8 @@ obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o
 obj-$(CONFIG_CRYPTO_SERPENT) += serpent_generic.o
 obj-$(CONFIG_CRYPTO_AES) += aes_generic.o
 obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia_generic.o
-obj-$(CONFIG_CRYPTO_CAST5) += cast5.o
-obj-$(CONFIG_CRYPTO_CAST6) += cast6.o
+obj-$(CONFIG_CRYPTO_CAST5) += cast5_generic.o
+obj-$(CONFIG_CRYPTO_CAST6) += cast6_generic.o
 obj-$(CONFIG_CRYPTO_ARC4) += arc4.o
 obj-$(CONFIG_CRYPTO_TEA) += tea.o
 obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o
@@ -82,6 +82,7 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
 obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
 obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o
 obj-$(CONFIG_CRYPTO_LZO) += lzo.o
+obj-$(CONFIG_CRYPTO_842) += 842.o
 obj-$(CONFIG_CRYPTO_RNG2) += rng.o
 obj-$(CONFIG_CRYPTO_RNG2) += krng.o
 obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o
diff --git a/crypto/aes_generic.c b/crypto/aes_generic.c
index a68c73d..47f2e5c 100644
--- a/crypto/aes_generic.c
+++ b/crypto/aes_generic.c
@@ -1448,7 +1448,6 @@ static struct crypto_alg aes_alg = {
 	.cra_ctxsize		=	sizeof(struct crypto_aes_ctx),
 	.cra_alignmask		=	3,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(aes_alg.cra_list),
 	.cra_u			=	{
 		.cipher = {
 			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c
index 6ddd99e..c0bb377 100644
--- a/crypto/ansi_cprng.c
+++ b/crypto/ansi_cprng.c
@@ -382,26 +382,6 @@ static int cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
 	return 0;
 }
 
-static struct crypto_alg rng_alg = {
-	.cra_name		= "stdrng",
-	.cra_driver_name	= "ansi_cprng",
-	.cra_priority		= 100,
-	.cra_flags		= CRYPTO_ALG_TYPE_RNG,
-	.cra_ctxsize		= sizeof(struct prng_context),
-	.cra_type		= &crypto_rng_type,
-	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(rng_alg.cra_list),
-	.cra_init		= cprng_init,
-	.cra_exit		= cprng_exit,
-	.cra_u			= {
-		.rng = {
-			.rng_make_random	= cprng_get_random,
-			.rng_reset		= cprng_reset,
-			.seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ,
-		}
-	}
-};
-
 #ifdef CONFIG_CRYPTO_FIPS
 static int fips_cprng_get_random(struct crypto_rng *tfm, u8 *rdata,
 			    unsigned int dlen)
@@ -438,8 +418,27 @@ static int fips_cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
 out:
 	return rc;
 }
+#endif
 
-static struct crypto_alg fips_rng_alg = {
+static struct crypto_alg rng_algs[] = { {
+	.cra_name		= "stdrng",
+	.cra_driver_name	= "ansi_cprng",
+	.cra_priority		= 100,
+	.cra_flags		= CRYPTO_ALG_TYPE_RNG,
+	.cra_ctxsize		= sizeof(struct prng_context),
+	.cra_type		= &crypto_rng_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= cprng_init,
+	.cra_exit		= cprng_exit,
+	.cra_u			= {
+		.rng = {
+			.rng_make_random	= cprng_get_random,
+			.rng_reset		= cprng_reset,
+			.seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ,
+		}
+	}
+#ifdef CONFIG_CRYPTO_FIPS
+}, {
 	.cra_name		= "fips(ansi_cprng)",
 	.cra_driver_name	= "fips_ansi_cprng",
 	.cra_priority		= 300,
@@ -447,7 +446,6 @@ static struct crypto_alg fips_rng_alg = {
 	.cra_ctxsize		= sizeof(struct prng_context),
 	.cra_type		= &crypto_rng_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(rng_alg.cra_list),
 	.cra_init		= cprng_init,
 	.cra_exit		= cprng_exit,
 	.cra_u			= {
@@ -457,33 +455,18 @@ static struct crypto_alg fips_rng_alg = {
 			.seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ,
 		}
 	}
-};
 #endif
+} };
 
 /* Module initalization */
 static int __init prng_mod_init(void)
 {
-	int rc = 0;
-
-	rc = crypto_register_alg(&rng_alg);
-#ifdef CONFIG_CRYPTO_FIPS
-	if (rc)
-		goto out;
-
-	rc = crypto_register_alg(&fips_rng_alg);
-
-out:
-#endif
-	return rc;
+	return crypto_register_algs(rng_algs, ARRAY_SIZE(rng_algs));
 }
 
 static void __exit prng_mod_fini(void)
 {
-	crypto_unregister_alg(&rng_alg);
-#ifdef CONFIG_CRYPTO_FIPS
-	crypto_unregister_alg(&fips_rng_alg);
-#endif
-	return;
+	crypto_unregister_algs(rng_algs, ARRAY_SIZE(rng_algs));
 }
 
 MODULE_LICENSE("GPL");
diff --git a/crypto/anubis.c b/crypto/anubis.c
index 77530d5..008c8a4 100644
--- a/crypto/anubis.c
+++ b/crypto/anubis.c
@@ -678,7 +678,6 @@ static struct crypto_alg anubis_alg = {
 	.cra_ctxsize		=	sizeof (struct anubis_ctx),
 	.cra_alignmask		=	3,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(anubis_alg.cra_list),
 	.cra_u			=	{ .cipher = {
 	.cia_min_keysize	=	ANUBIS_MIN_KEY_SIZE,
 	.cia_max_keysize	=	ANUBIS_MAX_KEY_SIZE,
diff --git a/crypto/blowfish_generic.c b/crypto/blowfish_generic.c
index 6f269b5..8baf544 100644
--- a/crypto/blowfish_generic.c
+++ b/crypto/blowfish_generic.c
@@ -115,7 +115,6 @@ static struct crypto_alg alg = {
 	.cra_ctxsize		=	sizeof(struct bf_ctx),
 	.cra_alignmask		=	3,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(alg.cra_list),
 	.cra_u			=	{ .cipher = {
 	.cia_min_keysize	=	BF_MIN_KEY_SIZE,
 	.cia_max_keysize	=	BF_MAX_KEY_SIZE,
diff --git a/crypto/camellia_generic.c b/crypto/camellia_generic.c
index f7aaaaf..75efa20 100644
--- a/crypto/camellia_generic.c
+++ b/crypto/camellia_generic.c
@@ -1072,7 +1072,6 @@ static struct crypto_alg camellia_alg = {
 	.cra_ctxsize		=	sizeof(struct camellia_ctx),
 	.cra_alignmask		=	3,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(camellia_alg.cra_list),
 	.cra_u			=	{
 		.cipher = {
 			.cia_min_keysize	=	CAMELLIA_MIN_KEY_SIZE,
diff --git a/crypto/cast5.c b/crypto/cast5.c
deleted file mode 100644
index 4a230dd..0000000
--- a/crypto/cast5.c
+++ /dev/null
@@ -1,809 +0,0 @@
-/* Kernel cryptographic api.
-* cast5.c - Cast5 cipher algorithm (rfc2144).
-*
-* Derived from GnuPG implementation of cast5.
-*
-* Major Changes.
-* 	Complete conformance to rfc2144.
-* 	Supports key size from 40 to 128 bits.
-*
-* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
-* Copyright (C) 2003 Kartikey Mahendra Bhatt <kartik_me@hotmail.com>.
-*
-* This program is free software; you can redistribute it and/or modify it
-* under the terms of GNU General Public License as published by the Free
-* Software Foundation; either version 2 of the License, or (at your option)
-* any later version.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program; if not, write to the Free Software
-* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
-*/
-
-
-#include <asm/byteorder.h>
-#include <linux/init.h>
-#include <linux/crypto.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-
-#define CAST5_BLOCK_SIZE 8
-#define CAST5_MIN_KEY_SIZE 5
-#define CAST5_MAX_KEY_SIZE 16
-
-struct cast5_ctx {
-	u32 Km[16];
-	u8 Kr[16];
-	int rr;	/* rr?number of rounds = 16:number of rounds = 12; (rfc 2144) */
-};
-
-
-static const u32 s1[256] = {
-	0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f,
-	0x9c004dd3, 0x6003e540, 0xcf9fc949,
-	0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0,
-	0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
-	0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3,
-	0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
-	0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1,
-	0xaa54166b, 0x22568e3a, 0xa2d341d0,
-	0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac,
-	0x4a97c1d8, 0x527644b7, 0xb5f437a7,
-	0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0,
-	0x90ecf52e, 0x22b0c054, 0xbc8e5935,
-	0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290,
-	0xe93b159f, 0xb48ee411, 0x4bff345d,
-	0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad,
-	0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
-	0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f,
-	0xc59c5319, 0xb949e354, 0xb04669fe,
-	0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5,
-	0x6a390493, 0xe63d37e0, 0x2a54f6b3,
-	0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5,
-	0xf61b1891, 0xbb72275e, 0xaa508167,
-	0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427,
-	0xa2d1936b, 0x2ad286af, 0xaa56d291,
-	0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d,
-	0x73e2bb14, 0xa0bebc3c, 0x54623779,
-	0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e,
-	0x89fe78e6, 0x3fab0950, 0x325ff6c2,
-	0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf,
-	0x380782d5, 0xc7fa5cf6, 0x8ac31511,
-	0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241,
-	0x051ef495, 0xaa573b04, 0x4a805d8d,
-	0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b,
-	0x50afd341, 0xa7c13275, 0x915a0bf5,
-	0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265,
-	0xab85c5f3, 0x1b55db94, 0xaad4e324,
-	0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3,
-	0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
-	0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6,
-	0x22513f1e, 0xaa51a79b, 0x2ad344cc,
-	0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6,
-	0x032268d4, 0xc9600acc, 0xce387e6d,
-	0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da,
-	0x4736f464, 0x5ad328d8, 0xb347cc96,
-	0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc,
-	0xbfc5fe4a, 0xa70aec10, 0xac39570a,
-	0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f,
-	0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
-	0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4,
-	0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
-	0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af,
-	0x51c85f4d, 0x56907596, 0xa5bb15e6,
-	0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a,
-	0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
-	0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf,
-	0x700b45e1, 0xd5ea50f1, 0x85a92872,
-	0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198,
-	0x0cd0ede7, 0x26470db8, 0xf881814c,
-	0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db,
-	0xab838653, 0x6e2f1e23, 0x83719c9e,
-	0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c,
-	0xe1e696ff, 0xb141ab08, 0x7cca89b9,
-	0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c,
-	0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
-};
-static const u32 s2[256] = {
-	0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a,
-	0xeec5207a, 0x55889c94, 0x72fc0651,
-	0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef,
-	0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
-	0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086,
-	0xef944459, 0xba83ccb3, 0xe0c3cdfb,
-	0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb,
-	0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
-	0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f,
-	0x77e83f4e, 0x79929269, 0x24fa9f7b,
-	0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154,
-	0x0d554b63, 0x5d681121, 0xc866c359,
-	0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181,
-	0x39f7627f, 0x361e3084, 0xe4eb573b,
-	0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c,
-	0x99847ab4, 0xa0e3df79, 0xba6cf38c,
-	0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a,
-	0x8f458c74, 0xd9e0a227, 0x4ec73a34,
-	0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c,
-	0x1d804366, 0x721d9bfd, 0xa58684bb,
-	0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1,
-	0x27e19ba5, 0xd5a6c252, 0xe49754bd,
-	0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9,
-	0xe0b56714, 0x21f043b7, 0xe5d05860,
-	0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf,
-	0x68561be6, 0x83ca6b94, 0x2d6ed23b,
-	0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c,
-	0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
-	0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122,
-	0xb96726d1, 0x8049a7e8, 0x22b7da7b,
-	0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402,
-	0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
-	0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53,
-	0xe3214517, 0xb4542835, 0x9f63293c,
-	0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6,
-	0x30a22c95, 0x31a70850, 0x60930f13,
-	0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6,
-	0xa02b1741, 0x7cbad9a2, 0x2180036f,
-	0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676,
-	0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
-	0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb,
-	0x846a3bae, 0x8ff77888, 0xee5d60f6,
-	0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54,
-	0x157fd7fa, 0xef8579cc, 0xd152de58,
-	0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5,
-	0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
-	0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8,
-	0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
-	0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc,
-	0x301e16e6, 0x273be979, 0xb0ffeaa6,
-	0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a,
-	0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
-	0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e,
-	0x1a513742, 0xef6828bc, 0x520365d6,
-	0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb,
-	0x5eea29cb, 0x145892f5, 0x91584f7f,
-	0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4,
-	0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
-	0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3,
-	0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
-	0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589,
-	0xa345415e, 0x5c038323, 0x3e5d3bb9,
-	0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539,
-	0x73bfbe70, 0x83877605, 0x4523ecf1
-};
-static const u32 s3[256] = {
-	0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff,
-	0x369fe44b, 0x8c1fc644, 0xaececa90,
-	0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806,
-	0xf0ad0548, 0xe13c8d83, 0x927010d5,
-	0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820,
-	0xfade82e0, 0xa067268b, 0x8272792e,
-	0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee,
-	0x825b1bfd, 0x9255c5ed, 0x1257a240,
-	0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf,
-	0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
-	0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1,
-	0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
-	0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c,
-	0x4a012d6e, 0xc5884a28, 0xccc36f71,
-	0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850,
-	0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
-	0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e,
-	0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
-	0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0,
-	0x1eac5790, 0x796fb449, 0x8252dc15,
-	0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403,
-	0xe83ec305, 0x4f91751a, 0x925669c2,
-	0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574,
-	0x927985b2, 0x8276dbcb, 0x02778176,
-	0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83,
-	0x340ce5c8, 0x96bbb682, 0x93b4b148,
-	0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20,
-	0x8437aa88, 0x7d29dc96, 0x2756d3dc,
-	0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e,
-	0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
-	0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9,
-	0xbda8229c, 0x127dadaa, 0x438a074e,
-	0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff,
-	0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
-	0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a,
-	0x76a2e214, 0xb9a40368, 0x925d958f,
-	0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623,
-	0x193cbcfa, 0x27627545, 0x825cf47a,
-	0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7,
-	0x8272a972, 0x9270c4a8, 0x127de50b,
-	0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb,
-	0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
-	0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11,
-	0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
-	0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c,
-	0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
-	0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40,
-	0x7c34671c, 0x02717ef6, 0x4feb5536,
-	0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1,
-	0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
-	0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33,
-	0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
-	0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff,
-	0x856302e0, 0x72dbd92b, 0xee971b69,
-	0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2,
-	0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
-	0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38,
-	0x0ff0443d, 0x606e6dc6, 0x60543a49,
-	0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f,
-	0x68458425, 0x99833be5, 0x600d457d,
-	0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31,
-	0x9c305a00, 0x52bce688, 0x1b03588a,
-	0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636,
-	0xa133c501, 0xe9d3531c, 0xee353783
-};
-static const u32 s4[256] = {
-	0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb,
-	0x64ad8c57, 0x85510443, 0xfa020ed1,
-	0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43,
-	0x6497b7b1, 0xf3641f63, 0x241e4adf,
-	0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30,
-	0xc0a5374f, 0x1d2d00d9, 0x24147b15,
-	0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f,
-	0x0c13fefe, 0x081b08ca, 0x05170121,
-	0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f,
-	0x06df4261, 0xbb9e9b8a, 0x7293ea25,
-	0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400,
-	0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
-	0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061,
-	0x11b638e1, 0x72500e03, 0xf80eb2bb,
-	0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400,
-	0x6920318f, 0x081dbb99, 0xffc304a5,
-	0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea,
-	0x9f926f91, 0x9f46222f, 0x3991467d,
-	0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8,
-	0x3fb6180c, 0x18f8931e, 0x281658e6,
-	0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25,
-	0x79098b02, 0xe4eabb81, 0x28123b23,
-	0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9,
-	0x0014377b, 0x041e8ac8, 0x09114003,
-	0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de,
-	0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
-	0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0,
-	0x56c8c391, 0x6b65811c, 0x5e146119,
-	0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d,
-	0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
-	0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a,
-	0xeca1d7c7, 0x041afa32, 0x1d16625a,
-	0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb,
-	0xc70b8b46, 0xd9e66a48, 0x56e55a79,
-	0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3,
-	0xedda04eb, 0x17a9be04, 0x2c18f4df,
-	0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254,
-	0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
-	0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2,
-	0x0418f2c8, 0x001a96a6, 0x0d1526ab,
-	0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86,
-	0x311170a7, 0x3e9b640c, 0xcc3e10d7,
-	0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1,
-	0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
-	0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca,
-	0xb4be31cd, 0xd8782806, 0x12a3a4e2,
-	0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5,
-	0x9711aac5, 0x001d7b95, 0x82e5e7d2,
-	0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415,
-	0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
-	0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7,
-	0x0ce454a9, 0xd60acd86, 0x015f1919,
-	0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe,
-	0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
-	0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb,
-	0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
-	0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8,
-	0x296b299e, 0x492fc295, 0x9266beab,
-	0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee,
-	0xf65324e6, 0x6afce36c, 0x0316cc04,
-	0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979,
-	0x932bcdf6, 0xb657c34d, 0x4edfd282,
-	0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0,
-	0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2
-};
-static const u32 s5[256] = {
-	0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff,
-	0x1dd358f5, 0x44dd9d44, 0x1731167f,
-	0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8,
-	0x386381cb, 0xacf6243a, 0x69befd7a,
-	0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640,
-	0x15b0a848, 0xe68b18cb, 0x4caadeff,
-	0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d,
-	0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
-	0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7,
-	0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
-	0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88,
-	0x8709e6b0, 0xd7e07156, 0x4e29fea7,
-	0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a,
-	0x578535f2, 0x2261be02, 0xd642a0c9,
-	0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8,
-	0xc8adedb3, 0x28a87fc9, 0x3d959981,
-	0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1,
-	0x4fb96976, 0x90c79505, 0xb0a8a774,
-	0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f,
-	0x0ec50966, 0xdfdd55bc, 0x29de0655,
-	0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980,
-	0x524755f4, 0x03b63cc9, 0x0cc844b2,
-	0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449,
-	0x64ee2d7e, 0xcddbb1da, 0x01c94910,
-	0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6,
-	0x50f5b616, 0xf24766e3, 0x8eca36c1,
-	0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9,
-	0x3063fcdf, 0xb6f589de, 0xec2941da,
-	0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401,
-	0xc1bacb7f, 0xe5ff550f, 0xb6083049,
-	0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd,
-	0x9e0885f9, 0x68cb3e47, 0x086c010f,
-	0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3,
-	0xcbb3d550, 0x1793084d, 0xb0d70eba,
-	0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56,
-	0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
-	0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280,
-	0x05687715, 0x646c6bd7, 0x44904db3,
-	0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f,
-	0x2cb6356a, 0x85808573, 0x4991f840,
-	0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8,
-	0xc1092910, 0x8bc95fc6, 0x7d869cf4,
-	0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717,
-	0x7d161bba, 0x9cad9010, 0xaf462ba2,
-	0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e,
-	0x176d486f, 0x097c13ea, 0x631da5c7,
-	0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72,
-	0x6e5dd2f3, 0x20936079, 0x459b80a5,
-	0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572,
-	0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
-	0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e,
-	0x75922283, 0x784d6b17, 0x58ebb16e,
-	0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf,
-	0xaaf47556, 0x5f46b02a, 0x2b092801,
-	0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874,
-	0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
-	0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826,
-	0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
-	0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9,
-	0x17e3fe2a, 0x24b79767, 0xf5a96b20,
-	0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a,
-	0xeeb9491d, 0x34010718, 0xbb30cab8,
-	0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8,
-	0xb1534546, 0x6d47de08, 0xefe9e7d4
-};
-static const u32 s6[256] = {
-	0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7,
-	0x016843b4, 0xeced5cbc, 0x325553ac,
-	0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8,
-	0xde5ebe39, 0xf38ff732, 0x8989b138,
-	0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99,
-	0x4e23e33c, 0x79cbd7cc, 0x48a14367,
-	0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d,
-	0x09a8486f, 0xa888614a, 0x2900af98,
-	0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932,
-	0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
-	0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c,
-	0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
-	0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01,
-	0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
-	0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c,
-	0xb88153e2, 0x08a19866, 0x1ae2eac8,
-	0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3,
-	0x9aea3906, 0xefe8c36e, 0xf890cdd9,
-	0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc,
-	0x221db3a6, 0x9a69a02f, 0x68818a54,
-	0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc,
-	0xcf222ebf, 0x25ac6f48, 0xa9a99387,
-	0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1,
-	0xe8a11be9, 0x4980740d, 0xc8087dfc,
-	0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f,
-	0x9528cd89, 0xfd339fed, 0xb87834bf,
-	0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa,
-	0x57f55ec5, 0xe2220abe, 0xd2916ebf,
-	0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff,
-	0xa8dc8af0, 0x7345c106, 0xf41e232f,
-	0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af,
-	0x692573e4, 0xe9a9d848, 0xf3160289,
-	0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063,
-	0x4576698d, 0xb6fad407, 0x592af950,
-	0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8,
-	0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
-	0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d,
-	0x48b9d585, 0xdc049441, 0xc8098f9b,
-	0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6,
-	0x890072d6, 0x28207682, 0xa9a9f7be,
-	0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a,
-	0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
-	0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a,
-	0xb6c85283, 0x3cc2acfb, 0x3fc06976,
-	0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0,
-	0x513021a5, 0x6c5b68b7, 0x822f8aa0,
-	0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9,
-	0x0c5ec241, 0x8809286c, 0xf592d891,
-	0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98,
-	0xb173ecc0, 0xbc60b42a, 0x953498da,
-	0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123,
-	0x257f0c3d, 0x9348af49, 0x361400bc,
-	0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57,
-	0xda41e7f9, 0xc25ad33a, 0x54f4a084,
-	0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5,
-	0xb6f6deaf, 0x3a479c3a, 0x5302da25,
-	0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88,
-	0x44136c76, 0x0404a8c8, 0xb8e5a121,
-	0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913,
-	0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
-	0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1,
-	0xf544edeb, 0xb0e93524, 0xbebb8fbd,
-	0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905,
-	0xa65b1db8, 0x851c97bd, 0xd675cf2f
-};
-static const u32 s7[256] = {
-	0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f,
-	0xab9bc912, 0xde6008a1, 0x2028da1f,
-	0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11,
-	0xb232e75c, 0x4b3695f2, 0xb28707de,
-	0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381,
-	0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
-	0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be,
-	0xbaeeadf4, 0x1286becf, 0xb6eacb19,
-	0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66,
-	0x28136086, 0x0bd8dfa8, 0x356d1cf2,
-	0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a,
-	0xeb12ff82, 0xe3486911, 0xd34d7516,
-	0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce,
-	0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
-	0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa,
-	0x4437f107, 0xb6e79962, 0x42d2d816,
-	0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7,
-	0xf9583745, 0xcf19df58, 0xbec3f756,
-	0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511,
-	0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
-	0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f,
-	0xaff60ff4, 0xea2c4e6d, 0x16e39264,
-	0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a,
-	0xb2856e6e, 0x1aec3ca9, 0xbe838688,
-	0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85,
-	0x61fe033c, 0x16746233, 0x3c034c28,
-	0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a,
-	0x1626a49f, 0xeed82b29, 0x1d382fe3,
-	0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c,
-	0xd45230c7, 0x2bd1408b, 0x60c03eb7,
-	0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32,
-	0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
-	0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f,
-	0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
-	0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0,
-	0x79d34217, 0x021a718d, 0x9ac6336a,
-	0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef,
-	0x4eeb8476, 0x488dcf25, 0x36c9d566,
-	0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6,
-	0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
-	0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887,
-	0x2b9f4fd5, 0x625aba82, 0x6a017962,
-	0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22,
-	0xe32dbf9a, 0x058745b9, 0x3453dc1e,
-	0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1,
-	0x19de7eae, 0x053e561a, 0x15ad6f8c,
-	0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0,
-	0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
-	0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108,
-	0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
-	0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f,
-	0x3d321c5d, 0xc3f5e194, 0x4b269301,
-	0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e,
-	0x296693f4, 0x3d1fce6f, 0xc61e45be,
-	0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d,
-	0xb5229301, 0xcfd2a87f, 0x60aeb767,
-	0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b,
-	0x589dd390, 0x5479f8e6, 0x1cb8d647,
-	0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad,
-	0x462e1b78, 0x6580f87e, 0xf3817914,
-	0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc,
-	0x3d40f021, 0xc3c0bdae, 0x4958c24c,
-	0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7,
-	0x94e01be8, 0x90716f4b, 0x954b8aa3
-};
-static const u32 sb8[256] = {
-	0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7,
-	0xe6c1121b, 0x0e241600, 0x052ce8b5,
-	0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c,
-	0x76e38111, 0xb12def3a, 0x37ddddfc,
-	0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f,
-	0xb4d137cf, 0xb44e79f0, 0x049eedfd,
-	0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831,
-	0x3f8f95e7, 0x72df191b, 0x7580330d,
-	0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a,
-	0x02e7d1ca, 0x53571dae, 0x7a3182a2,
-	0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022,
-	0xce949ad4, 0xb84769ad, 0x965bd862,
-	0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f,
-	0xc28ec4b8, 0x57e8726e, 0x647a78fc,
-	0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3,
-	0xae63aff2, 0x7e8bd632, 0x70108c0c,
-	0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53,
-	0x06918548, 0x58cb7e07, 0x3b74ef2e,
-	0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2,
-	0x19b47a38, 0x424f7618, 0x35856039,
-	0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd,
-	0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
-	0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c,
-	0x3dd00db3, 0x708f8f34, 0x77d51b42,
-	0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e,
-	0x3e378160, 0x7895cda5, 0x859c15a5,
-	0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e,
-	0x31842e7b, 0x24259fd7, 0xf8bef472,
-	0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c,
-	0xe2506d3d, 0x4f9b12ea, 0xf215f225,
-	0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187,
-	0xea7a6e98, 0x7cd16efc, 0x1436876c,
-	0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899,
-	0x92ecbae6, 0xdd67016d, 0x151682eb,
-	0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e,
-	0xe139673b, 0xefa63fb8, 0x71873054,
-	0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d,
-	0x844a1be5, 0xbae7dfdc, 0x42cbda70,
-	0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428,
-	0x79d130a4, 0x3486ebfb, 0x33d3cddc,
-	0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4,
-	0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
-	0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2,
-	0x37df932b, 0xc4248289, 0xacf3ebc3,
-	0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e,
-	0x5e410fab, 0xb48a2465, 0x2eda7fa4,
-	0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b,
-	0xdb485694, 0x38d7e5b2, 0x57720101,
-	0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282,
-	0x7523d24a, 0xe0779695, 0xf9c17a8f,
-	0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f,
-	0xad1163ed, 0xea7b5965, 0x1a00726e,
-	0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0,
-	0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
-	0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca,
-	0x8951570f, 0xdf09822b, 0xbd691a6c,
-	0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f,
-	0x0d771c2b, 0x67cdb156, 0x350d8384,
-	0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61,
-	0x8360d87b, 0x1fa98b0c, 0x1149382c,
-	0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82,
-	0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
-	0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80,
-	0xeaee6801, 0x8db2a283, 0xea8bf59e
-};
-
-#define F1(D, m, r)  ((I = ((m) + (D))), (I = rol32(I, (r))),   \
-    (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff]))
-#define F2(D, m, r)  ((I = ((m) ^ (D))), (I = rol32(I, (r))),   \
-    (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff]))
-#define F3(D, m, r)  ((I = ((m) - (D))), (I = rol32(I, (r))),   \
-    (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]))
-
-
-static void cast5_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
-{
-	struct cast5_ctx *c = crypto_tfm_ctx(tfm);
-	const __be32 *src = (const __be32 *)inbuf;
-	__be32 *dst = (__be32 *)outbuf;
-	u32 l, r, t;
-	u32 I;			/* used by the Fx macros */
-	u32 *Km;
-	u8 *Kr;
-
-	Km = c->Km;
-	Kr = c->Kr;
-
-	/* (L0,R0) <-- (m1...m64).  (Split the plaintext into left and
-	 * right 32-bit halves L0 = m1...m32 and R0 = m33...m64.)
-	 */
-	l = be32_to_cpu(src[0]);
-	r = be32_to_cpu(src[1]);
-
-	/* (16 rounds) for i from 1 to 16, compute Li and Ri as follows:
-	 *  Li = Ri-1;
-	 *  Ri = Li-1 ^ f(Ri-1,Kmi,Kri), where f is defined in Section 2.2
-	 * Rounds 1, 4, 7, 10, 13, and 16 use f function Type 1.
-	 * Rounds 2, 5, 8, 11, and 14 use f function Type 2.
-	 * Rounds 3, 6, 9, 12, and 15 use f function Type 3.
-	 */
-
-	t = l; l = r; r = t ^ F1(r, Km[0], Kr[0]);
-	t = l; l = r; r = t ^ F2(r, Km[1], Kr[1]);
-	t = l; l = r; r = t ^ F3(r, Km[2], Kr[2]);
-	t = l; l = r; r = t ^ F1(r, Km[3], Kr[3]);
-	t = l; l = r; r = t ^ F2(r, Km[4], Kr[4]);
-	t = l; l = r; r = t ^ F3(r, Km[5], Kr[5]);
-	t = l; l = r; r = t ^ F1(r, Km[6], Kr[6]);
-	t = l; l = r; r = t ^ F2(r, Km[7], Kr[7]);
-	t = l; l = r; r = t ^ F3(r, Km[8], Kr[8]);
-	t = l; l = r; r = t ^ F1(r, Km[9], Kr[9]);
-	t = l; l = r; r = t ^ F2(r, Km[10], Kr[10]);
-	t = l; l = r; r = t ^ F3(r, Km[11], Kr[11]);
-	if (!(c->rr)) {
-		t = l; l = r; r = t ^ F1(r, Km[12], Kr[12]);
-		t = l; l = r; r = t ^ F2(r, Km[13], Kr[13]);
-		t = l; l = r; r = t ^ F3(r, Km[14], Kr[14]);
-		t = l; l = r; r = t ^ F1(r, Km[15], Kr[15]);
-	}
-
-	/* c1...c64 <-- (R16,L16).  (Exchange final blocks L16, R16 and
-	 *  concatenate to form the ciphertext.) */
-	dst[0] = cpu_to_be32(r);
-	dst[1] = cpu_to_be32(l);
-}
-
-static void cast5_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
-{
-	struct cast5_ctx *c = crypto_tfm_ctx(tfm);
-	const __be32 *src = (const __be32 *)inbuf;
-	__be32 *dst = (__be32 *)outbuf;
-	u32 l, r, t;
-	u32 I;
-	u32 *Km;
-	u8 *Kr;
-
-	Km = c->Km;
-	Kr = c->Kr;
-
-	l = be32_to_cpu(src[0]);
-	r = be32_to_cpu(src[1]);
-
-	if (!(c->rr)) {
-		t = l; l = r; r = t ^ F1(r, Km[15], Kr[15]);
-		t = l; l = r; r = t ^ F3(r, Km[14], Kr[14]);
-		t = l; l = r; r = t ^ F2(r, Km[13], Kr[13]);
-		t = l; l = r; r = t ^ F1(r, Km[12], Kr[12]);
-	}
-	t = l; l = r; r = t ^ F3(r, Km[11], Kr[11]);
-	t = l; l = r; r = t ^ F2(r, Km[10], Kr[10]);
-	t = l; l = r; r = t ^ F1(r, Km[9], Kr[9]);
-	t = l; l = r; r = t ^ F3(r, Km[8], Kr[8]);
-	t = l; l = r; r = t ^ F2(r, Km[7], Kr[7]);
-	t = l; l = r; r = t ^ F1(r, Km[6], Kr[6]);
-	t = l; l = r; r = t ^ F3(r, Km[5], Kr[5]);
-	t = l; l = r; r = t ^ F2(r, Km[4], Kr[4]);
-	t = l; l = r; r = t ^ F1(r, Km[3], Kr[3]);
-	t = l; l = r; r = t ^ F3(r, Km[2], Kr[2]);
-	t = l; l = r; r = t ^ F2(r, Km[1], Kr[1]);
-	t = l; l = r; r = t ^ F1(r, Km[0], Kr[0]);
-
-	dst[0] = cpu_to_be32(r);
-	dst[1] = cpu_to_be32(l);
-}
-
-static void key_schedule(u32 *x, u32 *z, u32 *k)
-{
-
-#define xi(i)   ((x[(i)/4] >> (8*(3-((i)%4)))) & 0xff)
-#define zi(i)   ((z[(i)/4] >> (8*(3-((i)%4)))) & 0xff)
-
-	z[0] = x[0] ^ s5[xi(13)] ^ s6[xi(15)] ^ s7[xi(12)] ^ sb8[xi(14)] ^
-	    s7[xi(8)];
-	z[1] = x[2] ^ s5[zi(0)] ^ s6[zi(2)] ^ s7[zi(1)] ^ sb8[zi(3)] ^
-	    sb8[xi(10)];
-	z[2] = x[3] ^ s5[zi(7)] ^ s6[zi(6)] ^ s7[zi(5)] ^ sb8[zi(4)] ^
-	    s5[xi(9)];
-	z[3] = x[1] ^ s5[zi(10)] ^ s6[zi(9)] ^ s7[zi(11)] ^ sb8[zi(8)] ^
-	    s6[xi(11)];
-	k[0] = s5[zi(8)] ^ s6[zi(9)] ^ s7[zi(7)] ^ sb8[zi(6)] ^ s5[zi(2)];
-	k[1] = s5[zi(10)] ^ s6[zi(11)] ^ s7[zi(5)] ^ sb8[zi(4)] ^
-	    s6[zi(6)];
-	k[2] = s5[zi(12)] ^ s6[zi(13)] ^ s7[zi(3)] ^ sb8[zi(2)] ^
-	    s7[zi(9)];
-	k[3] = s5[zi(14)] ^ s6[zi(15)] ^ s7[zi(1)] ^ sb8[zi(0)] ^
-	    sb8[zi(12)];
-
-	x[0] = z[2] ^ s5[zi(5)] ^ s6[zi(7)] ^ s7[zi(4)] ^ sb8[zi(6)] ^
-	    s7[zi(0)];
-	x[1] = z[0] ^ s5[xi(0)] ^ s6[xi(2)] ^ s7[xi(1)] ^ sb8[xi(3)] ^
-	    sb8[zi(2)];
-	x[2] = z[1] ^ s5[xi(7)] ^ s6[xi(6)] ^ s7[xi(5)] ^ sb8[xi(4)] ^
-	    s5[zi(1)];
-	x[3] = z[3] ^ s5[xi(10)] ^ s6[xi(9)] ^ s7[xi(11)] ^ sb8[xi(8)] ^
-	    s6[zi(3)];
-	k[4] = s5[xi(3)] ^ s6[xi(2)] ^ s7[xi(12)] ^ sb8[xi(13)] ^
-	    s5[xi(8)];
-	k[5] = s5[xi(1)] ^ s6[xi(0)] ^ s7[xi(14)] ^ sb8[xi(15)] ^
-	    s6[xi(13)];
-	k[6] = s5[xi(7)] ^ s6[xi(6)] ^ s7[xi(8)] ^ sb8[xi(9)] ^ s7[xi(3)];
-	k[7] = s5[xi(5)] ^ s6[xi(4)] ^ s7[xi(10)] ^ sb8[xi(11)] ^
-	    sb8[xi(7)];
-
-	z[0] = x[0] ^ s5[xi(13)] ^ s6[xi(15)] ^ s7[xi(12)] ^ sb8[xi(14)] ^
-	    s7[xi(8)];
-	z[1] = x[2] ^ s5[zi(0)] ^ s6[zi(2)] ^ s7[zi(1)] ^ sb8[zi(3)] ^
-	    sb8[xi(10)];
-	z[2] = x[3] ^ s5[zi(7)] ^ s6[zi(6)] ^ s7[zi(5)] ^ sb8[zi(4)] ^
-	    s5[xi(9)];
-	z[3] = x[1] ^ s5[zi(10)] ^ s6[zi(9)] ^ s7[zi(11)] ^ sb8[zi(8)] ^
-	    s6[xi(11)];
-	k[8] = s5[zi(3)] ^ s6[zi(2)] ^ s7[zi(12)] ^ sb8[zi(13)] ^
-	    s5[zi(9)];
-	k[9] = s5[zi(1)] ^ s6[zi(0)] ^ s7[zi(14)] ^ sb8[zi(15)] ^
-	    s6[zi(12)];
-	k[10] = s5[zi(7)] ^ s6[zi(6)] ^ s7[zi(8)] ^ sb8[zi(9)] ^ s7[zi(2)];
-	k[11] = s5[zi(5)] ^ s6[zi(4)] ^ s7[zi(10)] ^ sb8[zi(11)] ^
-	    sb8[zi(6)];
-
-	x[0] = z[2] ^ s5[zi(5)] ^ s6[zi(7)] ^ s7[zi(4)] ^ sb8[zi(6)] ^
-	    s7[zi(0)];
-	x[1] = z[0] ^ s5[xi(0)] ^ s6[xi(2)] ^ s7[xi(1)] ^ sb8[xi(3)] ^
-	    sb8[zi(2)];
-	x[2] = z[1] ^ s5[xi(7)] ^ s6[xi(6)] ^ s7[xi(5)] ^ sb8[xi(4)] ^
-	    s5[zi(1)];
-	x[3] = z[3] ^ s5[xi(10)] ^ s6[xi(9)] ^ s7[xi(11)] ^ sb8[xi(8)] ^
-	    s6[zi(3)];
-	k[12] = s5[xi(8)] ^ s6[xi(9)] ^ s7[xi(7)] ^ sb8[xi(6)] ^ s5[xi(3)];
-	k[13] = s5[xi(10)] ^ s6[xi(11)] ^ s7[xi(5)] ^ sb8[xi(4)] ^
-	    s6[xi(7)];
-	k[14] = s5[xi(12)] ^ s6[xi(13)] ^ s7[xi(3)] ^ sb8[xi(2)] ^
-	    s7[xi(8)];
-	k[15] = s5[xi(14)] ^ s6[xi(15)] ^ s7[xi(1)] ^ sb8[xi(0)] ^
-	    sb8[xi(13)];
-
-#undef xi
-#undef zi
-}
-
-
-static int cast5_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned key_len)
-{
-	struct cast5_ctx *c = crypto_tfm_ctx(tfm);
-	int i;
-	u32 x[4];
-	u32 z[4];
-	u32 k[16];
-	__be32 p_key[4];
-
-	c->rr = key_len <= 10 ? 1 : 0;
-
-	memset(p_key, 0, 16);
-	memcpy(p_key, key, key_len);
-
-
-	x[0] = be32_to_cpu(p_key[0]);
-	x[1] = be32_to_cpu(p_key[1]);
-	x[2] = be32_to_cpu(p_key[2]);
-	x[3] = be32_to_cpu(p_key[3]);
-
-	key_schedule(x, z, k);
-	for (i = 0; i < 16; i++)
-		c->Km[i] = k[i];
-	key_schedule(x, z, k);
-	for (i = 0; i < 16; i++)
-		c->Kr[i] = k[i] & 0x1f;
-	return 0;
-}
-
-static struct crypto_alg alg = {
-	.cra_name 	= "cast5",
-	.cra_flags 	= CRYPTO_ALG_TYPE_CIPHER,
-	.cra_blocksize 	= CAST5_BLOCK_SIZE,
-	.cra_ctxsize 	= sizeof(struct cast5_ctx),
-	.cra_alignmask	= 3,
-	.cra_module 	= THIS_MODULE,
-	.cra_list 	= LIST_HEAD_INIT(alg.cra_list),
-	.cra_u 		= {
-		.cipher = {
-			.cia_min_keysize = CAST5_MIN_KEY_SIZE,
-			.cia_max_keysize = CAST5_MAX_KEY_SIZE,
-			.cia_setkey = cast5_setkey,
-			.cia_encrypt = cast5_encrypt,
-			.cia_decrypt = cast5_decrypt
-		}
-	}
-};
-
-static int __init cast5_mod_init(void)
-{
-	return crypto_register_alg(&alg);
-}
-
-static void __exit cast5_mod_fini(void)
-{
-	crypto_unregister_alg(&alg);
-}
-
-module_init(cast5_mod_init);
-module_exit(cast5_mod_fini);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Cast5 Cipher Algorithm");
-
diff --git a/crypto/cast5_generic.c b/crypto/cast5_generic.c
new file mode 100644
index 0000000..bc525db
--- /dev/null
+++ b/crypto/cast5_generic.c
@@ -0,0 +1,821 @@
+/* Kernel cryptographic api.
+* cast5.c - Cast5 cipher algorithm (rfc2144).
+*
+* Derived from GnuPG implementation of cast5.
+*
+* Major Changes.
+*	Complete conformance to rfc2144.
+*	Supports key size from 40 to 128 bits.
+*
+* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+* Copyright (C) 2003 Kartikey Mahendra Bhatt <kartik_me@hotmail.com>.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+*/
+
+
+#include <asm/byteorder.h>
+#include <linux/init.h>
+#include <linux/crypto.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <crypto/cast5.h>
+
+
+const u32 cast5_s1[256] = {
+	0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f,
+	0x9c004dd3, 0x6003e540, 0xcf9fc949,
+	0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0,
+	0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
+	0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3,
+	0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
+	0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1,
+	0xaa54166b, 0x22568e3a, 0xa2d341d0,
+	0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac,
+	0x4a97c1d8, 0x527644b7, 0xb5f437a7,
+	0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0,
+	0x90ecf52e, 0x22b0c054, 0xbc8e5935,
+	0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290,
+	0xe93b159f, 0xb48ee411, 0x4bff345d,
+	0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad,
+	0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
+	0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f,
+	0xc59c5319, 0xb949e354, 0xb04669fe,
+	0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5,
+	0x6a390493, 0xe63d37e0, 0x2a54f6b3,
+	0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5,
+	0xf61b1891, 0xbb72275e, 0xaa508167,
+	0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427,
+	0xa2d1936b, 0x2ad286af, 0xaa56d291,
+	0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d,
+	0x73e2bb14, 0xa0bebc3c, 0x54623779,
+	0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e,
+	0x89fe78e6, 0x3fab0950, 0x325ff6c2,
+	0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf,
+	0x380782d5, 0xc7fa5cf6, 0x8ac31511,
+	0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241,
+	0x051ef495, 0xaa573b04, 0x4a805d8d,
+	0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b,
+	0x50afd341, 0xa7c13275, 0x915a0bf5,
+	0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265,
+	0xab85c5f3, 0x1b55db94, 0xaad4e324,
+	0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3,
+	0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
+	0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6,
+	0x22513f1e, 0xaa51a79b, 0x2ad344cc,
+	0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6,
+	0x032268d4, 0xc9600acc, 0xce387e6d,
+	0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da,
+	0x4736f464, 0x5ad328d8, 0xb347cc96,
+	0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc,
+	0xbfc5fe4a, 0xa70aec10, 0xac39570a,
+	0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f,
+	0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
+	0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4,
+	0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
+	0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af,
+	0x51c85f4d, 0x56907596, 0xa5bb15e6,
+	0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a,
+	0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
+	0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf,
+	0x700b45e1, 0xd5ea50f1, 0x85a92872,
+	0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198,
+	0x0cd0ede7, 0x26470db8, 0xf881814c,
+	0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db,
+	0xab838653, 0x6e2f1e23, 0x83719c9e,
+	0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c,
+	0xe1e696ff, 0xb141ab08, 0x7cca89b9,
+	0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c,
+	0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
+};
+EXPORT_SYMBOL_GPL(cast5_s1);
+const u32 cast5_s2[256] = {
+	0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a,
+	0xeec5207a, 0x55889c94, 0x72fc0651,
+	0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef,
+	0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
+	0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086,
+	0xef944459, 0xba83ccb3, 0xe0c3cdfb,
+	0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb,
+	0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
+	0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f,
+	0x77e83f4e, 0x79929269, 0x24fa9f7b,
+	0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154,
+	0x0d554b63, 0x5d681121, 0xc866c359,
+	0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181,
+	0x39f7627f, 0x361e3084, 0xe4eb573b,
+	0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c,
+	0x99847ab4, 0xa0e3df79, 0xba6cf38c,
+	0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a,
+	0x8f458c74, 0xd9e0a227, 0x4ec73a34,
+	0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c,
+	0x1d804366, 0x721d9bfd, 0xa58684bb,
+	0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1,
+	0x27e19ba5, 0xd5a6c252, 0xe49754bd,
+	0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9,
+	0xe0b56714, 0x21f043b7, 0xe5d05860,
+	0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf,
+	0x68561be6, 0x83ca6b94, 0x2d6ed23b,
+	0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c,
+	0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
+	0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122,
+	0xb96726d1, 0x8049a7e8, 0x22b7da7b,
+	0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402,
+	0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
+	0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53,
+	0xe3214517, 0xb4542835, 0x9f63293c,
+	0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6,
+	0x30a22c95, 0x31a70850, 0x60930f13,
+	0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6,
+	0xa02b1741, 0x7cbad9a2, 0x2180036f,
+	0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676,
+	0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
+	0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb,
+	0x846a3bae, 0x8ff77888, 0xee5d60f6,
+	0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54,
+	0x157fd7fa, 0xef8579cc, 0xd152de58,
+	0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5,
+	0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
+	0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8,
+	0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
+	0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc,
+	0x301e16e6, 0x273be979, 0xb0ffeaa6,
+	0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a,
+	0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
+	0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e,
+	0x1a513742, 0xef6828bc, 0x520365d6,
+	0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb,
+	0x5eea29cb, 0x145892f5, 0x91584f7f,
+	0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4,
+	0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
+	0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3,
+	0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
+	0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589,
+	0xa345415e, 0x5c038323, 0x3e5d3bb9,
+	0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539,
+	0x73bfbe70, 0x83877605, 0x4523ecf1
+};
+EXPORT_SYMBOL_GPL(cast5_s2);
+const u32 cast5_s3[256] = {
+	0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff,
+	0x369fe44b, 0x8c1fc644, 0xaececa90,
+	0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806,
+	0xf0ad0548, 0xe13c8d83, 0x927010d5,
+	0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820,
+	0xfade82e0, 0xa067268b, 0x8272792e,
+	0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee,
+	0x825b1bfd, 0x9255c5ed, 0x1257a240,
+	0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf,
+	0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
+	0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1,
+	0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
+	0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c,
+	0x4a012d6e, 0xc5884a28, 0xccc36f71,
+	0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850,
+	0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
+	0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e,
+	0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
+	0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0,
+	0x1eac5790, 0x796fb449, 0x8252dc15,
+	0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403,
+	0xe83ec305, 0x4f91751a, 0x925669c2,
+	0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574,
+	0x927985b2, 0x8276dbcb, 0x02778176,
+	0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83,
+	0x340ce5c8, 0x96bbb682, 0x93b4b148,
+	0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20,
+	0x8437aa88, 0x7d29dc96, 0x2756d3dc,
+	0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e,
+	0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
+	0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9,
+	0xbda8229c, 0x127dadaa, 0x438a074e,
+	0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff,
+	0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
+	0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a,
+	0x76a2e214, 0xb9a40368, 0x925d958f,
+	0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623,
+	0x193cbcfa, 0x27627545, 0x825cf47a,
+	0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7,
+	0x8272a972, 0x9270c4a8, 0x127de50b,
+	0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb,
+	0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
+	0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11,
+	0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
+	0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c,
+	0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
+	0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40,
+	0x7c34671c, 0x02717ef6, 0x4feb5536,
+	0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1,
+	0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
+	0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33,
+	0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
+	0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff,
+	0x856302e0, 0x72dbd92b, 0xee971b69,
+	0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2,
+	0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
+	0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38,
+	0x0ff0443d, 0x606e6dc6, 0x60543a49,
+	0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f,
+	0x68458425, 0x99833be5, 0x600d457d,
+	0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31,
+	0x9c305a00, 0x52bce688, 0x1b03588a,
+	0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636,
+	0xa133c501, 0xe9d3531c, 0xee353783
+};
+EXPORT_SYMBOL_GPL(cast5_s3);
+const u32 cast5_s4[256] = {
+	0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb,
+	0x64ad8c57, 0x85510443, 0xfa020ed1,
+	0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43,
+	0x6497b7b1, 0xf3641f63, 0x241e4adf,
+	0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30,
+	0xc0a5374f, 0x1d2d00d9, 0x24147b15,
+	0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f,
+	0x0c13fefe, 0x081b08ca, 0x05170121,
+	0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f,
+	0x06df4261, 0xbb9e9b8a, 0x7293ea25,
+	0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400,
+	0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
+	0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061,
+	0x11b638e1, 0x72500e03, 0xf80eb2bb,
+	0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400,
+	0x6920318f, 0x081dbb99, 0xffc304a5,
+	0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea,
+	0x9f926f91, 0x9f46222f, 0x3991467d,
+	0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8,
+	0x3fb6180c, 0x18f8931e, 0x281658e6,
+	0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25,
+	0x79098b02, 0xe4eabb81, 0x28123b23,
+	0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9,
+	0x0014377b, 0x041e8ac8, 0x09114003,
+	0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de,
+	0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
+	0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0,
+	0x56c8c391, 0x6b65811c, 0x5e146119,
+	0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d,
+	0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
+	0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a,
+	0xeca1d7c7, 0x041afa32, 0x1d16625a,
+	0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb,
+	0xc70b8b46, 0xd9e66a48, 0x56e55a79,
+	0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3,
+	0xedda04eb, 0x17a9be04, 0x2c18f4df,
+	0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254,
+	0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
+	0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2,
+	0x0418f2c8, 0x001a96a6, 0x0d1526ab,
+	0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86,
+	0x311170a7, 0x3e9b640c, 0xcc3e10d7,
+	0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1,
+	0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
+	0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca,
+	0xb4be31cd, 0xd8782806, 0x12a3a4e2,
+	0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5,
+	0x9711aac5, 0x001d7b95, 0x82e5e7d2,
+	0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415,
+	0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
+	0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7,
+	0x0ce454a9, 0xd60acd86, 0x015f1919,
+	0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe,
+	0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
+	0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb,
+	0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
+	0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8,
+	0x296b299e, 0x492fc295, 0x9266beab,
+	0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee,
+	0xf65324e6, 0x6afce36c, 0x0316cc04,
+	0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979,
+	0x932bcdf6, 0xb657c34d, 0x4edfd282,
+	0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0,
+	0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2
+};
+EXPORT_SYMBOL_GPL(cast5_s4);
+static const u32 s5[256] = {
+	0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff,
+	0x1dd358f5, 0x44dd9d44, 0x1731167f,
+	0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8,
+	0x386381cb, 0xacf6243a, 0x69befd7a,
+	0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640,
+	0x15b0a848, 0xe68b18cb, 0x4caadeff,
+	0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d,
+	0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
+	0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7,
+	0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
+	0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88,
+	0x8709e6b0, 0xd7e07156, 0x4e29fea7,
+	0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a,
+	0x578535f2, 0x2261be02, 0xd642a0c9,
+	0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8,
+	0xc8adedb3, 0x28a87fc9, 0x3d959981,
+	0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1,
+	0x4fb96976, 0x90c79505, 0xb0a8a774,
+	0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f,
+	0x0ec50966, 0xdfdd55bc, 0x29de0655,
+	0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980,
+	0x524755f4, 0x03b63cc9, 0x0cc844b2,
+	0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449,
+	0x64ee2d7e, 0xcddbb1da, 0x01c94910,
+	0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6,
+	0x50f5b616, 0xf24766e3, 0x8eca36c1,
+	0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9,
+	0x3063fcdf, 0xb6f589de, 0xec2941da,
+	0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401,
+	0xc1bacb7f, 0xe5ff550f, 0xb6083049,
+	0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd,
+	0x9e0885f9, 0x68cb3e47, 0x086c010f,
+	0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3,
+	0xcbb3d550, 0x1793084d, 0xb0d70eba,
+	0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56,
+	0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
+	0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280,
+	0x05687715, 0x646c6bd7, 0x44904db3,
+	0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f,
+	0x2cb6356a, 0x85808573, 0x4991f840,
+	0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8,
+	0xc1092910, 0x8bc95fc6, 0x7d869cf4,
+	0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717,
+	0x7d161bba, 0x9cad9010, 0xaf462ba2,
+	0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e,
+	0x176d486f, 0x097c13ea, 0x631da5c7,
+	0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72,
+	0x6e5dd2f3, 0x20936079, 0x459b80a5,
+	0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572,
+	0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
+	0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e,
+	0x75922283, 0x784d6b17, 0x58ebb16e,
+	0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf,
+	0xaaf47556, 0x5f46b02a, 0x2b092801,
+	0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874,
+	0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
+	0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826,
+	0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
+	0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9,
+	0x17e3fe2a, 0x24b79767, 0xf5a96b20,
+	0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a,
+	0xeeb9491d, 0x34010718, 0xbb30cab8,
+	0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8,
+	0xb1534546, 0x6d47de08, 0xefe9e7d4
+};
+static const u32 s6[256] = {
+	0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7,
+	0x016843b4, 0xeced5cbc, 0x325553ac,
+	0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8,
+	0xde5ebe39, 0xf38ff732, 0x8989b138,
+	0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99,
+	0x4e23e33c, 0x79cbd7cc, 0x48a14367,
+	0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d,
+	0x09a8486f, 0xa888614a, 0x2900af98,
+	0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932,
+	0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
+	0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c,
+	0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
+	0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01,
+	0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
+	0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c,
+	0xb88153e2, 0x08a19866, 0x1ae2eac8,
+	0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3,
+	0x9aea3906, 0xefe8c36e, 0xf890cdd9,
+	0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc,
+	0x221db3a6, 0x9a69a02f, 0x68818a54,
+	0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc,
+	0xcf222ebf, 0x25ac6f48, 0xa9a99387,
+	0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1,
+	0xe8a11be9, 0x4980740d, 0xc8087dfc,
+	0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f,
+	0x9528cd89, 0xfd339fed, 0xb87834bf,
+	0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa,
+	0x57f55ec5, 0xe2220abe, 0xd2916ebf,
+	0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff,
+	0xa8dc8af0, 0x7345c106, 0xf41e232f,
+	0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af,
+	0x692573e4, 0xe9a9d848, 0xf3160289,
+	0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063,
+	0x4576698d, 0xb6fad407, 0x592af950,
+	0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8,
+	0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
+	0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d,
+	0x48b9d585, 0xdc049441, 0xc8098f9b,
+	0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6,
+	0x890072d6, 0x28207682, 0xa9a9f7be,
+	0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a,
+	0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
+	0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a,
+	0xb6c85283, 0x3cc2acfb, 0x3fc06976,
+	0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0,
+	0x513021a5, 0x6c5b68b7, 0x822f8aa0,
+	0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9,
+	0x0c5ec241, 0x8809286c, 0xf592d891,
+	0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98,
+	0xb173ecc0, 0xbc60b42a, 0x953498da,
+	0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123,
+	0x257f0c3d, 0x9348af49, 0x361400bc,
+	0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57,
+	0xda41e7f9, 0xc25ad33a, 0x54f4a084,
+	0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5,
+	0xb6f6deaf, 0x3a479c3a, 0x5302da25,
+	0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88,
+	0x44136c76, 0x0404a8c8, 0xb8e5a121,
+	0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913,
+	0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
+	0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1,
+	0xf544edeb, 0xb0e93524, 0xbebb8fbd,
+	0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905,
+	0xa65b1db8, 0x851c97bd, 0xd675cf2f
+};
+static const u32 s7[256] = {
+	0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f,
+	0xab9bc912, 0xde6008a1, 0x2028da1f,
+	0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11,
+	0xb232e75c, 0x4b3695f2, 0xb28707de,
+	0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381,
+	0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
+	0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be,
+	0xbaeeadf4, 0x1286becf, 0xb6eacb19,
+	0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66,
+	0x28136086, 0x0bd8dfa8, 0x356d1cf2,
+	0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a,
+	0xeb12ff82, 0xe3486911, 0xd34d7516,
+	0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce,
+	0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
+	0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa,
+	0x4437f107, 0xb6e79962, 0x42d2d816,
+	0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7,
+	0xf9583745, 0xcf19df58, 0xbec3f756,
+	0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511,
+	0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
+	0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f,
+	0xaff60ff4, 0xea2c4e6d, 0x16e39264,
+	0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a,
+	0xb2856e6e, 0x1aec3ca9, 0xbe838688,
+	0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85,
+	0x61fe033c, 0x16746233, 0x3c034c28,
+	0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a,
+	0x1626a49f, 0xeed82b29, 0x1d382fe3,
+	0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c,
+	0xd45230c7, 0x2bd1408b, 0x60c03eb7,
+	0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32,
+	0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
+	0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f,
+	0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
+	0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0,
+	0x79d34217, 0x021a718d, 0x9ac6336a,
+	0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef,
+	0x4eeb8476, 0x488dcf25, 0x36c9d566,
+	0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6,
+	0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
+	0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887,
+	0x2b9f4fd5, 0x625aba82, 0x6a017962,
+	0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22,
+	0xe32dbf9a, 0x058745b9, 0x3453dc1e,
+	0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1,
+	0x19de7eae, 0x053e561a, 0x15ad6f8c,
+	0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0,
+	0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
+	0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108,
+	0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
+	0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f,
+	0x3d321c5d, 0xc3f5e194, 0x4b269301,
+	0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e,
+	0x296693f4, 0x3d1fce6f, 0xc61e45be,
+	0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d,
+	0xb5229301, 0xcfd2a87f, 0x60aeb767,
+	0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b,
+	0x589dd390, 0x5479f8e6, 0x1cb8d647,
+	0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad,
+	0x462e1b78, 0x6580f87e, 0xf3817914,
+	0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc,
+	0x3d40f021, 0xc3c0bdae, 0x4958c24c,
+	0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7,
+	0x94e01be8, 0x90716f4b, 0x954b8aa3
+};
+static const u32 sb8[256] = {
+	0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7,
+	0xe6c1121b, 0x0e241600, 0x052ce8b5,
+	0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c,
+	0x76e38111, 0xb12def3a, 0x37ddddfc,
+	0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f,
+	0xb4d137cf, 0xb44e79f0, 0x049eedfd,
+	0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831,
+	0x3f8f95e7, 0x72df191b, 0x7580330d,
+	0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a,
+	0x02e7d1ca, 0x53571dae, 0x7a3182a2,
+	0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022,
+	0xce949ad4, 0xb84769ad, 0x965bd862,
+	0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f,
+	0xc28ec4b8, 0x57e8726e, 0x647a78fc,
+	0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3,
+	0xae63aff2, 0x7e8bd632, 0x70108c0c,
+	0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53,
+	0x06918548, 0x58cb7e07, 0x3b74ef2e,
+	0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2,
+	0x19b47a38, 0x424f7618, 0x35856039,
+	0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd,
+	0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
+	0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c,
+	0x3dd00db3, 0x708f8f34, 0x77d51b42,
+	0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e,
+	0x3e378160, 0x7895cda5, 0x859c15a5,
+	0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e,
+	0x31842e7b, 0x24259fd7, 0xf8bef472,
+	0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c,
+	0xe2506d3d, 0x4f9b12ea, 0xf215f225,
+	0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187,
+	0xea7a6e98, 0x7cd16efc, 0x1436876c,
+	0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899,
+	0x92ecbae6, 0xdd67016d, 0x151682eb,
+	0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e,
+	0xe139673b, 0xefa63fb8, 0x71873054,
+	0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d,
+	0x844a1be5, 0xbae7dfdc, 0x42cbda70,
+	0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428,
+	0x79d130a4, 0x3486ebfb, 0x33d3cddc,
+	0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4,
+	0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
+	0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2,
+	0x37df932b, 0xc4248289, 0xacf3ebc3,
+	0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e,
+	0x5e410fab, 0xb48a2465, 0x2eda7fa4,
+	0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b,
+	0xdb485694, 0x38d7e5b2, 0x57720101,
+	0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282,
+	0x7523d24a, 0xe0779695, 0xf9c17a8f,
+	0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f,
+	0xad1163ed, 0xea7b5965, 0x1a00726e,
+	0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0,
+	0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
+	0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca,
+	0x8951570f, 0xdf09822b, 0xbd691a6c,
+	0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f,
+	0x0d771c2b, 0x67cdb156, 0x350d8384,
+	0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61,
+	0x8360d87b, 0x1fa98b0c, 0x1149382c,
+	0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82,
+	0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
+	0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80,
+	0xeaee6801, 0x8db2a283, 0xea8bf59e
+};
+
+#define s1 cast5_s1
+#define s2 cast5_s2
+#define s3 cast5_s3
+#define s4 cast5_s4
+
+#define F1(D, m, r)  ((I = ((m) + (D))), (I = rol32(I, (r))),   \
+	(((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff]))
+#define F2(D, m, r)  ((I = ((m) ^ (D))), (I = rol32(I, (r))),   \
+	(((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff]))
+#define F3(D, m, r)  ((I = ((m) - (D))), (I = rol32(I, (r))),   \
+	(((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]))
+
+
+void __cast5_encrypt(struct cast5_ctx *c, u8 *outbuf, const u8 *inbuf)
+{
+	const __be32 *src = (const __be32 *)inbuf;
+	__be32 *dst = (__be32 *)outbuf;
+	u32 l, r, t;
+	u32 I;			/* used by the Fx macros */
+	u32 *Km;
+	u8 *Kr;
+
+	Km = c->Km;
+	Kr = c->Kr;
+
+	/* (L0,R0) <-- (m1...m64).  (Split the plaintext into left and
+	 * right 32-bit halves L0 = m1...m32 and R0 = m33...m64.)
+	 */
+	l = be32_to_cpu(src[0]);
+	r = be32_to_cpu(src[1]);
+
+	/* (16 rounds) for i from 1 to 16, compute Li and Ri as follows:
+	 *  Li = Ri-1;
+	 *  Ri = Li-1 ^ f(Ri-1,Kmi,Kri), where f is defined in Section 2.2
+	 * Rounds 1, 4, 7, 10, 13, and 16 use f function Type 1.
+	 * Rounds 2, 5, 8, 11, and 14 use f function Type 2.
+	 * Rounds 3, 6, 9, 12, and 15 use f function Type 3.
+	 */
+
+	t = l; l = r; r = t ^ F1(r, Km[0], Kr[0]);
+	t = l; l = r; r = t ^ F2(r, Km[1], Kr[1]);
+	t = l; l = r; r = t ^ F3(r, Km[2], Kr[2]);
+	t = l; l = r; r = t ^ F1(r, Km[3], Kr[3]);
+	t = l; l = r; r = t ^ F2(r, Km[4], Kr[4]);
+	t = l; l = r; r = t ^ F3(r, Km[5], Kr[5]);
+	t = l; l = r; r = t ^ F1(r, Km[6], Kr[6]);
+	t = l; l = r; r = t ^ F2(r, Km[7], Kr[7]);
+	t = l; l = r; r = t ^ F3(r, Km[8], Kr[8]);
+	t = l; l = r; r = t ^ F1(r, Km[9], Kr[9]);
+	t = l; l = r; r = t ^ F2(r, Km[10], Kr[10]);
+	t = l; l = r; r = t ^ F3(r, Km[11], Kr[11]);
+	if (!(c->rr)) {
+		t = l; l = r; r = t ^ F1(r, Km[12], Kr[12]);
+		t = l; l = r; r = t ^ F2(r, Km[13], Kr[13]);
+		t = l; l = r; r = t ^ F3(r, Km[14], Kr[14]);
+		t = l; l = r; r = t ^ F1(r, Km[15], Kr[15]);
+	}
+
+	/* c1...c64 <-- (R16,L16).  (Exchange final blocks L16, R16 and
+	 *  concatenate to form the ciphertext.) */
+	dst[0] = cpu_to_be32(r);
+	dst[1] = cpu_to_be32(l);
+}
+EXPORT_SYMBOL_GPL(__cast5_encrypt);
+
+static void cast5_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
+{
+	__cast5_encrypt(crypto_tfm_ctx(tfm), outbuf, inbuf);
+}
+
+void __cast5_decrypt(struct cast5_ctx *c, u8 *outbuf, const u8 *inbuf)
+{
+	const __be32 *src = (const __be32 *)inbuf;
+	__be32 *dst = (__be32 *)outbuf;
+	u32 l, r, t;
+	u32 I;
+	u32 *Km;
+	u8 *Kr;
+
+	Km = c->Km;
+	Kr = c->Kr;
+
+	l = be32_to_cpu(src[0]);
+	r = be32_to_cpu(src[1]);
+
+	if (!(c->rr)) {
+		t = l; l = r; r = t ^ F1(r, Km[15], Kr[15]);
+		t = l; l = r; r = t ^ F3(r, Km[14], Kr[14]);
+		t = l; l = r; r = t ^ F2(r, Km[13], Kr[13]);
+		t = l; l = r; r = t ^ F1(r, Km[12], Kr[12]);
+	}
+	t = l; l = r; r = t ^ F3(r, Km[11], Kr[11]);
+	t = l; l = r; r = t ^ F2(r, Km[10], Kr[10]);
+	t = l; l = r; r = t ^ F1(r, Km[9], Kr[9]);
+	t = l; l = r; r = t ^ F3(r, Km[8], Kr[8]);
+	t = l; l = r; r = t ^ F2(r, Km[7], Kr[7]);
+	t = l; l = r; r = t ^ F1(r, Km[6], Kr[6]);
+	t = l; l = r; r = t ^ F3(r, Km[5], Kr[5]);
+	t = l; l = r; r = t ^ F2(r, Km[4], Kr[4]);
+	t = l; l = r; r = t ^ F1(r, Km[3], Kr[3]);
+	t = l; l = r; r = t ^ F3(r, Km[2], Kr[2]);
+	t = l; l = r; r = t ^ F2(r, Km[1], Kr[1]);
+	t = l; l = r; r = t ^ F1(r, Km[0], Kr[0]);
+
+	dst[0] = cpu_to_be32(r);
+	dst[1] = cpu_to_be32(l);
+}
+EXPORT_SYMBOL_GPL(__cast5_decrypt);
+
+static void cast5_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
+{
+	__cast5_decrypt(crypto_tfm_ctx(tfm), outbuf, inbuf);
+}
+
+static void key_schedule(u32 *x, u32 *z, u32 *k)
+{
+
+#define xi(i)   ((x[(i)/4] >> (8*(3-((i)%4)))) & 0xff)
+#define zi(i)   ((z[(i)/4] >> (8*(3-((i)%4)))) & 0xff)
+
+	z[0] = x[0] ^ s5[xi(13)] ^ s6[xi(15)] ^ s7[xi(12)] ^ sb8[xi(14)] ^
+	    s7[xi(8)];
+	z[1] = x[2] ^ s5[zi(0)] ^ s6[zi(2)] ^ s7[zi(1)] ^ sb8[zi(3)] ^
+	    sb8[xi(10)];
+	z[2] = x[3] ^ s5[zi(7)] ^ s6[zi(6)] ^ s7[zi(5)] ^ sb8[zi(4)] ^
+	    s5[xi(9)];
+	z[3] = x[1] ^ s5[zi(10)] ^ s6[zi(9)] ^ s7[zi(11)] ^ sb8[zi(8)] ^
+	    s6[xi(11)];
+	k[0] = s5[zi(8)] ^ s6[zi(9)] ^ s7[zi(7)] ^ sb8[zi(6)] ^ s5[zi(2)];
+	k[1] = s5[zi(10)] ^ s6[zi(11)] ^ s7[zi(5)] ^ sb8[zi(4)] ^
+	    s6[zi(6)];
+	k[2] = s5[zi(12)] ^ s6[zi(13)] ^ s7[zi(3)] ^ sb8[zi(2)] ^
+	    s7[zi(9)];
+	k[3] = s5[zi(14)] ^ s6[zi(15)] ^ s7[zi(1)] ^ sb8[zi(0)] ^
+	    sb8[zi(12)];
+
+	x[0] = z[2] ^ s5[zi(5)] ^ s6[zi(7)] ^ s7[zi(4)] ^ sb8[zi(6)] ^
+	    s7[zi(0)];
+	x[1] = z[0] ^ s5[xi(0)] ^ s6[xi(2)] ^ s7[xi(1)] ^ sb8[xi(3)] ^
+	    sb8[zi(2)];
+	x[2] = z[1] ^ s5[xi(7)] ^ s6[xi(6)] ^ s7[xi(5)] ^ sb8[xi(4)] ^
+	    s5[zi(1)];
+	x[3] = z[3] ^ s5[xi(10)] ^ s6[xi(9)] ^ s7[xi(11)] ^ sb8[xi(8)] ^
+	    s6[zi(3)];
+	k[4] = s5[xi(3)] ^ s6[xi(2)] ^ s7[xi(12)] ^ sb8[xi(13)] ^
+	    s5[xi(8)];
+	k[5] = s5[xi(1)] ^ s6[xi(0)] ^ s7[xi(14)] ^ sb8[xi(15)] ^
+	    s6[xi(13)];
+	k[6] = s5[xi(7)] ^ s6[xi(6)] ^ s7[xi(8)] ^ sb8[xi(9)] ^ s7[xi(3)];
+	k[7] = s5[xi(5)] ^ s6[xi(4)] ^ s7[xi(10)] ^ sb8[xi(11)] ^
+	    sb8[xi(7)];
+
+	z[0] = x[0] ^ s5[xi(13)] ^ s6[xi(15)] ^ s7[xi(12)] ^ sb8[xi(14)] ^
+	    s7[xi(8)];
+	z[1] = x[2] ^ s5[zi(0)] ^ s6[zi(2)] ^ s7[zi(1)] ^ sb8[zi(3)] ^
+	    sb8[xi(10)];
+	z[2] = x[3] ^ s5[zi(7)] ^ s6[zi(6)] ^ s7[zi(5)] ^ sb8[zi(4)] ^
+	    s5[xi(9)];
+	z[3] = x[1] ^ s5[zi(10)] ^ s6[zi(9)] ^ s7[zi(11)] ^ sb8[zi(8)] ^
+	    s6[xi(11)];
+	k[8] = s5[zi(3)] ^ s6[zi(2)] ^ s7[zi(12)] ^ sb8[zi(13)] ^
+	    s5[zi(9)];
+	k[9] = s5[zi(1)] ^ s6[zi(0)] ^ s7[zi(14)] ^ sb8[zi(15)] ^
+	    s6[zi(12)];
+	k[10] = s5[zi(7)] ^ s6[zi(6)] ^ s7[zi(8)] ^ sb8[zi(9)] ^ s7[zi(2)];
+	k[11] = s5[zi(5)] ^ s6[zi(4)] ^ s7[zi(10)] ^ sb8[zi(11)] ^
+	    sb8[zi(6)];
+
+	x[0] = z[2] ^ s5[zi(5)] ^ s6[zi(7)] ^ s7[zi(4)] ^ sb8[zi(6)] ^
+	    s7[zi(0)];
+	x[1] = z[0] ^ s5[xi(0)] ^ s6[xi(2)] ^ s7[xi(1)] ^ sb8[xi(3)] ^
+	    sb8[zi(2)];
+	x[2] = z[1] ^ s5[xi(7)] ^ s6[xi(6)] ^ s7[xi(5)] ^ sb8[xi(4)] ^
+	    s5[zi(1)];
+	x[3] = z[3] ^ s5[xi(10)] ^ s6[xi(9)] ^ s7[xi(11)] ^ sb8[xi(8)] ^
+	    s6[zi(3)];
+	k[12] = s5[xi(8)] ^ s6[xi(9)] ^ s7[xi(7)] ^ sb8[xi(6)] ^ s5[xi(3)];
+	k[13] = s5[xi(10)] ^ s6[xi(11)] ^ s7[xi(5)] ^ sb8[xi(4)] ^
+	    s6[xi(7)];
+	k[14] = s5[xi(12)] ^ s6[xi(13)] ^ s7[xi(3)] ^ sb8[xi(2)] ^
+	    s7[xi(8)];
+	k[15] = s5[xi(14)] ^ s6[xi(15)] ^ s7[xi(1)] ^ sb8[xi(0)] ^
+	    sb8[xi(13)];
+
+#undef xi
+#undef zi
+}
+
+
+int cast5_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len)
+{
+	struct cast5_ctx *c = crypto_tfm_ctx(tfm);
+	int i;
+	u32 x[4];
+	u32 z[4];
+	u32 k[16];
+	__be32 p_key[4];
+
+	c->rr = key_len <= 10 ? 1 : 0;
+
+	memset(p_key, 0, 16);
+	memcpy(p_key, key, key_len);
+
+
+	x[0] = be32_to_cpu(p_key[0]);
+	x[1] = be32_to_cpu(p_key[1]);
+	x[2] = be32_to_cpu(p_key[2]);
+	x[3] = be32_to_cpu(p_key[3]);
+
+	key_schedule(x, z, k);
+	for (i = 0; i < 16; i++)
+		c->Km[i] = k[i];
+	key_schedule(x, z, k);
+	for (i = 0; i < 16; i++)
+		c->Kr[i] = k[i] & 0x1f;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cast5_setkey);
+
+static struct crypto_alg alg = {
+	.cra_name		= "cast5",
+	.cra_driver_name	= "cast5-generic",
+	.cra_priority		= 100,
+	.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		= CAST5_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct cast5_ctx),
+	.cra_alignmask		= 3,
+	.cra_module		= THIS_MODULE,
+	.cra_u			= {
+		.cipher = {
+			.cia_min_keysize = CAST5_MIN_KEY_SIZE,
+			.cia_max_keysize = CAST5_MAX_KEY_SIZE,
+			.cia_setkey  = cast5_setkey,
+			.cia_encrypt = cast5_encrypt,
+			.cia_decrypt = cast5_decrypt
+		}
+	}
+};
+
+static int __init cast5_mod_init(void)
+{
+	return crypto_register_alg(&alg);
+}
+
+static void __exit cast5_mod_fini(void)
+{
+	crypto_unregister_alg(&alg);
+}
+
+module_init(cast5_mod_init);
+module_exit(cast5_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cast5 Cipher Algorithm");
+MODULE_ALIAS("cast5");
diff --git a/crypto/cast6.c b/crypto/cast6.c
deleted file mode 100644
index e0c15a6..0000000
--- a/crypto/cast6.c
+++ /dev/null
@@ -1,547 +0,0 @@
-/* Kernel cryptographic api.
- * cast6.c - Cast6 cipher algorithm [rfc2612].
- *
- * CAST-256 (*cast6*) is a DES like Substitution-Permutation Network (SPN)
- * cryptosystem built upon the CAST-128 (*cast5*) [rfc2144] encryption
- * algorithm.
- *
- * Copyright (C) 2003 Kartikey Mahendra Bhatt <kartik_me@hotmail.com>.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-
-#include <asm/byteorder.h>
-#include <linux/init.h>
-#include <linux/crypto.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-
-#define CAST6_BLOCK_SIZE 16
-#define CAST6_MIN_KEY_SIZE 16
-#define CAST6_MAX_KEY_SIZE 32
-
-struct cast6_ctx {
-	u32 Km[12][4];
-	u8 Kr[12][4];
-};
-
-#define F1(D, r, m)  ((I = ((m) + (D))), (I = rol32(I, (r))),   \
-    (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff]))
-#define F2(D, r, m)  ((I = ((m) ^ (D))), (I = rol32(I, (r))),   \
-    (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff]))
-#define F3(D, r, m)  ((I = ((m) - (D))), (I = rol32(I, (r))),   \
-    (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]))
-
-static const u32 s1[256] = {
-	0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f,
-	0x9c004dd3, 0x6003e540, 0xcf9fc949,
-	0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0,
-	0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
-	0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3,
-	0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
-	0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1,
-	0xaa54166b, 0x22568e3a, 0xa2d341d0,
-	0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac,
-	0x4a97c1d8, 0x527644b7, 0xb5f437a7,
-	0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0,
-	0x90ecf52e, 0x22b0c054, 0xbc8e5935,
-	0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290,
-	0xe93b159f, 0xb48ee411, 0x4bff345d,
-	0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad,
-	0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
-	0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f,
-	0xc59c5319, 0xb949e354, 0xb04669fe,
-	0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5,
-	0x6a390493, 0xe63d37e0, 0x2a54f6b3,
-	0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5,
-	0xf61b1891, 0xbb72275e, 0xaa508167,
-	0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427,
-	0xa2d1936b, 0x2ad286af, 0xaa56d291,
-	0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d,
-	0x73e2bb14, 0xa0bebc3c, 0x54623779,
-	0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e,
-	0x89fe78e6, 0x3fab0950, 0x325ff6c2,
-	0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf,
-	0x380782d5, 0xc7fa5cf6, 0x8ac31511,
-	0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241,
-	0x051ef495, 0xaa573b04, 0x4a805d8d,
-	0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b,
-	0x50afd341, 0xa7c13275, 0x915a0bf5,
-	0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265,
-	0xab85c5f3, 0x1b55db94, 0xaad4e324,
-	0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3,
-	0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
-	0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6,
-	0x22513f1e, 0xaa51a79b, 0x2ad344cc,
-	0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6,
-	0x032268d4, 0xc9600acc, 0xce387e6d,
-	0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da,
-	0x4736f464, 0x5ad328d8, 0xb347cc96,
-	0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc,
-	0xbfc5fe4a, 0xa70aec10, 0xac39570a,
-	0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f,
-	0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
-	0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4,
-	0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
-	0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af,
-	0x51c85f4d, 0x56907596, 0xa5bb15e6,
-	0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a,
-	0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
-	0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf,
-	0x700b45e1, 0xd5ea50f1, 0x85a92872,
-	0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198,
-	0x0cd0ede7, 0x26470db8, 0xf881814c,
-	0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db,
-	0xab838653, 0x6e2f1e23, 0x83719c9e,
-	0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c,
-	0xe1e696ff, 0xb141ab08, 0x7cca89b9,
-	0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c,
-	0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
-};
-
-static const u32 s2[256] = {
-	0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a,
-	0xeec5207a, 0x55889c94, 0x72fc0651,
-	0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef,
-	0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
-	0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086,
-	0xef944459, 0xba83ccb3, 0xe0c3cdfb,
-	0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb,
-	0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
-	0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f,
-	0x77e83f4e, 0x79929269, 0x24fa9f7b,
-	0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154,
-	0x0d554b63, 0x5d681121, 0xc866c359,
-	0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181,
-	0x39f7627f, 0x361e3084, 0xe4eb573b,
-	0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c,
-	0x99847ab4, 0xa0e3df79, 0xba6cf38c,
-	0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a,
-	0x8f458c74, 0xd9e0a227, 0x4ec73a34,
-	0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c,
-	0x1d804366, 0x721d9bfd, 0xa58684bb,
-	0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1,
-	0x27e19ba5, 0xd5a6c252, 0xe49754bd,
-	0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9,
-	0xe0b56714, 0x21f043b7, 0xe5d05860,
-	0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf,
-	0x68561be6, 0x83ca6b94, 0x2d6ed23b,
-	0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c,
-	0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
-	0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122,
-	0xb96726d1, 0x8049a7e8, 0x22b7da7b,
-	0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402,
-	0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
-	0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53,
-	0xe3214517, 0xb4542835, 0x9f63293c,
-	0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6,
-	0x30a22c95, 0x31a70850, 0x60930f13,
-	0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6,
-	0xa02b1741, 0x7cbad9a2, 0x2180036f,
-	0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676,
-	0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
-	0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb,
-	0x846a3bae, 0x8ff77888, 0xee5d60f6,
-	0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54,
-	0x157fd7fa, 0xef8579cc, 0xd152de58,
-	0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5,
-	0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
-	0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8,
-	0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
-	0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc,
-	0x301e16e6, 0x273be979, 0xb0ffeaa6,
-	0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a,
-	0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
-	0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e,
-	0x1a513742, 0xef6828bc, 0x520365d6,
-	0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb,
-	0x5eea29cb, 0x145892f5, 0x91584f7f,
-	0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4,
-	0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
-	0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3,
-	0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
-	0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589,
-	0xa345415e, 0x5c038323, 0x3e5d3bb9,
-	0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539,
-	0x73bfbe70, 0x83877605, 0x4523ecf1
-};
-
-static const u32 s3[256] = {
-	0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff,
-	0x369fe44b, 0x8c1fc644, 0xaececa90,
-	0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806,
-	0xf0ad0548, 0xe13c8d83, 0x927010d5,
-	0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820,
-	0xfade82e0, 0xa067268b, 0x8272792e,
-	0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee,
-	0x825b1bfd, 0x9255c5ed, 0x1257a240,
-	0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf,
-	0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
-	0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1,
-	0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
-	0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c,
-	0x4a012d6e, 0xc5884a28, 0xccc36f71,
-	0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850,
-	0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
-	0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e,
-	0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
-	0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0,
-	0x1eac5790, 0x796fb449, 0x8252dc15,
-	0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403,
-	0xe83ec305, 0x4f91751a, 0x925669c2,
-	0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574,
-	0x927985b2, 0x8276dbcb, 0x02778176,
-	0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83,
-	0x340ce5c8, 0x96bbb682, 0x93b4b148,
-	0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20,
-	0x8437aa88, 0x7d29dc96, 0x2756d3dc,
-	0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e,
-	0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
-	0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9,
-	0xbda8229c, 0x127dadaa, 0x438a074e,
-	0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff,
-	0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
-	0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a,
-	0x76a2e214, 0xb9a40368, 0x925d958f,
-	0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623,
-	0x193cbcfa, 0x27627545, 0x825cf47a,
-	0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7,
-	0x8272a972, 0x9270c4a8, 0x127de50b,
-	0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb,
-	0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
-	0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11,
-	0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
-	0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c,
-	0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
-	0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40,
-	0x7c34671c, 0x02717ef6, 0x4feb5536,
-	0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1,
-	0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
-	0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33,
-	0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
-	0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff,
-	0x856302e0, 0x72dbd92b, 0xee971b69,
-	0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2,
-	0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
-	0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38,
-	0x0ff0443d, 0x606e6dc6, 0x60543a49,
-	0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f,
-	0x68458425, 0x99833be5, 0x600d457d,
-	0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31,
-	0x9c305a00, 0x52bce688, 0x1b03588a,
-	0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636,
-	0xa133c501, 0xe9d3531c, 0xee353783
-};
-
-static const u32 s4[256] = {
-	0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb,
-	0x64ad8c57, 0x85510443, 0xfa020ed1,
-	0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43,
-	0x6497b7b1, 0xf3641f63, 0x241e4adf,
-	0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30,
-	0xc0a5374f, 0x1d2d00d9, 0x24147b15,
-	0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f,
-	0x0c13fefe, 0x081b08ca, 0x05170121,
-	0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f,
-	0x06df4261, 0xbb9e9b8a, 0x7293ea25,
-	0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400,
-	0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
-	0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061,
-	0x11b638e1, 0x72500e03, 0xf80eb2bb,
-	0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400,
-	0x6920318f, 0x081dbb99, 0xffc304a5,
-	0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea,
-	0x9f926f91, 0x9f46222f, 0x3991467d,
-	0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8,
-	0x3fb6180c, 0x18f8931e, 0x281658e6,
-	0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25,
-	0x79098b02, 0xe4eabb81, 0x28123b23,
-	0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9,
-	0x0014377b, 0x041e8ac8, 0x09114003,
-	0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de,
-	0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
-	0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0,
-	0x56c8c391, 0x6b65811c, 0x5e146119,
-	0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d,
-	0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
-	0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a,
-	0xeca1d7c7, 0x041afa32, 0x1d16625a,
-	0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb,
-	0xc70b8b46, 0xd9e66a48, 0x56e55a79,
-	0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3,
-	0xedda04eb, 0x17a9be04, 0x2c18f4df,
-	0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254,
-	0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
-	0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2,
-	0x0418f2c8, 0x001a96a6, 0x0d1526ab,
-	0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86,
-	0x311170a7, 0x3e9b640c, 0xcc3e10d7,
-	0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1,
-	0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
-	0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca,
-	0xb4be31cd, 0xd8782806, 0x12a3a4e2,
-	0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5,
-	0x9711aac5, 0x001d7b95, 0x82e5e7d2,
-	0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415,
-	0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
-	0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7,
-	0x0ce454a9, 0xd60acd86, 0x015f1919,
-	0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe,
-	0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
-	0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb,
-	0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
-	0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8,
-	0x296b299e, 0x492fc295, 0x9266beab,
-	0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee,
-	0xf65324e6, 0x6afce36c, 0x0316cc04,
-	0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979,
-	0x932bcdf6, 0xb657c34d, 0x4edfd282,
-	0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0,
-	0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2
-};
-
-static const u32 Tm[24][8] = {
-	{ 0x5a827999, 0xc95c653a, 0x383650db, 0xa7103c7c, 0x15ea281d,
-		0x84c413be, 0xf39dff5f, 0x6277eb00 } ,
-	{ 0xd151d6a1, 0x402bc242, 0xaf05ade3, 0x1ddf9984, 0x8cb98525,
-		0xfb9370c6, 0x6a6d5c67, 0xd9474808 } ,
-	{ 0x482133a9, 0xb6fb1f4a, 0x25d50aeb, 0x94aef68c, 0x0388e22d,
-		0x7262cdce, 0xe13cb96f, 0x5016a510 } ,
-	{ 0xbef090b1, 0x2dca7c52, 0x9ca467f3, 0x0b7e5394, 0x7a583f35,
-		0xe9322ad6, 0x580c1677, 0xc6e60218 } ,
-	{ 0x35bfedb9, 0xa499d95a, 0x1373c4fb, 0x824db09c, 0xf1279c3d,
-		0x600187de, 0xcedb737f, 0x3db55f20 } ,
-	{ 0xac8f4ac1, 0x1b693662, 0x8a432203, 0xf91d0da4, 0x67f6f945,
-		0xd6d0e4e6, 0x45aad087, 0xb484bc28 } ,
-	{ 0x235ea7c9, 0x9238936a, 0x01127f0b, 0x6fec6aac, 0xdec6564d,
-		0x4da041ee, 0xbc7a2d8f, 0x2b541930 } ,
-	{ 0x9a2e04d1, 0x0907f072, 0x77e1dc13, 0xe6bbc7b4, 0x5595b355,
-		0xc46f9ef6, 0x33498a97, 0xa2237638 } ,
-	{ 0x10fd61d9, 0x7fd74d7a, 0xeeb1391b, 0x5d8b24bc, 0xcc65105d,
-		0x3b3efbfe, 0xaa18e79f, 0x18f2d340 } ,
-	{ 0x87ccbee1, 0xf6a6aa82, 0x65809623, 0xd45a81c4, 0x43346d65,
-		0xb20e5906, 0x20e844a7, 0x8fc23048 } ,
-	{ 0xfe9c1be9, 0x6d76078a, 0xdc4ff32b, 0x4b29decc, 0xba03ca6d,
-		0x28ddb60e, 0x97b7a1af, 0x06918d50 } ,
-	{ 0x756b78f1, 0xe4456492, 0x531f5033, 0xc1f93bd4, 0x30d32775,
-		0x9fad1316, 0x0e86feb7, 0x7d60ea58 } ,
-	{ 0xec3ad5f9, 0x5b14c19a, 0xc9eead3b, 0x38c898dc, 0xa7a2847d,
-		0x167c701e, 0x85565bbf, 0xf4304760 } ,
-	{ 0x630a3301, 0xd1e41ea2, 0x40be0a43, 0xaf97f5e4, 0x1e71e185,
-		0x8d4bcd26, 0xfc25b8c7, 0x6affa468 } ,
-	{ 0xd9d99009, 0x48b37baa, 0xb78d674b, 0x266752ec, 0x95413e8d,
-		0x041b2a2e, 0x72f515cf, 0xe1cf0170 } ,
-	{ 0x50a8ed11, 0xbf82d8b2, 0x2e5cc453, 0x9d36aff4, 0x0c109b95,
-		0x7aea8736, 0xe9c472d7, 0x589e5e78 } ,
-	{ 0xc7784a19, 0x365235ba, 0xa52c215b, 0x14060cfc, 0x82dff89d,
-		0xf1b9e43e, 0x6093cfdf, 0xcf6dbb80 } ,
-	{ 0x3e47a721, 0xad2192c2, 0x1bfb7e63, 0x8ad56a04, 0xf9af55a5,
-		0x68894146, 0xd7632ce7, 0x463d1888 } ,
-	{ 0xb5170429, 0x23f0efca, 0x92cadb6b, 0x01a4c70c, 0x707eb2ad,
-		0xdf589e4e, 0x4e3289ef, 0xbd0c7590 } ,
-	{ 0x2be66131, 0x9ac04cd2, 0x099a3873, 0x78742414, 0xe74e0fb5,
-		0x5627fb56, 0xc501e6f7, 0x33dbd298 } ,
-	{ 0xa2b5be39, 0x118fa9da, 0x8069957b, 0xef43811c, 0x5e1d6cbd,
-		0xccf7585e, 0x3bd143ff, 0xaaab2fa0 } ,
-	{ 0x19851b41, 0x885f06e2, 0xf738f283, 0x6612de24, 0xd4ecc9c5,
-		0x43c6b566, 0xb2a0a107, 0x217a8ca8 } ,
-	{ 0x90547849, 0xff2e63ea, 0x6e084f8b, 0xdce23b2c, 0x4bbc26cd,
-		0xba96126e, 0x296ffe0f, 0x9849e9b0 } ,
-	{ 0x0723d551, 0x75fdc0f2, 0xe4d7ac93, 0x53b19834, 0xc28b83d5,
-		0x31656f76, 0xa03f5b17, 0x0f1946b8 }
-};
-
-static const u8 Tr[4][8] = {
-	{ 0x13, 0x04, 0x15, 0x06, 0x17, 0x08, 0x19, 0x0a } ,
-	{ 0x1b, 0x0c, 0x1d, 0x0e, 0x1f, 0x10, 0x01, 0x12 } ,
-	{ 0x03, 0x14, 0x05, 0x16, 0x07, 0x18, 0x09, 0x1a } ,
-	{ 0x0b, 0x1c, 0x0d, 0x1e, 0x0f, 0x00, 0x11, 0x02 }
-};
-
-/* forward octave */
-static void W(u32 *key, unsigned int i)
-{
-	u32 I;
-	key[6] ^= F1(key[7], Tr[i % 4][0], Tm[i][0]);
-	key[5] ^= F2(key[6], Tr[i % 4][1], Tm[i][1]);
-	key[4] ^= F3(key[5], Tr[i % 4][2], Tm[i][2]);
-	key[3] ^= F1(key[4], Tr[i % 4][3], Tm[i][3]);
-	key[2] ^= F2(key[3], Tr[i % 4][4], Tm[i][4]);
-	key[1] ^= F3(key[2], Tr[i % 4][5], Tm[i][5]);
-	key[0] ^= F1(key[1], Tr[i % 4][6], Tm[i][6]);
-	key[7] ^= F2(key[0], Tr[i % 4][7], Tm[i][7]);
-}
-
-static int cast6_setkey(struct crypto_tfm *tfm, const u8 *in_key,
-			unsigned key_len)
-{
-	int i;
-	u32 key[8];
-	__be32 p_key[8]; /* padded key */
-	struct cast6_ctx *c = crypto_tfm_ctx(tfm);
-	u32 *flags = &tfm->crt_flags;
-
-	if (key_len % 4 != 0) {
-		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
-		return -EINVAL;
-	}
-
-	memset(p_key, 0, 32);
-	memcpy(p_key, in_key, key_len);
-
-	key[0] = be32_to_cpu(p_key[0]);		/* A */
-	key[1] = be32_to_cpu(p_key[1]);		/* B */
-	key[2] = be32_to_cpu(p_key[2]);		/* C */
-	key[3] = be32_to_cpu(p_key[3]);		/* D */
-	key[4] = be32_to_cpu(p_key[4]);		/* E */
-	key[5] = be32_to_cpu(p_key[5]);		/* F */
-	key[6] = be32_to_cpu(p_key[6]);		/* G */
-	key[7] = be32_to_cpu(p_key[7]);		/* H */
-
-	for (i = 0; i < 12; i++) {
-		W(key, 2 * i);
-		W(key, 2 * i + 1);
-
-		c->Kr[i][0] = key[0] & 0x1f;
-		c->Kr[i][1] = key[2] & 0x1f;
-		c->Kr[i][2] = key[4] & 0x1f;
-		c->Kr[i][3] = key[6] & 0x1f;
-
-		c->Km[i][0] = key[7];
-		c->Km[i][1] = key[5];
-		c->Km[i][2] = key[3];
-		c->Km[i][3] = key[1];
-	}
-
-	return 0;
-}
-
-/*forward quad round*/
-static void Q(u32 *block, u8 *Kr, u32 *Km)
-{
-	u32 I;
-	block[2] ^= F1(block[3], Kr[0], Km[0]);
-	block[1] ^= F2(block[2], Kr[1], Km[1]);
-	block[0] ^= F3(block[1], Kr[2], Km[2]);
-	block[3] ^= F1(block[0], Kr[3], Km[3]);
-}
-
-/*reverse quad round*/
-static void QBAR(u32 *block, u8 *Kr, u32 *Km)
-{
-	u32 I;
-	block[3] ^= F1(block[0], Kr[3], Km[3]);
-	block[0] ^= F3(block[1], Kr[2], Km[2]);
-	block[1] ^= F2(block[2], Kr[1], Km[1]);
-	block[2] ^= F1(block[3], Kr[0], Km[0]);
-}
-
-static void cast6_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
-{
-	struct cast6_ctx *c = crypto_tfm_ctx(tfm);
-	const __be32 *src = (const __be32 *)inbuf;
-	__be32 *dst = (__be32 *)outbuf;
-	u32 block[4];
-	u32 *Km;
-	u8 *Kr;
-
-	block[0] = be32_to_cpu(src[0]);
-	block[1] = be32_to_cpu(src[1]);
-	block[2] = be32_to_cpu(src[2]);
-	block[3] = be32_to_cpu(src[3]);
-
-	Km = c->Km[0]; Kr = c->Kr[0]; Q(block, Kr, Km);
-	Km = c->Km[1]; Kr = c->Kr[1]; Q(block, Kr, Km);
-	Km = c->Km[2]; Kr = c->Kr[2]; Q(block, Kr, Km);
-	Km = c->Km[3]; Kr = c->Kr[3]; Q(block, Kr, Km);
-	Km = c->Km[4]; Kr = c->Kr[4]; Q(block, Kr, Km);
-	Km = c->Km[5]; Kr = c->Kr[5]; Q(block, Kr, Km);
-	Km = c->Km[6]; Kr = c->Kr[6]; QBAR(block, Kr, Km);
-	Km = c->Km[7]; Kr = c->Kr[7]; QBAR(block, Kr, Km);
-	Km = c->Km[8]; Kr = c->Kr[8]; QBAR(block, Kr, Km);
-	Km = c->Km[9]; Kr = c->Kr[9]; QBAR(block, Kr, Km);
-	Km = c->Km[10]; Kr = c->Kr[10]; QBAR(block, Kr, Km);
-	Km = c->Km[11]; Kr = c->Kr[11]; QBAR(block, Kr, Km);
-
-	dst[0] = cpu_to_be32(block[0]);
-	dst[1] = cpu_to_be32(block[1]);
-	dst[2] = cpu_to_be32(block[2]);
-	dst[3] = cpu_to_be32(block[3]);
-}
-
-static void cast6_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
-{
-	struct cast6_ctx *c = crypto_tfm_ctx(tfm);
-	const __be32 *src = (const __be32 *)inbuf;
-	__be32 *dst = (__be32 *)outbuf;
-	u32 block[4];
-	u32 *Km;
-	u8 *Kr;
-
-	block[0] = be32_to_cpu(src[0]);
-	block[1] = be32_to_cpu(src[1]);
-	block[2] = be32_to_cpu(src[2]);
-	block[3] = be32_to_cpu(src[3]);
-
-	Km = c->Km[11]; Kr = c->Kr[11]; Q(block, Kr, Km);
-	Km = c->Km[10]; Kr = c->Kr[10]; Q(block, Kr, Km);
-	Km = c->Km[9]; Kr = c->Kr[9]; Q(block, Kr, Km);
-	Km = c->Km[8]; Kr = c->Kr[8]; Q(block, Kr, Km);
-	Km = c->Km[7]; Kr = c->Kr[7]; Q(block, Kr, Km);
-	Km = c->Km[6]; Kr = c->Kr[6]; Q(block, Kr, Km);
-	Km = c->Km[5]; Kr = c->Kr[5]; QBAR(block, Kr, Km);
-	Km = c->Km[4]; Kr = c->Kr[4]; QBAR(block, Kr, Km);
-	Km = c->Km[3]; Kr = c->Kr[3]; QBAR(block, Kr, Km);
-	Km = c->Km[2]; Kr = c->Kr[2]; QBAR(block, Kr, Km);
-	Km = c->Km[1]; Kr = c->Kr[1]; QBAR(block, Kr, Km);
-	Km = c->Km[0]; Kr = c->Kr[0]; QBAR(block, Kr, Km);
-
-	dst[0] = cpu_to_be32(block[0]);
-	dst[1] = cpu_to_be32(block[1]);
-	dst[2] = cpu_to_be32(block[2]);
-	dst[3] = cpu_to_be32(block[3]);
-}
-
-static struct crypto_alg alg = {
-	.cra_name = "cast6",
-	.cra_flags = CRYPTO_ALG_TYPE_CIPHER,
-	.cra_blocksize = CAST6_BLOCK_SIZE,
-	.cra_ctxsize = sizeof(struct cast6_ctx),
-	.cra_alignmask = 3,
-	.cra_module = THIS_MODULE,
-	.cra_list = LIST_HEAD_INIT(alg.cra_list),
-	.cra_u = {
-		  .cipher = {
-			     .cia_min_keysize = CAST6_MIN_KEY_SIZE,
-			     .cia_max_keysize = CAST6_MAX_KEY_SIZE,
-			     .cia_setkey = cast6_setkey,
-			     .cia_encrypt = cast6_encrypt,
-			     .cia_decrypt = cast6_decrypt}
-		  }
-};
-
-static int __init cast6_mod_init(void)
-{
-	return crypto_register_alg(&alg);
-}
-
-static void __exit cast6_mod_fini(void)
-{
-	crypto_unregister_alg(&alg);
-}
-
-module_init(cast6_mod_init);
-module_exit(cast6_mod_fini);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Cast6 Cipher Algorithm");
diff --git a/crypto/cast6_generic.c b/crypto/cast6_generic.c
new file mode 100644
index 0000000..dc9309d
--- /dev/null
+++ b/crypto/cast6_generic.c
@@ -0,0 +1,566 @@
+/* Kernel cryptographic api.
+ * cast6.c - Cast6 cipher algorithm [rfc2612].
+ *
+ * CAST-256 (*cast6*) is a DES like Substitution-Permutation Network (SPN)
+ * cryptosystem built upon the CAST-128 (*cast5*) [rfc2144] encryption
+ * algorithm.
+ *
+ * Copyright (C) 2003 Kartikey Mahendra Bhatt <kartik_me@hotmail.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#include <asm/byteorder.h>
+#include <linux/init.h>
+#include <linux/crypto.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <crypto/cast6.h>
+
+#define s1 cast6_s1
+#define s2 cast6_s2
+#define s3 cast6_s3
+#define s4 cast6_s4
+
+#define F1(D, r, m)  ((I = ((m) + (D))), (I = rol32(I, (r))),   \
+	(((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff]))
+#define F2(D, r, m)  ((I = ((m) ^ (D))), (I = rol32(I, (r))),   \
+	(((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff]))
+#define F3(D, r, m)  ((I = ((m) - (D))), (I = rol32(I, (r))),   \
+	(((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]))
+
+const u32 cast6_s1[256] = {
+	0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f,
+	0x9c004dd3, 0x6003e540, 0xcf9fc949,
+	0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0,
+	0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
+	0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3,
+	0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
+	0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1,
+	0xaa54166b, 0x22568e3a, 0xa2d341d0,
+	0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac,
+	0x4a97c1d8, 0x527644b7, 0xb5f437a7,
+	0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0,
+	0x90ecf52e, 0x22b0c054, 0xbc8e5935,
+	0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290,
+	0xe93b159f, 0xb48ee411, 0x4bff345d,
+	0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad,
+	0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
+	0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f,
+	0xc59c5319, 0xb949e354, 0xb04669fe,
+	0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5,
+	0x6a390493, 0xe63d37e0, 0x2a54f6b3,
+	0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5,
+	0xf61b1891, 0xbb72275e, 0xaa508167,
+	0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427,
+	0xa2d1936b, 0x2ad286af, 0xaa56d291,
+	0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d,
+	0x73e2bb14, 0xa0bebc3c, 0x54623779,
+	0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e,
+	0x89fe78e6, 0x3fab0950, 0x325ff6c2,
+	0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf,
+	0x380782d5, 0xc7fa5cf6, 0x8ac31511,
+	0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241,
+	0x051ef495, 0xaa573b04, 0x4a805d8d,
+	0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b,
+	0x50afd341, 0xa7c13275, 0x915a0bf5,
+	0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265,
+	0xab85c5f3, 0x1b55db94, 0xaad4e324,
+	0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3,
+	0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
+	0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6,
+	0x22513f1e, 0xaa51a79b, 0x2ad344cc,
+	0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6,
+	0x032268d4, 0xc9600acc, 0xce387e6d,
+	0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da,
+	0x4736f464, 0x5ad328d8, 0xb347cc96,
+	0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc,
+	0xbfc5fe4a, 0xa70aec10, 0xac39570a,
+	0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f,
+	0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
+	0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4,
+	0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
+	0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af,
+	0x51c85f4d, 0x56907596, 0xa5bb15e6,
+	0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a,
+	0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
+	0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf,
+	0x700b45e1, 0xd5ea50f1, 0x85a92872,
+	0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198,
+	0x0cd0ede7, 0x26470db8, 0xf881814c,
+	0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db,
+	0xab838653, 0x6e2f1e23, 0x83719c9e,
+	0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c,
+	0xe1e696ff, 0xb141ab08, 0x7cca89b9,
+	0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c,
+	0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
+};
+EXPORT_SYMBOL_GPL(cast6_s1);
+
+const u32 cast6_s2[256] = {
+	0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a,
+	0xeec5207a, 0x55889c94, 0x72fc0651,
+	0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef,
+	0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
+	0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086,
+	0xef944459, 0xba83ccb3, 0xe0c3cdfb,
+	0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb,
+	0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
+	0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f,
+	0x77e83f4e, 0x79929269, 0x24fa9f7b,
+	0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154,
+	0x0d554b63, 0x5d681121, 0xc866c359,
+	0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181,
+	0x39f7627f, 0x361e3084, 0xe4eb573b,
+	0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c,
+	0x99847ab4, 0xa0e3df79, 0xba6cf38c,
+	0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a,
+	0x8f458c74, 0xd9e0a227, 0x4ec73a34,
+	0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c,
+	0x1d804366, 0x721d9bfd, 0xa58684bb,
+	0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1,
+	0x27e19ba5, 0xd5a6c252, 0xe49754bd,
+	0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9,
+	0xe0b56714, 0x21f043b7, 0xe5d05860,
+	0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf,
+	0x68561be6, 0x83ca6b94, 0x2d6ed23b,
+	0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c,
+	0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
+	0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122,
+	0xb96726d1, 0x8049a7e8, 0x22b7da7b,
+	0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402,
+	0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
+	0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53,
+	0xe3214517, 0xb4542835, 0x9f63293c,
+	0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6,
+	0x30a22c95, 0x31a70850, 0x60930f13,
+	0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6,
+	0xa02b1741, 0x7cbad9a2, 0x2180036f,
+	0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676,
+	0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
+	0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb,
+	0x846a3bae, 0x8ff77888, 0xee5d60f6,
+	0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54,
+	0x157fd7fa, 0xef8579cc, 0xd152de58,
+	0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5,
+	0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
+	0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8,
+	0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
+	0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc,
+	0x301e16e6, 0x273be979, 0xb0ffeaa6,
+	0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a,
+	0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
+	0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e,
+	0x1a513742, 0xef6828bc, 0x520365d6,
+	0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb,
+	0x5eea29cb, 0x145892f5, 0x91584f7f,
+	0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4,
+	0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
+	0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3,
+	0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
+	0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589,
+	0xa345415e, 0x5c038323, 0x3e5d3bb9,
+	0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539,
+	0x73bfbe70, 0x83877605, 0x4523ecf1
+};
+EXPORT_SYMBOL_GPL(cast6_s2);
+
+const u32 cast6_s3[256] = {
+	0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff,
+	0x369fe44b, 0x8c1fc644, 0xaececa90,
+	0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806,
+	0xf0ad0548, 0xe13c8d83, 0x927010d5,
+	0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820,
+	0xfade82e0, 0xa067268b, 0x8272792e,
+	0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee,
+	0x825b1bfd, 0x9255c5ed, 0x1257a240,
+	0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf,
+	0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
+	0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1,
+	0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
+	0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c,
+	0x4a012d6e, 0xc5884a28, 0xccc36f71,
+	0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850,
+	0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
+	0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e,
+	0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
+	0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0,
+	0x1eac5790, 0x796fb449, 0x8252dc15,
+	0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403,
+	0xe83ec305, 0x4f91751a, 0x925669c2,
+	0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574,
+	0x927985b2, 0x8276dbcb, 0x02778176,
+	0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83,
+	0x340ce5c8, 0x96bbb682, 0x93b4b148,
+	0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20,
+	0x8437aa88, 0x7d29dc96, 0x2756d3dc,
+	0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e,
+	0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
+	0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9,
+	0xbda8229c, 0x127dadaa, 0x438a074e,
+	0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff,
+	0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
+	0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a,
+	0x76a2e214, 0xb9a40368, 0x925d958f,
+	0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623,
+	0x193cbcfa, 0x27627545, 0x825cf47a,
+	0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7,
+	0x8272a972, 0x9270c4a8, 0x127de50b,
+	0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb,
+	0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
+	0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11,
+	0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
+	0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c,
+	0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
+	0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40,
+	0x7c34671c, 0x02717ef6, 0x4feb5536,
+	0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1,
+	0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
+	0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33,
+	0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
+	0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff,
+	0x856302e0, 0x72dbd92b, 0xee971b69,
+	0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2,
+	0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
+	0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38,
+	0x0ff0443d, 0x606e6dc6, 0x60543a49,
+	0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f,
+	0x68458425, 0x99833be5, 0x600d457d,
+	0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31,
+	0x9c305a00, 0x52bce688, 0x1b03588a,
+	0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636,
+	0xa133c501, 0xe9d3531c, 0xee353783
+};
+EXPORT_SYMBOL_GPL(cast6_s3);
+
+const u32 cast6_s4[256] = {
+	0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb,
+	0x64ad8c57, 0x85510443, 0xfa020ed1,
+	0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43,
+	0x6497b7b1, 0xf3641f63, 0x241e4adf,
+	0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30,
+	0xc0a5374f, 0x1d2d00d9, 0x24147b15,
+	0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f,
+	0x0c13fefe, 0x081b08ca, 0x05170121,
+	0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f,
+	0x06df4261, 0xbb9e9b8a, 0x7293ea25,
+	0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400,
+	0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
+	0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061,
+	0x11b638e1, 0x72500e03, 0xf80eb2bb,
+	0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400,
+	0x6920318f, 0x081dbb99, 0xffc304a5,
+	0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea,
+	0x9f926f91, 0x9f46222f, 0x3991467d,
+	0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8,
+	0x3fb6180c, 0x18f8931e, 0x281658e6,
+	0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25,
+	0x79098b02, 0xe4eabb81, 0x28123b23,
+	0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9,
+	0x0014377b, 0x041e8ac8, 0x09114003,
+	0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de,
+	0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
+	0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0,
+	0x56c8c391, 0x6b65811c, 0x5e146119,
+	0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d,
+	0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
+	0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a,
+	0xeca1d7c7, 0x041afa32, 0x1d16625a,
+	0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb,
+	0xc70b8b46, 0xd9e66a48, 0x56e55a79,
+	0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3,
+	0xedda04eb, 0x17a9be04, 0x2c18f4df,
+	0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254,
+	0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
+	0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2,
+	0x0418f2c8, 0x001a96a6, 0x0d1526ab,
+	0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86,
+	0x311170a7, 0x3e9b640c, 0xcc3e10d7,
+	0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1,
+	0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
+	0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca,
+	0xb4be31cd, 0xd8782806, 0x12a3a4e2,
+	0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5,
+	0x9711aac5, 0x001d7b95, 0x82e5e7d2,
+	0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415,
+	0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
+	0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7,
+	0x0ce454a9, 0xd60acd86, 0x015f1919,
+	0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe,
+	0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
+	0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb,
+	0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
+	0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8,
+	0x296b299e, 0x492fc295, 0x9266beab,
+	0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee,
+	0xf65324e6, 0x6afce36c, 0x0316cc04,
+	0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979,
+	0x932bcdf6, 0xb657c34d, 0x4edfd282,
+	0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0,
+	0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2
+};
+EXPORT_SYMBOL_GPL(cast6_s4);
+
+static const u32 Tm[24][8] = {
+	{ 0x5a827999, 0xc95c653a, 0x383650db, 0xa7103c7c, 0x15ea281d,
+		0x84c413be, 0xf39dff5f, 0x6277eb00 } ,
+	{ 0xd151d6a1, 0x402bc242, 0xaf05ade3, 0x1ddf9984, 0x8cb98525,
+		0xfb9370c6, 0x6a6d5c67, 0xd9474808 } ,
+	{ 0x482133a9, 0xb6fb1f4a, 0x25d50aeb, 0x94aef68c, 0x0388e22d,
+		0x7262cdce, 0xe13cb96f, 0x5016a510 } ,
+	{ 0xbef090b1, 0x2dca7c52, 0x9ca467f3, 0x0b7e5394, 0x7a583f35,
+		0xe9322ad6, 0x580c1677, 0xc6e60218 } ,
+	{ 0x35bfedb9, 0xa499d95a, 0x1373c4fb, 0x824db09c, 0xf1279c3d,
+		0x600187de, 0xcedb737f, 0x3db55f20 } ,
+	{ 0xac8f4ac1, 0x1b693662, 0x8a432203, 0xf91d0da4, 0x67f6f945,
+		0xd6d0e4e6, 0x45aad087, 0xb484bc28 } ,
+	{ 0x235ea7c9, 0x9238936a, 0x01127f0b, 0x6fec6aac, 0xdec6564d,
+		0x4da041ee, 0xbc7a2d8f, 0x2b541930 } ,
+	{ 0x9a2e04d1, 0x0907f072, 0x77e1dc13, 0xe6bbc7b4, 0x5595b355,
+		0xc46f9ef6, 0x33498a97, 0xa2237638 } ,
+	{ 0x10fd61d9, 0x7fd74d7a, 0xeeb1391b, 0x5d8b24bc, 0xcc65105d,
+		0x3b3efbfe, 0xaa18e79f, 0x18f2d340 } ,
+	{ 0x87ccbee1, 0xf6a6aa82, 0x65809623, 0xd45a81c4, 0x43346d65,
+		0xb20e5906, 0x20e844a7, 0x8fc23048 } ,
+	{ 0xfe9c1be9, 0x6d76078a, 0xdc4ff32b, 0x4b29decc, 0xba03ca6d,
+		0x28ddb60e, 0x97b7a1af, 0x06918d50 } ,
+	{ 0x756b78f1, 0xe4456492, 0x531f5033, 0xc1f93bd4, 0x30d32775,
+		0x9fad1316, 0x0e86feb7, 0x7d60ea58 } ,
+	{ 0xec3ad5f9, 0x5b14c19a, 0xc9eead3b, 0x38c898dc, 0xa7a2847d,
+		0x167c701e, 0x85565bbf, 0xf4304760 } ,
+	{ 0x630a3301, 0xd1e41ea2, 0x40be0a43, 0xaf97f5e4, 0x1e71e185,
+		0x8d4bcd26, 0xfc25b8c7, 0x6affa468 } ,
+	{ 0xd9d99009, 0x48b37baa, 0xb78d674b, 0x266752ec, 0x95413e8d,
+		0x041b2a2e, 0x72f515cf, 0xe1cf0170 } ,
+	{ 0x50a8ed11, 0xbf82d8b2, 0x2e5cc453, 0x9d36aff4, 0x0c109b95,
+		0x7aea8736, 0xe9c472d7, 0x589e5e78 } ,
+	{ 0xc7784a19, 0x365235ba, 0xa52c215b, 0x14060cfc, 0x82dff89d,
+		0xf1b9e43e, 0x6093cfdf, 0xcf6dbb80 } ,
+	{ 0x3e47a721, 0xad2192c2, 0x1bfb7e63, 0x8ad56a04, 0xf9af55a5,
+		0x68894146, 0xd7632ce7, 0x463d1888 } ,
+	{ 0xb5170429, 0x23f0efca, 0x92cadb6b, 0x01a4c70c, 0x707eb2ad,
+		0xdf589e4e, 0x4e3289ef, 0xbd0c7590 } ,
+	{ 0x2be66131, 0x9ac04cd2, 0x099a3873, 0x78742414, 0xe74e0fb5,
+		0x5627fb56, 0xc501e6f7, 0x33dbd298 } ,
+	{ 0xa2b5be39, 0x118fa9da, 0x8069957b, 0xef43811c, 0x5e1d6cbd,
+		0xccf7585e, 0x3bd143ff, 0xaaab2fa0 } ,
+	{ 0x19851b41, 0x885f06e2, 0xf738f283, 0x6612de24, 0xd4ecc9c5,
+		0x43c6b566, 0xb2a0a107, 0x217a8ca8 } ,
+	{ 0x90547849, 0xff2e63ea, 0x6e084f8b, 0xdce23b2c, 0x4bbc26cd,
+		0xba96126e, 0x296ffe0f, 0x9849e9b0 } ,
+	{ 0x0723d551, 0x75fdc0f2, 0xe4d7ac93, 0x53b19834, 0xc28b83d5,
+		0x31656f76, 0xa03f5b17, 0x0f1946b8 }
+};
+
+static const u8 Tr[4][8] = {
+	{ 0x13, 0x04, 0x15, 0x06, 0x17, 0x08, 0x19, 0x0a } ,
+	{ 0x1b, 0x0c, 0x1d, 0x0e, 0x1f, 0x10, 0x01, 0x12 } ,
+	{ 0x03, 0x14, 0x05, 0x16, 0x07, 0x18, 0x09, 0x1a } ,
+	{ 0x0b, 0x1c, 0x0d, 0x1e, 0x0f, 0x00, 0x11, 0x02 }
+};
+
+/* forward octave */
+static void W(u32 *key, unsigned int i)
+{
+	u32 I;
+	key[6] ^= F1(key[7], Tr[i % 4][0], Tm[i][0]);
+	key[5] ^= F2(key[6], Tr[i % 4][1], Tm[i][1]);
+	key[4] ^= F3(key[5], Tr[i % 4][2], Tm[i][2]);
+	key[3] ^= F1(key[4], Tr[i % 4][3], Tm[i][3]);
+	key[2] ^= F2(key[3], Tr[i % 4][4], Tm[i][4]);
+	key[1] ^= F3(key[2], Tr[i % 4][5], Tm[i][5]);
+	key[0] ^= F1(key[1], Tr[i % 4][6], Tm[i][6]);
+	key[7] ^= F2(key[0], Tr[i % 4][7], Tm[i][7]);
+}
+
+int __cast6_setkey(struct cast6_ctx *c, const u8 *in_key,
+		   unsigned key_len, u32 *flags)
+{
+	int i;
+	u32 key[8];
+	__be32 p_key[8]; /* padded key */
+
+	if (key_len % 4 != 0) {
+		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		return -EINVAL;
+	}
+
+	memset(p_key, 0, 32);
+	memcpy(p_key, in_key, key_len);
+
+	key[0] = be32_to_cpu(p_key[0]);		/* A */
+	key[1] = be32_to_cpu(p_key[1]);		/* B */
+	key[2] = be32_to_cpu(p_key[2]);		/* C */
+	key[3] = be32_to_cpu(p_key[3]);		/* D */
+	key[4] = be32_to_cpu(p_key[4]);		/* E */
+	key[5] = be32_to_cpu(p_key[5]);		/* F */
+	key[6] = be32_to_cpu(p_key[6]);		/* G */
+	key[7] = be32_to_cpu(p_key[7]);		/* H */
+
+	for (i = 0; i < 12; i++) {
+		W(key, 2 * i);
+		W(key, 2 * i + 1);
+
+		c->Kr[i][0] = key[0] & 0x1f;
+		c->Kr[i][1] = key[2] & 0x1f;
+		c->Kr[i][2] = key[4] & 0x1f;
+		c->Kr[i][3] = key[6] & 0x1f;
+
+		c->Km[i][0] = key[7];
+		c->Km[i][1] = key[5];
+		c->Km[i][2] = key[3];
+		c->Km[i][3] = key[1];
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(__cast6_setkey);
+
+int cast6_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
+{
+	return __cast6_setkey(crypto_tfm_ctx(tfm), key, keylen,
+			      &tfm->crt_flags);
+}
+EXPORT_SYMBOL_GPL(cast6_setkey);
+
+/*forward quad round*/
+static void Q(u32 *block, u8 *Kr, u32 *Km)
+{
+	u32 I;
+	block[2] ^= F1(block[3], Kr[0], Km[0]);
+	block[1] ^= F2(block[2], Kr[1], Km[1]);
+	block[0] ^= F3(block[1], Kr[2], Km[2]);
+	block[3] ^= F1(block[0], Kr[3], Km[3]);
+}
+
+/*reverse quad round*/
+static void QBAR(u32 *block, u8 *Kr, u32 *Km)
+{
+	u32 I;
+	block[3] ^= F1(block[0], Kr[3], Km[3]);
+	block[0] ^= F3(block[1], Kr[2], Km[2]);
+	block[1] ^= F2(block[2], Kr[1], Km[1]);
+	block[2] ^= F1(block[3], Kr[0], Km[0]);
+}
+
+void __cast6_encrypt(struct cast6_ctx *c, u8 *outbuf, const u8 *inbuf)
+{
+	const __be32 *src = (const __be32 *)inbuf;
+	__be32 *dst = (__be32 *)outbuf;
+	u32 block[4];
+	u32 *Km;
+	u8 *Kr;
+
+	block[0] = be32_to_cpu(src[0]);
+	block[1] = be32_to_cpu(src[1]);
+	block[2] = be32_to_cpu(src[2]);
+	block[3] = be32_to_cpu(src[3]);
+
+	Km = c->Km[0]; Kr = c->Kr[0]; Q(block, Kr, Km);
+	Km = c->Km[1]; Kr = c->Kr[1]; Q(block, Kr, Km);
+	Km = c->Km[2]; Kr = c->Kr[2]; Q(block, Kr, Km);
+	Km = c->Km[3]; Kr = c->Kr[3]; Q(block, Kr, Km);
+	Km = c->Km[4]; Kr = c->Kr[4]; Q(block, Kr, Km);
+	Km = c->Km[5]; Kr = c->Kr[5]; Q(block, Kr, Km);
+	Km = c->Km[6]; Kr = c->Kr[6]; QBAR(block, Kr, Km);
+	Km = c->Km[7]; Kr = c->Kr[7]; QBAR(block, Kr, Km);
+	Km = c->Km[8]; Kr = c->Kr[8]; QBAR(block, Kr, Km);
+	Km = c->Km[9]; Kr = c->Kr[9]; QBAR(block, Kr, Km);
+	Km = c->Km[10]; Kr = c->Kr[10]; QBAR(block, Kr, Km);
+	Km = c->Km[11]; Kr = c->Kr[11]; QBAR(block, Kr, Km);
+
+	dst[0] = cpu_to_be32(block[0]);
+	dst[1] = cpu_to_be32(block[1]);
+	dst[2] = cpu_to_be32(block[2]);
+	dst[3] = cpu_to_be32(block[3]);
+}
+EXPORT_SYMBOL_GPL(__cast6_encrypt);
+
+static void cast6_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
+{
+	__cast6_encrypt(crypto_tfm_ctx(tfm), outbuf, inbuf);
+}
+
+void __cast6_decrypt(struct cast6_ctx *c, u8 *outbuf, const u8 *inbuf)
+{
+	const __be32 *src = (const __be32 *)inbuf;
+	__be32 *dst = (__be32 *)outbuf;
+	u32 block[4];
+	u32 *Km;
+	u8 *Kr;
+
+	block[0] = be32_to_cpu(src[0]);
+	block[1] = be32_to_cpu(src[1]);
+	block[2] = be32_to_cpu(src[2]);
+	block[3] = be32_to_cpu(src[3]);
+
+	Km = c->Km[11]; Kr = c->Kr[11]; Q(block, Kr, Km);
+	Km = c->Km[10]; Kr = c->Kr[10]; Q(block, Kr, Km);
+	Km = c->Km[9]; Kr = c->Kr[9]; Q(block, Kr, Km);
+	Km = c->Km[8]; Kr = c->Kr[8]; Q(block, Kr, Km);
+	Km = c->Km[7]; Kr = c->Kr[7]; Q(block, Kr, Km);
+	Km = c->Km[6]; Kr = c->Kr[6]; Q(block, Kr, Km);
+	Km = c->Km[5]; Kr = c->Kr[5]; QBAR(block, Kr, Km);
+	Km = c->Km[4]; Kr = c->Kr[4]; QBAR(block, Kr, Km);
+	Km = c->Km[3]; Kr = c->Kr[3]; QBAR(block, Kr, Km);
+	Km = c->Km[2]; Kr = c->Kr[2]; QBAR(block, Kr, Km);
+	Km = c->Km[1]; Kr = c->Kr[1]; QBAR(block, Kr, Km);
+	Km = c->Km[0]; Kr = c->Kr[0]; QBAR(block, Kr, Km);
+
+	dst[0] = cpu_to_be32(block[0]);
+	dst[1] = cpu_to_be32(block[1]);
+	dst[2] = cpu_to_be32(block[2]);
+	dst[3] = cpu_to_be32(block[3]);
+}
+EXPORT_SYMBOL_GPL(__cast6_decrypt);
+
+static void cast6_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
+{
+	__cast6_decrypt(crypto_tfm_ctx(tfm), outbuf, inbuf);
+}
+
+static struct crypto_alg alg = {
+	.cra_name = "cast6",
+	.cra_driver_name = "cast6-generic",
+	.cra_priority = 100,
+	.cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize = CAST6_BLOCK_SIZE,
+	.cra_ctxsize = sizeof(struct cast6_ctx),
+	.cra_alignmask = 3,
+	.cra_module = THIS_MODULE,
+	.cra_u = {
+		  .cipher = {
+			     .cia_min_keysize = CAST6_MIN_KEY_SIZE,
+			     .cia_max_keysize = CAST6_MAX_KEY_SIZE,
+			     .cia_setkey = cast6_setkey,
+			     .cia_encrypt = cast6_encrypt,
+			     .cia_decrypt = cast6_decrypt}
+		  }
+};
+
+static int __init cast6_mod_init(void)
+{
+	return crypto_register_alg(&alg);
+}
+
+static void __exit cast6_mod_fini(void)
+{
+	crypto_unregister_alg(&alg);
+}
+
+module_init(cast6_mod_init);
+module_exit(cast6_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cast6 Cipher Algorithm");
+MODULE_ALIAS("cast6");
diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c
index 07a8a96..fee7265 100644
--- a/crypto/crypto_null.c
+++ b/crypto/crypto_null.c
@@ -94,18 +94,6 @@ static int skcipher_null_crypt(struct blkcipher_desc *desc,
 	return err;
 }
 
-static struct crypto_alg compress_null = {
-	.cra_name		=	"compress_null",
-	.cra_flags		=	CRYPTO_ALG_TYPE_COMPRESS,
-	.cra_blocksize		=	NULL_BLOCK_SIZE,
-	.cra_ctxsize		=	0,
-	.cra_module		=	THIS_MODULE,
-	.cra_list		=       LIST_HEAD_INIT(compress_null.cra_list),
-	.cra_u			=	{ .compress = {
-	.coa_compress 		=	null_compress,
-	.coa_decompress		=	null_compress } }
-};
-
 static struct shash_alg digest_null = {
 	.digestsize		=	NULL_DIGEST_SIZE,
 	.setkey   		=	null_hash_setkey,
@@ -122,22 +110,19 @@ static struct shash_alg digest_null = {
 	}
 };
 
-static struct crypto_alg cipher_null = {
+static struct crypto_alg null_algs[3] = { {
 	.cra_name		=	"cipher_null",
 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
 	.cra_blocksize		=	NULL_BLOCK_SIZE,
 	.cra_ctxsize		=	0,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(cipher_null.cra_list),
 	.cra_u			=	{ .cipher = {
 	.cia_min_keysize	=	NULL_KEY_SIZE,
 	.cia_max_keysize	=	NULL_KEY_SIZE,
 	.cia_setkey		= 	null_setkey,
 	.cia_encrypt		=	null_crypt,
 	.cia_decrypt		=	null_crypt } }
-};
-
-static struct crypto_alg skcipher_null = {
+}, {
 	.cra_name		=	"ecb(cipher_null)",
 	.cra_driver_name	=	"ecb-cipher_null",
 	.cra_priority		=	100,
@@ -146,7 +131,6 @@ static struct crypto_alg skcipher_null = {
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_ctxsize		=	0,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(skcipher_null.cra_list),
 	.cra_u			=	{ .blkcipher = {
 	.min_keysize		=	NULL_KEY_SIZE,
 	.max_keysize		=	NULL_KEY_SIZE,
@@ -154,7 +138,16 @@ static struct crypto_alg skcipher_null = {
 	.setkey			= 	null_setkey,
 	.encrypt		=	skcipher_null_crypt,
 	.decrypt		=	skcipher_null_crypt } }
-};
+}, {
+	.cra_name		=	"compress_null",
+	.cra_flags		=	CRYPTO_ALG_TYPE_COMPRESS,
+	.cra_blocksize		=	NULL_BLOCK_SIZE,
+	.cra_ctxsize		=	0,
+	.cra_module		=	THIS_MODULE,
+	.cra_u			=	{ .compress = {
+	.coa_compress		=	null_compress,
+	.coa_decompress		=	null_compress } }
+} };
 
 MODULE_ALIAS("compress_null");
 MODULE_ALIAS("digest_null");
@@ -164,40 +157,26 @@ static int __init crypto_null_mod_init(void)
 {
 	int ret = 0;
 
-	ret = crypto_register_alg(&cipher_null);
+	ret = crypto_register_algs(null_algs, ARRAY_SIZE(null_algs));
 	if (ret < 0)
 		goto out;
 
-	ret = crypto_register_alg(&skcipher_null);
-	if (ret < 0)
-		goto out_unregister_cipher;
-
 	ret = crypto_register_shash(&digest_null);
 	if (ret < 0)
-		goto out_unregister_skcipher;
+		goto out_unregister_algs;
 
-	ret = crypto_register_alg(&compress_null);
-	if (ret < 0)
-		goto out_unregister_digest;
+	return 0;
 
+out_unregister_algs:
+	crypto_unregister_algs(null_algs, ARRAY_SIZE(null_algs));
 out:
 	return ret;
-
-out_unregister_digest:
-	crypto_unregister_shash(&digest_null);
-out_unregister_skcipher:
-	crypto_unregister_alg(&skcipher_null);
-out_unregister_cipher:
-	crypto_unregister_alg(&cipher_null);
-	goto out;
 }
 
 static void __exit crypto_null_mod_fini(void)
 {
-	crypto_unregister_alg(&compress_null);
 	crypto_unregister_shash(&digest_null);
-	crypto_unregister_alg(&skcipher_null);
-	crypto_unregister_alg(&cipher_null);
+	crypto_unregister_algs(null_algs, ARRAY_SIZE(null_algs));
 }
 
 module_init(crypto_null_mod_init);
diff --git a/crypto/deflate.c b/crypto/deflate.c
index b0165ec..b57d70e 100644
--- a/crypto/deflate.c
+++ b/crypto/deflate.c
@@ -199,7 +199,6 @@ static struct crypto_alg alg = {
 	.cra_flags		= CRYPTO_ALG_TYPE_COMPRESS,
 	.cra_ctxsize		= sizeof(struct deflate_ctx),
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(alg.cra_list),
 	.cra_init		= deflate_init,
 	.cra_exit		= deflate_exit,
 	.cra_u			= { .compress = {
diff --git a/crypto/des_generic.c b/crypto/des_generic.c
index 873818d..f6cf63f 100644
--- a/crypto/des_generic.c
+++ b/crypto/des_generic.c
@@ -943,59 +943,44 @@ static void des3_ede_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 	d[1] = cpu_to_le32(L);
 }
 
-static struct crypto_alg des_alg = {
+static struct crypto_alg des_algs[2] = { {
 	.cra_name		=	"des",
 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
 	.cra_blocksize		=	DES_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct des_ctx),
 	.cra_module		=	THIS_MODULE,
 	.cra_alignmask		=	3,
-	.cra_list		=	LIST_HEAD_INIT(des_alg.cra_list),
 	.cra_u			=	{ .cipher = {
 	.cia_min_keysize	=	DES_KEY_SIZE,
 	.cia_max_keysize	=	DES_KEY_SIZE,
 	.cia_setkey		=	des_setkey,
 	.cia_encrypt		=	des_encrypt,
 	.cia_decrypt		=	des_decrypt } }
-};
-
-static struct crypto_alg des3_ede_alg = {
+}, {
 	.cra_name		=	"des3_ede",
 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
 	.cra_blocksize		=	DES3_EDE_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct des3_ede_ctx),
 	.cra_module		=	THIS_MODULE,
 	.cra_alignmask		=	3,
-	.cra_list		=	LIST_HEAD_INIT(des3_ede_alg.cra_list),
 	.cra_u			=	{ .cipher = {
 	.cia_min_keysize	=	DES3_EDE_KEY_SIZE,
 	.cia_max_keysize	=	DES3_EDE_KEY_SIZE,
 	.cia_setkey		=	des3_ede_setkey,
 	.cia_encrypt		=	des3_ede_encrypt,
 	.cia_decrypt		=	des3_ede_decrypt } }
-};
+} };
 
 MODULE_ALIAS("des3_ede");
 
 static int __init des_generic_mod_init(void)
 {
-	int ret = 0;
-
-	ret = crypto_register_alg(&des_alg);
-	if (ret < 0)
-		goto out;
-
-	ret = crypto_register_alg(&des3_ede_alg);
-	if (ret < 0)
-		crypto_unregister_alg(&des_alg);
-out:
-	return ret;
+	return crypto_register_algs(des_algs, ARRAY_SIZE(des_algs));
 }
 
 static void __exit des_generic_mod_fini(void)
 {
-	crypto_unregister_alg(&des3_ede_alg);
-	crypto_unregister_alg(&des_alg);
+	crypto_unregister_algs(des_algs, ARRAY_SIZE(des_algs));
 }
 
 module_init(des_generic_mod_init);
diff --git a/crypto/fcrypt.c b/crypto/fcrypt.c
index c33107e..3b2cf56 100644
--- a/crypto/fcrypt.c
+++ b/crypto/fcrypt.c
@@ -396,7 +396,6 @@ static struct crypto_alg fcrypt_alg = {
 	.cra_ctxsize		=	sizeof(struct fcrypt_ctx),
 	.cra_module		=	THIS_MODULE,
 	.cra_alignmask		=	3,
-	.cra_list		=	LIST_HEAD_INIT(fcrypt_alg.cra_list),
 	.cra_u			=	{ .cipher = {
 	.cia_min_keysize	=	8,
 	.cia_max_keysize	=	8,
diff --git a/crypto/ghash-generic.c b/crypto/ghash-generic.c
index 7835b8f..9d3f0c6 100644
--- a/crypto/ghash-generic.c
+++ b/crypto/ghash-generic.c
@@ -153,7 +153,6 @@ static struct shash_alg ghash_alg = {
 		.cra_blocksize		= GHASH_BLOCK_SIZE,
 		.cra_ctxsize		= sizeof(struct ghash_ctx),
 		.cra_module		= THIS_MODULE,
-		.cra_list		= LIST_HEAD_INIT(ghash_alg.base.cra_list),
 		.cra_exit		= ghash_exit_tfm,
 	},
 };
diff --git a/crypto/khazad.c b/crypto/khazad.c
index 527e4e3..60e7cd6 100644
--- a/crypto/khazad.c
+++ b/crypto/khazad.c
@@ -853,7 +853,6 @@ static struct crypto_alg khazad_alg = {
 	.cra_ctxsize		=	sizeof (struct khazad_ctx),
 	.cra_alignmask		=	7,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(khazad_alg.cra_list),
 	.cra_u			=	{ .cipher = {
 	.cia_min_keysize	=	KHAZAD_KEY_SIZE,
 	.cia_max_keysize	=	KHAZAD_KEY_SIZE,
diff --git a/crypto/krng.c b/crypto/krng.c
index 4328bb3..a2d2b72 100644
--- a/crypto/krng.c
+++ b/crypto/krng.c
@@ -35,7 +35,6 @@ static struct crypto_alg krng_alg = {
 	.cra_ctxsize		= 0,
 	.cra_type		= &crypto_rng_type,
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(krng_alg.cra_list),
 	.cra_u			= {
 		.rng = {
 			.rng_make_random	= krng_get_random,
diff --git a/crypto/lzo.c b/crypto/lzo.c
index b5e7707..1c2aa69 100644
--- a/crypto/lzo.c
+++ b/crypto/lzo.c
@@ -81,7 +81,6 @@ static struct crypto_alg alg = {
 	.cra_flags		= CRYPTO_ALG_TYPE_COMPRESS,
 	.cra_ctxsize		= sizeof(struct lzo_ctx),
 	.cra_module		= THIS_MODULE,
-	.cra_list		= LIST_HEAD_INIT(alg.cra_list),
 	.cra_init		= lzo_init,
 	.cra_exit		= lzo_exit,
 	.cra_u			= { .compress = {
diff --git a/crypto/salsa20_generic.c b/crypto/salsa20_generic.c
index eac10c1..9a4770c 100644
--- a/crypto/salsa20_generic.c
+++ b/crypto/salsa20_generic.c
@@ -221,7 +221,6 @@ static struct crypto_alg alg = {
 	.cra_ctxsize        =   sizeof(struct salsa20_ctx),
 	.cra_alignmask      =	3,
 	.cra_module         =   THIS_MODULE,
-	.cra_list           =   LIST_HEAD_INIT(alg.cra_list),
 	.cra_u              =   {
 		.blkcipher = {
 			.setkey         =   setkey,
diff --git a/crypto/seed.c b/crypto/seed.c
index d3e422f..9c904d6 100644
--- a/crypto/seed.c
+++ b/crypto/seed.c
@@ -449,7 +449,6 @@ static struct crypto_alg seed_alg = {
 	.cra_ctxsize		=	sizeof(struct seed_ctx),
 	.cra_alignmask		=	3,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(seed_alg.cra_list),
 	.cra_u			=	{
 		.cipher = {
 			.cia_min_keysize	=	SEED_KEY_SIZE,
diff --git a/crypto/serpent_generic.c b/crypto/serpent_generic.c
index 8f32cf3..7ddbd7e 100644
--- a/crypto/serpent_generic.c
+++ b/crypto/serpent_generic.c
@@ -567,24 +567,6 @@ static void serpent_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 	__serpent_decrypt(ctx, dst, src);
 }
 
-static struct crypto_alg serpent_alg = {
-	.cra_name		=	"serpent",
-	.cra_driver_name	=	"serpent-generic",
-	.cra_priority		=	100,
-	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
-	.cra_blocksize		=	SERPENT_BLOCK_SIZE,
-	.cra_ctxsize		=	sizeof(struct serpent_ctx),
-	.cra_alignmask		=	3,
-	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(serpent_alg.cra_list),
-	.cra_u			=	{ .cipher = {
-	.cia_min_keysize	=	SERPENT_MIN_KEY_SIZE,
-	.cia_max_keysize	=	SERPENT_MAX_KEY_SIZE,
-	.cia_setkey		=	serpent_setkey,
-	.cia_encrypt		=	serpent_encrypt,
-	.cia_decrypt		=	serpent_decrypt } }
-};
-
 static int tnepres_setkey(struct crypto_tfm *tfm, const u8 *key,
 			  unsigned int keylen)
 {
@@ -637,41 +619,44 @@ static void tnepres_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 	d[3] = swab32(rd[0]);
 }
 
-static struct crypto_alg tnepres_alg = {
+static struct crypto_alg srp_algs[2] = { {
+	.cra_name		=	"serpent",
+	.cra_driver_name	=	"serpent-generic",
+	.cra_priority		=	100,
+	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		=	SERPENT_BLOCK_SIZE,
+	.cra_ctxsize		=	sizeof(struct serpent_ctx),
+	.cra_alignmask		=	3,
+	.cra_module		=	THIS_MODULE,
+	.cra_u			=	{ .cipher = {
+	.cia_min_keysize	=	SERPENT_MIN_KEY_SIZE,
+	.cia_max_keysize	=	SERPENT_MAX_KEY_SIZE,
+	.cia_setkey		=	serpent_setkey,
+	.cia_encrypt		=	serpent_encrypt,
+	.cia_decrypt		=	serpent_decrypt } }
+}, {
 	.cra_name		=	"tnepres",
 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
 	.cra_blocksize		=	SERPENT_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct serpent_ctx),
 	.cra_alignmask		=	3,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(serpent_alg.cra_list),
 	.cra_u			=	{ .cipher = {
 	.cia_min_keysize	=	SERPENT_MIN_KEY_SIZE,
 	.cia_max_keysize	=	SERPENT_MAX_KEY_SIZE,
 	.cia_setkey		=	tnepres_setkey,
 	.cia_encrypt		=	tnepres_encrypt,
 	.cia_decrypt		=	tnepres_decrypt } }
-};
+} };
 
 static int __init serpent_mod_init(void)
 {
-	int ret = crypto_register_alg(&serpent_alg);
-
-	if (ret)
-		return ret;
-
-	ret = crypto_register_alg(&tnepres_alg);
-
-	if (ret)
-		crypto_unregister_alg(&serpent_alg);
-
-	return ret;
+	return crypto_register_algs(srp_algs, ARRAY_SIZE(srp_algs));
 }
 
 static void __exit serpent_mod_fini(void)
 {
-	crypto_unregister_alg(&tnepres_alg);
-	crypto_unregister_alg(&serpent_alg);
+	crypto_unregister_algs(srp_algs, ARRAY_SIZE(srp_algs));
 }
 
 module_init(serpent_mod_init);
diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c
index c48459e..c3ed4ec 100644
--- a/crypto/sha256_generic.c
+++ b/crypto/sha256_generic.c
@@ -336,7 +336,7 @@ static int sha256_import(struct shash_desc *desc, const void *in)
 	return 0;
 }
 
-static struct shash_alg sha256 = {
+static struct shash_alg sha256_algs[2] = { {
 	.digestsize	=	SHA256_DIGEST_SIZE,
 	.init		=	sha256_init,
 	.update		=	sha256_update,
@@ -352,9 +352,7 @@ static struct shash_alg sha256 = {
 		.cra_blocksize	=	SHA256_BLOCK_SIZE,
 		.cra_module	=	THIS_MODULE,
 	}
-};
-
-static struct shash_alg sha224 = {
+}, {
 	.digestsize	=	SHA224_DIGEST_SIZE,
 	.init		=	sha224_init,
 	.update		=	sha256_update,
@@ -367,29 +365,16 @@ static struct shash_alg sha224 = {
 		.cra_blocksize	=	SHA224_BLOCK_SIZE,
 		.cra_module	=	THIS_MODULE,
 	}
-};
+} };
 
 static int __init sha256_generic_mod_init(void)
 {
-	int ret = 0;
-
-	ret = crypto_register_shash(&sha224);
-
-	if (ret < 0)
-		return ret;
-
-	ret = crypto_register_shash(&sha256);
-
-	if (ret < 0)
-		crypto_unregister_shash(&sha224);
-
-	return ret;
+	return crypto_register_shashes(sha256_algs, ARRAY_SIZE(sha256_algs));
 }
 
 static void __exit sha256_generic_mod_fini(void)
 {
-	crypto_unregister_shash(&sha224);
-	crypto_unregister_shash(&sha256);
+	crypto_unregister_shashes(sha256_algs, ARRAY_SIZE(sha256_algs));
 }
 
 module_init(sha256_generic_mod_init);
diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c
index dd30f40..71fcf36 100644
--- a/crypto/sha512_generic.c
+++ b/crypto/sha512_generic.c
@@ -242,7 +242,7 @@ static int sha384_final(struct shash_desc *desc, u8 *hash)
 	return 0;
 }
 
-static struct shash_alg sha512 = {
+static struct shash_alg sha512_algs[2] = { {
 	.digestsize	=	SHA512_DIGEST_SIZE,
 	.init		=	sha512_init,
 	.update		=	sha512_update,
@@ -254,9 +254,7 @@ static struct shash_alg sha512 = {
 		.cra_blocksize	=	SHA512_BLOCK_SIZE,
 		.cra_module	=	THIS_MODULE,
 	}
-};
-
-static struct shash_alg sha384 = {
+}, {
 	.digestsize	=	SHA384_DIGEST_SIZE,
 	.init		=	sha384_init,
 	.update		=	sha512_update,
@@ -268,24 +266,16 @@ static struct shash_alg sha384 = {
 		.cra_blocksize	=	SHA384_BLOCK_SIZE,
 		.cra_module	=	THIS_MODULE,
 	}
-};
+} };
 
 static int __init sha512_generic_mod_init(void)
 {
-        int ret = 0;
-
-        if ((ret = crypto_register_shash(&sha384)) < 0)
-                goto out;
-        if ((ret = crypto_register_shash(&sha512)) < 0)
-                crypto_unregister_shash(&sha384);
-out:
-        return ret;
+	return crypto_register_shashes(sha512_algs, ARRAY_SIZE(sha512_algs));
 }
 
 static void __exit sha512_generic_mod_fini(void)
 {
-        crypto_unregister_shash(&sha384);
-        crypto_unregister_shash(&sha512);
+	crypto_unregister_shashes(sha512_algs, ARRAY_SIZE(sha512_algs));
 }
 
 module_init(sha512_generic_mod_init);
diff --git a/crypto/shash.c b/crypto/shash.c
index 32067f4..f426330f 100644
--- a/crypto/shash.c
+++ b/crypto/shash.c
@@ -629,6 +629,42 @@ int crypto_unregister_shash(struct shash_alg *alg)
 }
 EXPORT_SYMBOL_GPL(crypto_unregister_shash);
 
+int crypto_register_shashes(struct shash_alg *algs, int count)
+{
+	int i, ret;
+
+	for (i = 0; i < count; i++) {
+		ret = crypto_register_shash(&algs[i]);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	for (--i; i >= 0; --i)
+		crypto_unregister_shash(&algs[i]);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(crypto_register_shashes);
+
+int crypto_unregister_shashes(struct shash_alg *algs, int count)
+{
+	int i, ret;
+
+	for (i = count - 1; i >= 0; --i) {
+		ret = crypto_unregister_shash(&algs[i]);
+		if (ret)
+			pr_err("Failed to unregister %s %s: %d\n",
+			       algs[i].base.cra_driver_name,
+			       algs[i].base.cra_name, ret);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_unregister_shashes);
+
 int shash_register_instance(struct crypto_template *tmpl,
 			    struct shash_instance *inst)
 {
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index 5cf2ccb..871076b 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -1037,10 +1037,16 @@ static int do_test(int m)
 
 	case 14:
 		ret += tcrypt_test("ecb(cast5)");
+		ret += tcrypt_test("cbc(cast5)");
+		ret += tcrypt_test("ctr(cast5)");
 		break;
 
 	case 15:
 		ret += tcrypt_test("ecb(cast6)");
+		ret += tcrypt_test("cbc(cast6)");
+		ret += tcrypt_test("ctr(cast6)");
+		ret += tcrypt_test("lrw(cast6)");
+		ret += tcrypt_test("xts(cast6)");
 		break;
 
 	case 16:
@@ -1359,6 +1365,44 @@ static int do_test(int m)
 				  speed_template_8);
 		break;
 
+	case 209:
+		test_cipher_speed("ecb(cast5)", ENCRYPT, sec, NULL, 0,
+				  speed_template_8_16);
+		test_cipher_speed("ecb(cast5)", DECRYPT, sec, NULL, 0,
+				  speed_template_8_16);
+		test_cipher_speed("cbc(cast5)", ENCRYPT, sec, NULL, 0,
+				  speed_template_8_16);
+		test_cipher_speed("cbc(cast5)", DECRYPT, sec, NULL, 0,
+				  speed_template_8_16);
+		test_cipher_speed("ctr(cast5)", ENCRYPT, sec, NULL, 0,
+				  speed_template_8_16);
+		test_cipher_speed("ctr(cast5)", DECRYPT, sec, NULL, 0,
+				  speed_template_8_16);
+		break;
+
+	case 210:
+		test_cipher_speed("ecb(cast6)", ENCRYPT, sec, NULL, 0,
+				  speed_template_16_32);
+		test_cipher_speed("ecb(cast6)", DECRYPT, sec, NULL, 0,
+				  speed_template_16_32);
+		test_cipher_speed("cbc(cast6)", ENCRYPT, sec, NULL, 0,
+				  speed_template_16_32);
+		test_cipher_speed("cbc(cast6)", DECRYPT, sec, NULL, 0,
+				  speed_template_16_32);
+		test_cipher_speed("ctr(cast6)", ENCRYPT, sec, NULL, 0,
+				  speed_template_16_32);
+		test_cipher_speed("ctr(cast6)", DECRYPT, sec, NULL, 0,
+				  speed_template_16_32);
+		test_cipher_speed("lrw(cast6)", ENCRYPT, sec, NULL, 0,
+				  speed_template_32_48);
+		test_cipher_speed("lrw(cast6)", DECRYPT, sec, NULL, 0,
+				  speed_template_32_48);
+		test_cipher_speed("xts(cast6)", ENCRYPT, sec, NULL, 0,
+				  speed_template_32_64);
+		test_cipher_speed("xts(cast6)", DECRYPT, sec, NULL, 0,
+				  speed_template_32_64);
+		break;
+
 	case 300:
 		/* fall through */
 
@@ -1639,6 +1683,44 @@ static int do_test(int m)
 				   speed_template_8);
 		break;
 
+	case 506:
+		test_acipher_speed("ecb(cast5)", ENCRYPT, sec, NULL, 0,
+				   speed_template_8_16);
+		test_acipher_speed("ecb(cast5)", DECRYPT, sec, NULL, 0,
+				   speed_template_8_16);
+		test_acipher_speed("cbc(cast5)", ENCRYPT, sec, NULL, 0,
+				   speed_template_8_16);
+		test_acipher_speed("cbc(cast5)", DECRYPT, sec, NULL, 0,
+				   speed_template_8_16);
+		test_acipher_speed("ctr(cast5)", ENCRYPT, sec, NULL, 0,
+				   speed_template_8_16);
+		test_acipher_speed("ctr(cast5)", DECRYPT, sec, NULL, 0,
+				   speed_template_8_16);
+		break;
+
+	case 507:
+		test_acipher_speed("ecb(cast6)", ENCRYPT, sec, NULL, 0,
+				   speed_template_16_32);
+		test_acipher_speed("ecb(cast6)", DECRYPT, sec, NULL, 0,
+				   speed_template_16_32);
+		test_acipher_speed("cbc(cast6)", ENCRYPT, sec, NULL, 0,
+				   speed_template_16_32);
+		test_acipher_speed("cbc(cast6)", DECRYPT, sec, NULL, 0,
+				   speed_template_16_32);
+		test_acipher_speed("ctr(cast6)", ENCRYPT, sec, NULL, 0,
+				   speed_template_16_32);
+		test_acipher_speed("ctr(cast6)", DECRYPT, sec, NULL, 0,
+				   speed_template_16_32);
+		test_acipher_speed("lrw(cast6)", ENCRYPT, sec, NULL, 0,
+				   speed_template_32_48);
+		test_acipher_speed("lrw(cast6)", DECRYPT, sec, NULL, 0,
+				   speed_template_32_48);
+		test_acipher_speed("xts(cast6)", ENCRYPT, sec, NULL, 0,
+				   speed_template_32_64);
+		test_acipher_speed("xts(cast6)", DECRYPT, sec, NULL, 0,
+				   speed_template_32_64);
+		break;
+
 	case 1000:
 		test_available();
 		break;
diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h
index 5be1fc8..cd20685 100644
--- a/crypto/tcrypt.h
+++ b/crypto/tcrypt.h
@@ -47,6 +47,7 @@ static struct cipher_speed_template des3_speed_template[] = {
  */
 static u8 speed_template_8[] = {8, 0};
 static u8 speed_template_24[] = {24, 0};
+static u8 speed_template_8_16[] = {8, 16, 0};
 static u8 speed_template_8_32[] = {8, 32, 0};
 static u8 speed_template_16_32[] = {16, 32, 0};
 static u8 speed_template_16_24_32[] = {16, 24, 32, 0};
diff --git a/crypto/tea.c b/crypto/tea.c
index 412bc74..0a57232 100644
--- a/crypto/tea.c
+++ b/crypto/tea.c
@@ -219,84 +219,55 @@ static void xeta_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 	out[1] = cpu_to_le32(z);
 }
 
-static struct crypto_alg tea_alg = {
+static struct crypto_alg tea_algs[3] = { {
 	.cra_name		=	"tea",
 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
 	.cra_blocksize		=	TEA_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof (struct tea_ctx),
 	.cra_alignmask		=	3,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(tea_alg.cra_list),
 	.cra_u			=	{ .cipher = {
 	.cia_min_keysize	=	TEA_KEY_SIZE,
 	.cia_max_keysize	=	TEA_KEY_SIZE,
 	.cia_setkey		= 	tea_setkey,
 	.cia_encrypt		=	tea_encrypt,
 	.cia_decrypt		=	tea_decrypt } }
-};
-
-static struct crypto_alg xtea_alg = {
+}, {
 	.cra_name		=	"xtea",
 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
 	.cra_blocksize		=	XTEA_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof (struct xtea_ctx),
 	.cra_alignmask		=	3,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(xtea_alg.cra_list),
 	.cra_u			=	{ .cipher = {
 	.cia_min_keysize	=	XTEA_KEY_SIZE,
 	.cia_max_keysize	=	XTEA_KEY_SIZE,
 	.cia_setkey		= 	xtea_setkey,
 	.cia_encrypt		=	xtea_encrypt,
 	.cia_decrypt		=	xtea_decrypt } }
-};
-
-static struct crypto_alg xeta_alg = {
+}, {
 	.cra_name		=	"xeta",
 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
 	.cra_blocksize		=	XTEA_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof (struct xtea_ctx),
 	.cra_alignmask		=	3,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(xtea_alg.cra_list),
 	.cra_u			=	{ .cipher = {
 	.cia_min_keysize	=	XTEA_KEY_SIZE,
 	.cia_max_keysize	=	XTEA_KEY_SIZE,
 	.cia_setkey		= 	xtea_setkey,
 	.cia_encrypt		=	xeta_encrypt,
 	.cia_decrypt		=	xeta_decrypt } }
-};
+} };
 
 static int __init tea_mod_init(void)
 {
-	int ret = 0;
-	
-	ret = crypto_register_alg(&tea_alg);
-	if (ret < 0)
-		goto out;
-
-	ret = crypto_register_alg(&xtea_alg);
-	if (ret < 0) {
-		crypto_unregister_alg(&tea_alg);
-		goto out;
-	}
-
-	ret = crypto_register_alg(&xeta_alg);
-	if (ret < 0) {
-		crypto_unregister_alg(&tea_alg);
-		crypto_unregister_alg(&xtea_alg);
-		goto out;
-	}
-
-out:	
-	return ret;
+	return crypto_register_algs(tea_algs, ARRAY_SIZE(tea_algs));
 }
 
 static void __exit tea_mod_fini(void)
 {
-	crypto_unregister_alg(&tea_alg);
-	crypto_unregister_alg(&xtea_alg);
-	crypto_unregister_alg(&xeta_alg);
+	crypto_unregister_algs(tea_algs, ARRAY_SIZE(tea_algs));
 }
 
 MODULE_ALIAS("xtea");
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index a2ca743..575b57c 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -1534,6 +1534,36 @@ static int alg_test_null(const struct alg_test_desc *desc,
 /* Please keep this list sorted by algorithm name. */
 static const struct alg_test_desc alg_test_descs[] = {
 	{
+		.alg = "__cbc-cast5-avx",
+		.test = alg_test_null,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = NULL,
+					.count = 0
+				},
+				.dec = {
+					.vecs = NULL,
+					.count = 0
+				}
+			}
+		}
+	}, {
+		.alg = "__cbc-cast6-avx",
+		.test = alg_test_null,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = NULL,
+					.count = 0
+				},
+				.dec = {
+					.vecs = NULL,
+					.count = 0
+				}
+			}
+		}
+	}, {
 		.alg = "__cbc-serpent-avx",
 		.test = alg_test_null,
 		.suite = {
@@ -1595,6 +1625,36 @@ static const struct alg_test_desc alg_test_descs[] = {
 			}
 		}
 	}, {
+		.alg = "__driver-cbc-cast5-avx",
+		.test = alg_test_null,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = NULL,
+					.count = 0
+				},
+				.dec = {
+					.vecs = NULL,
+					.count = 0
+				}
+			}
+		}
+	}, {
+		.alg = "__driver-cbc-cast6-avx",
+		.test = alg_test_null,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = NULL,
+					.count = 0
+				},
+				.dec = {
+					.vecs = NULL,
+					.count = 0
+				}
+			}
+		}
+	}, {
 		.alg = "__driver-cbc-serpent-avx",
 		.test = alg_test_null,
 		.suite = {
@@ -1656,6 +1716,36 @@ static const struct alg_test_desc alg_test_descs[] = {
 			}
 		}
 	}, {
+		.alg = "__driver-ecb-cast5-avx",
+		.test = alg_test_null,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = NULL,
+					.count = 0
+				},
+				.dec = {
+					.vecs = NULL,
+					.count = 0
+				}
+			}
+		}
+	}, {
+		.alg = "__driver-ecb-cast6-avx",
+		.test = alg_test_null,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = NULL,
+					.count = 0
+				},
+				.dec = {
+					.vecs = NULL,
+					.count = 0
+				}
+			}
+		}
+	}, {
 		.alg = "__driver-ecb-serpent-avx",
 		.test = alg_test_null,
 		.suite = {
@@ -1818,6 +1908,36 @@ static const struct alg_test_desc alg_test_descs[] = {
 			}
 		}
 	}, {
+		.alg = "cbc(cast5)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = cast5_cbc_enc_tv_template,
+					.count = CAST5_CBC_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = cast5_cbc_dec_tv_template,
+					.count = CAST5_CBC_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "cbc(cast6)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = cast6_cbc_enc_tv_template,
+					.count = CAST6_CBC_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = cast6_cbc_dec_tv_template,
+					.count = CAST6_CBC_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
 		.alg = "cbc(des)",
 		.test = alg_test_skcipher,
 		.suite = {
@@ -1937,6 +2057,36 @@ static const struct alg_test_desc alg_test_descs[] = {
 			}
 		}
 	}, {
+		.alg = "cryptd(__driver-ecb-cast5-avx)",
+		.test = alg_test_null,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = NULL,
+					.count = 0
+				},
+				.dec = {
+					.vecs = NULL,
+					.count = 0
+				}
+			}
+		}
+	}, {
+		.alg = "cryptd(__driver-ecb-cast6-avx)",
+		.test = alg_test_null,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = NULL,
+					.count = 0
+				},
+				.dec = {
+					.vecs = NULL,
+					.count = 0
+				}
+			}
+		}
+	}, {
 		.alg = "cryptd(__driver-ecb-serpent-avx)",
 		.test = alg_test_null,
 		.suite = {
@@ -2054,6 +2204,36 @@ static const struct alg_test_desc alg_test_descs[] = {
 			}
 		}
 	}, {
+		.alg = "ctr(cast5)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = cast5_ctr_enc_tv_template,
+					.count = CAST5_CTR_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = cast5_ctr_dec_tv_template,
+					.count = CAST5_CTR_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "ctr(cast6)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = cast6_ctr_enc_tv_template,
+					.count = CAST6_CTR_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = cast6_ctr_dec_tv_template,
+					.count = CAST6_CTR_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
 		.alg = "ctr(serpent)",
 		.test = alg_test_skcipher,
 		.suite = {
@@ -2530,6 +2710,21 @@ static const struct alg_test_desc alg_test_descs[] = {
 			}
 		}
 	}, {
+		.alg = "lrw(cast6)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = cast6_lrw_enc_tv_template,
+					.count = CAST6_LRW_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = cast6_lrw_dec_tv_template,
+					.count = CAST6_LRW_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
 		.alg = "lrw(serpent)",
 		.test = alg_test_skcipher,
 		.suite = {
@@ -2882,6 +3077,21 @@ static const struct alg_test_desc alg_test_descs[] = {
 			}
 		}
 	}, {
+		.alg = "xts(cast6)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = cast6_xts_enc_tv_template,
+					.count = CAST6_XTS_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = cast6_xts_dec_tv_template,
+					.count = CAST6_XTS_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
 		.alg = "xts(serpent)",
 		.test = alg_test_skcipher,
 		.suite = {
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index f8179e0..6eb3ef5 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -6896,8 +6896,16 @@ static struct cipher_testvec serpent_xts_dec_tv_template[] = {
 };
 
 /* Cast6 test vectors from RFC 2612 */
-#define CAST6_ENC_TEST_VECTORS	3
-#define CAST6_DEC_TEST_VECTORS  3
+#define CAST6_ENC_TEST_VECTORS		4
+#define CAST6_DEC_TEST_VECTORS		4
+#define CAST6_CBC_ENC_TEST_VECTORS	1
+#define CAST6_CBC_DEC_TEST_VECTORS	1
+#define CAST6_CTR_ENC_TEST_VECTORS	1
+#define CAST6_CTR_DEC_TEST_VECTORS	1
+#define CAST6_LRW_ENC_TEST_VECTORS	1
+#define CAST6_LRW_DEC_TEST_VECTORS	1
+#define CAST6_XTS_ENC_TEST_VECTORS	1
+#define CAST6_XTS_DEC_TEST_VECTORS	1
 
 static struct cipher_testvec cast6_enc_tv_template[] = {
 	{
@@ -6930,6 +6938,140 @@ static struct cipher_testvec cast6_enc_tv_template[] = {
 		.result	= "\x4f\x6a\x20\x38\x28\x68\x97\xb9"
 			  "\xc9\x87\x01\x36\x55\x33\x17\xfa",
 		.rlen	= 16,
+	}, { /* Generated from TF test vectors */
+		.key	= "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+			  "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+			  "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+			  "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+		.klen	= 32,
+		.iv	= "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+			  "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+		.input	= "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+			  "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+			  "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+			  "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.ilen	= 496,
+		.result	= "\xC3\x70\x22\x32\xF5\x80\xCB\x54"
+			  "\xFC\x30\xE0\xF6\xEB\x39\x57\xA6"
+			  "\xB6\xB9\xC5\xA4\x91\x55\x14\x97"
+			  "\xC1\x20\xFF\x6C\x5C\xF0\x67\xEA"
+			  "\x2F\xED\xD8\xC9\xFB\x38\x3F\xFE"
+			  "\x93\xBE\xDC\x00\xD3\x7F\xAD\x4C"
+			  "\x5A\x08\x92\xD1\x47\x0C\xFA\x6C"
+			  "\xD0\x6A\x99\x10\x72\xF8\x47\x62"
+			  "\x81\x42\xF8\xD8\xF5\xBB\x94\x08"
+			  "\xAA\x97\xA2\x8B\x69\xB3\xD2\x7E"
+			  "\xBC\xB5\x00\x0C\xE5\x44\x4B\x58"
+			  "\xE8\x63\xDC\xB3\xC4\xE5\x23\x12"
+			  "\x5A\x72\x85\x47\x8B\xEC\x9F\x26"
+			  "\x84\xB6\xED\x10\x33\x63\x9B\x5F"
+			  "\x4D\x53\xEE\x94\x45\x8B\x60\x58"
+			  "\x86\x20\xF9\x1E\x82\x08\x3E\x58"
+			  "\x60\x1B\x34\x19\x02\xBE\x4E\x09"
+			  "\xBB\x7C\x15\xCC\x60\x27\x55\x7A"
+			  "\x12\xB8\xD8\x08\x89\x3C\xA6\xF3"
+			  "\xF1\xDD\xA7\x07\xA3\x12\x85\x28"
+			  "\xE9\x57\xAC\x80\x0C\x5C\x0F\x3A"
+			  "\x5D\xC2\x91\xC7\x90\xE4\x8C\x43"
+			  "\x92\xE4\x7C\x26\x69\x4D\x83\x68"
+			  "\x14\x96\x42\x47\xBD\xA9\xE4\x8A"
+			  "\x33\x19\xEB\x54\x8E\x0D\x4B\x6E"
+			  "\x91\x51\xB5\x36\x08\xDE\x1C\x06"
+			  "\x03\xBD\xDE\x81\x26\xF7\x99\xC2"
+			  "\xBA\xF7\x6D\x87\x0D\xE4\xA6\xCF"
+			  "\xC1\xF5\x27\x05\xB8\x02\x57\x72"
+			  "\xE6\x42\x13\x0B\xC6\x47\x05\x74"
+			  "\x24\x15\xF7\x0D\xC2\x23\x9D\xB9"
+			  "\x3C\x77\x18\x93\xBA\xB4\xFC\x8C"
+			  "\x98\x82\x67\x67\xB4\xD7\xD3\x43"
+			  "\x23\x08\x02\xB7\x9B\x99\x05\xFB"
+			  "\xD3\xB5\x00\x0A\xA9\x9D\x66\xD6"
+			  "\x2E\x49\x58\xD0\xA8\x57\x29\x7F"
+			  "\x0A\x0E\x7D\xFC\x92\x83\xCC\x67"
+			  "\xA2\xB1\x70\x3A\x8F\x87\x4A\x8D"
+			  "\x17\xE2\x58\x2B\x88\x0D\x68\x62"
+			  "\xBF\x35\xD1\x6F\xC0\xF0\x18\x62"
+			  "\xB2\xC7\x2D\x58\xC7\x16\xDE\x08"
+			  "\xEB\x84\x1D\x25\xA7\x38\x94\x06"
+			  "\x93\x9D\xF8\xFE\x88\x71\xE7\x84"
+			  "\x2C\xA0\x38\xA3\x1D\x48\xCF\x29"
+			  "\x0B\xBC\xD8\x50\x99\x1A\x26\xFB"
+			  "\x8E\x75\x3D\x73\xEB\x6A\xED\x29"
+			  "\xE0\x8E\xED\xFC\xFE\x6F\xF6\xBA"
+			  "\x41\xE2\x10\x4C\x01\x8B\x69\x2B"
+			  "\x25\x3F\x4D\x70\x7B\x92\xD6\x3B"
+			  "\xAC\xF9\x77\x18\xD9\x6A\x30\xA6"
+			  "\x2E\xFA\x30\xFF\xC8\xD5\x1D\x06"
+			  "\x59\x28\x1D\x86\x43\x04\x5D\x3B"
+			  "\x99\x4C\x04\x5A\x21\x17\x8B\x76"
+			  "\x8F\x72\xCB\xA1\x9C\x29\x4C\xC3"
+			  "\x65\xA2\x58\x2A\xC5\x66\x24\xBF"
+			  "\xBA\xE6\x0C\xDD\x34\x24\x74\xC8"
+			  "\x84\x0A\x66\x2C\xBE\x8F\x32\xA9"
+			  "\xE7\xE4\xA1\xD7\xDA\xAB\x23\x1E"
+			  "\xEB\xEE\x6C\x94\x6F\x9C\x2E\xD1"
+			  "\x49\x2C\xF3\xD4\x90\xCC\x93\x4C"
+			  "\x84\x52\x6D\x68\xDE\xC6\x64\xB2"
+			  "\x11\x74\x93\x57\xB4\x7E\xC6\x00",
+		.rlen	= 496,
 	},
 };
 
@@ -6964,122 +7106,1388 @@ static struct cipher_testvec cast6_dec_tv_template[] = {
 		.ilen	= 16,
 		.result	= zeroed_string,
 		.rlen	= 16,
-	},
-};
-
-
-/*
- * AES test vectors.
- */
-#define AES_ENC_TEST_VECTORS 3
-#define AES_DEC_TEST_VECTORS 3
-#define AES_CBC_ENC_TEST_VECTORS 4
-#define AES_CBC_DEC_TEST_VECTORS 4
-#define HMAC_SHA1_AES_CBC_ENC_TEST_VECTORS 7
-#define HMAC_SHA256_AES_CBC_ENC_TEST_VECTORS 7
-#define HMAC_SHA512_AES_CBC_ENC_TEST_VECTORS 7
-#define AES_LRW_ENC_TEST_VECTORS 8
-#define AES_LRW_DEC_TEST_VECTORS 8
-#define AES_XTS_ENC_TEST_VECTORS 5
-#define AES_XTS_DEC_TEST_VECTORS 5
-#define AES_CTR_ENC_TEST_VECTORS 3
-#define AES_CTR_DEC_TEST_VECTORS 3
-#define AES_OFB_ENC_TEST_VECTORS 1
-#define AES_OFB_DEC_TEST_VECTORS 1
-#define AES_CTR_3686_ENC_TEST_VECTORS 7
-#define AES_CTR_3686_DEC_TEST_VECTORS 6
-#define AES_GCM_ENC_TEST_VECTORS 9
-#define AES_GCM_DEC_TEST_VECTORS 8
-#define AES_GCM_4106_ENC_TEST_VECTORS 7
-#define AES_GCM_4106_DEC_TEST_VECTORS 7
-#define AES_CCM_ENC_TEST_VECTORS 7
-#define AES_CCM_DEC_TEST_VECTORS 7
-#define AES_CCM_4309_ENC_TEST_VECTORS 7
-#define AES_CCM_4309_DEC_TEST_VECTORS 10
-
-static struct cipher_testvec aes_enc_tv_template[] = {
-	{ /* From FIPS-197 */
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.klen	= 16,
-		.input	= "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-		.ilen	= 16,
-		.result	= "\x69\xc4\xe0\xd8\x6a\x7b\x04\x30"
-			  "\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17",
-		.klen	= 24,
-		.input	= "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-		.ilen	= 16,
-		.result	= "\xdd\xa9\x7c\xa4\x86\x4c\xdf\xe0"
-			  "\x6e\xaf\x70\xa0\xec\x0d\x71\x91",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+	}, { /* Generated from TF test vectors */
+		.key	= "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+			  "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+			  "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+			  "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
 		.klen	= 32,
-		.input	= "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-		.ilen	= 16,
-		.result	= "\x8e\xa2\xb7\xca\x51\x67\x45\xbf"
-			  "\xea\xfc\x49\x90\x4b\x49\x60\x89",
-		.rlen	= 16,
+		.iv	= "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+			  "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+		.input	= "\xC3\x70\x22\x32\xF5\x80\xCB\x54"
+			  "\xFC\x30\xE0\xF6\xEB\x39\x57\xA6"
+			  "\xB6\xB9\xC5\xA4\x91\x55\x14\x97"
+			  "\xC1\x20\xFF\x6C\x5C\xF0\x67\xEA"
+			  "\x2F\xED\xD8\xC9\xFB\x38\x3F\xFE"
+			  "\x93\xBE\xDC\x00\xD3\x7F\xAD\x4C"
+			  "\x5A\x08\x92\xD1\x47\x0C\xFA\x6C"
+			  "\xD0\x6A\x99\x10\x72\xF8\x47\x62"
+			  "\x81\x42\xF8\xD8\xF5\xBB\x94\x08"
+			  "\xAA\x97\xA2\x8B\x69\xB3\xD2\x7E"
+			  "\xBC\xB5\x00\x0C\xE5\x44\x4B\x58"
+			  "\xE8\x63\xDC\xB3\xC4\xE5\x23\x12"
+			  "\x5A\x72\x85\x47\x8B\xEC\x9F\x26"
+			  "\x84\xB6\xED\x10\x33\x63\x9B\x5F"
+			  "\x4D\x53\xEE\x94\x45\x8B\x60\x58"
+			  "\x86\x20\xF9\x1E\x82\x08\x3E\x58"
+			  "\x60\x1B\x34\x19\x02\xBE\x4E\x09"
+			  "\xBB\x7C\x15\xCC\x60\x27\x55\x7A"
+			  "\x12\xB8\xD8\x08\x89\x3C\xA6\xF3"
+			  "\xF1\xDD\xA7\x07\xA3\x12\x85\x28"
+			  "\xE9\x57\xAC\x80\x0C\x5C\x0F\x3A"
+			  "\x5D\xC2\x91\xC7\x90\xE4\x8C\x43"
+			  "\x92\xE4\x7C\x26\x69\x4D\x83\x68"
+			  "\x14\x96\x42\x47\xBD\xA9\xE4\x8A"
+			  "\x33\x19\xEB\x54\x8E\x0D\x4B\x6E"
+			  "\x91\x51\xB5\x36\x08\xDE\x1C\x06"
+			  "\x03\xBD\xDE\x81\x26\xF7\x99\xC2"
+			  "\xBA\xF7\x6D\x87\x0D\xE4\xA6\xCF"
+			  "\xC1\xF5\x27\x05\xB8\x02\x57\x72"
+			  "\xE6\x42\x13\x0B\xC6\x47\x05\x74"
+			  "\x24\x15\xF7\x0D\xC2\x23\x9D\xB9"
+			  "\x3C\x77\x18\x93\xBA\xB4\xFC\x8C"
+			  "\x98\x82\x67\x67\xB4\xD7\xD3\x43"
+			  "\x23\x08\x02\xB7\x9B\x99\x05\xFB"
+			  "\xD3\xB5\x00\x0A\xA9\x9D\x66\xD6"
+			  "\x2E\x49\x58\xD0\xA8\x57\x29\x7F"
+			  "\x0A\x0E\x7D\xFC\x92\x83\xCC\x67"
+			  "\xA2\xB1\x70\x3A\x8F\x87\x4A\x8D"
+			  "\x17\xE2\x58\x2B\x88\x0D\x68\x62"
+			  "\xBF\x35\xD1\x6F\xC0\xF0\x18\x62"
+			  "\xB2\xC7\x2D\x58\xC7\x16\xDE\x08"
+			  "\xEB\x84\x1D\x25\xA7\x38\x94\x06"
+			  "\x93\x9D\xF8\xFE\x88\x71\xE7\x84"
+			  "\x2C\xA0\x38\xA3\x1D\x48\xCF\x29"
+			  "\x0B\xBC\xD8\x50\x99\x1A\x26\xFB"
+			  "\x8E\x75\x3D\x73\xEB\x6A\xED\x29"
+			  "\xE0\x8E\xED\xFC\xFE\x6F\xF6\xBA"
+			  "\x41\xE2\x10\x4C\x01\x8B\x69\x2B"
+			  "\x25\x3F\x4D\x70\x7B\x92\xD6\x3B"
+			  "\xAC\xF9\x77\x18\xD9\x6A\x30\xA6"
+			  "\x2E\xFA\x30\xFF\xC8\xD5\x1D\x06"
+			  "\x59\x28\x1D\x86\x43\x04\x5D\x3B"
+			  "\x99\x4C\x04\x5A\x21\x17\x8B\x76"
+			  "\x8F\x72\xCB\xA1\x9C\x29\x4C\xC3"
+			  "\x65\xA2\x58\x2A\xC5\x66\x24\xBF"
+			  "\xBA\xE6\x0C\xDD\x34\x24\x74\xC8"
+			  "\x84\x0A\x66\x2C\xBE\x8F\x32\xA9"
+			  "\xE7\xE4\xA1\xD7\xDA\xAB\x23\x1E"
+			  "\xEB\xEE\x6C\x94\x6F\x9C\x2E\xD1"
+			  "\x49\x2C\xF3\xD4\x90\xCC\x93\x4C"
+			  "\x84\x52\x6D\x68\xDE\xC6\x64\xB2"
+			  "\x11\x74\x93\x57\xB4\x7E\xC6\x00",
+		.ilen	= 496,
+		.result	= "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+			  "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+			  "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+			  "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.rlen	= 496,
 	},
 };
 
-static struct cipher_testvec aes_dec_tv_template[] = {
-	{ /* From FIPS-197 */
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-		.klen	= 16,
-		.input	= "\x69\xc4\xe0\xd8\x6a\x7b\x04\x30"
-			  "\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a",
-		.ilen	= 16,
-		.result	= "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17",
-		.klen	= 24,
-		.input	= "\xdd\xa9\x7c\xa4\x86\x4c\xdf\xe0"
-			  "\x6e\xaf\x70\xa0\xec\x0d\x71\x91",
-		.ilen	= 16,
-		.result	= "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-		.rlen	= 16,
-	}, {
-		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
-			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			  "\x10\x11\x12\x13\x14\x15\x16\x17"
-			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+static struct cipher_testvec cast6_cbc_enc_tv_template[] = {
+	{ /* Generated from TF test vectors */
+		.key	= "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+			  "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+			  "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+			  "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
 		.klen	= 32,
-		.input	= "\x8e\xa2\xb7\xca\x51\x67\x45\xbf"
-			  "\xea\xfc\x49\x90\x4b\x49\x60\x89",
-		.ilen	= 16,
-		.result	= "\x00\x11\x22\x33\x44\x55\x66\x77"
-			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-		.rlen	= 16,
-	},
-};
-
-static struct cipher_testvec aes_cbc_enc_tv_template[] = {
-	{ /* From RFC 3602 */
-		.key    = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
-			  "\x51\x2e\x03\xd5\x34\x12\x00\x06",
-		.klen   = 16,
-		.iv	= "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
-			  "\xb4\x22\xda\x80\x2c\x9f\xac\x41",
-		.input	= "Single block msg",
-		.ilen   = 16,
+		.iv	= "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+			  "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+		.input	= "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+			  "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+			  "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+			  "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.ilen	= 496,
+		.result	= "\xDF\x77\x68\x96\xC7\xBA\xF8\xE2"
+			  "\x0E\x24\x99\x1A\xAA\xF3\xC6\x9F"
+			  "\xA0\x73\xB3\x70\xC3\x68\x64\x70"
+			  "\xAD\x33\x02\xFB\x88\x74\xAA\x78"
+			  "\xC7\x47\x1A\x18\x61\x2D\xAC\x9F"
+			  "\x7E\x6F\xDF\x05\x13\x76\xA6\x72"
+			  "\xB7\x13\x09\x0F\x7D\x38\xDF\x25"
+			  "\x4E\xFD\x50\x45\xFA\x35\x6A\xC0"
+			  "\x57\x95\xE1\x21\x26\x10\x9A\x21"
+			  "\xA1\x8A\x51\x05\xD1\xB1\x78\x35"
+			  "\x98\xF5\xAE\xC0\xC1\x8B\x94\xFF"
+			  "\xD0\x69\x3F\x42\xC2\x01\xA7\x9B"
+			  "\x23\x16\x47\x72\x81\x13\x3A\x72"
+			  "\xEC\xD9\x40\x88\x00\x9C\xB0\xA8"
+			  "\x9C\xAC\xCE\x11\x73\x7B\x63\x3E"
+			  "\xA3\x63\x98\x7D\x35\xE4\xD9\x83"
+			  "\xE2\xD0\x52\x87\x0C\x1F\xB0\xB3"
+			  "\x41\x1A\x93\x8D\x76\x31\x9F\xF2"
+			  "\xFE\x09\xA3\x8F\x22\x6A\x3B\xB9"
+			  "\x6C\x9E\xE4\xA1\xA0\xC4\xE7\xA1"
+			  "\x21\x9C\x1A\xCA\x65\xDE\x44\x03"
+			  "\x99\xF2\xD2\x39\xE3\x3F\x0F\x37"
+			  "\x53\x50\x23\xA4\x81\x6E\xDA\xFB"
+			  "\xF8\x7B\x01\xD7\xB2\x32\x9C\xB8"
+			  "\xB1\x0E\x99\x17\xB5\x38\xF9\xD7"
+			  "\x86\x2D\x6E\x94\x5C\x99\x9D\xB3"
+			  "\xD3\x63\x4B\x2A\x7D\x44\x6A\xB2"
+			  "\xC1\x03\xE6\x5A\x37\xD8\x64\x18"
+			  "\xAA\x32\xCE\x29\xED\xC0\xA2\xCB"
+			  "\x8D\xAF\xCD\xBE\x8F\xB6\xEC\xB4"
+			  "\x89\x05\x81\x6E\x71\x4F\xC3\x28"
+			  "\x10\xC1\x62\xC4\x41\xE9\xD2\x39"
+			  "\xF3\x22\x39\x12\x2C\xC2\x95\x2D"
+			  "\xBF\x93\x58\x4B\x04\xD1\x8D\x57"
+			  "\xAE\xEB\x60\x03\x56\x35\xAD\x5A"
+			  "\xE9\xC3\xFF\x4E\x31\xE1\x37\xF8"
+			  "\x7D\xEE\x65\x8A\xB6\x88\x1A\x3E"
+			  "\x07\x09\x82\xBA\xF0\x80\x8A\xD0"
+			  "\xA0\x3F\x6A\xE9\x24\x87\x19\x65"
+			  "\x73\x3F\x12\x91\x47\x54\xBA\x39"
+			  "\x30\x5B\x1E\xE5\xC2\xF9\x3F\xEF"
+			  "\xD6\x75\xF9\xB8\x7C\x8B\x05\x76"
+			  "\xEE\xB7\x08\x25\x4B\xB6\x7B\x47"
+			  "\x72\xC0\x4C\xD4\xDA\xE0\x75\xF1"
+			  "\x7C\xE8\x94\x9E\x16\x6E\xB8\x12"
+			  "\xA1\xC1\x6E\x3B\x1C\x59\x41\x2D"
+			  "\x23\xFA\x7D\x77\xB8\x46\x75\xFE"
+			  "\x4F\x10\xD3\x09\x60\xA1\x36\x96"
+			  "\x5B\xC2\xDC\x6E\x84\x7D\x9B\x14"
+			  "\x80\x21\x83\x58\x3C\x76\xFD\x28"
+			  "\x1D\xF9\x93\x13\xD7\x0E\x62\x14"
+			  "\x5A\xC5\x4E\x08\xA5\x56\xA4\x3C"
+			  "\x68\x93\x44\x70\xDF\xCF\x4A\x51"
+			  "\x0B\x81\x29\x41\xE5\x62\x4D\x36"
+			  "\xB3\xEA\x94\xA6\xB9\xDD\x3F\x09"
+			  "\x62\x34\xA0\x6A\x7E\x7D\xF5\xF6"
+			  "\x01\x91\xB4\x27\xDA\x59\xD6\x17"
+			  "\x56\x4D\x82\x62\x37\xA3\x48\x01"
+			  "\x99\x91\x77\xB2\x08\x6B\x2C\x37"
+			  "\xC5\x5C\xAD\xB6\x07\xB6\x84\xF3"
+			  "\x4D\x59\x7D\xC5\x28\x69\xFA\x92"
+			  "\x22\x46\x89\x2D\x0F\x2B\x08\x24",
+		.rlen	= 496,
+	},
+};
+
+static struct cipher_testvec cast6_cbc_dec_tv_template[] = {
+	{ /* Generated from TF test vectors */
+		.key	= "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+			  "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+			  "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+			  "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+		.klen	= 32,
+		.iv	= "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+			  "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+		.input	= "\xDF\x77\x68\x96\xC7\xBA\xF8\xE2"
+			  "\x0E\x24\x99\x1A\xAA\xF3\xC6\x9F"
+			  "\xA0\x73\xB3\x70\xC3\x68\x64\x70"
+			  "\xAD\x33\x02\xFB\x88\x74\xAA\x78"
+			  "\xC7\x47\x1A\x18\x61\x2D\xAC\x9F"
+			  "\x7E\x6F\xDF\x05\x13\x76\xA6\x72"
+			  "\xB7\x13\x09\x0F\x7D\x38\xDF\x25"
+			  "\x4E\xFD\x50\x45\xFA\x35\x6A\xC0"
+			  "\x57\x95\xE1\x21\x26\x10\x9A\x21"
+			  "\xA1\x8A\x51\x05\xD1\xB1\x78\x35"
+			  "\x98\xF5\xAE\xC0\xC1\x8B\x94\xFF"
+			  "\xD0\x69\x3F\x42\xC2\x01\xA7\x9B"
+			  "\x23\x16\x47\x72\x81\x13\x3A\x72"
+			  "\xEC\xD9\x40\x88\x00\x9C\xB0\xA8"
+			  "\x9C\xAC\xCE\x11\x73\x7B\x63\x3E"
+			  "\xA3\x63\x98\x7D\x35\xE4\xD9\x83"
+			  "\xE2\xD0\x52\x87\x0C\x1F\xB0\xB3"
+			  "\x41\x1A\x93\x8D\x76\x31\x9F\xF2"
+			  "\xFE\x09\xA3\x8F\x22\x6A\x3B\xB9"
+			  "\x6C\x9E\xE4\xA1\xA0\xC4\xE7\xA1"
+			  "\x21\x9C\x1A\xCA\x65\xDE\x44\x03"
+			  "\x99\xF2\xD2\x39\xE3\x3F\x0F\x37"
+			  "\x53\x50\x23\xA4\x81\x6E\xDA\xFB"
+			  "\xF8\x7B\x01\xD7\xB2\x32\x9C\xB8"
+			  "\xB1\x0E\x99\x17\xB5\x38\xF9\xD7"
+			  "\x86\x2D\x6E\x94\x5C\x99\x9D\xB3"
+			  "\xD3\x63\x4B\x2A\x7D\x44\x6A\xB2"
+			  "\xC1\x03\xE6\x5A\x37\xD8\x64\x18"
+			  "\xAA\x32\xCE\x29\xED\xC0\xA2\xCB"
+			  "\x8D\xAF\xCD\xBE\x8F\xB6\xEC\xB4"
+			  "\x89\x05\x81\x6E\x71\x4F\xC3\x28"
+			  "\x10\xC1\x62\xC4\x41\xE9\xD2\x39"
+			  "\xF3\x22\x39\x12\x2C\xC2\x95\x2D"
+			  "\xBF\x93\x58\x4B\x04\xD1\x8D\x57"
+			  "\xAE\xEB\x60\x03\x56\x35\xAD\x5A"
+			  "\xE9\xC3\xFF\x4E\x31\xE1\x37\xF8"
+			  "\x7D\xEE\x65\x8A\xB6\x88\x1A\x3E"
+			  "\x07\x09\x82\xBA\xF0\x80\x8A\xD0"
+			  "\xA0\x3F\x6A\xE9\x24\x87\x19\x65"
+			  "\x73\x3F\x12\x91\x47\x54\xBA\x39"
+			  "\x30\x5B\x1E\xE5\xC2\xF9\x3F\xEF"
+			  "\xD6\x75\xF9\xB8\x7C\x8B\x05\x76"
+			  "\xEE\xB7\x08\x25\x4B\xB6\x7B\x47"
+			  "\x72\xC0\x4C\xD4\xDA\xE0\x75\xF1"
+			  "\x7C\xE8\x94\x9E\x16\x6E\xB8\x12"
+			  "\xA1\xC1\x6E\x3B\x1C\x59\x41\x2D"
+			  "\x23\xFA\x7D\x77\xB8\x46\x75\xFE"
+			  "\x4F\x10\xD3\x09\x60\xA1\x36\x96"
+			  "\x5B\xC2\xDC\x6E\x84\x7D\x9B\x14"
+			  "\x80\x21\x83\x58\x3C\x76\xFD\x28"
+			  "\x1D\xF9\x93\x13\xD7\x0E\x62\x14"
+			  "\x5A\xC5\x4E\x08\xA5\x56\xA4\x3C"
+			  "\x68\x93\x44\x70\xDF\xCF\x4A\x51"
+			  "\x0B\x81\x29\x41\xE5\x62\x4D\x36"
+			  "\xB3\xEA\x94\xA6\xB9\xDD\x3F\x09"
+			  "\x62\x34\xA0\x6A\x7E\x7D\xF5\xF6"
+			  "\x01\x91\xB4\x27\xDA\x59\xD6\x17"
+			  "\x56\x4D\x82\x62\x37\xA3\x48\x01"
+			  "\x99\x91\x77\xB2\x08\x6B\x2C\x37"
+			  "\xC5\x5C\xAD\xB6\x07\xB6\x84\xF3"
+			  "\x4D\x59\x7D\xC5\x28\x69\xFA\x92"
+			  "\x22\x46\x89\x2D\x0F\x2B\x08\x24",
+		.ilen	= 496,
+		.result	= "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+			  "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+			  "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+			  "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.rlen	= 496,
+	},
+};
+
+static struct cipher_testvec cast6_ctr_enc_tv_template[] = {
+	{ /* Generated from TF test vectors */
+		.key	= "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+			  "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+			  "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+			  "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+		.klen	= 32,
+		.iv	= "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+			  "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+		.input	= "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+			  "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+			  "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+			  "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.ilen	= 496,
+		.result	= "\x26\x0A\xF1\xE2\x3F\x8A\xEF\xA3"
+			  "\x53\x9A\x5E\x1B\x2A\x1A\xC6\x0A"
+			  "\x57\xA3\xEF\x47\x2A\xE8\x88\xA7"
+			  "\x3C\xD0\xEC\xB9\x94\x50\x7D\x56"
+			  "\xBC\xE1\xC1\xF5\xE1\xEE\x12\xF8"
+			  "\x4F\x03\x82\x3A\x93\x6B\x4C\xD3"
+			  "\xE3\xF3\xFA\xC2\x23\x55\x98\x20"
+			  "\x49\x76\x9B\x6B\xC1\x23\xBF\xE5"
+			  "\xD4\xC4\x2F\x61\xE1\x67\x2A\x30"
+			  "\x6F\x29\xCA\x54\xF8\x1B\xA6\x7D"
+			  "\x66\x45\xEE\xC8\x19\xBE\x50\xF0"
+			  "\x5F\x65\xF8\x1E\x4D\x07\x87\xD9"
+			  "\xD3\xD9\x1B\x09\x89\xFD\x42\xC5"
+			  "\xDB\xEB\x86\xF1\x67\x04\x0F\x5C"
+			  "\x81\xDF\x82\x12\xC7\x4C\x1B\x07"
+			  "\xDE\xE6\xFA\x29\x86\xD1\xB0\xBA"
+			  "\x3D\x6A\x69\x76\xEC\x0F\xB4\xE6"
+			  "\xCD\xA7\xF8\xA8\xB8\xE0\x33\xF5"
+			  "\x49\x61\x22\x52\x64\x8C\x46\x41"
+			  "\x1F\x48\x5F\x4F\xA2\x89\x36\x17"
+			  "\x20\xF8\x2F\x8F\x4B\xFA\xF2\xC0"
+			  "\x1E\x18\xA2\xF8\xB7\x6D\x98\xE3"
+			  "\x00\x14\x15\x59\xC1\x30\x64\xAF"
+			  "\xA8\x01\x38\xAB\xD4\x8B\xEC\x7C"
+			  "\x44\x9A\xC6\x2C\x2E\x2B\x2B\xF4"
+			  "\x02\x37\xC4\x69\xEF\x36\xC1\xF3"
+			  "\xA0\xFB\xFE\x29\xAD\x39\xCF\xD0"
+			  "\x51\x73\xA3\x22\x42\x41\xAB\xD2"
+			  "\x0F\x50\x14\xB9\x54\xD3\xD4\xFA"
+			  "\xBF\xC9\xBB\xCE\xC4\x1D\x2D\xAF"
+			  "\xC9\x3F\x07\x87\x42\x4B\x3A\x54"
+			  "\x34\x8E\x37\xA3\x03\x6F\x65\x66"
+			  "\xDB\x44\xC3\xE8\xD7\xDD\x7D\xDD"
+			  "\x61\xB4\x2B\x80\xA3\x98\x13\xF5"
+			  "\x5A\xD3\x34\x58\xC3\x6E\xF6\xB8"
+			  "\x0A\xC6\x50\x01\x8E\xD5\x6C\x7D"
+			  "\xFE\x16\xB6\xCF\xFC\x51\x40\xAE"
+			  "\xB3\x15\xAC\x90\x6F\x0B\x28\x3A"
+			  "\x60\x40\x38\x90\x20\x46\xC7\xB3"
+			  "\x0B\x12\x6D\x3B\x15\x14\xF9\xF4"
+			  "\x11\x41\x76\x6B\xB3\x60\x82\x3C"
+			  "\x84\xFB\x08\x2E\x92\x25\xCB\x79"
+			  "\x6F\x58\xC5\x94\x00\x00\x47\xB6"
+			  "\x9E\xDC\x0F\x29\x70\x46\x20\x76"
+			  "\x65\x75\x66\x5C\x00\x96\xB3\xE1"
+			  "\x0B\xA7\x11\x8B\x2E\x61\x4E\x45"
+			  "\x73\xFC\x91\xAB\x79\x41\x23\x14"
+			  "\x13\xB6\x72\x6C\x46\xB3\x03\x11"
+			  "\xE4\xF1\xEE\xC9\x7A\xCF\x96\x32"
+			  "\xB6\xF0\x8B\x97\xB4\xCF\x82\xB7"
+			  "\x15\x48\x44\x99\x09\xF6\xE0\xD7"
+			  "\xBC\xF1\x5B\x91\x4F\x30\x22\xA2"
+			  "\x45\xC4\x68\x55\xC2\xBE\xA7\xD2"
+			  "\x12\x53\x35\x9C\xF9\xE7\x35\x5D"
+			  "\x81\xE4\x86\x42\xC3\x58\xFB\xF0"
+			  "\x38\x9B\x8E\x5A\xEF\x83\x33\x0F"
+			  "\x00\x4E\x3F\x9F\xF5\x84\x62\xC4"
+			  "\x19\x35\x88\x22\x45\x59\x0E\x8F"
+			  "\xEC\x27\xDD\x4A\xA4\x1F\xBC\x41"
+			  "\x9B\x66\x8D\x32\xBA\x81\x34\x87"
+			  "\x0E\x74\x33\x30\x62\xB9\x89\xDF"
+			  "\xF9\xC5\xDD\x27\xB3\x39\xCB\xCB",
+		.rlen	= 496,
+	},
+};
+
+static struct cipher_testvec cast6_ctr_dec_tv_template[] = {
+	{ /* Generated from TF test vectors */
+		.key	= "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+			  "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+			  "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+			  "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+		.klen	= 32,
+		.iv	= "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+			  "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+		.input	= "\x26\x0A\xF1\xE2\x3F\x8A\xEF\xA3"
+			  "\x53\x9A\x5E\x1B\x2A\x1A\xC6\x0A"
+			  "\x57\xA3\xEF\x47\x2A\xE8\x88\xA7"
+			  "\x3C\xD0\xEC\xB9\x94\x50\x7D\x56"
+			  "\xBC\xE1\xC1\xF5\xE1\xEE\x12\xF8"
+			  "\x4F\x03\x82\x3A\x93\x6B\x4C\xD3"
+			  "\xE3\xF3\xFA\xC2\x23\x55\x98\x20"
+			  "\x49\x76\x9B\x6B\xC1\x23\xBF\xE5"
+			  "\xD4\xC4\x2F\x61\xE1\x67\x2A\x30"
+			  "\x6F\x29\xCA\x54\xF8\x1B\xA6\x7D"
+			  "\x66\x45\xEE\xC8\x19\xBE\x50\xF0"
+			  "\x5F\x65\xF8\x1E\x4D\x07\x87\xD9"
+			  "\xD3\xD9\x1B\x09\x89\xFD\x42\xC5"
+			  "\xDB\xEB\x86\xF1\x67\x04\x0F\x5C"
+			  "\x81\xDF\x82\x12\xC7\x4C\x1B\x07"
+			  "\xDE\xE6\xFA\x29\x86\xD1\xB0\xBA"
+			  "\x3D\x6A\x69\x76\xEC\x0F\xB4\xE6"
+			  "\xCD\xA7\xF8\xA8\xB8\xE0\x33\xF5"
+			  "\x49\x61\x22\x52\x64\x8C\x46\x41"
+			  "\x1F\x48\x5F\x4F\xA2\x89\x36\x17"
+			  "\x20\xF8\x2F\x8F\x4B\xFA\xF2\xC0"
+			  "\x1E\x18\xA2\xF8\xB7\x6D\x98\xE3"
+			  "\x00\x14\x15\x59\xC1\x30\x64\xAF"
+			  "\xA8\x01\x38\xAB\xD4\x8B\xEC\x7C"
+			  "\x44\x9A\xC6\x2C\x2E\x2B\x2B\xF4"
+			  "\x02\x37\xC4\x69\xEF\x36\xC1\xF3"
+			  "\xA0\xFB\xFE\x29\xAD\x39\xCF\xD0"
+			  "\x51\x73\xA3\x22\x42\x41\xAB\xD2"
+			  "\x0F\x50\x14\xB9\x54\xD3\xD4\xFA"
+			  "\xBF\xC9\xBB\xCE\xC4\x1D\x2D\xAF"
+			  "\xC9\x3F\x07\x87\x42\x4B\x3A\x54"
+			  "\x34\x8E\x37\xA3\x03\x6F\x65\x66"
+			  "\xDB\x44\xC3\xE8\xD7\xDD\x7D\xDD"
+			  "\x61\xB4\x2B\x80\xA3\x98\x13\xF5"
+			  "\x5A\xD3\x34\x58\xC3\x6E\xF6\xB8"
+			  "\x0A\xC6\x50\x01\x8E\xD5\x6C\x7D"
+			  "\xFE\x16\xB6\xCF\xFC\x51\x40\xAE"
+			  "\xB3\x15\xAC\x90\x6F\x0B\x28\x3A"
+			  "\x60\x40\x38\x90\x20\x46\xC7\xB3"
+			  "\x0B\x12\x6D\x3B\x15\x14\xF9\xF4"
+			  "\x11\x41\x76\x6B\xB3\x60\x82\x3C"
+			  "\x84\xFB\x08\x2E\x92\x25\xCB\x79"
+			  "\x6F\x58\xC5\x94\x00\x00\x47\xB6"
+			  "\x9E\xDC\x0F\x29\x70\x46\x20\x76"
+			  "\x65\x75\x66\x5C\x00\x96\xB3\xE1"
+			  "\x0B\xA7\x11\x8B\x2E\x61\x4E\x45"
+			  "\x73\xFC\x91\xAB\x79\x41\x23\x14"
+			  "\x13\xB6\x72\x6C\x46\xB3\x03\x11"
+			  "\xE4\xF1\xEE\xC9\x7A\xCF\x96\x32"
+			  "\xB6\xF0\x8B\x97\xB4\xCF\x82\xB7"
+			  "\x15\x48\x44\x99\x09\xF6\xE0\xD7"
+			  "\xBC\xF1\x5B\x91\x4F\x30\x22\xA2"
+			  "\x45\xC4\x68\x55\xC2\xBE\xA7\xD2"
+			  "\x12\x53\x35\x9C\xF9\xE7\x35\x5D"
+			  "\x81\xE4\x86\x42\xC3\x58\xFB\xF0"
+			  "\x38\x9B\x8E\x5A\xEF\x83\x33\x0F"
+			  "\x00\x4E\x3F\x9F\xF5\x84\x62\xC4"
+			  "\x19\x35\x88\x22\x45\x59\x0E\x8F"
+			  "\xEC\x27\xDD\x4A\xA4\x1F\xBC\x41"
+			  "\x9B\x66\x8D\x32\xBA\x81\x34\x87"
+			  "\x0E\x74\x33\x30\x62\xB9\x89\xDF"
+			  "\xF9\xC5\xDD\x27\xB3\x39\xCB\xCB",
+		.ilen	= 496,
+		.result	= "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+			  "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+			  "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+			  "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.rlen	= 496,
+	},
+};
+
+static struct cipher_testvec cast6_lrw_enc_tv_template[] = {
+	{ /* Generated from TF test vectors */
+		.key	= "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+			  "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+			  "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+			  "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+			  "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+			  "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+		.klen	= 48,
+		.iv	= "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x01",
+		.input	= "\x05\x11\xb7\x18\xab\xc6\x2d\xac"
+			  "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c"
+			  "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8"
+			  "\x50\x38\x1f\x71\x49\xb6\x57\xd6"
+			  "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90"
+			  "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6"
+			  "\xad\x1e\x9e\x20\x5f\x38\xbe\x04"
+			  "\xda\x10\x8e\xed\xa2\xa4\x87\xab"
+			  "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c"
+			  "\xc9\xac\x42\x31\x95\x7c\xc9\x04"
+			  "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6"
+			  "\x15\xd7\x3f\x4f\x2f\x66\x69\x03"
+			  "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65"
+			  "\x4c\x96\x12\xed\x7c\x92\x03\x01"
+			  "\x6f\xbc\x35\x93\xac\xf1\x27\xf1"
+			  "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50"
+			  "\x89\xa4\x8e\x66\x44\x85\xcc\xfd"
+			  "\x33\x14\x70\xe3\x96\xb2\xc3\xd3"
+			  "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5"
+			  "\x2d\x64\x75\xdd\xb4\x54\xe6\x74"
+			  "\x8c\xd3\x9d\x9e\x86\xab\x51\x53"
+			  "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40"
+			  "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5"
+			  "\x76\x12\x73\x44\x1a\x56\xd7\x72"
+			  "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda"
+			  "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd"
+			  "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60"
+			  "\x1a\xe2\x70\x85\x58\xc2\x1b\x09"
+			  "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9"
+			  "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8"
+			  "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8"
+			  "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10"
+			  "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1"
+			  "\x90\x3e\x76\x4a\x74\xa4\x21\x2c"
+			  "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e"
+			  "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f"
+			  "\x8d\x23\x31\x74\x84\xeb\x88\x6e"
+			  "\xcc\xb9\xbc\x22\x83\x19\x07\x22"
+			  "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78"
+			  "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5"
+			  "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41"
+			  "\x3c\xce\x8f\x42\x60\x71\xa7\x75"
+			  "\x08\x40\x65\x8a\x82\xbf\xf5\x43"
+			  "\x71\x96\xa9\x4d\x44\x8a\x20\xbe"
+			  "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65"
+			  "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9"
+			  "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4"
+			  "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a"
+			  "\x62\x73\x65\xfd\x46\x63\x25\x3d"
+			  "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf"
+			  "\x24\xf3\xb4\xac\x64\xba\xdf\x4b"
+			  "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7"
+			  "\xc5\x68\x77\x84\x32\x2b\xcc\x85"
+			  "\x74\x96\xf0\x12\x77\x61\xb9\xeb"
+			  "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8"
+			  "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24"
+			  "\xda\x39\x87\x45\xc0\x2b\xbb\x01"
+			  "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce"
+			  "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6"
+			  "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32"
+			  "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45"
+			  "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6"
+			  "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4"
+			  "\x21\xc4\xc2\x75\x67\x89\x37\x0a",
+		.ilen	= 512,
+		.result	= "\x55\x25\x09\x8B\xB5\xD5\xF8\xBF"
+			  "\x37\x4A\xFE\x3C\x47\xD8\xE6\xEB"
+			  "\xCA\xA4\x9B\xB0\xAB\x6D\x64\xCA"
+			  "\x58\xB6\x73\xF0\xD7\x52\x34\xEF"
+			  "\xFB\x3E\x96\x81\xB7\x71\x34\xA4"
+			  "\x55\x20\xBE\x39\x5A\x2B\xF9\xD1"
+			  "\x65\x0B\xDA\xD3\x7E\xB3\xA6\xF7"
+			  "\x2E\x0B\x5A\x52\xDB\x39\x8C\x9B"
+			  "\x61\x17\x5F\xAF\xB6\x5A\xC8\x08"
+			  "\xA7\xB7\x2A\x11\x7C\x97\x38\x9D"
+			  "\x59\x0E\x66\x59\x5E\xD8\x8B\xCE"
+			  "\x70\xE0\xC3\x42\xB0\x8C\x0F\xBA"
+			  "\xB2\x0D\x81\xB6\xBE\x61\x1C\x2D"
+			  "\x7E\xEA\x91\x25\xAC\xEC\xF8\x28"
+			  "\x80\x1D\xF0\x30\xBA\x62\x77\x7D"
+			  "\xDB\x15\x69\xDF\xFA\x2A\x81\x64"
+			  "\x95\x5B\xA4\x7F\x3E\x4F\xE3\x30"
+			  "\xB0\x5C\xC2\x05\xF8\xF0\x29\xE7"
+			  "\x0A\xA0\x66\xB2\x5D\x0F\x39\x2B"
+			  "\xB4\xB3\x00\xA9\xD0\xAB\x63\x61"
+			  "\x5E\xDB\xFC\x11\x74\x25\x96\x65"
+			  "\xE8\xE2\x34\x57\x77\x15\x5E\x70"
+			  "\xFF\x10\x90\xC3\x64\xF0\x11\x0A"
+			  "\x63\x3A\xD3\x55\x92\x15\x4B\x0C"
+			  "\xC7\x08\x89\x17\x3B\x99\xAD\x63"
+			  "\xE7\x06\xDF\x52\xBC\x15\x64\x45"
+			  "\x9D\x7A\xFB\x69\xBC\x2D\x6E\xA9"
+			  "\x35\xD9\xD8\xF5\x0C\xC4\xA2\x23"
+			  "\x9C\x18\x8B\xA8\x8C\xFE\xF8\x0E"
+			  "\xBD\xAB\x60\x1A\x51\x17\x54\x27"
+			  "\xB6\xE8\xBE\x0F\xA9\xA5\x82\x19"
+			  "\x2F\x6F\x20\xA7\x47\xED\x74\x6C"
+			  "\x4E\xC1\xF8\x8C\x14\xF3\xBB\x1F"
+			  "\xED\x4D\x8F\x7C\x37\xEF\x19\xA1"
+			  "\x07\x16\xDE\x76\xCC\x5E\x94\x02"
+			  "\xFB\xBF\xE4\x81\x50\xCE\xFC\x0F"
+			  "\x9E\xCF\x3D\xF6\x67\x00\xBF\xA7"
+			  "\x6E\x21\x58\x36\x06\xDE\xB3\xD4"
+			  "\xA2\xFA\xD8\x4E\xE0\xB9\x7F\x23"
+			  "\x51\x21\x2B\x32\x68\xAA\xF8\xA8"
+			  "\x93\x08\xB5\x6D\xE6\x43\x2C\xB7"
+			  "\x31\xB2\x0F\xD0\xA2\x51\xC0\x25"
+			  "\x30\xC7\x10\x3F\x97\x27\x01\x8E"
+			  "\xFA\xD8\x4F\x78\xD8\x2E\x1D\xEB"
+			  "\xA1\x37\x52\x0F\x7B\x5E\x87\xA8"
+			  "\x22\xE2\xE6\x92\xA7\x5F\x11\x32"
+			  "\xCC\x93\x34\xFC\xD1\x7E\xAE\x54"
+			  "\xBC\x6A\x1B\x91\xD1\x2E\x21\xEC"
+			  "\x5D\xF1\xC4\xF1\x55\x20\xBF\xE5"
+			  "\x96\x3D\x69\x91\x20\x4E\xF2\x61"
+			  "\xDA\x77\xFE\xEE\xC3\x74\x57\x2A"
+			  "\x78\x39\xB0\xE0\xCF\x12\x56\xD6"
+			  "\x05\xDC\xF9\x19\x66\x44\x1D\xF9"
+			  "\x82\x37\xD4\xC2\x60\xB6\x31\xDF"
+			  "\x0C\xAF\xBC\x8B\x55\x9A\xC8\x2D"
+			  "\xAB\xA7\x88\x7B\x41\xE8\x29\xC9"
+			  "\x9B\x8D\xA7\x00\x86\x25\xB6\x14"
+			  "\xF5\x13\x73\xD7\x4B\x6B\x83\xF3"
+			  "\xAF\x96\x00\xE4\xB7\x3C\x65\xA6"
+			  "\x15\xB7\x94\x7D\x4E\x70\x4C\x75"
+			  "\xF3\xB4\x02\xA9\x17\x1C\x7A\x0A"
+			  "\xC0\xD5\x33\x11\x56\xDE\xDC\xF5"
+			  "\x8D\xD9\xCD\x3B\x22\x67\x18\xC7"
+			  "\xC4\xF5\x99\x61\xBC\xBB\x5B\x46",
+		.rlen	= 512,
+	},
+};
+
+static struct cipher_testvec cast6_lrw_dec_tv_template[] = {
+	{ /* Generated from TF test vectors */
+		.key	= "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+			  "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+			  "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+			  "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+			  "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+			  "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+		.klen	= 48,
+		.iv	= "\x00\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x01",
+		.input	= "\x55\x25\x09\x8B\xB5\xD5\xF8\xBF"
+			  "\x37\x4A\xFE\x3C\x47\xD8\xE6\xEB"
+			  "\xCA\xA4\x9B\xB0\xAB\x6D\x64\xCA"
+			  "\x58\xB6\x73\xF0\xD7\x52\x34\xEF"
+			  "\xFB\x3E\x96\x81\xB7\x71\x34\xA4"
+			  "\x55\x20\xBE\x39\x5A\x2B\xF9\xD1"
+			  "\x65\x0B\xDA\xD3\x7E\xB3\xA6\xF7"
+			  "\x2E\x0B\x5A\x52\xDB\x39\x8C\x9B"
+			  "\x61\x17\x5F\xAF\xB6\x5A\xC8\x08"
+			  "\xA7\xB7\x2A\x11\x7C\x97\x38\x9D"
+			  "\x59\x0E\x66\x59\x5E\xD8\x8B\xCE"
+			  "\x70\xE0\xC3\x42\xB0\x8C\x0F\xBA"
+			  "\xB2\x0D\x81\xB6\xBE\x61\x1C\x2D"
+			  "\x7E\xEA\x91\x25\xAC\xEC\xF8\x28"
+			  "\x80\x1D\xF0\x30\xBA\x62\x77\x7D"
+			  "\xDB\x15\x69\xDF\xFA\x2A\x81\x64"
+			  "\x95\x5B\xA4\x7F\x3E\x4F\xE3\x30"
+			  "\xB0\x5C\xC2\x05\xF8\xF0\x29\xE7"
+			  "\x0A\xA0\x66\xB2\x5D\x0F\x39\x2B"
+			  "\xB4\xB3\x00\xA9\xD0\xAB\x63\x61"
+			  "\x5E\xDB\xFC\x11\x74\x25\x96\x65"
+			  "\xE8\xE2\x34\x57\x77\x15\x5E\x70"
+			  "\xFF\x10\x90\xC3\x64\xF0\x11\x0A"
+			  "\x63\x3A\xD3\x55\x92\x15\x4B\x0C"
+			  "\xC7\x08\x89\x17\x3B\x99\xAD\x63"
+			  "\xE7\x06\xDF\x52\xBC\x15\x64\x45"
+			  "\x9D\x7A\xFB\x69\xBC\x2D\x6E\xA9"
+			  "\x35\xD9\xD8\xF5\x0C\xC4\xA2\x23"
+			  "\x9C\x18\x8B\xA8\x8C\xFE\xF8\x0E"
+			  "\xBD\xAB\x60\x1A\x51\x17\x54\x27"
+			  "\xB6\xE8\xBE\x0F\xA9\xA5\x82\x19"
+			  "\x2F\x6F\x20\xA7\x47\xED\x74\x6C"
+			  "\x4E\xC1\xF8\x8C\x14\xF3\xBB\x1F"
+			  "\xED\x4D\x8F\x7C\x37\xEF\x19\xA1"
+			  "\x07\x16\xDE\x76\xCC\x5E\x94\x02"
+			  "\xFB\xBF\xE4\x81\x50\xCE\xFC\x0F"
+			  "\x9E\xCF\x3D\xF6\x67\x00\xBF\xA7"
+			  "\x6E\x21\x58\x36\x06\xDE\xB3\xD4"
+			  "\xA2\xFA\xD8\x4E\xE0\xB9\x7F\x23"
+			  "\x51\x21\x2B\x32\x68\xAA\xF8\xA8"
+			  "\x93\x08\xB5\x6D\xE6\x43\x2C\xB7"
+			  "\x31\xB2\x0F\xD0\xA2\x51\xC0\x25"
+			  "\x30\xC7\x10\x3F\x97\x27\x01\x8E"
+			  "\xFA\xD8\x4F\x78\xD8\x2E\x1D\xEB"
+			  "\xA1\x37\x52\x0F\x7B\x5E\x87\xA8"
+			  "\x22\xE2\xE6\x92\xA7\x5F\x11\x32"
+			  "\xCC\x93\x34\xFC\xD1\x7E\xAE\x54"
+			  "\xBC\x6A\x1B\x91\xD1\x2E\x21\xEC"
+			  "\x5D\xF1\xC4\xF1\x55\x20\xBF\xE5"
+			  "\x96\x3D\x69\x91\x20\x4E\xF2\x61"
+			  "\xDA\x77\xFE\xEE\xC3\x74\x57\x2A"
+			  "\x78\x39\xB0\xE0\xCF\x12\x56\xD6"
+			  "\x05\xDC\xF9\x19\x66\x44\x1D\xF9"
+			  "\x82\x37\xD4\xC2\x60\xB6\x31\xDF"
+			  "\x0C\xAF\xBC\x8B\x55\x9A\xC8\x2D"
+			  "\xAB\xA7\x88\x7B\x41\xE8\x29\xC9"
+			  "\x9B\x8D\xA7\x00\x86\x25\xB6\x14"
+			  "\xF5\x13\x73\xD7\x4B\x6B\x83\xF3"
+			  "\xAF\x96\x00\xE4\xB7\x3C\x65\xA6"
+			  "\x15\xB7\x94\x7D\x4E\x70\x4C\x75"
+			  "\xF3\xB4\x02\xA9\x17\x1C\x7A\x0A"
+			  "\xC0\xD5\x33\x11\x56\xDE\xDC\xF5"
+			  "\x8D\xD9\xCD\x3B\x22\x67\x18\xC7"
+			  "\xC4\xF5\x99\x61\xBC\xBB\x5B\x46",
+		.ilen	= 512,
+		.result	= "\x05\x11\xb7\x18\xab\xc6\x2d\xac"
+			  "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c"
+			  "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8"
+			  "\x50\x38\x1f\x71\x49\xb6\x57\xd6"
+			  "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90"
+			  "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6"
+			  "\xad\x1e\x9e\x20\x5f\x38\xbe\x04"
+			  "\xda\x10\x8e\xed\xa2\xa4\x87\xab"
+			  "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c"
+			  "\xc9\xac\x42\x31\x95\x7c\xc9\x04"
+			  "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6"
+			  "\x15\xd7\x3f\x4f\x2f\x66\x69\x03"
+			  "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65"
+			  "\x4c\x96\x12\xed\x7c\x92\x03\x01"
+			  "\x6f\xbc\x35\x93\xac\xf1\x27\xf1"
+			  "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50"
+			  "\x89\xa4\x8e\x66\x44\x85\xcc\xfd"
+			  "\x33\x14\x70\xe3\x96\xb2\xc3\xd3"
+			  "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5"
+			  "\x2d\x64\x75\xdd\xb4\x54\xe6\x74"
+			  "\x8c\xd3\x9d\x9e\x86\xab\x51\x53"
+			  "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40"
+			  "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5"
+			  "\x76\x12\x73\x44\x1a\x56\xd7\x72"
+			  "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda"
+			  "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd"
+			  "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60"
+			  "\x1a\xe2\x70\x85\x58\xc2\x1b\x09"
+			  "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9"
+			  "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8"
+			  "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8"
+			  "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10"
+			  "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1"
+			  "\x90\x3e\x76\x4a\x74\xa4\x21\x2c"
+			  "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e"
+			  "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f"
+			  "\x8d\x23\x31\x74\x84\xeb\x88\x6e"
+			  "\xcc\xb9\xbc\x22\x83\x19\x07\x22"
+			  "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78"
+			  "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5"
+			  "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41"
+			  "\x3c\xce\x8f\x42\x60\x71\xa7\x75"
+			  "\x08\x40\x65\x8a\x82\xbf\xf5\x43"
+			  "\x71\x96\xa9\x4d\x44\x8a\x20\xbe"
+			  "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65"
+			  "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9"
+			  "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4"
+			  "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a"
+			  "\x62\x73\x65\xfd\x46\x63\x25\x3d"
+			  "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf"
+			  "\x24\xf3\xb4\xac\x64\xba\xdf\x4b"
+			  "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7"
+			  "\xc5\x68\x77\x84\x32\x2b\xcc\x85"
+			  "\x74\x96\xf0\x12\x77\x61\xb9\xeb"
+			  "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8"
+			  "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24"
+			  "\xda\x39\x87\x45\xc0\x2b\xbb\x01"
+			  "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce"
+			  "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6"
+			  "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32"
+			  "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45"
+			  "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6"
+			  "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4"
+			  "\x21\xc4\xc2\x75\x67\x89\x37\x0a",
+		.rlen	= 512,
+	},
+};
+
+static struct cipher_testvec cast6_xts_enc_tv_template[] = {
+	{ /* Generated from TF test vectors */
+		.key	= "\x27\x18\x28\x18\x28\x45\x90\x45"
+			  "\x23\x53\x60\x28\x74\x71\x35\x26"
+			  "\x62\x49\x77\x57\x24\x70\x93\x69"
+			  "\x99\x59\x57\x49\x66\x96\x76\x27"
+			  "\x31\x41\x59\x26\x53\x58\x97\x93"
+			  "\x23\x84\x62\x64\x33\x83\x27\x95"
+			  "\x02\x88\x41\x97\x16\x93\x99\x37"
+			  "\x51\x05\x82\x09\x74\x94\x45\x92",
+		.klen	= 64,
+		.iv	= "\xff\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+			  "\x20\x21\x22\x23\x24\x25\x26\x27"
+			  "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+			  "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+			  "\x40\x41\x42\x43\x44\x45\x46\x47"
+			  "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+			  "\x50\x51\x52\x53\x54\x55\x56\x57"
+			  "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+			  "\x60\x61\x62\x63\x64\x65\x66\x67"
+			  "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+			  "\x70\x71\x72\x73\x74\x75\x76\x77"
+			  "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+			  "\x80\x81\x82\x83\x84\x85\x86\x87"
+			  "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+			  "\x90\x91\x92\x93\x94\x95\x96\x97"
+			  "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+			  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+			  "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+			  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+			  "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+			  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+			  "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+			  "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+			  "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+			  "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+			  "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+			  "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+			  "\x20\x21\x22\x23\x24\x25\x26\x27"
+			  "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+			  "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+			  "\x40\x41\x42\x43\x44\x45\x46\x47"
+			  "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+			  "\x50\x51\x52\x53\x54\x55\x56\x57"
+			  "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+			  "\x60\x61\x62\x63\x64\x65\x66\x67"
+			  "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+			  "\x70\x71\x72\x73\x74\x75\x76\x77"
+			  "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+			  "\x80\x81\x82\x83\x84\x85\x86\x87"
+			  "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+			  "\x90\x91\x92\x93\x94\x95\x96\x97"
+			  "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+			  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+			  "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+			  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+			  "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+			  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+			  "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+			  "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+			  "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+			  "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+			  "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.ilen	= 512,
+		.result	= "\xDE\x6F\x22\xA5\xE8\x39\xE8\x78"
+			  "\x88\x5A\x4F\x8D\x82\x76\x52\x6D"
+			  "\xB2\x41\x16\xF4\x2B\xA6\xEB\xF6"
+			  "\xE2\xC5\x62\x8D\x61\xA1\x01\xED"
+			  "\xD9\x38\x01\xC1\x43\x63\x4E\x88"
+			  "\xC9\x4B\x5A\x88\x80\xB7\x5C\x71"
+			  "\x47\xEE\x11\xD8\xB7\x2D\x5D\x13"
+			  "\x1A\xB1\x68\x5B\x61\xA7\xA9\x81"
+			  "\x8B\x83\xA1\x6A\xAA\x36\xD6\xB6"
+			  "\x60\x54\x09\x32\xFE\x6A\x76\x2E"
+			  "\x28\xFF\xD5\xD6\xDD\x1D\x45\x7D"
+			  "\xF0\x8B\xF3\x32\x4E\x6C\x12\xCB"
+			  "\xB8\x25\x70\xF8\x40\xBC\x90\x1B"
+			  "\x11\xC3\x59\xAF\xF0\x2F\x92\xDD"
+			  "\xD3\x3B\xCF\x60\xA1\x78\x94\x57"
+			  "\xAF\x76\xC1\x67\xA6\x3C\xCD\x98"
+			  "\xB1\xF7\x27\xB9\xA3\xBD\x10\xEA"
+			  "\xCD\x8B\xC2\xF2\x14\xF2\xB2\x67"
+			  "\x05\xDD\x1D\x58\x6E\x2F\x95\x08"
+			  "\x3A\xF8\x78\x76\x82\x56\xA7\xEC"
+			  "\x51\x4B\x85\x77\xC2\x4C\x4A\x34"
+			  "\x71\x38\x17\x91\x44\xE8\xFC\x65"
+			  "\x99\x0D\x52\x91\xEE\xF8\xEF\x27"
+			  "\x2A\x9E\x6E\x78\xC4\x26\x87\xF4"
+			  "\x8A\xF0\x2D\x04\xE8\x14\x92\x5D"
+			  "\x59\x22\x9B\x29\x5C\x18\xF0\xC3"
+			  "\x47\xF3\x76\xD8\xE4\xF3\x1B\xD1"
+			  "\x70\xA3\x0D\xB5\x70\x02\x1D\xA3"
+			  "\x91\x3B\x49\x73\x18\xAB\xD4\xC9"
+			  "\xC3\x1E\xEF\x1F\xFE\xD5\x59\x8A"
+			  "\xD7\xF6\xC9\x71\x67\x79\xD7\x0E"
+			  "\xBE\x1F\x8E\xEC\x55\x7E\x4F\x24"
+			  "\xE6\x87\xEA\xFE\x96\x25\x67\x8E"
+			  "\x93\x03\xFA\xFF\xCE\xAF\xB2\x3C"
+			  "\x6F\xEB\x57\xFB\xD3\x28\x87\xA9"
+			  "\xCE\xC2\xF5\x9C\xC6\x67\xB5\x97"
+			  "\x49\xF7\x04\xCB\xEF\x84\x98\x33"
+			  "\xAF\x38\xD3\x04\x1C\x24\x71\x38"
+			  "\xC7\x71\xDD\x43\x0D\x12\x4A\x18"
+			  "\xBA\xC4\xAF\xBA\xB2\x5B\xEB\x95"
+			  "\x02\x43\x5D\xCE\x19\xCC\xCD\x66"
+			  "\x91\x0B\x8C\x7F\x51\xC4\xBF\x3C"
+			  "\x8B\xF1\xCC\xAA\x29\xD7\x87\xCB"
+			  "\x3E\xC5\xF3\xC9\x75\xE8\xA3\x5B"
+			  "\x30\x45\xA9\xB7\xAF\x80\x64\x6F"
+			  "\x75\x4A\xA7\xC0\x6D\x19\x6B\xDE"
+			  "\x17\xDE\x6D\xEA\x87\x9F\x95\xAE"
+			  "\xF5\x3C\xEE\x54\xB8\x27\x84\xF8"
+			  "\x97\xA3\xE1\x6F\x38\x24\x34\x88"
+			  "\xCE\xBD\x32\x52\xE0\x00\x6C\x94"
+			  "\xC9\xD7\x5D\x37\x81\x33\x2E\x7F"
+			  "\x4F\x7E\x2E\x0D\x94\xBD\xEA\x59"
+			  "\x34\x39\xA8\x35\x12\xB7\xBC\xAC"
+			  "\xEA\x52\x9C\x78\x02\x6D\x92\x36"
+			  "\xFB\x59\x2B\xA4\xEA\x7B\x1B\x83"
+			  "\xE1\x4D\x5E\x2A\x7E\x92\xB1\x64"
+			  "\xDE\xE0\x27\x4B\x0A\x6F\x4C\xE3"
+			  "\xB0\xEB\x31\xE4\x69\x95\xAB\x35"
+			  "\x8B\x2C\xF5\x6B\x7F\xF1\xA2\x82"
+			  "\xF8\xD9\x47\x82\xA9\x82\x03\x91"
+			  "\x69\x1F\xBE\x4C\xE7\xC7\x34\x2F"
+			  "\x45\x72\x80\x17\x81\xBD\x9D\x62"
+			  "\xA1\xAC\xE8\xCF\xC6\x74\xCF\xDC"
+			  "\x22\x60\x4E\xE8\xA4\x5D\x85\xB9",
+		.rlen	= 512,
+	},
+};
+
+static struct cipher_testvec cast6_xts_dec_tv_template[] = {
+	{ /* Generated from TF test vectors */
+		.key	= "\x27\x18\x28\x18\x28\x45\x90\x45"
+			  "\x23\x53\x60\x28\x74\x71\x35\x26"
+			  "\x62\x49\x77\x57\x24\x70\x93\x69"
+			  "\x99\x59\x57\x49\x66\x96\x76\x27"
+			  "\x31\x41\x59\x26\x53\x58\x97\x93"
+			  "\x23\x84\x62\x64\x33\x83\x27\x95"
+			  "\x02\x88\x41\x97\x16\x93\x99\x37"
+			  "\x51\x05\x82\x09\x74\x94\x45\x92",
+		.klen	= 64,
+		.iv	= "\xff\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.input	= "\xDE\x6F\x22\xA5\xE8\x39\xE8\x78"
+			  "\x88\x5A\x4F\x8D\x82\x76\x52\x6D"
+			  "\xB2\x41\x16\xF4\x2B\xA6\xEB\xF6"
+			  "\xE2\xC5\x62\x8D\x61\xA1\x01\xED"
+			  "\xD9\x38\x01\xC1\x43\x63\x4E\x88"
+			  "\xC9\x4B\x5A\x88\x80\xB7\x5C\x71"
+			  "\x47\xEE\x11\xD8\xB7\x2D\x5D\x13"
+			  "\x1A\xB1\x68\x5B\x61\xA7\xA9\x81"
+			  "\x8B\x83\xA1\x6A\xAA\x36\xD6\xB6"
+			  "\x60\x54\x09\x32\xFE\x6A\x76\x2E"
+			  "\x28\xFF\xD5\xD6\xDD\x1D\x45\x7D"
+			  "\xF0\x8B\xF3\x32\x4E\x6C\x12\xCB"
+			  "\xB8\x25\x70\xF8\x40\xBC\x90\x1B"
+			  "\x11\xC3\x59\xAF\xF0\x2F\x92\xDD"
+			  "\xD3\x3B\xCF\x60\xA1\x78\x94\x57"
+			  "\xAF\x76\xC1\x67\xA6\x3C\xCD\x98"
+			  "\xB1\xF7\x27\xB9\xA3\xBD\x10\xEA"
+			  "\xCD\x8B\xC2\xF2\x14\xF2\xB2\x67"
+			  "\x05\xDD\x1D\x58\x6E\x2F\x95\x08"
+			  "\x3A\xF8\x78\x76\x82\x56\xA7\xEC"
+			  "\x51\x4B\x85\x77\xC2\x4C\x4A\x34"
+			  "\x71\x38\x17\x91\x44\xE8\xFC\x65"
+			  "\x99\x0D\x52\x91\xEE\xF8\xEF\x27"
+			  "\x2A\x9E\x6E\x78\xC4\x26\x87\xF4"
+			  "\x8A\xF0\x2D\x04\xE8\x14\x92\x5D"
+			  "\x59\x22\x9B\x29\x5C\x18\xF0\xC3"
+			  "\x47\xF3\x76\xD8\xE4\xF3\x1B\xD1"
+			  "\x70\xA3\x0D\xB5\x70\x02\x1D\xA3"
+			  "\x91\x3B\x49\x73\x18\xAB\xD4\xC9"
+			  "\xC3\x1E\xEF\x1F\xFE\xD5\x59\x8A"
+			  "\xD7\xF6\xC9\x71\x67\x79\xD7\x0E"
+			  "\xBE\x1F\x8E\xEC\x55\x7E\x4F\x24"
+			  "\xE6\x87\xEA\xFE\x96\x25\x67\x8E"
+			  "\x93\x03\xFA\xFF\xCE\xAF\xB2\x3C"
+			  "\x6F\xEB\x57\xFB\xD3\x28\x87\xA9"
+			  "\xCE\xC2\xF5\x9C\xC6\x67\xB5\x97"
+			  "\x49\xF7\x04\xCB\xEF\x84\x98\x33"
+			  "\xAF\x38\xD3\x04\x1C\x24\x71\x38"
+			  "\xC7\x71\xDD\x43\x0D\x12\x4A\x18"
+			  "\xBA\xC4\xAF\xBA\xB2\x5B\xEB\x95"
+			  "\x02\x43\x5D\xCE\x19\xCC\xCD\x66"
+			  "\x91\x0B\x8C\x7F\x51\xC4\xBF\x3C"
+			  "\x8B\xF1\xCC\xAA\x29\xD7\x87\xCB"
+			  "\x3E\xC5\xF3\xC9\x75\xE8\xA3\x5B"
+			  "\x30\x45\xA9\xB7\xAF\x80\x64\x6F"
+			  "\x75\x4A\xA7\xC0\x6D\x19\x6B\xDE"
+			  "\x17\xDE\x6D\xEA\x87\x9F\x95\xAE"
+			  "\xF5\x3C\xEE\x54\xB8\x27\x84\xF8"
+			  "\x97\xA3\xE1\x6F\x38\x24\x34\x88"
+			  "\xCE\xBD\x32\x52\xE0\x00\x6C\x94"
+			  "\xC9\xD7\x5D\x37\x81\x33\x2E\x7F"
+			  "\x4F\x7E\x2E\x0D\x94\xBD\xEA\x59"
+			  "\x34\x39\xA8\x35\x12\xB7\xBC\xAC"
+			  "\xEA\x52\x9C\x78\x02\x6D\x92\x36"
+			  "\xFB\x59\x2B\xA4\xEA\x7B\x1B\x83"
+			  "\xE1\x4D\x5E\x2A\x7E\x92\xB1\x64"
+			  "\xDE\xE0\x27\x4B\x0A\x6F\x4C\xE3"
+			  "\xB0\xEB\x31\xE4\x69\x95\xAB\x35"
+			  "\x8B\x2C\xF5\x6B\x7F\xF1\xA2\x82"
+			  "\xF8\xD9\x47\x82\xA9\x82\x03\x91"
+			  "\x69\x1F\xBE\x4C\xE7\xC7\x34\x2F"
+			  "\x45\x72\x80\x17\x81\xBD\x9D\x62"
+			  "\xA1\xAC\xE8\xCF\xC6\x74\xCF\xDC"
+			  "\x22\x60\x4E\xE8\xA4\x5D\x85\xB9",
+		.ilen	= 512,
+		.result	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+			  "\x20\x21\x22\x23\x24\x25\x26\x27"
+			  "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+			  "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+			  "\x40\x41\x42\x43\x44\x45\x46\x47"
+			  "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+			  "\x50\x51\x52\x53\x54\x55\x56\x57"
+			  "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+			  "\x60\x61\x62\x63\x64\x65\x66\x67"
+			  "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+			  "\x70\x71\x72\x73\x74\x75\x76\x77"
+			  "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+			  "\x80\x81\x82\x83\x84\x85\x86\x87"
+			  "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+			  "\x90\x91\x92\x93\x94\x95\x96\x97"
+			  "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+			  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+			  "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+			  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+			  "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+			  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+			  "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+			  "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+			  "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+			  "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+			  "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+			  "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+			  "\x20\x21\x22\x23\x24\x25\x26\x27"
+			  "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+			  "\x30\x31\x32\x33\x34\x35\x36\x37"
+			  "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+			  "\x40\x41\x42\x43\x44\x45\x46\x47"
+			  "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+			  "\x50\x51\x52\x53\x54\x55\x56\x57"
+			  "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+			  "\x60\x61\x62\x63\x64\x65\x66\x67"
+			  "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+			  "\x70\x71\x72\x73\x74\x75\x76\x77"
+			  "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+			  "\x80\x81\x82\x83\x84\x85\x86\x87"
+			  "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+			  "\x90\x91\x92\x93\x94\x95\x96\x97"
+			  "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+			  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+			  "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+			  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+			  "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+			  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+			  "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+			  "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+			  "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+			  "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+			  "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+			  "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.rlen	= 512,
+	},
+};
+
+
+/*
+ * AES test vectors.
+ */
+#define AES_ENC_TEST_VECTORS 3
+#define AES_DEC_TEST_VECTORS 3
+#define AES_CBC_ENC_TEST_VECTORS 4
+#define AES_CBC_DEC_TEST_VECTORS 4
+#define HMAC_SHA1_AES_CBC_ENC_TEST_VECTORS 7
+#define HMAC_SHA256_AES_CBC_ENC_TEST_VECTORS 7
+#define HMAC_SHA512_AES_CBC_ENC_TEST_VECTORS 7
+#define AES_LRW_ENC_TEST_VECTORS 8
+#define AES_LRW_DEC_TEST_VECTORS 8
+#define AES_XTS_ENC_TEST_VECTORS 5
+#define AES_XTS_DEC_TEST_VECTORS 5
+#define AES_CTR_ENC_TEST_VECTORS 3
+#define AES_CTR_DEC_TEST_VECTORS 3
+#define AES_OFB_ENC_TEST_VECTORS 1
+#define AES_OFB_DEC_TEST_VECTORS 1
+#define AES_CTR_3686_ENC_TEST_VECTORS 7
+#define AES_CTR_3686_DEC_TEST_VECTORS 6
+#define AES_GCM_ENC_TEST_VECTORS 9
+#define AES_GCM_DEC_TEST_VECTORS 8
+#define AES_GCM_4106_ENC_TEST_VECTORS 7
+#define AES_GCM_4106_DEC_TEST_VECTORS 7
+#define AES_CCM_ENC_TEST_VECTORS 7
+#define AES_CCM_DEC_TEST_VECTORS 7
+#define AES_CCM_4309_ENC_TEST_VECTORS 7
+#define AES_CCM_4309_DEC_TEST_VECTORS 10
+
+static struct cipher_testvec aes_enc_tv_template[] = {
+	{ /* From FIPS-197 */
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.klen	= 16,
+		.input	= "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+		.ilen	= 16,
+		.result	= "\x69\xc4\xe0\xd8\x6a\x7b\x04\x30"
+			  "\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17",
+		.klen	= 24,
+		.input	= "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+		.ilen	= 16,
+		.result	= "\xdd\xa9\x7c\xa4\x86\x4c\xdf\xe0"
+			  "\x6e\xaf\x70\xa0\xec\x0d\x71\x91",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.klen	= 32,
+		.input	= "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+		.ilen	= 16,
+		.result	= "\x8e\xa2\xb7\xca\x51\x67\x45\xbf"
+			  "\xea\xfc\x49\x90\x4b\x49\x60\x89",
+		.rlen	= 16,
+	},
+};
+
+static struct cipher_testvec aes_dec_tv_template[] = {
+	{ /* From FIPS-197 */
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+		.klen	= 16,
+		.input	= "\x69\xc4\xe0\xd8\x6a\x7b\x04\x30"
+			  "\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a",
+		.ilen	= 16,
+		.result	= "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17",
+		.klen	= 24,
+		.input	= "\xdd\xa9\x7c\xa4\x86\x4c\xdf\xe0"
+			  "\x6e\xaf\x70\xa0\xec\x0d\x71\x91",
+		.ilen	= 16,
+		.result	= "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+		.rlen	= 16,
+	}, {
+		.key	= "\x00\x01\x02\x03\x04\x05\x06\x07"
+			  "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+			  "\x10\x11\x12\x13\x14\x15\x16\x17"
+			  "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+		.klen	= 32,
+		.input	= "\x8e\xa2\xb7\xca\x51\x67\x45\xbf"
+			  "\xea\xfc\x49\x90\x4b\x49\x60\x89",
+		.ilen	= 16,
+		.result	= "\x00\x11\x22\x33\x44\x55\x66\x77"
+			  "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+		.rlen	= 16,
+	},
+};
+
+static struct cipher_testvec aes_cbc_enc_tv_template[] = {
+	{ /* From RFC 3602 */
+		.key    = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
+			  "\x51\x2e\x03\xd5\x34\x12\x00\x06",
+		.klen   = 16,
+		.iv	= "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
+			  "\xb4\x22\xda\x80\x2c\x9f\xac\x41",
+		.input	= "Single block msg",
+		.ilen   = 16,
 		.result = "\xe3\x53\x77\x9c\x10\x79\xae\xb8"
 			  "\x27\x08\x94\x2d\xbe\x77\x18\x1a",
 		.rlen   = 16,
@@ -12124,61 +13532,867 @@ static struct cprng_testvec ansi_cprng_aes_tv_template[] = {
 	},
 };
 
-/* Cast5 test vectors from RFC 2144 */
-#define CAST5_ENC_TEST_VECTORS	3
-#define CAST5_DEC_TEST_VECTORS	3
+/* Cast5 test vectors from RFC 2144 */
+#define CAST5_ENC_TEST_VECTORS		4
+#define CAST5_DEC_TEST_VECTORS		4
+#define CAST5_CBC_ENC_TEST_VECTORS	1
+#define CAST5_CBC_DEC_TEST_VECTORS	1
+#define CAST5_CTR_ENC_TEST_VECTORS	1
+#define CAST5_CTR_DEC_TEST_VECTORS	1
+
+static struct cipher_testvec cast5_enc_tv_template[] = {
+	{
+		.key	= "\x01\x23\x45\x67\x12\x34\x56\x78"
+			  "\x23\x45\x67\x89\x34\x56\x78\x9a",
+		.klen	= 16,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.ilen	= 8,
+		.result	= "\x23\x8b\x4f\xe5\x84\x7e\x44\xb2",
+		.rlen	= 8,
+	}, {
+		.key	= "\x01\x23\x45\x67\x12\x34\x56\x78"
+			  "\x23\x45",
+		.klen	= 10,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.ilen	= 8,
+		.result	= "\xeb\x6a\x71\x1a\x2c\x02\x27\x1b",
+		.rlen	= 8,
+	}, {
+		.key	= "\x01\x23\x45\x67\x12",
+		.klen	= 5,
+		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.ilen	= 8,
+		.result	= "\x7a\xc8\x16\xd1\x6e\x9b\x30\x2e",
+		.rlen	= 8,
+	}, { /* Generated from TF test vectors */
+		.key	= "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+			  "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A",
+		.klen	= 16,
+		.iv	= "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F",
+		.input	= "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+			  "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+			  "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+			  "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.ilen	= 496,
+		.result	= "\x8D\xFC\x81\x9C\xCB\xAA\x5A\x1C"
+			  "\x7E\x95\xCF\x40\xAB\x4D\x6F\xEA"
+			  "\xD3\xD9\xB0\x9A\xB7\xC7\xE0\x2E"
+			  "\xD1\x39\x34\x92\x8F\xFA\x14\xF1"
+			  "\xD5\xD2\x7B\x59\x1F\x35\x28\xC2"
+			  "\x20\xD9\x42\x06\xC9\x0B\x10\x04"
+			  "\xF8\x79\xCD\x32\x86\x75\x4C\xB6"
+			  "\x7B\x1C\x52\xB1\x91\x64\x22\x4B"
+			  "\x13\xC7\xAE\x98\x0E\xB5\xCF\x6F"
+			  "\x3F\xF4\x43\x96\x73\x0D\xA2\x05"
+			  "\xDB\xFD\x28\x90\x2C\x56\xB9\x37"
+			  "\x5B\x69\x0C\xAD\x84\x67\xFF\x15"
+			  "\x4A\xD4\xA7\xD3\xDD\x99\x47\x3A"
+			  "\xED\x34\x35\x78\x6B\x91\xC9\x32"
+			  "\xE1\xBF\xBC\xB4\x04\x85\x6A\x39"
+			  "\xC0\xBA\x51\xD0\x0F\x4E\xD1\xE2"
+			  "\x1C\xFD\x0E\x05\x07\xF4\x10\xED"
+			  "\xA2\x17\xFF\xF5\x64\xC6\x1A\x22"
+			  "\xAD\x78\xE7\xD7\x11\xE9\x99\xB9"
+			  "\xAA\xEC\x6F\xF8\x3B\xBF\xCE\x77"
+			  "\x93\xE8\xAD\x1D\x50\x6C\xAE\xBC"
+			  "\xBA\x5C\x80\xD1\x91\x65\x51\x1B"
+			  "\xE8\x0A\xCD\x99\x96\x71\x3D\xB6"
+			  "\x78\x75\x37\x55\xC1\xF5\x90\x40"
+			  "\x34\xF4\x7E\xC8\xCC\x3A\x5F\x6E"
+			  "\x36\xA1\xA1\xC2\x3A\x72\x42\x8E"
+			  "\x0E\x37\x88\xE8\xCE\x83\xCB\xAD"
+			  "\xE0\x69\x77\x50\xC7\x0C\x99\xCA"
+			  "\x19\x5B\x30\x25\x9A\xEF\x9B\x0C"
+			  "\xEF\x8F\x74\x4C\xCF\x49\x4E\xB9"
+			  "\xC5\xAE\x9E\x2E\x78\x9A\xB9\x48"
+			  "\xD5\x81\xE4\x37\x1D\xBF\x27\xD9"
+			  "\xC5\xD6\x65\x43\x45\x8C\xBB\xB6"
+			  "\x55\xF4\x06\xBB\x49\x53\x8B\x1B"
+			  "\x07\xA9\x96\x69\x5B\xCB\x0F\xBC"
+			  "\x93\x85\x90\x0F\x0A\x68\x40\x2A"
+			  "\x95\xED\x2D\x88\xBF\x71\xD0\xBB"
+			  "\xEC\xB0\x77\x6C\x79\xFC\x3C\x05"
+			  "\x49\x3F\xB8\x24\xEF\x8E\x09\xA2"
+			  "\x1D\xEF\x92\x02\x96\xD4\x7F\xC8"
+			  "\x03\xB2\xCA\xDB\x17\x5C\x52\xCF"
+			  "\xDD\x70\x37\x63\xAA\xA5\x83\x20"
+			  "\x52\x02\xF6\xB9\xE7\x6E\x0A\xB6"
+			  "\x79\x03\xA0\xDA\xA3\x79\x21\xBD"
+			  "\xE3\x37\x3A\xC0\xF7\x2C\x32\xBE"
+			  "\x8B\xE8\xA6\x00\xC7\x32\xD5\x06"
+			  "\xBB\xE3\xAB\x06\x21\x82\xB8\x32"
+			  "\x31\x34\x2A\xA7\x1F\x64\x99\xBF"
+			  "\xFA\xDA\x3D\x75\xF7\x48\xD5\x48"
+			  "\x4B\x52\x7E\xF6\x7C\xAB\x67\x59"
+			  "\xC5\xDC\xA8\xC6\x63\x85\x4A\xDF"
+			  "\xF0\x40\x5F\xCF\xE3\x58\x52\x67"
+			  "\x7A\x24\x32\xC5\xEC\x9E\xA9\x6F"
+			  "\x58\x56\xDD\x94\x1F\x71\x8D\xF4"
+			  "\x6E\xFF\x2C\xA7\xA5\xD8\xBA\xAF"
+			  "\x1D\x8B\xA2\x46\xB5\xC4\x9F\x57"
+			  "\x8D\xD8\xB3\x3C\x02\x0D\xBB\x84"
+			  "\xC7\xBD\xB4\x9A\x6E\xBB\xB1\x37"
+			  "\x95\x79\xC4\xA7\xEA\x1D\xDC\x33"
+			  "\x5D\x0B\x3F\x03\x8F\x30\xF9\xAE"
+			  "\x4F\xFE\x24\x9C\x9A\x02\xE5\x57"
+			  "\xF5\xBC\x25\xD6\x02\x56\x57\x1C",
+		.rlen	= 496,
+	},
+};
+
+static struct cipher_testvec cast5_dec_tv_template[] = {
+	{
+		.key	= "\x01\x23\x45\x67\x12\x34\x56\x78"
+			  "\x23\x45\x67\x89\x34\x56\x78\x9a",
+		.klen	= 16,
+		.input	= "\x23\x8b\x4f\xe5\x84\x7e\x44\xb2",
+		.ilen	= 8,
+		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.rlen	= 8,
+	}, {
+		.key	= "\x01\x23\x45\x67\x12\x34\x56\x78"
+			  "\x23\x45",
+		.klen	= 10,
+		.input	= "\xeb\x6a\x71\x1a\x2c\x02\x27\x1b",
+		.ilen	= 8,
+		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.rlen	= 8,
+	}, {
+		.key	= "\x01\x23\x45\x67\x12",
+		.klen	= 5,
+		.input	= "\x7a\xc8\x16\xd1\x6e\x9b\x30\x2e",
+		.ilen	= 8,
+		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
+		.rlen	= 8,
+	}, { /* Generated from TF test vectors */
+		.key	= "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+			  "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A",
+		.klen	= 16,
+		.iv	= "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F",
+		.input	= "\x8D\xFC\x81\x9C\xCB\xAA\x5A\x1C"
+			  "\x7E\x95\xCF\x40\xAB\x4D\x6F\xEA"
+			  "\xD3\xD9\xB0\x9A\xB7\xC7\xE0\x2E"
+			  "\xD1\x39\x34\x92\x8F\xFA\x14\xF1"
+			  "\xD5\xD2\x7B\x59\x1F\x35\x28\xC2"
+			  "\x20\xD9\x42\x06\xC9\x0B\x10\x04"
+			  "\xF8\x79\xCD\x32\x86\x75\x4C\xB6"
+			  "\x7B\x1C\x52\xB1\x91\x64\x22\x4B"
+			  "\x13\xC7\xAE\x98\x0E\xB5\xCF\x6F"
+			  "\x3F\xF4\x43\x96\x73\x0D\xA2\x05"
+			  "\xDB\xFD\x28\x90\x2C\x56\xB9\x37"
+			  "\x5B\x69\x0C\xAD\x84\x67\xFF\x15"
+			  "\x4A\xD4\xA7\xD3\xDD\x99\x47\x3A"
+			  "\xED\x34\x35\x78\x6B\x91\xC9\x32"
+			  "\xE1\xBF\xBC\xB4\x04\x85\x6A\x39"
+			  "\xC0\xBA\x51\xD0\x0F\x4E\xD1\xE2"
+			  "\x1C\xFD\x0E\x05\x07\xF4\x10\xED"
+			  "\xA2\x17\xFF\xF5\x64\xC6\x1A\x22"
+			  "\xAD\x78\xE7\xD7\x11\xE9\x99\xB9"
+			  "\xAA\xEC\x6F\xF8\x3B\xBF\xCE\x77"
+			  "\x93\xE8\xAD\x1D\x50\x6C\xAE\xBC"
+			  "\xBA\x5C\x80\xD1\x91\x65\x51\x1B"
+			  "\xE8\x0A\xCD\x99\x96\x71\x3D\xB6"
+			  "\x78\x75\x37\x55\xC1\xF5\x90\x40"
+			  "\x34\xF4\x7E\xC8\xCC\x3A\x5F\x6E"
+			  "\x36\xA1\xA1\xC2\x3A\x72\x42\x8E"
+			  "\x0E\x37\x88\xE8\xCE\x83\xCB\xAD"
+			  "\xE0\x69\x77\x50\xC7\x0C\x99\xCA"
+			  "\x19\x5B\x30\x25\x9A\xEF\x9B\x0C"
+			  "\xEF\x8F\x74\x4C\xCF\x49\x4E\xB9"
+			  "\xC5\xAE\x9E\x2E\x78\x9A\xB9\x48"
+			  "\xD5\x81\xE4\x37\x1D\xBF\x27\xD9"
+			  "\xC5\xD6\x65\x43\x45\x8C\xBB\xB6"
+			  "\x55\xF4\x06\xBB\x49\x53\x8B\x1B"
+			  "\x07\xA9\x96\x69\x5B\xCB\x0F\xBC"
+			  "\x93\x85\x90\x0F\x0A\x68\x40\x2A"
+			  "\x95\xED\x2D\x88\xBF\x71\xD0\xBB"
+			  "\xEC\xB0\x77\x6C\x79\xFC\x3C\x05"
+			  "\x49\x3F\xB8\x24\xEF\x8E\x09\xA2"
+			  "\x1D\xEF\x92\x02\x96\xD4\x7F\xC8"
+			  "\x03\xB2\xCA\xDB\x17\x5C\x52\xCF"
+			  "\xDD\x70\x37\x63\xAA\xA5\x83\x20"
+			  "\x52\x02\xF6\xB9\xE7\x6E\x0A\xB6"
+			  "\x79\x03\xA0\xDA\xA3\x79\x21\xBD"
+			  "\xE3\x37\x3A\xC0\xF7\x2C\x32\xBE"
+			  "\x8B\xE8\xA6\x00\xC7\x32\xD5\x06"
+			  "\xBB\xE3\xAB\x06\x21\x82\xB8\x32"
+			  "\x31\x34\x2A\xA7\x1F\x64\x99\xBF"
+			  "\xFA\xDA\x3D\x75\xF7\x48\xD5\x48"
+			  "\x4B\x52\x7E\xF6\x7C\xAB\x67\x59"
+			  "\xC5\xDC\xA8\xC6\x63\x85\x4A\xDF"
+			  "\xF0\x40\x5F\xCF\xE3\x58\x52\x67"
+			  "\x7A\x24\x32\xC5\xEC\x9E\xA9\x6F"
+			  "\x58\x56\xDD\x94\x1F\x71\x8D\xF4"
+			  "\x6E\xFF\x2C\xA7\xA5\xD8\xBA\xAF"
+			  "\x1D\x8B\xA2\x46\xB5\xC4\x9F\x57"
+			  "\x8D\xD8\xB3\x3C\x02\x0D\xBB\x84"
+			  "\xC7\xBD\xB4\x9A\x6E\xBB\xB1\x37"
+			  "\x95\x79\xC4\xA7\xEA\x1D\xDC\x33"
+			  "\x5D\x0B\x3F\x03\x8F\x30\xF9\xAE"
+			  "\x4F\xFE\x24\x9C\x9A\x02\xE5\x57"
+			  "\xF5\xBC\x25\xD6\x02\x56\x57\x1C",
+		.ilen	= 496,
+		.result	= "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+			  "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+			  "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+			  "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.rlen	= 496,
+	},
+};
+
+static struct cipher_testvec cast5_cbc_enc_tv_template[] = {
+	{ /* Generated from TF test vectors */
+		.key	= "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+			  "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A",
+		.klen	= 16,
+		.iv	= "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F",
+		.input	= "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+			  "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+			  "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+			  "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.ilen	= 496,
+		.result	= "\x05\x28\xCE\x61\x90\x80\xE1\x78"
+			  "\xB9\x2A\x97\x7C\xB0\x83\xD8\x1A"
+			  "\xDE\x58\x7F\xD7\xFD\x72\xB8\xFB"
+			  "\xDA\xF0\x6E\x77\x14\x47\x82\xBA"
+			  "\x29\x0E\x25\x6E\xB4\x39\xD9\x7F"
+			  "\x05\xA7\xA7\x3A\xC1\x5D\x9E\x39"
+			  "\xA7\xFB\x0D\x05\x00\xF3\x58\x67"
+			  "\x60\xEC\x73\x77\x46\x85\x9B\x6A"
+			  "\x08\x3E\xBE\x59\xFB\xE4\x96\x34"
+			  "\xB4\x05\x49\x1A\x97\x43\xAD\xA0"
+			  "\xA9\x1E\x6E\x74\xF1\x94\xEC\xA8"
+			  "\xB5\x8A\x20\xEA\x89\x6B\x19\xAA"
+			  "\xA7\xF1\x33\x67\x90\x23\x0D\xEE"
+			  "\x81\xD5\x78\x4F\xD3\x63\xEA\x46"
+			  "\xB5\xB2\x6E\xBB\xCA\x76\x06\x10"
+			  "\x96\x2A\x0A\xBA\xF9\x41\x5A\x1D"
+			  "\x36\x7C\x56\x14\x54\x83\xFA\xA1"
+			  "\x27\xDD\xBA\x8A\x90\x29\xD6\xA6"
+			  "\xFA\x48\x3E\x1E\x23\x6E\x98\xA8"
+			  "\xA7\xD9\x67\x92\x5C\x13\xB4\x71"
+			  "\xA8\xAA\x89\x4A\xA4\xB3\x49\x7C"
+			  "\x7D\x7F\xCE\x6F\x29\x2E\x7E\x37"
+			  "\xC8\x52\x60\xD9\xE7\xCA\x60\x98"
+			  "\xED\xCD\xE8\x60\x83\xAD\x34\x4D"
+			  "\x96\x4A\x99\x2B\xB7\x14\x75\x66"
+			  "\x6C\x2C\x1A\xBA\x4B\xBB\x49\x56"
+			  "\xE1\x86\xA2\x0E\xD0\xF0\x07\xD3"
+			  "\x18\x38\x09\x9C\x0E\x8B\x86\x07"
+			  "\x90\x12\x37\x49\x27\x98\x69\x18"
+			  "\xB0\xCC\xFB\xD3\xBD\x04\xA0\x85"
+			  "\x4B\x22\x97\x07\xB6\x97\xE9\x95"
+			  "\x0F\x88\x36\xA9\x44\x00\xC6\xE9"
+			  "\x27\x53\x5C\x5B\x1F\xD3\xE2\xEE"
+			  "\xD0\xCD\x63\x30\xA9\xC0\xDD\x49"
+			  "\xFE\x16\xA4\x07\x0D\xE2\x5D\x97"
+			  "\xDE\x89\xBA\x2E\xF3\xA9\x5E\xBE"
+			  "\x03\x55\x0E\x02\x41\x4A\x45\x06"
+			  "\xBE\xEA\x32\xF2\xDC\x91\x5C\x20"
+			  "\x94\x02\x30\xD2\xFC\x29\xFA\x8E"
+			  "\x34\xA0\x31\xB8\x34\xBA\xAE\x54"
+			  "\xB5\x88\x1F\xDC\x43\xDC\x22\x9F"
+			  "\xDC\xCE\xD3\xFA\xA4\xA8\xBC\x8A"
+			  "\xC7\x5A\x43\x21\xA5\xB1\xDB\xC3"
+			  "\x84\x3B\xB4\x9B\xB5\xA7\xF1\x0A"
+			  "\xB6\x37\x21\x19\x55\xC2\xBD\x99"
+			  "\x49\x24\xBB\x7C\xB3\x8E\xEF\xD2"
+			  "\x3A\xCF\xA0\x31\x28\x0E\x25\xA2"
+			  "\x11\xB4\x18\x17\x1A\x65\x92\x56"
+			  "\xE8\xE0\x52\x9C\x61\x18\x2A\xB1"
+			  "\x1A\x01\x22\x45\x17\x62\x52\x6C"
+			  "\x91\x44\xCF\x98\xC7\xC0\x79\x26"
+			  "\x32\x66\x6F\x23\x7F\x94\x36\x88"
+			  "\x3C\xC9\xD0\xB7\x45\x30\x31\x86"
+			  "\x3D\xC6\xA3\x98\x62\x84\x1A\x8B"
+			  "\x16\x88\xC7\xA3\xE9\x4F\xE0\x86"
+			  "\xA4\x93\xA8\x34\x5A\xCA\xDF\xCA"
+			  "\x46\x38\xD2\xF4\xE0\x2D\x1E\xC9"
+			  "\x7C\xEF\x53\xB7\x60\x72\x41\xBF"
+			  "\x29\x00\x87\x02\xAF\x44\x4C\xB7"
+			  "\x8C\xF5\x3F\x19\xF4\x80\x45\xA7"
+			  "\x15\x5F\xDB\xE9\xB1\x83\xD2\xE6"
+			  "\x1D\x18\x66\x44\x5B\x8F\x14\xEB",
+		.rlen	= 496,
+	},
+};
+
+static struct cipher_testvec cast5_cbc_dec_tv_template[] = {
+	{ /* Generated from TF test vectors */
+		.key	= "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+			  "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A",
+		.klen	= 16,
+		.iv	= "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F",
+		.input	= "\x05\x28\xCE\x61\x90\x80\xE1\x78"
+			  "\xB9\x2A\x97\x7C\xB0\x83\xD8\x1A"
+			  "\xDE\x58\x7F\xD7\xFD\x72\xB8\xFB"
+			  "\xDA\xF0\x6E\x77\x14\x47\x82\xBA"
+			  "\x29\x0E\x25\x6E\xB4\x39\xD9\x7F"
+			  "\x05\xA7\xA7\x3A\xC1\x5D\x9E\x39"
+			  "\xA7\xFB\x0D\x05\x00\xF3\x58\x67"
+			  "\x60\xEC\x73\x77\x46\x85\x9B\x6A"
+			  "\x08\x3E\xBE\x59\xFB\xE4\x96\x34"
+			  "\xB4\x05\x49\x1A\x97\x43\xAD\xA0"
+			  "\xA9\x1E\x6E\x74\xF1\x94\xEC\xA8"
+			  "\xB5\x8A\x20\xEA\x89\x6B\x19\xAA"
+			  "\xA7\xF1\x33\x67\x90\x23\x0D\xEE"
+			  "\x81\xD5\x78\x4F\xD3\x63\xEA\x46"
+			  "\xB5\xB2\x6E\xBB\xCA\x76\x06\x10"
+			  "\x96\x2A\x0A\xBA\xF9\x41\x5A\x1D"
+			  "\x36\x7C\x56\x14\x54\x83\xFA\xA1"
+			  "\x27\xDD\xBA\x8A\x90\x29\xD6\xA6"
+			  "\xFA\x48\x3E\x1E\x23\x6E\x98\xA8"
+			  "\xA7\xD9\x67\x92\x5C\x13\xB4\x71"
+			  "\xA8\xAA\x89\x4A\xA4\xB3\x49\x7C"
+			  "\x7D\x7F\xCE\x6F\x29\x2E\x7E\x37"
+			  "\xC8\x52\x60\xD9\xE7\xCA\x60\x98"
+			  "\xED\xCD\xE8\x60\x83\xAD\x34\x4D"
+			  "\x96\x4A\x99\x2B\xB7\x14\x75\x66"
+			  "\x6C\x2C\x1A\xBA\x4B\xBB\x49\x56"
+			  "\xE1\x86\xA2\x0E\xD0\xF0\x07\xD3"
+			  "\x18\x38\x09\x9C\x0E\x8B\x86\x07"
+			  "\x90\x12\x37\x49\x27\x98\x69\x18"
+			  "\xB0\xCC\xFB\xD3\xBD\x04\xA0\x85"
+			  "\x4B\x22\x97\x07\xB6\x97\xE9\x95"
+			  "\x0F\x88\x36\xA9\x44\x00\xC6\xE9"
+			  "\x27\x53\x5C\x5B\x1F\xD3\xE2\xEE"
+			  "\xD0\xCD\x63\x30\xA9\xC0\xDD\x49"
+			  "\xFE\x16\xA4\x07\x0D\xE2\x5D\x97"
+			  "\xDE\x89\xBA\x2E\xF3\xA9\x5E\xBE"
+			  "\x03\x55\x0E\x02\x41\x4A\x45\x06"
+			  "\xBE\xEA\x32\xF2\xDC\x91\x5C\x20"
+			  "\x94\x02\x30\xD2\xFC\x29\xFA\x8E"
+			  "\x34\xA0\x31\xB8\x34\xBA\xAE\x54"
+			  "\xB5\x88\x1F\xDC\x43\xDC\x22\x9F"
+			  "\xDC\xCE\xD3\xFA\xA4\xA8\xBC\x8A"
+			  "\xC7\x5A\x43\x21\xA5\xB1\xDB\xC3"
+			  "\x84\x3B\xB4\x9B\xB5\xA7\xF1\x0A"
+			  "\xB6\x37\x21\x19\x55\xC2\xBD\x99"
+			  "\x49\x24\xBB\x7C\xB3\x8E\xEF\xD2"
+			  "\x3A\xCF\xA0\x31\x28\x0E\x25\xA2"
+			  "\x11\xB4\x18\x17\x1A\x65\x92\x56"
+			  "\xE8\xE0\x52\x9C\x61\x18\x2A\xB1"
+			  "\x1A\x01\x22\x45\x17\x62\x52\x6C"
+			  "\x91\x44\xCF\x98\xC7\xC0\x79\x26"
+			  "\x32\x66\x6F\x23\x7F\x94\x36\x88"
+			  "\x3C\xC9\xD0\xB7\x45\x30\x31\x86"
+			  "\x3D\xC6\xA3\x98\x62\x84\x1A\x8B"
+			  "\x16\x88\xC7\xA3\xE9\x4F\xE0\x86"
+			  "\xA4\x93\xA8\x34\x5A\xCA\xDF\xCA"
+			  "\x46\x38\xD2\xF4\xE0\x2D\x1E\xC9"
+			  "\x7C\xEF\x53\xB7\x60\x72\x41\xBF"
+			  "\x29\x00\x87\x02\xAF\x44\x4C\xB7"
+			  "\x8C\xF5\x3F\x19\xF4\x80\x45\xA7"
+			  "\x15\x5F\xDB\xE9\xB1\x83\xD2\xE6"
+			  "\x1D\x18\x66\x44\x5B\x8F\x14\xEB",
+		.ilen	= 496,
+		.result	= "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+			  "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+			  "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+			  "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.rlen	= 496,
+	},
+};
 
-static struct cipher_testvec cast5_enc_tv_template[] = {
-	{
-		.key	= "\x01\x23\x45\x67\x12\x34\x56\x78"
-			  "\x23\x45\x67\x89\x34\x56\x78\x9a",
+static struct cipher_testvec cast5_ctr_enc_tv_template[] = {
+	{ /* Generated from TF test vectors */
+		.key	= "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+			  "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A",
 		.klen	= 16,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.ilen	= 8,
-		.result	= "\x23\x8b\x4f\xe5\x84\x7e\x44\xb2",
-		.rlen	= 8,
-	}, {
-		.key	= "\x01\x23\x45\x67\x12\x34\x56\x78"
-			  "\x23\x45",
-		.klen	= 10,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.ilen	= 8,
-		.result	= "\xeb\x6a\x71\x1a\x2c\x02\x27\x1b",
-		.rlen	= 8,
-	}, {
-		.key	= "\x01\x23\x45\x67\x12",
-		.klen	= 5,
-		.input	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.ilen	= 8,
-		.result	= "\x7a\xc8\x16\xd1\x6e\x9b\x30\x2e",
-		.rlen	= 8,
+		.iv	= "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F",
+		.input	= "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+			  "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+			  "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+			  "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.ilen	= 496,
+		.result	= "\xFF\xC4\x2E\x82\x3D\xF8\xA8\x39"
+			  "\x7C\x52\xC4\xD3\xBB\x62\xC6\xA8"
+			  "\x0C\x63\xA5\x55\xE3\xF8\x1C\x7F"
+			  "\xDC\x59\xF9\xA0\x52\xAD\x83\xDF"
+			  "\xD5\x3B\x53\x4A\xAA\x1F\x49\x44"
+			  "\xE8\x20\xCC\xF8\x97\xE6\xE0\x3C"
+			  "\x5A\xD2\x83\xEC\xEE\x25\x3F\xCF"
+			  "\x0D\xC2\x79\x80\x99\x6E\xFF\x7B"
+			  "\x64\xB0\x7B\x86\x29\x1D\x9F\x17"
+			  "\x10\xA5\xA5\xEB\x16\x55\x9E\xE3"
+			  "\x88\x18\x52\x56\x48\x58\xD1\x6B"
+			  "\xE8\x74\x6E\x48\xB0\x2E\x69\x63"
+			  "\x32\xAA\xAC\x26\x55\x45\x94\xDE"
+			  "\x30\x26\x26\xE6\x08\x82\x2F\x5F"
+			  "\xA7\x15\x94\x07\x75\x2D\xC6\x3A"
+			  "\x1B\xA0\x39\xFB\xBA\xB9\x06\x56"
+			  "\xF6\x9F\xF1\x2F\x9B\xF3\x89\x8B"
+			  "\x08\xC8\x9D\x5E\x6B\x95\x09\xC7"
+			  "\x98\xB7\x62\xA4\x1D\x25\xFA\xC5"
+			  "\x62\xC8\x5D\x6B\xB4\x85\x88\x7F"
+			  "\x3B\x29\xF9\xB4\x32\x62\x69\xBF"
+			  "\x32\xB8\xEB\xFD\x0E\x26\xAA\xA3"
+			  "\x44\x67\x90\x20\xAC\x41\xDF\x43"
+			  "\xC6\xC7\x19\x9F\x2C\x28\x74\xEB"
+			  "\x3E\x7F\x7A\x80\x5B\xE4\x08\x60"
+			  "\xC7\xC9\x71\x34\x44\xCE\x05\xFD"
+			  "\xA8\x91\xA8\x44\x5E\xD3\x89\x2C"
+			  "\xAE\x59\x0F\x07\x88\x79\x53\x26"
+			  "\xAF\xAC\xCB\x1D\x6F\x08\x25\x62"
+			  "\xD0\x82\x65\x66\xE4\x2A\x29\x1C"
+			  "\x9C\x64\x5F\x49\x9D\xF8\x62\xF9"
+			  "\xED\xC4\x13\x52\x75\xDC\xE4\xF9"
+			  "\x68\x0F\x8A\xCD\xA6\x8D\x75\xAA"
+			  "\x49\xA1\x86\x86\x37\x5C\x6B\x3D"
+			  "\x56\xE5\x6F\xBE\x27\xC0\x10\xF8"
+			  "\x3C\x4D\x17\x35\x14\xDC\x1C\xA0"
+			  "\x6E\xAE\xD1\x10\xDD\x83\x06\xC2"
+			  "\x23\xD3\xC7\x27\x15\x04\x2C\x27"
+			  "\xDD\x1F\x2E\x97\x09\x9C\x33\x7D"
+			  "\xAC\x50\x1B\x2E\xC9\x52\x0C\x14"
+			  "\x4B\x78\xC4\xDE\x07\x6A\x12\x02"
+			  "\x6E\xD7\x4B\x91\xB9\x88\x4D\x02"
+			  "\xC3\xB5\x04\xBC\xE0\x67\xCA\x18"
+			  "\x22\xA1\xAE\x9A\x21\xEF\xB2\x06"
+			  "\x35\xCD\xEC\x37\x70\x2D\xFC\x1E"
+			  "\xA8\x31\xE7\xFC\xE5\x8E\x88\x66"
+			  "\x16\xB5\xC8\x45\x21\x37\xBD\x24"
+			  "\xA9\xD5\x36\x12\x9F\x6E\x67\x80"
+			  "\x87\x54\xD5\xAF\x97\xE1\x15\xA7"
+			  "\x11\xF0\x63\x7B\xE1\x44\x14\x1C"
+			  "\x06\x32\x05\x8C\x6C\xDB\x9B\x36"
+			  "\x6A\x6B\xAD\x3A\x27\x55\x20\x4C"
+			  "\x76\x36\x43\xE8\x16\x60\xB5\xF3"
+			  "\xDF\x5A\xC6\xA5\x69\x78\x59\x51"
+			  "\x54\x68\x65\x06\x84\xDE\x3D\xAE"
+			  "\x38\x91\xBD\xCC\xA2\x8A\xEC\xE6"
+			  "\x9E\x83\xAE\x1E\x8E\x34\x5D\xDE"
+			  "\x91\xCE\x8F\xED\x40\xF7\xC8\x8B"
+			  "\x9A\x13\x4C\xAD\x89\x97\x9E\xD1"
+			  "\x91\x01\xD7\x21\x23\x28\x1E\xCC"
+			  "\x8C\x98\xDB\xDE\xFC\x72\x94\xAA"
+			  "\xC0\x0D\x96\xAA\x23\xF8\xFE\x13",
+		.rlen	= 496,
 	},
 };
 
-static struct cipher_testvec cast5_dec_tv_template[] = {
-	{
-		.key	= "\x01\x23\x45\x67\x12\x34\x56\x78"
-			  "\x23\x45\x67\x89\x34\x56\x78\x9a",
+static struct cipher_testvec cast5_ctr_dec_tv_template[] = {
+	{ /* Generated from TF test vectors */
+		.key	= "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+			  "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A",
 		.klen	= 16,
-		.input	= "\x23\x8b\x4f\xe5\x84\x7e\x44\xb2",
-		.ilen	= 8,
-		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.rlen	= 8,
-	}, {
-		.key	= "\x01\x23\x45\x67\x12\x34\x56\x78"
-			  "\x23\x45",
-		.klen	= 10,
-		.input	= "\xeb\x6a\x71\x1a\x2c\x02\x27\x1b",
-		.ilen	= 8,
-		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.rlen	= 8,
-	}, {
-		.key	= "\x01\x23\x45\x67\x12",
-		.klen	= 5,
-		.input	= "\x7a\xc8\x16\xd1\x6e\x9b\x30\x2e",
-		.ilen	= 8,
-		.result	= "\x01\x23\x45\x67\x89\xab\xcd\xef",
-		.rlen	= 8,
+		.iv	= "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F",
+		.input	= "\xFF\xC4\x2E\x82\x3D\xF8\xA8\x39"
+			  "\x7C\x52\xC4\xD3\xBB\x62\xC6\xA8"
+			  "\x0C\x63\xA5\x55\xE3\xF8\x1C\x7F"
+			  "\xDC\x59\xF9\xA0\x52\xAD\x83\xDF"
+			  "\xD5\x3B\x53\x4A\xAA\x1F\x49\x44"
+			  "\xE8\x20\xCC\xF8\x97\xE6\xE0\x3C"
+			  "\x5A\xD2\x83\xEC\xEE\x25\x3F\xCF"
+			  "\x0D\xC2\x79\x80\x99\x6E\xFF\x7B"
+			  "\x64\xB0\x7B\x86\x29\x1D\x9F\x17"
+			  "\x10\xA5\xA5\xEB\x16\x55\x9E\xE3"
+			  "\x88\x18\x52\x56\x48\x58\xD1\x6B"
+			  "\xE8\x74\x6E\x48\xB0\x2E\x69\x63"
+			  "\x32\xAA\xAC\x26\x55\x45\x94\xDE"
+			  "\x30\x26\x26\xE6\x08\x82\x2F\x5F"
+			  "\xA7\x15\x94\x07\x75\x2D\xC6\x3A"
+			  "\x1B\xA0\x39\xFB\xBA\xB9\x06\x56"
+			  "\xF6\x9F\xF1\x2F\x9B\xF3\x89\x8B"
+			  "\x08\xC8\x9D\x5E\x6B\x95\x09\xC7"
+			  "\x98\xB7\x62\xA4\x1D\x25\xFA\xC5"
+			  "\x62\xC8\x5D\x6B\xB4\x85\x88\x7F"
+			  "\x3B\x29\xF9\xB4\x32\x62\x69\xBF"
+			  "\x32\xB8\xEB\xFD\x0E\x26\xAA\xA3"
+			  "\x44\x67\x90\x20\xAC\x41\xDF\x43"
+			  "\xC6\xC7\x19\x9F\x2C\x28\x74\xEB"
+			  "\x3E\x7F\x7A\x80\x5B\xE4\x08\x60"
+			  "\xC7\xC9\x71\x34\x44\xCE\x05\xFD"
+			  "\xA8\x91\xA8\x44\x5E\xD3\x89\x2C"
+			  "\xAE\x59\x0F\x07\x88\x79\x53\x26"
+			  "\xAF\xAC\xCB\x1D\x6F\x08\x25\x62"
+			  "\xD0\x82\x65\x66\xE4\x2A\x29\x1C"
+			  "\x9C\x64\x5F\x49\x9D\xF8\x62\xF9"
+			  "\xED\xC4\x13\x52\x75\xDC\xE4\xF9"
+			  "\x68\x0F\x8A\xCD\xA6\x8D\x75\xAA"
+			  "\x49\xA1\x86\x86\x37\x5C\x6B\x3D"
+			  "\x56\xE5\x6F\xBE\x27\xC0\x10\xF8"
+			  "\x3C\x4D\x17\x35\x14\xDC\x1C\xA0"
+			  "\x6E\xAE\xD1\x10\xDD\x83\x06\xC2"
+			  "\x23\xD3\xC7\x27\x15\x04\x2C\x27"
+			  "\xDD\x1F\x2E\x97\x09\x9C\x33\x7D"
+			  "\xAC\x50\x1B\x2E\xC9\x52\x0C\x14"
+			  "\x4B\x78\xC4\xDE\x07\x6A\x12\x02"
+			  "\x6E\xD7\x4B\x91\xB9\x88\x4D\x02"
+			  "\xC3\xB5\x04\xBC\xE0\x67\xCA\x18"
+			  "\x22\xA1\xAE\x9A\x21\xEF\xB2\x06"
+			  "\x35\xCD\xEC\x37\x70\x2D\xFC\x1E"
+			  "\xA8\x31\xE7\xFC\xE5\x8E\x88\x66"
+			  "\x16\xB5\xC8\x45\x21\x37\xBD\x24"
+			  "\xA9\xD5\x36\x12\x9F\x6E\x67\x80"
+			  "\x87\x54\xD5\xAF\x97\xE1\x15\xA7"
+			  "\x11\xF0\x63\x7B\xE1\x44\x14\x1C"
+			  "\x06\x32\x05\x8C\x6C\xDB\x9B\x36"
+			  "\x6A\x6B\xAD\x3A\x27\x55\x20\x4C"
+			  "\x76\x36\x43\xE8\x16\x60\xB5\xF3"
+			  "\xDF\x5A\xC6\xA5\x69\x78\x59\x51"
+			  "\x54\x68\x65\x06\x84\xDE\x3D\xAE"
+			  "\x38\x91\xBD\xCC\xA2\x8A\xEC\xE6"
+			  "\x9E\x83\xAE\x1E\x8E\x34\x5D\xDE"
+			  "\x91\xCE\x8F\xED\x40\xF7\xC8\x8B"
+			  "\x9A\x13\x4C\xAD\x89\x97\x9E\xD1"
+			  "\x91\x01\xD7\x21\x23\x28\x1E\xCC"
+			  "\x8C\x98\xDB\xDE\xFC\x72\x94\xAA"
+			  "\xC0\x0D\x96\xAA\x23\xF8\xFE\x13",
+		.ilen	= 496,
+		.result	= "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+			  "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+			  "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+			  "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+			  "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+			  "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+			  "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+			  "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+			  "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+			  "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+			  "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+			  "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+			  "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+			  "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+			  "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+			  "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+			  "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+			  "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+			  "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+			  "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+			  "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+			  "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+			  "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+			  "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+			  "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+			  "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+			  "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+			  "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+			  "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+			  "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+			  "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+			  "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+			  "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+			  "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+			  "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+			  "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+			  "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+			  "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+			  "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+			  "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+			  "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+			  "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+			  "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+			  "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+			  "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+			  "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+			  "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+			  "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+			  "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+			  "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+			  "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+			  "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+			  "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+			  "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+			  "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+			  "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+			  "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+			  "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+			  "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+			  "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+			  "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+			  "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+		.rlen	= 496,
 	},
 };
 
diff --git a/crypto/tgr192.c b/crypto/tgr192.c
index cbca4f2..8740355 100644
--- a/crypto/tgr192.c
+++ b/crypto/tgr192.c
@@ -628,7 +628,7 @@ static int tgr128_final(struct shash_desc *desc, u8 * out)
 	return 0;
 }
 
-static struct shash_alg tgr192 = {
+static struct shash_alg tgr_algs[3] = { {
 	.digestsize	=	TGR192_DIGEST_SIZE,
 	.init		=	tgr192_init,
 	.update		=	tgr192_update,
@@ -640,9 +640,7 @@ static struct shash_alg tgr192 = {
 		.cra_blocksize	=	TGR192_BLOCK_SIZE,
 		.cra_module	=	THIS_MODULE,
 	}
-};
-
-static struct shash_alg tgr160 = {
+}, {
 	.digestsize	=	TGR160_DIGEST_SIZE,
 	.init		=	tgr192_init,
 	.update		=	tgr192_update,
@@ -654,9 +652,7 @@ static struct shash_alg tgr160 = {
 		.cra_blocksize	=	TGR192_BLOCK_SIZE,
 		.cra_module	=	THIS_MODULE,
 	}
-};
-
-static struct shash_alg tgr128 = {
+}, {
 	.digestsize	=	TGR128_DIGEST_SIZE,
 	.init		=	tgr192_init,
 	.update		=	tgr192_update,
@@ -668,38 +664,16 @@ static struct shash_alg tgr128 = {
 		.cra_blocksize	=	TGR192_BLOCK_SIZE,
 		.cra_module	=	THIS_MODULE,
 	}
-};
+} };
 
 static int __init tgr192_mod_init(void)
 {
-	int ret = 0;
-
-	ret = crypto_register_shash(&tgr192);
-
-	if (ret < 0) {
-		goto out;
-	}
-
-	ret = crypto_register_shash(&tgr160);
-	if (ret < 0) {
-		crypto_unregister_shash(&tgr192);
-		goto out;
-	}
-
-	ret = crypto_register_shash(&tgr128);
-	if (ret < 0) {
-		crypto_unregister_shash(&tgr192);
-		crypto_unregister_shash(&tgr160);
-	}
-      out:
-	return ret;
+	return crypto_register_shashes(tgr_algs, ARRAY_SIZE(tgr_algs));
 }
 
 static void __exit tgr192_mod_fini(void)
 {
-	crypto_unregister_shash(&tgr192);
-	crypto_unregister_shash(&tgr160);
-	crypto_unregister_shash(&tgr128);
+	crypto_unregister_shashes(tgr_algs, ARRAY_SIZE(tgr_algs));
 }
 
 MODULE_ALIAS("tgr160");
diff --git a/crypto/twofish_generic.c b/crypto/twofish_generic.c
index 1f07b84..2d50005 100644
--- a/crypto/twofish_generic.c
+++ b/crypto/twofish_generic.c
@@ -188,7 +188,6 @@ static struct crypto_alg alg = {
 	.cra_ctxsize        =   sizeof(struct twofish_ctx),
 	.cra_alignmask      =	3,
 	.cra_module         =   THIS_MODULE,
-	.cra_list           =   LIST_HEAD_INIT(alg.cra_list),
 	.cra_u              =   { .cipher = {
 	.cia_min_keysize    =   TF_MIN_KEY_SIZE,
 	.cia_max_keysize    =   TF_MAX_KEY_SIZE,
diff --git a/crypto/wp512.c b/crypto/wp512.c
index 71719a2..180f1d6 100644
--- a/crypto/wp512.c
+++ b/crypto/wp512.c
@@ -1119,7 +1119,7 @@ static int wp256_final(struct shash_desc *desc, u8 *out)
 	return 0;
 }
 
-static struct shash_alg wp512 = {
+static struct shash_alg wp_algs[3] = { {
 	.digestsize	=	WP512_DIGEST_SIZE,
 	.init		=	wp512_init,
 	.update		=	wp512_update,
@@ -1131,9 +1131,7 @@ static struct shash_alg wp512 = {
 		.cra_blocksize	=	WP512_BLOCK_SIZE,
 		.cra_module	=	THIS_MODULE,
 	}
-};
-
-static struct shash_alg wp384 = {
+}, {
 	.digestsize	=	WP384_DIGEST_SIZE,
 	.init		=	wp512_init,
 	.update		=	wp512_update,
@@ -1145,9 +1143,7 @@ static struct shash_alg wp384 = {
 		.cra_blocksize	=	WP512_BLOCK_SIZE,
 		.cra_module	=	THIS_MODULE,
 	}
-};
-
-static struct shash_alg wp256 = {
+}, {
 	.digestsize	=	WP256_DIGEST_SIZE,
 	.init		=	wp512_init,
 	.update		=	wp512_update,
@@ -1159,39 +1155,16 @@ static struct shash_alg wp256 = {
 		.cra_blocksize	=	WP512_BLOCK_SIZE,
 		.cra_module	=	THIS_MODULE,
 	}
-};
+} };
 
 static int __init wp512_mod_init(void)
 {
-	int ret = 0;
-
-	ret = crypto_register_shash(&wp512);
-
-	if (ret < 0)
-		goto out;
-
-	ret = crypto_register_shash(&wp384);
-	if (ret < 0)
-	{
-		crypto_unregister_shash(&wp512);
-		goto out;
-	}
-
-	ret = crypto_register_shash(&wp256);
-	if (ret < 0)
-	{
-		crypto_unregister_shash(&wp512);
-		crypto_unregister_shash(&wp384);
-	}
-out:
-	return ret;
+	return crypto_register_shashes(wp_algs, ARRAY_SIZE(wp_algs));
 }
 
 static void __exit wp512_mod_fini(void)
 {
-	crypto_unregister_shash(&wp512);
-	crypto_unregister_shash(&wp384);
-	crypto_unregister_shash(&wp256);
+	crypto_unregister_shashes(wp_algs, ARRAY_SIZE(wp_algs));
 }
 
 MODULE_ALIAS("wp384");
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 24c807f..05be17a 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -52,6 +52,9 @@ MODULE_LICENSE("GPL");
 #define MEMORY_POWER_ON_STATE	1
 #define MEMORY_POWER_OFF_STATE	2
 
+static bool auto_probe;
+module_param(auto_probe, bool, S_IRUGO | S_IWUSR);
+
 static int acpi_memory_device_add(struct acpi_device *device);
 static int acpi_memory_device_remove(struct acpi_device *device, int type);
 
@@ -78,6 +81,7 @@ struct acpi_memory_info {
 	unsigned short caching;	/* memory cache attribute */
 	unsigned short write_protect;	/* memory read/write attribute */
 	unsigned int enabled:1;
+	unsigned int failed:1;
 };
 
 struct acpi_memory_device {
@@ -86,8 +90,6 @@ struct acpi_memory_device {
 	struct list_head res_list;
 };
 
-static int acpi_hotmem_initialized;
-
 static acpi_status
 acpi_memory_get_resource(struct acpi_resource *resource, void *context)
 {
@@ -125,12 +127,20 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context)
 	return AE_OK;
 }
 
+static void
+acpi_memory_free_device_resources(struct acpi_memory_device *mem_device)
+{
+	struct acpi_memory_info *info, *n;
+
+	list_for_each_entry_safe(info, n, &mem_device->res_list, list)
+		kfree(info);
+	INIT_LIST_HEAD(&mem_device->res_list);
+}
+
 static int
 acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
 {
 	acpi_status status;
-	struct acpi_memory_info *info, *n;
-
 
 	if (!list_empty(&mem_device->res_list))
 		return 0;
@@ -138,9 +148,7 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
 	status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS,
 				     acpi_memory_get_resource, mem_device);
 	if (ACPI_FAILURE(status)) {
-		list_for_each_entry_safe(info, n, &mem_device->res_list, list)
-			kfree(info);
-		INIT_LIST_HEAD(&mem_device->res_list);
+		acpi_memory_free_device_resources(mem_device);
 		return -EINVAL;
 	}
 
@@ -251,9 +259,23 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
 			node = memory_add_physaddr_to_nid(info->start_addr);
 
 		result = add_memory(node, info->start_addr, info->length);
-		if (result)
+
+		/*
+		 * If the memory block has been used by the kernel, add_memory()
+		 * returns -EEXIST. If add_memory() returns the other error, it
+		 * means that this memory block is not used by the kernel.
+		 */
+		if (result && result != -EEXIST) {
+			info->failed = 1;
 			continue;
-		info->enabled = 1;
+		}
+
+		if (!result)
+			info->enabled = 1;
+		/*
+		 * Add num_enable even if add_memory() returns -EEXIST, so the
+		 * device is bound to this driver.
+		 */
 		num_enabled++;
 	}
 	if (!num_enabled) {
@@ -317,11 +339,21 @@ static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
 	 * Note: Assume that this function returns zero on success
 	 */
 	list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
-		if (info->enabled) {
-			result = remove_memory(info->start_addr, info->length);
-			if (result)
-				return result;
-		}
+		if (info->failed)
+			/* The kernel does not use this memory block */
+			continue;
+
+		if (!info->enabled)
+			/*
+			 * The kernel uses this memory block, but it may be not
+			 * managed by us.
+			 */
+			return -EBUSY;
+
+		result = remove_memory(info->start_addr, info->length);
+		if (result)
+			return result;
+		list_del(&info->list);
 		kfree(info);
 	}
 
@@ -420,6 +452,15 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
 	return;
 }
 
+static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
+{
+	if (!mem_device)
+		return;
+
+	acpi_memory_free_device_resources(mem_device);
+	kfree(mem_device);
+}
+
 static int acpi_memory_device_add(struct acpi_device *device)
 {
 	int result;
@@ -451,35 +492,24 @@ static int acpi_memory_device_add(struct acpi_device *device)
 
 	printk(KERN_DEBUG "%s \n", acpi_device_name(device));
 
-	/*
-	 * Early boot code has recognized memory area by EFI/E820.
-	 * If DSDT shows these memory devices on boot, hotplug is not necessary
-	 * for them. So, it just returns until completion of this driver's
-	 * start up.
-	 */
-	if (!acpi_hotmem_initialized)
-		return 0;
-
 	if (!acpi_memory_check_device(mem_device)) {
 		/* call add_memory func */
 		result = acpi_memory_enable_device(mem_device);
-		if (result)
+		if (result) {
 			printk(KERN_ERR PREFIX
 				"Error in acpi_memory_enable_device\n");
+			acpi_memory_device_free(mem_device);
+		}
 	}
 	return result;
 }
 
 static int acpi_memory_device_remove(struct acpi_device *device, int type)
 {
-	struct acpi_memory_device *mem_device = NULL;
-
-
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
 
-	mem_device = acpi_driver_data(device);
-	kfree(mem_device);
+	acpi_memory_device_free(acpi_driver_data(device));
 
 	return 0;
 }
@@ -516,12 +546,44 @@ acpi_memory_register_notify_handler(acpi_handle handle,
 				    u32 level, void *ctxt, void **retv)
 {
 	acpi_status status;
-
+	struct acpi_memory_device *mem_device = NULL;
+	unsigned long long current_status;
 
 	status = is_memory_device(handle);
 	if (ACPI_FAILURE(status))
 		return AE_OK;	/* continue */
 
+	if (auto_probe) {
+		/* Get device present/absent information from the _STA */
+		status = acpi_evaluate_integer(handle, "_STA", NULL,
+					       &current_status);
+		if (ACPI_FAILURE(status))
+			goto install;
+
+		/*
+		 * Check for device status. Device should be
+		 * present/enabled/functioning.
+		 */
+		if (!(current_status &
+		      (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
+		       ACPI_STA_DEVICE_FUNCTIONING)))
+			goto install;
+
+		if (acpi_memory_get_device(handle, &mem_device))
+			goto install;
+
+		/* We have bound this device while we register the driver */
+		if (mem_device->state == MEMORY_POWER_ON_STATE)
+			goto install;
+
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				  "\nauto probe memory device\n"));
+
+		if (acpi_memory_enable_device(mem_device))
+			pr_err(PREFIX "Cannot enable memory device\n");
+	}
+
+install:
 	status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
 					     acpi_memory_device_notify, NULL);
 	/* continue */
@@ -568,7 +630,6 @@ static int __init acpi_memory_device_init(void)
 		return -ENODEV;
 	}
 
-	acpi_hotmem_initialized = 1;
 	return 0;
 }
 
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index edda74a..804204d 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -708,6 +708,40 @@ static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
 		return -EINVAL;
 }
 
+static int thermal_get_trend(struct thermal_zone_device *thermal,
+				int trip, enum thermal_trend *trend)
+{
+	struct acpi_thermal *tz = thermal->devdata;
+	enum thermal_trip_type type;
+	int i;
+
+	if (thermal_get_trip_type(thermal, trip, &type))
+		return -EINVAL;
+
+	if (type == THERMAL_TRIP_ACTIVE) {
+		/* aggressive active cooling */
+		*trend = THERMAL_TREND_RAISING;
+		return 0;
+	}
+
+	/*
+	 * tz->temperature has already been updated by generic thermal layer,
+	 * before this callback being invoked
+	 */
+	i = (tz->trips.passive.tc1 * (tz->temperature - tz->last_temperature))
+		+ (tz->trips.passive.tc2
+		* (tz->temperature - tz->trips.passive.temperature));
+
+	if (i > 0)
+		*trend = THERMAL_TREND_RAISING;
+	else if (i < 0)
+		*trend = THERMAL_TREND_DROPPING;
+	else
+		*trend = THERMAL_TREND_STABLE;
+	return 0;
+}
+
+
 static int thermal_notify(struct thermal_zone_device *thermal, int trip,
 			   enum thermal_trip_type trip_type)
 {
@@ -731,11 +765,9 @@ static int thermal_notify(struct thermal_zone_device *thermal, int trip,
 	return 0;
 }
 
-typedef int (*cb)(struct thermal_zone_device *, int,
-		  struct thermal_cooling_device *);
 static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
 					struct thermal_cooling_device *cdev,
-					cb action)
+					bool bind)
 {
 	struct acpi_device *device = cdev->devdata;
 	struct acpi_thermal *tz = thermal->devdata;
@@ -759,11 +791,19 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
 		    i++) {
 			handle = tz->trips.passive.devices.handles[i];
 			status = acpi_bus_get_device(handle, &dev);
-			if (ACPI_SUCCESS(status) && (dev == device)) {
-				result = action(thermal, trip, cdev);
-				if (result)
-					goto failed;
-			}
+			if (ACPI_FAILURE(status) || dev != device)
+				continue;
+			if (bind)
+				result =
+					thermal_zone_bind_cooling_device
+					(thermal, trip, cdev,
+					 THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
+			else
+				result =
+					thermal_zone_unbind_cooling_device
+					(thermal, trip, cdev);
+			if (result)
+				goto failed;
 		}
 	}
 
@@ -776,11 +816,17 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
 		    j++) {
 			handle = tz->trips.active[i].devices.handles[j];
 			status = acpi_bus_get_device(handle, &dev);
-			if (ACPI_SUCCESS(status) && (dev == device)) {
-				result = action(thermal, trip, cdev);
-				if (result)
-					goto failed;
-			}
+			if (ACPI_FAILURE(status) || dev != device)
+				continue;
+			if (bind)
+				result = thermal_zone_bind_cooling_device
+					(thermal, trip, cdev,
+					 THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
+			else
+				result = thermal_zone_unbind_cooling_device
+					(thermal, trip, cdev);
+			if (result)
+				goto failed;
 		}
 	}
 
@@ -788,7 +834,14 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
 		handle = tz->devices.handles[i];
 		status = acpi_bus_get_device(handle, &dev);
 		if (ACPI_SUCCESS(status) && (dev == device)) {
-			result = action(thermal, -1, cdev);
+			if (bind)
+				result = thermal_zone_bind_cooling_device
+						(thermal, -1, cdev,
+						 THERMAL_NO_LIMIT,
+						 THERMAL_NO_LIMIT);
+			else
+				result = thermal_zone_unbind_cooling_device
+						(thermal, -1, cdev);
 			if (result)
 				goto failed;
 		}
@@ -802,16 +855,14 @@ static int
 acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal,
 					struct thermal_cooling_device *cdev)
 {
-	return acpi_thermal_cooling_device_cb(thermal, cdev,
-				thermal_zone_bind_cooling_device);
+	return acpi_thermal_cooling_device_cb(thermal, cdev, true);
 }
 
 static int
 acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
 					struct thermal_cooling_device *cdev)
 {
-	return acpi_thermal_cooling_device_cb(thermal, cdev,
-				thermal_zone_unbind_cooling_device);
+	return acpi_thermal_cooling_device_cb(thermal, cdev, false);
 }
 
 static const struct thermal_zone_device_ops acpi_thermal_zone_ops = {
@@ -823,6 +874,7 @@ static const struct thermal_zone_device_ops acpi_thermal_zone_ops = {
 	.get_trip_type = thermal_get_trip_type,
 	.get_trip_temp = thermal_get_trip_temp,
 	.get_crit_temp = thermal_get_crit_temp,
+	.get_trend = thermal_get_trend,
 	.notify = thermal_notify,
 };
 
@@ -849,15 +901,12 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
 		tz->thermal_zone =
 			thermal_zone_device_register("acpitz", trips, 0, tz,
 						     &acpi_thermal_zone_ops,
-						     tz->trips.passive.tc1,
-						     tz->trips.passive.tc2,
 						     tz->trips.passive.tsp*100,
 						     tz->polling_frequency*100);
 	else
 		tz->thermal_zone =
 			thermal_zone_device_register("acpitz", trips, 0, tz,
-						     &acpi_thermal_zone_ops,
-						     0, 0, 0,
+						     &acpi_thermal_zone_ops, 0,
 						     tz->polling_frequency*100);
 	if (IS_ERR(tz->thermal_zone))
 		return -ENODEV;
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 2be8ef1..27cecd3 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -115,7 +115,7 @@ config SATA_SIL24
 	  If unsure, say N.
 
 config ATA_SFF
-	bool "ATA SFF support"
+	bool "ATA SFF support (for legacy IDE and PATA)"
 	default y
 	help
 	  This option adds support for ATA controllers with SFF
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 062e6a1..50d5dea 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -256,6 +256,14 @@ static const struct pci_device_id ahci_pci_tbl[] = {
 	{ PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point RAID */
 	{ PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */
 	{ PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point RAID */
+	{ PCI_VDEVICE(INTEL, 0x9c02), board_ahci }, /* Lynx Point-LP AHCI */
+	{ PCI_VDEVICE(INTEL, 0x9c03), board_ahci }, /* Lynx Point-LP AHCI */
+	{ PCI_VDEVICE(INTEL, 0x9c04), board_ahci }, /* Lynx Point-LP RAID */
+	{ PCI_VDEVICE(INTEL, 0x9c05), board_ahci }, /* Lynx Point-LP RAID */
+	{ PCI_VDEVICE(INTEL, 0x9c06), board_ahci }, /* Lynx Point-LP RAID */
+	{ PCI_VDEVICE(INTEL, 0x9c07), board_ahci }, /* Lynx Point-LP RAID */
+	{ PCI_VDEVICE(INTEL, 0x9c0e), board_ahci }, /* Lynx Point-LP RAID */
+	{ PCI_VDEVICE(INTEL, 0x9c0f), board_ahci }, /* Lynx Point-LP RAID */
 
 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index c2594dd..57eb1c2 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -320,6 +320,7 @@ extern struct device_attribute *ahci_sdev_attrs[];
 extern struct ata_port_operations ahci_ops;
 extern struct ata_port_operations ahci_pmp_retry_srst_ops;
 
+unsigned int ahci_dev_classify(struct ata_port *ap);
 void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
 			u32 opts);
 void ahci_save_initial_config(struct device *dev,
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 3c809bf..ef773e1 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -329,6 +329,14 @@ static const struct pci_device_id piix_pci_tbl[] = {
 	{ 0x8086, 0x8c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
 	/* SATA Controller IDE (Lynx Point) */
 	{ 0x8086, 0x8c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+	/* SATA Controller IDE (Lynx Point-LP) */
+	{ 0x8086, 0x9c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+	/* SATA Controller IDE (Lynx Point-LP) */
+	{ 0x8086, 0x9c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+	/* SATA Controller IDE (Lynx Point-LP) */
+	{ 0x8086, 0x9c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+	/* SATA Controller IDE (Lynx Point-LP) */
+	{ 0x8086, 0x9c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
 	/* SATA Controller IDE (DH89xxCC) */
 	{ 0x8086, 0x2326, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
 	{ }	/* terminate list */
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index f9eaa82..555c07a 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -1139,7 +1139,7 @@ static void ahci_dev_config(struct ata_device *dev)
 	}
 }
 
-static unsigned int ahci_dev_classify(struct ata_port *ap)
+unsigned int ahci_dev_classify(struct ata_port *ap)
 {
 	void __iomem *port_mmio = ahci_port_base(ap);
 	struct ata_taskfile tf;
@@ -1153,6 +1153,7 @@ static unsigned int ahci_dev_classify(struct ata_port *ap)
 
 	return ata_dev_classify(&tf);
 }
+EXPORT_SYMBOL_GPL(ahci_dev_classify);
 
 void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
 			u32 opts)
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 902b5a4..fd9ecf7 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -60,17 +60,7 @@ acpi_handle ata_ap_acpi_handle(struct ata_port *ap)
 	if (ap->flags & ATA_FLAG_ACPI_SATA)
 		return NULL;
 
-	/*
-	 * If acpi bind operation has already happened, we can get the handle
-	 * for the port by checking the corresponding scsi_host device's
-	 * firmware node, otherwise we will need to find out the handle from
-	 * its parent's acpi node.
-	 */
-	if (ap->scsi_host)
-		return DEVICE_ACPI_HANDLE(&ap->scsi_host->shost_gendev);
-	else
-		return acpi_get_child(DEVICE_ACPI_HANDLE(ap->host->dev),
-				ap->port_no);
+	return acpi_get_child(DEVICE_ACPI_HANDLE(ap->host->dev), ap->port_no);
 }
 EXPORT_SYMBOL(ata_ap_acpi_handle);
 
@@ -1101,6 +1091,9 @@ static int ata_acpi_bind_host(struct ata_port *ap, acpi_handle *handle)
 	if (!*handle)
 		return -ENODEV;
 
+	if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
+		ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
+
 	return 0;
 }
 
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index fadd586..9d1e66f 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -135,9 +135,9 @@ int atapi_passthru16 = 1;
 module_param(atapi_passthru16, int, 0444);
 MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices (0=off, 1=on [default])");
 
-int libata_fua = 0;
+int libata_fua = 1;
 module_param_named(fua, libata_fua, int, 0444);
-MODULE_PARM_DESC(fua, "FUA support (0=off [default], 1=on)");
+MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on [default])");
 
 static int ata_ignore_hpa;
 module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644);
@@ -4128,6 +4128,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
 
 	/* Devices that do not need bridging limits applied */
 	{ "MTRON MSP-SATA*",		NULL,	ATA_HORKAGE_BRIDGE_OK, },
+	{ "BUFFALO HD-QSU2/R5",		NULL,	ATA_HORKAGE_BRIDGE_OK, },
 
 	/* Devices which aren't very happy with higher link speeds */
 	{ "WD My Book",			NULL,	ATA_HORKAGE_1_5_GBPS, },
@@ -5252,16 +5253,20 @@ bool ata_link_offline(struct ata_link *link)
 #ifdef CONFIG_PM
 static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 			       unsigned int action, unsigned int ehi_flags,
-			       int wait)
+			       int *async)
 {
 	struct ata_link *link;
 	unsigned long flags;
-	int rc;
+	int rc = 0;
 
 	/* Previous resume operation might still be in
 	 * progress.  Wait for PM_PENDING to clear.
 	 */
 	if (ap->pflags & ATA_PFLAG_PM_PENDING) {
+		if (async) {
+			*async = -EAGAIN;
+			return 0;
+		}
 		ata_port_wait_eh(ap);
 		WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
 	}
@@ -5270,10 +5275,10 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 	spin_lock_irqsave(ap->lock, flags);
 
 	ap->pm_mesg = mesg;
-	if (wait) {
-		rc = 0;
+	if (async)
+		ap->pm_result = async;
+	else
 		ap->pm_result = &rc;
-	}
 
 	ap->pflags |= ATA_PFLAG_PM_PENDING;
 	ata_for_each_link(link, ap, HOST_FIRST) {
@@ -5286,7 +5291,7 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 	spin_unlock_irqrestore(ap->lock, flags);
 
 	/* wait and check result */
-	if (wait) {
+	if (!async) {
 		ata_port_wait_eh(ap);
 		WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
 	}
@@ -5294,9 +5299,8 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 	return rc;
 }
 
-static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
+static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int *async)
 {
-	struct ata_port *ap = to_ata_port(dev);
 	unsigned int ehi_flags = ATA_EHI_QUIET;
 	int rc;
 
@@ -5311,10 +5315,17 @@ static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
 	if (mesg.event == PM_EVENT_SUSPEND)
 		ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY;
 
-	rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, 1);
+	rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, async);
 	return rc;
 }
 
+static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
+{
+	struct ata_port *ap = to_ata_port(dev);
+
+	return __ata_port_suspend_common(ap, mesg, NULL);
+}
+
 static int ata_port_suspend(struct device *dev)
 {
 	if (pm_runtime_suspended(dev))
@@ -5339,16 +5350,22 @@ static int ata_port_poweroff(struct device *dev)
 	return ata_port_suspend_common(dev, PMSG_HIBERNATE);
 }
 
-static int ata_port_resume_common(struct device *dev)
+static int __ata_port_resume_common(struct ata_port *ap, int *async)
 {
-	struct ata_port *ap = to_ata_port(dev);
 	int rc;
 
 	rc = ata_port_request_pm(ap, PMSG_ON, ATA_EH_RESET,
-		ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 1);
+		ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, async);
 	return rc;
 }
 
+static int ata_port_resume_common(struct device *dev)
+{
+	struct ata_port *ap = to_ata_port(dev);
+
+	return __ata_port_resume_common(ap, NULL);
+}
+
 static int ata_port_resume(struct device *dev)
 {
 	int rc;
@@ -5381,6 +5398,24 @@ static const struct dev_pm_ops ata_port_pm_ops = {
 	.runtime_idle = ata_port_runtime_idle,
 };
 
+/* sas ports don't participate in pm runtime management of ata_ports,
+ * and need to resume ata devices at the domain level, not the per-port
+ * level. sas suspend/resume is async to allow parallel port recovery
+ * since sas has multiple ata_port instances per Scsi_Host.
+ */
+int ata_sas_port_async_suspend(struct ata_port *ap, int *async)
+{
+	return __ata_port_suspend_common(ap, PMSG_SUSPEND, async);
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_async_suspend);
+
+int ata_sas_port_async_resume(struct ata_port *ap, int *async)
+{
+	return __ata_port_resume_common(ap, async);
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_async_resume);
+
+
 /**
  *	ata_host_suspend - suspend host
  *	@host: host to suspend
@@ -5926,24 +5961,18 @@ int ata_host_start(struct ata_host *host)
 }
 
 /**
- *	ata_sas_host_init - Initialize a host struct
+ *	ata_sas_host_init - Initialize a host struct for sas (ipr, libsas)
  *	@host:	host to initialize
  *	@dev:	device host is attached to
- *	@flags:	host flags
  *	@ops:	port_ops
  *
- *	LOCKING:
- *	PCI/etc. bus probe sem.
- *
  */
-/* KILLME - the only user left is ipr */
 void ata_host_init(struct ata_host *host, struct device *dev,
-		   unsigned long flags, struct ata_port_operations *ops)
+		   struct ata_port_operations *ops)
 {
 	spin_lock_init(&host->lock);
 	mutex_init(&host->eh_mutex);
 	host->dev = dev;
-	host->flags = flags;
 	host->ops = ops;
 }
 
@@ -6387,6 +6416,7 @@ static int __init ata_parse_force_one(char **cur,
 		{ "nohrst",	.lflags		= ATA_LFLAG_NO_HRST },
 		{ "nosrst",	.lflags		= ATA_LFLAG_NO_SRST },
 		{ "norst",	.lflags		= ATA_LFLAG_NO_HRST | ATA_LFLAG_NO_SRST },
+		{ "rstonce",	.lflags		= ATA_LFLAG_RST_ONCE },
 	};
 	char *start = *cur, *p = *cur;
 	char *id, *val, *endp;
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 7d4535e..100428d 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2623,6 +2623,8 @@ int ata_eh_reset(struct ata_link *link, int classify,
 	 */
 	while (ata_eh_reset_timeouts[max_tries] != ULONG_MAX)
 		max_tries++;
+	if (link->flags & ATA_LFLAG_RST_ONCE)
+		max_tries = 1;
 	if (link->flags & ATA_LFLAG_NO_HRST)
 		hardreset = NULL;
 	if (link->flags & ATA_LFLAG_NO_SRST)
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 8ec81ca..e3bda07 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1655,7 +1655,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
 		if (unlikely(scmd->cmd_len < 10))
 			goto invalid_fld;
 		scsi_10_lba_len(cdb, &block, &n_block);
-		if (unlikely(cdb[1] & (1 << 3)))
+		if (cdb[1] & (1 << 3))
 			tf_flags |= ATA_TFLAG_FUA;
 		break;
 	case READ_6:
@@ -1675,7 +1675,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
 		if (unlikely(scmd->cmd_len < 16))
 			goto invalid_fld;
 		scsi_16_lba_len(cdb, &block, &n_block);
-		if (unlikely(cdb[1] & (1 << 3)))
+		if (cdb[1] & (1 << 3))
 			tf_flags |= ATA_TFLAG_FUA;
 		break;
 	default:
@@ -2205,9 +2205,33 @@ static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf)
 }
 
 /**
+ *	modecpy - Prepare response for MODE SENSE
+ *	@dest: output buffer
+ *	@src: data being copied
+ *	@n: length of mode page
+ *	@changeable: whether changeable parameters are requested
+ *
+ *	Generate a generic MODE SENSE page for either current or changeable
+ *	parameters.
+ *
+ *	LOCKING:
+ *	None.
+ */
+static void modecpy(u8 *dest, const u8 *src, int n, bool changeable)
+{
+	if (changeable) {
+		memcpy(dest, src, 2);
+		memset(dest + 2, 0, n - 2);
+	} else {
+		memcpy(dest, src, n);
+	}
+}
+
+/**
  *	ata_msense_caching - Simulate MODE SENSE caching info page
  *	@id: device IDENTIFY data
  *	@buf: output buffer
+ *	@changeable: whether changeable parameters are requested
  *
  *	Generate a caching info page, which conditionally indicates
  *	write caching to the SCSI layer, depending on device
@@ -2216,12 +2240,12 @@ static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf)
  *	LOCKING:
  *	None.
  */
-static unsigned int ata_msense_caching(u16 *id, u8 *buf)
+static unsigned int ata_msense_caching(u16 *id, u8 *buf, bool changeable)
 {
-	memcpy(buf, def_cache_mpage, sizeof(def_cache_mpage));
-	if (ata_id_wcache_enabled(id))
+	modecpy(buf, def_cache_mpage, sizeof(def_cache_mpage), changeable);
+	if (changeable || ata_id_wcache_enabled(id))
 		buf[2] |= (1 << 2);	/* write cache enable */
-	if (!ata_id_rahead_enabled(id))
+	if (!changeable && !ata_id_rahead_enabled(id))
 		buf[12] |= (1 << 5);	/* disable read ahead */
 	return sizeof(def_cache_mpage);
 }
@@ -2229,30 +2253,33 @@ static unsigned int ata_msense_caching(u16 *id, u8 *buf)
 /**
  *	ata_msense_ctl_mode - Simulate MODE SENSE control mode page
  *	@buf: output buffer
+ *	@changeable: whether changeable parameters are requested
  *
  *	Generate a generic MODE SENSE control mode page.
  *
  *	LOCKING:
  *	None.
  */
-static unsigned int ata_msense_ctl_mode(u8 *buf)
+static unsigned int ata_msense_ctl_mode(u8 *buf, bool changeable)
 {
-	memcpy(buf, def_control_mpage, sizeof(def_control_mpage));
+	modecpy(buf, def_control_mpage, sizeof(def_control_mpage), changeable);
 	return sizeof(def_control_mpage);
 }
 
 /**
  *	ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page
  *	@buf: output buffer
+ *	@changeable: whether changeable parameters are requested
  *
  *	Generate a generic MODE SENSE r/w error recovery page.
  *
  *	LOCKING:
  *	None.
  */
-static unsigned int ata_msense_rw_recovery(u8 *buf)
+static unsigned int ata_msense_rw_recovery(u8 *buf, bool changeable)
 {
-	memcpy(buf, def_rw_recovery_mpage, sizeof(def_rw_recovery_mpage));
+	modecpy(buf, def_rw_recovery_mpage, sizeof(def_rw_recovery_mpage),
+		changeable);
 	return sizeof(def_rw_recovery_mpage);
 }
 
@@ -2316,11 +2343,11 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
 	page_control = scsicmd[2] >> 6;
 	switch (page_control) {
 	case 0: /* current */
+	case 1: /* changeable */
+	case 2: /* defaults */
 		break;  /* supported */
 	case 3: /* saved */
 		goto saving_not_supp;
-	case 1: /* changeable */
-	case 2: /* defaults */
 	default:
 		goto invalid_fld;
 	}
@@ -2341,21 +2368,21 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
 
 	switch(pg) {
 	case RW_RECOVERY_MPAGE:
-		p += ata_msense_rw_recovery(p);
+		p += ata_msense_rw_recovery(p, page_control == 1);
 		break;
 
 	case CACHE_MPAGE:
-		p += ata_msense_caching(args->id, p);
+		p += ata_msense_caching(args->id, p, page_control == 1);
 		break;
 
 	case CONTROL_MPAGE:
-		p += ata_msense_ctl_mode(p);
+		p += ata_msense_ctl_mode(p, page_control == 1);
 		break;
 
 	case ALL_MPAGES:
-		p += ata_msense_rw_recovery(p);
-		p += ata_msense_caching(args->id, p);
-		p += ata_msense_ctl_mode(p);
+		p += ata_msense_rw_recovery(p, page_control == 1);
+		p += ata_msense_caching(args->id, p, page_control == 1);
+		p += ata_msense_ctl_mode(p, page_control == 1);
 		break;
 
 	default:		/* invalid page code */
@@ -3080,6 +3107,188 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
 }
 
 /**
+ *	ata_mselect_caching - Simulate MODE SELECT for caching info page
+ *	@qc: Storage for translated ATA taskfile
+ *	@buf: input buffer
+ *	@len: number of valid bytes in the input buffer
+ *
+ *	Prepare a taskfile to modify caching information for the device.
+ *
+ *	LOCKING:
+ *	None.
+ */
+static int ata_mselect_caching(struct ata_queued_cmd *qc,
+			       const u8 *buf, int len)
+{
+	struct ata_taskfile *tf = &qc->tf;
+	struct ata_device *dev = qc->dev;
+	char mpage[CACHE_MPAGE_LEN];
+	u8 wce;
+
+	/*
+	 * The first two bytes of def_cache_mpage are a header, so offsets
+	 * in mpage are off by 2 compared to buf.  Same for len.
+	 */
+
+	if (len != CACHE_MPAGE_LEN - 2)
+		return -EINVAL;
+
+	wce = buf[0] & (1 << 2);
+
+	/*
+	 * Check that read-only bits are not modified.
+	 */
+	ata_msense_caching(dev->id, mpage, false);
+	mpage[2] &= ~(1 << 2);
+	mpage[2] |= wce;
+	if (memcmp(mpage + 2, buf, CACHE_MPAGE_LEN - 2) != 0)
+		return -EINVAL;
+
+	tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+	tf->protocol = ATA_PROT_NODATA;
+	tf->nsect = 0;
+	tf->command = ATA_CMD_SET_FEATURES;
+	tf->feature = wce ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF;
+	return 0;
+}
+
+/**
+ *	ata_scsiop_mode_select - Simulate MODE SELECT 6, 10 commands
+ *	@qc: Storage for translated ATA taskfile
+ *
+ *	Converts a MODE SELECT command to an ATA SET FEATURES taskfile.
+ *	Assume this is invoked for direct access devices (e.g. disks) only.
+ *	There should be no block descriptor for other device types.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ */
+static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc)
+{
+	struct scsi_cmnd *scmd = qc->scsicmd;
+	const u8 *cdb = scmd->cmnd;
+	const u8 *p;
+	u8 pg, spg;
+	unsigned six_byte, pg_len, hdr_len, bd_len;
+	int len;
+
+	VPRINTK("ENTER\n");
+
+	six_byte = (cdb[0] == MODE_SELECT);
+	if (six_byte) {
+		if (scmd->cmd_len < 5)
+			goto invalid_fld;
+
+		len = cdb[4];
+		hdr_len = 4;
+	} else {
+		if (scmd->cmd_len < 9)
+			goto invalid_fld;
+
+		len = (cdb[7] << 8) + cdb[8];
+		hdr_len = 8;
+	}
+
+	/* We only support PF=1, SP=0.  */
+	if ((cdb[1] & 0x11) != 0x10)
+		goto invalid_fld;
+
+	/* Test early for possible overrun.  */
+	if (!scsi_sg_count(scmd) || scsi_sglist(scmd)->length < len)
+		goto invalid_param_len;
+
+	p = page_address(sg_page(scsi_sglist(scmd)));
+
+	/* Move past header and block descriptors.  */
+	if (len < hdr_len)
+		goto invalid_param_len;
+
+	if (six_byte)
+		bd_len = p[3];
+	else
+		bd_len = (p[6] << 8) + p[7];
+
+	len -= hdr_len;
+	p += hdr_len;
+	if (len < bd_len)
+		goto invalid_param_len;
+	if (bd_len != 0 && bd_len != 8)
+		goto invalid_param;
+
+	len -= bd_len;
+	p += bd_len;
+	if (len == 0)
+		goto skip;
+
+	/* Parse both possible formats for the mode page headers.  */
+	pg = p[0] & 0x3f;
+	if (p[0] & 0x40) {
+		if (len < 4)
+			goto invalid_param_len;
+
+		spg = p[1];
+		pg_len = (p[2] << 8) | p[3];
+		p += 4;
+		len -= 4;
+	} else {
+		if (len < 2)
+			goto invalid_param_len;
+
+		spg = 0;
+		pg_len = p[1];
+		p += 2;
+		len -= 2;
+	}
+
+	/*
+	 * No mode subpages supported (yet) but asking for _all_
+	 * subpages may be valid
+	 */
+	if (spg && (spg != ALL_SUB_MPAGES))
+		goto invalid_param;
+	if (pg_len > len)
+		goto invalid_param_len;
+
+	switch (pg) {
+	case CACHE_MPAGE:
+		if (ata_mselect_caching(qc, p, pg_len) < 0)
+			goto invalid_param;
+		break;
+
+	default:		/* invalid page code */
+		goto invalid_param;
+	}
+
+	/*
+	 * Only one page has changeable data, so we only support setting one
+	 * page at a time.
+	 */
+	if (len > pg_len)
+		goto invalid_param;
+
+	return 0;
+
+ invalid_fld:
+	/* "Invalid field in CDB" */
+	ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0);
+	return 1;
+
+ invalid_param:
+	/* "Invalid field in parameter list" */
+	ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x26, 0x0);
+	return 1;
+
+ invalid_param_len:
+	/* "Parameter list length error" */
+	ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x1a, 0x0);
+	return 1;
+
+ skip:
+	scmd->result = SAM_STAT_GOOD;
+	return 1;
+}
+
+/**
  *	ata_get_xlat_func - check if SCSI to ATA translation is possible
  *	@dev: ATA device
  *	@cmd: SCSI command opcode to consider
@@ -3119,6 +3328,11 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
 	case ATA_16:
 		return ata_scsi_pass_thru;
 
+	case MODE_SELECT:
+	case MODE_SELECT_10:
+		return ata_scsi_mode_select_xlat;
+		break;
+
 	case START_STOP:
 		return ata_scsi_start_stop_xlat;
 	}
@@ -3311,11 +3525,6 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
 		ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense);
 		break;
 
-	case MODE_SELECT:	/* unconditionally return */
-	case MODE_SELECT_10:	/* bad-field-in-cdb */
-		ata_scsi_invalid_field(cmd);
-		break;
-
 	case READ_CAPACITY:
 		ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
 		break;
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 361c75c..24e5105 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -20,6 +20,7 @@
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
+#include <linux/dmi.h>
 
 #define DRV_NAME "pata_atiixp"
 #define DRV_VERSION "0.4.6"
@@ -33,11 +34,26 @@ enum {
 	ATIIXP_IDE_UDMA_MODE 	= 0x56
 };
 
+static const struct dmi_system_id attixp_cable_override_dmi_table[] = {
+	{
+		/* Board has onboard PATA<->SATA converters */
+		.ident = "MSI E350DM-E33",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
+			DMI_MATCH(DMI_BOARD_NAME, "E350DM-E33(MS-7720)"),
+		},
+	},
+	{ }
+};
+
 static int atiixp_cable_detect(struct ata_port *ap)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	u8 udma;
 
+	if (dmi_check_system(attixp_cable_override_dmi_table))
+		return ATA_CBL_PATA40_SHORT;
+
 	/* Hack from drivers/ide/pci. Really we want to know how to do the
 	   raw detection not play follow the bios mode guess */
 	pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ap->port_no, &udma);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index f338037..91478bd 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -184,6 +184,17 @@ static void device_release(struct kobject *kobj)
 	struct device *dev = kobj_to_dev(kobj);
 	struct device_private *p = dev->p;
 
+	/*
+	 * Some platform devices are driven without driver attached
+	 * and managed resources may have been acquired.  Make sure
+	 * all resources are released.
+	 *
+	 * Drivers still can add resources into device after device
+	 * is deleted but alive, so release devres here to avoid
+	 * possible memory leak.
+	 */
+	devres_release_all(dev);
+
 	if (dev->release)
 		dev->release(dev);
 	else if (dev->type && dev->type->release)
@@ -1196,13 +1207,6 @@ void device_del(struct device *dev)
 	bus_remove_device(dev);
 	driver_deferred_probe_del(dev);
 
-	/*
-	 * Some platform devices are driven without driver attached
-	 * and managed resources may have been acquired.  Make sure
-	 * all resources are released.
-	 */
-	devres_release_all(dev);
-
 	/* Notify the platform of the removal, in case they
 	 * need to do anything...
 	 */
@@ -1865,6 +1869,7 @@ int __dev_printk(const char *level, const struct device *dev,
 		 struct va_format *vaf)
 {
 	char dict[128];
+	const char *level_extra = "";
 	size_t dictlen = 0;
 	const char *subsys;
 
@@ -1911,10 +1916,14 @@ int __dev_printk(const char *level, const struct device *dev,
 				    "DEVICE=+%s:%s", subsys, dev_name(dev));
 	}
 skip:
+	if (level[2])
+		level_extra = &level[2]; /* skip past KERN_SOH "L" */
+
 	return printk_emit(0, level[1] - '0',
 			   dictlen ? dict : NULL, dictlen,
-			   "%s %s: %pV",
-			   dev_driver_string(dev), dev_name(dev), vaf);
+			   "%s %s: %s%pV",
+			   dev_driver_string(dev), dev_name(dev),
+			   level_extra, vaf);
 }
 EXPORT_SYMBOL(__dev_printk);
 
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index 2360adb..8731979 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -144,6 +144,48 @@ EXPORT_SYMBOL_GPL(devres_alloc);
 #endif
 
 /**
+ * devres_for_each_res - Resource iterator
+ * @dev: Device to iterate resource from
+ * @release: Look for resources associated with this release function
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ * @fn: Function to be called for each matched resource.
+ * @data: Data for @fn, the 3rd parameter of @fn
+ *
+ * Call @fn for each devres of @dev which is associated with @release
+ * and for which @match returns 1.
+ *
+ * RETURNS:
+ * 	void
+ */
+void devres_for_each_res(struct device *dev, dr_release_t release,
+			dr_match_t match, void *match_data,
+			void (*fn)(struct device *, void *, void *),
+			void *data)
+{
+	struct devres_node *node;
+	struct devres_node *tmp;
+	unsigned long flags;
+
+	if (!fn)
+		return;
+
+	spin_lock_irqsave(&dev->devres_lock, flags);
+	list_for_each_entry_safe_reverse(node, tmp,
+			&dev->devres_head, entry) {
+		struct devres *dr = container_of(node, struct devres, node);
+
+		if (node->release != release)
+			continue;
+		if (match && !match(dev, dr->data, match_data))
+			continue;
+		fn(dev, dr->data, data);
+	}
+	spin_unlock_irqrestore(&dev->devres_lock, flags);
+}
+EXPORT_SYMBOL_GPL(devres_for_each_res);
+
+/**
  * devres_free - Free device resource data
  * @res: Pointer to devres data to free
  *
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 803cfc1..ed0510a 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -21,6 +21,12 @@
 #include <linux/firmware.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/async.h>
+#include <linux/pm.h>
+#include <linux/suspend.h>
+
+#include "base.h"
 
 MODULE_AUTHOR("Manuel Estrada Sainz");
 MODULE_DESCRIPTION("Multi purpose firmware loading support");
@@ -85,23 +91,160 @@ static inline long firmware_loading_timeout(void)
 	return loading_timeout > 0 ? loading_timeout * HZ : MAX_SCHEDULE_TIMEOUT;
 }
 
-/* fw_lock could be moved to 'struct firmware_priv' but since it is just
- * guarding for corner cases a global lock should be OK */
-static DEFINE_MUTEX(fw_lock);
+struct firmware_cache {
+	/* firmware_buf instance will be added into the below list */
+	spinlock_t lock;
+	struct list_head head;
+
+	/*
+	 * Names of firmware images which have been cached successfully
+	 * will be added into the below list so that device uncache
+	 * helper can trace which firmware images have been cached
+	 * before.
+	 */
+	spinlock_t name_lock;
+	struct list_head fw_names;
+
+	wait_queue_head_t wait_queue;
+	int cnt;
+	struct delayed_work work;
+
+	struct notifier_block   pm_notify;
+};
 
-struct firmware_priv {
+struct firmware_buf {
+	struct kref ref;
+	struct list_head list;
 	struct completion completion;
-	struct firmware *fw;
+	struct firmware_cache *fwc;
 	unsigned long status;
+	void *data;
+	size_t size;
 	struct page **pages;
 	int nr_pages;
 	int page_array_size;
+	char fw_id[];
+};
+
+struct fw_cache_entry {
+	struct list_head list;
+	char name[];
+};
+
+struct firmware_priv {
 	struct timer_list timeout;
-	struct device dev;
 	bool nowait;
-	char fw_id[];
+	struct device dev;
+	struct firmware_buf *buf;
+	struct firmware *fw;
+};
+
+struct fw_name_devm {
+	unsigned long magic;
+	char name[];
 };
 
+#define to_fwbuf(d) container_of(d, struct firmware_buf, ref)
+
+/* fw_lock could be moved to 'struct firmware_priv' but since it is just
+ * guarding for corner cases a global lock should be OK */
+static DEFINE_MUTEX(fw_lock);
+
+static struct firmware_cache fw_cache;
+
+static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
+					      struct firmware_cache *fwc)
+{
+	struct firmware_buf *buf;
+
+	buf = kzalloc(sizeof(*buf) + strlen(fw_name) + 1 , GFP_ATOMIC);
+
+	if (!buf)
+		return buf;
+
+	kref_init(&buf->ref);
+	strcpy(buf->fw_id, fw_name);
+	buf->fwc = fwc;
+	init_completion(&buf->completion);
+
+	pr_debug("%s: fw-%s buf=%p\n", __func__, fw_name, buf);
+
+	return buf;
+}
+
+static struct firmware_buf *__fw_lookup_buf(const char *fw_name)
+{
+	struct firmware_buf *tmp;
+	struct firmware_cache *fwc = &fw_cache;
+
+	list_for_each_entry(tmp, &fwc->head, list)
+		if (!strcmp(tmp->fw_id, fw_name))
+			return tmp;
+	return NULL;
+}
+
+static int fw_lookup_and_allocate_buf(const char *fw_name,
+				      struct firmware_cache *fwc,
+				      struct firmware_buf **buf)
+{
+	struct firmware_buf *tmp;
+
+	spin_lock(&fwc->lock);
+	tmp = __fw_lookup_buf(fw_name);
+	if (tmp) {
+		kref_get(&tmp->ref);
+		spin_unlock(&fwc->lock);
+		*buf = tmp;
+		return 1;
+	}
+	tmp = __allocate_fw_buf(fw_name, fwc);
+	if (tmp)
+		list_add(&tmp->list, &fwc->head);
+	spin_unlock(&fwc->lock);
+
+	*buf = tmp;
+
+	return tmp ? 0 : -ENOMEM;
+}
+
+static struct firmware_buf *fw_lookup_buf(const char *fw_name)
+{
+	struct firmware_buf *tmp;
+	struct firmware_cache *fwc = &fw_cache;
+
+	spin_lock(&fwc->lock);
+	tmp = __fw_lookup_buf(fw_name);
+	spin_unlock(&fwc->lock);
+
+	return tmp;
+}
+
+static void __fw_free_buf(struct kref *ref)
+{
+	struct firmware_buf *buf = to_fwbuf(ref);
+	struct firmware_cache *fwc = buf->fwc;
+	int i;
+
+	pr_debug("%s: fw-%s buf=%p data=%p size=%u\n",
+		 __func__, buf->fw_id, buf, buf->data,
+		 (unsigned int)buf->size);
+
+	spin_lock(&fwc->lock);
+	list_del(&buf->list);
+	spin_unlock(&fwc->lock);
+
+	vunmap(buf->data);
+	for (i = 0; i < buf->nr_pages; i++)
+		__free_page(buf->pages[i]);
+	kfree(buf->pages);
+	kfree(buf);
+}
+
+static void fw_free_buf(struct firmware_buf *buf)
+{
+	kref_put(&buf->ref, __fw_free_buf);
+}
+
 static struct firmware_priv *to_firmware_priv(struct device *dev)
 {
 	return container_of(dev, struct firmware_priv, dev);
@@ -109,9 +252,10 @@ static struct firmware_priv *to_firmware_priv(struct device *dev)
 
 static void fw_load_abort(struct firmware_priv *fw_priv)
 {
-	set_bit(FW_STATUS_ABORT, &fw_priv->status);
-	wmb();
-	complete(&fw_priv->completion);
+	struct firmware_buf *buf = fw_priv->buf;
+
+	set_bit(FW_STATUS_ABORT, &buf->status);
+	complete_all(&buf->completion);
 }
 
 static ssize_t firmware_timeout_show(struct class *class,
@@ -154,11 +298,7 @@ static struct class_attribute firmware_class_attrs[] = {
 static void fw_dev_release(struct device *dev)
 {
 	struct firmware_priv *fw_priv = to_firmware_priv(dev);
-	int i;
 
-	for (i = 0; i < fw_priv->nr_pages; i++)
-		__free_page(fw_priv->pages[i]);
-	kfree(fw_priv->pages);
 	kfree(fw_priv);
 
 	module_put(THIS_MODULE);
@@ -168,7 +308,7 @@ static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct firmware_priv *fw_priv = to_firmware_priv(dev);
 
-	if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id))
+	if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->buf->fw_id))
 		return -ENOMEM;
 	if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout))
 		return -ENOMEM;
@@ -189,20 +329,16 @@ static ssize_t firmware_loading_show(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
 	struct firmware_priv *fw_priv = to_firmware_priv(dev);
-	int loading = test_bit(FW_STATUS_LOADING, &fw_priv->status);
+	int loading = test_bit(FW_STATUS_LOADING, &fw_priv->buf->status);
 
 	return sprintf(buf, "%d\n", loading);
 }
 
+/* firmware holds the ownership of pages */
 static void firmware_free_data(const struct firmware *fw)
 {
-	int i;
-	vunmap(fw->data);
-	if (fw->pages) {
-		for (i = 0; i < PFN_UP(fw->size); i++)
-			__free_page(fw->pages[i]);
-		kfree(fw->pages);
-	}
+	WARN_ON(!fw->priv);
+	fw_free_buf(fw->priv);
 }
 
 /* Some architectures don't have PAGE_KERNEL_RO */
@@ -227,45 +363,33 @@ static ssize_t firmware_loading_store(struct device *dev,
 				      const char *buf, size_t count)
 {
 	struct firmware_priv *fw_priv = to_firmware_priv(dev);
+	struct firmware_buf *fw_buf = fw_priv->buf;
 	int loading = simple_strtol(buf, NULL, 10);
 	int i;
 
 	mutex_lock(&fw_lock);
 
-	if (!fw_priv->fw)
+	if (!fw_buf)
 		goto out;
 
 	switch (loading) {
 	case 1:
-		firmware_free_data(fw_priv->fw);
-		memset(fw_priv->fw, 0, sizeof(struct firmware));
-		/* If the pages are not owned by 'struct firmware' */
-		for (i = 0; i < fw_priv->nr_pages; i++)
-			__free_page(fw_priv->pages[i]);
-		kfree(fw_priv->pages);
-		fw_priv->pages = NULL;
-		fw_priv->page_array_size = 0;
-		fw_priv->nr_pages = 0;
-		set_bit(FW_STATUS_LOADING, &fw_priv->status);
+		/* discarding any previous partial load */
+		if (!test_bit(FW_STATUS_DONE, &fw_buf->status)) {
+			for (i = 0; i < fw_buf->nr_pages; i++)
+				__free_page(fw_buf->pages[i]);
+			kfree(fw_buf->pages);
+			fw_buf->pages = NULL;
+			fw_buf->page_array_size = 0;
+			fw_buf->nr_pages = 0;
+			set_bit(FW_STATUS_LOADING, &fw_buf->status);
+		}
 		break;
 	case 0:
-		if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) {
-			vunmap(fw_priv->fw->data);
-			fw_priv->fw->data = vmap(fw_priv->pages,
-						 fw_priv->nr_pages,
-						 0, PAGE_KERNEL_RO);
-			if (!fw_priv->fw->data) {
-				dev_err(dev, "%s: vmap() failed\n", __func__);
-				goto err;
-			}
-			/* Pages are now owned by 'struct firmware' */
-			fw_priv->fw->pages = fw_priv->pages;
-			fw_priv->pages = NULL;
-
-			fw_priv->page_array_size = 0;
-			fw_priv->nr_pages = 0;
-			complete(&fw_priv->completion);
-			clear_bit(FW_STATUS_LOADING, &fw_priv->status);
+		if (test_bit(FW_STATUS_LOADING, &fw_buf->status)) {
+			set_bit(FW_STATUS_DONE, &fw_buf->status);
+			clear_bit(FW_STATUS_LOADING, &fw_buf->status);
+			complete_all(&fw_buf->completion);
 			break;
 		}
 		/* fallthrough */
@@ -273,7 +397,6 @@ static ssize_t firmware_loading_store(struct device *dev,
 		dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading);
 		/* fallthrough */
 	case -1:
-	err:
 		fw_load_abort(fw_priv);
 		break;
 	}
@@ -290,21 +413,21 @@ static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
 {
 	struct device *dev = kobj_to_dev(kobj);
 	struct firmware_priv *fw_priv = to_firmware_priv(dev);
-	struct firmware *fw;
+	struct firmware_buf *buf;
 	ssize_t ret_count;
 
 	mutex_lock(&fw_lock);
-	fw = fw_priv->fw;
-	if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
+	buf = fw_priv->buf;
+	if (!buf || test_bit(FW_STATUS_DONE, &buf->status)) {
 		ret_count = -ENODEV;
 		goto out;
 	}
-	if (offset > fw->size) {
+	if (offset > buf->size) {
 		ret_count = 0;
 		goto out;
 	}
-	if (count > fw->size - offset)
-		count = fw->size - offset;
+	if (count > buf->size - offset)
+		count = buf->size - offset;
 
 	ret_count = count;
 
@@ -314,11 +437,11 @@ static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
 		int page_ofs = offset & (PAGE_SIZE-1);
 		int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
 
-		page_data = kmap(fw_priv->pages[page_nr]);
+		page_data = kmap(buf->pages[page_nr]);
 
 		memcpy(buffer, page_data + page_ofs, page_cnt);
 
-		kunmap(fw_priv->pages[page_nr]);
+		kunmap(buf->pages[page_nr]);
 		buffer += page_cnt;
 		offset += page_cnt;
 		count -= page_cnt;
@@ -330,12 +453,13 @@ out:
 
 static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
 {
+	struct firmware_buf *buf = fw_priv->buf;
 	int pages_needed = ALIGN(min_size, PAGE_SIZE) >> PAGE_SHIFT;
 
 	/* If the array of pages is too small, grow it... */
-	if (fw_priv->page_array_size < pages_needed) {
+	if (buf->page_array_size < pages_needed) {
 		int new_array_size = max(pages_needed,
-					 fw_priv->page_array_size * 2);
+					 buf->page_array_size * 2);
 		struct page **new_pages;
 
 		new_pages = kmalloc(new_array_size * sizeof(void *),
@@ -344,24 +468,24 @@ static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
 			fw_load_abort(fw_priv);
 			return -ENOMEM;
 		}
-		memcpy(new_pages, fw_priv->pages,
-		       fw_priv->page_array_size * sizeof(void *));
-		memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
-		       (new_array_size - fw_priv->page_array_size));
-		kfree(fw_priv->pages);
-		fw_priv->pages = new_pages;
-		fw_priv->page_array_size = new_array_size;
+		memcpy(new_pages, buf->pages,
+		       buf->page_array_size * sizeof(void *));
+		memset(&new_pages[buf->page_array_size], 0, sizeof(void *) *
+		       (new_array_size - buf->page_array_size));
+		kfree(buf->pages);
+		buf->pages = new_pages;
+		buf->page_array_size = new_array_size;
 	}
 
-	while (fw_priv->nr_pages < pages_needed) {
-		fw_priv->pages[fw_priv->nr_pages] =
+	while (buf->nr_pages < pages_needed) {
+		buf->pages[buf->nr_pages] =
 			alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
 
-		if (!fw_priv->pages[fw_priv->nr_pages]) {
+		if (!buf->pages[buf->nr_pages]) {
 			fw_load_abort(fw_priv);
 			return -ENOMEM;
 		}
-		fw_priv->nr_pages++;
+		buf->nr_pages++;
 	}
 	return 0;
 }
@@ -384,18 +508,19 @@ static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj,
 {
 	struct device *dev = kobj_to_dev(kobj);
 	struct firmware_priv *fw_priv = to_firmware_priv(dev);
-	struct firmware *fw;
+	struct firmware_buf *buf;
 	ssize_t retval;
 
 	if (!capable(CAP_SYS_RAWIO))
 		return -EPERM;
 
 	mutex_lock(&fw_lock);
-	fw = fw_priv->fw;
-	if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
+	buf = fw_priv->buf;
+	if (!buf || test_bit(FW_STATUS_DONE, &buf->status)) {
 		retval = -ENODEV;
 		goto out;
 	}
+
 	retval = fw_realloc_buffer(fw_priv, offset + count);
 	if (retval)
 		goto out;
@@ -408,17 +533,17 @@ static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj,
 		int page_ofs = offset & (PAGE_SIZE - 1);
 		int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
 
-		page_data = kmap(fw_priv->pages[page_nr]);
+		page_data = kmap(buf->pages[page_nr]);
 
 		memcpy(page_data + page_ofs, buffer, page_cnt);
 
-		kunmap(fw_priv->pages[page_nr]);
+		kunmap(buf->pages[page_nr]);
 		buffer += page_cnt;
 		offset += page_cnt;
 		count -= page_cnt;
 	}
 
-	fw->size = max_t(size_t, offset, fw->size);
+	buf->size = max_t(size_t, offset, buf->size);
 out:
 	mutex_unlock(&fw_lock);
 	return retval;
@@ -445,35 +570,113 @@ fw_create_instance(struct firmware *firmware, const char *fw_name,
 	struct firmware_priv *fw_priv;
 	struct device *f_dev;
 
-	fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
+	fw_priv = kzalloc(sizeof(*fw_priv), GFP_KERNEL);
 	if (!fw_priv) {
 		dev_err(device, "%s: kmalloc failed\n", __func__);
-		return ERR_PTR(-ENOMEM);
+		fw_priv = ERR_PTR(-ENOMEM);
+		goto exit;
 	}
 
-	fw_priv->fw = firmware;
 	fw_priv->nowait = nowait;
-	strcpy(fw_priv->fw_id, fw_name);
-	init_completion(&fw_priv->completion);
+	fw_priv->fw = firmware;
 	setup_timer(&fw_priv->timeout,
 		    firmware_class_timeout, (u_long) fw_priv);
 
 	f_dev = &fw_priv->dev;
 
 	device_initialize(f_dev);
-	dev_set_name(f_dev, "%s", dev_name(device));
+	dev_set_name(f_dev, "%s", fw_name);
 	f_dev->parent = device;
 	f_dev->class = &firmware_class;
-
+exit:
 	return fw_priv;
 }
 
+/* one pages buffer is mapped/unmapped only once */
+static int fw_map_pages_buf(struct firmware_buf *buf)
+{
+	buf->data = vmap(buf->pages, buf->nr_pages, 0, PAGE_KERNEL_RO);
+	if (!buf->data)
+		return -ENOMEM;
+	return 0;
+}
+
+/* store the pages buffer info firmware from buf */
+static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw)
+{
+	fw->priv = buf;
+	fw->pages = buf->pages;
+	fw->size = buf->size;
+	fw->data = buf->data;
+
+	pr_debug("%s: fw-%s buf=%p data=%p size=%u\n",
+		 __func__, buf->fw_id, buf, buf->data,
+		 (unsigned int)buf->size);
+}
+
+static void fw_name_devm_release(struct device *dev, void *res)
+{
+	struct fw_name_devm *fwn = res;
+
+	if (fwn->magic == (unsigned long)&fw_cache)
+		pr_debug("%s: fw_name-%s devm-%p released\n",
+				__func__, fwn->name, res);
+}
+
+static int fw_devm_match(struct device *dev, void *res,
+		void *match_data)
+{
+	struct fw_name_devm *fwn = res;
+
+	return (fwn->magic == (unsigned long)&fw_cache) &&
+		!strcmp(fwn->name, match_data);
+}
+
+static struct fw_name_devm *fw_find_devm_name(struct device *dev,
+		const char *name)
+{
+	struct fw_name_devm *fwn;
+
+	fwn = devres_find(dev, fw_name_devm_release,
+			  fw_devm_match, (void *)name);
+	return fwn;
+}
+
+/* add firmware name into devres list */
+static int fw_add_devm_name(struct device *dev, const char *name)
+{
+	struct fw_name_devm *fwn;
+
+	fwn = fw_find_devm_name(dev, name);
+	if (fwn)
+		return 1;
+
+	fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm) +
+			   strlen(name) + 1, GFP_KERNEL);
+	if (!fwn)
+		return -ENOMEM;
+
+	fwn->magic = (unsigned long)&fw_cache;
+	strcpy(fwn->name, name);
+	devres_add(dev, fwn);
+
+	return 0;
+}
+
+static void _request_firmware_cleanup(const struct firmware **firmware_p)
+{
+	release_firmware(*firmware_p);
+	*firmware_p = NULL;
+}
+
 static struct firmware_priv *
 _request_firmware_prepare(const struct firmware **firmware_p, const char *name,
 			  struct device *device, bool uevent, bool nowait)
 {
 	struct firmware *firmware;
-	struct firmware_priv *fw_priv;
+	struct firmware_priv *fw_priv = NULL;
+	struct firmware_buf *buf;
+	int ret;
 
 	if (!firmware_p)
 		return ERR_PTR(-EINVAL);
@@ -490,18 +693,45 @@ _request_firmware_prepare(const struct firmware **firmware_p, const char *name,
 		return NULL;
 	}
 
-	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
-	if (IS_ERR(fw_priv)) {
-		release_firmware(firmware);
+	ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf);
+	if (!ret)
+		fw_priv = fw_create_instance(firmware, name, device,
+				uevent, nowait);
+
+	if (IS_ERR(fw_priv) || ret < 0) {
+		kfree(firmware);
 		*firmware_p = NULL;
+		return ERR_PTR(-ENOMEM);
+	} else if (fw_priv) {
+		fw_priv->buf = buf;
+
+		/*
+		 * bind with 'buf' now to avoid warning in failure path
+		 * of requesting firmware.
+		 */
+		firmware->priv = buf;
+		return fw_priv;
 	}
-	return fw_priv;
-}
 
-static void _request_firmware_cleanup(const struct firmware **firmware_p)
-{
-	release_firmware(*firmware_p);
-	*firmware_p = NULL;
+	/* share the cached buf, which is inprogessing or completed */
+ check_status:
+	mutex_lock(&fw_lock);
+	if (test_bit(FW_STATUS_ABORT, &buf->status)) {
+		fw_priv = ERR_PTR(-ENOENT);
+		_request_firmware_cleanup(firmware_p);
+		goto exit;
+	} else if (test_bit(FW_STATUS_DONE, &buf->status)) {
+		fw_priv = NULL;
+		fw_set_page_data(buf, firmware);
+		goto exit;
+	}
+	mutex_unlock(&fw_lock);
+	wait_for_completion(&buf->completion);
+	goto check_status;
+
+exit:
+	mutex_unlock(&fw_lock);
+	return fw_priv;
 }
 
 static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
@@ -509,6 +739,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
 {
 	int retval = 0;
 	struct device *f_dev = &fw_priv->dev;
+	struct firmware_buf *buf = fw_priv->buf;
 
 	dev_set_uevent_suppress(f_dev, true);
 
@@ -535,7 +766,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
 
 	if (uevent) {
 		dev_set_uevent_suppress(f_dev, false);
-		dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_id);
+		dev_dbg(f_dev, "firmware: requesting %s\n", buf->fw_id);
 		if (timeout != MAX_SCHEDULE_TIMEOUT)
 			mod_timer(&fw_priv->timeout,
 				  round_jiffies_up(jiffies + timeout));
@@ -543,15 +774,31 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
 		kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
 	}
 
-	wait_for_completion(&fw_priv->completion);
+	wait_for_completion(&buf->completion);
 
-	set_bit(FW_STATUS_DONE, &fw_priv->status);
 	del_timer_sync(&fw_priv->timeout);
 
 	mutex_lock(&fw_lock);
-	if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status))
+	if (!buf->size || test_bit(FW_STATUS_ABORT, &buf->status))
 		retval = -ENOENT;
-	fw_priv->fw = NULL;
+
+	/*
+	 * add firmware name into devres list so that we can auto cache
+	 * and uncache firmware for device.
+	 *
+	 * f_dev->parent may has been deleted already, but the problem
+	 * should be fixed in devres or driver core.
+	 */
+	if (!retval && f_dev->parent)
+		fw_add_devm_name(f_dev->parent, buf->fw_id);
+
+	if (!retval)
+		retval = fw_map_pages_buf(buf);
+
+	/* pass the pages buffer to driver at the last minute */
+	fw_set_page_data(buf, fw_priv->fw);
+
+	fw_priv->buf = NULL;
 	mutex_unlock(&fw_lock);
 
 	device_remove_file(f_dev, &dev_attr_loading);
@@ -578,6 +825,8 @@ err_put_dev:
  *      @name will be used as $FIRMWARE in the uevent environment and
  *      should be distinctive enough not to be confused with any other
  *      firmware image for this or any other device.
+ *
+ *	Caller must hold the reference count of @device.
  **/
 int
 request_firmware(const struct firmware **firmware_p, const char *name,
@@ -659,6 +908,7 @@ static void request_firmware_work_func(struct work_struct *work)
 
  out:
 	fw_work->cont(fw, fw_work->context);
+	put_device(fw_work->device);
 
 	module_put(fw_work->module);
 	kfree(fw_work);
@@ -677,9 +927,15 @@ static void request_firmware_work_func(struct work_struct *work)
  * @cont: function will be called asynchronously when the firmware
  *	request is over.
  *
- *	Asynchronous variant of request_firmware() for user contexts where
- *	it is not possible to sleep for long time. It can't be called
- *	in atomic contexts.
+ *	Caller must hold the reference count of @device.
+ *
+ *	Asynchronous variant of request_firmware() for user contexts:
+ *		- sleep for as small periods as possible since it may
+ *		increase kernel boot time of built-in device drivers
+ *		requesting firmware in their ->probe() methods, if
+ *		@gfp is GFP_KERNEL.
+ *
+ *		- can't sleep at all if @gfp is GFP_ATOMIC.
  **/
 int
 request_firmware_nowait(
@@ -705,18 +961,313 @@ request_firmware_nowait(
 		return -EFAULT;
 	}
 
+	get_device(fw_work->device);
 	INIT_WORK(&fw_work->work, request_firmware_work_func);
 	schedule_work(&fw_work->work);
 	return 0;
 }
 
+/**
+ * cache_firmware - cache one firmware image in kernel memory space
+ * @fw_name: the firmware image name
+ *
+ * Cache firmware in kernel memory so that drivers can use it when
+ * system isn't ready for them to request firmware image from userspace.
+ * Once it returns successfully, driver can use request_firmware or its
+ * nowait version to get the cached firmware without any interacting
+ * with userspace
+ *
+ * Return 0 if the firmware image has been cached successfully
+ * Return !0 otherwise
+ *
+ */
+int cache_firmware(const char *fw_name)
+{
+	int ret;
+	const struct firmware *fw;
+
+	pr_debug("%s: %s\n", __func__, fw_name);
+
+	ret = request_firmware(&fw, fw_name, NULL);
+	if (!ret)
+		kfree(fw);
+
+	pr_debug("%s: %s ret=%d\n", __func__, fw_name, ret);
+
+	return ret;
+}
+
+/**
+ * uncache_firmware - remove one cached firmware image
+ * @fw_name: the firmware image name
+ *
+ * Uncache one firmware image which has been cached successfully
+ * before.
+ *
+ * Return 0 if the firmware cache has been removed successfully
+ * Return !0 otherwise
+ *
+ */
+int uncache_firmware(const char *fw_name)
+{
+	struct firmware_buf *buf;
+	struct firmware fw;
+
+	pr_debug("%s: %s\n", __func__, fw_name);
+
+	if (fw_get_builtin_firmware(&fw, fw_name))
+		return 0;
+
+	buf = fw_lookup_buf(fw_name);
+	if (buf) {
+		fw_free_buf(buf);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static struct fw_cache_entry *alloc_fw_cache_entry(const char *name)
+{
+	struct fw_cache_entry *fce;
+
+	fce = kzalloc(sizeof(*fce) + strlen(name) + 1, GFP_ATOMIC);
+	if (!fce)
+		goto exit;
+
+	strcpy(fce->name, name);
+exit:
+	return fce;
+}
+
+static void free_fw_cache_entry(struct fw_cache_entry *fce)
+{
+	kfree(fce);
+}
+
+static void __async_dev_cache_fw_image(void *fw_entry,
+				       async_cookie_t cookie)
+{
+	struct fw_cache_entry *fce = fw_entry;
+	struct firmware_cache *fwc = &fw_cache;
+	int ret;
+
+	ret = cache_firmware(fce->name);
+	if (ret)
+		goto free;
+
+	spin_lock(&fwc->name_lock);
+	list_add(&fce->list, &fwc->fw_names);
+	spin_unlock(&fwc->name_lock);
+	goto drop_ref;
+
+free:
+	free_fw_cache_entry(fce);
+drop_ref:
+	spin_lock(&fwc->name_lock);
+	fwc->cnt--;
+	spin_unlock(&fwc->name_lock);
+
+	wake_up(&fwc->wait_queue);
+}
+
+/* called with dev->devres_lock held */
+static void dev_create_fw_entry(struct device *dev, void *res,
+				void *data)
+{
+	struct fw_name_devm *fwn = res;
+	const char *fw_name = fwn->name;
+	struct list_head *head = data;
+	struct fw_cache_entry *fce;
+
+	fce = alloc_fw_cache_entry(fw_name);
+	if (fce)
+		list_add(&fce->list, head);
+}
+
+static int devm_name_match(struct device *dev, void *res,
+			   void *match_data)
+{
+	struct fw_name_devm *fwn = res;
+	return (fwn->magic == (unsigned long)match_data);
+}
+
+static void dev_cache_fw_image(struct device *dev, void *data)
+{
+	LIST_HEAD(todo);
+	struct fw_cache_entry *fce;
+	struct fw_cache_entry *fce_next;
+	struct firmware_cache *fwc = &fw_cache;
+
+	devres_for_each_res(dev, fw_name_devm_release,
+			    devm_name_match, &fw_cache,
+			    dev_create_fw_entry, &todo);
+
+	list_for_each_entry_safe(fce, fce_next, &todo, list) {
+		list_del(&fce->list);
+
+		spin_lock(&fwc->name_lock);
+		fwc->cnt++;
+		spin_unlock(&fwc->name_lock);
+
+		async_schedule(__async_dev_cache_fw_image, (void *)fce);
+	}
+}
+
+static void __device_uncache_fw_images(void)
+{
+	struct firmware_cache *fwc = &fw_cache;
+	struct fw_cache_entry *fce;
+
+	spin_lock(&fwc->name_lock);
+	while (!list_empty(&fwc->fw_names)) {
+		fce = list_entry(fwc->fw_names.next,
+				struct fw_cache_entry, list);
+		list_del(&fce->list);
+		spin_unlock(&fwc->name_lock);
+
+		uncache_firmware(fce->name);
+		free_fw_cache_entry(fce);
+
+		spin_lock(&fwc->name_lock);
+	}
+	spin_unlock(&fwc->name_lock);
+}
+
+/**
+ * device_cache_fw_images - cache devices' firmware
+ *
+ * If one device called request_firmware or its nowait version
+ * successfully before, the firmware names are recored into the
+ * device's devres link list, so device_cache_fw_images can call
+ * cache_firmware() to cache these firmwares for the device,
+ * then the device driver can load its firmwares easily at
+ * time when system is not ready to complete loading firmware.
+ */
+static void device_cache_fw_images(void)
+{
+	struct firmware_cache *fwc = &fw_cache;
+	int old_timeout;
+	DEFINE_WAIT(wait);
+
+	pr_debug("%s\n", __func__);
+
+	/*
+	 * use small loading timeout for caching devices' firmware
+	 * because all these firmware images have been loaded
+	 * successfully at lease once, also system is ready for
+	 * completing firmware loading now. The maximum size of
+	 * firmware in current distributions is about 2M bytes,
+	 * so 10 secs should be enough.
+	 */
+	old_timeout = loading_timeout;
+	loading_timeout = 10;
+
+	dpm_for_each_dev(NULL, dev_cache_fw_image);
+
+	/* wait for completion of caching firmware for all devices */
+	spin_lock(&fwc->name_lock);
+	for (;;) {
+		prepare_to_wait(&fwc->wait_queue, &wait,
+				TASK_UNINTERRUPTIBLE);
+		if (!fwc->cnt)
+			break;
+
+		spin_unlock(&fwc->name_lock);
+
+		schedule();
+
+		spin_lock(&fwc->name_lock);
+	}
+	spin_unlock(&fwc->name_lock);
+	finish_wait(&fwc->wait_queue, &wait);
+
+	loading_timeout = old_timeout;
+}
+
+/**
+ * device_uncache_fw_images - uncache devices' firmware
+ *
+ * uncache all firmwares which have been cached successfully
+ * by device_uncache_fw_images earlier
+ */
+static void device_uncache_fw_images(void)
+{
+	pr_debug("%s\n", __func__);
+	__device_uncache_fw_images();
+}
+
+static void device_uncache_fw_images_work(struct work_struct *work)
+{
+	device_uncache_fw_images();
+}
+
+/**
+ * device_uncache_fw_images_delay - uncache devices firmwares
+ * @delay: number of milliseconds to delay uncache device firmwares
+ *
+ * uncache all devices's firmwares which has been cached successfully
+ * by device_cache_fw_images after @delay milliseconds.
+ */
+static void device_uncache_fw_images_delay(unsigned long delay)
+{
+	schedule_delayed_work(&fw_cache.work,
+			msecs_to_jiffies(delay));
+}
+
+#ifdef CONFIG_PM
+static int fw_pm_notify(struct notifier_block *notify_block,
+			unsigned long mode, void *unused)
+{
+	switch (mode) {
+	case PM_HIBERNATION_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		device_cache_fw_images();
+		break;
+
+	case PM_POST_SUSPEND:
+	case PM_POST_HIBERNATION:
+	case PM_POST_RESTORE:
+		device_uncache_fw_images_delay(10 * MSEC_PER_SEC);
+		break;
+	}
+
+	return 0;
+}
+#else
+static int fw_pm_notify(struct notifier_block *notify_block,
+			unsigned long mode, void *unused)
+{
+	return 0;
+}
+#endif
+
+static void __init fw_cache_init(void)
+{
+	spin_lock_init(&fw_cache.lock);
+	INIT_LIST_HEAD(&fw_cache.head);
+
+	spin_lock_init(&fw_cache.name_lock);
+	INIT_LIST_HEAD(&fw_cache.fw_names);
+	fw_cache.cnt = 0;
+
+	init_waitqueue_head(&fw_cache.wait_queue);
+	INIT_DELAYED_WORK(&fw_cache.work,
+			  device_uncache_fw_images_work);
+
+	fw_cache.pm_notify.notifier_call = fw_pm_notify;
+	register_pm_notifier(&fw_cache.pm_notify);
+}
+
 static int __init firmware_class_init(void)
 {
+	fw_cache_init();
 	return class_register(&firmware_class);
 }
 
 static void __exit firmware_class_exit(void)
 {
+	unregister_pm_notifier(&fw_cache.pm_notify);
 	class_unregister(&firmware_class);
 }
 
@@ -726,3 +1277,5 @@ module_exit(firmware_class_exit);
 EXPORT_SYMBOL(release_firmware);
 EXPORT_SYMBOL(request_firmware);
 EXPORT_SYMBOL(request_firmware_nowait);
+EXPORT_SYMBOL_GPL(cache_firmware);
+EXPORT_SYMBOL_GPL(uncache_firmware);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index a1a7225..42ca90c 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -20,8 +20,13 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
+#include <linux/idr.h>
 
 #include "base.h"
+#include "power/power.h"
+
+/* For automatically allocated device IDs */
+static DEFINE_IDA(platform_devid_ida);
 
 #define to_platform_driver(drv)	(container_of((drv), struct platform_driver, \
 				 driver))
@@ -263,7 +268,7 @@ EXPORT_SYMBOL_GPL(platform_device_add_data);
  */
 int platform_device_add(struct platform_device *pdev)
 {
-	int i, ret = 0;
+	int i, ret;
 
 	if (!pdev)
 		return -EINVAL;
@@ -273,10 +278,27 @@ int platform_device_add(struct platform_device *pdev)
 
 	pdev->dev.bus = &platform_bus_type;
 
-	if (pdev->id != -1)
+	switch (pdev->id) {
+	default:
 		dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
-	else
+		break;
+	case PLATFORM_DEVID_NONE:
 		dev_set_name(&pdev->dev, "%s", pdev->name);
+		break;
+	case PLATFORM_DEVID_AUTO:
+		/*
+		 * Automatically allocated device ID. We mark it as such so
+		 * that we remember it must be freed, and we append a suffix
+		 * to avoid namespace collision with explicit IDs.
+		 */
+		ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
+		if (ret < 0)
+			goto err_out;
+		pdev->id = ret;
+		pdev->id_auto = true;
+		dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
+		break;
+	}
 
 	for (i = 0; i < pdev->num_resources; i++) {
 		struct resource *p, *r = &pdev->resource[i];
@@ -309,6 +331,11 @@ int platform_device_add(struct platform_device *pdev)
 		return ret;
 
  failed:
+	if (pdev->id_auto) {
+		ida_simple_remove(&platform_devid_ida, pdev->id);
+		pdev->id = PLATFORM_DEVID_AUTO;
+	}
+
 	while (--i >= 0) {
 		struct resource *r = &pdev->resource[i];
 		unsigned long type = resource_type(r);
@@ -317,6 +344,7 @@ int platform_device_add(struct platform_device *pdev)
 			release_resource(r);
 	}
 
+ err_out:
 	return ret;
 }
 EXPORT_SYMBOL_GPL(platform_device_add);
@@ -336,6 +364,11 @@ void platform_device_del(struct platform_device *pdev)
 	if (pdev) {
 		device_del(&pdev->dev);
 
+		if (pdev->id_auto) {
+			ida_simple_remove(&platform_devid_ida, pdev->id);
+			pdev->id = PLATFORM_DEVID_AUTO;
+		}
+
 		for (i = 0; i < pdev->num_resources; i++) {
 			struct resource *r = &pdev->resource[i];
 			unsigned long type = resource_type(r);
@@ -948,6 +981,7 @@ void __init early_platform_add_devices(struct platform_device **devs, int num)
 		dev = &devs[i]->dev;
 
 		if (!dev->devres_head.next) {
+			pm_runtime_early_init(dev);
 			INIT_LIST_HEAD(&dev->devres_head);
 			list_add_tail(&dev->devres_head,
 				      &early_platform_device_list);
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index ba3487c..12ad070 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -53,6 +53,24 @@
 static LIST_HEAD(gpd_list);
 static DEFINE_MUTEX(gpd_list_lock);
 
+static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
+{
+	struct generic_pm_domain *genpd = NULL, *gpd;
+
+	if (IS_ERR_OR_NULL(domain_name))
+		return NULL;
+
+	mutex_lock(&gpd_list_lock);
+	list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
+		if (!strcmp(gpd->name, domain_name)) {
+			genpd = gpd;
+			break;
+		}
+	}
+	mutex_unlock(&gpd_list_lock);
+	return genpd;
+}
+
 #ifdef CONFIG_PM
 
 struct generic_pm_domain *dev_to_genpd(struct device *dev)
@@ -75,6 +93,12 @@ static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev)
 					start_latency_ns, "start");
 }
 
+static int genpd_start_dev_no_timing(struct generic_pm_domain *genpd,
+				     struct device *dev)
+{
+	return GENPD_DEV_CALLBACK(genpd, int, start, dev);
+}
+
 static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
 {
 	bool ret = false;
@@ -256,6 +280,18 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd)
 	return ret;
 }
 
+/**
+ * pm_genpd_name_poweron - Restore power to a given PM domain and its masters.
+ * @domain_name: Name of the PM domain to power up.
+ */
+int pm_genpd_name_poweron(const char *domain_name)
+{
+	struct generic_pm_domain *genpd;
+
+	genpd = pm_genpd_lookup_name(domain_name);
+	return genpd ? pm_genpd_poweron(genpd) : -EINVAL;
+}
+
 #endif /* CONFIG_PM */
 
 #ifdef CONFIG_PM_RUNTIME
@@ -436,7 +472,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
 	not_suspended = 0;
 	list_for_each_entry(pdd, &genpd->dev_list, list_node)
 		if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev)
-		    || pdd->dev->power.irq_safe || to_gpd_data(pdd)->always_on))
+		    || pdd->dev->power.irq_safe))
 			not_suspended++;
 
 	if (not_suspended > genpd->in_progress)
@@ -578,9 +614,6 @@ static int pm_genpd_runtime_suspend(struct device *dev)
 
 	might_sleep_if(!genpd->dev_irq_safe);
 
-	if (dev_gpd_data(dev)->always_on)
-		return -EBUSY;
-
 	stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL;
 	if (stop_ok && !stop_ok(dev))
 		return -EBUSY;
@@ -629,7 +662,7 @@ static int pm_genpd_runtime_resume(struct device *dev)
 
 	/* If power.irq_safe, the PM domain is never powered off. */
 	if (dev->power.irq_safe)
-		return genpd_start_dev(genpd, dev);
+		return genpd_start_dev_no_timing(genpd, dev);
 
 	mutex_lock(&genpd->lock);
 	ret = __pm_genpd_poweron(genpd);
@@ -697,6 +730,24 @@ static inline void genpd_power_off_work_fn(struct work_struct *work) {}
 
 #ifdef CONFIG_PM_SLEEP
 
+/**
+ * pm_genpd_present - Check if the given PM domain has been initialized.
+ * @genpd: PM domain to check.
+ */
+static bool pm_genpd_present(struct generic_pm_domain *genpd)
+{
+	struct generic_pm_domain *gpd;
+
+	if (IS_ERR_OR_NULL(genpd))
+		return false;
+
+	list_for_each_entry(gpd, &gpd_list, gpd_list_node)
+		if (gpd == genpd)
+			return true;
+
+	return false;
+}
+
 static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd,
 				    struct device *dev)
 {
@@ -750,9 +801,10 @@ static int genpd_thaw_dev(struct generic_pm_domain *genpd, struct device *dev)
  * Check if the given PM domain can be powered off (during system suspend or
  * hibernation) and do that if so.  Also, in that case propagate to its masters.
  *
- * This function is only called in "noirq" stages of system power transitions,
- * so it need not acquire locks (all of the "noirq" callbacks are executed
- * sequentially, so it is guaranteed that it will never run twice in parallel).
+ * This function is only called in "noirq" and "syscore" stages of system power
+ * transitions, so it need not acquire locks (all of the "noirq" callbacks are
+ * executed sequentially, so it is guaranteed that it will never run twice in
+ * parallel).
  */
 static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
 {
@@ -777,6 +829,33 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
 }
 
 /**
+ * pm_genpd_sync_poweron - Synchronously power on a PM domain and its masters.
+ * @genpd: PM domain to power on.
+ *
+ * This function is only called in "noirq" and "syscore" stages of system power
+ * transitions, so it need not acquire locks (all of the "noirq" callbacks are
+ * executed sequentially, so it is guaranteed that it will never run twice in
+ * parallel).
+ */
+static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd)
+{
+	struct gpd_link *link;
+
+	if (genpd->status != GPD_STATE_POWER_OFF)
+		return;
+
+	list_for_each_entry(link, &genpd->slave_links, slave_node) {
+		pm_genpd_sync_poweron(link->master);
+		genpd_sd_counter_inc(link->master);
+	}
+
+	if (genpd->power_on)
+		genpd->power_on(genpd);
+
+	genpd->status = GPD_STATE_ACTIVE;
+}
+
+/**
  * resume_needed - Check whether to resume a device before system suspend.
  * @dev: Device to check.
  * @genpd: PM domain the device belongs to.
@@ -937,7 +1016,7 @@ static int pm_genpd_suspend_noirq(struct device *dev)
 	if (IS_ERR(genpd))
 		return -EINVAL;
 
-	if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on
+	if (genpd->suspend_power_off
 	    || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)))
 		return 0;
 
@@ -970,7 +1049,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
 	if (IS_ERR(genpd))
 		return -EINVAL;
 
-	if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on
+	if (genpd->suspend_power_off
 	    || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)))
 		return 0;
 
@@ -979,7 +1058,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
 	 * guaranteed that this function will never run twice in parallel for
 	 * the same PM domain, so it is not necessary to use locking here.
 	 */
-	pm_genpd_poweron(genpd);
+	pm_genpd_sync_poweron(genpd);
 	genpd->suspended_count--;
 
 	return genpd_start_dev(genpd, dev);
@@ -1090,8 +1169,7 @@ static int pm_genpd_freeze_noirq(struct device *dev)
 	if (IS_ERR(genpd))
 		return -EINVAL;
 
-	return genpd->suspend_power_off || dev_gpd_data(dev)->always_on ?
-		0 : genpd_stop_dev(genpd, dev);
+	return genpd->suspend_power_off ? 0 : genpd_stop_dev(genpd, dev);
 }
 
 /**
@@ -1111,8 +1189,7 @@ static int pm_genpd_thaw_noirq(struct device *dev)
 	if (IS_ERR(genpd))
 		return -EINVAL;
 
-	return genpd->suspend_power_off || dev_gpd_data(dev)->always_on ?
-		0 : genpd_start_dev(genpd, dev);
+	return genpd->suspend_power_off ? 0 : genpd_start_dev(genpd, dev);
 }
 
 /**
@@ -1186,8 +1263,8 @@ static int pm_genpd_restore_noirq(struct device *dev)
 	if (genpd->suspended_count++ == 0) {
 		/*
 		 * The boot kernel might put the domain into arbitrary state,
-		 * so make it appear as powered off to pm_genpd_poweron(), so
-		 * that it tries to power it on in case it was really off.
+		 * so make it appear as powered off to pm_genpd_sync_poweron(),
+		 * so that it tries to power it on in case it was really off.
 		 */
 		genpd->status = GPD_STATE_POWER_OFF;
 		if (genpd->suspend_power_off) {
@@ -1205,9 +1282,9 @@ static int pm_genpd_restore_noirq(struct device *dev)
 	if (genpd->suspend_power_off)
 		return 0;
 
-	pm_genpd_poweron(genpd);
+	pm_genpd_sync_poweron(genpd);
 
-	return dev_gpd_data(dev)->always_on ? 0 : genpd_start_dev(genpd, dev);
+	return genpd_start_dev(genpd, dev);
 }
 
 /**
@@ -1246,6 +1323,31 @@ static void pm_genpd_complete(struct device *dev)
 	}
 }
 
+/**
+ * pm_genpd_syscore_switch - Switch power during system core suspend or resume.
+ * @dev: Device that normally is marked as "always on" to switch power for.
+ *
+ * This routine may only be called during the system core (syscore) suspend or
+ * resume phase for devices whose "always on" flags are set.
+ */
+void pm_genpd_syscore_switch(struct device *dev, bool suspend)
+{
+	struct generic_pm_domain *genpd;
+
+	genpd = dev_to_genpd(dev);
+	if (!pm_genpd_present(genpd))
+		return;
+
+	if (suspend) {
+		genpd->suspended_count++;
+		pm_genpd_sync_poweroff(genpd);
+	} else {
+		pm_genpd_sync_poweron(genpd);
+		genpd->suspended_count--;
+	}
+}
+EXPORT_SYMBOL_GPL(pm_genpd_syscore_switch);
+
 #else
 
 #define pm_genpd_prepare		NULL
@@ -1393,6 +1495,19 @@ int __pm_genpd_of_add_device(struct device_node *genpd_node, struct device *dev,
 	return __pm_genpd_add_device(genpd, dev, td);
 }
 
+
+/**
+ * __pm_genpd_name_add_device - Find I/O PM domain and add a device to it.
+ * @domain_name: Name of the PM domain to add the device to.
+ * @dev: Device to be added.
+ * @td: Set of PM QoS timing parameters to attach to the device.
+ */
+int __pm_genpd_name_add_device(const char *domain_name, struct device *dev,
+			       struct gpd_timing_data *td)
+{
+	return __pm_genpd_add_device(pm_genpd_lookup_name(domain_name), dev, td);
+}
+
 /**
  * pm_genpd_remove_device - Remove a device from an I/O PM domain.
  * @genpd: PM domain to remove the device from.
@@ -1455,26 +1570,6 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
 }
 
 /**
- * pm_genpd_dev_always_on - Set/unset the "always on" flag for a given device.
- * @dev: Device to set/unset the flag for.
- * @val: The new value of the device's "always on" flag.
- */
-void pm_genpd_dev_always_on(struct device *dev, bool val)
-{
-	struct pm_subsys_data *psd;
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev->power.lock, flags);
-
-	psd = dev_to_psd(dev);
-	if (psd && psd->domain_data)
-		to_gpd_data(psd->domain_data)->always_on = val;
-
-	spin_unlock_irqrestore(&dev->power.lock, flags);
-}
-EXPORT_SYMBOL_GPL(pm_genpd_dev_always_on);
-
-/**
  * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag.
  * @dev: Device to set/unset the flag for.
  * @val: The new value of the device's "need restore" flag.
@@ -1505,7 +1600,8 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
 	struct gpd_link *link;
 	int ret = 0;
 
-	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
+	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain)
+	    || genpd == subdomain)
 		return -EINVAL;
 
  start:
@@ -1552,6 +1648,35 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
 }
 
 /**
+ * pm_genpd_add_subdomain_names - Add a subdomain to an I/O PM domain.
+ * @master_name: Name of the master PM domain to add the subdomain to.
+ * @subdomain_name: Name of the subdomain to be added.
+ */
+int pm_genpd_add_subdomain_names(const char *master_name,
+				 const char *subdomain_name)
+{
+	struct generic_pm_domain *master = NULL, *subdomain = NULL, *gpd;
+
+	if (IS_ERR_OR_NULL(master_name) || IS_ERR_OR_NULL(subdomain_name))
+		return -EINVAL;
+
+	mutex_lock(&gpd_list_lock);
+	list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
+		if (!master && !strcmp(gpd->name, master_name))
+			master = gpd;
+
+		if (!subdomain && !strcmp(gpd->name, subdomain_name))
+			subdomain = gpd;
+
+		if (master && subdomain)
+			break;
+	}
+	mutex_unlock(&gpd_list_lock);
+
+	return pm_genpd_add_subdomain(master, subdomain);
+}
+
+/**
  * pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain.
  * @genpd: Master PM domain to remove the subdomain from.
  * @subdomain: Subdomain to be removed.
@@ -1704,7 +1829,16 @@ int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td)
 }
 EXPORT_SYMBOL_GPL(__pm_genpd_remove_callbacks);
 
-int genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state)
+/**
+ * pm_genpd_attach_cpuidle - Connect the given PM domain with cpuidle.
+ * @genpd: PM domain to be connected with cpuidle.
+ * @state: cpuidle state this domain can disable/enable.
+ *
+ * Make a PM domain behave as though it contained a CPU core, that is, instead
+ * of calling its power down routine it will enable the given cpuidle state so
+ * that the cpuidle subsystem can power it down (if possible and desirable).
+ */
+int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state)
 {
 	struct cpuidle_driver *cpuidle_drv;
 	struct gpd_cpu_data *cpu_data;
@@ -1753,7 +1887,24 @@ int genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state)
 	goto out;
 }
 
-int genpd_detach_cpuidle(struct generic_pm_domain *genpd)
+/**
+ * pm_genpd_name_attach_cpuidle - Find PM domain and connect cpuidle to it.
+ * @name: Name of the domain to connect to cpuidle.
+ * @state: cpuidle state this domain can manipulate.
+ */
+int pm_genpd_name_attach_cpuidle(const char *name, int state)
+{
+	return pm_genpd_attach_cpuidle(pm_genpd_lookup_name(name), state);
+}
+
+/**
+ * pm_genpd_detach_cpuidle - Remove the cpuidle connection from a PM domain.
+ * @genpd: PM domain to remove the cpuidle connection from.
+ *
+ * Remove the cpuidle connection set up by pm_genpd_attach_cpuidle() from the
+ * given PM domain.
+ */
+int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd)
 {
 	struct gpd_cpu_data *cpu_data;
 	struct cpuidle_state *idle_state;
@@ -1784,6 +1935,15 @@ int genpd_detach_cpuidle(struct generic_pm_domain *genpd)
 	return ret;
 }
 
+/**
+ * pm_genpd_name_detach_cpuidle - Find PM domain and disconnect cpuidle from it.
+ * @name: Name of the domain to disconnect cpuidle from.
+ */
+int pm_genpd_name_detach_cpuidle(const char *name)
+{
+	return pm_genpd_detach_cpuidle(pm_genpd_lookup_name(name));
+}
+
 /* Default device callbacks for generic PM domains. */
 
 /**
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 0113adc..23b417f 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -57,20 +57,17 @@ static pm_message_t pm_transition;
 static int async_error;
 
 /**
- * device_pm_init - Initialize the PM-related part of a device object.
+ * device_pm_sleep_init - Initialize system suspend-related device fields.
  * @dev: Device object being initialized.
  */
-void device_pm_init(struct device *dev)
+void device_pm_sleep_init(struct device *dev)
 {
 	dev->power.is_prepared = false;
 	dev->power.is_suspended = false;
 	init_completion(&dev->power.completion);
 	complete_all(&dev->power.completion);
 	dev->power.wakeup = NULL;
-	spin_lock_init(&dev->power.lock);
-	pm_runtime_init(dev);
 	INIT_LIST_HEAD(&dev->power.entry);
-	dev->power.power_state = PMSG_INVALID;
 }
 
 /**
@@ -408,6 +405,9 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
 	TRACE_DEVICE(dev);
 	TRACE_RESUME(0);
 
+	if (dev->power.syscore)
+		goto Out;
+
 	if (dev->pm_domain) {
 		info = "noirq power domain ";
 		callback = pm_noirq_op(&dev->pm_domain->ops, state);
@@ -429,6 +429,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
 
 	error = dpm_run_callback(callback, dev, state, info);
 
+ Out:
 	TRACE_RESUME(error);
 	return error;
 }
@@ -486,6 +487,9 @@ static int device_resume_early(struct device *dev, pm_message_t state)
 	TRACE_DEVICE(dev);
 	TRACE_RESUME(0);
 
+	if (dev->power.syscore)
+		goto Out;
+
 	if (dev->pm_domain) {
 		info = "early power domain ";
 		callback = pm_late_early_op(&dev->pm_domain->ops, state);
@@ -507,6 +511,7 @@ static int device_resume_early(struct device *dev, pm_message_t state)
 
 	error = dpm_run_callback(callback, dev, state, info);
 
+ Out:
 	TRACE_RESUME(error);
 	return error;
 }
@@ -570,6 +575,9 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
 	TRACE_DEVICE(dev);
 	TRACE_RESUME(0);
 
+	if (dev->power.syscore)
+		goto Complete;
+
 	dpm_wait(dev->parent, async);
 	device_lock(dev);
 
@@ -632,6 +640,8 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
 
  Unlock:
 	device_unlock(dev);
+
+ Complete:
 	complete_all(&dev->power.completion);
 
 	TRACE_RESUME(error);
@@ -722,6 +732,9 @@ static void device_complete(struct device *dev, pm_message_t state)
 	void (*callback)(struct device *) = NULL;
 	char *info = NULL;
 
+	if (dev->power.syscore)
+		return;
+
 	device_lock(dev);
 
 	if (dev->pm_domain) {
@@ -834,6 +847,9 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
 	pm_callback_t callback = NULL;
 	char *info = NULL;
 
+	if (dev->power.syscore)
+		return 0;
+
 	if (dev->pm_domain) {
 		info = "noirq power domain ";
 		callback = pm_noirq_op(&dev->pm_domain->ops, state);
@@ -917,6 +933,9 @@ static int device_suspend_late(struct device *dev, pm_message_t state)
 	pm_callback_t callback = NULL;
 	char *info = NULL;
 
+	if (dev->power.syscore)
+		return 0;
+
 	if (dev->pm_domain) {
 		info = "late power domain ";
 		callback = pm_late_early_op(&dev->pm_domain->ops, state);
@@ -1053,6 +1072,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
 		goto Complete;
 	}
 
+	if (dev->power.syscore)
+		goto Complete;
+
 	device_lock(dev);
 
 	if (dev->pm_domain) {
@@ -1209,6 +1231,9 @@ static int device_prepare(struct device *dev, pm_message_t state)
 	char *info = NULL;
 	int error = 0;
 
+	if (dev->power.syscore)
+		return 0;
+
 	device_lock(dev);
 
 	dev->power.wakeup_path = device_may_wakeup(dev);
@@ -1324,3 +1349,25 @@ int device_pm_wait_for_dev(struct device *subordinate, struct device *dev)
 	return async_error;
 }
 EXPORT_SYMBOL_GPL(device_pm_wait_for_dev);
+
+/**
+ * dpm_for_each_dev - device iterator.
+ * @data: data for the callback.
+ * @fn: function to be called for each device.
+ *
+ * Iterate over devices in dpm_list, and call @fn for each device,
+ * passing it @data.
+ */
+void dpm_for_each_dev(void *data, void (*fn)(struct device *, void *))
+{
+	struct device *dev;
+
+	if (!fn)
+		return;
+
+	device_pm_lock();
+	list_for_each_entry(dev, &dpm_list, power.entry)
+		fn(dev, data);
+	device_pm_unlock();
+}
+EXPORT_SYMBOL_GPL(dpm_for_each_dev);
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index eeb4bff..0dbfdf4 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -1,12 +1,32 @@
 #include <linux/pm_qos.h>
 
+static inline void device_pm_init_common(struct device *dev)
+{
+	if (!dev->power.early_init) {
+		spin_lock_init(&dev->power.lock);
+		dev->power.power_state = PMSG_INVALID;
+		dev->power.early_init = true;
+	}
+}
+
 #ifdef CONFIG_PM_RUNTIME
 
+static inline void pm_runtime_early_init(struct device *dev)
+{
+	dev->power.disable_depth = 1;
+	device_pm_init_common(dev);
+}
+
 extern void pm_runtime_init(struct device *dev);
 extern void pm_runtime_remove(struct device *dev);
 
 #else /* !CONFIG_PM_RUNTIME */
 
+static inline void pm_runtime_early_init(struct device *dev)
+{
+	device_pm_init_common(dev);
+}
+
 static inline void pm_runtime_init(struct device *dev) {}
 static inline void pm_runtime_remove(struct device *dev) {}
 
@@ -25,7 +45,7 @@ static inline struct device *to_device(struct list_head *entry)
 	return container_of(entry, struct device, power.entry);
 }
 
-extern void device_pm_init(struct device *dev);
+extern void device_pm_sleep_init(struct device *dev);
 extern void device_pm_add(struct device *);
 extern void device_pm_remove(struct device *);
 extern void device_pm_move_before(struct device *, struct device *);
@@ -34,12 +54,7 @@ extern void device_pm_move_last(struct device *);
 
 #else /* !CONFIG_PM_SLEEP */
 
-static inline void device_pm_init(struct device *dev)
-{
-	spin_lock_init(&dev->power.lock);
-	dev->power.power_state = PMSG_INVALID;
-	pm_runtime_init(dev);
-}
+static inline void device_pm_sleep_init(struct device *dev) {}
 
 static inline void device_pm_add(struct device *dev)
 {
@@ -60,6 +75,13 @@ static inline void device_pm_move_last(struct device *dev) {}
 
 #endif /* !CONFIG_PM_SLEEP */
 
+static inline void device_pm_init(struct device *dev)
+{
+	device_pm_init_common(dev);
+	device_pm_sleep_init(dev);
+	pm_runtime_init(dev);
+}
+
 #ifdef CONFIG_PM
 
 /*
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 5989487..7d9c1cb 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -147,6 +147,8 @@ static int rpm_check_suspend_allowed(struct device *dev)
 	    || (dev->power.request_pending
 			&& dev->power.request == RPM_REQ_RESUME))
 		retval = -EAGAIN;
+	else if (__dev_pm_qos_read_value(dev) < 0)
+		retval = -EPERM;
 	else if (dev->power.runtime_status == RPM_SUSPENDED)
 		retval = 1;
 
@@ -388,7 +390,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
 		goto repeat;
 	}
 
-	dev->power.deferred_resume = false;
 	if (dev->power.no_callbacks)
 		goto no_callback;	/* Assume success. */
 
@@ -403,12 +404,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
 		goto out;
 	}
 
-	if (__dev_pm_qos_read_value(dev) < 0) {
-		/* Negative PM QoS constraint means "never suspend". */
-		retval = -EPERM;
-		goto out;
-	}
-
 	__update_runtime_status(dev, RPM_SUSPENDING);
 
 	if (dev->pm_domain)
@@ -440,6 +435,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
 	wake_up_all(&dev->power.wait_queue);
 
 	if (dev->power.deferred_resume) {
+		dev->power.deferred_resume = false;
 		rpm_resume(dev, 0);
 		retval = -EAGAIN;
 		goto out;
@@ -584,6 +580,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
 		    || dev->parent->power.runtime_status == RPM_ACTIVE) {
 			atomic_inc(&dev->parent->power.child_count);
 			spin_unlock(&dev->parent->power.lock);
+			retval = 1;
 			goto no_callback;	/* Assume success. */
 		}
 		spin_unlock(&dev->parent->power.lock);
@@ -664,7 +661,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
 	}
 	wake_up_all(&dev->power.wait_queue);
 
-	if (!retval)
+	if (retval >= 0)
 		rpm_idle(dev, RPM_ASYNC);
 
  out:
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index cbb463b..8a0a9ca 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -649,6 +649,31 @@ void pm_wakeup_event(struct device *dev, unsigned int msec)
 }
 EXPORT_SYMBOL_GPL(pm_wakeup_event);
 
+static void print_active_wakeup_sources(void)
+{
+	struct wakeup_source *ws;
+	int active = 0;
+	struct wakeup_source *last_activity_ws = NULL;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
+		if (ws->active) {
+			pr_info("active wakeup source: %s\n", ws->name);
+			active = 1;
+		} else if (!active &&
+			   (!last_activity_ws ||
+			    ktime_to_ns(ws->last_time) >
+			    ktime_to_ns(last_activity_ws->last_time))) {
+			last_activity_ws = ws;
+		}
+	}
+
+	if (!active && last_activity_ws)
+		pr_info("last active wakeup source: %s\n",
+			last_activity_ws->name);
+	rcu_read_unlock();
+}
+
 /**
  * pm_wakeup_pending - Check if power transition in progress should be aborted.
  *
@@ -671,6 +696,10 @@ bool pm_wakeup_pending(void)
 		events_check_enabled = !ret;
 	}
 	spin_unlock_irqrestore(&events_lock, flags);
+
+	if (ret)
+		print_active_wakeup_sources();
+
 	return ret;
 }
 
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index a897346..bb5e103 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -16,12 +16,14 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/irqdomain.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 
 #include "internal.h"
 
 struct regmap_irq_chip_data {
 	struct mutex lock;
+	struct irq_chip irq_chip;
 
 	struct regmap *map;
 	const struct regmap_irq_chip *chip;
@@ -59,6 +61,14 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
 	struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
 	struct regmap *map = d->map;
 	int i, ret;
+	u32 reg;
+
+	if (d->chip->runtime_pm) {
+		ret = pm_runtime_get_sync(map->dev);
+		if (ret < 0)
+			dev_err(map->dev, "IRQ sync failed to resume: %d\n",
+				ret);
+	}
 
 	/*
 	 * If there's been a change in the mask write it back to the
@@ -66,15 +76,18 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
 	 * suppress pointless writes.
 	 */
 	for (i = 0; i < d->chip->num_regs; i++) {
-		ret = regmap_update_bits(d->map, d->chip->mask_base +
-						(i * map->reg_stride *
-						d->irq_reg_stride),
+		reg = d->chip->mask_base +
+			(i * map->reg_stride * d->irq_reg_stride);
+		ret = regmap_update_bits(d->map, reg,
 					 d->mask_buf_def[i], d->mask_buf[i]);
 		if (ret != 0)
 			dev_err(d->map->dev, "Failed to sync masks in %x\n",
-				d->chip->mask_base + (i * map->reg_stride));
+				reg);
 	}
 
+	if (d->chip->runtime_pm)
+		pm_runtime_put(map->dev);
+
 	/* If we've changed our wakeup count propagate it to the parent */
 	if (d->wake_count < 0)
 		for (i = d->wake_count; i < 0; i++)
@@ -128,8 +141,7 @@ static int regmap_irq_set_wake(struct irq_data *data, unsigned int on)
 	return 0;
 }
 
-static struct irq_chip regmap_irq_chip = {
-	.name			= "regmap",
+static const struct irq_chip regmap_irq_chip = {
 	.irq_bus_lock		= regmap_irq_lock,
 	.irq_bus_sync_unlock	= regmap_irq_sync_unlock,
 	.irq_disable		= regmap_irq_disable,
@@ -144,6 +156,16 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
 	struct regmap *map = data->map;
 	int ret, i;
 	bool handled = false;
+	u32 reg;
+
+	if (chip->runtime_pm) {
+		ret = pm_runtime_get_sync(map->dev);
+		if (ret < 0) {
+			dev_err(map->dev, "IRQ thread failed to resume: %d\n",
+				ret);
+			return IRQ_NONE;
+		}
+	}
 
 	/*
 	 * Ignore masked IRQs and ack if we need to; we ack early so
@@ -160,20 +182,20 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
 		if (ret != 0) {
 			dev_err(map->dev, "Failed to read IRQ status: %d\n",
 					ret);
+			if (chip->runtime_pm)
+				pm_runtime_put(map->dev);
 			return IRQ_NONE;
 		}
 
 		data->status_buf[i] &= ~data->mask_buf[i];
 
 		if (data->status_buf[i] && chip->ack_base) {
-			ret = regmap_write(map, chip->ack_base +
-						(i * map->reg_stride *
-						data->irq_reg_stride),
-					   data->status_buf[i]);
+			reg = chip->ack_base +
+				(i * map->reg_stride * data->irq_reg_stride);
+			ret = regmap_write(map, reg, data->status_buf[i]);
 			if (ret != 0)
 				dev_err(map->dev, "Failed to ack 0x%x: %d\n",
-					chip->ack_base + (i * map->reg_stride),
-					ret);
+					reg, ret);
 		}
 	}
 
@@ -185,6 +207,9 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
 		}
 	}
 
+	if (chip->runtime_pm)
+		pm_runtime_put(map->dev);
+
 	if (handled)
 		return IRQ_HANDLED;
 	else
@@ -197,7 +222,7 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq,
 	struct regmap_irq_chip_data *data = h->host_data;
 
 	irq_set_chip_data(virq, data);
-	irq_set_chip_and_handler(virq, &regmap_irq_chip, handle_edge_irq);
+	irq_set_chip_and_handler(virq, &data->irq_chip, handle_edge_irq);
 	irq_set_nested_thread(virq, 1);
 
 	/* ARM needs us to explicitly flag the IRQ as valid
@@ -238,6 +263,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
 	struct regmap_irq_chip_data *d;
 	int i;
 	int ret = -ENOMEM;
+	u32 reg;
 
 	for (i = 0; i < chip->num_irqs; i++) {
 		if (chip->irqs[i].reg_offset % map->reg_stride)
@@ -284,6 +310,13 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
 			goto err_alloc;
 	}
 
+	d->irq_chip = regmap_irq_chip;
+	d->irq_chip.name = chip->name;
+	if (!chip->wake_base) {
+		d->irq_chip.irq_set_wake = NULL;
+		d->irq_chip.flags |= IRQCHIP_MASK_ON_SUSPEND |
+				     IRQCHIP_SKIP_SET_WAKE;
+	}
 	d->irq = irq;
 	d->map = map;
 	d->chip = chip;
@@ -303,16 +336,33 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
 	/* Mask all the interrupts by default */
 	for (i = 0; i < chip->num_regs; i++) {
 		d->mask_buf[i] = d->mask_buf_def[i];
-		ret = regmap_write(map, chip->mask_base + (i * map->reg_stride
-				   * d->irq_reg_stride),
-				   d->mask_buf[i]);
+		reg = chip->mask_base +
+			(i * map->reg_stride * d->irq_reg_stride);
+		ret = regmap_update_bits(map, reg,
+					 d->mask_buf[i], d->mask_buf[i]);
 		if (ret != 0) {
 			dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
-				chip->mask_base + (i * map->reg_stride), ret);
+				reg, ret);
 			goto err_alloc;
 		}
 	}
 
+	/* Wake is disabled by default */
+	if (d->wake_buf) {
+		for (i = 0; i < chip->num_regs; i++) {
+			d->wake_buf[i] = d->mask_buf_def[i];
+			reg = chip->wake_base +
+				(i * map->reg_stride * d->irq_reg_stride);
+			ret = regmap_update_bits(map, reg, d->wake_buf[i],
+						 d->wake_buf[i]);
+			if (ret != 0) {
+				dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
+					reg, ret);
+				goto err_alloc;
+			}
+		}
+	}
+
 	if (irq_base)
 		d->domain = irq_domain_add_legacy(map->dev->of_node,
 						  chip->num_irqs, irq_base, 0,
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index c241ae2..52069d2 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -659,13 +659,12 @@ EXPORT_SYMBOL_GPL(devm_regmap_init);
  * new cache.  This can be used to restore the cache to defaults or to
  * update the cache configuration to reflect runtime discovery of the
  * hardware.
+ *
+ * No explicit locking is done here, the user needs to ensure that
+ * this function will not race with other calls to regmap.
  */
 int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
 {
-	int ret;
-
-	map->lock(map);
-
 	regcache_exit(map);
 	regmap_debugfs_exit(map);
 
@@ -681,11 +680,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
 	map->cache_bypass = false;
 	map->cache_only = false;
 
-	ret = regcache_init(map, config);
-
-	map->unlock(map);
-
-	return ret;
+	return regcache_init(map, config);
 }
 EXPORT_SYMBOL_GPL(regmap_reinit_cache);
 
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
index c9a4f46..8b8f2f3 100644
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -101,7 +101,7 @@ void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
 	bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
 }
 
-void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
+static void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
 {
 	struct bcma_bus *bus = cc->core->bus;
 
@@ -257,7 +257,7 @@ static u32 bcma_pmu_clock_bcm4706(struct bcma_drv_cc *cc, u32 pll0, u32 m)
 }
 
 /* query bus clock frequency for PMU-enabled chipcommon */
-u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
+static u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
 {
 	struct bcma_bus *bus = cc->core->bus;
 
diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c
index a6e5672..f7b0af7 100644
--- a/drivers/bcma/host_pci.c
+++ b/drivers/bcma/host_pci.c
@@ -77,8 +77,8 @@ static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
 }
 
 #ifdef CONFIG_BCMA_BLOCKIO
-void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
-			      size_t count, u16 offset, u8 reg_width)
+static void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
+				     size_t count, u16 offset, u8 reg_width)
 {
 	void __iomem *addr = core->bus->mmio + offset;
 	if (core->bus->mapped_core != core)
@@ -100,8 +100,9 @@ void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
 	}
 }
 
-void bcma_host_pci_block_write(struct bcma_device *core, const void *buffer,
-			       size_t count, u16 offset, u8 reg_width)
+static void bcma_host_pci_block_write(struct bcma_device *core,
+				      const void *buffer, size_t count,
+				      u16 offset, u8 reg_width)
 {
 	void __iomem *addr = core->bus->mmio + offset;
 	if (core->bus->mapped_core != core)
@@ -139,7 +140,7 @@ static void bcma_host_pci_awrite32(struct bcma_device *core, u16 offset,
 	iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
 }
 
-const struct bcma_host_ops bcma_host_pci_ops = {
+static const struct bcma_host_ops bcma_host_pci_ops = {
 	.read8		= bcma_host_pci_read8,
 	.read16		= bcma_host_pci_read16,
 	.read32		= bcma_host_pci_read32,
diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c
index 3c381fb..3475e60 100644
--- a/drivers/bcma/host_soc.c
+++ b/drivers/bcma/host_soc.c
@@ -143,7 +143,7 @@ static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
 	writel(value, core->io_wrap + offset);
 }
 
-const struct bcma_host_ops bcma_host_soc_ops = {
+static const struct bcma_host_ops bcma_host_soc_ops = {
 	.read8		= bcma_host_soc_read8,
 	.read16		= bcma_host_soc_read16,
 	.read32		= bcma_host_soc_read32,
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index acda773..38aa6dd 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -763,16 +763,7 @@ static void complete_scsi_command(CommandList_struct *c, int timeout,
 		{
 			case CMD_TARGET_STATUS:
 				/* Pass it up to the upper layers... */
-				if( ei->ScsiStatus)
-                		{
-#if 0
-                    			printk(KERN_WARNING "cciss: cmd %p "
-						"has SCSI Status = %x\n",
-						c, ei->ScsiStatus);
-#endif
-					cmd->result |= (ei->ScsiStatus << 1);
-                		}
-				else {  /* scsi status is zero??? How??? */
+				if (!ei->ScsiStatus) {
 					
 	/* Ordinarily, this case should never happen, but there is a bug
 	   in some released firmware revisions that allows it to happen
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 10308cd..11f36e5 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -79,6 +79,7 @@ static struct usb_device_id ath3k_table[] = {
 	{ USB_DEVICE(0x13d3, 0x3362) },
 	{ USB_DEVICE(0x0CF3, 0xE004) },
 	{ USB_DEVICE(0x0930, 0x0219) },
+	{ USB_DEVICE(0x0489, 0xe057) },
 
 	/* Atheros AR5BBU12 with sflash firmware */
 	{ USB_DEVICE(0x0489, 0xE02C) },
@@ -104,6 +105,7 @@ static struct usb_device_id ath3k_blist_tbl[] = {
 	{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
 
 	/* Atheros AR5BBU22 with sflash firmware */
 	{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c
index 37ae175..364f82b 100644
--- a/drivers/bluetooth/bcm203x.c
+++ b/drivers/bluetooth/bcm203x.c
@@ -177,7 +177,7 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
 	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
 		return -ENODEV;
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
 	if (!data) {
 		BT_ERR("Can't allocate memory for data structure");
 		return -ENOMEM;
@@ -189,14 +189,12 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
 	data->urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!data->urb) {
 		BT_ERR("Can't allocate URB");
-		kfree(data);
 		return -ENOMEM;
 	}
 
 	if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) {
 		BT_ERR("Mini driver request failed");
 		usb_free_urb(data->urb);
-		kfree(data);
 		return -EIO;
 	}
 
@@ -209,7 +207,6 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
 		BT_ERR("Can't allocate memory for mini driver");
 		release_firmware(firmware);
 		usb_free_urb(data->urb);
-		kfree(data);
 		return -ENOMEM;
 	}
 
@@ -224,7 +221,6 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
 		BT_ERR("Firmware request failed");
 		usb_free_urb(data->urb);
 		kfree(data->buffer);
-		kfree(data);
 		return -EIO;
 	}
 
@@ -236,7 +232,6 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
 		release_firmware(firmware);
 		usb_free_urb(data->urb);
 		kfree(data->buffer);
-		kfree(data);
 		return -ENOMEM;
 	}
 
@@ -271,7 +266,6 @@ static void bcm203x_disconnect(struct usb_interface *intf)
 	usb_free_urb(data->urb);
 	kfree(data->fw_data);
 	kfree(data->buffer);
-	kfree(data);
 }
 
 static struct usb_driver bcm203x_driver = {
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
index 32e8251..995aee9 100644
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -653,7 +653,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
 	}
 
 	/* Initialize control structure and load firmware */
-	data = kzalloc(sizeof(struct bfusb_data), GFP_KERNEL);
+	data = devm_kzalloc(&intf->dev, sizeof(struct bfusb_data), GFP_KERNEL);
 	if (!data) {
 		BT_ERR("Can't allocate memory for control structure");
 		goto done;
@@ -674,7 +674,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
 
 	if (request_firmware(&firmware, "bfubase.frm", &udev->dev) < 0) {
 		BT_ERR("Firmware request failed");
-		goto error;
+		goto done;
 	}
 
 	BT_DBG("firmware data %p size %zu", firmware->data, firmware->size);
@@ -690,7 +690,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
 	hdev = hci_alloc_dev();
 	if (!hdev) {
 		BT_ERR("Can't allocate HCI device");
-		goto error;
+		goto done;
 	}
 
 	data->hdev = hdev;
@@ -708,7 +708,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
 	if (hci_register_dev(hdev) < 0) {
 		BT_ERR("Can't register HCI device");
 		hci_free_dev(hdev);
-		goto error;
+		goto done;
 	}
 
 	usb_set_intfdata(intf, data);
@@ -718,9 +718,6 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
 release:
 	release_firmware(firmware);
 
-error:
-	kfree(data);
-
 done:
 	return -EIO;
 }
@@ -741,7 +738,6 @@ static void bfusb_disconnect(struct usb_interface *intf)
 
 	hci_unregister_dev(hdev);
 	hci_free_dev(hdev);
-	kfree(data);
 }
 
 static struct usb_driver bfusb_driver = {
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index 66c3a67..0c0838d 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -849,7 +849,7 @@ static int bluecard_probe(struct pcmcia_device *link)
 	bluecard_info_t *info;
 
 	/* Create new info device */
-	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
@@ -864,10 +864,7 @@ static int bluecard_probe(struct pcmcia_device *link)
 
 static void bluecard_detach(struct pcmcia_device *link)
 {
-	bluecard_info_t *info = link->priv;
-
 	bluecard_release(link);
-	kfree(info);
 }
 
 
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index 29caaed..2fe4a80 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -443,7 +443,7 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
 	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
 		return -ENODEV;
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -453,10 +453,8 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
 	init_usb_anchor(&data->rx_anchor);
 
 	hdev = hci_alloc_dev();
-	if (!hdev) {
-		kfree(data);
+	if (!hdev)
 		return -ENOMEM;
-	}
 
 	hdev->bus = HCI_USB;
 	hci_set_drvdata(hdev, data);
@@ -475,7 +473,6 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
 	err = hci_register_dev(hdev);
 	if (err < 0) {
 		hci_free_dev(hdev);
-		kfree(data);
 		return err;
 	}
 
@@ -500,7 +497,6 @@ static void bpa10x_disconnect(struct usb_interface *intf)
 	hci_free_dev(data->hdev);
 	kfree_skb(data->rx_skb[0]);
 	kfree_skb(data->rx_skb[1]);
-	kfree(data);
 }
 
 static struct usb_driver bpa10x_driver = {
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 8925b6d..7ffd3f4 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -638,7 +638,7 @@ static int bt3c_probe(struct pcmcia_device *link)
 	bt3c_info_t *info;
 
 	/* Create new info device */
-	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
@@ -654,10 +654,7 @@ static int bt3c_probe(struct pcmcia_device *link)
 
 static void bt3c_detach(struct pcmcia_device *link)
 {
-	bt3c_info_t *info = link->priv;
-
 	bt3c_release(link);
-	kfree(info);
 }
 
 static int bt3c_check_config(struct pcmcia_device *p_dev, void *priv_data)
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 6a9e971..03b3acb 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -956,11 +956,9 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
 	BT_INFO("vendor=0x%x, device=0x%x, class=%d, fn=%d",
 			id->vendor, id->device, id->class, func->num);
 
-	card = kzalloc(sizeof(*card), GFP_KERNEL);
-	if (!card) {
-		ret = -ENOMEM;
-		goto done;
-	}
+	card = devm_kzalloc(&func->dev, sizeof(*card), GFP_KERNEL);
+	if (!card)
+		return -ENOMEM;
 
 	card->func = func;
 
@@ -974,8 +972,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
 
 	if (btmrvl_sdio_register_dev(card) < 0) {
 		BT_ERR("Failed to register BT device!");
-		ret = -ENODEV;
-		goto free_card;
+		return -ENODEV;
 	}
 
 	/* Disable the interrupts on the card */
@@ -1023,9 +1020,6 @@ disable_host_int:
 	btmrvl_sdio_disable_host_int(card);
 unreg_dev:
 	btmrvl_sdio_unregister_dev(card);
-free_card:
-	kfree(card);
-done:
 	return ret;
 }
 
@@ -1047,7 +1041,6 @@ static void btmrvl_sdio_remove(struct sdio_func *func)
 			BT_DBG("unregester dev");
 			btmrvl_sdio_unregister_dev(card);
 			btmrvl_remove_card(card->priv);
-			kfree(card);
 		}
 	}
 }
diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c
index e10ea03..4a99097 100644
--- a/drivers/bluetooth/btsdio.c
+++ b/drivers/bluetooth/btsdio.c
@@ -304,7 +304,7 @@ static int btsdio_probe(struct sdio_func *func,
 		tuple = tuple->next;
 	}
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -315,10 +315,8 @@ static int btsdio_probe(struct sdio_func *func,
 	skb_queue_head_init(&data->txq);
 
 	hdev = hci_alloc_dev();
-	if (!hdev) {
-		kfree(data);
+	if (!hdev)
 		return -ENOMEM;
-	}
 
 	hdev->bus = HCI_SDIO;
 	hci_set_drvdata(hdev, data);
@@ -340,7 +338,6 @@ static int btsdio_probe(struct sdio_func *func,
 	err = hci_register_dev(hdev);
 	if (err < 0) {
 		hci_free_dev(hdev);
-		kfree(data);
 		return err;
 	}
 
@@ -366,7 +363,6 @@ static void btsdio_remove(struct sdio_func *func)
 	hci_unregister_dev(hdev);
 
 	hci_free_dev(hdev);
-	kfree(data);
 }
 
 static struct sdio_driver btsdio_driver = {
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index 21e803a..2f510a8 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -567,7 +567,7 @@ static int btuart_probe(struct pcmcia_device *link)
 	btuart_info_t *info;
 
 	/* Create new info device */
-	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
@@ -583,10 +583,7 @@ static int btuart_probe(struct pcmcia_device *link)
 
 static void btuart_detach(struct pcmcia_device *link)
 {
-	btuart_info_t *info = link->priv;
-
 	btuart_release(link);
-	kfree(info);
 }
 
 static int btuart_check_config(struct pcmcia_device *p_dev, void *priv_data)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index e272214..fa2a7d5 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -98,6 +98,7 @@ static struct usb_device_id btusb_table[] = {
 	{ USB_DEVICE(0x0a5c, 0x21e6) },
 	{ USB_DEVICE(0x0a5c, 0x21e8) },
 	{ USB_DEVICE(0x0a5c, 0x21f3) },
+	{ USB_DEVICE(0x0a5c, 0x21f4) },
 	{ USB_DEVICE(0x413c, 0x8197) },
 
 	/* Foxconn - Hon Hai */
@@ -133,6 +134,7 @@ static struct usb_device_id blacklist_table[] = {
 	{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
 
 	/* Atheros AR5BBU12 with sflash firmware */
 	{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
@@ -952,7 +954,7 @@ static int btusb_probe(struct usb_interface *intf,
 			return -ENODEV;
 	}
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -975,10 +977,8 @@ static int btusb_probe(struct usb_interface *intf,
 		}
 	}
 
-	if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) {
-		kfree(data);
+	if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep)
 		return -ENODEV;
-	}
 
 	data->cmdreq_type = USB_TYPE_CLASS;
 
@@ -998,10 +998,8 @@ static int btusb_probe(struct usb_interface *intf,
 	init_usb_anchor(&data->deferred);
 
 	hdev = hci_alloc_dev();
-	if (!hdev) {
-		kfree(data);
+	if (!hdev)
 		return -ENOMEM;
-	}
 
 	hdev->bus = HCI_USB;
 	hci_set_drvdata(hdev, data);
@@ -1069,7 +1067,6 @@ static int btusb_probe(struct usb_interface *intf,
 							data->isoc, data);
 		if (err < 0) {
 			hci_free_dev(hdev);
-			kfree(data);
 			return err;
 		}
 	}
@@ -1077,7 +1074,6 @@ static int btusb_probe(struct usb_interface *intf,
 	err = hci_register_dev(hdev);
 	if (err < 0) {
 		hci_free_dev(hdev);
-		kfree(data);
 		return err;
 	}
 
@@ -1110,7 +1106,6 @@ static void btusb_disconnect(struct usb_interface *intf)
 		usb_driver_release_interface(&btusb_driver, data->isoc);
 
 	hci_free_dev(hdev);
-	kfree(data);
 }
 
 #ifdef CONFIG_PM
diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c
index 8869469..4ad7b35 100644
--- a/drivers/bluetooth/btwilink.c
+++ b/drivers/bluetooth/btwilink.c
@@ -297,16 +297,14 @@ static int bt_ti_probe(struct platform_device *pdev)
 	struct hci_dev *hdev;
 	int err;
 
-	hst = kzalloc(sizeof(struct ti_st), GFP_KERNEL);
+	hst = devm_kzalloc(&pdev->dev, sizeof(struct ti_st), GFP_KERNEL);
 	if (!hst)
 		return -ENOMEM;
 
 	/* Expose "hciX" device to user space */
 	hdev = hci_alloc_dev();
-	if (!hdev) {
-		kfree(hst);
+	if (!hdev)
 		return -ENOMEM;
-	}
 
 	BT_DBG("hdev %p", hdev);
 
@@ -321,7 +319,6 @@ static int bt_ti_probe(struct platform_device *pdev)
 	err = hci_register_dev(hdev);
 	if (err < 0) {
 		BT_ERR("Can't register HCI device error %d", err);
-		kfree(hst);
 		hci_free_dev(hdev);
 		return err;
 	}
@@ -347,7 +344,6 @@ static int bt_ti_remove(struct platform_device *pdev)
 	hci_unregister_dev(hdev);
 
 	hci_free_dev(hdev);
-	kfree(hst);
 
 	dev_set_drvdata(&pdev->dev, NULL);
 	return 0;
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 97a7784..036cb36 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -550,7 +550,7 @@ static int dtl1_probe(struct pcmcia_device *link)
 	dtl1_info_t *info;
 
 	/* Create new info device */
-	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
@@ -569,7 +569,6 @@ static void dtl1_detach(struct pcmcia_device *link)
 
 	dtl1_close(info);
 	pcmcia_disable_device(link);
-	kfree(info);
 }
 
 static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data)
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index 12172a6..0bc8a6a 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -58,7 +58,7 @@ static int ath_wakeup_ar3k(struct tty_struct *tty)
 		return status;
 
 	/* Disable Automatic RTSCTS */
-	memcpy(&ktermios, tty->termios, sizeof(ktermios));
+	ktermios = tty->termios;
 	ktermios.c_cflag &= ~CRTSCTS;
 	tty_set_termios(tty, &ktermios);
 
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
index 47ff7e4..161b109 100644
--- a/drivers/char/mbcs.c
+++ b/drivers/char/mbcs.c
@@ -507,7 +507,7 @@ static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma)
 
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
-	/* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */
+	/* Remap-pfn-range will mark the range VM_IO */
 	if (remap_pfn_range(vma,
 			    vma->vm_start,
 			    __pa(soft->gscr_addr) >> PAGE_SHIFT,
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index e5eedfa..0537903 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -322,7 +322,7 @@ static int mmap_mem(struct file *file, struct vm_area_struct *vma)
 
 	vma->vm_ops = &mmap_mem_ops;
 
-	/* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */
+	/* Remap-pfn-range will mark the range VM_IO */
 	if (remap_pfn_range(vma,
 			    vma->vm_start,
 			    vma->vm_pgoff,
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index 845f97f..e1f60f9 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -286,7 +286,7 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma,
 	atomic_set(&vdata->refcnt, 1);
 	vma->vm_private_data = vdata;
 
-	vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP | VM_DONTEXPAND);
+	vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
 	if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED)
 		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 	vma->vm_ops = &mspec_vm_ops;
diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c
index 1d82d58..164544a 100644
--- a/drivers/char/mwave/mwavedd.c
+++ b/drivers/char/mwave/mwavedd.c
@@ -430,7 +430,7 @@ static ssize_t mwave_write(struct file *file, const char __user *buf,
 
 static int register_serial_portandirq(unsigned int port, int irq)
 {
-	struct uart_port uart;
+	struct uart_8250_port uart;
 	
 	switch ( port ) {
 		case 0x3f8:
@@ -462,14 +462,14 @@ static int register_serial_portandirq(unsigned int port, int irq)
 	} /* switch */
 	/* irq is okay */
 
-	memset(&uart, 0, sizeof(struct uart_port));
+	memset(&uart, 0, sizeof(uart));
 	
-	uart.uartclk =  1843200;
-	uart.iobase = port;
-	uart.irq = irq;
-	uart.iotype = UPIO_PORT;
-	uart.flags =  UPF_SHARE_IRQ;
-	return serial8250_register_port(&uart);
+	uart.port.uartclk =  1843200;
+	uart.port.iobase = port;
+	uart.port.irq = irq;
+	uart.port.iotype = UPIO_PORT;
+	uart.port.flags =  UPF_SHARE_IRQ;
+	return serial8250_register_8250_port(&uart);
 }
 
 
diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c
index d45c334..a0e2f7d 100644
--- a/drivers/char/nwflash.c
+++ b/drivers/char/nwflash.c
@@ -30,7 +30,6 @@
 
 #include <asm/hardware/dec21285.h>
 #include <asm/io.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/uaccess.h>
 
@@ -179,9 +178,6 @@ static ssize_t flash_write(struct file *file, const char __user *buf,
 
 	written = 0;
 
-	leds_event(led_claim);
-	leds_event(led_green_on);
-
 	nBlock = (int) p >> 16;	//block # of 64K bytes
 
 	/*
@@ -258,11 +254,6 @@ static ssize_t flash_write(struct file *file, const char __user *buf,
 			printk(KERN_DEBUG "flash_write: written 0x%X bytes OK.\n", written);
 	}
 
-	/*
-	 * restore reg on exit
-	 */
-	leds_event(led_release);
-
 	mutex_unlock(&nwflash_mutex);
 
 	return written;
@@ -334,11 +325,6 @@ static int erase_block(int nBlock)
 	int temp, temp1;
 
 	/*
-	 * orange LED == erase
-	 */
-	leds_event(led_amber_on);
-
-	/*
 	 * reset footbridge to the correct offset 0 (...0..3)
 	 */
 	*CSR_ROMWRITEREG = 0;
@@ -446,12 +432,6 @@ static int write_block(unsigned long p, const char __user *buf, int count)
 	unsigned long timeout;
 	unsigned long timeout1;
 
-	/*
-	 * red LED == write
-	 */
-	leds_event(led_amber_off);
-	leds_event(led_red_on);
-
 	pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p));
 
 	/*
@@ -558,17 +538,9 @@ static int write_block(unsigned long p, const char __user *buf, int count)
 					       pWritePtr - FLASH_BASE);
 
 				/*
-				 * no LED == waiting
-				 */
-				leds_event(led_amber_off);
-				/*
 				 * wait couple ms
 				 */
 				msleep(10);
-				/*
-				 * red LED == write
-				 */
-				leds_event(led_red_on);
 
 				goto WriteRetry;
 			} else {
@@ -583,12 +555,6 @@ static int write_block(unsigned long p, const char __user *buf, int count)
 		}
 	}
 
-	/*
-	 * green LED == read/verify
-	 */
-	leds_event(led_amber_off);
-	leds_event(led_green_on);
-
 	msleep(10);
 
 	pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p));
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 0a484b4..5db08c7 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -1344,7 +1344,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
 	/* TODO:disable interrupts instead of reset to preserve signal states */
 	reset_device(info);
 
- 	if (!tty || tty->termios->c_cflag & HUPCL) {
+ 	if (!tty || tty->termios.c_cflag & HUPCL) {
  		info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
 		set_signals(info);
 	}
@@ -1385,7 +1385,7 @@ static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty)
 	port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI);
 	get_signals(info);
 
-	if (info->netcount || (tty && (tty->termios->c_cflag & CREAD)))
+	if (info->netcount || (tty && (tty->termios.c_cflag & CREAD)))
 		rx_start(info);
 
 	spin_unlock_irqrestore(&info->lock,flags);
@@ -1398,14 +1398,14 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty)
 	unsigned cflag;
 	int bits_per_char;
 
-	if (!tty || !tty->termios)
+	if (!tty)
 		return;
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):mgslpc_change_params(%s)\n",
 			 __FILE__,__LINE__, info->device_name );
 
-	cflag = tty->termios->c_cflag;
+	cflag = tty->termios.c_cflag;
 
 	/* if B0 rate (hangup) specified then negate DTR and RTS */
 	/* otherwise assert DTR and RTS */
@@ -1728,7 +1728,7 @@ static void mgslpc_throttle(struct tty_struct * tty)
 	if (I_IXOFF(tty))
 		mgslpc_send_xchar(tty, STOP_CHAR(tty));
 
- 	if (tty->termios->c_cflag & CRTSCTS) {
+ 	if (tty->termios.c_cflag & CRTSCTS) {
 		spin_lock_irqsave(&info->lock,flags);
 		info->serial_signals &= ~SerialSignal_RTS;
 	 	set_signals(info);
@@ -1757,7 +1757,7 @@ static void mgslpc_unthrottle(struct tty_struct * tty)
 			mgslpc_send_xchar(tty, START_CHAR(tty));
 	}
 
- 	if (tty->termios->c_cflag & CRTSCTS) {
+ 	if (tty->termios.c_cflag & CRTSCTS) {
 		spin_lock_irqsave(&info->lock,flags);
 		info->serial_signals |= SerialSignal_RTS;
 	 	set_signals(info);
@@ -2293,8 +2293,8 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
 			tty->driver->name );
 
 	/* just return if nothing has changed */
-	if ((tty->termios->c_cflag == old_termios->c_cflag)
-	    && (RELEVANT_IFLAG(tty->termios->c_iflag)
+	if ((tty->termios.c_cflag == old_termios->c_cflag)
+	    && (RELEVANT_IFLAG(tty->termios.c_iflag)
 		== RELEVANT_IFLAG(old_termios->c_iflag)))
 	  return;
 
@@ -2302,7 +2302,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
 
 	/* Handle transition to B0 status */
 	if (old_termios->c_cflag & CBAUD &&
-	    !(tty->termios->c_cflag & CBAUD)) {
+	    !(tty->termios.c_cflag & CBAUD)) {
 		info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
 		spin_lock_irqsave(&info->lock,flags);
 	 	set_signals(info);
@@ -2311,9 +2311,9 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
 
 	/* Handle transition away from B0 status */
 	if (!(old_termios->c_cflag & CBAUD) &&
-	    tty->termios->c_cflag & CBAUD) {
+	    tty->termios.c_cflag & CBAUD) {
 		info->serial_signals |= SerialSignal_DTR;
- 		if (!(tty->termios->c_cflag & CRTSCTS) ||
+ 		if (!(tty->termios.c_cflag & CRTSCTS) ||
  		    !test_bit(TTY_THROTTLED, &tty->flags)) {
 			info->serial_signals |= SerialSignal_RTS;
  		}
@@ -2324,7 +2324,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
 
 	/* Handle turning off CRTSCTS */
 	if (old_termios->c_cflag & CRTSCTS &&
-	    !(tty->termios->c_cflag & CRTSCTS)) {
+	    !(tty->termios.c_cflag & CRTSCTS)) {
 		tty->hw_stopped = 0;
 		tx_release(tty);
 	}
@@ -2731,6 +2731,8 @@ static void mgslpc_add_device(MGSLPC_INFO *info)
 #if SYNCLINK_GENERIC_HDLC
 	hdlcdev_init(info);
 #endif
+	tty_port_register_device(&info->port, serial_driver, info->line,
+			&info->p_dev->dev);
 }
 
 static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
@@ -2744,6 +2746,7 @@ static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
 				last->next_device = info->next_device;
 			else
 				mgslpc_device_list = info->next_device;
+			tty_unregister_device(serial_driver, info->line);
 #if SYNCLINK_GENERIC_HDLC
 			hdlcdev_exit(info);
 #endif
@@ -2798,77 +2801,63 @@ static const struct tty_operations mgslpc_ops = {
 	.proc_fops = &mgslpc_proc_fops,
 };
 
-static void synclink_cs_cleanup(void)
+static int __init synclink_cs_init(void)
 {
 	int rc;
 
-	while(mgslpc_device_list)
-		mgslpc_remove_device(mgslpc_device_list);
-
-	if (serial_driver) {
-		if ((rc = tty_unregister_driver(serial_driver)))
-			printk("%s(%d) failed to unregister tty driver err=%d\n",
-			       __FILE__,__LINE__,rc);
-		put_tty_driver(serial_driver);
+	if (break_on_load) {
+		mgslpc_get_text_ptr();
+		BREAKPOINT();
 	}
 
-	pcmcia_unregister_driver(&mgslpc_driver);
-}
-
-static int __init synclink_cs_init(void)
-{
-    int rc;
-
-    if (break_on_load) {
-	    mgslpc_get_text_ptr();
-	    BREAKPOINT();
-    }
-
-    if ((rc = pcmcia_register_driver(&mgslpc_driver)) < 0)
-	    return rc;
-
-    serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT);
-    if (!serial_driver) {
-	    rc = -ENOMEM;
-	    goto error;
-    }
+	serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT,
+			TTY_DRIVER_REAL_RAW |
+			TTY_DRIVER_DYNAMIC_DEV);
+	if (IS_ERR(serial_driver)) {
+		rc = PTR_ERR(serial_driver);
+		goto err;
+	}
 
-    /* Initialize the tty_driver structure */
-
-    serial_driver->driver_name = "synclink_cs";
-    serial_driver->name = "ttySLP";
-    serial_driver->major = ttymajor;
-    serial_driver->minor_start = 64;
-    serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
-    serial_driver->subtype = SERIAL_TYPE_NORMAL;
-    serial_driver->init_termios = tty_std_termios;
-    serial_driver->init_termios.c_cflag =
-	    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-    serial_driver->flags = TTY_DRIVER_REAL_RAW;
-    tty_set_operations(serial_driver, &mgslpc_ops);
-
-    if ((rc = tty_register_driver(serial_driver)) < 0) {
-	    printk("%s(%d):Couldn't register serial driver\n",
-		   __FILE__,__LINE__);
-	    put_tty_driver(serial_driver);
-	    serial_driver = NULL;
-	    goto error;
-    }
+	/* Initialize the tty_driver structure */
+	serial_driver->driver_name = "synclink_cs";
+	serial_driver->name = "ttySLP";
+	serial_driver->major = ttymajor;
+	serial_driver->minor_start = 64;
+	serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
+	serial_driver->subtype = SERIAL_TYPE_NORMAL;
+	serial_driver->init_termios = tty_std_termios;
+	serial_driver->init_termios.c_cflag =
+	B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	tty_set_operations(serial_driver, &mgslpc_ops);
+
+	rc = tty_register_driver(serial_driver);
+	if (rc < 0) {
+		printk(KERN_ERR "%s(%d):Couldn't register serial driver\n",
+				__FILE__, __LINE__);
+		goto err_put_tty;
+	}
 
-    printk("%s %s, tty major#%d\n",
-	   driver_name, driver_version,
-	   serial_driver->major);
+	rc = pcmcia_register_driver(&mgslpc_driver);
+	if (rc < 0)
+		goto err_unreg_tty;
 
-    return 0;
+	printk(KERN_INFO "%s %s, tty major#%d\n", driver_name, driver_version,
+			serial_driver->major);
 
-error:
-    synclink_cs_cleanup();
-    return rc;
+	return 0;
+err_unreg_tty:
+	tty_unregister_driver(serial_driver);
+err_put_tty:
+	put_tty_driver(serial_driver);
+err:
+	return rc;
 }
 
 static void __exit synclink_cs_exit(void)
 {
-	synclink_cs_cleanup();
+	pcmcia_unregister_driver(&mgslpc_driver);
+	tty_unregister_driver(serial_driver);
+	put_tty_driver(serial_driver);
 }
 
 module_init(synclink_cs_init);
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c
index ce29e7c..e95e0ab 100644
--- a/drivers/char/tlclk.c
+++ b/drivers/char/tlclk.c
@@ -784,8 +784,10 @@ static int __init tlclk_init(void)
 	}
 	tlclk_major = ret;
 	alarm_events = kzalloc( sizeof(struct tlclk_alarms), GFP_KERNEL);
-	if (!alarm_events)
+	if (!alarm_events) {
+		ret = -ENOMEM;
 		goto out1;
+	}
 
 	/* Read telecom clock IRQ number (Set by BIOS) */
 	if (!request_region(TLCLK_BASE, 8, "telco_clock")) {
diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c
index 46b77ed..af98f6d 100644
--- a/drivers/char/ttyprintk.c
+++ b/drivers/char/ttyprintk.c
@@ -67,7 +67,7 @@ static int tpk_printk(const unsigned char *buf, int count)
 				tmp[tpk_curr + 1] = '\0';
 				printk(KERN_INFO "%s%s", tpk_tag, tmp);
 				tpk_curr = 0;
-				if (buf[i + 1] == '\n')
+				if ((i + 1) < count && buf[i + 1] == '\n')
 					i++;
 				break;
 			case '\n':
@@ -178,11 +178,17 @@ static struct tty_driver *ttyprintk_driver;
 static int __init ttyprintk_init(void)
 {
 	int ret = -ENOMEM;
-	void *rp;
 
-	ttyprintk_driver = alloc_tty_driver(1);
-	if (!ttyprintk_driver)
-		return ret;
+	tty_port_init(&tpk_port.port);
+	tpk_port.port.ops = &null_ops;
+	mutex_init(&tpk_port.port_write_mutex);
+
+	ttyprintk_driver = tty_alloc_driver(1,
+			TTY_DRIVER_RESET_TERMIOS |
+			TTY_DRIVER_REAL_RAW |
+			TTY_DRIVER_UNNUMBERED_NODE);
+	if (IS_ERR(ttyprintk_driver))
+		return PTR_ERR(ttyprintk_driver);
 
 	ttyprintk_driver->driver_name = "ttyprintk";
 	ttyprintk_driver->name = "ttyprintk";
@@ -191,9 +197,8 @@ static int __init ttyprintk_init(void)
 	ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
 	ttyprintk_driver->init_termios = tty_std_termios;
 	ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
-	ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
-		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
 	tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+	tty_port_link_device(&tpk_port.port, ttyprintk_driver, 0);
 
 	ret = tty_register_driver(ttyprintk_driver);
 	if (ret < 0) {
@@ -201,22 +206,10 @@ static int __init ttyprintk_init(void)
 		goto error;
 	}
 
-	/* create our unnumbered device */
-	rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
-				ttyprintk_driver->name);
-	if (IS_ERR(rp)) {
-		printk(KERN_ERR "Couldn't create ttyprintk device\n");
-		ret = PTR_ERR(rp);
-		goto error;
-	}
-
-	tty_port_init(&tpk_port.port);
-	tpk_port.port.ops = &null_ops;
-	mutex_init(&tpk_port.port_write_mutex);
-
 	return 0;
 
 error:
+	tty_unregister_driver(ttyprintk_driver);
 	put_tty_driver(ttyprintk_driver);
 	ttyprintk_driver = NULL;
 	return ret;
diff --git a/drivers/clk/mxs/Makefile b/drivers/clk/mxs/Makefile
index 7bedeec..a6a2223 100644
--- a/drivers/clk/mxs/Makefile
+++ b/drivers/clk/mxs/Makefile
@@ -2,7 +2,7 @@
 # Makefile for mxs specific clk
 #
 
-obj-y += clk.o clk-pll.o clk-ref.o clk-div.o clk-frac.o
+obj-y += clk.o clk-pll.o clk-ref.o clk-div.o clk-frac.o clk-ssp.o
 
 obj-$(CONFIG_SOC_IMX23) += clk-imx23.o
 obj-$(CONFIG_SOC_IMX28) += clk-imx28.o
diff --git a/drivers/clk/mxs/clk-ssp.c b/drivers/clk/mxs/clk-ssp.c
new file mode 100644
index 0000000..af7bdbf
--- /dev/null
+++ b/drivers/clk/mxs/clk-ssp.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2012 DENX Software Engineering, GmbH
+ *
+ * Pulled from code:
+ * Portions copyright (C) 2003 Russell King, PXA MMCI Driver
+ * Portions copyright (C) 2004-2005 Pierre Ossman, W83L51xD SD/MMC driver
+ *
+ * Copyright 2008 Embedded Alley Solutions, Inc.
+ * Copyright 2009-2011 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/spi/mxs-spi.h>
+
+void mxs_ssp_set_clk_rate(struct mxs_ssp *ssp, unsigned int rate)
+{
+	unsigned int ssp_clk, ssp_sck;
+	u32 clock_divide, clock_rate;
+	u32 val;
+
+	ssp_clk = clk_get_rate(ssp->clk);
+
+	for (clock_divide = 2; clock_divide <= 254; clock_divide += 2) {
+		clock_rate = DIV_ROUND_UP(ssp_clk, rate * clock_divide);
+		clock_rate = (clock_rate > 0) ? clock_rate - 1 : 0;
+		if (clock_rate <= 255)
+			break;
+	}
+
+	if (clock_divide > 254) {
+		dev_err(ssp->dev,
+			"%s: cannot set clock to %d\n", __func__, rate);
+		return;
+	}
+
+	ssp_sck = ssp_clk / clock_divide / (1 + clock_rate);
+
+	val = readl(ssp->base + HW_SSP_TIMING(ssp));
+	val &= ~(BM_SSP_TIMING_CLOCK_DIVIDE | BM_SSP_TIMING_CLOCK_RATE);
+	val |= BF_SSP(clock_divide, TIMING_CLOCK_DIVIDE);
+	val |= BF_SSP(clock_rate, TIMING_CLOCK_RATE);
+	writel(val, ssp->base + HW_SSP_TIMING(ssp));
+
+	ssp->clk_rate = ssp_sck;
+
+	dev_dbg(ssp->dev,
+		"%s: clock_divide %d, clock_rate %d, ssp_clk %d, rate_actual %d, rate_requested %d\n",
+		__func__, clock_divide, clock_rate, ssp_clk, ssp_sck, rate);
+}
+EXPORT_SYMBOL_GPL(mxs_ssp_set_clk_rate);
diff --git a/drivers/clocksource/cs5535-clockevt.c b/drivers/clocksource/cs5535-clockevt.c
index 540795c..d927938 100644
--- a/drivers/clocksource/cs5535-clockevt.c
+++ b/drivers/clocksource/cs5535-clockevt.c
@@ -53,7 +53,7 @@ static struct cs5535_mfgpt_timer *cs5535_event_clock;
 #define MFGPT_PERIODIC (MFGPT_HZ / HZ)
 
 /*
- * The MFPGT timers on the CS5536 provide us with suitable timers to use
+ * The MFGPT timers on the CS5536 provide us with suitable timers to use
  * as clock event sources - not as good as a HPET or APIC, but certainly
  * better than the PIT.  This isn't a general purpose MFGPT driver, but
  * a simplified one designed specifically to act as a clock event source.
@@ -144,7 +144,7 @@ static int __init cs5535_mfgpt_init(void)
 
 	timer = cs5535_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING);
 	if (!timer) {
-		printk(KERN_ERR DRV_NAME ": Could not allocate MFPGT timer\n");
+		printk(KERN_ERR DRV_NAME ": Could not allocate MFGPT timer\n");
 		return -ENODEV;
 	}
 	cs5535_event_clock = timer;
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index 98b06ba..a5f7829 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -33,6 +33,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
 
 struct sh_cmt_priv {
 	void __iomem *mapbase;
@@ -52,6 +53,7 @@ struct sh_cmt_priv {
 	struct clock_event_device ced;
 	struct clocksource cs;
 	unsigned long total_cycles;
+	bool cs_enabled;
 };
 
 static DEFINE_RAW_SPINLOCK(sh_cmt_lock);
@@ -155,6 +157,9 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
 {
 	int k, ret;
 
+	pm_runtime_get_sync(&p->pdev->dev);
+	dev_pm_syscore_device(&p->pdev->dev, true);
+
 	/* enable clock */
 	ret = clk_enable(p->clk);
 	if (ret) {
@@ -221,6 +226,9 @@ static void sh_cmt_disable(struct sh_cmt_priv *p)
 
 	/* stop clock */
 	clk_disable(p->clk);
+
+	dev_pm_syscore_device(&p->pdev->dev, false);
+	pm_runtime_put(&p->pdev->dev);
 }
 
 /* private flags */
@@ -451,22 +459,42 @@ static int sh_cmt_clocksource_enable(struct clocksource *cs)
 	int ret;
 	struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
 
+	WARN_ON(p->cs_enabled);
+
 	p->total_cycles = 0;
 
 	ret = sh_cmt_start(p, FLAG_CLOCKSOURCE);
-	if (!ret)
+	if (!ret) {
 		__clocksource_updatefreq_hz(cs, p->rate);
+		p->cs_enabled = true;
+	}
 	return ret;
 }
 
 static void sh_cmt_clocksource_disable(struct clocksource *cs)
 {
-	sh_cmt_stop(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE);
+	struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
+
+	WARN_ON(!p->cs_enabled);
+
+	sh_cmt_stop(p, FLAG_CLOCKSOURCE);
+	p->cs_enabled = false;
+}
+
+static void sh_cmt_clocksource_suspend(struct clocksource *cs)
+{
+	struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
+
+	sh_cmt_stop(p, FLAG_CLOCKSOURCE);
+	pm_genpd_syscore_poweroff(&p->pdev->dev);
 }
 
 static void sh_cmt_clocksource_resume(struct clocksource *cs)
 {
-	sh_cmt_start(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE);
+	struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
+
+	pm_genpd_syscore_poweron(&p->pdev->dev);
+	sh_cmt_start(p, FLAG_CLOCKSOURCE);
 }
 
 static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
@@ -479,7 +507,7 @@ static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
 	cs->read = sh_cmt_clocksource_read;
 	cs->enable = sh_cmt_clocksource_enable;
 	cs->disable = sh_cmt_clocksource_disable;
-	cs->suspend = sh_cmt_clocksource_disable;
+	cs->suspend = sh_cmt_clocksource_suspend;
 	cs->resume = sh_cmt_clocksource_resume;
 	cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
 	cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
@@ -562,6 +590,16 @@ static int sh_cmt_clock_event_next(unsigned long delta,
 	return 0;
 }
 
+static void sh_cmt_clock_event_suspend(struct clock_event_device *ced)
+{
+	pm_genpd_syscore_poweroff(&ced_to_sh_cmt(ced)->pdev->dev);
+}
+
+static void sh_cmt_clock_event_resume(struct clock_event_device *ced)
+{
+	pm_genpd_syscore_poweron(&ced_to_sh_cmt(ced)->pdev->dev);
+}
+
 static void sh_cmt_register_clockevent(struct sh_cmt_priv *p,
 				       char *name, unsigned long rating)
 {
@@ -576,6 +614,8 @@ static void sh_cmt_register_clockevent(struct sh_cmt_priv *p,
 	ced->cpumask = cpumask_of(0);
 	ced->set_next_event = sh_cmt_clock_event_next;
 	ced->set_mode = sh_cmt_clock_event_mode;
+	ced->suspend = sh_cmt_clock_event_suspend;
+	ced->resume = sh_cmt_clock_event_resume;
 
 	dev_info(&p->pdev->dev, "used for clock events\n");
 	clockevents_register_device(ced);
@@ -670,6 +710,7 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
 		dev_err(&p->pdev->dev, "registration failed\n");
 		goto err1;
 	}
+	p->cs_enabled = false;
 
 	ret = setup_irq(irq, &p->irqaction);
 	if (ret) {
@@ -688,14 +729,17 @@ err0:
 static int __devinit sh_cmt_probe(struct platform_device *pdev)
 {
 	struct sh_cmt_priv *p = platform_get_drvdata(pdev);
+	struct sh_timer_config *cfg = pdev->dev.platform_data;
 	int ret;
 
-	if (!is_early_platform_device(pdev))
-		pm_genpd_dev_always_on(&pdev->dev, true);
+	if (!is_early_platform_device(pdev)) {
+		pm_runtime_set_active(&pdev->dev);
+		pm_runtime_enable(&pdev->dev);
+	}
 
 	if (p) {
 		dev_info(&pdev->dev, "kept as earlytimer\n");
-		return 0;
+		goto out;
 	}
 
 	p = kmalloc(sizeof(*p), GFP_KERNEL);
@@ -708,8 +752,19 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev)
 	if (ret) {
 		kfree(p);
 		platform_set_drvdata(pdev, NULL);
+		pm_runtime_idle(&pdev->dev);
+		return ret;
 	}
-	return ret;
+	if (is_early_platform_device(pdev))
+		return 0;
+
+ out:
+	if (cfg->clockevent_rating || cfg->clocksource_rating)
+		pm_runtime_irq_safe(&pdev->dev);
+	else
+		pm_runtime_idle(&pdev->dev);
+
+	return 0;
 }
 
 static int __devexit sh_cmt_remove(struct platform_device *pdev)
diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c
index d9b76ca..c5eea85 100644
--- a/drivers/clocksource/sh_mtu2.c
+++ b/drivers/clocksource/sh_mtu2.c
@@ -32,6 +32,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
 
 struct sh_mtu2_priv {
 	void __iomem *mapbase;
@@ -123,6 +124,9 @@ static int sh_mtu2_enable(struct sh_mtu2_priv *p)
 {
 	int ret;
 
+	pm_runtime_get_sync(&p->pdev->dev);
+	dev_pm_syscore_device(&p->pdev->dev, true);
+
 	/* enable clock */
 	ret = clk_enable(p->clk);
 	if (ret) {
@@ -157,6 +161,9 @@ static void sh_mtu2_disable(struct sh_mtu2_priv *p)
 
 	/* stop clock */
 	clk_disable(p->clk);
+
+	dev_pm_syscore_device(&p->pdev->dev, false);
+	pm_runtime_put(&p->pdev->dev);
 }
 
 static irqreturn_t sh_mtu2_interrupt(int irq, void *dev_id)
@@ -208,6 +215,16 @@ static void sh_mtu2_clock_event_mode(enum clock_event_mode mode,
 	}
 }
 
+static void sh_mtu2_clock_event_suspend(struct clock_event_device *ced)
+{
+	pm_genpd_syscore_poweroff(&ced_to_sh_mtu2(ced)->pdev->dev);
+}
+
+static void sh_mtu2_clock_event_resume(struct clock_event_device *ced)
+{
+	pm_genpd_syscore_poweron(&ced_to_sh_mtu2(ced)->pdev->dev);
+}
+
 static void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p,
 				       char *name, unsigned long rating)
 {
@@ -221,6 +238,8 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p,
 	ced->rating = rating;
 	ced->cpumask = cpumask_of(0);
 	ced->set_mode = sh_mtu2_clock_event_mode;
+	ced->suspend = sh_mtu2_clock_event_suspend;
+	ced->resume = sh_mtu2_clock_event_resume;
 
 	dev_info(&p->pdev->dev, "used for clock events\n");
 	clockevents_register_device(ced);
@@ -305,14 +324,17 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev)
 static int __devinit sh_mtu2_probe(struct platform_device *pdev)
 {
 	struct sh_mtu2_priv *p = platform_get_drvdata(pdev);
+	struct sh_timer_config *cfg = pdev->dev.platform_data;
 	int ret;
 
-	if (!is_early_platform_device(pdev))
-		pm_genpd_dev_always_on(&pdev->dev, true);
+	if (!is_early_platform_device(pdev)) {
+		pm_runtime_set_active(&pdev->dev);
+		pm_runtime_enable(&pdev->dev);
+	}
 
 	if (p) {
 		dev_info(&pdev->dev, "kept as earlytimer\n");
-		return 0;
+		goto out;
 	}
 
 	p = kmalloc(sizeof(*p), GFP_KERNEL);
@@ -325,8 +347,19 @@ static int __devinit sh_mtu2_probe(struct platform_device *pdev)
 	if (ret) {
 		kfree(p);
 		platform_set_drvdata(pdev, NULL);
+		pm_runtime_idle(&pdev->dev);
+		return ret;
 	}
-	return ret;
+	if (is_early_platform_device(pdev))
+		return 0;
+
+ out:
+	if (cfg->clockevent_rating)
+		pm_runtime_irq_safe(&pdev->dev);
+	else
+		pm_runtime_idle(&pdev->dev);
+
+	return 0;
 }
 
 static int __devexit sh_mtu2_remove(struct platform_device *pdev)
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
index c1b51d4..0cc4add 100644
--- a/drivers/clocksource/sh_tmu.c
+++ b/drivers/clocksource/sh_tmu.c
@@ -33,6 +33,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
 
 struct sh_tmu_priv {
 	void __iomem *mapbase;
@@ -43,6 +44,8 @@ struct sh_tmu_priv {
 	unsigned long periodic;
 	struct clock_event_device ced;
 	struct clocksource cs;
+	bool cs_enabled;
+	unsigned int enable_count;
 };
 
 static DEFINE_RAW_SPINLOCK(sh_tmu_lock);
@@ -107,7 +110,7 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_priv *p, int start)
 	raw_spin_unlock_irqrestore(&sh_tmu_lock, flags);
 }
 
-static int sh_tmu_enable(struct sh_tmu_priv *p)
+static int __sh_tmu_enable(struct sh_tmu_priv *p)
 {
 	int ret;
 
@@ -135,7 +138,18 @@ static int sh_tmu_enable(struct sh_tmu_priv *p)
 	return 0;
 }
 
-static void sh_tmu_disable(struct sh_tmu_priv *p)
+static int sh_tmu_enable(struct sh_tmu_priv *p)
+{
+	if (p->enable_count++ > 0)
+		return 0;
+
+	pm_runtime_get_sync(&p->pdev->dev);
+	dev_pm_syscore_device(&p->pdev->dev, true);
+
+	return __sh_tmu_enable(p);
+}
+
+static void __sh_tmu_disable(struct sh_tmu_priv *p)
 {
 	/* disable channel */
 	sh_tmu_start_stop_ch(p, 0);
@@ -147,6 +161,20 @@ static void sh_tmu_disable(struct sh_tmu_priv *p)
 	clk_disable(p->clk);
 }
 
+static void sh_tmu_disable(struct sh_tmu_priv *p)
+{
+	if (WARN_ON(p->enable_count == 0))
+		return;
+
+	if (--p->enable_count > 0)
+		return;
+
+	__sh_tmu_disable(p);
+
+	dev_pm_syscore_device(&p->pdev->dev, false);
+	pm_runtime_put(&p->pdev->dev);
+}
+
 static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta,
 			    int periodic)
 {
@@ -203,15 +231,53 @@ static int sh_tmu_clocksource_enable(struct clocksource *cs)
 	struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
 	int ret;
 
+	if (WARN_ON(p->cs_enabled))
+		return 0;
+
 	ret = sh_tmu_enable(p);
-	if (!ret)
+	if (!ret) {
 		__clocksource_updatefreq_hz(cs, p->rate);
+		p->cs_enabled = true;
+	}
+
 	return ret;
 }
 
 static void sh_tmu_clocksource_disable(struct clocksource *cs)
 {
-	sh_tmu_disable(cs_to_sh_tmu(cs));
+	struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
+
+	if (WARN_ON(!p->cs_enabled))
+		return;
+
+	sh_tmu_disable(p);
+	p->cs_enabled = false;
+}
+
+static void sh_tmu_clocksource_suspend(struct clocksource *cs)
+{
+	struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
+
+	if (!p->cs_enabled)
+		return;
+
+	if (--p->enable_count == 0) {
+		__sh_tmu_disable(p);
+		pm_genpd_syscore_poweroff(&p->pdev->dev);
+	}
+}
+
+static void sh_tmu_clocksource_resume(struct clocksource *cs)
+{
+	struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
+
+	if (!p->cs_enabled)
+		return;
+
+	if (p->enable_count++ == 0) {
+		pm_genpd_syscore_poweron(&p->pdev->dev);
+		__sh_tmu_enable(p);
+	}
 }
 
 static int sh_tmu_register_clocksource(struct sh_tmu_priv *p,
@@ -224,6 +290,8 @@ static int sh_tmu_register_clocksource(struct sh_tmu_priv *p,
 	cs->read = sh_tmu_clocksource_read;
 	cs->enable = sh_tmu_clocksource_enable;
 	cs->disable = sh_tmu_clocksource_disable;
+	cs->suspend = sh_tmu_clocksource_suspend;
+	cs->resume = sh_tmu_clocksource_resume;
 	cs->mask = CLOCKSOURCE_MASK(32);
 	cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
 
@@ -301,6 +369,16 @@ static int sh_tmu_clock_event_next(unsigned long delta,
 	return 0;
 }
 
+static void sh_tmu_clock_event_suspend(struct clock_event_device *ced)
+{
+	pm_genpd_syscore_poweroff(&ced_to_sh_tmu(ced)->pdev->dev);
+}
+
+static void sh_tmu_clock_event_resume(struct clock_event_device *ced)
+{
+	pm_genpd_syscore_poweron(&ced_to_sh_tmu(ced)->pdev->dev);
+}
+
 static void sh_tmu_register_clockevent(struct sh_tmu_priv *p,
 				       char *name, unsigned long rating)
 {
@@ -316,6 +394,8 @@ static void sh_tmu_register_clockevent(struct sh_tmu_priv *p,
 	ced->cpumask = cpumask_of(0);
 	ced->set_next_event = sh_tmu_clock_event_next;
 	ced->set_mode = sh_tmu_clock_event_mode;
+	ced->suspend = sh_tmu_clock_event_suspend;
+	ced->resume = sh_tmu_clock_event_resume;
 
 	dev_info(&p->pdev->dev, "used for clock events\n");
 
@@ -392,6 +472,8 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
 		ret = PTR_ERR(p->clk);
 		goto err1;
 	}
+	p->cs_enabled = false;
+	p->enable_count = 0;
 
 	return sh_tmu_register(p, (char *)dev_name(&p->pdev->dev),
 			       cfg->clockevent_rating,
@@ -405,14 +487,17 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
 static int __devinit sh_tmu_probe(struct platform_device *pdev)
 {
 	struct sh_tmu_priv *p = platform_get_drvdata(pdev);
+	struct sh_timer_config *cfg = pdev->dev.platform_data;
 	int ret;
 
-	if (!is_early_platform_device(pdev))
-		pm_genpd_dev_always_on(&pdev->dev, true);
+	if (!is_early_platform_device(pdev)) {
+		pm_runtime_set_active(&pdev->dev);
+		pm_runtime_enable(&pdev->dev);
+	}
 
 	if (p) {
 		dev_info(&pdev->dev, "kept as earlytimer\n");
-		return 0;
+		goto out;
 	}
 
 	p = kmalloc(sizeof(*p), GFP_KERNEL);
@@ -425,8 +510,19 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev)
 	if (ret) {
 		kfree(p);
 		platform_set_drvdata(pdev, NULL);
+		pm_runtime_idle(&pdev->dev);
+		return ret;
 	}
-	return ret;
+	if (is_early_platform_device(pdev))
+		return 0;
+
+ out:
+	if (cfg->clockevent_rating || cfg->clocksource_rating)
+		pm_runtime_irq_safe(&pdev->dev);
+	else
+		pm_runtime_idle(&pdev->dev);
+
+	return 0;
 }
 
 static int __devexit sh_tmu_remove(struct platform_device *pdev)
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 235a340..a1563d7 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -504,6 +504,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
 				j_dbs_info->prev_cpu_nice =
 						kcpustat_cpu(j).cpustat[CPUTIME_NICE];
 		}
+		this_dbs_info->cpu = cpu;
 		this_dbs_info->down_skip = 0;
 		this_dbs_info->requested_freq = policy->cur;
 
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index 17fa04d..b47034e 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -218,7 +218,7 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
 
 	policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu);
 
-	if (atomic_inc_return(&freq_table_users) == 1)
+	if (!freq_table)
 		result = opp_init_cpufreq_table(mpu_dev, &freq_table);
 
 	if (result) {
@@ -227,6 +227,8 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
 		goto fail_ck;
 	}
 
+	atomic_inc_return(&freq_table_users);
+
 	result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
 	if (result)
 		goto fail_table;
diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c
index 2c9bf26..3265844 100644
--- a/drivers/cpuidle/coupled.c
+++ b/drivers/cpuidle/coupled.c
@@ -678,10 +678,22 @@ static int cpuidle_coupled_cpu_notify(struct notifier_block *nb,
 	int cpu = (unsigned long)hcpu;
 	struct cpuidle_device *dev;
 
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_UP_PREPARE:
+	case CPU_DOWN_PREPARE:
+	case CPU_ONLINE:
+	case CPU_DEAD:
+	case CPU_UP_CANCELED:
+	case CPU_DOWN_FAILED:
+		break;
+	default:
+		return NOTIFY_OK;
+	}
+
 	mutex_lock(&cpuidle_lock);
 
 	dev = per_cpu(cpuidle_devices, cpu);
-	if (!dev->coupled)
+	if (!dev || !dev->coupled)
 		goto out;
 
 	switch (action & ~CPU_TASKS_FROZEN) {
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index b6a09ea..9b78405 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -88,6 +88,8 @@ static int ladder_select_state(struct cpuidle_driver *drv,
 
 	/* consider promotion */
 	if (last_idx < drv->state_count - 1 &&
+	    !drv->states[last_idx + 1].disabled &&
+	    !dev->states_usage[last_idx + 1].disable &&
 	    last_residency > last_state->threshold.promotion_time &&
 	    drv->states[last_idx + 1].exit_latency <= latency_req) {
 		last_state->stats.promotion_count++;
@@ -100,7 +102,9 @@ static int ladder_select_state(struct cpuidle_driver *drv,
 
 	/* consider demotion */
 	if (last_idx > CPUIDLE_DRIVER_STATE_START &&
-	    drv->states[last_idx].exit_latency > latency_req) {
+	    (drv->states[last_idx].disabled ||
+	    dev->states_usage[last_idx].disable ||
+	    drv->states[last_idx].exit_latency > latency_req)) {
 		int i;
 
 		for (i = last_idx - 1; i > CPUIDLE_DRIVER_STATE_START; i--) {
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 7d74d09..662588a 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -298,21 +298,15 @@ config CRYPTO_DEV_TEGRA_AES
 	  will be called tegra-aes.
 
 config CRYPTO_DEV_NX
-	tristate "Support for Power7+ in-Nest cryptographic acceleration"
+	bool "Support for IBM Power7+ in-Nest cryptographic acceleration"
 	depends on PPC64 && IBMVIO
-	select CRYPTO_AES
-	select CRYPTO_CBC
-	select CRYPTO_ECB
-	select CRYPTO_CCM
-	select CRYPTO_GCM
-	select CRYPTO_AUTHENC
-	select CRYPTO_XCBC
-	select CRYPTO_SHA256
-	select CRYPTO_SHA512
+	default n
 	help
-	  Support for Power7+ in-Nest cryptographic acceleration. This
-	  module supports acceleration for AES and SHA2 algorithms. If you
-	  choose 'M' here, this module will be called nx_crypto.
+	  Support for Power7+ in-Nest cryptographic acceleration.
+
+if CRYPTO_DEV_NX
+	source "drivers/crypto/nx/Kconfig"
+endif
 
 config CRYPTO_DEV_UX500
 	tristate "Driver for ST-Ericsson UX500 crypto hardware acceleration"
diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
index 6bb20ff..872ca8c 100644
--- a/drivers/crypto/atmel-aes.c
+++ b/drivers/crypto/atmel-aes.c
@@ -1017,7 +1017,6 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
 	int err, i, j;
 
 	for (i = 0; i < ARRAY_SIZE(aes_algs); i++) {
-		INIT_LIST_HEAD(&aes_algs[i].cra_list);
 		err = crypto_register_alg(&aes_algs[i]);
 		if (err)
 			goto err_aes_algs;
@@ -1026,7 +1025,6 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
 	atmel_aes_hw_version_init(dd);
 
 	if (dd->hw_version >= 0x130) {
-		INIT_LIST_HEAD(&aes_cfb64_alg[0].cra_list);
 		err = crypto_register_alg(&aes_cfb64_alg[0]);
 		if (err)
 			goto err_aes_cfb64_alg;
diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c
index eb2b61e..53c1680 100644
--- a/drivers/crypto/atmel-tdes.c
+++ b/drivers/crypto/atmel-tdes.c
@@ -1044,7 +1044,6 @@ static int atmel_tdes_register_algs(struct atmel_tdes_dev *dd)
 	int err, i, j;
 
 	for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) {
-		INIT_LIST_HEAD(&tdes_algs[i].cra_list);
 		err = crypto_register_alg(&tdes_algs[i]);
 		if (err)
 			goto err_tdes_algs;
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index 0c1ea84..6b48295 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -205,7 +205,7 @@ static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx,
 {
 	u32 *key_jump_cmd;
 
-	init_sh_desc(desc, HDR_SHARE_WAIT);
+	init_sh_desc(desc, HDR_SHARE_SERIAL);
 
 	/* Skip if already shared */
 	key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
@@ -302,7 +302,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
 	desc = ctx->sh_desc_dec;
 
 	/* aead_decrypt shared descriptor */
-	init_sh_desc(desc, HDR_SHARE_WAIT);
+	init_sh_desc(desc, HDR_SHARE_SERIAL);
 
 	/* Skip if already shared */
 	key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
@@ -564,7 +564,7 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
 
 	/* ablkcipher_encrypt shared descriptor */
 	desc = ctx->sh_desc_enc;
-	init_sh_desc(desc, HDR_SHARE_WAIT);
+	init_sh_desc(desc, HDR_SHARE_SERIAL);
 	/* Skip if already shared */
 	key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
 				   JUMP_COND_SHRD);
@@ -605,7 +605,7 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
 	/* ablkcipher_decrypt shared descriptor */
 	desc = ctx->sh_desc_dec;
 
-	init_sh_desc(desc, HDR_SHARE_WAIT);
+	init_sh_desc(desc, HDR_SHARE_SERIAL);
 	/* Skip if already shared */
 	key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
 				   JUMP_COND_SHRD);
diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
index 895aaf2..fbf3fe8 100644
--- a/drivers/crypto/caam/caamhash.c
+++ b/drivers/crypto/caam/caamhash.c
@@ -225,7 +225,7 @@ static inline void init_sh_desc_key_ahash(u32 *desc, struct caam_hash_ctx *ctx)
 {
 	u32 *key_jump_cmd;
 
-	init_sh_desc(desc, HDR_SHARE_WAIT);
+	init_sh_desc(desc, HDR_SHARE_SERIAL);
 
 	if (ctx->split_key_len) {
 		/* Skip if already shared */
@@ -311,7 +311,7 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash)
 	/* ahash_update shared descriptor */
 	desc = ctx->sh_desc_update;
 
-	init_sh_desc(desc, HDR_SHARE_WAIT);
+	init_sh_desc(desc, HDR_SHARE_SERIAL);
 
 	/* Import context from software */
 	append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT |
@@ -1736,8 +1736,11 @@ static void __exit caam_algapi_hash_exit(void)
 	struct caam_hash_alg *t_alg, *n;
 
 	dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
-	if (!dev_node)
-		return;
+	if (!dev_node) {
+		dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+		if (!dev_node)
+			return;
+	}
 
 	pdev = of_find_device_by_node(dev_node);
 	if (!pdev)
@@ -1812,8 +1815,11 @@ static int __init caam_algapi_hash_init(void)
 	int i = 0, err = 0;
 
 	dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
-	if (!dev_node)
-		return -ENODEV;
+	if (!dev_node) {
+		dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+		if (!dev_node)
+			return -ENODEV;
+	}
 
 	pdev = of_find_device_by_node(dev_node);
 	if (!pdev)
diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c
index e2bfe16..d1939a9 100644
--- a/drivers/crypto/caam/caamrng.c
+++ b/drivers/crypto/caam/caamrng.c
@@ -193,7 +193,7 @@ static inline void rng_create_sh_desc(struct caam_rng_ctx *ctx)
 	struct device *jrdev = ctx->jrdev;
 	u32 *desc = ctx->sh_desc;
 
-	init_sh_desc(desc, HDR_SHARE_WAIT);
+	init_sh_desc(desc, HDR_SHARE_SERIAL);
 
 	/* Propagate errors from shared to job descriptor */
 	append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD);
@@ -284,8 +284,11 @@ static int __init caam_rng_init(void)
 	struct caam_drv_private *priv;
 
 	dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
-	if (!dev_node)
-		return -ENODEV;
+	if (!dev_node) {
+		dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+		if (!dev_node)
+			return -ENODEV;
+	}
 
 	pdev = of_find_device_by_node(dev_node);
 	if (!pdev)
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index 53c8c51..93d1407 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -63,7 +63,7 @@ static void caam_jr_dequeue(unsigned long devarg)
 
 		head = ACCESS_ONCE(jrp->head);
 
-		spin_lock_bh(&jrp->outlock);
+		spin_lock(&jrp->outlock);
 
 		sw_idx = tail = jrp->tail;
 		hw_idx = jrp->out_ring_read_index;
@@ -115,7 +115,7 @@ static void caam_jr_dequeue(unsigned long devarg)
 			jrp->tail = tail;
 		}
 
-		spin_unlock_bh(&jrp->outlock);
+		spin_unlock(&jrp->outlock);
 
 		/* Finally, execute user's callback */
 		usercall(dev, userdesc, userstatus, userarg);
@@ -236,14 +236,14 @@ int caam_jr_enqueue(struct device *dev, u32 *desc,
 		return -EIO;
 	}
 
-	spin_lock(&jrp->inplock);
+	spin_lock_bh(&jrp->inplock);
 
 	head = jrp->head;
 	tail = ACCESS_ONCE(jrp->tail);
 
 	if (!rd_reg32(&jrp->rregs->inpring_avail) ||
 	    CIRC_SPACE(head, tail, JOBR_DEPTH) <= 0) {
-		spin_unlock(&jrp->inplock);
+		spin_unlock_bh(&jrp->inplock);
 		dma_unmap_single(dev, desc_dma, desc_size, DMA_TO_DEVICE);
 		return -EBUSY;
 	}
@@ -265,7 +265,7 @@ int caam_jr_enqueue(struct device *dev, u32 *desc,
 
 	wr_reg32(&jrp->rregs->inpring_jobadd, 1);
 
-	spin_unlock(&jrp->inplock);
+	spin_unlock_bh(&jrp->inplock);
 
 	return 0;
 }
diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c
index f3e36c8..933fb4b4 100644
--- a/drivers/crypto/geode-aes.c
+++ b/drivers/crypto/geode-aes.c
@@ -289,7 +289,6 @@ static struct crypto_alg geode_alg = {
 	.cra_blocksize		=	AES_MIN_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct geode_aes_op),
 	.cra_module			=	THIS_MODULE,
-	.cra_list			=	LIST_HEAD_INIT(geode_alg.cra_list),
 	.cra_u				=	{
 		.cipher	=	{
 			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
@@ -402,7 +401,6 @@ static struct crypto_alg geode_cbc_alg = {
 	.cra_alignmask		=	15,
 	.cra_type			=	&crypto_blkcipher_type,
 	.cra_module			=	THIS_MODULE,
-	.cra_list			=	LIST_HEAD_INIT(geode_cbc_alg.cra_list),
 	.cra_u				=	{
 		.blkcipher	=	{
 			.min_keysize	=	AES_MIN_KEY_SIZE,
@@ -489,7 +487,6 @@ static struct crypto_alg geode_ecb_alg = {
 	.cra_alignmask		=	15,
 	.cra_type			=	&crypto_blkcipher_type,
 	.cra_module			=	THIS_MODULE,
-	.cra_list			=	LIST_HEAD_INIT(geode_ecb_alg.cra_list),
 	.cra_u				=	{
 		.blkcipher	=	{
 			.min_keysize	=	AES_MIN_KEY_SIZE,
diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c
index c9c4bef..df14358 100644
--- a/drivers/crypto/hifn_795x.c
+++ b/drivers/crypto/hifn_795x.c
@@ -821,8 +821,8 @@ static int hifn_register_rng(struct hifn_device *dev)
 	/*
 	 * We must wait at least 256 Pk_clk cycles between two reads of the rng.
 	 */
-	dev->rng_wait_time	= DIV_ROUND_UP(NSEC_PER_SEC, dev->pk_clk_freq) *
-				  256;
+	dev->rng_wait_time	= DIV_ROUND_UP_ULL(NSEC_PER_SEC,
+						   dev->pk_clk_freq) * 256;
 
 	dev->rng.name		= dev->name;
 	dev->rng.data_present	= hifn_rng_data_present,
diff --git a/drivers/crypto/nx/Kconfig b/drivers/crypto/nx/Kconfig
new file mode 100644
index 0000000..f826166
--- /dev/null
+++ b/drivers/crypto/nx/Kconfig
@@ -0,0 +1,26 @@
+config CRYPTO_DEV_NX_ENCRYPT
+	tristate "Encryption acceleration support"
+	depends on PPC64 && IBMVIO
+	default y
+	select CRYPTO_AES
+	select CRYPTO_CBC
+	select CRYPTO_ECB
+	select CRYPTO_CCM
+	select CRYPTO_GCM
+	select CRYPTO_AUTHENC
+	select CRYPTO_XCBC
+	select CRYPTO_SHA256
+	select CRYPTO_SHA512
+	help
+	  Support for Power7+ in-Nest encryption acceleration. This
+	  module supports acceleration for AES and SHA2 algorithms. If you
+	  choose 'M' here, this module will be called nx_crypto.
+
+config CRYPTO_DEV_NX_COMPRESS
+	tristate "Compression acceleration support"
+	depends on PPC64 && IBMVIO
+	default y
+	help
+	  Support for Power7+ in-Nest compression acceleration. This
+	  module supports acceleration for AES and SHA2 algorithms. If you
+	  choose 'M' here, this module will be called nx_compress.
diff --git a/drivers/crypto/nx/Makefile b/drivers/crypto/nx/Makefile
index 411ce59..bb770ea 100644
--- a/drivers/crypto/nx/Makefile
+++ b/drivers/crypto/nx/Makefile
@@ -1,4 +1,4 @@
-obj-$(CONFIG_CRYPTO_DEV_NX) += nx-crypto.o
+obj-$(CONFIG_CRYPTO_DEV_NX_ENCRYPT) += nx-crypto.o
 nx-crypto-objs := nx.o \
 		  nx_debugfs.o \
 		  nx-aes-cbc.o \
@@ -9,3 +9,6 @@ nx-crypto-objs := nx.o \
 		  nx-aes-xcbc.o \
 		  nx-sha256.o \
 		  nx-sha512.o
+
+obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS) += nx-compress.o
+nx-compress-objs := nx-842.o
diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c
new file mode 100644
index 0000000..9da0fb2
--- /dev/null
+++ b/drivers/crypto/nx/nx-842.c
@@ -0,0 +1,1615 @@
+/*
+ * Driver for IBM Power 842 compression accelerator
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright (C) IBM Corporation, 2012
+ *
+ * Authors: Robert Jennings <rcj@linux.vnet.ibm.com>
+ *          Seth Jennings <sjenning@linux.vnet.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <asm/vio.h>
+#include <asm/pSeries_reconfig.h>
+#include <linux/slab.h>
+#include <asm/abs_addr.h>
+#include <linux/nx842.h>
+#include <linux/kernel.h>
+
+#include "nx_csbcpb.h" /* struct nx_csbcpb */
+
+#define MODULE_NAME "nx-compress"
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Robert Jennings <rcj@linux.vnet.ibm.com>");
+MODULE_DESCRIPTION("842 H/W Compression driver for IBM Power processors");
+
+#define SHIFT_4K 12
+#define SHIFT_64K 16
+#define SIZE_4K (1UL << SHIFT_4K)
+#define SIZE_64K (1UL << SHIFT_64K)
+
+/* IO buffer must be 128 byte aligned */
+#define IO_BUFFER_ALIGN 128
+
+struct nx842_header {
+	int blocks_nr; /* number of compressed blocks */
+	int offset; /* offset of the first block (from beginning of header) */
+	int sizes[0]; /* size of compressed blocks */
+};
+
+static inline int nx842_header_size(const struct nx842_header *hdr)
+{
+	return sizeof(struct nx842_header) +
+			hdr->blocks_nr * sizeof(hdr->sizes[0]);
+}
+
+/* Macros for fields within nx_csbcpb */
+/* Check the valid bit within the csbcpb valid field */
+#define NX842_CSBCBP_VALID_CHK(x) (x & BIT_MASK(7))
+
+/* CE macros operate on the completion_extension field bits in the csbcpb.
+ * CE0 0=full completion, 1=partial completion
+ * CE1 0=CE0 indicates completion, 1=termination (output may be modified)
+ * CE2 0=processed_bytes is source bytes, 1=processed_bytes is target bytes */
+#define NX842_CSBCPB_CE0(x)	(x & BIT_MASK(7))
+#define NX842_CSBCPB_CE1(x)	(x & BIT_MASK(6))
+#define NX842_CSBCPB_CE2(x)	(x & BIT_MASK(5))
+
+/* The NX unit accepts data only on 4K page boundaries */
+#define NX842_HW_PAGE_SHIFT	SHIFT_4K
+#define NX842_HW_PAGE_SIZE	(ASM_CONST(1) << NX842_HW_PAGE_SHIFT)
+#define NX842_HW_PAGE_MASK	(~(NX842_HW_PAGE_SIZE-1))
+
+enum nx842_status {
+	UNAVAILABLE,
+	AVAILABLE
+};
+
+struct ibm_nx842_counters {
+	atomic64_t comp_complete;
+	atomic64_t comp_failed;
+	atomic64_t decomp_complete;
+	atomic64_t decomp_failed;
+	atomic64_t swdecomp;
+	atomic64_t comp_times[32];
+	atomic64_t decomp_times[32];
+};
+
+static struct nx842_devdata {
+	struct vio_dev *vdev;
+	struct device *dev;
+	struct ibm_nx842_counters *counters;
+	unsigned int max_sg_len;
+	unsigned int max_sync_size;
+	unsigned int max_sync_sg;
+	enum nx842_status status;
+} __rcu *devdata;
+static DEFINE_SPINLOCK(devdata_mutex);
+
+#define NX842_COUNTER_INC(_x) \
+static inline void nx842_inc_##_x( \
+	const struct nx842_devdata *dev) { \
+	if (dev) \
+		atomic64_inc(&dev->counters->_x); \
+}
+NX842_COUNTER_INC(comp_complete);
+NX842_COUNTER_INC(comp_failed);
+NX842_COUNTER_INC(decomp_complete);
+NX842_COUNTER_INC(decomp_failed);
+NX842_COUNTER_INC(swdecomp);
+
+#define NX842_HIST_SLOTS 16
+
+static void ibm_nx842_incr_hist(atomic64_t *times, unsigned int time)
+{
+	int bucket = fls(time);
+
+	if (bucket)
+		bucket = min((NX842_HIST_SLOTS - 1), bucket - 1);
+
+	atomic64_inc(&times[bucket]);
+}
+
+/* NX unit operation flags */
+#define NX842_OP_COMPRESS	0x0
+#define NX842_OP_CRC		0x1
+#define NX842_OP_DECOMPRESS	0x2
+#define NX842_OP_COMPRESS_CRC   (NX842_OP_COMPRESS | NX842_OP_CRC)
+#define NX842_OP_DECOMPRESS_CRC (NX842_OP_DECOMPRESS | NX842_OP_CRC)
+#define NX842_OP_ASYNC		(1<<23)
+#define NX842_OP_NOTIFY		(1<<22)
+#define NX842_OP_NOTIFY_INT(x)	((x & 0xff)<<8)
+
+static unsigned long nx842_get_desired_dma(struct vio_dev *viodev)
+{
+	/* No use of DMA mappings within the driver. */
+	return 0;
+}
+
+struct nx842_slentry {
+	unsigned long ptr; /* Absolute address (use virt_to_abs()) */
+	unsigned long len;
+};
+
+/* pHyp scatterlist entry */
+struct nx842_scatterlist {
+	int entry_nr; /* number of slentries */
+	struct nx842_slentry *entries; /* ptr to array of slentries */
+};
+
+/* Does not include sizeof(entry_nr) in the size */
+static inline unsigned long nx842_get_scatterlist_size(
+				struct nx842_scatterlist *sl)
+{
+	return sl->entry_nr * sizeof(struct nx842_slentry);
+}
+
+static int nx842_build_scatterlist(unsigned long buf, int len,
+			struct nx842_scatterlist *sl)
+{
+	unsigned long nextpage;
+	struct nx842_slentry *entry;
+
+	sl->entry_nr = 0;
+
+	entry = sl->entries;
+	while (len) {
+		entry->ptr = virt_to_abs(buf);
+		nextpage = ALIGN(buf + 1, NX842_HW_PAGE_SIZE);
+		if (nextpage < buf + len) {
+			/* we aren't at the end yet */
+			if (IS_ALIGNED(buf, NX842_HW_PAGE_SIZE))
+				/* we are in the middle (or beginning) */
+				entry->len = NX842_HW_PAGE_SIZE;
+			else
+				/* we are at the beginning */
+				entry->len = nextpage - buf;
+		} else {
+			/* at the end */
+			entry->len = len;
+		}
+
+		len -= entry->len;
+		buf += entry->len;
+		sl->entry_nr++;
+		entry++;
+	}
+
+	return 0;
+}
+
+/*
+ * Working memory for software decompression
+ */
+struct sw842_fifo {
+	union {
+		char f8[256][8];
+		char f4[512][4];
+	};
+	char f2[256][2];
+	unsigned char f84_full;
+	unsigned char f2_full;
+	unsigned char f8_count;
+	unsigned char f2_count;
+	unsigned int f4_count;
+};
+
+/*
+ * Working memory for crypto API
+ */
+struct nx842_workmem {
+	char bounce[PAGE_SIZE]; /* bounce buffer for decompression input */
+	union {
+		/* hardware working memory */
+		struct {
+			/* scatterlist */
+			char slin[SIZE_4K];
+			char slout[SIZE_4K];
+			/* coprocessor status/parameter block */
+			struct nx_csbcpb csbcpb;
+		};
+		/* software working memory */
+		struct sw842_fifo swfifo; /* software decompression fifo */
+	};
+};
+
+int nx842_get_workmem_size(void)
+{
+	return sizeof(struct nx842_workmem) + NX842_HW_PAGE_SIZE;
+}
+EXPORT_SYMBOL_GPL(nx842_get_workmem_size);
+
+int nx842_get_workmem_size_aligned(void)
+{
+	return sizeof(struct nx842_workmem);
+}
+EXPORT_SYMBOL_GPL(nx842_get_workmem_size_aligned);
+
+static int nx842_validate_result(struct device *dev,
+	struct cop_status_block *csb)
+{
+	/* The csb must be valid after returning from vio_h_cop_sync */
+	if (!NX842_CSBCBP_VALID_CHK(csb->valid)) {
+		dev_err(dev, "%s: cspcbp not valid upon completion.\n",
+				__func__);
+		dev_dbg(dev, "valid:0x%02x cs:0x%02x cc:0x%02x ce:0x%02x\n",
+				csb->valid,
+				csb->crb_seq_number,
+				csb->completion_code,
+				csb->completion_extension);
+		dev_dbg(dev, "processed_bytes:%d address:0x%016lx\n",
+				csb->processed_byte_count,
+				(unsigned long)csb->address);
+		return -EIO;
+	}
+
+	/* Check return values from the hardware in the CSB */
+	switch (csb->completion_code) {
+	case 0:	/* Completed without error */
+		break;
+	case 64: /* Target bytes > Source bytes during compression */
+	case 13: /* Output buffer too small */
+		dev_dbg(dev, "%s: Compression output larger than input\n",
+					__func__);
+		return -ENOSPC;
+	case 66: /* Input data contains an illegal template field */
+	case 67: /* Template indicates data past the end of the input stream */
+		dev_dbg(dev, "%s: Bad data for decompression (code:%d)\n",
+					__func__, csb->completion_code);
+		return -EINVAL;
+	default:
+		dev_dbg(dev, "%s: Unspecified error (code:%d)\n",
+					__func__, csb->completion_code);
+		return -EIO;
+	}
+
+	/* Hardware sanity check */
+	if (!NX842_CSBCPB_CE2(csb->completion_extension)) {
+		dev_err(dev, "%s: No error returned by hardware, but "
+				"data returned is unusable, contact support.\n"
+				"(Additional info: csbcbp->processed bytes "
+				"does not specify processed bytes for the "
+				"target buffer.)\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * nx842_compress - Compress data using the 842 algorithm
+ *
+ * Compression provide by the NX842 coprocessor on IBM Power systems.
+ * The input buffer is compressed and the result is stored in the
+ * provided output buffer.
+ *
+ * Upon return from this function @outlen contains the length of the
+ * compressed data.  If there is an error then @outlen will be 0 and an
+ * error will be specified by the return code from this function.
+ *
+ * @in: Pointer to input buffer, must be page aligned
+ * @inlen: Length of input buffer, must be PAGE_SIZE
+ * @out: Pointer to output buffer
+ * @outlen: Length of output buffer
+ * @wrkmem: ptr to buffer for working memory, size determined by
+ *          nx842_get_workmem_size()
+ *
+ * Returns:
+ *   0		Success, output of length @outlen stored in the buffer at @out
+ *   -ENOMEM	Unable to allocate internal buffers
+ *   -ENOSPC	Output buffer is to small
+ *   -EMSGSIZE	XXX Difficult to describe this limitation
+ *   -EIO	Internal error
+ *   -ENODEV	Hardware unavailable
+ */
+int nx842_compress(const unsigned char *in, unsigned int inlen,
+		       unsigned char *out, unsigned int *outlen, void *wmem)
+{
+	struct nx842_header *hdr;
+	struct nx842_devdata *local_devdata;
+	struct device *dev = NULL;
+	struct nx842_workmem *workmem;
+	struct nx842_scatterlist slin, slout;
+	struct nx_csbcpb *csbcpb;
+	int ret = 0, max_sync_size, i, bytesleft, size, hdrsize;
+	unsigned long inbuf, outbuf, padding;
+	struct vio_pfo_op op = {
+		.done = NULL,
+		.handle = 0,
+		.timeout = 0,
+	};
+	unsigned long start_time = get_tb();
+
+	/*
+	 * Make sure input buffer is 64k page aligned.  This is assumed since
+	 * this driver is designed for page compression only (for now).  This
+	 * is very nice since we can now use direct DDE(s) for the input and
+	 * the alignment is guaranteed.
+	*/
+	inbuf = (unsigned long)in;
+	if (!IS_ALIGNED(inbuf, PAGE_SIZE) || inlen != PAGE_SIZE)
+		return -EINVAL;
+
+	rcu_read_lock();
+	local_devdata = rcu_dereference(devdata);
+	if (!local_devdata || !local_devdata->dev) {
+		rcu_read_unlock();
+		return -ENODEV;
+	}
+	max_sync_size = local_devdata->max_sync_size;
+	dev = local_devdata->dev;
+
+	/* Create the header */
+	hdr = (struct nx842_header *)out;
+	hdr->blocks_nr = PAGE_SIZE / max_sync_size;
+	hdrsize = nx842_header_size(hdr);
+	outbuf = (unsigned long)out + hdrsize;
+	bytesleft = *outlen - hdrsize;
+
+	/* Init scatterlist */
+	workmem = (struct nx842_workmem *)ALIGN((unsigned long)wmem,
+		NX842_HW_PAGE_SIZE);
+	slin.entries = (struct nx842_slentry *)workmem->slin;
+	slout.entries = (struct nx842_slentry *)workmem->slout;
+
+	/* Init operation */
+	op.flags = NX842_OP_COMPRESS;
+	csbcpb = &workmem->csbcpb;
+	memset(csbcpb, 0, sizeof(*csbcpb));
+	op.csbcpb = virt_to_abs(csbcpb);
+	op.out = virt_to_abs(slout.entries);
+
+	for (i = 0; i < hdr->blocks_nr; i++) {
+		/*
+		 * Aligning the output blocks to 128 bytes does waste space,
+		 * but it prevents the need for bounce buffers and memory
+		 * copies.  It also simplifies the code a lot.  In the worst
+		 * case (64k page, 4k max_sync_size), you lose up to
+		 * (128*16)/64k = ~3% the compression factor. For 64k
+		 * max_sync_size, the loss would be at most 128/64k = ~0.2%.
+		 */
+		padding = ALIGN(outbuf, IO_BUFFER_ALIGN) - outbuf;
+		outbuf += padding;
+		bytesleft -= padding;
+		if (i == 0)
+			/* save offset into first block in header */
+			hdr->offset = padding + hdrsize;
+
+		if (bytesleft <= 0) {
+			ret = -ENOSPC;
+			goto unlock;
+		}
+
+		/*
+		 * NOTE: If the default max_sync_size is changed from 4k
+		 * to 64k, remove the "likely" case below, since a
+		 * scatterlist will always be needed.
+		 */
+		if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) {
+			/* Create direct DDE */
+			op.in = virt_to_abs(inbuf);
+			op.inlen = max_sync_size;
+
+		} else {
+			/* Create indirect DDE (scatterlist) */
+			nx842_build_scatterlist(inbuf, max_sync_size, &slin);
+			op.in = virt_to_abs(slin.entries);
+			op.inlen = -nx842_get_scatterlist_size(&slin);
+		}
+
+		/*
+		 * If max_sync_size != NX842_HW_PAGE_SIZE, an indirect
+		 * DDE is required for the outbuf.
+		 * If max_sync_size == NX842_HW_PAGE_SIZE, outbuf must
+		 * also be page aligned (1 in 128/4k=32 chance) in order
+		 * to use a direct DDE.
+		 * This is unlikely, just use an indirect DDE always.
+		 */
+		nx842_build_scatterlist(outbuf,
+			min(bytesleft, max_sync_size), &slout);
+		/* op.out set before loop */
+		op.outlen = -nx842_get_scatterlist_size(&slout);
+
+		/* Send request to pHyp */
+		ret = vio_h_cop_sync(local_devdata->vdev, &op);
+
+		/* Check for pHyp error */
+		if (ret) {
+			dev_dbg(dev, "%s: vio_h_cop_sync error (ret=%d, hret=%ld)\n",
+				__func__, ret, op.hcall_err);
+			ret = -EIO;
+			goto unlock;
+		}
+
+		/* Check for hardware error */
+		ret = nx842_validate_result(dev, &csbcpb->csb);
+		if (ret && ret != -ENOSPC)
+			goto unlock;
+
+		/* Handle incompressible data */
+		if (unlikely(ret == -ENOSPC)) {
+			if (bytesleft < max_sync_size) {
+				/*
+				 * Not enough space left in the output buffer
+				 * to store uncompressed block
+				 */
+				goto unlock;
+			} else {
+				/* Store incompressible block */
+				memcpy((void *)outbuf, (void *)inbuf,
+					max_sync_size);
+				hdr->sizes[i] = -max_sync_size;
+				outbuf += max_sync_size;
+				bytesleft -= max_sync_size;
+				/* Reset ret, incompressible data handled */
+				ret = 0;
+			}
+		} else {
+			/* Normal case, compression was successful */
+			size = csbcpb->csb.processed_byte_count;
+			dev_dbg(dev, "%s: processed_bytes=%d\n",
+				__func__, size);
+			hdr->sizes[i] = size;
+			outbuf += size;
+			bytesleft -= size;
+		}
+
+		inbuf += max_sync_size;
+	}
+
+	*outlen = (unsigned int)(outbuf - (unsigned long)out);
+
+unlock:
+	if (ret)
+		nx842_inc_comp_failed(local_devdata);
+	else {
+		nx842_inc_comp_complete(local_devdata);
+		ibm_nx842_incr_hist(local_devdata->counters->comp_times,
+			(get_tb() - start_time) / tb_ticks_per_usec);
+	}
+	rcu_read_unlock();
+	return ret;
+}
+EXPORT_SYMBOL_GPL(nx842_compress);
+
+static int sw842_decompress(const unsigned char *, int, unsigned char *, int *,
+			const void *);
+
+/**
+ * nx842_decompress - Decompress data using the 842 algorithm
+ *
+ * Decompression provide by the NX842 coprocessor on IBM Power systems.
+ * The input buffer is decompressed and the result is stored in the
+ * provided output buffer.  The size allocated to the output buffer is
+ * provided by the caller of this function in @outlen.  Upon return from
+ * this function @outlen contains the length of the decompressed data.
+ * If there is an error then @outlen will be 0 and an error will be
+ * specified by the return code from this function.
+ *
+ * @in: Pointer to input buffer, will use bounce buffer if not 128 byte
+ *      aligned
+ * @inlen: Length of input buffer
+ * @out: Pointer to output buffer, must be page aligned
+ * @outlen: Length of output buffer, must be PAGE_SIZE
+ * @wrkmem: ptr to buffer for working memory, size determined by
+ *          nx842_get_workmem_size()
+ *
+ * Returns:
+ *   0		Success, output of length @outlen stored in the buffer at @out
+ *   -ENODEV	Hardware decompression device is unavailable
+ *   -ENOMEM	Unable to allocate internal buffers
+ *   -ENOSPC	Output buffer is to small
+ *   -EINVAL	Bad input data encountered when attempting decompress
+ *   -EIO	Internal error
+ */
+int nx842_decompress(const unsigned char *in, unsigned int inlen,
+			 unsigned char *out, unsigned int *outlen, void *wmem)
+{
+	struct nx842_header *hdr;
+	struct nx842_devdata *local_devdata;
+	struct device *dev = NULL;
+	struct nx842_workmem *workmem;
+	struct nx842_scatterlist slin, slout;
+	struct nx_csbcpb *csbcpb;
+	int ret = 0, i, size, max_sync_size;
+	unsigned long inbuf, outbuf;
+	struct vio_pfo_op op = {
+		.done = NULL,
+		.handle = 0,
+		.timeout = 0,
+	};
+	unsigned long start_time = get_tb();
+
+	/* Ensure page alignment and size */
+	outbuf = (unsigned long)out;
+	if (!IS_ALIGNED(outbuf, PAGE_SIZE) || *outlen != PAGE_SIZE)
+		return -EINVAL;
+
+	rcu_read_lock();
+	local_devdata = rcu_dereference(devdata);
+	if (local_devdata)
+		dev = local_devdata->dev;
+
+	/* Get header */
+	hdr = (struct nx842_header *)in;
+
+	workmem = (struct nx842_workmem *)ALIGN((unsigned long)wmem,
+		NX842_HW_PAGE_SIZE);
+
+	inbuf = (unsigned long)in + hdr->offset;
+	if (likely(!IS_ALIGNED(inbuf, IO_BUFFER_ALIGN))) {
+		/* Copy block(s) into bounce buffer for alignment */
+		memcpy(workmem->bounce, in + hdr->offset, inlen - hdr->offset);
+		inbuf = (unsigned long)workmem->bounce;
+	}
+
+	/* Init scatterlist */
+	slin.entries = (struct nx842_slentry *)workmem->slin;
+	slout.entries = (struct nx842_slentry *)workmem->slout;
+
+	/* Init operation */
+	op.flags = NX842_OP_DECOMPRESS;
+	csbcpb = &workmem->csbcpb;
+	memset(csbcpb, 0, sizeof(*csbcpb));
+	op.csbcpb = virt_to_abs(csbcpb);
+
+	/*
+	 * max_sync_size may have changed since compression,
+	 * so we can't read it from the device info. We need
+	 * to derive it from hdr->blocks_nr.
+	 */
+	max_sync_size = PAGE_SIZE / hdr->blocks_nr;
+
+	for (i = 0; i < hdr->blocks_nr; i++) {
+		/* Skip padding */
+		inbuf = ALIGN(inbuf, IO_BUFFER_ALIGN);
+
+		if (hdr->sizes[i] < 0) {
+			/* Negative sizes indicate uncompressed data blocks */
+			size = abs(hdr->sizes[i]);
+			memcpy((void *)outbuf, (void *)inbuf, size);
+			outbuf += size;
+			inbuf += size;
+			continue;
+		}
+
+		if (!dev)
+			goto sw;
+
+		/*
+		 * The better the compression, the more likely the "likely"
+		 * case becomes.
+		 */
+		if (likely((inbuf & NX842_HW_PAGE_MASK) ==
+			((inbuf + hdr->sizes[i] - 1) & NX842_HW_PAGE_MASK))) {
+			/* Create direct DDE */
+			op.in = virt_to_abs(inbuf);
+			op.inlen = hdr->sizes[i];
+		} else {
+			/* Create indirect DDE (scatterlist) */
+			nx842_build_scatterlist(inbuf, hdr->sizes[i] , &slin);
+			op.in = virt_to_abs(slin.entries);
+			op.inlen = -nx842_get_scatterlist_size(&slin);
+		}
+
+		/*
+		 * NOTE: If the default max_sync_size is changed from 4k
+		 * to 64k, remove the "likely" case below, since a
+		 * scatterlist will always be needed.
+		 */
+		if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) {
+			/* Create direct DDE */
+			op.out = virt_to_abs(outbuf);
+			op.outlen = max_sync_size;
+		} else {
+			/* Create indirect DDE (scatterlist) */
+			nx842_build_scatterlist(outbuf, max_sync_size, &slout);
+			op.out = virt_to_abs(slout.entries);
+			op.outlen = -nx842_get_scatterlist_size(&slout);
+		}
+
+		/* Send request to pHyp */
+		ret = vio_h_cop_sync(local_devdata->vdev, &op);
+
+		/* Check for pHyp error */
+		if (ret) {
+			dev_dbg(dev, "%s: vio_h_cop_sync error (ret=%d, hret=%ld)\n",
+				__func__, ret, op.hcall_err);
+			dev = NULL;
+			goto sw;
+		}
+
+		/* Check for hardware error */
+		ret = nx842_validate_result(dev, &csbcpb->csb);
+		if (ret) {
+			dev = NULL;
+			goto sw;
+		}
+
+		/* HW decompression success */
+		inbuf += hdr->sizes[i];
+		outbuf += csbcpb->csb.processed_byte_count;
+		continue;
+
+sw:
+		/* software decompression */
+		size = max_sync_size;
+		ret = sw842_decompress(
+			(unsigned char *)inbuf, hdr->sizes[i],
+			(unsigned char *)outbuf, &size, wmem);
+		if (ret)
+			pr_debug("%s: sw842_decompress failed with %d\n",
+				__func__, ret);
+
+		if (ret) {
+			if (ret != -ENOSPC && ret != -EINVAL &&
+					ret != -EMSGSIZE)
+				ret = -EIO;
+			goto unlock;
+		}
+
+		/* SW decompression success */
+		inbuf += hdr->sizes[i];
+		outbuf += size;
+	}
+
+	*outlen = (unsigned int)(outbuf - (unsigned long)out);
+
+unlock:
+	if (ret)
+		/* decompress fail */
+		nx842_inc_decomp_failed(local_devdata);
+	else {
+		if (!dev)
+			/* software decompress */
+			nx842_inc_swdecomp(local_devdata);
+		nx842_inc_decomp_complete(local_devdata);
+		ibm_nx842_incr_hist(local_devdata->counters->decomp_times,
+			(get_tb() - start_time) / tb_ticks_per_usec);
+	}
+
+	rcu_read_unlock();
+	return ret;
+}
+EXPORT_SYMBOL_GPL(nx842_decompress);
+
+/**
+ * nx842_OF_set_defaults -- Set default (disabled) values for devdata
+ *
+ * @devdata - struct nx842_devdata to update
+ *
+ * Returns:
+ *  0 on success
+ *  -ENOENT if @devdata ptr is NULL
+ */
+static int nx842_OF_set_defaults(struct nx842_devdata *devdata)
+{
+	if (devdata) {
+		devdata->max_sync_size = 0;
+		devdata->max_sync_sg = 0;
+		devdata->max_sg_len = 0;
+		devdata->status = UNAVAILABLE;
+		return 0;
+	} else
+		return -ENOENT;
+}
+
+/**
+ * nx842_OF_upd_status -- Update the device info from OF status prop
+ *
+ * The status property indicates if the accelerator is enabled.  If the
+ * device is in the OF tree it indicates that the hardware is present.
+ * The status field indicates if the device is enabled when the status
+ * is 'okay'.  Otherwise the device driver will be disabled.
+ *
+ * @devdata - struct nx842_devdata to update
+ * @prop - struct property point containing the maxsyncop for the update
+ *
+ * Returns:
+ *  0 - Device is available
+ *  -EINVAL - Device is not available
+ */
+static int nx842_OF_upd_status(struct nx842_devdata *devdata,
+					struct property *prop) {
+	int ret = 0;
+	const char *status = (const char *)prop->value;
+
+	if (!strncmp(status, "okay", (size_t)prop->length)) {
+		devdata->status = AVAILABLE;
+	} else {
+		dev_info(devdata->dev, "%s: status '%s' is not 'okay'\n",
+				__func__, status);
+		devdata->status = UNAVAILABLE;
+	}
+
+	return ret;
+}
+
+/**
+ * nx842_OF_upd_maxsglen -- Update the device info from OF maxsglen prop
+ *
+ * Definition of the 'ibm,max-sg-len' OF property:
+ *  This field indicates the maximum byte length of a scatter list
+ *  for the platform facility. It is a single cell encoded as with encode-int.
+ *
+ * Example:
+ *  # od -x ibm,max-sg-len
+ *  0000000 0000 0ff0
+ *
+ *  In this example, the maximum byte length of a scatter list is
+ *  0x0ff0 (4,080).
+ *
+ * @devdata - struct nx842_devdata to update
+ * @prop - struct property point containing the maxsyncop for the update
+ *
+ * Returns:
+ *  0 on success
+ *  -EINVAL on failure
+ */
+static int nx842_OF_upd_maxsglen(struct nx842_devdata *devdata,
+					struct property *prop) {
+	int ret = 0;
+	const int *maxsglen = prop->value;
+
+	if (prop->length != sizeof(*maxsglen)) {
+		dev_err(devdata->dev, "%s: unexpected format for ibm,max-sg-len property\n", __func__);
+		dev_dbg(devdata->dev, "%s: ibm,max-sg-len is %d bytes long, expected %lu bytes\n", __func__,
+				prop->length, sizeof(*maxsglen));
+		ret = -EINVAL;
+	} else {
+		devdata->max_sg_len = (unsigned int)min(*maxsglen,
+				(int)NX842_HW_PAGE_SIZE);
+	}
+
+	return ret;
+}
+
+/**
+ * nx842_OF_upd_maxsyncop -- Update the device info from OF maxsyncop prop
+ *
+ * Definition of the 'ibm,max-sync-cop' OF property:
+ *  Two series of cells.  The first series of cells represents the maximums
+ *  that can be synchronously compressed. The second series of cells
+ *  represents the maximums that can be synchronously decompressed.
+ *  1. The first cell in each series contains the count of the number of
+ *     data length, scatter list elements pairs that follow – each being
+ *     of the form
+ *    a. One cell data byte length
+ *    b. One cell total number of scatter list elements
+ *
+ * Example:
+ *  # od -x ibm,max-sync-cop
+ *  0000000 0000 0001 0000 1000 0000 01fe 0000 0001
+ *  0000020 0000 1000 0000 01fe
+ *
+ *  In this example, compression supports 0x1000 (4,096) data byte length
+ *  and 0x1fe (510) total scatter list elements.  Decompression supports
+ *  0x1000 (4,096) data byte length and 0x1f3 (510) total scatter list
+ *  elements.
+ *
+ * @devdata - struct nx842_devdata to update
+ * @prop - struct property point containing the maxsyncop for the update
+ *
+ * Returns:
+ *  0 on success
+ *  -EINVAL on failure
+ */
+static int nx842_OF_upd_maxsyncop(struct nx842_devdata *devdata,
+					struct property *prop) {
+	int ret = 0;
+	const struct maxsynccop_t {
+		int comp_elements;
+		int comp_data_limit;
+		int comp_sg_limit;
+		int decomp_elements;
+		int decomp_data_limit;
+		int decomp_sg_limit;
+	} *maxsynccop;
+
+	if (prop->length != sizeof(*maxsynccop)) {
+		dev_err(devdata->dev, "%s: unexpected format for ibm,max-sync-cop property\n", __func__);
+		dev_dbg(devdata->dev, "%s: ibm,max-sync-cop is %d bytes long, expected %lu bytes\n", __func__, prop->length,
+				sizeof(*maxsynccop));
+		ret = -EINVAL;
+		goto out;
+	}
+
+	maxsynccop = (const struct maxsynccop_t *)prop->value;
+
+	/* Use one limit rather than separate limits for compression and
+	 * decompression. Set a maximum for this so as not to exceed the
+	 * size that the header can support and round the value down to
+	 * the hardware page size (4K) */
+	devdata->max_sync_size =
+			(unsigned int)min(maxsynccop->comp_data_limit,
+					maxsynccop->decomp_data_limit);
+
+	devdata->max_sync_size = min_t(unsigned int, devdata->max_sync_size,
+					SIZE_64K);
+
+	if (devdata->max_sync_size < SIZE_4K) {
+		dev_err(devdata->dev, "%s: hardware max data size (%u) is "
+				"less than the driver minimum, unable to use "
+				"the hardware device\n",
+				__func__, devdata->max_sync_size);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	devdata->max_sync_sg = (unsigned int)min(maxsynccop->comp_sg_limit,
+						maxsynccop->decomp_sg_limit);
+	if (devdata->max_sync_sg < 1) {
+		dev_err(devdata->dev, "%s: hardware max sg size (%u) is "
+				"less than the driver minimum, unable to use "
+				"the hardware device\n",
+				__func__, devdata->max_sync_sg);
+		ret = -EINVAL;
+		goto out;
+	}
+
+out:
+	return ret;
+}
+
+/**
+ *
+ * nx842_OF_upd -- Handle OF properties updates for the device.
+ *
+ * Set all properties from the OF tree.  Optionally, a new property
+ * can be provided by the @new_prop pointer to overwrite an existing value.
+ * The device will remain disabled until all values are valid, this function
+ * will return an error for updates unless all values are valid.
+ *
+ * @new_prop: If not NULL, this property is being updated.  If NULL, update
+ *  all properties from the current values in the OF tree.
+ *
+ * Returns:
+ *  0 - Success
+ *  -ENOMEM - Could not allocate memory for new devdata structure
+ *  -EINVAL - property value not found, new_prop is not a recognized
+ *	property for the device or property value is not valid.
+ *  -ENODEV - Device is not available
+ */
+static int nx842_OF_upd(struct property *new_prop)
+{
+	struct nx842_devdata *old_devdata = NULL;
+	struct nx842_devdata *new_devdata = NULL;
+	struct device_node *of_node = NULL;
+	struct property *status = NULL;
+	struct property *maxsglen = NULL;
+	struct property *maxsyncop = NULL;
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&devdata_mutex, flags);
+	old_devdata = rcu_dereference_check(devdata,
+			lockdep_is_held(&devdata_mutex));
+	if (old_devdata)
+		of_node = old_devdata->dev->of_node;
+
+	if (!old_devdata || !of_node) {
+		pr_err("%s: device is not available\n", __func__);
+		spin_unlock_irqrestore(&devdata_mutex, flags);
+		return -ENODEV;
+	}
+
+	new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS);
+	if (!new_devdata) {
+		dev_err(old_devdata->dev, "%s: Could not allocate memory for device data\n", __func__);
+		ret = -ENOMEM;
+		goto error_out;
+	}
+
+	memcpy(new_devdata, old_devdata, sizeof(*old_devdata));
+	new_devdata->counters = old_devdata->counters;
+
+	/* Set ptrs for existing properties */
+	status = of_find_property(of_node, "status", NULL);
+	maxsglen = of_find_property(of_node, "ibm,max-sg-len", NULL);
+	maxsyncop = of_find_property(of_node, "ibm,max-sync-cop", NULL);
+	if (!status || !maxsglen || !maxsyncop) {
+		dev_err(old_devdata->dev, "%s: Could not locate device properties\n", __func__);
+		ret = -EINVAL;
+		goto error_out;
+	}
+
+	/* Set ptr to new property if provided */
+	if (new_prop) {
+		/* Single property */
+		if (!strncmp(new_prop->name, "status", new_prop->length)) {
+			status = new_prop;
+
+		} else if (!strncmp(new_prop->name, "ibm,max-sg-len",
+					new_prop->length)) {
+			maxsglen = new_prop;
+
+		} else if (!strncmp(new_prop->name, "ibm,max-sync-cop",
+					new_prop->length)) {
+			maxsyncop = new_prop;
+
+		} else {
+			/*
+			 * Skip the update, the property being updated
+			 * has no impact.
+			 */
+			goto out;
+		}
+	}
+
+	/* Perform property updates */
+	ret = nx842_OF_upd_status(new_devdata, status);
+	if (ret)
+		goto error_out;
+
+	ret = nx842_OF_upd_maxsglen(new_devdata, maxsglen);
+	if (ret)
+		goto error_out;
+
+	ret = nx842_OF_upd_maxsyncop(new_devdata, maxsyncop);
+	if (ret)
+		goto error_out;
+
+out:
+	dev_info(old_devdata->dev, "%s: max_sync_size new:%u old:%u\n",
+			__func__, new_devdata->max_sync_size,
+			old_devdata->max_sync_size);
+	dev_info(old_devdata->dev, "%s: max_sync_sg new:%u old:%u\n",
+			__func__, new_devdata->max_sync_sg,
+			old_devdata->max_sync_sg);
+	dev_info(old_devdata->dev, "%s: max_sg_len new:%u old:%u\n",
+			__func__, new_devdata->max_sg_len,
+			old_devdata->max_sg_len);
+
+	rcu_assign_pointer(devdata, new_devdata);
+	spin_unlock_irqrestore(&devdata_mutex, flags);
+	synchronize_rcu();
+	dev_set_drvdata(new_devdata->dev, new_devdata);
+	kfree(old_devdata);
+	return 0;
+
+error_out:
+	if (new_devdata) {
+		dev_info(old_devdata->dev, "%s: device disabled\n", __func__);
+		nx842_OF_set_defaults(new_devdata);
+		rcu_assign_pointer(devdata, new_devdata);
+		spin_unlock_irqrestore(&devdata_mutex, flags);
+		synchronize_rcu();
+		dev_set_drvdata(new_devdata->dev, new_devdata);
+		kfree(old_devdata);
+	} else {
+		dev_err(old_devdata->dev, "%s: could not update driver from hardware\n", __func__);
+		spin_unlock_irqrestore(&devdata_mutex, flags);
+	}
+
+	if (!ret)
+		ret = -EINVAL;
+	return ret;
+}
+
+/**
+ * nx842_OF_notifier - Process updates to OF properties for the device
+ *
+ * @np: notifier block
+ * @action: notifier action
+ * @update: struct pSeries_reconfig_prop_update pointer if action is
+ *	PSERIES_UPDATE_PROPERTY
+ *
+ * Returns:
+ *	NOTIFY_OK on success
+ *	NOTIFY_BAD encoded with error number on failure, use
+ *		notifier_to_errno() to decode this value
+ */
+static int nx842_OF_notifier(struct notifier_block *np,
+					unsigned long action,
+					void *update)
+{
+	struct pSeries_reconfig_prop_update *upd;
+	struct nx842_devdata *local_devdata;
+	struct device_node *node = NULL;
+
+	upd = (struct pSeries_reconfig_prop_update *)update;
+
+	rcu_read_lock();
+	local_devdata = rcu_dereference(devdata);
+	if (local_devdata)
+		node = local_devdata->dev->of_node;
+
+	if (local_devdata &&
+			action == PSERIES_UPDATE_PROPERTY &&
+			!strcmp(upd->node->name, node->name)) {
+		rcu_read_unlock();
+		nx842_OF_upd(upd->property);
+	} else
+		rcu_read_unlock();
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block nx842_of_nb = {
+	.notifier_call = nx842_OF_notifier,
+};
+
+#define nx842_counter_read(_name)					\
+static ssize_t nx842_##_name##_show(struct device *dev,		\
+		struct device_attribute *attr,				\
+		char *buf) {						\
+	struct nx842_devdata *local_devdata;			\
+	int p = 0;							\
+	rcu_read_lock();						\
+	local_devdata = rcu_dereference(devdata);			\
+	if (local_devdata)						\
+		p = snprintf(buf, PAGE_SIZE, "%ld\n",			\
+		       atomic64_read(&local_devdata->counters->_name));	\
+	rcu_read_unlock();						\
+	return p;							\
+}
+
+#define NX842DEV_COUNTER_ATTR_RO(_name)					\
+	nx842_counter_read(_name);					\
+	static struct device_attribute dev_attr_##_name = __ATTR(_name,	\
+						0444,			\
+						nx842_##_name##_show,\
+						NULL);
+
+NX842DEV_COUNTER_ATTR_RO(comp_complete);
+NX842DEV_COUNTER_ATTR_RO(comp_failed);
+NX842DEV_COUNTER_ATTR_RO(decomp_complete);
+NX842DEV_COUNTER_ATTR_RO(decomp_failed);
+NX842DEV_COUNTER_ATTR_RO(swdecomp);
+
+static ssize_t nx842_timehist_show(struct device *,
+		struct device_attribute *, char *);
+
+static struct device_attribute dev_attr_comp_times = __ATTR(comp_times, 0444,
+		nx842_timehist_show, NULL);
+static struct device_attribute dev_attr_decomp_times = __ATTR(decomp_times,
+		0444, nx842_timehist_show, NULL);
+
+static ssize_t nx842_timehist_show(struct device *dev,
+		struct device_attribute *attr, char *buf) {
+	char *p = buf;
+	struct nx842_devdata *local_devdata;
+	atomic64_t *times;
+	int bytes_remain = PAGE_SIZE;
+	int bytes;
+	int i;
+
+	rcu_read_lock();
+	local_devdata = rcu_dereference(devdata);
+	if (!local_devdata) {
+		rcu_read_unlock();
+		return 0;
+	}
+
+	if (attr == &dev_attr_comp_times)
+		times = local_devdata->counters->comp_times;
+	else if (attr == &dev_attr_decomp_times)
+		times = local_devdata->counters->decomp_times;
+	else {
+		rcu_read_unlock();
+		return 0;
+	}
+
+	for (i = 0; i < (NX842_HIST_SLOTS - 2); i++) {
+		bytes = snprintf(p, bytes_remain, "%u-%uus:\t%ld\n",
+			       i ? (2<<(i-1)) : 0, (2<<i)-1,
+			       atomic64_read(&times[i]));
+		bytes_remain -= bytes;
+		p += bytes;
+	}
+	/* The last bucket holds everything over
+	 * 2<<(NX842_HIST_SLOTS - 2) us */
+	bytes = snprintf(p, bytes_remain, "%uus - :\t%ld\n",
+			2<<(NX842_HIST_SLOTS - 2),
+			atomic64_read(&times[(NX842_HIST_SLOTS - 1)]));
+	p += bytes;
+
+	rcu_read_unlock();
+	return p - buf;
+}
+
+static struct attribute *nx842_sysfs_entries[] = {
+	&dev_attr_comp_complete.attr,
+	&dev_attr_comp_failed.attr,
+	&dev_attr_decomp_complete.attr,
+	&dev_attr_decomp_failed.attr,
+	&dev_attr_swdecomp.attr,
+	&dev_attr_comp_times.attr,
+	&dev_attr_decomp_times.attr,
+	NULL,
+};
+
+static struct attribute_group nx842_attribute_group = {
+	.name = NULL,		/* put in device directory */
+	.attrs = nx842_sysfs_entries,
+};
+
+static int __init nx842_probe(struct vio_dev *viodev,
+				  const struct vio_device_id *id)
+{
+	struct nx842_devdata *old_devdata, *new_devdata = NULL;
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&devdata_mutex, flags);
+	old_devdata = rcu_dereference_check(devdata,
+			lockdep_is_held(&devdata_mutex));
+
+	if (old_devdata && old_devdata->vdev != NULL) {
+		dev_err(&viodev->dev, "%s: Attempt to register more than one instance of the hardware\n", __func__);
+		ret = -1;
+		goto error_unlock;
+	}
+
+	dev_set_drvdata(&viodev->dev, NULL);
+
+	new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS);
+	if (!new_devdata) {
+		dev_err(&viodev->dev, "%s: Could not allocate memory for device data\n", __func__);
+		ret = -ENOMEM;
+		goto error_unlock;
+	}
+
+	new_devdata->counters = kzalloc(sizeof(*new_devdata->counters),
+			GFP_NOFS);
+	if (!new_devdata->counters) {
+		dev_err(&viodev->dev, "%s: Could not allocate memory for performance counters\n", __func__);
+		ret = -ENOMEM;
+		goto error_unlock;
+	}
+
+	new_devdata->vdev = viodev;
+	new_devdata->dev = &viodev->dev;
+	nx842_OF_set_defaults(new_devdata);
+
+	rcu_assign_pointer(devdata, new_devdata);
+	spin_unlock_irqrestore(&devdata_mutex, flags);
+	synchronize_rcu();
+	kfree(old_devdata);
+
+	pSeries_reconfig_notifier_register(&nx842_of_nb);
+
+	ret = nx842_OF_upd(NULL);
+	if (ret && ret != -ENODEV) {
+		dev_err(&viodev->dev, "could not parse device tree. %d\n", ret);
+		ret = -1;
+		goto error;
+	}
+
+	rcu_read_lock();
+	if (dev_set_drvdata(&viodev->dev, rcu_dereference(devdata))) {
+		rcu_read_unlock();
+		dev_err(&viodev->dev, "failed to set driver data for device\n");
+		ret = -1;
+		goto error;
+	}
+	rcu_read_unlock();
+
+	if (sysfs_create_group(&viodev->dev.kobj, &nx842_attribute_group)) {
+		dev_err(&viodev->dev, "could not create sysfs device attributes\n");
+		ret = -1;
+		goto error;
+	}
+
+	return 0;
+
+error_unlock:
+	spin_unlock_irqrestore(&devdata_mutex, flags);
+	if (new_devdata)
+		kfree(new_devdata->counters);
+	kfree(new_devdata);
+error:
+	return ret;
+}
+
+static int __exit nx842_remove(struct vio_dev *viodev)
+{
+	struct nx842_devdata *old_devdata;
+	unsigned long flags;
+
+	pr_info("Removing IBM Power 842 compression device\n");
+	sysfs_remove_group(&viodev->dev.kobj, &nx842_attribute_group);
+
+	spin_lock_irqsave(&devdata_mutex, flags);
+	old_devdata = rcu_dereference_check(devdata,
+			lockdep_is_held(&devdata_mutex));
+	pSeries_reconfig_notifier_unregister(&nx842_of_nb);
+	rcu_assign_pointer(devdata, NULL);
+	spin_unlock_irqrestore(&devdata_mutex, flags);
+	synchronize_rcu();
+	dev_set_drvdata(&viodev->dev, NULL);
+	if (old_devdata)
+		kfree(old_devdata->counters);
+	kfree(old_devdata);
+	return 0;
+}
+
+static struct vio_device_id nx842_driver_ids[] = {
+	{"ibm,compression-v1", "ibm,compression"},
+	{"", ""},
+};
+
+static struct vio_driver nx842_driver = {
+	.name = MODULE_NAME,
+	.probe = nx842_probe,
+	.remove = nx842_remove,
+	.get_desired_dma = nx842_get_desired_dma,
+	.id_table = nx842_driver_ids,
+};
+
+static int __init nx842_init(void)
+{
+	struct nx842_devdata *new_devdata;
+	pr_info("Registering IBM Power 842 compression driver\n");
+
+	RCU_INIT_POINTER(devdata, NULL);
+	new_devdata = kzalloc(sizeof(*new_devdata), GFP_KERNEL);
+	if (!new_devdata) {
+		pr_err("Could not allocate memory for device data\n");
+		return -ENOMEM;
+	}
+	new_devdata->status = UNAVAILABLE;
+	RCU_INIT_POINTER(devdata, new_devdata);
+
+	return vio_register_driver(&nx842_driver);
+}
+
+module_init(nx842_init);
+
+static void __exit nx842_exit(void)
+{
+	struct nx842_devdata *old_devdata;
+	unsigned long flags;
+
+	pr_info("Exiting IBM Power 842 compression driver\n");
+	spin_lock_irqsave(&devdata_mutex, flags);
+	old_devdata = rcu_dereference_check(devdata,
+			lockdep_is_held(&devdata_mutex));
+	rcu_assign_pointer(devdata, NULL);
+	spin_unlock_irqrestore(&devdata_mutex, flags);
+	synchronize_rcu();
+	if (old_devdata)
+		dev_set_drvdata(old_devdata->dev, NULL);
+	kfree(old_devdata);
+	vio_unregister_driver(&nx842_driver);
+}
+
+module_exit(nx842_exit);
+
+/*********************************
+ * 842 software decompressor
+*********************************/
+typedef int (*sw842_template_op)(const char **, int *, unsigned char **,
+						struct sw842_fifo *);
+
+static int sw842_data8(const char **, int *, unsigned char **,
+						struct sw842_fifo *);
+static int sw842_data4(const char **, int *, unsigned char **,
+						struct sw842_fifo *);
+static int sw842_data2(const char **, int *, unsigned char **,
+						struct sw842_fifo *);
+static int sw842_ptr8(const char **, int *, unsigned char **,
+						struct sw842_fifo *);
+static int sw842_ptr4(const char **, int *, unsigned char **,
+						struct sw842_fifo *);
+static int sw842_ptr2(const char **, int *, unsigned char **,
+						struct sw842_fifo *);
+
+/* special templates */
+#define SW842_TMPL_REPEAT 0x1B
+#define SW842_TMPL_ZEROS 0x1C
+#define SW842_TMPL_EOF 0x1E
+
+static sw842_template_op sw842_tmpl_ops[26][4] = {
+	{ sw842_data8, NULL}, /* 0 (00000) */
+	{ sw842_data4, sw842_data2, sw842_ptr2,  NULL},
+	{ sw842_data4, sw842_ptr2,  sw842_data2, NULL},
+	{ sw842_data4, sw842_ptr2,  sw842_ptr2,  NULL},
+	{ sw842_data4, sw842_ptr4,  NULL},
+	{ sw842_data2, sw842_ptr2,  sw842_data4, NULL},
+	{ sw842_data2, sw842_ptr2,  sw842_data2, sw842_ptr2},
+	{ sw842_data2, sw842_ptr2,  sw842_ptr2,  sw842_data2},
+	{ sw842_data2, sw842_ptr2,  sw842_ptr2,  sw842_ptr2,},
+	{ sw842_data2, sw842_ptr2,  sw842_ptr4,  NULL},
+	{ sw842_ptr2,  sw842_data2, sw842_data4, NULL}, /* 10 (01010) */
+	{ sw842_ptr2,  sw842_data4, sw842_ptr2,  NULL},
+	{ sw842_ptr2,  sw842_data2, sw842_ptr2,  sw842_data2},
+	{ sw842_ptr2,  sw842_data2, sw842_ptr2,  sw842_ptr2},
+	{ sw842_ptr2,  sw842_data2, sw842_ptr4,  NULL},
+	{ sw842_ptr2,  sw842_ptr2,  sw842_data4, NULL},
+	{ sw842_ptr2,  sw842_ptr2,  sw842_data2, sw842_ptr2},
+	{ sw842_ptr2,  sw842_ptr2,  sw842_ptr2,  sw842_data2},
+	{ sw842_ptr2,  sw842_ptr2,  sw842_ptr2,  sw842_ptr2},
+	{ sw842_ptr2,  sw842_ptr2,  sw842_ptr4,  NULL},
+	{ sw842_ptr4,  sw842_data4, NULL}, /* 20 (10100) */
+	{ sw842_ptr4,  sw842_data2, sw842_ptr2,  NULL},
+	{ sw842_ptr4,  sw842_ptr2,  sw842_data2, NULL},
+	{ sw842_ptr4,  sw842_ptr2,  sw842_ptr2,  NULL},
+	{ sw842_ptr4,  sw842_ptr4,  NULL},
+	{ sw842_ptr8,  NULL}
+};
+
+/* Software decompress helpers */
+
+static uint8_t sw842_get_byte(const char *buf, int bit)
+{
+	uint8_t tmpl;
+	uint16_t tmp;
+	tmp = htons(*(uint16_t *)(buf));
+	tmp = (uint16_t)(tmp << bit);
+	tmp = ntohs(tmp);
+	memcpy(&tmpl, &tmp, 1);
+	return tmpl;
+}
+
+static uint8_t sw842_get_template(const char **buf, int *bit)
+{
+	uint8_t byte;
+	byte = sw842_get_byte(*buf, *bit);
+	byte = byte >> 3;
+	byte &= 0x1F;
+	*buf += (*bit + 5) / 8;
+	*bit = (*bit + 5) % 8;
+	return byte;
+}
+
+/* repeat_count happens to be 5-bit too (like the template) */
+static uint8_t sw842_get_repeat_count(const char **buf, int *bit)
+{
+	uint8_t byte;
+	byte = sw842_get_byte(*buf, *bit);
+	byte = byte >> 2;
+	byte &= 0x3F;
+	*buf += (*bit + 6) / 8;
+	*bit = (*bit + 6) % 8;
+	return byte;
+}
+
+static uint8_t sw842_get_ptr2(const char **buf, int *bit)
+{
+	uint8_t ptr;
+	ptr = sw842_get_byte(*buf, *bit);
+	(*buf)++;
+	return ptr;
+}
+
+static uint16_t sw842_get_ptr4(const char **buf, int *bit,
+		struct sw842_fifo *fifo)
+{
+	uint16_t ptr;
+	ptr = htons(*(uint16_t *)(*buf));
+	ptr = (uint16_t)(ptr << *bit);
+	ptr = ptr >> 7;
+	ptr &= 0x01FF;
+	*buf += (*bit + 9) / 8;
+	*bit = (*bit + 9) % 8;
+	return ptr;
+}
+
+static uint8_t sw842_get_ptr8(const char **buf, int *bit,
+		struct sw842_fifo *fifo)
+{
+	return sw842_get_ptr2(buf, bit);
+}
+
+/* Software decompress template ops */
+
+static int sw842_data8(const char **inbuf, int *inbit,
+		unsigned char **outbuf, struct sw842_fifo *fifo)
+{
+	int ret;
+
+	ret = sw842_data4(inbuf, inbit, outbuf, fifo);
+	if (ret)
+		return ret;
+	ret = sw842_data4(inbuf, inbit, outbuf, fifo);
+	return ret;
+}
+
+static int sw842_data4(const char **inbuf, int *inbit,
+		unsigned char **outbuf, struct sw842_fifo *fifo)
+{
+	int ret;
+
+	ret = sw842_data2(inbuf, inbit, outbuf, fifo);
+	if (ret)
+		return ret;
+	ret = sw842_data2(inbuf, inbit, outbuf, fifo);
+	return ret;
+}
+
+static int sw842_data2(const char **inbuf, int *inbit,
+		unsigned char **outbuf, struct sw842_fifo *fifo)
+{
+	**outbuf = sw842_get_byte(*inbuf, *inbit);
+	(*inbuf)++;
+	(*outbuf)++;
+	**outbuf = sw842_get_byte(*inbuf, *inbit);
+	(*inbuf)++;
+	(*outbuf)++;
+	return 0;
+}
+
+static int sw842_ptr8(const char **inbuf, int *inbit,
+		unsigned char **outbuf, struct sw842_fifo *fifo)
+{
+	uint8_t ptr;
+	ptr = sw842_get_ptr8(inbuf, inbit, fifo);
+	if (!fifo->f84_full && (ptr >= fifo->f8_count))
+		return 1;
+	memcpy(*outbuf, fifo->f8[ptr], 8);
+	*outbuf += 8;
+	return 0;
+}
+
+static int sw842_ptr4(const char **inbuf, int *inbit,
+		unsigned char **outbuf, struct sw842_fifo *fifo)
+{
+	uint16_t ptr;
+	ptr = sw842_get_ptr4(inbuf, inbit, fifo);
+	if (!fifo->f84_full && (ptr >= fifo->f4_count))
+		return 1;
+	memcpy(*outbuf, fifo->f4[ptr], 4);
+	*outbuf += 4;
+	return 0;
+}
+
+static int sw842_ptr2(const char **inbuf, int *inbit,
+		unsigned char **outbuf, struct sw842_fifo *fifo)
+{
+	uint8_t ptr;
+	ptr = sw842_get_ptr2(inbuf, inbit);
+	if (!fifo->f2_full && (ptr >= fifo->f2_count))
+		return 1;
+	memcpy(*outbuf, fifo->f2[ptr], 2);
+	*outbuf += 2;
+	return 0;
+}
+
+static void sw842_copy_to_fifo(const char *buf, struct sw842_fifo *fifo)
+{
+	unsigned char initial_f2count = fifo->f2_count;
+
+	memcpy(fifo->f8[fifo->f8_count], buf, 8);
+	fifo->f4_count += 2;
+	fifo->f8_count += 1;
+
+	if (!fifo->f84_full && fifo->f4_count >= 512) {
+		fifo->f84_full = 1;
+		fifo->f4_count /= 512;
+	}
+
+	memcpy(fifo->f2[fifo->f2_count++], buf, 2);
+	memcpy(fifo->f2[fifo->f2_count++], buf + 2, 2);
+	memcpy(fifo->f2[fifo->f2_count++], buf + 4, 2);
+	memcpy(fifo->f2[fifo->f2_count++], buf + 6, 2);
+	if (fifo->f2_count < initial_f2count)
+		fifo->f2_full = 1;
+}
+
+static int sw842_decompress(const unsigned char *src, int srclen,
+			unsigned char *dst, int *destlen,
+			const void *wrkmem)
+{
+	uint8_t tmpl;
+	const char *inbuf;
+	int inbit = 0;
+	unsigned char *outbuf, *outbuf_end, *origbuf, *prevbuf;
+	const char *inbuf_end;
+	sw842_template_op op;
+	int opindex;
+	int i, repeat_count;
+	struct sw842_fifo *fifo;
+	int ret = 0;
+
+	fifo = &((struct nx842_workmem *)(wrkmem))->swfifo;
+	memset(fifo, 0, sizeof(*fifo));
+
+	origbuf = NULL;
+	inbuf = src;
+	inbuf_end = src + srclen;
+	outbuf = dst;
+	outbuf_end = dst + *destlen;
+
+	while ((tmpl = sw842_get_template(&inbuf, &inbit)) != SW842_TMPL_EOF) {
+		if (inbuf >= inbuf_end) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		opindex = 0;
+		prevbuf = origbuf;
+		origbuf = outbuf;
+		switch (tmpl) {
+		case SW842_TMPL_REPEAT:
+			if (prevbuf == NULL) {
+				ret = -EINVAL;
+				goto out;
+			}
+
+			repeat_count = sw842_get_repeat_count(&inbuf,
+								&inbit) + 1;
+
+			/* Did the repeat count advance past the end of input */
+			if (inbuf > inbuf_end) {
+				ret = -EINVAL;
+				goto out;
+			}
+
+			for (i = 0; i < repeat_count; i++) {
+				/* Would this overflow the output buffer */
+				if ((outbuf + 8) > outbuf_end) {
+					ret = -ENOSPC;
+					goto out;
+				}
+
+				memcpy(outbuf, prevbuf, 8);
+				sw842_copy_to_fifo(outbuf, fifo);
+				outbuf += 8;
+			}
+			break;
+
+		case SW842_TMPL_ZEROS:
+			/* Would this overflow the output buffer */
+			if ((outbuf + 8) > outbuf_end) {
+				ret = -ENOSPC;
+				goto out;
+			}
+
+			memset(outbuf, 0, 8);
+			sw842_copy_to_fifo(outbuf, fifo);
+			outbuf += 8;
+			break;
+
+		default:
+			if (tmpl > 25) {
+				ret = -EINVAL;
+				goto out;
+			}
+
+			/* Does this go past the end of the input buffer */
+			if ((inbuf + 2) > inbuf_end) {
+				ret = -EINVAL;
+				goto out;
+			}
+
+			/* Would this overflow the output buffer */
+			if ((outbuf + 8) > outbuf_end) {
+				ret = -ENOSPC;
+				goto out;
+			}
+
+			while (opindex < 4 &&
+				(op = sw842_tmpl_ops[tmpl][opindex++])
+					!= NULL) {
+				ret = (*op)(&inbuf, &inbit, &outbuf, fifo);
+				if (ret) {
+					ret = -EINVAL;
+					goto out;
+				}
+				sw842_copy_to_fifo(origbuf, fifo);
+			}
+		}
+	}
+
+out:
+	if (!ret)
+		*destlen = (unsigned int)(outbuf - dst);
+	else
+		*destlen = 0;
+
+	return ret;
+}
diff --git a/drivers/crypto/nx/nx-aes-cbc.c b/drivers/crypto/nx/nx-aes-cbc.c
index 69ed796..a76d4c4 100644
--- a/drivers/crypto/nx/nx-aes-cbc.c
+++ b/drivers/crypto/nx/nx-aes-cbc.c
@@ -127,7 +127,6 @@ struct crypto_alg nx_cbc_aes_alg = {
 	.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
 	.cra_type        = &crypto_blkcipher_type,
 	.cra_module      = THIS_MODULE,
-	.cra_list        = LIST_HEAD_INIT(nx_cbc_aes_alg.cra_list),
 	.cra_init        = nx_crypto_ctx_aes_cbc_init,
 	.cra_exit        = nx_crypto_ctx_exit,
 	.cra_blkcipher = {
diff --git a/drivers/crypto/nx/nx-aes-ccm.c b/drivers/crypto/nx/nx-aes-ccm.c
index 7aeac67..ef5eae6 100644
--- a/drivers/crypto/nx/nx-aes-ccm.c
+++ b/drivers/crypto/nx/nx-aes-ccm.c
@@ -430,7 +430,6 @@ struct crypto_alg nx_ccm_aes_alg = {
 	.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
 	.cra_type        = &crypto_aead_type,
 	.cra_module      = THIS_MODULE,
-	.cra_list        = LIST_HEAD_INIT(nx_ccm_aes_alg.cra_list),
 	.cra_init        = nx_crypto_ctx_aes_ccm_init,
 	.cra_exit        = nx_crypto_ctx_exit,
 	.cra_aead = {
@@ -453,7 +452,6 @@ struct crypto_alg nx_ccm4309_aes_alg = {
 	.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
 	.cra_type        = &crypto_nivaead_type,
 	.cra_module      = THIS_MODULE,
-	.cra_list        = LIST_HEAD_INIT(nx_ccm4309_aes_alg.cra_list),
 	.cra_init        = nx_crypto_ctx_aes_ccm_init,
 	.cra_exit        = nx_crypto_ctx_exit,
 	.cra_aead = {
diff --git a/drivers/crypto/nx/nx-aes-ctr.c b/drivers/crypto/nx/nx-aes-ctr.c
index 52d4eb0..b6286f1 100644
--- a/drivers/crypto/nx/nx-aes-ctr.c
+++ b/drivers/crypto/nx/nx-aes-ctr.c
@@ -141,7 +141,6 @@ struct crypto_alg nx_ctr_aes_alg = {
 	.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
 	.cra_type        = &crypto_blkcipher_type,
 	.cra_module      = THIS_MODULE,
-	.cra_list        = LIST_HEAD_INIT(nx_ctr_aes_alg.cra_list),
 	.cra_init        = nx_crypto_ctx_aes_ctr_init,
 	.cra_exit        = nx_crypto_ctx_exit,
 	.cra_blkcipher = {
@@ -163,7 +162,6 @@ struct crypto_alg nx_ctr3686_aes_alg = {
 	.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
 	.cra_type        = &crypto_blkcipher_type,
 	.cra_module      = THIS_MODULE,
-	.cra_list        = LIST_HEAD_INIT(nx_ctr3686_aes_alg.cra_list),
 	.cra_init        = nx_crypto_ctx_aes_ctr_init,
 	.cra_exit        = nx_crypto_ctx_exit,
 	.cra_blkcipher = {
diff --git a/drivers/crypto/nx/nx-aes-ecb.c b/drivers/crypto/nx/nx-aes-ecb.c
index 7b77bc2..ba5f161 100644
--- a/drivers/crypto/nx/nx-aes-ecb.c
+++ b/drivers/crypto/nx/nx-aes-ecb.c
@@ -126,7 +126,6 @@ struct crypto_alg nx_ecb_aes_alg = {
 	.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
 	.cra_type        = &crypto_blkcipher_type,
 	.cra_module      = THIS_MODULE,
-	.cra_list        = LIST_HEAD_INIT(nx_ecb_aes_alg.cra_list),
 	.cra_init        = nx_crypto_ctx_aes_ecb_init,
 	.cra_exit        = nx_crypto_ctx_exit,
 	.cra_blkcipher = {
diff --git a/drivers/crypto/nx/nx-aes-gcm.c b/drivers/crypto/nx/nx-aes-gcm.c
index 9ab1c73..c8109ed 100644
--- a/drivers/crypto/nx/nx-aes-gcm.c
+++ b/drivers/crypto/nx/nx-aes-gcm.c
@@ -316,7 +316,6 @@ struct crypto_alg nx_gcm_aes_alg = {
 	.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
 	.cra_type        = &crypto_aead_type,
 	.cra_module      = THIS_MODULE,
-	.cra_list        = LIST_HEAD_INIT(nx_gcm_aes_alg.cra_list),
 	.cra_init        = nx_crypto_ctx_aes_gcm_init,
 	.cra_exit        = nx_crypto_ctx_exit,
 	.cra_aead = {
@@ -338,7 +337,6 @@ struct crypto_alg nx_gcm4106_aes_alg = {
 	.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
 	.cra_type        = &crypto_nivaead_type,
 	.cra_module      = THIS_MODULE,
-	.cra_list        = LIST_HEAD_INIT(nx_gcm4106_aes_alg.cra_list),
 	.cra_init        = nx_crypto_ctx_aes_gcm_init,
 	.cra_exit        = nx_crypto_ctx_exit,
 	.cra_aead = {
diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c
index 63e57b5..093a8af 100644
--- a/drivers/crypto/omap-aes.c
+++ b/drivers/crypto/omap-aes.c
@@ -876,7 +876,6 @@ static int omap_aes_probe(struct platform_device *pdev)
 
 	for (i = 0; i < ARRAY_SIZE(algs); i++) {
 		pr_debug("i: %d\n", i);
-		INIT_LIST_HEAD(&algs[i].cra_list);
 		err = crypto_register_alg(&algs[i]);
 		if (err)
 			goto err_algs;
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index 37b2e94..633ba94 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -328,7 +328,6 @@ static struct crypto_alg aes_alg = {
 	.cra_ctxsize		=	sizeof(struct aes_ctx),
 	.cra_alignmask		=	PADLOCK_ALIGNMENT - 1,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(aes_alg.cra_list),
 	.cra_u			=	{
 		.cipher = {
 			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
@@ -408,7 +407,6 @@ static struct crypto_alg ecb_aes_alg = {
 	.cra_alignmask		=	PADLOCK_ALIGNMENT - 1,
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(ecb_aes_alg.cra_list),
 	.cra_u			=	{
 		.blkcipher = {
 			.min_keysize		=	AES_MIN_KEY_SIZE,
@@ -491,7 +489,6 @@ static struct crypto_alg cbc_aes_alg = {
 	.cra_alignmask		=	PADLOCK_ALIGNMENT - 1,
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(cbc_aes_alg.cra_list),
 	.cra_u			=	{
 		.blkcipher = {
 			.min_keysize		=	AES_MIN_KEY_SIZE,
diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c
index bc986f8..a227144 100644
--- a/drivers/crypto/s5p-sss.c
+++ b/drivers/crypto/s5p-sss.c
@@ -626,7 +626,6 @@ static int s5p_aes_probe(struct platform_device *pdev)
 	crypto_init_queue(&pdata->queue, CRYPTO_QUEUE_LEN);
 
 	for (i = 0; i < ARRAY_SIZE(algs); i++) {
-		INIT_LIST_HEAD(&algs[i].cra_list);
 		err = crypto_register_alg(&algs[i]);
 		if (err)
 			goto err_algs;
diff --git a/drivers/crypto/tegra-aes.c b/drivers/crypto/tegra-aes.c
index ac236f6..631149e5 100644
--- a/drivers/crypto/tegra-aes.c
+++ b/drivers/crypto/tegra-aes.c
@@ -1004,8 +1004,6 @@ static int tegra_aes_probe(struct platform_device *pdev)
 
 	aes_dev = dd;
 	for (i = 0; i < ARRAY_SIZE(algs); i++) {
-		INIT_LIST_HEAD(&algs[i].cra_list);
-
 		algs[i].cra_priority = 300;
 		algs[i].cra_ctxsize = sizeof(struct tegra_aes_ctx);
 		algs[i].cra_module = THIS_MODULE;
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 3491654..a815d44 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -582,7 +582,7 @@ void dmaengine_get(void)
 				list_del_rcu(&device->global_node);
 				break;
 			} else if (err)
-				pr_err("%s: failed to get %s: (%d)\n",
+				pr_debug("%s: failed to get %s: (%d)\n",
 				       __func__, dma_chan_name(chan), err);
 		}
 	}
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index d3c5a5a..4f4ff13 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -1392,26 +1392,17 @@ static int __devinit dw_probe(struct platform_device *pdev)
 
 	size = sizeof(struct dw_dma);
 	size += pdata->nr_channels * sizeof(struct dw_dma_chan);
-	dw = kzalloc(size, GFP_KERNEL);
+	dw = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
 	if (!dw)
 		return -ENOMEM;
 
-	if (!request_mem_region(io->start, DW_REGLEN, pdev->dev.driver->name)) {
-		err = -EBUSY;
-		goto err_kfree;
-	}
-
-	dw->regs = ioremap(io->start, DW_REGLEN);
-	if (!dw->regs) {
-		err = -ENOMEM;
-		goto err_release_r;
-	}
+	dw->regs = devm_request_and_ioremap(&pdev->dev, io);
+	if (!dw->regs)
+		return -EBUSY;
 
-	dw->clk = clk_get(&pdev->dev, "hclk");
-	if (IS_ERR(dw->clk)) {
-		err = PTR_ERR(dw->clk);
-		goto err_clk;
-	}
+	dw->clk = devm_clk_get(&pdev->dev, "hclk");
+	if (IS_ERR(dw->clk))
+		return PTR_ERR(dw->clk);
 	clk_prepare_enable(dw->clk);
 
 	/* Calculate all channel mask before DMA setup */
@@ -1423,9 +1414,10 @@ static int __devinit dw_probe(struct platform_device *pdev)
 	/* disable BLOCK interrupts as well */
 	channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
 
-	err = request_irq(irq, dw_dma_interrupt, 0, "dw_dmac", dw);
+	err = devm_request_irq(&pdev->dev, irq, dw_dma_interrupt, 0,
+			       "dw_dmac", dw);
 	if (err)
-		goto err_irq;
+		return err;
 
 	platform_set_drvdata(pdev, dw);
 
@@ -1491,30 +1483,16 @@ static int __devinit dw_probe(struct platform_device *pdev)
 	dma_async_device_register(&dw->dma);
 
 	return 0;
-
-err_irq:
-	clk_disable_unprepare(dw->clk);
-	clk_put(dw->clk);
-err_clk:
-	iounmap(dw->regs);
-	dw->regs = NULL;
-err_release_r:
-	release_resource(io);
-err_kfree:
-	kfree(dw);
-	return err;
 }
 
 static int __devexit dw_remove(struct platform_device *pdev)
 {
 	struct dw_dma		*dw = platform_get_drvdata(pdev);
 	struct dw_dma_chan	*dwc, *_dwc;
-	struct resource		*io;
 
 	dw_dma_off(dw);
 	dma_async_device_unregister(&dw->dma);
 
-	free_irq(platform_get_irq(pdev, 0), dw);
 	tasklet_kill(&dw->tasklet);
 
 	list_for_each_entry_safe(dwc, _dwc, &dw->dma.channels,
@@ -1523,17 +1501,6 @@ static int __devexit dw_remove(struct platform_device *pdev)
 		channel_clear_bit(dw, CH_EN, dwc->mask);
 	}
 
-	clk_disable_unprepare(dw->clk);
-	clk_put(dw->clk);
-
-	iounmap(dw->regs);
-	dw->regs = NULL;
-
-	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(io->start, DW_REGLEN);
-
-	kfree(dw);
-
 	return 0;
 }
 
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index 50830be..f6d92d7 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -140,8 +140,6 @@ struct dw_dma_regs {
 /* Bitfields in CFG */
 #define DW_CFG_DMA_EN		(1 << 0)
 
-#define DW_REGLEN		0x400
-
 enum dw_dmac_flags {
 	DW_DMA_IS_CYCLIC = 0,
 };
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 616d90b..7c0df4a 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -538,7 +538,7 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
 		return;
 
 	INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
-	queue_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
+	mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
 }
 
 /*
@@ -578,21 +578,6 @@ void edac_mc_reset_delay_period(int value)
 
 	mutex_lock(&mem_ctls_mutex);
 
-	/* scan the list and turn off all workq timers, doing so under lock
-	 */
-	list_for_each(item, &mc_devices) {
-		mci = list_entry(item, struct mem_ctl_info, link);
-
-		if (mci->op_state == OP_RUNNING_POLL)
-			cancel_delayed_work(&mci->work);
-	}
-
-	mutex_unlock(&mem_ctls_mutex);
-
-
-	/* re-walk the list, and reset the poll delay */
-	mutex_lock(&mem_ctls_mutex);
-
 	list_for_each(item, &mc_devices) {
 		mci = list_entry(item, struct mem_ctl_info, link);
 
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 88961b3..9c0682da 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -2,8 +2,8 @@
 # Makefile for external connector class (extcon) devices
 #
 
-obj-$(CONFIG_EXTCON)		+= extcon_class.o
-obj-$(CONFIG_EXTCON_GPIO)	+= extcon_gpio.o
+obj-$(CONFIG_EXTCON)		+= extcon-class.o
+obj-$(CONFIG_EXTCON_GPIO)	+= extcon-gpio.o
 obj-$(CONFIG_EXTCON_MAX77693)	+= extcon-max77693.o
 obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
 obj-$(CONFIG_EXTCON_ARIZONA)	+= extcon-arizona.o
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 427a289..fa2114f 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -21,6 +21,7 @@
 #include <linux/interrupt.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/input.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
@@ -30,11 +31,14 @@
 #include <linux/mfd/arizona/pdata.h>
 #include <linux/mfd/arizona/registers.h>
 
+#define ARIZONA_NUM_BUTTONS 6
+
 struct arizona_extcon_info {
 	struct device *dev;
 	struct arizona *arizona;
 	struct mutex lock;
 	struct regulator *micvdd;
+	struct input_dev *input;
 
 	int micd_mode;
 	const struct arizona_micd_config *micd_modes;
@@ -54,6 +58,18 @@ static const struct arizona_micd_config micd_default_modes[] = {
 	{ 0,                  2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
 };
 
+static struct {
+	u16 status;
+	int report;
+} arizona_lvl_to_key[ARIZONA_NUM_BUTTONS] = {
+	{  0x1, BTN_0 },
+	{  0x2, BTN_1 },
+	{  0x4, BTN_2 },
+	{  0x8, BTN_3 },
+	{ 0x10, BTN_4 },
+	{ 0x20, BTN_5 },
+};
+
 #define ARIZONA_CABLE_MECHANICAL 0
 #define ARIZONA_CABLE_MICROPHONE 1
 #define ARIZONA_CABLE_HEADPHONE  2
@@ -133,6 +149,7 @@ static void arizona_stop_mic(struct arizona_extcon_info *info)
 
 	if (change) {
 		regulator_disable(info->micvdd);
+		pm_runtime_mark_last_busy(info->dev);
 		pm_runtime_put_autosuspend(info->dev);
 	}
 }
@@ -141,8 +158,8 @@ static irqreturn_t arizona_micdet(int irq, void *data)
 {
 	struct arizona_extcon_info *info = data;
 	struct arizona *arizona = info->arizona;
-	unsigned int val;
-	int ret;
+	unsigned int val, lvl;
+	int ret, i;
 
 	mutex_lock(&info->lock);
 
@@ -219,13 +236,22 @@ static irqreturn_t arizona_micdet(int irq, void *data)
 
 	/*
 	 * If we're still detecting and we detect a short then we've
-	 * got a headphone.  Otherwise it's a button press, the
-	 * button reporting is stubbed out for now.
+	 * got a headphone.  Otherwise it's a button press.
 	 */
 	if (val & 0x3fc) {
 		if (info->mic) {
 			dev_dbg(arizona->dev, "Mic button detected\n");
 
+			lvl = val & ARIZONA_MICD_LVL_MASK;
+			lvl >>= ARIZONA_MICD_LVL_SHIFT;
+
+			for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
+				if (lvl & arizona_lvl_to_key[i].status)
+					input_report_key(info->input,
+							 arizona_lvl_to_key[i].report,
+							 1);
+			input_sync(info->input);
+
 		} else if (info->detecting) {
 			dev_dbg(arizona->dev, "Headphone detected\n");
 			info->detecting = false;
@@ -244,6 +270,10 @@ static irqreturn_t arizona_micdet(int irq, void *data)
 		}
 	} else {
 		dev_dbg(arizona->dev, "Mic button released\n");
+		for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
+			input_report_key(info->input,
+					 arizona_lvl_to_key[i].report, 0);
+		input_sync(info->input);
 	}
 
 handled:
@@ -258,7 +288,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
 	struct arizona_extcon_info *info = data;
 	struct arizona *arizona = info->arizona;
 	unsigned int val;
-	int ret;
+	int ret, i;
 
 	pm_runtime_get_sync(info->dev);
 
@@ -288,6 +318,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
 
 		arizona_stop_mic(info);
 
+		for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
+			input_report_key(info->input,
+					 arizona_lvl_to_key[i].report, 0);
+		input_sync(info->input);
+
 		ret = extcon_update_state(&info->edev, 0xffffffff, 0);
 		if (ret != 0)
 			dev_err(arizona->dev, "Removal report failed: %d\n",
@@ -307,7 +342,7 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev)
 	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
 	struct arizona_pdata *pdata;
 	struct arizona_extcon_info *info;
-	int ret, mode;
+	int ret, mode, i;
 
 	pdata = dev_get_platdata(arizona->dev);
 
@@ -382,6 +417,20 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev)
 
 	arizona_extcon_set_mode(info, 0);
 
+	info->input = input_allocate_device();
+	if (!info->input) {
+		dev_err(arizona->dev, "Can't allocate input dev\n");
+		ret = -ENOMEM;
+		goto err_register;
+	}
+
+	for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
+		input_set_capability(info->input, EV_KEY,
+				     arizona_lvl_to_key[i].report);
+	info->input->name = "Headset";
+	info->input->phys = "arizona/extcon";
+	info->input->dev.parent = &pdev->dev;
+
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_idle(&pdev->dev);
 	pm_runtime_get_sync(&pdev->dev);
@@ -391,7 +440,7 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev)
 	if (ret != 0) {
 		dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
 			ret);
-		goto err_register;
+		goto err_input;
 	}
 
 	ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 1);
@@ -436,6 +485,12 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev)
 
 	pm_runtime_put(&pdev->dev);
 
+	ret = input_register_device(info->input);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
+		goto err_fall_wake;
+	}
+
 	return 0;
 
 err_fall_wake:
@@ -446,6 +501,8 @@ err_rise_wake:
 	arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 0);
 err_rise:
 	arizona_free_irq(arizona, ARIZONA_IRQ_JD_RISE, info);
+err_input:
+	input_free_device(info->input);
 err_register:
 	pm_runtime_disable(&pdev->dev);
 	extcon_dev_unregister(&info->edev);
@@ -468,6 +525,7 @@ static int __devexit arizona_extcon_remove(struct platform_device *pdev)
 	regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
 			   ARIZONA_JD1_ENA, 0);
 	arizona_clk32k_disable(arizona);
+	input_unregister_device(info->input);
 	extcon_dev_unregister(&info->edev);
 
 	return 0;
diff --git a/drivers/extcon/extcon-class.c b/drivers/extcon/extcon-class.c
new file mode 100644
index 0000000..481cfa0
--- /dev/null
+++ b/drivers/extcon/extcon-class.c
@@ -0,0 +1,836 @@
+/*
+ *  drivers/extcon/extcon_class.c
+ *
+ *  External connector (extcon) class driver
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Author: Donggeun Kim <dg77.kim@samsung.com>
+ * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * based on android/drivers/switch/switch_class.c
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/extcon.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+/*
+ * extcon_cable_name suggests the standard cable names for commonly used
+ * cable types.
+ *
+ * However, please do not use extcon_cable_name directly for extcon_dev
+ * struct's supported_cable pointer unless your device really supports
+ * every single port-type of the following cable names. Please choose cable
+ * names that are actually used in your extcon device.
+ */
+const char *extcon_cable_name[] = {
+	[EXTCON_USB]		= "USB",
+	[EXTCON_USB_HOST]	= "USB-Host",
+	[EXTCON_TA]		= "TA",
+	[EXTCON_FAST_CHARGER]	= "Fast-charger",
+	[EXTCON_SLOW_CHARGER]	= "Slow-charger",
+	[EXTCON_CHARGE_DOWNSTREAM]	= "Charge-downstream",
+	[EXTCON_HDMI]		= "HDMI",
+	[EXTCON_MHL]		= "MHL",
+	[EXTCON_DVI]		= "DVI",
+	[EXTCON_VGA]		= "VGA",
+	[EXTCON_DOCK]		= "Dock",
+	[EXTCON_LINE_IN]	= "Line-in",
+	[EXTCON_LINE_OUT]	= "Line-out",
+	[EXTCON_MIC_IN]		= "Microphone",
+	[EXTCON_HEADPHONE_OUT]	= "Headphone",
+	[EXTCON_SPDIF_IN]	= "SPDIF-in",
+	[EXTCON_SPDIF_OUT]	= "SPDIF-out",
+	[EXTCON_VIDEO_IN]	= "Video-in",
+	[EXTCON_VIDEO_OUT]	= "Video-out",
+	[EXTCON_MECHANICAL]	= "Mechanical",
+
+	NULL,
+};
+
+static struct class *extcon_class;
+#if defined(CONFIG_ANDROID)
+static struct class_compat *switch_class;
+#endif /* CONFIG_ANDROID */
+
+static LIST_HEAD(extcon_dev_list);
+static DEFINE_MUTEX(extcon_dev_list_lock);
+
+/**
+ * check_mutually_exclusive - Check if new_state violates mutually_exclusive
+ *			    condition.
+ * @edev:	the extcon device
+ * @new_state:	new cable attach status for @edev
+ *
+ * Returns 0 if nothing violates. Returns the index + 1 for the first
+ * violated condition.
+ */
+static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state)
+{
+	int i = 0;
+
+	if (!edev->mutually_exclusive)
+		return 0;
+
+	for (i = 0; edev->mutually_exclusive[i]; i++) {
+		int count = 0, j;
+		u32 correspondants = new_state & edev->mutually_exclusive[i];
+		u32 exp = 1;
+
+		for (j = 0; j < 32; j++) {
+			if (exp & correspondants)
+				count++;
+			if (count > 1)
+				return i + 1;
+			exp <<= 1;
+		}
+	}
+
+	return 0;
+}
+
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int i, count = 0;
+	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+	if (edev->print_state) {
+		int ret = edev->print_state(edev, buf);
+
+		if (ret >= 0)
+			return ret;
+		/* Use default if failed */
+	}
+
+	if (edev->max_supported == 0)
+		return sprintf(buf, "%u\n", edev->state);
+
+	for (i = 0; i < SUPPORTED_CABLE_MAX; i++) {
+		if (!edev->supported_cable[i])
+			break;
+		count += sprintf(buf + count, "%s=%d\n",
+				 edev->supported_cable[i],
+				 !!(edev->state & (1 << i)));
+	}
+
+	return count;
+}
+
+int extcon_set_state(struct extcon_dev *edev, u32 state);
+static ssize_t state_store(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	u32 state;
+	ssize_t ret = 0;
+	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+	ret = sscanf(buf, "0x%x", &state);
+	if (ret == 0)
+		ret = -EINVAL;
+	else
+		ret = extcon_set_state(edev, state);
+
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+	/* Optional callback given by the user */
+	if (edev->print_name) {
+		int ret = edev->print_name(edev, buf);
+		if (ret >= 0)
+			return ret;
+	}
+
+	return sprintf(buf, "%s\n", dev_name(edev->dev));
+}
+
+static ssize_t cable_name_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct extcon_cable *cable = container_of(attr, struct extcon_cable,
+						  attr_name);
+
+	return sprintf(buf, "%s\n",
+		       cable->edev->supported_cable[cable->cable_index]);
+}
+
+static ssize_t cable_state_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct extcon_cable *cable = container_of(attr, struct extcon_cable,
+						  attr_state);
+
+	return sprintf(buf, "%d\n",
+		       extcon_get_cable_state_(cable->edev,
+					       cable->cable_index));
+}
+
+static ssize_t cable_state_store(struct device *dev,
+				 struct device_attribute *attr, const char *buf,
+				 size_t count)
+{
+	struct extcon_cable *cable = container_of(attr, struct extcon_cable,
+						  attr_state);
+	int ret, state;
+
+	ret = sscanf(buf, "%d", &state);
+	if (ret == 0)
+		ret = -EINVAL;
+	else
+		ret = extcon_set_cable_state_(cable->edev, cable->cable_index,
+					      state);
+
+	if (ret < 0)
+		return ret;
+	return count;
+}
+
+/**
+ * extcon_update_state() - Update the cable attach states of the extcon device
+ *			only for the masked bits.
+ * @edev:	the extcon device
+ * @mask:	the bit mask to designate updated bits.
+ * @state:	new cable attach status for @edev
+ *
+ * Changing the state sends uevent with environment variable containing
+ * the name of extcon device (envp[0]) and the state output (envp[1]).
+ * Tizen uses this format for extcon device to get events from ports.
+ * Android uses this format as well.
+ *
+ * Note that the notifier provides which bits are changed in the state
+ * variable with the val parameter (second) to the callback.
+ */
+int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
+{
+	char name_buf[120];
+	char state_buf[120];
+	char *prop_buf;
+	char *envp[3];
+	int env_offset = 0;
+	int length;
+	unsigned long flags;
+
+	spin_lock_irqsave(&edev->lock, flags);
+
+	if (edev->state != ((edev->state & ~mask) | (state & mask))) {
+		u32 old_state = edev->state;
+
+		if (check_mutually_exclusive(edev, (edev->state & ~mask) |
+						   (state & mask))) {
+			spin_unlock_irqrestore(&edev->lock, flags);
+			return -EPERM;
+		}
+
+		edev->state &= ~mask;
+		edev->state |= state & mask;
+
+		raw_notifier_call_chain(&edev->nh, old_state, edev);
+
+		/* This could be in interrupt handler */
+		prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
+		if (prop_buf) {
+			length = name_show(edev->dev, NULL, prop_buf);
+			if (length > 0) {
+				if (prop_buf[length - 1] == '\n')
+					prop_buf[length - 1] = 0;
+				snprintf(name_buf, sizeof(name_buf),
+					"NAME=%s", prop_buf);
+				envp[env_offset++] = name_buf;
+			}
+			length = state_show(edev->dev, NULL, prop_buf);
+			if (length > 0) {
+				if (prop_buf[length - 1] == '\n')
+					prop_buf[length - 1] = 0;
+				snprintf(state_buf, sizeof(state_buf),
+					"STATE=%s", prop_buf);
+				envp[env_offset++] = state_buf;
+			}
+			envp[env_offset] = NULL;
+			/* Unlock early before uevent */
+			spin_unlock_irqrestore(&edev->lock, flags);
+
+			kobject_uevent_env(&edev->dev->kobj, KOBJ_CHANGE, envp);
+			free_page((unsigned long)prop_buf);
+		} else {
+			/* Unlock early before uevent */
+			spin_unlock_irqrestore(&edev->lock, flags);
+
+			dev_err(edev->dev, "out of memory in extcon_set_state\n");
+			kobject_uevent(&edev->dev->kobj, KOBJ_CHANGE);
+		}
+	} else {
+		/* No changes */
+		spin_unlock_irqrestore(&edev->lock, flags);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(extcon_update_state);
+
+/**
+ * extcon_set_state() - Set the cable attach states of the extcon device.
+ * @edev:	the extcon device
+ * @state:	new cable attach status for @edev
+ *
+ * Note that notifier provides which bits are changed in the state
+ * variable with the val parameter (second) to the callback.
+ */
+int extcon_set_state(struct extcon_dev *edev, u32 state)
+{
+	return extcon_update_state(edev, 0xffffffff, state);
+}
+EXPORT_SYMBOL_GPL(extcon_set_state);
+
+/**
+ * extcon_find_cable_index() - Get the cable index based on the cable name.
+ * @edev:	the extcon device that has the cable.
+ * @cable_name:	cable name to be searched.
+ *
+ * Note that accessing a cable state based on cable_index is faster than
+ * cable_name because using cable_name induces a loop with strncmp().
+ * Thus, when get/set_cable_state is repeatedly used, using cable_index
+ * is recommended.
+ */
+int extcon_find_cable_index(struct extcon_dev *edev, const char *cable_name)
+{
+	int i;
+
+	if (edev->supported_cable) {
+		for (i = 0; edev->supported_cable[i]; i++) {
+			if (!strncmp(edev->supported_cable[i],
+				cable_name, CABLE_NAME_MAX))
+				return i;
+		}
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(extcon_find_cable_index);
+
+/**
+ * extcon_get_cable_state_() - Get the status of a specific cable.
+ * @edev:	the extcon device that has the cable.
+ * @index:	cable index that can be retrieved by extcon_find_cable_index().
+ */
+int extcon_get_cable_state_(struct extcon_dev *edev, int index)
+{
+	if (index < 0 || (edev->max_supported && edev->max_supported <= index))
+		return -EINVAL;
+
+	return !!(edev->state & (1 << index));
+}
+EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
+
+/**
+ * extcon_get_cable_state() - Get the status of a specific cable.
+ * @edev:	the extcon device that has the cable.
+ * @cable_name:	cable name.
+ *
+ * Note that this is slower than extcon_get_cable_state_.
+ */
+int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
+{
+	return extcon_get_cable_state_(edev, extcon_find_cable_index
+						(edev, cable_name));
+}
+EXPORT_SYMBOL_GPL(extcon_get_cable_state);
+
+/**
+ * extcon_get_cable_state_() - Set the status of a specific cable.
+ * @edev:	the extcon device that has the cable.
+ * @index:	cable index that can be retrieved by extcon_find_cable_index().
+ * @cable_state:	the new cable status. The default semantics is
+ *			true: attached / false: detached.
+ */
+int extcon_set_cable_state_(struct extcon_dev *edev,
+			int index, bool cable_state)
+{
+	u32 state;
+
+	if (index < 0 || (edev->max_supported && edev->max_supported <= index))
+		return -EINVAL;
+
+	state = cable_state ? (1 << index) : 0;
+	return extcon_update_state(edev, 1 << index, state);
+}
+EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
+
+/**
+ * extcon_get_cable_state() - Set the status of a specific cable.
+ * @edev:	the extcon device that has the cable.
+ * @cable_name:	cable name.
+ * @cable_state:	the new cable status. The default semantics is
+ *			true: attached / false: detached.
+ *
+ * Note that this is slower than extcon_set_cable_state_.
+ */
+int extcon_set_cable_state(struct extcon_dev *edev,
+			const char *cable_name, bool cable_state)
+{
+	return extcon_set_cable_state_(edev, extcon_find_cable_index
+					(edev, cable_name), cable_state);
+}
+EXPORT_SYMBOL_GPL(extcon_set_cable_state);
+
+/**
+ * extcon_get_extcon_dev() - Get the extcon device instance from the name
+ * @extcon_name:	The extcon name provided with extcon_dev_register()
+ */
+struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
+{
+	struct extcon_dev *sd;
+
+	mutex_lock(&extcon_dev_list_lock);
+	list_for_each_entry(sd, &extcon_dev_list, entry) {
+		if (!strcmp(sd->name, extcon_name))
+			goto out;
+	}
+	sd = NULL;
+out:
+	mutex_unlock(&extcon_dev_list_lock);
+	return sd;
+}
+EXPORT_SYMBOL_GPL(extcon_get_extcon_dev);
+
+static int _call_per_cable(struct notifier_block *nb, unsigned long val,
+			   void *ptr)
+{
+	struct extcon_specific_cable_nb *obj = container_of(nb,
+			struct extcon_specific_cable_nb, internal_nb);
+	struct extcon_dev *edev = ptr;
+
+	if ((val & (1 << obj->cable_index)) !=
+	    (edev->state & (1 << obj->cable_index))) {
+		bool cable_state = true;
+
+		obj->previous_value = val;
+
+		if (val & (1 << obj->cable_index))
+			cable_state = false;
+
+		return obj->user_nb->notifier_call(obj->user_nb,
+				cable_state, ptr);
+	}
+
+	return NOTIFY_OK;
+}
+
+/**
+ * extcon_register_interest() - Register a notifier for a state change of a
+ *			      specific cable, not a entier set of cables of a
+ *			      extcon device.
+ * @obj:	an empty extcon_specific_cable_nb object to be returned.
+ * @extcon_name:	the name of extcon device.
+ * @cable_name:		the target cable name.
+ * @nb:		the notifier block to get notified.
+ *
+ * Provide an empty extcon_specific_cable_nb. extcon_register_interest() sets
+ * the struct for you.
+ *
+ * extcon_register_interest is a helper function for those who want to get
+ * notification for a single specific cable's status change. If a user wants
+ * to get notification for any changes of all cables of a extcon device,
+ * he/she should use the general extcon_register_notifier().
+ *
+ * Note that the second parameter given to the callback of nb (val) is
+ * "old_state", not the current state. The current state can be retrieved
+ * by looking at the third pameter (edev pointer)'s state value.
+ */
+int extcon_register_interest(struct extcon_specific_cable_nb *obj,
+			     const char *extcon_name, const char *cable_name,
+			     struct notifier_block *nb)
+{
+	if (!obj || !extcon_name || !cable_name || !nb)
+		return -EINVAL;
+
+	obj->edev = extcon_get_extcon_dev(extcon_name);
+	if (!obj->edev)
+		return -ENODEV;
+
+	obj->cable_index = extcon_find_cable_index(obj->edev, cable_name);
+	if (obj->cable_index < 0)
+		return -ENODEV;
+
+	obj->user_nb = nb;
+
+	obj->internal_nb.notifier_call = _call_per_cable;
+
+	return raw_notifier_chain_register(&obj->edev->nh, &obj->internal_nb);
+}
+
+/**
+ * extcon_unregister_interest() - Unregister the notifier registered by
+ *				extcon_register_interest().
+ * @obj:	the extcon_specific_cable_nb object returned by
+ *		extcon_register_interest().
+ */
+int extcon_unregister_interest(struct extcon_specific_cable_nb *obj)
+{
+	if (!obj)
+		return -EINVAL;
+
+	return raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb);
+}
+
+/**
+ * extcon_register_notifier() - Register a notifee to get notified by
+ *			      any attach status changes from the extcon.
+ * @edev:	the extcon device.
+ * @nb:		a notifier block to be registered.
+ *
+ * Note that the second parameter given to the callback of nb (val) is
+ * "old_state", not the current state. The current state can be retrieved
+ * by looking at the third pameter (edev pointer)'s state value.
+ */
+int extcon_register_notifier(struct extcon_dev *edev,
+			struct notifier_block *nb)
+{
+	return raw_notifier_chain_register(&edev->nh, nb);
+}
+EXPORT_SYMBOL_GPL(extcon_register_notifier);
+
+/**
+ * extcon_unregister_notifier() - Unregister a notifee from the extcon device.
+ * @edev:	the extcon device.
+ * @nb:		a registered notifier block to be unregistered.
+ */
+int extcon_unregister_notifier(struct extcon_dev *edev,
+			struct notifier_block *nb)
+{
+	return raw_notifier_chain_unregister(&edev->nh, nb);
+}
+EXPORT_SYMBOL_GPL(extcon_unregister_notifier);
+
+static struct device_attribute extcon_attrs[] = {
+	__ATTR(state, S_IRUGO | S_IWUSR, state_show, state_store),
+	__ATTR_RO(name),
+	__ATTR_NULL,
+};
+
+static int create_extcon_class(void)
+{
+	if (!extcon_class) {
+		extcon_class = class_create(THIS_MODULE, "extcon");
+		if (IS_ERR(extcon_class))
+			return PTR_ERR(extcon_class);
+		extcon_class->dev_attrs = extcon_attrs;
+
+#if defined(CONFIG_ANDROID)
+		switch_class = class_compat_register("switch");
+		if (WARN(!switch_class, "cannot allocate"))
+			return -ENOMEM;
+#endif /* CONFIG_ANDROID */
+	}
+
+	return 0;
+}
+
+static void extcon_cleanup(struct extcon_dev *edev, bool skip)
+{
+	mutex_lock(&extcon_dev_list_lock);
+	list_del(&edev->entry);
+	mutex_unlock(&extcon_dev_list_lock);
+
+	if (!skip && get_device(edev->dev)) {
+		int index;
+
+		if (edev->mutually_exclusive && edev->max_supported) {
+			for (index = 0; edev->mutually_exclusive[index];
+			     index++)
+				kfree(edev->d_attrs_muex[index].attr.name);
+			kfree(edev->d_attrs_muex);
+			kfree(edev->attrs_muex);
+		}
+
+		for (index = 0; index < edev->max_supported; index++)
+			kfree(edev->cables[index].attr_g.name);
+
+		if (edev->max_supported) {
+			kfree(edev->extcon_dev_type.groups);
+			kfree(edev->cables);
+		}
+
+		device_unregister(edev->dev);
+		put_device(edev->dev);
+	}
+
+	kfree(edev->dev);
+}
+
+static void extcon_dev_release(struct device *dev)
+{
+	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+	extcon_cleanup(edev, true);
+}
+
+static const char *muex_name = "mutually_exclusive";
+static void dummy_sysfs_dev_release(struct device *dev)
+{
+}
+
+/**
+ * extcon_dev_register() - Register a new extcon device
+ * @edev	: the new extcon device (should be allocated before calling)
+ * @dev		: the parent device for this extcon device.
+ *
+ * Among the members of edev struct, please set the "user initializing data"
+ * in any case and set the "optional callbacks" if required. However, please
+ * do not set the values of "internal data", which are initialized by
+ * this function.
+ */
+int extcon_dev_register(struct extcon_dev *edev, struct device *dev)
+{
+	int ret, index = 0;
+
+	if (!extcon_class) {
+		ret = create_extcon_class();
+		if (ret < 0)
+			return ret;
+	}
+
+	if (edev->supported_cable) {
+		/* Get size of array */
+		for (index = 0; edev->supported_cable[index]; index++)
+			;
+		edev->max_supported = index;
+	} else {
+		edev->max_supported = 0;
+	}
+
+	if (index > SUPPORTED_CABLE_MAX) {
+		dev_err(edev->dev, "extcon: maximum number of supported cables exceeded.\n");
+		return -EINVAL;
+	}
+
+	edev->dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+	if (!edev->dev)
+		return -ENOMEM;
+	edev->dev->parent = dev;
+	edev->dev->class = extcon_class;
+	edev->dev->release = extcon_dev_release;
+
+	dev_set_name(edev->dev, edev->name ? edev->name : dev_name(dev));
+
+	if (edev->max_supported) {
+		char buf[10];
+		char *str;
+		struct extcon_cable *cable;
+
+		edev->cables = kzalloc(sizeof(struct extcon_cable) *
+				       edev->max_supported, GFP_KERNEL);
+		if (!edev->cables) {
+			ret = -ENOMEM;
+			goto err_sysfs_alloc;
+		}
+		for (index = 0; index < edev->max_supported; index++) {
+			cable = &edev->cables[index];
+
+			snprintf(buf, 10, "cable.%d", index);
+			str = kzalloc(sizeof(char) * (strlen(buf) + 1),
+				      GFP_KERNEL);
+			if (!str) {
+				for (index--; index >= 0; index--) {
+					cable = &edev->cables[index];
+					kfree(cable->attr_g.name);
+				}
+				ret = -ENOMEM;
+
+				goto err_alloc_cables;
+			}
+			strcpy(str, buf);
+
+			cable->edev = edev;
+			cable->cable_index = index;
+			cable->attrs[0] = &cable->attr_name.attr;
+			cable->attrs[1] = &cable->attr_state.attr;
+			cable->attrs[2] = NULL;
+			cable->attr_g.name = str;
+			cable->attr_g.attrs = cable->attrs;
+
+			sysfs_attr_init(&cable->attr_name.attr);
+			cable->attr_name.attr.name = "name";
+			cable->attr_name.attr.mode = 0444;
+			cable->attr_name.show = cable_name_show;
+
+			sysfs_attr_init(&cable->attr_state.attr);
+			cable->attr_state.attr.name = "state";
+			cable->attr_state.attr.mode = 0644;
+			cable->attr_state.show = cable_state_show;
+			cable->attr_state.store = cable_state_store;
+		}
+	}
+
+	if (edev->max_supported && edev->mutually_exclusive) {
+		char buf[80];
+		char *name;
+
+		/* Count the size of mutually_exclusive array */
+		for (index = 0; edev->mutually_exclusive[index]; index++)
+			;
+
+		edev->attrs_muex = kzalloc(sizeof(struct attribute *) *
+					   (index + 1), GFP_KERNEL);
+		if (!edev->attrs_muex) {
+			ret = -ENOMEM;
+			goto err_muex;
+		}
+
+		edev->d_attrs_muex = kzalloc(sizeof(struct device_attribute) *
+					     index, GFP_KERNEL);
+		if (!edev->d_attrs_muex) {
+			ret = -ENOMEM;
+			kfree(edev->attrs_muex);
+			goto err_muex;
+		}
+
+		for (index = 0; edev->mutually_exclusive[index]; index++) {
+			sprintf(buf, "0x%x", edev->mutually_exclusive[index]);
+			name = kzalloc(sizeof(char) * (strlen(buf) + 1),
+				       GFP_KERNEL);
+			if (!name) {
+				for (index--; index >= 0; index--) {
+					kfree(edev->d_attrs_muex[index].attr.
+					      name);
+				}
+				kfree(edev->d_attrs_muex);
+				kfree(edev->attrs_muex);
+				ret = -ENOMEM;
+				goto err_muex;
+			}
+			strcpy(name, buf);
+			sysfs_attr_init(&edev->d_attrs_muex[index].attr);
+			edev->d_attrs_muex[index].attr.name = name;
+			edev->d_attrs_muex[index].attr.mode = 0000;
+			edev->attrs_muex[index] = &edev->d_attrs_muex[index]
+							.attr;
+		}
+		edev->attr_g_muex.name = muex_name;
+		edev->attr_g_muex.attrs = edev->attrs_muex;
+
+	}
+
+	if (edev->max_supported) {
+		edev->extcon_dev_type.groups =
+			kzalloc(sizeof(struct attribute_group *) *
+				(edev->max_supported + 2), GFP_KERNEL);
+		if (!edev->extcon_dev_type.groups) {
+			ret = -ENOMEM;
+			goto err_alloc_groups;
+		}
+
+		edev->extcon_dev_type.name = dev_name(edev->dev);
+		edev->extcon_dev_type.release = dummy_sysfs_dev_release;
+
+		for (index = 0; index < edev->max_supported; index++)
+			edev->extcon_dev_type.groups[index] =
+				&edev->cables[index].attr_g;
+		if (edev->mutually_exclusive)
+			edev->extcon_dev_type.groups[index] =
+				&edev->attr_g_muex;
+
+		edev->dev->type = &edev->extcon_dev_type;
+	}
+
+	ret = device_register(edev->dev);
+	if (ret) {
+		put_device(edev->dev);
+		goto err_dev;
+	}
+#if defined(CONFIG_ANDROID)
+	if (switch_class)
+		ret = class_compat_create_link(switch_class, edev->dev,
+					       NULL);
+#endif /* CONFIG_ANDROID */
+
+	spin_lock_init(&edev->lock);
+
+	RAW_INIT_NOTIFIER_HEAD(&edev->nh);
+
+	dev_set_drvdata(edev->dev, edev);
+	edev->state = 0;
+
+	mutex_lock(&extcon_dev_list_lock);
+	list_add(&edev->entry, &extcon_dev_list);
+	mutex_unlock(&extcon_dev_list_lock);
+
+	return 0;
+
+err_dev:
+	if (edev->max_supported)
+		kfree(edev->extcon_dev_type.groups);
+err_alloc_groups:
+	if (edev->max_supported && edev->mutually_exclusive) {
+		for (index = 0; edev->mutually_exclusive[index]; index++)
+			kfree(edev->d_attrs_muex[index].attr.name);
+		kfree(edev->d_attrs_muex);
+		kfree(edev->attrs_muex);
+	}
+err_muex:
+	for (index = 0; index < edev->max_supported; index++)
+		kfree(edev->cables[index].attr_g.name);
+err_alloc_cables:
+	if (edev->max_supported)
+		kfree(edev->cables);
+err_sysfs_alloc:
+	kfree(edev->dev);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(extcon_dev_register);
+
+/**
+ * extcon_dev_unregister() - Unregister the extcon device.
+ * @edev:	the extcon device instance to be unregitered.
+ *
+ * Note that this does not call kfree(edev) because edev was not allocated
+ * by this class.
+ */
+void extcon_dev_unregister(struct extcon_dev *edev)
+{
+	extcon_cleanup(edev, false);
+}
+EXPORT_SYMBOL_GPL(extcon_dev_unregister);
+
+static int __init extcon_class_init(void)
+{
+	return create_extcon_class();
+}
+module_init(extcon_class_init);
+
+static void __exit extcon_class_exit(void)
+{
+	class_destroy(extcon_class);
+}
+module_exit(extcon_class_exit);
+
+MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_DESCRIPTION("External connector (extcon) class driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
new file mode 100644
index 0000000..3cc152e
--- /dev/null
+++ b/drivers/extcon/extcon-gpio.c
@@ -0,0 +1,165 @@
+/*
+ *  drivers/extcon/extcon_gpio.c
+ *
+ *  Single-state GPIO extcon driver based on extcon class
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * Modified by MyungJoo Ham <myungjoo.ham@samsung.com> to support extcon
+ * (originally switch class is supported)
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/extcon.h>
+#include <linux/workqueue.h>
+#include <linux/gpio.h>
+#include <linux/extcon.h>
+#include <linux/extcon/extcon_gpio.h>
+
+struct gpio_extcon_data {
+	struct extcon_dev edev;
+	unsigned gpio;
+	const char *state_on;
+	const char *state_off;
+	int irq;
+	struct delayed_work work;
+	unsigned long debounce_jiffies;
+};
+
+static void gpio_extcon_work(struct work_struct *work)
+{
+	int state;
+	struct gpio_extcon_data	*data =
+		container_of(to_delayed_work(work), struct gpio_extcon_data,
+			     work);
+
+	state = gpio_get_value(data->gpio);
+	extcon_set_state(&data->edev, state);
+}
+
+static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
+{
+	struct gpio_extcon_data *extcon_data = dev_id;
+
+	schedule_delayed_work(&extcon_data->work,
+			      extcon_data->debounce_jiffies);
+	return IRQ_HANDLED;
+}
+
+static ssize_t extcon_gpio_print_state(struct extcon_dev *edev, char *buf)
+{
+	struct gpio_extcon_data	*extcon_data =
+		container_of(edev, struct gpio_extcon_data, edev);
+	const char *state;
+	if (extcon_get_state(edev))
+		state = extcon_data->state_on;
+	else
+		state = extcon_data->state_off;
+
+	if (state)
+		return sprintf(buf, "%s\n", state);
+	return -EINVAL;
+}
+
+static int __devinit gpio_extcon_probe(struct platform_device *pdev)
+{
+	struct gpio_extcon_platform_data *pdata = pdev->dev.platform_data;
+	struct gpio_extcon_data *extcon_data;
+	int ret = 0;
+
+	if (!pdata)
+		return -EBUSY;
+	if (!pdata->irq_flags) {
+		dev_err(&pdev->dev, "IRQ flag is not specified.\n");
+		return -EINVAL;
+	}
+
+	extcon_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data),
+				   GFP_KERNEL);
+	if (!extcon_data)
+		return -ENOMEM;
+
+	extcon_data->edev.name = pdata->name;
+	extcon_data->gpio = pdata->gpio;
+	extcon_data->state_on = pdata->state_on;
+	extcon_data->state_off = pdata->state_off;
+	if (pdata->state_on && pdata->state_off)
+		extcon_data->edev.print_state = extcon_gpio_print_state;
+	extcon_data->debounce_jiffies = msecs_to_jiffies(pdata->debounce);
+
+	ret = extcon_dev_register(&extcon_data->edev, &pdev->dev);
+	if (ret < 0)
+		return ret;
+
+	ret = devm_gpio_request_one(&pdev->dev, extcon_data->gpio, GPIOF_DIR_IN,
+				    pdev->name);
+	if (ret < 0)
+		goto err;
+
+	INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work);
+
+	extcon_data->irq = gpio_to_irq(extcon_data->gpio);
+	if (extcon_data->irq < 0) {
+		ret = extcon_data->irq;
+		goto err;
+	}
+
+	ret = request_any_context_irq(extcon_data->irq, gpio_irq_handler,
+				      pdata->irq_flags, pdev->name,
+				      extcon_data);
+	if (ret < 0)
+		goto err;
+
+	platform_set_drvdata(pdev, extcon_data);
+	/* Perform initial detection */
+	gpio_extcon_work(&extcon_data->work.work);
+
+	return 0;
+
+err:
+	extcon_dev_unregister(&extcon_data->edev);
+
+	return ret;
+}
+
+static int __devexit gpio_extcon_remove(struct platform_device *pdev)
+{
+	struct gpio_extcon_data *extcon_data = platform_get_drvdata(pdev);
+
+	cancel_delayed_work_sync(&extcon_data->work);
+	free_irq(extcon_data->irq, extcon_data);
+	extcon_dev_unregister(&extcon_data->edev);
+
+	return 0;
+}
+
+static struct platform_driver gpio_extcon_driver = {
+	.probe		= gpio_extcon_probe,
+	.remove		= __devexit_p(gpio_extcon_remove),
+	.driver		= {
+		.name	= "extcon-gpio",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(gpio_extcon_driver);
+
+MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
+MODULE_DESCRIPTION("GPIO extcon driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/extcon/extcon_class.c b/drivers/extcon/extcon_class.c
deleted file mode 100644
index f6419f9..0000000
--- a/drivers/extcon/extcon_class.c
+++ /dev/null
@@ -1,832 +0,0 @@
-/*
- *  drivers/extcon/extcon_class.c
- *
- *  External connector (extcon) class driver
- *
- * Copyright (C) 2012 Samsung Electronics
- * Author: Donggeun Kim <dg77.kim@samsung.com>
- * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
- *
- * based on android/drivers/switch/switch_class.c
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/err.h>
-#include <linux/extcon.h>
-#include <linux/slab.h>
-
-/*
- * extcon_cable_name suggests the standard cable names for commonly used
- * cable types.
- *
- * However, please do not use extcon_cable_name directly for extcon_dev
- * struct's supported_cable pointer unless your device really supports
- * every single port-type of the following cable names. Please choose cable
- * names that are actually used in your extcon device.
- */
-const char *extcon_cable_name[] = {
-	[EXTCON_USB]		= "USB",
-	[EXTCON_USB_HOST]	= "USB-Host",
-	[EXTCON_TA]		= "TA",
-	[EXTCON_FAST_CHARGER]	= "Fast-charger",
-	[EXTCON_SLOW_CHARGER]	= "Slow-charger",
-	[EXTCON_CHARGE_DOWNSTREAM]	= "Charge-downstream",
-	[EXTCON_HDMI]		= "HDMI",
-	[EXTCON_MHL]		= "MHL",
-	[EXTCON_DVI]		= "DVI",
-	[EXTCON_VGA]		= "VGA",
-	[EXTCON_DOCK]		= "Dock",
-	[EXTCON_LINE_IN]	= "Line-in",
-	[EXTCON_LINE_OUT]	= "Line-out",
-	[EXTCON_MIC_IN]		= "Microphone",
-	[EXTCON_HEADPHONE_OUT]	= "Headphone",
-	[EXTCON_SPDIF_IN]	= "SPDIF-in",
-	[EXTCON_SPDIF_OUT]	= "SPDIF-out",
-	[EXTCON_VIDEO_IN]	= "Video-in",
-	[EXTCON_VIDEO_OUT]	= "Video-out",
-	[EXTCON_MECHANICAL]	= "Mechanical",
-
-	NULL,
-};
-
-static struct class *extcon_class;
-#if defined(CONFIG_ANDROID)
-static struct class_compat *switch_class;
-#endif /* CONFIG_ANDROID */
-
-static LIST_HEAD(extcon_dev_list);
-static DEFINE_MUTEX(extcon_dev_list_lock);
-
-/**
- * check_mutually_exclusive - Check if new_state violates mutually_exclusive
- *			    condition.
- * @edev:	the extcon device
- * @new_state:	new cable attach status for @edev
- *
- * Returns 0 if nothing violates. Returns the index + 1 for the first
- * violated condition.
- */
-static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state)
-{
-	int i = 0;
-
-	if (!edev->mutually_exclusive)
-		return 0;
-
-	for (i = 0; edev->mutually_exclusive[i]; i++) {
-		int count = 0, j;
-		u32 correspondants = new_state & edev->mutually_exclusive[i];
-		u32 exp = 1;
-
-		for (j = 0; j < 32; j++) {
-			if (exp & correspondants)
-				count++;
-			if (count > 1)
-				return i + 1;
-			exp <<= 1;
-		}
-	}
-
-	return 0;
-}
-
-static ssize_t state_show(struct device *dev, struct device_attribute *attr,
-			  char *buf)
-{
-	int i, count = 0;
-	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
-
-	if (edev->print_state) {
-		int ret = edev->print_state(edev, buf);
-
-		if (ret >= 0)
-			return ret;
-		/* Use default if failed */
-	}
-
-	if (edev->max_supported == 0)
-		return sprintf(buf, "%u\n", edev->state);
-
-	for (i = 0; i < SUPPORTED_CABLE_MAX; i++) {
-		if (!edev->supported_cable[i])
-			break;
-		count += sprintf(buf + count, "%s=%d\n",
-				 edev->supported_cable[i],
-				 !!(edev->state & (1 << i)));
-	}
-
-	return count;
-}
-
-int extcon_set_state(struct extcon_dev *edev, u32 state);
-static ssize_t state_store(struct device *dev, struct device_attribute *attr,
-			   const char *buf, size_t count)
-{
-	u32 state;
-	ssize_t ret = 0;
-	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
-
-	ret = sscanf(buf, "0x%x", &state);
-	if (ret == 0)
-		ret = -EINVAL;
-	else
-		ret = extcon_set_state(edev, state);
-
-	if (ret < 0)
-		return ret;
-
-	return count;
-}
-
-static ssize_t name_show(struct device *dev, struct device_attribute *attr,
-		char *buf)
-{
-	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
-
-	/* Optional callback given by the user */
-	if (edev->print_name) {
-		int ret = edev->print_name(edev, buf);
-		if (ret >= 0)
-			return ret;
-	}
-
-	return sprintf(buf, "%s\n", dev_name(edev->dev));
-}
-
-static ssize_t cable_name_show(struct device *dev,
-			       struct device_attribute *attr, char *buf)
-{
-	struct extcon_cable *cable = container_of(attr, struct extcon_cable,
-						  attr_name);
-
-	return sprintf(buf, "%s\n",
-		       cable->edev->supported_cable[cable->cable_index]);
-}
-
-static ssize_t cable_state_show(struct device *dev,
-				struct device_attribute *attr, char *buf)
-{
-	struct extcon_cable *cable = container_of(attr, struct extcon_cable,
-						  attr_state);
-
-	return sprintf(buf, "%d\n",
-		       extcon_get_cable_state_(cable->edev,
-					       cable->cable_index));
-}
-
-static ssize_t cable_state_store(struct device *dev,
-				 struct device_attribute *attr, const char *buf,
-				 size_t count)
-{
-	struct extcon_cable *cable = container_of(attr, struct extcon_cable,
-						  attr_state);
-	int ret, state;
-
-	ret = sscanf(buf, "%d", &state);
-	if (ret == 0)
-		ret = -EINVAL;
-	else
-		ret = extcon_set_cable_state_(cable->edev, cable->cable_index,
-					      state);
-
-	if (ret < 0)
-		return ret;
-	return count;
-}
-
-/**
- * extcon_update_state() - Update the cable attach states of the extcon device
- *			only for the masked bits.
- * @edev:	the extcon device
- * @mask:	the bit mask to designate updated bits.
- * @state:	new cable attach status for @edev
- *
- * Changing the state sends uevent with environment variable containing
- * the name of extcon device (envp[0]) and the state output (envp[1]).
- * Tizen uses this format for extcon device to get events from ports.
- * Android uses this format as well.
- *
- * Note that the notifier provides which bits are changed in the state
- * variable with the val parameter (second) to the callback.
- */
-int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
-{
-	char name_buf[120];
-	char state_buf[120];
-	char *prop_buf;
-	char *envp[3];
-	int env_offset = 0;
-	int length;
-	unsigned long flags;
-
-	spin_lock_irqsave(&edev->lock, flags);
-
-	if (edev->state != ((edev->state & ~mask) | (state & mask))) {
-		u32 old_state = edev->state;
-
-		if (check_mutually_exclusive(edev, (edev->state & ~mask) |
-						   (state & mask))) {
-			spin_unlock_irqrestore(&edev->lock, flags);
-			return -EPERM;
-		}
-
-		edev->state &= ~mask;
-		edev->state |= state & mask;
-
-		raw_notifier_call_chain(&edev->nh, old_state, edev);
-
-		/* This could be in interrupt handler */
-		prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
-		if (prop_buf) {
-			length = name_show(edev->dev, NULL, prop_buf);
-			if (length > 0) {
-				if (prop_buf[length - 1] == '\n')
-					prop_buf[length - 1] = 0;
-				snprintf(name_buf, sizeof(name_buf),
-					"NAME=%s", prop_buf);
-				envp[env_offset++] = name_buf;
-			}
-			length = state_show(edev->dev, NULL, prop_buf);
-			if (length > 0) {
-				if (prop_buf[length - 1] == '\n')
-					prop_buf[length - 1] = 0;
-				snprintf(state_buf, sizeof(state_buf),
-					"STATE=%s", prop_buf);
-				envp[env_offset++] = state_buf;
-			}
-			envp[env_offset] = NULL;
-			/* Unlock early before uevent */
-			spin_unlock_irqrestore(&edev->lock, flags);
-
-			kobject_uevent_env(&edev->dev->kobj, KOBJ_CHANGE, envp);
-			free_page((unsigned long)prop_buf);
-		} else {
-			/* Unlock early before uevent */
-			spin_unlock_irqrestore(&edev->lock, flags);
-
-			dev_err(edev->dev, "out of memory in extcon_set_state\n");
-			kobject_uevent(&edev->dev->kobj, KOBJ_CHANGE);
-		}
-	} else {
-		/* No changes */
-		spin_unlock_irqrestore(&edev->lock, flags);
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(extcon_update_state);
-
-/**
- * extcon_set_state() - Set the cable attach states of the extcon device.
- * @edev:	the extcon device
- * @state:	new cable attach status for @edev
- *
- * Note that notifier provides which bits are changed in the state
- * variable with the val parameter (second) to the callback.
- */
-int extcon_set_state(struct extcon_dev *edev, u32 state)
-{
-	return extcon_update_state(edev, 0xffffffff, state);
-}
-EXPORT_SYMBOL_GPL(extcon_set_state);
-
-/**
- * extcon_find_cable_index() - Get the cable index based on the cable name.
- * @edev:	the extcon device that has the cable.
- * @cable_name:	cable name to be searched.
- *
- * Note that accessing a cable state based on cable_index is faster than
- * cable_name because using cable_name induces a loop with strncmp().
- * Thus, when get/set_cable_state is repeatedly used, using cable_index
- * is recommended.
- */
-int extcon_find_cable_index(struct extcon_dev *edev, const char *cable_name)
-{
-	int i;
-
-	if (edev->supported_cable) {
-		for (i = 0; edev->supported_cable[i]; i++) {
-			if (!strncmp(edev->supported_cable[i],
-				cable_name, CABLE_NAME_MAX))
-				return i;
-		}
-	}
-
-	return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(extcon_find_cable_index);
-
-/**
- * extcon_get_cable_state_() - Get the status of a specific cable.
- * @edev:	the extcon device that has the cable.
- * @index:	cable index that can be retrieved by extcon_find_cable_index().
- */
-int extcon_get_cable_state_(struct extcon_dev *edev, int index)
-{
-	if (index < 0 || (edev->max_supported && edev->max_supported <= index))
-		return -EINVAL;
-
-	return !!(edev->state & (1 << index));
-}
-EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
-
-/**
- * extcon_get_cable_state() - Get the status of a specific cable.
- * @edev:	the extcon device that has the cable.
- * @cable_name:	cable name.
- *
- * Note that this is slower than extcon_get_cable_state_.
- */
-int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
-{
-	return extcon_get_cable_state_(edev, extcon_find_cable_index
-						(edev, cable_name));
-}
-EXPORT_SYMBOL_GPL(extcon_get_cable_state);
-
-/**
- * extcon_get_cable_state_() - Set the status of a specific cable.
- * @edev:	the extcon device that has the cable.
- * @index:	cable index that can be retrieved by extcon_find_cable_index().
- * @cable_state:	the new cable status. The default semantics is
- *			true: attached / false: detached.
- */
-int extcon_set_cable_state_(struct extcon_dev *edev,
-			int index, bool cable_state)
-{
-	u32 state;
-
-	if (index < 0 || (edev->max_supported && edev->max_supported <= index))
-		return -EINVAL;
-
-	state = cable_state ? (1 << index) : 0;
-	return extcon_update_state(edev, 1 << index, state);
-}
-EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
-
-/**
- * extcon_get_cable_state() - Set the status of a specific cable.
- * @edev:	the extcon device that has the cable.
- * @cable_name:	cable name.
- * @cable_state:	the new cable status. The default semantics is
- *			true: attached / false: detached.
- *
- * Note that this is slower than extcon_set_cable_state_.
- */
-int extcon_set_cable_state(struct extcon_dev *edev,
-			const char *cable_name, bool cable_state)
-{
-	return extcon_set_cable_state_(edev, extcon_find_cable_index
-					(edev, cable_name), cable_state);
-}
-EXPORT_SYMBOL_GPL(extcon_set_cable_state);
-
-/**
- * extcon_get_extcon_dev() - Get the extcon device instance from the name
- * @extcon_name:	The extcon name provided with extcon_dev_register()
- */
-struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
-{
-	struct extcon_dev *sd;
-
-	mutex_lock(&extcon_dev_list_lock);
-	list_for_each_entry(sd, &extcon_dev_list, entry) {
-		if (!strcmp(sd->name, extcon_name))
-			goto out;
-	}
-	sd = NULL;
-out:
-	mutex_unlock(&extcon_dev_list_lock);
-	return sd;
-}
-EXPORT_SYMBOL_GPL(extcon_get_extcon_dev);
-
-static int _call_per_cable(struct notifier_block *nb, unsigned long val,
-			   void *ptr)
-{
-	struct extcon_specific_cable_nb *obj = container_of(nb,
-			struct extcon_specific_cable_nb, internal_nb);
-	struct extcon_dev *edev = ptr;
-
-	if ((val & (1 << obj->cable_index)) !=
-	    (edev->state & (1 << obj->cable_index))) {
-		bool cable_state = true;
-
-		obj->previous_value = val;
-
-		if (val & (1 << obj->cable_index))
-			cable_state = false;
-
-		return obj->user_nb->notifier_call(obj->user_nb,
-				cable_state, ptr);
-	}
-
-	return NOTIFY_OK;
-}
-
-/**
- * extcon_register_interest() - Register a notifier for a state change of a
- *			      specific cable, not a entier set of cables of a
- *			      extcon device.
- * @obj:	an empty extcon_specific_cable_nb object to be returned.
- * @extcon_name:	the name of extcon device.
- * @cable_name:		the target cable name.
- * @nb:		the notifier block to get notified.
- *
- * Provide an empty extcon_specific_cable_nb. extcon_register_interest() sets
- * the struct for you.
- *
- * extcon_register_interest is a helper function for those who want to get
- * notification for a single specific cable's status change. If a user wants
- * to get notification for any changes of all cables of a extcon device,
- * he/she should use the general extcon_register_notifier().
- *
- * Note that the second parameter given to the callback of nb (val) is
- * "old_state", not the current state. The current state can be retrieved
- * by looking at the third pameter (edev pointer)'s state value.
- */
-int extcon_register_interest(struct extcon_specific_cable_nb *obj,
-			     const char *extcon_name, const char *cable_name,
-			     struct notifier_block *nb)
-{
-	if (!obj || !extcon_name || !cable_name || !nb)
-		return -EINVAL;
-
-	obj->edev = extcon_get_extcon_dev(extcon_name);
-	if (!obj->edev)
-		return -ENODEV;
-
-	obj->cable_index = extcon_find_cable_index(obj->edev, cable_name);
-	if (obj->cable_index < 0)
-		return -ENODEV;
-
-	obj->user_nb = nb;
-
-	obj->internal_nb.notifier_call = _call_per_cable;
-
-	return raw_notifier_chain_register(&obj->edev->nh, &obj->internal_nb);
-}
-
-/**
- * extcon_unregister_interest() - Unregister the notifier registered by
- *				extcon_register_interest().
- * @obj:	the extcon_specific_cable_nb object returned by
- *		extcon_register_interest().
- */
-int extcon_unregister_interest(struct extcon_specific_cable_nb *obj)
-{
-	if (!obj)
-		return -EINVAL;
-
-	return raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb);
-}
-
-/**
- * extcon_register_notifier() - Register a notifee to get notified by
- *			      any attach status changes from the extcon.
- * @edev:	the extcon device.
- * @nb:		a notifier block to be registered.
- *
- * Note that the second parameter given to the callback of nb (val) is
- * "old_state", not the current state. The current state can be retrieved
- * by looking at the third pameter (edev pointer)'s state value.
- */
-int extcon_register_notifier(struct extcon_dev *edev,
-			struct notifier_block *nb)
-{
-	return raw_notifier_chain_register(&edev->nh, nb);
-}
-EXPORT_SYMBOL_GPL(extcon_register_notifier);
-
-/**
- * extcon_unregister_notifier() - Unregister a notifee from the extcon device.
- * @edev:	the extcon device.
- * @nb:		a registered notifier block to be unregistered.
- */
-int extcon_unregister_notifier(struct extcon_dev *edev,
-			struct notifier_block *nb)
-{
-	return raw_notifier_chain_unregister(&edev->nh, nb);
-}
-EXPORT_SYMBOL_GPL(extcon_unregister_notifier);
-
-static struct device_attribute extcon_attrs[] = {
-	__ATTR(state, S_IRUGO | S_IWUSR, state_show, state_store),
-	__ATTR_RO(name),
-	__ATTR_NULL,
-};
-
-static int create_extcon_class(void)
-{
-	if (!extcon_class) {
-		extcon_class = class_create(THIS_MODULE, "extcon");
-		if (IS_ERR(extcon_class))
-			return PTR_ERR(extcon_class);
-		extcon_class->dev_attrs = extcon_attrs;
-
-#if defined(CONFIG_ANDROID)
-		switch_class = class_compat_register("switch");
-		if (WARN(!switch_class, "cannot allocate"))
-			return -ENOMEM;
-#endif /* CONFIG_ANDROID */
-	}
-
-	return 0;
-}
-
-static void extcon_cleanup(struct extcon_dev *edev, bool skip)
-{
-	mutex_lock(&extcon_dev_list_lock);
-	list_del(&edev->entry);
-	mutex_unlock(&extcon_dev_list_lock);
-
-	if (!skip && get_device(edev->dev)) {
-		int index;
-
-		if (edev->mutually_exclusive && edev->max_supported) {
-			for (index = 0; edev->mutually_exclusive[index];
-			     index++)
-				kfree(edev->d_attrs_muex[index].attr.name);
-			kfree(edev->d_attrs_muex);
-			kfree(edev->attrs_muex);
-		}
-
-		for (index = 0; index < edev->max_supported; index++)
-			kfree(edev->cables[index].attr_g.name);
-
-		if (edev->max_supported) {
-			kfree(edev->extcon_dev_type.groups);
-			kfree(edev->cables);
-		}
-
-		device_unregister(edev->dev);
-		put_device(edev->dev);
-	}
-
-	kfree(edev->dev);
-}
-
-static void extcon_dev_release(struct device *dev)
-{
-	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
-
-	extcon_cleanup(edev, true);
-}
-
-static const char *muex_name = "mutually_exclusive";
-static void dummy_sysfs_dev_release(struct device *dev)
-{
-}
-
-/**
- * extcon_dev_register() - Register a new extcon device
- * @edev	: the new extcon device (should be allocated before calling)
- * @dev		: the parent device for this extcon device.
- *
- * Among the members of edev struct, please set the "user initializing data"
- * in any case and set the "optional callbacks" if required. However, please
- * do not set the values of "internal data", which are initialized by
- * this function.
- */
-int extcon_dev_register(struct extcon_dev *edev, struct device *dev)
-{
-	int ret, index = 0;
-
-	if (!extcon_class) {
-		ret = create_extcon_class();
-		if (ret < 0)
-			return ret;
-	}
-
-	if (edev->supported_cable) {
-		/* Get size of array */
-		for (index = 0; edev->supported_cable[index]; index++)
-			;
-		edev->max_supported = index;
-	} else {
-		edev->max_supported = 0;
-	}
-
-	if (index > SUPPORTED_CABLE_MAX) {
-		dev_err(edev->dev, "extcon: maximum number of supported cables exceeded.\n");
-		return -EINVAL;
-	}
-
-	edev->dev = kzalloc(sizeof(struct device), GFP_KERNEL);
-	if (!edev->dev)
-		return -ENOMEM;
-	edev->dev->parent = dev;
-	edev->dev->class = extcon_class;
-	edev->dev->release = extcon_dev_release;
-
-	dev_set_name(edev->dev, edev->name ? edev->name : dev_name(dev));
-
-	if (edev->max_supported) {
-		char buf[10];
-		char *str;
-		struct extcon_cable *cable;
-
-		edev->cables = kzalloc(sizeof(struct extcon_cable) *
-				       edev->max_supported, GFP_KERNEL);
-		if (!edev->cables) {
-			ret = -ENOMEM;
-			goto err_sysfs_alloc;
-		}
-		for (index = 0; index < edev->max_supported; index++) {
-			cable = &edev->cables[index];
-
-			snprintf(buf, 10, "cable.%d", index);
-			str = kzalloc(sizeof(char) * (strlen(buf) + 1),
-				      GFP_KERNEL);
-			if (!str) {
-				for (index--; index >= 0; index--) {
-					cable = &edev->cables[index];
-					kfree(cable->attr_g.name);
-				}
-				ret = -ENOMEM;
-
-				goto err_alloc_cables;
-			}
-			strcpy(str, buf);
-
-			cable->edev = edev;
-			cable->cable_index = index;
-			cable->attrs[0] = &cable->attr_name.attr;
-			cable->attrs[1] = &cable->attr_state.attr;
-			cable->attrs[2] = NULL;
-			cable->attr_g.name = str;
-			cable->attr_g.attrs = cable->attrs;
-
-			cable->attr_name.attr.name = "name";
-			cable->attr_name.attr.mode = 0444;
-			cable->attr_name.show = cable_name_show;
-
-			cable->attr_state.attr.name = "state";
-			cable->attr_state.attr.mode = 0644;
-			cable->attr_state.show = cable_state_show;
-			cable->attr_state.store = cable_state_store;
-		}
-	}
-
-	if (edev->max_supported && edev->mutually_exclusive) {
-		char buf[80];
-		char *name;
-
-		/* Count the size of mutually_exclusive array */
-		for (index = 0; edev->mutually_exclusive[index]; index++)
-			;
-
-		edev->attrs_muex = kzalloc(sizeof(struct attribute *) *
-					   (index + 1), GFP_KERNEL);
-		if (!edev->attrs_muex) {
-			ret = -ENOMEM;
-			goto err_muex;
-		}
-
-		edev->d_attrs_muex = kzalloc(sizeof(struct device_attribute) *
-					     index, GFP_KERNEL);
-		if (!edev->d_attrs_muex) {
-			ret = -ENOMEM;
-			kfree(edev->attrs_muex);
-			goto err_muex;
-		}
-
-		for (index = 0; edev->mutually_exclusive[index]; index++) {
-			sprintf(buf, "0x%x", edev->mutually_exclusive[index]);
-			name = kzalloc(sizeof(char) * (strlen(buf) + 1),
-				       GFP_KERNEL);
-			if (!name) {
-				for (index--; index >= 0; index--) {
-					kfree(edev->d_attrs_muex[index].attr.
-					      name);
-				}
-				kfree(edev->d_attrs_muex);
-				kfree(edev->attrs_muex);
-				ret = -ENOMEM;
-				goto err_muex;
-			}
-			strcpy(name, buf);
-			edev->d_attrs_muex[index].attr.name = name;
-			edev->d_attrs_muex[index].attr.mode = 0000;
-			edev->attrs_muex[index] = &edev->d_attrs_muex[index]
-							.attr;
-		}
-		edev->attr_g_muex.name = muex_name;
-		edev->attr_g_muex.attrs = edev->attrs_muex;
-
-	}
-
-	if (edev->max_supported) {
-		edev->extcon_dev_type.groups =
-			kzalloc(sizeof(struct attribute_group *) *
-				(edev->max_supported + 2), GFP_KERNEL);
-		if (!edev->extcon_dev_type.groups) {
-			ret = -ENOMEM;
-			goto err_alloc_groups;
-		}
-
-		edev->extcon_dev_type.name = dev_name(edev->dev);
-		edev->extcon_dev_type.release = dummy_sysfs_dev_release;
-
-		for (index = 0; index < edev->max_supported; index++)
-			edev->extcon_dev_type.groups[index] =
-				&edev->cables[index].attr_g;
-		if (edev->mutually_exclusive)
-			edev->extcon_dev_type.groups[index] =
-				&edev->attr_g_muex;
-
-		edev->dev->type = &edev->extcon_dev_type;
-	}
-
-	ret = device_register(edev->dev);
-	if (ret) {
-		put_device(edev->dev);
-		goto err_dev;
-	}
-#if defined(CONFIG_ANDROID)
-	if (switch_class)
-		ret = class_compat_create_link(switch_class, edev->dev,
-					       NULL);
-#endif /* CONFIG_ANDROID */
-
-	spin_lock_init(&edev->lock);
-
-	RAW_INIT_NOTIFIER_HEAD(&edev->nh);
-
-	dev_set_drvdata(edev->dev, edev);
-	edev->state = 0;
-
-	mutex_lock(&extcon_dev_list_lock);
-	list_add(&edev->entry, &extcon_dev_list);
-	mutex_unlock(&extcon_dev_list_lock);
-
-	return 0;
-
-err_dev:
-	if (edev->max_supported)
-		kfree(edev->extcon_dev_type.groups);
-err_alloc_groups:
-	if (edev->max_supported && edev->mutually_exclusive) {
-		for (index = 0; edev->mutually_exclusive[index]; index++)
-			kfree(edev->d_attrs_muex[index].attr.name);
-		kfree(edev->d_attrs_muex);
-		kfree(edev->attrs_muex);
-	}
-err_muex:
-	for (index = 0; index < edev->max_supported; index++)
-		kfree(edev->cables[index].attr_g.name);
-err_alloc_cables:
-	if (edev->max_supported)
-		kfree(edev->cables);
-err_sysfs_alloc:
-	kfree(edev->dev);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(extcon_dev_register);
-
-/**
- * extcon_dev_unregister() - Unregister the extcon device.
- * @edev:	the extcon device instance to be unregitered.
- *
- * Note that this does not call kfree(edev) because edev was not allocated
- * by this class.
- */
-void extcon_dev_unregister(struct extcon_dev *edev)
-{
-	extcon_cleanup(edev, false);
-}
-EXPORT_SYMBOL_GPL(extcon_dev_unregister);
-
-static int __init extcon_class_init(void)
-{
-	return create_extcon_class();
-}
-module_init(extcon_class_init);
-
-static void __exit extcon_class_exit(void)
-{
-	class_destroy(extcon_class);
-}
-module_exit(extcon_class_exit);
-
-MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
-MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
-MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
-MODULE_DESCRIPTION("External connector (extcon) class driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/extcon/extcon_gpio.c b/drivers/extcon/extcon_gpio.c
deleted file mode 100644
index fe3db45..0000000
--- a/drivers/extcon/extcon_gpio.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- *  drivers/extcon/extcon_gpio.c
- *
- *  Single-state GPIO extcon driver based on extcon class
- *
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * Modified by MyungJoo Ham <myungjoo.ham@samsung.com> to support extcon
- * (originally switch class is supported)
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/extcon.h>
-#include <linux/workqueue.h>
-#include <linux/gpio.h>
-#include <linux/extcon.h>
-#include <linux/extcon/extcon_gpio.h>
-
-struct gpio_extcon_data {
-	struct extcon_dev edev;
-	unsigned gpio;
-	const char *state_on;
-	const char *state_off;
-	int irq;
-	struct delayed_work work;
-	unsigned long debounce_jiffies;
-};
-
-static void gpio_extcon_work(struct work_struct *work)
-{
-	int state;
-	struct gpio_extcon_data	*data =
-		container_of(to_delayed_work(work), struct gpio_extcon_data,
-			     work);
-
-	state = gpio_get_value(data->gpio);
-	extcon_set_state(&data->edev, state);
-}
-
-static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
-{
-	struct gpio_extcon_data *extcon_data = dev_id;
-
-	schedule_delayed_work(&extcon_data->work,
-			      extcon_data->debounce_jiffies);
-	return IRQ_HANDLED;
-}
-
-static ssize_t extcon_gpio_print_state(struct extcon_dev *edev, char *buf)
-{
-	struct gpio_extcon_data	*extcon_data =
-		container_of(edev, struct gpio_extcon_data, edev);
-	const char *state;
-	if (extcon_get_state(edev))
-		state = extcon_data->state_on;
-	else
-		state = extcon_data->state_off;
-
-	if (state)
-		return sprintf(buf, "%s\n", state);
-	return -EINVAL;
-}
-
-static int __devinit gpio_extcon_probe(struct platform_device *pdev)
-{
-	struct gpio_extcon_platform_data *pdata = pdev->dev.platform_data;
-	struct gpio_extcon_data *extcon_data;
-	int ret = 0;
-
-	if (!pdata)
-		return -EBUSY;
-	if (!pdata->irq_flags) {
-		dev_err(&pdev->dev, "IRQ flag is not specified.\n");
-		return -EINVAL;
-	}
-
-	extcon_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data),
-				   GFP_KERNEL);
-	if (!extcon_data)
-		return -ENOMEM;
-
-	extcon_data->edev.name = pdata->name;
-	extcon_data->gpio = pdata->gpio;
-	extcon_data->state_on = pdata->state_on;
-	extcon_data->state_off = pdata->state_off;
-	if (pdata->state_on && pdata->state_off)
-		extcon_data->edev.print_state = extcon_gpio_print_state;
-	extcon_data->debounce_jiffies = msecs_to_jiffies(pdata->debounce);
-
-	ret = extcon_dev_register(&extcon_data->edev, &pdev->dev);
-	if (ret < 0)
-		return ret;
-
-	ret = gpio_request_one(extcon_data->gpio, GPIOF_DIR_IN, pdev->name);
-	if (ret < 0)
-		goto err;
-
-	INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work);
-
-	extcon_data->irq = gpio_to_irq(extcon_data->gpio);
-	if (extcon_data->irq < 0) {
-		ret = extcon_data->irq;
-		goto err;
-	}
-
-	ret = request_any_context_irq(extcon_data->irq, gpio_irq_handler,
-				      pdata->irq_flags, pdev->name,
-				      extcon_data);
-	if (ret < 0)
-		goto err;
-
-	platform_set_drvdata(pdev, extcon_data);
-	/* Perform initial detection */
-	gpio_extcon_work(&extcon_data->work.work);
-
-	return 0;
-
-err:
-	extcon_dev_unregister(&extcon_data->edev);
-
-	return ret;
-}
-
-static int __devexit gpio_extcon_remove(struct platform_device *pdev)
-{
-	struct gpio_extcon_data *extcon_data = platform_get_drvdata(pdev);
-
-	cancel_delayed_work_sync(&extcon_data->work);
-	free_irq(extcon_data->irq, extcon_data);
-	extcon_dev_unregister(&extcon_data->edev);
-
-	return 0;
-}
-
-static struct platform_driver gpio_extcon_driver = {
-	.probe		= gpio_extcon_probe,
-	.remove		= __devexit_p(gpio_extcon_remove),
-	.driver		= {
-		.name	= "extcon-gpio",
-		.owner	= THIS_MODULE,
-	},
-};
-
-module_platform_driver(gpio_extcon_driver);
-
-MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
-MODULE_DESCRIPTION("GPIO extcon driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index b298158..fd3ae62 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -16,6 +16,7 @@
  */
 static char dmi_empty_string[] = "        ";
 
+static u16 __initdata dmi_ver;
 /*
  * Catch too early calls to dmi_check_system():
  */
@@ -118,12 +119,12 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
 	return 0;
 }
 
-static int __init dmi_checksum(const u8 *buf)
+static int __init dmi_checksum(const u8 *buf, u8 len)
 {
 	u8 sum = 0;
 	int a;
 
-	for (a = 0; a < 15; a++)
+	for (a = 0; a < len; a++)
 		sum += buf[a];
 
 	return sum == 0;
@@ -161,8 +162,10 @@ static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int inde
 		return;
 
 	for (i = 0; i < 16 && (is_ff || is_00); i++) {
-		if(d[i] != 0x00) is_ff = 0;
-		if(d[i] != 0xFF) is_00 = 0;
+		if (d[i] != 0x00)
+			is_00 = 0;
+		if (d[i] != 0xFF)
+			is_ff = 0;
 	}
 
 	if (is_ff || is_00)
@@ -172,7 +175,15 @@ static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int inde
 	if (!s)
 		return;
 
-	sprintf(s, "%pUB", d);
+	/*
+	 * As of version 2.6 of the SMBIOS specification, the first 3 fields of
+	 * the UUID are supposed to be little-endian encoded.  The specification
+	 * says that this is the defacto standard.
+	 */
+	if (dmi_ver >= 0x0206)
+		sprintf(s, "%pUL", d);
+	else
+		sprintf(s, "%pUB", d);
 
         dmi_ident[slot] = s;
 }
@@ -404,29 +415,57 @@ static int __init dmi_present(const char __iomem *p)
 	u8 buf[15];
 
 	memcpy_fromio(buf, p, 15);
-	if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
+	if (dmi_checksum(buf, 15)) {
 		dmi_num = (buf[13] << 8) | buf[12];
 		dmi_len = (buf[7] << 8) | buf[6];
 		dmi_base = (buf[11] << 24) | (buf[10] << 16) |
 			(buf[9] << 8) | buf[8];
 
-		/*
-		 * DMI version 0.0 means that the real version is taken from
-		 * the SMBIOS version, which we don't know at this point.
-		 */
-		if (buf[14] != 0)
-			printk(KERN_INFO "DMI %d.%d present.\n",
-			       buf[14] >> 4, buf[14] & 0xF);
-		else
-			printk(KERN_INFO "DMI present.\n");
 		if (dmi_walk_early(dmi_decode) == 0) {
+			if (dmi_ver)
+				pr_info("SMBIOS %d.%d present.\n",
+				       dmi_ver >> 8, dmi_ver & 0xFF);
+			else {
+				dmi_ver = (buf[14] & 0xF0) << 4 |
+					   (buf[14] & 0x0F);
+				pr_info("Legacy DMI %d.%d present.\n",
+				       dmi_ver >> 8, dmi_ver & 0xFF);
+			}
 			dmi_dump_ids();
 			return 0;
 		}
 	}
+	dmi_ver = 0;
 	return 1;
 }
 
+static int __init smbios_present(const char __iomem *p)
+{
+	u8 buf[32];
+	int offset = 0;
+
+	memcpy_fromio(buf, p, 32);
+	if ((buf[5] < 32) && dmi_checksum(buf, buf[5])) {
+		dmi_ver = (buf[6] << 8) + buf[7];
+
+		/* Some BIOS report weird SMBIOS version, fix that up */
+		switch (dmi_ver) {
+		case 0x021F:
+		case 0x0221:
+			pr_debug("SMBIOS version fixup(2.%d->2.%d)\n",
+			       dmi_ver & 0xFF, 3);
+			dmi_ver = 0x0203;
+			break;
+		case 0x0233:
+			pr_debug("SMBIOS version fixup(2.%d->2.%d)\n", 51, 6);
+			dmi_ver = 0x0206;
+			break;
+		}
+		offset = 16;
+	}
+	return dmi_present(buf + offset);
+}
+
 void __init dmi_scan_machine(void)
 {
 	char __iomem *p, *q;
@@ -444,7 +483,7 @@ void __init dmi_scan_machine(void)
 		if (p == NULL)
 			goto error;
 
-		rc = dmi_present(p + 0x10); /* offset of _DMI_ string */
+		rc = smbios_present(p);
 		dmi_iounmap(p, 32);
 		if (!rc) {
 			dmi_available = 1;
@@ -462,7 +501,12 @@ void __init dmi_scan_machine(void)
 			goto error;
 
 		for (q = p; q < p + 0x10000; q += 16) {
-			rc = dmi_present(q);
+			if (memcmp(q, "_SM_", 4) == 0 && q - p <= 0xFFE0)
+				rc = smbios_present(q);
+			else if (memcmp(q, "_DMI_", 5) == 0)
+				rc = dmi_present(q);
+			else
+				continue;
 			if (!rc) {
 				dmi_available = 1;
 				dmi_iounmap(p, 0x10000);
diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c
index db01f15..6a29ee1 100644
--- a/drivers/gpio/gpio-ml-ioh.c
+++ b/drivers/gpio/gpio-ml-ioh.c
@@ -87,8 +87,7 @@ struct ioh_gpio_reg_data {
  * @gpio_use_sel:		Save GPIO_USE_SEL1~4 register for PM
  * @ch:				Indicate GPIO channel
  * @irq_base:		Save base of IRQ number for interrupt
- * @spinlock:		Used for register access protection in
- *				interrupt context ioh_irq_type and PM;
+ * @spinlock:		Used for register access protection
  */
 struct ioh_gpio {
 	void __iomem *base;
@@ -97,7 +96,6 @@ struct ioh_gpio {
 	struct gpio_chip gpio;
 	struct ioh_gpio_reg_data ioh_gpio_reg;
 	u32 gpio_use_sel;
-	struct mutex lock;
 	int ch;
 	int irq_base;
 	spinlock_t spinlock;
@@ -109,8 +107,9 @@ static void ioh_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
 {
 	u32 reg_val;
 	struct ioh_gpio *chip =	container_of(gpio, struct ioh_gpio, gpio);
+	unsigned long flags;
 
-	mutex_lock(&chip->lock);
+	spin_lock_irqsave(&chip->spinlock, flags);
 	reg_val = ioread32(&chip->reg->regs[chip->ch].po);
 	if (val)
 		reg_val |= (1 << nr);
@@ -118,7 +117,7 @@ static void ioh_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
 		reg_val &= ~(1 << nr);
 
 	iowrite32(reg_val, &chip->reg->regs[chip->ch].po);
-	mutex_unlock(&chip->lock);
+	spin_unlock_irqrestore(&chip->spinlock, flags);
 }
 
 static int ioh_gpio_get(struct gpio_chip *gpio, unsigned nr)
@@ -134,8 +133,9 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
 	struct ioh_gpio *chip =	container_of(gpio, struct ioh_gpio, gpio);
 	u32 pm;
 	u32 reg_val;
+	unsigned long flags;
 
-	mutex_lock(&chip->lock);
+	spin_lock_irqsave(&chip->spinlock, flags);
 	pm = ioread32(&chip->reg->regs[chip->ch].pm) &
 					((1 << num_ports[chip->ch]) - 1);
 	pm |= (1 << nr);
@@ -148,7 +148,7 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
 		reg_val &= ~(1 << nr);
 	iowrite32(reg_val, &chip->reg->regs[chip->ch].po);
 
-	mutex_unlock(&chip->lock);
+	spin_unlock_irqrestore(&chip->spinlock, flags);
 
 	return 0;
 }
@@ -157,13 +157,14 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
 {
 	struct ioh_gpio *chip =	container_of(gpio, struct ioh_gpio, gpio);
 	u32 pm;
+	unsigned long flags;
 
-	mutex_lock(&chip->lock);
+	spin_lock_irqsave(&chip->spinlock, flags);
 	pm = ioread32(&chip->reg->regs[chip->ch].pm) &
 				((1 << num_ports[chip->ch]) - 1);
 	pm &= ~(1 << nr);
 	iowrite32(pm, &chip->reg->regs[chip->ch].pm);
-	mutex_unlock(&chip->lock);
+	spin_unlock_irqrestore(&chip->spinlock, flags);
 
 	return 0;
 }
@@ -447,7 +448,6 @@ static int __devinit ioh_gpio_probe(struct pci_dev *pdev,
 		chip->base = base;
 		chip->reg = chip->base;
 		chip->ch = i;
-		mutex_init(&chip->lock);
 		spin_lock_init(&chip->spinlock);
 		ioh_gpio_setup(chip, num_ports[i]);
 		ret = gpiochip_add(&chip->gpio);
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
index 5a1817e..9ae29cc 100644
--- a/drivers/gpio/gpio-mpc8xxx.c
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -38,7 +38,7 @@ struct mpc8xxx_gpio_chip {
 	 */
 	u32 data;
 	struct irq_domain *irq;
-	void *of_dev_id_data;
+	const void *of_dev_id_data;
 };
 
 static inline u32 mpc8xxx_gpio2mask(unsigned int gpio)
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index e6efd77..0725d18 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -1058,7 +1058,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct device_node *node = dev->of_node;
 	const struct of_device_id *match;
-	struct omap_gpio_platform_data *pdata;
+	const struct omap_gpio_platform_data *pdata;
 	struct resource *res;
 	struct gpio_bank *bank;
 	int ret = 0;
@@ -1440,19 +1440,19 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = {
 	.fallingdetect =	OMAP4_GPIO_FALLINGDETECT,
 };
 
-static struct omap_gpio_platform_data omap2_pdata = {
+const static struct omap_gpio_platform_data omap2_pdata = {
 	.regs = &omap2_gpio_regs,
 	.bank_width = 32,
 	.dbck_flag = false,
 };
 
-static struct omap_gpio_platform_data omap3_pdata = {
+const static struct omap_gpio_platform_data omap3_pdata = {
 	.regs = &omap2_gpio_regs,
 	.bank_width = 32,
 	.dbck_flag = true,
 };
 
-static struct omap_gpio_platform_data omap4_pdata = {
+const static struct omap_gpio_platform_data omap4_pdata = {
 	.regs = &omap4_gpio_regs,
 	.bank_width = 32,
 	.dbck_flag = true,
diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c
index 139ad3e..4ad0c4f 100644
--- a/drivers/gpio/gpio-pch.c
+++ b/drivers/gpio/gpio-pch.c
@@ -92,9 +92,7 @@ struct pch_gpio_reg_data {
  * @lock:			Used for register access protection
  * @irq_base:		Save base of IRQ number for interrupt
  * @ioh:		IOH ID
- * @spinlock:		Used for register access protection in
- *				interrupt context pch_irq_mask,
- *				pch_irq_unmask and pch_irq_type;
+ * @spinlock:		Used for register access protection
  */
 struct pch_gpio {
 	void __iomem *base;
@@ -102,7 +100,6 @@ struct pch_gpio {
 	struct device *dev;
 	struct gpio_chip gpio;
 	struct pch_gpio_reg_data pch_gpio_reg;
-	struct mutex lock;
 	int irq_base;
 	enum pch_type_t ioh;
 	spinlock_t spinlock;
@@ -112,8 +109,9 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
 {
 	u32 reg_val;
 	struct pch_gpio *chip =	container_of(gpio, struct pch_gpio, gpio);
+	unsigned long flags;
 
-	mutex_lock(&chip->lock);
+	spin_lock_irqsave(&chip->spinlock, flags);
 	reg_val = ioread32(&chip->reg->po);
 	if (val)
 		reg_val |= (1 << nr);
@@ -121,7 +119,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
 		reg_val &= ~(1 << nr);
 
 	iowrite32(reg_val, &chip->reg->po);
-	mutex_unlock(&chip->lock);
+	spin_unlock_irqrestore(&chip->spinlock, flags);
 }
 
 static int pch_gpio_get(struct gpio_chip *gpio, unsigned nr)
@@ -137,8 +135,9 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
 	struct pch_gpio *chip =	container_of(gpio, struct pch_gpio, gpio);
 	u32 pm;
 	u32 reg_val;
+	unsigned long flags;
 
-	mutex_lock(&chip->lock);
+	spin_lock_irqsave(&chip->spinlock, flags);
 	pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1);
 	pm |= (1 << nr);
 	iowrite32(pm, &chip->reg->pm);
@@ -149,8 +148,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
 	else
 		reg_val &= ~(1 << nr);
 	iowrite32(reg_val, &chip->reg->po);
-
-	mutex_unlock(&chip->lock);
+	spin_unlock_irqrestore(&chip->spinlock, flags);
 
 	return 0;
 }
@@ -159,12 +157,13 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
 {
 	struct pch_gpio *chip =	container_of(gpio, struct pch_gpio, gpio);
 	u32 pm;
+	unsigned long flags;
 
-	mutex_lock(&chip->lock);
+	spin_lock_irqsave(&chip->spinlock, flags);
 	pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1);
 	pm &= ~(1 << nr);
 	iowrite32(pm, &chip->reg->pm);
-	mutex_unlock(&chip->lock);
+	spin_unlock_irqrestore(&chip->spinlock, flags);
 
 	return 0;
 }
@@ -387,7 +386,6 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev,
 
 	chip->reg = chip->base;
 	pci_set_drvdata(pdev, chip);
-	mutex_init(&chip->lock);
 	spin_lock_init(&chip->spinlock);
 	pch_gpio_setup(chip);
 	ret = gpiochip_add(&chip->gpio);
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index 9cac88a..9528779 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -26,6 +26,8 @@
 #include <linux/syscore_ops.h>
 #include <linux/slab.h>
 
+#include <asm/mach/irq.h>
+
 #include <mach/irqs.h>
 
 /*
@@ -59,6 +61,7 @@
 #define BANK_OFF(n)	(((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2))
 
 int pxa_last_gpio;
+static int irq_base;
 
 #ifdef CONFIG_OF
 static struct irq_domain *domain;
@@ -167,63 +170,14 @@ static inline int __gpio_is_occupied(unsigned gpio)
 	return ret;
 }
 
-#ifdef CONFIG_ARCH_PXA
-static inline int __pxa_gpio_to_irq(int gpio)
-{
-	if (gpio_is_pxa_type(gpio_type))
-		return PXA_GPIO_TO_IRQ(gpio);
-	return -1;
-}
-
-static inline int __pxa_irq_to_gpio(int irq)
-{
-	if (gpio_is_pxa_type(gpio_type))
-		return irq - PXA_GPIO_TO_IRQ(0);
-	return -1;
-}
-#else
-static inline int __pxa_gpio_to_irq(int gpio) { return -1; }
-static inline int __pxa_irq_to_gpio(int irq) { return -1; }
-#endif
-
-#ifdef CONFIG_ARCH_MMP
-static inline int __mmp_gpio_to_irq(int gpio)
-{
-	if (gpio_is_mmp_type(gpio_type))
-		return MMP_GPIO_TO_IRQ(gpio);
-	return -1;
-}
-
-static inline int __mmp_irq_to_gpio(int irq)
-{
-	if (gpio_is_mmp_type(gpio_type))
-		return irq - MMP_GPIO_TO_IRQ(0);
-	return -1;
-}
-#else
-static inline int __mmp_gpio_to_irq(int gpio) { return -1; }
-static inline int __mmp_irq_to_gpio(int irq) { return -1; }
-#endif
-
 static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	int gpio, ret;
-
-	gpio = chip->base + offset;
-	ret = __pxa_gpio_to_irq(gpio);
-	if (ret >= 0)
-		return ret;
-	return __mmp_gpio_to_irq(gpio);
+	return chip->base + offset + irq_base;
 }
 
 int pxa_irq_to_gpio(int irq)
 {
-	int ret;
-
-	ret = __pxa_irq_to_gpio(irq);
-	if (ret >= 0)
-		return ret;
-	return __mmp_irq_to_gpio(irq);
+	return irq - irq_base;
 }
 
 static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
@@ -403,6 +357,9 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
 	struct pxa_gpio_chip *c;
 	int loop, gpio, gpio_base, n;
 	unsigned long gedr;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	chained_irq_enter(chip, desc);
 
 	do {
 		loop = 0;
@@ -422,6 +379,8 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
 			}
 		}
 	} while (loop);
+
+	chained_irq_exit(chip, desc);
 }
 
 static void pxa_ack_muxed_gpio(struct irq_data *d)
@@ -535,7 +494,7 @@ const struct irq_domain_ops pxa_irq_domain_ops = {
 
 static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev)
 {
-	int ret, nr_banks, nr_gpios, irq_base;
+	int ret, nr_banks, nr_gpios;
 	struct device_node *prev, *next, *np = pdev->dev.of_node;
 	const struct of_device_id *of_id =
 				of_match_device(pxa_gpio_dt_ids, &pdev->dev);
@@ -590,10 +549,20 @@ static int __devinit pxa_gpio_probe(struct platform_device *pdev)
 	int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0;
 
 	ret = pxa_gpio_probe_dt(pdev);
-	if (ret < 0)
+	if (ret < 0) {
 		pxa_last_gpio = pxa_gpio_nums();
-	else
+#ifdef CONFIG_ARCH_PXA
+		if (gpio_is_pxa_type(gpio_type))
+			irq_base = PXA_GPIO_TO_IRQ(0);
+#endif
+#ifdef CONFIG_ARCH_MMP
+		if (gpio_is_mmp_type(gpio_type))
+			irq_base = MMP_GPIO_TO_IRQ(0);
+#endif
+	} else {
 		use_of = 1;
+	}
+
 	if (!pxa_last_gpio)
 		return -EINVAL;
 
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index a18c4aa..f1a4599 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -82,7 +82,7 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname,
 	gpiochip_find(&gg_data, of_gpiochip_find_and_xlate);
 
 	of_node_put(gg_data.gpiospec.np);
-	pr_debug("%s exited with status %d\n", __func__, ret);
+	pr_debug("%s exited with status %d\n", __func__, gg_data.out_gpio);
 	return gg_data.out_gpio;
 }
 EXPORT_SYMBOL(of_get_named_gpio_flags);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index de0213c..5d6c71e 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1773,56 +1773,102 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 	}
 }
 
-static int gpiolib_show(struct seq_file *s, void *unused)
+static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos)
 {
-	struct gpio_chip	*chip = NULL;
-	unsigned		gpio;
-	int			started = 0;
+	struct gpio_chip *chip = NULL;
+	unsigned int gpio;
+	void *ret = NULL;
+	loff_t index = 0;
 
 	/* REVISIT this isn't locked against gpio_chip removal ... */
 
 	for (gpio = 0; gpio_is_valid(gpio); gpio++) {
-		struct device *dev;
-
-		if (chip == gpio_desc[gpio].chip)
+		if (gpio_desc[gpio].chip == chip)
 			continue;
+
 		chip = gpio_desc[gpio].chip;
 		if (!chip)
 			continue;
 
-		seq_printf(s, "%sGPIOs %d-%d",
-				started ? "\n" : "",
-				chip->base, chip->base + chip->ngpio - 1);
-		dev = chip->dev;
-		if (dev)
-			seq_printf(s, ", %s/%s",
-				dev->bus ? dev->bus->name : "no-bus",
-				dev_name(dev));
-		if (chip->label)
-			seq_printf(s, ", %s", chip->label);
-		if (chip->can_sleep)
-			seq_printf(s, ", can sleep");
-		seq_printf(s, ":\n");
-
-		started = 1;
-		if (chip->dbg_show)
-			chip->dbg_show(s, chip);
-		else
-			gpiolib_dbg_show(s, chip);
+		if (index++ >= *pos) {
+			ret = chip;
+			break;
+		}
 	}
+
+	s->private = "";
+
+	return ret;
+}
+
+static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+	struct gpio_chip *chip = v;
+	unsigned int gpio;
+	void *ret = NULL;
+
+	/* skip GPIOs provided by the current chip */
+	for (gpio = chip->base + chip->ngpio; gpio_is_valid(gpio); gpio++) {
+		chip = gpio_desc[gpio].chip;
+		if (chip) {
+			ret = chip;
+			break;
+		}
+	}
+
+	s->private = "\n";
+	++*pos;
+
+	return ret;
+}
+
+static void gpiolib_seq_stop(struct seq_file *s, void *v)
+{
+}
+
+static int gpiolib_seq_show(struct seq_file *s, void *v)
+{
+	struct gpio_chip *chip = v;
+	struct device *dev;
+
+	seq_printf(s, "%sGPIOs %d-%d", (char *)s->private,
+			chip->base, chip->base + chip->ngpio - 1);
+	dev = chip->dev;
+	if (dev)
+		seq_printf(s, ", %s/%s", dev->bus ? dev->bus->name : "no-bus",
+			dev_name(dev));
+	if (chip->label)
+		seq_printf(s, ", %s", chip->label);
+	if (chip->can_sleep)
+		seq_printf(s, ", can sleep");
+	seq_printf(s, ":\n");
+
+	if (chip->dbg_show)
+		chip->dbg_show(s, chip);
+	else
+		gpiolib_dbg_show(s, chip);
+
 	return 0;
 }
 
+static const struct seq_operations gpiolib_seq_ops = {
+	.start = gpiolib_seq_start,
+	.next = gpiolib_seq_next,
+	.stop = gpiolib_seq_stop,
+	.show = gpiolib_seq_show,
+};
+
 static int gpiolib_open(struct inode *inode, struct file *file)
 {
-	return single_open(file, gpiolib_show, NULL);
+	return seq_open(file, &gpiolib_seq_ops);
 }
 
 static const struct file_operations gpiolib_operations = {
+	.owner		= THIS_MODULE,
 	.open		= gpiolib_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
-	.release	= single_release,
+	.release	= seq_release,
 };
 
 static int __init gpiolib_debugfs_init(void)
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index fbe0842..611c99d 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -706,7 +706,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
 		goto out_unlock;
 	}
 
-	vma->vm_flags |= VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND;
+	vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
 	vma->vm_ops = obj->dev->driver->gem_vm_ops;
 	vma->vm_private_data = map->handle;
 	vma->vm_page_prot =  pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c
index 961ee08..0b2f54d 100644
--- a/drivers/gpu/drm/drm_vm.c
+++ b/drivers/gpu/drm/drm_vm.c
@@ -514,8 +514,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
 
 	vma->vm_ops = &drm_vm_dma_ops;
 
-	vma->vm_flags |= VM_RESERVED;	/* Don't swap */
-	vma->vm_flags |= VM_DONTEXPAND;
+	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
 
 	drm_vm_open_locked(dev, vma);
 	return 0;
@@ -652,21 +651,16 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
 	case _DRM_SHM:
 		vma->vm_ops = &drm_vm_shm_ops;
 		vma->vm_private_data = (void *)map;
-		/* Don't let this area swap.  Change when
-		   DRM_KERNEL advisory is supported. */
-		vma->vm_flags |= VM_RESERVED;
 		break;
 	case _DRM_SCATTER_GATHER:
 		vma->vm_ops = &drm_vm_sg_ops;
 		vma->vm_private_data = (void *)map;
-		vma->vm_flags |= VM_RESERVED;
 		vma->vm_page_prot = drm_dma_prot(map->type, vma);
 		break;
 	default:
 		return -EINVAL;	/* This should never happen. */
 	}
-	vma->vm_flags |= VM_RESERVED;	/* Don't swap */
-	vma->vm_flags |= VM_DONTEXPAND;
+	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
 
 	drm_vm_open_locked(dev, vma);
 	return 0;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index a68d2b3..24c0bd4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -19,8 +19,8 @@
 #include <linux/clk.h>
 #include <linux/pm_runtime.h>
 
+#include <video/samsung_fimd.h>
 #include <drm/exynos_drm.h>
-#include <plat/regs-fb-v4.h>
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_fbdev.h"
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index f9efde4..c9a1637 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -501,7 +501,7 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
-	vma->vm_flags |= (VM_IO | VM_RESERVED);
+	vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
 
 	update_vm_cache_attr(exynos_gem_obj, vma);
 
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index 5732b57..1c60632 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -178,8 +178,7 @@ static int psbfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 	 */
 	vma->vm_ops = &psbfb_vm_ops;
 	vma->vm_private_data = (void *)psbfb;
-	vma->vm_flags |= VM_RESERVED | VM_IO |
-					VM_MIXEDMAP | VM_DONTEXPAND;
+	vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index a877813..3ba72db 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -285,7 +285,7 @@ int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma,
 	 */
 
 	vma->vm_private_data = bo;
-	vma->vm_flags |= VM_RESERVED | VM_IO | VM_MIXEDMAP | VM_DONTEXPAND;
+	vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP;
 	return 0;
 out_unref:
 	ttm_bo_unref(&bo);
@@ -300,7 +300,7 @@ int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
 
 	vma->vm_ops = &ttm_bo_vm_ops;
 	vma->vm_private_data = ttm_bo_reference(bo);
-	vma->vm_flags |= VM_RESERVED | VM_IO | VM_MIXEDMAP | VM_DONTEXPAND;
+	vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND;
 	return 0;
 }
 EXPORT_SYMBOL(ttm_fbdev_mmap);
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
index ce9a611..0ac95a9 100644
--- a/drivers/gpu/drm/udl/udl_fb.c
+++ b/drivers/gpu/drm/udl/udl_fb.c
@@ -243,7 +243,7 @@ static int udl_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 			size = 0;
 	}
 
-	vma->vm_flags |= VM_RESERVED;	/* avoid to swap out this VMA */
+	/* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
 	return 0;
 }
 
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index fbf4950..a451cdb 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -527,6 +527,14 @@ config HID_PICOLCD_LEDS
 	---help---
 	  Provide access to PicoLCD's GPO pins via leds class.
 
+config HID_PICOLCD_CIR
+	bool "CIR via RC class" if EXPERT
+	default !EXPERT
+	depends on HID_PICOLCD
+	depends on HID_PICOLCD=RC_CORE || RC_CORE=y
+	---help---
+	  Provide access to PicoLCD's CIR interface via remote control (LIRC).
+
 config HID_PRIMAX
 	tristate "Primax non-fully HID-compliant devices"
 	depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index f975485..3684750 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -69,6 +69,26 @@ obj-$(CONFIG_HID_PRODIKEYS)	+= hid-prodikeys.o
 obj-$(CONFIG_HID_PANTHERLORD)	+= hid-pl.o
 obj-$(CONFIG_HID_PETALYNX)	+= hid-petalynx.o
 obj-$(CONFIG_HID_PICOLCD)	+= hid-picolcd.o
+hid-picolcd-y			+= hid-picolcd_core.o
+ifdef CONFIG_HID_PICOLCD_FB
+hid-picolcd-y			+= hid-picolcd_fb.o
+endif
+ifdef CONFIG_HID_PICOLCD_BACKLIGHT
+hid-picolcd-y			+= hid-picolcd_backlight.o
+endif
+ifdef CONFIG_HID_PICOLCD_LCD
+hid-picolcd-y			+= hid-picolcd_lcd.o
+endif
+ifdef CONFIG_HID_PICOLCD_LEDS
+hid-picolcd-y			+= hid-picolcd_leds.o
+endif
+ifdef CONFIG_HID_PICOLCD_CIR
+hid-picolcd-y			+= hid-picolcd_cir.o
+endif
+ifdef CONFIG_DEBUG_FS
+hid-picolcd-y			+= hid-picolcd_debugfs.o
+endif
+
 obj-$(CONFIG_HID_PRIMAX)	+= hid-primax.o
 obj-$(CONFIG_HID_ROCCAT)	+= hid-roccat.o hid-roccat-common.o \
 	hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 60ea284..2b9dd76 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -374,7 +374,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
 
 	case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
 		parser->global.report_size = item_udata(item);
-		if (parser->global.report_size > 96) {
+		if (parser->global.report_size > 128) {
 			hid_err(parser->device, "invalid report_size %d\n",
 					parser->global.report_size);
 			return -1;
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 1dcb76f..2fb6605 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -269,7 +269,11 @@
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA	0x72fa
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302	0x7302
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349	0x7349
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7	0x73f7
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001	0xa001
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224      0x7224
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0      0x72d0
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4      0x72c4
 
 #define USB_VENDOR_ID_ELECOM		0x056e
 #define USB_DEVICE_ID_ELECOM_BM084	0x0061
@@ -296,6 +300,9 @@
 #define USB_VENDOR_ID_EZKEY		0x0518
 #define USB_DEVICE_ID_BTC_8193		0x0002
 
+#define USB_VENDOR_ID_FREESCALE		0x15A2
+#define USB_DEVICE_ID_FREESCALE_MX28	0x004F
+
 #define USB_VENDOR_ID_FRUCTEL	0x25B6
 #define USB_DEVICE_ID_GAMETEL_MT_MODE	0x0002
 
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 59c8b5c..e170112 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -691,12 +691,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 	struct mt_device *td;
 	struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
 
-	if (id) {
-		for (i = 0; mt_classes[i].name ; i++) {
-			if (id->driver_data == mt_classes[i].name) {
-				mtclass = &(mt_classes[i]);
-				break;
-			}
+	for (i = 0; mt_classes[i].name ; i++) {
+		if (id->driver_data == mt_classes[i].name) {
+			mtclass = &(mt_classes[i]);
+			break;
 		}
 	}
 
@@ -767,6 +765,32 @@ static int mt_reset_resume(struct hid_device *hdev)
 	mt_set_input_mode(hdev);
 	return 0;
 }
+
+static int mt_resume(struct hid_device *hdev)
+{
+	struct usb_interface *intf;
+	struct usb_host_interface *interface;
+	struct usb_device *dev;
+
+	if (hdev->bus != BUS_USB)
+		return 0;
+
+	intf = to_usb_interface(hdev->dev.parent);
+	interface = intf->cur_altsetting;
+	dev = hid_to_usb_dev(hdev);
+
+	/* Some Elan legacy devices require SET_IDLE to be set on resume.
+	 * It should be safe to send it to other devices too.
+	 * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */
+
+	usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+			HID_REQ_SET_IDLE,
+			USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			0, interface->desc.bInterfaceNumber,
+			NULL, 0, USB_CTRL_SET_TIMEOUT);
+
+	return 0;
+}
 #endif
 
 static void mt_remove(struct hid_device *hdev)
@@ -885,7 +909,19 @@ static const struct hid_device_id mt_devices[] = {
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349) },
 	{ .driver_data = MT_CLS_EGALAX_SERIAL,
 		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
+			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7) },
+	{ .driver_data = MT_CLS_EGALAX_SERIAL,
+		MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
 			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
+	{ .driver_data = MT_CLS_EGALAX,
+		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) },
+	{ .driver_data = MT_CLS_EGALAX,
+		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0) },
+	{ .driver_data = MT_CLS_EGALAX,
+		HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+			USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4) },
 
 	/* Elo TouchSystems IntelliTouch Plus panel */
 	{ .driver_data = MT_CLS_DUAL_NSMU_CONTACTID,
@@ -1092,6 +1128,7 @@ static struct hid_driver mt_driver = {
 	.event = mt_event,
 #ifdef CONFIG_PM
 	.reset_resume = mt_reset_resume,
+	.resume = mt_resume,
 #endif
 };
 
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c
deleted file mode 100644
index 27c8ebd..0000000
--- a/drivers/hid/hid-picolcd.c
+++ /dev/null
@@ -1,2748 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2010 by Bruno Prémont <bonbons@linux-vserver.org>       *
- *                                                                         *
- *   Based on Logitech G13 driver (v0.4)                                   *
- *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
- *                                                                         *
- *   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, version 2 of the License.               *
- *                                                                         *
- *   This driver is distributed in the hope that it will be useful, but    *
- *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
- *   General Public License for more details.                              *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
- ***************************************************************************/
-
-#include <linux/hid.h>
-#include <linux/hid-debug.h>
-#include <linux/input.h>
-#include "hid-ids.h"
-#include "usbhid/usbhid.h"
-#include <linux/usb.h>
-
-#include <linux/fb.h>
-#include <linux/vmalloc.h>
-#include <linux/backlight.h>
-#include <linux/lcd.h>
-
-#include <linux/leds.h>
-
-#include <linux/seq_file.h>
-#include <linux/debugfs.h>
-
-#include <linux/completion.h>
-#include <linux/uaccess.h>
-#include <linux/module.h>
-
-#define PICOLCD_NAME "PicoLCD (graphic)"
-
-/* Report numbers */
-#define REPORT_ERROR_CODE      0x10 /* LCD: IN[16]  */
-#define   ERR_SUCCESS            0x00
-#define   ERR_PARAMETER_MISSING  0x01
-#define   ERR_DATA_MISSING       0x02
-#define   ERR_BLOCK_READ_ONLY    0x03
-#define   ERR_BLOCK_NOT_ERASABLE 0x04
-#define   ERR_BLOCK_TOO_BIG      0x05
-#define   ERR_SECTION_OVERFLOW   0x06
-#define   ERR_INVALID_CMD_LEN    0x07
-#define   ERR_INVALID_DATA_LEN   0x08
-#define REPORT_KEY_STATE       0x11 /* LCD: IN[2]   */
-#define REPORT_IR_DATA         0x21 /* LCD: IN[63]  */
-#define REPORT_EE_DATA         0x32 /* LCD: IN[63]  */
-#define REPORT_MEMORY          0x41 /* LCD: IN[63]  */
-#define REPORT_LED_STATE       0x81 /* LCD: OUT[1]  */
-#define REPORT_BRIGHTNESS      0x91 /* LCD: OUT[1]  */
-#define REPORT_CONTRAST        0x92 /* LCD: OUT[1]  */
-#define REPORT_RESET           0x93 /* LCD: OUT[2]  */
-#define REPORT_LCD_CMD         0x94 /* LCD: OUT[63] */
-#define REPORT_LCD_DATA        0x95 /* LCD: OUT[63] */
-#define REPORT_LCD_CMD_DATA    0x96 /* LCD: OUT[63] */
-#define	REPORT_EE_READ         0xa3 /* LCD: OUT[63] */
-#define REPORT_EE_WRITE        0xa4 /* LCD: OUT[63] */
-#define REPORT_ERASE_MEMORY    0xb2 /* LCD: OUT[2]  */
-#define REPORT_READ_MEMORY     0xb3 /* LCD: OUT[3]  */
-#define REPORT_WRITE_MEMORY    0xb4 /* LCD: OUT[63] */
-#define REPORT_SPLASH_RESTART  0xc1 /* LCD: OUT[1]  */
-#define REPORT_EXIT_KEYBOARD   0xef /* LCD: OUT[2]  */
-#define REPORT_VERSION         0xf1 /* LCD: IN[2],OUT[1]    Bootloader: IN[2],OUT[1]   */
-#define REPORT_BL_ERASE_MEMORY 0xf2 /*                      Bootloader: IN[36],OUT[4]  */
-#define REPORT_BL_READ_MEMORY  0xf3 /*                      Bootloader: IN[36],OUT[4]  */
-#define REPORT_BL_WRITE_MEMORY 0xf4 /*                      Bootloader: IN[36],OUT[36] */
-#define REPORT_DEVID           0xf5 /* LCD: IN[5], OUT[1]   Bootloader: IN[5],OUT[1]   */
-#define REPORT_SPLASH_SIZE     0xf6 /* LCD: IN[4], OUT[1]   */
-#define REPORT_HOOK_VERSION    0xf7 /* LCD: IN[2], OUT[1]   */
-#define REPORT_EXIT_FLASHER    0xff /*                      Bootloader: OUT[2]         */
-
-#ifdef CONFIG_HID_PICOLCD_FB
-/* Framebuffer
- *
- * The PicoLCD use a Topway LCD module of 256x64 pixel
- * This display area is tiled over 4 controllers with 8 tiles
- * each. Each tile has 8x64 pixel, each data byte representing
- * a 1-bit wide vertical line of the tile.
- *
- * The display can be updated at a tile granularity.
- *
- *       Chip 1           Chip 2           Chip 3           Chip 4
- * +----------------+----------------+----------------+----------------+
- * |     Tile 1     |     Tile 1     |     Tile 1     |     Tile 1     |
- * +----------------+----------------+----------------+----------------+
- * |     Tile 2     |     Tile 2     |     Tile 2     |     Tile 2     |
- * +----------------+----------------+----------------+----------------+
- *                                  ...
- * +----------------+----------------+----------------+----------------+
- * |     Tile 8     |     Tile 8     |     Tile 8     |     Tile 8     |
- * +----------------+----------------+----------------+----------------+
- */
-#define PICOLCDFB_NAME "picolcdfb"
-#define PICOLCDFB_WIDTH (256)
-#define PICOLCDFB_HEIGHT (64)
-#define PICOLCDFB_SIZE (PICOLCDFB_WIDTH * PICOLCDFB_HEIGHT / 8)
-
-#define PICOLCDFB_UPDATE_RATE_LIMIT   10
-#define PICOLCDFB_UPDATE_RATE_DEFAULT  2
-
-/* Framebuffer visual structures */
-static const struct fb_fix_screeninfo picolcdfb_fix = {
-	.id          = PICOLCDFB_NAME,
-	.type        = FB_TYPE_PACKED_PIXELS,
-	.visual      = FB_VISUAL_MONO01,
-	.xpanstep    = 0,
-	.ypanstep    = 0,
-	.ywrapstep   = 0,
-	.line_length = PICOLCDFB_WIDTH / 8,
-	.accel       = FB_ACCEL_NONE,
-};
-
-static const struct fb_var_screeninfo picolcdfb_var = {
-	.xres           = PICOLCDFB_WIDTH,
-	.yres           = PICOLCDFB_HEIGHT,
-	.xres_virtual   = PICOLCDFB_WIDTH,
-	.yres_virtual   = PICOLCDFB_HEIGHT,
-	.width          = 103,
-	.height         = 26,
-	.bits_per_pixel = 1,
-	.grayscale      = 1,
-	.red            = {
-		.offset = 0,
-		.length = 1,
-		.msb_right = 0,
-	},
-	.green          = {
-		.offset = 0,
-		.length = 1,
-		.msb_right = 0,
-	},
-	.blue           = {
-		.offset = 0,
-		.length = 1,
-		.msb_right = 0,
-	},
-	.transp         = {
-		.offset = 0,
-		.length = 0,
-		.msb_right = 0,
-	},
-};
-#endif /* CONFIG_HID_PICOLCD_FB */
-
-/* Input device
- *
- * The PicoLCD has an IR receiver header, a built-in keypad with 5 keys
- * and header for 4x4 key matrix. The built-in keys are part of the matrix.
- */
-static const unsigned short def_keymap[] = {
-	KEY_RESERVED,	/* none */
-	KEY_BACK,	/* col 4 + row 1 */
-	KEY_HOMEPAGE,	/* col 3 + row 1 */
-	KEY_RESERVED,	/* col 2 + row 1 */
-	KEY_RESERVED,	/* col 1 + row 1 */
-	KEY_SCROLLUP,	/* col 4 + row 2 */
-	KEY_OK,		/* col 3 + row 2 */
-	KEY_SCROLLDOWN,	/* col 2 + row 2 */
-	KEY_RESERVED,	/* col 1 + row 2 */
-	KEY_RESERVED,	/* col 4 + row 3 */
-	KEY_RESERVED,	/* col 3 + row 3 */
-	KEY_RESERVED,	/* col 2 + row 3 */
-	KEY_RESERVED,	/* col 1 + row 3 */
-	KEY_RESERVED,	/* col 4 + row 4 */
-	KEY_RESERVED,	/* col 3 + row 4 */
-	KEY_RESERVED,	/* col 2 + row 4 */
-	KEY_RESERVED,	/* col 1 + row 4 */
-};
-#define PICOLCD_KEYS ARRAY_SIZE(def_keymap)
-
-/* Description of in-progress IO operation, used for operations
- * that trigger response from device */
-struct picolcd_pending {
-	struct hid_report *out_report;
-	struct hid_report *in_report;
-	struct completion ready;
-	int raw_size;
-	u8 raw_data[64];
-};
-
-/* Per device data structure */
-struct picolcd_data {
-	struct hid_device *hdev;
-#ifdef CONFIG_DEBUG_FS
-	struct dentry *debug_reset;
-	struct dentry *debug_eeprom;
-	struct dentry *debug_flash;
-	struct mutex mutex_flash;
-	int addr_sz;
-#endif
-	u8 version[2];
-	unsigned short opmode_delay;
-	/* input stuff */
-	u8 pressed_keys[2];
-	struct input_dev *input_keys;
-	struct input_dev *input_cir;
-	unsigned short keycode[PICOLCD_KEYS];
-
-#ifdef CONFIG_HID_PICOLCD_FB
-	/* Framebuffer stuff */
-	u8 fb_update_rate;
-	u8 fb_bpp;
-	u8 fb_force;
-	u8 *fb_vbitmap;		/* local copy of what was sent to PicoLCD */
-	u8 *fb_bitmap;		/* framebuffer */
-	struct fb_info *fb_info;
-	struct fb_deferred_io fb_defio;
-#endif /* CONFIG_HID_PICOLCD_FB */
-#ifdef CONFIG_HID_PICOLCD_LCD
-	struct lcd_device *lcd;
-	u8 lcd_contrast;
-#endif /* CONFIG_HID_PICOLCD_LCD */
-#ifdef CONFIG_HID_PICOLCD_BACKLIGHT
-	struct backlight_device *backlight;
-	u8 lcd_brightness;
-	u8 lcd_power;
-#endif /* CONFIG_HID_PICOLCD_BACKLIGHT */
-#ifdef CONFIG_HID_PICOLCD_LEDS
-	/* LED stuff */
-	u8 led_state;
-	struct led_classdev *led[8];
-#endif /* CONFIG_HID_PICOLCD_LEDS */
-
-	/* Housekeeping stuff */
-	spinlock_t lock;
-	struct mutex mutex;
-	struct picolcd_pending *pending;
-	int status;
-#define PICOLCD_BOOTLOADER 1
-#define PICOLCD_FAILED 2
-#define PICOLCD_READY_FB 4
-};
-
-
-/* Find a given report */
-#define picolcd_in_report(id, dev) picolcd_report(id, dev, HID_INPUT_REPORT)
-#define picolcd_out_report(id, dev) picolcd_report(id, dev, HID_OUTPUT_REPORT)
-
-static struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir)
-{
-	struct list_head *feature_report_list = &hdev->report_enum[dir].report_list;
-	struct hid_report *report = NULL;
-
-	list_for_each_entry(report, feature_report_list, list) {
-		if (report->id == id)
-			return report;
-	}
-	hid_warn(hdev, "No report with id 0x%x found\n", id);
-	return NULL;
-}
-
-#ifdef CONFIG_DEBUG_FS
-static void picolcd_debug_out_report(struct picolcd_data *data,
-		struct hid_device *hdev, struct hid_report *report);
-#define usbhid_submit_report(a, b, c) \
-	do { \
-		picolcd_debug_out_report(hid_get_drvdata(a), a, b); \
-		usbhid_submit_report(a, b, c); \
-	} while (0)
-#endif
-
-/* Submit a report and wait for a reply from device - if device fades away
- * or does not respond in time, return NULL */
-static struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
-		int report_id, const u8 *raw_data, int size)
-{
-	struct picolcd_data *data = hid_get_drvdata(hdev);
-	struct picolcd_pending *work;
-	struct hid_report *report = picolcd_out_report(report_id, hdev);
-	unsigned long flags;
-	int i, j, k;
-
-	if (!report || !data)
-		return NULL;
-	if (data->status & PICOLCD_FAILED)
-		return NULL;
-	work = kzalloc(sizeof(*work), GFP_KERNEL);
-	if (!work)
-		return NULL;
-
-	init_completion(&work->ready);
-	work->out_report = report;
-	work->in_report  = NULL;
-	work->raw_size   = 0;
-
-	mutex_lock(&data->mutex);
-	spin_lock_irqsave(&data->lock, flags);
-	for (i = k = 0; i < report->maxfield; i++)
-		for (j = 0; j < report->field[i]->report_count; j++) {
-			hid_set_field(report->field[i], j, k < size ? raw_data[k] : 0);
-			k++;
-		}
-	data->pending = work;
-	usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-	spin_unlock_irqrestore(&data->lock, flags);
-	wait_for_completion_interruptible_timeout(&work->ready, HZ*2);
-	spin_lock_irqsave(&data->lock, flags);
-	data->pending = NULL;
-	spin_unlock_irqrestore(&data->lock, flags);
-	mutex_unlock(&data->mutex);
-	return work;
-}
-
-#ifdef CONFIG_HID_PICOLCD_FB
-/* Send a given tile to PicoLCD */
-static int picolcd_fb_send_tile(struct hid_device *hdev, int chip, int tile)
-{
-	struct picolcd_data *data = hid_get_drvdata(hdev);
-	struct hid_report *report1 = picolcd_out_report(REPORT_LCD_CMD_DATA, hdev);
-	struct hid_report *report2 = picolcd_out_report(REPORT_LCD_DATA, hdev);
-	unsigned long flags;
-	u8 *tdata;
-	int i;
-
-	if (!report1 || report1->maxfield != 1 || !report2 || report2->maxfield != 1)
-		return -ENODEV;
-
-	spin_lock_irqsave(&data->lock, flags);
-	hid_set_field(report1->field[0],  0, chip << 2);
-	hid_set_field(report1->field[0],  1, 0x02);
-	hid_set_field(report1->field[0],  2, 0x00);
-	hid_set_field(report1->field[0],  3, 0x00);
-	hid_set_field(report1->field[0],  4, 0xb8 | tile);
-	hid_set_field(report1->field[0],  5, 0x00);
-	hid_set_field(report1->field[0],  6, 0x00);
-	hid_set_field(report1->field[0],  7, 0x40);
-	hid_set_field(report1->field[0],  8, 0x00);
-	hid_set_field(report1->field[0],  9, 0x00);
-	hid_set_field(report1->field[0], 10,   32);
-
-	hid_set_field(report2->field[0],  0, (chip << 2) | 0x01);
-	hid_set_field(report2->field[0],  1, 0x00);
-	hid_set_field(report2->field[0],  2, 0x00);
-	hid_set_field(report2->field[0],  3,   32);
-
-	tdata = data->fb_vbitmap + (tile * 4 + chip) * 64;
-	for (i = 0; i < 64; i++)
-		if (i < 32)
-			hid_set_field(report1->field[0], 11 + i, tdata[i]);
-		else
-			hid_set_field(report2->field[0], 4 + i - 32, tdata[i]);
-
-	usbhid_submit_report(data->hdev, report1, USB_DIR_OUT);
-	usbhid_submit_report(data->hdev, report2, USB_DIR_OUT);
-	spin_unlock_irqrestore(&data->lock, flags);
-	return 0;
-}
-
-/* Translate a single tile*/
-static int picolcd_fb_update_tile(u8 *vbitmap, const u8 *bitmap, int bpp,
-		int chip, int tile)
-{
-	int i, b, changed = 0;
-	u8 tdata[64];
-	u8 *vdata = vbitmap + (tile * 4 + chip) * 64;
-
-	if (bpp == 1) {
-		for (b = 7; b >= 0; b--) {
-			const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32;
-			for (i = 0; i < 64; i++) {
-				tdata[i] <<= 1;
-				tdata[i] |= (bdata[i/8] >> (i % 8)) & 0x01;
-			}
-		}
-	} else if (bpp == 8) {
-		for (b = 7; b >= 0; b--) {
-			const u8 *bdata = bitmap + (tile * 256 + chip * 8 + b * 32) * 8;
-			for (i = 0; i < 64; i++) {
-				tdata[i] <<= 1;
-				tdata[i] |= (bdata[i] & 0x80) ? 0x01 : 0x00;
-			}
-		}
-	} else {
-		/* Oops, we should never get here! */
-		WARN_ON(1);
-		return 0;
-	}
-
-	for (i = 0; i < 64; i++)
-		if (tdata[i] != vdata[i]) {
-			changed = 1;
-			vdata[i] = tdata[i];
-		}
-	return changed;
-}
-
-/* Reconfigure LCD display */
-static int picolcd_fb_reset(struct picolcd_data *data, int clear)
-{
-	struct hid_report *report = picolcd_out_report(REPORT_LCD_CMD, data->hdev);
-	int i, j;
-	unsigned long flags;
-	static const u8 mapcmd[8] = { 0x00, 0x02, 0x00, 0x64, 0x3f, 0x00, 0x64, 0xc0 };
-
-	if (!report || report->maxfield != 1)
-		return -ENODEV;
-
-	spin_lock_irqsave(&data->lock, flags);
-	for (i = 0; i < 4; i++) {
-		for (j = 0; j < report->field[0]->maxusage; j++)
-			if (j == 0)
-				hid_set_field(report->field[0], j, i << 2);
-			else if (j < sizeof(mapcmd))
-				hid_set_field(report->field[0], j, mapcmd[j]);
-			else
-				hid_set_field(report->field[0], j, 0);
-		usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-	}
-
-	data->status |= PICOLCD_READY_FB;
-	spin_unlock_irqrestore(&data->lock, flags);
-
-	if (data->fb_bitmap) {
-		if (clear) {
-			memset(data->fb_vbitmap, 0, PICOLCDFB_SIZE);
-			memset(data->fb_bitmap, 0, PICOLCDFB_SIZE*data->fb_bpp);
-		}
-		data->fb_force = 1;
-	}
-
-	/* schedule first output of framebuffer */
-	if (data->fb_info)
-		schedule_delayed_work(&data->fb_info->deferred_work, 0);
-
-	return 0;
-}
-
-/* Update fb_vbitmap from the screen_base and send changed tiles to device */
-static void picolcd_fb_update(struct picolcd_data *data)
-{
-	int chip, tile, n;
-	unsigned long flags;
-
-	if (!data)
-		return;
-
-	spin_lock_irqsave(&data->lock, flags);
-	if (!(data->status & PICOLCD_READY_FB)) {
-		spin_unlock_irqrestore(&data->lock, flags);
-		picolcd_fb_reset(data, 0);
-	} else {
-		spin_unlock_irqrestore(&data->lock, flags);
-	}
-
-	/*
-	 * Translate the framebuffer into the format needed by the PicoLCD.
-	 * See display layout above.
-	 * Do this one tile after the other and push those tiles that changed.
-	 *
-	 * Wait for our IO to complete as otherwise we might flood the queue!
-	 */
-	n = 0;
-	for (chip = 0; chip < 4; chip++)
-		for (tile = 0; tile < 8; tile++)
-			if (picolcd_fb_update_tile(data->fb_vbitmap,
-					data->fb_bitmap, data->fb_bpp, chip, tile) ||
-				data->fb_force) {
-				n += 2;
-				if (!data->fb_info->par)
-					return; /* device lost! */
-				if (n >= HID_OUTPUT_FIFO_SIZE / 2) {
-					usbhid_wait_io(data->hdev);
-					n = 0;
-				}
-				picolcd_fb_send_tile(data->hdev, chip, tile);
-			}
-	data->fb_force = false;
-	if (n)
-		usbhid_wait_io(data->hdev);
-}
-
-/* Stub to call the system default and update the image on the picoLCD */
-static void picolcd_fb_fillrect(struct fb_info *info,
-		const struct fb_fillrect *rect)
-{
-	if (!info->par)
-		return;
-	sys_fillrect(info, rect);
-
-	schedule_delayed_work(&info->deferred_work, 0);
-}
-
-/* Stub to call the system default and update the image on the picoLCD */
-static void picolcd_fb_copyarea(struct fb_info *info,
-		const struct fb_copyarea *area)
-{
-	if (!info->par)
-		return;
-	sys_copyarea(info, area);
-
-	schedule_delayed_work(&info->deferred_work, 0);
-}
-
-/* Stub to call the system default and update the image on the picoLCD */
-static void picolcd_fb_imageblit(struct fb_info *info, const struct fb_image *image)
-{
-	if (!info->par)
-		return;
-	sys_imageblit(info, image);
-
-	schedule_delayed_work(&info->deferred_work, 0);
-}
-
-/*
- * this is the slow path from userspace. they can seek and write to
- * the fb. it's inefficient to do anything less than a full screen draw
- */
-static ssize_t picolcd_fb_write(struct fb_info *info, const char __user *buf,
-		size_t count, loff_t *ppos)
-{
-	ssize_t ret;
-	if (!info->par)
-		return -ENODEV;
-	ret = fb_sys_write(info, buf, count, ppos);
-	if (ret >= 0)
-		schedule_delayed_work(&info->deferred_work, 0);
-	return ret;
-}
-
-static int picolcd_fb_blank(int blank, struct fb_info *info)
-{
-	if (!info->par)
-		return -ENODEV;
-	/* We let fb notification do this for us via lcd/backlight device */
-	return 0;
-}
-
-static void picolcd_fb_destroy(struct fb_info *info)
-{
-	struct picolcd_data *data = info->par;
-	u32 *ref_cnt = info->pseudo_palette;
-	int may_release;
-
-	info->par = NULL;
-	if (data)
-		data->fb_info = NULL;
-	fb_deferred_io_cleanup(info);
-
-	ref_cnt--;
-	mutex_lock(&info->lock);
-	(*ref_cnt)--;
-	may_release = !*ref_cnt;
-	mutex_unlock(&info->lock);
-	if (may_release) {
-		vfree((u8 *)info->fix.smem_start);
-		framebuffer_release(info);
-	}
-}
-
-static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
-{
-	__u32 bpp      = var->bits_per_pixel;
-	__u32 activate = var->activate;
-
-	/* only allow 1/8 bit depth (8-bit is grayscale) */
-	*var = picolcdfb_var;
-	var->activate = activate;
-	if (bpp >= 8) {
-		var->bits_per_pixel = 8;
-		var->red.length     = 8;
-		var->green.length   = 8;
-		var->blue.length    = 8;
-	} else {
-		var->bits_per_pixel = 1;
-		var->red.length     = 1;
-		var->green.length   = 1;
-		var->blue.length    = 1;
-	}
-	return 0;
-}
-
-static int picolcd_set_par(struct fb_info *info)
-{
-	struct picolcd_data *data = info->par;
-	u8 *tmp_fb, *o_fb;
-	if (!data)
-		return -ENODEV;
-	if (info->var.bits_per_pixel == data->fb_bpp)
-		return 0;
-	/* switch between 1/8 bit depths */
-	if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8)
-		return -EINVAL;
-
-	o_fb   = data->fb_bitmap;
-	tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL);
-	if (!tmp_fb)
-		return -ENOMEM;
-
-	/* translate FB content to new bits-per-pixel */
-	if (info->var.bits_per_pixel == 1) {
-		int i, b;
-		for (i = 0; i < PICOLCDFB_SIZE; i++) {
-			u8 p = 0;
-			for (b = 0; b < 8; b++) {
-				p <<= 1;
-				p |= o_fb[i*8+b] ? 0x01 : 0x00;
-			}
-			tmp_fb[i] = p;
-		}
-		memcpy(o_fb, tmp_fb, PICOLCDFB_SIZE);
-		info->fix.visual = FB_VISUAL_MONO01;
-		info->fix.line_length = PICOLCDFB_WIDTH / 8;
-	} else {
-		int i;
-		memcpy(tmp_fb, o_fb, PICOLCDFB_SIZE);
-		for (i = 0; i < PICOLCDFB_SIZE * 8; i++)
-			o_fb[i] = tmp_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00;
-		info->fix.visual = FB_VISUAL_DIRECTCOLOR;
-		info->fix.line_length = PICOLCDFB_WIDTH;
-	}
-
-	kfree(tmp_fb);
-	data->fb_bpp      = info->var.bits_per_pixel;
-	return 0;
-}
-
-/* Do refcounting on our FB and cleanup per worker if FB is
- * closed after unplug of our device
- * (fb_release holds info->lock and still touches info after
- *  we return so we can't release it immediately.
- */
-struct picolcd_fb_cleanup_item {
-	struct fb_info *info;
-	struct picolcd_fb_cleanup_item *next;
-};
-static struct picolcd_fb_cleanup_item *fb_pending;
-static DEFINE_SPINLOCK(fb_pending_lock);
-
-static void picolcd_fb_do_cleanup(struct work_struct *data)
-{
-	struct picolcd_fb_cleanup_item *item;
-	unsigned long flags;
-
-	do {
-		spin_lock_irqsave(&fb_pending_lock, flags);
-		item = fb_pending;
-		fb_pending = item ? item->next : NULL;
-		spin_unlock_irqrestore(&fb_pending_lock, flags);
-
-		if (item) {
-			u8 *fb = (u8 *)item->info->fix.smem_start;
-			/* make sure we do not race against fb core when
-			 * releasing */
-			mutex_lock(&item->info->lock);
-			mutex_unlock(&item->info->lock);
-			framebuffer_release(item->info);
-			vfree(fb);
-		}
-	} while (item);
-}
-
-static DECLARE_WORK(picolcd_fb_cleanup, picolcd_fb_do_cleanup);
-
-static int picolcd_fb_open(struct fb_info *info, int u)
-{
-	u32 *ref_cnt = info->pseudo_palette;
-	ref_cnt--;
-
-	(*ref_cnt)++;
-	return 0;
-}
-
-static int picolcd_fb_release(struct fb_info *info, int u)
-{
-	u32 *ref_cnt = info->pseudo_palette;
-	ref_cnt--;
-
-	(*ref_cnt)++;
-	if (!*ref_cnt) {
-		unsigned long flags;
-		struct picolcd_fb_cleanup_item *item = (struct picolcd_fb_cleanup_item *)ref_cnt;
-		item--;
-		spin_lock_irqsave(&fb_pending_lock, flags);
-		item->next = fb_pending;
-		fb_pending = item;
-		spin_unlock_irqrestore(&fb_pending_lock, flags);
-		schedule_work(&picolcd_fb_cleanup);
-	}
-	return 0;
-}
-
-/* Note this can't be const because of struct fb_info definition */
-static struct fb_ops picolcdfb_ops = {
-	.owner        = THIS_MODULE,
-	.fb_destroy   = picolcd_fb_destroy,
-	.fb_open      = picolcd_fb_open,
-	.fb_release   = picolcd_fb_release,
-	.fb_read      = fb_sys_read,
-	.fb_write     = picolcd_fb_write,
-	.fb_blank     = picolcd_fb_blank,
-	.fb_fillrect  = picolcd_fb_fillrect,
-	.fb_copyarea  = picolcd_fb_copyarea,
-	.fb_imageblit = picolcd_fb_imageblit,
-	.fb_check_var = picolcd_fb_check_var,
-	.fb_set_par   = picolcd_set_par,
-};
-
-
-/* Callback from deferred IO workqueue */
-static void picolcd_fb_deferred_io(struct fb_info *info, struct list_head *pagelist)
-{
-	picolcd_fb_update(info->par);
-}
-
-static const struct fb_deferred_io picolcd_fb_defio = {
-	.delay = HZ / PICOLCDFB_UPDATE_RATE_DEFAULT,
-	.deferred_io = picolcd_fb_deferred_io,
-};
-
-
-/*
- * The "fb_update_rate" sysfs attribute
- */
-static ssize_t picolcd_fb_update_rate_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct picolcd_data *data = dev_get_drvdata(dev);
-	unsigned i, fb_update_rate = data->fb_update_rate;
-	size_t ret = 0;
-
-	for (i = 1; i <= PICOLCDFB_UPDATE_RATE_LIMIT; i++)
-		if (ret >= PAGE_SIZE)
-			break;
-		else if (i == fb_update_rate)
-			ret += snprintf(buf+ret, PAGE_SIZE-ret, "[%u] ", i);
-		else
-			ret += snprintf(buf+ret, PAGE_SIZE-ret, "%u ", i);
-	if (ret > 0)
-		buf[min(ret, (size_t)PAGE_SIZE)-1] = '\n';
-	return ret;
-}
-
-static ssize_t picolcd_fb_update_rate_store(struct device *dev,
-		struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct picolcd_data *data = dev_get_drvdata(dev);
-	int i;
-	unsigned u;
-
-	if (count < 1 || count > 10)
-		return -EINVAL;
-
-	i = sscanf(buf, "%u", &u);
-	if (i != 1)
-		return -EINVAL;
-
-	if (u > PICOLCDFB_UPDATE_RATE_LIMIT)
-		return -ERANGE;
-	else if (u == 0)
-		u = PICOLCDFB_UPDATE_RATE_DEFAULT;
-
-	data->fb_update_rate = u;
-	data->fb_defio.delay = HZ / data->fb_update_rate;
-	return count;
-}
-
-static DEVICE_ATTR(fb_update_rate, 0666, picolcd_fb_update_rate_show,
-		picolcd_fb_update_rate_store);
-
-/* initialize Framebuffer device */
-static int picolcd_init_framebuffer(struct picolcd_data *data)
-{
-	struct device *dev = &data->hdev->dev;
-	struct fb_info *info = NULL;
-	int i, error = -ENOMEM;
-	u8 *fb_vbitmap = NULL;
-	u8 *fb_bitmap  = NULL;
-	u32 *palette;
-
-	fb_bitmap = vmalloc(PICOLCDFB_SIZE*8);
-	if (fb_bitmap == NULL) {
-		dev_err(dev, "can't get a free page for framebuffer\n");
-		goto err_nomem;
-	}
-
-	fb_vbitmap = kmalloc(PICOLCDFB_SIZE, GFP_KERNEL);
-	if (fb_vbitmap == NULL) {
-		dev_err(dev, "can't alloc vbitmap image buffer\n");
-		goto err_nomem;
-	}
-
-	data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT;
-	data->fb_defio = picolcd_fb_defio;
-	/* The extra memory is:
-	 * - struct picolcd_fb_cleanup_item
-	 * - u32 for ref_count
-	 * - 256*u32 for pseudo_palette
-	 */
-	info = framebuffer_alloc(257 * sizeof(u32) + sizeof(struct picolcd_fb_cleanup_item), dev);
-	if (info == NULL) {
-		dev_err(dev, "failed to allocate a framebuffer\n");
-		goto err_nomem;
-	}
-
-	palette  = info->par + sizeof(struct picolcd_fb_cleanup_item);
-	*palette = 1;
-	palette++;
-	for (i = 0; i < 256; i++)
-		palette[i] = i > 0 && i < 16 ? 0xff : 0;
-	info->pseudo_palette = palette;
-	info->fbdefio = &data->fb_defio;
-	info->screen_base = (char __force __iomem *)fb_bitmap;
-	info->fbops = &picolcdfb_ops;
-	info->var = picolcdfb_var;
-	info->fix = picolcdfb_fix;
-	info->fix.smem_len   = PICOLCDFB_SIZE*8;
-	info->fix.smem_start = (unsigned long)fb_bitmap;
-	info->par = data;
-	info->flags = FBINFO_FLAG_DEFAULT;
-
-	data->fb_vbitmap = fb_vbitmap;
-	data->fb_bitmap  = fb_bitmap;
-	data->fb_bpp     = picolcdfb_var.bits_per_pixel;
-	error = picolcd_fb_reset(data, 1);
-	if (error) {
-		dev_err(dev, "failed to configure display\n");
-		goto err_cleanup;
-	}
-	error = device_create_file(dev, &dev_attr_fb_update_rate);
-	if (error) {
-		dev_err(dev, "failed to create sysfs attributes\n");
-		goto err_cleanup;
-	}
-	fb_deferred_io_init(info);
-	data->fb_info    = info;
-	error = register_framebuffer(info);
-	if (error) {
-		dev_err(dev, "failed to register framebuffer\n");
-		goto err_sysfs;
-	}
-	/* schedule first output of framebuffer */
-	data->fb_force = 1;
-	schedule_delayed_work(&info->deferred_work, 0);
-	return 0;
-
-err_sysfs:
-	fb_deferred_io_cleanup(info);
-	device_remove_file(dev, &dev_attr_fb_update_rate);
-err_cleanup:
-	data->fb_vbitmap = NULL;
-	data->fb_bitmap  = NULL;
-	data->fb_bpp     = 0;
-	data->fb_info    = NULL;
-
-err_nomem:
-	framebuffer_release(info);
-	vfree(fb_bitmap);
-	kfree(fb_vbitmap);
-	return error;
-}
-
-static void picolcd_exit_framebuffer(struct picolcd_data *data)
-{
-	struct fb_info *info = data->fb_info;
-	u8 *fb_vbitmap = data->fb_vbitmap;
-
-	if (!info)
-		return;
-
-	info->par = NULL;
-	device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate);
-	unregister_framebuffer(info);
-	data->fb_vbitmap = NULL;
-	data->fb_bitmap  = NULL;
-	data->fb_bpp     = 0;
-	data->fb_info    = NULL;
-	kfree(fb_vbitmap);
-}
-
-#define picolcd_fbinfo(d) ((d)->fb_info)
-#else
-static inline int picolcd_fb_reset(struct picolcd_data *data, int clear)
-{
-	return 0;
-}
-static inline int picolcd_init_framebuffer(struct picolcd_data *data)
-{
-	return 0;
-}
-static inline void picolcd_exit_framebuffer(struct picolcd_data *data)
-{
-}
-#define picolcd_fbinfo(d) NULL
-#endif /* CONFIG_HID_PICOLCD_FB */
-
-#ifdef CONFIG_HID_PICOLCD_BACKLIGHT
-/*
- * backlight class device
- */
-static int picolcd_get_brightness(struct backlight_device *bdev)
-{
-	struct picolcd_data *data = bl_get_data(bdev);
-	return data->lcd_brightness;
-}
-
-static int picolcd_set_brightness(struct backlight_device *bdev)
-{
-	struct picolcd_data *data = bl_get_data(bdev);
-	struct hid_report *report = picolcd_out_report(REPORT_BRIGHTNESS, data->hdev);
-	unsigned long flags;
-
-	if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
-		return -ENODEV;
-
-	data->lcd_brightness = bdev->props.brightness & 0x0ff;
-	data->lcd_power      = bdev->props.power;
-	spin_lock_irqsave(&data->lock, flags);
-	hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0);
-	usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-	spin_unlock_irqrestore(&data->lock, flags);
-	return 0;
-}
-
-static int picolcd_check_bl_fb(struct backlight_device *bdev, struct fb_info *fb)
-{
-	return fb && fb == picolcd_fbinfo((struct picolcd_data *)bl_get_data(bdev));
-}
-
-static const struct backlight_ops picolcd_blops = {
-	.update_status  = picolcd_set_brightness,
-	.get_brightness = picolcd_get_brightness,
-	.check_fb       = picolcd_check_bl_fb,
-};
-
-static int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *report)
-{
-	struct device *dev = &data->hdev->dev;
-	struct backlight_device *bdev;
-	struct backlight_properties props;
-	if (!report)
-		return -ENODEV;
-	if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
-			report->field[0]->report_size != 8) {
-		dev_err(dev, "unsupported BRIGHTNESS report");
-		return -EINVAL;
-	}
-
-	memset(&props, 0, sizeof(props));
-	props.type = BACKLIGHT_RAW;
-	props.max_brightness = 0xff;
-	bdev = backlight_device_register(dev_name(dev), dev, data,
-			&picolcd_blops, &props);
-	if (IS_ERR(bdev)) {
-		dev_err(dev, "failed to register backlight\n");
-		return PTR_ERR(bdev);
-	}
-	bdev->props.brightness     = 0xff;
-	data->lcd_brightness       = 0xff;
-	data->backlight            = bdev;
-	picolcd_set_brightness(bdev);
-	return 0;
-}
-
-static void picolcd_exit_backlight(struct picolcd_data *data)
-{
-	struct backlight_device *bdev = data->backlight;
-
-	data->backlight = NULL;
-	if (bdev)
-		backlight_device_unregister(bdev);
-}
-
-static inline int picolcd_resume_backlight(struct picolcd_data *data)
-{
-	if (!data->backlight)
-		return 0;
-	return picolcd_set_brightness(data->backlight);
-}
-
-#ifdef CONFIG_PM
-static void picolcd_suspend_backlight(struct picolcd_data *data)
-{
-	int bl_power = data->lcd_power;
-	if (!data->backlight)
-		return;
-
-	data->backlight->props.power = FB_BLANK_POWERDOWN;
-	picolcd_set_brightness(data->backlight);
-	data->lcd_power = data->backlight->props.power = bl_power;
-}
-#endif /* CONFIG_PM */
-#else
-static inline int picolcd_init_backlight(struct picolcd_data *data,
-		struct hid_report *report)
-{
-	return 0;
-}
-static inline void picolcd_exit_backlight(struct picolcd_data *data)
-{
-}
-static inline int picolcd_resume_backlight(struct picolcd_data *data)
-{
-	return 0;
-}
-static inline void picolcd_suspend_backlight(struct picolcd_data *data)
-{
-}
-#endif /* CONFIG_HID_PICOLCD_BACKLIGHT */
-
-#ifdef CONFIG_HID_PICOLCD_LCD
-/*
- * lcd class device
- */
-static int picolcd_get_contrast(struct lcd_device *ldev)
-{
-	struct picolcd_data *data = lcd_get_data(ldev);
-	return data->lcd_contrast;
-}
-
-static int picolcd_set_contrast(struct lcd_device *ldev, int contrast)
-{
-	struct picolcd_data *data = lcd_get_data(ldev);
-	struct hid_report *report = picolcd_out_report(REPORT_CONTRAST, data->hdev);
-	unsigned long flags;
-
-	if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
-		return -ENODEV;
-
-	data->lcd_contrast = contrast & 0x0ff;
-	spin_lock_irqsave(&data->lock, flags);
-	hid_set_field(report->field[0], 0, data->lcd_contrast);
-	usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-	spin_unlock_irqrestore(&data->lock, flags);
-	return 0;
-}
-
-static int picolcd_check_lcd_fb(struct lcd_device *ldev, struct fb_info *fb)
-{
-	return fb && fb == picolcd_fbinfo((struct picolcd_data *)lcd_get_data(ldev));
-}
-
-static struct lcd_ops picolcd_lcdops = {
-	.get_contrast   = picolcd_get_contrast,
-	.set_contrast   = picolcd_set_contrast,
-	.check_fb       = picolcd_check_lcd_fb,
-};
-
-static int picolcd_init_lcd(struct picolcd_data *data, struct hid_report *report)
-{
-	struct device *dev = &data->hdev->dev;
-	struct lcd_device *ldev;
-
-	if (!report)
-		return -ENODEV;
-	if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
-			report->field[0]->report_size != 8) {
-		dev_err(dev, "unsupported CONTRAST report");
-		return -EINVAL;
-	}
-
-	ldev = lcd_device_register(dev_name(dev), dev, data, &picolcd_lcdops);
-	if (IS_ERR(ldev)) {
-		dev_err(dev, "failed to register LCD\n");
-		return PTR_ERR(ldev);
-	}
-	ldev->props.max_contrast = 0x0ff;
-	data->lcd_contrast = 0xe5;
-	data->lcd = ldev;
-	picolcd_set_contrast(ldev, 0xe5);
-	return 0;
-}
-
-static void picolcd_exit_lcd(struct picolcd_data *data)
-{
-	struct lcd_device *ldev = data->lcd;
-
-	data->lcd = NULL;
-	if (ldev)
-		lcd_device_unregister(ldev);
-}
-
-static inline int picolcd_resume_lcd(struct picolcd_data *data)
-{
-	if (!data->lcd)
-		return 0;
-	return picolcd_set_contrast(data->lcd, data->lcd_contrast);
-}
-#else
-static inline int picolcd_init_lcd(struct picolcd_data *data,
-		struct hid_report *report)
-{
-	return 0;
-}
-static inline void picolcd_exit_lcd(struct picolcd_data *data)
-{
-}
-static inline int picolcd_resume_lcd(struct picolcd_data *data)
-{
-	return 0;
-}
-#endif /* CONFIG_HID_PICOLCD_LCD */
-
-#ifdef CONFIG_HID_PICOLCD_LEDS
-/**
- * LED class device
- */
-static void picolcd_leds_set(struct picolcd_data *data)
-{
-	struct hid_report *report;
-	unsigned long flags;
-
-	if (!data->led[0])
-		return;
-	report = picolcd_out_report(REPORT_LED_STATE, data->hdev);
-	if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
-		return;
-
-	spin_lock_irqsave(&data->lock, flags);
-	hid_set_field(report->field[0], 0, data->led_state);
-	usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-	spin_unlock_irqrestore(&data->lock, flags);
-}
-
-static void picolcd_led_set_brightness(struct led_classdev *led_cdev,
-			enum led_brightness value)
-{
-	struct device *dev;
-	struct hid_device *hdev;
-	struct picolcd_data *data;
-	int i, state = 0;
-
-	dev  = led_cdev->dev->parent;
-	hdev = container_of(dev, struct hid_device, dev);
-	data = hid_get_drvdata(hdev);
-	for (i = 0; i < 8; i++) {
-		if (led_cdev != data->led[i])
-			continue;
-		state = (data->led_state >> i) & 1;
-		if (value == LED_OFF && state) {
-			data->led_state &= ~(1 << i);
-			picolcd_leds_set(data);
-		} else if (value != LED_OFF && !state) {
-			data->led_state |= 1 << i;
-			picolcd_leds_set(data);
-		}
-		break;
-	}
-}
-
-static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev)
-{
-	struct device *dev;
-	struct hid_device *hdev;
-	struct picolcd_data *data;
-	int i, value = 0;
-
-	dev  = led_cdev->dev->parent;
-	hdev = container_of(dev, struct hid_device, dev);
-	data = hid_get_drvdata(hdev);
-	for (i = 0; i < 8; i++)
-		if (led_cdev == data->led[i]) {
-			value = (data->led_state >> i) & 1;
-			break;
-		}
-	return value ? LED_FULL : LED_OFF;
-}
-
-static int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report)
-{
-	struct device *dev = &data->hdev->dev;
-	struct led_classdev *led;
-	size_t name_sz = strlen(dev_name(dev)) + 8;
-	char *name;
-	int i, ret = 0;
-
-	if (!report)
-		return -ENODEV;
-	if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
-			report->field[0]->report_size != 8) {
-		dev_err(dev, "unsupported LED_STATE report");
-		return -EINVAL;
-	}
-
-	for (i = 0; i < 8; i++) {
-		led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
-		if (!led) {
-			dev_err(dev, "can't allocate memory for LED %d\n", i);
-			ret = -ENOMEM;
-			goto err;
-		}
-		name = (void *)(&led[1]);
-		snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i);
-		led->name = name;
-		led->brightness = 0;
-		led->max_brightness = 1;
-		led->brightness_get = picolcd_led_get_brightness;
-		led->brightness_set = picolcd_led_set_brightness;
-
-		data->led[i] = led;
-		ret = led_classdev_register(dev, data->led[i]);
-		if (ret) {
-			data->led[i] = NULL;
-			kfree(led);
-			dev_err(dev, "can't register LED %d\n", i);
-			goto err;
-		}
-	}
-	return 0;
-err:
-	for (i = 0; i < 8; i++)
-		if (data->led[i]) {
-			led = data->led[i];
-			data->led[i] = NULL;
-			led_classdev_unregister(led);
-			kfree(led);
-		}
-	return ret;
-}
-
-static void picolcd_exit_leds(struct picolcd_data *data)
-{
-	struct led_classdev *led;
-	int i;
-
-	for (i = 0; i < 8; i++) {
-		led = data->led[i];
-		data->led[i] = NULL;
-		if (!led)
-			continue;
-		led_classdev_unregister(led);
-		kfree(led);
-	}
-}
-
-#else
-static inline int picolcd_init_leds(struct picolcd_data *data,
-		struct hid_report *report)
-{
-	return 0;
-}
-static inline void picolcd_exit_leds(struct picolcd_data *data)
-{
-}
-static inline int picolcd_leds_set(struct picolcd_data *data)
-{
-	return 0;
-}
-#endif /* CONFIG_HID_PICOLCD_LEDS */
-
-/*
- * input class device
- */
-static int picolcd_raw_keypad(struct picolcd_data *data,
-		struct hid_report *report, u8 *raw_data, int size)
-{
-	/*
-	 * Keypad event
-	 * First and second data bytes list currently pressed keys,
-	 * 0x00 means no key and at most 2 keys may be pressed at same time
-	 */
-	int i, j;
-
-	/* determine newly pressed keys */
-	for (i = 0; i < size; i++) {
-		unsigned int key_code;
-		if (raw_data[i] == 0)
-			continue;
-		for (j = 0; j < sizeof(data->pressed_keys); j++)
-			if (data->pressed_keys[j] == raw_data[i])
-				goto key_already_down;
-		for (j = 0; j < sizeof(data->pressed_keys); j++)
-			if (data->pressed_keys[j] == 0) {
-				data->pressed_keys[j] = raw_data[i];
-				break;
-			}
-		input_event(data->input_keys, EV_MSC, MSC_SCAN, raw_data[i]);
-		if (raw_data[i] < PICOLCD_KEYS)
-			key_code = data->keycode[raw_data[i]];
-		else
-			key_code = KEY_UNKNOWN;
-		if (key_code != KEY_UNKNOWN) {
-			dbg_hid(PICOLCD_NAME " got key press for %u:%d",
-					raw_data[i], key_code);
-			input_report_key(data->input_keys, key_code, 1);
-		}
-		input_sync(data->input_keys);
-key_already_down:
-		continue;
-	}
-
-	/* determine newly released keys */
-	for (j = 0; j < sizeof(data->pressed_keys); j++) {
-		unsigned int key_code;
-		if (data->pressed_keys[j] == 0)
-			continue;
-		for (i = 0; i < size; i++)
-			if (data->pressed_keys[j] == raw_data[i])
-				goto key_still_down;
-		input_event(data->input_keys, EV_MSC, MSC_SCAN, data->pressed_keys[j]);
-		if (data->pressed_keys[j] < PICOLCD_KEYS)
-			key_code = data->keycode[data->pressed_keys[j]];
-		else
-			key_code = KEY_UNKNOWN;
-		if (key_code != KEY_UNKNOWN) {
-			dbg_hid(PICOLCD_NAME " got key release for %u:%d",
-					data->pressed_keys[j], key_code);
-			input_report_key(data->input_keys, key_code, 0);
-		}
-		input_sync(data->input_keys);
-		data->pressed_keys[j] = 0;
-key_still_down:
-		continue;
-	}
-	return 1;
-}
-
-static int picolcd_raw_cir(struct picolcd_data *data,
-		struct hid_report *report, u8 *raw_data, int size)
-{
-	/* Need understanding of CIR data format to implement ... */
-	return 1;
-}
-
-static int picolcd_check_version(struct hid_device *hdev)
-{
-	struct picolcd_data *data = hid_get_drvdata(hdev);
-	struct picolcd_pending *verinfo;
-	int ret = 0;
-
-	if (!data)
-		return -ENODEV;
-
-	verinfo = picolcd_send_and_wait(hdev, REPORT_VERSION, NULL, 0);
-	if (!verinfo) {
-		hid_err(hdev, "no version response from PicoLCD\n");
-		return -ENODEV;
-	}
-
-	if (verinfo->raw_size == 2) {
-		data->version[0] = verinfo->raw_data[1];
-		data->version[1] = verinfo->raw_data[0];
-		if (data->status & PICOLCD_BOOTLOADER) {
-			hid_info(hdev, "PicoLCD, bootloader version %d.%d\n",
-				 verinfo->raw_data[1], verinfo->raw_data[0]);
-		} else {
-			hid_info(hdev, "PicoLCD, firmware version %d.%d\n",
-				 verinfo->raw_data[1], verinfo->raw_data[0]);
-		}
-	} else {
-		hid_err(hdev, "confused, got unexpected version response from PicoLCD\n");
-		ret = -EINVAL;
-	}
-	kfree(verinfo);
-	return ret;
-}
-
-/*
- * Reset our device and wait for answer to VERSION request
- */
-static int picolcd_reset(struct hid_device *hdev)
-{
-	struct picolcd_data *data = hid_get_drvdata(hdev);
-	struct hid_report *report = picolcd_out_report(REPORT_RESET, hdev);
-	unsigned long flags;
-	int error;
-
-	if (!data || !report || report->maxfield != 1)
-		return -ENODEV;
-
-	spin_lock_irqsave(&data->lock, flags);
-	if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
-		data->status |= PICOLCD_BOOTLOADER;
-
-	/* perform the reset */
-	hid_set_field(report->field[0], 0, 1);
-	usbhid_submit_report(hdev, report, USB_DIR_OUT);
-	spin_unlock_irqrestore(&data->lock, flags);
-
-	error = picolcd_check_version(hdev);
-	if (error)
-		return error;
-
-	picolcd_resume_lcd(data);
-	picolcd_resume_backlight(data);
-#ifdef CONFIG_HID_PICOLCD_FB
-	if (data->fb_info)
-		schedule_delayed_work(&data->fb_info->deferred_work, 0);
-#endif /* CONFIG_HID_PICOLCD_FB */
-
-	picolcd_leds_set(data);
-	return 0;
-}
-
-/*
- * The "operation_mode" sysfs attribute
- */
-static ssize_t picolcd_operation_mode_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct picolcd_data *data = dev_get_drvdata(dev);
-
-	if (data->status & PICOLCD_BOOTLOADER)
-		return snprintf(buf, PAGE_SIZE, "[bootloader] lcd\n");
-	else
-		return snprintf(buf, PAGE_SIZE, "bootloader [lcd]\n");
-}
-
-static ssize_t picolcd_operation_mode_store(struct device *dev,
-		struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct picolcd_data *data = dev_get_drvdata(dev);
-	struct hid_report *report = NULL;
-	size_t cnt = count;
-	int timeout = data->opmode_delay;
-	unsigned long flags;
-
-	if (cnt >= 3 && strncmp("lcd", buf, 3) == 0) {
-		if (data->status & PICOLCD_BOOTLOADER)
-			report = picolcd_out_report(REPORT_EXIT_FLASHER, data->hdev);
-		buf += 3;
-		cnt -= 3;
-	} else if (cnt >= 10 && strncmp("bootloader", buf, 10) == 0) {
-		if (!(data->status & PICOLCD_BOOTLOADER))
-			report = picolcd_out_report(REPORT_EXIT_KEYBOARD, data->hdev);
-		buf += 10;
-		cnt -= 10;
-	}
-	if (!report)
-		return -EINVAL;
-
-	while (cnt > 0 && (buf[cnt-1] == '\n' || buf[cnt-1] == '\r'))
-		cnt--;
-	if (cnt != 0)
-		return -EINVAL;
-
-	spin_lock_irqsave(&data->lock, flags);
-	hid_set_field(report->field[0], 0, timeout & 0xff);
-	hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff);
-	usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-	spin_unlock_irqrestore(&data->lock, flags);
-	return count;
-}
-
-static DEVICE_ATTR(operation_mode, 0644, picolcd_operation_mode_show,
-		picolcd_operation_mode_store);
-
-/*
- * The "operation_mode_delay" sysfs attribute
- */
-static ssize_t picolcd_operation_mode_delay_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct picolcd_data *data = dev_get_drvdata(dev);
-
-	return snprintf(buf, PAGE_SIZE, "%hu\n", data->opmode_delay);
-}
-
-static ssize_t picolcd_operation_mode_delay_store(struct device *dev,
-		struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct picolcd_data *data = dev_get_drvdata(dev);
-	unsigned u;
-	if (sscanf(buf, "%u", &u) != 1)
-		return -EINVAL;
-	if (u > 30000)
-		return -EINVAL;
-	else
-		data->opmode_delay = u;
-	return count;
-}
-
-static DEVICE_ATTR(operation_mode_delay, 0644, picolcd_operation_mode_delay_show,
-		picolcd_operation_mode_delay_store);
-
-
-#ifdef CONFIG_DEBUG_FS
-/*
- * The "reset" file
- */
-static int picolcd_debug_reset_show(struct seq_file *f, void *p)
-{
-	if (picolcd_fbinfo((struct picolcd_data *)f->private))
-		seq_printf(f, "all fb\n");
-	else
-		seq_printf(f, "all\n");
-	return 0;
-}
-
-static int picolcd_debug_reset_open(struct inode *inode, struct file *f)
-{
-	return single_open(f, picolcd_debug_reset_show, inode->i_private);
-}
-
-static ssize_t picolcd_debug_reset_write(struct file *f, const char __user *user_buf,
-		size_t count, loff_t *ppos)
-{
-	struct picolcd_data *data = ((struct seq_file *)f->private_data)->private;
-	char buf[32];
-	size_t cnt = min(count, sizeof(buf)-1);
-	if (copy_from_user(buf, user_buf, cnt))
-		return -EFAULT;
-
-	while (cnt > 0 && (buf[cnt-1] == ' ' || buf[cnt-1] == '\n'))
-		cnt--;
-	buf[cnt] = '\0';
-	if (strcmp(buf, "all") == 0) {
-		picolcd_reset(data->hdev);
-		picolcd_fb_reset(data, 1);
-	} else if (strcmp(buf, "fb") == 0) {
-		picolcd_fb_reset(data, 1);
-	} else {
-		return -EINVAL;
-	}
-	return count;
-}
-
-static const struct file_operations picolcd_debug_reset_fops = {
-	.owner    = THIS_MODULE,
-	.open     = picolcd_debug_reset_open,
-	.read     = seq_read,
-	.llseek   = seq_lseek,
-	.write    = picolcd_debug_reset_write,
-	.release  = single_release,
-};
-
-/*
- * The "eeprom" file
- */
-static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u,
-		size_t s, loff_t *off)
-{
-	struct picolcd_data *data = f->private_data;
-	struct picolcd_pending *resp;
-	u8 raw_data[3];
-	ssize_t ret = -EIO;
-
-	if (s == 0)
-		return -EINVAL;
-	if (*off > 0x0ff)
-		return 0;
-
-	/* prepare buffer with info about what we want to read (addr & len) */
-	raw_data[0] = *off & 0xff;
-	raw_data[1] = (*off >> 8) & 0xff;
-	raw_data[2] = s < 20 ? s : 20;
-	if (*off + raw_data[2] > 0xff)
-		raw_data[2] = 0x100 - *off;
-	resp = picolcd_send_and_wait(data->hdev, REPORT_EE_READ, raw_data,
-			sizeof(raw_data));
-	if (!resp)
-		return -EIO;
-
-	if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) {
-		/* successful read :) */
-		ret = resp->raw_data[2];
-		if (ret > s)
-			ret = s;
-		if (copy_to_user(u, resp->raw_data+3, ret))
-			ret = -EFAULT;
-		else
-			*off += ret;
-	} /* anything else is some kind of IO error */
-
-	kfree(resp);
-	return ret;
-}
-
-static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u,
-		size_t s, loff_t *off)
-{
-	struct picolcd_data *data = f->private_data;
-	struct picolcd_pending *resp;
-	ssize_t ret = -EIO;
-	u8 raw_data[23];
-
-	if (s == 0)
-		return -EINVAL;
-	if (*off > 0x0ff)
-		return -ENOSPC;
-
-	memset(raw_data, 0, sizeof(raw_data));
-	raw_data[0] = *off & 0xff;
-	raw_data[1] = (*off >> 8) & 0xff;
-	raw_data[2] = min((size_t)20, s);
-	if (*off + raw_data[2] > 0xff)
-		raw_data[2] = 0x100 - *off;
-
-	if (copy_from_user(raw_data+3, u, min((u8)20, raw_data[2])))
-		return -EFAULT;
-	resp = picolcd_send_and_wait(data->hdev, REPORT_EE_WRITE, raw_data,
-			sizeof(raw_data));
-
-	if (!resp)
-		return -EIO;
-
-	if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) {
-		/* check if written data matches */
-		if (memcmp(raw_data, resp->raw_data, 3+raw_data[2]) == 0) {
-			*off += raw_data[2];
-			ret = raw_data[2];
-		}
-	}
-	kfree(resp);
-	return ret;
-}
-
-/*
- * Notes:
- * - read/write happens in chunks of at most 20 bytes, it's up to userspace
- *   to loop in order to get more data.
- * - on write errors on otherwise correct write request the bytes
- *   that should have been written are in undefined state.
- */
-static const struct file_operations picolcd_debug_eeprom_fops = {
-	.owner    = THIS_MODULE,
-	.open     = simple_open,
-	.read     = picolcd_debug_eeprom_read,
-	.write    = picolcd_debug_eeprom_write,
-	.llseek   = generic_file_llseek,
-};
-
-/*
- * The "flash" file
- */
-/* record a flash address to buf (bounds check to be done by caller) */
-static int _picolcd_flash_setaddr(struct picolcd_data *data, u8 *buf, long off)
-{
-	buf[0] = off & 0xff;
-	buf[1] = (off >> 8) & 0xff;
-	if (data->addr_sz == 3)
-		buf[2] = (off >> 16) & 0xff;
-	return data->addr_sz == 2 ? 2 : 3;
-}
-
-/* read a given size of data (bounds check to be done by caller) */
-static ssize_t _picolcd_flash_read(struct picolcd_data *data, int report_id,
-		char __user *u, size_t s, loff_t *off)
-{
-	struct picolcd_pending *resp;
-	u8 raw_data[4];
-	ssize_t ret = 0;
-	int len_off, err = -EIO;
-
-	while (s > 0) {
-		err = -EIO;
-		len_off = _picolcd_flash_setaddr(data, raw_data, *off);
-		raw_data[len_off] = s > 32 ? 32 : s;
-		resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off+1);
-		if (!resp || !resp->in_report)
-			goto skip;
-		if (resp->in_report->id == REPORT_MEMORY ||
-			resp->in_report->id == REPORT_BL_READ_MEMORY) {
-			if (memcmp(raw_data, resp->raw_data, len_off+1) != 0)
-				goto skip;
-			if (copy_to_user(u+ret, resp->raw_data+len_off+1, raw_data[len_off])) {
-				err = -EFAULT;
-				goto skip;
-			}
-			*off += raw_data[len_off];
-			s    -= raw_data[len_off];
-			ret  += raw_data[len_off];
-			err   = 0;
-		}
-skip:
-		kfree(resp);
-		if (err)
-			return ret > 0 ? ret : err;
-	}
-	return ret;
-}
-
-static ssize_t picolcd_debug_flash_read(struct file *f, char __user *u,
-		size_t s, loff_t *off)
-{
-	struct picolcd_data *data = f->private_data;
-
-	if (s == 0)
-		return -EINVAL;
-	if (*off > 0x05fff)
-		return 0;
-	if (*off + s > 0x05fff)
-		s = 0x06000 - *off;
-
-	if (data->status & PICOLCD_BOOTLOADER)
-		return _picolcd_flash_read(data, REPORT_BL_READ_MEMORY, u, s, off);
-	else
-		return _picolcd_flash_read(data, REPORT_READ_MEMORY, u, s, off);
-}
-
-/* erase block aligned to 64bytes boundary */
-static ssize_t _picolcd_flash_erase64(struct picolcd_data *data, int report_id,
-		loff_t *off)
-{
-	struct picolcd_pending *resp;
-	u8 raw_data[3];
-	int len_off;
-	ssize_t ret = -EIO;
-
-	if (*off & 0x3f)
-		return -EINVAL;
-
-	len_off = _picolcd_flash_setaddr(data, raw_data, *off);
-	resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off);
-	if (!resp || !resp->in_report)
-		goto skip;
-	if (resp->in_report->id == REPORT_MEMORY ||
-		resp->in_report->id == REPORT_BL_ERASE_MEMORY) {
-		if (memcmp(raw_data, resp->raw_data, len_off) != 0)
-			goto skip;
-		ret = 0;
-	}
-skip:
-	kfree(resp);
-	return ret;
-}
-
-/* write a given size of data (bounds check to be done by caller) */
-static ssize_t _picolcd_flash_write(struct picolcd_data *data, int report_id,
-		const char __user *u, size_t s, loff_t *off)
-{
-	struct picolcd_pending *resp;
-	u8 raw_data[36];
-	ssize_t ret = 0;
-	int len_off, err = -EIO;
-
-	while (s > 0) {
-		err = -EIO;
-		len_off = _picolcd_flash_setaddr(data, raw_data, *off);
-		raw_data[len_off] = s > 32 ? 32 : s;
-		if (copy_from_user(raw_data+len_off+1, u, raw_data[len_off])) {
-			err = -EFAULT;
-			break;
-		}
-		resp = picolcd_send_and_wait(data->hdev, report_id, raw_data,
-				len_off+1+raw_data[len_off]);
-		if (!resp || !resp->in_report)
-			goto skip;
-		if (resp->in_report->id == REPORT_MEMORY ||
-			resp->in_report->id == REPORT_BL_WRITE_MEMORY) {
-			if (memcmp(raw_data, resp->raw_data, len_off+1+raw_data[len_off]) != 0)
-				goto skip;
-			*off += raw_data[len_off];
-			s    -= raw_data[len_off];
-			ret  += raw_data[len_off];
-			err   = 0;
-		}
-skip:
-		kfree(resp);
-		if (err)
-			break;
-	}
-	return ret > 0 ? ret : err;
-}
-
-static ssize_t picolcd_debug_flash_write(struct file *f, const char __user *u,
-		size_t s, loff_t *off)
-{
-	struct picolcd_data *data = f->private_data;
-	ssize_t err, ret = 0;
-	int report_erase, report_write;
-
-	if (s == 0)
-		return -EINVAL;
-	if (*off > 0x5fff)
-		return -ENOSPC;
-	if (s & 0x3f)
-		return -EINVAL;
-	if (*off & 0x3f)
-		return -EINVAL;
-
-	if (data->status & PICOLCD_BOOTLOADER) {
-		report_erase = REPORT_BL_ERASE_MEMORY;
-		report_write = REPORT_BL_WRITE_MEMORY;
-	} else {
-		report_erase = REPORT_ERASE_MEMORY;
-		report_write = REPORT_WRITE_MEMORY;
-	}
-	mutex_lock(&data->mutex_flash);
-	while (s > 0) {
-		err = _picolcd_flash_erase64(data, report_erase, off);
-		if (err)
-			break;
-		err = _picolcd_flash_write(data, report_write, u, 64, off);
-		if (err < 0)
-			break;
-		ret += err;
-		*off += err;
-		s -= err;
-		if (err != 64)
-			break;
-	}
-	mutex_unlock(&data->mutex_flash);
-	return ret > 0 ? ret : err;
-}
-
-/*
- * Notes:
- * - concurrent writing is prevented by mutex and all writes must be
- *   n*64 bytes and 64-byte aligned, each write being preceded by an
- *   ERASE which erases a 64byte block.
- *   If less than requested was written or an error is returned for an
- *   otherwise correct write request the next 64-byte block which should
- *   have been written is in undefined state (mostly: original, erased,
- *   (half-)written with write error)
- * - reading can happen without special restriction
- */
-static const struct file_operations picolcd_debug_flash_fops = {
-	.owner    = THIS_MODULE,
-	.open     = simple_open,
-	.read     = picolcd_debug_flash_read,
-	.write    = picolcd_debug_flash_write,
-	.llseek   = generic_file_llseek,
-};
-
-
-/*
- * Helper code for HID report level dumping/debugging
- */
-static const char *error_codes[] = {
-	"success", "parameter missing", "data_missing", "block readonly",
-	"block not erasable", "block too big", "section overflow",
-	"invalid command length", "invalid data length",
-};
-
-static void dump_buff_as_hex(char *dst, size_t dst_sz, const u8 *data,
-		const size_t data_len)
-{
-	int i, j;
-	for (i = j = 0; i < data_len && j + 3 < dst_sz; i++) {
-		dst[j++] = hex_asc[(data[i] >> 4) & 0x0f];
-		dst[j++] = hex_asc[data[i] & 0x0f];
-		dst[j++] = ' ';
-	}
-	if (j < dst_sz) {
-		dst[j--] = '\0';
-		dst[j] = '\n';
-	} else
-		dst[j] = '\0';
-}
-
-static void picolcd_debug_out_report(struct picolcd_data *data,
-		struct hid_device *hdev, struct hid_report *report)
-{
-	u8 raw_data[70];
-	int raw_size = (report->size >> 3) + 1;
-	char *buff;
-#define BUFF_SZ 256
-
-	/* Avoid unnecessary overhead if debugfs is disabled */
-	if (list_empty(&hdev->debug_list))
-		return;
-
-	buff = kmalloc(BUFF_SZ, GFP_ATOMIC);
-	if (!buff)
-		return;
-
-	snprintf(buff, BUFF_SZ, "\nout report %d (size %d) =  ",
-			report->id, raw_size);
-	hid_debug_event(hdev, buff);
-	if (raw_size + 5 > sizeof(raw_data)) {
-		kfree(buff);
-		hid_debug_event(hdev, " TOO BIG\n");
-		return;
-	} else {
-		raw_data[0] = report->id;
-		hid_output_report(report, raw_data);
-		dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size);
-		hid_debug_event(hdev, buff);
-	}
-
-	switch (report->id) {
-	case REPORT_LED_STATE:
-		/* 1 data byte with GPO state */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_LED_STATE", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tGPO state: 0x%02x\n", raw_data[1]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_BRIGHTNESS:
-		/* 1 data byte with brightness */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_BRIGHTNESS", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tBrightness: 0x%02x\n", raw_data[1]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_CONTRAST:
-		/* 1 data byte with contrast */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_CONTRAST", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tContrast: 0x%02x\n", raw_data[1]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_RESET:
-		/* 2 data bytes with reset duration in ms */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_RESET", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tDuration: 0x%02x%02x (%dms)\n",
-				raw_data[2], raw_data[1], raw_data[2] << 8 | raw_data[1]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_LCD_CMD:
-		/* 63 data bytes with LCD commands */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_LCD_CMD", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		/* TODO: format decoding */
-		break;
-	case REPORT_LCD_DATA:
-		/* 63 data bytes with LCD data */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_LCD_CMD", report->id, raw_size-1);
-		/* TODO: format decoding */
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_LCD_CMD_DATA:
-		/* 63 data bytes with LCD commands and data */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_LCD_CMD", report->id, raw_size-1);
-		/* TODO: format decoding */
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_EE_READ:
-		/* 3 data bytes with read area description */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_EE_READ", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-				raw_data[2], raw_data[1]);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_EE_WRITE:
-		/* 3+1..20 data bytes with write area description */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_EE_WRITE", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-				raw_data[2], raw_data[1]);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-		hid_debug_event(hdev, buff);
-		if (raw_data[3] == 0) {
-			snprintf(buff, BUFF_SZ, "\tNo data\n");
-		} else if (raw_data[3] + 4 <= raw_size) {
-			snprintf(buff, BUFF_SZ, "\tData: ");
-			hid_debug_event(hdev, buff);
-			dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
-		} else {
-			snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-		}
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_ERASE_MEMORY:
-	case REPORT_BL_ERASE_MEMORY:
-		/* 3 data bytes with pointer inside erase block */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_ERASE_MEMORY", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		switch (data->addr_sz) {
-		case 2:
-			snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x\n",
-					raw_data[2], raw_data[1]);
-			break;
-		case 3:
-			snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x%02x\n",
-					raw_data[3], raw_data[2], raw_data[1]);
-			break;
-		default:
-			snprintf(buff, BUFF_SZ, "\tNot supported\n");
-		}
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_READ_MEMORY:
-	case REPORT_BL_READ_MEMORY:
-		/* 4 data bytes with read area description */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_READ_MEMORY", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		switch (data->addr_sz) {
-		case 2:
-			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-					raw_data[2], raw_data[1]);
-			hid_debug_event(hdev, buff);
-			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-			break;
-		case 3:
-			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
-					raw_data[3], raw_data[2], raw_data[1]);
-			hid_debug_event(hdev, buff);
-			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
-			break;
-		default:
-			snprintf(buff, BUFF_SZ, "\tNot supported\n");
-		}
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_WRITE_MEMORY:
-	case REPORT_BL_WRITE_MEMORY:
-		/* 4+1..32 data bytes with write adrea description */
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_WRITE_MEMORY", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		switch (data->addr_sz) {
-		case 2:
-			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-					raw_data[2], raw_data[1]);
-			hid_debug_event(hdev, buff);
-			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-			hid_debug_event(hdev, buff);
-			if (raw_data[3] == 0) {
-				snprintf(buff, BUFF_SZ, "\tNo data\n");
-			} else if (raw_data[3] + 4 <= raw_size) {
-				snprintf(buff, BUFF_SZ, "\tData: ");
-				hid_debug_event(hdev, buff);
-				dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
-			} else {
-				snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-			}
-			break;
-		case 3:
-			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
-					raw_data[3], raw_data[2], raw_data[1]);
-			hid_debug_event(hdev, buff);
-			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
-			hid_debug_event(hdev, buff);
-			if (raw_data[4] == 0) {
-				snprintf(buff, BUFF_SZ, "\tNo data\n");
-			} else if (raw_data[4] + 5 <= raw_size) {
-				snprintf(buff, BUFF_SZ, "\tData: ");
-				hid_debug_event(hdev, buff);
-				dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]);
-			} else {
-				snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-			}
-			break;
-		default:
-			snprintf(buff, BUFF_SZ, "\tNot supported\n");
-		}
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_SPLASH_RESTART:
-		/* TODO */
-		break;
-	case REPORT_EXIT_KEYBOARD:
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_EXIT_KEYBOARD", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n",
-				raw_data[1] | (raw_data[2] << 8),
-				raw_data[2], raw_data[1]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_VERSION:
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_VERSION", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_DEVID:
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_DEVID", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_SPLASH_SIZE:
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_SPLASH_SIZE", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_HOOK_VERSION:
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_HOOK_VERSION", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_EXIT_FLASHER:
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"REPORT_VERSION", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n",
-				raw_data[1] | (raw_data[2] << 8),
-				raw_data[2], raw_data[1]);
-		hid_debug_event(hdev, buff);
-		break;
-	default:
-		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-			"<unknown>", report->id, raw_size-1);
-		hid_debug_event(hdev, buff);
-		break;
-	}
-	wake_up_interruptible(&hdev->debug_wait);
-	kfree(buff);
-}
-
-static void picolcd_debug_raw_event(struct picolcd_data *data,
-		struct hid_device *hdev, struct hid_report *report,
-		u8 *raw_data, int size)
-{
-	char *buff;
-
-#define BUFF_SZ 256
-	/* Avoid unnecessary overhead if debugfs is disabled */
-	if (!hdev->debug_events)
-		return;
-
-	buff = kmalloc(BUFF_SZ, GFP_ATOMIC);
-	if (!buff)
-		return;
-
-	switch (report->id) {
-	case REPORT_ERROR_CODE:
-		/* 2 data bytes with affected report and error code */
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_ERROR_CODE", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		if (raw_data[2] < ARRAY_SIZE(error_codes))
-			snprintf(buff, BUFF_SZ, "\tError code 0x%02x (%s) in reply to report 0x%02x\n",
-					raw_data[2], error_codes[raw_data[2]], raw_data[1]);
-		else
-			snprintf(buff, BUFF_SZ, "\tError code 0x%02x in reply to report 0x%02x\n",
-					raw_data[2], raw_data[1]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_KEY_STATE:
-		/* 2 data bytes with key state */
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_KEY_STATE", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		if (raw_data[1] == 0)
-			snprintf(buff, BUFF_SZ, "\tNo key pressed\n");
-		else if (raw_data[2] == 0)
-			snprintf(buff, BUFF_SZ, "\tOne key pressed: 0x%02x (%d)\n",
-					raw_data[1], raw_data[1]);
-		else
-			snprintf(buff, BUFF_SZ, "\tTwo keys pressed: 0x%02x (%d), 0x%02x (%d)\n",
-					raw_data[1], raw_data[1], raw_data[2], raw_data[2]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_IR_DATA:
-		/* Up to 20 byes of IR scancode data */
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_IR_DATA", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		if (raw_data[1] == 0) {
-			snprintf(buff, BUFF_SZ, "\tUnexpectedly 0 data length\n");
-			hid_debug_event(hdev, buff);
-		} else if (raw_data[1] + 1 <= size) {
-			snprintf(buff, BUFF_SZ, "\tData length: %d\n\tIR Data: ",
-					raw_data[1]-1);
-			hid_debug_event(hdev, buff);
-			dump_buff_as_hex(buff, BUFF_SZ, raw_data+2, raw_data[1]-1);
-			hid_debug_event(hdev, buff);
-		} else {
-			snprintf(buff, BUFF_SZ, "\tOverflowing data length: %d\n",
-					raw_data[1]-1);
-			hid_debug_event(hdev, buff);
-		}
-		break;
-	case REPORT_EE_DATA:
-		/* Data buffer in response to REPORT_EE_READ or REPORT_EE_WRITE */
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_EE_DATA", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-				raw_data[2], raw_data[1]);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-		hid_debug_event(hdev, buff);
-		if (raw_data[3] == 0) {
-			snprintf(buff, BUFF_SZ, "\tNo data\n");
-			hid_debug_event(hdev, buff);
-		} else if (raw_data[3] + 4 <= size) {
-			snprintf(buff, BUFF_SZ, "\tData: ");
-			hid_debug_event(hdev, buff);
-			dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
-			hid_debug_event(hdev, buff);
-		} else {
-			snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-			hid_debug_event(hdev, buff);
-		}
-		break;
-	case REPORT_MEMORY:
-		/* Data buffer in response to REPORT_READ_MEMORY or REPORT_WRTIE_MEMORY */
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_MEMORY", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		switch (data->addr_sz) {
-		case 2:
-			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-					raw_data[2], raw_data[1]);
-			hid_debug_event(hdev, buff);
-			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-			hid_debug_event(hdev, buff);
-			if (raw_data[3] == 0) {
-				snprintf(buff, BUFF_SZ, "\tNo data\n");
-			} else if (raw_data[3] + 4 <= size) {
-				snprintf(buff, BUFF_SZ, "\tData: ");
-				hid_debug_event(hdev, buff);
-				dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
-			} else {
-				snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-			}
-			break;
-		case 3:
-			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
-					raw_data[3], raw_data[2], raw_data[1]);
-			hid_debug_event(hdev, buff);
-			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
-			hid_debug_event(hdev, buff);
-			if (raw_data[4] == 0) {
-				snprintf(buff, BUFF_SZ, "\tNo data\n");
-			} else if (raw_data[4] + 5 <= size) {
-				snprintf(buff, BUFF_SZ, "\tData: ");
-				hid_debug_event(hdev, buff);
-				dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]);
-			} else {
-				snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-			}
-			break;
-		default:
-			snprintf(buff, BUFF_SZ, "\tNot supported\n");
-		}
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_VERSION:
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_VERSION", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n",
-				raw_data[2], raw_data[1]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_BL_ERASE_MEMORY:
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_BL_ERASE_MEMORY", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		/* TODO */
-		break;
-	case REPORT_BL_READ_MEMORY:
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_BL_READ_MEMORY", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		/* TODO */
-		break;
-	case REPORT_BL_WRITE_MEMORY:
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_BL_WRITE_MEMORY", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		/* TODO */
-		break;
-	case REPORT_DEVID:
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_DEVID", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tSerial: 0x%02x%02x%02x%02x\n",
-				raw_data[1], raw_data[2], raw_data[3], raw_data[4]);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tType: 0x%02x\n",
-				raw_data[5]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_SPLASH_SIZE:
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_SPLASH_SIZE", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tTotal splash space: %d\n",
-				(raw_data[2] << 8) | raw_data[1]);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tUsed splash space: %d\n",
-				(raw_data[4] << 8) | raw_data[3]);
-		hid_debug_event(hdev, buff);
-		break;
-	case REPORT_HOOK_VERSION:
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"REPORT_HOOK_VERSION", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n",
-				raw_data[1], raw_data[2]);
-		hid_debug_event(hdev, buff);
-		break;
-	default:
-		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-			"<unknown>", report->id, size-1);
-		hid_debug_event(hdev, buff);
-		break;
-	}
-	wake_up_interruptible(&hdev->debug_wait);
-	kfree(buff);
-}
-
-static void picolcd_init_devfs(struct picolcd_data *data,
-		struct hid_report *eeprom_r, struct hid_report *eeprom_w,
-		struct hid_report *flash_r, struct hid_report *flash_w,
-		struct hid_report *reset)
-{
-	struct hid_device *hdev = data->hdev;
-
-	mutex_init(&data->mutex_flash);
-
-	/* reset */
-	if (reset)
-		data->debug_reset = debugfs_create_file("reset", 0600,
-				hdev->debug_dir, data, &picolcd_debug_reset_fops);
-
-	/* eeprom */
-	if (eeprom_r || eeprom_w)
-		data->debug_eeprom = debugfs_create_file("eeprom",
-			(eeprom_w ? S_IWUSR : 0) | (eeprom_r ? S_IRUSR : 0),
-			hdev->debug_dir, data, &picolcd_debug_eeprom_fops);
-
-	/* flash */
-	if (flash_r && flash_r->maxfield == 1 && flash_r->field[0]->report_size == 8)
-		data->addr_sz = flash_r->field[0]->report_count - 1;
-	else
-		data->addr_sz = -1;
-	if (data->addr_sz == 2 || data->addr_sz == 3) {
-		data->debug_flash = debugfs_create_file("flash",
-			(flash_w ? S_IWUSR : 0) | (flash_r ? S_IRUSR : 0),
-			hdev->debug_dir, data, &picolcd_debug_flash_fops);
-	} else if (flash_r || flash_w)
-		hid_warn(hdev, "Unexpected FLASH access reports, please submit rdesc for review\n");
-}
-
-static void picolcd_exit_devfs(struct picolcd_data *data)
-{
-	struct dentry *dent;
-
-	dent = data->debug_reset;
-	data->debug_reset = NULL;
-	if (dent)
-		debugfs_remove(dent);
-	dent = data->debug_eeprom;
-	data->debug_eeprom = NULL;
-	if (dent)
-		debugfs_remove(dent);
-	dent = data->debug_flash;
-	data->debug_flash = NULL;
-	if (dent)
-		debugfs_remove(dent);
-	mutex_destroy(&data->mutex_flash);
-}
-#else
-static inline void picolcd_debug_raw_event(struct picolcd_data *data,
-		struct hid_device *hdev, struct hid_report *report,
-		u8 *raw_data, int size)
-{
-}
-static inline void picolcd_init_devfs(struct picolcd_data *data,
-		struct hid_report *eeprom_r, struct hid_report *eeprom_w,
-		struct hid_report *flash_r, struct hid_report *flash_w,
-		struct hid_report *reset)
-{
-}
-static inline void picolcd_exit_devfs(struct picolcd_data *data)
-{
-}
-#endif /* CONFIG_DEBUG_FS */
-
-/*
- * Handle raw report as sent by device
- */
-static int picolcd_raw_event(struct hid_device *hdev,
-		struct hid_report *report, u8 *raw_data, int size)
-{
-	struct picolcd_data *data = hid_get_drvdata(hdev);
-	unsigned long flags;
-	int ret = 0;
-
-	if (!data)
-		return 1;
-
-	if (report->id == REPORT_KEY_STATE) {
-		if (data->input_keys)
-			ret = picolcd_raw_keypad(data, report, raw_data+1, size-1);
-	} else if (report->id == REPORT_IR_DATA) {
-		if (data->input_cir)
-			ret = picolcd_raw_cir(data, report, raw_data+1, size-1);
-	} else {
-		spin_lock_irqsave(&data->lock, flags);
-		/*
-		 * We let the caller of picolcd_send_and_wait() check if the
-		 * report we got is one of the expected ones or not.
-		 */
-		if (data->pending) {
-			memcpy(data->pending->raw_data, raw_data+1, size-1);
-			data->pending->raw_size  = size-1;
-			data->pending->in_report = report;
-			complete(&data->pending->ready);
-		}
-		spin_unlock_irqrestore(&data->lock, flags);
-	}
-
-	picolcd_debug_raw_event(data, hdev, report, raw_data, size);
-	return 1;
-}
-
-#ifdef CONFIG_PM
-static int picolcd_suspend(struct hid_device *hdev, pm_message_t message)
-{
-	if (PMSG_IS_AUTO(message))
-		return 0;
-
-	picolcd_suspend_backlight(hid_get_drvdata(hdev));
-	dbg_hid(PICOLCD_NAME " device ready for suspend\n");
-	return 0;
-}
-
-static int picolcd_resume(struct hid_device *hdev)
-{
-	int ret;
-	ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
-	if (ret)
-		dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
-	return 0;
-}
-
-static int picolcd_reset_resume(struct hid_device *hdev)
-{
-	int ret;
-	ret = picolcd_reset(hdev);
-	if (ret)
-		dbg_hid(PICOLCD_NAME " resetting our device failed: %d\n", ret);
-	ret = picolcd_fb_reset(hid_get_drvdata(hdev), 0);
-	if (ret)
-		dbg_hid(PICOLCD_NAME " restoring framebuffer content failed: %d\n", ret);
-	ret = picolcd_resume_lcd(hid_get_drvdata(hdev));
-	if (ret)
-		dbg_hid(PICOLCD_NAME " restoring lcd failed: %d\n", ret);
-	ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
-	if (ret)
-		dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
-	picolcd_leds_set(hid_get_drvdata(hdev));
-	return 0;
-}
-#endif
-
-/* initialize keypad input device */
-static int picolcd_init_keys(struct picolcd_data *data,
-		struct hid_report *report)
-{
-	struct hid_device *hdev = data->hdev;
-	struct input_dev *idev;
-	int error, i;
-
-	if (!report)
-		return -ENODEV;
-	if (report->maxfield != 1 || report->field[0]->report_count != 2 ||
-			report->field[0]->report_size != 8) {
-		hid_err(hdev, "unsupported KEY_STATE report\n");
-		return -EINVAL;
-	}
-
-	idev = input_allocate_device();
-	if (idev == NULL) {
-		hid_err(hdev, "failed to allocate input device\n");
-		return -ENOMEM;
-	}
-	input_set_drvdata(idev, hdev);
-	memcpy(data->keycode, def_keymap, sizeof(def_keymap));
-	idev->name = hdev->name;
-	idev->phys = hdev->phys;
-	idev->uniq = hdev->uniq;
-	idev->id.bustype = hdev->bus;
-	idev->id.vendor  = hdev->vendor;
-	idev->id.product = hdev->product;
-	idev->id.version = hdev->version;
-	idev->dev.parent = hdev->dev.parent;
-	idev->keycode     = &data->keycode;
-	idev->keycodemax  = PICOLCD_KEYS;
-	idev->keycodesize = sizeof(data->keycode[0]);
-	input_set_capability(idev, EV_MSC, MSC_SCAN);
-	set_bit(EV_REP, idev->evbit);
-	for (i = 0; i < PICOLCD_KEYS; i++)
-		input_set_capability(idev, EV_KEY, data->keycode[i]);
-	error = input_register_device(idev);
-	if (error) {
-		hid_err(hdev, "error registering the input device\n");
-		input_free_device(idev);
-		return error;
-	}
-	data->input_keys = idev;
-	return 0;
-}
-
-static void picolcd_exit_keys(struct picolcd_data *data)
-{
-	struct input_dev *idev = data->input_keys;
-
-	data->input_keys = NULL;
-	if (idev)
-		input_unregister_device(idev);
-}
-
-/* initialize CIR input device */
-static inline int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
-{
-	/* support not implemented yet */
-	return 0;
-}
-
-static inline void picolcd_exit_cir(struct picolcd_data *data)
-{
-}
-
-static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data)
-{
-	int error;
-
-	error = picolcd_check_version(hdev);
-	if (error)
-		return error;
-
-	if (data->version[0] != 0 && data->version[1] != 3)
-		hid_info(hdev, "Device with untested firmware revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
-			 dev_name(&hdev->dev));
-
-	/* Setup keypad input device */
-	error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev));
-	if (error)
-		goto err;
-
-	/* Setup CIR input device */
-	error = picolcd_init_cir(data, picolcd_in_report(REPORT_IR_DATA, hdev));
-	if (error)
-		goto err;
-
-	/* Set up the framebuffer device */
-	error = picolcd_init_framebuffer(data);
-	if (error)
-		goto err;
-
-	/* Setup lcd class device */
-	error = picolcd_init_lcd(data, picolcd_out_report(REPORT_CONTRAST, hdev));
-	if (error)
-		goto err;
-
-	/* Setup backlight class device */
-	error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev));
-	if (error)
-		goto err;
-
-	/* Setup the LED class devices */
-	error = picolcd_init_leds(data, picolcd_out_report(REPORT_LED_STATE, hdev));
-	if (error)
-		goto err;
-
-	picolcd_init_devfs(data, picolcd_out_report(REPORT_EE_READ, hdev),
-			picolcd_out_report(REPORT_EE_WRITE, hdev),
-			picolcd_out_report(REPORT_READ_MEMORY, hdev),
-			picolcd_out_report(REPORT_WRITE_MEMORY, hdev),
-			picolcd_out_report(REPORT_RESET, hdev));
-	return 0;
-err:
-	picolcd_exit_leds(data);
-	picolcd_exit_backlight(data);
-	picolcd_exit_lcd(data);
-	picolcd_exit_framebuffer(data);
-	picolcd_exit_cir(data);
-	picolcd_exit_keys(data);
-	return error;
-}
-
-static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data *data)
-{
-	int error;
-
-	error = picolcd_check_version(hdev);
-	if (error)
-		return error;
-
-	if (data->version[0] != 1 && data->version[1] != 0)
-		hid_info(hdev, "Device with untested bootloader revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
-			 dev_name(&hdev->dev));
-
-	picolcd_init_devfs(data, NULL, NULL,
-			picolcd_out_report(REPORT_BL_READ_MEMORY, hdev),
-			picolcd_out_report(REPORT_BL_WRITE_MEMORY, hdev), NULL);
-	return 0;
-}
-
-static int picolcd_probe(struct hid_device *hdev,
-		     const struct hid_device_id *id)
-{
-	struct picolcd_data *data;
-	int error = -ENOMEM;
-
-	dbg_hid(PICOLCD_NAME " hardware probe...\n");
-
-	/*
-	 * Let's allocate the picolcd data structure, set some reasonable
-	 * defaults, and associate it with the device
-	 */
-	data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL);
-	if (data == NULL) {
-		hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n");
-		error = -ENOMEM;
-		goto err_no_cleanup;
-	}
-
-	spin_lock_init(&data->lock);
-	mutex_init(&data->mutex);
-	data->hdev = hdev;
-	data->opmode_delay = 5000;
-	if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
-		data->status |= PICOLCD_BOOTLOADER;
-	hid_set_drvdata(hdev, data);
-
-	/* Parse the device reports and start it up */
-	error = hid_parse(hdev);
-	if (error) {
-		hid_err(hdev, "device report parse failed\n");
-		goto err_cleanup_data;
-	}
-
-	error = hid_hw_start(hdev, 0);
-	if (error) {
-		hid_err(hdev, "hardware start failed\n");
-		goto err_cleanup_data;
-	}
-
-	error = hid_hw_open(hdev);
-	if (error) {
-		hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n");
-		goto err_cleanup_hid_hw;
-	}
-
-	error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay);
-	if (error) {
-		hid_err(hdev, "failed to create sysfs attributes\n");
-		goto err_cleanup_hid_ll;
-	}
-
-	error = device_create_file(&hdev->dev, &dev_attr_operation_mode);
-	if (error) {
-		hid_err(hdev, "failed to create sysfs attributes\n");
-		goto err_cleanup_sysfs1;
-	}
-
-	if (data->status & PICOLCD_BOOTLOADER)
-		error = picolcd_probe_bootloader(hdev, data);
-	else
-		error = picolcd_probe_lcd(hdev, data);
-	if (error)
-		goto err_cleanup_sysfs2;
-
-	dbg_hid(PICOLCD_NAME " activated and initialized\n");
-	return 0;
-
-err_cleanup_sysfs2:
-	device_remove_file(&hdev->dev, &dev_attr_operation_mode);
-err_cleanup_sysfs1:
-	device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
-err_cleanup_hid_ll:
-	hid_hw_close(hdev);
-err_cleanup_hid_hw:
-	hid_hw_stop(hdev);
-err_cleanup_data:
-	kfree(data);
-err_no_cleanup:
-	hid_set_drvdata(hdev, NULL);
-
-	return error;
-}
-
-static void picolcd_remove(struct hid_device *hdev)
-{
-	struct picolcd_data *data = hid_get_drvdata(hdev);
-	unsigned long flags;
-
-	dbg_hid(PICOLCD_NAME " hardware remove...\n");
-	spin_lock_irqsave(&data->lock, flags);
-	data->status |= PICOLCD_FAILED;
-	spin_unlock_irqrestore(&data->lock, flags);
-#ifdef CONFIG_HID_PICOLCD_FB
-	/* short-circuit FB as early as possible in order to
-	 * avoid long delays if we host console.
-	 */
-	if (data->fb_info)
-		data->fb_info->par = NULL;
-#endif
-
-	picolcd_exit_devfs(data);
-	device_remove_file(&hdev->dev, &dev_attr_operation_mode);
-	device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
-	hid_hw_close(hdev);
-	hid_hw_stop(hdev);
-	hid_set_drvdata(hdev, NULL);
-
-	/* Shortcut potential pending reply that will never arrive */
-	spin_lock_irqsave(&data->lock, flags);
-	if (data->pending)
-		complete(&data->pending->ready);
-	spin_unlock_irqrestore(&data->lock, flags);
-
-	/* Cleanup LED */
-	picolcd_exit_leds(data);
-	/* Clean up the framebuffer */
-	picolcd_exit_backlight(data);
-	picolcd_exit_lcd(data);
-	picolcd_exit_framebuffer(data);
-	/* Cleanup input */
-	picolcd_exit_cir(data);
-	picolcd_exit_keys(data);
-
-	mutex_destroy(&data->mutex);
-	/* Finally, clean up the picolcd data itself */
-	kfree(data);
-}
-
-static const struct hid_device_id picolcd_devices[] = {
-	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
-	{ }
-};
-MODULE_DEVICE_TABLE(hid, picolcd_devices);
-
-static struct hid_driver picolcd_driver = {
-	.name =          "hid-picolcd",
-	.id_table =      picolcd_devices,
-	.probe =         picolcd_probe,
-	.remove =        picolcd_remove,
-	.raw_event =     picolcd_raw_event,
-#ifdef CONFIG_PM
-	.suspend =       picolcd_suspend,
-	.resume =        picolcd_resume,
-	.reset_resume =  picolcd_reset_resume,
-#endif
-};
-
-static int __init picolcd_init(void)
-{
-	return hid_register_driver(&picolcd_driver);
-}
-
-static void __exit picolcd_exit(void)
-{
-	hid_unregister_driver(&picolcd_driver);
-#ifdef CONFIG_HID_PICOLCD_FB
-	flush_work_sync(&picolcd_fb_cleanup);
-	WARN_ON(fb_pending);
-#endif
-}
-
-module_init(picolcd_init);
-module_exit(picolcd_exit);
-MODULE_DESCRIPTION("Minibox graphics PicoLCD Driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-picolcd.h b/drivers/hid/hid-picolcd.h
new file mode 100644
index 0000000..9200be1
--- /dev/null
+++ b/drivers/hid/hid-picolcd.h
@@ -0,0 +1,300 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   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, version 2 of the License.               *
+ *                                                                         *
+ *   This driver is distributed in the hope that it will be useful, but    *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#define PICOLCD_NAME "PicoLCD (graphic)"
+
+/* Report numbers */
+#define REPORT_ERROR_CODE      0x10 /* LCD: IN[16]  */
+#define   ERR_SUCCESS            0x00
+#define   ERR_PARAMETER_MISSING  0x01
+#define   ERR_DATA_MISSING       0x02
+#define   ERR_BLOCK_READ_ONLY    0x03
+#define   ERR_BLOCK_NOT_ERASABLE 0x04
+#define   ERR_BLOCK_TOO_BIG      0x05
+#define   ERR_SECTION_OVERFLOW   0x06
+#define   ERR_INVALID_CMD_LEN    0x07
+#define   ERR_INVALID_DATA_LEN   0x08
+#define REPORT_KEY_STATE       0x11 /* LCD: IN[2]   */
+#define REPORT_IR_DATA         0x21 /* LCD: IN[63]  */
+#define REPORT_EE_DATA         0x32 /* LCD: IN[63]  */
+#define REPORT_MEMORY          0x41 /* LCD: IN[63]  */
+#define REPORT_LED_STATE       0x81 /* LCD: OUT[1]  */
+#define REPORT_BRIGHTNESS      0x91 /* LCD: OUT[1]  */
+#define REPORT_CONTRAST        0x92 /* LCD: OUT[1]  */
+#define REPORT_RESET           0x93 /* LCD: OUT[2]  */
+#define REPORT_LCD_CMD         0x94 /* LCD: OUT[63] */
+#define REPORT_LCD_DATA        0x95 /* LCD: OUT[63] */
+#define REPORT_LCD_CMD_DATA    0x96 /* LCD: OUT[63] */
+#define	REPORT_EE_READ         0xa3 /* LCD: OUT[63] */
+#define REPORT_EE_WRITE        0xa4 /* LCD: OUT[63] */
+#define REPORT_ERASE_MEMORY    0xb2 /* LCD: OUT[2]  */
+#define REPORT_READ_MEMORY     0xb3 /* LCD: OUT[3]  */
+#define REPORT_WRITE_MEMORY    0xb4 /* LCD: OUT[63] */
+#define REPORT_SPLASH_RESTART  0xc1 /* LCD: OUT[1]  */
+#define REPORT_EXIT_KEYBOARD   0xef /* LCD: OUT[2]  */
+#define REPORT_VERSION         0xf1 /* LCD: IN[2],OUT[1]    Bootloader: IN[2],OUT[1]   */
+#define REPORT_BL_ERASE_MEMORY 0xf2 /*                      Bootloader: IN[36],OUT[4]  */
+#define REPORT_BL_READ_MEMORY  0xf3 /*                      Bootloader: IN[36],OUT[4]  */
+#define REPORT_BL_WRITE_MEMORY 0xf4 /*                      Bootloader: IN[36],OUT[36] */
+#define REPORT_DEVID           0xf5 /* LCD: IN[5], OUT[1]   Bootloader: IN[5],OUT[1]   */
+#define REPORT_SPLASH_SIZE     0xf6 /* LCD: IN[4], OUT[1]   */
+#define REPORT_HOOK_VERSION    0xf7 /* LCD: IN[2], OUT[1]   */
+#define REPORT_EXIT_FLASHER    0xff /*                      Bootloader: OUT[2]         */
+
+/* Description of in-progress IO operation, used for operations
+ * that trigger response from device */
+struct picolcd_pending {
+	struct hid_report *out_report;
+	struct hid_report *in_report;
+	struct completion ready;
+	int raw_size;
+	u8 raw_data[64];
+};
+
+
+#define PICOLCD_KEYS 17
+
+/* Per device data structure */
+struct picolcd_data {
+	struct hid_device *hdev;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debug_reset;
+	struct dentry *debug_eeprom;
+	struct dentry *debug_flash;
+	struct mutex mutex_flash;
+	int addr_sz;
+#endif
+	u8 version[2];
+	unsigned short opmode_delay;
+	/* input stuff */
+	u8 pressed_keys[2];
+	struct input_dev *input_keys;
+	struct input_dev *input_cir;
+	unsigned short keycode[PICOLCD_KEYS];
+
+#ifdef CONFIG_HID_PICOLCD_FB
+	/* Framebuffer stuff */
+	u8 fb_update_rate;
+	u8 fb_bpp;
+	u8 fb_force;
+	u8 *fb_vbitmap;		/* local copy of what was sent to PicoLCD */
+	u8 *fb_bitmap;		/* framebuffer */
+	struct fb_info *fb_info;
+#endif /* CONFIG_HID_PICOLCD_FB */
+#ifdef CONFIG_HID_PICOLCD_LCD
+	struct lcd_device *lcd;
+	u8 lcd_contrast;
+#endif /* CONFIG_HID_PICOLCD_LCD */
+#ifdef CONFIG_HID_PICOLCD_BACKLIGHT
+	struct backlight_device *backlight;
+	u8 lcd_brightness;
+	u8 lcd_power;
+#endif /* CONFIG_HID_PICOLCD_BACKLIGHT */
+#ifdef CONFIG_HID_PICOLCD_LEDS
+	/* LED stuff */
+	u8 led_state;
+	struct led_classdev *led[8];
+#endif /* CONFIG_HID_PICOLCD_LEDS */
+
+	/* Housekeeping stuff */
+	spinlock_t lock;
+	struct mutex mutex;
+	struct picolcd_pending *pending;
+	int status;
+#define PICOLCD_BOOTLOADER 1
+#define PICOLCD_FAILED 2
+#define PICOLCD_READY_FB 4
+};
+
+
+/* Find a given report */
+#define picolcd_in_report(id, dev) picolcd_report(id, dev, HID_INPUT_REPORT)
+#define picolcd_out_report(id, dev) picolcd_report(id, dev, HID_OUTPUT_REPORT)
+
+struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir);
+
+#ifdef CONFIG_DEBUG_FS
+void picolcd_debug_out_report(struct picolcd_data *data,
+		struct hid_device *hdev, struct hid_report *report);
+#define usbhid_submit_report(a, b, c) \
+	do { \
+		picolcd_debug_out_report(hid_get_drvdata(a), a, b); \
+		usbhid_submit_report(a, b, c); \
+	} while (0)
+
+void picolcd_debug_raw_event(struct picolcd_data *data,
+		struct hid_device *hdev, struct hid_report *report,
+		u8 *raw_data, int size);
+
+void picolcd_init_devfs(struct picolcd_data *data,
+		struct hid_report *eeprom_r, struct hid_report *eeprom_w,
+		struct hid_report *flash_r, struct hid_report *flash_w,
+		struct hid_report *reset);
+
+void picolcd_exit_devfs(struct picolcd_data *data);
+#else
+static inline void picolcd_debug_raw_event(struct picolcd_data *data,
+		struct hid_device *hdev, struct hid_report *report,
+		u8 *raw_data, int size)
+{
+}
+static inline void picolcd_init_devfs(struct picolcd_data *data,
+		struct hid_report *eeprom_r, struct hid_report *eeprom_w,
+		struct hid_report *flash_r, struct hid_report *flash_w,
+		struct hid_report *reset)
+{
+}
+static inline void picolcd_exit_devfs(struct picolcd_data *data)
+{
+}
+static inline void picolcd_debug_raw_event(struct picolcd_data *data,
+		struct hid_device *hdev, struct hid_report *report,
+		u8 *raw_data, int size)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
+
+#ifdef CONFIG_HID_PICOLCD_FB
+int picolcd_fb_reset(struct picolcd_data *data, int clear);
+
+int picolcd_init_framebuffer(struct picolcd_data *data);
+
+void picolcd_exit_framebuffer(struct picolcd_data *data);
+
+void picolcd_fb_refresh(struct picolcd_data *data);
+#define picolcd_fbinfo(d) ((d)->fb_info)
+#else
+static inline int picolcd_fb_reset(struct picolcd_data *data, int clear)
+{
+	return 0;
+}
+static inline int picolcd_init_framebuffer(struct picolcd_data *data)
+{
+	return 0;
+}
+static inline void picolcd_exit_framebuffer(struct picolcd_data *data)
+{
+}
+static inline void picolcd_fb_refresh(struct picolcd_data *data)
+{
+}
+#define picolcd_fbinfo(d) NULL
+#endif /* CONFIG_HID_PICOLCD_FB */
+
+
+#ifdef CONFIG_HID_PICOLCD_BACKLIGHT
+int picolcd_init_backlight(struct picolcd_data *data,
+		struct hid_report *report);
+
+void picolcd_exit_backlight(struct picolcd_data *data);
+
+int picolcd_resume_backlight(struct picolcd_data *data);
+
+void picolcd_suspend_backlight(struct picolcd_data *data);
+#else
+static inline int picolcd_init_backlight(struct picolcd_data *data,
+		struct hid_report *report)
+{
+	return 0;
+}
+static inline void picolcd_exit_backlight(struct picolcd_data *data)
+{
+}
+static inline int picolcd_resume_backlight(struct picolcd_data *data)
+{
+	return 0;
+}
+static inline void picolcd_suspend_backlight(struct picolcd_data *data)
+{
+}
+
+#endif /* CONFIG_HID_PICOLCD_BACKLIGHT */
+
+
+#ifdef CONFIG_HID_PICOLCD_LCD
+int picolcd_init_lcd(struct picolcd_data *data,
+		struct hid_report *report);
+
+void picolcd_exit_lcd(struct picolcd_data *data);
+
+int picolcd_resume_lcd(struct picolcd_data *data);
+#else
+static inline int picolcd_init_lcd(struct picolcd_data *data,
+		struct hid_report *report)
+{
+	return 0;
+}
+static inline void picolcd_exit_lcd(struct picolcd_data *data)
+{
+}
+static inline int picolcd_resume_lcd(struct picolcd_data *data)
+{
+	return 0;
+}
+#endif /* CONFIG_HID_PICOLCD_LCD */
+
+
+#ifdef CONFIG_HID_PICOLCD_LEDS
+int picolcd_init_leds(struct picolcd_data *data,
+		struct hid_report *report);
+
+void picolcd_exit_leds(struct picolcd_data *data);
+
+void picolcd_leds_set(struct picolcd_data *data);
+#else
+static inline int picolcd_init_leds(struct picolcd_data *data,
+		struct hid_report *report)
+{
+	return 0;
+}
+static inline void picolcd_exit_leds(struct picolcd_data *data)
+{
+}
+static inline void picolcd_leds_set(struct picolcd_data *data)
+{
+}
+#endif /* CONFIG_HID_PICOLCD_LEDS */
+
+
+#ifdef CONFIG_HID_PICOLCD_CIR
+int picolcd_raw_cir(struct picolcd_data *data,
+		struct hid_report *report, u8 *raw_data, int size);
+
+int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report);
+
+void picolcd_exit_cir(struct picolcd_data *data);
+#else
+static inline int picolcd_raw_cir(struct picolcd_data *data,
+		struct hid_report *report, u8 *raw_data, int size)
+{
+	return 1;
+}
+static inline int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
+{
+	return 0;
+}
+static inline void picolcd_exit_cir(struct picolcd_data *data)
+{
+}
+#endif /* CONFIG_HID_PICOLCD_LIRC */
+
+int picolcd_reset(struct hid_device *hdev);
+struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
+			int report_id, const u8 *raw_data, int size);
diff --git a/drivers/hid/hid-picolcd_backlight.c b/drivers/hid/hid-picolcd_backlight.c
new file mode 100644
index 0000000..b91f309
--- /dev/null
+++ b/drivers/hid/hid-picolcd_backlight.c
@@ -0,0 +1,122 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   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, version 2 of the License.               *
+ *                                                                         *
+ *   This driver is distributed in the hope that it will be useful, but    *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/backlight.h>
+
+#include "hid-picolcd.h"
+
+static int picolcd_get_brightness(struct backlight_device *bdev)
+{
+	struct picolcd_data *data = bl_get_data(bdev);
+	return data->lcd_brightness;
+}
+
+static int picolcd_set_brightness(struct backlight_device *bdev)
+{
+	struct picolcd_data *data = bl_get_data(bdev);
+	struct hid_report *report = picolcd_out_report(REPORT_BRIGHTNESS, data->hdev);
+	unsigned long flags;
+
+	if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
+		return -ENODEV;
+
+	data->lcd_brightness = bdev->props.brightness & 0x0ff;
+	data->lcd_power      = bdev->props.power;
+	spin_lock_irqsave(&data->lock, flags);
+	hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0);
+	if (!(data->status & PICOLCD_FAILED))
+		usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+	spin_unlock_irqrestore(&data->lock, flags);
+	return 0;
+}
+
+static int picolcd_check_bl_fb(struct backlight_device *bdev, struct fb_info *fb)
+{
+	return fb && fb == picolcd_fbinfo((struct picolcd_data *)bl_get_data(bdev));
+}
+
+static const struct backlight_ops picolcd_blops = {
+	.update_status  = picolcd_set_brightness,
+	.get_brightness = picolcd_get_brightness,
+	.check_fb       = picolcd_check_bl_fb,
+};
+
+int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *report)
+{
+	struct device *dev = &data->hdev->dev;
+	struct backlight_device *bdev;
+	struct backlight_properties props;
+	if (!report)
+		return -ENODEV;
+	if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
+			report->field[0]->report_size != 8) {
+		dev_err(dev, "unsupported BRIGHTNESS report");
+		return -EINVAL;
+	}
+
+	memset(&props, 0, sizeof(props));
+	props.type = BACKLIGHT_RAW;
+	props.max_brightness = 0xff;
+	bdev = backlight_device_register(dev_name(dev), dev, data,
+			&picolcd_blops, &props);
+	if (IS_ERR(bdev)) {
+		dev_err(dev, "failed to register backlight\n");
+		return PTR_ERR(bdev);
+	}
+	bdev->props.brightness     = 0xff;
+	data->lcd_brightness       = 0xff;
+	data->backlight            = bdev;
+	picolcd_set_brightness(bdev);
+	return 0;
+}
+
+void picolcd_exit_backlight(struct picolcd_data *data)
+{
+	struct backlight_device *bdev = data->backlight;
+
+	data->backlight = NULL;
+	if (bdev)
+		backlight_device_unregister(bdev);
+}
+
+int picolcd_resume_backlight(struct picolcd_data *data)
+{
+	if (!data->backlight)
+		return 0;
+	return picolcd_set_brightness(data->backlight);
+}
+
+#ifdef CONFIG_PM
+void picolcd_suspend_backlight(struct picolcd_data *data)
+{
+	int bl_power = data->lcd_power;
+	if (!data->backlight)
+		return;
+
+	data->backlight->props.power = FB_BLANK_POWERDOWN;
+	picolcd_set_brightness(data->backlight);
+	data->lcd_power = data->backlight->props.power = bl_power;
+}
+#endif /* CONFIG_PM */
+
diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c
new file mode 100644
index 0000000..dc632c3
--- /dev/null
+++ b/drivers/hid/hid-picolcd_cir.c
@@ -0,0 +1,61 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   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, version 2 of the License.               *
+ *                                                                         *
+ *   This driver is distributed in the hope that it will be useful, but    *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include <linux/hid-debug.h>
+#include <linux/input.h>
+#include "hid-ids.h"
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/vmalloc.h>
+#include <linux/backlight.h>
+#include <linux/lcd.h>
+
+#include <linux/leds.h>
+
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+
+#include <linux/completion.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+
+#include "hid-picolcd.h"
+
+
+int picolcd_raw_cir(struct picolcd_data *data,
+		struct hid_report *report, u8 *raw_data, int size)
+{
+	/* Need understanding of CIR data format to implement ... */
+	return 1;
+}
+
+/* initialize CIR input device */
+int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
+{
+	/* support not implemented yet */
+	return 0;
+}
+
+void picolcd_exit_cir(struct picolcd_data *data)
+{
+}
+
diff --git a/drivers/hid/hid-picolcd_core.c b/drivers/hid/hid-picolcd_core.c
new file mode 100644
index 0000000..2d7ef68
--- /dev/null
+++ b/drivers/hid/hid-picolcd_core.c
@@ -0,0 +1,712 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   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, version 2 of the License.               *
+ *                                                                         *
+ *   This driver is distributed in the hope that it will be useful, but    *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include <linux/hid-debug.h>
+#include <linux/input.h>
+#include "hid-ids.h"
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/vmalloc.h>
+
+#include <linux/completion.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+
+#include "hid-picolcd.h"
+
+
+/* Input device
+ *
+ * The PicoLCD has an IR receiver header, a built-in keypad with 5 keys
+ * and header for 4x4 key matrix. The built-in keys are part of the matrix.
+ */
+static const unsigned short def_keymap[PICOLCD_KEYS] = {
+	KEY_RESERVED,	/* none */
+	KEY_BACK,	/* col 4 + row 1 */
+	KEY_HOMEPAGE,	/* col 3 + row 1 */
+	KEY_RESERVED,	/* col 2 + row 1 */
+	KEY_RESERVED,	/* col 1 + row 1 */
+	KEY_SCROLLUP,	/* col 4 + row 2 */
+	KEY_OK,		/* col 3 + row 2 */
+	KEY_SCROLLDOWN,	/* col 2 + row 2 */
+	KEY_RESERVED,	/* col 1 + row 2 */
+	KEY_RESERVED,	/* col 4 + row 3 */
+	KEY_RESERVED,	/* col 3 + row 3 */
+	KEY_RESERVED,	/* col 2 + row 3 */
+	KEY_RESERVED,	/* col 1 + row 3 */
+	KEY_RESERVED,	/* col 4 + row 4 */
+	KEY_RESERVED,	/* col 3 + row 4 */
+	KEY_RESERVED,	/* col 2 + row 4 */
+	KEY_RESERVED,	/* col 1 + row 4 */
+};
+
+
+/* Find a given report */
+struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir)
+{
+	struct list_head *feature_report_list = &hdev->report_enum[dir].report_list;
+	struct hid_report *report = NULL;
+
+	list_for_each_entry(report, feature_report_list, list) {
+		if (report->id == id)
+			return report;
+	}
+	hid_warn(hdev, "No report with id 0x%x found\n", id);
+	return NULL;
+}
+
+/* Submit a report and wait for a reply from device - if device fades away
+ * or does not respond in time, return NULL */
+struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
+		int report_id, const u8 *raw_data, int size)
+{
+	struct picolcd_data *data = hid_get_drvdata(hdev);
+	struct picolcd_pending *work;
+	struct hid_report *report = picolcd_out_report(report_id, hdev);
+	unsigned long flags;
+	int i, j, k;
+
+	if (!report || !data)
+		return NULL;
+	if (data->status & PICOLCD_FAILED)
+		return NULL;
+	work = kzalloc(sizeof(*work), GFP_KERNEL);
+	if (!work)
+		return NULL;
+
+	init_completion(&work->ready);
+	work->out_report = report;
+	work->in_report  = NULL;
+	work->raw_size   = 0;
+
+	mutex_lock(&data->mutex);
+	spin_lock_irqsave(&data->lock, flags);
+	for (i = k = 0; i < report->maxfield; i++)
+		for (j = 0; j < report->field[i]->report_count; j++) {
+			hid_set_field(report->field[i], j, k < size ? raw_data[k] : 0);
+			k++;
+		}
+	if (data->status & PICOLCD_FAILED) {
+		kfree(work);
+		work = NULL;
+	} else {
+		data->pending = work;
+		usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+		spin_unlock_irqrestore(&data->lock, flags);
+		wait_for_completion_interruptible_timeout(&work->ready, HZ*2);
+		spin_lock_irqsave(&data->lock, flags);
+		data->pending = NULL;
+	}
+	spin_unlock_irqrestore(&data->lock, flags);
+	mutex_unlock(&data->mutex);
+	return work;
+}
+
+/*
+ * input class device
+ */
+static int picolcd_raw_keypad(struct picolcd_data *data,
+		struct hid_report *report, u8 *raw_data, int size)
+{
+	/*
+	 * Keypad event
+	 * First and second data bytes list currently pressed keys,
+	 * 0x00 means no key and at most 2 keys may be pressed at same time
+	 */
+	int i, j;
+
+	/* determine newly pressed keys */
+	for (i = 0; i < size; i++) {
+		unsigned int key_code;
+		if (raw_data[i] == 0)
+			continue;
+		for (j = 0; j < sizeof(data->pressed_keys); j++)
+			if (data->pressed_keys[j] == raw_data[i])
+				goto key_already_down;
+		for (j = 0; j < sizeof(data->pressed_keys); j++)
+			if (data->pressed_keys[j] == 0) {
+				data->pressed_keys[j] = raw_data[i];
+				break;
+			}
+		input_event(data->input_keys, EV_MSC, MSC_SCAN, raw_data[i]);
+		if (raw_data[i] < PICOLCD_KEYS)
+			key_code = data->keycode[raw_data[i]];
+		else
+			key_code = KEY_UNKNOWN;
+		if (key_code != KEY_UNKNOWN) {
+			dbg_hid(PICOLCD_NAME " got key press for %u:%d",
+					raw_data[i], key_code);
+			input_report_key(data->input_keys, key_code, 1);
+		}
+		input_sync(data->input_keys);
+key_already_down:
+		continue;
+	}
+
+	/* determine newly released keys */
+	for (j = 0; j < sizeof(data->pressed_keys); j++) {
+		unsigned int key_code;
+		if (data->pressed_keys[j] == 0)
+			continue;
+		for (i = 0; i < size; i++)
+			if (data->pressed_keys[j] == raw_data[i])
+				goto key_still_down;
+		input_event(data->input_keys, EV_MSC, MSC_SCAN, data->pressed_keys[j]);
+		if (data->pressed_keys[j] < PICOLCD_KEYS)
+			key_code = data->keycode[data->pressed_keys[j]];
+		else
+			key_code = KEY_UNKNOWN;
+		if (key_code != KEY_UNKNOWN) {
+			dbg_hid(PICOLCD_NAME " got key release for %u:%d",
+					data->pressed_keys[j], key_code);
+			input_report_key(data->input_keys, key_code, 0);
+		}
+		input_sync(data->input_keys);
+		data->pressed_keys[j] = 0;
+key_still_down:
+		continue;
+	}
+	return 1;
+}
+
+static int picolcd_check_version(struct hid_device *hdev)
+{
+	struct picolcd_data *data = hid_get_drvdata(hdev);
+	struct picolcd_pending *verinfo;
+	int ret = 0;
+
+	if (!data)
+		return -ENODEV;
+
+	verinfo = picolcd_send_and_wait(hdev, REPORT_VERSION, NULL, 0);
+	if (!verinfo) {
+		hid_err(hdev, "no version response from PicoLCD\n");
+		return -ENODEV;
+	}
+
+	if (verinfo->raw_size == 2) {
+		data->version[0] = verinfo->raw_data[1];
+		data->version[1] = verinfo->raw_data[0];
+		if (data->status & PICOLCD_BOOTLOADER) {
+			hid_info(hdev, "PicoLCD, bootloader version %d.%d\n",
+				 verinfo->raw_data[1], verinfo->raw_data[0]);
+		} else {
+			hid_info(hdev, "PicoLCD, firmware version %d.%d\n",
+				 verinfo->raw_data[1], verinfo->raw_data[0]);
+		}
+	} else {
+		hid_err(hdev, "confused, got unexpected version response from PicoLCD\n");
+		ret = -EINVAL;
+	}
+	kfree(verinfo);
+	return ret;
+}
+
+/*
+ * Reset our device and wait for answer to VERSION request
+ */
+int picolcd_reset(struct hid_device *hdev)
+{
+	struct picolcd_data *data = hid_get_drvdata(hdev);
+	struct hid_report *report = picolcd_out_report(REPORT_RESET, hdev);
+	unsigned long flags;
+	int error;
+
+	if (!data || !report || report->maxfield != 1)
+		return -ENODEV;
+
+	spin_lock_irqsave(&data->lock, flags);
+	if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
+		data->status |= PICOLCD_BOOTLOADER;
+
+	/* perform the reset */
+	hid_set_field(report->field[0], 0, 1);
+	if (data->status & PICOLCD_FAILED) {
+		spin_unlock_irqrestore(&data->lock, flags);
+		return -ENODEV;
+	}
+	usbhid_submit_report(hdev, report, USB_DIR_OUT);
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	error = picolcd_check_version(hdev);
+	if (error)
+		return error;
+
+	picolcd_resume_lcd(data);
+	picolcd_resume_backlight(data);
+	picolcd_fb_refresh(data);
+	picolcd_leds_set(data);
+	return 0;
+}
+
+/*
+ * The "operation_mode" sysfs attribute
+ */
+static ssize_t picolcd_operation_mode_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct picolcd_data *data = dev_get_drvdata(dev);
+
+	if (data->status & PICOLCD_BOOTLOADER)
+		return snprintf(buf, PAGE_SIZE, "[bootloader] lcd\n");
+	else
+		return snprintf(buf, PAGE_SIZE, "bootloader [lcd]\n");
+}
+
+static ssize_t picolcd_operation_mode_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct picolcd_data *data = dev_get_drvdata(dev);
+	struct hid_report *report = NULL;
+	size_t cnt = count;
+	int timeout = data->opmode_delay;
+	unsigned long flags;
+
+	if (cnt >= 3 && strncmp("lcd", buf, 3) == 0) {
+		if (data->status & PICOLCD_BOOTLOADER)
+			report = picolcd_out_report(REPORT_EXIT_FLASHER, data->hdev);
+		buf += 3;
+		cnt -= 3;
+	} else if (cnt >= 10 && strncmp("bootloader", buf, 10) == 0) {
+		if (!(data->status & PICOLCD_BOOTLOADER))
+			report = picolcd_out_report(REPORT_EXIT_KEYBOARD, data->hdev);
+		buf += 10;
+		cnt -= 10;
+	}
+	if (!report)
+		return -EINVAL;
+
+	while (cnt > 0 && (buf[cnt-1] == '\n' || buf[cnt-1] == '\r'))
+		cnt--;
+	if (cnt != 0)
+		return -EINVAL;
+
+	spin_lock_irqsave(&data->lock, flags);
+	hid_set_field(report->field[0], 0, timeout & 0xff);
+	hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff);
+	usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+	spin_unlock_irqrestore(&data->lock, flags);
+	return count;
+}
+
+static DEVICE_ATTR(operation_mode, 0644, picolcd_operation_mode_show,
+		picolcd_operation_mode_store);
+
+/*
+ * The "operation_mode_delay" sysfs attribute
+ */
+static ssize_t picolcd_operation_mode_delay_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct picolcd_data *data = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE, "%hu\n", data->opmode_delay);
+}
+
+static ssize_t picolcd_operation_mode_delay_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct picolcd_data *data = dev_get_drvdata(dev);
+	unsigned u;
+	if (sscanf(buf, "%u", &u) != 1)
+		return -EINVAL;
+	if (u > 30000)
+		return -EINVAL;
+	else
+		data->opmode_delay = u;
+	return count;
+}
+
+static DEVICE_ATTR(operation_mode_delay, 0644, picolcd_operation_mode_delay_show,
+		picolcd_operation_mode_delay_store);
+
+/*
+ * Handle raw report as sent by device
+ */
+static int picolcd_raw_event(struct hid_device *hdev,
+		struct hid_report *report, u8 *raw_data, int size)
+{
+	struct picolcd_data *data = hid_get_drvdata(hdev);
+	unsigned long flags;
+	int ret = 0;
+
+	if (!data)
+		return 1;
+
+	if (report->id == REPORT_KEY_STATE) {
+		if (data->input_keys)
+			ret = picolcd_raw_keypad(data, report, raw_data+1, size-1);
+	} else if (report->id == REPORT_IR_DATA) {
+		if (data->input_cir)
+			ret = picolcd_raw_cir(data, report, raw_data+1, size-1);
+	} else {
+		spin_lock_irqsave(&data->lock, flags);
+		/*
+		 * We let the caller of picolcd_send_and_wait() check if the
+		 * report we got is one of the expected ones or not.
+		 */
+		if (data->pending) {
+			memcpy(data->pending->raw_data, raw_data+1, size-1);
+			data->pending->raw_size  = size-1;
+			data->pending->in_report = report;
+			complete(&data->pending->ready);
+		}
+		spin_unlock_irqrestore(&data->lock, flags);
+	}
+
+	picolcd_debug_raw_event(data, hdev, report, raw_data, size);
+	return 1;
+}
+
+#ifdef CONFIG_PM
+static int picolcd_suspend(struct hid_device *hdev, pm_message_t message)
+{
+	if (PMSG_IS_AUTO(message))
+		return 0;
+
+	picolcd_suspend_backlight(hid_get_drvdata(hdev));
+	dbg_hid(PICOLCD_NAME " device ready for suspend\n");
+	return 0;
+}
+
+static int picolcd_resume(struct hid_device *hdev)
+{
+	int ret;
+	ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
+	if (ret)
+		dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
+	return 0;
+}
+
+static int picolcd_reset_resume(struct hid_device *hdev)
+{
+	int ret;
+	ret = picolcd_reset(hdev);
+	if (ret)
+		dbg_hid(PICOLCD_NAME " resetting our device failed: %d\n", ret);
+	ret = picolcd_fb_reset(hid_get_drvdata(hdev), 0);
+	if (ret)
+		dbg_hid(PICOLCD_NAME " restoring framebuffer content failed: %d\n", ret);
+	ret = picolcd_resume_lcd(hid_get_drvdata(hdev));
+	if (ret)
+		dbg_hid(PICOLCD_NAME " restoring lcd failed: %d\n", ret);
+	ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
+	if (ret)
+		dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
+	picolcd_leds_set(hid_get_drvdata(hdev));
+	return 0;
+}
+#endif
+
+/* initialize keypad input device */
+static int picolcd_init_keys(struct picolcd_data *data,
+		struct hid_report *report)
+{
+	struct hid_device *hdev = data->hdev;
+	struct input_dev *idev;
+	int error, i;
+
+	if (!report)
+		return -ENODEV;
+	if (report->maxfield != 1 || report->field[0]->report_count != 2 ||
+			report->field[0]->report_size != 8) {
+		hid_err(hdev, "unsupported KEY_STATE report\n");
+		return -EINVAL;
+	}
+
+	idev = input_allocate_device();
+	if (idev == NULL) {
+		hid_err(hdev, "failed to allocate input device\n");
+		return -ENOMEM;
+	}
+	input_set_drvdata(idev, hdev);
+	memcpy(data->keycode, def_keymap, sizeof(def_keymap));
+	idev->name = hdev->name;
+	idev->phys = hdev->phys;
+	idev->uniq = hdev->uniq;
+	idev->id.bustype = hdev->bus;
+	idev->id.vendor  = hdev->vendor;
+	idev->id.product = hdev->product;
+	idev->id.version = hdev->version;
+	idev->dev.parent = hdev->dev.parent;
+	idev->keycode     = &data->keycode;
+	idev->keycodemax  = PICOLCD_KEYS;
+	idev->keycodesize = sizeof(data->keycode[0]);
+	input_set_capability(idev, EV_MSC, MSC_SCAN);
+	set_bit(EV_REP, idev->evbit);
+	for (i = 0; i < PICOLCD_KEYS; i++)
+		input_set_capability(idev, EV_KEY, data->keycode[i]);
+	error = input_register_device(idev);
+	if (error) {
+		hid_err(hdev, "error registering the input device\n");
+		input_free_device(idev);
+		return error;
+	}
+	data->input_keys = idev;
+	return 0;
+}
+
+static void picolcd_exit_keys(struct picolcd_data *data)
+{
+	struct input_dev *idev = data->input_keys;
+
+	data->input_keys = NULL;
+	if (idev)
+		input_unregister_device(idev);
+}
+
+static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data)
+{
+	int error;
+
+	error = picolcd_check_version(hdev);
+	if (error)
+		return error;
+
+	if (data->version[0] != 0 && data->version[1] != 3)
+		hid_info(hdev, "Device with untested firmware revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
+			 dev_name(&hdev->dev));
+
+	/* Setup keypad input device */
+	error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev));
+	if (error)
+		goto err;
+
+	/* Setup CIR input device */
+	error = picolcd_init_cir(data, picolcd_in_report(REPORT_IR_DATA, hdev));
+	if (error)
+		goto err;
+
+	/* Set up the framebuffer device */
+	error = picolcd_init_framebuffer(data);
+	if (error)
+		goto err;
+
+	/* Setup lcd class device */
+	error = picolcd_init_lcd(data, picolcd_out_report(REPORT_CONTRAST, hdev));
+	if (error)
+		goto err;
+
+	/* Setup backlight class device */
+	error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev));
+	if (error)
+		goto err;
+
+	/* Setup the LED class devices */
+	error = picolcd_init_leds(data, picolcd_out_report(REPORT_LED_STATE, hdev));
+	if (error)
+		goto err;
+
+	picolcd_init_devfs(data, picolcd_out_report(REPORT_EE_READ, hdev),
+			picolcd_out_report(REPORT_EE_WRITE, hdev),
+			picolcd_out_report(REPORT_READ_MEMORY, hdev),
+			picolcd_out_report(REPORT_WRITE_MEMORY, hdev),
+			picolcd_out_report(REPORT_RESET, hdev));
+	return 0;
+err:
+	picolcd_exit_leds(data);
+	picolcd_exit_backlight(data);
+	picolcd_exit_lcd(data);
+	picolcd_exit_framebuffer(data);
+	picolcd_exit_cir(data);
+	picolcd_exit_keys(data);
+	return error;
+}
+
+static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data *data)
+{
+	int error;
+
+	error = picolcd_check_version(hdev);
+	if (error)
+		return error;
+
+	if (data->version[0] != 1 && data->version[1] != 0)
+		hid_info(hdev, "Device with untested bootloader revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
+			 dev_name(&hdev->dev));
+
+	picolcd_init_devfs(data, NULL, NULL,
+			picolcd_out_report(REPORT_BL_READ_MEMORY, hdev),
+			picolcd_out_report(REPORT_BL_WRITE_MEMORY, hdev), NULL);
+	return 0;
+}
+
+static int picolcd_probe(struct hid_device *hdev,
+		     const struct hid_device_id *id)
+{
+	struct picolcd_data *data;
+	int error = -ENOMEM;
+
+	dbg_hid(PICOLCD_NAME " hardware probe...\n");
+
+	/*
+	 * Let's allocate the picolcd data structure, set some reasonable
+	 * defaults, and associate it with the device
+	 */
+	data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL);
+	if (data == NULL) {
+		hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n");
+		error = -ENOMEM;
+		goto err_no_cleanup;
+	}
+
+	spin_lock_init(&data->lock);
+	mutex_init(&data->mutex);
+	data->hdev = hdev;
+	data->opmode_delay = 5000;
+	if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
+		data->status |= PICOLCD_BOOTLOADER;
+	hid_set_drvdata(hdev, data);
+
+	/* Parse the device reports and start it up */
+	error = hid_parse(hdev);
+	if (error) {
+		hid_err(hdev, "device report parse failed\n");
+		goto err_cleanup_data;
+	}
+
+	/* We don't use hidinput but hid_hw_start() fails if nothing is
+	 * claimed. So spoof claimed input. */
+	hdev->claimed = HID_CLAIMED_INPUT;
+	error = hid_hw_start(hdev, 0);
+	hdev->claimed = 0;
+	if (error) {
+		hid_err(hdev, "hardware start failed\n");
+		goto err_cleanup_data;
+	}
+
+	error = hid_hw_open(hdev);
+	if (error) {
+		hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n");
+		goto err_cleanup_hid_hw;
+	}
+
+	error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay);
+	if (error) {
+		hid_err(hdev, "failed to create sysfs attributes\n");
+		goto err_cleanup_hid_ll;
+	}
+
+	error = device_create_file(&hdev->dev, &dev_attr_operation_mode);
+	if (error) {
+		hid_err(hdev, "failed to create sysfs attributes\n");
+		goto err_cleanup_sysfs1;
+	}
+
+	if (data->status & PICOLCD_BOOTLOADER)
+		error = picolcd_probe_bootloader(hdev, data);
+	else
+		error = picolcd_probe_lcd(hdev, data);
+	if (error)
+		goto err_cleanup_sysfs2;
+
+	dbg_hid(PICOLCD_NAME " activated and initialized\n");
+	return 0;
+
+err_cleanup_sysfs2:
+	device_remove_file(&hdev->dev, &dev_attr_operation_mode);
+err_cleanup_sysfs1:
+	device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
+err_cleanup_hid_ll:
+	hid_hw_close(hdev);
+err_cleanup_hid_hw:
+	hid_hw_stop(hdev);
+err_cleanup_data:
+	kfree(data);
+err_no_cleanup:
+	hid_set_drvdata(hdev, NULL);
+
+	return error;
+}
+
+static void picolcd_remove(struct hid_device *hdev)
+{
+	struct picolcd_data *data = hid_get_drvdata(hdev);
+	unsigned long flags;
+
+	dbg_hid(PICOLCD_NAME " hardware remove...\n");
+	spin_lock_irqsave(&data->lock, flags);
+	data->status |= PICOLCD_FAILED;
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	picolcd_exit_devfs(data);
+	device_remove_file(&hdev->dev, &dev_attr_operation_mode);
+	device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
+	hid_hw_close(hdev);
+	hid_hw_stop(hdev);
+	hid_set_drvdata(hdev, NULL);
+
+	/* Shortcut potential pending reply that will never arrive */
+	spin_lock_irqsave(&data->lock, flags);
+	if (data->pending)
+		complete(&data->pending->ready);
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	/* Cleanup LED */
+	picolcd_exit_leds(data);
+	/* Clean up the framebuffer */
+	picolcd_exit_backlight(data);
+	picolcd_exit_lcd(data);
+	picolcd_exit_framebuffer(data);
+	/* Cleanup input */
+	picolcd_exit_cir(data);
+	picolcd_exit_keys(data);
+
+	mutex_destroy(&data->mutex);
+	/* Finally, clean up the picolcd data itself */
+	kfree(data);
+}
+
+static const struct hid_device_id picolcd_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, picolcd_devices);
+
+static struct hid_driver picolcd_driver = {
+	.name =          "hid-picolcd",
+	.id_table =      picolcd_devices,
+	.probe =         picolcd_probe,
+	.remove =        picolcd_remove,
+	.raw_event =     picolcd_raw_event,
+#ifdef CONFIG_PM
+	.suspend =       picolcd_suspend,
+	.resume =        picolcd_resume,
+	.reset_resume =  picolcd_reset_resume,
+#endif
+};
+
+static int __init picolcd_init(void)
+{
+	return hid_register_driver(&picolcd_driver);
+}
+
+static void __exit picolcd_exit(void)
+{
+	hid_unregister_driver(&picolcd_driver);
+}
+
+module_init(picolcd_init);
+module_exit(picolcd_exit);
+MODULE_DESCRIPTION("Minibox graphics PicoLCD Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-picolcd_debugfs.c b/drivers/hid/hid-picolcd_debugfs.c
new file mode 100644
index 0000000..f2491fa
--- /dev/null
+++ b/drivers/hid/hid-picolcd_debugfs.c
@@ -0,0 +1,898 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   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, version 2 of the License.               *
+ *                                                                         *
+ *   This driver is distributed in the hope that it will be useful, but    *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include <linux/hid-debug.h>
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+
+#include <linux/module.h>
+
+#include "hid-picolcd.h"
+
+
+static int picolcd_debug_reset_show(struct seq_file *f, void *p)
+{
+	if (picolcd_fbinfo((struct picolcd_data *)f->private))
+		seq_printf(f, "all fb\n");
+	else
+		seq_printf(f, "all\n");
+	return 0;
+}
+
+static int picolcd_debug_reset_open(struct inode *inode, struct file *f)
+{
+	return single_open(f, picolcd_debug_reset_show, inode->i_private);
+}
+
+static ssize_t picolcd_debug_reset_write(struct file *f, const char __user *user_buf,
+		size_t count, loff_t *ppos)
+{
+	struct picolcd_data *data = ((struct seq_file *)f->private_data)->private;
+	char buf[32];
+	size_t cnt = min(count, sizeof(buf)-1);
+	if (copy_from_user(buf, user_buf, cnt))
+		return -EFAULT;
+
+	while (cnt > 0 && (buf[cnt-1] == ' ' || buf[cnt-1] == '\n'))
+		cnt--;
+	buf[cnt] = '\0';
+	if (strcmp(buf, "all") == 0) {
+		picolcd_reset(data->hdev);
+		picolcd_fb_reset(data, 1);
+	} else if (strcmp(buf, "fb") == 0) {
+		picolcd_fb_reset(data, 1);
+	} else {
+		return -EINVAL;
+	}
+	return count;
+}
+
+static const struct file_operations picolcd_debug_reset_fops = {
+	.owner    = THIS_MODULE,
+	.open     = picolcd_debug_reset_open,
+	.read     = seq_read,
+	.llseek   = seq_lseek,
+	.write    = picolcd_debug_reset_write,
+	.release  = single_release,
+};
+
+/*
+ * The "eeprom" file
+ */
+static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u,
+		size_t s, loff_t *off)
+{
+	struct picolcd_data *data = f->private_data;
+	struct picolcd_pending *resp;
+	u8 raw_data[3];
+	ssize_t ret = -EIO;
+
+	if (s == 0)
+		return -EINVAL;
+	if (*off > 0x0ff)
+		return 0;
+
+	/* prepare buffer with info about what we want to read (addr & len) */
+	raw_data[0] = *off & 0xff;
+	raw_data[1] = (*off >> 8) & 0xff;
+	raw_data[2] = s < 20 ? s : 20;
+	if (*off + raw_data[2] > 0xff)
+		raw_data[2] = 0x100 - *off;
+	resp = picolcd_send_and_wait(data->hdev, REPORT_EE_READ, raw_data,
+			sizeof(raw_data));
+	if (!resp)
+		return -EIO;
+
+	if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) {
+		/* successful read :) */
+		ret = resp->raw_data[2];
+		if (ret > s)
+			ret = s;
+		if (copy_to_user(u, resp->raw_data+3, ret))
+			ret = -EFAULT;
+		else
+			*off += ret;
+	} /* anything else is some kind of IO error */
+
+	kfree(resp);
+	return ret;
+}
+
+static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u,
+		size_t s, loff_t *off)
+{
+	struct picolcd_data *data = f->private_data;
+	struct picolcd_pending *resp;
+	ssize_t ret = -EIO;
+	u8 raw_data[23];
+
+	if (s == 0)
+		return -EINVAL;
+	if (*off > 0x0ff)
+		return -ENOSPC;
+
+	memset(raw_data, 0, sizeof(raw_data));
+	raw_data[0] = *off & 0xff;
+	raw_data[1] = (*off >> 8) & 0xff;
+	raw_data[2] = min_t(size_t, 20, s);
+	if (*off + raw_data[2] > 0xff)
+		raw_data[2] = 0x100 - *off;
+
+	if (copy_from_user(raw_data+3, u, min((u8)20, raw_data[2])))
+		return -EFAULT;
+	resp = picolcd_send_and_wait(data->hdev, REPORT_EE_WRITE, raw_data,
+			sizeof(raw_data));
+
+	if (!resp)
+		return -EIO;
+
+	if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) {
+		/* check if written data matches */
+		if (memcmp(raw_data, resp->raw_data, 3+raw_data[2]) == 0) {
+			*off += raw_data[2];
+			ret = raw_data[2];
+		}
+	}
+	kfree(resp);
+	return ret;
+}
+
+/*
+ * Notes:
+ * - read/write happens in chunks of at most 20 bytes, it's up to userspace
+ *   to loop in order to get more data.
+ * - on write errors on otherwise correct write request the bytes
+ *   that should have been written are in undefined state.
+ */
+static const struct file_operations picolcd_debug_eeprom_fops = {
+	.owner    = THIS_MODULE,
+	.open     = simple_open,
+	.read     = picolcd_debug_eeprom_read,
+	.write    = picolcd_debug_eeprom_write,
+	.llseek   = generic_file_llseek,
+};
+
+/*
+ * The "flash" file
+ */
+/* record a flash address to buf (bounds check to be done by caller) */
+static int _picolcd_flash_setaddr(struct picolcd_data *data, u8 *buf, long off)
+{
+	buf[0] = off & 0xff;
+	buf[1] = (off >> 8) & 0xff;
+	if (data->addr_sz == 3)
+		buf[2] = (off >> 16) & 0xff;
+	return data->addr_sz == 2 ? 2 : 3;
+}
+
+/* read a given size of data (bounds check to be done by caller) */
+static ssize_t _picolcd_flash_read(struct picolcd_data *data, int report_id,
+		char __user *u, size_t s, loff_t *off)
+{
+	struct picolcd_pending *resp;
+	u8 raw_data[4];
+	ssize_t ret = 0;
+	int len_off, err = -EIO;
+
+	while (s > 0) {
+		err = -EIO;
+		len_off = _picolcd_flash_setaddr(data, raw_data, *off);
+		raw_data[len_off] = s > 32 ? 32 : s;
+		resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off+1);
+		if (!resp || !resp->in_report)
+			goto skip;
+		if (resp->in_report->id == REPORT_MEMORY ||
+			resp->in_report->id == REPORT_BL_READ_MEMORY) {
+			if (memcmp(raw_data, resp->raw_data, len_off+1) != 0)
+				goto skip;
+			if (copy_to_user(u+ret, resp->raw_data+len_off+1, raw_data[len_off])) {
+				err = -EFAULT;
+				goto skip;
+			}
+			*off += raw_data[len_off];
+			s    -= raw_data[len_off];
+			ret  += raw_data[len_off];
+			err   = 0;
+		}
+skip:
+		kfree(resp);
+		if (err)
+			return ret > 0 ? ret : err;
+	}
+	return ret;
+}
+
+static ssize_t picolcd_debug_flash_read(struct file *f, char __user *u,
+		size_t s, loff_t *off)
+{
+	struct picolcd_data *data = f->private_data;
+
+	if (s == 0)
+		return -EINVAL;
+	if (*off > 0x05fff)
+		return 0;
+	if (*off + s > 0x05fff)
+		s = 0x06000 - *off;
+
+	if (data->status & PICOLCD_BOOTLOADER)
+		return _picolcd_flash_read(data, REPORT_BL_READ_MEMORY, u, s, off);
+	else
+		return _picolcd_flash_read(data, REPORT_READ_MEMORY, u, s, off);
+}
+
+/* erase block aligned to 64bytes boundary */
+static ssize_t _picolcd_flash_erase64(struct picolcd_data *data, int report_id,
+		loff_t *off)
+{
+	struct picolcd_pending *resp;
+	u8 raw_data[3];
+	int len_off;
+	ssize_t ret = -EIO;
+
+	if (*off & 0x3f)
+		return -EINVAL;
+
+	len_off = _picolcd_flash_setaddr(data, raw_data, *off);
+	resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off);
+	if (!resp || !resp->in_report)
+		goto skip;
+	if (resp->in_report->id == REPORT_MEMORY ||
+		resp->in_report->id == REPORT_BL_ERASE_MEMORY) {
+		if (memcmp(raw_data, resp->raw_data, len_off) != 0)
+			goto skip;
+		ret = 0;
+	}
+skip:
+	kfree(resp);
+	return ret;
+}
+
+/* write a given size of data (bounds check to be done by caller) */
+static ssize_t _picolcd_flash_write(struct picolcd_data *data, int report_id,
+		const char __user *u, size_t s, loff_t *off)
+{
+	struct picolcd_pending *resp;
+	u8 raw_data[36];
+	ssize_t ret = 0;
+	int len_off, err = -EIO;
+
+	while (s > 0) {
+		err = -EIO;
+		len_off = _picolcd_flash_setaddr(data, raw_data, *off);
+		raw_data[len_off] = s > 32 ? 32 : s;
+		if (copy_from_user(raw_data+len_off+1, u, raw_data[len_off])) {
+			err = -EFAULT;
+			break;
+		}
+		resp = picolcd_send_and_wait(data->hdev, report_id, raw_data,
+				len_off+1+raw_data[len_off]);
+		if (!resp || !resp->in_report)
+			goto skip;
+		if (resp->in_report->id == REPORT_MEMORY ||
+			resp->in_report->id == REPORT_BL_WRITE_MEMORY) {
+			if (memcmp(raw_data, resp->raw_data, len_off+1+raw_data[len_off]) != 0)
+				goto skip;
+			*off += raw_data[len_off];
+			s    -= raw_data[len_off];
+			ret  += raw_data[len_off];
+			err   = 0;
+		}
+skip:
+		kfree(resp);
+		if (err)
+			break;
+	}
+	return ret > 0 ? ret : err;
+}
+
+static ssize_t picolcd_debug_flash_write(struct file *f, const char __user *u,
+		size_t s, loff_t *off)
+{
+	struct picolcd_data *data = f->private_data;
+	ssize_t err, ret = 0;
+	int report_erase, report_write;
+
+	if (s == 0)
+		return -EINVAL;
+	if (*off > 0x5fff)
+		return -ENOSPC;
+	if (s & 0x3f)
+		return -EINVAL;
+	if (*off & 0x3f)
+		return -EINVAL;
+
+	if (data->status & PICOLCD_BOOTLOADER) {
+		report_erase = REPORT_BL_ERASE_MEMORY;
+		report_write = REPORT_BL_WRITE_MEMORY;
+	} else {
+		report_erase = REPORT_ERASE_MEMORY;
+		report_write = REPORT_WRITE_MEMORY;
+	}
+	mutex_lock(&data->mutex_flash);
+	while (s > 0) {
+		err = _picolcd_flash_erase64(data, report_erase, off);
+		if (err)
+			break;
+		err = _picolcd_flash_write(data, report_write, u, 64, off);
+		if (err < 0)
+			break;
+		ret += err;
+		*off += err;
+		s -= err;
+		if (err != 64)
+			break;
+	}
+	mutex_unlock(&data->mutex_flash);
+	return ret > 0 ? ret : err;
+}
+
+/*
+ * Notes:
+ * - concurrent writing is prevented by mutex and all writes must be
+ *   n*64 bytes and 64-byte aligned, each write being preceded by an
+ *   ERASE which erases a 64byte block.
+ *   If less than requested was written or an error is returned for an
+ *   otherwise correct write request the next 64-byte block which should
+ *   have been written is in undefined state (mostly: original, erased,
+ *   (half-)written with write error)
+ * - reading can happen without special restriction
+ */
+static const struct file_operations picolcd_debug_flash_fops = {
+	.owner    = THIS_MODULE,
+	.open     = simple_open,
+	.read     = picolcd_debug_flash_read,
+	.write    = picolcd_debug_flash_write,
+	.llseek   = generic_file_llseek,
+};
+
+
+/*
+ * Helper code for HID report level dumping/debugging
+ */
+static const char * const error_codes[] = {
+	"success", "parameter missing", "data_missing", "block readonly",
+	"block not erasable", "block too big", "section overflow",
+	"invalid command length", "invalid data length",
+};
+
+static void dump_buff_as_hex(char *dst, size_t dst_sz, const u8 *data,
+		const size_t data_len)
+{
+	int i, j;
+	for (i = j = 0; i < data_len && j + 3 < dst_sz; i++) {
+		dst[j++] = hex_asc[(data[i] >> 4) & 0x0f];
+		dst[j++] = hex_asc[data[i] & 0x0f];
+		dst[j++] = ' ';
+	}
+	if (j < dst_sz) {
+		dst[j--] = '\0';
+		dst[j] = '\n';
+	} else
+		dst[j] = '\0';
+}
+
+void picolcd_debug_out_report(struct picolcd_data *data,
+		struct hid_device *hdev, struct hid_report *report)
+{
+	u8 raw_data[70];
+	int raw_size = (report->size >> 3) + 1;
+	char *buff;
+#define BUFF_SZ 256
+
+	/* Avoid unnecessary overhead if debugfs is disabled */
+	if (!hdev->debug_events)
+		return;
+
+	buff = kmalloc(BUFF_SZ, GFP_ATOMIC);
+	if (!buff)
+		return;
+
+	snprintf(buff, BUFF_SZ, "\nout report %d (size %d) =  ",
+			report->id, raw_size);
+	hid_debug_event(hdev, buff);
+	if (raw_size + 5 > sizeof(raw_data)) {
+		kfree(buff);
+		hid_debug_event(hdev, " TOO BIG\n");
+		return;
+	} else {
+		raw_data[0] = report->id;
+		hid_output_report(report, raw_data);
+		dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size);
+		hid_debug_event(hdev, buff);
+	}
+
+	switch (report->id) {
+	case REPORT_LED_STATE:
+		/* 1 data byte with GPO state */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_LED_STATE", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tGPO state: 0x%02x\n", raw_data[1]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_BRIGHTNESS:
+		/* 1 data byte with brightness */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_BRIGHTNESS", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tBrightness: 0x%02x\n", raw_data[1]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_CONTRAST:
+		/* 1 data byte with contrast */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_CONTRAST", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tContrast: 0x%02x\n", raw_data[1]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_RESET:
+		/* 2 data bytes with reset duration in ms */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_RESET", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tDuration: 0x%02x%02x (%dms)\n",
+				raw_data[2], raw_data[1], raw_data[2] << 8 | raw_data[1]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_LCD_CMD:
+		/* 63 data bytes with LCD commands */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_LCD_CMD", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		/* TODO: format decoding */
+		break;
+	case REPORT_LCD_DATA:
+		/* 63 data bytes with LCD data */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_LCD_CMD", report->id, raw_size-1);
+		/* TODO: format decoding */
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_LCD_CMD_DATA:
+		/* 63 data bytes with LCD commands and data */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_LCD_CMD", report->id, raw_size-1);
+		/* TODO: format decoding */
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_EE_READ:
+		/* 3 data bytes with read area description */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_EE_READ", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+				raw_data[2], raw_data[1]);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_EE_WRITE:
+		/* 3+1..20 data bytes with write area description */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_EE_WRITE", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+				raw_data[2], raw_data[1]);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+		hid_debug_event(hdev, buff);
+		if (raw_data[3] == 0) {
+			snprintf(buff, BUFF_SZ, "\tNo data\n");
+		} else if (raw_data[3] + 4 <= raw_size) {
+			snprintf(buff, BUFF_SZ, "\tData: ");
+			hid_debug_event(hdev, buff);
+			dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
+		} else {
+			snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+		}
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_ERASE_MEMORY:
+	case REPORT_BL_ERASE_MEMORY:
+		/* 3 data bytes with pointer inside erase block */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_ERASE_MEMORY", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		switch (data->addr_sz) {
+		case 2:
+			snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x\n",
+					raw_data[2], raw_data[1]);
+			break;
+		case 3:
+			snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x%02x\n",
+					raw_data[3], raw_data[2], raw_data[1]);
+			break;
+		default:
+			snprintf(buff, BUFF_SZ, "\tNot supported\n");
+		}
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_READ_MEMORY:
+	case REPORT_BL_READ_MEMORY:
+		/* 4 data bytes with read area description */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_READ_MEMORY", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		switch (data->addr_sz) {
+		case 2:
+			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+					raw_data[2], raw_data[1]);
+			hid_debug_event(hdev, buff);
+			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+			break;
+		case 3:
+			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
+					raw_data[3], raw_data[2], raw_data[1]);
+			hid_debug_event(hdev, buff);
+			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
+			break;
+		default:
+			snprintf(buff, BUFF_SZ, "\tNot supported\n");
+		}
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_WRITE_MEMORY:
+	case REPORT_BL_WRITE_MEMORY:
+		/* 4+1..32 data bytes with write adrea description */
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_WRITE_MEMORY", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		switch (data->addr_sz) {
+		case 2:
+			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+					raw_data[2], raw_data[1]);
+			hid_debug_event(hdev, buff);
+			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+			hid_debug_event(hdev, buff);
+			if (raw_data[3] == 0) {
+				snprintf(buff, BUFF_SZ, "\tNo data\n");
+			} else if (raw_data[3] + 4 <= raw_size) {
+				snprintf(buff, BUFF_SZ, "\tData: ");
+				hid_debug_event(hdev, buff);
+				dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
+			} else {
+				snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+			}
+			break;
+		case 3:
+			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
+					raw_data[3], raw_data[2], raw_data[1]);
+			hid_debug_event(hdev, buff);
+			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
+			hid_debug_event(hdev, buff);
+			if (raw_data[4] == 0) {
+				snprintf(buff, BUFF_SZ, "\tNo data\n");
+			} else if (raw_data[4] + 5 <= raw_size) {
+				snprintf(buff, BUFF_SZ, "\tData: ");
+				hid_debug_event(hdev, buff);
+				dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]);
+			} else {
+				snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+			}
+			break;
+		default:
+			snprintf(buff, BUFF_SZ, "\tNot supported\n");
+		}
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_SPLASH_RESTART:
+		/* TODO */
+		break;
+	case REPORT_EXIT_KEYBOARD:
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_EXIT_KEYBOARD", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n",
+				raw_data[1] | (raw_data[2] << 8),
+				raw_data[2], raw_data[1]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_VERSION:
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_VERSION", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_DEVID:
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_DEVID", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_SPLASH_SIZE:
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_SPLASH_SIZE", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_HOOK_VERSION:
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_HOOK_VERSION", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_EXIT_FLASHER:
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"REPORT_VERSION", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n",
+				raw_data[1] | (raw_data[2] << 8),
+				raw_data[2], raw_data[1]);
+		hid_debug_event(hdev, buff);
+		break;
+	default:
+		snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+			"<unknown>", report->id, raw_size-1);
+		hid_debug_event(hdev, buff);
+		break;
+	}
+	wake_up_interruptible(&hdev->debug_wait);
+	kfree(buff);
+}
+
+void picolcd_debug_raw_event(struct picolcd_data *data,
+		struct hid_device *hdev, struct hid_report *report,
+		u8 *raw_data, int size)
+{
+	char *buff;
+
+#define BUFF_SZ 256
+	/* Avoid unnecessary overhead if debugfs is disabled */
+	if (!hdev->debug_events)
+		return;
+
+	buff = kmalloc(BUFF_SZ, GFP_ATOMIC);
+	if (!buff)
+		return;
+
+	switch (report->id) {
+	case REPORT_ERROR_CODE:
+		/* 2 data bytes with affected report and error code */
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_ERROR_CODE", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		if (raw_data[2] < ARRAY_SIZE(error_codes))
+			snprintf(buff, BUFF_SZ, "\tError code 0x%02x (%s) in reply to report 0x%02x\n",
+					raw_data[2], error_codes[raw_data[2]], raw_data[1]);
+		else
+			snprintf(buff, BUFF_SZ, "\tError code 0x%02x in reply to report 0x%02x\n",
+					raw_data[2], raw_data[1]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_KEY_STATE:
+		/* 2 data bytes with key state */
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_KEY_STATE", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		if (raw_data[1] == 0)
+			snprintf(buff, BUFF_SZ, "\tNo key pressed\n");
+		else if (raw_data[2] == 0)
+			snprintf(buff, BUFF_SZ, "\tOne key pressed: 0x%02x (%d)\n",
+					raw_data[1], raw_data[1]);
+		else
+			snprintf(buff, BUFF_SZ, "\tTwo keys pressed: 0x%02x (%d), 0x%02x (%d)\n",
+					raw_data[1], raw_data[1], raw_data[2], raw_data[2]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_IR_DATA:
+		/* Up to 20 byes of IR scancode data */
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_IR_DATA", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		if (raw_data[1] == 0) {
+			snprintf(buff, BUFF_SZ, "\tUnexpectedly 0 data length\n");
+			hid_debug_event(hdev, buff);
+		} else if (raw_data[1] + 1 <= size) {
+			snprintf(buff, BUFF_SZ, "\tData length: %d\n\tIR Data: ",
+					raw_data[1]-1);
+			hid_debug_event(hdev, buff);
+			dump_buff_as_hex(buff, BUFF_SZ, raw_data+2, raw_data[1]-1);
+			hid_debug_event(hdev, buff);
+		} else {
+			snprintf(buff, BUFF_SZ, "\tOverflowing data length: %d\n",
+					raw_data[1]-1);
+			hid_debug_event(hdev, buff);
+		}
+		break;
+	case REPORT_EE_DATA:
+		/* Data buffer in response to REPORT_EE_READ or REPORT_EE_WRITE */
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_EE_DATA", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+				raw_data[2], raw_data[1]);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+		hid_debug_event(hdev, buff);
+		if (raw_data[3] == 0) {
+			snprintf(buff, BUFF_SZ, "\tNo data\n");
+			hid_debug_event(hdev, buff);
+		} else if (raw_data[3] + 4 <= size) {
+			snprintf(buff, BUFF_SZ, "\tData: ");
+			hid_debug_event(hdev, buff);
+			dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
+			hid_debug_event(hdev, buff);
+		} else {
+			snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+			hid_debug_event(hdev, buff);
+		}
+		break;
+	case REPORT_MEMORY:
+		/* Data buffer in response to REPORT_READ_MEMORY or REPORT_WRTIE_MEMORY */
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_MEMORY", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		switch (data->addr_sz) {
+		case 2:
+			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+					raw_data[2], raw_data[1]);
+			hid_debug_event(hdev, buff);
+			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+			hid_debug_event(hdev, buff);
+			if (raw_data[3] == 0) {
+				snprintf(buff, BUFF_SZ, "\tNo data\n");
+			} else if (raw_data[3] + 4 <= size) {
+				snprintf(buff, BUFF_SZ, "\tData: ");
+				hid_debug_event(hdev, buff);
+				dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
+			} else {
+				snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+			}
+			break;
+		case 3:
+			snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
+					raw_data[3], raw_data[2], raw_data[1]);
+			hid_debug_event(hdev, buff);
+			snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
+			hid_debug_event(hdev, buff);
+			if (raw_data[4] == 0) {
+				snprintf(buff, BUFF_SZ, "\tNo data\n");
+			} else if (raw_data[4] + 5 <= size) {
+				snprintf(buff, BUFF_SZ, "\tData: ");
+				hid_debug_event(hdev, buff);
+				dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]);
+			} else {
+				snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+			}
+			break;
+		default:
+			snprintf(buff, BUFF_SZ, "\tNot supported\n");
+		}
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_VERSION:
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_VERSION", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n",
+				raw_data[2], raw_data[1]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_BL_ERASE_MEMORY:
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_BL_ERASE_MEMORY", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		/* TODO */
+		break;
+	case REPORT_BL_READ_MEMORY:
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_BL_READ_MEMORY", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		/* TODO */
+		break;
+	case REPORT_BL_WRITE_MEMORY:
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_BL_WRITE_MEMORY", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		/* TODO */
+		break;
+	case REPORT_DEVID:
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_DEVID", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tSerial: 0x%02x%02x%02x%02x\n",
+				raw_data[1], raw_data[2], raw_data[3], raw_data[4]);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tType: 0x%02x\n",
+				raw_data[5]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_SPLASH_SIZE:
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_SPLASH_SIZE", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tTotal splash space: %d\n",
+				(raw_data[2] << 8) | raw_data[1]);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tUsed splash space: %d\n",
+				(raw_data[4] << 8) | raw_data[3]);
+		hid_debug_event(hdev, buff);
+		break;
+	case REPORT_HOOK_VERSION:
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"REPORT_HOOK_VERSION", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n",
+				raw_data[1], raw_data[2]);
+		hid_debug_event(hdev, buff);
+		break;
+	default:
+		snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+			"<unknown>", report->id, size-1);
+		hid_debug_event(hdev, buff);
+		break;
+	}
+	wake_up_interruptible(&hdev->debug_wait);
+	kfree(buff);
+}
+
+void picolcd_init_devfs(struct picolcd_data *data,
+		struct hid_report *eeprom_r, struct hid_report *eeprom_w,
+		struct hid_report *flash_r, struct hid_report *flash_w,
+		struct hid_report *reset)
+{
+	struct hid_device *hdev = data->hdev;
+
+	mutex_init(&data->mutex_flash);
+
+	/* reset */
+	if (reset)
+		data->debug_reset = debugfs_create_file("reset", 0600,
+				hdev->debug_dir, data, &picolcd_debug_reset_fops);
+
+	/* eeprom */
+	if (eeprom_r || eeprom_w)
+		data->debug_eeprom = debugfs_create_file("eeprom",
+			(eeprom_w ? S_IWUSR : 0) | (eeprom_r ? S_IRUSR : 0),
+			hdev->debug_dir, data, &picolcd_debug_eeprom_fops);
+
+	/* flash */
+	if (flash_r && flash_r->maxfield == 1 && flash_r->field[0]->report_size == 8)
+		data->addr_sz = flash_r->field[0]->report_count - 1;
+	else
+		data->addr_sz = -1;
+	if (data->addr_sz == 2 || data->addr_sz == 3) {
+		data->debug_flash = debugfs_create_file("flash",
+			(flash_w ? S_IWUSR : 0) | (flash_r ? S_IRUSR : 0),
+			hdev->debug_dir, data, &picolcd_debug_flash_fops);
+	} else if (flash_r || flash_w)
+		hid_warn(hdev, "Unexpected FLASH access reports, please submit rdesc for review\n");
+}
+
+void picolcd_exit_devfs(struct picolcd_data *data)
+{
+	struct dentry *dent;
+
+	dent = data->debug_reset;
+	data->debug_reset = NULL;
+	if (dent)
+		debugfs_remove(dent);
+	dent = data->debug_eeprom;
+	data->debug_eeprom = NULL;
+	if (dent)
+		debugfs_remove(dent);
+	dent = data->debug_flash;
+	data->debug_flash = NULL;
+	if (dent)
+		debugfs_remove(dent);
+	mutex_destroy(&data->mutex_flash);
+}
+
diff --git a/drivers/hid/hid-picolcd_fb.c b/drivers/hid/hid-picolcd_fb.c
new file mode 100644
index 0000000..cf295c5
--- /dev/null
+++ b/drivers/hid/hid-picolcd_fb.c
@@ -0,0 +1,605 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   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, version 2 of the License.               *
+ *                                                                         *
+ *   This driver is distributed in the hope that it will be useful, but    *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include <linux/vmalloc.h>
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/module.h>
+
+#include "hid-picolcd.h"
+
+/* Framebuffer
+ *
+ * The PicoLCD use a Topway LCD module of 256x64 pixel
+ * This display area is tiled over 4 controllers with 8 tiles
+ * each. Each tile has 8x64 pixel, each data byte representing
+ * a 1-bit wide vertical line of the tile.
+ *
+ * The display can be updated at a tile granularity.
+ *
+ *       Chip 1           Chip 2           Chip 3           Chip 4
+ * +----------------+----------------+----------------+----------------+
+ * |     Tile 1     |     Tile 1     |     Tile 1     |     Tile 1     |
+ * +----------------+----------------+----------------+----------------+
+ * |     Tile 2     |     Tile 2     |     Tile 2     |     Tile 2     |
+ * +----------------+----------------+----------------+----------------+
+ *                                  ...
+ * +----------------+----------------+----------------+----------------+
+ * |     Tile 8     |     Tile 8     |     Tile 8     |     Tile 8     |
+ * +----------------+----------------+----------------+----------------+
+ */
+#define PICOLCDFB_NAME "picolcdfb"
+#define PICOLCDFB_WIDTH (256)
+#define PICOLCDFB_HEIGHT (64)
+#define PICOLCDFB_SIZE (PICOLCDFB_WIDTH * PICOLCDFB_HEIGHT / 8)
+
+#define PICOLCDFB_UPDATE_RATE_LIMIT   10
+#define PICOLCDFB_UPDATE_RATE_DEFAULT  2
+
+/* Framebuffer visual structures */
+static const struct fb_fix_screeninfo picolcdfb_fix = {
+	.id          = PICOLCDFB_NAME,
+	.type        = FB_TYPE_PACKED_PIXELS,
+	.visual      = FB_VISUAL_MONO01,
+	.xpanstep    = 0,
+	.ypanstep    = 0,
+	.ywrapstep   = 0,
+	.line_length = PICOLCDFB_WIDTH / 8,
+	.accel       = FB_ACCEL_NONE,
+};
+
+static const struct fb_var_screeninfo picolcdfb_var = {
+	.xres           = PICOLCDFB_WIDTH,
+	.yres           = PICOLCDFB_HEIGHT,
+	.xres_virtual   = PICOLCDFB_WIDTH,
+	.yres_virtual   = PICOLCDFB_HEIGHT,
+	.width          = 103,
+	.height         = 26,
+	.bits_per_pixel = 1,
+	.grayscale      = 1,
+	.red            = {
+		.offset = 0,
+		.length = 1,
+		.msb_right = 0,
+	},
+	.green          = {
+		.offset = 0,
+		.length = 1,
+		.msb_right = 0,
+	},
+	.blue           = {
+		.offset = 0,
+		.length = 1,
+		.msb_right = 0,
+	},
+	.transp         = {
+		.offset = 0,
+		.length = 0,
+		.msb_right = 0,
+	},
+};
+
+/* Send a given tile to PicoLCD */
+static int picolcd_fb_send_tile(struct hid_device *hdev, int chip, int tile)
+{
+	struct picolcd_data *data = hid_get_drvdata(hdev);
+	struct hid_report *report1 = picolcd_out_report(REPORT_LCD_CMD_DATA, hdev);
+	struct hid_report *report2 = picolcd_out_report(REPORT_LCD_DATA, hdev);
+	unsigned long flags;
+	u8 *tdata;
+	int i;
+
+	if (!report1 || report1->maxfield != 1 || !report2 || report2->maxfield != 1)
+		return -ENODEV;
+
+	spin_lock_irqsave(&data->lock, flags);
+	hid_set_field(report1->field[0],  0, chip << 2);
+	hid_set_field(report1->field[0],  1, 0x02);
+	hid_set_field(report1->field[0],  2, 0x00);
+	hid_set_field(report1->field[0],  3, 0x00);
+	hid_set_field(report1->field[0],  4, 0xb8 | tile);
+	hid_set_field(report1->field[0],  5, 0x00);
+	hid_set_field(report1->field[0],  6, 0x00);
+	hid_set_field(report1->field[0],  7, 0x40);
+	hid_set_field(report1->field[0],  8, 0x00);
+	hid_set_field(report1->field[0],  9, 0x00);
+	hid_set_field(report1->field[0], 10,   32);
+
+	hid_set_field(report2->field[0],  0, (chip << 2) | 0x01);
+	hid_set_field(report2->field[0],  1, 0x00);
+	hid_set_field(report2->field[0],  2, 0x00);
+	hid_set_field(report2->field[0],  3,   32);
+
+	tdata = data->fb_vbitmap + (tile * 4 + chip) * 64;
+	for (i = 0; i < 64; i++)
+		if (i < 32)
+			hid_set_field(report1->field[0], 11 + i, tdata[i]);
+		else
+			hid_set_field(report2->field[0], 4 + i - 32, tdata[i]);
+
+	usbhid_submit_report(data->hdev, report1, USB_DIR_OUT);
+	usbhid_submit_report(data->hdev, report2, USB_DIR_OUT);
+	spin_unlock_irqrestore(&data->lock, flags);
+	return 0;
+}
+
+/* Translate a single tile*/
+static int picolcd_fb_update_tile(u8 *vbitmap, const u8 *bitmap, int bpp,
+		int chip, int tile)
+{
+	int i, b, changed = 0;
+	u8 tdata[64];
+	u8 *vdata = vbitmap + (tile * 4 + chip) * 64;
+
+	if (bpp == 1) {
+		for (b = 7; b >= 0; b--) {
+			const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32;
+			for (i = 0; i < 64; i++) {
+				tdata[i] <<= 1;
+				tdata[i] |= (bdata[i/8] >> (i % 8)) & 0x01;
+			}
+		}
+	} else if (bpp == 8) {
+		for (b = 7; b >= 0; b--) {
+			const u8 *bdata = bitmap + (tile * 256 + chip * 8 + b * 32) * 8;
+			for (i = 0; i < 64; i++) {
+				tdata[i] <<= 1;
+				tdata[i] |= (bdata[i] & 0x80) ? 0x01 : 0x00;
+			}
+		}
+	} else {
+		/* Oops, we should never get here! */
+		WARN_ON(1);
+		return 0;
+	}
+
+	for (i = 0; i < 64; i++)
+		if (tdata[i] != vdata[i]) {
+			changed = 1;
+			vdata[i] = tdata[i];
+		}
+	return changed;
+}
+
+void picolcd_fb_refresh(struct picolcd_data *data)
+{
+	if (data->fb_info)
+		schedule_delayed_work(&data->fb_info->deferred_work, 0);
+}
+
+/* Reconfigure LCD display */
+int picolcd_fb_reset(struct picolcd_data *data, int clear)
+{
+	struct hid_report *report = picolcd_out_report(REPORT_LCD_CMD, data->hdev);
+	int i, j;
+	unsigned long flags;
+	static const u8 mapcmd[8] = { 0x00, 0x02, 0x00, 0x64, 0x3f, 0x00, 0x64, 0xc0 };
+
+	if (!report || report->maxfield != 1)
+		return -ENODEV;
+
+	spin_lock_irqsave(&data->lock, flags);
+	for (i = 0; i < 4; i++) {
+		for (j = 0; j < report->field[0]->maxusage; j++)
+			if (j == 0)
+				hid_set_field(report->field[0], j, i << 2);
+			else if (j < sizeof(mapcmd))
+				hid_set_field(report->field[0], j, mapcmd[j]);
+			else
+				hid_set_field(report->field[0], j, 0);
+		usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+	}
+
+	data->status |= PICOLCD_READY_FB;
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	if (data->fb_bitmap) {
+		if (clear) {
+			memset(data->fb_vbitmap, 0, PICOLCDFB_SIZE);
+			memset(data->fb_bitmap, 0, PICOLCDFB_SIZE*data->fb_bpp);
+		}
+		data->fb_force = 1;
+	}
+
+	/* schedule first output of framebuffer */
+	picolcd_fb_refresh(data);
+
+	return 0;
+}
+
+/* Update fb_vbitmap from the screen_base and send changed tiles to device */
+static void picolcd_fb_update(struct fb_info *info)
+{
+	int chip, tile, n;
+	unsigned long flags;
+	struct picolcd_data *data;
+
+	mutex_lock(&info->lock);
+	data = info->par;
+	if (!data)
+		goto out;
+
+	spin_lock_irqsave(&data->lock, flags);
+	if (!(data->status & PICOLCD_READY_FB)) {
+		spin_unlock_irqrestore(&data->lock, flags);
+		picolcd_fb_reset(data, 0);
+	} else {
+		spin_unlock_irqrestore(&data->lock, flags);
+	}
+
+	/*
+	 * Translate the framebuffer into the format needed by the PicoLCD.
+	 * See display layout above.
+	 * Do this one tile after the other and push those tiles that changed.
+	 *
+	 * Wait for our IO to complete as otherwise we might flood the queue!
+	 */
+	n = 0;
+	for (chip = 0; chip < 4; chip++)
+		for (tile = 0; tile < 8; tile++)
+			if (picolcd_fb_update_tile(data->fb_vbitmap,
+					data->fb_bitmap, data->fb_bpp, chip, tile) ||
+				data->fb_force) {
+				n += 2;
+				if (n >= HID_OUTPUT_FIFO_SIZE / 2) {
+					mutex_unlock(&info->lock);
+					usbhid_wait_io(data->hdev);
+					mutex_lock(&info->lock);
+					data = info->par;
+					if (!data)
+						goto out;
+					spin_lock_irqsave(&data->lock, flags);
+					if (data->status & PICOLCD_FAILED) {
+						spin_unlock_irqrestore(&data->lock, flags);
+						goto out;
+					}
+					spin_unlock_irqrestore(&data->lock, flags);
+					n = 0;
+				}
+				picolcd_fb_send_tile(data->hdev, chip, tile);
+			}
+	data->fb_force = false;
+	if (n) {
+		mutex_unlock(&info->lock);
+		usbhid_wait_io(data->hdev);
+		return;
+	}
+out:
+	mutex_unlock(&info->lock);
+}
+
+/* Stub to call the system default and update the image on the picoLCD */
+static void picolcd_fb_fillrect(struct fb_info *info,
+		const struct fb_fillrect *rect)
+{
+	if (!info->par)
+		return;
+	sys_fillrect(info, rect);
+
+	schedule_delayed_work(&info->deferred_work, 0);
+}
+
+/* Stub to call the system default and update the image on the picoLCD */
+static void picolcd_fb_copyarea(struct fb_info *info,
+		const struct fb_copyarea *area)
+{
+	if (!info->par)
+		return;
+	sys_copyarea(info, area);
+
+	schedule_delayed_work(&info->deferred_work, 0);
+}
+
+/* Stub to call the system default and update the image on the picoLCD */
+static void picolcd_fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	if (!info->par)
+		return;
+	sys_imageblit(info, image);
+
+	schedule_delayed_work(&info->deferred_work, 0);
+}
+
+/*
+ * this is the slow path from userspace. they can seek and write to
+ * the fb. it's inefficient to do anything less than a full screen draw
+ */
+static ssize_t picolcd_fb_write(struct fb_info *info, const char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	ssize_t ret;
+	if (!info->par)
+		return -ENODEV;
+	ret = fb_sys_write(info, buf, count, ppos);
+	if (ret >= 0)
+		schedule_delayed_work(&info->deferred_work, 0);
+	return ret;
+}
+
+static int picolcd_fb_blank(int blank, struct fb_info *info)
+{
+	if (!info->par)
+		return -ENODEV;
+	/* We let fb notification do this for us via lcd/backlight device */
+	return 0;
+}
+
+static void picolcd_fb_destroy(struct fb_info *info)
+{
+	/* make sure no work is deferred */
+	fb_deferred_io_cleanup(info);
+
+	vfree((u8 *)info->fix.smem_start);
+	framebuffer_release(info);
+	printk(KERN_DEBUG "picolcd_fb_destroy(%p)\n", info);
+}
+
+static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	__u32 bpp      = var->bits_per_pixel;
+	__u32 activate = var->activate;
+
+	/* only allow 1/8 bit depth (8-bit is grayscale) */
+	*var = picolcdfb_var;
+	var->activate = activate;
+	if (bpp >= 8) {
+		var->bits_per_pixel = 8;
+		var->red.length     = 8;
+		var->green.length   = 8;
+		var->blue.length    = 8;
+	} else {
+		var->bits_per_pixel = 1;
+		var->red.length     = 1;
+		var->green.length   = 1;
+		var->blue.length    = 1;
+	}
+	return 0;
+}
+
+static int picolcd_set_par(struct fb_info *info)
+{
+	struct picolcd_data *data = info->par;
+	u8 *tmp_fb, *o_fb;
+	if (!data)
+		return -ENODEV;
+	if (info->var.bits_per_pixel == data->fb_bpp)
+		return 0;
+	/* switch between 1/8 bit depths */
+	if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8)
+		return -EINVAL;
+
+	o_fb   = data->fb_bitmap;
+	tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL);
+	if (!tmp_fb)
+		return -ENOMEM;
+
+	/* translate FB content to new bits-per-pixel */
+	if (info->var.bits_per_pixel == 1) {
+		int i, b;
+		for (i = 0; i < PICOLCDFB_SIZE; i++) {
+			u8 p = 0;
+			for (b = 0; b < 8; b++) {
+				p <<= 1;
+				p |= o_fb[i*8+b] ? 0x01 : 0x00;
+			}
+			tmp_fb[i] = p;
+		}
+		memcpy(o_fb, tmp_fb, PICOLCDFB_SIZE);
+		info->fix.visual = FB_VISUAL_MONO01;
+		info->fix.line_length = PICOLCDFB_WIDTH / 8;
+	} else {
+		int i;
+		memcpy(tmp_fb, o_fb, PICOLCDFB_SIZE);
+		for (i = 0; i < PICOLCDFB_SIZE * 8; i++)
+			o_fb[i] = tmp_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00;
+		info->fix.visual = FB_VISUAL_DIRECTCOLOR;
+		info->fix.line_length = PICOLCDFB_WIDTH;
+	}
+
+	kfree(tmp_fb);
+	data->fb_bpp      = info->var.bits_per_pixel;
+	return 0;
+}
+
+/* Note this can't be const because of struct fb_info definition */
+static struct fb_ops picolcdfb_ops = {
+	.owner        = THIS_MODULE,
+	.fb_destroy   = picolcd_fb_destroy,
+	.fb_read      = fb_sys_read,
+	.fb_write     = picolcd_fb_write,
+	.fb_blank     = picolcd_fb_blank,
+	.fb_fillrect  = picolcd_fb_fillrect,
+	.fb_copyarea  = picolcd_fb_copyarea,
+	.fb_imageblit = picolcd_fb_imageblit,
+	.fb_check_var = picolcd_fb_check_var,
+	.fb_set_par   = picolcd_set_par,
+};
+
+
+/* Callback from deferred IO workqueue */
+static void picolcd_fb_deferred_io(struct fb_info *info, struct list_head *pagelist)
+{
+	picolcd_fb_update(info);
+}
+
+static const struct fb_deferred_io picolcd_fb_defio = {
+	.delay = HZ / PICOLCDFB_UPDATE_RATE_DEFAULT,
+	.deferred_io = picolcd_fb_deferred_io,
+};
+
+
+/*
+ * The "fb_update_rate" sysfs attribute
+ */
+static ssize_t picolcd_fb_update_rate_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct picolcd_data *data = dev_get_drvdata(dev);
+	unsigned i, fb_update_rate = data->fb_update_rate;
+	size_t ret = 0;
+
+	for (i = 1; i <= PICOLCDFB_UPDATE_RATE_LIMIT; i++)
+		if (ret >= PAGE_SIZE)
+			break;
+		else if (i == fb_update_rate)
+			ret += snprintf(buf+ret, PAGE_SIZE-ret, "[%u] ", i);
+		else
+			ret += snprintf(buf+ret, PAGE_SIZE-ret, "%u ", i);
+	if (ret > 0)
+		buf[min(ret, (size_t)PAGE_SIZE)-1] = '\n';
+	return ret;
+}
+
+static ssize_t picolcd_fb_update_rate_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct picolcd_data *data = dev_get_drvdata(dev);
+	int i;
+	unsigned u;
+
+	if (count < 1 || count > 10)
+		return -EINVAL;
+
+	i = sscanf(buf, "%u", &u);
+	if (i != 1)
+		return -EINVAL;
+
+	if (u > PICOLCDFB_UPDATE_RATE_LIMIT)
+		return -ERANGE;
+	else if (u == 0)
+		u = PICOLCDFB_UPDATE_RATE_DEFAULT;
+
+	data->fb_update_rate = u;
+	data->fb_info->fbdefio->delay = HZ / data->fb_update_rate;
+	return count;
+}
+
+static DEVICE_ATTR(fb_update_rate, 0666, picolcd_fb_update_rate_show,
+		picolcd_fb_update_rate_store);
+
+/* initialize Framebuffer device */
+int picolcd_init_framebuffer(struct picolcd_data *data)
+{
+	struct device *dev = &data->hdev->dev;
+	struct fb_info *info = NULL;
+	int i, error = -ENOMEM;
+	u8 *fb_vbitmap = NULL;
+	u8 *fb_bitmap  = NULL;
+	u32 *palette;
+
+	fb_bitmap = vmalloc(PICOLCDFB_SIZE*8);
+	if (fb_bitmap == NULL) {
+		dev_err(dev, "can't get a free page for framebuffer\n");
+		goto err_nomem;
+	}
+
+	fb_vbitmap = kmalloc(PICOLCDFB_SIZE, GFP_KERNEL);
+	if (fb_vbitmap == NULL) {
+		dev_err(dev, "can't alloc vbitmap image buffer\n");
+		goto err_nomem;
+	}
+
+	data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT;
+	/* The extra memory is:
+	 * - 256*u32 for pseudo_palette
+	 * - struct fb_deferred_io
+	 */
+	info = framebuffer_alloc(256 * sizeof(u32) +
+			sizeof(struct fb_deferred_io), dev);
+	if (info == NULL) {
+		dev_err(dev, "failed to allocate a framebuffer\n");
+		goto err_nomem;
+	}
+
+	info->fbdefio = info->par;
+	*info->fbdefio = picolcd_fb_defio;
+	palette  = info->par + sizeof(struct fb_deferred_io);
+	for (i = 0; i < 256; i++)
+		palette[i] = i > 0 && i < 16 ? 0xff : 0;
+	info->pseudo_palette = palette;
+	info->screen_base = (char __force __iomem *)fb_bitmap;
+	info->fbops = &picolcdfb_ops;
+	info->var = picolcdfb_var;
+	info->fix = picolcdfb_fix;
+	info->fix.smem_len   = PICOLCDFB_SIZE*8;
+	info->fix.smem_start = (unsigned long)fb_bitmap;
+	info->par = data;
+	info->flags = FBINFO_FLAG_DEFAULT;
+
+	data->fb_vbitmap = fb_vbitmap;
+	data->fb_bitmap  = fb_bitmap;
+	data->fb_bpp     = picolcdfb_var.bits_per_pixel;
+	error = picolcd_fb_reset(data, 1);
+	if (error) {
+		dev_err(dev, "failed to configure display\n");
+		goto err_cleanup;
+	}
+	error = device_create_file(dev, &dev_attr_fb_update_rate);
+	if (error) {
+		dev_err(dev, "failed to create sysfs attributes\n");
+		goto err_cleanup;
+	}
+	fb_deferred_io_init(info);
+	data->fb_info    = info;
+	error = register_framebuffer(info);
+	if (error) {
+		dev_err(dev, "failed to register framebuffer\n");
+		goto err_sysfs;
+	}
+	/* schedule first output of framebuffer */
+	data->fb_force = 1;
+	schedule_delayed_work(&info->deferred_work, 0);
+	return 0;
+
+err_sysfs:
+	fb_deferred_io_cleanup(info);
+	device_remove_file(dev, &dev_attr_fb_update_rate);
+err_cleanup:
+	data->fb_vbitmap = NULL;
+	data->fb_bitmap  = NULL;
+	data->fb_bpp     = 0;
+	data->fb_info    = NULL;
+
+err_nomem:
+	framebuffer_release(info);
+	vfree(fb_bitmap);
+	kfree(fb_vbitmap);
+	return error;
+}
+
+void picolcd_exit_framebuffer(struct picolcd_data *data)
+{
+	struct fb_info *info = data->fb_info;
+	u8 *fb_vbitmap = data->fb_vbitmap;
+
+	if (!info)
+		return;
+
+	device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate);
+	info->par = NULL;
+	unregister_framebuffer(info);
+	data->fb_vbitmap = NULL;
+	data->fb_bitmap  = NULL;
+	data->fb_bpp     = 0;
+	data->fb_info    = NULL;
+	kfree(fb_vbitmap);
+}
diff --git a/drivers/hid/hid-picolcd_lcd.c b/drivers/hid/hid-picolcd_lcd.c
new file mode 100644
index 0000000..2d0ddc5
--- /dev/null
+++ b/drivers/hid/hid-picolcd_lcd.c
@@ -0,0 +1,107 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   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, version 2 of the License.               *
+ *                                                                         *
+ *   This driver is distributed in the hope that it will be useful, but    *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/lcd.h>
+
+#include "hid-picolcd.h"
+
+/*
+ * lcd class device
+ */
+static int picolcd_get_contrast(struct lcd_device *ldev)
+{
+	struct picolcd_data *data = lcd_get_data(ldev);
+	return data->lcd_contrast;
+}
+
+static int picolcd_set_contrast(struct lcd_device *ldev, int contrast)
+{
+	struct picolcd_data *data = lcd_get_data(ldev);
+	struct hid_report *report = picolcd_out_report(REPORT_CONTRAST, data->hdev);
+	unsigned long flags;
+
+	if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
+		return -ENODEV;
+
+	data->lcd_contrast = contrast & 0x0ff;
+	spin_lock_irqsave(&data->lock, flags);
+	hid_set_field(report->field[0], 0, data->lcd_contrast);
+	if (!(data->status & PICOLCD_FAILED))
+		usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+	spin_unlock_irqrestore(&data->lock, flags);
+	return 0;
+}
+
+static int picolcd_check_lcd_fb(struct lcd_device *ldev, struct fb_info *fb)
+{
+	return fb && fb == picolcd_fbinfo((struct picolcd_data *)lcd_get_data(ldev));
+}
+
+static struct lcd_ops picolcd_lcdops = {
+	.get_contrast   = picolcd_get_contrast,
+	.set_contrast   = picolcd_set_contrast,
+	.check_fb       = picolcd_check_lcd_fb,
+};
+
+int picolcd_init_lcd(struct picolcd_data *data, struct hid_report *report)
+{
+	struct device *dev = &data->hdev->dev;
+	struct lcd_device *ldev;
+
+	if (!report)
+		return -ENODEV;
+	if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
+			report->field[0]->report_size != 8) {
+		dev_err(dev, "unsupported CONTRAST report");
+		return -EINVAL;
+	}
+
+	ldev = lcd_device_register(dev_name(dev), dev, data, &picolcd_lcdops);
+	if (IS_ERR(ldev)) {
+		dev_err(dev, "failed to register LCD\n");
+		return PTR_ERR(ldev);
+	}
+	ldev->props.max_contrast = 0x0ff;
+	data->lcd_contrast = 0xe5;
+	data->lcd = ldev;
+	picolcd_set_contrast(ldev, 0xe5);
+	return 0;
+}
+
+void picolcd_exit_lcd(struct picolcd_data *data)
+{
+	struct lcd_device *ldev = data->lcd;
+
+	data->lcd = NULL;
+	if (ldev)
+		lcd_device_unregister(ldev);
+}
+
+int picolcd_resume_lcd(struct picolcd_data *data)
+{
+	if (!data->lcd)
+		return 0;
+	return picolcd_set_contrast(data->lcd, data->lcd_contrast);
+}
+
diff --git a/drivers/hid/hid-picolcd_leds.c b/drivers/hid/hid-picolcd_leds.c
new file mode 100644
index 0000000..28cb6a4
--- /dev/null
+++ b/drivers/hid/hid-picolcd_leds.c
@@ -0,0 +1,175 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   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, version 2 of the License.               *
+ *                                                                         *
+ *   This driver is distributed in the hope that it will be useful, but    *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include <linux/hid-debug.h>
+#include <linux/input.h>
+#include "hid-ids.h"
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/vmalloc.h>
+#include <linux/backlight.h>
+#include <linux/lcd.h>
+
+#include <linux/leds.h>
+
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+
+#include <linux/completion.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+
+#include "hid-picolcd.h"
+
+
+void picolcd_leds_set(struct picolcd_data *data)
+{
+	struct hid_report *report;
+	unsigned long flags;
+
+	if (!data->led[0])
+		return;
+	report = picolcd_out_report(REPORT_LED_STATE, data->hdev);
+	if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
+		return;
+
+	spin_lock_irqsave(&data->lock, flags);
+	hid_set_field(report->field[0], 0, data->led_state);
+	if (!(data->status & PICOLCD_FAILED))
+		usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+	spin_unlock_irqrestore(&data->lock, flags);
+}
+
+static void picolcd_led_set_brightness(struct led_classdev *led_cdev,
+			enum led_brightness value)
+{
+	struct device *dev;
+	struct hid_device *hdev;
+	struct picolcd_data *data;
+	int i, state = 0;
+
+	dev  = led_cdev->dev->parent;
+	hdev = container_of(dev, struct hid_device, dev);
+	data = hid_get_drvdata(hdev);
+	if (!data)
+		return;
+	for (i = 0; i < 8; i++) {
+		if (led_cdev != data->led[i])
+			continue;
+		state = (data->led_state >> i) & 1;
+		if (value == LED_OFF && state) {
+			data->led_state &= ~(1 << i);
+			picolcd_leds_set(data);
+		} else if (value != LED_OFF && !state) {
+			data->led_state |= 1 << i;
+			picolcd_leds_set(data);
+		}
+		break;
+	}
+}
+
+static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev)
+{
+	struct device *dev;
+	struct hid_device *hdev;
+	struct picolcd_data *data;
+	int i, value = 0;
+
+	dev  = led_cdev->dev->parent;
+	hdev = container_of(dev, struct hid_device, dev);
+	data = hid_get_drvdata(hdev);
+	for (i = 0; i < 8; i++)
+		if (led_cdev == data->led[i]) {
+			value = (data->led_state >> i) & 1;
+			break;
+		}
+	return value ? LED_FULL : LED_OFF;
+}
+
+int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report)
+{
+	struct device *dev = &data->hdev->dev;
+	struct led_classdev *led;
+	size_t name_sz = strlen(dev_name(dev)) + 8;
+	char *name;
+	int i, ret = 0;
+
+	if (!report)
+		return -ENODEV;
+	if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
+			report->field[0]->report_size != 8) {
+		dev_err(dev, "unsupported LED_STATE report");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < 8; i++) {
+		led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
+		if (!led) {
+			dev_err(dev, "can't allocate memory for LED %d\n", i);
+			ret = -ENOMEM;
+			goto err;
+		}
+		name = (void *)(&led[1]);
+		snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i);
+		led->name = name;
+		led->brightness = 0;
+		led->max_brightness = 1;
+		led->brightness_get = picolcd_led_get_brightness;
+		led->brightness_set = picolcd_led_set_brightness;
+
+		data->led[i] = led;
+		ret = led_classdev_register(dev, data->led[i]);
+		if (ret) {
+			data->led[i] = NULL;
+			kfree(led);
+			dev_err(dev, "can't register LED %d\n", i);
+			goto err;
+		}
+	}
+	return 0;
+err:
+	for (i = 0; i < 8; i++)
+		if (data->led[i]) {
+			led = data->led[i];
+			data->led[i] = NULL;
+			led_classdev_unregister(led);
+			kfree(led);
+		}
+	return ret;
+}
+
+void picolcd_exit_leds(struct picolcd_data *data)
+{
+	struct led_classdev *led;
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		led = data->led[i];
+		data->led[i] = NULL;
+		if (!led)
+			continue;
+		led_classdev_unregister(led);
+		kfree(led);
+	}
+}
+
+
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index fe23a1e..0f02358 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -33,6 +33,8 @@
 #define PAD_DEVICE_ID	0x0F
 
 #define WAC_CMD_LED_CONTROL     0x20
+#define WAC_CMD_ICON_START_STOP     0x21
+#define WAC_CMD_ICON_TRANSFER       0x26
 
 struct wacom_data {
 	__u16 tool;
@@ -69,6 +71,91 @@ static enum power_supply_property wacom_ac_props[] = {
 	POWER_SUPPLY_PROP_SCOPE,
 };
 
+static void wacom_scramble(__u8 *image)
+{
+	__u16 mask;
+	__u16 s1;
+	__u16 s2;
+	__u16 r1 ;
+	__u16 r2 ;
+	__u16 r;
+	__u8 buf[256];
+	int i, w, x, y, z;
+
+	for (x = 0; x < 32; x++) {
+		for (y = 0; y < 8; y++)
+			buf[(8 * x) + (7 - y)] = image[(8 * x) + y];
+	}
+
+	/* Change 76543210 into GECA6420 as required by Intuos4 WL
+	 *        HGFEDCBA      HFDB7531
+	 */
+	for (x = 0; x < 4; x++) {
+		for (y = 0; y < 4; y++) {
+			for (z = 0; z < 8; z++) {
+				mask = 0x0001;
+				r1 = 0;
+				r2 = 0;
+				i = (x << 6) + (y << 4) + z;
+				s1 = buf[i];
+				s2 = buf[i+8];
+				for (w = 0; w < 8; w++) {
+					r1 |= (s1 & mask);
+					r2 |= (s2 & mask);
+					s1 <<= 1;
+					s2 <<= 1;
+					mask <<= 2;
+				}
+				r = r1 | (r2 << 1);
+				i = (x << 6) + (y << 4) + (z << 1);
+				image[i] = 0xFF & r;
+				image[i+1] = (0xFF00 & r) >> 8;
+			}
+		}
+	}
+}
+
+static void wacom_set_image(struct hid_device *hdev, const char *image,
+						__u8 icon_no)
+{
+	__u8 rep_data[68];
+	__u8 p[256];
+	int ret, i, j;
+
+	for (i = 0; i < 256; i++)
+		p[i] = image[i];
+
+	rep_data[0] = WAC_CMD_ICON_START_STOP;
+	rep_data[1] = 0;
+	ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
+				HID_FEATURE_REPORT);
+	if (ret < 0)
+		goto err;
+
+	rep_data[0] = WAC_CMD_ICON_TRANSFER;
+	rep_data[1] = icon_no & 0x07;
+
+	wacom_scramble(p);
+
+	for (i = 0; i < 4; i++) {
+		for (j = 0; j < 64; j++)
+			rep_data[j + 3] = p[(i << 6) + j];
+
+		rep_data[2] = i;
+		ret = hdev->hid_output_raw_report(hdev, rep_data, 67,
+					HID_FEATURE_REPORT);
+	}
+
+	rep_data[0] = WAC_CMD_ICON_START_STOP;
+	rep_data[1] = 0;
+
+	ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
+				HID_FEATURE_REPORT);
+
+err:
+	return;
+}
+
 static void wacom_leds_set_brightness(struct led_classdev *led_dev,
 						enum led_brightness value)
 {
@@ -91,7 +178,10 @@ static void wacom_leds_set_brightness(struct led_classdev *led_dev,
 	if (buf) {
 		buf[0] = WAC_CMD_LED_CONTROL;
 		buf[1] = led;
-		buf[2] = value;
+		buf[2] = value >> 2;
+		buf[3] = value;
+		/* use fixed brightness for OLEDs */
+		buf[4] = 0x08;
 		hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT);
 		kfree(buf);
 	}
@@ -317,6 +407,34 @@ static ssize_t wacom_store_speed(struct device *dev,
 static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP,
 		wacom_show_speed, wacom_store_speed);
 
+#define WACOM_STORE(OLED_ID)						\
+static ssize_t wacom_oled##OLED_ID##_store(struct device *dev,		\
+				struct device_attribute *attr,		\
+				const char *buf, size_t count)		\
+{									\
+	struct hid_device *hdev = container_of(dev, struct hid_device,	\
+				dev);					\
+									\
+	if (count != 256)						\
+		return -EINVAL;						\
+									\
+	wacom_set_image(hdev, buf, OLED_ID);				\
+									\
+	return count;							\
+}									\
+									\
+static DEVICE_ATTR(oled##OLED_ID##_img, S_IWUSR | S_IWGRP, NULL,	\
+				wacom_oled##OLED_ID##_store)
+
+WACOM_STORE(0);
+WACOM_STORE(1);
+WACOM_STORE(2);
+WACOM_STORE(3);
+WACOM_STORE(4);
+WACOM_STORE(5);
+WACOM_STORE(6);
+WACOM_STORE(7);
+
 static int wacom_gr_parse_report(struct hid_device *hdev,
 			struct wacom_data *wdata,
 			struct input_dev *input, unsigned char *data)
@@ -717,6 +835,24 @@ static int wacom_probe(struct hid_device *hdev,
 		hid_warn(hdev,
 			 "can't create sysfs speed attribute err: %d\n", ret);
 
+#define OLED_INIT(OLED_ID)						\
+	do {								\
+		ret = device_create_file(&hdev->dev,			\
+				&dev_attr_oled##OLED_ID##_img);		\
+		if (ret)						\
+			hid_warn(hdev,					\
+			 "can't create sysfs oled attribute, err: %d\n", ret);\
+	} while (0)
+
+OLED_INIT(0);
+OLED_INIT(1);
+OLED_INIT(2);
+OLED_INIT(3);
+OLED_INIT(4);
+OLED_INIT(5);
+OLED_INIT(6);
+OLED_INIT(7);
+
 	wdata->features = 0;
 	wacom_set_features(hdev, 1);
 
@@ -781,6 +917,14 @@ static void wacom_remove(struct hid_device *hdev)
 	struct wacom_data *wdata = hid_get_drvdata(hdev);
 
 	wacom_destroy_leds(hdev);
+	device_remove_file(&hdev->dev, &dev_attr_oled0_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled1_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled2_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled3_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled4_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled5_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled6_img);
+	device_remove_file(&hdev->dev, &dev_attr_oled7_img);
 	device_remove_file(&hdev->dev, &dev_attr_speed);
 	hid_hw_stop(hdev);
 
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 3b6f7bf..7c47fc3 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -559,21 +559,28 @@ int __init hidraw_init(void)
 
 	if (result < 0) {
 		pr_warn("can't get major number\n");
-		result = 0;
 		goto out;
 	}
 
 	hidraw_class = class_create(THIS_MODULE, "hidraw");
 	if (IS_ERR(hidraw_class)) {
 		result = PTR_ERR(hidraw_class);
-		unregister_chrdev(hidraw_major, "hidraw");
-		goto out;
+		goto error_cdev;
 	}
 
         cdev_init(&hidraw_cdev, &hidraw_ops);
-        cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
+	result = cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
+	if (result < 0)
+		goto error_class;
+
 out:
 	return result;
+
+error_class:
+	class_destroy(hidraw_class);
+error_cdev:
+	unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
+	goto out;
 }
 
 void hidraw_exit(void)
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 903eef3..ccb8de6 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -70,6 +70,7 @@ static const struct hid_blacklist {
 	{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS },
 	{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS },
 	{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS },
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 86f8885..3648f8f 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/hyperv.h>
+#include <linux/version.h>
 #include <asm/hyperv.h>
 #include "hyperv_vmbus.h"
 
@@ -38,28 +39,6 @@ struct hv_context hv_context = {
 };
 
 /*
- * query_hypervisor_presence
- * - Query the cpuid for presence of windows hypervisor
- */
-static int query_hypervisor_presence(void)
-{
-	unsigned int eax;
-	unsigned int ebx;
-	unsigned int ecx;
-	unsigned int edx;
-	unsigned int op;
-
-	eax = 0;
-	ebx = 0;
-	ecx = 0;
-	edx = 0;
-	op = HVCPUID_VERSION_FEATURES;
-	cpuid(op, &eax, &ebx, &ecx, &edx);
-
-	return ecx & HV_PRESENT_BIT;
-}
-
-/*
  * query_hypervisor_info - Get version info of the windows hypervisor
  */
 static int query_hypervisor_info(void)
@@ -159,14 +138,13 @@ int hv_init(void)
 	memset(hv_context.synic_message_page, 0,
 	       sizeof(void *) * NR_CPUS);
 
-	if (!query_hypervisor_presence())
-		goto cleanup;
-
 	max_leaf = query_hypervisor_info();
 
-	/* Write our OS info */
-	wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
-	hv_context.guestid = HV_LINUX_GUEST_ID;
+	/*
+	 * Write our OS ID.
+	 */
+	hv_context.guestid = generate_guest_id(0, LINUX_VERSION_CODE, 0);
+	wrmsrl(HV_X64_MSR_GUEST_OS_ID, hv_context.guestid);
 
 	/* See if the hypercall page is already set */
 	rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 0012eed..d906050 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -48,13 +48,24 @@ static struct {
 	void *kvp_context; /* for the channel callback */
 } kvp_transaction;
 
+/*
+ * Before we can accept KVP messages from the host, we need
+ * to handshake with the user level daemon. This state tracks
+ * if we are in the handshake phase.
+ */
+static bool in_hand_shake = true;
+
+/*
+ * This state maintains the version number registered by the daemon.
+ */
+static int dm_reg_value;
+
 static void kvp_send_key(struct work_struct *dummy);
 
-#define TIMEOUT_FIRED 1
 
-static void kvp_respond_to_host(char *key, char *value, int error);
+static void kvp_respond_to_host(struct hv_kvp_msg *msg, int error);
 static void kvp_work_func(struct work_struct *dummy);
-static void kvp_register(void);
+static void kvp_register(int);
 
 static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func);
 static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
@@ -68,7 +79,7 @@ static u8 *recv_buffer;
  */
 
 static void
-kvp_register(void)
+kvp_register(int reg_value)
 {
 
 	struct cn_msg *msg;
@@ -83,7 +94,7 @@ kvp_register(void)
 		msg->id.idx =  CN_KVP_IDX;
 		msg->id.val = CN_KVP_VAL;
 
-		kvp_msg->kvp_hdr.operation = KVP_OP_REGISTER;
+		kvp_msg->kvp_hdr.operation = reg_value;
 		strcpy(version, HV_DRV_VERSION);
 		msg->len = sizeof(struct hv_kvp_msg);
 		cn_netlink_send(msg, 0, GFP_ATOMIC);
@@ -97,9 +108,43 @@ kvp_work_func(struct work_struct *dummy)
 	 * If the timer fires, the user-mode component has not responded;
 	 * process the pending transaction.
 	 */
-	kvp_respond_to_host("Unknown key", "Guest timed out", TIMEOUT_FIRED);
+	kvp_respond_to_host(NULL, HV_E_FAIL);
+}
+
+static int kvp_handle_handshake(struct hv_kvp_msg *msg)
+{
+	int ret = 1;
+
+	switch (msg->kvp_hdr.operation) {
+	case KVP_OP_REGISTER:
+		dm_reg_value = KVP_OP_REGISTER;
+		pr_info("KVP: IP injection functionality not available\n");
+		pr_info("KVP: Upgrade the KVP daemon\n");
+		break;
+	case KVP_OP_REGISTER1:
+		dm_reg_value = KVP_OP_REGISTER1;
+		break;
+	default:
+		pr_info("KVP: incompatible daemon\n");
+		pr_info("KVP: KVP version: %d, Daemon version: %d\n",
+			KVP_OP_REGISTER1, msg->kvp_hdr.operation);
+		ret = 0;
+	}
+
+	if (ret) {
+		/*
+		 * We have a compatible daemon; complete the handshake.
+		 */
+		pr_info("KVP: user-mode registering done.\n");
+		kvp_register(dm_reg_value);
+		kvp_transaction.active = false;
+		if (kvp_transaction.kvp_context)
+			hv_kvp_onchannelcallback(kvp_transaction.kvp_context);
+	}
+	return ret;
 }
 
+
 /*
  * Callback when data is received from user mode.
  */
@@ -109,29 +154,163 @@ kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
 {
 	struct hv_kvp_msg *message;
 	struct hv_kvp_msg_enumerate *data;
+	int	error = 0;
 
 	message = (struct hv_kvp_msg *)msg->data;
-	switch (message->kvp_hdr.operation) {
+
+	/*
+	 * If we are negotiating the version information
+	 * with the daemon; handle that first.
+	 */
+
+	if (in_hand_shake) {
+		if (kvp_handle_handshake(message))
+			in_hand_shake = false;
+		return;
+	}
+
+	/*
+	 * Based on the version of the daemon, we propagate errors from the
+	 * daemon differently.
+	 */
+
+	data = &message->body.kvp_enum_data;
+
+	switch (dm_reg_value) {
 	case KVP_OP_REGISTER:
-		pr_info("KVP: user-mode registering done.\n");
-		kvp_register();
-		kvp_transaction.active = false;
-		hv_kvp_onchannelcallback(kvp_transaction.kvp_context);
+		/*
+		 * Null string is used to pass back error condition.
+		 */
+		if (data->data.key[0] == 0)
+			error = HV_S_CONT;
 		break;
 
-	default:
-		data = &message->body.kvp_enum_data;
+	case KVP_OP_REGISTER1:
 		/*
-		 * Complete the transaction by forwarding the key value
-		 * to the host. But first, cancel the timeout.
+		 * We use the message header information from
+		 * the user level daemon to transmit errors.
 		 */
-		if (cancel_delayed_work_sync(&kvp_work))
-			kvp_respond_to_host(data->data.key,
-					 data->data.value,
-					!strlen(data->data.key));
+		error = message->error;
+		break;
+	}
+
+	/*
+	 * Complete the transaction by forwarding the key value
+	 * to the host. But first, cancel the timeout.
+	 */
+	if (cancel_delayed_work_sync(&kvp_work))
+		kvp_respond_to_host(message, error);
+}
+
+
+static int process_ob_ipinfo(void *in_msg, void *out_msg, int op)
+{
+	struct hv_kvp_msg *in = in_msg;
+	struct hv_kvp_ip_msg *out = out_msg;
+	int len;
+
+	switch (op) {
+	case KVP_OP_GET_IP_INFO:
+		/*
+		 * Transform all parameters into utf16 encoding.
+		 */
+		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.ip_addr,
+				strlen((char *)in->body.kvp_ip_val.ip_addr),
+				UTF16_HOST_ENDIAN,
+				(wchar_t *)out->kvp_ip_val.ip_addr,
+				MAX_IP_ADDR_SIZE);
+		if (len < 0)
+			return len;
+
+		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.sub_net,
+				strlen((char *)in->body.kvp_ip_val.sub_net),
+				UTF16_HOST_ENDIAN,
+				(wchar_t *)out->kvp_ip_val.sub_net,
+				MAX_IP_ADDR_SIZE);
+		if (len < 0)
+			return len;
+
+		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.gate_way,
+				strlen((char *)in->body.kvp_ip_val.gate_way),
+				UTF16_HOST_ENDIAN,
+				(wchar_t *)out->kvp_ip_val.gate_way,
+				MAX_GATEWAY_SIZE);
+		if (len < 0)
+			return len;
+
+		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.dns_addr,
+				strlen((char *)in->body.kvp_ip_val.dns_addr),
+				UTF16_HOST_ENDIAN,
+				(wchar_t *)out->kvp_ip_val.dns_addr,
+				MAX_IP_ADDR_SIZE);
+		if (len < 0)
+			return len;
+
+		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.adapter_id,
+				strlen((char *)in->body.kvp_ip_val.adapter_id),
+				UTF16_HOST_ENDIAN,
+				(wchar_t *)out->kvp_ip_val.adapter_id,
+				MAX_IP_ADDR_SIZE);
+		if (len < 0)
+			return len;
+
+		out->kvp_ip_val.dhcp_enabled =
+			in->body.kvp_ip_val.dhcp_enabled;
+	}
+
+	return 0;
+}
+
+static void process_ib_ipinfo(void *in_msg, void *out_msg, int op)
+{
+	struct hv_kvp_ip_msg *in = in_msg;
+	struct hv_kvp_msg *out = out_msg;
+
+	switch (op) {
+	case KVP_OP_SET_IP_INFO:
+		/*
+		 * Transform all parameters into utf8 encoding.
+		 */
+		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.ip_addr,
+				MAX_IP_ADDR_SIZE,
+				UTF16_LITTLE_ENDIAN,
+				(__u8 *)out->body.kvp_ip_val.ip_addr,
+				MAX_IP_ADDR_SIZE);
+
+		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.sub_net,
+				MAX_IP_ADDR_SIZE,
+				UTF16_LITTLE_ENDIAN,
+				(__u8 *)out->body.kvp_ip_val.sub_net,
+				MAX_IP_ADDR_SIZE);
+
+		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.gate_way,
+				MAX_GATEWAY_SIZE,
+				UTF16_LITTLE_ENDIAN,
+				(__u8 *)out->body.kvp_ip_val.gate_way,
+				MAX_GATEWAY_SIZE);
+
+		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.dns_addr,
+				MAX_IP_ADDR_SIZE,
+				UTF16_LITTLE_ENDIAN,
+				(__u8 *)out->body.kvp_ip_val.dns_addr,
+				MAX_IP_ADDR_SIZE);
+
+		out->body.kvp_ip_val.dhcp_enabled = in->kvp_ip_val.dhcp_enabled;
+
+	default:
+		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.adapter_id,
+				MAX_ADAPTER_ID_SIZE,
+				UTF16_LITTLE_ENDIAN,
+				(__u8 *)out->body.kvp_ip_val.adapter_id,
+				MAX_ADAPTER_ID_SIZE);
+
+		out->body.kvp_ip_val.addr_family = in->kvp_ip_val.addr_family;
 	}
 }
 
+
+
+
 static void
 kvp_send_key(struct work_struct *dummy)
 {
@@ -167,6 +346,12 @@ kvp_send_key(struct work_struct *dummy)
 	 */
 
 	switch (message->kvp_hdr.operation) {
+	case KVP_OP_SET_IP_INFO:
+		process_ib_ipinfo(in_msg, message, KVP_OP_SET_IP_INFO);
+		break;
+	case KVP_OP_GET_IP_INFO:
+		process_ib_ipinfo(in_msg, message, KVP_OP_GET_IP_INFO);
+		break;
 	case KVP_OP_SET:
 		switch (in_msg->body.kvp_set.data.value_type) {
 		case REG_SZ:
@@ -243,17 +428,19 @@ kvp_send_key(struct work_struct *dummy)
  */
 
 static void
-kvp_respond_to_host(char *key, char *value, int error)
+kvp_respond_to_host(struct hv_kvp_msg *msg_to_host, int error)
 {
 	struct hv_kvp_msg  *kvp_msg;
 	struct hv_kvp_exchg_msg_value  *kvp_data;
 	char	*key_name;
+	char	*value;
 	struct icmsg_hdr *icmsghdrp;
 	int	keylen = 0;
 	int	valuelen = 0;
 	u32	buf_len;
 	struct vmbus_channel *channel;
 	u64	req_id;
+	int ret;
 
 	/*
 	 * If a transaction is not active; log and return.
@@ -287,6 +474,7 @@ kvp_respond_to_host(char *key, char *value, int error)
 		 */
 		return;
 
+	icmsghdrp->status = error;
 
 	/*
 	 * If the error parameter is set, terminate the host's enumeration
@@ -294,20 +482,27 @@ kvp_respond_to_host(char *key, char *value, int error)
 	 */
 	if (error) {
 		/*
-		 * Something failed or the we have timedout;
-		 * terminate the current  host-side iteration.
+		 * Something failed or we have timedout;
+		 * terminate the current host-side iteration.
 		 */
-		icmsghdrp->status = HV_S_CONT;
 		goto response_done;
 	}
 
-	icmsghdrp->status = HV_S_OK;
-
 	kvp_msg = (struct hv_kvp_msg *)
 			&recv_buffer[sizeof(struct vmbuspipe_hdr) +
 			sizeof(struct icmsg_hdr)];
 
 	switch (kvp_transaction.kvp_msg->kvp_hdr.operation) {
+	case KVP_OP_GET_IP_INFO:
+		ret = process_ob_ipinfo(msg_to_host,
+				 (struct hv_kvp_ip_msg *)kvp_msg,
+				 KVP_OP_GET_IP_INFO);
+		if (ret < 0)
+			icmsghdrp->status = HV_E_FAIL;
+
+		goto response_done;
+	case KVP_OP_SET_IP_INFO:
+		goto response_done;
 	case KVP_OP_GET:
 		kvp_data = &kvp_msg->body.kvp_get.data;
 		goto copy_value;
@@ -321,7 +516,7 @@ kvp_respond_to_host(char *key, char *value, int error)
 	}
 
 	kvp_data = &kvp_msg->body.kvp_enum_data.data;
-	key_name = key;
+	key_name = msg_to_host->body.kvp_enum_data.data.key;
 
 	/*
 	 * The windows host expects the key/value pair to be encoded
@@ -335,6 +530,7 @@ kvp_respond_to_host(char *key, char *value, int error)
 	kvp_data->key_size = 2*(keylen + 1); /* utf16 encoding */
 
 copy_value:
+	value = msg_to_host->body.kvp_enum_data.data.value;
 	valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN,
 				(wchar_t *) kvp_data->value,
 				(HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2);
@@ -387,7 +583,8 @@ void hv_kvp_onchannelcallback(void *context)
 		return;
 	}
 
-	vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid);
+	vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
+			 &requestid);
 
 	if (recvlen > 0) {
 		icmsghdrp = (struct icmsg_hdr *)&recv_buffer[
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index d3ac6a4..a0667de 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -263,7 +263,7 @@ static int util_probe(struct hv_device *dev,
 		(struct hv_util_service *)dev_id->driver_data;
 	int ret;
 
-	srv->recv_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	srv->recv_buffer = kmalloc(PAGE_SIZE * 2, GFP_KERNEL);
 	if (!srv->recv_buffer)
 		return -ENOMEM;
 	if (srv->util_init) {
@@ -274,7 +274,7 @@ static int util_probe(struct hv_device *dev,
 		}
 	}
 
-	ret = vmbus_open(dev->channel, 2 * PAGE_SIZE, 2 * PAGE_SIZE, NULL, 0,
+	ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0,
 			srv->util_cb, dev->channel);
 	if (ret)
 		goto error;
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 0614ff3..d8d1fad 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -410,10 +410,49 @@ enum {
 
 #define HV_PRESENT_BIT			0x80000000
 
-#define HV_LINUX_GUEST_ID_LO		0x00000000
-#define HV_LINUX_GUEST_ID_HI		2976579765
-#define HV_LINUX_GUEST_ID		(((u64)HV_LINUX_GUEST_ID_HI << 32) | \
-					   HV_LINUX_GUEST_ID_LO)
+/*
+ * The guest OS needs to register the guest ID with the hypervisor.
+ * The guest ID is a 64 bit entity and the structure of this ID is
+ * specified in the Hyper-V specification:
+ *
+ * http://msdn.microsoft.com/en-us/library/windows/hardware/ff542653%28v=vs.85%29.aspx
+ *
+ * While the current guideline does not specify how Linux guest ID(s)
+ * need to be generated, our plan is to publish the guidelines for
+ * Linux and other guest operating systems that currently are hosted
+ * on Hyper-V. The implementation here conforms to this yet
+ * unpublished guidelines.
+ *
+ *
+ * Bit(s)
+ * 63 - Indicates if the OS is Open Source or not; 1 is Open Source
+ * 62:56 - Os Type; Linux is 0x100
+ * 55:48 - Distro specific identification
+ * 47:16 - Linux kernel version number
+ * 15:0  - Distro specific identification
+ *
+ *
+ */
+
+#define HV_LINUX_VENDOR_ID		0x8100
+
+/*
+ * Generate the guest ID based on the guideline described above.
+ */
+
+static inline  __u64 generate_guest_id(__u8 d_info1, __u32 kernel_version,
+					__u16 d_info2)
+{
+	__u64 guest_id = 0;
+
+	guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 48);
+	guest_id |= (((__u64)(d_info1)) << 48);
+	guest_id |= (((__u64)(kernel_version)) << 16);
+	guest_id |= ((__u64)(d_info2));
+
+	return guest_id;
+}
+
 
 #define HV_CPU_POWER_MANAGEMENT		(1 << 0)
 #define HV_RECOMMENDATIONS_MAX		4
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 4748086..f40dd57 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -146,43 +146,9 @@ static ssize_t vmbus_show_device_attr(struct device *dev,
 	get_channel_info(hv_dev, device_info);
 
 	if (!strcmp(dev_attr->attr.name, "class_id")) {
-		ret = sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
-			       "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
-			       device_info->chn_type.b[3],
-			       device_info->chn_type.b[2],
-			       device_info->chn_type.b[1],
-			       device_info->chn_type.b[0],
-			       device_info->chn_type.b[5],
-			       device_info->chn_type.b[4],
-			       device_info->chn_type.b[7],
-			       device_info->chn_type.b[6],
-			       device_info->chn_type.b[8],
-			       device_info->chn_type.b[9],
-			       device_info->chn_type.b[10],
-			       device_info->chn_type.b[11],
-			       device_info->chn_type.b[12],
-			       device_info->chn_type.b[13],
-			       device_info->chn_type.b[14],
-			       device_info->chn_type.b[15]);
+		ret = sprintf(buf, "{%pUl}\n", device_info->chn_type.b);
 	} else if (!strcmp(dev_attr->attr.name, "device_id")) {
-		ret = sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
-			       "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
-			       device_info->chn_instance.b[3],
-			       device_info->chn_instance.b[2],
-			       device_info->chn_instance.b[1],
-			       device_info->chn_instance.b[0],
-			       device_info->chn_instance.b[5],
-			       device_info->chn_instance.b[4],
-			       device_info->chn_instance.b[7],
-			       device_info->chn_instance.b[6],
-			       device_info->chn_instance.b[8],
-			       device_info->chn_instance.b[9],
-			       device_info->chn_instance.b[10],
-			       device_info->chn_instance.b[11],
-			       device_info->chn_instance.b[12],
-			       device_info->chn_instance.b[13],
-			       device_info->chn_instance.b[14],
-			       device_info->chn_instance.b[15]);
+		ret = sprintf(buf, "{%pUl}\n", device_info->chn_instance.b);
 	} else if (!strcmp(dev_attr->attr.name, "modalias")) {
 		print_alias_name(hv_dev, alias_name);
 		ret = sprintf(buf, "vmbus:%s\n", alias_name);
@@ -753,10 +719,35 @@ static struct acpi_driver vmbus_acpi_driver = {
 	},
 };
 
+/*
+ * query_hypervisor_presence
+ * - Query the cpuid for presence of windows hypervisor
+ */
+static int query_hypervisor_presence(void)
+{
+	unsigned int eax;
+	unsigned int ebx;
+	unsigned int ecx;
+	unsigned int edx;
+	unsigned int op;
+
+	eax = 0;
+	ebx = 0;
+	ecx = 0;
+	edx = 0;
+	op = HVCPUID_VERSION_FEATURES;
+	cpuid(op, &eax, &ebx, &ecx, &edx);
+
+	return ecx & HV_PRESENT_BIT;
+}
+
 static int __init hv_acpi_init(void)
 {
 	int ret, t;
 
+	if (!query_hypervisor_presence())
+		return -ENODEV;
+
 	init_completion(&probe_event);
 
 	/*
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index b0a2e4c..df463a3 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -179,6 +179,16 @@ config SENSORS_ADM9240
 	  This driver can also be built as a module.  If so, the module
 	  will be called adm9240.
 
+config SENSORS_ADT7410
+	tristate "Analog Devices ADT7410"
+	depends on I2C && EXPERIMENTAL
+	help
+	  If you say yes here you get support for the Analog Devices
+	  ADT7410 temperature monitoring chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called adt7410.
+
 config SENSORS_ADT7411
 	tristate "Analog Devices ADT7411"
 	depends on I2C && EXPERIMENTAL
@@ -324,16 +334,6 @@ config SENSORS_DA9052_ADC
 	  This driver can also be built as module. If so, the module
 	  will be called da9052-hwmon.
 
-config SENSORS_EXYNOS4_TMU
-	tristate "Temperature sensor on Samsung EXYNOS4"
-	depends on ARCH_EXYNOS4
-	help
-	  If you say yes here you get support for TMU (Thermal Management
-	  Unit) on SAMSUNG EXYNOS4 series of SoC.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called exynos4-tmu.
-
 config SENSORS_I5K_AMB
 	tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
 	depends on PCI && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 7aa9811..b622dcb 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_SENSORS_ADM9240)	+= adm9240.o
 obj-$(CONFIG_SENSORS_ADS1015)	+= ads1015.o
 obj-$(CONFIG_SENSORS_ADS7828)	+= ads7828.o
 obj-$(CONFIG_SENSORS_ADS7871)	+= ads7871.o
+obj-$(CONFIG_SENSORS_ADT7410)	+= adt7410.o
 obj-$(CONFIG_SENSORS_ADT7411)	+= adt7411.o
 obj-$(CONFIG_SENSORS_ADT7462)	+= adt7462.o
 obj-$(CONFIG_SENSORS_ADT7470)	+= adt7470.o
@@ -49,7 +50,6 @@ obj-$(CONFIG_SENSORS_DS1621)	+= ds1621.o
 obj-$(CONFIG_SENSORS_EMC1403)	+= emc1403.o
 obj-$(CONFIG_SENSORS_EMC2103)	+= emc2103.o
 obj-$(CONFIG_SENSORS_EMC6W201)	+= emc6w201.o
-obj-$(CONFIG_SENSORS_EXYNOS4_TMU)	+= exynos4_tmu.o
 obj-$(CONFIG_SENSORS_F71805F)	+= f71805f.o
 obj-$(CONFIG_SENSORS_F71882FG)	+= f71882fg.o
 obj-$(CONFIG_SENSORS_F75375S)	+= f75375s.o
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
index d4419b4..78b8179 100644
--- a/drivers/hwmon/abituguru.c
+++ b/drivers/hwmon/abituguru.c
@@ -1278,7 +1278,8 @@ static int __devinit abituguru_probe(struct platform_device *pdev)
 		0x00, 0x01, 0x03, 0x04, 0x0A, 0x08, 0x0E, 0x02,
 		0x09, 0x06, 0x05, 0x0B, 0x0F, 0x0D, 0x07, 0x0C };
 
-	data = kzalloc(sizeof(struct abituguru_data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(struct abituguru_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -1430,8 +1431,6 @@ abituguru_probe_error:
 	for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
 		device_remove_file(&pdev->dev,
 			&abituguru_sysfs_attr[i].dev_attr);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
 	return res;
 }
 
@@ -1446,8 +1445,6 @@ static int __devexit abituguru_remove(struct platform_device *pdev)
 	for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
 		device_remove_file(&pdev->dev,
 			&abituguru_sysfs_attr[i].dev_attr);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
 
 	return 0;
 }
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
index 5d582ae..b174b8b 100644
--- a/drivers/hwmon/abituguru3.c
+++ b/drivers/hwmon/abituguru3.c
@@ -976,7 +976,8 @@ static int __devinit abituguru3_probe(struct platform_device *pdev)
 	u8 buf[2];
 	u16 id;
 
-	data = kzalloc(sizeof(struct abituguru3_data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(struct abituguru3_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -1068,7 +1069,6 @@ abituguru3_probe_error:
 	for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
 		device_remove_file(&pdev->dev,
 			&abituguru3_sysfs_attr[i].dev_attr);
-	kfree(data);
 	return res;
 }
 
@@ -1084,8 +1084,6 @@ static int __devexit abituguru3_remove(struct platform_device *pdev)
 	for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
 		device_remove_file(&pdev->dev,
 			&abituguru3_sysfs_attr[i].dev_attr);
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c
index cfec802..455294f 100644
--- a/drivers/hwmon/ad7314.c
+++ b/drivers/hwmon/ad7314.c
@@ -104,16 +104,16 @@ static int __devinit ad7314_probe(struct spi_device *spi_dev)
 	int ret;
 	struct ad7314_data *chip;
 
-	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-	if (chip == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	chip = devm_kzalloc(&spi_dev->dev, sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL)
+		return -ENOMEM;
+
 	dev_set_drvdata(&spi_dev->dev, chip);
 
 	ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group);
 	if (ret < 0)
-		goto error_free_chip;
+		return ret;
+
 	chip->hwmon_dev = hwmon_device_register(&spi_dev->dev);
 	if (IS_ERR(chip->hwmon_dev)) {
 		ret = PTR_ERR(chip->hwmon_dev);
@@ -124,9 +124,6 @@ static int __devinit ad7314_probe(struct spi_device *spi_dev)
 	return 0;
 error_remove_group:
 	sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
-error_free_chip:
-	kfree(chip);
-error_ret:
 	return ret;
 }
 
@@ -136,7 +133,6 @@ static int __devexit ad7314_remove(struct spi_device *spi_dev)
 
 	hwmon_device_unregister(chip->hwmon_dev);
 	sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
-	kfree(chip);
 
 	return 0;
 }
diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c
index 06d2d60..b420fb3 100644
--- a/drivers/hwmon/ad7414.c
+++ b/drivers/hwmon/ad7414.c
@@ -185,16 +185,13 @@ static int ad7414_probe(struct i2c_client *client,
 	int err;
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
-				     I2C_FUNC_SMBUS_READ_WORD_DATA)) {
-		err = -EOPNOTSUPP;
-		goto exit;
-	}
+				     I2C_FUNC_SMBUS_READ_WORD_DATA))
+		return -EOPNOTSUPP;
 
-	data = kzalloc(sizeof(struct ad7414_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct ad7414_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->lock);
@@ -214,7 +211,7 @@ static int ad7414_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &ad7414_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -226,9 +223,6 @@ static int ad7414_probe(struct i2c_client *client,
 
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &ad7414_group);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -238,7 +232,6 @@ static int __devexit ad7414_remove(struct i2c_client *client)
 
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &ad7414_group);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c
index a50a6be..57d4a62 100644
--- a/drivers/hwmon/ad7418.c
+++ b/drivers/hwmon/ad7418.c
@@ -227,16 +227,13 @@ static int ad7418_probe(struct i2c_client *client,
 	int err;
 
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
-					I2C_FUNC_SMBUS_WORD_DATA)) {
-		err = -EOPNOTSUPP;
-		goto exit;
-	}
+					I2C_FUNC_SMBUS_WORD_DATA))
+		return -EOPNOTSUPP;
 
-	data = kzalloc(sizeof(struct ad7418_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct ad7418_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 
@@ -268,7 +265,7 @@ static int ad7418_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &data->attrs);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -280,9 +277,6 @@ static int ad7418_probe(struct i2c_client *client,
 
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &data->attrs);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -291,7 +285,6 @@ static int ad7418_remove(struct i2c_client *client)
 	struct ad7418_data *data = i2c_get_clientdata(client);
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &data->attrs);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/adcxx.c b/drivers/hwmon/adcxx.c
index a3d3183..111af7c 100644
--- a/drivers/hwmon/adcxx.c
+++ b/drivers/hwmon/adcxx.c
@@ -171,7 +171,7 @@ static int __devinit adcxx_probe(struct spi_device *spi)
 	int status;
 	int i;
 
-	adc = kzalloc(sizeof *adc, GFP_KERNEL);
+	adc = devm_kzalloc(&spi->dev, sizeof(*adc), GFP_KERNEL);
 	if (!adc)
 		return -ENOMEM;
 
@@ -208,7 +208,6 @@ out_err:
 
 	spi_set_drvdata(spi, NULL);
 	mutex_unlock(&adc->lock);
-	kfree(adc);
 	return status;
 }
 
@@ -224,7 +223,6 @@ static int __devexit adcxx_remove(struct spi_device *spi)
 
 	spi_set_drvdata(spi, NULL);
 	mutex_unlock(&adc->lock);
-	kfree(adc);
 
 	return 0;
 }
diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c
index 80cc465..97f4718 100644
--- a/drivers/hwmon/adm1029.c
+++ b/drivers/hwmon/adm1029.c
@@ -342,11 +342,10 @@ static int adm1029_probe(struct i2c_client *client,
 	struct adm1029_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct adm1029_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct adm1029_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -355,15 +354,13 @@ static int adm1029_probe(struct i2c_client *client,
 	 * Initialize the ADM1029 chip
 	 * Check config register
 	 */
-	if (adm1029_init_client(client) == 0) {
-		err = -ENODEV;
-		goto exit_free;
-	}
+	if (adm1029_init_client(client) == 0)
+		return -ENODEV;
 
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &adm1029_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -375,9 +372,6 @@ static int adm1029_probe(struct i2c_client *client,
 
  exit_remove_files:
 	sysfs_remove_group(&client->dev.kobj, &adm1029_group);
- exit_free:
-	kfree(data);
- exit:
 	return err;
 }
 
@@ -405,7 +399,6 @@ static int adm1029_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &adm1029_group);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
index 1958f03..2798246 100644
--- a/drivers/hwmon/ads1015.c
+++ b/drivers/hwmon/ads1015.c
@@ -156,7 +156,6 @@ static int ads1015_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	for (k = 0; k < ADS1015_CHANNELS; ++k)
 		device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
-	kfree(data);
 	return 0;
 }
 
@@ -254,11 +253,10 @@ static int ads1015_probe(struct i2c_client *client,
 	int err;
 	unsigned int k;
 
-	data = kzalloc(sizeof(struct ads1015_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct ads1015_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -284,8 +282,6 @@ static int ads1015_probe(struct i2c_client *client,
 exit_remove:
 	for (k = 0; k < ADS1015_CHANNELS; ++k)
 		device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
-	kfree(data);
-exit:
 	return err;
 }
 
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index bf3fdf4..1f9e8af 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -154,7 +154,6 @@ static int ads7828_remove(struct i2c_client *client)
 	struct ads7828_data *data = i2c_get_clientdata(client);
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &ads7828_group);
-	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
@@ -217,11 +216,10 @@ static int ads7828_probe(struct i2c_client *client,
 	struct ads7828_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct ads7828_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct ads7828_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -229,7 +227,7 @@ static int ads7828_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &ads7828_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -241,9 +239,6 @@ static int ads7828_probe(struct i2c_client *client,
 
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &ads7828_group);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
diff --git a/drivers/hwmon/ads7871.c b/drivers/hwmon/ads7871.c
index e65c6e4..e837707 100644
--- a/drivers/hwmon/ads7871.c
+++ b/drivers/hwmon/ads7871.c
@@ -189,20 +189,17 @@ static int __devinit ads7871_probe(struct spi_device *spi)
 	 * because there is no other error checking on an SPI bus
 	 * we need to make sure we really have a chip
 	 */
-	if (val != ret) {
-		err = -ENODEV;
-		goto exit;
-	}
+	if (val != ret)
+		return -ENODEV;
 
-	pdata = kzalloc(sizeof(struct ads7871_data), GFP_KERNEL);
-	if (!pdata) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	pdata = devm_kzalloc(&spi->dev, sizeof(struct ads7871_data),
+			     GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
 
 	err = sysfs_create_group(&spi->dev.kobj, &ads7871_group);
 	if (err < 0)
-		goto error_free;
+		return err;
 
 	spi_set_drvdata(spi, pdata);
 
@@ -216,9 +213,6 @@ static int __devinit ads7871_probe(struct spi_device *spi)
 
 error_remove:
 	sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
-error_free:
-	kfree(pdata);
-exit:
 	return err;
 }
 
@@ -228,7 +222,6 @@ static int __devexit ads7871_remove(struct spi_device *spi)
 
 	hwmon_device_unregister(pdata->hwmon_dev);
 	sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
-	kfree(pdata);
 	return 0;
 }
 
diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
new file mode 100644
index 0000000..030c8d7
--- /dev/null
+++ b/drivers/hwmon/adt7410.c
@@ -0,0 +1,464 @@
+/*
+ * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	 monitoring
+ * This driver handles the ADT7410 and compatible digital temperature sensors.
+ * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
+ * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
+ * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+/*
+ * ADT7410 registers definition
+ */
+
+#define ADT7410_TEMPERATURE		0
+#define ADT7410_STATUS			2
+#define ADT7410_CONFIG			3
+#define ADT7410_T_ALARM_HIGH		4
+#define ADT7410_T_ALARM_LOW		6
+#define ADT7410_T_CRIT			8
+#define ADT7410_T_HYST			0xA
+
+/*
+ * ADT7410 status
+ */
+#define ADT7410_STAT_T_LOW		(1 << 4)
+#define ADT7410_STAT_T_HIGH		(1 << 5)
+#define ADT7410_STAT_T_CRIT		(1 << 6)
+#define ADT7410_STAT_NOT_RDY		(1 << 7)
+
+/*
+ * ADT7410 config
+ */
+#define ADT7410_FAULT_QUEUE_MASK	(1 << 0 | 1 << 1)
+#define ADT7410_CT_POLARITY		(1 << 2)
+#define ADT7410_INT_POLARITY		(1 << 3)
+#define ADT7410_EVENT_MODE		(1 << 4)
+#define ADT7410_MODE_MASK		(1 << 5 | 1 << 6)
+#define ADT7410_FULL			(0 << 5 | 0 << 6)
+#define ADT7410_PD			(1 << 5 | 1 << 6)
+#define ADT7410_RESOLUTION		(1 << 7)
+
+/*
+ * ADT7410 masks
+ */
+#define ADT7410_T13_VALUE_MASK			0xFFF8
+#define ADT7410_T_HYST_MASK			0xF
+
+/* straight from the datasheet */
+#define ADT7410_TEMP_MIN (-55000)
+#define ADT7410_TEMP_MAX 150000
+
+enum adt7410_type {		/* keep sorted in alphabetical order */
+	adt7410,
+};
+
+/* Addresses scanned */
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
+					I2C_CLIENT_END };
+
+static const u8 ADT7410_REG_TEMP[4] = {
+	ADT7410_TEMPERATURE,		/* input */
+	ADT7410_T_ALARM_HIGH,		/* high */
+	ADT7410_T_ALARM_LOW,		/* low */
+	ADT7410_T_CRIT,			/* critical */
+};
+
+/* Each client has this additional data */
+struct adt7410_data {
+	struct device		*hwmon_dev;
+	struct mutex		update_lock;
+	u8			config;
+	u8			oldconfig;
+	bool			valid;		/* true if registers valid */
+	unsigned long		last_updated;	/* In jiffies */
+	s16			temp[4];	/* Register values,
+						   0 = input
+						   1 = high
+						   2 = low
+						   3 = critical */
+	u8			hyst;		/* hysteresis offset */
+};
+
+/*
+ * adt7410 register access by I2C
+ */
+static int adt7410_temp_ready(struct i2c_client *client)
+{
+	int i, status;
+
+	for (i = 0; i < 6; i++) {
+		status = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
+		if (status < 0)
+			return status;
+		if (!(status & ADT7410_STAT_NOT_RDY))
+			return 0;
+		msleep(60);
+	}
+	return -ETIMEDOUT;
+}
+
+static struct adt7410_data *adt7410_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7410_data *data = i2c_get_clientdata(client);
+	struct adt7410_data *ret = data;
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+		int i, status;
+
+		dev_dbg(&client->dev, "Starting update\n");
+
+		status = adt7410_temp_ready(client); /* check for new value */
+		if (unlikely(status)) {
+			ret = ERR_PTR(status);
+			goto abort;
+		}
+		for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+			status = i2c_smbus_read_word_swapped(client,
+							ADT7410_REG_TEMP[i]);
+			if (unlikely(status < 0)) {
+				dev_dbg(dev,
+					"Failed to read value: reg %d, error %d\n",
+					ADT7410_REG_TEMP[i], status);
+				ret = ERR_PTR(status);
+				goto abort;
+			}
+			data->temp[i] = status;
+		}
+		status = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
+		if (unlikely(status < 0)) {
+			dev_dbg(dev,
+				"Failed to read value: reg %d, error %d\n",
+				ADT7410_T_HYST, status);
+			ret = ERR_PTR(status);
+			goto abort;
+		}
+		data->hyst = status;
+		data->last_updated = jiffies;
+		data->valid = true;
+	}
+
+abort:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static s16 ADT7410_TEMP_TO_REG(long temp)
+{
+	return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, ADT7410_TEMP_MIN,
+					       ADT7410_TEMP_MAX) * 128, 1000);
+}
+
+static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
+{
+	/* in 13 bit mode, bits 0-2 are status flags - mask them out */
+	if (!(data->config & ADT7410_RESOLUTION))
+		reg &= ADT7410_T13_VALUE_MASK;
+	/*
+	 * temperature is stored in twos complement format, in steps of
+	 * 1/128°C
+	 */
+	return DIV_ROUND_CLOSEST(reg * 1000, 128);
+}
+
+/*-----------------------------------------------------------------------*/
+
+/* sysfs attributes for hwmon */
+
+static ssize_t adt7410_show_temp(struct device *dev,
+				 struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct adt7410_data *data = adt7410_update_device(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
+		       data->temp[attr->index]));
+}
+
+static ssize_t adt7410_set_temp(struct device *dev,
+				struct device_attribute *da,
+				const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7410_data *data = i2c_get_clientdata(client);
+	int nr = attr->index;
+	long temp;
+	int ret;
+
+	ret = kstrtol(buf, 10, &temp);
+	if (ret)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
+	ret = i2c_smbus_write_word_swapped(client, ADT7410_REG_TEMP[nr],
+					   data->temp[nr]);
+	if (ret)
+		count = ret;
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t adt7410_show_t_hyst(struct device *dev,
+				   struct device_attribute *da,
+				   char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct adt7410_data *data;
+	int nr = attr->index;
+	int hyst;
+
+	data = adt7410_update_device(dev);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
+
+	/*
+	 * hysteresis is stored as a 4 bit offset in the device, convert it
+	 * to an absolute value
+	 */
+	if (nr == 2)	/* min has positive offset, others have negative */
+		hyst = -hyst;
+	return sprintf(buf, "%d\n",
+		       ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
+}
+
+static ssize_t adt7410_set_t_hyst(struct device *dev,
+				  struct device_attribute *da,
+				  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7410_data *data = i2c_get_clientdata(client);
+	int limit, ret;
+	long hyst;
+
+	ret = kstrtol(buf, 10, &hyst);
+	if (ret)
+		return ret;
+	/* convert absolute hysteresis value to a 4 bit delta value */
+	limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
+	hyst = SENSORS_LIMIT(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
+	data->hyst = SENSORS_LIMIT(DIV_ROUND_CLOSEST(limit - hyst, 1000),
+				   0, ADT7410_T_HYST_MASK);
+	ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static ssize_t adt7410_show_alarm(struct device *dev,
+				  struct device_attribute *da,
+				  char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", !!(ret & attr->index));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+			  adt7410_show_temp, adt7410_set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+			  adt7410_show_temp, adt7410_set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
+			  adt7410_show_temp, adt7410_set_temp, 3);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+			  adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
+			  adt7410_show_t_hyst, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
+			  adt7410_show_t_hyst, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
+			  NULL, ADT7410_STAT_T_LOW);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
+			  NULL, ADT7410_STAT_T_HIGH);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
+			  NULL, ADT7410_STAT_T_CRIT);
+
+static struct attribute *adt7410_attributes[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group adt7410_group = {
+	.attrs = adt7410_attributes,
+};
+
+/*-----------------------------------------------------------------------*/
+
+/* device probe and removal */
+
+static int adt7410_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct adt7410_data *data;
+	int ret;
+
+	if (!i2c_check_functionality(client->adapter,
+			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(&client->dev, sizeof(struct adt7410_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	/* configure as specified */
+	ret = i2c_smbus_read_byte_data(client, ADT7410_CONFIG);
+	if (ret < 0) {
+		dev_dbg(&client->dev, "Can't read config? %d\n", ret);
+		return ret;
+	}
+	data->oldconfig = ret;
+	/*
+	 * Set to 16 bit resolution, continous conversion and comparator mode.
+	 */
+	data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
+			ADT7410_EVENT_MODE;
+	if (data->config != data->oldconfig) {
+		ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
+						data->config);
+		if (ret)
+			return ret;
+	}
+	dev_dbg(&client->dev, "Config %02x\n", data->config);
+
+	/* Register sysfs hooks */
+	ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
+	if (ret)
+		goto exit_restore;
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		ret = PTR_ERR(data->hwmon_dev);
+		goto exit_remove;
+	}
+
+	dev_info(&client->dev, "sensor '%s'\n", client->name);
+
+	return 0;
+
+exit_remove:
+	sysfs_remove_group(&client->dev.kobj, &adt7410_group);
+exit_restore:
+	i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->oldconfig);
+	return ret;
+}
+
+static int adt7410_remove(struct i2c_client *client)
+{
+	struct adt7410_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&client->dev.kobj, &adt7410_group);
+	if (data->oldconfig != data->config)
+		i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
+					  data->oldconfig);
+	return 0;
+}
+
+static const struct i2c_device_id adt7410_ids[] = {
+	{ "adt7410", adt7410, },
+	{ /* LIST END */ }
+};
+MODULE_DEVICE_TABLE(i2c, adt7410_ids);
+
+#ifdef CONFIG_PM
+static int adt7410_suspend(struct device *dev)
+{
+	int ret;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7410_data *data = i2c_get_clientdata(client);
+
+	ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
+					data->config | ADT7410_PD);
+	return ret;
+}
+
+static int adt7410_resume(struct device *dev)
+{
+	int ret;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7410_data *data = i2c_get_clientdata(client);
+
+	ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->config);
+	return ret;
+}
+
+static const struct dev_pm_ops adt7410_dev_pm_ops = {
+	.suspend	= adt7410_suspend,
+	.resume		= adt7410_resume,
+};
+#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
+#else
+#define ADT7410_DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static struct i2c_driver adt7410_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "adt7410",
+		.pm	= ADT7410_DEV_PM_OPS,
+	},
+	.probe		= adt7410_probe,
+	.remove		= adt7410_remove,
+	.id_table	= adt7410_ids,
+	.address_list	= normal_i2c,
+};
+
+module_i2c_driver(adt7410_driver);
+
+MODULE_AUTHOR("Hartmut Knaack");
+MODULE_DESCRIPTION("ADT7410 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c
index 71bacc5..fe72c69 100644
--- a/drivers/hwmon/adt7411.c
+++ b/drivers/hwmon/adt7411.c
@@ -283,7 +283,7 @@ static int __devinit adt7411_probe(struct i2c_client *client,
 	struct adt7411_data *data;
 	int ret;
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -294,14 +294,14 @@ static int __devinit adt7411_probe(struct i2c_client *client,
 	ret = adt7411_modify_bit(client, ADT7411_REG_CFG1,
 				 ADT7411_CFG1_START_MONITOR, 1);
 	if (ret < 0)
-		goto exit_free;
+		return ret;
 
 	/* force update on first occasion */
 	data->next_update = jiffies;
 
 	ret = sysfs_create_group(&client->dev.kobj, &adt7411_attr_grp);
 	if (ret)
-		goto exit_free;
+		return ret;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -315,8 +315,6 @@ static int __devinit adt7411_probe(struct i2c_client *client,
 
  exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp);
- exit_free:
-	kfree(data);
 	return ret;
 }
 
@@ -326,7 +324,6 @@ static int __devexit adt7411_remove(struct i2c_client *client)
 
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c
index 339269f..baee482 100644
--- a/drivers/hwmon/adt7462.c
+++ b/drivers/hwmon/adt7462.c
@@ -1931,11 +1931,10 @@ static int adt7462_probe(struct i2c_client *client,
 	struct adt7462_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct adt7462_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct adt7462_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->lock);
@@ -1946,7 +1945,7 @@ static int adt7462_probe(struct i2c_client *client,
 	data->attrs.attrs = adt7462_attr;
 	err = sysfs_create_group(&client->dev.kobj, &data->attrs);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -1958,9 +1957,6 @@ static int adt7462_probe(struct i2c_client *client,
 
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &data->attrs);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -1970,7 +1966,6 @@ static int adt7462_remove(struct i2c_client *client)
 
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &data->attrs);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index 54ec890..39ecb1a 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -1256,11 +1256,10 @@ static int adt7470_probe(struct i2c_client *client,
 	struct adt7470_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct adt7470_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct adt7470_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	data->num_temp_sensors = -1;
 	data->auto_update_interval = AUTO_UPDATE_INTERVAL;
@@ -1277,7 +1276,7 @@ static int adt7470_probe(struct i2c_client *client,
 	data->attrs.attrs = adt7470_attr;
 	err = sysfs_create_group(&client->dev.kobj, &data->attrs);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -1299,9 +1298,6 @@ exit_unregister:
 	hwmon_device_unregister(data->hwmon_dev);
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &data->attrs);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -1313,7 +1309,6 @@ static int adt7470_remove(struct i2c_client *client)
 	wait_for_completion(&data->auto_update_stop);
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &data->attrs);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c
index f600fa1..ae482e3 100644
--- a/drivers/hwmon/amc6821.c
+++ b/drivers/hwmon/amc6821.c
@@ -862,12 +862,10 @@ static int amc6821_probe(
 	struct amc6821_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct amc6821_data), GFP_KERNEL);
-	if (!data) {
-		dev_err(&client->dev, "out of memory.\n");
+	data = devm_kzalloc(&client->dev, sizeof(struct amc6821_data),
+			    GFP_KERNEL);
+	if (!data)
 		return -ENOMEM;
-	}
-
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -877,11 +875,11 @@ static int amc6821_probe(
 	 */
 	err = amc6821_init_client(client);
 	if (err)
-		goto err_free;
+		return err;
 
 	err = sysfs_create_group(&client->dev.kobj, &amc6821_attr_grp);
 	if (err)
-		goto err_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (!IS_ERR(data->hwmon_dev))
@@ -890,8 +888,6 @@ static int amc6821_probe(
 	err = PTR_ERR(data->hwmon_dev);
 	dev_err(&client->dev, "error registering hwmon device.\n");
 	sysfs_remove_group(&client->dev.kobj, &amc6821_attr_grp);
-err_free:
-	kfree(data);
 	return err;
 }
 
@@ -902,8 +898,6 @@ static int amc6821_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &amc6821_attr_grp);
 
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 4b8814d..a227be4 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -787,12 +787,10 @@ static int asb100_probe(struct i2c_client *client,
 	int err;
 	struct asb100_data *data;
 
-	data = kzalloc(sizeof(struct asb100_data), GFP_KERNEL);
-	if (!data) {
-		pr_debug("probe failed, kzalloc failed!\n");
-		err = -ENOMEM;
-		goto ERROR0;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct asb100_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->lock);
@@ -801,7 +799,7 @@ static int asb100_probe(struct i2c_client *client,
 	/* Attach secondary lm75 clients */
 	err = asb100_detect_subclients(client);
 	if (err)
-		goto ERROR1;
+		return err;
 
 	/* Initialize the chip */
 	asb100_init_client(client);
@@ -829,9 +827,6 @@ ERROR4:
 ERROR3:
 	i2c_unregister_device(data->lm75[1]);
 	i2c_unregister_device(data->lm75[0]);
-ERROR1:
-	kfree(data);
-ERROR0:
 	return err;
 }
 
@@ -845,8 +840,6 @@ static int asb100_remove(struct i2c_client *client)
 	i2c_unregister_device(data->lm75[1]);
 	i2c_unregister_device(data->lm75[0]);
 
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index faa16f8..984a3f1 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -196,7 +196,7 @@ struct tjmax {
 	int tjmax;
 };
 
-static struct tjmax __cpuinitconst tjmax_table[] = {
+static const struct tjmax __cpuinitconst tjmax_table[] = {
 	{ "CPU D410", 100000 },
 	{ "CPU D425", 100000 },
 	{ "CPU D510", 100000 },
@@ -815,17 +815,20 @@ static int __init coretemp_init(void)
 	if (err)
 		goto exit;
 
+	get_online_cpus();
 	for_each_online_cpu(i)
 		get_core_online(i);
 
 #ifndef CONFIG_HOTPLUG_CPU
 	if (list_empty(&pdev_list)) {
+		put_online_cpus();
 		err = -ENODEV;
 		goto exit_driver_unreg;
 	}
 #endif
 
 	register_hotcpu_notifier(&coretemp_cpu_notifier);
+	put_online_cpus();
 	return 0;
 
 #ifndef CONFIG_HOTPLUG_CPU
@@ -840,6 +843,7 @@ static void __exit coretemp_exit(void)
 {
 	struct pdev_entry *p, *n;
 
+	get_online_cpus();
 	unregister_hotcpu_notifier(&coretemp_cpu_notifier);
 	mutex_lock(&pdev_list_mutex);
 	list_for_each_entry_safe(p, n, &pdev_list, list) {
@@ -848,6 +852,7 @@ static void __exit coretemp_exit(void)
 		kfree(p);
 	}
 	mutex_unlock(&pdev_list_mutex);
+	put_online_cpus();
 	platform_driver_unregister(&coretemp_driver);
 }
 
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index e7c6a19..fe0eeec 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -2475,11 +2475,9 @@ static int dme1737_i2c_probe(struct i2c_client *client,
 	struct device *dev = &client->dev;
 	int err;
 
-	data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(dev, sizeof(struct dme1737_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	data->type = id->driver_data;
@@ -2491,14 +2489,14 @@ static int dme1737_i2c_probe(struct i2c_client *client,
 	err = dme1737_init_device(dev);
 	if (err) {
 		dev_err(dev, "Failed to initialize device.\n");
-		goto exit_kfree;
+		return err;
 	}
 
 	/* Create sysfs files */
 	err = dme1737_create_files(dev);
 	if (err) {
 		dev_err(dev, "Failed to create sysfs files.\n");
-		goto exit_kfree;
+		return err;
 	}
 
 	/* Register device */
@@ -2513,9 +2511,6 @@ static int dme1737_i2c_probe(struct i2c_client *client,
 
 exit_remove:
 	dme1737_remove_files(dev);
-exit_kfree:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -2526,7 +2521,6 @@ static int dme1737_i2c_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	dme1737_remove_files(&client->dev);
 
-	kfree(data);
 	return 0;
 }
 
@@ -2645,19 +2639,16 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
 	int err;
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!request_region(res->start, DME1737_EXTENT, "dme1737")) {
+	if (!devm_request_region(dev, res->start, DME1737_EXTENT, "dme1737")) {
 		dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n",
 			(unsigned short)res->start,
 			(unsigned short)res->start + DME1737_EXTENT - 1);
-		err = -EBUSY;
-		goto exit;
+		return -EBUSY;
 	}
 
-	data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit_release_region;
-	}
+	data = devm_kzalloc(dev, sizeof(struct dme1737_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	data->addr = res->start;
 	platform_set_drvdata(pdev, data);
@@ -2683,8 +2674,7 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
 			   (device == SCH5127_DEVICE)) {
 			data->type = sch5127;
 		} else {
-			err = -ENODEV;
-			goto exit_kfree;
+			return -ENODEV;
 		}
 	}
 
@@ -2703,14 +2693,14 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
 	err = dme1737_init_device(dev);
 	if (err) {
 		dev_err(dev, "Failed to initialize device.\n");
-		goto exit_kfree;
+		return err;
 	}
 
 	/* Create sysfs files */
 	err = dme1737_create_files(dev);
 	if (err) {
 		dev_err(dev, "Failed to create sysfs files.\n");
-		goto exit_kfree;
+		return err;
 	}
 
 	/* Register device */
@@ -2725,12 +2715,6 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
 
 exit_remove_files:
 	dme1737_remove_files(dev);
-exit_kfree:
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-exit_release_region:
-	release_region(res->start, DME1737_EXTENT);
-exit:
 	return err;
 }
 
@@ -2740,9 +2724,6 @@ static int __devexit dme1737_isa_remove(struct platform_device *pdev)
 
 	hwmon_device_unregister(data->hwmon_dev);
 	dme1737_remove_files(&pdev->dev);
-	release_region(data->addr, DME1737_EXTENT);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
 
 	return 0;
 }
diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c
index 50663ef..f1d6b42 100644
--- a/drivers/hwmon/ds620.c
+++ b/drivers/hwmon/ds620.c
@@ -232,11 +232,10 @@ static int ds620_probe(struct i2c_client *client,
 	struct ds620_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct ds620_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct ds620_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -247,7 +246,7 @@ static int ds620_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &ds620_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -261,9 +260,6 @@ static int ds620_probe(struct i2c_client *client,
 
 exit_remove_files:
 	sysfs_remove_group(&client->dev.kobj, &ds620_group);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -274,8 +270,6 @@ static int ds620_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &ds620_group);
 
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c
index 149dcb0..68ab94b 100644
--- a/drivers/hwmon/emc1403.c
+++ b/drivers/hwmon/emc1403.c
@@ -306,11 +306,10 @@ static int emc1403_probe(struct i2c_client *client,
 	int res;
 	struct thermal_data *data;
 
-	data = kzalloc(sizeof(struct thermal_data), GFP_KERNEL);
-	if (data == NULL) {
-		dev_warn(&client->dev, "out of memory");
+	data = devm_kzalloc(&client->dev, sizeof(struct thermal_data),
+			    GFP_KERNEL);
+	if (data == NULL)
 		return -ENOMEM;
-	}
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->mutex);
@@ -319,21 +318,19 @@ static int emc1403_probe(struct i2c_client *client,
 	res = sysfs_create_group(&client->dev.kobj, &m_thermal_gr);
 	if (res) {
 		dev_warn(&client->dev, "create group failed\n");
-		goto thermal_error1;
+		return res;
 	}
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
 		res = PTR_ERR(data->hwmon_dev);
 		dev_warn(&client->dev, "register hwmon dev failed\n");
-		goto thermal_error2;
+		goto thermal_error;
 	}
 	dev_info(&client->dev, "EMC1403 Thermal chip found\n");
-	return res;
+	return 0;
 
-thermal_error2:
+thermal_error:
 	sysfs_remove_group(&client->dev.kobj, &m_thermal_gr);
-thermal_error1:
-	kfree(data);
 	return res;
 }
 
@@ -343,7 +340,6 @@ static int emc1403_remove(struct i2c_client *client)
 
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &m_thermal_gr);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c
index 7bb8e88..77f434c 100644
--- a/drivers/hwmon/emc2103.c
+++ b/drivers/hwmon/emc2103.c
@@ -590,7 +590,8 @@ emc2103_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 		return -EIO;
 
-	data = kzalloc(sizeof(struct emc2103_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct emc2103_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -608,7 +609,7 @@ emc2103_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		if (status < 0) {
 			dev_dbg(&client->dev, "reg 0x%02x, err %d\n", REG_CONF1,
 				status);
-			goto exit_free;
+			return status;
 		}
 
 		/* detect current state of hardware */
@@ -631,7 +632,7 @@ emc2103_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	/* Register sysfs hooks */
 	status = sysfs_create_group(&client->dev.kobj, &emc2103_group);
 	if (status)
-		goto exit_free;
+		return status;
 
 	if (data->temp_count >= 3) {
 		status = sysfs_create_group(&client->dev.kobj,
@@ -666,8 +667,6 @@ exit_remove_temp3:
 		sysfs_remove_group(&client->dev.kobj, &emc2103_temp3_group);
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &emc2103_group);
-exit_free:
-	kfree(data);
 	return status;
 }
 
@@ -685,7 +684,6 @@ static int emc2103_remove(struct i2c_client *client)
 
 	sysfs_remove_group(&client->dev.kobj, &emc2103_group);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/exynos4_tmu.c b/drivers/hwmon/exynos4_tmu.c
deleted file mode 100644
index e912059..0000000
--- a/drivers/hwmon/exynos4_tmu.c
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * exynos4_tmu.c - Samsung EXYNOS4 TMU (Thermal Management Unit)
- *
- *  Copyright (C) 2011 Samsung Electronics
- *  Donggeun Kim <dg77.kim@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/clk.h>
-#include <linux/workqueue.h>
-#include <linux/sysfs.h>
-#include <linux/kobject.h>
-#include <linux/io.h>
-#include <linux/mutex.h>
-
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-
-#include <linux/platform_data/exynos4_tmu.h>
-
-#define EXYNOS4_TMU_REG_TRIMINFO	0x0
-#define EXYNOS4_TMU_REG_CONTROL		0x20
-#define EXYNOS4_TMU_REG_STATUS		0x28
-#define EXYNOS4_TMU_REG_CURRENT_TEMP	0x40
-#define EXYNOS4_TMU_REG_THRESHOLD_TEMP	0x44
-#define EXYNOS4_TMU_REG_TRIG_LEVEL0	0x50
-#define EXYNOS4_TMU_REG_TRIG_LEVEL1	0x54
-#define EXYNOS4_TMU_REG_TRIG_LEVEL2	0x58
-#define EXYNOS4_TMU_REG_TRIG_LEVEL3	0x5C
-#define EXYNOS4_TMU_REG_PAST_TEMP0	0x60
-#define EXYNOS4_TMU_REG_PAST_TEMP1	0x64
-#define EXYNOS4_TMU_REG_PAST_TEMP2	0x68
-#define EXYNOS4_TMU_REG_PAST_TEMP3	0x6C
-#define EXYNOS4_TMU_REG_INTEN		0x70
-#define EXYNOS4_TMU_REG_INTSTAT		0x74
-#define EXYNOS4_TMU_REG_INTCLEAR	0x78
-
-#define EXYNOS4_TMU_GAIN_SHIFT		8
-#define EXYNOS4_TMU_REF_VOLTAGE_SHIFT	24
-
-#define EXYNOS4_TMU_TRIM_TEMP_MASK	0xff
-#define EXYNOS4_TMU_CORE_ON	3
-#define EXYNOS4_TMU_CORE_OFF	2
-#define EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET	50
-#define EXYNOS4_TMU_TRIG_LEVEL0_MASK	0x1
-#define EXYNOS4_TMU_TRIG_LEVEL1_MASK	0x10
-#define EXYNOS4_TMU_TRIG_LEVEL2_MASK	0x100
-#define EXYNOS4_TMU_TRIG_LEVEL3_MASK	0x1000
-#define EXYNOS4_TMU_INTCLEAR_VAL	0x1111
-
-struct exynos4_tmu_data {
-	struct exynos4_tmu_platform_data *pdata;
-	struct device *hwmon_dev;
-	struct resource *mem;
-	void __iomem *base;
-	int irq;
-	struct work_struct irq_work;
-	struct mutex lock;
-	struct clk *clk;
-	u8 temp_error1, temp_error2;
-};
-
-/*
- * TMU treats temperature as a mapped temperature code.
- * The temperature is converted differently depending on the calibration type.
- */
-static int temp_to_code(struct exynos4_tmu_data *data, u8 temp)
-{
-	struct exynos4_tmu_platform_data *pdata = data->pdata;
-	int temp_code;
-
-	/* temp should range between 25 and 125 */
-	if (temp < 25 || temp > 125) {
-		temp_code = -EINVAL;
-		goto out;
-	}
-
-	switch (pdata->cal_type) {
-	case TYPE_TWO_POINT_TRIMMING:
-		temp_code = (temp - 25) *
-		    (data->temp_error2 - data->temp_error1) /
-		    (85 - 25) + data->temp_error1;
-		break;
-	case TYPE_ONE_POINT_TRIMMING:
-		temp_code = temp + data->temp_error1 - 25;
-		break;
-	default:
-		temp_code = temp + EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
-		break;
-	}
-out:
-	return temp_code;
-}
-
-/*
- * Calculate a temperature value from a temperature code.
- * The unit of the temperature is degree Celsius.
- */
-static int code_to_temp(struct exynos4_tmu_data *data, u8 temp_code)
-{
-	struct exynos4_tmu_platform_data *pdata = data->pdata;
-	int temp;
-
-	/* temp_code should range between 75 and 175 */
-	if (temp_code < 75 || temp_code > 175) {
-		temp = -ENODATA;
-		goto out;
-	}
-
-	switch (pdata->cal_type) {
-	case TYPE_TWO_POINT_TRIMMING:
-		temp = (temp_code - data->temp_error1) * (85 - 25) /
-		    (data->temp_error2 - data->temp_error1) + 25;
-		break;
-	case TYPE_ONE_POINT_TRIMMING:
-		temp = temp_code - data->temp_error1 + 25;
-		break;
-	default:
-		temp = temp_code - EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
-		break;
-	}
-out:
-	return temp;
-}
-
-static int exynos4_tmu_initialize(struct platform_device *pdev)
-{
-	struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
-	struct exynos4_tmu_platform_data *pdata = data->pdata;
-	unsigned int status, trim_info;
-	int ret = 0, threshold_code;
-
-	mutex_lock(&data->lock);
-	clk_enable(data->clk);
-
-	status = readb(data->base + EXYNOS4_TMU_REG_STATUS);
-	if (!status) {
-		ret = -EBUSY;
-		goto out;
-	}
-
-	/* Save trimming info in order to perform calibration */
-	trim_info = readl(data->base + EXYNOS4_TMU_REG_TRIMINFO);
-	data->temp_error1 = trim_info & EXYNOS4_TMU_TRIM_TEMP_MASK;
-	data->temp_error2 = ((trim_info >> 8) & EXYNOS4_TMU_TRIM_TEMP_MASK);
-
-	/* Write temperature code for threshold */
-	threshold_code = temp_to_code(data, pdata->threshold);
-	if (threshold_code < 0) {
-		ret = threshold_code;
-		goto out;
-	}
-	writeb(threshold_code,
-		data->base + EXYNOS4_TMU_REG_THRESHOLD_TEMP);
-
-	writeb(pdata->trigger_levels[0],
-		data->base + EXYNOS4_TMU_REG_TRIG_LEVEL0);
-	writeb(pdata->trigger_levels[1],
-		data->base + EXYNOS4_TMU_REG_TRIG_LEVEL1);
-	writeb(pdata->trigger_levels[2],
-		data->base + EXYNOS4_TMU_REG_TRIG_LEVEL2);
-	writeb(pdata->trigger_levels[3],
-		data->base + EXYNOS4_TMU_REG_TRIG_LEVEL3);
-
-	writel(EXYNOS4_TMU_INTCLEAR_VAL,
-		data->base + EXYNOS4_TMU_REG_INTCLEAR);
-out:
-	clk_disable(data->clk);
-	mutex_unlock(&data->lock);
-
-	return ret;
-}
-
-static void exynos4_tmu_control(struct platform_device *pdev, bool on)
-{
-	struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
-	struct exynos4_tmu_platform_data *pdata = data->pdata;
-	unsigned int con, interrupt_en;
-
-	mutex_lock(&data->lock);
-	clk_enable(data->clk);
-
-	con = pdata->reference_voltage << EXYNOS4_TMU_REF_VOLTAGE_SHIFT |
-		pdata->gain << EXYNOS4_TMU_GAIN_SHIFT;
-	if (on) {
-		con |= EXYNOS4_TMU_CORE_ON;
-		interrupt_en = pdata->trigger_level3_en << 12 |
-			pdata->trigger_level2_en << 8 |
-			pdata->trigger_level1_en << 4 |
-			pdata->trigger_level0_en;
-	} else {
-		con |= EXYNOS4_TMU_CORE_OFF;
-		interrupt_en = 0; /* Disable all interrupts */
-	}
-	writel(interrupt_en, data->base + EXYNOS4_TMU_REG_INTEN);
-	writel(con, data->base + EXYNOS4_TMU_REG_CONTROL);
-
-	clk_disable(data->clk);
-	mutex_unlock(&data->lock);
-}
-
-static int exynos4_tmu_read(struct exynos4_tmu_data *data)
-{
-	u8 temp_code;
-	int temp;
-
-	mutex_lock(&data->lock);
-	clk_enable(data->clk);
-
-	temp_code = readb(data->base + EXYNOS4_TMU_REG_CURRENT_TEMP);
-	temp = code_to_temp(data, temp_code);
-
-	clk_disable(data->clk);
-	mutex_unlock(&data->lock);
-
-	return temp;
-}
-
-static void exynos4_tmu_work(struct work_struct *work)
-{
-	struct exynos4_tmu_data *data = container_of(work,
-			struct exynos4_tmu_data, irq_work);
-
-	mutex_lock(&data->lock);
-	clk_enable(data->clk);
-
-	writel(EXYNOS4_TMU_INTCLEAR_VAL, data->base + EXYNOS4_TMU_REG_INTCLEAR);
-
-	kobject_uevent(&data->hwmon_dev->kobj, KOBJ_CHANGE);
-
-	enable_irq(data->irq);
-
-	clk_disable(data->clk);
-	mutex_unlock(&data->lock);
-}
-
-static irqreturn_t exynos4_tmu_irq(int irq, void *id)
-{
-	struct exynos4_tmu_data *data = id;
-
-	disable_irq_nosync(irq);
-	schedule_work(&data->irq_work);
-
-	return IRQ_HANDLED;
-}
-
-static ssize_t exynos4_tmu_show_name(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	return sprintf(buf, "exynos4-tmu\n");
-}
-
-static ssize_t exynos4_tmu_show_temp(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct exynos4_tmu_data *data = dev_get_drvdata(dev);
-	int ret;
-
-	ret = exynos4_tmu_read(data);
-	if (ret < 0)
-		return ret;
-
-	/* convert from degree Celsius to millidegree Celsius */
-	return sprintf(buf, "%d\n", ret * 1000);
-}
-
-static ssize_t exynos4_tmu_show_alarm(struct device *dev,
-		struct device_attribute *devattr, char *buf)
-{
-	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct exynos4_tmu_data *data = dev_get_drvdata(dev);
-	struct exynos4_tmu_platform_data *pdata = data->pdata;
-	int temp;
-	unsigned int trigger_level;
-
-	temp = exynos4_tmu_read(data);
-	if (temp < 0)
-		return temp;
-
-	trigger_level = pdata->threshold + pdata->trigger_levels[attr->index];
-
-	return sprintf(buf, "%d\n", !!(temp > trigger_level));
-}
-
-static ssize_t exynos4_tmu_show_level(struct device *dev,
-		struct device_attribute *devattr, char *buf)
-{
-	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct exynos4_tmu_data *data = dev_get_drvdata(dev);
-	struct exynos4_tmu_platform_data *pdata = data->pdata;
-	unsigned int temp = pdata->threshold +
-			pdata->trigger_levels[attr->index];
-
-	return sprintf(buf, "%u\n", temp * 1000);
-}
-
-static DEVICE_ATTR(name, S_IRUGO, exynos4_tmu_show_name, NULL);
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, exynos4_tmu_show_temp, NULL, 0);
-
-static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
-		exynos4_tmu_show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
-		exynos4_tmu_show_alarm, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO,
-		exynos4_tmu_show_alarm, NULL, 3);
-
-static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, exynos4_tmu_show_level, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, exynos4_tmu_show_level, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp1_emergency, S_IRUGO,
-		exynos4_tmu_show_level, NULL, 3);
-
-static struct attribute *exynos4_tmu_attributes[] = {
-	&dev_attr_name.attr,
-	&sensor_dev_attr_temp1_input.dev_attr.attr,
-	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
-	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
-	&sensor_dev_attr_temp1_emergency_alarm.dev_attr.attr,
-	&sensor_dev_attr_temp1_max.dev_attr.attr,
-	&sensor_dev_attr_temp1_crit.dev_attr.attr,
-	&sensor_dev_attr_temp1_emergency.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group exynos4_tmu_attr_group = {
-	.attrs = exynos4_tmu_attributes,
-};
-
-static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
-{
-	struct exynos4_tmu_data *data;
-	struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data;
-	int ret;
-
-	if (!pdata) {
-		dev_err(&pdev->dev, "No platform init data supplied.\n");
-		return -ENODEV;
-	}
-
-	data = kzalloc(sizeof(struct exynos4_tmu_data), GFP_KERNEL);
-	if (!data) {
-		dev_err(&pdev->dev, "Failed to allocate driver structure\n");
-		return -ENOMEM;
-	}
-
-	data->irq = platform_get_irq(pdev, 0);
-	if (data->irq < 0) {
-		ret = data->irq;
-		dev_err(&pdev->dev, "Failed to get platform irq\n");
-		goto err_free;
-	}
-
-	INIT_WORK(&data->irq_work, exynos4_tmu_work);
-
-	data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!data->mem) {
-		ret = -ENOENT;
-		dev_err(&pdev->dev, "Failed to get platform resource\n");
-		goto err_free;
-	}
-
-	data->mem = request_mem_region(data->mem->start,
-			resource_size(data->mem), pdev->name);
-	if (!data->mem) {
-		ret = -ENODEV;
-		dev_err(&pdev->dev, "Failed to request memory region\n");
-		goto err_free;
-	}
-
-	data->base = ioremap(data->mem->start, resource_size(data->mem));
-	if (!data->base) {
-		ret = -ENODEV;
-		dev_err(&pdev->dev, "Failed to ioremap memory\n");
-		goto err_mem_region;
-	}
-
-	ret = request_irq(data->irq, exynos4_tmu_irq,
-		IRQF_TRIGGER_RISING,
-		"exynos4-tmu", data);
-	if (ret) {
-		dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
-		goto err_io_remap;
-	}
-
-	data->clk = clk_get(NULL, "tmu_apbif");
-	if (IS_ERR(data->clk)) {
-		ret = PTR_ERR(data->clk);
-		dev_err(&pdev->dev, "Failed to get clock\n");
-		goto err_irq;
-	}
-
-	data->pdata = pdata;
-	platform_set_drvdata(pdev, data);
-	mutex_init(&data->lock);
-
-	ret = exynos4_tmu_initialize(pdev);
-	if (ret) {
-		dev_err(&pdev->dev, "Failed to initialize TMU\n");
-		goto err_clk;
-	}
-
-	ret = sysfs_create_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
-	if (ret) {
-		dev_err(&pdev->dev, "Failed to create sysfs group\n");
-		goto err_clk;
-	}
-
-	data->hwmon_dev = hwmon_device_register(&pdev->dev);
-	if (IS_ERR(data->hwmon_dev)) {
-		ret = PTR_ERR(data->hwmon_dev);
-		dev_err(&pdev->dev, "Failed to register hwmon device\n");
-		goto err_create_group;
-	}
-
-	exynos4_tmu_control(pdev, true);
-
-	return 0;
-
-err_create_group:
-	sysfs_remove_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
-err_clk:
-	platform_set_drvdata(pdev, NULL);
-	clk_put(data->clk);
-err_irq:
-	free_irq(data->irq, data);
-err_io_remap:
-	iounmap(data->base);
-err_mem_region:
-	release_mem_region(data->mem->start, resource_size(data->mem));
-err_free:
-	kfree(data);
-
-	return ret;
-}
-
-static int __devexit exynos4_tmu_remove(struct platform_device *pdev)
-{
-	struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
-
-	exynos4_tmu_control(pdev, false);
-
-	hwmon_device_unregister(data->hwmon_dev);
-	sysfs_remove_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
-
-	clk_put(data->clk);
-
-	free_irq(data->irq, data);
-
-	iounmap(data->base);
-	release_mem_region(data->mem->start, resource_size(data->mem));
-
-	platform_set_drvdata(pdev, NULL);
-
-	kfree(data);
-
-	return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int exynos4_tmu_suspend(struct device *dev)
-{
-	exynos4_tmu_control(to_platform_device(dev), false);
-
-	return 0;
-}
-
-static int exynos4_tmu_resume(struct device *dev)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-
-	exynos4_tmu_initialize(pdev);
-	exynos4_tmu_control(pdev, true);
-
-	return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(exynos4_tmu_pm,
-			 exynos4_tmu_suspend, exynos4_tmu_resume);
-#define EXYNOS4_TMU_PM	&exynos4_tmu_pm
-#else
-#define EXYNOS4_TMU_PM	NULL
-#endif
-
-static struct platform_driver exynos4_tmu_driver = {
-	.driver = {
-		.name   = "exynos4-tmu",
-		.owner  = THIS_MODULE,
-		.pm     = EXYNOS4_TMU_PM,
-	},
-	.probe = exynos4_tmu_probe,
-	.remove	= __devexit_p(exynos4_tmu_remove),
-};
-
-module_platform_driver(exynos4_tmu_driver);
-
-MODULE_DESCRIPTION("EXYNOS4 TMU Driver");
-MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:exynos4-tmu");
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
index 6d12263..50e4ce2 100644
--- a/drivers/hwmon/f71882fg.c
+++ b/drivers/hwmon/f71882fg.c
@@ -2274,7 +2274,8 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
 	int err, i;
 	u8 start_reg, reg;
 
-	data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(struct f71882fg_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -2288,13 +2289,11 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
 	start_reg = f71882fg_read8(data, F71882FG_REG_START);
 	if (start_reg & 0x04) {
 		dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
-		err = -ENODEV;
-		goto exit_free;
+		return -ENODEV;
 	}
 	if (!(start_reg & 0x03)) {
 		dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
-		err = -ENODEV;
-		goto exit_free;
+		return -ENODEV;
 	}
 
 	/* Register sysfs interface files */
@@ -2422,8 +2421,6 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
 exit_unregister_sysfs:
 	f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
 	return err; /* f71882fg_remove() also frees our data */
-exit_free:
-	kfree(data);
 	return err;
 }
 
@@ -2525,17 +2522,13 @@ static int f71882fg_remove(struct platform_device *pdev)
 				ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
 		}
 	}
-
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-
 	return 0;
 }
 
-static int __init f71882fg_find(int sioaddr, unsigned short *address,
-	struct f71882fg_sio_data *sio_data)
+static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data)
 {
 	u16 devid;
+	unsigned short address;
 	int err = superio_enter(sioaddr);
 	if (err)
 		return err;
@@ -2603,25 +2596,25 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
 		goto exit;
 	}
 
-	*address = superio_inw(sioaddr, SIO_REG_ADDR);
-	if (*address == 0) {
+	address = superio_inw(sioaddr, SIO_REG_ADDR);
+	if (address == 0) {
 		pr_warn("Base address not set\n");
 		err = -ENODEV;
 		goto exit;
 	}
-	*address &= ~(REGION_LENGTH - 1);	/* Ignore 3 LSB */
+	address &= ~(REGION_LENGTH - 1);	/* Ignore 3 LSB */
 
-	err = 0;
+	err = address;
 	pr_info("Found %s chip at %#x, revision %d\n",
-		f71882fg_names[sio_data->type],	(unsigned int)*address,
+		f71882fg_names[sio_data->type],	(unsigned int)address,
 		(int)superio_inb(sioaddr, SIO_REG_DEVREV));
 exit:
 	superio_exit(sioaddr);
 	return err;
 }
 
-static int __init f71882fg_device_add(unsigned short address,
-	const struct f71882fg_sio_data *sio_data)
+static int __init f71882fg_device_add(int address,
+				      const struct f71882fg_sio_data *sio_data)
 {
 	struct resource res = {
 		.start	= address,
@@ -2668,19 +2661,21 @@ exit_device_put:
 
 static int __init f71882fg_init(void)
 {
-	int err = -ENODEV;
-	unsigned short address;
+	int err;
+	int address;
 	struct f71882fg_sio_data sio_data;
 
 	memset(&sio_data, 0, sizeof(sio_data));
 
-	if (f71882fg_find(0x2e, &address, &sio_data) &&
-	    f71882fg_find(0x4e, &address, &sio_data))
-		goto exit;
+	address = f71882fg_find(0x2e, &sio_data);
+	if (address < 0)
+		address = f71882fg_find(0x4e, &sio_data);
+	if (address < 0)
+		return address;
 
 	err = platform_driver_register(&f71882fg_driver);
 	if (err)
-		goto exit;
+		return err;
 
 	err = f71882fg_device_add(address, &sio_data);
 	if (err)
@@ -2690,7 +2685,6 @@ static int __init f71882fg_init(void)
 
 exit_driver:
 	platform_driver_unregister(&f71882fg_driver);
-exit:
 	return err;
 }
 
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
index ece4159..f7dba22 100644
--- a/drivers/hwmon/f75375s.c
+++ b/drivers/hwmon/f75375s.c
@@ -838,7 +838,8 @@ static int f75375_probe(struct i2c_client *client,
 	if (!i2c_check_functionality(client->adapter,
 				I2C_FUNC_SMBUS_BYTE_DATA))
 		return -EIO;
-	data = kzalloc(sizeof(struct f75375_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct f75375_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -848,7 +849,7 @@ static int f75375_probe(struct i2c_client *client,
 
 	err = sysfs_create_group(&client->dev.kobj, &f75375_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	if (data->kind != f75373) {
 		err = sysfs_chmod_file(&client->dev.kobj,
@@ -875,8 +876,6 @@ static int f75375_probe(struct i2c_client *client,
 
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &f75375_group);
-exit_free:
-	kfree(data);
 	return err;
 }
 
@@ -885,7 +884,6 @@ static int f75375_remove(struct i2c_client *client)
 	struct f75375_data *data = i2c_get_clientdata(client);
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &f75375_group);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c
index 2764b78..9e93ae4 100644
--- a/drivers/hwmon/fam15h_power.c
+++ b/drivers/hwmon/fam15h_power.c
@@ -188,7 +188,7 @@ static int __devinit fam15h_power_probe(struct pci_dev *pdev,
 					const struct pci_device_id *id)
 {
 	struct fam15h_power_data *data;
-	struct device *dev;
+	struct device *dev = &pdev->dev;
 	int err;
 
 	/*
@@ -198,23 +198,19 @@ static int __devinit fam15h_power_probe(struct pci_dev *pdev,
 	 */
 	tweak_runavg_range(pdev);
 
-	if (!fam15h_power_is_internal_node0(pdev)) {
-		err = -ENODEV;
-		goto exit;
-	}
+	if (!fam15h_power_is_internal_node0(pdev))
+		return -ENODEV;
+
+	data = devm_kzalloc(dev, sizeof(struct fam15h_power_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
-	data = kzalloc(sizeof(struct fam15h_power_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
 	fam15h_power_init_data(pdev, data);
-	dev = &pdev->dev;
 
 	dev_set_drvdata(dev, data);
 	err = sysfs_create_group(&dev->kobj, &fam15h_power_attr_group);
 	if (err)
-		goto exit_free_data;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -226,9 +222,6 @@ static int __devinit fam15h_power_probe(struct pci_dev *pdev,
 
 exit_remove_group:
 	sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group);
-exit_free_data:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -241,8 +234,6 @@ static void __devexit fam15h_power_remove(struct pci_dev *pdev)
 	data = dev_get_drvdata(dev);
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group);
-	dev_set_drvdata(dev, NULL);
-	kfree(data);
 }
 
 static DEFINE_PCI_DEVICE_TABLE(fam15h_power_id_table) = {
diff --git a/drivers/hwmon/g760a.c b/drivers/hwmon/g760a.c
index ebcd269..8b2106f 100644
--- a/drivers/hwmon/g760a.c
+++ b/drivers/hwmon/g760a.c
@@ -207,7 +207,8 @@ static int g760a_probe(struct i2c_client *client,
 				     I2C_FUNC_SMBUS_BYTE_DATA))
 		return -EIO;
 
-	data = kzalloc(sizeof(struct g760a_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct g760a_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -223,7 +224,7 @@ static int g760a_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &g760a_group);
 	if (err)
-		goto error_sysfs_create_group;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -235,9 +236,6 @@ static int g760a_probe(struct i2c_client *client,
 
 error_hwmon_device_register:
 	sysfs_remove_group(&client->dev.kobj, &g760a_group);
-error_sysfs_create_group:
-	kfree(data);
-
 	return err;
 }
 
@@ -246,8 +244,6 @@ static int g760a_remove(struct i2c_client *client)
 	struct g760a_data *data = i2c_get_clientdata(client);
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &g760a_group);
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c
index 5253d23..84bf215 100644
--- a/drivers/hwmon/jz4740-hwmon.c
+++ b/drivers/hwmon/jz4740-hwmon.c
@@ -106,42 +106,36 @@ static int __devinit jz4740_hwmon_probe(struct platform_device *pdev)
 	int ret;
 	struct jz4740_hwmon *hwmon;
 
-	hwmon = kmalloc(sizeof(*hwmon), GFP_KERNEL);
-	if (!hwmon) {
-		dev_err(&pdev->dev, "Failed to allocate driver structure\n");
+	hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
+	if (!hwmon)
 		return -ENOMEM;
-	}
 
 	hwmon->cell = mfd_get_cell(pdev);
 
 	hwmon->irq = platform_get_irq(pdev, 0);
 	if (hwmon->irq < 0) {
-		ret = hwmon->irq;
 		dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
-		goto err_free;
+		return hwmon->irq;
 	}
 
 	hwmon->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!hwmon->mem) {
-		ret = -ENOENT;
 		dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
-		goto err_free;
+		return -ENOENT;
 	}
 
-	hwmon->mem = request_mem_region(hwmon->mem->start,
+	hwmon->mem = devm_request_mem_region(&pdev->dev, hwmon->mem->start,
 			resource_size(hwmon->mem), pdev->name);
 	if (!hwmon->mem) {
-		ret = -EBUSY;
 		dev_err(&pdev->dev, "Failed to request mmio memory region\n");
-		goto err_free;
+		return -EBUSY;
 	}
 
-	hwmon->base = ioremap_nocache(hwmon->mem->start,
-			resource_size(hwmon->mem));
+	hwmon->base = devm_ioremap_nocache(&pdev->dev, hwmon->mem->start,
+					   resource_size(hwmon->mem));
 	if (!hwmon->base) {
-		ret = -EBUSY;
 		dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
-		goto err_release_mem_region;
+		return -EBUSY;
 	}
 
 	init_completion(&hwmon->read_completion);
@@ -149,17 +143,18 @@ static int __devinit jz4740_hwmon_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, hwmon);
 
-	ret = request_irq(hwmon->irq, jz4740_hwmon_irq, 0, pdev->name, hwmon);
+	ret = devm_request_irq(&pdev->dev, hwmon->irq, jz4740_hwmon_irq, 0,
+			       pdev->name, hwmon);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
-		goto err_iounmap;
+		return ret;
 	}
 	disable_irq(hwmon->irq);
 
 	ret = sysfs_create_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to create sysfs group: %d\n", ret);
-		goto err_free_irq;
+		return ret;
 	}
 
 	hwmon->hwmon = hwmon_device_register(&pdev->dev);
@@ -172,16 +167,6 @@ static int __devinit jz4740_hwmon_probe(struct platform_device *pdev)
 
 err_remove_file:
 	sysfs_remove_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
-err_free_irq:
-	free_irq(hwmon->irq, hwmon);
-err_iounmap:
-	platform_set_drvdata(pdev, NULL);
-	iounmap(hwmon->base);
-err_release_mem_region:
-	release_mem_region(hwmon->mem->start, resource_size(hwmon->mem));
-err_free:
-	kfree(hwmon);
-
 	return ret;
 }
 
@@ -192,14 +177,6 @@ static int __devexit jz4740_hwmon_remove(struct platform_device *pdev)
 	hwmon_device_unregister(hwmon->hwmon);
 	sysfs_remove_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
 
-	free_irq(hwmon->irq, hwmon);
-
-	iounmap(hwmon->base);
-	release_mem_region(hwmon->mem->start, resource_size(hwmon->mem));
-
-	platform_set_drvdata(pdev, NULL);
-	kfree(hwmon);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c
index 472f795..dd7f0ca 100644
--- a/drivers/hwmon/lm70.c
+++ b/drivers/hwmon/lm70.c
@@ -149,7 +149,7 @@ static int __devinit lm70_probe(struct spi_device *spi)
 
 	/* NOTE:  we assume 8-bit words, and convert to 16 bits manually */
 
-	p_lm70 = kzalloc(sizeof *p_lm70, GFP_KERNEL);
+	p_lm70 = devm_kzalloc(&spi->dev, sizeof(*p_lm70), GFP_KERNEL);
 	if (!p_lm70)
 		return -ENOMEM;
 
@@ -181,7 +181,6 @@ out_dev_create_file_failed:
 	device_remove_file(&spi->dev, &dev_attr_temp1_input);
 out_dev_create_temp_file_failed:
 	spi_set_drvdata(spi, NULL);
-	kfree(p_lm70);
 	return status;
 }
 
@@ -193,7 +192,6 @@ static int __devexit lm70_remove(struct spi_device *spi)
 	device_remove_file(&spi->dev, &dev_attr_temp1_input);
 	device_remove_file(&spi->dev, &dev_attr_name);
 	spi_set_drvdata(spi, NULL);
-	kfree(p_lm70);
 
 	return 0;
 }
diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c
index bd8cdb7..4b68fb2 100644
--- a/drivers/hwmon/lm95241.c
+++ b/drivers/hwmon/lm95241.c
@@ -391,11 +391,10 @@ static int lm95241_probe(struct i2c_client *new_client,
 	struct lm95241_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct lm95241_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&new_client->dev, sizeof(struct lm95241_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(new_client, data);
 	mutex_init(&data->update_lock);
@@ -406,7 +405,7 @@ static int lm95241_probe(struct i2c_client *new_client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&new_client->dev.kobj, &lm95241_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&new_client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -418,9 +417,6 @@ static int lm95241_probe(struct i2c_client *new_client,
 
 exit_remove_files:
 	sysfs_remove_group(&new_client->dev.kobj, &lm95241_group);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -431,7 +427,6 @@ static int lm95241_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &lm95241_group);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c
index 9a46c10..2915fd9 100644
--- a/drivers/hwmon/lm95245.c
+++ b/drivers/hwmon/lm95245.c
@@ -462,11 +462,10 @@ static int lm95245_probe(struct i2c_client *new_client,
 	struct lm95245_data *data;
 	int err;
 
-	data = kzalloc(sizeof(struct lm95245_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&new_client->dev, sizeof(struct lm95245_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(new_client, data);
 	mutex_init(&data->update_lock);
@@ -477,7 +476,7 @@ static int lm95245_probe(struct i2c_client *new_client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&new_client->dev.kobj, &lm95245_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&new_client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -489,9 +488,6 @@ static int lm95245_probe(struct i2c_client *new_client,
 
 exit_remove_files:
 	sysfs_remove_group(&new_client->dev.kobj, &lm95245_group);
-exit_free:
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -502,7 +498,6 @@ static int lm95245_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &lm95245_group);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/ltc4151.c b/drivers/hwmon/ltc4151.c
index 4d005b2..8496baa 100644
--- a/drivers/hwmon/ltc4151.c
+++ b/drivers/hwmon/ltc4151.c
@@ -181,11 +181,9 @@ static int ltc4151_probe(struct i2c_client *client,
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 		return -ENODEV;
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		ret = -ENOMEM;
-		goto out_kzalloc;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -193,7 +191,7 @@ static int ltc4151_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	ret = sysfs_create_group(&client->dev.kobj, &ltc4151_group);
 	if (ret)
-		goto out_sysfs_create_group;
+		return ret;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -205,9 +203,6 @@ static int ltc4151_probe(struct i2c_client *client,
 
 out_hwmon_device_register:
 	sysfs_remove_group(&client->dev.kobj, &ltc4151_group);
-out_sysfs_create_group:
-	kfree(data);
-out_kzalloc:
 	return ret;
 }
 
@@ -218,8 +213,6 @@ static int ltc4151_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &ltc4151_group);
 
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c
index 429c5b2..98b3d04f 100644
--- a/drivers/hwmon/ltc4215.c
+++ b/drivers/hwmon/ltc4215.c
@@ -253,11 +253,9 @@ static int ltc4215_probe(struct i2c_client *client,
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 		return -ENODEV;
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		ret = -ENOMEM;
-		goto out_kzalloc;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -268,7 +266,7 @@ static int ltc4215_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	ret = sysfs_create_group(&client->dev.kobj, &ltc4215_group);
 	if (ret)
-		goto out_sysfs_create_group;
+		return ret;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -280,9 +278,6 @@ static int ltc4215_probe(struct i2c_client *client,
 
 out_hwmon_device_register:
 	sysfs_remove_group(&client->dev.kobj, &ltc4215_group);
-out_sysfs_create_group:
-	kfree(data);
-out_kzalloc:
 	return ret;
 }
 
@@ -293,8 +288,6 @@ static int ltc4215_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &ltc4215_group);
 
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c
index b99b45b..5207591 100644
--- a/drivers/hwmon/ltc4245.c
+++ b/drivers/hwmon/ltc4245.c
@@ -519,11 +519,9 @@ static int ltc4245_probe(struct i2c_client *client,
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 		return -ENODEV;
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		ret = -ENOMEM;
-		goto out_kzalloc;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -536,7 +534,7 @@ static int ltc4245_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	ret = ltc4245_sysfs_create_groups(client);
 	if (ret)
-		goto out_sysfs_create_groups;
+		return ret;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -548,9 +546,6 @@ static int ltc4245_probe(struct i2c_client *client,
 
 out_hwmon_device_register:
 	ltc4245_sysfs_remove_groups(client);
-out_sysfs_create_groups:
-	kfree(data);
-out_kzalloc:
 	return ret;
 }
 
@@ -560,7 +555,6 @@ static int ltc4245_remove(struct i2c_client *client)
 
 	hwmon_device_unregister(data->hwmon_dev);
 	ltc4245_sysfs_remove_groups(client);
-	kfree(data);
 
 	return 0;
 }
diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c
index 335b183..666d9f6 100644
--- a/drivers/hwmon/max1668.c
+++ b/drivers/hwmon/max1668.c
@@ -411,7 +411,8 @@ static int max1668_probe(struct i2c_client *client,
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 		return -ENODEV;
 
-	data = kzalloc(sizeof(struct max1668_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct max1668_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -422,7 +423,7 @@ static int max1668_probe(struct i2c_client *client,
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&client->dev.kobj, &max1668_group_common);
 	if (err)
-		goto error_free;
+		return err;
 
 	if (data->type == max1668 || data->type == max1989) {
 		err = sysfs_create_group(&client->dev.kobj,
@@ -444,8 +445,6 @@ error_sysrem1:
 		sysfs_remove_group(&client->dev.kobj, &max1668_group_unique);
 error_sysrem0:
 	sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
-error_free:
-	kfree(data);
 	return err;
 }
 
@@ -459,7 +458,6 @@ static int max1668_remove(struct i2c_client *client)
 
 	sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c
index d0afc0c..5162bb9 100644
--- a/drivers/hwmon/mcp3021.c
+++ b/drivers/hwmon/mcp3021.c
@@ -103,7 +103,8 @@ static int mcp3021_probe(struct i2c_client *client,
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 		return -ENODEV;
 
-	data = kzalloc(sizeof(struct mcp3021_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev, sizeof(struct mcp3021_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -111,17 +112,14 @@ static int mcp3021_probe(struct i2c_client *client,
 
 	if (client->dev.platform_data) {
 		data->vdd = *(u32 *)client->dev.platform_data;
-		if (data->vdd > MCP3021_VDD_MAX ||
-				data->vdd < MCP3021_VDD_MIN) {
-			err = -EINVAL;
-			goto exit_free;
-		}
+		if (data->vdd > MCP3021_VDD_MAX || data->vdd < MCP3021_VDD_MIN)
+			return -EINVAL;
 	} else
 		data->vdd = MCP3021_VDD_REF;
 
 	err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr);
 	if (err)
-		goto exit_free;
+		return err;
 
 	data->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -133,8 +131,6 @@ static int mcp3021_probe(struct i2c_client *client,
 
 exit_remove:
 	sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
-exit_free:
-	kfree(data);
 	return err;
 }
 
@@ -144,7 +140,6 @@ static int mcp3021_remove(struct i2c_client *client)
 
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
-	kfree(data);
 
 	return 0;
 }
diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c
index 8342275..49f6230 100644
--- a/drivers/hwmon/sch5627.c
+++ b/drivers/hwmon/sch5627.c
@@ -461,8 +461,6 @@ static int sch5627_remove(struct platform_device *pdev)
 		hwmon_device_unregister(data->hwmon_dev);
 
 	sysfs_remove_group(&pdev->dev.kobj, &sch5627_group);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
 
 	return 0;
 }
@@ -472,7 +470,8 @@ static int __devinit sch5627_probe(struct platform_device *pdev)
 	struct sch5627_data *data;
 	int err, build_code, build_id, hwmon_rev, val;
 
-	data = kzalloc(sizeof(struct sch5627_data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(struct sch5627_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
diff --git a/drivers/hwmon/sch5636.c b/drivers/hwmon/sch5636.c
index 96a7e68..5171180 100644
--- a/drivers/hwmon/sch5636.c
+++ b/drivers/hwmon/sch5636.c
@@ -402,9 +402,6 @@ static int sch5636_remove(struct platform_device *pdev)
 		device_remove_file(&pdev->dev,
 				   &sch5636_fan_attr[i].dev_attr);
 
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-
 	return 0;
 }
 
@@ -414,7 +411,8 @@ static int __devinit sch5636_probe(struct platform_device *pdev)
 	int i, err, val, revision[2];
 	char id[4];
 
-	data = kzalloc(sizeof(struct sch5636_data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(struct sch5636_data),
+			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c
index 4380f5d..d00b30a 100644
--- a/drivers/hwmon/sch56xx-common.c
+++ b/drivers/hwmon/sch56xx-common.c
@@ -503,10 +503,10 @@ EXPORT_SYMBOL(sch56xx_watchdog_unregister);
  * platform dev find, add and remove functions
  */
 
-static int __init sch56xx_find(int sioaddr, unsigned short *address,
-			       const char **name)
+static int __init sch56xx_find(int sioaddr, const char **name)
 {
 	u8 devid;
+	unsigned short address;
 	int err;
 
 	err = superio_enter(sioaddr);
@@ -540,20 +540,21 @@ static int __init sch56xx_find(int sioaddr, unsigned short *address,
 	 * Warning the order of the low / high byte is the other way around
 	 * as on most other superio devices!!
 	 */
-	*address = superio_inb(sioaddr, SIO_REG_ADDR) |
+	address = superio_inb(sioaddr, SIO_REG_ADDR) |
 		   superio_inb(sioaddr, SIO_REG_ADDR + 1) << 8;
-	if (*address == 0) {
+	if (address == 0) {
 		pr_warn("Base address not set\n");
 		err = -ENODEV;
 		goto exit;
 	}
+	err = address;
 
 exit:
 	superio_exit(sioaddr);
 	return err;
 }
 
-static int __init sch56xx_device_add(unsigned short address, const char *name)
+static int __init sch56xx_device_add(int address, const char *name)
 {
 	struct resource res = {
 		.start	= address,
@@ -593,15 +594,14 @@ exit_device_put:
 
 static int __init sch56xx_init(void)
 {
-	int err;
-	unsigned short address;
-	const char *name;
-
-	err = sch56xx_find(0x4e, &address, &name);
-	if (err)
-		err = sch56xx_find(0x2e, &address, &name);
-	if (err)
-		return err;
+	int address;
+	const char *name = NULL;
+
+	address = sch56xx_find(0x4e, &name);
+	if (address < 0)
+		address = sch56xx_find(0x2e, &name);
+	if (address < 0)
+		return address;
 
 	return sch56xx_device_add(address, name);
 }
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
index 8b011d0..e461464 100644
--- a/drivers/hwmon/sht15.c
+++ b/drivers/hwmon/sht15.c
@@ -884,14 +884,12 @@ static int sht15_invalidate_voltage(struct notifier_block *nb,
 static int __devinit sht15_probe(struct platform_device *pdev)
 {
 	int ret;
-	struct sht15_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
+	struct sht15_data *data;
 	u8 status = 0;
 
-	if (!data) {
-		ret = -ENOMEM;
-		dev_err(&pdev->dev, "kzalloc failed\n");
-		goto error_ret;
-	}
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	INIT_WORK(&data->read_work, sht15_bh_read_data);
 	INIT_WORK(&data->update_supply_work, sht15_update_voltage);
@@ -901,9 +899,8 @@ static int __devinit sht15_probe(struct platform_device *pdev)
 	init_waitqueue_head(&data->wait_queue);
 
 	if (pdev->dev.platform_data == NULL) {
-		ret = -EINVAL;
 		dev_err(&pdev->dev, "no platform data supplied\n");
-		goto err_free_data;
+		return -EINVAL;
 	}
 	data->pdata = pdev->dev.platform_data;
 	data->supply_uV = data->pdata->supply_mv * 1000;
@@ -918,7 +915,7 @@ static int __devinit sht15_probe(struct platform_device *pdev)
 	 * If a regulator is available,
 	 * query what the supply voltage actually is!
 	 */
-	data->reg = regulator_get(data->dev, "vcc");
+	data->reg = devm_regulator_get(data->dev, "vcc");
 	if (!IS_ERR(data->reg)) {
 		int voltage;
 
@@ -937,51 +934,51 @@ static int __devinit sht15_probe(struct platform_device *pdev)
 			dev_err(&pdev->dev,
 				"regulator notifier request failed\n");
 			regulator_disable(data->reg);
-			regulator_put(data->reg);
-			goto err_free_data;
+			return ret;
 		}
 	}
 
 	/* Try requesting the GPIOs */
-	ret = gpio_request(data->pdata->gpio_sck, "SHT15 sck");
+	ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_sck, "SHT15 sck");
 	if (ret) {
 		dev_err(&pdev->dev, "gpio request failed\n");
 		goto err_release_reg;
 	}
 	gpio_direction_output(data->pdata->gpio_sck, 0);
 
-	ret = gpio_request(data->pdata->gpio_data, "SHT15 data");
+	ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_data,
+				"SHT15 data");
 	if (ret) {
 		dev_err(&pdev->dev, "gpio request failed\n");
-		goto err_release_gpio_sck;
+		goto err_release_reg;
 	}
 
-	ret = request_irq(gpio_to_irq(data->pdata->gpio_data),
-			  sht15_interrupt_fired,
-			  IRQF_TRIGGER_FALLING,
-			  "sht15 data",
-			  data);
+	ret = devm_request_irq(&pdev->dev, gpio_to_irq(data->pdata->gpio_data),
+			       sht15_interrupt_fired,
+			       IRQF_TRIGGER_FALLING,
+			       "sht15 data",
+			       data);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to get irq for data line\n");
-		goto err_release_gpio_data;
+		goto err_release_reg;
 	}
 	disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
 	sht15_connection_reset(data);
 	ret = sht15_soft_reset(data);
 	if (ret)
-		goto err_release_irq;
+		goto err_release_reg;
 
 	/* write status with platform data options */
 	if (status) {
 		ret = sht15_send_status(data, status);
 		if (ret)
-			goto err_release_irq;
+			goto err_release_reg;
 	}
 
 	ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
 	if (ret) {
 		dev_err(&pdev->dev, "sysfs create failed\n");
-		goto err_release_irq;
+		goto err_release_reg;
 	}
 
 	data->hwmon_dev = hwmon_device_register(data->dev);
@@ -994,21 +991,11 @@ static int __devinit sht15_probe(struct platform_device *pdev)
 
 err_release_sysfs_group:
 	sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
-err_release_irq:
-	free_irq(gpio_to_irq(data->pdata->gpio_data), data);
-err_release_gpio_data:
-	gpio_free(data->pdata->gpio_data);
-err_release_gpio_sck:
-	gpio_free(data->pdata->gpio_sck);
 err_release_reg:
 	if (!IS_ERR(data->reg)) {
 		regulator_unregister_notifier(data->reg, &data->nb);
 		regulator_disable(data->reg);
-		regulator_put(data->reg);
 	}
-err_free_data:
-	kfree(data);
-error_ret:
 	return ret;
 }
 
@@ -1030,14 +1017,9 @@ static int __devexit sht15_remove(struct platform_device *pdev)
 	if (!IS_ERR(data->reg)) {
 		regulator_unregister_notifier(data->reg, &data->nb);
 		regulator_disable(data->reg);
-		regulator_put(data->reg);
 	}
 
-	free_irq(gpio_to_irq(data->pdata->gpio_data), data);
-	gpio_free(data->pdata->gpio_data);
-	gpio_free(data->pdata->gpio_sck);
 	mutex_unlock(&data->read_lock);
-	kfree(data);
 
 	return 0;
 }
diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c
index 6c2dede..c2565d0 100644
--- a/drivers/hwmon/sht21.c
+++ b/drivers/hwmon/sht21.c
@@ -199,11 +199,10 @@ static int __devinit sht21_probe(struct i2c_client *client,
 		return -ENODEV;
 	}
 
-	sht21 = kzalloc(sizeof(*sht21), GFP_KERNEL);
-	if (!sht21) {
-		dev_dbg(&client->dev, "kzalloc failed\n");
+	sht21 = devm_kzalloc(&client->dev, sizeof(*sht21), GFP_KERNEL);
+	if (!sht21)
 		return -ENOMEM;
-	}
+
 	i2c_set_clientdata(client, sht21);
 
 	mutex_init(&sht21->lock);
@@ -211,7 +210,7 @@ static int __devinit sht21_probe(struct i2c_client *client,
 	err = sysfs_create_group(&client->dev.kobj, &sht21_attr_group);
 	if (err) {
 		dev_dbg(&client->dev, "could not create sysfs files\n");
-		goto fail_free;
+		return err;
 	}
 	sht21->hwmon_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(sht21->hwmon_dev)) {
@@ -226,9 +225,6 @@ static int __devinit sht21_probe(struct i2c_client *client,
 
 fail_remove_sysfs:
 	sysfs_remove_group(&client->dev.kobj, &sht21_attr_group);
-fail_free:
-	kfree(sht21);
-
 	return err;
 }
 
@@ -242,7 +238,6 @@ static int __devexit sht21_remove(struct i2c_client *client)
 
 	hwmon_device_unregister(sht21->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &sht21_attr_group);
-	kfree(sht21);
 
 	return 0;
 }
diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c
index ee4ebc1..4cddee0 100644
--- a/drivers/hwmon/via-cputemp.c
+++ b/drivers/hwmon/via-cputemp.c
@@ -128,12 +128,10 @@ static int __devinit via_cputemp_probe(struct platform_device *pdev)
 	int err;
 	u32 eax, edx;
 
-	data = kzalloc(sizeof(struct via_cputemp_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		dev_err(&pdev->dev, "Out of memory\n");
-		goto exit;
-	}
+	data = devm_kzalloc(&pdev->dev, sizeof(struct via_cputemp_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	data->id = pdev->id;
 	data->name = "via_cputemp";
@@ -151,8 +149,7 @@ static int __devinit via_cputemp_probe(struct platform_device *pdev)
 		data->msr_temp = 0x1423;
 		break;
 	default:
-		err = -ENODEV;
-		goto exit_free;
+		return -ENODEV;
 	}
 
 	/* test if we can access the TEMPERATURE MSR */
@@ -160,14 +157,14 @@ static int __devinit via_cputemp_probe(struct platform_device *pdev)
 	if (err) {
 		dev_err(&pdev->dev,
 			"Unable to access TEMPERATURE MSR, giving up\n");
-		goto exit_free;
+		return err;
 	}
 
 	platform_set_drvdata(pdev, data);
 
 	err = sysfs_create_group(&pdev->dev.kobj, &via_cputemp_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	if (data->msr_vid)
 		data->vrm = vid_which_vrm();
@@ -192,10 +189,6 @@ exit_remove:
 	if (data->vrm)
 		device_remove_file(&pdev->dev, &dev_attr_cpu0_vid);
 	sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group);
-exit_free:
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -207,8 +200,6 @@ static int __devexit via_cputemp_remove(struct platform_device *pdev)
 	if (data->vrm)
 		device_remove_file(&pdev->dev, &dev_attr_cpu0_vid);
 	sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
 	return 0;
 }
 
@@ -328,6 +319,7 @@ static int __init via_cputemp_init(void)
 	if (err)
 		goto exit;
 
+	get_online_cpus();
 	for_each_online_cpu(i) {
 		struct cpuinfo_x86 *c = &cpu_data(i);
 
@@ -347,12 +339,14 @@ static int __init via_cputemp_init(void)
 
 #ifndef CONFIG_HOTPLUG_CPU
 	if (list_empty(&pdev_list)) {
+		put_online_cpus();
 		err = -ENODEV;
 		goto exit_driver_unreg;
 	}
 #endif
 
 	register_hotcpu_notifier(&via_cputemp_cpu_notifier);
+	put_online_cpus();
 	return 0;
 
 #ifndef CONFIG_HOTPLUG_CPU
@@ -367,6 +361,7 @@ static void __exit via_cputemp_exit(void)
 {
 	struct pdev_entry *p, *n;
 
+	get_online_cpus();
 	unregister_hotcpu_notifier(&via_cputemp_cpu_notifier);
 	mutex_lock(&pdev_list_mutex);
 	list_for_each_entry_safe(p, n, &pdev_list, list) {
@@ -375,6 +370,7 @@ static void __exit via_cputemp_exit(void)
 		kfree(p);
 	}
 	mutex_unlock(&pdev_list_mutex);
+	put_online_cpus();
 	platform_driver_unregister(&via_cputemp_driver);
 }
 
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index 386a845..84e3dc5 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -789,18 +789,16 @@ static int vt8231_probe(struct platform_device *pdev)
 
 	/* Reserve the ISA region */
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!request_region(res->start, VT8231_EXTENT,
-			    vt8231_driver.driver.name)) {
+	if (!devm_request_region(&pdev->dev, res->start, VT8231_EXTENT,
+				 vt8231_driver.driver.name)) {
 		dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
 			(unsigned long)res->start, (unsigned long)res->end);
 		return -ENODEV;
 	}
 
-	data = kzalloc(sizeof(struct vt8231_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit_release;
-	}
+	data = devm_kzalloc(&pdev->dev, sizeof(struct vt8231_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	platform_set_drvdata(pdev, data);
 	data->addr = res->start;
@@ -812,7 +810,7 @@ static int vt8231_probe(struct platform_device *pdev)
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&pdev->dev.kobj, &vt8231_group);
 	if (err)
-		goto exit_free;
+		return err;
 
 	/* Must update device information to find out the config field */
 	data->uch_config = vt8231_read_value(data, VT8231_REG_UCH_CONFIG);
@@ -850,13 +848,6 @@ exit_remove_files:
 		sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]);
 
 	sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
-
-exit_free:
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
-
-exit_release:
-	release_region(res->start, VT8231_EXTENT);
 	return err;
 }
 
@@ -875,9 +866,6 @@ static int __devexit vt8231_remove(struct platform_device *pdev)
 
 	sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
 
-	release_region(data->addr, VT8231_EXTENT);
-	platform_set_drvdata(pdev, NULL);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index ab48252..5b1a6a6 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -1206,7 +1206,7 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
 	int err = -ENODEV;
 	u16 val;
 
-	static const __initdata char *names[] = {
+	static __initconst char *const names[] = {
 		"W83627HF",
 		"W83627THF",
 		"W83697HF",
diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c
index 5850b77..c99c8a0 100644
--- a/drivers/hwmon/w83l786ng.c
+++ b/drivers/hwmon/w83l786ng.c
@@ -668,11 +668,10 @@ w83l786ng_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	int i, err = 0;
 	u8 reg_tmp;
 
-	data = kzalloc(sizeof(struct w83l786ng_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	data = devm_kzalloc(&client->dev, sizeof(struct w83l786ng_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
@@ -708,8 +707,6 @@ w83l786ng_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
 exit_remove:
 	sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
-	kfree(data);
-exit:
 	return err;
 }
 
@@ -721,8 +718,6 @@ w83l786ng_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
 
-	kfree(data);
-
 	return 0;
 }
 
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index b4aaa1b..86b7847 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -80,6 +80,7 @@ config I2C_I801
 	tristate "Intel 82801 (ICH/PCH)"
 	depends on PCI
 	select CHECK_SIGNATURE if X86 && DMI
+	select GPIOLIB if I2C_MUX
 	help
 	  If you say yes to this option, support will be included for the Intel
 	  801 family of mainboard I2C interfaces.  Specifically, the following
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 898dcf9..6f00785 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -79,6 +79,13 @@
 #include <linux/dmi.h>
 #include <linux/slab.h>
 #include <linux/wait.h>
+#include <linux/err.h>
+
+#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
+#include <linux/gpio.h>
+#include <linux/i2c-mux-gpio.h>
+#include <linux/platform_device.h>
+#endif
 
 /* I801 SMBus address offsets */
 #define SMBHSTSTS(p)	(0 + (p)->smba)
@@ -156,6 +163,15 @@
 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS	0x3b30
 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS	0x8c22
 
+struct i801_mux_config {
+	char *gpio_chip;
+	unsigned values[3];
+	int n_values;
+	unsigned classes[3];
+	unsigned gpios[2];		/* Relative to gpio_chip->base */
+	int n_gpios;
+};
+
 struct i801_priv {
 	struct i2c_adapter adapter;
 	unsigned long smba;
@@ -173,6 +189,12 @@ struct i801_priv {
 	int count;
 	int len;
 	u8 *data;
+
+#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
+	const struct i801_mux_config *mux_drvdata;
+	unsigned mux_priv[2];
+	struct platform_device *mux_pdev;
+#endif
 };
 
 static struct pci_driver i801_driver;
@@ -897,6 +919,193 @@ static void __init input_apanel_init(void) {}
 static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) {}
 #endif	/* CONFIG_X86 && CONFIG_DMI */
 
+#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
+static struct i801_mux_config i801_mux_config_asus_z8_d12 = {
+	.gpio_chip = "gpio_ich",
+	.values = { 0x02, 0x03 },
+	.n_values = 2,
+	.classes = { I2C_CLASS_SPD, I2C_CLASS_SPD },
+	.gpios = { 52, 53 },
+	.n_gpios = 2,
+};
+
+static struct i801_mux_config i801_mux_config_asus_z8_d18 = {
+	.gpio_chip = "gpio_ich",
+	.values = { 0x02, 0x03, 0x01 },
+	.n_values = 3,
+	.classes = { I2C_CLASS_SPD, I2C_CLASS_SPD, I2C_CLASS_SPD },
+	.gpios = { 52, 53 },
+	.n_gpios = 2,
+};
+
+static struct dmi_system_id __devinitdata mux_dmi_table[] = {
+	{
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "Z8NA-D6(C)"),
+		},
+		.driver_data = &i801_mux_config_asus_z8_d12,
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)E-D12(X)"),
+		},
+		.driver_data = &i801_mux_config_asus_z8_d12,
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "Z8NH-D12"),
+		},
+		.driver_data = &i801_mux_config_asus_z8_d12,
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "Z8PH-D12/IFB"),
+		},
+		.driver_data = &i801_mux_config_asus_z8_d12,
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "Z8NR-D12"),
+		},
+		.driver_data = &i801_mux_config_asus_z8_d12,
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)H-D12"),
+		},
+		.driver_data = &i801_mux_config_asus_z8_d12,
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "Z8PG-D18"),
+		},
+		.driver_data = &i801_mux_config_asus_z8_d18,
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "Z8PE-D18"),
+		},
+		.driver_data = &i801_mux_config_asus_z8_d18,
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "Z8PS-D12"),
+		},
+		.driver_data = &i801_mux_config_asus_z8_d12,
+	},
+	{ }
+};
+
+static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip,
+					      void *data)
+{
+	return !strcmp(chip->label, data);
+}
+
+/* Setup multiplexing if needed */
+static int __devinit i801_add_mux(struct i801_priv *priv)
+{
+	struct device *dev = &priv->adapter.dev;
+	const struct i801_mux_config *mux_config;
+	struct gpio_chip *gpio;
+	struct i2c_mux_gpio_platform_data gpio_data;
+	int i, err;
+
+	if (!priv->mux_drvdata)
+		return 0;
+	mux_config = priv->mux_drvdata;
+
+	/* Find GPIO chip */
+	gpio = gpiochip_find(mux_config->gpio_chip, match_gpio_chip_by_label);
+	if (gpio) {
+		dev_info(dev,
+			 "GPIO chip %s found, SMBus multiplexing enabled\n",
+			 mux_config->gpio_chip);
+	} else {
+		dev_err(dev,
+			"GPIO chip %s not found, SMBus multiplexing disabled\n",
+			mux_config->gpio_chip);
+		return -ENODEV;
+	}
+
+	/* Find absolute GPIO pin numbers */
+	if (ARRAY_SIZE(priv->mux_priv) < mux_config->n_gpios) {
+		dev_err(dev, "i801_priv.mux_priv too small (%zu, need %d)\n",
+			ARRAY_SIZE(priv->mux_priv), mux_config->n_gpios);
+		return -ENODEV;
+	}
+	for (i = 0; i < mux_config->n_gpios; i++)
+		priv->mux_priv[i] = gpio->base + mux_config->gpios[i];
+
+	/* Prepare the platform data */
+	memset(&gpio_data, 0, sizeof(struct i2c_mux_gpio_platform_data));
+	gpio_data.parent = priv->adapter.nr;
+	gpio_data.values = mux_config->values;
+	gpio_data.n_values = mux_config->n_values;
+	gpio_data.classes = mux_config->classes;
+	gpio_data.gpios = priv->mux_priv;
+	gpio_data.n_gpios = mux_config->n_gpios;
+	gpio_data.idle = I2C_MUX_GPIO_NO_IDLE;
+
+	/* Register the mux device */
+	priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio",
+				priv->mux_priv[0], &gpio_data,
+				sizeof(struct i2c_mux_gpio_platform_data));
+	if (IS_ERR(priv->mux_pdev)) {
+		err = PTR_ERR(priv->mux_pdev);
+		priv->mux_pdev = NULL;
+		dev_err(dev, "Failed to register i2c-mux-gpio device\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static void __devexit i801_del_mux(struct i801_priv *priv)
+{
+	if (priv->mux_pdev)
+		platform_device_unregister(priv->mux_pdev);
+}
+
+static unsigned int __devinit i801_get_adapter_class(struct i801_priv *priv)
+{
+	const struct dmi_system_id *id;
+	const struct i801_mux_config *mux_config;
+	unsigned int class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	int i;
+
+	id = dmi_first_match(mux_dmi_table);
+	if (id) {
+		/* Remove from branch classes from trunk */
+		mux_config = id->driver_data;
+		for (i = 0; i < mux_config->n_values; i++)
+			class &= ~mux_config->classes[i];
+
+		/* Remember for later */
+		priv->mux_drvdata = mux_config;
+	}
+
+	return class;
+}
+#else
+static inline int i801_add_mux(struct i801_priv *priv) { return 0; }
+static inline void i801_del_mux(struct i801_priv *priv) { }
+
+static inline unsigned int i801_get_adapter_class(struct i801_priv *priv)
+{
+	return I2C_CLASS_HWMON | I2C_CLASS_SPD;
+}
+#endif
+
 static int __devinit i801_probe(struct pci_dev *dev,
 				const struct pci_device_id *id)
 {
@@ -910,7 +1119,7 @@ static int __devinit i801_probe(struct pci_dev *dev,
 
 	i2c_set_adapdata(&priv->adapter, priv);
 	priv->adapter.owner = THIS_MODULE;
-	priv->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	priv->adapter.class = i801_get_adapter_class(priv);
 	priv->adapter.algo = &smbus_algorithm;
 
 	priv->pci_dev = dev;
@@ -1030,6 +1239,8 @@ static int __devinit i801_probe(struct pci_dev *dev,
 	}
 
 	i801_probe_optional_slaves(priv);
+	/* We ignore errors - multiplexing is optional */
+	i801_add_mux(priv);
 
 	pci_set_drvdata(dev, priv);
 
@@ -1049,6 +1260,7 @@ static void __devexit i801_remove(struct pci_dev *dev)
 {
 	struct i801_priv *priv = pci_get_drvdata(dev);
 
+	i801_del_mux(priv);
 	i2c_del_adapter(&priv->adapter);
 	pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
 
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index 93f147a..2f99613 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -4,13 +4,13 @@
 /* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd
  *                    <Peter dot Milne at D hyphen TACQ dot com>
  *
- * With acknowledgements to i2c-algo-ibm_ocp.c by 
+ * With acknowledgements to i2c-algo-ibm_ocp.c by
  * Ian DaSilva, MontaVista Software, Inc. idasilva@mvista.com
  *
  * And i2c-algo-pcf.c, which was created by Simon G. Vogl and Hans Berglund:
  *
  * Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund
- *  
+ *
  * And which acknowledged Kyösti Mälkki <kmalkki@cc.hut.fi>,
  * Frodo Looijaard <frodol@dds.nl>, Martin Bailey<mbailey@littlefeet-inc.com>
  *
@@ -39,14 +39,15 @@
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
 #include <linux/io.h>
+#include <linux/gpio.h>
 
 #include "i2c-iop3xx.h"
 
 /* global unit counter */
 static int i2c_id;
 
-static inline unsigned char 
-iic_cook_addr(struct i2c_msg *msg) 
+static inline unsigned char
+iic_cook_addr(struct i2c_msg *msg)
 {
 	unsigned char addr;
 
@@ -55,38 +56,38 @@ iic_cook_addr(struct i2c_msg *msg)
 	if (msg->flags & I2C_M_RD)
 		addr |= 1;
 
-	return addr;   
+	return addr;
 }
 
-static void 
+static void
 iop3xx_i2c_reset(struct i2c_algo_iop3xx_data *iop3xx_adap)
 {
 	/* Follows devman 9.3 */
 	__raw_writel(IOP3XX_ICR_UNIT_RESET, iop3xx_adap->ioaddr + CR_OFFSET);
 	__raw_writel(IOP3XX_ISR_CLEARBITS, iop3xx_adap->ioaddr + SR_OFFSET);
 	__raw_writel(0, iop3xx_adap->ioaddr + CR_OFFSET);
-} 
+}
 
-static void 
+static void
 iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
 {
 	u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE;
 
-	/* 
+	/*
 	 * Every time unit enable is asserted, GPOD needs to be cleared
 	 * on IOP3XX to avoid data corruption on the bus.
 	 */
 #if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X)
 	if (iop3xx_adap->id == 0) {
-		gpio_line_set(IOP3XX_GPIO_LINE(7), GPIO_LOW);
-		gpio_line_set(IOP3XX_GPIO_LINE(6), GPIO_LOW);
+		gpio_set_value(7, 0);
+		gpio_set_value(6, 0);
 	} else {
-		gpio_line_set(IOP3XX_GPIO_LINE(5), GPIO_LOW);
-		gpio_line_set(IOP3XX_GPIO_LINE(4), GPIO_LOW);
+		gpio_set_value(5, 0);
+		gpio_set_value(4, 0);
 	}
 #endif
 	/* NB SR bits not same position as CR IE bits :-( */
-	iop3xx_adap->SR_enabled = 
+	iop3xx_adap->SR_enabled =
 		IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD |
 		IOP3XX_ISR_RXFULL | IOP3XX_ISR_TXEMPTY;
 
@@ -96,23 +97,23 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
 	__raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
 }
 
-static void 
+static void
 iop3xx_i2c_transaction_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap)
 {
 	unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
-	
-	cr &= ~(IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE | 
+
+	cr &= ~(IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE |
 		IOP3XX_ICR_MSTOP | IOP3XX_ICR_SCLEN);
 
 	__raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
 }
 
-/* 
- * NB: the handler has to clear the source of the interrupt! 
+/*
+ * NB: the handler has to clear the source of the interrupt!
  * Then it passes the SR flags of interest to BH via adap data
  */
-static irqreturn_t 
-iop3xx_i2c_irq_handler(int this_irq, void *dev_id) 
+static irqreturn_t
+iop3xx_i2c_irq_handler(int this_irq, void *dev_id)
 {
 	struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id;
 	u32 sr = __raw_readl(iop3xx_adap->ioaddr + SR_OFFSET);
@@ -126,7 +127,7 @@ iop3xx_i2c_irq_handler(int this_irq, void *dev_id)
 }
 
 /* check all error conditions, clear them , report most important */
-static int 
+static int
 iop3xx_i2c_error(u32 sr)
 {
 	int rc = 0;
@@ -135,12 +136,12 @@ iop3xx_i2c_error(u32 sr)
 		if ( !rc ) rc = -I2C_ERR_BERR;
 	}
 	if ((sr & IOP3XX_ISR_ALD)) {
-		if ( !rc ) rc = -I2C_ERR_ALD;		
+		if ( !rc ) rc = -I2C_ERR_ALD;
 	}
-	return rc;	
+	return rc;
 }
 
-static inline u32 
+static inline u32
 iop3xx_i2c_get_srstat(struct i2c_algo_iop3xx_data *iop3xx_adap)
 {
 	unsigned long flags;
@@ -161,8 +162,8 @@ iop3xx_i2c_get_srstat(struct i2c_algo_iop3xx_data *iop3xx_adap)
 typedef int (* compare_func)(unsigned test, unsigned mask);
 /* returns 1 on correct comparison */
 
-static int 
-iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap, 
+static int
+iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap,
 			  unsigned flags, unsigned* status,
 			  compare_func compare)
 {
@@ -192,47 +193,47 @@ iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap,
 }
 
 /*
- * Concrete compare_funcs 
+ * Concrete compare_funcs
  */
-static int 
+static int
 all_bits_clear(unsigned test, unsigned mask)
 {
 	return (test & mask) == 0;
 }
 
-static int 
+static int
 any_bits_set(unsigned test, unsigned mask)
 {
 	return (test & mask) != 0;
 }
 
-static int 
+static int
 iop3xx_i2c_wait_tx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
 {
-	return iop3xx_i2c_wait_event( 
-		iop3xx_adap, 
+	return iop3xx_i2c_wait_event(
+		iop3xx_adap,
 	        IOP3XX_ISR_TXEMPTY | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD,
 		status, any_bits_set);
 }
 
-static int 
+static int
 iop3xx_i2c_wait_rx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
 {
-	return iop3xx_i2c_wait_event( 
-		iop3xx_adap, 
+	return iop3xx_i2c_wait_event(
+		iop3xx_adap,
 		IOP3XX_ISR_RXFULL | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD,
 		status,	any_bits_set);
 }
 
-static int 
+static int
 iop3xx_i2c_wait_idle(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
 {
-	return iop3xx_i2c_wait_event( 
+	return iop3xx_i2c_wait_event(
 		iop3xx_adap, IOP3XX_ISR_UNITBUSY, status, all_bits_clear);
 }
 
-static int 
-iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap, 
+static int
+iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap,
 				struct i2c_msg* msg)
 {
 	unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
@@ -247,7 +248,7 @@ iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap,
 	}
 
 	__raw_writel(iic_cook_addr(msg), iop3xx_adap->ioaddr + DBR_OFFSET);
-	
+
 	cr &= ~(IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK);
 	cr |= IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE;
 
@@ -257,8 +258,8 @@ iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap,
 	return rc;
 }
 
-static int 
-iop3xx_i2c_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte, 
+static int
+iop3xx_i2c_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte,
 				int stop)
 {
 	unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
@@ -277,10 +278,10 @@ iop3xx_i2c_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte,
 	rc = iop3xx_i2c_wait_tx_done(iop3xx_adap, &status);
 
 	return rc;
-} 
+}
 
-static int 
-iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char* byte, 
+static int
+iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char* byte,
 				int stop)
 {
 	unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
@@ -304,19 +305,19 @@ iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char* byte,
 	return rc;
 }
 
-static int 
+static int
 iop3xx_i2c_writebytes(struct i2c_adapter *i2c_adap, const char *buf, int count)
 {
 	struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
 	int ii;
 	int rc = 0;
 
-	for (ii = 0; rc == 0 && ii != count; ++ii) 
+	for (ii = 0; rc == 0 && ii != count; ++ii)
 		rc = iop3xx_i2c_write_byte(iop3xx_adap, buf[ii], ii==count-1);
 	return rc;
 }
 
-static int 
+static int
 iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count)
 {
 	struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
@@ -325,7 +326,7 @@ iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count)
 
 	for (ii = 0; rc == 0 && ii != count; ++ii)
 		rc = iop3xx_i2c_read_byte(iop3xx_adap, &buf[ii], ii==count-1);
-	
+
 	return rc;
 }
 
@@ -336,8 +337,8 @@ iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count)
  * Each transfer (i.e. a read or a write) is separated by a repeated start
  * condition.
  */
-static int 
-iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg) 
+static int
+iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg)
 {
 	struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
 	int rc;
@@ -357,8 +358,8 @@ iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg)
 /*
  * master_xfer() - main read/write entry
  */
-static int 
-iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, 
+static int
+iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
 				int num)
 {
 	struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
@@ -375,14 +376,14 @@ iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
 	}
 
 	iop3xx_i2c_transaction_cleanup(iop3xx_adap);
-	
+
 	if(ret)
 		return ret;
 
-	return im;   
+	return im;
 }
 
-static u32 
+static u32
 iop3xx_i2c_func(struct i2c_adapter *adap)
 {
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
@@ -393,11 +394,11 @@ static const struct i2c_algorithm iop3xx_i2c_algo = {
 	.functionality	= iop3xx_i2c_func,
 };
 
-static int 
+static int
 iop3xx_i2c_remove(struct platform_device *pdev)
 {
 	struct i2c_adapter *padapter = platform_get_drvdata(pdev);
-	struct i2c_algo_iop3xx_data *adapter_data = 
+	struct i2c_algo_iop3xx_data *adapter_data =
 		(struct i2c_algo_iop3xx_data *)padapter->algo_data;
 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	unsigned long cr = __raw_readl(adapter_data->ioaddr + CR_OFFSET);
@@ -419,7 +420,7 @@ iop3xx_i2c_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static int 
+static int
 iop3xx_i2c_probe(struct platform_device *pdev)
 {
 	struct resource *res;
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index b76731e..57f7703 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -647,7 +647,7 @@ static int __devinit fsl_i2c_probe(struct platform_device *op)
 	}
 
 	if (match->data) {
-		struct mpc_i2c_data *data = match->data;
+		const struct mpc_i2c_data *data = match->data;
 		data->setup(op->dev.of_node, i2c, clock, data->prescaler);
 	} else {
 		/* Backwards compatibility */
@@ -730,24 +730,24 @@ static int mpc_i2c_resume(struct device *dev)
 SIMPLE_DEV_PM_OPS(mpc_i2c_pm_ops, mpc_i2c_suspend, mpc_i2c_resume);
 #endif
 
-static struct mpc_i2c_data mpc_i2c_data_512x __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_512x __devinitdata = {
 	.setup = mpc_i2c_setup_512x,
 };
 
-static struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = {
 	.setup = mpc_i2c_setup_52xx,
 };
 
-static struct mpc_i2c_data mpc_i2c_data_8313 __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_8313 __devinitdata = {
 	.setup = mpc_i2c_setup_8xxx,
 };
 
-static struct mpc_i2c_data mpc_i2c_data_8543 __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_8543 __devinitdata = {
 	.setup = mpc_i2c_setup_8xxx,
 	.prescaler = 2,
 };
 
-static struct mpc_i2c_data mpc_i2c_data_8544 __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_8544 __devinitdata = {
 	.setup = mpc_i2c_setup_8xxx,
 	.prescaler = 3,
 };
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 6849635..3d2a33a 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -944,7 +944,8 @@ omap_i2c_probe(struct platform_device *pdev)
 	struct omap_i2c_dev	*dev;
 	struct i2c_adapter	*adap;
 	struct resource		*mem, *irq, *ioarea;
-	struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data;
+	const struct omap_i2c_bus_platform_data *pdata =
+		pdev->dev.platform_data;
 	struct device_node	*node = pdev->dev.of_node;
 	const struct of_device_id *match;
 	irq_handler_t isr;
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 66eb53f..7149625 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -117,8 +117,8 @@ enum msg_end_type {
  * struct tegra_i2c_dev	- per device i2c context
  * @dev: device reference for power management
  * @adapter: core i2c layer adapter information
- * @clk: clock reference for i2c controller
- * @i2c_clk: clock reference for i2c bus
+ * @div_clk: clock reference for div clock of i2c controller.
+ * @fast_clk: clock reference for fast clock of i2c controller.
  * @base: ioremapped registers cookie
  * @cont_id: i2c controller id, used for for packet header
  * @irq: irq number of transfer complete interrupt
@@ -134,8 +134,8 @@ enum msg_end_type {
 struct tegra_i2c_dev {
 	struct device *dev;
 	struct i2c_adapter adapter;
-	struct clk *clk;
-	struct clk *i2c_clk;
+	struct clk *div_clk;
+	struct clk *fast_clk;
 	void __iomem *base;
 	int cont_id;
 	int irq;
@@ -356,11 +356,11 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
 	u32 val;
 	int err = 0;
 
-	clk_prepare_enable(i2c_dev->clk);
+	clk_prepare_enable(i2c_dev->div_clk);
 
-	tegra_periph_reset_assert(i2c_dev->clk);
+	tegra_periph_reset_assert(i2c_dev->div_clk);
 	udelay(2);
-	tegra_periph_reset_deassert(i2c_dev->clk);
+	tegra_periph_reset_deassert(i2c_dev->div_clk);
 
 	if (i2c_dev->is_dvc)
 		tegra_dvc_init(i2c_dev);
@@ -369,7 +369,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
 		(0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
 	i2c_writel(i2c_dev, val, I2C_CNFG);
 	i2c_writel(i2c_dev, 0, I2C_INT_MASK);
-	clk_set_rate(i2c_dev->clk, i2c_dev->bus_clk_rate * 8);
+	clk_set_rate(i2c_dev->div_clk, i2c_dev->bus_clk_rate * 8);
 
 	if (!i2c_dev->is_dvc) {
 		u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
@@ -387,7 +387,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
 	if (tegra_i2c_flush_fifos(i2c_dev))
 		err = -ETIMEDOUT;
 
-	clk_disable_unprepare(i2c_dev->clk);
+	clk_disable_unprepare(i2c_dev->div_clk);
 
 	if (i2c_dev->irq_disabled) {
 		i2c_dev->irq_disabled = 0;
@@ -563,7 +563,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
 	if (i2c_dev->is_suspended)
 		return -EBUSY;
 
-	clk_prepare_enable(i2c_dev->clk);
+	clk_prepare_enable(i2c_dev->div_clk);
 	for (i = 0; i < num; i++) {
 		enum msg_end_type end_type = MSG_END_STOP;
 		if (i < (num - 1)) {
@@ -576,7 +576,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
 		if (ret)
 			break;
 	}
-	clk_disable_unprepare(i2c_dev->clk);
+	clk_disable_unprepare(i2c_dev->div_clk);
 	return ret ?: i;
 }
 
@@ -596,8 +596,8 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
 	struct tegra_i2c_dev *i2c_dev;
 	struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data;
 	struct resource *res;
-	struct clk *clk;
-	struct clk *i2c_clk;
+	struct clk *div_clk;
+	struct clk *fast_clk;
 	const unsigned int *prop;
 	void __iomem *base;
 	int irq;
@@ -622,16 +622,16 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
 	}
 	irq = res->start;
 
-	clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(clk)) {
+	div_clk = devm_clk_get(&pdev->dev, "div-clk");
+	if (IS_ERR(div_clk)) {
 		dev_err(&pdev->dev, "missing controller clock");
-		return PTR_ERR(clk);
+		return PTR_ERR(div_clk);
 	}
 
-	i2c_clk = devm_clk_get(&pdev->dev, "i2c");
-	if (IS_ERR(i2c_clk)) {
+	fast_clk = devm_clk_get(&pdev->dev, "fast-clk");
+	if (IS_ERR(fast_clk)) {
 		dev_err(&pdev->dev, "missing bus clock");
-		return PTR_ERR(i2c_clk);
+		return PTR_ERR(fast_clk);
 	}
 
 	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
@@ -641,8 +641,8 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
 	}
 
 	i2c_dev->base = base;
-	i2c_dev->clk = clk;
-	i2c_dev->i2c_clk = i2c_clk;
+	i2c_dev->div_clk = div_clk;
+	i2c_dev->fast_clk = fast_clk;
 	i2c_dev->adapter.algo = &tegra_i2c_algo;
 	i2c_dev->irq = irq;
 	i2c_dev->cont_id = pdev->id;
@@ -681,7 +681,7 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	clk_prepare_enable(i2c_dev->i2c_clk);
+	clk_prepare_enable(i2c_dev->fast_clk);
 
 	i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
 	i2c_dev->adapter.owner = THIS_MODULE;
@@ -696,7 +696,7 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
 	ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to add I2C adapter\n");
-		clk_disable_unprepare(i2c_dev->i2c_clk);
+		clk_disable_unprepare(i2c_dev->fast_clk);
 		return ret;
 	}
 
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 2efa56c..96ef3d8 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -1971,12 +1971,22 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
 	unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
 	unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
 	int num = read_write == I2C_SMBUS_READ ? 2 : 1;
-	struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
-	                          { addr, flags | I2C_M_RD, 0, msgbuf1 }
-	                        };
 	int i;
 	u8 partial_pec = 0;
 	int status;
+	struct i2c_msg msg[2] = {
+		{
+			.addr = addr,
+			.flags = flags,
+			.len = 1,
+			.buf = msgbuf0,
+		}, {
+			.addr = addr,
+			.flags = flags | I2C_M_RD,
+			.len = 0,
+			.buf = msgbuf1,
+		},
+	};
 
 	msgbuf0[0] = command;
 	switch (size) {
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 1038c38..d94e0ce 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -88,9 +88,23 @@ static u32 i2c_mux_functionality(struct i2c_adapter *adap)
 	return parent->algo->functionality(parent);
 }
 
+/* Return all parent classes, merged */
+static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
+{
+	unsigned int class = 0;
+
+	do {
+		class |= parent->class;
+		parent = i2c_parent_is_i2c_adapter(parent);
+	} while (parent);
+
+	return class;
+}
+
 struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
 				struct device *mux_dev,
 				void *mux_priv, u32 force_nr, u32 chan_id,
+				unsigned int class,
 				int (*select) (struct i2c_adapter *,
 					       void *, u32),
 				int (*deselect) (struct i2c_adapter *,
@@ -127,6 +141,14 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
 	priv->adap.algo_data = priv;
 	priv->adap.dev.parent = &parent->dev;
 
+	/* Sanity check on class */
+	if (i2c_mux_parent_classes(parent) & class)
+		dev_err(&parent->dev,
+			"Segment %d behind mux can't share classes with ancestors\n",
+			chan_id);
+	else
+		priv->adap.class = class;
+
 	/*
 	 * Try to populate the mux adapter's of_node, expands to
 	 * nothing if !CONFIG_OF.
diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
index df3e0bf..92cdd23 100644
--- a/drivers/i2c/i2c-smbus.c
+++ b/drivers/i2c/i2c-smbus.c
@@ -142,7 +142,8 @@ static int smbalert_probe(struct i2c_client *ara,
 	struct i2c_adapter *adapter = ara->adapter;
 	int res;
 
-	alert = kzalloc(sizeof(struct i2c_smbus_alert), GFP_KERNEL);
+	alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert),
+			     GFP_KERNEL);
 	if (!alert)
 		return -ENOMEM;
 
@@ -154,10 +155,8 @@ static int smbalert_probe(struct i2c_client *ara,
 	if (setup->irq > 0) {
 		res = devm_request_irq(&ara->dev, setup->irq, smbalert_irq,
 				       0, "smbus_alert", alert);
-		if (res) {
-			kfree(alert);
+		if (res)
 			return res;
-		}
 	}
 
 	i2c_set_clientdata(ara, alert);
@@ -167,14 +166,12 @@ static int smbalert_probe(struct i2c_client *ara,
 	return 0;
 }
 
-/* IRQ resource is managed so it is freed automatically */
+/* IRQ and memory resources are managed so they are freed automatically */
 static int smbalert_remove(struct i2c_client *ara)
 {
 	struct i2c_smbus_alert *alert = i2c_get_clientdata(ara);
 
 	cancel_work_sync(&alert->alert);
-
-	kfree(alert);
 	return 0;
 }
 
diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c
index 68b1f8e..56889e0 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -104,8 +104,10 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev)
 
 	for (i = 0; i < pdata->n_values; i++) {
 		u32 nr = pdata->base_nr ? (pdata->base_nr + i) : 0;
+		unsigned int class = pdata->classes ? pdata->classes[i] : 0;
 
-		mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr, i,
+		mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr,
+						   i, class,
 						   i2c_mux_gpio_select, deselect);
 		if (!mux->adap[i]) {
 			ret = -ENODEV;
diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
index f8f72f3..f3b8f9a 100644
--- a/drivers/i2c/muxes/i2c-mux-pca9541.c
+++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
@@ -354,7 +354,7 @@ static int pca9541_probe(struct i2c_client *client,
 	if (pdata)
 		force = pdata->modes[0].adap_id;
 	data->mux_adap = i2c_add_mux_adapter(adap, &client->dev, client,
-					     force, 0,
+					     force, 0, 0,
 					     pca9541_select_chan,
 					     pca9541_release_chan);
 
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index f2dfe0d..8e43872 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -186,7 +186,7 @@ static int pca954x_probe(struct i2c_client *client,
 {
 	struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
 	struct pca954x_platform_data *pdata = client->dev.platform_data;
-	int num, force;
+	int num, force, class;
 	struct pca954x *data;
 	int ret = -ENODEV;
 
@@ -216,18 +216,20 @@ static int pca954x_probe(struct i2c_client *client,
 	/* Now create an adapter for each channel */
 	for (num = 0; num < chips[data->type].nchans; num++) {
 		force = 0;			  /* dynamic adap number */
+		class = 0;			  /* no class by default */
 		if (pdata) {
-			if (num < pdata->num_modes)
+			if (num < pdata->num_modes) {
 				/* force static number */
 				force = pdata->modes[num].adap_id;
-			else
+				class = pdata->modes[num].class;
+			} else
 				/* discard unconfigured channels */
 				break;
 		}
 
 		data->virt_adaps[num] =
 			i2c_add_mux_adapter(adap, &client->dev, client,
-				force, num, pca954x_select_chan,
+				force, num, class, pca954x_select_chan,
 				(pdata && pdata->modes[num].deselect_on_exit)
 					? pca954x_deselect_mux : NULL);
 
diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index 46a6697..5f097f3 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -221,7 +221,7 @@ static int __devinit i2c_mux_pinctrl_probe(struct platform_device *pdev)
 				(mux->pdata->base_bus_num + i) : 0;
 
 		mux->busses[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev,
-						     mux, bus, i,
+						     mux, bus, i, 0,
 						     i2c_mux_pinctrl_select,
 						     deselect);
 		if (!mux->busses[i]) {
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index f559088..e872617 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -606,8 +606,9 @@ static int __init intel_idle_init(void)
 	intel_idle_cpuidle_driver_init();
 	retval = cpuidle_register_driver(&intel_idle_driver);
 	if (retval) {
+		struct cpuidle_driver *drv = cpuidle_get_driver();
 		printk(KERN_DEBUG PREFIX "intel_idle yielding to %s",
-			cpuidle_get_driver()->name);
+			drv ? drv->name : "none");
 		return retval;
 	}
 
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index f61780a..98c96f9 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -545,13 +545,6 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
 		goto error_free_device;
 	}
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "No resource defined\n");
-		ret = -ENXIO;
-		goto error_ret;
-	}
-
 	platform_set_drvdata(pdev, idev);
 
 	idev->dev.parent = &pdev->dev;
@@ -566,18 +559,12 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
 		goto error_free_device;
 	}
 
-	if (!request_mem_region(res->start, resource_size(res),
-				"AT91 adc registers")) {
-		dev_err(&pdev->dev, "Resources are unavailable.\n");
-		ret = -EBUSY;
-		goto error_free_device;
-	}
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
-	st->reg_base = ioremap(res->start, resource_size(res));
+	st->reg_base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!st->reg_base) {
-		dev_err(&pdev->dev, "Failed to map registers.\n");
 		ret = -ENOMEM;
-		goto error_release_mem;
+		goto error_free_device;
 	}
 
 	/*
@@ -592,10 +579,10 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
 			  idev);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to allocate IRQ.\n");
-		goto error_unmap_reg;
+		goto error_free_device;
 	}
 
-	st->clk = clk_get(&pdev->dev, "adc_clk");
+	st->clk = devm_clk_get(&pdev->dev, "adc_clk");
 	if (IS_ERR(st->clk)) {
 		dev_err(&pdev->dev, "Failed to get the clock.\n");
 		ret = PTR_ERR(st->clk);
@@ -605,7 +592,7 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
 	ret = clk_prepare(st->clk);
 	if (ret) {
 		dev_err(&pdev->dev, "Could not prepare the clock.\n");
-		goto error_free_clk;
+		goto error_free_irq;
 	}
 
 	ret = clk_enable(st->clk);
@@ -614,7 +601,7 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
 		goto error_unprepare_clk;
 	}
 
-	st->adc_clk = clk_get(&pdev->dev, "adc_op_clk");
+	st->adc_clk = devm_clk_get(&pdev->dev, "adc_op_clk");
 	if (IS_ERR(st->adc_clk)) {
 		dev_err(&pdev->dev, "Failed to get the ADC clock.\n");
 		ret = PTR_ERR(st->clk);
@@ -624,7 +611,7 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
 	ret = clk_prepare(st->adc_clk);
 	if (ret) {
 		dev_err(&pdev->dev, "Could not prepare the ADC clock.\n");
-		goto error_free_adc_clk;
+		goto error_disable_clk;
 	}
 
 	ret = clk_enable(st->adc_clk);
@@ -697,20 +684,12 @@ error_disable_adc_clk:
 	clk_disable(st->adc_clk);
 error_unprepare_adc_clk:
 	clk_unprepare(st->adc_clk);
-error_free_adc_clk:
-	clk_put(st->adc_clk);
 error_disable_clk:
 	clk_disable(st->clk);
 error_unprepare_clk:
 	clk_unprepare(st->clk);
-error_free_clk:
-	clk_put(st->clk);
 error_free_irq:
 	free_irq(st->irq, idev);
-error_unmap_reg:
-	iounmap(st->reg_base);
-error_release_mem:
-	release_mem_region(res->start, resource_size(res));
 error_free_device:
 	iio_device_free(idev);
 error_ret:
@@ -720,20 +699,15 @@ error_ret:
 static int __devexit at91_adc_remove(struct platform_device *pdev)
 {
 	struct iio_dev *idev = platform_get_drvdata(pdev);
-	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	struct at91_adc_state *st = iio_priv(idev);
 
 	iio_device_unregister(idev);
 	at91_adc_trigger_remove(idev);
 	at91_adc_buffer_remove(idev);
 	clk_disable_unprepare(st->adc_clk);
-	clk_put(st->adc_clk);
 	clk_disable(st->clk);
 	clk_unprepare(st->clk);
-	clk_put(st->clk);
 	free_irq(st->irq, idev);
-	iounmap(st->reg_base);
-	release_mem_region(res->start, resource_size(res));
 	iio_device_free(idev);
 
 	return 0;
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c
index 59fbb3ae..e35bb8f 100644
--- a/drivers/iio/frequency/adf4350.c
+++ b/drivers/iio/frequency/adf4350.c
@@ -129,7 +129,7 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq)
 {
 	struct adf4350_platform_data *pdata = st->pdata;
 	u64 tmp;
-	u32 div_gcd, prescaler;
+	u32 div_gcd, prescaler, chspc;
 	u16 mdiv, r_cnt = 0;
 	u8 band_sel_div;
 
@@ -158,14 +158,20 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq)
 	if (pdata->ref_div_factor)
 		r_cnt = pdata->ref_div_factor - 1;
 
-	do  {
-		r_cnt = adf4350_tune_r_cnt(st, r_cnt);
+	chspc = st->chspc;
 
-		st->r1_mod = st->fpfd / st->chspc;
-		while (st->r1_mod > ADF4350_MAX_MODULUS) {
-			r_cnt = adf4350_tune_r_cnt(st, r_cnt);
-			st->r1_mod = st->fpfd / st->chspc;
-		}
+	do  {
+		do {
+			do {
+				r_cnt = adf4350_tune_r_cnt(st, r_cnt);
+				st->r1_mod = st->fpfd / chspc;
+				if (r_cnt > ADF4350_MAX_R_CNT) {
+					/* try higher spacing values */
+					chspc++;
+					r_cnt = 0;
+				}
+			} while ((st->r1_mod > ADF4350_MAX_MODULUS) && r_cnt);
+		} while (r_cnt == 0);
 
 		tmp = freq * (u64)st->r1_mod + (st->fpfd > 1);
 		do_div(tmp, st->fpfd); /* Div round closest (n + d/2)/d */
@@ -194,7 +200,7 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq)
 	st->regs[ADF4350_REG0] = ADF4350_REG0_INT(st->r0_int) |
 				 ADF4350_REG0_FRACT(st->r0_fract);
 
-	st->regs[ADF4350_REG1] = ADF4350_REG1_PHASE(0) |
+	st->regs[ADF4350_REG1] = ADF4350_REG1_PHASE(1) |
 				 ADF4350_REG1_MOD(st->r1_mod) |
 				 prescaler;
 
diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c
index 1cbb449..9a99f43 100644
--- a/drivers/iio/light/adjd_s311.c
+++ b/drivers/iio/light/adjd_s311.c
@@ -271,9 +271,10 @@ static int adjd_s311_update_scan_mode(struct iio_dev *indio_dev,
 	const unsigned long *scan_mask)
 {
 	struct adjd_s311_data *data = iio_priv(indio_dev);
-	data->buffer = krealloc(data->buffer, indio_dev->scan_bytes,
-				GFP_KERNEL);
-	if (!data->buffer)
+
+	kfree(data->buffer);
+	data->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
+	if (data->buffer == NULL)
 		return -ENOMEM;
 
 	return 0;
diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c
index c3e7bac..e45712a9 100644
--- a/drivers/iio/light/lm3533-als.c
+++ b/drivers/iio/light/lm3533-als.c
@@ -404,7 +404,7 @@ out:
 	return ret;
 }
 
-static int show_thresh_either_en(struct device *dev,
+static ssize_t show_thresh_either_en(struct device *dev,
 					struct device_attribute *attr,
 					char *buf)
 {
@@ -424,7 +424,7 @@ static int show_thresh_either_en(struct device *dev,
 	return scnprintf(buf, PAGE_SIZE, "%u\n", enable);
 }
 
-static int store_thresh_either_en(struct device *dev,
+static ssize_t store_thresh_either_en(struct device *dev,
 					struct device_attribute *attr,
 					const char *buf, size_t len)
 {
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 28058ae..eaec8d7 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -152,13 +152,11 @@ static void set_timeout(unsigned long time)
 {
 	unsigned long delay;
 
-	cancel_delayed_work(&work);
-
 	delay = time - jiffies;
 	if ((long)delay <= 0)
 		delay = 1;
 
-	queue_delayed_work(addr_wq, &work, delay);
+	mod_delayed_work(addr_wq, &work, delay);
 }
 
 static void queue_req(struct addr_req *req)
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 6bf8504..055ed59 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -267,6 +267,7 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id,
 	if (!uevent)
 		return event->event == RDMA_CM_EVENT_CONNECT_REQUEST;
 
+	mutex_lock(&ctx->file->mut);
 	uevent->cm_id = cm_id;
 	ucma_set_event_context(ctx, event, uevent);
 	uevent->resp.event = event->event;
@@ -277,7 +278,6 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id,
 		ucma_copy_conn_event(&uevent->resp.param.conn,
 				     &event->param.conn);
 
-	mutex_lock(&ctx->file->mut);
 	if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST) {
 		if (!ctx->backlog) {
 			ret = -ENOMEM;
diff --git a/drivers/infiniband/hw/amso1100/c2_rnic.c b/drivers/infiniband/hw/amso1100/c2_rnic.c
index 8c81992..e4a7315 100644
--- a/drivers/infiniband/hw/amso1100/c2_rnic.c
+++ b/drivers/infiniband/hw/amso1100/c2_rnic.c
@@ -439,7 +439,7 @@ static int c2_rnic_close(struct c2_dev *c2dev)
 
 /*
  * Called by c2_probe to initialize the RNIC. This principally
- * involves initalizing the various limits and resouce pools that
+ * involves initializing the various limits and resource pools that
  * comprise the RNIC instance.
  */
 int __devinit c2_rnic_init(struct c2_dev *c2dev)
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 77b6b18..aaf88ef9 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -1680,7 +1680,7 @@ static int close_con_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
  * T3A does 3 things when a TERM is received:
  * 1) send up a CPL_RDMA_TERMINATE message with the TERM packet
  * 2) generate an async event on the QP with the TERMINATE opcode
- * 3) post a TERMINATE opcde cqe into the associated CQ.
+ * 3) post a TERMINATE opcode cqe into the associated CQ.
  *
  * For (1), we save the message in the qp for later consumer consumption.
  * For (2), we move the QP into TERMINATE, post a QP event and disconnect.
diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c
index 45ee89b..1a1d5d9 100644
--- a/drivers/infiniband/hw/ehca/ehca_uverbs.c
+++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c
@@ -117,7 +117,7 @@ static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas,
 	physical = galpas->user.fw_handle;
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 	ehca_gen_dbg("vsize=%llx physical=%llx", vsize, physical);
-	/* VM_IO | VM_RESERVED are set by remap_pfn_range() */
+	/* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
 	ret = remap_4k_pfn(vma, vma->vm_start, physical >> EHCA_PAGESHIFT,
 			   vma->vm_page_prot);
 	if (unlikely(ret)) {
@@ -139,7 +139,7 @@ static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue,
 	u64 start, ofs;
 	struct page *page;
 
-	vma->vm_flags |= VM_RESERVED;
+	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
 	start = vma->vm_start;
 	for (ofs = 0; ofs < queue->queue_length; ofs += PAGE_SIZE) {
 		u64 virt_addr = (u64)ipz_qeit_calc(queue, ofs);
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index 736d9ed..3eb7e45 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -1225,7 +1225,7 @@ static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr,
 
 	vma->vm_pgoff = (unsigned long) addr >> PAGE_SHIFT;
 	vma->vm_ops = &ipath_file_vm_ops;
-	vma->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
+	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
 	ret = 1;
 
 bail:
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
index c27141f..9c2ae7e 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -125,6 +125,7 @@ static void update_sm_ah(struct mlx4_ib_dev *dev, u8 port_num, u16 lid, u8 sl)
 {
 	struct ib_ah *new_ah;
 	struct ib_ah_attr ah_attr;
+	unsigned long flags;
 
 	if (!dev->send_agent[port_num - 1][0])
 		return;
@@ -139,11 +140,11 @@ static void update_sm_ah(struct mlx4_ib_dev *dev, u8 port_num, u16 lid, u8 sl)
 	if (IS_ERR(new_ah))
 		return;
 
-	spin_lock(&dev->sm_lock);
+	spin_lock_irqsave(&dev->sm_lock, flags);
 	if (dev->sm_ah[port_num - 1])
 		ib_destroy_ah(dev->sm_ah[port_num - 1]);
 	dev->sm_ah[port_num - 1] = new_ah;
-	spin_unlock(&dev->sm_lock);
+	spin_unlock_irqrestore(&dev->sm_lock, flags);
 }
 
 /*
@@ -197,13 +198,15 @@ static void smp_snoop(struct ib_device *ibdev, u8 port_num, struct ib_mad *mad,
 static void node_desc_override(struct ib_device *dev,
 			       struct ib_mad *mad)
 {
+	unsigned long flags;
+
 	if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
 	     mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
 	    mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP &&
 	    mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) {
-		spin_lock(&to_mdev(dev)->sm_lock);
+		spin_lock_irqsave(&to_mdev(dev)->sm_lock, flags);
 		memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64);
-		spin_unlock(&to_mdev(dev)->sm_lock);
+		spin_unlock_irqrestore(&to_mdev(dev)->sm_lock, flags);
 	}
 }
 
@@ -213,6 +216,7 @@ static void forward_trap(struct mlx4_ib_dev *dev, u8 port_num, struct ib_mad *ma
 	struct ib_mad_send_buf *send_buf;
 	struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn];
 	int ret;
+	unsigned long flags;
 
 	if (agent) {
 		send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR,
@@ -225,13 +229,13 @@ static void forward_trap(struct mlx4_ib_dev *dev, u8 port_num, struct ib_mad *ma
 		 * wrong following the IB spec strictly, but we know
 		 * it's OK for our devices).
 		 */
-		spin_lock(&dev->sm_lock);
+		spin_lock_irqsave(&dev->sm_lock, flags);
 		memcpy(send_buf->mad, mad, sizeof *mad);
 		if ((send_buf->ah = dev->sm_ah[port_num - 1]))
 			ret = ib_post_send_mad(send_buf, NULL);
 		else
 			ret = -EINVAL;
-		spin_unlock(&dev->sm_lock);
+		spin_unlock_irqrestore(&dev->sm_lock, flags);
 
 		if (ret)
 			ib_free_send_mad(send_buf);
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index fe2088c..cc05579 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -423,6 +423,7 @@ static int mlx4_ib_modify_device(struct ib_device *ibdev, int mask,
 				 struct ib_device_modify *props)
 {
 	struct mlx4_cmd_mailbox *mailbox;
+	unsigned long flags;
 
 	if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
 		return -EOPNOTSUPP;
@@ -430,9 +431,9 @@ static int mlx4_ib_modify_device(struct ib_device *ibdev, int mask,
 	if (!(mask & IB_DEVICE_MODIFY_NODE_DESC))
 		return 0;
 
-	spin_lock(&to_mdev(ibdev)->sm_lock);
+	spin_lock_irqsave(&to_mdev(ibdev)->sm_lock, flags);
 	memcpy(ibdev->node_desc, props->node_desc, 64);
-	spin_unlock(&to_mdev(ibdev)->sm_lock);
+	spin_unlock_irqrestore(&to_mdev(ibdev)->sm_lock, flags);
 
 	/*
 	 * If possible, pass node desc to FW, so it can generate
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index a6d8ea0..f585edd 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -1407,6 +1407,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
 	struct mlx4_wqe_mlx_seg *mlx = wqe;
 	struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx;
 	struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah);
+	struct net_device *ndev;
 	union ib_gid sgid;
 	u16 pkey;
 	int send_size;
@@ -1483,7 +1484,10 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
 
 		memcpy(sqp->ud_header.eth.dmac_h, ah->av.eth.mac, 6);
 		/* FIXME: cache smac value? */
-		smac = to_mdev(sqp->qp.ibqp.device)->iboe.netdevs[sqp->qp.port - 1]->dev_addr;
+		ndev = to_mdev(sqp->qp.ibqp.device)->iboe.netdevs[sqp->qp.port - 1];
+		if (!ndev)
+			return -ENODEV;
+		smac = ndev->dev_addr;
 		memcpy(sqp->ud_header.eth.smac_h, smac, 6);
 		if (!memcmp(sqp->ud_header.eth.smac_h, sqp->ud_header.eth.dmac_h, 6))
 			mlx->flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK);
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index d42c9f4..9e0895b 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -2679,11 +2679,9 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
 			}
 		}
 		if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_SFP_D) {
-			if (nesdev->link_recheck)
-				cancel_delayed_work(&nesdev->work);
 			nesdev->link_recheck = 1;
-			schedule_delayed_work(&nesdev->work,
-					      NES_LINK_RECHECK_DELAY);
+			mod_delayed_work(system_wq, &nesdev->work,
+					 NES_LINK_RECHECK_DELAY);
 		}
 	}
 
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index f3a3ecf..e43f6e4 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -243,10 +243,9 @@ static int nes_netdev_open(struct net_device *netdev)
 
 	spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags);
 	if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_SFP_D) {
-		if (nesdev->link_recheck)
-			cancel_delayed_work(&nesdev->work);
 		nesdev->link_recheck = 1;
-		schedule_delayed_work(&nesdev->work, NES_LINK_RECHECK_DELAY);
+		mod_delayed_work(system_wq, &nesdev->work,
+				 NES_LINK_RECHECK_DELAY);
 	}
 	spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags);
 
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
index 5a04452..c4e0131 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
@@ -161,7 +161,7 @@ static void ocrdma_add_default_sgid(struct ocrdma_dev *dev)
 	ocrdma_get_guid(dev, &sgid->raw[8]);
 }
 
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+#if IS_ENABLED(CONFIG_VLAN_8021Q)
 static void ocrdma_add_vlan_sgids(struct ocrdma_dev *dev)
 {
 	struct net_device *netdev, *tmp;
@@ -202,14 +202,13 @@ static int ocrdma_build_sgid_tbl(struct ocrdma_dev *dev)
 	return 0;
 }
 
-#if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_VLAN_8021Q)
+#if IS_ENABLED(CONFIG_IPV6)
 
 static int ocrdma_inet6addr_event(struct notifier_block *notifier,
 				  unsigned long event, void *ptr)
 {
 	struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
-	struct net_device *event_netdev = ifa->idev->dev;
-	struct net_device *netdev = NULL;
+	struct net_device *netdev = ifa->idev->dev;
 	struct ib_event gid_event;
 	struct ocrdma_dev *dev;
 	bool found = false;
@@ -217,11 +216,12 @@ static int ocrdma_inet6addr_event(struct notifier_block *notifier,
 	bool is_vlan = false;
 	u16 vid = 0;
 
-	netdev = vlan_dev_real_dev(event_netdev);
-	if (netdev != event_netdev) {
-		is_vlan = true;
-		vid = vlan_dev_vlan_id(event_netdev);
+	is_vlan = netdev->priv_flags & IFF_802_1Q_VLAN;
+	if (is_vlan) {
+		vid = vlan_dev_vlan_id(netdev);
+		netdev = vlan_dev_real_dev(netdev);
 	}
+
 	rcu_read_lock();
 	list_for_each_entry_rcu(dev, &ocrdma_dev_list, entry) {
 		if (dev->nic_info.netdev == netdev) {
diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c
index faa44cb..959a5c4 100644
--- a/drivers/infiniband/hw/qib/qib_file_ops.c
+++ b/drivers/infiniband/hw/qib/qib_file_ops.c
@@ -971,7 +971,7 @@ static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr,
 
 	vma->vm_pgoff = (unsigned long) addr >> PAGE_SHIFT;
 	vma->vm_ops = &qib_file_vm_ops;
-	vma->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
+	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
 	ret = 1;
 
 bail:
diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c
index 0d7280a..3f6b21e 100644
--- a/drivers/infiniband/hw/qib/qib_iba7322.c
+++ b/drivers/infiniband/hw/qib/qib_iba7322.c
@@ -6346,8 +6346,10 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
 			dd->piobcnt4k * dd->align4k;
 		dd->piovl15base	= ioremap_nocache(vl15off,
 						  NUM_VL15_BUFS * dd->align4k);
-		if (!dd->piovl15base)
+		if (!dd->piovl15base) {
+			ret = -ENOMEM;
 			goto bail;
+		}
 	}
 	qib_7322_set_baseaddrs(dd); /* set chip access pointers now */
 
diff --git a/drivers/infiniband/hw/qib/qib_sd7220.c b/drivers/infiniband/hw/qib/qib_sd7220.c
index a322d51..50a8a0d 100644
--- a/drivers/infiniband/hw/qib/qib_sd7220.c
+++ b/drivers/infiniband/hw/qib/qib_sd7220.c
@@ -372,7 +372,7 @@ static void qib_sd_trimdone_monitor(struct qib_devdata *dd,
 		/* Read CTRL reg for each channel to check TRIMDONE */
 		if (baduns & (1 << chn)) {
 			qib_dev_err(dd,
-				"Reseting TRIMDONE on chn %d (%s)\n",
+				"Resetting TRIMDONE on chn %d (%s)\n",
 				chn, where);
 			ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES,
 				IB_CTRL2(chn), 0x10, 0x10);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 95ecf4e..24683fd 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -1271,12 +1271,15 @@ struct ipoib_cm_tx *ipoib_cm_create_tx(struct net_device *dev, struct ipoib_path
 void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(tx->dev);
+	unsigned long flags;
 	if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) {
+		spin_lock_irqsave(&priv->lock, flags);
 		list_move(&tx->list, &priv->cm.reap_list);
 		queue_work(ipoib_workqueue, &priv->cm.reap_task);
 		ipoib_dbg(priv, "Reap connection for gid %pI6\n",
 			  tx->neigh->daddr + 4);
 		tx->neigh = NULL;
+		spin_unlock_irqrestore(&priv->lock, flags);
 	}
 }
 
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 97920b7..3e2085a 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -1052,7 +1052,7 @@ void ipoib_neigh_free(struct ipoib_neigh *neigh)
 	for (n = rcu_dereference_protected(*np,
 					    lockdep_is_held(&ntbl->rwlock));
 	     n != NULL;
-	     n = rcu_dereference_protected(neigh->hnext,
+	     n = rcu_dereference_protected(*np,
 					lockdep_is_held(&ntbl->rwlock))) {
 		if (n == neigh) {
 			/* found */
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index bcbf22e..1b5b0c7 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -586,24 +586,62 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
 			scmnd->sc_data_direction);
 }
 
-static void srp_remove_req(struct srp_target_port *target,
-			   struct srp_request *req, s32 req_lim_delta)
+/**
+ * srp_claim_req - Take ownership of the scmnd associated with a request.
+ * @target: SRP target port.
+ * @req: SRP request.
+ * @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take
+ *         ownership of @req->scmnd if it equals @scmnd.
+ *
+ * Return value:
+ * Either NULL or a pointer to the SCSI command the caller became owner of.
+ */
+static struct scsi_cmnd *srp_claim_req(struct srp_target_port *target,
+				       struct srp_request *req,
+				       struct scsi_cmnd *scmnd)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&target->lock, flags);
+	if (!scmnd) {
+		scmnd = req->scmnd;
+		req->scmnd = NULL;
+	} else if (req->scmnd == scmnd) {
+		req->scmnd = NULL;
+	} else {
+		scmnd = NULL;
+	}
+	spin_unlock_irqrestore(&target->lock, flags);
+
+	return scmnd;
+}
+
+/**
+ * srp_free_req() - Unmap data and add request to the free request list.
+ */
+static void srp_free_req(struct srp_target_port *target,
+			 struct srp_request *req, struct scsi_cmnd *scmnd,
+			 s32 req_lim_delta)
 {
 	unsigned long flags;
 
-	srp_unmap_data(req->scmnd, target, req);
+	srp_unmap_data(scmnd, target, req);
+
 	spin_lock_irqsave(&target->lock, flags);
 	target->req_lim += req_lim_delta;
-	req->scmnd = NULL;
 	list_add_tail(&req->list, &target->free_reqs);
 	spin_unlock_irqrestore(&target->lock, flags);
 }
 
 static void srp_reset_req(struct srp_target_port *target, struct srp_request *req)
 {
-	req->scmnd->result = DID_RESET << 16;
-	req->scmnd->scsi_done(req->scmnd);
-	srp_remove_req(target, req, 0);
+	struct scsi_cmnd *scmnd = srp_claim_req(target, req, NULL);
+
+	if (scmnd) {
+		scmnd->result = DID_RESET << 16;
+		scmnd->scsi_done(scmnd);
+		srp_free_req(target, req, scmnd, 0);
+	}
 }
 
 static int srp_reconnect_target(struct srp_target_port *target)
@@ -1073,11 +1111,18 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
 		complete(&target->tsk_mgmt_done);
 	} else {
 		req = &target->req_ring[rsp->tag];
-		scmnd = req->scmnd;
-		if (!scmnd)
+		scmnd = srp_claim_req(target, req, NULL);
+		if (!scmnd) {
 			shost_printk(KERN_ERR, target->scsi_host,
 				     "Null scmnd for RSP w/tag %016llx\n",
 				     (unsigned long long) rsp->tag);
+
+			spin_lock_irqsave(&target->lock, flags);
+			target->req_lim += be32_to_cpu(rsp->req_lim_delta);
+			spin_unlock_irqrestore(&target->lock, flags);
+
+			return;
+		}
 		scmnd->result = rsp->status;
 
 		if (rsp->flags & SRP_RSP_FLAG_SNSVALID) {
@@ -1092,7 +1137,9 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
 		else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER))
 			scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt));
 
-		srp_remove_req(target, req, be32_to_cpu(rsp->req_lim_delta));
+		srp_free_req(target, req, scmnd,
+			     be32_to_cpu(rsp->req_lim_delta));
+
 		scmnd->host_scribble = NULL;
 		scmnd->scsi_done(scmnd);
 	}
@@ -1631,25 +1678,17 @@ static int srp_abort(struct scsi_cmnd *scmnd)
 {
 	struct srp_target_port *target = host_to_target(scmnd->device->host);
 	struct srp_request *req = (struct srp_request *) scmnd->host_scribble;
-	int ret = SUCCESS;
 
 	shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n");
 
-	if (!req || target->qp_in_error)
+	if (!req || target->qp_in_error || !srp_claim_req(target, req, scmnd))
 		return FAILED;
-	if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun,
-			      SRP_TSK_ABORT_TASK))
-		return FAILED;
-
-	if (req->scmnd) {
-		if (!target->tsk_mgmt_status) {
-			srp_remove_req(target, req, 0);
-			scmnd->result = DID_ABORT << 16;
-		} else
-			ret = FAILED;
-	}
+	srp_send_tsk_mgmt(target, req->index, scmnd->device->lun,
+			  SRP_TSK_ABORT_TASK);
+	srp_free_req(target, req, scmnd, 0);
+	scmnd->result = DID_ABORT << 16;
 
-	return ret;
+	return SUCCESS;
 }
 
 static int srp_reset_device(struct scsi_cmnd *scmnd)
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index 7a0ce8d..cf23c46 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -1469,7 +1469,7 @@ static void srpt_handle_send_comp(struct srpt_rdma_ch *ch,
  *
  * XXX: what is now target_execute_cmd used to be asynchronous, and unmapping
  * the data that has been transferred via IB RDMA had to be postponed until the
- * check_stop_free() callback.  None of this is nessecary anymore and needs to
+ * check_stop_free() callback.  None of this is necessary anymore and needs to
  * be cleaned up.
  */
 static void srpt_handle_rdma_comp(struct srpt_rdma_ch *ch,
@@ -3564,16 +3564,6 @@ static int srpt_get_tcm_cmd_state(struct se_cmd *se_cmd)
 	return srpt_get_cmd_state(ioctx);
 }
 
-static u16 srpt_set_fabric_sense_len(struct se_cmd *cmd, u32 sense_length)
-{
-	return 0;
-}
-
-static u16 srpt_get_fabric_sense_len(void)
-{
-	return 0;
-}
-
 /**
  * srpt_parse_i_port_id() - Parse an initiator port ID.
  * @name: ASCII representation of a 128-bit initiator port ID.
@@ -3953,8 +3943,6 @@ static struct target_core_fabric_ops srpt_template = {
 	.queue_data_in			= srpt_queue_response,
 	.queue_status			= srpt_queue_status,
 	.queue_tm_rsp			= srpt_queue_response,
-	.get_fabric_sense_len		= srpt_get_fabric_sense_len,
-	.set_fabric_sense_len		= srpt_set_fabric_sense_len,
 	/*
 	 * Setup function pointers for generic logic in
 	 * target_core_fabric_configfs.c
diff --git a/drivers/input/apm-power.c b/drivers/input/apm-power.c
index e90ee3d..650177a 100644
--- a/drivers/input/apm-power.c
+++ b/drivers/input/apm-power.c
@@ -33,7 +33,7 @@ static void system_power_event(unsigned int keycode)
 }
 
 static void apmpower_event(struct input_handle *handle, unsigned int type,
-		        unsigned int code, int value)
+			   unsigned int code, int value)
 {
 	/* only react on key down events */
 	if (value != 1)
diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c
index 480eb9d..f50f6dd 100644
--- a/drivers/input/ff-core.c
+++ b/drivers/input/ff-core.c
@@ -138,8 +138,8 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect,
 
 	if (effect->id == -1) {
 		for (id = 0; id < ff->max_effects; id++)
-		     if (!ff->effect_owners[id])
-			break;
+			if (!ff->effect_owners[id])
+				break;
 
 		if (id >= ff->max_effects) {
 			ret = -ENOSPC;
diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c
index b107922..74c0d8c 100644
--- a/drivers/input/ff-memless.c
+++ b/drivers/input/ff-memless.c
@@ -72,12 +72,14 @@ static const struct ff_envelope *get_envelope(const struct ff_effect *effect)
 	static const struct ff_envelope empty_envelope;
 
 	switch (effect->type) {
-		case FF_PERIODIC:
-			return &effect->u.periodic.envelope;
-		case FF_CONSTANT:
-			return &effect->u.constant.envelope;
-		default:
-			return &empty_envelope;
+	case FF_PERIODIC:
+		return &effect->u.periodic.envelope;
+
+	case FF_CONSTANT:
+		return &effect->u.constant.envelope;
+
+	default:
+		return &empty_envelope;
 	}
 }
 
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 26043cc..78f323e 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -711,7 +711,7 @@ static long joydev_ioctl(struct file *file,
 
 	case JS_SET_ALL:
 		retval = copy_from_user(&joydev->glue, argp,
-					sizeof(joydev->glue)) ? -EFAULT: 0;
+					sizeof(joydev->glue)) ? -EFAULT : 0;
 		break;
 
 	case JS_GET_ALL:
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index cbb1add..6ee68ec 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -43,11 +43,9 @@ struct gpio_button_data {
 };
 
 struct gpio_keys_drvdata {
+	const struct gpio_keys_platform_data *pdata;
 	struct input_dev *input;
 	struct mutex disable_lock;
-	unsigned int n_buttons;
-	int (*enable)(struct device *dev);
-	void (*disable)(struct device *dev);
 	struct gpio_button_data data[0];
 };
 
@@ -171,7 +169,7 @@ static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,
 	if (!bits)
 		return -ENOMEM;
 
-	for (i = 0; i < ddata->n_buttons; i++) {
+	for (i = 0; i < ddata->pdata->nbuttons; i++) {
 		struct gpio_button_data *bdata = &ddata->data[i];
 
 		if (bdata->button->type != type)
@@ -219,7 +217,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
 		goto out;
 
 	/* First validate */
-	for (i = 0; i < ddata->n_buttons; i++) {
+	for (i = 0; i < ddata->pdata->nbuttons; i++) {
 		struct gpio_button_data *bdata = &ddata->data[i];
 
 		if (bdata->button->type != type)
@@ -234,7 +232,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
 
 	mutex_lock(&ddata->disable_lock);
 
-	for (i = 0; i < ddata->n_buttons; i++) {
+	for (i = 0; i < ddata->pdata->nbuttons; i++) {
 		struct gpio_button_data *bdata = &ddata->data[i];
 
 		if (bdata->button->type != type)
@@ -346,6 +344,9 @@ static void gpio_keys_gpio_work_func(struct work_struct *work)
 		container_of(work, struct gpio_button_data, work);
 
 	gpio_keys_gpio_report_event(bdata);
+
+	if (bdata->button->wakeup)
+		pm_relax(bdata->input->dev.parent);
 }
 
 static void gpio_keys_gpio_timer(unsigned long _data)
@@ -361,6 +362,8 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
 
 	BUG_ON(irq != bdata->irq);
 
+	if (bdata->button->wakeup)
+		pm_stay_awake(bdata->input->dev.parent);
 	if (bdata->timer_debounce)
 		mod_timer(&bdata->timer,
 			jiffies + msecs_to_jiffies(bdata->timer_debounce));
@@ -397,6 +400,9 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
 	spin_lock_irqsave(&bdata->lock, flags);
 
 	if (!bdata->key_pressed) {
+		if (bdata->button->wakeup)
+			pm_wakeup_event(bdata->input->dev.parent, 0);
+
 		input_event(input, EV_KEY, button->code, 1);
 		input_sync(input);
 
@@ -523,56 +529,61 @@ fail:
 static int gpio_keys_open(struct input_dev *input)
 {
 	struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
+	const struct gpio_keys_platform_data *pdata = ddata->pdata;
 
-	return ddata->enable ? ddata->enable(input->dev.parent) : 0;
+	return pdata->enable ? pdata->enable(input->dev.parent) : 0;
 }
 
 static void gpio_keys_close(struct input_dev *input)
 {
 	struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
+	const struct gpio_keys_platform_data *pdata = ddata->pdata;
 
-	if (ddata->disable)
-		ddata->disable(input->dev.parent);
+	if (pdata->disable)
+		pdata->disable(input->dev.parent);
 }
 
 /*
  * Handlers for alternative sources of platform_data
  */
+
 #ifdef CONFIG_OF
 /*
  * Translate OpenFirmware node properties into platform_data
  */
-static int gpio_keys_get_devtree_pdata(struct device *dev,
-			    struct gpio_keys_platform_data *pdata)
+static struct gpio_keys_platform_data * __devinit
+gpio_keys_get_devtree_pdata(struct device *dev)
 {
 	struct device_node *node, *pp;
+	struct gpio_keys_platform_data *pdata;
+	struct gpio_keys_button *button;
+	int error;
+	int nbuttons;
 	int i;
-	struct gpio_keys_button *buttons;
-	u32 reg;
 
 	node = dev->of_node;
-	if (node == NULL)
-		return -ENODEV;
-
-	memset(pdata, 0, sizeof *pdata);
-
-	pdata->rep = !!of_get_property(node, "autorepeat", NULL);
+	if (!node) {
+		error = -ENODEV;
+		goto err_out;
+	}
 
-	/* First count the subnodes */
-	pp = NULL;
-	while ((pp = of_get_next_child(node, pp)))
-		pdata->nbuttons++;
+	nbuttons = of_get_child_count(node);
+	if (nbuttons == 0) {
+		error = -ENODEV;
+		goto err_out;
+	}
 
-	if (pdata->nbuttons == 0)
-		return -ENODEV;
+	pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button),
+			GFP_KERNEL);
+	if (!pdata) {
+		error = -ENOMEM;
+		goto err_out;
+	}
 
-	buttons = kzalloc(pdata->nbuttons * (sizeof *buttons), GFP_KERNEL);
-	if (!buttons)
-		return -ENOMEM;
+	pdata->rep = !!of_get_property(node, "autorepeat", NULL);
 
-	pp = NULL;
 	i = 0;
-	while ((pp = of_get_next_child(node, pp))) {
+	for_each_child_of_node(node, pp) {
 		enum of_gpio_flags flags;
 
 		if (!of_find_property(pp, "gpios", NULL)) {
@@ -580,39 +591,42 @@ static int gpio_keys_get_devtree_pdata(struct device *dev,
 			dev_warn(dev, "Found button without gpios\n");
 			continue;
 		}
-		buttons[i].gpio = of_get_gpio_flags(pp, 0, &flags);
-		buttons[i].active_low = flags & OF_GPIO_ACTIVE_LOW;
 
-		if (of_property_read_u32(pp, "linux,code", &reg)) {
-			dev_err(dev, "Button without keycode: 0x%x\n", buttons[i].gpio);
-			goto out_fail;
-		}
-		buttons[i].code = reg;
+		button = &pdata->buttons[i++];
 
-		buttons[i].desc = of_get_property(pp, "label", NULL);
+		button->gpio = of_get_gpio_flags(pp, 0, &flags);
+		button->active_low = flags & OF_GPIO_ACTIVE_LOW;
 
-		if (of_property_read_u32(pp, "linux,input-type", &reg) == 0)
-			buttons[i].type = reg;
-		else
-			buttons[i].type = EV_KEY;
+		if (of_property_read_u32(pp, "linux,code", &button->code)) {
+			dev_err(dev, "Button without keycode: 0x%x\n",
+				button->gpio);
+			error = -EINVAL;
+			goto err_free_pdata;
+		}
 
-		buttons[i].wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
+		button->desc = of_get_property(pp, "label", NULL);
 
-		if (of_property_read_u32(pp, "debounce-interval", &reg) == 0)
-			buttons[i].debounce_interval = reg;
-		else
-			buttons[i].debounce_interval = 5;
+		if (of_property_read_u32(pp, "linux,input-type", &button->type))
+			button->type = EV_KEY;
 
-		i++;
+		button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
+
+		if (of_property_read_u32(pp, "debounce-interval",
+					 &button->debounce_interval))
+			button->debounce_interval = 5;
 	}
 
-	pdata->buttons = buttons;
+	if (pdata->nbuttons == 0) {
+		error = -EINVAL;
+		goto err_free_pdata;
+	}
 
-	return 0;
+	return pdata;
 
-out_fail:
-	kfree(buttons);
-	return -ENODEV;
+err_free_pdata:
+	kfree(pdata);
+err_out:
+	return ERR_PTR(error);
 }
 
 static struct of_device_id gpio_keys_of_match[] = {
@@ -623,14 +637,12 @@ MODULE_DEVICE_TABLE(of, gpio_keys_of_match);
 
 #else
 
-static int gpio_keys_get_devtree_pdata(struct device *dev,
-			    struct gpio_keys_platform_data *altp)
+static inline struct gpio_keys_platform_data *
+gpio_keys_get_devtree_pdata(struct device *dev)
 {
-	return -ENODEV;
+	return ERR_PTR(-ENODEV);
 }
 
-#define gpio_keys_of_match NULL
-
 #endif
 
 static void gpio_remove_key(struct gpio_button_data *bdata)
@@ -645,19 +657,17 @@ static void gpio_remove_key(struct gpio_button_data *bdata)
 
 static int __devinit gpio_keys_probe(struct platform_device *pdev)
 {
-	const struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
-	struct gpio_keys_drvdata *ddata;
 	struct device *dev = &pdev->dev;
-	struct gpio_keys_platform_data alt_pdata;
+	const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
+	struct gpio_keys_drvdata *ddata;
 	struct input_dev *input;
 	int i, error;
 	int wakeup = 0;
 
 	if (!pdata) {
-		error = gpio_keys_get_devtree_pdata(dev, &alt_pdata);
-		if (error)
-			return error;
-		pdata = &alt_pdata;
+		pdata = gpio_keys_get_devtree_pdata(dev);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
 	}
 
 	ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
@@ -670,10 +680,8 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 		goto fail1;
 	}
 
+	ddata->pdata = pdata;
 	ddata->input = input;
-	ddata->n_buttons = pdata->nbuttons;
-	ddata->enable = pdata->enable;
-	ddata->disable = pdata->disable;
 	mutex_init(&ddata->disable_lock);
 
 	platform_set_drvdata(pdev, ddata);
@@ -742,9 +750,9 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
  fail1:
 	input_free_device(input);
 	kfree(ddata);
-	/* If we have no platform_data, we allocated buttons dynamically. */
-	if (!pdev->dev.platform_data)
-		kfree(pdata->buttons);
+	/* If we have no platform data, we allocated pdata dynamically. */
+	if (!dev_get_platdata(&pdev->dev))
+		kfree(pdata);
 
 	return error;
 }
@@ -759,18 +767,14 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
 
 	device_init_wakeup(&pdev->dev, 0);
 
-	for (i = 0; i < ddata->n_buttons; i++)
+	for (i = 0; i < ddata->pdata->nbuttons; i++)
 		gpio_remove_key(&ddata->data[i]);
 
 	input_unregister_device(input);
 
-	/*
-	 * If we had no platform_data, we allocated buttons dynamically, and
-	 * must free them here. ddata->data[0].button is the pointer to the
-	 * beginning of the allocated array.
-	 */
-	if (!pdev->dev.platform_data)
-		kfree(ddata->data[0].button);
+	/* If we have no platform data, we allocated pdata dynamically. */
+	if (!dev_get_platdata(&pdev->dev))
+		kfree(ddata->pdata);
 
 	kfree(ddata);
 
@@ -784,7 +788,7 @@ static int gpio_keys_suspend(struct device *dev)
 	int i;
 
 	if (device_may_wakeup(dev)) {
-		for (i = 0; i < ddata->n_buttons; i++) {
+		for (i = 0; i < ddata->pdata->nbuttons; i++) {
 			struct gpio_button_data *bdata = &ddata->data[i];
 			if (bdata->button->wakeup)
 				enable_irq_wake(bdata->irq);
@@ -799,7 +803,7 @@ static int gpio_keys_resume(struct device *dev)
 	struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
 	int i;
 
-	for (i = 0; i < ddata->n_buttons; i++) {
+	for (i = 0; i < ddata->pdata->nbuttons; i++) {
 		struct gpio_button_data *bdata = &ddata->data[i];
 		if (bdata->button->wakeup && device_may_wakeup(dev))
 			disable_irq_wake(bdata->irq);
@@ -822,7 +826,7 @@ static struct platform_driver gpio_keys_device_driver = {
 		.name	= "gpio-keys",
 		.owner	= THIS_MODULE,
 		.pm	= &gpio_keys_pm_ops,
-		.of_match_table = gpio_keys_of_match,
+		.of_match_table = of_match_ptr(gpio_keys_of_match),
 	}
 };
 
diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c
index 38e4b50..b3dd96d 100644
--- a/drivers/input/misc/twl4030-pwrbutton.c
+++ b/drivers/input/misc/twl4030-pwrbutton.c
@@ -42,6 +42,7 @@ static irqreturn_t powerbutton_irq(int irq, void *_pwr)
 	err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value,
 				STS_HW_CONDITIONS);
 	if (!err)  {
+		pm_wakeup_event(pwr->dev.parent, 0);
 		input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ);
 		input_sync(pwr);
 	} else {
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 0110b5a..964e43d 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -551,17 +551,16 @@ static int mousedev_open(struct inode *inode, struct file *file)
 		return -ENODEV;
 
 	error = mutex_lock_interruptible(&mousedev_table_mutex);
-	if (error) {
+	if (error)
 		return error;
-	}
+
 	mousedev = mousedev_table[i];
 	if (mousedev)
 		get_device(&mousedev->dev);
 	mutex_unlock(&mousedev_table_mutex);
 
-	if (!mousedev) {
+	if (!mousedev)
 		return -ENODEV;
-	}
 
 	client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL);
 	if (!client) {
@@ -1088,7 +1087,7 @@ static int __init mousedev_init(void)
 #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
 	error = misc_register(&psaux_mouse);
 	if (error)
-		pr_warning("could not register psaux device, error: %d\n",
+		pr_warn("could not register psaux device, error: %d\n",
 			   error);
 	else
 		psaux_registered = 1;
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c
index 75fb040..a70aa55 100644
--- a/drivers/input/sparse-keymap.c
+++ b/drivers/input/sparse-keymap.c
@@ -180,11 +180,11 @@ int sparse_keymap_setup(struct input_dev *dev,
 	for (e = keymap; e->type != KE_END; e++)
 		map_size++;
 
-	map = kcalloc(map_size, sizeof (struct key_entry), GFP_KERNEL);
+	map = kcalloc(map_size, sizeof(struct key_entry), GFP_KERNEL);
 	if (!map)
 		return -ENOMEM;
 
-	memcpy(map, keymap, map_size * sizeof (struct key_entry));
+	memcpy(map, keymap, map_size * sizeof(struct key_entry));
 
 	for (i = 0; i < map_size; i++) {
 		entry = &map[i];
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 0a2ea31..18a89b7 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -1111,7 +1111,7 @@ static void print_iommu_info(void)
 
 		if (iommu->cap & (1 << IOMMU_CAP_EFR)) {
 			pr_info("AMD-Vi:  Extended features: ");
-			for (i = 0; ARRAY_SIZE(feat_str); ++i) {
+			for (i = 0; i < ARRAY_SIZE(feat_str); ++i) {
 				if (iommu_feature(iommu, (1ULL << i)))
 					pr_cont(" %s", feat_str[i]);
 			}
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index e0b18f3..af8904d 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -736,6 +736,7 @@ int __init parse_ioapics_under_ir(void)
 {
 	struct dmar_drhd_unit *drhd;
 	int ir_supported = 0;
+	int ioapic_idx;
 
 	for_each_drhd_unit(drhd) {
 		struct intel_iommu *iommu = drhd->iommu;
@@ -748,13 +749,20 @@ int __init parse_ioapics_under_ir(void)
 		}
 	}
 
-	if (ir_supported && ir_ioapic_num != nr_ioapics) {
-		printk(KERN_WARNING
-		       "Not all IO-APIC's listed under remapping hardware\n");
-		return -1;
+	if (!ir_supported)
+		return 0;
+
+	for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++) {
+		int ioapic_id = mpc_ioapic_id(ioapic_idx);
+		if (!map_ioapic_to_ir(ioapic_id)) {
+			pr_err(FW_BUG "ioapic %d has no mapping iommu, "
+			       "interrupt remapping will be disabled\n",
+			       ioapic_id);
+			return -1;
+		}
 	}
 
-	return ir_supported;
+	return 1;
 }
 
 int __init ir_dev_scope_init(void)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 2a4bb36..5e51fb7 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -32,6 +32,8 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_iommu.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
 #include <asm/page.h>
 #include <asm/cacheflush.h>
@@ -47,16 +49,29 @@
 #define SMMU_CONFIG_DISABLE			0
 #define SMMU_CONFIG_ENABLE			1
 
-#define SMMU_TLB_CONFIG				0x14
-#define SMMU_TLB_CONFIG_STATS__MASK		(1 << 31)
-#define SMMU_TLB_CONFIG_STATS__ENABLE		(1 << 31)
+/* REVISIT: To support multiple MCs */
+enum {
+	_MC = 0,
+};
+
+enum {
+	_TLB = 0,
+	_PTC,
+};
+
+#define SMMU_CACHE_CONFIG_BASE			0x14
+#define __SMMU_CACHE_CONFIG(mc, cache)		(SMMU_CACHE_CONFIG_BASE + 4 * cache)
+#define SMMU_CACHE_CONFIG(cache)		__SMMU_CACHE_CONFIG(_MC, cache)
+
+#define SMMU_CACHE_CONFIG_STATS_SHIFT		31
+#define SMMU_CACHE_CONFIG_STATS_ENABLE		(1 << SMMU_CACHE_CONFIG_STATS_SHIFT)
+#define SMMU_CACHE_CONFIG_STATS_TEST_SHIFT	30
+#define SMMU_CACHE_CONFIG_STATS_TEST		(1 << SMMU_CACHE_CONFIG_STATS_TEST_SHIFT)
+
 #define SMMU_TLB_CONFIG_HIT_UNDER_MISS__ENABLE	(1 << 29)
 #define SMMU_TLB_CONFIG_ACTIVE_LINES__VALUE	0x10
 #define SMMU_TLB_CONFIG_RESET_VAL		0x20000010
 
-#define SMMU_PTC_CONFIG				0x18
-#define SMMU_PTC_CONFIG_STATS__MASK		(1 << 31)
-#define SMMU_PTC_CONFIG_STATS__ENABLE		(1 << 31)
 #define SMMU_PTC_CONFIG_CACHE__ENABLE		(1 << 29)
 #define SMMU_PTC_CONFIG_INDEX_MAP__PATTERN	0x3f
 #define SMMU_PTC_CONFIG_RESET_VAL		0x2000003f
@@ -86,10 +101,10 @@
 
 #define SMMU_ASID_SECURITY			0x38
 
-#define SMMU_STATS_TLB_HIT_COUNT		0x1f0
-#define SMMU_STATS_TLB_MISS_COUNT		0x1f4
-#define SMMU_STATS_PTC_HIT_COUNT		0x1f8
-#define SMMU_STATS_PTC_MISS_COUNT		0x1fc
+#define SMMU_STATS_CACHE_COUNT_BASE		0x1f0
+
+#define SMMU_STATS_CACHE_COUNT(mc, cache, hitmiss)		\
+	(SMMU_STATS_CACHE_COUNT_BASE + 8 * cache + 4 * hitmiss)
 
 #define SMMU_TRANSLATION_ENABLE_0		0x228
 #define SMMU_TRANSLATION_ENABLE_1		0x22c
@@ -251,6 +266,8 @@ struct smmu_device {
 	unsigned long translation_enable_2;
 	unsigned long asid_security;
 
+	struct dentry *debugfs_root;
+
 	struct device_node *ahb;
 
 	int		num_as;
@@ -412,8 +429,8 @@ static int smmu_setup_regs(struct smmu_device *smmu)
 	smmu_write(smmu, smmu->translation_enable_1, SMMU_TRANSLATION_ENABLE_1);
 	smmu_write(smmu, smmu->translation_enable_2, SMMU_TRANSLATION_ENABLE_2);
 	smmu_write(smmu, smmu->asid_security, SMMU_ASID_SECURITY);
-	smmu_write(smmu, SMMU_TLB_CONFIG_RESET_VAL, SMMU_TLB_CONFIG);
-	smmu_write(smmu, SMMU_PTC_CONFIG_RESET_VAL, SMMU_PTC_CONFIG);
+	smmu_write(smmu, SMMU_TLB_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_TLB));
+	smmu_write(smmu, SMMU_PTC_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_PTC));
 
 	smmu_flush_regs(smmu, 1);
 
@@ -895,6 +912,164 @@ static struct iommu_ops smmu_iommu_ops = {
 	.pgsize_bitmap	= SMMU_IOMMU_PGSIZES,
 };
 
+/* Should be in the order of enum */
+static const char * const smmu_debugfs_mc[] = { "mc", };
+static const char * const smmu_debugfs_cache[] = {  "tlb", "ptc", };
+
+static ssize_t smmu_debugfs_stats_write(struct file *file,
+					const char __user *buffer,
+					size_t count, loff_t *pos)
+{
+	struct smmu_device *smmu;
+	struct dentry *dent;
+	int i, cache, mc;
+	enum {
+		_OFF = 0,
+		_ON,
+		_RESET,
+	};
+	const char * const command[] = {
+		[_OFF]		= "off",
+		[_ON]		= "on",
+		[_RESET]	= "reset",
+	};
+	char str[] = "reset";
+	u32 val;
+	size_t offs;
+
+	count = min_t(size_t, count, sizeof(str));
+	if (copy_from_user(str, buffer, count))
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(command); i++)
+		if (strncmp(str, command[i],
+			    strlen(command[i])) == 0)
+			break;
+
+	if (i == ARRAY_SIZE(command))
+		return -EINVAL;
+
+	dent = file->f_dentry;
+	cache = (int)dent->d_inode->i_private;
+	mc = (int)dent->d_parent->d_inode->i_private;
+	smmu = dent->d_parent->d_parent->d_inode->i_private;
+
+	offs = SMMU_CACHE_CONFIG(cache);
+	val = smmu_read(smmu, offs);
+	switch (i) {
+	case _OFF:
+		val &= ~SMMU_CACHE_CONFIG_STATS_ENABLE;
+		val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
+		smmu_write(smmu, val, offs);
+		break;
+	case _ON:
+		val |= SMMU_CACHE_CONFIG_STATS_ENABLE;
+		val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
+		smmu_write(smmu, val, offs);
+		break;
+	case _RESET:
+		val |= SMMU_CACHE_CONFIG_STATS_TEST;
+		smmu_write(smmu, val, offs);
+		val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
+		smmu_write(smmu, val, offs);
+		break;
+	default:
+		BUG();
+		break;
+	}
+
+	dev_dbg(smmu->dev, "%s() %08x, %08x @%08x\n", __func__,
+		val, smmu_read(smmu, offs), offs);
+
+	return count;
+}
+
+static int smmu_debugfs_stats_show(struct seq_file *s, void *v)
+{
+	struct smmu_device *smmu;
+	struct dentry *dent;
+	int i, cache, mc;
+	const char * const stats[] = { "hit", "miss", };
+
+	dent = d_find_alias(s->private);
+	cache = (int)dent->d_inode->i_private;
+	mc = (int)dent->d_parent->d_inode->i_private;
+	smmu = dent->d_parent->d_parent->d_inode->i_private;
+
+	for (i = 0; i < ARRAY_SIZE(stats); i++) {
+		u32 val;
+		size_t offs;
+
+		offs = SMMU_STATS_CACHE_COUNT(mc, cache, i);
+		val = smmu_read(smmu, offs);
+		seq_printf(s, "%s:%08x ", stats[i], val);
+
+		dev_dbg(smmu->dev, "%s() %s %08x @%08x\n", __func__,
+			stats[i], val, offs);
+	}
+	seq_printf(s, "\n");
+
+	return 0;
+}
+
+static int smmu_debugfs_stats_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, smmu_debugfs_stats_show, inode);
+}
+
+static const struct file_operations smmu_debugfs_stats_fops = {
+	.open		= smmu_debugfs_stats_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+	.write		= smmu_debugfs_stats_write,
+};
+
+static void smmu_debugfs_delete(struct smmu_device *smmu)
+{
+	debugfs_remove_recursive(smmu->debugfs_root);
+}
+
+static void smmu_debugfs_create(struct smmu_device *smmu)
+{
+	int i;
+	struct dentry *root;
+
+	root = debugfs_create_file(dev_name(smmu->dev),
+				   S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
+				   NULL, smmu, NULL);
+	if (!root)
+		goto err_out;
+	smmu->debugfs_root = root;
+
+	for (i = 0; i < ARRAY_SIZE(smmu_debugfs_mc); i++) {
+		int j;
+		struct dentry *mc;
+
+		mc = debugfs_create_file(smmu_debugfs_mc[i],
+					 S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
+					 root, (void *)i, NULL);
+		if (!mc)
+			goto err_out;
+
+		for (j = 0; j < ARRAY_SIZE(smmu_debugfs_cache); j++) {
+			struct dentry *cache;
+
+			cache = debugfs_create_file(smmu_debugfs_cache[j],
+						    S_IWUGO | S_IRUGO, mc,
+						    (void *)j,
+						    &smmu_debugfs_stats_fops);
+			if (!cache)
+				goto err_out;
+		}
+	}
+
+	return;
+
+err_out:
+	smmu_debugfs_delete(smmu);
+}
+
 static int tegra_smmu_suspend(struct device *dev)
 {
 	struct smmu_device *smmu = dev_get_drvdata(dev);
@@ -999,6 +1174,7 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 	if (!smmu->avp_vector_page)
 		return -ENOMEM;
 
+	smmu_debugfs_create(smmu);
 	smmu_handle = smmu;
 	return 0;
 }
@@ -1008,6 +1184,8 @@ static int tegra_smmu_remove(struct platform_device *pdev)
 	struct smmu_device *smmu = platform_get_drvdata(pdev);
 	int i;
 
+	smmu_debugfs_delete(smmu);
+
 	smmu_write(smmu, SMMU_CONFIG_DISABLE, SMMU_CONFIG);
 	for (i = 0; i < smmu->num_as; i++)
 		free_pdir(&smmu->as[i]);
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 38c4bd8..c679867 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -234,7 +234,8 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
 
 	mp->minor = minor;
 
-	dev = tty_register_device(capinc_tty_driver, minor, NULL);
+	dev = tty_port_register_device(&mp->port, capinc_tty_driver, minor,
+			NULL);
 	if (IS_ERR(dev))
 		goto err_out2;
 
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index a6d9fd2..67abf3f 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -446,8 +446,8 @@ static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
 		goto out;
 	}
 
-	iflag = tty->termios->c_iflag;
-	cflag = tty->termios->c_cflag;
+	iflag = tty->termios.c_iflag;
+	cflag = tty->termios.c_cflag;
 	old_cflag = old ? old->c_cflag : cflag;
 	gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x",
 		cs->minor_index, iflag, cflag, old_cflag);
@@ -524,7 +524,8 @@ void gigaset_if_init(struct cardstate *cs)
 	tasklet_init(&cs->if_wake_tasklet, if_wake, (unsigned long) cs);
 
 	mutex_lock(&cs->mutex);
-	cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL);
+	cs->tty_dev = tty_port_register_device(&cs->port, drv->tty,
+			cs->minor_index, NULL);
 
 	if (!IS_ERR(cs->tty_dev))
 		dev_set_drvdata(cs->tty_dev, cs);
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 7bc5067..b817809 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1009,15 +1009,15 @@ isdn_tty_change_speed(modem_info *info)
 		quot;
 	int i;
 
-	if (!port->tty || !port->tty->termios)
+	if (!port->tty)
 		return;
-	cflag = port->tty->termios->c_cflag;
+	cflag = port->tty->termios.c_cflag;
 
 	quot = i = cflag & CBAUD;
 	if (i & CBAUDEX) {
 		i &= ~CBAUDEX;
 		if (i < 1 || i > 2)
-			port->tty->termios->c_cflag &= ~CBAUDEX;
+			port->tty->termios.c_cflag &= ~CBAUDEX;
 		else
 			i += 15;
 	}
@@ -1097,7 +1097,7 @@ isdn_tty_shutdown(modem_info *info)
 #endif
 	isdn_unlock_drivers();
 	info->msr &= ~UART_MSR_RI;
-	if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
+	if (!info->port.tty || (info->port.tty->termios.c_cflag & HUPCL)) {
 		info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
 		if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
 			isdn_tty_modem_reset_regs(info, 0);
@@ -1469,13 +1469,13 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 	if (!old_termios)
 		isdn_tty_change_speed(info);
 	else {
-		if (tty->termios->c_cflag == old_termios->c_cflag &&
-		    tty->termios->c_ispeed == old_termios->c_ispeed &&
-		    tty->termios->c_ospeed == old_termios->c_ospeed)
+		if (tty->termios.c_cflag == old_termios->c_cflag &&
+		    tty->termios.c_ispeed == old_termios->c_ispeed &&
+		    tty->termios.c_ospeed == old_termios->c_ospeed)
 			return;
 		isdn_tty_change_speed(info);
 		if ((old_termios->c_cflag & CRTSCTS) &&
-		    !(tty->termios->c_cflag & CRTSCTS))
+		    !(tty->termios.c_cflag & CRTSCTS))
 			tty->hw_stopped = 0;
 	}
 }
@@ -1486,6 +1486,18 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
  * ------------------------------------------------------------
  */
 
+static int isdn_tty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+	modem_info *info = &dev->mdm.info[tty->index];
+
+	if (isdn_tty_paranoia_check(info, tty->name, __func__))
+		return -ENODEV;
+
+	tty->driver_data = info;
+
+	return tty_port_install(&info->port, driver, tty);
+}
+
 /*
  * This routine is called whenever a serial port is opened.  It
  * enables interrupts for a serial port, linking in its async structure into
@@ -1495,22 +1507,16 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 static int
 isdn_tty_open(struct tty_struct *tty, struct file *filp)
 {
-	struct tty_port *port;
-	modem_info *info;
+	modem_info *info = tty->driver_data;
+	struct tty_port *port = &info->port;
 	int retval;
 
-	info = &dev->mdm.info[tty->index];
-	if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
-		return -ENODEV;
-	port = &info->port;
 #ifdef ISDN_DEBUG_MODEM_OPEN
 	printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name,
 	       port->count);
 #endif
 	port->count++;
-	tty->driver_data = info;
 	port->tty = tty;
-	tty->port = port;
 	/*
 	 * Start up serial port
 	 */
@@ -1738,6 +1744,7 @@ modem_write_profile(atemu *m)
 }
 
 static const struct tty_operations modem_ops = {
+	.install = isdn_tty_install,
 	.open = isdn_tty_open,
 	.close = isdn_tty_close,
 	.write = isdn_tty_write,
@@ -1782,7 +1789,7 @@ isdn_tty_modem_init(void)
 	m->tty_modem->subtype = SERIAL_TYPE_NORMAL;
 	m->tty_modem->init_termios = tty_std_termios;
 	m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-	m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	m->tty_modem->flags = TTY_DRIVER_REAL_RAW;
 	m->tty_modem->driver_name = "isdn_tty";
 	tty_set_operations(m->tty_modem, &modem_ops);
 	retval = tty_register_driver(m->tty_modem);
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index c96bbaa..16578d3 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -506,6 +506,16 @@ config LEDS_TRIGGER_BACKLIGHT
 
 	  If unsure, say N.
 
+config LEDS_TRIGGER_CPU
+	bool "LED CPU Trigger"
+	depends on LEDS_TRIGGERS
+	help
+	  This allows LEDs to be controlled by active CPUs. This shows
+	  the active CPUs across an array of LEDs so you can see which
+	  CPUs are active on the system at any given moment.
+
+	  If unsure, say N.
+
 config LEDS_TRIGGER_GPIO
 	tristate "LED GPIO Trigger"
 	depends on LEDS_TRIGGERS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index a4429a9..a9b627c 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -61,5 +61,6 @@ obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK)	+= ledtrig-ide-disk.o
 obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT)	+= ledtrig-heartbeat.o
 obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT)	+= ledtrig-backlight.o
 obj-$(CONFIG_LEDS_TRIGGER_GPIO)		+= ledtrig-gpio.o
+obj-$(CONFIG_LEDS_TRIGGER_CPU)		+= ledtrig-cpu.o
 obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON)	+= ledtrig-default-on.o
 obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT)	+= ledtrig-transient.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index c599095..48cce18 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -124,6 +124,16 @@ static void led_timer_function(unsigned long data)
 	mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay));
 }
 
+static void set_brightness_delayed(struct work_struct *ws)
+{
+	struct led_classdev *led_cdev =
+		container_of(ws, struct led_classdev, set_brightness_work);
+
+	led_stop_software_blink(led_cdev);
+
+	__led_set_brightness(led_cdev, led_cdev->delayed_set_value);
+}
+
 /**
  * led_classdev_suspend - suspend an led_classdev.
  * @led_cdev: the led_classdev to suspend.
@@ -191,6 +201,8 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
 
 	led_update_brightness(led_cdev);
 
+	INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed);
+
 	init_timer(&led_cdev->blink_timer);
 	led_cdev->blink_timer.function = led_timer_function;
 	led_cdev->blink_timer.data = (unsigned long)led_cdev;
@@ -221,7 +233,10 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
 	up_write(&led_cdev->trigger_lock);
 #endif
 
+	cancel_work_sync(&led_cdev->set_brightness_work);
+
 	/* Stop blinking */
+	led_stop_software_blink(led_cdev);
 	led_set_brightness(led_cdev, LED_OFF);
 
 	device_unregister(led_cdev->dev);
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index 2ab05af..ce8921a 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -103,13 +103,23 @@ void led_blink_set_oneshot(struct led_classdev *led_cdev,
 }
 EXPORT_SYMBOL(led_blink_set_oneshot);
 
-void led_set_brightness(struct led_classdev *led_cdev,
-			enum led_brightness brightness)
+void led_stop_software_blink(struct led_classdev *led_cdev)
 {
-	/* stop and clear soft-blink timer */
 	del_timer_sync(&led_cdev->blink_timer);
 	led_cdev->blink_delay_on = 0;
 	led_cdev->blink_delay_off = 0;
+}
+EXPORT_SYMBOL_GPL(led_stop_software_blink);
+
+void led_set_brightness(struct led_classdev *led_cdev,
+			enum led_brightness brightness)
+{
+	/* delay brightness setting if need to stop soft-blink timer */
+	if (led_cdev->blink_delay_on || led_cdev->blink_delay_off) {
+		led_cdev->delayed_set_value = brightness;
+		schedule_work(&led_cdev->set_brightness_work);
+		return;
+	}
 
 	__led_set_brightness(led_cdev, brightness);
 }
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 363975b..b53bf54 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -109,6 +109,8 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
 		list_del(&led_cdev->trig_list);
 		write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock,
 			flags);
+		cancel_work_sync(&led_cdev->set_brightness_work);
+		led_stop_software_blink(led_cdev);
 		if (led_cdev->trigger->deactivate)
 			led_cdev->trigger->deactivate(led_cdev);
 		led_cdev->trigger = NULL;
@@ -224,7 +226,7 @@ void led_trigger_event(struct led_trigger *trig,
 		struct led_classdev *led_cdev;
 
 		led_cdev = list_entry(entry, struct led_classdev, trig_list);
-		__led_set_brightness(led_cdev, brightness);
+		led_set_brightness(led_cdev, brightness);
 	}
 	read_unlock(&trig->leddev_list_lock);
 }
diff --git a/drivers/leds/leds-clevo-mail.c b/drivers/leds/leds-clevo-mail.c
index 1ed1677..e024b0b 100644
--- a/drivers/leds/leds-clevo-mail.c
+++ b/drivers/leds/leds-clevo-mail.c
@@ -31,7 +31,7 @@ static int __init clevo_mail_led_dmi_callback(const struct dmi_system_id *id)
 }
 
 /*
- * struct mail_led_whitelist - List of known good models
+ * struct clevo_mail_led_dmi_table - List of known good models
  *
  * Contains the known good models this driver is compatible with.
  * When adding a new model try to be as strict as possible. This
@@ -39,7 +39,7 @@ static int __init clevo_mail_led_dmi_callback(const struct dmi_system_id *id)
  * detected as working, but in reality it is not) as low as
  * possible.
  */
-static struct dmi_system_id __initdata mail_led_whitelist[] = {
+static struct dmi_system_id __initdata clevo_mail_led_dmi_table[] = {
 	{
 		.callback = clevo_mail_led_dmi_callback,
 		.ident = "Clevo D410J",
@@ -59,11 +59,10 @@ static struct dmi_system_id __initdata mail_led_whitelist[] = {
 	},
 	{
 		.callback = clevo_mail_led_dmi_callback,
-		.ident = "Positivo Mobile",
+		.ident = "Clevo M5x0V",
 		.matches = {
 			DMI_MATCH(DMI_BOARD_VENDOR, "CLEVO Co. "),
 			DMI_MATCH(DMI_BOARD_NAME, "M5X0V "),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Positivo Mobile"),
 			DMI_MATCH(DMI_PRODUCT_VERSION, "VT6198")
 		}
 	},
@@ -89,6 +88,7 @@ static struct dmi_system_id __initdata mail_led_whitelist[] = {
 	},
 	{ }
 };
+MODULE_DEVICE_TABLE(dmi, clevo_mail_led_dmi_table);
 
 static void clevo_mail_led_set(struct led_classdev *led_cdev,
 				enum led_brightness value)
@@ -180,7 +180,7 @@ static int __init clevo_mail_led_init(void)
 
 	/* Check with the help of DMI if we are running on supported hardware */
 	if (!nodetect) {
-		count = dmi_check_system(mail_led_whitelist);
+		count = dmi_check_system(clevo_mail_led_dmi_table);
 	} else {
 		count = 1;
 		printk(KERN_ERR KBUILD_MODNAME ": Skipping DMI detection. "
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index c032b21..c392c1e 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -228,7 +228,6 @@ static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_dev
 {
 	return NULL;
 }
-#define of_gpio_leds_match NULL
 #endif /* CONFIG_OF_GPIO */
 
 
@@ -270,13 +269,13 @@ static int __devinit gpio_led_probe(struct platform_device *pdev)
 
 static int __devexit gpio_led_remove(struct platform_device *pdev)
 {
-	struct gpio_leds_priv *priv = dev_get_drvdata(&pdev->dev);
+	struct gpio_leds_priv *priv = platform_get_drvdata(pdev);
 	int i;
 
 	for (i = 0; i < priv->num_leds; i++)
 		delete_gpio_led(&priv->leds[i]);
 
-	dev_set_drvdata(&pdev->dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 
 	return 0;
 }
@@ -287,7 +286,7 @@ static struct platform_driver gpio_led_driver = {
 	.driver		= {
 		.name	= "leds-gpio",
 		.owner	= THIS_MODULE,
-		.of_match_table = of_gpio_leds_match,
+		.of_match_table = of_match_ptr(of_gpio_leds_match),
 	},
 };
 
diff --git a/drivers/leds/leds-wm8350.c b/drivers/leds/leds-wm8350.c
index 918d4ba..f5d9ac3 100644
--- a/drivers/leds/leds-wm8350.c
+++ b/drivers/leds/leds-wm8350.c
@@ -201,7 +201,7 @@ static int wm8350_led_probe(struct platform_device *pdev)
 	struct regulator *isink, *dcdc;
 	struct wm8350_led *led;
 	struct wm8350_led_platform_data *pdata = pdev->dev.platform_data;
-	int ret, i;
+	int i;
 
 	if (pdata == NULL) {
 		dev_err(&pdev->dev, "no platform data\n");
@@ -214,24 +214,21 @@ static int wm8350_led_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	isink = regulator_get(&pdev->dev, "led_isink");
+	isink = devm_regulator_get(&pdev->dev, "led_isink");
 	if (IS_ERR(isink)) {
 		printk(KERN_ERR "%s: can't get ISINK\n", __func__);
 		return PTR_ERR(isink);
 	}
 
-	dcdc = regulator_get(&pdev->dev, "led_vcc");
+	dcdc = devm_regulator_get(&pdev->dev, "led_vcc");
 	if (IS_ERR(dcdc)) {
 		printk(KERN_ERR "%s: can't get DCDC\n", __func__);
-		ret = PTR_ERR(dcdc);
-		goto err_isink;
+		return PTR_ERR(dcdc);
 	}
 
 	led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
-	if (led == NULL) {
-		ret = -ENOMEM;
-		goto err_dcdc;
-	}
+	if (led == NULL)
+		return -ENOMEM;
 
 	led->cdev.brightness_set = wm8350_led_set;
 	led->cdev.default_trigger = pdata->default_trigger;
@@ -257,17 +254,7 @@ static int wm8350_led_probe(struct platform_device *pdev)
 	led->value = LED_OFF;
 	platform_set_drvdata(pdev, led);
 
-	ret = led_classdev_register(&pdev->dev, &led->cdev);
-	if (ret < 0)
-		goto err_dcdc;
-
-	return 0;
-
- err_dcdc:
-	regulator_put(dcdc);
- err_isink:
-	regulator_put(isink);
-	return ret;
+	return led_classdev_register(&pdev->dev, &led->cdev);
 }
 
 static int wm8350_led_remove(struct platform_device *pdev)
@@ -277,8 +264,6 @@ static int wm8350_led_remove(struct platform_device *pdev)
 	led_classdev_unregister(&led->cdev);
 	flush_work_sync(&led->work);
 	wm8350_led_disable(led);
-	regulator_put(led->dcdc);
-	regulator_put(led->isink);
 	return 0;
 }
 
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index d02acd4..4c50365 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -32,6 +32,8 @@ static inline int led_get_brightness(struct led_classdev *led_cdev)
 	return led_cdev->brightness;
 }
 
+void led_stop_software_blink(struct led_classdev *led_cdev);
+
 extern struct rw_semaphore leds_list_lock;
 extern struct list_head leds_list;
 
diff --git a/drivers/leds/ledtrig-cpu.c b/drivers/leds/ledtrig-cpu.c
new file mode 100644
index 0000000..b312056
--- /dev/null
+++ b/drivers/leds/ledtrig-cpu.c
@@ -0,0 +1,163 @@
+/*
+ * ledtrig-cpu.c - LED trigger based on CPU activity
+ *
+ * This LED trigger will be registered for each possible CPU and named as
+ * cpu0, cpu1, cpu2, cpu3, etc.
+ *
+ * It can be bound to any LED just like other triggers using either a
+ * board file or via sysfs interface.
+ *
+ * An API named ledtrig_cpu is exported for any user, who want to add CPU
+ * activity indication in their code
+ *
+ * Copyright 2011 Linus Walleij <linus.walleij@linaro.org>
+ * Copyright 2011 - 2012 Bryan Wu <bryan.wu@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/percpu.h>
+#include <linux/syscore_ops.h>
+#include <linux/rwsem.h>
+#include "leds.h"
+
+#define MAX_NAME_LEN	8
+
+struct led_trigger_cpu {
+	char name[MAX_NAME_LEN];
+	struct led_trigger *_trig;
+	struct mutex lock;
+	int lock_is_inited;
+};
+
+static DEFINE_PER_CPU(struct led_trigger_cpu, cpu_trig);
+
+/**
+ * ledtrig_cpu - emit a CPU event as a trigger
+ * @evt: CPU event to be emitted
+ *
+ * Emit a CPU event on a CPU core, which will trigger a
+ * binded LED to turn on or turn off.
+ */
+void ledtrig_cpu(enum cpu_led_event ledevt)
+{
+	struct led_trigger_cpu *trig = &__get_cpu_var(cpu_trig);
+
+	/* mutex lock should be initialized before calling mutex_call() */
+	if (!trig->lock_is_inited)
+		return;
+
+	mutex_lock(&trig->lock);
+
+	/* Locate the correct CPU LED */
+	switch (ledevt) {
+	case CPU_LED_IDLE_END:
+	case CPU_LED_START:
+		/* Will turn the LED on, max brightness */
+		led_trigger_event(trig->_trig, LED_FULL);
+		break;
+
+	case CPU_LED_IDLE_START:
+	case CPU_LED_STOP:
+	case CPU_LED_HALTED:
+		/* Will turn the LED off */
+		led_trigger_event(trig->_trig, LED_OFF);
+		break;
+
+	default:
+		/* Will leave the LED as it is */
+		break;
+	}
+
+	mutex_unlock(&trig->lock);
+}
+EXPORT_SYMBOL(ledtrig_cpu);
+
+static int ledtrig_cpu_syscore_suspend(void)
+{
+	ledtrig_cpu(CPU_LED_STOP);
+	return 0;
+}
+
+static void ledtrig_cpu_syscore_resume(void)
+{
+	ledtrig_cpu(CPU_LED_START);
+}
+
+static void ledtrig_cpu_syscore_shutdown(void)
+{
+	ledtrig_cpu(CPU_LED_HALTED);
+}
+
+static struct syscore_ops ledtrig_cpu_syscore_ops = {
+	.shutdown	= ledtrig_cpu_syscore_shutdown,
+	.suspend	= ledtrig_cpu_syscore_suspend,
+	.resume		= ledtrig_cpu_syscore_resume,
+};
+
+static int __init ledtrig_cpu_init(void)
+{
+	int cpu;
+
+	/* Supports up to 9999 cpu cores */
+	BUILD_BUG_ON(CONFIG_NR_CPUS > 9999);
+
+	/*
+	 * Registering CPU led trigger for each CPU core here
+	 * ignores CPU hotplug, but after this CPU hotplug works
+	 * fine with this trigger.
+	 */
+	for_each_possible_cpu(cpu) {
+		struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
+
+		mutex_init(&trig->lock);
+
+		snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu);
+
+		mutex_lock(&trig->lock);
+		led_trigger_register_simple(trig->name, &trig->_trig);
+		trig->lock_is_inited = 1;
+		mutex_unlock(&trig->lock);
+	}
+
+	register_syscore_ops(&ledtrig_cpu_syscore_ops);
+
+	pr_info("ledtrig-cpu: registered to indicate activity on CPUs\n");
+
+	return 0;
+}
+module_init(ledtrig_cpu_init);
+
+static void __exit ledtrig_cpu_exit(void)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu) {
+		struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
+
+		mutex_lock(&trig->lock);
+
+		led_trigger_unregister_simple(trig->_trig);
+		trig->_trig = NULL;
+		memset(trig->name, 0, MAX_NAME_LEN);
+		trig->lock_is_inited = 0;
+
+		mutex_unlock(&trig->lock);
+		mutex_destroy(&trig->lock);
+	}
+
+	unregister_syscore_ops(&ledtrig_cpu_syscore_ops);
+}
+module_exit(ledtrig_cpu_exit);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
+MODULE_AUTHOR("Bryan Wu <bryan.wu@canonical.com>");
+MODULE_DESCRIPTION("CPU LED trigger");
+MODULE_LICENSE("GPL");
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 831d751..3f8d032 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -63,7 +63,7 @@ struct media_bay_info {
 	int				value_count;
 	int				timer;
 	struct macio_dev		*mdev;
-	struct mb_ops*			ops;
+	const struct mb_ops*		ops;
 	int				index;
 	int				cached_gpio;
 	int				sleeping;
@@ -669,7 +669,7 @@ static int media_bay_resume(struct macio_dev *mdev)
 
 /* Definitions of "ops" structures.
  */
-static struct mb_ops ohare_mb_ops = {
+static const struct mb_ops ohare_mb_ops = {
 	.name		= "Ohare",
 	.content	= ohare_mb_content,
 	.power		= ohare_mb_power,
@@ -678,7 +678,7 @@ static struct mb_ops ohare_mb_ops = {
 	.un_reset_ide	= ohare_mb_un_reset_ide,
 };
 
-static struct mb_ops heathrow_mb_ops = {
+static const struct mb_ops heathrow_mb_ops = {
 	.name		= "Heathrow",
 	.content	= heathrow_mb_content,
 	.power		= heathrow_mb_power,
@@ -687,7 +687,7 @@ static struct mb_ops heathrow_mb_ops = {
 	.un_reset_ide	= heathrow_mb_un_reset_ide,
 };
 
-static struct mb_ops keylargo_mb_ops = {
+static const struct mb_ops keylargo_mb_ops = {
 	.name		= "KeyLargo",
 	.init		= keylargo_mb_init,
 	.content	= keylargo_mb_content,
diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c
index 254d192..892ae27 100644
--- a/drivers/md/dm-verity.c
+++ b/drivers/md/dm-verity.c
@@ -718,8 +718,8 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
 	v->hash_dev_block_bits = ffs(num) - 1;
 
 	if (sscanf(argv[5], "%llu%c", &num_ll, &dummy) != 1 ||
-	    num_ll << (v->data_dev_block_bits - SECTOR_SHIFT) !=
-	    (sector_t)num_ll << (v->data_dev_block_bits - SECTOR_SHIFT)) {
+	    (sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT))
+	    >> (v->data_dev_block_bits - SECTOR_SHIFT) != num_ll) {
 		ti->error = "Invalid data blocks";
 		r = -EINVAL;
 		goto bad;
@@ -733,8 +733,8 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
 	}
 
 	if (sscanf(argv[6], "%llu%c", &num_ll, &dummy) != 1 ||
-	    num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT) !=
-	    (sector_t)num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT)) {
+	    (sector_t)(num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT))
+	    >> (v->hash_dev_block_bits - SECTOR_SHIFT) != num_ll) {
 		ti->error = "Invalid hash start";
 		r = -EINVAL;
 		goto bad;
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index fa211d8..2101483 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -138,6 +138,7 @@ static struct linear_conf *linear_conf(struct mddev *mddev, int raid_disks)
 	struct linear_conf *conf;
 	struct md_rdev *rdev;
 	int i, cnt;
+	bool discard_supported = false;
 
 	conf = kzalloc (sizeof (*conf) + raid_disks*sizeof(struct dev_info),
 			GFP_KERNEL);
@@ -171,6 +172,8 @@ static struct linear_conf *linear_conf(struct mddev *mddev, int raid_disks)
 		conf->array_sectors += rdev->sectors;
 		cnt++;
 
+		if (blk_queue_discard(bdev_get_queue(rdev->bdev)))
+			discard_supported = true;
 	}
 	if (cnt != raid_disks) {
 		printk(KERN_ERR "md/linear:%s: not enough drives present. Aborting!\n",
@@ -178,6 +181,11 @@ static struct linear_conf *linear_conf(struct mddev *mddev, int raid_disks)
 		goto out;
 	}
 
+	if (!discard_supported)
+		queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
+	else
+		queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
+
 	/*
 	 * Here we calculate the device offsets.
 	 */
@@ -244,7 +252,9 @@ static int linear_add(struct mddev *mddev, struct md_rdev *rdev)
 	if (!newconf)
 		return -ENOMEM;
 
-	oldconf = rcu_dereference(mddev->private);
+	oldconf = rcu_dereference_protected(mddev->private,
+					    lockdep_is_held(
+						    &mddev->reconfig_mutex));
 	mddev->raid_disks++;
 	rcu_assign_pointer(mddev->private, newconf);
 	md_set_array_sectors(mddev, linear_size(mddev, 0, 0));
@@ -256,7 +266,10 @@ static int linear_add(struct mddev *mddev, struct md_rdev *rdev)
 
 static int linear_stop (struct mddev *mddev)
 {
-	struct linear_conf *conf = mddev->private;
+	struct linear_conf *conf =
+		rcu_dereference_protected(mddev->private,
+					  lockdep_is_held(
+						  &mddev->reconfig_mutex));
 
 	/*
 	 * We do not require rcu protection here since
@@ -326,6 +339,14 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio)
 	bio->bi_sector = bio->bi_sector - start_sector
 		+ tmp_dev->rdev->data_offset;
 	rcu_read_unlock();
+
+	if (unlikely((bio->bi_rw & REQ_DISCARD) &&
+		     !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) {
+		/* Just ignore it */
+		bio_endio(bio, 0);
+		return;
+	}
+
 	generic_make_request(bio);
 }
 
diff --git a/drivers/md/md.c b/drivers/md/md.c
index fcd0987..e34934a 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -640,9 +640,9 @@ static struct mddev * mddev_find(dev_t unit)
 	goto retry;
 }
 
-static inline int mddev_lock(struct mddev * mddev)
+int md_queue_misc_work(struct work_struct *work)
 {
-	return mutex_lock_interruptible(&mddev->reconfig_mutex);
+	return queue_work(md_misc_wq, work);
 }
 
 static inline int mddev_is_locked(struct mddev *mddev)
@@ -657,7 +657,7 @@ static inline int mddev_trylock(struct mddev * mddev)
 
 static struct attribute_group md_redundancy_group;
 
-static void mddev_unlock(struct mddev * mddev)
+void mddev_unlock(struct mddev * mddev)
 {
 	if (mddev->to_remove) {
 		/* These cannot be removed under reconfig_mutex as
@@ -711,6 +711,17 @@ static struct md_rdev * find_rdev_nr(struct mddev *mddev, int nr)
 	return NULL;
 }
 
+static struct md_rdev * find_rdev_nr_rcu(struct mddev *mddev, int nr)
+{
+	struct md_rdev *rdev;
+
+	rdev_for_each_rcu(rdev, mddev)
+		if (rdev->desc_nr == nr)
+			return rdev;
+
+	return NULL;
+}
+
 static struct md_rdev * find_rdev(struct mddev * mddev, dev_t dev)
 {
 	struct md_rdev *rdev;
@@ -722,6 +733,17 @@ static struct md_rdev * find_rdev(struct mddev * mddev, dev_t dev)
 	return NULL;
 }
 
+static struct md_rdev * find_rdev_rcu(struct mddev * mddev, dev_t dev)
+{
+	struct md_rdev *rdev;
+
+	rdev_for_each_rcu(rdev, mddev)
+		if (rdev->bdev->bd_dev == dev)
+			return rdev;
+
+	return NULL;
+}
+
 static struct md_personality *find_pers(int level, char *clevel)
 {
 	struct md_personality *pers;
@@ -1108,8 +1130,11 @@ static int super_90_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor
 			ret = 0;
 	}
 	rdev->sectors = rdev->sb_start;
-	/* Limit to 4TB as metadata cannot record more than that */
-	if (rdev->sectors >= (2ULL << 32))
+	/* Limit to 4TB as metadata cannot record more than that.
+	 * (not needed for Linear and RAID0 as metadata doesn't
+	 * record this size)
+	 */
+	if (rdev->sectors >= (2ULL << 32) && sb->level >= 1)
 		rdev->sectors = (2ULL << 32) - 2;
 
 	if (rdev->sectors < ((sector_t)sb->size) * 2 && sb->level >= 1)
@@ -1400,7 +1425,7 @@ super_90_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
 	/* Limit to 4TB as metadata cannot record more than that.
 	 * 4TB == 2^32 KB, or 2*2^32 sectors.
 	 */
-	if (num_sectors >= (2ULL << 32))
+	if (num_sectors >= (2ULL << 32) && rdev->mddev->level >= 1)
 		num_sectors = (2ULL << 32) - 2;
 	md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
 		       rdev->sb_page);
@@ -5544,8 +5569,9 @@ static int get_array_info(struct mddev * mddev, void __user * arg)
 	int nr,working,insync,failed,spare;
 	struct md_rdev *rdev;
 
-	nr=working=insync=failed=spare=0;
-	rdev_for_each(rdev, mddev) {
+	nr = working = insync = failed = spare = 0;
+	rcu_read_lock();
+	rdev_for_each_rcu(rdev, mddev) {
 		nr++;
 		if (test_bit(Faulty, &rdev->flags))
 			failed++;
@@ -5557,6 +5583,7 @@ static int get_array_info(struct mddev * mddev, void __user * arg)
 				spare++;
 		}
 	}
+	rcu_read_unlock();
 
 	info.major_version = mddev->major_version;
 	info.minor_version = mddev->minor_version;
@@ -5640,7 +5667,8 @@ static int get_disk_info(struct mddev * mddev, void __user * arg)
 	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 
-	rdev = find_rdev_nr(mddev, info.number);
+	rcu_read_lock();
+	rdev = find_rdev_nr_rcu(mddev, info.number);
 	if (rdev) {
 		info.major = MAJOR(rdev->bdev->bd_dev);
 		info.minor = MINOR(rdev->bdev->bd_dev);
@@ -5659,6 +5687,7 @@ static int get_disk_info(struct mddev * mddev, void __user * arg)
 		info.raid_disk = -1;
 		info.state = (1<<MD_DISK_REMOVED);
 	}
+	rcu_read_unlock();
 
 	if (copy_to_user(arg, &info, sizeof(info)))
 		return -EFAULT;
@@ -6267,18 +6296,22 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
 static int set_disk_faulty(struct mddev *mddev, dev_t dev)
 {
 	struct md_rdev *rdev;
+	int err = 0;
 
 	if (mddev->pers == NULL)
 		return -ENODEV;
 
-	rdev = find_rdev(mddev, dev);
+	rcu_read_lock();
+	rdev = find_rdev_rcu(mddev, dev);
 	if (!rdev)
-		return -ENODEV;
-
-	md_error(mddev, rdev);
-	if (!test_bit(Faulty, &rdev->flags))
-		return -EBUSY;
-	return 0;
+		err =  -ENODEV;
+	else {
+		md_error(mddev, rdev);
+		if (!test_bit(Faulty, &rdev->flags))
+			err = -EBUSY;
+	}
+	rcu_read_unlock();
+	return err;
 }
 
 /*
@@ -6350,6 +6383,21 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
 		goto abort;
 	}
 
+	/* Some actions do not requires the mutex */
+	switch (cmd) {
+		case GET_ARRAY_INFO:
+			err = get_array_info(mddev, argp);
+			goto abort;
+
+		case GET_DISK_INFO:
+			err = get_disk_info(mddev, argp);
+			goto abort;
+
+		case SET_DISK_FAULTY:
+			err = set_disk_faulty(mddev, new_decode_dev(arg));
+			goto abort;
+	}
+
 	err = mddev_lock(mddev);
 	if (err) {
 		printk(KERN_INFO 
@@ -6422,18 +6470,10 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
 	 */
 	switch (cmd)
 	{
-		case GET_ARRAY_INFO:
-			err = get_array_info(mddev, argp);
-			goto done_unlock;
-
 		case GET_BITMAP_FILE:
 			err = get_bitmap_file(mddev, argp);
 			goto done_unlock;
 
-		case GET_DISK_INFO:
-			err = get_disk_info(mddev, argp);
-			goto done_unlock;
-
 		case RESTART_ARRAY_RW:
 			err = restart_array(mddev);
 			goto done_unlock;
@@ -6515,10 +6555,6 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
 			err = hot_add_disk(mddev, new_decode_dev(arg));
 			goto done_unlock;
 
-		case SET_DISK_FAULTY:
-			err = set_disk_faulty(mddev, new_decode_dev(arg));
-			goto done_unlock;
-
 		case RUN_ARRAY:
 			err = do_md_run(mddev);
 			goto done_unlock;
@@ -6676,7 +6712,7 @@ static int md_thread(void * arg)
 
 		clear_bit(THREAD_WAKEUP, &thread->flags);
 		if (!kthread_should_stop())
-			thread->run(thread->mddev);
+			thread->run(thread);
 	}
 
 	return 0;
@@ -6691,8 +6727,8 @@ void md_wakeup_thread(struct md_thread *thread)
 	}
 }
 
-struct md_thread *md_register_thread(void (*run) (struct mddev *), struct mddev *mddev,
-				 const char *name)
+struct md_thread *md_register_thread(void (*run) (struct md_thread *),
+		struct mddev *mddev, const char *name)
 {
 	struct md_thread *thread;
 
@@ -7241,8 +7277,9 @@ EXPORT_SYMBOL_GPL(md_allow_write);
 
 #define SYNC_MARKS	10
 #define	SYNC_MARK_STEP	(3*HZ)
-void md_do_sync(struct mddev *mddev)
+void md_do_sync(struct md_thread *thread)
 {
+	struct mddev *mddev = thread->mddev;
 	struct mddev *mddev2;
 	unsigned int currspeed = 0,
 		 window;
@@ -8568,6 +8605,8 @@ EXPORT_SYMBOL(md_register_thread);
 EXPORT_SYMBOL(md_unregister_thread);
 EXPORT_SYMBOL(md_wakeup_thread);
 EXPORT_SYMBOL(md_check_recovery);
+EXPORT_SYMBOL(mddev_unlock);
+EXPORT_SYMBOL(md_queue_misc_work);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("MD RAID framework");
 MODULE_ALIAS("md");
diff --git a/drivers/md/md.h b/drivers/md/md.h
index f385b03..dce301c 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -540,12 +540,13 @@ static inline void sysfs_unlink_rdev(struct mddev *mddev, struct md_rdev *rdev)
 	list_for_each_entry_rcu(rdev, &((mddev)->disks), same_set)
 
 struct md_thread {
-	void			(*run) (struct mddev *mddev);
+	void			(*run) (struct md_thread *thread);
 	struct mddev		*mddev;
 	wait_queue_head_t	wqueue;
 	unsigned long           flags;
 	struct task_struct	*tsk;
 	unsigned long		timeout;
+	void			*private;
 };
 
 #define THREAD_WAKEUP  0
@@ -584,7 +585,7 @@ static inline void safe_put_page(struct page *p)
 extern int register_md_personality(struct md_personality *p);
 extern int unregister_md_personality(struct md_personality *p);
 extern struct md_thread *md_register_thread(
-	void (*run)(struct mddev *mddev),
+	void (*run)(struct md_thread *thread),
 	struct mddev *mddev,
 	const char *name);
 extern void md_unregister_thread(struct md_thread **threadp);
@@ -603,7 +604,7 @@ extern void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
 extern void md_super_wait(struct mddev *mddev);
 extern int sync_page_io(struct md_rdev *rdev, sector_t sector, int size, 
 			struct page *page, int rw, bool metadata_op);
-extern void md_do_sync(struct mddev *mddev);
+extern void md_do_sync(struct md_thread *thread);
 extern void md_new_event(struct mddev *mddev);
 extern int md_allow_write(struct mddev *mddev);
 extern void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev);
@@ -635,4 +636,12 @@ static inline int mddev_check_plugged(struct mddev *mddev)
 	return !!blk_check_plugged(md_unplug, mddev,
 				   sizeof(struct blk_plug_cb));
 }
+
+static inline int mddev_lock(struct mddev * mddev)
+{
+	return mutex_lock_interruptible(&mddev->reconfig_mutex);
+}
+extern void mddev_unlock(struct mddev *mddev);
+extern int md_queue_misc_work(struct work_struct *work);
+
 #endif /* _MD_MD_H */
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 61a1833..2ab23d0 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -335,8 +335,9 @@ abort:
  *	3.	Performs writes following reads for array syncronising.
  */
 
-static void multipathd (struct mddev *mddev)
+static void multipathd (struct md_thread *thread)
 {
+	struct mddev *mddev = thread->mddev;
 	struct multipath_bh *mp_bh;
 	struct bio *bio;
 	unsigned long flags;
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index de63a1f..1a8e5e3 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -88,6 +88,7 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
 	char b[BDEVNAME_SIZE];
 	char b2[BDEVNAME_SIZE];
 	struct r0conf *conf = kzalloc(sizeof(*conf), GFP_KERNEL);
+	bool discard_supported = false;
 
 	if (!conf)
 		return -ENOMEM;
@@ -195,6 +196,9 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
 		if (!smallest || (rdev1->sectors < smallest->sectors))
 			smallest = rdev1;
 		cnt++;
+
+		if (blk_queue_discard(bdev_get_queue(rdev1->bdev)))
+			discard_supported = true;
 	}
 	if (cnt != mddev->raid_disks) {
 		printk(KERN_ERR "md/raid0:%s: too few disks (%d of %d) - "
@@ -272,6 +276,11 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
 	blk_queue_io_opt(mddev->queue,
 			 (mddev->chunk_sectors << 9) * mddev->raid_disks);
 
+	if (!discard_supported)
+		queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
+	else
+		queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
+
 	pr_debug("md/raid0:%s: done.\n", mdname(mddev));
 	*private_conf = conf;
 
@@ -422,6 +431,7 @@ static int raid0_run(struct mddev *mddev)
 	if (md_check_no_bitmap(mddev))
 		return -EINVAL;
 	blk_queue_max_hw_sectors(mddev->queue, mddev->chunk_sectors);
+	blk_queue_max_discard_sectors(mddev->queue, mddev->chunk_sectors);
 
 	/* if private is not null, we are here after takeover */
 	if (mddev->private == NULL) {
@@ -509,7 +519,7 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio)
 		sector_t sector = bio->bi_sector;
 		struct bio_pair *bp;
 		/* Sanity check -- queue functions should prevent this happening */
-		if (bio->bi_vcnt != 1 ||
+		if ((bio->bi_vcnt != 1 && bio->bi_vcnt != 0) ||
 		    bio->bi_idx != 0)
 			goto bad_map;
 		/* This is a one page bio that upper layers
@@ -535,6 +545,13 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio)
 	bio->bi_sector = sector_offset + zone->dev_start +
 		tmp_dev->data_offset;
 
+	if (unlikely((bio->bi_rw & REQ_DISCARD) &&
+		     !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) {
+		/* Just ignore it */
+		bio_endio(bio, 0);
+		return;
+	}
+
 	generic_make_request(bio);
 	return;
 
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 611b5f7..3092afe 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -781,7 +781,12 @@ static void flush_pending_writes(struct r1conf *conf)
 		while (bio) { /* submit pending writes */
 			struct bio *next = bio->bi_next;
 			bio->bi_next = NULL;
-			generic_make_request(bio);
+			if (unlikely((bio->bi_rw & REQ_DISCARD) &&
+			    !blk_queue_discard(bdev_get_queue(bio->bi_bdev))))
+				/* Just ignore it */
+				bio_endio(bio, 0);
+			else
+				generic_make_request(bio);
 			bio = next;
 		}
 	} else
@@ -994,6 +999,7 @@ static void make_request(struct mddev *mddev, struct bio * bio)
 	const int rw = bio_data_dir(bio);
 	const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
 	const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA));
+	const unsigned long do_discard = (bio->bi_rw & (REQ_DISCARD | REQ_SECURE));
 	struct md_rdev *blocked_rdev;
 	struct blk_plug_cb *cb;
 	struct raid1_plug_cb *plug = NULL;
@@ -1295,7 +1301,7 @@ read_again:
 				   conf->mirrors[i].rdev->data_offset);
 		mbio->bi_bdev = conf->mirrors[i].rdev->bdev;
 		mbio->bi_end_io	= raid1_end_write_request;
-		mbio->bi_rw = WRITE | do_flush_fua | do_sync;
+		mbio->bi_rw = WRITE | do_flush_fua | do_sync | do_discard;
 		mbio->bi_private = r1_bio;
 
 		atomic_inc(&r1_bio->remaining);
@@ -1549,6 +1555,8 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)
 		clear_bit(Unmerged, &rdev->flags);
 	}
 	md_integrity_add_rdev(rdev, mddev);
+	if (blk_queue_discard(bdev_get_queue(rdev->bdev)))
+		queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
 	print_conf(conf);
 	return err;
 }
@@ -2285,8 +2293,9 @@ read_more:
 	}
 }
 
-static void raid1d(struct mddev *mddev)
+static void raid1d(struct md_thread *thread)
 {
+	struct mddev *mddev = thread->mddev;
 	struct r1bio *r1_bio;
 	unsigned long flags;
 	struct r1conf *conf = mddev->private;
@@ -2783,6 +2792,7 @@ static int run(struct mddev *mddev)
 	int i;
 	struct md_rdev *rdev;
 	int ret;
+	bool discard_supported = false;
 
 	if (mddev->level != 1) {
 		printk(KERN_ERR "md/raid1:%s: raid level not set to mirroring (%d)\n",
@@ -2812,6 +2822,8 @@ static int run(struct mddev *mddev)
 			continue;
 		disk_stack_limits(mddev->gendisk, rdev->bdev,
 				  rdev->data_offset << 9);
+		if (blk_queue_discard(bdev_get_queue(rdev->bdev)))
+			discard_supported = true;
 	}
 
 	mddev->degraded = 0;
@@ -2846,6 +2858,11 @@ static int run(struct mddev *mddev)
 		mddev->queue->backing_dev_info.congested_fn = raid1_congested;
 		mddev->queue->backing_dev_info.congested_data = mddev;
 		blk_queue_merge_bvec(mddev->queue, raid1_mergeable_bvec);
+
+		if (discard_supported)
+			queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
+		else
+			queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
 	}
 
 	ret =  md_integrity_register(mddev);
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index de5ed6f..13ffd82 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -659,7 +659,11 @@ static int raid10_mergeable_bvec(struct request_queue *q,
 		max = biovec->bv_len;
 
 	if (mddev->merge_check_needed) {
-		struct r10bio r10_bio;
+		struct {
+			struct r10bio r10_bio;
+			struct r10dev devs[conf->copies];
+		} on_stack;
+		struct r10bio *r10_bio = &on_stack.r10_bio;
 		int s;
 		if (conf->reshape_progress != MaxSector) {
 			/* Cannot give any guidance during reshape */
@@ -667,18 +671,18 @@ static int raid10_mergeable_bvec(struct request_queue *q,
 				return biovec->bv_len;
 			return 0;
 		}
-		r10_bio.sector = sector;
-		raid10_find_phys(conf, &r10_bio);
+		r10_bio->sector = sector;
+		raid10_find_phys(conf, r10_bio);
 		rcu_read_lock();
 		for (s = 0; s < conf->copies; s++) {
-			int disk = r10_bio.devs[s].devnum;
+			int disk = r10_bio->devs[s].devnum;
 			struct md_rdev *rdev = rcu_dereference(
 				conf->mirrors[disk].rdev);
 			if (rdev && !test_bit(Faulty, &rdev->flags)) {
 				struct request_queue *q =
 					bdev_get_queue(rdev->bdev);
 				if (q->merge_bvec_fn) {
-					bvm->bi_sector = r10_bio.devs[s].addr
+					bvm->bi_sector = r10_bio->devs[s].addr
 						+ rdev->data_offset;
 					bvm->bi_bdev = rdev->bdev;
 					max = min(max, q->merge_bvec_fn(
@@ -690,7 +694,7 @@ static int raid10_mergeable_bvec(struct request_queue *q,
 				struct request_queue *q =
 					bdev_get_queue(rdev->bdev);
 				if (q->merge_bvec_fn) {
-					bvm->bi_sector = r10_bio.devs[s].addr
+					bvm->bi_sector = r10_bio->devs[s].addr
 						+ rdev->data_offset;
 					bvm->bi_bdev = rdev->bdev;
 					max = min(max, q->merge_bvec_fn(
@@ -907,7 +911,12 @@ static void flush_pending_writes(struct r10conf *conf)
 		while (bio) { /* submit pending writes */
 			struct bio *next = bio->bi_next;
 			bio->bi_next = NULL;
-			generic_make_request(bio);
+			if (unlikely((bio->bi_rw & REQ_DISCARD) &&
+			    !blk_queue_discard(bdev_get_queue(bio->bi_bdev))))
+				/* Just ignore it */
+				bio_endio(bio, 0);
+			else
+				generic_make_request(bio);
 			bio = next;
 		}
 	} else
@@ -1057,6 +1066,7 @@ static void make_request(struct mddev *mddev, struct bio * bio)
 	const int rw = bio_data_dir(bio);
 	const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
 	const unsigned long do_fua = (bio->bi_rw & REQ_FUA);
+	const unsigned long do_discard = (bio->bi_rw & (REQ_DISCARD | REQ_SECURE));
 	unsigned long flags;
 	struct md_rdev *blocked_rdev;
 	int sectors_handled;
@@ -1077,7 +1087,7 @@ static void make_request(struct mddev *mddev, struct bio * bio)
 			 || conf->prev.near_copies < conf->prev.raid_disks))) {
 		struct bio_pair *bp;
 		/* Sanity check -- queue functions should prevent this happening */
-		if (bio->bi_vcnt != 1 ||
+		if ((bio->bi_vcnt != 1 && bio->bi_vcnt !=0) ||
 		    bio->bi_idx != 0)
 			goto bad_map;
 		/* This is a one page bio that upper layers
@@ -1406,7 +1416,7 @@ retry_write:
 						      conf->mirrors[d].rdev));
 		mbio->bi_bdev = conf->mirrors[d].rdev->bdev;
 		mbio->bi_end_io	= raid10_end_write_request;
-		mbio->bi_rw = WRITE | do_sync | do_fua;
+		mbio->bi_rw = WRITE | do_sync | do_fua | do_discard;
 		mbio->bi_private = r10_bio;
 
 		atomic_inc(&r10_bio->remaining);
@@ -1435,7 +1445,7 @@ retry_write:
 					   conf->mirrors[d].replacement));
 		mbio->bi_bdev = conf->mirrors[d].replacement->bdev;
 		mbio->bi_end_io	= raid10_end_write_request;
-		mbio->bi_rw = WRITE | do_sync | do_fua;
+		mbio->bi_rw = WRITE | do_sync | do_fua | do_discard;
 		mbio->bi_private = r10_bio;
 
 		atomic_inc(&r10_bio->remaining);
@@ -1719,6 +1729,9 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
 		clear_bit(Unmerged, &rdev->flags);
 	}
 	md_integrity_add_rdev(rdev, mddev);
+	if (blk_queue_discard(bdev_get_queue(rdev->bdev)))
+		queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
+
 	print_conf(conf);
 	return err;
 }
@@ -2667,8 +2680,9 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
 	}
 }
 
-static void raid10d(struct mddev *mddev)
+static void raid10d(struct md_thread *thread)
 {
+	struct mddev *mddev = thread->mddev;
 	struct r10bio *r10_bio;
 	unsigned long flags;
 	struct r10conf *conf = mddev->private;
@@ -3476,6 +3490,7 @@ static int run(struct mddev *mddev)
 	sector_t size;
 	sector_t min_offset_diff = 0;
 	int first = 1;
+	bool discard_supported = false;
 
 	if (mddev->private == NULL) {
 		conf = setup_conf(mddev);
@@ -3492,6 +3507,7 @@ static int run(struct mddev *mddev)
 
 	chunk_size = mddev->chunk_sectors << 9;
 	if (mddev->queue) {
+		blk_queue_max_discard_sectors(mddev->queue, mddev->chunk_sectors);
 		blk_queue_io_min(mddev->queue, chunk_size);
 		if (conf->geo.raid_disks % conf->geo.near_copies)
 			blk_queue_io_opt(mddev->queue, chunk_size * conf->geo.raid_disks);
@@ -3537,8 +3553,16 @@ static int run(struct mddev *mddev)
 					  rdev->data_offset << 9);
 
 		disk->head_position = 0;
+
+		if (blk_queue_discard(bdev_get_queue(rdev->bdev)))
+			discard_supported = true;
 	}
 
+	if (discard_supported)
+		queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
+	else
+		queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
+
 	/* need to check that every block has at least one working mirror */
 	if (!enough(conf, -1)) {
 		printk(KERN_ERR "md/raid10:%s: not enough operational mirrors.\n",
@@ -4414,14 +4438,18 @@ static int handle_reshape_read_error(struct mddev *mddev,
 {
 	/* Use sync reads to get the blocks from somewhere else */
 	int sectors = r10_bio->sectors;
-	struct r10bio r10b;
 	struct r10conf *conf = mddev->private;
+	struct {
+		struct r10bio r10_bio;
+		struct r10dev devs[conf->copies];
+	} on_stack;
+	struct r10bio *r10b = &on_stack.r10_bio;
 	int slot = 0;
 	int idx = 0;
 	struct bio_vec *bvec = r10_bio->master_bio->bi_io_vec;
 
-	r10b.sector = r10_bio->sector;
-	__raid10_find_phys(&conf->prev, &r10b);
+	r10b->sector = r10_bio->sector;
+	__raid10_find_phys(&conf->prev, r10b);
 
 	while (sectors) {
 		int s = sectors;
@@ -4432,7 +4460,7 @@ static int handle_reshape_read_error(struct mddev *mddev,
 			s = PAGE_SIZE >> 9;
 
 		while (!success) {
-			int d = r10b.devs[slot].devnum;
+			int d = r10b->devs[slot].devnum;
 			struct md_rdev *rdev = conf->mirrors[d].rdev;
 			sector_t addr;
 			if (rdev == NULL ||
@@ -4440,7 +4468,7 @@ static int handle_reshape_read_error(struct mddev *mddev,
 			    !test_bit(In_sync, &rdev->flags))
 				goto failed;
 
-			addr = r10b.devs[slot].addr + idx * PAGE_SIZE;
+			addr = r10b->devs[slot].addr + idx * PAGE_SIZE;
 			success = sync_page_io(rdev,
 					       addr,
 					       s << 9,
diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h
index 007c2c6..1054cf6 100644
--- a/drivers/md/raid10.h
+++ b/drivers/md/raid10.h
@@ -110,7 +110,7 @@ struct r10bio {
 	 * We choose the number when they are allocated.
 	 * We sometimes need an extra bio to write to the replacement.
 	 */
-	struct {
+	struct r10dev {
 		struct bio	*bio;
 		union {
 			struct bio	*repl_bio; /* used for resync and
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index adda94d..7c8151a 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -196,6 +196,21 @@ static int stripe_operations_active(struct stripe_head *sh)
 	       test_bit(STRIPE_COMPUTE_RUN, &sh->state);
 }
 
+static void raid5_wakeup_stripe_thread(struct stripe_head *sh)
+{
+	struct r5conf *conf = sh->raid_conf;
+	struct raid5_percpu *percpu;
+	int i, orphaned = 1;
+
+	percpu = per_cpu_ptr(conf->percpu, sh->cpu);
+	for_each_cpu(i, &percpu->handle_threads) {
+		md_wakeup_thread(conf->aux_threads[i]->thread);
+		orphaned = 0;
+	}
+	if (orphaned)
+		md_wakeup_thread(conf->mddev->thread);
+}
+
 static void do_release_stripe(struct r5conf *conf, struct stripe_head *sh)
 {
 	BUG_ON(!list_empty(&sh->lru));
@@ -208,9 +223,19 @@ static void do_release_stripe(struct r5conf *conf, struct stripe_head *sh)
 			   sh->bm_seq - conf->seq_write > 0)
 			list_add_tail(&sh->lru, &conf->bitmap_list);
 		else {
+			int cpu = sh->cpu;
+			struct raid5_percpu *percpu;
+			if (!cpu_online(cpu)) {
+				cpu = cpumask_any(cpu_online_mask);
+				sh->cpu = cpu;
+			}
+			percpu = per_cpu_ptr(conf->percpu, cpu);
+
 			clear_bit(STRIPE_DELAYED, &sh->state);
 			clear_bit(STRIPE_BIT_DELAY, &sh->state);
-			list_add_tail(&sh->lru, &conf->handle_list);
+			list_add_tail(&sh->lru, &percpu->handle_list);
+			raid5_wakeup_stripe_thread(sh);
+			return;
 		}
 		md_wakeup_thread(conf->mddev->thread);
 	} else {
@@ -355,6 +380,7 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int previous)
 		raid5_build_block(sh, i, previous);
 	}
 	insert_hash(conf, sh);
+	sh->cpu = smp_processor_id();
 }
 
 static struct stripe_head *__find_stripe(struct r5conf *conf, sector_t sector,
@@ -3689,12 +3715,19 @@ static void raid5_activate_delayed(struct r5conf *conf)
 		while (!list_empty(&conf->delayed_list)) {
 			struct list_head *l = conf->delayed_list.next;
 			struct stripe_head *sh;
+			int cpu;
 			sh = list_entry(l, struct stripe_head, lru);
 			list_del_init(l);
 			clear_bit(STRIPE_DELAYED, &sh->state);
 			if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
 				atomic_inc(&conf->preread_active_stripes);
 			list_add_tail(&sh->lru, &conf->hold_list);
+			cpu = sh->cpu;
+			if (!cpu_online(cpu)) {
+				cpu = cpumask_any(cpu_online_mask);
+				sh->cpu = cpu;
+			}
+			raid5_wakeup_stripe_thread(sh);
 		}
 	}
 }
@@ -3968,18 +4001,29 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio)
  * head of the hold_list has changed, i.e. the head was promoted to the
  * handle_list.
  */
-static struct stripe_head *__get_priority_stripe(struct r5conf *conf)
-{
-	struct stripe_head *sh;
-
+static struct stripe_head *__get_priority_stripe(struct r5conf *conf,
+	cpumask_t *mask)
+{
+	struct stripe_head *sh = NULL, *tmp;
+	struct list_head *handle_list = NULL;
+	int cpu;
+
+	/* Should we take action to avoid starvation of latter CPUs ? */
+	for_each_cpu(cpu, mask) {
+		struct raid5_percpu *percpu = per_cpu_ptr(conf->percpu, cpu);
+		if (!list_empty(&percpu->handle_list)) {
+			handle_list = &percpu->handle_list;
+			break;
+		}
+	}
 	pr_debug("%s: handle: %s hold: %s full_writes: %d bypass_count: %d\n",
 		  __func__,
-		  list_empty(&conf->handle_list) ? "empty" : "busy",
+		  !handle_list ? "empty" : "busy",
 		  list_empty(&conf->hold_list) ? "empty" : "busy",
 		  atomic_read(&conf->pending_full_writes), conf->bypass_count);
 
-	if (!list_empty(&conf->handle_list)) {
-		sh = list_entry(conf->handle_list.next, typeof(*sh), lru);
+	if (handle_list) {
+		sh = list_entry(handle_list->next, typeof(*sh), lru);
 
 		if (list_empty(&conf->hold_list))
 			conf->bypass_count = 0;
@@ -3997,12 +4041,23 @@ static struct stripe_head *__get_priority_stripe(struct r5conf *conf)
 		   ((conf->bypass_threshold &&
 		     conf->bypass_count > conf->bypass_threshold) ||
 		    atomic_read(&conf->pending_full_writes) == 0)) {
-		sh = list_entry(conf->hold_list.next,
-				typeof(*sh), lru);
-		conf->bypass_count -= conf->bypass_threshold;
-		if (conf->bypass_count < 0)
-			conf->bypass_count = 0;
-	} else
+
+		list_for_each_entry(tmp, &conf->hold_list,  lru) {
+			if (cpumask_test_cpu(tmp->cpu, mask) ||
+			    !cpu_online(tmp->cpu)) {
+				sh = tmp;
+				break;
+			}
+		}
+
+		if (sh) {
+			conf->bypass_count -= conf->bypass_threshold;
+			if (conf->bypass_count < 0)
+				conf->bypass_count = 0;
+		}
+	}
+
+	if (!sh)
 		return NULL;
 
 	list_del_init(&sh->lru);
@@ -4594,13 +4649,13 @@ static int  retry_aligned_read(struct r5conf *conf, struct bio *raid_bio)
 }
 
 #define MAX_STRIPE_BATCH 8
-static int handle_active_stripes(struct r5conf *conf)
+static int handle_active_stripes(struct r5conf *conf, cpumask_t *mask)
 {
 	struct stripe_head *batch[MAX_STRIPE_BATCH], *sh;
 	int i, batch_size = 0;
 
 	while (batch_size < MAX_STRIPE_BATCH &&
-			(sh = __get_priority_stripe(conf)) != NULL)
+			(sh = __get_priority_stripe(conf, mask)) != NULL)
 		batch[batch_size++] = sh;
 
 	if (batch_size == 0)
@@ -4618,6 +4673,35 @@ static int handle_active_stripes(struct r5conf *conf)
 	return batch_size;
 }
 
+static void raid5auxd(struct md_thread *thread)
+{
+	struct mddev *mddev = thread->mddev;
+	struct r5conf *conf = mddev->private;
+	struct blk_plug plug;
+	int handled;
+	struct raid5_auxth *auxth = thread->private;
+
+	pr_debug("+++ raid5auxd active\n");
+
+	blk_start_plug(&plug);
+	handled = 0;
+	spin_lock_irq(&conf->device_lock);
+	while (1) {
+		int batch_size;
+
+		batch_size = handle_active_stripes(conf, &auxth->work_mask);
+		if (!batch_size)
+			break;
+		handled += batch_size;
+	}
+	pr_debug("%d stripes handled\n", handled);
+
+	spin_unlock_irq(&conf->device_lock);
+	blk_finish_plug(&plug);
+
+	pr_debug("--- raid5auxd inactive\n");
+}
+
 /*
  * This is our raid5 kernel thread.
  *
@@ -4625,8 +4709,9 @@ static int handle_active_stripes(struct r5conf *conf)
  * During the scan, completed stripes are saved for us by the interrupt
  * handler, so that they will not have to wait for our next wakeup.
  */
-static void raid5d(struct mddev *mddev)
+static void raid5d(struct md_thread *thread)
 {
+	struct mddev *mddev = thread->mddev;
 	struct r5conf *conf = mddev->private;
 	int handled;
 	struct blk_plug plug;
@@ -4664,7 +4749,7 @@ static void raid5d(struct mddev *mddev)
 			handled++;
 		}
 
-		batch_size = handle_active_stripes(conf);
+		batch_size = handle_active_stripes(conf, &conf->work_mask);
 		if (!batch_size)
 			break;
 		handled += batch_size;
@@ -4793,10 +4878,270 @@ stripe_cache_active_show(struct mddev *mddev, char *page)
 static struct md_sysfs_entry
 raid5_stripecache_active = __ATTR_RO(stripe_cache_active);
 
+static void raid5_update_threads_handle_mask(struct mddev *mddev)
+{
+	int cpu, i;
+	struct raid5_percpu *percpu;
+	struct r5conf *conf = mddev->private;
+
+	for_each_online_cpu(cpu) {
+		percpu = per_cpu_ptr(conf->percpu, cpu);
+		cpumask_clear(&percpu->handle_threads);
+	}
+	cpumask_copy(&conf->work_mask, cpu_online_mask);
+
+	for (i = 0; i < conf->aux_thread_num; i++) {
+		cpumask_t *work_mask = &conf->aux_threads[i]->work_mask;
+		for_each_cpu(cpu, work_mask) {
+			percpu = per_cpu_ptr(conf->percpu, cpu);
+			cpumask_set_cpu(i, &percpu->handle_threads);
+		}
+		cpumask_andnot(&conf->work_mask, &conf->work_mask,
+				work_mask);
+	}
+}
+
+struct raid5_auxth_sysfs {
+	struct attribute attr;
+	ssize_t (*show)(struct mddev *, struct raid5_auxth *, char *);
+	ssize_t (*store)(struct mddev *, struct raid5_auxth *,
+		const char *, size_t);
+};
+
+static ssize_t raid5_show_thread_cpulist(struct mddev *mddev,
+	struct raid5_auxth *thread, char *page)
+{
+	if (!mddev->private)
+		return 0;
+	return cpulist_scnprintf(page, PAGE_SIZE, &thread->work_mask);
+}
+
+static ssize_t
+raid5_store_thread_cpulist(struct mddev *mddev, struct raid5_auxth *thread,
+	const char *page, size_t len)
+{
+	struct r5conf *conf = mddev->private;
+	cpumask_var_t mask;
+
+	if (!conf)
+		return -ENODEV;
+	if (!alloc_cpumask_var(&mask, GFP_KERNEL))
+		return -ENOMEM;
+
+	if (cpulist_parse(page, mask)) {
+		free_cpumask_var(mask);
+		return -EINVAL;
+	}
+
+	get_online_cpus();
+	spin_lock_irq(&conf->device_lock);
+	cpumask_copy(&thread->work_mask, mask);
+	raid5_update_threads_handle_mask(mddev);
+	spin_unlock_irq(&conf->device_lock);
+	put_online_cpus();
+	set_cpus_allowed_ptr(thread->thread->tsk, mask);
+
+	free_cpumask_var(mask);
+	return len;
+}
+
+static struct raid5_auxth_sysfs thread_cpulist =
+__ATTR(cpulist, S_IRUGO|S_IWUSR, raid5_show_thread_cpulist,
+	raid5_store_thread_cpulist);
+
+static struct attribute *auxth_attrs[] = {
+	&thread_cpulist.attr,
+	NULL,
+};
+
+static ssize_t
+raid5_auxth_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
+{
+	struct raid5_auxth_sysfs *entry = container_of(attr,
+		struct raid5_auxth_sysfs, attr);
+	struct raid5_auxth *thread = container_of(kobj,
+		struct raid5_auxth, kobj);
+	struct mddev *mddev = thread->thread->mddev;
+	ssize_t ret;
+
+	if (!entry->show)
+		return -EIO;
+	mddev_lock(mddev);
+	ret = entry->show(mddev, thread, page);
+	mddev_unlock(mddev);
+	return ret;
+}
+
+static ssize_t
+raid5_auxth_attr_store(struct kobject *kobj, struct attribute *attr,
+	      const char *page, size_t length)
+{
+	struct raid5_auxth_sysfs *entry = container_of(attr,
+		struct raid5_auxth_sysfs, attr);
+	struct raid5_auxth *thread = container_of(kobj,
+		struct raid5_auxth, kobj);
+	struct mddev *mddev = thread->thread->mddev;
+	ssize_t ret;
+
+	if (!entry->store)
+		return -EIO;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	mddev_lock(mddev);
+	ret = entry->store(mddev, thread, page, length);
+	mddev_unlock(mddev);
+	return ret;
+}
+
+static void raid5_auxth_release(struct kobject *kobj)
+{
+	struct raid5_auxth *thread = container_of(kobj,
+		struct raid5_auxth, kobj);
+	kfree(thread);
+}
+
+static const struct sysfs_ops raid5_auxth_sysfsops = {
+	.show = raid5_auxth_attr_show,
+	.store = raid5_auxth_attr_store,
+};
+static struct kobj_type raid5_auxth_ktype = {
+	.release = raid5_auxth_release,
+	.sysfs_ops = &raid5_auxth_sysfsops,
+	.default_attrs = auxth_attrs,
+};
+
+static ssize_t
+raid5_show_auxthread_number(struct mddev *mddev, char *page)
+{
+	struct r5conf *conf = mddev->private;
+	if (conf)
+		return sprintf(page, "%d\n", conf->aux_thread_num);
+	else
+		return 0;
+}
+
+static void raid5_auxth_delete(struct work_struct *ws)
+{
+	struct raid5_auxth *thread = container_of(ws, struct raid5_auxth,
+		del_work);
+
+	kobject_del(&thread->kobj);
+	kobject_put(&thread->kobj);
+}
+
+static void __free_aux_thread(struct mddev *mddev, struct raid5_auxth *thread)
+{
+	md_unregister_thread(&thread->thread);
+	INIT_WORK(&thread->del_work, raid5_auxth_delete);
+	kobject_get(&thread->kobj);
+	md_queue_misc_work(&thread->del_work);
+}
+
+static struct raid5_auxth *__create_aux_thread(struct mddev *mddev, int i)
+{
+	struct raid5_auxth *thread;
+	char name[10];
+
+	thread = kzalloc(sizeof(*thread), GFP_KERNEL);
+	if (!thread)
+		return NULL;
+	snprintf(name, 10, "aux%d", i);
+	thread->thread = md_register_thread(raid5auxd, mddev, name);
+	if (!thread->thread) {
+		kfree(thread);
+		return NULL;
+	}
+	thread->thread->private = thread;
+
+	cpumask_copy(&thread->work_mask, cpu_online_mask);
+
+	if (kobject_init_and_add(&thread->kobj, &raid5_auxth_ktype,
+	    &mddev->kobj, "auxth%d", i)) {
+		md_unregister_thread(&thread->thread);
+		kfree(thread);
+		return NULL;
+	}
+	return thread;
+}
+
+static ssize_t
+raid5_store_auxthread_number(struct mddev *mddev, const char *page, size_t len)
+{
+	struct r5conf *conf = mddev->private;
+	unsigned long new;
+	int i;
+	struct raid5_auxth **threads;
+
+	if (len >= PAGE_SIZE)
+		return -EINVAL;
+	if (!conf)
+		return -ENODEV;
+
+	if (kstrtoul(page, 10, &new))
+		return -EINVAL;
+
+	if (new == conf->aux_thread_num)
+		return len;
+
+	/* There is no point creating more threads than cpu number */
+	if (new > num_online_cpus())
+		return -EINVAL;
+
+	if (new > conf->aux_thread_num) {
+		threads = kzalloc(sizeof(struct raid5_auxth *) * new,
+				GFP_KERNEL);
+		if (!threads)
+			return -ENOMEM;
+
+		i = conf->aux_thread_num;
+		while (i < new) {
+			threads[i] = __create_aux_thread(mddev, i);
+			if (!threads[i])
+				goto error;
+
+			i++;
+		}
+		memcpy(threads, conf->aux_threads,
+			sizeof(struct raid5_auxth *) * conf->aux_thread_num);
+		get_online_cpus();
+		spin_lock_irq(&conf->device_lock);
+		kfree(conf->aux_threads);
+		conf->aux_threads = threads;
+		conf->aux_thread_num = new;
+		raid5_update_threads_handle_mask(mddev);
+		spin_unlock_irq(&conf->device_lock);
+		put_online_cpus();
+	} else {
+		int old = conf->aux_thread_num;
+
+		get_online_cpus();
+		spin_lock_irq(&conf->device_lock);
+		conf->aux_thread_num = new;
+		raid5_update_threads_handle_mask(mddev);
+		spin_unlock_irq(&conf->device_lock);
+		put_online_cpus();
+		for (i = new; i < old; i++)
+			__free_aux_thread(mddev, conf->aux_threads[i]);
+	}
+
+	return len;
+error:
+	while (--i >= conf->aux_thread_num)
+		__free_aux_thread(mddev, threads[i]);
+	kfree(threads);
+	return -ENOMEM;
+}
+
+static struct md_sysfs_entry
+raid5_auxthread_number = __ATTR(auxthread_number, S_IRUGO|S_IWUSR,
+				raid5_show_auxthread_number,
+				raid5_store_auxthread_number);
+
 static struct attribute *raid5_attrs[] =  {
 	&raid5_stripecache_size.attr,
 	&raid5_stripecache_active.attr,
 	&raid5_preread_bypass_threshold.attr,
+	&raid5_auxthread_number.attr,
 	NULL,
 };
 static struct attribute_group raid5_attrs_group = {
@@ -4844,6 +5189,7 @@ static void raid5_free_percpu(struct r5conf *conf)
 
 static void free_conf(struct r5conf *conf)
 {
+	kfree(conf->aux_threads);
 	shrink_stripes(conf);
 	raid5_free_percpu(conf);
 	kfree(conf->disks);
@@ -4856,7 +5202,7 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
 			      void *hcpu)
 {
 	struct r5conf *conf = container_of(nfb, struct r5conf, cpu_notify);
-	long cpu = (long)hcpu;
+	long cpu = (long)hcpu, anycpu;
 	struct raid5_percpu *percpu = per_cpu_ptr(conf->percpu, cpu);
 
 	switch (action) {
@@ -4875,9 +5221,17 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
 			       __func__, cpu);
 			return notifier_from_errno(-ENOMEM);
 		}
+		INIT_LIST_HEAD(&(percpu->handle_list));
+		cpumask_clear(&percpu->handle_threads);
 		break;
 	case CPU_DEAD:
 	case CPU_DEAD_FROZEN:
+		spin_lock_irq(&conf->device_lock);
+		anycpu = cpumask_any(cpu_online_mask);
+		list_splice_tail_init(&percpu->handle_list,
+			&per_cpu_ptr(conf->percpu, anycpu)->handle_list);
+		spin_unlock_irq(&conf->device_lock);
+
 		safe_put_page(percpu->spare_page);
 		kfree(percpu->scribble);
 		percpu->spare_page = NULL;
@@ -4886,6 +5240,10 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
 	default:
 		break;
 	}
+
+	spin_lock_irq(&conf->device_lock);
+	raid5_update_threads_handle_mask(conf->mddev);
+	spin_unlock_irq(&conf->device_lock);
 	return NOTIFY_OK;
 }
 #endif
@@ -4906,20 +5264,24 @@ static int raid5_alloc_percpu(struct r5conf *conf)
 	get_online_cpus();
 	err = 0;
 	for_each_present_cpu(cpu) {
+		struct raid5_percpu *percpu = per_cpu_ptr(conf->percpu, cpu);
+
 		if (conf->level == 6) {
 			spare_page = alloc_page(GFP_KERNEL);
 			if (!spare_page) {
 				err = -ENOMEM;
 				break;
 			}
-			per_cpu_ptr(conf->percpu, cpu)->spare_page = spare_page;
+			percpu->spare_page = spare_page;
 		}
 		scribble = kmalloc(conf->scribble_len, GFP_KERNEL);
 		if (!scribble) {
 			err = -ENOMEM;
 			break;
 		}
-		per_cpu_ptr(conf->percpu, cpu)->scribble = scribble;
+		percpu->scribble = scribble;
+		INIT_LIST_HEAD(&percpu->handle_list);
+		cpumask_clear(&percpu->handle_threads);
 	}
 #ifdef CONFIG_HOTPLUG_CPU
 	conf->cpu_notify.notifier_call = raid456_cpu_notify;
@@ -4975,7 +5337,6 @@ static struct r5conf *setup_conf(struct mddev *mddev)
 	spin_lock_init(&conf->device_lock);
 	init_waitqueue_head(&conf->wait_for_stripe);
 	init_waitqueue_head(&conf->wait_for_overlap);
-	INIT_LIST_HEAD(&conf->handle_list);
 	INIT_LIST_HEAD(&conf->hold_list);
 	INIT_LIST_HEAD(&conf->delayed_list);
 	INIT_LIST_HEAD(&conf->bitmap_list);
@@ -4986,6 +5347,8 @@ static struct r5conf *setup_conf(struct mddev *mddev)
 	conf->bypass_threshold = BYPASS_THRESHOLD;
 	conf->recovery_disabled = mddev->recovery_disabled - 1;
 
+	cpumask_copy(&conf->work_mask, cpu_online_mask);
+
 	conf->raid_disks = mddev->raid_disks;
 	if (mddev->reshape_position == MaxSector)
 		conf->previous_raid_disks = mddev->raid_disks;
@@ -5402,6 +5765,10 @@ abort:
 static int stop(struct mddev *mddev)
 {
 	struct r5conf *conf = mddev->private;
+	int i;
+
+	for (i = 0; i < conf->aux_thread_num; i++)
+		__free_aux_thread(mddev, conf->aux_threads[i]);
 
 	md_unregister_thread(&mddev->thread);
 	if (mddev->queue)
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
index a9fc249..813b6c1 100644
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -211,6 +211,7 @@ struct stripe_head {
 	enum check_states	check_state;
 	enum reconstruct_states reconstruct_state;
 	spinlock_t		stripe_lock;
+	int			cpu;
 	/**
 	 * struct stripe_operations
 	 * @target - STRIPE_OP_COMPUTE_BLK target
@@ -364,6 +365,14 @@ struct disk_info {
 	struct md_rdev	*rdev, *replacement;
 };
 
+struct raid5_auxth {
+	struct md_thread	*thread;
+	/* which CPUs should the auxiliary thread handle stripes from */
+	cpumask_t		work_mask;
+	struct kobject		kobj;
+	struct work_struct	del_work;
+};
+
 struct r5conf {
 	struct hlist_head	*stripe_hashtbl;
 	struct mddev		*mddev;
@@ -432,6 +441,12 @@ struct r5conf {
 					      * lists and performing address
 					      * conversions
 					      */
+		struct list_head handle_list;
+		cpumask_t	handle_threads; /* Which threads can the CPU's
+						 * stripes be handled. It really
+						 * is a bitmap to aux_threads[],
+						 * but has max bits NR_CPUS
+						 */
 	} __percpu *percpu;
 	size_t			scribble_len; /* size of scribble region must be
 					       * associated with conf to handle
@@ -459,6 +474,10 @@ struct r5conf {
 	 * the new thread here until we fully activate the array.
 	 */
 	struct md_thread	*thread;
+	int			aux_thread_num;
+	struct raid5_auxth	**aux_threads;
+	/* which CPUs should raid5d thread handle stripes from */
+	cpumask_t		work_mask;
 };
 
 /*
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index d941581..dcaaf8e 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -113,6 +113,8 @@ config VIDEO_V4L2_SUBDEV_API
 
 	  This API is mostly used by camera interfaces in embedded platforms.
 
+source "drivers/media/v4l2-core/Kconfig"
+
 #
 # DVB Core
 #	Only enables if one of DTV is selected
@@ -138,28 +140,40 @@ config DVB_NET
 	  You may want to disable the network support on embedded devices. If
 	  unsure say Y.
 
+source "drivers/media/dvb-core/Kconfig"
+
 comment "Media drivers"
-source "drivers/media/common/Kconfig"
 source "drivers/media/rc/Kconfig"
 
 #
 # Tuner drivers for DVB and V4L
 #
 
-source "drivers/media/common/tuners/Kconfig"
+source "drivers/media/tuners/Kconfig"
+
+source "drivers/media/i2c/Kconfig"
 
 #
-# Video/Radio/Hybrid adapters
+# V4L platform/mem2mem drivers
 #
-
-source "drivers/media/video/Kconfig"
+source "drivers/media/platform/Kconfig"
 
 source "drivers/media/radio/Kconfig"
 
-#
-# DVB adapters
-#
+source "drivers/media/pci/Kconfig"
+source "drivers/media/usb/Kconfig"
+source "drivers/media/mmc/Kconfig"
+source "drivers/media/parport/Kconfig"
+
+comment "Supported FireWire (IEEE 1394) Adapters"
+	depends on DVB_CORE && FIREWIRE
+source "drivers/media/firewire/Kconfig"
 
-source "drivers/media/dvb/Kconfig"
+comment "Supported DVB Frontends"
+	depends on DVB_CORE
+source "drivers/media/dvb-frontends/Kconfig"
+
+# Common drivers
+source "drivers/media/common/Kconfig"
 
 endif # MEDIA_SUPPORT
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index 64755c9..b0b0193 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -8,7 +8,8 @@ ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
   obj-$(CONFIG_MEDIA_SUPPORT) += media.o
 endif
 
-obj-y += common/ rc/ video/
+obj-y += tuners/ common/ rc/ platform/
+obj-y += i2c/ pci/ usb/ mmc/ firewire/ parport/
 
-obj-$(CONFIG_VIDEO_DEV) += radio/
-obj-$(CONFIG_DVB_CORE)  += dvb/
+obj-$(CONFIG_VIDEO_DEV) += radio/ v4l2-core/
+obj-$(CONFIG_DVB_CORE)  += dvb-core/ dvb-frontends/
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index 769c6f8..121b011 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -1,9 +1,3 @@
-config VIDEO_SAA7146
-	tristate
-	depends on I2C && PCI
-
-config VIDEO_SAA7146_VV
-	tristate
-	depends on VIDEO_V4L2
-	select VIDEOBUF_DMA_SG
-	select VIDEO_SAA7146
+source "drivers/media/common/b2c2/Kconfig"
+source "drivers/media/common/saa7146/Kconfig"
+source "drivers/media/common/siano/Kconfig"
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index e3ec963..b8e2e3a 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -1,6 +1 @@
-saa7146-objs    := saa7146_i2c.o saa7146_core.o
-saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
-
-obj-y += tuners/
-obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
-obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o
+obj-y += b2c2/ saa7146/ siano/
diff --git a/drivers/media/common/b2c2/Kconfig b/drivers/media/common/b2c2/Kconfig
new file mode 100644
index 0000000..e270dd8
--- /dev/null
+++ b/drivers/media/common/b2c2/Kconfig
@@ -0,0 +1,31 @@
+config DVB_B2C2_FLEXCOP
+	tristate
+	depends on DVB_CORE && I2C
+	depends on DVB_B2C2_FLEXCOP_PCI || DVB_B2C2_FLEXCOP_USB
+	default y
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_MT352 if !DVB_FE_CUSTOMISE
+	select DVB_MT312 if !DVB_FE_CUSTOMISE
+	select DVB_NXT200X if !DVB_FE_CUSTOMISE
+	select DVB_STV0297 if !DVB_FE_CUSTOMISE
+	select DVB_BCM3510 if !DVB_FE_CUSTOMISE
+	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+	select DVB_S5H1420 if !DVB_FE_CUSTOMISE
+	select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE
+	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
+	select DVB_CX24123 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
+	select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE
+	help
+	  Support for the digital TV receiver chip made by B2C2 Inc. included in
+	  Technisats PCI cards and USB boxes.
+
+	  Say Y if you own such a device and want to use it.
+
+config DVB_B2C2_FLEXCOP_DEBUG
+	bool "Enable debug for the B2C2 FlexCop drivers"
+	depends on DVB_B2C2_FLEXCOP
+	help
+	  Say Y if you want to enable the module option to control debug messages
+	  of all B2C2 FlexCop drivers.
diff --git a/drivers/media/common/b2c2/Makefile b/drivers/media/common/b2c2/Makefile
new file mode 100644
index 0000000..24993a5
--- /dev/null
+++ b/drivers/media/common/b2c2/Makefile
@@ -0,0 +1,8 @@
+b2c2-flexcop-objs += flexcop.o flexcop-fe-tuner.o flexcop-i2c.o
+b2c2-flexcop-objs += flexcop-sram.o flexcop-eeprom.o flexcop-misc.o
+b2c2-flexcop-objs += flexcop-hw-filter.o
+obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o
+
+ccflags-y += -Idrivers/media/dvb-core/
+ccflags-y += -Idrivers/media/dvb-frontends/
+ccflags-y += -Idrivers/media/tuners/
diff --git a/drivers/media/common/b2c2/flexcop-common.h b/drivers/media/common/b2c2/flexcop-common.h
new file mode 100644
index 0000000..437912e
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop-common.h
@@ -0,0 +1,185 @@
+/*
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-common.h - common header file for device-specific source files
+ * see flexcop.c for copyright information
+ */
+#ifndef __FLEXCOP_COMMON_H__
+#define __FLEXCOP_COMMON_H__
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+
+#include "flexcop-reg.h"
+
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_filter.h"
+#include "dvb_net.h"
+#include "dvb_frontend.h"
+
+#define FC_MAX_FEED 256
+
+#ifndef FC_LOG_PREFIX
+#warning please define a log prefix for your file, using a default one
+#define FC_LOG_PREFIX "b2c2-undef"
+#endif
+
+/* Steal from usb.h */
+#undef err
+#define err(format, arg...) \
+	printk(KERN_ERR FC_LOG_PREFIX ": " format "\n" , ## arg)
+#undef info
+#define info(format, arg...) \
+	printk(KERN_INFO FC_LOG_PREFIX ": " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) \
+	printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg)
+
+struct flexcop_dma {
+	struct pci_dev *pdev;
+
+	u8 *cpu_addr0;
+	dma_addr_t dma_addr0;
+	u8 *cpu_addr1;
+	dma_addr_t dma_addr1;
+	u32 size; /* size of each address in bytes */
+};
+
+struct flexcop_i2c_adapter {
+	struct flexcop_device *fc;
+	struct i2c_adapter i2c_adap;
+
+	u8 no_base_addr;
+	flexcop_i2c_port_t port;
+};
+
+/* Control structure for data definitions that are common to
+ * the B2C2-based PCI and USB devices.
+ */
+struct flexcop_device {
+	/* general */
+	struct device *dev; /* for firmware_class */
+
+#define FC_STATE_DVB_INIT 0x01
+#define FC_STATE_I2C_INIT 0x02
+#define FC_STATE_FE_INIT  0x04
+	int init_state;
+
+	/* device information */
+	int has_32_hw_pid_filter;
+	flexcop_revision_t rev;
+	flexcop_device_type_t dev_type;
+	flexcop_bus_t bus_type;
+
+	/* dvb stuff */
+	struct dvb_adapter dvb_adapter;
+	struct dvb_frontend *fe;
+	struct dvb_net dvbnet;
+	struct dvb_demux demux;
+	struct dmxdev dmxdev;
+	struct dmx_frontend hw_frontend;
+	struct dmx_frontend mem_frontend;
+	int (*fe_sleep) (struct dvb_frontend *);
+
+	struct flexcop_i2c_adapter fc_i2c_adap[3];
+	struct mutex i2c_mutex;
+	struct module *owner;
+
+	/* options and status */
+	int extra_feedcount;
+	int feedcount;
+	int pid_filtering;
+	int fullts_streaming_state;
+
+	/* bus specific callbacks */
+	flexcop_ibi_value(*read_ibi_reg) (struct flexcop_device *,
+			flexcop_ibi_register);
+	int (*write_ibi_reg) (struct flexcop_device *,
+			flexcop_ibi_register, flexcop_ibi_value);
+	int (*i2c_request) (struct flexcop_i2c_adapter *,
+		flexcop_access_op_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
+	int (*stream_control) (struct flexcop_device *, int);
+	int (*get_mac_addr) (struct flexcop_device *fc, int extended);
+	void *bus_specific;
+};
+
+/* exported prototypes */
+
+/* from flexcop.c */
+void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len);
+void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no);
+
+struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len);
+void flexcop_device_kfree(struct flexcop_device *);
+
+int flexcop_device_initialize(struct flexcop_device *);
+void flexcop_device_exit(struct flexcop_device *fc);
+void flexcop_reset_block_300(struct flexcop_device *fc);
+
+/* from flexcop-dma.c */
+int flexcop_dma_allocate(struct pci_dev *pdev,
+		struct flexcop_dma *dma, u32 size);
+void flexcop_dma_free(struct flexcop_dma *dma);
+
+int flexcop_dma_control_timer_irq(struct flexcop_device *fc,
+		flexcop_dma_index_t no, int onoff);
+int flexcop_dma_control_size_irq(struct flexcop_device *fc,
+		flexcop_dma_index_t no, int onoff);
+int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma,
+		flexcop_dma_index_t dma_idx);
+int flexcop_dma_xfer_control(struct flexcop_device *fc,
+		flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index,
+		int onoff);
+int flexcop_dma_config_timer(struct flexcop_device *fc,
+		flexcop_dma_index_t dma_idx, u8 cycles);
+
+/* from flexcop-eeprom.c */
+/* the PCI part uses this call to get the MAC address, the USB part has its own */
+int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended);
+
+/* from flexcop-i2c.c */
+/* the PCI part uses this a i2c_request callback, whereas the usb part has its own
+ * one. We have it in flexcop-i2c.c, because it is going via the actual
+ * I2C-channel of the flexcop.
+ */
+int flexcop_i2c_request(struct flexcop_i2c_adapter*, flexcop_access_op_t,
+	u8 chipaddr, u8 addr, u8 *buf, u16 len);
+
+/* from flexcop-sram.c */
+int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest,
+	flexcop_sram_dest_target_t target);
+void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s);
+void flexcop_sram_ctrl(struct flexcop_device *fc,
+		int usb_wan, int sramdma, int maximumfill);
+
+/* global prototypes for the flexcop-chip */
+/* from flexcop-fe-tuner.c */
+int flexcop_frontend_init(struct flexcop_device *fc);
+void flexcop_frontend_exit(struct flexcop_device *fc);
+
+/* from flexcop-i2c.c */
+int flexcop_i2c_init(struct flexcop_device *fc);
+void flexcop_i2c_exit(struct flexcop_device *fc);
+
+/* from flexcop-sram.c */
+int flexcop_sram_init(struct flexcop_device *fc);
+
+/* from flexcop-misc.c */
+void flexcop_determine_revision(struct flexcop_device *fc);
+void flexcop_device_name(struct flexcop_device *fc,
+		const char *prefix, const char *suffix);
+void flexcop_dump_reg(struct flexcop_device *fc,
+		flexcop_ibi_register reg, int num);
+
+/* from flexcop-hw-filter.c */
+int flexcop_pid_feed_control(struct flexcop_device *fc,
+		struct dvb_demux_feed *dvbdmxfeed, int onoff);
+void flexcop_hw_filter_init(struct flexcop_device *fc);
+
+void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff);
+
+void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]);
+void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff);
+
+#endif
diff --git a/drivers/media/common/b2c2/flexcop-eeprom.c b/drivers/media/common/b2c2/flexcop-eeprom.c
new file mode 100644
index 0000000..a25373a
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop-eeprom.c
@@ -0,0 +1,147 @@
+/*
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading)
+ * see flexcop.c for copyright information
+ */
+#include "flexcop.h"
+
+#if 0
+/*EEPROM (Skystar2 has one "24LC08B" chip on board) */
+static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len)
+{
+	return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len);
+}
+
+static int eeprom_lrc_write(struct adapter *adapter, u32 addr,
+		u32 len, u8 *wbuf, u8 *rbuf, int retries)
+{
+int i;
+
+for (i = 0; i < retries; i++) {
+	if (eeprom_write(adapter, addr, wbuf, len) == len) {
+		if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1)
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/* These functions could be used to unlock SkyStar2 cards. */
+
+static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len)
+{
+	u8 rbuf[20];
+	u8 wbuf[20];
+
+	if (len != 16)
+		return 0;
+
+	memcpy(wbuf, key, len);
+	wbuf[16] = 0;
+	wbuf[17] = 0;
+	wbuf[18] = 0;
+	wbuf[19] = calc_lrc(wbuf, 19);
+	return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4);
+}
+
+static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len)
+{
+	u8 buf[20];
+
+	if (len != 16)
+		return 0;
+
+	if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0)
+		return 0;
+
+	memcpy(key, buf, len);
+	return 1;
+}
+
+static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac)
+{
+	u8 tmp[8];
+
+	if (type != 0) {
+		tmp[0] = mac[0];
+		tmp[1] = mac[1];
+		tmp[2] = mac[2];
+		tmp[3] = mac[5];
+		tmp[4] = mac[6];
+		tmp[5] = mac[7];
+	} else {
+		tmp[0] = mac[0];
+		tmp[1] = mac[1];
+		tmp[2] = mac[2];
+		tmp[3] = mac[3];
+		tmp[4] = mac[4];
+		tmp[5] = mac[5];
+	}
+
+	tmp[6] = 0;
+	tmp[7] = calc_lrc(tmp, 7);
+
+	if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8)
+		return 1;
+	return 0;
+}
+
+static int flexcop_eeprom_read(struct flexcop_device *fc,
+		u16 addr, u8 *buf, u16 len)
+{
+	return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len);
+}
+
+#endif
+
+static u8 calc_lrc(u8 *buf, int len)
+{
+	int i;
+	u8 sum = 0;
+	for (i = 0; i < len; i++)
+		sum = sum ^ buf[i];
+	return sum;
+}
+
+static int flexcop_eeprom_request(struct flexcop_device *fc,
+	flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries)
+{
+	int i,ret = 0;
+	u8 chipaddr =  0x50 | ((addr >> 8) & 3);
+	for (i = 0; i < retries; i++) {
+		ret = fc->i2c_request(&fc->fc_i2c_adap[1], op, chipaddr,
+			addr & 0xff, buf, len);
+		if (ret == 0)
+			break;
+	}
+	return ret;
+}
+
+static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr,
+		u8 *buf, u16 len, int retries)
+{
+	int ret = flexcop_eeprom_request(fc, FC_READ, addr, buf, len, retries);
+	if (ret == 0)
+		if (calc_lrc(buf, len - 1) != buf[len - 1])
+			ret = -EINVAL;
+	return ret;
+}
+
+/* JJ's comment about extended == 1: it is not presently used anywhere but was
+ * added to the low-level functions for possible support of EUI64 */
+int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended)
+{
+	u8 buf[8];
+	int ret = 0;
+
+	if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) {
+		if (extended != 0) {
+			err("TODO: extended (EUI64) MAC addresses aren't "
+				"completely supported yet");
+			ret = -EINVAL;
+		} else
+			memcpy(fc->dvb_adapter.proposed_mac,buf,6);
+	}
+	return ret;
+}
+EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr);
diff --git a/drivers/media/common/b2c2/flexcop-fe-tuner.c b/drivers/media/common/b2c2/flexcop-fe-tuner.c
new file mode 100644
index 0000000..850a6c6
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop-fe-tuner.c
@@ -0,0 +1,678 @@
+/*
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling
+ * see flexcop.c for copyright information
+ */
+#include <media/tuner.h>
+#include "flexcop.h"
+#include "mt312.h"
+#include "stv0299.h"
+#include "s5h1420.h"
+#include "itd1000.h"
+#include "cx24113.h"
+#include "cx24123.h"
+#include "isl6421.h"
+#include "mt352.h"
+#include "bcm3510.h"
+#include "nxt200x.h"
+#include "dvb-pll.h"
+#include "lgdt330x.h"
+#include "tuner-simple.h"
+#include "stv0297.h"
+
+
+/* Can we use the specified front-end?  Remember that if we are compiled
+ * into the kernel we can't call code that's in modules.  */
+#define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \
+	(defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE)))
+
+/* lnb control */
+#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)
+static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct flexcop_device *fc = fe->dvb->priv;
+	flexcop_ibi_value v;
+	deb_tuner("polarity/voltage = %u\n", voltage);
+
+	v = fc->read_ibi_reg(fc, misc_204);
+	switch (voltage) {
+	case SEC_VOLTAGE_OFF:
+		v.misc_204.ACPI1_sig = 1;
+		break;
+	case SEC_VOLTAGE_13:
+		v.misc_204.ACPI1_sig = 0;
+		v.misc_204.LNB_L_H_sig = 0;
+		break;
+	case SEC_VOLTAGE_18:
+		v.misc_204.ACPI1_sig = 0;
+		v.misc_204.LNB_L_H_sig = 1;
+		break;
+	default:
+		err("unknown SEC_VOLTAGE value");
+		return -EINVAL;
+	}
+	return fc->write_ibi_reg(fc, misc_204, v);
+}
+#endif
+
+#if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312)
+static int flexcop_sleep(struct dvb_frontend* fe)
+{
+	struct flexcop_device *fc = fe->dvb->priv;
+	if (fc->fe_sleep)
+		return fc->fe_sleep(fe);
+	return 0;
+}
+#endif
+
+/* SkyStar2 DVB-S rev 2.3 */
+#if FE_SUPPORTED(MT312) && FE_SUPPORTED(PLL)
+static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
+	struct flexcop_device *fc = fe->dvb->priv;
+	flexcop_ibi_value v;
+	u16 ax;
+	v.raw = 0;
+	deb_tuner("tone = %u\n",tone);
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		ax = 0x01ff;
+		break;
+	case SEC_TONE_OFF:
+		ax = 0;
+		break;
+	default:
+		err("unknown SEC_TONE value");
+		return -EINVAL;
+	}
+
+	v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
+	v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
+	v.lnb_switch_freq_200.LNB_CTLLowCount_sig  = ax == 0 ? 0x1ff : ax;
+	return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
+}
+
+static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
+{
+	flexcop_set_tone(fe, SEC_TONE_ON);
+	udelay(data ? 500 : 1000);
+	flexcop_set_tone(fe, SEC_TONE_OFF);
+	udelay(data ? 1000 : 500);
+}
+
+static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
+{
+	int i, par = 1, d;
+	for (i = 7; i >= 0; i--) {
+		d = (data >> i) & 1;
+		par ^= d;
+		flexcop_diseqc_send_bit(fe, d);
+	}
+	flexcop_diseqc_send_bit(fe, par);
+}
+
+static int flexcop_send_diseqc_msg(struct dvb_frontend *fe,
+	int len, u8 *msg, unsigned long burst)
+{
+	int i;
+
+	flexcop_set_tone(fe, SEC_TONE_OFF);
+	mdelay(16);
+
+	for (i = 0; i < len; i++)
+		flexcop_diseqc_send_byte(fe,msg[i]);
+	mdelay(16);
+
+	if (burst != -1) {
+		if (burst)
+			flexcop_diseqc_send_byte(fe, 0xff);
+		else {
+			flexcop_set_tone(fe, SEC_TONE_ON);
+			mdelay(12);
+			udelay(500);
+			flexcop_set_tone(fe, SEC_TONE_OFF);
+		}
+		msleep(20);
+	}
+	return 0;
+}
+
+static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe,
+	struct dvb_diseqc_master_cmd *cmd)
+{
+	return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
+}
+
+static int flexcop_diseqc_send_burst(struct dvb_frontend *fe,
+	fe_sec_mini_cmd_t minicmd)
+{
+	return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
+}
+
+static struct mt312_config skystar23_samsung_tbdu18132_config = {
+	.demod_address = 0x0e,
+};
+
+static int skystar2_rev23_attach(struct flexcop_device *fc,
+	struct i2c_adapter *i2c)
+{
+	struct dvb_frontend_ops *ops;
+
+	fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
+	if (!fc->fe)
+		return 0;
+
+	if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
+			DVB_PLL_SAMSUNG_TBDU18132))
+		return 0;
+
+	ops = &fc->fe->ops;
+	ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
+	ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
+	ops->set_tone               = flexcop_set_tone;
+	ops->set_voltage            = flexcop_set_voltage;
+	fc->fe_sleep                = ops->sleep;
+	ops->sleep                  = flexcop_sleep;
+	return 1;
+}
+#else
+#define skystar2_rev23_attach NULL
+#endif
+
+/* SkyStar2 DVB-S rev 2.6 */
+#if FE_SUPPORTED(STV0299) && FE_SUPPORTED(PLL)
+static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
+	u32 srate, u32 ratio)
+{
+	u8 aclk = 0;
+	u8 bclk = 0;
+
+	if (srate < 1500000) {
+		aclk = 0xb7; bclk = 0x47;
+	} else if (srate < 3000000) {
+		aclk = 0xb7; bclk = 0x4b;
+	} else if (srate < 7000000) {
+		aclk = 0xb7; bclk = 0x4f;
+	} else if (srate < 14000000) {
+		aclk = 0xb7; bclk = 0x53;
+	} else if (srate < 30000000) {
+		aclk = 0xb6; bclk = 0x53;
+	} else if (srate < 45000000) {
+		aclk = 0xb4; bclk = 0x51;
+	}
+
+	stv0299_writereg(fe, 0x13, aclk);
+	stv0299_writereg(fe, 0x14, bclk);
+	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+	stv0299_writereg(fe, 0x20, (ratio >>  8) & 0xff);
+	stv0299_writereg(fe, 0x21,  ratio        & 0xf0);
+	return 0;
+}
+
+static u8 samsung_tbmu24112_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x30,
+	0x03, 0x00,
+	0x04, 0x7D,
+	0x05, 0x35,
+	0x06, 0x02,
+	0x07, 0x00,
+	0x08, 0xC3,
+	0x0C, 0x00,
+	0x0D, 0x81,
+	0x0E, 0x23,
+	0x0F, 0x12,
+	0x10, 0x7E,
+	0x11, 0x84,
+	0x12, 0xB9,
+	0x13, 0x88,
+	0x14, 0x89,
+	0x15, 0xC9,
+	0x16, 0x00,
+	0x17, 0x5C,
+	0x18, 0x00,
+	0x19, 0x00,
+	0x1A, 0x00,
+	0x1C, 0x00,
+	0x1D, 0x00,
+	0x1E, 0x00,
+	0x1F, 0x3A,
+	0x20, 0x2E,
+	0x21, 0x80,
+	0x22, 0xFF,
+	0x23, 0xC1,
+	0x28, 0x00,
+	0x29, 0x1E,
+	0x2A, 0x14,
+	0x2B, 0x0F,
+	0x2C, 0x09,
+	0x2D, 0x05,
+	0x31, 0x1F,
+	0x32, 0x19,
+	0x33, 0xFE,
+	0x34, 0x93,
+	0xff, 0xff,
+};
+
+static struct stv0299_config samsung_tbmu24112_config = {
+	.demod_address = 0x68,
+	.inittab = samsung_tbmu24112_inittab,
+	.mclk = 88000000UL,
+	.invert = 0,
+	.skip_reinit = 0,
+	.lock_output = STV0299_LOCKOUTPUT_LK,
+	.volt13_op0_op1 = STV0299_VOLT13_OP1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
+};
+
+static int skystar2_rev26_attach(struct flexcop_device *fc,
+	struct i2c_adapter *i2c)
+{
+	fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
+	if (!fc->fe)
+		return 0;
+
+	if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
+			DVB_PLL_SAMSUNG_TBMU24112))
+		return 0;
+
+	fc->fe->ops.set_voltage = flexcop_set_voltage;
+	fc->fe_sleep = fc->fe->ops.sleep;
+	fc->fe->ops.sleep = flexcop_sleep;
+	return 1;
+
+}
+#else
+#define skystar2_rev26_attach NULL
+#endif
+
+/* SkyStar2 DVB-S rev 2.7 */
+#if FE_SUPPORTED(S5H1420) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_ITD1000)
+static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
+	.demod_address = 0x53,
+	.invert = 1,
+	.repeated_start_workaround = 1,
+	.serial_mpeg = 1,
+};
+
+static struct itd1000_config skystar2_rev2_7_itd1000_config = {
+	.i2c_address = 0x61,
+};
+
+static int skystar2_rev27_attach(struct flexcop_device *fc,
+	struct i2c_adapter *i2c)
+{
+	flexcop_ibi_value r108;
+	struct i2c_adapter *i2c_tuner;
+
+	/* enable no_base_addr - no repeated start when reading */
+	fc->fc_i2c_adap[0].no_base_addr = 1;
+	fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config,
+			    i2c);
+	if (!fc->fe)
+		goto fail;
+
+	i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
+	if (!i2c_tuner)
+		goto fail;
+
+	fc->fe_sleep = fc->fe->ops.sleep;
+	fc->fe->ops.sleep = flexcop_sleep;
+
+	/* enable no_base_addr - no repeated start when reading */
+	fc->fc_i2c_adap[2].no_base_addr = 1;
+	if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
+			0x08, 1, 1)) {
+		err("ISL6421 could NOT be attached");
+		goto fail_isl;
+	}
+	info("ISL6421 successfully attached");
+
+	/* the ITD1000 requires a lower i2c clock - is it a problem ? */
+	r108.raw = 0x00000506;
+	fc->write_ibi_reg(fc, tw_sm_c_108, r108);
+	if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner,
+			&skystar2_rev2_7_itd1000_config)) {
+		err("ITD1000 could NOT be attached");
+		/* Should i2c clock be restored? */
+		goto fail_isl;
+	}
+	info("ITD1000 successfully attached");
+
+	return 1;
+
+fail_isl:
+	fc->fc_i2c_adap[2].no_base_addr = 0;
+fail:
+	/* for the next devices we need it again */
+	fc->fc_i2c_adap[0].no_base_addr = 0;
+	return 0;
+}
+#else
+#define skystar2_rev27_attach NULL
+#endif
+
+/* SkyStar2 rev 2.8 */
+#if FE_SUPPORTED(CX24123) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_CX24113)
+static struct cx24123_config skystar2_rev2_8_cx24123_config = {
+	.demod_address = 0x55,
+	.dont_use_pll = 1,
+	.agc_callback = cx24113_agc_callback,
+};
+
+static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
+	.i2c_addr = 0x54,
+	.xtal_khz = 10111,
+};
+
+static int skystar2_rev28_attach(struct flexcop_device *fc,
+	struct i2c_adapter *i2c)
+{
+	struct i2c_adapter *i2c_tuner;
+
+	fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config,
+			    i2c);
+	if (!fc->fe)
+		return 0;
+
+	i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);
+	if (!i2c_tuner)
+		return 0;
+
+	if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config,
+			i2c_tuner)) {
+		err("CX24113 could NOT be attached");
+		return 0;
+	}
+	info("CX24113 successfully attached");
+
+	fc->fc_i2c_adap[2].no_base_addr = 1;
+	if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
+			0x08, 0, 0)) {
+		err("ISL6421 could NOT be attached");
+		fc->fc_i2c_adap[2].no_base_addr = 0;
+		return 0;
+	}
+	info("ISL6421 successfully attached");
+	/* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
+	 * IR-receiver (PIC16F818) - but the card has no input for that ??? */
+	return 1;
+}
+#else
+#define skystar2_rev28_attach NULL
+#endif
+
+/* AirStar DVB-T */
+#if FE_SUPPORTED(MT352) && FE_SUPPORTED(PLL)
+static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
+{
+	static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d };
+	static u8 mt352_reset[] = { 0x50, 0x80 };
+	static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
+	static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 };
+	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
+
+	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+	udelay(2000);
+	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
+	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
+	return 0;
+}
+
+static struct mt352_config samsung_tdtc9251dh0_config = {
+	.demod_address = 0x0f,
+	.demod_init    = samsung_tdtc9251dh0_demod_init,
+};
+
+static int airstar_dvbt_attach(struct flexcop_device *fc,
+	struct i2c_adapter *i2c)
+{
+	fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
+	if (!fc->fe)
+		return 0;
+
+	return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
+			    DVB_PLL_SAMSUNG_TDTC9251DH0);
+}
+#else
+#define airstar_dvbt_attach NULL
+#endif
+
+/* AirStar ATSC 1st generation */
+#if FE_SUPPORTED(BCM3510)
+static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
+	const struct firmware **fw, char* name)
+{
+	struct flexcop_device *fc = fe->dvb->priv;
+	return request_firmware(fw, name, fc->dev);
+}
+
+static struct bcm3510_config air2pc_atsc_first_gen_config = {
+	.demod_address    = 0x0f,
+	.request_firmware = flexcop_fe_request_firmware,
+};
+
+static int airstar_atsc1_attach(struct flexcop_device *fc,
+	struct i2c_adapter *i2c)
+{
+	fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
+	return fc->fe != NULL;
+}
+#else
+#define airstar_atsc1_attach NULL
+#endif
+
+/* AirStar ATSC 2nd generation */
+#if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL)
+static struct nxt200x_config samsung_tbmv_config = {
+	.demod_address = 0x0a,
+};
+
+static int airstar_atsc2_attach(struct flexcop_device *fc,
+	struct i2c_adapter *i2c)
+{
+	fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
+	if (!fc->fe)
+		return 0;
+
+	return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
+			    DVB_PLL_SAMSUNG_TBMV);
+}
+#else
+#define airstar_atsc2_attach NULL
+#endif
+
+/* AirStar ATSC 3rd generation */
+#if FE_SUPPORTED(LGDT330X)
+static struct lgdt330x_config air2pc_atsc_hd5000_config = {
+	.demod_address       = 0x59,
+	.demod_chip          = LGDT3303,
+	.serial_mpeg         = 0x04,
+	.clock_polarity_flip = 1,
+};
+
+static int airstar_atsc3_attach(struct flexcop_device *fc,
+	struct i2c_adapter *i2c)
+{
+	fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
+	if (!fc->fe)
+		return 0;
+
+	return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
+			    TUNER_LG_TDVS_H06XF);
+}
+#else
+#define airstar_atsc3_attach NULL
+#endif
+
+/* CableStar2 DVB-C */
+#if FE_SUPPORTED(STV0297) && FE_SUPPORTED(PLL)
+static u8 alps_tdee4_stv0297_inittab[] = {
+	0x80, 0x01,
+	0x80, 0x00,
+	0x81, 0x01,
+	0x81, 0x00,
+	0x00, 0x48,
+	0x01, 0x58,
+	0x03, 0x00,
+	0x04, 0x00,
+	0x07, 0x00,
+	0x08, 0x00,
+	0x30, 0xff,
+	0x31, 0x9d,
+	0x32, 0xff,
+	0x33, 0x00,
+	0x34, 0x29,
+	0x35, 0x55,
+	0x36, 0x80,
+	0x37, 0x6e,
+	0x38, 0x9c,
+	0x40, 0x1a,
+	0x41, 0xfe,
+	0x42, 0x33,
+	0x43, 0x00,
+	0x44, 0xff,
+	0x45, 0x00,
+	0x46, 0x00,
+	0x49, 0x04,
+	0x4a, 0x51,
+	0x4b, 0xf8,
+	0x52, 0x30,
+	0x53, 0x06,
+	0x59, 0x06,
+	0x5a, 0x5e,
+	0x5b, 0x04,
+	0x61, 0x49,
+	0x62, 0x0a,
+	0x70, 0xff,
+	0x71, 0x04,
+	0x72, 0x00,
+	0x73, 0x00,
+	0x74, 0x0c,
+	0x80, 0x20,
+	0x81, 0x00,
+	0x82, 0x30,
+	0x83, 0x00,
+	0x84, 0x04,
+	0x85, 0x22,
+	0x86, 0x08,
+	0x87, 0x1b,
+	0x88, 0x00,
+	0x89, 0x00,
+	0x90, 0x00,
+	0x91, 0x04,
+	0xa0, 0x86,
+	0xa1, 0x00,
+	0xa2, 0x00,
+	0xb0, 0x91,
+	0xb1, 0x0b,
+	0xc0, 0x5b,
+	0xc1, 0x10,
+	0xc2, 0x12,
+	0xd0, 0x02,
+	0xd1, 0x00,
+	0xd2, 0x00,
+	0xd3, 0x00,
+	0xd4, 0x02,
+	0xd5, 0x00,
+	0xde, 0x00,
+	0xdf, 0x01,
+	0xff, 0xff,
+};
+
+static struct stv0297_config alps_tdee4_stv0297_config = {
+	.demod_address = 0x1c,
+	.inittab = alps_tdee4_stv0297_inittab,
+};
+
+static int cablestar2_attach(struct flexcop_device *fc,
+	struct i2c_adapter *i2c)
+{
+	fc->fc_i2c_adap[0].no_base_addr = 1;
+	fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
+	if (!fc->fe)
+		goto fail;
+
+	/* This tuner doesn't use the stv0297's I2C gate, but instead the
+	 * tuner is connected to a different flexcop I2C adapter.  */
+	if (fc->fe->ops.i2c_gate_ctrl)
+		fc->fe->ops.i2c_gate_ctrl(fc->fe, 0);
+	fc->fe->ops.i2c_gate_ctrl = NULL;
+
+	if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61,
+			&fc->fc_i2c_adap[2].i2c_adap, DVB_PLL_TDEE4))
+		goto fail;
+
+	return 1;
+
+fail:
+	/* Reset for next frontend to try */
+	fc->fc_i2c_adap[0].no_base_addr = 0;
+	return 0;
+}
+#else
+#define cablestar2_attach NULL
+#endif
+
+static struct {
+	flexcop_device_type_t type;
+	int (*attach)(struct flexcop_device *, struct i2c_adapter *);
+} flexcop_frontends[] = {
+	{ FC_SKY_REV27, skystar2_rev27_attach },
+	{ FC_SKY_REV28, skystar2_rev28_attach },
+	{ FC_SKY_REV26, skystar2_rev26_attach },
+	{ FC_AIR_DVBT, airstar_dvbt_attach },
+	{ FC_AIR_ATSC2, airstar_atsc2_attach },
+	{ FC_AIR_ATSC3, airstar_atsc3_attach },
+	{ FC_AIR_ATSC1, airstar_atsc1_attach },
+	{ FC_CABLE, cablestar2_attach },
+	{ FC_SKY_REV23, skystar2_rev23_attach },
+};
+
+/* try to figure out the frontend */
+int flexcop_frontend_init(struct flexcop_device *fc)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) {
+		if (!flexcop_frontends[i].attach)
+			continue;
+		/* type needs to be set before, because of some workarounds
+		 * done based on the probed card type */
+		fc->dev_type = flexcop_frontends[i].type;
+		if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap))
+			goto fe_found;
+		/* Clean up partially attached frontend */
+		if (fc->fe) {
+			dvb_frontend_detach(fc->fe);
+			fc->fe = NULL;
+		}
+	}
+	fc->dev_type = FC_UNK;
+	err("no frontend driver found for this B2C2/FlexCop adapter");
+	return -ENODEV;
+
+fe_found:
+	info("found '%s' .", fc->fe->ops.info.name);
+	if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
+		err("frontend registration failed!");
+		dvb_frontend_detach(fc->fe);
+		fc->fe = NULL;
+		return -EINVAL;
+	}
+	fc->init_state |= FC_STATE_FE_INIT;
+	return 0;
+}
+
+void flexcop_frontend_exit(struct flexcop_device *fc)
+{
+	if (fc->init_state & FC_STATE_FE_INIT) {
+		dvb_unregister_frontend(fc->fe);
+		dvb_frontend_detach(fc->fe);
+	}
+	fc->init_state &= ~FC_STATE_FE_INIT;
+}
diff --git a/drivers/media/common/b2c2/flexcop-hw-filter.c b/drivers/media/common/b2c2/flexcop-hw-filter.c
new file mode 100644
index 0000000..77e4547
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop-hw-filter.c
@@ -0,0 +1,232 @@
+/*
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-hw-filter.c - pid and mac address filtering and control functions
+ * see flexcop.c for copyright information
+ */
+#include "flexcop.h"
+
+static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff)
+{
+	flexcop_set_ibi_value(ctrl_208, Rcv_Data_sig, onoff);
+	deb_ts("rcv_data is now: '%s'\n", onoff ? "on" : "off");
+}
+
+void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff)
+{
+	flexcop_set_ibi_value(ctrl_208, SMC_Enable_sig, onoff);
+}
+
+static void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff)
+{
+	flexcop_set_ibi_value(ctrl_208, Null_filter_sig, onoff);
+}
+
+void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6])
+{
+	flexcop_ibi_value v418, v41c;
+	v41c = fc->read_ibi_reg(fc, mac_address_41c);
+
+	v418.mac_address_418.MAC1 = mac[0];
+	v418.mac_address_418.MAC2 = mac[1];
+	v418.mac_address_418.MAC3 = mac[2];
+	v418.mac_address_418.MAC6 = mac[3];
+	v41c.mac_address_41c.MAC7 = mac[4];
+	v41c.mac_address_41c.MAC8 = mac[5];
+
+	fc->write_ibi_reg(fc, mac_address_418, v418);
+	fc->write_ibi_reg(fc, mac_address_41c, v41c);
+}
+
+void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff)
+{
+	flexcop_set_ibi_value(ctrl_208, MAC_filter_Mode_sig, onoff);
+}
+
+static void flexcop_pid_group_filter(struct flexcop_device *fc,
+		u16 pid, u16 mask)
+{
+	/* index_reg_310.extra_index_reg need to 0 or 7 to work */
+	flexcop_ibi_value v30c;
+	v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid;
+	v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask;
+	fc->write_ibi_reg(fc, pid_filter_30c, v30c);
+}
+
+static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff)
+{
+	flexcop_set_ibi_value(ctrl_208, Mask_filter_sig, onoff);
+}
+
+/* this fancy define reduces the code size of the quite similar PID controlling of
+ * the first 6 PIDs
+ */
+
+#define pid_ctrl(vregname,field,enablefield,trans_field,transval) \
+	flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \
+v208 = fc->read_ibi_reg(fc, ctrl_208); \
+vpid.vregname.field = onoff ? pid : 0x1fff; \
+vpid.vregname.trans_field = transval; \
+v208.ctrl_208.enablefield = onoff; \
+fc->write_ibi_reg(fc, vregname, vpid); \
+fc->write_ibi_reg(fc, ctrl_208, v208);
+
+static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc,
+		u16 pid, int onoff)
+{
+	pid_ctrl(pid_filter_300, Stream1_PID, Stream1_filter_sig,
+			Stream1_trans, 0);
+}
+
+static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc,
+		u16 pid, int onoff)
+{
+	pid_ctrl(pid_filter_300, Stream2_PID, Stream2_filter_sig,
+			Stream2_trans, 0);
+}
+
+static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc,
+		u16 pid, int onoff)
+{
+	pid_ctrl(pid_filter_304, PCR_PID, PCR_filter_sig, PCR_trans, 0);
+}
+
+static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc,
+		u16 pid, int onoff)
+{
+	pid_ctrl(pid_filter_304, PMT_PID, PMT_filter_sig, PMT_trans, 0);
+}
+
+static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc,
+		u16 pid, int onoff)
+{
+	pid_ctrl(pid_filter_308, EMM_PID, EMM_filter_sig, EMM_trans, 0);
+}
+
+static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc,
+		u16 pid, int onoff)
+{
+	pid_ctrl(pid_filter_308, ECM_PID, ECM_filter_sig, ECM_trans, 0);
+}
+
+static void flexcop_pid_control(struct flexcop_device *fc,
+		int index, u16 pid, int onoff)
+{
+	if (pid == 0x2000)
+		return;
+
+	deb_ts("setting pid: %5d %04x at index %d '%s'\n",
+			pid, pid, index, onoff ? "on" : "off");
+
+	/* We could use bit magic here to reduce source code size.
+	 * I decided against it, but to use the real register names */
+	switch (index) {
+	case 0:
+		flexcop_pid_Stream1_PID_ctrl(fc, pid, onoff);
+		break;
+	case 1:
+		flexcop_pid_Stream2_PID_ctrl(fc, pid, onoff);
+		break;
+	case 2:
+		flexcop_pid_PCR_PID_ctrl(fc, pid, onoff);
+		break;
+	case 3:
+		flexcop_pid_PMT_PID_ctrl(fc, pid, onoff);
+		break;
+	case 4:
+		flexcop_pid_EMM_PID_ctrl(fc, pid, onoff);
+		break;
+	case 5:
+		flexcop_pid_ECM_PID_ctrl(fc, pid, onoff);
+		break;
+	default:
+		if (fc->has_32_hw_pid_filter && index < 38) {
+			flexcop_ibi_value vpid, vid;
+
+			/* set the index */
+			vid = fc->read_ibi_reg(fc, index_reg_310);
+			vid.index_reg_310.index_reg = index - 6;
+			fc->write_ibi_reg(fc, index_reg_310, vid);
+
+			vpid = fc->read_ibi_reg(fc, pid_n_reg_314);
+			vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff;
+			vpid.pid_n_reg_314.PID_enable_bit = onoff;
+			fc->write_ibi_reg(fc, pid_n_reg_314, vpid);
+		}
+		break;
+	}
+}
+
+static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc, int onoff)
+{
+	if (fc->fullts_streaming_state != onoff) {
+		deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling");
+		flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff));
+		flexcop_pid_group_filter_ctrl(fc, onoff);
+		fc->fullts_streaming_state = onoff;
+	}
+	return 0;
+}
+
+int flexcop_pid_feed_control(struct flexcop_device *fc,
+		struct dvb_demux_feed *dvbdmxfeed, int onoff)
+{
+	int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32;
+
+	fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */
+	if (dvbdmxfeed->index >= max_pid_filter)
+		fc->extra_feedcount += onoff ? 1 : -1;
+
+	/* toggle complete-TS-streaming when:
+	 * - pid_filtering is not enabled and it is the first or last feed requested
+	 * - pid_filtering is enabled,
+	 *   - but the number of requested feeds is exceeded
+	 *   - or the requested pid is 0x2000 */
+
+	if (!fc->pid_filtering && fc->feedcount == onoff)
+		flexcop_toggle_fullts_streaming(fc, onoff);
+
+	if (fc->pid_filtering) {
+		flexcop_pid_control \
+			(fc, dvbdmxfeed->index, dvbdmxfeed->pid, onoff);
+
+		if (fc->extra_feedcount > 0)
+			flexcop_toggle_fullts_streaming(fc, 1);
+		else if (dvbdmxfeed->pid == 0x2000)
+			flexcop_toggle_fullts_streaming(fc, onoff);
+		else
+			flexcop_toggle_fullts_streaming(fc, 0);
+	}
+
+	/* if it was the first or last feed request change the stream-status */
+	if (fc->feedcount == onoff) {
+		flexcop_rcv_data_ctrl(fc, onoff);
+		if (fc->stream_control) /* device specific stream control */
+			fc->stream_control(fc, onoff);
+
+		/* feeding stopped -> reset the flexcop filter*/
+		if (onoff == 0) {
+			flexcop_reset_block_300(fc);
+			flexcop_hw_filter_init(fc);
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL(flexcop_pid_feed_control);
+
+void flexcop_hw_filter_init(struct flexcop_device *fc)
+{
+	int i;
+	flexcop_ibi_value v;
+	for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++)
+		flexcop_pid_control(fc, i, 0x1fff, 0);
+
+	flexcop_pid_group_filter(fc, 0, 0x1fe0);
+	flexcop_pid_group_filter_ctrl(fc, 0);
+
+	v = fc->read_ibi_reg(fc, pid_filter_308);
+	v.pid_filter_308.EMM_filter_4 = 1;
+	v.pid_filter_308.EMM_filter_6 = 0;
+	fc->write_ibi_reg(fc, pid_filter_308, v);
+
+	flexcop_null_filter_ctrl(fc, 1);
+}
diff --git a/drivers/media/common/b2c2/flexcop-i2c.c b/drivers/media/common/b2c2/flexcop-i2c.c
new file mode 100644
index 0000000..965d5eb
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop-i2c.c
@@ -0,0 +1,288 @@
+/*
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-i2c.c - flexcop internal 2Wire bus (I2C) and dvb i2c initialization
+ * see flexcop.c for copyright information
+ */
+#include "flexcop.h"
+
+#define FC_MAX_I2C_RETRIES 100000
+
+static int flexcop_i2c_operation(struct flexcop_device *fc,
+		flexcop_ibi_value *r100)
+{
+	int i;
+	flexcop_ibi_value r;
+
+	r100->tw_sm_c_100.working_start = 1;
+	deb_i2c("r100 before: %08x\n",r100->raw);
+
+	fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero);
+	fc->write_ibi_reg(fc, tw_sm_c_100, *r100); /* initiating i2c operation */
+
+	for (i = 0; i < FC_MAX_I2C_RETRIES; i++) {
+		r = fc->read_ibi_reg(fc, tw_sm_c_100);
+
+		if (!r.tw_sm_c_100.no_base_addr_ack_error) {
+			if (r.tw_sm_c_100.st_done) {
+				*r100 = r;
+				deb_i2c("i2c success\n");
+				return 0;
+			}
+		} else {
+			deb_i2c("suffering from an i2c ack_error\n");
+			return -EREMOTEIO;
+		}
+	}
+	deb_i2c("tried %d times i2c operation, "
+			"never finished or too many ack errors.\n", i);
+	return -EREMOTEIO;
+}
+
+static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c,
+		flexcop_ibi_value r100, u8 *buf)
+{
+	flexcop_ibi_value r104;
+	int len = r100.tw_sm_c_100.total_bytes,
+		/* remember total_bytes is buflen-1 */
+		ret;
+
+	/* work-around to have CableStar2 and SkyStar2 rev 2.7 work
+	 * correctly:
+	 *
+	 * the ITD1000 is behind an i2c-gate which closes automatically
+	 * after an i2c-transaction the STV0297 needs 2 consecutive reads
+	 * one with no_base_addr = 0 and one with 1
+	 *
+	 * those two work-arounds are conflictin: we check for the card
+	 * type, it is set when probing the ITD1000 */
+	if (i2c->fc->dev_type == FC_SKY_REV27)
+		r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
+
+	ret = flexcop_i2c_operation(i2c->fc, &r100);
+	if (ret != 0) {
+		deb_i2c("Retrying operation\n");
+		r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
+		ret = flexcop_i2c_operation(i2c->fc, &r100);
+	}
+	if (ret != 0) {
+		deb_i2c("read failed. %d\n", ret);
+		return ret;
+	}
+
+	buf[0] = r100.tw_sm_c_100.data1_reg;
+
+	if (len > 0) {
+		r104 = i2c->fc->read_ibi_reg(i2c->fc, tw_sm_c_104);
+		deb_i2c("read: r100: %08x, r104: %08x\n", r100.raw, r104.raw);
+
+		/* there is at least one more byte, otherwise we wouldn't be here */
+		buf[1] = r104.tw_sm_c_104.data2_reg;
+		if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg;
+		if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg;
+	}
+	return 0;
+}
+
+static int flexcop_i2c_write4(struct flexcop_device *fc,
+		flexcop_ibi_value r100, u8 *buf)
+{
+	flexcop_ibi_value r104;
+	int len = r100.tw_sm_c_100.total_bytes; /* remember total_bytes is buflen-1 */
+	r104.raw = 0;
+
+	/* there is at least one byte, otherwise we wouldn't be here */
+	r100.tw_sm_c_100.data1_reg = buf[0];
+	r104.tw_sm_c_104.data2_reg = len > 0 ? buf[1] : 0;
+	r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0;
+	r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0;
+
+	deb_i2c("write: r100: %08x, r104: %08x\n", r100.raw, r104.raw);
+
+	/* write the additional i2c data before doing the actual i2c operation */
+	fc->write_ibi_reg(fc, tw_sm_c_104, r104);
+	return flexcop_i2c_operation(fc, &r100);
+}
+
+int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c,
+		flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
+{
+	int ret;
+
+#ifdef DUMP_I2C_MESSAGES
+	int i;
+#endif
+
+	u16 bytes_to_transfer;
+	flexcop_ibi_value r100;
+
+	deb_i2c("op = %d\n",op);
+	r100.raw = 0;
+	r100.tw_sm_c_100.chipaddr = chipaddr;
+	r100.tw_sm_c_100.twoWS_rw = op;
+	r100.tw_sm_c_100.twoWS_port_reg = i2c->port;
+
+#ifdef DUMP_I2C_MESSAGES
+	printk(KERN_DEBUG "%d ", i2c->port);
+	if (op == FC_READ)
+		printk("rd(");
+	else
+		printk("wr(");
+	printk("%02x): %02x ", chipaddr, addr);
+#endif
+
+	/* in that case addr is the only value ->
+	 * we write it twice as baseaddr and val0
+	 * BBTI is doing it like that for ISL6421 at least */
+	if (i2c->no_base_addr && len == 0 && op == FC_WRITE) {
+		buf = &addr;
+		len = 1;
+	}
+
+	while (len != 0) {
+		bytes_to_transfer = len > 4 ? 4 : len;
+
+		r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1;
+		r100.tw_sm_c_100.baseaddr = addr;
+
+		if (op == FC_READ)
+			ret = flexcop_i2c_read4(i2c, r100, buf);
+		else
+			ret = flexcop_i2c_write4(i2c->fc, r100, buf);
+
+#ifdef DUMP_I2C_MESSAGES
+		for (i = 0; i < bytes_to_transfer; i++)
+			printk("%02x ", buf[i]);
+#endif
+
+		if (ret < 0)
+			return ret;
+
+		buf  += bytes_to_transfer;
+		addr += bytes_to_transfer;
+		len  -= bytes_to_transfer;
+	}
+
+#ifdef DUMP_I2C_MESSAGES
+	printk("\n");
+#endif
+
+	return 0;
+}
+/* exported for PCI i2c */
+EXPORT_SYMBOL(flexcop_i2c_request);
+
+/* master xfer callback for demodulator */
+static int flexcop_master_xfer(struct i2c_adapter *i2c_adap,
+		struct i2c_msg msgs[], int num)
+{
+	struct flexcop_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap);
+	int i, ret = 0;
+
+	/* Some drivers use 1 byte or 0 byte reads as probes, which this
+	 * driver doesn't support.  These probes will always fail, so this
+	 * hack makes them always succeed.  If one knew how, it would of
+	 * course be better to actually do the read.  */
+	if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1)
+		return 1;
+
+	if (mutex_lock_interruptible(&i2c->fc->i2c_mutex))
+		return -ERESTARTSYS;
+
+	for (i = 0; i < num; i++) {
+		/* reading */
+		if (i+1 < num && (msgs[i+1].flags == I2C_M_RD)) {
+			ret = i2c->fc->i2c_request(i2c, FC_READ, msgs[i].addr,
+					msgs[i].buf[0], msgs[i+1].buf,
+					msgs[i+1].len);
+			i++; /* skip the following message */
+		} else /* writing */
+			ret = i2c->fc->i2c_request(i2c, FC_WRITE, msgs[i].addr,
+					msgs[i].buf[0], &msgs[i].buf[1],
+					msgs[i].len - 1);
+		if (ret < 0) {
+			deb_i2c("i2c master_xfer failed");
+			break;
+		}
+	}
+
+	mutex_unlock(&i2c->fc->i2c_mutex);
+
+	if (ret == 0)
+		ret = num;
+	return ret;
+}
+
+static u32 flexcop_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm flexcop_algo = {
+	.master_xfer	= flexcop_master_xfer,
+	.functionality	= flexcop_i2c_func,
+};
+
+int flexcop_i2c_init(struct flexcop_device *fc)
+{
+	int ret;
+	mutex_init(&fc->i2c_mutex);
+
+	fc->fc_i2c_adap[0].fc = fc;
+	fc->fc_i2c_adap[1].fc = fc;
+	fc->fc_i2c_adap[2].fc = fc;
+	fc->fc_i2c_adap[0].port = FC_I2C_PORT_DEMOD;
+	fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM;
+	fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER;
+
+	strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod",
+			sizeof(fc->fc_i2c_adap[0].i2c_adap.name));
+	strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom",
+			sizeof(fc->fc_i2c_adap[1].i2c_adap.name));
+	strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner",
+			sizeof(fc->fc_i2c_adap[2].i2c_adap.name));
+
+	i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]);
+	i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
+	i2c_set_adapdata(&fc->fc_i2c_adap[2].i2c_adap, &fc->fc_i2c_adap[2]);
+
+	fc->fc_i2c_adap[0].i2c_adap.algo =
+		fc->fc_i2c_adap[1].i2c_adap.algo =
+		fc->fc_i2c_adap[2].i2c_adap.algo = &flexcop_algo;
+	fc->fc_i2c_adap[0].i2c_adap.algo_data =
+		fc->fc_i2c_adap[1].i2c_adap.algo_data =
+		fc->fc_i2c_adap[2].i2c_adap.algo_data = NULL;
+	fc->fc_i2c_adap[0].i2c_adap.dev.parent =
+		fc->fc_i2c_adap[1].i2c_adap.dev.parent =
+		fc->fc_i2c_adap[2].i2c_adap.dev.parent = fc->dev;
+
+	ret = i2c_add_adapter(&fc->fc_i2c_adap[0].i2c_adap);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_add_adapter(&fc->fc_i2c_adap[1].i2c_adap);
+	if (ret < 0)
+		goto adap_1_failed;
+
+	ret = i2c_add_adapter(&fc->fc_i2c_adap[2].i2c_adap);
+	if (ret < 0)
+		goto adap_2_failed;
+
+	fc->init_state |= FC_STATE_I2C_INIT;
+	return 0;
+
+adap_2_failed:
+	i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
+adap_1_failed:
+	i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
+	return ret;
+}
+
+void flexcop_i2c_exit(struct flexcop_device *fc)
+{
+	if (fc->init_state & FC_STATE_I2C_INIT) {
+		i2c_del_adapter(&fc->fc_i2c_adap[2].i2c_adap);
+		i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
+		i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
+	}
+	fc->init_state &= ~FC_STATE_I2C_INIT;
+}
diff --git a/drivers/media/common/b2c2/flexcop-misc.c b/drivers/media/common/b2c2/flexcop-misc.c
new file mode 100644
index 0000000..f06f3a9
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop-misc.c
@@ -0,0 +1,86 @@
+/*
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-misc.c - miscellaneous functions
+ * see flexcop.c for copyright information
+ */
+#include "flexcop.h"
+
+void flexcop_determine_revision(struct flexcop_device *fc)
+{
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204);
+
+	switch (v.misc_204.Rev_N_sig_revision_hi) {
+	case 0x2:
+		deb_info("found a FlexCopII.\n");
+		fc->rev = FLEXCOP_II;
+		break;
+	case 0x3:
+		deb_info("found a FlexCopIIb.\n");
+		fc->rev = FLEXCOP_IIB;
+		break;
+	case 0x0:
+		deb_info("found a FlexCopIII.\n");
+		fc->rev = FLEXCOP_III;
+		break;
+	default:
+		err("unknown FlexCop Revision: %x. Please report this to "
+				"linux-dvb@linuxtv.org.",
+				v.misc_204.Rev_N_sig_revision_hi);
+		break;
+	}
+
+	if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps))
+		deb_info("this FlexCop has "
+				"the additional 32 hardware pid filter.\n");
+	else
+		deb_info("this FlexCop has "
+				"the 6 basic main hardware pid filter.\n");
+	/* bus parts have to decide if hw pid filtering is used or not. */
+}
+
+static const char *flexcop_revision_names[] = {
+	"Unknown chip",
+	"FlexCopII",
+	"FlexCopIIb",
+	"FlexCopIII",
+};
+
+static const char *flexcop_device_names[] = {
+	[FC_UNK]	= "Unknown device",
+	[FC_CABLE]	= "Cable2PC/CableStar 2 DVB-C",
+	[FC_AIR_DVBT]	= "Air2PC/AirStar 2 DVB-T",
+	[FC_AIR_ATSC1]	= "Air2PC/AirStar 2 ATSC 1st generation",
+	[FC_AIR_ATSC2]	= "Air2PC/AirStar 2 ATSC 2nd generation",
+	[FC_AIR_ATSC3]	= "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
+	[FC_SKY_REV23]	= "Sky2PC/SkyStar 2 DVB-S rev 2.3 (old version)",
+	[FC_SKY_REV26]	= "Sky2PC/SkyStar 2 DVB-S rev 2.6",
+	[FC_SKY_REV27]	= "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
+	[FC_SKY_REV28]	= "Sky2PC/SkyStar 2 DVB-S rev 2.8",
+};
+
+static const char *flexcop_bus_names[] = {
+	"USB",
+	"PCI",
+};
+
+void flexcop_device_name(struct flexcop_device *fc,
+		const char *prefix, const char *suffix)
+{
+	info("%s '%s' at the '%s' bus controlled by a '%s' %s",
+			prefix,	flexcop_device_names[fc->dev_type],
+			flexcop_bus_names[fc->bus_type],
+			flexcop_revision_names[fc->rev], suffix);
+}
+
+void flexcop_dump_reg(struct flexcop_device *fc,
+		flexcop_ibi_register reg, int num)
+{
+	flexcop_ibi_value v;
+	int i;
+	for (i = 0; i < num; i++) {
+		v = fc->read_ibi_reg(fc, reg+4*i);
+		deb_rdump("0x%03x: %08x, ", reg+4*i, v.raw);
+	}
+	deb_rdump("\n");
+}
+EXPORT_SYMBOL(flexcop_dump_reg);
diff --git a/drivers/media/common/b2c2/flexcop-reg.h b/drivers/media/common/b2c2/flexcop-reg.h
new file mode 100644
index 0000000..dc4528d
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop-reg.h
@@ -0,0 +1,166 @@
+/*
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-reg.h - register abstraction for FlexCopII, FlexCopIIb and FlexCopIII
+ * see flexcop.c for copyright information
+ */
+#ifndef __FLEXCOP_REG_H__
+#define __FLEXCOP_REG_H__
+
+typedef enum {
+	FLEXCOP_UNK = 0,
+	FLEXCOP_II,
+	FLEXCOP_IIB,
+	FLEXCOP_III,
+} flexcop_revision_t;
+
+typedef enum {
+	FC_UNK = 0,
+	FC_CABLE,
+	FC_AIR_DVBT,
+	FC_AIR_ATSC1,
+	FC_AIR_ATSC2,
+	FC_AIR_ATSC3,
+	FC_SKY_REV23,
+	FC_SKY_REV26,
+	FC_SKY_REV27,
+	FC_SKY_REV28,
+} flexcop_device_type_t;
+
+typedef enum {
+	FC_USB = 0,
+	FC_PCI,
+} flexcop_bus_t;
+
+/* FlexCop IBI Registers */
+#if defined(__LITTLE_ENDIAN)
+#include "flexcop_ibi_value_le.h"
+#else
+#if defined(__BIG_ENDIAN)
+#include "flexcop_ibi_value_be.h"
+#else
+#error no endian defined
+#endif
+#endif
+
+#define fc_data_Tag_ID_DVB  0x3e
+#define fc_data_Tag_ID_ATSC 0x3f
+#define fc_data_Tag_ID_IDSB 0x8b
+
+#define fc_key_code_default 0x1
+#define fc_key_code_even    0x2
+#define fc_key_code_odd     0x3
+
+extern flexcop_ibi_value ibi_zero;
+
+typedef enum {
+	FC_I2C_PORT_DEMOD  = 1,
+	FC_I2C_PORT_EEPROM = 2,
+	FC_I2C_PORT_TUNER  = 3,
+} flexcop_i2c_port_t;
+
+typedef enum {
+	FC_WRITE = 0,
+	FC_READ  = 1,
+} flexcop_access_op_t;
+
+typedef enum {
+	FC_SRAM_DEST_NET   = 1,
+	FC_SRAM_DEST_CAI   = 2,
+	FC_SRAM_DEST_CAO   = 4,
+	FC_SRAM_DEST_MEDIA = 8
+} flexcop_sram_dest_t;
+
+typedef enum {
+	FC_SRAM_DEST_TARGET_WAN_USB = 0,
+	FC_SRAM_DEST_TARGET_DMA1    = 1,
+	FC_SRAM_DEST_TARGET_DMA2    = 2,
+	FC_SRAM_DEST_TARGET_FC3_CA  = 3
+} flexcop_sram_dest_target_t;
+
+typedef enum {
+	FC_SRAM_2_32KB  = 0, /*  64KB */
+	FC_SRAM_1_32KB  = 1, /*  32KB - default fow FCII */
+	FC_SRAM_1_128KB = 2, /* 128KB */
+	FC_SRAM_1_48KB  = 3, /*  48KB - default for FCIII */
+} flexcop_sram_type_t;
+
+typedef enum {
+	FC_WAN_SPEED_4MBITS  = 0,
+	FC_WAN_SPEED_8MBITS  = 1,
+	FC_WAN_SPEED_12MBITS = 2,
+	FC_WAN_SPEED_16MBITS = 3,
+} flexcop_wan_speed_t;
+
+typedef enum {
+	FC_DMA_1 = 1,
+	FC_DMA_2 = 2,
+} flexcop_dma_index_t;
+
+typedef enum {
+	FC_DMA_SUBADDR_0 = 1,
+	FC_DMA_SUBADDR_1 = 2,
+} flexcop_dma_addr_index_t;
+
+/* names of the particular registers */
+typedef enum {
+	dma1_000            = 0x000,
+	dma1_004            = 0x004,
+	dma1_008            = 0x008,
+	dma1_00c            = 0x00c,
+	dma2_010            = 0x010,
+	dma2_014            = 0x014,
+	dma2_018            = 0x018,
+	dma2_01c            = 0x01c,
+
+	tw_sm_c_100         = 0x100,
+	tw_sm_c_104         = 0x104,
+	tw_sm_c_108         = 0x108,
+	tw_sm_c_10c         = 0x10c,
+	tw_sm_c_110         = 0x110,
+
+	lnb_switch_freq_200 = 0x200,
+	misc_204            = 0x204,
+	ctrl_208            = 0x208,
+	irq_20c             = 0x20c,
+	sw_reset_210        = 0x210,
+	misc_214            = 0x214,
+	mbox_v8_to_host_218 = 0x218,
+	mbox_host_to_v8_21c = 0x21c,
+
+	pid_filter_300      = 0x300,
+	pid_filter_304      = 0x304,
+	pid_filter_308      = 0x308,
+	pid_filter_30c      = 0x30c,
+	index_reg_310       = 0x310,
+	pid_n_reg_314       = 0x314,
+	mac_low_reg_318     = 0x318,
+	mac_high_reg_31c    = 0x31c,
+
+	data_tag_400        = 0x400,
+	card_id_408         = 0x408,
+	card_id_40c         = 0x40c,
+	mac_address_418     = 0x418,
+	mac_address_41c     = 0x41c,
+
+	ci_600              = 0x600,
+	pi_604              = 0x604,
+	pi_608              = 0x608,
+	dvb_reg_60c         = 0x60c,
+
+	sram_ctrl_reg_700   = 0x700,
+	net_buf_reg_704     = 0x704,
+	cai_buf_reg_708     = 0x708,
+	cao_buf_reg_70c     = 0x70c,
+	media_buf_reg_710   = 0x710,
+	sram_dest_reg_714   = 0x714,
+	net_buf_reg_718     = 0x718,
+	wan_ctrl_reg_71c    = 0x71c,
+} flexcop_ibi_register;
+
+#define flexcop_set_ibi_value(reg,attr,val) { \
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,reg); \
+	v.reg.attr = val; \
+	fc->write_ibi_reg(fc,reg,v); \
+}
+
+#endif
diff --git a/drivers/media/common/b2c2/flexcop-sram.c b/drivers/media/common/b2c2/flexcop-sram.c
new file mode 100644
index 0000000..f2199e4
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop-sram.c
@@ -0,0 +1,363 @@
+/*
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-sram.c - functions for controlling the SRAM
+ * see flexcop.c for copyright information
+ */
+#include "flexcop.h"
+
+static void flexcop_sram_set_chip(struct flexcop_device *fc,
+		flexcop_sram_type_t type)
+{
+	flexcop_set_ibi_value(wan_ctrl_reg_71c, sram_chip, type);
+}
+
+int flexcop_sram_init(struct flexcop_device *fc)
+{
+	switch (fc->rev) {
+	case FLEXCOP_II:
+	case FLEXCOP_IIB:
+		flexcop_sram_set_chip(fc, FC_SRAM_1_32KB);
+		break;
+	case FLEXCOP_III:
+		flexcop_sram_set_chip(fc, FC_SRAM_1_48KB);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest,
+		 flexcop_sram_dest_target_t target)
+{
+	flexcop_ibi_value v;
+	v = fc->read_ibi_reg(fc, sram_dest_reg_714);
+
+	if (fc->rev != FLEXCOP_III && target == FC_SRAM_DEST_TARGET_FC3_CA) {
+		err("SRAM destination target to available on FlexCopII(b)\n");
+		return -EINVAL;
+	}
+	deb_sram("sram dest: %x target: %x\n", dest, target);
+
+	if (dest & FC_SRAM_DEST_NET)
+		v.sram_dest_reg_714.NET_Dest = target;
+	if (dest & FC_SRAM_DEST_CAI)
+		v.sram_dest_reg_714.CAI_Dest = target;
+	if (dest & FC_SRAM_DEST_CAO)
+		v.sram_dest_reg_714.CAO_Dest = target;
+	if (dest & FC_SRAM_DEST_MEDIA)
+		v.sram_dest_reg_714.MEDIA_Dest = target;
+
+	fc->write_ibi_reg(fc,sram_dest_reg_714,v);
+	udelay(1000); /* TODO delay really necessary */
+
+	return 0;
+}
+EXPORT_SYMBOL(flexcop_sram_set_dest);
+
+void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s)
+{
+	flexcop_set_ibi_value(wan_ctrl_reg_71c,wan_speed_sig,s);
+}
+EXPORT_SYMBOL(flexcop_wan_set_speed);
+
+void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill)
+{
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714);
+	v.sram_dest_reg_714.ctrl_usb_wan = usb_wan;
+	v.sram_dest_reg_714.ctrl_sramdma = sramdma;
+	v.sram_dest_reg_714.ctrl_maximumfill = maximumfill;
+	fc->write_ibi_reg(fc,sram_dest_reg_714,v);
+}
+EXPORT_SYMBOL(flexcop_sram_ctrl);
+
+#if 0
+static void flexcop_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
+{
+	int i, retries;
+	u32 command;
+
+	for (i = 0; i < len; i++) {
+		command = bank | addr | 0x04000000 | (*buf << 0x10);
+
+		retries = 2;
+
+		while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
+			mdelay(1);
+			retries--;
+		};
+
+		if (retries == 0)
+			printk("%s: SRAM timeout\n", __func__);
+
+		write_reg_dw(adapter, 0x700, command);
+
+		buf++;
+		addr++;
+	}
+}
+
+static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
+{
+	int i, retries;
+	u32 command, value;
+
+	for (i = 0; i < len; i++) {
+		command = bank | addr | 0x04008000;
+
+		retries = 10000;
+
+		while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
+			mdelay(1);
+			retries--;
+		};
+
+		if (retries == 0)
+			printk("%s: SRAM timeout\n", __func__);
+
+		write_reg_dw(adapter, 0x700, command);
+
+		retries = 10000;
+
+		while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
+			mdelay(1);
+			retries--;
+		};
+
+		if (retries == 0)
+			printk("%s: SRAM timeout\n", __func__);
+
+		value = read_reg_dw(adapter, 0x700) >> 0x10;
+
+		*buf = (value & 0xff);
+
+		addr++;
+		buf++;
+	}
+}
+
+static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
+{
+	u32 bank;
+
+	bank = 0;
+
+	if (adapter->dw_sram_type == 0x20000) {
+		bank = (addr & 0x18000) << 0x0d;
+	}
+
+	if (adapter->dw_sram_type == 0x00000) {
+		if ((addr >> 0x0f) == 0)
+			bank = 0x20000000;
+		else
+			bank = 0x10000000;
+	}
+	flex_sram_write(adapter, bank, addr & 0x7fff, buf, len);
+}
+
+static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
+{
+	u32 bank;
+	bank = 0;
+
+	if (adapter->dw_sram_type == 0x20000) {
+		bank = (addr & 0x18000) << 0x0d;
+	}
+
+	if (adapter->dw_sram_type == 0x00000) {
+		if ((addr >> 0x0f) == 0)
+			bank = 0x20000000;
+		else
+			bank = 0x10000000;
+	}
+	flex_sram_read(adapter, bank, addr & 0x7fff, buf, len);
+}
+
+static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
+{
+	u32 length;
+	while (len != 0) {
+		length = len;
+		/* check if the address range belongs to the same
+		 * 32K memory chip. If not, the data is read
+		 * from one chip at a time */
+		if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
+			length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
+		}
+
+		sram_read_chunk(adapter, addr, buf, length);
+		addr = addr + length;
+		buf = buf + length;
+		len = len - length;
+	}
+}
+
+static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
+{
+	u32 length;
+	while (len != 0) {
+		length = len;
+
+		/* check if the address range belongs to the same
+		 * 32K memory chip. If not, the data is
+		 * written to one chip at a time */
+		if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
+			length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
+		}
+
+		sram_write_chunk(adapter, addr, buf, length);
+		addr = addr + length;
+		buf = buf + length;
+		len = len - length;
+	}
+}
+
+static void sram_set_size(struct adapter *adapter, u32 mask)
+{
+	write_reg_dw(adapter, 0x71c,
+			(mask | (~0x30000 & read_reg_dw(adapter, 0x71c))));
+}
+
+static void sram_init(struct adapter *adapter)
+{
+	u32 tmp;
+	tmp = read_reg_dw(adapter, 0x71c);
+	write_reg_dw(adapter, 0x71c, 1);
+
+	if (read_reg_dw(adapter, 0x71c) != 0) {
+		write_reg_dw(adapter, 0x71c, tmp);
+		adapter->dw_sram_type = tmp & 0x30000;
+		ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type);
+	} else {
+		adapter->dw_sram_type = 0x10000;
+		ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type);
+	}
+}
+
+static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
+{
+	u8 tmp1, tmp2;
+	dprintk("%s: mask = %x, addr = %x\n", __func__, mask, addr);
+
+	sram_set_size(adapter, mask);
+	sram_init(adapter);
+
+	tmp2 = 0xa5;
+	tmp1 = 0x4f;
+
+	sram_write(adapter, addr, &tmp2, 1);
+	sram_write(adapter, addr + 4, &tmp1, 1);
+
+	tmp2 = 0;
+	mdelay(20);
+
+	sram_read(adapter, addr, &tmp2, 1);
+	sram_read(adapter, addr, &tmp2, 1);
+
+	dprintk("%s: wrote 0xa5, read 0x%2x\n", __func__, tmp2);
+
+	if (tmp2 != 0xa5)
+		return 0;
+
+	tmp2 = 0x5a;
+	tmp1 = 0xf4;
+
+	sram_write(adapter, addr, &tmp2, 1);
+	sram_write(adapter, addr + 4, &tmp1, 1);
+
+	tmp2 = 0;
+	mdelay(20);
+
+	sram_read(adapter, addr, &tmp2, 1);
+	sram_read(adapter, addr, &tmp2, 1);
+
+	dprintk("%s: wrote 0x5a, read 0x%2x\n", __func__, tmp2);
+
+	if (tmp2 != 0x5a)
+		return 0;
+	return 1;
+}
+
+static u32 sram_length(struct adapter *adapter)
+{
+	if (adapter->dw_sram_type == 0x10000)
+		return 32768; /* 32K */
+	if (adapter->dw_sram_type == 0x00000)
+		return 65536; /* 64K */
+	if (adapter->dw_sram_type == 0x20000)
+		return 131072; /* 128K */
+	return 32768; /* 32K */
+}
+
+/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory.
+   - for 128K there are 4x32K chips at bank 0,1,2,3.
+   - for  64K there are 2x32K chips at bank 1,2.
+   - for  32K there is one 32K chip at bank 0.
+
+   FlexCop works only with one bank at a time. The bank is selected
+   by bits 28-29 of the 0x700 register.
+
+   bank 0 covers addresses 0x00000-0x07fff
+   bank 1 covers addresses 0x08000-0x0ffff
+   bank 2 covers addresses 0x10000-0x17fff
+   bank 3 covers addresses 0x18000-0x1ffff */
+
+static int flexcop_sram_detect(struct flexcop_device *fc)
+{
+	flexcop_ibi_value r208, r71c_0, vr71c_1;
+	r208 = fc->read_ibi_reg(fc, ctrl_208);
+	fc->write_ibi_reg(fc, ctrl_208, ibi_zero);
+
+	r71c_0 = fc->read_ibi_reg(fc, wan_ctrl_reg_71c);
+	write_reg_dw(adapter, 0x71c, 1);
+	tmp3 = read_reg_dw(adapter, 0x71c);
+	dprintk("%s: tmp3 = %x\n", __func__, tmp3);
+	write_reg_dw(adapter, 0x71c, tmp2);
+
+	// check for internal SRAM ???
+	tmp3--;
+	if (tmp3 != 0) {
+		sram_set_size(adapter, 0x10000);
+		sram_init(adapter);
+		write_reg_dw(adapter, 0x208, tmp);
+		dprintk("%s: sram size = 32K\n", __func__);
+		return 32;
+	}
+
+	if (sram_test_location(adapter, 0x20000, 0x18000) != 0) {
+		sram_set_size(adapter, 0x20000);
+		sram_init(adapter);
+		write_reg_dw(adapter, 0x208, tmp);
+		dprintk("%s: sram size = 128K\n", __func__);
+		return 128;
+	}
+
+	if (sram_test_location(adapter, 0x00000, 0x10000) != 0) {
+		sram_set_size(adapter, 0x00000);
+		sram_init(adapter);
+		write_reg_dw(adapter, 0x208, tmp);
+		dprintk("%s: sram size = 64K\n", __func__);
+		return 64;
+	}
+
+	if (sram_test_location(adapter, 0x10000, 0x00000) != 0) {
+		sram_set_size(adapter, 0x10000);
+		sram_init(adapter);
+		write_reg_dw(adapter, 0x208, tmp);
+		dprintk("%s: sram size = 32K\n", __func__);
+		return 32;
+	}
+
+	sram_set_size(adapter, 0x10000);
+	sram_init(adapter);
+	write_reg_dw(adapter, 0x208, tmp);
+	dprintk("%s: SRAM detection failed. Set to 32K \n", __func__);
+	return 0;
+}
+
+static void sll_detect_sram_size(struct adapter *adapter)
+{
+	sram_detect_for_flex2(adapter);
+}
+
+#endif
diff --git a/drivers/media/common/b2c2/flexcop.c b/drivers/media/common/b2c2/flexcop.c
new file mode 100644
index 0000000..412c5da
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop.c
@@ -0,0 +1,325 @@
+/*
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop.c - main module part
+ * Copyright (C) 2004-9 Patrick Boettcher <patrick.boettcher@desy.de>
+ * based on skystar2-driver Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
+ *
+ * Acknowledgements:
+ *   John Jurrius from BBTI, Inc. for extensive support
+ *                    with code examples and data books
+ *   Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting)
+ *
+ * Contributions to the skystar2-driver have been done by
+ *   Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes)
+ *   Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code)
+ *   Uwe Bugla, uwe.bugla at gmx.de (doing tests, restyling code, writing docu)
+ *   Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac
+ *               filtering)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include "flexcop.h"
+
+#define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip"
+#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de"
+
+#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
+#define DEBSTATUS ""
+#else
+#define DEBSTATUS " (debugging is not enabled)"
+#endif
+
+int b2c2_flexcop_debug;
+EXPORT_SYMBOL_GPL(b2c2_flexcop_debug);
+module_param_named(debug, b2c2_flexcop_debug,  int, 0644);
+MODULE_PARM_DESC(debug,
+		"set debug level (1=info,2=tuner,4=i2c,8=ts,"
+		"16=sram,32=reg (|-able))."
+		DEBSTATUS);
+#undef DEBSTATUS
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* global zero for ibi values */
+flexcop_ibi_value ibi_zero;
+
+static int flexcop_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct flexcop_device *fc = dvbdmxfeed->demux->priv;
+	return flexcop_pid_feed_control(fc, dvbdmxfeed, 1);
+}
+
+static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct flexcop_device *fc = dvbdmxfeed->demux->priv;
+	return flexcop_pid_feed_control(fc, dvbdmxfeed, 0);
+}
+
+static int flexcop_dvb_init(struct flexcop_device *fc)
+{
+	int ret = dvb_register_adapter(&fc->dvb_adapter,
+			"FlexCop Digital TV device", fc->owner,
+			fc->dev, adapter_nr);
+	if (ret < 0) {
+		err("error registering DVB adapter");
+		return ret;
+	}
+	fc->dvb_adapter.priv = fc;
+
+	fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING
+			| DMX_MEMORY_BASED_FILTERING);
+	fc->demux.priv = fc;
+	fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED;
+	fc->demux.start_feed = flexcop_dvb_start_feed;
+	fc->demux.stop_feed = flexcop_dvb_stop_feed;
+	fc->demux.write_to_decoder = NULL;
+
+	ret = dvb_dmx_init(&fc->demux);
+	if (ret < 0) {
+		err("dvb_dmx failed: error %d", ret);
+		goto err_dmx;
+	}
+
+	fc->hw_frontend.source = DMX_FRONTEND_0;
+
+	fc->dmxdev.filternum = fc->demux.feednum;
+	fc->dmxdev.demux = &fc->demux.dmx;
+	fc->dmxdev.capabilities = 0;
+	ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter);
+	if (ret < 0) {
+		err("dvb_dmxdev_init failed: error %d", ret);
+		goto err_dmx_dev;
+	}
+
+	ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend);
+	if (ret < 0) {
+		err("adding hw_frontend to dmx failed: error %d", ret);
+		goto err_dmx_add_hw_frontend;
+	}
+
+	fc->mem_frontend.source = DMX_MEMORY_FE;
+	ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend);
+	if (ret < 0) {
+		err("adding mem_frontend to dmx failed: error %d", ret);
+		goto err_dmx_add_mem_frontend;
+	}
+
+	ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend);
+	if (ret < 0) {
+		err("connect frontend failed: error %d", ret);
+		goto err_connect_frontend;
+	}
+
+	ret = dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
+	if (ret < 0) {
+		err("dvb_net_init failed: error %d", ret);
+		goto err_net;
+	}
+
+	fc->init_state |= FC_STATE_DVB_INIT;
+	return 0;
+
+err_net:
+	fc->demux.dmx.disconnect_frontend(&fc->demux.dmx);
+err_connect_frontend:
+	fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->mem_frontend);
+err_dmx_add_mem_frontend:
+	fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->hw_frontend);
+err_dmx_add_hw_frontend:
+	dvb_dmxdev_release(&fc->dmxdev);
+err_dmx_dev:
+	dvb_dmx_release(&fc->demux);
+err_dmx:
+	dvb_unregister_adapter(&fc->dvb_adapter);
+	return ret;
+}
+
+static void flexcop_dvb_exit(struct flexcop_device *fc)
+{
+	if (fc->init_state & FC_STATE_DVB_INIT) {
+		dvb_net_release(&fc->dvbnet);
+
+		fc->demux.dmx.close(&fc->demux.dmx);
+		fc->demux.dmx.remove_frontend(&fc->demux.dmx,
+			&fc->mem_frontend);
+		fc->demux.dmx.remove_frontend(&fc->demux.dmx,
+			&fc->hw_frontend);
+		dvb_dmxdev_release(&fc->dmxdev);
+		dvb_dmx_release(&fc->demux);
+		dvb_unregister_adapter(&fc->dvb_adapter);
+		deb_info("deinitialized dvb stuff\n");
+	}
+	fc->init_state &= ~FC_STATE_DVB_INIT;
+}
+
+/* these methods are necessary to achieve the long-term-goal of hiding the
+ * struct flexcop_device from the bus-parts */
+void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len)
+{
+	dvb_dmx_swfilter(&fc->demux, buf, len);
+}
+EXPORT_SYMBOL(flexcop_pass_dmx_data);
+
+void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no)
+{
+	dvb_dmx_swfilter_packets(&fc->demux, buf, no);
+}
+EXPORT_SYMBOL(flexcop_pass_dmx_packets);
+
+static void flexcop_reset(struct flexcop_device *fc)
+{
+	flexcop_ibi_value v210, v204;
+
+	/* reset the flexcop itself */
+	fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
+
+	v210.raw = 0;
+	v210.sw_reset_210.reset_block_000 = 1;
+	v210.sw_reset_210.reset_block_100 = 1;
+	v210.sw_reset_210.reset_block_200 = 1;
+	v210.sw_reset_210.reset_block_300 = 1;
+	v210.sw_reset_210.reset_block_400 = 1;
+	v210.sw_reset_210.reset_block_500 = 1;
+	v210.sw_reset_210.reset_block_600 = 1;
+	v210.sw_reset_210.reset_block_700 = 1;
+	v210.sw_reset_210.Block_reset_enable = 0xb2;
+	v210.sw_reset_210.Special_controls = 0xc259;
+	fc->write_ibi_reg(fc,sw_reset_210,v210);
+	msleep(1);
+
+	/* reset the periphical devices */
+
+	v204 = fc->read_ibi_reg(fc,misc_204);
+	v204.misc_204.Per_reset_sig = 0;
+	fc->write_ibi_reg(fc,misc_204,v204);
+	msleep(1);
+	v204.misc_204.Per_reset_sig = 1;
+	fc->write_ibi_reg(fc,misc_204,v204);
+}
+
+void flexcop_reset_block_300(struct flexcop_device *fc)
+{
+	flexcop_ibi_value v208_save = fc->read_ibi_reg(fc, ctrl_208),
+			  v210 = fc->read_ibi_reg(fc, sw_reset_210);
+
+	deb_rdump("208: %08x, 210: %08x\n", v208_save.raw, v210.raw);
+	fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
+
+	v210.sw_reset_210.reset_block_300 = 1;
+	v210.sw_reset_210.Block_reset_enable = 0xb2;
+
+	fc->write_ibi_reg(fc,sw_reset_210,v210);
+	fc->write_ibi_reg(fc,ctrl_208,v208_save);
+}
+
+struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
+{
+	void *bus;
+	struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device),
+				GFP_KERNEL);
+	if (!fc) {
+		err("no memory");
+		return NULL;
+	}
+
+	bus = kzalloc(bus_specific_len, GFP_KERNEL);
+	if (!bus) {
+		err("no memory");
+		kfree(fc);
+		return NULL;
+	}
+
+	fc->bus_specific = bus;
+
+	return fc;
+}
+EXPORT_SYMBOL(flexcop_device_kmalloc);
+
+void flexcop_device_kfree(struct flexcop_device *fc)
+{
+	kfree(fc->bus_specific);
+	kfree(fc);
+}
+EXPORT_SYMBOL(flexcop_device_kfree);
+
+int flexcop_device_initialize(struct flexcop_device *fc)
+{
+	int ret;
+	ibi_zero.raw = 0;
+
+	flexcop_reset(fc);
+	flexcop_determine_revision(fc);
+	flexcop_sram_init(fc);
+	flexcop_hw_filter_init(fc);
+	flexcop_smc_ctrl(fc, 0);
+
+	ret = flexcop_dvb_init(fc);
+	if (ret)
+		goto error;
+
+	/* i2c has to be done before doing EEProm stuff -
+	 * because the EEProm is accessed via i2c */
+	ret = flexcop_i2c_init(fc);
+	if (ret)
+		goto error;
+
+	/* do the MAC address reading after initializing the dvb_adapter */
+	if (fc->get_mac_addr(fc, 0) == 0) {
+		u8 *b = fc->dvb_adapter.proposed_mac;
+		info("MAC address = %pM", b);
+		flexcop_set_mac_filter(fc,b);
+		flexcop_mac_filter_ctrl(fc,1);
+	} else
+		warn("reading of MAC address failed.\n");
+
+	ret = flexcop_frontend_init(fc);
+	if (ret)
+		goto error;
+
+	flexcop_device_name(fc,"initialization of","complete");
+	return 0;
+
+error:
+	flexcop_device_exit(fc);
+	return ret;
+}
+EXPORT_SYMBOL(flexcop_device_initialize);
+
+void flexcop_device_exit(struct flexcop_device *fc)
+{
+	flexcop_frontend_exit(fc);
+	flexcop_i2c_exit(fc);
+	flexcop_dvb_exit(fc);
+}
+EXPORT_SYMBOL(flexcop_device_exit);
+
+static int flexcop_module_init(void)
+{
+	info(DRIVER_NAME " loaded successfully");
+	return 0;
+}
+
+static void flexcop_module_cleanup(void)
+{
+	info(DRIVER_NAME " unloaded successfully");
+}
+
+module_init(flexcop_module_init);
+module_exit(flexcop_module_cleanup);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_NAME);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/b2c2/flexcop.h b/drivers/media/common/b2c2/flexcop.h
new file mode 100644
index 0000000..897b10c
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop.h
@@ -0,0 +1,29 @@
+/*
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop.h - private header file for all flexcop-chip-source files
+ * see flexcop.c for copyright information
+ */
+#ifndef __FLEXCOP_H__
+#define __FLEXCOP_H___
+
+#define FC_LOG_PREFIX "b2c2-flexcop"
+#include "flexcop-common.h"
+
+extern int b2c2_flexcop_debug;
+
+/* debug */
+#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
+#define dprintk(level,args...) \
+	do { if ((b2c2_flexcop_debug & level)) printk(args); } while (0)
+#else
+#define dprintk(level,args...)
+#endif
+
+#define deb_info(args...) dprintk(0x01, args)
+#define deb_tuner(args...) dprintk(0x02, args)
+#define deb_i2c(args...) dprintk(0x04, args)
+#define deb_ts(args...) dprintk(0x08, args)
+#define deb_sram(args...) dprintk(0x10, args)
+#define deb_rdump(args...) dprintk(0x20, args)
+
+#endif
diff --git a/drivers/media/common/b2c2/flexcop_ibi_value_be.h b/drivers/media/common/b2c2/flexcop_ibi_value_be.h
new file mode 100644
index 0000000..8f64bdb
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop_ibi_value_be.h
@@ -0,0 +1,455 @@
+/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * register descriptions
+ * see flexcop.c for copyright information
+ */
+/* This file is automatically generated, do not edit things here. */
+#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
+#define __FLEXCOP_IBI_VALUE_INCLUDED__
+
+typedef union {
+	u32 raw;
+
+	struct {
+		u32 dma_address0                   :30;
+		u32 dma_0No_update                 : 1;
+		u32 dma_0start                     : 1;
+	} dma_0x0;
+
+	struct {
+		u32 dma_addr_size                  :24;
+		u32 DMA_maxpackets                 : 8;
+	} dma_0x4_remap;
+
+	struct {
+		u32 dma_addr_size                  :24;
+		u32 unused                         : 1;
+		u32 dma1timer                      : 7;
+	} dma_0x4_read;
+
+	struct {
+		u32 dma_addr_size                  :24;
+		u32 dmatimer                       : 7;
+		u32 unused                         : 1;
+	} dma_0x4_write;
+
+	struct {
+		u32 dma_cur_addr                   :30;
+		u32 unused                         : 2;
+	} dma_0x8;
+
+	struct {
+		u32 dma_address1                   :30;
+		u32 remap_enable                   : 1;
+		u32 dma_1start                     : 1;
+	} dma_0xc;
+
+	struct {
+		u32 st_done                        : 1;
+		u32 no_base_addr_ack_error         : 1;
+		u32 twoWS_port_reg                 : 2;
+		u32 total_bytes                    : 2;
+		u32 twoWS_rw                       : 1;
+		u32 working_start                  : 1;
+		u32 data1_reg                      : 8;
+		u32 baseaddr                       : 8;
+		u32 reserved1                      : 1;
+		u32 chipaddr                       : 7;
+	} tw_sm_c_100;
+
+	struct {
+		u32 unused                         : 6;
+		u32 force_stop                     : 1;
+		u32 exlicit_stops                  : 1;
+		u32 data4_reg                      : 8;
+		u32 data3_reg                      : 8;
+		u32 data2_reg                      : 8;
+	} tw_sm_c_104;
+
+	struct {
+		u32 reserved2                      :19;
+		u32 tlo1                           : 5;
+		u32 reserved1                      : 2;
+		u32 thi1                           : 6;
+	} tw_sm_c_108;
+
+	struct {
+		u32 reserved2                      :19;
+		u32 tlo1                           : 5;
+		u32 reserved1                      : 2;
+		u32 thi1                           : 6;
+	} tw_sm_c_10c;
+
+	struct {
+		u32 reserved2                      :19;
+		u32 tlo1                           : 5;
+		u32 reserved1                      : 2;
+		u32 thi1                           : 6;
+	} tw_sm_c_110;
+
+	struct {
+		u32 LNB_CTLPrescaler_sig           : 2;
+		u32 LNB_CTLLowCount_sig            :15;
+		u32 LNB_CTLHighCount_sig           :15;
+	} lnb_switch_freq_200;
+
+	struct {
+		u32 Rev_N_sig_reserved2            : 1;
+		u32 Rev_N_sig_caps                 : 1;
+		u32 Rev_N_sig_reserved1            : 2;
+		u32 Rev_N_sig_revision_hi          : 4;
+		u32 reserved                       :20;
+		u32 Per_reset_sig                  : 1;
+		u32 LNB_L_H_sig                    : 1;
+		u32 ACPI3_sig                      : 1;
+		u32 ACPI1_sig                      : 1;
+	} misc_204;
+
+	struct {
+		u32 unused                         : 9;
+		u32 Mailbox_from_V8_Enable_sig     : 1;
+		u32 DMA2_Size_IRQ_Enable_sig       : 1;
+		u32 DMA1_Size_IRQ_Enable_sig       : 1;
+		u32 DMA2_Timer_Enable_sig          : 1;
+		u32 DMA2_IRQ_Enable_sig            : 1;
+		u32 DMA1_Timer_Enable_sig          : 1;
+		u32 DMA1_IRQ_Enable_sig            : 1;
+		u32 Rcv_Data_sig                   : 1;
+		u32 MAC_filter_Mode_sig            : 1;
+		u32 Multi2_Enable_sig              : 1;
+		u32 Per_CA_Enable_sig              : 1;
+		u32 SMC_Enable_sig                 : 1;
+		u32 CA_Enable_sig                  : 1;
+		u32 WAN_CA_Enable_sig              : 1;
+		u32 WAN_Enable_sig                 : 1;
+		u32 Mask_filter_sig                : 1;
+		u32 Null_filter_sig                : 1;
+		u32 ECM_filter_sig                 : 1;
+		u32 EMM_filter_sig                 : 1;
+		u32 PMT_filter_sig                 : 1;
+		u32 PCR_filter_sig                 : 1;
+		u32 Stream2_filter_sig             : 1;
+		u32 Stream1_filter_sig             : 1;
+	} ctrl_208;
+
+	struct {
+		u32 reserved                       :21;
+		u32 Transport_Error                : 1;
+		u32 LLC_SNAP_FLAG_set              : 1;
+		u32 Continuity_error_flag          : 1;
+		u32 Data_receiver_error            : 1;
+		u32 Mailbox_from_V8_Status_sig     : 1;
+		u32 DMA2_Size_IRQ_Status           : 1;
+		u32 DMA1_Size_IRQ_Status           : 1;
+		u32 DMA2_Timer_Status              : 1;
+		u32 DMA2_IRQ_Status                : 1;
+		u32 DMA1_Timer_Status              : 1;
+		u32 DMA1_IRQ_Status                : 1;
+	} irq_20c;
+
+	struct {
+		u32 Special_controls               :16;
+		u32 Block_reset_enable             : 8;
+		u32 reset_block_700                : 1;
+		u32 reset_block_600                : 1;
+		u32 reset_block_500                : 1;
+		u32 reset_block_400                : 1;
+		u32 reset_block_300                : 1;
+		u32 reset_block_200                : 1;
+		u32 reset_block_100                : 1;
+		u32 reset_block_000                : 1;
+	} sw_reset_210;
+
+	struct {
+		u32 unused2                        :20;
+		u32 polarity_PS_ERR_sig            : 1;
+		u32 polarity_PS_SYNC_sig           : 1;
+		u32 polarity_PS_VALID_sig          : 1;
+		u32 polarity_PS_CLK_sig            : 1;
+		u32 unused1                        : 3;
+		u32 s2p_sel_sig                    : 1;
+		u32 section_pkg_enable_sig         : 1;
+		u32 halt_V8_sig                    : 1;
+		u32 v2WS_oe_sig                    : 1;
+		u32 vuart_oe_sig                   : 1;
+	} misc_214;
+
+	struct {
+		u32 Mailbox_from_V8                :32;
+	} mbox_v8_to_host_218;
+
+	struct {
+		u32 sysramaccess_busmuster         : 1;
+		u32 sysramaccess_write             : 1;
+		u32 unused                         : 7;
+		u32 sysramaccess_addr              :15;
+		u32 sysramaccess_data              : 8;
+	} mbox_host_to_v8_21c;
+
+	struct {
+		u32 debug_fifo_problem             : 1;
+		u32 debug_flag_write_status00      : 1;
+		u32 Stream2_trans                  : 1;
+		u32 Stream2_PID                    :13;
+		u32 debug_flag_pid_saved           : 1;
+		u32 MAC_Multicast_filter           : 1;
+		u32 Stream1_trans                  : 1;
+		u32 Stream1_PID                    :13;
+	} pid_filter_300;
+
+	struct {
+		u32 reserved                       : 2;
+		u32 PMT_trans                      : 1;
+		u32 PMT_PID                        :13;
+		u32 debug_overrun2                 : 1;
+		u32 debug_overrun3                 : 1;
+		u32 PCR_trans                      : 1;
+		u32 PCR_PID                        :13;
+	} pid_filter_304;
+
+	struct {
+		u32 reserved                       : 2;
+		u32 ECM_trans                      : 1;
+		u32 ECM_PID                        :13;
+		u32 EMM_filter_6                   : 1;
+		u32 EMM_filter_4                   : 1;
+		u32 EMM_trans                      : 1;
+		u32 EMM_PID                        :13;
+	} pid_filter_308;
+
+	struct {
+		u32 unused2                        : 3;
+		u32 Group_mask                     :13;
+		u32 unused1                        : 2;
+		u32 Group_trans                    : 1;
+		u32 Group_PID                      :13;
+	} pid_filter_30c_ext_ind_0_7;
+
+	struct {
+		u32 unused                         :15;
+		u32 net_master_read                :17;
+	} pid_filter_30c_ext_ind_1;
+
+	struct {
+		u32 unused                         :15;
+		u32 net_master_write               :17;
+	} pid_filter_30c_ext_ind_2;
+
+	struct {
+		u32 unused                         :15;
+		u32 next_net_master_write          :17;
+	} pid_filter_30c_ext_ind_3;
+
+	struct {
+		u32 reserved2                      : 5;
+		u32 stack_read                     :10;
+		u32 reserved1                      : 6;
+		u32 state_write                    :10;
+		u32 unused1                        : 1;
+	} pid_filter_30c_ext_ind_4;
+
+	struct {
+		u32 unused                         :22;
+		u32 stack_cnt                      :10;
+	} pid_filter_30c_ext_ind_5;
+
+	struct {
+		u32 unused                         : 4;
+		u32 data_size_reg                  :12;
+		u32 write_status4                  : 2;
+		u32 write_status1                  : 2;
+		u32 pid_fsm_save_reg300            : 2;
+		u32 pid_fsm_save_reg4              : 2;
+		u32 pid_fsm_save_reg3              : 2;
+		u32 pid_fsm_save_reg2              : 2;
+		u32 pid_fsm_save_reg1              : 2;
+		u32 pid_fsm_save_reg0              : 2;
+	} pid_filter_30c_ext_ind_6;
+
+	struct {
+		u32 unused                         :22;
+		u32 pass_alltables                 : 1;
+		u32 AB_select                      : 1;
+		u32 extra_index_reg                : 3;
+		u32 index_reg                      : 5;
+	} index_reg_310;
+
+	struct {
+		u32 reserved                       :17;
+		u32 PID_enable_bit                 : 1;
+		u32 PID_trans                      : 1;
+		u32 PID                            :13;
+	} pid_n_reg_314;
+
+	struct {
+		u32 reserved                       : 6;
+		u32 HighAB_bit                     : 1;
+		u32 Enable_bit                     : 1;
+		u32 A6_byte                        : 8;
+		u32 A5_byte                        : 8;
+		u32 A4_byte                        : 8;
+	} mac_low_reg_318;
+
+	struct {
+		u32 reserved                       : 8;
+		u32 A3_byte                        : 8;
+		u32 A2_byte                        : 8;
+		u32 A1_byte                        : 8;
+	} mac_high_reg_31c;
+
+	struct {
+		u32 data_Tag_ID                    :16;
+		u32 reserved                       :16;
+	} data_tag_400;
+
+	struct {
+		u32 Card_IDbyte3                   : 8;
+		u32 Card_IDbyte4                   : 8;
+		u32 Card_IDbyte5                   : 8;
+		u32 Card_IDbyte6                   : 8;
+	} card_id_408;
+
+	struct {
+		u32 Card_IDbyte1                   : 8;
+		u32 Card_IDbyte2                   : 8;
+	} card_id_40c;
+
+	struct {
+		u32 MAC6                           : 8;
+		u32 MAC3                           : 8;
+		u32 MAC2                           : 8;
+		u32 MAC1                           : 8;
+	} mac_address_418;
+
+	struct {
+		u32 reserved                       :16;
+		u32 MAC8                           : 8;
+		u32 MAC7                           : 8;
+	} mac_address_41c;
+
+	struct {
+		u32 reserved                       :21;
+		u32 txbuffempty                    : 1;
+		u32 ReceiveByteFrameError          : 1;
+		u32 ReceiveDataReady               : 1;
+		u32 transmitter_data_byte          : 8;
+	} ci_600;
+
+	struct {
+		u32 pi_component_reg               : 3;
+		u32 pi_rw                          : 1;
+		u32 pi_ha                          :20;
+		u32 pi_d                           : 8;
+	} pi_604;
+
+	struct {
+		u32 pi_busy_n                      : 1;
+		u32 pi_wait_n                      : 1;
+		u32 pi_timeout_status              : 1;
+		u32 pi_CiMax_IRQ_n                 : 1;
+		u32 config_cclk                    : 1;
+		u32 config_cs_n                    : 1;
+		u32 config_wr_n                    : 1;
+		u32 config_Prog_n                  : 1;
+		u32 config_Init_stat               : 1;
+		u32 config_Done_stat               : 1;
+		u32 pcmcia_b_mod_pwr_n             : 1;
+		u32 pcmcia_a_mod_pwr_n             : 1;
+		u32 reserved                       : 3;
+		u32 Timer_addr                     : 5;
+		u32 unused                         : 1;
+		u32 timer_data                     : 7;
+		u32 Timer_Load_req                 : 1;
+		u32 Timer_Read_req                 : 1;
+		u32 oncecycle_read                 : 1;
+		u32 serialReset                    : 1;
+	} pi_608;
+
+	struct {
+		u32 reserved                       : 6;
+		u32 rw_flag                        : 1;
+		u32 dvb_en                         : 1;
+		u32 key_array_row                  : 5;
+		u32 key_array_col                  : 3;
+		u32 key_code                       : 2;
+		u32 key_enable                     : 1;
+		u32 PID                            :13;
+	} dvb_reg_60c;
+
+	struct {
+		u32 start_sram_ibi                 : 1;
+		u32 reserved2                      : 1;
+		u32 ce_pin_reg                     : 1;
+		u32 oe_pin_reg                     : 1;
+		u32 reserved1                      : 3;
+		u32 sc_xfer_bit                    : 1;
+		u32 sram_data                      : 8;
+		u32 sram_rw                        : 1;
+		u32 sram_addr                      :15;
+	} sram_ctrl_reg_700;
+
+	struct {
+		u32 net_addr_write                 :16;
+		u32 net_addr_read                  :16;
+	} net_buf_reg_704;
+
+	struct {
+		u32 cai_cnt                        : 4;
+		u32 reserved2                      : 6;
+		u32 cai_write                      :11;
+		u32 reserved1                      : 5;
+		u32 cai_read                       :11;
+	} cai_buf_reg_708;
+
+	struct {
+		u32 cao_cnt                        : 4;
+		u32 reserved2                      : 6;
+		u32 cap_write                      :11;
+		u32 reserved1                      : 5;
+		u32 cao_read                       :11;
+	} cao_buf_reg_70c;
+
+	struct {
+		u32 media_cnt                      : 4;
+		u32 reserved2                      : 6;
+		u32 media_write                    :11;
+		u32 reserved1                      : 5;
+		u32 media_read                     :11;
+	} media_buf_reg_710;
+
+	struct {
+		u32 reserved                       :17;
+		u32 ctrl_maximumfill               : 1;
+		u32 ctrl_sramdma                   : 1;
+		u32 ctrl_usb_wan                   : 1;
+		u32 cao_ovflow_error               : 1;
+		u32 cai_ovflow_error               : 1;
+		u32 media_ovflow_error             : 1;
+		u32 net_ovflow_error               : 1;
+		u32 MEDIA_Dest                     : 2;
+		u32 CAO_Dest                       : 2;
+		u32 CAI_Dest                       : 2;
+		u32 NET_Dest                       : 2;
+	} sram_dest_reg_714;
+
+	struct {
+		u32 reserved3                      :11;
+		u32 net_addr_write                 : 1;
+		u32 reserved2                      : 3;
+		u32 net_addr_read                  : 1;
+		u32 reserved1                      : 4;
+		u32 net_cnt                        :12;
+	} net_buf_reg_718;
+
+	struct {
+		u32 reserved3                      : 4;
+		u32 wan_pkt_frame                  : 4;
+		u32 reserved2                      : 4;
+		u32 sram_memmap                    : 2;
+		u32 sram_chip                      : 2;
+		u32 wan_wait_state                 : 8;
+		u32 reserved1                      : 6;
+		u32 wan_speed_sig                  : 2;
+	} wan_ctrl_reg_71c;
+} flexcop_ibi_value;
+
+#endif
diff --git a/drivers/media/common/b2c2/flexcop_ibi_value_le.h b/drivers/media/common/b2c2/flexcop_ibi_value_le.h
new file mode 100644
index 0000000..c75830d
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop_ibi_value_le.h
@@ -0,0 +1,455 @@
+/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * register descriptions
+ * see flexcop.c for copyright information
+ */
+/* This file is automatically generated, do not edit things here. */
+#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
+#define __FLEXCOP_IBI_VALUE_INCLUDED__
+
+typedef union {
+	u32 raw;
+
+	struct {
+		u32 dma_0start                     : 1;
+		u32 dma_0No_update                 : 1;
+		u32 dma_address0                   :30;
+	} dma_0x0;
+
+	struct {
+		u32 DMA_maxpackets                 : 8;
+		u32 dma_addr_size                  :24;
+	} dma_0x4_remap;
+
+	struct {
+		u32 dma1timer                      : 7;
+		u32 unused                         : 1;
+		u32 dma_addr_size                  :24;
+	} dma_0x4_read;
+
+	struct {
+		u32 unused                         : 1;
+		u32 dmatimer                       : 7;
+		u32 dma_addr_size                  :24;
+	} dma_0x4_write;
+
+	struct {
+		u32 unused                         : 2;
+		u32 dma_cur_addr                   :30;
+	} dma_0x8;
+
+	struct {
+		u32 dma_1start                     : 1;
+		u32 remap_enable                   : 1;
+		u32 dma_address1                   :30;
+	} dma_0xc;
+
+	struct {
+		u32 chipaddr                       : 7;
+		u32 reserved1                      : 1;
+		u32 baseaddr                       : 8;
+		u32 data1_reg                      : 8;
+		u32 working_start                  : 1;
+		u32 twoWS_rw                       : 1;
+		u32 total_bytes                    : 2;
+		u32 twoWS_port_reg                 : 2;
+		u32 no_base_addr_ack_error         : 1;
+		u32 st_done                        : 1;
+	} tw_sm_c_100;
+
+	struct {
+		u32 data2_reg                      : 8;
+		u32 data3_reg                      : 8;
+		u32 data4_reg                      : 8;
+		u32 exlicit_stops                  : 1;
+		u32 force_stop                     : 1;
+		u32 unused                         : 6;
+	} tw_sm_c_104;
+
+	struct {
+		u32 thi1                           : 6;
+		u32 reserved1                      : 2;
+		u32 tlo1                           : 5;
+		u32 reserved2                      :19;
+	} tw_sm_c_108;
+
+	struct {
+		u32 thi1                           : 6;
+		u32 reserved1                      : 2;
+		u32 tlo1                           : 5;
+		u32 reserved2                      :19;
+	} tw_sm_c_10c;
+
+	struct {
+		u32 thi1                           : 6;
+		u32 reserved1                      : 2;
+		u32 tlo1                           : 5;
+		u32 reserved2                      :19;
+	} tw_sm_c_110;
+
+	struct {
+		u32 LNB_CTLHighCount_sig           :15;
+		u32 LNB_CTLLowCount_sig            :15;
+		u32 LNB_CTLPrescaler_sig           : 2;
+	} lnb_switch_freq_200;
+
+	struct {
+		u32 ACPI1_sig                      : 1;
+		u32 ACPI3_sig                      : 1;
+		u32 LNB_L_H_sig                    : 1;
+		u32 Per_reset_sig                  : 1;
+		u32 reserved                       :20;
+		u32 Rev_N_sig_revision_hi          : 4;
+		u32 Rev_N_sig_reserved1            : 2;
+		u32 Rev_N_sig_caps                 : 1;
+		u32 Rev_N_sig_reserved2            : 1;
+	} misc_204;
+
+	struct {
+		u32 Stream1_filter_sig             : 1;
+		u32 Stream2_filter_sig             : 1;
+		u32 PCR_filter_sig                 : 1;
+		u32 PMT_filter_sig                 : 1;
+		u32 EMM_filter_sig                 : 1;
+		u32 ECM_filter_sig                 : 1;
+		u32 Null_filter_sig                : 1;
+		u32 Mask_filter_sig                : 1;
+		u32 WAN_Enable_sig                 : 1;
+		u32 WAN_CA_Enable_sig              : 1;
+		u32 CA_Enable_sig                  : 1;
+		u32 SMC_Enable_sig                 : 1;
+		u32 Per_CA_Enable_sig              : 1;
+		u32 Multi2_Enable_sig              : 1;
+		u32 MAC_filter_Mode_sig            : 1;
+		u32 Rcv_Data_sig                   : 1;
+		u32 DMA1_IRQ_Enable_sig            : 1;
+		u32 DMA1_Timer_Enable_sig          : 1;
+		u32 DMA2_IRQ_Enable_sig            : 1;
+		u32 DMA2_Timer_Enable_sig          : 1;
+		u32 DMA1_Size_IRQ_Enable_sig       : 1;
+		u32 DMA2_Size_IRQ_Enable_sig       : 1;
+		u32 Mailbox_from_V8_Enable_sig     : 1;
+		u32 unused                         : 9;
+	} ctrl_208;
+
+	struct {
+		u32 DMA1_IRQ_Status                : 1;
+		u32 DMA1_Timer_Status              : 1;
+		u32 DMA2_IRQ_Status                : 1;
+		u32 DMA2_Timer_Status              : 1;
+		u32 DMA1_Size_IRQ_Status           : 1;
+		u32 DMA2_Size_IRQ_Status           : 1;
+		u32 Mailbox_from_V8_Status_sig     : 1;
+		u32 Data_receiver_error            : 1;
+		u32 Continuity_error_flag          : 1;
+		u32 LLC_SNAP_FLAG_set              : 1;
+		u32 Transport_Error                : 1;
+		u32 reserved                       :21;
+	} irq_20c;
+
+	struct {
+		u32 reset_block_000                : 1;
+		u32 reset_block_100                : 1;
+		u32 reset_block_200                : 1;
+		u32 reset_block_300                : 1;
+		u32 reset_block_400                : 1;
+		u32 reset_block_500                : 1;
+		u32 reset_block_600                : 1;
+		u32 reset_block_700                : 1;
+		u32 Block_reset_enable             : 8;
+		u32 Special_controls               :16;
+	} sw_reset_210;
+
+	struct {
+		u32 vuart_oe_sig                   : 1;
+		u32 v2WS_oe_sig                    : 1;
+		u32 halt_V8_sig                    : 1;
+		u32 section_pkg_enable_sig         : 1;
+		u32 s2p_sel_sig                    : 1;
+		u32 unused1                        : 3;
+		u32 polarity_PS_CLK_sig            : 1;
+		u32 polarity_PS_VALID_sig          : 1;
+		u32 polarity_PS_SYNC_sig           : 1;
+		u32 polarity_PS_ERR_sig            : 1;
+		u32 unused2                        :20;
+	} misc_214;
+
+	struct {
+		u32 Mailbox_from_V8                :32;
+	} mbox_v8_to_host_218;
+
+	struct {
+		u32 sysramaccess_data              : 8;
+		u32 sysramaccess_addr              :15;
+		u32 unused                         : 7;
+		u32 sysramaccess_write             : 1;
+		u32 sysramaccess_busmuster         : 1;
+	} mbox_host_to_v8_21c;
+
+	struct {
+		u32 Stream1_PID                    :13;
+		u32 Stream1_trans                  : 1;
+		u32 MAC_Multicast_filter           : 1;
+		u32 debug_flag_pid_saved           : 1;
+		u32 Stream2_PID                    :13;
+		u32 Stream2_trans                  : 1;
+		u32 debug_flag_write_status00      : 1;
+		u32 debug_fifo_problem             : 1;
+	} pid_filter_300;
+
+	struct {
+		u32 PCR_PID                        :13;
+		u32 PCR_trans                      : 1;
+		u32 debug_overrun3                 : 1;
+		u32 debug_overrun2                 : 1;
+		u32 PMT_PID                        :13;
+		u32 PMT_trans                      : 1;
+		u32 reserved                       : 2;
+	} pid_filter_304;
+
+	struct {
+		u32 EMM_PID                        :13;
+		u32 EMM_trans                      : 1;
+		u32 EMM_filter_4                   : 1;
+		u32 EMM_filter_6                   : 1;
+		u32 ECM_PID                        :13;
+		u32 ECM_trans                      : 1;
+		u32 reserved                       : 2;
+	} pid_filter_308;
+
+	struct {
+		u32 Group_PID                      :13;
+		u32 Group_trans                    : 1;
+		u32 unused1                        : 2;
+		u32 Group_mask                     :13;
+		u32 unused2                        : 3;
+	} pid_filter_30c_ext_ind_0_7;
+
+	struct {
+		u32 net_master_read                :17;
+		u32 unused                         :15;
+	} pid_filter_30c_ext_ind_1;
+
+	struct {
+		u32 net_master_write               :17;
+		u32 unused                         :15;
+	} pid_filter_30c_ext_ind_2;
+
+	struct {
+		u32 next_net_master_write          :17;
+		u32 unused                         :15;
+	} pid_filter_30c_ext_ind_3;
+
+	struct {
+		u32 unused1                        : 1;
+		u32 state_write                    :10;
+		u32 reserved1                      : 6;
+		u32 stack_read                     :10;
+		u32 reserved2                      : 5;
+	} pid_filter_30c_ext_ind_4;
+
+	struct {
+		u32 stack_cnt                      :10;
+		u32 unused                         :22;
+	} pid_filter_30c_ext_ind_5;
+
+	struct {
+		u32 pid_fsm_save_reg0              : 2;
+		u32 pid_fsm_save_reg1              : 2;
+		u32 pid_fsm_save_reg2              : 2;
+		u32 pid_fsm_save_reg3              : 2;
+		u32 pid_fsm_save_reg4              : 2;
+		u32 pid_fsm_save_reg300            : 2;
+		u32 write_status1                  : 2;
+		u32 write_status4                  : 2;
+		u32 data_size_reg                  :12;
+		u32 unused                         : 4;
+	} pid_filter_30c_ext_ind_6;
+
+	struct {
+		u32 index_reg                      : 5;
+		u32 extra_index_reg                : 3;
+		u32 AB_select                      : 1;
+		u32 pass_alltables                 : 1;
+		u32 unused                         :22;
+	} index_reg_310;
+
+	struct {
+		u32 PID                            :13;
+		u32 PID_trans                      : 1;
+		u32 PID_enable_bit                 : 1;
+		u32 reserved                       :17;
+	} pid_n_reg_314;
+
+	struct {
+		u32 A4_byte                        : 8;
+		u32 A5_byte                        : 8;
+		u32 A6_byte                        : 8;
+		u32 Enable_bit                     : 1;
+		u32 HighAB_bit                     : 1;
+		u32 reserved                       : 6;
+	} mac_low_reg_318;
+
+	struct {
+		u32 A1_byte                        : 8;
+		u32 A2_byte                        : 8;
+		u32 A3_byte                        : 8;
+		u32 reserved                       : 8;
+	} mac_high_reg_31c;
+
+	struct {
+		u32 reserved                       :16;
+		u32 data_Tag_ID                    :16;
+	} data_tag_400;
+
+	struct {
+		u32 Card_IDbyte6                   : 8;
+		u32 Card_IDbyte5                   : 8;
+		u32 Card_IDbyte4                   : 8;
+		u32 Card_IDbyte3                   : 8;
+	} card_id_408;
+
+	struct {
+		u32 Card_IDbyte2                   : 8;
+		u32 Card_IDbyte1                   : 8;
+	} card_id_40c;
+
+	struct {
+		u32 MAC1                           : 8;
+		u32 MAC2                           : 8;
+		u32 MAC3                           : 8;
+		u32 MAC6                           : 8;
+	} mac_address_418;
+
+	struct {
+		u32 MAC7                           : 8;
+		u32 MAC8                           : 8;
+		u32 reserved                       :16;
+	} mac_address_41c;
+
+	struct {
+		u32 transmitter_data_byte          : 8;
+		u32 ReceiveDataReady               : 1;
+		u32 ReceiveByteFrameError          : 1;
+		u32 txbuffempty                    : 1;
+		u32 reserved                       :21;
+	} ci_600;
+
+	struct {
+		u32 pi_d                           : 8;
+		u32 pi_ha                          :20;
+		u32 pi_rw                          : 1;
+		u32 pi_component_reg               : 3;
+	} pi_604;
+
+	struct {
+		u32 serialReset                    : 1;
+		u32 oncecycle_read                 : 1;
+		u32 Timer_Read_req                 : 1;
+		u32 Timer_Load_req                 : 1;
+		u32 timer_data                     : 7;
+		u32 unused                         : 1;
+		u32 Timer_addr                     : 5;
+		u32 reserved                       : 3;
+		u32 pcmcia_a_mod_pwr_n             : 1;
+		u32 pcmcia_b_mod_pwr_n             : 1;
+		u32 config_Done_stat               : 1;
+		u32 config_Init_stat               : 1;
+		u32 config_Prog_n                  : 1;
+		u32 config_wr_n                    : 1;
+		u32 config_cs_n                    : 1;
+		u32 config_cclk                    : 1;
+		u32 pi_CiMax_IRQ_n                 : 1;
+		u32 pi_timeout_status              : 1;
+		u32 pi_wait_n                      : 1;
+		u32 pi_busy_n                      : 1;
+	} pi_608;
+
+	struct {
+		u32 PID                            :13;
+		u32 key_enable                     : 1;
+		u32 key_code                       : 2;
+		u32 key_array_col                  : 3;
+		u32 key_array_row                  : 5;
+		u32 dvb_en                         : 1;
+		u32 rw_flag                        : 1;
+		u32 reserved                       : 6;
+	} dvb_reg_60c;
+
+	struct {
+		u32 sram_addr                      :15;
+		u32 sram_rw                        : 1;
+		u32 sram_data                      : 8;
+		u32 sc_xfer_bit                    : 1;
+		u32 reserved1                      : 3;
+		u32 oe_pin_reg                     : 1;
+		u32 ce_pin_reg                     : 1;
+		u32 reserved2                      : 1;
+		u32 start_sram_ibi                 : 1;
+	} sram_ctrl_reg_700;
+
+	struct {
+		u32 net_addr_read                  :16;
+		u32 net_addr_write                 :16;
+	} net_buf_reg_704;
+
+	struct {
+		u32 cai_read                       :11;
+		u32 reserved1                      : 5;
+		u32 cai_write                      :11;
+		u32 reserved2                      : 6;
+		u32 cai_cnt                        : 4;
+	} cai_buf_reg_708;
+
+	struct {
+		u32 cao_read                       :11;
+		u32 reserved1                      : 5;
+		u32 cap_write                      :11;
+		u32 reserved2                      : 6;
+		u32 cao_cnt                        : 4;
+	} cao_buf_reg_70c;
+
+	struct {
+		u32 media_read                     :11;
+		u32 reserved1                      : 5;
+		u32 media_write                    :11;
+		u32 reserved2                      : 6;
+		u32 media_cnt                      : 4;
+	} media_buf_reg_710;
+
+	struct {
+		u32 NET_Dest                       : 2;
+		u32 CAI_Dest                       : 2;
+		u32 CAO_Dest                       : 2;
+		u32 MEDIA_Dest                     : 2;
+		u32 net_ovflow_error               : 1;
+		u32 media_ovflow_error             : 1;
+		u32 cai_ovflow_error               : 1;
+		u32 cao_ovflow_error               : 1;
+		u32 ctrl_usb_wan                   : 1;
+		u32 ctrl_sramdma                   : 1;
+		u32 ctrl_maximumfill               : 1;
+		u32 reserved                       :17;
+	} sram_dest_reg_714;
+
+	struct {
+		u32 net_cnt                        :12;
+		u32 reserved1                      : 4;
+		u32 net_addr_read                  : 1;
+		u32 reserved2                      : 3;
+		u32 net_addr_write                 : 1;
+		u32 reserved3                      :11;
+	} net_buf_reg_718;
+
+	struct {
+		u32 wan_speed_sig                  : 2;
+		u32 reserved1                      : 6;
+		u32 wan_wait_state                 : 8;
+		u32 sram_chip                      : 2;
+		u32 sram_memmap                    : 2;
+		u32 reserved2                      : 4;
+		u32 wan_pkt_frame                  : 4;
+		u32 reserved3                      : 4;
+	} wan_ctrl_reg_71c;
+} flexcop_ibi_value;
+
+#endif
diff --git a/drivers/media/common/saa7146/Kconfig b/drivers/media/common/saa7146/Kconfig
new file mode 100644
index 0000000..769c6f8
--- /dev/null
+++ b/drivers/media/common/saa7146/Kconfig
@@ -0,0 +1,9 @@
+config VIDEO_SAA7146
+	tristate
+	depends on I2C && PCI
+
+config VIDEO_SAA7146_VV
+	tristate
+	depends on VIDEO_V4L2
+	select VIDEOBUF_DMA_SG
+	select VIDEO_SAA7146
diff --git a/drivers/media/common/saa7146/Makefile b/drivers/media/common/saa7146/Makefile
new file mode 100644
index 0000000..3219b00
--- /dev/null
+++ b/drivers/media/common/saa7146/Makefile
@@ -0,0 +1,5 @@
+saa7146-objs    := saa7146_i2c.o saa7146_core.o
+saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
+
+obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
+obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o
diff --git a/drivers/media/common/saa7146/saa7146_core.c b/drivers/media/common/saa7146/saa7146_core.c
new file mode 100644
index 0000000..bb6ee51
--- /dev/null
+++ b/drivers/media/common/saa7146/saa7146_core.c
@@ -0,0 +1,592 @@
+/*
+    saa7146.o - driver for generic saa7146-based hardware
+
+    Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <media/saa7146.h>
+#include <linux/module.h>
+
+static int saa7146_num;
+
+unsigned int saa7146_debug;
+
+module_param(saa7146_debug, uint, 0644);
+MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");
+
+#if 0
+static void dump_registers(struct saa7146_dev* dev)
+{
+	int i = 0;
+
+	pr_info(" @ %li jiffies:\n", jiffies);
+	for (i = 0; i <= 0x148; i += 4)
+		pr_info("0x%03x: 0x%08x\n", i, saa7146_read(dev, i));
+}
+#endif
+
+/****************************************************************************
+ * gpio and debi helper functions
+ ****************************************************************************/
+
+void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
+{
+	u32 value = 0;
+
+	BUG_ON(port > 3);
+
+	value = saa7146_read(dev, GPIO_CTRL);
+	value &= ~(0xff << (8*port));
+	value |= (data << (8*port));
+	saa7146_write(dev, GPIO_CTRL, value);
+}
+
+/* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */
+static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev,
+				unsigned long us1, unsigned long us2)
+{
+	unsigned long timeout;
+	int err;
+
+	/* wait for registers to be programmed */
+	timeout = jiffies + usecs_to_jiffies(us1);
+	while (1) {
+		err = time_after(jiffies, timeout);
+		if (saa7146_read(dev, MC2) & 2)
+			break;
+		if (err) {
+			pr_err("%s: %s timed out while waiting for registers getting programmed\n",
+			       dev->name, __func__);
+			return -ETIMEDOUT;
+		}
+		msleep(1);
+	}
+
+	/* wait for transfer to complete */
+	timeout = jiffies + usecs_to_jiffies(us2);
+	while (1) {
+		err = time_after(jiffies, timeout);
+		if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
+			break;
+		saa7146_read(dev, MC2);
+		if (err) {
+			DEB_S("%s: %s timed out while waiting for transfer completion\n",
+			      dev->name, __func__);
+			return -ETIMEDOUT;
+		}
+		msleep(1);
+	}
+
+	return 0;
+}
+
+static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev,
+				unsigned long us1, unsigned long us2)
+{
+	unsigned long loops;
+
+	/* wait for registers to be programmed */
+	loops = us1;
+	while (1) {
+		if (saa7146_read(dev, MC2) & 2)
+			break;
+		if (!loops--) {
+			pr_err("%s: %s timed out while waiting for registers getting programmed\n",
+			       dev->name, __func__);
+			return -ETIMEDOUT;
+		}
+		udelay(1);
+	}
+
+	/* wait for transfer to complete */
+	loops = us2 / 5;
+	while (1) {
+		if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
+			break;
+		saa7146_read(dev, MC2);
+		if (!loops--) {
+			DEB_S("%s: %s timed out while waiting for transfer completion\n",
+			      dev->name, __func__);
+			return -ETIMEDOUT;
+		}
+		udelay(5);
+	}
+
+	return 0;
+}
+
+int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
+{
+	if (nobusyloop)
+		return saa7146_wait_for_debi_done_sleep(dev, 50000, 250000);
+	else
+		return saa7146_wait_for_debi_done_busyloop(dev, 50000, 250000);
+}
+
+/****************************************************************************
+ * general helper functions
+ ****************************************************************************/
+
+/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c
+   make sure virt has been allocated with vmalloc_32(), otherwise the BUG()
+   may be triggered on highmem machines */
+static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
+{
+	struct scatterlist *sglist;
+	struct page *pg;
+	int i;
+
+	sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
+	if (NULL == sglist)
+		return NULL;
+	sg_init_table(sglist, nr_pages);
+	for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
+		pg = vmalloc_to_page(virt);
+		if (NULL == pg)
+			goto err;
+		BUG_ON(PageHighMem(pg));
+		sg_set_page(&sglist[i], pg, PAGE_SIZE, 0);
+	}
+	return sglist;
+
+ err:
+	kfree(sglist);
+	return NULL;
+}
+
+/********************************************************************************/
+/* common page table functions */
+
+void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
+{
+	int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;
+	void *mem = vmalloc_32(length);
+	int slen = 0;
+
+	if (NULL == mem)
+		goto err_null;
+
+	if (!(pt->slist = vmalloc_to_sg(mem, pages)))
+		goto err_free_mem;
+
+	if (saa7146_pgtable_alloc(pci, pt))
+		goto err_free_slist;
+
+	pt->nents = pages;
+	slen = pci_map_sg(pci,pt->slist,pt->nents,PCI_DMA_FROMDEVICE);
+	if (0 == slen)
+		goto err_free_pgtable;
+
+	if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen))
+		goto err_unmap_sg;
+
+	return mem;
+
+err_unmap_sg:
+	pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
+err_free_pgtable:
+	saa7146_pgtable_free(pci, pt);
+err_free_slist:
+	kfree(pt->slist);
+	pt->slist = NULL;
+err_free_mem:
+	vfree(mem);
+err_null:
+	return NULL;
+}
+
+void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt)
+{
+	pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
+	saa7146_pgtable_free(pci, pt);
+	kfree(pt->slist);
+	pt->slist = NULL;
+	vfree(mem);
+}
+
+void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt)
+{
+	if (NULL == pt->cpu)
+		return;
+	pci_free_consistent(pci, pt->size, pt->cpu, pt->dma);
+	pt->cpu = NULL;
+}
+
+int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
+{
+	__le32       *cpu;
+	dma_addr_t   dma_addr = 0;
+
+	cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
+	if (NULL == cpu) {
+		return -ENOMEM;
+	}
+	pt->size = PAGE_SIZE;
+	pt->cpu  = cpu;
+	pt->dma  = dma_addr;
+
+	return 0;
+}
+
+int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt,
+	struct scatterlist *list, int sglen  )
+{
+	__le32 *ptr, fill;
+	int nr_pages = 0;
+	int i,p;
+
+	BUG_ON(0 == sglen);
+	BUG_ON(list->offset > PAGE_SIZE);
+
+	/* if we have a user buffer, the first page may not be
+	   aligned to a page boundary. */
+	pt->offset = list->offset;
+
+	ptr = pt->cpu;
+	for (i = 0; i < sglen; i++, list++) {
+/*
+		pr_debug("i:%d, adr:0x%08x, len:%d, offset:%d\n",
+			 i, sg_dma_address(list), sg_dma_len(list),
+			 list->offset);
+*/
+		for (p = 0; p * 4096 < list->length; p++, ptr++) {
+			*ptr = cpu_to_le32(sg_dma_address(list) + p * 4096);
+			nr_pages++;
+		}
+	}
+
+
+	/* safety; fill the page table up with the last valid page */
+	fill = *(ptr-1);
+	for(i=nr_pages;i<1024;i++) {
+		*ptr++ = fill;
+	}
+
+/*
+	ptr = pt->cpu;
+	pr_debug("offset: %d\n", pt->offset);
+	for(i=0;i<5;i++) {
+		pr_debug("ptr1 %d: 0x%08x\n", i, ptr[i]);
+	}
+*/
+	return 0;
+}
+
+/********************************************************************************/
+/* interrupt handler */
+static irqreturn_t interrupt_hw(int irq, void *dev_id)
+{
+	struct saa7146_dev *dev = dev_id;
+	u32 isr;
+	u32 ack_isr;
+
+	/* read out the interrupt status register */
+	ack_isr = isr = saa7146_read(dev, ISR);
+
+	/* is this our interrupt? */
+	if ( 0 == isr ) {
+		/* nope, some other device */
+		return IRQ_NONE;
+	}
+
+	if (dev->ext) {
+		if (dev->ext->irq_mask & isr) {
+			if (dev->ext->irq_func)
+				dev->ext->irq_func(dev, &isr);
+			isr &= ~dev->ext->irq_mask;
+		}
+	}
+	if (0 != (isr & (MASK_27))) {
+		DEB_INT("irq: RPS0 (0x%08x)\n", isr);
+		if (dev->vv_data && dev->vv_callback)
+			dev->vv_callback(dev,isr);
+		isr &= ~MASK_27;
+	}
+	if (0 != (isr & (MASK_28))) {
+		if (dev->vv_data && dev->vv_callback)
+			dev->vv_callback(dev,isr);
+		isr &= ~MASK_28;
+	}
+	if (0 != (isr & (MASK_16|MASK_17))) {
+		SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
+		/* only wake up if we expect something */
+		if (0 != dev->i2c_op) {
+			dev->i2c_op = 0;
+			wake_up(&dev->i2c_wq);
+		} else {
+			u32 psr = saa7146_read(dev, PSR);
+			u32 ssr = saa7146_read(dev, SSR);
+			pr_warn("%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",
+				dev->name, isr, psr, ssr);
+		}
+		isr &= ~(MASK_16|MASK_17);
+	}
+	if( 0 != isr ) {
+		ERR("warning: interrupt enabled, but not handled properly.(0x%08x)\n",
+		    isr);
+		ERR("disabling interrupt source(s)!\n");
+		SAA7146_IER_DISABLE(dev,isr);
+	}
+	saa7146_write(dev, ISR, ack_isr);
+	return IRQ_HANDLED;
+}
+
+/*********************************************************************************/
+/* configuration-functions                                                       */
+
+static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent)
+{
+	struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data;
+	struct saa7146_extension *ext = pci_ext->ext;
+	struct saa7146_dev *dev;
+	int err = -ENOMEM;
+
+	/* clear out mem for sure */
+	dev = kzalloc(sizeof(struct saa7146_dev), GFP_KERNEL);
+	if (!dev) {
+		ERR("out of memory\n");
+		goto out;
+	}
+
+	DEB_EE("pci:%p\n", pci);
+
+	err = pci_enable_device(pci);
+	if (err < 0) {
+		ERR("pci_enable_device() failed\n");
+		goto err_free;
+	}
+
+	/* enable bus-mastering */
+	pci_set_master(pci);
+
+	dev->pci = pci;
+
+	/* get chip-revision; this is needed to enable bug-fixes */
+	dev->revision = pci->revision;
+
+	/* remap the memory from virtual to physical address */
+
+	err = pci_request_region(pci, 0, "saa7146");
+	if (err < 0)
+		goto err_disable;
+
+	dev->mem = ioremap(pci_resource_start(pci, 0),
+			   pci_resource_len(pci, 0));
+	if (!dev->mem) {
+		ERR("ioremap() failed\n");
+		err = -ENODEV;
+		goto err_release;
+	}
+
+	/* we don't do a master reset here anymore, it screws up
+	   some boards that don't have an i2c-eeprom for configuration
+	   values */
+/*
+	saa7146_write(dev, MC1, MASK_31);
+*/
+
+	/* disable all irqs */
+	saa7146_write(dev, IER, 0);
+
+	/* shut down all dma transfers and rps tasks */
+	saa7146_write(dev, MC1, 0x30ff0000);
+
+	/* clear out any rps-signals pending */
+	saa7146_write(dev, MC2, 0xf8000000);
+
+	/* request an interrupt for the saa7146 */
+	err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED | IRQF_DISABLED,
+			  dev->name, dev);
+	if (err < 0) {
+		ERR("request_irq() failed\n");
+		goto err_unmap;
+	}
+
+	err = -ENOMEM;
+
+	/* get memory for various stuff */
+	dev->d_rps0.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
+						    &dev->d_rps0.dma_handle);
+	if (!dev->d_rps0.cpu_addr)
+		goto err_free_irq;
+	memset(dev->d_rps0.cpu_addr, 0x0, SAA7146_RPS_MEM);
+
+	dev->d_rps1.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
+						    &dev->d_rps1.dma_handle);
+	if (!dev->d_rps1.cpu_addr)
+		goto err_free_rps0;
+	memset(dev->d_rps1.cpu_addr, 0x0, SAA7146_RPS_MEM);
+
+	dev->d_i2c.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
+						   &dev->d_i2c.dma_handle);
+	if (!dev->d_i2c.cpu_addr)
+		goto err_free_rps1;
+	memset(dev->d_i2c.cpu_addr, 0x0, SAA7146_RPS_MEM);
+
+	/* the rest + print status message */
+
+	/* create a nice device name */
+	sprintf(dev->name, "saa7146 (%d)", saa7146_num);
+
+	pr_info("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x)\n",
+		dev->mem, dev->revision, pci->irq,
+		pci->subsystem_vendor, pci->subsystem_device);
+	dev->ext = ext;
+
+	mutex_init(&dev->v4l2_lock);
+	spin_lock_init(&dev->int_slock);
+	spin_lock_init(&dev->slock);
+
+	mutex_init(&dev->i2c_lock);
+
+	dev->module = THIS_MODULE;
+	init_waitqueue_head(&dev->i2c_wq);
+
+	/* set some sane pci arbitrition values */
+	saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
+
+	/* TODO: use the status code of the callback */
+
+	err = -ENODEV;
+
+	if (ext->probe && ext->probe(dev)) {
+		DEB_D("ext->probe() failed for %p. skipping device.\n", dev);
+		goto err_free_i2c;
+	}
+
+	if (ext->attach(dev, pci_ext)) {
+		DEB_D("ext->attach() failed for %p. skipping device.\n", dev);
+		goto err_free_i2c;
+	}
+	/* V4L extensions will set the pci drvdata to the v4l2_device in the
+	   attach() above. So for those cards that do not use V4L we have to
+	   set it explicitly. */
+	pci_set_drvdata(pci, &dev->v4l2_dev);
+
+	saa7146_num++;
+
+	err = 0;
+out:
+	return err;
+
+err_free_i2c:
+	pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr,
+			    dev->d_i2c.dma_handle);
+err_free_rps1:
+	pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr,
+			    dev->d_rps1.dma_handle);
+err_free_rps0:
+	pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr,
+			    dev->d_rps0.dma_handle);
+err_free_irq:
+	free_irq(pci->irq, (void *)dev);
+err_unmap:
+	iounmap(dev->mem);
+err_release:
+	pci_release_region(pci, 0);
+err_disable:
+	pci_disable_device(pci);
+err_free:
+	kfree(dev);
+	goto out;
+}
+
+static void saa7146_remove_one(struct pci_dev *pdev)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+	struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev);
+	struct {
+		void *addr;
+		dma_addr_t dma;
+	} dev_map[] = {
+		{ dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle },
+		{ dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle },
+		{ dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle },
+		{ NULL, 0 }
+	}, *p;
+
+	DEB_EE("dev:%p\n", dev);
+
+	dev->ext->detach(dev);
+	/* Zero the PCI drvdata after use. */
+	pci_set_drvdata(pdev, NULL);
+
+	/* shut down all video dma transfers */
+	saa7146_write(dev, MC1, 0x00ff0000);
+
+	/* disable all irqs, release irq-routine */
+	saa7146_write(dev, IER, 0);
+
+	free_irq(pdev->irq, dev);
+
+	for (p = dev_map; p->addr; p++)
+		pci_free_consistent(pdev, SAA7146_RPS_MEM, p->addr, p->dma);
+
+	iounmap(dev->mem);
+	pci_release_region(pdev, 0);
+	pci_disable_device(pdev);
+	kfree(dev);
+
+	saa7146_num--;
+}
+
+/*********************************************************************************/
+/* extension handling functions                                                  */
+
+int saa7146_register_extension(struct saa7146_extension* ext)
+{
+	DEB_EE("ext:%p\n", ext);
+
+	ext->driver.name = ext->name;
+	ext->driver.id_table = ext->pci_tbl;
+	ext->driver.probe = saa7146_init_one;
+	ext->driver.remove = saa7146_remove_one;
+
+	pr_info("register extension '%s'\n", ext->name);
+	return pci_register_driver(&ext->driver);
+}
+
+int saa7146_unregister_extension(struct saa7146_extension* ext)
+{
+	DEB_EE("ext:%p\n", ext);
+	pr_info("unregister extension '%s'\n", ext->name);
+	pci_unregister_driver(&ext->driver);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(saa7146_register_extension);
+EXPORT_SYMBOL_GPL(saa7146_unregister_extension);
+
+/* misc functions used by extension modules */
+EXPORT_SYMBOL_GPL(saa7146_pgtable_alloc);
+EXPORT_SYMBOL_GPL(saa7146_pgtable_free);
+EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single);
+EXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable);
+EXPORT_SYMBOL_GPL(saa7146_vfree_destroy_pgtable);
+EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done);
+
+EXPORT_SYMBOL_GPL(saa7146_setgpio);
+
+EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare);
+
+EXPORT_SYMBOL_GPL(saa7146_debug);
+
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_DESCRIPTION("driver for generic saa7146-based hardware");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c
new file mode 100644
index 0000000..b3890bd
--- /dev/null
+++ b/drivers/media/common/saa7146/saa7146_fops.c
@@ -0,0 +1,664 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <media/saa7146_vv.h>
+#include <linux/module.h>
+
+/****************************************************************************/
+/* resource management functions, shamelessly stolen from saa7134 driver */
+
+int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
+{
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+
+	if (fh->resources & bit) {
+		DEB_D("already allocated! want: 0x%02x, cur:0x%02x\n",
+		      bit, vv->resources);
+		/* have it already allocated */
+		return 1;
+	}
+
+	/* is it free? */
+	if (vv->resources & bit) {
+		DEB_D("locked! vv->resources:0x%02x, we want:0x%02x\n",
+		      vv->resources, bit);
+		/* no, someone else uses it */
+		return 0;
+	}
+	/* it's free, grab it */
+	fh->resources |= bit;
+	vv->resources |= bit;
+	DEB_D("res: get 0x%02x, cur:0x%02x\n", bit, vv->resources);
+	return 1;
+}
+
+void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
+{
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+
+	BUG_ON((fh->resources & bits) != bits);
+
+	fh->resources &= ~bits;
+	vv->resources &= ~bits;
+	DEB_D("res: put 0x%02x, cur:0x%02x\n", bits, vv->resources);
+}
+
+
+/********************************************************************************/
+/* common dma functions */
+
+void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
+						struct saa7146_buf *buf)
+{
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+	DEB_EE("dev:%p, buf:%p\n", dev, buf);
+
+	BUG_ON(in_interrupt());
+
+	videobuf_waiton(q, &buf->vb, 0, 0);
+	videobuf_dma_unmap(q->dev, dma);
+	videobuf_dma_free(dma);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+
+/********************************************************************************/
+/* common buffer functions */
+
+int saa7146_buffer_queue(struct saa7146_dev *dev,
+			 struct saa7146_dmaqueue *q,
+			 struct saa7146_buf *buf)
+{
+	assert_spin_locked(&dev->slock);
+	DEB_EE("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf);
+
+	BUG_ON(!q);
+
+	if (NULL == q->curr) {
+		q->curr = buf;
+		DEB_D("immediately activating buffer %p\n", buf);
+		buf->activate(dev,buf,NULL);
+	} else {
+		list_add_tail(&buf->vb.queue,&q->queue);
+		buf->vb.state = VIDEOBUF_QUEUED;
+		DEB_D("adding buffer %p to queue. (active buffer present)\n",
+		      buf);
+	}
+	return 0;
+}
+
+void saa7146_buffer_finish(struct saa7146_dev *dev,
+			   struct saa7146_dmaqueue *q,
+			   int state)
+{
+	assert_spin_locked(&dev->slock);
+	DEB_EE("dev:%p, dmaq:%p, state:%d\n", dev, q, state);
+	DEB_EE("q->curr:%p\n", q->curr);
+
+	BUG_ON(!q->curr);
+
+	/* finish current buffer */
+	if (NULL == q->curr) {
+		DEB_D("aiii. no current buffer\n");
+		return;
+	}
+
+	q->curr->vb.state = state;
+	do_gettimeofday(&q->curr->vb.ts);
+	wake_up(&q->curr->vb.done);
+
+	q->curr = NULL;
+}
+
+void saa7146_buffer_next(struct saa7146_dev *dev,
+			 struct saa7146_dmaqueue *q, int vbi)
+{
+	struct saa7146_buf *buf,*next = NULL;
+
+	BUG_ON(!q);
+
+	DEB_INT("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi);
+
+	assert_spin_locked(&dev->slock);
+	if (!list_empty(&q->queue)) {
+		/* activate next one from queue */
+		buf = list_entry(q->queue.next,struct saa7146_buf,vb.queue);
+		list_del(&buf->vb.queue);
+		if (!list_empty(&q->queue))
+			next = list_entry(q->queue.next,struct saa7146_buf, vb.queue);
+		q->curr = buf;
+		DEB_INT("next buffer: buf:%p, prev:%p, next:%p\n",
+			buf, q->queue.prev, q->queue.next);
+		buf->activate(dev,buf,next);
+	} else {
+		DEB_INT("no next buffer. stopping.\n");
+		if( 0 != vbi ) {
+			/* turn off video-dma3 */
+			saa7146_write(dev,MC1, MASK_20);
+		} else {
+			/* nothing to do -- just prevent next video-dma1 transfer
+			   by lowering the protection address */
+
+			// fixme: fix this for vflip != 0
+
+			saa7146_write(dev, PROT_ADDR1, 0);
+			saa7146_write(dev, MC2, (MASK_02|MASK_18));
+
+			/* write the address of the rps-program */
+			saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle);
+			/* turn on rps */
+			saa7146_write(dev, MC1, (MASK_12 | MASK_28));
+
+/*
+			printk("vdma%d.base_even:     0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1));
+			printk("vdma%d.base_odd:      0x%08x\n", 1,saa7146_read(dev,BASE_ODD1));
+			printk("vdma%d.prot_addr:     0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1));
+			printk("vdma%d.base_page:     0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1));
+			printk("vdma%d.pitch:         0x%08x\n", 1,saa7146_read(dev,PITCH1));
+			printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1));
+*/
+		}
+		del_timer(&q->timeout);
+	}
+}
+
+void saa7146_buffer_timeout(unsigned long data)
+{
+	struct saa7146_dmaqueue *q = (struct saa7146_dmaqueue*)data;
+	struct saa7146_dev *dev = q->dev;
+	unsigned long flags;
+
+	DEB_EE("dev:%p, dmaq:%p\n", dev, q);
+
+	spin_lock_irqsave(&dev->slock,flags);
+	if (q->curr) {
+		DEB_D("timeout on %p\n", q->curr);
+		saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR);
+	}
+
+	/* we don't restart the transfer here like other drivers do. when
+	   a streaming capture is disabled, the timeout function will be
+	   called for the current buffer. if we activate the next buffer now,
+	   we mess up our capture logic. if a timeout occurs on another buffer,
+	   then something is seriously broken before, so no need to buffer the
+	   next capture IMHO... */
+/*
+	saa7146_buffer_next(dev,q);
+*/
+	spin_unlock_irqrestore(&dev->slock,flags);
+}
+
+/********************************************************************************/
+/* file operations */
+
+static int fops_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct saa7146_dev *dev = video_drvdata(file);
+	struct saa7146_fh *fh = NULL;
+	int result = 0;
+
+	DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev));
+
+	if (mutex_lock_interruptible(vdev->lock))
+		return -ERESTARTSYS;
+
+	DEB_D("using: %p\n", dev);
+
+	/* check if an extension is registered */
+	if( NULL == dev->ext ) {
+		DEB_S("no extension registered for this device\n");
+		result = -ENODEV;
+		goto out;
+	}
+
+	/* allocate per open data */
+	fh = kzalloc(sizeof(*fh),GFP_KERNEL);
+	if (NULL == fh) {
+		DEB_S("cannot allocate memory for per open data\n");
+		result = -ENOMEM;
+		goto out;
+	}
+
+	v4l2_fh_init(&fh->fh, vdev);
+
+	file->private_data = &fh->fh;
+	fh->dev = dev;
+
+	if (vdev->vfl_type == VFL_TYPE_VBI) {
+		DEB_S("initializing vbi...\n");
+		if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+			result = saa7146_vbi_uops.open(dev,file);
+		if (dev->ext_vv_data->vbi_fops.open)
+			dev->ext_vv_data->vbi_fops.open(file);
+	} else {
+		DEB_S("initializing video...\n");
+		result = saa7146_video_uops.open(dev,file);
+	}
+
+	if (0 != result) {
+		goto out;
+	}
+
+	if( 0 == try_module_get(dev->ext->module)) {
+		result = -EINVAL;
+		goto out;
+	}
+
+	result = 0;
+	v4l2_fh_add(&fh->fh);
+out:
+	if (fh && result != 0) {
+		kfree(fh);
+		file->private_data = NULL;
+	}
+	mutex_unlock(vdev->lock);
+	return result;
+}
+
+static int fops_release(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct saa7146_fh  *fh  = file->private_data;
+	struct saa7146_dev *dev = fh->dev;
+
+	DEB_EE("file:%p\n", file);
+
+	if (mutex_lock_interruptible(vdev->lock))
+		return -ERESTARTSYS;
+
+	if (vdev->vfl_type == VFL_TYPE_VBI) {
+		if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+			saa7146_vbi_uops.release(dev,file);
+		if (dev->ext_vv_data->vbi_fops.release)
+			dev->ext_vv_data->vbi_fops.release(file);
+	} else {
+		saa7146_video_uops.release(dev,file);
+	}
+
+	v4l2_fh_del(&fh->fh);
+	v4l2_fh_exit(&fh->fh);
+	module_put(dev->ext->module);
+	file->private_data = NULL;
+	kfree(fh);
+
+	mutex_unlock(vdev->lock);
+
+	return 0;
+}
+
+static int fops_mmap(struct file *file, struct vm_area_struct * vma)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct saa7146_fh *fh = file->private_data;
+	struct videobuf_queue *q;
+	int res;
+
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_GRABBER: {
+		DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",
+		       file, vma);
+		q = &fh->video_q;
+		break;
+		}
+	case VFL_TYPE_VBI: {
+		DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",
+		       file, vma);
+		if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
+			return -ENODEV;
+		q = &fh->vbi_q;
+		break;
+		}
+	default:
+		BUG();
+		return 0;
+	}
+
+	if (mutex_lock_interruptible(vdev->lock))
+		return -ERESTARTSYS;
+	res = videobuf_mmap_mapper(q, vma);
+	mutex_unlock(vdev->lock);
+	return res;
+}
+
+static unsigned int __fops_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct saa7146_fh *fh = file->private_data;
+	struct videobuf_buffer *buf = NULL;
+	struct videobuf_queue *q;
+	unsigned int res = v4l2_ctrl_poll(file, wait);
+
+	DEB_EE("file:%p, poll:%p\n", file, wait);
+
+	if (vdev->vfl_type == VFL_TYPE_VBI) {
+		if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
+			return res | POLLOUT | POLLWRNORM;
+		if( 0 == fh->vbi_q.streaming )
+			return res | videobuf_poll_stream(file, &fh->vbi_q, wait);
+		q = &fh->vbi_q;
+	} else {
+		DEB_D("using video queue\n");
+		q = &fh->video_q;
+	}
+
+	if (!list_empty(&q->stream))
+		buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
+
+	if (!buf) {
+		DEB_D("buf == NULL!\n");
+		return res | POLLERR;
+	}
+
+	poll_wait(file, &buf->done, wait);
+	if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) {
+		DEB_D("poll succeeded!\n");
+		return res | POLLIN | POLLRDNORM;
+	}
+
+	DEB_D("nothing to poll for, buf->state:%d\n", buf->state);
+	return res;
+}
+
+static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct video_device *vdev = video_devdata(file);
+	unsigned int res;
+
+	mutex_lock(vdev->lock);
+	res = __fops_poll(file, wait);
+	mutex_unlock(vdev->lock);
+	return res;
+}
+
+static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct saa7146_fh *fh = file->private_data;
+	int ret;
+
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_GRABBER:
+/*
+		DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun",
+		       file, data, (unsigned long)count);
+*/
+		return saa7146_video_uops.read(file,data,count,ppos);
+	case VFL_TYPE_VBI:
+/*
+		DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n",
+		       file, data, (unsigned long)count);
+*/
+		if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) {
+			if (mutex_lock_interruptible(vdev->lock))
+				return -ERESTARTSYS;
+			ret = saa7146_vbi_uops.read(file, data, count, ppos);
+			mutex_unlock(vdev->lock);
+			return ret;
+		}
+		return -EINVAL;
+	default:
+		BUG();
+		return 0;
+	}
+}
+
+static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct saa7146_fh *fh = file->private_data;
+	int ret;
+
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_GRABBER:
+		return -EINVAL;
+	case VFL_TYPE_VBI:
+		if (fh->dev->ext_vv_data->vbi_fops.write) {
+			if (mutex_lock_interruptible(vdev->lock))
+				return -ERESTARTSYS;
+			ret = fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
+			mutex_unlock(vdev->lock);
+			return ret;
+		}
+		return -EINVAL;
+	default:
+		BUG();
+		return -EINVAL;
+	}
+}
+
+static const struct v4l2_file_operations video_fops =
+{
+	.owner		= THIS_MODULE,
+	.open		= fops_open,
+	.release	= fops_release,
+	.read		= fops_read,
+	.write		= fops_write,
+	.poll		= fops_poll,
+	.mmap		= fops_mmap,
+	.unlocked_ioctl	= video_ioctl2,
+};
+
+static void vv_callback(struct saa7146_dev *dev, unsigned long status)
+{
+	u32 isr = status;
+
+	DEB_INT("dev:%p, isr:0x%08x\n", dev, (u32)status);
+
+	if (0 != (isr & (MASK_27))) {
+		DEB_INT("irq: RPS0 (0x%08x)\n", isr);
+		saa7146_video_uops.irq_done(dev,isr);
+	}
+
+	if (0 != (isr & (MASK_28))) {
+		u32 mc2 = saa7146_read(dev, MC2);
+		if( 0 != (mc2 & MASK_15)) {
+			DEB_INT("irq: RPS1 vbi workaround (0x%08x)\n", isr);
+			wake_up(&dev->vv_data->vbi_wq);
+			saa7146_write(dev,MC2, MASK_31);
+			return;
+		}
+		DEB_INT("irq: RPS1 (0x%08x)\n", isr);
+		saa7146_vbi_uops.irq_done(dev,isr);
+	}
+}
+
+static const struct v4l2_ctrl_ops saa7146_ctrl_ops = {
+	.s_ctrl = saa7146_s_ctrl,
+};
+
+int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
+{
+	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
+	struct v4l2_pix_format *fmt;
+	struct v4l2_vbi_format *vbi;
+	struct saa7146_vv *vv;
+	int err;
+
+	err = v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev);
+	if (err)
+		return err;
+
+	v4l2_ctrl_handler_init(hdl, 6);
+	v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+		V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+		V4L2_CID_CONTRAST, 0, 127, 1, 64);
+	v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+		V4L2_CID_SATURATION, 0, 127, 1, 64);
+	v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+		V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+		V4L2_CID_HFLIP, 0, 1, 1, 0);
+	if (hdl->error) {
+		err = hdl->error;
+		v4l2_ctrl_handler_free(hdl);
+		return err;
+	}
+	dev->v4l2_dev.ctrl_handler = hdl;
+
+	vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
+	if (vv == NULL) {
+		ERR("out of memory. aborting.\n");
+		v4l2_ctrl_handler_free(hdl);
+		return -ENOMEM;
+	}
+	ext_vv->vid_ops = saa7146_video_ioctl_ops;
+	ext_vv->vbi_ops = saa7146_vbi_ioctl_ops;
+	ext_vv->core_ops = &saa7146_video_ioctl_ops;
+
+	DEB_EE("dev:%p\n", dev);
+
+	/* set default values for video parts of the saa7146 */
+	saa7146_write(dev, BCS_CTRL, 0x80400040);
+
+	/* enable video-port pins */
+	saa7146_write(dev, MC1, (MASK_10 | MASK_26));
+
+	/* save per-device extension data (one extension can
+	   handle different devices that might need different
+	   configuration data) */
+	dev->ext_vv_data = ext_vv;
+
+	vv->d_clipping.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, &vv->d_clipping.dma_handle);
+	if( NULL == vv->d_clipping.cpu_addr ) {
+		ERR("out of memory. aborting.\n");
+		kfree(vv);
+		v4l2_ctrl_handler_free(hdl);
+		return -1;
+	}
+	memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM);
+
+	saa7146_video_uops.init(dev,vv);
+	if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+		saa7146_vbi_uops.init(dev,vv);
+
+	fmt = &vv->ov_fb.fmt;
+	fmt->width = vv->standard->h_max_out;
+	fmt->height = vv->standard->v_max_out;
+	fmt->pixelformat = V4L2_PIX_FMT_RGB565;
+	fmt->bytesperline = 2 * fmt->width;
+	fmt->sizeimage = fmt->bytesperline * fmt->height;
+	fmt->colorspace = V4L2_COLORSPACE_SRGB;
+
+	fmt = &vv->video_fmt;
+	fmt->width = 384;
+	fmt->height = 288;
+	fmt->pixelformat = V4L2_PIX_FMT_BGR24;
+	fmt->field = V4L2_FIELD_ANY;
+	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	fmt->bytesperline = 3 * fmt->width;
+	fmt->sizeimage = fmt->bytesperline * fmt->height;
+
+	vbi = &vv->vbi_fmt;
+	vbi->sampling_rate	= 27000000;
+	vbi->offset		= 248; /* todo */
+	vbi->samples_per_line	= 720 * 2;
+	vbi->sample_format	= V4L2_PIX_FMT_GREY;
+
+	/* fixme: this only works for PAL */
+	vbi->start[0] = 5;
+	vbi->count[0] = 16;
+	vbi->start[1] = 312;
+	vbi->count[1] = 16;
+
+	init_timer(&vv->vbi_read_timeout);
+
+	vv->ov_fb.capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+	vv->ov_fb.flags = V4L2_FBUF_FLAG_PRIMARY;
+	dev->vv_data = vv;
+	dev->vv_callback = &vv_callback;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(saa7146_vv_init);
+
+int saa7146_vv_release(struct saa7146_dev* dev)
+{
+	struct saa7146_vv *vv = dev->vv_data;
+
+	DEB_EE("dev:%p\n", dev);
+
+	v4l2_device_unregister(&dev->v4l2_dev);
+	pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
+	v4l2_ctrl_handler_free(&dev->ctrl_handler);
+	kfree(vv);
+	dev->vv_data = NULL;
+	dev->vv_callback = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(saa7146_vv_release);
+
+int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
+			    char *name, int type)
+{
+	struct video_device *vfd;
+	int err;
+	int i;
+
+	DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type);
+
+	// released by vfd->release
+	vfd = video_device_alloc();
+	if (vfd == NULL)
+		return -ENOMEM;
+
+	vfd->fops = &video_fops;
+	if (type == VFL_TYPE_GRABBER)
+		vfd->ioctl_ops = &dev->ext_vv_data->vid_ops;
+	else
+		vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops;
+	vfd->release = video_device_release;
+	vfd->lock = &dev->v4l2_lock;
+	vfd->v4l2_dev = &dev->v4l2_dev;
+	vfd->tvnorms = 0;
+	set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+	for (i = 0; i < dev->ext_vv_data->num_stds; i++)
+		vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
+	strlcpy(vfd->name, name, sizeof(vfd->name));
+	video_set_drvdata(vfd, dev);
+
+	err = video_register_device(vfd, type, -1);
+	if (err < 0) {
+		ERR("cannot register v4l2 device. skipping.\n");
+		video_device_release(vfd);
+		return err;
+	}
+
+	pr_info("%s: registered device %s [v4l2]\n",
+		dev->name, video_device_node_name(vfd));
+
+	*vid = vfd;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(saa7146_register_device);
+
+int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
+{
+	DEB_EE("dev:%p\n", dev);
+
+	video_unregister_device(*vid);
+	*vid = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(saa7146_unregister_device);
+
+static int __init saa7146_vv_init_module(void)
+{
+	return 0;
+}
+
+
+static void __exit saa7146_vv_cleanup_module(void)
+{
+}
+
+module_init(saa7146_vv_init_module);
+module_exit(saa7146_vv_cleanup_module);
+
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_DESCRIPTION("video4linux driver for saa7146-based hardware");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/saa7146/saa7146_hlp.c b/drivers/media/common/saa7146/saa7146_hlp.c
new file mode 100644
index 0000000..be746d1
--- /dev/null
+++ b/drivers/media/common/saa7146/saa7146_hlp.c
@@ -0,0 +1,1048 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <media/saa7146_vv.h>
+
+static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format)
+{
+	/* clear out the necessary bits */
+	*clip_format &= 0x0000ffff;
+	/* set these bits new */
+	*clip_format |=  (( ((palette&0xf00)>>8) << 30) | ((palette&0x00f) << 24) | (((palette&0x0f0)>>4) << 16));
+}
+
+static void calculate_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync, u32* hps_ctrl)
+{
+	*hps_ctrl &= ~(MASK_30 | MASK_31 | MASK_28);
+	*hps_ctrl |= (source << 30) | (sync << 28);
+}
+
+static void calculate_hxo_and_hyo(struct saa7146_vv *vv, u32* hps_h_scale, u32* hps_ctrl)
+{
+	int hyo = 0, hxo = 0;
+
+	hyo = vv->standard->v_offset;
+	hxo = vv->standard->h_offset;
+
+	*hps_h_scale	&= ~(MASK_B0 | 0xf00);
+	*hps_h_scale	|= (hxo <<  0);
+
+	*hps_ctrl	&= ~(MASK_W0 | MASK_B2);
+	*hps_ctrl	|= (hyo << 12);
+}
+
+/* helper functions for the calculation of the horizontal- and vertical
+   scaling registers, clip-format-register etc ...
+   these functions take pointers to the (most-likely read-out
+   original-values) and manipulate them according to the requested
+   changes.
+*/
+
+/* hps_coeff used for CXY and CXUV; scale 1/1 -> scale 1/64 */
+static struct {
+	u16 hps_coeff;
+	u16 weight_sum;
+} hps_h_coeff_tab [] = {
+	{0x00,   2}, {0x02,   4}, {0x00,   4}, {0x06,   8}, {0x02,   8},
+	{0x08,   8}, {0x00,   8}, {0x1E,  16}, {0x0E,   8}, {0x26,   8},
+	{0x06,   8}, {0x42,   8}, {0x02,   8}, {0x80,   8}, {0x00,   8},
+	{0xFE,  16}, {0xFE,   8}, {0x7E,   8}, {0x7E,   8}, {0x3E,   8},
+	{0x3E,   8}, {0x1E,   8}, {0x1E,   8}, {0x0E,   8}, {0x0E,   8},
+	{0x06,   8}, {0x06,   8}, {0x02,   8}, {0x02,   8}, {0x00,   8},
+	{0x00,   8}, {0xFE,  16}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8},
+	{0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8},
+	{0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8},
+	{0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0x7E,   8},
+	{0x7E,   8}, {0x3E,   8}, {0x3E,   8}, {0x1E,   8}, {0x1E,   8},
+	{0x0E,   8}, {0x0E,   8}, {0x06,   8}, {0x06,   8}, {0x02,   8},
+	{0x02,   8}, {0x00,   8}, {0x00,   8}, {0xFE,  16}
+};
+
+/* table of attenuation values for horizontal scaling */
+static u8 h_attenuation[] = { 1, 2, 4, 8, 2, 4, 8, 16, 0};
+
+/* calculate horizontal scale registers */
+static int calculate_h_scale_registers(struct saa7146_dev *dev,
+	int in_x, int out_x, int flip_lr,
+	u32* hps_ctrl, u32* hps_v_gain, u32* hps_h_prescale, u32* hps_h_scale)
+{
+	/* horizontal prescaler */
+	u32 dcgx = 0, xpsc = 0, xacm = 0, cxy = 0, cxuv = 0;
+	/* horizontal scaler */
+	u32 xim = 0, xp = 0, xsci =0;
+	/* vertical scale & gain */
+	u32 pfuv = 0;
+
+	/* helper variables */
+	u32 h_atten = 0, i = 0;
+
+	if ( 0 == out_x ) {
+		return -EINVAL;
+	}
+
+	/* mask out vanity-bit */
+	*hps_ctrl &= ~MASK_29;
+
+	/* calculate prescale-(xspc)-value:	[n   .. 1/2) : 1
+						[1/2 .. 1/3) : 2
+						[1/3 .. 1/4) : 3
+						...		*/
+	if (in_x > out_x) {
+		xpsc = in_x / out_x;
+	}
+	else {
+		/* zooming */
+		xpsc = 1;
+	}
+
+	/* if flip_lr-bit is set, number of pixels after
+	   horizontal prescaling must be < 384 */
+	if ( 0 != flip_lr ) {
+
+		/* set vanity bit */
+		*hps_ctrl |= MASK_29;
+
+		while (in_x / xpsc >= 384 )
+			xpsc++;
+	}
+	/* if zooming is wanted, number of pixels after
+	   horizontal prescaling must be < 768 */
+	else {
+		while ( in_x / xpsc >= 768 )
+			xpsc++;
+	}
+
+	/* maximum prescale is 64 (p.69) */
+	if ( xpsc > 64 )
+		xpsc = 64;
+
+	/* keep xacm clear*/
+	xacm = 0;
+
+	/* set horizontal filter parameters (CXY = CXUV) */
+	cxy = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].hps_coeff;
+	cxuv = cxy;
+
+	/* calculate and set horizontal fine scale (xsci) */
+
+	/* bypass the horizontal scaler ? */
+	if ( (in_x == out_x) && ( 1 == xpsc ) )
+		xsci = 0x400;
+	else
+		xsci = ( (1024 * in_x) / (out_x * xpsc) ) + xpsc;
+
+	/* set start phase for horizontal fine scale (xp) to 0 */
+	xp = 0;
+
+	/* set xim, if we bypass the horizontal scaler */
+	if ( 0x400 == xsci )
+		xim = 1;
+	else
+		xim = 0;
+
+	/* if the prescaler is bypassed, enable horizontal
+	   accumulation mode (xacm) and clear dcgx */
+	if( 1 == xpsc ) {
+		xacm = 1;
+		dcgx = 0;
+	} else {
+		xacm = 0;
+		/* get best match in the table of attenuations
+		   for horizontal scaling */
+		h_atten = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].weight_sum;
+
+		for (i = 0; h_attenuation[i] != 0; i++) {
+			if (h_attenuation[i] >= h_atten)
+				break;
+		}
+
+		dcgx = i;
+	}
+
+	/* the horizontal scaling increment controls the UV filter
+	   to reduce the bandwidth to improve the display quality,
+	   so set it ... */
+	if ( xsci == 0x400)
+		pfuv = 0x00;
+	else if ( xsci < 0x600)
+		pfuv = 0x01;
+	else if ( xsci < 0x680)
+		pfuv = 0x11;
+	else if ( xsci < 0x700)
+		pfuv = 0x22;
+	else
+		pfuv = 0x33;
+
+
+	*hps_v_gain  &= MASK_W0|MASK_B2;
+	*hps_v_gain  |= (pfuv << 24);
+
+	*hps_h_scale	&= ~(MASK_W1 | 0xf000);
+	*hps_h_scale	|= (xim << 31) | (xp << 24) | (xsci << 12);
+
+	*hps_h_prescale	|= (dcgx << 27) | ((xpsc-1) << 18) | (xacm << 17) | (cxy << 8) | (cxuv << 0);
+
+	return 0;
+}
+
+static struct {
+	u16 hps_coeff;
+	u16 weight_sum;
+} hps_v_coeff_tab [] = {
+ {0x0100,   2},  {0x0102,   4},  {0x0300,   4},  {0x0106,   8},  {0x0502,   8},
+ {0x0708,   8},  {0x0F00,   8},  {0x011E,  16},  {0x110E,  16},  {0x1926,  16},
+ {0x3906,  16},  {0x3D42,  16},  {0x7D02,  16},  {0x7F80,  16},  {0xFF00,  16},
+ {0x01FE,  32},  {0x01FE,  32},  {0x817E,  32},  {0x817E,  32},  {0xC13E,  32},
+ {0xC13E,  32},  {0xE11E,  32},  {0xE11E,  32},  {0xF10E,  32},  {0xF10E,  32},
+ {0xF906,  32},  {0xF906,  32},  {0xFD02,  32},  {0xFD02,  32},  {0xFF00,  32},
+ {0xFF00,  32},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},
+ {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},
+ {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},
+ {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x817E,  64},
+ {0x817E,  64},  {0xC13E,  64},  {0xC13E,  64},  {0xE11E,  64},  {0xE11E,  64},
+ {0xF10E,  64},  {0xF10E,  64},  {0xF906,  64},  {0xF906,  64},  {0xFD02,  64},
+ {0xFD02,  64},  {0xFF00,  64},  {0xFF00,  64},  {0x01FE, 128}
+};
+
+/* table of attenuation values for vertical scaling */
+static u16 v_attenuation[] = { 2, 4, 8, 16, 32, 64, 128, 256, 0};
+
+/* calculate vertical scale registers */
+static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field field,
+	int in_y, int out_y, u32* hps_v_scale, u32* hps_v_gain)
+{
+	int lpi = 0;
+
+	/* vertical scaling */
+	u32 yacm = 0, ysci = 0, yacl = 0, ypo = 0, ype = 0;
+	/* vertical scale & gain */
+	u32 dcgy = 0, cya_cyb = 0;
+
+	/* helper variables */
+	u32 v_atten = 0, i = 0;
+
+	/* error, if vertical zooming */
+	if ( in_y < out_y ) {
+		return -EINVAL;
+	}
+
+	/* linear phase interpolation may be used
+	   if scaling is between 1 and 1/2 (both fields used)
+	   or scaling is between 1/2 and 1/4 (if only one field is used) */
+
+	if (V4L2_FIELD_HAS_BOTH(field)) {
+		if( 2*out_y >= in_y) {
+			lpi = 1;
+		}
+	} else if (field == V4L2_FIELD_TOP
+		|| field == V4L2_FIELD_ALTERNATE
+		|| field == V4L2_FIELD_BOTTOM) {
+		if( 4*out_y >= in_y ) {
+			lpi = 1;
+		}
+		out_y *= 2;
+	}
+	if( 0 != lpi ) {
+
+		yacm = 0;
+		yacl = 0;
+		cya_cyb = 0x00ff;
+
+		/* calculate scaling increment */
+		if ( in_y > out_y )
+			ysci = ((1024 * in_y) / (out_y + 1)) - 1024;
+		else
+			ysci = 0;
+
+		dcgy = 0;
+
+		/* calculate ype and ypo */
+		ype = ysci / 16;
+		ypo = ype + (ysci / 64);
+
+	} else {
+		yacm = 1;
+
+		/* calculate scaling increment */
+		ysci = (((10 * 1024 * (in_y - out_y - 1)) / in_y) + 9) / 10;
+
+		/* calculate ype and ypo */
+		ypo = ype = ((ysci + 15) / 16);
+
+		/* the sequence length interval (yacl) has to be set according
+		   to the prescale value, e.g.	[n   .. 1/2) : 0
+						[1/2 .. 1/3) : 1
+						[1/3 .. 1/4) : 2
+						... */
+		if ( ysci < 512) {
+			yacl = 0;
+		} else {
+			yacl = ( ysci / (1024 - ysci) );
+		}
+
+		/* get filter coefficients for cya, cyb from table hps_v_coeff_tab */
+		cya_cyb = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].hps_coeff;
+
+		/* get best match in the table of attenuations for vertical scaling */
+		v_atten = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].weight_sum;
+
+		for (i = 0; v_attenuation[i] != 0; i++) {
+			if (v_attenuation[i] >= v_atten)
+				break;
+		}
+
+		dcgy = i;
+	}
+
+	/* ypo and ype swapped in spec ? */
+	*hps_v_scale	|= (yacm << 31) | (ysci << 21) | (yacl << 15) | (ypo << 8 ) | (ype << 1);
+
+	*hps_v_gain	&= ~(MASK_W0|MASK_B2);
+	*hps_v_gain	|= (dcgy << 16) | (cya_cyb << 0);
+
+	return 0;
+}
+
+/* simple bubble-sort algorithm with duplicate elimination */
+static int sort_and_eliminate(u32* values, int* count)
+{
+	int low = 0, high = 0, top = 0, temp = 0;
+	int cur = 0, next = 0;
+
+	/* sanity checks */
+	if( (0 > *count) || (NULL == values) ) {
+		return -EINVAL;
+	}
+
+	/* bubble sort the first @count items of the array @values */
+	for( top = *count; top > 0; top--) {
+		for( low = 0, high = 1; high < top; low++, high++) {
+			if( values[low] > values[high] ) {
+				temp = values[low];
+				values[low] = values[high];
+				values[high] = temp;
+			}
+		}
+	}
+
+	/* remove duplicate items */
+	for( cur = 0, next = 1; next < *count; next++) {
+		if( values[cur] != values[next])
+			values[++cur] = values[next];
+	}
+
+	*count = cur + 1;
+
+	return 0;
+}
+
+static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct saa7146_fh *fh,
+	struct saa7146_video_dma *vdma2, u32* clip_format, u32* arbtr_ctrl, enum v4l2_field field)
+{
+	struct saa7146_vv *vv = dev->vv_data;
+	__le32 *clipping = vv->d_clipping.cpu_addr;
+
+	int width = vv->ov.win.w.width;
+	int height =  vv->ov.win.w.height;
+	int clipcount = vv->ov.nclips;
+
+	u32 line_list[32];
+	u32 pixel_list[32];
+	int numdwords = 0;
+
+	int i = 0, j = 0;
+	int cnt_line = 0, cnt_pixel = 0;
+
+	int x[32], y[32], w[32], h[32];
+
+	/* clear out memory */
+	memset(&line_list[0],  0x00, sizeof(u32)*32);
+	memset(&pixel_list[0], 0x00, sizeof(u32)*32);
+	memset(clipping,  0x00, SAA7146_CLIPPING_MEM);
+
+	/* fill the line and pixel-lists */
+	for(i = 0; i < clipcount; i++) {
+		int l = 0, r = 0, t = 0, b = 0;
+
+		x[i] = vv->ov.clips[i].c.left;
+		y[i] = vv->ov.clips[i].c.top;
+		w[i] = vv->ov.clips[i].c.width;
+		h[i] = vv->ov.clips[i].c.height;
+
+		if( w[i] < 0) {
+			x[i] += w[i]; w[i] = -w[i];
+		}
+		if( h[i] < 0) {
+			y[i] += h[i]; h[i] = -h[i];
+		}
+		if( x[i] < 0) {
+			w[i] += x[i]; x[i] = 0;
+		}
+		if( y[i] < 0) {
+			h[i] += y[i]; y[i] = 0;
+		}
+		if( 0 != vv->vflip ) {
+			y[i] = height - y[i] - h[i];
+		}
+
+		l = x[i];
+		r = x[i]+w[i];
+		t = y[i];
+		b = y[i]+h[i];
+
+		/* insert left/right coordinates */
+		pixel_list[ 2*i   ] = min_t(int, l, width);
+		pixel_list[(2*i)+1] = min_t(int, r, width);
+		/* insert top/bottom coordinates */
+		line_list[ 2*i   ] = min_t(int, t, height);
+		line_list[(2*i)+1] = min_t(int, b, height);
+	}
+
+	/* sort and eliminate lists */
+	cnt_line = cnt_pixel = 2*clipcount;
+	sort_and_eliminate( &pixel_list[0], &cnt_pixel );
+	sort_and_eliminate( &line_list[0], &cnt_line );
+
+	/* calculate the number of used u32s */
+	numdwords = max_t(int, (cnt_line+1), (cnt_pixel+1))*2;
+	numdwords = max_t(int, 4, numdwords);
+	numdwords = min_t(int, 64, numdwords);
+
+	/* fill up cliptable */
+	for(i = 0; i < cnt_pixel; i++) {
+		clipping[2*i] |= cpu_to_le32(pixel_list[i] << 16);
+	}
+	for(i = 0; i < cnt_line; i++) {
+		clipping[(2*i)+1] |= cpu_to_le32(line_list[i] << 16);
+	}
+
+	/* fill up cliptable with the display infos */
+	for(j = 0; j < clipcount; j++) {
+
+		for(i = 0; i < cnt_pixel; i++) {
+
+			if( x[j] < 0)
+				x[j] = 0;
+
+			if( pixel_list[i] < (x[j] + w[j])) {
+
+				if ( pixel_list[i] >= x[j] ) {
+					clipping[2*i] |= cpu_to_le32(1 << j);
+				}
+			}
+		}
+		for(i = 0; i < cnt_line; i++) {
+
+			if( y[j] < 0)
+				y[j] = 0;
+
+			if( line_list[i] < (y[j] + h[j]) ) {
+
+				if( line_list[i] >= y[j] ) {
+					clipping[(2*i)+1] |= cpu_to_le32(1 << j);
+				}
+			}
+		}
+	}
+
+	/* adjust arbitration control register */
+	*arbtr_ctrl &= 0xffff00ff;
+	*arbtr_ctrl |= 0x00001c00;
+
+	vdma2->base_even	= vv->d_clipping.dma_handle;
+	vdma2->base_odd		= vv->d_clipping.dma_handle;
+	vdma2->prot_addr	= vv->d_clipping.dma_handle+((sizeof(u32))*(numdwords));
+	vdma2->base_page	= 0x04;
+	vdma2->pitch		= 0x00;
+	vdma2->num_line_byte	= (0 << 16 | (sizeof(u32))*(numdwords-1) );
+
+	/* set clipping-mode. this depends on the field(s) used */
+	*clip_format &= 0xfffffff7;
+	if (V4L2_FIELD_HAS_BOTH(field)) {
+		*clip_format |= 0x00000008;
+	} else {
+		*clip_format |= 0x00000000;
+	}
+}
+
+/* disable clipping */
+static void saa7146_disable_clipping(struct saa7146_dev *dev)
+{
+	u32 clip_format	= saa7146_read(dev, CLIP_FORMAT_CTRL);
+
+	/* mask out relevant bits (=lower word)*/
+	clip_format &= MASK_W1;
+
+	/* upload clipping-registers*/
+	saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format);
+	saa7146_write(dev, MC2, (MASK_05 | MASK_21));
+
+	/* disable video dma2 */
+	saa7146_write(dev, MC1, MASK_21);
+}
+
+static void saa7146_set_clipping_rect(struct saa7146_fh *fh)
+{
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	enum v4l2_field field = vv->ov.win.field;
+	struct	saa7146_video_dma vdma2;
+	u32 clip_format;
+	u32 arbtr_ctrl;
+
+	/* check clipcount, disable clipping if clipcount == 0*/
+	if (vv->ov.nclips == 0) {
+		saa7146_disable_clipping(dev);
+		return;
+	}
+
+	clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL);
+	arbtr_ctrl = saa7146_read(dev, PCI_BT_V1);
+
+	calculate_clipping_registers_rect(dev, fh, &vdma2, &clip_format, &arbtr_ctrl, field);
+
+	/* set clipping format */
+	clip_format &= 0xffff0008;
+	clip_format |= (SAA7146_CLIPPING_RECT << 4);
+
+	/* prepare video dma2 */
+	saa7146_write(dev, BASE_EVEN2,		vdma2.base_even);
+	saa7146_write(dev, BASE_ODD2,		vdma2.base_odd);
+	saa7146_write(dev, PROT_ADDR2,		vdma2.prot_addr);
+	saa7146_write(dev, BASE_PAGE2,		vdma2.base_page);
+	saa7146_write(dev, PITCH2,		vdma2.pitch);
+	saa7146_write(dev, NUM_LINE_BYTE2,	vdma2.num_line_byte);
+
+	/* prepare the rest */
+	saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format);
+	saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
+
+	/* upload clip_control-register, clipping-registers, enable video dma2 */
+	saa7146_write(dev, MC2, (MASK_05 | MASK_21 | MASK_03 | MASK_19));
+	saa7146_write(dev, MC1, (MASK_05 | MASK_21));
+}
+
+static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, enum v4l2_field field)
+{
+	struct saa7146_vv *vv = dev->vv_data;
+
+	int source = vv->current_hps_source;
+	int sync = vv->current_hps_sync;
+
+	u32 hps_v_scale = 0, hps_v_gain  = 0, hps_ctrl = 0, hps_h_prescale = 0, hps_h_scale = 0;
+
+	/* set vertical scale */
+	hps_v_scale = 0; /* all bits get set by the function-call */
+	hps_v_gain  = 0; /* fixme: saa7146_read(dev, HPS_V_GAIN);*/
+	calculate_v_scale_registers(dev, field, vv->standard->v_field*2, height, &hps_v_scale, &hps_v_gain);
+
+	/* set horizontal scale */
+	hps_ctrl	= 0;
+	hps_h_prescale	= 0; /* all bits get set in the function */
+	hps_h_scale	= 0;
+	calculate_h_scale_registers(dev, vv->standard->h_pixels, width, vv->hflip, &hps_ctrl, &hps_v_gain, &hps_h_prescale, &hps_h_scale);
+
+	/* set hyo and hxo */
+	calculate_hxo_and_hyo(vv, &hps_h_scale, &hps_ctrl);
+	calculate_hps_source_and_sync(dev, source, sync, &hps_ctrl);
+
+	/* write out new register contents */
+	saa7146_write(dev, HPS_V_SCALE,	hps_v_scale);
+	saa7146_write(dev, HPS_V_GAIN,	hps_v_gain);
+	saa7146_write(dev, HPS_CTRL,	hps_ctrl);
+	saa7146_write(dev, HPS_H_PRESCALE,hps_h_prescale);
+	saa7146_write(dev, HPS_H_SCALE,	hps_h_scale);
+
+	/* upload shadow-ram registers */
+	saa7146_write(dev, MC2, (MASK_05 | MASK_06 | MASK_21 | MASK_22) );
+}
+
+/* calculate the new memory offsets for a desired position */
+static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat)
+{
+	struct saa7146_vv *vv = dev->vv_data;
+	struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pixelformat);
+
+	int b_depth = vv->ov_fmt->depth;
+	int b_bpl = vv->ov_fb.fmt.bytesperline;
+	/* The unsigned long cast is to remove a 64-bit compile warning since
+	   it looks like a 64-bit address is cast to a 32-bit value, even
+	   though the base pointer is really a 32-bit physical address that
+	   goes into a 32-bit DMA register.
+	   FIXME: might not work on some 64-bit platforms, but see the FIXME
+	   in struct v4l2_framebuffer (videodev2.h) for that.
+	 */
+	u32 base = (u32)(unsigned long)vv->ov_fb.base;
+
+	struct	saa7146_video_dma vdma1;
+
+	/* calculate memory offsets for picture, look if we shall top-down-flip */
+	vdma1.pitch	= 2*b_bpl;
+	if ( 0 == vv->vflip ) {
+		vdma1.base_even = base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
+		vdma1.base_odd  = vdma1.base_even + (vdma1.pitch / 2);
+		vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2));
+	}
+	else {
+		vdma1.base_even = base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
+		vdma1.base_odd  = vdma1.base_even - (vdma1.pitch / 2);
+		vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2));
+	}
+
+	if (V4L2_FIELD_HAS_BOTH(field)) {
+	} else if (field == V4L2_FIELD_ALTERNATE) {
+		/* fixme */
+		vdma1.base_odd = vdma1.prot_addr;
+		vdma1.pitch /= 2;
+	} else if (field == V4L2_FIELD_TOP) {
+		vdma1.base_odd = vdma1.prot_addr;
+		vdma1.pitch /= 2;
+	} else if (field == V4L2_FIELD_BOTTOM) {
+		vdma1.base_odd = vdma1.base_even;
+		vdma1.base_even = vdma1.prot_addr;
+		vdma1.pitch /= 2;
+	}
+
+	if ( 0 != vv->vflip ) {
+		vdma1.pitch *= -1;
+	}
+
+	vdma1.base_page = sfmt->swap;
+	vdma1.num_line_byte = (vv->standard->v_field<<16)+vv->standard->h_pixels;
+
+	saa7146_write_out_dma(dev, 1, &vdma1);
+}
+
+static void saa7146_set_output_format(struct saa7146_dev *dev, unsigned long palette)
+{
+	u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL);
+
+	/* call helper function */
+	calculate_output_format_register(dev,palette,&clip_format);
+
+	/* update the hps registers */
+	saa7146_write(dev, CLIP_FORMAT_CTRL, clip_format);
+	saa7146_write(dev, MC2, (MASK_05 | MASK_21));
+}
+
+/* select input-source */
+void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync)
+{
+	struct saa7146_vv *vv = dev->vv_data;
+	u32 hps_ctrl = 0;
+
+	/* read old state */
+	hps_ctrl = saa7146_read(dev, HPS_CTRL);
+
+	hps_ctrl &= ~( MASK_31 | MASK_30 | MASK_28 );
+	hps_ctrl |= (source << 30) | (sync << 28);
+
+	/* write back & upload register */
+	saa7146_write(dev, HPS_CTRL, hps_ctrl);
+	saa7146_write(dev, MC2, (MASK_05 | MASK_21));
+
+	vv->current_hps_source = source;
+	vv->current_hps_sync = sync;
+}
+EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
+
+int saa7146_enable_overlay(struct saa7146_fh *fh)
+{
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+
+	saa7146_set_window(dev, vv->ov.win.w.width, vv->ov.win.w.height, vv->ov.win.field);
+	saa7146_set_position(dev, vv->ov.win.w.left, vv->ov.win.w.top, vv->ov.win.w.height, vv->ov.win.field, vv->ov_fmt->pixelformat);
+	saa7146_set_output_format(dev, vv->ov_fmt->trans);
+	saa7146_set_clipping_rect(fh);
+
+	/* enable video dma1 */
+	saa7146_write(dev, MC1, (MASK_06 | MASK_22));
+	return 0;
+}
+
+void saa7146_disable_overlay(struct saa7146_fh *fh)
+{
+	struct saa7146_dev *dev = fh->dev;
+
+	/* disable clipping + video dma1 */
+	saa7146_disable_clipping(dev);
+	saa7146_write(dev, MC1, MASK_22);
+}
+
+void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma)
+{
+	int where = 0;
+
+	if( which < 1 || which > 3) {
+		return;
+	}
+
+	/* calculate starting address */
+	where  = (which-1)*0x18;
+
+	saa7146_write(dev, where,	vdma->base_odd);
+	saa7146_write(dev, where+0x04,	vdma->base_even);
+	saa7146_write(dev, where+0x08,	vdma->prot_addr);
+	saa7146_write(dev, where+0x0c,	vdma->pitch);
+	saa7146_write(dev, where+0x10,	vdma->base_page);
+	saa7146_write(dev, where+0x14,	vdma->num_line_byte);
+
+	/* upload */
+	saa7146_write(dev, MC2, (MASK_02<<(which-1))|(MASK_18<<(which-1)));
+/*
+	printk("vdma%d.base_even:     0x%08x\n", which,vdma->base_even);
+	printk("vdma%d.base_odd:      0x%08x\n", which,vdma->base_odd);
+	printk("vdma%d.prot_addr:     0x%08x\n", which,vdma->prot_addr);
+	printk("vdma%d.base_page:     0x%08x\n", which,vdma->base_page);
+	printk("vdma%d.pitch:         0x%08x\n", which,vdma->pitch);
+	printk("vdma%d.num_line_byte: 0x%08x\n", which,vdma->num_line_byte);
+*/
+}
+
+static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa7146_buf *buf)
+{
+	struct saa7146_vv *vv = dev->vv_data;
+	struct saa7146_video_dma vdma1;
+
+	struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
+
+	int width = buf->fmt->width;
+	int height = buf->fmt->height;
+	int bytesperline = buf->fmt->bytesperline;
+	enum v4l2_field field = buf->fmt->field;
+
+	int depth = sfmt->depth;
+
+	DEB_CAP("[size=%dx%d,fields=%s]\n",
+		width, height, v4l2_field_names[field]);
+
+	if( bytesperline != 0) {
+		vdma1.pitch = bytesperline*2;
+	} else {
+		vdma1.pitch = (width*depth*2)/8;
+	}
+	vdma1.num_line_byte	= ((vv->standard->v_field<<16) + vv->standard->h_pixels);
+	vdma1.base_page		= buf->pt[0].dma | ME1 | sfmt->swap;
+
+	if( 0 != vv->vflip ) {
+		vdma1.prot_addr	= buf->pt[0].offset;
+		vdma1.base_even	= buf->pt[0].offset+(vdma1.pitch/2)*height;
+		vdma1.base_odd	= vdma1.base_even - (vdma1.pitch/2);
+	} else {
+		vdma1.base_even	= buf->pt[0].offset;
+		vdma1.base_odd	= vdma1.base_even + (vdma1.pitch/2);
+		vdma1.prot_addr	= buf->pt[0].offset+(vdma1.pitch/2)*height;
+	}
+
+	if (V4L2_FIELD_HAS_BOTH(field)) {
+	} else if (field == V4L2_FIELD_ALTERNATE) {
+		/* fixme */
+		if ( vv->last_field == V4L2_FIELD_TOP ) {
+			vdma1.base_odd	= vdma1.prot_addr;
+			vdma1.pitch /= 2;
+		} else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {
+			vdma1.base_odd	= vdma1.base_even;
+			vdma1.base_even = vdma1.prot_addr;
+			vdma1.pitch /= 2;
+		}
+	} else if (field == V4L2_FIELD_TOP) {
+		vdma1.base_odd	= vdma1.prot_addr;
+		vdma1.pitch /= 2;
+	} else if (field == V4L2_FIELD_BOTTOM) {
+		vdma1.base_odd	= vdma1.base_even;
+		vdma1.base_even = vdma1.prot_addr;
+		vdma1.pitch /= 2;
+	}
+
+	if( 0 != vv->vflip ) {
+		vdma1.pitch *= -1;
+	}
+
+	saa7146_write_out_dma(dev, 1, &vdma1);
+	return 0;
+}
+
+static int calc_planar_422(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3)
+{
+	int height = buf->fmt->height;
+	int width = buf->fmt->width;
+
+	vdma2->pitch	= width;
+	vdma3->pitch	= width;
+
+	/* fixme: look at bytesperline! */
+
+	if( 0 != vv->vflip ) {
+		vdma2->prot_addr	= buf->pt[1].offset;
+		vdma2->base_even	= ((vdma2->pitch/2)*height)+buf->pt[1].offset;
+		vdma2->base_odd		= vdma2->base_even - (vdma2->pitch/2);
+
+		vdma3->prot_addr	= buf->pt[2].offset;
+		vdma3->base_even	= ((vdma3->pitch/2)*height)+buf->pt[2].offset;
+		vdma3->base_odd		= vdma3->base_even - (vdma3->pitch/2);
+	} else {
+		vdma3->base_even	= buf->pt[2].offset;
+		vdma3->base_odd		= vdma3->base_even + (vdma3->pitch/2);
+		vdma3->prot_addr	= (vdma3->pitch/2)*height+buf->pt[2].offset;
+
+		vdma2->base_even	= buf->pt[1].offset;
+		vdma2->base_odd		= vdma2->base_even + (vdma2->pitch/2);
+		vdma2->prot_addr	= (vdma2->pitch/2)*height+buf->pt[1].offset;
+	}
+
+	return 0;
+}
+
+static int calc_planar_420(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3)
+{
+	int height = buf->fmt->height;
+	int width = buf->fmt->width;
+
+	vdma2->pitch	= width/2;
+	vdma3->pitch	= width/2;
+
+	if( 0 != vv->vflip ) {
+		vdma2->prot_addr	= buf->pt[2].offset;
+		vdma2->base_even	= ((vdma2->pitch/2)*height)+buf->pt[2].offset;
+		vdma2->base_odd		= vdma2->base_even - (vdma2->pitch/2);
+
+		vdma3->prot_addr	= buf->pt[1].offset;
+		vdma3->base_even	= ((vdma3->pitch/2)*height)+buf->pt[1].offset;
+		vdma3->base_odd		= vdma3->base_even - (vdma3->pitch/2);
+
+	} else {
+		vdma3->base_even	= buf->pt[2].offset;
+		vdma3->base_odd		= vdma3->base_even + (vdma3->pitch);
+		vdma3->prot_addr	= (vdma3->pitch/2)*height+buf->pt[2].offset;
+
+		vdma2->base_even	= buf->pt[1].offset;
+		vdma2->base_odd		= vdma2->base_even + (vdma2->pitch);
+		vdma2->prot_addr	= (vdma2->pitch/2)*height+buf->pt[1].offset;
+	}
+	return 0;
+}
+
+static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa7146_buf *buf)
+{
+	struct saa7146_vv *vv = dev->vv_data;
+	struct saa7146_video_dma vdma1;
+	struct saa7146_video_dma vdma2;
+	struct saa7146_video_dma vdma3;
+
+	struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
+
+	int width = buf->fmt->width;
+	int height = buf->fmt->height;
+	enum v4l2_field field = buf->fmt->field;
+
+	BUG_ON(0 == buf->pt[0].dma);
+	BUG_ON(0 == buf->pt[1].dma);
+	BUG_ON(0 == buf->pt[2].dma);
+
+	DEB_CAP("[size=%dx%d,fields=%s]\n",
+		width, height, v4l2_field_names[field]);
+
+	/* fixme: look at bytesperline! */
+
+	/* fixme: what happens for user space buffers here?. The offsets are
+	   most likely wrong, this version here only works for page-aligned
+	   buffers, modifications to the pagetable-functions are necessary...*/
+
+	vdma1.pitch		= width*2;
+	vdma1.num_line_byte	= ((vv->standard->v_field<<16) + vv->standard->h_pixels);
+	vdma1.base_page		= buf->pt[0].dma | ME1;
+
+	if( 0 != vv->vflip ) {
+		vdma1.prot_addr	= buf->pt[0].offset;
+		vdma1.base_even	= ((vdma1.pitch/2)*height)+buf->pt[0].offset;
+		vdma1.base_odd	= vdma1.base_even - (vdma1.pitch/2);
+	} else {
+		vdma1.base_even	= buf->pt[0].offset;
+		vdma1.base_odd	= vdma1.base_even + (vdma1.pitch/2);
+		vdma1.prot_addr	= (vdma1.pitch/2)*height+buf->pt[0].offset;
+	}
+
+	vdma2.num_line_byte	= 0; /* unused */
+	vdma2.base_page		= buf->pt[1].dma | ME1;
+
+	vdma3.num_line_byte	= 0; /* unused */
+	vdma3.base_page		= buf->pt[2].dma | ME1;
+
+	switch( sfmt->depth ) {
+		case 12: {
+			calc_planar_420(vv,buf,&vdma2,&vdma3);
+			break;
+		}
+		case 16: {
+			calc_planar_422(vv,buf,&vdma2,&vdma3);
+			break;
+		}
+		default: {
+			return -1;
+		}
+	}
+
+	if (V4L2_FIELD_HAS_BOTH(field)) {
+	} else if (field == V4L2_FIELD_ALTERNATE) {
+		/* fixme */
+		vdma1.base_odd	= vdma1.prot_addr;
+		vdma1.pitch /= 2;
+		vdma2.base_odd	= vdma2.prot_addr;
+		vdma2.pitch /= 2;
+		vdma3.base_odd	= vdma3.prot_addr;
+		vdma3.pitch /= 2;
+	} else if (field == V4L2_FIELD_TOP) {
+		vdma1.base_odd	= vdma1.prot_addr;
+		vdma1.pitch /= 2;
+		vdma2.base_odd	= vdma2.prot_addr;
+		vdma2.pitch /= 2;
+		vdma3.base_odd	= vdma3.prot_addr;
+		vdma3.pitch /= 2;
+	} else if (field == V4L2_FIELD_BOTTOM) {
+		vdma1.base_odd	= vdma1.base_even;
+		vdma1.base_even = vdma1.prot_addr;
+		vdma1.pitch /= 2;
+		vdma2.base_odd	= vdma2.base_even;
+		vdma2.base_even = vdma2.prot_addr;
+		vdma2.pitch /= 2;
+		vdma3.base_odd	= vdma3.base_even;
+		vdma3.base_even = vdma3.prot_addr;
+		vdma3.pitch /= 2;
+	}
+
+	if( 0 != vv->vflip ) {
+		vdma1.pitch *= -1;
+		vdma2.pitch *= -1;
+		vdma3.pitch *= -1;
+	}
+
+	saa7146_write_out_dma(dev, 1, &vdma1);
+	if( (sfmt->flags & FORMAT_BYTE_SWAP) != 0 ) {
+		saa7146_write_out_dma(dev, 3, &vdma2);
+		saa7146_write_out_dma(dev, 2, &vdma3);
+	} else {
+		saa7146_write_out_dma(dev, 2, &vdma2);
+		saa7146_write_out_dma(dev, 3, &vdma3);
+	}
+	return 0;
+}
+
+static void program_capture_engine(struct saa7146_dev *dev, int planar)
+{
+	struct saa7146_vv *vv = dev->vv_data;
+	int count = 0;
+
+	unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B;
+	unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B;
+
+	/* wait for o_fid_a/b / e_fid_a/b toggle only if rps register 0 is not set*/
+	WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | o_wait);
+	WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait);
+
+	/* set rps register 0 */
+	WRITE_RPS0(CMD_WR_REG | (1 << 8) | (MC2/4));
+	WRITE_RPS0(MASK_27 | MASK_11);
+
+	/* turn on video-dma1 */
+	WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
+	WRITE_RPS0(MASK_06 | MASK_22);			/* => mask */
+	WRITE_RPS0(MASK_06 | MASK_22);			/* => values */
+	if( 0 != planar ) {
+		/* turn on video-dma2 */
+		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
+		WRITE_RPS0(MASK_05 | MASK_21);			/* => mask */
+		WRITE_RPS0(MASK_05 | MASK_21);			/* => values */
+
+		/* turn on video-dma3 */
+		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
+		WRITE_RPS0(MASK_04 | MASK_20);			/* => mask */
+		WRITE_RPS0(MASK_04 | MASK_20);			/* => values */
+	}
+
+	/* wait for o_fid_a/b / e_fid_a/b toggle */
+	if ( vv->last_field == V4L2_FIELD_INTERLACED ) {
+		WRITE_RPS0(CMD_PAUSE | o_wait);
+		WRITE_RPS0(CMD_PAUSE | e_wait);
+	} else if ( vv->last_field == V4L2_FIELD_TOP ) {
+		WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09));
+		WRITE_RPS0(CMD_PAUSE | o_wait);
+	} else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {
+		WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09));
+		WRITE_RPS0(CMD_PAUSE | e_wait);
+	}
+
+	/* turn off video-dma1 */
+	WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
+	WRITE_RPS0(MASK_22 | MASK_06);			/* => mask */
+	WRITE_RPS0(MASK_22);				/* => values */
+	if( 0 != planar ) {
+		/* turn off video-dma2 */
+		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
+		WRITE_RPS0(MASK_05 | MASK_21);			/* => mask */
+		WRITE_RPS0(MASK_21);				/* => values */
+
+		/* turn off video-dma3 */
+		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
+		WRITE_RPS0(MASK_04 | MASK_20);			/* => mask */
+		WRITE_RPS0(MASK_20);				/* => values */
+	}
+
+	/* generate interrupt */
+	WRITE_RPS0(CMD_INTERRUPT);
+
+	/* stop */
+	WRITE_RPS0(CMD_STOP);
+}
+
+void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next)
+{
+	struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
+	struct saa7146_vv *vv = dev->vv_data;
+	u32 vdma1_prot_addr;
+
+	DEB_CAP("buf:%p, next:%p\n", buf, next);
+
+	vdma1_prot_addr = saa7146_read(dev, PROT_ADDR1);
+	if( 0 == vdma1_prot_addr ) {
+		/* clear out beginning of streaming bit (rps register 0)*/
+		DEB_CAP("forcing sync to new frame\n");
+		saa7146_write(dev, MC2, MASK_27 );
+	}
+
+	saa7146_set_window(dev, buf->fmt->width, buf->fmt->height, buf->fmt->field);
+	saa7146_set_output_format(dev, sfmt->trans);
+	saa7146_disable_clipping(dev);
+
+	if ( vv->last_field == V4L2_FIELD_INTERLACED ) {
+	} else if ( vv->last_field == V4L2_FIELD_TOP ) {
+		vv->last_field = V4L2_FIELD_BOTTOM;
+	} else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {
+		vv->last_field = V4L2_FIELD_TOP;
+	}
+
+	if( 0 != IS_PLANAR(sfmt->trans)) {
+		calculate_video_dma_grab_planar(dev, buf);
+		program_capture_engine(dev,1);
+	} else {
+		calculate_video_dma_grab_packed(dev, buf);
+		program_capture_engine(dev,0);
+	}
+
+/*
+	printk("vdma%d.base_even:     0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1));
+	printk("vdma%d.base_odd:      0x%08x\n", 1,saa7146_read(dev,BASE_ODD1));
+	printk("vdma%d.prot_addr:     0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1));
+	printk("vdma%d.base_page:     0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1));
+	printk("vdma%d.pitch:         0x%08x\n", 1,saa7146_read(dev,PITCH1));
+	printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1));
+	printk("vdma%d => vptr      : 0x%08x\n", 1,saa7146_read(dev,PCI_VDP1));
+*/
+
+	/* write the address of the rps-program */
+	saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle);
+
+	/* turn on rps */
+	saa7146_write(dev, MC1, (MASK_12 | MASK_28));
+}
diff --git a/drivers/media/common/saa7146/saa7146_i2c.c b/drivers/media/common/saa7146/saa7146_i2c.c
new file mode 100644
index 0000000..2202719
--- /dev/null
+++ b/drivers/media/common/saa7146/saa7146_i2c.c
@@ -0,0 +1,423 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <media/saa7146_vv.h>
+
+static u32 saa7146_i2c_func(struct i2c_adapter *adapter)
+{
+	/* DEB_I2C("'%s'\n", adapter->name); */
+
+	return	  I2C_FUNC_I2C
+		| I2C_FUNC_SMBUS_QUICK
+		| I2C_FUNC_SMBUS_READ_BYTE	| I2C_FUNC_SMBUS_WRITE_BYTE
+		| I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
+}
+
+/* this function returns the status-register of our i2c-device */
+static inline u32 saa7146_i2c_status(struct saa7146_dev *dev)
+{
+	u32 iicsta = saa7146_read(dev, I2C_STATUS);
+	/* DEB_I2C("status: 0x%08x\n", iicsta); */
+	return iicsta;
+}
+
+/* this function runs through the i2c-messages and prepares the data to be
+   sent through the saa7146. have a look at the specifications p. 122 ff
+   to understand this. it returns the number of u32s to send, or -1
+   in case of an error. */
+static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op)
+{
+	int h1, h2;
+	int i, j, addr;
+	int mem = 0, op_count = 0;
+
+	/* first determine size of needed memory */
+	for(i = 0; i < num; i++) {
+		mem += m[i].len + 1;
+	}
+
+	/* worst case: we need one u32 for three bytes to be send
+	   plus one extra byte to address the device */
+	mem = 1 + ((mem-1) / 3);
+
+	/* we assume that op points to a memory of at least
+	 * SAA7146_I2C_MEM bytes size. if we exceed this limit...
+	 */
+	if ((4 * mem) > SAA7146_I2C_MEM) {
+		/* DEB_I2C("cannot prepare i2c-message\n"); */
+		return -ENOMEM;
+	}
+
+	/* be careful: clear out the i2c-mem first */
+	memset(op,0,sizeof(__le32)*mem);
+
+	/* loop through all messages */
+	for(i = 0; i < num; i++) {
+
+		/* insert the address of the i2c-slave.
+		   note: we get 7 bit i2c-addresses,
+		   so we have to perform a translation */
+		addr = (m[i].addr*2) + ( (0 != (m[i].flags & I2C_M_RD)) ? 1 : 0);
+		h1 = op_count/3; h2 = op_count%3;
+		op[h1] |= cpu_to_le32(	    (u8)addr << ((3-h2)*8));
+		op[h1] |= cpu_to_le32(SAA7146_I2C_START << ((3-h2)*2));
+		op_count++;
+
+		/* loop through all bytes of message i */
+		for(j = 0; j < m[i].len; j++) {
+			/* insert the data bytes */
+			h1 = op_count/3; h2 = op_count%3;
+			op[h1] |= cpu_to_le32( (u32)((u8)m[i].buf[j]) << ((3-h2)*8));
+			op[h1] |= cpu_to_le32(       SAA7146_I2C_CONT << ((3-h2)*2));
+			op_count++;
+		}
+
+	}
+
+	/* have a look at the last byte inserted:
+	  if it was: ...CONT change it to ...STOP */
+	h1 = (op_count-1)/3; h2 = (op_count-1)%3;
+	if ( SAA7146_I2C_CONT == (0x3 & (le32_to_cpu(op[h1]) >> ((3-h2)*2))) ) {
+		op[h1] &= ~cpu_to_le32(0x2 << ((3-h2)*2));
+		op[h1] |= cpu_to_le32(SAA7146_I2C_STOP << ((3-h2)*2));
+	}
+
+	/* return the number of u32s to send */
+	return mem;
+}
+
+/* this functions loops through all i2c-messages. normally, it should determine
+   which bytes were read through the adapter and write them back to the corresponding
+   i2c-message. but instead, we simply write back all bytes.
+   fixme: this could be improved. */
+static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, __le32 *op)
+{
+	int i, j;
+	int op_count = 0;
+
+	/* loop through all messages */
+	for(i = 0; i < num; i++) {
+
+		op_count++;
+
+		/* loop through all bytes of message i */
+		for(j = 0; j < m[i].len; j++) {
+			/* write back all bytes that could have been read */
+			m[i].buf[j] = (le32_to_cpu(op[op_count/3]) >> ((3-(op_count%3))*8));
+			op_count++;
+		}
+	}
+
+	return 0;
+}
+
+/* this functions resets the i2c-device and returns 0 if everything was fine, otherwise -1 */
+static int saa7146_i2c_reset(struct saa7146_dev *dev)
+{
+	/* get current status */
+	u32 status = saa7146_i2c_status(dev);
+
+	/* clear registers for sure */
+	saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
+	saa7146_write(dev, I2C_TRANSFER, 0);
+
+	/* check if any operation is still in progress */
+	if ( 0 != ( status & SAA7146_I2C_BUSY) ) {
+
+		/* yes, kill ongoing operation */
+		DEB_I2C("busy_state detected\n");
+
+		/* set "ABORT-OPERATION"-bit (bit 7)*/
+		saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07));
+		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
+		msleep(SAA7146_I2C_DELAY);
+
+		/* clear all error-bits pending; this is needed because p.123, note 1 */
+		saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
+		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
+		msleep(SAA7146_I2C_DELAY);
+	}
+
+	/* check if any error is (still) present. (this can be necessary because p.123, note 1) */
+	status = saa7146_i2c_status(dev);
+
+	if ( dev->i2c_bitrate != status ) {
+
+		DEB_I2C("error_state detected. status:0x%08x\n", status);
+
+		/* Repeat the abort operation. This seems to be necessary
+		   after serious protocol errors caused by e.g. the SAA7740 */
+		saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07));
+		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
+		msleep(SAA7146_I2C_DELAY);
+
+		/* clear all error-bits pending */
+		saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
+		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
+		msleep(SAA7146_I2C_DELAY);
+
+		/* the data sheet says it might be necessary to clear the status
+		   twice after an abort */
+		saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
+		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
+		msleep(SAA7146_I2C_DELAY);
+	}
+
+	/* if any error is still present, a fatal error has occurred ... */
+	status = saa7146_i2c_status(dev);
+	if ( dev->i2c_bitrate != status ) {
+		DEB_I2C("fatal error. status:0x%08x\n", status);
+		return -1;
+	}
+
+	return 0;
+}
+
+/* this functions writes out the data-byte 'dword' to the i2c-device.
+   it returns 0 if ok, -1 if the transfer failed, -2 if the transfer
+   failed badly (e.g. address error) */
+static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int short_delay)
+{
+	u32 status = 0, mc2 = 0;
+	int trial = 0;
+	unsigned long timeout;
+
+	/* write out i2c-command */
+	DEB_I2C("before: 0x%08x (status: 0x%08x), %d\n",
+		*dword, saa7146_read(dev, I2C_STATUS), dev->i2c_op);
+
+	if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) {
+
+		saa7146_write(dev, I2C_STATUS,	 dev->i2c_bitrate);
+		saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
+
+		dev->i2c_op = 1;
+		SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
+		SAA7146_IER_ENABLE(dev, MASK_16|MASK_17);
+		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
+
+		timeout = HZ/100 + 1; /* 10ms */
+		timeout = wait_event_interruptible_timeout(dev->i2c_wq, dev->i2c_op == 0, timeout);
+		if (timeout == -ERESTARTSYS || dev->i2c_op) {
+			SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
+			SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
+			if (timeout == -ERESTARTSYS)
+				/* a signal arrived */
+				return -ERESTARTSYS;
+
+			pr_warn("%s %s [irq]: timed out waiting for end of xfer\n",
+				dev->name, __func__);
+			return -EIO;
+		}
+		status = saa7146_read(dev, I2C_STATUS);
+	} else {
+		saa7146_write(dev, I2C_STATUS,	 dev->i2c_bitrate);
+		saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
+		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
+
+		/* do not poll for i2c-status before upload is complete */
+		timeout = jiffies + HZ/100 + 1; /* 10ms */
+		while(1) {
+			mc2 = (saa7146_read(dev, MC2) & 0x1);
+			if( 0 != mc2 ) {
+				break;
+			}
+			if (time_after(jiffies,timeout)) {
+				pr_warn("%s %s: timed out waiting for MC2\n",
+					dev->name, __func__);
+				return -EIO;
+			}
+		}
+		/* wait until we get a transfer done or error */
+		timeout = jiffies + HZ/100 + 1; /* 10ms */
+		/* first read usually delivers bogus results... */
+		saa7146_i2c_status(dev);
+		while(1) {
+			status = saa7146_i2c_status(dev);
+			if ((status & 0x3) != 1)
+				break;
+			if (time_after(jiffies,timeout)) {
+				/* this is normal when probing the bus
+				 * (no answer from nonexisistant device...)
+				 */
+				pr_warn("%s %s [poll]: timed out waiting for end of xfer\n",
+					dev->name, __func__);
+				return -EIO;
+			}
+			if (++trial < 50 && short_delay)
+				udelay(10);
+			else
+				msleep(1);
+		}
+	}
+
+	/* give a detailed status report */
+	if ( 0 != (status & (SAA7146_I2C_SPERR | SAA7146_I2C_APERR |
+			     SAA7146_I2C_DTERR | SAA7146_I2C_DRERR |
+			     SAA7146_I2C_AL    | SAA7146_I2C_ERR   |
+			     SAA7146_I2C_BUSY)) ) {
+
+		if ( 0 == (status & SAA7146_I2C_ERR) ||
+		     0 == (status & SAA7146_I2C_BUSY) ) {
+			/* it may take some time until ERR goes high - ignore */
+			DEB_I2C("unexpected i2c status %04x\n", status);
+		}
+		if( 0 != (status & SAA7146_I2C_SPERR) ) {
+			DEB_I2C("error due to invalid start/stop condition\n");
+		}
+		if( 0 != (status & SAA7146_I2C_DTERR) ) {
+			DEB_I2C("error in data transmission\n");
+		}
+		if( 0 != (status & SAA7146_I2C_DRERR) ) {
+			DEB_I2C("error when receiving data\n");
+		}
+		if( 0 != (status & SAA7146_I2C_AL) ) {
+			DEB_I2C("error because arbitration lost\n");
+		}
+
+		/* we handle address-errors here */
+		if( 0 != (status & SAA7146_I2C_APERR) ) {
+			DEB_I2C("error in address phase\n");
+			return -EREMOTEIO;
+		}
+
+		return -EIO;
+	}
+
+	/* read back data, just in case we were reading ... */
+	*dword = cpu_to_le32(saa7146_read(dev, I2C_TRANSFER));
+
+	DEB_I2C("after: 0x%08x\n", *dword);
+	return 0;
+}
+
+static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
+{
+	int i = 0, count = 0;
+	__le32 *buffer = dev->d_i2c.cpu_addr;
+	int err = 0;
+	int short_delay = 0;
+
+	if (mutex_lock_interruptible(&dev->i2c_lock))
+		return -ERESTARTSYS;
+
+	for(i=0;i<num;i++) {
+		DEB_I2C("msg:%d/%d\n", i+1, num);
+	}
+
+	/* prepare the message(s), get number of u32s to transfer */
+	count = saa7146_i2c_msg_prepare(msgs, num, buffer);
+	if ( 0 > count ) {
+		err = -1;
+		goto out;
+	}
+
+	if ( count > 3 || 0 != (SAA7146_I2C_SHORT_DELAY & dev->ext->flags) )
+		short_delay = 1;
+
+	do {
+		/* reset the i2c-device if necessary */
+		err = saa7146_i2c_reset(dev);
+		if ( 0 > err ) {
+			DEB_I2C("could not reset i2c-device\n");
+			goto out;
+		}
+
+		/* write out the u32s one after another */
+		for(i = 0; i < count; i++) {
+			err = saa7146_i2c_writeout(dev, &buffer[i], short_delay);
+			if ( 0 != err) {
+				/* this one is unsatisfying: some i2c slaves on some
+				   dvb cards don't acknowledge correctly, so the saa7146
+				   thinks that an address error occurred. in that case, the
+				   transaction should be retrying, even if an address error
+				   occurred. analog saa7146 based cards extensively rely on
+				   i2c address probing, however, and address errors indicate that a
+				   device is really *not* there. retrying in that case
+				   increases the time the device needs to probe greatly, so
+				   it should be avoided. So we bail out in irq mode after an
+				   address error and trust the saa7146 address error detection. */
+				if (-EREMOTEIO == err && 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags))
+					goto out;
+				DEB_I2C("error while sending message(s). starting again\n");
+				break;
+			}
+		}
+		if( 0 == err ) {
+			err = num;
+			break;
+		}
+
+		/* delay a bit before retrying */
+		msleep(10);
+
+	} while (err != num && retries--);
+
+	/* quit if any error occurred */
+	if (err != num)
+		goto out;
+
+	/* if any things had to be read, get the results */
+	if ( 0 != saa7146_i2c_msg_cleanup(msgs, num, buffer)) {
+		DEB_I2C("could not cleanup i2c-message\n");
+		err = -1;
+		goto out;
+	}
+
+	/* return the number of delivered messages */
+	DEB_I2C("transmission successful. (msg:%d)\n", err);
+out:
+	/* another bug in revision 0: the i2c-registers get uploaded randomly by other
+	   uploads, so we better clear them out before continuing */
+	if( 0 == dev->revision ) {
+		__le32 zero = 0;
+		saa7146_i2c_reset(dev);
+		if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) {
+			pr_info("revision 0 error. this should never happen\n");
+		}
+	}
+
+	mutex_unlock(&dev->i2c_lock);
+	return err;
+}
+
+/* utility functions */
+static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num)
+{
+	struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
+	struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev);
+
+	/* use helper function to transfer data */
+	return saa7146_i2c_transfer(dev, msg, num, adapter->retries);
+}
+
+
+/*****************************************************************************/
+/* i2c-adapter helper functions                                              */
+
+/* exported algorithm data */
+static struct i2c_algorithm saa7146_algo = {
+	.master_xfer	= saa7146_i2c_xfer,
+	.functionality	= saa7146_i2c_func,
+};
+
+int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate)
+{
+	DEB_EE("bitrate: 0x%08x\n", bitrate);
+
+	/* enable i2c-port pins */
+	saa7146_write(dev, MC1, (MASK_08 | MASK_24));
+
+	dev->i2c_bitrate = bitrate;
+	saa7146_i2c_reset(dev);
+
+	if (i2c_adapter) {
+		i2c_set_adapdata(i2c_adapter, &dev->v4l2_dev);
+		i2c_adapter->dev.parent    = &dev->pci->dev;
+		i2c_adapter->algo	   = &saa7146_algo;
+		i2c_adapter->algo_data     = NULL;
+		i2c_adapter->timeout = SAA7146_I2C_TIMEOUT;
+		i2c_adapter->retries = SAA7146_I2C_RETRIES;
+	}
+
+	return 0;
+}
diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c
new file mode 100644
index 0000000..1e71e37
--- /dev/null
+++ b/drivers/media/common/saa7146/saa7146_vbi.c
@@ -0,0 +1,498 @@
+#include <media/saa7146_vv.h>
+
+static int vbi_pixel_to_capture = 720 * 2;
+
+static int vbi_workaround(struct saa7146_dev *dev)
+{
+	struct saa7146_vv *vv = dev->vv_data;
+
+	u32          *cpu;
+	dma_addr_t   dma_addr;
+
+	int count = 0;
+	int i;
+
+	DECLARE_WAITQUEUE(wait, current);
+
+	DEB_VBI("dev:%p\n", dev);
+
+	/* once again, a bug in the saa7146: the brs acquisition
+	   is buggy and especially the BXO-counter does not work
+	   as specified. there is this workaround, but please
+	   don't let me explain it. ;-) */
+
+	cpu = pci_alloc_consistent(dev->pci, 4096, &dma_addr);
+	if (NULL == cpu)
+		return -ENOMEM;
+
+	/* setup some basic programming, just for the workaround */
+	saa7146_write(dev, BASE_EVEN3,	dma_addr);
+	saa7146_write(dev, BASE_ODD3,	dma_addr+vbi_pixel_to_capture);
+	saa7146_write(dev, PROT_ADDR3,	dma_addr+4096);
+	saa7146_write(dev, PITCH3,	vbi_pixel_to_capture);
+	saa7146_write(dev, BASE_PAGE3,	0x0);
+	saa7146_write(dev, NUM_LINE_BYTE3, (2<<16)|((vbi_pixel_to_capture)<<0));
+	saa7146_write(dev, MC2, MASK_04|MASK_20);
+
+	/* load brs-control register */
+	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
+	/* BXO = 1h, BRS to outbound */
+	WRITE_RPS1(0xc000008c);
+	/* wait for vbi_a or vbi_b*/
+	if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
+		DEB_D("...using port b\n");
+		WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_E_FID_B);
+		WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_O_FID_B);
+/*
+		WRITE_RPS1(CMD_PAUSE | MASK_09);
+*/
+	} else {
+		DEB_D("...using port a\n");
+		WRITE_RPS1(CMD_PAUSE | MASK_10);
+	}
+	/* upload brs */
+	WRITE_RPS1(CMD_UPLOAD | MASK_08);
+	/* load brs-control register */
+	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
+	/* BYO = 1, BXO = NQBIL (=1728 for PAL, for NTSC this is 858*2) - NumByte3 (=1440) = 288 */
+	WRITE_RPS1(((1728-(vbi_pixel_to_capture)) << 7) | MASK_19);
+	/* wait for brs_done */
+	WRITE_RPS1(CMD_PAUSE | MASK_08);
+	/* upload brs */
+	WRITE_RPS1(CMD_UPLOAD | MASK_08);
+	/* load video-dma3 NumLines3 and NumBytes3 */
+	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (NUM_LINE_BYTE3/4));
+	/* dev->vbi_count*2 lines, 720 pixel (= 1440 Bytes) */
+	WRITE_RPS1((2 << 16) | (vbi_pixel_to_capture));
+	/* load brs-control register */
+	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
+	/* Set BRS right: note: this is an experimental value for BXO (=> PAL!) */
+	WRITE_RPS1((540 << 7) | (5 << 19));  // 5 == vbi_start
+	/* wait for brs_done */
+	WRITE_RPS1(CMD_PAUSE | MASK_08);
+	/* upload brs and video-dma3*/
+	WRITE_RPS1(CMD_UPLOAD | MASK_08 | MASK_04);
+	/* load mc2 register: enable dma3 */
+	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC1/4));
+	WRITE_RPS1(MASK_20 | MASK_04);
+	/* generate interrupt */
+	WRITE_RPS1(CMD_INTERRUPT);
+	/* stop rps1 */
+	WRITE_RPS1(CMD_STOP);
+
+	/* we have to do the workaround twice to be sure that
+	   everything is ok */
+	for(i = 0; i < 2; i++) {
+
+		/* indicate to the irq handler that we do the workaround */
+		saa7146_write(dev, MC2, MASK_31|MASK_15);
+
+		saa7146_write(dev, NUM_LINE_BYTE3, (1<<16)|(2<<0));
+		saa7146_write(dev, MC2, MASK_04|MASK_20);
+
+		/* enable rps1 irqs */
+		SAA7146_IER_ENABLE(dev,MASK_28);
+
+		/* prepare to wait to be woken up by the irq-handler */
+		add_wait_queue(&vv->vbi_wq, &wait);
+		current->state = TASK_INTERRUPTIBLE;
+
+		/* start rps1 to enable workaround */
+		saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
+		saa7146_write(dev, MC1, (MASK_13 | MASK_29));
+
+		schedule();
+
+		DEB_VBI("brs bug workaround %d/1\n", i);
+
+		remove_wait_queue(&vv->vbi_wq, &wait);
+		current->state = TASK_RUNNING;
+
+		/* disable rps1 irqs */
+		SAA7146_IER_DISABLE(dev,MASK_28);
+
+		/* stop video-dma3 */
+		saa7146_write(dev, MC1, MASK_20);
+
+		if(signal_pending(current)) {
+
+			DEB_VBI("aborted (rps:0x%08x)\n",
+				saa7146_read(dev, RPS_ADDR1));
+
+			/* stop rps1 for sure */
+			saa7146_write(dev, MC1, MASK_29);
+
+			pci_free_consistent(dev->pci, 4096, cpu, dma_addr);
+			return -EINTR;
+		}
+	}
+
+	pci_free_consistent(dev->pci, 4096, cpu, dma_addr);
+	return 0;
+}
+
+static void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next)
+{
+	struct saa7146_vv *vv = dev->vv_data;
+
+	struct saa7146_video_dma vdma3;
+
+	int count = 0;
+	unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B;
+	unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B;
+
+/*
+	vdma3.base_even	= 0xc8000000+2560*70;
+	vdma3.base_odd	= 0xc8000000;
+	vdma3.prot_addr	= 0xc8000000+2560*164;
+	vdma3.pitch	= 2560;
+	vdma3.base_page	= 0;
+	vdma3.num_line_byte = (64<<16)|((vbi_pixel_to_capture)<<0); // set above!
+*/
+	vdma3.base_even	= buf->pt[2].offset;
+	vdma3.base_odd	= buf->pt[2].offset + 16 * vbi_pixel_to_capture;
+	vdma3.prot_addr	= buf->pt[2].offset + 16 * 2 * vbi_pixel_to_capture;
+	vdma3.pitch	= vbi_pixel_to_capture;
+	vdma3.base_page	= buf->pt[2].dma | ME1;
+	vdma3.num_line_byte = (16 << 16) | vbi_pixel_to_capture;
+
+	saa7146_write_out_dma(dev, 3, &vdma3);
+
+	/* write beginning of rps-program */
+	count = 0;
+
+	/* wait for o_fid_a/b / e_fid_a/b toggle only if bit 1 is not set */
+
+	/* we don't wait here for the first field anymore. this is different from the video
+	   capture and might cause that the first buffer is only half filled (with only
+	   one field). but since this is some sort of streaming data, this is not that negative.
+	   but by doing this, we can use the whole engine from videobuf-dma-sg.c... */
+
+/*
+	WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait);
+	WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | o_wait);
+*/
+	/* set bit 1 */
+	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC2/4));
+	WRITE_RPS1(MASK_28 | MASK_12);
+
+	/* turn on video-dma3 */
+	WRITE_RPS1(CMD_WR_REG_MASK | (MC1/4));
+	WRITE_RPS1(MASK_04 | MASK_20);			/* => mask */
+	WRITE_RPS1(MASK_04 | MASK_20);			/* => values */
+
+	/* wait for o_fid_a/b / e_fid_a/b toggle */
+	WRITE_RPS1(CMD_PAUSE | o_wait);
+	WRITE_RPS1(CMD_PAUSE | e_wait);
+
+	/* generate interrupt */
+	WRITE_RPS1(CMD_INTERRUPT);
+
+	/* stop */
+	WRITE_RPS1(CMD_STOP);
+
+	/* enable rps1 irqs */
+	SAA7146_IER_ENABLE(dev, MASK_28);
+
+	/* write the address of the rps-program */
+	saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
+
+	/* turn on rps */
+	saa7146_write(dev, MC1, (MASK_13 | MASK_29));
+}
+
+static int buffer_activate(struct saa7146_dev *dev,
+			   struct saa7146_buf *buf,
+			   struct saa7146_buf *next)
+{
+	struct saa7146_vv *vv = dev->vv_data;
+	buf->vb.state = VIDEOBUF_ACTIVE;
+
+	DEB_VBI("dev:%p, buf:%p, next:%p\n", dev, buf, next);
+	saa7146_set_vbi_capture(dev,buf,next);
+
+	mod_timer(&vv->vbi_dmaq.timeout, jiffies+BUFFER_TIMEOUT);
+	return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,enum v4l2_field field)
+{
+	struct file *file = q->priv_data;
+	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
+
+	int err = 0;
+	int lines, llength, size;
+
+	lines   = 16 * 2 ; /* 2 fields */
+	llength = vbi_pixel_to_capture;
+	size = lines * llength;
+
+	DEB_VBI("vb:%p\n", vb);
+
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size) {
+		DEB_VBI("size mismatch\n");
+		return -EINVAL;
+	}
+
+	if (buf->vb.size != size)
+		saa7146_dma_free(dev,q,buf);
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
+		buf->vb.width  = llength;
+		buf->vb.height = lines;
+		buf->vb.size   = size;
+		buf->vb.field  = field;	// FIXME: check this
+
+		saa7146_pgtable_free(dev->pci, &buf->pt[2]);
+		saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
+
+		err = videobuf_iolock(q,&buf->vb, NULL);
+		if (err)
+			goto oops;
+		err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2],
+						 dma->sglist, dma->sglen);
+		if (0 != err)
+			return err;
+	}
+	buf->vb.state = VIDEOBUF_PREPARED;
+	buf->activate = buffer_activate;
+
+	return 0;
+
+ oops:
+	DEB_VBI("error out\n");
+	saa7146_dma_free(dev,q,buf);
+
+	return err;
+}
+
+static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+	int llength,lines;
+
+	lines   = 16 * 2 ; /* 2 fields */
+	llength = vbi_pixel_to_capture;
+
+	*size = lines * llength;
+	*count = 2;
+
+	DEB_VBI("count:%d, size:%d\n", *count, *size);
+
+	return 0;
+}
+
+static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct file *file = q->priv_data;
+	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
+
+	DEB_VBI("vb:%p\n", vb);
+	saa7146_buffer_queue(dev, &vv->vbi_dmaq, buf);
+}
+
+static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct file *file = q->priv_data;
+	struct saa7146_fh *fh   = file->private_data;
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
+
+	DEB_VBI("vb:%p\n", vb);
+	saa7146_dma_free(dev,q,buf);
+}
+
+static struct videobuf_queue_ops vbi_qops = {
+	.buf_setup    = buffer_setup,
+	.buf_prepare  = buffer_prepare,
+	.buf_queue    = buffer_queue,
+	.buf_release  = buffer_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+static void vbi_stop(struct saa7146_fh *fh, struct file *file)
+{
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	unsigned long flags;
+	DEB_VBI("dev:%p, fh:%p\n", dev, fh);
+
+	spin_lock_irqsave(&dev->slock,flags);
+
+	/* disable rps1  */
+	saa7146_write(dev, MC1, MASK_29);
+
+	/* disable rps1 irqs */
+	SAA7146_IER_DISABLE(dev, MASK_28);
+
+	/* shut down dma 3 transfers */
+	saa7146_write(dev, MC1, MASK_20);
+
+	if (vv->vbi_dmaq.curr)
+		saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE);
+
+	videobuf_queue_cancel(&fh->vbi_q);
+
+	vv->vbi_streaming = NULL;
+
+	del_timer(&vv->vbi_dmaq.timeout);
+	del_timer(&vv->vbi_read_timeout);
+
+	spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+static void vbi_read_timeout(unsigned long data)
+{
+	struct file *file = (struct file*)data;
+	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_dev *dev = fh->dev;
+
+	DEB_VBI("dev:%p, fh:%p\n", dev, fh);
+
+	vbi_stop(fh, file);
+}
+
+static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
+{
+	DEB_VBI("dev:%p\n", dev);
+
+	INIT_LIST_HEAD(&vv->vbi_dmaq.queue);
+
+	init_timer(&vv->vbi_dmaq.timeout);
+	vv->vbi_dmaq.timeout.function = saa7146_buffer_timeout;
+	vv->vbi_dmaq.timeout.data     = (unsigned long)(&vv->vbi_dmaq);
+	vv->vbi_dmaq.dev              = dev;
+
+	init_waitqueue_head(&vv->vbi_wq);
+}
+
+static int vbi_open(struct saa7146_dev *dev, struct file *file)
+{
+	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_vv *vv = fh->dev->vv_data;
+
+	u32 arbtr_ctrl	= saa7146_read(dev, PCI_BT_V1);
+	int ret = 0;
+
+	DEB_VBI("dev:%p, fh:%p\n", dev, fh);
+
+	ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS);
+	if (0 == ret) {
+		DEB_S("cannot get vbi RESOURCE_DMA3_BRS resource\n");
+		return -EBUSY;
+	}
+
+	/* adjust arbitrition control for video dma 3 */
+	arbtr_ctrl &= ~0x1f0000;
+	arbtr_ctrl |=  0x1d0000;
+	saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
+	saa7146_write(dev, MC2, (MASK_04|MASK_20));
+
+	videobuf_queue_sg_init(&fh->vbi_q, &vbi_qops,
+			    &dev->pci->dev, &dev->slock,
+			    V4L2_BUF_TYPE_VBI_CAPTURE,
+			    V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
+			    sizeof(struct saa7146_buf),
+			    file, &dev->v4l2_lock);
+
+	vv->vbi_read_timeout.function = vbi_read_timeout;
+	vv->vbi_read_timeout.data = (unsigned long)file;
+
+	/* initialize the brs */
+	if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
+		saa7146_write(dev, BRS_CTRL, MASK_30|MASK_29 | (7 << 19));
+	} else {
+		saa7146_write(dev, BRS_CTRL, 0x00000001);
+
+		if (0 != (ret = vbi_workaround(dev))) {
+			DEB_VBI("vbi workaround failed!\n");
+			/* return ret;*/
+		}
+	}
+
+	/* upload brs register */
+	saa7146_write(dev, MC2, (MASK_08|MASK_24));
+	return 0;
+}
+
+static void vbi_close(struct saa7146_dev *dev, struct file *file)
+{
+	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_vv *vv = dev->vv_data;
+	DEB_VBI("dev:%p, fh:%p\n", dev, fh);
+
+	if( fh == vv->vbi_streaming ) {
+		vbi_stop(fh, file);
+	}
+	saa7146_res_free(fh, RESOURCE_DMA3_BRS);
+}
+
+static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
+{
+	struct saa7146_vv *vv = dev->vv_data;
+	spin_lock(&dev->slock);
+
+	if (vv->vbi_dmaq.curr) {
+		DEB_VBI("dev:%p, curr:%p\n", dev, vv->vbi_dmaq.curr);
+		/* this must be += 2, one count for each field */
+		vv->vbi_fieldcount+=2;
+		vv->vbi_dmaq.curr->vb.field_count = vv->vbi_fieldcount;
+		saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE);
+	} else {
+		DEB_VBI("dev:%p\n", dev);
+	}
+	saa7146_buffer_next(dev, &vv->vbi_dmaq, 1);
+
+	spin_unlock(&dev->slock);
+}
+
+static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+{
+	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	ssize_t ret = 0;
+
+	DEB_VBI("dev:%p, fh:%p\n", dev, fh);
+
+	if( NULL == vv->vbi_streaming ) {
+		// fixme: check if dma3 is available
+		// fixme: activate vbi engine here if necessary. (really?)
+		vv->vbi_streaming = fh;
+	}
+
+	if( fh != vv->vbi_streaming ) {
+		DEB_VBI("open %p is already using vbi capture\n",
+			vv->vbi_streaming);
+		return -EBUSY;
+	}
+
+	mod_timer(&vv->vbi_read_timeout, jiffies+BUFFER_TIMEOUT);
+	ret = videobuf_read_stream(&fh->vbi_q, data, count, ppos, 1,
+				   file->f_flags & O_NONBLOCK);
+/*
+	printk("BASE_ODD3:      0x%08x\n", saa7146_read(dev, BASE_ODD3));
+	printk("BASE_EVEN3:     0x%08x\n", saa7146_read(dev, BASE_EVEN3));
+	printk("PROT_ADDR3:     0x%08x\n", saa7146_read(dev, PROT_ADDR3));
+	printk("PITCH3:         0x%08x\n", saa7146_read(dev, PITCH3));
+	printk("BASE_PAGE3:     0x%08x\n", saa7146_read(dev, BASE_PAGE3));
+	printk("NUM_LINE_BYTE3: 0x%08x\n", saa7146_read(dev, NUM_LINE_BYTE3));
+	printk("BRS_CTRL:       0x%08x\n", saa7146_read(dev, BRS_CTRL));
+*/
+	return ret;
+}
+
+struct saa7146_use_ops saa7146_vbi_uops = {
+	.init		= vbi_init,
+	.open		= vbi_open,
+	.release	= vbi_close,
+	.irq_done	= vbi_irq_done,
+	.read		= vbi_read,
+};
diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c
new file mode 100644
index 0000000..6d14785
--- /dev/null
+++ b/drivers/media/common/saa7146/saa7146_video.c
@@ -0,0 +1,1332 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <media/saa7146_vv.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ctrls.h>
+#include <linux/module.h>
+
+static int max_memory = 32;
+
+module_param(max_memory, int, 0644);
+MODULE_PARM_DESC(max_memory, "maximum memory usage for capture buffers (default: 32Mb)");
+
+#define IS_CAPTURE_ACTIVE(fh) \
+	(((vv->video_status & STATUS_CAPTURE) != 0) && (vv->video_fh == fh))
+
+#define IS_OVERLAY_ACTIVE(fh) \
+	(((vv->video_status & STATUS_OVERLAY) != 0) && (vv->video_fh == fh))
+
+/* format descriptions for capture and preview */
+static struct saa7146_format formats[] = {
+	{
+		.name		= "RGB-8 (3-3-2)",
+		.pixelformat	= V4L2_PIX_FMT_RGB332,
+		.trans		= RGB08_COMPOSED,
+		.depth		= 8,
+		.flags		= 0,
+	}, {
+		.name		= "RGB-16 (5/B-6/G-5/R)",
+		.pixelformat	= V4L2_PIX_FMT_RGB565,
+		.trans		= RGB16_COMPOSED,
+		.depth		= 16,
+		.flags		= 0,
+	}, {
+		.name		= "RGB-24 (B-G-R)",
+		.pixelformat	= V4L2_PIX_FMT_BGR24,
+		.trans		= RGB24_COMPOSED,
+		.depth		= 24,
+		.flags		= 0,
+	}, {
+		.name		= "RGB-32 (B-G-R)",
+		.pixelformat	= V4L2_PIX_FMT_BGR32,
+		.trans		= RGB32_COMPOSED,
+		.depth		= 32,
+		.flags		= 0,
+	}, {
+		.name		= "RGB-32 (R-G-B)",
+		.pixelformat	= V4L2_PIX_FMT_RGB32,
+		.trans		= RGB32_COMPOSED,
+		.depth		= 32,
+		.flags		= 0,
+		.swap		= 0x2,
+	}, {
+		.name		= "Greyscale-8",
+		.pixelformat	= V4L2_PIX_FMT_GREY,
+		.trans		= Y8,
+		.depth		= 8,
+		.flags		= 0,
+	}, {
+		.name		= "YUV 4:2:2 planar (Y-Cb-Cr)",
+		.pixelformat	= V4L2_PIX_FMT_YUV422P,
+		.trans		= YUV422_DECOMPOSED,
+		.depth		= 16,
+		.flags		= FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,
+	}, {
+		.name		= "YVU 4:2:0 planar (Y-Cb-Cr)",
+		.pixelformat	= V4L2_PIX_FMT_YVU420,
+		.trans		= YUV420_DECOMPOSED,
+		.depth		= 12,
+		.flags		= FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,
+	}, {
+		.name		= "YUV 4:2:0 planar (Y-Cb-Cr)",
+		.pixelformat	= V4L2_PIX_FMT_YUV420,
+		.trans		= YUV420_DECOMPOSED,
+		.depth		= 12,
+		.flags		= FORMAT_IS_PLANAR,
+	}, {
+		.name		= "YUV 4:2:2 (U-Y-V-Y)",
+		.pixelformat	= V4L2_PIX_FMT_UYVY,
+		.trans		= YUV422_COMPOSED,
+		.depth		= 16,
+		.flags		= 0,
+	}
+};
+
+/* unfortunately, the saa7146 contains a bug which prevents it from doing on-the-fly byte swaps.
+   due to this, it's impossible to provide additional *packed* formats, which are simply byte swapped
+   (like V4L2_PIX_FMT_YUYV) ... 8-( */
+
+static int NUM_FORMATS = sizeof(formats)/sizeof(struct saa7146_format);
+
+struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc)
+{
+	int i, j = NUM_FORMATS;
+
+	for (i = 0; i < j; i++) {
+		if (formats[i].pixelformat == fourcc) {
+			return formats+i;
+		}
+	}
+
+	DEB_D("unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
+	return NULL;
+}
+
+static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f);
+
+int saa7146_start_preview(struct saa7146_fh *fh)
+{
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	struct v4l2_format fmt;
+	int ret = 0, err = 0;
+
+	DEB_EE("dev:%p, fh:%p\n", dev, fh);
+
+	/* check if we have overlay information */
+	if (vv->ov.fh == NULL) {
+		DEB_D("no overlay data available. try S_FMT first.\n");
+		return -EAGAIN;
+	}
+
+	/* check if streaming capture is running */
+	if (IS_CAPTURE_ACTIVE(fh) != 0) {
+		DEB_D("streaming capture is active\n");
+		return -EBUSY;
+	}
+
+	/* check if overlay is running */
+	if (IS_OVERLAY_ACTIVE(fh) != 0) {
+		if (vv->video_fh == fh) {
+			DEB_D("overlay is already active\n");
+			return 0;
+		}
+		DEB_D("overlay is already active in another open\n");
+		return -EBUSY;
+	}
+
+	if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) {
+		DEB_D("cannot get necessary overlay resources\n");
+		return -EBUSY;
+	}
+
+	fmt.fmt.win = vv->ov.win;
+	err = vidioc_try_fmt_vid_overlay(NULL, fh, &fmt);
+	if (0 != err) {
+		saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
+		return -EBUSY;
+	}
+	vv->ov.win = fmt.fmt.win;
+
+	DEB_D("%dx%d+%d+%d %s field=%s\n",
+	      vv->ov.win.w.width, vv->ov.win.w.height,
+	      vv->ov.win.w.left, vv->ov.win.w.top,
+	      vv->ov_fmt->name, v4l2_field_names[vv->ov.win.field]);
+
+	if (0 != (ret = saa7146_enable_overlay(fh))) {
+		DEB_D("enabling overlay failed: %d\n", ret);
+		saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
+		return ret;
+	}
+
+	vv->video_status = STATUS_OVERLAY;
+	vv->video_fh = fh;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(saa7146_start_preview);
+
+int saa7146_stop_preview(struct saa7146_fh *fh)
+{
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+
+	DEB_EE("dev:%p, fh:%p\n", dev, fh);
+
+	/* check if streaming capture is running */
+	if (IS_CAPTURE_ACTIVE(fh) != 0) {
+		DEB_D("streaming capture is active\n");
+		return -EBUSY;
+	}
+
+	/* check if overlay is running at all */
+	if ((vv->video_status & STATUS_OVERLAY) == 0) {
+		DEB_D("no active overlay\n");
+		return 0;
+	}
+
+	if (vv->video_fh != fh) {
+		DEB_D("overlay is active, but in another open\n");
+		return -EBUSY;
+	}
+
+	vv->video_status = 0;
+	vv->video_fh = NULL;
+
+	saa7146_disable_overlay(fh);
+
+	saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(saa7146_stop_preview);
+
+/********************************************************************************/
+/* common pagetable functions */
+
+static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf)
+{
+	struct pci_dev *pci = dev->pci;
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+	struct scatterlist *list = dma->sglist;
+	int length = dma->sglen;
+	struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
+
+	DEB_EE("dev:%p, buf:%p, sg_len:%d\n", dev, buf, length);
+
+	if( 0 != IS_PLANAR(sfmt->trans)) {
+		struct saa7146_pgtable *pt1 = &buf->pt[0];
+		struct saa7146_pgtable *pt2 = &buf->pt[1];
+		struct saa7146_pgtable *pt3 = &buf->pt[2];
+		__le32  *ptr1, *ptr2, *ptr3;
+		__le32 fill;
+
+		int size = buf->fmt->width*buf->fmt->height;
+		int i,p,m1,m2,m3,o1,o2;
+
+		switch( sfmt->depth ) {
+			case 12: {
+				/* create some offsets inside the page table */
+				m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
+				m2 = ((size+(size/4)+PAGE_SIZE)/PAGE_SIZE)-1;
+				m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
+				o1 = size%PAGE_SIZE;
+				o2 = (size+(size/4))%PAGE_SIZE;
+				DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",
+					size, m1, m2, m3, o1, o2);
+				break;
+			}
+			case 16: {
+				/* create some offsets inside the page table */
+				m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
+				m2 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
+				m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1;
+				o1 = size%PAGE_SIZE;
+				o2 = (size+(size/2))%PAGE_SIZE;
+				DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",
+					size, m1, m2, m3, o1, o2);
+				break;
+			}
+			default: {
+				return -1;
+			}
+		}
+
+		ptr1 = pt1->cpu;
+		ptr2 = pt2->cpu;
+		ptr3 = pt3->cpu;
+
+		/* walk all pages, copy all page addresses to ptr1 */
+		for (i = 0; i < length; i++, list++) {
+			for (p = 0; p * 4096 < list->length; p++, ptr1++) {
+				*ptr1 = cpu_to_le32(sg_dma_address(list) - list->offset);
+			}
+		}
+/*
+		ptr1 = pt1->cpu;
+		for(j=0;j<40;j++) {
+			printk("ptr1 %d: 0x%08x\n",j,ptr1[j]);
+		}
+*/
+
+		/* if we have a user buffer, the first page may not be
+		   aligned to a page boundary. */
+		pt1->offset = dma->sglist->offset;
+		pt2->offset = pt1->offset+o1;
+		pt3->offset = pt1->offset+o2;
+
+		/* create video-dma2 page table */
+		ptr1 = pt1->cpu;
+		for(i = m1; i <= m2 ; i++, ptr2++) {
+			*ptr2 = ptr1[i];
+		}
+		fill = *(ptr2-1);
+		for(;i<1024;i++,ptr2++) {
+			*ptr2 = fill;
+		}
+		/* create video-dma3 page table */
+		ptr1 = pt1->cpu;
+		for(i = m2; i <= m3; i++,ptr3++) {
+			*ptr3 = ptr1[i];
+		}
+		fill = *(ptr3-1);
+		for(;i<1024;i++,ptr3++) {
+			*ptr3 = fill;
+		}
+		/* finally: finish up video-dma1 page table */
+		ptr1 = pt1->cpu+m1;
+		fill = pt1->cpu[m1];
+		for(i=m1;i<1024;i++,ptr1++) {
+			*ptr1 = fill;
+		}
+/*
+		ptr1 = pt1->cpu;
+		ptr2 = pt2->cpu;
+		ptr3 = pt3->cpu;
+		for(j=0;j<40;j++) {
+			printk("ptr1 %d: 0x%08x\n",j,ptr1[j]);
+		}
+		for(j=0;j<40;j++) {
+			printk("ptr2 %d: 0x%08x\n",j,ptr2[j]);
+		}
+		for(j=0;j<40;j++) {
+			printk("ptr3 %d: 0x%08x\n",j,ptr3[j]);
+		}
+*/
+	} else {
+		struct saa7146_pgtable *pt = &buf->pt[0];
+		return saa7146_pgtable_build_single(pci, pt, list, length);
+	}
+
+	return 0;
+}
+
+
+/********************************************************************************/
+/* file operations */
+
+static int video_begin(struct saa7146_fh *fh)
+{
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	struct saa7146_format *fmt = NULL;
+	unsigned int resource;
+	int ret = 0, err = 0;
+
+	DEB_EE("dev:%p, fh:%p\n", dev, fh);
+
+	if ((vv->video_status & STATUS_CAPTURE) != 0) {
+		if (vv->video_fh == fh) {
+			DEB_S("already capturing\n");
+			return 0;
+		}
+		DEB_S("already capturing in another open\n");
+		return -EBUSY;
+	}
+
+	if ((vv->video_status & STATUS_OVERLAY) != 0) {
+		DEB_S("warning: suspending overlay video for streaming capture\n");
+		vv->ov_suspend = vv->video_fh;
+		err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
+		if (0 != err) {
+			DEB_D("suspending video failed. aborting\n");
+			return err;
+		}
+	}
+
+	fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);
+	/* we need to have a valid format set here */
+	BUG_ON(NULL == fmt);
+
+	if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
+		resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;
+	} else {
+		resource = RESOURCE_DMA1_HPS;
+	}
+
+	ret = saa7146_res_get(fh, resource);
+	if (0 == ret) {
+		DEB_S("cannot get capture resource %d\n", resource);
+		if (vv->ov_suspend != NULL) {
+			saa7146_start_preview(vv->ov_suspend);
+			vv->ov_suspend = NULL;
+		}
+		return -EBUSY;
+	}
+
+	/* clear out beginning of streaming bit (rps register 0)*/
+	saa7146_write(dev, MC2, MASK_27 );
+
+	/* enable rps0 irqs */
+	SAA7146_IER_ENABLE(dev, MASK_27);
+
+	vv->video_fh = fh;
+	vv->video_status = STATUS_CAPTURE;
+
+	return 0;
+}
+
+static int video_end(struct saa7146_fh *fh, struct file *file)
+{
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	struct saa7146_format *fmt = NULL;
+	unsigned long flags;
+	unsigned int resource;
+	u32 dmas = 0;
+	DEB_EE("dev:%p, fh:%p\n", dev, fh);
+
+	if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
+		DEB_S("not capturing\n");
+		return 0;
+	}
+
+	if (vv->video_fh != fh) {
+		DEB_S("capturing, but in another open\n");
+		return -EBUSY;
+	}
+
+	fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);
+	/* we need to have a valid format set here */
+	BUG_ON(NULL == fmt);
+
+	if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
+		resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;
+		dmas = MASK_22 | MASK_21 | MASK_20;
+	} else {
+		resource = RESOURCE_DMA1_HPS;
+		dmas = MASK_22;
+	}
+	spin_lock_irqsave(&dev->slock,flags);
+
+	/* disable rps0  */
+	saa7146_write(dev, MC1, MASK_28);
+
+	/* disable rps0 irqs */
+	SAA7146_IER_DISABLE(dev, MASK_27);
+
+	/* shut down all used video dma transfers */
+	saa7146_write(dev, MC1, dmas);
+
+	spin_unlock_irqrestore(&dev->slock, flags);
+
+	vv->video_fh = NULL;
+	vv->video_status = 0;
+
+	saa7146_res_free(fh, resource);
+
+	if (vv->ov_suspend != NULL) {
+		saa7146_start_preview(vv->ov_suspend);
+		vv->ov_suspend = NULL;
+	}
+
+	return 0;
+}
+
+static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+
+	strcpy((char *)cap->driver, "saa7146 v4l2");
+	strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
+	sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci));
+	cap->device_caps =
+		V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_VIDEO_OVERLAY |
+		V4L2_CAP_READWRITE |
+		V4L2_CAP_STREAMING;
+	cap->device_caps |= dev->ext_vv_data->capabilities;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+	if (vdev->vfl_type == VFL_TYPE_GRABBER)
+		cap->device_caps &=
+			~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT);
+	else
+		cap->device_caps &=
+			~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_AUDIO);
+	return 0;
+}
+
+static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+
+	*fb = vv->ov_fb;
+	fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+	fb->flags = V4L2_FBUF_FLAG_PRIMARY;
+	return 0;
+}
+
+static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	struct saa7146_format *fmt;
+
+	DEB_EE("VIDIOC_S_FBUF\n");
+
+	if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	/* check args */
+	fmt = saa7146_format_by_fourcc(dev, fb->fmt.pixelformat);
+	if (NULL == fmt)
+		return -EINVAL;
+
+	/* planar formats are not allowed for overlay video, clipping and video dma would clash */
+	if (fmt->flags & FORMAT_IS_PLANAR)
+		DEB_S("planar pixelformat '%4.4s' not allowed for overlay\n",
+		      (char *)&fmt->pixelformat);
+
+	/* check if overlay is running */
+	if (IS_OVERLAY_ACTIVE(fh) != 0) {
+		if (vv->video_fh != fh) {
+			DEB_D("refusing to change framebuffer informations while overlay is active in another open\n");
+			return -EBUSY;
+		}
+	}
+
+	/* ok, accept it */
+	vv->ov_fb = *fb;
+	vv->ov_fmt = fmt;
+
+	if (vv->ov_fb.fmt.bytesperline < vv->ov_fb.fmt.width) {
+		vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8;
+		DEB_D("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline);
+	}
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+	if (f->index >= NUM_FORMATS)
+		return -EINVAL;
+	strlcpy((char *)f->description, formats[f->index].name,
+			sizeof(f->description));
+	f->pixelformat = formats[f->index].pixelformat;
+	return 0;
+}
+
+int saa7146_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct saa7146_dev *dev = container_of(ctrl->handler,
+				struct saa7146_dev, ctrl_handler);
+	struct saa7146_vv *vv = dev->vv_data;
+	u32 val;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		val = saa7146_read(dev, BCS_CTRL);
+		val &= 0x00ffffff;
+		val |= (ctrl->val << 24);
+		saa7146_write(dev, BCS_CTRL, val);
+		saa7146_write(dev, MC2, MASK_22 | MASK_06);
+		break;
+
+	case V4L2_CID_CONTRAST:
+		val = saa7146_read(dev, BCS_CTRL);
+		val &= 0xff00ffff;
+		val |= (ctrl->val << 16);
+		saa7146_write(dev, BCS_CTRL, val);
+		saa7146_write(dev, MC2, MASK_22 | MASK_06);
+		break;
+
+	case V4L2_CID_SATURATION:
+		val = saa7146_read(dev, BCS_CTRL);
+		val &= 0xffffff00;
+		val |= (ctrl->val << 0);
+		saa7146_write(dev, BCS_CTRL, val);
+		saa7146_write(dev, MC2, MASK_22 | MASK_06);
+		break;
+
+	case V4L2_CID_HFLIP:
+		/* fixme: we can support changing VFLIP and HFLIP here... */
+		if ((vv->video_status & STATUS_CAPTURE))
+			return -EBUSY;
+		vv->hflip = ctrl->val;
+		break;
+
+	case V4L2_CID_VFLIP:
+		if ((vv->video_status & STATUS_CAPTURE))
+			return -EBUSY;
+		vv->vflip = ctrl->val;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if ((vv->video_status & STATUS_OVERLAY) != 0) { /* CHECK: && (vv->video_fh == fh)) */
+		struct saa7146_fh *fh = vv->video_fh;
+
+		saa7146_stop_preview(fh);
+		saa7146_start_preview(fh);
+	}
+	return 0;
+}
+
+static int vidioc_g_parm(struct file *file, void *fh,
+		struct v4l2_streamparm *parm)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+
+	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	parm->parm.capture.readbuffers = 1;
+	v4l2_video_std_frame_period(vv->standard->id,
+				    &parm->parm.capture.timeperframe);
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+
+	f->fmt.pix = vv->video_fmt;
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+
+	f->fmt.win = vv->ov.win;
+	return 0;
+}
+
+static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+
+	f->fmt.vbi = vv->vbi_fmt;
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	struct saa7146_format *fmt;
+	enum v4l2_field field;
+	int maxw, maxh;
+	int calc_bpl;
+
+	DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh);
+
+	fmt = saa7146_format_by_fourcc(dev, f->fmt.pix.pixelformat);
+	if (NULL == fmt)
+		return -EINVAL;
+
+	field = f->fmt.pix.field;
+	maxw  = vv->standard->h_max_out;
+	maxh  = vv->standard->v_max_out;
+
+	if (V4L2_FIELD_ANY == field) {
+		field = (f->fmt.pix.height > maxh / 2)
+			? V4L2_FIELD_INTERLACED
+			: V4L2_FIELD_BOTTOM;
+	}
+	switch (field) {
+	case V4L2_FIELD_ALTERNATE:
+		vv->last_field = V4L2_FIELD_TOP;
+		maxh = maxh / 2;
+		break;
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+		vv->last_field = V4L2_FIELD_INTERLACED;
+		maxh = maxh / 2;
+		break;
+	case V4L2_FIELD_INTERLACED:
+		vv->last_field = V4L2_FIELD_INTERLACED;
+		break;
+	default:
+		DEB_D("no known field mode '%d'\n", field);
+		return -EINVAL;
+	}
+
+	f->fmt.pix.field = field;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	if (f->fmt.pix.width > maxw)
+		f->fmt.pix.width = maxw;
+	if (f->fmt.pix.height > maxh)
+		f->fmt.pix.height = maxh;
+
+	calc_bpl = (f->fmt.pix.width * fmt->depth) / 8;
+
+	if (f->fmt.pix.bytesperline < calc_bpl)
+		f->fmt.pix.bytesperline = calc_bpl;
+
+	if (f->fmt.pix.bytesperline > (2 * PAGE_SIZE * fmt->depth) / 8) /* arbitrary constraint */
+		f->fmt.pix.bytesperline = calc_bpl;
+
+	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
+	DEB_D("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n",
+	      f->fmt.pix.width, f->fmt.pix.height,
+	      f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
+
+	return 0;
+}
+
+
+static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	struct v4l2_window *win = &f->fmt.win;
+	enum v4l2_field field;
+	int maxw, maxh;
+
+	DEB_EE("dev:%p\n", dev);
+
+	if (NULL == vv->ov_fb.base) {
+		DEB_D("no fb base set\n");
+		return -EINVAL;
+	}
+	if (NULL == vv->ov_fmt) {
+		DEB_D("no fb fmt set\n");
+		return -EINVAL;
+	}
+	if (win->w.width < 48 || win->w.height < 32) {
+		DEB_D("min width/height. (%d,%d)\n",
+		      win->w.width, win->w.height);
+		return -EINVAL;
+	}
+	if (win->clipcount > 16) {
+		DEB_D("clipcount too big\n");
+		return -EINVAL;
+	}
+
+	field = win->field;
+	maxw  = vv->standard->h_max_out;
+	maxh  = vv->standard->v_max_out;
+
+	if (V4L2_FIELD_ANY == field) {
+		field = (win->w.height > maxh / 2)
+			? V4L2_FIELD_INTERLACED
+			: V4L2_FIELD_TOP;
+		}
+	switch (field) {
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+	case V4L2_FIELD_ALTERNATE:
+		maxh = maxh / 2;
+		break;
+	case V4L2_FIELD_INTERLACED:
+		break;
+	default:
+		DEB_D("no known field mode '%d'\n", field);
+		return -EINVAL;
+	}
+
+	win->field = field;
+	if (win->w.width > maxw)
+		win->w.width = maxw;
+	if (win->w.height > maxh)
+		win->w.height = maxh;
+
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_format *f)
+{
+	struct saa7146_fh *fh = __fh;
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	int err;
+
+	DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh);
+	if (IS_CAPTURE_ACTIVE(fh) != 0) {
+		DEB_EE("streaming capture is active\n");
+		return -EBUSY;
+	}
+	err = vidioc_try_fmt_vid_cap(file, fh, f);
+	if (0 != err)
+		return err;
+	vv->video_fmt = f->fmt.pix;
+	DEB_EE("set to pixelformat '%4.4s'\n",
+	       (char *)&vv->video_fmt.pixelformat);
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_format *f)
+{
+	struct saa7146_fh *fh = __fh;
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	int err;
+
+	DEB_EE("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh);
+	err = vidioc_try_fmt_vid_overlay(file, fh, f);
+	if (0 != err)
+		return err;
+	vv->ov.win    = f->fmt.win;
+	vv->ov.nclips = f->fmt.win.clipcount;
+	if (vv->ov.nclips > 16)
+		vv->ov.nclips = 16;
+	if (copy_from_user(vv->ov.clips, f->fmt.win.clips,
+				sizeof(struct v4l2_clip) * vv->ov.nclips)) {
+		return -EFAULT;
+	}
+
+	/* vv->ov.fh is used to indicate that we have valid overlay informations, too */
+	vv->ov.fh = fh;
+
+	/* check if our current overlay is active */
+	if (IS_OVERLAY_ACTIVE(fh) != 0) {
+		saa7146_stop_preview(fh);
+		saa7146_start_preview(fh);
+	}
+	return 0;
+}
+
+static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+
+	*norm = vv->standard->id;
+	return 0;
+}
+
+	/* the saa7146 supfhrts (used in conjunction with the saa7111a for example)
+	   PAL / NTSC / SECAM. if your hardware does not (or does more)
+	   -- override this function in your extension */
+/*
+	case VIDIOC_ENUMSTD:
+	{
+		struct v4l2_standard *e = arg;
+		if (e->index < 0 )
+			return -EINVAL;
+		if( e->index < dev->ext_vv_data->num_stds ) {
+			DEB_EE("VIDIOC_ENUMSTD: index:%d\n", e->index);
+			v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name);
+			return 0;
+		}
+		return -EINVAL;
+	}
+	*/
+
+static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	int found = 0;
+	int err, i;
+
+	DEB_EE("VIDIOC_S_STD\n");
+
+	if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) {
+		DEB_D("cannot change video standard while streaming capture is active\n");
+		return -EBUSY;
+	}
+
+	if ((vv->video_status & STATUS_OVERLAY) != 0) {
+		vv->ov_suspend = vv->video_fh;
+		err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
+		if (0 != err) {
+			DEB_D("suspending video failed. aborting\n");
+			return err;
+		}
+	}
+
+	for (i = 0; i < dev->ext_vv_data->num_stds; i++)
+		if (*id & dev->ext_vv_data->stds[i].id)
+			break;
+	if (i != dev->ext_vv_data->num_stds) {
+		vv->standard = &dev->ext_vv_data->stds[i];
+		if (NULL != dev->ext_vv_data->std_callback)
+			dev->ext_vv_data->std_callback(dev, vv->standard);
+		found = 1;
+	}
+
+	if (vv->ov_suspend != NULL) {
+		saa7146_start_preview(vv->ov_suspend);
+		vv->ov_suspend = NULL;
+	}
+
+	if (!found) {
+		DEB_EE("VIDIOC_S_STD: standard not found\n");
+		return -EINVAL;
+	}
+
+	DEB_EE("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name);
+	return 0;
+}
+
+static int vidioc_overlay(struct file *file, void *fh, unsigned int on)
+{
+	int err;
+
+	DEB_D("VIDIOC_OVERLAY on:%d\n", on);
+	if (on)
+		err = saa7146_start_preview(fh);
+	else
+		err = saa7146_stop_preview(fh);
+	return err;
+}
+
+static int vidioc_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *b)
+{
+	struct saa7146_fh *fh = __fh;
+
+	if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return videobuf_reqbufs(&fh->video_q, b);
+	if (b->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		return videobuf_reqbufs(&fh->vbi_q, b);
+	return -EINVAL;
+}
+
+static int vidioc_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
+{
+	struct saa7146_fh *fh = __fh;
+
+	if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return videobuf_querybuf(&fh->video_q, buf);
+	if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		return videobuf_querybuf(&fh->vbi_q, buf);
+	return -EINVAL;
+}
+
+static int vidioc_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
+{
+	struct saa7146_fh *fh = __fh;
+
+	if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return videobuf_qbuf(&fh->video_q, buf);
+	if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		return videobuf_qbuf(&fh->vbi_q, buf);
+	return -EINVAL;
+}
+
+static int vidioc_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
+{
+	struct saa7146_fh *fh = __fh;
+
+	if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return videobuf_dqbuf(&fh->video_q, buf, file->f_flags & O_NONBLOCK);
+	if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		return videobuf_dqbuf(&fh->vbi_q, buf, file->f_flags & O_NONBLOCK);
+	return -EINVAL;
+}
+
+static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type type)
+{
+	struct saa7146_fh *fh = __fh;
+	int err;
+
+	DEB_D("VIDIOC_STREAMON, type:%d\n", type);
+
+	err = video_begin(fh);
+	if (err)
+		return err;
+	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return videobuf_streamon(&fh->video_q);
+	if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		return videobuf_streamon(&fh->vbi_q);
+	return -EINVAL;
+}
+
+static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type)
+{
+	struct saa7146_fh *fh = __fh;
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	int err;
+
+	DEB_D("VIDIOC_STREAMOFF, type:%d\n", type);
+
+	/* ugly: we need to copy some checks from video_end(),
+	   because videobuf_streamoff() relies on the capture running.
+	   check and fix this */
+	if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
+		DEB_S("not capturing\n");
+		return 0;
+	}
+
+	if (vv->video_fh != fh) {
+		DEB_S("capturing, but in another open\n");
+		return -EBUSY;
+	}
+
+	err = -EINVAL;
+	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		err = videobuf_streamoff(&fh->video_q);
+	else if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		err = videobuf_streamoff(&fh->vbi_q);
+	if (0 != err) {
+		DEB_D("warning: videobuf_streamoff() failed\n");
+		video_end(fh, file);
+	} else {
+		err = video_end(fh, file);
+	}
+	return err;
+}
+
+static int vidioc_g_chip_ident(struct file *file, void *__fh,
+		struct v4l2_dbg_chip_ident *chip)
+{
+	struct saa7146_fh *fh = __fh;
+	struct saa7146_dev *dev = fh->dev;
+
+	chip->ident = V4L2_IDENT_NONE;
+	chip->revision = 0;
+	if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
+		if (v4l2_chip_match_host(&chip->match))
+			chip->ident = V4L2_IDENT_SAA7146;
+		return 0;
+	}
+	if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+	    chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+	return v4l2_device_call_until_err(&dev->v4l2_dev, 0,
+			core, g_chip_ident, chip);
+}
+
+const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
+	.vidioc_querycap             = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap     = vidioc_enum_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap        = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap      = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap        = vidioc_s_fmt_vid_cap,
+	.vidioc_g_fmt_vid_overlay    = vidioc_g_fmt_vid_overlay,
+	.vidioc_try_fmt_vid_overlay  = vidioc_try_fmt_vid_overlay,
+	.vidioc_s_fmt_vid_overlay    = vidioc_s_fmt_vid_overlay,
+	.vidioc_g_chip_ident         = vidioc_g_chip_ident,
+
+	.vidioc_overlay 	     = vidioc_overlay,
+	.vidioc_g_fbuf  	     = vidioc_g_fbuf,
+	.vidioc_s_fbuf  	     = vidioc_s_fbuf,
+	.vidioc_reqbufs              = vidioc_reqbufs,
+	.vidioc_querybuf             = vidioc_querybuf,
+	.vidioc_qbuf                 = vidioc_qbuf,
+	.vidioc_dqbuf                = vidioc_dqbuf,
+	.vidioc_g_std                = vidioc_g_std,
+	.vidioc_s_std                = vidioc_s_std,
+	.vidioc_streamon             = vidioc_streamon,
+	.vidioc_streamoff            = vidioc_streamoff,
+	.vidioc_g_parm 		     = vidioc_g_parm,
+	.vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
+};
+
+const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops = {
+	.vidioc_querycap             = vidioc_querycap,
+	.vidioc_g_fmt_vbi_cap        = vidioc_g_fmt_vbi_cap,
+	.vidioc_g_chip_ident         = vidioc_g_chip_ident,
+
+	.vidioc_reqbufs              = vidioc_reqbufs,
+	.vidioc_querybuf             = vidioc_querybuf,
+	.vidioc_qbuf                 = vidioc_qbuf,
+	.vidioc_dqbuf                = vidioc_dqbuf,
+	.vidioc_g_std                = vidioc_g_std,
+	.vidioc_s_std                = vidioc_s_std,
+	.vidioc_streamon             = vidioc_streamon,
+	.vidioc_streamoff            = vidioc_streamoff,
+	.vidioc_g_parm		     = vidioc_g_parm,
+	.vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
+};
+
+/*********************************************************************************/
+/* buffer handling functions                                                  */
+
+static int buffer_activate (struct saa7146_dev *dev,
+		     struct saa7146_buf *buf,
+		     struct saa7146_buf *next)
+{
+	struct saa7146_vv *vv = dev->vv_data;
+
+	buf->vb.state = VIDEOBUF_ACTIVE;
+	saa7146_set_capture(dev,buf,next);
+
+	mod_timer(&vv->video_dmaq.timeout, jiffies+BUFFER_TIMEOUT);
+	return 0;
+}
+
+static void release_all_pagetables(struct saa7146_dev *dev, struct saa7146_buf *buf)
+{
+	saa7146_pgtable_free(dev->pci, &buf->pt[0]);
+	saa7146_pgtable_free(dev->pci, &buf->pt[1]);
+	saa7146_pgtable_free(dev->pci, &buf->pt[2]);
+}
+
+static int buffer_prepare(struct videobuf_queue *q,
+			  struct videobuf_buffer *vb, enum v4l2_field field)
+{
+	struct file *file = q->priv_data;
+	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
+	int size,err = 0;
+
+	DEB_CAP("vbuf:%p\n", vb);
+
+	/* sanity checks */
+	if (vv->video_fmt.width  < 48 ||
+	    vv->video_fmt.height < 32 ||
+	    vv->video_fmt.width  > vv->standard->h_max_out ||
+	    vv->video_fmt.height > vv->standard->v_max_out) {
+		DEB_D("w (%d) / h (%d) out of bounds\n",
+		      vv->video_fmt.width, vv->video_fmt.height);
+		return -EINVAL;
+	}
+
+	size = vv->video_fmt.sizeimage;
+	if (0 != buf->vb.baddr && buf->vb.bsize < size) {
+		DEB_D("size mismatch\n");
+		return -EINVAL;
+	}
+
+	DEB_CAP("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n",
+		vv->video_fmt.width, vv->video_fmt.height,
+		size, v4l2_field_names[vv->video_fmt.field]);
+	if (buf->vb.width  != vv->video_fmt.width  ||
+	    buf->vb.bytesperline != vv->video_fmt.bytesperline ||
+	    buf->vb.height != vv->video_fmt.height ||
+	    buf->vb.size   != size ||
+	    buf->vb.field  != field      ||
+	    buf->vb.field  != vv->video_fmt.field  ||
+	    buf->fmt       != &vv->video_fmt) {
+		saa7146_dma_free(dev,q,buf);
+	}
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		struct saa7146_format *sfmt;
+
+		buf->vb.bytesperline  = vv->video_fmt.bytesperline;
+		buf->vb.width  = vv->video_fmt.width;
+		buf->vb.height = vv->video_fmt.height;
+		buf->vb.size   = size;
+		buf->vb.field  = field;
+		buf->fmt       = &vv->video_fmt;
+		buf->vb.field  = vv->video_fmt.field;
+
+		sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
+
+		release_all_pagetables(dev, buf);
+		if( 0 != IS_PLANAR(sfmt->trans)) {
+			saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
+			saa7146_pgtable_alloc(dev->pci, &buf->pt[1]);
+			saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
+		} else {
+			saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
+		}
+
+		err = videobuf_iolock(q,&buf->vb, &vv->ov_fb);
+		if (err)
+			goto oops;
+		err = saa7146_pgtable_build(dev,buf);
+		if (err)
+			goto oops;
+	}
+	buf->vb.state = VIDEOBUF_PREPARED;
+	buf->activate = buffer_activate;
+
+	return 0;
+
+ oops:
+	DEB_D("error out\n");
+	saa7146_dma_free(dev,q,buf);
+
+	return err;
+}
+
+static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+	struct file *file = q->priv_data;
+	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_vv *vv = fh->dev->vv_data;
+
+	if (0 == *count || *count > MAX_SAA7146_CAPTURE_BUFFERS)
+		*count = MAX_SAA7146_CAPTURE_BUFFERS;
+
+	*size = vv->video_fmt.sizeimage;
+
+	/* check if we exceed the "max_memory" parameter */
+	if( (*count * *size) > (max_memory*1048576) ) {
+		*count = (max_memory*1048576) / *size;
+	}
+
+	DEB_CAP("%d buffers, %d bytes each\n", *count, *size);
+
+	return 0;
+}
+
+static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct file *file = q->priv_data;
+	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
+
+	DEB_CAP("vbuf:%p\n", vb);
+	saa7146_buffer_queue(fh->dev, &vv->video_dmaq, buf);
+}
+
+static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct file *file = q->priv_data;
+	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
+
+	DEB_CAP("vbuf:%p\n", vb);
+
+	saa7146_dma_free(dev,q,buf);
+
+	release_all_pagetables(dev, buf);
+}
+
+static struct videobuf_queue_ops video_qops = {
+	.buf_setup    = buffer_setup,
+	.buf_prepare  = buffer_prepare,
+	.buf_queue    = buffer_queue,
+	.buf_release  = buffer_release,
+};
+
+/********************************************************************************/
+/* file operations */
+
+static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
+{
+	INIT_LIST_HEAD(&vv->video_dmaq.queue);
+
+	init_timer(&vv->video_dmaq.timeout);
+	vv->video_dmaq.timeout.function = saa7146_buffer_timeout;
+	vv->video_dmaq.timeout.data     = (unsigned long)(&vv->video_dmaq);
+	vv->video_dmaq.dev              = dev;
+
+	/* set some default values */
+	vv->standard = &dev->ext_vv_data->stds[0];
+
+	/* FIXME: what's this? */
+	vv->current_hps_source = SAA7146_HPS_SOURCE_PORT_A;
+	vv->current_hps_sync = SAA7146_HPS_SYNC_PORT_A;
+}
+
+
+static int video_open(struct saa7146_dev *dev, struct file *file)
+{
+	struct saa7146_fh *fh = file->private_data;
+
+	videobuf_queue_sg_init(&fh->video_q, &video_qops,
+			    &dev->pci->dev, &dev->slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			    V4L2_FIELD_INTERLACED,
+			    sizeof(struct saa7146_buf),
+			    file, &dev->v4l2_lock);
+
+	return 0;
+}
+
+
+static void video_close(struct saa7146_dev *dev, struct file *file)
+{
+	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_vv *vv = dev->vv_data;
+	struct videobuf_queue *q = &fh->video_q;
+
+	if (IS_CAPTURE_ACTIVE(fh) != 0)
+		video_end(fh, file);
+	else if (IS_OVERLAY_ACTIVE(fh) != 0)
+		saa7146_stop_preview(fh);
+
+	videobuf_stop(q);
+	/* hmm, why is this function declared void? */
+}
+
+
+static void video_irq_done(struct saa7146_dev *dev, unsigned long st)
+{
+	struct saa7146_vv *vv = dev->vv_data;
+	struct saa7146_dmaqueue *q = &vv->video_dmaq;
+
+	spin_lock(&dev->slock);
+	DEB_CAP("called\n");
+
+	/* only finish the buffer if we have one... */
+	if( NULL != q->curr ) {
+		saa7146_buffer_finish(dev,q,VIDEOBUF_DONE);
+	}
+	saa7146_buffer_next(dev,q,0);
+
+	spin_unlock(&dev->slock);
+}
+
+static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+{
+	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	ssize_t ret = 0;
+
+	DEB_EE("called\n");
+
+	if ((vv->video_status & STATUS_CAPTURE) != 0) {
+		/* fixme: should we allow read() captures while streaming capture? */
+		if (vv->video_fh == fh) {
+			DEB_S("already capturing\n");
+			return -EBUSY;
+		}
+		DEB_S("already capturing in another open\n");
+		return -EBUSY;
+	}
+
+	ret = video_begin(fh);
+	if( 0 != ret) {
+		goto out;
+	}
+
+	ret = videobuf_read_one(&fh->video_q , data, count, ppos,
+				file->f_flags & O_NONBLOCK);
+	if (ret != 0) {
+		video_end(fh, file);
+	} else {
+		ret = video_end(fh, file);
+	}
+out:
+	/* restart overlay if it was active before */
+	if (vv->ov_suspend != NULL) {
+		saa7146_start_preview(vv->ov_suspend);
+		vv->ov_suspend = NULL;
+	}
+
+	return ret;
+}
+
+struct saa7146_use_ops saa7146_video_uops = {
+	.init = video_init,
+	.open = video_open,
+	.release = video_close,
+	.irq_done = video_irq_done,
+	.read = video_read,
+};
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
deleted file mode 100644
index d6b1cf6..0000000
--- a/drivers/media/common/saa7146_core.c
+++ /dev/null
@@ -1,600 +0,0 @@
-/*
-    saa7146.o - driver for generic saa7146-based hardware
-
-    Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <media/saa7146.h>
-#include <linux/module.h>
-
-LIST_HEAD(saa7146_devices);
-DEFINE_MUTEX(saa7146_devices_lock);
-
-static int saa7146_num;
-
-unsigned int saa7146_debug;
-
-module_param(saa7146_debug, uint, 0644);
-MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");
-
-#if 0
-static void dump_registers(struct saa7146_dev* dev)
-{
-	int i = 0;
-
-	pr_info(" @ %li jiffies:\n", jiffies);
-	for (i = 0; i <= 0x148; i += 4)
-		pr_info("0x%03x: 0x%08x\n", i, saa7146_read(dev, i));
-}
-#endif
-
-/****************************************************************************
- * gpio and debi helper functions
- ****************************************************************************/
-
-void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
-{
-	u32 value = 0;
-
-	BUG_ON(port > 3);
-
-	value = saa7146_read(dev, GPIO_CTRL);
-	value &= ~(0xff << (8*port));
-	value |= (data << (8*port));
-	saa7146_write(dev, GPIO_CTRL, value);
-}
-
-/* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */
-static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev,
-				unsigned long us1, unsigned long us2)
-{
-	unsigned long timeout;
-	int err;
-
-	/* wait for registers to be programmed */
-	timeout = jiffies + usecs_to_jiffies(us1);
-	while (1) {
-		err = time_after(jiffies, timeout);
-		if (saa7146_read(dev, MC2) & 2)
-			break;
-		if (err) {
-			pr_err("%s: %s timed out while waiting for registers getting programmed\n",
-			       dev->name, __func__);
-			return -ETIMEDOUT;
-		}
-		msleep(1);
-	}
-
-	/* wait for transfer to complete */
-	timeout = jiffies + usecs_to_jiffies(us2);
-	while (1) {
-		err = time_after(jiffies, timeout);
-		if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
-			break;
-		saa7146_read(dev, MC2);
-		if (err) {
-			DEB_S("%s: %s timed out while waiting for transfer completion\n",
-			      dev->name, __func__);
-			return -ETIMEDOUT;
-		}
-		msleep(1);
-	}
-
-	return 0;
-}
-
-static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev,
-				unsigned long us1, unsigned long us2)
-{
-	unsigned long loops;
-
-	/* wait for registers to be programmed */
-	loops = us1;
-	while (1) {
-		if (saa7146_read(dev, MC2) & 2)
-			break;
-		if (!loops--) {
-			pr_err("%s: %s timed out while waiting for registers getting programmed\n",
-			       dev->name, __func__);
-			return -ETIMEDOUT;
-		}
-		udelay(1);
-	}
-
-	/* wait for transfer to complete */
-	loops = us2 / 5;
-	while (1) {
-		if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
-			break;
-		saa7146_read(dev, MC2);
-		if (!loops--) {
-			DEB_S("%s: %s timed out while waiting for transfer completion\n",
-			      dev->name, __func__);
-			return -ETIMEDOUT;
-		}
-		udelay(5);
-	}
-
-	return 0;
-}
-
-int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
-{
-	if (nobusyloop)
-		return saa7146_wait_for_debi_done_sleep(dev, 50000, 250000);
-	else
-		return saa7146_wait_for_debi_done_busyloop(dev, 50000, 250000);
-}
-
-/****************************************************************************
- * general helper functions
- ****************************************************************************/
-
-/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c
-   make sure virt has been allocated with vmalloc_32(), otherwise the BUG()
-   may be triggered on highmem machines */
-static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
-{
-	struct scatterlist *sglist;
-	struct page *pg;
-	int i;
-
-	sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
-	if (NULL == sglist)
-		return NULL;
-	sg_init_table(sglist, nr_pages);
-	for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
-		pg = vmalloc_to_page(virt);
-		if (NULL == pg)
-			goto err;
-		BUG_ON(PageHighMem(pg));
-		sg_set_page(&sglist[i], pg, PAGE_SIZE, 0);
-	}
-	return sglist;
-
- err:
-	kfree(sglist);
-	return NULL;
-}
-
-/********************************************************************************/
-/* common page table functions */
-
-void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
-{
-	int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;
-	void *mem = vmalloc_32(length);
-	int slen = 0;
-
-	if (NULL == mem)
-		goto err_null;
-
-	if (!(pt->slist = vmalloc_to_sg(mem, pages)))
-		goto err_free_mem;
-
-	if (saa7146_pgtable_alloc(pci, pt))
-		goto err_free_slist;
-
-	pt->nents = pages;
-	slen = pci_map_sg(pci,pt->slist,pt->nents,PCI_DMA_FROMDEVICE);
-	if (0 == slen)
-		goto err_free_pgtable;
-
-	if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen))
-		goto err_unmap_sg;
-
-	return mem;
-
-err_unmap_sg:
-	pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
-err_free_pgtable:
-	saa7146_pgtable_free(pci, pt);
-err_free_slist:
-	kfree(pt->slist);
-	pt->slist = NULL;
-err_free_mem:
-	vfree(mem);
-err_null:
-	return NULL;
-}
-
-void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt)
-{
-	pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
-	saa7146_pgtable_free(pci, pt);
-	kfree(pt->slist);
-	pt->slist = NULL;
-	vfree(mem);
-}
-
-void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt)
-{
-	if (NULL == pt->cpu)
-		return;
-	pci_free_consistent(pci, pt->size, pt->cpu, pt->dma);
-	pt->cpu = NULL;
-}
-
-int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
-{
-	__le32       *cpu;
-	dma_addr_t   dma_addr = 0;
-
-	cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
-	if (NULL == cpu) {
-		return -ENOMEM;
-	}
-	pt->size = PAGE_SIZE;
-	pt->cpu  = cpu;
-	pt->dma  = dma_addr;
-
-	return 0;
-}
-
-int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt,
-	struct scatterlist *list, int sglen  )
-{
-	__le32 *ptr, fill;
-	int nr_pages = 0;
-	int i,p;
-
-	BUG_ON(0 == sglen);
-	BUG_ON(list->offset > PAGE_SIZE);
-
-	/* if we have a user buffer, the first page may not be
-	   aligned to a page boundary. */
-	pt->offset = list->offset;
-
-	ptr = pt->cpu;
-	for (i = 0; i < sglen; i++, list++) {
-/*
-		pr_debug("i:%d, adr:0x%08x, len:%d, offset:%d\n",
-			 i, sg_dma_address(list), sg_dma_len(list),
-			 list->offset);
-*/
-		for (p = 0; p * 4096 < list->length; p++, ptr++) {
-			*ptr = cpu_to_le32(sg_dma_address(list) + p * 4096);
-			nr_pages++;
-		}
-	}
-
-
-	/* safety; fill the page table up with the last valid page */
-	fill = *(ptr-1);
-	for(i=nr_pages;i<1024;i++) {
-		*ptr++ = fill;
-	}
-
-/*
-	ptr = pt->cpu;
-	pr_debug("offset: %d\n", pt->offset);
-	for(i=0;i<5;i++) {
-		pr_debug("ptr1 %d: 0x%08x\n", i, ptr[i]);
-	}
-*/
-	return 0;
-}
-
-/********************************************************************************/
-/* interrupt handler */
-static irqreturn_t interrupt_hw(int irq, void *dev_id)
-{
-	struct saa7146_dev *dev = dev_id;
-	u32 isr;
-	u32 ack_isr;
-
-	/* read out the interrupt status register */
-	ack_isr = isr = saa7146_read(dev, ISR);
-
-	/* is this our interrupt? */
-	if ( 0 == isr ) {
-		/* nope, some other device */
-		return IRQ_NONE;
-	}
-
-	if (dev->ext) {
-		if (dev->ext->irq_mask & isr) {
-			if (dev->ext->irq_func)
-				dev->ext->irq_func(dev, &isr);
-			isr &= ~dev->ext->irq_mask;
-		}
-	}
-	if (0 != (isr & (MASK_27))) {
-		DEB_INT("irq: RPS0 (0x%08x)\n", isr);
-		if (dev->vv_data && dev->vv_callback)
-			dev->vv_callback(dev,isr);
-		isr &= ~MASK_27;
-	}
-	if (0 != (isr & (MASK_28))) {
-		if (dev->vv_data && dev->vv_callback)
-			dev->vv_callback(dev,isr);
-		isr &= ~MASK_28;
-	}
-	if (0 != (isr & (MASK_16|MASK_17))) {
-		SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
-		/* only wake up if we expect something */
-		if (0 != dev->i2c_op) {
-			dev->i2c_op = 0;
-			wake_up(&dev->i2c_wq);
-		} else {
-			u32 psr = saa7146_read(dev, PSR);
-			u32 ssr = saa7146_read(dev, SSR);
-			pr_warn("%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",
-				dev->name, isr, psr, ssr);
-		}
-		isr &= ~(MASK_16|MASK_17);
-	}
-	if( 0 != isr ) {
-		ERR("warning: interrupt enabled, but not handled properly.(0x%08x)\n",
-		    isr);
-		ERR("disabling interrupt source(s)!\n");
-		SAA7146_IER_DISABLE(dev,isr);
-	}
-	saa7146_write(dev, ISR, ack_isr);
-	return IRQ_HANDLED;
-}
-
-/*********************************************************************************/
-/* configuration-functions                                                       */
-
-static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent)
-{
-	struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data;
-	struct saa7146_extension *ext = pci_ext->ext;
-	struct saa7146_dev *dev;
-	int err = -ENOMEM;
-
-	/* clear out mem for sure */
-	dev = kzalloc(sizeof(struct saa7146_dev), GFP_KERNEL);
-	if (!dev) {
-		ERR("out of memory\n");
-		goto out;
-	}
-
-	DEB_EE("pci:%p\n", pci);
-
-	err = pci_enable_device(pci);
-	if (err < 0) {
-		ERR("pci_enable_device() failed\n");
-		goto err_free;
-	}
-
-	/* enable bus-mastering */
-	pci_set_master(pci);
-
-	dev->pci = pci;
-
-	/* get chip-revision; this is needed to enable bug-fixes */
-	dev->revision = pci->revision;
-
-	/* remap the memory from virtual to physical address */
-
-	err = pci_request_region(pci, 0, "saa7146");
-	if (err < 0)
-		goto err_disable;
-
-	dev->mem = ioremap(pci_resource_start(pci, 0),
-			   pci_resource_len(pci, 0));
-	if (!dev->mem) {
-		ERR("ioremap() failed\n");
-		err = -ENODEV;
-		goto err_release;
-	}
-
-	/* we don't do a master reset here anymore, it screws up
-	   some boards that don't have an i2c-eeprom for configuration
-	   values */
-/*
-	saa7146_write(dev, MC1, MASK_31);
-*/
-
-	/* disable all irqs */
-	saa7146_write(dev, IER, 0);
-
-	/* shut down all dma transfers and rps tasks */
-	saa7146_write(dev, MC1, 0x30ff0000);
-
-	/* clear out any rps-signals pending */
-	saa7146_write(dev, MC2, 0xf8000000);
-
-	/* request an interrupt for the saa7146 */
-	err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED | IRQF_DISABLED,
-			  dev->name, dev);
-	if (err < 0) {
-		ERR("request_irq() failed\n");
-		goto err_unmap;
-	}
-
-	err = -ENOMEM;
-
-	/* get memory for various stuff */
-	dev->d_rps0.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
-						    &dev->d_rps0.dma_handle);
-	if (!dev->d_rps0.cpu_addr)
-		goto err_free_irq;
-	memset(dev->d_rps0.cpu_addr, 0x0, SAA7146_RPS_MEM);
-
-	dev->d_rps1.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
-						    &dev->d_rps1.dma_handle);
-	if (!dev->d_rps1.cpu_addr)
-		goto err_free_rps0;
-	memset(dev->d_rps1.cpu_addr, 0x0, SAA7146_RPS_MEM);
-
-	dev->d_i2c.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
-						   &dev->d_i2c.dma_handle);
-	if (!dev->d_i2c.cpu_addr)
-		goto err_free_rps1;
-	memset(dev->d_i2c.cpu_addr, 0x0, SAA7146_RPS_MEM);
-
-	/* the rest + print status message */
-
-	/* create a nice device name */
-	sprintf(dev->name, "saa7146 (%d)", saa7146_num);
-
-	pr_info("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x)\n",
-		dev->mem, dev->revision, pci->irq,
-		pci->subsystem_vendor, pci->subsystem_device);
-	dev->ext = ext;
-
-	mutex_init(&dev->v4l2_lock);
-	spin_lock_init(&dev->int_slock);
-	spin_lock_init(&dev->slock);
-
-	mutex_init(&dev->i2c_lock);
-
-	dev->module = THIS_MODULE;
-	init_waitqueue_head(&dev->i2c_wq);
-
-	/* set some sane pci arbitrition values */
-	saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
-
-	/* TODO: use the status code of the callback */
-
-	err = -ENODEV;
-
-	if (ext->probe && ext->probe(dev)) {
-		DEB_D("ext->probe() failed for %p. skipping device.\n", dev);
-		goto err_free_i2c;
-	}
-
-	if (ext->attach(dev, pci_ext)) {
-		DEB_D("ext->attach() failed for %p. skipping device.\n", dev);
-		goto err_free_i2c;
-	}
-	/* V4L extensions will set the pci drvdata to the v4l2_device in the
-	   attach() above. So for those cards that do not use V4L we have to
-	   set it explicitly. */
-	pci_set_drvdata(pci, &dev->v4l2_dev);
-
-	INIT_LIST_HEAD(&dev->item);
-	list_add_tail(&dev->item,&saa7146_devices);
-	saa7146_num++;
-
-	err = 0;
-out:
-	return err;
-
-err_free_i2c:
-	pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr,
-			    dev->d_i2c.dma_handle);
-err_free_rps1:
-	pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr,
-			    dev->d_rps1.dma_handle);
-err_free_rps0:
-	pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr,
-			    dev->d_rps0.dma_handle);
-err_free_irq:
-	free_irq(pci->irq, (void *)dev);
-err_unmap:
-	iounmap(dev->mem);
-err_release:
-	pci_release_region(pci, 0);
-err_disable:
-	pci_disable_device(pci);
-err_free:
-	kfree(dev);
-	goto out;
-}
-
-static void saa7146_remove_one(struct pci_dev *pdev)
-{
-	struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
-	struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev);
-	struct {
-		void *addr;
-		dma_addr_t dma;
-	} dev_map[] = {
-		{ dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle },
-		{ dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle },
-		{ dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle },
-		{ NULL, 0 }
-	}, *p;
-
-	DEB_EE("dev:%p\n", dev);
-
-	dev->ext->detach(dev);
-	/* Zero the PCI drvdata after use. */
-	pci_set_drvdata(pdev, NULL);
-
-	/* shut down all video dma transfers */
-	saa7146_write(dev, MC1, 0x00ff0000);
-
-	/* disable all irqs, release irq-routine */
-	saa7146_write(dev, IER, 0);
-
-	free_irq(pdev->irq, dev);
-
-	for (p = dev_map; p->addr; p++)
-		pci_free_consistent(pdev, SAA7146_RPS_MEM, p->addr, p->dma);
-
-	iounmap(dev->mem);
-	pci_release_region(pdev, 0);
-	list_del(&dev->item);
-	pci_disable_device(pdev);
-	kfree(dev);
-
-	saa7146_num--;
-}
-
-/*********************************************************************************/
-/* extension handling functions                                                  */
-
-int saa7146_register_extension(struct saa7146_extension* ext)
-{
-	DEB_EE("ext:%p\n", ext);
-
-	ext->driver.name = ext->name;
-	ext->driver.id_table = ext->pci_tbl;
-	ext->driver.probe = saa7146_init_one;
-	ext->driver.remove = saa7146_remove_one;
-
-	pr_info("register extension '%s'\n", ext->name);
-	return pci_register_driver(&ext->driver);
-}
-
-int saa7146_unregister_extension(struct saa7146_extension* ext)
-{
-	DEB_EE("ext:%p\n", ext);
-	pr_info("unregister extension '%s'\n", ext->name);
-	pci_unregister_driver(&ext->driver);
-	return 0;
-}
-
-EXPORT_SYMBOL_GPL(saa7146_register_extension);
-EXPORT_SYMBOL_GPL(saa7146_unregister_extension);
-
-/* misc functions used by extension modules */
-EXPORT_SYMBOL_GPL(saa7146_pgtable_alloc);
-EXPORT_SYMBOL_GPL(saa7146_pgtable_free);
-EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single);
-EXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable);
-EXPORT_SYMBOL_GPL(saa7146_vfree_destroy_pgtable);
-EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done);
-
-EXPORT_SYMBOL_GPL(saa7146_setgpio);
-
-EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare);
-
-EXPORT_SYMBOL_GPL(saa7146_debug);
-EXPORT_SYMBOL_GPL(saa7146_devices);
-EXPORT_SYMBOL_GPL(saa7146_devices_lock);
-
-MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
-MODULE_DESCRIPTION("driver for generic saa7146-based hardware");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
deleted file mode 100644
index 0cdbd74..0000000
--- a/drivers/media/common/saa7146_fops.c
+++ /dev/null
@@ -1,641 +0,0 @@
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <media/saa7146_vv.h>
-#include <linux/module.h>
-
-/****************************************************************************/
-/* resource management functions, shamelessly stolen from saa7134 driver */
-
-int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
-{
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-
-	if (fh->resources & bit) {
-		DEB_D("already allocated! want: 0x%02x, cur:0x%02x\n",
-		      bit, vv->resources);
-		/* have it already allocated */
-		return 1;
-	}
-
-	/* is it free? */
-	if (vv->resources & bit) {
-		DEB_D("locked! vv->resources:0x%02x, we want:0x%02x\n",
-		      vv->resources, bit);
-		/* no, someone else uses it */
-		return 0;
-	}
-	/* it's free, grab it */
-	fh->resources |= bit;
-	vv->resources |= bit;
-	DEB_D("res: get 0x%02x, cur:0x%02x\n", bit, vv->resources);
-	return 1;
-}
-
-void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
-{
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-
-	BUG_ON((fh->resources & bits) != bits);
-
-	fh->resources &= ~bits;
-	vv->resources &= ~bits;
-	DEB_D("res: put 0x%02x, cur:0x%02x\n", bits, vv->resources);
-}
-
-
-/********************************************************************************/
-/* common dma functions */
-
-void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
-						struct saa7146_buf *buf)
-{
-	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
-	DEB_EE("dev:%p, buf:%p\n", dev, buf);
-
-	BUG_ON(in_interrupt());
-
-	videobuf_waiton(q, &buf->vb, 0, 0);
-	videobuf_dma_unmap(q->dev, dma);
-	videobuf_dma_free(dma);
-	buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-
-/********************************************************************************/
-/* common buffer functions */
-
-int saa7146_buffer_queue(struct saa7146_dev *dev,
-			 struct saa7146_dmaqueue *q,
-			 struct saa7146_buf *buf)
-{
-	assert_spin_locked(&dev->slock);
-	DEB_EE("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf);
-
-	BUG_ON(!q);
-
-	if (NULL == q->curr) {
-		q->curr = buf;
-		DEB_D("immediately activating buffer %p\n", buf);
-		buf->activate(dev,buf,NULL);
-	} else {
-		list_add_tail(&buf->vb.queue,&q->queue);
-		buf->vb.state = VIDEOBUF_QUEUED;
-		DEB_D("adding buffer %p to queue. (active buffer present)\n",
-		      buf);
-	}
-	return 0;
-}
-
-void saa7146_buffer_finish(struct saa7146_dev *dev,
-			   struct saa7146_dmaqueue *q,
-			   int state)
-{
-	assert_spin_locked(&dev->slock);
-	DEB_EE("dev:%p, dmaq:%p, state:%d\n", dev, q, state);
-	DEB_EE("q->curr:%p\n", q->curr);
-
-	BUG_ON(!q->curr);
-
-	/* finish current buffer */
-	if (NULL == q->curr) {
-		DEB_D("aiii. no current buffer\n");
-		return;
-	}
-
-	q->curr->vb.state = state;
-	do_gettimeofday(&q->curr->vb.ts);
-	wake_up(&q->curr->vb.done);
-
-	q->curr = NULL;
-}
-
-void saa7146_buffer_next(struct saa7146_dev *dev,
-			 struct saa7146_dmaqueue *q, int vbi)
-{
-	struct saa7146_buf *buf,*next = NULL;
-
-	BUG_ON(!q);
-
-	DEB_INT("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi);
-
-	assert_spin_locked(&dev->slock);
-	if (!list_empty(&q->queue)) {
-		/* activate next one from queue */
-		buf = list_entry(q->queue.next,struct saa7146_buf,vb.queue);
-		list_del(&buf->vb.queue);
-		if (!list_empty(&q->queue))
-			next = list_entry(q->queue.next,struct saa7146_buf, vb.queue);
-		q->curr = buf;
-		DEB_INT("next buffer: buf:%p, prev:%p, next:%p\n",
-			buf, q->queue.prev, q->queue.next);
-		buf->activate(dev,buf,next);
-	} else {
-		DEB_INT("no next buffer. stopping.\n");
-		if( 0 != vbi ) {
-			/* turn off video-dma3 */
-			saa7146_write(dev,MC1, MASK_20);
-		} else {
-			/* nothing to do -- just prevent next video-dma1 transfer
-			   by lowering the protection address */
-
-			// fixme: fix this for vflip != 0
-
-			saa7146_write(dev, PROT_ADDR1, 0);
-			saa7146_write(dev, MC2, (MASK_02|MASK_18));
-
-			/* write the address of the rps-program */
-			saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle);
-			/* turn on rps */
-			saa7146_write(dev, MC1, (MASK_12 | MASK_28));
-
-/*
-			printk("vdma%d.base_even:     0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1));
-			printk("vdma%d.base_odd:      0x%08x\n", 1,saa7146_read(dev,BASE_ODD1));
-			printk("vdma%d.prot_addr:     0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1));
-			printk("vdma%d.base_page:     0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1));
-			printk("vdma%d.pitch:         0x%08x\n", 1,saa7146_read(dev,PITCH1));
-			printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1));
-*/
-		}
-		del_timer(&q->timeout);
-	}
-}
-
-void saa7146_buffer_timeout(unsigned long data)
-{
-	struct saa7146_dmaqueue *q = (struct saa7146_dmaqueue*)data;
-	struct saa7146_dev *dev = q->dev;
-	unsigned long flags;
-
-	DEB_EE("dev:%p, dmaq:%p\n", dev, q);
-
-	spin_lock_irqsave(&dev->slock,flags);
-	if (q->curr) {
-		DEB_D("timeout on %p\n", q->curr);
-		saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR);
-	}
-
-	/* we don't restart the transfer here like other drivers do. when
-	   a streaming capture is disabled, the timeout function will be
-	   called for the current buffer. if we activate the next buffer now,
-	   we mess up our capture logic. if a timeout occurs on another buffer,
-	   then something is seriously broken before, so no need to buffer the
-	   next capture IMHO... */
-/*
-	saa7146_buffer_next(dev,q);
-*/
-	spin_unlock_irqrestore(&dev->slock,flags);
-}
-
-/********************************************************************************/
-/* file operations */
-
-static int fops_open(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct saa7146_dev *dev = video_drvdata(file);
-	struct saa7146_fh *fh = NULL;
-	int result = 0;
-
-	DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev));
-
-	if (mutex_lock_interruptible(&saa7146_devices_lock))
-		return -ERESTARTSYS;
-
-	DEB_D("using: %p\n", dev);
-
-	/* check if an extension is registered */
-	if( NULL == dev->ext ) {
-		DEB_S("no extension registered for this device\n");
-		result = -ENODEV;
-		goto out;
-	}
-
-	/* allocate per open data */
-	fh = kzalloc(sizeof(*fh),GFP_KERNEL);
-	if (NULL == fh) {
-		DEB_S("cannot allocate memory for per open data\n");
-		result = -ENOMEM;
-		goto out;
-	}
-
-	v4l2_fh_init(&fh->fh, vdev);
-
-	file->private_data = &fh->fh;
-	fh->dev = dev;
-
-	if (vdev->vfl_type == VFL_TYPE_VBI) {
-		DEB_S("initializing vbi...\n");
-		if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
-			result = saa7146_vbi_uops.open(dev,file);
-		if (dev->ext_vv_data->vbi_fops.open)
-			dev->ext_vv_data->vbi_fops.open(file);
-	} else {
-		DEB_S("initializing video...\n");
-		result = saa7146_video_uops.open(dev,file);
-	}
-
-	if (0 != result) {
-		goto out;
-	}
-
-	if( 0 == try_module_get(dev->ext->module)) {
-		result = -EINVAL;
-		goto out;
-	}
-
-	result = 0;
-	v4l2_fh_add(&fh->fh);
-out:
-	if (fh && result != 0) {
-		kfree(fh);
-		file->private_data = NULL;
-	}
-	mutex_unlock(&saa7146_devices_lock);
-	return result;
-}
-
-static int fops_release(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct saa7146_fh  *fh  = file->private_data;
-	struct saa7146_dev *dev = fh->dev;
-
-	DEB_EE("file:%p\n", file);
-
-	if (mutex_lock_interruptible(&saa7146_devices_lock))
-		return -ERESTARTSYS;
-
-	if (vdev->vfl_type == VFL_TYPE_VBI) {
-		if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
-			saa7146_vbi_uops.release(dev,file);
-		if (dev->ext_vv_data->vbi_fops.release)
-			dev->ext_vv_data->vbi_fops.release(file);
-	} else {
-		saa7146_video_uops.release(dev,file);
-	}
-
-	v4l2_fh_del(&fh->fh);
-	v4l2_fh_exit(&fh->fh);
-	module_put(dev->ext->module);
-	file->private_data = NULL;
-	kfree(fh);
-
-	mutex_unlock(&saa7146_devices_lock);
-
-	return 0;
-}
-
-static int fops_mmap(struct file *file, struct vm_area_struct * vma)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct saa7146_fh *fh = file->private_data;
-	struct videobuf_queue *q;
-
-	switch (vdev->vfl_type) {
-	case VFL_TYPE_GRABBER: {
-		DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",
-		       file, vma);
-		q = &fh->video_q;
-		break;
-		}
-	case VFL_TYPE_VBI: {
-		DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",
-		       file, vma);
-		if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
-			return -ENODEV;
-		q = &fh->vbi_q;
-		break;
-		}
-	default:
-		BUG();
-		return 0;
-	}
-
-	return videobuf_mmap_mapper(q,vma);
-}
-
-static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct saa7146_fh *fh = file->private_data;
-	struct videobuf_buffer *buf = NULL;
-	struct videobuf_queue *q;
-	unsigned int res = v4l2_ctrl_poll(file, wait);
-
-	DEB_EE("file:%p, poll:%p\n", file, wait);
-
-	if (vdev->vfl_type == VFL_TYPE_VBI) {
-		if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
-			return res | POLLOUT | POLLWRNORM;
-		if( 0 == fh->vbi_q.streaming )
-			return res | videobuf_poll_stream(file, &fh->vbi_q, wait);
-		q = &fh->vbi_q;
-	} else {
-		DEB_D("using video queue\n");
-		q = &fh->video_q;
-	}
-
-	if (!list_empty(&q->stream))
-		buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
-
-	if (!buf) {
-		DEB_D("buf == NULL!\n");
-		return res | POLLERR;
-	}
-
-	poll_wait(file, &buf->done, wait);
-	if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) {
-		DEB_D("poll succeeded!\n");
-		return res | POLLIN | POLLRDNORM;
-	}
-
-	DEB_D("nothing to poll for, buf->state:%d\n", buf->state);
-	return res;
-}
-
-static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct saa7146_fh *fh = file->private_data;
-
-	switch (vdev->vfl_type) {
-	case VFL_TYPE_GRABBER:
-/*
-		DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun",
-		       file, data, (unsigned long)count);
-*/
-		return saa7146_video_uops.read(file,data,count,ppos);
-	case VFL_TYPE_VBI:
-/*
-		DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n",
-		       file, data, (unsigned long)count);
-*/
-		if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
-			return saa7146_vbi_uops.read(file,data,count,ppos);
-		return -EINVAL;
-	default:
-		BUG();
-		return 0;
-	}
-}
-
-static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct saa7146_fh *fh = file->private_data;
-
-	switch (vdev->vfl_type) {
-	case VFL_TYPE_GRABBER:
-		return -EINVAL;
-	case VFL_TYPE_VBI:
-		if (fh->dev->ext_vv_data->vbi_fops.write)
-			return fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
-		else
-			return -EINVAL;
-	default:
-		BUG();
-		return -EINVAL;
-	}
-}
-
-static const struct v4l2_file_operations video_fops =
-{
-	.owner		= THIS_MODULE,
-	.open		= fops_open,
-	.release	= fops_release,
-	.read		= fops_read,
-	.write		= fops_write,
-	.poll		= fops_poll,
-	.mmap		= fops_mmap,
-	.unlocked_ioctl	= video_ioctl2,
-};
-
-static void vv_callback(struct saa7146_dev *dev, unsigned long status)
-{
-	u32 isr = status;
-
-	DEB_INT("dev:%p, isr:0x%08x\n", dev, (u32)status);
-
-	if (0 != (isr & (MASK_27))) {
-		DEB_INT("irq: RPS0 (0x%08x)\n", isr);
-		saa7146_video_uops.irq_done(dev,isr);
-	}
-
-	if (0 != (isr & (MASK_28))) {
-		u32 mc2 = saa7146_read(dev, MC2);
-		if( 0 != (mc2 & MASK_15)) {
-			DEB_INT("irq: RPS1 vbi workaround (0x%08x)\n", isr);
-			wake_up(&dev->vv_data->vbi_wq);
-			saa7146_write(dev,MC2, MASK_31);
-			return;
-		}
-		DEB_INT("irq: RPS1 (0x%08x)\n", isr);
-		saa7146_vbi_uops.irq_done(dev,isr);
-	}
-}
-
-static const struct v4l2_ctrl_ops saa7146_ctrl_ops = {
-	.s_ctrl = saa7146_s_ctrl,
-};
-
-int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
-{
-	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
-	struct v4l2_pix_format *fmt;
-	struct v4l2_vbi_format *vbi;
-	struct saa7146_vv *vv;
-	int err;
-
-	err = v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev);
-	if (err)
-		return err;
-
-	v4l2_ctrl_handler_init(hdl, 6);
-	v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
-		V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
-	v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
-		V4L2_CID_CONTRAST, 0, 127, 1, 64);
-	v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
-		V4L2_CID_SATURATION, 0, 127, 1, 64);
-	v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
-		V4L2_CID_VFLIP, 0, 1, 1, 0);
-	v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
-		V4L2_CID_HFLIP, 0, 1, 1, 0);
-	if (hdl->error) {
-		err = hdl->error;
-		v4l2_ctrl_handler_free(hdl);
-		return err;
-	}
-	dev->v4l2_dev.ctrl_handler = hdl;
-
-	vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
-	if (vv == NULL) {
-		ERR("out of memory. aborting.\n");
-		v4l2_ctrl_handler_free(hdl);
-		return -ENOMEM;
-	}
-	ext_vv->vid_ops = saa7146_video_ioctl_ops;
-	ext_vv->vbi_ops = saa7146_vbi_ioctl_ops;
-	ext_vv->core_ops = &saa7146_video_ioctl_ops;
-
-	DEB_EE("dev:%p\n", dev);
-
-	/* set default values for video parts of the saa7146 */
-	saa7146_write(dev, BCS_CTRL, 0x80400040);
-
-	/* enable video-port pins */
-	saa7146_write(dev, MC1, (MASK_10 | MASK_26));
-
-	/* save per-device extension data (one extension can
-	   handle different devices that might need different
-	   configuration data) */
-	dev->ext_vv_data = ext_vv;
-
-	vv->d_clipping.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, &vv->d_clipping.dma_handle);
-	if( NULL == vv->d_clipping.cpu_addr ) {
-		ERR("out of memory. aborting.\n");
-		kfree(vv);
-		v4l2_ctrl_handler_free(hdl);
-		return -1;
-	}
-	memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM);
-
-	saa7146_video_uops.init(dev,vv);
-	if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
-		saa7146_vbi_uops.init(dev,vv);
-
-	fmt = &vv->ov_fb.fmt;
-	fmt->width = vv->standard->h_max_out;
-	fmt->height = vv->standard->v_max_out;
-	fmt->pixelformat = V4L2_PIX_FMT_RGB565;
-	fmt->bytesperline = 2 * fmt->width;
-	fmt->sizeimage = fmt->bytesperline * fmt->height;
-	fmt->colorspace = V4L2_COLORSPACE_SRGB;
-
-	fmt = &vv->video_fmt;
-	fmt->width = 384;
-	fmt->height = 288;
-	fmt->pixelformat = V4L2_PIX_FMT_BGR24;
-	fmt->field = V4L2_FIELD_ANY;
-	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
-	fmt->bytesperline = 3 * fmt->width;
-	fmt->sizeimage = fmt->bytesperline * fmt->height;
-
-	vbi = &vv->vbi_fmt;
-	vbi->sampling_rate	= 27000000;
-	vbi->offset		= 248; /* todo */
-	vbi->samples_per_line	= 720 * 2;
-	vbi->sample_format	= V4L2_PIX_FMT_GREY;
-
-	/* fixme: this only works for PAL */
-	vbi->start[0] = 5;
-	vbi->count[0] = 16;
-	vbi->start[1] = 312;
-	vbi->count[1] = 16;
-
-	init_timer(&vv->vbi_read_timeout);
-
-	vv->ov_fb.capability = V4L2_FBUF_CAP_LIST_CLIPPING;
-	vv->ov_fb.flags = V4L2_FBUF_FLAG_PRIMARY;
-	dev->vv_data = vv;
-	dev->vv_callback = &vv_callback;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(saa7146_vv_init);
-
-int saa7146_vv_release(struct saa7146_dev* dev)
-{
-	struct saa7146_vv *vv = dev->vv_data;
-
-	DEB_EE("dev:%p\n", dev);
-
-	v4l2_device_unregister(&dev->v4l2_dev);
-	pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
-	v4l2_ctrl_handler_free(&dev->ctrl_handler);
-	kfree(vv);
-	dev->vv_data = NULL;
-	dev->vv_callback = NULL;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(saa7146_vv_release);
-
-int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
-			    char *name, int type)
-{
-	struct video_device *vfd;
-	int err;
-	int i;
-
-	DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type);
-
-	// released by vfd->release
-	vfd = video_device_alloc();
-	if (vfd == NULL)
-		return -ENOMEM;
-
-	vfd->fops = &video_fops;
-	if (type == VFL_TYPE_GRABBER)
-		vfd->ioctl_ops = &dev->ext_vv_data->vid_ops;
-	else
-		vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops;
-	vfd->release = video_device_release;
-	/* Locking in file operations other than ioctl should be done by
-	   the driver, not the V4L2 core.
-	   This driver needs auditing so that this flag can be removed. */
-	set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
-	vfd->lock = &dev->v4l2_lock;
-	vfd->v4l2_dev = &dev->v4l2_dev;
-	vfd->tvnorms = 0;
-	set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
-	for (i = 0; i < dev->ext_vv_data->num_stds; i++)
-		vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
-	strlcpy(vfd->name, name, sizeof(vfd->name));
-	video_set_drvdata(vfd, dev);
-
-	err = video_register_device(vfd, type, -1);
-	if (err < 0) {
-		ERR("cannot register v4l2 device. skipping.\n");
-		video_device_release(vfd);
-		return err;
-	}
-
-	pr_info("%s: registered device %s [v4l2]\n",
-		dev->name, video_device_node_name(vfd));
-
-	*vid = vfd;
-	return 0;
-}
-EXPORT_SYMBOL_GPL(saa7146_register_device);
-
-int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
-{
-	DEB_EE("dev:%p\n", dev);
-
-	video_unregister_device(*vid);
-	*vid = NULL;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(saa7146_unregister_device);
-
-static int __init saa7146_vv_init_module(void)
-{
-	return 0;
-}
-
-
-static void __exit saa7146_vv_cleanup_module(void)
-{
-}
-
-module_init(saa7146_vv_init_module);
-module_exit(saa7146_vv_cleanup_module);
-
-MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
-MODULE_DESCRIPTION("video4linux driver for saa7146-based hardware");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c
deleted file mode 100644
index be746d1..0000000
--- a/drivers/media/common/saa7146_hlp.c
+++ /dev/null
@@ -1,1048 +0,0 @@
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <media/saa7146_vv.h>
-
-static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format)
-{
-	/* clear out the necessary bits */
-	*clip_format &= 0x0000ffff;
-	/* set these bits new */
-	*clip_format |=  (( ((palette&0xf00)>>8) << 30) | ((palette&0x00f) << 24) | (((palette&0x0f0)>>4) << 16));
-}
-
-static void calculate_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync, u32* hps_ctrl)
-{
-	*hps_ctrl &= ~(MASK_30 | MASK_31 | MASK_28);
-	*hps_ctrl |= (source << 30) | (sync << 28);
-}
-
-static void calculate_hxo_and_hyo(struct saa7146_vv *vv, u32* hps_h_scale, u32* hps_ctrl)
-{
-	int hyo = 0, hxo = 0;
-
-	hyo = vv->standard->v_offset;
-	hxo = vv->standard->h_offset;
-
-	*hps_h_scale	&= ~(MASK_B0 | 0xf00);
-	*hps_h_scale	|= (hxo <<  0);
-
-	*hps_ctrl	&= ~(MASK_W0 | MASK_B2);
-	*hps_ctrl	|= (hyo << 12);
-}
-
-/* helper functions for the calculation of the horizontal- and vertical
-   scaling registers, clip-format-register etc ...
-   these functions take pointers to the (most-likely read-out
-   original-values) and manipulate them according to the requested
-   changes.
-*/
-
-/* hps_coeff used for CXY and CXUV; scale 1/1 -> scale 1/64 */
-static struct {
-	u16 hps_coeff;
-	u16 weight_sum;
-} hps_h_coeff_tab [] = {
-	{0x00,   2}, {0x02,   4}, {0x00,   4}, {0x06,   8}, {0x02,   8},
-	{0x08,   8}, {0x00,   8}, {0x1E,  16}, {0x0E,   8}, {0x26,   8},
-	{0x06,   8}, {0x42,   8}, {0x02,   8}, {0x80,   8}, {0x00,   8},
-	{0xFE,  16}, {0xFE,   8}, {0x7E,   8}, {0x7E,   8}, {0x3E,   8},
-	{0x3E,   8}, {0x1E,   8}, {0x1E,   8}, {0x0E,   8}, {0x0E,   8},
-	{0x06,   8}, {0x06,   8}, {0x02,   8}, {0x02,   8}, {0x00,   8},
-	{0x00,   8}, {0xFE,  16}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8},
-	{0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8},
-	{0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8},
-	{0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0x7E,   8},
-	{0x7E,   8}, {0x3E,   8}, {0x3E,   8}, {0x1E,   8}, {0x1E,   8},
-	{0x0E,   8}, {0x0E,   8}, {0x06,   8}, {0x06,   8}, {0x02,   8},
-	{0x02,   8}, {0x00,   8}, {0x00,   8}, {0xFE,  16}
-};
-
-/* table of attenuation values for horizontal scaling */
-static u8 h_attenuation[] = { 1, 2, 4, 8, 2, 4, 8, 16, 0};
-
-/* calculate horizontal scale registers */
-static int calculate_h_scale_registers(struct saa7146_dev *dev,
-	int in_x, int out_x, int flip_lr,
-	u32* hps_ctrl, u32* hps_v_gain, u32* hps_h_prescale, u32* hps_h_scale)
-{
-	/* horizontal prescaler */
-	u32 dcgx = 0, xpsc = 0, xacm = 0, cxy = 0, cxuv = 0;
-	/* horizontal scaler */
-	u32 xim = 0, xp = 0, xsci =0;
-	/* vertical scale & gain */
-	u32 pfuv = 0;
-
-	/* helper variables */
-	u32 h_atten = 0, i = 0;
-
-	if ( 0 == out_x ) {
-		return -EINVAL;
-	}
-
-	/* mask out vanity-bit */
-	*hps_ctrl &= ~MASK_29;
-
-	/* calculate prescale-(xspc)-value:	[n   .. 1/2) : 1
-						[1/2 .. 1/3) : 2
-						[1/3 .. 1/4) : 3
-						...		*/
-	if (in_x > out_x) {
-		xpsc = in_x / out_x;
-	}
-	else {
-		/* zooming */
-		xpsc = 1;
-	}
-
-	/* if flip_lr-bit is set, number of pixels after
-	   horizontal prescaling must be < 384 */
-	if ( 0 != flip_lr ) {
-
-		/* set vanity bit */
-		*hps_ctrl |= MASK_29;
-
-		while (in_x / xpsc >= 384 )
-			xpsc++;
-	}
-	/* if zooming is wanted, number of pixels after
-	   horizontal prescaling must be < 768 */
-	else {
-		while ( in_x / xpsc >= 768 )
-			xpsc++;
-	}
-
-	/* maximum prescale is 64 (p.69) */
-	if ( xpsc > 64 )
-		xpsc = 64;
-
-	/* keep xacm clear*/
-	xacm = 0;
-
-	/* set horizontal filter parameters (CXY = CXUV) */
-	cxy = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].hps_coeff;
-	cxuv = cxy;
-
-	/* calculate and set horizontal fine scale (xsci) */
-
-	/* bypass the horizontal scaler ? */
-	if ( (in_x == out_x) && ( 1 == xpsc ) )
-		xsci = 0x400;
-	else
-		xsci = ( (1024 * in_x) / (out_x * xpsc) ) + xpsc;
-
-	/* set start phase for horizontal fine scale (xp) to 0 */
-	xp = 0;
-
-	/* set xim, if we bypass the horizontal scaler */
-	if ( 0x400 == xsci )
-		xim = 1;
-	else
-		xim = 0;
-
-	/* if the prescaler is bypassed, enable horizontal
-	   accumulation mode (xacm) and clear dcgx */
-	if( 1 == xpsc ) {
-		xacm = 1;
-		dcgx = 0;
-	} else {
-		xacm = 0;
-		/* get best match in the table of attenuations
-		   for horizontal scaling */
-		h_atten = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].weight_sum;
-
-		for (i = 0; h_attenuation[i] != 0; i++) {
-			if (h_attenuation[i] >= h_atten)
-				break;
-		}
-
-		dcgx = i;
-	}
-
-	/* the horizontal scaling increment controls the UV filter
-	   to reduce the bandwidth to improve the display quality,
-	   so set it ... */
-	if ( xsci == 0x400)
-		pfuv = 0x00;
-	else if ( xsci < 0x600)
-		pfuv = 0x01;
-	else if ( xsci < 0x680)
-		pfuv = 0x11;
-	else if ( xsci < 0x700)
-		pfuv = 0x22;
-	else
-		pfuv = 0x33;
-
-
-	*hps_v_gain  &= MASK_W0|MASK_B2;
-	*hps_v_gain  |= (pfuv << 24);
-
-	*hps_h_scale	&= ~(MASK_W1 | 0xf000);
-	*hps_h_scale	|= (xim << 31) | (xp << 24) | (xsci << 12);
-
-	*hps_h_prescale	|= (dcgx << 27) | ((xpsc-1) << 18) | (xacm << 17) | (cxy << 8) | (cxuv << 0);
-
-	return 0;
-}
-
-static struct {
-	u16 hps_coeff;
-	u16 weight_sum;
-} hps_v_coeff_tab [] = {
- {0x0100,   2},  {0x0102,   4},  {0x0300,   4},  {0x0106,   8},  {0x0502,   8},
- {0x0708,   8},  {0x0F00,   8},  {0x011E,  16},  {0x110E,  16},  {0x1926,  16},
- {0x3906,  16},  {0x3D42,  16},  {0x7D02,  16},  {0x7F80,  16},  {0xFF00,  16},
- {0x01FE,  32},  {0x01FE,  32},  {0x817E,  32},  {0x817E,  32},  {0xC13E,  32},
- {0xC13E,  32},  {0xE11E,  32},  {0xE11E,  32},  {0xF10E,  32},  {0xF10E,  32},
- {0xF906,  32},  {0xF906,  32},  {0xFD02,  32},  {0xFD02,  32},  {0xFF00,  32},
- {0xFF00,  32},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},
- {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},
- {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},
- {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x817E,  64},
- {0x817E,  64},  {0xC13E,  64},  {0xC13E,  64},  {0xE11E,  64},  {0xE11E,  64},
- {0xF10E,  64},  {0xF10E,  64},  {0xF906,  64},  {0xF906,  64},  {0xFD02,  64},
- {0xFD02,  64},  {0xFF00,  64},  {0xFF00,  64},  {0x01FE, 128}
-};
-
-/* table of attenuation values for vertical scaling */
-static u16 v_attenuation[] = { 2, 4, 8, 16, 32, 64, 128, 256, 0};
-
-/* calculate vertical scale registers */
-static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field field,
-	int in_y, int out_y, u32* hps_v_scale, u32* hps_v_gain)
-{
-	int lpi = 0;
-
-	/* vertical scaling */
-	u32 yacm = 0, ysci = 0, yacl = 0, ypo = 0, ype = 0;
-	/* vertical scale & gain */
-	u32 dcgy = 0, cya_cyb = 0;
-
-	/* helper variables */
-	u32 v_atten = 0, i = 0;
-
-	/* error, if vertical zooming */
-	if ( in_y < out_y ) {
-		return -EINVAL;
-	}
-
-	/* linear phase interpolation may be used
-	   if scaling is between 1 and 1/2 (both fields used)
-	   or scaling is between 1/2 and 1/4 (if only one field is used) */
-
-	if (V4L2_FIELD_HAS_BOTH(field)) {
-		if( 2*out_y >= in_y) {
-			lpi = 1;
-		}
-	} else if (field == V4L2_FIELD_TOP
-		|| field == V4L2_FIELD_ALTERNATE
-		|| field == V4L2_FIELD_BOTTOM) {
-		if( 4*out_y >= in_y ) {
-			lpi = 1;
-		}
-		out_y *= 2;
-	}
-	if( 0 != lpi ) {
-
-		yacm = 0;
-		yacl = 0;
-		cya_cyb = 0x00ff;
-
-		/* calculate scaling increment */
-		if ( in_y > out_y )
-			ysci = ((1024 * in_y) / (out_y + 1)) - 1024;
-		else
-			ysci = 0;
-
-		dcgy = 0;
-
-		/* calculate ype and ypo */
-		ype = ysci / 16;
-		ypo = ype + (ysci / 64);
-
-	} else {
-		yacm = 1;
-
-		/* calculate scaling increment */
-		ysci = (((10 * 1024 * (in_y - out_y - 1)) / in_y) + 9) / 10;
-
-		/* calculate ype and ypo */
-		ypo = ype = ((ysci + 15) / 16);
-
-		/* the sequence length interval (yacl) has to be set according
-		   to the prescale value, e.g.	[n   .. 1/2) : 0
-						[1/2 .. 1/3) : 1
-						[1/3 .. 1/4) : 2
-						... */
-		if ( ysci < 512) {
-			yacl = 0;
-		} else {
-			yacl = ( ysci / (1024 - ysci) );
-		}
-
-		/* get filter coefficients for cya, cyb from table hps_v_coeff_tab */
-		cya_cyb = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].hps_coeff;
-
-		/* get best match in the table of attenuations for vertical scaling */
-		v_atten = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].weight_sum;
-
-		for (i = 0; v_attenuation[i] != 0; i++) {
-			if (v_attenuation[i] >= v_atten)
-				break;
-		}
-
-		dcgy = i;
-	}
-
-	/* ypo and ype swapped in spec ? */
-	*hps_v_scale	|= (yacm << 31) | (ysci << 21) | (yacl << 15) | (ypo << 8 ) | (ype << 1);
-
-	*hps_v_gain	&= ~(MASK_W0|MASK_B2);
-	*hps_v_gain	|= (dcgy << 16) | (cya_cyb << 0);
-
-	return 0;
-}
-
-/* simple bubble-sort algorithm with duplicate elimination */
-static int sort_and_eliminate(u32* values, int* count)
-{
-	int low = 0, high = 0, top = 0, temp = 0;
-	int cur = 0, next = 0;
-
-	/* sanity checks */
-	if( (0 > *count) || (NULL == values) ) {
-		return -EINVAL;
-	}
-
-	/* bubble sort the first @count items of the array @values */
-	for( top = *count; top > 0; top--) {
-		for( low = 0, high = 1; high < top; low++, high++) {
-			if( values[low] > values[high] ) {
-				temp = values[low];
-				values[low] = values[high];
-				values[high] = temp;
-			}
-		}
-	}
-
-	/* remove duplicate items */
-	for( cur = 0, next = 1; next < *count; next++) {
-		if( values[cur] != values[next])
-			values[++cur] = values[next];
-	}
-
-	*count = cur + 1;
-
-	return 0;
-}
-
-static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct saa7146_fh *fh,
-	struct saa7146_video_dma *vdma2, u32* clip_format, u32* arbtr_ctrl, enum v4l2_field field)
-{
-	struct saa7146_vv *vv = dev->vv_data;
-	__le32 *clipping = vv->d_clipping.cpu_addr;
-
-	int width = vv->ov.win.w.width;
-	int height =  vv->ov.win.w.height;
-	int clipcount = vv->ov.nclips;
-
-	u32 line_list[32];
-	u32 pixel_list[32];
-	int numdwords = 0;
-
-	int i = 0, j = 0;
-	int cnt_line = 0, cnt_pixel = 0;
-
-	int x[32], y[32], w[32], h[32];
-
-	/* clear out memory */
-	memset(&line_list[0],  0x00, sizeof(u32)*32);
-	memset(&pixel_list[0], 0x00, sizeof(u32)*32);
-	memset(clipping,  0x00, SAA7146_CLIPPING_MEM);
-
-	/* fill the line and pixel-lists */
-	for(i = 0; i < clipcount; i++) {
-		int l = 0, r = 0, t = 0, b = 0;
-
-		x[i] = vv->ov.clips[i].c.left;
-		y[i] = vv->ov.clips[i].c.top;
-		w[i] = vv->ov.clips[i].c.width;
-		h[i] = vv->ov.clips[i].c.height;
-
-		if( w[i] < 0) {
-			x[i] += w[i]; w[i] = -w[i];
-		}
-		if( h[i] < 0) {
-			y[i] += h[i]; h[i] = -h[i];
-		}
-		if( x[i] < 0) {
-			w[i] += x[i]; x[i] = 0;
-		}
-		if( y[i] < 0) {
-			h[i] += y[i]; y[i] = 0;
-		}
-		if( 0 != vv->vflip ) {
-			y[i] = height - y[i] - h[i];
-		}
-
-		l = x[i];
-		r = x[i]+w[i];
-		t = y[i];
-		b = y[i]+h[i];
-
-		/* insert left/right coordinates */
-		pixel_list[ 2*i   ] = min_t(int, l, width);
-		pixel_list[(2*i)+1] = min_t(int, r, width);
-		/* insert top/bottom coordinates */
-		line_list[ 2*i   ] = min_t(int, t, height);
-		line_list[(2*i)+1] = min_t(int, b, height);
-	}
-
-	/* sort and eliminate lists */
-	cnt_line = cnt_pixel = 2*clipcount;
-	sort_and_eliminate( &pixel_list[0], &cnt_pixel );
-	sort_and_eliminate( &line_list[0], &cnt_line );
-
-	/* calculate the number of used u32s */
-	numdwords = max_t(int, (cnt_line+1), (cnt_pixel+1))*2;
-	numdwords = max_t(int, 4, numdwords);
-	numdwords = min_t(int, 64, numdwords);
-
-	/* fill up cliptable */
-	for(i = 0; i < cnt_pixel; i++) {
-		clipping[2*i] |= cpu_to_le32(pixel_list[i] << 16);
-	}
-	for(i = 0; i < cnt_line; i++) {
-		clipping[(2*i)+1] |= cpu_to_le32(line_list[i] << 16);
-	}
-
-	/* fill up cliptable with the display infos */
-	for(j = 0; j < clipcount; j++) {
-
-		for(i = 0; i < cnt_pixel; i++) {
-
-			if( x[j] < 0)
-				x[j] = 0;
-
-			if( pixel_list[i] < (x[j] + w[j])) {
-
-				if ( pixel_list[i] >= x[j] ) {
-					clipping[2*i] |= cpu_to_le32(1 << j);
-				}
-			}
-		}
-		for(i = 0; i < cnt_line; i++) {
-
-			if( y[j] < 0)
-				y[j] = 0;
-
-			if( line_list[i] < (y[j] + h[j]) ) {
-
-				if( line_list[i] >= y[j] ) {
-					clipping[(2*i)+1] |= cpu_to_le32(1 << j);
-				}
-			}
-		}
-	}
-
-	/* adjust arbitration control register */
-	*arbtr_ctrl &= 0xffff00ff;
-	*arbtr_ctrl |= 0x00001c00;
-
-	vdma2->base_even	= vv->d_clipping.dma_handle;
-	vdma2->base_odd		= vv->d_clipping.dma_handle;
-	vdma2->prot_addr	= vv->d_clipping.dma_handle+((sizeof(u32))*(numdwords));
-	vdma2->base_page	= 0x04;
-	vdma2->pitch		= 0x00;
-	vdma2->num_line_byte	= (0 << 16 | (sizeof(u32))*(numdwords-1) );
-
-	/* set clipping-mode. this depends on the field(s) used */
-	*clip_format &= 0xfffffff7;
-	if (V4L2_FIELD_HAS_BOTH(field)) {
-		*clip_format |= 0x00000008;
-	} else {
-		*clip_format |= 0x00000000;
-	}
-}
-
-/* disable clipping */
-static void saa7146_disable_clipping(struct saa7146_dev *dev)
-{
-	u32 clip_format	= saa7146_read(dev, CLIP_FORMAT_CTRL);
-
-	/* mask out relevant bits (=lower word)*/
-	clip_format &= MASK_W1;
-
-	/* upload clipping-registers*/
-	saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format);
-	saa7146_write(dev, MC2, (MASK_05 | MASK_21));
-
-	/* disable video dma2 */
-	saa7146_write(dev, MC1, MASK_21);
-}
-
-static void saa7146_set_clipping_rect(struct saa7146_fh *fh)
-{
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	enum v4l2_field field = vv->ov.win.field;
-	struct	saa7146_video_dma vdma2;
-	u32 clip_format;
-	u32 arbtr_ctrl;
-
-	/* check clipcount, disable clipping if clipcount == 0*/
-	if (vv->ov.nclips == 0) {
-		saa7146_disable_clipping(dev);
-		return;
-	}
-
-	clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL);
-	arbtr_ctrl = saa7146_read(dev, PCI_BT_V1);
-
-	calculate_clipping_registers_rect(dev, fh, &vdma2, &clip_format, &arbtr_ctrl, field);
-
-	/* set clipping format */
-	clip_format &= 0xffff0008;
-	clip_format |= (SAA7146_CLIPPING_RECT << 4);
-
-	/* prepare video dma2 */
-	saa7146_write(dev, BASE_EVEN2,		vdma2.base_even);
-	saa7146_write(dev, BASE_ODD2,		vdma2.base_odd);
-	saa7146_write(dev, PROT_ADDR2,		vdma2.prot_addr);
-	saa7146_write(dev, BASE_PAGE2,		vdma2.base_page);
-	saa7146_write(dev, PITCH2,		vdma2.pitch);
-	saa7146_write(dev, NUM_LINE_BYTE2,	vdma2.num_line_byte);
-
-	/* prepare the rest */
-	saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format);
-	saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
-
-	/* upload clip_control-register, clipping-registers, enable video dma2 */
-	saa7146_write(dev, MC2, (MASK_05 | MASK_21 | MASK_03 | MASK_19));
-	saa7146_write(dev, MC1, (MASK_05 | MASK_21));
-}
-
-static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, enum v4l2_field field)
-{
-	struct saa7146_vv *vv = dev->vv_data;
-
-	int source = vv->current_hps_source;
-	int sync = vv->current_hps_sync;
-
-	u32 hps_v_scale = 0, hps_v_gain  = 0, hps_ctrl = 0, hps_h_prescale = 0, hps_h_scale = 0;
-
-	/* set vertical scale */
-	hps_v_scale = 0; /* all bits get set by the function-call */
-	hps_v_gain  = 0; /* fixme: saa7146_read(dev, HPS_V_GAIN);*/
-	calculate_v_scale_registers(dev, field, vv->standard->v_field*2, height, &hps_v_scale, &hps_v_gain);
-
-	/* set horizontal scale */
-	hps_ctrl	= 0;
-	hps_h_prescale	= 0; /* all bits get set in the function */
-	hps_h_scale	= 0;
-	calculate_h_scale_registers(dev, vv->standard->h_pixels, width, vv->hflip, &hps_ctrl, &hps_v_gain, &hps_h_prescale, &hps_h_scale);
-
-	/* set hyo and hxo */
-	calculate_hxo_and_hyo(vv, &hps_h_scale, &hps_ctrl);
-	calculate_hps_source_and_sync(dev, source, sync, &hps_ctrl);
-
-	/* write out new register contents */
-	saa7146_write(dev, HPS_V_SCALE,	hps_v_scale);
-	saa7146_write(dev, HPS_V_GAIN,	hps_v_gain);
-	saa7146_write(dev, HPS_CTRL,	hps_ctrl);
-	saa7146_write(dev, HPS_H_PRESCALE,hps_h_prescale);
-	saa7146_write(dev, HPS_H_SCALE,	hps_h_scale);
-
-	/* upload shadow-ram registers */
-	saa7146_write(dev, MC2, (MASK_05 | MASK_06 | MASK_21 | MASK_22) );
-}
-
-/* calculate the new memory offsets for a desired position */
-static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat)
-{
-	struct saa7146_vv *vv = dev->vv_data;
-	struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pixelformat);
-
-	int b_depth = vv->ov_fmt->depth;
-	int b_bpl = vv->ov_fb.fmt.bytesperline;
-	/* The unsigned long cast is to remove a 64-bit compile warning since
-	   it looks like a 64-bit address is cast to a 32-bit value, even
-	   though the base pointer is really a 32-bit physical address that
-	   goes into a 32-bit DMA register.
-	   FIXME: might not work on some 64-bit platforms, but see the FIXME
-	   in struct v4l2_framebuffer (videodev2.h) for that.
-	 */
-	u32 base = (u32)(unsigned long)vv->ov_fb.base;
-
-	struct	saa7146_video_dma vdma1;
-
-	/* calculate memory offsets for picture, look if we shall top-down-flip */
-	vdma1.pitch	= 2*b_bpl;
-	if ( 0 == vv->vflip ) {
-		vdma1.base_even = base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
-		vdma1.base_odd  = vdma1.base_even + (vdma1.pitch / 2);
-		vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2));
-	}
-	else {
-		vdma1.base_even = base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
-		vdma1.base_odd  = vdma1.base_even - (vdma1.pitch / 2);
-		vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2));
-	}
-
-	if (V4L2_FIELD_HAS_BOTH(field)) {
-	} else if (field == V4L2_FIELD_ALTERNATE) {
-		/* fixme */
-		vdma1.base_odd = vdma1.prot_addr;
-		vdma1.pitch /= 2;
-	} else if (field == V4L2_FIELD_TOP) {
-		vdma1.base_odd = vdma1.prot_addr;
-		vdma1.pitch /= 2;
-	} else if (field == V4L2_FIELD_BOTTOM) {
-		vdma1.base_odd = vdma1.base_even;
-		vdma1.base_even = vdma1.prot_addr;
-		vdma1.pitch /= 2;
-	}
-
-	if ( 0 != vv->vflip ) {
-		vdma1.pitch *= -1;
-	}
-
-	vdma1.base_page = sfmt->swap;
-	vdma1.num_line_byte = (vv->standard->v_field<<16)+vv->standard->h_pixels;
-
-	saa7146_write_out_dma(dev, 1, &vdma1);
-}
-
-static void saa7146_set_output_format(struct saa7146_dev *dev, unsigned long palette)
-{
-	u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL);
-
-	/* call helper function */
-	calculate_output_format_register(dev,palette,&clip_format);
-
-	/* update the hps registers */
-	saa7146_write(dev, CLIP_FORMAT_CTRL, clip_format);
-	saa7146_write(dev, MC2, (MASK_05 | MASK_21));
-}
-
-/* select input-source */
-void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync)
-{
-	struct saa7146_vv *vv = dev->vv_data;
-	u32 hps_ctrl = 0;
-
-	/* read old state */
-	hps_ctrl = saa7146_read(dev, HPS_CTRL);
-
-	hps_ctrl &= ~( MASK_31 | MASK_30 | MASK_28 );
-	hps_ctrl |= (source << 30) | (sync << 28);
-
-	/* write back & upload register */
-	saa7146_write(dev, HPS_CTRL, hps_ctrl);
-	saa7146_write(dev, MC2, (MASK_05 | MASK_21));
-
-	vv->current_hps_source = source;
-	vv->current_hps_sync = sync;
-}
-EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
-
-int saa7146_enable_overlay(struct saa7146_fh *fh)
-{
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-
-	saa7146_set_window(dev, vv->ov.win.w.width, vv->ov.win.w.height, vv->ov.win.field);
-	saa7146_set_position(dev, vv->ov.win.w.left, vv->ov.win.w.top, vv->ov.win.w.height, vv->ov.win.field, vv->ov_fmt->pixelformat);
-	saa7146_set_output_format(dev, vv->ov_fmt->trans);
-	saa7146_set_clipping_rect(fh);
-
-	/* enable video dma1 */
-	saa7146_write(dev, MC1, (MASK_06 | MASK_22));
-	return 0;
-}
-
-void saa7146_disable_overlay(struct saa7146_fh *fh)
-{
-	struct saa7146_dev *dev = fh->dev;
-
-	/* disable clipping + video dma1 */
-	saa7146_disable_clipping(dev);
-	saa7146_write(dev, MC1, MASK_22);
-}
-
-void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma)
-{
-	int where = 0;
-
-	if( which < 1 || which > 3) {
-		return;
-	}
-
-	/* calculate starting address */
-	where  = (which-1)*0x18;
-
-	saa7146_write(dev, where,	vdma->base_odd);
-	saa7146_write(dev, where+0x04,	vdma->base_even);
-	saa7146_write(dev, where+0x08,	vdma->prot_addr);
-	saa7146_write(dev, where+0x0c,	vdma->pitch);
-	saa7146_write(dev, where+0x10,	vdma->base_page);
-	saa7146_write(dev, where+0x14,	vdma->num_line_byte);
-
-	/* upload */
-	saa7146_write(dev, MC2, (MASK_02<<(which-1))|(MASK_18<<(which-1)));
-/*
-	printk("vdma%d.base_even:     0x%08x\n", which,vdma->base_even);
-	printk("vdma%d.base_odd:      0x%08x\n", which,vdma->base_odd);
-	printk("vdma%d.prot_addr:     0x%08x\n", which,vdma->prot_addr);
-	printk("vdma%d.base_page:     0x%08x\n", which,vdma->base_page);
-	printk("vdma%d.pitch:         0x%08x\n", which,vdma->pitch);
-	printk("vdma%d.num_line_byte: 0x%08x\n", which,vdma->num_line_byte);
-*/
-}
-
-static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa7146_buf *buf)
-{
-	struct saa7146_vv *vv = dev->vv_data;
-	struct saa7146_video_dma vdma1;
-
-	struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
-
-	int width = buf->fmt->width;
-	int height = buf->fmt->height;
-	int bytesperline = buf->fmt->bytesperline;
-	enum v4l2_field field = buf->fmt->field;
-
-	int depth = sfmt->depth;
-
-	DEB_CAP("[size=%dx%d,fields=%s]\n",
-		width, height, v4l2_field_names[field]);
-
-	if( bytesperline != 0) {
-		vdma1.pitch = bytesperline*2;
-	} else {
-		vdma1.pitch = (width*depth*2)/8;
-	}
-	vdma1.num_line_byte	= ((vv->standard->v_field<<16) + vv->standard->h_pixels);
-	vdma1.base_page		= buf->pt[0].dma | ME1 | sfmt->swap;
-
-	if( 0 != vv->vflip ) {
-		vdma1.prot_addr	= buf->pt[0].offset;
-		vdma1.base_even	= buf->pt[0].offset+(vdma1.pitch/2)*height;
-		vdma1.base_odd	= vdma1.base_even - (vdma1.pitch/2);
-	} else {
-		vdma1.base_even	= buf->pt[0].offset;
-		vdma1.base_odd	= vdma1.base_even + (vdma1.pitch/2);
-		vdma1.prot_addr	= buf->pt[0].offset+(vdma1.pitch/2)*height;
-	}
-
-	if (V4L2_FIELD_HAS_BOTH(field)) {
-	} else if (field == V4L2_FIELD_ALTERNATE) {
-		/* fixme */
-		if ( vv->last_field == V4L2_FIELD_TOP ) {
-			vdma1.base_odd	= vdma1.prot_addr;
-			vdma1.pitch /= 2;
-		} else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {
-			vdma1.base_odd	= vdma1.base_even;
-			vdma1.base_even = vdma1.prot_addr;
-			vdma1.pitch /= 2;
-		}
-	} else if (field == V4L2_FIELD_TOP) {
-		vdma1.base_odd	= vdma1.prot_addr;
-		vdma1.pitch /= 2;
-	} else if (field == V4L2_FIELD_BOTTOM) {
-		vdma1.base_odd	= vdma1.base_even;
-		vdma1.base_even = vdma1.prot_addr;
-		vdma1.pitch /= 2;
-	}
-
-	if( 0 != vv->vflip ) {
-		vdma1.pitch *= -1;
-	}
-
-	saa7146_write_out_dma(dev, 1, &vdma1);
-	return 0;
-}
-
-static int calc_planar_422(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3)
-{
-	int height = buf->fmt->height;
-	int width = buf->fmt->width;
-
-	vdma2->pitch	= width;
-	vdma3->pitch	= width;
-
-	/* fixme: look at bytesperline! */
-
-	if( 0 != vv->vflip ) {
-		vdma2->prot_addr	= buf->pt[1].offset;
-		vdma2->base_even	= ((vdma2->pitch/2)*height)+buf->pt[1].offset;
-		vdma2->base_odd		= vdma2->base_even - (vdma2->pitch/2);
-
-		vdma3->prot_addr	= buf->pt[2].offset;
-		vdma3->base_even	= ((vdma3->pitch/2)*height)+buf->pt[2].offset;
-		vdma3->base_odd		= vdma3->base_even - (vdma3->pitch/2);
-	} else {
-		vdma3->base_even	= buf->pt[2].offset;
-		vdma3->base_odd		= vdma3->base_even + (vdma3->pitch/2);
-		vdma3->prot_addr	= (vdma3->pitch/2)*height+buf->pt[2].offset;
-
-		vdma2->base_even	= buf->pt[1].offset;
-		vdma2->base_odd		= vdma2->base_even + (vdma2->pitch/2);
-		vdma2->prot_addr	= (vdma2->pitch/2)*height+buf->pt[1].offset;
-	}
-
-	return 0;
-}
-
-static int calc_planar_420(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3)
-{
-	int height = buf->fmt->height;
-	int width = buf->fmt->width;
-
-	vdma2->pitch	= width/2;
-	vdma3->pitch	= width/2;
-
-	if( 0 != vv->vflip ) {
-		vdma2->prot_addr	= buf->pt[2].offset;
-		vdma2->base_even	= ((vdma2->pitch/2)*height)+buf->pt[2].offset;
-		vdma2->base_odd		= vdma2->base_even - (vdma2->pitch/2);
-
-		vdma3->prot_addr	= buf->pt[1].offset;
-		vdma3->base_even	= ((vdma3->pitch/2)*height)+buf->pt[1].offset;
-		vdma3->base_odd		= vdma3->base_even - (vdma3->pitch/2);
-
-	} else {
-		vdma3->base_even	= buf->pt[2].offset;
-		vdma3->base_odd		= vdma3->base_even + (vdma3->pitch);
-		vdma3->prot_addr	= (vdma3->pitch/2)*height+buf->pt[2].offset;
-
-		vdma2->base_even	= buf->pt[1].offset;
-		vdma2->base_odd		= vdma2->base_even + (vdma2->pitch);
-		vdma2->prot_addr	= (vdma2->pitch/2)*height+buf->pt[1].offset;
-	}
-	return 0;
-}
-
-static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa7146_buf *buf)
-{
-	struct saa7146_vv *vv = dev->vv_data;
-	struct saa7146_video_dma vdma1;
-	struct saa7146_video_dma vdma2;
-	struct saa7146_video_dma vdma3;
-
-	struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
-
-	int width = buf->fmt->width;
-	int height = buf->fmt->height;
-	enum v4l2_field field = buf->fmt->field;
-
-	BUG_ON(0 == buf->pt[0].dma);
-	BUG_ON(0 == buf->pt[1].dma);
-	BUG_ON(0 == buf->pt[2].dma);
-
-	DEB_CAP("[size=%dx%d,fields=%s]\n",
-		width, height, v4l2_field_names[field]);
-
-	/* fixme: look at bytesperline! */
-
-	/* fixme: what happens for user space buffers here?. The offsets are
-	   most likely wrong, this version here only works for page-aligned
-	   buffers, modifications to the pagetable-functions are necessary...*/
-
-	vdma1.pitch		= width*2;
-	vdma1.num_line_byte	= ((vv->standard->v_field<<16) + vv->standard->h_pixels);
-	vdma1.base_page		= buf->pt[0].dma | ME1;
-
-	if( 0 != vv->vflip ) {
-		vdma1.prot_addr	= buf->pt[0].offset;
-		vdma1.base_even	= ((vdma1.pitch/2)*height)+buf->pt[0].offset;
-		vdma1.base_odd	= vdma1.base_even - (vdma1.pitch/2);
-	} else {
-		vdma1.base_even	= buf->pt[0].offset;
-		vdma1.base_odd	= vdma1.base_even + (vdma1.pitch/2);
-		vdma1.prot_addr	= (vdma1.pitch/2)*height+buf->pt[0].offset;
-	}
-
-	vdma2.num_line_byte	= 0; /* unused */
-	vdma2.base_page		= buf->pt[1].dma | ME1;
-
-	vdma3.num_line_byte	= 0; /* unused */
-	vdma3.base_page		= buf->pt[2].dma | ME1;
-
-	switch( sfmt->depth ) {
-		case 12: {
-			calc_planar_420(vv,buf,&vdma2,&vdma3);
-			break;
-		}
-		case 16: {
-			calc_planar_422(vv,buf,&vdma2,&vdma3);
-			break;
-		}
-		default: {
-			return -1;
-		}
-	}
-
-	if (V4L2_FIELD_HAS_BOTH(field)) {
-	} else if (field == V4L2_FIELD_ALTERNATE) {
-		/* fixme */
-		vdma1.base_odd	= vdma1.prot_addr;
-		vdma1.pitch /= 2;
-		vdma2.base_odd	= vdma2.prot_addr;
-		vdma2.pitch /= 2;
-		vdma3.base_odd	= vdma3.prot_addr;
-		vdma3.pitch /= 2;
-	} else if (field == V4L2_FIELD_TOP) {
-		vdma1.base_odd	= vdma1.prot_addr;
-		vdma1.pitch /= 2;
-		vdma2.base_odd	= vdma2.prot_addr;
-		vdma2.pitch /= 2;
-		vdma3.base_odd	= vdma3.prot_addr;
-		vdma3.pitch /= 2;
-	} else if (field == V4L2_FIELD_BOTTOM) {
-		vdma1.base_odd	= vdma1.base_even;
-		vdma1.base_even = vdma1.prot_addr;
-		vdma1.pitch /= 2;
-		vdma2.base_odd	= vdma2.base_even;
-		vdma2.base_even = vdma2.prot_addr;
-		vdma2.pitch /= 2;
-		vdma3.base_odd	= vdma3.base_even;
-		vdma3.base_even = vdma3.prot_addr;
-		vdma3.pitch /= 2;
-	}
-
-	if( 0 != vv->vflip ) {
-		vdma1.pitch *= -1;
-		vdma2.pitch *= -1;
-		vdma3.pitch *= -1;
-	}
-
-	saa7146_write_out_dma(dev, 1, &vdma1);
-	if( (sfmt->flags & FORMAT_BYTE_SWAP) != 0 ) {
-		saa7146_write_out_dma(dev, 3, &vdma2);
-		saa7146_write_out_dma(dev, 2, &vdma3);
-	} else {
-		saa7146_write_out_dma(dev, 2, &vdma2);
-		saa7146_write_out_dma(dev, 3, &vdma3);
-	}
-	return 0;
-}
-
-static void program_capture_engine(struct saa7146_dev *dev, int planar)
-{
-	struct saa7146_vv *vv = dev->vv_data;
-	int count = 0;
-
-	unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B;
-	unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B;
-
-	/* wait for o_fid_a/b / e_fid_a/b toggle only if rps register 0 is not set*/
-	WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | o_wait);
-	WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait);
-
-	/* set rps register 0 */
-	WRITE_RPS0(CMD_WR_REG | (1 << 8) | (MC2/4));
-	WRITE_RPS0(MASK_27 | MASK_11);
-
-	/* turn on video-dma1 */
-	WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
-	WRITE_RPS0(MASK_06 | MASK_22);			/* => mask */
-	WRITE_RPS0(MASK_06 | MASK_22);			/* => values */
-	if( 0 != planar ) {
-		/* turn on video-dma2 */
-		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
-		WRITE_RPS0(MASK_05 | MASK_21);			/* => mask */
-		WRITE_RPS0(MASK_05 | MASK_21);			/* => values */
-
-		/* turn on video-dma3 */
-		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
-		WRITE_RPS0(MASK_04 | MASK_20);			/* => mask */
-		WRITE_RPS0(MASK_04 | MASK_20);			/* => values */
-	}
-
-	/* wait for o_fid_a/b / e_fid_a/b toggle */
-	if ( vv->last_field == V4L2_FIELD_INTERLACED ) {
-		WRITE_RPS0(CMD_PAUSE | o_wait);
-		WRITE_RPS0(CMD_PAUSE | e_wait);
-	} else if ( vv->last_field == V4L2_FIELD_TOP ) {
-		WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09));
-		WRITE_RPS0(CMD_PAUSE | o_wait);
-	} else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {
-		WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09));
-		WRITE_RPS0(CMD_PAUSE | e_wait);
-	}
-
-	/* turn off video-dma1 */
-	WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
-	WRITE_RPS0(MASK_22 | MASK_06);			/* => mask */
-	WRITE_RPS0(MASK_22);				/* => values */
-	if( 0 != planar ) {
-		/* turn off video-dma2 */
-		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
-		WRITE_RPS0(MASK_05 | MASK_21);			/* => mask */
-		WRITE_RPS0(MASK_21);				/* => values */
-
-		/* turn off video-dma3 */
-		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
-		WRITE_RPS0(MASK_04 | MASK_20);			/* => mask */
-		WRITE_RPS0(MASK_20);				/* => values */
-	}
-
-	/* generate interrupt */
-	WRITE_RPS0(CMD_INTERRUPT);
-
-	/* stop */
-	WRITE_RPS0(CMD_STOP);
-}
-
-void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next)
-{
-	struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
-	struct saa7146_vv *vv = dev->vv_data;
-	u32 vdma1_prot_addr;
-
-	DEB_CAP("buf:%p, next:%p\n", buf, next);
-
-	vdma1_prot_addr = saa7146_read(dev, PROT_ADDR1);
-	if( 0 == vdma1_prot_addr ) {
-		/* clear out beginning of streaming bit (rps register 0)*/
-		DEB_CAP("forcing sync to new frame\n");
-		saa7146_write(dev, MC2, MASK_27 );
-	}
-
-	saa7146_set_window(dev, buf->fmt->width, buf->fmt->height, buf->fmt->field);
-	saa7146_set_output_format(dev, sfmt->trans);
-	saa7146_disable_clipping(dev);
-
-	if ( vv->last_field == V4L2_FIELD_INTERLACED ) {
-	} else if ( vv->last_field == V4L2_FIELD_TOP ) {
-		vv->last_field = V4L2_FIELD_BOTTOM;
-	} else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {
-		vv->last_field = V4L2_FIELD_TOP;
-	}
-
-	if( 0 != IS_PLANAR(sfmt->trans)) {
-		calculate_video_dma_grab_planar(dev, buf);
-		program_capture_engine(dev,1);
-	} else {
-		calculate_video_dma_grab_packed(dev, buf);
-		program_capture_engine(dev,0);
-	}
-
-/*
-	printk("vdma%d.base_even:     0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1));
-	printk("vdma%d.base_odd:      0x%08x\n", 1,saa7146_read(dev,BASE_ODD1));
-	printk("vdma%d.prot_addr:     0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1));
-	printk("vdma%d.base_page:     0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1));
-	printk("vdma%d.pitch:         0x%08x\n", 1,saa7146_read(dev,PITCH1));
-	printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1));
-	printk("vdma%d => vptr      : 0x%08x\n", 1,saa7146_read(dev,PCI_VDP1));
-*/
-
-	/* write the address of the rps-program */
-	saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle);
-
-	/* turn on rps */
-	saa7146_write(dev, MC1, (MASK_12 | MASK_28));
-}
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c
deleted file mode 100644
index 2202719..0000000
--- a/drivers/media/common/saa7146_i2c.c
+++ /dev/null
@@ -1,423 +0,0 @@
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <media/saa7146_vv.h>
-
-static u32 saa7146_i2c_func(struct i2c_adapter *adapter)
-{
-	/* DEB_I2C("'%s'\n", adapter->name); */
-
-	return	  I2C_FUNC_I2C
-		| I2C_FUNC_SMBUS_QUICK
-		| I2C_FUNC_SMBUS_READ_BYTE	| I2C_FUNC_SMBUS_WRITE_BYTE
-		| I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
-}
-
-/* this function returns the status-register of our i2c-device */
-static inline u32 saa7146_i2c_status(struct saa7146_dev *dev)
-{
-	u32 iicsta = saa7146_read(dev, I2C_STATUS);
-	/* DEB_I2C("status: 0x%08x\n", iicsta); */
-	return iicsta;
-}
-
-/* this function runs through the i2c-messages and prepares the data to be
-   sent through the saa7146. have a look at the specifications p. 122 ff
-   to understand this. it returns the number of u32s to send, or -1
-   in case of an error. */
-static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op)
-{
-	int h1, h2;
-	int i, j, addr;
-	int mem = 0, op_count = 0;
-
-	/* first determine size of needed memory */
-	for(i = 0; i < num; i++) {
-		mem += m[i].len + 1;
-	}
-
-	/* worst case: we need one u32 for three bytes to be send
-	   plus one extra byte to address the device */
-	mem = 1 + ((mem-1) / 3);
-
-	/* we assume that op points to a memory of at least
-	 * SAA7146_I2C_MEM bytes size. if we exceed this limit...
-	 */
-	if ((4 * mem) > SAA7146_I2C_MEM) {
-		/* DEB_I2C("cannot prepare i2c-message\n"); */
-		return -ENOMEM;
-	}
-
-	/* be careful: clear out the i2c-mem first */
-	memset(op,0,sizeof(__le32)*mem);
-
-	/* loop through all messages */
-	for(i = 0; i < num; i++) {
-
-		/* insert the address of the i2c-slave.
-		   note: we get 7 bit i2c-addresses,
-		   so we have to perform a translation */
-		addr = (m[i].addr*2) + ( (0 != (m[i].flags & I2C_M_RD)) ? 1 : 0);
-		h1 = op_count/3; h2 = op_count%3;
-		op[h1] |= cpu_to_le32(	    (u8)addr << ((3-h2)*8));
-		op[h1] |= cpu_to_le32(SAA7146_I2C_START << ((3-h2)*2));
-		op_count++;
-
-		/* loop through all bytes of message i */
-		for(j = 0; j < m[i].len; j++) {
-			/* insert the data bytes */
-			h1 = op_count/3; h2 = op_count%3;
-			op[h1] |= cpu_to_le32( (u32)((u8)m[i].buf[j]) << ((3-h2)*8));
-			op[h1] |= cpu_to_le32(       SAA7146_I2C_CONT << ((3-h2)*2));
-			op_count++;
-		}
-
-	}
-
-	/* have a look at the last byte inserted:
-	  if it was: ...CONT change it to ...STOP */
-	h1 = (op_count-1)/3; h2 = (op_count-1)%3;
-	if ( SAA7146_I2C_CONT == (0x3 & (le32_to_cpu(op[h1]) >> ((3-h2)*2))) ) {
-		op[h1] &= ~cpu_to_le32(0x2 << ((3-h2)*2));
-		op[h1] |= cpu_to_le32(SAA7146_I2C_STOP << ((3-h2)*2));
-	}
-
-	/* return the number of u32s to send */
-	return mem;
-}
-
-/* this functions loops through all i2c-messages. normally, it should determine
-   which bytes were read through the adapter and write them back to the corresponding
-   i2c-message. but instead, we simply write back all bytes.
-   fixme: this could be improved. */
-static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, __le32 *op)
-{
-	int i, j;
-	int op_count = 0;
-
-	/* loop through all messages */
-	for(i = 0; i < num; i++) {
-
-		op_count++;
-
-		/* loop through all bytes of message i */
-		for(j = 0; j < m[i].len; j++) {
-			/* write back all bytes that could have been read */
-			m[i].buf[j] = (le32_to_cpu(op[op_count/3]) >> ((3-(op_count%3))*8));
-			op_count++;
-		}
-	}
-
-	return 0;
-}
-
-/* this functions resets the i2c-device and returns 0 if everything was fine, otherwise -1 */
-static int saa7146_i2c_reset(struct saa7146_dev *dev)
-{
-	/* get current status */
-	u32 status = saa7146_i2c_status(dev);
-
-	/* clear registers for sure */
-	saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
-	saa7146_write(dev, I2C_TRANSFER, 0);
-
-	/* check if any operation is still in progress */
-	if ( 0 != ( status & SAA7146_I2C_BUSY) ) {
-
-		/* yes, kill ongoing operation */
-		DEB_I2C("busy_state detected\n");
-
-		/* set "ABORT-OPERATION"-bit (bit 7)*/
-		saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07));
-		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
-		msleep(SAA7146_I2C_DELAY);
-
-		/* clear all error-bits pending; this is needed because p.123, note 1 */
-		saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
-		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
-		msleep(SAA7146_I2C_DELAY);
-	}
-
-	/* check if any error is (still) present. (this can be necessary because p.123, note 1) */
-	status = saa7146_i2c_status(dev);
-
-	if ( dev->i2c_bitrate != status ) {
-
-		DEB_I2C("error_state detected. status:0x%08x\n", status);
-
-		/* Repeat the abort operation. This seems to be necessary
-		   after serious protocol errors caused by e.g. the SAA7740 */
-		saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07));
-		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
-		msleep(SAA7146_I2C_DELAY);
-
-		/* clear all error-bits pending */
-		saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
-		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
-		msleep(SAA7146_I2C_DELAY);
-
-		/* the data sheet says it might be necessary to clear the status
-		   twice after an abort */
-		saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
-		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
-		msleep(SAA7146_I2C_DELAY);
-	}
-
-	/* if any error is still present, a fatal error has occurred ... */
-	status = saa7146_i2c_status(dev);
-	if ( dev->i2c_bitrate != status ) {
-		DEB_I2C("fatal error. status:0x%08x\n", status);
-		return -1;
-	}
-
-	return 0;
-}
-
-/* this functions writes out the data-byte 'dword' to the i2c-device.
-   it returns 0 if ok, -1 if the transfer failed, -2 if the transfer
-   failed badly (e.g. address error) */
-static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int short_delay)
-{
-	u32 status = 0, mc2 = 0;
-	int trial = 0;
-	unsigned long timeout;
-
-	/* write out i2c-command */
-	DEB_I2C("before: 0x%08x (status: 0x%08x), %d\n",
-		*dword, saa7146_read(dev, I2C_STATUS), dev->i2c_op);
-
-	if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) {
-
-		saa7146_write(dev, I2C_STATUS,	 dev->i2c_bitrate);
-		saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
-
-		dev->i2c_op = 1;
-		SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
-		SAA7146_IER_ENABLE(dev, MASK_16|MASK_17);
-		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
-
-		timeout = HZ/100 + 1; /* 10ms */
-		timeout = wait_event_interruptible_timeout(dev->i2c_wq, dev->i2c_op == 0, timeout);
-		if (timeout == -ERESTARTSYS || dev->i2c_op) {
-			SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
-			SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
-			if (timeout == -ERESTARTSYS)
-				/* a signal arrived */
-				return -ERESTARTSYS;
-
-			pr_warn("%s %s [irq]: timed out waiting for end of xfer\n",
-				dev->name, __func__);
-			return -EIO;
-		}
-		status = saa7146_read(dev, I2C_STATUS);
-	} else {
-		saa7146_write(dev, I2C_STATUS,	 dev->i2c_bitrate);
-		saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
-		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
-
-		/* do not poll for i2c-status before upload is complete */
-		timeout = jiffies + HZ/100 + 1; /* 10ms */
-		while(1) {
-			mc2 = (saa7146_read(dev, MC2) & 0x1);
-			if( 0 != mc2 ) {
-				break;
-			}
-			if (time_after(jiffies,timeout)) {
-				pr_warn("%s %s: timed out waiting for MC2\n",
-					dev->name, __func__);
-				return -EIO;
-			}
-		}
-		/* wait until we get a transfer done or error */
-		timeout = jiffies + HZ/100 + 1; /* 10ms */
-		/* first read usually delivers bogus results... */
-		saa7146_i2c_status(dev);
-		while(1) {
-			status = saa7146_i2c_status(dev);
-			if ((status & 0x3) != 1)
-				break;
-			if (time_after(jiffies,timeout)) {
-				/* this is normal when probing the bus
-				 * (no answer from nonexisistant device...)
-				 */
-				pr_warn("%s %s [poll]: timed out waiting for end of xfer\n",
-					dev->name, __func__);
-				return -EIO;
-			}
-			if (++trial < 50 && short_delay)
-				udelay(10);
-			else
-				msleep(1);
-		}
-	}
-
-	/* give a detailed status report */
-	if ( 0 != (status & (SAA7146_I2C_SPERR | SAA7146_I2C_APERR |
-			     SAA7146_I2C_DTERR | SAA7146_I2C_DRERR |
-			     SAA7146_I2C_AL    | SAA7146_I2C_ERR   |
-			     SAA7146_I2C_BUSY)) ) {
-
-		if ( 0 == (status & SAA7146_I2C_ERR) ||
-		     0 == (status & SAA7146_I2C_BUSY) ) {
-			/* it may take some time until ERR goes high - ignore */
-			DEB_I2C("unexpected i2c status %04x\n", status);
-		}
-		if( 0 != (status & SAA7146_I2C_SPERR) ) {
-			DEB_I2C("error due to invalid start/stop condition\n");
-		}
-		if( 0 != (status & SAA7146_I2C_DTERR) ) {
-			DEB_I2C("error in data transmission\n");
-		}
-		if( 0 != (status & SAA7146_I2C_DRERR) ) {
-			DEB_I2C("error when receiving data\n");
-		}
-		if( 0 != (status & SAA7146_I2C_AL) ) {
-			DEB_I2C("error because arbitration lost\n");
-		}
-
-		/* we handle address-errors here */
-		if( 0 != (status & SAA7146_I2C_APERR) ) {
-			DEB_I2C("error in address phase\n");
-			return -EREMOTEIO;
-		}
-
-		return -EIO;
-	}
-
-	/* read back data, just in case we were reading ... */
-	*dword = cpu_to_le32(saa7146_read(dev, I2C_TRANSFER));
-
-	DEB_I2C("after: 0x%08x\n", *dword);
-	return 0;
-}
-
-static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
-{
-	int i = 0, count = 0;
-	__le32 *buffer = dev->d_i2c.cpu_addr;
-	int err = 0;
-	int short_delay = 0;
-
-	if (mutex_lock_interruptible(&dev->i2c_lock))
-		return -ERESTARTSYS;
-
-	for(i=0;i<num;i++) {
-		DEB_I2C("msg:%d/%d\n", i+1, num);
-	}
-
-	/* prepare the message(s), get number of u32s to transfer */
-	count = saa7146_i2c_msg_prepare(msgs, num, buffer);
-	if ( 0 > count ) {
-		err = -1;
-		goto out;
-	}
-
-	if ( count > 3 || 0 != (SAA7146_I2C_SHORT_DELAY & dev->ext->flags) )
-		short_delay = 1;
-
-	do {
-		/* reset the i2c-device if necessary */
-		err = saa7146_i2c_reset(dev);
-		if ( 0 > err ) {
-			DEB_I2C("could not reset i2c-device\n");
-			goto out;
-		}
-
-		/* write out the u32s one after another */
-		for(i = 0; i < count; i++) {
-			err = saa7146_i2c_writeout(dev, &buffer[i], short_delay);
-			if ( 0 != err) {
-				/* this one is unsatisfying: some i2c slaves on some
-				   dvb cards don't acknowledge correctly, so the saa7146
-				   thinks that an address error occurred. in that case, the
-				   transaction should be retrying, even if an address error
-				   occurred. analog saa7146 based cards extensively rely on
-				   i2c address probing, however, and address errors indicate that a
-				   device is really *not* there. retrying in that case
-				   increases the time the device needs to probe greatly, so
-				   it should be avoided. So we bail out in irq mode after an
-				   address error and trust the saa7146 address error detection. */
-				if (-EREMOTEIO == err && 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags))
-					goto out;
-				DEB_I2C("error while sending message(s). starting again\n");
-				break;
-			}
-		}
-		if( 0 == err ) {
-			err = num;
-			break;
-		}
-
-		/* delay a bit before retrying */
-		msleep(10);
-
-	} while (err != num && retries--);
-
-	/* quit if any error occurred */
-	if (err != num)
-		goto out;
-
-	/* if any things had to be read, get the results */
-	if ( 0 != saa7146_i2c_msg_cleanup(msgs, num, buffer)) {
-		DEB_I2C("could not cleanup i2c-message\n");
-		err = -1;
-		goto out;
-	}
-
-	/* return the number of delivered messages */
-	DEB_I2C("transmission successful. (msg:%d)\n", err);
-out:
-	/* another bug in revision 0: the i2c-registers get uploaded randomly by other
-	   uploads, so we better clear them out before continuing */
-	if( 0 == dev->revision ) {
-		__le32 zero = 0;
-		saa7146_i2c_reset(dev);
-		if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) {
-			pr_info("revision 0 error. this should never happen\n");
-		}
-	}
-
-	mutex_unlock(&dev->i2c_lock);
-	return err;
-}
-
-/* utility functions */
-static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num)
-{
-	struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
-	struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev);
-
-	/* use helper function to transfer data */
-	return saa7146_i2c_transfer(dev, msg, num, adapter->retries);
-}
-
-
-/*****************************************************************************/
-/* i2c-adapter helper functions                                              */
-
-/* exported algorithm data */
-static struct i2c_algorithm saa7146_algo = {
-	.master_xfer	= saa7146_i2c_xfer,
-	.functionality	= saa7146_i2c_func,
-};
-
-int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate)
-{
-	DEB_EE("bitrate: 0x%08x\n", bitrate);
-
-	/* enable i2c-port pins */
-	saa7146_write(dev, MC1, (MASK_08 | MASK_24));
-
-	dev->i2c_bitrate = bitrate;
-	saa7146_i2c_reset(dev);
-
-	if (i2c_adapter) {
-		i2c_set_adapdata(i2c_adapter, &dev->v4l2_dev);
-		i2c_adapter->dev.parent    = &dev->pci->dev;
-		i2c_adapter->algo	   = &saa7146_algo;
-		i2c_adapter->algo_data     = NULL;
-		i2c_adapter->timeout = SAA7146_I2C_TIMEOUT;
-		i2c_adapter->retries = SAA7146_I2C_RETRIES;
-	}
-
-	return 0;
-}
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
deleted file mode 100644
index 1e71e37..0000000
--- a/drivers/media/common/saa7146_vbi.c
+++ /dev/null
@@ -1,498 +0,0 @@
-#include <media/saa7146_vv.h>
-
-static int vbi_pixel_to_capture = 720 * 2;
-
-static int vbi_workaround(struct saa7146_dev *dev)
-{
-	struct saa7146_vv *vv = dev->vv_data;
-
-	u32          *cpu;
-	dma_addr_t   dma_addr;
-
-	int count = 0;
-	int i;
-
-	DECLARE_WAITQUEUE(wait, current);
-
-	DEB_VBI("dev:%p\n", dev);
-
-	/* once again, a bug in the saa7146: the brs acquisition
-	   is buggy and especially the BXO-counter does not work
-	   as specified. there is this workaround, but please
-	   don't let me explain it. ;-) */
-
-	cpu = pci_alloc_consistent(dev->pci, 4096, &dma_addr);
-	if (NULL == cpu)
-		return -ENOMEM;
-
-	/* setup some basic programming, just for the workaround */
-	saa7146_write(dev, BASE_EVEN3,	dma_addr);
-	saa7146_write(dev, BASE_ODD3,	dma_addr+vbi_pixel_to_capture);
-	saa7146_write(dev, PROT_ADDR3,	dma_addr+4096);
-	saa7146_write(dev, PITCH3,	vbi_pixel_to_capture);
-	saa7146_write(dev, BASE_PAGE3,	0x0);
-	saa7146_write(dev, NUM_LINE_BYTE3, (2<<16)|((vbi_pixel_to_capture)<<0));
-	saa7146_write(dev, MC2, MASK_04|MASK_20);
-
-	/* load brs-control register */
-	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
-	/* BXO = 1h, BRS to outbound */
-	WRITE_RPS1(0xc000008c);
-	/* wait for vbi_a or vbi_b*/
-	if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
-		DEB_D("...using port b\n");
-		WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_E_FID_B);
-		WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_O_FID_B);
-/*
-		WRITE_RPS1(CMD_PAUSE | MASK_09);
-*/
-	} else {
-		DEB_D("...using port a\n");
-		WRITE_RPS1(CMD_PAUSE | MASK_10);
-	}
-	/* upload brs */
-	WRITE_RPS1(CMD_UPLOAD | MASK_08);
-	/* load brs-control register */
-	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
-	/* BYO = 1, BXO = NQBIL (=1728 for PAL, for NTSC this is 858*2) - NumByte3 (=1440) = 288 */
-	WRITE_RPS1(((1728-(vbi_pixel_to_capture)) << 7) | MASK_19);
-	/* wait for brs_done */
-	WRITE_RPS1(CMD_PAUSE | MASK_08);
-	/* upload brs */
-	WRITE_RPS1(CMD_UPLOAD | MASK_08);
-	/* load video-dma3 NumLines3 and NumBytes3 */
-	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (NUM_LINE_BYTE3/4));
-	/* dev->vbi_count*2 lines, 720 pixel (= 1440 Bytes) */
-	WRITE_RPS1((2 << 16) | (vbi_pixel_to_capture));
-	/* load brs-control register */
-	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
-	/* Set BRS right: note: this is an experimental value for BXO (=> PAL!) */
-	WRITE_RPS1((540 << 7) | (5 << 19));  // 5 == vbi_start
-	/* wait for brs_done */
-	WRITE_RPS1(CMD_PAUSE | MASK_08);
-	/* upload brs and video-dma3*/
-	WRITE_RPS1(CMD_UPLOAD | MASK_08 | MASK_04);
-	/* load mc2 register: enable dma3 */
-	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC1/4));
-	WRITE_RPS1(MASK_20 | MASK_04);
-	/* generate interrupt */
-	WRITE_RPS1(CMD_INTERRUPT);
-	/* stop rps1 */
-	WRITE_RPS1(CMD_STOP);
-
-	/* we have to do the workaround twice to be sure that
-	   everything is ok */
-	for(i = 0; i < 2; i++) {
-
-		/* indicate to the irq handler that we do the workaround */
-		saa7146_write(dev, MC2, MASK_31|MASK_15);
-
-		saa7146_write(dev, NUM_LINE_BYTE3, (1<<16)|(2<<0));
-		saa7146_write(dev, MC2, MASK_04|MASK_20);
-
-		/* enable rps1 irqs */
-		SAA7146_IER_ENABLE(dev,MASK_28);
-
-		/* prepare to wait to be woken up by the irq-handler */
-		add_wait_queue(&vv->vbi_wq, &wait);
-		current->state = TASK_INTERRUPTIBLE;
-
-		/* start rps1 to enable workaround */
-		saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
-		saa7146_write(dev, MC1, (MASK_13 | MASK_29));
-
-		schedule();
-
-		DEB_VBI("brs bug workaround %d/1\n", i);
-
-		remove_wait_queue(&vv->vbi_wq, &wait);
-		current->state = TASK_RUNNING;
-
-		/* disable rps1 irqs */
-		SAA7146_IER_DISABLE(dev,MASK_28);
-
-		/* stop video-dma3 */
-		saa7146_write(dev, MC1, MASK_20);
-
-		if(signal_pending(current)) {
-
-			DEB_VBI("aborted (rps:0x%08x)\n",
-				saa7146_read(dev, RPS_ADDR1));
-
-			/* stop rps1 for sure */
-			saa7146_write(dev, MC1, MASK_29);
-
-			pci_free_consistent(dev->pci, 4096, cpu, dma_addr);
-			return -EINTR;
-		}
-	}
-
-	pci_free_consistent(dev->pci, 4096, cpu, dma_addr);
-	return 0;
-}
-
-static void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next)
-{
-	struct saa7146_vv *vv = dev->vv_data;
-
-	struct saa7146_video_dma vdma3;
-
-	int count = 0;
-	unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B;
-	unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B;
-
-/*
-	vdma3.base_even	= 0xc8000000+2560*70;
-	vdma3.base_odd	= 0xc8000000;
-	vdma3.prot_addr	= 0xc8000000+2560*164;
-	vdma3.pitch	= 2560;
-	vdma3.base_page	= 0;
-	vdma3.num_line_byte = (64<<16)|((vbi_pixel_to_capture)<<0); // set above!
-*/
-	vdma3.base_even	= buf->pt[2].offset;
-	vdma3.base_odd	= buf->pt[2].offset + 16 * vbi_pixel_to_capture;
-	vdma3.prot_addr	= buf->pt[2].offset + 16 * 2 * vbi_pixel_to_capture;
-	vdma3.pitch	= vbi_pixel_to_capture;
-	vdma3.base_page	= buf->pt[2].dma | ME1;
-	vdma3.num_line_byte = (16 << 16) | vbi_pixel_to_capture;
-
-	saa7146_write_out_dma(dev, 3, &vdma3);
-
-	/* write beginning of rps-program */
-	count = 0;
-
-	/* wait for o_fid_a/b / e_fid_a/b toggle only if bit 1 is not set */
-
-	/* we don't wait here for the first field anymore. this is different from the video
-	   capture and might cause that the first buffer is only half filled (with only
-	   one field). but since this is some sort of streaming data, this is not that negative.
-	   but by doing this, we can use the whole engine from videobuf-dma-sg.c... */
-
-/*
-	WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait);
-	WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | o_wait);
-*/
-	/* set bit 1 */
-	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC2/4));
-	WRITE_RPS1(MASK_28 | MASK_12);
-
-	/* turn on video-dma3 */
-	WRITE_RPS1(CMD_WR_REG_MASK | (MC1/4));
-	WRITE_RPS1(MASK_04 | MASK_20);			/* => mask */
-	WRITE_RPS1(MASK_04 | MASK_20);			/* => values */
-
-	/* wait for o_fid_a/b / e_fid_a/b toggle */
-	WRITE_RPS1(CMD_PAUSE | o_wait);
-	WRITE_RPS1(CMD_PAUSE | e_wait);
-
-	/* generate interrupt */
-	WRITE_RPS1(CMD_INTERRUPT);
-
-	/* stop */
-	WRITE_RPS1(CMD_STOP);
-
-	/* enable rps1 irqs */
-	SAA7146_IER_ENABLE(dev, MASK_28);
-
-	/* write the address of the rps-program */
-	saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
-
-	/* turn on rps */
-	saa7146_write(dev, MC1, (MASK_13 | MASK_29));
-}
-
-static int buffer_activate(struct saa7146_dev *dev,
-			   struct saa7146_buf *buf,
-			   struct saa7146_buf *next)
-{
-	struct saa7146_vv *vv = dev->vv_data;
-	buf->vb.state = VIDEOBUF_ACTIVE;
-
-	DEB_VBI("dev:%p, buf:%p, next:%p\n", dev, buf, next);
-	saa7146_set_vbi_capture(dev,buf,next);
-
-	mod_timer(&vv->vbi_dmaq.timeout, jiffies+BUFFER_TIMEOUT);
-	return 0;
-}
-
-static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,enum v4l2_field field)
-{
-	struct file *file = q->priv_data;
-	struct saa7146_fh *fh = file->private_data;
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
-
-	int err = 0;
-	int lines, llength, size;
-
-	lines   = 16 * 2 ; /* 2 fields */
-	llength = vbi_pixel_to_capture;
-	size = lines * llength;
-
-	DEB_VBI("vb:%p\n", vb);
-
-	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size) {
-		DEB_VBI("size mismatch\n");
-		return -EINVAL;
-	}
-
-	if (buf->vb.size != size)
-		saa7146_dma_free(dev,q,buf);
-
-	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
-
-		buf->vb.width  = llength;
-		buf->vb.height = lines;
-		buf->vb.size   = size;
-		buf->vb.field  = field;	// FIXME: check this
-
-		saa7146_pgtable_free(dev->pci, &buf->pt[2]);
-		saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
-
-		err = videobuf_iolock(q,&buf->vb, NULL);
-		if (err)
-			goto oops;
-		err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2],
-						 dma->sglist, dma->sglen);
-		if (0 != err)
-			return err;
-	}
-	buf->vb.state = VIDEOBUF_PREPARED;
-	buf->activate = buffer_activate;
-
-	return 0;
-
- oops:
-	DEB_VBI("error out\n");
-	saa7146_dma_free(dev,q,buf);
-
-	return err;
-}
-
-static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
-{
-	int llength,lines;
-
-	lines   = 16 * 2 ; /* 2 fields */
-	llength = vbi_pixel_to_capture;
-
-	*size = lines * llength;
-	*count = 2;
-
-	DEB_VBI("count:%d, size:%d\n", *count, *size);
-
-	return 0;
-}
-
-static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
-{
-	struct file *file = q->priv_data;
-	struct saa7146_fh *fh = file->private_data;
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
-
-	DEB_VBI("vb:%p\n", vb);
-	saa7146_buffer_queue(dev, &vv->vbi_dmaq, buf);
-}
-
-static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
-{
-	struct file *file = q->priv_data;
-	struct saa7146_fh *fh   = file->private_data;
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
-
-	DEB_VBI("vb:%p\n", vb);
-	saa7146_dma_free(dev,q,buf);
-}
-
-static struct videobuf_queue_ops vbi_qops = {
-	.buf_setup    = buffer_setup,
-	.buf_prepare  = buffer_prepare,
-	.buf_queue    = buffer_queue,
-	.buf_release  = buffer_release,
-};
-
-/* ------------------------------------------------------------------ */
-
-static void vbi_stop(struct saa7146_fh *fh, struct file *file)
-{
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	unsigned long flags;
-	DEB_VBI("dev:%p, fh:%p\n", dev, fh);
-
-	spin_lock_irqsave(&dev->slock,flags);
-
-	/* disable rps1  */
-	saa7146_write(dev, MC1, MASK_29);
-
-	/* disable rps1 irqs */
-	SAA7146_IER_DISABLE(dev, MASK_28);
-
-	/* shut down dma 3 transfers */
-	saa7146_write(dev, MC1, MASK_20);
-
-	if (vv->vbi_dmaq.curr)
-		saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE);
-
-	videobuf_queue_cancel(&fh->vbi_q);
-
-	vv->vbi_streaming = NULL;
-
-	del_timer(&vv->vbi_dmaq.timeout);
-	del_timer(&vv->vbi_read_timeout);
-
-	spin_unlock_irqrestore(&dev->slock, flags);
-}
-
-static void vbi_read_timeout(unsigned long data)
-{
-	struct file *file = (struct file*)data;
-	struct saa7146_fh *fh = file->private_data;
-	struct saa7146_dev *dev = fh->dev;
-
-	DEB_VBI("dev:%p, fh:%p\n", dev, fh);
-
-	vbi_stop(fh, file);
-}
-
-static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
-{
-	DEB_VBI("dev:%p\n", dev);
-
-	INIT_LIST_HEAD(&vv->vbi_dmaq.queue);
-
-	init_timer(&vv->vbi_dmaq.timeout);
-	vv->vbi_dmaq.timeout.function = saa7146_buffer_timeout;
-	vv->vbi_dmaq.timeout.data     = (unsigned long)(&vv->vbi_dmaq);
-	vv->vbi_dmaq.dev              = dev;
-
-	init_waitqueue_head(&vv->vbi_wq);
-}
-
-static int vbi_open(struct saa7146_dev *dev, struct file *file)
-{
-	struct saa7146_fh *fh = file->private_data;
-	struct saa7146_vv *vv = fh->dev->vv_data;
-
-	u32 arbtr_ctrl	= saa7146_read(dev, PCI_BT_V1);
-	int ret = 0;
-
-	DEB_VBI("dev:%p, fh:%p\n", dev, fh);
-
-	ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS);
-	if (0 == ret) {
-		DEB_S("cannot get vbi RESOURCE_DMA3_BRS resource\n");
-		return -EBUSY;
-	}
-
-	/* adjust arbitrition control for video dma 3 */
-	arbtr_ctrl &= ~0x1f0000;
-	arbtr_ctrl |=  0x1d0000;
-	saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
-	saa7146_write(dev, MC2, (MASK_04|MASK_20));
-
-	videobuf_queue_sg_init(&fh->vbi_q, &vbi_qops,
-			    &dev->pci->dev, &dev->slock,
-			    V4L2_BUF_TYPE_VBI_CAPTURE,
-			    V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
-			    sizeof(struct saa7146_buf),
-			    file, &dev->v4l2_lock);
-
-	vv->vbi_read_timeout.function = vbi_read_timeout;
-	vv->vbi_read_timeout.data = (unsigned long)file;
-
-	/* initialize the brs */
-	if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
-		saa7146_write(dev, BRS_CTRL, MASK_30|MASK_29 | (7 << 19));
-	} else {
-		saa7146_write(dev, BRS_CTRL, 0x00000001);
-
-		if (0 != (ret = vbi_workaround(dev))) {
-			DEB_VBI("vbi workaround failed!\n");
-			/* return ret;*/
-		}
-	}
-
-	/* upload brs register */
-	saa7146_write(dev, MC2, (MASK_08|MASK_24));
-	return 0;
-}
-
-static void vbi_close(struct saa7146_dev *dev, struct file *file)
-{
-	struct saa7146_fh *fh = file->private_data;
-	struct saa7146_vv *vv = dev->vv_data;
-	DEB_VBI("dev:%p, fh:%p\n", dev, fh);
-
-	if( fh == vv->vbi_streaming ) {
-		vbi_stop(fh, file);
-	}
-	saa7146_res_free(fh, RESOURCE_DMA3_BRS);
-}
-
-static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
-{
-	struct saa7146_vv *vv = dev->vv_data;
-	spin_lock(&dev->slock);
-
-	if (vv->vbi_dmaq.curr) {
-		DEB_VBI("dev:%p, curr:%p\n", dev, vv->vbi_dmaq.curr);
-		/* this must be += 2, one count for each field */
-		vv->vbi_fieldcount+=2;
-		vv->vbi_dmaq.curr->vb.field_count = vv->vbi_fieldcount;
-		saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE);
-	} else {
-		DEB_VBI("dev:%p\n", dev);
-	}
-	saa7146_buffer_next(dev, &vv->vbi_dmaq, 1);
-
-	spin_unlock(&dev->slock);
-}
-
-static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
-{
-	struct saa7146_fh *fh = file->private_data;
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	ssize_t ret = 0;
-
-	DEB_VBI("dev:%p, fh:%p\n", dev, fh);
-
-	if( NULL == vv->vbi_streaming ) {
-		// fixme: check if dma3 is available
-		// fixme: activate vbi engine here if necessary. (really?)
-		vv->vbi_streaming = fh;
-	}
-
-	if( fh != vv->vbi_streaming ) {
-		DEB_VBI("open %p is already using vbi capture\n",
-			vv->vbi_streaming);
-		return -EBUSY;
-	}
-
-	mod_timer(&vv->vbi_read_timeout, jiffies+BUFFER_TIMEOUT);
-	ret = videobuf_read_stream(&fh->vbi_q, data, count, ppos, 1,
-				   file->f_flags & O_NONBLOCK);
-/*
-	printk("BASE_ODD3:      0x%08x\n", saa7146_read(dev, BASE_ODD3));
-	printk("BASE_EVEN3:     0x%08x\n", saa7146_read(dev, BASE_EVEN3));
-	printk("PROT_ADDR3:     0x%08x\n", saa7146_read(dev, PROT_ADDR3));
-	printk("PITCH3:         0x%08x\n", saa7146_read(dev, PITCH3));
-	printk("BASE_PAGE3:     0x%08x\n", saa7146_read(dev, BASE_PAGE3));
-	printk("NUM_LINE_BYTE3: 0x%08x\n", saa7146_read(dev, NUM_LINE_BYTE3));
-	printk("BRS_CTRL:       0x%08x\n", saa7146_read(dev, BRS_CTRL));
-*/
-	return ret;
-}
-
-struct saa7146_use_ops saa7146_vbi_uops = {
-	.init		= vbi_init,
-	.open		= vbi_open,
-	.release	= vbi_close,
-	.irq_done	= vbi_irq_done,
-	.read		= vbi_read,
-};
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
deleted file mode 100644
index 6d14785..0000000
--- a/drivers/media/common/saa7146_video.c
+++ /dev/null
@@ -1,1332 +0,0 @@
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <media/saa7146_vv.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-ctrls.h>
-#include <linux/module.h>
-
-static int max_memory = 32;
-
-module_param(max_memory, int, 0644);
-MODULE_PARM_DESC(max_memory, "maximum memory usage for capture buffers (default: 32Mb)");
-
-#define IS_CAPTURE_ACTIVE(fh) \
-	(((vv->video_status & STATUS_CAPTURE) != 0) && (vv->video_fh == fh))
-
-#define IS_OVERLAY_ACTIVE(fh) \
-	(((vv->video_status & STATUS_OVERLAY) != 0) && (vv->video_fh == fh))
-
-/* format descriptions for capture and preview */
-static struct saa7146_format formats[] = {
-	{
-		.name		= "RGB-8 (3-3-2)",
-		.pixelformat	= V4L2_PIX_FMT_RGB332,
-		.trans		= RGB08_COMPOSED,
-		.depth		= 8,
-		.flags		= 0,
-	}, {
-		.name		= "RGB-16 (5/B-6/G-5/R)",
-		.pixelformat	= V4L2_PIX_FMT_RGB565,
-		.trans		= RGB16_COMPOSED,
-		.depth		= 16,
-		.flags		= 0,
-	}, {
-		.name		= "RGB-24 (B-G-R)",
-		.pixelformat	= V4L2_PIX_FMT_BGR24,
-		.trans		= RGB24_COMPOSED,
-		.depth		= 24,
-		.flags		= 0,
-	}, {
-		.name		= "RGB-32 (B-G-R)",
-		.pixelformat	= V4L2_PIX_FMT_BGR32,
-		.trans		= RGB32_COMPOSED,
-		.depth		= 32,
-		.flags		= 0,
-	}, {
-		.name		= "RGB-32 (R-G-B)",
-		.pixelformat	= V4L2_PIX_FMT_RGB32,
-		.trans		= RGB32_COMPOSED,
-		.depth		= 32,
-		.flags		= 0,
-		.swap		= 0x2,
-	}, {
-		.name		= "Greyscale-8",
-		.pixelformat	= V4L2_PIX_FMT_GREY,
-		.trans		= Y8,
-		.depth		= 8,
-		.flags		= 0,
-	}, {
-		.name		= "YUV 4:2:2 planar (Y-Cb-Cr)",
-		.pixelformat	= V4L2_PIX_FMT_YUV422P,
-		.trans		= YUV422_DECOMPOSED,
-		.depth		= 16,
-		.flags		= FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,
-	}, {
-		.name		= "YVU 4:2:0 planar (Y-Cb-Cr)",
-		.pixelformat	= V4L2_PIX_FMT_YVU420,
-		.trans		= YUV420_DECOMPOSED,
-		.depth		= 12,
-		.flags		= FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,
-	}, {
-		.name		= "YUV 4:2:0 planar (Y-Cb-Cr)",
-		.pixelformat	= V4L2_PIX_FMT_YUV420,
-		.trans		= YUV420_DECOMPOSED,
-		.depth		= 12,
-		.flags		= FORMAT_IS_PLANAR,
-	}, {
-		.name		= "YUV 4:2:2 (U-Y-V-Y)",
-		.pixelformat	= V4L2_PIX_FMT_UYVY,
-		.trans		= YUV422_COMPOSED,
-		.depth		= 16,
-		.flags		= 0,
-	}
-};
-
-/* unfortunately, the saa7146 contains a bug which prevents it from doing on-the-fly byte swaps.
-   due to this, it's impossible to provide additional *packed* formats, which are simply byte swapped
-   (like V4L2_PIX_FMT_YUYV) ... 8-( */
-
-static int NUM_FORMATS = sizeof(formats)/sizeof(struct saa7146_format);
-
-struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc)
-{
-	int i, j = NUM_FORMATS;
-
-	for (i = 0; i < j; i++) {
-		if (formats[i].pixelformat == fourcc) {
-			return formats+i;
-		}
-	}
-
-	DEB_D("unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
-	return NULL;
-}
-
-static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f);
-
-int saa7146_start_preview(struct saa7146_fh *fh)
-{
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	struct v4l2_format fmt;
-	int ret = 0, err = 0;
-
-	DEB_EE("dev:%p, fh:%p\n", dev, fh);
-
-	/* check if we have overlay information */
-	if (vv->ov.fh == NULL) {
-		DEB_D("no overlay data available. try S_FMT first.\n");
-		return -EAGAIN;
-	}
-
-	/* check if streaming capture is running */
-	if (IS_CAPTURE_ACTIVE(fh) != 0) {
-		DEB_D("streaming capture is active\n");
-		return -EBUSY;
-	}
-
-	/* check if overlay is running */
-	if (IS_OVERLAY_ACTIVE(fh) != 0) {
-		if (vv->video_fh == fh) {
-			DEB_D("overlay is already active\n");
-			return 0;
-		}
-		DEB_D("overlay is already active in another open\n");
-		return -EBUSY;
-	}
-
-	if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) {
-		DEB_D("cannot get necessary overlay resources\n");
-		return -EBUSY;
-	}
-
-	fmt.fmt.win = vv->ov.win;
-	err = vidioc_try_fmt_vid_overlay(NULL, fh, &fmt);
-	if (0 != err) {
-		saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
-		return -EBUSY;
-	}
-	vv->ov.win = fmt.fmt.win;
-
-	DEB_D("%dx%d+%d+%d %s field=%s\n",
-	      vv->ov.win.w.width, vv->ov.win.w.height,
-	      vv->ov.win.w.left, vv->ov.win.w.top,
-	      vv->ov_fmt->name, v4l2_field_names[vv->ov.win.field]);
-
-	if (0 != (ret = saa7146_enable_overlay(fh))) {
-		DEB_D("enabling overlay failed: %d\n", ret);
-		saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
-		return ret;
-	}
-
-	vv->video_status = STATUS_OVERLAY;
-	vv->video_fh = fh;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(saa7146_start_preview);
-
-int saa7146_stop_preview(struct saa7146_fh *fh)
-{
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-
-	DEB_EE("dev:%p, fh:%p\n", dev, fh);
-
-	/* check if streaming capture is running */
-	if (IS_CAPTURE_ACTIVE(fh) != 0) {
-		DEB_D("streaming capture is active\n");
-		return -EBUSY;
-	}
-
-	/* check if overlay is running at all */
-	if ((vv->video_status & STATUS_OVERLAY) == 0) {
-		DEB_D("no active overlay\n");
-		return 0;
-	}
-
-	if (vv->video_fh != fh) {
-		DEB_D("overlay is active, but in another open\n");
-		return -EBUSY;
-	}
-
-	vv->video_status = 0;
-	vv->video_fh = NULL;
-
-	saa7146_disable_overlay(fh);
-
-	saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(saa7146_stop_preview);
-
-/********************************************************************************/
-/* common pagetable functions */
-
-static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf)
-{
-	struct pci_dev *pci = dev->pci;
-	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
-	struct scatterlist *list = dma->sglist;
-	int length = dma->sglen;
-	struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
-
-	DEB_EE("dev:%p, buf:%p, sg_len:%d\n", dev, buf, length);
-
-	if( 0 != IS_PLANAR(sfmt->trans)) {
-		struct saa7146_pgtable *pt1 = &buf->pt[0];
-		struct saa7146_pgtable *pt2 = &buf->pt[1];
-		struct saa7146_pgtable *pt3 = &buf->pt[2];
-		__le32  *ptr1, *ptr2, *ptr3;
-		__le32 fill;
-
-		int size = buf->fmt->width*buf->fmt->height;
-		int i,p,m1,m2,m3,o1,o2;
-
-		switch( sfmt->depth ) {
-			case 12: {
-				/* create some offsets inside the page table */
-				m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
-				m2 = ((size+(size/4)+PAGE_SIZE)/PAGE_SIZE)-1;
-				m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
-				o1 = size%PAGE_SIZE;
-				o2 = (size+(size/4))%PAGE_SIZE;
-				DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",
-					size, m1, m2, m3, o1, o2);
-				break;
-			}
-			case 16: {
-				/* create some offsets inside the page table */
-				m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
-				m2 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
-				m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1;
-				o1 = size%PAGE_SIZE;
-				o2 = (size+(size/2))%PAGE_SIZE;
-				DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",
-					size, m1, m2, m3, o1, o2);
-				break;
-			}
-			default: {
-				return -1;
-			}
-		}
-
-		ptr1 = pt1->cpu;
-		ptr2 = pt2->cpu;
-		ptr3 = pt3->cpu;
-
-		/* walk all pages, copy all page addresses to ptr1 */
-		for (i = 0; i < length; i++, list++) {
-			for (p = 0; p * 4096 < list->length; p++, ptr1++) {
-				*ptr1 = cpu_to_le32(sg_dma_address(list) - list->offset);
-			}
-		}
-/*
-		ptr1 = pt1->cpu;
-		for(j=0;j<40;j++) {
-			printk("ptr1 %d: 0x%08x\n",j,ptr1[j]);
-		}
-*/
-
-		/* if we have a user buffer, the first page may not be
-		   aligned to a page boundary. */
-		pt1->offset = dma->sglist->offset;
-		pt2->offset = pt1->offset+o1;
-		pt3->offset = pt1->offset+o2;
-
-		/* create video-dma2 page table */
-		ptr1 = pt1->cpu;
-		for(i = m1; i <= m2 ; i++, ptr2++) {
-			*ptr2 = ptr1[i];
-		}
-		fill = *(ptr2-1);
-		for(;i<1024;i++,ptr2++) {
-			*ptr2 = fill;
-		}
-		/* create video-dma3 page table */
-		ptr1 = pt1->cpu;
-		for(i = m2; i <= m3; i++,ptr3++) {
-			*ptr3 = ptr1[i];
-		}
-		fill = *(ptr3-1);
-		for(;i<1024;i++,ptr3++) {
-			*ptr3 = fill;
-		}
-		/* finally: finish up video-dma1 page table */
-		ptr1 = pt1->cpu+m1;
-		fill = pt1->cpu[m1];
-		for(i=m1;i<1024;i++,ptr1++) {
-			*ptr1 = fill;
-		}
-/*
-		ptr1 = pt1->cpu;
-		ptr2 = pt2->cpu;
-		ptr3 = pt3->cpu;
-		for(j=0;j<40;j++) {
-			printk("ptr1 %d: 0x%08x\n",j,ptr1[j]);
-		}
-		for(j=0;j<40;j++) {
-			printk("ptr2 %d: 0x%08x\n",j,ptr2[j]);
-		}
-		for(j=0;j<40;j++) {
-			printk("ptr3 %d: 0x%08x\n",j,ptr3[j]);
-		}
-*/
-	} else {
-		struct saa7146_pgtable *pt = &buf->pt[0];
-		return saa7146_pgtable_build_single(pci, pt, list, length);
-	}
-
-	return 0;
-}
-
-
-/********************************************************************************/
-/* file operations */
-
-static int video_begin(struct saa7146_fh *fh)
-{
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	struct saa7146_format *fmt = NULL;
-	unsigned int resource;
-	int ret = 0, err = 0;
-
-	DEB_EE("dev:%p, fh:%p\n", dev, fh);
-
-	if ((vv->video_status & STATUS_CAPTURE) != 0) {
-		if (vv->video_fh == fh) {
-			DEB_S("already capturing\n");
-			return 0;
-		}
-		DEB_S("already capturing in another open\n");
-		return -EBUSY;
-	}
-
-	if ((vv->video_status & STATUS_OVERLAY) != 0) {
-		DEB_S("warning: suspending overlay video for streaming capture\n");
-		vv->ov_suspend = vv->video_fh;
-		err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
-		if (0 != err) {
-			DEB_D("suspending video failed. aborting\n");
-			return err;
-		}
-	}
-
-	fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);
-	/* we need to have a valid format set here */
-	BUG_ON(NULL == fmt);
-
-	if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
-		resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;
-	} else {
-		resource = RESOURCE_DMA1_HPS;
-	}
-
-	ret = saa7146_res_get(fh, resource);
-	if (0 == ret) {
-		DEB_S("cannot get capture resource %d\n", resource);
-		if (vv->ov_suspend != NULL) {
-			saa7146_start_preview(vv->ov_suspend);
-			vv->ov_suspend = NULL;
-		}
-		return -EBUSY;
-	}
-
-	/* clear out beginning of streaming bit (rps register 0)*/
-	saa7146_write(dev, MC2, MASK_27 );
-
-	/* enable rps0 irqs */
-	SAA7146_IER_ENABLE(dev, MASK_27);
-
-	vv->video_fh = fh;
-	vv->video_status = STATUS_CAPTURE;
-
-	return 0;
-}
-
-static int video_end(struct saa7146_fh *fh, struct file *file)
-{
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	struct saa7146_format *fmt = NULL;
-	unsigned long flags;
-	unsigned int resource;
-	u32 dmas = 0;
-	DEB_EE("dev:%p, fh:%p\n", dev, fh);
-
-	if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
-		DEB_S("not capturing\n");
-		return 0;
-	}
-
-	if (vv->video_fh != fh) {
-		DEB_S("capturing, but in another open\n");
-		return -EBUSY;
-	}
-
-	fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);
-	/* we need to have a valid format set here */
-	BUG_ON(NULL == fmt);
-
-	if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
-		resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;
-		dmas = MASK_22 | MASK_21 | MASK_20;
-	} else {
-		resource = RESOURCE_DMA1_HPS;
-		dmas = MASK_22;
-	}
-	spin_lock_irqsave(&dev->slock,flags);
-
-	/* disable rps0  */
-	saa7146_write(dev, MC1, MASK_28);
-
-	/* disable rps0 irqs */
-	SAA7146_IER_DISABLE(dev, MASK_27);
-
-	/* shut down all used video dma transfers */
-	saa7146_write(dev, MC1, dmas);
-
-	spin_unlock_irqrestore(&dev->slock, flags);
-
-	vv->video_fh = NULL;
-	vv->video_status = 0;
-
-	saa7146_res_free(fh, resource);
-
-	if (vv->ov_suspend != NULL) {
-		saa7146_start_preview(vv->ov_suspend);
-		vv->ov_suspend = NULL;
-	}
-
-	return 0;
-}
-
-static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-
-	strcpy((char *)cap->driver, "saa7146 v4l2");
-	strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
-	sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci));
-	cap->device_caps =
-		V4L2_CAP_VIDEO_CAPTURE |
-		V4L2_CAP_VIDEO_OVERLAY |
-		V4L2_CAP_READWRITE |
-		V4L2_CAP_STREAMING;
-	cap->device_caps |= dev->ext_vv_data->capabilities;
-	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-	if (vdev->vfl_type == VFL_TYPE_GRABBER)
-		cap->device_caps &=
-			~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT);
-	else
-		cap->device_caps &=
-			~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_AUDIO);
-	return 0;
-}
-
-static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-
-	*fb = vv->ov_fb;
-	fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
-	fb->flags = V4L2_FBUF_FLAG_PRIMARY;
-	return 0;
-}
-
-static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	struct saa7146_format *fmt;
-
-	DEB_EE("VIDIOC_S_FBUF\n");
-
-	if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
-		return -EPERM;
-
-	/* check args */
-	fmt = saa7146_format_by_fourcc(dev, fb->fmt.pixelformat);
-	if (NULL == fmt)
-		return -EINVAL;
-
-	/* planar formats are not allowed for overlay video, clipping and video dma would clash */
-	if (fmt->flags & FORMAT_IS_PLANAR)
-		DEB_S("planar pixelformat '%4.4s' not allowed for overlay\n",
-		      (char *)&fmt->pixelformat);
-
-	/* check if overlay is running */
-	if (IS_OVERLAY_ACTIVE(fh) != 0) {
-		if (vv->video_fh != fh) {
-			DEB_D("refusing to change framebuffer informations while overlay is active in another open\n");
-			return -EBUSY;
-		}
-	}
-
-	/* ok, accept it */
-	vv->ov_fb = *fb;
-	vv->ov_fmt = fmt;
-
-	if (vv->ov_fb.fmt.bytesperline < vv->ov_fb.fmt.width) {
-		vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8;
-		DEB_D("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline);
-	}
-	return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
-{
-	if (f->index >= NUM_FORMATS)
-		return -EINVAL;
-	strlcpy((char *)f->description, formats[f->index].name,
-			sizeof(f->description));
-	f->pixelformat = formats[f->index].pixelformat;
-	return 0;
-}
-
-int saa7146_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-	struct saa7146_dev *dev = container_of(ctrl->handler,
-				struct saa7146_dev, ctrl_handler);
-	struct saa7146_vv *vv = dev->vv_data;
-	u32 val;
-
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		val = saa7146_read(dev, BCS_CTRL);
-		val &= 0x00ffffff;
-		val |= (ctrl->val << 24);
-		saa7146_write(dev, BCS_CTRL, val);
-		saa7146_write(dev, MC2, MASK_22 | MASK_06);
-		break;
-
-	case V4L2_CID_CONTRAST:
-		val = saa7146_read(dev, BCS_CTRL);
-		val &= 0xff00ffff;
-		val |= (ctrl->val << 16);
-		saa7146_write(dev, BCS_CTRL, val);
-		saa7146_write(dev, MC2, MASK_22 | MASK_06);
-		break;
-
-	case V4L2_CID_SATURATION:
-		val = saa7146_read(dev, BCS_CTRL);
-		val &= 0xffffff00;
-		val |= (ctrl->val << 0);
-		saa7146_write(dev, BCS_CTRL, val);
-		saa7146_write(dev, MC2, MASK_22 | MASK_06);
-		break;
-
-	case V4L2_CID_HFLIP:
-		/* fixme: we can support changing VFLIP and HFLIP here... */
-		if ((vv->video_status & STATUS_CAPTURE))
-			return -EBUSY;
-		vv->hflip = ctrl->val;
-		break;
-
-	case V4L2_CID_VFLIP:
-		if ((vv->video_status & STATUS_CAPTURE))
-			return -EBUSY;
-		vv->vflip = ctrl->val;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	if ((vv->video_status & STATUS_OVERLAY) != 0) { /* CHECK: && (vv->video_fh == fh)) */
-		struct saa7146_fh *fh = vv->video_fh;
-
-		saa7146_stop_preview(fh);
-		saa7146_start_preview(fh);
-	}
-	return 0;
-}
-
-static int vidioc_g_parm(struct file *file, void *fh,
-		struct v4l2_streamparm *parm)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-
-	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-	parm->parm.capture.readbuffers = 1;
-	v4l2_video_std_frame_period(vv->standard->id,
-				    &parm->parm.capture.timeperframe);
-	return 0;
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-
-	f->fmt.pix = vv->video_fmt;
-	return 0;
-}
-
-static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-
-	f->fmt.win = vv->ov.win;
-	return 0;
-}
-
-static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-
-	f->fmt.vbi = vv->vbi_fmt;
-	return 0;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	struct saa7146_format *fmt;
-	enum v4l2_field field;
-	int maxw, maxh;
-	int calc_bpl;
-
-	DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh);
-
-	fmt = saa7146_format_by_fourcc(dev, f->fmt.pix.pixelformat);
-	if (NULL == fmt)
-		return -EINVAL;
-
-	field = f->fmt.pix.field;
-	maxw  = vv->standard->h_max_out;
-	maxh  = vv->standard->v_max_out;
-
-	if (V4L2_FIELD_ANY == field) {
-		field = (f->fmt.pix.height > maxh / 2)
-			? V4L2_FIELD_INTERLACED
-			: V4L2_FIELD_BOTTOM;
-	}
-	switch (field) {
-	case V4L2_FIELD_ALTERNATE:
-		vv->last_field = V4L2_FIELD_TOP;
-		maxh = maxh / 2;
-		break;
-	case V4L2_FIELD_TOP:
-	case V4L2_FIELD_BOTTOM:
-		vv->last_field = V4L2_FIELD_INTERLACED;
-		maxh = maxh / 2;
-		break;
-	case V4L2_FIELD_INTERLACED:
-		vv->last_field = V4L2_FIELD_INTERLACED;
-		break;
-	default:
-		DEB_D("no known field mode '%d'\n", field);
-		return -EINVAL;
-	}
-
-	f->fmt.pix.field = field;
-	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-	if (f->fmt.pix.width > maxw)
-		f->fmt.pix.width = maxw;
-	if (f->fmt.pix.height > maxh)
-		f->fmt.pix.height = maxh;
-
-	calc_bpl = (f->fmt.pix.width * fmt->depth) / 8;
-
-	if (f->fmt.pix.bytesperline < calc_bpl)
-		f->fmt.pix.bytesperline = calc_bpl;
-
-	if (f->fmt.pix.bytesperline > (2 * PAGE_SIZE * fmt->depth) / 8) /* arbitrary constraint */
-		f->fmt.pix.bytesperline = calc_bpl;
-
-	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
-	DEB_D("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n",
-	      f->fmt.pix.width, f->fmt.pix.height,
-	      f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
-
-	return 0;
-}
-
-
-static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	struct v4l2_window *win = &f->fmt.win;
-	enum v4l2_field field;
-	int maxw, maxh;
-
-	DEB_EE("dev:%p\n", dev);
-
-	if (NULL == vv->ov_fb.base) {
-		DEB_D("no fb base set\n");
-		return -EINVAL;
-	}
-	if (NULL == vv->ov_fmt) {
-		DEB_D("no fb fmt set\n");
-		return -EINVAL;
-	}
-	if (win->w.width < 48 || win->w.height < 32) {
-		DEB_D("min width/height. (%d,%d)\n",
-		      win->w.width, win->w.height);
-		return -EINVAL;
-	}
-	if (win->clipcount > 16) {
-		DEB_D("clipcount too big\n");
-		return -EINVAL;
-	}
-
-	field = win->field;
-	maxw  = vv->standard->h_max_out;
-	maxh  = vv->standard->v_max_out;
-
-	if (V4L2_FIELD_ANY == field) {
-		field = (win->w.height > maxh / 2)
-			? V4L2_FIELD_INTERLACED
-			: V4L2_FIELD_TOP;
-		}
-	switch (field) {
-	case V4L2_FIELD_TOP:
-	case V4L2_FIELD_BOTTOM:
-	case V4L2_FIELD_ALTERNATE:
-		maxh = maxh / 2;
-		break;
-	case V4L2_FIELD_INTERLACED:
-		break;
-	default:
-		DEB_D("no known field mode '%d'\n", field);
-		return -EINVAL;
-	}
-
-	win->field = field;
-	if (win->w.width > maxw)
-		win->w.width = maxw;
-	if (win->w.height > maxh)
-		win->w.height = maxh;
-
-	return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_format *f)
-{
-	struct saa7146_fh *fh = __fh;
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	int err;
-
-	DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh);
-	if (IS_CAPTURE_ACTIVE(fh) != 0) {
-		DEB_EE("streaming capture is active\n");
-		return -EBUSY;
-	}
-	err = vidioc_try_fmt_vid_cap(file, fh, f);
-	if (0 != err)
-		return err;
-	vv->video_fmt = f->fmt.pix;
-	DEB_EE("set to pixelformat '%4.4s'\n",
-	       (char *)&vv->video_fmt.pixelformat);
-	return 0;
-}
-
-static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_format *f)
-{
-	struct saa7146_fh *fh = __fh;
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	int err;
-
-	DEB_EE("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh);
-	err = vidioc_try_fmt_vid_overlay(file, fh, f);
-	if (0 != err)
-		return err;
-	vv->ov.win    = f->fmt.win;
-	vv->ov.nclips = f->fmt.win.clipcount;
-	if (vv->ov.nclips > 16)
-		vv->ov.nclips = 16;
-	if (copy_from_user(vv->ov.clips, f->fmt.win.clips,
-				sizeof(struct v4l2_clip) * vv->ov.nclips)) {
-		return -EFAULT;
-	}
-
-	/* vv->ov.fh is used to indicate that we have valid overlay informations, too */
-	vv->ov.fh = fh;
-
-	/* check if our current overlay is active */
-	if (IS_OVERLAY_ACTIVE(fh) != 0) {
-		saa7146_stop_preview(fh);
-		saa7146_start_preview(fh);
-	}
-	return 0;
-}
-
-static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-
-	*norm = vv->standard->id;
-	return 0;
-}
-
-	/* the saa7146 supfhrts (used in conjunction with the saa7111a for example)
-	   PAL / NTSC / SECAM. if your hardware does not (or does more)
-	   -- override this function in your extension */
-/*
-	case VIDIOC_ENUMSTD:
-	{
-		struct v4l2_standard *e = arg;
-		if (e->index < 0 )
-			return -EINVAL;
-		if( e->index < dev->ext_vv_data->num_stds ) {
-			DEB_EE("VIDIOC_ENUMSTD: index:%d\n", e->index);
-			v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name);
-			return 0;
-		}
-		return -EINVAL;
-	}
-	*/
-
-static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	int found = 0;
-	int err, i;
-
-	DEB_EE("VIDIOC_S_STD\n");
-
-	if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) {
-		DEB_D("cannot change video standard while streaming capture is active\n");
-		return -EBUSY;
-	}
-
-	if ((vv->video_status & STATUS_OVERLAY) != 0) {
-		vv->ov_suspend = vv->video_fh;
-		err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
-		if (0 != err) {
-			DEB_D("suspending video failed. aborting\n");
-			return err;
-		}
-	}
-
-	for (i = 0; i < dev->ext_vv_data->num_stds; i++)
-		if (*id & dev->ext_vv_data->stds[i].id)
-			break;
-	if (i != dev->ext_vv_data->num_stds) {
-		vv->standard = &dev->ext_vv_data->stds[i];
-		if (NULL != dev->ext_vv_data->std_callback)
-			dev->ext_vv_data->std_callback(dev, vv->standard);
-		found = 1;
-	}
-
-	if (vv->ov_suspend != NULL) {
-		saa7146_start_preview(vv->ov_suspend);
-		vv->ov_suspend = NULL;
-	}
-
-	if (!found) {
-		DEB_EE("VIDIOC_S_STD: standard not found\n");
-		return -EINVAL;
-	}
-
-	DEB_EE("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name);
-	return 0;
-}
-
-static int vidioc_overlay(struct file *file, void *fh, unsigned int on)
-{
-	int err;
-
-	DEB_D("VIDIOC_OVERLAY on:%d\n", on);
-	if (on)
-		err = saa7146_start_preview(fh);
-	else
-		err = saa7146_stop_preview(fh);
-	return err;
-}
-
-static int vidioc_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *b)
-{
-	struct saa7146_fh *fh = __fh;
-
-	if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return videobuf_reqbufs(&fh->video_q, b);
-	if (b->type == V4L2_BUF_TYPE_VBI_CAPTURE)
-		return videobuf_reqbufs(&fh->vbi_q, b);
-	return -EINVAL;
-}
-
-static int vidioc_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
-{
-	struct saa7146_fh *fh = __fh;
-
-	if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return videobuf_querybuf(&fh->video_q, buf);
-	if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
-		return videobuf_querybuf(&fh->vbi_q, buf);
-	return -EINVAL;
-}
-
-static int vidioc_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
-{
-	struct saa7146_fh *fh = __fh;
-
-	if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return videobuf_qbuf(&fh->video_q, buf);
-	if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
-		return videobuf_qbuf(&fh->vbi_q, buf);
-	return -EINVAL;
-}
-
-static int vidioc_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
-{
-	struct saa7146_fh *fh = __fh;
-
-	if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return videobuf_dqbuf(&fh->video_q, buf, file->f_flags & O_NONBLOCK);
-	if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
-		return videobuf_dqbuf(&fh->vbi_q, buf, file->f_flags & O_NONBLOCK);
-	return -EINVAL;
-}
-
-static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type type)
-{
-	struct saa7146_fh *fh = __fh;
-	int err;
-
-	DEB_D("VIDIOC_STREAMON, type:%d\n", type);
-
-	err = video_begin(fh);
-	if (err)
-		return err;
-	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return videobuf_streamon(&fh->video_q);
-	if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
-		return videobuf_streamon(&fh->vbi_q);
-	return -EINVAL;
-}
-
-static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type)
-{
-	struct saa7146_fh *fh = __fh;
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	int err;
-
-	DEB_D("VIDIOC_STREAMOFF, type:%d\n", type);
-
-	/* ugly: we need to copy some checks from video_end(),
-	   because videobuf_streamoff() relies on the capture running.
-	   check and fix this */
-	if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
-		DEB_S("not capturing\n");
-		return 0;
-	}
-
-	if (vv->video_fh != fh) {
-		DEB_S("capturing, but in another open\n");
-		return -EBUSY;
-	}
-
-	err = -EINVAL;
-	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		err = videobuf_streamoff(&fh->video_q);
-	else if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
-		err = videobuf_streamoff(&fh->vbi_q);
-	if (0 != err) {
-		DEB_D("warning: videobuf_streamoff() failed\n");
-		video_end(fh, file);
-	} else {
-		err = video_end(fh, file);
-	}
-	return err;
-}
-
-static int vidioc_g_chip_ident(struct file *file, void *__fh,
-		struct v4l2_dbg_chip_ident *chip)
-{
-	struct saa7146_fh *fh = __fh;
-	struct saa7146_dev *dev = fh->dev;
-
-	chip->ident = V4L2_IDENT_NONE;
-	chip->revision = 0;
-	if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
-		if (v4l2_chip_match_host(&chip->match))
-			chip->ident = V4L2_IDENT_SAA7146;
-		return 0;
-	}
-	if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
-	    chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
-		return -EINVAL;
-	return v4l2_device_call_until_err(&dev->v4l2_dev, 0,
-			core, g_chip_ident, chip);
-}
-
-const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
-	.vidioc_querycap             = vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap     = vidioc_enum_fmt_vid_cap,
-	.vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap        = vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap      = vidioc_try_fmt_vid_cap,
-	.vidioc_s_fmt_vid_cap        = vidioc_s_fmt_vid_cap,
-	.vidioc_g_fmt_vid_overlay    = vidioc_g_fmt_vid_overlay,
-	.vidioc_try_fmt_vid_overlay  = vidioc_try_fmt_vid_overlay,
-	.vidioc_s_fmt_vid_overlay    = vidioc_s_fmt_vid_overlay,
-	.vidioc_g_chip_ident         = vidioc_g_chip_ident,
-
-	.vidioc_overlay 	     = vidioc_overlay,
-	.vidioc_g_fbuf  	     = vidioc_g_fbuf,
-	.vidioc_s_fbuf  	     = vidioc_s_fbuf,
-	.vidioc_reqbufs              = vidioc_reqbufs,
-	.vidioc_querybuf             = vidioc_querybuf,
-	.vidioc_qbuf                 = vidioc_qbuf,
-	.vidioc_dqbuf                = vidioc_dqbuf,
-	.vidioc_g_std                = vidioc_g_std,
-	.vidioc_s_std                = vidioc_s_std,
-	.vidioc_streamon             = vidioc_streamon,
-	.vidioc_streamoff            = vidioc_streamoff,
-	.vidioc_g_parm 		     = vidioc_g_parm,
-	.vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
-	.vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
-};
-
-const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops = {
-	.vidioc_querycap             = vidioc_querycap,
-	.vidioc_g_fmt_vbi_cap        = vidioc_g_fmt_vbi_cap,
-	.vidioc_g_chip_ident         = vidioc_g_chip_ident,
-
-	.vidioc_reqbufs              = vidioc_reqbufs,
-	.vidioc_querybuf             = vidioc_querybuf,
-	.vidioc_qbuf                 = vidioc_qbuf,
-	.vidioc_dqbuf                = vidioc_dqbuf,
-	.vidioc_g_std                = vidioc_g_std,
-	.vidioc_s_std                = vidioc_s_std,
-	.vidioc_streamon             = vidioc_streamon,
-	.vidioc_streamoff            = vidioc_streamoff,
-	.vidioc_g_parm		     = vidioc_g_parm,
-	.vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
-	.vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
-};
-
-/*********************************************************************************/
-/* buffer handling functions                                                  */
-
-static int buffer_activate (struct saa7146_dev *dev,
-		     struct saa7146_buf *buf,
-		     struct saa7146_buf *next)
-{
-	struct saa7146_vv *vv = dev->vv_data;
-
-	buf->vb.state = VIDEOBUF_ACTIVE;
-	saa7146_set_capture(dev,buf,next);
-
-	mod_timer(&vv->video_dmaq.timeout, jiffies+BUFFER_TIMEOUT);
-	return 0;
-}
-
-static void release_all_pagetables(struct saa7146_dev *dev, struct saa7146_buf *buf)
-{
-	saa7146_pgtable_free(dev->pci, &buf->pt[0]);
-	saa7146_pgtable_free(dev->pci, &buf->pt[1]);
-	saa7146_pgtable_free(dev->pci, &buf->pt[2]);
-}
-
-static int buffer_prepare(struct videobuf_queue *q,
-			  struct videobuf_buffer *vb, enum v4l2_field field)
-{
-	struct file *file = q->priv_data;
-	struct saa7146_fh *fh = file->private_data;
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
-	int size,err = 0;
-
-	DEB_CAP("vbuf:%p\n", vb);
-
-	/* sanity checks */
-	if (vv->video_fmt.width  < 48 ||
-	    vv->video_fmt.height < 32 ||
-	    vv->video_fmt.width  > vv->standard->h_max_out ||
-	    vv->video_fmt.height > vv->standard->v_max_out) {
-		DEB_D("w (%d) / h (%d) out of bounds\n",
-		      vv->video_fmt.width, vv->video_fmt.height);
-		return -EINVAL;
-	}
-
-	size = vv->video_fmt.sizeimage;
-	if (0 != buf->vb.baddr && buf->vb.bsize < size) {
-		DEB_D("size mismatch\n");
-		return -EINVAL;
-	}
-
-	DEB_CAP("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n",
-		vv->video_fmt.width, vv->video_fmt.height,
-		size, v4l2_field_names[vv->video_fmt.field]);
-	if (buf->vb.width  != vv->video_fmt.width  ||
-	    buf->vb.bytesperline != vv->video_fmt.bytesperline ||
-	    buf->vb.height != vv->video_fmt.height ||
-	    buf->vb.size   != size ||
-	    buf->vb.field  != field      ||
-	    buf->vb.field  != vv->video_fmt.field  ||
-	    buf->fmt       != &vv->video_fmt) {
-		saa7146_dma_free(dev,q,buf);
-	}
-
-	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-		struct saa7146_format *sfmt;
-
-		buf->vb.bytesperline  = vv->video_fmt.bytesperline;
-		buf->vb.width  = vv->video_fmt.width;
-		buf->vb.height = vv->video_fmt.height;
-		buf->vb.size   = size;
-		buf->vb.field  = field;
-		buf->fmt       = &vv->video_fmt;
-		buf->vb.field  = vv->video_fmt.field;
-
-		sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
-
-		release_all_pagetables(dev, buf);
-		if( 0 != IS_PLANAR(sfmt->trans)) {
-			saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
-			saa7146_pgtable_alloc(dev->pci, &buf->pt[1]);
-			saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
-		} else {
-			saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
-		}
-
-		err = videobuf_iolock(q,&buf->vb, &vv->ov_fb);
-		if (err)
-			goto oops;
-		err = saa7146_pgtable_build(dev,buf);
-		if (err)
-			goto oops;
-	}
-	buf->vb.state = VIDEOBUF_PREPARED;
-	buf->activate = buffer_activate;
-
-	return 0;
-
- oops:
-	DEB_D("error out\n");
-	saa7146_dma_free(dev,q,buf);
-
-	return err;
-}
-
-static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
-{
-	struct file *file = q->priv_data;
-	struct saa7146_fh *fh = file->private_data;
-	struct saa7146_vv *vv = fh->dev->vv_data;
-
-	if (0 == *count || *count > MAX_SAA7146_CAPTURE_BUFFERS)
-		*count = MAX_SAA7146_CAPTURE_BUFFERS;
-
-	*size = vv->video_fmt.sizeimage;
-
-	/* check if we exceed the "max_memory" parameter */
-	if( (*count * *size) > (max_memory*1048576) ) {
-		*count = (max_memory*1048576) / *size;
-	}
-
-	DEB_CAP("%d buffers, %d bytes each\n", *count, *size);
-
-	return 0;
-}
-
-static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
-{
-	struct file *file = q->priv_data;
-	struct saa7146_fh *fh = file->private_data;
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
-
-	DEB_CAP("vbuf:%p\n", vb);
-	saa7146_buffer_queue(fh->dev, &vv->video_dmaq, buf);
-}
-
-static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
-{
-	struct file *file = q->priv_data;
-	struct saa7146_fh *fh = file->private_data;
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
-
-	DEB_CAP("vbuf:%p\n", vb);
-
-	saa7146_dma_free(dev,q,buf);
-
-	release_all_pagetables(dev, buf);
-}
-
-static struct videobuf_queue_ops video_qops = {
-	.buf_setup    = buffer_setup,
-	.buf_prepare  = buffer_prepare,
-	.buf_queue    = buffer_queue,
-	.buf_release  = buffer_release,
-};
-
-/********************************************************************************/
-/* file operations */
-
-static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
-{
-	INIT_LIST_HEAD(&vv->video_dmaq.queue);
-
-	init_timer(&vv->video_dmaq.timeout);
-	vv->video_dmaq.timeout.function = saa7146_buffer_timeout;
-	vv->video_dmaq.timeout.data     = (unsigned long)(&vv->video_dmaq);
-	vv->video_dmaq.dev              = dev;
-
-	/* set some default values */
-	vv->standard = &dev->ext_vv_data->stds[0];
-
-	/* FIXME: what's this? */
-	vv->current_hps_source = SAA7146_HPS_SOURCE_PORT_A;
-	vv->current_hps_sync = SAA7146_HPS_SYNC_PORT_A;
-}
-
-
-static int video_open(struct saa7146_dev *dev, struct file *file)
-{
-	struct saa7146_fh *fh = file->private_data;
-
-	videobuf_queue_sg_init(&fh->video_q, &video_qops,
-			    &dev->pci->dev, &dev->slock,
-			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			    V4L2_FIELD_INTERLACED,
-			    sizeof(struct saa7146_buf),
-			    file, &dev->v4l2_lock);
-
-	return 0;
-}
-
-
-static void video_close(struct saa7146_dev *dev, struct file *file)
-{
-	struct saa7146_fh *fh = file->private_data;
-	struct saa7146_vv *vv = dev->vv_data;
-	struct videobuf_queue *q = &fh->video_q;
-
-	if (IS_CAPTURE_ACTIVE(fh) != 0)
-		video_end(fh, file);
-	else if (IS_OVERLAY_ACTIVE(fh) != 0)
-		saa7146_stop_preview(fh);
-
-	videobuf_stop(q);
-	/* hmm, why is this function declared void? */
-}
-
-
-static void video_irq_done(struct saa7146_dev *dev, unsigned long st)
-{
-	struct saa7146_vv *vv = dev->vv_data;
-	struct saa7146_dmaqueue *q = &vv->video_dmaq;
-
-	spin_lock(&dev->slock);
-	DEB_CAP("called\n");
-
-	/* only finish the buffer if we have one... */
-	if( NULL != q->curr ) {
-		saa7146_buffer_finish(dev,q,VIDEOBUF_DONE);
-	}
-	saa7146_buffer_next(dev,q,0);
-
-	spin_unlock(&dev->slock);
-}
-
-static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
-{
-	struct saa7146_fh *fh = file->private_data;
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	ssize_t ret = 0;
-
-	DEB_EE("called\n");
-
-	if ((vv->video_status & STATUS_CAPTURE) != 0) {
-		/* fixme: should we allow read() captures while streaming capture? */
-		if (vv->video_fh == fh) {
-			DEB_S("already capturing\n");
-			return -EBUSY;
-		}
-		DEB_S("already capturing in another open\n");
-		return -EBUSY;
-	}
-
-	ret = video_begin(fh);
-	if( 0 != ret) {
-		goto out;
-	}
-
-	ret = videobuf_read_one(&fh->video_q , data, count, ppos,
-				file->f_flags & O_NONBLOCK);
-	if (ret != 0) {
-		video_end(fh, file);
-	} else {
-		ret = video_end(fh, file);
-	}
-out:
-	/* restart overlay if it was active before */
-	if (vv->ov_suspend != NULL) {
-		saa7146_start_preview(vv->ov_suspend);
-		vv->ov_suspend = NULL;
-	}
-
-	return ret;
-}
-
-struct saa7146_use_ops saa7146_video_uops = {
-	.init = video_init,
-	.open = video_open,
-	.release = video_close,
-	.irq_done = video_irq_done,
-	.read = video_read,
-};
diff --git a/drivers/media/common/siano/Kconfig b/drivers/media/common/siano/Kconfig
new file mode 100644
index 0000000..425aead
--- /dev/null
+++ b/drivers/media/common/siano/Kconfig
@@ -0,0 +1,17 @@
+#
+# Siano Mobile Silicon Digital TV device configuration
+#
+
+config SMS_SIANO_MDTV
+	tristate
+	depends on DVB_CORE && RC_CORE && HAS_DMA
+	depends on SMS_USB_DRV || SMS_SDIO_DRV
+	default y
+	---help---
+	  Choose Y or M here if you have MDTV receiver with a Siano chipset.
+
+	  To compile this driver as a module, choose M here
+	  (The module will be called smsmdtv).
+
+	  Further documentation on this driver can be found on the WWW
+	  at http://www.siano-ms.com/
diff --git a/drivers/media/common/siano/Makefile b/drivers/media/common/siano/Makefile
new file mode 100644
index 0000000..2a09279
--- /dev/null
+++ b/drivers/media/common/siano/Makefile
@@ -0,0 +1,7 @@
+smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o
+
+obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
+
diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c
new file mode 100644
index 0000000..680c781
--- /dev/null
+++ b/drivers/media/common/siano/sms-cards.c
@@ -0,0 +1,311 @@
+/*
+ *  Card-specific functions for the Siano SMS1xxx USB dongle
+ *
+ *  Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ *  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "sms-cards.h"
+#include "smsir.h"
+#include <linux/module.h>
+
+static int sms_dbg;
+module_param_named(cards_dbg, sms_dbg, int, 0644);
+MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))");
+
+static struct sms_board sms_boards[] = {
+	[SMS_BOARD_UNKNOWN] = {
+		.name	= "Unknown board",
+	},
+	[SMS1XXX_BOARD_SIANO_STELLAR] = {
+		.name	= "Siano Stellar Digital Receiver",
+		.type	= SMS_STELLAR,
+	},
+	[SMS1XXX_BOARD_SIANO_NOVA_A] = {
+		.name	= "Siano Nova A Digital Receiver",
+		.type	= SMS_NOVA_A0,
+	},
+	[SMS1XXX_BOARD_SIANO_NOVA_B] = {
+		.name	= "Siano Nova B Digital Receiver",
+		.type	= SMS_NOVA_B0,
+	},
+	[SMS1XXX_BOARD_SIANO_VEGA] = {
+		.name	= "Siano Vega Digital Receiver",
+		.type	= SMS_VEGA,
+	},
+	[SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = {
+		.name	= "Hauppauge Catamount",
+		.type	= SMS_STELLAR,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
+	},
+	[SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = {
+		.name	= "Hauppauge Okemo-A",
+		.type	= SMS_NOVA_A0,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
+	},
+	[SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = {
+		.name	= "Hauppauge Okemo-B",
+		.type	= SMS_NOVA_B0,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
+	},
+	[SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
+		.name	= "Hauppauge WinTV MiniStick",
+		.type	= SMS_NOVA_B0,
+		.fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw",
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+		.rc_codes = RC_MAP_HAUPPAUGE,
+		.board_cfg.leds_power = 26,
+		.board_cfg.led0 = 27,
+		.board_cfg.led1 = 28,
+		.board_cfg.ir = 9,
+		.led_power = 26,
+		.led_lo    = 27,
+		.led_hi    = 28,
+	},
+	[SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = {
+		.name	= "Hauppauge WinTV MiniCard",
+		.type	= SMS_NOVA_B0,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+		.lna_ctrl  = 29,
+		.board_cfg.foreign_lna0_ctrl = 29,
+		.rf_switch = 17,
+		.board_cfg.rf_switch_uhf = 17,
+	},
+	[SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
+		.name	= "Hauppauge WinTV MiniCard",
+		.type	= SMS_NOVA_B0,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+		.lna_ctrl  = -1,
+	},
+	[SMS1XXX_BOARD_SIANO_NICE] = {
+	/* 11 */
+		.name = "Siano Nice Digital Receiver",
+		.type = SMS_NOVA_B0,
+	},
+	[SMS1XXX_BOARD_SIANO_VENICE] = {
+	/* 12 */
+		.name = "Siano Venice Digital Receiver",
+		.type = SMS_VEGA,
+	},
+};
+
+struct sms_board *sms_get_board(unsigned id)
+{
+	BUG_ON(id >= ARRAY_SIZE(sms_boards));
+
+	return &sms_boards[id];
+}
+EXPORT_SYMBOL_GPL(sms_get_board);
+static inline void sms_gpio_assign_11xx_default_led_config(
+		struct smscore_gpio_config *pGpioConfig) {
+	pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT;
+	pGpioConfig->InputCharacteristics =
+		SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL;
+	pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA;
+	pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS;
+	pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE;
+}
+
+int sms_board_event(struct smscore_device_t *coredev,
+		enum SMS_BOARD_EVENTS gevent) {
+	struct smscore_gpio_config MyGpioConfig;
+
+	sms_gpio_assign_11xx_default_led_config(&MyGpioConfig);
+
+	switch (gevent) {
+	case BOARD_EVENT_POWER_INIT: /* including hotplug */
+		break; /* BOARD_EVENT_BIND */
+
+	case BOARD_EVENT_POWER_SUSPEND:
+		break; /* BOARD_EVENT_POWER_SUSPEND */
+
+	case BOARD_EVENT_POWER_RESUME:
+		break; /* BOARD_EVENT_POWER_RESUME */
+
+	case BOARD_EVENT_BIND:
+		break; /* BOARD_EVENT_BIND */
+
+	case BOARD_EVENT_SCAN_PROG:
+		break; /* BOARD_EVENT_SCAN_PROG */
+	case BOARD_EVENT_SCAN_COMP:
+		break; /* BOARD_EVENT_SCAN_COMP */
+	case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL:
+		break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */
+	case BOARD_EVENT_FE_LOCK:
+		break; /* BOARD_EVENT_FE_LOCK */
+	case BOARD_EVENT_FE_UNLOCK:
+		break; /* BOARD_EVENT_FE_UNLOCK */
+	case BOARD_EVENT_DEMOD_LOCK:
+		break; /* BOARD_EVENT_DEMOD_LOCK */
+	case BOARD_EVENT_DEMOD_UNLOCK:
+		break; /* BOARD_EVENT_DEMOD_UNLOCK */
+	case BOARD_EVENT_RECEPTION_MAX_4:
+		break; /* BOARD_EVENT_RECEPTION_MAX_4 */
+	case BOARD_EVENT_RECEPTION_3:
+		break; /* BOARD_EVENT_RECEPTION_3 */
+	case BOARD_EVENT_RECEPTION_2:
+		break; /* BOARD_EVENT_RECEPTION_2 */
+	case BOARD_EVENT_RECEPTION_1:
+		break; /* BOARD_EVENT_RECEPTION_1 */
+	case BOARD_EVENT_RECEPTION_LOST_0:
+		break; /* BOARD_EVENT_RECEPTION_LOST_0 */
+	case BOARD_EVENT_MULTIPLEX_OK:
+		break; /* BOARD_EVENT_MULTIPLEX_OK */
+	case BOARD_EVENT_MULTIPLEX_ERRORS:
+		break; /* BOARD_EVENT_MULTIPLEX_ERRORS */
+
+	default:
+		sms_err("Unknown SMS board event");
+		break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sms_board_event);
+
+static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
+{
+	int lvl, ret;
+	u32 gpio;
+	struct smscore_config_gpio gpioconfig = {
+		.direction            = SMS_GPIO_DIRECTION_OUTPUT,
+		.pullupdown           = SMS_GPIO_PULLUPDOWN_NONE,
+		.inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,
+		.outputslewrate       = SMS_GPIO_OUTPUTSLEWRATE_FAST,
+		.outputdriving        = SMS_GPIO_OUTPUTDRIVING_4mA,
+	};
+
+	if (pin == 0)
+		return -EINVAL;
+
+	if (pin < 0) {
+		/* inverted gpio */
+		gpio = pin * -1;
+		lvl = enable ? 0 : 1;
+	} else {
+		gpio = pin;
+		lvl = enable ? 1 : 0;
+	}
+
+	ret = smscore_configure_gpio(coredev, gpio, &gpioconfig);
+	if (ret < 0)
+		return ret;
+
+	return smscore_set_gpio(coredev, gpio, lvl);
+}
+
+int sms_board_setup(struct smscore_device_t *coredev)
+{
+	int board_id = smscore_get_board_id(coredev);
+	struct sms_board *board = sms_get_board(board_id);
+
+	switch (board_id) {
+	case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+		/* turn off all LEDs */
+		sms_set_gpio(coredev, board->led_power, 0);
+		sms_set_gpio(coredev, board->led_hi, 0);
+		sms_set_gpio(coredev, board->led_lo, 0);
+		break;
+	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+		/* turn off LNA */
+		sms_set_gpio(coredev, board->lna_ctrl, 0);
+		break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sms_board_setup);
+
+int sms_board_power(struct smscore_device_t *coredev, int onoff)
+{
+	int board_id = smscore_get_board_id(coredev);
+	struct sms_board *board = sms_get_board(board_id);
+
+	switch (board_id) {
+	case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+		/* power LED */
+		sms_set_gpio(coredev,
+			     board->led_power, onoff ? 1 : 0);
+		break;
+	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+		/* LNA */
+		if (!onoff)
+			sms_set_gpio(coredev, board->lna_ctrl, 0);
+		break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sms_board_power);
+
+int sms_board_led_feedback(struct smscore_device_t *coredev, int led)
+{
+	int board_id = smscore_get_board_id(coredev);
+	struct sms_board *board = sms_get_board(board_id);
+
+	/* dont touch GPIO if LEDs are already set */
+	if (smscore_led_state(coredev, -1) == led)
+		return 0;
+
+	switch (board_id) {
+	case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+		sms_set_gpio(coredev,
+			     board->led_lo, (led & SMS_LED_LO) ? 1 : 0);
+		sms_set_gpio(coredev,
+			     board->led_hi, (led & SMS_LED_HI) ? 1 : 0);
+
+		smscore_led_state(coredev, led);
+		break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sms_board_led_feedback);
+
+int sms_board_lna_control(struct smscore_device_t *coredev, int onoff)
+{
+	int board_id = smscore_get_board_id(coredev);
+	struct sms_board *board = sms_get_board(board_id);
+
+	sms_debug("%s: LNA %s", __func__, onoff ? "enabled" : "disabled");
+
+	switch (board_id) {
+	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+		sms_set_gpio(coredev,
+			     board->rf_switch, onoff ? 1 : 0);
+		return sms_set_gpio(coredev,
+				    board->lna_ctrl, onoff ? 1 : 0);
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(sms_board_lna_control);
+
+int sms_board_load_modules(int id)
+{
+	switch (id) {
+	case SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT:
+	case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A:
+	case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B:
+	case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+		request_module("smsdvb");
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sms_board_load_modules);
diff --git a/drivers/media/common/siano/sms-cards.h b/drivers/media/common/siano/sms-cards.h
new file mode 100644
index 0000000..d8cdf75
--- /dev/null
+++ b/drivers/media/common/siano/sms-cards.h
@@ -0,0 +1,123 @@
+/*
+ *  Card-specific functions for the Siano SMS1xxx USB dongle
+ *
+ *  Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ *  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SMS_CARDS_H__
+#define __SMS_CARDS_H__
+
+#include <linux/usb.h>
+#include "smscoreapi.h"
+#include "smsir.h"
+
+#define SMS_BOARD_UNKNOWN 0
+#define SMS1XXX_BOARD_SIANO_STELLAR 1
+#define SMS1XXX_BOARD_SIANO_NOVA_A  2
+#define SMS1XXX_BOARD_SIANO_NOVA_B  3
+#define SMS1XXX_BOARD_SIANO_VEGA    4
+#define SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT 5
+#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6
+#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7
+#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
+#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9
+#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10
+#define SMS1XXX_BOARD_SIANO_NICE	11
+#define SMS1XXX_BOARD_SIANO_VENICE	12
+
+struct sms_board_gpio_cfg {
+	int lna_vhf_exist;
+	int lna_vhf_ctrl;
+	int lna_uhf_exist;
+	int lna_uhf_ctrl;
+	int lna_uhf_d_ctrl;
+	int lna_sband_exist;
+	int lna_sband_ctrl;
+	int lna_sband_d_ctrl;
+	int foreign_lna0_ctrl;
+	int foreign_lna1_ctrl;
+	int foreign_lna2_ctrl;
+	int rf_switch_vhf;
+	int rf_switch_uhf;
+	int rf_switch_sband;
+	int leds_power;
+	int led0;
+	int led1;
+	int led2;
+	int led3;
+	int led4;
+	int ir;
+	int eeprom_wp;
+	int mrc_sense;
+	int mrc_pdn_resetn;
+	int mrc_gp0; /* mrcs spi int */
+	int mrc_gp1;
+	int mrc_gp2;
+	int mrc_gp3;
+	int mrc_gp4;
+	int host_spi_gsp_ts_int;
+};
+
+struct sms_board {
+	enum sms_device_type_st type;
+	char *name, *fw[DEVICE_MODE_MAX];
+	struct sms_board_gpio_cfg board_cfg;
+	char *rc_codes;				/* Name of IR codes table */
+
+	/* gpios */
+	int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
+};
+
+struct sms_board *sms_get_board(unsigned id);
+
+extern struct smscore_device_t *coredev;
+
+enum SMS_BOARD_EVENTS {
+	BOARD_EVENT_POWER_INIT,
+	BOARD_EVENT_POWER_SUSPEND,
+	BOARD_EVENT_POWER_RESUME,
+	BOARD_EVENT_BIND,
+	BOARD_EVENT_SCAN_PROG,
+	BOARD_EVENT_SCAN_COMP,
+	BOARD_EVENT_EMERGENCY_WARNING_SIGNAL,
+	BOARD_EVENT_FE_LOCK,
+	BOARD_EVENT_FE_UNLOCK,
+	BOARD_EVENT_DEMOD_LOCK,
+	BOARD_EVENT_DEMOD_UNLOCK,
+	BOARD_EVENT_RECEPTION_MAX_4,
+	BOARD_EVENT_RECEPTION_3,
+	BOARD_EVENT_RECEPTION_2,
+	BOARD_EVENT_RECEPTION_1,
+	BOARD_EVENT_RECEPTION_LOST_0,
+	BOARD_EVENT_MULTIPLEX_OK,
+	BOARD_EVENT_MULTIPLEX_ERRORS
+};
+
+int sms_board_event(struct smscore_device_t *coredev,
+		enum SMS_BOARD_EVENTS gevent);
+
+int sms_board_setup(struct smscore_device_t *coredev);
+
+#define SMS_LED_OFF 0
+#define SMS_LED_LO  1
+#define SMS_LED_HI  2
+int sms_board_led_feedback(struct smscore_device_t *coredev, int led);
+int sms_board_power(struct smscore_device_t *coredev, int onoff);
+int sms_board_lna_control(struct smscore_device_t *coredev, int onoff);
+
+extern int sms_board_load_modules(int id);
+
+#endif /* __SMS_CARDS_H__ */
diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c
new file mode 100644
index 0000000..9cc5554
--- /dev/null
+++ b/drivers/media/common/siano/smscoreapi.c
@@ -0,0 +1,1637 @@
+/*
+ *  Siano core API module
+ *
+ *  This file contains implementation for the interface to sms core component
+ *
+ *  author: Uri Shkolnik
+ *
+ *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ *  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <linux/firmware.h>
+#include <linux/wait.h>
+#include <asm/byteorder.h>
+
+#include "smscoreapi.h"
+#include "sms-cards.h"
+#include "smsir.h"
+#include "smsendian.h"
+
+static int sms_dbg;
+module_param_named(debug, sms_dbg, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
+
+struct smscore_device_notifyee_t {
+	struct list_head entry;
+	hotplug_t hotplug;
+};
+
+struct smscore_idlist_t {
+	struct list_head entry;
+	int		id;
+	int		data_type;
+};
+
+struct smscore_client_t {
+	struct list_head entry;
+	struct smscore_device_t *coredev;
+	void			*context;
+	struct list_head 	idlist;
+	onresponse_t	onresponse_handler;
+	onremove_t		onremove_handler;
+};
+
+void smscore_set_board_id(struct smscore_device_t *core, int id)
+{
+	core->board_id = id;
+}
+
+int smscore_led_state(struct smscore_device_t *core, int led)
+{
+	if (led >= 0)
+		core->led_state = led;
+	return core->led_state;
+}
+EXPORT_SYMBOL_GPL(smscore_set_board_id);
+
+int smscore_get_board_id(struct smscore_device_t *core)
+{
+	return core->board_id;
+}
+EXPORT_SYMBOL_GPL(smscore_get_board_id);
+
+struct smscore_registry_entry_t {
+	struct list_head entry;
+	char			devpath[32];
+	int				mode;
+	enum sms_device_type_st	type;
+};
+
+static struct list_head g_smscore_notifyees;
+static struct list_head g_smscore_devices;
+static struct mutex g_smscore_deviceslock;
+
+static struct list_head g_smscore_registry;
+static struct mutex g_smscore_registrylock;
+
+static int default_mode = 4;
+
+module_param(default_mode, int, 0644);
+MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
+
+static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
+{
+	struct smscore_registry_entry_t *entry;
+	struct list_head *next;
+
+	kmutex_lock(&g_smscore_registrylock);
+	for (next = g_smscore_registry.next;
+	     next != &g_smscore_registry;
+	     next = next->next) {
+		entry = (struct smscore_registry_entry_t *) next;
+		if (!strcmp(entry->devpath, devpath)) {
+			kmutex_unlock(&g_smscore_registrylock);
+			return entry;
+		}
+	}
+	entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL);
+	if (entry) {
+		entry->mode = default_mode;
+		strcpy(entry->devpath, devpath);
+		list_add(&entry->entry, &g_smscore_registry);
+	} else
+		sms_err("failed to create smscore_registry.");
+	kmutex_unlock(&g_smscore_registrylock);
+	return entry;
+}
+
+int smscore_registry_getmode(char *devpath)
+{
+	struct smscore_registry_entry_t *entry;
+
+	entry = smscore_find_registry(devpath);
+	if (entry)
+		return entry->mode;
+	else
+		sms_err("No registry found.");
+
+	return default_mode;
+}
+EXPORT_SYMBOL_GPL(smscore_registry_getmode);
+
+static enum sms_device_type_st smscore_registry_gettype(char *devpath)
+{
+	struct smscore_registry_entry_t *entry;
+
+	entry = smscore_find_registry(devpath);
+	if (entry)
+		return entry->type;
+	else
+		sms_err("No registry found.");
+
+	return -1;
+}
+
+void smscore_registry_setmode(char *devpath, int mode)
+{
+	struct smscore_registry_entry_t *entry;
+
+	entry = smscore_find_registry(devpath);
+	if (entry)
+		entry->mode = mode;
+	else
+		sms_err("No registry found.");
+}
+
+static void smscore_registry_settype(char *devpath,
+				     enum sms_device_type_st type)
+{
+	struct smscore_registry_entry_t *entry;
+
+	entry = smscore_find_registry(devpath);
+	if (entry)
+		entry->type = type;
+	else
+		sms_err("No registry found.");
+}
+
+
+static void list_add_locked(struct list_head *new, struct list_head *head,
+			    spinlock_t *lock)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(lock, flags);
+
+	list_add(new, head);
+
+	spin_unlock_irqrestore(lock, flags);
+}
+
+/**
+ * register a client callback that called when device plugged in/unplugged
+ * NOTE: if devices exist callback is called immediately for each device
+ *
+ * @param hotplug callback
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_hotplug(hotplug_t hotplug)
+{
+	struct smscore_device_notifyee_t *notifyee;
+	struct list_head *next, *first;
+	int rc = 0;
+
+	kmutex_lock(&g_smscore_deviceslock);
+
+	notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
+			   GFP_KERNEL);
+	if (notifyee) {
+		/* now notify callback about existing devices */
+		first = &g_smscore_devices;
+		for (next = first->next;
+		     next != first && !rc;
+		     next = next->next) {
+			struct smscore_device_t *coredev =
+				(struct smscore_device_t *) next;
+			rc = hotplug(coredev, coredev->device, 1);
+		}
+
+		if (rc >= 0) {
+			notifyee->hotplug = hotplug;
+			list_add(&notifyee->entry, &g_smscore_notifyees);
+		} else
+			kfree(notifyee);
+	} else
+		rc = -ENOMEM;
+
+	kmutex_unlock(&g_smscore_deviceslock);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(smscore_register_hotplug);
+
+/**
+ * unregister a client callback that called when device plugged in/unplugged
+ *
+ * @param hotplug callback
+ *
+ */
+void smscore_unregister_hotplug(hotplug_t hotplug)
+{
+	struct list_head *next, *first;
+
+	kmutex_lock(&g_smscore_deviceslock);
+
+	first = &g_smscore_notifyees;
+
+	for (next = first->next; next != first;) {
+		struct smscore_device_notifyee_t *notifyee =
+			(struct smscore_device_notifyee_t *) next;
+		next = next->next;
+
+		if (notifyee->hotplug == hotplug) {
+			list_del(&notifyee->entry);
+			kfree(notifyee);
+		}
+	}
+
+	kmutex_unlock(&g_smscore_deviceslock);
+}
+EXPORT_SYMBOL_GPL(smscore_unregister_hotplug);
+
+static void smscore_notify_clients(struct smscore_device_t *coredev)
+{
+	struct smscore_client_t *client;
+
+	/* the client must call smscore_unregister_client from remove handler */
+	while (!list_empty(&coredev->clients)) {
+		client = (struct smscore_client_t *) coredev->clients.next;
+		client->onremove_handler(client->context);
+	}
+}
+
+static int smscore_notify_callbacks(struct smscore_device_t *coredev,
+				    struct device *device, int arrival)
+{
+	struct smscore_device_notifyee_t *elem;
+	int rc = 0;
+
+	/* note: must be called under g_deviceslock */
+
+	list_for_each_entry(elem, &g_smscore_notifyees, entry) {
+		rc = elem->hotplug(coredev, device, arrival);
+		if (rc < 0)
+			break;
+	}
+
+	return rc;
+}
+
+static struct
+smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
+				       dma_addr_t common_buffer_phys)
+{
+	struct smscore_buffer_t *cb =
+		kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
+	if (!cb) {
+		sms_info("kmalloc(...) failed");
+		return NULL;
+	}
+
+	cb->p = buffer;
+	cb->offset_in_common = buffer - (u8 *) common_buffer;
+	cb->phys = common_buffer_phys + cb->offset_in_common;
+
+	return cb;
+}
+
+/**
+ * creates coredev object for a device, prepares buffers,
+ * creates buffer mappings, notifies registered hotplugs about new device.
+ *
+ * @param params device pointer to struct with device specific parameters
+ *               and handlers
+ * @param coredev pointer to a value that receives created coredev object
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_device(struct smsdevice_params_t *params,
+			    struct smscore_device_t **coredev)
+{
+	struct smscore_device_t *dev;
+	u8 *buffer;
+
+	dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
+	if (!dev) {
+		sms_info("kzalloc(...) failed");
+		return -ENOMEM;
+	}
+
+	/* init list entry so it could be safe in smscore_unregister_device */
+	INIT_LIST_HEAD(&dev->entry);
+
+	/* init queues */
+	INIT_LIST_HEAD(&dev->clients);
+	INIT_LIST_HEAD(&dev->buffers);
+
+	/* init locks */
+	spin_lock_init(&dev->clientslock);
+	spin_lock_init(&dev->bufferslock);
+
+	/* init completion events */
+	init_completion(&dev->version_ex_done);
+	init_completion(&dev->data_download_done);
+	init_completion(&dev->trigger_done);
+	init_completion(&dev->init_device_done);
+	init_completion(&dev->reload_start_done);
+	init_completion(&dev->resume_done);
+	init_completion(&dev->gpio_configuration_done);
+	init_completion(&dev->gpio_set_level_done);
+	init_completion(&dev->gpio_get_level_done);
+	init_completion(&dev->ir_init_done);
+
+	/* Buffer management */
+	init_waitqueue_head(&dev->buffer_mng_waitq);
+
+	/* alloc common buffer */
+	dev->common_buffer_size = params->buffer_size * params->num_buffers;
+	dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
+						&dev->common_buffer_phys,
+						GFP_KERNEL | GFP_DMA);
+	if (!dev->common_buffer) {
+		smscore_unregister_device(dev);
+		return -ENOMEM;
+	}
+
+	/* prepare dma buffers */
+	for (buffer = dev->common_buffer;
+	     dev->num_buffers < params->num_buffers;
+	     dev->num_buffers++, buffer += params->buffer_size) {
+		struct smscore_buffer_t *cb =
+			smscore_createbuffer(buffer, dev->common_buffer,
+					     dev->common_buffer_phys);
+		if (!cb) {
+			smscore_unregister_device(dev);
+			return -ENOMEM;
+		}
+
+		smscore_putbuffer(dev, cb);
+	}
+
+	sms_info("allocated %d buffers", dev->num_buffers);
+
+	dev->mode = DEVICE_MODE_NONE;
+	dev->context = params->context;
+	dev->device = params->device;
+	dev->setmode_handler = params->setmode_handler;
+	dev->detectmode_handler = params->detectmode_handler;
+	dev->sendrequest_handler = params->sendrequest_handler;
+	dev->preload_handler = params->preload_handler;
+	dev->postload_handler = params->postload_handler;
+
+	dev->device_flags = params->flags;
+	strcpy(dev->devpath, params->devpath);
+
+	smscore_registry_settype(dev->devpath, params->device_type);
+
+	/* add device to devices list */
+	kmutex_lock(&g_smscore_deviceslock);
+	list_add(&dev->entry, &g_smscore_devices);
+	kmutex_unlock(&g_smscore_deviceslock);
+
+	*coredev = dev;
+
+	sms_info("device %p created", dev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(smscore_register_device);
+
+
+static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
+		void *buffer, size_t size, struct completion *completion) {
+	int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
+	if (rc < 0) {
+		sms_info("sendrequest returned error %d", rc);
+		return rc;
+	}
+
+	return wait_for_completion_timeout(completion,
+			msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ?
+			0 : -ETIME;
+}
+
+/**
+ * Starts & enables IR operations
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int smscore_init_ir(struct smscore_device_t *coredev)
+{
+	int ir_io;
+	int rc;
+	void *buffer;
+
+	coredev->ir.dev = NULL;
+	ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir;
+	if (ir_io) {/* only if IR port exist we use IR sub-module */
+		sms_info("IR loading");
+		rc = sms_ir_init(coredev);
+
+		if	(rc != 0)
+			sms_err("Error initialization DTV IR sub-module");
+		else {
+			buffer = kmalloc(sizeof(struct SmsMsgData_ST2) +
+						SMS_DMA_ALIGNMENT,
+						GFP_KERNEL | GFP_DMA);
+			if (buffer) {
+				struct SmsMsgData_ST2 *msg =
+				(struct SmsMsgData_ST2 *)
+				SMS_ALIGN_ADDRESS(buffer);
+
+				SMS_INIT_MSG(&msg->xMsgHeader,
+						MSG_SMS_START_IR_REQ,
+						sizeof(struct SmsMsgData_ST2));
+				msg->msgData[0] = coredev->ir.controller;
+				msg->msgData[1] = coredev->ir.timeout;
+
+				smsendian_handle_tx_message(
+					(struct SmsMsgHdr_ST2 *)msg);
+				rc = smscore_sendrequest_and_wait(coredev, msg,
+						msg->xMsgHeader. msgLength,
+						&coredev->ir_init_done);
+
+				kfree(buffer);
+			} else
+				sms_err
+				("Sending IR initialization message failed");
+		}
+	} else
+		sms_info("IR port has not been detected");
+
+	return 0;
+}
+
+/**
+ * sets initial device mode and notifies client hotplugs that device is ready
+ *
+ * @param coredev pointer to a coredev object returned by
+ * 		  smscore_register_device
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_start_device(struct smscore_device_t *coredev)
+{
+	int rc = smscore_set_device_mode(
+			coredev, smscore_registry_getmode(coredev->devpath));
+	if (rc < 0) {
+		sms_info("set device mode faile , rc %d", rc);
+		return rc;
+	}
+
+	kmutex_lock(&g_smscore_deviceslock);
+
+	rc = smscore_notify_callbacks(coredev, coredev->device, 1);
+	smscore_init_ir(coredev);
+
+	sms_info("device %p started, rc %d", coredev, rc);
+
+	kmutex_unlock(&g_smscore_deviceslock);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(smscore_start_device);
+
+
+static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
+					 void *buffer, size_t size)
+{
+	struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
+	struct SmsMsgHdr_ST *msg;
+	u32 mem_address;
+	u8 *payload = firmware->Payload;
+	int rc = 0;
+	firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
+	firmware->Length = le32_to_cpu(firmware->Length);
+
+	mem_address = firmware->StartAddress;
+
+	sms_info("loading FW to addr 0x%x size %d",
+		 mem_address, firmware->Length);
+	if (coredev->preload_handler) {
+		rc = coredev->preload_handler(coredev->context);
+		if (rc < 0)
+			return rc;
+	}
+
+	/* PAGE_SIZE buffer shall be enough and dma aligned */
+	msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
+	if (!msg)
+		return -ENOMEM;
+
+	if (coredev->mode != DEVICE_MODE_NONE) {
+		sms_debug("sending reload command.");
+		SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
+			     sizeof(struct SmsMsgHdr_ST));
+		rc = smscore_sendrequest_and_wait(coredev, msg,
+						  msg->msgLength,
+						  &coredev->reload_start_done);
+		mem_address = *(u32 *) &payload[20];
+	}
+
+	while (size && rc >= 0) {
+		struct SmsDataDownload_ST *DataMsg =
+			(struct SmsDataDownload_ST *) msg;
+		int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
+
+		SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
+			     (u16)(sizeof(struct SmsMsgHdr_ST) +
+				      sizeof(u32) + payload_size));
+
+		DataMsg->MemAddr = mem_address;
+		memcpy(DataMsg->Payload, payload, payload_size);
+
+		if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
+		    (coredev->mode == DEVICE_MODE_NONE))
+			rc = coredev->sendrequest_handler(
+				coredev->context, DataMsg,
+				DataMsg->xMsgHeader.msgLength);
+		else
+			rc = smscore_sendrequest_and_wait(
+				coredev, DataMsg,
+				DataMsg->xMsgHeader.msgLength,
+				&coredev->data_download_done);
+
+		payload += payload_size;
+		size -= payload_size;
+		mem_address += payload_size;
+	}
+
+	if (rc >= 0) {
+		if (coredev->mode == DEVICE_MODE_NONE) {
+			struct SmsMsgData_ST *TriggerMsg =
+				(struct SmsMsgData_ST *) msg;
+
+			SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
+				     sizeof(struct SmsMsgHdr_ST) +
+				     sizeof(u32) * 5);
+
+			TriggerMsg->msgData[0] = firmware->StartAddress;
+						/* Entry point */
+			TriggerMsg->msgData[1] = 5; /* Priority */
+			TriggerMsg->msgData[2] = 0x200; /* Stack size */
+			TriggerMsg->msgData[3] = 0; /* Parameter */
+			TriggerMsg->msgData[4] = 4; /* Task ID */
+
+			if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
+				rc = coredev->sendrequest_handler(
+					coredev->context, TriggerMsg,
+					TriggerMsg->xMsgHeader.msgLength);
+				msleep(100);
+			} else
+				rc = smscore_sendrequest_and_wait(
+					coredev, TriggerMsg,
+					TriggerMsg->xMsgHeader.msgLength,
+					&coredev->trigger_done);
+		} else {
+			SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
+				     sizeof(struct SmsMsgHdr_ST));
+
+			rc = coredev->sendrequest_handler(coredev->context,
+							  msg, msg->msgLength);
+		}
+		msleep(500);
+	}
+
+	sms_debug("rc=%d, postload=%p ", rc,
+		  coredev->postload_handler);
+
+	kfree(msg);
+
+	return ((rc >= 0) && coredev->postload_handler) ?
+		coredev->postload_handler(coredev->context) :
+		rc;
+}
+
+/**
+ * loads specified firmware into a buffer and calls device loadfirmware_handler
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param filename null-terminated string specifies firmware file name
+ * @param loadfirmware_handler device handler that loads firmware
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
+					   char *filename,
+					   loadfirmware_t loadfirmware_handler)
+{
+	int rc = -ENOENT;
+	const struct firmware *fw;
+	u8 *fw_buffer;
+
+	if (loadfirmware_handler == NULL && !(coredev->device_flags &
+					      SMS_DEVICE_FAMILY2))
+		return -EINVAL;
+
+	rc = request_firmware(&fw, filename, coredev->device);
+	if (rc < 0) {
+		sms_info("failed to open \"%s\"", filename);
+		return rc;
+	}
+	sms_info("read FW %s, size=%zd", filename, fw->size);
+	fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
+			    GFP_KERNEL | GFP_DMA);
+	if (fw_buffer) {
+		memcpy(fw_buffer, fw->data, fw->size);
+
+		rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
+		      smscore_load_firmware_family2(coredev,
+						    fw_buffer,
+						    fw->size) :
+		      loadfirmware_handler(coredev->context,
+					   fw_buffer, fw->size);
+
+		kfree(fw_buffer);
+	} else {
+		sms_info("failed to allocate firmware buffer");
+		rc = -ENOMEM;
+	}
+
+	release_firmware(fw);
+
+	return rc;
+}
+
+/**
+ * notifies all clients registered with the device, notifies hotplugs,
+ * frees all buffers and coredev object
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ *
+ * @return 0 on success, <0 on error.
+ */
+void smscore_unregister_device(struct smscore_device_t *coredev)
+{
+	struct smscore_buffer_t *cb;
+	int num_buffers = 0;
+	int retry = 0;
+
+	kmutex_lock(&g_smscore_deviceslock);
+
+	/* Release input device (IR) resources */
+	sms_ir_exit(coredev);
+
+	smscore_notify_clients(coredev);
+	smscore_notify_callbacks(coredev, NULL, 0);
+
+	/* at this point all buffers should be back
+	 * onresponse must no longer be called */
+
+	while (1) {
+		while (!list_empty(&coredev->buffers)) {
+			cb = (struct smscore_buffer_t *) coredev->buffers.next;
+			list_del(&cb->entry);
+			kfree(cb);
+			num_buffers++;
+		}
+		if (num_buffers == coredev->num_buffers)
+			break;
+		if (++retry > 10) {
+			sms_info("exiting although "
+				 "not all buffers released.");
+			break;
+		}
+
+		sms_info("waiting for %d buffer(s)",
+			 coredev->num_buffers - num_buffers);
+		msleep(100);
+	}
+
+	sms_info("freed %d buffers", num_buffers);
+
+	if (coredev->common_buffer)
+		dma_free_coherent(NULL, coredev->common_buffer_size,
+			coredev->common_buffer, coredev->common_buffer_phys);
+
+	if (coredev->fw_buf != NULL)
+		kfree(coredev->fw_buf);
+
+	list_del(&coredev->entry);
+	kfree(coredev);
+
+	kmutex_unlock(&g_smscore_deviceslock);
+
+	sms_info("device %p destroyed", coredev);
+}
+EXPORT_SYMBOL_GPL(smscore_unregister_device);
+
+static int smscore_detect_mode(struct smscore_device_t *coredev)
+{
+	void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
+			       GFP_KERNEL | GFP_DMA);
+	struct SmsMsgHdr_ST *msg =
+		(struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
+	int rc;
+
+	if (!buffer)
+		return -ENOMEM;
+
+	SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
+		     sizeof(struct SmsMsgHdr_ST));
+
+	rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
+					  &coredev->version_ex_done);
+	if (rc == -ETIME) {
+		sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
+
+		if (wait_for_completion_timeout(&coredev->resume_done,
+						msecs_to_jiffies(5000))) {
+			rc = smscore_sendrequest_and_wait(
+				coredev, msg, msg->msgLength,
+				&coredev->version_ex_done);
+			if (rc < 0)
+				sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
+					"second try, rc %d", rc);
+		} else
+			rc = -ETIME;
+	}
+
+	kfree(buffer);
+
+	return rc;
+}
+
+static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
+	/*Stellar		NOVA A0		Nova B0		VEGA*/
+	/*DVBT*/
+	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
+	/*DVBH*/
+	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
+	/*TDMB*/
+	{"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
+	/*DABIP*/
+	{"none", "none", "none", "none"},
+	/*BDA*/
+	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
+	/*ISDBT*/
+	{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
+	/*ISDBTBDA*/
+	{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
+	/*CMMB*/
+	{"none", "none", "none", "cmmb_vega_12mhz.inp"}
+};
+
+static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
+				    int mode, enum sms_device_type_st type)
+{
+	char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
+	return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
+}
+
+/**
+ * calls device handler to change mode of operation
+ * NOTE: stellar/usb may disconnect when changing mode
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param mode requested mode of operation
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
+{
+	void *buffer;
+	int rc = 0;
+	enum sms_device_type_st type;
+
+	sms_debug("set device mode to %d", mode);
+	if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
+		if (mode < DEVICE_MODE_DVBT || mode >= DEVICE_MODE_RAW_TUNER) {
+			sms_err("invalid mode specified %d", mode);
+			return -EINVAL;
+		}
+
+		smscore_registry_setmode(coredev->devpath, mode);
+
+		if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
+			rc = smscore_detect_mode(coredev);
+			if (rc < 0) {
+				sms_err("mode detect failed %d", rc);
+				return rc;
+			}
+		}
+
+		if (coredev->mode == mode) {
+			sms_info("device mode %d already set", mode);
+			return 0;
+		}
+
+		if (!(coredev->modes_supported & (1 << mode))) {
+			char *fw_filename;
+
+			type = smscore_registry_gettype(coredev->devpath);
+			fw_filename = sms_get_fw_name(coredev, mode, type);
+
+			rc = smscore_load_firmware_from_file(coredev,
+							     fw_filename, NULL);
+			if (rc < 0) {
+				sms_warn("error %d loading firmware: %s, "
+					 "trying again with default firmware",
+					 rc, fw_filename);
+
+				/* try again with the default firmware */
+				fw_filename = smscore_fw_lkup[mode][type];
+				rc = smscore_load_firmware_from_file(coredev,
+							     fw_filename, NULL);
+
+				if (rc < 0) {
+					sms_warn("error %d loading "
+						 "firmware: %s", rc,
+						 fw_filename);
+					return rc;
+				}
+			}
+			sms_log("firmware download success: %s", fw_filename);
+		} else
+			sms_info("mode %d supported by running "
+				 "firmware", mode);
+
+		buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
+				 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
+		if (buffer) {
+			struct SmsMsgData_ST *msg =
+				(struct SmsMsgData_ST *)
+					SMS_ALIGN_ADDRESS(buffer);
+
+			SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
+				     sizeof(struct SmsMsgData_ST));
+			msg->msgData[0] = mode;
+
+			rc = smscore_sendrequest_and_wait(
+				coredev, msg, msg->xMsgHeader.msgLength,
+				&coredev->init_device_done);
+
+			kfree(buffer);
+		} else {
+			sms_err("Could not allocate buffer for "
+				"init device message.");
+			rc = -ENOMEM;
+		}
+	} else {
+		if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
+			sms_err("invalid mode specified %d", mode);
+			return -EINVAL;
+		}
+
+		smscore_registry_setmode(coredev->devpath, mode);
+
+		if (coredev->detectmode_handler)
+			coredev->detectmode_handler(coredev->context,
+						    &coredev->mode);
+
+		if (coredev->mode != mode && coredev->setmode_handler)
+			rc = coredev->setmode_handler(coredev->context, mode);
+	}
+
+	if (rc >= 0) {
+		coredev->mode = mode;
+		coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
+	}
+
+	if (rc < 0)
+		sms_err("return error code %d.", rc);
+	return rc;
+}
+
+/**
+ * calls device handler to get current mode of operation
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ *
+ * @return current mode
+ */
+int smscore_get_device_mode(struct smscore_device_t *coredev)
+{
+	return coredev->mode;
+}
+EXPORT_SYMBOL_GPL(smscore_get_device_mode);
+
+/**
+ * find client by response id & type within the clients list.
+ * return client handle or NULL.
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param data_type client data type (SMS_DONT_CARE for all types)
+ * @param id client id (SMS_DONT_CARE for all id)
+ *
+ */
+static struct
+smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
+				      int data_type, int id)
+{
+	struct list_head *first;
+	struct smscore_client_t *client;
+	unsigned long flags;
+	struct list_head *firstid;
+	struct smscore_idlist_t *client_id;
+
+	spin_lock_irqsave(&coredev->clientslock, flags);
+	first = &coredev->clients;
+	list_for_each_entry(client, first, entry) {
+		firstid = &client->idlist;
+		list_for_each_entry(client_id, firstid, entry) {
+			if ((client_id->id == id) &&
+			    (client_id->data_type == data_type ||
+			    (client_id->data_type == 0)))
+				goto found;
+		}
+	}
+	client = NULL;
+found:
+	spin_unlock_irqrestore(&coredev->clientslock, flags);
+	return client;
+}
+
+/**
+ * find client by response id/type, call clients onresponse handler
+ * return buffer to pool on error
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param cb pointer to response buffer descriptor
+ *
+ */
+void smscore_onresponse(struct smscore_device_t *coredev,
+		struct smscore_buffer_t *cb) {
+	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p
+			+ cb->offset);
+	struct smscore_client_t *client;
+	int rc = -EBUSY;
+	static unsigned long last_sample_time; /* = 0; */
+	static int data_total; /* = 0; */
+	unsigned long time_now = jiffies_to_msecs(jiffies);
+
+	if (!last_sample_time)
+		last_sample_time = time_now;
+
+	if (time_now - last_sample_time > 10000) {
+		sms_debug("\ndata rate %d bytes/secs",
+			  (int)((data_total * 1000) /
+				(time_now - last_sample_time)));
+
+		last_sample_time = time_now;
+		data_total = 0;
+	}
+
+	data_total += cb->size;
+	/* Do we need to re-route? */
+	if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) ||
+			(phdr->msgType == MSG_SMS_TRANSMISSION_IND)) {
+		if (coredev->mode == DEVICE_MODE_DVBT_BDA)
+			phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID;
+	}
+
+
+	client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
+
+	/* If no client registered for type & id,
+	 * check for control client where type is not registered */
+	if (client)
+		rc = client->onresponse_handler(client->context, cb);
+
+	if (rc < 0) {
+		switch (phdr->msgType) {
+		case MSG_SMS_GET_VERSION_EX_RES:
+		{
+			struct SmsVersionRes_ST *ver =
+				(struct SmsVersionRes_ST *) phdr;
+			sms_debug("MSG_SMS_GET_VERSION_EX_RES "
+				  "id %d prots 0x%x ver %d.%d",
+				  ver->FirmwareId, ver->SupportedProtocols,
+				  ver->RomVersionMajor, ver->RomVersionMinor);
+
+			coredev->mode = ver->FirmwareId == 255 ?
+				DEVICE_MODE_NONE : ver->FirmwareId;
+			coredev->modes_supported = ver->SupportedProtocols;
+
+			complete(&coredev->version_ex_done);
+			break;
+		}
+		case MSG_SMS_INIT_DEVICE_RES:
+			sms_debug("MSG_SMS_INIT_DEVICE_RES");
+			complete(&coredev->init_device_done);
+			break;
+		case MSG_SW_RELOAD_START_RES:
+			sms_debug("MSG_SW_RELOAD_START_RES");
+			complete(&coredev->reload_start_done);
+			break;
+		case MSG_SMS_DATA_DOWNLOAD_RES:
+			complete(&coredev->data_download_done);
+			break;
+		case MSG_SW_RELOAD_EXEC_RES:
+			sms_debug("MSG_SW_RELOAD_EXEC_RES");
+			break;
+		case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
+			sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
+			complete(&coredev->trigger_done);
+			break;
+		case MSG_SMS_SLEEP_RESUME_COMP_IND:
+			complete(&coredev->resume_done);
+			break;
+		case MSG_SMS_GPIO_CONFIG_EX_RES:
+			sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES");
+			complete(&coredev->gpio_configuration_done);
+			break;
+		case MSG_SMS_GPIO_SET_LEVEL_RES:
+			sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES");
+			complete(&coredev->gpio_set_level_done);
+			break;
+		case MSG_SMS_GPIO_GET_LEVEL_RES:
+		{
+			u32 *msgdata = (u32 *) phdr;
+			coredev->gpio_get_res = msgdata[1];
+			sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d",
+					coredev->gpio_get_res);
+			complete(&coredev->gpio_get_level_done);
+			break;
+		}
+		case MSG_SMS_START_IR_RES:
+			complete(&coredev->ir_init_done);
+			break;
+		case MSG_SMS_IR_SAMPLES_IND:
+			sms_ir_event(coredev,
+				(const char *)
+				((char *)phdr
+				+ sizeof(struct SmsMsgHdr_ST)),
+				(int)phdr->msgLength
+				- sizeof(struct SmsMsgHdr_ST));
+			break;
+
+		default:
+			break;
+		}
+		smscore_putbuffer(coredev, cb);
+	}
+}
+EXPORT_SYMBOL_GPL(smscore_onresponse);
+
+/**
+ * return pointer to next free buffer descriptor from core pool
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ *
+ * @return pointer to descriptor on success, NULL on error.
+ */
+
+struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev)
+{
+	struct smscore_buffer_t *cb = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&coredev->bufferslock, flags);
+	if (!list_empty(&coredev->buffers)) {
+		cb = (struct smscore_buffer_t *) coredev->buffers.next;
+		list_del(&cb->entry);
+	}
+	spin_unlock_irqrestore(&coredev->bufferslock, flags);
+	return cb;
+}
+
+struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+{
+	struct smscore_buffer_t *cb = NULL;
+
+	wait_event(coredev->buffer_mng_waitq, (cb = get_entry(coredev)));
+
+	return cb;
+}
+EXPORT_SYMBOL_GPL(smscore_getbuffer);
+
+/**
+ * return buffer descriptor to a pool
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param cb pointer buffer descriptor
+ *
+ */
+void smscore_putbuffer(struct smscore_device_t *coredev,
+		struct smscore_buffer_t *cb) {
+	wake_up_interruptible(&coredev->buffer_mng_waitq);
+	list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
+}
+EXPORT_SYMBOL_GPL(smscore_putbuffer);
+
+static int smscore_validate_client(struct smscore_device_t *coredev,
+				   struct smscore_client_t *client,
+				   int data_type, int id)
+{
+	struct smscore_idlist_t *listentry;
+	struct smscore_client_t *registered_client;
+
+	if (!client) {
+		sms_err("bad parameter.");
+		return -EINVAL;
+	}
+	registered_client = smscore_find_client(coredev, data_type, id);
+	if (registered_client == client)
+		return 0;
+
+	if (registered_client) {
+		sms_err("The msg ID already registered to another client.");
+		return -EEXIST;
+	}
+	listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
+	if (!listentry) {
+		sms_err("Can't allocate memory for client id.");
+		return -ENOMEM;
+	}
+	listentry->id = id;
+	listentry->data_type = data_type;
+	list_add_locked(&listentry->entry, &client->idlist,
+			&coredev->clientslock);
+	return 0;
+}
+
+/**
+ * creates smsclient object, check that id is taken by another client
+ *
+ * @param coredev pointer to a coredev object from clients hotplug
+ * @param initial_id all messages with this id would be sent to this client
+ * @param data_type all messages of this type would be sent to this client
+ * @param onresponse_handler client handler that is called to
+ *                           process incoming messages
+ * @param onremove_handler client handler that is called when device is removed
+ * @param context client-specific context
+ * @param client pointer to a value that receives created smsclient object
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_client(struct smscore_device_t *coredev,
+			    struct smsclient_params_t *params,
+			    struct smscore_client_t **client)
+{
+	struct smscore_client_t *newclient;
+	/* check that no other channel with same parameters exists */
+	if (smscore_find_client(coredev, params->data_type,
+				params->initial_id)) {
+		sms_err("Client already exist.");
+		return -EEXIST;
+	}
+
+	newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
+	if (!newclient) {
+		sms_err("Failed to allocate memory for client.");
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&newclient->idlist);
+	newclient->coredev = coredev;
+	newclient->onresponse_handler = params->onresponse_handler;
+	newclient->onremove_handler = params->onremove_handler;
+	newclient->context = params->context;
+	list_add_locked(&newclient->entry, &coredev->clients,
+			&coredev->clientslock);
+	smscore_validate_client(coredev, newclient, params->data_type,
+				params->initial_id);
+	*client = newclient;
+	sms_debug("%p %d %d", params->context, params->data_type,
+		  params->initial_id);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(smscore_register_client);
+
+/**
+ * frees smsclient object and all subclients associated with it
+ *
+ * @param client pointer to smsclient object returned by
+ *               smscore_register_client
+ *
+ */
+void smscore_unregister_client(struct smscore_client_t *client)
+{
+	struct smscore_device_t *coredev = client->coredev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&coredev->clientslock, flags);
+
+
+	while (!list_empty(&client->idlist)) {
+		struct smscore_idlist_t *identry =
+			(struct smscore_idlist_t *) client->idlist.next;
+		list_del(&identry->entry);
+		kfree(identry);
+	}
+
+	sms_info("%p", client->context);
+
+	list_del(&client->entry);
+	kfree(client);
+
+	spin_unlock_irqrestore(&coredev->clientslock, flags);
+}
+EXPORT_SYMBOL_GPL(smscore_unregister_client);
+
+/**
+ * verifies that source id is not taken by another client,
+ * calls device handler to send requests to the device
+ *
+ * @param client pointer to smsclient object returned by
+ *               smscore_register_client
+ * @param buffer pointer to a request buffer
+ * @param size size (in bytes) of request buffer
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smsclient_sendrequest(struct smscore_client_t *client,
+			  void *buffer, size_t size)
+{
+	struct smscore_device_t *coredev;
+	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
+	int rc;
+
+	if (client == NULL) {
+		sms_err("Got NULL client");
+		return -EINVAL;
+	}
+
+	coredev = client->coredev;
+
+	/* check that no other channel with same id exists */
+	if (coredev == NULL) {
+		sms_err("Got NULL coredev");
+		return -EINVAL;
+	}
+
+	rc = smscore_validate_client(client->coredev, client, 0,
+				     phdr->msgSrcId);
+	if (rc < 0)
+		return rc;
+
+	return coredev->sendrequest_handler(coredev->context, buffer, size);
+}
+EXPORT_SYMBOL_GPL(smsclient_sendrequest);
+
+
+/* old GPIO managements implementation */
+int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
+			   struct smscore_config_gpio *pinconfig)
+{
+	struct {
+		struct SmsMsgHdr_ST hdr;
+		u32 data[6];
+	} msg;
+
+	if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
+		msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+		msg.hdr.msgDstId = HIF_TASK;
+		msg.hdr.msgFlags = 0;
+		msg.hdr.msgType  = MSG_SMS_GPIO_CONFIG_EX_REQ;
+		msg.hdr.msgLength = sizeof(msg);
+
+		msg.data[0] = pin;
+		msg.data[1] = pinconfig->pullupdown;
+
+		/* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */
+		msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0;
+
+		switch (pinconfig->outputdriving) {
+		case SMS_GPIO_OUTPUTDRIVING_16mA:
+			msg.data[3] = 7; /* Nova - 16mA */
+			break;
+		case SMS_GPIO_OUTPUTDRIVING_12mA:
+			msg.data[3] = 5; /* Nova - 11mA */
+			break;
+		case SMS_GPIO_OUTPUTDRIVING_8mA:
+			msg.data[3] = 3; /* Nova - 7mA */
+			break;
+		case SMS_GPIO_OUTPUTDRIVING_4mA:
+		default:
+			msg.data[3] = 2; /* Nova - 4mA */
+			break;
+		}
+
+		msg.data[4] = pinconfig->direction;
+		msg.data[5] = 0;
+	} else /* TODO: SMS_DEVICE_FAMILY1 */
+		return -EINVAL;
+
+	return coredev->sendrequest_handler(coredev->context,
+					    &msg, sizeof(msg));
+}
+
+int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
+{
+	struct {
+		struct SmsMsgHdr_ST hdr;
+		u32 data[3];
+	} msg;
+
+	if (pin > MAX_GPIO_PIN_NUMBER)
+		return -EINVAL;
+
+	msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+	msg.hdr.msgDstId = HIF_TASK;
+	msg.hdr.msgFlags = 0;
+	msg.hdr.msgType  = MSG_SMS_GPIO_SET_LEVEL_REQ;
+	msg.hdr.msgLength = sizeof(msg);
+
+	msg.data[0] = pin;
+	msg.data[1] = level ? 1 : 0;
+	msg.data[2] = 0;
+
+	return coredev->sendrequest_handler(coredev->context,
+					    &msg, sizeof(msg));
+}
+
+/* new GPIO management implementation */
+static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
+		u32 *pGroupNum, u32 *pGroupCfg) {
+
+	*pGroupCfg = 1;
+
+	if (PinNum <= 1)	{
+		*pTranslatedPinNum = 0;
+		*pGroupNum = 9;
+		*pGroupCfg = 2;
+	} else if (PinNum >= 2 && PinNum <= 6) {
+		*pTranslatedPinNum = 2;
+		*pGroupNum = 0;
+		*pGroupCfg = 2;
+	} else if (PinNum >= 7 && PinNum <= 11) {
+		*pTranslatedPinNum = 7;
+		*pGroupNum = 1;
+	} else if (PinNum >= 12 && PinNum <= 15) {
+		*pTranslatedPinNum = 12;
+		*pGroupNum = 2;
+		*pGroupCfg = 3;
+	} else if (PinNum == 16) {
+		*pTranslatedPinNum = 16;
+		*pGroupNum = 23;
+	} else if (PinNum >= 17 && PinNum <= 24) {
+		*pTranslatedPinNum = 17;
+		*pGroupNum = 3;
+	} else if (PinNum == 25) {
+		*pTranslatedPinNum = 25;
+		*pGroupNum = 6;
+	} else if (PinNum >= 26 && PinNum <= 28) {
+		*pTranslatedPinNum = 26;
+		*pGroupNum = 4;
+	} else if (PinNum == 29) {
+		*pTranslatedPinNum = 29;
+		*pGroupNum = 5;
+		*pGroupCfg = 2;
+	} else if (PinNum == 30) {
+		*pTranslatedPinNum = 30;
+		*pGroupNum = 8;
+	} else if (PinNum == 31) {
+		*pTranslatedPinNum = 31;
+		*pGroupNum = 17;
+	} else
+		return -1;
+
+	*pGroupCfg <<= 24;
+
+	return 0;
+}
+
+int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
+		struct smscore_gpio_config *pGpioConfig) {
+
+	u32 totalLen;
+	u32 TranslatedPinNum = 0;
+	u32 GroupNum = 0;
+	u32 ElectricChar;
+	u32 groupCfg;
+	void *buffer;
+	int rc;
+
+	struct SetGpioMsg {
+		struct SmsMsgHdr_ST xMsgHeader;
+		u32 msgData[6];
+	} *pMsg;
+
+
+	if (PinNum > MAX_GPIO_PIN_NUMBER)
+		return -EINVAL;
+
+	if (pGpioConfig == NULL)
+		return -EINVAL;
+
+	totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6);
+
+	buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+			GFP_KERNEL | GFP_DMA);
+	if (!buffer)
+		return -ENOMEM;
+
+	pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+
+	pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+	pMsg->xMsgHeader.msgDstId = HIF_TASK;
+	pMsg->xMsgHeader.msgFlags = 0;
+	pMsg->xMsgHeader.msgLength = (u16) totalLen;
+	pMsg->msgData[0] = PinNum;
+
+	if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
+		pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
+		if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
+				&groupCfg) != 0) {
+			rc = -EINVAL;
+			goto free;
+		}
+
+		pMsg->msgData[1] = TranslatedPinNum;
+		pMsg->msgData[2] = GroupNum;
+		ElectricChar = (pGpioConfig->PullUpDown)
+				| (pGpioConfig->InputCharacteristics << 2)
+				| (pGpioConfig->OutputSlewRate << 3)
+				| (pGpioConfig->OutputDriving << 4);
+		pMsg->msgData[3] = ElectricChar;
+		pMsg->msgData[4] = pGpioConfig->Direction;
+		pMsg->msgData[5] = groupCfg;
+	} else {
+		pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
+		pMsg->msgData[1] = pGpioConfig->PullUpDown;
+		pMsg->msgData[2] = pGpioConfig->OutputSlewRate;
+		pMsg->msgData[3] = pGpioConfig->OutputDriving;
+		pMsg->msgData[4] = pGpioConfig->Direction;
+		pMsg->msgData[5] = 0;
+	}
+
+	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+	rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+			&coredev->gpio_configuration_done);
+
+	if (rc != 0) {
+		if (rc == -ETIME)
+			sms_err("smscore_gpio_configure timeout");
+		else
+			sms_err("smscore_gpio_configure error");
+	}
+free:
+	kfree(buffer);
+
+	return rc;
+}
+
+int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
+		u8 NewLevel) {
+
+	u32 totalLen;
+	int rc;
+	void *buffer;
+
+	struct SetGpioMsg {
+		struct SmsMsgHdr_ST xMsgHeader;
+		u32 msgData[3]; /* keep it 3 ! */
+	} *pMsg;
+
+	if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER))
+		return -EINVAL;
+
+	totalLen = sizeof(struct SmsMsgHdr_ST) +
+			(3 * sizeof(u32)); /* keep it 3 ! */
+
+	buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+			GFP_KERNEL | GFP_DMA);
+	if (!buffer)
+		return -ENOMEM;
+
+	pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+
+	pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+	pMsg->xMsgHeader.msgDstId = HIF_TASK;
+	pMsg->xMsgHeader.msgFlags = 0;
+	pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
+	pMsg->xMsgHeader.msgLength = (u16) totalLen;
+	pMsg->msgData[0] = PinNum;
+	pMsg->msgData[1] = NewLevel;
+
+	/* Send message to SMS */
+	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+	rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+			&coredev->gpio_set_level_done);
+
+	if (rc != 0) {
+		if (rc == -ETIME)
+			sms_err("smscore_gpio_set_level timeout");
+		else
+			sms_err("smscore_gpio_set_level error");
+	}
+	kfree(buffer);
+
+	return rc;
+}
+
+int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
+		u8 *level) {
+
+	u32 totalLen;
+	int rc;
+	void *buffer;
+
+	struct SetGpioMsg {
+		struct SmsMsgHdr_ST xMsgHeader;
+		u32 msgData[2];
+	} *pMsg;
+
+
+	if (PinNum > MAX_GPIO_PIN_NUMBER)
+		return -EINVAL;
+
+	totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32));
+
+	buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+			GFP_KERNEL | GFP_DMA);
+	if (!buffer)
+		return -ENOMEM;
+
+	pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+
+	pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+	pMsg->xMsgHeader.msgDstId = HIF_TASK;
+	pMsg->xMsgHeader.msgFlags = 0;
+	pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ;
+	pMsg->xMsgHeader.msgLength = (u16) totalLen;
+	pMsg->msgData[0] = PinNum;
+	pMsg->msgData[1] = 0;
+
+	/* Send message to SMS */
+	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+	rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+			&coredev->gpio_get_level_done);
+
+	if (rc != 0) {
+		if (rc == -ETIME)
+			sms_err("smscore_gpio_get_level timeout");
+		else
+			sms_err("smscore_gpio_get_level error");
+	}
+	kfree(buffer);
+
+	/* Its a race between other gpio_get_level() and the copy of the single
+	 * global 'coredev->gpio_get_res' to  the function's variable 'level'
+	 */
+	*level = coredev->gpio_get_res;
+
+	return rc;
+}
+
+static int __init smscore_module_init(void)
+{
+	int rc = 0;
+
+	INIT_LIST_HEAD(&g_smscore_notifyees);
+	INIT_LIST_HEAD(&g_smscore_devices);
+	kmutex_init(&g_smscore_deviceslock);
+
+	INIT_LIST_HEAD(&g_smscore_registry);
+	kmutex_init(&g_smscore_registrylock);
+
+	return rc;
+}
+
+static void __exit smscore_module_exit(void)
+{
+	kmutex_lock(&g_smscore_deviceslock);
+	while (!list_empty(&g_smscore_notifyees)) {
+		struct smscore_device_notifyee_t *notifyee =
+			(struct smscore_device_notifyee_t *)
+				g_smscore_notifyees.next;
+
+		list_del(&notifyee->entry);
+		kfree(notifyee);
+	}
+	kmutex_unlock(&g_smscore_deviceslock);
+
+	kmutex_lock(&g_smscore_registrylock);
+	while (!list_empty(&g_smscore_registry)) {
+		struct smscore_registry_entry_t *entry =
+			(struct smscore_registry_entry_t *)
+				g_smscore_registry.next;
+
+		list_del(&entry->entry);
+		kfree(entry);
+	}
+	kmutex_unlock(&g_smscore_registrylock);
+
+	sms_debug("");
+}
+
+module_init(smscore_module_init);
+module_exit(smscore_module_exit);
+
+MODULE_DESCRIPTION("Siano MDTV Core module");
+MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h
new file mode 100644
index 0000000..c592ae0
--- /dev/null
+++ b/drivers/media/common/siano/smscoreapi.h
@@ -0,0 +1,775 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik, Anatoly Greenblat
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#ifndef __SMS_CORE_API_H__
+#define __SMS_CORE_API_H__
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+
+#include <asm/page.h>
+
+#include "smsir.h"
+
+#define kmutex_init(_p_) mutex_init(_p_)
+#define kmutex_lock(_p_) mutex_lock(_p_)
+#define kmutex_trylock(_p_) mutex_trylock(_p_)
+#define kmutex_unlock(_p_) mutex_unlock(_p_)
+
+#ifndef min
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS			(10000)
+#define SMS_ALLOC_ALIGNMENT				128
+#define SMS_DMA_ALIGNMENT				16
+#define SMS_ALIGN_ADDRESS(addr) \
+	((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1))
+
+#define SMS_DEVICE_FAMILY2				1
+#define SMS_ROM_NO_RESPONSE				2
+#define SMS_DEVICE_NOT_READY				0x8000000
+
+enum sms_device_type_st {
+	SMS_STELLAR = 0,
+	SMS_NOVA_A0,
+	SMS_NOVA_B0,
+	SMS_VEGA,
+	SMS_NUM_OF_DEVICE_TYPES
+};
+
+struct smscore_device_t;
+struct smscore_client_t;
+struct smscore_buffer_t;
+
+typedef int (*hotplug_t)(struct smscore_device_t *coredev,
+			 struct device *device, int arrival);
+
+typedef int (*setmode_t)(void *context, int mode);
+typedef void (*detectmode_t)(void *context, int *mode);
+typedef int (*sendrequest_t)(void *context, void *buffer, size_t size);
+typedef int (*loadfirmware_t)(void *context, void *buffer, size_t size);
+typedef int (*preload_t)(void *context);
+typedef int (*postload_t)(void *context);
+
+typedef int (*onresponse_t)(void *context, struct smscore_buffer_t *cb);
+typedef void (*onremove_t)(void *context);
+
+struct smscore_buffer_t {
+	/* public members, once passed to clients can be changed freely */
+	struct list_head entry;
+	int size;
+	int offset;
+
+	/* private members, read-only for clients */
+	void *p;
+	dma_addr_t phys;
+	unsigned long offset_in_common;
+};
+
+struct smsdevice_params_t {
+	struct device	*device;
+
+	int				buffer_size;
+	int				num_buffers;
+
+	char			devpath[32];
+	unsigned long	flags;
+
+	setmode_t		setmode_handler;
+	detectmode_t	detectmode_handler;
+	sendrequest_t	sendrequest_handler;
+	preload_t		preload_handler;
+	postload_t		postload_handler;
+
+	void			*context;
+	enum sms_device_type_st device_type;
+};
+
+struct smsclient_params_t {
+	int				initial_id;
+	int				data_type;
+	onresponse_t	onresponse_handler;
+	onremove_t		onremove_handler;
+	void			*context;
+};
+
+struct smscore_device_t {
+	struct list_head entry;
+
+	struct list_head clients;
+	struct list_head subclients;
+	spinlock_t clientslock;
+
+	struct list_head buffers;
+	spinlock_t bufferslock;
+	int num_buffers;
+
+	void *common_buffer;
+	int common_buffer_size;
+	dma_addr_t common_buffer_phys;
+
+	void *context;
+	struct device *device;
+
+	char devpath[32];
+	unsigned long device_flags;
+
+	setmode_t setmode_handler;
+	detectmode_t detectmode_handler;
+	sendrequest_t sendrequest_handler;
+	preload_t preload_handler;
+	postload_t postload_handler;
+
+	int mode, modes_supported;
+
+	/* host <--> device messages */
+	struct completion version_ex_done, data_download_done, trigger_done;
+	struct completion init_device_done, reload_start_done, resume_done;
+	struct completion gpio_configuration_done, gpio_set_level_done;
+	struct completion gpio_get_level_done, ir_init_done;
+
+	/* Buffer management */
+	wait_queue_head_t buffer_mng_waitq;
+
+	/* GPIO */
+	int gpio_get_res;
+
+	/* Target hardware board */
+	int board_id;
+
+	/* Firmware */
+	u8 *fw_buf;
+	u32 fw_buf_size;
+
+	/* Infrared (IR) */
+	struct ir_t ir;
+
+	int led_state;
+};
+
+/* GPIO definitions for antenna frequency domain control (SMS8021) */
+#define SMS_ANTENNA_GPIO_0					1
+#define SMS_ANTENNA_GPIO_1					0
+
+#define BW_8_MHZ							0
+#define BW_7_MHZ							1
+#define BW_6_MHZ							2
+#define BW_5_MHZ							3
+#define BW_ISDBT_1SEG						4
+#define BW_ISDBT_3SEG						5
+
+#define MSG_HDR_FLAG_SPLIT_MSG				4
+
+#define MAX_GPIO_PIN_NUMBER					31
+
+#define HIF_TASK							11
+#define SMS_HOST_LIB						150
+#define DVBT_BDA_CONTROL_MSG_ID				201
+
+#define SMS_MAX_PAYLOAD_SIZE				240
+#define SMS_TUNE_TIMEOUT					500
+
+#define MSG_SMS_GPIO_CONFIG_REQ				507
+#define MSG_SMS_GPIO_CONFIG_RES				508
+#define MSG_SMS_GPIO_SET_LEVEL_REQ			509
+#define MSG_SMS_GPIO_SET_LEVEL_RES			510
+#define MSG_SMS_GPIO_GET_LEVEL_REQ			511
+#define MSG_SMS_GPIO_GET_LEVEL_RES			512
+#define MSG_SMS_RF_TUNE_REQ					561
+#define MSG_SMS_RF_TUNE_RES					562
+#define MSG_SMS_INIT_DEVICE_REQ				578
+#define MSG_SMS_INIT_DEVICE_RES				579
+#define MSG_SMS_ADD_PID_FILTER_REQ			601
+#define MSG_SMS_ADD_PID_FILTER_RES			602
+#define MSG_SMS_REMOVE_PID_FILTER_REQ			603
+#define MSG_SMS_REMOVE_PID_FILTER_RES			604
+#define MSG_SMS_DAB_CHANNEL				607
+#define MSG_SMS_GET_PID_FILTER_LIST_REQ			608
+#define MSG_SMS_GET_PID_FILTER_LIST_RES			609
+#define MSG_SMS_GET_STATISTICS_RES			616
+#define MSG_SMS_GET_STATISTICS_REQ			615
+#define MSG_SMS_HO_PER_SLICES_IND			630
+#define MSG_SMS_SET_ANTENNA_CONFIG_REQ			651
+#define MSG_SMS_SET_ANTENNA_CONFIG_RES			652
+#define MSG_SMS_SLEEP_RESUME_COMP_IND			655
+#define MSG_SMS_DATA_DOWNLOAD_REQ			660
+#define MSG_SMS_DATA_DOWNLOAD_RES			661
+#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ		664
+#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES		665
+#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ		666
+#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES		667
+#define MSG_SMS_GET_VERSION_EX_REQ			668
+#define MSG_SMS_GET_VERSION_EX_RES			669
+#define MSG_SMS_SET_CLOCK_OUTPUT_REQ		670
+#define MSG_SMS_I2C_SET_FREQ_REQ			685
+#define MSG_SMS_GENERIC_I2C_REQ				687
+#define MSG_SMS_GENERIC_I2C_RES				688
+#define MSG_SMS_DVBT_BDA_DATA				693
+#define MSG_SW_RELOAD_REQ					697
+#define MSG_SMS_DATA_MSG					699
+#define MSG_SW_RELOAD_START_REQ				702
+#define MSG_SW_RELOAD_START_RES				703
+#define MSG_SW_RELOAD_EXEC_REQ				704
+#define MSG_SW_RELOAD_EXEC_RES				705
+#define MSG_SMS_SPI_INT_LINE_SET_REQ		710
+#define MSG_SMS_GPIO_CONFIG_EX_REQ			712
+#define MSG_SMS_GPIO_CONFIG_EX_RES			713
+#define MSG_SMS_ISDBT_TUNE_REQ				776
+#define MSG_SMS_ISDBT_TUNE_RES				777
+#define MSG_SMS_TRANSMISSION_IND			782
+#define MSG_SMS_START_IR_REQ				800
+#define MSG_SMS_START_IR_RES				801
+#define MSG_SMS_IR_SAMPLES_IND				802
+#define MSG_SMS_SIGNAL_DETECTED_IND			827
+#define MSG_SMS_NO_SIGNAL_IND				828
+
+#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \
+	(ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \
+	(ptr)->msgLength = len; (ptr)->msgFlags = 0; \
+} while (0)
+
+#define SMS_INIT_MSG(ptr, type, len) \
+	SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len)
+
+enum SMS_DVB3_EVENTS {
+	DVB3_EVENT_INIT = 0,
+	DVB3_EVENT_SLEEP,
+	DVB3_EVENT_HOTPLUG,
+	DVB3_EVENT_FE_LOCK,
+	DVB3_EVENT_FE_UNLOCK,
+	DVB3_EVENT_UNC_OK,
+	DVB3_EVENT_UNC_ERR
+};
+
+enum SMS_DEVICE_MODE {
+	DEVICE_MODE_NONE = -1,
+	DEVICE_MODE_DVBT = 0,
+	DEVICE_MODE_DVBH,
+	DEVICE_MODE_DAB_TDMB,
+	DEVICE_MODE_DAB_TDMB_DABIP,
+	DEVICE_MODE_DVBT_BDA,
+	DEVICE_MODE_ISDBT,
+	DEVICE_MODE_ISDBT_BDA,
+	DEVICE_MODE_CMMB,
+	DEVICE_MODE_RAW_TUNER,
+	DEVICE_MODE_MAX,
+};
+
+struct SmsMsgHdr_ST {
+	u16	msgType;
+	u8	msgSrcId;
+	u8	msgDstId;
+	u16	msgLength; /* Length of entire message, including header */
+	u16	msgFlags;
+};
+
+struct SmsMsgData_ST {
+	struct SmsMsgHdr_ST xMsgHeader;
+	u32 msgData[1];
+};
+
+struct SmsMsgData_ST2 {
+	struct SmsMsgHdr_ST xMsgHeader;
+	u32 msgData[2];
+};
+
+struct SmsDataDownload_ST {
+	struct SmsMsgHdr_ST	xMsgHeader;
+	u32			MemAddr;
+	u8			Payload[SMS_MAX_PAYLOAD_SIZE];
+};
+
+struct SmsVersionRes_ST {
+	struct SmsMsgHdr_ST	xMsgHeader;
+
+	u16		ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */
+	u8		Step; /* 0 - Step A */
+	u8		MetalFix; /* 0 - Metal 0 */
+
+	/* FirmwareId 0xFF if ROM, otherwise the
+	 * value indicated by SMSHOSTLIB_DEVICE_MODES_E */
+	u8 FirmwareId;
+	/* SupportedProtocols Bitwise OR combination of
+					     * supported protocols */
+	u8 SupportedProtocols;
+
+	u8		VersionMajor;
+	u8		VersionMinor;
+	u8		VersionPatch;
+	u8		VersionFieldPatch;
+
+	u8		RomVersionMajor;
+	u8		RomVersionMinor;
+	u8		RomVersionPatch;
+	u8		RomVersionFieldPatch;
+
+	u8		TextLabel[34];
+};
+
+struct SmsFirmware_ST {
+	u32			CheckSum;
+	u32			Length;
+	u32			StartAddress;
+	u8			Payload[1];
+};
+
+/* Statistics information returned as response for
+ * SmsHostApiGetStatistics_Req */
+struct SMSHOSTLIB_STATISTICS_ST {
+	u32 Reserved;		/* Reserved */
+
+	/* Common parameters */
+	u32 IsRfLocked;		/* 0 - not locked, 1 - locked */
+	u32 IsDemodLocked;	/* 0 - not locked, 1 - locked */
+	u32 IsExternalLNAOn;	/* 0 - external LNA off, 1 - external LNA on */
+
+	/* Reception quality */
+	s32 SNR;		/* dB */
+	u32 BER;		/* Post Viterbi BER [1E-5] */
+	u32 FIB_CRC;		/* CRC errors percentage, valid only for DAB */
+	u32 TS_PER;		/* Transport stream PER,
+	0xFFFFFFFF indicate N/A, valid only for DVB-T/H */
+	u32 MFER;		/* DVB-H frame error rate in percentage,
+	0xFFFFFFFF indicate N/A, valid only for DVB-H */
+	s32 RSSI;		/* dBm */
+	s32 InBandPwr;		/* In band power in dBM */
+	s32 CarrierOffset;	/* Carrier Offset in bin/1024 */
+
+	/* Transmission parameters */
+	u32 Frequency;		/* Frequency in Hz */
+	u32 Bandwidth;		/* Bandwidth in MHz, valid only for DVB-T/H */
+	u32 TransmissionMode;	/* Transmission Mode, for DAB modes 1-4,
+	for DVB-T/H FFT mode carriers in Kilos */
+	u32 ModemState;		/* from SMSHOSTLIB_DVB_MODEM_STATE_ET,
+	valid only for DVB-T/H */
+	u32 GuardInterval;	/* Guard Interval from
+	SMSHOSTLIB_GUARD_INTERVALS_ET, 	valid only for DVB-T/H */
+	u32 CodeRate;		/* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
+	valid only for DVB-T/H */
+	u32 LPCodeRate;		/* Low Priority Code Rate from
+	SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */
+	u32 Hierarchy;		/* Hierarchy from SMSHOSTLIB_HIERARCHY_ET,
+	valid only for DVB-T/H */
+	u32 Constellation;	/* Constellation from
+	SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */
+
+	/* Burst parameters, valid only for DVB-H */
+	u32 BurstSize;		/* Current burst size in bytes,
+	valid only for DVB-H */
+	u32 BurstDuration;	/* Current burst duration in mSec,
+	valid only for DVB-H */
+	u32 BurstCycleTime;	/* Current burst cycle time in mSec,
+	valid only for DVB-H */
+	u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec,
+	as calculated by demodulator, valid only for DVB-H */
+	u32 NumOfRows;		/* Number of rows in MPE table,
+	valid only for DVB-H */
+	u32 NumOfPaddCols;	/* Number of padding columns in MPE table,
+	valid only for DVB-H */
+	u32 NumOfPunctCols;	/* Number of puncturing columns in MPE table,
+	valid only for DVB-H */
+	u32 ErrorTSPackets;	/* Number of erroneous
+	transport-stream packets */
+	u32 TotalTSPackets;	/* Total number of transport-stream packets */
+	u32 NumOfValidMpeTlbs;	/* Number of MPE tables which do not include
+	errors after MPE RS decoding */
+	u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors
+	after MPE RS decoding */
+	u32 NumOfCorrectedMpeTlbs;/* Number of MPE tables which were
+	corrected by MPE RS decoding */
+	/* Common params */
+	u32 BERErrorCount;	/* Number of errornous SYNC bits. */
+	u32 BERBitCount;	/* Total number of SYNC bits. */
+
+	/* Interface information */
+	u32 SmsToHostTxErrors;	/* Total number of transmission errors. */
+
+	/* DAB/T-DMB */
+	u32 PreBER; 		/* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
+
+	/* DVB-H TPS parameters */
+	u32 CellId;		/* TPS Cell ID in bits 15..0, bits 31..16 zero;
+	 if set to 0xFFFFFFFF cell_id not yet recovered */
+	u32 DvbhSrvIndHP;	/* DVB-H service indication info, bit 1 -
+	Time Slicing indicator, bit 0 - MPE-FEC indicator */
+	u32 DvbhSrvIndLP;	/* DVB-H service indication info, bit 1 -
+	Time Slicing indicator, bit 0 - MPE-FEC indicator */
+
+	u32 NumMPEReceived;	/* DVB-H, Num MPE section received */
+
+	u32 ReservedFields[10];	/* Reserved */
+};
+
+struct SmsMsgStatisticsInfo_ST {
+	u32 RequestResult;
+
+	struct SMSHOSTLIB_STATISTICS_ST Stat;
+
+	/* Split the calc of the SNR in DAB */
+	u32 Signal; /* dB */
+	u32 Noise; /* dB */
+
+};
+
+struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST {
+	/* Per-layer information */
+	u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
+		       * 255 means layer does not exist */
+	u32 Constellation; /* Constellation from SMSHOSTLIB_CONSTELLATION_ET,
+			    * 255 means layer does not exist */
+	u32 BER; /* Post Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */
+	u32 BERErrorCount; /* Post Viterbi Error Bits Count */
+	u32 BERBitCount; /* Post Viterbi Total Bits Count */
+	u32 PreBER; /* Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */
+	u32 TS_PER; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */
+	u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */
+	u32 TotalTSPackets; /* Total number of transport-stream packets */
+	u32 TILdepthI; /* Time interleaver depth I parameter,
+			* 255 means layer does not exist */
+	u32 NumberOfSegments; /* Number of segments in layer A,
+			       * 255 means layer does not exist */
+	u32 TMCCErrors; /* TMCC errors */
+};
+
+struct SMSHOSTLIB_STATISTICS_ISDBT_ST {
+	u32 StatisticsType; /* Enumerator identifying the type of the
+				* structure.  Values are the same as
+				* SMSHOSTLIB_DEVICE_MODES_E
+				*
+				* This field MUST always be first in any
+				* statistics structure */
+
+	u32 FullSize; /* Total size of the structure returned by the modem.
+		       * If the size requested by the host is smaller than
+		       * FullSize, the struct will be truncated */
+
+	/* Common parameters */
+	u32 IsRfLocked; /* 0 - not locked, 1 - locked */
+	u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
+	u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
+
+	/* Reception quality */
+	s32  SNR; /* dB */
+	s32  RSSI; /* dBm */
+	s32  InBandPwr; /* In band power in dBM */
+	s32  CarrierOffset; /* Carrier Offset in Hz */
+
+	/* Transmission parameters */
+	u32 Frequency; /* Frequency in Hz */
+	u32 Bandwidth; /* Bandwidth in MHz */
+	u32 TransmissionMode; /* ISDB-T transmission mode */
+	u32 ModemState; /* 0 - Acquisition, 1 - Locked */
+	u32 GuardInterval; /* Guard Interval, 1 divided by value */
+	u32 SystemType; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */
+	u32 PartialReception; /* TRUE - partial reception, FALSE otherwise */
+	u32 NumOfLayers; /* Number of ISDB-T layers in the network */
+
+	/* Per-layer information */
+	/* Layers A, B and C */
+	struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST	LayerInfo[3];
+	/* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */
+
+	/* Interface information */
+	u32 SmsToHostTxErrors; /* Total number of transmission errors. */
+};
+
+struct PID_STATISTICS_DATA_S {
+	struct PID_BURST_S {
+		u32 size;
+		u32 padding_cols;
+		u32 punct_cols;
+		u32 duration;
+		u32 cycle;
+		u32 calc_cycle;
+	} burst;
+
+	u32 tot_tbl_cnt;
+	u32 invalid_tbl_cnt;
+	u32 tot_cor_tbl;
+};
+
+struct PID_DATA_S {
+	u32 pid;
+	u32 num_rows;
+	struct PID_STATISTICS_DATA_S pid_statistics;
+};
+
+#define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1)
+#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth)
+#define CORRECT_STAT_TRANSMISSON_MODE(_stat) \
+	if (_stat.TransmissionMode == 0) \
+		_stat.TransmissionMode = 2; \
+	else if (_stat.TransmissionMode == 1) \
+		_stat.TransmissionMode = 8; \
+		else \
+			_stat.TransmissionMode = 4;
+
+struct TRANSMISSION_STATISTICS_S {
+	u32 Frequency;		/* Frequency in Hz */
+	u32 Bandwidth;		/* Bandwidth in MHz */
+	u32 TransmissionMode;	/* FFT mode carriers in Kilos */
+	u32 GuardInterval;	/* Guard Interval from
+	SMSHOSTLIB_GUARD_INTERVALS_ET */
+	u32 CodeRate;		/* Code Rate from SMSHOSTLIB_CODE_RATE_ET */
+	u32 LPCodeRate;		/* Low Priority Code Rate from
+	SMSHOSTLIB_CODE_RATE_ET */
+	u32 Hierarchy;		/* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */
+	u32 Constellation;	/* Constellation from
+	SMSHOSTLIB_CONSTELLATION_ET */
+
+	/* DVB-H TPS parameters */
+	u32 CellId;		/* TPS Cell ID in bits 15..0, bits 31..16 zero;
+	 if set to 0xFFFFFFFF cell_id not yet recovered */
+	u32 DvbhSrvIndHP;	/* DVB-H service indication info, bit 1 -
+	 Time Slicing indicator, bit 0 - MPE-FEC indicator */
+	u32 DvbhSrvIndLP;	/* DVB-H service indication info, bit 1 -
+	 Time Slicing indicator, bit 0 - MPE-FEC indicator */
+	u32 IsDemodLocked;	/* 0 - not locked, 1 - locked */
+};
+
+struct RECEPTION_STATISTICS_S {
+	u32 IsRfLocked;		/* 0 - not locked, 1 - locked */
+	u32 IsDemodLocked;	/* 0 - not locked, 1 - locked */
+	u32 IsExternalLNAOn;	/* 0 - external LNA off, 1 - external LNA on */
+
+	u32 ModemState;		/* from SMSHOSTLIB_DVB_MODEM_STATE_ET */
+	s32 SNR;		/* dB */
+	u32 BER;		/* Post Viterbi BER [1E-5] */
+	u32 BERErrorCount;	/* Number of erronous SYNC bits. */
+	u32 BERBitCount;	/* Total number of SYNC bits. */
+	u32 TS_PER;		/* Transport stream PER,
+	0xFFFFFFFF indicate N/A */
+	u32 MFER;		/* DVB-H frame error rate in percentage,
+	0xFFFFFFFF indicate N/A, valid only for DVB-H */
+	s32 RSSI;		/* dBm */
+	s32 InBandPwr;		/* In band power in dBM */
+	s32 CarrierOffset;	/* Carrier Offset in bin/1024 */
+	u32 ErrorTSPackets;	/* Number of erroneous
+	transport-stream packets */
+	u32 TotalTSPackets;	/* Total number of transport-stream packets */
+
+	s32 MRC_SNR;		/* dB */
+	s32 MRC_RSSI;		/* dBm */
+	s32 MRC_InBandPwr;	/* In band power in dBM */
+};
+
+
+/* Statistics information returned as response for
+ * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */
+struct SMSHOSTLIB_STATISTICS_DVB_S {
+	/* Reception */
+	struct RECEPTION_STATISTICS_S ReceptionData;
+
+	/* Transmission parameters */
+	struct TRANSMISSION_STATISTICS_S TransmissionData;
+
+	/* Burst parameters, valid only for DVB-H */
+#define	SRVM_MAX_PID_FILTERS 8
+	struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS];
+};
+
+struct SRVM_SIGNAL_STATUS_S {
+	u32 result;
+	u32 snr;
+	u32 tsPackets;
+	u32 etsPackets;
+	u32 constellation;
+	u32 hpCode;
+	u32 tpsSrvIndLP;
+	u32 tpsSrvIndHP;
+	u32 cellId;
+	u32 reason;
+
+	s32 inBandPower;
+	u32 requestId;
+};
+
+struct SMSHOSTLIB_I2C_REQ_ST {
+	u32	DeviceAddress; /* I2c device address */
+	u32	WriteCount; /* number of bytes to write */
+	u32	ReadCount; /* number of bytes to read */
+	u8	Data[1];
+};
+
+struct SMSHOSTLIB_I2C_RES_ST {
+	u32	Status; /* non-zero value in case of failure */
+	u32	ReadCount; /* number of bytes read */
+	u8	Data[1];
+};
+
+
+struct smscore_config_gpio {
+#define SMS_GPIO_DIRECTION_INPUT  0
+#define SMS_GPIO_DIRECTION_OUTPUT 1
+	u8 direction;
+
+#define SMS_GPIO_PULLUPDOWN_NONE     0
+#define SMS_GPIO_PULLUPDOWN_PULLDOWN 1
+#define SMS_GPIO_PULLUPDOWN_PULLUP   2
+#define SMS_GPIO_PULLUPDOWN_KEEPER   3
+	u8 pullupdown;
+
+#define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL  0
+#define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1
+	u8 inputcharacteristics;
+
+#define SMS_GPIO_OUTPUTSLEWRATE_FAST 0
+#define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1
+	u8 outputslewrate;
+
+#define SMS_GPIO_OUTPUTDRIVING_4mA  0
+#define SMS_GPIO_OUTPUTDRIVING_8mA  1
+#define SMS_GPIO_OUTPUTDRIVING_12mA 2
+#define SMS_GPIO_OUTPUTDRIVING_16mA 3
+	u8 outputdriving;
+};
+
+struct smscore_gpio_config {
+#define SMS_GPIO_DIRECTION_INPUT  0
+#define SMS_GPIO_DIRECTION_OUTPUT 1
+	u8 Direction;
+
+#define SMS_GPIO_PULL_UP_DOWN_NONE     0
+#define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1
+#define SMS_GPIO_PULL_UP_DOWN_PULLUP   2
+#define SMS_GPIO_PULL_UP_DOWN_KEEPER   3
+	u8 PullUpDown;
+
+#define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL  0
+#define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1
+	u8 InputCharacteristics;
+
+#define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW		1 /* 10xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST		0 /* 10xx */
+
+
+#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS	0 /* 11xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS	1 /* 11xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS	2 /* 11xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS	3 /* 11xx */
+	u8 OutputSlewRate;
+
+#define SMS_GPIO_OUTPUT_DRIVING_S_4mA		0 /* 10xx */
+#define SMS_GPIO_OUTPUT_DRIVING_S_8mA		1 /* 10xx */
+#define SMS_GPIO_OUTPUT_DRIVING_S_12mA		2 /* 10xx */
+#define SMS_GPIO_OUTPUT_DRIVING_S_16mA		3 /* 10xx */
+
+#define SMS_GPIO_OUTPUT_DRIVING_1_5mA		0 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_2_8mA		1 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_4mA		2 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_7mA		3 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_10mA		4 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_11mA		5 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_14mA		6 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_16mA		7 /* 11xx */
+	u8 OutputDriving;
+};
+
+extern void smscore_registry_setmode(char *devpath, int mode);
+extern int smscore_registry_getmode(char *devpath);
+
+extern int smscore_register_hotplug(hotplug_t hotplug);
+extern void smscore_unregister_hotplug(hotplug_t hotplug);
+
+extern int smscore_register_device(struct smsdevice_params_t *params,
+				   struct smscore_device_t **coredev);
+extern void smscore_unregister_device(struct smscore_device_t *coredev);
+
+extern int smscore_start_device(struct smscore_device_t *coredev);
+extern int smscore_load_firmware(struct smscore_device_t *coredev,
+				 char *filename,
+				 loadfirmware_t loadfirmware_handler);
+
+extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode);
+extern int smscore_get_device_mode(struct smscore_device_t *coredev);
+
+extern int smscore_register_client(struct smscore_device_t *coredev,
+				    struct smsclient_params_t *params,
+				    struct smscore_client_t **client);
+extern void smscore_unregister_client(struct smscore_client_t *client);
+
+extern int smsclient_sendrequest(struct smscore_client_t *client,
+				 void *buffer, size_t size);
+extern void smscore_onresponse(struct smscore_device_t *coredev,
+			       struct smscore_buffer_t *cb);
+
+extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev);
+extern int smscore_map_common_buffer(struct smscore_device_t *coredev,
+				      struct vm_area_struct *vma);
+extern int smscore_get_fw_filename(struct smscore_device_t *coredev,
+				   int mode, char *filename);
+extern int smscore_send_fw_file(struct smscore_device_t *coredev,
+				u8 *ufwbuf, int size);
+
+extern
+struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
+extern void smscore_putbuffer(struct smscore_device_t *coredev,
+			      struct smscore_buffer_t *cb);
+
+/* old GPIO management */
+int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
+			   struct smscore_config_gpio *pinconfig);
+int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level);
+
+/* new GPIO management */
+extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
+		struct smscore_gpio_config *pGpioConfig);
+extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
+		u8 NewLevel);
+extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
+		u8 *level);
+
+void smscore_set_board_id(struct smscore_device_t *core, int id);
+int smscore_get_board_id(struct smscore_device_t *core);
+
+int smscore_led_state(struct smscore_device_t *core, int led);
+
+
+/* ------------------------------------------------------------------------ */
+
+#define DBG_INFO 1
+#define DBG_ADV  2
+
+#define sms_printk(kern, fmt, arg...) \
+	printk(kern "%s: " fmt "\n", __func__, ##arg)
+
+#define dprintk(kern, lvl, fmt, arg...) do {\
+	if (sms_dbg & lvl) \
+		sms_printk(kern, fmt, ##arg); } while (0)
+
+#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg)
+#define sms_err(fmt, arg...) \
+	sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg)
+#define sms_warn(fmt, arg...)  sms_printk(KERN_WARNING, fmt, ##arg)
+#define sms_info(fmt, arg...) \
+	dprintk(KERN_INFO, DBG_INFO, fmt, ##arg)
+#define sms_debug(fmt, arg...) \
+	dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg)
+
+
+#endif /* __SMS_CORE_API_H__ */
diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c
new file mode 100644
index 0000000..aa77e54
--- /dev/null
+++ b/drivers/media/common/siano/smsdvb.c
@@ -0,0 +1,1078 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+
+#include "smscoreapi.h"
+#include "smsendian.h"
+#include "sms-cards.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct smsdvb_client_t {
+	struct list_head entry;
+
+	struct smscore_device_t *coredev;
+	struct smscore_client_t *smsclient;
+
+	struct dvb_adapter      adapter;
+	struct dvb_demux        demux;
+	struct dmxdev           dmxdev;
+	struct dvb_frontend     frontend;
+
+	fe_status_t             fe_status;
+
+	struct completion       tune_done;
+
+	struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
+	int event_fe_state;
+	int event_unc_state;
+};
+
+static struct list_head g_smsdvb_clients;
+static struct mutex g_smsdvb_clientslock;
+
+static int sms_dbg;
+module_param_named(debug, sms_dbg, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
+
+/* Events that may come from DVB v3 adapter */
+static void sms_board_dvb3_event(struct smsdvb_client_t *client,
+		enum SMS_DVB3_EVENTS event) {
+
+	struct smscore_device_t *coredev = client->coredev;
+	switch (event) {
+	case DVB3_EVENT_INIT:
+		sms_debug("DVB3_EVENT_INIT");
+		sms_board_event(coredev, BOARD_EVENT_BIND);
+		break;
+	case DVB3_EVENT_SLEEP:
+		sms_debug("DVB3_EVENT_SLEEP");
+		sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
+		break;
+	case DVB3_EVENT_HOTPLUG:
+		sms_debug("DVB3_EVENT_HOTPLUG");
+		sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
+		break;
+	case DVB3_EVENT_FE_LOCK:
+		if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
+			client->event_fe_state = DVB3_EVENT_FE_LOCK;
+			sms_debug("DVB3_EVENT_FE_LOCK");
+			sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
+		}
+		break;
+	case DVB3_EVENT_FE_UNLOCK:
+		if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
+			client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
+			sms_debug("DVB3_EVENT_FE_UNLOCK");
+			sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
+		}
+		break;
+	case DVB3_EVENT_UNC_OK:
+		if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
+			client->event_unc_state = DVB3_EVENT_UNC_OK;
+			sms_debug("DVB3_EVENT_UNC_OK");
+			sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
+		}
+		break;
+	case DVB3_EVENT_UNC_ERR:
+		if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
+			client->event_unc_state = DVB3_EVENT_UNC_ERR;
+			sms_debug("DVB3_EVENT_UNC_ERR");
+			sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
+		}
+		break;
+
+	default:
+		sms_err("Unknown dvb3 api event");
+		break;
+	}
+}
+
+
+static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
+				   struct SMSHOSTLIB_STATISTICS_ST *p)
+{
+	if (sms_dbg & 2) {
+		printk(KERN_DEBUG "Reserved = %d", p->Reserved);
+		printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
+		printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
+		printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
+		printk(KERN_DEBUG "SNR = %d", p->SNR);
+		printk(KERN_DEBUG "BER = %d", p->BER);
+		printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC);
+		printk(KERN_DEBUG "TS_PER = %d", p->TS_PER);
+		printk(KERN_DEBUG "MFER = %d", p->MFER);
+		printk(KERN_DEBUG "RSSI = %d", p->RSSI);
+		printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
+		printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
+		printk(KERN_DEBUG "Frequency = %d", p->Frequency);
+		printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
+		printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
+		printk(KERN_DEBUG "ModemState = %d", p->ModemState);
+		printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
+		printk(KERN_DEBUG "CodeRate = %d", p->CodeRate);
+		printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate);
+		printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy);
+		printk(KERN_DEBUG "Constellation = %d", p->Constellation);
+		printk(KERN_DEBUG "BurstSize = %d", p->BurstSize);
+		printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration);
+		printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime);
+		printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime);
+		printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows);
+		printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols);
+		printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols);
+		printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets);
+		printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets);
+		printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs);
+		printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs);
+		printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs);
+		printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount);
+		printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount);
+		printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
+		printk(KERN_DEBUG "PreBER = %d", p->PreBER);
+		printk(KERN_DEBUG "CellId = %d", p->CellId);
+		printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP);
+		printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP);
+		printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived);
+	}
+
+	pReceptionData->IsDemodLocked = p->IsDemodLocked;
+
+	pReceptionData->SNR = p->SNR;
+	pReceptionData->BER = p->BER;
+	pReceptionData->BERErrorCount = p->BERErrorCount;
+	pReceptionData->InBandPwr = p->InBandPwr;
+	pReceptionData->ErrorTSPackets = p->ErrorTSPackets;
+};
+
+
+static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
+				    struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
+{
+	int i;
+
+	if (sms_dbg & 2) {
+		printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
+		printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
+		printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
+		printk(KERN_DEBUG "SNR = %d", p->SNR);
+		printk(KERN_DEBUG "RSSI = %d", p->RSSI);
+		printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
+		printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
+		printk(KERN_DEBUG "Frequency = %d", p->Frequency);
+		printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
+		printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
+		printk(KERN_DEBUG "ModemState = %d", p->ModemState);
+		printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
+		printk(KERN_DEBUG "SystemType = %d", p->SystemType);
+		printk(KERN_DEBUG "PartialReception = %d", p->PartialReception);
+		printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers);
+		printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
+
+		for (i = 0; i < 3; i++) {
+			printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate);
+			printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation);
+			printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER);
+			printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount);
+			printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount);
+			printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER);
+			printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER);
+			printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets);
+			printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets);
+			printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI);
+			printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments);
+			printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors);
+		}
+	}
+
+	pReceptionData->IsDemodLocked = p->IsDemodLocked;
+
+	pReceptionData->SNR = p->SNR;
+	pReceptionData->InBandPwr = p->InBandPwr;
+
+	pReceptionData->ErrorTSPackets = 0;
+	pReceptionData->BER = 0;
+	pReceptionData->BERErrorCount = 0;
+	for (i = 0; i < 3; i++) {
+		pReceptionData->BER += p->LayerInfo[i].BER;
+		pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount;
+		pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets;
+	}
+}
+
+static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
+{
+	struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
+	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
+			+ cb->offset);
+	u32 *pMsgData = (u32 *) phdr + 1;
+	/*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
+	bool is_status_update = false;
+
+	smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);
+
+	switch (phdr->msgType) {
+	case MSG_SMS_DVBT_BDA_DATA:
+		dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),
+				 cb->size - sizeof(struct SmsMsgHdr_ST));
+		break;
+
+	case MSG_SMS_RF_TUNE_RES:
+	case MSG_SMS_ISDBT_TUNE_RES:
+		complete(&client->tune_done);
+		break;
+
+	case MSG_SMS_SIGNAL_DETECTED_IND:
+		sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
+		client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;
+		is_status_update = true;
+		break;
+
+	case MSG_SMS_NO_SIGNAL_IND:
+		sms_info("MSG_SMS_NO_SIGNAL_IND");
+		client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;
+		is_status_update = true;
+		break;
+
+	case MSG_SMS_TRANSMISSION_IND: {
+		sms_info("MSG_SMS_TRANSMISSION_IND");
+
+		pMsgData++;
+		memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
+				sizeof(struct TRANSMISSION_STATISTICS_S));
+
+		/* Mo need to correct guard interval
+		 * (as opposed to old statistics message).
+		 */
+		CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);
+		CORRECT_STAT_TRANSMISSON_MODE(
+				client->sms_stat_dvb.TransmissionData);
+		is_status_update = true;
+		break;
+	}
+	case MSG_SMS_HO_PER_SLICES_IND: {
+		struct RECEPTION_STATISTICS_S *pReceptionData =
+				&client->sms_stat_dvb.ReceptionData;
+		struct SRVM_SIGNAL_STATUS_S SignalStatusData;
+
+		/*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
+		pMsgData++;
+		SignalStatusData.result = pMsgData[0];
+		SignalStatusData.snr = pMsgData[1];
+		SignalStatusData.inBandPower = (s32) pMsgData[2];
+		SignalStatusData.tsPackets = pMsgData[3];
+		SignalStatusData.etsPackets = pMsgData[4];
+		SignalStatusData.constellation = pMsgData[5];
+		SignalStatusData.hpCode = pMsgData[6];
+		SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;
+		SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;
+		SignalStatusData.cellId = pMsgData[9] & 0xFFFF;
+		SignalStatusData.reason = pMsgData[10];
+		SignalStatusData.requestId = pMsgData[11];
+		pReceptionData->IsRfLocked = pMsgData[16];
+		pReceptionData->IsDemodLocked = pMsgData[17];
+		pReceptionData->ModemState = pMsgData[12];
+		pReceptionData->SNR = pMsgData[1];
+		pReceptionData->BER = pMsgData[13];
+		pReceptionData->RSSI = pMsgData[14];
+		CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);
+
+		pReceptionData->InBandPwr = (s32) pMsgData[2];
+		pReceptionData->CarrierOffset = (s32) pMsgData[15];
+		pReceptionData->TotalTSPackets = pMsgData[3];
+		pReceptionData->ErrorTSPackets = pMsgData[4];
+
+		/* TS PER */
+		if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
+				> 0) {
+			pReceptionData->TS_PER = (SignalStatusData.etsPackets
+					* 100) / (SignalStatusData.tsPackets
+					+ SignalStatusData.etsPackets);
+		} else {
+			pReceptionData->TS_PER = 0;
+		}
+
+		pReceptionData->BERBitCount = pMsgData[18];
+		pReceptionData->BERErrorCount = pMsgData[19];
+
+		pReceptionData->MRC_SNR = pMsgData[20];
+		pReceptionData->MRC_InBandPwr = pMsgData[21];
+		pReceptionData->MRC_RSSI = pMsgData[22];
+
+		is_status_update = true;
+		break;
+	}
+	case MSG_SMS_GET_STATISTICS_RES: {
+		union {
+			struct SMSHOSTLIB_STATISTICS_ISDBT_ST  isdbt;
+			struct SmsMsgStatisticsInfo_ST         dvb;
+		} *p = (void *) (phdr + 1);
+		struct RECEPTION_STATISTICS_S *pReceptionData =
+				&client->sms_stat_dvb.ReceptionData;
+
+		sms_info("MSG_SMS_GET_STATISTICS_RES");
+
+		is_status_update = true;
+
+		switch (smscore_get_device_mode(client->coredev)) {
+		case DEVICE_MODE_ISDBT:
+		case DEVICE_MODE_ISDBT_BDA:
+			smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt);
+			break;
+		default:
+			smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat);
+		}
+		if (!pReceptionData->IsDemodLocked) {
+			pReceptionData->SNR = 0;
+			pReceptionData->BER = 0;
+			pReceptionData->BERErrorCount = 0;
+			pReceptionData->InBandPwr = 0;
+			pReceptionData->ErrorTSPackets = 0;
+		}
+
+		complete(&client->tune_done);
+		break;
+	}
+	default:
+		sms_info("Unhandled message %d", phdr->msgType);
+
+	}
+	smscore_putbuffer(client->coredev, cb);
+
+	if (is_status_update) {
+		if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {
+			client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER
+				| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+			sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
+			if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets
+					== 0)
+				sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
+			else
+				sms_board_dvb3_event(client,
+						DVB3_EVENT_UNC_ERR);
+
+		} else {
+			if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
+				client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
+			else
+				client->fe_status = 0;
+			sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
+		}
+	}
+
+	return 0;
+}
+
+static void smsdvb_unregister_client(struct smsdvb_client_t *client)
+{
+	/* must be called under clientslock */
+
+	list_del(&client->entry);
+
+	smscore_unregister_client(client->smsclient);
+	dvb_unregister_frontend(&client->frontend);
+	dvb_dmxdev_release(&client->dmxdev);
+	dvb_dmx_release(&client->demux);
+	dvb_unregister_adapter(&client->adapter);
+	kfree(client);
+}
+
+static void smsdvb_onremove(void *context)
+{
+	kmutex_lock(&g_smsdvb_clientslock);
+
+	smsdvb_unregister_client((struct smsdvb_client_t *) context);
+
+	kmutex_unlock(&g_smsdvb_clientslock);
+}
+
+static int smsdvb_start_feed(struct dvb_demux_feed *feed)
+{
+	struct smsdvb_client_t *client =
+		container_of(feed->demux, struct smsdvb_client_t, demux);
+	struct SmsMsgData_ST PidMsg;
+
+	sms_debug("add pid %d(%x)",
+		  feed->pid, feed->pid);
+
+	PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+	PidMsg.xMsgHeader.msgDstId = HIF_TASK;
+	PidMsg.xMsgHeader.msgFlags = 0;
+	PidMsg.xMsgHeader.msgType  = MSG_SMS_ADD_PID_FILTER_REQ;
+	PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
+	PidMsg.msgData[0] = feed->pid;
+
+	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
+	return smsclient_sendrequest(client->smsclient,
+				     &PidMsg, sizeof(PidMsg));
+}
+
+static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
+{
+	struct smsdvb_client_t *client =
+		container_of(feed->demux, struct smsdvb_client_t, demux);
+	struct SmsMsgData_ST PidMsg;
+
+	sms_debug("remove pid %d(%x)",
+		  feed->pid, feed->pid);
+
+	PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+	PidMsg.xMsgHeader.msgDstId = HIF_TASK;
+	PidMsg.xMsgHeader.msgFlags = 0;
+	PidMsg.xMsgHeader.msgType  = MSG_SMS_REMOVE_PID_FILTER_REQ;
+	PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
+	PidMsg.msgData[0] = feed->pid;
+
+	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
+	return smsclient_sendrequest(client->smsclient,
+				     &PidMsg, sizeof(PidMsg));
+}
+
+static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
+					void *buffer, size_t size,
+					struct completion *completion)
+{
+	int rc;
+
+	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
+	rc = smsclient_sendrequest(client->smsclient, buffer, size);
+	if (rc < 0)
+		return rc;
+
+	return wait_for_completion_timeout(completion,
+					   msecs_to_jiffies(2000)) ?
+						0 : -ETIME;
+}
+
+static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
+{
+	int rc;
+	struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
+				    DVBT_BDA_CONTROL_MSG_ID,
+				    HIF_TASK,
+				    sizeof(struct SmsMsgHdr_ST), 0 };
+
+	rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+					  &client->tune_done);
+
+	return rc;
+}
+
+static inline int led_feedback(struct smsdvb_client_t *client)
+{
+	if (client->fe_status & FE_HAS_LOCK)
+		return sms_board_led_feedback(client->coredev,
+			(client->sms_stat_dvb.ReceptionData.BER
+			== 0) ? SMS_LED_HI : SMS_LED_LO);
+	else
+		return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
+}
+
+static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+{
+	int rc;
+	struct smsdvb_client_t *client;
+	client = container_of(fe, struct smsdvb_client_t, frontend);
+
+	rc = smsdvb_send_statistics_request(client);
+
+	*stat = client->fe_status;
+
+	led_feedback(client);
+
+	return rc;
+}
+
+static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	int rc;
+	struct smsdvb_client_t *client;
+	client = container_of(fe, struct smsdvb_client_t, frontend);
+
+	rc = smsdvb_send_statistics_request(client);
+
+	*ber = client->sms_stat_dvb.ReceptionData.BER;
+
+	led_feedback(client);
+
+	return rc;
+}
+
+static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	int rc;
+
+	struct smsdvb_client_t *client;
+	client = container_of(fe, struct smsdvb_client_t, frontend);
+
+	rc = smsdvb_send_statistics_request(client);
+
+	if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
+		*strength = 0;
+		else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
+			*strength = 100;
+		else
+			*strength =
+				(client->sms_stat_dvb.ReceptionData.InBandPwr
+				+ 95) * 3 / 2;
+
+	led_feedback(client);
+
+	return rc;
+}
+
+static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	int rc;
+	struct smsdvb_client_t *client;
+	client = container_of(fe, struct smsdvb_client_t, frontend);
+
+	rc = smsdvb_send_statistics_request(client);
+
+	*snr = client->sms_stat_dvb.ReceptionData.SNR;
+
+	led_feedback(client);
+
+	return rc;
+}
+
+static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	int rc;
+	struct smsdvb_client_t *client;
+	client = container_of(fe, struct smsdvb_client_t, frontend);
+
+	rc = smsdvb_send_statistics_request(client);
+
+	*ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
+
+	led_feedback(client);
+
+	return rc;
+}
+
+static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
+				    struct dvb_frontend_tune_settings *tune)
+{
+	sms_debug("");
+
+	tune->min_delay_ms = 400;
+	tune->step_size = 250000;
+	tune->max_drift = 0;
+	return 0;
+}
+
+static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+
+	struct {
+		struct SmsMsgHdr_ST	Msg;
+		u32		Data[3];
+	} Msg;
+
+	int ret;
+
+	client->fe_status = FE_HAS_SIGNAL;
+	client->event_fe_state = -1;
+	client->event_unc_state = -1;
+	fe->dtv_property_cache.delivery_system = SYS_DVBT;
+
+	Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+	Msg.Msg.msgDstId = HIF_TASK;
+	Msg.Msg.msgFlags = 0;
+	Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
+	Msg.Msg.msgLength = sizeof(Msg);
+	Msg.Data[0] = c->frequency;
+	Msg.Data[2] = 12000000;
+
+	sms_info("%s: freq %d band %d", __func__, c->frequency,
+		 c->bandwidth_hz);
+
+	switch (c->bandwidth_hz / 1000000) {
+	case 8:
+		Msg.Data[1] = BW_8_MHZ;
+		break;
+	case 7:
+		Msg.Data[1] = BW_7_MHZ;
+		break;
+	case 6:
+		Msg.Data[1] = BW_6_MHZ;
+		break;
+	case 0:
+		return -EOPNOTSUPP;
+	default:
+		return -EINVAL;
+	}
+	/* Disable LNA, if any. An error is returned if no LNA is present */
+	ret = sms_board_lna_control(client->coredev, 0);
+	if (ret == 0) {
+		fe_status_t status;
+
+		/* tune with LNA off at first */
+		ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+						  &client->tune_done);
+
+		smsdvb_read_status(fe, &status);
+
+		if (status & FE_HAS_LOCK)
+			return ret;
+
+		/* previous tune didn't lock - enable LNA and tune again */
+		sms_board_lna_control(client->coredev, 1);
+	}
+
+	return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+					   &client->tune_done);
+}
+
+static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+
+	struct {
+		struct SmsMsgHdr_ST	Msg;
+		u32		Data[4];
+	} Msg;
+
+	fe->dtv_property_cache.delivery_system = SYS_ISDBT;
+
+	Msg.Msg.msgSrcId  = DVBT_BDA_CONTROL_MSG_ID;
+	Msg.Msg.msgDstId  = HIF_TASK;
+	Msg.Msg.msgFlags  = 0;
+	Msg.Msg.msgType   = MSG_SMS_ISDBT_TUNE_REQ;
+	Msg.Msg.msgLength = sizeof(Msg);
+
+	if (c->isdbt_sb_segment_idx == -1)
+		c->isdbt_sb_segment_idx = 0;
+
+	switch (c->isdbt_sb_segment_count) {
+	case 3:
+		Msg.Data[1] = BW_ISDBT_3SEG;
+		break;
+	case 1:
+		Msg.Data[1] = BW_ISDBT_1SEG;
+		break;
+	case 0:	/* AUTO */
+		switch (c->bandwidth_hz / 1000000) {
+		case 8:
+		case 7:
+			c->isdbt_sb_segment_count = 3;
+			Msg.Data[1] = BW_ISDBT_3SEG;
+			break;
+		case 6:
+			c->isdbt_sb_segment_count = 1;
+			Msg.Data[1] = BW_ISDBT_1SEG;
+			break;
+		default: /* Assumes 6 MHZ bw */
+			c->isdbt_sb_segment_count = 1;
+			c->bandwidth_hz = 6000;
+			Msg.Data[1] = BW_ISDBT_1SEG;
+			break;
+		}
+		break;
+	default:
+		sms_info("Segment count %d not supported", c->isdbt_sb_segment_count);
+		return -EINVAL;
+	}
+
+	Msg.Data[0] = c->frequency;
+	Msg.Data[2] = 12000000;
+	Msg.Data[3] = c->isdbt_sb_segment_idx;
+
+	sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,
+		 c->frequency, c->isdbt_sb_segment_count,
+		 c->isdbt_sb_segment_idx);
+
+	return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+					   &client->tune_done);
+}
+
+static int smsdvb_set_frontend(struct dvb_frontend *fe)
+{
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+	struct smscore_device_t *coredev = client->coredev;
+
+	switch (smscore_get_device_mode(coredev)) {
+	case DEVICE_MODE_DVBT:
+	case DEVICE_MODE_DVBT_BDA:
+		return smsdvb_dvbt_set_frontend(fe);
+	case DEVICE_MODE_ISDBT:
+	case DEVICE_MODE_ISDBT_BDA:
+		return smsdvb_isdbt_set_frontend(fe);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int smsdvb_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+	struct smscore_device_t *coredev = client->coredev;
+	struct TRANSMISSION_STATISTICS_S *td =
+		&client->sms_stat_dvb.TransmissionData;
+
+	switch (smscore_get_device_mode(coredev)) {
+	case DEVICE_MODE_DVBT:
+	case DEVICE_MODE_DVBT_BDA:
+		fep->frequency = td->Frequency;
+
+		switch (td->Bandwidth) {
+		case 6:
+			fep->bandwidth_hz = 6000000;
+			break;
+		case 7:
+			fep->bandwidth_hz = 7000000;
+			break;
+		case 8:
+			fep->bandwidth_hz = 8000000;
+			break;
+		}
+
+		switch (td->TransmissionMode) {
+		case 2:
+			fep->transmission_mode = TRANSMISSION_MODE_2K;
+			break;
+		case 8:
+			fep->transmission_mode = TRANSMISSION_MODE_8K;
+		}
+
+		switch (td->GuardInterval) {
+		case 0:
+			fep->guard_interval = GUARD_INTERVAL_1_32;
+			break;
+		case 1:
+			fep->guard_interval = GUARD_INTERVAL_1_16;
+			break;
+		case 2:
+			fep->guard_interval = GUARD_INTERVAL_1_8;
+			break;
+		case 3:
+			fep->guard_interval = GUARD_INTERVAL_1_4;
+			break;
+		}
+
+		switch (td->CodeRate) {
+		case 0:
+			fep->code_rate_HP = FEC_1_2;
+			break;
+		case 1:
+			fep->code_rate_HP = FEC_2_3;
+			break;
+		case 2:
+			fep->code_rate_HP = FEC_3_4;
+			break;
+		case 3:
+			fep->code_rate_HP = FEC_5_6;
+			break;
+		case 4:
+			fep->code_rate_HP = FEC_7_8;
+			break;
+		}
+
+		switch (td->LPCodeRate) {
+		case 0:
+			fep->code_rate_LP = FEC_1_2;
+			break;
+		case 1:
+			fep->code_rate_LP = FEC_2_3;
+			break;
+		case 2:
+			fep->code_rate_LP = FEC_3_4;
+			break;
+		case 3:
+			fep->code_rate_LP = FEC_5_6;
+			break;
+		case 4:
+			fep->code_rate_LP = FEC_7_8;
+			break;
+		}
+
+		switch (td->Constellation) {
+		case 0:
+			fep->modulation = QPSK;
+			break;
+		case 1:
+			fep->modulation = QAM_16;
+			break;
+		case 2:
+			fep->modulation = QAM_64;
+			break;
+		}
+
+		switch (td->Hierarchy) {
+		case 0:
+			fep->hierarchy = HIERARCHY_NONE;
+			break;
+		case 1:
+			fep->hierarchy = HIERARCHY_1;
+			break;
+		case 2:
+			fep->hierarchy = HIERARCHY_2;
+			break;
+		case 3:
+			fep->hierarchy = HIERARCHY_4;
+			break;
+		}
+
+		fep->inversion = INVERSION_AUTO;
+		break;
+	case DEVICE_MODE_ISDBT:
+	case DEVICE_MODE_ISDBT_BDA:
+		fep->frequency = td->Frequency;
+		fep->bandwidth_hz = 6000000;
+		/* todo: retrive the other parameters */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int smsdvb_init(struct dvb_frontend *fe)
+{
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+
+	sms_board_power(client->coredev, 1);
+
+	sms_board_dvb3_event(client, DVB3_EVENT_INIT);
+	return 0;
+}
+
+static int smsdvb_sleep(struct dvb_frontend *fe)
+{
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+
+	sms_board_led_feedback(client->coredev, SMS_LED_OFF);
+	sms_board_power(client->coredev, 0);
+
+	sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
+
+	return 0;
+}
+
+static void smsdvb_release(struct dvb_frontend *fe)
+{
+	/* do nothing */
+}
+
+static struct dvb_frontend_ops smsdvb_fe_ops = {
+	.info = {
+		.name			= "Siano Mobile Digital MDTV Receiver",
+		.frequency_min		= 44250000,
+		.frequency_max		= 867250000,
+		.frequency_stepsize	= 250000,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+			FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_RECOVER |
+			FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.release = smsdvb_release,
+
+	.set_frontend = smsdvb_set_frontend,
+	.get_frontend = smsdvb_get_frontend,
+	.get_tune_settings = smsdvb_get_tune_settings,
+
+	.read_status = smsdvb_read_status,
+	.read_ber = smsdvb_read_ber,
+	.read_signal_strength = smsdvb_read_signal_strength,
+	.read_snr = smsdvb_read_snr,
+	.read_ucblocks = smsdvb_read_ucblocks,
+
+	.init = smsdvb_init,
+	.sleep = smsdvb_sleep,
+};
+
+static int smsdvb_hotplug(struct smscore_device_t *coredev,
+			  struct device *device, int arrival)
+{
+	struct smsclient_params_t params;
+	struct smsdvb_client_t *client;
+	int rc;
+
+	/* device removal handled by onremove callback */
+	if (!arrival)
+		return 0;
+	client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
+	if (!client) {
+		sms_err("kmalloc() failed");
+		return -ENOMEM;
+	}
+
+	/* register dvb adapter */
+	rc = dvb_register_adapter(&client->adapter,
+				  sms_get_board(
+					smscore_get_board_id(coredev))->name,
+				  THIS_MODULE, device, adapter_nr);
+	if (rc < 0) {
+		sms_err("dvb_register_adapter() failed %d", rc);
+		goto adapter_error;
+	}
+
+	/* init dvb demux */
+	client->demux.dmx.capabilities = DMX_TS_FILTERING;
+	client->demux.filternum = 32; /* todo: nova ??? */
+	client->demux.feednum = 32;
+	client->demux.start_feed = smsdvb_start_feed;
+	client->demux.stop_feed = smsdvb_stop_feed;
+
+	rc = dvb_dmx_init(&client->demux);
+	if (rc < 0) {
+		sms_err("dvb_dmx_init failed %d", rc);
+		goto dvbdmx_error;
+	}
+
+	/* init dmxdev */
+	client->dmxdev.filternum = 32;
+	client->dmxdev.demux = &client->demux.dmx;
+	client->dmxdev.capabilities = 0;
+
+	rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
+	if (rc < 0) {
+		sms_err("dvb_dmxdev_init failed %d", rc);
+		goto dmxdev_error;
+	}
+
+	/* init and register frontend */
+	memcpy(&client->frontend.ops, &smsdvb_fe_ops,
+	       sizeof(struct dvb_frontend_ops));
+
+	switch (smscore_get_device_mode(coredev)) {
+	case DEVICE_MODE_DVBT:
+	case DEVICE_MODE_DVBT_BDA:
+		client->frontend.ops.delsys[0] = SYS_DVBT;
+		break;
+	case DEVICE_MODE_ISDBT:
+	case DEVICE_MODE_ISDBT_BDA:
+		client->frontend.ops.delsys[0] = SYS_ISDBT;
+		break;
+	}
+
+	rc = dvb_register_frontend(&client->adapter, &client->frontend);
+	if (rc < 0) {
+		sms_err("frontend registration failed %d", rc);
+		goto frontend_error;
+	}
+
+	params.initial_id = 1;
+	params.data_type = MSG_SMS_DVBT_BDA_DATA;
+	params.onresponse_handler = smsdvb_onresponse;
+	params.onremove_handler = smsdvb_onremove;
+	params.context = client;
+
+	rc = smscore_register_client(coredev, &params, &client->smsclient);
+	if (rc < 0) {
+		sms_err("smscore_register_client() failed %d", rc);
+		goto client_error;
+	}
+
+	client->coredev = coredev;
+
+	init_completion(&client->tune_done);
+
+	kmutex_lock(&g_smsdvb_clientslock);
+
+	list_add(&client->entry, &g_smsdvb_clients);
+
+	kmutex_unlock(&g_smsdvb_clientslock);
+
+	client->event_fe_state = -1;
+	client->event_unc_state = -1;
+	sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
+
+	sms_info("success");
+	sms_board_setup(coredev);
+
+	return 0;
+
+client_error:
+	dvb_unregister_frontend(&client->frontend);
+
+frontend_error:
+	dvb_dmxdev_release(&client->dmxdev);
+
+dmxdev_error:
+	dvb_dmx_release(&client->demux);
+
+dvbdmx_error:
+	dvb_unregister_adapter(&client->adapter);
+
+adapter_error:
+	kfree(client);
+	return rc;
+}
+
+static int __init smsdvb_module_init(void)
+{
+	int rc;
+
+	INIT_LIST_HEAD(&g_smsdvb_clients);
+	kmutex_init(&g_smsdvb_clientslock);
+
+	rc = smscore_register_hotplug(smsdvb_hotplug);
+
+	sms_debug("");
+
+	return rc;
+}
+
+static void __exit smsdvb_module_exit(void)
+{
+	smscore_unregister_hotplug(smsdvb_hotplug);
+
+	kmutex_lock(&g_smsdvb_clientslock);
+
+	while (!list_empty(&g_smsdvb_clients))
+	       smsdvb_unregister_client(
+			(struct smsdvb_client_t *) g_smsdvb_clients.next);
+
+	kmutex_unlock(&g_smsdvb_clientslock);
+}
+
+module_init(smsdvb_module_init);
+module_exit(smsdvb_module_exit);
+
+MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
+MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/siano/smsendian.c b/drivers/media/common/siano/smsendian.c
new file mode 100644
index 0000000..e2657c2
--- /dev/null
+++ b/drivers/media/common/siano/smsendian.c
@@ -0,0 +1,103 @@
+/****************************************************************
+
+ Siano Mobile Silicon, Inc.
+ MDTV receiver kernel modules.
+ Copyright (C) 2006-2009, Uri Shkolnik
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+ ****************************************************************/
+
+#include <linux/export.h>
+#include <asm/byteorder.h>
+
+#include "smsendian.h"
+#include "smscoreapi.h"
+
+void smsendian_handle_tx_message(void *buffer)
+{
+#ifdef __BIG_ENDIAN
+	struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
+	int i;
+	int msgWords;
+
+	switch (msg->xMsgHeader.msgType) {
+	case MSG_SMS_DATA_DOWNLOAD_REQ:
+	{
+		msg->msgData[0] = le32_to_cpu(msg->msgData[0]);
+		break;
+	}
+
+	default:
+		msgWords = (msg->xMsgHeader.msgLength -
+				sizeof(struct SmsMsgHdr_ST))/4;
+
+		for (i = 0; i < msgWords; i++)
+			msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
+
+		break;
+	}
+#endif /* __BIG_ENDIAN */
+}
+EXPORT_SYMBOL_GPL(smsendian_handle_tx_message);
+
+void smsendian_handle_rx_message(void *buffer)
+{
+#ifdef __BIG_ENDIAN
+	struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
+	int i;
+	int msgWords;
+
+	switch (msg->xMsgHeader.msgType) {
+	case MSG_SMS_GET_VERSION_EX_RES:
+	{
+		struct SmsVersionRes_ST *ver =
+			(struct SmsVersionRes_ST *) msg;
+		ver->ChipModel = le16_to_cpu(ver->ChipModel);
+		break;
+	}
+
+	case MSG_SMS_DVBT_BDA_DATA:
+	case MSG_SMS_DAB_CHANNEL:
+	case MSG_SMS_DATA_MSG:
+	{
+		break;
+	}
+
+	default:
+	{
+		msgWords = (msg->xMsgHeader.msgLength -
+				sizeof(struct SmsMsgHdr_ST))/4;
+
+		for (i = 0; i < msgWords; i++)
+			msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
+
+		break;
+	}
+	}
+#endif /* __BIG_ENDIAN */
+}
+EXPORT_SYMBOL_GPL(smsendian_handle_rx_message);
+
+void smsendian_handle_message_header(void *msg)
+{
+#ifdef __BIG_ENDIAN
+	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg;
+
+	phdr->msgType = le16_to_cpu(phdr->msgType);
+	phdr->msgLength = le16_to_cpu(phdr->msgLength);
+	phdr->msgFlags = le16_to_cpu(phdr->msgFlags);
+#endif /* __BIG_ENDIAN */
+}
+EXPORT_SYMBOL_GPL(smsendian_handle_message_header);
diff --git a/drivers/media/common/siano/smsendian.h b/drivers/media/common/siano/smsendian.h
new file mode 100644
index 0000000..1624d6f
--- /dev/null
+++ b/drivers/media/common/siano/smsendian.h
@@ -0,0 +1,32 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2009, Uri Shkolnik
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#ifndef __SMS_ENDIAN_H__
+#define __SMS_ENDIAN_H__
+
+#include <asm/byteorder.h>
+
+extern void smsendian_handle_tx_message(void *buffer);
+extern void smsendian_handle_rx_message(void *buffer);
+extern void smsendian_handle_message_header(void *msg);
+
+#endif /* __SMS_ENDIAN_H__ */
+
diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c
new file mode 100644
index 0000000..37bc5c4
--- /dev/null
+++ b/drivers/media/common/siano/smsir.c
@@ -0,0 +1,114 @@
+/****************************************************************
+
+ Siano Mobile Silicon, Inc.
+ MDTV receiver kernel modules.
+ Copyright (C) 2006-2009, Uri Shkolnik
+
+ Copyright (c) 2010 - Mauro Carvalho Chehab
+	- Ported the driver to use rc-core
+	- IR raw event decoding is now done at rc-core
+	- Code almost re-written
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+ ****************************************************************/
+
+
+#include <linux/types.h>
+#include <linux/input.h>
+
+#include "smscoreapi.h"
+#include "smsir.h"
+#include "sms-cards.h"
+
+#define MODULE_NAME "smsmdtv"
+
+void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
+{
+	int i;
+	const s32 *samples = (const void *)buf;
+
+	for (i = 0; i < len >> 2; i++) {
+		DEFINE_IR_RAW_EVENT(ev);
+
+		ev.duration = abs(samples[i]) * 1000; /* Convert to ns */
+		ev.pulse = (samples[i] > 0) ? false : true;
+
+		ir_raw_event_store(coredev->ir.dev, &ev);
+	}
+	ir_raw_event_handle(coredev->ir.dev);
+}
+
+int sms_ir_init(struct smscore_device_t *coredev)
+{
+	int err;
+	int board_id = smscore_get_board_id(coredev);
+	struct rc_dev *dev;
+
+	sms_log("Allocating rc device");
+	dev = rc_allocate_device();
+	if (!dev) {
+		sms_err("Not enough memory");
+		return -ENOMEM;
+	}
+
+	coredev->ir.controller = 0;	/* Todo: vega/nova SPI number */
+	coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
+	sms_log("IR port %d, timeout %d ms",
+			coredev->ir.controller, coredev->ir.timeout);
+
+	snprintf(coredev->ir.name, sizeof(coredev->ir.name),
+		 "SMS IR (%s)", sms_get_board(board_id)->name);
+
+	strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys));
+	strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys));
+
+	dev->input_name = coredev->ir.name;
+	dev->input_phys = coredev->ir.phys;
+	dev->dev.parent = coredev->device;
+
+#if 0
+	/* TODO: properly initialize the parameters bellow */
+	dev->input_id.bustype = BUS_USB;
+	dev->input_id.version = 1;
+	dev->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+	dev->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+#endif
+
+	dev->priv = coredev;
+	dev->driver_type = RC_DRIVER_IR_RAW;
+	dev->allowed_protos = RC_TYPE_ALL;
+	dev->map_name = sms_get_board(board_id)->rc_codes;
+	dev->driver_name = MODULE_NAME;
+
+	sms_log("Input device (IR) %s is set for key events", dev->input_name);
+
+	err = rc_register_device(dev);
+	if (err < 0) {
+		sms_err("Failed to register device");
+		rc_free_device(dev);
+		return err;
+	}
+
+	coredev->ir.dev = dev;
+	return 0;
+}
+
+void sms_ir_exit(struct smscore_device_t *coredev)
+{
+	if (coredev->ir.dev)
+		rc_unregister_device(coredev->ir.dev);
+
+	sms_log("");
+}
diff --git a/drivers/media/common/siano/smsir.h b/drivers/media/common/siano/smsir.h
new file mode 100644
index 0000000..ae92b3a
--- /dev/null
+++ b/drivers/media/common/siano/smsir.h
@@ -0,0 +1,55 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2009, Uri Shkolnik
+
+ Copyright (c) 2010 - Mauro Carvalho Chehab
+	- Ported the driver to use rc-core
+	- IR raw event decoding is now done at rc-core
+	- Code almost re-written
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#ifndef __SMS_IR_H__
+#define __SMS_IR_H__
+
+#include <linux/input.h>
+#include <media/rc-core.h>
+
+#define IR_DEFAULT_TIMEOUT		100
+
+struct smscore_device_t;
+
+struct ir_t {
+	struct rc_dev *dev;
+	char name[40];
+	char phys[32];
+
+	char *rc_codes;
+	u64 protocol;
+
+	u32 timeout;
+	u32 controller;
+};
+
+int sms_ir_init(struct smscore_device_t *coredev);
+void sms_ir_exit(struct smscore_device_t *coredev);
+void sms_ir_event(struct smscore_device_t *coredev,
+			const char *buf, int len);
+
+#endif /* __SMS_IR_H__ */
+
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
deleted file mode 100644
index 94c6ff7..0000000
--- a/drivers/media/common/tuners/Kconfig
+++ /dev/null
@@ -1,243 +0,0 @@
-config MEDIA_ATTACH
-	bool "Load and attach frontend and tuner driver modules as needed"
-	depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT
-	depends on MODULES
-	default y if !EXPERT
-	help
-	  Remove the static dependency of DVB card drivers on all
-	  frontend modules for all possible card variants. Instead,
-	  allow the card drivers to only load the frontend modules
-	  they require.
-
-	  Also, tuner module will automatically load a tuner driver
-	  when needed, for analog mode.
-
-	  This saves several KBytes of memory.
-
-	  Note: You will need module-init-tools v3.2 or later for this feature.
-
-	  If unsure say Y.
-
-config MEDIA_TUNER
-	tristate
-	depends on (MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT) && I2C
-	default y
-	select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT && EXPERIMENTAL
-	select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT
-	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
-
-config MEDIA_TUNER_CUSTOMISE
-	bool "Customize analog and hybrid tuner modules to build"
-	depends on MEDIA_TUNER
-	default y if EXPERT
-	help
-	  This allows the user to deselect tuner drivers unnecessary
-	  for their hardware from the build. Use this option with care
-	  as deselecting tuner drivers which are in fact necessary will
-	  result in V4L/DVB devices which cannot be tuned due to lack of
-	  driver support
-
-	  If unsure say N.
-
-menu "Customize TV tuners"
-	visible if MEDIA_TUNER_CUSTOMISE
-	depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT
-
-config MEDIA_TUNER_SIMPLE
-	tristate "Simple tuner support"
-	depends on MEDIA_SUPPORT && I2C
-	select MEDIA_TUNER_TDA9887
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to include support for various simple tuners.
-
-config MEDIA_TUNER_TDA8290
-	tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo"
-	depends on MEDIA_SUPPORT && I2C
-	select MEDIA_TUNER_TDA827X
-	select MEDIA_TUNER_TDA18271
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to include support for Philips TDA8290+8275(a) tuner.
-
-config MEDIA_TUNER_TDA827X
-	tristate "Philips TDA827X silicon tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  A DVB-T silicon tuner module. Say Y when you want to support this tuner.
-
-config MEDIA_TUNER_TDA18271
-	tristate "NXP TDA18271 silicon tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  A silicon tuner module. Say Y when you want to support this tuner.
-
-config MEDIA_TUNER_TDA9887
-	tristate "TDA 9885/6/7 analog IF demodulator"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to include support for Philips TDA9885/6/7
-	  analog IF demodulator.
-
-config MEDIA_TUNER_TEA5761
-	tristate "TEA 5761 radio tuner (EXPERIMENTAL)"
-	depends on MEDIA_SUPPORT && I2C
-	depends on EXPERIMENTAL
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to include support for the Philips TEA5761 radio tuner.
-
-config MEDIA_TUNER_TEA5767
-	tristate "TEA 5767 radio tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to include support for the Philips TEA5767 radio tuner.
-
-config MEDIA_TUNER_MT20XX
-	tristate "Microtune 2032 / 2050 tuners"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to include support for the MT2032 / MT2050 tuner.
-
-config MEDIA_TUNER_MT2060
-	tristate "Microtune MT2060 silicon IF tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  A driver for the silicon IF tuner MT2060 from Microtune.
-
-config MEDIA_TUNER_MT2063
-	tristate "Microtune MT2063 silicon IF tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  A driver for the silicon IF tuner MT2063 from Microtune.
-
-config MEDIA_TUNER_MT2266
-	tristate "Microtune MT2266 silicon tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  A driver for the silicon baseband tuner MT2266 from Microtune.
-
-config MEDIA_TUNER_MT2131
-	tristate "Microtune MT2131 silicon tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  A driver for the silicon baseband tuner MT2131 from Microtune.
-
-config MEDIA_TUNER_QT1010
-	tristate "Quantek QT1010 silicon tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  A driver for the silicon tuner QT1010 from Quantek.
-
-config MEDIA_TUNER_XC2028
-	tristate "XCeive xc2028/xc3028 tuners"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to include support for the xc2028/xc3028 tuners.
-
-config MEDIA_TUNER_XC5000
-	tristate "Xceive XC5000 silicon tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  A driver for the silicon tuner XC5000 from Xceive.
-	  This device is only used inside a SiP called together with a
-	  demodulator for now.
-
-config MEDIA_TUNER_XC4000
-	tristate "Xceive XC4000 silicon tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  A driver for the silicon tuner XC4000 from Xceive.
-	  This device is only used inside a SiP called together with a
-	  demodulator for now.
-
-config MEDIA_TUNER_MXL5005S
-	tristate "MaxLinear MSL5005S silicon tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  A driver for the silicon tuner MXL5005S from MaxLinear.
-
-config MEDIA_TUNER_MXL5007T
-	tristate "MaxLinear MxL5007T silicon tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  A driver for the silicon tuner MxL5007T from MaxLinear.
-
-config MEDIA_TUNER_MC44S803
-	tristate "Freescale MC44S803 Low Power CMOS Broadband tuners"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to support the Freescale MC44S803 based tuners
-
-config MEDIA_TUNER_MAX2165
-	tristate "Maxim MAX2165 silicon tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  A driver for the silicon tuner MAX2165 from Maxim.
-
-config MEDIA_TUNER_TDA18218
-	tristate "NXP TDA18218 silicon tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  NXP TDA18218 silicon tuner driver.
-
-config MEDIA_TUNER_FC0011
-	tristate "Fitipower FC0011 silicon tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  Fitipower FC0011 silicon tuner driver.
-
-config MEDIA_TUNER_FC0012
-	tristate "Fitipower FC0012 silicon tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  Fitipower FC0012 silicon tuner driver.
-
-config MEDIA_TUNER_FC0013
-	tristate "Fitipower FC0013 silicon tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  Fitipower FC0013 silicon tuner driver.
-
-config MEDIA_TUNER_TDA18212
-	tristate "NXP TDA18212 silicon tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  NXP TDA18212 silicon tuner driver.
-
-config MEDIA_TUNER_TUA9001
-	tristate "Infineon TUA 9001 silicon tuner"
-	depends on MEDIA_SUPPORT && I2C
-	default m if MEDIA_TUNER_CUSTOMISE
-	help
-	  Infineon TUA 9001 silicon tuner driver.
-endmenu
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile
deleted file mode 100644
index 891b80e..0000000
--- a/drivers/media/common/tuners/Makefile
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Makefile for common V4L/DVB tuners
-#
-
-tda18271-objs := tda18271-maps.o tda18271-common.o tda18271-fe.o
-
-obj-$(CONFIG_MEDIA_TUNER_XC2028) += tuner-xc2028.o
-obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-simple.o
-# tuner-types will be merged into tuner-simple, in the future
-obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-types.o
-obj-$(CONFIG_MEDIA_TUNER_MT20XX) += mt20xx.o
-obj-$(CONFIG_MEDIA_TUNER_TDA8290) += tda8290.o
-obj-$(CONFIG_MEDIA_TUNER_TEA5767) += tea5767.o
-obj-$(CONFIG_MEDIA_TUNER_TEA5761) += tea5761.o
-obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o
-obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o
-obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o
-obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o
-obj-$(CONFIG_MEDIA_TUNER_XC4000) += xc4000.o
-obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o
-obj-$(CONFIG_MEDIA_TUNER_MT2063) += mt2063.o
-obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o
-obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o
-obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o
-obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o
-obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
-obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
-obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
-obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
-obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
-obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o
-obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
-obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
-obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o
-
-ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
-ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/common/tuners/fc0011.c b/drivers/media/common/tuners/fc0011.c
deleted file mode 100644
index e488254..0000000
--- a/drivers/media/common/tuners/fc0011.c
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Fitipower FC0011 tuner driver
- *
- * Copyright (C) 2012 Michael Buesch <m@bues.ch>
- *
- * Derived from FC0012 tuner driver:
- * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "fc0011.h"
-
-
-/* Tuner registers */
-enum {
-	FC11_REG_0,
-	FC11_REG_FA,		/* FA */
-	FC11_REG_FP,		/* FP */
-	FC11_REG_XINHI,		/* XIN high 8 bit */
-	FC11_REG_XINLO,		/* XIN low 8 bit */
-	FC11_REG_VCO,		/* VCO */
-	FC11_REG_VCOSEL,	/* VCO select */
-	FC11_REG_7,		/* Unknown tuner reg 7 */
-	FC11_REG_8,		/* Unknown tuner reg 8 */
-	FC11_REG_9,
-	FC11_REG_10,		/* Unknown tuner reg 10 */
-	FC11_REG_11,		/* Unknown tuner reg 11 */
-	FC11_REG_12,
-	FC11_REG_RCCAL,		/* RC calibrate */
-	FC11_REG_VCOCAL,	/* VCO calibrate */
-	FC11_REG_15,
-	FC11_REG_16,		/* Unknown tuner reg 16 */
-	FC11_REG_17,
-
-	FC11_NR_REGS,		/* Number of registers */
-};
-
-enum FC11_REG_VCOSEL_bits {
-	FC11_VCOSEL_2		= 0x08, /* VCO select 2 */
-	FC11_VCOSEL_1		= 0x10, /* VCO select 1 */
-	FC11_VCOSEL_CLKOUT	= 0x20, /* Fix clock out */
-	FC11_VCOSEL_BW7M	= 0x40, /* 7MHz bw */
-	FC11_VCOSEL_BW6M	= 0x80, /* 6MHz bw */
-};
-
-enum FC11_REG_RCCAL_bits {
-	FC11_RCCAL_FORCE	= 0x10, /* force */
-};
-
-enum FC11_REG_VCOCAL_bits {
-	FC11_VCOCAL_RUN		= 0,	/* VCO calibration run */
-	FC11_VCOCAL_VALUEMASK	= 0x3F,	/* VCO calibration value mask */
-	FC11_VCOCAL_OK		= 0x40,	/* VCO calibration Ok */
-	FC11_VCOCAL_RESET	= 0x80, /* VCO calibration reset */
-};
-
-
-struct fc0011_priv {
-	struct i2c_adapter *i2c;
-	u8 addr;
-
-	u32 frequency;
-	u32 bandwidth;
-};
-
-
-static int fc0011_writereg(struct fc0011_priv *priv, u8 reg, u8 val)
-{
-	u8 buf[2] = { reg, val };
-	struct i2c_msg msg = { .addr = priv->addr,
-		.flags = 0, .buf = buf, .len = 2 };
-
-	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
-		dev_err(&priv->i2c->dev,
-			"I2C write reg failed, reg: %02x, val: %02x\n",
-			reg, val);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int fc0011_readreg(struct fc0011_priv *priv, u8 reg, u8 *val)
-{
-	u8 dummy;
-	struct i2c_msg msg[2] = {
-		{ .addr = priv->addr,
-		  .flags = 0, .buf = &reg, .len = 1 },
-		{ .addr = priv->addr,
-		  .flags = I2C_M_RD, .buf = val ? : &dummy, .len = 1 },
-	};
-
-	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
-		dev_err(&priv->i2c->dev,
-			"I2C read failed, reg: %02x\n", reg);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int fc0011_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-
-	return 0;
-}
-
-static int fc0011_init(struct dvb_frontend *fe)
-{
-	struct fc0011_priv *priv = fe->tuner_priv;
-	int err;
-
-	if (WARN_ON(!fe->callback))
-		return -EINVAL;
-
-	err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
-			   FC0011_FE_CALLBACK_POWER, priv->addr);
-	if (err) {
-		dev_err(&priv->i2c->dev, "Power-on callback failed\n");
-		return err;
-	}
-	err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
-			   FC0011_FE_CALLBACK_RESET, priv->addr);
-	if (err) {
-		dev_err(&priv->i2c->dev, "Reset callback failed\n");
-		return err;
-	}
-
-	return 0;
-}
-
-/* Initiate VCO calibration */
-static int fc0011_vcocal_trigger(struct fc0011_priv *priv)
-{
-	int err;
-
-	err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RESET);
-	if (err)
-		return err;
-	err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN);
-	if (err)
-		return err;
-
-	return 0;
-}
-
-/* Read VCO calibration value */
-static int fc0011_vcocal_read(struct fc0011_priv *priv, u8 *value)
-{
-	int err;
-
-	err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN);
-	if (err)
-		return err;
-	usleep_range(10000, 20000);
-	err = fc0011_readreg(priv, FC11_REG_VCOCAL, value);
-	if (err)
-		return err;
-
-	return 0;
-}
-
-static int fc0011_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct fc0011_priv *priv = fe->tuner_priv;
-	int err;
-	unsigned int i, vco_retries;
-	u32 freq = p->frequency / 1000;
-	u32 bandwidth = p->bandwidth_hz / 1000;
-	u32 fvco, xin, xdiv, xdivr;
-	u16 frac;
-	u8 fa, fp, vco_sel, vco_cal;
-	u8 regs[FC11_NR_REGS] = { };
-
-	regs[FC11_REG_7] = 0x0F;
-	regs[FC11_REG_8] = 0x3E;
-	regs[FC11_REG_10] = 0xB8;
-	regs[FC11_REG_11] = 0x80;
-	regs[FC11_REG_RCCAL] = 0x04;
-	err = fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]);
-	err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]);
-	err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]);
-	err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]);
-	err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
-	if (err)
-		return -EIO;
-
-	/* Set VCO freq and VCO div */
-	if (freq < 54000) {
-		fvco = freq * 64;
-		regs[FC11_REG_VCO] = 0x82;
-	} else if (freq < 108000) {
-		fvco = freq * 32;
-		regs[FC11_REG_VCO] = 0x42;
-	} else if (freq < 216000) {
-		fvco = freq * 16;
-		regs[FC11_REG_VCO] = 0x22;
-	} else if (freq < 432000) {
-		fvco = freq * 8;
-		regs[FC11_REG_VCO] = 0x12;
-	} else {
-		fvco = freq * 4;
-		regs[FC11_REG_VCO] = 0x0A;
-	}
-
-	/* Calc XIN. The PLL reference frequency is 18 MHz. */
-	xdiv = fvco / 18000;
-	frac = fvco - xdiv * 18000;
-	frac = (frac << 15) / 18000;
-	if (frac >= 16384)
-		frac += 32786;
-	if (!frac)
-		xin = 0;
-	else if (frac < 511)
-		xin = 512;
-	else if (frac < 65026)
-		xin = frac;
-	else
-		xin = 65024;
-	regs[FC11_REG_XINHI] = xin >> 8;
-	regs[FC11_REG_XINLO] = xin;
-
-	/* Calc FP and FA */
-	xdivr = xdiv;
-	if (fvco - xdiv * 18000 >= 9000)
-		xdivr += 1; /* round */
-	fp = xdivr / 8;
-	fa = xdivr - fp * 8;
-	if (fa < 2) {
-		fp -= 1;
-		fa += 8;
-	}
-	if (fp > 0x1F) {
-		fp &= 0x1F;
-		fa &= 0xF;
-	}
-	if (fa >= fp) {
-		dev_warn(&priv->i2c->dev,
-			 "fa %02X >= fp %02X, but trying to continue\n",
-			 (unsigned int)(u8)fa, (unsigned int)(u8)fp);
-	}
-	regs[FC11_REG_FA] = fa;
-	regs[FC11_REG_FP] = fp;
-
-	/* Select bandwidth */
-	switch (bandwidth) {
-	case 8000:
-		break;
-	case 7000:
-		regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW7M;
-		break;
-	default:
-		dev_warn(&priv->i2c->dev, "Unsupported bandwidth %u kHz. "
-			 "Using 6000 kHz.\n",
-			 bandwidth);
-		bandwidth = 6000;
-		/* fallthrough */
-	case 6000:
-		regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW6M;
-		break;
-	}
-
-	/* Pre VCO select */
-	if (fvco < 2320000) {
-		vco_sel = 0;
-		regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
-	} else if (fvco < 3080000) {
-		vco_sel = 1;
-		regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
-		regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
-	} else {
-		vco_sel = 2;
-		regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
-		regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
-	}
-
-	/* Fix for low freqs */
-	if (freq < 45000) {
-		regs[FC11_REG_FA] = 0x6;
-		regs[FC11_REG_FP] = 0x11;
-	}
-
-	/* Clock out fix */
-	regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_CLKOUT;
-
-	/* Write the cached registers */
-	for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) {
-		err = fc0011_writereg(priv, i, regs[i]);
-		if (err)
-			return err;
-	}
-
-	/* VCO calibration */
-	err = fc0011_vcocal_trigger(priv);
-	if (err)
-		return err;
-	err = fc0011_vcocal_read(priv, &vco_cal);
-	if (err)
-		return err;
-	vco_retries = 0;
-	while (!(vco_cal & FC11_VCOCAL_OK) && vco_retries < 3) {
-		/* Reset the tuner and try again */
-		err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
-				   FC0011_FE_CALLBACK_RESET, priv->addr);
-		if (err) {
-			dev_err(&priv->i2c->dev, "Failed to reset tuner\n");
-			return err;
-		}
-		/* Reinit tuner config */
-		err = 0;
-		for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++)
-			err |= fc0011_writereg(priv, i, regs[i]);
-		err |= fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]);
-		err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]);
-		err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]);
-		err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]);
-		err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
-		if (err)
-			return -EIO;
-		/* VCO calibration */
-		err = fc0011_vcocal_trigger(priv);
-		if (err)
-			return err;
-		err = fc0011_vcocal_read(priv, &vco_cal);
-		if (err)
-			return err;
-		vco_retries++;
-	}
-	if (!(vco_cal & FC11_VCOCAL_OK)) {
-		dev_err(&priv->i2c->dev,
-			"Failed to read VCO calibration value (got %02X)\n",
-			(unsigned int)vco_cal);
-		return -EIO;
-	}
-	vco_cal &= FC11_VCOCAL_VALUEMASK;
-
-	switch (vco_sel) {
-	case 0:
-		if (vco_cal < 8) {
-			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
-			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
-			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
-					      regs[FC11_REG_VCOSEL]);
-			if (err)
-				return err;
-			err = fc0011_vcocal_trigger(priv);
-			if (err)
-				return err;
-		} else {
-			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
-			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
-					      regs[FC11_REG_VCOSEL]);
-			if (err)
-				return err;
-		}
-		break;
-	case 1:
-		if (vco_cal < 5) {
-			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
-			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
-			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
-					      regs[FC11_REG_VCOSEL]);
-			if (err)
-				return err;
-			err = fc0011_vcocal_trigger(priv);
-			if (err)
-				return err;
-		} else if (vco_cal <= 48) {
-			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
-			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
-			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
-					      regs[FC11_REG_VCOSEL]);
-			if (err)
-				return err;
-		} else {
-			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
-			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
-					      regs[FC11_REG_VCOSEL]);
-			if (err)
-				return err;
-			err = fc0011_vcocal_trigger(priv);
-			if (err)
-				return err;
-		}
-		break;
-	case 2:
-		if (vco_cal > 53) {
-			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
-			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
-			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
-					      regs[FC11_REG_VCOSEL]);
-			if (err)
-				return err;
-			err = fc0011_vcocal_trigger(priv);
-			if (err)
-				return err;
-		} else {
-			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
-			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
-			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
-					      regs[FC11_REG_VCOSEL]);
-			if (err)
-				return err;
-		}
-		break;
-	}
-	err = fc0011_vcocal_read(priv, NULL);
-	if (err)
-		return err;
-	usleep_range(10000, 50000);
-
-	err = fc0011_readreg(priv, FC11_REG_RCCAL, &regs[FC11_REG_RCCAL]);
-	if (err)
-		return err;
-	regs[FC11_REG_RCCAL] |= FC11_RCCAL_FORCE;
-	err = fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
-	if (err)
-		return err;
-	err = fc0011_writereg(priv, FC11_REG_16, 0xB);
-	if (err)
-		return err;
-
-	dev_dbg(&priv->i2c->dev, "Tuned to "
-		"fa=%02X fp=%02X xin=%02X%02X vco=%02X vcosel=%02X "
-		"vcocal=%02X(%u) bw=%u\n",
-		(unsigned int)regs[FC11_REG_FA],
-		(unsigned int)regs[FC11_REG_FP],
-		(unsigned int)regs[FC11_REG_XINHI],
-		(unsigned int)regs[FC11_REG_XINLO],
-		(unsigned int)regs[FC11_REG_VCO],
-		(unsigned int)regs[FC11_REG_VCOSEL],
-		(unsigned int)vco_cal, vco_retries,
-		(unsigned int)bandwidth);
-
-	priv->frequency = p->frequency;
-	priv->bandwidth = p->bandwidth_hz;
-
-	return 0;
-}
-
-static int fc0011_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct fc0011_priv *priv = fe->tuner_priv;
-
-	*frequency = priv->frequency;
-
-	return 0;
-}
-
-static int fc0011_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	*frequency = 0;
-
-	return 0;
-}
-
-static int fc0011_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	struct fc0011_priv *priv = fe->tuner_priv;
-
-	*bandwidth = priv->bandwidth;
-
-	return 0;
-}
-
-static const struct dvb_tuner_ops fc0011_tuner_ops = {
-	.info = {
-		.name		= "Fitipower FC0011",
-
-		.frequency_min	= 45000000,
-		.frequency_max	= 1000000000,
-	},
-
-	.release		= fc0011_release,
-	.init			= fc0011_init,
-
-	.set_params		= fc0011_set_params,
-
-	.get_frequency		= fc0011_get_frequency,
-	.get_if_frequency	= fc0011_get_if_frequency,
-	.get_bandwidth		= fc0011_get_bandwidth,
-};
-
-struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe,
-				   struct i2c_adapter *i2c,
-				   const struct fc0011_config *config)
-{
-	struct fc0011_priv *priv;
-
-	priv = kzalloc(sizeof(struct fc0011_priv), GFP_KERNEL);
-	if (!priv)
-		return NULL;
-
-	priv->i2c = i2c;
-	priv->addr = config->i2c_address;
-
-	fe->tuner_priv = priv;
-	fe->ops.tuner_ops = fc0011_tuner_ops;
-
-	dev_info(&priv->i2c->dev, "Fitipower FC0011 tuner attached\n");
-
-	return fe;
-}
-EXPORT_SYMBOL(fc0011_attach);
-
-MODULE_DESCRIPTION("Fitipower FC0011 silicon tuner driver");
-MODULE_AUTHOR("Michael Buesch <m@bues.ch>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/fc0011.h b/drivers/media/common/tuners/fc0011.h
deleted file mode 100644
index 0ee581f..0000000
--- a/drivers/media/common/tuners/fc0011.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef LINUX_FC0011_H_
-#define LINUX_FC0011_H_
-
-#include "dvb_frontend.h"
-
-
-/** struct fc0011_config - fc0011 hardware config
- *
- * @i2c_address: I2C bus address.
- */
-struct fc0011_config {
-	u8 i2c_address;
-};
-
-/** enum fc0011_fe_callback_commands - Frontend callbacks
- *
- * @FC0011_FE_CALLBACK_POWER: Power on tuner hardware.
- * @FC0011_FE_CALLBACK_RESET: Request a tuner reset.
- */
-enum fc0011_fe_callback_commands {
-	FC0011_FE_CALLBACK_POWER,
-	FC0011_FE_CALLBACK_RESET,
-};
-
-#if defined(CONFIG_MEDIA_TUNER_FC0011) ||\
-    defined(CONFIG_MEDIA_TUNER_FC0011_MODULE)
-struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe,
-				   struct i2c_adapter *i2c,
-				   const struct fc0011_config *config);
-#else
-static inline
-struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe,
-				   struct i2c_adapter *i2c,
-				   const struct fc0011_config *config)
-{
-	dev_err(&i2c->dev, "fc0011 driver disabled in Kconfig\n");
-	return NULL;
-}
-#endif
-
-#endif /* LINUX_FC0011_H_ */
diff --git a/drivers/media/common/tuners/fc0012-priv.h b/drivers/media/common/tuners/fc0012-priv.h
deleted file mode 100644
index 4577c91..0000000
--- a/drivers/media/common/tuners/fc0012-priv.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Fitipower FC0012 tuner driver - private includes
- *
- * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _FC0012_PRIV_H_
-#define _FC0012_PRIV_H_
-
-#define LOG_PREFIX "fc0012"
-
-#undef err
-#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
-#undef info
-#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
-#undef warn
-#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
-
-struct fc0012_priv {
-	struct i2c_adapter *i2c;
-	u8 addr;
-	u8 dual_master;
-	u8 xtal_freq;
-
-	u32 frequency;
-	u32 bandwidth;
-};
-
-#endif
diff --git a/drivers/media/common/tuners/fc0012.c b/drivers/media/common/tuners/fc0012.c
deleted file mode 100644
index 308135a..0000000
--- a/drivers/media/common/tuners/fc0012.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * Fitipower FC0012 tuner driver
- *
- * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "fc0012.h"
-#include "fc0012-priv.h"
-
-static int fc0012_writereg(struct fc0012_priv *priv, u8 reg, u8 val)
-{
-	u8 buf[2] = {reg, val};
-	struct i2c_msg msg = {
-		.addr = priv->addr, .flags = 0, .buf = buf, .len = 2
-	};
-
-	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
-		err("I2C write reg failed, reg: %02x, val: %02x", reg, val);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val)
-{
-	struct i2c_msg msg[2] = {
-		{ .addr = priv->addr, .flags = 0, .buf = &reg, .len = 1 },
-		{ .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 },
-	};
-
-	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
-		err("I2C read reg failed, reg: %02x", reg);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int fc0012_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static int fc0012_init(struct dvb_frontend *fe)
-{
-	struct fc0012_priv *priv = fe->tuner_priv;
-	int i, ret = 0;
-	unsigned char reg[] = {
-		0x00,	/* dummy reg. 0 */
-		0x05,	/* reg. 0x01 */
-		0x10,	/* reg. 0x02 */
-		0x00,	/* reg. 0x03 */
-		0x00,	/* reg. 0x04 */
-		0x0f,	/* reg. 0x05: may also be 0x0a */
-		0x00,	/* reg. 0x06: divider 2, VCO slow */
-		0x00,	/* reg. 0x07: may also be 0x0f */
-		0xff,	/* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
-			   Loop Bw 1/8 */
-		0x6e,	/* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */
-		0xb8,	/* reg. 0x0a: Disable LO Test Buffer */
-		0x82,	/* reg. 0x0b: Output Clock is same as clock frequency,
-			   may also be 0x83 */
-		0xfc,	/* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */
-		0x02,	/* reg. 0x0d: AGC Not Forcing & LNA Forcing, 0x02 for DVB-T */
-		0x00,	/* reg. 0x0e */
-		0x00,	/* reg. 0x0f */
-		0x00,	/* reg. 0x10: may also be 0x0d */
-		0x00,	/* reg. 0x11 */
-		0x1f,	/* reg. 0x12: Set to maximum gain */
-		0x08,	/* reg. 0x13: Set to Middle Gain: 0x08,
-			   Low Gain: 0x00, High Gain: 0x10, enable IX2: 0x80 */
-		0x00,	/* reg. 0x14 */
-		0x04,	/* reg. 0x15: Enable LNA COMPS */
-	};
-
-	switch (priv->xtal_freq) {
-	case FC_XTAL_27_MHZ:
-	case FC_XTAL_28_8_MHZ:
-		reg[0x07] |= 0x20;
-		break;
-	case FC_XTAL_36_MHZ:
-	default:
-		break;
-	}
-
-	if (priv->dual_master)
-		reg[0x0c] |= 0x02;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
-	for (i = 1; i < sizeof(reg); i++) {
-		ret = fc0012_writereg(priv, i, reg[i]);
-		if (ret)
-			break;
-	}
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-
-	if (ret)
-		err("fc0012_writereg failed: %d", ret);
-
-	return ret;
-}
-
-static int fc0012_sleep(struct dvb_frontend *fe)
-{
-	/* nothing to do here */
-	return 0;
-}
-
-static int fc0012_set_params(struct dvb_frontend *fe)
-{
-	struct fc0012_priv *priv = fe->tuner_priv;
-	int i, ret = 0;
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	u32 freq = p->frequency / 1000;
-	u32 delsys = p->delivery_system;
-	unsigned char reg[7], am, pm, multi, tmp;
-	unsigned long f_vco;
-	unsigned short xtal_freq_khz_2, xin, xdiv;
-	int vco_select = false;
-
-	if (fe->callback) {
-		ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
-			FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1));
-		if (ret)
-			goto exit;
-	}
-
-	switch (priv->xtal_freq) {
-	case FC_XTAL_27_MHZ:
-		xtal_freq_khz_2 = 27000 / 2;
-		break;
-	case FC_XTAL_36_MHZ:
-		xtal_freq_khz_2 = 36000 / 2;
-		break;
-	case FC_XTAL_28_8_MHZ:
-	default:
-		xtal_freq_khz_2 = 28800 / 2;
-		break;
-	}
-
-	/* select frequency divider and the frequency of VCO */
-	if (freq < 37084) {		/* freq * 96 < 3560000 */
-		multi = 96;
-		reg[5] = 0x82;
-		reg[6] = 0x00;
-	} else if (freq < 55625) {	/* freq * 64 < 3560000 */
-		multi = 64;
-		reg[5] = 0x82;
-		reg[6] = 0x02;
-	} else if (freq < 74167) {	/* freq * 48 < 3560000 */
-		multi = 48;
-		reg[5] = 0x42;
-		reg[6] = 0x00;
-	} else if (freq < 111250) {	/* freq * 32 < 3560000 */
-		multi = 32;
-		reg[5] = 0x42;
-		reg[6] = 0x02;
-	} else if (freq < 148334) {	/* freq * 24 < 3560000 */
-		multi = 24;
-		reg[5] = 0x22;
-		reg[6] = 0x00;
-	} else if (freq < 222500) {	/* freq * 16 < 3560000 */
-		multi = 16;
-		reg[5] = 0x22;
-		reg[6] = 0x02;
-	} else if (freq < 296667) {	/* freq * 12 < 3560000 */
-		multi = 12;
-		reg[5] = 0x12;
-		reg[6] = 0x00;
-	} else if (freq < 445000) {	/* freq * 8 < 3560000 */
-		multi = 8;
-		reg[5] = 0x12;
-		reg[6] = 0x02;
-	} else if (freq < 593334) {	/* freq * 6 < 3560000 */
-		multi = 6;
-		reg[5] = 0x0a;
-		reg[6] = 0x00;
-	} else {
-		multi = 4;
-		reg[5] = 0x0a;
-		reg[6] = 0x02;
-	}
-
-	f_vco = freq * multi;
-
-	if (f_vco >= 3060000) {
-		reg[6] |= 0x08;
-		vco_select = true;
-	}
-
-	if (freq >= 45000) {
-		/* From divided value (XDIV) determined the FA and FP value */
-		xdiv = (unsigned short)(f_vco / xtal_freq_khz_2);
-		if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2))
-			xdiv++;
-
-		pm = (unsigned char)(xdiv / 8);
-		am = (unsigned char)(xdiv - (8 * pm));
-
-		if (am < 2) {
-			reg[1] = am + 8;
-			reg[2] = pm - 1;
-		} else {
-			reg[1] = am;
-			reg[2] = pm;
-		}
-	} else {
-		/* fix for frequency less than 45 MHz */
-		reg[1] = 0x06;
-		reg[2] = 0x11;
-	}
-
-	/* fix clock out */
-	reg[6] |= 0x20;
-
-	/* From VCO frequency determines the XIN ( fractional part of Delta
-	   Sigma PLL) and divided value (XDIV) */
-	xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2);
-	xin = (xin << 15) / xtal_freq_khz_2;
-	if (xin >= 16384)
-		xin += 32768;
-
-	reg[3] = xin >> 8;	/* xin with 9 bit resolution */
-	reg[4] = xin & 0xff;
-
-	if (delsys == SYS_DVBT) {
-		reg[6] &= 0x3f;	/* bits 6 and 7 describe the bandwidth */
-		switch (p->bandwidth_hz) {
-		case 6000000:
-			reg[6] |= 0x80;
-			break;
-		case 7000000:
-			reg[6] |= 0x40;
-			break;
-		case 8000000:
-		default:
-			break;
-		}
-	} else {
-		err("%s: modulation type not supported!", __func__);
-		return -EINVAL;
-	}
-
-	/* modified for Realtek demod */
-	reg[5] |= 0x07;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
-	for (i = 1; i <= 6; i++) {
-		ret = fc0012_writereg(priv, i, reg[i]);
-		if (ret)
-			goto exit;
-	}
-
-	/* VCO Calibration */
-	ret = fc0012_writereg(priv, 0x0e, 0x80);
-	if (!ret)
-		ret = fc0012_writereg(priv, 0x0e, 0x00);
-
-	/* VCO Re-Calibration if needed */
-	if (!ret)
-		ret = fc0012_writereg(priv, 0x0e, 0x00);
-
-	if (!ret) {
-		msleep(10);
-		ret = fc0012_readreg(priv, 0x0e, &tmp);
-	}
-	if (ret)
-		goto exit;
-
-	/* vco selection */
-	tmp &= 0x3f;
-
-	if (vco_select) {
-		if (tmp > 0x3c) {
-			reg[6] &= ~0x08;
-			ret = fc0012_writereg(priv, 0x06, reg[6]);
-			if (!ret)
-				ret = fc0012_writereg(priv, 0x0e, 0x80);
-			if (!ret)
-				ret = fc0012_writereg(priv, 0x0e, 0x00);
-		}
-	} else {
-		if (tmp < 0x02) {
-			reg[6] |= 0x08;
-			ret = fc0012_writereg(priv, 0x06, reg[6]);
-			if (!ret)
-				ret = fc0012_writereg(priv, 0x0e, 0x80);
-			if (!ret)
-				ret = fc0012_writereg(priv, 0x0e, 0x00);
-		}
-	}
-
-	priv->frequency = p->frequency;
-	priv->bandwidth = p->bandwidth_hz;
-
-exit:
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-	if (ret)
-		warn("%s: failed: %d", __func__, ret);
-	return ret;
-}
-
-static int fc0012_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct fc0012_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-	return 0;
-}
-
-static int fc0012_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	/* CHECK: always ? */
-	*frequency = 0;
-	return 0;
-}
-
-static int fc0012_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	struct fc0012_priv *priv = fe->tuner_priv;
-	*bandwidth = priv->bandwidth;
-	return 0;
-}
-
-#define INPUT_ADC_LEVEL	-8
-
-static int fc0012_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct fc0012_priv *priv = fe->tuner_priv;
-	int ret;
-	unsigned char tmp;
-	int int_temp, lna_gain, int_lna, tot_agc_gain, power;
-	const int fc0012_lna_gain_table[] = {
-		/* low gain */
-		-63, -58, -99, -73,
-		-63, -65, -54, -60,
-		/* middle gain */
-		 71,  70,  68,  67,
-		 65,  63,  61,  58,
-		/* high gain */
-		197, 191, 188, 186,
-		184, 182, 181, 179,
-	};
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
-	ret = fc0012_writereg(priv, 0x12, 0x00);
-	if (ret)
-		goto err;
-
-	ret = fc0012_readreg(priv, 0x12, &tmp);
-	if (ret)
-		goto err;
-	int_temp = tmp;
-
-	ret = fc0012_readreg(priv, 0x13, &tmp);
-	if (ret)
-		goto err;
-	lna_gain = tmp & 0x1f;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-
-	if (lna_gain < ARRAY_SIZE(fc0012_lna_gain_table)) {
-		int_lna = fc0012_lna_gain_table[lna_gain];
-		tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 +
-				(int_temp & 0x1f)) * 2;
-		power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10;
-
-		if (power >= 45)
-			*strength = 255;	/* 100% */
-		else if (power < -95)
-			*strength = 0;
-		else
-			*strength = (power + 95) * 255 / 140;
-
-		*strength |= *strength << 8;
-	} else {
-		ret = -1;
-	}
-
-	goto exit;
-
-err:
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-exit:
-	if (ret)
-		warn("%s: failed: %d", __func__, ret);
-	return ret;
-}
-
-static const struct dvb_tuner_ops fc0012_tuner_ops = {
-	.info = {
-		.name           = "Fitipower FC0012",
-
-		.frequency_min  = 37000000,	/* estimate */
-		.frequency_max  = 862000000,	/* estimate */
-		.frequency_step = 0,
-	},
-
-	.release	= fc0012_release,
-
-	.init		= fc0012_init,
-	.sleep		= fc0012_sleep,
-
-	.set_params	= fc0012_set_params,
-
-	.get_frequency	= fc0012_get_frequency,
-	.get_if_frequency = fc0012_get_if_frequency,
-	.get_bandwidth	= fc0012_get_bandwidth,
-
-	.get_rf_strength = fc0012_get_rf_strength,
-};
-
-struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, u8 i2c_address, int dual_master,
-	enum fc001x_xtal_freq xtal_freq)
-{
-	struct fc0012_priv *priv = NULL;
-
-	priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	priv->i2c = i2c;
-	priv->dual_master = dual_master;
-	priv->addr = i2c_address;
-	priv->xtal_freq = xtal_freq;
-
-	info("Fitipower FC0012 successfully attached.");
-
-	fe->tuner_priv = priv;
-
-	memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops,
-		sizeof(struct dvb_tuner_ops));
-
-	return fe;
-}
-EXPORT_SYMBOL(fc0012_attach);
-
-MODULE_DESCRIPTION("Fitipower FC0012 silicon tuner driver");
-MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.6");
diff --git a/drivers/media/common/tuners/fc0012.h b/drivers/media/common/tuners/fc0012.h
deleted file mode 100644
index 4dbd5ef..0000000
--- a/drivers/media/common/tuners/fc0012.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Fitipower FC0012 tuner driver - include
- *
- * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _FC0012_H_
-#define _FC0012_H_
-
-#include "dvb_frontend.h"
-#include "fc001x-common.h"
-
-#if defined(CONFIG_MEDIA_TUNER_FC0012) || \
-	(defined(CONFIG_MEDIA_TUNER_FC0012_MODULE) && defined(MODULE))
-extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
-					struct i2c_adapter *i2c,
-					u8 i2c_address, int dual_master,
-					enum fc001x_xtal_freq xtal_freq);
-#else
-static inline struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
-					struct i2c_adapter *i2c,
-					u8 i2c_address, int dual_master,
-					enum fc001x_xtal_freq xtal_freq)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/common/tuners/fc0013-priv.h b/drivers/media/common/tuners/fc0013-priv.h
deleted file mode 100644
index bfd49de..0000000
--- a/drivers/media/common/tuners/fc0013-priv.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Fitipower FC0013 tuner driver
- *
- * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.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.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef _FC0013_PRIV_H_
-#define _FC0013_PRIV_H_
-
-#define LOG_PREFIX "fc0013"
-
-#undef err
-#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
-#undef info
-#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
-#undef warn
-#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
-
-struct fc0013_priv {
-	struct i2c_adapter *i2c;
-	u8 addr;
-	u8 dual_master;
-	u8 xtal_freq;
-
-	u32 frequency;
-	u32 bandwidth;
-};
-
-#endif
diff --git a/drivers/media/common/tuners/fc0013.c b/drivers/media/common/tuners/fc0013.c
deleted file mode 100644
index bd8f0f1..0000000
--- a/drivers/media/common/tuners/fc0013.c
+++ /dev/null
@@ -1,634 +0,0 @@
-/*
- * Fitipower FC0013 tuner driver
- *
- * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
- * partially based on driver code from Fitipower
- * Copyright (C) 2010 Fitipower Integrated Technology Inc
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include "fc0013.h"
-#include "fc0013-priv.h"
-
-static int fc0013_writereg(struct fc0013_priv *priv, u8 reg, u8 val)
-{
-	u8 buf[2] = {reg, val};
-	struct i2c_msg msg = {
-		.addr = priv->addr, .flags = 0, .buf = buf, .len = 2
-	};
-
-	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
-		err("I2C write reg failed, reg: %02x, val: %02x", reg, val);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int fc0013_readreg(struct fc0013_priv *priv, u8 reg, u8 *val)
-{
-	struct i2c_msg msg[2] = {
-		{ .addr = priv->addr, .flags = 0, .buf = &reg, .len = 1 },
-		{ .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 },
-	};
-
-	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
-		err("I2C read reg failed, reg: %02x", reg);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int fc0013_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static int fc0013_init(struct dvb_frontend *fe)
-{
-	struct fc0013_priv *priv = fe->tuner_priv;
-	int i, ret = 0;
-	unsigned char reg[] = {
-		0x00,	/* reg. 0x00: dummy */
-		0x09,	/* reg. 0x01 */
-		0x16,	/* reg. 0x02 */
-		0x00,	/* reg. 0x03 */
-		0x00,	/* reg. 0x04 */
-		0x17,	/* reg. 0x05 */
-		0x02,	/* reg. 0x06 */
-		0x0a,	/* reg. 0x07: CHECK */
-		0xff,	/* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
-			   Loop Bw 1/8 */
-		0x6f,	/* reg. 0x09: enable LoopThrough */
-		0xb8,	/* reg. 0x0a: Disable LO Test Buffer */
-		0x82,	/* reg. 0x0b: CHECK */
-		0xfc,	/* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */
-		0x01,	/* reg. 0x0d: AGC Not Forcing & LNA Forcing, may need 0x02 */
-		0x00,	/* reg. 0x0e */
-		0x00,	/* reg. 0x0f */
-		0x00,	/* reg. 0x10 */
-		0x00,	/* reg. 0x11 */
-		0x00,	/* reg. 0x12 */
-		0x00,	/* reg. 0x13 */
-		0x50,	/* reg. 0x14: DVB-t High Gain, UHF.
-			   Middle Gain: 0x48, Low Gain: 0x40 */
-		0x01,	/* reg. 0x15 */
-	};
-
-	switch (priv->xtal_freq) {
-	case FC_XTAL_27_MHZ:
-	case FC_XTAL_28_8_MHZ:
-		reg[0x07] |= 0x20;
-		break;
-	case FC_XTAL_36_MHZ:
-	default:
-		break;
-	}
-
-	if (priv->dual_master)
-		reg[0x0c] |= 0x02;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
-	for (i = 1; i < sizeof(reg); i++) {
-		ret = fc0013_writereg(priv, i, reg[i]);
-		if (ret)
-			break;
-	}
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-
-	if (ret)
-		err("fc0013_writereg failed: %d", ret);
-
-	return ret;
-}
-
-static int fc0013_sleep(struct dvb_frontend *fe)
-{
-	/* nothing to do here */
-	return 0;
-}
-
-int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val)
-{
-	struct fc0013_priv *priv = fe->tuner_priv;
-	int ret;
-	u8 rc_cal;
-	int val;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
-	/* push rc_cal value, get rc_cal value */
-	ret = fc0013_writereg(priv, 0x10, 0x00);
-	if (ret)
-		goto error_out;
-
-	/* get rc_cal value */
-	ret = fc0013_readreg(priv, 0x10, &rc_cal);
-	if (ret)
-		goto error_out;
-
-	rc_cal &= 0x0f;
-
-	val = (int)rc_cal + rc_val;
-
-	/* forcing rc_cal */
-	ret = fc0013_writereg(priv, 0x0d, 0x11);
-	if (ret)
-		goto error_out;
-
-	/* modify rc_cal value */
-	if (val > 15)
-		ret = fc0013_writereg(priv, 0x10, 0x0f);
-	else if (val < 0)
-		ret = fc0013_writereg(priv, 0x10, 0x00);
-	else
-		ret = fc0013_writereg(priv, 0x10, (u8)val);
-
-error_out:
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-
-	return ret;
-}
-EXPORT_SYMBOL(fc0013_rc_cal_add);
-
-int fc0013_rc_cal_reset(struct dvb_frontend *fe)
-{
-	struct fc0013_priv *priv = fe->tuner_priv;
-	int ret;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
-	ret = fc0013_writereg(priv, 0x0d, 0x01);
-	if (!ret)
-		ret = fc0013_writereg(priv, 0x10, 0x00);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-
-	return ret;
-}
-EXPORT_SYMBOL(fc0013_rc_cal_reset);
-
-static int fc0013_set_vhf_track(struct fc0013_priv *priv, u32 freq)
-{
-	int ret;
-	u8 tmp;
-
-	ret = fc0013_readreg(priv, 0x1d, &tmp);
-	if (ret)
-		goto error_out;
-	tmp &= 0xe3;
-	if (freq <= 177500) {		/* VHF Track: 7 */
-		ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c);
-	} else if (freq <= 184500) {	/* VHF Track: 6 */
-		ret = fc0013_writereg(priv, 0x1d, tmp | 0x18);
-	} else if (freq <= 191500) {	/* VHF Track: 5 */
-		ret = fc0013_writereg(priv, 0x1d, tmp | 0x14);
-	} else if (freq <= 198500) {	/* VHF Track: 4 */
-		ret = fc0013_writereg(priv, 0x1d, tmp | 0x10);
-	} else if (freq <= 205500) {	/* VHF Track: 3 */
-		ret = fc0013_writereg(priv, 0x1d, tmp | 0x0c);
-	} else if (freq <= 219500) {	/* VHF Track: 2 */
-		ret = fc0013_writereg(priv, 0x1d, tmp | 0x08);
-	} else if (freq < 300000) {	/* VHF Track: 1 */
-		ret = fc0013_writereg(priv, 0x1d, tmp | 0x04);
-	} else {			/* UHF and GPS */
-		ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c);
-	}
-	if (ret)
-		goto error_out;
-error_out:
-	return ret;
-}
-
-static int fc0013_set_params(struct dvb_frontend *fe)
-{
-	struct fc0013_priv *priv = fe->tuner_priv;
-	int i, ret = 0;
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	u32 freq = p->frequency / 1000;
-	u32 delsys = p->delivery_system;
-	unsigned char reg[7], am, pm, multi, tmp;
-	unsigned long f_vco;
-	unsigned short xtal_freq_khz_2, xin, xdiv;
-	int vco_select = false;
-
-	if (fe->callback) {
-		ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
-			FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1));
-		if (ret)
-			goto exit;
-	}
-
-	switch (priv->xtal_freq) {
-	case FC_XTAL_27_MHZ:
-		xtal_freq_khz_2 = 27000 / 2;
-		break;
-	case FC_XTAL_36_MHZ:
-		xtal_freq_khz_2 = 36000 / 2;
-		break;
-	case FC_XTAL_28_8_MHZ:
-	default:
-		xtal_freq_khz_2 = 28800 / 2;
-		break;
-	}
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
-	/* set VHF track */
-	ret = fc0013_set_vhf_track(priv, freq);
-	if (ret)
-		goto exit;
-
-	if (freq < 300000) {
-		/* enable VHF filter */
-		ret = fc0013_readreg(priv, 0x07, &tmp);
-		if (ret)
-			goto exit;
-		ret = fc0013_writereg(priv, 0x07, tmp | 0x10);
-		if (ret)
-			goto exit;
-
-		/* disable UHF & disable GPS */
-		ret = fc0013_readreg(priv, 0x14, &tmp);
-		if (ret)
-			goto exit;
-		ret = fc0013_writereg(priv, 0x14, tmp & 0x1f);
-		if (ret)
-			goto exit;
-	} else if (freq <= 862000) {
-		/* disable VHF filter */
-		ret = fc0013_readreg(priv, 0x07, &tmp);
-		if (ret)
-			goto exit;
-		ret = fc0013_writereg(priv, 0x07, tmp & 0xef);
-		if (ret)
-			goto exit;
-
-		/* enable UHF & disable GPS */
-		ret = fc0013_readreg(priv, 0x14, &tmp);
-		if (ret)
-			goto exit;
-		ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x40);
-		if (ret)
-			goto exit;
-	} else {
-		/* disable VHF filter */
-		ret = fc0013_readreg(priv, 0x07, &tmp);
-		if (ret)
-			goto exit;
-		ret = fc0013_writereg(priv, 0x07, tmp & 0xef);
-		if (ret)
-			goto exit;
-
-		/* disable UHF & enable GPS */
-		ret = fc0013_readreg(priv, 0x14, &tmp);
-		if (ret)
-			goto exit;
-		ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x20);
-		if (ret)
-			goto exit;
-	}
-
-	/* select frequency divider and the frequency of VCO */
-	if (freq < 37084) {		/* freq * 96 < 3560000 */
-		multi = 96;
-		reg[5] = 0x82;
-		reg[6] = 0x00;
-	} else if (freq < 55625) {	/* freq * 64 < 3560000 */
-		multi = 64;
-		reg[5] = 0x02;
-		reg[6] = 0x02;
-	} else if (freq < 74167) {	/* freq * 48 < 3560000 */
-		multi = 48;
-		reg[5] = 0x42;
-		reg[6] = 0x00;
-	} else if (freq < 111250) {	/* freq * 32 < 3560000 */
-		multi = 32;
-		reg[5] = 0x82;
-		reg[6] = 0x02;
-	} else if (freq < 148334) {	/* freq * 24 < 3560000 */
-		multi = 24;
-		reg[5] = 0x22;
-		reg[6] = 0x00;
-	} else if (freq < 222500) {	/* freq * 16 < 3560000 */
-		multi = 16;
-		reg[5] = 0x42;
-		reg[6] = 0x02;
-	} else if (freq < 296667) {	/* freq * 12 < 3560000 */
-		multi = 12;
-		reg[5] = 0x12;
-		reg[6] = 0x00;
-	} else if (freq < 445000) {	/* freq * 8 < 3560000 */
-		multi = 8;
-		reg[5] = 0x22;
-		reg[6] = 0x02;
-	} else if (freq < 593334) {	/* freq * 6 < 3560000 */
-		multi = 6;
-		reg[5] = 0x0a;
-		reg[6] = 0x00;
-	} else if (freq < 950000) {	/* freq * 4 < 3800000 */
-		multi = 4;
-		reg[5] = 0x12;
-		reg[6] = 0x02;
-	} else {
-		multi = 2;
-		reg[5] = 0x0a;
-		reg[6] = 0x02;
-	}
-
-	f_vco = freq * multi;
-
-	if (f_vco >= 3060000) {
-		reg[6] |= 0x08;
-		vco_select = true;
-	}
-
-	if (freq >= 45000) {
-		/* From divided value (XDIV) determined the FA and FP value */
-		xdiv = (unsigned short)(f_vco / xtal_freq_khz_2);
-		if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2))
-			xdiv++;
-
-		pm = (unsigned char)(xdiv / 8);
-		am = (unsigned char)(xdiv - (8 * pm));
-
-		if (am < 2) {
-			reg[1] = am + 8;
-			reg[2] = pm - 1;
-		} else {
-			reg[1] = am;
-			reg[2] = pm;
-		}
-	} else {
-		/* fix for frequency less than 45 MHz */
-		reg[1] = 0x06;
-		reg[2] = 0x11;
-	}
-
-	/* fix clock out */
-	reg[6] |= 0x20;
-
-	/* From VCO frequency determines the XIN ( fractional part of Delta
-	   Sigma PLL) and divided value (XDIV) */
-	xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2);
-	xin = (xin << 15) / xtal_freq_khz_2;
-	if (xin >= 16384)
-		xin += 32768;
-
-	reg[3] = xin >> 8;
-	reg[4] = xin & 0xff;
-
-	if (delsys == SYS_DVBT) {
-		reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */
-		switch (p->bandwidth_hz) {
-		case 6000000:
-			reg[6] |= 0x80;
-			break;
-		case 7000000:
-			reg[6] |= 0x40;
-			break;
-		case 8000000:
-		default:
-			break;
-		}
-	} else {
-		err("%s: modulation type not supported!", __func__);
-		return -EINVAL;
-	}
-
-	/* modified for Realtek demod */
-	reg[5] |= 0x07;
-
-	for (i = 1; i <= 6; i++) {
-		ret = fc0013_writereg(priv, i, reg[i]);
-		if (ret)
-			goto exit;
-	}
-
-	ret = fc0013_readreg(priv, 0x11, &tmp);
-	if (ret)
-		goto exit;
-	if (multi == 64)
-		ret = fc0013_writereg(priv, 0x11, tmp | 0x04);
-	else
-		ret = fc0013_writereg(priv, 0x11, tmp & 0xfb);
-	if (ret)
-		goto exit;
-
-	/* VCO Calibration */
-	ret = fc0013_writereg(priv, 0x0e, 0x80);
-	if (!ret)
-		ret = fc0013_writereg(priv, 0x0e, 0x00);
-
-	/* VCO Re-Calibration if needed */
-	if (!ret)
-		ret = fc0013_writereg(priv, 0x0e, 0x00);
-
-	if (!ret) {
-		msleep(10);
-		ret = fc0013_readreg(priv, 0x0e, &tmp);
-	}
-	if (ret)
-		goto exit;
-
-	/* vco selection */
-	tmp &= 0x3f;
-
-	if (vco_select) {
-		if (tmp > 0x3c) {
-			reg[6] &= ~0x08;
-			ret = fc0013_writereg(priv, 0x06, reg[6]);
-			if (!ret)
-				ret = fc0013_writereg(priv, 0x0e, 0x80);
-			if (!ret)
-				ret = fc0013_writereg(priv, 0x0e, 0x00);
-		}
-	} else {
-		if (tmp < 0x02) {
-			reg[6] |= 0x08;
-			ret = fc0013_writereg(priv, 0x06, reg[6]);
-			if (!ret)
-				ret = fc0013_writereg(priv, 0x0e, 0x80);
-			if (!ret)
-				ret = fc0013_writereg(priv, 0x0e, 0x00);
-		}
-	}
-
-	priv->frequency = p->frequency;
-	priv->bandwidth = p->bandwidth_hz;
-
-exit:
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-	if (ret)
-		warn("%s: failed: %d", __func__, ret);
-	return ret;
-}
-
-static int fc0013_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct fc0013_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-	return 0;
-}
-
-static int fc0013_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	/* always ? */
-	*frequency = 0;
-	return 0;
-}
-
-static int fc0013_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	struct fc0013_priv *priv = fe->tuner_priv;
-	*bandwidth = priv->bandwidth;
-	return 0;
-}
-
-#define INPUT_ADC_LEVEL	-8
-
-static int fc0013_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct fc0013_priv *priv = fe->tuner_priv;
-	int ret;
-	unsigned char tmp;
-	int int_temp, lna_gain, int_lna, tot_agc_gain, power;
-	const int fc0013_lna_gain_table[] = {
-		/* low gain */
-		-63, -58, -99, -73,
-		-63, -65, -54, -60,
-		/* middle gain */
-		 71,  70,  68,  67,
-		 65,  63,  61,  58,
-		/* high gain */
-		197, 191, 188, 186,
-		184, 182, 181, 179,
-	};
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
-	ret = fc0013_writereg(priv, 0x13, 0x00);
-	if (ret)
-		goto err;
-
-	ret = fc0013_readreg(priv, 0x13, &tmp);
-	if (ret)
-		goto err;
-	int_temp = tmp;
-
-	ret = fc0013_readreg(priv, 0x14, &tmp);
-	if (ret)
-		goto err;
-	lna_gain = tmp & 0x1f;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-
-	if (lna_gain < ARRAY_SIZE(fc0013_lna_gain_table)) {
-		int_lna = fc0013_lna_gain_table[lna_gain];
-		tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 +
-				(int_temp & 0x1f)) * 2;
-		power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10;
-
-		if (power >= 45)
-			*strength = 255;	/* 100% */
-		else if (power < -95)
-			*strength = 0;
-		else
-			*strength = (power + 95) * 255 / 140;
-
-		*strength |= *strength << 8;
-	} else {
-		ret = -1;
-	}
-
-	goto exit;
-
-err:
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-exit:
-	if (ret)
-		warn("%s: failed: %d", __func__, ret);
-	return ret;
-}
-
-static const struct dvb_tuner_ops fc0013_tuner_ops = {
-	.info = {
-		.name		= "Fitipower FC0013",
-
-		.frequency_min	= 37000000,	/* estimate */
-		.frequency_max	= 1680000000,	/* CHECK */
-		.frequency_step	= 0,
-	},
-
-	.release	= fc0013_release,
-
-	.init		= fc0013_init,
-	.sleep		= fc0013_sleep,
-
-	.set_params	= fc0013_set_params,
-
-	.get_frequency	= fc0013_get_frequency,
-	.get_if_frequency = fc0013_get_if_frequency,
-	.get_bandwidth	= fc0013_get_bandwidth,
-
-	.get_rf_strength = fc0013_get_rf_strength,
-};
-
-struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, u8 i2c_address, int dual_master,
-	enum fc001x_xtal_freq xtal_freq)
-{
-	struct fc0013_priv *priv = NULL;
-
-	priv = kzalloc(sizeof(struct fc0013_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	priv->i2c = i2c;
-	priv->dual_master = dual_master;
-	priv->addr = i2c_address;
-	priv->xtal_freq = xtal_freq;
-
-	info("Fitipower FC0013 successfully attached.");
-
-	fe->tuner_priv = priv;
-
-	memcpy(&fe->ops.tuner_ops, &fc0013_tuner_ops,
-		sizeof(struct dvb_tuner_ops));
-
-	return fe;
-}
-EXPORT_SYMBOL(fc0013_attach);
-
-MODULE_DESCRIPTION("Fitipower FC0013 silicon tuner driver");
-MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.2");
diff --git a/drivers/media/common/tuners/fc0013.h b/drivers/media/common/tuners/fc0013.h
deleted file mode 100644
index 594efd6..0000000
--- a/drivers/media/common/tuners/fc0013.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Fitipower FC0013 tuner driver
- *
- * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.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.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef _FC0013_H_
-#define _FC0013_H_
-
-#include "dvb_frontend.h"
-#include "fc001x-common.h"
-
-#if defined(CONFIG_MEDIA_TUNER_FC0013) || \
-	(defined(CONFIG_MEDIA_TUNER_FC0013_MODULE) && defined(MODULE))
-extern struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe,
-					struct i2c_adapter *i2c,
-					u8 i2c_address, int dual_master,
-					enum fc001x_xtal_freq xtal_freq);
-extern int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val);
-extern int fc0013_rc_cal_reset(struct dvb_frontend *fe);
-#else
-static inline struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe,
-					struct i2c_adapter *i2c,
-					u8 i2c_address, int dual_master,
-					enum fc001x_xtal_freq xtal_freq)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val)
-{
-	return 0;
-}
-
-static inline int fc0013_rc_cal_reset(struct dvb_frontend *fe)
-{
-	return 0;
-}
-#endif
-
-#endif
diff --git a/drivers/media/common/tuners/fc001x-common.h b/drivers/media/common/tuners/fc001x-common.h
deleted file mode 100644
index 7188181..0000000
--- a/drivers/media/common/tuners/fc001x-common.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Fitipower FC0012 & FC0013 tuner driver - common defines
- *
- * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _FC001X_COMMON_H_
-#define _FC001X_COMMON_H_
-
-enum fc001x_xtal_freq {
-	FC_XTAL_27_MHZ,		/* 27000000 */
-	FC_XTAL_28_8_MHZ,	/* 28800000 */
-	FC_XTAL_36_MHZ,		/* 36000000 */
-};
-
-/*
- * enum fc001x_fe_callback_commands - Frontend callbacks
- *
- * @FC_FE_CALLBACK_VHF_ENABLE: enable VHF or UHF
- */
-enum fc001x_fe_callback_commands {
-	FC_FE_CALLBACK_VHF_ENABLE,
-};
-
-#endif
diff --git a/drivers/media/common/tuners/max2165.c b/drivers/media/common/tuners/max2165.c
deleted file mode 100644
index ba84936..0000000
--- a/drivers/media/common/tuners/max2165.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- *  Driver for Maxim MAX2165 silicon tuner
- *
- *  Copyright (c) 2009 David T. L. Wong <davidtlwong@gmail.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/videodev2.h>
-#include <linux/delay.h>
-#include <linux/dvb/frontend.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-
-#include "max2165.h"
-#include "max2165_priv.h"
-#include "tuner-i2c.h"
-
-#define dprintk(args...) \
-	do { \
-		if (debug) \
-			printk(KERN_DEBUG "max2165: " args); \
-	} while (0)
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-static int max2165_write_reg(struct max2165_priv *priv, u8 reg, u8 data)
-{
-	int ret;
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
-
-	msg.addr = priv->config->i2c_address;
-
-	if (debug >= 2)
-		dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data);
-
-	ret = i2c_transfer(priv->i2c, &msg, 1);
-
-	if (ret != 1)
-		dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
-			__func__, reg, data, ret);
-
-	return (ret != 1) ? -EIO : 0;
-}
-
-static int max2165_read_reg(struct max2165_priv *priv, u8 reg, u8 *p_data)
-{
-	int ret;
-	u8 dev_addr = priv->config->i2c_address;
-
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
-	struct i2c_msg msg[] = {
-		{ .addr = dev_addr, .flags = 0, .buf = b0, .len = 1 },
-		{ .addr = dev_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 },
-	};
-
-	ret = i2c_transfer(priv->i2c, msg, 2);
-	if (ret != 2) {
-		dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret);
-		return -EIO;
-	}
-
-	*p_data = b1[0];
-	if (debug >= 2)
-		dprintk("%s: reg=0x%02X, data=0x%02X\n",
-			__func__, reg, b1[0]);
-	return 0;
-}
-
-static int max2165_mask_write_reg(struct max2165_priv *priv, u8 reg,
-	u8 mask, u8 data)
-{
-	int ret;
-	u8 v;
-
-	data &= mask;
-	ret = max2165_read_reg(priv, reg, &v);
-	if (ret != 0)
-		return ret;
-	v &= ~mask;
-	v |= data;
-	ret = max2165_write_reg(priv, reg, v);
-
-	return ret;
-}
-
-static int max2165_read_rom_table(struct max2165_priv *priv)
-{
-	u8 dat[3];
-	int i;
-
-	for (i = 0; i < 3; i++) {
-		max2165_write_reg(priv, REG_ROM_TABLE_ADDR, i + 1);
-		max2165_read_reg(priv, REG_ROM_TABLE_DATA, &dat[i]);
-	}
-
-	priv->tf_ntch_low_cfg = dat[0] >> 4;
-	priv->tf_ntch_hi_cfg = dat[0] & 0x0F;
-	priv->tf_balun_low_ref = dat[1] & 0x0F;
-	priv->tf_balun_hi_ref = dat[1] >> 4;
-	priv->bb_filter_7mhz_cfg = dat[2] & 0x0F;
-	priv->bb_filter_8mhz_cfg = dat[2] >> 4;
-
-	dprintk("tf_ntch_low_cfg = 0x%X\n", priv->tf_ntch_low_cfg);
-	dprintk("tf_ntch_hi_cfg = 0x%X\n", priv->tf_ntch_hi_cfg);
-	dprintk("tf_balun_low_ref = 0x%X\n", priv->tf_balun_low_ref);
-	dprintk("tf_balun_hi_ref = 0x%X\n", priv->tf_balun_hi_ref);
-	dprintk("bb_filter_7mhz_cfg = 0x%X\n", priv->bb_filter_7mhz_cfg);
-	dprintk("bb_filter_8mhz_cfg = 0x%X\n", priv->bb_filter_8mhz_cfg);
-
-	return 0;
-}
-
-static int max2165_set_osc(struct max2165_priv *priv, u8 osc /*MHz*/)
-{
-	u8 v;
-
-	v = (osc / 2);
-	if (v == 2)
-		v = 0x7;
-	else
-		v -= 8;
-
-	max2165_mask_write_reg(priv, REG_PLL_CFG, 0x07, v);
-
-	return 0;
-}
-
-static int max2165_set_bandwidth(struct max2165_priv *priv, u32 bw)
-{
-	u8 val;
-
-	if (bw == 8000000)
-		val = priv->bb_filter_8mhz_cfg;
-	else
-		val = priv->bb_filter_7mhz_cfg;
-
-	max2165_mask_write_reg(priv, REG_BASEBAND_CTRL, 0xF0, val << 4);
-
-	return 0;
-}
-
-int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction)
-{
-	u32 remainder;
-	u32 q, f = 0;
-	int i;
-
-	if (0 == divisor)
-		return -EINVAL;
-
-	q = dividend / divisor;
-	remainder = dividend - q * divisor;
-
-	for (i = 0; i < 31; i++) {
-		remainder <<= 1;
-		if (remainder >= divisor) {
-			f += 1;
-			remainder -= divisor;
-		}
-		f <<= 1;
-	}
-
-	*quotient = q;
-	*fraction = f;
-
-	return 0;
-}
-
-static int max2165_set_rf(struct max2165_priv *priv, u32 freq)
-{
-	u8 tf;
-	u8 tf_ntch;
-	u32 t;
-	u32 quotient, fraction;
-	int ret;
-
-	/* Set PLL divider according to RF frequency */
-	ret = fixpt_div32(freq / 1000, priv->config->osc_clk * 1000,
-			 &quotient, &fraction);
-	if (ret != 0)
-		return ret;
-
-	/* 20-bit fraction */
-	fraction >>= 12;
-
-	max2165_write_reg(priv, REG_NDIV_INT, quotient);
-	max2165_mask_write_reg(priv, REG_NDIV_FRAC2, 0x0F, fraction >> 16);
-	max2165_write_reg(priv, REG_NDIV_FRAC1, fraction >> 8);
-	max2165_write_reg(priv, REG_NDIV_FRAC0, fraction);
-
-	/* Norch Filter */
-	tf_ntch = (freq < 725000000) ?
-		priv->tf_ntch_low_cfg : priv->tf_ntch_hi_cfg;
-
-	/* Tracking filter balun */
-	t = priv->tf_balun_low_ref;
-	t += (priv->tf_balun_hi_ref - priv->tf_balun_low_ref)
-		* (freq / 1000 - 470000) / (780000 - 470000);
-
-	tf = t;
-	dprintk("tf = %X\n", tf);
-	tf |= tf_ntch << 4;
-
-	max2165_write_reg(priv, REG_TRACK_FILTER, tf);
-
-	return 0;
-}
-
-static void max2165_debug_status(struct max2165_priv *priv)
-{
-	u8 status, autotune;
-	u8 auto_vco_success, auto_vco_active;
-	u8 pll_locked;
-	u8 dc_offset_low, dc_offset_hi;
-	u8 signal_lv_over_threshold;
-	u8 vco, vco_sub_band, adc;
-
-	max2165_read_reg(priv, REG_STATUS, &status);
-	max2165_read_reg(priv, REG_AUTOTUNE, &autotune);
-
-	auto_vco_success = (status >> 6) & 0x01;
-	auto_vco_active = (status >> 5) & 0x01;
-	pll_locked = (status >> 4) & 0x01;
-	dc_offset_low = (status >> 3) & 0x01;
-	dc_offset_hi = (status >> 2) & 0x01;
-	signal_lv_over_threshold = status & 0x01;
-
-	vco = autotune >> 6;
-	vco_sub_band = (autotune >> 3) & 0x7;
-	adc = autotune & 0x7;
-
-	dprintk("auto VCO active: %d, auto VCO success: %d\n",
-		auto_vco_active, auto_vco_success);
-	dprintk("PLL locked: %d\n", pll_locked);
-	dprintk("DC offset low: %d, DC offset high: %d\n",
-		dc_offset_low, dc_offset_hi);
-	dprintk("Signal lvl over threshold: %d\n", signal_lv_over_threshold);
-	dprintk("VCO: %d, VCO Sub-band: %d, ADC: %d\n", vco, vco_sub_band, adc);
-}
-
-static int max2165_set_params(struct dvb_frontend *fe)
-{
-	struct max2165_priv *priv = fe->tuner_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret;
-
-	switch (c->bandwidth_hz) {
-	case 7000000:
-	case 8000000:
-		priv->frequency = c->frequency;
-		break;
-	default:
-		printk(KERN_INFO "MAX2165: bandwidth %d Hz not supported.\n",
-		       c->bandwidth_hz);
-		return -EINVAL;
-	}
-
-	dprintk("%s() frequency=%d\n", __func__, c->frequency);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	max2165_set_bandwidth(priv, c->bandwidth_hz);
-	ret = max2165_set_rf(priv, priv->frequency);
-	mdelay(50);
-	max2165_debug_status(priv);
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	if (ret != 0)
-		return -EREMOTEIO;
-
-	return 0;
-}
-
-static int max2165_get_frequency(struct dvb_frontend *fe, u32 *freq)
-{
-	struct max2165_priv *priv = fe->tuner_priv;
-	dprintk("%s()\n", __func__);
-	*freq = priv->frequency;
-	return 0;
-}
-
-static int max2165_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
-{
-	struct max2165_priv *priv = fe->tuner_priv;
-	dprintk("%s()\n", __func__);
-
-	*bw = priv->bandwidth;
-	return 0;
-}
-
-static int max2165_get_status(struct dvb_frontend *fe, u32 *status)
-{
-	struct max2165_priv *priv = fe->tuner_priv;
-	u16 lock_status = 0;
-
-	dprintk("%s()\n", __func__);
-
-	if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-
-	max2165_debug_status(priv);
-	*status = lock_status;
-
-	if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-
-	return 0;
-}
-
-static int max2165_sleep(struct dvb_frontend *fe)
-{
-	dprintk("%s()\n", __func__);
-	return 0;
-}
-
-static int max2165_init(struct dvb_frontend *fe)
-{
-	struct max2165_priv *priv = fe->tuner_priv;
-	dprintk("%s()\n", __func__);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	/* Setup initial values */
-	/* Fractional Mode on */
-	max2165_write_reg(priv, REG_NDIV_FRAC2, 0x18);
-	/* LNA on */
-	max2165_write_reg(priv, REG_LNA, 0x01);
-	max2165_write_reg(priv, REG_PLL_CFG, 0x7A);
-	max2165_write_reg(priv, REG_TEST, 0x08);
-	max2165_write_reg(priv, REG_SHUTDOWN, 0x40);
-	max2165_write_reg(priv, REG_VCO_CTRL, 0x84);
-	max2165_write_reg(priv, REG_BASEBAND_CTRL, 0xC3);
-	max2165_write_reg(priv, REG_DC_OFFSET_CTRL, 0x75);
-	max2165_write_reg(priv, REG_DC_OFFSET_DAC, 0x00);
-	max2165_write_reg(priv, REG_ROM_TABLE_ADDR, 0x00);
-
-	max2165_set_osc(priv, priv->config->osc_clk);
-
-	max2165_read_rom_table(priv);
-
-	max2165_set_bandwidth(priv, 8000000);
-
-	if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-
-	return 0;
-}
-
-static int max2165_release(struct dvb_frontend *fe)
-{
-	struct max2165_priv *priv = fe->tuner_priv;
-	dprintk("%s()\n", __func__);
-
-	kfree(priv);
-	fe->tuner_priv = NULL;
-
-	return 0;
-}
-
-static const struct dvb_tuner_ops max2165_tuner_ops = {
-	.info = {
-		.name           = "Maxim MAX2165",
-		.frequency_min  = 470000000,
-		.frequency_max  = 780000000,
-		.frequency_step =     50000,
-	},
-
-	.release	   = max2165_release,
-	.init		   = max2165_init,
-	.sleep		   = max2165_sleep,
-
-	.set_params	   = max2165_set_params,
-	.set_analog_params = NULL,
-	.get_frequency	   = max2165_get_frequency,
-	.get_bandwidth	   = max2165_get_bandwidth,
-	.get_status	   = max2165_get_status
-};
-
-struct dvb_frontend *max2165_attach(struct dvb_frontend *fe,
-				   struct i2c_adapter *i2c,
-				   struct max2165_config *cfg)
-{
-	struct max2165_priv *priv = NULL;
-
-	dprintk("%s(%d-%04x)\n", __func__,
-		i2c ? i2c_adapter_id(i2c) : -1,
-		cfg ? cfg->i2c_address : -1);
-
-	priv = kzalloc(sizeof(struct max2165_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	memcpy(&fe->ops.tuner_ops, &max2165_tuner_ops,
-		sizeof(struct dvb_tuner_ops));
-
-	priv->config = cfg;
-	priv->i2c = i2c;
-	fe->tuner_priv = priv;
-
-	max2165_init(fe);
-	max2165_debug_status(priv);
-
-	return fe;
-}
-EXPORT_SYMBOL(max2165_attach);
-
-MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
-MODULE_DESCRIPTION("Maxim MAX2165 silicon tuner driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/max2165.h b/drivers/media/common/tuners/max2165.h
deleted file mode 100644
index c063c36..0000000
--- a/drivers/media/common/tuners/max2165.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  Driver for Maxim MAX2165 silicon tuner
- *
- *  Copyright (c) 2009 David T. L. Wong <davidtlwong@gmail.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __MAX2165_H__
-#define __MAX2165_H__
-
-struct dvb_frontend;
-struct i2c_adapter;
-
-struct max2165_config {
-	u8 i2c_address;
-	u8 osc_clk; /* in MHz, selectable values: 4,16,18,20,22,24,26,28 */
-};
-
-#if defined(CONFIG_MEDIA_TUNER_MAX2165) || \
-    (defined(CONFIG_MEDIA_TUNER_MAX2165_MODULE) && defined(MODULE))
-extern struct dvb_frontend *max2165_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c,
-	struct max2165_config *cfg);
-#else
-static inline struct dvb_frontend *max2165_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c,
-	struct max2165_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/common/tuners/max2165_priv.h b/drivers/media/common/tuners/max2165_priv.h
deleted file mode 100644
index 91bbe02..0000000
--- a/drivers/media/common/tuners/max2165_priv.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *  Driver for Maxim MAX2165 silicon tuner
- *
- *  Copyright (c) 2009 David T. L. Wong <davidtlwong@gmail.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __MAX2165_PRIV_H__
-#define __MAX2165_PRIV_H__
-
-#define REG_NDIV_INT 0x00
-#define REG_NDIV_FRAC2 0x01
-#define REG_NDIV_FRAC1 0x02
-#define REG_NDIV_FRAC0 0x03
-#define REG_TRACK_FILTER 0x04
-#define REG_LNA 0x05
-#define REG_PLL_CFG 0x06
-#define REG_TEST 0x07
-#define REG_SHUTDOWN 0x08
-#define REG_VCO_CTRL 0x09
-#define REG_BASEBAND_CTRL 0x0A
-#define REG_DC_OFFSET_CTRL 0x0B
-#define REG_DC_OFFSET_DAC 0x0C
-#define REG_ROM_TABLE_ADDR 0x0D
-
-/* Read Only Registers */
-#define REG_ROM_TABLE_DATA 0x10
-#define REG_STATUS 0x11
-#define REG_AUTOTUNE 0x12
-
-struct max2165_priv {
-	struct max2165_config *config;
-	struct i2c_adapter *i2c;
-
-	u32 frequency;
-	u32 bandwidth;
-
-	u8 tf_ntch_low_cfg;
-	u8 tf_ntch_hi_cfg;
-	u8 tf_balun_low_ref;
-	u8 tf_balun_hi_ref;
-	u8 bb_filter_7mhz_cfg;
-	u8 bb_filter_8mhz_cfg;
-};
-
-#endif
diff --git a/drivers/media/common/tuners/mc44s803.c b/drivers/media/common/tuners/mc44s803.c
deleted file mode 100644
index 5ddce7e..0000000
--- a/drivers/media/common/tuners/mc44s803.c
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- *  Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
- *
- *  Copyright (c) 2009 Jochen Friedrich <jochen@scram.de>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/dvb/frontend.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-
-#include "mc44s803.h"
-#include "mc44s803_priv.h"
-
-#define mc_printk(level, format, arg...)	\
-	printk(level "mc44s803: " format , ## arg)
-
-/* Writes a single register */
-static int mc44s803_writereg(struct mc44s803_priv *priv, u32 val)
-{
-	u8 buf[3];
-	struct i2c_msg msg = {
-		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 3
-	};
-
-	buf[0] = (val & 0xff0000) >> 16;
-	buf[1] = (val & 0xff00) >> 8;
-	buf[2] = (val & 0xff);
-
-	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
-		mc_printk(KERN_WARNING, "I2C write failed\n");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-/* Reads a single register */
-static int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val)
-{
-	u32 wval;
-	u8 buf[3];
-	int ret;
-	struct i2c_msg msg[] = {
-		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
-		  .buf = buf, .len = 3 },
-	};
-
-	wval = MC44S803_REG_SM(MC44S803_REG_DATAREG, MC44S803_ADDR) |
-	       MC44S803_REG_SM(reg, MC44S803_D);
-
-	ret = mc44s803_writereg(priv, wval);
-	if (ret)
-		return ret;
-
-	if (i2c_transfer(priv->i2c, msg, 1) != 1) {
-		mc_printk(KERN_WARNING, "I2C read failed\n");
-		return -EREMOTEIO;
-	}
-
-	*val = (buf[0] << 16) | (buf[1] << 8) | buf[2];
-
-	return 0;
-}
-
-static int mc44s803_release(struct dvb_frontend *fe)
-{
-	struct mc44s803_priv *priv = fe->tuner_priv;
-
-	fe->tuner_priv = NULL;
-	kfree(priv);
-
-	return 0;
-}
-
-static int mc44s803_init(struct dvb_frontend *fe)
-{
-	struct mc44s803_priv *priv = fe->tuner_priv;
-	u32 val;
-	int err;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-/* Reset chip */
-	val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR) |
-	      MC44S803_REG_SM(1, MC44S803_RS);
-
-	err = mc44s803_writereg(priv, val);
-	if (err)
-		goto exit;
-
-	val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR);
-
-	err = mc44s803_writereg(priv, val);
-	if (err)
-		goto exit;
-
-/* Power Up and Start Osc */
-
-	val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
-	      MC44S803_REG_SM(0xC0, MC44S803_REFOSC) |
-	      MC44S803_REG_SM(1, MC44S803_OSCSEL);
-
-	err = mc44s803_writereg(priv, val);
-	if (err)
-		goto exit;
-
-	val = MC44S803_REG_SM(MC44S803_REG_POWER, MC44S803_ADDR) |
-	      MC44S803_REG_SM(0x200, MC44S803_POWER);
-
-	err = mc44s803_writereg(priv, val);
-	if (err)
-		goto exit;
-
-	msleep(10);
-
-	val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
-	      MC44S803_REG_SM(0x40, MC44S803_REFOSC) |
-	      MC44S803_REG_SM(1, MC44S803_OSCSEL);
-
-	err = mc44s803_writereg(priv, val);
-	if (err)
-		goto exit;
-
-	msleep(20);
-
-/* Setup Mixer */
-
-	val = MC44S803_REG_SM(MC44S803_REG_MIXER, MC44S803_ADDR) |
-	      MC44S803_REG_SM(1, MC44S803_TRI_STATE) |
-	      MC44S803_REG_SM(0x7F, MC44S803_MIXER_RES);
-
-	err = mc44s803_writereg(priv, val);
-	if (err)
-		goto exit;
-
-/* Setup Cirquit Adjust */
-
-	val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
-	      MC44S803_REG_SM(1, MC44S803_G1) |
-	      MC44S803_REG_SM(1, MC44S803_G3) |
-	      MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
-	      MC44S803_REG_SM(1, MC44S803_G6) |
-	      MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
-	      MC44S803_REG_SM(0x3, MC44S803_LP) |
-	      MC44S803_REG_SM(1, MC44S803_CLRF) |
-	      MC44S803_REG_SM(1, MC44S803_CLIF);
-
-	err = mc44s803_writereg(priv, val);
-	if (err)
-		goto exit;
-
-	val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
-	      MC44S803_REG_SM(1, MC44S803_G1) |
-	      MC44S803_REG_SM(1, MC44S803_G3) |
-	      MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
-	      MC44S803_REG_SM(1, MC44S803_G6) |
-	      MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
-	      MC44S803_REG_SM(0x3, MC44S803_LP);
-
-	err = mc44s803_writereg(priv, val);
-	if (err)
-		goto exit;
-
-/* Setup Digtune */
-
-	val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
-	      MC44S803_REG_SM(3, MC44S803_XOD);
-
-	err = mc44s803_writereg(priv, val);
-	if (err)
-		goto exit;
-
-/* Setup AGC */
-
-	val = MC44S803_REG_SM(MC44S803_REG_LNAAGC, MC44S803_ADDR) |
-	      MC44S803_REG_SM(1, MC44S803_AT1) |
-	      MC44S803_REG_SM(1, MC44S803_AT2) |
-	      MC44S803_REG_SM(1, MC44S803_AGC_AN_DIG) |
-	      MC44S803_REG_SM(1, MC44S803_AGC_READ_EN) |
-	      MC44S803_REG_SM(1, MC44S803_LNA0);
-
-	err = mc44s803_writereg(priv, val);
-	if (err)
-		goto exit;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-	return 0;
-
-exit:
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	mc_printk(KERN_WARNING, "I/O Error\n");
-	return err;
-}
-
-static int mc44s803_set_params(struct dvb_frontend *fe)
-{
-	struct mc44s803_priv *priv = fe->tuner_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 r1, r2, n1, n2, lo1, lo2, freq, val;
-	int err;
-
-	priv->frequency = c->frequency;
-
-	r1 = MC44S803_OSC / 1000000;
-	r2 = MC44S803_OSC /  100000;
-
-	n1 = (c->frequency + MC44S803_IF1 + 500000) / 1000000;
-	freq = MC44S803_OSC / r1 * n1;
-	lo1 = ((60 * n1) + (r1 / 2)) / r1;
-	freq = freq - c->frequency;
-
-	n2 = (freq - MC44S803_IF2 + 50000) / 100000;
-	lo2 = ((60 * n2) + (r2 / 2)) / r2;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	val = MC44S803_REG_SM(MC44S803_REG_REFDIV, MC44S803_ADDR) |
-	      MC44S803_REG_SM(r1-1, MC44S803_R1) |
-	      MC44S803_REG_SM(r2-1, MC44S803_R2) |
-	      MC44S803_REG_SM(1, MC44S803_REFBUF_EN);
-
-	err = mc44s803_writereg(priv, val);
-	if (err)
-		goto exit;
-
-	val = MC44S803_REG_SM(MC44S803_REG_LO1, MC44S803_ADDR) |
-	      MC44S803_REG_SM(n1-2, MC44S803_LO1);
-
-	err = mc44s803_writereg(priv, val);
-	if (err)
-		goto exit;
-
-	val = MC44S803_REG_SM(MC44S803_REG_LO2, MC44S803_ADDR) |
-	      MC44S803_REG_SM(n2-2, MC44S803_LO2);
-
-	err = mc44s803_writereg(priv, val);
-	if (err)
-		goto exit;
-
-	val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
-	      MC44S803_REG_SM(1, MC44S803_DA) |
-	      MC44S803_REG_SM(lo1, MC44S803_LO_REF) |
-	      MC44S803_REG_SM(1, MC44S803_AT);
-
-	err = mc44s803_writereg(priv, val);
-	if (err)
-		goto exit;
-
-	val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
-	      MC44S803_REG_SM(2, MC44S803_DA) |
-	      MC44S803_REG_SM(lo2, MC44S803_LO_REF) |
-	      MC44S803_REG_SM(1, MC44S803_AT);
-
-	err = mc44s803_writereg(priv, val);
-	if (err)
-		goto exit;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	return 0;
-
-exit:
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	mc_printk(KERN_WARNING, "I/O Error\n");
-	return err;
-}
-
-static int mc44s803_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct mc44s803_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-	return 0;
-}
-
-static const struct dvb_tuner_ops mc44s803_tuner_ops = {
-	.info = {
-		.name           = "Freescale MC44S803",
-		.frequency_min  =   48000000,
-		.frequency_max  = 1000000000,
-		.frequency_step =     100000,
-	},
-
-	.release       = mc44s803_release,
-	.init          = mc44s803_init,
-	.set_params    = mc44s803_set_params,
-	.get_frequency = mc44s803_get_frequency
-};
-
-/* This functions tries to identify a MC44S803 tuner by reading the ID
-   register. This is hasty. */
-struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
-	 struct i2c_adapter *i2c, struct mc44s803_config *cfg)
-{
-	struct mc44s803_priv *priv;
-	u32 reg;
-	u8 id;
-	int ret;
-
-	reg = 0;
-
-	priv = kzalloc(sizeof(struct mc44s803_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	priv->cfg = cfg;
-	priv->i2c = i2c;
-	priv->fe  = fe;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
-
-	ret = mc44s803_readreg(priv, MC44S803_REG_ID, &reg);
-	if (ret)
-		goto error;
-
-	id = MC44S803_REG_MS(reg, MC44S803_ID);
-
-	if (id != 0x14) {
-		mc_printk(KERN_ERR, "unsupported ID "
-		       "(%x should be 0x14)\n", id);
-		goto error;
-	}
-
-	mc_printk(KERN_INFO, "successfully identified (ID = %x)\n", id);
-	memcpy(&fe->ops.tuner_ops, &mc44s803_tuner_ops,
-	       sizeof(struct dvb_tuner_ops));
-
-	fe->tuner_priv = priv;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
-
-	return fe;
-
-error:
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
-
-	kfree(priv);
-	return NULL;
-}
-EXPORT_SYMBOL(mc44s803_attach);
-
-MODULE_AUTHOR("Jochen Friedrich");
-MODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/mc44s803.h b/drivers/media/common/tuners/mc44s803.h
deleted file mode 100644
index 34f3892..0000000
--- a/drivers/media/common/tuners/mc44s803.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- *  Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
- *
- *  Copyright (c) 2009 Jochen Friedrich <jochen@scram.de>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef MC44S803_H
-#define MC44S803_H
-
-struct dvb_frontend;
-struct i2c_adapter;
-
-struct mc44s803_config {
-	u8 i2c_address;
-	u8 dig_out;
-};
-
-#if defined(CONFIG_MEDIA_TUNER_MC44S803) || \
-    (defined(CONFIG_MEDIA_TUNER_MC44S803_MODULE) && defined(MODULE))
-extern struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
-	 struct i2c_adapter *i2c, struct mc44s803_config *cfg);
-#else
-static inline struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
-	 struct i2c_adapter *i2c, struct mc44s803_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_MEDIA_TUNER_MC44S803 */
-
-#endif
diff --git a/drivers/media/common/tuners/mc44s803_priv.h b/drivers/media/common/tuners/mc44s803_priv.h
deleted file mode 100644
index 14a9278..0000000
--- a/drivers/media/common/tuners/mc44s803_priv.h
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- *  Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
- *
- *  Copyright (c) 2009 Jochen Friedrich <jochen@scram.de>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef MC44S803_PRIV_H
-#define MC44S803_PRIV_H
-
-/* This driver is based on the information available in the datasheet
-   http://www.freescale.com/files/rf_if/doc/data_sheet/MC44S803.pdf
-
-   SPI or I2C Address : 0xc0-0xc6
-
-   Reg.No | Function
-   -------------------------------------------
-       00 | Power Down
-       01 | Reference Oszillator
-       02 | Reference Dividers
-       03 | Mixer and Reference Buffer
-       04 | Reset/Serial Out
-       05 | LO 1
-       06 | LO 2
-       07 | Circuit Adjust
-       08 | Test
-       09 | Digital Tune
-       0A | LNA AGC
-       0B | Data Register Address
-       0C | Regulator Test
-       0D | VCO Test
-       0E | LNA Gain/Input Power
-       0F | ID Bits
-
-*/
-
-#define MC44S803_OSC 26000000	/* 26 MHz */
-#define MC44S803_IF1 1086000000 /* 1086 MHz */
-#define MC44S803_IF2 36125000	/* 36.125 MHz */
-
-#define MC44S803_REG_POWER	0
-#define MC44S803_REG_REFOSC	1
-#define MC44S803_REG_REFDIV	2
-#define MC44S803_REG_MIXER	3
-#define MC44S803_REG_RESET	4
-#define MC44S803_REG_LO1	5
-#define MC44S803_REG_LO2	6
-#define MC44S803_REG_CIRCADJ	7
-#define MC44S803_REG_TEST	8
-#define MC44S803_REG_DIGTUNE	9
-#define MC44S803_REG_LNAAGC	0x0A
-#define MC44S803_REG_DATAREG	0x0B
-#define MC44S803_REG_REGTEST	0x0C
-#define MC44S803_REG_VCOTEST	0x0D
-#define MC44S803_REG_LNAGAIN	0x0E
-#define MC44S803_REG_ID		0x0F
-
-/* Register definitions */
-#define MC44S803_ADDR		0x0F
-#define MC44S803_ADDR_S		0
-/* REG_POWER */
-#define MC44S803_POWER		0xFFFFF0
-#define MC44S803_POWER_S	4
-/* REG_REFOSC */
-#define MC44S803_REFOSC		0x1FF0
-#define MC44S803_REFOSC_S	4
-#define MC44S803_OSCSEL		0x2000
-#define MC44S803_OSCSEL_S	13
-/* REG_REFDIV */
-#define MC44S803_R2		0x1FF0
-#define MC44S803_R2_S		4
-#define MC44S803_REFBUF_EN	0x2000
-#define MC44S803_REFBUF_EN_S	13
-#define MC44S803_R1		0x7C000
-#define MC44S803_R1_S		14
-/* REG_MIXER */
-#define MC44S803_R3		0x70
-#define MC44S803_R3_S		4
-#define MC44S803_MUX3		0x80
-#define MC44S803_MUX3_S		7
-#define MC44S803_MUX4		0x100
-#define MC44S803_MUX4_S		8
-#define MC44S803_OSC_SCR	0x200
-#define MC44S803_OSC_SCR_S	9
-#define MC44S803_TRI_STATE	0x400
-#define MC44S803_TRI_STATE_S	10
-#define MC44S803_BUF_GAIN	0x800
-#define MC44S803_BUF_GAIN_S	11
-#define MC44S803_BUF_IO		0x1000
-#define MC44S803_BUF_IO_S	12
-#define MC44S803_MIXER_RES	0xFE000
-#define MC44S803_MIXER_RES_S	13
-/* REG_RESET */
-#define MC44S803_RS		0x10
-#define MC44S803_RS_S		4
-#define MC44S803_SO		0x20
-#define MC44S803_SO_S		5
-/* REG_LO1 */
-#define MC44S803_LO1		0xFFF0
-#define MC44S803_LO1_S		4
-/* REG_LO2 */
-#define MC44S803_LO2		0x7FFF0
-#define MC44S803_LO2_S		4
-/* REG_CIRCADJ */
-#define MC44S803_G1		0x20
-#define MC44S803_G1_S		5
-#define MC44S803_G3		0x80
-#define MC44S803_G3_S		7
-#define MC44S803_CIRCADJ_RES	0x300
-#define MC44S803_CIRCADJ_RES_S	8
-#define MC44S803_G6		0x400
-#define MC44S803_G6_S		10
-#define MC44S803_G7		0x800
-#define MC44S803_G7_S		11
-#define MC44S803_S1		0x1000
-#define MC44S803_S1_S		12
-#define MC44S803_LP		0x7E000
-#define MC44S803_LP_S		13
-#define MC44S803_CLRF		0x80000
-#define MC44S803_CLRF_S		19
-#define MC44S803_CLIF		0x100000
-#define MC44S803_CLIF_S		20
-/* REG_TEST */
-/* REG_DIGTUNE */
-#define MC44S803_DA		0xF0
-#define MC44S803_DA_S		4
-#define MC44S803_XOD		0x300
-#define MC44S803_XOD_S		8
-#define MC44S803_RST		0x10000
-#define MC44S803_RST_S		16
-#define MC44S803_LO_REF		0x1FFF00
-#define MC44S803_LO_REF_S	8
-#define MC44S803_AT		0x200000
-#define MC44S803_AT_S		21
-#define MC44S803_MT		0x400000
-#define MC44S803_MT_S		22
-/* REG_LNAAGC */
-#define MC44S803_G		0x3F0
-#define MC44S803_G_S		4
-#define MC44S803_AT1		0x400
-#define MC44S803_AT1_S		10
-#define MC44S803_AT2		0x800
-#define MC44S803_AT2_S		11
-#define MC44S803_HL_GR_EN	0x8000
-#define MC44S803_HL_GR_EN_S	15
-#define MC44S803_AGC_AN_DIG	0x10000
-#define MC44S803_AGC_AN_DIG_S	16
-#define MC44S803_ATTEN_EN	0x20000
-#define MC44S803_ATTEN_EN_S	17
-#define MC44S803_AGC_READ_EN	0x40000
-#define MC44S803_AGC_READ_EN_S	18
-#define MC44S803_LNA0		0x80000
-#define MC44S803_LNA0_S		19
-#define MC44S803_AGC_SEL	0x100000
-#define MC44S803_AGC_SEL_S	20
-#define MC44S803_AT0		0x200000
-#define MC44S803_AT0_S		21
-#define MC44S803_B		0xC00000
-#define MC44S803_B_S		22
-/* REG_DATAREG */
-#define MC44S803_D		0xF0
-#define MC44S803_D_S		4
-/* REG_REGTEST */
-/* REG_VCOTEST */
-/* REG_LNAGAIN */
-#define MC44S803_IF_PWR		0x700
-#define MC44S803_IF_PWR_S	8
-#define MC44S803_RF_PWR		0x3800
-#define MC44S803_RF_PWR_S	11
-#define MC44S803_LNA_GAIN	0xFC000
-#define MC44S803_LNA_GAIN_S	14
-/* REG_ID */
-#define MC44S803_ID		0x3E00
-#define MC44S803_ID_S		9
-
-/* Some macros to read/write fields */
-
-/* First shift, then mask */
-#define MC44S803_REG_SM(_val, _reg)					\
-	(((_val) << _reg##_S) & (_reg))
-
-/* First mask, then shift */
-#define MC44S803_REG_MS(_val, _reg)					\
-	(((_val) & (_reg)) >> _reg##_S)
-
-struct mc44s803_priv {
-	struct mc44s803_config *cfg;
-	struct i2c_adapter *i2c;
-	struct dvb_frontend *fe;
-
-	u32 frequency;
-};
-
-#endif
diff --git a/drivers/media/common/tuners/mt2060.c b/drivers/media/common/tuners/mt2060.c
deleted file mode 100644
index 13381de..0000000
--- a/drivers/media/common/tuners/mt2060.c
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- *  Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
- *
- *  Copyright (c) 2006 Olivier DANET <odanet@caramail.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-/* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/dvb/frontend.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-
-#include "mt2060.h"
-#include "mt2060_priv.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2060: " args); printk("\n"); }} while (0)
-
-// Reads a single register
-static int mt2060_readreg(struct mt2060_priv *priv, u8 reg, u8 *val)
-{
-	struct i2c_msg msg[2] = {
-		{ .addr = priv->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
-		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val,  .len = 1 },
-	};
-
-	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
-		printk(KERN_WARNING "mt2060 I2C read failed\n");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-// Writes a single register
-static int mt2060_writereg(struct mt2060_priv *priv, u8 reg, u8 val)
-{
-	u8 buf[2] = { reg, val };
-	struct i2c_msg msg = {
-		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
-	};
-
-	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
-		printk(KERN_WARNING "mt2060 I2C write failed\n");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-// Writes a set of consecutive registers
-static int mt2060_writeregs(struct mt2060_priv *priv,u8 *buf, u8 len)
-{
-	struct i2c_msg msg = {
-		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len
-	};
-	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
-		printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n",(int)len);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-// Initialisation sequences
-// LNABAND=3, NUM1=0x3C, DIV1=0x74, NUM2=0x1080, DIV2=0x49
-static u8 mt2060_config1[] = {
-	REG_LO1C1,
-	0x3F,	0x74,	0x00,	0x08,	0x93
-};
-
-// FMCG=2, GP2=0, GP1=0
-static u8 mt2060_config2[] = {
-	REG_MISC_CTRL,
-	0x20,	0x1E,	0x30,	0xff,	0x80,	0xff,	0x00,	0x2c,	0x42
-};
-
-//  VGAG=3, V1CSE=1
-
-#ifdef  MT2060_SPURCHECK
-/* The function below calculates the frequency offset between the output frequency if2
- and the closer cross modulation subcarrier between lo1 and lo2 up to the tenth harmonic */
-static int mt2060_spurcalc(u32 lo1,u32 lo2,u32 if2)
-{
-	int I,J;
-	int dia,diamin,diff;
-	diamin=1000000;
-	for (I = 1; I < 10; I++) {
-		J = ((2*I*lo1)/lo2+1)/2;
-		diff = I*(int)lo1-J*(int)lo2;
-		if (diff < 0) diff=-diff;
-		dia = (diff-(int)if2);
-		if (dia < 0) dia=-dia;
-		if (diamin > dia) diamin=dia;
-	}
-	return diamin;
-}
-
-#define BANDWIDTH 4000 // kHz
-
-/* Calculates the frequency offset to add to avoid spurs. Returns 0 if no offset is needed */
-static int mt2060_spurcheck(u32 lo1,u32 lo2,u32 if2)
-{
-	u32 Spur,Sp1,Sp2;
-	int I,J;
-	I=0;
-	J=1000;
-
-	Spur=mt2060_spurcalc(lo1,lo2,if2);
-	if (Spur < BANDWIDTH) {
-		/* Potential spurs detected */
-		dprintk("Spurs before : f_lo1: %d  f_lo2: %d  (kHz)",
-			(int)lo1,(int)lo2);
-		I=1000;
-		Sp1 = mt2060_spurcalc(lo1+I,lo2+I,if2);
-		Sp2 = mt2060_spurcalc(lo1-I,lo2-I,if2);
-
-		if (Sp1 < Sp2) {
-			J=-J; I=-I; Spur=Sp2;
-		} else
-			Spur=Sp1;
-
-		while (Spur < BANDWIDTH) {
-			I += J;
-			Spur = mt2060_spurcalc(lo1+I,lo2+I,if2);
-		}
-		dprintk("Spurs after  : f_lo1: %d  f_lo2: %d  (kHz)",
-			(int)(lo1+I),(int)(lo2+I));
-	}
-	return I;
-}
-#endif
-
-#define IF2  36150       // IF2 frequency = 36.150 MHz
-#define FREF 16000       // Quartz oscillator 16 MHz
-
-static int mt2060_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct mt2060_priv *priv;
-	int ret=0;
-	int i=0;
-	u32 freq;
-	u8  lnaband;
-	u32 f_lo1,f_lo2;
-	u32 div1,num1,div2,num2;
-	u8  b[8];
-	u32 if1;
-
-	priv = fe->tuner_priv;
-
-	if1 = priv->if1_freq;
-	b[0] = REG_LO1B1;
-	b[1] = 0xFF;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
-
-	mt2060_writeregs(priv,b,2);
-
-	freq = c->frequency / 1000; /* Hz -> kHz */
-
-	f_lo1 = freq + if1 * 1000;
-	f_lo1 = (f_lo1 / 250) * 250;
-	f_lo2 = f_lo1 - freq - IF2;
-	// From the Comtech datasheet, the step used is 50kHz. The tuner chip could be more precise
-	f_lo2 = ((f_lo2 + 25) / 50) * 50;
-	priv->frequency =  (f_lo1 - f_lo2 - IF2) * 1000,
-
-#ifdef MT2060_SPURCHECK
-	// LO-related spurs detection and correction
-	num1   = mt2060_spurcheck(f_lo1,f_lo2,IF2);
-	f_lo1 += num1;
-	f_lo2 += num1;
-#endif
-	//Frequency LO1 = 16MHz * (DIV1 + NUM1/64 )
-	num1 = f_lo1 / (FREF / 64);
-	div1 = num1 / 64;
-	num1 &= 0x3f;
-
-	// Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 )
-	num2 = f_lo2 * 64 / (FREF / 128);
-	div2 = num2 / 8192;
-	num2 &= 0x1fff;
-
-	if (freq <=  95000) lnaband = 0xB0; else
-	if (freq <= 180000) lnaband = 0xA0; else
-	if (freq <= 260000) lnaband = 0x90; else
-	if (freq <= 335000) lnaband = 0x80; else
-	if (freq <= 425000) lnaband = 0x70; else
-	if (freq <= 480000) lnaband = 0x60; else
-	if (freq <= 570000) lnaband = 0x50; else
-	if (freq <= 645000) lnaband = 0x40; else
-	if (freq <= 730000) lnaband = 0x30; else
-	if (freq <= 810000) lnaband = 0x20; else lnaband = 0x10;
-
-	b[0] = REG_LO1C1;
-	b[1] = lnaband | ((num1 >>2) & 0x0F);
-	b[2] = div1;
-	b[3] = (num2 & 0x0F)  | ((num1 & 3) << 4);
-	b[4] = num2 >> 4;
-	b[5] = ((num2 >>12) & 1) | (div2 << 1);
-
-	dprintk("IF1: %dMHz",(int)if1);
-	dprintk("PLL freq=%dkHz  f_lo1=%dkHz  f_lo2=%dkHz",(int)freq,(int)f_lo1,(int)f_lo2);
-	dprintk("PLL div1=%d  num1=%d  div2=%d  num2=%d",(int)div1,(int)num1,(int)div2,(int)num2);
-	dprintk("PLL [1..5]: %2x %2x %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3],(int)b[4],(int)b[5]);
-
-	mt2060_writeregs(priv,b,6);
-
-	//Waits for pll lock or timeout
-	i = 0;
-	do {
-		mt2060_readreg(priv,REG_LO_STATUS,b);
-		if ((b[0] & 0x88)==0x88)
-			break;
-		msleep(4);
-		i++;
-	} while (i<10);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
-
-	return ret;
-}
-
-static void mt2060_calibrate(struct mt2060_priv *priv)
-{
-	u8 b = 0;
-	int i = 0;
-
-	if (mt2060_writeregs(priv,mt2060_config1,sizeof(mt2060_config1)))
-		return;
-	if (mt2060_writeregs(priv,mt2060_config2,sizeof(mt2060_config2)))
-		return;
-
-	/* initialize the clock output */
-	mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30);
-
-	do {
-		b |= (1 << 6); // FM1SS;
-		mt2060_writereg(priv, REG_LO2C1,b);
-		msleep(20);
-
-		if (i == 0) {
-			b |= (1 << 7); // FM1CA;
-			mt2060_writereg(priv, REG_LO2C1,b);
-			b &= ~(1 << 7); // FM1CA;
-			msleep(20);
-		}
-
-		b &= ~(1 << 6); // FM1SS
-		mt2060_writereg(priv, REG_LO2C1,b);
-
-		msleep(20);
-		i++;
-	} while (i < 9);
-
-	i = 0;
-	while (i++ < 10 && mt2060_readreg(priv, REG_MISC_STAT, &b) == 0 && (b & (1 << 6)) == 0)
-		msleep(20);
-
-	if (i <= 10) {
-		mt2060_readreg(priv, REG_FM_FREQ, &priv->fmfreq); // now find out, what is fmreq used for :)
-		dprintk("calibration was successful: %d", (int)priv->fmfreq);
-	} else
-		dprintk("FMCAL timed out");
-}
-
-static int mt2060_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct mt2060_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-	return 0;
-}
-
-static int mt2060_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	*frequency = IF2 * 1000;
-	return 0;
-}
-
-static int mt2060_init(struct dvb_frontend *fe)
-{
-	struct mt2060_priv *priv = fe->tuner_priv;
-	int ret;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
-
-	ret = mt2060_writereg(priv, REG_VGAG,
-			      (priv->cfg->clock_out << 6) | 0x33);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
-
-	return ret;
-}
-
-static int mt2060_sleep(struct dvb_frontend *fe)
-{
-	struct mt2060_priv *priv = fe->tuner_priv;
-	int ret;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
-
-	ret = mt2060_writereg(priv, REG_VGAG,
-			      (priv->cfg->clock_out << 6) | 0x30);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
-
-	return ret;
-}
-
-static int mt2060_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static const struct dvb_tuner_ops mt2060_tuner_ops = {
-	.info = {
-		.name           = "Microtune MT2060",
-		.frequency_min  =  48000000,
-		.frequency_max  = 860000000,
-		.frequency_step =     50000,
-	},
-
-	.release       = mt2060_release,
-
-	.init          = mt2060_init,
-	.sleep         = mt2060_sleep,
-
-	.set_params    = mt2060_set_params,
-	.get_frequency = mt2060_get_frequency,
-	.get_if_frequency = mt2060_get_if_frequency,
-};
-
-/* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */
-struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1)
-{
-	struct mt2060_priv *priv = NULL;
-	u8 id = 0;
-
-	priv = kzalloc(sizeof(struct mt2060_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	priv->cfg      = cfg;
-	priv->i2c      = i2c;
-	priv->if1_freq = if1;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
-
-	if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) {
-		kfree(priv);
-		return NULL;
-	}
-
-	if (id != PART_REV) {
-		kfree(priv);
-		return NULL;
-	}
-	printk(KERN_INFO "MT2060: successfully identified (IF1 = %d)\n", if1);
-	memcpy(&fe->ops.tuner_ops, &mt2060_tuner_ops, sizeof(struct dvb_tuner_ops));
-
-	fe->tuner_priv = priv;
-
-	mt2060_calibrate(priv);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
-
-	return fe;
-}
-EXPORT_SYMBOL(mt2060_attach);
-
-MODULE_AUTHOR("Olivier DANET");
-MODULE_DESCRIPTION("Microtune MT2060 silicon tuner driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/mt2060.h b/drivers/media/common/tuners/mt2060.h
deleted file mode 100644
index cb60caf..0000000
--- a/drivers/media/common/tuners/mt2060.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- *  Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
- *
- *  Copyright (c) 2006 Olivier DANET <odanet@caramail.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef MT2060_H
-#define MT2060_H
-
-struct dvb_frontend;
-struct i2c_adapter;
-
-struct mt2060_config {
-	u8 i2c_address;
-	u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
-};
-
-#if defined(CONFIG_MEDIA_TUNER_MT2060) || (defined(CONFIG_MEDIA_TUNER_MT2060_MODULE) && defined(MODULE))
-extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1);
-#else
-static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_MEDIA_TUNER_MT2060
-
-#endif
diff --git a/drivers/media/common/tuners/mt2060_priv.h b/drivers/media/common/tuners/mt2060_priv.h
deleted file mode 100644
index 2b60de6..0000000
--- a/drivers/media/common/tuners/mt2060_priv.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- *  Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
- *
- *  Copyright (c) 2006 Olivier DANET <odanet@caramail.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef MT2060_PRIV_H
-#define MT2060_PRIV_H
-
-// Uncomment the #define below to enable spurs checking. The results where quite unconvincing.
-// #define MT2060_SPURCHECK
-
-/* This driver is based on the information available in the datasheet of the
-   "Comtech SDVBT-3K6M" tuner ( K1000737843.pdf ) which features the MT2060 register map :
-
-   I2C Address : 0x60
-
-   Reg.No |   B7   |   B6   |   B5   |   B4   |   B3   |   B2   |   B1   |   B0   | ( defaults )
-   --------------------------------------------------------------------------------
-       00 | [              PART             ] | [              REV              ] | R  = 0x63
-       01 | [             LNABAND           ] | [              NUM1(5:2)        ] | RW = 0x3F
-       02 | [                               DIV1                                ] | RW = 0x74
-       03 | FM1CA  | FM1SS  | [  NUM1(1:0)  ] | [              NUM2(3:0)        ] | RW = 0x00
-       04 |                                 NUM2(11:4)                          ] | RW = 0x08
-       05 | [                               DIV2                       ] |NUM2(12)| RW = 0x93
-       06 | L1LK   | [        TAD1          ] | L2LK   | [         TAD2         ] | R
-       07 | [                               FMF                                 ] | R
-       08 |   ?    | FMCAL  |   ?    |   ?    |   ?    |   ?    |   ?    | TEMP   | R
-       09 |   0    |   0    | [    FMGC     ] |   0    | GP02   | GP01   |   0    | RW = 0x20
-       0A | ??
-       0B |   0    |   0    |   1    |   1    |   0    |   0    | [   VGAG      ] | RW = 0x30
-       0C | V1CSE  |   1    |   1    |   1    |   1    |   1    |   1    |   1    | RW = 0xFF
-       0D |   1    |   0    | [                      V1CS                       ] | RW = 0xB0
-       0E | ??
-       0F | ??
-       10 | ??
-       11 | [             LOTO              ] |   0    |   0    |   1    |   0    | RW = 0x42
-
-       PART    : Part code      : 6 for MT2060
-       REV     : Revision code  : 3 for current revision
-       LNABAND : Input frequency range : ( See code for details )
-       NUM1 / DIV1 / NUM2 / DIV2 : Frequencies programming ( See code for details )
-       FM1CA  : Calibration Start Bit
-       FM1SS  : Calibration Single Step bit
-       L1LK   : LO1 Lock Detect
-       TAD1   : Tune Line ADC ( ? )
-       L2LK   : LO2 Lock Detect
-       TAD2   : Tune Line ADC ( ? )
-       FMF    : Estimated first IF Center frequency Offset ( ? )
-       FM1CAL : Calibration done bit
-       TEMP   : On chip temperature sensor
-       FMCG   : Mixer 1 Cap Gain ( ? )
-       GP01 / GP02 : Programmable digital outputs. Unconnected pins ?
-       V1CSE  : LO1 VCO Automatic Capacitor Select Enable ( ? )
-       V1CS   : LO1 Capacitor Selection Value ( ? )
-       LOTO   : LO Timeout ( ? )
-       VGAG   : Tuner Output gain
-*/
-
-#define I2C_ADDRESS 0x60
-
-#define REG_PART_REV   0
-#define REG_LO1C1      1
-#define REG_LO1C2      2
-#define REG_LO2C1      3
-#define REG_LO2C2      4
-#define REG_LO2C3      5
-#define REG_LO_STATUS  6
-#define REG_FM_FREQ    7
-#define REG_MISC_STAT  8
-#define REG_MISC_CTRL  9
-#define REG_RESERVED_A 0x0A
-#define REG_VGAG       0x0B
-#define REG_LO1B1      0x0C
-#define REG_LO1B2      0x0D
-#define REG_LOTO       0x11
-
-#define PART_REV 0x63 // The current driver works only with PART=6 and REV=3 chips
-
-struct mt2060_priv {
-	struct mt2060_config *cfg;
-	struct i2c_adapter   *i2c;
-
-	u32 frequency;
-	u16 if1_freq;
-	u8  fmfreq;
-};
-
-#endif
diff --git a/drivers/media/common/tuners/mt2063.c b/drivers/media/common/tuners/mt2063.c
deleted file mode 100644
index 0ed9091..0000000
--- a/drivers/media/common/tuners/mt2063.c
+++ /dev/null
@@ -1,2307 +0,0 @@
-/*
- * Driver for mt2063 Micronas tuner
- *
- * Copyright (c) 2011 Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This driver came from a driver originally written by:
- *		Henry Wang <Henry.wang@AzureWave.com>
- * Made publicly available by Terratec, at:
- *	http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
- * The original driver's license is GPL, as declared with MODULE_LICENSE()
- *
- * 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 under version 2 of the License.
- *
- * 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/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/videodev2.h>
-
-#include "mt2063.h"
-
-static unsigned int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Set Verbosity level");
-
-#define dprintk(level, fmt, arg...) do {				\
-if (debug >= level)							\
-	printk(KERN_DEBUG "mt2063 %s: " fmt, __func__, ## arg);	\
-} while (0)
-
-
-/* positive error codes used internally */
-
-/*  Info: Unavoidable LO-related spur may be present in the output  */
-#define MT2063_SPUR_PRESENT_ERR             (0x00800000)
-
-/*  Info: Mask of bits used for # of LO-related spurs that were avoided during tuning  */
-#define MT2063_SPUR_CNT_MASK                (0x001f0000)
-#define MT2063_SPUR_SHIFT                   (16)
-
-/*  Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */
-#define MT2063_UPC_RANGE                    (0x04000000)
-
-/*  Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */
-#define MT2063_DNC_RANGE                    (0x08000000)
-
-/*
- *  Constant defining the version of the following structure
- *  and therefore the API for this code.
- *
- *  When compiling the tuner driver, the preprocessor will
- *  check against this version number to make sure that
- *  it matches the version that the tuner driver knows about.
- */
-
-/* DECT Frequency Avoidance */
-#define MT2063_DECT_AVOID_US_FREQS      0x00000001
-
-#define MT2063_DECT_AVOID_EURO_FREQS    0x00000002
-
-#define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0)
-
-#define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0)
-
-enum MT2063_DECT_Avoid_Type {
-	MT2063_NO_DECT_AVOIDANCE = 0,				/* Do not create DECT exclusion zones.     */
-	MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS,	/* Avoid US DECT frequencies.              */
-	MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS,	/* Avoid European DECT frequencies.        */
-	MT2063_AVOID_BOTH					/* Avoid both regions. Not typically used. */
-};
-
-#define MT2063_MAX_ZONES 48
-
-struct MT2063_ExclZone_t {
-	u32 min_;
-	u32 max_;
-	struct MT2063_ExclZone_t *next_;
-};
-
-/*
- *  Structure of data needed for Spur Avoidance
- */
-struct MT2063_AvoidSpursData_t {
-	u32 f_ref;
-	u32 f_in;
-	u32 f_LO1;
-	u32 f_if1_Center;
-	u32 f_if1_Request;
-	u32 f_if1_bw;
-	u32 f_LO2;
-	u32 f_out;
-	u32 f_out_bw;
-	u32 f_LO1_Step;
-	u32 f_LO2_Step;
-	u32 f_LO1_FracN_Avoid;
-	u32 f_LO2_FracN_Avoid;
-	u32 f_zif_bw;
-	u32 f_min_LO_Separation;
-	u32 maxH1;
-	u32 maxH2;
-	enum MT2063_DECT_Avoid_Type avoidDECT;
-	u32 bSpurPresent;
-	u32 bSpurAvoided;
-	u32 nSpursFound;
-	u32 nZones;
-	struct MT2063_ExclZone_t *freeZones;
-	struct MT2063_ExclZone_t *usedZones;
-	struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES];
-};
-
-/*
- * Parameter for function MT2063_SetPowerMask that specifies the power down
- * of various sections of the MT2063.
- */
-enum MT2063_Mask_Bits {
-	MT2063_REG_SD = 0x0040,		/* Shutdown regulator                 */
-	MT2063_SRO_SD = 0x0020,		/* Shutdown SRO                       */
-	MT2063_AFC_SD = 0x0010,		/* Shutdown AFC A/D                   */
-	MT2063_PD_SD = 0x0002,		/* Enable power detector shutdown     */
-	MT2063_PDADC_SD = 0x0001,	/* Enable power detector A/D shutdown */
-	MT2063_VCO_SD = 0x8000,		/* Enable VCO shutdown                */
-	MT2063_LTX_SD = 0x4000,		/* Enable LTX shutdown                */
-	MT2063_LT1_SD = 0x2000,		/* Enable LT1 shutdown                */
-	MT2063_LNA_SD = 0x1000,		/* Enable LNA shutdown                */
-	MT2063_UPC_SD = 0x0800,		/* Enable upconverter shutdown        */
-	MT2063_DNC_SD = 0x0400,		/* Enable downconverter shutdown      */
-	MT2063_VGA_SD = 0x0200,		/* Enable VGA shutdown                */
-	MT2063_AMP_SD = 0x0100,		/* Enable AMP shutdown                */
-	MT2063_ALL_SD = 0xFF73,		/* All shutdown bits for this tuner   */
-	MT2063_NONE_SD = 0x0000		/* No shutdown bits                   */
-};
-
-/*
- *  Possible values for MT2063_DNC_OUTPUT
- */
-enum MT2063_DNC_Output_Enable {
-	MT2063_DNC_NONE = 0,
-	MT2063_DNC_1,
-	MT2063_DNC_2,
-	MT2063_DNC_BOTH
-};
-
-/*
- *  Two-wire serial bus subaddresses of the tuner registers.
- *  Also known as the tuner's register addresses.
- */
-enum MT2063_Register_Offsets {
-	MT2063_REG_PART_REV = 0,	/*  0x00: Part/Rev Code         */
-	MT2063_REG_LO1CQ_1,		/*  0x01: LO1C Queued Byte 1    */
-	MT2063_REG_LO1CQ_2,		/*  0x02: LO1C Queued Byte 2    */
-	MT2063_REG_LO2CQ_1,		/*  0x03: LO2C Queued Byte 1    */
-	MT2063_REG_LO2CQ_2,		/*  0x04: LO2C Queued Byte 2    */
-	MT2063_REG_LO2CQ_3,		/*  0x05: LO2C Queued Byte 3    */
-	MT2063_REG_RSVD_06,		/*  0x06: Reserved              */
-	MT2063_REG_LO_STATUS,		/*  0x07: LO Status             */
-	MT2063_REG_FIFFC,		/*  0x08: FIFF Center           */
-	MT2063_REG_CLEARTUNE,		/*  0x09: ClearTune Filter      */
-	MT2063_REG_ADC_OUT,		/*  0x0A: ADC_OUT               */
-	MT2063_REG_LO1C_1,		/*  0x0B: LO1C Byte 1           */
-	MT2063_REG_LO1C_2,		/*  0x0C: LO1C Byte 2           */
-	MT2063_REG_LO2C_1,		/*  0x0D: LO2C Byte 1           */
-	MT2063_REG_LO2C_2,		/*  0x0E: LO2C Byte 2           */
-	MT2063_REG_LO2C_3,		/*  0x0F: LO2C Byte 3           */
-	MT2063_REG_RSVD_10,		/*  0x10: Reserved              */
-	MT2063_REG_PWR_1,		/*  0x11: PWR Byte 1            */
-	MT2063_REG_PWR_2,		/*  0x12: PWR Byte 2            */
-	MT2063_REG_TEMP_STATUS,		/*  0x13: Temp Status           */
-	MT2063_REG_XO_STATUS,		/*  0x14: Crystal Status        */
-	MT2063_REG_RF_STATUS,		/*  0x15: RF Attn Status        */
-	MT2063_REG_FIF_STATUS,		/*  0x16: FIF Attn Status       */
-	MT2063_REG_LNA_OV,		/*  0x17: LNA Attn Override     */
-	MT2063_REG_RF_OV,		/*  0x18: RF Attn Override      */
-	MT2063_REG_FIF_OV,		/*  0x19: FIF Attn Override     */
-	MT2063_REG_LNA_TGT,		/*  0x1A: Reserved              */
-	MT2063_REG_PD1_TGT,		/*  0x1B: Pwr Det 1 Target      */
-	MT2063_REG_PD2_TGT,		/*  0x1C: Pwr Det 2 Target      */
-	MT2063_REG_RSVD_1D,		/*  0x1D: Reserved              */
-	MT2063_REG_RSVD_1E,		/*  0x1E: Reserved              */
-	MT2063_REG_RSVD_1F,		/*  0x1F: Reserved              */
-	MT2063_REG_RSVD_20,		/*  0x20: Reserved              */
-	MT2063_REG_BYP_CTRL,		/*  0x21: Bypass Control        */
-	MT2063_REG_RSVD_22,		/*  0x22: Reserved              */
-	MT2063_REG_RSVD_23,		/*  0x23: Reserved              */
-	MT2063_REG_RSVD_24,		/*  0x24: Reserved              */
-	MT2063_REG_RSVD_25,		/*  0x25: Reserved              */
-	MT2063_REG_RSVD_26,		/*  0x26: Reserved              */
-	MT2063_REG_RSVD_27,		/*  0x27: Reserved              */
-	MT2063_REG_FIFF_CTRL,		/*  0x28: FIFF Control          */
-	MT2063_REG_FIFF_OFFSET,		/*  0x29: FIFF Offset           */
-	MT2063_REG_CTUNE_CTRL,		/*  0x2A: Reserved              */
-	MT2063_REG_CTUNE_OV,		/*  0x2B: Reserved              */
-	MT2063_REG_CTRL_2C,		/*  0x2C: Reserved              */
-	MT2063_REG_FIFF_CTRL2,		/*  0x2D: Fiff Control          */
-	MT2063_REG_RSVD_2E,		/*  0x2E: Reserved              */
-	MT2063_REG_DNC_GAIN,		/*  0x2F: DNC Control           */
-	MT2063_REG_VGA_GAIN,		/*  0x30: VGA Gain Ctrl         */
-	MT2063_REG_RSVD_31,		/*  0x31: Reserved              */
-	MT2063_REG_TEMP_SEL,		/*  0x32: Temperature Selection */
-	MT2063_REG_RSVD_33,		/*  0x33: Reserved              */
-	MT2063_REG_RSVD_34,		/*  0x34: Reserved              */
-	MT2063_REG_RSVD_35,		/*  0x35: Reserved              */
-	MT2063_REG_RSVD_36,		/*  0x36: Reserved              */
-	MT2063_REG_RSVD_37,		/*  0x37: Reserved              */
-	MT2063_REG_RSVD_38,		/*  0x38: Reserved              */
-	MT2063_REG_RSVD_39,		/*  0x39: Reserved              */
-	MT2063_REG_RSVD_3A,		/*  0x3A: Reserved              */
-	MT2063_REG_RSVD_3B,		/*  0x3B: Reserved              */
-	MT2063_REG_RSVD_3C,		/*  0x3C: Reserved              */
-	MT2063_REG_END_REGS
-};
-
-struct mt2063_state {
-	struct i2c_adapter *i2c;
-
-	bool init;
-
-	const struct mt2063_config *config;
-	struct dvb_tuner_ops ops;
-	struct dvb_frontend *frontend;
-	struct tuner_state status;
-
-	u32 frequency;
-	u32 srate;
-	u32 bandwidth;
-	u32 reference;
-
-	u32 tuner_id;
-	struct MT2063_AvoidSpursData_t AS_Data;
-	u32 f_IF1_actual;
-	u32 rcvr_mode;
-	u32 ctfilt_sw;
-	u32 CTFiltMax[31];
-	u32 num_regs;
-	u8 reg[MT2063_REG_END_REGS];
-};
-
-/*
- * mt2063_write - Write data into the I2C bus
- */
-static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len)
-{
-	struct dvb_frontend *fe = state->frontend;
-	int ret;
-	u8 buf[60];
-	struct i2c_msg msg = {
-		.addr = state->config->tuner_address,
-		.flags = 0,
-		.buf = buf,
-		.len = len + 1
-	};
-
-	dprintk(2, "\n");
-
-	msg.buf[0] = reg;
-	memcpy(msg.buf + 1, data, len);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	ret = i2c_transfer(state->i2c, &msg, 1);
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	if (ret < 0)
-		printk(KERN_ERR "%s error ret=%d\n", __func__, ret);
-
-	return ret;
-}
-
-/*
- * mt2063_write - Write register data into the I2C bus, caching the value
- */
-static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val)
-{
-	u32 status;
-
-	dprintk(2, "\n");
-
-	if (reg >= MT2063_REG_END_REGS)
-		return -ERANGE;
-
-	status = mt2063_write(state, reg, &val, 1);
-	if (status < 0)
-		return status;
-
-	state->reg[reg] = val;
-
-	return 0;
-}
-
-/*
- * mt2063_read - Read data from the I2C bus
- */
-static u32 mt2063_read(struct mt2063_state *state,
-			   u8 subAddress, u8 *pData, u32 cnt)
-{
-	u32 status = 0;	/* Status to be returned        */
-	struct dvb_frontend *fe = state->frontend;
-	u32 i = 0;
-
-	dprintk(2, "addr 0x%02x, cnt %d\n", subAddress, cnt);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	for (i = 0; i < cnt; i++) {
-		u8 b0[] = { subAddress + i };
-		struct i2c_msg msg[] = {
-			{
-				.addr = state->config->tuner_address,
-				.flags = 0,
-				.buf = b0,
-				.len = 1
-			}, {
-				.addr = state->config->tuner_address,
-				.flags = I2C_M_RD,
-				.buf = pData + i,
-				.len = 1
-			}
-		};
-
-		status = i2c_transfer(state->i2c, msg, 2);
-		dprintk(2, "addr 0x%02x, ret = %d, val = 0x%02x\n",
-			   subAddress + i, status, *(pData + i));
-		if (status < 0)
-			break;
-	}
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	if (status < 0)
-		printk(KERN_ERR "Can't read from address 0x%02x,\n",
-		       subAddress + i);
-
-	return status;
-}
-
-/*
- * FIXME: Is this really needed?
- */
-static int MT2063_Sleep(struct dvb_frontend *fe)
-{
-	/*
-	 *  ToDo:  Add code here to implement a OS blocking
-	 */
-	msleep(100);
-
-	return 0;
-}
-
-/*
- * Microtune spur avoidance
- */
-
-/*  Implement ceiling, floor functions.  */
-#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0))
-#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d))
-
-struct MT2063_FIFZone_t {
-	s32 min_;
-	s32 max_;
-};
-
-static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t
-					    *pAS_Info,
-					    struct MT2063_ExclZone_t *pPrevNode)
-{
-	struct MT2063_ExclZone_t *pNode;
-
-	dprintk(2, "\n");
-
-	/*  Check for a node in the free list  */
-	if (pAS_Info->freeZones != NULL) {
-		/*  Use one from the free list  */
-		pNode = pAS_Info->freeZones;
-		pAS_Info->freeZones = pNode->next_;
-	} else {
-		/*  Grab a node from the array  */
-		pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones];
-	}
-
-	if (pPrevNode != NULL) {
-		pNode->next_ = pPrevNode->next_;
-		pPrevNode->next_ = pNode;
-	} else {		/*  insert at the beginning of the list  */
-
-		pNode->next_ = pAS_Info->usedZones;
-		pAS_Info->usedZones = pNode;
-	}
-
-	pAS_Info->nZones++;
-	return pNode;
-}
-
-static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t
-					    *pAS_Info,
-					    struct MT2063_ExclZone_t *pPrevNode,
-					    struct MT2063_ExclZone_t
-					    *pNodeToRemove)
-{
-	struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_;
-
-	dprintk(2, "\n");
-
-	/*  Make previous node point to the subsequent node  */
-	if (pPrevNode != NULL)
-		pPrevNode->next_ = pNext;
-
-	/*  Add pNodeToRemove to the beginning of the freeZones  */
-	pNodeToRemove->next_ = pAS_Info->freeZones;
-	pAS_Info->freeZones = pNodeToRemove;
-
-	/*  Decrement node count  */
-	pAS_Info->nZones--;
-
-	return pNext;
-}
-
-/*
- * MT_AddExclZone()
- *
- * Add (and merge) an exclusion zone into the list.
- * If the range (f_min, f_max) is totally outside the
- * 1st IF BW, ignore the entry.
- * If the range (f_min, f_max) is negative, ignore the entry.
- */
-static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info,
-			       u32 f_min, u32 f_max)
-{
-	struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
-	struct MT2063_ExclZone_t *pPrev = NULL;
-	struct MT2063_ExclZone_t *pNext = NULL;
-
-	dprintk(2, "\n");
-
-	/*  Check to see if this overlaps the 1st IF filter  */
-	if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2)))
-	    && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2)))
-	    && (f_min < f_max)) {
-		/*
-		 *                1        2         3      4       5        6
-		 *
-		 *   New entry:  |---|    |--|      |--|    |-|    |---|    |--|
-		 *                or       or        or     or      or
-		 *   Existing:  |--|      |--|      |--|    |---|  |-|      |--|
-		 */
-
-		/*  Check for our place in the list  */
-		while ((pNode != NULL) && (pNode->max_ < f_min)) {
-			pPrev = pNode;
-			pNode = pNode->next_;
-		}
-
-		if ((pNode != NULL) && (pNode->min_ < f_max)) {
-			/*  Combine me with pNode  */
-			if (f_min < pNode->min_)
-				pNode->min_ = f_min;
-			if (f_max > pNode->max_)
-				pNode->max_ = f_max;
-		} else {
-			pNode = InsertNode(pAS_Info, pPrev);
-			pNode->min_ = f_min;
-			pNode->max_ = f_max;
-		}
-
-		/*  Look for merging possibilities  */
-		pNext = pNode->next_;
-		while ((pNext != NULL) && (pNext->min_ < pNode->max_)) {
-			if (pNext->max_ > pNode->max_)
-				pNode->max_ = pNext->max_;
-			/*  Remove pNext, return ptr to pNext->next  */
-			pNext = RemoveNode(pAS_Info, pNode, pNext);
-		}
-	}
-}
-
-/*
- *  Reset all exclusion zones.
- *  Add zones to protect the PLL FracN regions near zero
- */
-static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info)
-{
-	u32 center;
-
-	dprintk(2, "\n");
-
-	pAS_Info->nZones = 0;	/*  this clears the used list  */
-	pAS_Info->usedZones = NULL;	/*  reset ptr                  */
-	pAS_Info->freeZones = NULL;	/*  reset ptr                  */
-
-	center =
-	    pAS_Info->f_ref *
-	    ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 +
-	      pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in;
-	while (center <
-	       pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
-	       pAS_Info->f_LO1_FracN_Avoid) {
-		/*  Exclude LO1 FracN  */
-		MT2063_AddExclZone(pAS_Info,
-				   center - pAS_Info->f_LO1_FracN_Avoid,
-				   center - 1);
-		MT2063_AddExclZone(pAS_Info, center + 1,
-				   center + pAS_Info->f_LO1_FracN_Avoid);
-		center += pAS_Info->f_ref;
-	}
-
-	center =
-	    pAS_Info->f_ref *
-	    ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 -
-	      pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out;
-	while (center <
-	       pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
-	       pAS_Info->f_LO2_FracN_Avoid) {
-		/*  Exclude LO2 FracN  */
-		MT2063_AddExclZone(pAS_Info,
-				   center - pAS_Info->f_LO2_FracN_Avoid,
-				   center - 1);
-		MT2063_AddExclZone(pAS_Info, center + 1,
-				   center + pAS_Info->f_LO2_FracN_Avoid);
-		center += pAS_Info->f_ref;
-	}
-
-	if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
-		/*  Exclude LO1 values that conflict with DECT channels */
-		MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in);	/* Ctr = 1921.536 */
-		MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in);	/* Ctr = 1923.264 */
-		MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in);	/* Ctr = 1924.992 */
-		MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in);	/* Ctr = 1926.720 */
-		MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in);	/* Ctr = 1928.448 */
-	}
-
-	if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
-		MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in);	/* Ctr = 1897.344 */
-		MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in);	/* Ctr = 1895.616 */
-		MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in);	/* Ctr = 1893.888 */
-		MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in);	/* Ctr = 1892.16  */
-		MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in);	/* Ctr = 1890.432 */
-		MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in);	/* Ctr = 1888.704 */
-		MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in);	/* Ctr = 1886.976 */
-		MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in);	/* Ctr = 1885.248 */
-		MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in);	/* Ctr = 1883.52  */
-		MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in);	/* Ctr = 1881.792 */
-	}
-}
-
-/*
- * MT_ChooseFirstIF - Choose the best available 1st IF
- *                    If f_Desired is not excluded, choose that first.
- *                    Otherwise, return the value closest to f_Center that is
- *                    not excluded
- */
-static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info)
-{
-	/*
-	 * Update "f_Desired" to be the nearest "combinational-multiple" of
-	 * "f_LO1_Step".
-	 * The resulting number, F_LO1 must be a multiple of f_LO1_Step.
-	 * And F_LO1 is the arithmetic sum of f_in + f_Center.
-	 * Neither f_in, nor f_Center must be a multiple of f_LO1_Step.
-	 * However, the sum must be.
-	 */
-	const u32 f_Desired =
-	    pAS_Info->f_LO1_Step *
-	    ((pAS_Info->f_if1_Request + pAS_Info->f_in +
-	      pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) -
-	    pAS_Info->f_in;
-	const u32 f_Step =
-	    (pAS_Info->f_LO1_Step >
-	     pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info->
-	    f_LO2_Step;
-	u32 f_Center;
-	s32 i;
-	s32 j = 0;
-	u32 bDesiredExcluded = 0;
-	u32 bZeroExcluded = 0;
-	s32 tmpMin, tmpMax;
-	s32 bestDiff;
-	struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
-	struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES];
-
-	dprintk(2, "\n");
-
-	if (pAS_Info->nZones == 0)
-		return f_Desired;
-
-	/*
-	 *  f_Center needs to be an integer multiple of f_Step away
-	 *  from f_Desired
-	 */
-	if (pAS_Info->f_if1_Center > f_Desired)
-		f_Center =
-		    f_Desired +
-		    f_Step *
-		    ((pAS_Info->f_if1_Center - f_Desired +
-		      f_Step / 2) / f_Step);
-	else
-		f_Center =
-		    f_Desired -
-		    f_Step *
-		    ((f_Desired - pAS_Info->f_if1_Center +
-		      f_Step / 2) / f_Step);
-
-	/*
-	 * Take MT_ExclZones, center around f_Center and change the
-	 * resolution to f_Step
-	 */
-	while (pNode != NULL) {
-		/*  floor function  */
-		tmpMin =
-		    floor((s32) (pNode->min_ - f_Center), (s32) f_Step);
-
-		/*  ceil function  */
-		tmpMax =
-		    ceil((s32) (pNode->max_ - f_Center), (s32) f_Step);
-
-		if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired))
-			bDesiredExcluded = 1;
-
-		if ((tmpMin < 0) && (tmpMax > 0))
-			bZeroExcluded = 1;
-
-		/*  See if this zone overlaps the previous  */
-		if ((j > 0) && (tmpMin < zones[j - 1].max_))
-			zones[j - 1].max_ = tmpMax;
-		else {
-			/*  Add new zone  */
-			zones[j].min_ = tmpMin;
-			zones[j].max_ = tmpMax;
-			j++;
-		}
-		pNode = pNode->next_;
-	}
-
-	/*
-	 *  If the desired is okay, return with it
-	 */
-	if (bDesiredExcluded == 0)
-		return f_Desired;
-
-	/*
-	 *  If the desired is excluded and the center is okay, return with it
-	 */
-	if (bZeroExcluded == 0)
-		return f_Center;
-
-	/*  Find the value closest to 0 (f_Center)  */
-	bestDiff = zones[0].min_;
-	for (i = 0; i < j; i++) {
-		if (abs(zones[i].min_) < abs(bestDiff))
-			bestDiff = zones[i].min_;
-		if (abs(zones[i].max_) < abs(bestDiff))
-			bestDiff = zones[i].max_;
-	}
-
-	if (bestDiff < 0)
-		return f_Center - ((u32) (-bestDiff) * f_Step);
-
-	return f_Center + (bestDiff * f_Step);
-}
-
-/**
- * gcd() - Uses Euclid's algorithm
- *
- * @u, @v:	Unsigned values whose GCD is desired.
- *
- * Returns THE greatest common divisor of u and v, if either value is 0,
- * the other value is returned as the result.
- */
-static u32 MT2063_gcd(u32 u, u32 v)
-{
-	u32 r;
-
-	while (v != 0) {
-		r = u % v;
-		u = v;
-		v = r;
-	}
-
-	return u;
-}
-
-/**
- * IsSpurInBand() - Checks to see if a spur will be present within the IF's
- *                  bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW)
- *
- *                    ma   mb                                     mc   md
- *                  <--+-+-+-------------------+-------------------+-+-+-->
- *                     |   ^                   0                   ^   |
- *                     ^   b=-fIFOut+fIFBW/2      -b=+fIFOut-fIFBW/2   ^
- *                     a=-fIFOut-fIFBW/2              -a=+fIFOut+fIFBW/2
- *
- *                  Note that some equations are doubled to prevent round-off
- *                  problems when calculating fIFBW/2
- *
- * @pAS_Info:	Avoid Spurs information block
- * @fm:		If spur, amount f_IF1 has to move negative
- * @fp:		If spur, amount f_IF1 has to move positive
- *
- *  Returns 1 if an LO spur would be present, otherwise 0.
- */
-static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info,
-			u32 *fm, u32 * fp)
-{
-	/*
-	 **  Calculate LO frequency settings.
-	 */
-	u32 n, n0;
-	const u32 f_LO1 = pAS_Info->f_LO1;
-	const u32 f_LO2 = pAS_Info->f_LO2;
-	const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2;
-	const u32 c = d - pAS_Info->f_out_bw;
-	const u32 f = pAS_Info->f_zif_bw / 2;
-	const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1;
-	s32 f_nsLO1, f_nsLO2;
-	s32 f_Spur;
-	u32 ma, mb, mc, md, me, mf;
-	u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs;
-
-	dprintk(2, "\n");
-
-	*fm = 0;
-
-	/*
-	 ** For each edge (d, c & f), calculate a scale, based on the gcd
-	 ** of f_LO1, f_LO2 and the edge value.  Use the larger of this
-	 ** gcd-based scale factor or f_Scale.
-	 */
-	lo_gcd = MT2063_gcd(f_LO1, f_LO2);
-	gd_Scale = max((u32) MT2063_gcd(lo_gcd, d), f_Scale);
-	hgds = gd_Scale / 2;
-	gc_Scale = max((u32) MT2063_gcd(lo_gcd, c), f_Scale);
-	hgcs = gc_Scale / 2;
-	gf_Scale = max((u32) MT2063_gcd(lo_gcd, f), f_Scale);
-	hgfs = gf_Scale / 2;
-
-	n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2);
-
-	/*  Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic  */
-	for (n = n0; n <= pAS_Info->maxH1; ++n) {
-		md = (n * ((f_LO1 + hgds) / gd_Scale) -
-		      ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
-
-		/*  If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present  */
-		if (md >= pAS_Info->maxH1)
-			break;
-
-		ma = (n * ((f_LO1 + hgds) / gd_Scale) +
-		      ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
-
-		/*  If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic  */
-		if (md == ma)
-			continue;
-
-		mc = (n * ((f_LO1 + hgcs) / gc_Scale) -
-		      ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
-		if (mc != md) {
-			f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale));
-			f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale));
-			f_Spur =
-			    (gc_Scale * (f_nsLO1 - f_nsLO2)) +
-			    n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale);
-
-			*fp = ((f_Spur - (s32) c) / (mc - n)) + 1;
-			*fm = (((s32) d - f_Spur) / (mc - n)) + 1;
-			return 1;
-		}
-
-		/*  Location of Zero-IF-spur to be checked  */
-		me = (n * ((f_LO1 + hgfs) / gf_Scale) +
-		      ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
-		mf = (n * ((f_LO1 + hgfs) / gf_Scale) -
-		      ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
-		if (me != mf) {
-			f_nsLO1 = n * (f_LO1 / gf_Scale);
-			f_nsLO2 = me * (f_LO2 / gf_Scale);
-			f_Spur =
-			    (gf_Scale * (f_nsLO1 - f_nsLO2)) +
-			    n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale);
-
-			*fp = ((f_Spur + (s32) f) / (me - n)) + 1;
-			*fm = (((s32) f - f_Spur) / (me - n)) + 1;
-			return 1;
-		}
-
-		mb = (n * ((f_LO1 + hgcs) / gc_Scale) +
-		      ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
-		if (ma != mb) {
-			f_nsLO1 = n * (f_LO1 / gc_Scale);
-			f_nsLO2 = ma * (f_LO2 / gc_Scale);
-			f_Spur =
-			    (gc_Scale * (f_nsLO1 - f_nsLO2)) +
-			    n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale);
-
-			*fp = (((s32) d + f_Spur) / (ma - n)) + 1;
-			*fm = (-(f_Spur + (s32) c) / (ma - n)) + 1;
-			return 1;
-		}
-	}
-
-	/*  No spurs found  */
-	return 0;
-}
-
-/*
- * MT_AvoidSpurs() - Main entry point to avoid spurs.
- *                   Checks for existing spurs in present LO1, LO2 freqs
- *                   and if present, chooses spur-free LO1, LO2 combination
- *                   that tunes the same input/output frequencies.
- */
-static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info)
-{
-	u32 status = 0;
-	u32 fm, fp;		/*  restricted range on LO's        */
-	pAS_Info->bSpurAvoided = 0;
-	pAS_Info->nSpursFound = 0;
-
-	dprintk(2, "\n");
-
-	if (pAS_Info->maxH1 == 0)
-		return 0;
-
-	/*
-	 * Avoid LO Generated Spurs
-	 *
-	 * Make sure that have no LO-related spurs within the IF output
-	 * bandwidth.
-	 *
-	 * If there is an LO spur in this band, start at the current IF1 frequency
-	 * and work out until we find a spur-free frequency or run up against the
-	 * 1st IF SAW band edge.  Use temporary copies of fLO1 and fLO2 so that they
-	 * will be unchanged if a spur-free setting is not found.
-	 */
-	pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
-	if (pAS_Info->bSpurPresent) {
-		u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in;	/*  current attempt at a 1st IF  */
-		u32 zfLO1 = pAS_Info->f_LO1;	/*  current attempt at an LO1 freq  */
-		u32 zfLO2 = pAS_Info->f_LO2;	/*  current attempt at an LO2 freq  */
-		u32 delta_IF1;
-		u32 new_IF1;
-
-		/*
-		 **  Spur was found, attempt to find a spur-free 1st IF
-		 */
-		do {
-			pAS_Info->nSpursFound++;
-
-			/*  Raise f_IF1_upper, if needed  */
-			MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp);
-
-			/*  Choose next IF1 that is closest to f_IF1_CENTER              */
-			new_IF1 = MT2063_ChooseFirstIF(pAS_Info);
-
-			if (new_IF1 > zfIF1) {
-				pAS_Info->f_LO1 += (new_IF1 - zfIF1);
-				pAS_Info->f_LO2 += (new_IF1 - zfIF1);
-			} else {
-				pAS_Info->f_LO1 -= (zfIF1 - new_IF1);
-				pAS_Info->f_LO2 -= (zfIF1 - new_IF1);
-			}
-			zfIF1 = new_IF1;
-
-			if (zfIF1 > pAS_Info->f_if1_Center)
-				delta_IF1 = zfIF1 - pAS_Info->f_if1_Center;
-			else
-				delta_IF1 = pAS_Info->f_if1_Center - zfIF1;
-
-			pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
-		/*
-		 *  Continue while the new 1st IF is still within the 1st IF bandwidth
-		 *  and there is a spur in the band (again)
-		 */
-		} while ((2 * delta_IF1 + pAS_Info->f_out_bw <= pAS_Info->f_if1_bw) && pAS_Info->bSpurPresent);
-
-		/*
-		 * Use the LO-spur free values found.  If the search went all
-		 * the way to the 1st IF band edge and always found spurs, just
-		 * leave the original choice.  It's as "good" as any other.
-		 */
-		if (pAS_Info->bSpurPresent == 1) {
-			status |= MT2063_SPUR_PRESENT_ERR;
-			pAS_Info->f_LO1 = zfLO1;
-			pAS_Info->f_LO2 = zfLO2;
-		} else
-			pAS_Info->bSpurAvoided = 1;
-	}
-
-	status |=
-	    ((pAS_Info->
-	      nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK);
-
-	return status;
-}
-
-/*
- * Constants used by the tuning algorithm
- */
-#define MT2063_REF_FREQ          (16000000UL)	/* Reference oscillator Frequency (in Hz) */
-#define MT2063_IF1_BW            (22000000UL)	/* The IF1 filter bandwidth (in Hz) */
-#define MT2063_TUNE_STEP_SIZE       (50000UL)	/* Tune in steps of 50 kHz */
-#define MT2063_SPUR_STEP_HZ        (250000UL)	/* Step size (in Hz) to move IF1 when avoiding spurs */
-#define MT2063_ZIF_BW             (2000000UL)	/* Zero-IF spur-free bandwidth (in Hz) */
-#define MT2063_MAX_HARMONICS_1         (15UL)	/* Highest intra-tuner LO Spur Harmonic to be avoided */
-#define MT2063_MAX_HARMONICS_2          (5UL)	/* Highest inter-tuner LO Spur Harmonic to be avoided */
-#define MT2063_MIN_LO_SEP         (1000000UL)	/* Minimum inter-tuner LO frequency separation */
-#define MT2063_LO1_FRACN_AVOID          (0UL)	/* LO1 FracN numerator avoid region (in Hz) */
-#define MT2063_LO2_FRACN_AVOID     (199999UL)	/* LO2 FracN numerator avoid region (in Hz) */
-#define MT2063_MIN_FIN_FREQ      (44000000UL)	/* Minimum input frequency (in Hz) */
-#define MT2063_MAX_FIN_FREQ    (1100000000UL)	/* Maximum input frequency (in Hz) */
-#define MT2063_MIN_FOUT_FREQ     (36000000UL)	/* Minimum output frequency (in Hz) */
-#define MT2063_MAX_FOUT_FREQ     (57000000UL)	/* Maximum output frequency (in Hz) */
-#define MT2063_MIN_DNC_FREQ    (1293000000UL)	/* Minimum LO2 frequency (in Hz) */
-#define MT2063_MAX_DNC_FREQ    (1614000000UL)	/* Maximum LO2 frequency (in Hz) */
-#define MT2063_MIN_UPC_FREQ    (1396000000UL)	/* Minimum LO1 frequency (in Hz) */
-#define MT2063_MAX_UPC_FREQ    (2750000000UL)	/* Maximum LO1 frequency (in Hz) */
-
-/*
- *  Define the supported Part/Rev codes for the MT2063
- */
-#define MT2063_B0       (0x9B)
-#define MT2063_B1       (0x9C)
-#define MT2063_B2       (0x9D)
-#define MT2063_B3       (0x9E)
-
-/**
- * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked
- *
- * @state:	struct mt2063_state pointer
- *
- * This function returns 0, if no lock, 1 if locked and a value < 1 if error
- */
-static unsigned int mt2063_lockStatus(struct mt2063_state *state)
-{
-	const u32 nMaxWait = 100;	/*  wait a maximum of 100 msec   */
-	const u32 nPollRate = 2;	/*  poll status bits every 2 ms */
-	const u32 nMaxLoops = nMaxWait / nPollRate;
-	const u8 LO1LK = 0x80;
-	u8 LO2LK = 0x08;
-	u32 status;
-	u32 nDelays = 0;
-
-	dprintk(2, "\n");
-
-	/*  LO2 Lock bit was in a different place for B0 version  */
-	if (state->tuner_id == MT2063_B0)
-		LO2LK = 0x40;
-
-	do {
-		status = mt2063_read(state, MT2063_REG_LO_STATUS,
-				     &state->reg[MT2063_REG_LO_STATUS], 1);
-
-		if (status < 0)
-			return status;
-
-		if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) ==
-		    (LO1LK | LO2LK)) {
-			return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO;
-		}
-		msleep(nPollRate);	/*  Wait between retries  */
-	} while (++nDelays < nMaxLoops);
-
-	/*
-	 * Got no lock or partial lock
-	 */
-	return 0;
-}
-
-/*
- *  Constants for setting receiver modes.
- *  (6 modes defined at this time, enumerated by mt2063_delivery_sys)
- *  (DNC1GC & DNC2GC are the values, which are used, when the specific
- *   DNC Output is selected, the other is always off)
- *
- *                enum mt2063_delivery_sys
- * -------------+----------------------------------------------
- * Mode 0 :     | MT2063_CABLE_QAM
- * Mode 1 :     | MT2063_CABLE_ANALOG
- * Mode 2 :     | MT2063_OFFAIR_COFDM
- * Mode 3 :     | MT2063_OFFAIR_COFDM_SAWLESS
- * Mode 4 :     | MT2063_OFFAIR_ANALOG
- * Mode 5 :     | MT2063_OFFAIR_8VSB
- * --------------+----------------------------------------------
- *
- *                |<----------   Mode  -------------->|
- *    Reg Field   |  0  |  1  |  2  |  3  |  4  |  5  |
- *    ------------+-----+-----+-----+-----+-----+-----+
- *    RFAGCen     | OFF | OFF | OFF | OFF | OFF | OFF
- *    LNARin      |   0 |   0 |   3 |   3 |  3  |  3
- *    FIFFQen     |   1 |   1 |   1 |   1 |  1  |  1
- *    FIFFq       |   0 |   0 |   0 |   0 |  0  |  0
- *    DNC1gc      |   0 |   0 |   0 |   0 |  0  |  0
- *    DNC2gc      |   0 |   0 |   0 |   0 |  0  |  0
- *    GCU Auto    |   1 |   1 |   1 |   1 |  1  |  1
- *    LNA max Atn |  31 |  31 |  31 |  31 | 31  | 31
- *    LNA Target  |  44 |  43 |  43 |  43 | 43  | 43
- *    ign  RF Ovl |   0 |   0 |   0 |   0 |  0  |  0
- *    RF  max Atn |  31 |  31 |  31 |  31 | 31  | 31
- *    PD1 Target  |  36 |  36 |  38 |  38 | 36  | 38
- *    ign FIF Ovl |   0 |   0 |   0 |   0 |  0  |  0
- *    FIF max Atn |   5 |   5 |   5 |   5 |  5  |  5
- *    PD2 Target  |  40 |  33 |  42 |  42 | 33  | 42
- */
-
-enum mt2063_delivery_sys {
-	MT2063_CABLE_QAM = 0,
-	MT2063_CABLE_ANALOG,
-	MT2063_OFFAIR_COFDM,
-	MT2063_OFFAIR_COFDM_SAWLESS,
-	MT2063_OFFAIR_ANALOG,
-	MT2063_OFFAIR_8VSB,
-	MT2063_NUM_RCVR_MODES
-};
-
-static const char *mt2063_mode_name[] = {
-	[MT2063_CABLE_QAM]		= "digital cable",
-	[MT2063_CABLE_ANALOG]		= "analog cable",
-	[MT2063_OFFAIR_COFDM]		= "digital offair",
-	[MT2063_OFFAIR_COFDM_SAWLESS]	= "digital offair without SAW",
-	[MT2063_OFFAIR_ANALOG]		= "analog offair",
-	[MT2063_OFFAIR_8VSB]		= "analog offair 8vsb",
-};
-
-static const u8 RFAGCEN[]	= {  0,  0,  0,  0,  0,  0 };
-static const u8 LNARIN[]	= {  0,  0,  3,  3,  3,  3 };
-static const u8 FIFFQEN[]	= {  1,  1,  1,  1,  1,  1 };
-static const u8 FIFFQ[]		= {  0,  0,  0,  0,  0,  0 };
-static const u8 DNC1GC[]	= {  0,  0,  0,  0,  0,  0 };
-static const u8 DNC2GC[]	= {  0,  0,  0,  0,  0,  0 };
-static const u8 ACLNAMAX[]	= { 31, 31, 31, 31, 31, 31 };
-static const u8 LNATGT[]	= { 44, 43, 43, 43, 43, 43 };
-static const u8 RFOVDIS[]	= {  0,  0,  0,  0,  0,  0 };
-static const u8 ACRFMAX[]	= { 31, 31, 31, 31, 31, 31 };
-static const u8 PD1TGT[]	= { 36, 36, 38, 38, 36, 38 };
-static const u8 FIFOVDIS[]	= {  0,  0,  0,  0,  0,  0 };
-static const u8 ACFIFMAX[]	= { 29, 29, 29, 29, 29, 29 };
-static const u8 PD2TGT[]	= { 40, 33, 38, 42, 30, 38 };
-
-/*
- * mt2063_set_dnc_output_enable()
- */
-static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state,
-					enum MT2063_DNC_Output_Enable *pValue)
-{
-	dprintk(2, "\n");
-
-	if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) {	/* if DNC1 is off */
-		if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03)	/* if DNC2 is off */
-			*pValue = MT2063_DNC_NONE;
-		else
-			*pValue = MT2063_DNC_2;
-	} else {	/* DNC1 is on */
-		if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03)	/* if DNC2 is off */
-			*pValue = MT2063_DNC_1;
-		else
-			*pValue = MT2063_DNC_BOTH;
-	}
-	return 0;
-}
-
-/*
- * mt2063_set_dnc_output_enable()
- */
-static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state,
-					enum MT2063_DNC_Output_Enable nValue)
-{
-	u32 status = 0;	/* Status to be returned        */
-	u8 val = 0;
-
-	dprintk(2, "\n");
-
-	/* selects, which DNC output is used */
-	switch (nValue) {
-	case MT2063_DNC_NONE:
-		val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03;	/* Set DNC1GC=3 */
-		if (state->reg[MT2063_REG_DNC_GAIN] !=
-		    val)
-			status |=
-			    mt2063_setreg(state,
-					  MT2063_REG_DNC_GAIN,
-					  val);
-
-		val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03;	/* Set DNC2GC=3 */
-		if (state->reg[MT2063_REG_VGA_GAIN] !=
-		    val)
-			status |=
-			    mt2063_setreg(state,
-					  MT2063_REG_VGA_GAIN,
-					  val);
-
-		val = (state->reg[MT2063_REG_RSVD_20] & ~0x40);	/* Set PD2MUX=0 */
-		if (state->reg[MT2063_REG_RSVD_20] !=
-		    val)
-			status |=
-			    mt2063_setreg(state,
-					  MT2063_REG_RSVD_20,
-					  val);
-
-		break;
-	case MT2063_DNC_1:
-		val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03);	/* Set DNC1GC=x */
-		if (state->reg[MT2063_REG_DNC_GAIN] !=
-		    val)
-			status |=
-			    mt2063_setreg(state,
-					  MT2063_REG_DNC_GAIN,
-					  val);
-
-		val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03;	/* Set DNC2GC=3 */
-		if (state->reg[MT2063_REG_VGA_GAIN] !=
-		    val)
-			status |=
-			    mt2063_setreg(state,
-					  MT2063_REG_VGA_GAIN,
-					  val);
-
-		val = (state->reg[MT2063_REG_RSVD_20] & ~0x40);	/* Set PD2MUX=0 */
-		if (state->reg[MT2063_REG_RSVD_20] !=
-		    val)
-			status |=
-			    mt2063_setreg(state,
-					  MT2063_REG_RSVD_20,
-					  val);
-
-		break;
-	case MT2063_DNC_2:
-		val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03;	/* Set DNC1GC=3 */
-		if (state->reg[MT2063_REG_DNC_GAIN] !=
-		    val)
-			status |=
-			    mt2063_setreg(state,
-					  MT2063_REG_DNC_GAIN,
-					  val);
-
-		val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03);	/* Set DNC2GC=x */
-		if (state->reg[MT2063_REG_VGA_GAIN] !=
-		    val)
-			status |=
-			    mt2063_setreg(state,
-					  MT2063_REG_VGA_GAIN,
-					  val);
-
-		val = (state->reg[MT2063_REG_RSVD_20] | 0x40);	/* Set PD2MUX=1 */
-		if (state->reg[MT2063_REG_RSVD_20] !=
-		    val)
-			status |=
-			    mt2063_setreg(state,
-					  MT2063_REG_RSVD_20,
-					  val);
-
-		break;
-	case MT2063_DNC_BOTH:
-		val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03);	/* Set DNC1GC=x */
-		if (state->reg[MT2063_REG_DNC_GAIN] !=
-		    val)
-			status |=
-			    mt2063_setreg(state,
-					  MT2063_REG_DNC_GAIN,
-					  val);
-
-		val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03);	/* Set DNC2GC=x */
-		if (state->reg[MT2063_REG_VGA_GAIN] !=
-		    val)
-			status |=
-			    mt2063_setreg(state,
-					  MT2063_REG_VGA_GAIN,
-					  val);
-
-		val = (state->reg[MT2063_REG_RSVD_20] | 0x40);	/* Set PD2MUX=1 */
-		if (state->reg[MT2063_REG_RSVD_20] !=
-		    val)
-			status |=
-			    mt2063_setreg(state,
-					  MT2063_REG_RSVD_20,
-					  val);
-
-		break;
-	default:
-		break;
-	}
-
-	return status;
-}
-
-/*
- * MT2063_SetReceiverMode() - Set the MT2063 receiver mode, according with
- * 			      the selected enum mt2063_delivery_sys type.
- *
- *  (DNC1GC & DNC2GC are the values, which are used, when the specific
- *   DNC Output is selected, the other is always off)
- *
- * @state:	ptr to mt2063_state structure
- * @Mode:	desired reciever delivery system
- *
- * Note: Register cache must be valid for it to work
- */
-
-static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
-				  enum mt2063_delivery_sys Mode)
-{
-	u32 status = 0;	/* Status to be returned        */
-	u8 val;
-	u32 longval;
-
-	dprintk(2, "\n");
-
-	if (Mode >= MT2063_NUM_RCVR_MODES)
-		status = -ERANGE;
-
-	/* RFAGCen */
-	if (status >= 0) {
-		val =
-		    (state->
-		     reg[MT2063_REG_PD1_TGT] & (u8) ~0x40) | (RFAGCEN[Mode]
-								   ? 0x40 :
-								   0x00);
-		if (state->reg[MT2063_REG_PD1_TGT] != val)
-			status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
-	}
-
-	/* LNARin */
-	if (status >= 0) {
-		u8 val = (state->reg[MT2063_REG_CTRL_2C] & (u8) ~0x03) |
-			 (LNARIN[Mode] & 0x03);
-		if (state->reg[MT2063_REG_CTRL_2C] != val)
-			status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val);
-	}
-
-	/* FIFFQEN and FIFFQ */
-	if (status >= 0) {
-		val =
-		    (state->
-		     reg[MT2063_REG_FIFF_CTRL2] & (u8) ~0xF0) |
-		    (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
-		if (state->reg[MT2063_REG_FIFF_CTRL2] != val) {
-			status |=
-			    mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val);
-			/* trigger FIFF calibration, needed after changing FIFFQ */
-			val =
-			    (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01);
-			status |=
-			    mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
-			val =
-			    (state->
-			     reg[MT2063_REG_FIFF_CTRL] & (u8) ~0x01);
-			status |=
-			    mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
-		}
-	}
-
-	/* DNC1GC & DNC2GC */
-	status |= mt2063_get_dnc_output_enable(state, &longval);
-	status |= mt2063_set_dnc_output_enable(state, longval);
-
-	/* acLNAmax */
-	if (status >= 0) {
-		u8 val = (state->reg[MT2063_REG_LNA_OV] & (u8) ~0x1F) |
-			 (ACLNAMAX[Mode] & 0x1F);
-		if (state->reg[MT2063_REG_LNA_OV] != val)
-			status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val);
-	}
-
-	/* LNATGT */
-	if (status >= 0) {
-		u8 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x3F) |
-			 (LNATGT[Mode] & 0x3F);
-		if (state->reg[MT2063_REG_LNA_TGT] != val)
-			status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
-	}
-
-	/* ACRF */
-	if (status >= 0) {
-		u8 val = (state->reg[MT2063_REG_RF_OV] & (u8) ~0x1F) |
-			 (ACRFMAX[Mode] & 0x1F);
-		if (state->reg[MT2063_REG_RF_OV] != val)
-			status |= mt2063_setreg(state, MT2063_REG_RF_OV, val);
-	}
-
-	/* PD1TGT */
-	if (status >= 0) {
-		u8 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x3F) |
-			 (PD1TGT[Mode] & 0x3F);
-		if (state->reg[MT2063_REG_PD1_TGT] != val)
-			status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
-	}
-
-	/* FIFATN */
-	if (status >= 0) {
-		u8 val = ACFIFMAX[Mode];
-		if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5)
-			val = 5;
-		val = (state->reg[MT2063_REG_FIF_OV] & (u8) ~0x1F) |
-		      (val & 0x1F);
-		if (state->reg[MT2063_REG_FIF_OV] != val)
-			status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val);
-	}
-
-	/* PD2TGT */
-	if (status >= 0) {
-		u8 val = (state->reg[MT2063_REG_PD2_TGT] & (u8) ~0x3F) |
-		    (PD2TGT[Mode] & 0x3F);
-		if (state->reg[MT2063_REG_PD2_TGT] != val)
-			status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val);
-	}
-
-	/* Ignore ATN Overload */
-	if (status >= 0) {
-		val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x80) |
-		      (RFOVDIS[Mode] ? 0x80 : 0x00);
-		if (state->reg[MT2063_REG_LNA_TGT] != val)
-			status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
-	}
-
-	/* Ignore FIF Overload */
-	if (status >= 0) {
-		val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x80) |
-		      (FIFOVDIS[Mode] ? 0x80 : 0x00);
-		if (state->reg[MT2063_REG_PD1_TGT] != val)
-			status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
-	}
-
-	if (status >= 0) {
-		state->rcvr_mode = Mode;
-		dprintk(1, "mt2063 mode changed to %s\n",
-			mt2063_mode_name[state->rcvr_mode]);
-	}
-
-	return status;
-}
-
-/*
- * MT2063_ClearPowerMaskBits () - Clears the power-down mask bits for various
- *				  sections of the MT2063
- *
- * @Bits:		Mask bits to be cleared.
- *
- * See definition of MT2063_Mask_Bits type for description
- * of each of the power bits.
- */
-static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state,
-				     enum MT2063_Mask_Bits Bits)
-{
-	u32 status = 0;
-
-	dprintk(2, "\n");
-	Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD);	/* Only valid bits for this tuner */
-	if ((Bits & 0xFF00) != 0) {
-		state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8);
-		status |=
-		    mt2063_write(state,
-				    MT2063_REG_PWR_2,
-				    &state->reg[MT2063_REG_PWR_2], 1);
-	}
-	if ((Bits & 0xFF) != 0) {
-		state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF);
-		status |=
-		    mt2063_write(state,
-				    MT2063_REG_PWR_1,
-				    &state->reg[MT2063_REG_PWR_1], 1);
-	}
-
-	return status;
-}
-
-/*
- * MT2063_SoftwareShutdown() - Enables or disables software shutdown function.
- *			       When Shutdown is 1, any section whose power
- *			       mask is set will be shutdown.
- */
-static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown)
-{
-	u32 status;
-
-	dprintk(2, "\n");
-	if (Shutdown == 1)
-		state->reg[MT2063_REG_PWR_1] |= 0x04;
-	else
-		state->reg[MT2063_REG_PWR_1] &= ~0x04;
-
-	status = mt2063_write(state,
-			    MT2063_REG_PWR_1,
-			    &state->reg[MT2063_REG_PWR_1], 1);
-
-	if (Shutdown != 1) {
-		state->reg[MT2063_REG_BYP_CTRL] =
-		    (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40;
-		status |=
-		    mt2063_write(state,
-				    MT2063_REG_BYP_CTRL,
-				    &state->reg[MT2063_REG_BYP_CTRL],
-				    1);
-		state->reg[MT2063_REG_BYP_CTRL] =
-		    (state->reg[MT2063_REG_BYP_CTRL] & 0x9F);
-		status |=
-		    mt2063_write(state,
-				    MT2063_REG_BYP_CTRL,
-				    &state->reg[MT2063_REG_BYP_CTRL],
-				    1);
-	}
-
-	return status;
-}
-
-static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref)
-{
-	return f_ref * (f_LO / f_ref)
-	    + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step);
-}
-
-/**
- * fLO_FractionalTerm() - Calculates the portion contributed by FracN / denom.
- *                        This function preserves maximum precision without
- *                        risk of overflow.  It accurately calculates
- *                        f_ref * num / denom to within 1 HZ with fixed math.
- *
- * @num :	Fractional portion of the multiplier
- * @denom:	denominator portion of the ratio
- * @f_Ref:	SRO frequency.
- *
- * This calculation handles f_ref as two separate 14-bit fields.
- * Therefore, a maximum value of 2^28-1 may safely be used for f_ref.
- * This is the genesis of the magic number "14" and the magic mask value of
- * 0x03FFF.
- *
- * This routine successfully handles denom values up to and including 2^18.
- *  Returns:        f_ref * num / denom
- */
-static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom)
-{
-	u32 t1 = (f_ref >> 14) * num;
-	u32 term1 = t1 / denom;
-	u32 loss = t1 % denom;
-	u32 term2 =
-	    (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom;
-	return (term1 << 14) + term2;
-}
-
-/*
- * CalcLO1Mult()- Calculates Integer divider value and the numerator
- *                value for a FracN PLL.
- *
- *                This function assumes that the f_LO and f_Ref are
- *                evenly divisible by f_LO_Step.
- *
- * @Div:	OUTPUT: Whole number portion of the multiplier
- * @FracN:	OUTPUT: Fractional portion of the multiplier
- * @f_LO:	desired LO frequency.
- * @f_LO_Step:	Minimum step size for the LO (in Hz).
- * @f_Ref:	SRO frequency.
- * @f_Avoid:	Range of PLL frequencies to avoid near integer multiples
- *		of f_Ref (in Hz).
- *
- * Returns:        Recalculated LO frequency.
- */
-static u32 MT2063_CalcLO1Mult(u32 *Div,
-			      u32 *FracN,
-			      u32 f_LO,
-			      u32 f_LO_Step, u32 f_Ref)
-{
-	/*  Calculate the whole number portion of the divider */
-	*Div = f_LO / f_Ref;
-
-	/*  Calculate the numerator value (round to nearest f_LO_Step) */
-	*FracN =
-	    (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
-	     (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
-
-	return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64);
-}
-
-/**
- * CalcLO2Mult() - Calculates Integer divider value and the numerator
- *                 value for a FracN PLL.
- *
- *                  This function assumes that the f_LO and f_Ref are
- *                  evenly divisible by f_LO_Step.
- *
- * @Div:	OUTPUT: Whole number portion of the multiplier
- * @FracN:	OUTPUT: Fractional portion of the multiplier
- * @f_LO:	desired LO frequency.
- * @f_LO_Step:	Minimum step size for the LO (in Hz).
- * @f_Ref:	SRO frequency.
- * @f_Avoid:	Range of PLL frequencies to avoid near
- *		integer multiples of f_Ref (in Hz).
- *
- * Returns: Recalculated LO frequency.
- */
-static u32 MT2063_CalcLO2Mult(u32 *Div,
-			      u32 *FracN,
-			      u32 f_LO,
-			      u32 f_LO_Step, u32 f_Ref)
-{
-	/*  Calculate the whole number portion of the divider */
-	*Div = f_LO / f_Ref;
-
-	/*  Calculate the numerator value (round to nearest f_LO_Step) */
-	*FracN =
-	    (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
-	     (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
-
-	return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN,
-							    8191);
-}
-
-/*
- * FindClearTuneFilter() - Calculate the corrrect ClearTune filter to be
- *			   used for a given input frequency.
- *
- * @state:	ptr to tuner data structure
- * @f_in:	RF input center frequency (in Hz).
- *
- * Returns: ClearTune filter number (0-31)
- */
-static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in)
-{
-	u32 RFBand;
-	u32 idx;		/*  index loop                      */
-
-	/*
-	 **  Find RF Band setting
-	 */
-	RFBand = 31;		/*  def when f_in > all    */
-	for (idx = 0; idx < 31; ++idx) {
-		if (state->CTFiltMax[idx] >= f_in) {
-			RFBand = idx;
-			break;
-		}
-	}
-	return RFBand;
-}
-
-/*
- * MT2063_Tune() - Change the tuner's tuned frequency to RFin.
- */
-static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in)
-{				/* RF input center frequency   */
-
-	u32 status = 0;
-	u32 LO1;		/*  1st LO register value           */
-	u32 Num1;		/*  Numerator for LO1 reg. value    */
-	u32 f_IF1;		/*  1st IF requested                */
-	u32 LO2;		/*  2nd LO register value           */
-	u32 Num2;		/*  Numerator for LO2 reg. value    */
-	u32 ofLO1, ofLO2;	/*  last time's LO frequencies      */
-	u8 fiffc = 0x80;	/*  FIFF center freq from tuner     */
-	u32 fiffof;		/*  Offset from FIFF center freq    */
-	const u8 LO1LK = 0x80;	/*  Mask for LO1 Lock bit           */
-	u8 LO2LK = 0x08;	/*  Mask for LO2 Lock bit           */
-	u8 val;
-	u32 RFBand;
-
-	dprintk(2, "\n");
-	/*  Check the input and output frequency ranges                   */
-	if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ))
-		return -EINVAL;
-
-	if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ)
-	    || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ))
-		return -EINVAL;
-
-	/*
-	 * Save original LO1 and LO2 register values
-	 */
-	ofLO1 = state->AS_Data.f_LO1;
-	ofLO2 = state->AS_Data.f_LO2; 
-
-	/*
-	 * Find and set RF Band setting
-	 */
-	if (state->ctfilt_sw == 1) {
-		val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08);
-		if (state->reg[MT2063_REG_CTUNE_CTRL] != val) {
-			status |=
-			    mt2063_setreg(state, MT2063_REG_CTUNE_CTRL, val);
-		}
-		val = state->reg[MT2063_REG_CTUNE_OV];
-		RFBand = FindClearTuneFilter(state, f_in);
-		state->reg[MT2063_REG_CTUNE_OV] =
-		    (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F)
-			      | RFBand);
-		if (state->reg[MT2063_REG_CTUNE_OV] != val) {
-			status |=
-			    mt2063_setreg(state, MT2063_REG_CTUNE_OV, val);
-		}
-	}
-
-	/*
-	 * Read the FIFF Center Frequency from the tuner
-	 */
-	if (status >= 0) {
-		status |=
-		    mt2063_read(state,
-				   MT2063_REG_FIFFC,
-				   &state->reg[MT2063_REG_FIFFC], 1);
-		fiffc = state->reg[MT2063_REG_FIFFC];
-	}
-	/*
-	 * Assign in the requested values
-	 */
-	state->AS_Data.f_in = f_in;
-	/*  Request a 1st IF such that LO1 is on a step size */
-	state->AS_Data.f_if1_Request =
-	    MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in,
-			     state->AS_Data.f_LO1_Step,
-			     state->AS_Data.f_ref) - f_in;
-
-	/*
-	 * Calculate frequency settings.  f_IF1_FREQ + f_in is the
-	 * desired LO1 frequency
-	 */
-	MT2063_ResetExclZones(&state->AS_Data);
-
-	f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data);
-
-	state->AS_Data.f_LO1 =
-	    MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step,
-			     state->AS_Data.f_ref);
-
-	state->AS_Data.f_LO2 =
-	    MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
-			     state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
-
-	/*
-	 * Check for any LO spurs in the output bandwidth and adjust
-	 * the LO settings to avoid them if needed
-	 */
-	status |= MT2063_AvoidSpurs(&state->AS_Data);
-	/*
-	 * MT_AvoidSpurs spurs may have changed the LO1 & LO2 values.
-	 * Recalculate the LO frequencies and the values to be placed
-	 * in the tuning registers.
-	 */
-	state->AS_Data.f_LO1 =
-	    MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1,
-			       state->AS_Data.f_LO1_Step, state->AS_Data.f_ref);
-	state->AS_Data.f_LO2 =
-	    MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
-			     state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
-	state->AS_Data.f_LO2 =
-	    MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2,
-			       state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
-
-	/*
-	 *  Check the upconverter and downconverter frequency ranges
-	 */
-	if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ)
-	    || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ))
-		status |= MT2063_UPC_RANGE;
-	if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ)
-	    || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ))
-		status |= MT2063_DNC_RANGE;
-	/*  LO2 Lock bit was in a different place for B0 version  */
-	if (state->tuner_id == MT2063_B0)
-		LO2LK = 0x40;
-
-	/*
-	 *  If we have the same LO frequencies and we're already locked,
-	 *  then skip re-programming the LO registers.
-	 */
-	if ((ofLO1 != state->AS_Data.f_LO1)
-	    || (ofLO2 != state->AS_Data.f_LO2)
-	    || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) !=
-		(LO1LK | LO2LK))) {
-		/*
-		 * Calculate the FIFFOF register value
-		 *
-		 *           IF1_Actual
-		 * FIFFOF = ------------ - 8 * FIFFC - 4992
-		 *            f_ref/64
-		 */
-		fiffof =
-		    (state->AS_Data.f_LO1 -
-		     f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc -
-		    4992;
-		if (fiffof > 0xFF)
-			fiffof = 0xFF;
-
-		/*
-		 * Place all of the calculated values into the local tuner
-		 * register fields.
-		 */
-		if (status >= 0) {
-			state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF);	/* DIV1q */
-			state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F);	/* NUM1q */
-			state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1)	/* DIV2q */
-								   |(Num2 >> 12));	/* NUM2q (hi) */
-			state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4);	/* NUM2q (mid) */
-			state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F));	/* NUM2q (lo) */
-
-			/*
-			 * Now write out the computed register values
-			 * IMPORTANT: There is a required order for writing
-			 *            (0x05 must follow all the others).
-			 */
-			status |= mt2063_write(state, MT2063_REG_LO1CQ_1, &state->reg[MT2063_REG_LO1CQ_1], 5);	/* 0x01 - 0x05 */
-			if (state->tuner_id == MT2063_B0) {
-				/* Re-write the one-shot bits to trigger the tune operation */
-				status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1);	/* 0x05 */
-			}
-			/* Write out the FIFF offset only if it's changing */
-			if (state->reg[MT2063_REG_FIFF_OFFSET] !=
-			    (u8) fiffof) {
-				state->reg[MT2063_REG_FIFF_OFFSET] =
-				    (u8) fiffof;
-				status |=
-				    mt2063_write(state,
-						    MT2063_REG_FIFF_OFFSET,
-						    &state->
-						    reg[MT2063_REG_FIFF_OFFSET],
-						    1);
-			}
-		}
-
-		/*
-		 * Check for LO's locking
-		 */
-
-		if (status < 0)
-			return status;
-
-		status = mt2063_lockStatus(state);
-		if (status < 0)
-			return status;
-		if (!status)
-			return -EINVAL;		/* Couldn't lock */
-
-		/*
-		 * If we locked OK, assign calculated data to mt2063_state structure
-		 */
-		state->f_IF1_actual = state->AS_Data.f_LO1 - f_in;
-	}
-
-	return status;
-}
-
-static const u8 MT2063B0_defaults[] = {
-	/* Reg,  Value */
-	0x19, 0x05,
-	0x1B, 0x1D,
-	0x1C, 0x1F,
-	0x1D, 0x0F,
-	0x1E, 0x3F,
-	0x1F, 0x0F,
-	0x20, 0x3F,
-	0x22, 0x21,
-	0x23, 0x3F,
-	0x24, 0x20,
-	0x25, 0x3F,
-	0x27, 0xEE,
-	0x2C, 0x27,	/*  bit at 0x20 is cleared below  */
-	0x30, 0x03,
-	0x2C, 0x07,	/*  bit at 0x20 is cleared here   */
-	0x2D, 0x87,
-	0x2E, 0xAA,
-	0x28, 0xE1,	/*  Set the FIFCrst bit here      */
-	0x28, 0xE0,	/*  Clear the FIFCrst bit here    */
-	0x00
-};
-
-/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
-static const u8 MT2063B1_defaults[] = {
-	/* Reg,  Value */
-	0x05, 0xF0,
-	0x11, 0x10,	/* New Enable AFCsd */
-	0x19, 0x05,
-	0x1A, 0x6C,
-	0x1B, 0x24,
-	0x1C, 0x28,
-	0x1D, 0x8F,
-	0x1E, 0x14,
-	0x1F, 0x8F,
-	0x20, 0x57,
-	0x22, 0x21,	/* New - ver 1.03 */
-	0x23, 0x3C,	/* New - ver 1.10 */
-	0x24, 0x20,	/* New - ver 1.03 */
-	0x2C, 0x24,	/*  bit at 0x20 is cleared below  */
-	0x2D, 0x87,	/*  FIFFQ=0  */
-	0x2F, 0xF3,
-	0x30, 0x0C,	/* New - ver 1.11 */
-	0x31, 0x1B,	/* New - ver 1.11 */
-	0x2C, 0x04,	/*  bit at 0x20 is cleared here  */
-	0x28, 0xE1,	/*  Set the FIFCrst bit here      */
-	0x28, 0xE0,	/*  Clear the FIFCrst bit here    */
-	0x00
-};
-
-/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
-static const u8 MT2063B3_defaults[] = {
-	/* Reg,  Value */
-	0x05, 0xF0,
-	0x19, 0x3D,
-	0x2C, 0x24,	/*  bit at 0x20 is cleared below  */
-	0x2C, 0x04,	/*  bit at 0x20 is cleared here  */
-	0x28, 0xE1,	/*  Set the FIFCrst bit here      */
-	0x28, 0xE0,	/*  Clear the FIFCrst bit here    */
-	0x00
-};
-
-static int mt2063_init(struct dvb_frontend *fe)
-{
-	u32 status;
-	struct mt2063_state *state = fe->tuner_priv;
-	u8 all_resets = 0xF0;	/* reset/load bits */
-	const u8 *def = NULL;
-	char *step;
-	u32 FCRUN;
-	s32 maxReads;
-	u32 fcu_osc;
-	u32 i;
-
-	dprintk(2, "\n");
-
-	state->rcvr_mode = MT2063_CABLE_QAM;
-
-	/*  Read the Part/Rev code from the tuner */
-	status = mt2063_read(state, MT2063_REG_PART_REV,
-			     &state->reg[MT2063_REG_PART_REV], 1);
-	if (status < 0) {
-		printk(KERN_ERR "Can't read mt2063 part ID\n");
-		return status;
-	}
-
-	/* Check the part/rev code */
-	switch (state->reg[MT2063_REG_PART_REV]) {
-	case MT2063_B0:
-		step = "B0";
-		break;
-	case MT2063_B1:
-		step = "B1";
-		break;
-	case MT2063_B2:
-		step = "B2";
-		break;
-	case MT2063_B3:
-		step = "B3";
-		break;
-	default:
-		printk(KERN_ERR "mt2063: Unknown mt2063 device ID (0x%02x)\n",
-		       state->reg[MT2063_REG_PART_REV]);
-		return -ENODEV;	/*  Wrong tuner Part/Rev code */
-	}
-
-	/*  Check the 2nd byte of the Part/Rev code from the tuner */
-	status = mt2063_read(state, MT2063_REG_RSVD_3B,
-			     &state->reg[MT2063_REG_RSVD_3B], 1);
-
-	/* b7 != 0 ==> NOT MT2063 */
-	if (status < 0 || ((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) {
-		printk(KERN_ERR "mt2063: Unknown part ID (0x%02x%02x)\n",
-		       state->reg[MT2063_REG_PART_REV],
-		       state->reg[MT2063_REG_RSVD_3B]);
-		return -ENODEV;	/*  Wrong tuner Part/Rev code */
-	}
-
-	printk(KERN_INFO "mt2063: detected a mt2063 %s\n", step);
-
-	/*  Reset the tuner  */
-	status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1);
-	if (status < 0)
-		return status;
-
-	/* change all of the default values that vary from the HW reset values */
-	/*  def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */
-	switch (state->reg[MT2063_REG_PART_REV]) {
-	case MT2063_B3:
-		def = MT2063B3_defaults;
-		break;
-
-	case MT2063_B1:
-		def = MT2063B1_defaults;
-		break;
-
-	case MT2063_B0:
-		def = MT2063B0_defaults;
-		break;
-
-	default:
-		return -ENODEV;
-		break;
-	}
-
-	while (status >= 0 && *def) {
-		u8 reg = *def++;
-		u8 val = *def++;
-		status = mt2063_write(state, reg, &val, 1);
-	}
-	if (status < 0)
-		return status;
-
-	/*  Wait for FIFF location to complete.  */
-	FCRUN = 1;
-	maxReads = 10;
-	while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) {
-		msleep(2);
-		status = mt2063_read(state,
-					 MT2063_REG_XO_STATUS,
-					 &state->
-					 reg[MT2063_REG_XO_STATUS], 1);
-		FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6;
-	}
-
-	if (FCRUN != 0 || status < 0)
-		return -ENODEV;
-
-	status = mt2063_read(state,
-			   MT2063_REG_FIFFC,
-			   &state->reg[MT2063_REG_FIFFC], 1);
-	if (status < 0)
-		return status;
-
-	/* Read back all the registers from the tuner */
-	status = mt2063_read(state,
-				MT2063_REG_PART_REV,
-				state->reg, MT2063_REG_END_REGS);
-	if (status < 0)
-		return status;
-
-	/*  Initialize the tuner state.  */
-	state->tuner_id = state->reg[MT2063_REG_PART_REV];
-	state->AS_Data.f_ref = MT2063_REF_FREQ;
-	state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) *
-				      ((u32) state->reg[MT2063_REG_FIFFC] + 640);
-	state->AS_Data.f_if1_bw = MT2063_IF1_BW;
-	state->AS_Data.f_out = 43750000UL;
-	state->AS_Data.f_out_bw = 6750000UL;
-	state->AS_Data.f_zif_bw = MT2063_ZIF_BW;
-	state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64;
-	state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE;
-	state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1;
-	state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2;
-	state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP;
-	state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center;
-	state->AS_Data.f_LO1 = 2181000000UL;
-	state->AS_Data.f_LO2 = 1486249786UL;
-	state->f_IF1_actual = state->AS_Data.f_if1_Center;
-	state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual;
-	state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID;
-	state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID;
-	state->num_regs = MT2063_REG_END_REGS;
-	state->AS_Data.avoidDECT = MT2063_AVOID_BOTH;
-	state->ctfilt_sw = 0;
-
-	state->CTFiltMax[0] = 69230000;
-	state->CTFiltMax[1] = 105770000;
-	state->CTFiltMax[2] = 140350000;
-	state->CTFiltMax[3] = 177110000;
-	state->CTFiltMax[4] = 212860000;
-	state->CTFiltMax[5] = 241130000;
-	state->CTFiltMax[6] = 274370000;
-	state->CTFiltMax[7] = 309820000;
-	state->CTFiltMax[8] = 342450000;
-	state->CTFiltMax[9] = 378870000;
-	state->CTFiltMax[10] = 416210000;
-	state->CTFiltMax[11] = 456500000;
-	state->CTFiltMax[12] = 495790000;
-	state->CTFiltMax[13] = 534530000;
-	state->CTFiltMax[14] = 572610000;
-	state->CTFiltMax[15] = 598970000;
-	state->CTFiltMax[16] = 635910000;
-	state->CTFiltMax[17] = 672130000;
-	state->CTFiltMax[18] = 714840000;
-	state->CTFiltMax[19] = 739660000;
-	state->CTFiltMax[20] = 770410000;
-	state->CTFiltMax[21] = 814660000;
-	state->CTFiltMax[22] = 846950000;
-	state->CTFiltMax[23] = 867820000;
-	state->CTFiltMax[24] = 915980000;
-	state->CTFiltMax[25] = 947450000;
-	state->CTFiltMax[26] = 983110000;
-	state->CTFiltMax[27] = 1021630000;
-	state->CTFiltMax[28] = 1061870000;
-	state->CTFiltMax[29] = 1098330000;
-	state->CTFiltMax[30] = 1138990000;
-
-	/*
-	 **   Fetch the FCU osc value and use it and the fRef value to
-	 **   scale all of the Band Max values
-	 */
-
-	state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A;
-	status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
-			      &state->reg[MT2063_REG_CTUNE_CTRL], 1);
-	if (status < 0)
-		return status;
-
-	/*  Read the ClearTune filter calibration value  */
-	status = mt2063_read(state, MT2063_REG_FIFFC,
-			     &state->reg[MT2063_REG_FIFFC], 1);
-	if (status < 0)
-		return status;
-
-	fcu_osc = state->reg[MT2063_REG_FIFFC];
-
-	state->reg[MT2063_REG_CTUNE_CTRL] = 0x00;
-	status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
-			      &state->reg[MT2063_REG_CTUNE_CTRL], 1);
-	if (status < 0)
-		return status;
-
-	/*  Adjust each of the values in the ClearTune filter cross-over table  */
-	for (i = 0; i < 31; i++)
-		state->CTFiltMax[i] = (state->CTFiltMax[i] / 768) * (fcu_osc + 640);
-
-	status = MT2063_SoftwareShutdown(state, 1);
-	if (status < 0)
-		return status;
-	status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
-	if (status < 0)
-		return status;
-
-	state->init = true;
-
-	return 0;
-}
-
-static int mt2063_get_status(struct dvb_frontend *fe, u32 *tuner_status)
-{
-	struct mt2063_state *state = fe->tuner_priv;
-	int status;
-
-	dprintk(2, "\n");
-
-	if (!state->init)
-		return -ENODEV;
-
-	*tuner_status = 0;
-	status = mt2063_lockStatus(state);
-	if (status < 0)
-		return status;
-	if (status)
-		*tuner_status = TUNER_STATUS_LOCKED;
-
-	dprintk(1, "Tuner status: %d", *tuner_status);
-
-	return 0;
-}
-
-static int mt2063_release(struct dvb_frontend *fe)
-{
-	struct mt2063_state *state = fe->tuner_priv;
-
-	dprintk(2, "\n");
-
-	fe->tuner_priv = NULL;
-	kfree(state);
-
-	return 0;
-}
-
-static int mt2063_set_analog_params(struct dvb_frontend *fe,
-				    struct analog_parameters *params)
-{
-	struct mt2063_state *state = fe->tuner_priv;
-	s32 pict_car;
-	s32 pict2chanb_vsb;
-	s32 ch_bw;
-	s32 if_mid;
-	s32 rcvr_mode;
-	int status;
-
-	dprintk(2, "\n");
-
-	if (!state->init) {
-		status = mt2063_init(fe);
-		if (status < 0)
-			return status;
-	}
-
-	switch (params->mode) {
-	case V4L2_TUNER_RADIO:
-		pict_car = 38900000;
-		ch_bw = 8000000;
-		pict2chanb_vsb = -(ch_bw / 2);
-		rcvr_mode = MT2063_OFFAIR_ANALOG;
-		break;
-	case V4L2_TUNER_ANALOG_TV:
-		rcvr_mode = MT2063_CABLE_ANALOG;
-		if (params->std & ~V4L2_STD_MN) {
-			pict_car = 38900000;
-			ch_bw = 6000000;
-			pict2chanb_vsb = -1250000;
-		} else if (params->std & V4L2_STD_PAL_G) {
-			pict_car = 38900000;
-			ch_bw = 7000000;
-			pict2chanb_vsb = -1250000;
-		} else {		/* PAL/SECAM standards */
-			pict_car = 38900000;
-			ch_bw = 8000000;
-			pict2chanb_vsb = -1250000;
-		}
-		break;
-	default:
-		return -EINVAL;
-	}
-	if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
-
-	state->AS_Data.f_LO2_Step = 125000;	/* FIXME: probably 5000 for FM */
-	state->AS_Data.f_out = if_mid;
-	state->AS_Data.f_out_bw = ch_bw + 750000;
-	status = MT2063_SetReceiverMode(state, rcvr_mode);
-	if (status < 0)
-		return status;
-
-	dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n",
-		params->frequency, ch_bw, pict2chanb_vsb);
-
-	status = MT2063_Tune(state, (params->frequency + (pict2chanb_vsb + (ch_bw / 2))));
-	if (status < 0)
-		return status;
-
-	state->frequency = params->frequency;
-	return 0;
-}
-
-/*
- * As defined on EN 300 429, the DVB-C roll-off factor is 0.15.
- * So, the amount of the needed bandwith is given by:
- *	Bw = Symbol_rate * (1 + 0.15)
- * As such, the maximum symbol rate supported by 6 MHz is given by:
- *	max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds
- */
-#define MAX_SYMBOL_RATE_6MHz	5217391
-
-static int mt2063_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct mt2063_state *state = fe->tuner_priv;
-	int status;
-	s32 pict_car;
-	s32 pict2chanb_vsb;
-	s32 ch_bw;
-	s32 if_mid;
-	s32 rcvr_mode;
-
-	if (!state->init) {
-		status = mt2063_init(fe);
-		if (status < 0)
-			return status;
-	}
-
-	dprintk(2, "\n");
-
-	if (c->bandwidth_hz == 0)
-		return -EINVAL;
-	if (c->bandwidth_hz <= 6000000)
-		ch_bw = 6000000;
-	else if (c->bandwidth_hz <= 7000000)
-		ch_bw = 7000000;
-	else
-		ch_bw = 8000000;
-
-	switch (c->delivery_system) {
-	case SYS_DVBT:
-		rcvr_mode = MT2063_OFFAIR_COFDM;
-		pict_car = 36125000;
-		pict2chanb_vsb = -(ch_bw / 2);
-		break;
-	case SYS_DVBC_ANNEX_A:
-	case SYS_DVBC_ANNEX_C:
-		rcvr_mode = MT2063_CABLE_QAM;
-		pict_car = 36125000;
-		pict2chanb_vsb = -(ch_bw / 2);
-		break;
-	default:
-		return -EINVAL;
-	}
-	if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
-
-	state->AS_Data.f_LO2_Step = 125000;	/* FIXME: probably 5000 for FM */
-	state->AS_Data.f_out = if_mid;
-	state->AS_Data.f_out_bw = ch_bw + 750000;
-	status = MT2063_SetReceiverMode(state, rcvr_mode);
-	if (status < 0)
-		return status;
-
-	dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n",
-		c->frequency, ch_bw, pict2chanb_vsb);
-
-	status = MT2063_Tune(state, (c->frequency + (pict2chanb_vsb + (ch_bw / 2))));
-
-	if (status < 0)
-		return status;
-
-	state->frequency = c->frequency;
-	return 0;
-}
-
-static int mt2063_get_if_frequency(struct dvb_frontend *fe, u32 *freq)
-{
-	struct mt2063_state *state = fe->tuner_priv;
-
-	dprintk(2, "\n");
-
-	if (!state->init)
-		return -ENODEV;
-
-	*freq = state->AS_Data.f_out;
-
-	dprintk(1, "IF frequency: %d\n", *freq);
-
-	return 0;
-}
-
-static int mt2063_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
-{
-	struct mt2063_state *state = fe->tuner_priv;
-
-	dprintk(2, "\n");
-
-	if (!state->init)
-		return -ENODEV;
-
-	*bw = state->AS_Data.f_out_bw - 750000;
-
-	dprintk(1, "bandwidth: %d\n", *bw);
-
-	return 0;
-}
-
-static struct dvb_tuner_ops mt2063_ops = {
-	.info = {
-		 .name = "MT2063 Silicon Tuner",
-		 .frequency_min = 45000000,
-		 .frequency_max = 865000000,
-		 .frequency_step = 0,
-		 },
-
-	.init = mt2063_init,
-	.sleep = MT2063_Sleep,
-	.get_status = mt2063_get_status,
-	.set_analog_params = mt2063_set_analog_params,
-	.set_params    = mt2063_set_params,
-	.get_if_frequency = mt2063_get_if_frequency,
-	.get_bandwidth = mt2063_get_bandwidth,
-	.release = mt2063_release,
-};
-
-struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
-				   struct mt2063_config *config,
-				   struct i2c_adapter *i2c)
-{
-	struct mt2063_state *state = NULL;
-
-	dprintk(2, "\n");
-
-	state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	state->config = config;
-	state->i2c = i2c;
-	state->frontend = fe;
-	state->reference = config->refclock / 1000;	/* kHz */
-	fe->tuner_priv = state;
-	fe->ops.tuner_ops = mt2063_ops;
-
-	printk(KERN_INFO "%s: Attaching MT2063\n", __func__);
-	return fe;
-
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL_GPL(mt2063_attach);
-
-/*
- * Ancillary routines visible outside mt2063
- * FIXME: Remove them in favor of using standard tuner callbacks
- */
-unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe)
-{
-	struct mt2063_state *state = fe->tuner_priv;
-	int err = 0;
-
-	dprintk(2, "\n");
-
-	err = MT2063_SoftwareShutdown(state, 1);
-	if (err < 0)
-		printk(KERN_ERR "%s: Couldn't shutdown\n", __func__);
-
-	return err;
-}
-EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown);
-
-unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe)
-{
-	struct mt2063_state *state = fe->tuner_priv;
-	int err = 0;
-
-	dprintk(2, "\n");
-
-	err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
-	if (err < 0)
-		printk(KERN_ERR "%s: Invalid parameter\n", __func__);
-
-	return err;
-}
-EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits);
-
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_DESCRIPTION("MT2063 Silicon tuner");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/mt2063.h b/drivers/media/common/tuners/mt2063.h
deleted file mode 100644
index 3f5cfd9..0000000
--- a/drivers/media/common/tuners/mt2063.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef __MT2063_H__
-#define __MT2063_H__
-
-#include "dvb_frontend.h"
-
-struct mt2063_config {
-	u8 tuner_address;
-	u32 refclock;
-};
-
-#if defined(CONFIG_MEDIA_TUNER_MT2063) || (defined(CONFIG_MEDIA_TUNER_MT2063_MODULE) && defined(MODULE))
-struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
-				   struct mt2063_config *config,
-				   struct i2c_adapter *i2c);
-
-#else
-
-static inline struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
-				   struct mt2063_config *config,
-				   struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-/* FIXME: Should use the standard DVB attachment interfaces */
-unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe);
-unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe);
-
-#endif /* CONFIG_DVB_MT2063 */
-
-#endif /* __MT2063_H__ */
diff --git a/drivers/media/common/tuners/mt20xx.c b/drivers/media/common/tuners/mt20xx.c
deleted file mode 100644
index 0e74e97..0000000
--- a/drivers/media/common/tuners/mt20xx.c
+++ /dev/null
@@ -1,670 +0,0 @@
-/*
- * i2c tv tuner chip device driver
- * controls microtune tuners, mt2032 + mt2050 at the moment.
- *
- * This "mt20xx" module was split apart from the original "tuner" module.
- */
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include "tuner-i2c.h"
-#include "mt20xx.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-/* ---------------------------------------------------------------------- */
-
-static unsigned int optimize_vco  = 1;
-module_param(optimize_vco,      int, 0644);
-
-static unsigned int tv_antenna    = 1;
-module_param(tv_antenna,        int, 0644);
-
-static unsigned int radio_antenna;
-module_param(radio_antenna,     int, 0644);
-
-/* ---------------------------------------------------------------------- */
-
-#define MT2032 0x04
-#define MT2030 0x06
-#define MT2040 0x07
-#define MT2050 0x42
-
-static char *microtune_part[] = {
-	[ MT2030 ] = "MT2030",
-	[ MT2032 ] = "MT2032",
-	[ MT2040 ] = "MT2040",
-	[ MT2050 ] = "MT2050",
-};
-
-struct microtune_priv {
-	struct tuner_i2c_props i2c_props;
-
-	unsigned int xogc;
-	//unsigned int radio_if2;
-
-	u32 frequency;
-};
-
-static int microtune_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-
-	return 0;
-}
-
-static int microtune_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct microtune_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-	return 0;
-}
-
-// IsSpurInBand()?
-static int mt2032_spurcheck(struct dvb_frontend *fe,
-			    int f1, int f2, int spectrum_from,int spectrum_to)
-{
-	struct microtune_priv *priv = fe->tuner_priv;
-	int n1=1,n2,f;
-
-	f1=f1/1000; //scale to kHz to avoid 32bit overflows
-	f2=f2/1000;
-	spectrum_from/=1000;
-	spectrum_to/=1000;
-
-	tuner_dbg("spurcheck f1=%d f2=%d  from=%d to=%d\n",
-		  f1,f2,spectrum_from,spectrum_to);
-
-	do {
-	    n2=-n1;
-	    f=n1*(f1-f2);
-	    do {
-		n2--;
-		f=f-f2;
-		tuner_dbg("spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f);
-
-		if( (f>spectrum_from) && (f<spectrum_to))
-			tuner_dbg("mt2032 spurcheck triggered: %d\n",n1);
-	    } while ( (f>(f2-spectrum_to)) || (n2>-5));
-	    n1++;
-	} while (n1<5);
-
-	return 1;
-}
-
-static int mt2032_compute_freq(struct dvb_frontend *fe,
-			       unsigned int rfin,
-			       unsigned int if1, unsigned int if2,
-			       unsigned int spectrum_from,
-			       unsigned int spectrum_to,
-			       unsigned char *buf,
-			       int *ret_sel,
-			       unsigned int xogc) //all in Hz
-{
-	struct microtune_priv *priv = fe->tuner_priv;
-	unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
-		desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq;
-
-	fref= 5250 *1000; //5.25MHz
-	desired_lo1=rfin+if1;
-
-	lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000);
-	lo1n=lo1/8;
-	lo1a=lo1-(lo1n*8);
-
-	s=rfin/1000/1000+1090;
-
-	if(optimize_vco) {
-		if(s>1890) sel=0;
-		else if(s>1720) sel=1;
-		else if(s>1530) sel=2;
-		else if(s>1370) sel=3;
-		else sel=4; // >1090
-	}
-	else {
-		if(s>1790) sel=0; // <1958
-		else if(s>1617) sel=1;
-		else if(s>1449) sel=2;
-		else if(s>1291) sel=3;
-		else sel=4; // >1090
-	}
-	*ret_sel=sel;
-
-	lo1freq=(lo1a+8*lo1n)*fref;
-
-	tuner_dbg("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n",
-		  rfin,lo1,lo1n,lo1a,sel,lo1freq);
-
-	desired_lo2=lo1freq-rfin-if2;
-	lo2=(desired_lo2)/fref;
-	lo2n=lo2/8;
-	lo2a=lo2-(lo2n*8);
-	lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith
-	lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000;
-
-	tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n",
-		  rfin,lo2,lo2n,lo2a,lo2num,lo2freq);
-
-	if (lo1a > 7 || lo1n < 17 || lo1n > 48 || lo2a > 7 || lo2n < 17 ||
-			lo2n > 30) {
-		tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n",
-			   lo1a, lo1n, lo2a,lo2n);
-		return(-1);
-	}
-
-	mt2032_spurcheck(fe, lo1freq, desired_lo2,  spectrum_from, spectrum_to);
-	// should recalculate lo1 (one step up/down)
-
-	// set up MT2032 register map for transfer over i2c
-	buf[0]=lo1n-1;
-	buf[1]=lo1a | (sel<<4);
-	buf[2]=0x86; // LOGC
-	buf[3]=0x0f; //reserved
-	buf[4]=0x1f;
-	buf[5]=(lo2n-1) | (lo2a<<5);
-	if(rfin >400*1000*1000)
-		buf[6]=0xe4;
-	else
-		buf[6]=0xf4; // set PKEN per rev 1.2
-	buf[7]=8+xogc;
-	buf[8]=0xc3; //reserved
-	buf[9]=0x4e; //reserved
-	buf[10]=0xec; //reserved
-	buf[11]=(lo2num&0xff);
-	buf[12]=(lo2num>>8) |0x80; // Lo2RST
-
-	return 0;
-}
-
-static int mt2032_check_lo_lock(struct dvb_frontend *fe)
-{
-	struct microtune_priv *priv = fe->tuner_priv;
-	int try,lock=0;
-	unsigned char buf[2];
-
-	for(try=0;try<10;try++) {
-		buf[0]=0x0e;
-		tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
-		tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
-		tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]);
-		lock=buf[0] &0x06;
-
-		if (lock==6)
-			break;
-
-		tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]);
-		udelay(1000);
-	}
-	return lock;
-}
-
-static int mt2032_optimize_vco(struct dvb_frontend *fe,int sel,int lock)
-{
-	struct microtune_priv *priv = fe->tuner_priv;
-	unsigned char buf[2];
-	int tad1;
-
-	buf[0]=0x0f;
-	tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
-	tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
-	tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]);
-	tad1=buf[0]&0x07;
-
-	if(tad1 ==0) return lock;
-	if(tad1 ==1) return lock;
-
-	if(tad1==2) {
-		if(sel==0)
-			return lock;
-		else sel--;
-	}
-	else {
-		if(sel<4)
-			sel++;
-		else
-			return lock;
-	}
-
-	tuner_dbg("mt2032 optimize_vco: sel=%d\n",sel);
-
-	buf[0]=0x0f;
-	buf[1]=sel;
-	tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
-	lock=mt2032_check_lo_lock(fe);
-	return lock;
-}
-
-
-static void mt2032_set_if_freq(struct dvb_frontend *fe, unsigned int rfin,
-			       unsigned int if1, unsigned int if2,
-			       unsigned int from, unsigned int to)
-{
-	unsigned char buf[21];
-	int lint_try,ret,sel,lock=0;
-	struct microtune_priv *priv = fe->tuner_priv;
-
-	tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",
-		  rfin,if1,if2,from,to);
-
-	buf[0]=0;
-	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
-	tuner_i2c_xfer_recv(&priv->i2c_props,buf,21);
-
-	buf[0]=0;
-	ret=mt2032_compute_freq(fe,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc);
-	if (ret<0)
-		return;
-
-	// send only the relevant registers per Rev. 1.2
-	buf[0]=0;
-	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,4);
-	buf[5]=5;
-	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,4);
-	buf[11]=11;
-	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+11,3);
-	if(ret!=3)
-		tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret);
-
-	// wait for PLLs to lock (per manual), retry LINT if not.
-	for(lint_try=0; lint_try<2; lint_try++) {
-		lock=mt2032_check_lo_lock(fe);
-
-		if(optimize_vco)
-			lock=mt2032_optimize_vco(fe,sel,lock);
-		if(lock==6) break;
-
-		tuner_dbg("mt2032: re-init PLLs by LINT\n");
-		buf[0]=7;
-		buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs
-		tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
-		mdelay(10);
-		buf[1]=8+priv->xogc;
-		tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
-	}
-
-	if (lock!=6)
-		tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n");
-
-	buf[0]=2;
-	buf[1]=0x20; // LOGC for optimal phase noise
-	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
-	if (ret!=2)
-		tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
-}
-
-
-static int mt2032_set_tv_freq(struct dvb_frontend *fe,
-			      struct analog_parameters *params)
-{
-	int if2,from,to;
-
-	// signal bandwidth and picture carrier
-	if (params->std & V4L2_STD_525_60) {
-		// NTSC
-		from = 40750*1000;
-		to   = 46750*1000;
-		if2  = 45750*1000;
-	} else {
-		// PAL
-		from = 32900*1000;
-		to   = 39900*1000;
-		if2  = 38900*1000;
-	}
-
-	mt2032_set_if_freq(fe, params->frequency*62500,
-			   1090*1000*1000, if2, from, to);
-
-	return 0;
-}
-
-static int mt2032_set_radio_freq(struct dvb_frontend *fe,
-				 struct analog_parameters *params)
-{
-	struct microtune_priv *priv = fe->tuner_priv;
-	int if2;
-
-	if (params->std & V4L2_STD_525_60) {
-		tuner_dbg("pinnacle ntsc\n");
-		if2 = 41300 * 1000;
-	} else {
-		tuner_dbg("pinnacle pal\n");
-		if2 = 33300 * 1000;
-	}
-
-	// per Manual for FM tuning: first if center freq. 1085 MHz
-	mt2032_set_if_freq(fe, params->frequency * 125 / 2,
-			   1085*1000*1000,if2,if2,if2);
-
-	return 0;
-}
-
-static int mt2032_set_params(struct dvb_frontend *fe,
-			     struct analog_parameters *params)
-{
-	struct microtune_priv *priv = fe->tuner_priv;
-	int ret = -EINVAL;
-
-	switch (params->mode) {
-	case V4L2_TUNER_RADIO:
-		ret = mt2032_set_radio_freq(fe, params);
-		priv->frequency = params->frequency * 125 / 2;
-		break;
-	case V4L2_TUNER_ANALOG_TV:
-	case V4L2_TUNER_DIGITAL_TV:
-		ret = mt2032_set_tv_freq(fe, params);
-		priv->frequency = params->frequency * 62500;
-		break;
-	}
-
-	return ret;
-}
-
-static struct dvb_tuner_ops mt2032_tuner_ops = {
-	.set_analog_params = mt2032_set_params,
-	.release           = microtune_release,
-	.get_frequency     = microtune_get_frequency,
-};
-
-// Initialization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
-static int mt2032_init(struct dvb_frontend *fe)
-{
-	struct microtune_priv *priv = fe->tuner_priv;
-	unsigned char buf[21];
-	int ret,xogc,xok=0;
-
-	// Initialize Registers per spec.
-	buf[1]=2; // Index to register 2
-	buf[2]=0xff;
-	buf[3]=0x0f;
-	buf[4]=0x1f;
-	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+1,4);
-
-	buf[5]=6; // Index register 6
-	buf[6]=0xe4;
-	buf[7]=0x8f;
-	buf[8]=0xc3;
-	buf[9]=0x4e;
-	buf[10]=0xec;
-	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,6);
-
-	buf[12]=13;  // Index register 13
-	buf[13]=0x32;
-	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+12,2);
-
-	// Adjust XOGC (register 7), wait for XOK
-	xogc=7;
-	do {
-		tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
-		mdelay(10);
-		buf[0]=0x0e;
-		tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
-		tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
-		xok=buf[0]&0x01;
-		tuner_dbg("mt2032: xok = 0x%02x\n",xok);
-		if (xok == 1) break;
-
-		xogc--;
-		tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
-		if (xogc == 3) {
-			xogc=4; // min. 4 per spec
-			break;
-		}
-		buf[0]=0x07;
-		buf[1]=0x88 + xogc;
-		ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
-		if (ret!=2)
-			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
-	} while (xok != 1 );
-	priv->xogc=xogc;
-
-	memcpy(&fe->ops.tuner_ops, &mt2032_tuner_ops, sizeof(struct dvb_tuner_ops));
-
-	return(1);
-}
-
-static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna)
-{
-	struct microtune_priv *priv = fe->tuner_priv;
-	unsigned char buf[2];
-
-	buf[0] = 6;
-	buf[1] = antenna ? 0x11 : 0x10;
-	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
-	tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
-}
-
-static void mt2050_set_if_freq(struct dvb_frontend *fe,unsigned int freq, unsigned int if2)
-{
-	struct microtune_priv *priv = fe->tuner_priv;
-	unsigned int if1=1218*1000*1000;
-	unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b;
-	int ret;
-	unsigned char buf[6];
-
-	tuner_dbg("mt2050_set_if_freq freq=%d if1=%d if2=%d\n",
-		  freq,if1,if2);
-
-	f_lo1=freq+if1;
-	f_lo1=(f_lo1/1000000)*1000000;
-
-	f_lo2=f_lo1-freq-if2;
-	f_lo2=(f_lo2/50000)*50000;
-
-	lo1=f_lo1/4000000;
-	lo2=f_lo2/4000000;
-
-	f_lo1_modulo= f_lo1-(lo1*4000000);
-	f_lo2_modulo= f_lo2-(lo2*4000000);
-
-	num1=4*f_lo1_modulo/4000000;
-	num2=4096*(f_lo2_modulo/1000)/4000;
-
-	// todo spurchecks
-
-	div1a=(lo1/12)-1;
-	div1b=lo1-(div1a+1)*12;
-
-	div2a=(lo2/8)-1;
-	div2b=lo2-(div2a+1)*8;
-
-	if (debug > 1) {
-		tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2);
-		tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n",
-			  num1,num2,div1a,div1b,div2a,div2b);
-	}
-
-	buf[0]=1;
-	buf[1]= 4*div1b + num1;
-	if(freq<275*1000*1000) buf[1] = buf[1]|0x80;
-
-	buf[2]=div1a;
-	buf[3]=32*div2b + num2/256;
-	buf[4]=num2-(num2/256)*256;
-	buf[5]=div2a;
-	if(num2!=0) buf[5]=buf[5]|0x40;
-
-	if (debug > 1) {
-		int i;
-		tuner_dbg("bufs is: ");
-		for(i=0;i<6;i++)
-			printk("%x ",buf[i]);
-		printk("\n");
-	}
-
-	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,6);
-	if (ret!=6)
-		tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret);
-}
-
-static int mt2050_set_tv_freq(struct dvb_frontend *fe,
-			      struct analog_parameters *params)
-{
-	unsigned int if2;
-
-	if (params->std & V4L2_STD_525_60) {
-		// NTSC
-		if2 = 45750*1000;
-	} else {
-		// PAL
-		if2 = 38900*1000;
-	}
-	if (V4L2_TUNER_DIGITAL_TV == params->mode) {
-		// DVB (pinnacle 300i)
-		if2 = 36150*1000;
-	}
-	mt2050_set_if_freq(fe, params->frequency*62500, if2);
-	mt2050_set_antenna(fe, tv_antenna);
-
-	return 0;
-}
-
-static int mt2050_set_radio_freq(struct dvb_frontend *fe,
-				 struct analog_parameters *params)
-{
-	struct microtune_priv *priv = fe->tuner_priv;
-	int if2;
-
-	if (params->std & V4L2_STD_525_60) {
-		tuner_dbg("pinnacle ntsc\n");
-		if2 = 41300 * 1000;
-	} else {
-		tuner_dbg("pinnacle pal\n");
-		if2 = 33300 * 1000;
-	}
-
-	mt2050_set_if_freq(fe, params->frequency * 125 / 2, if2);
-	mt2050_set_antenna(fe, radio_antenna);
-
-	return 0;
-}
-
-static int mt2050_set_params(struct dvb_frontend *fe,
-			     struct analog_parameters *params)
-{
-	struct microtune_priv *priv = fe->tuner_priv;
-	int ret = -EINVAL;
-
-	switch (params->mode) {
-	case V4L2_TUNER_RADIO:
-		ret = mt2050_set_radio_freq(fe, params);
-		priv->frequency = params->frequency * 125 / 2;
-		break;
-	case V4L2_TUNER_ANALOG_TV:
-	case V4L2_TUNER_DIGITAL_TV:
-		ret = mt2050_set_tv_freq(fe, params);
-		priv->frequency = params->frequency * 62500;
-		break;
-	}
-
-	return ret;
-}
-
-static struct dvb_tuner_ops mt2050_tuner_ops = {
-	.set_analog_params = mt2050_set_params,
-	.release           = microtune_release,
-	.get_frequency     = microtune_get_frequency,
-};
-
-static int mt2050_init(struct dvb_frontend *fe)
-{
-	struct microtune_priv *priv = fe->tuner_priv;
-	unsigned char buf[2];
-
-	buf[0] = 6;
-	buf[1] = 0x10;
-	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); /* power */
-
-	buf[0] = 0x0f;
-	buf[1] = 0x0f;
-	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); /* m1lo */
-
-	buf[0] = 0x0d;
-	tuner_i2c_xfer_send(&priv->i2c_props, buf, 1);
-	tuner_i2c_xfer_recv(&priv->i2c_props, buf, 1);
-
-	tuner_dbg("mt2050: sro is %x\n", buf[0]);
-
-	memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops));
-
-	return 0;
-}
-
-struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
-				      struct i2c_adapter* i2c_adap,
-				      u8 i2c_addr)
-{
-	struct microtune_priv *priv = NULL;
-	char *name;
-	unsigned char buf[21];
-	int company_code;
-
-	priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-	fe->tuner_priv = priv;
-
-	priv->i2c_props.addr = i2c_addr;
-	priv->i2c_props.adap = i2c_adap;
-	priv->i2c_props.name = "mt20xx";
-
-	//priv->radio_if2 = 10700 * 1000;	/* 10.7MHz - FM radio */
-
-	memset(buf,0,sizeof(buf));
-
-	name = "unknown";
-
-	tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
-	tuner_i2c_xfer_recv(&priv->i2c_props,buf,21);
-	if (debug) {
-		int i;
-		tuner_dbg("MT20xx hexdump:");
-		for(i=0;i<21;i++) {
-			printk(" %02x",buf[i]);
-			if(((i+1)%8)==0) printk(" ");
-		}
-		printk("\n");
-	}
-	company_code = buf[0x11] << 8 | buf[0x12];
-	tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n",
-		   company_code,buf[0x13],buf[0x14]);
-
-
-	if (buf[0x13] < ARRAY_SIZE(microtune_part) &&
-	    NULL != microtune_part[buf[0x13]])
-		name = microtune_part[buf[0x13]];
-	switch (buf[0x13]) {
-	case MT2032:
-		mt2032_init(fe);
-		break;
-	case MT2050:
-		mt2050_init(fe);
-		break;
-	default:
-		tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n",
-			   name);
-		return NULL;
-	}
-
-	strlcpy(fe->ops.tuner_ops.info.name, name,
-		sizeof(fe->ops.tuner_ops.info.name));
-	tuner_info("microtune %s found, OK\n",name);
-	return fe;
-}
-
-EXPORT_SYMBOL_GPL(microtune_attach);
-
-MODULE_DESCRIPTION("Microtune tuner driver");
-MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
-MODULE_LICENSE("GPL");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/common/tuners/mt20xx.h b/drivers/media/common/tuners/mt20xx.h
deleted file mode 100644
index 259553a..0000000
--- a/drivers/media/common/tuners/mt20xx.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MT20XX_H__
-#define __MT20XX_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-#if defined(CONFIG_MEDIA_TUNER_MT20XX) || (defined(CONFIG_MEDIA_TUNER_MT20XX_MODULE) && defined(MODULE))
-extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
-					     struct i2c_adapter* i2c_adap,
-					     u8 i2c_addr);
-#else
-static inline struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
-					     struct i2c_adapter* i2c_adap,
-					     u8 i2c_addr)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* __MT20XX_H__ */
diff --git a/drivers/media/common/tuners/mt2131.c b/drivers/media/common/tuners/mt2131.c
deleted file mode 100644
index f83b0c1..0000000
--- a/drivers/media/common/tuners/mt2131.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
- *
- *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/dvb/frontend.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-
-#include "mt2131.h"
-#include "mt2131_priv.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-#define dprintk(level,fmt, arg...) if (debug >= level) \
-	printk(KERN_INFO "%s: " fmt, "mt2131", ## arg)
-
-static u8 mt2131_config1[] = {
-	0x01,
-	0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88,
-	0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32,
-	0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80,
-	0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00
-};
-
-static u8 mt2131_config2[] = {
-	0x10,
-	0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04
-};
-
-static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val)
-{
-	struct i2c_msg msg[2] = {
-		{ .addr = priv->cfg->i2c_address, .flags = 0,
-		  .buf = &reg, .len = 1 },
-		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
-		  .buf = val,  .len = 1 },
-	};
-
-	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
-		printk(KERN_WARNING "mt2131 I2C read failed\n");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val)
-{
-	u8 buf[2] = { reg, val };
-	struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0,
-			       .buf = buf, .len = 2 };
-
-	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
-		printk(KERN_WARNING "mt2131 I2C write failed\n");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len)
-{
-	struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
-			       .flags = 0, .buf = buf, .len = len };
-
-	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
-		printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n",
-		       (int)len);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int mt2131_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct mt2131_priv *priv;
-	int ret=0, i;
-	u32 freq;
-	u8  if_band_center;
-	u32 f_lo1, f_lo2;
-	u32 div1, num1, div2, num2;
-	u8  b[8];
-	u8 lockval = 0;
-
-	priv = fe->tuner_priv;
-
-	freq = c->frequency / 1000;  /* Hz -> kHz */
-	dprintk(1, "%s() freq=%d\n", __func__, freq);
-
-	f_lo1 = freq + MT2131_IF1 * 1000;
-	f_lo1 = (f_lo1 / 250) * 250;
-	f_lo2 = f_lo1 - freq - MT2131_IF2;
-
-	priv->frequency =  (f_lo1 - f_lo2 - MT2131_IF2) * 1000;
-
-	/* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */
-	num1 = f_lo1 * 64 / (MT2131_FREF / 128);
-	div1 = num1 / 8192;
-	num1 &= 0x1fff;
-
-	/* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */
-	num2 = f_lo2 * 64 / (MT2131_FREF / 128);
-	div2 = num2 / 8192;
-	num2 &= 0x1fff;
-
-	if (freq <=   82500) if_band_center = 0x00; else
-	if (freq <=  137500) if_band_center = 0x01; else
-	if (freq <=  192500) if_band_center = 0x02; else
-	if (freq <=  247500) if_band_center = 0x03; else
-	if (freq <=  302500) if_band_center = 0x04; else
-	if (freq <=  357500) if_band_center = 0x05; else
-	if (freq <=  412500) if_band_center = 0x06; else
-	if (freq <=  467500) if_band_center = 0x07; else
-	if (freq <=  522500) if_band_center = 0x08; else
-	if (freq <=  577500) if_band_center = 0x09; else
-	if (freq <=  632500) if_band_center = 0x0A; else
-	if (freq <=  687500) if_band_center = 0x0B; else
-	if (freq <=  742500) if_band_center = 0x0C; else
-	if (freq <=  797500) if_band_center = 0x0D; else
-	if (freq <=  852500) if_band_center = 0x0E; else
-	if (freq <=  907500) if_band_center = 0x0F; else
-	if (freq <=  962500) if_band_center = 0x10; else
-	if (freq <= 1017500) if_band_center = 0x11; else
-	if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13;
-
-	b[0] = 1;
-	b[1] = (num1 >> 5) & 0xFF;
-	b[2] = (num1 & 0x1F);
-	b[3] = div1;
-	b[4] = (num2 >> 5) & 0xFF;
-	b[5] = num2 & 0x1F;
-	b[6] = div2;
-
-	dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2);
-	dprintk(1, "PLL freq=%dkHz  band=%d\n", (int)freq, (int)if_band_center);
-	dprintk(1, "PLL f_lo1=%dkHz  f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2);
-	dprintk(1, "PLL div1=%d  num1=%d  div2=%d  num2=%d\n",
-		(int)div1, (int)num1, (int)div2, (int)num2);
-	dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n",
-		(int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5],
-		(int)b[6]);
-
-	ret = mt2131_writeregs(priv,b,7);
-	if (ret < 0)
-		return ret;
-
-	mt2131_writereg(priv, 0x0b, if_band_center);
-
-	/* Wait for lock */
-	i = 0;
-	do {
-		mt2131_readreg(priv, 0x08, &lockval);
-		if ((lockval & 0x88) == 0x88)
-			break;
-		msleep(4);
-		i++;
-	} while (i < 10);
-
-	return ret;
-}
-
-static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct mt2131_priv *priv = fe->tuner_priv;
-	dprintk(1, "%s()\n", __func__);
-	*frequency = priv->frequency;
-	return 0;
-}
-
-static int mt2131_get_status(struct dvb_frontend *fe, u32 *status)
-{
-	struct mt2131_priv *priv = fe->tuner_priv;
-	u8 lock_status = 0;
-	u8 afc_status = 0;
-
-	*status = 0;
-
-	mt2131_readreg(priv, 0x08, &lock_status);
-	if ((lock_status & 0x88) == 0x88)
-		*status = TUNER_STATUS_LOCKED;
-
-	mt2131_readreg(priv, 0x09, &afc_status);
-	dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n",
-		__func__, lock_status, afc_status);
-
-	return 0;
-}
-
-static int mt2131_init(struct dvb_frontend *fe)
-{
-	struct mt2131_priv *priv = fe->tuner_priv;
-	int ret;
-	dprintk(1, "%s()\n", __func__);
-
-	if ((ret = mt2131_writeregs(priv, mt2131_config1,
-				    sizeof(mt2131_config1))) < 0)
-		return ret;
-
-	mt2131_writereg(priv, 0x0b, 0x09);
-	mt2131_writereg(priv, 0x15, 0x47);
-	mt2131_writereg(priv, 0x07, 0xf2);
-	mt2131_writereg(priv, 0x0b, 0x01);
-
-	if ((ret = mt2131_writeregs(priv, mt2131_config2,
-				    sizeof(mt2131_config2))) < 0)
-		return ret;
-
-	return ret;
-}
-
-static int mt2131_release(struct dvb_frontend *fe)
-{
-	dprintk(1, "%s()\n", __func__);
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static const struct dvb_tuner_ops mt2131_tuner_ops = {
-	.info = {
-		.name           = "Microtune MT2131",
-		.frequency_min  =  48000000,
-		.frequency_max  = 860000000,
-		.frequency_step =     50000,
-	},
-
-	.release       = mt2131_release,
-	.init          = mt2131_init,
-
-	.set_params    = mt2131_set_params,
-	.get_frequency = mt2131_get_frequency,
-	.get_status    = mt2131_get_status
-};
-
-struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe,
-				    struct i2c_adapter *i2c,
-				    struct mt2131_config *cfg, u16 if1)
-{
-	struct mt2131_priv *priv = NULL;
-	u8 id = 0;
-
-	dprintk(1, "%s()\n", __func__);
-
-	priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	priv->cfg = cfg;
-	priv->i2c = i2c;
-
-	if (mt2131_readreg(priv, 0, &id) != 0) {
-		kfree(priv);
-		return NULL;
-	}
-	if ( (id != 0x3E) && (id != 0x3F) ) {
-		printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n",
-		       cfg->i2c_address);
-		kfree(priv);
-		return NULL;
-	}
-
-	printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n",
-	       cfg->i2c_address);
-	memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops,
-	       sizeof(struct dvb_tuner_ops));
-
-	fe->tuner_priv = priv;
-	return fe;
-}
-EXPORT_SYMBOL(mt2131_attach);
-
-MODULE_AUTHOR("Steven Toth");
-MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver");
-MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/common/tuners/mt2131.h b/drivers/media/common/tuners/mt2131.h
deleted file mode 100644
index 6632de6..0000000
--- a/drivers/media/common/tuners/mt2131.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
- *
- *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __MT2131_H__
-#define __MT2131_H__
-
-struct dvb_frontend;
-struct i2c_adapter;
-
-struct mt2131_config {
-	u8 i2c_address;
-	u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
-};
-
-#if defined(CONFIG_MEDIA_TUNER_MT2131) || (defined(CONFIG_MEDIA_TUNER_MT2131_MODULE) && defined(MODULE))
-extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
-					  struct i2c_adapter *i2c,
-					  struct mt2131_config *cfg,
-					  u16 if1);
-#else
-static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
-						 struct i2c_adapter *i2c,
-						 struct mt2131_config *cfg,
-						 u16 if1)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_MEDIA_TUNER_MT2131 */
-
-#endif /* __MT2131_H__ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/common/tuners/mt2131_priv.h b/drivers/media/common/tuners/mt2131_priv.h
deleted file mode 100644
index 62aeedf..0000000
--- a/drivers/media/common/tuners/mt2131_priv.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
- *
- *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __MT2131_PRIV_H__
-#define __MT2131_PRIV_H__
-
-/* Regs */
-#define MT2131_PWR              0x07
-#define MT2131_UPC_1            0x0b
-#define MT2131_AGC_RL           0x10
-#define MT2131_MISC_2           0x15
-
-/* frequency values in KHz */
-#define MT2131_IF1              1220
-#define MT2131_IF2              44000
-#define MT2131_FREF             16000
-
-struct mt2131_priv {
-	struct mt2131_config *cfg;
-	struct i2c_adapter   *i2c;
-
-	u32 frequency;
-};
-
-#endif /* __MT2131_PRIV_H__ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/common/tuners/mt2266.c b/drivers/media/common/tuners/mt2266.c
deleted file mode 100644
index bca4d75..0000000
--- a/drivers/media/common/tuners/mt2266.c
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- *  Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
- *
- *  Copyright (c) 2007 Olivier DANET <odanet@caramail.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/dvb/frontend.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "mt2266.h"
-
-#define I2C_ADDRESS 0x60
-
-#define REG_PART_REV   0
-#define REG_TUNE       1
-#define REG_BAND       6
-#define REG_BANDWIDTH  8
-#define REG_LOCK       0x12
-
-#define PART_REV 0x85
-
-struct mt2266_priv {
-	struct mt2266_config *cfg;
-	struct i2c_adapter   *i2c;
-
-	u32 frequency;
-	u32 bandwidth;
-	u8 band;
-};
-
-#define MT2266_VHF 1
-#define MT2266_UHF 0
-
-/* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0)
-
-// Reads a single register
-static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val)
-{
-	struct i2c_msg msg[2] = {
-		{ .addr = priv->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
-		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val,  .len = 1 },
-	};
-	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
-		printk(KERN_WARNING "MT2266 I2C read failed\n");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-// Writes a single register
-static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val)
-{
-	u8 buf[2] = { reg, val };
-	struct i2c_msg msg = {
-		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
-	};
-	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
-		printk(KERN_WARNING "MT2266 I2C write failed\n");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-// Writes a set of consecutive registers
-static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len)
-{
-	struct i2c_msg msg = {
-		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len
-	};
-	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
-		printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-// Initialisation sequences
-static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28,
-				 0x00, 0x52, 0x99, 0x3f };
-
-static u8 mt2266_init2[] = {
-    0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4,
-    0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14,
-    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff,
-    0xff, 0x00, 0x77, 0x0f, 0x2d
-};
-
-static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22,
-						0x22, 0x22, 0x22, 0x22 };
-
-static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32,
-						0x32, 0x32, 0x32, 0x32 };
-
-static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7,
-						0xa7, 0xa7, 0xa7, 0xa7 };
-
-static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64,
-			   0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 };
-
-static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5,
-			   0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f };
-
-#define FREF 30000       // Quartz oscillator 30 MHz
-
-static int mt2266_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct mt2266_priv *priv;
-	int ret=0;
-	u32 freq;
-	u32 tune;
-	u8  lnaband;
-	u8  b[10];
-	int i;
-	u8 band;
-
-	priv = fe->tuner_priv;
-
-	freq = priv->frequency / 1000; /* Hz -> kHz */
-	if (freq < 470000 && freq > 230000)
-		return -EINVAL; /* Gap between VHF and UHF bands */
-
-	priv->frequency = c->frequency;
-	tune = 2 * freq * (8192/16) / (FREF/16);
-	band = (freq < 300000) ? MT2266_VHF : MT2266_UHF;
-	if (band == MT2266_VHF)
-		tune *= 2;
-
-	switch (c->bandwidth_hz) {
-	case 6000000:
-		mt2266_writeregs(priv, mt2266_init_6mhz,
-				 sizeof(mt2266_init_6mhz));
-		break;
-	case 8000000:
-		mt2266_writeregs(priv, mt2266_init_8mhz,
-				 sizeof(mt2266_init_8mhz));
-		break;
-	case 7000000:
-	default:
-		mt2266_writeregs(priv, mt2266_init_7mhz,
-				 sizeof(mt2266_init_7mhz));
-		break;
-	}
-	priv->bandwidth = c->bandwidth_hz;
-
-	if (band == MT2266_VHF && priv->band == MT2266_UHF) {
-		dprintk("Switch from UHF to VHF");
-		mt2266_writereg(priv, 0x05, 0x04);
-		mt2266_writereg(priv, 0x19, 0x61);
-		mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf));
-	} else if (band == MT2266_UHF && priv->band == MT2266_VHF) {
-		dprintk("Switch from VHF to UHF");
-		mt2266_writereg(priv, 0x05, 0x52);
-		mt2266_writereg(priv, 0x19, 0x61);
-		mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf));
-	}
-	msleep(10);
-
-	if (freq <= 495000)
-		lnaband = 0xEE;
-	else if (freq <= 525000)
-		lnaband = 0xDD;
-	else if (freq <= 550000)
-		lnaband = 0xCC;
-	else if (freq <= 580000)
-		lnaband = 0xBB;
-	else if (freq <= 605000)
-		lnaband = 0xAA;
-	else if (freq <= 630000)
-		lnaband = 0x99;
-	else if (freq <= 655000)
-		lnaband = 0x88;
-	else if (freq <= 685000)
-		lnaband = 0x77;
-	else if (freq <= 710000)
-		lnaband = 0x66;
-	else if (freq <= 735000)
-		lnaband = 0x55;
-	else if (freq <= 765000)
-		lnaband = 0x44;
-	else if (freq <= 802000)
-		lnaband = 0x33;
-	else if (freq <= 840000)
-		lnaband = 0x22;
-	else
-		lnaband = 0x11;
-
-	b[0] = REG_TUNE;
-	b[1] = (tune >> 8) & 0x1F;
-	b[2] = tune & 0xFF;
-	b[3] = tune >> 13;
-	mt2266_writeregs(priv,b,4);
-
-	dprintk("set_parms: tune=%d band=%d %s",
-		(int) tune, (int) lnaband,
-		(band == MT2266_UHF) ? "UHF" : "VHF");
-	dprintk("set_parms: [1..3]: %2x %2x %2x",
-		(int) b[1], (int) b[2], (int)b[3]);
-
-	if (band == MT2266_UHF) {
-		b[0] = 0x05;
-		b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62;
-		b[2] = lnaband;
-		mt2266_writeregs(priv, b, 3);
-	}
-
-	/* Wait for pll lock or timeout */
-	i = 0;
-	do {
-		mt2266_readreg(priv,REG_LOCK,b);
-		if (b[0] & 0x40)
-			break;
-		msleep(10);
-		i++;
-	} while (i<10);
-	dprintk("Lock when i=%i",(int)i);
-
-	if (band == MT2266_UHF && priv->band == MT2266_VHF)
-		mt2266_writereg(priv, 0x05, 0x62);
-
-	priv->band = band;
-
-	return ret;
-}
-
-static void mt2266_calibrate(struct mt2266_priv *priv)
-{
-	mt2266_writereg(priv, 0x11, 0x03);
-	mt2266_writereg(priv, 0x11, 0x01);
-	mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1));
-	mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2));
-	mt2266_writereg(priv, 0x33, 0x5e);
-	mt2266_writereg(priv, 0x10, 0x10);
-	mt2266_writereg(priv, 0x10, 0x00);
-	mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz));
-	msleep(25);
-	mt2266_writereg(priv, 0x17, 0x6d);
-	mt2266_writereg(priv, 0x1c, 0x00);
-	msleep(75);
-	mt2266_writereg(priv, 0x17, 0x6d);
-	mt2266_writereg(priv, 0x1c, 0xff);
-}
-
-static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct mt2266_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-	return 0;
-}
-
-static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	struct mt2266_priv *priv = fe->tuner_priv;
-	*bandwidth = priv->bandwidth;
-	return 0;
-}
-
-static int mt2266_init(struct dvb_frontend *fe)
-{
-	int ret;
-	struct mt2266_priv *priv = fe->tuner_priv;
-	ret = mt2266_writereg(priv, 0x17, 0x6d);
-	if (ret < 0)
-		return ret;
-	ret = mt2266_writereg(priv, 0x1c, 0xff);
-	if (ret < 0)
-		return ret;
-	return 0;
-}
-
-static int mt2266_sleep(struct dvb_frontend *fe)
-{
-	struct mt2266_priv *priv = fe->tuner_priv;
-	mt2266_writereg(priv, 0x17, 0x6d);
-	mt2266_writereg(priv, 0x1c, 0x00);
-	return 0;
-}
-
-static int mt2266_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static const struct dvb_tuner_ops mt2266_tuner_ops = {
-	.info = {
-		.name           = "Microtune MT2266",
-		.frequency_min  = 174000000,
-		.frequency_max  = 862000000,
-		.frequency_step =     50000,
-	},
-	.release       = mt2266_release,
-	.init          = mt2266_init,
-	.sleep         = mt2266_sleep,
-	.set_params    = mt2266_set_params,
-	.get_frequency = mt2266_get_frequency,
-	.get_bandwidth = mt2266_get_bandwidth
-};
-
-struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
-{
-	struct mt2266_priv *priv = NULL;
-	u8 id = 0;
-
-	priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	priv->cfg      = cfg;
-	priv->i2c      = i2c;
-	priv->band     = MT2266_UHF;
-
-	if (mt2266_readreg(priv, 0, &id)) {
-		kfree(priv);
-		return NULL;
-	}
-	if (id != PART_REV) {
-		kfree(priv);
-		return NULL;
-	}
-	printk(KERN_INFO "MT2266: successfully identified\n");
-	memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops));
-
-	fe->tuner_priv = priv;
-	mt2266_calibrate(priv);
-	return fe;
-}
-EXPORT_SYMBOL(mt2266_attach);
-
-MODULE_AUTHOR("Olivier DANET");
-MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/mt2266.h b/drivers/media/common/tuners/mt2266.h
deleted file mode 100644
index 4d08388..0000000
--- a/drivers/media/common/tuners/mt2266.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- *  Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
- *
- *  Copyright (c) 2007 Olivier DANET <odanet@caramail.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- */
-
-#ifndef MT2266_H
-#define MT2266_H
-
-struct dvb_frontend;
-struct i2c_adapter;
-
-struct mt2266_config {
-	u8 i2c_address;
-};
-
-#if defined(CONFIG_MEDIA_TUNER_MT2266) || (defined(CONFIG_MEDIA_TUNER_MT2266_MODULE) && defined(MODULE))
-extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg);
-#else
-static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_MEDIA_TUNER_MT2266
-
-#endif
diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c
deleted file mode 100644
index 6133315..0000000
--- a/drivers/media/common/tuners/mxl5005s.c
+++ /dev/null
@@ -1,4109 +0,0 @@
-/*
-    MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
-
-    Copyright (C) 2008 MaxLinear
-    Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
-      Functions:
-	mxl5005s_reset()
-	mxl5005s_writereg()
-	mxl5005s_writeregs()
-	mxl5005s_init()
-	mxl5005s_reconfigure()
-	mxl5005s_AssignTunerMode()
-	mxl5005s_set_params()
-	mxl5005s_get_frequency()
-	mxl5005s_get_bandwidth()
-	mxl5005s_release()
-	mxl5005s_attach()
-
-    Copyright (C) 2008 Realtek
-    Copyright (C) 2008 Jan Hoogenraad
-      Functions:
-	mxl5005s_SetRfFreqHz()
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/*
-    History of this driver (Steven Toth):
-      I was given a public release of a linux driver that included
-      support for the MaxLinear MXL5005S silicon tuner. Analysis of
-      the tuner driver showed clearly three things.
-
-      1. The tuner driver didn't support the LinuxTV tuner API
-	 so the code Realtek added had to be removed.
-
-      2. A significant amount of the driver is reference driver code
-	 from MaxLinear, I felt it was important to identify and
-	 preserve this.
-
-      3. New code has to be added to interface correctly with the
-	 LinuxTV API, as a regular kernel module.
-
-      Other than the reference driver enum's, I've clearly marked
-      sections of the code and retained the copyright of the
-      respective owners.
-*/
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include "dvb_frontend.h"
-#include "mxl5005s.h"
-
-static int debug;
-
-#define dprintk(level, arg...) do {    \
-	if (level <= debug)            \
-		printk(arg);    \
-	} while (0)
-
-#define TUNER_REGS_NUM          104
-#define INITCTRL_NUM            40
-
-#ifdef _MXL_PRODUCTION
-#define CHCTRL_NUM              39
-#else
-#define CHCTRL_NUM              36
-#endif
-
-#define MXLCTRL_NUM             189
-#define MASTER_CONTROL_ADDR     9
-
-/* Enumeration of Master Control Register State */
-enum master_control_state {
-	MC_LOAD_START = 1,
-	MC_POWER_DOWN,
-	MC_SYNTH_RESET,
-	MC_SEQ_OFF
-};
-
-/* Enumeration of MXL5005 Tuner Modulation Type */
-enum {
-	MXL_DEFAULT_MODULATION = 0,
-	MXL_DVBT,
-	MXL_ATSC,
-	MXL_QAM,
-	MXL_ANALOG_CABLE,
-	MXL_ANALOG_OTA
-};
-
-/* MXL5005 Tuner Register Struct */
-struct TunerReg {
-	u16 Reg_Num;	/* Tuner Register Address */
-	u16 Reg_Val;	/* Current sw programmed value waiting to be written */
-};
-
-enum {
-	/* Initialization Control Names */
-	DN_IQTN_AMP_CUT = 1,       /* 1 */
-	BB_MODE,                   /* 2 */
-	BB_BUF,                    /* 3 */
-	BB_BUF_OA,                 /* 4 */
-	BB_ALPF_BANDSELECT,        /* 5 */
-	BB_IQSWAP,                 /* 6 */
-	BB_DLPF_BANDSEL,           /* 7 */
-	RFSYN_CHP_GAIN,            /* 8 */
-	RFSYN_EN_CHP_HIGAIN,       /* 9 */
-	AGC_IF,                    /* 10 */
-	AGC_RF,                    /* 11 */
-	IF_DIVVAL,                 /* 12 */
-	IF_VCO_BIAS,               /* 13 */
-	CHCAL_INT_MOD_IF,          /* 14 */
-	CHCAL_FRAC_MOD_IF,         /* 15 */
-	DRV_RES_SEL,               /* 16 */
-	I_DRIVER,                  /* 17 */
-	EN_AAF,                    /* 18 */
-	EN_3P,                     /* 19 */
-	EN_AUX_3P,                 /* 20 */
-	SEL_AAF_BAND,              /* 21 */
-	SEQ_ENCLK16_CLK_OUT,       /* 22 */
-	SEQ_SEL4_16B,              /* 23 */
-	XTAL_CAPSELECT,            /* 24 */
-	IF_SEL_DBL,                /* 25 */
-	RFSYN_R_DIV,               /* 26 */
-	SEQ_EXTSYNTHCALIF,         /* 27 */
-	SEQ_EXTDCCAL,              /* 28 */
-	AGC_EN_RSSI,               /* 29 */
-	RFA_ENCLKRFAGC,            /* 30 */
-	RFA_RSSI_REFH,             /* 31 */
-	RFA_RSSI_REF,              /* 32 */
-	RFA_RSSI_REFL,             /* 33 */
-	RFA_FLR,                   /* 34 */
-	RFA_CEIL,                  /* 35 */
-	SEQ_EXTIQFSMPULSE,         /* 36 */
-	OVERRIDE_1,                /* 37 */
-	BB_INITSTATE_DLPF_TUNE,    /* 38 */
-	TG_R_DIV,                  /* 39 */
-	EN_CHP_LIN_B,              /* 40 */
-
-	/* Channel Change Control Names */
-	DN_POLY = 51,              /* 51 */
-	DN_RFGAIN,                 /* 52 */
-	DN_CAP_RFLPF,              /* 53 */
-	DN_EN_VHFUHFBAR,           /* 54 */
-	DN_GAIN_ADJUST,            /* 55 */
-	DN_IQTNBUF_AMP,            /* 56 */
-	DN_IQTNGNBFBIAS_BST,       /* 57 */
-	RFSYN_EN_OUTMUX,           /* 58 */
-	RFSYN_SEL_VCO_OUT,         /* 59 */
-	RFSYN_SEL_VCO_HI,          /* 60 */
-	RFSYN_SEL_DIVM,            /* 61 */
-	RFSYN_RF_DIV_BIAS,         /* 62 */
-	DN_SEL_FREQ,               /* 63 */
-	RFSYN_VCO_BIAS,            /* 64 */
-	CHCAL_INT_MOD_RF,          /* 65 */
-	CHCAL_FRAC_MOD_RF,         /* 66 */
-	RFSYN_LPF_R,               /* 67 */
-	CHCAL_EN_INT_RF,           /* 68 */
-	TG_LO_DIVVAL,              /* 69 */
-	TG_LO_SELVAL,              /* 70 */
-	TG_DIV_VAL,                /* 71 */
-	TG_VCO_BIAS,               /* 72 */
-	SEQ_EXTPOWERUP,            /* 73 */
-	OVERRIDE_2,                /* 74 */
-	OVERRIDE_3,                /* 75 */
-	OVERRIDE_4,                /* 76 */
-	SEQ_FSM_PULSE,             /* 77 */
-	GPIO_4B,                   /* 78 */
-	GPIO_3B,                   /* 79 */
-	GPIO_4,                    /* 80 */
-	GPIO_3,                    /* 81 */
-	GPIO_1B,                   /* 82 */
-	DAC_A_ENABLE,              /* 83 */
-	DAC_B_ENABLE,              /* 84 */
-	DAC_DIN_A,                 /* 85 */
-	DAC_DIN_B,                 /* 86 */
-#ifdef _MXL_PRODUCTION
-	RFSYN_EN_DIV,              /* 87 */
-	RFSYN_DIVM,                /* 88 */
-	DN_BYPASS_AGC_I2C          /* 89 */
-#endif
-};
-
-/*
- * The following context is source code provided by MaxLinear.
- * MaxLinear source code - Common_MXL.h (?)
- */
-
-/* Constants */
-#define MXL5005S_REG_WRITING_TABLE_LEN_MAX	104
-#define MXL5005S_LATCH_BYTE			0xfe
-
-/* Register address, MSB, and LSB */
-#define MXL5005S_BB_IQSWAP_ADDR			59
-#define MXL5005S_BB_IQSWAP_MSB			0
-#define MXL5005S_BB_IQSWAP_LSB			0
-
-#define MXL5005S_BB_DLPF_BANDSEL_ADDR		53
-#define MXL5005S_BB_DLPF_BANDSEL_MSB		4
-#define MXL5005S_BB_DLPF_BANDSEL_LSB		3
-
-/* Standard modes */
-enum {
-	MXL5005S_STANDARD_DVBT,
-	MXL5005S_STANDARD_ATSC,
-};
-#define MXL5005S_STANDARD_MODE_NUM		2
-
-/* Bandwidth modes */
-enum {
-	MXL5005S_BANDWIDTH_6MHZ = 6000000,
-	MXL5005S_BANDWIDTH_7MHZ = 7000000,
-	MXL5005S_BANDWIDTH_8MHZ = 8000000,
-};
-#define MXL5005S_BANDWIDTH_MODE_NUM		3
-
-/* MXL5005 Tuner Control Struct */
-struct TunerControl {
-	u16 Ctrl_Num;	/* Control Number */
-	u16 size;	/* Number of bits to represent Value */
-	u16 addr[25];	/* Array of Tuner Register Address for each bit pos */
-	u16 bit[25];	/* Array of bit pos in Reg Addr for each bit pos */
-	u16 val[25];	/* Binary representation of Value */
-};
-
-/* MXL5005 Tuner Struct */
-struct mxl5005s_state {
-	u8	Mode;		/* 0: Analog Mode ; 1: Digital Mode */
-	u8	IF_Mode;	/* for Analog Mode, 0: zero IF; 1: low IF */
-	u32	Chan_Bandwidth;	/* filter  channel bandwidth (6, 7, 8) */
-	u32	IF_OUT;		/* Desired IF Out Frequency */
-	u16	IF_OUT_LOAD;	/* IF Out Load Resistor (200/300 Ohms) */
-	u32	RF_IN;		/* RF Input Frequency */
-	u32	Fxtal;		/* XTAL Frequency */
-	u8	AGC_Mode;	/* AGC Mode 0: Dual AGC; 1: Single AGC */
-	u16	TOP;		/* Value: take over point */
-	u8	CLOCK_OUT;	/* 0: turn off clk out; 1: turn on clock out */
-	u8	DIV_OUT;	/* 4MHz or 16MHz */
-	u8	CAPSELECT;	/* 0: disable On-Chip pulling cap; 1: enable */
-	u8	EN_RSSI;	/* 0: disable RSSI; 1: enable RSSI */
-
-	/* Modulation Type; */
-	/* 0 - Default;	1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */
-	u8	Mod_Type;
-
-	/* Tracking Filter Type */
-	/* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */
-	u8	TF_Type;
-
-	/* Calculated Settings */
-	u32	RF_LO;		/* Synth RF LO Frequency */
-	u32	IF_LO;		/* Synth IF LO Frequency */
-	u32	TG_LO;		/* Synth TG_LO Frequency */
-
-	/* Pointers to ControlName Arrays */
-	u16	Init_Ctrl_Num;		/* Number of INIT Control Names */
-	struct TunerControl
-		Init_Ctrl[INITCTRL_NUM]; /* INIT Control Names Array Pointer */
-
-	u16	CH_Ctrl_Num;		/* Number of CH Control Names */
-	struct TunerControl
-		CH_Ctrl[CHCTRL_NUM];	/* CH Control Name Array Pointer */
-
-	u16	MXL_Ctrl_Num;		/* Number of MXL Control Names */
-	struct TunerControl
-		MXL_Ctrl[MXLCTRL_NUM];	/* MXL Control Name Array Pointer */
-
-	/* Pointer to Tuner Register Array */
-	u16	TunerRegs_Num;		/* Number of Tuner Registers */
-	struct TunerReg
-		TunerRegs[TUNER_REGS_NUM]; /* Tuner Register Array Pointer */
-
-	/* Linux driver framework specific */
-	struct mxl5005s_config *config;
-	struct dvb_frontend *frontend;
-	struct i2c_adapter *i2c;
-
-	/* Cache values */
-	u32 current_mode;
-
-};
-
-static u16 MXL_GetMasterControl(u8 *MasterReg, int state);
-static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value);
-static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value);
-static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit,
-	u8 bitVal);
-static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum,
-	u8 *RegVal, int *count);
-static u32 MXL_Ceiling(u32 value, u32 resolution);
-static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal);
-static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum,
-	u32 value, u16 controlGroup);
-static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val);
-static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum,
-	u8 *RegVal, int *count);
-static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq);
-static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe);
-static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe);
-static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum,
-	u8 *RegVal, int *count);
-static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable,
-	u8 *datatable, u8 len);
-static u16 MXL_IFSynthInit(struct dvb_frontend *fe);
-static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type,
-	u32 bandwidth);
-static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type,
-	u32 bandwidth);
-
-/* ----------------------------------------------------------------
- * Begin: Custom code salvaged from the Realtek driver.
- * Copyright (C) 2008 Realtek
- * Copyright (C) 2008 Jan Hoogenraad
- * This code is placed under the terms of the GNU General Public License
- *
- * Released by Realtek under GPLv2.
- * Thanks to Realtek for a lot of support we received !
- *
- *  Revision: 080314 - original version
- */
-
-static int mxl5005s_SetRfFreqHz(struct dvb_frontend *fe, unsigned long RfFreqHz)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	unsigned char AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
-	unsigned char ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
-	int TableLen;
-
-	u32 IfDivval = 0;
-	unsigned char MasterControlByte;
-
-	dprintk(1, "%s() freq=%ld\n", __func__, RfFreqHz);
-
-	/* Set MxL5005S tuner RF frequency according to example code. */
-
-	/* Tuner RF frequency setting stage 0 */
-	MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET);
-	AddrTable[0] = MASTER_CONTROL_ADDR;
-	ByteTable[0] |= state->config->AgcMasterByte;
-
-	mxl5005s_writeregs(fe, AddrTable, ByteTable, 1);
-
-	/* Tuner RF frequency setting stage 1 */
-	MXL_TuneRF(fe, RfFreqHz);
-
-	MXL_ControlRead(fe, IF_DIVVAL, &IfDivval);
-
-	MXL_ControlWrite(fe, SEQ_FSM_PULSE, 0);
-	MXL_ControlWrite(fe, SEQ_EXTPOWERUP, 1);
-	MXL_ControlWrite(fe, IF_DIVVAL, 8);
-	MXL_GetCHRegister(fe, AddrTable, ByteTable, &TableLen);
-
-	MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START);
-	AddrTable[TableLen] = MASTER_CONTROL_ADDR ;
-	ByteTable[TableLen] = MasterControlByte |
-		state->config->AgcMasterByte;
-	TableLen += 1;
-
-	mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen);
-
-	/* Wait 30 ms. */
-	msleep(150);
-
-	/* Tuner RF frequency setting stage 2 */
-	MXL_ControlWrite(fe, SEQ_FSM_PULSE, 1);
-	MXL_ControlWrite(fe, IF_DIVVAL, IfDivval);
-	MXL_GetCHRegister_ZeroIF(fe, AddrTable, ByteTable, &TableLen);
-
-	MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START);
-	AddrTable[TableLen] = MASTER_CONTROL_ADDR ;
-	ByteTable[TableLen] = MasterControlByte |
-		state->config->AgcMasterByte ;
-	TableLen += 1;
-
-	mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen);
-
-	msleep(100);
-
-	return 0;
-}
-/* End: Custom code taken from the Realtek driver */
-
-/* ----------------------------------------------------------------
- * Begin: Reference driver code found in the Realtek driver.
- * Copyright (C) 2008 MaxLinear
- */
-static u16 MXL5005_RegisterInit(struct dvb_frontend *fe)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	state->TunerRegs_Num = TUNER_REGS_NUM ;
-
-	state->TunerRegs[0].Reg_Num = 9 ;
-	state->TunerRegs[0].Reg_Val = 0x40 ;
-
-	state->TunerRegs[1].Reg_Num = 11 ;
-	state->TunerRegs[1].Reg_Val = 0x19 ;
-
-	state->TunerRegs[2].Reg_Num = 12 ;
-	state->TunerRegs[2].Reg_Val = 0x60 ;
-
-	state->TunerRegs[3].Reg_Num = 13 ;
-	state->TunerRegs[3].Reg_Val = 0x00 ;
-
-	state->TunerRegs[4].Reg_Num = 14 ;
-	state->TunerRegs[4].Reg_Val = 0x00 ;
-
-	state->TunerRegs[5].Reg_Num = 15 ;
-	state->TunerRegs[5].Reg_Val = 0xC0 ;
-
-	state->TunerRegs[6].Reg_Num = 16 ;
-	state->TunerRegs[6].Reg_Val = 0x00 ;
-
-	state->TunerRegs[7].Reg_Num = 17 ;
-	state->TunerRegs[7].Reg_Val = 0x00 ;
-
-	state->TunerRegs[8].Reg_Num = 18 ;
-	state->TunerRegs[8].Reg_Val = 0x00 ;
-
-	state->TunerRegs[9].Reg_Num = 19 ;
-	state->TunerRegs[9].Reg_Val = 0x34 ;
-
-	state->TunerRegs[10].Reg_Num = 21 ;
-	state->TunerRegs[10].Reg_Val = 0x00 ;
-
-	state->TunerRegs[11].Reg_Num = 22 ;
-	state->TunerRegs[11].Reg_Val = 0x6B ;
-
-	state->TunerRegs[12].Reg_Num = 23 ;
-	state->TunerRegs[12].Reg_Val = 0x35 ;
-
-	state->TunerRegs[13].Reg_Num = 24 ;
-	state->TunerRegs[13].Reg_Val = 0x70 ;
-
-	state->TunerRegs[14].Reg_Num = 25 ;
-	state->TunerRegs[14].Reg_Val = 0x3E ;
-
-	state->TunerRegs[15].Reg_Num = 26 ;
-	state->TunerRegs[15].Reg_Val = 0x82 ;
-
-	state->TunerRegs[16].Reg_Num = 31 ;
-	state->TunerRegs[16].Reg_Val = 0x00 ;
-
-	state->TunerRegs[17].Reg_Num = 32 ;
-	state->TunerRegs[17].Reg_Val = 0x40 ;
-
-	state->TunerRegs[18].Reg_Num = 33 ;
-	state->TunerRegs[18].Reg_Val = 0x53 ;
-
-	state->TunerRegs[19].Reg_Num = 34 ;
-	state->TunerRegs[19].Reg_Val = 0x81 ;
-
-	state->TunerRegs[20].Reg_Num = 35 ;
-	state->TunerRegs[20].Reg_Val = 0xC9 ;
-
-	state->TunerRegs[21].Reg_Num = 36 ;
-	state->TunerRegs[21].Reg_Val = 0x01 ;
-
-	state->TunerRegs[22].Reg_Num = 37 ;
-	state->TunerRegs[22].Reg_Val = 0x00 ;
-
-	state->TunerRegs[23].Reg_Num = 41 ;
-	state->TunerRegs[23].Reg_Val = 0x00 ;
-
-	state->TunerRegs[24].Reg_Num = 42 ;
-	state->TunerRegs[24].Reg_Val = 0xF8 ;
-
-	state->TunerRegs[25].Reg_Num = 43 ;
-	state->TunerRegs[25].Reg_Val = 0x43 ;
-
-	state->TunerRegs[26].Reg_Num = 44 ;
-	state->TunerRegs[26].Reg_Val = 0x20 ;
-
-	state->TunerRegs[27].Reg_Num = 45 ;
-	state->TunerRegs[27].Reg_Val = 0x80 ;
-
-	state->TunerRegs[28].Reg_Num = 46 ;
-	state->TunerRegs[28].Reg_Val = 0x88 ;
-
-	state->TunerRegs[29].Reg_Num = 47 ;
-	state->TunerRegs[29].Reg_Val = 0x86 ;
-
-	state->TunerRegs[30].Reg_Num = 48 ;
-	state->TunerRegs[30].Reg_Val = 0x00 ;
-
-	state->TunerRegs[31].Reg_Num = 49 ;
-	state->TunerRegs[31].Reg_Val = 0x00 ;
-
-	state->TunerRegs[32].Reg_Num = 53 ;
-	state->TunerRegs[32].Reg_Val = 0x94 ;
-
-	state->TunerRegs[33].Reg_Num = 54 ;
-	state->TunerRegs[33].Reg_Val = 0xFA ;
-
-	state->TunerRegs[34].Reg_Num = 55 ;
-	state->TunerRegs[34].Reg_Val = 0x92 ;
-
-	state->TunerRegs[35].Reg_Num = 56 ;
-	state->TunerRegs[35].Reg_Val = 0x80 ;
-
-	state->TunerRegs[36].Reg_Num = 57 ;
-	state->TunerRegs[36].Reg_Val = 0x41 ;
-
-	state->TunerRegs[37].Reg_Num = 58 ;
-	state->TunerRegs[37].Reg_Val = 0xDB ;
-
-	state->TunerRegs[38].Reg_Num = 59 ;
-	state->TunerRegs[38].Reg_Val = 0x00 ;
-
-	state->TunerRegs[39].Reg_Num = 60 ;
-	state->TunerRegs[39].Reg_Val = 0x00 ;
-
-	state->TunerRegs[40].Reg_Num = 61 ;
-	state->TunerRegs[40].Reg_Val = 0x00 ;
-
-	state->TunerRegs[41].Reg_Num = 62 ;
-	state->TunerRegs[41].Reg_Val = 0x00 ;
-
-	state->TunerRegs[42].Reg_Num = 65 ;
-	state->TunerRegs[42].Reg_Val = 0xF8 ;
-
-	state->TunerRegs[43].Reg_Num = 66 ;
-	state->TunerRegs[43].Reg_Val = 0xE4 ;
-
-	state->TunerRegs[44].Reg_Num = 67 ;
-	state->TunerRegs[44].Reg_Val = 0x90 ;
-
-	state->TunerRegs[45].Reg_Num = 68 ;
-	state->TunerRegs[45].Reg_Val = 0xC0 ;
-
-	state->TunerRegs[46].Reg_Num = 69 ;
-	state->TunerRegs[46].Reg_Val = 0x01 ;
-
-	state->TunerRegs[47].Reg_Num = 70 ;
-	state->TunerRegs[47].Reg_Val = 0x50 ;
-
-	state->TunerRegs[48].Reg_Num = 71 ;
-	state->TunerRegs[48].Reg_Val = 0x06 ;
-
-	state->TunerRegs[49].Reg_Num = 72 ;
-	state->TunerRegs[49].Reg_Val = 0x00 ;
-
-	state->TunerRegs[50].Reg_Num = 73 ;
-	state->TunerRegs[50].Reg_Val = 0x20 ;
-
-	state->TunerRegs[51].Reg_Num = 76 ;
-	state->TunerRegs[51].Reg_Val = 0xBB ;
-
-	state->TunerRegs[52].Reg_Num = 77 ;
-	state->TunerRegs[52].Reg_Val = 0x13 ;
-
-	state->TunerRegs[53].Reg_Num = 81 ;
-	state->TunerRegs[53].Reg_Val = 0x04 ;
-
-	state->TunerRegs[54].Reg_Num = 82 ;
-	state->TunerRegs[54].Reg_Val = 0x75 ;
-
-	state->TunerRegs[55].Reg_Num = 83 ;
-	state->TunerRegs[55].Reg_Val = 0x00 ;
-
-	state->TunerRegs[56].Reg_Num = 84 ;
-	state->TunerRegs[56].Reg_Val = 0x00 ;
-
-	state->TunerRegs[57].Reg_Num = 85 ;
-	state->TunerRegs[57].Reg_Val = 0x00 ;
-
-	state->TunerRegs[58].Reg_Num = 91 ;
-	state->TunerRegs[58].Reg_Val = 0x70 ;
-
-	state->TunerRegs[59].Reg_Num = 92 ;
-	state->TunerRegs[59].Reg_Val = 0x00 ;
-
-	state->TunerRegs[60].Reg_Num = 93 ;
-	state->TunerRegs[60].Reg_Val = 0x00 ;
-
-	state->TunerRegs[61].Reg_Num = 94 ;
-	state->TunerRegs[61].Reg_Val = 0x00 ;
-
-	state->TunerRegs[62].Reg_Num = 95 ;
-	state->TunerRegs[62].Reg_Val = 0x0C ;
-
-	state->TunerRegs[63].Reg_Num = 96 ;
-	state->TunerRegs[63].Reg_Val = 0x00 ;
-
-	state->TunerRegs[64].Reg_Num = 97 ;
-	state->TunerRegs[64].Reg_Val = 0x00 ;
-
-	state->TunerRegs[65].Reg_Num = 98 ;
-	state->TunerRegs[65].Reg_Val = 0xE2 ;
-
-	state->TunerRegs[66].Reg_Num = 99 ;
-	state->TunerRegs[66].Reg_Val = 0x00 ;
-
-	state->TunerRegs[67].Reg_Num = 100 ;
-	state->TunerRegs[67].Reg_Val = 0x00 ;
-
-	state->TunerRegs[68].Reg_Num = 101 ;
-	state->TunerRegs[68].Reg_Val = 0x12 ;
-
-	state->TunerRegs[69].Reg_Num = 102 ;
-	state->TunerRegs[69].Reg_Val = 0x80 ;
-
-	state->TunerRegs[70].Reg_Num = 103 ;
-	state->TunerRegs[70].Reg_Val = 0x32 ;
-
-	state->TunerRegs[71].Reg_Num = 104 ;
-	state->TunerRegs[71].Reg_Val = 0xB4 ;
-
-	state->TunerRegs[72].Reg_Num = 105 ;
-	state->TunerRegs[72].Reg_Val = 0x60 ;
-
-	state->TunerRegs[73].Reg_Num = 106 ;
-	state->TunerRegs[73].Reg_Val = 0x83 ;
-
-	state->TunerRegs[74].Reg_Num = 107 ;
-	state->TunerRegs[74].Reg_Val = 0x84 ;
-
-	state->TunerRegs[75].Reg_Num = 108 ;
-	state->TunerRegs[75].Reg_Val = 0x9C ;
-
-	state->TunerRegs[76].Reg_Num = 109 ;
-	state->TunerRegs[76].Reg_Val = 0x02 ;
-
-	state->TunerRegs[77].Reg_Num = 110 ;
-	state->TunerRegs[77].Reg_Val = 0x81 ;
-
-	state->TunerRegs[78].Reg_Num = 111 ;
-	state->TunerRegs[78].Reg_Val = 0xC0 ;
-
-	state->TunerRegs[79].Reg_Num = 112 ;
-	state->TunerRegs[79].Reg_Val = 0x10 ;
-
-	state->TunerRegs[80].Reg_Num = 131 ;
-	state->TunerRegs[80].Reg_Val = 0x8A ;
-
-	state->TunerRegs[81].Reg_Num = 132 ;
-	state->TunerRegs[81].Reg_Val = 0x10 ;
-
-	state->TunerRegs[82].Reg_Num = 133 ;
-	state->TunerRegs[82].Reg_Val = 0x24 ;
-
-	state->TunerRegs[83].Reg_Num = 134 ;
-	state->TunerRegs[83].Reg_Val = 0x00 ;
-
-	state->TunerRegs[84].Reg_Num = 135 ;
-	state->TunerRegs[84].Reg_Val = 0x00 ;
-
-	state->TunerRegs[85].Reg_Num = 136 ;
-	state->TunerRegs[85].Reg_Val = 0x7E ;
-
-	state->TunerRegs[86].Reg_Num = 137 ;
-	state->TunerRegs[86].Reg_Val = 0x40 ;
-
-	state->TunerRegs[87].Reg_Num = 138 ;
-	state->TunerRegs[87].Reg_Val = 0x38 ;
-
-	state->TunerRegs[88].Reg_Num = 146 ;
-	state->TunerRegs[88].Reg_Val = 0xF6 ;
-
-	state->TunerRegs[89].Reg_Num = 147 ;
-	state->TunerRegs[89].Reg_Val = 0x1A ;
-
-	state->TunerRegs[90].Reg_Num = 148 ;
-	state->TunerRegs[90].Reg_Val = 0x62 ;
-
-	state->TunerRegs[91].Reg_Num = 149 ;
-	state->TunerRegs[91].Reg_Val = 0x33 ;
-
-	state->TunerRegs[92].Reg_Num = 150 ;
-	state->TunerRegs[92].Reg_Val = 0x80 ;
-
-	state->TunerRegs[93].Reg_Num = 156 ;
-	state->TunerRegs[93].Reg_Val = 0x56 ;
-
-	state->TunerRegs[94].Reg_Num = 157 ;
-	state->TunerRegs[94].Reg_Val = 0x17 ;
-
-	state->TunerRegs[95].Reg_Num = 158 ;
-	state->TunerRegs[95].Reg_Val = 0xA9 ;
-
-	state->TunerRegs[96].Reg_Num = 159 ;
-	state->TunerRegs[96].Reg_Val = 0x00 ;
-
-	state->TunerRegs[97].Reg_Num = 160 ;
-	state->TunerRegs[97].Reg_Val = 0x00 ;
-
-	state->TunerRegs[98].Reg_Num = 161 ;
-	state->TunerRegs[98].Reg_Val = 0x00 ;
-
-	state->TunerRegs[99].Reg_Num = 162 ;
-	state->TunerRegs[99].Reg_Val = 0x40 ;
-
-	state->TunerRegs[100].Reg_Num = 166 ;
-	state->TunerRegs[100].Reg_Val = 0xAE ;
-
-	state->TunerRegs[101].Reg_Num = 167 ;
-	state->TunerRegs[101].Reg_Val = 0x1B ;
-
-	state->TunerRegs[102].Reg_Num = 168 ;
-	state->TunerRegs[102].Reg_Val = 0xF2 ;
-
-	state->TunerRegs[103].Reg_Num = 195 ;
-	state->TunerRegs[103].Reg_Val = 0x00 ;
-
-	return 0 ;
-}
-
-static u16 MXL5005_ControlInit(struct dvb_frontend *fe)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	state->Init_Ctrl_Num = INITCTRL_NUM;
-
-	state->Init_Ctrl[0].Ctrl_Num = DN_IQTN_AMP_CUT ;
-	state->Init_Ctrl[0].size = 1 ;
-	state->Init_Ctrl[0].addr[0] = 73;
-	state->Init_Ctrl[0].bit[0] = 7;
-	state->Init_Ctrl[0].val[0] = 0;
-
-	state->Init_Ctrl[1].Ctrl_Num = BB_MODE ;
-	state->Init_Ctrl[1].size = 1 ;
-	state->Init_Ctrl[1].addr[0] = 53;
-	state->Init_Ctrl[1].bit[0] = 2;
-	state->Init_Ctrl[1].val[0] = 1;
-
-	state->Init_Ctrl[2].Ctrl_Num = BB_BUF ;
-	state->Init_Ctrl[2].size = 2 ;
-	state->Init_Ctrl[2].addr[0] = 53;
-	state->Init_Ctrl[2].bit[0] = 1;
-	state->Init_Ctrl[2].val[0] = 0;
-	state->Init_Ctrl[2].addr[1] = 57;
-	state->Init_Ctrl[2].bit[1] = 0;
-	state->Init_Ctrl[2].val[1] = 1;
-
-	state->Init_Ctrl[3].Ctrl_Num = BB_BUF_OA ;
-	state->Init_Ctrl[3].size = 1 ;
-	state->Init_Ctrl[3].addr[0] = 53;
-	state->Init_Ctrl[3].bit[0] = 0;
-	state->Init_Ctrl[3].val[0] = 0;
-
-	state->Init_Ctrl[4].Ctrl_Num = BB_ALPF_BANDSELECT ;
-	state->Init_Ctrl[4].size = 3 ;
-	state->Init_Ctrl[4].addr[0] = 53;
-	state->Init_Ctrl[4].bit[0] = 5;
-	state->Init_Ctrl[4].val[0] = 0;
-	state->Init_Ctrl[4].addr[1] = 53;
-	state->Init_Ctrl[4].bit[1] = 6;
-	state->Init_Ctrl[4].val[1] = 0;
-	state->Init_Ctrl[4].addr[2] = 53;
-	state->Init_Ctrl[4].bit[2] = 7;
-	state->Init_Ctrl[4].val[2] = 1;
-
-	state->Init_Ctrl[5].Ctrl_Num = BB_IQSWAP ;
-	state->Init_Ctrl[5].size = 1 ;
-	state->Init_Ctrl[5].addr[0] = 59;
-	state->Init_Ctrl[5].bit[0] = 0;
-	state->Init_Ctrl[5].val[0] = 0;
-
-	state->Init_Ctrl[6].Ctrl_Num = BB_DLPF_BANDSEL ;
-	state->Init_Ctrl[6].size = 2 ;
-	state->Init_Ctrl[6].addr[0] = 53;
-	state->Init_Ctrl[6].bit[0] = 3;
-	state->Init_Ctrl[6].val[0] = 0;
-	state->Init_Ctrl[6].addr[1] = 53;
-	state->Init_Ctrl[6].bit[1] = 4;
-	state->Init_Ctrl[6].val[1] = 1;
-
-	state->Init_Ctrl[7].Ctrl_Num = RFSYN_CHP_GAIN ;
-	state->Init_Ctrl[7].size = 4 ;
-	state->Init_Ctrl[7].addr[0] = 22;
-	state->Init_Ctrl[7].bit[0] = 4;
-	state->Init_Ctrl[7].val[0] = 0;
-	state->Init_Ctrl[7].addr[1] = 22;
-	state->Init_Ctrl[7].bit[1] = 5;
-	state->Init_Ctrl[7].val[1] = 1;
-	state->Init_Ctrl[7].addr[2] = 22;
-	state->Init_Ctrl[7].bit[2] = 6;
-	state->Init_Ctrl[7].val[2] = 1;
-	state->Init_Ctrl[7].addr[3] = 22;
-	state->Init_Ctrl[7].bit[3] = 7;
-	state->Init_Ctrl[7].val[3] = 0;
-
-	state->Init_Ctrl[8].Ctrl_Num = RFSYN_EN_CHP_HIGAIN ;
-	state->Init_Ctrl[8].size = 1 ;
-	state->Init_Ctrl[8].addr[0] = 22;
-	state->Init_Ctrl[8].bit[0] = 2;
-	state->Init_Ctrl[8].val[0] = 0;
-
-	state->Init_Ctrl[9].Ctrl_Num = AGC_IF ;
-	state->Init_Ctrl[9].size = 4 ;
-	state->Init_Ctrl[9].addr[0] = 76;
-	state->Init_Ctrl[9].bit[0] = 0;
-	state->Init_Ctrl[9].val[0] = 1;
-	state->Init_Ctrl[9].addr[1] = 76;
-	state->Init_Ctrl[9].bit[1] = 1;
-	state->Init_Ctrl[9].val[1] = 1;
-	state->Init_Ctrl[9].addr[2] = 76;
-	state->Init_Ctrl[9].bit[2] = 2;
-	state->Init_Ctrl[9].val[2] = 0;
-	state->Init_Ctrl[9].addr[3] = 76;
-	state->Init_Ctrl[9].bit[3] = 3;
-	state->Init_Ctrl[9].val[3] = 1;
-
-	state->Init_Ctrl[10].Ctrl_Num = AGC_RF ;
-	state->Init_Ctrl[10].size = 4 ;
-	state->Init_Ctrl[10].addr[0] = 76;
-	state->Init_Ctrl[10].bit[0] = 4;
-	state->Init_Ctrl[10].val[0] = 1;
-	state->Init_Ctrl[10].addr[1] = 76;
-	state->Init_Ctrl[10].bit[1] = 5;
-	state->Init_Ctrl[10].val[1] = 1;
-	state->Init_Ctrl[10].addr[2] = 76;
-	state->Init_Ctrl[10].bit[2] = 6;
-	state->Init_Ctrl[10].val[2] = 0;
-	state->Init_Ctrl[10].addr[3] = 76;
-	state->Init_Ctrl[10].bit[3] = 7;
-	state->Init_Ctrl[10].val[3] = 1;
-
-	state->Init_Ctrl[11].Ctrl_Num = IF_DIVVAL ;
-	state->Init_Ctrl[11].size = 5 ;
-	state->Init_Ctrl[11].addr[0] = 43;
-	state->Init_Ctrl[11].bit[0] = 3;
-	state->Init_Ctrl[11].val[0] = 0;
-	state->Init_Ctrl[11].addr[1] = 43;
-	state->Init_Ctrl[11].bit[1] = 4;
-	state->Init_Ctrl[11].val[1] = 0;
-	state->Init_Ctrl[11].addr[2] = 43;
-	state->Init_Ctrl[11].bit[2] = 5;
-	state->Init_Ctrl[11].val[2] = 0;
-	state->Init_Ctrl[11].addr[3] = 43;
-	state->Init_Ctrl[11].bit[3] = 6;
-	state->Init_Ctrl[11].val[3] = 1;
-	state->Init_Ctrl[11].addr[4] = 43;
-	state->Init_Ctrl[11].bit[4] = 7;
-	state->Init_Ctrl[11].val[4] = 0;
-
-	state->Init_Ctrl[12].Ctrl_Num = IF_VCO_BIAS ;
-	state->Init_Ctrl[12].size = 6 ;
-	state->Init_Ctrl[12].addr[0] = 44;
-	state->Init_Ctrl[12].bit[0] = 2;
-	state->Init_Ctrl[12].val[0] = 0;
-	state->Init_Ctrl[12].addr[1] = 44;
-	state->Init_Ctrl[12].bit[1] = 3;
-	state->Init_Ctrl[12].val[1] = 0;
-	state->Init_Ctrl[12].addr[2] = 44;
-	state->Init_Ctrl[12].bit[2] = 4;
-	state->Init_Ctrl[12].val[2] = 0;
-	state->Init_Ctrl[12].addr[3] = 44;
-	state->Init_Ctrl[12].bit[3] = 5;
-	state->Init_Ctrl[12].val[3] = 1;
-	state->Init_Ctrl[12].addr[4] = 44;
-	state->Init_Ctrl[12].bit[4] = 6;
-	state->Init_Ctrl[12].val[4] = 0;
-	state->Init_Ctrl[12].addr[5] = 44;
-	state->Init_Ctrl[12].bit[5] = 7;
-	state->Init_Ctrl[12].val[5] = 0;
-
-	state->Init_Ctrl[13].Ctrl_Num = CHCAL_INT_MOD_IF ;
-	state->Init_Ctrl[13].size = 7 ;
-	state->Init_Ctrl[13].addr[0] = 11;
-	state->Init_Ctrl[13].bit[0] = 0;
-	state->Init_Ctrl[13].val[0] = 1;
-	state->Init_Ctrl[13].addr[1] = 11;
-	state->Init_Ctrl[13].bit[1] = 1;
-	state->Init_Ctrl[13].val[1] = 0;
-	state->Init_Ctrl[13].addr[2] = 11;
-	state->Init_Ctrl[13].bit[2] = 2;
-	state->Init_Ctrl[13].val[2] = 0;
-	state->Init_Ctrl[13].addr[3] = 11;
-	state->Init_Ctrl[13].bit[3] = 3;
-	state->Init_Ctrl[13].val[3] = 1;
-	state->Init_Ctrl[13].addr[4] = 11;
-	state->Init_Ctrl[13].bit[4] = 4;
-	state->Init_Ctrl[13].val[4] = 1;
-	state->Init_Ctrl[13].addr[5] = 11;
-	state->Init_Ctrl[13].bit[5] = 5;
-	state->Init_Ctrl[13].val[5] = 0;
-	state->Init_Ctrl[13].addr[6] = 11;
-	state->Init_Ctrl[13].bit[6] = 6;
-	state->Init_Ctrl[13].val[6] = 0;
-
-	state->Init_Ctrl[14].Ctrl_Num = CHCAL_FRAC_MOD_IF ;
-	state->Init_Ctrl[14].size = 16 ;
-	state->Init_Ctrl[14].addr[0] = 13;
-	state->Init_Ctrl[14].bit[0] = 0;
-	state->Init_Ctrl[14].val[0] = 0;
-	state->Init_Ctrl[14].addr[1] = 13;
-	state->Init_Ctrl[14].bit[1] = 1;
-	state->Init_Ctrl[14].val[1] = 0;
-	state->Init_Ctrl[14].addr[2] = 13;
-	state->Init_Ctrl[14].bit[2] = 2;
-	state->Init_Ctrl[14].val[2] = 0;
-	state->Init_Ctrl[14].addr[3] = 13;
-	state->Init_Ctrl[14].bit[3] = 3;
-	state->Init_Ctrl[14].val[3] = 0;
-	state->Init_Ctrl[14].addr[4] = 13;
-	state->Init_Ctrl[14].bit[4] = 4;
-	state->Init_Ctrl[14].val[4] = 0;
-	state->Init_Ctrl[14].addr[5] = 13;
-	state->Init_Ctrl[14].bit[5] = 5;
-	state->Init_Ctrl[14].val[5] = 0;
-	state->Init_Ctrl[14].addr[6] = 13;
-	state->Init_Ctrl[14].bit[6] = 6;
-	state->Init_Ctrl[14].val[6] = 0;
-	state->Init_Ctrl[14].addr[7] = 13;
-	state->Init_Ctrl[14].bit[7] = 7;
-	state->Init_Ctrl[14].val[7] = 0;
-	state->Init_Ctrl[14].addr[8] = 12;
-	state->Init_Ctrl[14].bit[8] = 0;
-	state->Init_Ctrl[14].val[8] = 0;
-	state->Init_Ctrl[14].addr[9] = 12;
-	state->Init_Ctrl[14].bit[9] = 1;
-	state->Init_Ctrl[14].val[9] = 0;
-	state->Init_Ctrl[14].addr[10] = 12;
-	state->Init_Ctrl[14].bit[10] = 2;
-	state->Init_Ctrl[14].val[10] = 0;
-	state->Init_Ctrl[14].addr[11] = 12;
-	state->Init_Ctrl[14].bit[11] = 3;
-	state->Init_Ctrl[14].val[11] = 0;
-	state->Init_Ctrl[14].addr[12] = 12;
-	state->Init_Ctrl[14].bit[12] = 4;
-	state->Init_Ctrl[14].val[12] = 0;
-	state->Init_Ctrl[14].addr[13] = 12;
-	state->Init_Ctrl[14].bit[13] = 5;
-	state->Init_Ctrl[14].val[13] = 1;
-	state->Init_Ctrl[14].addr[14] = 12;
-	state->Init_Ctrl[14].bit[14] = 6;
-	state->Init_Ctrl[14].val[14] = 1;
-	state->Init_Ctrl[14].addr[15] = 12;
-	state->Init_Ctrl[14].bit[15] = 7;
-	state->Init_Ctrl[14].val[15] = 0;
-
-	state->Init_Ctrl[15].Ctrl_Num = DRV_RES_SEL ;
-	state->Init_Ctrl[15].size = 3 ;
-	state->Init_Ctrl[15].addr[0] = 147;
-	state->Init_Ctrl[15].bit[0] = 2;
-	state->Init_Ctrl[15].val[0] = 0;
-	state->Init_Ctrl[15].addr[1] = 147;
-	state->Init_Ctrl[15].bit[1] = 3;
-	state->Init_Ctrl[15].val[1] = 1;
-	state->Init_Ctrl[15].addr[2] = 147;
-	state->Init_Ctrl[15].bit[2] = 4;
-	state->Init_Ctrl[15].val[2] = 1;
-
-	state->Init_Ctrl[16].Ctrl_Num = I_DRIVER ;
-	state->Init_Ctrl[16].size = 2 ;
-	state->Init_Ctrl[16].addr[0] = 147;
-	state->Init_Ctrl[16].bit[0] = 0;
-	state->Init_Ctrl[16].val[0] = 0;
-	state->Init_Ctrl[16].addr[1] = 147;
-	state->Init_Ctrl[16].bit[1] = 1;
-	state->Init_Ctrl[16].val[1] = 1;
-
-	state->Init_Ctrl[17].Ctrl_Num = EN_AAF ;
-	state->Init_Ctrl[17].size = 1 ;
-	state->Init_Ctrl[17].addr[0] = 147;
-	state->Init_Ctrl[17].bit[0] = 7;
-	state->Init_Ctrl[17].val[0] = 0;
-
-	state->Init_Ctrl[18].Ctrl_Num = EN_3P ;
-	state->Init_Ctrl[18].size = 1 ;
-	state->Init_Ctrl[18].addr[0] = 147;
-	state->Init_Ctrl[18].bit[0] = 6;
-	state->Init_Ctrl[18].val[0] = 0;
-
-	state->Init_Ctrl[19].Ctrl_Num = EN_AUX_3P ;
-	state->Init_Ctrl[19].size = 1 ;
-	state->Init_Ctrl[19].addr[0] = 156;
-	state->Init_Ctrl[19].bit[0] = 0;
-	state->Init_Ctrl[19].val[0] = 0;
-
-	state->Init_Ctrl[20].Ctrl_Num = SEL_AAF_BAND ;
-	state->Init_Ctrl[20].size = 1 ;
-	state->Init_Ctrl[20].addr[0] = 147;
-	state->Init_Ctrl[20].bit[0] = 5;
-	state->Init_Ctrl[20].val[0] = 0;
-
-	state->Init_Ctrl[21].Ctrl_Num = SEQ_ENCLK16_CLK_OUT ;
-	state->Init_Ctrl[21].size = 1 ;
-	state->Init_Ctrl[21].addr[0] = 137;
-	state->Init_Ctrl[21].bit[0] = 4;
-	state->Init_Ctrl[21].val[0] = 0;
-
-	state->Init_Ctrl[22].Ctrl_Num = SEQ_SEL4_16B ;
-	state->Init_Ctrl[22].size = 1 ;
-	state->Init_Ctrl[22].addr[0] = 137;
-	state->Init_Ctrl[22].bit[0] = 7;
-	state->Init_Ctrl[22].val[0] = 0;
-
-	state->Init_Ctrl[23].Ctrl_Num = XTAL_CAPSELECT ;
-	state->Init_Ctrl[23].size = 1 ;
-	state->Init_Ctrl[23].addr[0] = 91;
-	state->Init_Ctrl[23].bit[0] = 5;
-	state->Init_Ctrl[23].val[0] = 1;
-
-	state->Init_Ctrl[24].Ctrl_Num = IF_SEL_DBL ;
-	state->Init_Ctrl[24].size = 1 ;
-	state->Init_Ctrl[24].addr[0] = 43;
-	state->Init_Ctrl[24].bit[0] = 0;
-	state->Init_Ctrl[24].val[0] = 1;
-
-	state->Init_Ctrl[25].Ctrl_Num = RFSYN_R_DIV ;
-	state->Init_Ctrl[25].size = 2 ;
-	state->Init_Ctrl[25].addr[0] = 22;
-	state->Init_Ctrl[25].bit[0] = 0;
-	state->Init_Ctrl[25].val[0] = 1;
-	state->Init_Ctrl[25].addr[1] = 22;
-	state->Init_Ctrl[25].bit[1] = 1;
-	state->Init_Ctrl[25].val[1] = 1;
-
-	state->Init_Ctrl[26].Ctrl_Num = SEQ_EXTSYNTHCALIF ;
-	state->Init_Ctrl[26].size = 1 ;
-	state->Init_Ctrl[26].addr[0] = 134;
-	state->Init_Ctrl[26].bit[0] = 2;
-	state->Init_Ctrl[26].val[0] = 0;
-
-	state->Init_Ctrl[27].Ctrl_Num = SEQ_EXTDCCAL ;
-	state->Init_Ctrl[27].size = 1 ;
-	state->Init_Ctrl[27].addr[0] = 137;
-	state->Init_Ctrl[27].bit[0] = 3;
-	state->Init_Ctrl[27].val[0] = 0;
-
-	state->Init_Ctrl[28].Ctrl_Num = AGC_EN_RSSI ;
-	state->Init_Ctrl[28].size = 1 ;
-	state->Init_Ctrl[28].addr[0] = 77;
-	state->Init_Ctrl[28].bit[0] = 7;
-	state->Init_Ctrl[28].val[0] = 0;
-
-	state->Init_Ctrl[29].Ctrl_Num = RFA_ENCLKRFAGC ;
-	state->Init_Ctrl[29].size = 1 ;
-	state->Init_Ctrl[29].addr[0] = 166;
-	state->Init_Ctrl[29].bit[0] = 7;
-	state->Init_Ctrl[29].val[0] = 1;
-
-	state->Init_Ctrl[30].Ctrl_Num = RFA_RSSI_REFH ;
-	state->Init_Ctrl[30].size = 3 ;
-	state->Init_Ctrl[30].addr[0] = 166;
-	state->Init_Ctrl[30].bit[0] = 0;
-	state->Init_Ctrl[30].val[0] = 0;
-	state->Init_Ctrl[30].addr[1] = 166;
-	state->Init_Ctrl[30].bit[1] = 1;
-	state->Init_Ctrl[30].val[1] = 1;
-	state->Init_Ctrl[30].addr[2] = 166;
-	state->Init_Ctrl[30].bit[2] = 2;
-	state->Init_Ctrl[30].val[2] = 1;
-
-	state->Init_Ctrl[31].Ctrl_Num = RFA_RSSI_REF ;
-	state->Init_Ctrl[31].size = 3 ;
-	state->Init_Ctrl[31].addr[0] = 166;
-	state->Init_Ctrl[31].bit[0] = 3;
-	state->Init_Ctrl[31].val[0] = 1;
-	state->Init_Ctrl[31].addr[1] = 166;
-	state->Init_Ctrl[31].bit[1] = 4;
-	state->Init_Ctrl[31].val[1] = 0;
-	state->Init_Ctrl[31].addr[2] = 166;
-	state->Init_Ctrl[31].bit[2] = 5;
-	state->Init_Ctrl[31].val[2] = 1;
-
-	state->Init_Ctrl[32].Ctrl_Num = RFA_RSSI_REFL ;
-	state->Init_Ctrl[32].size = 3 ;
-	state->Init_Ctrl[32].addr[0] = 167;
-	state->Init_Ctrl[32].bit[0] = 0;
-	state->Init_Ctrl[32].val[0] = 1;
-	state->Init_Ctrl[32].addr[1] = 167;
-	state->Init_Ctrl[32].bit[1] = 1;
-	state->Init_Ctrl[32].val[1] = 1;
-	state->Init_Ctrl[32].addr[2] = 167;
-	state->Init_Ctrl[32].bit[2] = 2;
-	state->Init_Ctrl[32].val[2] = 0;
-
-	state->Init_Ctrl[33].Ctrl_Num = RFA_FLR ;
-	state->Init_Ctrl[33].size = 4 ;
-	state->Init_Ctrl[33].addr[0] = 168;
-	state->Init_Ctrl[33].bit[0] = 0;
-	state->Init_Ctrl[33].val[0] = 0;
-	state->Init_Ctrl[33].addr[1] = 168;
-	state->Init_Ctrl[33].bit[1] = 1;
-	state->Init_Ctrl[33].val[1] = 1;
-	state->Init_Ctrl[33].addr[2] = 168;
-	state->Init_Ctrl[33].bit[2] = 2;
-	state->Init_Ctrl[33].val[2] = 0;
-	state->Init_Ctrl[33].addr[3] = 168;
-	state->Init_Ctrl[33].bit[3] = 3;
-	state->Init_Ctrl[33].val[3] = 0;
-
-	state->Init_Ctrl[34].Ctrl_Num = RFA_CEIL ;
-	state->Init_Ctrl[34].size = 4 ;
-	state->Init_Ctrl[34].addr[0] = 168;
-	state->Init_Ctrl[34].bit[0] = 4;
-	state->Init_Ctrl[34].val[0] = 1;
-	state->Init_Ctrl[34].addr[1] = 168;
-	state->Init_Ctrl[34].bit[1] = 5;
-	state->Init_Ctrl[34].val[1] = 1;
-	state->Init_Ctrl[34].addr[2] = 168;
-	state->Init_Ctrl[34].bit[2] = 6;
-	state->Init_Ctrl[34].val[2] = 1;
-	state->Init_Ctrl[34].addr[3] = 168;
-	state->Init_Ctrl[34].bit[3] = 7;
-	state->Init_Ctrl[34].val[3] = 1;
-
-	state->Init_Ctrl[35].Ctrl_Num = SEQ_EXTIQFSMPULSE ;
-	state->Init_Ctrl[35].size = 1 ;
-	state->Init_Ctrl[35].addr[0] = 135;
-	state->Init_Ctrl[35].bit[0] = 0;
-	state->Init_Ctrl[35].val[0] = 0;
-
-	state->Init_Ctrl[36].Ctrl_Num = OVERRIDE_1 ;
-	state->Init_Ctrl[36].size = 1 ;
-	state->Init_Ctrl[36].addr[0] = 56;
-	state->Init_Ctrl[36].bit[0] = 3;
-	state->Init_Ctrl[36].val[0] = 0;
-
-	state->Init_Ctrl[37].Ctrl_Num = BB_INITSTATE_DLPF_TUNE ;
-	state->Init_Ctrl[37].size = 7 ;
-	state->Init_Ctrl[37].addr[0] = 59;
-	state->Init_Ctrl[37].bit[0] = 1;
-	state->Init_Ctrl[37].val[0] = 0;
-	state->Init_Ctrl[37].addr[1] = 59;
-	state->Init_Ctrl[37].bit[1] = 2;
-	state->Init_Ctrl[37].val[1] = 0;
-	state->Init_Ctrl[37].addr[2] = 59;
-	state->Init_Ctrl[37].bit[2] = 3;
-	state->Init_Ctrl[37].val[2] = 0;
-	state->Init_Ctrl[37].addr[3] = 59;
-	state->Init_Ctrl[37].bit[3] = 4;
-	state->Init_Ctrl[37].val[3] = 0;
-	state->Init_Ctrl[37].addr[4] = 59;
-	state->Init_Ctrl[37].bit[4] = 5;
-	state->Init_Ctrl[37].val[4] = 0;
-	state->Init_Ctrl[37].addr[5] = 59;
-	state->Init_Ctrl[37].bit[5] = 6;
-	state->Init_Ctrl[37].val[5] = 0;
-	state->Init_Ctrl[37].addr[6] = 59;
-	state->Init_Ctrl[37].bit[6] = 7;
-	state->Init_Ctrl[37].val[6] = 0;
-
-	state->Init_Ctrl[38].Ctrl_Num = TG_R_DIV ;
-	state->Init_Ctrl[38].size = 6 ;
-	state->Init_Ctrl[38].addr[0] = 32;
-	state->Init_Ctrl[38].bit[0] = 2;
-	state->Init_Ctrl[38].val[0] = 0;
-	state->Init_Ctrl[38].addr[1] = 32;
-	state->Init_Ctrl[38].bit[1] = 3;
-	state->Init_Ctrl[38].val[1] = 0;
-	state->Init_Ctrl[38].addr[2] = 32;
-	state->Init_Ctrl[38].bit[2] = 4;
-	state->Init_Ctrl[38].val[2] = 0;
-	state->Init_Ctrl[38].addr[3] = 32;
-	state->Init_Ctrl[38].bit[3] = 5;
-	state->Init_Ctrl[38].val[3] = 0;
-	state->Init_Ctrl[38].addr[4] = 32;
-	state->Init_Ctrl[38].bit[4] = 6;
-	state->Init_Ctrl[38].val[4] = 1;
-	state->Init_Ctrl[38].addr[5] = 32;
-	state->Init_Ctrl[38].bit[5] = 7;
-	state->Init_Ctrl[38].val[5] = 0;
-
-	state->Init_Ctrl[39].Ctrl_Num = EN_CHP_LIN_B ;
-	state->Init_Ctrl[39].size = 1 ;
-	state->Init_Ctrl[39].addr[0] = 25;
-	state->Init_Ctrl[39].bit[0] = 3;
-	state->Init_Ctrl[39].val[0] = 1;
-
-
-	state->CH_Ctrl_Num = CHCTRL_NUM ;
-
-	state->CH_Ctrl[0].Ctrl_Num = DN_POLY ;
-	state->CH_Ctrl[0].size = 2 ;
-	state->CH_Ctrl[0].addr[0] = 68;
-	state->CH_Ctrl[0].bit[0] = 6;
-	state->CH_Ctrl[0].val[0] = 1;
-	state->CH_Ctrl[0].addr[1] = 68;
-	state->CH_Ctrl[0].bit[1] = 7;
-	state->CH_Ctrl[0].val[1] = 1;
-
-	state->CH_Ctrl[1].Ctrl_Num = DN_RFGAIN ;
-	state->CH_Ctrl[1].size = 2 ;
-	state->CH_Ctrl[1].addr[0] = 70;
-	state->CH_Ctrl[1].bit[0] = 6;
-	state->CH_Ctrl[1].val[0] = 1;
-	state->CH_Ctrl[1].addr[1] = 70;
-	state->CH_Ctrl[1].bit[1] = 7;
-	state->CH_Ctrl[1].val[1] = 0;
-
-	state->CH_Ctrl[2].Ctrl_Num = DN_CAP_RFLPF ;
-	state->CH_Ctrl[2].size = 9 ;
-	state->CH_Ctrl[2].addr[0] = 69;
-	state->CH_Ctrl[2].bit[0] = 5;
-	state->CH_Ctrl[2].val[0] = 0;
-	state->CH_Ctrl[2].addr[1] = 69;
-	state->CH_Ctrl[2].bit[1] = 6;
-	state->CH_Ctrl[2].val[1] = 0;
-	state->CH_Ctrl[2].addr[2] = 69;
-	state->CH_Ctrl[2].bit[2] = 7;
-	state->CH_Ctrl[2].val[2] = 0;
-	state->CH_Ctrl[2].addr[3] = 68;
-	state->CH_Ctrl[2].bit[3] = 0;
-	state->CH_Ctrl[2].val[3] = 0;
-	state->CH_Ctrl[2].addr[4] = 68;
-	state->CH_Ctrl[2].bit[4] = 1;
-	state->CH_Ctrl[2].val[4] = 0;
-	state->CH_Ctrl[2].addr[5] = 68;
-	state->CH_Ctrl[2].bit[5] = 2;
-	state->CH_Ctrl[2].val[5] = 0;
-	state->CH_Ctrl[2].addr[6] = 68;
-	state->CH_Ctrl[2].bit[6] = 3;
-	state->CH_Ctrl[2].val[6] = 0;
-	state->CH_Ctrl[2].addr[7] = 68;
-	state->CH_Ctrl[2].bit[7] = 4;
-	state->CH_Ctrl[2].val[7] = 0;
-	state->CH_Ctrl[2].addr[8] = 68;
-	state->CH_Ctrl[2].bit[8] = 5;
-	state->CH_Ctrl[2].val[8] = 0;
-
-	state->CH_Ctrl[3].Ctrl_Num = DN_EN_VHFUHFBAR ;
-	state->CH_Ctrl[3].size = 1 ;
-	state->CH_Ctrl[3].addr[0] = 70;
-	state->CH_Ctrl[3].bit[0] = 5;
-	state->CH_Ctrl[3].val[0] = 0;
-
-	state->CH_Ctrl[4].Ctrl_Num = DN_GAIN_ADJUST ;
-	state->CH_Ctrl[4].size = 3 ;
-	state->CH_Ctrl[4].addr[0] = 73;
-	state->CH_Ctrl[4].bit[0] = 4;
-	state->CH_Ctrl[4].val[0] = 0;
-	state->CH_Ctrl[4].addr[1] = 73;
-	state->CH_Ctrl[4].bit[1] = 5;
-	state->CH_Ctrl[4].val[1] = 1;
-	state->CH_Ctrl[4].addr[2] = 73;
-	state->CH_Ctrl[4].bit[2] = 6;
-	state->CH_Ctrl[4].val[2] = 0;
-
-	state->CH_Ctrl[5].Ctrl_Num = DN_IQTNBUF_AMP ;
-	state->CH_Ctrl[5].size = 4 ;
-	state->CH_Ctrl[5].addr[0] = 70;
-	state->CH_Ctrl[5].bit[0] = 0;
-	state->CH_Ctrl[5].val[0] = 0;
-	state->CH_Ctrl[5].addr[1] = 70;
-	state->CH_Ctrl[5].bit[1] = 1;
-	state->CH_Ctrl[5].val[1] = 0;
-	state->CH_Ctrl[5].addr[2] = 70;
-	state->CH_Ctrl[5].bit[2] = 2;
-	state->CH_Ctrl[5].val[2] = 0;
-	state->CH_Ctrl[5].addr[3] = 70;
-	state->CH_Ctrl[5].bit[3] = 3;
-	state->CH_Ctrl[5].val[3] = 0;
-
-	state->CH_Ctrl[6].Ctrl_Num = DN_IQTNGNBFBIAS_BST ;
-	state->CH_Ctrl[6].size = 1 ;
-	state->CH_Ctrl[6].addr[0] = 70;
-	state->CH_Ctrl[6].bit[0] = 4;
-	state->CH_Ctrl[6].val[0] = 1;
-
-	state->CH_Ctrl[7].Ctrl_Num = RFSYN_EN_OUTMUX ;
-	state->CH_Ctrl[7].size = 1 ;
-	state->CH_Ctrl[7].addr[0] = 111;
-	state->CH_Ctrl[7].bit[0] = 4;
-	state->CH_Ctrl[7].val[0] = 0;
-
-	state->CH_Ctrl[8].Ctrl_Num = RFSYN_SEL_VCO_OUT ;
-	state->CH_Ctrl[8].size = 1 ;
-	state->CH_Ctrl[8].addr[0] = 111;
-	state->CH_Ctrl[8].bit[0] = 7;
-	state->CH_Ctrl[8].val[0] = 1;
-
-	state->CH_Ctrl[9].Ctrl_Num = RFSYN_SEL_VCO_HI ;
-	state->CH_Ctrl[9].size = 1 ;
-	state->CH_Ctrl[9].addr[0] = 111;
-	state->CH_Ctrl[9].bit[0] = 6;
-	state->CH_Ctrl[9].val[0] = 1;
-
-	state->CH_Ctrl[10].Ctrl_Num = RFSYN_SEL_DIVM ;
-	state->CH_Ctrl[10].size = 1 ;
-	state->CH_Ctrl[10].addr[0] = 111;
-	state->CH_Ctrl[10].bit[0] = 5;
-	state->CH_Ctrl[10].val[0] = 0;
-
-	state->CH_Ctrl[11].Ctrl_Num = RFSYN_RF_DIV_BIAS ;
-	state->CH_Ctrl[11].size = 2 ;
-	state->CH_Ctrl[11].addr[0] = 110;
-	state->CH_Ctrl[11].bit[0] = 0;
-	state->CH_Ctrl[11].val[0] = 1;
-	state->CH_Ctrl[11].addr[1] = 110;
-	state->CH_Ctrl[11].bit[1] = 1;
-	state->CH_Ctrl[11].val[1] = 0;
-
-	state->CH_Ctrl[12].Ctrl_Num = DN_SEL_FREQ ;
-	state->CH_Ctrl[12].size = 3 ;
-	state->CH_Ctrl[12].addr[0] = 69;
-	state->CH_Ctrl[12].bit[0] = 2;
-	state->CH_Ctrl[12].val[0] = 0;
-	state->CH_Ctrl[12].addr[1] = 69;
-	state->CH_Ctrl[12].bit[1] = 3;
-	state->CH_Ctrl[12].val[1] = 0;
-	state->CH_Ctrl[12].addr[2] = 69;
-	state->CH_Ctrl[12].bit[2] = 4;
-	state->CH_Ctrl[12].val[2] = 0;
-
-	state->CH_Ctrl[13].Ctrl_Num = RFSYN_VCO_BIAS ;
-	state->CH_Ctrl[13].size = 6 ;
-	state->CH_Ctrl[13].addr[0] = 110;
-	state->CH_Ctrl[13].bit[0] = 2;
-	state->CH_Ctrl[13].val[0] = 0;
-	state->CH_Ctrl[13].addr[1] = 110;
-	state->CH_Ctrl[13].bit[1] = 3;
-	state->CH_Ctrl[13].val[1] = 0;
-	state->CH_Ctrl[13].addr[2] = 110;
-	state->CH_Ctrl[13].bit[2] = 4;
-	state->CH_Ctrl[13].val[2] = 0;
-	state->CH_Ctrl[13].addr[3] = 110;
-	state->CH_Ctrl[13].bit[3] = 5;
-	state->CH_Ctrl[13].val[3] = 0;
-	state->CH_Ctrl[13].addr[4] = 110;
-	state->CH_Ctrl[13].bit[4] = 6;
-	state->CH_Ctrl[13].val[4] = 0;
-	state->CH_Ctrl[13].addr[5] = 110;
-	state->CH_Ctrl[13].bit[5] = 7;
-	state->CH_Ctrl[13].val[5] = 1;
-
-	state->CH_Ctrl[14].Ctrl_Num = CHCAL_INT_MOD_RF ;
-	state->CH_Ctrl[14].size = 7 ;
-	state->CH_Ctrl[14].addr[0] = 14;
-	state->CH_Ctrl[14].bit[0] = 0;
-	state->CH_Ctrl[14].val[0] = 0;
-	state->CH_Ctrl[14].addr[1] = 14;
-	state->CH_Ctrl[14].bit[1] = 1;
-	state->CH_Ctrl[14].val[1] = 0;
-	state->CH_Ctrl[14].addr[2] = 14;
-	state->CH_Ctrl[14].bit[2] = 2;
-	state->CH_Ctrl[14].val[2] = 0;
-	state->CH_Ctrl[14].addr[3] = 14;
-	state->CH_Ctrl[14].bit[3] = 3;
-	state->CH_Ctrl[14].val[3] = 0;
-	state->CH_Ctrl[14].addr[4] = 14;
-	state->CH_Ctrl[14].bit[4] = 4;
-	state->CH_Ctrl[14].val[4] = 0;
-	state->CH_Ctrl[14].addr[5] = 14;
-	state->CH_Ctrl[14].bit[5] = 5;
-	state->CH_Ctrl[14].val[5] = 0;
-	state->CH_Ctrl[14].addr[6] = 14;
-	state->CH_Ctrl[14].bit[6] = 6;
-	state->CH_Ctrl[14].val[6] = 0;
-
-	state->CH_Ctrl[15].Ctrl_Num = CHCAL_FRAC_MOD_RF ;
-	state->CH_Ctrl[15].size = 18 ;
-	state->CH_Ctrl[15].addr[0] = 17;
-	state->CH_Ctrl[15].bit[0] = 6;
-	state->CH_Ctrl[15].val[0] = 0;
-	state->CH_Ctrl[15].addr[1] = 17;
-	state->CH_Ctrl[15].bit[1] = 7;
-	state->CH_Ctrl[15].val[1] = 0;
-	state->CH_Ctrl[15].addr[2] = 16;
-	state->CH_Ctrl[15].bit[2] = 0;
-	state->CH_Ctrl[15].val[2] = 0;
-	state->CH_Ctrl[15].addr[3] = 16;
-	state->CH_Ctrl[15].bit[3] = 1;
-	state->CH_Ctrl[15].val[3] = 0;
-	state->CH_Ctrl[15].addr[4] = 16;
-	state->CH_Ctrl[15].bit[4] = 2;
-	state->CH_Ctrl[15].val[4] = 0;
-	state->CH_Ctrl[15].addr[5] = 16;
-	state->CH_Ctrl[15].bit[5] = 3;
-	state->CH_Ctrl[15].val[5] = 0;
-	state->CH_Ctrl[15].addr[6] = 16;
-	state->CH_Ctrl[15].bit[6] = 4;
-	state->CH_Ctrl[15].val[6] = 0;
-	state->CH_Ctrl[15].addr[7] = 16;
-	state->CH_Ctrl[15].bit[7] = 5;
-	state->CH_Ctrl[15].val[7] = 0;
-	state->CH_Ctrl[15].addr[8] = 16;
-	state->CH_Ctrl[15].bit[8] = 6;
-	state->CH_Ctrl[15].val[8] = 0;
-	state->CH_Ctrl[15].addr[9] = 16;
-	state->CH_Ctrl[15].bit[9] = 7;
-	state->CH_Ctrl[15].val[9] = 0;
-	state->CH_Ctrl[15].addr[10] = 15;
-	state->CH_Ctrl[15].bit[10] = 0;
-	state->CH_Ctrl[15].val[10] = 0;
-	state->CH_Ctrl[15].addr[11] = 15;
-	state->CH_Ctrl[15].bit[11] = 1;
-	state->CH_Ctrl[15].val[11] = 0;
-	state->CH_Ctrl[15].addr[12] = 15;
-	state->CH_Ctrl[15].bit[12] = 2;
-	state->CH_Ctrl[15].val[12] = 0;
-	state->CH_Ctrl[15].addr[13] = 15;
-	state->CH_Ctrl[15].bit[13] = 3;
-	state->CH_Ctrl[15].val[13] = 0;
-	state->CH_Ctrl[15].addr[14] = 15;
-	state->CH_Ctrl[15].bit[14] = 4;
-	state->CH_Ctrl[15].val[14] = 0;
-	state->CH_Ctrl[15].addr[15] = 15;
-	state->CH_Ctrl[15].bit[15] = 5;
-	state->CH_Ctrl[15].val[15] = 0;
-	state->CH_Ctrl[15].addr[16] = 15;
-	state->CH_Ctrl[15].bit[16] = 6;
-	state->CH_Ctrl[15].val[16] = 1;
-	state->CH_Ctrl[15].addr[17] = 15;
-	state->CH_Ctrl[15].bit[17] = 7;
-	state->CH_Ctrl[15].val[17] = 1;
-
-	state->CH_Ctrl[16].Ctrl_Num = RFSYN_LPF_R ;
-	state->CH_Ctrl[16].size = 5 ;
-	state->CH_Ctrl[16].addr[0] = 112;
-	state->CH_Ctrl[16].bit[0] = 0;
-	state->CH_Ctrl[16].val[0] = 0;
-	state->CH_Ctrl[16].addr[1] = 112;
-	state->CH_Ctrl[16].bit[1] = 1;
-	state->CH_Ctrl[16].val[1] = 0;
-	state->CH_Ctrl[16].addr[2] = 112;
-	state->CH_Ctrl[16].bit[2] = 2;
-	state->CH_Ctrl[16].val[2] = 0;
-	state->CH_Ctrl[16].addr[3] = 112;
-	state->CH_Ctrl[16].bit[3] = 3;
-	state->CH_Ctrl[16].val[3] = 0;
-	state->CH_Ctrl[16].addr[4] = 112;
-	state->CH_Ctrl[16].bit[4] = 4;
-	state->CH_Ctrl[16].val[4] = 1;
-
-	state->CH_Ctrl[17].Ctrl_Num = CHCAL_EN_INT_RF ;
-	state->CH_Ctrl[17].size = 1 ;
-	state->CH_Ctrl[17].addr[0] = 14;
-	state->CH_Ctrl[17].bit[0] = 7;
-	state->CH_Ctrl[17].val[0] = 0;
-
-	state->CH_Ctrl[18].Ctrl_Num = TG_LO_DIVVAL ;
-	state->CH_Ctrl[18].size = 4 ;
-	state->CH_Ctrl[18].addr[0] = 107;
-	state->CH_Ctrl[18].bit[0] = 3;
-	state->CH_Ctrl[18].val[0] = 0;
-	state->CH_Ctrl[18].addr[1] = 107;
-	state->CH_Ctrl[18].bit[1] = 4;
-	state->CH_Ctrl[18].val[1] = 0;
-	state->CH_Ctrl[18].addr[2] = 107;
-	state->CH_Ctrl[18].bit[2] = 5;
-	state->CH_Ctrl[18].val[2] = 0;
-	state->CH_Ctrl[18].addr[3] = 107;
-	state->CH_Ctrl[18].bit[3] = 6;
-	state->CH_Ctrl[18].val[3] = 0;
-
-	state->CH_Ctrl[19].Ctrl_Num = TG_LO_SELVAL ;
-	state->CH_Ctrl[19].size = 3 ;
-	state->CH_Ctrl[19].addr[0] = 107;
-	state->CH_Ctrl[19].bit[0] = 7;
-	state->CH_Ctrl[19].val[0] = 1;
-	state->CH_Ctrl[19].addr[1] = 106;
-	state->CH_Ctrl[19].bit[1] = 0;
-	state->CH_Ctrl[19].val[1] = 1;
-	state->CH_Ctrl[19].addr[2] = 106;
-	state->CH_Ctrl[19].bit[2] = 1;
-	state->CH_Ctrl[19].val[2] = 1;
-
-	state->CH_Ctrl[20].Ctrl_Num = TG_DIV_VAL ;
-	state->CH_Ctrl[20].size = 11 ;
-	state->CH_Ctrl[20].addr[0] = 109;
-	state->CH_Ctrl[20].bit[0] = 2;
-	state->CH_Ctrl[20].val[0] = 0;
-	state->CH_Ctrl[20].addr[1] = 109;
-	state->CH_Ctrl[20].bit[1] = 3;
-	state->CH_Ctrl[20].val[1] = 0;
-	state->CH_Ctrl[20].addr[2] = 109;
-	state->CH_Ctrl[20].bit[2] = 4;
-	state->CH_Ctrl[20].val[2] = 0;
-	state->CH_Ctrl[20].addr[3] = 109;
-	state->CH_Ctrl[20].bit[3] = 5;
-	state->CH_Ctrl[20].val[3] = 0;
-	state->CH_Ctrl[20].addr[4] = 109;
-	state->CH_Ctrl[20].bit[4] = 6;
-	state->CH_Ctrl[20].val[4] = 0;
-	state->CH_Ctrl[20].addr[5] = 109;
-	state->CH_Ctrl[20].bit[5] = 7;
-	state->CH_Ctrl[20].val[5] = 0;
-	state->CH_Ctrl[20].addr[6] = 108;
-	state->CH_Ctrl[20].bit[6] = 0;
-	state->CH_Ctrl[20].val[6] = 0;
-	state->CH_Ctrl[20].addr[7] = 108;
-	state->CH_Ctrl[20].bit[7] = 1;
-	state->CH_Ctrl[20].val[7] = 0;
-	state->CH_Ctrl[20].addr[8] = 108;
-	state->CH_Ctrl[20].bit[8] = 2;
-	state->CH_Ctrl[20].val[8] = 1;
-	state->CH_Ctrl[20].addr[9] = 108;
-	state->CH_Ctrl[20].bit[9] = 3;
-	state->CH_Ctrl[20].val[9] = 1;
-	state->CH_Ctrl[20].addr[10] = 108;
-	state->CH_Ctrl[20].bit[10] = 4;
-	state->CH_Ctrl[20].val[10] = 1;
-
-	state->CH_Ctrl[21].Ctrl_Num = TG_VCO_BIAS ;
-	state->CH_Ctrl[21].size = 6 ;
-	state->CH_Ctrl[21].addr[0] = 106;
-	state->CH_Ctrl[21].bit[0] = 2;
-	state->CH_Ctrl[21].val[0] = 0;
-	state->CH_Ctrl[21].addr[1] = 106;
-	state->CH_Ctrl[21].bit[1] = 3;
-	state->CH_Ctrl[21].val[1] = 0;
-	state->CH_Ctrl[21].addr[2] = 106;
-	state->CH_Ctrl[21].bit[2] = 4;
-	state->CH_Ctrl[21].val[2] = 0;
-	state->CH_Ctrl[21].addr[3] = 106;
-	state->CH_Ctrl[21].bit[3] = 5;
-	state->CH_Ctrl[21].val[3] = 0;
-	state->CH_Ctrl[21].addr[4] = 106;
-	state->CH_Ctrl[21].bit[4] = 6;
-	state->CH_Ctrl[21].val[4] = 0;
-	state->CH_Ctrl[21].addr[5] = 106;
-	state->CH_Ctrl[21].bit[5] = 7;
-	state->CH_Ctrl[21].val[5] = 1;
-
-	state->CH_Ctrl[22].Ctrl_Num = SEQ_EXTPOWERUP ;
-	state->CH_Ctrl[22].size = 1 ;
-	state->CH_Ctrl[22].addr[0] = 138;
-	state->CH_Ctrl[22].bit[0] = 4;
-	state->CH_Ctrl[22].val[0] = 1;
-
-	state->CH_Ctrl[23].Ctrl_Num = OVERRIDE_2 ;
-	state->CH_Ctrl[23].size = 1 ;
-	state->CH_Ctrl[23].addr[0] = 17;
-	state->CH_Ctrl[23].bit[0] = 5;
-	state->CH_Ctrl[23].val[0] = 0;
-
-	state->CH_Ctrl[24].Ctrl_Num = OVERRIDE_3 ;
-	state->CH_Ctrl[24].size = 1 ;
-	state->CH_Ctrl[24].addr[0] = 111;
-	state->CH_Ctrl[24].bit[0] = 3;
-	state->CH_Ctrl[24].val[0] = 0;
-
-	state->CH_Ctrl[25].Ctrl_Num = OVERRIDE_4 ;
-	state->CH_Ctrl[25].size = 1 ;
-	state->CH_Ctrl[25].addr[0] = 112;
-	state->CH_Ctrl[25].bit[0] = 7;
-	state->CH_Ctrl[25].val[0] = 0;
-
-	state->CH_Ctrl[26].Ctrl_Num = SEQ_FSM_PULSE ;
-	state->CH_Ctrl[26].size = 1 ;
-	state->CH_Ctrl[26].addr[0] = 136;
-	state->CH_Ctrl[26].bit[0] = 7;
-	state->CH_Ctrl[26].val[0] = 0;
-
-	state->CH_Ctrl[27].Ctrl_Num = GPIO_4B ;
-	state->CH_Ctrl[27].size = 1 ;
-	state->CH_Ctrl[27].addr[0] = 149;
-	state->CH_Ctrl[27].bit[0] = 7;
-	state->CH_Ctrl[27].val[0] = 0;
-
-	state->CH_Ctrl[28].Ctrl_Num = GPIO_3B ;
-	state->CH_Ctrl[28].size = 1 ;
-	state->CH_Ctrl[28].addr[0] = 149;
-	state->CH_Ctrl[28].bit[0] = 6;
-	state->CH_Ctrl[28].val[0] = 0;
-
-	state->CH_Ctrl[29].Ctrl_Num = GPIO_4 ;
-	state->CH_Ctrl[29].size = 1 ;
-	state->CH_Ctrl[29].addr[0] = 149;
-	state->CH_Ctrl[29].bit[0] = 5;
-	state->CH_Ctrl[29].val[0] = 1;
-
-	state->CH_Ctrl[30].Ctrl_Num = GPIO_3 ;
-	state->CH_Ctrl[30].size = 1 ;
-	state->CH_Ctrl[30].addr[0] = 149;
-	state->CH_Ctrl[30].bit[0] = 4;
-	state->CH_Ctrl[30].val[0] = 1;
-
-	state->CH_Ctrl[31].Ctrl_Num = GPIO_1B ;
-	state->CH_Ctrl[31].size = 1 ;
-	state->CH_Ctrl[31].addr[0] = 149;
-	state->CH_Ctrl[31].bit[0] = 3;
-	state->CH_Ctrl[31].val[0] = 0;
-
-	state->CH_Ctrl[32].Ctrl_Num = DAC_A_ENABLE ;
-	state->CH_Ctrl[32].size = 1 ;
-	state->CH_Ctrl[32].addr[0] = 93;
-	state->CH_Ctrl[32].bit[0] = 1;
-	state->CH_Ctrl[32].val[0] = 0;
-
-	state->CH_Ctrl[33].Ctrl_Num = DAC_B_ENABLE ;
-	state->CH_Ctrl[33].size = 1 ;
-	state->CH_Ctrl[33].addr[0] = 93;
-	state->CH_Ctrl[33].bit[0] = 0;
-	state->CH_Ctrl[33].val[0] = 0;
-
-	state->CH_Ctrl[34].Ctrl_Num = DAC_DIN_A ;
-	state->CH_Ctrl[34].size = 6 ;
-	state->CH_Ctrl[34].addr[0] = 92;
-	state->CH_Ctrl[34].bit[0] = 2;
-	state->CH_Ctrl[34].val[0] = 0;
-	state->CH_Ctrl[34].addr[1] = 92;
-	state->CH_Ctrl[34].bit[1] = 3;
-	state->CH_Ctrl[34].val[1] = 0;
-	state->CH_Ctrl[34].addr[2] = 92;
-	state->CH_Ctrl[34].bit[2] = 4;
-	state->CH_Ctrl[34].val[2] = 0;
-	state->CH_Ctrl[34].addr[3] = 92;
-	state->CH_Ctrl[34].bit[3] = 5;
-	state->CH_Ctrl[34].val[3] = 0;
-	state->CH_Ctrl[34].addr[4] = 92;
-	state->CH_Ctrl[34].bit[4] = 6;
-	state->CH_Ctrl[34].val[4] = 0;
-	state->CH_Ctrl[34].addr[5] = 92;
-	state->CH_Ctrl[34].bit[5] = 7;
-	state->CH_Ctrl[34].val[5] = 0;
-
-	state->CH_Ctrl[35].Ctrl_Num = DAC_DIN_B ;
-	state->CH_Ctrl[35].size = 6 ;
-	state->CH_Ctrl[35].addr[0] = 93;
-	state->CH_Ctrl[35].bit[0] = 2;
-	state->CH_Ctrl[35].val[0] = 0;
-	state->CH_Ctrl[35].addr[1] = 93;
-	state->CH_Ctrl[35].bit[1] = 3;
-	state->CH_Ctrl[35].val[1] = 0;
-	state->CH_Ctrl[35].addr[2] = 93;
-	state->CH_Ctrl[35].bit[2] = 4;
-	state->CH_Ctrl[35].val[2] = 0;
-	state->CH_Ctrl[35].addr[3] = 93;
-	state->CH_Ctrl[35].bit[3] = 5;
-	state->CH_Ctrl[35].val[3] = 0;
-	state->CH_Ctrl[35].addr[4] = 93;
-	state->CH_Ctrl[35].bit[4] = 6;
-	state->CH_Ctrl[35].val[4] = 0;
-	state->CH_Ctrl[35].addr[5] = 93;
-	state->CH_Ctrl[35].bit[5] = 7;
-	state->CH_Ctrl[35].val[5] = 0;
-
-#ifdef _MXL_PRODUCTION
-	state->CH_Ctrl[36].Ctrl_Num = RFSYN_EN_DIV ;
-	state->CH_Ctrl[36].size = 1 ;
-	state->CH_Ctrl[36].addr[0] = 109;
-	state->CH_Ctrl[36].bit[0] = 1;
-	state->CH_Ctrl[36].val[0] = 1;
-
-	state->CH_Ctrl[37].Ctrl_Num = RFSYN_DIVM ;
-	state->CH_Ctrl[37].size = 2 ;
-	state->CH_Ctrl[37].addr[0] = 112;
-	state->CH_Ctrl[37].bit[0] = 5;
-	state->CH_Ctrl[37].val[0] = 0;
-	state->CH_Ctrl[37].addr[1] = 112;
-	state->CH_Ctrl[37].bit[1] = 6;
-	state->CH_Ctrl[37].val[1] = 0;
-
-	state->CH_Ctrl[38].Ctrl_Num = DN_BYPASS_AGC_I2C ;
-	state->CH_Ctrl[38].size = 1 ;
-	state->CH_Ctrl[38].addr[0] = 65;
-	state->CH_Ctrl[38].bit[0] = 1;
-	state->CH_Ctrl[38].val[0] = 0;
-#endif
-
-	return 0 ;
-}
-
-static void InitTunerControls(struct dvb_frontend *fe)
-{
-	MXL5005_RegisterInit(fe);
-	MXL5005_ControlInit(fe);
-#ifdef _MXL_INTERNAL
-	MXL5005_MXLControlInit(fe);
-#endif
-}
-
-static u16 MXL5005_TunerConfig(struct dvb_frontend *fe,
-	u8	Mode,		/* 0: Analog Mode ; 1: Digital Mode */
-	u8	IF_mode,	/* for Analog Mode, 0: zero IF; 1: low IF */
-	u32	Bandwidth,	/* filter  channel bandwidth (6, 7, 8) */
-	u32	IF_out,		/* Desired IF Out Frequency */
-	u32	Fxtal,		/* XTAL Frequency */
-	u8	AGC_Mode,	/* AGC Mode - Dual AGC: 0, Single AGC: 1 */
-	u16	TOP,		/* 0: Dual AGC; Value: take over point */
-	u16	IF_OUT_LOAD,	/* IF Out Load Resistor (200 / 300 Ohms) */
-	u8	CLOCK_OUT, 	/* 0: turn off clk out; 1: turn on clock out */
-	u8	DIV_OUT,	/* 0: Div-1; 1: Div-4 */
-	u8	CAPSELECT, 	/* 0: disable On-Chip pulling cap; 1: enable */
-	u8	EN_RSSI, 	/* 0: disable RSSI; 1: enable RSSI */
-
-	/* Modulation Type; */
-	/* 0 - Default;	1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */
-	u8	Mod_Type,
-
-	/* Tracking Filter */
-	/* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */
-	u8	TF_Type
-	)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	u16 status = 0;
-
-	state->Mode = Mode;
-	state->IF_Mode = IF_mode;
-	state->Chan_Bandwidth = Bandwidth;
-	state->IF_OUT = IF_out;
-	state->Fxtal = Fxtal;
-	state->AGC_Mode = AGC_Mode;
-	state->TOP = TOP;
-	state->IF_OUT_LOAD = IF_OUT_LOAD;
-	state->CLOCK_OUT = CLOCK_OUT;
-	state->DIV_OUT = DIV_OUT;
-	state->CAPSELECT = CAPSELECT;
-	state->EN_RSSI = EN_RSSI;
-	state->Mod_Type = Mod_Type;
-	state->TF_Type = TF_Type;
-
-	/* Initialize all the controls and registers */
-	InitTunerControls(fe);
-
-	/* Synthesizer LO frequency calculation */
-	MXL_SynthIFLO_Calc(fe);
-
-	return status;
-}
-
-static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	if (state->Mode == 1) /* Digital Mode */
-		state->IF_LO = state->IF_OUT;
-	else /* Analog Mode */ {
-		if (state->IF_Mode == 0) /* Analog Zero IF mode */
-			state->IF_LO = state->IF_OUT + 400000;
-		else /* Analog Low IF mode */
-			state->IF_LO = state->IF_OUT + state->Chan_Bandwidth/2;
-	}
-}
-
-static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-
-	if (state->Mode == 1) /* Digital Mode */ {
-			/* remove 20.48MHz setting for 2.6.10 */
-			state->RF_LO = state->RF_IN;
-			/* change for 2.6.6 */
-			state->TG_LO = state->RF_IN - 750000;
-	} else /* Analog Mode */ {
-		if (state->IF_Mode == 0) /* Analog Zero IF mode */ {
-			state->RF_LO = state->RF_IN - 400000;
-			state->TG_LO = state->RF_IN - 1750000;
-		} else /* Analog Low IF mode */ {
-			state->RF_LO = state->RF_IN - state->Chan_Bandwidth/2;
-			state->TG_LO = state->RF_IN -
-				state->Chan_Bandwidth + 500000;
-		}
-	}
-}
-
-static u16 MXL_OverwriteICDefault(struct dvb_frontend *fe)
-{
-	u16 status = 0;
-
-	status += MXL_ControlWrite(fe, OVERRIDE_1, 1);
-	status += MXL_ControlWrite(fe, OVERRIDE_2, 1);
-	status += MXL_ControlWrite(fe, OVERRIDE_3, 1);
-	status += MXL_ControlWrite(fe, OVERRIDE_4, 1);
-
-	return status;
-}
-
-static u16 MXL_BlockInit(struct dvb_frontend *fe)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	u16 status = 0;
-
-	status += MXL_OverwriteICDefault(fe);
-
-	/* Downconverter Control Dig Ana */
-	status += MXL_ControlWrite(fe, DN_IQTN_AMP_CUT, state->Mode ? 1 : 0);
-
-	/* Filter Control  Dig  Ana */
-	status += MXL_ControlWrite(fe, BB_MODE, state->Mode ? 0 : 1);
-	status += MXL_ControlWrite(fe, BB_BUF, state->Mode ? 3 : 2);
-	status += MXL_ControlWrite(fe, BB_BUF_OA, state->Mode ? 1 : 0);
-	status += MXL_ControlWrite(fe, BB_IQSWAP, state->Mode ? 0 : 1);
-	status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 0);
-
-	/* Initialize Low-Pass Filter */
-	if (state->Mode) { /* Digital Mode */
-		switch (state->Chan_Bandwidth) {
-		case 8000000:
-			status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 0);
-			break;
-		case 7000000:
-			status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 2);
-			break;
-		case 6000000:
-			status += MXL_ControlWrite(fe,
-					BB_DLPF_BANDSEL, 3);
-			break;
-		}
-	} else { /* Analog Mode */
-		switch (state->Chan_Bandwidth) {
-		case 8000000:	/* Low Zero */
-			status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT,
-					(state->IF_Mode ? 0 : 3));
-			break;
-		case 7000000:
-			status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT,
-					(state->IF_Mode ? 1 : 4));
-			break;
-		case 6000000:
-			status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT,
-					(state->IF_Mode ? 2 : 5));
-			break;
-		}
-	}
-
-	/* Charge Pump Control Dig  Ana */
-	status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, state->Mode ? 5 : 8);
-	status += MXL_ControlWrite(fe,
-		RFSYN_EN_CHP_HIGAIN, state->Mode ? 1 : 1);
-	status += MXL_ControlWrite(fe, EN_CHP_LIN_B, state->Mode ? 0 : 0);
-
-	/* AGC TOP Control */
-	if (state->AGC_Mode == 0) /* Dual AGC */ {
-		status += MXL_ControlWrite(fe, AGC_IF, 15);
-		status += MXL_ControlWrite(fe, AGC_RF, 15);
-	} else /*  Single AGC Mode Dig  Ana */
-		status += MXL_ControlWrite(fe, AGC_RF, state->Mode ? 15 : 12);
-
-	if (state->TOP == 55) /* TOP == 5.5 */
-		status += MXL_ControlWrite(fe, AGC_IF, 0x0);
-
-	if (state->TOP == 72) /* TOP == 7.2 */
-		status += MXL_ControlWrite(fe, AGC_IF, 0x1);
-
-	if (state->TOP == 92) /* TOP == 9.2 */
-		status += MXL_ControlWrite(fe, AGC_IF, 0x2);
-
-	if (state->TOP == 110) /* TOP == 11.0 */
-		status += MXL_ControlWrite(fe, AGC_IF, 0x3);
-
-	if (state->TOP == 129) /* TOP == 12.9 */
-		status += MXL_ControlWrite(fe, AGC_IF, 0x4);
-
-	if (state->TOP == 147) /* TOP == 14.7 */
-		status += MXL_ControlWrite(fe, AGC_IF, 0x5);
-
-	if (state->TOP == 168) /* TOP == 16.8 */
-		status += MXL_ControlWrite(fe, AGC_IF, 0x6);
-
-	if (state->TOP == 194) /* TOP == 19.4 */
-		status += MXL_ControlWrite(fe, AGC_IF, 0x7);
-
-	if (state->TOP == 212) /* TOP == 21.2 */
-		status += MXL_ControlWrite(fe, AGC_IF, 0x9);
-
-	if (state->TOP == 232) /* TOP == 23.2 */
-		status += MXL_ControlWrite(fe, AGC_IF, 0xA);
-
-	if (state->TOP == 252) /* TOP == 25.2 */
-		status += MXL_ControlWrite(fe, AGC_IF, 0xB);
-
-	if (state->TOP == 271) /* TOP == 27.1 */
-		status += MXL_ControlWrite(fe, AGC_IF, 0xC);
-
-	if (state->TOP == 292) /* TOP == 29.2 */
-		status += MXL_ControlWrite(fe, AGC_IF, 0xD);
-
-	if (state->TOP == 317) /* TOP == 31.7 */
-		status += MXL_ControlWrite(fe, AGC_IF, 0xE);
-
-	if (state->TOP == 349) /* TOP == 34.9 */
-		status += MXL_ControlWrite(fe, AGC_IF, 0xF);
-
-	/* IF Synthesizer Control */
-	status += MXL_IFSynthInit(fe);
-
-	/* IF UpConverter Control */
-	if (state->IF_OUT_LOAD == 200) {
-		status += MXL_ControlWrite(fe, DRV_RES_SEL, 6);
-		status += MXL_ControlWrite(fe, I_DRIVER, 2);
-	}
-	if (state->IF_OUT_LOAD == 300) {
-		status += MXL_ControlWrite(fe, DRV_RES_SEL, 4);
-		status += MXL_ControlWrite(fe, I_DRIVER, 1);
-	}
-
-	/* Anti-Alias Filtering Control
-	 * initialise Anti-Aliasing Filter
-	 */
-	if (state->Mode) { /* Digital Mode */
-		if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 6280000UL) {
-			status += MXL_ControlWrite(fe, EN_AAF, 1);
-			status += MXL_ControlWrite(fe, EN_3P, 1);
-			status += MXL_ControlWrite(fe, EN_AUX_3P, 1);
-			status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0);
-		}
-		if ((state->IF_OUT == 36125000UL) ||
-			(state->IF_OUT == 36150000UL)) {
-			status += MXL_ControlWrite(fe, EN_AAF, 1);
-			status += MXL_ControlWrite(fe, EN_3P, 1);
-			status += MXL_ControlWrite(fe, EN_AUX_3P, 1);
-			status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1);
-		}
-		if (state->IF_OUT > 36150000UL) {
-			status += MXL_ControlWrite(fe, EN_AAF, 0);
-			status += MXL_ControlWrite(fe, EN_3P, 1);
-			status += MXL_ControlWrite(fe, EN_AUX_3P, 1);
-			status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1);
-		}
-	} else { /* Analog Mode */
-		if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 5000000UL) {
-			status += MXL_ControlWrite(fe, EN_AAF, 1);
-			status += MXL_ControlWrite(fe, EN_3P, 1);
-			status += MXL_ControlWrite(fe, EN_AUX_3P, 1);
-			status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0);
-		}
-		if (state->IF_OUT > 5000000UL) {
-			status += MXL_ControlWrite(fe, EN_AAF, 0);
-			status += MXL_ControlWrite(fe, EN_3P, 0);
-			status += MXL_ControlWrite(fe, EN_AUX_3P, 0);
-			status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0);
-		}
-	}
-
-	/* Demod Clock Out */
-	if (state->CLOCK_OUT)
-		status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 1);
-	else
-		status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 0);
-
-	if (state->DIV_OUT == 1)
-		status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 1);
-	if (state->DIV_OUT == 0)
-		status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 0);
-
-	/* Crystal Control */
-	if (state->CAPSELECT)
-		status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 1);
-	else
-		status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 0);
-
-	if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL)
-		status += MXL_ControlWrite(fe, IF_SEL_DBL, 1);
-	if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL)
-		status += MXL_ControlWrite(fe, IF_SEL_DBL, 0);
-
-	if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL)
-		status += MXL_ControlWrite(fe, RFSYN_R_DIV, 3);
-	if (state->Fxtal > 22000000UL && state->Fxtal <= 32000000UL)
-		status += MXL_ControlWrite(fe, RFSYN_R_DIV, 0);
-
-	/* Misc Controls */
-	if (state->Mode == 0 && state->IF_Mode == 1) /* Analog LowIF mode */
-		status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 0);
-	else
-		status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 1);
-
-	/* status += MXL_ControlRead(fe, IF_DIVVAL, &IF_DIVVAL_Val); */
-
-	/* Set TG_R_DIV */
-	status += MXL_ControlWrite(fe, TG_R_DIV,
-		MXL_Ceiling(state->Fxtal, 1000000));
-
-	/* Apply Default value to BB_INITSTATE_DLPF_TUNE */
-
-	/* RSSI Control */
-	if (state->EN_RSSI) {
-		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
-		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
-		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
-		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
-
-		/* RSSI reference point */
-		status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2);
-		status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 3);
-		status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1);
-
-		/* TOP point */
-		status += MXL_ControlWrite(fe, RFA_FLR, 0);
-		status += MXL_ControlWrite(fe, RFA_CEIL, 12);
-	}
-
-	/* Modulation type bit settings
-	 * Override the control values preset
-	 */
-	if (state->Mod_Type == MXL_DVBT) /* DVB-T Mode */ {
-		state->AGC_Mode = 1; /* Single AGC Mode */
-
-		/* Enable RSSI */
-		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
-		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
-		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
-		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
-
-		/* RSSI reference point */
-		status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3);
-		status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5);
-		status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1);
-
-		/* TOP point */
-		status += MXL_ControlWrite(fe, RFA_FLR, 2);
-		status += MXL_ControlWrite(fe, RFA_CEIL, 13);
-		if (state->IF_OUT <= 6280000UL)	/* Low IF */
-			status += MXL_ControlWrite(fe, BB_IQSWAP, 0);
-		else /* High IF */
-			status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
-
-	}
-	if (state->Mod_Type == MXL_ATSC) /* ATSC Mode */ {
-		state->AGC_Mode = 1;	/* Single AGC Mode */
-
-		/* Enable RSSI */
-		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
-		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
-		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
-		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
-
-		/* RSSI reference point */
-		status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2);
-		status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 4);
-		status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1);
-
-		/* TOP point */
-		status += MXL_ControlWrite(fe, RFA_FLR, 2);
-		status += MXL_ControlWrite(fe, RFA_CEIL, 13);
-		status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 1);
-		/* Low Zero */
-		status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5);
-
-		if (state->IF_OUT <= 6280000UL)	/* Low IF */
-			status += MXL_ControlWrite(fe, BB_IQSWAP, 0);
-		else /* High IF */
-			status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
-	}
-	if (state->Mod_Type == MXL_QAM) /* QAM Mode */ {
-		state->Mode = MXL_DIGITAL_MODE;
-
-		/* state->AGC_Mode = 1; */ /* Single AGC Mode */
-
-		/* Disable RSSI */	/* change here for v2.6.5 */
-		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
-		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
-		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0);
-		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
-
-		/* RSSI reference point */
-		status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5);
-		status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3);
-		status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2);
-		/* change here for v2.6.5 */
-		status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
-
-		if (state->IF_OUT <= 6280000UL)	/* Low IF */
-			status += MXL_ControlWrite(fe, BB_IQSWAP, 0);
-		else /* High IF */
-			status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
-		status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2);
-
-	}
-	if (state->Mod_Type == MXL_ANALOG_CABLE) {
-		/* Analog Cable Mode */
-		/* state->Mode = MXL_DIGITAL_MODE; */
-
-		state->AGC_Mode = 1; /* Single AGC Mode */
-
-		/* Disable RSSI */
-		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
-		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
-		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0);
-		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
-		/* change for 2.6.3 */
-		status += MXL_ControlWrite(fe, AGC_IF, 1);
-		status += MXL_ControlWrite(fe, AGC_RF, 15);
-		status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
-	}
-
-	if (state->Mod_Type == MXL_ANALOG_OTA) {
-		/* Analog OTA Terrestrial mode add for 2.6.7 */
-		/* state->Mode = MXL_ANALOG_MODE; */
-
-		/* Enable RSSI */
-		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
-		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
-		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
-		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
-
-		/* RSSI reference point */
-		status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5);
-		status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3);
-		status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2);
-		status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
-		status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
-	}
-
-	/* RSSI disable */
-	if (state->EN_RSSI == 0) {
-		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
-		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
-		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0);
-		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
-	}
-
-	return status;
-}
-
-static u16 MXL_IFSynthInit(struct dvb_frontend *fe)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	u16 status = 0 ;
-	u32	Fref = 0 ;
-	u32	Kdbl, intModVal ;
-	u32	fracModVal ;
-	Kdbl = 2 ;
-
-	if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL)
-		Kdbl = 2 ;
-	if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL)
-		Kdbl = 1 ;
-
-	/* IF Synthesizer Control */
-	if (state->Mode == 0 && state->IF_Mode == 1) /* Analog Low IF mode */ {
-		if (state->IF_LO == 41000000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
-			Fref = 328000000UL ;
-		}
-		if (state->IF_LO == 47000000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 376000000UL ;
-		}
-		if (state->IF_LO == 54000000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x10);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
-			Fref = 324000000UL ;
-		}
-		if (state->IF_LO == 60000000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x10);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 360000000UL ;
-		}
-		if (state->IF_LO == 39250000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
-			Fref = 314000000UL ;
-		}
-		if (state->IF_LO == 39650000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
-			Fref = 317200000UL ;
-		}
-		if (state->IF_LO == 40150000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
-			Fref = 321200000UL ;
-		}
-		if (state->IF_LO == 40650000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
-			Fref = 325200000UL ;
-		}
-	}
-
-	if (state->Mode || (state->Mode == 0 && state->IF_Mode == 0)) {
-		if (state->IF_LO == 57000000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x10);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 342000000UL ;
-		}
-		if (state->IF_LO == 44000000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 352000000UL ;
-		}
-		if (state->IF_LO == 43750000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 350000000UL ;
-		}
-		if (state->IF_LO == 36650000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 366500000UL ;
-		}
-		if (state->IF_LO == 36150000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 361500000UL ;
-		}
-		if (state->IF_LO == 36000000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 360000000UL ;
-		}
-		if (state->IF_LO == 35250000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 352500000UL ;
-		}
-		if (state->IF_LO == 34750000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 347500000UL ;
-		}
-		if (state->IF_LO == 6280000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x07);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 376800000UL ;
-		}
-		if (state->IF_LO == 5000000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x09);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 360000000UL ;
-		}
-		if (state->IF_LO == 4500000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x06);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 360000000UL ;
-		}
-		if (state->IF_LO == 4570000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x06);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 365600000UL ;
-		}
-		if (state->IF_LO == 4000000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x05);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 360000000UL ;
-		}
-		if (state->IF_LO == 57400000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x10);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 344400000UL ;
-		}
-		if (state->IF_LO == 44400000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 355200000UL ;
-		}
-		if (state->IF_LO == 44150000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 353200000UL ;
-		}
-		if (state->IF_LO == 37050000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 370500000UL ;
-		}
-		if (state->IF_LO == 36550000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 365500000UL ;
-		}
-		if (state->IF_LO == 36125000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 361250000UL ;
-		}
-		if (state->IF_LO == 6000000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x07);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 360000000UL ;
-		}
-		if (state->IF_LO == 5400000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x07);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
-			Fref = 324000000UL ;
-		}
-		if (state->IF_LO == 5380000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x07);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
-			Fref = 322800000UL ;
-		}
-		if (state->IF_LO == 5200000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x09);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 374400000UL ;
-		}
-		if (state->IF_LO == 4900000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x09);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 352800000UL ;
-		}
-		if (state->IF_LO == 4400000UL) {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x06);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 352000000UL ;
-		}
-		if (state->IF_LO == 4063000UL)  /* add for 2.6.8 */ {
-			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x05);
-			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
-			Fref = 365670000UL ;
-		}
-	}
-	/* CHCAL_INT_MOD_IF */
-	/* CHCAL_FRAC_MOD_IF */
-	intModVal = Fref / (state->Fxtal * Kdbl/2);
-	status += MXL_ControlWrite(fe, CHCAL_INT_MOD_IF, intModVal);
-
-	fracModVal = (2<<15)*(Fref/1000 - (state->Fxtal/1000 * Kdbl/2) *
-		intModVal);
-
-	fracModVal = fracModVal / ((state->Fxtal * Kdbl/2)/1000);
-	status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_IF, fracModVal);
-
-	return status ;
-}
-
-static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	u16 status = 0;
-	u32 divider_val, E3, E4, E5, E5A;
-	u32 Fmax, Fmin, FmaxBin, FminBin;
-	u32 Kdbl_RF = 2;
-	u32 tg_divval;
-	u32 tg_lo;
-
-	u32 Fref_TG;
-	u32 Fvco;
-
-	state->RF_IN = RF_Freq;
-
-	MXL_SynthRFTGLO_Calc(fe);
-
-	if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL)
-		Kdbl_RF = 2;
-	if (state->Fxtal > 22000000 && state->Fxtal <= 32000000)
-		Kdbl_RF = 1;
-
-	/* Downconverter Controls
-	 * Look-Up Table Implementation for:
-	 *	DN_POLY
-	 *	DN_RFGAIN
-	 *	DN_CAP_RFLPF
-	 *	DN_EN_VHFUHFBAR
-	 *	DN_GAIN_ADJUST
-	 *  Change the boundary reference from RF_IN to RF_LO
-	 */
-	if (state->RF_LO < 40000000UL)
-		return -1;
-
-	if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) {
-		status += MXL_ControlWrite(fe, DN_POLY,              2);
-		status += MXL_ControlWrite(fe, DN_RFGAIN,            3);
-		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         423);
-		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      1);
-		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       1);
-	}
-	if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) {
-		status += MXL_ControlWrite(fe, DN_POLY,              3);
-		status += MXL_ControlWrite(fe, DN_RFGAIN,            3);
-		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         222);
-		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      1);
-		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       1);
-	}
-	if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) {
-		status += MXL_ControlWrite(fe, DN_POLY,              3);
-		status += MXL_ControlWrite(fe, DN_RFGAIN,            3);
-		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         147);
-		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      1);
-		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       2);
-	}
-	if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) {
-		status += MXL_ControlWrite(fe, DN_POLY,              3);
-		status += MXL_ControlWrite(fe, DN_RFGAIN,            3);
-		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         9);
-		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      1);
-		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       2);
-	}
-	if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) {
-		status += MXL_ControlWrite(fe, DN_POLY,              3);
-		status += MXL_ControlWrite(fe, DN_RFGAIN,            3);
-		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         0);
-		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      1);
-		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       3);
-	}
-	if (state->RF_LO > 300000000UL && state->RF_LO <= 650000000UL) {
-		status += MXL_ControlWrite(fe, DN_POLY,              3);
-		status += MXL_ControlWrite(fe, DN_RFGAIN,            1);
-		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         0);
-		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      0);
-		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       3);
-	}
-	if (state->RF_LO > 650000000UL && state->RF_LO <= 900000000UL) {
-		status += MXL_ControlWrite(fe, DN_POLY,              3);
-		status += MXL_ControlWrite(fe, DN_RFGAIN,            2);
-		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         0);
-		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      0);
-		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       3);
-	}
-	if (state->RF_LO > 900000000UL)
-		return -1;
-
-	/*	DN_IQTNBUF_AMP */
-	/*	DN_IQTNGNBFBIAS_BST */
-	if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) {
-		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
-		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
-	}
-	if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) {
-		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
-		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
-	}
-	if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) {
-		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
-		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
-	}
-	if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) {
-		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
-		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
-	}
-	if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) {
-		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
-		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
-	}
-	if (state->RF_LO > 300000000UL && state->RF_LO <= 400000000UL) {
-		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
-		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
-	}
-	if (state->RF_LO > 400000000UL && state->RF_LO <= 450000000UL) {
-		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
-		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
-	}
-	if (state->RF_LO > 450000000UL && state->RF_LO <= 500000000UL) {
-		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
-		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
-	}
-	if (state->RF_LO > 500000000UL && state->RF_LO <= 550000000UL) {
-		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
-		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
-	}
-	if (state->RF_LO > 550000000UL && state->RF_LO <= 600000000UL) {
-		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
-		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
-	}
-	if (state->RF_LO > 600000000UL && state->RF_LO <= 650000000UL) {
-		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
-		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
-	}
-	if (state->RF_LO > 650000000UL && state->RF_LO <= 700000000UL) {
-		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
-		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
-	}
-	if (state->RF_LO > 700000000UL && state->RF_LO <= 750000000UL) {
-		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
-		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
-	}
-	if (state->RF_LO > 750000000UL && state->RF_LO <= 800000000UL) {
-		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
-		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
-	}
-	if (state->RF_LO > 800000000UL && state->RF_LO <= 850000000UL) {
-		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       10);
-		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  1);
-	}
-	if (state->RF_LO > 850000000UL && state->RF_LO <= 900000000UL) {
-		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       10);
-		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  1);
-	}
-
-	/*
-	 * Set RF Synth and LO Path Control
-	 *
-	 * Look-Up table implementation for:
-	 *	RFSYN_EN_OUTMUX
-	 *	RFSYN_SEL_VCO_OUT
-	 *	RFSYN_SEL_VCO_HI
-	 *  RFSYN_SEL_DIVM
-	 *	RFSYN_RF_DIV_BIAS
-	 *	DN_SEL_FREQ
-	 *
-	 * Set divider_val, Fmax, Fmix to use in Equations
-	 */
-	FminBin = 28000000UL ;
-	FmaxBin = 42500000UL ;
-	if (state->RF_LO >= 40000000UL && state->RF_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
-		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
-		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         1);
-		divider_val = 64 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-	FminBin = 42500000UL ;
-	FmaxBin = 56000000UL ;
-	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
-		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
-		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         1);
-		divider_val = 64 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-	FminBin = 56000000UL ;
-	FmaxBin = 85000000UL ;
-	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
-		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
-		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         1);
-		divider_val = 32 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-	FminBin = 85000000UL ;
-	FmaxBin = 112000000UL ;
-	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
-		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
-		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         1);
-		divider_val = 32 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-	FminBin = 112000000UL ;
-	FmaxBin = 170000000UL ;
-	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
-		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
-		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         2);
-		divider_val = 16 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-	FminBin = 170000000UL ;
-	FmaxBin = 225000000UL ;
-	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
-		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
-		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         2);
-		divider_val = 16 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-	FminBin = 225000000UL ;
-	FmaxBin = 300000000UL ;
-	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
-		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
-		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         4);
-		divider_val = 8 ;
-		Fmax = 340000000UL ;
-		Fmin = FminBin ;
-	}
-	FminBin = 300000000UL ;
-	FmaxBin = 340000000UL ;
-	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
-		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
-		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         0);
-		divider_val = 8 ;
-		Fmax = FmaxBin ;
-		Fmin = 225000000UL ;
-	}
-	FminBin = 340000000UL ;
-	FmaxBin = 450000000UL ;
-	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
-		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   2);
-		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         0);
-		divider_val = 8 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-	FminBin = 450000000UL ;
-	FmaxBin = 680000000UL ;
-	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      1);
-		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
-		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         0);
-		divider_val = 4 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-	FminBin = 680000000UL ;
-	FmaxBin = 900000000UL ;
-	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      1);
-		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
-		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         0);
-		divider_val = 4 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-
-	/*	CHCAL_INT_MOD_RF
-	 *	CHCAL_FRAC_MOD_RF
-	 *	RFSYN_LPF_R
-	 *	CHCAL_EN_INT_RF
-	 */
-	/* Equation E3 RFSYN_VCO_BIAS */
-	E3 = (((Fmax-state->RF_LO)/1000)*32)/((Fmax-Fmin)/1000) + 8 ;
-	status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, E3);
-
-	/* Equation E4 CHCAL_INT_MOD_RF */
-	E4 = (state->RF_LO*divider_val/1000)/(2*state->Fxtal*Kdbl_RF/1000);
-	MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, E4);
-
-	/* Equation E5 CHCAL_FRAC_MOD_RF CHCAL_EN_INT_RF */
-	E5 = ((2<<17)*(state->RF_LO/10000*divider_val -
-		(E4*(2*state->Fxtal*Kdbl_RF)/10000))) /
-		(2*state->Fxtal*Kdbl_RF/10000);
-
-	status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5);
-
-	/* Equation E5A RFSYN_LPF_R */
-	E5A = (((Fmax - state->RF_LO)/1000)*4/((Fmax-Fmin)/1000)) + 1 ;
-	status += MXL_ControlWrite(fe, RFSYN_LPF_R, E5A);
-
-	/* Euqation E5B CHCAL_EN_INIT_RF */
-	status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, ((E5 == 0) ? 1 : 0));
-	/*if (E5 == 0)
-	 *	status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, 1);
-	 *else
-	 *	status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5);
-	 */
-
-	/*
-	 * Set TG Synth
-	 *
-	 * Look-Up table implementation for:
-	 *	TG_LO_DIVVAL
-	 *	TG_LO_SELVAL
-	 *
-	 * Set divider_val, Fmax, Fmix to use in Equations
-	 */
-	if (state->TG_LO < 33000000UL)
-		return -1;
-
-	FminBin = 33000000UL ;
-	FmaxBin = 50000000UL ;
-	if (state->TG_LO >= FminBin && state->TG_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x6);
-		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x0);
-		divider_val = 36 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-	FminBin = 50000000UL ;
-	FmaxBin = 67000000UL ;
-	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x1);
-		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x0);
-		divider_val = 24 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-	FminBin = 67000000UL ;
-	FmaxBin = 100000000UL ;
-	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0xC);
-		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x2);
-		divider_val = 18 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-	FminBin = 100000000UL ;
-	FmaxBin = 150000000UL ;
-	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x8);
-		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x2);
-		divider_val = 12 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-	FminBin = 150000000UL ;
-	FmaxBin = 200000000UL ;
-	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x0);
-		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x2);
-		divider_val = 8 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-	FminBin = 200000000UL ;
-	FmaxBin = 300000000UL ;
-	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x8);
-		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x3);
-		divider_val = 6 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-	FminBin = 300000000UL ;
-	FmaxBin = 400000000UL ;
-	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x0);
-		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x3);
-		divider_val = 4 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-	FminBin = 400000000UL ;
-	FmaxBin = 600000000UL ;
-	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x8);
-		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x7);
-		divider_val = 3 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-	FminBin = 600000000UL ;
-	FmaxBin = 900000000UL ;
-	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
-		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x0);
-		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x7);
-		divider_val = 2 ;
-		Fmax = FmaxBin ;
-		Fmin = FminBin ;
-	}
-
-	/* TG_DIV_VAL */
-	tg_divval = (state->TG_LO*divider_val/100000) *
-		(MXL_Ceiling(state->Fxtal, 1000000) * 100) /
-		(state->Fxtal/1000);
-
-	status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval);
-
-	if (state->TG_LO > 600000000UL)
-		status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval + 1);
-
-	Fmax = 1800000000UL ;
-	Fmin = 1200000000UL ;
-
-	/* prevent overflow of 32 bit unsigned integer, use
-	 * following equation. Edit for v2.6.4
-	 */
-	/* Fref_TF = Fref_TG * 1000 */
-	Fref_TG = (state->Fxtal/1000) / MXL_Ceiling(state->Fxtal, 1000000);
-
-	/* Fvco = Fvco/10 */
-	Fvco = (state->TG_LO/10000) * divider_val * Fref_TG;
-
-	tg_lo = (((Fmax/10 - Fvco)/100)*32) / ((Fmax-Fmin)/1000)+8;
-
-	/* below equation is same as above but much harder to debug.
-	 *
-	 * static u32 MXL_GetXtalInt(u32 Xtal_Freq)
-	 * {
-	 *	if ((Xtal_Freq % 1000000) == 0)
-	 *		return (Xtal_Freq / 10000);
-	 *	else
-	 *		return (((Xtal_Freq / 1000000) + 1)*100);
-	 * }
-	 *
-	 * u32 Xtal_Int = MXL_GetXtalInt(state->Fxtal);
-	 * tg_lo = ( ((Fmax/10000 * Xtal_Int)/100) -
-	 * ((state->TG_LO/10000)*divider_val *
-	 * (state->Fxtal/10000)/100) )*32/((Fmax-Fmin)/10000 *
-	 * Xtal_Int/100) + 8;
-	 */
-
-	status += MXL_ControlWrite(fe, TG_VCO_BIAS , tg_lo);
-
-	/* add for 2.6.5 Special setting for QAM */
-	if (state->Mod_Type == MXL_QAM) {
-		if (state->config->qam_gain != 0)
-			status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN,
-						   state->config->qam_gain);
-		else if (state->RF_IN < 680000000)
-			status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
-		else
-			status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2);
-	}
-
-	/* Off Chip Tracking Filter Control */
-	if (state->TF_Type == MXL_TF_OFF) {
-		/* Tracking Filter Off State; turn off all the banks */
-		status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
-		status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-		status += MXL_SetGPIO(fe, 3, 1); /* Bank1 Off */
-		status += MXL_SetGPIO(fe, 1, 1); /* Bank2 Off */
-		status += MXL_SetGPIO(fe, 4, 1); /* Bank3 Off */
-	}
-
-	if (state->TF_Type == MXL_TF_C) /* Tracking Filter type C */ {
-		status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
-		status += MXL_ControlWrite(fe, DAC_DIN_A, 0);
-
-		if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
-			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
-			status += MXL_SetGPIO(fe, 3, 0);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-		}
-		if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
-			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-		}
-		if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
-			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 4, 0);
-		}
-		if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
-			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 4, 0);
-		}
-		if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
-			status += MXL_ControlWrite(fe, DAC_DIN_B, 29);
-			status += MXL_SetGPIO(fe, 3, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 4, 0);
-		}
-		if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
-			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 4, 0);
-		}
-		if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
-			status += MXL_ControlWrite(fe, DAC_DIN_B, 16);
-			status += MXL_SetGPIO(fe, 3, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-		}
-		if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
-			status += MXL_ControlWrite(fe, DAC_DIN_B, 7);
-			status += MXL_SetGPIO(fe, 3, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-		}
-		if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
-			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-		}
-	}
-
-	if (state->TF_Type == MXL_TF_C_H) {
-
-		/* Tracking Filter type C-H for Hauppauge only */
-		status += MXL_ControlWrite(fe, DAC_DIN_A, 0);
-
-		if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-		}
-		if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 3, 0);
-			status += MXL_SetGPIO(fe, 1, 1);
-		}
-		if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 3, 0);
-			status += MXL_SetGPIO(fe, 1, 0);
-		}
-		if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-		}
-		if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-		}
-		if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-		}
-		if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-		}
-		if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-		}
-		if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) {
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-		}
-	}
-
-	if (state->TF_Type == MXL_TF_D) { /* Tracking Filter type D */
-
-		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
-
-		if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 0);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 0);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-	}
-
-	if (state->TF_Type == MXL_TF_D_L) {
-
-		/* Tracking Filter type D-L for Lumanate ONLY change 2.6.3 */
-		status += MXL_ControlWrite(fe, DAC_DIN_A, 0);
-
-		/* if UHF and terrestrial => Turn off Tracking Filter */
-		if (state->RF_IN >= 471000000 &&
-			(state->RF_IN - 471000000)%6000000 != 0) {
-			/* Turn off all the banks */
-			status += MXL_SetGPIO(fe, 3, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
-			status += MXL_ControlWrite(fe, AGC_IF, 10);
-		} else {
-			/* if VHF or cable => Turn on Tracking Filter */
-			if (state->RF_IN >= 43000000 &&
-				state->RF_IN < 140000000) {
-
-				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
-				status += MXL_SetGPIO(fe, 4, 1);
-				status += MXL_SetGPIO(fe, 1, 1);
-				status += MXL_SetGPIO(fe, 3, 0);
-			}
-			if (state->RF_IN >= 140000000 &&
-				state->RF_IN < 240000000) {
-				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
-				status += MXL_SetGPIO(fe, 4, 1);
-				status += MXL_SetGPIO(fe, 1, 0);
-				status += MXL_SetGPIO(fe, 3, 0);
-			}
-			if (state->RF_IN >= 240000000 &&
-				state->RF_IN < 340000000) {
-				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
-				status += MXL_SetGPIO(fe, 4, 0);
-				status += MXL_SetGPIO(fe, 1, 1);
-				status += MXL_SetGPIO(fe, 3, 0);
-			}
-			if (state->RF_IN >= 340000000 &&
-				state->RF_IN < 430000000) {
-				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
-				status += MXL_SetGPIO(fe, 4, 0);
-				status += MXL_SetGPIO(fe, 1, 0);
-				status += MXL_SetGPIO(fe, 3, 1);
-			}
-			if (state->RF_IN >= 430000000 &&
-				state->RF_IN < 470000000) {
-				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
-				status += MXL_SetGPIO(fe, 4, 1);
-				status += MXL_SetGPIO(fe, 1, 0);
-				status += MXL_SetGPIO(fe, 3, 1);
-			}
-			if (state->RF_IN >= 470000000 &&
-				state->RF_IN < 570000000) {
-				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
-				status += MXL_SetGPIO(fe, 4, 0);
-				status += MXL_SetGPIO(fe, 1, 0);
-				status += MXL_SetGPIO(fe, 3, 1);
-			}
-			if (state->RF_IN >= 570000000 &&
-				state->RF_IN < 620000000) {
-				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
-				status += MXL_SetGPIO(fe, 4, 0);
-				status += MXL_SetGPIO(fe, 1, 1);
-				status += MXL_SetGPIO(fe, 3, 1);
-			}
-			if (state->RF_IN >= 620000000 &&
-				state->RF_IN < 760000000) {
-				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
-				status += MXL_SetGPIO(fe, 4, 0);
-				status += MXL_SetGPIO(fe, 1, 1);
-				status += MXL_SetGPIO(fe, 3, 1);
-			}
-			if (state->RF_IN >= 760000000 &&
-				state->RF_IN <= 900000000) {
-				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
-				status += MXL_SetGPIO(fe, 4, 1);
-				status += MXL_SetGPIO(fe, 1, 1);
-				status += MXL_SetGPIO(fe, 3, 1);
-			}
-		}
-	}
-
-	if (state->TF_Type == MXL_TF_E) /* Tracking Filter type E */ {
-
-		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
-
-		if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 0);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 0);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-	}
-
-	if (state->TF_Type == MXL_TF_F) {
-
-		/* Tracking Filter type F */
-		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
-
-		if (state->RF_IN >= 43000000 && state->RF_IN < 160000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 0);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 160000000 && state->RF_IN < 210000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 0);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 210000000 && state->RF_IN < 300000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 300000000 && state->RF_IN < 390000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 390000000 && state->RF_IN < 515000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 515000000 && state->RF_IN < 650000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 650000000 && state->RF_IN <= 900000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-	}
-
-	if (state->TF_Type == MXL_TF_E_2) {
-
-		/* Tracking Filter type E_2 */
-		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
-
-		if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 0);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 0);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-	}
-
-	if (state->TF_Type == MXL_TF_G) {
-
-		/* Tracking Filter type G add for v2.6.8 */
-		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
-
-		if (state->RF_IN >= 50000000 && state->RF_IN < 190000000) {
-
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 0);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 190000000 && state->RF_IN < 280000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 0);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 280000000 && state->RF_IN < 350000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 400000000 && state->RF_IN < 470000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 640000000 && state->RF_IN < 820000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 820000000 && state->RF_IN <= 900000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-	}
-
-	if (state->TF_Type == MXL_TF_E_NA) {
-
-		/* Tracking Filter type E-NA for Empia ONLY change for 2.6.8 */
-		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
-
-		/* if UHF and terrestrial=> Turn off Tracking Filter */
-		if (state->RF_IN >= 471000000 &&
-			(state->RF_IN - 471000000)%6000000 != 0) {
-
-			/* Turn off all the banks */
-			status += MXL_SetGPIO(fe, 3, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-
-			/* 2.6.12 Turn on RSSI */
-			status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
-			status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
-			status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
-			status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
-
-			/* RSSI reference point */
-			status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5);
-			status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3);
-			status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2);
-
-			/* following parameter is from analog OTA mode,
-			 * can be change to seek better performance */
-			status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
-		} else {
-		/* if VHF or Cable =>  Turn on Tracking Filter */
-
-		/* 2.6.12 Turn off RSSI */
-		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0);
-
-		/* change back from above condition */
-		status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5);
-
-
-		if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) {
-
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 0);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 0);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 0);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 0);
-		}
-		if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) {
-			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
-			status += MXL_SetGPIO(fe, 4, 1);
-			status += MXL_SetGPIO(fe, 1, 1);
-			status += MXL_SetGPIO(fe, 3, 1);
-		}
-		}
-	}
-	return status ;
-}
-
-static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val)
-{
-	u16 status = 0;
-
-	if (GPIO_Num == 1)
-		status += MXL_ControlWrite(fe, GPIO_1B, GPIO_Val ? 0 : 1);
-
-	/* GPIO2 is not available */
-
-	if (GPIO_Num == 3) {
-		if (GPIO_Val == 1) {
-			status += MXL_ControlWrite(fe, GPIO_3, 0);
-			status += MXL_ControlWrite(fe, GPIO_3B, 0);
-		}
-		if (GPIO_Val == 0) {
-			status += MXL_ControlWrite(fe, GPIO_3, 1);
-			status += MXL_ControlWrite(fe, GPIO_3B, 1);
-		}
-		if (GPIO_Val == 3) { /* tri-state */
-			status += MXL_ControlWrite(fe, GPIO_3, 0);
-			status += MXL_ControlWrite(fe, GPIO_3B, 1);
-		}
-	}
-	if (GPIO_Num == 4) {
-		if (GPIO_Val == 1) {
-			status += MXL_ControlWrite(fe, GPIO_4, 0);
-			status += MXL_ControlWrite(fe, GPIO_4B, 0);
-		}
-		if (GPIO_Val == 0) {
-			status += MXL_ControlWrite(fe, GPIO_4, 1);
-			status += MXL_ControlWrite(fe, GPIO_4B, 1);
-		}
-		if (GPIO_Val == 3) { /* tri-state */
-			status += MXL_ControlWrite(fe, GPIO_4, 0);
-			status += MXL_ControlWrite(fe, GPIO_4B, 1);
-		}
-	}
-
-	return status;
-}
-
-static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value)
-{
-	u16 status = 0;
-
-	/* Will write ALL Matching Control Name */
-	/* Write Matching INIT Control */
-	status += MXL_ControlWrite_Group(fe, ControlNum, value, 1);
-	/* Write Matching CH Control */
-	status += MXL_ControlWrite_Group(fe, ControlNum, value, 2);
-#ifdef _MXL_INTERNAL
-	/* Write Matching MXL Control */
-	status += MXL_ControlWrite_Group(fe, ControlNum, value, 3);
-#endif
-	return status;
-}
-
-static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum,
-	u32 value, u16 controlGroup)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	u16 i, j, k;
-	u32 highLimit;
-	u32 ctrlVal;
-
-	if (controlGroup == 1) /* Initial Control */ {
-
-		for (i = 0; i < state->Init_Ctrl_Num; i++) {
-
-			if (controlNum == state->Init_Ctrl[i].Ctrl_Num) {
-
-				highLimit = 1 << state->Init_Ctrl[i].size;
-				if (value < highLimit) {
-					for (j = 0; j < state->Init_Ctrl[i].size; j++) {
-						state->Init_Ctrl[i].val[j] = (u8)((value >> j) & 0x01);
-						MXL_RegWriteBit(fe, (u8)(state->Init_Ctrl[i].addr[j]),
-							(u8)(state->Init_Ctrl[i].bit[j]),
-							(u8)((value>>j) & 0x01));
-					}
-					ctrlVal = 0;
-					for (k = 0; k < state->Init_Ctrl[i].size; k++)
-						ctrlVal += state->Init_Ctrl[i].val[k] * (1 << k);
-				} else
-					return -1;
-			}
-		}
-	}
-	if (controlGroup == 2) /* Chan change Control */ {
-
-		for (i = 0; i < state->CH_Ctrl_Num; i++) {
-
-			if (controlNum == state->CH_Ctrl[i].Ctrl_Num) {
-
-				highLimit = 1 << state->CH_Ctrl[i].size;
-				if (value < highLimit) {
-					for (j = 0; j < state->CH_Ctrl[i].size; j++) {
-						state->CH_Ctrl[i].val[j] = (u8)((value >> j) & 0x01);
-						MXL_RegWriteBit(fe, (u8)(state->CH_Ctrl[i].addr[j]),
-							(u8)(state->CH_Ctrl[i].bit[j]),
-							(u8)((value>>j) & 0x01));
-					}
-					ctrlVal = 0;
-					for (k = 0; k < state->CH_Ctrl[i].size; k++)
-						ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k);
-				} else
-					return -1;
-			}
-		}
-	}
-#ifdef _MXL_INTERNAL
-	if (controlGroup == 3) /* Maxlinear Control */ {
-
-		for (i = 0; i < state->MXL_Ctrl_Num; i++) {
-
-			if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) {
-
-				highLimit = (1 << state->MXL_Ctrl[i].size);
-				if (value < highLimit) {
-					for (j = 0; j < state->MXL_Ctrl[i].size; j++) {
-						state->MXL_Ctrl[i].val[j] = (u8)((value >> j) & 0x01);
-						MXL_RegWriteBit(fe, (u8)(state->MXL_Ctrl[i].addr[j]),
-							(u8)(state->MXL_Ctrl[i].bit[j]),
-							(u8)((value>>j) & 0x01));
-					}
-					ctrlVal = 0;
-					for (k = 0; k < state->MXL_Ctrl[i].size; k++)
-						ctrlVal += state->
-							MXL_Ctrl[i].val[k] *
-							(1 << k);
-				} else
-					return -1;
-			}
-		}
-	}
-#endif
-	return 0 ; /* successful return */
-}
-
-static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	int i ;
-
-	for (i = 0; i < 104; i++) {
-		if (RegNum == state->TunerRegs[i].Reg_Num) {
-			*RegVal = (u8)(state->TunerRegs[i].Reg_Val);
-			return 0;
-		}
-	}
-
-	return 1;
-}
-
-static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	u32 ctrlVal ;
-	u16 i, k ;
-
-	for (i = 0; i < state->Init_Ctrl_Num ; i++) {
-
-		if (controlNum == state->Init_Ctrl[i].Ctrl_Num) {
-
-			ctrlVal = 0;
-			for (k = 0; k < state->Init_Ctrl[i].size; k++)
-				ctrlVal += state->Init_Ctrl[i].val[k] * (1<<k);
-			*value = ctrlVal;
-			return 0;
-		}
-	}
-
-	for (i = 0; i < state->CH_Ctrl_Num ; i++) {
-
-		if (controlNum == state->CH_Ctrl[i].Ctrl_Num) {
-
-			ctrlVal = 0;
-			for (k = 0; k < state->CH_Ctrl[i].size; k++)
-				ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k);
-			*value = ctrlVal;
-			return 0;
-
-		}
-	}
-
-#ifdef _MXL_INTERNAL
-	for (i = 0; i < state->MXL_Ctrl_Num ; i++) {
-
-		if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) {
-
-			ctrlVal = 0;
-			for (k = 0; k < state->MXL_Ctrl[i].size; k++)
-				ctrlVal += state->MXL_Ctrl[i].val[k] * (1<<k);
-			*value = ctrlVal;
-			return 0;
-
-		}
-	}
-#endif
-	return 1;
-}
-
-static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit,
-	u8 bitVal)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	int i ;
-
-	const u8 AND_MAP[8] = {
-		0xFE, 0xFD, 0xFB, 0xF7,
-		0xEF, 0xDF, 0xBF, 0x7F } ;
-
-	const u8 OR_MAP[8] = {
-		0x01, 0x02, 0x04, 0x08,
-		0x10, 0x20, 0x40, 0x80 } ;
-
-	for (i = 0; i < state->TunerRegs_Num; i++) {
-		if (state->TunerRegs[i].Reg_Num == address) {
-			if (bitVal)
-				state->TunerRegs[i].Reg_Val |= OR_MAP[bit];
-			else
-				state->TunerRegs[i].Reg_Val &= AND_MAP[bit];
-			break ;
-		}
-	}
-}
-
-static u32 MXL_Ceiling(u32 value, u32 resolution)
-{
-	return value / resolution + (value % resolution > 0 ? 1 : 0);
-}
-
-/* Retrieve the Initialzation Registers */
-static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum,
-	u8 *RegVal, int *count)
-{
-	u16 status = 0;
-	int i ;
-
-	u8 RegAddr[] = {
-		11, 12, 13, 22, 32, 43, 44, 53, 56, 59, 73,
-		76, 77, 91, 134, 135, 137, 147,
-		156, 166, 167, 168, 25 };
-
-	*count = ARRAY_SIZE(RegAddr);
-
-	status += MXL_BlockInit(fe);
-
-	for (i = 0 ; i < *count; i++) {
-		RegNum[i] = RegAddr[i];
-		status += MXL_RegRead(fe, RegNum[i], &RegVal[i]);
-	}
-
-	return status;
-}
-
-static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal,
-	int *count)
-{
-	u16 status = 0;
-	int i ;
-
-/* add 77, 166, 167, 168 register for 2.6.12 */
-#ifdef _MXL_PRODUCTION
-	u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 65, 68, 69, 70, 73, 92, 93, 106,
-	   107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ;
-#else
-	u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 68, 69, 70, 73, 92, 93, 106,
-	   107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ;
-	/*
-	u8 RegAddr[171];
-	for (i = 0; i <= 170; i++)
-		RegAddr[i] = i;
-	*/
-#endif
-
-	*count = ARRAY_SIZE(RegAddr);
-
-	for (i = 0 ; i < *count; i++) {
-		RegNum[i] = RegAddr[i];
-		status += MXL_RegRead(fe, RegNum[i], &RegVal[i]);
-	}
-
-	return status;
-}
-
-static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum,
-	u8 *RegVal, int *count)
-{
-	u16 status = 0;
-	int i;
-
-	u8 RegAddr[] = {43, 136};
-
-	*count = ARRAY_SIZE(RegAddr);
-
-	for (i = 0; i < *count; i++) {
-		RegNum[i] = RegAddr[i];
-		status += MXL_RegRead(fe, RegNum[i], &RegVal[i]);
-	}
-
-	return status;
-}
-
-static u16 MXL_GetMasterControl(u8 *MasterReg, int state)
-{
-	if (state == 1) /* Load_Start */
-		*MasterReg = 0xF3;
-	if (state == 2) /* Power_Down */
-		*MasterReg = 0x41;
-	if (state == 3) /* Synth_Reset */
-		*MasterReg = 0xB1;
-	if (state == 4) /* Seq_Off */
-		*MasterReg = 0xF1;
-
-	return 0;
-}
-
-#ifdef _MXL_PRODUCTION
-static u16 MXL_VCORange_Test(struct dvb_frontend *fe, int VCO_Range)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	u16 status = 0 ;
-
-	if (VCO_Range == 1) {
-		status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1);
-		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
-		status += MXL_ControlWrite(fe, RFSYN_DIVM, 1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
-		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
-		status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
-		if (state->Mode == 0 && state->IF_Mode == 1) {
-			/* Analog Low IF Mode */
-			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
-			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
-			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56);
-			status += MXL_ControlWrite(fe,
-				CHCAL_FRAC_MOD_RF, 180224);
-		}
-		if (state->Mode == 0 && state->IF_Mode == 0) {
-			/* Analog Zero IF Mode */
-			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
-			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
-			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56);
-			status += MXL_ControlWrite(fe,
-				CHCAL_FRAC_MOD_RF, 222822);
-		}
-		if (state->Mode == 1) /* Digital Mode */ {
-			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
-			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
-			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56);
-			status += MXL_ControlWrite(fe,
-				CHCAL_FRAC_MOD_RF, 229376);
-		}
-	}
-
-	if (VCO_Range == 2) {
-		status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1);
-		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
-		status += MXL_ControlWrite(fe, RFSYN_DIVM, 1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
-		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
-		status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
-		status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
-		status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41);
-		if (state->Mode == 0 && state->IF_Mode == 1) {
-			/* Analog Low IF Mode */
-			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
-			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
-			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42);
-			status += MXL_ControlWrite(fe,
-				CHCAL_FRAC_MOD_RF, 206438);
-		}
-		if (state->Mode == 0 && state->IF_Mode == 0) {
-			/* Analog Zero IF Mode */
-			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
-			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
-			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42);
-			status += MXL_ControlWrite(fe,
-				CHCAL_FRAC_MOD_RF, 206438);
-		}
-		if (state->Mode == 1) /* Digital Mode */ {
-			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
-			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
-			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41);
-			status += MXL_ControlWrite(fe,
-				CHCAL_FRAC_MOD_RF, 16384);
-		}
-	}
-
-	if (VCO_Range == 3) {
-		status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1);
-		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
-		status += MXL_ControlWrite(fe, RFSYN_DIVM, 1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
-		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
-		status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
-		status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
-		status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42);
-		if (state->Mode == 0 && state->IF_Mode == 1) {
-			/* Analog Low IF Mode */
-			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
-			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
-			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44);
-			status += MXL_ControlWrite(fe,
-				CHCAL_FRAC_MOD_RF, 173670);
-		}
-		if (state->Mode == 0 && state->IF_Mode == 0) {
-			/* Analog Zero IF Mode */
-			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
-			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
-			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44);
-			status += MXL_ControlWrite(fe,
-				CHCAL_FRAC_MOD_RF, 173670);
-		}
-		if (state->Mode == 1) /* Digital Mode */ {
-			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
-			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
-			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42);
-			status += MXL_ControlWrite(fe,
-				CHCAL_FRAC_MOD_RF, 245760);
-		}
-	}
-
-	if (VCO_Range == 4) {
-		status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1);
-		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
-		status += MXL_ControlWrite(fe, RFSYN_DIVM, 1);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
-		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
-		status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
-		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
-		status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
-		status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27);
-		if (state->Mode == 0 && state->IF_Mode == 1) {
-			/* Analog Low IF Mode */
-			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
-			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
-			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27);
-			status += MXL_ControlWrite(fe,
-				CHCAL_FRAC_MOD_RF, 206438);
-		}
-		if (state->Mode == 0 && state->IF_Mode == 0) {
-			/* Analog Zero IF Mode */
-			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
-			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
-			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27);
-			status += MXL_ControlWrite(fe,
-				CHCAL_FRAC_MOD_RF, 206438);
-		}
-		if (state->Mode == 1) /* Digital Mode */ {
-			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
-			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
-			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27);
-			status += MXL_ControlWrite(fe,
-				CHCAL_FRAC_MOD_RF, 212992);
-		}
-	}
-
-	return status;
-}
-
-static u16 MXL_Hystersis_Test(struct dvb_frontend *fe, int Hystersis)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	u16 status = 0;
-
-	if (Hystersis == 1)
-		status += MXL_ControlWrite(fe, DN_BYPASS_AGC_I2C, 1);
-
-	return status;
-}
-#endif
-/* End: Reference driver code found in the Realtek driver that
- * is copyright MaxLinear */
-
-/* ----------------------------------------------------------------
- * Begin: Everything after here is new code to adapt the
- * proprietary Realtek driver into a Linux API tuner.
- * Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
- */
-static int mxl5005s_reset(struct dvb_frontend *fe)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	int ret = 0;
-
-	u8 buf[2] = { 0xff, 0x00 };
-	struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0,
-			       .buf = buf, .len = 2 };
-
-	dprintk(2, "%s()\n", __func__);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
-		printk(KERN_WARNING "mxl5005s I2C reset failed\n");
-		ret = -EREMOTEIO;
-	}
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	return ret;
-}
-
-/* Write a single byte to a single reg, latch the value if required by
- * following the transaction with the latch byte.
- */
-static int mxl5005s_writereg(struct dvb_frontend *fe, u8 reg, u8 val, int latch)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	u8 buf[3] = { reg, val, MXL5005S_LATCH_BYTE };
-	struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0,
-			       .buf = buf, .len = 3 };
-
-	if (latch == 0)
-		msg.len = 2;
-
-	dprintk(2, "%s(0x%x, 0x%x, 0x%x)\n", __func__, reg, val, msg.addr);
-
-	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
-		printk(KERN_WARNING "mxl5005s I2C write failed\n");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable,
-	u8 *datatable, u8 len)
-{
-	int ret = 0, i;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	for (i = 0 ; i < len-1; i++) {
-		ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 0);
-		if (ret < 0)
-			break;
-	}
-
-	ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 1);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	return ret;
-}
-
-static int mxl5005s_init(struct dvb_frontend *fe)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-
-	dprintk(1, "%s()\n", __func__);
-	state->current_mode = MXL_QAM;
-	return mxl5005s_reconfigure(fe, MXL_QAM, MXL5005S_BANDWIDTH_6MHZ);
-}
-
-static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type,
-	u32 bandwidth)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-
-	u8 AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
-	u8 ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
-	int TableLen;
-
-	dprintk(1, "%s(type=%d, bw=%d)\n", __func__, mod_type, bandwidth);
-
-	mxl5005s_reset(fe);
-
-	/* Tuner initialization stage 0 */
-	MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET);
-	AddrTable[0] = MASTER_CONTROL_ADDR;
-	ByteTable[0] |= state->config->AgcMasterByte;
-
-	mxl5005s_writeregs(fe, AddrTable, ByteTable, 1);
-
-	mxl5005s_AssignTunerMode(fe, mod_type, bandwidth);
-
-	/* Tuner initialization stage 1 */
-	MXL_GetInitRegister(fe, AddrTable, ByteTable, &TableLen);
-
-	mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen);
-
-	return 0;
-}
-
-static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type,
-	u32 bandwidth)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	struct mxl5005s_config *c = state->config;
-
-	InitTunerControls(fe);
-
-	/* Set MxL5005S parameters. */
-	MXL5005_TunerConfig(
-		fe,
-		c->mod_mode,
-		c->if_mode,
-		bandwidth,
-		c->if_freq,
-		c->xtal_freq,
-		c->agc_mode,
-		c->top,
-		c->output_load,
-		c->clock_out,
-		c->div_out,
-		c->cap_select,
-		c->rssi_enable,
-		mod_type,
-		c->tracking_filter);
-
-	return 0;
-}
-
-static int mxl5005s_set_params(struct dvb_frontend *fe)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 delsys = c->delivery_system;
-	u32 bw = c->bandwidth_hz;
-	u32 req_mode, req_bw = 0;
-	int ret;
-
-	dprintk(1, "%s()\n", __func__);
-
-	switch (delsys) {
-	case SYS_ATSC:
-		req_mode = MXL_ATSC;
-		req_bw  = MXL5005S_BANDWIDTH_6MHZ;
-		break;
-	case SYS_DVBC_ANNEX_B:
-		req_mode = MXL_QAM;
-		req_bw  = MXL5005S_BANDWIDTH_6MHZ;
-		break;
-	default:	/* Assume DVB-T */
-		req_mode = MXL_DVBT;
-		switch (bw) {
-		case 6000000:
-			req_bw = MXL5005S_BANDWIDTH_6MHZ;
-			break;
-		case 7000000:
-			req_bw = MXL5005S_BANDWIDTH_7MHZ;
-			break;
-		case 8000000:
-		case 0:
-			req_bw = MXL5005S_BANDWIDTH_8MHZ;
-			break;
-		default:
-			return -EINVAL;
-		}
-	}
-
-	/* Change tuner for new modulation type if reqd */
-	if (req_mode != state->current_mode ||
-	    req_bw != state->Chan_Bandwidth) {
-		state->current_mode = req_mode;
-		ret = mxl5005s_reconfigure(fe, req_mode, req_bw);
-
-	} else
-		ret = 0;
-
-	if (ret == 0) {
-		dprintk(1, "%s() freq=%d\n", __func__, c->frequency);
-		ret = mxl5005s_SetRfFreqHz(fe, c->frequency);
-	}
-
-	return ret;
-}
-
-static int mxl5005s_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	dprintk(1, "%s()\n", __func__);
-
-	*frequency = state->RF_IN;
-
-	return 0;
-}
-
-static int mxl5005s_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	struct mxl5005s_state *state = fe->tuner_priv;
-	dprintk(1, "%s()\n", __func__);
-
-	*bandwidth = state->Chan_Bandwidth;
-
-	return 0;
-}
-
-static int mxl5005s_release(struct dvb_frontend *fe)
-{
-	dprintk(1, "%s()\n", __func__);
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static const struct dvb_tuner_ops mxl5005s_tuner_ops = {
-	.info = {
-		.name           = "MaxLinear MXL5005S",
-		.frequency_min  =  48000000,
-		.frequency_max  = 860000000,
-		.frequency_step =     50000,
-	},
-
-	.release       = mxl5005s_release,
-	.init          = mxl5005s_init,
-
-	.set_params    = mxl5005s_set_params,
-	.get_frequency = mxl5005s_get_frequency,
-	.get_bandwidth = mxl5005s_get_bandwidth,
-};
-
-struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
-				     struct i2c_adapter *i2c,
-				     struct mxl5005s_config *config)
-{
-	struct mxl5005s_state *state = NULL;
-	dprintk(1, "%s()\n", __func__);
-
-	state = kzalloc(sizeof(struct mxl5005s_state), GFP_KERNEL);
-	if (state == NULL)
-		return NULL;
-
-	state->frontend = fe;
-	state->config = config;
-	state->i2c = i2c;
-
-	printk(KERN_INFO "MXL5005S: Attached at address 0x%02x\n",
-		config->i2c_address);
-
-	memcpy(&fe->ops.tuner_ops, &mxl5005s_tuner_ops,
-		sizeof(struct dvb_tuner_ops));
-
-	fe->tuner_priv = state;
-	return fe;
-}
-EXPORT_SYMBOL(mxl5005s_attach);
-
-MODULE_DESCRIPTION("MaxLinear MXL5005S silicon tuner driver");
-MODULE_AUTHOR("Steven Toth");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/mxl5005s.h b/drivers/media/common/tuners/mxl5005s.h
deleted file mode 100644
index fc8a1ff..0000000
--- a/drivers/media/common/tuners/mxl5005s.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
-    MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
-
-    Copyright (C) 2008 MaxLinear
-    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef __MXL5005S_H
-#define __MXL5005S_H
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-struct mxl5005s_config {
-
-	/* 7 bit i2c address */
-	u8 i2c_address;
-
-#define IF_FREQ_4570000HZ    4570000
-#define IF_FREQ_4571429HZ    4571429
-#define IF_FREQ_5380000HZ    5380000
-#define IF_FREQ_36000000HZ  36000000
-#define IF_FREQ_36125000HZ  36125000
-#define IF_FREQ_36166667HZ  36166667
-#define IF_FREQ_44000000HZ  44000000
-	u32 if_freq;
-
-#define CRYSTAL_FREQ_4000000HZ    4000000
-#define CRYSTAL_FREQ_16000000HZ  16000000
-#define CRYSTAL_FREQ_25000000HZ  25000000
-#define CRYSTAL_FREQ_28800000HZ  28800000
-	u32 xtal_freq;
-
-#define MXL_DUAL_AGC   0
-#define MXL_SINGLE_AGC 1
-	u8 agc_mode;
-
-#define MXL_TF_DEFAULT	0
-#define MXL_TF_OFF	1
-#define MXL_TF_C	2
-#define MXL_TF_C_H	3
-#define MXL_TF_D	4
-#define MXL_TF_D_L	5
-#define MXL_TF_E	6
-#define MXL_TF_F	7
-#define MXL_TF_E_2	8
-#define MXL_TF_E_NA	9
-#define MXL_TF_G	10
-	u8 tracking_filter;
-
-#define MXL_RSSI_DISABLE	0
-#define MXL_RSSI_ENABLE		1
-	u8 rssi_enable;
-
-#define MXL_CAP_SEL_DISABLE	0
-#define MXL_CAP_SEL_ENABLE	1
-	u8 cap_select;
-
-#define MXL_DIV_OUT_1	0
-#define MXL_DIV_OUT_4	1
-	u8 div_out;
-
-#define MXL_CLOCK_OUT_DISABLE	0
-#define MXL_CLOCK_OUT_ENABLE	1
-	u8 clock_out;
-
-#define MXL5005S_IF_OUTPUT_LOAD_200_OHM 200
-#define MXL5005S_IF_OUTPUT_LOAD_300_OHM 300
-	u32 output_load;
-
-#define MXL5005S_TOP_5P5   55
-#define MXL5005S_TOP_7P2   72
-#define MXL5005S_TOP_9P2   92
-#define MXL5005S_TOP_11P0 110
-#define MXL5005S_TOP_12P9 129
-#define MXL5005S_TOP_14P7 147
-#define MXL5005S_TOP_16P8 168
-#define MXL5005S_TOP_19P4 194
-#define MXL5005S_TOP_21P2 212
-#define MXL5005S_TOP_23P2 232
-#define MXL5005S_TOP_25P2 252
-#define MXL5005S_TOP_27P1 271
-#define MXL5005S_TOP_29P2 292
-#define MXL5005S_TOP_31P7 317
-#define MXL5005S_TOP_34P9 349
-	u32 top;
-
-#define MXL_ANALOG_MODE  0
-#define MXL_DIGITAL_MODE 1
-	u8 mod_mode;
-
-#define MXL_ZERO_IF 0
-#define MXL_LOW_IF  1
-	u8 if_mode;
-
-	/* Some boards need to override the built-in logic for determining
-	   the gain when in QAM mode (the HVR-1600 is one such case) */
-	u8 qam_gain;
-
-	/* Stuff I don't know what to do with */
-	u8 AgcMasterByte;
-};
-
-#if defined(CONFIG_MEDIA_TUNER_MXL5005S) || \
-	(defined(CONFIG_MEDIA_TUNER_MXL5005S_MODULE) && defined(MODULE))
-extern struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
-					    struct i2c_adapter *i2c,
-					    struct mxl5005s_config *config);
-#else
-static inline struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
-					    struct i2c_adapter *i2c,
-					    struct mxl5005s_config *config)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_TUNER_MXL5005S */
-
-#endif /* __MXL5005S_H */
-
diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/common/tuners/mxl5007t.c
deleted file mode 100644
index 69e453e..0000000
--- a/drivers/media/common/tuners/mxl5007t.c
+++ /dev/null
@@ -1,928 +0,0 @@
-/*
- *  mxl5007t.c - driver for the MaxLinear MxL5007T silicon tuner
- *
- *  Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/i2c.h>
-#include <linux/types.h>
-#include <linux/videodev2.h>
-#include "tuner-i2c.h"
-#include "mxl5007t.h"
-
-static DEFINE_MUTEX(mxl5007t_list_mutex);
-static LIST_HEAD(hybrid_tuner_instance_list);
-
-static int mxl5007t_debug;
-module_param_named(debug, mxl5007t_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debug level");
-
-/* ------------------------------------------------------------------------- */
-
-#define mxl_printk(kern, fmt, arg...) \
-	printk(kern "%s: " fmt "\n", __func__, ##arg)
-
-#define mxl_err(fmt, arg...) \
-	mxl_printk(KERN_ERR, "%d: " fmt, __LINE__, ##arg)
-
-#define mxl_warn(fmt, arg...) \
-	mxl_printk(KERN_WARNING, fmt, ##arg)
-
-#define mxl_info(fmt, arg...) \
-	mxl_printk(KERN_INFO, fmt, ##arg)
-
-#define mxl_debug(fmt, arg...)				\
-({							\
-	if (mxl5007t_debug)				\
-		mxl_printk(KERN_DEBUG, fmt, ##arg);	\
-})
-
-#define mxl_fail(ret)							\
-({									\
-	int __ret;							\
-	__ret = (ret < 0);						\
-	if (__ret)							\
-		mxl_printk(KERN_ERR, "error %d on line %d",		\
-			   ret, __LINE__);				\
-	__ret;								\
-})
-
-/* ------------------------------------------------------------------------- */
-
-#define MHz 1000000
-
-enum mxl5007t_mode {
-	MxL_MODE_ISDBT     =    0,
-	MxL_MODE_DVBT      =    1,
-	MxL_MODE_ATSC      =    2,
-	MxL_MODE_CABLE     = 0x10,
-};
-
-enum mxl5007t_chip_version {
-	MxL_UNKNOWN_ID     = 0x00,
-	MxL_5007_V1_F1     = 0x11,
-	MxL_5007_V1_F2     = 0x12,
-	MxL_5007_V4        = 0x14,
-	MxL_5007_V2_100_F1 = 0x21,
-	MxL_5007_V2_100_F2 = 0x22,
-	MxL_5007_V2_200_F1 = 0x23,
-	MxL_5007_V2_200_F2 = 0x24,
-};
-
-struct reg_pair_t {
-	u8 reg;
-	u8 val;
-};
-
-/* ------------------------------------------------------------------------- */
-
-static struct reg_pair_t init_tab[] = {
-	{ 0x02, 0x06 },
-	{ 0x03, 0x48 },
-	{ 0x05, 0x04 },
-	{ 0x06, 0x10 },
-	{ 0x2e, 0x15 }, /* OVERRIDE */
-	{ 0x30, 0x10 }, /* OVERRIDE */
-	{ 0x45, 0x58 }, /* OVERRIDE */
-	{ 0x48, 0x19 }, /* OVERRIDE */
-	{ 0x52, 0x03 }, /* OVERRIDE */
-	{ 0x53, 0x44 }, /* OVERRIDE */
-	{ 0x6a, 0x4b }, /* OVERRIDE */
-	{ 0x76, 0x00 }, /* OVERRIDE */
-	{ 0x78, 0x18 }, /* OVERRIDE */
-	{ 0x7a, 0x17 }, /* OVERRIDE */
-	{ 0x85, 0x06 }, /* OVERRIDE */
-	{ 0x01, 0x01 }, /* TOP_MASTER_ENABLE */
-	{ 0, 0 }
-};
-
-static struct reg_pair_t init_tab_cable[] = {
-	{ 0x02, 0x06 },
-	{ 0x03, 0x48 },
-	{ 0x05, 0x04 },
-	{ 0x06, 0x10 },
-	{ 0x09, 0x3f },
-	{ 0x0a, 0x3f },
-	{ 0x0b, 0x3f },
-	{ 0x2e, 0x15 }, /* OVERRIDE */
-	{ 0x30, 0x10 }, /* OVERRIDE */
-	{ 0x45, 0x58 }, /* OVERRIDE */
-	{ 0x48, 0x19 }, /* OVERRIDE */
-	{ 0x52, 0x03 }, /* OVERRIDE */
-	{ 0x53, 0x44 }, /* OVERRIDE */
-	{ 0x6a, 0x4b }, /* OVERRIDE */
-	{ 0x76, 0x00 }, /* OVERRIDE */
-	{ 0x78, 0x18 }, /* OVERRIDE */
-	{ 0x7a, 0x17 }, /* OVERRIDE */
-	{ 0x85, 0x06 }, /* OVERRIDE */
-	{ 0x01, 0x01 }, /* TOP_MASTER_ENABLE */
-	{ 0, 0 }
-};
-
-/* ------------------------------------------------------------------------- */
-
-static struct reg_pair_t reg_pair_rftune[] = {
-	{ 0x0f, 0x00 }, /* abort tune */
-	{ 0x0c, 0x15 },
-	{ 0x0d, 0x40 },
-	{ 0x0e, 0x0e },
-	{ 0x1f, 0x87 }, /* OVERRIDE */
-	{ 0x20, 0x1f }, /* OVERRIDE */
-	{ 0x21, 0x87 }, /* OVERRIDE */
-	{ 0x22, 0x1f }, /* OVERRIDE */
-	{ 0x80, 0x01 }, /* freq dependent */
-	{ 0x0f, 0x01 }, /* start tune */
-	{ 0, 0 }
-};
-
-/* ------------------------------------------------------------------------- */
-
-struct mxl5007t_state {
-	struct list_head hybrid_tuner_instance_list;
-	struct tuner_i2c_props i2c_props;
-
-	struct mutex lock;
-
-	struct mxl5007t_config *config;
-
-	enum mxl5007t_chip_version chip_id;
-
-	struct reg_pair_t tab_init[ARRAY_SIZE(init_tab)];
-	struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)];
-	struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)];
-
-	enum mxl5007t_if_freq if_freq;
-
-	u32 frequency;
-	u32 bandwidth;
-};
-
-/* ------------------------------------------------------------------------- */
-
-/* called by _init and _rftun to manipulate the register arrays */
-
-static void set_reg_bits(struct reg_pair_t *reg_pair, u8 reg, u8 mask, u8 val)
-{
-	unsigned int i = 0;
-
-	while (reg_pair[i].reg || reg_pair[i].val) {
-		if (reg_pair[i].reg == reg) {
-			reg_pair[i].val &= ~mask;
-			reg_pair[i].val |= val;
-		}
-		i++;
-
-	}
-	return;
-}
-
-static void copy_reg_bits(struct reg_pair_t *reg_pair1,
-			  struct reg_pair_t *reg_pair2)
-{
-	unsigned int i, j;
-
-	i = j = 0;
-
-	while (reg_pair1[i].reg || reg_pair1[i].val) {
-		while (reg_pair2[j].reg || reg_pair2[j].val) {
-			if (reg_pair1[i].reg != reg_pair2[j].reg) {
-				j++;
-				continue;
-			}
-			reg_pair2[j].val = reg_pair1[i].val;
-			break;
-		}
-		i++;
-	}
-	return;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void mxl5007t_set_mode_bits(struct mxl5007t_state *state,
-				   enum mxl5007t_mode mode,
-				   s32 if_diff_out_level)
-{
-	switch (mode) {
-	case MxL_MODE_ATSC:
-		set_reg_bits(state->tab_init, 0x06, 0x1f, 0x12);
-		break;
-	case MxL_MODE_DVBT:
-		set_reg_bits(state->tab_init, 0x06, 0x1f, 0x11);
-		break;
-	case MxL_MODE_ISDBT:
-		set_reg_bits(state->tab_init, 0x06, 0x1f, 0x10);
-		break;
-	case MxL_MODE_CABLE:
-		set_reg_bits(state->tab_init_cable, 0x09, 0xff, 0xc1);
-		set_reg_bits(state->tab_init_cable, 0x0a, 0xff,
-			     8 - if_diff_out_level);
-		set_reg_bits(state->tab_init_cable, 0x0b, 0xff, 0x17);
-		break;
-	default:
-		mxl_fail(-EINVAL);
-	}
-	return;
-}
-
-static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state,
-				      enum mxl5007t_if_freq if_freq,
-				      int invert_if)
-{
-	u8 val;
-
-	switch (if_freq) {
-	case MxL_IF_4_MHZ:
-		val = 0x00;
-		break;
-	case MxL_IF_4_5_MHZ:
-		val = 0x02;
-		break;
-	case MxL_IF_4_57_MHZ:
-		val = 0x03;
-		break;
-	case MxL_IF_5_MHZ:
-		val = 0x04;
-		break;
-	case MxL_IF_5_38_MHZ:
-		val = 0x05;
-		break;
-	case MxL_IF_6_MHZ:
-		val = 0x06;
-		break;
-	case MxL_IF_6_28_MHZ:
-		val = 0x07;
-		break;
-	case MxL_IF_9_1915_MHZ:
-		val = 0x08;
-		break;
-	case MxL_IF_35_25_MHZ:
-		val = 0x09;
-		break;
-	case MxL_IF_36_15_MHZ:
-		val = 0x0a;
-		break;
-	case MxL_IF_44_MHZ:
-		val = 0x0b;
-		break;
-	default:
-		mxl_fail(-EINVAL);
-		return;
-	}
-	set_reg_bits(state->tab_init, 0x02, 0x0f, val);
-
-	/* set inverted IF or normal IF */
-	set_reg_bits(state->tab_init, 0x02, 0x10, invert_if ? 0x10 : 0x00);
-
-	state->if_freq = if_freq;
-
-	return;
-}
-
-static void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state,
-					enum mxl5007t_xtal_freq xtal_freq)
-{
-	switch (xtal_freq) {
-	case MxL_XTAL_16_MHZ:
-		/* select xtal freq & ref freq */
-		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x00);
-		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x00);
-		break;
-	case MxL_XTAL_20_MHZ:
-		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x10);
-		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x01);
-		break;
-	case MxL_XTAL_20_25_MHZ:
-		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x20);
-		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x02);
-		break;
-	case MxL_XTAL_20_48_MHZ:
-		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x30);
-		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x03);
-		break;
-	case MxL_XTAL_24_MHZ:
-		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x40);
-		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x04);
-		break;
-	case MxL_XTAL_25_MHZ:
-		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x50);
-		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x05);
-		break;
-	case MxL_XTAL_25_14_MHZ:
-		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x60);
-		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x06);
-		break;
-	case MxL_XTAL_27_MHZ:
-		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x70);
-		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x07);
-		break;
-	case MxL_XTAL_28_8_MHZ:
-		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x80);
-		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x08);
-		break;
-	case MxL_XTAL_32_MHZ:
-		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x90);
-		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x09);
-		break;
-	case MxL_XTAL_40_MHZ:
-		set_reg_bits(state->tab_init, 0x03, 0xf0, 0xa0);
-		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0a);
-		break;
-	case MxL_XTAL_44_MHZ:
-		set_reg_bits(state->tab_init, 0x03, 0xf0, 0xb0);
-		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0b);
-		break;
-	case MxL_XTAL_48_MHZ:
-		set_reg_bits(state->tab_init, 0x03, 0xf0, 0xc0);
-		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0c);
-		break;
-	case MxL_XTAL_49_3811_MHZ:
-		set_reg_bits(state->tab_init, 0x03, 0xf0, 0xd0);
-		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0d);
-		break;
-	default:
-		mxl_fail(-EINVAL);
-		return;
-	}
-
-	return;
-}
-
-static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state,
-						  enum mxl5007t_mode mode)
-{
-	struct mxl5007t_config *cfg = state->config;
-
-	memcpy(&state->tab_init, &init_tab, sizeof(init_tab));
-	memcpy(&state->tab_init_cable, &init_tab_cable, sizeof(init_tab_cable));
-
-	mxl5007t_set_mode_bits(state, mode, cfg->if_diff_out_level);
-	mxl5007t_set_if_freq_bits(state, cfg->if_freq_hz, cfg->invert_if);
-	mxl5007t_set_xtal_freq_bits(state, cfg->xtal_freq_hz);
-
-	set_reg_bits(state->tab_init, 0x04, 0x01, cfg->loop_thru_enable);
-	set_reg_bits(state->tab_init, 0x03, 0x08, cfg->clk_out_enable << 3);
-	set_reg_bits(state->tab_init, 0x03, 0x07, cfg->clk_out_amp);
-
-	if (mode >= MxL_MODE_CABLE) {
-		copy_reg_bits(state->tab_init, state->tab_init_cable);
-		return state->tab_init_cable;
-	} else
-		return state->tab_init;
-}
-
-/* ------------------------------------------------------------------------- */
-
-enum mxl5007t_bw_mhz {
-	MxL_BW_6MHz = 6,
-	MxL_BW_7MHz = 7,
-	MxL_BW_8MHz = 8,
-};
-
-static void mxl5007t_set_bw_bits(struct mxl5007t_state *state,
-				 enum mxl5007t_bw_mhz bw)
-{
-	u8 val;
-
-	switch (bw) {
-	case MxL_BW_6MHz:
-		val = 0x15; /* set DIG_MODEINDEX, DIG_MODEINDEX_A,
-			     * and DIG_MODEINDEX_CSF */
-		break;
-	case MxL_BW_7MHz:
-		val = 0x2a;
-		break;
-	case MxL_BW_8MHz:
-		val = 0x3f;
-		break;
-	default:
-		mxl_fail(-EINVAL);
-		return;
-	}
-	set_reg_bits(state->tab_rftune, 0x0c, 0x3f, val);
-
-	return;
-}
-
-static struct
-reg_pair_t *mxl5007t_calc_rf_tune_regs(struct mxl5007t_state *state,
-				       u32 rf_freq, enum mxl5007t_bw_mhz bw)
-{
-	u32 dig_rf_freq = 0;
-	u32 temp;
-	u32 frac_divider = 1000000;
-	unsigned int i;
-
-	memcpy(&state->tab_rftune, &reg_pair_rftune, sizeof(reg_pair_rftune));
-
-	mxl5007t_set_bw_bits(state, bw);
-
-	/* Convert RF frequency into 16 bits =>
-	 * 10 bit integer (MHz) + 6 bit fraction */
-	dig_rf_freq = rf_freq / MHz;
-
-	temp = rf_freq % MHz;
-
-	for (i = 0; i < 6; i++) {
-		dig_rf_freq <<= 1;
-		frac_divider /= 2;
-		if (temp > frac_divider) {
-			temp -= frac_divider;
-			dig_rf_freq++;
-		}
-	}
-
-	/* add to have shift center point by 7.8124 kHz */
-	if (temp > 7812)
-		dig_rf_freq++;
-
-	set_reg_bits(state->tab_rftune, 0x0d, 0xff, (u8) dig_rf_freq);
-	set_reg_bits(state->tab_rftune, 0x0e, 0xff, (u8) (dig_rf_freq >> 8));
-
-	if (rf_freq >= 333000000)
-		set_reg_bits(state->tab_rftune, 0x80, 0x40, 0x40);
-
-	return state->tab_rftune;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static int mxl5007t_write_reg(struct mxl5007t_state *state, u8 reg, u8 val)
-{
-	u8 buf[] = { reg, val };
-	struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0,
-			       .buf = buf, .len = 2 };
-	int ret;
-
-	ret = i2c_transfer(state->i2c_props.adap, &msg, 1);
-	if (ret != 1) {
-		mxl_err("failed!");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int mxl5007t_write_regs(struct mxl5007t_state *state,
-			       struct reg_pair_t *reg_pair)
-{
-	unsigned int i = 0;
-	int ret = 0;
-
-	while ((ret == 0) && (reg_pair[i].reg || reg_pair[i].val)) {
-		ret = mxl5007t_write_reg(state,
-					 reg_pair[i].reg, reg_pair[i].val);
-		i++;
-	}
-	return ret;
-}
-
-static int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val)
-{
-	u8 buf[2] = { 0xfb, reg };
-	struct i2c_msg msg[] = {
-		{ .addr = state->i2c_props.addr, .flags = 0,
-		  .buf = buf, .len = 2 },
-		{ .addr = state->i2c_props.addr, .flags = I2C_M_RD,
-		  .buf = val, .len = 1 },
-	};
-	int ret;
-
-	ret = i2c_transfer(state->i2c_props.adap, msg, 2);
-	if (ret != 2) {
-		mxl_err("failed!");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int mxl5007t_soft_reset(struct mxl5007t_state *state)
-{
-	u8 d = 0xff;
-	struct i2c_msg msg = {
-		.addr = state->i2c_props.addr, .flags = 0,
-		.buf = &d, .len = 1
-	};
-	int ret = i2c_transfer(state->i2c_props.adap, &msg, 1);
-
-	if (ret != 1) {
-		mxl_err("failed!");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int mxl5007t_tuner_init(struct mxl5007t_state *state,
-			       enum mxl5007t_mode mode)
-{
-	struct reg_pair_t *init_regs;
-	int ret;
-
-	ret = mxl5007t_soft_reset(state);
-	if (mxl_fail(ret))
-		goto fail;
-
-	/* calculate initialization reg array */
-	init_regs = mxl5007t_calc_init_regs(state, mode);
-
-	ret = mxl5007t_write_regs(state, init_regs);
-	if (mxl_fail(ret))
-		goto fail;
-	mdelay(1);
-fail:
-	return ret;
-}
-
-static int mxl5007t_tuner_rf_tune(struct mxl5007t_state *state, u32 rf_freq_hz,
-				  enum mxl5007t_bw_mhz bw)
-{
-	struct reg_pair_t *rf_tune_regs;
-	int ret;
-
-	/* calculate channel change reg array */
-	rf_tune_regs = mxl5007t_calc_rf_tune_regs(state, rf_freq_hz, bw);
-
-	ret = mxl5007t_write_regs(state, rf_tune_regs);
-	if (mxl_fail(ret))
-		goto fail;
-	msleep(3);
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static int mxl5007t_synth_lock_status(struct mxl5007t_state *state,
-				      int *rf_locked, int *ref_locked)
-{
-	u8 d;
-	int ret;
-
-	*rf_locked = 0;
-	*ref_locked = 0;
-
-	ret = mxl5007t_read_reg(state, 0xd8, &d);
-	if (mxl_fail(ret))
-		goto fail;
-
-	if ((d & 0x0c) == 0x0c)
-		*rf_locked = 1;
-
-	if ((d & 0x03) == 0x03)
-		*ref_locked = 1;
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status)
-{
-	struct mxl5007t_state *state = fe->tuner_priv;
-	int rf_locked, ref_locked, ret;
-
-	*status = 0;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	ret = mxl5007t_synth_lock_status(state, &rf_locked, &ref_locked);
-	if (mxl_fail(ret))
-		goto fail;
-	mxl_debug("%s%s", rf_locked ? "rf locked " : "",
-		  ref_locked ? "ref locked" : "");
-
-	if ((rf_locked) || (ref_locked))
-		*status |= TUNER_STATUS_LOCKED;
-fail:
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	return ret;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static int mxl5007t_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 delsys = c->delivery_system;
-	struct mxl5007t_state *state = fe->tuner_priv;
-	enum mxl5007t_bw_mhz bw;
-	enum mxl5007t_mode mode;
-	int ret;
-	u32 freq = c->frequency;
-
-	switch (delsys) {
-	case SYS_ATSC:
-		mode = MxL_MODE_ATSC;
-		bw = MxL_BW_6MHz;
-		break;
-	case SYS_DVBC_ANNEX_B:
-		mode = MxL_MODE_CABLE;
-		bw = MxL_BW_6MHz;
-		break;
-	case SYS_DVBT:
-	case SYS_DVBT2:
-		mode = MxL_MODE_DVBT;
-		switch (c->bandwidth_hz) {
-		case 6000000:
-			bw = MxL_BW_6MHz;
-			break;
-		case 7000000:
-			bw = MxL_BW_7MHz;
-			break;
-		case 8000000:
-			bw = MxL_BW_8MHz;
-			break;
-		default:
-			return -EINVAL;
-		}
-		break;
-	default:
-		mxl_err("modulation type not supported!");
-		return -EINVAL;
-	}
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	mutex_lock(&state->lock);
-
-	ret = mxl5007t_tuner_init(state, mode);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl5007t_tuner_rf_tune(state, freq, bw);
-	if (mxl_fail(ret))
-		goto fail;
-
-	state->frequency = freq;
-	state->bandwidth = c->bandwidth_hz;
-fail:
-	mutex_unlock(&state->lock);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	return ret;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static int mxl5007t_init(struct dvb_frontend *fe)
-{
-	struct mxl5007t_state *state = fe->tuner_priv;
-	int ret;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	/* wake from standby */
-	ret = mxl5007t_write_reg(state, 0x01, 0x01);
-	mxl_fail(ret);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	return ret;
-}
-
-static int mxl5007t_sleep(struct dvb_frontend *fe)
-{
-	struct mxl5007t_state *state = fe->tuner_priv;
-	int ret;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	/* enter standby mode */
-	ret = mxl5007t_write_reg(state, 0x01, 0x00);
-	mxl_fail(ret);
-	ret = mxl5007t_write_reg(state, 0x0f, 0x00);
-	mxl_fail(ret);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	return ret;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static int mxl5007t_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct mxl5007t_state *state = fe->tuner_priv;
-	*frequency = state->frequency;
-	return 0;
-}
-
-static int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	struct mxl5007t_state *state = fe->tuner_priv;
-	*bandwidth = state->bandwidth;
-	return 0;
-}
-
-static int mxl5007t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct mxl5007t_state *state = fe->tuner_priv;
-
-	*frequency = 0;
-
-	switch (state->if_freq) {
-	case MxL_IF_4_MHZ:
-		*frequency = 4000000;
-		break;
-	case MxL_IF_4_5_MHZ:
-		*frequency = 4500000;
-		break;
-	case MxL_IF_4_57_MHZ:
-		*frequency = 4570000;
-		break;
-	case MxL_IF_5_MHZ:
-		*frequency = 5000000;
-		break;
-	case MxL_IF_5_38_MHZ:
-		*frequency = 5380000;
-		break;
-	case MxL_IF_6_MHZ:
-		*frequency = 6000000;
-		break;
-	case MxL_IF_6_28_MHZ:
-		*frequency = 6280000;
-		break;
-	case MxL_IF_9_1915_MHZ:
-		*frequency = 9191500;
-		break;
-	case MxL_IF_35_25_MHZ:
-		*frequency = 35250000;
-		break;
-	case MxL_IF_36_15_MHZ:
-		*frequency = 36150000;
-		break;
-	case MxL_IF_44_MHZ:
-		*frequency = 44000000;
-		break;
-	}
-	return 0;
-}
-
-static int mxl5007t_release(struct dvb_frontend *fe)
-{
-	struct mxl5007t_state *state = fe->tuner_priv;
-
-	mutex_lock(&mxl5007t_list_mutex);
-
-	if (state)
-		hybrid_tuner_release_state(state);
-
-	mutex_unlock(&mxl5007t_list_mutex);
-
-	fe->tuner_priv = NULL;
-
-	return 0;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static struct dvb_tuner_ops mxl5007t_tuner_ops = {
-	.info = {
-		.name = "MaxLinear MxL5007T",
-	},
-	.init              = mxl5007t_init,
-	.sleep             = mxl5007t_sleep,
-	.set_params        = mxl5007t_set_params,
-	.get_status        = mxl5007t_get_status,
-	.get_frequency     = mxl5007t_get_frequency,
-	.get_bandwidth     = mxl5007t_get_bandwidth,
-	.release           = mxl5007t_release,
-	.get_if_frequency  = mxl5007t_get_if_frequency,
-};
-
-static int mxl5007t_get_chip_id(struct mxl5007t_state *state)
-{
-	char *name;
-	int ret;
-	u8 id;
-
-	ret = mxl5007t_read_reg(state, 0xd9, &id);
-	if (mxl_fail(ret))
-		goto fail;
-
-	switch (id) {
-	case MxL_5007_V1_F1:
-		name = "MxL5007.v1.f1";
-		break;
-	case MxL_5007_V1_F2:
-		name = "MxL5007.v1.f2";
-		break;
-	case MxL_5007_V2_100_F1:
-		name = "MxL5007.v2.100.f1";
-		break;
-	case MxL_5007_V2_100_F2:
-		name = "MxL5007.v2.100.f2";
-		break;
-	case MxL_5007_V2_200_F1:
-		name = "MxL5007.v2.200.f1";
-		break;
-	case MxL_5007_V2_200_F2:
-		name = "MxL5007.v2.200.f2";
-		break;
-	case MxL_5007_V4:
-		name = "MxL5007T.v4";
-		break;
-	default:
-		name = "MxL5007T";
-		printk(KERN_WARNING "%s: unknown rev (%02x)\n", __func__, id);
-		id = MxL_UNKNOWN_ID;
-	}
-	state->chip_id = id;
-	mxl_info("%s detected @ %d-%04x", name,
-		 i2c_adapter_id(state->i2c_props.adap),
-		 state->i2c_props.addr);
-	return 0;
-fail:
-	mxl_warn("unable to identify device @ %d-%04x",
-		 i2c_adapter_id(state->i2c_props.adap),
-		 state->i2c_props.addr);
-
-	state->chip_id = MxL_UNKNOWN_ID;
-	return ret;
-}
-
-struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
-				     struct i2c_adapter *i2c, u8 addr,
-				     struct mxl5007t_config *cfg)
-{
-	struct mxl5007t_state *state = NULL;
-	int instance, ret;
-
-	mutex_lock(&mxl5007t_list_mutex);
-	instance = hybrid_tuner_request_state(struct mxl5007t_state, state,
-					      hybrid_tuner_instance_list,
-					      i2c, addr, "mxl5007t");
-	switch (instance) {
-	case 0:
-		goto fail;
-	case 1:
-		/* new tuner instance */
-		state->config = cfg;
-
-		mutex_init(&state->lock);
-
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-
-		ret = mxl5007t_get_chip_id(state);
-
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-
-		/* check return value of mxl5007t_get_chip_id */
-		if (mxl_fail(ret))
-			goto fail;
-		break;
-	default:
-		/* existing tuner instance */
-		break;
-	}
-	fe->tuner_priv = state;
-	mutex_unlock(&mxl5007t_list_mutex);
-
-	memcpy(&fe->ops.tuner_ops, &mxl5007t_tuner_ops,
-	       sizeof(struct dvb_tuner_ops));
-
-	return fe;
-fail:
-	mutex_unlock(&mxl5007t_list_mutex);
-
-	mxl5007t_release(fe);
-	return NULL;
-}
-EXPORT_SYMBOL_GPL(mxl5007t_attach);
-MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver");
-MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.2");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/common/tuners/mxl5007t.h b/drivers/media/common/tuners/mxl5007t.h
deleted file mode 100644
index aa3eea0..0000000
--- a/drivers/media/common/tuners/mxl5007t.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- *  mxl5007t.h - driver for the MaxLinear MxL5007T silicon tuner
- *
- *  Copyright (C) 2008 Michael Krufky <mkrufky@linuxtv.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __MXL5007T_H__
-#define __MXL5007T_H__
-
-#include "dvb_frontend.h"
-
-/* ------------------------------------------------------------------------- */
-
-enum mxl5007t_if_freq {
-	MxL_IF_4_MHZ,      /*  4000000 */
-	MxL_IF_4_5_MHZ,    /*  4500000 */
-	MxL_IF_4_57_MHZ,   /*  4570000 */
-	MxL_IF_5_MHZ,      /*  5000000 */
-	MxL_IF_5_38_MHZ,   /*  5380000 */
-	MxL_IF_6_MHZ,      /*  6000000 */
-	MxL_IF_6_28_MHZ,   /*  6280000 */
-	MxL_IF_9_1915_MHZ, /*  9191500 */
-	MxL_IF_35_25_MHZ,  /* 35250000 */
-	MxL_IF_36_15_MHZ,  /* 36150000 */
-	MxL_IF_44_MHZ,     /* 44000000 */
-};
-
-enum mxl5007t_xtal_freq {
-	MxL_XTAL_16_MHZ,      /* 16000000 */
-	MxL_XTAL_20_MHZ,      /* 20000000 */
-	MxL_XTAL_20_25_MHZ,   /* 20250000 */
-	MxL_XTAL_20_48_MHZ,   /* 20480000 */
-	MxL_XTAL_24_MHZ,      /* 24000000 */
-	MxL_XTAL_25_MHZ,      /* 25000000 */
-	MxL_XTAL_25_14_MHZ,   /* 25140000 */
-	MxL_XTAL_27_MHZ,      /* 27000000 */
-	MxL_XTAL_28_8_MHZ,    /* 28800000 */
-	MxL_XTAL_32_MHZ,      /* 32000000 */
-	MxL_XTAL_40_MHZ,      /* 40000000 */
-	MxL_XTAL_44_MHZ,      /* 44000000 */
-	MxL_XTAL_48_MHZ,      /* 48000000 */
-	MxL_XTAL_49_3811_MHZ, /* 49381100 */
-};
-
-enum mxl5007t_clkout_amp {
-	MxL_CLKOUT_AMP_0_94V = 0,
-	MxL_CLKOUT_AMP_0_53V = 1,
-	MxL_CLKOUT_AMP_0_37V = 2,
-	MxL_CLKOUT_AMP_0_28V = 3,
-	MxL_CLKOUT_AMP_0_23V = 4,
-	MxL_CLKOUT_AMP_0_20V = 5,
-	MxL_CLKOUT_AMP_0_17V = 6,
-	MxL_CLKOUT_AMP_0_15V = 7,
-};
-
-struct mxl5007t_config {
-	s32 if_diff_out_level;
-	enum mxl5007t_clkout_amp clk_out_amp;
-	enum mxl5007t_xtal_freq xtal_freq_hz;
-	enum mxl5007t_if_freq if_freq_hz;
-	unsigned int invert_if:1;
-	unsigned int loop_thru_enable:1;
-	unsigned int clk_out_enable:1;
-};
-
-#if defined(CONFIG_MEDIA_TUNER_MXL5007T) || (defined(CONFIG_MEDIA_TUNER_MXL5007T_MODULE) && defined(MODULE))
-extern struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
-					    struct i2c_adapter *i2c, u8 addr,
-					    struct mxl5007t_config *cfg);
-#else
-static inline struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
-						   struct i2c_adapter *i2c,
-						   u8 addr,
-						   struct mxl5007t_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* __MXL5007T_H__ */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
-
diff --git a/drivers/media/common/tuners/qt1010.c b/drivers/media/common/tuners/qt1010.c
deleted file mode 100644
index 2d79b1f..0000000
--- a/drivers/media/common/tuners/qt1010.c
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- *  Driver for Quantek QT1010 silicon tuner
- *
- *  Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
- *                     Aapo Tahkola <aet@rasterburn.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#include "qt1010.h"
-#include "qt1010_priv.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-#define dprintk(args...) \
-	do { \
-		if (debug) printk(KERN_DEBUG "QT1010: " args); \
-	} while (0)
-
-/* read single register */
-static int qt1010_readreg(struct qt1010_priv *priv, u8 reg, u8 *val)
-{
-	struct i2c_msg msg[2] = {
-		{ .addr = priv->cfg->i2c_address,
-		  .flags = 0, .buf = &reg, .len = 1 },
-		{ .addr = priv->cfg->i2c_address,
-		  .flags = I2C_M_RD, .buf = val, .len = 1 },
-	};
-
-	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
-		printk(KERN_WARNING "qt1010 I2C read failed\n");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-/* write single register */
-static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val)
-{
-	u8 buf[2] = { reg, val };
-	struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
-			       .flags = 0, .buf = buf, .len = 2 };
-
-	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
-		printk(KERN_WARNING "qt1010 I2C write failed\n");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-/* dump all registers */
-static void qt1010_dump_regs(struct qt1010_priv *priv)
-{
-	u8 reg, val;
-
-	for (reg = 0; ; reg++) {
-		if (reg % 16 == 0) {
-			if (reg)
-				printk(KERN_CONT "\n");
-			printk(KERN_DEBUG "%02x:", reg);
-		}
-		if (qt1010_readreg(priv, reg, &val) == 0)
-			printk(KERN_CONT " %02x", val);
-		else
-			printk(KERN_CONT " --");
-		if (reg == 0x2f)
-			break;
-	}
-	printk(KERN_CONT "\n");
-}
-
-static int qt1010_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct qt1010_priv *priv;
-	int err;
-	u32 freq, div, mod1, mod2;
-	u8 i, tmpval, reg05;
-	qt1010_i2c_oper_t rd[48] = {
-		{ QT1010_WR, 0x01, 0x80 },
-		{ QT1010_WR, 0x02, 0x3f },
-		{ QT1010_WR, 0x05, 0xff }, /* 02 c write */
-		{ QT1010_WR, 0x06, 0x44 },
-		{ QT1010_WR, 0x07, 0xff }, /* 04 c write */
-		{ QT1010_WR, 0x08, 0x08 },
-		{ QT1010_WR, 0x09, 0xff }, /* 06 c write */
-		{ QT1010_WR, 0x0a, 0xff }, /* 07 c write */
-		{ QT1010_WR, 0x0b, 0xff }, /* 08 c write */
-		{ QT1010_WR, 0x0c, 0xe1 },
-		{ QT1010_WR, 0x1a, 0xff }, /* 10 c write */
-		{ QT1010_WR, 0x1b, 0x00 },
-		{ QT1010_WR, 0x1c, 0x89 },
-		{ QT1010_WR, 0x11, 0xff }, /* 13 c write */
-		{ QT1010_WR, 0x12, 0xff }, /* 14 c write */
-		{ QT1010_WR, 0x22, 0xff }, /* 15 c write */
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_WR, 0x1e, 0xd0 },
-		{ QT1010_RD, 0x22, 0xff }, /* 16 c read */
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_RD, 0x05, 0xff }, /* 20 c read */
-		{ QT1010_RD, 0x22, 0xff }, /* 21 c read */
-		{ QT1010_WR, 0x23, 0xd0 },
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_WR, 0x1e, 0xe0 },
-		{ QT1010_RD, 0x23, 0xff }, /* 25 c read */
-		{ QT1010_RD, 0x23, 0xff }, /* 26 c read */
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_WR, 0x24, 0xd0 },
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_WR, 0x1e, 0xf0 },
-		{ QT1010_RD, 0x24, 0xff }, /* 31 c read */
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_WR, 0x14, 0x7f },
-		{ QT1010_WR, 0x15, 0x7f },
-		{ QT1010_WR, 0x05, 0xff }, /* 35 c write */
-		{ QT1010_WR, 0x06, 0x00 },
-		{ QT1010_WR, 0x15, 0x1f },
-		{ QT1010_WR, 0x16, 0xff },
-		{ QT1010_WR, 0x18, 0xff },
-		{ QT1010_WR, 0x1f, 0xff }, /* 40 c write */
-		{ QT1010_WR, 0x20, 0xff }, /* 41 c write */
-		{ QT1010_WR, 0x21, 0x53 },
-		{ QT1010_WR, 0x25, 0xff }, /* 43 c write */
-		{ QT1010_WR, 0x26, 0x15 },
-		{ QT1010_WR, 0x00, 0xff }, /* 45 c write */
-		{ QT1010_WR, 0x02, 0x00 },
-		{ QT1010_WR, 0x01, 0x00 }
-	};
-
-#define FREQ1 32000000 /* 32 MHz */
-#define FREQ2  4000000 /* 4 MHz Quartz oscillator in the stick? */
-
-	priv = fe->tuner_priv;
-	freq = c->frequency;
-	div = (freq + QT1010_OFFSET) / QT1010_STEP;
-	freq = (div * QT1010_STEP) - QT1010_OFFSET;
-	mod1 = (freq + QT1010_OFFSET) % FREQ1;
-	mod2 = (freq + QT1010_OFFSET) % FREQ2;
-	priv->frequency = freq;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
-
-	/* reg 05 base value */
-	if      (freq < 290000000) reg05 = 0x14; /* 290 MHz */
-	else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */
-	else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */
-	else                       reg05 = 0x74;
-
-	/* 0x5 */
-	rd[2].val = reg05;
-
-	/* 07 - set frequency: 32 MHz scale */
-	rd[4].val = (freq + QT1010_OFFSET) / FREQ1;
-
-	/* 09 - changes every 8/24 MHz */
-	if (mod1 < 8000000) rd[6].val = 0x1d;
-	else                rd[6].val = 0x1c;
-
-	/* 0a - set frequency: 4 MHz scale (max 28 MHz) */
-	if      (mod1 < 1*FREQ2) rd[7].val = 0x09; /*  +0 MHz */
-	else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /*  +4 MHz */
-	else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /*  +8 MHz */
-	else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */
-	else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */
-	else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */
-	else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */
-	else                     rd[7].val = 0x0a; /* +28 MHz */
-
-	/* 0b - changes every 2/2 MHz */
-	if (mod2 < 2000000) rd[8].val = 0x45;
-	else                rd[8].val = 0x44;
-
-	/* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/
-	tmpval = 0x78; /* byte, overflows intentionally */
-	rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08);
-
-	/* 11 */
-	rd[13].val = 0xfd; /* TODO: correct value calculation */
-
-	/* 12 */
-	rd[14].val = 0x91; /* TODO: correct value calculation */
-
-	/* 22 */
-	if      (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */
-	else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */
-	else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */
-	else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */
-	else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */
-	else                       rd[15].val = 0xd0;
-
-	/* 05 */
-	rd[35].val = (reg05 & 0xf0);
-
-	/* 1f */
-	if      (mod1 <  8000000) tmpval = 0x00;
-	else if (mod1 < 12000000) tmpval = 0x01;
-	else if (mod1 < 16000000) tmpval = 0x02;
-	else if (mod1 < 24000000) tmpval = 0x03;
-	else if (mod1 < 28000000) tmpval = 0x04;
-	else                      tmpval = 0x05;
-	rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval);
-
-	/* 20 */
-	if      (mod1 <  8000000) tmpval = 0x00;
-	else if (mod1 < 12000000) tmpval = 0x01;
-	else if (mod1 < 20000000) tmpval = 0x02;
-	else if (mod1 < 24000000) tmpval = 0x03;
-	else if (mod1 < 28000000) tmpval = 0x04;
-	else                      tmpval = 0x05;
-	rd[41].val = (priv->reg20_init_val + 0x0d + tmpval);
-
-	/* 25 */
-	rd[43].val = priv->reg25_init_val;
-
-	/* 00 */
-	rd[45].val = 0x92; /* TODO: correct value calculation */
-
-	dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \
-		"1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \
-		"20:%02x 25:%02x 00:%02x", \
-		freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \
-		rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \
-		rd[40].val, rd[41].val, rd[43].val, rd[45].val);
-
-	for (i = 0; i < ARRAY_SIZE(rd); i++) {
-		if (rd[i].oper == QT1010_WR) {
-			err = qt1010_writereg(priv, rd[i].reg, rd[i].val);
-		} else { /* read is required to proper locking */
-			err = qt1010_readreg(priv, rd[i].reg, &tmpval);
-		}
-		if (err) return err;
-	}
-
-	if (debug)
-		qt1010_dump_regs(priv);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
-
-	return 0;
-}
-
-static int qt1010_init_meas1(struct qt1010_priv *priv,
-			     u8 oper, u8 reg, u8 reg_init_val, u8 *retval)
-{
-	u8 i, val1, val2;
-	int err;
-
-	qt1010_i2c_oper_t i2c_data[] = {
-		{ QT1010_WR, reg, reg_init_val },
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_WR, 0x1e, oper },
-		{ QT1010_RD, reg, 0xff }
-	};
-
-	for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
-		if (i2c_data[i].oper == QT1010_WR) {
-			err = qt1010_writereg(priv, i2c_data[i].reg,
-					      i2c_data[i].val);
-		} else {
-			err = qt1010_readreg(priv, i2c_data[i].reg, &val2);
-		}
-		if (err) return err;
-	}
-
-	do {
-		val1 = val2;
-		err = qt1010_readreg(priv, reg, &val2);
-		if (err) return err;
-		dprintk("compare reg:%02x %02x %02x", reg, val1, val2);
-	} while (val1 != val2);
-	*retval = val1;
-
-	return qt1010_writereg(priv, 0x1e, 0x00);
-}
-
-static u8 qt1010_init_meas2(struct qt1010_priv *priv,
-			    u8 reg_init_val, u8 *retval)
-{
-	u8 i, val;
-	int err;
-	qt1010_i2c_oper_t i2c_data[] = {
-		{ QT1010_WR, 0x07, reg_init_val },
-		{ QT1010_WR, 0x22, 0xd0 },
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_WR, 0x1e, 0xd0 },
-		{ QT1010_RD, 0x22, 0xff },
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_WR, 0x22, 0xff }
-	};
-	for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
-		if (i2c_data[i].oper == QT1010_WR) {
-			err = qt1010_writereg(priv, i2c_data[i].reg,
-					      i2c_data[i].val);
-		} else {
-			err = qt1010_readreg(priv, i2c_data[i].reg, &val);
-		}
-		if (err) return err;
-	}
-	*retval = val;
-	return 0;
-}
-
-static int qt1010_init(struct dvb_frontend *fe)
-{
-	struct qt1010_priv *priv = fe->tuner_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int err = 0;
-	u8 i, tmpval, *valptr = NULL;
-
-	qt1010_i2c_oper_t i2c_data[] = {
-		{ QT1010_WR, 0x01, 0x80 },
-		{ QT1010_WR, 0x0d, 0x84 },
-		{ QT1010_WR, 0x0e, 0xb7 },
-		{ QT1010_WR, 0x2a, 0x23 },
-		{ QT1010_WR, 0x2c, 0xdc },
-		{ QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */
-		{ QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */
-		{ QT1010_WR, 0x2b, 0x70 },
-		{ QT1010_WR, 0x2a, 0x23 },
-		{ QT1010_M1, 0x26, 0x08 },
-		{ QT1010_M1, 0x82, 0xff },
-		{ QT1010_WR, 0x05, 0x14 },
-		{ QT1010_WR, 0x06, 0x44 },
-		{ QT1010_WR, 0x07, 0x28 },
-		{ QT1010_WR, 0x08, 0x0b },
-		{ QT1010_WR, 0x11, 0xfd },
-		{ QT1010_M1, 0x22, 0x0d },
-		{ QT1010_M1, 0xd0, 0xff },
-		{ QT1010_WR, 0x06, 0x40 },
-		{ QT1010_WR, 0x16, 0xf0 },
-		{ QT1010_WR, 0x02, 0x38 },
-		{ QT1010_WR, 0x03, 0x18 },
-		{ QT1010_WR, 0x20, 0xe0 },
-		{ QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */
-		{ QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */
-		{ QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */
-		{ QT1010_WR, 0x03, 0x19 },
-		{ QT1010_WR, 0x02, 0x3f },
-		{ QT1010_WR, 0x21, 0x53 },
-		{ QT1010_RD, 0x21, 0xff },
-		{ QT1010_WR, 0x11, 0xfd },
-		{ QT1010_WR, 0x05, 0x34 },
-		{ QT1010_WR, 0x06, 0x44 },
-		{ QT1010_WR, 0x08, 0x08 }
-	};
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
-
-	for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
-		switch (i2c_data[i].oper) {
-		case QT1010_WR:
-			err = qt1010_writereg(priv, i2c_data[i].reg,
-					      i2c_data[i].val);
-			break;
-		case QT1010_RD:
-			if (i2c_data[i].val == 0x20)
-				valptr = &priv->reg20_init_val;
-			else
-				valptr = &tmpval;
-			err = qt1010_readreg(priv, i2c_data[i].reg, valptr);
-			break;
-		case QT1010_M1:
-			if (i2c_data[i].val == 0x25)
-				valptr = &priv->reg25_init_val;
-			else if (i2c_data[i].val == 0x1f)
-				valptr = &priv->reg1f_init_val;
-			else
-				valptr = &tmpval;
-			err = qt1010_init_meas1(priv, i2c_data[i+1].reg,
-						i2c_data[i].reg,
-						i2c_data[i].val, valptr);
-			i++;
-			break;
-		}
-		if (err) return err;
-	}
-
-	for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */
-		if ((err = qt1010_init_meas2(priv, i, &tmpval)))
-			return err;
-
-	c->frequency = 545000000; /* Sigmatek DVB-110 545000000 */
-				      /* MSI Megasky 580 GL861 533000000 */
-	return qt1010_set_params(fe);
-}
-
-static int qt1010_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct qt1010_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-	return 0;
-}
-
-static int qt1010_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	*frequency = 36125000;
-	return 0;
-}
-
-static const struct dvb_tuner_ops qt1010_tuner_ops = {
-	.info = {
-		.name           = "Quantek QT1010",
-		.frequency_min  = QT1010_MIN_FREQ,
-		.frequency_max  = QT1010_MAX_FREQ,
-		.frequency_step = QT1010_STEP,
-	},
-
-	.release       = qt1010_release,
-	.init          = qt1010_init,
-	/* TODO: implement sleep */
-
-	.set_params    = qt1010_set_params,
-	.get_frequency = qt1010_get_frequency,
-	.get_if_frequency = qt1010_get_if_frequency,
-};
-
-struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe,
-				    struct i2c_adapter *i2c,
-				    struct qt1010_config *cfg)
-{
-	struct qt1010_priv *priv = NULL;
-	u8 id;
-
-	priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	priv->cfg = cfg;
-	priv->i2c = i2c;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
-
-
-	/* Try to detect tuner chip. Probably this is not correct register. */
-	if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) {
-		kfree(priv);
-		return NULL;
-	}
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
-
-	printk(KERN_INFO "Quantek QT1010 successfully identified.\n");
-	memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops,
-	       sizeof(struct dvb_tuner_ops));
-
-	fe->tuner_priv = priv;
-	return fe;
-}
-EXPORT_SYMBOL(qt1010_attach);
-
-MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver");
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
-MODULE_VERSION("0.1");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/qt1010.h b/drivers/media/common/tuners/qt1010.h
deleted file mode 100644
index 807fb7b..0000000
--- a/drivers/media/common/tuners/qt1010.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *  Driver for Quantek QT1010 silicon tuner
- *
- *  Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
- *                     Aapo Tahkola <aet@rasterburn.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef QT1010_H
-#define QT1010_H
-
-#include "dvb_frontend.h"
-
-struct qt1010_config {
-	u8 i2c_address;
-};
-
-/**
- * Attach a qt1010 tuner to the supplied frontend structure.
- *
- * @param fe   frontend to attach to
- * @param i2c  i2c adapter to use
- * @param cfg  tuner hw based configuration
- * @return fe  pointer on success, NULL on failure
- */
-#if defined(CONFIG_MEDIA_TUNER_QT1010) || (defined(CONFIG_MEDIA_TUNER_QT1010_MODULE) && defined(MODULE))
-extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
-					  struct i2c_adapter *i2c,
-					  struct qt1010_config *cfg);
-#else
-static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
-						 struct i2c_adapter *i2c,
-						 struct qt1010_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_MEDIA_TUNER_QT1010
-
-#endif
diff --git a/drivers/media/common/tuners/qt1010_priv.h b/drivers/media/common/tuners/qt1010_priv.h
deleted file mode 100644
index 2c42d3f..0000000
--- a/drivers/media/common/tuners/qt1010_priv.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- *  Driver for Quantek QT1010 silicon tuner
- *
- *  Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
- *                     Aapo Tahkola <aet@rasterburn.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef QT1010_PRIV_H
-#define QT1010_PRIV_H
-
-/*
-reg def meaning
-=== === =======
-00  00  ?
-01  a0  ? operation start/stop; start=80, stop=00
-02  00  ?
-03  19  ?
-04  00  ?
-05  00  ? maybe band selection
-06  00  ?
-07  2b  set frequency: 32 MHz scale, n*32 MHz
-08  0b  ?
-09  10  ? changes every 8/24 MHz; values 1d/1c
-0a  08  set frequency: 4 MHz scale, n*4 MHz
-0b  41  ? changes every 2/2 MHz; values 45/45
-0c  e1  ?
-0d  94  ?
-0e  b6  ?
-0f  2c  ?
-10  10  ?
-11  f1  ? maybe device specified adjustment
-12  11  ? maybe device specified adjustment
-13  3f  ?
-14  1f  ?
-15  3f  ?
-16  ff  ?
-17  ff  ?
-18  f7  ?
-19  80  ?
-1a  d0  set frequency: 125 kHz scale, n*125 kHz
-1b  00  ?
-1c  89  ?
-1d  00  ?
-1e  00  ? looks like operation register; write cmd here, read result from 1f-26
-1f  20  ? chip initialization
-20  e0  ? chip initialization
-21  20  ?
-22  d0  ?
-23  d0  ?
-24  d0  ?
-25  40  ? chip initialization
-26  08  ?
-27  29  ?
-28  55  ?
-29  39  ?
-2a  13  ?
-2b  01  ?
-2c  ea  ?
-2d  00  ?
-2e  00  ? not used?
-2f  00  ? not used?
-*/
-
-#define QT1010_STEP         125000 /*  125 kHz used by Windows drivers,
-				      hw could be more precise but we don't
-				      know how to use */
-#define QT1010_MIN_FREQ   48000000 /*   48 MHz */
-#define QT1010_MAX_FREQ  860000000 /*  860 MHz */
-#define QT1010_OFFSET   1246000000 /* 1246 MHz */
-
-#define QT1010_WR 0
-#define QT1010_RD 1
-#define QT1010_M1 3
-
-typedef struct {
-	u8 oper, reg, val;
-} qt1010_i2c_oper_t;
-
-struct qt1010_priv {
-	struct qt1010_config *cfg;
-	struct i2c_adapter   *i2c;
-
-	u8 reg1f_init_val;
-	u8 reg20_init_val;
-	u8 reg25_init_val;
-
-	u32 frequency;
-};
-
-#endif
diff --git a/drivers/media/common/tuners/tda18212.c b/drivers/media/common/tuners/tda18212.c
deleted file mode 100644
index 602c2e3..0000000
--- a/drivers/media/common/tuners/tda18212.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * NXP TDA18212HN silicon tuner driver
- *
- * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include "tda18212.h"
-
-struct tda18212_priv {
-	struct tda18212_config *cfg;
-	struct i2c_adapter *i2c;
-
-	u32 if_frequency;
-};
-
-#define dbg(fmt, arg...)					\
-do {								\
-	if (debug)						\
-		pr_info("%s: " fmt, __func__, ##arg);		\
-} while (0)
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-/* write multiple registers */
-static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
-	int len)
-{
-	int ret;
-	u8 buf[len+1];
-	struct i2c_msg msg[1] = {
-		{
-			.addr = priv->cfg->i2c_address,
-			.flags = 0,
-			.len = sizeof(buf),
-			.buf = buf,
-		}
-	};
-
-	buf[0] = reg;
-	memcpy(&buf[1], val, len);
-
-	ret = i2c_transfer(priv->i2c, msg, 1);
-	if (ret == 1) {
-		ret = 0;
-	} else {
-		pr_warn("i2c wr failed ret:%d reg:%02x len:%d\n",
-			ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-	return ret;
-}
-
-/* read multiple registers */
-static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
-	int len)
-{
-	int ret;
-	u8 buf[len];
-	struct i2c_msg msg[2] = {
-		{
-			.addr = priv->cfg->i2c_address,
-			.flags = 0,
-			.len = 1,
-			.buf = &reg,
-		}, {
-			.addr = priv->cfg->i2c_address,
-			.flags = I2C_M_RD,
-			.len = sizeof(buf),
-			.buf = buf,
-		}
-	};
-
-	ret = i2c_transfer(priv->i2c, msg, 2);
-	if (ret == 2) {
-		memcpy(val, buf, len);
-		ret = 0;
-	} else {
-		pr_warn("i2c rd failed ret:%d reg:%02x len:%d\n",
-			ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-
-	return ret;
-}
-
-/* write single register */
-static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val)
-{
-	return tda18212_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val)
-{
-	return tda18212_rd_regs(priv, reg, val, 1);
-}
-
-#if 0 /* keep, useful when developing driver */
-static void tda18212_dump_regs(struct tda18212_priv *priv)
-{
-	int i;
-	u8 buf[256];
-
-	#define TDA18212_RD_LEN 32
-	for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN)
-		tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN);
-
-	print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf,
-		sizeof(buf), true);
-
-	return;
-}
-#endif
-
-static int tda18212_set_params(struct dvb_frontend *fe)
-{
-	struct tda18212_priv *priv = fe->tuner_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret, i;
-	u32 if_khz;
-	u8 buf[9];
-	#define DVBT_6   0
-	#define DVBT_7   1
-	#define DVBT_8   2
-	#define DVBT2_6  3
-	#define DVBT2_7  4
-	#define DVBT2_8  5
-	#define DVBC_6   6
-	#define DVBC_8   7
-	static const u8 bw_params[][3] = {
-		     /* reg:   0f    13    23 */
-		[DVBT_6]  = { 0xb3, 0x20, 0x03 },
-		[DVBT_7]  = { 0xb3, 0x31, 0x01 },
-		[DVBT_8]  = { 0xb3, 0x22, 0x01 },
-		[DVBT2_6] = { 0xbc, 0x20, 0x03 },
-		[DVBT2_7] = { 0xbc, 0x72, 0x03 },
-		[DVBT2_8] = { 0xbc, 0x22, 0x01 },
-		[DVBC_6]  = { 0x92, 0x50, 0x03 },
-		[DVBC_8]  = { 0x92, 0x53, 0x03 },
-	};
-
-	dbg("delsys=%d RF=%d BW=%d\n",
-	    c->delivery_system, c->frequency, c->bandwidth_hz);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
-	switch (c->delivery_system) {
-	case SYS_DVBT:
-		switch (c->bandwidth_hz) {
-		case 6000000:
-			if_khz = priv->cfg->if_dvbt_6;
-			i = DVBT_6;
-			break;
-		case 7000000:
-			if_khz = priv->cfg->if_dvbt_7;
-			i = DVBT_7;
-			break;
-		case 8000000:
-			if_khz = priv->cfg->if_dvbt_8;
-			i = DVBT_8;
-			break;
-		default:
-			ret = -EINVAL;
-			goto error;
-		}
-		break;
-	case SYS_DVBT2:
-		switch (c->bandwidth_hz) {
-		case 6000000:
-			if_khz = priv->cfg->if_dvbt2_6;
-			i = DVBT2_6;
-			break;
-		case 7000000:
-			if_khz = priv->cfg->if_dvbt2_7;
-			i = DVBT2_7;
-			break;
-		case 8000000:
-			if_khz = priv->cfg->if_dvbt2_8;
-			i = DVBT2_8;
-			break;
-		default:
-			ret = -EINVAL;
-			goto error;
-		}
-		break;
-	case SYS_DVBC_ANNEX_A:
-	case SYS_DVBC_ANNEX_C:
-		if_khz = priv->cfg->if_dvbc;
-		i = DVBC_8;
-		break;
-	default:
-		ret = -EINVAL;
-		goto error;
-	}
-
-	ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]);
-	if (ret)
-		goto error;
-
-	ret = tda18212_wr_reg(priv, 0x06, 0x00);
-	if (ret)
-		goto error;
-
-	ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]);
-	if (ret)
-		goto error;
-
-	buf[0] = 0x02;
-	buf[1] = bw_params[i][1];
-	buf[2] = 0x03; /* default value */
-	buf[3] = DIV_ROUND_CLOSEST(if_khz, 50);
-	buf[4] = ((c->frequency / 1000) >> 16) & 0xff;
-	buf[5] = ((c->frequency / 1000) >>  8) & 0xff;
-	buf[6] = ((c->frequency / 1000) >>  0) & 0xff;
-	buf[7] = 0xc1;
-	buf[8] = 0x01;
-	ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf));
-	if (ret)
-		goto error;
-
-	/* actual IF rounded as it is on register */
-	priv->if_frequency = buf[3] * 50 * 1000;
-
-exit:
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-
-	return ret;
-
-error:
-	dbg("failed:%d\n", ret);
-	goto exit;
-}
-
-static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct tda18212_priv *priv = fe->tuner_priv;
-
-	*frequency = priv->if_frequency;
-
-	return 0;
-}
-
-static int tda18212_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static const struct dvb_tuner_ops tda18212_tuner_ops = {
-	.info = {
-		.name           = "NXP TDA18212",
-
-		.frequency_min  =  48000000,
-		.frequency_max  = 864000000,
-		.frequency_step =      1000,
-	},
-
-	.release       = tda18212_release,
-
-	.set_params    = tda18212_set_params,
-	.get_if_frequency = tda18212_get_if_frequency,
-};
-
-struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, struct tda18212_config *cfg)
-{
-	struct tda18212_priv *priv = NULL;
-	int ret;
-	u8 val;
-
-	priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	priv->cfg = cfg;
-	priv->i2c = i2c;
-	fe->tuner_priv = priv;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
-	/* check if the tuner is there */
-	ret = tda18212_rd_reg(priv, 0x00, &val);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-
-	dbg("ret:%d chip ID:%02x\n", ret, val);
-	if (ret || val != 0xc7) {
-		kfree(priv);
-		return NULL;
-	}
-
-	pr_info("NXP TDA18212HN successfully identified\n");
-
-	memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,
-		sizeof(struct dvb_tuner_ops));
-
-	return fe;
-}
-EXPORT_SYMBOL(tda18212_attach);
-
-MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver");
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tda18212.h b/drivers/media/common/tuners/tda18212.h
deleted file mode 100644
index 9bd5da4..0000000
--- a/drivers/media/common/tuners/tda18212.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * NXP TDA18212HN silicon tuner driver
- *
- * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef TDA18212_H
-#define TDA18212_H
-
-#include "dvb_frontend.h"
-
-struct tda18212_config {
-	u8 i2c_address;
-
-	u16 if_dvbt_6;
-	u16 if_dvbt_7;
-	u16 if_dvbt_8;
-	u16 if_dvbt2_5;
-	u16 if_dvbt2_6;
-	u16 if_dvbt2_7;
-	u16 if_dvbt2_8;
-	u16 if_dvbc;
-};
-
-#if defined(CONFIG_MEDIA_TUNER_TDA18212) || \
-	(defined(CONFIG_MEDIA_TUNER_TDA18212_MODULE) && defined(MODULE))
-extern struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, struct tda18212_config *cfg);
-#else
-static inline struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, struct tda18212_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/common/tuners/tda18218.c b/drivers/media/common/tuners/tda18218.c
deleted file mode 100644
index dfb3a83..0000000
--- a/drivers/media/common/tuners/tda18218.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * NXP TDA18218HN silicon tuner driver
- *
- * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "tda18218.h"
-#include "tda18218_priv.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-/* write multiple registers */
-static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
-{
-	int ret = 0;
-	u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max;
-	struct i2c_msg msg[1] = {
-		{
-			.addr = priv->cfg->i2c_address,
-			.flags = 0,
-			.buf = buf,
-		}
-	};
-
-	msg_len_max = priv->cfg->i2c_wr_max - 1;
-	quotient = len / msg_len_max;
-	remainder = len % msg_len_max;
-	msg_len = msg_len_max;
-	for (i = 0; (i <= quotient && remainder); i++) {
-		if (i == quotient)  /* set len of the last msg */
-			msg_len = remainder;
-
-		msg[0].len = msg_len + 1;
-		buf[0] = reg + i * msg_len_max;
-		memcpy(&buf[1], &val[i * msg_len_max], msg_len);
-
-		ret = i2c_transfer(priv->i2c, msg, 1);
-		if (ret != 1)
-			break;
-	}
-
-	if (ret == 1) {
-		ret = 0;
-	} else {
-		warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-
-	return ret;
-}
-
-/* read multiple registers */
-static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
-{
-	int ret;
-	u8 buf[reg+len]; /* we must start read always from reg 0x00 */
-	struct i2c_msg msg[2] = {
-		{
-			.addr = priv->cfg->i2c_address,
-			.flags = 0,
-			.len = 1,
-			.buf = "\x00",
-		}, {
-			.addr = priv->cfg->i2c_address,
-			.flags = I2C_M_RD,
-			.len = sizeof(buf),
-			.buf = buf,
-		}
-	};
-
-	ret = i2c_transfer(priv->i2c, msg, 2);
-	if (ret == 2) {
-		memcpy(val, &buf[reg], len);
-		ret = 0;
-	} else {
-		warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-
-	return ret;
-}
-
-/* write single register */
-static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val)
-{
-	return tda18218_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-
-static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val)
-{
-	return tda18218_rd_regs(priv, reg, val, 1);
-}
-
-static int tda18218_set_params(struct dvb_frontend *fe)
-{
-	struct tda18218_priv *priv = fe->tuner_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 bw = c->bandwidth_hz;
-	int ret;
-	u8 buf[3], i, BP_Filter, LP_Fc;
-	u32 LO_Frac;
-	/* TODO: find out correct AGC algorithm */
-	u8 agc[][2] = {
-		{ R20_AGC11, 0x60 },
-		{ R23_AGC21, 0x02 },
-		{ R20_AGC11, 0xa0 },
-		{ R23_AGC21, 0x09 },
-		{ R20_AGC11, 0xe0 },
-		{ R23_AGC21, 0x0c },
-		{ R20_AGC11, 0x40 },
-		{ R23_AGC21, 0x01 },
-		{ R20_AGC11, 0x80 },
-		{ R23_AGC21, 0x08 },
-		{ R20_AGC11, 0xc0 },
-		{ R23_AGC21, 0x0b },
-		{ R24_AGC22, 0x1c },
-		{ R24_AGC22, 0x0c },
-	};
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
-	/* low-pass filter cut-off frequency */
-	if (bw <= 6000000) {
-		LP_Fc = 0;
-		priv->if_frequency = 3000000;
-	} else if (bw <= 7000000) {
-		LP_Fc = 1;
-		priv->if_frequency = 3500000;
-	} else {
-		LP_Fc = 2;
-		priv->if_frequency = 4000000;
-	}
-
-	LO_Frac = c->frequency + priv->if_frequency;
-
-	/* band-pass filter */
-	if (LO_Frac < 188000000)
-		BP_Filter = 3;
-	else if (LO_Frac < 253000000)
-		BP_Filter = 4;
-	else if (LO_Frac < 343000000)
-		BP_Filter = 5;
-	else
-		BP_Filter = 6;
-
-	buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */
-	buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */
-	buf[2] = priv->regs[R1C_AGC2B];
-	ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3);
-	if (ret)
-		goto error;
-
-	buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */
-	buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */
-	buf[2] = (LO_Frac / 1000) << 4 |
-		(priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */
-	ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3);
-	if (ret)
-		goto error;
-
-	buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */
-	ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
-	if (ret)
-		goto error;
-
-	buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */
-	ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
-	if (ret)
-		goto error;
-
-	/* trigger AGC */
-	for (i = 0; i < ARRAY_SIZE(agc); i++) {
-		ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]);
-		if (ret)
-			goto error;
-	}
-
-error:
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-
-	if (ret)
-		dbg("%s: failed ret:%d", __func__, ret);
-
-	return ret;
-}
-
-static int tda18218_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct tda18218_priv *priv = fe->tuner_priv;
-	*frequency = priv->if_frequency;
-	dbg("%s: if=%d", __func__, *frequency);
-	return 0;
-}
-
-static int tda18218_sleep(struct dvb_frontend *fe)
-{
-	struct tda18218_priv *priv = fe->tuner_priv;
-	int ret;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
-	/* standby */
-	ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-
-	if (ret)
-		dbg("%s: failed ret:%d", __func__, ret);
-
-	return ret;
-}
-
-static int tda18218_init(struct dvb_frontend *fe)
-{
-	struct tda18218_priv *priv = fe->tuner_priv;
-	int ret;
-
-	/* TODO: calibrations */
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
-	ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-
-	if (ret)
-		dbg("%s: failed ret:%d", __func__, ret);
-
-	return ret;
-}
-
-static int tda18218_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static const struct dvb_tuner_ops tda18218_tuner_ops = {
-	.info = {
-		.name           = "NXP TDA18218",
-
-		.frequency_min  = 174000000,
-		.frequency_max  = 864000000,
-		.frequency_step =      1000,
-	},
-
-	.release       = tda18218_release,
-	.init          = tda18218_init,
-	.sleep         = tda18218_sleep,
-
-	.set_params    = tda18218_set_params,
-
-	.get_if_frequency = tda18218_get_if_frequency,
-};
-
-struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, struct tda18218_config *cfg)
-{
-	struct tda18218_priv *priv = NULL;
-	u8 val;
-	int ret;
-	/* chip default registers values */
-	static u8 def_regs[] = {
-		0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40,
-		0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00,
-		0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01,
-		0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9,
-		0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00,
-		0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6
-	};
-
-	priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	priv->cfg = cfg;
-	priv->i2c = i2c;
-	fe->tuner_priv = priv;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
-	/* check if the tuner is there */
-	ret = tda18218_rd_reg(priv, R00_ID, &val);
-	dbg("%s: ret:%d chip ID:%02x", __func__, ret, val);
-	if (ret || val != def_regs[R00_ID]) {
-		kfree(priv);
-		return NULL;
-	}
-
-	info("NXP TDA18218HN successfully identified.");
-
-	memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops,
-		sizeof(struct dvb_tuner_ops));
-	memcpy(priv->regs, def_regs, sizeof(def_regs));
-
-	/* loop-through enabled chip default register values */
-	if (priv->cfg->loop_through) {
-		priv->regs[R17_PD1] = 0xb0;
-		priv->regs[R18_PD2] = 0x59;
-	}
-
-	/* standby */
-	ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
-	if (ret)
-		dbg("%s: failed ret:%d", __func__, ret);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-
-	return fe;
-}
-EXPORT_SYMBOL(tda18218_attach);
-
-MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver");
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tda18218.h b/drivers/media/common/tuners/tda18218.h
deleted file mode 100644
index b4180d1..0000000
--- a/drivers/media/common/tuners/tda18218.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * NXP TDA18218HN silicon tuner driver
- *
- * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef TDA18218_H
-#define TDA18218_H
-
-#include "dvb_frontend.h"
-
-struct tda18218_config {
-	u8 i2c_address;
-	u8 i2c_wr_max;
-	u8 loop_through:1;
-};
-
-#if defined(CONFIG_MEDIA_TUNER_TDA18218) || \
-	(defined(CONFIG_MEDIA_TUNER_TDA18218_MODULE) && defined(MODULE))
-extern struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, struct tda18218_config *cfg);
-#else
-static inline struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, struct tda18218_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/common/tuners/tda18218_priv.h b/drivers/media/common/tuners/tda18218_priv.h
deleted file mode 100644
index dc52b72..0000000
--- a/drivers/media/common/tuners/tda18218_priv.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * NXP TDA18218HN silicon tuner driver
- *
- * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef TDA18218_PRIV_H
-#define TDA18218_PRIV_H
-
-#define LOG_PREFIX "tda18218"
-
-#undef dbg
-#define dbg(f, arg...) \
-	if (debug) \
-		printk(KERN_DEBUG   LOG_PREFIX": " f "\n" , ## arg)
-#undef err
-#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
-#undef info
-#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
-#undef warn
-#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
-
-#define R00_ID         0x00	/* ID byte */
-#define R01_R1         0x01	/* Read byte 1 */
-#define R02_R2         0x02	/* Read byte 2 */
-#define R03_R3         0x03	/* Read byte 3 */
-#define R04_R4         0x04	/* Read byte 4 */
-#define R05_R5         0x05	/* Read byte 5 */
-#define R06_R6         0x06	/* Read byte 6 */
-#define R07_MD1        0x07	/* Main divider byte 1 */
-#define R08_PSM1       0x08	/* PSM byte 1 */
-#define R09_MD2        0x09	/* Main divider byte 2 */
-#define R0A_MD3        0x0a	/* Main divider byte 1 */
-#define R0B_MD4        0x0b	/* Main divider byte 4 */
-#define R0C_MD5        0x0c	/* Main divider byte 5 */
-#define R0D_MD6        0x0d	/* Main divider byte 6 */
-#define R0E_MD7        0x0e	/* Main divider byte 7 */
-#define R0F_MD8        0x0f	/* Main divider byte 8 */
-#define R10_CD1        0x10	/* Call divider byte 1 */
-#define R11_CD2        0x11	/* Call divider byte 2 */
-#define R12_CD3        0x12	/* Call divider byte 3 */
-#define R13_CD4        0x13	/* Call divider byte 4 */
-#define R14_CD5        0x14	/* Call divider byte 5 */
-#define R15_CD6        0x15	/* Call divider byte 6 */
-#define R16_CD7        0x16	/* Call divider byte 7 */
-#define R17_PD1        0x17	/* Power-down byte 1 */
-#define R18_PD2        0x18	/* Power-down byte 2 */
-#define R19_XTOUT      0x19	/* XTOUT byte */
-#define R1A_IF1        0x1a	/* IF byte 1 */
-#define R1B_IF2        0x1b	/* IF byte 2 */
-#define R1C_AGC2B      0x1c	/* AGC2b byte */
-#define R1D_PSM2       0x1d	/* PSM byte 2 */
-#define R1E_PSM3       0x1e	/* PSM byte 3 */
-#define R1F_PSM4       0x1f	/* PSM byte 4 */
-#define R20_AGC11      0x20	/* AGC1 byte 1 */
-#define R21_AGC12      0x21	/* AGC1 byte 2 */
-#define R22_AGC13      0x22	/* AGC1 byte 3 */
-#define R23_AGC21      0x23	/* AGC2 byte 1 */
-#define R24_AGC22      0x24	/* AGC2 byte 2 */
-#define R25_AAGC       0x25	/* Analog AGC byte */
-#define R26_RC         0x26	/* RC byte */
-#define R27_RSSI       0x27	/* RSSI byte */
-#define R28_IRCAL1     0x28	/* IR CAL byte 1 */
-#define R29_IRCAL2     0x29	/* IR CAL byte 2 */
-#define R2A_IRCAL3     0x2a	/* IR CAL byte 3 */
-#define R2B_IRCAL4     0x2b	/* IR CAL byte 4 */
-#define R2C_RFCAL1     0x2c	/* RF CAL byte 1 */
-#define R2D_RFCAL2     0x2d	/* RF CAL byte 2 */
-#define R2E_RFCAL3     0x2e	/* RF CAL byte 3 */
-#define R2F_RFCAL4     0x2f	/* RF CAL byte 4 */
-#define R30_RFCAL5     0x30	/* RF CAL byte 5 */
-#define R31_RFCAL6     0x31	/* RF CAL byte 6 */
-#define R32_RFCAL7     0x32	/* RF CAL byte 7 */
-#define R33_RFCAL8     0x33	/* RF CAL byte 8 */
-#define R34_RFCAL9     0x34	/* RF CAL byte 9 */
-#define R35_RFCAL10    0x35	/* RF CAL byte 10 */
-#define R36_RFCALRAM1  0x36	/* RF CAL RAM byte 1 */
-#define R37_RFCALRAM2  0x37	/* RF CAL RAM byte 2 */
-#define R38_MARGIN     0x38	/* Margin byte */
-#define R39_FMAX1      0x39	/* Fmax byte 1 */
-#define R3A_FMAX2      0x3a	/* Fmax byte 2 */
-
-#define TDA18218_NUM_REGS 59
-
-struct tda18218_priv {
-	struct tda18218_config *cfg;
-	struct i2c_adapter *i2c;
-
-	u32 if_frequency;
-
-	u8 regs[TDA18218_NUM_REGS];
-};
-
-#endif
diff --git a/drivers/media/common/tuners/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c
deleted file mode 100644
index 39c6457..0000000
--- a/drivers/media/common/tuners/tda18271-common.c
+++ /dev/null
@@ -1,703 +0,0 @@
-/*
-    tda18271-common.c - driver for the Philips / NXP TDA18271 silicon tuner
-
-    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "tda18271-priv.h"
-
-static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	enum tda18271_i2c_gate gate;
-	int ret = 0;
-
-	switch (priv->gate) {
-	case TDA18271_GATE_DIGITAL:
-	case TDA18271_GATE_ANALOG:
-		gate = priv->gate;
-		break;
-	case TDA18271_GATE_AUTO:
-	default:
-		switch (priv->mode) {
-		case TDA18271_DIGITAL:
-			gate = TDA18271_GATE_DIGITAL;
-			break;
-		case TDA18271_ANALOG:
-		default:
-			gate = TDA18271_GATE_ANALOG;
-			break;
-		}
-	}
-
-	switch (gate) {
-	case TDA18271_GATE_ANALOG:
-		if (fe->ops.analog_ops.i2c_gate_ctrl)
-			ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable);
-		break;
-	case TDA18271_GATE_DIGITAL:
-		if (fe->ops.i2c_gate_ctrl)
-			ret = fe->ops.i2c_gate_ctrl(fe, enable);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-
-	return ret;
-};
-
-/*---------------------------------------------------------------------*/
-
-static void tda18271_dump_regs(struct dvb_frontend *fe, int extended)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-
-	tda_reg("=== TDA18271 REG DUMP ===\n");
-	tda_reg("ID_BYTE            = 0x%02x\n", 0xff & regs[R_ID]);
-	tda_reg("THERMO_BYTE        = 0x%02x\n", 0xff & regs[R_TM]);
-	tda_reg("POWER_LEVEL_BYTE   = 0x%02x\n", 0xff & regs[R_PL]);
-	tda_reg("EASY_PROG_BYTE_1   = 0x%02x\n", 0xff & regs[R_EP1]);
-	tda_reg("EASY_PROG_BYTE_2   = 0x%02x\n", 0xff & regs[R_EP2]);
-	tda_reg("EASY_PROG_BYTE_3   = 0x%02x\n", 0xff & regs[R_EP3]);
-	tda_reg("EASY_PROG_BYTE_4   = 0x%02x\n", 0xff & regs[R_EP4]);
-	tda_reg("EASY_PROG_BYTE_5   = 0x%02x\n", 0xff & regs[R_EP5]);
-	tda_reg("CAL_POST_DIV_BYTE  = 0x%02x\n", 0xff & regs[R_CPD]);
-	tda_reg("CAL_DIV_BYTE_1     = 0x%02x\n", 0xff & regs[R_CD1]);
-	tda_reg("CAL_DIV_BYTE_2     = 0x%02x\n", 0xff & regs[R_CD2]);
-	tda_reg("CAL_DIV_BYTE_3     = 0x%02x\n", 0xff & regs[R_CD3]);
-	tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]);
-	tda_reg("MAIN_DIV_BYTE_1    = 0x%02x\n", 0xff & regs[R_MD1]);
-	tda_reg("MAIN_DIV_BYTE_2    = 0x%02x\n", 0xff & regs[R_MD2]);
-	tda_reg("MAIN_DIV_BYTE_3    = 0x%02x\n", 0xff & regs[R_MD3]);
-
-	/* only dump extended regs if DBG_ADV is set */
-	if (!(tda18271_debug & DBG_ADV))
-		return;
-
-	/* W indicates write-only registers.
-	 * Register dump for write-only registers shows last value written. */
-
-	tda_reg("EXTENDED_BYTE_1    = 0x%02x\n", 0xff & regs[R_EB1]);
-	tda_reg("EXTENDED_BYTE_2    = 0x%02x\n", 0xff & regs[R_EB2]);
-	tda_reg("EXTENDED_BYTE_3    = 0x%02x\n", 0xff & regs[R_EB3]);
-	tda_reg("EXTENDED_BYTE_4    = 0x%02x\n", 0xff & regs[R_EB4]);
-	tda_reg("EXTENDED_BYTE_5    = 0x%02x\n", 0xff & regs[R_EB5]);
-	tda_reg("EXTENDED_BYTE_6    = 0x%02x\n", 0xff & regs[R_EB6]);
-	tda_reg("EXTENDED_BYTE_7    = 0x%02x\n", 0xff & regs[R_EB7]);
-	tda_reg("EXTENDED_BYTE_8    = 0x%02x\n", 0xff & regs[R_EB8]);
-	tda_reg("EXTENDED_BYTE_9  W = 0x%02x\n", 0xff & regs[R_EB9]);
-	tda_reg("EXTENDED_BYTE_10   = 0x%02x\n", 0xff & regs[R_EB10]);
-	tda_reg("EXTENDED_BYTE_11   = 0x%02x\n", 0xff & regs[R_EB11]);
-	tda_reg("EXTENDED_BYTE_12   = 0x%02x\n", 0xff & regs[R_EB12]);
-	tda_reg("EXTENDED_BYTE_13   = 0x%02x\n", 0xff & regs[R_EB13]);
-	tda_reg("EXTENDED_BYTE_14   = 0x%02x\n", 0xff & regs[R_EB14]);
-	tda_reg("EXTENDED_BYTE_15   = 0x%02x\n", 0xff & regs[R_EB15]);
-	tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]);
-	tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]);
-	tda_reg("EXTENDED_BYTE_18   = 0x%02x\n", 0xff & regs[R_EB18]);
-	tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]);
-	tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]);
-	tda_reg("EXTENDED_BYTE_21   = 0x%02x\n", 0xff & regs[R_EB21]);
-	tda_reg("EXTENDED_BYTE_22   = 0x%02x\n", 0xff & regs[R_EB22]);
-	tda_reg("EXTENDED_BYTE_23   = 0x%02x\n", 0xff & regs[R_EB23]);
-}
-
-int tda18271_read_regs(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	unsigned char buf = 0x00;
-	int ret;
-	struct i2c_msg msg[] = {
-		{ .addr = priv->i2c_props.addr, .flags = 0,
-		  .buf = &buf, .len = 1 },
-		{ .addr = priv->i2c_props.addr, .flags = I2C_M_RD,
-		  .buf = regs, .len = 16 }
-	};
-
-	tda18271_i2c_gate_ctrl(fe, 1);
-
-	/* read all registers */
-	ret = i2c_transfer(priv->i2c_props.adap, msg, 2);
-
-	tda18271_i2c_gate_ctrl(fe, 0);
-
-	if (ret != 2)
-		tda_err("ERROR: i2c_transfer returned: %d\n", ret);
-
-	if (tda18271_debug & DBG_REG)
-		tda18271_dump_regs(fe, 0);
-
-	return (ret == 2 ? 0 : ret);
-}
-
-int tda18271_read_extended(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	unsigned char regdump[TDA18271_NUM_REGS];
-	unsigned char buf = 0x00;
-	int ret, i;
-	struct i2c_msg msg[] = {
-		{ .addr = priv->i2c_props.addr, .flags = 0,
-		  .buf = &buf, .len = 1 },
-		{ .addr = priv->i2c_props.addr, .flags = I2C_M_RD,
-		  .buf = regdump, .len = TDA18271_NUM_REGS }
-	};
-
-	tda18271_i2c_gate_ctrl(fe, 1);
-
-	/* read all registers */
-	ret = i2c_transfer(priv->i2c_props.adap, msg, 2);
-
-	tda18271_i2c_gate_ctrl(fe, 0);
-
-	if (ret != 2)
-		tda_err("ERROR: i2c_transfer returned: %d\n", ret);
-
-	for (i = 0; i < TDA18271_NUM_REGS; i++) {
-		/* don't update write-only registers */
-		if ((i != R_EB9)  &&
-		    (i != R_EB16) &&
-		    (i != R_EB17) &&
-		    (i != R_EB19) &&
-		    (i != R_EB20))
-		regs[i] = regdump[i];
-	}
-
-	if (tda18271_debug & DBG_REG)
-		tda18271_dump_regs(fe, 1);
-
-	return (ret == 2 ? 0 : ret);
-}
-
-int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	unsigned char buf[TDA18271_NUM_REGS + 1];
-	struct i2c_msg msg = { .addr = priv->i2c_props.addr, .flags = 0,
-			       .buf = buf };
-	int i, ret = 1, max;
-
-	BUG_ON((len == 0) || (idx + len > sizeof(buf)));
-
-
-	switch (priv->small_i2c) {
-	case TDA18271_03_BYTE_CHUNK_INIT:
-		max = 3;
-		break;
-	case TDA18271_08_BYTE_CHUNK_INIT:
-		max = 8;
-		break;
-	case TDA18271_16_BYTE_CHUNK_INIT:
-		max = 16;
-		break;
-	case TDA18271_39_BYTE_CHUNK_INIT:
-	default:
-		max = 39;
-	}
-
-	tda18271_i2c_gate_ctrl(fe, 1);
-	while (len) {
-		if (max > len)
-			max = len;
-
-		buf[0] = idx;
-		for (i = 1; i <= max; i++)
-			buf[i] = regs[idx - 1 + i];
-
-		msg.len = max + 1;
-
-		/* write registers */
-		ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
-		if (ret != 1)
-			break;
-
-		idx += max;
-		len -= max;
-	}
-	tda18271_i2c_gate_ctrl(fe, 0);
-
-	if (ret != 1)
-		tda_err("ERROR: idx = 0x%x, len = %d, "
-			"i2c_transfer returned: %d\n", idx, max, ret);
-
-	return (ret == 1 ? 0 : ret);
-}
-
-/*---------------------------------------------------------------------*/
-
-int tda18271_charge_pump_source(struct dvb_frontend *fe,
-				enum tda18271_pll pll, int force)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-
-	int r_cp = (pll == TDA18271_CAL_PLL) ? R_EB7 : R_EB4;
-
-	regs[r_cp] &= ~0x20;
-	regs[r_cp] |= ((force & 1) << 5);
-
-	return tda18271_write_regs(fe, r_cp, 1);
-}
-
-int tda18271_init_regs(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-
-	tda_dbg("initializing registers for device @ %d-%04x\n",
-		i2c_adapter_id(priv->i2c_props.adap),
-		priv->i2c_props.addr);
-
-	/* initialize registers */
-	switch (priv->id) {
-	case TDA18271HDC1:
-		regs[R_ID]   = 0x83;
-		break;
-	case TDA18271HDC2:
-		regs[R_ID]   = 0x84;
-		break;
-	};
-
-	regs[R_TM]   = 0x08;
-	regs[R_PL]   = 0x80;
-	regs[R_EP1]  = 0xc6;
-	regs[R_EP2]  = 0xdf;
-	regs[R_EP3]  = 0x16;
-	regs[R_EP4]  = 0x60;
-	regs[R_EP5]  = 0x80;
-	regs[R_CPD]  = 0x80;
-	regs[R_CD1]  = 0x00;
-	regs[R_CD2]  = 0x00;
-	regs[R_CD3]  = 0x00;
-	regs[R_MPD]  = 0x00;
-	regs[R_MD1]  = 0x00;
-	regs[R_MD2]  = 0x00;
-	regs[R_MD3]  = 0x00;
-
-	switch (priv->id) {
-	case TDA18271HDC1:
-		regs[R_EB1]  = 0xff;
-		break;
-	case TDA18271HDC2:
-		regs[R_EB1]  = 0xfc;
-		break;
-	};
-
-	regs[R_EB2]  = 0x01;
-	regs[R_EB3]  = 0x84;
-	regs[R_EB4]  = 0x41;
-	regs[R_EB5]  = 0x01;
-	regs[R_EB6]  = 0x84;
-	regs[R_EB7]  = 0x40;
-	regs[R_EB8]  = 0x07;
-	regs[R_EB9]  = 0x00;
-	regs[R_EB10] = 0x00;
-	regs[R_EB11] = 0x96;
-
-	switch (priv->id) {
-	case TDA18271HDC1:
-		regs[R_EB12] = 0x0f;
-		break;
-	case TDA18271HDC2:
-		regs[R_EB12] = 0x33;
-		break;
-	};
-
-	regs[R_EB13] = 0xc1;
-	regs[R_EB14] = 0x00;
-	regs[R_EB15] = 0x8f;
-	regs[R_EB16] = 0x00;
-	regs[R_EB17] = 0x00;
-
-	switch (priv->id) {
-	case TDA18271HDC1:
-		regs[R_EB18] = 0x00;
-		break;
-	case TDA18271HDC2:
-		regs[R_EB18] = 0x8c;
-		break;
-	};
-
-	regs[R_EB19] = 0x00;
-	regs[R_EB20] = 0x20;
-
-	switch (priv->id) {
-	case TDA18271HDC1:
-		regs[R_EB21] = 0x33;
-		break;
-	case TDA18271HDC2:
-		regs[R_EB21] = 0xb3;
-		break;
-	};
-
-	regs[R_EB22] = 0x48;
-	regs[R_EB23] = 0xb0;
-
-	tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
-
-	/* setup agc1 gain */
-	regs[R_EB17] = 0x00;
-	tda18271_write_regs(fe, R_EB17, 1);
-	regs[R_EB17] = 0x03;
-	tda18271_write_regs(fe, R_EB17, 1);
-	regs[R_EB17] = 0x43;
-	tda18271_write_regs(fe, R_EB17, 1);
-	regs[R_EB17] = 0x4c;
-	tda18271_write_regs(fe, R_EB17, 1);
-
-	/* setup agc2 gain */
-	if ((priv->id) == TDA18271HDC1) {
-		regs[R_EB20] = 0xa0;
-		tda18271_write_regs(fe, R_EB20, 1);
-		regs[R_EB20] = 0xa7;
-		tda18271_write_regs(fe, R_EB20, 1);
-		regs[R_EB20] = 0xe7;
-		tda18271_write_regs(fe, R_EB20, 1);
-		regs[R_EB20] = 0xec;
-		tda18271_write_regs(fe, R_EB20, 1);
-	}
-
-	/* image rejection calibration */
-
-	/* low-band */
-	regs[R_EP3] = 0x1f;
-	regs[R_EP4] = 0x66;
-	regs[R_EP5] = 0x81;
-	regs[R_CPD] = 0xcc;
-	regs[R_CD1] = 0x6c;
-	regs[R_CD2] = 0x00;
-	regs[R_CD3] = 0x00;
-	regs[R_MPD] = 0xcd;
-	regs[R_MD1] = 0x77;
-	regs[R_MD2] = 0x08;
-	regs[R_MD3] = 0x00;
-
-	tda18271_write_regs(fe, R_EP3, 11);
-
-	if ((priv->id) == TDA18271HDC2) {
-		/* main pll cp source on */
-		tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1);
-		msleep(1);
-
-		/* main pll cp source off */
-		tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0);
-	}
-
-	msleep(5); /* pll locking */
-
-	/* launch detector */
-	tda18271_write_regs(fe, R_EP1, 1);
-	msleep(5); /* wanted low measurement */
-
-	regs[R_EP5] = 0x85;
-	regs[R_CPD] = 0xcb;
-	regs[R_CD1] = 0x66;
-	regs[R_CD2] = 0x70;
-
-	tda18271_write_regs(fe, R_EP3, 7);
-	msleep(5); /* pll locking */
-
-	/* launch optimization algorithm */
-	tda18271_write_regs(fe, R_EP2, 1);
-	msleep(30); /* image low optimization completion */
-
-	/* mid-band */
-	regs[R_EP5] = 0x82;
-	regs[R_CPD] = 0xa8;
-	regs[R_CD2] = 0x00;
-	regs[R_MPD] = 0xa9;
-	regs[R_MD1] = 0x73;
-	regs[R_MD2] = 0x1a;
-
-	tda18271_write_regs(fe, R_EP3, 11);
-	msleep(5); /* pll locking */
-
-	/* launch detector */
-	tda18271_write_regs(fe, R_EP1, 1);
-	msleep(5); /* wanted mid measurement */
-
-	regs[R_EP5] = 0x86;
-	regs[R_CPD] = 0xa8;
-	regs[R_CD1] = 0x66;
-	regs[R_CD2] = 0xa0;
-
-	tda18271_write_regs(fe, R_EP3, 7);
-	msleep(5); /* pll locking */
-
-	/* launch optimization algorithm */
-	tda18271_write_regs(fe, R_EP2, 1);
-	msleep(30); /* image mid optimization completion */
-
-	/* high-band */
-	regs[R_EP5] = 0x83;
-	regs[R_CPD] = 0x98;
-	regs[R_CD1] = 0x65;
-	regs[R_CD2] = 0x00;
-	regs[R_MPD] = 0x99;
-	regs[R_MD1] = 0x71;
-	regs[R_MD2] = 0xcd;
-
-	tda18271_write_regs(fe, R_EP3, 11);
-	msleep(5); /* pll locking */
-
-	/* launch detector */
-	tda18271_write_regs(fe, R_EP1, 1);
-	msleep(5); /* wanted high measurement */
-
-	regs[R_EP5] = 0x87;
-	regs[R_CD1] = 0x65;
-	regs[R_CD2] = 0x50;
-
-	tda18271_write_regs(fe, R_EP3, 7);
-	msleep(5); /* pll locking */
-
-	/* launch optimization algorithm */
-	tda18271_write_regs(fe, R_EP2, 1);
-	msleep(30); /* image high optimization completion */
-
-	/* return to normal mode */
-	regs[R_EP4] = 0x64;
-	tda18271_write_regs(fe, R_EP4, 1);
-
-	/* synchronize */
-	tda18271_write_regs(fe, R_EP1, 1);
-
-	return 0;
-}
-
-/*---------------------------------------------------------------------*/
-
-/*
- *  Standby modes, EP3 [7:5]
- *
- *  | SM  || SM_LT || SM_XT || mode description
- *  |=====\\=======\\=======\\===================================
- *  |  0  ||   0   ||   0   || normal mode
- *  |-----||-------||-------||-----------------------------------
- *  |     ||       ||       || standby mode w/ slave tuner output
- *  |  1  ||   0   ||   0   || & loop thru & xtal oscillator on
- *  |-----||-------||-------||-----------------------------------
- *  |  1  ||   1   ||   0   || standby mode w/ xtal oscillator on
- *  |-----||-------||-------||-----------------------------------
- *  |  1  ||   1   ||   1   || power off
- *
- */
-
-int tda18271_set_standby_mode(struct dvb_frontend *fe,
-			      int sm, int sm_lt, int sm_xt)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-
-	if (tda18271_debug & DBG_ADV)
-		tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt);
-
-	regs[R_EP3]  &= ~0xe0; /* clear sm, sm_lt, sm_xt */
-	regs[R_EP3]  |= (sm    ? (1 << 7) : 0) |
-			(sm_lt ? (1 << 6) : 0) |
-			(sm_xt ? (1 << 5) : 0);
-
-	return tda18271_write_regs(fe, R_EP3, 1);
-}
-
-/*---------------------------------------------------------------------*/
-
-int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq)
-{
-	/* sets main post divider & divider bytes, but does not write them */
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	u8 d, pd;
-	u32 div;
-
-	int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d);
-	if (tda_fail(ret))
-		goto fail;
-
-	regs[R_MPD]   = (0x7f & pd);
-
-	div =  ((d * (freq / 1000)) << 7) / 125;
-
-	regs[R_MD1]   = 0x7f & (div >> 16);
-	regs[R_MD2]   = 0xff & (div >> 8);
-	regs[R_MD3]   = 0xff & div;
-fail:
-	return ret;
-}
-
-int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq)
-{
-	/* sets cal post divider & divider bytes, but does not write them */
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	u8 d, pd;
-	u32 div;
-
-	int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d);
-	if (tda_fail(ret))
-		goto fail;
-
-	regs[R_CPD]   = pd;
-
-	div =  ((d * (freq / 1000)) << 7) / 125;
-
-	regs[R_CD1]   = 0x7f & (div >> 16);
-	regs[R_CD2]   = 0xff & (div >> 8);
-	regs[R_CD3]   = 0xff & div;
-fail:
-	return ret;
-}
-
-/*---------------------------------------------------------------------*/
-
-int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq)
-{
-	/* sets bp filter bits, but does not write them */
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	u8 val;
-
-	int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val);
-	if (tda_fail(ret))
-		goto fail;
-
-	regs[R_EP1]  &= ~0x07; /* clear bp filter bits */
-	regs[R_EP1]  |= (0x07 & val);
-fail:
-	return ret;
-}
-
-int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq)
-{
-	/* sets K & M bits, but does not write them */
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	u8 val;
-
-	int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val);
-	if (tda_fail(ret))
-		goto fail;
-
-	regs[R_EB13] &= ~0x7c; /* clear k & m bits */
-	regs[R_EB13] |= (0x7c & val);
-fail:
-	return ret;
-}
-
-int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq)
-{
-	/* sets rf band bits, but does not write them */
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	u8 val;
-
-	int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val);
-	if (tda_fail(ret))
-		goto fail;
-
-	regs[R_EP2]  &= ~0xe0; /* clear rf band bits */
-	regs[R_EP2]  |= (0xe0 & (val << 5));
-fail:
-	return ret;
-}
-
-int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq)
-{
-	/* sets gain taper bits, but does not write them */
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	u8 val;
-
-	int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val);
-	if (tda_fail(ret))
-		goto fail;
-
-	regs[R_EP2]  &= ~0x1f; /* clear gain taper bits */
-	regs[R_EP2]  |= (0x1f & val);
-fail:
-	return ret;
-}
-
-int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq)
-{
-	/* sets IR Meas bits, but does not write them */
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	u8 val;
-
-	int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val);
-	if (tda_fail(ret))
-		goto fail;
-
-	regs[R_EP5] &= ~0x07;
-	regs[R_EP5] |= (0x07 & val);
-fail:
-	return ret;
-}
-
-int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq)
-{
-	/* sets rf cal byte (RFC_Cprog), but does not write it */
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	u8 val;
-
-	int ret = tda18271_lookup_map(fe, RF_CAL, freq, &val);
-	/* The TDA18271HD/C1 rf_cal map lookup is expected to go out of range
-	 * for frequencies above 61.1 MHz.  In these cases, the internal RF
-	 * tracking filters calibration mechanism is used.
-	 *
-	 * There is no need to warn the user about this.
-	 */
-	if (ret < 0)
-		goto fail;
-
-	regs[R_EB14] = val;
-fail:
-	return ret;
-}
-
-int _tda_printk(struct tda18271_priv *state, const char *level,
-		const char *func, const char *fmt, ...)
-{
-	struct va_format vaf;
-	va_list args;
-	int rtn;
-
-	va_start(args, fmt);
-
-	vaf.fmt = fmt;
-	vaf.va = &args;
-
-	if (state)
-		rtn = printk("%s%s: [%d-%04x|%c] %pV",
-			     level, func, i2c_adapter_id(state->i2c_props.adap),
-			     state->i2c_props.addr,
-			     (state->role == TDA18271_MASTER) ? 'M' : 'S',
-			     &vaf);
-	else
-		rtn = printk("%s%s: %pV", level, func, &vaf);
-
-	va_end(args);
-
-	return rtn;
-}
diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c
deleted file mode 100644
index 2e67f44..0000000
--- a/drivers/media/common/tuners/tda18271-fe.c
+++ /dev/null
@@ -1,1345 +0,0 @@
-/*
-    tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner
-
-    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/delay.h>
-#include <linux/videodev2.h>
-#include "tda18271-priv.h"
-
-int tda18271_debug;
-module_param_named(debug, tda18271_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debug level "
-		 "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))");
-
-static int tda18271_cal_on_startup = -1;
-module_param_named(cal, tda18271_cal_on_startup, int, 0644);
-MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup");
-
-static DEFINE_MUTEX(tda18271_list_mutex);
-static LIST_HEAD(hybrid_tuner_instance_list);
-
-/*---------------------------------------------------------------------*/
-
-static int tda18271_toggle_output(struct dvb_frontend *fe, int standby)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-
-	int ret = tda18271_set_standby_mode(fe, standby ? 1 : 0,
-			priv->output_opt & TDA18271_OUTPUT_LT_OFF ? 1 : 0,
-			priv->output_opt & TDA18271_OUTPUT_XT_OFF ? 1 : 0);
-
-	if (tda_fail(ret))
-		goto fail;
-
-	tda_dbg("%s mode: xtal oscillator %s, slave tuner loop thru %s\n",
-		standby ? "standby" : "active",
-		priv->output_opt & TDA18271_OUTPUT_XT_OFF ? "off" : "on",
-		priv->output_opt & TDA18271_OUTPUT_LT_OFF ? "off" : "on");
-fail:
-	return ret;
-}
-
-/*---------------------------------------------------------------------*/
-
-static inline int charge_pump_source(struct dvb_frontend *fe, int force)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	return tda18271_charge_pump_source(fe,
-					   (priv->role == TDA18271_SLAVE) ?
-					   TDA18271_CAL_PLL :
-					   TDA18271_MAIN_PLL, force);
-}
-
-static inline void tda18271_set_if_notch(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-
-	switch (priv->mode) {
-	case TDA18271_ANALOG:
-		regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
-		break;
-	case TDA18271_DIGITAL:
-		regs[R_MPD]  |= 0x80; /* IF notch = 1 */
-		break;
-	}
-}
-
-static int tda18271_channel_configuration(struct dvb_frontend *fe,
-					  struct tda18271_std_map_item *map,
-					  u32 freq, u32 bw)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	int ret;
-	u32 N;
-
-	/* update TV broadcast parameters */
-
-	/* set standard */
-	regs[R_EP3]  &= ~0x1f; /* clear std bits */
-	regs[R_EP3]  |= (map->agc_mode << 3) | map->std;
-
-	if (priv->id == TDA18271HDC2) {
-		/* set rfagc to high speed mode */
-		regs[R_EP3] &= ~0x04;
-	}
-
-	/* set cal mode to normal */
-	regs[R_EP4]  &= ~0x03;
-
-	/* update IF output level */
-	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
-	regs[R_EP4]  |= (map->if_lvl << 2);
-
-	/* update FM_RFn */
-	regs[R_EP4]  &= ~0x80;
-	regs[R_EP4]  |= map->fm_rfn << 7;
-
-	/* update rf top / if top */
-	regs[R_EB22]  = 0x00;
-	regs[R_EB22] |= map->rfagc_top;
-	ret = tda18271_write_regs(fe, R_EB22, 1);
-	if (tda_fail(ret))
-		goto fail;
-
-	/* --------------------------------------------------------------- */
-
-	/* disable Power Level Indicator */
-	regs[R_EP1]  |= 0x40;
-
-	/* make sure thermometer is off */
-	regs[R_TM]   &= ~0x10;
-
-	/* frequency dependent parameters */
-
-	tda18271_calc_ir_measure(fe, &freq);
-
-	tda18271_calc_bp_filter(fe, &freq);
-
-	tda18271_calc_rf_band(fe, &freq);
-
-	tda18271_calc_gain_taper(fe, &freq);
-
-	/* --------------------------------------------------------------- */
-
-	/* dual tuner and agc1 extra configuration */
-
-	switch (priv->role) {
-	case TDA18271_MASTER:
-		regs[R_EB1]  |= 0x04; /* main vco */
-		break;
-	case TDA18271_SLAVE:
-		regs[R_EB1]  &= ~0x04; /* cal vco */
-		break;
-	}
-
-	/* agc1 always active */
-	regs[R_EB1]  &= ~0x02;
-
-	/* agc1 has priority on agc2 */
-	regs[R_EB1]  &= ~0x01;
-
-	ret = tda18271_write_regs(fe, R_EB1, 1);
-	if (tda_fail(ret))
-		goto fail;
-
-	/* --------------------------------------------------------------- */
-
-	N = map->if_freq * 1000 + freq;
-
-	switch (priv->role) {
-	case TDA18271_MASTER:
-		tda18271_calc_main_pll(fe, N);
-		tda18271_set_if_notch(fe);
-		tda18271_write_regs(fe, R_MPD, 4);
-		break;
-	case TDA18271_SLAVE:
-		tda18271_calc_cal_pll(fe, N);
-		tda18271_write_regs(fe, R_CPD, 4);
-
-		regs[R_MPD] = regs[R_CPD] & 0x7f;
-		tda18271_set_if_notch(fe);
-		tda18271_write_regs(fe, R_MPD, 1);
-		break;
-	}
-
-	ret = tda18271_write_regs(fe, R_TM, 7);
-	if (tda_fail(ret))
-		goto fail;
-
-	/* force charge pump source */
-	charge_pump_source(fe, 1);
-
-	msleep(1);
-
-	/* return pll to normal operation */
-	charge_pump_source(fe, 0);
-
-	msleep(20);
-
-	if (priv->id == TDA18271HDC2) {
-		/* set rfagc to normal speed mode */
-		if (map->fm_rfn)
-			regs[R_EP3] &= ~0x04;
-		else
-			regs[R_EP3] |= 0x04;
-		ret = tda18271_write_regs(fe, R_EP3, 1);
-	}
-fail:
-	return ret;
-}
-
-static int tda18271_read_thermometer(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	int tm;
-
-	/* switch thermometer on */
-	regs[R_TM]   |= 0x10;
-	tda18271_write_regs(fe, R_TM, 1);
-
-	/* read thermometer info */
-	tda18271_read_regs(fe);
-
-	if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) ||
-	    (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) {
-
-		if ((regs[R_TM] & 0x20) == 0x20)
-			regs[R_TM] &= ~0x20;
-		else
-			regs[R_TM] |= 0x20;
-
-		tda18271_write_regs(fe, R_TM, 1);
-
-		msleep(10); /* temperature sensing */
-
-		/* read thermometer info */
-		tda18271_read_regs(fe);
-	}
-
-	tm = tda18271_lookup_thermometer(fe);
-
-	/* switch thermometer off */
-	regs[R_TM]   &= ~0x10;
-	tda18271_write_regs(fe, R_TM, 1);
-
-	/* set CAL mode to normal */
-	regs[R_EP4]  &= ~0x03;
-	tda18271_write_regs(fe, R_EP4, 1);
-
-	return tm;
-}
-
-/* ------------------------------------------------------------------ */
-
-static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe,
-						     u32 freq)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
-	unsigned char *regs = priv->tda18271_regs;
-	int i, ret;
-	u8 tm_current, dc_over_dt, rf_tab;
-	s32 rfcal_comp, approx;
-
-	/* power up */
-	ret = tda18271_set_standby_mode(fe, 0, 0, 0);
-	if (tda_fail(ret))
-		goto fail;
-
-	/* read die current temperature */
-	tm_current = tda18271_read_thermometer(fe);
-
-	/* frequency dependent parameters */
-
-	tda18271_calc_rf_cal(fe, &freq);
-	rf_tab = regs[R_EB14];
-
-	i = tda18271_lookup_rf_band(fe, &freq, NULL);
-	if (tda_fail(i))
-		return i;
-
-	if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) {
-		approx = map[i].rf_a1 * (s32)(freq / 1000 - map[i].rf1) +
-			map[i].rf_b1 + rf_tab;
-	} else {
-		approx = map[i].rf_a2 * (s32)(freq / 1000 - map[i].rf2) +
-			map[i].rf_b2 + rf_tab;
-	}
-
-	if (approx < 0)
-		approx = 0;
-	if (approx > 255)
-		approx = 255;
-
-	tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt);
-
-	/* calculate temperature compensation */
-	rfcal_comp = dc_over_dt * (s32)(tm_current - priv->tm_rfcal) / 1000;
-
-	regs[R_EB14] = (unsigned char)(approx + rfcal_comp);
-	ret = tda18271_write_regs(fe, R_EB14, 1);
-fail:
-	return ret;
-}
-
-static int tda18271_por(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	int ret;
-
-	/* power up detector 1 */
-	regs[R_EB12] &= ~0x20;
-	ret = tda18271_write_regs(fe, R_EB12, 1);
-	if (tda_fail(ret))
-		goto fail;
-
-	regs[R_EB18] &= ~0x80; /* turn agc1 loop on */
-	regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
-	ret = tda18271_write_regs(fe, R_EB18, 1);
-	if (tda_fail(ret))
-		goto fail;
-
-	regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */
-
-	/* POR mode */
-	ret = tda18271_set_standby_mode(fe, 1, 0, 0);
-	if (tda_fail(ret))
-		goto fail;
-
-	/* disable 1.5 MHz low pass filter */
-	regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */
-	regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */
-	ret = tda18271_write_regs(fe, R_EB21, 3);
-fail:
-	return ret;
-}
-
-static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	u32 N;
-
-	/* set CAL mode to normal */
-	regs[R_EP4]  &= ~0x03;
-	tda18271_write_regs(fe, R_EP4, 1);
-
-	/* switch off agc1 */
-	regs[R_EP3]  |= 0x40; /* sm_lt = 1 */
-
-	regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */
-	tda18271_write_regs(fe, R_EB18, 1);
-
-	/* frequency dependent parameters */
-
-	tda18271_calc_bp_filter(fe, &freq);
-	tda18271_calc_gain_taper(fe, &freq);
-	tda18271_calc_rf_band(fe, &freq);
-	tda18271_calc_km(fe, &freq);
-
-	tda18271_write_regs(fe, R_EP1, 3);
-	tda18271_write_regs(fe, R_EB13, 1);
-
-	/* main pll charge pump source */
-	tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1);
-
-	/* cal pll charge pump source */
-	tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 1);
-
-	/* force dcdc converter to 0 V */
-	regs[R_EB14] = 0x00;
-	tda18271_write_regs(fe, R_EB14, 1);
-
-	/* disable plls lock */
-	regs[R_EB20] &= ~0x20;
-	tda18271_write_regs(fe, R_EB20, 1);
-
-	/* set CAL mode to RF tracking filter calibration */
-	regs[R_EP4]  |= 0x03;
-	tda18271_write_regs(fe, R_EP4, 2);
-
-	/* --------------------------------------------------------------- */
-
-	/* set the internal calibration signal */
-	N = freq;
-
-	tda18271_calc_cal_pll(fe, N);
-	tda18271_write_regs(fe, R_CPD, 4);
-
-	/* downconvert internal calibration */
-	N += 1000000;
-
-	tda18271_calc_main_pll(fe, N);
-	tda18271_write_regs(fe, R_MPD, 4);
-
-	msleep(5);
-
-	tda18271_write_regs(fe, R_EP2, 1);
-	tda18271_write_regs(fe, R_EP1, 1);
-	tda18271_write_regs(fe, R_EP2, 1);
-	tda18271_write_regs(fe, R_EP1, 1);
-
-	/* --------------------------------------------------------------- */
-
-	/* normal operation for the main pll */
-	tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0);
-
-	/* normal operation for the cal pll  */
-	tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 0);
-
-	msleep(10); /* plls locking */
-
-	/* launch the rf tracking filters calibration */
-	regs[R_EB20]  |= 0x20;
-	tda18271_write_regs(fe, R_EB20, 1);
-
-	msleep(60); /* calibration */
-
-	/* --------------------------------------------------------------- */
-
-	/* set CAL mode to normal */
-	regs[R_EP4]  &= ~0x03;
-
-	/* switch on agc1 */
-	regs[R_EP3]  &= ~0x40; /* sm_lt = 0 */
-
-	regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
-	tda18271_write_regs(fe, R_EB18, 1);
-
-	tda18271_write_regs(fe, R_EP3, 2);
-
-	/* synchronization */
-	tda18271_write_regs(fe, R_EP1, 1);
-
-	/* get calibration result */
-	tda18271_read_extended(fe);
-
-	return regs[R_EB14];
-}
-
-static int tda18271_powerscan(struct dvb_frontend *fe,
-			      u32 *freq_in, u32 *freq_out)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	int sgn, bcal, count, wait, ret;
-	u8 cid_target;
-	u16 count_limit;
-	u32 freq;
-
-	freq = *freq_in;
-
-	tda18271_calc_rf_band(fe, &freq);
-	tda18271_calc_rf_cal(fe, &freq);
-	tda18271_calc_gain_taper(fe, &freq);
-	tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit);
-
-	tda18271_write_regs(fe, R_EP2, 1);
-	tda18271_write_regs(fe, R_EB14, 1);
-
-	/* downconvert frequency */
-	freq += 1000000;
-
-	tda18271_calc_main_pll(fe, freq);
-	tda18271_write_regs(fe, R_MPD, 4);
-
-	msleep(5); /* pll locking */
-
-	/* detection mode */
-	regs[R_EP4]  &= ~0x03;
-	regs[R_EP4]  |= 0x01;
-	tda18271_write_regs(fe, R_EP4, 1);
-
-	/* launch power detection measurement */
-	tda18271_write_regs(fe, R_EP2, 1);
-
-	/* read power detection info, stored in EB10 */
-	ret = tda18271_read_extended(fe);
-	if (tda_fail(ret))
-		return ret;
-
-	/* algorithm initialization */
-	sgn = 1;
-	*freq_out = *freq_in;
-	bcal = 0;
-	count = 0;
-	wait = false;
-
-	while ((regs[R_EB10] & 0x3f) < cid_target) {
-		/* downconvert updated freq to 1 MHz */
-		freq = *freq_in + (sgn * count) + 1000000;
-
-		tda18271_calc_main_pll(fe, freq);
-		tda18271_write_regs(fe, R_MPD, 4);
-
-		if (wait) {
-			msleep(5); /* pll locking */
-			wait = false;
-		} else
-			udelay(100); /* pll locking */
-
-		/* launch power detection measurement */
-		tda18271_write_regs(fe, R_EP2, 1);
-
-		/* read power detection info, stored in EB10 */
-		ret = tda18271_read_extended(fe);
-		if (tda_fail(ret))
-			return ret;
-
-		count += 200;
-
-		if (count <= count_limit)
-			continue;
-
-		if (sgn <= 0)
-			break;
-
-		sgn = -1 * sgn;
-		count = 200;
-		wait = true;
-	}
-
-	if ((regs[R_EB10] & 0x3f) >= cid_target) {
-		bcal = 1;
-		*freq_out = freq - 1000000;
-	} else
-		bcal = 0;
-
-	tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n",
-		bcal, *freq_in, *freq_out, freq);
-
-	return bcal;
-}
-
-static int tda18271_powerscan_init(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	int ret;
-
-	/* set standard to digital */
-	regs[R_EP3]  &= ~0x1f; /* clear std bits */
-	regs[R_EP3]  |= 0x12;
-
-	/* set cal mode to normal */
-	regs[R_EP4]  &= ~0x03;
-
-	/* update IF output level */
-	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
-
-	ret = tda18271_write_regs(fe, R_EP3, 2);
-	if (tda_fail(ret))
-		goto fail;
-
-	regs[R_EB18] &= ~0x03; /* set agc1_gain to   6 dB */
-	ret = tda18271_write_regs(fe, R_EB18, 1);
-	if (tda_fail(ret))
-		goto fail;
-
-	regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */
-
-	/* 1.5 MHz low pass filter */
-	regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */
-	regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */
-
-	ret = tda18271_write_regs(fe, R_EB21, 3);
-fail:
-	return ret;
-}
-
-static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
-	unsigned char *regs = priv->tda18271_regs;
-	int bcal, rf, i;
-	s32 divisor, dividend;
-#define RF1 0
-#define RF2 1
-#define RF3 2
-	u32 rf_default[3];
-	u32 rf_freq[3];
-	s32 prog_cal[3];
-	s32 prog_tab[3];
-
-	i = tda18271_lookup_rf_band(fe, &freq, NULL);
-
-	if (tda_fail(i))
-		return i;
-
-	rf_default[RF1] = 1000 * map[i].rf1_def;
-	rf_default[RF2] = 1000 * map[i].rf2_def;
-	rf_default[RF3] = 1000 * map[i].rf3_def;
-
-	for (rf = RF1; rf <= RF3; rf++) {
-		if (0 == rf_default[rf])
-			return 0;
-		tda_cal("freq = %d, rf = %d\n", freq, rf);
-
-		/* look for optimized calibration frequency */
-		bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]);
-		if (tda_fail(bcal))
-			return bcal;
-
-		tda18271_calc_rf_cal(fe, &rf_freq[rf]);
-		prog_tab[rf] = (s32)regs[R_EB14];
-
-		if (1 == bcal)
-			prog_cal[rf] =
-				(s32)tda18271_calibrate_rf(fe, rf_freq[rf]);
-		else
-			prog_cal[rf] = prog_tab[rf];
-
-		switch (rf) {
-		case RF1:
-			map[i].rf_a1 = 0;
-			map[i].rf_b1 = (prog_cal[RF1] - prog_tab[RF1]);
-			map[i].rf1   = rf_freq[RF1] / 1000;
-			break;
-		case RF2:
-			dividend = (prog_cal[RF2] - prog_tab[RF2] -
-				    prog_cal[RF1] + prog_tab[RF1]);
-			divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000;
-			map[i].rf_a1 = (dividend / divisor);
-			map[i].rf2   = rf_freq[RF2] / 1000;
-			break;
-		case RF3:
-			dividend = (prog_cal[RF3] - prog_tab[RF3] -
-				    prog_cal[RF2] + prog_tab[RF2]);
-			divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000;
-			map[i].rf_a2 = (dividend / divisor);
-			map[i].rf_b2 = (prog_cal[RF2] - prog_tab[RF2]);
-			map[i].rf3   = rf_freq[RF3] / 1000;
-			break;
-		default:
-			BUG();
-		}
-	}
-
-	return 0;
-}
-
-static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned int i;
-	int ret;
-
-	tda_info("tda18271: performing RF tracking filter calibration\n");
-
-	/* wait for die temperature stabilization */
-	msleep(200);
-
-	ret = tda18271_powerscan_init(fe);
-	if (tda_fail(ret))
-		goto fail;
-
-	/* rf band calibration */
-	for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++) {
-		ret =
-		tda18271_rf_tracking_filters_init(fe, 1000 *
-						  priv->rf_cal_state[i].rfmax);
-		if (tda_fail(ret))
-			goto fail;
-	}
-
-	priv->tm_rfcal = tda18271_read_thermometer(fe);
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------ */
-
-static int tda18271c2_rf_cal_init(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	int ret;
-
-	/* test RF_CAL_OK to see if we need init */
-	if ((regs[R_EP1] & 0x10) == 0)
-		priv->cal_initialized = false;
-
-	if (priv->cal_initialized)
-		return 0;
-
-	ret = tda18271_calc_rf_filter_curve(fe);
-	if (tda_fail(ret))
-		goto fail;
-
-	ret = tda18271_por(fe);
-	if (tda_fail(ret))
-		goto fail;
-
-	tda_info("tda18271: RF tracking filter calibration complete\n");
-
-	priv->cal_initialized = true;
-	goto end;
-fail:
-	tda_info("tda18271: RF tracking filter calibration failed!\n");
-end:
-	return ret;
-}
-
-static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe,
-						     u32 freq, u32 bw)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	int ret;
-	u32 N = 0;
-
-	/* calculate bp filter */
-	tda18271_calc_bp_filter(fe, &freq);
-	tda18271_write_regs(fe, R_EP1, 1);
-
-	regs[R_EB4]  &= 0x07;
-	regs[R_EB4]  |= 0x60;
-	tda18271_write_regs(fe, R_EB4, 1);
-
-	regs[R_EB7]   = 0x60;
-	tda18271_write_regs(fe, R_EB7, 1);
-
-	regs[R_EB14]  = 0x00;
-	tda18271_write_regs(fe, R_EB14, 1);
-
-	regs[R_EB20]  = 0xcc;
-	tda18271_write_regs(fe, R_EB20, 1);
-
-	/* set cal mode to RF tracking filter calibration */
-	regs[R_EP4]  |= 0x03;
-
-	/* calculate cal pll */
-
-	switch (priv->mode) {
-	case TDA18271_ANALOG:
-		N = freq - 1250000;
-		break;
-	case TDA18271_DIGITAL:
-		N = freq + bw / 2;
-		break;
-	}
-
-	tda18271_calc_cal_pll(fe, N);
-
-	/* calculate main pll */
-
-	switch (priv->mode) {
-	case TDA18271_ANALOG:
-		N = freq - 250000;
-		break;
-	case TDA18271_DIGITAL:
-		N = freq + bw / 2 + 1000000;
-		break;
-	}
-
-	tda18271_calc_main_pll(fe, N);
-
-	ret = tda18271_write_regs(fe, R_EP3, 11);
-	if (tda_fail(ret))
-		return ret;
-
-	msleep(5); /* RF tracking filter calibration initialization */
-
-	/* search for K,M,CO for RF calibration */
-	tda18271_calc_km(fe, &freq);
-	tda18271_write_regs(fe, R_EB13, 1);
-
-	/* search for rf band */
-	tda18271_calc_rf_band(fe, &freq);
-
-	/* search for gain taper */
-	tda18271_calc_gain_taper(fe, &freq);
-
-	tda18271_write_regs(fe, R_EP2, 1);
-	tda18271_write_regs(fe, R_EP1, 1);
-	tda18271_write_regs(fe, R_EP2, 1);
-	tda18271_write_regs(fe, R_EP1, 1);
-
-	regs[R_EB4]  &= 0x07;
-	regs[R_EB4]  |= 0x40;
-	tda18271_write_regs(fe, R_EB4, 1);
-
-	regs[R_EB7]   = 0x40;
-	tda18271_write_regs(fe, R_EB7, 1);
-	msleep(10); /* pll locking */
-
-	regs[R_EB20]  = 0xec;
-	tda18271_write_regs(fe, R_EB20, 1);
-	msleep(60); /* RF tracking filter calibration completion */
-
-	regs[R_EP4]  &= ~0x03; /* set cal mode to normal */
-	tda18271_write_regs(fe, R_EP4, 1);
-
-	tda18271_write_regs(fe, R_EP1, 1);
-
-	/* RF tracking filter correction for VHF_Low band */
-	if (0 == tda18271_calc_rf_cal(fe, &freq))
-		tda18271_write_regs(fe, R_EB14, 1);
-
-	return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-static int tda18271_ir_cal_init(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	int ret;
-
-	ret = tda18271_read_regs(fe);
-	if (tda_fail(ret))
-		goto fail;
-
-	/* test IR_CAL_OK to see if we need init */
-	if ((regs[R_EP1] & 0x08) == 0)
-		ret = tda18271_init_regs(fe);
-fail:
-	return ret;
-}
-
-static int tda18271_init(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	int ret;
-
-	mutex_lock(&priv->lock);
-
-	/* full power up */
-	ret = tda18271_set_standby_mode(fe, 0, 0, 0);
-	if (tda_fail(ret))
-		goto fail;
-
-	/* initialization */
-	ret = tda18271_ir_cal_init(fe);
-	if (tda_fail(ret))
-		goto fail;
-
-	if (priv->id == TDA18271HDC2)
-		tda18271c2_rf_cal_init(fe);
-fail:
-	mutex_unlock(&priv->lock);
-
-	return ret;
-}
-
-static int tda18271_sleep(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	int ret;
-
-	mutex_lock(&priv->lock);
-
-	/* enter standby mode, with required output features enabled */
-	ret = tda18271_toggle_output(fe, 1);
-
-	mutex_unlock(&priv->lock);
-
-	return ret;
-}
-
-/* ------------------------------------------------------------------ */
-
-static int tda18271_agc(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	int ret = 0;
-
-	switch (priv->config) {
-	case 0:
-		/* no external agc configuration required */
-		if (tda18271_debug & DBG_ADV)
-			tda_dbg("no agc configuration provided\n");
-		break;
-	case 3:
-		/* switch with GPIO of saa713x */
-		tda_dbg("invoking callback\n");
-		if (fe->callback)
-			ret = fe->callback(priv->i2c_props.adap->algo_data,
-					   DVB_FRONTEND_COMPONENT_TUNER,
-					   TDA18271_CALLBACK_CMD_AGC_ENABLE,
-					   priv->mode);
-		break;
-	case 1:
-	case 2:
-	default:
-		/* n/a - currently not supported */
-		tda_err("unsupported configuration: %d\n", priv->config);
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
-
-static int tda18271_tune(struct dvb_frontend *fe,
-			 struct tda18271_std_map_item *map, u32 freq, u32 bw)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	int ret;
-
-	tda_dbg("freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d\n",
-		freq, map->if_freq, bw, map->agc_mode, map->std);
-
-	ret = tda18271_agc(fe);
-	if (tda_fail(ret))
-		tda_warn("failed to configure agc\n");
-
-	ret = tda18271_init(fe);
-	if (tda_fail(ret))
-		goto fail;
-
-	mutex_lock(&priv->lock);
-
-	switch (priv->id) {
-	case TDA18271HDC1:
-		tda18271c1_rf_tracking_filter_calibration(fe, freq, bw);
-		break;
-	case TDA18271HDC2:
-		tda18271c2_rf_tracking_filters_correction(fe, freq);
-		break;
-	}
-	ret = tda18271_channel_configuration(fe, map, freq, bw);
-
-	mutex_unlock(&priv->lock);
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------ */
-
-static int tda18271_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 delsys = c->delivery_system;
-	u32 bw = c->bandwidth_hz;
-	u32 freq = c->frequency;
-	struct tda18271_priv *priv = fe->tuner_priv;
-	struct tda18271_std_map *std_map = &priv->std;
-	struct tda18271_std_map_item *map;
-	int ret;
-
-	priv->mode = TDA18271_DIGITAL;
-
-	switch (delsys) {
-	case SYS_ATSC:
-		map = &std_map->atsc_6;
-		bw = 6000000;
-		break;
-	case SYS_ISDBT:
-	case SYS_DVBT:
-	case SYS_DVBT2:
-		if (bw <= 6000000) {
-			map = &std_map->dvbt_6;
-		} else if (bw <= 7000000) {
-			map = &std_map->dvbt_7;
-		} else {
-			map = &std_map->dvbt_8;
-		}
-		break;
-	case SYS_DVBC_ANNEX_B:
-		bw = 6000000;
-		/* falltrough */
-	case SYS_DVBC_ANNEX_A:
-	case SYS_DVBC_ANNEX_C:
-		if (bw <= 6000000) {
-			map = &std_map->qam_6;
-		} else if (bw <= 7000000) {
-			map = &std_map->qam_7;
-		} else {
-			map = &std_map->qam_8;
-		}
-		break;
-	default:
-		tda_warn("modulation type not supported!\n");
-		return -EINVAL;
-	}
-
-	/* When tuning digital, the analog demod must be tri-stated */
-	if (fe->ops.analog_ops.standby)
-		fe->ops.analog_ops.standby(fe);
-
-	ret = tda18271_tune(fe, map, freq, bw);
-
-	if (tda_fail(ret))
-		goto fail;
-
-	priv->if_freq   = map->if_freq;
-	priv->frequency = freq;
-	priv->bandwidth = bw;
-fail:
-	return ret;
-}
-
-static int tda18271_set_analog_params(struct dvb_frontend *fe,
-				      struct analog_parameters *params)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	struct tda18271_std_map *std_map = &priv->std;
-	struct tda18271_std_map_item *map;
-	char *mode;
-	int ret;
-	u32 freq = params->frequency * 125 *
-		((params->mode == V4L2_TUNER_RADIO) ? 1 : 1000) / 2;
-
-	priv->mode = TDA18271_ANALOG;
-
-	if (params->mode == V4L2_TUNER_RADIO) {
-		map = &std_map->fm_radio;
-		mode = "fm";
-	} else if (params->std & V4L2_STD_MN) {
-		map = &std_map->atv_mn;
-		mode = "MN";
-	} else if (params->std & V4L2_STD_B) {
-		map = &std_map->atv_b;
-		mode = "B";
-	} else if (params->std & V4L2_STD_GH) {
-		map = &std_map->atv_gh;
-		mode = "GH";
-	} else if (params->std & V4L2_STD_PAL_I) {
-		map = &std_map->atv_i;
-		mode = "I";
-	} else if (params->std & V4L2_STD_DK) {
-		map = &std_map->atv_dk;
-		mode = "DK";
-	} else if (params->std & V4L2_STD_SECAM_L) {
-		map = &std_map->atv_l;
-		mode = "L";
-	} else if (params->std & V4L2_STD_SECAM_LC) {
-		map = &std_map->atv_lc;
-		mode = "L'";
-	} else {
-		map = &std_map->atv_i;
-		mode = "xx";
-	}
-
-	tda_dbg("setting tda18271 to system %s\n", mode);
-
-	ret = tda18271_tune(fe, map, freq, 0);
-
-	if (tda_fail(ret))
-		goto fail;
-
-	priv->if_freq   = map->if_freq;
-	priv->frequency = freq;
-	priv->bandwidth = 0;
-fail:
-	return ret;
-}
-
-static int tda18271_release(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-
-	mutex_lock(&tda18271_list_mutex);
-
-	if (priv)
-		hybrid_tuner_release_state(priv);
-
-	mutex_unlock(&tda18271_list_mutex);
-
-	fe->tuner_priv = NULL;
-
-	return 0;
-}
-
-static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-	return 0;
-}
-
-static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	*bandwidth = priv->bandwidth;
-	return 0;
-}
-
-static int tda18271_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	*frequency = (u32)priv->if_freq * 1000;
-	return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-#define tda18271_update_std(std_cfg, name) do {				\
-	if (map->std_cfg.if_freq +					\
-		map->std_cfg.agc_mode + map->std_cfg.std +		\
-		map->std_cfg.if_lvl + map->std_cfg.rfagc_top > 0) {	\
-		tda_dbg("Using custom std config for %s\n", name);	\
-		memcpy(&std->std_cfg, &map->std_cfg,			\
-			sizeof(struct tda18271_std_map_item));		\
-	} } while (0)
-
-#define tda18271_dump_std_item(std_cfg, name) do {			\
-	tda_dbg("(%s) if_freq = %d, agc_mode = %d, std = %d, "		\
-		"if_lvl = %d, rfagc_top = 0x%02x\n",			\
-		name, std->std_cfg.if_freq,				\
-		std->std_cfg.agc_mode, std->std_cfg.std,		\
-		std->std_cfg.if_lvl, std->std_cfg.rfagc_top);		\
-	} while (0)
-
-static int tda18271_dump_std_map(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	struct tda18271_std_map *std = &priv->std;
-
-	tda_dbg("========== STANDARD MAP SETTINGS ==========\n");
-	tda18271_dump_std_item(fm_radio, "  fm  ");
-	tda18271_dump_std_item(atv_b,  "atv b ");
-	tda18271_dump_std_item(atv_dk, "atv dk");
-	tda18271_dump_std_item(atv_gh, "atv gh");
-	tda18271_dump_std_item(atv_i,  "atv i ");
-	tda18271_dump_std_item(atv_l,  "atv l ");
-	tda18271_dump_std_item(atv_lc, "atv l'");
-	tda18271_dump_std_item(atv_mn, "atv mn");
-	tda18271_dump_std_item(atsc_6, "atsc 6");
-	tda18271_dump_std_item(dvbt_6, "dvbt 6");
-	tda18271_dump_std_item(dvbt_7, "dvbt 7");
-	tda18271_dump_std_item(dvbt_8, "dvbt 8");
-	tda18271_dump_std_item(qam_6,  "qam 6 ");
-	tda18271_dump_std_item(qam_8,  "qam 8 ");
-
-	return 0;
-}
-
-static int tda18271_update_std_map(struct dvb_frontend *fe,
-				   struct tda18271_std_map *map)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	struct tda18271_std_map *std = &priv->std;
-
-	if (!map)
-		return -EINVAL;
-
-	tda18271_update_std(fm_radio, "fm");
-	tda18271_update_std(atv_b,  "atv b");
-	tda18271_update_std(atv_dk, "atv dk");
-	tda18271_update_std(atv_gh, "atv gh");
-	tda18271_update_std(atv_i,  "atv i");
-	tda18271_update_std(atv_l,  "atv l");
-	tda18271_update_std(atv_lc, "atv l'");
-	tda18271_update_std(atv_mn, "atv mn");
-	tda18271_update_std(atsc_6, "atsc 6");
-	tda18271_update_std(dvbt_6, "dvbt 6");
-	tda18271_update_std(dvbt_7, "dvbt 7");
-	tda18271_update_std(dvbt_8, "dvbt 8");
-	tda18271_update_std(qam_6,  "qam 6");
-	tda18271_update_std(qam_8,  "qam 8");
-
-	return 0;
-}
-
-static int tda18271_get_id(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	char *name;
-
-	mutex_lock(&priv->lock);
-	tda18271_read_regs(fe);
-	mutex_unlock(&priv->lock);
-
-	switch (regs[R_ID] & 0x7f) {
-	case 3:
-		name = "TDA18271HD/C1";
-		priv->id = TDA18271HDC1;
-		break;
-	case 4:
-		name = "TDA18271HD/C2";
-		priv->id = TDA18271HDC2;
-		break;
-	default:
-		tda_info("Unknown device (%i) detected @ %d-%04x, device not supported.\n",
-			 regs[R_ID], i2c_adapter_id(priv->i2c_props.adap),
-			 priv->i2c_props.addr);
-		return -EINVAL;
-	}
-
-	tda_info("%s detected @ %d-%04x\n", name,
-		 i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr);
-
-	return 0;
-}
-
-static int tda18271_setup_configuration(struct dvb_frontend *fe,
-					struct tda18271_config *cfg)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-
-	priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
-	priv->role = (cfg) ? cfg->role : TDA18271_MASTER;
-	priv->config = (cfg) ? cfg->config : 0;
-	priv->small_i2c = (cfg) ?
-		cfg->small_i2c : TDA18271_39_BYTE_CHUNK_INIT;
-	priv->output_opt = (cfg) ?
-		cfg->output_opt : TDA18271_OUTPUT_LT_XT_ON;
-
-	return 0;
-}
-
-static inline int tda18271_need_cal_on_startup(struct tda18271_config *cfg)
-{
-	/* tda18271_cal_on_startup == -1 when cal module option is unset */
-	return ((tda18271_cal_on_startup == -1) ?
-		/* honor configuration setting */
-		((cfg) && (cfg->rf_cal_on_startup)) :
-		/* module option overrides configuration setting */
-		(tda18271_cal_on_startup)) ? 1 : 0;
-}
-
-static int tda18271_set_config(struct dvb_frontend *fe, void *priv_cfg)
-{
-	struct tda18271_config *cfg = (struct tda18271_config *) priv_cfg;
-
-	tda18271_setup_configuration(fe, cfg);
-
-	if (tda18271_need_cal_on_startup(cfg))
-		tda18271_init(fe);
-
-	/* override default std map with values in config struct */
-	if ((cfg) && (cfg->std_map))
-		tda18271_update_std_map(fe, cfg->std_map);
-
-	return 0;
-}
-
-static const struct dvb_tuner_ops tda18271_tuner_ops = {
-	.info = {
-		.name = "NXP TDA18271HD",
-		.frequency_min  =  45000000,
-		.frequency_max  = 864000000,
-		.frequency_step =     62500
-	},
-	.init              = tda18271_init,
-	.sleep             = tda18271_sleep,
-	.set_params        = tda18271_set_params,
-	.set_analog_params = tda18271_set_analog_params,
-	.release           = tda18271_release,
-	.set_config        = tda18271_set_config,
-	.get_frequency     = tda18271_get_frequency,
-	.get_bandwidth     = tda18271_get_bandwidth,
-	.get_if_frequency  = tda18271_get_if_frequency,
-};
-
-struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
-				     struct i2c_adapter *i2c,
-				     struct tda18271_config *cfg)
-{
-	struct tda18271_priv *priv = NULL;
-	int instance, ret;
-
-	mutex_lock(&tda18271_list_mutex);
-
-	instance = hybrid_tuner_request_state(struct tda18271_priv, priv,
-					      hybrid_tuner_instance_list,
-					      i2c, addr, "tda18271");
-	switch (instance) {
-	case 0:
-		goto fail;
-	case 1:
-		/* new tuner instance */
-		fe->tuner_priv = priv;
-
-		tda18271_setup_configuration(fe, cfg);
-
-		priv->cal_initialized = false;
-		mutex_init(&priv->lock);
-
-		ret = tda18271_get_id(fe);
-		if (tda_fail(ret))
-			goto fail;
-
-		ret = tda18271_assign_map_layout(fe);
-		if (tda_fail(ret))
-			goto fail;
-
-		mutex_lock(&priv->lock);
-		tda18271_init_regs(fe);
-
-		if ((tda18271_need_cal_on_startup(cfg)) &&
-		    (priv->id == TDA18271HDC2))
-			tda18271c2_rf_cal_init(fe);
-
-		mutex_unlock(&priv->lock);
-		break;
-	default:
-		/* existing tuner instance */
-		fe->tuner_priv = priv;
-
-		/* allow dvb driver to override configuration settings */
-		if (cfg) {
-			if (cfg->gate != TDA18271_GATE_ANALOG)
-				priv->gate = cfg->gate;
-			if (cfg->role)
-				priv->role = cfg->role;
-			if (cfg->config)
-				priv->config = cfg->config;
-			if (cfg->small_i2c)
-				priv->small_i2c = cfg->small_i2c;
-			if (cfg->output_opt)
-				priv->output_opt = cfg->output_opt;
-			if (cfg->std_map)
-				tda18271_update_std_map(fe, cfg->std_map);
-		}
-		if (tda18271_need_cal_on_startup(cfg))
-			tda18271_init(fe);
-		break;
-	}
-
-	/* override default std map with values in config struct */
-	if ((cfg) && (cfg->std_map))
-		tda18271_update_std_map(fe, cfg->std_map);
-
-	mutex_unlock(&tda18271_list_mutex);
-
-	memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops,
-	       sizeof(struct dvb_tuner_ops));
-
-	if (tda18271_debug & (DBG_MAP | DBG_ADV))
-		tda18271_dump_std_map(fe);
-
-	return fe;
-fail:
-	mutex_unlock(&tda18271_list_mutex);
-
-	tda18271_release(fe);
-	return NULL;
-}
-EXPORT_SYMBOL_GPL(tda18271_attach);
-MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver");
-MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.4");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/common/tuners/tda18271-maps.c b/drivers/media/common/tuners/tda18271-maps.c
deleted file mode 100644
index fb881c6..0000000
--- a/drivers/media/common/tuners/tda18271-maps.c
+++ /dev/null
@@ -1,1317 +0,0 @@
-/*
-    tda18271-maps.c - driver for the Philips / NXP TDA18271 silicon tuner
-
-    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "tda18271-priv.h"
-
-struct tda18271_pll_map {
-	u32 lomax;
-	u8 pd; /* post div */
-	u8 d;  /*      div */
-};
-
-struct tda18271_map {
-	u32 rfmax;
-	u8  val;
-};
-
-/*---------------------------------------------------------------------*/
-
-static struct tda18271_pll_map tda18271c1_main_pll[] = {
-	{ .lomax =  32000, .pd = 0x5f, .d = 0xf0 },
-	{ .lomax =  35000, .pd = 0x5e, .d = 0xe0 },
-	{ .lomax =  37000, .pd = 0x5d, .d = 0xd0 },
-	{ .lomax =  41000, .pd = 0x5c, .d = 0xc0 },
-	{ .lomax =  44000, .pd = 0x5b, .d = 0xb0 },
-	{ .lomax =  49000, .pd = 0x5a, .d = 0xa0 },
-	{ .lomax =  54000, .pd = 0x59, .d = 0x90 },
-	{ .lomax =  61000, .pd = 0x58, .d = 0x80 },
-	{ .lomax =  65000, .pd = 0x4f, .d = 0x78 },
-	{ .lomax =  70000, .pd = 0x4e, .d = 0x70 },
-	{ .lomax =  75000, .pd = 0x4d, .d = 0x68 },
-	{ .lomax =  82000, .pd = 0x4c, .d = 0x60 },
-	{ .lomax =  89000, .pd = 0x4b, .d = 0x58 },
-	{ .lomax =  98000, .pd = 0x4a, .d = 0x50 },
-	{ .lomax = 109000, .pd = 0x49, .d = 0x48 },
-	{ .lomax = 123000, .pd = 0x48, .d = 0x40 },
-	{ .lomax = 131000, .pd = 0x3f, .d = 0x3c },
-	{ .lomax = 141000, .pd = 0x3e, .d = 0x38 },
-	{ .lomax = 151000, .pd = 0x3d, .d = 0x34 },
-	{ .lomax = 164000, .pd = 0x3c, .d = 0x30 },
-	{ .lomax = 179000, .pd = 0x3b, .d = 0x2c },
-	{ .lomax = 197000, .pd = 0x3a, .d = 0x28 },
-	{ .lomax = 219000, .pd = 0x39, .d = 0x24 },
-	{ .lomax = 246000, .pd = 0x38, .d = 0x20 },
-	{ .lomax = 263000, .pd = 0x2f, .d = 0x1e },
-	{ .lomax = 282000, .pd = 0x2e, .d = 0x1c },
-	{ .lomax = 303000, .pd = 0x2d, .d = 0x1a },
-	{ .lomax = 329000, .pd = 0x2c, .d = 0x18 },
-	{ .lomax = 359000, .pd = 0x2b, .d = 0x16 },
-	{ .lomax = 395000, .pd = 0x2a, .d = 0x14 },
-	{ .lomax = 438000, .pd = 0x29, .d = 0x12 },
-	{ .lomax = 493000, .pd = 0x28, .d = 0x10 },
-	{ .lomax = 526000, .pd = 0x1f, .d = 0x0f },
-	{ .lomax = 564000, .pd = 0x1e, .d = 0x0e },
-	{ .lomax = 607000, .pd = 0x1d, .d = 0x0d },
-	{ .lomax = 658000, .pd = 0x1c, .d = 0x0c },
-	{ .lomax = 718000, .pd = 0x1b, .d = 0x0b },
-	{ .lomax = 790000, .pd = 0x1a, .d = 0x0a },
-	{ .lomax = 877000, .pd = 0x19, .d = 0x09 },
-	{ .lomax = 987000, .pd = 0x18, .d = 0x08 },
-	{ .lomax =      0, .pd = 0x00, .d = 0x00 }, /* end */
-};
-
-static struct tda18271_pll_map tda18271c2_main_pll[] = {
-	{ .lomax =  33125, .pd = 0x57, .d = 0xf0 },
-	{ .lomax =  35500, .pd = 0x56, .d = 0xe0 },
-	{ .lomax =  38188, .pd = 0x55, .d = 0xd0 },
-	{ .lomax =  41375, .pd = 0x54, .d = 0xc0 },
-	{ .lomax =  45125, .pd = 0x53, .d = 0xb0 },
-	{ .lomax =  49688, .pd = 0x52, .d = 0xa0 },
-	{ .lomax =  55188, .pd = 0x51, .d = 0x90 },
-	{ .lomax =  62125, .pd = 0x50, .d = 0x80 },
-	{ .lomax =  66250, .pd = 0x47, .d = 0x78 },
-	{ .lomax =  71000, .pd = 0x46, .d = 0x70 },
-	{ .lomax =  76375, .pd = 0x45, .d = 0x68 },
-	{ .lomax =  82750, .pd = 0x44, .d = 0x60 },
-	{ .lomax =  90250, .pd = 0x43, .d = 0x58 },
-	{ .lomax =  99375, .pd = 0x42, .d = 0x50 },
-	{ .lomax = 110375, .pd = 0x41, .d = 0x48 },
-	{ .lomax = 124250, .pd = 0x40, .d = 0x40 },
-	{ .lomax = 132500, .pd = 0x37, .d = 0x3c },
-	{ .lomax = 142000, .pd = 0x36, .d = 0x38 },
-	{ .lomax = 152750, .pd = 0x35, .d = 0x34 },
-	{ .lomax = 165500, .pd = 0x34, .d = 0x30 },
-	{ .lomax = 180500, .pd = 0x33, .d = 0x2c },
-	{ .lomax = 198750, .pd = 0x32, .d = 0x28 },
-	{ .lomax = 220750, .pd = 0x31, .d = 0x24 },
-	{ .lomax = 248500, .pd = 0x30, .d = 0x20 },
-	{ .lomax = 265000, .pd = 0x27, .d = 0x1e },
-	{ .lomax = 284000, .pd = 0x26, .d = 0x1c },
-	{ .lomax = 305500, .pd = 0x25, .d = 0x1a },
-	{ .lomax = 331000, .pd = 0x24, .d = 0x18 },
-	{ .lomax = 361000, .pd = 0x23, .d = 0x16 },
-	{ .lomax = 397500, .pd = 0x22, .d = 0x14 },
-	{ .lomax = 441500, .pd = 0x21, .d = 0x12 },
-	{ .lomax = 497000, .pd = 0x20, .d = 0x10 },
-	{ .lomax = 530000, .pd = 0x17, .d = 0x0f },
-	{ .lomax = 568000, .pd = 0x16, .d = 0x0e },
-	{ .lomax = 611000, .pd = 0x15, .d = 0x0d },
-	{ .lomax = 662000, .pd = 0x14, .d = 0x0c },
-	{ .lomax = 722000, .pd = 0x13, .d = 0x0b },
-	{ .lomax = 795000, .pd = 0x12, .d = 0x0a },
-	{ .lomax = 883000, .pd = 0x11, .d = 0x09 },
-	{ .lomax = 994000, .pd = 0x10, .d = 0x08 },
-	{ .lomax =      0, .pd = 0x00, .d = 0x00 }, /* end */
-};
-
-static struct tda18271_pll_map tda18271c1_cal_pll[] = {
-	{ .lomax =   33000, .pd = 0xdd, .d = 0xd0 },
-	{ .lomax =   36000, .pd = 0xdc, .d = 0xc0 },
-	{ .lomax =   40000, .pd = 0xdb, .d = 0xb0 },
-	{ .lomax =   44000, .pd = 0xda, .d = 0xa0 },
-	{ .lomax =   49000, .pd = 0xd9, .d = 0x90 },
-	{ .lomax =   55000, .pd = 0xd8, .d = 0x80 },
-	{ .lomax =   63000, .pd = 0xd3, .d = 0x70 },
-	{ .lomax =   67000, .pd = 0xcd, .d = 0x68 },
-	{ .lomax =   73000, .pd = 0xcc, .d = 0x60 },
-	{ .lomax =   80000, .pd = 0xcb, .d = 0x58 },
-	{ .lomax =   88000, .pd = 0xca, .d = 0x50 },
-	{ .lomax =   98000, .pd = 0xc9, .d = 0x48 },
-	{ .lomax =  110000, .pd = 0xc8, .d = 0x40 },
-	{ .lomax =  126000, .pd = 0xc3, .d = 0x38 },
-	{ .lomax =  135000, .pd = 0xbd, .d = 0x34 },
-	{ .lomax =  147000, .pd = 0xbc, .d = 0x30 },
-	{ .lomax =  160000, .pd = 0xbb, .d = 0x2c },
-	{ .lomax =  176000, .pd = 0xba, .d = 0x28 },
-	{ .lomax =  196000, .pd = 0xb9, .d = 0x24 },
-	{ .lomax =  220000, .pd = 0xb8, .d = 0x20 },
-	{ .lomax =  252000, .pd = 0xb3, .d = 0x1c },
-	{ .lomax =  271000, .pd = 0xad, .d = 0x1a },
-	{ .lomax =  294000, .pd = 0xac, .d = 0x18 },
-	{ .lomax =  321000, .pd = 0xab, .d = 0x16 },
-	{ .lomax =  353000, .pd = 0xaa, .d = 0x14 },
-	{ .lomax =  392000, .pd = 0xa9, .d = 0x12 },
-	{ .lomax =  441000, .pd = 0xa8, .d = 0x10 },
-	{ .lomax =  505000, .pd = 0xa3, .d = 0x0e },
-	{ .lomax =  543000, .pd = 0x9d, .d = 0x0d },
-	{ .lomax =  589000, .pd = 0x9c, .d = 0x0c },
-	{ .lomax =  642000, .pd = 0x9b, .d = 0x0b },
-	{ .lomax =  707000, .pd = 0x9a, .d = 0x0a },
-	{ .lomax =  785000, .pd = 0x99, .d = 0x09 },
-	{ .lomax =  883000, .pd = 0x98, .d = 0x08 },
-	{ .lomax = 1010000, .pd = 0x93, .d = 0x07 },
-	{ .lomax =       0, .pd = 0x00, .d = 0x00 }, /* end */
-};
-
-static struct tda18271_pll_map tda18271c2_cal_pll[] = {
-	{ .lomax =   33813, .pd = 0xdd, .d = 0xd0 },
-	{ .lomax =   36625, .pd = 0xdc, .d = 0xc0 },
-	{ .lomax =   39938, .pd = 0xdb, .d = 0xb0 },
-	{ .lomax =   43938, .pd = 0xda, .d = 0xa0 },
-	{ .lomax =   48813, .pd = 0xd9, .d = 0x90 },
-	{ .lomax =   54938, .pd = 0xd8, .d = 0x80 },
-	{ .lomax =   62813, .pd = 0xd3, .d = 0x70 },
-	{ .lomax =   67625, .pd = 0xcd, .d = 0x68 },
-	{ .lomax =   73250, .pd = 0xcc, .d = 0x60 },
-	{ .lomax =   79875, .pd = 0xcb, .d = 0x58 },
-	{ .lomax =   87875, .pd = 0xca, .d = 0x50 },
-	{ .lomax =   97625, .pd = 0xc9, .d = 0x48 },
-	{ .lomax =  109875, .pd = 0xc8, .d = 0x40 },
-	{ .lomax =  125625, .pd = 0xc3, .d = 0x38 },
-	{ .lomax =  135250, .pd = 0xbd, .d = 0x34 },
-	{ .lomax =  146500, .pd = 0xbc, .d = 0x30 },
-	{ .lomax =  159750, .pd = 0xbb, .d = 0x2c },
-	{ .lomax =  175750, .pd = 0xba, .d = 0x28 },
-	{ .lomax =  195250, .pd = 0xb9, .d = 0x24 },
-	{ .lomax =  219750, .pd = 0xb8, .d = 0x20 },
-	{ .lomax =  251250, .pd = 0xb3, .d = 0x1c },
-	{ .lomax =  270500, .pd = 0xad, .d = 0x1a },
-	{ .lomax =  293000, .pd = 0xac, .d = 0x18 },
-	{ .lomax =  319500, .pd = 0xab, .d = 0x16 },
-	{ .lomax =  351500, .pd = 0xaa, .d = 0x14 },
-	{ .lomax =  390500, .pd = 0xa9, .d = 0x12 },
-	{ .lomax =  439500, .pd = 0xa8, .d = 0x10 },
-	{ .lomax =  502500, .pd = 0xa3, .d = 0x0e },
-	{ .lomax =  541000, .pd = 0x9d, .d = 0x0d },
-	{ .lomax =  586000, .pd = 0x9c, .d = 0x0c },
-	{ .lomax =  639000, .pd = 0x9b, .d = 0x0b },
-	{ .lomax =  703000, .pd = 0x9a, .d = 0x0a },
-	{ .lomax =  781000, .pd = 0x99, .d = 0x09 },
-	{ .lomax =  879000, .pd = 0x98, .d = 0x08 },
-	{ .lomax =       0, .pd = 0x00, .d = 0x00 }, /* end */
-};
-
-static struct tda18271_map tda18271_bp_filter[] = {
-	{ .rfmax =  62000, .val = 0x00 },
-	{ .rfmax =  84000, .val = 0x01 },
-	{ .rfmax = 100000, .val = 0x02 },
-	{ .rfmax = 140000, .val = 0x03 },
-	{ .rfmax = 170000, .val = 0x04 },
-	{ .rfmax = 180000, .val = 0x05 },
-	{ .rfmax = 865000, .val = 0x06 },
-	{ .rfmax =      0, .val = 0x00 }, /* end */
-};
-
-static struct tda18271_map tda18271c1_km[] = {
-	{ .rfmax =  61100, .val = 0x74 },
-	{ .rfmax = 350000, .val = 0x40 },
-	{ .rfmax = 720000, .val = 0x30 },
-	{ .rfmax = 865000, .val = 0x40 },
-	{ .rfmax =      0, .val = 0x00 }, /* end */
-};
-
-static struct tda18271_map tda18271c2_km[] = {
-	{ .rfmax =  47900, .val = 0x38 },
-	{ .rfmax =  61100, .val = 0x44 },
-	{ .rfmax = 350000, .val = 0x30 },
-	{ .rfmax = 720000, .val = 0x24 },
-	{ .rfmax = 865000, .val = 0x3c },
-	{ .rfmax =      0, .val = 0x00 }, /* end */
-};
-
-static struct tda18271_map tda18271_rf_band[] = {
-	{ .rfmax =  47900, .val = 0x00 },
-	{ .rfmax =  61100, .val = 0x01 },
-	{ .rfmax = 152600, .val = 0x02 },
-	{ .rfmax = 164700, .val = 0x03 },
-	{ .rfmax = 203500, .val = 0x04 },
-	{ .rfmax = 457800, .val = 0x05 },
-	{ .rfmax = 865000, .val = 0x06 },
-	{ .rfmax =      0, .val = 0x00 }, /* end */
-};
-
-static struct tda18271_map tda18271_gain_taper[] = {
-	{ .rfmax =  45400, .val = 0x1f },
-	{ .rfmax =  45800, .val = 0x1e },
-	{ .rfmax =  46200, .val = 0x1d },
-	{ .rfmax =  46700, .val = 0x1c },
-	{ .rfmax =  47100, .val = 0x1b },
-	{ .rfmax =  47500, .val = 0x1a },
-	{ .rfmax =  47900, .val = 0x19 },
-	{ .rfmax =  49600, .val = 0x17 },
-	{ .rfmax =  51200, .val = 0x16 },
-	{ .rfmax =  52900, .val = 0x15 },
-	{ .rfmax =  54500, .val = 0x14 },
-	{ .rfmax =  56200, .val = 0x13 },
-	{ .rfmax =  57800, .val = 0x12 },
-	{ .rfmax =  59500, .val = 0x11 },
-	{ .rfmax =  61100, .val = 0x10 },
-	{ .rfmax =  67600, .val = 0x0d },
-	{ .rfmax =  74200, .val = 0x0c },
-	{ .rfmax =  80700, .val = 0x0b },
-	{ .rfmax =  87200, .val = 0x0a },
-	{ .rfmax =  93800, .val = 0x09 },
-	{ .rfmax = 100300, .val = 0x08 },
-	{ .rfmax = 106900, .val = 0x07 },
-	{ .rfmax = 113400, .val = 0x06 },
-	{ .rfmax = 119900, .val = 0x05 },
-	{ .rfmax = 126500, .val = 0x04 },
-	{ .rfmax = 133000, .val = 0x03 },
-	{ .rfmax = 139500, .val = 0x02 },
-	{ .rfmax = 146100, .val = 0x01 },
-	{ .rfmax = 152600, .val = 0x00 },
-	{ .rfmax = 154300, .val = 0x1f },
-	{ .rfmax = 156100, .val = 0x1e },
-	{ .rfmax = 157800, .val = 0x1d },
-	{ .rfmax = 159500, .val = 0x1c },
-	{ .rfmax = 161200, .val = 0x1b },
-	{ .rfmax = 163000, .val = 0x1a },
-	{ .rfmax = 164700, .val = 0x19 },
-	{ .rfmax = 170200, .val = 0x17 },
-	{ .rfmax = 175800, .val = 0x16 },
-	{ .rfmax = 181300, .val = 0x15 },
-	{ .rfmax = 186900, .val = 0x14 },
-	{ .rfmax = 192400, .val = 0x13 },
-	{ .rfmax = 198000, .val = 0x12 },
-	{ .rfmax = 203500, .val = 0x11 },
-	{ .rfmax = 216200, .val = 0x14 },
-	{ .rfmax = 228900, .val = 0x13 },
-	{ .rfmax = 241600, .val = 0x12 },
-	{ .rfmax = 254400, .val = 0x11 },
-	{ .rfmax = 267100, .val = 0x10 },
-	{ .rfmax = 279800, .val = 0x0f },
-	{ .rfmax = 292500, .val = 0x0e },
-	{ .rfmax = 305200, .val = 0x0d },
-	{ .rfmax = 317900, .val = 0x0c },
-	{ .rfmax = 330700, .val = 0x0b },
-	{ .rfmax = 343400, .val = 0x0a },
-	{ .rfmax = 356100, .val = 0x09 },
-	{ .rfmax = 368800, .val = 0x08 },
-	{ .rfmax = 381500, .val = 0x07 },
-	{ .rfmax = 394200, .val = 0x06 },
-	{ .rfmax = 406900, .val = 0x05 },
-	{ .rfmax = 419700, .val = 0x04 },
-	{ .rfmax = 432400, .val = 0x03 },
-	{ .rfmax = 445100, .val = 0x02 },
-	{ .rfmax = 457800, .val = 0x01 },
-	{ .rfmax = 476300, .val = 0x19 },
-	{ .rfmax = 494800, .val = 0x18 },
-	{ .rfmax = 513300, .val = 0x17 },
-	{ .rfmax = 531800, .val = 0x16 },
-	{ .rfmax = 550300, .val = 0x15 },
-	{ .rfmax = 568900, .val = 0x14 },
-	{ .rfmax = 587400, .val = 0x13 },
-	{ .rfmax = 605900, .val = 0x12 },
-	{ .rfmax = 624400, .val = 0x11 },
-	{ .rfmax = 642900, .val = 0x10 },
-	{ .rfmax = 661400, .val = 0x0f },
-	{ .rfmax = 679900, .val = 0x0e },
-	{ .rfmax = 698400, .val = 0x0d },
-	{ .rfmax = 716900, .val = 0x0c },
-	{ .rfmax = 735400, .val = 0x0b },
-	{ .rfmax = 753900, .val = 0x0a },
-	{ .rfmax = 772500, .val = 0x09 },
-	{ .rfmax = 791000, .val = 0x08 },
-	{ .rfmax = 809500, .val = 0x07 },
-	{ .rfmax = 828000, .val = 0x06 },
-	{ .rfmax = 846500, .val = 0x05 },
-	{ .rfmax = 865000, .val = 0x04 },
-	{ .rfmax =      0, .val = 0x00 }, /* end */
-};
-
-static struct tda18271_map tda18271c1_rf_cal[] = {
-	{ .rfmax = 41000, .val = 0x1e },
-	{ .rfmax = 43000, .val = 0x30 },
-	{ .rfmax = 45000, .val = 0x43 },
-	{ .rfmax = 46000, .val = 0x4d },
-	{ .rfmax = 47000, .val = 0x54 },
-	{ .rfmax = 47900, .val = 0x64 },
-	{ .rfmax = 49100, .val = 0x20 },
-	{ .rfmax = 50000, .val = 0x22 },
-	{ .rfmax = 51000, .val = 0x2a },
-	{ .rfmax = 53000, .val = 0x32 },
-	{ .rfmax = 55000, .val = 0x35 },
-	{ .rfmax = 56000, .val = 0x3c },
-	{ .rfmax = 57000, .val = 0x3f },
-	{ .rfmax = 58000, .val = 0x48 },
-	{ .rfmax = 59000, .val = 0x4d },
-	{ .rfmax = 60000, .val = 0x58 },
-	{ .rfmax = 61100, .val = 0x5f },
-	{ .rfmax =     0, .val = 0x00 }, /* end */
-};
-
-static struct tda18271_map tda18271c2_rf_cal[] = {
-	{ .rfmax =  41000, .val = 0x0f },
-	{ .rfmax =  43000, .val = 0x1c },
-	{ .rfmax =  45000, .val = 0x2f },
-	{ .rfmax =  46000, .val = 0x39 },
-	{ .rfmax =  47000, .val = 0x40 },
-	{ .rfmax =  47900, .val = 0x50 },
-	{ .rfmax =  49100, .val = 0x16 },
-	{ .rfmax =  50000, .val = 0x18 },
-	{ .rfmax =  51000, .val = 0x20 },
-	{ .rfmax =  53000, .val = 0x28 },
-	{ .rfmax =  55000, .val = 0x2b },
-	{ .rfmax =  56000, .val = 0x32 },
-	{ .rfmax =  57000, .val = 0x35 },
-	{ .rfmax =  58000, .val = 0x3e },
-	{ .rfmax =  59000, .val = 0x43 },
-	{ .rfmax =  60000, .val = 0x4e },
-	{ .rfmax =  61100, .val = 0x55 },
-	{ .rfmax =  63000, .val = 0x0f },
-	{ .rfmax =  64000, .val = 0x11 },
-	{ .rfmax =  65000, .val = 0x12 },
-	{ .rfmax =  66000, .val = 0x15 },
-	{ .rfmax =  67000, .val = 0x16 },
-	{ .rfmax =  68000, .val = 0x17 },
-	{ .rfmax =  70000, .val = 0x19 },
-	{ .rfmax =  71000, .val = 0x1c },
-	{ .rfmax =  72000, .val = 0x1d },
-	{ .rfmax =  73000, .val = 0x1f },
-	{ .rfmax =  74000, .val = 0x20 },
-	{ .rfmax =  75000, .val = 0x21 },
-	{ .rfmax =  76000, .val = 0x24 },
-	{ .rfmax =  77000, .val = 0x25 },
-	{ .rfmax =  78000, .val = 0x27 },
-	{ .rfmax =  80000, .val = 0x28 },
-	{ .rfmax =  81000, .val = 0x29 },
-	{ .rfmax =  82000, .val = 0x2d },
-	{ .rfmax =  83000, .val = 0x2e },
-	{ .rfmax =  84000, .val = 0x2f },
-	{ .rfmax =  85000, .val = 0x31 },
-	{ .rfmax =  86000, .val = 0x33 },
-	{ .rfmax =  87000, .val = 0x34 },
-	{ .rfmax =  88000, .val = 0x35 },
-	{ .rfmax =  89000, .val = 0x37 },
-	{ .rfmax =  90000, .val = 0x38 },
-	{ .rfmax =  91000, .val = 0x39 },
-	{ .rfmax =  93000, .val = 0x3c },
-	{ .rfmax =  94000, .val = 0x3e },
-	{ .rfmax =  95000, .val = 0x3f },
-	{ .rfmax =  96000, .val = 0x40 },
-	{ .rfmax =  97000, .val = 0x42 },
-	{ .rfmax =  99000, .val = 0x45 },
-	{ .rfmax = 100000, .val = 0x46 },
-	{ .rfmax = 102000, .val = 0x48 },
-	{ .rfmax = 103000, .val = 0x4a },
-	{ .rfmax = 105000, .val = 0x4d },
-	{ .rfmax = 106000, .val = 0x4e },
-	{ .rfmax = 107000, .val = 0x50 },
-	{ .rfmax = 108000, .val = 0x51 },
-	{ .rfmax = 110000, .val = 0x54 },
-	{ .rfmax = 111000, .val = 0x56 },
-	{ .rfmax = 112000, .val = 0x57 },
-	{ .rfmax = 113000, .val = 0x58 },
-	{ .rfmax = 114000, .val = 0x59 },
-	{ .rfmax = 115000, .val = 0x5c },
-	{ .rfmax = 116000, .val = 0x5d },
-	{ .rfmax = 117000, .val = 0x5f },
-	{ .rfmax = 119000, .val = 0x60 },
-	{ .rfmax = 120000, .val = 0x64 },
-	{ .rfmax = 121000, .val = 0x65 },
-	{ .rfmax = 122000, .val = 0x66 },
-	{ .rfmax = 123000, .val = 0x68 },
-	{ .rfmax = 124000, .val = 0x69 },
-	{ .rfmax = 125000, .val = 0x6c },
-	{ .rfmax = 126000, .val = 0x6d },
-	{ .rfmax = 127000, .val = 0x6e },
-	{ .rfmax = 128000, .val = 0x70 },
-	{ .rfmax = 129000, .val = 0x71 },
-	{ .rfmax = 130000, .val = 0x75 },
-	{ .rfmax = 131000, .val = 0x77 },
-	{ .rfmax = 132000, .val = 0x78 },
-	{ .rfmax = 133000, .val = 0x7b },
-	{ .rfmax = 134000, .val = 0x7e },
-	{ .rfmax = 135000, .val = 0x81 },
-	{ .rfmax = 136000, .val = 0x82 },
-	{ .rfmax = 137000, .val = 0x87 },
-	{ .rfmax = 138000, .val = 0x88 },
-	{ .rfmax = 139000, .val = 0x8d },
-	{ .rfmax = 140000, .val = 0x8e },
-	{ .rfmax = 141000, .val = 0x91 },
-	{ .rfmax = 142000, .val = 0x95 },
-	{ .rfmax = 143000, .val = 0x9a },
-	{ .rfmax = 144000, .val = 0x9d },
-	{ .rfmax = 145000, .val = 0xa1 },
-	{ .rfmax = 146000, .val = 0xa2 },
-	{ .rfmax = 147000, .val = 0xa4 },
-	{ .rfmax = 148000, .val = 0xa9 },
-	{ .rfmax = 149000, .val = 0xae },
-	{ .rfmax = 150000, .val = 0xb0 },
-	{ .rfmax = 151000, .val = 0xb1 },
-	{ .rfmax = 152000, .val = 0xb7 },
-	{ .rfmax = 152600, .val = 0xbd },
-	{ .rfmax = 154000, .val = 0x20 },
-	{ .rfmax = 155000, .val = 0x22 },
-	{ .rfmax = 156000, .val = 0x24 },
-	{ .rfmax = 157000, .val = 0x25 },
-	{ .rfmax = 158000, .val = 0x27 },
-	{ .rfmax = 159000, .val = 0x29 },
-	{ .rfmax = 160000, .val = 0x2c },
-	{ .rfmax = 161000, .val = 0x2d },
-	{ .rfmax = 163000, .val = 0x2e },
-	{ .rfmax = 164000, .val = 0x2f },
-	{ .rfmax = 164700, .val = 0x30 },
-	{ .rfmax = 166000, .val = 0x11 },
-	{ .rfmax = 167000, .val = 0x12 },
-	{ .rfmax = 168000, .val = 0x13 },
-	{ .rfmax = 169000, .val = 0x14 },
-	{ .rfmax = 170000, .val = 0x15 },
-	{ .rfmax = 172000, .val = 0x16 },
-	{ .rfmax = 173000, .val = 0x17 },
-	{ .rfmax = 174000, .val = 0x18 },
-	{ .rfmax = 175000, .val = 0x1a },
-	{ .rfmax = 176000, .val = 0x1b },
-	{ .rfmax = 178000, .val = 0x1d },
-	{ .rfmax = 179000, .val = 0x1e },
-	{ .rfmax = 180000, .val = 0x1f },
-	{ .rfmax = 181000, .val = 0x20 },
-	{ .rfmax = 182000, .val = 0x21 },
-	{ .rfmax = 183000, .val = 0x22 },
-	{ .rfmax = 184000, .val = 0x24 },
-	{ .rfmax = 185000, .val = 0x25 },
-	{ .rfmax = 186000, .val = 0x26 },
-	{ .rfmax = 187000, .val = 0x27 },
-	{ .rfmax = 188000, .val = 0x29 },
-	{ .rfmax = 189000, .val = 0x2a },
-	{ .rfmax = 190000, .val = 0x2c },
-	{ .rfmax = 191000, .val = 0x2d },
-	{ .rfmax = 192000, .val = 0x2e },
-	{ .rfmax = 193000, .val = 0x2f },
-	{ .rfmax = 194000, .val = 0x30 },
-	{ .rfmax = 195000, .val = 0x33 },
-	{ .rfmax = 196000, .val = 0x35 },
-	{ .rfmax = 198000, .val = 0x36 },
-	{ .rfmax = 200000, .val = 0x38 },
-	{ .rfmax = 201000, .val = 0x3c },
-	{ .rfmax = 202000, .val = 0x3d },
-	{ .rfmax = 203500, .val = 0x3e },
-	{ .rfmax = 206000, .val = 0x0e },
-	{ .rfmax = 208000, .val = 0x0f },
-	{ .rfmax = 212000, .val = 0x10 },
-	{ .rfmax = 216000, .val = 0x11 },
-	{ .rfmax = 217000, .val = 0x12 },
-	{ .rfmax = 218000, .val = 0x13 },
-	{ .rfmax = 220000, .val = 0x14 },
-	{ .rfmax = 222000, .val = 0x15 },
-	{ .rfmax = 225000, .val = 0x16 },
-	{ .rfmax = 228000, .val = 0x17 },
-	{ .rfmax = 231000, .val = 0x18 },
-	{ .rfmax = 234000, .val = 0x19 },
-	{ .rfmax = 235000, .val = 0x1a },
-	{ .rfmax = 236000, .val = 0x1b },
-	{ .rfmax = 237000, .val = 0x1c },
-	{ .rfmax = 240000, .val = 0x1d },
-	{ .rfmax = 242000, .val = 0x1e },
-	{ .rfmax = 244000, .val = 0x1f },
-	{ .rfmax = 247000, .val = 0x20 },
-	{ .rfmax = 249000, .val = 0x21 },
-	{ .rfmax = 252000, .val = 0x22 },
-	{ .rfmax = 253000, .val = 0x23 },
-	{ .rfmax = 254000, .val = 0x24 },
-	{ .rfmax = 256000, .val = 0x25 },
-	{ .rfmax = 259000, .val = 0x26 },
-	{ .rfmax = 262000, .val = 0x27 },
-	{ .rfmax = 264000, .val = 0x28 },
-	{ .rfmax = 267000, .val = 0x29 },
-	{ .rfmax = 269000, .val = 0x2a },
-	{ .rfmax = 271000, .val = 0x2b },
-	{ .rfmax = 273000, .val = 0x2c },
-	{ .rfmax = 275000, .val = 0x2d },
-	{ .rfmax = 277000, .val = 0x2e },
-	{ .rfmax = 279000, .val = 0x2f },
-	{ .rfmax = 282000, .val = 0x30 },
-	{ .rfmax = 284000, .val = 0x31 },
-	{ .rfmax = 286000, .val = 0x32 },
-	{ .rfmax = 287000, .val = 0x33 },
-	{ .rfmax = 290000, .val = 0x34 },
-	{ .rfmax = 293000, .val = 0x35 },
-	{ .rfmax = 295000, .val = 0x36 },
-	{ .rfmax = 297000, .val = 0x37 },
-	{ .rfmax = 300000, .val = 0x38 },
-	{ .rfmax = 303000, .val = 0x39 },
-	{ .rfmax = 305000, .val = 0x3a },
-	{ .rfmax = 306000, .val = 0x3b },
-	{ .rfmax = 307000, .val = 0x3c },
-	{ .rfmax = 310000, .val = 0x3d },
-	{ .rfmax = 312000, .val = 0x3e },
-	{ .rfmax = 315000, .val = 0x3f },
-	{ .rfmax = 318000, .val = 0x40 },
-	{ .rfmax = 320000, .val = 0x41 },
-	{ .rfmax = 323000, .val = 0x42 },
-	{ .rfmax = 324000, .val = 0x43 },
-	{ .rfmax = 325000, .val = 0x44 },
-	{ .rfmax = 327000, .val = 0x45 },
-	{ .rfmax = 331000, .val = 0x46 },
-	{ .rfmax = 334000, .val = 0x47 },
-	{ .rfmax = 337000, .val = 0x48 },
-	{ .rfmax = 339000, .val = 0x49 },
-	{ .rfmax = 340000, .val = 0x4a },
-	{ .rfmax = 341000, .val = 0x4b },
-	{ .rfmax = 343000, .val = 0x4c },
-	{ .rfmax = 345000, .val = 0x4d },
-	{ .rfmax = 349000, .val = 0x4e },
-	{ .rfmax = 352000, .val = 0x4f },
-	{ .rfmax = 353000, .val = 0x50 },
-	{ .rfmax = 355000, .val = 0x51 },
-	{ .rfmax = 357000, .val = 0x52 },
-	{ .rfmax = 359000, .val = 0x53 },
-	{ .rfmax = 361000, .val = 0x54 },
-	{ .rfmax = 362000, .val = 0x55 },
-	{ .rfmax = 364000, .val = 0x56 },
-	{ .rfmax = 368000, .val = 0x57 },
-	{ .rfmax = 370000, .val = 0x58 },
-	{ .rfmax = 372000, .val = 0x59 },
-	{ .rfmax = 375000, .val = 0x5a },
-	{ .rfmax = 376000, .val = 0x5b },
-	{ .rfmax = 377000, .val = 0x5c },
-	{ .rfmax = 379000, .val = 0x5d },
-	{ .rfmax = 382000, .val = 0x5e },
-	{ .rfmax = 384000, .val = 0x5f },
-	{ .rfmax = 385000, .val = 0x60 },
-	{ .rfmax = 386000, .val = 0x61 },
-	{ .rfmax = 388000, .val = 0x62 },
-	{ .rfmax = 390000, .val = 0x63 },
-	{ .rfmax = 393000, .val = 0x64 },
-	{ .rfmax = 394000, .val = 0x65 },
-	{ .rfmax = 396000, .val = 0x66 },
-	{ .rfmax = 397000, .val = 0x67 },
-	{ .rfmax = 398000, .val = 0x68 },
-	{ .rfmax = 400000, .val = 0x69 },
-	{ .rfmax = 402000, .val = 0x6a },
-	{ .rfmax = 403000, .val = 0x6b },
-	{ .rfmax = 407000, .val = 0x6c },
-	{ .rfmax = 408000, .val = 0x6d },
-	{ .rfmax = 409000, .val = 0x6e },
-	{ .rfmax = 410000, .val = 0x6f },
-	{ .rfmax = 411000, .val = 0x70 },
-	{ .rfmax = 412000, .val = 0x71 },
-	{ .rfmax = 413000, .val = 0x72 },
-	{ .rfmax = 414000, .val = 0x73 },
-	{ .rfmax = 417000, .val = 0x74 },
-	{ .rfmax = 418000, .val = 0x75 },
-	{ .rfmax = 420000, .val = 0x76 },
-	{ .rfmax = 422000, .val = 0x77 },
-	{ .rfmax = 423000, .val = 0x78 },
-	{ .rfmax = 424000, .val = 0x79 },
-	{ .rfmax = 427000, .val = 0x7a },
-	{ .rfmax = 428000, .val = 0x7b },
-	{ .rfmax = 429000, .val = 0x7d },
-	{ .rfmax = 432000, .val = 0x7f },
-	{ .rfmax = 434000, .val = 0x80 },
-	{ .rfmax = 435000, .val = 0x81 },
-	{ .rfmax = 436000, .val = 0x83 },
-	{ .rfmax = 437000, .val = 0x84 },
-	{ .rfmax = 438000, .val = 0x85 },
-	{ .rfmax = 439000, .val = 0x86 },
-	{ .rfmax = 440000, .val = 0x87 },
-	{ .rfmax = 441000, .val = 0x88 },
-	{ .rfmax = 442000, .val = 0x89 },
-	{ .rfmax = 445000, .val = 0x8a },
-	{ .rfmax = 446000, .val = 0x8b },
-	{ .rfmax = 447000, .val = 0x8c },
-	{ .rfmax = 448000, .val = 0x8e },
-	{ .rfmax = 449000, .val = 0x8f },
-	{ .rfmax = 450000, .val = 0x90 },
-	{ .rfmax = 452000, .val = 0x91 },
-	{ .rfmax = 453000, .val = 0x93 },
-	{ .rfmax = 454000, .val = 0x94 },
-	{ .rfmax = 456000, .val = 0x96 },
-	{ .rfmax = 457800, .val = 0x98 },
-	{ .rfmax = 461000, .val = 0x11 },
-	{ .rfmax = 468000, .val = 0x12 },
-	{ .rfmax = 472000, .val = 0x13 },
-	{ .rfmax = 473000, .val = 0x14 },
-	{ .rfmax = 474000, .val = 0x15 },
-	{ .rfmax = 481000, .val = 0x16 },
-	{ .rfmax = 486000, .val = 0x17 },
-	{ .rfmax = 491000, .val = 0x18 },
-	{ .rfmax = 498000, .val = 0x19 },
-	{ .rfmax = 499000, .val = 0x1a },
-	{ .rfmax = 501000, .val = 0x1b },
-	{ .rfmax = 506000, .val = 0x1c },
-	{ .rfmax = 511000, .val = 0x1d },
-	{ .rfmax = 516000, .val = 0x1e },
-	{ .rfmax = 520000, .val = 0x1f },
-	{ .rfmax = 521000, .val = 0x20 },
-	{ .rfmax = 525000, .val = 0x21 },
-	{ .rfmax = 529000, .val = 0x22 },
-	{ .rfmax = 533000, .val = 0x23 },
-	{ .rfmax = 539000, .val = 0x24 },
-	{ .rfmax = 541000, .val = 0x25 },
-	{ .rfmax = 547000, .val = 0x26 },
-	{ .rfmax = 549000, .val = 0x27 },
-	{ .rfmax = 551000, .val = 0x28 },
-	{ .rfmax = 556000, .val = 0x29 },
-	{ .rfmax = 561000, .val = 0x2a },
-	{ .rfmax = 563000, .val = 0x2b },
-	{ .rfmax = 565000, .val = 0x2c },
-	{ .rfmax = 569000, .val = 0x2d },
-	{ .rfmax = 571000, .val = 0x2e },
-	{ .rfmax = 577000, .val = 0x2f },
-	{ .rfmax = 580000, .val = 0x30 },
-	{ .rfmax = 582000, .val = 0x31 },
-	{ .rfmax = 584000, .val = 0x32 },
-	{ .rfmax = 588000, .val = 0x33 },
-	{ .rfmax = 591000, .val = 0x34 },
-	{ .rfmax = 596000, .val = 0x35 },
-	{ .rfmax = 598000, .val = 0x36 },
-	{ .rfmax = 603000, .val = 0x37 },
-	{ .rfmax = 604000, .val = 0x38 },
-	{ .rfmax = 606000, .val = 0x39 },
-	{ .rfmax = 612000, .val = 0x3a },
-	{ .rfmax = 615000, .val = 0x3b },
-	{ .rfmax = 617000, .val = 0x3c },
-	{ .rfmax = 621000, .val = 0x3d },
-	{ .rfmax = 622000, .val = 0x3e },
-	{ .rfmax = 625000, .val = 0x3f },
-	{ .rfmax = 632000, .val = 0x40 },
-	{ .rfmax = 633000, .val = 0x41 },
-	{ .rfmax = 634000, .val = 0x42 },
-	{ .rfmax = 642000, .val = 0x43 },
-	{ .rfmax = 643000, .val = 0x44 },
-	{ .rfmax = 647000, .val = 0x45 },
-	{ .rfmax = 650000, .val = 0x46 },
-	{ .rfmax = 652000, .val = 0x47 },
-	{ .rfmax = 657000, .val = 0x48 },
-	{ .rfmax = 661000, .val = 0x49 },
-	{ .rfmax = 662000, .val = 0x4a },
-	{ .rfmax = 665000, .val = 0x4b },
-	{ .rfmax = 667000, .val = 0x4c },
-	{ .rfmax = 670000, .val = 0x4d },
-	{ .rfmax = 673000, .val = 0x4e },
-	{ .rfmax = 676000, .val = 0x4f },
-	{ .rfmax = 677000, .val = 0x50 },
-	{ .rfmax = 681000, .val = 0x51 },
-	{ .rfmax = 683000, .val = 0x52 },
-	{ .rfmax = 686000, .val = 0x53 },
-	{ .rfmax = 688000, .val = 0x54 },
-	{ .rfmax = 689000, .val = 0x55 },
-	{ .rfmax = 691000, .val = 0x56 },
-	{ .rfmax = 695000, .val = 0x57 },
-	{ .rfmax = 698000, .val = 0x58 },
-	{ .rfmax = 703000, .val = 0x59 },
-	{ .rfmax = 704000, .val = 0x5a },
-	{ .rfmax = 705000, .val = 0x5b },
-	{ .rfmax = 707000, .val = 0x5c },
-	{ .rfmax = 710000, .val = 0x5d },
-	{ .rfmax = 712000, .val = 0x5e },
-	{ .rfmax = 717000, .val = 0x5f },
-	{ .rfmax = 718000, .val = 0x60 },
-	{ .rfmax = 721000, .val = 0x61 },
-	{ .rfmax = 722000, .val = 0x62 },
-	{ .rfmax = 723000, .val = 0x63 },
-	{ .rfmax = 725000, .val = 0x64 },
-	{ .rfmax = 727000, .val = 0x65 },
-	{ .rfmax = 730000, .val = 0x66 },
-	{ .rfmax = 732000, .val = 0x67 },
-	{ .rfmax = 735000, .val = 0x68 },
-	{ .rfmax = 740000, .val = 0x69 },
-	{ .rfmax = 741000, .val = 0x6a },
-	{ .rfmax = 742000, .val = 0x6b },
-	{ .rfmax = 743000, .val = 0x6c },
-	{ .rfmax = 745000, .val = 0x6d },
-	{ .rfmax = 747000, .val = 0x6e },
-	{ .rfmax = 748000, .val = 0x6f },
-	{ .rfmax = 750000, .val = 0x70 },
-	{ .rfmax = 752000, .val = 0x71 },
-	{ .rfmax = 754000, .val = 0x72 },
-	{ .rfmax = 757000, .val = 0x73 },
-	{ .rfmax = 758000, .val = 0x74 },
-	{ .rfmax = 760000, .val = 0x75 },
-	{ .rfmax = 763000, .val = 0x76 },
-	{ .rfmax = 764000, .val = 0x77 },
-	{ .rfmax = 766000, .val = 0x78 },
-	{ .rfmax = 767000, .val = 0x79 },
-	{ .rfmax = 768000, .val = 0x7a },
-	{ .rfmax = 773000, .val = 0x7b },
-	{ .rfmax = 774000, .val = 0x7c },
-	{ .rfmax = 776000, .val = 0x7d },
-	{ .rfmax = 777000, .val = 0x7e },
-	{ .rfmax = 778000, .val = 0x7f },
-	{ .rfmax = 779000, .val = 0x80 },
-	{ .rfmax = 781000, .val = 0x81 },
-	{ .rfmax = 783000, .val = 0x82 },
-	{ .rfmax = 784000, .val = 0x83 },
-	{ .rfmax = 785000, .val = 0x84 },
-	{ .rfmax = 786000, .val = 0x85 },
-	{ .rfmax = 793000, .val = 0x86 },
-	{ .rfmax = 794000, .val = 0x87 },
-	{ .rfmax = 795000, .val = 0x88 },
-	{ .rfmax = 797000, .val = 0x89 },
-	{ .rfmax = 799000, .val = 0x8a },
-	{ .rfmax = 801000, .val = 0x8b },
-	{ .rfmax = 802000, .val = 0x8c },
-	{ .rfmax = 803000, .val = 0x8d },
-	{ .rfmax = 804000, .val = 0x8e },
-	{ .rfmax = 810000, .val = 0x90 },
-	{ .rfmax = 811000, .val = 0x91 },
-	{ .rfmax = 812000, .val = 0x92 },
-	{ .rfmax = 814000, .val = 0x93 },
-	{ .rfmax = 816000, .val = 0x94 },
-	{ .rfmax = 817000, .val = 0x96 },
-	{ .rfmax = 818000, .val = 0x97 },
-	{ .rfmax = 820000, .val = 0x98 },
-	{ .rfmax = 821000, .val = 0x99 },
-	{ .rfmax = 822000, .val = 0x9a },
-	{ .rfmax = 828000, .val = 0x9b },
-	{ .rfmax = 829000, .val = 0x9d },
-	{ .rfmax = 830000, .val = 0x9f },
-	{ .rfmax = 831000, .val = 0xa0 },
-	{ .rfmax = 833000, .val = 0xa1 },
-	{ .rfmax = 835000, .val = 0xa2 },
-	{ .rfmax = 836000, .val = 0xa3 },
-	{ .rfmax = 837000, .val = 0xa4 },
-	{ .rfmax = 838000, .val = 0xa6 },
-	{ .rfmax = 840000, .val = 0xa8 },
-	{ .rfmax = 842000, .val = 0xa9 },
-	{ .rfmax = 845000, .val = 0xaa },
-	{ .rfmax = 846000, .val = 0xab },
-	{ .rfmax = 847000, .val = 0xad },
-	{ .rfmax = 848000, .val = 0xae },
-	{ .rfmax = 852000, .val = 0xaf },
-	{ .rfmax = 853000, .val = 0xb0 },
-	{ .rfmax = 858000, .val = 0xb1 },
-	{ .rfmax = 860000, .val = 0xb2 },
-	{ .rfmax = 861000, .val = 0xb3 },
-	{ .rfmax = 862000, .val = 0xb4 },
-	{ .rfmax = 863000, .val = 0xb6 },
-	{ .rfmax = 864000, .val = 0xb8 },
-	{ .rfmax = 865000, .val = 0xb9 },
-	{ .rfmax =      0, .val = 0x00 }, /* end */
-};
-
-static struct tda18271_map tda18271_ir_measure[] = {
-	{ .rfmax =  30000, .val = 4 },
-	{ .rfmax = 200000, .val = 5 },
-	{ .rfmax = 600000, .val = 6 },
-	{ .rfmax = 865000, .val = 7 },
-	{ .rfmax =      0, .val = 0 }, /* end */
-};
-
-static struct tda18271_map tda18271_rf_cal_dc_over_dt[] = {
-	{ .rfmax =  47900, .val = 0x00 },
-	{ .rfmax =  55000, .val = 0x00 },
-	{ .rfmax =  61100, .val = 0x0a },
-	{ .rfmax =  64000, .val = 0x0a },
-	{ .rfmax =  82000, .val = 0x14 },
-	{ .rfmax =  84000, .val = 0x19 },
-	{ .rfmax = 119000, .val = 0x1c },
-	{ .rfmax = 124000, .val = 0x20 },
-	{ .rfmax = 129000, .val = 0x2a },
-	{ .rfmax = 134000, .val = 0x32 },
-	{ .rfmax = 139000, .val = 0x39 },
-	{ .rfmax = 144000, .val = 0x3e },
-	{ .rfmax = 149000, .val = 0x3f },
-	{ .rfmax = 152600, .val = 0x40 },
-	{ .rfmax = 154000, .val = 0x40 },
-	{ .rfmax = 164700, .val = 0x41 },
-	{ .rfmax = 203500, .val = 0x32 },
-	{ .rfmax = 353000, .val = 0x19 },
-	{ .rfmax = 356000, .val = 0x1a },
-	{ .rfmax = 359000, .val = 0x1b },
-	{ .rfmax = 363000, .val = 0x1c },
-	{ .rfmax = 366000, .val = 0x1d },
-	{ .rfmax = 369000, .val = 0x1e },
-	{ .rfmax = 373000, .val = 0x1f },
-	{ .rfmax = 376000, .val = 0x20 },
-	{ .rfmax = 379000, .val = 0x21 },
-	{ .rfmax = 383000, .val = 0x22 },
-	{ .rfmax = 386000, .val = 0x23 },
-	{ .rfmax = 389000, .val = 0x24 },
-	{ .rfmax = 393000, .val = 0x25 },
-	{ .rfmax = 396000, .val = 0x26 },
-	{ .rfmax = 399000, .val = 0x27 },
-	{ .rfmax = 402000, .val = 0x28 },
-	{ .rfmax = 404000, .val = 0x29 },
-	{ .rfmax = 407000, .val = 0x2a },
-	{ .rfmax = 409000, .val = 0x2b },
-	{ .rfmax = 412000, .val = 0x2c },
-	{ .rfmax = 414000, .val = 0x2d },
-	{ .rfmax = 417000, .val = 0x2e },
-	{ .rfmax = 419000, .val = 0x2f },
-	{ .rfmax = 422000, .val = 0x30 },
-	{ .rfmax = 424000, .val = 0x31 },
-	{ .rfmax = 427000, .val = 0x32 },
-	{ .rfmax = 429000, .val = 0x33 },
-	{ .rfmax = 432000, .val = 0x34 },
-	{ .rfmax = 434000, .val = 0x35 },
-	{ .rfmax = 437000, .val = 0x36 },
-	{ .rfmax = 439000, .val = 0x37 },
-	{ .rfmax = 442000, .val = 0x38 },
-	{ .rfmax = 444000, .val = 0x39 },
-	{ .rfmax = 447000, .val = 0x3a },
-	{ .rfmax = 449000, .val = 0x3b },
-	{ .rfmax = 457800, .val = 0x3c },
-	{ .rfmax = 465000, .val = 0x0f },
-	{ .rfmax = 477000, .val = 0x12 },
-	{ .rfmax = 483000, .val = 0x14 },
-	{ .rfmax = 502000, .val = 0x19 },
-	{ .rfmax = 508000, .val = 0x1b },
-	{ .rfmax = 519000, .val = 0x1c },
-	{ .rfmax = 522000, .val = 0x1d },
-	{ .rfmax = 524000, .val = 0x1e },
-	{ .rfmax = 534000, .val = 0x1f },
-	{ .rfmax = 549000, .val = 0x20 },
-	{ .rfmax = 554000, .val = 0x22 },
-	{ .rfmax = 584000, .val = 0x24 },
-	{ .rfmax = 589000, .val = 0x26 },
-	{ .rfmax = 658000, .val = 0x27 },
-	{ .rfmax = 664000, .val = 0x2c },
-	{ .rfmax = 669000, .val = 0x2d },
-	{ .rfmax = 699000, .val = 0x2e },
-	{ .rfmax = 704000, .val = 0x30 },
-	{ .rfmax = 709000, .val = 0x31 },
-	{ .rfmax = 714000, .val = 0x32 },
-	{ .rfmax = 724000, .val = 0x33 },
-	{ .rfmax = 729000, .val = 0x36 },
-	{ .rfmax = 739000, .val = 0x38 },
-	{ .rfmax = 744000, .val = 0x39 },
-	{ .rfmax = 749000, .val = 0x3b },
-	{ .rfmax = 754000, .val = 0x3c },
-	{ .rfmax = 759000, .val = 0x3d },
-	{ .rfmax = 764000, .val = 0x3e },
-	{ .rfmax = 769000, .val = 0x3f },
-	{ .rfmax = 774000, .val = 0x40 },
-	{ .rfmax = 779000, .val = 0x41 },
-	{ .rfmax = 784000, .val = 0x43 },
-	{ .rfmax = 789000, .val = 0x46 },
-	{ .rfmax = 794000, .val = 0x48 },
-	{ .rfmax = 799000, .val = 0x4b },
-	{ .rfmax = 804000, .val = 0x4f },
-	{ .rfmax = 809000, .val = 0x54 },
-	{ .rfmax = 814000, .val = 0x59 },
-	{ .rfmax = 819000, .val = 0x5d },
-	{ .rfmax = 824000, .val = 0x61 },
-	{ .rfmax = 829000, .val = 0x68 },
-	{ .rfmax = 834000, .val = 0x6e },
-	{ .rfmax = 839000, .val = 0x75 },
-	{ .rfmax = 844000, .val = 0x7e },
-	{ .rfmax = 849000, .val = 0x82 },
-	{ .rfmax = 854000, .val = 0x84 },
-	{ .rfmax = 859000, .val = 0x8f },
-	{ .rfmax = 865000, .val = 0x9a },
-	{ .rfmax =      0, .val = 0x00 }, /* end */
-};
-
-/*---------------------------------------------------------------------*/
-
-struct tda18271_thermo_map {
-	u8 d;
-	u8 r0;
-	u8 r1;
-};
-
-static struct tda18271_thermo_map tda18271_thermometer[] = {
-	{ .d = 0x00, .r0 = 60, .r1 =  92 },
-	{ .d = 0x01, .r0 = 62, .r1 =  94 },
-	{ .d = 0x02, .r0 = 66, .r1 =  98 },
-	{ .d = 0x03, .r0 = 64, .r1 =  96 },
-	{ .d = 0x04, .r0 = 74, .r1 = 106 },
-	{ .d = 0x05, .r0 = 72, .r1 = 104 },
-	{ .d = 0x06, .r0 = 68, .r1 = 100 },
-	{ .d = 0x07, .r0 = 70, .r1 = 102 },
-	{ .d = 0x08, .r0 = 90, .r1 = 122 },
-	{ .d = 0x09, .r0 = 88, .r1 = 120 },
-	{ .d = 0x0a, .r0 = 84, .r1 = 116 },
-	{ .d = 0x0b, .r0 = 86, .r1 = 118 },
-	{ .d = 0x0c, .r0 = 76, .r1 = 108 },
-	{ .d = 0x0d, .r0 = 78, .r1 = 110 },
-	{ .d = 0x0e, .r0 = 82, .r1 = 114 },
-	{ .d = 0x0f, .r0 = 80, .r1 = 112 },
-	{ .d = 0x00, .r0 =  0, .r1 =   0 }, /* end */
-};
-
-int tda18271_lookup_thermometer(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-	int val, i = 0;
-
-	while (tda18271_thermometer[i].d < (regs[R_TM] & 0x0f)) {
-		if (tda18271_thermometer[i + 1].d == 0)
-			break;
-		i++;
-	}
-
-	if ((regs[R_TM] & 0x20) == 0x20)
-		val = tda18271_thermometer[i].r1;
-	else
-		val = tda18271_thermometer[i].r0;
-
-	tda_map("(%d) tm = %d\n", i, val);
-
-	return val;
-}
-
-/*---------------------------------------------------------------------*/
-
-struct tda18271_cid_target_map {
-	u32 rfmax;
-	u8  target;
-	u16 limit;
-};
-
-static struct tda18271_cid_target_map tda18271_cid_target[] = {
-	{ .rfmax =  46000, .target = 0x04, .limit =  1800 },
-	{ .rfmax =  52200, .target = 0x0a, .limit =  1500 },
-	{ .rfmax =  70100, .target = 0x01, .limit =  4000 },
-	{ .rfmax = 136800, .target = 0x18, .limit =  4000 },
-	{ .rfmax = 156700, .target = 0x18, .limit =  4000 },
-	{ .rfmax = 186250, .target = 0x0a, .limit =  4000 },
-	{ .rfmax = 230000, .target = 0x0a, .limit =  4000 },
-	{ .rfmax = 345000, .target = 0x18, .limit =  4000 },
-	{ .rfmax = 426000, .target = 0x0e, .limit =  4000 },
-	{ .rfmax = 489500, .target = 0x1e, .limit =  4000 },
-	{ .rfmax = 697500, .target = 0x32, .limit =  4000 },
-	{ .rfmax = 842000, .target = 0x3a, .limit =  4000 },
-	{ .rfmax =      0, .target = 0x00, .limit =     0 }, /* end */
-};
-
-int tda18271_lookup_cid_target(struct dvb_frontend *fe,
-			       u32 *freq, u8 *cid_target, u16 *count_limit)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	int i = 0;
-
-	while ((tda18271_cid_target[i].rfmax * 1000) < *freq) {
-		if (tda18271_cid_target[i + 1].rfmax == 0)
-			break;
-		i++;
-	}
-	*cid_target  = tda18271_cid_target[i].target;
-	*count_limit = tda18271_cid_target[i].limit;
-
-	tda_map("(%d) cid_target = %02x, count_limit = %d\n", i,
-		tda18271_cid_target[i].target, tda18271_cid_target[i].limit);
-
-	return 0;
-}
-
-/*---------------------------------------------------------------------*/
-
-static struct tda18271_rf_tracking_filter_cal tda18271_rf_band_template[] = {
-	{ .rfmax =  47900, .rfband = 0x00,
-	  .rf1_def =  46000, .rf2_def =      0, .rf3_def =      0 },
-	{ .rfmax =  61100, .rfband = 0x01,
-	  .rf1_def =  52200, .rf2_def =      0, .rf3_def =      0 },
-	{ .rfmax = 152600, .rfband = 0x02,
-	  .rf1_def =  70100, .rf2_def = 136800, .rf3_def =      0 },
-	{ .rfmax = 164700, .rfband = 0x03,
-	  .rf1_def = 156700, .rf2_def =      0, .rf3_def =      0 },
-	{ .rfmax = 203500, .rfband = 0x04,
-	  .rf1_def = 186250, .rf2_def =      0, .rf3_def =      0 },
-	{ .rfmax = 457800, .rfband = 0x05,
-	  .rf1_def = 230000, .rf2_def = 345000, .rf3_def = 426000 },
-	{ .rfmax = 865000, .rfband = 0x06,
-	  .rf1_def = 489500, .rf2_def = 697500, .rf3_def = 842000 },
-	{ .rfmax =      0, .rfband = 0x00,
-	  .rf1_def =      0, .rf2_def =      0, .rf3_def =      0 }, /* end */
-};
-
-int tda18271_lookup_rf_band(struct dvb_frontend *fe, u32 *freq, u8 *rf_band)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
-	int i = 0;
-
-	while ((map[i].rfmax * 1000) < *freq) {
-		if (tda18271_debug & DBG_ADV)
-			tda_map("(%d) rfmax = %d < freq = %d, "
-				"rf1_def = %d, rf2_def = %d, rf3_def = %d, "
-				"rf1 = %d, rf2 = %d, rf3 = %d, "
-				"rf_a1 = %d, rf_a2 = %d, "
-				"rf_b1 = %d, rf_b2 = %d\n",
-				i, map[i].rfmax * 1000, *freq,
-				map[i].rf1_def, map[i].rf2_def, map[i].rf3_def,
-				map[i].rf1, map[i].rf2, map[i].rf3,
-				map[i].rf_a1, map[i].rf_a2,
-				map[i].rf_b1, map[i].rf_b2);
-		if (map[i].rfmax == 0)
-			return -EINVAL;
-		i++;
-	}
-	if (rf_band)
-		*rf_band = map[i].rfband;
-
-	tda_map("(%d) rf_band = %02x\n", i, map[i].rfband);
-
-	return i;
-}
-
-/*---------------------------------------------------------------------*/
-
-struct tda18271_map_layout {
-	struct tda18271_pll_map *main_pll;
-	struct tda18271_pll_map *cal_pll;
-
-	struct tda18271_map *rf_cal;
-	struct tda18271_map *rf_cal_kmco;
-	struct tda18271_map *rf_cal_dc_over_dt;
-
-	struct tda18271_map *bp_filter;
-	struct tda18271_map *rf_band;
-	struct tda18271_map *gain_taper;
-	struct tda18271_map *ir_measure;
-};
-
-/*---------------------------------------------------------------------*/
-
-int tda18271_lookup_pll_map(struct dvb_frontend *fe,
-			    enum tda18271_map_type map_type,
-			    u32 *freq, u8 *post_div, u8 *div)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	struct tda18271_pll_map *map = NULL;
-	unsigned int i = 0;
-	char *map_name;
-	int ret = 0;
-
-	BUG_ON(!priv->maps);
-
-	switch (map_type) {
-	case MAIN_PLL:
-		map = priv->maps->main_pll;
-		map_name = "main_pll";
-		break;
-	case CAL_PLL:
-		map = priv->maps->cal_pll;
-		map_name = "cal_pll";
-		break;
-	default:
-		/* we should never get here */
-		map_name = "undefined";
-		break;
-	}
-
-	if (!map) {
-		tda_warn("%s map is not set!\n", map_name);
-		ret = -EINVAL;
-		goto fail;
-	}
-
-	while ((map[i].lomax * 1000) < *freq) {
-		if (map[i + 1].lomax == 0) {
-			tda_map("%s: frequency (%d) out of range\n",
-				map_name, *freq);
-			ret = -ERANGE;
-			break;
-		}
-		i++;
-	}
-	*post_div = map[i].pd;
-	*div      = map[i].d;
-
-	tda_map("(%d) %s: post div = 0x%02x, div = 0x%02x\n",
-		i, map_name, *post_div, *div);
-fail:
-	return ret;
-}
-
-int tda18271_lookup_map(struct dvb_frontend *fe,
-			enum tda18271_map_type map_type,
-			u32 *freq, u8 *val)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	struct tda18271_map *map = NULL;
-	unsigned int i = 0;
-	char *map_name;
-	int ret = 0;
-
-	BUG_ON(!priv->maps);
-
-	switch (map_type) {
-	case BP_FILTER:
-		map = priv->maps->bp_filter;
-		map_name = "bp_filter";
-		break;
-	case RF_CAL_KMCO:
-		map = priv->maps->rf_cal_kmco;
-		map_name = "km";
-		break;
-	case RF_BAND:
-		map = priv->maps->rf_band;
-		map_name = "rf_band";
-		break;
-	case GAIN_TAPER:
-		map = priv->maps->gain_taper;
-		map_name = "gain_taper";
-		break;
-	case RF_CAL:
-		map = priv->maps->rf_cal;
-		map_name = "rf_cal";
-		break;
-	case IR_MEASURE:
-		map = priv->maps->ir_measure;
-		map_name = "ir_measure";
-		break;
-	case RF_CAL_DC_OVER_DT:
-		map = priv->maps->rf_cal_dc_over_dt;
-		map_name = "rf_cal_dc_over_dt";
-		break;
-	default:
-		/* we should never get here */
-		map_name = "undefined";
-		break;
-	}
-
-	if (!map) {
-		tda_warn("%s map is not set!\n", map_name);
-		ret = -EINVAL;
-		goto fail;
-	}
-
-	while ((map[i].rfmax * 1000) < *freq) {
-		if (map[i + 1].rfmax == 0) {
-			tda_map("%s: frequency (%d) out of range\n",
-				map_name, *freq);
-			ret = -ERANGE;
-			break;
-		}
-		i++;
-	}
-	*val = map[i].val;
-
-	tda_map("(%d) %s: 0x%02x\n", i, map_name, *val);
-fail:
-	return ret;
-}
-
-/*---------------------------------------------------------------------*/
-
-static struct tda18271_std_map tda18271c1_std_map = {
-	.fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0,
-		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */
-	.atv_b    = { .if_freq = 6750, .fm_rfn = 0, .agc_mode = 1, .std = 6,
-		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
-	.atv_dk   = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7,
-		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
-	.atv_gh   = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7,
-		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
-	.atv_i    = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7,
-		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
-	.atv_l    = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7,
-		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
-	.atv_lc   = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 7,
-		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
-	.atv_mn   = { .if_freq = 5750, .fm_rfn = 0, .agc_mode = 1, .std = 5,
-		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */
-	.atsc_6   = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4,
-		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
-	.dvbt_6   = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4,
-		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
-	.dvbt_7   = { .if_freq = 3800, .fm_rfn = 0, .agc_mode = 3, .std = 5,
-		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
-	.dvbt_8   = { .if_freq = 4300, .fm_rfn = 0, .agc_mode = 3, .std = 6,
-		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */
-	.qam_6    = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5,
-		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
-	.qam_7    = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6,
-		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */
-	.qam_8    = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7,
-		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */
-};
-
-static struct tda18271_std_map tda18271c2_std_map = {
-	.fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0,
-		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */
-	.atv_b    = { .if_freq = 6000, .fm_rfn = 0, .agc_mode = 1, .std = 5,
-		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */
-	.atv_dk   = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6,
-		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
-	.atv_gh   = { .if_freq = 7100, .fm_rfn = 0, .agc_mode = 1, .std = 6,
-		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
-	.atv_i    = { .if_freq = 7250, .fm_rfn = 0, .agc_mode = 1, .std = 6,
-		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
-	.atv_l    = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6,
-		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
-	.atv_lc   = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 6,
-		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
-	.atv_mn   = { .if_freq = 5400, .fm_rfn = 0, .agc_mode = 1, .std = 4,
-		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0c */
-	.atsc_6   = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4,
-		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
-	.dvbt_6   = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4,
-		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
-	.dvbt_7   = { .if_freq = 3500, .fm_rfn = 0, .agc_mode = 3, .std = 4,
-		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
-	.dvbt_8   = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5,
-		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
-	.qam_6    = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5,
-		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
-	.qam_7    = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6,
-		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */
-	.qam_8    = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7,
-		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */
-};
-
-/*---------------------------------------------------------------------*/
-
-static struct tda18271_map_layout tda18271c1_map_layout = {
-	.main_pll          = tda18271c1_main_pll,
-	.cal_pll           = tda18271c1_cal_pll,
-
-	.rf_cal            = tda18271c1_rf_cal,
-	.rf_cal_kmco       = tda18271c1_km,
-
-	.bp_filter         = tda18271_bp_filter,
-	.rf_band           = tda18271_rf_band,
-	.gain_taper        = tda18271_gain_taper,
-	.ir_measure        = tda18271_ir_measure,
-};
-
-static struct tda18271_map_layout tda18271c2_map_layout = {
-	.main_pll          = tda18271c2_main_pll,
-	.cal_pll           = tda18271c2_cal_pll,
-
-	.rf_cal            = tda18271c2_rf_cal,
-	.rf_cal_kmco       = tda18271c2_km,
-
-	.rf_cal_dc_over_dt = tda18271_rf_cal_dc_over_dt,
-
-	.bp_filter         = tda18271_bp_filter,
-	.rf_band           = tda18271_rf_band,
-	.gain_taper        = tda18271_gain_taper,
-	.ir_measure        = tda18271_ir_measure,
-};
-
-int tda18271_assign_map_layout(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-	int ret = 0;
-
-	switch (priv->id) {
-	case TDA18271HDC1:
-		priv->maps = &tda18271c1_map_layout;
-		memcpy(&priv->std, &tda18271c1_std_map,
-		       sizeof(struct tda18271_std_map));
-		break;
-	case TDA18271HDC2:
-		priv->maps = &tda18271c2_map_layout;
-		memcpy(&priv->std, &tda18271c2_std_map,
-		       sizeof(struct tda18271_std_map));
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	memcpy(priv->rf_cal_state, &tda18271_rf_band_template,
-	       sizeof(tda18271_rf_band_template));
-
-	return ret;
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/common/tuners/tda18271-priv.h b/drivers/media/common/tuners/tda18271-priv.h
deleted file mode 100644
index 454c152..0000000
--- a/drivers/media/common/tuners/tda18271-priv.h
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
-    tda18271-priv.h - private header for the NXP TDA18271 silicon tuner
-
-    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TDA18271_PRIV_H__
-#define __TDA18271_PRIV_H__
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/mutex.h>
-#include "tuner-i2c.h"
-#include "tda18271.h"
-
-#define R_ID     0x00	/* ID byte                */
-#define R_TM     0x01	/* Thermo byte            */
-#define R_PL     0x02	/* Power level byte       */
-#define R_EP1    0x03	/* Easy Prog byte 1       */
-#define R_EP2    0x04	/* Easy Prog byte 2       */
-#define R_EP3    0x05	/* Easy Prog byte 3       */
-#define R_EP4    0x06	/* Easy Prog byte 4       */
-#define R_EP5    0x07	/* Easy Prog byte 5       */
-#define R_CPD    0x08	/* Cal Post-Divider byte  */
-#define R_CD1    0x09	/* Cal Divider byte 1     */
-#define R_CD2    0x0a	/* Cal Divider byte 2     */
-#define R_CD3    0x0b	/* Cal Divider byte 3     */
-#define R_MPD    0x0c	/* Main Post-Divider byte */
-#define R_MD1    0x0d	/* Main Divider byte 1    */
-#define R_MD2    0x0e	/* Main Divider byte 2    */
-#define R_MD3    0x0f	/* Main Divider byte 3    */
-#define R_EB1    0x10	/* Extended byte 1        */
-#define R_EB2    0x11	/* Extended byte 2        */
-#define R_EB3    0x12	/* Extended byte 3        */
-#define R_EB4    0x13	/* Extended byte 4        */
-#define R_EB5    0x14	/* Extended byte 5        */
-#define R_EB6    0x15	/* Extended byte 6        */
-#define R_EB7    0x16	/* Extended byte 7        */
-#define R_EB8    0x17	/* Extended byte 8        */
-#define R_EB9    0x18	/* Extended byte 9        */
-#define R_EB10   0x19	/* Extended byte 10       */
-#define R_EB11   0x1a	/* Extended byte 11       */
-#define R_EB12   0x1b	/* Extended byte 12       */
-#define R_EB13   0x1c	/* Extended byte 13       */
-#define R_EB14   0x1d	/* Extended byte 14       */
-#define R_EB15   0x1e	/* Extended byte 15       */
-#define R_EB16   0x1f	/* Extended byte 16       */
-#define R_EB17   0x20	/* Extended byte 17       */
-#define R_EB18   0x21	/* Extended byte 18       */
-#define R_EB19   0x22	/* Extended byte 19       */
-#define R_EB20   0x23	/* Extended byte 20       */
-#define R_EB21   0x24	/* Extended byte 21       */
-#define R_EB22   0x25	/* Extended byte 22       */
-#define R_EB23   0x26	/* Extended byte 23       */
-
-#define TDA18271_NUM_REGS 39
-
-/*---------------------------------------------------------------------*/
-
-struct tda18271_rf_tracking_filter_cal {
-	u32 rfmax;
-	u8  rfband;
-	u32 rf1_def;
-	u32 rf2_def;
-	u32 rf3_def;
-	u32 rf1;
-	u32 rf2;
-	u32 rf3;
-	s32 rf_a1;
-	s32 rf_b1;
-	s32 rf_a2;
-	s32 rf_b2;
-};
-
-enum tda18271_pll {
-	TDA18271_MAIN_PLL,
-	TDA18271_CAL_PLL,
-};
-
-struct tda18271_map_layout;
-
-enum tda18271_ver {
-	TDA18271HDC1,
-	TDA18271HDC2,
-};
-
-struct tda18271_priv {
-	unsigned char tda18271_regs[TDA18271_NUM_REGS];
-
-	struct list_head	hybrid_tuner_instance_list;
-	struct tuner_i2c_props	i2c_props;
-
-	enum tda18271_mode mode;
-	enum tda18271_role role;
-	enum tda18271_i2c_gate gate;
-	enum tda18271_ver id;
-	enum tda18271_output_options output_opt;
-	enum tda18271_small_i2c small_i2c;
-
-	unsigned int config; /* interface to saa713x / tda829x */
-	unsigned int cal_initialized:1;
-
-	u8 tm_rfcal;
-
-	struct tda18271_map_layout *maps;
-	struct tda18271_std_map std;
-	struct tda18271_rf_tracking_filter_cal rf_cal_state[8];
-
-	struct mutex lock;
-
-	u16 if_freq;
-
-	u32 frequency;
-	u32 bandwidth;
-};
-
-/*---------------------------------------------------------------------*/
-
-extern int tda18271_debug;
-
-#define DBG_INFO 1
-#define DBG_MAP  2
-#define DBG_REG  4
-#define DBG_ADV  8
-#define DBG_CAL  16
-
-__attribute__((format(printf, 4, 5)))
-int _tda_printk(struct tda18271_priv *state, const char *level,
-		const char *func, const char *fmt, ...);
-
-#define tda_printk(st, lvl, fmt, arg...)			\
-	_tda_printk(st, lvl, __func__, fmt, ##arg)
-
-#define tda_dprintk(st, lvl, fmt, arg...)			\
-do {								\
-	if (tda18271_debug & lvl)				\
-		tda_printk(st, KERN_DEBUG, fmt, ##arg);		\
-} while (0)
-
-#define tda_info(fmt, arg...)	pr_info(fmt, ##arg)
-#define tda_warn(fmt, arg...)	tda_printk(priv, KERN_WARNING, fmt, ##arg)
-#define tda_err(fmt, arg...)	tda_printk(priv, KERN_ERR,     fmt, ##arg)
-#define tda_dbg(fmt, arg...)	tda_dprintk(priv, DBG_INFO,    fmt, ##arg)
-#define tda_map(fmt, arg...)	tda_dprintk(priv, DBG_MAP,     fmt, ##arg)
-#define tda_reg(fmt, arg...)	tda_dprintk(priv, DBG_REG,     fmt, ##arg)
-#define tda_cal(fmt, arg...)	tda_dprintk(priv, DBG_CAL,     fmt, ##arg)
-
-#define tda_fail(ret)							     \
-({									     \
-	int __ret;							     \
-	__ret = (ret < 0);						     \
-	if (__ret)							     \
-		tda_printk(priv, KERN_ERR,				     \
-			   "error %d on line %d\n", ret, __LINE__);	     \
-	__ret;								     \
-})
-
-/*---------------------------------------------------------------------*/
-
-enum tda18271_map_type {
-	/* tda18271_pll_map */
-	MAIN_PLL,
-	CAL_PLL,
-	/* tda18271_map */
-	RF_CAL,
-	RF_CAL_KMCO,
-	RF_CAL_DC_OVER_DT,
-	BP_FILTER,
-	RF_BAND,
-	GAIN_TAPER,
-	IR_MEASURE,
-};
-
-extern int tda18271_lookup_pll_map(struct dvb_frontend *fe,
-				   enum tda18271_map_type map_type,
-				   u32 *freq, u8 *post_div, u8 *div);
-extern int tda18271_lookup_map(struct dvb_frontend *fe,
-			       enum tda18271_map_type map_type,
-			       u32 *freq, u8 *val);
-
-extern int tda18271_lookup_thermometer(struct dvb_frontend *fe);
-
-extern int tda18271_lookup_rf_band(struct dvb_frontend *fe,
-				   u32 *freq, u8 *rf_band);
-
-extern int tda18271_lookup_cid_target(struct dvb_frontend *fe,
-				      u32 *freq, u8 *cid_target,
-				      u16 *count_limit);
-
-extern int tda18271_assign_map_layout(struct dvb_frontend *fe);
-
-/*---------------------------------------------------------------------*/
-
-extern int tda18271_read_regs(struct dvb_frontend *fe);
-extern int tda18271_read_extended(struct dvb_frontend *fe);
-extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len);
-extern int tda18271_init_regs(struct dvb_frontend *fe);
-
-extern int tda18271_charge_pump_source(struct dvb_frontend *fe,
-				       enum tda18271_pll pll, int force);
-extern int tda18271_set_standby_mode(struct dvb_frontend *fe,
-				     int sm, int sm_lt, int sm_xt);
-
-extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq);
-extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq);
-
-extern int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq);
-extern int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq);
-extern int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq);
-extern int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq);
-extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq);
-extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq);
-
-#endif /* __TDA18271_PRIV_H__ */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/common/tuners/tda18271.h b/drivers/media/common/tuners/tda18271.h
deleted file mode 100644
index 640bae4..0000000
--- a/drivers/media/common/tuners/tda18271.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
-    tda18271.h - header for the Philips / NXP TDA18271 silicon tuner
-
-    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TDA18271_H__
-#define __TDA18271_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-struct tda18271_std_map_item {
-	u16 if_freq;
-
-	/* EP3[4:3] */
-	unsigned int agc_mode:2;
-	/* EP3[2:0] */
-	unsigned int std:3;
-	/* EP4[7] */
-	unsigned int fm_rfn:1;
-	/* EP4[4:2] */
-	unsigned int if_lvl:3;
-	/* EB22[6:0] */
-	unsigned int rfagc_top:7;
-};
-
-struct tda18271_std_map {
-	struct tda18271_std_map_item fm_radio;
-	struct tda18271_std_map_item atv_b;
-	struct tda18271_std_map_item atv_dk;
-	struct tda18271_std_map_item atv_gh;
-	struct tda18271_std_map_item atv_i;
-	struct tda18271_std_map_item atv_l;
-	struct tda18271_std_map_item atv_lc;
-	struct tda18271_std_map_item atv_mn;
-	struct tda18271_std_map_item atsc_6;
-	struct tda18271_std_map_item dvbt_6;
-	struct tda18271_std_map_item dvbt_7;
-	struct tda18271_std_map_item dvbt_8;
-	struct tda18271_std_map_item qam_6;
-	struct tda18271_std_map_item qam_7;
-	struct tda18271_std_map_item qam_8;
-};
-
-enum tda18271_role {
-	TDA18271_MASTER = 0,
-	TDA18271_SLAVE,
-};
-
-enum tda18271_i2c_gate {
-	TDA18271_GATE_AUTO = 0,
-	TDA18271_GATE_ANALOG,
-	TDA18271_GATE_DIGITAL,
-};
-
-enum tda18271_output_options {
-	/* slave tuner output & loop thru & xtal oscillator always on */
-	TDA18271_OUTPUT_LT_XT_ON = 0,
-
-	/* slave tuner output loop thru off */
-	TDA18271_OUTPUT_LT_OFF = 1,
-
-	/* xtal oscillator off */
-	TDA18271_OUTPUT_XT_OFF = 2,
-};
-
-enum tda18271_small_i2c {
-	TDA18271_39_BYTE_CHUNK_INIT = 0,
-	TDA18271_16_BYTE_CHUNK_INIT = 16,
-	TDA18271_08_BYTE_CHUNK_INIT = 8,
-	TDA18271_03_BYTE_CHUNK_INIT = 3,
-};
-
-struct tda18271_config {
-	/* override default if freq / std settings (optional) */
-	struct tda18271_std_map *std_map;
-
-	/* master / slave tuner: master uses main pll, slave uses cal pll */
-	enum tda18271_role role;
-
-	/* use i2c gate provided by analog or digital demod */
-	enum tda18271_i2c_gate gate;
-
-	/* output options that can be disabled */
-	enum tda18271_output_options output_opt;
-
-	/* some i2c providers can't write all 39 registers at once */
-	enum tda18271_small_i2c small_i2c;
-
-	/* force rf tracking filter calibration on startup */
-	unsigned int rf_cal_on_startup:1;
-
-	/* interface to saa713x / tda829x */
-	unsigned int config;
-};
-
-#define TDA18271_CALLBACK_CMD_AGC_ENABLE 0
-
-enum tda18271_mode {
-	TDA18271_ANALOG = 0,
-	TDA18271_DIGITAL,
-};
-
-#if defined(CONFIG_MEDIA_TUNER_TDA18271) || (defined(CONFIG_MEDIA_TUNER_TDA18271_MODULE) && defined(MODULE))
-extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
-					    struct i2c_adapter *i2c,
-					    struct tda18271_config *cfg);
-#else
-static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe,
-						   u8 addr,
-						   struct i2c_adapter *i2c,
-						   struct tda18271_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* __TDA18271_H__ */
diff --git a/drivers/media/common/tuners/tda827x.c b/drivers/media/common/tuners/tda827x.c
deleted file mode 100644
index a0d1762..0000000
--- a/drivers/media/common/tuners/tda827x.c
+++ /dev/null
@@ -1,917 +0,0 @@
-/*
- *
- * (c) 2005 Hartmut Hackmann
- * (c) 2007 Michael Krufky
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <asm/types.h>
-#include <linux/dvb/frontend.h>
-#include <linux/videodev2.h>
-
-#include "tda827x.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-#define dprintk(args...) \
-	do {					    \
-		if (debug) printk(KERN_DEBUG "tda827x: " args); \
-	} while (0)
-
-struct tda827x_priv {
-	int i2c_addr;
-	struct i2c_adapter *i2c_adap;
-	struct tda827x_config *cfg;
-
-	unsigned int sgIF;
-	unsigned char lpsel;
-
-	u32 frequency;
-	u32 bandwidth;
-};
-
-static void tda827x_set_std(struct dvb_frontend *fe,
-			    struct analog_parameters *params)
-{
-	struct tda827x_priv *priv = fe->tuner_priv;
-	char *mode;
-
-	priv->lpsel = 0;
-	if (params->std & V4L2_STD_MN) {
-		priv->sgIF = 92;
-		priv->lpsel = 1;
-		mode = "MN";
-	} else if (params->std & V4L2_STD_B) {
-		priv->sgIF = 108;
-		mode = "B";
-	} else if (params->std & V4L2_STD_GH) {
-		priv->sgIF = 124;
-		mode = "GH";
-	} else if (params->std & V4L2_STD_PAL_I) {
-		priv->sgIF = 124;
-		mode = "I";
-	} else if (params->std & V4L2_STD_DK) {
-		priv->sgIF = 124;
-		mode = "DK";
-	} else if (params->std & V4L2_STD_SECAM_L) {
-		priv->sgIF = 124;
-		mode = "L";
-	} else if (params->std & V4L2_STD_SECAM_LC) {
-		priv->sgIF = 20;
-		mode = "LC";
-	} else {
-		priv->sgIF = 124;
-		mode = "xx";
-	}
-
-	if (params->mode == V4L2_TUNER_RADIO) {
-		priv->sgIF = 88; /* if frequency is 5.5 MHz */
-		dprintk("setting tda827x to radio FM\n");
-	} else
-		dprintk("setting tda827x to system %s\n", mode);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-struct tda827x_data {
-	u32 lomax;
-	u8  spd;
-	u8  bs;
-	u8  bp;
-	u8  cp;
-	u8  gc3;
-	u8 div1p5;
-};
-
-static const struct tda827x_data tda827x_table[] = {
-	{ .lomax =  62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
-	{ .lomax =  66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
-	{ .lomax =  76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
-	{ .lomax =  84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
-	{ .lomax =  93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax =  98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
-	{ .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
-	{ .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0},
-	{ .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
-	{ .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
-	{ .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
-	{ .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
-	{ .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
-	{ .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
-	{ .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
-	{ .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
-	{ .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
-	{ .lomax =         0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}
-};
-
-static int tuner_transfer(struct dvb_frontend *fe,
-			  struct i2c_msg *msg,
-			  const int size)
-{
-	int rc;
-	struct tda827x_priv *priv = fe->tuner_priv;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	rc = i2c_transfer(priv->i2c_adap, msg, size);
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	if (rc >= 0 && rc != size)
-		return -EIO;
-
-	return rc;
-}
-
-static int tda827xo_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct tda827x_priv *priv = fe->tuner_priv;
-	u8 buf[14];
-	int rc;
-
-	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
-			       .buf = buf, .len = sizeof(buf) };
-	int i, tuner_freq, if_freq;
-	u32 N;
-
-	dprintk("%s:\n", __func__);
-	if (c->bandwidth_hz == 0) {
-		if_freq = 5000000;
-	} else if (c->bandwidth_hz <= 6000000) {
-		if_freq = 4000000;
-	} else if (c->bandwidth_hz <= 7000000) {
-		if_freq = 4500000;
-	} else {	/* 8 MHz */
-		if_freq = 5000000;
-	}
-	tuner_freq = c->frequency;
-
-	i = 0;
-	while (tda827x_table[i].lomax < tuner_freq) {
-		if (tda827x_table[i + 1].lomax == 0)
-			break;
-		i++;
-	}
-
-	tuner_freq += if_freq;
-
-	N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2);
-	buf[0] = 0;
-	buf[1] = (N>>8) | 0x40;
-	buf[2] = N & 0xff;
-	buf[3] = 0;
-	buf[4] = 0x52;
-	buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) +
-				(tda827x_table[i].bs << 3) +
-				tda827x_table[i].bp;
-	buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f;
-	buf[7] = 0xbf;
-	buf[8] = 0x2a;
-	buf[9] = 0x05;
-	buf[10] = 0xff;
-	buf[11] = 0x00;
-	buf[12] = 0x00;
-	buf[13] = 0x40;
-
-	msg.len = 14;
-	rc = tuner_transfer(fe, &msg, 1);
-	if (rc < 0)
-		goto err;
-
-	msleep(500);
-	/* correct CP value */
-	buf[0] = 0x30;
-	buf[1] = 0x50 + tda827x_table[i].cp;
-	msg.len = 2;
-
-	rc = tuner_transfer(fe, &msg, 1);
-	if (rc < 0)
-		goto err;
-
-	priv->frequency = c->frequency;
-	priv->bandwidth = c->bandwidth_hz;
-
-	return 0;
-
-err:
-	printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n",
-	       __func__, priv->i2c_addr << 1);
-	return rc;
-}
-
-static int tda827xo_sleep(struct dvb_frontend *fe)
-{
-	struct tda827x_priv *priv = fe->tuner_priv;
-	static u8 buf[] = { 0x30, 0xd0 };
-	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
-			       .buf = buf, .len = sizeof(buf) };
-
-	dprintk("%s:\n", __func__);
-	tuner_transfer(fe, &msg, 1);
-
-	if (priv->cfg && priv->cfg->sleep)
-		priv->cfg->sleep(fe);
-
-	return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-static int tda827xo_set_analog_params(struct dvb_frontend *fe,
-				      struct analog_parameters *params)
-{
-	unsigned char tuner_reg[8];
-	unsigned char reg2[2];
-	u32 N;
-	int i;
-	struct tda827x_priv *priv = fe->tuner_priv;
-	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 };
-	unsigned int freq = params->frequency;
-
-	tda827x_set_std(fe, params);
-
-	if (params->mode == V4L2_TUNER_RADIO)
-		freq = freq / 1000;
-
-	N = freq + priv->sgIF;
-
-	i = 0;
-	while (tda827x_table[i].lomax < N * 62500) {
-		if (tda827x_table[i + 1].lomax == 0)
-			break;
-		i++;
-	}
-
-	N = N << tda827x_table[i].spd;
-
-	tuner_reg[0] = 0;
-	tuner_reg[1] = (unsigned char)(N>>8);
-	tuner_reg[2] = (unsigned char) N;
-	tuner_reg[3] = 0x40;
-	tuner_reg[4] = 0x52 + (priv->lpsel << 5);
-	tuner_reg[5] = (tda827x_table[i].spd    << 6) +
-		       (tda827x_table[i].div1p5 << 5) +
-		       (tda827x_table[i].bs     << 3) + tda827x_table[i].bp;
-	tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4);
-	tuner_reg[7] = 0x8f;
-
-	msg.buf = tuner_reg;
-	msg.len = 8;
-	tuner_transfer(fe, &msg, 1);
-
-	msg.buf = reg2;
-	msg.len = 2;
-	reg2[0] = 0x80;
-	reg2[1] = 0;
-	tuner_transfer(fe, &msg, 1);
-
-	reg2[0] = 0x60;
-	reg2[1] = 0xbf;
-	tuner_transfer(fe, &msg, 1);
-
-	reg2[0] = 0x30;
-	reg2[1] = tuner_reg[4] + 0x80;
-	tuner_transfer(fe, &msg, 1);
-
-	msleep(1);
-	reg2[0] = 0x30;
-	reg2[1] = tuner_reg[4] + 4;
-	tuner_transfer(fe, &msg, 1);
-
-	msleep(1);
-	reg2[0] = 0x30;
-	reg2[1] = tuner_reg[4];
-	tuner_transfer(fe, &msg, 1);
-
-	msleep(550);
-	reg2[0] = 0x30;
-	reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp;
-	tuner_transfer(fe, &msg, 1);
-
-	reg2[0] = 0x60;
-	reg2[1] = 0x3f;
-	tuner_transfer(fe, &msg, 1);
-
-	reg2[0] = 0x80;
-	reg2[1] = 0x08;   /* Vsync en */
-	tuner_transfer(fe, &msg, 1);
-
-	priv->frequency = params->frequency;
-
-	return 0;
-}
-
-static void tda827xo_agcf(struct dvb_frontend *fe)
-{
-	struct tda827x_priv *priv = fe->tuner_priv;
-	unsigned char data[] = { 0x80, 0x0c };
-	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
-			       .buf = data, .len = 2};
-
-	tuner_transfer(fe, &msg, 1);
-}
-
-/* ------------------------------------------------------------------ */
-
-struct tda827xa_data {
-	u32 lomax;
-	u8  svco;
-	u8  spd;
-	u8  scr;
-	u8  sbs;
-	u8  gc3;
-};
-
-static struct tda827xa_data tda827xa_dvbt[] = {
-	{ .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1},
-	{ .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
-	{ .lomax =  81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
-	{ .lomax =  97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
-	{ .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
-	{ .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-	{ .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-	{ .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-	{ .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-	{ .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
-	{ .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
-	{ .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
-	{ .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
-	{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
-	{ .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
-	{ .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
-	{ .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
-	{ .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
-	{ .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
-	{ .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
-	{ .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
-	{ .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
-	{ .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
-	{ .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
-	{ .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
-	{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
-	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
-};
-
-static struct tda827xa_data tda827xa_dvbc[] = {
-	{ .lomax =  50125000, .svco = 2, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3},
-	{ .lomax =  58500000, .svco = 3, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3},
-	{ .lomax =  69250000, .svco = 0, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
-	{ .lomax =  83625000, .svco = 1, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
-	{ .lomax =  97500000, .svco = 2, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
-	{ .lomax = 100250000, .svco = 2, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1},
-	{ .lomax = 117000000, .svco = 3, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1},
-	{ .lomax = 138500000, .svco = 0, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
-	{ .lomax = 167250000, .svco = 1, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
-	{ .lomax = 187000000, .svco = 2, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
-	{ .lomax = 200500000, .svco = 2, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 1},
-	{ .lomax = 234000000, .svco = 3, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 3},
-	{ .lomax = 277000000, .svco = 0, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 3},
-	{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 1},
-	{ .lomax = 334500000, .svco = 1, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3},
-	{ .lomax = 401000000, .svco = 2, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3},
-	{ .lomax = 468000000, .svco = 3, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 1},
-	{ .lomax = 535000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
-	{ .lomax = 554000000, .svco = 0, .spd = 0, .scr = 2, .sbs = 3, .gc3 = 1},
-	{ .lomax = 638000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
-	{ .lomax = 669000000, .svco = 1, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
-	{ .lomax = 720000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
-	{ .lomax = 802000000, .svco = 2, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
-	{ .lomax = 835000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
-	{ .lomax = 885000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
-	{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
-	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
-};
-
-static struct tda827xa_data tda827xa_analog[] = {
-	{ .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},
-	{ .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
-	{ .lomax =  81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
-	{ .lomax =  97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
-	{ .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
-	{ .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-	{ .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-	{ .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-	{ .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-	{ .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
-	{ .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3},
-	{ .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3},
-	{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
-	{ .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
-	{ .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
-	{ .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
-	{ .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
-	{ .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
-	{ .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
-	{ .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
-	{ .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
-	{ .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
-	{ .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
-	{ .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
-	{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
-	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
-};
-
-static int tda827xa_sleep(struct dvb_frontend *fe)
-{
-	struct tda827x_priv *priv = fe->tuner_priv;
-	static u8 buf[] = { 0x30, 0x90 };
-	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
-			       .buf = buf, .len = sizeof(buf) };
-
-	dprintk("%s:\n", __func__);
-
-	tuner_transfer(fe, &msg, 1);
-
-	if (priv->cfg && priv->cfg->sleep)
-		priv->cfg->sleep(fe);
-
-	return 0;
-}
-
-static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
-			      struct analog_parameters *params)
-{
-	struct tda827x_priv *priv = fe->tuner_priv;
-	unsigned char buf[] = {0x22, 0x01};
-	int arg;
-	int gp_func;
-	struct i2c_msg msg = { .flags = 0, .buf = buf, .len = sizeof(buf) };
-
-	if (NULL == priv->cfg) {
-		dprintk("tda827x_config not defined, cannot set LNA gain!\n");
-		return;
-	}
-	msg.addr = priv->cfg->switch_addr;
-	if (priv->cfg->config) {
-		if (high)
-			dprintk("setting LNA to high gain\n");
-		else
-			dprintk("setting LNA to low gain\n");
-	}
-	switch (priv->cfg->config) {
-	case 0: /* no LNA */
-		break;
-	case 1: /* switch is GPIO 0 of tda8290 */
-	case 2:
-		if (params == NULL) {
-			gp_func = 0;
-			arg  = 0;
-		} else {
-			/* turn Vsync on */
-			gp_func = 1;
-			if (params->std & V4L2_STD_MN)
-				arg = 1;
-			else
-				arg = 0;
-		}
-		if (fe->callback)
-			fe->callback(priv->i2c_adap->algo_data,
-				     DVB_FRONTEND_COMPONENT_TUNER,
-				     gp_func, arg);
-		buf[1] = high ? 0 : 1;
-		if (priv->cfg->config == 2)
-			buf[1] = high ? 1 : 0;
-		tuner_transfer(fe, &msg, 1);
-		break;
-	case 3: /* switch with GPIO of saa713x */
-		if (fe->callback)
-			fe->callback(priv->i2c_adap->algo_data,
-				     DVB_FRONTEND_COMPONENT_TUNER, 0, high);
-		break;
-	}
-}
-
-static int tda827xa_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct tda827x_priv *priv = fe->tuner_priv;
-	struct tda827xa_data *frequency_map = tda827xa_dvbt;
-	u8 buf[11];
-
-	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
-			       .buf = buf, .len = sizeof(buf) };
-
-	int i, tuner_freq, if_freq, rc;
-	u32 N;
-
-	dprintk("%s:\n", __func__);
-
-	tda827xa_lna_gain(fe, 1, NULL);
-	msleep(20);
-
-	if (c->bandwidth_hz == 0) {
-		if_freq = 5000000;
-	} else if (c->bandwidth_hz <= 6000000) {
-		if_freq = 4000000;
-	} else if (c->bandwidth_hz <= 7000000) {
-		if_freq = 4500000;
-	} else {	/* 8 MHz */
-		if_freq = 5000000;
-	}
-	tuner_freq = c->frequency;
-
-	switch (c->delivery_system) {
-	case SYS_DVBC_ANNEX_A:
-	case SYS_DVBC_ANNEX_C:
-		dprintk("%s select tda827xa_dvbc\n", __func__);
-		frequency_map = tda827xa_dvbc;
-		break;
-	default:
-		break;
-	}
-
-	i = 0;
-	while (frequency_map[i].lomax < tuner_freq) {
-		if (frequency_map[i + 1].lomax == 0)
-			break;
-		i++;
-	}
-
-	tuner_freq += if_freq;
-
-	N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd;
-	buf[0] = 0;            // subaddress
-	buf[1] = N >> 8;
-	buf[2] = N & 0xff;
-	buf[3] = 0;
-	buf[4] = 0x16;
-	buf[5] = (frequency_map[i].spd << 5) + (frequency_map[i].svco << 3) +
-			frequency_map[i].sbs;
-	buf[6] = 0x4b + (frequency_map[i].gc3 << 4);
-	buf[7] = 0x1c;
-	buf[8] = 0x06;
-	buf[9] = 0x24;
-	buf[10] = 0x00;
-	msg.len = 11;
-	rc = tuner_transfer(fe, &msg, 1);
-	if (rc < 0)
-		goto err;
-
-	buf[0] = 0x90;
-	buf[1] = 0xff;
-	buf[2] = 0x60;
-	buf[3] = 0x00;
-	buf[4] = 0x59;  // lpsel, for 6MHz + 2
-	msg.len = 5;
-	rc = tuner_transfer(fe, &msg, 1);
-	if (rc < 0)
-		goto err;
-
-	buf[0] = 0xa0;
-	buf[1] = 0x40;
-	msg.len = 2;
-	rc = tuner_transfer(fe, &msg, 1);
-	if (rc < 0)
-		goto err;
-
-	msleep(11);
-	msg.flags = I2C_M_RD;
-	rc = tuner_transfer(fe, &msg, 1);
-	if (rc < 0)
-		goto err;
-	msg.flags = 0;
-
-	buf[1] >>= 4;
-	dprintk("tda8275a AGC2 gain is: %d\n", buf[1]);
-	if ((buf[1]) < 2) {
-		tda827xa_lna_gain(fe, 0, NULL);
-		buf[0] = 0x60;
-		buf[1] = 0x0c;
-		rc = tuner_transfer(fe, &msg, 1);
-		if (rc < 0)
-			goto err;
-	}
-
-	buf[0] = 0xc0;
-	buf[1] = 0x99;    // lpsel, for 6MHz + 2
-	rc = tuner_transfer(fe, &msg, 1);
-	if (rc < 0)
-		goto err;
-
-	buf[0] = 0x60;
-	buf[1] = 0x3c;
-	rc = tuner_transfer(fe, &msg, 1);
-	if (rc < 0)
-		goto err;
-
-	/* correct CP value */
-	buf[0] = 0x30;
-	buf[1] = 0x10 + frequency_map[i].scr;
-	rc = tuner_transfer(fe, &msg, 1);
-	if (rc < 0)
-		goto err;
-
-	msleep(163);
-	buf[0] = 0xc0;
-	buf[1] = 0x39;  // lpsel, for 6MHz + 2
-	rc = tuner_transfer(fe, &msg, 1);
-	if (rc < 0)
-		goto err;
-
-	msleep(3);
-	/* freeze AGC1 */
-	buf[0] = 0x50;
-	buf[1] = 0x4f + (frequency_map[i].gc3 << 4);
-	rc = tuner_transfer(fe, &msg, 1);
-	if (rc < 0)
-		goto err;
-
-	priv->frequency = c->frequency;
-	priv->bandwidth = c->bandwidth_hz;
-
-	return 0;
-
-err:
-	printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n",
-	       __func__, priv->i2c_addr << 1);
-	return rc;
-}
-
-
-static int tda827xa_set_analog_params(struct dvb_frontend *fe,
-				      struct analog_parameters *params)
-{
-	unsigned char tuner_reg[11];
-	u32 N;
-	int i;
-	struct tda827x_priv *priv = fe->tuner_priv;
-	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
-			       .buf = tuner_reg, .len = sizeof(tuner_reg) };
-	unsigned int freq = params->frequency;
-
-	tda827x_set_std(fe, params);
-
-	tda827xa_lna_gain(fe, 1, params);
-	msleep(10);
-
-	if (params->mode == V4L2_TUNER_RADIO)
-		freq = freq / 1000;
-
-	N = freq + priv->sgIF;
-
-	i = 0;
-	while (tda827xa_analog[i].lomax < N * 62500) {
-		if (tda827xa_analog[i + 1].lomax == 0)
-			break;
-		i++;
-	}
-
-	N = N << tda827xa_analog[i].spd;
-
-	tuner_reg[0] = 0;
-	tuner_reg[1] = (unsigned char)(N>>8);
-	tuner_reg[2] = (unsigned char) N;
-	tuner_reg[3] = 0;
-	tuner_reg[4] = 0x16;
-	tuner_reg[5] = (tda827xa_analog[i].spd << 5) +
-		       (tda827xa_analog[i].svco << 3) +
-			tda827xa_analog[i].sbs;
-	tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
-	tuner_reg[7] = 0x1c;
-	tuner_reg[8] = 4;
-	tuner_reg[9] = 0x20;
-	tuner_reg[10] = 0x00;
-	msg.len = 11;
-	tuner_transfer(fe, &msg, 1);
-
-	tuner_reg[0] = 0x90;
-	tuner_reg[1] = 0xff;
-	tuner_reg[2] = 0xe0;
-	tuner_reg[3] = 0;
-	tuner_reg[4] = 0x99 + (priv->lpsel << 1);
-	msg.len = 5;
-	tuner_transfer(fe, &msg, 1);
-
-	tuner_reg[0] = 0xa0;
-	tuner_reg[1] = 0xc0;
-	msg.len = 2;
-	tuner_transfer(fe, &msg, 1);
-
-	tuner_reg[0] = 0x30;
-	tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
-	tuner_transfer(fe, &msg, 1);
-
-	msg.flags = I2C_M_RD;
-	tuner_transfer(fe, &msg, 1);
-	msg.flags = 0;
-	tuner_reg[1] >>= 4;
-	dprintk("AGC2 gain is: %d\n", tuner_reg[1]);
-	if (tuner_reg[1] < 1)
-		tda827xa_lna_gain(fe, 0, params);
-
-	msleep(100);
-	tuner_reg[0] = 0x60;
-	tuner_reg[1] = 0x3c;
-	tuner_transfer(fe, &msg, 1);
-
-	msleep(163);
-	tuner_reg[0] = 0x50;
-	tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
-	tuner_transfer(fe, &msg, 1);
-
-	tuner_reg[0] = 0x80;
-	tuner_reg[1] = 0x28;
-	tuner_transfer(fe, &msg, 1);
-
-	tuner_reg[0] = 0xb0;
-	tuner_reg[1] = 0x01;
-	tuner_transfer(fe, &msg, 1);
-
-	tuner_reg[0] = 0xc0;
-	tuner_reg[1] = 0x19 + (priv->lpsel << 1);
-	tuner_transfer(fe, &msg, 1);
-
-	priv->frequency = params->frequency;
-
-	return 0;
-}
-
-static void tda827xa_agcf(struct dvb_frontend *fe)
-{
-	struct tda827x_priv *priv = fe->tuner_priv;
-	unsigned char data[] = {0x80, 0x2c};
-	struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0,
-			      .buf = data, .len = 2};
-	tuner_transfer(fe, &msg, 1);
-}
-
-/* ------------------------------------------------------------------ */
-
-static int tda827x_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct tda827x_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-	return 0;
-}
-
-static int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	struct tda827x_priv *priv = fe->tuner_priv;
-	*bandwidth = priv->bandwidth;
-	return 0;
-}
-
-static int tda827x_init(struct dvb_frontend *fe)
-{
-	struct tda827x_priv *priv = fe->tuner_priv;
-	dprintk("%s:\n", __func__);
-	if (priv->cfg && priv->cfg->init)
-		priv->cfg->init(fe);
-
-	return 0;
-}
-
-static int tda827x_probe_version(struct dvb_frontend *fe);
-
-static int tda827x_initial_init(struct dvb_frontend *fe)
-{
-	int ret;
-	ret = tda827x_probe_version(fe);
-	if (ret)
-		return ret;
-	return fe->ops.tuner_ops.init(fe);
-}
-
-static int tda827x_initial_sleep(struct dvb_frontend *fe)
-{
-	int ret;
-	ret = tda827x_probe_version(fe);
-	if (ret)
-		return ret;
-	return fe->ops.tuner_ops.sleep(fe);
-}
-
-static struct dvb_tuner_ops tda827xo_tuner_ops = {
-	.info = {
-		.name = "Philips TDA827X",
-		.frequency_min  =  55000000,
-		.frequency_max  = 860000000,
-		.frequency_step =    250000
-	},
-	.release = tda827x_release,
-	.init = tda827x_initial_init,
-	.sleep = tda827x_initial_sleep,
-	.set_params = tda827xo_set_params,
-	.set_analog_params = tda827xo_set_analog_params,
-	.get_frequency = tda827x_get_frequency,
-	.get_bandwidth = tda827x_get_bandwidth,
-};
-
-static struct dvb_tuner_ops tda827xa_tuner_ops = {
-	.info = {
-		.name = "Philips TDA827XA",
-		.frequency_min  =  44000000,
-		.frequency_max  = 906000000,
-		.frequency_step =     62500
-	},
-	.release = tda827x_release,
-	.init = tda827x_init,
-	.sleep = tda827xa_sleep,
-	.set_params = tda827xa_set_params,
-	.set_analog_params = tda827xa_set_analog_params,
-	.get_frequency = tda827x_get_frequency,
-	.get_bandwidth = tda827x_get_bandwidth,
-};
-
-static int tda827x_probe_version(struct dvb_frontend *fe)
-{
-	u8 data;
-	int rc;
-	struct tda827x_priv *priv = fe->tuner_priv;
-	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD,
-			       .buf = &data, .len = 1 };
-
-	rc = tuner_transfer(fe, &msg, 1);
-
-	if (rc < 0) {
-		printk("%s: could not read from tuner at addr: 0x%02x\n",
-		       __func__, msg.addr << 1);
-		return rc;
-	}
-	if ((data & 0x3c) == 0) {
-		dprintk("tda827x tuner found\n");
-		fe->ops.tuner_ops.init  = tda827x_init;
-		fe->ops.tuner_ops.sleep = tda827xo_sleep;
-		if (priv->cfg)
-			priv->cfg->agcf = tda827xo_agcf;
-	} else {
-		dprintk("tda827xa tuner found\n");
-		memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops));
-		if (priv->cfg)
-			priv->cfg->agcf = tda827xa_agcf;
-	}
-	return 0;
-}
-
-struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr,
-				    struct i2c_adapter *i2c,
-				    struct tda827x_config *cfg)
-{
-	struct tda827x_priv *priv = NULL;
-
-	dprintk("%s:\n", __func__);
-	priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	priv->i2c_addr = addr;
-	priv->i2c_adap = i2c;
-	priv->cfg = cfg;
-	memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops));
-	fe->tuner_priv = priv;
-
-	dprintk("type set to %s\n", fe->ops.tuner_ops.info.name);
-
-	return fe;
-}
-EXPORT_SYMBOL_GPL(tda827x_attach);
-
-MODULE_DESCRIPTION("DVB TDA827x driver");
-MODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann@t-online.de>");
-MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
-MODULE_LICENSE("GPL");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/common/tuners/tda827x.h b/drivers/media/common/tuners/tda827x.h
deleted file mode 100644
index 7d72ce0..0000000
--- a/drivers/media/common/tuners/tda827x.h
+++ /dev/null
@@ -1,68 +0,0 @@
-  /*
-     DVB Driver for Philips tda827x / tda827xa Silicon tuners
-
-     (c) 2005 Hartmut Hackmann
-     (c) 2007 Michael Krufky
-
-     This program is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published by
-     the Free Software Foundation; either version 2 of the License, or
-     (at your option) any later version.
-
-     This program is distributed in the hope that it will be useful,
-     but WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-     GNU General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with this program; if not, write to the Free Software
-     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-  */
-
-#ifndef __DVB_TDA827X_H__
-#define __DVB_TDA827X_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-struct tda827x_config
-{
-	/* saa7134 - provided callbacks */
-	int (*init) (struct dvb_frontend *fe);
-	int (*sleep) (struct dvb_frontend *fe);
-
-	/* interface to tda829x driver */
-	unsigned int config;
-	int 	     switch_addr;
-
-	void (*agcf)(struct dvb_frontend *fe);
-};
-
-
-/**
- * Attach a tda827x tuner to the supplied frontend structure.
- *
- * @param fe Frontend to attach to.
- * @param addr i2c address of the tuner.
- * @param i2c i2c adapter to use.
- * @param cfg optional callback function pointers.
- * @return FE pointer on success, NULL on failure.
- */
-#if defined(CONFIG_MEDIA_TUNER_TDA827X) || (defined(CONFIG_MEDIA_TUNER_TDA827X_MODULE) && defined(MODULE))
-extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr,
-					   struct i2c_adapter *i2c,
-					   struct tda827x_config *cfg);
-#else
-static inline struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe,
-						  int addr,
-						  struct i2c_adapter *i2c,
-						  struct tda827x_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_MEDIA_TUNER_TDA827X
-
-#endif // __DVB_TDA827X_H__
diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/common/tuners/tda8290.c
deleted file mode 100644
index 8c48521..0000000
--- a/drivers/media/common/tuners/tda8290.c
+++ /dev/null
@@ -1,874 +0,0 @@
-/*
-
-   i2c tv tuner chip device driver
-   controls the philips tda8290+75 tuner chip combo.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-   This "tda8290" module was split apart from the original "tuner" module.
-*/
-
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/videodev2.h>
-#include "tuner-i2c.h"
-#include "tda8290.h"
-#include "tda827x.h"
-#include "tda18271.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-static int deemphasis_50;
-module_param(deemphasis_50, int, 0644);
-MODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis");
-
-/* ---------------------------------------------------------------------- */
-
-struct tda8290_priv {
-	struct tuner_i2c_props i2c_props;
-
-	unsigned char tda8290_easy_mode;
-
-	unsigned char tda827x_addr;
-
-	unsigned char ver;
-#define TDA8290   1
-#define TDA8295   2
-#define TDA8275   4
-#define TDA8275A  8
-#define TDA18271 16
-
-	struct tda827x_config cfg;
-};
-
-/*---------------------------------------------------------------------*/
-
-static int tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-
-	unsigned char  enable[2] = { 0x21, 0xC0 };
-	unsigned char disable[2] = { 0x21, 0x00 };
-	unsigned char *msg;
-
-	if (close) {
-		msg = enable;
-		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
-		/* let the bridge stabilize */
-		msleep(20);
-	} else {
-		msg = disable;
-		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
-	}
-
-	return 0;
-}
-
-static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-
-	unsigned char  enable[2] = { 0x45, 0xc1 };
-	unsigned char disable[2] = { 0x46, 0x00 };
-	unsigned char buf[3] = { 0x45, 0x01, 0x00 };
-	unsigned char *msg;
-
-	if (close) {
-		msg = enable;
-		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
-		/* let the bridge stabilize */
-		msleep(20);
-	} else {
-		msg = disable;
-		tuner_i2c_xfer_send_recv(&priv->i2c_props, msg, 1, &msg[1], 1);
-
-		buf[2] = msg[1];
-		buf[2] &= ~0x04;
-		tuner_i2c_xfer_send(&priv->i2c_props, buf, 3);
-		msleep(5);
-
-		msg[1] |= 0x04;
-		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
-	}
-
-	return 0;
-}
-
-/*---------------------------------------------------------------------*/
-
-static void set_audio(struct dvb_frontend *fe,
-		      struct analog_parameters *params)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-	char* mode;
-
-	if (params->std & V4L2_STD_MN) {
-		priv->tda8290_easy_mode = 0x01;
-		mode = "MN";
-	} else if (params->std & V4L2_STD_B) {
-		priv->tda8290_easy_mode = 0x02;
-		mode = "B";
-	} else if (params->std & V4L2_STD_GH) {
-		priv->tda8290_easy_mode = 0x04;
-		mode = "GH";
-	} else if (params->std & V4L2_STD_PAL_I) {
-		priv->tda8290_easy_mode = 0x08;
-		mode = "I";
-	} else if (params->std & V4L2_STD_DK) {
-		priv->tda8290_easy_mode = 0x10;
-		mode = "DK";
-	} else if (params->std & V4L2_STD_SECAM_L) {
-		priv->tda8290_easy_mode = 0x20;
-		mode = "L";
-	} else if (params->std & V4L2_STD_SECAM_LC) {
-		priv->tda8290_easy_mode = 0x40;
-		mode = "LC";
-	} else {
-		priv->tda8290_easy_mode = 0x10;
-		mode = "xx";
-	}
-
-	if (params->mode == V4L2_TUNER_RADIO) {
-		/* Set TDA8295 to FM radio; Start TDA8290 with MN values */
-		priv->tda8290_easy_mode = (priv->ver & TDA8295) ? 0x80 : 0x01;
-		tuner_dbg("setting to radio FM\n");
-	} else {
-		tuner_dbg("setting tda829x to system %s\n", mode);
-	}
-}
-
-static struct {
-	unsigned char seq[2];
-} fm_mode[] = {
-	{ { 0x01, 0x81} },	/* Put device into expert mode */
-	{ { 0x03, 0x48} },	/* Disable NOTCH and VIDEO filters */
-	{ { 0x04, 0x04} },	/* Disable color carrier filter (SSIF) */
-	{ { 0x05, 0x04} },	/* ADC headroom */
-	{ { 0x06, 0x10} },	/* group delay flat */
-
-	{ { 0x07, 0x00} },	/* use the same radio DTO values as a tda8295 */
-	{ { 0x08, 0x00} },
-	{ { 0x09, 0x80} },
-	{ { 0x0a, 0xda} },
-	{ { 0x0b, 0x4b} },
-	{ { 0x0c, 0x68} },
-
-	{ { 0x0d, 0x00} },	/* PLL off, no video carrier detect */
-	{ { 0x14, 0x00} },	/* disable auto mute if no video */
-};
-
-static void tda8290_set_params(struct dvb_frontend *fe,
-			       struct analog_parameters *params)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-
-	unsigned char soft_reset[]  = { 0x00, 0x00 };
-	unsigned char easy_mode[]   = { 0x01, priv->tda8290_easy_mode };
-	unsigned char expert_mode[] = { 0x01, 0x80 };
-	unsigned char agc_out_on[]  = { 0x02, 0x00 };
-	unsigned char gainset_off[] = { 0x28, 0x14 };
-	unsigned char if_agc_spd[]  = { 0x0f, 0x88 };
-	unsigned char adc_head_6[]  = { 0x05, 0x04 };
-	unsigned char adc_head_9[]  = { 0x05, 0x02 };
-	unsigned char adc_head_12[] = { 0x05, 0x01 };
-	unsigned char pll_bw_nom[]  = { 0x0d, 0x47 };
-	unsigned char pll_bw_low[]  = { 0x0d, 0x27 };
-	unsigned char gainset_2[]   = { 0x28, 0x64 };
-	unsigned char agc_rst_on[]  = { 0x0e, 0x0b };
-	unsigned char agc_rst_off[] = { 0x0e, 0x09 };
-	unsigned char if_agc_set[]  = { 0x0f, 0x81 };
-	unsigned char addr_adc_sat  = 0x1a;
-	unsigned char addr_agc_stat = 0x1d;
-	unsigned char addr_pll_stat = 0x1b;
-	unsigned char adc_sat, agc_stat,
-		      pll_stat;
-	int i;
-
-	set_audio(fe, params);
-
-	if (priv->cfg.config)
-		tuner_dbg("tda827xa config is 0x%02x\n", priv->cfg.config);
-	tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2);
-	tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2);
-	tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
-	msleep(1);
-
-	if (params->mode == V4L2_TUNER_RADIO) {
-		unsigned char deemphasis[]  = { 0x13, 1 };
-
-		/* FIXME: allow using a different deemphasis */
-
-		if (deemphasis_50)
-			deemphasis[1] = 2;
-
-		for (i = 0; i < ARRAY_SIZE(fm_mode); i++)
-			tuner_i2c_xfer_send(&priv->i2c_props, fm_mode[i].seq, 2);
-
-		tuner_i2c_xfer_send(&priv->i2c_props, deemphasis, 2);
-	} else {
-		expert_mode[1] = priv->tda8290_easy_mode + 0x80;
-		tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
-		tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
-		tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
-		if (priv->tda8290_easy_mode & 0x60)
-			tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
-		else
-			tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
-		tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
-	}
-
-
-	tda8290_i2c_bridge(fe, 1);
-
-	if (fe->ops.tuner_ops.set_analog_params)
-		fe->ops.tuner_ops.set_analog_params(fe, params);
-
-	for (i = 0; i < 3; i++) {
-		tuner_i2c_xfer_send_recv(&priv->i2c_props,
-					 &addr_pll_stat, 1, &pll_stat, 1);
-		if (pll_stat & 0x80) {
-			tuner_i2c_xfer_send_recv(&priv->i2c_props,
-						 &addr_adc_sat, 1,
-						 &adc_sat, 1);
-			tuner_i2c_xfer_send_recv(&priv->i2c_props,
-						 &addr_agc_stat, 1,
-						 &agc_stat, 1);
-			tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat);
-			break;
-		} else {
-			tuner_dbg("tda8290 not locked, no signal?\n");
-			msleep(100);
-		}
-	}
-	/* adjust headroom resp. gain */
-	if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) {
-		tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n",
-			   agc_stat, adc_sat, pll_stat & 0x80);
-		tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2);
-		msleep(100);
-		tuner_i2c_xfer_send_recv(&priv->i2c_props,
-					 &addr_agc_stat, 1, &agc_stat, 1);
-		tuner_i2c_xfer_send_recv(&priv->i2c_props,
-					 &addr_pll_stat, 1, &pll_stat, 1);
-		if ((agc_stat > 115) || !(pll_stat & 0x80)) {
-			tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
-				   agc_stat, pll_stat & 0x80);
-			if (priv->cfg.agcf)
-				priv->cfg.agcf(fe);
-			msleep(100);
-			tuner_i2c_xfer_send_recv(&priv->i2c_props,
-						 &addr_agc_stat, 1,
-						 &agc_stat, 1);
-			tuner_i2c_xfer_send_recv(&priv->i2c_props,
-						 &addr_pll_stat, 1,
-						 &pll_stat, 1);
-			if((agc_stat > 115) || !(pll_stat & 0x80)) {
-				tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat);
-				tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2);
-				tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_low, 2);
-				msleep(100);
-			}
-		}
-	}
-
-	/* l/ l' deadlock? */
-	if(priv->tda8290_easy_mode & 0x60) {
-		tuner_i2c_xfer_send_recv(&priv->i2c_props,
-					 &addr_adc_sat, 1,
-					 &adc_sat, 1);
-		tuner_i2c_xfer_send_recv(&priv->i2c_props,
-					 &addr_pll_stat, 1,
-					 &pll_stat, 1);
-		if ((adc_sat > 20) || !(pll_stat & 0x80)) {
-			tuner_dbg("trying to resolve SECAM L deadlock\n");
-			tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2);
-			msleep(40);
-			tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_off, 2);
-		}
-	}
-
-	tda8290_i2c_bridge(fe, 0);
-	tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2);
-}
-
-/*---------------------------------------------------------------------*/
-
-static void tda8295_power(struct dvb_frontend *fe, int enable)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-	unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */
-
-	tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1);
-
-	if (enable)
-		buf[1] = 0x01;
-	else
-		buf[1] = 0x03;
-
-	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
-}
-
-static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-	unsigned char buf[] = { 0x01, 0x00 };
-
-	tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1);
-
-	if (enable)
-		buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */
-	else
-		buf[1] = 0x00; /* reset active bit */
-
-	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
-}
-
-static void tda8295_set_video_std(struct dvb_frontend *fe)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-	unsigned char buf[] = { 0x00, priv->tda8290_easy_mode };
-
-	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
-
-	tda8295_set_easy_mode(fe, 1);
-	msleep(20);
-	tda8295_set_easy_mode(fe, 0);
-}
-
-/*---------------------------------------------------------------------*/
-
-static void tda8295_agc1_out(struct dvb_frontend *fe, int enable)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-	unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */
-
-	tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1);
-
-	if (enable)
-		buf[1] &= ~0x40;
-	else
-		buf[1] |= 0x40;
-
-	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
-}
-
-static void tda8295_agc2_out(struct dvb_frontend *fe, int enable)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-	unsigned char set_gpio_cf[]    = { 0x44, 0x00 };
-	unsigned char set_gpio_val[]   = { 0x46, 0x00 };
-
-	tuner_i2c_xfer_send_recv(&priv->i2c_props,
-				 &set_gpio_cf[0], 1, &set_gpio_cf[1], 1);
-	tuner_i2c_xfer_send_recv(&priv->i2c_props,
-				 &set_gpio_val[0], 1, &set_gpio_val[1], 1);
-
-	set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */
-
-	if (enable) {
-		set_gpio_cf[1]  |= 0x01; /* config GPIO_0 as Open Drain Out */
-		set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */
-	}
-	tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2);
-	tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2);
-}
-
-static int tda8295_has_signal(struct dvb_frontend *fe)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-
-	unsigned char hvpll_stat = 0x26;
-	unsigned char ret;
-
-	tuner_i2c_xfer_send_recv(&priv->i2c_props, &hvpll_stat, 1, &ret, 1);
-	return (ret & 0x01) ? 65535 : 0;
-}
-
-/*---------------------------------------------------------------------*/
-
-static void tda8295_set_params(struct dvb_frontend *fe,
-			       struct analog_parameters *params)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-
-	unsigned char blanking_mode[]     = { 0x1d, 0x00 };
-
-	set_audio(fe, params);
-
-	tuner_dbg("%s: freq = %d\n", __func__, params->frequency);
-
-	tda8295_power(fe, 1);
-	tda8295_agc1_out(fe, 1);
-
-	tuner_i2c_xfer_send_recv(&priv->i2c_props,
-				 &blanking_mode[0], 1, &blanking_mode[1], 1);
-
-	tda8295_set_video_std(fe);
-
-	blanking_mode[1] = 0x03;
-	tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2);
-	msleep(20);
-
-	tda8295_i2c_bridge(fe, 1);
-
-	if (fe->ops.tuner_ops.set_analog_params)
-		fe->ops.tuner_ops.set_analog_params(fe, params);
-
-	if (priv->cfg.agcf)
-		priv->cfg.agcf(fe);
-
-	if (tda8295_has_signal(fe))
-		tuner_dbg("tda8295 is locked\n");
-	else
-		tuner_dbg("tda8295 not locked, no signal?\n");
-
-	tda8295_i2c_bridge(fe, 0);
-}
-
-/*---------------------------------------------------------------------*/
-
-static int tda8290_has_signal(struct dvb_frontend *fe)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-
-	unsigned char i2c_get_afc[1] = { 0x1B };
-	unsigned char afc = 0;
-
-	tuner_i2c_xfer_send_recv(&priv->i2c_props,
-				 i2c_get_afc, ARRAY_SIZE(i2c_get_afc), &afc, 1);
-	return (afc & 0x80)? 65535:0;
-}
-
-/*---------------------------------------------------------------------*/
-
-static void tda8290_standby(struct dvb_frontend *fe)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-
-	unsigned char cb1[] = { 0x30, 0xD0 };
-	unsigned char tda8290_standby[] = { 0x00, 0x02 };
-	unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
-	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
-
-	tda8290_i2c_bridge(fe, 1);
-	if (priv->ver & TDA8275A)
-		cb1[1] = 0x90;
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-	tda8290_i2c_bridge(fe, 0);
-	tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2);
-	tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2);
-}
-
-static void tda8295_standby(struct dvb_frontend *fe)
-{
-	tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */
-
-	tda8295_power(fe, 0);
-}
-
-static void tda8290_init_if(struct dvb_frontend *fe)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-
-	unsigned char set_VS[] = { 0x30, 0x6F };
-	unsigned char set_GP00_CF[] = { 0x20, 0x01 };
-	unsigned char set_GP01_CF[] = { 0x20, 0x0B };
-
-	if ((priv->cfg.config == 1) || (priv->cfg.config == 2))
-		tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2);
-	else
-		tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2);
-	tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2);
-}
-
-static void tda8295_init_if(struct dvb_frontend *fe)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-
-	static unsigned char set_adc_ctl[]       = { 0x33, 0x14 };
-	static unsigned char set_adc_ctl2[]      = { 0x34, 0x00 };
-	static unsigned char set_pll_reg6[]      = { 0x3e, 0x63 };
-	static unsigned char set_pll_reg0[]      = { 0x38, 0x23 };
-	static unsigned char set_pll_reg7[]      = { 0x3f, 0x01 };
-	static unsigned char set_pll_reg10[]     = { 0x42, 0x61 };
-	static unsigned char set_gpio_reg0[]     = { 0x44, 0x0b };
-
-	tda8295_power(fe, 1);
-
-	tda8295_set_easy_mode(fe, 0);
-	tda8295_set_video_std(fe);
-
-	tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2);
-	tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2);
-	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2);
-	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2);
-	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2);
-	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2);
-	tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2);
-
-	tda8295_agc1_out(fe, 0);
-	tda8295_agc2_out(fe, 0);
-}
-
-static void tda8290_init_tuner(struct dvb_frontend *fe)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-	unsigned char tda8275_init[]  = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
-					  0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
-	unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
-					  0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
-	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0,
-			      .buf=tda8275_init, .len = 14};
-	if (priv->ver & TDA8275A)
-		msg.buf = tda8275a_init;
-
-	tda8290_i2c_bridge(fe, 1);
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-	tda8290_i2c_bridge(fe, 0);
-}
-
-/*---------------------------------------------------------------------*/
-
-static void tda829x_release(struct dvb_frontend *fe)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-
-	/* only try to release the tuner if we've
-	 * attached it from within this module */
-	if (priv->ver & (TDA18271 | TDA8275 | TDA8275A))
-		if (fe->ops.tuner_ops.release)
-			fe->ops.tuner_ops.release(fe);
-
-	kfree(fe->analog_demod_priv);
-	fe->analog_demod_priv = NULL;
-}
-
-static struct tda18271_config tda829x_tda18271_config = {
-	.gate    = TDA18271_GATE_ANALOG,
-};
-
-static int tda829x_find_tuner(struct dvb_frontend *fe)
-{
-	struct tda8290_priv *priv = fe->analog_demod_priv;
-	struct analog_demod_ops *analog_ops = &fe->ops.analog_ops;
-	int i, ret, tuners_found;
-	u32 tuner_addrs;
-	u8 data;
-	struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 };
-
-	if (!analog_ops->i2c_gate_ctrl) {
-		printk(KERN_ERR "tda8290: no gate control were provided!\n");
-
-		return -EINVAL;
-	}
-
-	analog_ops->i2c_gate_ctrl(fe, 1);
-
-	/* probe for tuner chip */
-	tuners_found = 0;
-	tuner_addrs = 0;
-	for (i = 0x60; i <= 0x63; i++) {
-		msg.addr = i;
-		ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
-		if (ret == 1) {
-			tuners_found++;
-			tuner_addrs = (tuner_addrs << 8) + i;
-		}
-	}
-	/* if there is more than one tuner, we expect the right one is
-	   behind the bridge and we choose the highest address that doesn't
-	   give a response now
-	 */
-
-	analog_ops->i2c_gate_ctrl(fe, 0);
-
-	if (tuners_found > 1)
-		for (i = 0; i < tuners_found; i++) {
-			msg.addr = tuner_addrs  & 0xff;
-			ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
-			if (ret == 1)
-				tuner_addrs = tuner_addrs >> 8;
-			else
-				break;
-		}
-
-	if (tuner_addrs == 0) {
-		tuner_addrs = 0x60;
-		tuner_info("could not clearly identify tuner address, "
-			   "defaulting to %x\n", tuner_addrs);
-	} else {
-		tuner_addrs = tuner_addrs & 0xff;
-		tuner_info("setting tuner address to %x\n", tuner_addrs);
-	}
-	priv->tda827x_addr = tuner_addrs;
-	msg.addr = tuner_addrs;
-
-	analog_ops->i2c_gate_ctrl(fe, 1);
-	ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-	if (ret != 1) {
-		tuner_warn("tuner access failed!\n");
-		analog_ops->i2c_gate_ctrl(fe, 0);
-		return -EREMOTEIO;
-	}
-
-	if ((data == 0x83) || (data == 0x84)) {
-		priv->ver |= TDA18271;
-		tda829x_tda18271_config.config = priv->cfg.config;
-		dvb_attach(tda18271_attach, fe, priv->tda827x_addr,
-			   priv->i2c_props.adap, &tda829x_tda18271_config);
-	} else {
-		if ((data & 0x3c) == 0)
-			priv->ver |= TDA8275;
-		else
-			priv->ver |= TDA8275A;
-
-		dvb_attach(tda827x_attach, fe, priv->tda827x_addr,
-			   priv->i2c_props.adap, &priv->cfg);
-		priv->cfg.switch_addr = priv->i2c_props.addr;
-	}
-	if (fe->ops.tuner_ops.init)
-		fe->ops.tuner_ops.init(fe);
-
-	if (fe->ops.tuner_ops.sleep)
-		fe->ops.tuner_ops.sleep(fe);
-
-	analog_ops->i2c_gate_ctrl(fe, 0);
-
-	return 0;
-}
-
-static int tda8290_probe(struct tuner_i2c_props *i2c_props)
-{
-#define TDA8290_ID 0x89
-	u8 reg = 0x1f, id;
-	struct i2c_msg msg_read[] = {
-		{ .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = &reg },
-		{ .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id },
-	};
-
-	/* detect tda8290 */
-	if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) {
-		printk(KERN_WARNING "%s: couldn't read register 0x%02x\n",
-			       __func__, reg);
-		return -ENODEV;
-	}
-
-	if (id == TDA8290_ID) {
-		if (debug)
-			printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n",
-			       __func__, i2c_adapter_id(i2c_props->adap),
-			       i2c_props->addr);
-		return 0;
-	}
-	return -ENODEV;
-}
-
-static int tda8295_probe(struct tuner_i2c_props *i2c_props)
-{
-#define TDA8295_ID 0x8a
-#define TDA8295C2_ID 0x8b
-	u8 reg = 0x2f, id;
-	struct i2c_msg msg_read[] = {
-		{ .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = &reg },
-		{ .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id },
-	};
-
-	/* detect tda8295 */
-	if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) {
-		printk(KERN_WARNING "%s: couldn't read register 0x%02x\n",
-			       __func__, reg);
-		return -ENODEV;
-	}
-
-	if ((id & 0xfe) == TDA8295_ID) {
-		if (debug)
-			printk(KERN_DEBUG "%s: %s detected @ %d-%04x\n",
-			       __func__, (id == TDA8295_ID) ?
-			       "tda8295c1" : "tda8295c2",
-			       i2c_adapter_id(i2c_props->adap),
-			       i2c_props->addr);
-		return 0;
-	}
-
-	return -ENODEV;
-}
-
-static struct analog_demod_ops tda8290_ops = {
-	.set_params     = tda8290_set_params,
-	.has_signal     = tda8290_has_signal,
-	.standby        = tda8290_standby,
-	.release        = tda829x_release,
-	.i2c_gate_ctrl  = tda8290_i2c_bridge,
-};
-
-static struct analog_demod_ops tda8295_ops = {
-	.set_params     = tda8295_set_params,
-	.has_signal     = tda8295_has_signal,
-	.standby        = tda8295_standby,
-	.release        = tda829x_release,
-	.i2c_gate_ctrl  = tda8295_i2c_bridge,
-};
-
-struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
-				    struct i2c_adapter *i2c_adap, u8 i2c_addr,
-				    struct tda829x_config *cfg)
-{
-	struct tda8290_priv *priv = NULL;
-	char *name;
-
-	priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-	fe->analog_demod_priv = priv;
-
-	priv->i2c_props.addr     = i2c_addr;
-	priv->i2c_props.adap     = i2c_adap;
-	priv->i2c_props.name     = "tda829x";
-	if (cfg)
-		priv->cfg.config         = cfg->lna_cfg;
-
-	if (tda8290_probe(&priv->i2c_props) == 0) {
-		priv->ver = TDA8290;
-		memcpy(&fe->ops.analog_ops, &tda8290_ops,
-		       sizeof(struct analog_demod_ops));
-	}
-
-	if (tda8295_probe(&priv->i2c_props) == 0) {
-		priv->ver = TDA8295;
-		memcpy(&fe->ops.analog_ops, &tda8295_ops,
-		       sizeof(struct analog_demod_ops));
-	}
-
-	if (!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) {
-		tda8295_power(fe, 1);
-		if (tda829x_find_tuner(fe) < 0)
-			goto fail;
-	}
-
-	switch (priv->ver) {
-	case TDA8290:
-		name = "tda8290";
-		break;
-	case TDA8295:
-		name = "tda8295";
-		break;
-	case TDA8290 | TDA8275:
-		name = "tda8290+75";
-		break;
-	case TDA8295 | TDA8275:
-		name = "tda8295+75";
-		break;
-	case TDA8290 | TDA8275A:
-		name = "tda8290+75a";
-		break;
-	case TDA8295 | TDA8275A:
-		name = "tda8295+75a";
-		break;
-	case TDA8290 | TDA18271:
-		name = "tda8290+18271";
-		break;
-	case TDA8295 | TDA18271:
-		name = "tda8295+18271";
-		break;
-	default:
-		goto fail;
-	}
-	tuner_info("type set to %s\n", name);
-
-	fe->ops.analog_ops.info.name = name;
-
-	if (priv->ver & TDA8290) {
-		if (priv->ver & (TDA8275 | TDA8275A))
-			tda8290_init_tuner(fe);
-		tda8290_init_if(fe);
-	} else if (priv->ver & TDA8295)
-		tda8295_init_if(fe);
-
-	return fe;
-
-fail:
-	memset(&fe->ops.analog_ops, 0, sizeof(struct analog_demod_ops));
-
-	tda829x_release(fe);
-	return NULL;
-}
-EXPORT_SYMBOL_GPL(tda829x_attach);
-
-int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
-{
-	struct tuner_i2c_props i2c_props = {
-		.adap = i2c_adap,
-		.addr = i2c_addr,
-	};
-
-	unsigned char soft_reset[]   = { 0x00, 0x00 };
-	unsigned char easy_mode_b[]  = { 0x01, 0x02 };
-	unsigned char easy_mode_g[]  = { 0x01, 0x04 };
-	unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 };
-	unsigned char addr_dto_lsb = 0x07;
-	unsigned char data;
-#define PROBE_BUFFER_SIZE 8
-	unsigned char buf[PROBE_BUFFER_SIZE];
-	int i;
-
-	/* rule out tda9887, which would return the same byte repeatedly */
-	tuner_i2c_xfer_send_recv(&i2c_props,
-				 soft_reset, 1, buf, PROBE_BUFFER_SIZE);
-	for (i = 1; i < PROBE_BUFFER_SIZE; i++) {
-		if (buf[i] != buf[0])
-			break;
-	}
-
-	/* all bytes are equal, not a tda829x - probably a tda9887 */
-	if (i == PROBE_BUFFER_SIZE)
-		return -ENODEV;
-
-	if ((tda8290_probe(&i2c_props) == 0) ||
-	    (tda8295_probe(&i2c_props) == 0))
-		return 0;
-
-	/* fall back to old probing method */
-	tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2);
-	tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
-	tuner_i2c_xfer_send_recv(&i2c_props, &addr_dto_lsb, 1, &data, 1);
-	if (data == 0) {
-		tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2);
-		tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
-		tuner_i2c_xfer_send_recv(&i2c_props,
-					 &addr_dto_lsb, 1, &data, 1);
-		if (data == 0x7b) {
-			return 0;
-		}
-	}
-	tuner_i2c_xfer_send(&i2c_props, restore_9886, 3);
-	return -ENODEV;
-}
-EXPORT_SYMBOL_GPL(tda829x_probe);
-
-MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver");
-MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky");
-MODULE_LICENSE("GPL");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/common/tuners/tda8290.h b/drivers/media/common/tuners/tda8290.h
deleted file mode 100644
index 7e288b2..0000000
--- a/drivers/media/common/tuners/tda8290.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TDA8290_H__
-#define __TDA8290_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-struct tda829x_config {
-	unsigned int lna_cfg;
-
-	unsigned int probe_tuner:1;
-#define TDA829X_PROBE_TUNER 0
-#define TDA829X_DONT_PROBE  1
-};
-
-#if defined(CONFIG_MEDIA_TUNER_TDA8290) || (defined(CONFIG_MEDIA_TUNER_TDA8290_MODULE) && defined(MODULE))
-extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr);
-
-extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
-					   struct i2c_adapter *i2c_adap,
-					   u8 i2c_addr,
-					   struct tda829x_config *cfg);
-#else
-static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -EINVAL;
-}
-
-static inline struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
-						  struct i2c_adapter *i2c_adap,
-						  u8 i2c_addr,
-						  struct tda829x_config *cfg)
-{
-	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
-	       __func__);
-	return NULL;
-}
-#endif
-
-#endif /* __TDA8290_H__ */
diff --git a/drivers/media/common/tuners/tda9887.c b/drivers/media/common/tuners/tda9887.c
deleted file mode 100644
index cdb645d..0000000
--- a/drivers/media/common/tuners/tda9887.c
+++ /dev/null
@@ -1,717 +0,0 @@
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/i2c.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/tuner.h>
-#include "tuner-i2c.h"
-#include "tda9887.h"
-
-
-/* Chips:
-   TDA9885 (PAL, NTSC)
-   TDA9886 (PAL, SECAM, NTSC)
-   TDA9887 (PAL, SECAM, NTSC, FM Radio)
-
-   Used as part of several tuners
-*/
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-static DEFINE_MUTEX(tda9887_list_mutex);
-static LIST_HEAD(hybrid_tuner_instance_list);
-
-struct tda9887_priv {
-	struct tuner_i2c_props i2c_props;
-	struct list_head hybrid_tuner_instance_list;
-
-	unsigned char 	   data[4];
-	unsigned int       config;
-	unsigned int       mode;
-	unsigned int       audmode;
-	v4l2_std_id        std;
-
-	bool               standby;
-};
-
-/* ---------------------------------------------------------------------- */
-
-#define UNSET       (-1U)
-
-struct tvnorm {
-	v4l2_std_id       std;
-	char              *name;
-	unsigned char     b;
-	unsigned char     c;
-	unsigned char     e;
-};
-
-/* ---------------------------------------------------------------------- */
-
-//
-// TDA defines
-//
-
-//// first reg (b)
-#define cVideoTrapBypassOFF     0x00    // bit b0
-#define cVideoTrapBypassON      0x01    // bit b0
-
-#define cAutoMuteFmInactive     0x00    // bit b1
-#define cAutoMuteFmActive       0x02    // bit b1
-
-#define cIntercarrier           0x00    // bit b2
-#define cQSS                    0x04    // bit b2
-
-#define cPositiveAmTV           0x00    // bit b3:4
-#define cFmRadio                0x08    // bit b3:4
-#define cNegativeFmTV           0x10    // bit b3:4
-
-
-#define cForcedMuteAudioON      0x20    // bit b5
-#define cForcedMuteAudioOFF     0x00    // bit b5
-
-#define cOutputPort1Active      0x00    // bit b6
-#define cOutputPort1Inactive    0x40    // bit b6
-
-#define cOutputPort2Active      0x00    // bit b7
-#define cOutputPort2Inactive    0x80    // bit b7
-
-
-//// second reg (c)
-#define cDeemphasisOFF          0x00    // bit c5
-#define cDeemphasisON           0x20    // bit c5
-
-#define cDeemphasis75           0x00    // bit c6
-#define cDeemphasis50           0x40    // bit c6
-
-#define cAudioGain0             0x00    // bit c7
-#define cAudioGain6             0x80    // bit c7
-
-#define cTopMask                0x1f    // bit c0:4
-#define cTopDefault		0x10 	// bit c0:4
-
-//// third reg (e)
-#define cAudioIF_4_5             0x00    // bit e0:1
-#define cAudioIF_5_5             0x01    // bit e0:1
-#define cAudioIF_6_0             0x02    // bit e0:1
-#define cAudioIF_6_5             0x03    // bit e0:1
-
-
-#define cVideoIFMask		0x1c	// bit e2:4
-/* Video IF selection in TV Mode (bit B3=0) */
-#define cVideoIF_58_75           0x00    // bit e2:4
-#define cVideoIF_45_75           0x04    // bit e2:4
-#define cVideoIF_38_90           0x08    // bit e2:4
-#define cVideoIF_38_00           0x0C    // bit e2:4
-#define cVideoIF_33_90           0x10    // bit e2:4
-#define cVideoIF_33_40           0x14    // bit e2:4
-#define cRadioIF_45_75           0x18    // bit e2:4
-#define cRadioIF_38_90           0x1C    // bit e2:4
-
-/* IF1 selection in Radio Mode (bit B3=1) */
-#define cRadioIF_33_30		0x00	// bit e2,4 (also 0x10,0x14)
-#define cRadioIF_41_30		0x04	// bit e2,4
-
-/* Output of AFC pin in radio mode when bit E7=1 */
-#define cRadioAGC_SIF		0x00	// bit e3
-#define cRadioAGC_FM		0x08	// bit e3
-
-#define cTunerGainNormal         0x00    // bit e5
-#define cTunerGainLow            0x20    // bit e5
-
-#define cGating_18               0x00    // bit e6
-#define cGating_36               0x40    // bit e6
-
-#define cAgcOutON                0x80    // bit e7
-#define cAgcOutOFF               0x00    // bit e7
-
-/* ---------------------------------------------------------------------- */
-
-static struct tvnorm tvnorms[] = {
-	{
-		.std   = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
-		.name  = "PAL-BGHN",
-		.b     = ( cNegativeFmTV  |
-			   cQSS           ),
-		.c     = ( cDeemphasisON  |
-			   cDeemphasis50  |
-			   cTopDefault),
-		.e     = ( cGating_36     |
-			   cAudioIF_5_5   |
-			   cVideoIF_38_90 ),
-	},{
-		.std   = V4L2_STD_PAL_I,
-		.name  = "PAL-I",
-		.b     = ( cNegativeFmTV  |
-			   cQSS           ),
-		.c     = ( cDeemphasisON  |
-			   cDeemphasis50  |
-			   cTopDefault),
-		.e     = ( cGating_36     |
-			   cAudioIF_6_0   |
-			   cVideoIF_38_90 ),
-	},{
-		.std   = V4L2_STD_PAL_DK,
-		.name  = "PAL-DK",
-		.b     = ( cNegativeFmTV  |
-			   cQSS           ),
-		.c     = ( cDeemphasisON  |
-			   cDeemphasis50  |
-			   cTopDefault),
-		.e     = ( cGating_36     |
-			   cAudioIF_6_5   |
-			   cVideoIF_38_90 ),
-	},{
-		.std   = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
-		.name  = "PAL-M/Nc",
-		.b     = ( cNegativeFmTV  |
-			   cQSS           ),
-		.c     = ( cDeemphasisON  |
-			   cDeemphasis75  |
-			   cTopDefault),
-		.e     = ( cGating_36     |
-			   cAudioIF_4_5   |
-			   cVideoIF_45_75 ),
-	},{
-		.std   = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
-		.name  = "SECAM-BGH",
-		.b     = ( cNegativeFmTV  |
-			   cQSS           ),
-		.c     = ( cTopDefault),
-		.e     = ( cAudioIF_5_5   |
-			   cVideoIF_38_90 ),
-	},{
-		.std   = V4L2_STD_SECAM_L,
-		.name  = "SECAM-L",
-		.b     = ( cPositiveAmTV  |
-			   cQSS           ),
-		.c     = ( cTopDefault),
-		.e     = ( cGating_36	  |
-			   cAudioIF_6_5   |
-			   cVideoIF_38_90 ),
-	},{
-		.std   = V4L2_STD_SECAM_LC,
-		.name  = "SECAM-L'",
-		.b     = ( cOutputPort2Inactive |
-			   cPositiveAmTV  |
-			   cQSS           ),
-		.c     = ( cTopDefault),
-		.e     = ( cGating_36	  |
-			   cAudioIF_6_5   |
-			   cVideoIF_33_90 ),
-	},{
-		.std   = V4L2_STD_SECAM_DK,
-		.name  = "SECAM-DK",
-		.b     = ( cNegativeFmTV  |
-			   cQSS           ),
-		.c     = ( cDeemphasisON  |
-			   cDeemphasis50  |
-			   cTopDefault),
-		.e     = ( cGating_36     |
-			   cAudioIF_6_5   |
-			   cVideoIF_38_90 ),
-	},{
-		.std   = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
-		.name  = "NTSC-M",
-		.b     = ( cNegativeFmTV  |
-			   cQSS           ),
-		.c     = ( cDeemphasisON  |
-			   cDeemphasis75  |
-			   cTopDefault),
-		.e     = ( cGating_36     |
-			   cAudioIF_4_5   |
-			   cVideoIF_45_75 ),
-	},{
-		.std   = V4L2_STD_NTSC_M_JP,
-		.name  = "NTSC-M-JP",
-		.b     = ( cNegativeFmTV  |
-			   cQSS           ),
-		.c     = ( cDeemphasisON  |
-			   cDeemphasis50  |
-			   cTopDefault),
-		.e     = ( cGating_36     |
-			   cAudioIF_4_5   |
-			   cVideoIF_58_75 ),
-	}
-};
-
-static struct tvnorm radio_stereo = {
-	.name = "Radio Stereo",
-	.b    = ( cFmRadio       |
-		  cQSS           ),
-	.c    = ( cDeemphasisOFF |
-		  cAudioGain6    |
-		  cTopDefault),
-	.e    = ( cTunerGainLow  |
-		  cAudioIF_5_5   |
-		  cRadioIF_38_90 ),
-};
-
-static struct tvnorm radio_mono = {
-	.name = "Radio Mono",
-	.b    = ( cFmRadio       |
-		  cQSS           ),
-	.c    = ( cDeemphasisON  |
-		  cDeemphasis75  |
-		  cTopDefault),
-	.e    = ( cTunerGainLow  |
-		  cAudioIF_5_5   |
-		  cRadioIF_38_90 ),
-};
-
-/* ---------------------------------------------------------------------- */
-
-static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf)
-{
-	struct tda9887_priv *priv = fe->analog_demod_priv;
-
-	static char *afc[16] = {
-		"- 12.5 kHz",
-		"- 37.5 kHz",
-		"- 62.5 kHz",
-		"- 87.5 kHz",
-		"-112.5 kHz",
-		"-137.5 kHz",
-		"-162.5 kHz",
-		"-187.5 kHz [min]",
-		"+187.5 kHz [max]",
-		"+162.5 kHz",
-		"+137.5 kHz",
-		"+112.5 kHz",
-		"+ 87.5 kHz",
-		"+ 62.5 kHz",
-		"+ 37.5 kHz",
-		"+ 12.5 kHz",
-	};
-	tuner_info("read: 0x%2x\n", buf[0]);
-	tuner_info("  after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
-	tuner_info("  afc            : %s\n", afc[(buf[0] >> 1) & 0x0f]);
-	tuner_info("  fmif level     : %s\n", (buf[0] & 0x20) ? "high" : "low");
-	tuner_info("  afc window     : %s\n", (buf[0] & 0x40) ? "in" : "out");
-	tuner_info("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
-}
-
-static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf)
-{
-	struct tda9887_priv *priv = fe->analog_demod_priv;
-
-	static char *sound[4] = {
-		"AM/TV",
-		"FM/radio",
-		"FM/TV",
-		"FM/radio"
-	};
-	static char *adjust[32] = {
-		"-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9",
-		"-8",  "-7",  "-6",  "-5",  "-4",  "-3",  "-2",  "-1",
-		"0",   "+1",  "+2",  "+3",  "+4",  "+5",  "+6",  "+7",
-		"+8",  "+9",  "+10", "+11", "+12", "+13", "+14", "+15"
-	};
-	static char *deemph[4] = {
-		"no", "no", "75", "50"
-	};
-	static char *carrier[4] = {
-		"4.5 MHz",
-		"5.5 MHz",
-		"6.0 MHz",
-		"6.5 MHz / AM"
-	};
-	static char *vif[8] = {
-		"58.75 MHz",
-		"45.75 MHz",
-		"38.9 MHz",
-		"38.0 MHz",
-		"33.9 MHz",
-		"33.4 MHz",
-		"45.75 MHz + pin13",
-		"38.9 MHz + pin13",
-	};
-	static char *rif[4] = {
-		"44 MHz",
-		"52 MHz",
-		"52 MHz",
-		"44 MHz",
-	};
-
-	tuner_info("write: byte B 0x%02x\n", buf[1]);
-	tuner_info("  B0   video mode      : %s\n",
-		   (buf[1] & 0x01) ? "video trap" : "sound trap");
-	tuner_info("  B1   auto mute fm    : %s\n",
-		   (buf[1] & 0x02) ? "yes" : "no");
-	tuner_info("  B2   carrier mode    : %s\n",
-		   (buf[1] & 0x04) ? "QSS" : "Intercarrier");
-	tuner_info("  B3-4 tv sound/radio  : %s\n",
-		   sound[(buf[1] & 0x18) >> 3]);
-	tuner_info("  B5   force mute audio: %s\n",
-		   (buf[1] & 0x20) ? "yes" : "no");
-	tuner_info("  B6   output port 1   : %s\n",
-		   (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
-	tuner_info("  B7   output port 2   : %s\n",
-		   (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
-
-	tuner_info("write: byte C 0x%02x\n", buf[2]);
-	tuner_info("  C0-4 top adjustment  : %s dB\n",
-		   adjust[buf[2] & 0x1f]);
-	tuner_info("  C5-6 de-emphasis     : %s\n",
-		   deemph[(buf[2] & 0x60) >> 5]);
-	tuner_info("  C7   audio gain      : %s\n",
-		   (buf[2] & 0x80) ? "-6" : "0");
-
-	tuner_info("write: byte E 0x%02x\n", buf[3]);
-	tuner_info("  E0-1 sound carrier   : %s\n",
-		   carrier[(buf[3] & 0x03)]);
-	tuner_info("  E6   l pll gating   : %s\n",
-		   (buf[3] & 0x40) ? "36" : "13");
-
-	if (buf[1] & 0x08) {
-		/* radio */
-		tuner_info("  E2-4 video if        : %s\n",
-			   rif[(buf[3] & 0x0c) >> 2]);
-		tuner_info("  E7   vif agc output  : %s\n",
-			   (buf[3] & 0x80)
-			   ? ((buf[3] & 0x10) ? "fm-agc radio" :
-						"sif-agc radio")
-			   : "fm radio carrier afc");
-	} else {
-		/* video */
-		tuner_info("  E2-4 video if        : %s\n",
-			   vif[(buf[3] & 0x1c) >> 2]);
-		tuner_info("  E5   tuner gain      : %s\n",
-			   (buf[3] & 0x80)
-			   ? ((buf[3] & 0x20) ? "external" : "normal")
-			   : ((buf[3] & 0x20) ? "minimum"  : "normal"));
-		tuner_info("  E7   vif agc output  : %s\n",
-			   (buf[3] & 0x80) ? ((buf[3] & 0x20)
-				? "pin3 port, pin22 vif agc out"
-				: "pin22 port, pin3 vif acg ext in")
-				: "pin3+pin22 port");
-	}
-	tuner_info("--\n");
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int tda9887_set_tvnorm(struct dvb_frontend *fe)
-{
-	struct tda9887_priv *priv = fe->analog_demod_priv;
-	struct tvnorm *norm = NULL;
-	char *buf = priv->data;
-	int i;
-
-	if (priv->mode == V4L2_TUNER_RADIO) {
-		if (priv->audmode == V4L2_TUNER_MODE_MONO)
-			norm = &radio_mono;
-		else
-			norm = &radio_stereo;
-	} else {
-		for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
-			if (tvnorms[i].std & priv->std) {
-				norm = tvnorms+i;
-				break;
-			}
-		}
-	}
-	if (NULL == norm) {
-		tuner_dbg("Unsupported tvnorm entry - audio muted\n");
-		return -1;
-	}
-
-	tuner_dbg("configure for: %s\n", norm->name);
-	buf[1] = norm->b;
-	buf[2] = norm->c;
-	buf[3] = norm->e;
-	return 0;
-}
-
-static unsigned int port1  = UNSET;
-static unsigned int port2  = UNSET;
-static unsigned int qss    = UNSET;
-static unsigned int adjust = UNSET;
-
-module_param(port1, int, 0644);
-module_param(port2, int, 0644);
-module_param(qss, int, 0644);
-module_param(adjust, int, 0644);
-
-static int tda9887_set_insmod(struct dvb_frontend *fe)
-{
-	struct tda9887_priv *priv = fe->analog_demod_priv;
-	char *buf = priv->data;
-
-	if (UNSET != port1) {
-		if (port1)
-			buf[1] |= cOutputPort1Inactive;
-		else
-			buf[1] &= ~cOutputPort1Inactive;
-	}
-	if (UNSET != port2) {
-		if (port2)
-			buf[1] |= cOutputPort2Inactive;
-		else
-			buf[1] &= ~cOutputPort2Inactive;
-	}
-
-	if (UNSET != qss) {
-		if (qss)
-			buf[1] |= cQSS;
-		else
-			buf[1] &= ~cQSS;
-	}
-
-	if (adjust < 0x20) {
-		buf[2] &= ~cTopMask;
-		buf[2] |= adjust;
-	}
-	return 0;
-}
-
-static int tda9887_do_config(struct dvb_frontend *fe)
-{
-	struct tda9887_priv *priv = fe->analog_demod_priv;
-	char *buf = priv->data;
-
-	if (priv->config & TDA9887_PORT1_ACTIVE)
-		buf[1] &= ~cOutputPort1Inactive;
-	if (priv->config & TDA9887_PORT1_INACTIVE)
-		buf[1] |= cOutputPort1Inactive;
-	if (priv->config & TDA9887_PORT2_ACTIVE)
-		buf[1] &= ~cOutputPort2Inactive;
-	if (priv->config & TDA9887_PORT2_INACTIVE)
-		buf[1] |= cOutputPort2Inactive;
-
-	if (priv->config & TDA9887_QSS)
-		buf[1] |= cQSS;
-	if (priv->config & TDA9887_INTERCARRIER)
-		buf[1] &= ~cQSS;
-
-	if (priv->config & TDA9887_AUTOMUTE)
-		buf[1] |= cAutoMuteFmActive;
-	if (priv->config & TDA9887_DEEMPHASIS_MASK) {
-		buf[2] &= ~0x60;
-		switch (priv->config & TDA9887_DEEMPHASIS_MASK) {
-		case TDA9887_DEEMPHASIS_NONE:
-			buf[2] |= cDeemphasisOFF;
-			break;
-		case TDA9887_DEEMPHASIS_50:
-			buf[2] |= cDeemphasisON | cDeemphasis50;
-			break;
-		case TDA9887_DEEMPHASIS_75:
-			buf[2] |= cDeemphasisON | cDeemphasis75;
-			break;
-		}
-	}
-	if (priv->config & TDA9887_TOP_SET) {
-		buf[2] &= ~cTopMask;
-		buf[2] |= (priv->config >> 8) & cTopMask;
-	}
-	if ((priv->config & TDA9887_INTERCARRIER_NTSC) &&
-	    (priv->std & V4L2_STD_NTSC))
-		buf[1] &= ~cQSS;
-	if (priv->config & TDA9887_GATING_18)
-		buf[3] &= ~cGating_36;
-
-	if (priv->mode == V4L2_TUNER_RADIO) {
-		if (priv->config & TDA9887_RIF_41_3) {
-			buf[3] &= ~cVideoIFMask;
-			buf[3] |= cRadioIF_41_30;
-		}
-		if (priv->config & TDA9887_GAIN_NORMAL)
-			buf[3] &= ~cTunerGainLow;
-	}
-
-	return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int tda9887_status(struct dvb_frontend *fe)
-{
-	struct tda9887_priv *priv = fe->analog_demod_priv;
-	unsigned char buf[1];
-	int rc;
-
-	memset(buf,0,sizeof(buf));
-	if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1)))
-		tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc);
-	dump_read_message(fe, buf);
-	return 0;
-}
-
-static void tda9887_configure(struct dvb_frontend *fe)
-{
-	struct tda9887_priv *priv = fe->analog_demod_priv;
-	int rc;
-
-	memset(priv->data,0,sizeof(priv->data));
-	tda9887_set_tvnorm(fe);
-
-	/* A note on the port settings:
-	   These settings tend to depend on the specifics of the board.
-	   By default they are set to inactive (bit value 1) by this driver,
-	   overwriting any changes made by the tvnorm. This means that it
-	   is the responsibility of the module using the tda9887 to set
-	   these values in case of changes in the tvnorm.
-	   In many cases port 2 should be made active (0) when selecting
-	   SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.
-
-	   For the other standards the tda9887 application note says that
-	   the ports should be set to active (0), but, again, that may
-	   differ depending on the precise hardware configuration.
-	 */
-	priv->data[1] |= cOutputPort1Inactive;
-	priv->data[1] |= cOutputPort2Inactive;
-
-	tda9887_do_config(fe);
-	tda9887_set_insmod(fe);
-
-	if (priv->standby)
-		priv->data[1] |= cForcedMuteAudioON;
-
-	tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
-		  priv->data[1], priv->data[2], priv->data[3]);
-	if (debug > 1)
-		dump_write_message(fe, priv->data);
-
-	if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))
-		tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc);
-
-	if (debug > 2) {
-		msleep_interruptible(1000);
-		tda9887_status(fe);
-	}
-}
-
-/* ---------------------------------------------------------------------- */
-
-static void tda9887_tuner_status(struct dvb_frontend *fe)
-{
-	struct tda9887_priv *priv = fe->analog_demod_priv;
-	tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n",
-		   priv->data[1], priv->data[2], priv->data[3]);
-}
-
-static int tda9887_get_afc(struct dvb_frontend *fe)
-{
-	struct tda9887_priv *priv = fe->analog_demod_priv;
-	static int AFC_BITS_2_kHz[] = {
-		-12500,  -37500,  -62500,  -97500,
-		-112500, -137500, -162500, -187500,
-		187500,  162500,  137500,  112500,
-		97500 ,  62500,   37500 ,  12500
-	};
-	int afc=0;
-	__u8 reg = 0;
-
-	if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,&reg,1))
-		afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
-
-	return afc;
-}
-
-static void tda9887_standby(struct dvb_frontend *fe)
-{
-	struct tda9887_priv *priv = fe->analog_demod_priv;
-
-	priv->standby = true;
-
-	tda9887_configure(fe);
-}
-
-static void tda9887_set_params(struct dvb_frontend *fe,
-			       struct analog_parameters *params)
-{
-	struct tda9887_priv *priv = fe->analog_demod_priv;
-
-	priv->standby = false;
-	priv->mode    = params->mode;
-	priv->audmode = params->audmode;
-	priv->std     = params->std;
-	tda9887_configure(fe);
-}
-
-static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg)
-{
-	struct tda9887_priv *priv = fe->analog_demod_priv;
-
-	priv->config = *(unsigned int *)priv_cfg;
-	tda9887_configure(fe);
-
-	return 0;
-}
-
-static void tda9887_release(struct dvb_frontend *fe)
-{
-	struct tda9887_priv *priv = fe->analog_demod_priv;
-
-	mutex_lock(&tda9887_list_mutex);
-
-	if (priv)
-		hybrid_tuner_release_state(priv);
-
-	mutex_unlock(&tda9887_list_mutex);
-
-	fe->analog_demod_priv = NULL;
-}
-
-static struct analog_demod_ops tda9887_ops = {
-	.info		= {
-		.name	= "tda9887",
-	},
-	.set_params     = tda9887_set_params,
-	.standby        = tda9887_standby,
-	.tuner_status   = tda9887_tuner_status,
-	.get_afc        = tda9887_get_afc,
-	.release        = tda9887_release,
-	.set_config     = tda9887_set_config,
-};
-
-struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
-				    struct i2c_adapter *i2c_adap,
-				    u8 i2c_addr)
-{
-	struct tda9887_priv *priv = NULL;
-	int instance;
-
-	mutex_lock(&tda9887_list_mutex);
-
-	instance = hybrid_tuner_request_state(struct tda9887_priv, priv,
-					      hybrid_tuner_instance_list,
-					      i2c_adap, i2c_addr, "tda9887");
-	switch (instance) {
-	case 0:
-		mutex_unlock(&tda9887_list_mutex);
-		return NULL;
-	case 1:
-		fe->analog_demod_priv = priv;
-		priv->standby = true;
-		tuner_info("tda988[5/6/7] found\n");
-		break;
-	default:
-		fe->analog_demod_priv = priv;
-		break;
-	}
-
-	mutex_unlock(&tda9887_list_mutex);
-
-	memcpy(&fe->ops.analog_ops, &tda9887_ops,
-	       sizeof(struct analog_demod_ops));
-
-	return fe;
-}
-EXPORT_SYMBOL_GPL(tda9887_attach);
-
-MODULE_LICENSE("GPL");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/common/tuners/tda9887.h b/drivers/media/common/tuners/tda9887.h
deleted file mode 100644
index acc419e..0000000
--- a/drivers/media/common/tuners/tda9887.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TDA9887_H__
-#define __TDA9887_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-/* ------------------------------------------------------------------------ */
-#if defined(CONFIG_MEDIA_TUNER_TDA9887) || (defined(CONFIG_MEDIA_TUNER_TDA9887_MODULE) && defined(MODULE))
-extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
-					   struct i2c_adapter *i2c_adap,
-					   u8 i2c_addr);
-#else
-static inline struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
-						  struct i2c_adapter *i2c_adap,
-						  u8 i2c_addr)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* __TDA9887_H__ */
diff --git a/drivers/media/common/tuners/tea5761.c b/drivers/media/common/tuners/tea5761.c
deleted file mode 100644
index bf78cb9..0000000
--- a/drivers/media/common/tuners/tea5761.c
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * For Philips TEA5761 FM Chip
- * I2C address is allways 0x20 (0x10 at 7-bit mode).
- *
- * Copyright (c) 2005-2007 Mauro Carvalho Chehab (mchehab@infradead.org)
- * This code is placed under the terms of the GNUv2 General Public License
- *
- */
-
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/videodev2.h>
-#include <media/tuner.h>
-#include "tuner-i2c.h"
-#include "tea5761.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-struct tea5761_priv {
-	struct tuner_i2c_props i2c_props;
-
-	u32 frequency;
-	bool standby;
-};
-
-/*****************************************************************************/
-
-/***************************
- * TEA5761HN I2C registers *
- ***************************/
-
-/* INTREG - Read: bytes 0 and 1 / Write: byte 0 */
-
-	/* first byte for reading */
-#define TEA5761_INTREG_IFFLAG		0x10
-#define TEA5761_INTREG_LEVFLAG		0x8
-#define TEA5761_INTREG_FRRFLAG		0x2
-#define TEA5761_INTREG_BLFLAG		0x1
-
-	/* second byte for reading / byte for writing */
-#define TEA5761_INTREG_IFMSK		0x10
-#define TEA5761_INTREG_LEVMSK		0x8
-#define TEA5761_INTREG_FRMSK		0x2
-#define TEA5761_INTREG_BLMSK		0x1
-
-/* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */
-
-	/* First byte */
-#define TEA5761_FRQSET_SEARCH_UP 0x80		/* 1=Station search from botton to up */
-#define TEA5761_FRQSET_SEARCH_MODE 0x40		/* 1=Search mode */
-
-	/* Bits 0-5 for divider MSB */
-
-	/* Second byte */
-	/* Bits 0-7 for divider LSB */
-
-/* TNCTRL - Read: bytes 4 and 5 / Write: Bytes 3 and 4 */
-
-	/* first byte */
-
-#define TEA5761_TNCTRL_PUPD_0	0x40	/* Power UP/Power Down MSB */
-#define TEA5761_TNCTRL_BLIM	0X20	/* 1= Japan Frequencies, 0= European frequencies */
-#define TEA5761_TNCTRL_SWPM	0x10	/* 1= software port is FRRFLAG */
-#define TEA5761_TNCTRL_IFCTC	0x08	/* 1= IF count time 15.02 ms, 0= IF count time 2.02 ms */
-#define TEA5761_TNCTRL_AFM	0x04
-#define TEA5761_TNCTRL_SMUTE	0x02	/* 1= Soft mute */
-#define TEA5761_TNCTRL_SNC	0x01
-
-	/* second byte */
-
-#define TEA5761_TNCTRL_MU	0x80	/* 1=Hard mute */
-#define TEA5761_TNCTRL_SSL_1	0x40
-#define TEA5761_TNCTRL_SSL_0	0x20
-#define TEA5761_TNCTRL_HLSI	0x10
-#define TEA5761_TNCTRL_MST	0x08	/* 1 = mono */
-#define TEA5761_TNCTRL_SWP	0x04
-#define TEA5761_TNCTRL_DTC	0x02	/* 1 = deemphasis 50 us, 0 = deemphasis 75 us */
-#define TEA5761_TNCTRL_AHLSI	0x01
-
-/* FRQCHECK - Read: bytes 6 and 7  */
-	/* First byte */
-
-	/* Bits 0-5 for divider MSB */
-
-	/* Second byte */
-	/* Bits 0-7 for divider LSB */
-
-/* TUNCHECK - Read: bytes 8 and 9  */
-
-	/* First byte */
-#define TEA5761_TUNCHECK_IF_MASK	0x7e	/* IF count */
-#define TEA5761_TUNCHECK_TUNTO		0x01
-
-	/* Second byte */
-#define TEA5761_TUNCHECK_LEV_MASK	0xf0	/* Level Count */
-#define TEA5761_TUNCHECK_LD		0x08
-#define TEA5761_TUNCHECK_STEREO		0x04
-
-/* TESTREG - Read: bytes 10 and 11 / Write: bytes 5 and 6 */
-
-	/* All zero = no test mode */
-
-/* MANID - Read: bytes 12 and 13 */
-
-	/* First byte - should be 0x10 */
-#define TEA5767_MANID_VERSION_MASK	0xf0	/* Version = 1 */
-#define TEA5767_MANID_ID_MSB_MASK	0x0f	/* Manufacurer ID - should be 0 */
-
-	/* Second byte - Should be 0x2b */
-
-#define TEA5767_MANID_ID_LSB_MASK	0xfe	/* Manufacturer ID - should be 0x15 */
-#define TEA5767_MANID_IDAV		0x01	/* 1 = Chip has ID, 0 = Chip has no ID */
-
-/* Chip ID - Read: bytes 14 and 15 */
-
-	/* First byte - should be 0x57 */
-
-	/* Second byte - should be 0x61 */
-
-/*****************************************************************************/
-
-#define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */
-static void tea5761_status_dump(unsigned char *buffer)
-{
-	unsigned int div, frq;
-
-	div = ((buffer[2] & 0x3f) << 8) | buffer[3];
-
-	frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4;	/* Freq in KHz */
-
-	printk(KERN_INFO "tea5761: Frequency %d.%03d KHz (divider = 0x%04x)\n",
-	       frq / 1000, frq % 1000, div);
-}
-
-/* Freq should be specifyed at 62.5 Hz */
-static int __set_radio_freq(struct dvb_frontend *fe,
-			    unsigned int freq,
-			    bool mono)
-{
-	struct tea5761_priv *priv = fe->tuner_priv;
-	unsigned int frq = freq;
-	unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 };
-	unsigned div;
-	int rc;
-
-	tuner_dbg("radio freq counter %d\n", frq);
-
-	if (priv->standby) {
-		tuner_dbg("TEA5761 set to standby mode\n");
-		buffer[5] |= TEA5761_TNCTRL_MU;
-	} else {
-		buffer[4] |= TEA5761_TNCTRL_PUPD_0;
-	}
-
-
-	if (mono) {
-		tuner_dbg("TEA5761 set to mono\n");
-		buffer[5] |= TEA5761_TNCTRL_MST;
-	} else {
-		tuner_dbg("TEA5761 set to stereo\n");
-	}
-
-	div = (1000 * (frq * 4 / 16 + 700 + 225) ) >> 15;
-	buffer[1] = (div >> 8) & 0x3f;
-	buffer[2] = div & 0xff;
-
-	if (debug)
-		tea5761_status_dump(buffer);
-
-	if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7)))
-		tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
-
-	priv->frequency = frq * 125 / 2;
-
-	return 0;
-}
-
-static int set_radio_freq(struct dvb_frontend *fe,
-			  struct analog_parameters *params)
-{
-	struct tea5761_priv *priv = fe->analog_demod_priv;
-
-	priv->standby = false;
-
-	return __set_radio_freq(fe, params->frequency,
-				params->audmode == V4L2_TUNER_MODE_MONO);
-}
-
-static int set_radio_sleep(struct dvb_frontend *fe)
-{
-	struct tea5761_priv *priv = fe->analog_demod_priv;
-
-	priv->standby = true;
-
-	return __set_radio_freq(fe, priv->frequency, false);
-}
-
-static int tea5761_read_status(struct dvb_frontend *fe, char *buffer)
-{
-	struct tea5761_priv *priv = fe->tuner_priv;
-	int rc;
-
-	memset(buffer, 0, 16);
-	if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) {
-		tuner_warn("i2c i/o error: rc == %d (should be 16)\n", rc);
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static inline int tea5761_signal(struct dvb_frontend *fe, const char *buffer)
-{
-	struct tea5761_priv *priv = fe->tuner_priv;
-
-	int signal = ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4));
-
-	tuner_dbg("Signal strength: %d\n", signal);
-
-	return signal;
-}
-
-static inline int tea5761_stereo(struct dvb_frontend *fe, const char *buffer)
-{
-	struct tea5761_priv *priv = fe->tuner_priv;
-
-	int stereo = buffer[9] & TEA5761_TUNCHECK_STEREO;
-
-	tuner_dbg("Radio ST GET = %02x\n", stereo);
-
-	return (stereo ? V4L2_TUNER_SUB_STEREO : 0);
-}
-
-static int tea5761_get_status(struct dvb_frontend *fe, u32 *status)
-{
-	unsigned char buffer[16];
-
-	*status = 0;
-
-	if (0 == tea5761_read_status(fe, buffer)) {
-		if (tea5761_signal(fe, buffer))
-			*status = TUNER_STATUS_LOCKED;
-		if (tea5761_stereo(fe, buffer))
-			*status |= TUNER_STATUS_STEREO;
-	}
-
-	return 0;
-}
-
-static int tea5761_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	unsigned char buffer[16];
-
-	*strength = 0;
-
-	if (0 == tea5761_read_status(fe, buffer))
-		*strength = tea5761_signal(fe, buffer);
-
-	return 0;
-}
-
-int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
-{
-	unsigned char buffer[16];
-	int rc;
-	struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr };
-
-	if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) {
-		printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc);
-		return -EINVAL;
-	}
-
-	if ((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061)) {
-		printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x."
-				    " It is not a TEA5761\n",
-				    buffer[13], buffer[14], buffer[15]);
-		return -EINVAL;
-	}
-	printk(KERN_WARNING "tea5761: TEA%02x%02x detected. "
-			    "Manufacturer ID= 0x%02x\n",
-			    buffer[14], buffer[15], buffer[13]);
-
-	return 0;
-}
-
-static int tea5761_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-
-	return 0;
-}
-
-static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct tea5761_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-	return 0;
-}
-
-static struct dvb_tuner_ops tea5761_tuner_ops = {
-	.info = {
-		.name           = "tea5761", // Philips TEA5761HN FM Radio
-	},
-	.set_analog_params = set_radio_freq,
-	.sleep		   = set_radio_sleep,
-	.release           = tea5761_release,
-	.get_frequency     = tea5761_get_frequency,
-	.get_status        = tea5761_get_status,
-	.get_rf_strength   = tea5761_get_rf_strength,
-};
-
-struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
-				    struct i2c_adapter* i2c_adap,
-				    u8 i2c_addr)
-{
-	struct tea5761_priv *priv = NULL;
-
-	if (tea5761_autodetection(i2c_adap, i2c_addr) != 0)
-		return NULL;
-
-	priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-	fe->tuner_priv = priv;
-
-	priv->i2c_props.addr = i2c_addr;
-	priv->i2c_props.adap = i2c_adap;
-	priv->i2c_props.name = "tea5761";
-
-	memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops,
-	       sizeof(struct dvb_tuner_ops));
-
-	tuner_info("type set to %s\n", "Philips TEA5761HN FM Radio");
-
-	return fe;
-}
-
-
-EXPORT_SYMBOL_GPL(tea5761_attach);
-EXPORT_SYMBOL_GPL(tea5761_autodetection);
-
-MODULE_DESCRIPTION("Philips TEA5761 FM tuner driver");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tea5761.h b/drivers/media/common/tuners/tea5761.h
deleted file mode 100644
index 2e2ff82..0000000
--- a/drivers/media/common/tuners/tea5761.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TEA5761_H__
-#define __TEA5761_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE))
-extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
-
-extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
-					   struct i2c_adapter* i2c_adap,
-					   u8 i2c_addr);
-#else
-static inline int tea5761_autodetection(struct i2c_adapter* i2c_adap,
-					u8 i2c_addr)
-{
-	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
-	       __func__);
-	return -EINVAL;
-}
-
-static inline struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
-						   struct i2c_adapter* i2c_adap,
-						   u8 i2c_addr)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* __TEA5761_H__ */
diff --git a/drivers/media/common/tuners/tea5767.c b/drivers/media/common/tuners/tea5767.c
deleted file mode 100644
index 36e85d8..0000000
--- a/drivers/media/common/tuners/tea5767.c
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview
- * I2C address is allways 0xC0.
- *
- *
- * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@infradead.org)
- * This code is placed under the terms of the GNU General Public License
- *
- * tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa
- * from their contributions on DScaler.
- */
-
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/videodev2.h>
-#include "tuner-i2c.h"
-#include "tea5767.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-/*****************************************************************************/
-
-struct tea5767_priv {
-	struct tuner_i2c_props	i2c_props;
-	u32			frequency;
-	struct tea5767_ctrl	ctrl;
-};
-
-/*****************************************************************************/
-
-/******************************
- * Write mode register values *
- ******************************/
-
-/* First register */
-#define TEA5767_MUTE		0x80	/* Mutes output */
-#define TEA5767_SEARCH		0x40	/* Activates station search */
-/* Bits 0-5 for divider MSB */
-
-/* Second register */
-/* Bits 0-7 for divider LSB */
-
-/* Third register */
-
-/* Station search from botton to up */
-#define TEA5767_SEARCH_UP	0x80
-
-/* Searches with ADC output = 10 */
-#define TEA5767_SRCH_HIGH_LVL	0x60
-
-/* Searches with ADC output = 10 */
-#define TEA5767_SRCH_MID_LVL	0x40
-
-/* Searches with ADC output = 5 */
-#define TEA5767_SRCH_LOW_LVL	0x20
-
-/* if on, div=4*(Frf+Fif)/Fref otherwise, div=4*(Frf-Fif)/Freq) */
-#define TEA5767_HIGH_LO_INJECT	0x10
-
-/* Disable stereo */
-#define TEA5767_MONO		0x08
-
-/* Disable right channel and turns to mono */
-#define TEA5767_MUTE_RIGHT	0x04
-
-/* Disable left channel and turns to mono */
-#define TEA5767_MUTE_LEFT	0x02
-
-#define TEA5767_PORT1_HIGH	0x01
-
-/* Fourth register */
-#define TEA5767_PORT2_HIGH	0x80
-/* Chips stops working. Only I2C bus remains on */
-#define TEA5767_STDBY		0x40
-
-/* Japan freq (76-108 MHz. If disabled, 87.5-108 MHz */
-#define TEA5767_JAPAN_BAND	0x20
-
-/* Unselected means 32.768 KHz freq as reference. Otherwise Xtal at 13 MHz */
-#define TEA5767_XTAL_32768	0x10
-
-/* Cuts weak signals */
-#define TEA5767_SOFT_MUTE	0x08
-
-/* Activates high cut control */
-#define TEA5767_HIGH_CUT_CTRL	0x04
-
-/* Activates stereo noise control */
-#define TEA5767_ST_NOISE_CTL	0x02
-
-/* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */
-#define TEA5767_SRCH_IND	0x01
-
-/* Fifth register */
-
-/* By activating, it will use Xtal at 13 MHz as reference for divider */
-#define TEA5767_PLLREF_ENABLE	0x80
-
-/* By activating, deemphasis=50, or else, deemphasis of 50us */
-#define TEA5767_DEEMPH_75	0X40
-
-/*****************************
- * Read mode register values *
- *****************************/
-
-/* First register */
-#define TEA5767_READY_FLAG_MASK	0x80
-#define TEA5767_BAND_LIMIT_MASK	0X40
-/* Bits 0-5 for divider MSB after search or preset */
-
-/* Second register */
-/* Bits 0-7 for divider LSB after search or preset */
-
-/* Third register */
-#define TEA5767_STEREO_MASK	0x80
-#define TEA5767_IF_CNTR_MASK	0x7f
-
-/* Fourth register */
-#define TEA5767_ADC_LEVEL_MASK	0xf0
-
-/* should be 0 */
-#define TEA5767_CHIP_ID_MASK	0x0f
-
-/* Fifth register */
-/* Reserved for future extensions */
-#define TEA5767_RESERVED_MASK	0xff
-
-/*****************************************************************************/
-
-static void tea5767_status_dump(struct tea5767_priv *priv,
-				unsigned char *buffer)
-{
-	unsigned int div, frq;
-
-	if (TEA5767_READY_FLAG_MASK & buffer[0])
-		tuner_info("Ready Flag ON\n");
-	else
-		tuner_info("Ready Flag OFF\n");
-
-	if (TEA5767_BAND_LIMIT_MASK & buffer[0])
-		tuner_info("Tuner at band limit\n");
-	else
-		tuner_info("Tuner not at band limit\n");
-
-	div = ((buffer[0] & 0x3f) << 8) | buffer[1];
-
-	switch (priv->ctrl.xtal_freq) {
-	case TEA5767_HIGH_LO_13MHz:
-		frq = (div * 50000 - 700000 - 225000) / 4;	/* Freq in KHz */
-		break;
-	case TEA5767_LOW_LO_13MHz:
-		frq = (div * 50000 + 700000 + 225000) / 4;	/* Freq in KHz */
-		break;
-	case TEA5767_LOW_LO_32768:
-		frq = (div * 32768 + 700000 + 225000) / 4;	/* Freq in KHz */
-		break;
-	case TEA5767_HIGH_LO_32768:
-	default:
-		frq = (div * 32768 - 700000 - 225000) / 4;	/* Freq in KHz */
-		break;
-	}
-	buffer[0] = (div >> 8) & 0x3f;
-	buffer[1] = div & 0xff;
-
-	tuner_info("Frequency %d.%03d KHz (divider = 0x%04x)\n",
-		   frq / 1000, frq % 1000, div);
-
-	if (TEA5767_STEREO_MASK & buffer[2])
-		tuner_info("Stereo\n");
-	else
-		tuner_info("Mono\n");
-
-	tuner_info("IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK);
-
-	tuner_info("ADC Level = %d\n",
-		   (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4);
-
-	tuner_info("Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK));
-
-	tuner_info("Reserved = 0x%02x\n",
-		   (buffer[4] & TEA5767_RESERVED_MASK));
-}
-
-/* Freq should be specifyed at 62.5 Hz */
-static int set_radio_freq(struct dvb_frontend *fe,
-			  struct analog_parameters *params)
-{
-	struct tea5767_priv *priv = fe->tuner_priv;
-	unsigned int frq = params->frequency;
-	unsigned char buffer[5];
-	unsigned div;
-	int rc;
-
-	tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000);
-
-	buffer[2] = 0;
-
-	if (priv->ctrl.port1)
-		buffer[2] |= TEA5767_PORT1_HIGH;
-
-	if (params->audmode == V4L2_TUNER_MODE_MONO) {
-		tuner_dbg("TEA5767 set to mono\n");
-		buffer[2] |= TEA5767_MONO;
-	} else {
-		tuner_dbg("TEA5767 set to stereo\n");
-	}
-
-
-	buffer[3] = 0;
-
-	if (priv->ctrl.port2)
-		buffer[3] |= TEA5767_PORT2_HIGH;
-
-	if (priv->ctrl.high_cut)
-		buffer[3] |= TEA5767_HIGH_CUT_CTRL;
-
-	if (priv->ctrl.st_noise)
-		buffer[3] |= TEA5767_ST_NOISE_CTL;
-
-	if (priv->ctrl.soft_mute)
-		buffer[3] |= TEA5767_SOFT_MUTE;
-
-	if (priv->ctrl.japan_band)
-		buffer[3] |= TEA5767_JAPAN_BAND;
-
-	buffer[4] = 0;
-
-	if (priv->ctrl.deemph_75)
-		buffer[4] |= TEA5767_DEEMPH_75;
-
-	if (priv->ctrl.pllref)
-		buffer[4] |= TEA5767_PLLREF_ENABLE;
-
-
-	/* Rounds freq to next decimal value - for 62.5 KHz step */
-	/* frq = 20*(frq/16)+radio_frq[frq%16]; */
-
-	switch (priv->ctrl.xtal_freq) {
-	case TEA5767_HIGH_LO_13MHz:
-		tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n");
-		buffer[2] |= TEA5767_HIGH_LO_INJECT;
-		div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000;
-		break;
-	case TEA5767_LOW_LO_13MHz:
-		tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n");
-
-		div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000;
-		break;
-	case TEA5767_LOW_LO_32768:
-		tuner_dbg("radio LOW LO inject xtal @ 32,768 MHz\n");
-		buffer[3] |= TEA5767_XTAL_32768;
-		/* const 700=4000*175 Khz - to adjust freq to right value */
-		div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15;
-		break;
-	case TEA5767_HIGH_LO_32768:
-	default:
-		tuner_dbg("radio HIGH LO inject xtal @ 32,768 MHz\n");
-
-		buffer[2] |= TEA5767_HIGH_LO_INJECT;
-		buffer[3] |= TEA5767_XTAL_32768;
-		div = ((frq * (4000 / 16) + 700000 + 225000) + 16384) >> 15;
-		break;
-	}
-	buffer[0] = (div >> 8) & 0x3f;
-	buffer[1] = div & 0xff;
-
-	if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5)))
-		tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
-
-	if (debug) {
-		if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5)))
-			tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
-		else
-			tea5767_status_dump(priv, buffer);
-	}
-
-	priv->frequency = frq * 125 / 2;
-
-	return 0;
-}
-
-static int tea5767_read_status(struct dvb_frontend *fe, char *buffer)
-{
-	struct tea5767_priv *priv = fe->tuner_priv;
-	int rc;
-
-	memset(buffer, 0, 5);
-	if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) {
-		tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static inline int tea5767_signal(struct dvb_frontend *fe, const char *buffer)
-{
-	struct tea5767_priv *priv = fe->tuner_priv;
-
-	int signal = ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8);
-
-	tuner_dbg("Signal strength: %d\n", signal);
-
-	return signal;
-}
-
-static inline int tea5767_stereo(struct dvb_frontend *fe, const char *buffer)
-{
-	struct tea5767_priv *priv = fe->tuner_priv;
-
-	int stereo = buffer[2] & TEA5767_STEREO_MASK;
-
-	tuner_dbg("Radio ST GET = %02x\n", stereo);
-
-	return (stereo ? V4L2_TUNER_SUB_STEREO : 0);
-}
-
-static int tea5767_get_status(struct dvb_frontend *fe, u32 *status)
-{
-	unsigned char buffer[5];
-
-	*status = 0;
-
-	if (0 == tea5767_read_status(fe, buffer)) {
-		if (tea5767_signal(fe, buffer))
-			*status = TUNER_STATUS_LOCKED;
-		if (tea5767_stereo(fe, buffer))
-			*status |= TUNER_STATUS_STEREO;
-	}
-
-	return 0;
-}
-
-static int tea5767_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	unsigned char buffer[5];
-
-	*strength = 0;
-
-	if (0 == tea5767_read_status(fe, buffer))
-		*strength = tea5767_signal(fe, buffer);
-
-	return 0;
-}
-
-static int tea5767_standby(struct dvb_frontend *fe)
-{
-	unsigned char buffer[5];
-	struct tea5767_priv *priv = fe->tuner_priv;
-	unsigned div, rc;
-
-	div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */
-	buffer[0] = (div >> 8) & 0x3f;
-	buffer[1] = div & 0xff;
-	buffer[2] = TEA5767_PORT1_HIGH;
-	buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL |
-		    TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY;
-	buffer[4] = 0;
-
-	if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5)))
-		tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
-
-	return 0;
-}
-
-int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
-{
-	struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr };
-	unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-	int rc;
-
-	if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) {
-		printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc);
-		return -EINVAL;
-	}
-
-	/* If all bytes are the same then it's a TV tuner and not a tea5767 */
-	if (buffer[0] == buffer[1] && buffer[0] == buffer[2] &&
-	    buffer[0] == buffer[3] && buffer[0] == buffer[4]) {
-		printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n");
-		return -EINVAL;
-	}
-
-	/*  Status bytes:
-	 *  Byte 4: bit 3:1 : CI (Chip Identification) == 0
-	 *          bit 0   : internally set to 0
-	 *  Byte 5: bit 7:0 : == 0
-	 */
-	if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) {
-		printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n");
-		return -EINVAL;
-	}
-
-
-	return 0;
-}
-
-static int tea5767_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-
-	return 0;
-}
-
-static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct tea5767_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-
-	return 0;
-}
-
-static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg)
-{
-	struct tea5767_priv *priv = fe->tuner_priv;
-
-	memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl));
-
-	return 0;
-}
-
-static struct dvb_tuner_ops tea5767_tuner_ops = {
-	.info = {
-		.name           = "tea5767", // Philips TEA5767HN FM Radio
-	},
-
-	.set_analog_params = set_radio_freq,
-	.set_config	   = tea5767_set_config,
-	.sleep             = tea5767_standby,
-	.release           = tea5767_release,
-	.get_frequency     = tea5767_get_frequency,
-	.get_status        = tea5767_get_status,
-	.get_rf_strength   = tea5767_get_rf_strength,
-};
-
-struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
-				    struct i2c_adapter* i2c_adap,
-				    u8 i2c_addr)
-{
-	struct tea5767_priv *priv = NULL;
-
-	priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-	fe->tuner_priv = priv;
-
-	priv->i2c_props.addr  = i2c_addr;
-	priv->i2c_props.adap  = i2c_adap;
-	priv->i2c_props.name  = "tea5767";
-
-	priv->ctrl.xtal_freq  = TEA5767_HIGH_LO_32768;
-	priv->ctrl.port1      = 1;
-	priv->ctrl.port2      = 1;
-	priv->ctrl.high_cut   = 1;
-	priv->ctrl.st_noise   = 1;
-	priv->ctrl.japan_band = 1;
-
-	memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops,
-	       sizeof(struct dvb_tuner_ops));
-
-	tuner_info("type set to %s\n", "Philips TEA5767HN FM Radio");
-
-	return fe;
-}
-
-EXPORT_SYMBOL_GPL(tea5767_attach);
-EXPORT_SYMBOL_GPL(tea5767_autodetection);
-
-MODULE_DESCRIPTION("Philips TEA5767 FM tuner driver");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tea5767.h b/drivers/media/common/tuners/tea5767.h
deleted file mode 100644
index d30ab1b..0000000
--- a/drivers/media/common/tuners/tea5767.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TEA5767_H__
-#define __TEA5767_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-enum tea5767_xtal {
-	TEA5767_LOW_LO_32768    = 0,
-	TEA5767_HIGH_LO_32768   = 1,
-	TEA5767_LOW_LO_13MHz    = 2,
-	TEA5767_HIGH_LO_13MHz   = 3,
-};
-
-struct tea5767_ctrl {
-	unsigned int		port1:1;
-	unsigned int		port2:1;
-	unsigned int		high_cut:1;
-	unsigned int		st_noise:1;
-	unsigned int		soft_mute:1;
-	unsigned int		japan_band:1;
-	unsigned int		deemph_75:1;
-	unsigned int		pllref:1;
-	enum tea5767_xtal	xtal_freq;
-};
-
-#if defined(CONFIG_MEDIA_TUNER_TEA5767) || (defined(CONFIG_MEDIA_TUNER_TEA5767_MODULE) && defined(MODULE))
-extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
-
-extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
-					   struct i2c_adapter* i2c_adap,
-					   u8 i2c_addr);
-#else
-static inline int tea5767_autodetection(struct i2c_adapter* i2c_adap,
-					u8 i2c_addr)
-{
-	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
-	       __func__);
-	return -EINVAL;
-}
-
-static inline struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
-						   struct i2c_adapter* i2c_adap,
-						   u8 i2c_addr)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* __TEA5767_H__ */
diff --git a/drivers/media/common/tuners/tua9001.c b/drivers/media/common/tuners/tua9001.c
deleted file mode 100644
index de26070..0000000
--- a/drivers/media/common/tuners/tua9001.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Infineon TUA 9001 silicon tuner driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "tua9001.h"
-#include "tua9001_priv.h"
-
-/* write register */
-static int tua9001_wr_reg(struct tua9001_priv *priv, u8 reg, u16 val)
-{
-	int ret;
-	u8 buf[3] = { reg, (val >> 8) & 0xff, (val >> 0) & 0xff };
-	struct i2c_msg msg[1] = {
-		{
-			.addr = priv->cfg->i2c_addr,
-			.flags = 0,
-			.len = sizeof(buf),
-			.buf = buf,
-		}
-	};
-
-	ret = i2c_transfer(priv->i2c, msg, 1);
-	if (ret == 1) {
-		ret = 0;
-	} else {
-		printk(KERN_WARNING "%s: I2C wr failed=%d reg=%02x\n",
-				__func__, ret, reg);
-		ret = -EREMOTEIO;
-	}
-
-	return ret;
-}
-
-static int tua9001_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-
-	return 0;
-}
-
-static int tua9001_init(struct dvb_frontend *fe)
-{
-	struct tua9001_priv *priv = fe->tuner_priv;
-	int ret = 0;
-	u8 i;
-	struct reg_val data[] = {
-		{ 0x1e, 0x6512 },
-		{ 0x25, 0xb888 },
-		{ 0x39, 0x5460 },
-		{ 0x3b, 0x00c0 },
-		{ 0x3a, 0xf000 },
-		{ 0x08, 0x0000 },
-		{ 0x32, 0x0030 },
-		{ 0x41, 0x703a },
-		{ 0x40, 0x1c78 },
-		{ 0x2c, 0x1c00 },
-		{ 0x36, 0xc013 },
-		{ 0x37, 0x6f18 },
-		{ 0x27, 0x0008 },
-		{ 0x2a, 0x0001 },
-		{ 0x34, 0x0a40 },
-	};
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */
-
-	for (i = 0; i < ARRAY_SIZE(data); i++) {
-		ret = tua9001_wr_reg(priv, data[i].reg, data[i].val);
-		if (ret)
-			break;
-	}
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */
-
-	if (ret < 0)
-		pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static int tua9001_set_params(struct dvb_frontend *fe)
-{
-	struct tua9001_priv *priv = fe->tuner_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret, i;
-	u16 val;
-	u32 frequency;
-	struct reg_val data[2];
-
-	pr_debug("%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n",
-			__func__, c->delivery_system, c->frequency,
-			c->bandwidth_hz);
-
-	switch (c->delivery_system) {
-	case SYS_DVBT:
-		switch (c->bandwidth_hz) {
-		case 8000000:
-			val  = 0x0000;
-			break;
-		case 7000000:
-			val  = 0x1000;
-			break;
-		case 6000000:
-			val  = 0x2000;
-			break;
-		case 5000000:
-			val  = 0x3000;
-			break;
-		default:
-			ret = -EINVAL;
-			goto err;
-		}
-		break;
-	default:
-		ret = -EINVAL;
-		goto err;
-	}
-
-	data[0].reg = 0x04;
-	data[0].val = val;
-
-	frequency = (c->frequency - 150000000);
-	frequency /= 100;
-	frequency *= 48;
-	frequency /= 10000;
-
-	data[1].reg = 0x1f;
-	data[1].val = frequency;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */
-
-	for (i = 0; i < ARRAY_SIZE(data); i++) {
-		ret = tua9001_wr_reg(priv, data[i].reg, data[i].val);
-		if (ret < 0)
-			break;
-	}
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */
-
-err:
-	if (ret < 0)
-		pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	*frequency = 0; /* Zero-IF */
-
-	return 0;
-}
-
-static const struct dvb_tuner_ops tua9001_tuner_ops = {
-	.info = {
-		.name           = "Infineon TUA 9001",
-
-		.frequency_min  = 170000000,
-		.frequency_max  = 862000000,
-		.frequency_step = 0,
-	},
-
-	.release = tua9001_release,
-
-	.init = tua9001_init,
-	.set_params = tua9001_set_params,
-
-	.get_if_frequency = tua9001_get_if_frequency,
-};
-
-struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe,
-		struct i2c_adapter *i2c, struct tua9001_config *cfg)
-{
-	struct tua9001_priv *priv = NULL;
-
-	priv = kzalloc(sizeof(struct tua9001_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	priv->cfg = cfg;
-	priv->i2c = i2c;
-
-	printk(KERN_INFO "Infineon TUA 9001 successfully attached.");
-
-	memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops,
-			sizeof(struct dvb_tuner_ops));
-
-	fe->tuner_priv = priv;
-	return fe;
-}
-EXPORT_SYMBOL(tua9001_attach);
-
-MODULE_DESCRIPTION("Infineon TUA 9001 silicon tuner driver");
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tua9001.h b/drivers/media/common/tuners/tua9001.h
deleted file mode 100644
index 38d6ae7..0000000
--- a/drivers/media/common/tuners/tua9001.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Infineon TUA 9001 silicon tuner driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef TUA9001_H
-#define TUA9001_H
-
-#include "dvb_frontend.h"
-
-struct tua9001_config {
-	/*
-	 * I2C address
-	 */
-	u8 i2c_addr;
-};
-
-#if defined(CONFIG_MEDIA_TUNER_TUA9001) || \
-	(defined(CONFIG_MEDIA_TUNER_TUA9001_MODULE) && defined(MODULE))
-extern struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe,
-		struct i2c_adapter *i2c, struct tua9001_config *cfg);
-#else
-static inline struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe,
-		struct i2c_adapter *i2c, struct tua9001_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/common/tuners/tua9001_priv.h b/drivers/media/common/tuners/tua9001_priv.h
deleted file mode 100644
index 73cc1ce..0000000
--- a/drivers/media/common/tuners/tua9001_priv.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Infineon TUA 9001 silicon tuner driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef TUA9001_PRIV_H
-#define TUA9001_PRIV_H
-
-struct reg_val {
-	u8 reg;
-	u16 val;
-};
-
-struct tua9001_priv {
-	struct tua9001_config *cfg;
-	struct i2c_adapter *i2c;
-};
-
-#endif
diff --git a/drivers/media/common/tuners/tuner-i2c.h b/drivers/media/common/tuners/tuner-i2c.h
deleted file mode 100644
index 18f0056..0000000
--- a/drivers/media/common/tuners/tuner-i2c.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
-    tuner-i2c.h - i2c interface for different tuners
-
-    Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org)
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TUNER_I2C_H__
-#define __TUNER_I2C_H__
-
-#include <linux/i2c.h>
-#include <linux/slab.h>
-
-struct tuner_i2c_props {
-	u8 addr;
-	struct i2c_adapter *adap;
-
-	/* used for tuner instance management */
-	int count;
-	char *name;
-};
-
-static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len)
-{
-	struct i2c_msg msg = { .addr = props->addr, .flags = 0,
-			       .buf = buf, .len = len };
-	int ret = i2c_transfer(props->adap, &msg, 1);
-
-	return (ret == 1) ? len : ret;
-}
-
-static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, int len)
-{
-	struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD,
-			       .buf = buf, .len = len };
-	int ret = i2c_transfer(props->adap, &msg, 1);
-
-	return (ret == 1) ? len : ret;
-}
-
-static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props,
-					   char *obuf, int olen,
-					   char *ibuf, int ilen)
-{
-	struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0,
-				    .buf = obuf, .len = olen },
-				  { .addr = props->addr, .flags = I2C_M_RD,
-				    .buf = ibuf, .len = ilen } };
-	int ret = i2c_transfer(props->adap, msg, 2);
-
-	return (ret == 2) ? ilen : ret;
-}
-
-/* Callers must declare as a global for the module:
- *
- * static LIST_HEAD(hybrid_tuner_instance_list);
- *
- * hybrid_tuner_instance_list should be the third argument
- * passed into hybrid_tuner_request_state().
- *
- * state structure must contain the following:
- *
- * 	struct list_head	hybrid_tuner_instance_list;
- *	struct tuner_i2c_props	i2c_props;
- *
- * hybrid_tuner_instance_list (both within state structure and globally)
- * is only required if the driver is using hybrid_tuner_request_state
- * and hybrid_tuner_release_state to manage state sharing between
- * multiple instances of hybrid tuners.
- */
-
-#define tuner_printk(kernlvl, i2cprops, fmt, arg...) do {		\
-	printk(kernlvl "%s %d-%04x: " fmt, i2cprops.name,		\
-			i2cprops.adap ?					\
-				i2c_adapter_id(i2cprops.adap) : -1,	\
-			i2cprops.addr, ##arg);				\
-	 } while (0)
-
-/* TO DO: convert all callers of these macros to pass in
- * struct tuner_i2c_props, then remove the macro wrappers */
-
-#define __tuner_warn(i2cprops, fmt, arg...) do {			\
-	tuner_printk(KERN_WARNING, i2cprops, fmt, ##arg);		\
-	} while (0)
-
-#define __tuner_info(i2cprops, fmt, arg...) do {			\
-	tuner_printk(KERN_INFO, i2cprops, fmt, ##arg);			\
-	} while (0)
-
-#define __tuner_err(i2cprops, fmt, arg...) do {				\
-	tuner_printk(KERN_ERR, i2cprops, fmt, ##arg);			\
-	} while (0)
-
-#define __tuner_dbg(i2cprops, fmt, arg...) do {				\
-	if ((debug))							\
-		tuner_printk(KERN_DEBUG, i2cprops, fmt, ##arg);		\
-	} while (0)
-
-#define tuner_warn(fmt, arg...) __tuner_warn(priv->i2c_props, fmt, ##arg)
-#define tuner_info(fmt, arg...) __tuner_info(priv->i2c_props, fmt, ##arg)
-#define tuner_err(fmt, arg...) __tuner_err(priv->i2c_props, fmt, ##arg)
-#define tuner_dbg(fmt, arg...) __tuner_dbg(priv->i2c_props, fmt, ##arg)
-
-/****************************************************************************/
-
-/* The return value of hybrid_tuner_request_state indicates the number of
- * instances using this tuner object.
- *
- * 0 - no instances, indicates an error - kzalloc must have failed
- *
- * 1 - one instance, indicates that the tuner object was created successfully
- *
- * 2 (or more) instances, indicates that an existing tuner object was found
- */
-
-#define hybrid_tuner_request_state(type, state, list, i2cadap, i2caddr, devname)\
-({									\
-	int __ret = 0;							\
-	list_for_each_entry(state, &list, hybrid_tuner_instance_list) {	\
-		if (((i2cadap) && (state->i2c_props.adap)) &&		\
-		    ((i2c_adapter_id(state->i2c_props.adap) ==		\
-		      i2c_adapter_id(i2cadap)) &&			\
-		     (i2caddr == state->i2c_props.addr))) {		\
-			__tuner_info(state->i2c_props,			\
-				     "attaching existing instance\n");	\
-			state->i2c_props.count++;			\
-			__ret = state->i2c_props.count;			\
-			break;						\
-		}							\
-	}								\
-	if (0 == __ret) {						\
-		state = kzalloc(sizeof(type), GFP_KERNEL);		\
-		if (NULL == state)					\
-			goto __fail;					\
-		state->i2c_props.addr = i2caddr;			\
-		state->i2c_props.adap = i2cadap;			\
-		state->i2c_props.name = devname;			\
-		__tuner_info(state->i2c_props,				\
-			     "creating new instance\n");		\
-		list_add_tail(&state->hybrid_tuner_instance_list, &list);\
-		state->i2c_props.count++;				\
-		__ret = state->i2c_props.count;				\
-	}								\
-__fail:									\
-	__ret;								\
-})
-
-#define hybrid_tuner_release_state(state)				\
-({									\
-	int __ret;							\
-	state->i2c_props.count--;					\
-	__ret = state->i2c_props.count;					\
-	if (!state->i2c_props.count) {					\
-		__tuner_info(state->i2c_props, "destroying instance\n");\
-		list_del(&state->hybrid_tuner_instance_list);		\
-		kfree(state);						\
-	}								\
-	__ret;								\
-})
-
-#define hybrid_tuner_report_instance_count(state)			\
-({									\
-	int __ret = 0;							\
-	if (state)							\
-		__ret = state->i2c_props.count;				\
-	__ret;								\
-})
-
-#endif /* __TUNER_I2C_H__ */
diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c
deleted file mode 100644
index 39e7e58..0000000
--- a/drivers/media/common/tuners/tuner-simple.c
+++ /dev/null
@@ -1,1155 +0,0 @@
-/*
- * i2c tv tuner chip device driver
- * controls all those simple 4-control-bytes style tuners.
- *
- * This "tuner-simple" module was split apart from the original "tuner" module.
- */
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <media/tuner.h>
-#include <media/v4l2-common.h>
-#include <media/tuner-types.h>
-#include "tuner-i2c.h"
-#include "tuner-simple.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-#define TUNER_SIMPLE_MAX 64
-static unsigned int simple_devcount;
-
-static int offset;
-module_param(offset, int, 0664);
-MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner");
-
-static unsigned int atv_input[TUNER_SIMPLE_MAX] = \
-			{ [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
-static unsigned int dtv_input[TUNER_SIMPLE_MAX] = \
-			{ [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
-module_param_array(atv_input, int, NULL, 0644);
-module_param_array(dtv_input, int, NULL, 0644);
-MODULE_PARM_DESC(atv_input, "specify atv rf input, 0 for autoselect");
-MODULE_PARM_DESC(dtv_input, "specify dtv rf input, 0 for autoselect");
-
-/* ---------------------------------------------------------------------- */
-
-/* tv standard selection for Temic 4046 FM5
-   this value takes the low bits of control byte 2
-   from datasheet Rev.01, Feb.00
-     standard     BG      I       L       L2      D
-     picture IF   38.9    38.9    38.9    33.95   38.9
-     sound 1      33.4    32.9    32.4    40.45   32.4
-     sound 2      33.16
-     NICAM        33.05   32.348  33.05           33.05
- */
-#define TEMIC_SET_PAL_I         0x05
-#define TEMIC_SET_PAL_DK        0x09
-#define TEMIC_SET_PAL_L         0x0a /* SECAM ? */
-#define TEMIC_SET_PAL_L2        0x0b /* change IF ! */
-#define TEMIC_SET_PAL_BG        0x0c
-
-/* tv tuner system standard selection for Philips FQ1216ME
-   this value takes the low bits of control byte 2
-   from datasheet "1999 Nov 16" (supersedes "1999 Mar 23")
-     standard 		BG	DK	I	L	L`
-     picture carrier	38.90	38.90	38.90	38.90	33.95
-     colour		34.47	34.47	34.47	34.47	38.38
-     sound 1		33.40	32.40	32.90	32.40	40.45
-     sound 2		33.16	-	-	-	-
-     NICAM		33.05	33.05	32.35	33.05	39.80
- */
-#define PHILIPS_SET_PAL_I	0x01 /* Bit 2 always zero !*/
-#define PHILIPS_SET_PAL_BGDK	0x09
-#define PHILIPS_SET_PAL_L2	0x0a
-#define PHILIPS_SET_PAL_L	0x0b
-
-/* system switching for Philips FI1216MF MK2
-   from datasheet "1996 Jul 09",
-    standard         BG     L      L'
-    picture carrier  38.90  38.90  33.95
-    colour	     34.47  34.37  38.38
-    sound 1          33.40  32.40  40.45
-    sound 2          33.16  -      -
-    NICAM            33.05  33.05  39.80
- */
-#define PHILIPS_MF_SET_STD_BG	0x01 /* Bit 2 must be zero, Bit 3 is system output */
-#define PHILIPS_MF_SET_STD_L	0x03 /* Used on Secam France */
-#define PHILIPS_MF_SET_STD_LC	0x02 /* Used on SECAM L' */
-
-/* Control byte */
-
-#define TUNER_RATIO_MASK        0x06 /* Bit cb1:cb2 */
-#define TUNER_RATIO_SELECT_50   0x00
-#define TUNER_RATIO_SELECT_32   0x02
-#define TUNER_RATIO_SELECT_166  0x04
-#define TUNER_RATIO_SELECT_62   0x06
-
-#define TUNER_CHARGE_PUMP       0x40  /* Bit cb6 */
-
-/* Status byte */
-
-#define TUNER_POR	  0x80
-#define TUNER_FL          0x40
-#define TUNER_MODE        0x38
-#define TUNER_AFC         0x07
-#define TUNER_SIGNAL      0x07
-#define TUNER_STEREO      0x10
-
-#define TUNER_PLL_LOCKED   0x40
-#define TUNER_STEREO_MK3   0x04
-
-static DEFINE_MUTEX(tuner_simple_list_mutex);
-static LIST_HEAD(hybrid_tuner_instance_list);
-
-struct tuner_simple_priv {
-	unsigned int nr;
-	u16 last_div;
-
-	struct tuner_i2c_props i2c_props;
-	struct list_head hybrid_tuner_instance_list;
-
-	unsigned int type;
-	struct tunertype *tun;
-
-	u32 frequency;
-	u32 bandwidth;
-};
-
-/* ---------------------------------------------------------------------- */
-
-static int tuner_read_status(struct dvb_frontend *fe)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-	unsigned char byte;
-
-	if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1))
-		return 0;
-
-	return byte;
-}
-
-static inline int tuner_signal(const int status)
-{
-	return (status & TUNER_SIGNAL) << 13;
-}
-
-static inline int tuner_stereo(const int type, const int status)
-{
-	switch (type) {
-	case TUNER_PHILIPS_FM1216ME_MK3:
-	case TUNER_PHILIPS_FM1236_MK3:
-	case TUNER_PHILIPS_FM1256_IH3:
-	case TUNER_LG_NTSC_TAPE:
-	case TUNER_TCL_MF02GIP_5N:
-		return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
-	case TUNER_PHILIPS_FM1216MK5:
-		return status | TUNER_STEREO;
-	default:
-		return status & TUNER_STEREO;
-	}
-}
-
-static inline int tuner_islocked(const int status)
-{
-	return (status & TUNER_FL);
-}
-
-static inline int tuner_afcstatus(const int status)
-{
-	return (status & TUNER_AFC) - 2;
-}
-
-
-static int simple_get_status(struct dvb_frontend *fe, u32 *status)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-	int tuner_status;
-
-	if (priv->i2c_props.adap == NULL)
-		return -EINVAL;
-
-	tuner_status = tuner_read_status(fe);
-
-	*status = 0;
-
-	if (tuner_islocked(tuner_status))
-		*status = TUNER_STATUS_LOCKED;
-	if (tuner_stereo(priv->type, tuner_status))
-		*status |= TUNER_STATUS_STEREO;
-
-	tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status));
-
-	return 0;
-}
-
-static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-	int signal;
-
-	if (priv->i2c_props.adap == NULL)
-		return -EINVAL;
-
-	signal = tuner_signal(tuner_read_status(fe));
-
-	*strength = signal;
-
-	tuner_dbg("Signal strength: %d\n", signal);
-
-	return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static inline char *tuner_param_name(enum param_type type)
-{
-	char *name;
-
-	switch (type) {
-	case TUNER_PARAM_TYPE_RADIO:
-		name = "radio";
-		break;
-	case TUNER_PARAM_TYPE_PAL:
-		name = "pal";
-		break;
-	case TUNER_PARAM_TYPE_SECAM:
-		name = "secam";
-		break;
-	case TUNER_PARAM_TYPE_NTSC:
-		name = "ntsc";
-		break;
-	case TUNER_PARAM_TYPE_DIGITAL:
-		name = "digital";
-		break;
-	default:
-		name = "unknown";
-		break;
-	}
-	return name;
-}
-
-static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe,
-						enum param_type desired_type)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-	struct tunertype *tun = priv->tun;
-	int i;
-
-	for (i = 0; i < tun->count; i++)
-		if (desired_type == tun->params[i].type)
-			break;
-
-	/* use default tuner params if desired_type not available */
-	if (i == tun->count) {
-		tuner_dbg("desired params (%s) undefined for tuner %d\n",
-			  tuner_param_name(desired_type), priv->type);
-		i = 0;
-	}
-
-	tuner_dbg("using tuner params #%d (%s)\n", i,
-		  tuner_param_name(tun->params[i].type));
-
-	return &tun->params[i];
-}
-
-static int simple_config_lookup(struct dvb_frontend *fe,
-				struct tuner_params *t_params,
-				unsigned *frequency, u8 *config, u8 *cb)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-	int i;
-
-	for (i = 0; i < t_params->count; i++) {
-		if (*frequency > t_params->ranges[i].limit)
-			continue;
-		break;
-	}
-	if (i == t_params->count) {
-		tuner_dbg("frequency out of range (%d > %d)\n",
-			  *frequency, t_params->ranges[i - 1].limit);
-		*frequency = t_params->ranges[--i].limit;
-	}
-	*config = t_params->ranges[i].config;
-	*cb     = t_params->ranges[i].cb;
-
-	tuner_dbg("freq = %d.%02d (%d), range = %d, "
-		  "config = 0x%02x, cb = 0x%02x\n",
-		  *frequency / 16, *frequency % 16 * 100 / 16, *frequency,
-		  i, *config, *cb);
-
-	return i;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static void simple_set_rf_input(struct dvb_frontend *fe,
-				u8 *config, u8 *cb, unsigned int rf)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-
-	switch (priv->type) {
-	case TUNER_PHILIPS_TUV1236D:
-		switch (rf) {
-		case 1:
-			*cb |= 0x08;
-			break;
-		default:
-			*cb &= ~0x08;
-			break;
-		}
-		break;
-	case TUNER_PHILIPS_FCV1236D:
-		switch (rf) {
-		case 1:
-			*cb |= 0x01;
-			break;
-		default:
-			*cb &= ~0x01;
-			break;
-		}
-		break;
-	default:
-		break;
-	}
-}
-
-static int simple_std_setup(struct dvb_frontend *fe,
-			    struct analog_parameters *params,
-			    u8 *config, u8 *cb)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-	int rc;
-
-	/* tv norm specific stuff for multi-norm tuners */
-	switch (priv->type) {
-	case TUNER_PHILIPS_SECAM: /* FI1216MF */
-		/* 0x01 -> ??? no change ??? */
-		/* 0x02 -> PAL BDGHI / SECAM L */
-		/* 0x04 -> ??? PAL others / SECAM others ??? */
-		*cb &= ~0x03;
-		if (params->std & V4L2_STD_SECAM_L)
-			/* also valid for V4L2_STD_SECAM */
-			*cb |= PHILIPS_MF_SET_STD_L;
-		else if (params->std & V4L2_STD_SECAM_LC)
-			*cb |= PHILIPS_MF_SET_STD_LC;
-		else /* V4L2_STD_B|V4L2_STD_GH */
-			*cb |= PHILIPS_MF_SET_STD_BG;
-		break;
-
-	case TUNER_TEMIC_4046FM5:
-		*cb &= ~0x0f;
-
-		if (params->std & V4L2_STD_PAL_BG) {
-			*cb |= TEMIC_SET_PAL_BG;
-
-		} else if (params->std & V4L2_STD_PAL_I) {
-			*cb |= TEMIC_SET_PAL_I;
-
-		} else if (params->std & V4L2_STD_PAL_DK) {
-			*cb |= TEMIC_SET_PAL_DK;
-
-		} else if (params->std & V4L2_STD_SECAM_L) {
-			*cb |= TEMIC_SET_PAL_L;
-
-		}
-		break;
-
-	case TUNER_PHILIPS_FQ1216ME:
-		*cb &= ~0x0f;
-
-		if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
-			*cb |= PHILIPS_SET_PAL_BGDK;
-
-		} else if (params->std & V4L2_STD_PAL_I) {
-			*cb |= PHILIPS_SET_PAL_I;
-
-		} else if (params->std & V4L2_STD_SECAM_L) {
-			*cb |= PHILIPS_SET_PAL_L;
-
-		}
-		break;
-
-	case TUNER_PHILIPS_FCV1236D:
-		/* 0x00 -> ATSC antenna input 1 */
-		/* 0x01 -> ATSC antenna input 2 */
-		/* 0x02 -> NTSC antenna input 1 */
-		/* 0x03 -> NTSC antenna input 2 */
-		*cb &= ~0x03;
-		if (!(params->std & V4L2_STD_ATSC))
-			*cb |= 2;
-		break;
-
-	case TUNER_MICROTUNE_4042FI5:
-		/* Set the charge pump for fast tuning */
-		*config |= TUNER_CHARGE_PUMP;
-		break;
-
-	case TUNER_PHILIPS_TUV1236D:
-	{
-		struct tuner_i2c_props i2c = priv->i2c_props;
-		/* 0x40 -> ATSC antenna input 1 */
-		/* 0x48 -> ATSC antenna input 2 */
-		/* 0x00 -> NTSC antenna input 1 */
-		/* 0x08 -> NTSC antenna input 2 */
-		u8 buffer[4] = { 0x14, 0x00, 0x17, 0x00};
-		*cb &= ~0x40;
-		if (params->std & V4L2_STD_ATSC) {
-			*cb |= 0x40;
-			buffer[1] = 0x04;
-		}
-		/* set to the correct mode (analog or digital) */
-		i2c.addr = 0x0a;
-		rc = tuner_i2c_xfer_send(&i2c, &buffer[0], 2);
-		if (2 != rc)
-			tuner_warn("i2c i/o error: rc == %d "
-				   "(should be 2)\n", rc);
-		rc = tuner_i2c_xfer_send(&i2c, &buffer[2], 2);
-		if (2 != rc)
-			tuner_warn("i2c i/o error: rc == %d "
-				   "(should be 2)\n", rc);
-		break;
-	}
-	}
-	if (atv_input[priv->nr])
-		simple_set_rf_input(fe, config, cb, atv_input[priv->nr]);
-
-	return 0;
-}
-
-static int simple_set_aux_byte(struct dvb_frontend *fe, u8 config, u8 aux)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-	int rc;
-	u8 buffer[2];
-
-	buffer[0] = (config & ~0x38) | 0x18;
-	buffer[1] = aux;
-
-	tuner_dbg("setting aux byte: 0x%02x 0x%02x\n", buffer[0], buffer[1]);
-
-	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
-	if (2 != rc)
-		tuner_warn("i2c i/o error: rc == %d (should be 2)\n", rc);
-
-	return rc == 2 ? 0 : rc;
-}
-
-static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
-			    u16 div, u8 config, u8 cb)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-	int rc;
-
-	switch (priv->type) {
-	case TUNER_LG_TDVS_H06XF:
-		simple_set_aux_byte(fe, config, 0x20);
-		break;
-	case TUNER_PHILIPS_FQ1216LME_MK3:
-		simple_set_aux_byte(fe, config, 0x60); /* External AGC */
-		break;
-	case TUNER_MICROTUNE_4042FI5:
-	{
-		/* FIXME - this may also work for other tuners */
-		unsigned long timeout = jiffies + msecs_to_jiffies(1);
-		u8 status_byte = 0;
-
-		/* Wait until the PLL locks */
-		for (;;) {
-			if (time_after(jiffies, timeout))
-				return 0;
-			rc = tuner_i2c_xfer_recv(&priv->i2c_props,
-						 &status_byte, 1);
-			if (1 != rc) {
-				tuner_warn("i2c i/o read error: rc == %d "
-					   "(should be 1)\n", rc);
-				break;
-			}
-			if (status_byte & TUNER_PLL_LOCKED)
-				break;
-			udelay(10);
-		}
-
-		/* Set the charge pump for optimized phase noise figure */
-		config &= ~TUNER_CHARGE_PUMP;
-		buffer[0] = (div>>8) & 0x7f;
-		buffer[1] = div      & 0xff;
-		buffer[2] = config;
-		buffer[3] = cb;
-		tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
-			  buffer[0], buffer[1], buffer[2], buffer[3]);
-
-		rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
-		if (4 != rc)
-			tuner_warn("i2c i/o error: rc == %d "
-				   "(should be 4)\n", rc);
-		break;
-	}
-	}
-
-	return 0;
-}
-
-static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-
-	switch (priv->type) {
-	case TUNER_TENA_9533_DI:
-	case TUNER_YMEC_TVF_5533MF:
-		tuner_dbg("This tuner doesn't have FM. "
-			  "Most cards have a TEA5767 for FM\n");
-		return 0;
-	case TUNER_PHILIPS_FM1216ME_MK3:
-	case TUNER_PHILIPS_FM1236_MK3:
-	case TUNER_PHILIPS_FMD1216ME_MK3:
-	case TUNER_PHILIPS_FMD1216MEX_MK3:
-	case TUNER_LG_NTSC_TAPE:
-	case TUNER_PHILIPS_FM1256_IH3:
-	case TUNER_TCL_MF02GIP_5N:
-		buffer[3] = 0x19;
-		break;
-	case TUNER_PHILIPS_FM1216MK5:
-		buffer[2] = 0x88;
-		buffer[3] = 0x09;
-		break;
-	case TUNER_TNF_5335MF:
-		buffer[3] = 0x11;
-		break;
-	case TUNER_LG_PAL_FM:
-		buffer[3] = 0xa5;
-		break;
-	case TUNER_THOMSON_DTT761X:
-		buffer[3] = 0x39;
-		break;
-	case TUNER_PHILIPS_FQ1216LME_MK3:
-	case TUNER_PHILIPS_FQ1236_MK5:
-		tuner_err("This tuner doesn't have FM\n");
-		/* Set the low band for sanity, since it covers 88-108 MHz */
-		buffer[3] = 0x01;
-		break;
-	case TUNER_MICROTUNE_4049FM5:
-	default:
-		buffer[3] = 0xa4;
-		break;
-	}
-
-	return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int simple_set_tv_freq(struct dvb_frontend *fe,
-			      struct analog_parameters *params)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-	u8 config, cb;
-	u16 div;
-	u8 buffer[4];
-	int rc, IFPCoff, i;
-	enum param_type desired_type;
-	struct tuner_params *t_params;
-
-	/* IFPCoff = Video Intermediate Frequency - Vif:
-		940  =16*58.75  NTSC/J (Japan)
-		732  =16*45.75  M/N STD
-		704  =16*44     ATSC (at DVB code)
-		632  =16*39.50  I U.K.
-		622.4=16*38.90  B/G D/K I, L STD
-		592  =16*37.00  D China
-		590  =16.36.875 B Australia
-		543.2=16*33.95  L' STD
-		171.2=16*10.70  FM Radio (at set_radio_freq)
-	*/
-
-	if (params->std == V4L2_STD_NTSC_M_JP) {
-		IFPCoff      = 940;
-		desired_type = TUNER_PARAM_TYPE_NTSC;
-	} else if ((params->std & V4L2_STD_MN) &&
-		  !(params->std & ~V4L2_STD_MN)) {
-		IFPCoff      = 732;
-		desired_type = TUNER_PARAM_TYPE_NTSC;
-	} else if (params->std == V4L2_STD_SECAM_LC) {
-		IFPCoff      = 543;
-		desired_type = TUNER_PARAM_TYPE_SECAM;
-	} else {
-		IFPCoff      = 623;
-		desired_type = TUNER_PARAM_TYPE_PAL;
-	}
-
-	t_params = simple_tuner_params(fe, desired_type);
-
-	i = simple_config_lookup(fe, t_params, &params->frequency,
-				 &config, &cb);
-
-	div = params->frequency + IFPCoff + offset;
-
-	tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, "
-		  "Offset=%d.%02d MHz, div=%0d\n",
-		  params->frequency / 16, params->frequency % 16 * 100 / 16,
-		  IFPCoff / 16, IFPCoff % 16 * 100 / 16,
-		  offset / 16, offset % 16 * 100 / 16, div);
-
-	/* tv norm specific stuff for multi-norm tuners */
-	simple_std_setup(fe, params, &config, &cb);
-
-	if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
-		buffer[0] = config;
-		buffer[1] = cb;
-		buffer[2] = (div>>8) & 0x7f;
-		buffer[3] = div      & 0xff;
-	} else {
-		buffer[0] = (div>>8) & 0x7f;
-		buffer[1] = div      & 0xff;
-		buffer[2] = config;
-		buffer[3] = cb;
-	}
-	priv->last_div = div;
-	if (t_params->has_tda9887) {
-		struct v4l2_priv_tun_config tda9887_cfg;
-		int tda_config = 0;
-		int is_secam_l = (params->std & (V4L2_STD_SECAM_L |
-						 V4L2_STD_SECAM_LC)) &&
-			!(params->std & ~(V4L2_STD_SECAM_L |
-					  V4L2_STD_SECAM_LC));
-
-		tda9887_cfg.tuner = TUNER_TDA9887;
-		tda9887_cfg.priv  = &tda_config;
-
-		if (params->std == V4L2_STD_SECAM_LC) {
-			if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
-				tda_config |= TDA9887_PORT1_ACTIVE;
-			if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)
-				tda_config |= TDA9887_PORT2_ACTIVE;
-		} else {
-			if (t_params->port1_active)
-				tda_config |= TDA9887_PORT1_ACTIVE;
-			if (t_params->port2_active)
-				tda_config |= TDA9887_PORT2_ACTIVE;
-		}
-		if (t_params->intercarrier_mode)
-			tda_config |= TDA9887_INTERCARRIER;
-		if (is_secam_l) {
-			if (i == 0 && t_params->default_top_secam_low)
-				tda_config |= TDA9887_TOP(t_params->default_top_secam_low);
-			else if (i == 1 && t_params->default_top_secam_mid)
-				tda_config |= TDA9887_TOP(t_params->default_top_secam_mid);
-			else if (t_params->default_top_secam_high)
-				tda_config |= TDA9887_TOP(t_params->default_top_secam_high);
-		} else {
-			if (i == 0 && t_params->default_top_low)
-				tda_config |= TDA9887_TOP(t_params->default_top_low);
-			else if (i == 1 && t_params->default_top_mid)
-				tda_config |= TDA9887_TOP(t_params->default_top_mid);
-			else if (t_params->default_top_high)
-				tda_config |= TDA9887_TOP(t_params->default_top_high);
-		}
-		if (t_params->default_pll_gating_18)
-			tda_config |= TDA9887_GATING_18;
-		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
-				    &tda9887_cfg);
-	}
-	tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
-		  buffer[0], buffer[1], buffer[2], buffer[3]);
-
-	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
-	if (4 != rc)
-		tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
-
-	simple_post_tune(fe, &buffer[0], div, config, cb);
-
-	return 0;
-}
-
-static int simple_set_radio_freq(struct dvb_frontend *fe,
-				 struct analog_parameters *params)
-{
-	struct tunertype *tun;
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-	u8 buffer[4];
-	u16 div;
-	int rc, j;
-	struct tuner_params *t_params;
-	unsigned int freq = params->frequency;
-
-	tun = priv->tun;
-
-	for (j = tun->count-1; j > 0; j--)
-		if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO)
-			break;
-	/* default t_params (j=0) will be used if desired type wasn't found */
-	t_params = &tun->params[j];
-
-	/* Select Radio 1st IF used */
-	switch (t_params->radio_if) {
-	case 0: /* 10.7 MHz */
-		freq += (unsigned int)(10.7*16000);
-		break;
-	case 1: /* 33.3 MHz */
-		freq += (unsigned int)(33.3*16000);
-		break;
-	case 2: /* 41.3 MHz */
-		freq += (unsigned int)(41.3*16000);
-		break;
-	default:
-		tuner_warn("Unsupported radio_if value %d\n",
-			   t_params->radio_if);
-		return 0;
-	}
-
-	buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
-		    TUNER_RATIO_SELECT_50; /* 50 kHz step */
-
-	/* Bandswitch byte */
-	simple_radio_bandswitch(fe, &buffer[0]);
-
-	/* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
-	   freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
-	   freq * (1/800) */
-	div = (freq + 400) / 800;
-
-	if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
-		buffer[0] = buffer[2];
-		buffer[1] = buffer[3];
-		buffer[2] = (div>>8) & 0x7f;
-		buffer[3] = div      & 0xff;
-	} else {
-		buffer[0] = (div>>8) & 0x7f;
-		buffer[1] = div      & 0xff;
-	}
-
-	tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
-	       buffer[0], buffer[1], buffer[2], buffer[3]);
-	priv->last_div = div;
-
-	if (t_params->has_tda9887) {
-		int config = 0;
-		struct v4l2_priv_tun_config tda9887_cfg;
-
-		tda9887_cfg.tuner = TUNER_TDA9887;
-		tda9887_cfg.priv = &config;
-
-		if (t_params->port1_active &&
-		    !t_params->port1_fm_high_sensitivity)
-			config |= TDA9887_PORT1_ACTIVE;
-		if (t_params->port2_active &&
-		    !t_params->port2_fm_high_sensitivity)
-			config |= TDA9887_PORT2_ACTIVE;
-		if (t_params->intercarrier_mode)
-			config |= TDA9887_INTERCARRIER;
-/*		if (t_params->port1_set_for_fm_mono)
-			config &= ~TDA9887_PORT1_ACTIVE;*/
-		if (t_params->fm_gain_normal)
-			config |= TDA9887_GAIN_NORMAL;
-		if (t_params->radio_if == 2)
-			config |= TDA9887_RIF_41_3;
-		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
-				    &tda9887_cfg);
-	}
-	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
-	if (4 != rc)
-		tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
-
-	/* Write AUX byte */
-	switch (priv->type) {
-	case TUNER_PHILIPS_FM1216ME_MK3:
-		buffer[2] = 0x98;
-		buffer[3] = 0x20; /* set TOP AGC */
-		rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
-		if (4 != rc)
-			tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
-		break;
-	}
-
-	return 0;
-}
-
-static int simple_set_params(struct dvb_frontend *fe,
-			     struct analog_parameters *params)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-	int ret = -EINVAL;
-
-	if (priv->i2c_props.adap == NULL)
-		return -EINVAL;
-
-	switch (params->mode) {
-	case V4L2_TUNER_RADIO:
-		ret = simple_set_radio_freq(fe, params);
-		priv->frequency = params->frequency * 125 / 2;
-		break;
-	case V4L2_TUNER_ANALOG_TV:
-	case V4L2_TUNER_DIGITAL_TV:
-		ret = simple_set_tv_freq(fe, params);
-		priv->frequency = params->frequency * 62500;
-		break;
-	}
-	priv->bandwidth = 0;
-
-	return ret;
-}
-
-static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
-			   const u32 delsys,
-			   const u32 frequency,
-			   const u32 bandwidth)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-
-	switch (priv->type) {
-	case TUNER_PHILIPS_FMD1216ME_MK3:
-	case TUNER_PHILIPS_FMD1216MEX_MK3:
-		if (bandwidth == 8000000 &&
-		    frequency >= 158870000)
-			buf[3] |= 0x08;
-		break;
-	case TUNER_PHILIPS_TD1316:
-		/* determine band */
-		buf[3] |= (frequency < 161000000) ? 1 :
-			  (frequency < 444000000) ? 2 : 4;
-
-		/* setup PLL filter */
-		if (bandwidth == 8000000)
-			buf[3] |= 1 << 3;
-		break;
-	case TUNER_PHILIPS_TUV1236D:
-	case TUNER_PHILIPS_FCV1236D:
-	{
-		unsigned int new_rf;
-
-		if (dtv_input[priv->nr])
-			new_rf = dtv_input[priv->nr];
-		else
-			switch (delsys) {
-			case SYS_DVBC_ANNEX_B:
-				new_rf = 1;
-				break;
-			case SYS_ATSC:
-			default:
-				new_rf = 0;
-				break;
-			}
-		simple_set_rf_input(fe, &buf[2], &buf[3], new_rf);
-		break;
-	}
-	default:
-		break;
-	}
-}
-
-static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
-				const u32 delsys,
-				const u32 freq,
-				const u32 bw)
-{
-	/* This function returns the tuned frequency on success, 0 on error */
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-	struct tunertype *tun = priv->tun;
-	static struct tuner_params *t_params;
-	u8 config, cb;
-	u32 div;
-	int ret;
-	u32 frequency = freq / 62500;
-
-	if (!tun->stepsize) {
-		/* tuner-core was loaded before the digital tuner was
-		 * configured and somehow picked the wrong tuner type */
-		tuner_err("attempt to treat tuner %d (%s) as digital tuner "
-			  "without stepsize defined.\n",
-			  priv->type, priv->tun->name);
-		return 0; /* failure */
-	}
-
-	t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL);
-	ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb);
-	if (ret < 0)
-		return 0; /* failure */
-
-	div = ((frequency + t_params->iffreq) * 62500 + offset +
-	       tun->stepsize/2) / tun->stepsize;
-
-	buf[0] = div >> 8;
-	buf[1] = div & 0xff;
-	buf[2] = config;
-	buf[3] = cb;
-
-	simple_set_dvb(fe, buf, delsys, freq, bw);
-
-	tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
-		  tun->name, div, buf[0], buf[1], buf[2], buf[3]);
-
-	/* calculate the frequency we set it to */
-	return (div * tun->stepsize) - t_params->iffreq;
-}
-
-static int simple_dvb_calc_regs(struct dvb_frontend *fe,
-				u8 *buf, int buf_len)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 delsys = c->delivery_system;
-	u32 bw = c->bandwidth_hz;
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-	u32 frequency;
-
-	if (buf_len < 5)
-		return -EINVAL;
-
-	frequency = simple_dvb_configure(fe, buf+1, delsys, c->frequency, bw);
-	if (frequency == 0)
-		return -EINVAL;
-
-	buf[0] = priv->i2c_props.addr;
-
-	priv->frequency = frequency;
-	priv->bandwidth = c->bandwidth_hz;
-
-	return 5;
-}
-
-static int simple_dvb_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 delsys = c->delivery_system;
-	u32 bw = c->bandwidth_hz;
-	u32 freq = c->frequency;
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-	u32 frequency;
-	u32 prev_freq, prev_bw;
-	int ret;
-	u8 buf[5];
-
-	if (priv->i2c_props.adap == NULL)
-		return -EINVAL;
-
-	prev_freq = priv->frequency;
-	prev_bw   = priv->bandwidth;
-
-	frequency = simple_dvb_configure(fe, buf+1, delsys, freq, bw);
-	if (frequency == 0)
-		return -EINVAL;
-
-	buf[0] = priv->i2c_props.addr;
-
-	priv->frequency = frequency;
-	priv->bandwidth = bw;
-
-	/* put analog demod in standby when tuning digital */
-	if (fe->ops.analog_ops.standby)
-		fe->ops.analog_ops.standby(fe);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	/* buf[0] contains the i2c address, but *
-	 * we already have it in i2c_props.addr */
-	ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4);
-	if (ret != 4)
-		goto fail;
-
-	return 0;
-fail:
-	/* calc_regs sets frequency and bandwidth. if we failed, unset them */
-	priv->frequency = prev_freq;
-	priv->bandwidth = prev_bw;
-
-	return ret;
-}
-
-static int simple_init(struct dvb_frontend *fe)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-
-	if (priv->i2c_props.adap == NULL)
-		return -EINVAL;
-
-	if (priv->tun->initdata) {
-		int ret;
-
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-
-		ret = tuner_i2c_xfer_send(&priv->i2c_props,
-					  priv->tun->initdata + 1,
-					  priv->tun->initdata[0]);
-		if (ret != priv->tun->initdata[0])
-			return ret;
-	}
-
-	return 0;
-}
-
-static int simple_sleep(struct dvb_frontend *fe)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-
-	if (priv->i2c_props.adap == NULL)
-		return -EINVAL;
-
-	if (priv->tun->sleepdata) {
-		int ret;
-
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-
-		ret = tuner_i2c_xfer_send(&priv->i2c_props,
-					  priv->tun->sleepdata + 1,
-					  priv->tun->sleepdata[0]);
-		if (ret != priv->tun->sleepdata[0])
-			return ret;
-	}
-
-	return 0;
-}
-
-static int simple_release(struct dvb_frontend *fe)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-
-	mutex_lock(&tuner_simple_list_mutex);
-
-	if (priv)
-		hybrid_tuner_release_state(priv);
-
-	mutex_unlock(&tuner_simple_list_mutex);
-
-	fe->tuner_priv = NULL;
-
-	return 0;
-}
-
-static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-	return 0;
-}
-
-static int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	struct tuner_simple_priv *priv = fe->tuner_priv;
-	*bandwidth = priv->bandwidth;
-	return 0;
-}
-
-static struct dvb_tuner_ops simple_tuner_ops = {
-	.init              = simple_init,
-	.sleep             = simple_sleep,
-	.set_analog_params = simple_set_params,
-	.set_params        = simple_dvb_set_params,
-	.calc_regs         = simple_dvb_calc_regs,
-	.release           = simple_release,
-	.get_frequency     = simple_get_frequency,
-	.get_bandwidth     = simple_get_bandwidth,
-	.get_status        = simple_get_status,
-	.get_rf_strength   = simple_get_rf_strength,
-};
-
-struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
-					 struct i2c_adapter *i2c_adap,
-					 u8 i2c_addr,
-					 unsigned int type)
-{
-	struct tuner_simple_priv *priv = NULL;
-	int instance;
-
-	if (type >= tuner_count) {
-		printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n",
-		       __func__, type, tuner_count-1);
-		return NULL;
-	}
-
-	/* If i2c_adap is set, check that the tuner is at the correct address.
-	 * Otherwise, if i2c_adap is NULL, the tuner will be programmed directly
-	 * by the digital demod via calc_regs.
-	 */
-	if (i2c_adap != NULL) {
-		u8 b[1];
-		struct i2c_msg msg = {
-			.addr = i2c_addr, .flags = I2C_M_RD,
-			.buf = b, .len = 1,
-		};
-
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-
-		if (1 != i2c_transfer(i2c_adap, &msg, 1))
-			printk(KERN_WARNING "tuner-simple %d-%04x: "
-			       "unable to probe %s, proceeding anyway.",
-			       i2c_adapter_id(i2c_adap), i2c_addr,
-			       tuners[type].name);
-
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	mutex_lock(&tuner_simple_list_mutex);
-
-	instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv,
-					      hybrid_tuner_instance_list,
-					      i2c_adap, i2c_addr,
-					      "tuner-simple");
-	switch (instance) {
-	case 0:
-		mutex_unlock(&tuner_simple_list_mutex);
-		return NULL;
-	case 1:
-		fe->tuner_priv = priv;
-
-		priv->type = type;
-		priv->tun  = &tuners[type];
-		priv->nr   = simple_devcount++;
-		break;
-	default:
-		fe->tuner_priv = priv;
-		break;
-	}
-
-	mutex_unlock(&tuner_simple_list_mutex);
-
-	memcpy(&fe->ops.tuner_ops, &simple_tuner_ops,
-	       sizeof(struct dvb_tuner_ops));
-
-	if (type != priv->type)
-		tuner_warn("couldn't set type to %d. Using %d (%s) instead\n",
-			    type, priv->type, priv->tun->name);
-	else
-		tuner_info("type set to %d (%s)\n",
-			   priv->type, priv->tun->name);
-
-	if ((debug) || ((atv_input[priv->nr] > 0) ||
-			(dtv_input[priv->nr] > 0))) {
-		if (0 == atv_input[priv->nr])
-			tuner_info("tuner %d atv rf input will be "
-				   "autoselected\n", priv->nr);
-		else
-			tuner_info("tuner %d atv rf input will be "
-				   "set to input %d (insmod option)\n",
-				   priv->nr, atv_input[priv->nr]);
-		if (0 == dtv_input[priv->nr])
-			tuner_info("tuner %d dtv rf input will be "
-				   "autoselected\n", priv->nr);
-		else
-			tuner_info("tuner %d dtv rf input will be "
-				   "set to input %d (insmod option)\n",
-				   priv->nr, dtv_input[priv->nr]);
-	}
-
-	strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name,
-		sizeof(fe->ops.tuner_ops.info.name));
-
-	return fe;
-}
-EXPORT_SYMBOL_GPL(simple_tuner_attach);
-
-MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver");
-MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
-MODULE_LICENSE("GPL");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/common/tuners/tuner-simple.h b/drivers/media/common/tuners/tuner-simple.h
deleted file mode 100644
index 381fa5d..0000000
--- a/drivers/media/common/tuners/tuner-simple.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TUNER_SIMPLE_H__
-#define __TUNER_SIMPLE_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-#if defined(CONFIG_MEDIA_TUNER_SIMPLE) || (defined(CONFIG_MEDIA_TUNER_SIMPLE_MODULE) && defined(MODULE))
-extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
-						struct i2c_adapter *i2c_adap,
-						u8 i2c_addr,
-						unsigned int type);
-#else
-static inline struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
-						       struct i2c_adapter *i2c_adap,
-						       u8 i2c_addr,
-						       unsigned int type)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* __TUNER_SIMPLE_H__ */
diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c
deleted file mode 100644
index 2da4440..0000000
--- a/drivers/media/common/tuners/tuner-types.c
+++ /dev/null
@@ -1,1883 +0,0 @@
-/*
- *
- * i2c tv tuner chip device type database.
- *
- */
-
-#include <linux/i2c.h>
-#include <linux/module.h>
-#include <media/tuner.h>
-#include <media/tuner-types.h>
-
-/* ---------------------------------------------------------------------- */
-
-/*
- *	The floats in the tuner struct are computed at compile time
- *	by gcc and cast back to integers. Thus we don't violate the
- *	"no float in kernel" rule.
- *
- *	A tuner_range may be referenced by multiple tuner_params structs.
- *	There are many duplicates in here. Reusing tuner_range structs,
- *	rather than defining new ones for each tuner, will cut down on
- *	memory usage, and is preferred when possible.
- *
- *	Each tuner_params array may contain one or more elements, one
- *	for each video standard.
- *
- *	FIXME: tuner_params struct contains an element, tda988x. We must
- *	set this for all tuners that contain a tda988x chip, and then we
- *	can remove this setting from the various card structs.
- *
- *	FIXME: Right now, all tuners are using the first tuner_params[]
- *	array element for analog mode. In the future, we will be merging
- *	similar tuner definitions together, such that each tuner definition
- *	will have a tuner_params struct for each available video standard.
- *	At that point, the tuner_params[] array element will be chosen
- *	based on the video standard in use.
- */
-
-/* The following was taken from dvb-pll.c: */
-
-/* Set AGC TOP value to 103 dBuV:
- *	0x80 = Control Byte
- *	0x40 = 250 uA charge pump (irrelevant)
- *	0x18 = Aux Byte to follow
- *	0x06 = 64.5 kHz divider (irrelevant)
- *	0x01 = Disable Vt (aka sleep)
- *
- *	0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA)
- *	0x50 = AGC Take over point = 103 dBuV
- */
-static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 };
-
-/*	0x04 = 166.67 kHz divider
- *
- *	0x80 = AGC Time constant 50ms Iagc = 9 uA
- *	0x20 = AGC Take over point = 112 dBuV
- */
-static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 };
-
-/* 0-9 */
-/* ------------ TUNER_TEMIC_PAL - TEMIC PAL ------------ */
-
-static struct tuner_range tuner_temic_pal_ranges[] = {
-	{ 16 * 140.25 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 463.25 /*MHz*/, 0x8e, 0x04, },
-	{ 16 * 999.99        , 0x8e, 0x01, },
-};
-
-static struct tuner_params tuner_temic_pal_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_temic_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_PHILIPS_PAL_I - Philips PAL_I ------------ */
-
-static struct tuner_range tuner_philips_pal_i_ranges[] = {
-	{ 16 * 140.25 /*MHz*/, 0x8e, 0xa0, },
-	{ 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
-	{ 16 * 999.99        , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_philips_pal_i_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_philips_pal_i_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_pal_i_ranges),
-	},
-};
-
-/* ------------ TUNER_PHILIPS_NTSC - Philips NTSC ------------ */
-
-static struct tuner_range tuner_philips_ntsc_ranges[] = {
-	{ 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
-	{ 16 * 451.25 /*MHz*/, 0x8e, 0x90, },
-	{ 16 * 999.99        , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_philips_ntsc_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_philips_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_ntsc_ranges),
-		.cb_first_if_lower_freq = 1,
-	},
-};
-
-/* ------------ TUNER_PHILIPS_SECAM - Philips SECAM ------------ */
-
-static struct tuner_range tuner_philips_secam_ranges[] = {
-	{ 16 * 168.25 /*MHz*/, 0x8e, 0xa7, },
-	{ 16 * 447.25 /*MHz*/, 0x8e, 0x97, },
-	{ 16 * 999.99        , 0x8e, 0x37, },
-};
-
-static struct tuner_params tuner_philips_secam_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_SECAM,
-		.ranges = tuner_philips_secam_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_secam_ranges),
-		.cb_first_if_lower_freq = 1,
-	},
-};
-
-/* ------------ TUNER_PHILIPS_PAL - Philips PAL ------------ */
-
-static struct tuner_range tuner_philips_pal_ranges[] = {
-	{ 16 * 168.25 /*MHz*/, 0x8e, 0xa0, },
-	{ 16 * 447.25 /*MHz*/, 0x8e, 0x90, },
-	{ 16 * 999.99        , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_philips_pal_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_philips_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_pal_ranges),
-		.cb_first_if_lower_freq = 1,
-	},
-};
-
-/* ------------ TUNER_TEMIC_NTSC - TEMIC NTSC ------------ */
-
-static struct tuner_range tuner_temic_ntsc_ranges[] = {
-	{ 16 * 157.25 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 463.25 /*MHz*/, 0x8e, 0x04, },
-	{ 16 * 999.99        , 0x8e, 0x01, },
-};
-
-static struct tuner_params tuner_temic_ntsc_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_temic_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_ntsc_ranges),
-	},
-};
-
-/* ------------ TUNER_TEMIC_PAL_I - TEMIC PAL_I ------------ */
-
-static struct tuner_range tuner_temic_pal_i_ranges[] = {
-	{ 16 * 170.00 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 450.00 /*MHz*/, 0x8e, 0x04, },
-	{ 16 * 999.99        , 0x8e, 0x01, },
-};
-
-static struct tuner_params tuner_temic_pal_i_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_temic_pal_i_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_pal_i_ranges),
-	},
-};
-
-/* ------------ TUNER_TEMIC_4036FY5_NTSC - TEMIC NTSC ------------ */
-
-static struct tuner_range tuner_temic_4036fy5_ntsc_ranges[] = {
-	{ 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
-	{ 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
-	{ 16 * 999.99        , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_temic_4036fy5_ntsc_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_temic_4036fy5_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_ranges),
-	},
-};
-
-/* ------------ TUNER_ALPS_TSBH1_NTSC - TEMIC NTSC ------------ */
-
-static struct tuner_range tuner_alps_tsb_1_ranges[] = {
-	{ 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
-	{ 16 * 385.25 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 999.99        , 0x8e, 0x08, },
-};
-
-static struct tuner_params tuner_alps_tsbh1_ntsc_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_alps_tsb_1_ranges,
-		.count  = ARRAY_SIZE(tuner_alps_tsb_1_ranges),
-	},
-};
-
-/* 10-19 */
-/* ------------ TUNER_ALPS_TSBE1_PAL - TEMIC PAL ------------ */
-
-static struct tuner_params tuner_alps_tsb_1_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_alps_tsb_1_ranges,
-		.count  = ARRAY_SIZE(tuner_alps_tsb_1_ranges),
-	},
-};
-
-/* ------------ TUNER_ALPS_TSBB5_PAL_I - Alps PAL_I ------------ */
-
-static struct tuner_range tuner_alps_tsb_5_pal_ranges[] = {
-	{ 16 * 133.25 /*MHz*/, 0x8e, 0x01, },
-	{ 16 * 351.25 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 999.99        , 0x8e, 0x08, },
-};
-
-static struct tuner_params tuner_alps_tsbb5_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_alps_tsb_5_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_ALPS_TSBE5_PAL - Alps PAL ------------ */
-
-static struct tuner_params tuner_alps_tsbe5_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_alps_tsb_5_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_ALPS_TSBC5_PAL - Alps PAL ------------ */
-
-static struct tuner_params tuner_alps_tsbc5_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_alps_tsb_5_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_TEMIC_4006FH5_PAL - TEMIC PAL ------------ */
-
-static struct tuner_range tuner_lg_pal_ranges[] = {
-	{ 16 * 170.00 /*MHz*/, 0x8e, 0xa0, },
-	{ 16 * 450.00 /*MHz*/, 0x8e, 0x90, },
-	{ 16 * 999.99        , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_temic_4006fh5_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_lg_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_ALPS_TSHC6_NTSC - Alps NTSC ------------ */
-
-static struct tuner_range tuner_alps_tshc6_ntsc_ranges[] = {
-	{ 16 * 137.25 /*MHz*/, 0x8e, 0x14, },
-	{ 16 * 385.25 /*MHz*/, 0x8e, 0x12, },
-	{ 16 * 999.99        , 0x8e, 0x11, },
-};
-
-static struct tuner_params tuner_alps_tshc6_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_alps_tshc6_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_alps_tshc6_ntsc_ranges),
-	},
-};
-
-/* ------------ TUNER_TEMIC_PAL_DK - TEMIC PAL ------------ */
-
-static struct tuner_range tuner_temic_pal_dk_ranges[] = {
-	{ 16 * 168.25 /*MHz*/, 0x8e, 0xa0, },
-	{ 16 * 456.25 /*MHz*/, 0x8e, 0x90, },
-	{ 16 * 999.99        , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_temic_pal_dk_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_temic_pal_dk_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_pal_dk_ranges),
-	},
-};
-
-/* ------------ TUNER_PHILIPS_NTSC_M - Philips NTSC ------------ */
-
-static struct tuner_range tuner_philips_ntsc_m_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0x8e, 0xa0, },
-	{ 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
-	{ 16 * 999.99        , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_philips_ntsc_m_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_philips_ntsc_m_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_ntsc_m_ranges),
-	},
-};
-
-/* ------------ TUNER_TEMIC_4066FY5_PAL_I - TEMIC PAL_I ------------ */
-
-static struct tuner_range tuner_temic_40x6f_5_pal_ranges[] = {
-	{ 16 * 169.00 /*MHz*/, 0x8e, 0xa0, },
-	{ 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
-	{ 16 * 999.99        , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_temic_4066fy5_pal_i_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_temic_40x6f_5_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_TEMIC_4006FN5_MULTI_PAL - TEMIC PAL ------------ */
-
-static struct tuner_params tuner_temic_4006fn5_multi_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_temic_40x6f_5_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
-	},
-};
-
-/* 20-29 */
-/* ------------ TUNER_TEMIC_4009FR5_PAL - TEMIC PAL ------------ */
-
-static struct tuner_range tuner_temic_4009f_5_pal_ranges[] = {
-	{ 16 * 141.00 /*MHz*/, 0x8e, 0xa0, },
-	{ 16 * 464.00 /*MHz*/, 0x8e, 0x90, },
-	{ 16 * 999.99        , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_temic_4009f_5_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_temic_4009f_5_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_TEMIC_4039FR5_NTSC - TEMIC NTSC ------------ */
-
-static struct tuner_range tuner_temic_4x3x_f_5_ntsc_ranges[] = {
-	{ 16 * 158.00 /*MHz*/, 0x8e, 0xa0, },
-	{ 16 * 453.00 /*MHz*/, 0x8e, 0x90, },
-	{ 16 * 999.99        , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_temic_4039fr5_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_temic_4x3x_f_5_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges),
-	},
-};
-
-/* ------------ TUNER_TEMIC_4046FM5 - TEMIC PAL ------------ */
-
-static struct tuner_params tuner_temic_4046fm5_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_temic_40x6f_5_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_PHILIPS_PAL_DK - Philips PAL ------------ */
-
-static struct tuner_params tuner_philips_pal_dk_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_lg_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_PHILIPS_FQ1216ME - Philips PAL ------------ */
-
-static struct tuner_params tuner_philips_fq1216me_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_lg_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-		.has_tda9887 = 1,
-		.port1_active = 1,
-		.port2_active = 1,
-		.port2_invert_for_secam_lc = 1,
-	},
-};
-
-/* ------------ TUNER_LG_PAL_I_FM - LGINNOTEK PAL_I ------------ */
-
-static struct tuner_params tuner_lg_pal_i_fm_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_lg_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_LG_PAL_I - LGINNOTEK PAL_I ------------ */
-
-static struct tuner_params tuner_lg_pal_i_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_lg_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_LG_NTSC_FM - LGINNOTEK NTSC ------------ */
-
-static struct tuner_range tuner_lg_ntsc_fm_ranges[] = {
-	{ 16 * 210.00 /*MHz*/, 0x8e, 0xa0, },
-	{ 16 * 497.00 /*MHz*/, 0x8e, 0x90, },
-	{ 16 * 999.99        , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_lg_ntsc_fm_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_lg_ntsc_fm_ranges,
-		.count  = ARRAY_SIZE(tuner_lg_ntsc_fm_ranges),
-	},
-};
-
-/* ------------ TUNER_LG_PAL_FM - LGINNOTEK PAL ------------ */
-
-static struct tuner_params tuner_lg_pal_fm_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_lg_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_LG_PAL - LGINNOTEK PAL ------------ */
-
-static struct tuner_params tuner_lg_pal_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_lg_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-	},
-};
-
-/* 30-39 */
-/* ------------ TUNER_TEMIC_4009FN5_MULTI_PAL_FM - TEMIC PAL ------------ */
-
-static struct tuner_params tuner_temic_4009_fn5_multi_pal_fm_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_temic_4009f_5_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_SHARP_2U5JF5540_NTSC - SHARP NTSC ------------ */
-
-static struct tuner_range tuner_sharp_2u5jf5540_ntsc_ranges[] = {
-	{ 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
-	{ 16 * 317.25 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 999.99        , 0x8e, 0x08, },
-};
-
-static struct tuner_params tuner_sharp_2u5jf5540_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_sharp_2u5jf5540_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_sharp_2u5jf5540_ntsc_ranges),
-	},
-};
-
-/* ------------ TUNER_Samsung_PAL_TCPM9091PD27 - Samsung PAL ------------ */
-
-static struct tuner_range tuner_samsung_pal_tcpm9091pd27_ranges[] = {
-	{ 16 * 169 /*MHz*/, 0x8e, 0xa0, },
-	{ 16 * 464 /*MHz*/, 0x8e, 0x90, },
-	{ 16 * 999.99     , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_samsung_pal_tcpm9091pd27_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_samsung_pal_tcpm9091pd27_ranges,
-		.count  = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_ranges),
-	},
-};
-
-/* ------------ TUNER_TEMIC_4106FH5 - TEMIC PAL ------------ */
-
-static struct tuner_params tuner_temic_4106fh5_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_temic_4009f_5_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_TEMIC_4012FY5 - TEMIC PAL ------------ */
-
-static struct tuner_params tuner_temic_4012fy5_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_temic_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_TEMIC_4136FY5 - TEMIC NTSC ------------ */
-
-static struct tuner_params tuner_temic_4136_fy5_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_temic_4x3x_f_5_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges),
-	},
-};
-
-/* ------------ TUNER_LG_PAL_NEW_TAPC - LGINNOTEK PAL ------------ */
-
-static struct tuner_range tuner_lg_new_tapc_ranges[] = {
-	{ 16 * 170.00 /*MHz*/, 0x8e, 0x01, },
-	{ 16 * 450.00 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 999.99        , 0x8e, 0x08, },
-};
-
-static struct tuner_params tuner_lg_pal_new_tapc_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_lg_new_tapc_ranges,
-		.count  = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
-	},
-};
-
-/* ------------ TUNER_PHILIPS_FM1216ME_MK3 - Philips PAL ------------ */
-
-static struct tuner_range tuner_fm1216me_mk3_pal_ranges[] = {
-	{ 16 * 158.00 /*MHz*/, 0x8e, 0x01, },
-	{ 16 * 442.00 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 999.99        , 0x8e, 0x04, },
-};
-
-static struct tuner_params tuner_fm1216me_mk3_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_fm1216me_mk3_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges),
-		.cb_first_if_lower_freq = 1,
-		.has_tda9887 = 1,
-		.port1_active = 1,
-		.port2_active = 1,
-		.port2_invert_for_secam_lc = 1,
-		.port1_fm_high_sensitivity = 1,
-		.default_top_mid = -2,
-		.default_top_secam_mid = -2,
-		.default_top_secam_high = -2,
-	},
-};
-
-/* ------------ TUNER_PHILIPS_FM1216MK5 - Philips PAL ------------ */
-
-static struct tuner_range tuner_fm1216mk5_pal_ranges[] = {
-	{ 16 * 158.00 /*MHz*/, 0xce, 0x01, },
-	{ 16 * 441.00 /*MHz*/, 0xce, 0x02, },
-	{ 16 * 864.00        , 0xce, 0x04, },
-};
-
-static struct tuner_params tuner_fm1216mk5_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_fm1216mk5_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_fm1216mk5_pal_ranges),
-		.cb_first_if_lower_freq = 1,
-		.has_tda9887 = 1,
-		.port1_active = 1,
-		.port2_active = 1,
-		.port2_invert_for_secam_lc = 1,
-		.port1_fm_high_sensitivity = 1,
-		.default_top_mid = -2,
-		.default_top_secam_mid = -2,
-		.default_top_secam_high = -2,
-	},
-};
-
-/* ------------ TUNER_LG_NTSC_NEW_TAPC - LGINNOTEK NTSC ------------ */
-
-static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_lg_new_tapc_ranges,
-		.count  = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
-	},
-};
-
-/* 40-49 */
-/* ------------ TUNER_HITACHI_NTSC - HITACHI NTSC ------------ */
-
-static struct tuner_params tuner_hitachi_ntsc_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_lg_new_tapc_ranges,
-		.count  = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
-	},
-};
-
-/* ------------ TUNER_PHILIPS_PAL_MK - Philips PAL ------------ */
-
-static struct tuner_range tuner_philips_pal_mk_pal_ranges[] = {
-	{ 16 * 140.25 /*MHz*/, 0x8e, 0x01, },
-	{ 16 * 463.25 /*MHz*/, 0x8e, 0xc2, },
-	{ 16 * 999.99        , 0x8e, 0xcf, },
-};
-
-static struct tuner_params tuner_philips_pal_mk_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_philips_pal_mk_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_pal_mk_pal_ranges),
-	},
-};
-
-/* ---- TUNER_PHILIPS_FCV1236D - Philips FCV1236D (ATSC/NTSC) ---- */
-
-static struct tuner_range tuner_philips_fcv1236d_ntsc_ranges[] = {
-	{ 16 * 157.25 /*MHz*/, 0x8e, 0xa2, },
-	{ 16 * 451.25 /*MHz*/, 0x8e, 0x92, },
-	{ 16 * 999.99        , 0x8e, 0x32, },
-};
-
-static struct tuner_range tuner_philips_fcv1236d_atsc_ranges[] = {
-	{ 16 * 159.00 /*MHz*/, 0x8e, 0xa0, },
-	{ 16 * 453.00 /*MHz*/, 0x8e, 0x90, },
-	{ 16 * 999.99        , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_philips_fcv1236d_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_philips_fcv1236d_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_fcv1236d_ntsc_ranges),
-	},
-	{
-		.type   = TUNER_PARAM_TYPE_DIGITAL,
-		.ranges = tuner_philips_fcv1236d_atsc_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_fcv1236d_atsc_ranges),
-		.iffreq = 16 * 44.00,
-	},
-};
-
-/* ------------ TUNER_PHILIPS_FM1236_MK3 - Philips NTSC ------------ */
-
-static struct tuner_range tuner_fm1236_mk3_ntsc_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0x8e, 0x01, },
-	{ 16 * 442.00 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 999.99        , 0x8e, 0x04, },
-};
-
-static struct tuner_params tuner_fm1236_mk3_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_fm1236_mk3_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
-		.cb_first_if_lower_freq = 1,
-		.has_tda9887 = 1,
-		.port1_active = 1,
-		.port2_active = 1,
-		.port1_fm_high_sensitivity = 1,
-	},
-};
-
-/* ------------ TUNER_PHILIPS_4IN1 - Philips NTSC ------------ */
-
-static struct tuner_params tuner_philips_4in1_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_fm1236_mk3_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
-	},
-};
-
-/* ------------ TUNER_MICROTUNE_4049FM5 - Microtune PAL ------------ */
-
-static struct tuner_params tuner_microtune_4049_fm5_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_temic_4009f_5_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
-		.has_tda9887 = 1,
-		.port1_invert_for_secam_lc = 1,
-		.default_pll_gating_18 = 1,
-		.fm_gain_normal=1,
-		.radio_if = 1, /* 33.3 MHz */
-	},
-};
-
-/* ------------ TUNER_PANASONIC_VP27 - Panasonic NTSC ------------ */
-
-static struct tuner_range tuner_panasonic_vp27_ntsc_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0xce, 0x01, },
-	{ 16 * 454.00 /*MHz*/, 0xce, 0x02, },
-	{ 16 * 999.99        , 0xce, 0x08, },
-};
-
-static struct tuner_params tuner_panasonic_vp27_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_panasonic_vp27_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges),
-		.has_tda9887 = 1,
-		.intercarrier_mode = 1,
-		.default_top_low = -3,
-		.default_top_mid = -3,
-		.default_top_high = -3,
-	},
-};
-
-/* ------------ TUNER_TNF_8831BGFF - Philips PAL ------------ */
-
-static struct tuner_range tuner_tnf_8831bgff_pal_ranges[] = {
-	{ 16 * 161.25 /*MHz*/, 0x8e, 0xa0, },
-	{ 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
-	{ 16 * 999.99        , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_tnf_8831bgff_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_tnf_8831bgff_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_tnf_8831bgff_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_MICROTUNE_4042FI5 - Microtune NTSC ------------ */
-
-static struct tuner_range tuner_microtune_4042fi5_ntsc_ranges[] = {
-	{ 16 * 162.00 /*MHz*/, 0x8e, 0xa2, },
-	{ 16 * 457.00 /*MHz*/, 0x8e, 0x94, },
-	{ 16 * 999.99        , 0x8e, 0x31, },
-};
-
-static struct tuner_range tuner_microtune_4042fi5_atsc_ranges[] = {
-	{ 16 * 162.00 /*MHz*/, 0x8e, 0xa1, },
-	{ 16 * 457.00 /*MHz*/, 0x8e, 0x91, },
-	{ 16 * 999.99        , 0x8e, 0x31, },
-};
-
-static struct tuner_params tuner_microtune_4042fi5_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_microtune_4042fi5_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_microtune_4042fi5_ntsc_ranges),
-	},
-	{
-		.type   = TUNER_PARAM_TYPE_DIGITAL,
-		.ranges = tuner_microtune_4042fi5_atsc_ranges,
-		.count  = ARRAY_SIZE(tuner_microtune_4042fi5_atsc_ranges),
-		.iffreq = 16 * 44.00 /*MHz*/,
-	},
-};
-
-/* 50-59 */
-/* ------------ TUNER_TCL_2002N - TCL NTSC ------------ */
-
-static struct tuner_range tuner_tcl_2002n_ntsc_ranges[] = {
-	{ 16 * 172.00 /*MHz*/, 0x8e, 0x01, },
-	{ 16 * 448.00 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 999.99        , 0x8e, 0x08, },
-};
-
-static struct tuner_params tuner_tcl_2002n_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_tcl_2002n_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_tcl_2002n_ntsc_ranges),
-		.cb_first_if_lower_freq = 1,
-	},
-};
-
-/* ------------ TUNER_PHILIPS_FM1256_IH3 - Philips PAL ------------ */
-
-static struct tuner_params tuner_philips_fm1256_ih3_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_fm1236_mk3_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
-		.radio_if = 1, /* 33.3 MHz */
-	},
-};
-
-/* ------------ TUNER_THOMSON_DTT7610 - THOMSON ATSC ------------ */
-
-/* single range used for both ntsc and atsc */
-static struct tuner_range tuner_thomson_dtt7610_ntsc_ranges[] = {
-	{ 16 * 157.25 /*MHz*/, 0x8e, 0x39, },
-	{ 16 * 454.00 /*MHz*/, 0x8e, 0x3a, },
-	{ 16 * 999.99        , 0x8e, 0x3c, },
-};
-
-static struct tuner_params tuner_thomson_dtt7610_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_thomson_dtt7610_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges),
-	},
-	{
-		.type   = TUNER_PARAM_TYPE_DIGITAL,
-		.ranges = tuner_thomson_dtt7610_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges),
-		.iffreq = 16 * 44.00 /*MHz*/,
-	},
-};
-
-/* ------------ TUNER_PHILIPS_FQ1286 - Philips NTSC ------------ */
-
-static struct tuner_range tuner_philips_fq1286_ntsc_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0x8e, 0x41, },
-	{ 16 * 454.00 /*MHz*/, 0x8e, 0x42, },
-	{ 16 * 999.99        , 0x8e, 0x04, },
-};
-
-static struct tuner_params tuner_philips_fq1286_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_philips_fq1286_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_fq1286_ntsc_ranges),
-	},
-};
-
-/* ------------ TUNER_TCL_2002MB - TCL PAL ------------ */
-
-static struct tuner_range tuner_tcl_2002mb_pal_ranges[] = {
-	{ 16 * 170.00 /*MHz*/, 0xce, 0x01, },
-	{ 16 * 450.00 /*MHz*/, 0xce, 0x02, },
-	{ 16 * 999.99        , 0xce, 0x08, },
-};
-
-static struct tuner_params tuner_tcl_2002mb_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_tcl_2002mb_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_tcl_2002mb_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_PHILIPS_FQ1216AME_MK4 - Philips PAL ------------ */
-
-static struct tuner_range tuner_philips_fq12_6a___mk4_pal_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0xce, 0x01, },
-	{ 16 * 442.00 /*MHz*/, 0xce, 0x02, },
-	{ 16 * 999.99        , 0xce, 0x04, },
-};
-
-static struct tuner_params tuner_philips_fq1216ame_mk4_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_philips_fq12_6a___mk4_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_pal_ranges),
-		.has_tda9887 = 1,
-		.port1_active = 1,
-		.port2_invert_for_secam_lc = 1,
-		.default_top_mid = -2,
-		.default_top_secam_low = -2,
-		.default_top_secam_mid = -2,
-		.default_top_secam_high = -2,
-	},
-};
-
-/* ------------ TUNER_PHILIPS_FQ1236A_MK4 - Philips NTSC ------------ */
-
-static struct tuner_params tuner_philips_fq1236a_mk4_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_fm1236_mk3_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
-	},
-};
-
-/* ------------ TUNER_YMEC_TVF_8531MF - Philips NTSC ------------ */
-
-static struct tuner_params tuner_ymec_tvf_8531mf_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_philips_ntsc_m_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_ntsc_m_ranges),
-	},
-};
-
-/* ------------ TUNER_YMEC_TVF_5533MF - Philips NTSC ------------ */
-
-static struct tuner_range tuner_ymec_tvf_5533mf_ntsc_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0x8e, 0x01, },
-	{ 16 * 454.00 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 999.99        , 0x8e, 0x04, },
-};
-
-static struct tuner_params tuner_ymec_tvf_5533mf_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_ymec_tvf_5533mf_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_ymec_tvf_5533mf_ntsc_ranges),
-	},
-};
-
-/* 60-69 */
-/* ------------ TUNER_THOMSON_DTT761X - THOMSON ATSC ------------ */
-/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
-
-static struct tuner_range tuner_thomson_dtt761x_ntsc_ranges[] = {
-	{ 16 * 145.25 /*MHz*/, 0x8e, 0x39, },
-	{ 16 * 415.25 /*MHz*/, 0x8e, 0x3a, },
-	{ 16 * 999.99        , 0x8e, 0x3c, },
-};
-
-static struct tuner_range tuner_thomson_dtt761x_atsc_ranges[] = {
-	{ 16 * 147.00 /*MHz*/, 0x8e, 0x39, },
-	{ 16 * 417.00 /*MHz*/, 0x8e, 0x3a, },
-	{ 16 * 999.99        , 0x8e, 0x3c, },
-};
-
-static struct tuner_params tuner_thomson_dtt761x_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_thomson_dtt761x_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges),
-		.has_tda9887 = 1,
-		.fm_gain_normal = 1,
-		.radio_if = 2, /* 41.3 MHz */
-	},
-	{
-		.type   = TUNER_PARAM_TYPE_DIGITAL,
-		.ranges = tuner_thomson_dtt761x_atsc_ranges,
-		.count  = ARRAY_SIZE(tuner_thomson_dtt761x_atsc_ranges),
-		.iffreq = 16 * 44.00, /*MHz*/
-	},
-};
-
-/* ------------ TUNER_TENA_9533_DI - Philips PAL ------------ */
-
-static struct tuner_range tuner_tena_9533_di_pal_ranges[] = {
-	{ 16 * 160.25 /*MHz*/, 0x8e, 0x01, },
-	{ 16 * 464.25 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 999.99        , 0x8e, 0x04, },
-};
-
-static struct tuner_params tuner_tena_9533_di_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_tena_9533_di_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_TENA_TNF_5337 - Tena tnf5337MFD STD M/N ------------ */
-
-static struct tuner_range tuner_tena_tnf_5337_ntsc_ranges[] = {
-	{ 16 * 166.25 /*MHz*/, 0x86, 0x01, },
-	{ 16 * 466.25 /*MHz*/, 0x86, 0x02, },
-	{ 16 * 999.99        , 0x86, 0x08, },
-};
-
-static struct tuner_params tuner_tena_tnf_5337_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_tena_tnf_5337_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_tena_tnf_5337_ntsc_ranges),
-	},
-};
-
-/* ------------ TUNER_PHILIPS_FMD1216ME(X)_MK3 - Philips PAL ------------ */
-
-static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0x86, 0x51, },
-	{ 16 * 442.00 /*MHz*/, 0x86, 0x52, },
-	{ 16 * 999.99        , 0x86, 0x54, },
-};
-
-static struct tuner_range tuner_philips_fmd1216me_mk3_dvb_ranges[] = {
-	{ 16 * 143.87 /*MHz*/, 0xbc, 0x41 },
-	{ 16 * 158.87 /*MHz*/, 0xf4, 0x41 },
-	{ 16 * 329.87 /*MHz*/, 0xbc, 0x42 },
-	{ 16 * 441.87 /*MHz*/, 0xf4, 0x42 },
-	{ 16 * 625.87 /*MHz*/, 0xbc, 0x44 },
-	{ 16 * 803.87 /*MHz*/, 0xf4, 0x44 },
-	{ 16 * 999.99        , 0xfc, 0x44 },
-};
-
-static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_philips_fmd1216me_mk3_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges),
-		.has_tda9887 = 1,
-		.port1_active = 1,
-		.port2_active = 1,
-		.port2_fm_high_sensitivity = 1,
-		.port2_invert_for_secam_lc = 1,
-		.port1_set_for_fm_mono = 1,
-	},
-	{
-		.type   = TUNER_PARAM_TYPE_DIGITAL,
-		.ranges = tuner_philips_fmd1216me_mk3_dvb_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges),
-		.iffreq = 16 * 36.125, /*MHz*/
-	},
-};
-
-static struct tuner_params tuner_philips_fmd1216mex_mk3_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_philips_fmd1216me_mk3_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges),
-		.has_tda9887 = 1,
-		.port1_active = 1,
-		.port2_active = 1,
-		.port2_fm_high_sensitivity = 1,
-		.port2_invert_for_secam_lc = 1,
-		.port1_set_for_fm_mono = 1,
-		.radio_if = 1,
-		.fm_gain_normal = 1,
-	},
-	{
-		.type   = TUNER_PARAM_TYPE_DIGITAL,
-		.ranges = tuner_philips_fmd1216me_mk3_dvb_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges),
-		.iffreq = 16 * 36.125, /*MHz*/
-	},
-};
-
-/* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */
-
-static struct tuner_range tuner_tua6034_ntsc_ranges[] = {
-	{ 16 * 165.00 /*MHz*/, 0x8e, 0x01 },
-	{ 16 * 450.00 /*MHz*/, 0x8e, 0x02 },
-	{ 16 * 999.99        , 0x8e, 0x04 },
-};
-
-static struct tuner_range tuner_tua6034_atsc_ranges[] = {
-	{ 16 * 165.00 /*MHz*/, 0xce, 0x01 },
-	{ 16 * 450.00 /*MHz*/, 0xce, 0x02 },
-	{ 16 * 999.99        , 0xce, 0x04 },
-};
-
-static struct tuner_params tuner_lg_tdvs_h06xf_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_tua6034_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_tua6034_ntsc_ranges),
-	},
-	{
-		.type   = TUNER_PARAM_TYPE_DIGITAL,
-		.ranges = tuner_tua6034_atsc_ranges,
-		.count  = ARRAY_SIZE(tuner_tua6034_atsc_ranges),
-		.iffreq = 16 * 44.00,
-	},
-};
-
-/* ------------ TUNER_YMEC_TVF66T5_B_DFF - Philips PAL ------------ */
-
-static struct tuner_range tuner_ymec_tvf66t5_b_dff_pal_ranges[] = {
-	{ 16 * 160.25 /*MHz*/, 0x8e, 0x01, },
-	{ 16 * 464.25 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 999.99        , 0x8e, 0x08, },
-};
-
-static struct tuner_params tuner_ymec_tvf66t5_b_dff_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_ymec_tvf66t5_b_dff_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_pal_ranges),
-	},
-};
-
-/* ------------ TUNER_LG_NTSC_TALN_MINI - LGINNOTEK NTSC ------------ */
-
-static struct tuner_range tuner_lg_taln_ntsc_ranges[] = {
-	{ 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
-	{ 16 * 373.25 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 999.99        , 0x8e, 0x08, },
-};
-
-static struct tuner_range tuner_lg_taln_pal_secam_ranges[] = {
-	{ 16 * 150.00 /*MHz*/, 0x8e, 0x01, },
-	{ 16 * 425.00 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 999.99        , 0x8e, 0x08, },
-};
-
-static struct tuner_params tuner_lg_taln_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_lg_taln_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_lg_taln_ntsc_ranges),
-	},{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_lg_taln_pal_secam_ranges,
-		.count  = ARRAY_SIZE(tuner_lg_taln_pal_secam_ranges),
-	},
-};
-
-/* ------------ TUNER_PHILIPS_TD1316 - Philips PAL ------------ */
-
-static struct tuner_range tuner_philips_td1316_pal_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0xc8, 0xa1, },
-	{ 16 * 442.00 /*MHz*/, 0xc8, 0xa2, },
-	{ 16 * 999.99        , 0xc8, 0xa4, },
-};
-
-static struct tuner_range tuner_philips_td1316_dvb_ranges[] = {
-	{ 16 *  93.834 /*MHz*/, 0xca, 0x60, },
-	{ 16 * 123.834 /*MHz*/, 0xca, 0xa0, },
-	{ 16 * 163.834 /*MHz*/, 0xca, 0xc0, },
-	{ 16 * 253.834 /*MHz*/, 0xca, 0x60, },
-	{ 16 * 383.834 /*MHz*/, 0xca, 0xa0, },
-	{ 16 * 443.834 /*MHz*/, 0xca, 0xc0, },
-	{ 16 * 583.834 /*MHz*/, 0xca, 0x60, },
-	{ 16 * 793.834 /*MHz*/, 0xca, 0xa0, },
-	{ 16 * 999.999        , 0xca, 0xe0, },
-};
-
-static struct tuner_params tuner_philips_td1316_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_philips_td1316_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_td1316_pal_ranges),
-	},
-	{
-		.type   = TUNER_PARAM_TYPE_DIGITAL,
-		.ranges = tuner_philips_td1316_dvb_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_td1316_dvb_ranges),
-		.iffreq = 16 * 36.166667 /*MHz*/,
-	},
-};
-
-/* ------------ TUNER_PHILIPS_TUV1236D - Philips ATSC ------------ */
-
-static struct tuner_range tuner_tuv1236d_ntsc_ranges[] = {
-	{ 16 * 157.25 /*MHz*/, 0xce, 0x01, },
-	{ 16 * 454.00 /*MHz*/, 0xce, 0x02, },
-	{ 16 * 999.99        , 0xce, 0x04, },
-};
-
-static struct tuner_range tuner_tuv1236d_atsc_ranges[] = {
-	{ 16 * 157.25 /*MHz*/, 0xc6, 0x41, },
-	{ 16 * 454.00 /*MHz*/, 0xc6, 0x42, },
-	{ 16 * 999.99        , 0xc6, 0x44, },
-};
-
-static struct tuner_params tuner_tuv1236d_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_tuv1236d_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_tuv1236d_ntsc_ranges),
-	},
-	{
-		.type   = TUNER_PARAM_TYPE_DIGITAL,
-		.ranges = tuner_tuv1236d_atsc_ranges,
-		.count  = ARRAY_SIZE(tuner_tuv1236d_atsc_ranges),
-		.iffreq = 16 * 44.00,
-	},
-};
-
-/* ------------ TUNER_TNF_xxx5  - Texas Instruments--------- */
-/* This is known to work with Tenna TVF58t5-MFF and TVF5835 MFF
- *	but it is expected to work also with other Tenna/Ymec
- *	models based on TI SN 761677 chip on both PAL and NTSC
- */
-
-static struct tuner_range tuner_tnf_5335_d_if_pal_ranges[] = {
-	{ 16 * 168.25 /*MHz*/, 0x8e, 0x01, },
-	{ 16 * 471.25 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 999.99        , 0x8e, 0x08, },
-};
-
-static struct tuner_range tuner_tnf_5335mf_ntsc_ranges[] = {
-	{ 16 * 169.25 /*MHz*/, 0x8e, 0x01, },
-	{ 16 * 469.25 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 999.99        , 0x8e, 0x08, },
-};
-
-static struct tuner_params tuner_tnf_5335mf_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_tnf_5335mf_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_tnf_5335mf_ntsc_ranges),
-	},
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_tnf_5335_d_if_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_tnf_5335_d_if_pal_ranges),
-	},
-};
-
-/* 70-79 */
-/* ------------ TUNER_SAMSUNG_TCPN_2121P30A - Samsung NTSC ------------ */
-
-/* '+ 4' turns on the Low Noise Amplifier */
-static struct tuner_range tuner_samsung_tcpn_2121p30a_ntsc_ranges[] = {
-	{ 16 * 130.00 /*MHz*/, 0xce, 0x01 + 4, },
-	{ 16 * 364.50 /*MHz*/, 0xce, 0x02 + 4, },
-	{ 16 * 999.99        , 0xce, 0x08 + 4, },
-};
-
-static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges),
-	},
-};
-
-/* ------------ TUNER_THOMSON_FE6600 - DViCO Hybrid PAL ------------ */
-
-static struct tuner_range tuner_thomson_fe6600_pal_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0xfe, 0x11, },
-	{ 16 * 442.00 /*MHz*/, 0xf6, 0x12, },
-	{ 16 * 999.99        , 0xf6, 0x18, },
-};
-
-static struct tuner_range tuner_thomson_fe6600_dvb_ranges[] = {
-	{ 16 * 250.00 /*MHz*/, 0xb4, 0x12, },
-	{ 16 * 455.00 /*MHz*/, 0xfe, 0x11, },
-	{ 16 * 775.50 /*MHz*/, 0xbc, 0x18, },
-	{ 16 * 999.99        , 0xf4, 0x18, },
-};
-
-static struct tuner_params tuner_thomson_fe6600_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_thomson_fe6600_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_thomson_fe6600_pal_ranges),
-	},
-	{
-		.type   = TUNER_PARAM_TYPE_DIGITAL,
-		.ranges = tuner_thomson_fe6600_dvb_ranges,
-		.count  = ARRAY_SIZE(tuner_thomson_fe6600_dvb_ranges),
-		.iffreq = 16 * 36.125 /*MHz*/,
-	},
-};
-
-/* ------------ TUNER_SAMSUNG_TCPG_6121P30A - Samsung PAL ------------ */
-
-/* '+ 4' turns on the Low Noise Amplifier */
-static struct tuner_range tuner_samsung_tcpg_6121p30a_pal_ranges[] = {
-	{ 16 * 146.25 /*MHz*/, 0xce, 0x01 + 4, },
-	{ 16 * 428.50 /*MHz*/, 0xce, 0x02 + 4, },
-	{ 16 * 999.99        , 0xce, 0x08 + 4, },
-};
-
-static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_samsung_tcpg_6121p30a_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_pal_ranges),
-		.has_tda9887 = 1,
-		.port1_active = 1,
-		.port2_active = 1,
-		.port2_invert_for_secam_lc = 1,
-	},
-};
-
-/* ------------ TUNER_TCL_MF02GIP-5N-E - TCL MF02GIP-5N ------------ */
-
-static struct tuner_range tuner_tcl_mf02gip_5n_ntsc_ranges[] = {
-	{ 16 * 172.00 /*MHz*/, 0x8e, 0x01, },
-	{ 16 * 448.00 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 999.99        , 0x8e, 0x04, },
-};
-
-static struct tuner_params tuner_tcl_mf02gip_5n_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_tcl_mf02gip_5n_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_tcl_mf02gip_5n_ntsc_ranges),
-		.cb_first_if_lower_freq = 1,
-	},
-};
-
-/* 80-89 */
-/* --------- TUNER_PHILIPS_FQ1216LME_MK3 -- active loopthrough, no FM ------- */
-
-static struct tuner_params tuner_fq1216lme_mk3_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_fm1216me_mk3_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges),
-		.cb_first_if_lower_freq = 1, /* not specified, but safe to do */
-		.has_tda9887 = 1, /* TDA9886 */
-		.port1_active = 1,
-		.port2_active = 1,
-		.port2_invert_for_secam_lc = 1,
-		.default_top_low = 4,
-		.default_top_mid = 4,
-		.default_top_high = 4,
-		.default_top_secam_low = 4,
-		.default_top_secam_mid = 4,
-		.default_top_secam_high = 4,
-	},
-};
-
-/* ----- TUNER_PARTSNIC_PTI_5NF05 - Partsnic (Daewoo) PTI-5NF05 NTSC ----- */
-
-static struct tuner_range tuner_partsnic_pti_5nf05_ranges[] = {
-	/* The datasheet specified channel ranges and the bandswitch byte */
-	/* The control byte value of 0x8e is just a guess */
-	{ 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, /* Channels    2 -    B */
-	{ 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, /* Channels    C - W+11 */
-	{ 16 * 999.99        , 0x8e, 0x08, }, /* Channels W+12 -   69 */
-};
-
-static struct tuner_params tuner_partsnic_pti_5nf05_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_partsnic_pti_5nf05_ranges,
-		.count  = ARRAY_SIZE(tuner_partsnic_pti_5nf05_ranges),
-		.cb_first_if_lower_freq = 1, /* not specified but safe to do */
-	},
-};
-
-/* --------- TUNER_PHILIPS_CU1216L - DVB-C NIM ------------------------- */
-
-static struct tuner_range tuner_cu1216l_ranges[] = {
-	{ 16 * 160.25 /*MHz*/, 0xce, 0x01 },
-	{ 16 * 444.25 /*MHz*/, 0xce, 0x02 },
-	{ 16 * 999.99        , 0xce, 0x04 },
-};
-
-static struct tuner_params tuner_philips_cu1216l_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_DIGITAL,
-		.ranges = tuner_cu1216l_ranges,
-		.count  = ARRAY_SIZE(tuner_cu1216l_ranges),
-		.iffreq = 16 * 36.125, /*MHz*/
-	},
-};
-
-/* ---------------------- TUNER_SONY_BTF_PXN01Z ------------------------ */
-
-static struct tuner_range tuner_sony_btf_pxn01z_ranges[] = {
-	{ 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
-	{ 16 * 367.25 /*MHz*/, 0x8e, 0x02, },
-	{ 16 * 999.99        , 0x8e, 0x04, },
-};
-
-static struct tuner_params tuner_sony_btf_pxn01z_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_sony_btf_pxn01z_ranges,
-		.count  = ARRAY_SIZE(tuner_sony_btf_pxn01z_ranges),
-	},
-};
-
-/* ------------ TUNER_PHILIPS_FQ1236_MK5 - Philips NTSC ------------ */
-
-static struct tuner_params tuner_philips_fq1236_mk5_params[] = {
-	{
-		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_fm1236_mk3_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
-		.has_tda9887 = 1, /* TDA9885, no FM radio */
-	},
-};
-
-/* --------------------------------------------------------------------- */
-
-struct tunertype tuners[] = {
-	/* 0-9 */
-	[TUNER_TEMIC_PAL] = { /* TEMIC PAL */
-		.name   = "Temic PAL (4002 FH5)",
-		.params = tuner_temic_pal_params,
-		.count  = ARRAY_SIZE(tuner_temic_pal_params),
-	},
-	[TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */
-		.name   = "Philips PAL_I (FI1246 and compatibles)",
-		.params = tuner_philips_pal_i_params,
-		.count  = ARRAY_SIZE(tuner_philips_pal_i_params),
-	},
-	[TUNER_PHILIPS_NTSC] = { /* Philips NTSC */
-		.name   = "Philips NTSC (FI1236,FM1236 and compatibles)",
-		.params = tuner_philips_ntsc_params,
-		.count  = ARRAY_SIZE(tuner_philips_ntsc_params),
-	},
-	[TUNER_PHILIPS_SECAM] = { /* Philips SECAM */
-		.name   = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)",
-		.params = tuner_philips_secam_params,
-		.count  = ARRAY_SIZE(tuner_philips_secam_params),
-	},
-	[TUNER_ABSENT] = { /* Tuner Absent */
-		.name   = "NoTuner",
-	},
-	[TUNER_PHILIPS_PAL] = { /* Philips PAL */
-		.name   = "Philips PAL_BG (FI1216 and compatibles)",
-		.params = tuner_philips_pal_params,
-		.count  = ARRAY_SIZE(tuner_philips_pal_params),
-	},
-	[TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */
-		.name   = "Temic NTSC (4032 FY5)",
-		.params = tuner_temic_ntsc_params,
-		.count  = ARRAY_SIZE(tuner_temic_ntsc_params),
-	},
-	[TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */
-		.name   = "Temic PAL_I (4062 FY5)",
-		.params = tuner_temic_pal_i_params,
-		.count  = ARRAY_SIZE(tuner_temic_pal_i_params),
-	},
-	[TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */
-		.name   = "Temic NTSC (4036 FY5)",
-		.params = tuner_temic_4036fy5_ntsc_params,
-		.count  = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_params),
-	},
-	[TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */
-		.name   = "Alps HSBH1",
-		.params = tuner_alps_tsbh1_ntsc_params,
-		.count  = ARRAY_SIZE(tuner_alps_tsbh1_ntsc_params),
-	},
-
-	/* 10-19 */
-	[TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */
-		.name   = "Alps TSBE1",
-		.params = tuner_alps_tsb_1_params,
-		.count  = ARRAY_SIZE(tuner_alps_tsb_1_params),
-	},
-	[TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */
-		.name   = "Alps TSBB5",
-		.params = tuner_alps_tsbb5_params,
-		.count  = ARRAY_SIZE(tuner_alps_tsbb5_params),
-	},
-	[TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */
-		.name   = "Alps TSBE5",
-		.params = tuner_alps_tsbe5_params,
-		.count  = ARRAY_SIZE(tuner_alps_tsbe5_params),
-	},
-	[TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */
-		.name   = "Alps TSBC5",
-		.params = tuner_alps_tsbc5_params,
-		.count  = ARRAY_SIZE(tuner_alps_tsbc5_params),
-	},
-	[TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */
-		.name   = "Temic PAL_BG (4006FH5)",
-		.params = tuner_temic_4006fh5_params,
-		.count  = ARRAY_SIZE(tuner_temic_4006fh5_params),
-	},
-	[TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */
-		.name   = "Alps TSCH6",
-		.params = tuner_alps_tshc6_params,
-		.count  = ARRAY_SIZE(tuner_alps_tshc6_params),
-	},
-	[TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */
-		.name   = "Temic PAL_DK (4016 FY5)",
-		.params = tuner_temic_pal_dk_params,
-		.count  = ARRAY_SIZE(tuner_temic_pal_dk_params),
-	},
-	[TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */
-		.name   = "Philips NTSC_M (MK2)",
-		.params = tuner_philips_ntsc_m_params,
-		.count  = ARRAY_SIZE(tuner_philips_ntsc_m_params),
-	},
-	[TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */
-		.name   = "Temic PAL_I (4066 FY5)",
-		.params = tuner_temic_4066fy5_pal_i_params,
-		.count  = ARRAY_SIZE(tuner_temic_4066fy5_pal_i_params),
-	},
-	[TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */
-		.name   = "Temic PAL* auto (4006 FN5)",
-		.params = tuner_temic_4006fn5_multi_params,
-		.count  = ARRAY_SIZE(tuner_temic_4006fn5_multi_params),
-	},
-
-	/* 20-29 */
-	[TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */
-		.name   = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)",
-		.params = tuner_temic_4009f_5_params,
-		.count  = ARRAY_SIZE(tuner_temic_4009f_5_params),
-	},
-	[TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */
-		.name   = "Temic NTSC (4039 FR5)",
-		.params = tuner_temic_4039fr5_params,
-		.count  = ARRAY_SIZE(tuner_temic_4039fr5_params),
-	},
-	[TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */
-		.name   = "Temic PAL/SECAM multi (4046 FM5)",
-		.params = tuner_temic_4046fm5_params,
-		.count  = ARRAY_SIZE(tuner_temic_4046fm5_params),
-	},
-	[TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */
-		.name   = "Philips PAL_DK (FI1256 and compatibles)",
-		.params = tuner_philips_pal_dk_params,
-		.count  = ARRAY_SIZE(tuner_philips_pal_dk_params),
-	},
-	[TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */
-		.name   = "Philips PAL/SECAM multi (FQ1216ME)",
-		.params = tuner_philips_fq1216me_params,
-		.count  = ARRAY_SIZE(tuner_philips_fq1216me_params),
-	},
-	[TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */
-		.name   = "LG PAL_I+FM (TAPC-I001D)",
-		.params = tuner_lg_pal_i_fm_params,
-		.count  = ARRAY_SIZE(tuner_lg_pal_i_fm_params),
-	},
-	[TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */
-		.name   = "LG PAL_I (TAPC-I701D)",
-		.params = tuner_lg_pal_i_params,
-		.count  = ARRAY_SIZE(tuner_lg_pal_i_params),
-	},
-	[TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */
-		.name   = "LG NTSC+FM (TPI8NSR01F)",
-		.params = tuner_lg_ntsc_fm_params,
-		.count  = ARRAY_SIZE(tuner_lg_ntsc_fm_params),
-	},
-	[TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */
-		.name   = "LG PAL_BG+FM (TPI8PSB01D)",
-		.params = tuner_lg_pal_fm_params,
-		.count  = ARRAY_SIZE(tuner_lg_pal_fm_params),
-	},
-	[TUNER_LG_PAL] = { /* LGINNOTEK PAL */
-		.name   = "LG PAL_BG (TPI8PSB11D)",
-		.params = tuner_lg_pal_params,
-		.count  = ARRAY_SIZE(tuner_lg_pal_params),
-	},
-
-	/* 30-39 */
-	[TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */
-		.name   = "Temic PAL* auto + FM (4009 FN5)",
-		.params = tuner_temic_4009_fn5_multi_pal_fm_params,
-		.count  = ARRAY_SIZE(tuner_temic_4009_fn5_multi_pal_fm_params),
-	},
-	[TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */
-		.name   = "SHARP NTSC_JP (2U5JF5540)",
-		.params = tuner_sharp_2u5jf5540_params,
-		.count  = ARRAY_SIZE(tuner_sharp_2u5jf5540_params),
-	},
-	[TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */
-		.name   = "Samsung PAL TCPM9091PD27",
-		.params = tuner_samsung_pal_tcpm9091pd27_params,
-		.count  = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_params),
-	},
-	[TUNER_MT2032] = { /* Microtune PAL|NTSC */
-		.name   = "MT20xx universal",
-		/* see mt20xx.c for details */ },
-	[TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */
-		.name   = "Temic PAL_BG (4106 FH5)",
-		.params = tuner_temic_4106fh5_params,
-		.count  = ARRAY_SIZE(tuner_temic_4106fh5_params),
-	},
-	[TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */
-		.name   = "Temic PAL_DK/SECAM_L (4012 FY5)",
-		.params = tuner_temic_4012fy5_params,
-		.count  = ARRAY_SIZE(tuner_temic_4012fy5_params),
-	},
-	[TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */
-		.name   = "Temic NTSC (4136 FY5)",
-		.params = tuner_temic_4136_fy5_params,
-		.count  = ARRAY_SIZE(tuner_temic_4136_fy5_params),
-	},
-	[TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */
-		.name   = "LG PAL (newer TAPC series)",
-		.params = tuner_lg_pal_new_tapc_params,
-		.count  = ARRAY_SIZE(tuner_lg_pal_new_tapc_params),
-	},
-	[TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */
-		.name   = "Philips PAL/SECAM multi (FM1216ME MK3)",
-		.params = tuner_fm1216me_mk3_params,
-		.count  = ARRAY_SIZE(tuner_fm1216me_mk3_params),
-	},
-	[TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */
-		.name   = "LG NTSC (newer TAPC series)",
-		.params = tuner_lg_ntsc_new_tapc_params,
-		.count  = ARRAY_SIZE(tuner_lg_ntsc_new_tapc_params),
-	},
-
-	/* 40-49 */
-	[TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */
-		.name   = "HITACHI V7-J180AT",
-		.params = tuner_hitachi_ntsc_params,
-		.count  = ARRAY_SIZE(tuner_hitachi_ntsc_params),
-	},
-	[TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */
-		.name   = "Philips PAL_MK (FI1216 MK)",
-		.params = tuner_philips_pal_mk_params,
-		.count  = ARRAY_SIZE(tuner_philips_pal_mk_params),
-	},
-	[TUNER_PHILIPS_FCV1236D] = { /* Philips ATSC */
-		.name   = "Philips FCV1236D ATSC/NTSC dual in",
-		.params = tuner_philips_fcv1236d_params,
-		.count  = ARRAY_SIZE(tuner_philips_fcv1236d_params),
-		.min = 16 *  53.00,
-		.max = 16 * 803.00,
-		.stepsize = 62500,
-	},
-	[TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */
-		.name   = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)",
-		.params = tuner_fm1236_mk3_params,
-		.count  = ARRAY_SIZE(tuner_fm1236_mk3_params),
-	},
-	[TUNER_PHILIPS_4IN1] = { /* Philips NTSC */
-		.name   = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)",
-		.params = tuner_philips_4in1_params,
-		.count  = ARRAY_SIZE(tuner_philips_4in1_params),
-	},
-	[TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */
-		.name   = "Microtune 4049 FM5",
-		.params = tuner_microtune_4049_fm5_params,
-		.count  = ARRAY_SIZE(tuner_microtune_4049_fm5_params),
-	},
-	[TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */
-		.name   = "Panasonic VP27s/ENGE4324D",
-		.params = tuner_panasonic_vp27_params,
-		.count  = ARRAY_SIZE(tuner_panasonic_vp27_params),
-	},
-	[TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */
-		.name   = "LG NTSC (TAPE series)",
-		.params = tuner_fm1236_mk3_params,
-		.count  = ARRAY_SIZE(tuner_fm1236_mk3_params),
-	},
-	[TUNER_TNF_8831BGFF] = { /* Philips PAL */
-		.name   = "Tenna TNF 8831 BGFF)",
-		.params = tuner_tnf_8831bgff_params,
-		.count  = ARRAY_SIZE(tuner_tnf_8831bgff_params),
-	},
-	[TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */
-		.name   = "Microtune 4042 FI5 ATSC/NTSC dual in",
-		.params = tuner_microtune_4042fi5_params,
-		.count  = ARRAY_SIZE(tuner_microtune_4042fi5_params),
-		.min    = 16 *  57.00,
-		.max    = 16 * 858.00,
-		.stepsize = 62500,
-	},
-
-	/* 50-59 */
-	[TUNER_TCL_2002N] = { /* TCL NTSC */
-		.name   = "TCL 2002N",
-		.params = tuner_tcl_2002n_params,
-		.count  = ARRAY_SIZE(tuner_tcl_2002n_params),
-	},
-	[TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */
-		.name   = "Philips PAL/SECAM_D (FM 1256 I-H3)",
-		.params = tuner_philips_fm1256_ih3_params,
-		.count  = ARRAY_SIZE(tuner_philips_fm1256_ih3_params),
-	},
-	[TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */
-		.name   = "Thomson DTT 7610 (ATSC/NTSC)",
-		.params = tuner_thomson_dtt7610_params,
-		.count  = ARRAY_SIZE(tuner_thomson_dtt7610_params),
-		.min    = 16 *  44.00,
-		.max    = 16 * 958.00,
-		.stepsize = 62500,
-	},
-	[TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */
-		.name   = "Philips FQ1286",
-		.params = tuner_philips_fq1286_params,
-		.count  = ARRAY_SIZE(tuner_philips_fq1286_params),
-	},
-	[TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */
-		.name   = "Philips/NXP TDA 8290/8295 + 8275/8275A/18271",
-		/* see tda8290.c for details */ },
-	[TUNER_TCL_2002MB] = { /* TCL PAL */
-		.name   = "TCL 2002MB",
-		.params = tuner_tcl_2002mb_params,
-		.count  = ARRAY_SIZE(tuner_tcl_2002mb_params),
-	},
-	[TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */
-		.name   = "Philips PAL/SECAM multi (FQ1216AME MK4)",
-		.params = tuner_philips_fq1216ame_mk4_params,
-		.count  = ARRAY_SIZE(tuner_philips_fq1216ame_mk4_params),
-	},
-	[TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */
-		.name   = "Philips FQ1236A MK4",
-		.params = tuner_philips_fq1236a_mk4_params,
-		.count  = ARRAY_SIZE(tuner_philips_fq1236a_mk4_params),
-	},
-	[TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */
-		.name   = "Ymec TVision TVF-8531MF/8831MF/8731MF",
-		.params = tuner_ymec_tvf_8531mf_params,
-		.count  = ARRAY_SIZE(tuner_ymec_tvf_8531mf_params),
-	},
-	[TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */
-		.name   = "Ymec TVision TVF-5533MF",
-		.params = tuner_ymec_tvf_5533mf_params,
-		.count  = ARRAY_SIZE(tuner_ymec_tvf_5533mf_params),
-	},
-
-	/* 60-69 */
-	[TUNER_THOMSON_DTT761X] = { /* THOMSON ATSC */
-		/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
-		.name   = "Thomson DTT 761X (ATSC/NTSC)",
-		.params = tuner_thomson_dtt761x_params,
-		.count  = ARRAY_SIZE(tuner_thomson_dtt761x_params),
-		.min    = 16 *  57.00,
-		.max    = 16 * 863.00,
-		.stepsize = 62500,
-		.initdata = tua603x_agc103,
-	},
-	[TUNER_TENA_9533_DI] = { /* Philips PAL */
-		.name   = "Tena TNF9533-D/IF/TNF9533-B/DF",
-		.params = tuner_tena_9533_di_params,
-		.count  = ARRAY_SIZE(tuner_tena_9533_di_params),
-	},
-	[TUNER_TEA5767] = { /* Philips RADIO */
-		.name   = "Philips TEA5767HN FM Radio",
-		/* see tea5767.c for details */
-	},
-	[TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */
-		.name   = "Philips FMD1216ME MK3 Hybrid Tuner",
-		.params = tuner_philips_fmd1216me_mk3_params,
-		.count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params),
-		.min = 16 *  50.87,
-		.max = 16 * 858.00,
-		.stepsize = 166667,
-		.initdata = tua603x_agc112,
-		.sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
-	},
-	[TUNER_LG_TDVS_H06XF] = { /* LGINNOTEK ATSC */
-		.name   = "LG TDVS-H06xF", /* H061F, H062F & H064F */
-		.params = tuner_lg_tdvs_h06xf_params,
-		.count  = ARRAY_SIZE(tuner_lg_tdvs_h06xf_params),
-		.min    = 16 *  54.00,
-		.max    = 16 * 863.00,
-		.stepsize = 62500,
-		.initdata = tua603x_agc103,
-	},
-	[TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */
-		.name   = "Ymec TVF66T5-B/DFF",
-		.params = tuner_ymec_tvf66t5_b_dff_params,
-		.count  = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_params),
-	},
-	[TUNER_LG_TALN] = { /* LGINNOTEK NTSC / PAL / SECAM */
-		.name   = "LG TALN series",
-		.params = tuner_lg_taln_params,
-		.count  = ARRAY_SIZE(tuner_lg_taln_params),
-	},
-	[TUNER_PHILIPS_TD1316] = { /* Philips PAL */
-		.name   = "Philips TD1316 Hybrid Tuner",
-		.params = tuner_philips_td1316_params,
-		.count  = ARRAY_SIZE(tuner_philips_td1316_params),
-		.min    = 16 *  87.00,
-		.max    = 16 * 895.00,
-		.stepsize = 166667,
-	},
-	[TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */
-		.name   = "Philips TUV1236D ATSC/NTSC dual in",
-		.params = tuner_tuv1236d_params,
-		.count  = ARRAY_SIZE(tuner_tuv1236d_params),
-		.min    = 16 *  54.00,
-		.max    = 16 * 864.00,
-		.stepsize = 62500,
-	},
-	[TUNER_TNF_5335MF] = { /* Tenna PAL/NTSC */
-		.name   = "Tena TNF 5335 and similar models",
-		.params = tuner_tnf_5335mf_params,
-		.count  = ARRAY_SIZE(tuner_tnf_5335mf_params),
-	},
-
-	/* 70-79 */
-	[TUNER_SAMSUNG_TCPN_2121P30A] = { /* Samsung NTSC */
-		.name   = "Samsung TCPN 2121P30A",
-		.params = tuner_samsung_tcpn_2121p30a_params,
-		.count  = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params),
-	},
-	[TUNER_XC2028] = { /* Xceive 2028 */
-		.name   = "Xceive xc2028/xc3028 tuner",
-		/* see tuner-xc2028.c for details */
-	},
-	[TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */
-		.name   = "Thomson FE6600",
-		.params = tuner_thomson_fe6600_params,
-		.count  = ARRAY_SIZE(tuner_thomson_fe6600_params),
-		.min    = 16 *  44.25,
-		.max    = 16 * 858.00,
-		.stepsize = 166667,
-	},
-	[TUNER_SAMSUNG_TCPG_6121P30A] = { /* Samsung PAL */
-		.name   = "Samsung TCPG 6121P30A",
-		.params = tuner_samsung_tcpg_6121p30a_params,
-		.count  = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_params),
-	},
-	[TUNER_TDA9887] = { /* Philips TDA 9887 IF PLL Demodulator.
-				This chip is part of some modern tuners */
-		.name   = "Philips TDA988[5,6,7] IF PLL Demodulator",
-		/* see tda9887.c for details */
-	},
-	[TUNER_TEA5761] = { /* Philips RADIO */
-		.name   = "Philips TEA5761 FM Radio",
-		/* see tea5767.c for details */
-	},
-	[TUNER_XC5000] = { /* Xceive 5000 */
-		.name   = "Xceive 5000 tuner",
-		/* see xc5000.c for details */
-	},
-	[TUNER_XC4000] = { /* Xceive 4000 */
-		.name   = "Xceive 4000 tuner",
-		/* see xc4000.c for details */
-	},
-	[TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */
-		.name   = "TCL tuner MF02GIP-5N-E",
-		.params = tuner_tcl_mf02gip_5n_params,
-		.count  = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params),
-	},
-	[TUNER_PHILIPS_FMD1216MEX_MK3] = { /* Philips PAL */
-		.name   = "Philips FMD1216MEX MK3 Hybrid Tuner",
-		.params = tuner_philips_fmd1216mex_mk3_params,
-		.count  = ARRAY_SIZE(tuner_philips_fmd1216mex_mk3_params),
-		.min = 16 *  50.87,
-		.max = 16 * 858.00,
-		.stepsize = 166667,
-		.initdata = tua603x_agc112,
-		.sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
-	},
-		[TUNER_PHILIPS_FM1216MK5] = { /* Philips PAL */
-		.name   = "Philips PAL/SECAM multi (FM1216 MK5)",
-		.params = tuner_fm1216mk5_params,
-		.count  = ARRAY_SIZE(tuner_fm1216mk5_params),
-	},
-
-	/* 80-89 */
-	[TUNER_PHILIPS_FQ1216LME_MK3] = { /* PAL/SECAM, Loop-thru, no FM */
-		.name = "Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough",
-		.params = tuner_fq1216lme_mk3_params,
-		.count  = ARRAY_SIZE(tuner_fq1216lme_mk3_params),
-	},
-
-	[TUNER_PARTSNIC_PTI_5NF05] = {
-		.name = "Partsnic (Daewoo) PTI-5NF05",
-		.params = tuner_partsnic_pti_5nf05_params,
-		.count  = ARRAY_SIZE(tuner_partsnic_pti_5nf05_params),
-	},
-	[TUNER_PHILIPS_CU1216L] = {
-		.name = "Philips CU1216L",
-		.params = tuner_philips_cu1216l_params,
-		.count  = ARRAY_SIZE(tuner_philips_cu1216l_params),
-		.stepsize = 62500,
-	},
-	[TUNER_NXP_TDA18271] = {
-		.name   = "NXP TDA18271",
-		/* see tda18271-fe.c for details */
-	},
-	[TUNER_SONY_BTF_PXN01Z] = {
-		.name   = "Sony BTF-Pxn01Z",
-		.params = tuner_sony_btf_pxn01z_params,
-		.count  = ARRAY_SIZE(tuner_sony_btf_pxn01z_params),
-	},
-	[TUNER_PHILIPS_FQ1236_MK5] = { /* NTSC, TDA9885, no FM radio */
-		.name   = "Philips FQ1236 MK5",
-		.params = tuner_philips_fq1236_mk5_params,
-		.count  = ARRAY_SIZE(tuner_philips_fq1236_mk5_params),
-	},
-	[TUNER_TENA_TNF_5337] = { /* Tena 5337 MFD */
-		.name   = "Tena TNF5337 MFD",
-		.params = tuner_tena_tnf_5337_params,
-		.count  = ARRAY_SIZE(tuner_tena_tnf_5337_params),
-	},
-	[TUNER_XC5000C] = { /* Xceive 5000C */
-		.name   = "Xceive 5000C tuner",
-		/* see xc5000.c for details */
-	},
-};
-EXPORT_SYMBOL(tuners);
-
-unsigned const int tuner_count = ARRAY_SIZE(tuners);
-EXPORT_SYMBOL(tuner_count);
-
-MODULE_DESCRIPTION("Simple tuner device type database");
-MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tuner-xc2028-types.h b/drivers/media/common/tuners/tuner-xc2028-types.h
deleted file mode 100644
index 74dc46a..0000000
--- a/drivers/media/common/tuners/tuner-xc2028-types.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/* tuner-xc2028_types
- *
- * This file includes internal tipes to be used inside tuner-xc2028.
- * Shouldn't be included outside tuner-xc2028
- *
- * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org)
- * This code is placed under the terms of the GNU General Public License v2
- */
-
-/* xc3028 firmware types */
-
-/* BASE firmware should be loaded before any other firmware */
-#define BASE		(1<<0)
-#define BASE_TYPES	(BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1)
-
-/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */
-#define F8MHZ		(1<<1)
-
-/* Multichannel Television Sound (MTS)
-   Those firmwares are capable of using xc2038 DSP to decode audio and
-   produce a baseband audio output on some pins of the chip.
-   There are MTS firmwares for the most used video standards. It should be
-   required to use MTS firmwares, depending on the way audio is routed into
-   the bridge chip
- */
-#define MTS		(1<<2)
-
-/* FIXME: I have no idea what's the difference between
-   D2620 and D2633 firmwares
- */
-#define D2620		(1<<3)
-#define D2633		(1<<4)
-
-/* DTV firmwares for 6, 7 and 8 MHz
-   DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS
-   DTV8 - 8MHz - DVB-C/DVB-T
- */
-#define DTV6           (1 << 5)
-#define QAM            (1 << 6)
-#define DTV7		(1<<7)
-#define DTV78		(1<<8)
-#define DTV8		(1<<9)
-
-#define DTV_TYPES	(D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC)
-
-/* There's a FM | BASE firmware + FM specific firmware (std=0) */
-#define	FM		(1<<10)
-
-#define STD_SPECIFIC_TYPES (MTS|FM|LCD|NOGD)
-
-/* Applies only for FM firmware
-   Makes it use RF input 1 (pin #2) instead of input 2 (pin #4)
- */
-#define INPUT1		(1<<11)
-
-
-/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
-	and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
-	There are variants both with and without NOGD
-	Those firmwares produce better result with LCD displays
- */
-#define LCD		(1<<12)
-
-/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
-	and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
-	The NOGD firmwares don't have group delay compensation filter
- */
-#define NOGD		(1<<13)
-
-/* Old firmwares were broken into init0 and init1 */
-#define INIT1		(1<<14)
-
-/* SCODE firmware selects particular behaviours */
-#define MONO           (1 << 15)
-#define ATSC           (1 << 16)
-#define IF             (1 << 17)
-#define LG60           (1 << 18)
-#define ATI638         (1 << 19)
-#define OREN538        (1 << 20)
-#define OREN36         (1 << 21)
-#define TOYOTA388      (1 << 22)
-#define TOYOTA794      (1 << 23)
-#define DIBCOM52       (1 << 24)
-#define ZARLINK456     (1 << 25)
-#define CHINA          (1 << 26)
-#define F6MHZ          (1 << 27)
-#define INPUT2         (1 << 28)
-#define SCODE          (1 << 29)
-
-/* This flag identifies that the scode table has a new format */
-#define HAS_IF         (1 << 30)
-
-/* There are different scode tables for MTS and non-MTS.
-   The MTS firmwares support mono only
-  */
-#define SCODE_TYPES (SCODE | MTS)
-
-
-/* Newer types not defined on videodev2.h.
-   The original idea were to move all those types to videodev2.h, but
-   it seemed overkill, since, with the exception of SECAM/K3, the other
-   types seem to be autodetected.
-   It is not clear where secam/k3 is used, nor we have a feedback of this
-   working or being autodetected by the standard secam firmware.
- */
-
-#define V4L2_STD_SECAM_K3	(0x04000000)
-
-/* Audio types */
-
-#define V4L2_STD_A2_A		(1LL<<32)
-#define V4L2_STD_A2_B		(1LL<<33)
-#define V4L2_STD_NICAM_A	(1LL<<34)
-#define V4L2_STD_NICAM_B	(1LL<<35)
-#define V4L2_STD_AM		(1LL<<36)
-#define V4L2_STD_BTSC		(1LL<<37)
-#define V4L2_STD_EIAJ		(1LL<<38)
-
-#define V4L2_STD_A2		(V4L2_STD_A2_A    | V4L2_STD_A2_B)
-#define V4L2_STD_NICAM		(V4L2_STD_NICAM_A | V4L2_STD_NICAM_B)
-
-/* To preserve backward compatibilty,
-   (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported
- */
-
-#define V4L2_STD_AUDIO		(V4L2_STD_A2    | \
-				 V4L2_STD_NICAM | \
-				 V4L2_STD_AM    | \
-				 V4L2_STD_BTSC  | \
-				 V4L2_STD_EIAJ)
-
-/* Used standards with audio restrictions */
-
-#define V4L2_STD_PAL_BG_A2_A	(V4L2_STD_PAL_BG | V4L2_STD_A2_A)
-#define V4L2_STD_PAL_BG_A2_B	(V4L2_STD_PAL_BG | V4L2_STD_A2_B)
-#define V4L2_STD_PAL_BG_NICAM_A	(V4L2_STD_PAL_BG | V4L2_STD_NICAM_A)
-#define V4L2_STD_PAL_BG_NICAM_B	(V4L2_STD_PAL_BG | V4L2_STD_NICAM_B)
-#define V4L2_STD_PAL_DK_A2	(V4L2_STD_PAL_DK | V4L2_STD_A2)
-#define V4L2_STD_PAL_DK_NICAM	(V4L2_STD_PAL_DK | V4L2_STD_NICAM)
-#define V4L2_STD_SECAM_L_NICAM	(V4L2_STD_SECAM_L | V4L2_STD_NICAM)
-#define V4L2_STD_SECAM_L_AM	(V4L2_STD_SECAM_L | V4L2_STD_AM)
diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c
deleted file mode 100644
index ea0550e..0000000
--- a/drivers/media/common/tuners/tuner-xc2028.c
+++ /dev/null
@@ -1,1510 +0,0 @@
-/* tuner-xc2028
- *
- * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org)
- *
- * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com)
- *       - frontend interface
- *
- * This code is placed under the terms of the GNU General Public License v2
- */
-
-#include <linux/i2c.h>
-#include <asm/div64.h>
-#include <linux/firmware.h>
-#include <linux/videodev2.h>
-#include <linux/delay.h>
-#include <media/tuner.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <asm/unaligned.h>
-#include "tuner-i2c.h"
-#include "tuner-xc2028.h"
-#include "tuner-xc2028-types.h"
-
-#include <linux/dvb/frontend.h>
-#include "dvb_frontend.h"
-
-/* Registers (Write-only) */
-#define XREG_INIT         0x00
-#define XREG_RF_FREQ      0x02
-#define XREG_POWER_DOWN   0x08
-
-/* Registers (Read-only) */
-#define XREG_FREQ_ERROR   0x01
-#define XREG_LOCK         0x02
-#define XREG_VERSION      0x04
-#define XREG_PRODUCT_ID   0x08
-#define XREG_HSYNC_FREQ   0x10
-#define XREG_FRAME_LINES  0x20
-#define XREG_SNR          0x40
-
-#define XREG_ADC_ENV      0x0100
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-static int no_poweroff;
-module_param(no_poweroff, int, 0644);
-MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
-	"1 keep device energized and with tuner ready all the times.\n"
-	"  Faster, but consumes more power and keeps the device hotter\n");
-
-static char audio_std[8];
-module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
-MODULE_PARM_DESC(audio_std,
-	"Audio standard. XC3028 audio decoder explicitly "
-	"needs to know what audio\n"
-	"standard is needed for some video standards with audio A2 or NICAM.\n"
-	"The valid values are:\n"
-	"A2\n"
-	"A2/A\n"
-	"A2/B\n"
-	"NICAM\n"
-	"NICAM/A\n"
-	"NICAM/B\n");
-
-static char firmware_name[30];
-module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
-MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
-				"default firmware name\n");
-
-static LIST_HEAD(hybrid_tuner_instance_list);
-static DEFINE_MUTEX(xc2028_list_mutex);
-
-/* struct for storing firmware table */
-struct firmware_description {
-	unsigned int  type;
-	v4l2_std_id   id;
-	__u16         int_freq;
-	unsigned char *ptr;
-	unsigned int  size;
-};
-
-struct firmware_properties {
-	unsigned int	type;
-	v4l2_std_id	id;
-	v4l2_std_id	std_req;
-	__u16		int_freq;
-	unsigned int	scode_table;
-	int 		scode_nr;
-};
-
-enum xc2028_state {
-	XC2028_NO_FIRMWARE = 0,
-	XC2028_WAITING_FIRMWARE,
-	XC2028_ACTIVE,
-	XC2028_SLEEP,
-	XC2028_NODEV,
-};
-
-struct xc2028_data {
-	struct list_head        hybrid_tuner_instance_list;
-	struct tuner_i2c_props  i2c_props;
-	__u32			frequency;
-
-	enum xc2028_state	state;
-	const char		*fname;
-
-	struct firmware_description *firm;
-	int			firm_size;
-	__u16			firm_version;
-
-	__u16			hwmodel;
-	__u16			hwvers;
-
-	struct xc2028_ctrl	ctrl;
-
-	struct firmware_properties cur_fw;
-
-	struct mutex lock;
-};
-
-#define i2c_send(priv, buf, size) ({					\
-	int _rc;							\
-	_rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size);		\
-	if (size != _rc)						\
-		tuner_info("i2c output error: rc = %d (should be %d)\n",\
-			   _rc, (int)size);				\
-	if (priv->ctrl.msleep)						\
-		msleep(priv->ctrl.msleep);				\
-	_rc;								\
-})
-
-#define i2c_rcv(priv, buf, size) ({					\
-	int _rc;							\
-	_rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size);		\
-	if (size != _rc)						\
-		tuner_err("i2c input error: rc = %d (should be %d)\n",	\
-			   _rc, (int)size); 				\
-	_rc;								\
-})
-
-#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({		\
-	int _rc;							\
-	_rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize,	\
-				       ibuf, isize);			\
-	if (isize != _rc)						\
-		tuner_err("i2c input error: rc = %d (should be %d)\n",	\
-			   _rc, (int)isize); 				\
-	if (priv->ctrl.msleep)						\
-		msleep(priv->ctrl.msleep);				\
-	_rc;								\
-})
-
-#define send_seq(priv, data...)	({					\
-	static u8 _val[] = data;					\
-	int _rc;							\
-	if (sizeof(_val) !=						\
-			(_rc = tuner_i2c_xfer_send(&priv->i2c_props,	\
-						_val, sizeof(_val)))) {	\
-		tuner_err("Error on line %d: %d\n", __LINE__, _rc);	\
-	} else if (priv->ctrl.msleep)					\
-		msleep(priv->ctrl.msleep);				\
-	_rc;								\
-})
-
-static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
-{
-	unsigned char buf[2];
-	unsigned char ibuf[2];
-
-	tuner_dbg("%s %04x called\n", __func__, reg);
-
-	buf[0] = reg >> 8;
-	buf[1] = (unsigned char) reg;
-
-	if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2)
-		return -EIO;
-
-	*val = (ibuf[1]) | (ibuf[0] << 8);
-	return 0;
-}
-
-#define dump_firm_type(t) 	dump_firm_type_and_int_freq(t, 0)
-static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
-{
-	 if (type & BASE)
-		printk("BASE ");
-	 if (type & INIT1)
-		printk("INIT1 ");
-	 if (type & F8MHZ)
-		printk("F8MHZ ");
-	 if (type & MTS)
-		printk("MTS ");
-	 if (type & D2620)
-		printk("D2620 ");
-	 if (type & D2633)
-		printk("D2633 ");
-	 if (type & DTV6)
-		printk("DTV6 ");
-	 if (type & QAM)
-		printk("QAM ");
-	 if (type & DTV7)
-		printk("DTV7 ");
-	 if (type & DTV78)
-		printk("DTV78 ");
-	 if (type & DTV8)
-		printk("DTV8 ");
-	 if (type & FM)
-		printk("FM ");
-	 if (type & INPUT1)
-		printk("INPUT1 ");
-	 if (type & LCD)
-		printk("LCD ");
-	 if (type & NOGD)
-		printk("NOGD ");
-	 if (type & MONO)
-		printk("MONO ");
-	 if (type & ATSC)
-		printk("ATSC ");
-	 if (type & IF)
-		printk("IF ");
-	 if (type & LG60)
-		printk("LG60 ");
-	 if (type & ATI638)
-		printk("ATI638 ");
-	 if (type & OREN538)
-		printk("OREN538 ");
-	 if (type & OREN36)
-		printk("OREN36 ");
-	 if (type & TOYOTA388)
-		printk("TOYOTA388 ");
-	 if (type & TOYOTA794)
-		printk("TOYOTA794 ");
-	 if (type & DIBCOM52)
-		printk("DIBCOM52 ");
-	 if (type & ZARLINK456)
-		printk("ZARLINK456 ");
-	 if (type & CHINA)
-		printk("CHINA ");
-	 if (type & F6MHZ)
-		printk("F6MHZ ");
-	 if (type & INPUT2)
-		printk("INPUT2 ");
-	 if (type & SCODE)
-		printk("SCODE ");
-	 if (type & HAS_IF)
-		printk("HAS_IF_%d ", int_freq);
-}
-
-static  v4l2_std_id parse_audio_std_option(void)
-{
-	if (strcasecmp(audio_std, "A2") == 0)
-		return V4L2_STD_A2;
-	if (strcasecmp(audio_std, "A2/A") == 0)
-		return V4L2_STD_A2_A;
-	if (strcasecmp(audio_std, "A2/B") == 0)
-		return V4L2_STD_A2_B;
-	if (strcasecmp(audio_std, "NICAM") == 0)
-		return V4L2_STD_NICAM;
-	if (strcasecmp(audio_std, "NICAM/A") == 0)
-		return V4L2_STD_NICAM_A;
-	if (strcasecmp(audio_std, "NICAM/B") == 0)
-		return V4L2_STD_NICAM_B;
-
-	return 0;
-}
-
-static int check_device_status(struct xc2028_data *priv)
-{
-	switch (priv->state) {
-	case XC2028_NO_FIRMWARE:
-	case XC2028_WAITING_FIRMWARE:
-		return -EAGAIN;
-	case XC2028_ACTIVE:
-	case XC2028_SLEEP:
-		return 0;
-	case XC2028_NODEV:
-		return -ENODEV;
-	}
-	return 0;
-}
-
-static void free_firmware(struct xc2028_data *priv)
-{
-	int i;
-	tuner_dbg("%s called\n", __func__);
-
-	if (!priv->firm)
-		return;
-
-	for (i = 0; i < priv->firm_size; i++)
-		kfree(priv->firm[i].ptr);
-
-	kfree(priv->firm);
-
-	priv->firm = NULL;
-	priv->firm_size = 0;
-	priv->state = XC2028_NO_FIRMWARE;
-
-	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
-}
-
-static int load_all_firmwares(struct dvb_frontend *fe,
-			      const struct firmware *fw)
-{
-	struct xc2028_data    *priv = fe->tuner_priv;
-	const unsigned char   *p, *endp;
-	int                   rc = 0;
-	int		      n, n_array;
-	char		      name[33];
-
-	tuner_dbg("%s called\n", __func__);
-
-	p = fw->data;
-	endp = p + fw->size;
-
-	if (fw->size < sizeof(name) - 1 + 2 + 2) {
-		tuner_err("Error: firmware file %s has invalid size!\n",
-			  priv->fname);
-		goto corrupt;
-	}
-
-	memcpy(name, p, sizeof(name) - 1);
-	name[sizeof(name) - 1] = 0;
-	p += sizeof(name) - 1;
-
-	priv->firm_version = get_unaligned_le16(p);
-	p += 2;
-
-	n_array = get_unaligned_le16(p);
-	p += 2;
-
-	tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
-		   n_array, priv->fname, name,
-		   priv->firm_version >> 8, priv->firm_version & 0xff);
-
-	priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL);
-	if (priv->firm == NULL) {
-		tuner_err("Not enough memory to load firmware file.\n");
-		rc = -ENOMEM;
-		goto err;
-	}
-	priv->firm_size = n_array;
-
-	n = -1;
-	while (p < endp) {
-		__u32 type, size;
-		v4l2_std_id id;
-		__u16 int_freq = 0;
-
-		n++;
-		if (n >= n_array) {
-			tuner_err("More firmware images in file than "
-				  "were expected!\n");
-			goto corrupt;
-		}
-
-		/* Checks if there's enough bytes to read */
-		if (endp - p < sizeof(type) + sizeof(id) + sizeof(size))
-			goto header;
-
-		type = get_unaligned_le32(p);
-		p += sizeof(type);
-
-		id = get_unaligned_le64(p);
-		p += sizeof(id);
-
-		if (type & HAS_IF) {
-			int_freq = get_unaligned_le16(p);
-			p += sizeof(int_freq);
-			if (endp - p < sizeof(size))
-				goto header;
-		}
-
-		size = get_unaligned_le32(p);
-		p += sizeof(size);
-
-		if (!size || size > endp - p) {
-			tuner_err("Firmware type ");
-			dump_firm_type(type);
-			printk("(%x), id %llx is corrupted "
-			       "(size=%d, expected %d)\n",
-			       type, (unsigned long long)id,
-			       (unsigned)(endp - p), size);
-			goto corrupt;
-		}
-
-		priv->firm[n].ptr = kzalloc(size, GFP_KERNEL);
-		if (priv->firm[n].ptr == NULL) {
-			tuner_err("Not enough memory to load firmware file.\n");
-			rc = -ENOMEM;
-			goto err;
-		}
-		tuner_dbg("Reading firmware type ");
-		if (debug) {
-			dump_firm_type_and_int_freq(type, int_freq);
-			printk("(%x), id %llx, size=%d.\n",
-			       type, (unsigned long long)id, size);
-		}
-
-		memcpy(priv->firm[n].ptr, p, size);
-		priv->firm[n].type = type;
-		priv->firm[n].id   = id;
-		priv->firm[n].size = size;
-		priv->firm[n].int_freq = int_freq;
-
-		p += size;
-	}
-
-	if (n + 1 != priv->firm_size) {
-		tuner_err("Firmware file is incomplete!\n");
-		goto corrupt;
-	}
-
-	goto done;
-
-header:
-	tuner_err("Firmware header is incomplete!\n");
-corrupt:
-	rc = -EINVAL;
-	tuner_err("Error: firmware file is corrupted!\n");
-
-err:
-	tuner_info("Releasing partially loaded firmware file.\n");
-	free_firmware(priv);
-
-done:
-	if (rc == 0)
-		tuner_dbg("Firmware files loaded.\n");
-	else
-		priv->state = XC2028_NODEV;
-
-	return rc;
-}
-
-static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
-			 v4l2_std_id *id)
-{
-	struct xc2028_data *priv = fe->tuner_priv;
-	int                 i, best_i = -1, best_nr_matches = 0;
-	unsigned int        type_mask = 0;
-
-	tuner_dbg("%s called, want type=", __func__);
-	if (debug) {
-		dump_firm_type(type);
-		printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
-	}
-
-	if (!priv->firm) {
-		tuner_err("Error! firmware not loaded\n");
-		return -EINVAL;
-	}
-
-	if (((type & ~SCODE) == 0) && (*id == 0))
-		*id = V4L2_STD_PAL;
-
-	if (type & BASE)
-		type_mask = BASE_TYPES;
-	else if (type & SCODE) {
-		type &= SCODE_TYPES;
-		type_mask = SCODE_TYPES & ~HAS_IF;
-	} else if (type & DTV_TYPES)
-		type_mask = DTV_TYPES;
-	else if (type & STD_SPECIFIC_TYPES)
-		type_mask = STD_SPECIFIC_TYPES;
-
-	type &= type_mask;
-
-	if (!(type & SCODE))
-		type_mask = ~0;
-
-	/* Seek for exact match */
-	for (i = 0; i < priv->firm_size; i++) {
-		if ((type == (priv->firm[i].type & type_mask)) &&
-		    (*id == priv->firm[i].id))
-			goto found;
-	}
-
-	/* Seek for generic video standard match */
-	for (i = 0; i < priv->firm_size; i++) {
-		v4l2_std_id match_mask;
-		int nr_matches;
-
-		if (type != (priv->firm[i].type & type_mask))
-			continue;
-
-		match_mask = *id & priv->firm[i].id;
-		if (!match_mask)
-			continue;
-
-		if ((*id & match_mask) == *id)
-			goto found; /* Supports all the requested standards */
-
-		nr_matches = hweight64(match_mask);
-		if (nr_matches > best_nr_matches) {
-			best_nr_matches = nr_matches;
-			best_i = i;
-		}
-	}
-
-	if (best_nr_matches > 0) {
-		tuner_dbg("Selecting best matching firmware (%d bits) for "
-			  "type=", best_nr_matches);
-		dump_firm_type(type);
-		printk("(%x), id %016llx:\n", type, (unsigned long long)*id);
-		i = best_i;
-		goto found;
-	}
-
-	/*FIXME: Would make sense to seek for type "hint" match ? */
-
-	i = -ENOENT;
-	goto ret;
-
-found:
-	*id = priv->firm[i].id;
-
-ret:
-	tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found");
-	if (debug) {
-		dump_firm_type(type);
-		printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
-	}
-	return i;
-}
-
-static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg)
-{
-	struct xc2028_data *priv = fe->tuner_priv;
-
-	/* analog side (tuner-core) uses i2c_adap->algo_data.
-	 * digital side is not guaranteed to have algo_data defined.
-	 *
-	 * digital side will always have fe->dvb defined.
-	 * analog side (tuner-core) doesn't (yet) define fe->dvb.
-	 */
-
-	return (!fe->callback) ? -EINVAL :
-		fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
-				fe->dvb->priv : priv->i2c_props.adap->algo_data,
-			     DVB_FRONTEND_COMPONENT_TUNER, cmd, arg);
-}
-
-static int load_firmware(struct dvb_frontend *fe, unsigned int type,
-			 v4l2_std_id *id)
-{
-	struct xc2028_data *priv = fe->tuner_priv;
-	int                pos, rc;
-	unsigned char      *p, *endp, buf[priv->ctrl.max_len];
-
-	tuner_dbg("%s called\n", __func__);
-
-	pos = seek_firmware(fe, type, id);
-	if (pos < 0)
-		return pos;
-
-	tuner_info("Loading firmware for type=");
-	dump_firm_type(priv->firm[pos].type);
-	printk("(%x), id %016llx.\n", priv->firm[pos].type,
-	       (unsigned long long)*id);
-
-	p = priv->firm[pos].ptr;
-	endp = p + priv->firm[pos].size;
-
-	while (p < endp) {
-		__u16 size;
-
-		/* Checks if there's enough bytes to read */
-		if (p + sizeof(size) > endp) {
-			tuner_err("Firmware chunk size is wrong\n");
-			return -EINVAL;
-		}
-
-		size = le16_to_cpu(*(__u16 *) p);
-		p += sizeof(size);
-
-		if (size == 0xffff)
-			return 0;
-
-		if (!size) {
-			/* Special callback command received */
-			rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
-			if (rc < 0) {
-				tuner_err("Error at RESET code %d\n",
-					   (*p) & 0x7f);
-				return -EINVAL;
-			}
-			continue;
-		}
-		if (size >= 0xff00) {
-			switch (size) {
-			case 0xff00:
-				rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0);
-				if (rc < 0) {
-					tuner_err("Error at RESET code %d\n",
-						  (*p) & 0x7f);
-					return -EINVAL;
-				}
-				break;
-			default:
-				tuner_info("Invalid RESET code %d\n",
-					   size & 0x7f);
-				return -EINVAL;
-
-			}
-			continue;
-		}
-
-		/* Checks for a sleep command */
-		if (size & 0x8000) {
-			msleep(size & 0x7fff);
-			continue;
-		}
-
-		if ((size + p > endp)) {
-			tuner_err("missing bytes: need %d, have %d\n",
-				   size, (int)(endp - p));
-			return -EINVAL;
-		}
-
-		buf[0] = *p;
-		p++;
-		size--;
-
-		/* Sends message chunks */
-		while (size > 0) {
-			int len = (size < priv->ctrl.max_len - 1) ?
-				   size : priv->ctrl.max_len - 1;
-
-			memcpy(buf + 1, p, len);
-
-			rc = i2c_send(priv, buf, len + 1);
-			if (rc < 0) {
-				tuner_err("%d returned from send\n", rc);
-				return -EINVAL;
-			}
-
-			p += len;
-			size -= len;
-		}
-
-		/* silently fail if the frontend doesn't support I2C flush */
-		rc = do_tuner_callback(fe, XC2028_I2C_FLUSH, 0);
-		if ((rc < 0) && (rc != -EINVAL)) {
-			tuner_err("error executing flush: %d\n", rc);
-			return rc;
-		}
-	}
-	return 0;
-}
-
-static int load_scode(struct dvb_frontend *fe, unsigned int type,
-			 v4l2_std_id *id, __u16 int_freq, int scode)
-{
-	struct xc2028_data *priv = fe->tuner_priv;
-	int                pos, rc;
-	unsigned char	   *p;
-
-	tuner_dbg("%s called\n", __func__);
-
-	if (!int_freq) {
-		pos = seek_firmware(fe, type, id);
-		if (pos < 0)
-			return pos;
-	} else {
-		for (pos = 0; pos < priv->firm_size; pos++) {
-			if ((priv->firm[pos].int_freq == int_freq) &&
-			    (priv->firm[pos].type & HAS_IF))
-				break;
-		}
-		if (pos == priv->firm_size)
-			return -ENOENT;
-	}
-
-	p = priv->firm[pos].ptr;
-
-	if (priv->firm[pos].type & HAS_IF) {
-		if (priv->firm[pos].size != 12 * 16 || scode >= 16)
-			return -EINVAL;
-		p += 12 * scode;
-	} else {
-		/* 16 SCODE entries per file; each SCODE entry is 12 bytes and
-		 * has a 2-byte size header in the firmware format. */
-		if (priv->firm[pos].size != 14 * 16 || scode >= 16 ||
-		    le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12)
-			return -EINVAL;
-		p += 14 * scode + 2;
-	}
-
-	tuner_info("Loading SCODE for type=");
-	dump_firm_type_and_int_freq(priv->firm[pos].type,
-				    priv->firm[pos].int_freq);
-	printk("(%x), id %016llx.\n", priv->firm[pos].type,
-	       (unsigned long long)*id);
-
-	if (priv->firm_version < 0x0202)
-		rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00});
-	else
-		rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00});
-	if (rc < 0)
-		return -EIO;
-
-	rc = i2c_send(priv, p, 12);
-	if (rc < 0)
-		return -EIO;
-
-	rc = send_seq(priv, {0x00, 0x8c});
-	if (rc < 0)
-		return -EIO;
-
-	return 0;
-}
-
-static int check_firmware(struct dvb_frontend *fe, unsigned int type,
-			  v4l2_std_id std, __u16 int_freq)
-{
-	struct xc2028_data         *priv = fe->tuner_priv;
-	struct firmware_properties new_fw;
-	int			   rc, retry_count = 0;
-	u16			   version, hwmodel;
-	v4l2_std_id		   std0;
-
-	tuner_dbg("%s called\n", __func__);
-
-	rc = check_device_status(priv);
-	if (rc < 0)
-		return rc;
-
-	if (priv->ctrl.mts && !(type & FM))
-		type |= MTS;
-
-retry:
-	new_fw.type = type;
-	new_fw.id = std;
-	new_fw.std_req = std;
-	new_fw.scode_table = SCODE | priv->ctrl.scode_table;
-	new_fw.scode_nr = 0;
-	new_fw.int_freq = int_freq;
-
-	tuner_dbg("checking firmware, user requested type=");
-	if (debug) {
-		dump_firm_type(new_fw.type);
-		printk("(%x), id %016llx, ", new_fw.type,
-		       (unsigned long long)new_fw.std_req);
-		if (!int_freq) {
-			printk("scode_tbl ");
-			dump_firm_type(priv->ctrl.scode_table);
-			printk("(%x), ", priv->ctrl.scode_table);
-		} else
-			printk("int_freq %d, ", new_fw.int_freq);
-		printk("scode_nr %d\n", new_fw.scode_nr);
-	}
-
-	/*
-	 * No need to reload base firmware if it matches and if the tuner
-	 * is not at sleep mode
-	 */
-	if ((priv->state == XC2028_ACTIVE) &&
-	    (((BASE | new_fw.type) & BASE_TYPES) ==
-	    (priv->cur_fw.type & BASE_TYPES))) {
-		tuner_dbg("BASE firmware not changed.\n");
-		goto skip_base;
-	}
-
-	/* Updating BASE - forget about all currently loaded firmware */
-	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
-
-	/* Reset is needed before loading firmware */
-	rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
-	if (rc < 0)
-		goto fail;
-
-	/* BASE firmwares are all std0 */
-	std0 = 0;
-	rc = load_firmware(fe, BASE | new_fw.type, &std0);
-	if (rc < 0) {
-		tuner_err("Error %d while loading base firmware\n",
-			  rc);
-		goto fail;
-	}
-
-	/* Load INIT1, if needed */
-	tuner_dbg("Load init1 firmware, if exists\n");
-
-	rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0);
-	if (rc == -ENOENT)
-		rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ,
-				   &std0);
-	if (rc < 0 && rc != -ENOENT) {
-		tuner_err("Error %d while loading init1 firmware\n",
-			  rc);
-		goto fail;
-	}
-
-skip_base:
-	/*
-	 * No need to reload standard specific firmware if base firmware
-	 * was not reloaded and requested video standards have not changed.
-	 */
-	if (priv->cur_fw.type == (BASE | new_fw.type) &&
-	    priv->cur_fw.std_req == std) {
-		tuner_dbg("Std-specific firmware already loaded.\n");
-		goto skip_std_specific;
-	}
-
-	/* Reloading std-specific firmware forces a SCODE update */
-	priv->cur_fw.scode_table = 0;
-
-	rc = load_firmware(fe, new_fw.type, &new_fw.id);
-	if (rc == -ENOENT)
-		rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id);
-
-	if (rc < 0)
-		goto fail;
-
-skip_std_specific:
-	if (priv->cur_fw.scode_table == new_fw.scode_table &&
-	    priv->cur_fw.scode_nr == new_fw.scode_nr) {
-		tuner_dbg("SCODE firmware already loaded.\n");
-		goto check_device;
-	}
-
-	if (new_fw.type & FM)
-		goto check_device;
-
-	/* Load SCODE firmware, if exists */
-	tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr);
-
-	rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
-			new_fw.int_freq, new_fw.scode_nr);
-
-check_device:
-	if (xc2028_get_reg(priv, 0x0004, &version) < 0 ||
-	    xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) {
-		tuner_err("Unable to read tuner registers.\n");
-		goto fail;
-	}
-
-	tuner_dbg("Device is Xceive %d version %d.%d, "
-		  "firmware version %d.%d\n",
-		  hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
-		  (version & 0xf0) >> 4, version & 0xf);
-
-
-	if (priv->ctrl.read_not_reliable)
-		goto read_not_reliable;
-
-	/* Check firmware version against what we downloaded. */
-	if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) {
-		if (!priv->ctrl.read_not_reliable) {
-			tuner_err("Incorrect readback of firmware version.\n");
-			goto fail;
-		} else {
-			tuner_err("Returned an incorrect version. However, "
-				  "read is not reliable enough. Ignoring it.\n");
-			hwmodel = 3028;
-		}
-	}
-
-	/* Check that the tuner hardware model remains consistent over time. */
-	if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) {
-		priv->hwmodel = hwmodel;
-		priv->hwvers  = version & 0xff00;
-	} else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
-		   priv->hwvers != (version & 0xff00)) {
-		tuner_err("Read invalid device hardware information - tuner "
-			  "hung?\n");
-		goto fail;
-	}
-
-read_not_reliable:
-	memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
-
-	/*
-	 * By setting BASE in cur_fw.type only after successfully loading all
-	 * firmwares, we can:
-	 * 1. Identify that BASE firmware with type=0 has been loaded;
-	 * 2. Tell whether BASE firmware was just changed the next time through.
-	 */
-	priv->cur_fw.type |= BASE;
-	priv->state = XC2028_ACTIVE;
-
-	return 0;
-
-fail:
-	priv->state = XC2028_SLEEP;
-
-	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
-	if (retry_count < 8) {
-		msleep(50);
-		retry_count++;
-		tuner_dbg("Retrying firmware load\n");
-		goto retry;
-	}
-
-	if (rc == -ENOENT)
-		rc = -EINVAL;
-	return rc;
-}
-
-static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
-{
-	struct xc2028_data *priv = fe->tuner_priv;
-	u16                 frq_lock, signal = 0;
-	int                 rc, i;
-
-	tuner_dbg("%s called\n", __func__);
-
-	rc = check_device_status(priv);
-	if (rc < 0)
-		return rc;
-
-	mutex_lock(&priv->lock);
-
-	/* Sync Lock Indicator */
-	for (i = 0; i < 3; i++) {
-		rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
-		if (rc < 0)
-			goto ret;
-
-		if (frq_lock)
-			break;
-		msleep(6);
-	}
-
-	/* Frequency didn't lock */
-	if (frq_lock == 2)
-		goto ret;
-
-	/* Get SNR of the video signal */
-	rc = xc2028_get_reg(priv, XREG_SNR, &signal);
-	if (rc < 0)
-		goto ret;
-
-	/* Signal level is 3 bits only */
-
-	signal = ((1 << 12) - 1) | ((signal & 0x07) << 12);
-
-ret:
-	mutex_unlock(&priv->lock);
-
-	*strength = signal;
-
-	tuner_dbg("signal strength is %d\n", signal);
-
-	return rc;
-}
-
-static int xc2028_get_afc(struct dvb_frontend *fe, s32 *afc)
-{
-	struct xc2028_data *priv = fe->tuner_priv;
-	int i, rc;
-	u16 frq_lock = 0;
-	s16 afc_reg = 0;
-
-	rc = check_device_status(priv);
-	if (rc < 0)
-		return rc;
-
-	mutex_lock(&priv->lock);
-
-	/* Sync Lock Indicator */
-	for (i = 0; i < 3; i++) {
-		rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
-		if (rc < 0)
-			goto ret;
-
-		if (frq_lock)
-			break;
-		msleep(6);
-	}
-
-	/* Frequency didn't lock */
-	if (frq_lock == 2)
-		goto ret;
-
-	/* Get AFC */
-	rc = xc2028_get_reg(priv, XREG_FREQ_ERROR, &afc_reg);
-	if (rc < 0)
-		goto ret;
-
-	*afc = afc_reg * 15625; /* Hz */
-
-	tuner_dbg("AFC is %d Hz\n", *afc);
-
-ret:
-	mutex_unlock(&priv->lock);
-
-	return rc;
-}
-
-#define DIV 15625
-
-static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
-			    enum v4l2_tuner_type new_type,
-			    unsigned int type,
-			    v4l2_std_id std,
-			    u16 int_freq)
-{
-	struct xc2028_data *priv = fe->tuner_priv;
-	int		   rc = -EINVAL;
-	unsigned char	   buf[4];
-	u32		   div, offset = 0;
-
-	tuner_dbg("%s called\n", __func__);
-
-	mutex_lock(&priv->lock);
-
-	tuner_dbg("should set frequency %d kHz\n", freq / 1000);
-
-	if (check_firmware(fe, type, std, int_freq) < 0)
-		goto ret;
-
-	/* On some cases xc2028 can disable video output, if
-	 * very weak signals are received. By sending a soft
-	 * reset, this is re-enabled. So, it is better to always
-	 * send a soft reset before changing channels, to be sure
-	 * that xc2028 will be in a safe state.
-	 * Maybe this might also be needed for DTV.
-	 */
-	switch (new_type) {
-	case V4L2_TUNER_ANALOG_TV:
-		rc = send_seq(priv, {0x00, 0x00});
-
-		/* Analog mode requires offset = 0 */
-		break;
-	case V4L2_TUNER_RADIO:
-		/* Radio mode requires offset = 0 */
-		break;
-	case V4L2_TUNER_DIGITAL_TV:
-		/*
-		 * Digital modes require an offset to adjust to the
-		 * proper frequency. The offset depends on what
-		 * firmware version is used.
-		 */
-
-		/*
-		 * Adjust to the center frequency. This is calculated by the
-		 * formula: offset = 1.25MHz - BW/2
-		 * For DTV 7/8, the firmware uses BW = 8000, so it needs a
-		 * further adjustment to get the frequency center on VHF
-		 */
-
-		/*
-		 * The firmware DTV78 used to work fine in UHF band (8 MHz
-		 * bandwidth) but not at all in VHF band (7 MHz bandwidth).
-		 * The real problem was connected to the formula used to
-		 * calculate the center frequency offset in VHF band.
-		 * In fact, removing the 500KHz adjustment fixed the problem.
-		 * This is coherent to what was implemented for the DTV7
-		 * firmware.
-		 * In the end, now the center frequency is the same for all 3
-		 * firmwares (DTV7, DTV8, DTV78) and doesn't depend on channel
-		 * bandwidth.
-		 */
-
-		if (priv->cur_fw.type & DTV6)
-			offset = 1750000;
-		else	/* DTV7 or DTV8 or DTV78 */
-			offset = 2750000;
-
-		/*
-		 * xc3028 additional "magic"
-		 * Depending on the firmware version, it needs some adjustments
-		 * to properly centralize the frequency. This seems to be
-		 * needed to compensate the SCODE table adjustments made by
-		 * newer firmwares
-		 */
-
-		/*
-		 * The proper adjustment would be to do it at s-code table.
-		 * However, this didn't work, as reported by
-		 * Robert Lowery <rglowery@exemail.com.au>
-		 */
-
-#if 0
-		/*
-		 * Still need tests for XC3028L (firmware 3.2 or upper)
-		 * So, for now, let's just comment the per-firmware
-		 * version of this change. Reports with xc3028l working
-		 * with and without the lines bellow are welcome
-		 */
-
-		if (priv->firm_version < 0x0302) {
-			if (priv->cur_fw.type & DTV7)
-				offset += 500000;
-		} else {
-			if (priv->cur_fw.type & DTV7)
-				offset -= 300000;
-			else if (type != ATSC) /* DVB @6MHz, DTV 8 and DTV 7/8 */
-				offset += 200000;
-		}
-#endif
-	}
-
-	div = (freq - offset + DIV / 2) / DIV;
-
-	/* CMD= Set frequency */
-	if (priv->firm_version < 0x0202)
-		rc = send_seq(priv, {0x00, XREG_RF_FREQ, 0x00, 0x00});
-	else
-		rc = send_seq(priv, {0x80, XREG_RF_FREQ, 0x00, 0x00});
-	if (rc < 0)
-		goto ret;
-
-	/* Return code shouldn't be checked.
-	   The reset CLK is needed only with tm6000.
-	   Driver should work fine even if this fails.
-	 */
-	if (priv->ctrl.msleep)
-		msleep(priv->ctrl.msleep);
-	do_tuner_callback(fe, XC2028_RESET_CLK, 1);
-
-	msleep(10);
-
-	buf[0] = 0xff & (div >> 24);
-	buf[1] = 0xff & (div >> 16);
-	buf[2] = 0xff & (div >> 8);
-	buf[3] = 0xff & (div);
-
-	rc = i2c_send(priv, buf, sizeof(buf));
-	if (rc < 0)
-		goto ret;
-	msleep(100);
-
-	priv->frequency = freq;
-
-	tuner_dbg("divisor= %02x %02x %02x %02x (freq=%d.%03d)\n",
-	       buf[0], buf[1], buf[2], buf[3],
-	       freq / 1000000, (freq % 1000000) / 1000);
-
-	rc = 0;
-
-ret:
-	mutex_unlock(&priv->lock);
-
-	return rc;
-}
-
-static int xc2028_set_analog_freq(struct dvb_frontend *fe,
-			      struct analog_parameters *p)
-{
-	struct xc2028_data *priv = fe->tuner_priv;
-	unsigned int       type=0;
-
-	tuner_dbg("%s called\n", __func__);
-
-	if (p->mode == V4L2_TUNER_RADIO) {
-		type |= FM;
-		if (priv->ctrl.input1)
-			type |= INPUT1;
-		return generic_set_freq(fe, (625l * p->frequency) / 10,
-				V4L2_TUNER_RADIO, type, 0, 0);
-	}
-
-	/* if std is not defined, choose one */
-	if (!p->std)
-		p->std = V4L2_STD_MN;
-
-	/* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */
-	if (!(p->std & V4L2_STD_MN))
-		type |= F8MHZ;
-
-	/* Add audio hack to std mask */
-	p->std |= parse_audio_std_option();
-
-	return generic_set_freq(fe, 62500l * p->frequency,
-				V4L2_TUNER_ANALOG_TV, type, p->std, 0);
-}
-
-static int xc2028_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 delsys = c->delivery_system;
-	u32 bw = c->bandwidth_hz;
-	struct xc2028_data *priv = fe->tuner_priv;
-	int rc;
-	unsigned int       type = 0;
-	u16                demod = 0;
-
-	tuner_dbg("%s called\n", __func__);
-
-	rc = check_device_status(priv);
-	if (rc < 0)
-		return rc;
-
-	switch (delsys) {
-	case SYS_DVBT:
-	case SYS_DVBT2:
-		/*
-		 * The only countries with 6MHz seem to be Taiwan/Uruguay.
-		 * Both seem to require QAM firmware for OFDM decoding
-		 * Tested in Taiwan by Terry Wu <terrywu2009@gmail.com>
-		 */
-		if (bw <= 6000000)
-			type |= QAM;
-
-		switch (priv->ctrl.type) {
-		case XC2028_D2633:
-			type |= D2633;
-			break;
-		case XC2028_D2620:
-			type |= D2620;
-			break;
-		case XC2028_AUTO:
-		default:
-			/* Zarlink seems to need D2633 */
-			if (priv->ctrl.demod == XC3028_FE_ZARLINK456)
-				type |= D2633;
-			else
-				type |= D2620;
-		}
-		break;
-	case SYS_ATSC:
-		/* The only ATSC firmware (at least on v2.7) is D2633 */
-		type |= ATSC | D2633;
-		break;
-	/* DVB-S and pure QAM (FE_QAM) are not supported */
-	default:
-		return -EINVAL;
-	}
-
-	if (bw <= 6000000) {
-		type |= DTV6;
-		priv->ctrl.vhfbw7 = 0;
-		priv->ctrl.uhfbw8 = 0;
-	} else if (bw <= 7000000) {
-		if (c->frequency < 470000000)
-			priv->ctrl.vhfbw7 = 1;
-		else
-			priv->ctrl.uhfbw8 = 0;
-		type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7;
-		type |= F8MHZ;
-	} else {
-		if (c->frequency < 470000000)
-			priv->ctrl.vhfbw7 = 0;
-		else
-			priv->ctrl.uhfbw8 = 1;
-		type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8;
-		type |= F8MHZ;
-	}
-
-	/* All S-code tables need a 200kHz shift */
-	if (priv->ctrl.demod) {
-		demod = priv->ctrl.demod;
-
-		/*
-		 * Newer firmwares require a 200 kHz offset only for ATSC
-		 */
-		if (type == ATSC || priv->firm_version < 0x0302)
-			demod += 200;
-		/*
-		 * The DTV7 S-code table needs a 700 kHz shift.
-		 *
-		 * DTV7 is only used in Australia.  Germany or Italy may also
-		 * use this firmware after initialization, but a tune to a UHF
-		 * channel should then cause DTV78 to be used.
-		 *
-		 * Unfortunately, on real-field tests, the s-code offset
-		 * didn't work as expected, as reported by
-		 * Robert Lowery <rglowery@exemail.com.au>
-		 */
-	}
-
-	return generic_set_freq(fe, c->frequency,
-				V4L2_TUNER_DIGITAL_TV, type, 0, demod);
-}
-
-static int xc2028_sleep(struct dvb_frontend *fe)
-{
-	struct xc2028_data *priv = fe->tuner_priv;
-	int rc;
-
-	rc = check_device_status(priv);
-	if (rc < 0)
-		return rc;
-
-	/* Avoid firmware reload on slow devices or if PM disabled */
-	if (no_poweroff || priv->ctrl.disable_power_mgmt)
-		return 0;
-
-	tuner_dbg("Putting xc2028/3028 into poweroff mode.\n");
-	if (debug > 1) {
-		tuner_dbg("Printing sleep stack trace:\n");
-		dump_stack();
-	}
-
-	mutex_lock(&priv->lock);
-
-	if (priv->firm_version < 0x0202)
-		rc = send_seq(priv, {0x00, XREG_POWER_DOWN, 0x00, 0x00});
-	else
-		rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00});
-
-	priv->state = XC2028_SLEEP;
-
-	mutex_unlock(&priv->lock);
-
-	return rc;
-}
-
-static int xc2028_dvb_release(struct dvb_frontend *fe)
-{
-	struct xc2028_data *priv = fe->tuner_priv;
-
-	tuner_dbg("%s called\n", __func__);
-
-	mutex_lock(&xc2028_list_mutex);
-
-	/* only perform final cleanup if this is the last instance */
-	if (hybrid_tuner_report_instance_count(priv) == 1) {
-		free_firmware(priv);
-		kfree(priv->ctrl.fname);
-		priv->ctrl.fname = NULL;
-	}
-
-	if (priv)
-		hybrid_tuner_release_state(priv);
-
-	mutex_unlock(&xc2028_list_mutex);
-
-	fe->tuner_priv = NULL;
-
-	return 0;
-}
-
-static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct xc2028_data *priv = fe->tuner_priv;
-	int rc;
-
-	tuner_dbg("%s called\n", __func__);
-
-	rc = check_device_status(priv);
-	if (rc < 0)
-		return rc;
-
-	*frequency = priv->frequency;
-
-	return 0;
-}
-
-static void load_firmware_cb(const struct firmware *fw,
-			     void *context)
-{
-	struct dvb_frontend *fe = context;
-	struct xc2028_data *priv = fe->tuner_priv;
-	int rc;
-
-	tuner_dbg("request_firmware_nowait(): %s\n", fw ? "OK" : "error");
-	if (!fw) {
-		tuner_err("Could not load firmware %s.\n", priv->fname);
-		priv->state = XC2028_NODEV;
-		return;
-	}
-
-	rc = load_all_firmwares(fe, fw);
-
-	release_firmware(fw);
-
-	if (rc < 0)
-		return;
-	priv->state = XC2028_SLEEP;
-}
-
-static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
-{
-	struct xc2028_data *priv = fe->tuner_priv;
-	struct xc2028_ctrl *p    = priv_cfg;
-	int                 rc   = 0;
-
-	tuner_dbg("%s called\n", __func__);
-
-	mutex_lock(&priv->lock);
-
-	/*
-	 * Copy the config data.
-	 * For the firmware name, keep a local copy of the string,
-	 * in order to avoid troubles during device release.
-	 */
-	if (priv->ctrl.fname)
-		kfree(priv->ctrl.fname);
-	memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
-	if (p->fname) {
-		priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
-		if (priv->ctrl.fname == NULL)
-			rc = -ENOMEM;
-	}
-
-	/*
-	 * If firmware name changed, frees firmware. As free_firmware will
-	 * reset the status to NO_FIRMWARE, this forces a new request_firmware
-	 */
-	if (!firmware_name[0] && p->fname &&
-	    priv->fname && strcmp(p->fname, priv->fname))
-		free_firmware(priv);
-
-	if (priv->ctrl.max_len < 9)
-		priv->ctrl.max_len = 13;
-
-	if (priv->state == XC2028_NO_FIRMWARE) {
-		if (!firmware_name[0])
-			priv->fname = priv->ctrl.fname;
-		else
-			priv->fname = firmware_name;
-
-		rc = request_firmware_nowait(THIS_MODULE, 1,
-					     priv->fname,
-					     priv->i2c_props.adap->dev.parent,
-					     GFP_KERNEL,
-					     fe, load_firmware_cb);
-		if (rc < 0) {
-			tuner_err("Failed to request firmware %s\n",
-				  priv->fname);
-			priv->state = XC2028_NODEV;
-		}
-		priv->state = XC2028_WAITING_FIRMWARE;
-	}
-	mutex_unlock(&priv->lock);
-
-	return rc;
-}
-
-static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
-	.info = {
-		 .name = "Xceive XC3028",
-		 .frequency_min = 42000000,
-		 .frequency_max = 864000000,
-		 .frequency_step = 50000,
-		 },
-
-	.set_config	   = xc2028_set_config,
-	.set_analog_params = xc2028_set_analog_freq,
-	.release           = xc2028_dvb_release,
-	.get_frequency     = xc2028_get_frequency,
-	.get_rf_strength   = xc2028_signal,
-	.get_afc           = xc2028_get_afc,
-	.set_params        = xc2028_set_params,
-	.sleep             = xc2028_sleep,
-};
-
-struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
-				   struct xc2028_config *cfg)
-{
-	struct xc2028_data *priv;
-	int instance;
-
-	if (debug)
-		printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n");
-
-	if (NULL == cfg)
-		return NULL;
-
-	if (!fe) {
-		printk(KERN_ERR "xc2028: No frontend!\n");
-		return NULL;
-	}
-
-	mutex_lock(&xc2028_list_mutex);
-
-	instance = hybrid_tuner_request_state(struct xc2028_data, priv,
-					      hybrid_tuner_instance_list,
-					      cfg->i2c_adap, cfg->i2c_addr,
-					      "xc2028");
-	switch (instance) {
-	case 0:
-		/* memory allocation failure */
-		goto fail;
-		break;
-	case 1:
-		/* new tuner instance */
-		priv->ctrl.max_len = 13;
-
-		mutex_init(&priv->lock);
-
-		fe->tuner_priv = priv;
-		break;
-	case 2:
-		/* existing tuner instance */
-		fe->tuner_priv = priv;
-		break;
-	}
-
-	memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
-	       sizeof(xc2028_dvb_tuner_ops));
-
-	tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner");
-
-	if (cfg->ctrl)
-		xc2028_set_config(fe, cfg->ctrl);
-
-	mutex_unlock(&xc2028_list_mutex);
-
-	return fe;
-fail:
-	mutex_unlock(&xc2028_list_mutex);
-
-	xc2028_dvb_release(fe);
-	return NULL;
-}
-
-EXPORT_SYMBOL(xc2028_attach);
-
-MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver");
-MODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE);
-MODULE_FIRMWARE(XC3028L_DEFAULT_FIRMWARE);
diff --git a/drivers/media/common/tuners/tuner-xc2028.h b/drivers/media/common/tuners/tuner-xc2028.h
deleted file mode 100644
index 9ebfb2d..0000000
--- a/drivers/media/common/tuners/tuner-xc2028.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* tuner-xc2028
- *
- * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org)
- * This code is placed under the terms of the GNU General Public License v2
- */
-
-#ifndef __TUNER_XC2028_H__
-#define __TUNER_XC2028_H__
-
-#include "dvb_frontend.h"
-
-#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw"
-#define XC3028L_DEFAULT_FIRMWARE "xc3028L-v36.fw"
-
-/*      Dmoduler		IF (kHz) */
-#define	XC3028_FE_DEFAULT	0		/* Don't load SCODE */
-#define XC3028_FE_LG60		6000
-#define	XC3028_FE_ATI638	6380
-#define	XC3028_FE_OREN538	5380
-#define	XC3028_FE_OREN36	3600
-#define	XC3028_FE_TOYOTA388	3880
-#define	XC3028_FE_TOYOTA794	7940
-#define	XC3028_FE_DIBCOM52	5200
-#define	XC3028_FE_ZARLINK456	4560
-#define	XC3028_FE_CHINA		5200
-
-enum firmware_type {
-	XC2028_AUTO = 0,        /* By default, auto-detects */
-	XC2028_D2633,
-	XC2028_D2620,
-};
-
-struct xc2028_ctrl {
-	char			*fname;
-	int			max_len;
-	int			msleep;
-	unsigned int		scode_table;
-	unsigned int		mts   :1;
-	unsigned int		input1:1;
-	unsigned int		vhfbw7:1;
-	unsigned int		uhfbw8:1;
-	unsigned int		disable_power_mgmt:1;
-	unsigned int            read_not_reliable:1;
-	unsigned int		demod;
-	enum firmware_type	type:2;
-};
-
-struct xc2028_config {
-	struct i2c_adapter *i2c_adap;
-	u8 		   i2c_addr;
-	struct xc2028_ctrl *ctrl;
-};
-
-/* xc2028 commands for callback */
-#define XC2028_TUNER_RESET	0
-#define XC2028_RESET_CLK	1
-#define XC2028_I2C_FLUSH	2
-
-#if defined(CONFIG_MEDIA_TUNER_XC2028) || (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE))
-extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
-					  struct xc2028_config *cfg);
-#else
-static inline struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
-						 struct xc2028_config *cfg)
-{
-	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
-	       __func__);
-	return NULL;
-}
-#endif
-
-#endif /* __TUNER_XC2028_H__ */
diff --git a/drivers/media/common/tuners/xc4000.c b/drivers/media/common/tuners/xc4000.c
deleted file mode 100644
index 6839711..0000000
--- a/drivers/media/common/tuners/xc4000.c
+++ /dev/null
@@ -1,1758 +0,0 @@
-/*
- *  Driver for Xceive XC4000 "QAM/8VSB single chip tuner"
- *
- *  Copyright (c) 2007 Xceive Corporation
- *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
- *  Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
- *  Copyright (c) 2009 Davide Ferri <d.ferri@zero11.it>
- *  Copyright (c) 2010 Istvan Varga <istvan_v@mailbox.hu>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/videodev2.h>
-#include <linux/delay.h>
-#include <linux/dvb/frontend.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <asm/unaligned.h>
-
-#include "dvb_frontend.h"
-
-#include "xc4000.h"
-#include "tuner-i2c.h"
-#include "tuner-xc2028-types.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Debugging level (0 to 2, default: 0 (off)).");
-
-static int no_poweroff;
-module_param(no_poweroff, int, 0644);
-MODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, "
-	"0 (default): use device-specific default mode).");
-
-static int audio_std;
-module_param(audio_std, int, 0644);
-MODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly "
-	"needs to know what audio standard is needed for some video standards "
-	"with audio A2 or NICAM. The valid settings are a sum of:\n"
-	" 1: use NICAM/B or A2/B instead of NICAM/A or A2/A\n"
-	" 2: use A2 instead of NICAM or BTSC\n"
-	" 4: use SECAM/K3 instead of K1\n"
-	" 8: use PAL-D/K audio for SECAM-D/K\n"
-	"16: use FM radio input 1 instead of input 2\n"
-	"32: use mono audio (the lower three bits are ignored)");
-
-static char firmware_name[30];
-module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
-MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
-	"default firmware name.");
-
-static DEFINE_MUTEX(xc4000_list_mutex);
-static LIST_HEAD(hybrid_tuner_instance_list);
-
-#define dprintk(level, fmt, arg...) if (debug >= level) \
-	printk(KERN_INFO "%s: " fmt, "xc4000", ## arg)
-
-/* struct for storing firmware table */
-struct firmware_description {
-	unsigned int  type;
-	v4l2_std_id   id;
-	__u16         int_freq;
-	unsigned char *ptr;
-	unsigned int  size;
-};
-
-struct firmware_properties {
-	unsigned int	type;
-	v4l2_std_id	id;
-	v4l2_std_id	std_req;
-	__u16		int_freq;
-	unsigned int	scode_table;
-	int		scode_nr;
-};
-
-struct xc4000_priv {
-	struct tuner_i2c_props i2c_props;
-	struct list_head hybrid_tuner_instance_list;
-	struct firmware_description *firm;
-	int	firm_size;
-	u32	if_khz;
-	u32	freq_hz;
-	u32	bandwidth;
-	u8	video_standard;
-	u8	rf_mode;
-	u8	default_pm;
-	u8	dvb_amplitude;
-	u8	set_smoothedcvbs;
-	u8	ignore_i2c_write_errors;
-	__u16	firm_version;
-	struct firmware_properties cur_fw;
-	__u16	hwmodel;
-	__u16	hwvers;
-	struct mutex	lock;
-};
-
-#define XC4000_AUDIO_STD_B		 1
-#define XC4000_AUDIO_STD_A2		 2
-#define XC4000_AUDIO_STD_K3		 4
-#define XC4000_AUDIO_STD_L		 8
-#define XC4000_AUDIO_STD_INPUT1		16
-#define XC4000_AUDIO_STD_MONO		32
-
-#define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.fw"
-
-/* Misc Defines */
-#define MAX_TV_STANDARD			24
-#define XC_MAX_I2C_WRITE_LENGTH		64
-#define XC_POWERED_DOWN			0x80000000U
-
-/* Signal Types */
-#define XC_RF_MODE_AIR			0
-#define XC_RF_MODE_CABLE		1
-
-/* Product id */
-#define XC_PRODUCT_ID_FW_NOT_LOADED	0x2000
-#define XC_PRODUCT_ID_XC4000		0x0FA0
-#define XC_PRODUCT_ID_XC4100		0x1004
-
-/* Registers (Write-only) */
-#define XREG_INIT         0x00
-#define XREG_VIDEO_MODE   0x01
-#define XREG_AUDIO_MODE   0x02
-#define XREG_RF_FREQ      0x03
-#define XREG_D_CODE       0x04
-#define XREG_DIRECTSITTING_MODE 0x05
-#define XREG_SEEK_MODE    0x06
-#define XREG_POWER_DOWN   0x08
-#define XREG_SIGNALSOURCE 0x0A
-#define XREG_SMOOTHEDCVBS 0x0E
-#define XREG_AMPLITUDE    0x10
-
-/* Registers (Read-only) */
-#define XREG_ADC_ENV      0x00
-#define XREG_QUALITY      0x01
-#define XREG_FRAME_LINES  0x02
-#define XREG_HSYNC_FREQ   0x03
-#define XREG_LOCK         0x04
-#define XREG_FREQ_ERROR   0x05
-#define XREG_SNR          0x06
-#define XREG_VERSION      0x07
-#define XREG_PRODUCT_ID   0x08
-#define XREG_SIGNAL_LEVEL 0x0A
-#define XREG_NOISE_LEVEL  0x0B
-
-/*
-   Basic firmware description. This will remain with
-   the driver for documentation purposes.
-
-   This represents an I2C firmware file encoded as a
-   string of unsigned char. Format is as follows:
-
-   char[0  ]=len0_MSB  -> len = len_MSB * 256 + len_LSB
-   char[1  ]=len0_LSB  -> length of first write transaction
-   char[2  ]=data0 -> first byte to be sent
-   char[3  ]=data1
-   char[4  ]=data2
-   char[   ]=...
-   char[M  ]=dataN  -> last byte to be sent
-   char[M+1]=len1_MSB  -> len = len_MSB * 256 + len_LSB
-   char[M+2]=len1_LSB  -> length of second write transaction
-   char[M+3]=data0
-   char[M+4]=data1
-   ...
-   etc.
-
-   The [len] value should be interpreted as follows:
-
-   len= len_MSB _ len_LSB
-   len=1111_1111_1111_1111   : End of I2C_SEQUENCE
-   len=0000_0000_0000_0000   : Reset command: Do hardware reset
-   len=0NNN_NNNN_NNNN_NNNN   : Normal transaction: number of bytes = {1:32767)
-   len=1WWW_WWWW_WWWW_WWWW   : Wait command: wait for {1:32767} ms
-
-   For the RESET and WAIT commands, the two following bytes will contain
-   immediately the length of the following transaction.
-*/
-
-struct XC_TV_STANDARD {
-	const char  *Name;
-	u16	    audio_mode;
-	u16	    video_mode;
-	u16	    int_freq;
-};
-
-/* Tuner standards */
-#define XC4000_MN_NTSC_PAL_BTSC		0
-#define XC4000_MN_NTSC_PAL_A2		1
-#define XC4000_MN_NTSC_PAL_EIAJ		2
-#define XC4000_MN_NTSC_PAL_Mono		3
-#define XC4000_BG_PAL_A2		4
-#define XC4000_BG_PAL_NICAM		5
-#define XC4000_BG_PAL_MONO		6
-#define XC4000_I_PAL_NICAM		7
-#define XC4000_I_PAL_NICAM_MONO		8
-#define XC4000_DK_PAL_A2		9
-#define XC4000_DK_PAL_NICAM		10
-#define XC4000_DK_PAL_MONO		11
-#define XC4000_DK_SECAM_A2DK1		12
-#define XC4000_DK_SECAM_A2LDK3		13
-#define XC4000_DK_SECAM_A2MONO		14
-#define XC4000_DK_SECAM_NICAM		15
-#define XC4000_L_SECAM_NICAM		16
-#define XC4000_LC_SECAM_NICAM		17
-#define XC4000_DTV6			18
-#define XC4000_DTV8			19
-#define XC4000_DTV7_8			20
-#define XC4000_DTV7			21
-#define XC4000_FM_Radio_INPUT2		22
-#define XC4000_FM_Radio_INPUT1		23
-
-static struct XC_TV_STANDARD xc4000_standard[MAX_TV_STANDARD] = {
-	{"M/N-NTSC/PAL-BTSC",	0x0000, 0x80A0, 4500},
-	{"M/N-NTSC/PAL-A2",	0x0000, 0x80A0, 4600},
-	{"M/N-NTSC/PAL-EIAJ",	0x0040, 0x80A0, 4500},
-	{"M/N-NTSC/PAL-Mono",	0x0078, 0x80A0, 4500},
-	{"B/G-PAL-A2",		0x0000, 0x8159, 5640},
-	{"B/G-PAL-NICAM",	0x0004, 0x8159, 5740},
-	{"B/G-PAL-MONO",	0x0078, 0x8159, 5500},
-	{"I-PAL-NICAM",		0x0080, 0x8049, 6240},
-	{"I-PAL-NICAM-MONO",	0x0078, 0x8049, 6000},
-	{"D/K-PAL-A2",		0x0000, 0x8049, 6380},
-	{"D/K-PAL-NICAM",	0x0080, 0x8049, 6200},
-	{"D/K-PAL-MONO",	0x0078, 0x8049, 6500},
-	{"D/K-SECAM-A2 DK1",	0x0000, 0x8049, 6340},
-	{"D/K-SECAM-A2 L/DK3",	0x0000, 0x8049, 6000},
-	{"D/K-SECAM-A2 MONO",	0x0078, 0x8049, 6500},
-	{"D/K-SECAM-NICAM",	0x0080, 0x8049, 6200},
-	{"L-SECAM-NICAM",	0x8080, 0x0009, 6200},
-	{"L'-SECAM-NICAM",	0x8080, 0x4009, 6200},
-	{"DTV6",		0x00C0, 0x8002,    0},
-	{"DTV8",		0x00C0, 0x800B,    0},
-	{"DTV7/8",		0x00C0, 0x801B,    0},
-	{"DTV7",		0x00C0, 0x8007,    0},
-	{"FM Radio-INPUT2",	0x0008, 0x9800, 10700},
-	{"FM Radio-INPUT1",	0x0008, 0x9000, 10700}
-};
-
-static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val);
-static int xc4000_tuner_reset(struct dvb_frontend *fe);
-static void xc_debug_dump(struct xc4000_priv *priv);
-
-static int xc_send_i2c_data(struct xc4000_priv *priv, u8 *buf, int len)
-{
-	struct i2c_msg msg = { .addr = priv->i2c_props.addr,
-			       .flags = 0, .buf = buf, .len = len };
-	if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
-		if (priv->ignore_i2c_write_errors == 0) {
-			printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n",
-			       len);
-			if (len == 4) {
-				printk(KERN_ERR "bytes %02x %02x %02x %02x\n", buf[0],
-				       buf[1], buf[2], buf[3]);
-			}
-			return -EREMOTEIO;
-		}
-	}
-	return 0;
-}
-
-static int xc4000_tuner_reset(struct dvb_frontend *fe)
-{
-	struct xc4000_priv *priv = fe->tuner_priv;
-	int ret;
-
-	dprintk(1, "%s()\n", __func__);
-
-	if (fe->callback) {
-		ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
-					   fe->dvb->priv :
-					   priv->i2c_props.adap->algo_data,
-					   DVB_FRONTEND_COMPONENT_TUNER,
-					   XC4000_TUNER_RESET, 0);
-		if (ret) {
-			printk(KERN_ERR "xc4000: reset failed\n");
-			return -EREMOTEIO;
-		}
-	} else {
-		printk(KERN_ERR "xc4000: no tuner reset callback function, "
-				"fatal\n");
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int xc_write_reg(struct xc4000_priv *priv, u16 regAddr, u16 i2cData)
-{
-	u8 buf[4];
-	int result;
-
-	buf[0] = (regAddr >> 8) & 0xFF;
-	buf[1] = regAddr & 0xFF;
-	buf[2] = (i2cData >> 8) & 0xFF;
-	buf[3] = i2cData & 0xFF;
-	result = xc_send_i2c_data(priv, buf, 4);
-
-	return result;
-}
-
-static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
-{
-	struct xc4000_priv *priv = fe->tuner_priv;
-
-	int i, nbytes_to_send, result;
-	unsigned int len, pos, index;
-	u8 buf[XC_MAX_I2C_WRITE_LENGTH];
-
-	index = 0;
-	while ((i2c_sequence[index] != 0xFF) ||
-		(i2c_sequence[index + 1] != 0xFF)) {
-		len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
-		if (len == 0x0000) {
-			/* RESET command */
-			/* NOTE: this is ignored, as the reset callback was */
-			/* already called by check_firmware() */
-			index += 2;
-		} else if (len & 0x8000) {
-			/* WAIT command */
-			msleep(len & 0x7FFF);
-			index += 2;
-		} else {
-			/* Send i2c data whilst ensuring individual transactions
-			 * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
-			 */
-			index += 2;
-			buf[0] = i2c_sequence[index];
-			buf[1] = i2c_sequence[index + 1];
-			pos = 2;
-			while (pos < len) {
-				if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2)
-					nbytes_to_send =
-						XC_MAX_I2C_WRITE_LENGTH;
-				else
-					nbytes_to_send = (len - pos + 2);
-				for (i = 2; i < nbytes_to_send; i++) {
-					buf[i] = i2c_sequence[index + pos +
-						i - 2];
-				}
-				result = xc_send_i2c_data(priv, buf,
-					nbytes_to_send);
-
-				if (result != 0)
-					return result;
-
-				pos += nbytes_to_send - 2;
-			}
-			index += len;
-		}
-	}
-	return 0;
-}
-
-static int xc_set_tv_standard(struct xc4000_priv *priv,
-	u16 video_mode, u16 audio_mode)
-{
-	int ret;
-	dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode);
-	dprintk(1, "%s() Standard = %s\n",
-		__func__,
-		xc4000_standard[priv->video_standard].Name);
-
-	/* Don't complain when the request fails because of i2c stretching */
-	priv->ignore_i2c_write_errors = 1;
-
-	ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode);
-	if (ret == 0)
-		ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode);
-
-	priv->ignore_i2c_write_errors = 0;
-
-	return ret;
-}
-
-static int xc_set_signal_source(struct xc4000_priv *priv, u16 rf_mode)
-{
-	dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
-		rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
-
-	if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) {
-		rf_mode = XC_RF_MODE_CABLE;
-		printk(KERN_ERR
-			"%s(), Invalid mode, defaulting to CABLE",
-			__func__);
-	}
-	return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
-}
-
-static const struct dvb_tuner_ops xc4000_tuner_ops;
-
-static int xc_set_rf_frequency(struct xc4000_priv *priv, u32 freq_hz)
-{
-	u16 freq_code;
-
-	dprintk(1, "%s(%u)\n", __func__, freq_hz);
-
-	if ((freq_hz > xc4000_tuner_ops.info.frequency_max) ||
-	    (freq_hz < xc4000_tuner_ops.info.frequency_min))
-		return -EINVAL;
-
-	freq_code = (u16)(freq_hz / 15625);
-
-	/* WAS: Starting in firmware version 1.1.44, Xceive recommends using the
-	   FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
-	   only be used for fast scanning for channel lock) */
-	/* WAS: XREG_FINERFREQ */
-	return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
-}
-
-static int xc_get_adc_envelope(struct xc4000_priv *priv, u16 *adc_envelope)
-{
-	return xc4000_readreg(priv, XREG_ADC_ENV, adc_envelope);
-}
-
-static int xc_get_frequency_error(struct xc4000_priv *priv, u32 *freq_error_hz)
-{
-	int result;
-	u16 regData;
-	u32 tmp;
-
-	result = xc4000_readreg(priv, XREG_FREQ_ERROR, &regData);
-	if (result != 0)
-		return result;
-
-	tmp = (u32)regData & 0xFFFFU;
-	tmp = (tmp < 0x8000U ? tmp : 0x10000U - tmp);
-	(*freq_error_hz) = tmp * 15625;
-	return result;
-}
-
-static int xc_get_lock_status(struct xc4000_priv *priv, u16 *lock_status)
-{
-	return xc4000_readreg(priv, XREG_LOCK, lock_status);
-}
-
-static int xc_get_version(struct xc4000_priv *priv,
-	u8 *hw_majorversion, u8 *hw_minorversion,
-	u8 *fw_majorversion, u8 *fw_minorversion)
-{
-	u16 data;
-	int result;
-
-	result = xc4000_readreg(priv, XREG_VERSION, &data);
-	if (result != 0)
-		return result;
-
-	(*hw_majorversion) = (data >> 12) & 0x0F;
-	(*hw_minorversion) = (data >>  8) & 0x0F;
-	(*fw_majorversion) = (data >>  4) & 0x0F;
-	(*fw_minorversion) = data & 0x0F;
-
-	return 0;
-}
-
-static int xc_get_hsync_freq(struct xc4000_priv *priv, u32 *hsync_freq_hz)
-{
-	u16 regData;
-	int result;
-
-	result = xc4000_readreg(priv, XREG_HSYNC_FREQ, &regData);
-	if (result != 0)
-		return result;
-
-	(*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
-	return result;
-}
-
-static int xc_get_frame_lines(struct xc4000_priv *priv, u16 *frame_lines)
-{
-	return xc4000_readreg(priv, XREG_FRAME_LINES, frame_lines);
-}
-
-static int xc_get_quality(struct xc4000_priv *priv, u16 *quality)
-{
-	return xc4000_readreg(priv, XREG_QUALITY, quality);
-}
-
-static int xc_get_signal_level(struct xc4000_priv *priv, u16 *signal)
-{
-	return xc4000_readreg(priv, XREG_SIGNAL_LEVEL, signal);
-}
-
-static int xc_get_noise_level(struct xc4000_priv *priv, u16 *noise)
-{
-	return xc4000_readreg(priv, XREG_NOISE_LEVEL, noise);
-}
-
-static u16 xc_wait_for_lock(struct xc4000_priv *priv)
-{
-	u16	lock_state = 0;
-	int	watchdog_count = 40;
-
-	while ((lock_state == 0) && (watchdog_count > 0)) {
-		xc_get_lock_status(priv, &lock_state);
-		if (lock_state != 1) {
-			msleep(5);
-			watchdog_count--;
-		}
-	}
-	return lock_state;
-}
-
-static int xc_tune_channel(struct xc4000_priv *priv, u32 freq_hz)
-{
-	int	found = 1;
-	int	result;
-
-	dprintk(1, "%s(%u)\n", __func__, freq_hz);
-
-	/* Don't complain when the request fails because of i2c stretching */
-	priv->ignore_i2c_write_errors = 1;
-	result = xc_set_rf_frequency(priv, freq_hz);
-	priv->ignore_i2c_write_errors = 0;
-
-	if (result != 0)
-		return 0;
-
-	/* wait for lock only in analog TV mode */
-	if ((priv->cur_fw.type & (FM | DTV6 | DTV7 | DTV78 | DTV8)) == 0) {
-		if (xc_wait_for_lock(priv) != 1)
-			found = 0;
-	}
-
-	/* Wait for stats to stabilize.
-	 * Frame Lines needs two frame times after initial lock
-	 * before it is valid.
-	 */
-	msleep(debug ? 100 : 10);
-
-	if (debug)
-		xc_debug_dump(priv);
-
-	return found;
-}
-
-static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val)
-{
-	u8 buf[2] = { reg >> 8, reg & 0xff };
-	u8 bval[2] = { 0, 0 };
-	struct i2c_msg msg[2] = {
-		{ .addr = priv->i2c_props.addr,
-			.flags = 0, .buf = &buf[0], .len = 2 },
-		{ .addr = priv->i2c_props.addr,
-			.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
-	};
-
-	if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
-		printk(KERN_ERR "xc4000: I2C read failed\n");
-		return -EREMOTEIO;
-	}
-
-	*val = (bval[0] << 8) | bval[1];
-	return 0;
-}
-
-#define dump_firm_type(t)	dump_firm_type_and_int_freq(t, 0)
-static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
-{
-	 if (type & BASE)
-		printk(KERN_CONT "BASE ");
-	 if (type & INIT1)
-		printk(KERN_CONT "INIT1 ");
-	 if (type & F8MHZ)
-		printk(KERN_CONT "F8MHZ ");
-	 if (type & MTS)
-		printk(KERN_CONT "MTS ");
-	 if (type & D2620)
-		printk(KERN_CONT "D2620 ");
-	 if (type & D2633)
-		printk(KERN_CONT "D2633 ");
-	 if (type & DTV6)
-		printk(KERN_CONT "DTV6 ");
-	 if (type & QAM)
-		printk(KERN_CONT "QAM ");
-	 if (type & DTV7)
-		printk(KERN_CONT "DTV7 ");
-	 if (type & DTV78)
-		printk(KERN_CONT "DTV78 ");
-	 if (type & DTV8)
-		printk(KERN_CONT "DTV8 ");
-	 if (type & FM)
-		printk(KERN_CONT "FM ");
-	 if (type & INPUT1)
-		printk(KERN_CONT "INPUT1 ");
-	 if (type & LCD)
-		printk(KERN_CONT "LCD ");
-	 if (type & NOGD)
-		printk(KERN_CONT "NOGD ");
-	 if (type & MONO)
-		printk(KERN_CONT "MONO ");
-	 if (type & ATSC)
-		printk(KERN_CONT "ATSC ");
-	 if (type & IF)
-		printk(KERN_CONT "IF ");
-	 if (type & LG60)
-		printk(KERN_CONT "LG60 ");
-	 if (type & ATI638)
-		printk(KERN_CONT "ATI638 ");
-	 if (type & OREN538)
-		printk(KERN_CONT "OREN538 ");
-	 if (type & OREN36)
-		printk(KERN_CONT "OREN36 ");
-	 if (type & TOYOTA388)
-		printk(KERN_CONT "TOYOTA388 ");
-	 if (type & TOYOTA794)
-		printk(KERN_CONT "TOYOTA794 ");
-	 if (type & DIBCOM52)
-		printk(KERN_CONT "DIBCOM52 ");
-	 if (type & ZARLINK456)
-		printk(KERN_CONT "ZARLINK456 ");
-	 if (type & CHINA)
-		printk(KERN_CONT "CHINA ");
-	 if (type & F6MHZ)
-		printk(KERN_CONT "F6MHZ ");
-	 if (type & INPUT2)
-		printk(KERN_CONT "INPUT2 ");
-	 if (type & SCODE)
-		printk(KERN_CONT "SCODE ");
-	 if (type & HAS_IF)
-		printk(KERN_CONT "HAS_IF_%d ", int_freq);
-}
-
-static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
-			 v4l2_std_id *id)
-{
-	struct xc4000_priv *priv = fe->tuner_priv;
-	int		i, best_i = -1;
-	unsigned int	best_nr_diffs = 255U;
-
-	if (!priv->firm) {
-		printk(KERN_ERR "Error! firmware not loaded\n");
-		return -EINVAL;
-	}
-
-	if (((type & ~SCODE) == 0) && (*id == 0))
-		*id = V4L2_STD_PAL;
-
-	/* Seek for generic video standard match */
-	for (i = 0; i < priv->firm_size; i++) {
-		v4l2_std_id	id_diff_mask =
-			(priv->firm[i].id ^ (*id)) & (*id);
-		unsigned int	type_diff_mask =
-			(priv->firm[i].type ^ type)
-			& (BASE_TYPES | DTV_TYPES | LCD | NOGD | MONO | SCODE);
-		unsigned int	nr_diffs;
-
-		if (type_diff_mask
-		    & (BASE | INIT1 | FM | DTV6 | DTV7 | DTV78 | DTV8 | SCODE))
-			continue;
-
-		nr_diffs = hweight64(id_diff_mask) + hweight32(type_diff_mask);
-		if (!nr_diffs)	/* Supports all the requested standards */
-			goto found;
-
-		if (nr_diffs < best_nr_diffs) {
-			best_nr_diffs = nr_diffs;
-			best_i = i;
-		}
-	}
-
-	/* FIXME: Would make sense to seek for type "hint" match ? */
-	if (best_i < 0) {
-		i = -ENOENT;
-		goto ret;
-	}
-
-	if (best_nr_diffs > 0U) {
-		printk(KERN_WARNING
-		       "Selecting best matching firmware (%u bits differ) for "
-		       "type=(%x), id %016llx:\n",
-		       best_nr_diffs, type, (unsigned long long)*id);
-		i = best_i;
-	}
-
-found:
-	*id = priv->firm[i].id;
-
-ret:
-	if (debug) {
-		printk(KERN_DEBUG "%s firmware for type=",
-		       (i < 0) ? "Can't find" : "Found");
-		dump_firm_type(type);
-		printk(KERN_DEBUG "(%x), id %016llx.\n", type, (unsigned long long)*id);
-	}
-	return i;
-}
-
-static int load_firmware(struct dvb_frontend *fe, unsigned int type,
-			 v4l2_std_id *id)
-{
-	struct xc4000_priv *priv = fe->tuner_priv;
-	int                pos, rc;
-	unsigned char      *p;
-
-	pos = seek_firmware(fe, type, id);
-	if (pos < 0)
-		return pos;
-
-	p = priv->firm[pos].ptr;
-
-	/* Don't complain when the request fails because of i2c stretching */
-	priv->ignore_i2c_write_errors = 1;
-
-	rc = xc_load_i2c_sequence(fe, p);
-
-	priv->ignore_i2c_write_errors = 0;
-
-	return rc;
-}
-
-static int xc4000_fwupload(struct dvb_frontend *fe)
-{
-	struct xc4000_priv *priv = fe->tuner_priv;
-	const struct firmware *fw   = NULL;
-	const unsigned char   *p, *endp;
-	int                   rc = 0;
-	int		      n, n_array;
-	char		      name[33];
-	const char	      *fname;
-
-	if (firmware_name[0] != '\0')
-		fname = firmware_name;
-	else
-		fname = XC4000_DEFAULT_FIRMWARE;
-
-	dprintk(1, "Reading firmware %s\n", fname);
-	rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent);
-	if (rc < 0) {
-		if (rc == -ENOENT)
-			printk(KERN_ERR "Error: firmware %s not found.\n", fname);
-		else
-			printk(KERN_ERR "Error %d while requesting firmware %s\n",
-			       rc, fname);
-
-		return rc;
-	}
-	p = fw->data;
-	endp = p + fw->size;
-
-	if (fw->size < sizeof(name) - 1 + 2 + 2) {
-		printk(KERN_ERR "Error: firmware file %s has invalid size!\n",
-		       fname);
-		goto corrupt;
-	}
-
-	memcpy(name, p, sizeof(name) - 1);
-	name[sizeof(name) - 1] = '\0';
-	p += sizeof(name) - 1;
-
-	priv->firm_version = get_unaligned_le16(p);
-	p += 2;
-
-	n_array = get_unaligned_le16(p);
-	p += 2;
-
-	dprintk(1, "Loading %d firmware images from %s, type: %s, ver %d.%d\n",
-		n_array, fname, name,
-		priv->firm_version >> 8, priv->firm_version & 0xff);
-
-	priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL);
-	if (priv->firm == NULL) {
-		printk(KERN_ERR "Not enough memory to load firmware file.\n");
-		rc = -ENOMEM;
-		goto done;
-	}
-	priv->firm_size = n_array;
-
-	n = -1;
-	while (p < endp) {
-		__u32 type, size;
-		v4l2_std_id id;
-		__u16 int_freq = 0;
-
-		n++;
-		if (n >= n_array) {
-			printk(KERN_ERR "More firmware images in file than "
-			       "were expected!\n");
-			goto corrupt;
-		}
-
-		/* Checks if there's enough bytes to read */
-		if (endp - p < sizeof(type) + sizeof(id) + sizeof(size))
-			goto header;
-
-		type = get_unaligned_le32(p);
-		p += sizeof(type);
-
-		id = get_unaligned_le64(p);
-		p += sizeof(id);
-
-		if (type & HAS_IF) {
-			int_freq = get_unaligned_le16(p);
-			p += sizeof(int_freq);
-			if (endp - p < sizeof(size))
-				goto header;
-		}
-
-		size = get_unaligned_le32(p);
-		p += sizeof(size);
-
-		if (!size || size > endp - p) {
-			printk(KERN_ERR "Firmware type (%x), id %llx is corrupted (size=%d, expected %d)\n",
-			       type, (unsigned long long)id,
-			       (unsigned)(endp - p), size);
-			goto corrupt;
-		}
-
-		priv->firm[n].ptr = kzalloc(size, GFP_KERNEL);
-		if (priv->firm[n].ptr == NULL) {
-			printk(KERN_ERR "Not enough memory to load firmware file.\n");
-			rc = -ENOMEM;
-			goto done;
-		}
-
-		if (debug) {
-			printk(KERN_DEBUG "Reading firmware type ");
-			dump_firm_type_and_int_freq(type, int_freq);
-			printk(KERN_DEBUG "(%x), id %llx, size=%d.\n",
-			       type, (unsigned long long)id, size);
-		}
-
-		memcpy(priv->firm[n].ptr, p, size);
-		priv->firm[n].type = type;
-		priv->firm[n].id   = id;
-		priv->firm[n].size = size;
-		priv->firm[n].int_freq = int_freq;
-
-		p += size;
-	}
-
-	if (n + 1 != priv->firm_size) {
-		printk(KERN_ERR "Firmware file is incomplete!\n");
-		goto corrupt;
-	}
-
-	goto done;
-
-header:
-	printk(KERN_ERR "Firmware header is incomplete!\n");
-corrupt:
-	rc = -EINVAL;
-	printk(KERN_ERR "Error: firmware file is corrupted!\n");
-
-done:
-	release_firmware(fw);
-	if (rc == 0)
-		dprintk(1, "Firmware files loaded.\n");
-
-	return rc;
-}
-
-static int load_scode(struct dvb_frontend *fe, unsigned int type,
-			 v4l2_std_id *id, __u16 int_freq, int scode)
-{
-	struct xc4000_priv *priv = fe->tuner_priv;
-	int		pos, rc;
-	unsigned char	*p;
-	u8		scode_buf[13];
-	u8		indirect_mode[5];
-
-	dprintk(1, "%s called int_freq=%d\n", __func__, int_freq);
-
-	if (!int_freq) {
-		pos = seek_firmware(fe, type, id);
-		if (pos < 0)
-			return pos;
-	} else {
-		for (pos = 0; pos < priv->firm_size; pos++) {
-			if ((priv->firm[pos].int_freq == int_freq) &&
-			    (priv->firm[pos].type & HAS_IF))
-				break;
-		}
-		if (pos == priv->firm_size)
-			return -ENOENT;
-	}
-
-	p = priv->firm[pos].ptr;
-
-	if (priv->firm[pos].size != 12 * 16 || scode >= 16)
-		return -EINVAL;
-	p += 12 * scode;
-
-	if (debug) {
-		tuner_info("Loading SCODE for type=");
-		dump_firm_type_and_int_freq(priv->firm[pos].type,
-					    priv->firm[pos].int_freq);
-		printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type,
-		       (unsigned long long)*id);
-	}
-
-	scode_buf[0] = 0x00;
-	memcpy(&scode_buf[1], p, 12);
-
-	/* Enter direct-mode */
-	rc = xc_write_reg(priv, XREG_DIRECTSITTING_MODE, 0);
-	if (rc < 0) {
-		printk(KERN_ERR "failed to put device into direct mode!\n");
-		return -EIO;
-	}
-
-	rc = xc_send_i2c_data(priv, scode_buf, 13);
-	if (rc != 0) {
-		/* Even if the send failed, make sure we set back to indirect
-		   mode */
-		printk(KERN_ERR "Failed to set scode %d\n", rc);
-	}
-
-	/* Switch back to indirect-mode */
-	memset(indirect_mode, 0, sizeof(indirect_mode));
-	indirect_mode[4] = 0x88;
-	xc_send_i2c_data(priv, indirect_mode, sizeof(indirect_mode));
-	msleep(10);
-
-	return 0;
-}
-
-static int check_firmware(struct dvb_frontend *fe, unsigned int type,
-			  v4l2_std_id std, __u16 int_freq)
-{
-	struct xc4000_priv         *priv = fe->tuner_priv;
-	struct firmware_properties new_fw;
-	int			   rc = 0, is_retry = 0;
-	u16			   hwmodel;
-	v4l2_std_id		   std0;
-	u8			   hw_major, hw_minor, fw_major, fw_minor;
-
-	dprintk(1, "%s called\n", __func__);
-
-	if (!priv->firm) {
-		rc = xc4000_fwupload(fe);
-		if (rc < 0)
-			return rc;
-	}
-
-retry:
-	new_fw.type = type;
-	new_fw.id = std;
-	new_fw.std_req = std;
-	new_fw.scode_table = SCODE;
-	new_fw.scode_nr = 0;
-	new_fw.int_freq = int_freq;
-
-	dprintk(1, "checking firmware, user requested type=");
-	if (debug) {
-		dump_firm_type(new_fw.type);
-		printk(KERN_CONT "(%x), id %016llx, ", new_fw.type,
-		       (unsigned long long)new_fw.std_req);
-		if (!int_freq)
-			printk(KERN_CONT "scode_tbl ");
-		else
-			printk(KERN_CONT "int_freq %d, ", new_fw.int_freq);
-		printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr);
-	}
-
-	/* No need to reload base firmware if it matches */
-	if (priv->cur_fw.type & BASE) {
-		dprintk(1, "BASE firmware not changed.\n");
-		goto skip_base;
-	}
-
-	/* Updating BASE - forget about all currently loaded firmware */
-	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
-
-	/* Reset is needed before loading firmware */
-	rc = xc4000_tuner_reset(fe);
-	if (rc < 0)
-		goto fail;
-
-	/* BASE firmwares are all std0 */
-	std0 = 0;
-	rc = load_firmware(fe, BASE, &std0);
-	if (rc < 0) {
-		printk(KERN_ERR "Error %d while loading base firmware\n", rc);
-		goto fail;
-	}
-
-	/* Load INIT1, if needed */
-	dprintk(1, "Load init1 firmware, if exists\n");
-
-	rc = load_firmware(fe, BASE | INIT1, &std0);
-	if (rc == -ENOENT)
-		rc = load_firmware(fe, BASE | INIT1, &std0);
-	if (rc < 0 && rc != -ENOENT) {
-		tuner_err("Error %d while loading init1 firmware\n",
-			  rc);
-		goto fail;
-	}
-
-skip_base:
-	/*
-	 * No need to reload standard specific firmware if base firmware
-	 * was not reloaded and requested video standards have not changed.
-	 */
-	if (priv->cur_fw.type == (BASE | new_fw.type) &&
-	    priv->cur_fw.std_req == std) {
-		dprintk(1, "Std-specific firmware already loaded.\n");
-		goto skip_std_specific;
-	}
-
-	/* Reloading std-specific firmware forces a SCODE update */
-	priv->cur_fw.scode_table = 0;
-
-	/* Load the standard firmware */
-	rc = load_firmware(fe, new_fw.type, &new_fw.id);
-
-	if (rc < 0)
-		goto fail;
-
-skip_std_specific:
-	if (priv->cur_fw.scode_table == new_fw.scode_table &&
-	    priv->cur_fw.scode_nr == new_fw.scode_nr) {
-		dprintk(1, "SCODE firmware already loaded.\n");
-		goto check_device;
-	}
-
-	/* Load SCODE firmware, if exists */
-	rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
-			new_fw.int_freq, new_fw.scode_nr);
-	if (rc != 0)
-		dprintk(1, "load scode failed %d\n", rc);
-
-check_device:
-	rc = xc4000_readreg(priv, XREG_PRODUCT_ID, &hwmodel);
-
-	if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major,
-			   &fw_minor) != 0) {
-		printk(KERN_ERR "Unable to read tuner registers.\n");
-		goto fail;
-	}
-
-	dprintk(1, "Device is Xceive %d version %d.%d, "
-		"firmware version %d.%d\n",
-		hwmodel, hw_major, hw_minor, fw_major, fw_minor);
-
-	/* Check firmware version against what we downloaded. */
-	if (priv->firm_version != ((fw_major << 8) | fw_minor)) {
-		printk(KERN_WARNING
-		       "Incorrect readback of firmware version %d.%d.\n",
-		       fw_major, fw_minor);
-		goto fail;
-	}
-
-	/* Check that the tuner hardware model remains consistent over time. */
-	if (priv->hwmodel == 0 &&
-	    (hwmodel == XC_PRODUCT_ID_XC4000 ||
-	     hwmodel == XC_PRODUCT_ID_XC4100)) {
-		priv->hwmodel = hwmodel;
-		priv->hwvers = (hw_major << 8) | hw_minor;
-	} else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
-		   priv->hwvers != ((hw_major << 8) | hw_minor)) {
-		printk(KERN_WARNING
-		       "Read invalid device hardware information - tuner "
-		       "hung?\n");
-		goto fail;
-	}
-
-	memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
-
-	/*
-	 * By setting BASE in cur_fw.type only after successfully loading all
-	 * firmwares, we can:
-	 * 1. Identify that BASE firmware with type=0 has been loaded;
-	 * 2. Tell whether BASE firmware was just changed the next time through.
-	 */
-	priv->cur_fw.type |= BASE;
-
-	return 0;
-
-fail:
-	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
-	if (!is_retry) {
-		msleep(50);
-		is_retry = 1;
-		dprintk(1, "Retrying firmware load\n");
-		goto retry;
-	}
-
-	if (rc == -ENOENT)
-		rc = -EINVAL;
-	return rc;
-}
-
-static void xc_debug_dump(struct xc4000_priv *priv)
-{
-	u16	adc_envelope;
-	u32	freq_error_hz = 0;
-	u16	lock_status;
-	u32	hsync_freq_hz = 0;
-	u16	frame_lines;
-	u16	quality;
-	u16	signal = 0;
-	u16	noise = 0;
-	u8	hw_majorversion = 0, hw_minorversion = 0;
-	u8	fw_majorversion = 0, fw_minorversion = 0;
-
-	xc_get_adc_envelope(priv, &adc_envelope);
-	dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
-
-	xc_get_frequency_error(priv, &freq_error_hz);
-	dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
-
-	xc_get_lock_status(priv, &lock_status);
-	dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
-		lock_status);
-
-	xc_get_version(priv, &hw_majorversion, &hw_minorversion,
-		       &fw_majorversion, &fw_minorversion);
-	dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
-		hw_majorversion, hw_minorversion,
-		fw_majorversion, fw_minorversion);
-
-	if (priv->video_standard < XC4000_DTV6) {
-		xc_get_hsync_freq(priv, &hsync_freq_hz);
-		dprintk(1, "*** Horizontal sync frequency = %d Hz\n",
-			hsync_freq_hz);
-
-		xc_get_frame_lines(priv, &frame_lines);
-		dprintk(1, "*** Frame lines = %d\n", frame_lines);
-	}
-
-	xc_get_quality(priv, &quality);
-	dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
-
-	xc_get_signal_level(priv, &signal);
-	dprintk(1, "*** Signal level = -%ddB (%d)\n", signal >> 8, signal);
-
-	xc_get_noise_level(priv, &noise);
-	dprintk(1, "*** Noise level = %ddB (%d)\n", noise >> 8, noise);
-}
-
-static int xc4000_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 delsys = c->delivery_system;
-	u32 bw = c->bandwidth_hz;
-	struct xc4000_priv *priv = fe->tuner_priv;
-	unsigned int type;
-	int	ret = -EREMOTEIO;
-
-	dprintk(1, "%s() frequency=%d (Hz)\n", __func__, c->frequency);
-
-	mutex_lock(&priv->lock);
-
-	switch (delsys) {
-	case SYS_ATSC:
-		dprintk(1, "%s() VSB modulation\n", __func__);
-		priv->rf_mode = XC_RF_MODE_AIR;
-		priv->freq_hz = c->frequency - 1750000;
-		priv->video_standard = XC4000_DTV6;
-		type = DTV6;
-		break;
-	case SYS_DVBC_ANNEX_B:
-		dprintk(1, "%s() QAM modulation\n", __func__);
-		priv->rf_mode = XC_RF_MODE_CABLE;
-		priv->freq_hz = c->frequency - 1750000;
-		priv->video_standard = XC4000_DTV6;
-		type = DTV6;
-		break;
-	case SYS_DVBT:
-	case SYS_DVBT2:
-		dprintk(1, "%s() OFDM\n", __func__);
-		if (bw == 0) {
-			if (c->frequency < 400000000) {
-				priv->freq_hz = c->frequency - 2250000;
-			} else {
-				priv->freq_hz = c->frequency - 2750000;
-			}
-			priv->video_standard = XC4000_DTV7_8;
-			type = DTV78;
-		} else if (bw <= 6000000) {
-			priv->video_standard = XC4000_DTV6;
-			priv->freq_hz = c->frequency - 1750000;
-			type = DTV6;
-		} else if (bw <= 7000000) {
-			priv->video_standard = XC4000_DTV7;
-			priv->freq_hz = c->frequency - 2250000;
-			type = DTV7;
-		} else {
-			priv->video_standard = XC4000_DTV8;
-			priv->freq_hz = c->frequency - 2750000;
-			type = DTV8;
-		}
-		priv->rf_mode = XC_RF_MODE_AIR;
-		break;
-	default:
-		printk(KERN_ERR "xc4000 delivery system not supported!\n");
-		ret = -EINVAL;
-		goto fail;
-	}
-
-	dprintk(1, "%s() frequency=%d (compensated)\n",
-		__func__, priv->freq_hz);
-
-	/* Make sure the correct firmware type is loaded */
-	if (check_firmware(fe, type, 0, priv->if_khz) != 0)
-		goto fail;
-
-	priv->bandwidth = c->bandwidth_hz;
-
-	ret = xc_set_signal_source(priv, priv->rf_mode);
-	if (ret != 0) {
-		printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n",
-		       priv->rf_mode);
-		goto fail;
-	} else {
-		u16	video_mode, audio_mode;
-		video_mode = xc4000_standard[priv->video_standard].video_mode;
-		audio_mode = xc4000_standard[priv->video_standard].audio_mode;
-		if (type == DTV6 && priv->firm_version != 0x0102)
-			video_mode |= 0x0001;
-		ret = xc_set_tv_standard(priv, video_mode, audio_mode);
-		if (ret != 0) {
-			printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n");
-			/* DJH - do not return when it fails... */
-			/* goto fail; */
-		}
-	}
-
-	if (xc_write_reg(priv, XREG_D_CODE, 0) == 0)
-		ret = 0;
-	if (priv->dvb_amplitude != 0) {
-		if (xc_write_reg(priv, XREG_AMPLITUDE,
-				 (priv->firm_version != 0x0102 ||
-				  priv->dvb_amplitude != 134 ?
-				  priv->dvb_amplitude : 132)) != 0)
-			ret = -EREMOTEIO;
-	}
-	if (priv->set_smoothedcvbs != 0) {
-		if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0)
-			ret = -EREMOTEIO;
-	}
-	if (ret != 0) {
-		printk(KERN_ERR "xc4000: setting registers failed\n");
-		/* goto fail; */
-	}
-
-	xc_tune_channel(priv, priv->freq_hz);
-
-	ret = 0;
-
-fail:
-	mutex_unlock(&priv->lock);
-
-	return ret;
-}
-
-static int xc4000_set_analog_params(struct dvb_frontend *fe,
-	struct analog_parameters *params)
-{
-	struct xc4000_priv *priv = fe->tuner_priv;
-	unsigned int type = 0;
-	int	ret = -EREMOTEIO;
-
-	if (params->mode == V4L2_TUNER_RADIO) {
-		dprintk(1, "%s() frequency=%d (in units of 62.5Hz)\n",
-			__func__, params->frequency);
-
-		mutex_lock(&priv->lock);
-
-		params->std = 0;
-		priv->freq_hz = params->frequency * 125L / 2;
-
-		if (audio_std & XC4000_AUDIO_STD_INPUT1) {
-			priv->video_standard = XC4000_FM_Radio_INPUT1;
-			type = FM | INPUT1;
-		} else {
-			priv->video_standard = XC4000_FM_Radio_INPUT2;
-			type = FM | INPUT2;
-		}
-
-		goto tune_channel;
-	}
-
-	dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
-		__func__, params->frequency);
-
-	mutex_lock(&priv->lock);
-
-	/* params->frequency is in units of 62.5khz */
-	priv->freq_hz = params->frequency * 62500;
-
-	params->std &= V4L2_STD_ALL;
-	/* if std is not defined, choose one */
-	if (!params->std)
-		params->std = V4L2_STD_PAL_BG;
-
-	if (audio_std & XC4000_AUDIO_STD_MONO)
-		type = MONO;
-
-	if (params->std & V4L2_STD_MN) {
-		params->std = V4L2_STD_MN;
-		if (audio_std & XC4000_AUDIO_STD_MONO) {
-			priv->video_standard = XC4000_MN_NTSC_PAL_Mono;
-		} else if (audio_std & XC4000_AUDIO_STD_A2) {
-			params->std |= V4L2_STD_A2;
-			priv->video_standard = XC4000_MN_NTSC_PAL_A2;
-		} else {
-			params->std |= V4L2_STD_BTSC;
-			priv->video_standard = XC4000_MN_NTSC_PAL_BTSC;
-		}
-		goto tune_channel;
-	}
-
-	if (params->std & V4L2_STD_PAL_BG) {
-		params->std = V4L2_STD_PAL_BG;
-		if (audio_std & XC4000_AUDIO_STD_MONO) {
-			priv->video_standard = XC4000_BG_PAL_MONO;
-		} else if (!(audio_std & XC4000_AUDIO_STD_A2)) {
-			if (!(audio_std & XC4000_AUDIO_STD_B)) {
-				params->std |= V4L2_STD_NICAM_A;
-				priv->video_standard = XC4000_BG_PAL_NICAM;
-			} else {
-				params->std |= V4L2_STD_NICAM_B;
-				priv->video_standard = XC4000_BG_PAL_NICAM;
-			}
-		} else {
-			if (!(audio_std & XC4000_AUDIO_STD_B)) {
-				params->std |= V4L2_STD_A2_A;
-				priv->video_standard = XC4000_BG_PAL_A2;
-			} else {
-				params->std |= V4L2_STD_A2_B;
-				priv->video_standard = XC4000_BG_PAL_A2;
-			}
-		}
-		goto tune_channel;
-	}
-
-	if (params->std & V4L2_STD_PAL_I) {
-		/* default to NICAM audio standard */
-		params->std = V4L2_STD_PAL_I | V4L2_STD_NICAM;
-		if (audio_std & XC4000_AUDIO_STD_MONO)
-			priv->video_standard = XC4000_I_PAL_NICAM_MONO;
-		else
-			priv->video_standard = XC4000_I_PAL_NICAM;
-		goto tune_channel;
-	}
-
-	if (params->std & V4L2_STD_PAL_DK) {
-		params->std = V4L2_STD_PAL_DK;
-		if (audio_std & XC4000_AUDIO_STD_MONO) {
-			priv->video_standard = XC4000_DK_PAL_MONO;
-		} else if (audio_std & XC4000_AUDIO_STD_A2) {
-			params->std |= V4L2_STD_A2;
-			priv->video_standard = XC4000_DK_PAL_A2;
-		} else {
-			params->std |= V4L2_STD_NICAM;
-			priv->video_standard = XC4000_DK_PAL_NICAM;
-		}
-		goto tune_channel;
-	}
-
-	if (params->std & V4L2_STD_SECAM_DK) {
-		/* default to A2 audio standard */
-		params->std = V4L2_STD_SECAM_DK | V4L2_STD_A2;
-		if (audio_std & XC4000_AUDIO_STD_L) {
-			type = 0;
-			priv->video_standard = XC4000_DK_SECAM_NICAM;
-		} else if (audio_std & XC4000_AUDIO_STD_MONO) {
-			priv->video_standard = XC4000_DK_SECAM_A2MONO;
-		} else if (audio_std & XC4000_AUDIO_STD_K3) {
-			params->std |= V4L2_STD_SECAM_K3;
-			priv->video_standard = XC4000_DK_SECAM_A2LDK3;
-		} else {
-			priv->video_standard = XC4000_DK_SECAM_A2DK1;
-		}
-		goto tune_channel;
-	}
-
-	if (params->std & V4L2_STD_SECAM_L) {
-		/* default to NICAM audio standard */
-		type = 0;
-		params->std = V4L2_STD_SECAM_L | V4L2_STD_NICAM;
-		priv->video_standard = XC4000_L_SECAM_NICAM;
-		goto tune_channel;
-	}
-
-	if (params->std & V4L2_STD_SECAM_LC) {
-		/* default to NICAM audio standard */
-		type = 0;
-		params->std = V4L2_STD_SECAM_LC | V4L2_STD_NICAM;
-		priv->video_standard = XC4000_LC_SECAM_NICAM;
-		goto tune_channel;
-	}
-
-tune_channel:
-	/* FIXME: it could be air. */
-	priv->rf_mode = XC_RF_MODE_CABLE;
-
-	if (check_firmware(fe, type, params->std,
-			   xc4000_standard[priv->video_standard].int_freq) != 0)
-		goto fail;
-
-	ret = xc_set_signal_source(priv, priv->rf_mode);
-	if (ret != 0) {
-		printk(KERN_ERR
-		       "xc4000: xc_set_signal_source(%d) failed\n",
-		       priv->rf_mode);
-		goto fail;
-	} else {
-		u16	video_mode, audio_mode;
-		video_mode = xc4000_standard[priv->video_standard].video_mode;
-		audio_mode = xc4000_standard[priv->video_standard].audio_mode;
-		if (priv->video_standard < XC4000_BG_PAL_A2) {
-			if (type & NOGD)
-				video_mode &= 0xFF7F;
-		} else if (priv->video_standard < XC4000_I_PAL_NICAM) {
-			if (priv->firm_version == 0x0102)
-				video_mode &= 0xFEFF;
-			if (audio_std & XC4000_AUDIO_STD_B)
-				video_mode |= 0x0080;
-		}
-		ret = xc_set_tv_standard(priv, video_mode, audio_mode);
-		if (ret != 0) {
-			printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n");
-			goto fail;
-		}
-	}
-
-	if (xc_write_reg(priv, XREG_D_CODE, 0) == 0)
-		ret = 0;
-	if (xc_write_reg(priv, XREG_AMPLITUDE, 1) != 0)
-		ret = -EREMOTEIO;
-	if (priv->set_smoothedcvbs != 0) {
-		if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0)
-			ret = -EREMOTEIO;
-	}
-	if (ret != 0) {
-		printk(KERN_ERR "xc4000: setting registers failed\n");
-		goto fail;
-	}
-
-	xc_tune_channel(priv, priv->freq_hz);
-
-	ret = 0;
-
-fail:
-	mutex_unlock(&priv->lock);
-
-	return ret;
-}
-
-static int xc4000_get_signal(struct dvb_frontend *fe, u16 *strength)
-{
-	struct xc4000_priv *priv = fe->tuner_priv;
-	u16 value = 0;
-	int rc;
-
-	mutex_lock(&priv->lock);
-	rc = xc4000_readreg(priv, XREG_SIGNAL_LEVEL, &value);
-	mutex_unlock(&priv->lock);
-
-	if (rc < 0)
-		goto ret;
-
-	/* Informations from real testing of DVB-T and radio part,
-	   coeficient for one dB is 0xff.
-	 */
-	tuner_dbg("Signal strength: -%ddB (%05d)\n", value >> 8, value);
-
-	/* all known digital modes */
-	if ((priv->video_standard == XC4000_DTV6) ||
-	    (priv->video_standard == XC4000_DTV7) ||
-	    (priv->video_standard == XC4000_DTV7_8) ||
-	    (priv->video_standard == XC4000_DTV8))
-		goto digital;
-
-	/* Analog mode has NOISE LEVEL important, signal
-	   depends only on gain of antenna and amplifiers,
-	   but it doesn't tell anything about real quality
-	   of reception.
-	 */
-	mutex_lock(&priv->lock);
-	rc = xc4000_readreg(priv, XREG_NOISE_LEVEL, &value);
-	mutex_unlock(&priv->lock);
-
-	tuner_dbg("Noise level: %ddB (%05d)\n", value >> 8, value);
-
-	/* highest noise level: 32dB */
-	if (value >= 0x2000) {
-		value = 0;
-	} else {
-		value = ~value << 3;
-	}
-
-	goto ret;
-
-	/* Digital mode has SIGNAL LEVEL important and real
-	   noise level is stored in demodulator registers.
-	 */
-digital:
-	/* best signal: -50dB */
-	if (value <= 0x3200) {
-		value = 0xffff;
-	/* minimum: -114dB - should be 0x7200 but real zero is 0x713A */
-	} else if (value >= 0x713A) {
-		value = 0;
-	} else {
-		value = ~(value - 0x3200) << 2;
-	}
-
-ret:
-	*strength = value;
-
-	return rc;
-}
-
-static int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq)
-{
-	struct xc4000_priv *priv = fe->tuner_priv;
-
-	*freq = priv->freq_hz;
-
-	if (debug) {
-		mutex_lock(&priv->lock);
-		if ((priv->cur_fw.type
-		     & (BASE | FM | DTV6 | DTV7 | DTV78 | DTV8)) == BASE) {
-			u16	snr = 0;
-			if (xc4000_readreg(priv, XREG_SNR, &snr) == 0) {
-				mutex_unlock(&priv->lock);
-				dprintk(1, "%s() freq = %u, SNR = %d\n",
-					__func__, *freq, snr);
-				return 0;
-			}
-		}
-		mutex_unlock(&priv->lock);
-	}
-
-	dprintk(1, "%s()\n", __func__);
-
-	return 0;
-}
-
-static int xc4000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
-{
-	struct xc4000_priv *priv = fe->tuner_priv;
-	dprintk(1, "%s()\n", __func__);
-
-	*bw = priv->bandwidth;
-	return 0;
-}
-
-static int xc4000_get_status(struct dvb_frontend *fe, u32 *status)
-{
-	struct xc4000_priv *priv = fe->tuner_priv;
-	u16	lock_status = 0;
-
-	mutex_lock(&priv->lock);
-
-	if (priv->cur_fw.type & BASE)
-		xc_get_lock_status(priv, &lock_status);
-
-	*status = (lock_status == 1 ?
-		   TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO : 0);
-	if (priv->cur_fw.type & (DTV6 | DTV7 | DTV78 | DTV8))
-		*status &= (~TUNER_STATUS_STEREO);
-
-	mutex_unlock(&priv->lock);
-
-	dprintk(2, "%s() lock_status = %d\n", __func__, lock_status);
-
-	return 0;
-}
-
-static int xc4000_sleep(struct dvb_frontend *fe)
-{
-	struct xc4000_priv *priv = fe->tuner_priv;
-	int	ret = 0;
-
-	dprintk(1, "%s()\n", __func__);
-
-	mutex_lock(&priv->lock);
-
-	/* Avoid firmware reload on slow devices */
-	if ((no_poweroff == 2 ||
-	     (no_poweroff == 0 && priv->default_pm != 0)) &&
-	    (priv->cur_fw.type & BASE) != 0) {
-		/* force reset and firmware reload */
-		priv->cur_fw.type = XC_POWERED_DOWN;
-
-		if (xc_write_reg(priv, XREG_POWER_DOWN, 0) != 0) {
-			printk(KERN_ERR
-			       "xc4000: %s() unable to shutdown tuner\n",
-			       __func__);
-			ret = -EREMOTEIO;
-		}
-		msleep(20);
-	}
-
-	mutex_unlock(&priv->lock);
-
-	return ret;
-}
-
-static int xc4000_init(struct dvb_frontend *fe)
-{
-	dprintk(1, "%s()\n", __func__);
-
-	return 0;
-}
-
-static int xc4000_release(struct dvb_frontend *fe)
-{
-	struct xc4000_priv *priv = fe->tuner_priv;
-
-	dprintk(1, "%s()\n", __func__);
-
-	mutex_lock(&xc4000_list_mutex);
-
-	if (priv)
-		hybrid_tuner_release_state(priv);
-
-	mutex_unlock(&xc4000_list_mutex);
-
-	fe->tuner_priv = NULL;
-
-	return 0;
-}
-
-static const struct dvb_tuner_ops xc4000_tuner_ops = {
-	.info = {
-		.name           = "Xceive XC4000",
-		.frequency_min  =    1000000,
-		.frequency_max  = 1023000000,
-		.frequency_step =      50000,
-	},
-
-	.release	   = xc4000_release,
-	.init		   = xc4000_init,
-	.sleep		   = xc4000_sleep,
-
-	.set_params	   = xc4000_set_params,
-	.set_analog_params = xc4000_set_analog_params,
-	.get_frequency	   = xc4000_get_frequency,
-	.get_rf_strength   = xc4000_get_signal,
-	.get_bandwidth	   = xc4000_get_bandwidth,
-	.get_status	   = xc4000_get_status
-};
-
-struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
-				   struct i2c_adapter *i2c,
-				   struct xc4000_config *cfg)
-{
-	struct xc4000_priv *priv = NULL;
-	int	instance;
-	u16	id = 0;
-
-	dprintk(1, "%s(%d-%04x)\n", __func__,
-		i2c ? i2c_adapter_id(i2c) : -1,
-		cfg ? cfg->i2c_address : -1);
-
-	mutex_lock(&xc4000_list_mutex);
-
-	instance = hybrid_tuner_request_state(struct xc4000_priv, priv,
-					      hybrid_tuner_instance_list,
-					      i2c, cfg->i2c_address, "xc4000");
-	switch (instance) {
-	case 0:
-		goto fail;
-		break;
-	case 1:
-		/* new tuner instance */
-		priv->bandwidth = 6000000;
-		/* set default configuration */
-		priv->if_khz = 4560;
-		priv->default_pm = 0;
-		priv->dvb_amplitude = 134;
-		priv->set_smoothedcvbs = 1;
-		mutex_init(&priv->lock);
-		fe->tuner_priv = priv;
-		break;
-	default:
-		/* existing tuner instance */
-		fe->tuner_priv = priv;
-		break;
-	}
-
-	if (cfg->if_khz != 0) {
-		/* copy configuration if provided by the caller */
-		priv->if_khz = cfg->if_khz;
-		priv->default_pm = cfg->default_pm;
-		priv->dvb_amplitude = cfg->dvb_amplitude;
-		priv->set_smoothedcvbs = cfg->set_smoothedcvbs;
-	}
-
-	/* Check if firmware has been loaded. It is possible that another
-	   instance of the driver has loaded the firmware.
-	 */
-
-	if (instance == 1) {
-		if (xc4000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
-			goto fail;
-	} else {
-		id = ((priv->cur_fw.type & BASE) != 0 ?
-		      priv->hwmodel : XC_PRODUCT_ID_FW_NOT_LOADED);
-	}
-
-	switch (id) {
-	case XC_PRODUCT_ID_XC4000:
-	case XC_PRODUCT_ID_XC4100:
-		printk(KERN_INFO
-			"xc4000: Successfully identified at address 0x%02x\n",
-			cfg->i2c_address);
-		printk(KERN_INFO
-			"xc4000: Firmware has been loaded previously\n");
-		break;
-	case XC_PRODUCT_ID_FW_NOT_LOADED:
-		printk(KERN_INFO
-			"xc4000: Successfully identified at address 0x%02x\n",
-			cfg->i2c_address);
-		printk(KERN_INFO
-			"xc4000: Firmware has not been loaded previously\n");
-		break;
-	default:
-		printk(KERN_ERR
-			"xc4000: Device not found at addr 0x%02x (0x%x)\n",
-			cfg->i2c_address, id);
-		goto fail;
-	}
-
-	mutex_unlock(&xc4000_list_mutex);
-
-	memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops,
-		sizeof(struct dvb_tuner_ops));
-
-	if (instance == 1) {
-		int	ret;
-		mutex_lock(&priv->lock);
-		ret = xc4000_fwupload(fe);
-		mutex_unlock(&priv->lock);
-		if (ret != 0)
-			goto fail2;
-	}
-
-	return fe;
-fail:
-	mutex_unlock(&xc4000_list_mutex);
-fail2:
-	xc4000_release(fe);
-	return NULL;
-}
-EXPORT_SYMBOL(xc4000_attach);
-
-MODULE_AUTHOR("Steven Toth, Davide Ferri");
-MODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/xc4000.h b/drivers/media/common/tuners/xc4000.h
deleted file mode 100644
index e6a44d1..0000000
--- a/drivers/media/common/tuners/xc4000.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- *  Driver for Xceive XC4000 "QAM/8VSB single chip tuner"
- *
- *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __XC4000_H__
-#define __XC4000_H__
-
-#include <linux/firmware.h>
-
-struct dvb_frontend;
-struct i2c_adapter;
-
-struct xc4000_config {
-	u8	i2c_address;
-	/* if non-zero, power management is enabled by default */
-	u8	default_pm;
-	/* value to be written to XREG_AMPLITUDE in DVB-T mode (0: no write) */
-	u8	dvb_amplitude;
-	/* if non-zero, register 0x0E is set to filter analog TV video output */
-	u8	set_smoothedcvbs;
-	/* IF for DVB-T */
-	u32	if_khz;
-};
-
-/* xc4000 callback command */
-#define XC4000_TUNER_RESET		0
-
-/* For each bridge framework, when it attaches either analog or digital,
- * it has to store a reference back to its _core equivalent structure,
- * so that it can service the hardware by steering gpio's etc.
- * Each bridge implementation is different so cast devptr accordingly.
- * The xc4000 driver cares not for this value, other than ensuring
- * it's passed back to a bridge during tuner_callback().
- */
-
-#if defined(CONFIG_MEDIA_TUNER_XC4000) || (defined(CONFIG_MEDIA_TUNER_XC4000_MODULE) && defined(MODULE))
-extern struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
-					  struct i2c_adapter *i2c,
-					  struct xc4000_config *cfg);
-#else
-static inline struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
-						 struct i2c_adapter *i2c,
-						 struct xc4000_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
deleted file mode 100644
index 362a8d7..0000000
--- a/drivers/media/common/tuners/xc5000.c
+++ /dev/null
@@ -1,1265 +0,0 @@
-/*
- *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
- *
- *  Copyright (c) 2007 Xceive Corporation
- *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
- *  Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/videodev2.h>
-#include <linux/delay.h>
-#include <linux/dvb/frontend.h>
-#include <linux/i2c.h>
-
-#include "dvb_frontend.h"
-
-#include "xc5000.h"
-#include "tuner-i2c.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-static int no_poweroff;
-module_param(no_poweroff, int, 0644);
-MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
-	"\t\t1 keep device energized and with tuner ready all the times.\n"
-	"\t\tFaster, but consumes more power and keeps the device hotter");
-
-static DEFINE_MUTEX(xc5000_list_mutex);
-static LIST_HEAD(hybrid_tuner_instance_list);
-
-#define dprintk(level, fmt, arg...) if (debug >= level) \
-	printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
-
-struct xc5000_priv {
-	struct tuner_i2c_props i2c_props;
-	struct list_head hybrid_tuner_instance_list;
-
-	u32 if_khz;
-	u16 xtal_khz;
-	u32 freq_hz;
-	u32 bandwidth;
-	u8  video_standard;
-	u8  rf_mode;
-	u8  radio_input;
-
-	int chip_id;
-};
-
-/* Misc Defines */
-#define MAX_TV_STANDARD			24
-#define XC_MAX_I2C_WRITE_LENGTH		64
-
-/* Signal Types */
-#define XC_RF_MODE_AIR			0
-#define XC_RF_MODE_CABLE		1
-
-/* Result codes */
-#define XC_RESULT_SUCCESS		0
-#define XC_RESULT_RESET_FAILURE		1
-#define XC_RESULT_I2C_WRITE_FAILURE	2
-#define XC_RESULT_I2C_READ_FAILURE	3
-#define XC_RESULT_OUT_OF_RANGE		5
-
-/* Product id */
-#define XC_PRODUCT_ID_FW_NOT_LOADED	0x2000
-#define XC_PRODUCT_ID_FW_LOADED 	0x1388
-
-/* Registers */
-#define XREG_INIT         0x00
-#define XREG_VIDEO_MODE   0x01
-#define XREG_AUDIO_MODE   0x02
-#define XREG_RF_FREQ      0x03
-#define XREG_D_CODE       0x04
-#define XREG_IF_OUT       0x05
-#define XREG_SEEK_MODE    0x07
-#define XREG_POWER_DOWN   0x0A /* Obsolete */
-/* Set the output amplitude - SIF for analog, DTVP/DTVN for digital */
-#define XREG_OUTPUT_AMP   0x0B
-#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
-#define XREG_SMOOTHEDCVBS 0x0E
-#define XREG_XTALFREQ     0x0F
-#define XREG_FINERFREQ    0x10
-#define XREG_DDIMODE      0x11
-
-#define XREG_ADC_ENV      0x00
-#define XREG_QUALITY      0x01
-#define XREG_FRAME_LINES  0x02
-#define XREG_HSYNC_FREQ   0x03
-#define XREG_LOCK         0x04
-#define XREG_FREQ_ERROR   0x05
-#define XREG_SNR          0x06
-#define XREG_VERSION      0x07
-#define XREG_PRODUCT_ID   0x08
-#define XREG_BUSY         0x09
-#define XREG_BUILD        0x0D
-
-/*
-   Basic firmware description. This will remain with
-   the driver for documentation purposes.
-
-   This represents an I2C firmware file encoded as a
-   string of unsigned char. Format is as follows:
-
-   char[0  ]=len0_MSB  -> len = len_MSB * 256 + len_LSB
-   char[1  ]=len0_LSB  -> length of first write transaction
-   char[2  ]=data0 -> first byte to be sent
-   char[3  ]=data1
-   char[4  ]=data2
-   char[   ]=...
-   char[M  ]=dataN  -> last byte to be sent
-   char[M+1]=len1_MSB  -> len = len_MSB * 256 + len_LSB
-   char[M+2]=len1_LSB  -> length of second write transaction
-   char[M+3]=data0
-   char[M+4]=data1
-   ...
-   etc.
-
-   The [len] value should be interpreted as follows:
-
-   len= len_MSB _ len_LSB
-   len=1111_1111_1111_1111   : End of I2C_SEQUENCE
-   len=0000_0000_0000_0000   : Reset command: Do hardware reset
-   len=0NNN_NNNN_NNNN_NNNN   : Normal transaction: number of bytes = {1:32767)
-   len=1WWW_WWWW_WWWW_WWWW   : Wait command: wait for {1:32767} ms
-
-   For the RESET and WAIT commands, the two following bytes will contain
-   immediately the length of the following transaction.
-
-*/
-struct XC_TV_STANDARD {
-	char *Name;
-	u16 AudioMode;
-	u16 VideoMode;
-};
-
-/* Tuner standards */
-#define MN_NTSC_PAL_BTSC	0
-#define MN_NTSC_PAL_A2		1
-#define MN_NTSC_PAL_EIAJ	2
-#define MN_NTSC_PAL_Mono	3
-#define BG_PAL_A2		4
-#define BG_PAL_NICAM		5
-#define BG_PAL_MONO		6
-#define I_PAL_NICAM		7
-#define I_PAL_NICAM_MONO	8
-#define DK_PAL_A2		9
-#define DK_PAL_NICAM		10
-#define DK_PAL_MONO		11
-#define DK_SECAM_A2DK1		12
-#define DK_SECAM_A2LDK3 	13
-#define DK_SECAM_A2MONO 	14
-#define L_SECAM_NICAM		15
-#define LC_SECAM_NICAM		16
-#define DTV6			17
-#define DTV8			18
-#define DTV7_8			19
-#define DTV7			20
-#define FM_Radio_INPUT2 	21
-#define FM_Radio_INPUT1 	22
-#define FM_Radio_INPUT1_MONO	23
-
-static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
-	{"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
-	{"M/N-NTSC/PAL-A2",   0x0600, 0x8020},
-	{"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020},
-	{"M/N-NTSC/PAL-Mono", 0x0478, 0x8020},
-	{"B/G-PAL-A2",        0x0A00, 0x8049},
-	{"B/G-PAL-NICAM",     0x0C04, 0x8049},
-	{"B/G-PAL-MONO",      0x0878, 0x8059},
-	{"I-PAL-NICAM",       0x1080, 0x8009},
-	{"I-PAL-NICAM-MONO",  0x0E78, 0x8009},
-	{"D/K-PAL-A2",        0x1600, 0x8009},
-	{"D/K-PAL-NICAM",     0x0E80, 0x8009},
-	{"D/K-PAL-MONO",      0x1478, 0x8009},
-	{"D/K-SECAM-A2 DK1",  0x1200, 0x8009},
-	{"D/K-SECAM-A2 L/DK3", 0x0E00, 0x8009},
-	{"D/K-SECAM-A2 MONO", 0x1478, 0x8009},
-	{"L-SECAM-NICAM",     0x8E82, 0x0009},
-	{"L'-SECAM-NICAM",    0x8E82, 0x4009},
-	{"DTV6",              0x00C0, 0x8002},
-	{"DTV8",              0x00C0, 0x800B},
-	{"DTV7/8",            0x00C0, 0x801B},
-	{"DTV7",              0x00C0, 0x8007},
-	{"FM Radio-INPUT2",   0x9802, 0x9002},
-	{"FM Radio-INPUT1",   0x0208, 0x9002},
-	{"FM Radio-INPUT1_MONO", 0x0278, 0x9002}
-};
-
-
-struct xc5000_fw_cfg {
-	char *name;
-	u16 size;
-};
-
-#define XC5000A_FIRMWARE "dvb-fe-xc5000-1.6.114.fw"
-static const struct xc5000_fw_cfg xc5000a_1_6_114 = {
-	.name = XC5000A_FIRMWARE,
-	.size = 12401,
-};
-
-#define XC5000C_FIRMWARE "dvb-fe-xc5000c-41.024.5.fw"
-static const struct xc5000_fw_cfg xc5000c_41_024_5 = {
-	.name = XC5000C_FIRMWARE,
-	.size = 16497,
-};
-
-static inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id)
-{
-	switch (chip_id) {
-	default:
-	case XC5000A:
-		return &xc5000a_1_6_114;
-	case XC5000C:
-		return &xc5000c_41_024_5;
-	}
-}
-
-static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
-static int xc5000_is_firmware_loaded(struct dvb_frontend *fe);
-static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val);
-static int xc5000_TunerReset(struct dvb_frontend *fe);
-
-static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
-{
-	struct i2c_msg msg = { .addr = priv->i2c_props.addr,
-			       .flags = 0, .buf = buf, .len = len };
-
-	if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
-		printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len);
-		return XC_RESULT_I2C_WRITE_FAILURE;
-	}
-	return XC_RESULT_SUCCESS;
-}
-
-#if 0
-/* This routine is never used because the only time we read data from the
-   i2c bus is when we read registers, and we want that to be an atomic i2c
-   transaction in case we are on a multi-master bus */
-static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
-{
-	struct i2c_msg msg = { .addr = priv->i2c_props.addr,
-		.flags = I2C_M_RD, .buf = buf, .len = len };
-
-	if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
-		printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-#endif
-
-static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
-{
-	u8 buf[2] = { reg >> 8, reg & 0xff };
-	u8 bval[2] = { 0, 0 };
-	struct i2c_msg msg[2] = {
-		{ .addr = priv->i2c_props.addr,
-			.flags = 0, .buf = &buf[0], .len = 2 },
-		{ .addr = priv->i2c_props.addr,
-			.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
-	};
-
-	if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
-		printk(KERN_WARNING "xc5000: I2C read failed\n");
-		return -EREMOTEIO;
-	}
-
-	*val = (bval[0] << 8) | bval[1];
-	return XC_RESULT_SUCCESS;
-}
-
-static void xc_wait(int wait_ms)
-{
-	msleep(wait_ms);
-}
-
-static int xc5000_TunerReset(struct dvb_frontend *fe)
-{
-	struct xc5000_priv *priv = fe->tuner_priv;
-	int ret;
-
-	dprintk(1, "%s()\n", __func__);
-
-	if (fe->callback) {
-		ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
-					   fe->dvb->priv :
-					   priv->i2c_props.adap->algo_data,
-					   DVB_FRONTEND_COMPONENT_TUNER,
-					   XC5000_TUNER_RESET, 0);
-		if (ret) {
-			printk(KERN_ERR "xc5000: reset failed\n");
-			return XC_RESULT_RESET_FAILURE;
-		}
-	} else {
-		printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
-		return XC_RESULT_RESET_FAILURE;
-	}
-	return XC_RESULT_SUCCESS;
-}
-
-static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
-{
-	u8 buf[4];
-	int WatchDogTimer = 100;
-	int result;
-
-	buf[0] = (regAddr >> 8) & 0xFF;
-	buf[1] = regAddr & 0xFF;
-	buf[2] = (i2cData >> 8) & 0xFF;
-	buf[3] = i2cData & 0xFF;
-	result = xc_send_i2c_data(priv, buf, 4);
-	if (result == XC_RESULT_SUCCESS) {
-		/* wait for busy flag to clear */
-		while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) {
-			result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf);
-			if (result == XC_RESULT_SUCCESS) {
-				if ((buf[0] == 0) && (buf[1] == 0)) {
-					/* busy flag cleared */
-					break;
-				} else {
-					xc_wait(5); /* wait 5 ms */
-					WatchDogTimer--;
-				}
-			}
-		}
-	}
-	if (WatchDogTimer < 0)
-		result = XC_RESULT_I2C_WRITE_FAILURE;
-
-	return result;
-}
-
-static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
-{
-	struct xc5000_priv *priv = fe->tuner_priv;
-
-	int i, nbytes_to_send, result;
-	unsigned int len, pos, index;
-	u8 buf[XC_MAX_I2C_WRITE_LENGTH];
-
-	index = 0;
-	while ((i2c_sequence[index] != 0xFF) ||
-		(i2c_sequence[index + 1] != 0xFF)) {
-		len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
-		if (len == 0x0000) {
-			/* RESET command */
-			result = xc5000_TunerReset(fe);
-			index += 2;
-			if (result != XC_RESULT_SUCCESS)
-				return result;
-		} else if (len & 0x8000) {
-			/* WAIT command */
-			xc_wait(len & 0x7FFF);
-			index += 2;
-		} else {
-			/* Send i2c data whilst ensuring individual transactions
-			 * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
-			 */
-			index += 2;
-			buf[0] = i2c_sequence[index];
-			buf[1] = i2c_sequence[index + 1];
-			pos = 2;
-			while (pos < len) {
-				if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2)
-					nbytes_to_send =
-						XC_MAX_I2C_WRITE_LENGTH;
-				else
-					nbytes_to_send = (len - pos + 2);
-				for (i = 2; i < nbytes_to_send; i++) {
-					buf[i] = i2c_sequence[index + pos +
-						i - 2];
-				}
-				result = xc_send_i2c_data(priv, buf,
-					nbytes_to_send);
-
-				if (result != XC_RESULT_SUCCESS)
-					return result;
-
-				pos += nbytes_to_send - 2;
-			}
-			index += len;
-		}
-	}
-	return XC_RESULT_SUCCESS;
-}
-
-static int xc_initialize(struct xc5000_priv *priv)
-{
-	dprintk(1, "%s()\n", __func__);
-	return xc_write_reg(priv, XREG_INIT, 0);
-}
-
-static int xc_SetTVStandard(struct xc5000_priv *priv,
-	u16 VideoMode, u16 AudioMode)
-{
-	int ret;
-	dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, VideoMode, AudioMode);
-	dprintk(1, "%s() Standard = %s\n",
-		__func__,
-		XC5000_Standard[priv->video_standard].Name);
-
-	ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode);
-	if (ret == XC_RESULT_SUCCESS)
-		ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode);
-
-	return ret;
-}
-
-static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
-{
-	dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
-		rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
-
-	if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) {
-		rf_mode = XC_RF_MODE_CABLE;
-		printk(KERN_ERR
-			"%s(), Invalid mode, defaulting to CABLE",
-			__func__);
-	}
-	return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
-}
-
-static const struct dvb_tuner_ops xc5000_tuner_ops;
-
-static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
-{
-	u16 freq_code;
-
-	dprintk(1, "%s(%u)\n", __func__, freq_hz);
-
-	if ((freq_hz > xc5000_tuner_ops.info.frequency_max) ||
-		(freq_hz < xc5000_tuner_ops.info.frequency_min))
-		return XC_RESULT_OUT_OF_RANGE;
-
-	freq_code = (u16)(freq_hz / 15625);
-
-	/* Starting in firmware version 1.1.44, Xceive recommends using the
-	   FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
-	   only be used for fast scanning for channel lock) */
-	return xc_write_reg(priv, XREG_FINERFREQ, freq_code);
-}
-
-
-static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz)
-{
-	u32 freq_code = (freq_khz * 1024)/1000;
-	dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n",
-		__func__, freq_khz, freq_code);
-
-	return xc_write_reg(priv, XREG_IF_OUT, freq_code);
-}
-
-
-static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
-{
-	return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope);
-}
-
-static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
-{
-	int result;
-	u16 regData;
-	u32 tmp;
-
-	result = xc5000_readreg(priv, XREG_FREQ_ERROR, &regData);
-	if (result != XC_RESULT_SUCCESS)
-		return result;
-
-	tmp = (u32)regData;
-	(*freq_error_hz) = (tmp * 15625) / 1000;
-	return result;
-}
-
-static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status)
-{
-	return xc5000_readreg(priv, XREG_LOCK, lock_status);
-}
-
-static int xc_get_version(struct xc5000_priv *priv,
-	u8 *hw_majorversion, u8 *hw_minorversion,
-	u8 *fw_majorversion, u8 *fw_minorversion)
-{
-	u16 data;
-	int result;
-
-	result = xc5000_readreg(priv, XREG_VERSION, &data);
-	if (result != XC_RESULT_SUCCESS)
-		return result;
-
-	(*hw_majorversion) = (data >> 12) & 0x0F;
-	(*hw_minorversion) = (data >>  8) & 0x0F;
-	(*fw_majorversion) = (data >>  4) & 0x0F;
-	(*fw_minorversion) = data & 0x0F;
-
-	return 0;
-}
-
-static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev)
-{
-	return xc5000_readreg(priv, XREG_BUILD, buildrev);
-}
-
-static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
-{
-	u16 regData;
-	int result;
-
-	result = xc5000_readreg(priv, XREG_HSYNC_FREQ, &regData);
-	if (result != XC_RESULT_SUCCESS)
-		return result;
-
-	(*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
-	return result;
-}
-
-static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines)
-{
-	return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines);
-}
-
-static int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
-{
-	return xc5000_readreg(priv, XREG_QUALITY, quality);
-}
-
-static u16 WaitForLock(struct xc5000_priv *priv)
-{
-	u16 lockState = 0;
-	int watchDogCount = 40;
-
-	while ((lockState == 0) && (watchDogCount > 0)) {
-		xc_get_lock_status(priv, &lockState);
-		if (lockState != 1) {
-			xc_wait(5);
-			watchDogCount--;
-		}
-	}
-	return lockState;
-}
-
-#define XC_TUNE_ANALOG  0
-#define XC_TUNE_DIGITAL 1
-static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode)
-{
-	int found = 0;
-
-	dprintk(1, "%s(%u)\n", __func__, freq_hz);
-
-	if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
-		return 0;
-
-	if (mode == XC_TUNE_ANALOG) {
-		if (WaitForLock(priv) == 1)
-			found = 1;
-	}
-
-	return found;
-}
-
-static int xc_set_xtal(struct dvb_frontend *fe)
-{
-	struct xc5000_priv *priv = fe->tuner_priv;
-	int ret = XC_RESULT_SUCCESS;
-
-	switch (priv->chip_id) {
-	default:
-	case XC5000A:
-		/* 32.000 MHz xtal is default */
-		break;
-	case XC5000C:
-		switch (priv->xtal_khz) {
-		default:
-		case 32000:
-			/* 32.000 MHz xtal is default */
-			break;
-		case 31875:
-			/* 31.875 MHz xtal configuration */
-			ret = xc_write_reg(priv, 0x000f, 0x8081);
-			break;
-		}
-		break;
-	}
-	return ret;
-}
-
-static int xc5000_fwupload(struct dvb_frontend *fe)
-{
-	struct xc5000_priv *priv = fe->tuner_priv;
-	const struct firmware *fw;
-	int ret;
-	const struct xc5000_fw_cfg *desired_fw =
-		xc5000_assign_firmware(priv->chip_id);
-
-	/* request the firmware, this will block and timeout */
-	printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
-		desired_fw->name);
-
-	ret = request_firmware(&fw, desired_fw->name,
-		priv->i2c_props.adap->dev.parent);
-	if (ret) {
-		printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
-		ret = XC_RESULT_RESET_FAILURE;
-		goto out;
-	} else {
-		printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n",
-		       fw->size);
-		ret = XC_RESULT_SUCCESS;
-	}
-
-	if (fw->size != desired_fw->size) {
-		printk(KERN_ERR "xc5000: firmware incorrect size\n");
-		ret = XC_RESULT_RESET_FAILURE;
-	} else {
-		printk(KERN_INFO "xc5000: firmware uploading...\n");
-		ret = xc_load_i2c_sequence(fe,  fw->data);
-		if (XC_RESULT_SUCCESS == ret)
-			ret = xc_set_xtal(fe);
-		if (XC_RESULT_SUCCESS == ret)
-			printk(KERN_INFO "xc5000: firmware upload complete...\n");
-		else
-			printk(KERN_ERR "xc5000: firmware upload failed...\n");
-	}
-
-out:
-	release_firmware(fw);
-	return ret;
-}
-
-static void xc_debug_dump(struct xc5000_priv *priv)
-{
-	u16 adc_envelope;
-	u32 freq_error_hz = 0;
-	u16 lock_status;
-	u32 hsync_freq_hz = 0;
-	u16 frame_lines;
-	u16 quality;
-	u8 hw_majorversion = 0, hw_minorversion = 0;
-	u8 fw_majorversion = 0, fw_minorversion = 0;
-	u16 fw_buildversion = 0;
-
-	/* Wait for stats to stabilize.
-	 * Frame Lines needs two frame times after initial lock
-	 * before it is valid.
-	 */
-	xc_wait(100);
-
-	xc_get_ADC_Envelope(priv,  &adc_envelope);
-	dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
-
-	xc_get_frequency_error(priv, &freq_error_hz);
-	dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
-
-	xc_get_lock_status(priv,  &lock_status);
-	dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
-		lock_status);
-
-	xc_get_version(priv,  &hw_majorversion, &hw_minorversion,
-		&fw_majorversion, &fw_minorversion);
-	xc_get_buildversion(priv,  &fw_buildversion);
-	dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x.%04x\n",
-		hw_majorversion, hw_minorversion,
-		fw_majorversion, fw_minorversion, fw_buildversion);
-
-	xc_get_hsync_freq(priv,  &hsync_freq_hz);
-	dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz);
-
-	xc_get_frame_lines(priv,  &frame_lines);
-	dprintk(1, "*** Frame lines = %d\n", frame_lines);
-
-	xc_get_quality(priv,  &quality);
-	dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
-}
-
-static int xc5000_set_params(struct dvb_frontend *fe)
-{
-	int ret, b;
-	struct xc5000_priv *priv = fe->tuner_priv;
-	u32 bw = fe->dtv_property_cache.bandwidth_hz;
-	u32 freq = fe->dtv_property_cache.frequency;
-	u32 delsys  = fe->dtv_property_cache.delivery_system;
-
-	if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
-		if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
-			dprintk(1, "Unable to load firmware and init tuner\n");
-			return -EINVAL;
-		}
-	}
-
-	dprintk(1, "%s() frequency=%d (Hz)\n", __func__, freq);
-
-	switch (delsys) {
-	case SYS_ATSC:
-		dprintk(1, "%s() VSB modulation\n", __func__);
-		priv->rf_mode = XC_RF_MODE_AIR;
-		priv->freq_hz = freq - 1750000;
-		priv->video_standard = DTV6;
-		break;
-	case SYS_DVBC_ANNEX_B:
-		dprintk(1, "%s() QAM modulation\n", __func__);
-		priv->rf_mode = XC_RF_MODE_CABLE;
-		priv->freq_hz = freq - 1750000;
-		priv->video_standard = DTV6;
-		break;
-	case SYS_ISDBT:
-		/* All ISDB-T are currently for 6 MHz bw */
-		if (!bw)
-			bw = 6000000;
-		/* fall to OFDM handling */
-	case SYS_DMBTH:
-	case SYS_DVBT:
-	case SYS_DVBT2:
-		dprintk(1, "%s() OFDM\n", __func__);
-		switch (bw) {
-		case 6000000:
-			priv->video_standard = DTV6;
-			priv->freq_hz = freq - 1750000;
-			break;
-		case 7000000:
-			priv->video_standard = DTV7;
-			priv->freq_hz = freq - 2250000;
-			break;
-		case 8000000:
-			priv->video_standard = DTV8;
-			priv->freq_hz = freq - 2750000;
-			break;
-		default:
-			printk(KERN_ERR "xc5000 bandwidth not set!\n");
-			return -EINVAL;
-		}
-		priv->rf_mode = XC_RF_MODE_AIR;
-	case SYS_DVBC_ANNEX_A:
-	case SYS_DVBC_ANNEX_C:
-		dprintk(1, "%s() QAM modulation\n", __func__);
-		priv->rf_mode = XC_RF_MODE_CABLE;
-		if (bw <= 6000000) {
-			priv->video_standard = DTV6;
-			priv->freq_hz = freq - 1750000;
-			b = 6;
-		} else if (bw <= 7000000) {
-			priv->video_standard = DTV7;
-			priv->freq_hz = freq - 2250000;
-			b = 7;
-		} else {
-			priv->video_standard = DTV7_8;
-			priv->freq_hz = freq - 2750000;
-			b = 8;
-		}
-		dprintk(1, "%s() Bandwidth %dMHz (%d)\n", __func__,
-			b, bw);
-		break;
-	default:
-		printk(KERN_ERR "xc5000: delivery system is not supported!\n");
-		return -EINVAL;
-	}
-
-	dprintk(1, "%s() frequency=%d (compensated to %d)\n",
-		__func__, freq, priv->freq_hz);
-
-	ret = xc_SetSignalSource(priv, priv->rf_mode);
-	if (ret != XC_RESULT_SUCCESS) {
-		printk(KERN_ERR
-			"xc5000: xc_SetSignalSource(%d) failed\n",
-			priv->rf_mode);
-		return -EREMOTEIO;
-	}
-
-	ret = xc_SetTVStandard(priv,
-		XC5000_Standard[priv->video_standard].VideoMode,
-		XC5000_Standard[priv->video_standard].AudioMode);
-	if (ret != XC_RESULT_SUCCESS) {
-		printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
-		return -EREMOTEIO;
-	}
-
-	ret = xc_set_IF_frequency(priv, priv->if_khz);
-	if (ret != XC_RESULT_SUCCESS) {
-		printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
-		       priv->if_khz);
-		return -EIO;
-	}
-
-	xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a);
-
-	xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
-
-	if (debug)
-		xc_debug_dump(priv);
-
-	priv->bandwidth = bw;
-
-	return 0;
-}
-
-static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
-{
-	struct xc5000_priv *priv = fe->tuner_priv;
-	int ret;
-	u16 id;
-
-	ret = xc5000_readreg(priv, XREG_PRODUCT_ID, &id);
-	if (ret == XC_RESULT_SUCCESS) {
-		if (id == XC_PRODUCT_ID_FW_NOT_LOADED)
-			ret = XC_RESULT_RESET_FAILURE;
-		else
-			ret = XC_RESULT_SUCCESS;
-	}
-
-	dprintk(1, "%s() returns %s id = 0x%x\n", __func__,
-		ret == XC_RESULT_SUCCESS ? "True" : "False", id);
-	return ret;
-}
-
-static int xc5000_set_tv_freq(struct dvb_frontend *fe,
-	struct analog_parameters *params)
-{
-	struct xc5000_priv *priv = fe->tuner_priv;
-	int ret;
-
-	dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
-		__func__, params->frequency);
-
-	/* Fix me: it could be air. */
-	priv->rf_mode = params->mode;
-	if (params->mode > XC_RF_MODE_CABLE)
-		priv->rf_mode = XC_RF_MODE_CABLE;
-
-	/* params->frequency is in units of 62.5khz */
-	priv->freq_hz = params->frequency * 62500;
-
-	/* FIX ME: Some video standards may have several possible audio
-		   standards. We simply default to one of them here.
-	 */
-	if (params->std & V4L2_STD_MN) {
-		/* default to BTSC audio standard */
-		priv->video_standard = MN_NTSC_PAL_BTSC;
-		goto tune_channel;
-	}
-
-	if (params->std & V4L2_STD_PAL_BG) {
-		/* default to NICAM audio standard */
-		priv->video_standard = BG_PAL_NICAM;
-		goto tune_channel;
-	}
-
-	if (params->std & V4L2_STD_PAL_I) {
-		/* default to NICAM audio standard */
-		priv->video_standard = I_PAL_NICAM;
-		goto tune_channel;
-	}
-
-	if (params->std & V4L2_STD_PAL_DK) {
-		/* default to NICAM audio standard */
-		priv->video_standard = DK_PAL_NICAM;
-		goto tune_channel;
-	}
-
-	if (params->std & V4L2_STD_SECAM_DK) {
-		/* default to A2 DK1 audio standard */
-		priv->video_standard = DK_SECAM_A2DK1;
-		goto tune_channel;
-	}
-
-	if (params->std & V4L2_STD_SECAM_L) {
-		priv->video_standard = L_SECAM_NICAM;
-		goto tune_channel;
-	}
-
-	if (params->std & V4L2_STD_SECAM_LC) {
-		priv->video_standard = LC_SECAM_NICAM;
-		goto tune_channel;
-	}
-
-tune_channel:
-	ret = xc_SetSignalSource(priv, priv->rf_mode);
-	if (ret != XC_RESULT_SUCCESS) {
-		printk(KERN_ERR
-			"xc5000: xc_SetSignalSource(%d) failed\n",
-			priv->rf_mode);
-		return -EREMOTEIO;
-	}
-
-	ret = xc_SetTVStandard(priv,
-		XC5000_Standard[priv->video_standard].VideoMode,
-		XC5000_Standard[priv->video_standard].AudioMode);
-	if (ret != XC_RESULT_SUCCESS) {
-		printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
-		return -EREMOTEIO;
-	}
-
-	xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09);
-
-	xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
-
-	if (debug)
-		xc_debug_dump(priv);
-
-	return 0;
-}
-
-static int xc5000_set_radio_freq(struct dvb_frontend *fe,
-	struct analog_parameters *params)
-{
-	struct xc5000_priv *priv = fe->tuner_priv;
-	int ret = -EINVAL;
-	u8 radio_input;
-
-	dprintk(1, "%s() frequency=%d (in units of khz)\n",
-		__func__, params->frequency);
-
-	if (priv->radio_input == XC5000_RADIO_NOT_CONFIGURED) {
-		dprintk(1, "%s() radio input not configured\n", __func__);
-		return -EINVAL;
-	}
-
-	if (priv->radio_input == XC5000_RADIO_FM1)
-		radio_input = FM_Radio_INPUT1;
-	else if  (priv->radio_input == XC5000_RADIO_FM2)
-		radio_input = FM_Radio_INPUT2;
-	else if  (priv->radio_input == XC5000_RADIO_FM1_MONO)
-		radio_input = FM_Radio_INPUT1_MONO;
-	else {
-		dprintk(1, "%s() unknown radio input %d\n", __func__,
-			priv->radio_input);
-		return -EINVAL;
-	}
-
-	priv->freq_hz = params->frequency * 125 / 2;
-
-	priv->rf_mode = XC_RF_MODE_AIR;
-
-	ret = xc_SetTVStandard(priv, XC5000_Standard[radio_input].VideoMode,
-			       XC5000_Standard[radio_input].AudioMode);
-
-	if (ret != XC_RESULT_SUCCESS) {
-		printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
-		return -EREMOTEIO;
-	}
-
-	ret = xc_SetSignalSource(priv, priv->rf_mode);
-	if (ret != XC_RESULT_SUCCESS) {
-		printk(KERN_ERR
-			"xc5000: xc_SetSignalSource(%d) failed\n",
-			priv->rf_mode);
-		return -EREMOTEIO;
-	}
-
-	if ((priv->radio_input == XC5000_RADIO_FM1) ||
-				(priv->radio_input == XC5000_RADIO_FM2))
-		xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09);
-	else if  (priv->radio_input == XC5000_RADIO_FM1_MONO)
-		xc_write_reg(priv, XREG_OUTPUT_AMP, 0x06);
-
-	xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
-
-	return 0;
-}
-
-static int xc5000_set_analog_params(struct dvb_frontend *fe,
-			     struct analog_parameters *params)
-{
-	struct xc5000_priv *priv = fe->tuner_priv;
-	int ret = -EINVAL;
-
-	if (priv->i2c_props.adap == NULL)
-		return -EINVAL;
-
-	if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
-		if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
-			dprintk(1, "Unable to load firmware and init tuner\n");
-			return -EINVAL;
-		}
-	}
-
-	switch (params->mode) {
-	case V4L2_TUNER_RADIO:
-		ret = xc5000_set_radio_freq(fe, params);
-		break;
-	case V4L2_TUNER_ANALOG_TV:
-	case V4L2_TUNER_DIGITAL_TV:
-		ret = xc5000_set_tv_freq(fe, params);
-		break;
-	}
-
-	return ret;
-}
-
-
-static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
-{
-	struct xc5000_priv *priv = fe->tuner_priv;
-	dprintk(1, "%s()\n", __func__);
-	*freq = priv->freq_hz;
-	return 0;
-}
-
-static int xc5000_get_if_frequency(struct dvb_frontend *fe, u32 *freq)
-{
-	struct xc5000_priv *priv = fe->tuner_priv;
-	dprintk(1, "%s()\n", __func__);
-	*freq = priv->if_khz * 1000;
-	return 0;
-}
-
-static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
-{
-	struct xc5000_priv *priv = fe->tuner_priv;
-	dprintk(1, "%s()\n", __func__);
-
-	*bw = priv->bandwidth;
-	return 0;
-}
-
-static int xc5000_get_status(struct dvb_frontend *fe, u32 *status)
-{
-	struct xc5000_priv *priv = fe->tuner_priv;
-	u16 lock_status = 0;
-
-	xc_get_lock_status(priv, &lock_status);
-
-	dprintk(1, "%s() lock_status = 0x%08x\n", __func__, lock_status);
-
-	*status = lock_status;
-
-	return 0;
-}
-
-static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
-{
-	struct xc5000_priv *priv = fe->tuner_priv;
-	int ret = 0;
-
-	if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
-		ret = xc5000_fwupload(fe);
-		if (ret != XC_RESULT_SUCCESS)
-			return ret;
-	}
-
-	/* Start the tuner self-calibration process */
-	ret |= xc_initialize(priv);
-
-	/* Wait for calibration to complete.
-	 * We could continue but XC5000 will clock stretch subsequent
-	 * I2C transactions until calibration is complete.  This way we
-	 * don't have to rely on clock stretching working.
-	 */
-	xc_wait(100);
-
-	/* Default to "CABLE" mode */
-	ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
-
-	return ret;
-}
-
-static int xc5000_sleep(struct dvb_frontend *fe)
-{
-	int ret;
-
-	dprintk(1, "%s()\n", __func__);
-
-	/* Avoid firmware reload on slow devices */
-	if (no_poweroff)
-		return 0;
-
-	/* According to Xceive technical support, the "powerdown" register
-	   was removed in newer versions of the firmware.  The "supported"
-	   way to sleep the tuner is to pull the reset pin low for 10ms */
-	ret = xc5000_TunerReset(fe);
-	if (ret != XC_RESULT_SUCCESS) {
-		printk(KERN_ERR
-			"xc5000: %s() unable to shutdown tuner\n",
-			__func__);
-		return -EREMOTEIO;
-	} else
-		return XC_RESULT_SUCCESS;
-}
-
-static int xc5000_init(struct dvb_frontend *fe)
-{
-	struct xc5000_priv *priv = fe->tuner_priv;
-	dprintk(1, "%s()\n", __func__);
-
-	if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
-		printk(KERN_ERR "xc5000: Unable to initialise tuner\n");
-		return -EREMOTEIO;
-	}
-
-	if (debug)
-		xc_debug_dump(priv);
-
-	return 0;
-}
-
-static int xc5000_release(struct dvb_frontend *fe)
-{
-	struct xc5000_priv *priv = fe->tuner_priv;
-
-	dprintk(1, "%s()\n", __func__);
-
-	mutex_lock(&xc5000_list_mutex);
-
-	if (priv)
-		hybrid_tuner_release_state(priv);
-
-	mutex_unlock(&xc5000_list_mutex);
-
-	fe->tuner_priv = NULL;
-
-	return 0;
-}
-
-static int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg)
-{
-	struct xc5000_priv *priv = fe->tuner_priv;
-	struct xc5000_config *p = priv_cfg;
-
-	dprintk(1, "%s()\n", __func__);
-
-	if (p->if_khz)
-		priv->if_khz = p->if_khz;
-
-	if (p->radio_input)
-		priv->radio_input = p->radio_input;
-
-	return 0;
-}
-
-
-static const struct dvb_tuner_ops xc5000_tuner_ops = {
-	.info = {
-		.name           = "Xceive XC5000",
-		.frequency_min  =    1000000,
-		.frequency_max  = 1023000000,
-		.frequency_step =      50000,
-	},
-
-	.release	   = xc5000_release,
-	.init		   = xc5000_init,
-	.sleep		   = xc5000_sleep,
-
-	.set_config	   = xc5000_set_config,
-	.set_params	   = xc5000_set_params,
-	.set_analog_params = xc5000_set_analog_params,
-	.get_frequency	   = xc5000_get_frequency,
-	.get_if_frequency  = xc5000_get_if_frequency,
-	.get_bandwidth	   = xc5000_get_bandwidth,
-	.get_status	   = xc5000_get_status
-};
-
-struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
-				   struct i2c_adapter *i2c,
-				   const struct xc5000_config *cfg)
-{
-	struct xc5000_priv *priv = NULL;
-	int instance;
-	u16 id = 0;
-
-	dprintk(1, "%s(%d-%04x)\n", __func__,
-		i2c ? i2c_adapter_id(i2c) : -1,
-		cfg ? cfg->i2c_address : -1);
-
-	mutex_lock(&xc5000_list_mutex);
-
-	instance = hybrid_tuner_request_state(struct xc5000_priv, priv,
-					      hybrid_tuner_instance_list,
-					      i2c, cfg->i2c_address, "xc5000");
-	switch (instance) {
-	case 0:
-		goto fail;
-		break;
-	case 1:
-		/* new tuner instance */
-		priv->bandwidth = 6000000;
-		fe->tuner_priv = priv;
-		break;
-	default:
-		/* existing tuner instance */
-		fe->tuner_priv = priv;
-		break;
-	}
-
-	if (priv->if_khz == 0) {
-		/* If the IF hasn't been set yet, use the value provided by
-		   the caller (occurs in hybrid devices where the analog
-		   call to xc5000_attach occurs before the digital side) */
-		priv->if_khz = cfg->if_khz;
-	}
-
-	if (priv->xtal_khz == 0)
-		priv->xtal_khz = cfg->xtal_khz;
-
-	if (priv->radio_input == 0)
-		priv->radio_input = cfg->radio_input;
-
-	/* don't override chip id if it's already been set
-	   unless explicitly specified */
-	if ((priv->chip_id == 0) || (cfg->chip_id))
-		/* use default chip id if none specified, set to 0 so
-		   it can be overridden if this is a hybrid driver */
-		priv->chip_id = (cfg->chip_id) ? cfg->chip_id : 0;
-
-	/* Check if firmware has been loaded. It is possible that another
-	   instance of the driver has loaded the firmware.
-	 */
-	if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS)
-		goto fail;
-
-	switch (id) {
-	case XC_PRODUCT_ID_FW_LOADED:
-		printk(KERN_INFO
-			"xc5000: Successfully identified at address 0x%02x\n",
-			cfg->i2c_address);
-		printk(KERN_INFO
-			"xc5000: Firmware has been loaded previously\n");
-		break;
-	case XC_PRODUCT_ID_FW_NOT_LOADED:
-		printk(KERN_INFO
-			"xc5000: Successfully identified at address 0x%02x\n",
-			cfg->i2c_address);
-		printk(KERN_INFO
-			"xc5000: Firmware has not been loaded previously\n");
-		break;
-	default:
-		printk(KERN_ERR
-			"xc5000: Device not found at addr 0x%02x (0x%x)\n",
-			cfg->i2c_address, id);
-		goto fail;
-	}
-
-	mutex_unlock(&xc5000_list_mutex);
-
-	memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
-		sizeof(struct dvb_tuner_ops));
-
-	return fe;
-fail:
-	mutex_unlock(&xc5000_list_mutex);
-
-	xc5000_release(fe);
-	return NULL;
-}
-EXPORT_SYMBOL(xc5000_attach);
-
-MODULE_AUTHOR("Steven Toth");
-MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(XC5000A_FIRMWARE);
-MODULE_FIRMWARE(XC5000C_FIRMWARE);
diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h
deleted file mode 100644
index b1a5474..0000000
--- a/drivers/media/common/tuners/xc5000.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
- *
- *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __XC5000_H__
-#define __XC5000_H__
-
-#include <linux/firmware.h>
-
-struct dvb_frontend;
-struct i2c_adapter;
-
-#define XC5000A 1
-#define XC5000C 2
-
-struct xc5000_config {
-	u8   i2c_address;
-	u32  if_khz;
-	u8   radio_input;
-	u16  xtal_khz;
-
-	int chip_id;
-};
-
-/* xc5000 callback command */
-#define XC5000_TUNER_RESET		0
-
-/* Possible Radio inputs */
-#define XC5000_RADIO_NOT_CONFIGURED		0
-#define XC5000_RADIO_FM1			1
-#define XC5000_RADIO_FM2			2
-#define XC5000_RADIO_FM1_MONO			3
-
-/* For each bridge framework, when it attaches either analog or digital,
- * it has to store a reference back to its _core equivalent structure,
- * so that it can service the hardware by steering gpio's etc.
- * Each bridge implementation is different so cast devptr accordingly.
- * The xc5000 driver cares not for this value, other than ensuring
- * it's passed back to a bridge during tuner_callback().
- */
-
-#if defined(CONFIG_MEDIA_TUNER_XC5000) || \
-    (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
-extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
-					  struct i2c_adapter *i2c,
-					  const struct xc5000_config *cfg);
-#else
-static inline struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
-						 struct i2c_adapter *i2c,
-						 const struct xc5000_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/dvb-core/Kconfig b/drivers/media/dvb-core/Kconfig
new file mode 100644
index 0000000..fa7a249
--- /dev/null
+++ b/drivers/media/dvb-core/Kconfig
@@ -0,0 +1,29 @@
+#
+# DVB device configuration
+#
+
+config DVB_MAX_ADAPTERS
+	int "maximum number of DVB/ATSC adapters"
+	depends on DVB_CORE
+	default 8
+	range 1 255
+	help
+	  Maximum number of DVB/ATSC adapters. Increasing this number
+	  increases the memory consumption of the DVB subsystem even
+	  if a much lower number of DVB/ATSC adapters is present.
+	  Only values in the range 4-32 are tested.
+
+	  If you are unsure about this, use the default value 8
+
+config DVB_DYNAMIC_MINORS
+	bool "Dynamic DVB minor allocation"
+	depends on DVB_CORE
+	default n
+	help
+	  If you say Y here, the DVB subsystem will use dynamic minor
+	  allocation for any device that uses the DVB major number.
+	  This means that you can have more than 4 of a single type
+	  of device (like demuxes and frontends) per adapter, but udev
+	  will be required to manage the device nodes.
+
+	  If you are unsure about this, say N here.
diff --git a/drivers/media/dvb-core/Makefile b/drivers/media/dvb-core/Makefile
new file mode 100644
index 0000000..8f22bcd
--- /dev/null
+++ b/drivers/media/dvb-core/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the kernel DVB device drivers.
+#
+
+dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
+
+dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o 	\
+		 dvb_ca_en50221.o dvb_frontend.o 		\
+		 $(dvb-net-y) dvb_ringbuffer.o dvb_math.o
+
+obj-$(CONFIG_DVB_CORE) += dvb-core.o
diff --git a/drivers/media/dvb-core/demux.h b/drivers/media/dvb-core/demux.h
new file mode 100644
index 0000000..eb91fd8
--- /dev/null
+++ b/drivers/media/dvb-core/demux.h
@@ -0,0 +1,280 @@
+/*
+ * demux.h
+ *
+ * Copyright (c) 2002 Convergence GmbH
+ *
+ * based on code:
+ * Copyright (c) 2000 Nokia Research Center
+ *                    Tampere, FINLAND
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef __DEMUX_H
+#define __DEMUX_H
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/time.h>
+#include <linux/dvb/dmx.h>
+
+/*--------------------------------------------------------------------------*/
+/* Common definitions */
+/*--------------------------------------------------------------------------*/
+
+/*
+ * DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter.
+ */
+
+#ifndef DMX_MAX_FILTER_SIZE
+#define DMX_MAX_FILTER_SIZE 18
+#endif
+
+/*
+ * DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter.
+ */
+
+#ifndef DMX_MAX_SECTION_SIZE
+#define DMX_MAX_SECTION_SIZE 4096
+#endif
+#ifndef DMX_MAX_SECFEED_SIZE
+#define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188)
+#endif
+
+
+/*
+ * enum dmx_success: Success codes for the Demux Callback API.
+ */
+
+enum dmx_success {
+  DMX_OK = 0, /* Received Ok */
+  DMX_LENGTH_ERROR, /* Incorrect length */
+  DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */
+  DMX_CRC_ERROR, /* Incorrect CRC */
+  DMX_FRAME_ERROR, /* Frame alignment error */
+  DMX_FIFO_ERROR, /* Receiver FIFO overrun */
+  DMX_MISSED_ERROR /* Receiver missed packet */
+} ;
+
+/*--------------------------------------------------------------------------*/
+/* TS packet reception */
+/*--------------------------------------------------------------------------*/
+
+/* TS filter type for set() */
+
+#define TS_PACKET       1   /* send TS packets (188 bytes) to callback (default) */
+#define	TS_PAYLOAD_ONLY 2   /* in case TS_PACKET is set, only send the TS
+			       payload (<=184 bytes per packet) to callback */
+#define TS_DECODER      4   /* send stream to built-in decoder (if present) */
+#define TS_DEMUX        8   /* in case TS_PACKET is set, send the TS to
+			       the demux device, not to the dvr device */
+
+/* PES type for filters which write to built-in decoder */
+/* these should be kept identical to the types in dmx.h */
+
+enum dmx_ts_pes
+{  /* also send packets to decoder (if it exists) */
+	DMX_TS_PES_AUDIO0,
+	DMX_TS_PES_VIDEO0,
+	DMX_TS_PES_TELETEXT0,
+	DMX_TS_PES_SUBTITLE0,
+	DMX_TS_PES_PCR0,
+
+	DMX_TS_PES_AUDIO1,
+	DMX_TS_PES_VIDEO1,
+	DMX_TS_PES_TELETEXT1,
+	DMX_TS_PES_SUBTITLE1,
+	DMX_TS_PES_PCR1,
+
+	DMX_TS_PES_AUDIO2,
+	DMX_TS_PES_VIDEO2,
+	DMX_TS_PES_TELETEXT2,
+	DMX_TS_PES_SUBTITLE2,
+	DMX_TS_PES_PCR2,
+
+	DMX_TS_PES_AUDIO3,
+	DMX_TS_PES_VIDEO3,
+	DMX_TS_PES_TELETEXT3,
+	DMX_TS_PES_SUBTITLE3,
+	DMX_TS_PES_PCR3,
+
+	DMX_TS_PES_OTHER
+};
+
+#define DMX_TS_PES_AUDIO    DMX_TS_PES_AUDIO0
+#define DMX_TS_PES_VIDEO    DMX_TS_PES_VIDEO0
+#define DMX_TS_PES_TELETEXT DMX_TS_PES_TELETEXT0
+#define DMX_TS_PES_SUBTITLE DMX_TS_PES_SUBTITLE0
+#define DMX_TS_PES_PCR      DMX_TS_PES_PCR0
+
+
+struct dmx_ts_feed {
+	int is_filtering; /* Set to non-zero when filtering in progress */
+	struct dmx_demux *parent; /* Back-pointer */
+	void *priv; /* Pointer to private data of the API client */
+	int (*set) (struct dmx_ts_feed *feed,
+		    u16 pid,
+		    int type,
+		    enum dmx_ts_pes pes_type,
+		    size_t circular_buffer_size,
+		    struct timespec timeout);
+	int (*start_filtering) (struct dmx_ts_feed* feed);
+	int (*stop_filtering) (struct dmx_ts_feed* feed);
+};
+
+/*--------------------------------------------------------------------------*/
+/* Section reception */
+/*--------------------------------------------------------------------------*/
+
+struct dmx_section_filter {
+	u8 filter_value [DMX_MAX_FILTER_SIZE];
+	u8 filter_mask [DMX_MAX_FILTER_SIZE];
+	u8 filter_mode [DMX_MAX_FILTER_SIZE];
+	struct dmx_section_feed* parent; /* Back-pointer */
+	void* priv; /* Pointer to private data of the API client */
+};
+
+struct dmx_section_feed {
+	int is_filtering; /* Set to non-zero when filtering in progress */
+	struct dmx_demux* parent; /* Back-pointer */
+	void* priv; /* Pointer to private data of the API client */
+
+	int check_crc;
+	u32 crc_val;
+
+	u8 *secbuf;
+	u8 secbuf_base[DMX_MAX_SECFEED_SIZE];
+	u16 secbufp, seclen, tsfeedp;
+
+	int (*set) (struct dmx_section_feed* feed,
+		    u16 pid,
+		    size_t circular_buffer_size,
+		    int check_crc);
+	int (*allocate_filter) (struct dmx_section_feed* feed,
+				struct dmx_section_filter** filter);
+	int (*release_filter) (struct dmx_section_feed* feed,
+			       struct dmx_section_filter* filter);
+	int (*start_filtering) (struct dmx_section_feed* feed);
+	int (*stop_filtering) (struct dmx_section_feed* feed);
+};
+
+/*--------------------------------------------------------------------------*/
+/* Callback functions */
+/*--------------------------------------------------------------------------*/
+
+typedef int (*dmx_ts_cb) ( const u8 * buffer1,
+			   size_t buffer1_length,
+			   const u8 * buffer2,
+			   size_t buffer2_length,
+			   struct dmx_ts_feed* source,
+			   enum dmx_success success);
+
+typedef int (*dmx_section_cb) (	const u8 * buffer1,
+				size_t buffer1_len,
+				const u8 * buffer2,
+				size_t buffer2_len,
+				struct dmx_section_filter * source,
+				enum dmx_success success);
+
+/*--------------------------------------------------------------------------*/
+/* DVB Front-End */
+/*--------------------------------------------------------------------------*/
+
+enum dmx_frontend_source {
+	DMX_MEMORY_FE,
+	DMX_FRONTEND_0,
+	DMX_FRONTEND_1,
+	DMX_FRONTEND_2,
+	DMX_FRONTEND_3,
+	DMX_STREAM_0,    /* external stream input, e.g. LVDS */
+	DMX_STREAM_1,
+	DMX_STREAM_2,
+	DMX_STREAM_3
+};
+
+struct dmx_frontend {
+	struct list_head connectivity_list; /* List of front-ends that can
+					       be connected to a particular
+					       demux */
+	enum dmx_frontend_source source;
+};
+
+/*--------------------------------------------------------------------------*/
+/* MPEG-2 TS Demux */
+/*--------------------------------------------------------------------------*/
+
+/*
+ * Flags OR'ed in the capabilities field of struct dmx_demux.
+ */
+
+#define DMX_TS_FILTERING                        1
+#define DMX_PES_FILTERING                       2
+#define DMX_SECTION_FILTERING                   4
+#define DMX_MEMORY_BASED_FILTERING              8    /* write() available */
+#define DMX_CRC_CHECKING                        16
+#define DMX_TS_DESCRAMBLING                     32
+
+/*
+ * Demux resource type identifier.
+*/
+
+/*
+ * DMX_FE_ENTRY(): Casts elements in the list of registered
+ * front-ends from the generic type struct list_head
+ * to the type * struct dmx_frontend
+ *.
+*/
+
+#define DMX_FE_ENTRY(list) list_entry(list, struct dmx_frontend, connectivity_list)
+
+struct dmx_demux {
+	u32 capabilities;            /* Bitfield of capability flags */
+	struct dmx_frontend* frontend;    /* Front-end connected to the demux */
+	void* priv;                  /* Pointer to private data of the API client */
+	int (*open) (struct dmx_demux* demux);
+	int (*close) (struct dmx_demux* demux);
+	int (*write) (struct dmx_demux* demux, const char __user *buf, size_t count);
+	int (*allocate_ts_feed) (struct dmx_demux* demux,
+				 struct dmx_ts_feed** feed,
+				 dmx_ts_cb callback);
+	int (*release_ts_feed) (struct dmx_demux* demux,
+				struct dmx_ts_feed* feed);
+	int (*allocate_section_feed) (struct dmx_demux* demux,
+				      struct dmx_section_feed** feed,
+				      dmx_section_cb callback);
+	int (*release_section_feed) (struct dmx_demux* demux,
+				     struct dmx_section_feed* feed);
+	int (*add_frontend) (struct dmx_demux* demux,
+			     struct dmx_frontend* frontend);
+	int (*remove_frontend) (struct dmx_demux* demux,
+				struct dmx_frontend* frontend);
+	struct list_head* (*get_frontends) (struct dmx_demux* demux);
+	int (*connect_frontend) (struct dmx_demux* demux,
+				 struct dmx_frontend* frontend);
+	int (*disconnect_frontend) (struct dmx_demux* demux);
+
+	int (*get_pes_pids) (struct dmx_demux* demux, u16 *pids);
+
+	int (*get_caps) (struct dmx_demux* demux, struct dmx_caps *caps);
+
+	int (*set_source) (struct dmx_demux* demux, const dmx_source_t *src);
+
+	int (*get_stc) (struct dmx_demux* demux, unsigned int num,
+			u64 *stc, unsigned int *base);
+};
+
+#endif /* #ifndef __DEMUX_H */
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
new file mode 100644
index 0000000..889c9c1
--- /dev/null
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -0,0 +1,1275 @@
+/*
+ * dmxdev.c - DVB demultiplexer device
+ *
+ * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
+ *		      for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/ioctl.h>
+#include <linux/wait.h>
+#include <asm/uaccess.h>
+#include "dmxdev.h"
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk	if (debug) printk
+
+static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
+				   const u8 *src, size_t len)
+{
+	ssize_t free;
+
+	if (!len)
+		return 0;
+	if (!buf->data)
+		return 0;
+
+	free = dvb_ringbuffer_free(buf);
+	if (len > free) {
+		dprintk("dmxdev: buffer overflow\n");
+		return -EOVERFLOW;
+	}
+
+	return dvb_ringbuffer_write(buf, src, len);
+}
+
+static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
+				      int non_blocking, char __user *buf,
+				      size_t count, loff_t *ppos)
+{
+	size_t todo;
+	ssize_t avail;
+	ssize_t ret = 0;
+
+	if (!src->data)
+		return 0;
+
+	if (src->error) {
+		ret = src->error;
+		dvb_ringbuffer_flush(src);
+		return ret;
+	}
+
+	for (todo = count; todo > 0; todo -= ret) {
+		if (non_blocking && dvb_ringbuffer_empty(src)) {
+			ret = -EWOULDBLOCK;
+			break;
+		}
+
+		ret = wait_event_interruptible(src->queue,
+					       !dvb_ringbuffer_empty(src) ||
+					       (src->error != 0));
+		if (ret < 0)
+			break;
+
+		if (src->error) {
+			ret = src->error;
+			dvb_ringbuffer_flush(src);
+			break;
+		}
+
+		avail = dvb_ringbuffer_avail(src);
+		if (avail > todo)
+			avail = todo;
+
+		ret = dvb_ringbuffer_read_user(src, buf, avail);
+		if (ret < 0)
+			break;
+
+		buf += ret;
+	}
+
+	return (count - todo) ? (count - todo) : ret;
+}
+
+static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type)
+{
+	struct list_head *head, *pos;
+
+	head = demux->get_frontends(demux);
+	if (!head)
+		return NULL;
+	list_for_each(pos, head)
+		if (DMX_FE_ENTRY(pos)->source == type)
+			return DMX_FE_ENTRY(pos);
+
+	return NULL;
+}
+
+static int dvb_dvr_open(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dmxdev *dmxdev = dvbdev->priv;
+	struct dmx_frontend *front;
+
+	dprintk("function : %s\n", __func__);
+
+	if (mutex_lock_interruptible(&dmxdev->mutex))
+		return -ERESTARTSYS;
+
+	if (dmxdev->exit) {
+		mutex_unlock(&dmxdev->mutex);
+		return -ENODEV;
+	}
+
+	if ((file->f_flags & O_ACCMODE) == O_RDWR) {
+		if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -EOPNOTSUPP;
+		}
+	}
+
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+		void *mem;
+		if (!dvbdev->readers) {
+			mutex_unlock(&dmxdev->mutex);
+			return -EBUSY;
+		}
+		mem = vmalloc(DVR_BUFFER_SIZE);
+		if (!mem) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ENOMEM;
+		}
+		dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
+		dvbdev->readers--;
+	}
+
+	if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+		dmxdev->dvr_orig_fe = dmxdev->demux->frontend;
+
+		if (!dmxdev->demux->write) {
+			mutex_unlock(&dmxdev->mutex);
+			return -EOPNOTSUPP;
+		}
+
+		front = get_fe(dmxdev->demux, DMX_MEMORY_FE);
+
+		if (!front) {
+			mutex_unlock(&dmxdev->mutex);
+			return -EINVAL;
+		}
+		dmxdev->demux->disconnect_frontend(dmxdev->demux);
+		dmxdev->demux->connect_frontend(dmxdev->demux, front);
+	}
+	dvbdev->users++;
+	mutex_unlock(&dmxdev->mutex);
+	return 0;
+}
+
+static int dvb_dvr_release(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dmxdev *dmxdev = dvbdev->priv;
+
+	mutex_lock(&dmxdev->mutex);
+
+	if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+		dmxdev->demux->disconnect_frontend(dmxdev->demux);
+		dmxdev->demux->connect_frontend(dmxdev->demux,
+						dmxdev->dvr_orig_fe);
+	}
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+		dvbdev->readers++;
+		if (dmxdev->dvr_buffer.data) {
+			void *mem = dmxdev->dvr_buffer.data;
+			mb();
+			spin_lock_irq(&dmxdev->lock);
+			dmxdev->dvr_buffer.data = NULL;
+			spin_unlock_irq(&dmxdev->lock);
+			vfree(mem);
+		}
+	}
+	/* TODO */
+	dvbdev->users--;
+	if (dvbdev->users == 1 && dmxdev->exit == 1) {
+		fops_put(file->f_op);
+		file->f_op = NULL;
+		mutex_unlock(&dmxdev->mutex);
+		wake_up(&dvbdev->wait_queue);
+	} else
+		mutex_unlock(&dmxdev->mutex);
+
+	return 0;
+}
+
+static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
+			     size_t count, loff_t *ppos)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dmxdev *dmxdev = dvbdev->priv;
+	int ret;
+
+	if (!dmxdev->demux->write)
+		return -EOPNOTSUPP;
+	if ((file->f_flags & O_ACCMODE) != O_WRONLY)
+		return -EINVAL;
+	if (mutex_lock_interruptible(&dmxdev->mutex))
+		return -ERESTARTSYS;
+
+	if (dmxdev->exit) {
+		mutex_unlock(&dmxdev->mutex);
+		return -ENODEV;
+	}
+	ret = dmxdev->demux->write(dmxdev->demux, buf, count);
+	mutex_unlock(&dmxdev->mutex);
+	return ret;
+}
+
+static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
+			    loff_t *ppos)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dmxdev *dmxdev = dvbdev->priv;
+
+	if (dmxdev->exit)
+		return -ENODEV;
+
+	return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
+				      file->f_flags & O_NONBLOCK,
+				      buf, count, ppos);
+}
+
+static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
+				      unsigned long size)
+{
+	struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer;
+	void *newmem;
+	void *oldmem;
+
+	dprintk("function : %s\n", __func__);
+
+	if (buf->size == size)
+		return 0;
+	if (!size)
+		return -EINVAL;
+
+	newmem = vmalloc(size);
+	if (!newmem)
+		return -ENOMEM;
+
+	oldmem = buf->data;
+
+	spin_lock_irq(&dmxdev->lock);
+	buf->data = newmem;
+	buf->size = size;
+
+	/* reset and not flush in case the buffer shrinks */
+	dvb_ringbuffer_reset(buf);
+	spin_unlock_irq(&dmxdev->lock);
+
+	vfree(oldmem);
+
+	return 0;
+}
+
+static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter
+					       *dmxdevfilter, int state)
+{
+	spin_lock_irq(&dmxdevfilter->dev->lock);
+	dmxdevfilter->state = state;
+	spin_unlock_irq(&dmxdevfilter->dev->lock);
+}
+
+static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,
+				      unsigned long size)
+{
+	struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
+	void *newmem;
+	void *oldmem;
+
+	if (buf->size == size)
+		return 0;
+	if (!size)
+		return -EINVAL;
+	if (dmxdevfilter->state >= DMXDEV_STATE_GO)
+		return -EBUSY;
+
+	newmem = vmalloc(size);
+	if (!newmem)
+		return -ENOMEM;
+
+	oldmem = buf->data;
+
+	spin_lock_irq(&dmxdevfilter->dev->lock);
+	buf->data = newmem;
+	buf->size = size;
+
+	/* reset and not flush in case the buffer shrinks */
+	dvb_ringbuffer_reset(buf);
+	spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+	vfree(oldmem);
+
+	return 0;
+}
+
+static void dvb_dmxdev_filter_timeout(unsigned long data)
+{
+	struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
+
+	dmxdevfilter->buffer.error = -ETIMEDOUT;
+	spin_lock_irq(&dmxdevfilter->dev->lock);
+	dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
+	spin_unlock_irq(&dmxdevfilter->dev->lock);
+	wake_up(&dmxdevfilter->buffer.queue);
+}
+
+static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
+{
+	struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec;
+
+	del_timer(&dmxdevfilter->timer);
+	if (para->timeout) {
+		dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout;
+		dmxdevfilter->timer.data = (unsigned long)dmxdevfilter;
+		dmxdevfilter->timer.expires =
+		    jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000;
+		add_timer(&dmxdevfilter->timer);
+	}
+}
+
+static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
+				       const u8 *buffer2, size_t buffer2_len,
+				       struct dmx_section_filter *filter,
+				       enum dmx_success success)
+{
+	struct dmxdev_filter *dmxdevfilter = filter->priv;
+	int ret;
+
+	if (dmxdevfilter->buffer.error) {
+		wake_up(&dmxdevfilter->buffer.queue);
+		return 0;
+	}
+	spin_lock(&dmxdevfilter->dev->lock);
+	if (dmxdevfilter->state != DMXDEV_STATE_GO) {
+		spin_unlock(&dmxdevfilter->dev->lock);
+		return 0;
+	}
+	del_timer(&dmxdevfilter->timer);
+	dprintk("dmxdev: section callback %*ph\n", 6, buffer1);
+	ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
+				      buffer1_len);
+	if (ret == buffer1_len) {
+		ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
+					      buffer2_len);
+	}
+	if (ret < 0) {
+		dvb_ringbuffer_flush(&dmxdevfilter->buffer);
+		dmxdevfilter->buffer.error = ret;
+	}
+	if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
+		dmxdevfilter->state = DMXDEV_STATE_DONE;
+	spin_unlock(&dmxdevfilter->dev->lock);
+	wake_up(&dmxdevfilter->buffer.queue);
+	return 0;
+}
+
+static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
+				  const u8 *buffer2, size_t buffer2_len,
+				  struct dmx_ts_feed *feed,
+				  enum dmx_success success)
+{
+	struct dmxdev_filter *dmxdevfilter = feed->priv;
+	struct dvb_ringbuffer *buffer;
+	int ret;
+
+	spin_lock(&dmxdevfilter->dev->lock);
+	if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
+		spin_unlock(&dmxdevfilter->dev->lock);
+		return 0;
+	}
+
+	if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
+	    || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
+		buffer = &dmxdevfilter->buffer;
+	else
+		buffer = &dmxdevfilter->dev->dvr_buffer;
+	if (buffer->error) {
+		spin_unlock(&dmxdevfilter->dev->lock);
+		wake_up(&buffer->queue);
+		return 0;
+	}
+	ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
+	if (ret == buffer1_len)
+		ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
+	if (ret < 0) {
+		dvb_ringbuffer_flush(buffer);
+		buffer->error = ret;
+	}
+	spin_unlock(&dmxdevfilter->dev->lock);
+	wake_up(&buffer->queue);
+	return 0;
+}
+
+/* stop feed but only mark the specified filter as stopped (state set) */
+static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
+{
+	struct dmxdev_feed *feed;
+
+	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
+
+	switch (dmxdevfilter->type) {
+	case DMXDEV_TYPE_SEC:
+		del_timer(&dmxdevfilter->timer);
+		dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);
+		break;
+	case DMXDEV_TYPE_PES:
+		list_for_each_entry(feed, &dmxdevfilter->feed.ts, next)
+			feed->ts->stop_filtering(feed->ts);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* start feed associated with the specified filter */
+static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
+{
+	struct dmxdev_feed *feed;
+	int ret;
+
+	dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
+
+	switch (filter->type) {
+	case DMXDEV_TYPE_SEC:
+		return filter->feed.sec->start_filtering(filter->feed.sec);
+	case DMXDEV_TYPE_PES:
+		list_for_each_entry(feed, &filter->feed.ts, next) {
+			ret = feed->ts->start_filtering(feed->ts);
+			if (ret < 0) {
+				dvb_dmxdev_feed_stop(filter);
+				return ret;
+			}
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* restart section feed if it has filters left associated with it,
+   otherwise release the feed */
+static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter)
+{
+	int i;
+	struct dmxdev *dmxdev = filter->dev;
+	u16 pid = filter->params.sec.pid;
+
+	for (i = 0; i < dmxdev->filternum; i++)
+		if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
+		    dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
+		    dmxdev->filter[i].params.sec.pid == pid) {
+			dvb_dmxdev_feed_start(&dmxdev->filter[i]);
+			return 0;
+		}
+
+	filter->dev->demux->release_section_feed(dmxdev->demux,
+						 filter->feed.sec);
+
+	return 0;
+}
+
+static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
+{
+	struct dmxdev_feed *feed;
+	struct dmx_demux *demux;
+
+	if (dmxdevfilter->state < DMXDEV_STATE_GO)
+		return 0;
+
+	switch (dmxdevfilter->type) {
+	case DMXDEV_TYPE_SEC:
+		if (!dmxdevfilter->feed.sec)
+			break;
+		dvb_dmxdev_feed_stop(dmxdevfilter);
+		if (dmxdevfilter->filter.sec)
+			dmxdevfilter->feed.sec->
+			    release_filter(dmxdevfilter->feed.sec,
+					   dmxdevfilter->filter.sec);
+		dvb_dmxdev_feed_restart(dmxdevfilter);
+		dmxdevfilter->feed.sec = NULL;
+		break;
+	case DMXDEV_TYPE_PES:
+		dvb_dmxdev_feed_stop(dmxdevfilter);
+		demux = dmxdevfilter->dev->demux;
+		list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
+			demux->release_ts_feed(demux, feed->ts);
+			feed->ts = NULL;
+		}
+		break;
+	default:
+		if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)
+			return 0;
+		return -EINVAL;
+	}
+
+	dvb_ringbuffer_flush(&dmxdevfilter->buffer);
+	return 0;
+}
+
+static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter)
+{
+	struct dmxdev_feed *feed, *tmp;
+
+	/* delete all PIDs */
+	list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) {
+		list_del(&feed->next);
+		kfree(feed);
+	}
+
+	BUG_ON(!list_empty(&dmxdevfilter->feed.ts));
+}
+
+static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)
+{
+	if (dmxdevfilter->state < DMXDEV_STATE_SET)
+		return 0;
+
+	if (dmxdevfilter->type == DMXDEV_TYPE_PES)
+		dvb_dmxdev_delete_pids(dmxdevfilter);
+
+	dmxdevfilter->type = DMXDEV_TYPE_NONE;
+	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
+	return 0;
+}
+
+static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
+				 struct dmxdev_filter *filter,
+				 struct dmxdev_feed *feed)
+{
+	struct timespec timeout = { 0 };
+	struct dmx_pes_filter_params *para = &filter->params.pes;
+	dmx_output_t otype;
+	int ret;
+	int ts_type;
+	dmx_pes_type_t ts_pes;
+	struct dmx_ts_feed *tsfeed;
+
+	feed->ts = NULL;
+	otype = para->output;
+
+	ts_pes = para->pes_type;
+
+	if (ts_pes < DMX_PES_OTHER)
+		ts_type = TS_DECODER;
+	else
+		ts_type = 0;
+
+	if (otype == DMX_OUT_TS_TAP)
+		ts_type |= TS_PACKET;
+	else if (otype == DMX_OUT_TSDEMUX_TAP)
+		ts_type |= TS_PACKET | TS_DEMUX;
+	else if (otype == DMX_OUT_TAP)
+		ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
+
+	ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts,
+					      dvb_dmxdev_ts_callback);
+	if (ret < 0)
+		return ret;
+
+	tsfeed = feed->ts;
+	tsfeed->priv = filter;
+
+	ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);
+	if (ret < 0) {
+		dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
+		return ret;
+	}
+
+	ret = tsfeed->start_filtering(tsfeed);
+	if (ret < 0) {
+		dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
+{
+	struct dmxdev *dmxdev = filter->dev;
+	struct dmxdev_feed *feed;
+	void *mem;
+	int ret, i;
+
+	if (filter->state < DMXDEV_STATE_SET)
+		return -EINVAL;
+
+	if (filter->state >= DMXDEV_STATE_GO)
+		dvb_dmxdev_filter_stop(filter);
+
+	if (!filter->buffer.data) {
+		mem = vmalloc(filter->buffer.size);
+		if (!mem)
+			return -ENOMEM;
+		spin_lock_irq(&filter->dev->lock);
+		filter->buffer.data = mem;
+		spin_unlock_irq(&filter->dev->lock);
+	}
+
+	dvb_ringbuffer_flush(&filter->buffer);
+
+	switch (filter->type) {
+	case DMXDEV_TYPE_SEC:
+	{
+		struct dmx_sct_filter_params *para = &filter->params.sec;
+		struct dmx_section_filter **secfilter = &filter->filter.sec;
+		struct dmx_section_feed **secfeed = &filter->feed.sec;
+
+		*secfilter = NULL;
+		*secfeed = NULL;
+
+
+		/* find active filter/feed with same PID */
+		for (i = 0; i < dmxdev->filternum; i++) {
+			if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
+			    dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
+			    dmxdev->filter[i].params.sec.pid == para->pid) {
+				*secfeed = dmxdev->filter[i].feed.sec;
+				break;
+			}
+		}
+
+		/* if no feed found, try to allocate new one */
+		if (!*secfeed) {
+			ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,
+								   secfeed,
+								   dvb_dmxdev_section_callback);
+			if (ret < 0) {
+				printk("DVB (%s): could not alloc feed\n",
+				       __func__);
+				return ret;
+			}
+
+			ret = (*secfeed)->set(*secfeed, para->pid, 32768,
+					      (para->flags & DMX_CHECK_CRC) ? 1 : 0);
+			if (ret < 0) {
+				printk("DVB (%s): could not set feed\n",
+				       __func__);
+				dvb_dmxdev_feed_restart(filter);
+				return ret;
+			}
+		} else {
+			dvb_dmxdev_feed_stop(filter);
+		}
+
+		ret = (*secfeed)->allocate_filter(*secfeed, secfilter);
+		if (ret < 0) {
+			dvb_dmxdev_feed_restart(filter);
+			filter->feed.sec->start_filtering(*secfeed);
+			dprintk("could not get filter\n");
+			return ret;
+		}
+
+		(*secfilter)->priv = filter;
+
+		memcpy(&((*secfilter)->filter_value[3]),
+		       &(para->filter.filter[1]), DMX_FILTER_SIZE - 1);
+		memcpy(&(*secfilter)->filter_mask[3],
+		       &para->filter.mask[1], DMX_FILTER_SIZE - 1);
+		memcpy(&(*secfilter)->filter_mode[3],
+		       &para->filter.mode[1], DMX_FILTER_SIZE - 1);
+
+		(*secfilter)->filter_value[0] = para->filter.filter[0];
+		(*secfilter)->filter_mask[0] = para->filter.mask[0];
+		(*secfilter)->filter_mode[0] = para->filter.mode[0];
+		(*secfilter)->filter_mask[1] = 0;
+		(*secfilter)->filter_mask[2] = 0;
+
+		filter->todo = 0;
+
+		ret = filter->feed.sec->start_filtering(filter->feed.sec);
+		if (ret < 0)
+			return ret;
+
+		dvb_dmxdev_filter_timer(filter);
+		break;
+	}
+	case DMXDEV_TYPE_PES:
+		list_for_each_entry(feed, &filter->feed.ts, next) {
+			ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
+			if (ret < 0) {
+				dvb_dmxdev_filter_stop(filter);
+				return ret;
+			}
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
+	return 0;
+}
+
+static int dvb_demux_open(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dmxdev *dmxdev = dvbdev->priv;
+	int i;
+	struct dmxdev_filter *dmxdevfilter;
+
+	if (!dmxdev->filter)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&dmxdev->mutex))
+		return -ERESTARTSYS;
+
+	for (i = 0; i < dmxdev->filternum; i++)
+		if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
+			break;
+
+	if (i == dmxdev->filternum) {
+		mutex_unlock(&dmxdev->mutex);
+		return -EMFILE;
+	}
+
+	dmxdevfilter = &dmxdev->filter[i];
+	mutex_init(&dmxdevfilter->mutex);
+	file->private_data = dmxdevfilter;
+
+	dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
+	dmxdevfilter->type = DMXDEV_TYPE_NONE;
+	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
+	init_timer(&dmxdevfilter->timer);
+
+	dvbdev->users++;
+
+	mutex_unlock(&dmxdev->mutex);
+	return 0;
+}
+
+static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
+				  struct dmxdev_filter *dmxdevfilter)
+{
+	mutex_lock(&dmxdev->mutex);
+	mutex_lock(&dmxdevfilter->mutex);
+
+	dvb_dmxdev_filter_stop(dmxdevfilter);
+	dvb_dmxdev_filter_reset(dmxdevfilter);
+
+	if (dmxdevfilter->buffer.data) {
+		void *mem = dmxdevfilter->buffer.data;
+
+		spin_lock_irq(&dmxdev->lock);
+		dmxdevfilter->buffer.data = NULL;
+		spin_unlock_irq(&dmxdev->lock);
+		vfree(mem);
+	}
+
+	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
+	wake_up(&dmxdevfilter->buffer.queue);
+	mutex_unlock(&dmxdevfilter->mutex);
+	mutex_unlock(&dmxdev->mutex);
+	return 0;
+}
+
+static inline void invert_mode(dmx_filter_t *filter)
+{
+	int i;
+
+	for (i = 0; i < DMX_FILTER_SIZE; i++)
+		filter->mode[i] ^= 0xff;
+}
+
+static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev,
+			      struct dmxdev_filter *filter, u16 pid)
+{
+	struct dmxdev_feed *feed;
+
+	if ((filter->type != DMXDEV_TYPE_PES) ||
+	    (filter->state < DMXDEV_STATE_SET))
+		return -EINVAL;
+
+	/* only TS packet filters may have multiple PIDs */
+	if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) &&
+	    (!list_empty(&filter->feed.ts)))
+		return -EINVAL;
+
+	feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL);
+	if (feed == NULL)
+		return -ENOMEM;
+
+	feed->pid = pid;
+	list_add(&feed->next, &filter->feed.ts);
+
+	if (filter->state >= DMXDEV_STATE_GO)
+		return dvb_dmxdev_start_feed(dmxdev, filter, feed);
+
+	return 0;
+}
+
+static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,
+				  struct dmxdev_filter *filter, u16 pid)
+{
+	struct dmxdev_feed *feed, *tmp;
+
+	if ((filter->type != DMXDEV_TYPE_PES) ||
+	    (filter->state < DMXDEV_STATE_SET))
+		return -EINVAL;
+
+	list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {
+		if ((feed->pid == pid) && (feed->ts != NULL)) {
+			feed->ts->stop_filtering(feed->ts);
+			filter->dev->demux->release_ts_feed(filter->dev->demux,
+							    feed->ts);
+			list_del(&feed->next);
+			kfree(feed);
+		}
+	}
+
+	return 0;
+}
+
+static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
+				 struct dmxdev_filter *dmxdevfilter,
+				 struct dmx_sct_filter_params *params)
+{
+	dprintk("function : %s\n", __func__);
+
+	dvb_dmxdev_filter_stop(dmxdevfilter);
+
+	dmxdevfilter->type = DMXDEV_TYPE_SEC;
+	memcpy(&dmxdevfilter->params.sec,
+	       params, sizeof(struct dmx_sct_filter_params));
+	invert_mode(&dmxdevfilter->params.sec.filter);
+	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
+
+	if (params->flags & DMX_IMMEDIATE_START)
+		return dvb_dmxdev_filter_start(dmxdevfilter);
+
+	return 0;
+}
+
+static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
+				     struct dmxdev_filter *dmxdevfilter,
+				     struct dmx_pes_filter_params *params)
+{
+	int ret;
+
+	dvb_dmxdev_filter_stop(dmxdevfilter);
+	dvb_dmxdev_filter_reset(dmxdevfilter);
+
+	if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
+		return -EINVAL;
+
+	dmxdevfilter->type = DMXDEV_TYPE_PES;
+	memcpy(&dmxdevfilter->params, params,
+	       sizeof(struct dmx_pes_filter_params));
+	INIT_LIST_HEAD(&dmxdevfilter->feed.ts);
+
+	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
+
+	ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter,
+				 dmxdevfilter->params.pes.pid);
+	if (ret < 0)
+		return ret;
+
+	if (params->flags & DMX_IMMEDIATE_START)
+		return dvb_dmxdev_filter_start(dmxdevfilter);
+
+	return 0;
+}
+
+static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
+				   struct file *file, char __user *buf,
+				   size_t count, loff_t *ppos)
+{
+	int result, hcount;
+	int done = 0;
+
+	if (dfil->todo <= 0) {
+		hcount = 3 + dfil->todo;
+		if (hcount > count)
+			hcount = count;
+		result = dvb_dmxdev_buffer_read(&dfil->buffer,
+						file->f_flags & O_NONBLOCK,
+						buf, hcount, ppos);
+		if (result < 0) {
+			dfil->todo = 0;
+			return result;
+		}
+		if (copy_from_user(dfil->secheader - dfil->todo, buf, result))
+			return -EFAULT;
+		buf += result;
+		done = result;
+		count -= result;
+		dfil->todo -= result;
+		if (dfil->todo > -3)
+			return done;
+		dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff;
+		if (!count)
+			return done;
+	}
+	if (count > dfil->todo)
+		count = dfil->todo;
+	result = dvb_dmxdev_buffer_read(&dfil->buffer,
+					file->f_flags & O_NONBLOCK,
+					buf, count, ppos);
+	if (result < 0)
+		return result;
+	dfil->todo -= result;
+	return (result + done);
+}
+
+static ssize_t
+dvb_demux_read(struct file *file, char __user *buf, size_t count,
+	       loff_t *ppos)
+{
+	struct dmxdev_filter *dmxdevfilter = file->private_data;
+	int ret;
+
+	if (mutex_lock_interruptible(&dmxdevfilter->mutex))
+		return -ERESTARTSYS;
+
+	if (dmxdevfilter->type == DMXDEV_TYPE_SEC)
+		ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
+	else
+		ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
+					     file->f_flags & O_NONBLOCK,
+					     buf, count, ppos);
+
+	mutex_unlock(&dmxdevfilter->mutex);
+	return ret;
+}
+
+static int dvb_demux_do_ioctl(struct file *file,
+			      unsigned int cmd, void *parg)
+{
+	struct dmxdev_filter *dmxdevfilter = file->private_data;
+	struct dmxdev *dmxdev = dmxdevfilter->dev;
+	unsigned long arg = (unsigned long)parg;
+	int ret = 0;
+
+	if (mutex_lock_interruptible(&dmxdev->mutex))
+		return -ERESTARTSYS;
+
+	switch (cmd) {
+	case DMX_START:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		if (dmxdevfilter->state < DMXDEV_STATE_SET)
+			ret = -EINVAL;
+		else
+			ret = dvb_dmxdev_filter_start(dmxdevfilter);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_STOP:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_filter_stop(dmxdevfilter);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_SET_FILTER:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_SET_PES_FILTER:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_SET_BUFFER_SIZE:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_GET_PES_PIDS:
+		if (!dmxdev->demux->get_pes_pids) {
+			ret = -EINVAL;
+			break;
+		}
+		dmxdev->demux->get_pes_pids(dmxdev->demux, parg);
+		break;
+
+	case DMX_GET_CAPS:
+		if (!dmxdev->demux->get_caps) {
+			ret = -EINVAL;
+			break;
+		}
+		ret = dmxdev->demux->get_caps(dmxdev->demux, parg);
+		break;
+
+	case DMX_SET_SOURCE:
+		if (!dmxdev->demux->set_source) {
+			ret = -EINVAL;
+			break;
+		}
+		ret = dmxdev->demux->set_source(dmxdev->demux, parg);
+		break;
+
+	case DMX_GET_STC:
+		if (!dmxdev->demux->get_stc) {
+			ret = -EINVAL;
+			break;
+		}
+		ret = dmxdev->demux->get_stc(dmxdev->demux,
+					     ((struct dmx_stc *)parg)->num,
+					     &((struct dmx_stc *)parg)->stc,
+					     &((struct dmx_stc *)parg)->base);
+		break;
+
+	case DMX_ADD_PID:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+		ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_REMOVE_PID:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+		ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	mutex_unlock(&dmxdev->mutex);
+	return ret;
+}
+
+static long dvb_demux_ioctl(struct file *file, unsigned int cmd,
+			    unsigned long arg)
+{
+	return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl);
+}
+
+static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
+{
+	struct dmxdev_filter *dmxdevfilter = file->private_data;
+	unsigned int mask = 0;
+
+	if (!dmxdevfilter)
+		return -EINVAL;
+
+	poll_wait(file, &dmxdevfilter->buffer.queue, wait);
+
+	if (dmxdevfilter->state != DMXDEV_STATE_GO &&
+	    dmxdevfilter->state != DMXDEV_STATE_DONE &&
+	    dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT)
+		return 0;
+
+	if (dmxdevfilter->buffer.error)
+		mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
+
+	if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
+		mask |= (POLLIN | POLLRDNORM | POLLPRI);
+
+	return mask;
+}
+
+static int dvb_demux_release(struct inode *inode, struct file *file)
+{
+	struct dmxdev_filter *dmxdevfilter = file->private_data;
+	struct dmxdev *dmxdev = dmxdevfilter->dev;
+
+	int ret;
+
+	ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
+
+	mutex_lock(&dmxdev->mutex);
+	dmxdev->dvbdev->users--;
+	if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) {
+		fops_put(file->f_op);
+		file->f_op = NULL;
+		mutex_unlock(&dmxdev->mutex);
+		wake_up(&dmxdev->dvbdev->wait_queue);
+	} else
+		mutex_unlock(&dmxdev->mutex);
+
+	return ret;
+}
+
+static const struct file_operations dvb_demux_fops = {
+	.owner = THIS_MODULE,
+	.read = dvb_demux_read,
+	.unlocked_ioctl = dvb_demux_ioctl,
+	.open = dvb_demux_open,
+	.release = dvb_demux_release,
+	.poll = dvb_demux_poll,
+	.llseek = default_llseek,
+};
+
+static struct dvb_device dvbdev_demux = {
+	.priv = NULL,
+	.users = 1,
+	.writers = 1,
+	.fops = &dvb_demux_fops
+};
+
+static int dvb_dvr_do_ioctl(struct file *file,
+			    unsigned int cmd, void *parg)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dmxdev *dmxdev = dvbdev->priv;
+	unsigned long arg = (unsigned long)parg;
+	int ret;
+
+	if (mutex_lock_interruptible(&dmxdev->mutex))
+		return -ERESTARTSYS;
+
+	switch (cmd) {
+	case DMX_SET_BUFFER_SIZE:
+		ret = dvb_dvr_set_buffer_size(dmxdev, arg);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	mutex_unlock(&dmxdev->mutex);
+	return ret;
+}
+
+static long dvb_dvr_ioctl(struct file *file,
+			 unsigned int cmd, unsigned long arg)
+{
+	return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl);
+}
+
+static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dmxdev *dmxdev = dvbdev->priv;
+	unsigned int mask = 0;
+
+	dprintk("function : %s\n", __func__);
+
+	poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
+
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+		if (dmxdev->dvr_buffer.error)
+			mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
+
+		if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
+			mask |= (POLLIN | POLLRDNORM | POLLPRI);
+	} else
+		mask |= (POLLOUT | POLLWRNORM | POLLPRI);
+
+	return mask;
+}
+
+static const struct file_operations dvb_dvr_fops = {
+	.owner = THIS_MODULE,
+	.read = dvb_dvr_read,
+	.write = dvb_dvr_write,
+	.unlocked_ioctl = dvb_dvr_ioctl,
+	.open = dvb_dvr_open,
+	.release = dvb_dvr_release,
+	.poll = dvb_dvr_poll,
+	.llseek = default_llseek,
+};
+
+static struct dvb_device dvbdev_dvr = {
+	.priv = NULL,
+	.readers = 1,
+	.users = 1,
+	.fops = &dvb_dvr_fops
+};
+
+int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
+{
+	int i;
+
+	if (dmxdev->demux->open(dmxdev->demux) < 0)
+		return -EUSERS;
+
+	dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter));
+	if (!dmxdev->filter)
+		return -ENOMEM;
+
+	mutex_init(&dmxdev->mutex);
+	spin_lock_init(&dmxdev->lock);
+	for (i = 0; i < dmxdev->filternum; i++) {
+		dmxdev->filter[i].dev = dmxdev;
+		dmxdev->filter[i].buffer.data = NULL;
+		dvb_dmxdev_filter_state_set(&dmxdev->filter[i],
+					    DMXDEV_STATE_FREE);
+	}
+
+	dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
+			    DVB_DEVICE_DEMUX);
+	dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
+			    dmxdev, DVB_DEVICE_DVR);
+
+	dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(dvb_dmxdev_init);
+
+void dvb_dmxdev_release(struct dmxdev *dmxdev)
+{
+	dmxdev->exit=1;
+	if (dmxdev->dvbdev->users > 1) {
+		wait_event(dmxdev->dvbdev->wait_queue,
+				dmxdev->dvbdev->users==1);
+	}
+	if (dmxdev->dvr_dvbdev->users > 1) {
+		wait_event(dmxdev->dvr_dvbdev->wait_queue,
+				dmxdev->dvr_dvbdev->users==1);
+	}
+
+	dvb_unregister_device(dmxdev->dvbdev);
+	dvb_unregister_device(dmxdev->dvr_dvbdev);
+
+	vfree(dmxdev->filter);
+	dmxdev->filter = NULL;
+	dmxdev->demux->close(dmxdev->demux);
+}
+
+EXPORT_SYMBOL(dvb_dmxdev_release);
diff --git a/drivers/media/dvb-core/dmxdev.h b/drivers/media/dvb-core/dmxdev.h
new file mode 100644
index 0000000..02ebe28
--- /dev/null
+++ b/drivers/media/dvb-core/dmxdev.h
@@ -0,0 +1,118 @@
+/*
+ * dmxdev.h
+ *
+ * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
+ *                    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DMXDEV_H_
+#define _DMXDEV_H_
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <linux/dvb/dmx.h>
+
+#include "dvbdev.h"
+#include "demux.h"
+#include "dvb_ringbuffer.h"
+
+enum dmxdev_type {
+	DMXDEV_TYPE_NONE,
+	DMXDEV_TYPE_SEC,
+	DMXDEV_TYPE_PES,
+};
+
+enum dmxdev_state {
+	DMXDEV_STATE_FREE,
+	DMXDEV_STATE_ALLOCATED,
+	DMXDEV_STATE_SET,
+	DMXDEV_STATE_GO,
+	DMXDEV_STATE_DONE,
+	DMXDEV_STATE_TIMEDOUT
+};
+
+struct dmxdev_feed {
+	u16 pid;
+	struct dmx_ts_feed *ts;
+	struct list_head next;
+};
+
+struct dmxdev_filter {
+	union {
+		struct dmx_section_filter *sec;
+	} filter;
+
+	union {
+		/* list of TS and PES feeds (struct dmxdev_feed) */
+		struct list_head ts;
+		struct dmx_section_feed *sec;
+	} feed;
+
+	union {
+		struct dmx_sct_filter_params sec;
+		struct dmx_pes_filter_params pes;
+	} params;
+
+	enum dmxdev_type type;
+	enum dmxdev_state state;
+	struct dmxdev *dev;
+	struct dvb_ringbuffer buffer;
+
+	struct mutex mutex;
+
+	/* only for sections */
+	struct timer_list timer;
+	int todo;
+	u8 secheader[3];
+};
+
+
+struct dmxdev {
+	struct dvb_device *dvbdev;
+	struct dvb_device *dvr_dvbdev;
+
+	struct dmxdev_filter *filter;
+	struct dmx_demux *demux;
+
+	int filternum;
+	int capabilities;
+
+	unsigned int exit:1;
+#define DMXDEV_CAP_DUPLEX 1
+	struct dmx_frontend *dvr_orig_fe;
+
+	struct dvb_ringbuffer dvr_buffer;
+#define DVR_BUFFER_SIZE (10*188*1024)
+
+	struct mutex mutex;
+	spinlock_t lock;
+};
+
+
+int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *);
+void dvb_dmxdev_release(struct dmxdev *dmxdev);
+
+#endif /* _DMXDEV_H_ */
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
new file mode 100644
index 0000000..26c4481
--- /dev/null
+++ b/drivers/media/dvb-core/dvb-usb-ids.h
@@ -0,0 +1,361 @@
+/* dvb-usb-ids.h is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) see
+ * dvb-usb-init.c for copyright information.
+ *
+ * a header file containing define's for the USB device supported by the
+ * various drivers.
+ */
+#ifndef _DVB_USB_IDS_H_
+#define _DVB_USB_IDS_H_
+
+/* Vendor IDs */
+#define USB_VID_ADSTECH				0x06e1
+#define USB_VID_AFATECH				0x15a4
+#define USB_VID_ALCOR_MICRO			0x058f
+#define USB_VID_ALINK				0x05e3
+#define USB_VID_AMT				0x1c73
+#define USB_VID_ANCHOR				0x0547
+#define USB_VID_ANSONIC				0x10b9
+#define USB_VID_ANUBIS_ELECTRONIC		0x10fd
+#define USB_VID_ASUS				0x0b05
+#define USB_VID_AVERMEDIA			0x07ca
+#define USB_VID_COMPRO				0x185b
+#define USB_VID_COMPRO_UNK			0x145f
+#define USB_VID_CONEXANT			0x0572
+#define USB_VID_CYPRESS				0x04b4
+#define USB_VID_DIBCOM				0x10b8
+#define USB_VID_DPOSH				0x1498
+#define USB_VID_DVICO				0x0fe9
+#define USB_VID_E3C				0x18b4
+#define USB_VID_ELGATO				0x0fd9
+#define USB_VID_EMPIA				0xeb1a
+#define USB_VID_GENPIX				0x09c0
+#define USB_VID_GRANDTEC			0x5032
+#define USB_VID_GTEK				0x1f4d
+#define USB_VID_HANFTEK				0x15f4
+#define USB_VID_HAUPPAUGE			0x2040
+#define USB_VID_HYPER_PALTEK			0x1025
+#define USB_VID_INTEL				0x8086
+#define USB_VID_ITETECH				0x048d
+#define USB_VID_KWORLD				0xeb2a
+#define USB_VID_KWORLD_2			0x1b80
+#define USB_VID_KYE				0x0458
+#define USB_VID_LEADTEK				0x0413
+#define USB_VID_LITEON				0x04ca
+#define USB_VID_MEDION				0x1660
+#define USB_VID_MIGLIA				0x18f3
+#define USB_VID_MSI				0x0db0
+#define USB_VID_MSI_2				0x1462
+#define USB_VID_OPERA1				0x695c
+#define USB_VID_PINNACLE			0x2304
+#define USB_VID_PCTV				0x2013
+#define USB_VID_PIXELVIEW			0x1554
+#define USB_VID_REALTEK				0x0bda
+#define USB_VID_TECHNOTREND			0x0b48
+#define USB_VID_TERRATEC			0x0ccd
+#define USB_VID_TELESTAR			0x10b9
+#define USB_VID_VISIONPLUS			0x13d3
+#define USB_VID_SONY				0x1415
+#define USB_VID_TWINHAN				0x1822
+#define USB_VID_ULTIMA_ELECTRONIC		0x05d8
+#define USB_VID_UNIWILL				0x1584
+#define USB_VID_WIDEVIEW			0x14aa
+#define USB_VID_GIGABYTE			0x1044
+#define USB_VID_YUAN				0x1164
+#define USB_VID_XTENSIONS			0x1ae7
+#define USB_VID_HUMAX_COEX			0x10b9
+#define USB_VID_774				0x7a69
+#define USB_VID_EVOLUTEPC			0x1e59
+#define USB_VID_AZUREWAVE			0x13d3
+#define USB_VID_TECHNISAT			0x14f7
+
+/* Product IDs */
+#define USB_PID_ADSTECH_USB2_COLD			0xa333
+#define USB_PID_ADSTECH_USB2_WARM			0xa334
+#define USB_PID_AFATECH_AF9005				0x9020
+#define USB_PID_AFATECH_AF9015_9015			0x9015
+#define USB_PID_AFATECH_AF9015_9016			0x9016
+#define USB_PID_AFATECH_AF9035_1000			0x1000
+#define USB_PID_AFATECH_AF9035_1001			0x1001
+#define USB_PID_AFATECH_AF9035_1002			0x1002
+#define USB_PID_AFATECH_AF9035_1003			0x1003
+#define USB_PID_AFATECH_AF9035_9035			0x9035
+#define USB_PID_TREKSTOR_DVBT				0x901b
+#define USB_VID_ALINK_DTU				0xf170
+#define USB_PID_ANSONIC_DVBT_USB			0x6000
+#define USB_PID_ANYSEE					0x861f
+#define USB_PID_AZUREWAVE_AD_TU700			0x3237
+#define USB_PID_AZUREWAVE_6007				0x0ccd
+#define USB_PID_AVERMEDIA_DVBT_USB_COLD			0x0001
+#define USB_PID_AVERMEDIA_DVBT_USB_WARM			0x0002
+#define USB_PID_AVERMEDIA_DVBT_USB2_COLD		0xa800
+#define USB_PID_AVERMEDIA_DVBT_USB2_WARM		0xa801
+#define USB_PID_COMPRO_DVBU2000_COLD			0xd000
+#define USB_PID_COMPRO_DVBU2000_WARM			0xd001
+#define USB_PID_COMPRO_DVBU2000_UNK_COLD		0x010c
+#define USB_PID_COMPRO_DVBU2000_UNK_WARM		0x010d
+#define USB_PID_COMPRO_VIDEOMATE_U500			0x1e78
+#define USB_PID_COMPRO_VIDEOMATE_U500_PC		0x1e80
+#define USB_PID_CONCEPTRONIC_CTVDIGRCU			0xe397
+#define USB_PID_CONEXANT_D680_DMB			0x86d6
+#define USB_PID_CREATIX_CTX1921				0x1921
+#define USB_PID_DELOCK_USB2_DVBT			0xb803
+#define USB_PID_DIBCOM_HOOK_DEFAULT			0x0064
+#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM		0x0065
+#define USB_PID_DIBCOM_MOD3000_COLD			0x0bb8
+#define USB_PID_DIBCOM_MOD3000_WARM			0x0bb9
+#define USB_PID_DIBCOM_MOD3001_COLD			0x0bc6
+#define USB_PID_DIBCOM_MOD3001_WARM			0x0bc7
+#define USB_PID_DIBCOM_STK7700P				0x1e14
+#define USB_PID_DIBCOM_STK7700P_PC			0x1e78
+#define USB_PID_DIBCOM_STK7700D				0x1ef0
+#define USB_PID_DIBCOM_STK7700_U7000			0x7001
+#define USB_PID_DIBCOM_STK7070P				0x1ebc
+#define USB_PID_DIBCOM_STK7070PD			0x1ebe
+#define USB_PID_DIBCOM_STK807XP				0x1f90
+#define USB_PID_DIBCOM_STK807XPVR			0x1f98
+#define USB_PID_DIBCOM_STK8096GP                        0x1fa0
+#define USB_PID_DIBCOM_NIM8096MD                        0x1fa8
+#define USB_PID_DIBCOM_TFE8096P				0x1f9C
+#define USB_PID_DIBCOM_ANCHOR_2135_COLD			0x2131
+#define USB_PID_DIBCOM_STK7770P				0x1e80
+#define USB_PID_DIBCOM_NIM7090				0x1bb2
+#define USB_PID_DIBCOM_TFE7090PVR			0x1bb4
+#define USB_PID_DIBCOM_TFE7090E				0x1bb7
+#define USB_PID_DIBCOM_TFE7790E				0x1e6e
+#define USB_PID_DIBCOM_NIM9090M				0x2383
+#define USB_PID_DIBCOM_NIM9090MD			0x2384
+#define USB_PID_DPOSH_M9206_COLD			0x9206
+#define USB_PID_DPOSH_M9206_WARM			0xa090
+#define USB_PID_E3C_EC168				0x1689
+#define USB_PID_E3C_EC168_2				0xfffa
+#define USB_PID_E3C_EC168_3				0xfffb
+#define USB_PID_E3C_EC168_4				0x1001
+#define USB_PID_E3C_EC168_5				0x1002
+#define USB_PID_FREECOM_DVBT				0x0160
+#define USB_PID_FREECOM_DVBT_2				0x0161
+#define USB_PID_UNIWILL_STK7700P			0x6003
+#define USB_PID_GENIUS_TVGO_DVB_T03			0x4012
+#define USB_PID_GRANDTEC_DVBT_USB_COLD			0x0fa0
+#define USB_PID_GRANDTEC_DVBT_USB_WARM			0x0fa1
+#define USB_PID_INTEL_CE9500				0x9500
+#define USB_PID_ITETECH_IT9135				0x9135
+#define USB_PID_ITETECH_IT9135_9005			0x9005
+#define USB_PID_ITETECH_IT9135_9006			0x9006
+#define USB_PID_KWORLD_399U				0xe399
+#define USB_PID_KWORLD_399U_2				0xe400
+#define USB_PID_KWORLD_395U				0xe396
+#define USB_PID_KWORLD_395U_2				0xe39b
+#define USB_PID_KWORLD_395U_3				0xe395
+#define USB_PID_KWORLD_395U_4				0xe39a
+#define USB_PID_KWORLD_MC810				0xc810
+#define USB_PID_KWORLD_PC160_2T				0xc160
+#define USB_PID_KWORLD_PC160_T				0xc161
+#define USB_PID_KWORLD_UB383_T				0xe383
+#define USB_PID_KWORLD_UB499_2T_T09			0xe409
+#define USB_PID_KWORLD_VSTREAM_COLD			0x17de
+#define USB_PID_KWORLD_VSTREAM_WARM			0x17df
+#define USB_PID_TERRATEC_CINERGY_T_USB_XE		0x0055
+#define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2		0x0069
+#define USB_PID_TERRATEC_CINERGY_T_STICK		0x0093
+#define USB_PID_TERRATEC_CINERGY_T_STICK_RC		0x0097
+#define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC	0x0099
+#define USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1	0x00a9
+#define USB_PID_TWINHAN_VP7041_COLD			0x3201
+#define USB_PID_TWINHAN_VP7041_WARM			0x3202
+#define USB_PID_TWINHAN_VP7020_COLD			0x3203
+#define USB_PID_TWINHAN_VP7020_WARM			0x3204
+#define USB_PID_TWINHAN_VP7045_COLD			0x3205
+#define USB_PID_TWINHAN_VP7045_WARM			0x3206
+#define USB_PID_TWINHAN_VP7021_COLD			0x3207
+#define USB_PID_TWINHAN_VP7021_WARM			0x3208
+#define USB_PID_TINYTWIN				0x3226
+#define USB_PID_TINYTWIN_2				0xe402
+#define USB_PID_TINYTWIN_3				0x9016
+#define USB_PID_DNTV_TINYUSB2_COLD			0x3223
+#define USB_PID_DNTV_TINYUSB2_WARM			0x3224
+#define USB_PID_ULTIMA_TVBOX_COLD			0x8105
+#define USB_PID_ULTIMA_TVBOX_WARM			0x8106
+#define USB_PID_ULTIMA_TVBOX_AN2235_COLD		0x8107
+#define USB_PID_ULTIMA_TVBOX_AN2235_WARM		0x8108
+#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD		0x2235
+#define USB_PID_ULTIMA_TVBOX_USB2_COLD			0x8109
+#define USB_PID_ULTIMA_TVBOX_USB2_WARM			0x810a
+#define USB_PID_ARTEC_T14_COLD				0x810b
+#define USB_PID_ARTEC_T14_WARM				0x810c
+#define USB_PID_ARTEC_T14BR				0x810f
+#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD		0x8613
+#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM		0x1002
+#define USB_PID_UNK_HYPER_PALTEK_COLD			0x005e
+#define USB_PID_UNK_HYPER_PALTEK_WARM			0x005f
+#define USB_PID_HANFTEK_UMT_010_COLD			0x0001
+#define USB_PID_HANFTEK_UMT_010_WARM			0x0015
+#define USB_PID_DTT200U_COLD				0x0201
+#define USB_PID_DTT200U_WARM				0x0301
+#define USB_PID_WT220U_ZAP250_COLD			0x0220
+#define USB_PID_WT220U_COLD				0x0222
+#define USB_PID_WT220U_WARM				0x0221
+#define USB_PID_WT220U_FC_COLD				0x0225
+#define USB_PID_WT220U_FC_WARM				0x0226
+#define USB_PID_WT220U_ZL0353_COLD			0x022a
+#define USB_PID_WT220U_ZL0353_WARM			0x022b
+#define USB_PID_WINTV_NOVA_T_USB2_COLD			0x9300
+#define USB_PID_WINTV_NOVA_T_USB2_WARM			0x9301
+#define USB_PID_HAUPPAUGE_NOVA_T_500			0x9941
+#define USB_PID_HAUPPAUGE_NOVA_T_500_2			0x9950
+#define USB_PID_HAUPPAUGE_NOVA_T_500_3			0x8400
+#define USB_PID_HAUPPAUGE_NOVA_T_STICK			0x7050
+#define USB_PID_HAUPPAUGE_NOVA_T_STICK_2		0x7060
+#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3		0x7070
+#define USB_PID_HAUPPAUGE_MYTV_T			0x7080
+#define USB_PID_HAUPPAUGE_NOVA_TD_STICK			0x9580
+#define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009		0x5200
+#define USB_PID_HAUPPAUGE_TIGER_ATSC			0xb200
+#define USB_PID_HAUPPAUGE_TIGER_ATSC_B210		0xb210
+#define USB_PID_AVERMEDIA_EXPRESS			0xb568
+#define USB_PID_AVERMEDIA_VOLAR				0xa807
+#define USB_PID_AVERMEDIA_VOLAR_2			0xb808
+#define USB_PID_AVERMEDIA_VOLAR_A868R			0xa868
+#define USB_PID_AVERMEDIA_MCE_USB_M038			0x1228
+#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R	0x0039
+#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC	0x1039
+#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT	0x2039
+#define USB_PID_AVERMEDIA_VOLAR_X			0xa815
+#define USB_PID_AVERMEDIA_VOLAR_X_2			0x8150
+#define USB_PID_AVERMEDIA_A309				0xa309
+#define USB_PID_AVERMEDIA_A310				0xa310
+#define USB_PID_AVERMEDIA_A850				0x850a
+#define USB_PID_AVERMEDIA_A850T				0x850b
+#define USB_PID_AVERMEDIA_A805				0xa805
+#define USB_PID_AVERMEDIA_A815M				0x815a
+#define USB_PID_AVERMEDIA_A835				0xa835
+#define USB_PID_AVERMEDIA_B835				0xb835
+#define USB_PID_AVERMEDIA_1867				0x1867
+#define USB_PID_AVERMEDIA_A867				0xa867
+#define USB_PID_AVERMEDIA_TWINSTAR			0x0825
+#define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
+#define USB_PID_TECHNOTREND_CONNECT_CT3650		0x300d
+#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY	0x005a
+#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2	0x0081
+#define USB_PID_TERRATEC_CINERGY_HT_USB_XE		0x0058
+#define USB_PID_TERRATEC_CINERGY_HT_EXPRESS		0x0060
+#define USB_PID_TERRATEC_CINERGY_T_EXPRESS		0x0062
+#define USB_PID_TERRATEC_CINERGY_T_XXS			0x0078
+#define USB_PID_TERRATEC_CINERGY_T_XXS_2		0x00ab
+#define USB_PID_TERRATEC_H7				0x10b4
+#define USB_PID_TERRATEC_H7_2				0x10a3
+#define USB_PID_TERRATEC_T3				0x10a0
+#define USB_PID_TERRATEC_T5				0x10a1
+#define USB_PID_NOXON_DAB_STICK				0x00b3
+#define USB_PID_PINNACLE_EXPRESSCARD_320CX		0x022e
+#define USB_PID_PINNACLE_PCTV2000E			0x022c
+#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH		0x0228
+#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T	0x0229
+#define USB_PID_PINNACLE_PCTV71E			0x022b
+#define USB_PID_PINNACLE_PCTV72E			0x0236
+#define USB_PID_PINNACLE_PCTV73E			0x0237
+#define USB_PID_PINNACLE_PCTV310E			0x3211
+#define USB_PID_PINNACLE_PCTV801E			0x023a
+#define USB_PID_PINNACLE_PCTV801E_SE			0x023b
+#define USB_PID_PINNACLE_PCTV340E			0x023d
+#define USB_PID_PINNACLE_PCTV340E_SE			0x023e
+#define USB_PID_PINNACLE_PCTV73A			0x0243
+#define USB_PID_PINNACLE_PCTV73ESE			0x0245
+#define USB_PID_PINNACLE_PCTV74E			0x0246
+#define USB_PID_PINNACLE_PCTV282E			0x0248
+#define USB_PID_PIXELVIEW_SBTVD				0x5010
+#define USB_PID_PCTV_200E				0x020e
+#define USB_PID_PCTV_400E				0x020f
+#define USB_PID_PCTV_450E				0x0222
+#define USB_PID_PCTV_452E				0x021f
+#define USB_PID_REALTEK_RTL2831U			0x2831
+#define USB_PID_REALTEK_RTL2832U			0x2832
+#define USB_PID_TECHNOTREND_CONNECT_S2_3600		0x3007
+#define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI		0x300a
+#define USB_PID_NEBULA_DIGITV				0x0201
+#define USB_PID_DVICO_BLUEBIRD_LGDT			0xd820
+#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD		0xd500
+#define USB_PID_DVICO_BLUEBIRD_LG064F_WARM		0xd501
+#define USB_PID_DVICO_BLUEBIRD_LGZ201_COLD		0xdb00
+#define USB_PID_DVICO_BLUEBIRD_LGZ201_WARM		0xdb01
+#define USB_PID_DVICO_BLUEBIRD_TH7579_COLD		0xdb10
+#define USB_PID_DVICO_BLUEBIRD_TH7579_WARM		0xdb11
+#define USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD		0xdb50
+#define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM		0xdb51
+#define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD		0xdb58
+#define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM		0xdb59
+#define USB_PID_DVICO_BLUEBIRD_DUAL_4			0xdb78
+#define USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2		0xdb98
+#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2		0xdb70
+#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM	0xdb71
+#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD		0xdb54
+#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM		0xdb55
+#define USB_PID_MEDION_MD95700				0x0932
+#define USB_PID_MSI_MEGASKY580				0x5580
+#define USB_PID_MSI_MEGASKY580_55801			0x5581
+#define USB_PID_KYE_DVB_T_COLD				0x701e
+#define USB_PID_KYE_DVB_T_WARM				0x701f
+#define USB_PID_LITEON_DVB_T_COLD			0xf000
+#define USB_PID_LITEON_DVB_T_WARM			0xf001
+#define USB_PID_DIGIVOX_MINI_SL_COLD			0xe360
+#define USB_PID_DIGIVOX_MINI_SL_WARM			0xe361
+#define USB_PID_GRANDTEC_DVBT_USB2_COLD			0x0bc6
+#define USB_PID_GRANDTEC_DVBT_USB2_WARM			0x0bc7
+#define USB_PID_WINFAST_DTV2000DS			0x6a04
+#define USB_PID_WINFAST_DTV_DONGLE_COLD			0x6025
+#define USB_PID_WINFAST_DTV_DONGLE_WARM			0x6026
+#define USB_PID_WINFAST_DTV_DONGLE_STK7700P		0x6f00
+#define USB_PID_WINFAST_DTV_DONGLE_H			0x60f6
+#define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2		0x6f01
+#define USB_PID_WINFAST_DTV_DONGLE_GOLD			0x6029
+#define USB_PID_GENPIX_8PSK_REV_1_COLD			0x0200
+#define USB_PID_GENPIX_8PSK_REV_1_WARM			0x0201
+#define USB_PID_GENPIX_8PSK_REV_2			0x0202
+#define USB_PID_GENPIX_SKYWALKER_1			0x0203
+#define USB_PID_GENPIX_SKYWALKER_CW3K			0x0204
+#define USB_PID_GENPIX_SKYWALKER_2			0x0206
+#define USB_PID_SIGMATEK_DVB_110			0x6610
+#define USB_PID_MSI_DIGI_VOX_MINI_II			0x1513
+#define USB_PID_MSI_DIGIVOX_DUO				0x8801
+#define USB_PID_OPERA1_COLD				0x2830
+#define USB_PID_OPERA1_WARM				0x3829
+#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD		0x0514
+#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM		0x0513
+#define USB_PID_GIGABYTE_U7000				0x7001
+#define USB_PID_GIGABYTE_U8000				0x7002
+#define USB_PID_ASUS_U3000				0x171f
+#define USB_PID_ASUS_U3000H				0x1736
+#define USB_PID_ASUS_U3100				0x173f
+#define USB_PID_YUAN_EC372S				0x1edc
+#define USB_PID_YUAN_STK7700PH				0x1f08
+#define USB_PID_YUAN_PD378S				0x2edc
+#define USB_PID_YUAN_MC770				0x0871
+#define USB_PID_YUAN_STK7700D				0x1efc
+#define USB_PID_YUAN_STK7700D_2				0x1e8c
+#define USB_PID_DW2102					0x2102
+#define USB_PID_XTENSIONS_XD_380			0x0381
+#define USB_PID_TELESTAR_STARSTICK_2			0x8000
+#define USB_PID_MSI_DIGI_VOX_MINI_III                   0x8807
+#define USB_PID_SONY_PLAYTV				0x0003
+#define USB_PID_MYGICA_D689				0xd811
+#define USB_PID_ELGATO_EYETV_DIVERSITY			0x0011
+#define USB_PID_ELGATO_EYETV_DTT			0x0021
+#define USB_PID_ELGATO_EYETV_DTT_2			0x003f
+#define USB_PID_ELGATO_EYETV_DTT_Dlx			0x0020
+#define USB_PID_ELGATO_EYETV_SAT			0x002a
+#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD		0x5000
+#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM		0x5001
+#define USB_PID_FRIIO_WHITE				0x0001
+#define USB_PID_TVWAY_PLUS				0x0002
+#define USB_PID_SVEON_STV20				0xe39d
+#define USB_PID_SVEON_STV22				0xe401
+#define USB_PID_SVEON_STV22_IT9137			0xe411
+#define USB_PID_AZUREWAVE_AZ6027			0x3275
+#define USB_PID_TERRATEC_DVBS2CI_V1			0x10a4
+#define USB_PID_TERRATEC_DVBS2CI_V2			0x10ac
+#define USB_PID_TECHNISAT_USB2_HDCI_V1			0x0001
+#define USB_PID_TECHNISAT_USB2_HDCI_V2			0x0002
+#define USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2		0x0004
+#define USB_PID_TECHNISAT_USB2_DVB_S2			0x0500
+#endif
diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
new file mode 100644
index 0000000..9be65a3
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_ca_en50221.c
@@ -0,0 +1,1753 @@
+/*
+ * dvb_ca.c: generic DVB functions for EN50221 CAM interfaces
+ *
+ * Copyright (C) 2004 Andrew de Quincey
+ *
+ * Parts of this file were based on sources as follows:
+ *
+ * Copyright (C) 2003 Ralph Metzler <rjkm@metzlerbros.de>
+ *
+ * based on code:
+ *
+ * Copyright (C) 1999-2002 Ralph  Metzler
+ *                       & Marcus Metzler for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+
+#include "dvb_ca_en50221.h"
+#include "dvb_ringbuffer.h"
+
+static int dvb_ca_en50221_debug;
+
+module_param_named(cam_debug, dvb_ca_en50221_debug, int, 0644);
+MODULE_PARM_DESC(cam_debug, "enable verbose debug messages");
+
+#define dprintk if (dvb_ca_en50221_debug) printk
+
+#define INIT_TIMEOUT_SECS 10
+
+#define HOST_LINK_BUF_SIZE 0x200
+
+#define RX_BUFFER_SIZE 65535
+
+#define MAX_RX_PACKETS_PER_ITERATION 10
+
+#define CTRLIF_DATA      0
+#define CTRLIF_COMMAND   1
+#define CTRLIF_STATUS    1
+#define CTRLIF_SIZE_LOW  2
+#define CTRLIF_SIZE_HIGH 3
+
+#define CMDREG_HC        1	/* Host control */
+#define CMDREG_SW        2	/* Size write */
+#define CMDREG_SR        4	/* Size read */
+#define CMDREG_RS        8	/* Reset interface */
+#define CMDREG_FRIE   0x40	/* Enable FR interrupt */
+#define CMDREG_DAIE   0x80	/* Enable DA interrupt */
+#define IRQEN (CMDREG_DAIE)
+
+#define STATUSREG_RE     1	/* read error */
+#define STATUSREG_WE     2	/* write error */
+#define STATUSREG_FR  0x40	/* module free */
+#define STATUSREG_DA  0x80	/* data available */
+#define STATUSREG_TXERR (STATUSREG_RE|STATUSREG_WE)	/* general transfer error */
+
+
+#define DVB_CA_SLOTSTATE_NONE           0
+#define DVB_CA_SLOTSTATE_UNINITIALISED  1
+#define DVB_CA_SLOTSTATE_RUNNING        2
+#define DVB_CA_SLOTSTATE_INVALID        3
+#define DVB_CA_SLOTSTATE_WAITREADY      4
+#define DVB_CA_SLOTSTATE_VALIDATE       5
+#define DVB_CA_SLOTSTATE_WAITFR         6
+#define DVB_CA_SLOTSTATE_LINKINIT       7
+
+
+/* Information on a CA slot */
+struct dvb_ca_slot {
+
+	/* current state of the CAM */
+	int slot_state;
+
+	/* mutex used for serializing access to one CI slot */
+	struct mutex slot_lock;
+
+	/* Number of CAMCHANGES that have occurred since last processing */
+	atomic_t camchange_count;
+
+	/* Type of last CAMCHANGE */
+	int camchange_type;
+
+	/* base address of CAM config */
+	u32 config_base;
+
+	/* value to write into Config Control register */
+	u8 config_option;
+
+	/* if 1, the CAM supports DA IRQs */
+	u8 da_irq_supported:1;
+
+	/* size of the buffer to use when talking to the CAM */
+	int link_buf_size;
+
+	/* buffer for incoming packets */
+	struct dvb_ringbuffer rx_buffer;
+
+	/* timer used during various states of the slot */
+	unsigned long timeout;
+};
+
+/* Private CA-interface information */
+struct dvb_ca_private {
+
+	/* pointer back to the public data structure */
+	struct dvb_ca_en50221 *pub;
+
+	/* the DVB device */
+	struct dvb_device *dvbdev;
+
+	/* Flags describing the interface (DVB_CA_FLAG_*) */
+	u32 flags;
+
+	/* number of slots supported by this CA interface */
+	unsigned int slot_count;
+
+	/* information on each slot */
+	struct dvb_ca_slot *slot_info;
+
+	/* wait queues for read() and write() operations */
+	wait_queue_head_t wait_queue;
+
+	/* PID of the monitoring thread */
+	struct task_struct *thread;
+
+	/* Flag indicating if the CA device is open */
+	unsigned int open:1;
+
+	/* Flag indicating the thread should wake up now */
+	unsigned int wakeup:1;
+
+	/* Delay the main thread should use */
+	unsigned long delay;
+
+	/* Slot to start looking for data to read from in the next user-space read operation */
+	int next_read_slot;
+};
+
+static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca);
+static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount);
+static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount);
+
+
+/**
+ * Safely find needle in haystack.
+ *
+ * @param haystack Buffer to look in.
+ * @param hlen Number of bytes in haystack.
+ * @param needle Buffer to find.
+ * @param nlen Number of bytes in needle.
+ * @return Pointer into haystack needle was found at, or NULL if not found.
+ */
+static char *findstr(char * haystack, int hlen, char * needle, int nlen)
+{
+	int i;
+
+	if (hlen < nlen)
+		return NULL;
+
+	for (i = 0; i <= hlen - nlen; i++) {
+		if (!strncmp(haystack + i, needle, nlen))
+			return haystack + i;
+	}
+
+	return NULL;
+}
+
+
+
+/* ******************************************************************************** */
+/* EN50221 physical interface functions */
+
+
+/**
+ * Check CAM status.
+ */
+static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot)
+{
+	int slot_status;
+	int cam_present_now;
+	int cam_changed;
+
+	/* IRQ mode */
+	if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) {
+		return (atomic_read(&ca->slot_info[slot].camchange_count) != 0);
+	}
+
+	/* poll mode */
+	slot_status = ca->pub->poll_slot_status(ca->pub, slot, ca->open);
+
+	cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1 : 0;
+	cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1 : 0;
+	if (!cam_changed) {
+		int cam_present_old = (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE);
+		cam_changed = (cam_present_now != cam_present_old);
+	}
+
+	if (cam_changed) {
+		if (!cam_present_now) {
+			ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
+		} else {
+			ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_INSERTED;
+		}
+		atomic_set(&ca->slot_info[slot].camchange_count, 1);
+	} else {
+		if ((ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) &&
+		    (slot_status & DVB_CA_EN50221_POLL_CAM_READY)) {
+			// move to validate state if reset is completed
+			ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;
+		}
+	}
+
+	return cam_changed;
+}
+
+
+/**
+ * Wait for flags to become set on the STATUS register on a CAM interface,
+ * checking for errors and timeout.
+ *
+ * @param ca CA instance.
+ * @param slot Slot on interface.
+ * @param waitfor Flags to wait for.
+ * @param timeout_ms Timeout in milliseconds.
+ *
+ * @return 0 on success, nonzero on error.
+ */
+static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot,
+					 u8 waitfor, int timeout_hz)
+{
+	unsigned long timeout;
+	unsigned long start;
+
+	dprintk("%s\n", __func__);
+
+	/* loop until timeout elapsed */
+	start = jiffies;
+	timeout = jiffies + timeout_hz;
+	while (1) {
+		/* read the status and check for error */
+		int res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
+		if (res < 0)
+			return -EIO;
+
+		/* if we got the flags, it was successful! */
+		if (res & waitfor) {
+			dprintk("%s succeeded timeout:%lu\n", __func__, jiffies - start);
+			return 0;
+		}
+
+		/* check for timeout */
+		if (time_after(jiffies, timeout)) {
+			break;
+		}
+
+		/* wait for a bit */
+		msleep(1);
+	}
+
+	dprintk("%s failed timeout:%lu\n", __func__, jiffies - start);
+
+	/* if we get here, we've timed out */
+	return -ETIMEDOUT;
+}
+
+
+/**
+ * Initialise the link layer connection to a CAM.
+ *
+ * @param ca CA instance.
+ * @param slot Slot id.
+ *
+ * @return 0 on success, nonzero on failure.
+ */
+static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
+{
+	int ret;
+	int buf_size;
+	u8 buf[2];
+
+	dprintk("%s\n", __func__);
+
+	/* we'll be determining these during this function */
+	ca->slot_info[slot].da_irq_supported = 0;
+
+	/* set the host link buffer size temporarily. it will be overwritten with the
+	 * real negotiated size later. */
+	ca->slot_info[slot].link_buf_size = 2;
+
+	/* read the buffer size from the CAM */
+	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0)
+		return ret;
+	if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ / 10)) != 0)
+		return ret;
+	if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2)
+		return -EIO;
+	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0)
+		return ret;
+
+	/* store it, and choose the minimum of our buffer and the CAM's buffer size */
+	buf_size = (buf[0] << 8) | buf[1];
+	if (buf_size > HOST_LINK_BUF_SIZE)
+		buf_size = HOST_LINK_BUF_SIZE;
+	ca->slot_info[slot].link_buf_size = buf_size;
+	buf[0] = buf_size >> 8;
+	buf[1] = buf_size & 0xff;
+	dprintk("Chosen link buffer size of %i\n", buf_size);
+
+	/* write the buffer size to the CAM */
+	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SW)) != 0)
+		return ret;
+	if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10)) != 0)
+		return ret;
+	if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2)
+		return -EIO;
+	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0)
+		return ret;
+
+	/* success */
+	return 0;
+}
+
+/**
+ * Read a tuple from attribute memory.
+ *
+ * @param ca CA instance.
+ * @param slot Slot id.
+ * @param address Address to read from. Updated.
+ * @param tupleType Tuple id byte. Updated.
+ * @param tupleLength Tuple length. Updated.
+ * @param tuple Dest buffer for tuple (must be 256 bytes). Updated.
+ *
+ * @return 0 on success, nonzero on error.
+ */
+static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot,
+				     int *address, int *tupleType, int *tupleLength, u8 * tuple)
+{
+	int i;
+	int _tupleType;
+	int _tupleLength;
+	int _address = *address;
+
+	/* grab the next tuple length and type */
+	if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0)
+		return _tupleType;
+	if (_tupleType == 0xff) {
+		dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType);
+		*address += 2;
+		*tupleType = _tupleType;
+		*tupleLength = 0;
+		return 0;
+	}
+	if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address + 2)) < 0)
+		return _tupleLength;
+	_address += 4;
+
+	dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength);
+
+	/* read in the whole tuple */
+	for (i = 0; i < _tupleLength; i++) {
+		tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, _address + (i * 2));
+		dprintk("  0x%02x: 0x%02x %c\n",
+			i, tuple[i] & 0xff,
+			((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.');
+	}
+	_address += (_tupleLength * 2);
+
+	// success
+	*tupleType = _tupleType;
+	*tupleLength = _tupleLength;
+	*address = _address;
+	return 0;
+}
+
+
+/**
+ * Parse attribute memory of a CAM module, extracting Config register, and checking
+ * it is a DVB CAM module.
+ *
+ * @param ca CA instance.
+ * @param slot Slot id.
+ *
+ * @return 0 on success, <0 on failure.
+ */
+static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
+{
+	int address = 0;
+	int tupleLength;
+	int tupleType;
+	u8 tuple[257];
+	char *dvb_str;
+	int rasz;
+	int status;
+	int got_cftableentry = 0;
+	int end_chain = 0;
+	int i;
+	u16 manfid = 0;
+	u16 devid = 0;
+
+
+	// CISTPL_DEVICE_0A
+	if ((status =
+	     dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
+		return status;
+	if (tupleType != 0x1D)
+		return -EINVAL;
+
+
+
+	// CISTPL_DEVICE_0C
+	if ((status =
+	     dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
+		return status;
+	if (tupleType != 0x1C)
+		return -EINVAL;
+
+
+
+	// CISTPL_VERS_1
+	if ((status =
+	     dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
+		return status;
+	if (tupleType != 0x15)
+		return -EINVAL;
+
+
+
+	// CISTPL_MANFID
+	if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
+						&tupleLength, tuple)) < 0)
+		return status;
+	if (tupleType != 0x20)
+		return -EINVAL;
+	if (tupleLength != 4)
+		return -EINVAL;
+	manfid = (tuple[1] << 8) | tuple[0];
+	devid = (tuple[3] << 8) | tuple[2];
+
+
+
+	// CISTPL_CONFIG
+	if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
+						&tupleLength, tuple)) < 0)
+		return status;
+	if (tupleType != 0x1A)
+		return -EINVAL;
+	if (tupleLength < 3)
+		return -EINVAL;
+
+	/* extract the configbase */
+	rasz = tuple[0] & 3;
+	if (tupleLength < (3 + rasz + 14))
+		return -EINVAL;
+	ca->slot_info[slot].config_base = 0;
+	for (i = 0; i < rasz + 1; i++) {
+		ca->slot_info[slot].config_base |= (tuple[2 + i] << (8 * i));
+	}
+
+	/* check it contains the correct DVB string */
+	dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8);
+	if (dvb_str == NULL)
+		return -EINVAL;
+	if (tupleLength < ((dvb_str - (char *) tuple) + 12))
+		return -EINVAL;
+
+	/* is it a version we support? */
+	if (strncmp(dvb_str + 8, "1.00", 4)) {
+		printk("dvb_ca adapter %d: Unsupported DVB CAM module version %c%c%c%c\n",
+		       ca->dvbdev->adapter->num, dvb_str[8], dvb_str[9], dvb_str[10], dvb_str[11]);
+		return -EINVAL;
+	}
+
+	/* process the CFTABLE_ENTRY tuples, and any after those */
+	while ((!end_chain) && (address < 0x1000)) {
+		if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
+							&tupleLength, tuple)) < 0)
+			return status;
+		switch (tupleType) {
+		case 0x1B:	// CISTPL_CFTABLE_ENTRY
+			if (tupleLength < (2 + 11 + 17))
+				break;
+
+			/* if we've already parsed one, just use it */
+			if (got_cftableentry)
+				break;
+
+			/* get the config option */
+			ca->slot_info[slot].config_option = tuple[0] & 0x3f;
+
+			/* OK, check it contains the correct strings */
+			if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
+			    (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
+				break;
+
+			got_cftableentry = 1;
+			break;
+
+		case 0x14:	// CISTPL_NO_LINK
+			break;
+
+		case 0xFF:	// CISTPL_END
+			end_chain = 1;
+			break;
+
+		default:	/* Unknown tuple type - just skip this tuple and move to the next one */
+			dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", tupleType,
+				tupleLength);
+			break;
+		}
+	}
+
+	if ((address > 0x1000) || (!got_cftableentry))
+		return -EINVAL;
+
+	dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n",
+		manfid, devid, ca->slot_info[slot].config_base, ca->slot_info[slot].config_option);
+
+	// success!
+	return 0;
+}
+
+
+/**
+ * Set CAM's configoption correctly.
+ *
+ * @param ca CA instance.
+ * @param slot Slot containing the CAM.
+ */
+static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot)
+{
+	int configoption;
+
+	dprintk("%s\n", __func__);
+
+	/* set the config option */
+	ca->pub->write_attribute_mem(ca->pub, slot,
+				     ca->slot_info[slot].config_base,
+				     ca->slot_info[slot].config_option);
+
+	/* check it */
+	configoption = ca->pub->read_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base);
+	dprintk("Set configoption 0x%x, read configoption 0x%x\n",
+		ca->slot_info[slot].config_option, configoption & 0x3f);
+
+	/* fine! */
+	return 0;
+
+}
+
+
+/**
+ * This function talks to an EN50221 CAM control interface. It reads a buffer of
+ * data from the CAM. The data can either be stored in a supplied buffer, or
+ * automatically be added to the slot's rx_buffer.
+ *
+ * @param ca CA instance.
+ * @param slot Slot to read from.
+ * @param ebuf If non-NULL, the data will be written to this buffer. If NULL,
+ * the data will be added into the buffering system as a normal fragment.
+ * @param ecount Size of ebuf. Ignored if ebuf is NULL.
+ *
+ * @return Number of bytes read, or < 0 on error
+ */
+static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount)
+{
+	int bytes_read;
+	int status;
+	u8 buf[HOST_LINK_BUF_SIZE];
+	int i;
+
+	dprintk("%s\n", __func__);
+
+	/* check if we have space for a link buf in the rx_buffer */
+	if (ebuf == NULL) {
+		int buf_free;
+
+		if (ca->slot_info[slot].rx_buffer.data == NULL) {
+			status = -EIO;
+			goto exit;
+		}
+		buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer);
+
+		if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) {
+			status = -EAGAIN;
+			goto exit;
+		}
+	}
+
+	/* check if there is data available */
+	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
+		goto exit;
+	if (!(status & STATUSREG_DA)) {
+		/* no data */
+		status = 0;
+		goto exit;
+	}
+
+	/* read the amount of data */
+	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0)
+		goto exit;
+	bytes_read = status << 8;
+	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0)
+		goto exit;
+	bytes_read |= status;
+
+	/* check it will fit */
+	if (ebuf == NULL) {
+		if (bytes_read > ca->slot_info[slot].link_buf_size) {
+			printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n",
+			       ca->dvbdev->adapter->num, bytes_read, ca->slot_info[slot].link_buf_size);
+			ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+			status = -EIO;
+			goto exit;
+		}
+		if (bytes_read < 2) {
+			printk("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n",
+			       ca->dvbdev->adapter->num);
+			ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+			status = -EIO;
+			goto exit;
+		}
+	} else {
+		if (bytes_read > ecount) {
+			printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n",
+			       ca->dvbdev->adapter->num);
+			status = -EIO;
+			goto exit;
+		}
+	}
+
+	/* fill the buffer */
+	for (i = 0; i < bytes_read; i++) {
+		/* read byte and check */
+		if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0)
+			goto exit;
+
+		/* OK, store it in the buffer */
+		buf[i] = status;
+	}
+
+	/* check for read error (RE should now be 0) */
+	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
+		goto exit;
+	if (status & STATUSREG_RE) {
+		ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+		status = -EIO;
+		goto exit;
+	}
+
+	/* OK, add it to the receive buffer, or copy into external buffer if supplied */
+	if (ebuf == NULL) {
+		if (ca->slot_info[slot].rx_buffer.data == NULL) {
+			status = -EIO;
+			goto exit;
+		}
+		dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read);
+	} else {
+		memcpy(ebuf, buf, bytes_read);
+	}
+
+	dprintk("Received CA packet for slot %i connection id 0x%x last_frag:%i size:0x%x\n", slot,
+		buf[0], (buf[1] & 0x80) == 0, bytes_read);
+
+	/* wake up readers when a last_fragment is received */
+	if ((buf[1] & 0x80) == 0x00) {
+		wake_up_interruptible(&ca->wait_queue);
+	}
+	status = bytes_read;
+
+exit:
+	return status;
+}
+
+
+/**
+ * This function talks to an EN50221 CAM control interface. It writes a buffer of data
+ * to a CAM.
+ *
+ * @param ca CA instance.
+ * @param slot Slot to write to.
+ * @param ebuf The data in this buffer is treated as a complete link-level packet to
+ * be written.
+ * @param count Size of ebuf.
+ *
+ * @return Number of bytes written, or < 0 on error.
+ */
+static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * buf, int bytes_write)
+{
+	int status;
+	int i;
+
+	dprintk("%s\n", __func__);
+
+
+	/* sanity check */
+	if (bytes_write > ca->slot_info[slot].link_buf_size)
+		return -EINVAL;
+
+	/* it is possible we are dealing with a single buffer implementation,
+	   thus if there is data available for read or if there is even a read
+	   already in progress, we do nothing but awake the kernel thread to
+	   process the data if necessary. */
+	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
+		goto exitnowrite;
+	if (status & (STATUSREG_DA | STATUSREG_RE)) {
+		if (status & STATUSREG_DA)
+			dvb_ca_en50221_thread_wakeup(ca);
+
+		status = -EAGAIN;
+		goto exitnowrite;
+	}
+
+	/* OK, set HC bit */
+	if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
+						 IRQEN | CMDREG_HC)) != 0)
+		goto exit;
+
+	/* check if interface is still free */
+	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
+		goto exit;
+	if (!(status & STATUSREG_FR)) {
+		/* it wasn't free => try again later */
+		status = -EAGAIN;
+		goto exit;
+	}
+
+	/* send the amount of data */
+	if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0)
+		goto exit;
+	if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW,
+						 bytes_write & 0xff)) != 0)
+		goto exit;
+
+	/* send the buffer */
+	for (i = 0; i < bytes_write; i++) {
+		if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, buf[i])) != 0)
+			goto exit;
+	}
+
+	/* check for write error (WE should now be 0) */
+	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
+		goto exit;
+	if (status & STATUSREG_WE) {
+		ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+		status = -EIO;
+		goto exit;
+	}
+	status = bytes_write;
+
+	dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i size:0x%x\n", slot,
+		buf[0], (buf[1] & 0x80) == 0, bytes_write);
+
+exit:
+	ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
+
+exitnowrite:
+	return status;
+}
+EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq);
+
+
+
+/* ******************************************************************************** */
+/* EN50221 higher level functions */
+
+
+/**
+ * A CAM has been removed => shut it down.
+ *
+ * @param ca CA instance.
+ * @param slot Slot to shut down.
+ */
+static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot)
+{
+	dprintk("%s\n", __func__);
+
+	ca->pub->slot_shutdown(ca->pub, slot);
+	ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+
+	/* need to wake up all processes to check if they're now
+	   trying to write to a defunct CAM */
+	wake_up_interruptible(&ca->wait_queue);
+
+	dprintk("Slot %i shutdown\n", slot);
+
+	/* success */
+	return 0;
+}
+EXPORT_SYMBOL(dvb_ca_en50221_camready_irq);
+
+
+/**
+ * A CAMCHANGE IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ * @param change_type One of the DVB_CA_CAMCHANGE_* values.
+ */
+void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot, int change_type)
+{
+	struct dvb_ca_private *ca = pubca->private;
+
+	dprintk("CAMCHANGE IRQ slot:%i change_type:%i\n", slot, change_type);
+
+	switch (change_type) {
+	case DVB_CA_EN50221_CAMCHANGE_REMOVED:
+	case DVB_CA_EN50221_CAMCHANGE_INSERTED:
+		break;
+
+	default:
+		return;
+	}
+
+	ca->slot_info[slot].camchange_type = change_type;
+	atomic_inc(&ca->slot_info[slot].camchange_count);
+	dvb_ca_en50221_thread_wakeup(ca);
+}
+EXPORT_SYMBOL(dvb_ca_en50221_frda_irq);
+
+
+/**
+ * A CAMREADY IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ */
+void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot)
+{
+	struct dvb_ca_private *ca = pubca->private;
+
+	dprintk("CAMREADY IRQ slot:%i\n", slot);
+
+	if (ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) {
+		ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;
+		dvb_ca_en50221_thread_wakeup(ca);
+	}
+}
+
+
+/**
+ * An FR or DA IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ */
+void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot)
+{
+	struct dvb_ca_private *ca = pubca->private;
+	int flags;
+
+	dprintk("FR/DA IRQ slot:%i\n", slot);
+
+	switch (ca->slot_info[slot].slot_state) {
+	case DVB_CA_SLOTSTATE_LINKINIT:
+		flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS);
+		if (flags & STATUSREG_DA) {
+			dprintk("CAM supports DA IRQ\n");
+			ca->slot_info[slot].da_irq_supported = 1;
+		}
+		break;
+
+	case DVB_CA_SLOTSTATE_RUNNING:
+		if (ca->open)
+			dvb_ca_en50221_thread_wakeup(ca);
+		break;
+	}
+}
+
+
+
+/* ******************************************************************************** */
+/* EN50221 thread functions */
+
+/**
+ * Wake up the DVB CA thread
+ *
+ * @param ca CA instance.
+ */
+static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca)
+{
+
+	dprintk("%s\n", __func__);
+
+	ca->wakeup = 1;
+	mb();
+	wake_up_process(ca->thread);
+}
+
+/**
+ * Update the delay used by the thread.
+ *
+ * @param ca CA instance.
+ */
+static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
+{
+	int delay;
+	int curdelay = 100000000;
+	int slot;
+
+	/* Beware of too high polling frequency, because one polling
+	 * call might take several hundred milliseconds until timeout!
+	 */
+	for (slot = 0; slot < ca->slot_count; slot++) {
+		switch (ca->slot_info[slot].slot_state) {
+		default:
+		case DVB_CA_SLOTSTATE_NONE:
+			delay = HZ * 60;  /* 60s */
+			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+				delay = HZ * 5;  /* 5s */
+			break;
+		case DVB_CA_SLOTSTATE_INVALID:
+			delay = HZ * 60;  /* 60s */
+			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+				delay = HZ / 10;  /* 100ms */
+			break;
+
+		case DVB_CA_SLOTSTATE_UNINITIALISED:
+		case DVB_CA_SLOTSTATE_WAITREADY:
+		case DVB_CA_SLOTSTATE_VALIDATE:
+		case DVB_CA_SLOTSTATE_WAITFR:
+		case DVB_CA_SLOTSTATE_LINKINIT:
+			delay = HZ / 10;  /* 100ms */
+			break;
+
+		case DVB_CA_SLOTSTATE_RUNNING:
+			delay = HZ * 60;  /* 60s */
+			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+				delay = HZ / 10;  /* 100ms */
+			if (ca->open) {
+				if ((!ca->slot_info[slot].da_irq_supported) ||
+				    (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA)))
+					delay = HZ / 10;  /* 100ms */
+			}
+			break;
+		}
+
+		if (delay < curdelay)
+			curdelay = delay;
+	}
+
+	ca->delay = curdelay;
+}
+
+
+
+/**
+ * Kernel thread which monitors CA slots for CAM changes, and performs data transfers.
+ */
+static int dvb_ca_en50221_thread(void *data)
+{
+	struct dvb_ca_private *ca = data;
+	int slot;
+	int flags;
+	int status;
+	int pktcount;
+	void *rxbuf;
+
+	dprintk("%s\n", __func__);
+
+	/* choose the correct initial delay */
+	dvb_ca_en50221_thread_update_delay(ca);
+
+	/* main loop */
+	while (!kthread_should_stop()) {
+		/* sleep for a bit */
+		if (!ca->wakeup) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(ca->delay);
+			if (kthread_should_stop())
+				return 0;
+		}
+		ca->wakeup = 0;
+
+		/* go through all the slots processing them */
+		for (slot = 0; slot < ca->slot_count; slot++) {
+
+			mutex_lock(&ca->slot_info[slot].slot_lock);
+
+			// check the cam status + deal with CAMCHANGEs
+			while (dvb_ca_en50221_check_camstatus(ca, slot)) {
+				/* clear down an old CI slot if necessary */
+				if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE)
+					dvb_ca_en50221_slot_shutdown(ca, slot);
+
+				/* if a CAM is NOW present, initialise it */
+				if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) {
+					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_UNINITIALISED;
+				}
+
+				/* we've handled one CAMCHANGE */
+				dvb_ca_en50221_thread_update_delay(ca);
+				atomic_dec(&ca->slot_info[slot].camchange_count);
+			}
+
+			// CAM state machine
+			switch (ca->slot_info[slot].slot_state) {
+			case DVB_CA_SLOTSTATE_NONE:
+			case DVB_CA_SLOTSTATE_INVALID:
+				// no action needed
+				break;
+
+			case DVB_CA_SLOTSTATE_UNINITIALISED:
+				ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITREADY;
+				ca->pub->slot_reset(ca->pub, slot);
+				ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
+				break;
+
+			case DVB_CA_SLOTSTATE_WAITREADY:
+				if (time_after(jiffies, ca->slot_info[slot].timeout)) {
+					printk("dvb_ca adaptor %d: PC card did not respond :(\n",
+					       ca->dvbdev->adapter->num);
+					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+					dvb_ca_en50221_thread_update_delay(ca);
+					break;
+				}
+				// no other action needed; will automatically change state when ready
+				break;
+
+			case DVB_CA_SLOTSTATE_VALIDATE:
+				if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
+					/* we need this extra check for annoying interfaces like the budget-av */
+					if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+					    (ca->pub->poll_slot_status)) {
+						status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+						if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+							ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+							dvb_ca_en50221_thread_update_delay(ca);
+							break;
+						}
+					}
+
+					printk("dvb_ca adapter %d: Invalid PC card inserted :(\n",
+					       ca->dvbdev->adapter->num);
+					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+					dvb_ca_en50221_thread_update_delay(ca);
+					break;
+				}
+				if (dvb_ca_en50221_set_configoption(ca, slot) != 0) {
+					printk("dvb_ca adapter %d: Unable to initialise CAM :(\n",
+					       ca->dvbdev->adapter->num);
+					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+					dvb_ca_en50221_thread_update_delay(ca);
+					break;
+				}
+				if (ca->pub->write_cam_control(ca->pub, slot,
+							       CTRLIF_COMMAND, CMDREG_RS) != 0) {
+					printk("dvb_ca adapter %d: Unable to reset CAM IF\n",
+					       ca->dvbdev->adapter->num);
+					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+					dvb_ca_en50221_thread_update_delay(ca);
+					break;
+				}
+				dprintk("DVB CAM validated successfully\n");
+
+				ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
+				ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITFR;
+				ca->wakeup = 1;
+				break;
+
+			case DVB_CA_SLOTSTATE_WAITFR:
+				if (time_after(jiffies, ca->slot_info[slot].timeout)) {
+					printk("dvb_ca adapter %d: DVB CAM did not respond :(\n",
+					       ca->dvbdev->adapter->num);
+					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+					dvb_ca_en50221_thread_update_delay(ca);
+					break;
+				}
+
+				flags = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
+				if (flags & STATUSREG_FR) {
+					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+					ca->wakeup = 1;
+				}
+				break;
+
+			case DVB_CA_SLOTSTATE_LINKINIT:
+				if (dvb_ca_en50221_link_init(ca, slot) != 0) {
+					/* we need this extra check for annoying interfaces like the budget-av */
+					if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+					    (ca->pub->poll_slot_status)) {
+						status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+						if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+							ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+							dvb_ca_en50221_thread_update_delay(ca);
+							break;
+						}
+					}
+
+					printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num);
+					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+					dvb_ca_en50221_thread_update_delay(ca);
+					break;
+				}
+
+				if (ca->slot_info[slot].rx_buffer.data == NULL) {
+					rxbuf = vmalloc(RX_BUFFER_SIZE);
+					if (rxbuf == NULL) {
+						printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num);
+						ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+						dvb_ca_en50221_thread_update_delay(ca);
+						break;
+					}
+					dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE);
+				}
+
+				ca->pub->slot_ts_enable(ca->pub, slot);
+				ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING;
+				dvb_ca_en50221_thread_update_delay(ca);
+				printk("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", ca->dvbdev->adapter->num);
+				break;
+
+			case DVB_CA_SLOTSTATE_RUNNING:
+				if (!ca->open)
+					break;
+
+				// poll slots for data
+				pktcount = 0;
+				while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) {
+					if (!ca->open)
+						break;
+
+					/* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */
+					if (dvb_ca_en50221_check_camstatus(ca, slot)) {
+						// we dont want to sleep on the next iteration so we can handle the cam change
+						ca->wakeup = 1;
+						break;
+					}
+
+					/* check if we've hit our limit this time */
+					if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) {
+						// dont sleep; there is likely to be more data to read
+						ca->wakeup = 1;
+						break;
+					}
+				}
+				break;
+			}
+
+			mutex_unlock(&ca->slot_info[slot].slot_lock);
+		}
+	}
+
+	return 0;
+}
+
+
+
+/* ******************************************************************************** */
+/* EN50221 IO interface functions */
+
+/**
+ * Real ioctl implementation.
+ * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them.
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ * @param cmd IOCTL command.
+ * @param arg Associated argument.
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int dvb_ca_en50221_io_do_ioctl(struct file *file,
+				      unsigned int cmd, void *parg)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_ca_private *ca = dvbdev->priv;
+	int err = 0;
+	int slot;
+
+	dprintk("%s\n", __func__);
+
+	switch (cmd) {
+	case CA_RESET:
+		for (slot = 0; slot < ca->slot_count; slot++) {
+			mutex_lock(&ca->slot_info[slot].slot_lock);
+			if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) {
+				dvb_ca_en50221_slot_shutdown(ca, slot);
+				if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)
+					dvb_ca_en50221_camchange_irq(ca->pub,
+								     slot,
+								     DVB_CA_EN50221_CAMCHANGE_INSERTED);
+			}
+			mutex_unlock(&ca->slot_info[slot].slot_lock);
+		}
+		ca->next_read_slot = 0;
+		dvb_ca_en50221_thread_wakeup(ca);
+		break;
+
+	case CA_GET_CAP: {
+		struct ca_caps *caps = parg;
+
+		caps->slot_num = ca->slot_count;
+		caps->slot_type = CA_CI_LINK;
+		caps->descr_num = 0;
+		caps->descr_type = 0;
+		break;
+	}
+
+	case CA_GET_SLOT_INFO: {
+		struct ca_slot_info *info = parg;
+
+		if ((info->num > ca->slot_count) || (info->num < 0))
+			return -EINVAL;
+
+		info->type = CA_CI_LINK;
+		info->flags = 0;
+		if ((ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_NONE)
+			&& (ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_INVALID)) {
+			info->flags = CA_CI_MODULE_PRESENT;
+		}
+		if (ca->slot_info[info->num].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
+			info->flags |= CA_CI_MODULE_READY;
+		}
+		break;
+	}
+
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+
+/**
+ * Wrapper for ioctl implementation.
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ * @param cmd IOCTL command.
+ * @param arg Associated argument.
+ *
+ * @return 0 on success, <0 on error.
+ */
+static long dvb_ca_en50221_io_ioctl(struct file *file,
+				    unsigned int cmd, unsigned long arg)
+{
+	return dvb_usercopy(file, cmd, arg, dvb_ca_en50221_io_do_ioctl);
+}
+
+
+/**
+ * Implementation of write() syscall.
+ *
+ * @param file File structure.
+ * @param buf Source buffer.
+ * @param count Size of source buffer.
+ * @param ppos Position in file (ignored).
+ *
+ * @return Number of bytes read, or <0 on error.
+ */
+static ssize_t dvb_ca_en50221_io_write(struct file *file,
+				       const char __user * buf, size_t count, loff_t * ppos)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_ca_private *ca = dvbdev->priv;
+	u8 slot, connection_id;
+	int status;
+	u8 fragbuf[HOST_LINK_BUF_SIZE];
+	int fragpos = 0;
+	int fraglen;
+	unsigned long timeout;
+	int written;
+
+	dprintk("%s\n", __func__);
+
+	/* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
+	if (count < 2)
+		return -EINVAL;
+
+	/* extract slot & connection id */
+	if (copy_from_user(&slot, buf, 1))
+		return -EFAULT;
+	if (copy_from_user(&connection_id, buf + 1, 1))
+		return -EFAULT;
+	buf += 2;
+	count -= 2;
+
+	/* check if the slot is actually running */
+	if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
+		return -EINVAL;
+
+	/* fragment the packets & store in the buffer */
+	while (fragpos < count) {
+		fraglen = ca->slot_info[slot].link_buf_size - 2;
+		if (fraglen < 0)
+			break;
+		if (fraglen > HOST_LINK_BUF_SIZE - 2)
+			fraglen = HOST_LINK_BUF_SIZE - 2;
+		if ((count - fragpos) < fraglen)
+			fraglen = count - fragpos;
+
+		fragbuf[0] = connection_id;
+		fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00;
+		status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen);
+		if (status) {
+			status = -EFAULT;
+			goto exit;
+		}
+
+		timeout = jiffies + HZ / 2;
+		written = 0;
+		while (!time_after(jiffies, timeout)) {
+			/* check the CAM hasn't been removed/reset in the meantime */
+			if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) {
+				status = -EIO;
+				goto exit;
+			}
+
+			mutex_lock(&ca->slot_info[slot].slot_lock);
+			status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen + 2);
+			mutex_unlock(&ca->slot_info[slot].slot_lock);
+			if (status == (fraglen + 2)) {
+				written = 1;
+				break;
+			}
+			if (status != -EAGAIN)
+				goto exit;
+
+			msleep(1);
+		}
+		if (!written) {
+			status = -EIO;
+			goto exit;
+		}
+
+		fragpos += fraglen;
+	}
+	status = count + 2;
+
+exit:
+	return status;
+}
+
+
+/**
+ * Condition for waking up in dvb_ca_en50221_io_read_condition
+ */
+static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca,
+					    int *result, int *_slot)
+{
+	int slot;
+	int slot_count = 0;
+	int idx;
+	size_t fraglen;
+	int connection_id = -1;
+	int found = 0;
+	u8 hdr[2];
+
+	slot = ca->next_read_slot;
+	while ((slot_count < ca->slot_count) && (!found)) {
+		if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
+			goto nextslot;
+
+		if (ca->slot_info[slot].rx_buffer.data == NULL) {
+			return 0;
+		}
+
+		idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
+		while (idx != -1) {
+			dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
+			if (connection_id == -1)
+				connection_id = hdr[0];
+			if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) {
+				*_slot = slot;
+				found = 1;
+				break;
+			}
+
+			idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
+		}
+
+nextslot:
+		slot = (slot + 1) % ca->slot_count;
+		slot_count++;
+	}
+
+	ca->next_read_slot = slot;
+	return found;
+}
+
+
+/**
+ * Implementation of read() syscall.
+ *
+ * @param file File structure.
+ * @param buf Destination buffer.
+ * @param count Size of destination buffer.
+ * @param ppos Position in file (ignored).
+ *
+ * @return Number of bytes read, or <0 on error.
+ */
+static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
+				      size_t count, loff_t * ppos)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_ca_private *ca = dvbdev->priv;
+	int status;
+	int result = 0;
+	u8 hdr[2];
+	int slot;
+	int connection_id = -1;
+	size_t idx, idx2;
+	int last_fragment = 0;
+	size_t fraglen;
+	int pktlen;
+	int dispose = 0;
+
+	dprintk("%s\n", __func__);
+
+	/* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
+	if (count < 2)
+		return -EINVAL;
+
+	/* wait for some data */
+	if ((status = dvb_ca_en50221_io_read_condition(ca, &result, &slot)) == 0) {
+
+		/* if we're in nonblocking mode, exit immediately */
+		if (file->f_flags & O_NONBLOCK)
+			return -EWOULDBLOCK;
+
+		/* wait for some data */
+		status = wait_event_interruptible(ca->wait_queue,
+						  dvb_ca_en50221_io_read_condition
+						  (ca, &result, &slot));
+	}
+	if ((status < 0) || (result < 0)) {
+		if (result)
+			return result;
+		return status;
+	}
+
+	idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
+	pktlen = 2;
+	do {
+		if (idx == -1) {
+			printk("dvb_ca adapter %d: BUG: read packet ended before last_fragment encountered\n", ca->dvbdev->adapter->num);
+			status = -EIO;
+			goto exit;
+		}
+
+		dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
+		if (connection_id == -1)
+			connection_id = hdr[0];
+		if (hdr[0] == connection_id) {
+			if (pktlen < count) {
+				if ((pktlen + fraglen - 2) > count) {
+					fraglen = count - pktlen;
+				} else {
+					fraglen -= 2;
+				}
+
+				if ((status = dvb_ringbuffer_pkt_read_user(&ca->slot_info[slot].rx_buffer, idx, 2,
+								      buf + pktlen, fraglen)) < 0) {
+					goto exit;
+				}
+				pktlen += fraglen;
+			}
+
+			if ((hdr[1] & 0x80) == 0)
+				last_fragment = 1;
+			dispose = 1;
+		}
+
+		idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
+		if (dispose)
+			dvb_ringbuffer_pkt_dispose(&ca->slot_info[slot].rx_buffer, idx);
+		idx = idx2;
+		dispose = 0;
+	} while (!last_fragment);
+
+	hdr[0] = slot;
+	hdr[1] = connection_id;
+	status = copy_to_user(buf, hdr, 2);
+	if (status) {
+		status = -EFAULT;
+		goto exit;
+	}
+	status = pktlen;
+
+exit:
+	return status;
+}
+
+
+/**
+ * Implementation of file open syscall.
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ *
+ * @return 0 on success, <0 on failure.
+ */
+static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_ca_private *ca = dvbdev->priv;
+	int err;
+	int i;
+
+	dprintk("%s\n", __func__);
+
+	if (!try_module_get(ca->pub->owner))
+		return -EIO;
+
+	err = dvb_generic_open(inode, file);
+	if (err < 0) {
+		module_put(ca->pub->owner);
+		return err;
+	}
+
+	for (i = 0; i < ca->slot_count; i++) {
+
+		if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
+			if (ca->slot_info[i].rx_buffer.data != NULL) {
+				/* it is safe to call this here without locks because
+				 * ca->open == 0. Data is not read in this case */
+				dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer);
+			}
+		}
+	}
+
+	ca->open = 1;
+	dvb_ca_en50221_thread_update_delay(ca);
+	dvb_ca_en50221_thread_wakeup(ca);
+
+	return 0;
+}
+
+
+/**
+ * Implementation of file close syscall.
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ *
+ * @return 0 on success, <0 on failure.
+ */
+static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_ca_private *ca = dvbdev->priv;
+	int err;
+
+	dprintk("%s\n", __func__);
+
+	/* mark the CA device as closed */
+	ca->open = 0;
+	dvb_ca_en50221_thread_update_delay(ca);
+
+	err = dvb_generic_release(inode, file);
+
+	module_put(ca->pub->owner);
+
+	return err;
+}
+
+
+/**
+ * Implementation of poll() syscall.
+ *
+ * @param file File concerned.
+ * @param wait poll wait table.
+ *
+ * @return Standard poll mask.
+ */
+static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_ca_private *ca = dvbdev->priv;
+	unsigned int mask = 0;
+	int slot;
+	int result = 0;
+
+	dprintk("%s\n", __func__);
+
+	if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
+		mask |= POLLIN;
+	}
+
+	/* if there is something, return now */
+	if (mask)
+		return mask;
+
+	/* wait for something to happen */
+	poll_wait(file, &ca->wait_queue, wait);
+
+	if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
+		mask |= POLLIN;
+	}
+
+	return mask;
+}
+EXPORT_SYMBOL(dvb_ca_en50221_init);
+
+
+static const struct file_operations dvb_ca_fops = {
+	.owner = THIS_MODULE,
+	.read = dvb_ca_en50221_io_read,
+	.write = dvb_ca_en50221_io_write,
+	.unlocked_ioctl = dvb_ca_en50221_io_ioctl,
+	.open = dvb_ca_en50221_io_open,
+	.release = dvb_ca_en50221_io_release,
+	.poll = dvb_ca_en50221_io_poll,
+	.llseek = noop_llseek,
+};
+
+static struct dvb_device dvbdev_ca = {
+	.priv = NULL,
+	.users = 1,
+	.readers = 1,
+	.writers = 1,
+	.fops = &dvb_ca_fops,
+};
+
+
+/* ******************************************************************************** */
+/* Initialisation/shutdown functions */
+
+
+/**
+ * Initialise a new DVB CA EN50221 interface device.
+ *
+ * @param dvb_adapter DVB adapter to attach the new CA device to.
+ * @param ca The dvb_ca instance.
+ * @param flags Flags describing the CA device (DVB_CA_FLAG_*).
+ * @param slot_count Number of slots supported.
+ *
+ * @return 0 on success, nonzero on failure
+ */
+int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
+			struct dvb_ca_en50221 *pubca, int flags, int slot_count)
+{
+	int ret;
+	struct dvb_ca_private *ca = NULL;
+	int i;
+
+	dprintk("%s\n", __func__);
+
+	if (slot_count < 1)
+		return -EINVAL;
+
+	/* initialise the system data */
+	if ((ca = kzalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) {
+		ret = -ENOMEM;
+		goto error;
+	}
+	ca->pub = pubca;
+	ca->flags = flags;
+	ca->slot_count = slot_count;
+	if ((ca->slot_info = kcalloc(slot_count, sizeof(struct dvb_ca_slot), GFP_KERNEL)) == NULL) {
+		ret = -ENOMEM;
+		goto error;
+	}
+	init_waitqueue_head(&ca->wait_queue);
+	ca->open = 0;
+	ca->wakeup = 0;
+	ca->next_read_slot = 0;
+	pubca->private = ca;
+
+	/* register the DVB device */
+	ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA);
+	if (ret)
+		goto error;
+
+	/* now initialise each slot */
+	for (i = 0; i < slot_count; i++) {
+		memset(&ca->slot_info[i], 0, sizeof(struct dvb_ca_slot));
+		ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE;
+		atomic_set(&ca->slot_info[i].camchange_count, 0);
+		ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
+		mutex_init(&ca->slot_info[i].slot_lock);
+	}
+
+	if (signal_pending(current)) {
+		ret = -EINTR;
+		goto error;
+	}
+	mb();
+
+	/* create a kthread for monitoring this CA device */
+	ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i",
+				 ca->dvbdev->adapter->num, ca->dvbdev->id);
+	if (IS_ERR(ca->thread)) {
+		ret = PTR_ERR(ca->thread);
+		printk("dvb_ca_init: failed to start kernel_thread (%d)\n",
+			ret);
+		goto error;
+	}
+	return 0;
+
+error:
+	if (ca != NULL) {
+		if (ca->dvbdev != NULL)
+			dvb_unregister_device(ca->dvbdev);
+		kfree(ca->slot_info);
+		kfree(ca);
+	}
+	pubca->private = NULL;
+	return ret;
+}
+EXPORT_SYMBOL(dvb_ca_en50221_release);
+
+
+
+/**
+ * Release a DVB CA EN50221 interface device.
+ *
+ * @param ca_dev The dvb_device_t instance for the CA device.
+ * @param ca The associated dvb_ca instance.
+ */
+void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
+{
+	struct dvb_ca_private *ca = pubca->private;
+	int i;
+
+	dprintk("%s\n", __func__);
+
+	/* shutdown the thread if there was one */
+	kthread_stop(ca->thread);
+
+	for (i = 0; i < ca->slot_count; i++) {
+		dvb_ca_en50221_slot_shutdown(ca, i);
+		vfree(ca->slot_info[i].rx_buffer.data);
+	}
+	kfree(ca->slot_info);
+	dvb_unregister_device(ca->dvbdev);
+	kfree(ca);
+	pubca->private = NULL;
+}
diff --git a/drivers/media/dvb-core/dvb_ca_en50221.h b/drivers/media/dvb-core/dvb_ca_en50221.h
new file mode 100644
index 0000000..7df2e14
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_ca_en50221.h
@@ -0,0 +1,136 @@
+/*
+ * dvb_ca.h: generic DVB functions for EN50221 CA interfaces
+ *
+ * Copyright (C) 2004 Andrew de Quincey
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _DVB_CA_EN50221_H_
+#define _DVB_CA_EN50221_H_
+
+#include <linux/list.h>
+#include <linux/dvb/ca.h>
+
+#include "dvbdev.h"
+
+#define DVB_CA_EN50221_POLL_CAM_PRESENT	1
+#define DVB_CA_EN50221_POLL_CAM_CHANGED	2
+#define DVB_CA_EN50221_POLL_CAM_READY		4
+
+#define DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE	1
+#define DVB_CA_EN50221_FLAG_IRQ_FR		2
+#define DVB_CA_EN50221_FLAG_IRQ_DA		4
+
+#define DVB_CA_EN50221_CAMCHANGE_REMOVED		0
+#define DVB_CA_EN50221_CAMCHANGE_INSERTED		1
+
+
+
+/* Structure describing a CA interface */
+struct dvb_ca_en50221 {
+
+	/* the module owning this structure */
+	struct module* owner;
+
+	/* NOTE: the read_*, write_* and poll_slot_status functions will be
+	 * called for different slots concurrently and need to use locks where
+	 * and if appropriate. There will be no concurrent access to one slot.
+	 */
+
+	/* functions for accessing attribute memory on the CAM */
+	int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address);
+	int (*write_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address, u8 value);
+
+	/* functions for accessing the control interface on the CAM */
+	int (*read_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address);
+	int (*write_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value);
+
+	/* Functions for controlling slots */
+	int (*slot_reset)(struct dvb_ca_en50221* ca, int slot);
+	int (*slot_shutdown)(struct dvb_ca_en50221* ca, int slot);
+	int (*slot_ts_enable)(struct dvb_ca_en50221* ca, int slot);
+
+	/*
+	* Poll slot status.
+	* Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set
+	*/
+	int (*poll_slot_status)(struct dvb_ca_en50221* ca, int slot, int open);
+
+	/* private data, used by caller */
+	void* data;
+
+	/* Opaque data used by the dvb_ca core. Do not modify! */
+	void* private;
+};
+
+
+
+
+/* ******************************************************************************** */
+/* Functions for reporting IRQ events */
+
+/**
+ * A CAMCHANGE IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ * @param change_type One of the DVB_CA_CAMCHANGE_* values
+ */
+void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int change_type);
+
+/**
+ * A CAMREADY IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ */
+void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221* pubca, int slot);
+
+/**
+ * An FR or a DA IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ */
+void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* ca, int slot);
+
+
+
+/* ******************************************************************************** */
+/* Initialisation/shutdown functions */
+
+/**
+ * Initialise a new DVB CA device.
+ *
+ * @param dvb_adapter DVB adapter to attach the new CA device to.
+ * @param ca The dvb_ca instance.
+ * @param flags Flags describing the CA device (DVB_CA_EN50221_FLAG_*).
+ * @param slot_count Number of slots supported.
+ *
+ * @return 0 on success, nonzero on failure
+ */
+extern int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* ca, int flags, int slot_count);
+
+/**
+ * Release a DVB CA device.
+ *
+ * @param ca The associated dvb_ca instance.
+ */
+extern void dvb_ca_en50221_release(struct dvb_ca_en50221* ca);
+
+
+
+#endif
diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c
new file mode 100644
index 0000000..17cb81f
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_demux.c
@@ -0,0 +1,1318 @@
+/*
+ * dvb_demux.c - DVB kernel demux API
+ *
+ * Copyright (C) 2000-2001 Ralph  Metzler <ralph@convergence.de>
+ *		       & Marcus Metzler <marcus@convergence.de>
+ *			 for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/string.h>
+#include <linux/crc32.h>
+#include <asm/uaccess.h>
+#include <asm/div64.h>
+
+#include "dvb_demux.h"
+
+#define NOBUFS
+/*
+** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog
+*/
+// #define DVB_DEMUX_SECTION_LOSS_LOG
+
+static int dvb_demux_tscheck;
+module_param(dvb_demux_tscheck, int, 0644);
+MODULE_PARM_DESC(dvb_demux_tscheck,
+		"enable transport stream continuity and TEI check");
+
+static int dvb_demux_speedcheck;
+module_param(dvb_demux_speedcheck, int, 0644);
+MODULE_PARM_DESC(dvb_demux_speedcheck,
+		"enable transport stream speed check");
+
+static int dvb_demux_feed_err_pkts = 1;
+module_param(dvb_demux_feed_err_pkts, int, 0644);
+MODULE_PARM_DESC(dvb_demux_feed_err_pkts,
+		 "when set to 0, drop packets with the TEI bit set (1 by default)");
+
+#define dprintk_tscheck(x...) do {                              \
+		if (dvb_demux_tscheck && printk_ratelimit())    \
+			printk(x);                              \
+	} while (0)
+
+/******************************************************************************
+ * static inlined helper functions
+ ******************************************************************************/
+
+static inline u16 section_length(const u8 *buf)
+{
+	return 3 + ((buf[1] & 0x0f) << 8) + buf[2];
+}
+
+static inline u16 ts_pid(const u8 *buf)
+{
+	return ((buf[1] & 0x1f) << 8) + buf[2];
+}
+
+static inline u8 payload(const u8 *tsp)
+{
+	if (!(tsp[3] & 0x10))	// no payload?
+		return 0;
+
+	if (tsp[3] & 0x20) {	// adaptation field?
+		if (tsp[4] > 183)	// corrupted data?
+			return 0;
+		else
+			return 184 - 1 - tsp[4];
+	}
+
+	return 184;
+}
+
+static u32 dvb_dmx_crc32(struct dvb_demux_feed *f, const u8 *src, size_t len)
+{
+	return (f->feed.sec.crc_val = crc32_be(f->feed.sec.crc_val, src, len));
+}
+
+static void dvb_dmx_memcopy(struct dvb_demux_feed *f, u8 *d, const u8 *s,
+			    size_t len)
+{
+	memcpy(d, s, len);
+}
+
+/******************************************************************************
+ * Software filter functions
+ ******************************************************************************/
+
+static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
+					   const u8 *buf)
+{
+	int count = payload(buf);
+	int p;
+	//int ccok;
+	//u8 cc;
+
+	if (count == 0)
+		return -1;
+
+	p = 188 - count;
+
+	/*
+	cc = buf[3] & 0x0f;
+	ccok = ((feed->cc + 1) & 0x0f) == cc;
+	feed->cc = cc;
+	if (!ccok)
+		printk("missed packet!\n");
+	*/
+
+	if (buf[1] & 0x40)	// PUSI ?
+		feed->peslen = 0xfffa;
+
+	feed->peslen += count;
+
+	return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK);
+}
+
+static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
+					  struct dvb_demux_filter *f)
+{
+	u8 neq = 0;
+	int i;
+
+	for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
+		u8 xor = f->filter.filter_value[i] ^ feed->feed.sec.secbuf[i];
+
+		if (f->maskandmode[i] & xor)
+			return 0;
+
+		neq |= f->maskandnotmode[i] & xor;
+	}
+
+	if (f->doneq && !neq)
+		return 0;
+
+	return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen,
+			    NULL, 0, &f->filter, DMX_OK);
+}
+
+static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct dvb_demux_filter *f = feed->filter;
+	struct dmx_section_feed *sec = &feed->feed.sec;
+	int section_syntax_indicator;
+
+	if (!sec->is_filtering)
+		return 0;
+
+	if (!f)
+		return 0;
+
+	if (sec->check_crc) {
+		section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
+		if (section_syntax_indicator &&
+		    demux->check_crc32(feed, sec->secbuf, sec->seclen))
+			return -1;
+	}
+
+	do {
+		if (dvb_dmx_swfilter_sectionfilter(feed, f) < 0)
+			return -1;
+	} while ((f = f->next) && sec->is_filtering);
+
+	sec->seclen = 0;
+
+	return 0;
+}
+
+static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
+{
+	struct dmx_section_feed *sec = &feed->feed.sec;
+
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+	if (sec->secbufp < sec->tsfeedp) {
+		int i, n = sec->tsfeedp - sec->secbufp;
+
+		/*
+		 * Section padding is done with 0xff bytes entirely.
+		 * Due to speed reasons, we won't check all of them
+		 * but just first and last.
+		 */
+		if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) {
+			printk("dvb_demux.c section ts padding loss: %d/%d\n",
+			       n, sec->tsfeedp);
+			printk("dvb_demux.c pad data:");
+			for (i = 0; i < n; i++)
+				printk(" %02x", sec->secbuf[i]);
+			printk("\n");
+		}
+	}
+#endif
+
+	sec->tsfeedp = sec->secbufp = sec->seclen = 0;
+	sec->secbuf = sec->secbuf_base;
+}
+
+/*
+ * Losless Section Demux 1.4.1 by Emard
+ * Valsecchi Patrick:
+ *  - middle of section A  (no PUSI)
+ *  - end of section A and start of section B
+ *    (with PUSI pointing to the start of the second section)
+ *
+ *  In this case, without feed->pusi_seen you'll receive a garbage section
+ *  consisting of the end of section A. Basically because tsfeedp
+ *  is incemented and the use=0 condition is not raised
+ *  when the second packet arrives.
+ *
+ * Fix:
+ * when demux is started, let feed->pusi_seen = 0 to
+ * prevent initial feeding of garbage from the end of
+ * previous section. When you for the first time see PUSI=1
+ * then set feed->pusi_seen = 1
+ */
+static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
+					      const u8 *buf, u8 len)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct dmx_section_feed *sec = &feed->feed.sec;
+	u16 limit, seclen, n;
+
+	if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE)
+		return 0;
+
+	if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) {
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+		printk("dvb_demux.c section buffer full loss: %d/%d\n",
+		       sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
+		       DMX_MAX_SECFEED_SIZE);
+#endif
+		len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp;
+	}
+
+	if (len <= 0)
+		return 0;
+
+	demux->memcopy(feed, sec->secbuf_base + sec->tsfeedp, buf, len);
+	sec->tsfeedp += len;
+
+	/*
+	 * Dump all the sections we can find in the data (Emard)
+	 */
+	limit = sec->tsfeedp;
+	if (limit > DMX_MAX_SECFEED_SIZE)
+		return -1;	/* internal error should never happen */
+
+	/* to be sure always set secbuf */
+	sec->secbuf = sec->secbuf_base + sec->secbufp;
+
+	for (n = 0; sec->secbufp + 2 < limit; n++) {
+		seclen = section_length(sec->secbuf);
+		if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE
+		    || seclen + sec->secbufp > limit)
+			return 0;
+		sec->seclen = seclen;
+		sec->crc_val = ~0;
+		/* dump [secbuf .. secbuf+seclen) */
+		if (feed->pusi_seen)
+			dvb_dmx_swfilter_section_feed(feed);
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+		else
+			printk("dvb_demux.c pusi not seen, discarding section data\n");
+#endif
+		sec->secbufp += seclen;	/* secbufp and secbuf moving together is */
+		sec->secbuf += seclen;	/* redundant but saves pointer arithmetic */
+	}
+
+	return 0;
+}
+
+static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
+					   const u8 *buf)
+{
+	u8 p, count;
+	int ccok, dc_i = 0;
+	u8 cc;
+
+	count = payload(buf);
+
+	if (count == 0)		/* count == 0 if no payload or out of range */
+		return -1;
+
+	p = 188 - count;	/* payload start */
+
+	cc = buf[3] & 0x0f;
+	ccok = ((feed->cc + 1) & 0x0f) == cc;
+	feed->cc = cc;
+
+	if (buf[3] & 0x20) {
+		/* adaption field present, check for discontinuity_indicator */
+		if ((buf[4] > 0) && (buf[5] & 0x80))
+			dc_i = 1;
+	}
+
+	if (!ccok || dc_i) {
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+		printk("dvb_demux.c discontinuity detected %d bytes lost\n",
+		       count);
+		/*
+		 * those bytes under sume circumstances will again be reported
+		 * in the following dvb_dmx_swfilter_section_new
+		 */
+#endif
+		/*
+		 * Discontinuity detected. Reset pusi_seen = 0 to
+		 * stop feeding of suspicious data until next PUSI=1 arrives
+		 */
+		feed->pusi_seen = 0;
+		dvb_dmx_swfilter_section_new(feed);
+	}
+
+	if (buf[1] & 0x40) {
+		/* PUSI=1 (is set), section boundary is here */
+		if (count > 1 && buf[p] < count) {
+			const u8 *before = &buf[p + 1];
+			u8 before_len = buf[p];
+			const u8 *after = &before[before_len];
+			u8 after_len = count - 1 - before_len;
+
+			dvb_dmx_swfilter_section_copy_dump(feed, before,
+							   before_len);
+			/* before start of new section, set pusi_seen = 1 */
+			feed->pusi_seen = 1;
+			dvb_dmx_swfilter_section_new(feed);
+			dvb_dmx_swfilter_section_copy_dump(feed, after,
+							   after_len);
+		}
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+		else if (count > 0)
+			printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count);
+#endif
+	} else {
+		/* PUSI=0 (is not set), no section boundary */
+		dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count);
+	}
+
+	return 0;
+}
+
+static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
+						const u8 *buf)
+{
+	switch (feed->type) {
+	case DMX_TYPE_TS:
+		if (!feed->feed.ts.is_filtering)
+			break;
+		if (feed->ts_type & TS_PACKET) {
+			if (feed->ts_type & TS_PAYLOAD_ONLY)
+				dvb_dmx_swfilter_payload(feed, buf);
+			else
+				feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
+					    DMX_OK);
+		}
+		if (feed->ts_type & TS_DECODER)
+			if (feed->demux->write_to_decoder)
+				feed->demux->write_to_decoder(feed, buf, 188);
+		break;
+
+	case DMX_TYPE_SEC:
+		if (!feed->feed.sec.is_filtering)
+			break;
+		if (dvb_dmx_swfilter_section_packet(feed, buf) < 0)
+			feed->feed.sec.seclen = feed->feed.sec.secbufp = 0;
+		break;
+
+	default:
+		break;
+	}
+}
+
+#define DVR_FEED(f)							\
+	(((f)->type == DMX_TYPE_TS) &&					\
+	((f)->feed.ts.is_filtering) &&					\
+	(((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET))
+
+static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
+{
+	struct dvb_demux_feed *feed;
+	u16 pid = ts_pid(buf);
+	int dvr_done = 0;
+
+	if (dvb_demux_speedcheck) {
+		struct timespec cur_time, delta_time;
+		u64 speed_bytes, speed_timedelta;
+
+		demux->speed_pkts_cnt++;
+
+		/* show speed every SPEED_PKTS_INTERVAL packets */
+		if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) {
+			cur_time = current_kernel_time();
+
+			if (demux->speed_last_time.tv_sec != 0 &&
+					demux->speed_last_time.tv_nsec != 0) {
+				delta_time = timespec_sub(cur_time,
+						demux->speed_last_time);
+				speed_bytes = (u64)demux->speed_pkts_cnt
+					* 188 * 8;
+				/* convert to 1024 basis */
+				speed_bytes = 1000 * div64_u64(speed_bytes,
+						1024);
+				speed_timedelta =
+					(u64)timespec_to_ns(&delta_time);
+				speed_timedelta = div64_u64(speed_timedelta,
+						1000000); /* nsec -> usec */
+				printk(KERN_INFO "TS speed %llu Kbits/sec \n",
+						div64_u64(speed_bytes,
+							speed_timedelta));
+			};
+
+			demux->speed_last_time = cur_time;
+			demux->speed_pkts_cnt = 0;
+		};
+	};
+
+	if (buf[1] & 0x80) {
+		dprintk_tscheck("TEI detected. "
+				"PID=0x%x data1=0x%x\n",
+				pid, buf[1]);
+		/* data in this packet cant be trusted - drop it unless
+		 * module option dvb_demux_feed_err_pkts is set */
+		if (!dvb_demux_feed_err_pkts)
+			return;
+	} else /* if TEI bit is set, pid may be wrong- skip pkt counter */
+	if (demux->cnt_storage && dvb_demux_tscheck) {
+		/* check pkt counter */
+		if (pid < MAX_PID) {
+			if ((buf[3] & 0xf) != demux->cnt_storage[pid])
+				dprintk_tscheck("TS packet counter mismatch. "
+						"PID=0x%x expected 0x%x "
+						"got 0x%x\n",
+						pid, demux->cnt_storage[pid],
+						buf[3] & 0xf);
+
+			demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf;
+		};
+		/* end check */
+	};
+
+	list_for_each_entry(feed, &demux->feed_list, list_head) {
+		if ((feed->pid != pid) && (feed->pid != 0x2000))
+			continue;
+
+		/* copy each packet only once to the dvr device, even
+		 * if a PID is in multiple filters (e.g. video + PCR) */
+		if ((DVR_FEED(feed)) && (dvr_done++))
+			continue;
+
+		if (feed->pid == pid)
+			dvb_dmx_swfilter_packet_type(feed, buf);
+		else if (feed->pid == 0x2000)
+			feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
+	}
+}
+
+void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
+			      size_t count)
+{
+	spin_lock(&demux->lock);
+
+	while (count--) {
+		if (buf[0] == 0x47)
+			dvb_dmx_swfilter_packet(demux, buf);
+		buf += 188;
+	}
+
+	spin_unlock(&demux->lock);
+}
+
+EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
+
+static inline int find_next_packet(const u8 *buf, int pos, size_t count,
+				   const int pktsize)
+{
+	int start = pos, lost;
+
+	while (pos < count) {
+		if (buf[pos] == 0x47 ||
+		    (pktsize == 204 && buf[pos] == 0xB8))
+			break;
+		pos++;
+	}
+
+	lost = pos - start;
+	if (lost) {
+		/* This garbage is part of a valid packet? */
+		int backtrack = pos - pktsize;
+		if (backtrack >= 0 && (buf[backtrack] == 0x47 ||
+		    (pktsize == 204 && buf[backtrack] == 0xB8)))
+			return backtrack;
+	}
+
+	return pos;
+}
+
+/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */
+static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
+		size_t count, const int pktsize)
+{
+	int p = 0, i, j;
+	const u8 *q;
+
+	spin_lock(&demux->lock);
+
+	if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
+		i = demux->tsbufp;
+		j = pktsize - i;
+		if (count < j) {
+			memcpy(&demux->tsbuf[i], buf, count);
+			demux->tsbufp += count;
+			goto bailout;
+		}
+		memcpy(&demux->tsbuf[i], buf, j);
+		if (demux->tsbuf[0] == 0x47) /* double check */
+			dvb_dmx_swfilter_packet(demux, demux->tsbuf);
+		demux->tsbufp = 0;
+		p += j;
+	}
+
+	while (1) {
+		p = find_next_packet(buf, p, count, pktsize);
+		if (p >= count)
+			break;
+		if (count - p < pktsize)
+			break;
+
+		q = &buf[p];
+
+		if (pktsize == 204 && (*q == 0xB8)) {
+			memcpy(demux->tsbuf, q, 188);
+			demux->tsbuf[0] = 0x47;
+			q = demux->tsbuf;
+		}
+		dvb_dmx_swfilter_packet(demux, q);
+		p += pktsize;
+	}
+
+	i = count - p;
+	if (i) {
+		memcpy(demux->tsbuf, &buf[p], i);
+		demux->tsbufp = i;
+		if (pktsize == 204 && demux->tsbuf[0] == 0xB8)
+			demux->tsbuf[0] = 0x47;
+	}
+
+bailout:
+	spin_unlock(&demux->lock);
+}
+
+void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
+{
+	_dvb_dmx_swfilter(demux, buf, count, 188);
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter);
+
+void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
+{
+	_dvb_dmx_swfilter(demux, buf, count, 204);
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter_204);
+
+void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
+{
+	spin_lock(&demux->lock);
+
+	demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, DMX_OK);
+
+	spin_unlock(&demux->lock);
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter_raw);
+
+static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
+{
+	int i;
+
+	for (i = 0; i < demux->filternum; i++)
+		if (demux->filter[i].state == DMX_STATE_FREE)
+			break;
+
+	if (i == demux->filternum)
+		return NULL;
+
+	demux->filter[i].state = DMX_STATE_ALLOCATED;
+
+	return &demux->filter[i];
+}
+
+static struct dvb_demux_feed *dvb_dmx_feed_alloc(struct dvb_demux *demux)
+{
+	int i;
+
+	for (i = 0; i < demux->feednum; i++)
+		if (demux->feed[i].state == DMX_STATE_FREE)
+			break;
+
+	if (i == demux->feednum)
+		return NULL;
+
+	demux->feed[i].state = DMX_STATE_ALLOCATED;
+
+	return &demux->feed[i];
+}
+
+static int dvb_demux_feed_find(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux_feed *entry;
+
+	list_for_each_entry(entry, &feed->demux->feed_list, list_head)
+		if (entry == feed)
+			return 1;
+
+	return 0;
+}
+
+static void dvb_demux_feed_add(struct dvb_demux_feed *feed)
+{
+	spin_lock_irq(&feed->demux->lock);
+	if (dvb_demux_feed_find(feed)) {
+		printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n",
+		       __func__, feed->type, feed->state, feed->pid);
+		goto out;
+	}
+
+	list_add(&feed->list_head, &feed->demux->feed_list);
+out:
+	spin_unlock_irq(&feed->demux->lock);
+}
+
+static void dvb_demux_feed_del(struct dvb_demux_feed *feed)
+{
+	spin_lock_irq(&feed->demux->lock);
+	if (!(dvb_demux_feed_find(feed))) {
+		printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n",
+		       __func__, feed->type, feed->state, feed->pid);
+		goto out;
+	}
+
+	list_del(&feed->list_head);
+out:
+	spin_unlock_irq(&feed->demux->lock);
+}
+
+static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
+			   enum dmx_ts_pes pes_type,
+			   size_t circular_buffer_size, struct timespec timeout)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dvb_demux *demux = feed->demux;
+
+	if (pid > DMX_MAX_PID)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&demux->mutex))
+		return -ERESTARTSYS;
+
+	if (ts_type & TS_DECODER) {
+		if (pes_type >= DMX_TS_PES_OTHER) {
+			mutex_unlock(&demux->mutex);
+			return -EINVAL;
+		}
+
+		if (demux->pesfilter[pes_type] &&
+		    demux->pesfilter[pes_type] != feed) {
+			mutex_unlock(&demux->mutex);
+			return -EINVAL;
+		}
+
+		demux->pesfilter[pes_type] = feed;
+		demux->pids[pes_type] = pid;
+	}
+
+	dvb_demux_feed_add(feed);
+
+	feed->pid = pid;
+	feed->buffer_size = circular_buffer_size;
+	feed->timeout = timeout;
+	feed->ts_type = ts_type;
+	feed->pes_type = pes_type;
+
+	if (feed->buffer_size) {
+#ifdef NOBUFS
+		feed->buffer = NULL;
+#else
+		feed->buffer = vmalloc(feed->buffer_size);
+		if (!feed->buffer) {
+			mutex_unlock(&demux->mutex);
+			return -ENOMEM;
+		}
+#endif
+	}
+
+	feed->state = DMX_STATE_READY;
+	mutex_unlock(&demux->mutex);
+
+	return 0;
+}
+
+static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dvb_demux *demux = feed->demux;
+	int ret;
+
+	if (mutex_lock_interruptible(&demux->mutex))
+		return -ERESTARTSYS;
+
+	if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) {
+		mutex_unlock(&demux->mutex);
+		return -EINVAL;
+	}
+
+	if (!demux->start_feed) {
+		mutex_unlock(&demux->mutex);
+		return -ENODEV;
+	}
+
+	if ((ret = demux->start_feed(feed)) < 0) {
+		mutex_unlock(&demux->mutex);
+		return ret;
+	}
+
+	spin_lock_irq(&demux->lock);
+	ts_feed->is_filtering = 1;
+	feed->state = DMX_STATE_GO;
+	spin_unlock_irq(&demux->lock);
+	mutex_unlock(&demux->mutex);
+
+	return 0;
+}
+
+static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dvb_demux *demux = feed->demux;
+	int ret;
+
+	mutex_lock(&demux->mutex);
+
+	if (feed->state < DMX_STATE_GO) {
+		mutex_unlock(&demux->mutex);
+		return -EINVAL;
+	}
+
+	if (!demux->stop_feed) {
+		mutex_unlock(&demux->mutex);
+		return -ENODEV;
+	}
+
+	ret = demux->stop_feed(feed);
+
+	spin_lock_irq(&demux->lock);
+	ts_feed->is_filtering = 0;
+	feed->state = DMX_STATE_ALLOCATED;
+	spin_unlock_irq(&demux->lock);
+	mutex_unlock(&demux->mutex);
+
+	return ret;
+}
+
+static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
+				   struct dmx_ts_feed **ts_feed,
+				   dmx_ts_cb callback)
+{
+	struct dvb_demux *demux = (struct dvb_demux *)dmx;
+	struct dvb_demux_feed *feed;
+
+	if (mutex_lock_interruptible(&demux->mutex))
+		return -ERESTARTSYS;
+
+	if (!(feed = dvb_dmx_feed_alloc(demux))) {
+		mutex_unlock(&demux->mutex);
+		return -EBUSY;
+	}
+
+	feed->type = DMX_TYPE_TS;
+	feed->cb.ts = callback;
+	feed->demux = demux;
+	feed->pid = 0xffff;
+	feed->peslen = 0xfffa;
+	feed->buffer = NULL;
+
+	(*ts_feed) = &feed->feed.ts;
+	(*ts_feed)->parent = dmx;
+	(*ts_feed)->priv = NULL;
+	(*ts_feed)->is_filtering = 0;
+	(*ts_feed)->start_filtering = dmx_ts_feed_start_filtering;
+	(*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering;
+	(*ts_feed)->set = dmx_ts_feed_set;
+
+	if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
+		feed->state = DMX_STATE_FREE;
+		mutex_unlock(&demux->mutex);
+		return -EBUSY;
+	}
+
+	feed->filter->type = DMX_TYPE_TS;
+	feed->filter->feed = feed;
+	feed->filter->state = DMX_STATE_READY;
+
+	mutex_unlock(&demux->mutex);
+
+	return 0;
+}
+
+static int dvbdmx_release_ts_feed(struct dmx_demux *dmx,
+				  struct dmx_ts_feed *ts_feed)
+{
+	struct dvb_demux *demux = (struct dvb_demux *)dmx;
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+
+	mutex_lock(&demux->mutex);
+
+	if (feed->state == DMX_STATE_FREE) {
+		mutex_unlock(&demux->mutex);
+		return -EINVAL;
+	}
+#ifndef NOBUFS
+	vfree(feed->buffer);
+	feed->buffer = NULL;
+#endif
+
+	feed->state = DMX_STATE_FREE;
+	feed->filter->state = DMX_STATE_FREE;
+
+	dvb_demux_feed_del(feed);
+
+	feed->pid = 0xffff;
+
+	if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER)
+		demux->pesfilter[feed->pes_type] = NULL;
+
+	mutex_unlock(&demux->mutex);
+	return 0;
+}
+
+/******************************************************************************
+ * dmx_section_feed API calls
+ ******************************************************************************/
+
+static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed,
+					    struct dmx_section_filter **filter)
+{
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+	struct dvb_demux *dvbdemux = dvbdmxfeed->demux;
+	struct dvb_demux_filter *dvbdmxfilter;
+
+	if (mutex_lock_interruptible(&dvbdemux->mutex))
+		return -ERESTARTSYS;
+
+	dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux);
+	if (!dvbdmxfilter) {
+		mutex_unlock(&dvbdemux->mutex);
+		return -EBUSY;
+	}
+
+	spin_lock_irq(&dvbdemux->lock);
+	*filter = &dvbdmxfilter->filter;
+	(*filter)->parent = feed;
+	(*filter)->priv = NULL;
+	dvbdmxfilter->feed = dvbdmxfeed;
+	dvbdmxfilter->type = DMX_TYPE_SEC;
+	dvbdmxfilter->state = DMX_STATE_READY;
+	dvbdmxfilter->next = dvbdmxfeed->filter;
+	dvbdmxfeed->filter = dvbdmxfilter;
+	spin_unlock_irq(&dvbdemux->lock);
+
+	mutex_unlock(&dvbdemux->mutex);
+	return 0;
+}
+
+static int dmx_section_feed_set(struct dmx_section_feed *feed,
+				u16 pid, size_t circular_buffer_size,
+				int check_crc)
+{
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+
+	if (pid > 0x1fff)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
+		return -ERESTARTSYS;
+
+	dvb_demux_feed_add(dvbdmxfeed);
+
+	dvbdmxfeed->pid = pid;
+	dvbdmxfeed->buffer_size = circular_buffer_size;
+	dvbdmxfeed->feed.sec.check_crc = check_crc;
+
+#ifdef NOBUFS
+	dvbdmxfeed->buffer = NULL;
+#else
+	dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size);
+	if (!dvbdmxfeed->buffer) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -ENOMEM;
+	}
+#endif
+
+	dvbdmxfeed->state = DMX_STATE_READY;
+	mutex_unlock(&dvbdmx->mutex);
+	return 0;
+}
+
+static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed)
+{
+	int i;
+	struct dvb_demux_filter *f;
+	struct dmx_section_filter *sf;
+	u8 mask, mode, doneq;
+
+	if (!(f = dvbdmxfeed->filter))
+		return;
+	do {
+		sf = &f->filter;
+		doneq = 0;
+		for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
+			mode = sf->filter_mode[i];
+			mask = sf->filter_mask[i];
+			f->maskandmode[i] = mask & mode;
+			doneq |= f->maskandnotmode[i] = mask & ~mode;
+		}
+		f->doneq = doneq ? 1 : 0;
+	} while ((f = f->next));
+}
+
+static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
+{
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	int ret;
+
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
+		return -ERESTARTSYS;
+
+	if (feed->is_filtering) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -EBUSY;
+	}
+
+	if (!dvbdmxfeed->filter) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -EINVAL;
+	}
+
+	dvbdmxfeed->feed.sec.tsfeedp = 0;
+	dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
+	dvbdmxfeed->feed.sec.secbufp = 0;
+	dvbdmxfeed->feed.sec.seclen = 0;
+
+	if (!dvbdmx->start_feed) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -ENODEV;
+	}
+
+	prepare_secfilters(dvbdmxfeed);
+
+	if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) {
+		mutex_unlock(&dvbdmx->mutex);
+		return ret;
+	}
+
+	spin_lock_irq(&dvbdmx->lock);
+	feed->is_filtering = 1;
+	dvbdmxfeed->state = DMX_STATE_GO;
+	spin_unlock_irq(&dvbdmx->lock);
+
+	mutex_unlock(&dvbdmx->mutex);
+	return 0;
+}
+
+static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed)
+{
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	int ret;
+
+	mutex_lock(&dvbdmx->mutex);
+
+	if (!dvbdmx->stop_feed) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -ENODEV;
+	}
+
+	ret = dvbdmx->stop_feed(dvbdmxfeed);
+
+	spin_lock_irq(&dvbdmx->lock);
+	dvbdmxfeed->state = DMX_STATE_READY;
+	feed->is_filtering = 0;
+	spin_unlock_irq(&dvbdmx->lock);
+
+	mutex_unlock(&dvbdmx->mutex);
+	return ret;
+}
+
+static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
+					   struct dmx_section_filter *filter)
+{
+	struct dvb_demux_filter *dvbdmxfilter = (struct dvb_demux_filter *)filter, *f;
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+
+	mutex_lock(&dvbdmx->mutex);
+
+	if (dvbdmxfilter->feed != dvbdmxfeed) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -EINVAL;
+	}
+
+	if (feed->is_filtering)
+		feed->stop_filtering(feed);
+
+	spin_lock_irq(&dvbdmx->lock);
+	f = dvbdmxfeed->filter;
+
+	if (f == dvbdmxfilter) {
+		dvbdmxfeed->filter = dvbdmxfilter->next;
+	} else {
+		while (f->next != dvbdmxfilter)
+			f = f->next;
+		f->next = f->next->next;
+	}
+
+	dvbdmxfilter->state = DMX_STATE_FREE;
+	spin_unlock_irq(&dvbdmx->lock);
+	mutex_unlock(&dvbdmx->mutex);
+	return 0;
+}
+
+static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
+					struct dmx_section_feed **feed,
+					dmx_section_cb callback)
+{
+	struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
+	struct dvb_demux_feed *dvbdmxfeed;
+
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
+		return -ERESTARTSYS;
+
+	if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -EBUSY;
+	}
+
+	dvbdmxfeed->type = DMX_TYPE_SEC;
+	dvbdmxfeed->cb.sec = callback;
+	dvbdmxfeed->demux = dvbdmx;
+	dvbdmxfeed->pid = 0xffff;
+	dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
+	dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
+	dvbdmxfeed->feed.sec.tsfeedp = 0;
+	dvbdmxfeed->filter = NULL;
+	dvbdmxfeed->buffer = NULL;
+
+	(*feed) = &dvbdmxfeed->feed.sec;
+	(*feed)->is_filtering = 0;
+	(*feed)->parent = demux;
+	(*feed)->priv = NULL;
+
+	(*feed)->set = dmx_section_feed_set;
+	(*feed)->allocate_filter = dmx_section_feed_allocate_filter;
+	(*feed)->start_filtering = dmx_section_feed_start_filtering;
+	(*feed)->stop_filtering = dmx_section_feed_stop_filtering;
+	(*feed)->release_filter = dmx_section_feed_release_filter;
+
+	mutex_unlock(&dvbdmx->mutex);
+	return 0;
+}
+
+static int dvbdmx_release_section_feed(struct dmx_demux *demux,
+				       struct dmx_section_feed *feed)
+{
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+	struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
+
+	mutex_lock(&dvbdmx->mutex);
+
+	if (dvbdmxfeed->state == DMX_STATE_FREE) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -EINVAL;
+	}
+#ifndef NOBUFS
+	vfree(dvbdmxfeed->buffer);
+	dvbdmxfeed->buffer = NULL;
+#endif
+	dvbdmxfeed->state = DMX_STATE_FREE;
+
+	dvb_demux_feed_del(dvbdmxfeed);
+
+	dvbdmxfeed->pid = 0xffff;
+
+	mutex_unlock(&dvbdmx->mutex);
+	return 0;
+}
+
+/******************************************************************************
+ * dvb_demux kernel data API calls
+ ******************************************************************************/
+
+static int dvbdmx_open(struct dmx_demux *demux)
+{
+	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+	if (dvbdemux->users >= MAX_DVB_DEMUX_USERS)
+		return -EUSERS;
+
+	dvbdemux->users++;
+	return 0;
+}
+
+static int dvbdmx_close(struct dmx_demux *demux)
+{
+	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+	if (dvbdemux->users == 0)
+		return -ENODEV;
+
+	dvbdemux->users--;
+	//FIXME: release any unneeded resources if users==0
+	return 0;
+}
+
+static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count)
+{
+	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+	void *p;
+
+	if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
+		return -EINVAL;
+
+	p = memdup_user(buf, count);
+	if (IS_ERR(p))
+		return PTR_ERR(p);
+	if (mutex_lock_interruptible(&dvbdemux->mutex)) {
+		kfree(p);
+		return -ERESTARTSYS;
+	}
+	dvb_dmx_swfilter(dvbdemux, p, count);
+	kfree(p);
+	mutex_unlock(&dvbdemux->mutex);
+
+	if (signal_pending(current))
+		return -EINTR;
+	return count;
+}
+
+static int dvbdmx_add_frontend(struct dmx_demux *demux,
+			       struct dmx_frontend *frontend)
+{
+	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+	struct list_head *head = &dvbdemux->frontend_list;
+
+	list_add(&(frontend->connectivity_list), head);
+
+	return 0;
+}
+
+static int dvbdmx_remove_frontend(struct dmx_demux *demux,
+				  struct dmx_frontend *frontend)
+{
+	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+	struct list_head *pos, *n, *head = &dvbdemux->frontend_list;
+
+	list_for_each_safe(pos, n, head) {
+		if (DMX_FE_ENTRY(pos) == frontend) {
+			list_del(pos);
+			return 0;
+		}
+	}
+
+	return -ENODEV;
+}
+
+static struct list_head *dvbdmx_get_frontends(struct dmx_demux *demux)
+{
+	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+	if (list_empty(&dvbdemux->frontend_list))
+		return NULL;
+
+	return &dvbdemux->frontend_list;
+}
+
+static int dvbdmx_connect_frontend(struct dmx_demux *demux,
+				   struct dmx_frontend *frontend)
+{
+	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+	if (demux->frontend)
+		return -EINVAL;
+
+	mutex_lock(&dvbdemux->mutex);
+
+	demux->frontend = frontend;
+	mutex_unlock(&dvbdemux->mutex);
+	return 0;
+}
+
+static int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
+{
+	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+	mutex_lock(&dvbdemux->mutex);
+
+	demux->frontend = NULL;
+	mutex_unlock(&dvbdemux->mutex);
+	return 0;
+}
+
+static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids)
+{
+	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+	memcpy(pids, dvbdemux->pids, 5 * sizeof(u16));
+	return 0;
+}
+
+int dvb_dmx_init(struct dvb_demux *dvbdemux)
+{
+	int i;
+	struct dmx_demux *dmx = &dvbdemux->dmx;
+
+	dvbdemux->cnt_storage = NULL;
+	dvbdemux->users = 0;
+	dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter));
+
+	if (!dvbdemux->filter)
+		return -ENOMEM;
+
+	dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed));
+	if (!dvbdemux->feed) {
+		vfree(dvbdemux->filter);
+		dvbdemux->filter = NULL;
+		return -ENOMEM;
+	}
+	for (i = 0; i < dvbdemux->filternum; i++) {
+		dvbdemux->filter[i].state = DMX_STATE_FREE;
+		dvbdemux->filter[i].index = i;
+	}
+	for (i = 0; i < dvbdemux->feednum; i++) {
+		dvbdemux->feed[i].state = DMX_STATE_FREE;
+		dvbdemux->feed[i].index = i;
+	}
+
+	dvbdemux->cnt_storage = vmalloc(MAX_PID + 1);
+	if (!dvbdemux->cnt_storage)
+		printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
+
+	INIT_LIST_HEAD(&dvbdemux->frontend_list);
+
+	for (i = 0; i < DMX_TS_PES_OTHER; i++) {
+		dvbdemux->pesfilter[i] = NULL;
+		dvbdemux->pids[i] = 0xffff;
+	}
+
+	INIT_LIST_HEAD(&dvbdemux->feed_list);
+
+	dvbdemux->playing = 0;
+	dvbdemux->recording = 0;
+	dvbdemux->tsbufp = 0;
+
+	if (!dvbdemux->check_crc32)
+		dvbdemux->check_crc32 = dvb_dmx_crc32;
+
+	if (!dvbdemux->memcopy)
+		dvbdemux->memcopy = dvb_dmx_memcopy;
+
+	dmx->frontend = NULL;
+	dmx->priv = dvbdemux;
+	dmx->open = dvbdmx_open;
+	dmx->close = dvbdmx_close;
+	dmx->write = dvbdmx_write;
+	dmx->allocate_ts_feed = dvbdmx_allocate_ts_feed;
+	dmx->release_ts_feed = dvbdmx_release_ts_feed;
+	dmx->allocate_section_feed = dvbdmx_allocate_section_feed;
+	dmx->release_section_feed = dvbdmx_release_section_feed;
+
+	dmx->add_frontend = dvbdmx_add_frontend;
+	dmx->remove_frontend = dvbdmx_remove_frontend;
+	dmx->get_frontends = dvbdmx_get_frontends;
+	dmx->connect_frontend = dvbdmx_connect_frontend;
+	dmx->disconnect_frontend = dvbdmx_disconnect_frontend;
+	dmx->get_pes_pids = dvbdmx_get_pes_pids;
+
+	mutex_init(&dvbdemux->mutex);
+	spin_lock_init(&dvbdemux->lock);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(dvb_dmx_init);
+
+void dvb_dmx_release(struct dvb_demux *dvbdemux)
+{
+	vfree(dvbdemux->cnt_storage);
+	vfree(dvbdemux->filter);
+	vfree(dvbdemux->feed);
+}
+
+EXPORT_SYMBOL(dvb_dmx_release);
diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h
new file mode 100644
index 0000000..fa7188a
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_demux.h
@@ -0,0 +1,151 @@
+/*
+ * dvb_demux.h: DVB kernel demux API
+ *
+ * Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler
+ *                         for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVB_DEMUX_H_
+#define _DVB_DEMUX_H_
+
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+
+#include "demux.h"
+
+#define DMX_TYPE_TS  0
+#define DMX_TYPE_SEC 1
+#define DMX_TYPE_PES 2
+
+#define DMX_STATE_FREE      0
+#define DMX_STATE_ALLOCATED 1
+#define DMX_STATE_SET       2
+#define DMX_STATE_READY     3
+#define DMX_STATE_GO        4
+
+#define DVB_DEMUX_MASK_MAX 18
+
+#define MAX_PID 0x1fff
+
+#define SPEED_PKTS_INTERVAL 50000
+
+struct dvb_demux_filter {
+	struct dmx_section_filter filter;
+	u8 maskandmode[DMX_MAX_FILTER_SIZE];
+	u8 maskandnotmode[DMX_MAX_FILTER_SIZE];
+	int doneq;
+
+	struct dvb_demux_filter *next;
+	struct dvb_demux_feed *feed;
+	int index;
+	int state;
+	int type;
+
+	u16 hw_handle;
+	struct timer_list timer;
+};
+
+#define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head)
+
+struct dvb_demux_feed {
+	union {
+		struct dmx_ts_feed ts;
+		struct dmx_section_feed sec;
+	} feed;
+
+	union {
+		dmx_ts_cb ts;
+		dmx_section_cb sec;
+	} cb;
+
+	struct dvb_demux *demux;
+	void *priv;
+	int type;
+	int state;
+	u16 pid;
+	u8 *buffer;
+	int buffer_size;
+
+	struct timespec timeout;
+	struct dvb_demux_filter *filter;
+
+	int ts_type;
+	enum dmx_ts_pes pes_type;
+
+	int cc;
+	int pusi_seen;		/* prevents feeding of garbage from previous section */
+
+	u16 peslen;
+
+	struct list_head list_head;
+	unsigned int index;	/* a unique index for each feed (can be used as hardware pid filter index) */
+};
+
+struct dvb_demux {
+	struct dmx_demux dmx;
+	void *priv;
+	int filternum;
+	int feednum;
+	int (*start_feed)(struct dvb_demux_feed *feed);
+	int (*stop_feed)(struct dvb_demux_feed *feed);
+	int (*write_to_decoder)(struct dvb_demux_feed *feed,
+				 const u8 *buf, size_t len);
+	u32 (*check_crc32)(struct dvb_demux_feed *feed,
+			    const u8 *buf, size_t len);
+	void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst,
+			 const u8 *src, size_t len);
+
+	int users;
+#define MAX_DVB_DEMUX_USERS 10
+	struct dvb_demux_filter *filter;
+	struct dvb_demux_feed *feed;
+
+	struct list_head frontend_list;
+
+	struct dvb_demux_feed *pesfilter[DMX_TS_PES_OTHER];
+	u16 pids[DMX_TS_PES_OTHER];
+	int playing;
+	int recording;
+
+#define DMX_MAX_PID 0x2000
+	struct list_head feed_list;
+	u8 tsbuf[204];
+	int tsbufp;
+
+	struct mutex mutex;
+	spinlock_t lock;
+
+	uint8_t *cnt_storage; /* for TS continuity check */
+
+	struct timespec speed_last_time; /* for TS speed check */
+	uint32_t speed_pkts_cnt; /* for TS speed check */
+};
+
+int dvb_dmx_init(struct dvb_demux *dvbdemux);
+void dvb_dmx_release(struct dvb_demux *dvbdemux);
+void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf,
+			      size_t count);
+void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
+void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf,
+			  size_t count);
+void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf,
+			  size_t count);
+
+#endif /* _DVB_DEMUX_H_ */
diff --git a/drivers/media/dvb-core/dvb_filter.c b/drivers/media/dvb-core/dvb_filter.c
new file mode 100644
index 0000000..772003f
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_filter.c
@@ -0,0 +1,603 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include "dvb_filter.h"
+
+#if 0
+static unsigned int bitrates[3][16] =
+{{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},
+ {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0},
+ {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}};
+#endif
+
+static u32 freq[4] = {480, 441, 320, 0};
+
+static unsigned int ac3_bitrates[32] =
+    {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640,
+     0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+static u32 ac3_frames[3][32] =
+    {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024,
+      1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0},
+     {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114,
+      1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0},
+     {96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344,
+      1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+
+
+
+#if 0
+static void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv,
+		  void (*pes_write)(u8 *buf, int count, void *data),
+		  void *priv)
+{
+	dvb_filter_ipack_init(pa, IPACKS, pes_write);
+	dvb_filter_ipack_init(pv, IPACKS, pes_write);
+	pa->pid = pida;
+	pv->pid = pidv;
+	pa->data = priv;
+	pv->data = priv;
+}
+#endif
+
+#if 0
+static void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188)
+{
+	u8 off = 0;
+
+	if (!buf || !p ){
+		printk("NULL POINTER IDIOT\n");
+		return;
+	}
+	if (buf[1]&PAY_START) {
+		if (p->plength == MMAX_PLENGTH-6 && p->found>6){
+			p->plength = p->found-6;
+			p->found = 0;
+			send_ipack(p);
+			dvb_filter_ipack_reset(p);
+		}
+	}
+	if (buf[3] & ADAPT_FIELD) {  // adaptation field?
+		off = buf[4] + 1;
+		if (off+4 > 187) return;
+	}
+	dvb_filter_instant_repack(buf+4+off, TS_SIZE-4-off, p);
+}
+#endif
+
+#if 0
+/* needs 5 byte input, returns picture coding type*/
+static int read_picture_header(u8 *headr, struct mpg_picture *pic, int field, int pr)
+{
+	u8 pct;
+
+	if (pr) printk( "Pic header: ");
+	pic->temporal_reference[field] = (( headr[0] << 2 ) |
+					  (headr[1] & 0x03) )& 0x03ff;
+	if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]);
+
+	pct = ( headr[1] >> 2 ) & 0x07;
+	pic->picture_coding_type[field] = pct;
+	if (pr) {
+		switch(pct){
+			case I_FRAME:
+				printk( "  I-FRAME");
+				break;
+			case B_FRAME:
+				printk( "  B-FRAME");
+				break;
+			case P_FRAME:
+				printk( "  P-FRAME");
+				break;
+		}
+	}
+
+
+	pic->vinfo.vbv_delay  = (( headr[1] >> 5 ) | ( headr[2] << 3) |
+				 ( (headr[3] & 0x1F) << 11) ) & 0xffff;
+
+	if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay);
+
+	pic->picture_header_parameter = ( headr[3] & 0xe0 ) |
+		((headr[4] & 0x80) >> 3);
+
+	if ( pct == B_FRAME ){
+		pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f;
+	}
+	if (pr) printk( " pic head param: 0x%x",
+			pic->picture_header_parameter);
+
+	return pct;
+}
+#endif
+
+#if 0
+/* needs 4 byte input */
+static int read_gop_header(u8 *headr, struct mpg_picture *pic, int pr)
+{
+	if (pr) printk("GOP header: ");
+
+	pic->time_code  = (( headr[0] << 17 ) | ( headr[1] << 9) |
+			   ( headr[2] << 1 ) | (headr[3] &0x01)) & 0x1ffffff;
+
+	if (pr) printk(" time: %d:%d.%d ", (headr[0]>>2)& 0x1F,
+		       ((headr[0]<<4)& 0x30)| ((headr[1]>>4)& 0x0F),
+		       ((headr[1]<<3)& 0x38)| ((headr[2]>>5)& 0x0F));
+
+	if ( ( headr[3] & 0x40 ) != 0 ){
+		pic->closed_gop = 1;
+	} else {
+		pic->closed_gop = 0;
+	}
+	if (pr) printk("closed: %d", pic->closed_gop);
+
+	if ( ( headr[3] & 0x20 ) != 0 ){
+		pic->broken_link = 1;
+	} else {
+		pic->broken_link = 0;
+	}
+	if (pr) printk(" broken: %d\n", pic->broken_link);
+
+	return 0;
+}
+#endif
+
+#if 0
+/* needs 8 byte input */
+static int read_sequence_header(u8 *headr, struct dvb_video_info *vi, int pr)
+{
+	int sw;
+	int form = -1;
+
+	if (pr) printk("Reading sequence header\n");
+
+	vi->horizontal_size	= ((headr[1] &0xF0) >> 4) | (headr[0] << 4);
+	vi->vertical_size	= ((headr[1] &0x0F) << 8) | (headr[2]);
+
+	sw = (int)((headr[3]&0xF0) >> 4) ;
+
+	switch( sw ){
+	case 1:
+		if (pr)
+			printk("Videostream: ASPECT: 1:1");
+		vi->aspect_ratio = 100;
+		break;
+	case 2:
+		if (pr)
+			printk("Videostream: ASPECT: 4:3");
+		vi->aspect_ratio = 133;
+		break;
+	case 3:
+		if (pr)
+			printk("Videostream: ASPECT: 16:9");
+		vi->aspect_ratio = 177;
+		break;
+	case 4:
+		if (pr)
+			printk("Videostream: ASPECT: 2.21:1");
+		vi->aspect_ratio = 221;
+		break;
+
+	case 5 ... 15:
+		if (pr)
+			printk("Videostream: ASPECT: reserved");
+		vi->aspect_ratio = 0;
+		break;
+
+	default:
+		vi->aspect_ratio = 0;
+		return -1;
+	}
+
+	if (pr)
+		printk("  Size = %dx%d",vi->horizontal_size,vi->vertical_size);
+
+	sw = (int)(headr[3]&0x0F);
+
+	switch ( sw ) {
+	case 1:
+		if (pr)
+			printk("  FRate: 23.976 fps");
+		vi->framerate = 23976;
+		form = -1;
+		break;
+	case 2:
+		if (pr)
+			printk("  FRate: 24 fps");
+		vi->framerate = 24000;
+		form = -1;
+		break;
+	case 3:
+		if (pr)
+			printk("  FRate: 25 fps");
+		vi->framerate = 25000;
+		form = VIDEO_MODE_PAL;
+		break;
+	case 4:
+		if (pr)
+			printk("  FRate: 29.97 fps");
+		vi->framerate = 29970;
+		form = VIDEO_MODE_NTSC;
+		break;
+	case 5:
+		if (pr)
+			printk("  FRate: 30 fps");
+		vi->framerate = 30000;
+		form = VIDEO_MODE_NTSC;
+		break;
+	case 6:
+		if (pr)
+			printk("  FRate: 50 fps");
+		vi->framerate = 50000;
+		form = VIDEO_MODE_PAL;
+		break;
+	case 7:
+		if (pr)
+			printk("  FRate: 60 fps");
+		vi->framerate = 60000;
+		form = VIDEO_MODE_NTSC;
+		break;
+	}
+
+	vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03);
+
+	vi->vbv_buffer_size
+		= (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5);
+
+	if (pr){
+		printk("  BRate: %d Mbit/s",4*(vi->bit_rate)/10000);
+		printk("  vbvbuffer %d",16*1024*(vi->vbv_buffer_size));
+		printk("\n");
+	}
+
+	vi->video_format = form;
+
+	return 0;
+}
+#endif
+
+
+#if 0
+static int get_vinfo(u8 *mbuf, int count, struct dvb_video_info *vi, int pr)
+{
+	u8 *headr;
+	int found = 0;
+	int c = 0;
+
+	while (found < 4 && c+4 < count){
+		u8 *b;
+
+		b = mbuf+c;
+		if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01
+		     && b[3] == 0xb3) found = 4;
+		else {
+			c++;
+		}
+	}
+
+	if (! found) return -1;
+	c += 4;
+	if (c+12 >= count) return -1;
+	headr = mbuf+c;
+	if (read_sequence_header(headr, vi, pr) < 0) return -1;
+	vi->off = c-4;
+	return 0;
+}
+#endif
+
+
+#if 0
+static int get_ainfo(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr)
+{
+	u8 *headr;
+	int found = 0;
+	int c = 0;
+	int fr = 0;
+
+	while (found < 2 && c < count){
+		u8 b[2];
+		memcpy( b, mbuf+c, 2);
+
+		if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8)
+			found = 2;
+		else {
+			c++;
+		}
+	}
+
+	if (!found) return -1;
+
+	if (c+3 >= count) return -1;
+	headr = mbuf+c;
+
+	ai->layer = (headr[1] & 0x06) >> 1;
+
+	if (pr)
+		printk("Audiostream: Layer: %d", 4-ai->layer);
+
+
+	ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000;
+
+	if (pr){
+		if (ai->bit_rate == 0)
+			printk("  Bit rate: free");
+		else if (ai->bit_rate == 0xf)
+			printk("  BRate: reserved");
+		else
+			printk("  BRate: %d kb/s", ai->bit_rate/1000);
+	}
+
+	fr = (headr[2] & 0x0c ) >> 2;
+	ai->frequency = freq[fr]*100;
+	if (pr){
+		if (ai->frequency == 3)
+			printk("  Freq: reserved\n");
+		else
+			printk("  Freq: %d kHz\n",ai->frequency);
+
+	}
+	ai->off = c;
+	return 0;
+}
+#endif
+
+
+int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr)
+{
+	u8 *headr;
+	int found = 0;
+	int c = 0;
+	u8 frame = 0;
+	int fr = 0;
+
+	while ( !found  && c < count){
+		u8 *b = mbuf+c;
+
+		if ( b[0] == 0x0b &&  b[1] == 0x77 )
+			found = 1;
+		else {
+			c++;
+		}
+	}
+
+	if (!found) return -1;
+	if (pr)
+		printk("Audiostream: AC3");
+
+	ai->off = c;
+	if (c+5 >= count) return -1;
+
+	ai->layer = 0;  // 0 for AC3
+	headr = mbuf+c+2;
+
+	frame = (headr[2]&0x3f);
+	ai->bit_rate = ac3_bitrates[frame >> 1]*1000;
+
+	if (pr)
+		printk("  BRate: %d kb/s", (int) ai->bit_rate/1000);
+
+	ai->frequency = (headr[2] & 0xc0 ) >> 6;
+	fr = (headr[2] & 0xc0 ) >> 6;
+	ai->frequency = freq[fr]*100;
+	if (pr) printk ("  Freq: %d Hz\n", (int) ai->frequency);
+
+
+	ai->framesize = ac3_frames[fr][frame >> 1];
+	if ((frame & 1) &&  (fr == 1)) ai->framesize++;
+	ai->framesize = ai->framesize << 1;
+	if (pr) printk ("  Framesize %d\n",(int) ai->framesize);
+
+
+	return 0;
+}
+EXPORT_SYMBOL(dvb_filter_get_ac3info);
+
+
+#if 0
+static u8 *skip_pes_header(u8 **bufp)
+{
+	u8 *inbuf = *bufp;
+	u8 *buf = inbuf;
+	u8 *pts = NULL;
+	int skip = 0;
+
+	static const int mpeg1_skip_table[16] = {
+		1, 0xffff,      5,     10, 0xffff, 0xffff, 0xffff, 0xffff,
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
+	};
+
+
+	if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */
+		if (buf[7] & PTS_ONLY)
+			pts = buf+9;
+		else pts = NULL;
+		buf = inbuf + 9 + inbuf[8];
+	} else {        /* mpeg1 */
+		for (buf = inbuf + 6; *buf == 0xff; buf++)
+			if (buf == inbuf + 6 + 16) {
+				break;
+			}
+		if ((*buf & 0xc0) == 0x40)
+			buf += 2;
+		skip = mpeg1_skip_table [*buf >> 4];
+		if (skip == 5 || skip == 10) pts = buf;
+		else pts = NULL;
+
+		buf += mpeg1_skip_table [*buf >> 4];
+	}
+
+	*bufp = buf;
+	return pts;
+}
+#endif
+
+#if 0
+static void initialize_quant_matrix( u32 *matrix )
+{
+	int i;
+
+	matrix[0]  = 0x08101013;
+	matrix[1]  = 0x10131616;
+	matrix[2]  = 0x16161616;
+	matrix[3]  = 0x1a181a1b;
+	matrix[4]  = 0x1b1b1a1a;
+	matrix[5]  = 0x1a1a1b1b;
+	matrix[6]  = 0x1b1d1d1d;
+	matrix[7]  = 0x2222221d;
+	matrix[8]  = 0x1d1d1b1b;
+	matrix[9]  = 0x1d1d2020;
+	matrix[10] = 0x22222526;
+	matrix[11] = 0x25232322;
+	matrix[12] = 0x23262628;
+	matrix[13] = 0x28283030;
+	matrix[14] = 0x2e2e3838;
+	matrix[15] = 0x3a454553;
+
+	for ( i = 16 ; i < 32 ; i++ )
+		matrix[i] = 0x10101010;
+}
+#endif
+
+#if 0
+static void initialize_mpg_picture(struct mpg_picture *pic)
+{
+	int i;
+
+	/* set MPEG1 */
+	pic->mpeg1_flag = 1;
+	pic->profile_and_level = 0x4A ;        /* MP@LL */
+	pic->progressive_sequence = 1;
+	pic->low_delay = 0;
+
+	pic->sequence_display_extension_flag = 0;
+	for ( i = 0 ; i < 4 ; i++ ){
+		pic->frame_centre_horizontal_offset[i] = 0;
+		pic->frame_centre_vertical_offset[i] = 0;
+	}
+	pic->last_frame_centre_horizontal_offset = 0;
+	pic->last_frame_centre_vertical_offset = 0;
+
+	pic->picture_display_extension_flag[0] = 0;
+	pic->picture_display_extension_flag[1] = 0;
+	pic->sequence_header_flag = 0;
+	pic->gop_flag = 0;
+	pic->sequence_end_flag = 0;
+}
+#endif
+
+#if 0
+static void mpg_set_picture_parameter( int32_t field_type, struct mpg_picture *pic )
+{
+	int16_t last_h_offset;
+	int16_t last_v_offset;
+
+	int16_t *p_h_offset;
+	int16_t *p_v_offset;
+
+	if ( pic->mpeg1_flag ){
+		pic->picture_structure[field_type] = VIDEO_FRAME_PICTURE;
+		pic->top_field_first = 0;
+		pic->repeat_first_field = 0;
+		pic->progressive_frame = 1;
+		pic->picture_coding_parameter = 0x000010;
+	}
+
+	/* Reset flag */
+	pic->picture_display_extension_flag[field_type] = 0;
+
+	last_h_offset = pic->last_frame_centre_horizontal_offset;
+	last_v_offset = pic->last_frame_centre_vertical_offset;
+	if ( field_type == FIRST_FIELD ){
+		p_h_offset = pic->frame_centre_horizontal_offset;
+		p_v_offset = pic->frame_centre_vertical_offset;
+		*p_h_offset = last_h_offset;
+		*(p_h_offset + 1) = last_h_offset;
+		*(p_h_offset + 2) = last_h_offset;
+		*p_v_offset = last_v_offset;
+		*(p_v_offset + 1) = last_v_offset;
+		*(p_v_offset + 2) = last_v_offset;
+	} else {
+		pic->frame_centre_horizontal_offset[3] = last_h_offset;
+		pic->frame_centre_vertical_offset[3] = last_v_offset;
+	}
+}
+#endif
+
+#if 0
+static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_type)
+{
+	pic->picture_header = 0;
+	pic->sequence_header_data
+		= ( INIT_HORIZONTAL_SIZE << 20 )
+			| ( INIT_VERTICAL_SIZE << 8 )
+			| ( INIT_ASPECT_RATIO << 4 )
+			| ( INIT_FRAME_RATE );
+	pic->mpeg1_flag = 0;
+	pic->vinfo.horizontal_size
+		= INIT_DISP_HORIZONTAL_SIZE;
+	pic->vinfo.vertical_size
+		= INIT_DISP_VERTICAL_SIZE;
+	pic->picture_display_extension_flag[field_type]
+		= 0;
+	pic->pts_flag[field_type] = 0;
+
+	pic->sequence_gop_header = 0;
+	pic->picture_header = 0;
+	pic->sequence_header_flag = 0;
+	pic->gop_flag = 0;
+	pic->sequence_end_flag = 0;
+	pic->sequence_display_extension_flag = 0;
+	pic->last_frame_centre_horizontal_offset = 0;
+	pic->last_frame_centre_vertical_offset = 0;
+	pic->channel = chan;
+}
+#endif
+
+void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
+			    dvb_filter_pes2ts_cb_t *cb, void *priv)
+{
+	unsigned char *buf=p2ts->buf;
+
+	buf[0]=0x47;
+	buf[1]=(pid>>8);
+	buf[2]=pid&0xff;
+	p2ts->cc=0;
+	p2ts->cb=cb;
+	p2ts->priv=priv;
+}
+EXPORT_SYMBOL(dvb_filter_pes2ts_init);
+
+int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
+		      int len, int payload_start)
+{
+	unsigned char *buf=p2ts->buf;
+	int ret=0, rest;
+
+	//len=6+((pes[4]<<8)|pes[5]);
+
+	if (payload_start)
+		buf[1]|=0x40;
+	else
+		buf[1]&=~0x40;
+	while (len>=184) {
+		buf[3]=0x10|((p2ts->cc++)&0x0f);
+		memcpy(buf+4, pes, 184);
+		if ((ret=p2ts->cb(p2ts->priv, buf)))
+			return ret;
+		len-=184; pes+=184;
+		buf[1]&=~0x40;
+	}
+	if (!len)
+		return 0;
+	buf[3]=0x30|((p2ts->cc++)&0x0f);
+	rest=183-len;
+	if (rest) {
+		buf[5]=0x00;
+		if (rest-1)
+			memset(buf+6, 0xff, rest-1);
+	}
+	buf[4]=rest;
+	memcpy(buf+5+rest, pes, len);
+	return p2ts->cb(p2ts->priv, buf);
+}
+EXPORT_SYMBOL(dvb_filter_pes2ts);
diff --git a/drivers/media/dvb-core/dvb_filter.h b/drivers/media/dvb-core/dvb_filter.h
new file mode 100644
index 0000000..375e3be
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_filter.h
@@ -0,0 +1,246 @@
+/*
+ * dvb_filter.h
+ *
+ * Copyright (C) 2003 Convergence GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _DVB_FILTER_H_
+#define _DVB_FILTER_H_
+
+#include <linux/slab.h>
+
+#include "demux.h"
+
+typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *);
+
+struct dvb_filter_pes2ts {
+	unsigned char buf[188];
+	unsigned char cc;
+	dvb_filter_pes2ts_cb_t *cb;
+	void *priv;
+};
+
+void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
+			    dvb_filter_pes2ts_cb_t *cb, void *priv);
+
+int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
+		      int len, int payload_start);
+
+
+#define PROG_STREAM_MAP  0xBC
+#define PRIVATE_STREAM1  0xBD
+#define PADDING_STREAM   0xBE
+#define PRIVATE_STREAM2  0xBF
+#define AUDIO_STREAM_S   0xC0
+#define AUDIO_STREAM_E   0xDF
+#define VIDEO_STREAM_S   0xE0
+#define VIDEO_STREAM_E   0xEF
+#define ECM_STREAM       0xF0
+#define EMM_STREAM       0xF1
+#define DSM_CC_STREAM    0xF2
+#define ISO13522_STREAM  0xF3
+#define PROG_STREAM_DIR  0xFF
+
+#define DVB_PICTURE_START    0x00
+#define DVB_USER_START       0xb2
+#define DVB_SEQUENCE_HEADER  0xb3
+#define DVB_SEQUENCE_ERROR   0xb4
+#define DVB_EXTENSION_START  0xb5
+#define DVB_SEQUENCE_END     0xb7
+#define DVB_GOP_START        0xb8
+#define DVB_EXCEPT_SLICE     0xb0
+
+#define SEQUENCE_EXTENSION           0x01
+#define SEQUENCE_DISPLAY_EXTENSION   0x02
+#define PICTURE_CODING_EXTENSION     0x08
+#define QUANT_MATRIX_EXTENSION       0x03
+#define PICTURE_DISPLAY_EXTENSION    0x07
+
+#define I_FRAME 0x01
+#define B_FRAME 0x02
+#define P_FRAME 0x03
+
+/* Initialize sequence_data */
+#define INIT_HORIZONTAL_SIZE        720
+#define INIT_VERTICAL_SIZE          576
+#define INIT_ASPECT_RATIO          0x02
+#define INIT_FRAME_RATE            0x03
+#define INIT_DISP_HORIZONTAL_SIZE   540
+#define INIT_DISP_VERTICAL_SIZE     576
+
+
+//flags2
+#define PTS_DTS_FLAGS    0xC0
+#define ESCR_FLAG        0x20
+#define ES_RATE_FLAG     0x10
+#define DSM_TRICK_FLAG   0x08
+#define ADD_CPY_FLAG     0x04
+#define PES_CRC_FLAG     0x02
+#define PES_EXT_FLAG     0x01
+
+//pts_dts flags
+#define PTS_ONLY         0x80
+#define PTS_DTS          0xC0
+
+#define TS_SIZE        188
+#define TRANS_ERROR    0x80
+#define PAY_START      0x40
+#define TRANS_PRIO     0x20
+#define PID_MASK_HI    0x1F
+//flags
+#define TRANS_SCRMBL1  0x80
+#define TRANS_SCRMBL2  0x40
+#define ADAPT_FIELD    0x20
+#define PAYLOAD        0x10
+#define COUNT_MASK     0x0F
+
+// adaptation flags
+#define DISCON_IND     0x80
+#define RAND_ACC_IND   0x40
+#define ES_PRI_IND     0x20
+#define PCR_FLAG       0x10
+#define OPCR_FLAG      0x08
+#define SPLICE_FLAG    0x04
+#define TRANS_PRIV     0x02
+#define ADAP_EXT_FLAG  0x01
+
+// adaptation extension flags
+#define LTW_FLAG       0x80
+#define PIECE_RATE     0x40
+#define SEAM_SPLICE    0x20
+
+
+#define MAX_PLENGTH 0xFFFF
+#define MMAX_PLENGTH (256*MAX_PLENGTH)
+
+#ifndef IPACKS
+#define IPACKS 2048
+#endif
+
+struct ipack {
+	int size;
+	int found;
+	u8 *buf;
+	u8 cid;
+	u32 plength;
+	u8 plen[2];
+	u8 flag1;
+	u8 flag2;
+	u8 hlength;
+	u8 pts[5];
+	u16 *pid;
+	int mpeg;
+	u8 check;
+	int which;
+	int done;
+	void *data;
+	void (*func)(u8 *buf,  int size, void *priv);
+	int count;
+	int repack_subids;
+};
+
+struct dvb_video_info {
+	u32 horizontal_size;
+	u32 vertical_size;
+	u32 aspect_ratio;
+	u32 framerate;
+	u32 video_format;
+	u32 bit_rate;
+	u32 comp_bit_rate;
+	u32 vbv_buffer_size;
+	s16 vbv_delay;
+	u32 CSPF;
+	u32 off;
+};
+
+#define OFF_SIZE 4
+#define FIRST_FIELD 0
+#define SECOND_FIELD 1
+#define VIDEO_FRAME_PICTURE 0x03
+
+struct mpg_picture {
+	int       channel;
+	struct dvb_video_info vinfo;
+	u32      *sequence_gop_header;
+	u32      *picture_header;
+	s32       time_code;
+	int       low_delay;
+	int       closed_gop;
+	int       broken_link;
+	int       sequence_header_flag;
+	int       gop_flag;
+	int       sequence_end_flag;
+
+	u8        profile_and_level;
+	s32       picture_coding_parameter;
+	u32       matrix[32];
+	s8        matrix_change_flag;
+
+	u8        picture_header_parameter;
+  /* bit 0 - 2: bwd f code
+     bit 3    : fpb vector
+     bit 4 - 6: fwd f code
+     bit 7    : fpf vector */
+
+	int       mpeg1_flag;
+	int       progressive_sequence;
+	int       sequence_display_extension_flag;
+	u32       sequence_header_data;
+	s16       last_frame_centre_horizontal_offset;
+	s16       last_frame_centre_vertical_offset;
+
+	u32       pts[2]; /* [0] 1st field, [1] 2nd field */
+	int       top_field_first;
+	int       repeat_first_field;
+	int       progressive_frame;
+	int       bank;
+	int       forward_bank;
+	int       backward_bank;
+	int       compress;
+	s16       frame_centre_horizontal_offset[OFF_SIZE];
+		  /* [0-2] 1st field, [3] 2nd field */
+	s16       frame_centre_vertical_offset[OFF_SIZE];
+		  /* [0-2] 1st field, [3] 2nd field */
+	s16       temporal_reference[2];
+		  /* [0] 1st field, [1] 2nd field */
+
+	s8        picture_coding_type[2];
+		  /* [0] 1st field, [1] 2nd field */
+	s8        picture_structure[2];
+		  /* [0] 1st field, [1] 2nd field */
+	s8        picture_display_extension_flag[2];
+		  /* [0] 1st field, [1] 2nd field */
+		  /* picture_display_extenion() 0:no 1:exit*/
+	s8        pts_flag[2];
+		  /* [0] 1st field, [1] 2nd field */
+};
+
+struct dvb_audio_info {
+	int layer;
+	u32 bit_rate;
+	u32 frequency;
+	u32 mode;
+	u32 mode_extension ;
+	u32 emphasis;
+	u32 framesize;
+	u32 off;
+};
+
+int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr);
+
+
+#endif
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
new file mode 100644
index 0000000..aa4d4d8
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -0,0 +1,2591 @@
+/*
+ * dvb_frontend.c: DVB frontend tuning interface/thread
+ *
+ *
+ * Copyright (C) 1999-2001 Ralph  Metzler
+ *			   Marcus Metzler
+ *			   Holger Waechtler
+ *				      for convergence integrated media GmbH
+ *
+ * Copyright (C) 2004 Andrew de Quincey (tuning thread cleanup)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+/* Enables DVBv3 compatibility bits at the headers */
+#define __DVB_CORE__
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/semaphore.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/freezer.h>
+#include <linux/jiffies.h>
+#include <linux/kthread.h>
+#include <asm/processor.h>
+
+#include "dvb_frontend.h"
+#include "dvbdev.h"
+#include <linux/dvb/version.h>
+
+static int dvb_frontend_debug;
+static int dvb_shutdown_timeout;
+static int dvb_force_auto_inversion;
+static int dvb_override_tune_delay;
+static int dvb_powerdown_on_sleep = 1;
+static int dvb_mfe_wait_time = 5;
+
+module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
+MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off).");
+module_param(dvb_shutdown_timeout, int, 0644);
+MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");
+module_param(dvb_force_auto_inversion, int, 0644);
+MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always");
+module_param(dvb_override_tune_delay, int, 0644);
+MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
+module_param(dvb_powerdown_on_sleep, int, 0644);
+MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");
+module_param(dvb_mfe_wait_time, int, 0644);
+MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)");
+
+#define dprintk if (dvb_frontend_debug) printk
+
+#define FESTATE_IDLE 1
+#define FESTATE_RETUNE 2
+#define FESTATE_TUNING_FAST 4
+#define FESTATE_TUNING_SLOW 8
+#define FESTATE_TUNED 16
+#define FESTATE_ZIGZAG_FAST 32
+#define FESTATE_ZIGZAG_SLOW 64
+#define FESTATE_DISEQC 128
+#define FESTATE_ERROR 256
+#define FESTATE_WAITFORLOCK (FESTATE_TUNING_FAST | FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW | FESTATE_DISEQC)
+#define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST)
+#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
+#define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
+
+#define FE_ALGO_HW		1
+/*
+ * FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
+ * FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.
+ * FESTATE_TUNING_FAST. Tuning parameters have been supplied and fast zigzag scan is in progress.
+ * FESTATE_TUNING_SLOW. Tuning parameters have been supplied. Fast zigzag failed, so we're trying again, but slower.
+ * FESTATE_TUNED. The frontend has successfully locked on.
+ * FESTATE_ZIGZAG_FAST. The lock has been lost, and a fast zigzag has been initiated to try and regain it.
+ * FESTATE_ZIGZAG_SLOW. The lock has been lost. Fast zigzag has been failed, so we're trying again, but slower.
+ * FESTATE_DISEQC. A DISEQC command has just been issued.
+ * FESTATE_WAITFORLOCK. When we're waiting for a lock.
+ * FESTATE_SEARCHING_FAST. When we're searching for a signal using a fast zigzag scan.
+ * FESTATE_SEARCHING_SLOW. When we're searching for a signal using a slow zigzag scan.
+ * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
+ */
+
+#define DVB_FE_NO_EXIT	0
+#define DVB_FE_NORMAL_EXIT	1
+#define DVB_FE_DEVICE_REMOVED	2
+
+static DEFINE_MUTEX(frontend_mutex);
+
+struct dvb_frontend_private {
+
+	/* thread/frontend values */
+	struct dvb_device *dvbdev;
+	struct dvb_frontend_parameters parameters_out;
+	struct dvb_fe_events events;
+	struct semaphore sem;
+	struct list_head list_head;
+	wait_queue_head_t wait_queue;
+	struct task_struct *thread;
+	unsigned long release_jiffies;
+	unsigned int exit;
+	unsigned int wakeup;
+	fe_status_t status;
+	unsigned long tune_mode_flags;
+	unsigned int delay;
+	unsigned int reinitialise;
+	int tone;
+	int voltage;
+
+	/* swzigzag values */
+	unsigned int state;
+	unsigned int bending;
+	int lnb_drift;
+	unsigned int inversion;
+	unsigned int auto_step;
+	unsigned int auto_sub_step;
+	unsigned int started_auto_step;
+	unsigned int min_delay;
+	unsigned int max_drift;
+	unsigned int step_size;
+	int quality;
+	unsigned int check_wrapped;
+	enum dvbfe_search algo_status;
+};
+
+static void dvb_frontend_wakeup(struct dvb_frontend *fe);
+static int dtv_get_frontend(struct dvb_frontend *fe,
+			    struct dvb_frontend_parameters *p_out);
+static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
+					   struct dvb_frontend_parameters *p);
+
+static bool has_get_frontend(struct dvb_frontend *fe)
+{
+	return fe->ops.get_frontend != NULL;
+}
+
+/*
+ * Due to DVBv3 API calls, a delivery system should be mapped into one of
+ * the 4 DVBv3 delivery systems (FE_QPSK, FE_QAM, FE_OFDM or FE_ATSC),
+ * otherwise, a DVBv3 call will fail.
+ */
+enum dvbv3_emulation_type {
+	DVBV3_UNKNOWN,
+	DVBV3_QPSK,
+	DVBV3_QAM,
+	DVBV3_OFDM,
+	DVBV3_ATSC,
+};
+
+static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system)
+{
+	switch (delivery_system) {
+	case SYS_DVBC_ANNEX_A:
+	case SYS_DVBC_ANNEX_C:
+		return DVBV3_QAM;
+	case SYS_DVBS:
+	case SYS_DVBS2:
+	case SYS_TURBO:
+	case SYS_ISDBS:
+	case SYS_DSS:
+		return DVBV3_QPSK;
+	case SYS_DVBT:
+	case SYS_DVBT2:
+	case SYS_ISDBT:
+	case SYS_DTMB:
+		return DVBV3_OFDM;
+	case SYS_ATSC:
+	case SYS_ATSCMH:
+	case SYS_DVBC_ANNEX_B:
+		return DVBV3_ATSC;
+	case SYS_UNDEFINED:
+	case SYS_ISDBC:
+	case SYS_DVBH:
+	case SYS_DAB:
+	default:
+		/*
+		 * Doesn't know how to emulate those types and/or
+		 * there's no frontend driver from this type yet
+		 * with some emulation code, so, we're not sure yet how
+		 * to handle them, or they're not compatible with a DVBv3 call.
+		 */
+		return DVBV3_UNKNOWN;
+	}
+}
+
+static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
+{
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	struct dvb_fe_events *events = &fepriv->events;
+	struct dvb_frontend_event *e;
+	int wp;
+
+	dprintk ("%s\n", __func__);
+
+	if ((status & FE_HAS_LOCK) && has_get_frontend(fe))
+		dtv_get_frontend(fe, &fepriv->parameters_out);
+
+	mutex_lock(&events->mtx);
+
+	wp = (events->eventw + 1) % MAX_EVENT;
+	if (wp == events->eventr) {
+		events->overflow = 1;
+		events->eventr = (events->eventr + 1) % MAX_EVENT;
+	}
+
+	e = &events->events[events->eventw];
+	e->status = status;
+	e->parameters = fepriv->parameters_out;
+
+	events->eventw = wp;
+
+	mutex_unlock(&events->mtx);
+
+	wake_up_interruptible (&events->wait_queue);
+}
+
+static int dvb_frontend_get_event(struct dvb_frontend *fe,
+			    struct dvb_frontend_event *event, int flags)
+{
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	struct dvb_fe_events *events = &fepriv->events;
+
+	dprintk ("%s\n", __func__);
+
+	if (events->overflow) {
+		events->overflow = 0;
+		return -EOVERFLOW;
+	}
+
+	if (events->eventw == events->eventr) {
+		int ret;
+
+		if (flags & O_NONBLOCK)
+			return -EWOULDBLOCK;
+
+		up(&fepriv->sem);
+
+		ret = wait_event_interruptible (events->wait_queue,
+						events->eventw != events->eventr);
+
+		if (down_interruptible (&fepriv->sem))
+			return -ERESTARTSYS;
+
+		if (ret < 0)
+			return ret;
+	}
+
+	mutex_lock(&events->mtx);
+	*event = events->events[events->eventr];
+	events->eventr = (events->eventr + 1) % MAX_EVENT;
+	mutex_unlock(&events->mtx);
+
+	return 0;
+}
+
+static void dvb_frontend_clear_events(struct dvb_frontend *fe)
+{
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	struct dvb_fe_events *events = &fepriv->events;
+
+	mutex_lock(&events->mtx);
+	events->eventr = events->eventw;
+	mutex_unlock(&events->mtx);
+}
+
+static void dvb_frontend_init(struct dvb_frontend *fe)
+{
+	dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n",
+		 fe->dvb->num,
+		 fe->id,
+		 fe->ops.info.name);
+
+	if (fe->ops.init)
+		fe->ops.init(fe);
+	if (fe->ops.tuner_ops.init) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		fe->ops.tuner_ops.init(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+}
+
+void dvb_frontend_reinitialise(struct dvb_frontend *fe)
+{
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+	fepriv->reinitialise = 1;
+	dvb_frontend_wakeup(fe);
+}
+EXPORT_SYMBOL(dvb_frontend_reinitialise);
+
+static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked)
+{
+	int q2;
+
+	dprintk ("%s\n", __func__);
+
+	if (locked)
+		(fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256;
+	else
+		(fepriv->quality) = (fepriv->quality * 220 + 0) / 256;
+
+	q2 = fepriv->quality - 128;
+	q2 *= q2;
+
+	fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128);
+}
+
+/**
+ * Performs automatic twiddling of frontend parameters.
+ *
+ * @param fe The frontend concerned.
+ * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT
+ * @returns Number of complete iterations that have been performed.
+ */
+static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped)
+{
+	int autoinversion;
+	int ready = 0;
+	int fe_set_err = 0;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp;
+	int original_inversion = c->inversion;
+	u32 original_frequency = c->frequency;
+
+	/* are we using autoinversion? */
+	autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
+			 (c->inversion == INVERSION_AUTO));
+
+	/* setup parameters correctly */
+	while(!ready) {
+		/* calculate the lnb_drift */
+		fepriv->lnb_drift = fepriv->auto_step * fepriv->step_size;
+
+		/* wrap the auto_step if we've exceeded the maximum drift */
+		if (fepriv->lnb_drift > fepriv->max_drift) {
+			fepriv->auto_step = 0;
+			fepriv->auto_sub_step = 0;
+			fepriv->lnb_drift = 0;
+		}
+
+		/* perform inversion and +/- zigzag */
+		switch(fepriv->auto_sub_step) {
+		case 0:
+			/* try with the current inversion and current drift setting */
+			ready = 1;
+			break;
+
+		case 1:
+			if (!autoinversion) break;
+
+			fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
+			ready = 1;
+			break;
+
+		case 2:
+			if (fepriv->lnb_drift == 0) break;
+
+			fepriv->lnb_drift = -fepriv->lnb_drift;
+			ready = 1;
+			break;
+
+		case 3:
+			if (fepriv->lnb_drift == 0) break;
+			if (!autoinversion) break;
+
+			fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
+			fepriv->lnb_drift = -fepriv->lnb_drift;
+			ready = 1;
+			break;
+
+		default:
+			fepriv->auto_step++;
+			fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */
+			break;
+		}
+
+		if (!ready) fepriv->auto_sub_step++;
+	}
+
+	/* if this attempt would hit where we started, indicate a complete
+	 * iteration has occurred */
+	if ((fepriv->auto_step == fepriv->started_auto_step) &&
+	    (fepriv->auto_sub_step == 0) && check_wrapped) {
+		return 1;
+	}
+
+	dprintk("%s: drift:%i inversion:%i auto_step:%i "
+		"auto_sub_step:%i started_auto_step:%i\n",
+		__func__, fepriv->lnb_drift, fepriv->inversion,
+		fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
+
+	/* set the frontend itself */
+	c->frequency += fepriv->lnb_drift;
+	if (autoinversion)
+		c->inversion = fepriv->inversion;
+	tmp = *c;
+	if (fe->ops.set_frontend)
+		fe_set_err = fe->ops.set_frontend(fe);
+	*c = tmp;
+	if (fe_set_err < 0) {
+		fepriv->state = FESTATE_ERROR;
+		return fe_set_err;
+	}
+
+	c->frequency = original_frequency;
+	c->inversion = original_inversion;
+
+	fepriv->auto_sub_step++;
+	return 0;
+}
+
+static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
+{
+	fe_status_t s = 0;
+	int retval = 0;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp;
+
+	/* if we've got no parameters, just keep idling */
+	if (fepriv->state & FESTATE_IDLE) {
+		fepriv->delay = 3*HZ;
+		fepriv->quality = 0;
+		return;
+	}
+
+	/* in SCAN mode, we just set the frontend when asked and leave it alone */
+	if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
+		if (fepriv->state & FESTATE_RETUNE) {
+			tmp = *c;
+			if (fe->ops.set_frontend)
+				retval = fe->ops.set_frontend(fe);
+			*c = tmp;
+			if (retval < 0)
+				fepriv->state = FESTATE_ERROR;
+			else
+				fepriv->state = FESTATE_TUNED;
+		}
+		fepriv->delay = 3*HZ;
+		fepriv->quality = 0;
+		return;
+	}
+
+	/* get the frontend status */
+	if (fepriv->state & FESTATE_RETUNE) {
+		s = 0;
+	} else {
+		if (fe->ops.read_status)
+			fe->ops.read_status(fe, &s);
+		if (s != fepriv->status) {
+			dvb_frontend_add_event(fe, s);
+			fepriv->status = s;
+		}
+	}
+
+	/* if we're not tuned, and we have a lock, move to the TUNED state */
+	if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
+		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+		fepriv->state = FESTATE_TUNED;
+
+		/* if we're tuned, then we have determined the correct inversion */
+		if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
+		    (c->inversion == INVERSION_AUTO)) {
+			c->inversion = fepriv->inversion;
+		}
+		return;
+	}
+
+	/* if we are tuned already, check we're still locked */
+	if (fepriv->state & FESTATE_TUNED) {
+		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+
+		/* we're tuned, and the lock is still good... */
+		if (s & FE_HAS_LOCK) {
+			return;
+		} else { /* if we _WERE_ tuned, but now don't have a lock */
+			fepriv->state = FESTATE_ZIGZAG_FAST;
+			fepriv->started_auto_step = fepriv->auto_step;
+			fepriv->check_wrapped = 0;
+		}
+	}
+
+	/* don't actually do anything if we're in the LOSTLOCK state,
+	 * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
+	if ((fepriv->state & FESTATE_LOSTLOCK) &&
+	    (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
+		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+		return;
+	}
+
+	/* don't do anything if we're in the DISEQC state, since this
+	 * might be someone with a motorized dish controlled by DISEQC.
+	 * If its actually a re-tune, there will be a SET_FRONTEND soon enough.	*/
+	if (fepriv->state & FESTATE_DISEQC) {
+		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+		return;
+	}
+
+	/* if we're in the RETUNE state, set everything up for a brand
+	 * new scan, keeping the current inversion setting, as the next
+	 * tune is _very_ likely to require the same */
+	if (fepriv->state & FESTATE_RETUNE) {
+		fepriv->lnb_drift = 0;
+		fepriv->auto_step = 0;
+		fepriv->auto_sub_step = 0;
+		fepriv->started_auto_step = 0;
+		fepriv->check_wrapped = 0;
+	}
+
+	/* fast zigzag. */
+	if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
+		fepriv->delay = fepriv->min_delay;
+
+		/* perform a tune */
+		retval = dvb_frontend_swzigzag_autotune(fe,
+							fepriv->check_wrapped);
+		if (retval < 0) {
+			return;
+		} else if (retval) {
+			/* OK, if we've run out of trials at the fast speed.
+			 * Drop back to slow for the _next_ attempt */
+			fepriv->state = FESTATE_SEARCHING_SLOW;
+			fepriv->started_auto_step = fepriv->auto_step;
+			return;
+		}
+		fepriv->check_wrapped = 1;
+
+		/* if we've just retuned, enter the ZIGZAG_FAST state.
+		 * This ensures we cannot return from an
+		 * FE_SET_FRONTEND ioctl before the first frontend tune
+		 * occurs */
+		if (fepriv->state & FESTATE_RETUNE) {
+			fepriv->state = FESTATE_TUNING_FAST;
+		}
+	}
+
+	/* slow zigzag */
+	if (fepriv->state & FESTATE_SEARCHING_SLOW) {
+		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+
+		/* Note: don't bother checking for wrapping; we stay in this
+		 * state until we get a lock */
+		dvb_frontend_swzigzag_autotune(fe, 0);
+	}
+}
+
+static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
+{
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+	if (fepriv->exit != DVB_FE_NO_EXIT)
+		return 1;
+
+	if (fepriv->dvbdev->writers == 1)
+		if (time_after_eq(jiffies, fepriv->release_jiffies +
+				  dvb_shutdown_timeout * HZ))
+			return 1;
+
+	return 0;
+}
+
+static int dvb_frontend_should_wakeup(struct dvb_frontend *fe)
+{
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+	if (fepriv->wakeup) {
+		fepriv->wakeup = 0;
+		return 1;
+	}
+	return dvb_frontend_is_exiting(fe);
+}
+
+static void dvb_frontend_wakeup(struct dvb_frontend *fe)
+{
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+	fepriv->wakeup = 1;
+	wake_up_interruptible(&fepriv->wait_queue);
+}
+
+static int dvb_frontend_thread(void *data)
+{
+	struct dvb_frontend *fe = data;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	fe_status_t s;
+	enum dvbfe_algo algo;
+
+	bool re_tune = false;
+
+	dprintk("%s\n", __func__);
+
+	fepriv->check_wrapped = 0;
+	fepriv->quality = 0;
+	fepriv->delay = 3*HZ;
+	fepriv->status = 0;
+	fepriv->wakeup = 0;
+	fepriv->reinitialise = 0;
+
+	dvb_frontend_init(fe);
+
+	set_freezable();
+	while (1) {
+		up(&fepriv->sem);	    /* is locked when we enter the thread... */
+restart:
+		wait_event_interruptible_timeout(fepriv->wait_queue,
+			dvb_frontend_should_wakeup(fe) || kthread_should_stop()
+				|| freezing(current),
+			fepriv->delay);
+
+		if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
+			/* got signal or quitting */
+			fepriv->exit = DVB_FE_NORMAL_EXIT;
+			break;
+		}
+
+		if (try_to_freeze())
+			goto restart;
+
+		if (down_interruptible(&fepriv->sem))
+			break;
+
+		if (fepriv->reinitialise) {
+			dvb_frontend_init(fe);
+			if (fe->ops.set_tone && fepriv->tone != -1)
+				fe->ops.set_tone(fe, fepriv->tone);
+			if (fe->ops.set_voltage && fepriv->voltage != -1)
+				fe->ops.set_voltage(fe, fepriv->voltage);
+			fepriv->reinitialise = 0;
+		}
+
+		/* do an iteration of the tuning loop */
+		if (fe->ops.get_frontend_algo) {
+			algo = fe->ops.get_frontend_algo(fe);
+			switch (algo) {
+			case DVBFE_ALGO_HW:
+				dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__);
+
+				if (fepriv->state & FESTATE_RETUNE) {
+					dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
+					re_tune = true;
+					fepriv->state = FESTATE_TUNED;
+				} else {
+					re_tune = false;
+				}
+
+				if (fe->ops.tune)
+					fe->ops.tune(fe, re_tune, fepriv->tune_mode_flags, &fepriv->delay, &s);
+
+				if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
+					dprintk("%s: state changed, adding current state\n", __func__);
+					dvb_frontend_add_event(fe, s);
+					fepriv->status = s;
+				}
+				break;
+			case DVBFE_ALGO_SW:
+				dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__);
+				dvb_frontend_swzigzag(fe);
+				break;
+			case DVBFE_ALGO_CUSTOM:
+				dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);
+				if (fepriv->state & FESTATE_RETUNE) {
+					dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);
+					fepriv->state = FESTATE_TUNED;
+				}
+				/* Case where we are going to search for a carrier
+				 * User asked us to retune again for some reason, possibly
+				 * requesting a search with a new set of parameters
+				 */
+				if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
+					if (fe->ops.search) {
+						fepriv->algo_status = fe->ops.search(fe);
+						/* We did do a search as was requested, the flags are
+						 * now unset as well and has the flags wrt to search.
+						 */
+					} else {
+						fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN;
+					}
+				}
+				/* Track the carrier if the search was successful */
+				if (fepriv->algo_status != DVBFE_ALGO_SEARCH_SUCCESS) {
+					fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+					fepriv->delay = HZ / 2;
+				}
+				dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
+				fe->ops.read_status(fe, &s);
+				if (s != fepriv->status) {
+					dvb_frontend_add_event(fe, s); /* update event list */
+					fepriv->status = s;
+					if (!(s & FE_HAS_LOCK)) {
+						fepriv->delay = HZ / 10;
+						fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+					} else {
+						fepriv->delay = 60 * HZ;
+					}
+				}
+				break;
+			default:
+				dprintk("%s: UNDEFINED ALGO !\n", __func__);
+				break;
+			}
+		} else {
+			dvb_frontend_swzigzag(fe);
+		}
+	}
+
+	if (dvb_powerdown_on_sleep) {
+		if (fe->ops.set_voltage)
+			fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
+		if (fe->ops.tuner_ops.sleep) {
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 1);
+			fe->ops.tuner_ops.sleep(fe);
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+		if (fe->ops.sleep)
+			fe->ops.sleep(fe);
+	}
+
+	fepriv->thread = NULL;
+	if (kthread_should_stop())
+		fepriv->exit = DVB_FE_DEVICE_REMOVED;
+	else
+		fepriv->exit = DVB_FE_NO_EXIT;
+	mb();
+
+	dvb_frontend_wakeup(fe);
+	return 0;
+}
+
+static void dvb_frontend_stop(struct dvb_frontend *fe)
+{
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+	dprintk ("%s\n", __func__);
+
+	fepriv->exit = DVB_FE_NORMAL_EXIT;
+	mb();
+
+	if (!fepriv->thread)
+		return;
+
+	kthread_stop(fepriv->thread);
+
+	sema_init(&fepriv->sem, 1);
+	fepriv->state = FESTATE_IDLE;
+
+	/* paranoia check in case a signal arrived */
+	if (fepriv->thread)
+		printk("dvb_frontend_stop: warning: thread %p won't exit\n",
+				fepriv->thread);
+}
+
+s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)
+{
+	return ((curtime.tv_usec < lasttime.tv_usec) ?
+		1000000 - lasttime.tv_usec + curtime.tv_usec :
+		curtime.tv_usec - lasttime.tv_usec);
+}
+EXPORT_SYMBOL(timeval_usec_diff);
+
+static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec)
+{
+	curtime->tv_usec += add_usec;
+	if (curtime->tv_usec >= 1000000) {
+		curtime->tv_usec -= 1000000;
+		curtime->tv_sec++;
+	}
+}
+
+/*
+ * Sleep until gettimeofday() > waketime + add_usec
+ * This needs to be as precise as possible, but as the delay is
+ * usually between 2ms and 32ms, it is done using a scheduled msleep
+ * followed by usleep (normally a busy-wait loop) for the remainder
+ */
+void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec)
+{
+	struct timeval lasttime;
+	s32 delta, newdelta;
+
+	timeval_usec_add(waketime, add_usec);
+
+	do_gettimeofday(&lasttime);
+	delta = timeval_usec_diff(lasttime, *waketime);
+	if (delta > 2500) {
+		msleep((delta - 1500) / 1000);
+		do_gettimeofday(&lasttime);
+		newdelta = timeval_usec_diff(lasttime, *waketime);
+		delta = (newdelta > delta) ? 0 : newdelta;
+	}
+	if (delta > 0)
+		udelay(delta);
+}
+EXPORT_SYMBOL(dvb_frontend_sleep_until);
+
+static int dvb_frontend_start(struct dvb_frontend *fe)
+{
+	int ret;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	struct task_struct *fe_thread;
+
+	dprintk ("%s\n", __func__);
+
+	if (fepriv->thread) {
+		if (fepriv->exit == DVB_FE_NO_EXIT)
+			return 0;
+		else
+			dvb_frontend_stop (fe);
+	}
+
+	if (signal_pending(current))
+		return -EINTR;
+	if (down_interruptible (&fepriv->sem))
+		return -EINTR;
+
+	fepriv->state = FESTATE_IDLE;
+	fepriv->exit = DVB_FE_NO_EXIT;
+	fepriv->thread = NULL;
+	mb();
+
+	fe_thread = kthread_run(dvb_frontend_thread, fe,
+		"kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id);
+	if (IS_ERR(fe_thread)) {
+		ret = PTR_ERR(fe_thread);
+		printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);
+		up(&fepriv->sem);
+		return ret;
+	}
+	fepriv->thread = fe_thread;
+	return 0;
+}
+
+static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,
+					u32 *freq_min, u32 *freq_max)
+{
+	*freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min);
+
+	if (fe->ops.info.frequency_max == 0)
+		*freq_max = fe->ops.tuner_ops.info.frequency_max;
+	else if (fe->ops.tuner_ops.info.frequency_max == 0)
+		*freq_max = fe->ops.info.frequency_max;
+	else
+		*freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);
+
+	if (*freq_min == 0 || *freq_max == 0)
+		printk(KERN_WARNING "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n",
+		       fe->dvb->num,fe->id);
+}
+
+static int dvb_frontend_check_parameters(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 freq_min;
+	u32 freq_max;
+
+	/* range check: frequency */
+	dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max);
+	if ((freq_min && c->frequency < freq_min) ||
+	    (freq_max && c->frequency > freq_max)) {
+		printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n",
+		       fe->dvb->num, fe->id, c->frequency, freq_min, freq_max);
+		return -EINVAL;
+	}
+
+	/* range check: symbol rate */
+	switch (c->delivery_system) {
+	case SYS_DVBS:
+	case SYS_DVBS2:
+	case SYS_TURBO:
+	case SYS_DVBC_ANNEX_A:
+	case SYS_DVBC_ANNEX_C:
+		if ((fe->ops.info.symbol_rate_min &&
+		     c->symbol_rate < fe->ops.info.symbol_rate_min) ||
+		    (fe->ops.info.symbol_rate_max &&
+		     c->symbol_rate > fe->ops.info.symbol_rate_max)) {
+			printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
+			       fe->dvb->num, fe->id, c->symbol_rate,
+			       fe->ops.info.symbol_rate_min,
+			       fe->ops.info.symbol_rate_max);
+			return -EINVAL;
+		}
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int i;
+	u32 delsys;
+
+	delsys = c->delivery_system;
+	memset(c, 0, sizeof(struct dtv_frontend_properties));
+	c->delivery_system = delsys;
+
+	c->state = DTV_CLEAR;
+
+	dprintk("%s() Clearing cache for delivery system %d\n", __func__,
+		c->delivery_system);
+
+	c->transmission_mode = TRANSMISSION_MODE_AUTO;
+	c->bandwidth_hz = 0;	/* AUTO */
+	c->guard_interval = GUARD_INTERVAL_AUTO;
+	c->hierarchy = HIERARCHY_AUTO;
+	c->symbol_rate = 0;
+	c->code_rate_HP = FEC_AUTO;
+	c->code_rate_LP = FEC_AUTO;
+	c->fec_inner = FEC_AUTO;
+	c->rolloff = ROLLOFF_AUTO;
+	c->voltage = SEC_VOLTAGE_OFF;
+	c->sectone = SEC_TONE_OFF;
+	c->pilot = PILOT_AUTO;
+
+	c->isdbt_partial_reception = 0;
+	c->isdbt_sb_mode = 0;
+	c->isdbt_sb_subchannel = 0;
+	c->isdbt_sb_segment_idx = 0;
+	c->isdbt_sb_segment_count = 0;
+	c->isdbt_layer_enabled = 0;
+	for (i = 0; i < 3; i++) {
+		c->layer[i].fec = FEC_AUTO;
+		c->layer[i].modulation = QAM_AUTO;
+		c->layer[i].interleaving = 0;
+		c->layer[i].segment_count = 0;
+	}
+
+	c->isdbs_ts_id = 0;
+	c->dvbt2_plp_id = 0;
+
+	switch (c->delivery_system) {
+	case SYS_DVBS:
+	case SYS_DVBS2:
+	case SYS_TURBO:
+		c->modulation = QPSK;   /* implied for DVB-S in legacy API */
+		c->rolloff = ROLLOFF_35;/* implied for DVB-S */
+		break;
+	case SYS_ATSC:
+		c->modulation = VSB_8;
+		break;
+	default:
+		c->modulation = QAM_AUTO;
+		break;
+	}
+
+	return 0;
+}
+
+#define _DTV_CMD(n, s, b) \
+[n] = { \
+	.name = #n, \
+	.cmd  = n, \
+	.set  = s,\
+	.buffer = b \
+}
+
+static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
+	_DTV_CMD(DTV_TUNE, 1, 0),
+	_DTV_CMD(DTV_CLEAR, 1, 0),
+
+	/* Set */
+	_DTV_CMD(DTV_FREQUENCY, 1, 0),
+	_DTV_CMD(DTV_BANDWIDTH_HZ, 1, 0),
+	_DTV_CMD(DTV_MODULATION, 1, 0),
+	_DTV_CMD(DTV_INVERSION, 1, 0),
+	_DTV_CMD(DTV_DISEQC_MASTER, 1, 1),
+	_DTV_CMD(DTV_SYMBOL_RATE, 1, 0),
+	_DTV_CMD(DTV_INNER_FEC, 1, 0),
+	_DTV_CMD(DTV_VOLTAGE, 1, 0),
+	_DTV_CMD(DTV_TONE, 1, 0),
+	_DTV_CMD(DTV_PILOT, 1, 0),
+	_DTV_CMD(DTV_ROLLOFF, 1, 0),
+	_DTV_CMD(DTV_DELIVERY_SYSTEM, 1, 0),
+	_DTV_CMD(DTV_HIERARCHY, 1, 0),
+	_DTV_CMD(DTV_CODE_RATE_HP, 1, 0),
+	_DTV_CMD(DTV_CODE_RATE_LP, 1, 0),
+	_DTV_CMD(DTV_GUARD_INTERVAL, 1, 0),
+	_DTV_CMD(DTV_TRANSMISSION_MODE, 1, 0),
+	_DTV_CMD(DTV_INTERLEAVING, 1, 0),
+
+	_DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0),
+	_DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0),
+	_DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 1, 0),
+	_DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 1, 0),
+	_DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 1, 0),
+	_DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 1, 0),
+	_DTV_CMD(DTV_ISDBT_LAYERA_FEC, 1, 0),
+	_DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 1, 0),
+	_DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 1, 0),
+	_DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 1, 0),
+	_DTV_CMD(DTV_ISDBT_LAYERB_FEC, 1, 0),
+	_DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 1, 0),
+	_DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 1, 0),
+	_DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 1, 0),
+	_DTV_CMD(DTV_ISDBT_LAYERC_FEC, 1, 0),
+	_DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 1, 0),
+	_DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0),
+	_DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0),
+
+	_DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),
+	_DTV_CMD(DTV_DVBT2_PLP_ID, 1, 0),
+
+	/* Get */
+	_DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
+	_DTV_CMD(DTV_API_VERSION, 0, 0),
+	_DTV_CMD(DTV_CODE_RATE_HP, 0, 0),
+	_DTV_CMD(DTV_CODE_RATE_LP, 0, 0),
+	_DTV_CMD(DTV_GUARD_INTERVAL, 0, 0),
+	_DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0),
+	_DTV_CMD(DTV_HIERARCHY, 0, 0),
+	_DTV_CMD(DTV_INTERLEAVING, 0, 0),
+
+	_DTV_CMD(DTV_ENUM_DELSYS, 0, 0),
+
+	_DTV_CMD(DTV_ATSCMH_PARADE_ID, 1, 0),
+	_DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 1, 0),
+
+	_DTV_CMD(DTV_ATSCMH_FIC_VER, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_PARADE_ID, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_NOG, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_TNOG, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_SGN, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_PRC, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_A, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0),
+	_DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0),
+};
+
+static void dtv_property_dump(struct dtv_property *tvp)
+{
+	int i;
+
+	if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
+		printk(KERN_WARNING "%s: tvp.cmd = 0x%08x undefined\n",
+			__func__, tvp->cmd);
+		return;
+	}
+
+	dprintk("%s() tvp.cmd    = 0x%08x (%s)\n"
+		,__func__
+		,tvp->cmd
+		,dtv_cmds[ tvp->cmd ].name);
+
+	if(dtv_cmds[ tvp->cmd ].buffer) {
+
+		dprintk("%s() tvp.u.buffer.len = 0x%02x\n"
+			,__func__
+			,tvp->u.buffer.len);
+
+		for(i = 0; i < tvp->u.buffer.len; i++)
+			dprintk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
+				,__func__
+				,i
+				,tvp->u.buffer.data[i]);
+
+	} else
+		dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data);
+}
+
+/* Synchronise the legacy tuning parameters into the cache, so that demodulator
+ * drivers can use a single set_frontend tuning function, regardless of whether
+ * it's being used for the legacy or new API, reducing code and complexity.
+ */
+static int dtv_property_cache_sync(struct dvb_frontend *fe,
+				   struct dtv_frontend_properties *c,
+				   const struct dvb_frontend_parameters *p)
+{
+	c->frequency = p->frequency;
+	c->inversion = p->inversion;
+
+	switch (dvbv3_type(c->delivery_system)) {
+	case DVBV3_QPSK:
+		dprintk("%s() Preparing QPSK req\n", __func__);
+		c->symbol_rate = p->u.qpsk.symbol_rate;
+		c->fec_inner = p->u.qpsk.fec_inner;
+		break;
+	case DVBV3_QAM:
+		dprintk("%s() Preparing QAM req\n", __func__);
+		c->symbol_rate = p->u.qam.symbol_rate;
+		c->fec_inner = p->u.qam.fec_inner;
+		c->modulation = p->u.qam.modulation;
+		break;
+	case DVBV3_OFDM:
+		dprintk("%s() Preparing OFDM req\n", __func__);
+		switch (p->u.ofdm.bandwidth) {
+		case BANDWIDTH_10_MHZ:
+			c->bandwidth_hz = 10000000;
+			break;
+		case BANDWIDTH_8_MHZ:
+			c->bandwidth_hz = 8000000;
+			break;
+		case BANDWIDTH_7_MHZ:
+			c->bandwidth_hz = 7000000;
+			break;
+		case BANDWIDTH_6_MHZ:
+			c->bandwidth_hz = 6000000;
+			break;
+		case BANDWIDTH_5_MHZ:
+			c->bandwidth_hz = 5000000;
+			break;
+		case BANDWIDTH_1_712_MHZ:
+			c->bandwidth_hz = 1712000;
+			break;
+		case BANDWIDTH_AUTO:
+			c->bandwidth_hz = 0;
+		}
+
+		c->code_rate_HP = p->u.ofdm.code_rate_HP;
+		c->code_rate_LP = p->u.ofdm.code_rate_LP;
+		c->modulation = p->u.ofdm.constellation;
+		c->transmission_mode = p->u.ofdm.transmission_mode;
+		c->guard_interval = p->u.ofdm.guard_interval;
+		c->hierarchy = p->u.ofdm.hierarchy_information;
+		break;
+	case DVBV3_ATSC:
+		dprintk("%s() Preparing ATSC req\n", __func__);
+		c->modulation = p->u.vsb.modulation;
+		if (c->delivery_system == SYS_ATSCMH)
+			break;
+		if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
+			c->delivery_system = SYS_ATSC;
+		else
+			c->delivery_system = SYS_DVBC_ANNEX_B;
+		break;
+	case DVBV3_UNKNOWN:
+		printk(KERN_ERR
+		       "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
+		       __func__, c->delivery_system);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Ensure the cached values are set correctly in the frontend
+ * legacy tuning structures, for the advanced tuning API.
+ */
+static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
+					    struct dvb_frontend_parameters *p)
+{
+	const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+	p->frequency = c->frequency;
+	p->inversion = c->inversion;
+
+	switch (dvbv3_type(c->delivery_system)) {
+	case DVBV3_UNKNOWN:
+		printk(KERN_ERR
+		       "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
+		       __func__, c->delivery_system);
+		return -EINVAL;
+	case DVBV3_QPSK:
+		dprintk("%s() Preparing QPSK req\n", __func__);
+		p->u.qpsk.symbol_rate = c->symbol_rate;
+		p->u.qpsk.fec_inner = c->fec_inner;
+		break;
+	case DVBV3_QAM:
+		dprintk("%s() Preparing QAM req\n", __func__);
+		p->u.qam.symbol_rate = c->symbol_rate;
+		p->u.qam.fec_inner = c->fec_inner;
+		p->u.qam.modulation = c->modulation;
+		break;
+	case DVBV3_OFDM:
+		dprintk("%s() Preparing OFDM req\n", __func__);
+
+		switch (c->bandwidth_hz) {
+		case 10000000:
+			p->u.ofdm.bandwidth = BANDWIDTH_10_MHZ;
+			break;
+		case 8000000:
+			p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+			break;
+		case 7000000:
+			p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+			break;
+		case 6000000:
+			p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+			break;
+		case 5000000:
+			p->u.ofdm.bandwidth = BANDWIDTH_5_MHZ;
+			break;
+		case 1712000:
+			p->u.ofdm.bandwidth = BANDWIDTH_1_712_MHZ;
+			break;
+		case 0:
+		default:
+			p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
+		}
+		p->u.ofdm.code_rate_HP = c->code_rate_HP;
+		p->u.ofdm.code_rate_LP = c->code_rate_LP;
+		p->u.ofdm.constellation = c->modulation;
+		p->u.ofdm.transmission_mode = c->transmission_mode;
+		p->u.ofdm.guard_interval = c->guard_interval;
+		p->u.ofdm.hierarchy_information = c->hierarchy;
+		break;
+	case DVBV3_ATSC:
+		dprintk("%s() Preparing VSB req\n", __func__);
+		p->u.vsb.modulation = c->modulation;
+		break;
+	}
+	return 0;
+}
+
+/**
+ * dtv_get_frontend - calls a callback for retrieving DTV parameters
+ * @fe:		struct dvb_frontend pointer
+ * @c:		struct dtv_frontend_properties pointer (DVBv5 cache)
+ * @p_out	struct dvb_frontend_parameters pointer (DVBv3 FE struct)
+ *
+ * This routine calls either the DVBv3 or DVBv5 get_frontend call.
+ * If c is not null, it will update the DVBv5 cache struct pointed by it.
+ * If p_out is not null, it will update the DVBv3 params pointed by it.
+ */
+static int dtv_get_frontend(struct dvb_frontend *fe,
+			    struct dvb_frontend_parameters *p_out)
+{
+	int r;
+
+	if (fe->ops.get_frontend) {
+		r = fe->ops.get_frontend(fe);
+		if (unlikely(r < 0))
+			return r;
+		if (p_out)
+			dtv_property_legacy_params_sync(fe, p_out);
+		return 0;
+	}
+
+	/* As everything is in cache, get_frontend fops are always supported */
+	return 0;
+}
+
+static int dvb_frontend_ioctl_legacy(struct file *file,
+			unsigned int cmd, void *parg);
+static int dvb_frontend_ioctl_properties(struct file *file,
+			unsigned int cmd, void *parg);
+
+static int dtv_property_process_get(struct dvb_frontend *fe,
+				    const struct dtv_frontend_properties *c,
+				    struct dtv_property *tvp,
+				    struct file *file)
+{
+	int r, ncaps;
+
+	switch(tvp->cmd) {
+	case DTV_ENUM_DELSYS:
+		ncaps = 0;
+		while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+			tvp->u.buffer.data[ncaps] = fe->ops.delsys[ncaps];
+			ncaps++;
+		}
+		tvp->u.buffer.len = ncaps;
+		break;
+	case DTV_FREQUENCY:
+		tvp->u.data = c->frequency;
+		break;
+	case DTV_MODULATION:
+		tvp->u.data = c->modulation;
+		break;
+	case DTV_BANDWIDTH_HZ:
+		tvp->u.data = c->bandwidth_hz;
+		break;
+	case DTV_INVERSION:
+		tvp->u.data = c->inversion;
+		break;
+	case DTV_SYMBOL_RATE:
+		tvp->u.data = c->symbol_rate;
+		break;
+	case DTV_INNER_FEC:
+		tvp->u.data = c->fec_inner;
+		break;
+	case DTV_PILOT:
+		tvp->u.data = c->pilot;
+		break;
+	case DTV_ROLLOFF:
+		tvp->u.data = c->rolloff;
+		break;
+	case DTV_DELIVERY_SYSTEM:
+		tvp->u.data = c->delivery_system;
+		break;
+	case DTV_VOLTAGE:
+		tvp->u.data = c->voltage;
+		break;
+	case DTV_TONE:
+		tvp->u.data = c->sectone;
+		break;
+	case DTV_API_VERSION:
+		tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
+		break;
+	case DTV_CODE_RATE_HP:
+		tvp->u.data = c->code_rate_HP;
+		break;
+	case DTV_CODE_RATE_LP:
+		tvp->u.data = c->code_rate_LP;
+		break;
+	case DTV_GUARD_INTERVAL:
+		tvp->u.data = c->guard_interval;
+		break;
+	case DTV_TRANSMISSION_MODE:
+		tvp->u.data = c->transmission_mode;
+		break;
+	case DTV_HIERARCHY:
+		tvp->u.data = c->hierarchy;
+		break;
+	case DTV_INTERLEAVING:
+		tvp->u.data = c->interleaving;
+		break;
+
+	/* ISDB-T Support here */
+	case DTV_ISDBT_PARTIAL_RECEPTION:
+		tvp->u.data = c->isdbt_partial_reception;
+		break;
+	case DTV_ISDBT_SOUND_BROADCASTING:
+		tvp->u.data = c->isdbt_sb_mode;
+		break;
+	case DTV_ISDBT_SB_SUBCHANNEL_ID:
+		tvp->u.data = c->isdbt_sb_subchannel;
+		break;
+	case DTV_ISDBT_SB_SEGMENT_IDX:
+		tvp->u.data = c->isdbt_sb_segment_idx;
+		break;
+	case DTV_ISDBT_SB_SEGMENT_COUNT:
+		tvp->u.data = c->isdbt_sb_segment_count;
+		break;
+	case DTV_ISDBT_LAYER_ENABLED:
+		tvp->u.data = c->isdbt_layer_enabled;
+		break;
+	case DTV_ISDBT_LAYERA_FEC:
+		tvp->u.data = c->layer[0].fec;
+		break;
+	case DTV_ISDBT_LAYERA_MODULATION:
+		tvp->u.data = c->layer[0].modulation;
+		break;
+	case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
+		tvp->u.data = c->layer[0].segment_count;
+		break;
+	case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
+		tvp->u.data = c->layer[0].interleaving;
+		break;
+	case DTV_ISDBT_LAYERB_FEC:
+		tvp->u.data = c->layer[1].fec;
+		break;
+	case DTV_ISDBT_LAYERB_MODULATION:
+		tvp->u.data = c->layer[1].modulation;
+		break;
+	case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
+		tvp->u.data = c->layer[1].segment_count;
+		break;
+	case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
+		tvp->u.data = c->layer[1].interleaving;
+		break;
+	case DTV_ISDBT_LAYERC_FEC:
+		tvp->u.data = c->layer[2].fec;
+		break;
+	case DTV_ISDBT_LAYERC_MODULATION:
+		tvp->u.data = c->layer[2].modulation;
+		break;
+	case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
+		tvp->u.data = c->layer[2].segment_count;
+		break;
+	case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
+		tvp->u.data = c->layer[2].interleaving;
+		break;
+	case DTV_ISDBS_TS_ID:
+		tvp->u.data = c->isdbs_ts_id;
+		break;
+	case DTV_DVBT2_PLP_ID:
+		tvp->u.data = c->dvbt2_plp_id;
+		break;
+
+	/* ATSC-MH */
+	case DTV_ATSCMH_FIC_VER:
+		tvp->u.data = fe->dtv_property_cache.atscmh_fic_ver;
+		break;
+	case DTV_ATSCMH_PARADE_ID:
+		tvp->u.data = fe->dtv_property_cache.atscmh_parade_id;
+		break;
+	case DTV_ATSCMH_NOG:
+		tvp->u.data = fe->dtv_property_cache.atscmh_nog;
+		break;
+	case DTV_ATSCMH_TNOG:
+		tvp->u.data = fe->dtv_property_cache.atscmh_tnog;
+		break;
+	case DTV_ATSCMH_SGN:
+		tvp->u.data = fe->dtv_property_cache.atscmh_sgn;
+		break;
+	case DTV_ATSCMH_PRC:
+		tvp->u.data = fe->dtv_property_cache.atscmh_prc;
+		break;
+	case DTV_ATSCMH_RS_FRAME_MODE:
+		tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_mode;
+		break;
+	case DTV_ATSCMH_RS_FRAME_ENSEMBLE:
+		tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_ensemble;
+		break;
+	case DTV_ATSCMH_RS_CODE_MODE_PRI:
+		tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_pri;
+		break;
+	case DTV_ATSCMH_RS_CODE_MODE_SEC:
+		tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_sec;
+		break;
+	case DTV_ATSCMH_SCCC_BLOCK_MODE:
+		tvp->u.data = fe->dtv_property_cache.atscmh_sccc_block_mode;
+		break;
+	case DTV_ATSCMH_SCCC_CODE_MODE_A:
+		tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_a;
+		break;
+	case DTV_ATSCMH_SCCC_CODE_MODE_B:
+		tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_b;
+		break;
+	case DTV_ATSCMH_SCCC_CODE_MODE_C:
+		tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_c;
+		break;
+	case DTV_ATSCMH_SCCC_CODE_MODE_D:
+		tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_d;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Allow the frontend to override outgoing properties */
+	if (fe->ops.get_property) {
+		r = fe->ops.get_property(fe, tvp);
+		if (r < 0)
+			return r;
+	}
+
+	dtv_property_dump(tvp);
+
+	return 0;
+}
+
+static int dtv_set_frontend(struct dvb_frontend *fe);
+
+static bool is_dvbv3_delsys(u32 delsys)
+{
+	bool status;
+
+	status = (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) ||
+		 (delsys == SYS_DVBS) || (delsys == SYS_ATSC);
+
+	return status;
+}
+
+static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system)
+{
+	int ncaps, i;
+	u32 delsys = SYS_UNDEFINED;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	enum dvbv3_emulation_type type;
+
+	/*
+	 * It was reported that some old DVBv5 applications were
+	 * filling delivery_system with SYS_UNDEFINED. If this happens,
+	 * assume that the application wants to use the first supported
+	 * delivery system.
+	 */
+	if (c->delivery_system == SYS_UNDEFINED)
+	        c->delivery_system = fe->ops.delsys[0];
+
+	if (desired_system == SYS_UNDEFINED) {
+		/*
+		 * A DVBv3 call doesn't know what's the desired system.
+		 * Also, DVBv3 applications don't know that ops.info->type
+		 * could be changed, and they simply dies when it doesn't
+		 * match.
+		 * So, don't change the current delivery system, as it
+		 * may be trying to do the wrong thing, like setting an
+		 * ISDB-T frontend as DVB-T. Instead, find the closest
+		 * DVBv3 system that matches the delivery system.
+		 */
+		if (is_dvbv3_delsys(c->delivery_system)) {
+			dprintk("%s() Using delivery system to %d\n",
+				__func__, c->delivery_system);
+			return 0;
+		}
+		type = dvbv3_type(c->delivery_system);
+		switch (type) {
+		case DVBV3_QPSK:
+			desired_system = SYS_DVBS;
+			break;
+		case DVBV3_QAM:
+			desired_system = SYS_DVBC_ANNEX_A;
+			break;
+		case DVBV3_ATSC:
+			desired_system = SYS_ATSC;
+			break;
+		case DVBV3_OFDM:
+			desired_system = SYS_DVBT;
+			break;
+		default:
+			dprintk("%s(): This frontend doesn't support DVBv3 calls\n",
+				__func__);
+			return -EINVAL;
+		}
+		/*
+		 * Get a delivery system that is compatible with DVBv3
+		 * NOTE: in order for this to work with softwares like Kaffeine that
+		 *	uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to
+		 *	DVB-S, drivers that support both should put the SYS_DVBS entry
+		 *	before the SYS_DVBS2, otherwise it won't switch back to DVB-S.
+		 *	The real fix is that userspace applications should not use DVBv3
+		 *	and not trust on calling FE_SET_FRONTEND to switch the delivery
+		 *	system.
+		 */
+		ncaps = 0;
+		while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+			if (fe->ops.delsys[ncaps] == desired_system) {
+				delsys = desired_system;
+				break;
+			}
+			ncaps++;
+		}
+		if (delsys == SYS_UNDEFINED) {
+			dprintk("%s() Couldn't find a delivery system that matches %d\n",
+				__func__, desired_system);
+		}
+	} else {
+		/*
+		 * This is a DVBv5 call. So, it likely knows the supported
+		 * delivery systems.
+		 */
+
+		/* Check if the desired delivery system is supported */
+		ncaps = 0;
+		while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+			if (fe->ops.delsys[ncaps] == desired_system) {
+				c->delivery_system = desired_system;
+				dprintk("%s() Changing delivery system to %d\n",
+					__func__, desired_system);
+				return 0;
+			}
+			ncaps++;
+		}
+		type = dvbv3_type(desired_system);
+
+		/*
+		 * The delivery system is not supported. See if it can be
+		 * emulated.
+		 * The emulation only works if the desired system is one of the
+		 * DVBv3 delivery systems
+		 */
+		if (!is_dvbv3_delsys(desired_system)) {
+			dprintk("%s() can't use a DVBv3 FE_SET_FRONTEND call on this frontend\n",
+				__func__);
+			return -EINVAL;
+		}
+
+		/*
+		 * Get the last non-DVBv3 delivery system that has the same type
+		 * of the desired system
+		 */
+		ncaps = 0;
+		while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+			if ((dvbv3_type(fe->ops.delsys[ncaps]) == type) &&
+			    !is_dvbv3_delsys(fe->ops.delsys[ncaps]))
+				delsys = fe->ops.delsys[ncaps];
+			ncaps++;
+		}
+		/* There's nothing compatible with the desired delivery system */
+		if (delsys == SYS_UNDEFINED) {
+			dprintk("%s() Incompatible DVBv3 FE_SET_FRONTEND call for this frontend\n",
+				__func__);
+			return -EINVAL;
+		}
+	}
+
+	c->delivery_system = delsys;
+
+	/*
+	 * The DVBv3 or DVBv5 call is requesting a different system. So,
+	 * emulation is needed.
+	 *
+	 * Emulate newer delivery systems like ISDBT, DVBT and DTMB
+	 * for older DVBv5 applications. The emulation will try to use
+	 * the auto mode for most things, and will assume that the desired
+	 * delivery system is the last one at the ops.delsys[] array
+	 */
+	dprintk("%s() Using delivery system %d emulated as if it were a %d\n",
+		__func__, delsys, desired_system);
+
+	/*
+	 * For now, handles ISDB-T calls. More code may be needed here for the
+	 * other emulated stuff
+	 */
+	if (type == DVBV3_OFDM) {
+		if (c->delivery_system == SYS_ISDBT) {
+			dprintk("%s() Using defaults for SYS_ISDBT\n",
+				__func__);
+			if (!c->bandwidth_hz)
+				c->bandwidth_hz = 6000000;
+
+			c->isdbt_partial_reception = 0;
+			c->isdbt_sb_mode = 0;
+			c->isdbt_sb_subchannel = 0;
+			c->isdbt_sb_segment_idx = 0;
+			c->isdbt_sb_segment_count = 0;
+			c->isdbt_layer_enabled = 0;
+			for (i = 0; i < 3; i++) {
+				c->layer[i].fec = FEC_AUTO;
+				c->layer[i].modulation = QAM_AUTO;
+				c->layer[i].interleaving = 0;
+				c->layer[i].segment_count = 0;
+			}
+		}
+	}
+	dprintk("change delivery system on cache to %d\n", c->delivery_system);
+
+	return 0;
+}
+
+static int dtv_property_process_set(struct dvb_frontend *fe,
+				    struct dtv_property *tvp,
+				    struct file *file)
+{
+	int r = 0;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+	/* Allow the frontend to validate incoming properties */
+	if (fe->ops.set_property) {
+		r = fe->ops.set_property(fe, tvp);
+		if (r < 0)
+			return r;
+	}
+
+	switch(tvp->cmd) {
+	case DTV_CLEAR:
+		/*
+		 * Reset a cache of data specific to the frontend here. This does
+		 * not effect hardware.
+		 */
+		dvb_frontend_clear_cache(fe);
+		break;
+	case DTV_TUNE:
+		/* interpret the cache of data, build either a traditional frontend
+		 * tunerequest so we can pass validation in the FE_SET_FRONTEND
+		 * ioctl.
+		 */
+		c->state = tvp->cmd;
+		dprintk("%s() Finalised property cache\n", __func__);
+
+		r = dtv_set_frontend(fe);
+		break;
+	case DTV_FREQUENCY:
+		c->frequency = tvp->u.data;
+		break;
+	case DTV_MODULATION:
+		c->modulation = tvp->u.data;
+		break;
+	case DTV_BANDWIDTH_HZ:
+		c->bandwidth_hz = tvp->u.data;
+		break;
+	case DTV_INVERSION:
+		c->inversion = tvp->u.data;
+		break;
+	case DTV_SYMBOL_RATE:
+		c->symbol_rate = tvp->u.data;
+		break;
+	case DTV_INNER_FEC:
+		c->fec_inner = tvp->u.data;
+		break;
+	case DTV_PILOT:
+		c->pilot = tvp->u.data;
+		break;
+	case DTV_ROLLOFF:
+		c->rolloff = tvp->u.data;
+		break;
+	case DTV_DELIVERY_SYSTEM:
+		r = set_delivery_system(fe, tvp->u.data);
+		break;
+	case DTV_VOLTAGE:
+		c->voltage = tvp->u.data;
+		r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE,
+			(void *)c->voltage);
+		break;
+	case DTV_TONE:
+		c->sectone = tvp->u.data;
+		r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE,
+			(void *)c->sectone);
+		break;
+	case DTV_CODE_RATE_HP:
+		c->code_rate_HP = tvp->u.data;
+		break;
+	case DTV_CODE_RATE_LP:
+		c->code_rate_LP = tvp->u.data;
+		break;
+	case DTV_GUARD_INTERVAL:
+		c->guard_interval = tvp->u.data;
+		break;
+	case DTV_TRANSMISSION_MODE:
+		c->transmission_mode = tvp->u.data;
+		break;
+	case DTV_HIERARCHY:
+		c->hierarchy = tvp->u.data;
+		break;
+	case DTV_INTERLEAVING:
+		c->interleaving = tvp->u.data;
+		break;
+
+	/* ISDB-T Support here */
+	case DTV_ISDBT_PARTIAL_RECEPTION:
+		c->isdbt_partial_reception = tvp->u.data;
+		break;
+	case DTV_ISDBT_SOUND_BROADCASTING:
+		c->isdbt_sb_mode = tvp->u.data;
+		break;
+	case DTV_ISDBT_SB_SUBCHANNEL_ID:
+		c->isdbt_sb_subchannel = tvp->u.data;
+		break;
+	case DTV_ISDBT_SB_SEGMENT_IDX:
+		c->isdbt_sb_segment_idx = tvp->u.data;
+		break;
+	case DTV_ISDBT_SB_SEGMENT_COUNT:
+		c->isdbt_sb_segment_count = tvp->u.data;
+		break;
+	case DTV_ISDBT_LAYER_ENABLED:
+		c->isdbt_layer_enabled = tvp->u.data;
+		break;
+	case DTV_ISDBT_LAYERA_FEC:
+		c->layer[0].fec = tvp->u.data;
+		break;
+	case DTV_ISDBT_LAYERA_MODULATION:
+		c->layer[0].modulation = tvp->u.data;
+		break;
+	case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
+		c->layer[0].segment_count = tvp->u.data;
+		break;
+	case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
+		c->layer[0].interleaving = tvp->u.data;
+		break;
+	case DTV_ISDBT_LAYERB_FEC:
+		c->layer[1].fec = tvp->u.data;
+		break;
+	case DTV_ISDBT_LAYERB_MODULATION:
+		c->layer[1].modulation = tvp->u.data;
+		break;
+	case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
+		c->layer[1].segment_count = tvp->u.data;
+		break;
+	case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
+		c->layer[1].interleaving = tvp->u.data;
+		break;
+	case DTV_ISDBT_LAYERC_FEC:
+		c->layer[2].fec = tvp->u.data;
+		break;
+	case DTV_ISDBT_LAYERC_MODULATION:
+		c->layer[2].modulation = tvp->u.data;
+		break;
+	case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
+		c->layer[2].segment_count = tvp->u.data;
+		break;
+	case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
+		c->layer[2].interleaving = tvp->u.data;
+		break;
+	case DTV_ISDBS_TS_ID:
+		c->isdbs_ts_id = tvp->u.data;
+		break;
+	case DTV_DVBT2_PLP_ID:
+		c->dvbt2_plp_id = tvp->u.data;
+		break;
+
+	/* ATSC-MH */
+	case DTV_ATSCMH_PARADE_ID:
+		fe->dtv_property_cache.atscmh_parade_id = tvp->u.data;
+		break;
+	case DTV_ATSCMH_RS_FRAME_ENSEMBLE:
+		fe->dtv_property_cache.atscmh_rs_frame_ensemble = tvp->u.data;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return r;
+}
+
+static int dvb_frontend_ioctl(struct file *file,
+			unsigned int cmd, void *parg)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_frontend *fe = dvbdev->priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	int err = -EOPNOTSUPP;
+
+	dprintk("%s (%d)\n", __func__, _IOC_NR(cmd));
+
+	if (fepriv->exit != DVB_FE_NO_EXIT)
+		return -ENODEV;
+
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
+	    (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT ||
+	     cmd == FE_DISEQC_RECV_SLAVE_REPLY))
+		return -EPERM;
+
+	if (down_interruptible (&fepriv->sem))
+		return -ERESTARTSYS;
+
+	if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
+		err = dvb_frontend_ioctl_properties(file, cmd, parg);
+	else {
+		c->state = DTV_UNDEFINED;
+		err = dvb_frontend_ioctl_legacy(file, cmd, parg);
+	}
+
+	up(&fepriv->sem);
+	return err;
+}
+
+static int dvb_frontend_ioctl_properties(struct file *file,
+			unsigned int cmd, void *parg)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_frontend *fe = dvbdev->priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int err = 0;
+
+	struct dtv_properties *tvps = NULL;
+	struct dtv_property *tvp = NULL;
+	int i;
+
+	dprintk("%s\n", __func__);
+
+	if(cmd == FE_SET_PROPERTY) {
+		tvps = (struct dtv_properties __user *)parg;
+
+		dprintk("%s() properties.num = %d\n", __func__, tvps->num);
+		dprintk("%s() properties.props = %p\n", __func__, tvps->props);
+
+		/* Put an arbitrary limit on the number of messages that can
+		 * be sent at once */
+		if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
+			return -EINVAL;
+
+		tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
+		if (!tvp) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+			err = -EFAULT;
+			goto out;
+		}
+
+		for (i = 0; i < tvps->num; i++) {
+			err = dtv_property_process_set(fe, tvp + i, file);
+			if (err < 0)
+				goto out;
+			(tvp + i)->result = err;
+		}
+
+		if (c->state == DTV_TUNE)
+			dprintk("%s() Property cache is full, tuning\n", __func__);
+
+	} else
+	if(cmd == FE_GET_PROPERTY) {
+		tvps = (struct dtv_properties __user *)parg;
+
+		dprintk("%s() properties.num = %d\n", __func__, tvps->num);
+		dprintk("%s() properties.props = %p\n", __func__, tvps->props);
+
+		/* Put an arbitrary limit on the number of messages that can
+		 * be sent at once */
+		if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
+			return -EINVAL;
+
+		tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
+		if (!tvp) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+			err = -EFAULT;
+			goto out;
+		}
+
+		/*
+		 * Fills the cache out struct with the cache contents, plus
+		 * the data retrieved from get_frontend, if the frontend
+		 * is not idle. Otherwise, returns the cached content
+		 */
+		if (fepriv->state != FESTATE_IDLE) {
+			err = dtv_get_frontend(fe, NULL);
+			if (err < 0)
+				goto out;
+		}
+		for (i = 0; i < tvps->num; i++) {
+			err = dtv_property_process_get(fe, c, tvp + i, file);
+			if (err < 0)
+				goto out;
+			(tvp + i)->result = err;
+		}
+
+		if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
+			err = -EFAULT;
+			goto out;
+		}
+
+	} else
+		err = -EOPNOTSUPP;
+
+out:
+	kfree(tvp);
+	return err;
+}
+
+static int dtv_set_frontend(struct dvb_frontend *fe)
+{
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct dvb_frontend_tune_settings fetunesettings;
+	u32 rolloff = 0;
+
+	if (dvb_frontend_check_parameters(fe) < 0)
+		return -EINVAL;
+
+	/*
+	 * Initialize output parameters to match the values given by
+	 * the user. FE_SET_FRONTEND triggers an initial frontend event
+	 * with status = 0, which copies output parameters to userspace.
+	 */
+	dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
+
+	/*
+	 * Be sure that the bandwidth will be filled for all
+	 * non-satellite systems, as tuners need to know what
+	 * low pass/Nyquist half filter should be applied, in
+	 * order to avoid inter-channel noise.
+	 *
+	 * ISDB-T and DVB-T/T2 already sets bandwidth.
+	 * ATSC and DVB-C don't set, so, the core should fill it.
+	 *
+	 * On DVB-C Annex A and C, the bandwidth is a function of
+	 * the roll-off and symbol rate. Annex B defines different
+	 * roll-off factors depending on the modulation. Fortunately,
+	 * Annex B is only used with 6MHz, so there's no need to
+	 * calculate it.
+	 *
+	 * While not officially supported, a side effect of handling it at
+	 * the cache level is that a program could retrieve the bandwidth
+	 * via DTV_BANDWIDTH_HZ, which may be useful for test programs.
+	 */
+	switch (c->delivery_system) {
+	case SYS_ATSC:
+	case SYS_DVBC_ANNEX_B:
+		c->bandwidth_hz = 6000000;
+		break;
+	case SYS_DVBC_ANNEX_A:
+		rolloff = 115;
+		break;
+	case SYS_DVBC_ANNEX_C:
+		rolloff = 113;
+		break;
+	default:
+		break;
+	}
+	if (rolloff)
+		c->bandwidth_hz = (c->symbol_rate * rolloff) / 100;
+
+	/* force auto frequency inversion if requested */
+	if (dvb_force_auto_inversion)
+		c->inversion = INVERSION_AUTO;
+
+	/*
+	 * without hierarchical coding code_rate_LP is irrelevant,
+	 * so we tolerate the otherwise invalid FEC_NONE setting
+	 */
+	if (c->hierarchy == HIERARCHY_NONE && c->code_rate_LP == FEC_NONE)
+		c->code_rate_LP = FEC_AUTO;
+
+	/* get frontend-specific tuning settings */
+	memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
+	if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
+		fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
+		fepriv->max_drift = fetunesettings.max_drift;
+		fepriv->step_size = fetunesettings.step_size;
+	} else {
+		/* default values */
+		switch (c->delivery_system) {
+		case SYS_DVBS:
+		case SYS_DVBS2:
+		case SYS_ISDBS:
+		case SYS_TURBO:
+		case SYS_DVBC_ANNEX_A:
+		case SYS_DVBC_ANNEX_C:
+			fepriv->min_delay = HZ / 20;
+			fepriv->step_size = c->symbol_rate / 16000;
+			fepriv->max_drift = c->symbol_rate / 2000;
+			break;
+		case SYS_DVBT:
+		case SYS_DVBT2:
+		case SYS_ISDBT:
+		case SYS_DTMB:
+			fepriv->min_delay = HZ / 20;
+			fepriv->step_size = fe->ops.info.frequency_stepsize * 2;
+			fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+			break;
+		default:
+			/*
+			 * FIXME: This sounds wrong! if freqency_stepsize is
+			 * defined by the frontend, why not use it???
+			 */
+			fepriv->min_delay = HZ / 20;
+			fepriv->step_size = 0; /* no zigzag */
+			fepriv->max_drift = 0;
+			break;
+		}
+	}
+	if (dvb_override_tune_delay > 0)
+		fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000;
+
+	fepriv->state = FESTATE_RETUNE;
+
+	/* Request the search algorithm to search */
+	fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+
+	dvb_frontend_clear_events(fe);
+	dvb_frontend_add_event(fe, 0);
+	dvb_frontend_wakeup(fe);
+	fepriv->status = 0;
+
+	return 0;
+}
+
+
+static int dvb_frontend_ioctl_legacy(struct file *file,
+			unsigned int cmd, void *parg)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_frontend *fe = dvbdev->priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int err = -EOPNOTSUPP;
+
+	switch (cmd) {
+	case FE_GET_INFO: {
+		struct dvb_frontend_info* info = parg;
+
+		memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
+		dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max);
+
+		/*
+		 * Associate the 4 delivery systems supported by DVBv3
+		 * API with their DVBv5 counterpart. For the other standards,
+		 * use the closest type, assuming that it would hopefully
+		 * work with a DVBv3 application.
+		 * It should be noticed that, on multi-frontend devices with
+		 * different types (terrestrial and cable, for example),
+		 * a pure DVBv3 application won't be able to use all delivery
+		 * systems. Yet, changing the DVBv5 cache to the other delivery
+		 * system should be enough for making it work.
+		 */
+		switch (dvbv3_type(c->delivery_system)) {
+		case DVBV3_QPSK:
+			info->type = FE_QPSK;
+			break;
+		case DVBV3_ATSC:
+			info->type = FE_ATSC;
+			break;
+		case DVBV3_QAM:
+			info->type = FE_QAM;
+			break;
+		case DVBV3_OFDM:
+			info->type = FE_OFDM;
+			break;
+		default:
+			printk(KERN_ERR
+			       "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
+			       __func__, c->delivery_system);
+			fe->ops.info.type = FE_OFDM;
+		}
+		dprintk("current delivery system on cache: %d, V3 type: %d\n",
+			c->delivery_system, fe->ops.info.type);
+
+		/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
+		 * do it, it is done for it. */
+		info->caps |= FE_CAN_INVERSION_AUTO;
+		err = 0;
+		break;
+	}
+
+	case FE_READ_STATUS: {
+		fe_status_t* status = parg;
+
+		/* if retune was requested but hasn't occurred yet, prevent
+		 * that user get signal state from previous tuning */
+		if (fepriv->state == FESTATE_RETUNE ||
+		    fepriv->state == FESTATE_ERROR) {
+			err=0;
+			*status = 0;
+			break;
+		}
+
+		if (fe->ops.read_status)
+			err = fe->ops.read_status(fe, status);
+		break;
+	}
+	case FE_READ_BER:
+		if (fe->ops.read_ber)
+			err = fe->ops.read_ber(fe, (__u32*) parg);
+		break;
+
+	case FE_READ_SIGNAL_STRENGTH:
+		if (fe->ops.read_signal_strength)
+			err = fe->ops.read_signal_strength(fe, (__u16*) parg);
+		break;
+
+	case FE_READ_SNR:
+		if (fe->ops.read_snr)
+			err = fe->ops.read_snr(fe, (__u16*) parg);
+		break;
+
+	case FE_READ_UNCORRECTED_BLOCKS:
+		if (fe->ops.read_ucblocks)
+			err = fe->ops.read_ucblocks(fe, (__u32*) parg);
+		break;
+
+
+	case FE_DISEQC_RESET_OVERLOAD:
+		if (fe->ops.diseqc_reset_overload) {
+			err = fe->ops.diseqc_reset_overload(fe);
+			fepriv->state = FESTATE_DISEQC;
+			fepriv->status = 0;
+		}
+		break;
+
+	case FE_DISEQC_SEND_MASTER_CMD:
+		if (fe->ops.diseqc_send_master_cmd) {
+			err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
+			fepriv->state = FESTATE_DISEQC;
+			fepriv->status = 0;
+		}
+		break;
+
+	case FE_DISEQC_SEND_BURST:
+		if (fe->ops.diseqc_send_burst) {
+			err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
+			fepriv->state = FESTATE_DISEQC;
+			fepriv->status = 0;
+		}
+		break;
+
+	case FE_SET_TONE:
+		if (fe->ops.set_tone) {
+			err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
+			fepriv->tone = (fe_sec_tone_mode_t) parg;
+			fepriv->state = FESTATE_DISEQC;
+			fepriv->status = 0;
+		}
+		break;
+
+	case FE_SET_VOLTAGE:
+		if (fe->ops.set_voltage) {
+			err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
+			fepriv->voltage = (fe_sec_voltage_t) parg;
+			fepriv->state = FESTATE_DISEQC;
+			fepriv->status = 0;
+		}
+		break;
+
+	case FE_DISHNETWORK_SEND_LEGACY_CMD:
+		if (fe->ops.dishnetwork_send_legacy_command) {
+			err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);
+			fepriv->state = FESTATE_DISEQC;
+			fepriv->status = 0;
+		} else if (fe->ops.set_voltage) {
+			/*
+			 * NOTE: This is a fallback condition.  Some frontends
+			 * (stv0299 for instance) take longer than 8msec to
+			 * respond to a set_voltage command.  Those switches
+			 * need custom routines to switch properly.  For all
+			 * other frontends, the following should work ok.
+			 * Dish network legacy switches (as used by Dish500)
+			 * are controlled by sending 9-bit command words
+			 * spaced 8msec apart.
+			 * the actual command word is switch/port dependent
+			 * so it is up to the userspace application to send
+			 * the right command.
+			 * The command must always start with a '0' after
+			 * initialization, so parg is 8 bits and does not
+			 * include the initialization or start bit
+			 */
+			unsigned long swcmd = ((unsigned long) parg) << 1;
+			struct timeval nexttime;
+			struct timeval tv[10];
+			int i;
+			u8 last = 1;
+			if (dvb_frontend_debug)
+				printk("%s switch command: 0x%04lx\n", __func__, swcmd);
+			do_gettimeofday(&nexttime);
+			if (dvb_frontend_debug)
+				memcpy(&tv[0], &nexttime, sizeof(struct timeval));
+			/* before sending a command, initialize by sending
+			 * a 32ms 18V to the switch
+			 */
+			fe->ops.set_voltage(fe, SEC_VOLTAGE_18);
+			dvb_frontend_sleep_until(&nexttime, 32000);
+
+			for (i = 0; i < 9; i++) {
+				if (dvb_frontend_debug)
+					do_gettimeofday(&tv[i + 1]);
+				if ((swcmd & 0x01) != last) {
+					/* set voltage to (last ? 13V : 18V) */
+					fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
+					last = (last) ? 0 : 1;
+				}
+				swcmd = swcmd >> 1;
+				if (i != 8)
+					dvb_frontend_sleep_until(&nexttime, 8000);
+			}
+			if (dvb_frontend_debug) {
+				printk("%s(%d): switch delay (should be 32k followed by all 8k\n",
+					__func__, fe->dvb->num);
+				for (i = 1; i < 10; i++)
+					printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
+			}
+			err = 0;
+			fepriv->state = FESTATE_DISEQC;
+			fepriv->status = 0;
+		}
+		break;
+
+	case FE_DISEQC_RECV_SLAVE_REPLY:
+		if (fe->ops.diseqc_recv_slave_reply)
+			err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
+		break;
+
+	case FE_ENABLE_HIGH_LNB_VOLTAGE:
+		if (fe->ops.enable_high_lnb_voltage)
+			err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
+		break;
+
+	case FE_SET_FRONTEND:
+		err = set_delivery_system(fe, SYS_UNDEFINED);
+		if (err)
+			break;
+
+		err = dtv_property_cache_sync(fe, c, parg);
+		if (err)
+			break;
+		err = dtv_set_frontend(fe);
+		break;
+	case FE_GET_EVENT:
+		err = dvb_frontend_get_event (fe, parg, file->f_flags);
+		break;
+
+	case FE_GET_FRONTEND:
+		err = dtv_get_frontend(fe, parg);
+		break;
+
+	case FE_SET_FRONTEND_TUNE_MODE:
+		fepriv->tune_mode_flags = (unsigned long) parg;
+		err = 0;
+		break;
+	};
+
+	return err;
+}
+
+
+static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_frontend *fe = dvbdev->priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+	dprintk ("%s\n", __func__);
+
+	poll_wait (file, &fepriv->events.wait_queue, wait);
+
+	if (fepriv->events.eventw != fepriv->events.eventr)
+		return (POLLIN | POLLRDNORM | POLLPRI);
+
+	return 0;
+}
+
+static int dvb_frontend_open(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_frontend *fe = dvbdev->priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	struct dvb_adapter *adapter = fe->dvb;
+	int ret;
+
+	dprintk ("%s\n", __func__);
+	if (fepriv->exit == DVB_FE_DEVICE_REMOVED)
+		return -ENODEV;
+
+	if (adapter->mfe_shared) {
+		mutex_lock (&adapter->mfe_lock);
+
+		if (adapter->mfe_dvbdev == NULL)
+			adapter->mfe_dvbdev = dvbdev;
+
+		else if (adapter->mfe_dvbdev != dvbdev) {
+			struct dvb_device
+				*mfedev = adapter->mfe_dvbdev;
+			struct dvb_frontend
+				*mfe = mfedev->priv;
+			struct dvb_frontend_private
+				*mfepriv = mfe->frontend_priv;
+			int mferetry = (dvb_mfe_wait_time << 1);
+
+			mutex_unlock (&adapter->mfe_lock);
+			while (mferetry-- && (mfedev->users != -1 ||
+					mfepriv->thread != NULL)) {
+				if(msleep_interruptible(500)) {
+					if(signal_pending(current))
+						return -EINTR;
+				}
+			}
+
+			mutex_lock (&adapter->mfe_lock);
+			if(adapter->mfe_dvbdev != dvbdev) {
+				mfedev = adapter->mfe_dvbdev;
+				mfe = mfedev->priv;
+				mfepriv = mfe->frontend_priv;
+				if (mfedev->users != -1 ||
+						mfepriv->thread != NULL) {
+					mutex_unlock (&adapter->mfe_lock);
+					return -EBUSY;
+				}
+				adapter->mfe_dvbdev = dvbdev;
+			}
+		}
+	}
+
+	if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
+		if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
+			goto err0;
+
+		/* If we took control of the bus, we need to force
+		   reinitialization.  This is because many ts_bus_ctrl()
+		   functions strobe the RESET pin on the demod, and if the
+		   frontend thread already exists then the dvb_init() routine
+		   won't get called (which is what usually does initial
+		   register configuration). */
+		fepriv->reinitialise = 1;
+	}
+
+	if ((ret = dvb_generic_open (inode, file)) < 0)
+		goto err1;
+
+	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+		/* normal tune mode when opened R/W */
+		fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
+		fepriv->tone = -1;
+		fepriv->voltage = -1;
+
+		ret = dvb_frontend_start (fe);
+		if (ret)
+			goto err2;
+
+		/*  empty event queue */
+		fepriv->events.eventr = fepriv->events.eventw = 0;
+	}
+
+	if (adapter->mfe_shared)
+		mutex_unlock (&adapter->mfe_lock);
+	return ret;
+
+err2:
+	dvb_generic_release(inode, file);
+err1:
+	if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
+		fe->ops.ts_bus_ctrl(fe, 0);
+err0:
+	if (adapter->mfe_shared)
+		mutex_unlock (&adapter->mfe_lock);
+	return ret;
+}
+
+static int dvb_frontend_release(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_frontend *fe = dvbdev->priv;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	int ret;
+
+	dprintk ("%s\n", __func__);
+
+	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+		fepriv->release_jiffies = jiffies;
+		mb();
+	}
+
+	ret = dvb_generic_release (inode, file);
+
+	if (dvbdev->users == -1) {
+		wake_up(&fepriv->wait_queue);
+		if (fepriv->exit != DVB_FE_NO_EXIT) {
+			fops_put(file->f_op);
+			file->f_op = NULL;
+			wake_up(&dvbdev->wait_queue);
+		}
+		if (fe->ops.ts_bus_ctrl)
+			fe->ops.ts_bus_ctrl(fe, 0);
+	}
+
+	return ret;
+}
+
+static const struct file_operations dvb_frontend_fops = {
+	.owner		= THIS_MODULE,
+	.unlocked_ioctl	= dvb_generic_ioctl,
+	.poll		= dvb_frontend_poll,
+	.open		= dvb_frontend_open,
+	.release	= dvb_frontend_release,
+	.llseek		= noop_llseek,
+};
+
+int dvb_frontend_suspend(struct dvb_frontend *fe)
+{
+	int ret = 0;
+
+	dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num,
+			fe->id);
+
+	if (fe->ops.tuner_ops.sleep)
+		ret = fe->ops.tuner_ops.sleep(fe);
+
+	if (fe->ops.sleep)
+		ret = fe->ops.sleep(fe);
+
+	return ret;
+}
+EXPORT_SYMBOL(dvb_frontend_suspend);
+
+int dvb_frontend_resume(struct dvb_frontend *fe)
+{
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	int ret = 0;
+
+	dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num,
+			fe->id);
+
+	if (fe->ops.init)
+		ret = fe->ops.init(fe);
+
+	if (fe->ops.tuner_ops.init)
+		ret = fe->ops.tuner_ops.init(fe);
+
+	fepriv->state = FESTATE_RETUNE;
+	dvb_frontend_wakeup(fe);
+
+	return ret;
+}
+EXPORT_SYMBOL(dvb_frontend_resume);
+
+int dvb_register_frontend(struct dvb_adapter* dvb,
+			  struct dvb_frontend* fe)
+{
+	struct dvb_frontend_private *fepriv;
+	static const struct dvb_device dvbdev_template = {
+		.users = ~0,
+		.writers = 1,
+		.readers = (~0)-1,
+		.fops = &dvb_frontend_fops,
+		.kernel_ioctl = dvb_frontend_ioctl
+	};
+
+	dprintk ("%s\n", __func__);
+
+	if (mutex_lock_interruptible(&frontend_mutex))
+		return -ERESTARTSYS;
+
+	fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL);
+	if (fe->frontend_priv == NULL) {
+		mutex_unlock(&frontend_mutex);
+		return -ENOMEM;
+	}
+	fepriv = fe->frontend_priv;
+
+	sema_init(&fepriv->sem, 1);
+	init_waitqueue_head (&fepriv->wait_queue);
+	init_waitqueue_head (&fepriv->events.wait_queue);
+	mutex_init(&fepriv->events.mtx);
+	fe->dvb = dvb;
+	fepriv->inversion = INVERSION_OFF;
+
+	printk ("DVB: registering adapter %i frontend %i (%s)...\n",
+		fe->dvb->num,
+		fe->id,
+		fe->ops.info.name);
+
+	dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
+			     fe, DVB_DEVICE_FRONTEND);
+
+	/*
+	 * Initialize the cache to the proper values according with the
+	 * first supported delivery system (ops->delsys[0])
+	 */
+
+        fe->dtv_property_cache.delivery_system = fe->ops.delsys[0];
+	dvb_frontend_clear_cache(fe);
+
+	mutex_unlock(&frontend_mutex);
+	return 0;
+}
+EXPORT_SYMBOL(dvb_register_frontend);
+
+int dvb_unregister_frontend(struct dvb_frontend* fe)
+{
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	dprintk ("%s\n", __func__);
+
+	mutex_lock(&frontend_mutex);
+	dvb_frontend_stop (fe);
+	mutex_unlock(&frontend_mutex);
+
+	if (fepriv->dvbdev->users < -1)
+		wait_event(fepriv->dvbdev->wait_queue,
+				fepriv->dvbdev->users==-1);
+
+	mutex_lock(&frontend_mutex);
+	dvb_unregister_device (fepriv->dvbdev);
+
+	/* fe is invalid now */
+	kfree(fepriv);
+	mutex_unlock(&frontend_mutex);
+	return 0;
+}
+EXPORT_SYMBOL(dvb_unregister_frontend);
+
+#ifdef CONFIG_MEDIA_ATTACH
+void dvb_frontend_detach(struct dvb_frontend* fe)
+{
+	void *ptr;
+
+	if (fe->ops.release_sec) {
+		fe->ops.release_sec(fe);
+		symbol_put_addr(fe->ops.release_sec);
+	}
+	if (fe->ops.tuner_ops.release) {
+		fe->ops.tuner_ops.release(fe);
+		symbol_put_addr(fe->ops.tuner_ops.release);
+	}
+	if (fe->ops.analog_ops.release) {
+		fe->ops.analog_ops.release(fe);
+		symbol_put_addr(fe->ops.analog_ops.release);
+	}
+	ptr = (void*)fe->ops.release;
+	if (ptr) {
+		fe->ops.release(fe);
+		symbol_put_addr(ptr);
+	}
+}
+#else
+void dvb_frontend_detach(struct dvb_frontend* fe)
+{
+	if (fe->ops.release_sec)
+		fe->ops.release_sec(fe);
+	if (fe->ops.tuner_ops.release)
+		fe->ops.tuner_ops.release(fe);
+	if (fe->ops.analog_ops.release)
+		fe->ops.analog_ops.release(fe);
+	if (fe->ops.release)
+		fe->ops.release(fe);
+}
+#endif
+EXPORT_SYMBOL(dvb_frontend_detach);
diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h
new file mode 100644
index 0000000..db309db
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_frontend.h
@@ -0,0 +1,427 @@
+/*
+ * dvb_frontend.h
+ *
+ * Copyright (C) 2001 convergence integrated media GmbH
+ * Copyright (C) 2004 convergence GmbH
+ *
+ * Written by Ralph Metzler
+ * Overhauled by Holger Waechtler
+ * Kernel I2C stuff by Michael Hunold <hunold@convergence.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVB_FRONTEND_H_
+#define _DVB_FRONTEND_H_
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/ioctl.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <linux/dvb/frontend.h>
+
+#include "dvbdev.h"
+
+/*
+ * Maximum number of Delivery systems per frontend. It
+ * should be smaller or equal to 32
+ */
+#define MAX_DELSYS	8
+
+struct dvb_frontend_tune_settings {
+	int min_delay_ms;
+	int step_size;
+	int max_drift;
+};
+
+struct dvb_frontend;
+
+struct dvb_tuner_info {
+	char name[128];
+
+	u32 frequency_min;
+	u32 frequency_max;
+	u32 frequency_step;
+
+	u32 bandwidth_min;
+	u32 bandwidth_max;
+	u32 bandwidth_step;
+};
+
+struct analog_parameters {
+	unsigned int frequency;
+	unsigned int mode;
+	unsigned int audmode;
+	u64 std;
+};
+
+enum dvbfe_modcod {
+	DVBFE_MODCOD_DUMMY_PLFRAME	= 0,
+	DVBFE_MODCOD_QPSK_1_4,
+	DVBFE_MODCOD_QPSK_1_3,
+	DVBFE_MODCOD_QPSK_2_5,
+	DVBFE_MODCOD_QPSK_1_2,
+	DVBFE_MODCOD_QPSK_3_5,
+	DVBFE_MODCOD_QPSK_2_3,
+	DVBFE_MODCOD_QPSK_3_4,
+	DVBFE_MODCOD_QPSK_4_5,
+	DVBFE_MODCOD_QPSK_5_6,
+	DVBFE_MODCOD_QPSK_8_9,
+	DVBFE_MODCOD_QPSK_9_10,
+	DVBFE_MODCOD_8PSK_3_5,
+	DVBFE_MODCOD_8PSK_2_3,
+	DVBFE_MODCOD_8PSK_3_4,
+	DVBFE_MODCOD_8PSK_5_6,
+	DVBFE_MODCOD_8PSK_8_9,
+	DVBFE_MODCOD_8PSK_9_10,
+	DVBFE_MODCOD_16APSK_2_3,
+	DVBFE_MODCOD_16APSK_3_4,
+	DVBFE_MODCOD_16APSK_4_5,
+	DVBFE_MODCOD_16APSK_5_6,
+	DVBFE_MODCOD_16APSK_8_9,
+	DVBFE_MODCOD_16APSK_9_10,
+	DVBFE_MODCOD_32APSK_3_4,
+	DVBFE_MODCOD_32APSK_4_5,
+	DVBFE_MODCOD_32APSK_5_6,
+	DVBFE_MODCOD_32APSK_8_9,
+	DVBFE_MODCOD_32APSK_9_10,
+	DVBFE_MODCOD_RESERVED_1,
+	DVBFE_MODCOD_BPSK_1_3,
+	DVBFE_MODCOD_BPSK_1_4,
+	DVBFE_MODCOD_RESERVED_2
+};
+
+enum tuner_param {
+	DVBFE_TUNER_FREQUENCY		= (1 <<  0),
+	DVBFE_TUNER_TUNERSTEP		= (1 <<  1),
+	DVBFE_TUNER_IFFREQ		= (1 <<  2),
+	DVBFE_TUNER_BANDWIDTH		= (1 <<  3),
+	DVBFE_TUNER_REFCLOCK		= (1 <<  4),
+	DVBFE_TUNER_IQSENSE		= (1 <<  5),
+	DVBFE_TUNER_DUMMY		= (1 << 31)
+};
+
+/*
+ * ALGO_HW: (Hardware Algorithm)
+ * ----------------------------------------------------------------
+ * Devices that support this algorithm do everything in hardware
+ * and no software support is needed to handle them.
+ * Requesting these devices to LOCK is the only thing required,
+ * device is supposed to do everything in the hardware.
+ *
+ * ALGO_SW: (Software Algorithm)
+ * ----------------------------------------------------------------
+ * These are dumb devices, that require software to do everything
+ *
+ * ALGO_CUSTOM: (Customizable Agorithm)
+ * ----------------------------------------------------------------
+ * Devices having this algorithm can be customized to have specific
+ * algorithms in the frontend driver, rather than simply doing a
+ * software zig-zag. In this case the zigzag maybe hardware assisted
+ * or it maybe completely done in hardware. In all cases, usage of
+ * this algorithm, in conjunction with the search and track
+ * callbacks, utilizes the driver specific algorithm.
+ *
+ * ALGO_RECOVERY: (Recovery Algorithm)
+ * ----------------------------------------------------------------
+ * These devices have AUTO recovery capabilities from LOCK failure
+ */
+enum dvbfe_algo {
+	DVBFE_ALGO_HW			= (1 <<  0),
+	DVBFE_ALGO_SW			= (1 <<  1),
+	DVBFE_ALGO_CUSTOM		= (1 <<  2),
+	DVBFE_ALGO_RECOVERY		= (1 << 31)
+};
+
+struct tuner_state {
+	u32 frequency;
+	u32 tunerstep;
+	u32 ifreq;
+	u32 bandwidth;
+	u32 iqsense;
+	u32 refclock;
+};
+
+/*
+ * search callback possible return status
+ *
+ * DVBFE_ALGO_SEARCH_SUCCESS
+ * The frontend search algorithm completed and returned successfully
+ *
+ * DVBFE_ALGO_SEARCH_ASLEEP
+ * The frontend search algorithm is sleeping
+ *
+ * DVBFE_ALGO_SEARCH_FAILED
+ * The frontend search for a signal failed
+ *
+ * DVBFE_ALGO_SEARCH_INVALID
+ * The frontend search algorith was probably supplied with invalid
+ * parameters and the search is an invalid one
+ *
+ * DVBFE_ALGO_SEARCH_ERROR
+ * The frontend search algorithm failed due to some error
+ *
+ * DVBFE_ALGO_SEARCH_AGAIN
+ * The frontend search algorithm was requested to search again
+ */
+enum dvbfe_search {
+	DVBFE_ALGO_SEARCH_SUCCESS	= (1 <<  0),
+	DVBFE_ALGO_SEARCH_ASLEEP	= (1 <<  1),
+	DVBFE_ALGO_SEARCH_FAILED	= (1 <<  2),
+	DVBFE_ALGO_SEARCH_INVALID	= (1 <<  3),
+	DVBFE_ALGO_SEARCH_AGAIN		= (1 <<  4),
+	DVBFE_ALGO_SEARCH_ERROR		= (1 << 31),
+};
+
+
+struct dvb_tuner_ops {
+
+	struct dvb_tuner_info info;
+
+	int (*release)(struct dvb_frontend *fe);
+	int (*init)(struct dvb_frontend *fe);
+	int (*sleep)(struct dvb_frontend *fe);
+
+	/** This is for simple PLLs - set all parameters in one go. */
+	int (*set_params)(struct dvb_frontend *fe);
+	int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p);
+
+	/** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
+	int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len);
+
+	/** This is to allow setting tuner-specific configs */
+	int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
+
+	int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
+	int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
+	int (*get_if_frequency)(struct dvb_frontend *fe, u32 *frequency);
+
+#define TUNER_STATUS_LOCKED 1
+#define TUNER_STATUS_STEREO 2
+	int (*get_status)(struct dvb_frontend *fe, u32 *status);
+	int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
+	int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
+
+	/** These are provided separately from set_params in order to facilitate silicon
+	 * tuners which require sophisticated tuning loops, controlling each parameter separately. */
+	int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
+	int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
+
+	/*
+	 * These are provided separately from set_params in order to facilitate silicon
+	 * tuners which require sophisticated tuning loops, controlling each parameter separately.
+	 */
+	int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
+	int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
+};
+
+struct analog_demod_info {
+	char *name;
+};
+
+struct analog_demod_ops {
+
+	struct analog_demod_info info;
+
+	void (*set_params)(struct dvb_frontend *fe,
+			   struct analog_parameters *params);
+	int  (*has_signal)(struct dvb_frontend *fe);
+	int  (*get_afc)(struct dvb_frontend *fe);
+	void (*tuner_status)(struct dvb_frontend *fe);
+	void (*standby)(struct dvb_frontend *fe);
+	void (*release)(struct dvb_frontend *fe);
+	int  (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable);
+
+	/** This is to allow setting tuner-specific configuration */
+	int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
+};
+
+struct dtv_frontend_properties;
+
+struct dvb_frontend_ops {
+
+	struct dvb_frontend_info info;
+
+	u8 delsys[MAX_DELSYS];
+
+	void (*release)(struct dvb_frontend* fe);
+	void (*release_sec)(struct dvb_frontend* fe);
+
+	int (*init)(struct dvb_frontend* fe);
+	int (*sleep)(struct dvb_frontend* fe);
+
+	int (*write)(struct dvb_frontend* fe, const u8 buf[], int len);
+
+	/* if this is set, it overrides the default swzigzag */
+	int (*tune)(struct dvb_frontend* fe,
+		    bool re_tune,
+		    unsigned int mode_flags,
+		    unsigned int *delay,
+		    fe_status_t *status);
+	/* get frontend tuning algorithm from the module */
+	enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe);
+
+	/* these two are only used for the swzigzag code */
+	int (*set_frontend)(struct dvb_frontend *fe);
+	int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
+
+	int (*get_frontend)(struct dvb_frontend *fe);
+
+	int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
+	int (*read_ber)(struct dvb_frontend* fe, u32* ber);
+	int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
+	int (*read_snr)(struct dvb_frontend* fe, u16* snr);
+	int (*read_ucblocks)(struct dvb_frontend* fe, u32* ucblocks);
+
+	int (*diseqc_reset_overload)(struct dvb_frontend* fe);
+	int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
+	int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply);
+	int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
+	int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
+	int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+	int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
+	int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
+	int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
+	int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
+
+	/* These callbacks are for devices that implement their own
+	 * tuning algorithms, rather than a simple swzigzag
+	 */
+	enum dvbfe_search (*search)(struct dvb_frontend *fe);
+
+	struct dvb_tuner_ops tuner_ops;
+	struct analog_demod_ops analog_ops;
+
+	int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
+	int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
+};
+
+#ifdef __DVB_CORE__
+#define MAX_EVENT 8
+
+struct dvb_fe_events {
+	struct dvb_frontend_event events[MAX_EVENT];
+	int			  eventw;
+	int			  eventr;
+	int			  overflow;
+	wait_queue_head_t	  wait_queue;
+	struct mutex		  mtx;
+};
+#endif
+
+struct dtv_frontend_properties {
+
+	/* Cache State */
+	u32			state;
+
+	u32			frequency;
+	fe_modulation_t		modulation;
+
+	fe_sec_voltage_t	voltage;
+	fe_sec_tone_mode_t	sectone;
+	fe_spectral_inversion_t	inversion;
+	fe_code_rate_t		fec_inner;
+	fe_transmit_mode_t	transmission_mode;
+	u32			bandwidth_hz;	/* 0 = AUTO */
+	fe_guard_interval_t	guard_interval;
+	fe_hierarchy_t		hierarchy;
+	u32			symbol_rate;
+	fe_code_rate_t		code_rate_HP;
+	fe_code_rate_t		code_rate_LP;
+
+	fe_pilot_t		pilot;
+	fe_rolloff_t		rolloff;
+
+	fe_delivery_system_t	delivery_system;
+
+	enum fe_interleaving	interleaving;
+
+	/* ISDB-T specifics */
+	u8			isdbt_partial_reception;
+	u8			isdbt_sb_mode;
+	u8			isdbt_sb_subchannel;
+	u32			isdbt_sb_segment_idx;
+	u32			isdbt_sb_segment_count;
+	u8			isdbt_layer_enabled;
+	struct {
+	    u8			segment_count;
+	    fe_code_rate_t	fec;
+	    fe_modulation_t	modulation;
+	    u8			interleaving;
+	} layer[3];
+
+	/* ISDB-T specifics */
+	u32			isdbs_ts_id;
+
+	/* DVB-T2 specifics */
+	u32                     dvbt2_plp_id;
+
+	/* ATSC-MH specifics */
+	u8			atscmh_fic_ver;
+	u8			atscmh_parade_id;
+	u8			atscmh_nog;
+	u8			atscmh_tnog;
+	u8			atscmh_sgn;
+	u8			atscmh_prc;
+
+	u8			atscmh_rs_frame_mode;
+	u8			atscmh_rs_frame_ensemble;
+	u8			atscmh_rs_code_mode_pri;
+	u8			atscmh_rs_code_mode_sec;
+	u8			atscmh_sccc_block_mode;
+	u8			atscmh_sccc_code_mode_a;
+	u8			atscmh_sccc_code_mode_b;
+	u8			atscmh_sccc_code_mode_c;
+	u8			atscmh_sccc_code_mode_d;
+};
+
+struct dvb_frontend {
+	struct dvb_frontend_ops ops;
+	struct dvb_adapter *dvb;
+	void *demodulator_priv;
+	void *tuner_priv;
+	void *frontend_priv;
+	void *sec_priv;
+	void *analog_demod_priv;
+	struct dtv_frontend_properties dtv_property_cache;
+#define DVB_FRONTEND_COMPONENT_TUNER 0
+#define DVB_FRONTEND_COMPONENT_DEMOD 1
+	int (*callback)(void *adapter_priv, int component, int cmd, int arg);
+	int id;
+};
+
+extern int dvb_register_frontend(struct dvb_adapter *dvb,
+				 struct dvb_frontend *fe);
+
+extern int dvb_unregister_frontend(struct dvb_frontend *fe);
+
+extern void dvb_frontend_detach(struct dvb_frontend *fe);
+
+extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
+extern int dvb_frontend_suspend(struct dvb_frontend *fe);
+extern int dvb_frontend_resume(struct dvb_frontend *fe);
+
+extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec);
+extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime);
+
+#endif
diff --git a/drivers/media/dvb-core/dvb_math.c b/drivers/media/dvb-core/dvb_math.c
new file mode 100644
index 0000000..beb7c93
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_math.c
@@ -0,0 +1,145 @@
+/*
+ * dvb-math provides some complex fixed-point math
+ * operations shared between the dvb related stuff
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/bug.h>
+#include "dvb_math.h"
+
+static const unsigned short logtable[256] = {
+	0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
+	0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
+	0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
+	0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
+	0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
+	0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
+	0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
+	0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
+	0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
+	0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
+	0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
+	0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
+	0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
+	0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
+	0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
+	0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
+	0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
+	0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
+	0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
+	0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
+	0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
+	0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
+	0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
+	0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
+	0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
+	0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
+	0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
+	0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
+	0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
+	0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
+	0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
+	0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
+};
+
+unsigned int intlog2(u32 value)
+{
+	/**
+	 *	returns: log2(value) * 2^24
+	 *	wrong result if value = 0 (log2(0) is undefined)
+	 */
+	unsigned int msb;
+	unsigned int logentry;
+	unsigned int significand;
+	unsigned int interpolation;
+
+	if (unlikely(value == 0)) {
+		WARN_ON(1);
+		return 0;
+	}
+
+	/* first detect the msb (count begins at 0) */
+	msb = fls(value) - 1;
+
+	/**
+	 *	now we use a logtable after the following method:
+	 *
+	 *	log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
+	 *	where x = msb and therefore 1 <= y < 2
+	 *	first y is determined by shifting the value left
+	 *	so that msb is bit 31
+	 *		0x00231f56 -> 0x8C7D5800
+	 *	the result is y * 2^31 -> "significand"
+	 *	then the highest 9 bits are used for a table lookup
+	 *	the highest bit is discarded because it's always set
+	 *	the highest nine bits in our example are 100011000
+	 *	so we would use the entry 0x18
+	 */
+	significand = value << (31 - msb);
+	logentry = (significand >> 23) & 0xff;
+
+	/**
+	 *	last step we do is interpolation because of the
+	 *	limitations of the log table the error is that part of
+	 *	the significand which isn't used for lookup then we
+	 *	compute the ratio between the error and the next table entry
+	 *	and interpolate it between the log table entry used and the
+	 *	next one the biggest error possible is 0x7fffff
+	 *	(in our example it's 0x7D5800)
+	 *	needed value for next table entry is 0x800000
+	 *	so the interpolation is
+	 *	(error / 0x800000) * (logtable_next - logtable_current)
+	 *	in the implementation the division is moved to the end for
+	 *	better accuracy there is also an overflow correction if
+	 *	logtable_next is 256
+	 */
+	interpolation = ((significand & 0x7fffff) *
+			((logtable[(logentry + 1) & 0xff] -
+			  logtable[logentry]) & 0xffff)) >> 15;
+
+	/* now we return the result */
+	return ((msb << 24) + (logtable[logentry] << 8) + interpolation);
+}
+EXPORT_SYMBOL(intlog2);
+
+unsigned int intlog10(u32 value)
+{
+	/**
+	 *	returns: log10(value) * 2^24
+	 *	wrong result if value = 0 (log10(0) is undefined)
+	 */
+	u64 log;
+
+	if (unlikely(value == 0)) {
+		WARN_ON(1);
+		return 0;
+	}
+
+	log = intlog2(value);
+
+	/**
+	 *	we use the following method:
+	 *	log10(x) = log2(x) * log10(2)
+	 */
+
+	return (log * 646456993) >> 31;
+}
+EXPORT_SYMBOL(intlog10);
diff --git a/drivers/media/dvb-core/dvb_math.h b/drivers/media/dvb-core/dvb_math.h
new file mode 100644
index 0000000..aecc867
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_math.h
@@ -0,0 +1,58 @@
+/*
+ * dvb-math provides some complex fixed-point math
+ * operations shared between the dvb related stuff
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __DVB_MATH_H
+#define __DVB_MATH_H
+
+#include <linux/types.h>
+
+/**
+ * computes log2 of a value; the result is shifted left by 24 bits
+ *
+ * to use rational values you can use the following method:
+ *   intlog2(value) = intlog2(value * 2^x) - x * 2^24
+ *
+ * example: intlog2(8) will give 3 << 24 = 3 * 2^24
+ * example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
+ * example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
+ *
+ * @param value The value (must be != 0)
+ * @return log2(value) * 2^24
+ */
+extern unsigned int intlog2(u32 value);
+
+/**
+ * computes log10 of a value; the result is shifted left by 24 bits
+ *
+ * to use rational values you can use the following method:
+ *   intlog10(value) = intlog10(value * 10^x) - x * 2^24
+ *
+ * example: intlog10(1000) will give 3 << 24 = 3 * 2^24
+ *   due to the implementation intlog10(1000) might be not exactly 3 * 2^24
+ *
+ * look at intlog2 for similar examples
+ *
+ * @param value The value (must be != 0)
+ * @return log10(value) * 2^24
+ */
+extern unsigned int intlog10(u32 value);
+
+#endif
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
new file mode 100644
index 0000000..8766ce8
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_net.c
@@ -0,0 +1,1516 @@
+/*
+ * dvb_net.c
+ *
+ * Copyright (C) 2001 Convergence integrated media GmbH
+ *                    Ralph Metzler <ralph@convergence.de>
+ * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
+ *
+ * ULE Decapsulation code:
+ * Copyright (C) 2003, 2004 gcs - Global Communication & Services GmbH.
+ *                      and Department of Scientific Computing
+ *                          Paris Lodron University of Salzburg.
+ *                          Hilmar Linder <hlinder@cosy.sbg.ac.at>
+ *                      and Wolfram Stering <wstering@cosy.sbg.ac.at>
+ *
+ * ULE Decaps according to RFC 4326.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ * ULE ChangeLog:
+ * Feb 2004: hl/ws v1: Implementing draft-fair-ipdvb-ule-01.txt
+ *
+ * Dec 2004: hl/ws v2: Implementing draft-ietf-ipdvb-ule-03.txt:
+ *                       ULE Extension header handling.
+ *                     Bugreports by Moritz Vieth and Hanno Tersteegen,
+ *                       Fraunhofer Institute for Open Communication Systems
+ *                       Competence Center for Advanced Satellite Communications.
+ *                     Bugfixes and robustness improvements.
+ *                     Filtering on dest MAC addresses, if present (D-Bit = 0)
+ *                     ULE_DEBUG compile-time option.
+ * Apr 2006: cp v3:    Bugfixes and compliency with RFC 4326 (ULE) by
+ *                       Christian Praehauser <cpraehaus@cosy.sbg.ac.at>,
+ *                       Paris Lodron University of Salzburg.
+ */
+
+/*
+ * FIXME / TODO (dvb_net.c):
+ *
+ * Unloading does not work for 2.6.9 kernels: a refcount doesn't go to zero.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/dvb/net.h>
+#include <linux/uio.h>
+#include <asm/uaccess.h>
+#include <linux/crc32.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+
+#include "dvb_demux.h"
+#include "dvb_net.h"
+
+static int dvb_net_debug;
+module_param(dvb_net_debug, int, 0444);
+MODULE_PARM_DESC(dvb_net_debug, "enable debug messages");
+
+#define dprintk(x...) do { if (dvb_net_debug) printk(x); } while (0)
+
+
+static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
+{
+	unsigned int j;
+	for (j = 0; j < cnt; j++)
+		c = crc32_be( c, iov[j].iov_base, iov[j].iov_len );
+	return c;
+}
+
+
+#define DVB_NET_MULTICAST_MAX 10
+
+#undef ULE_DEBUG
+
+#ifdef ULE_DEBUG
+
+#define MAC_ADDR_PRINTFMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"
+#define MAX_ADDR_PRINTFMT_ARGS(macap) (macap)[0],(macap)[1],(macap)[2],(macap)[3],(macap)[4],(macap)[5]
+
+#define isprint(c)	((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
+
+static void hexdump( const unsigned char *buf, unsigned short len )
+{
+	char str[80], octet[10];
+	int ofs, i, l;
+
+	for (ofs = 0; ofs < len; ofs += 16) {
+		sprintf( str, "%03d: ", ofs );
+
+		for (i = 0; i < 16; i++) {
+			if ((i + ofs) < len)
+				sprintf( octet, "%02x ", buf[ofs + i] );
+			else
+				strcpy( octet, "   " );
+
+			strcat( str, octet );
+		}
+		strcat( str, "  " );
+		l = strlen( str );
+
+		for (i = 0; (i < 16) && ((i + ofs) < len); i++)
+			str[l++] = isprint( buf[ofs + i] ) ? buf[ofs + i] : '.';
+
+		str[l] = '\0';
+		printk( KERN_WARNING "%s\n", str );
+	}
+}
+
+#endif
+
+struct dvb_net_priv {
+	int in_use;
+	u16 pid;
+	struct net_device *net;
+	struct dvb_net *host;
+	struct dmx_demux *demux;
+	struct dmx_section_feed *secfeed;
+	struct dmx_section_filter *secfilter;
+	struct dmx_ts_feed *tsfeed;
+	int multi_num;
+	struct dmx_section_filter *multi_secfilter[DVB_NET_MULTICAST_MAX];
+	unsigned char multi_macs[DVB_NET_MULTICAST_MAX][6];
+	int rx_mode;
+#define RX_MODE_UNI 0
+#define RX_MODE_MULTI 1
+#define RX_MODE_ALL_MULTI 2
+#define RX_MODE_PROMISC 3
+	struct work_struct set_multicast_list_wq;
+	struct work_struct restart_net_feed_wq;
+	unsigned char feedtype;			/* Either FEED_TYPE_ or FEED_TYPE_ULE */
+	int need_pusi;				/* Set to 1, if synchronization on PUSI required. */
+	unsigned char tscc;			/* TS continuity counter after sync on PUSI. */
+	struct sk_buff *ule_skb;		/* ULE SNDU decodes into this buffer. */
+	unsigned char *ule_next_hdr;		/* Pointer into skb to next ULE extension header. */
+	unsigned short ule_sndu_len;		/* ULE SNDU length in bytes, w/o D-Bit. */
+	unsigned short ule_sndu_type;		/* ULE SNDU type field, complete. */
+	unsigned char ule_sndu_type_1;		/* ULE SNDU type field, if split across 2 TS cells. */
+	unsigned char ule_dbit;			/* Whether the DestMAC address present
+						 * or not (bit is set). */
+	unsigned char ule_bridged;		/* Whether the ULE_BRIDGED extension header was found. */
+	int ule_sndu_remain;			/* Nr. of bytes still required for current ULE SNDU. */
+	unsigned long ts_count;			/* Current ts cell counter. */
+	struct mutex mutex;
+};
+
+
+/**
+ *	Determine the packet's protocol ID. The rule here is that we
+ *	assume 802.3 if the type field is short enough to be a length.
+ *	This is normal practice and works for any 'now in use' protocol.
+ *
+ *  stolen from eth.c out of the linux kernel, hacked for dvb-device
+ *  by Michael Holzt <kju@debian.org>
+ */
+static __be16 dvb_net_eth_type_trans(struct sk_buff *skb,
+				      struct net_device *dev)
+{
+	struct ethhdr *eth;
+	unsigned char *rawp;
+
+	skb_reset_mac_header(skb);
+	skb_pull(skb,dev->hard_header_len);
+	eth = eth_hdr(skb);
+
+	if (*eth->h_dest & 1) {
+		if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
+			skb->pkt_type=PACKET_BROADCAST;
+		else
+			skb->pkt_type=PACKET_MULTICAST;
+	}
+
+	if (ntohs(eth->h_proto) >= 1536)
+		return eth->h_proto;
+
+	rawp = skb->data;
+
+	/**
+	 *	This is a magic hack to spot IPX packets. Older Novell breaks
+	 *	the protocol design and runs IPX over 802.3 without an 802.2 LLC
+	 *	layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
+	 *	won't work for fault tolerant netware but does for the rest.
+	 */
+	if (*(unsigned short *)rawp == 0xFFFF)
+		return htons(ETH_P_802_3);
+
+	/**
+	 *	Real 802.2 LLC
+	 */
+	return htons(ETH_P_802_2);
+}
+
+#define TS_SZ	188
+#define TS_SYNC	0x47
+#define TS_TEI	0x80
+#define TS_SC	0xC0
+#define TS_PUSI	0x40
+#define TS_AF_A	0x20
+#define TS_AF_D	0x10
+
+/* ULE Extension Header handlers. */
+
+#define ULE_TEST	0
+#define ULE_BRIDGED	1
+
+#define ULE_OPTEXTHDR_PADDING 0
+
+static int ule_test_sndu( struct dvb_net_priv *p )
+{
+	return -1;
+}
+
+static int ule_bridged_sndu( struct dvb_net_priv *p )
+{
+	struct ethhdr *hdr = (struct ethhdr*) p->ule_next_hdr;
+	if(ntohs(hdr->h_proto) < 1536) {
+		int framelen = p->ule_sndu_len - ((p->ule_next_hdr+sizeof(struct ethhdr)) - p->ule_skb->data);
+		/* A frame Type < 1536 for a bridged frame, introduces a LLC Length field. */
+		if(framelen != ntohs(hdr->h_proto)) {
+			return -1;
+		}
+	}
+	/* Note:
+	 * From RFC4326:
+	 *  "A bridged SNDU is a Mandatory Extension Header of Type 1.
+	 *   It must be the final (or only) extension header specified in the header chain of a SNDU."
+	 * The 'ule_bridged' flag will cause the extension header processing loop to terminate.
+	 */
+	p->ule_bridged = 1;
+	return 0;
+}
+
+static int ule_exthdr_padding(struct dvb_net_priv *p)
+{
+	return 0;
+}
+
+/** Handle ULE extension headers.
+ *  Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding.
+ *  Returns: >= 0: nr. of bytes consumed by next extension header
+ *	     -1:   Mandatory extension header that is not recognized or TEST SNDU; discard.
+ */
+static int handle_one_ule_extension( struct dvb_net_priv *p )
+{
+	/* Table of mandatory extension header handlers.  The header type is the index. */
+	static int (*ule_mandatory_ext_handlers[255])( struct dvb_net_priv *p ) =
+		{ [0] = ule_test_sndu, [1] = ule_bridged_sndu, [2] = NULL,  };
+
+	/* Table of optional extension header handlers.  The header type is the index. */
+	static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) =
+		{ [0] = ule_exthdr_padding, [1] = NULL, };
+
+	int ext_len = 0;
+	unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8;
+	unsigned char htype = p->ule_sndu_type & 0x00FF;
+
+	/* Discriminate mandatory and optional extension headers. */
+	if (hlen == 0) {
+		/* Mandatory extension header */
+		if (ule_mandatory_ext_handlers[htype]) {
+			ext_len = ule_mandatory_ext_handlers[htype]( p );
+			if(ext_len >= 0) {
+				p->ule_next_hdr += ext_len;
+				if (!p->ule_bridged) {
+					p->ule_sndu_type = ntohs(*(__be16 *)p->ule_next_hdr);
+					p->ule_next_hdr += 2;
+				} else {
+					p->ule_sndu_type = ntohs(*(__be16 *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)));
+					/* This assures the extension handling loop will terminate. */
+				}
+			}
+			// else: extension handler failed or SNDU should be discarded
+		} else
+			ext_len = -1;	/* SNDU has to be discarded. */
+	} else {
+		/* Optional extension header.  Calculate the length. */
+		ext_len = hlen << 1;
+		/* Process the optional extension header according to its type. */
+		if (ule_optional_ext_handlers[htype])
+			(void)ule_optional_ext_handlers[htype]( p );
+		p->ule_next_hdr += ext_len;
+		p->ule_sndu_type = ntohs( *(__be16 *)(p->ule_next_hdr-2) );
+		/*
+		 * note: the length of the next header type is included in the
+		 * length of THIS optional extension header
+		 */
+	}
+
+	return ext_len;
+}
+
+static int handle_ule_extensions( struct dvb_net_priv *p )
+{
+	int total_ext_len = 0, l;
+
+	p->ule_next_hdr = p->ule_skb->data;
+	do {
+		l = handle_one_ule_extension( p );
+		if (l < 0)
+			return l;	/* Stop extension header processing and discard SNDU. */
+		total_ext_len += l;
+#ifdef ULE_DEBUG
+		dprintk("handle_ule_extensions: ule_next_hdr=%p, ule_sndu_type=%i, "
+			"l=%i, total_ext_len=%i\n", p->ule_next_hdr,
+			(int) p->ule_sndu_type, l, total_ext_len);
+#endif
+
+	} while (p->ule_sndu_type < 1536);
+
+	return total_ext_len;
+}
+
+
+/** Prepare for a new ULE SNDU: reset the decoder state. */
+static inline void reset_ule( struct dvb_net_priv *p )
+{
+	p->ule_skb = NULL;
+	p->ule_next_hdr = NULL;
+	p->ule_sndu_len = 0;
+	p->ule_sndu_type = 0;
+	p->ule_sndu_type_1 = 0;
+	p->ule_sndu_remain = 0;
+	p->ule_dbit = 0xFF;
+	p->ule_bridged = 0;
+}
+
+/**
+ * Decode ULE SNDUs according to draft-ietf-ipdvb-ule-03.txt from a sequence of
+ * TS cells of a single PID.
+ */
+static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
+{
+	struct dvb_net_priv *priv = netdev_priv(dev);
+	unsigned long skipped = 0L;
+	const u8 *ts, *ts_end, *from_where = NULL;
+	u8 ts_remain = 0, how_much = 0, new_ts = 1;
+	struct ethhdr *ethh = NULL;
+	bool error = false;
+
+#ifdef ULE_DEBUG
+	/* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */
+	static unsigned char ule_hist[100*TS_SZ];
+	static unsigned char *ule_where = ule_hist, ule_dump;
+#endif
+
+	/* For all TS cells in current buffer.
+	 * Appearently, we are called for every single TS cell.
+	 */
+	for (ts = buf, ts_end = buf + buf_len; ts < ts_end; /* no default incr. */ ) {
+
+		if (new_ts) {
+			/* We are about to process a new TS cell. */
+
+#ifdef ULE_DEBUG
+			if (ule_where >= &ule_hist[100*TS_SZ]) ule_where = ule_hist;
+			memcpy( ule_where, ts, TS_SZ );
+			if (ule_dump) {
+				hexdump( ule_where, TS_SZ );
+				ule_dump = 0;
+			}
+			ule_where += TS_SZ;
+#endif
+
+			/* Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control . */
+			if ((ts[0] != TS_SYNC) || (ts[1] & TS_TEI) || ((ts[3] & TS_SC) != 0)) {
+				printk(KERN_WARNING "%lu: Invalid TS cell: SYNC %#x, TEI %u, SC %#x.\n",
+				       priv->ts_count, ts[0], ts[1] & TS_TEI >> 7, ts[3] & 0xC0 >> 6);
+
+				/* Drop partly decoded SNDU, reset state, resync on PUSI. */
+				if (priv->ule_skb) {
+					dev_kfree_skb( priv->ule_skb );
+					/* Prepare for next SNDU. */
+					dev->stats.rx_errors++;
+					dev->stats.rx_frame_errors++;
+				}
+				reset_ule(priv);
+				priv->need_pusi = 1;
+
+				/* Continue with next TS cell. */
+				ts += TS_SZ;
+				priv->ts_count++;
+				continue;
+			}
+
+			ts_remain = 184;
+			from_where = ts + 4;
+		}
+		/* Synchronize on PUSI, if required. */
+		if (priv->need_pusi) {
+			if (ts[1] & TS_PUSI) {
+				/* Find beginning of first ULE SNDU in current TS cell. */
+				/* Synchronize continuity counter. */
+				priv->tscc = ts[3] & 0x0F;
+				/* There is a pointer field here. */
+				if (ts[4] > ts_remain) {
+					printk(KERN_ERR "%lu: Invalid ULE packet "
+					       "(pointer field %d)\n", priv->ts_count, ts[4]);
+					ts += TS_SZ;
+					priv->ts_count++;
+					continue;
+				}
+				/* Skip to destination of pointer field. */
+				from_where = &ts[5] + ts[4];
+				ts_remain -= 1 + ts[4];
+				skipped = 0;
+			} else {
+				skipped++;
+				ts += TS_SZ;
+				priv->ts_count++;
+				continue;
+			}
+		}
+
+		if (new_ts) {
+			/* Check continuity counter. */
+			if ((ts[3] & 0x0F) == priv->tscc)
+				priv->tscc = (priv->tscc + 1) & 0x0F;
+			else {
+				/* TS discontinuity handling: */
+				printk(KERN_WARNING "%lu: TS discontinuity: got %#x, "
+				       "expected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);
+				/* Drop partly decoded SNDU, reset state, resync on PUSI. */
+				if (priv->ule_skb) {
+					dev_kfree_skb( priv->ule_skb );
+					/* Prepare for next SNDU. */
+					// reset_ule(priv);  moved to below.
+					dev->stats.rx_errors++;
+					dev->stats.rx_frame_errors++;
+				}
+				reset_ule(priv);
+				/* skip to next PUSI. */
+				priv->need_pusi = 1;
+				continue;
+			}
+			/* If we still have an incomplete payload, but PUSI is
+			 * set; some TS cells are missing.
+			 * This is only possible here, if we missed exactly 16 TS
+			 * cells (continuity counter wrap). */
+			if (ts[1] & TS_PUSI) {
+				if (! priv->need_pusi) {
+					if (!(*from_where < (ts_remain-1)) || *from_where != priv->ule_sndu_remain) {
+						/* Pointer field is invalid.  Drop this TS cell and any started ULE SNDU. */
+						printk(KERN_WARNING "%lu: Invalid pointer "
+						       "field: %u.\n", priv->ts_count, *from_where);
+
+						/* Drop partly decoded SNDU, reset state, resync on PUSI. */
+						if (priv->ule_skb) {
+							error = true;
+							dev_kfree_skb(priv->ule_skb);
+						}
+
+						if (error || priv->ule_sndu_remain) {
+							dev->stats.rx_errors++;
+							dev->stats.rx_frame_errors++;
+							error = false;
+						}
+
+						reset_ule(priv);
+						priv->need_pusi = 1;
+						continue;
+					}
+					/* Skip pointer field (we're processing a
+					 * packed payload). */
+					from_where += 1;
+					ts_remain -= 1;
+				} else
+					priv->need_pusi = 0;
+
+				if (priv->ule_sndu_remain > 183) {
+					/* Current SNDU lacks more data than there could be available in the
+					 * current TS cell. */
+					dev->stats.rx_errors++;
+					dev->stats.rx_length_errors++;
+					printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but "
+					       "got PUSI (pf %d, ts_remain %d).  Flushing incomplete payload.\n",
+					       priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain);
+					dev_kfree_skb(priv->ule_skb);
+					/* Prepare for next SNDU. */
+					reset_ule(priv);
+					/* Resync: go to where pointer field points to: start of next ULE SNDU. */
+					from_where += ts[4];
+					ts_remain -= ts[4];
+				}
+			}
+		}
+
+		/* Check if new payload needs to be started. */
+		if (priv->ule_skb == NULL) {
+			/* Start a new payload with skb.
+			 * Find ULE header.  It is only guaranteed that the
+			 * length field (2 bytes) is contained in the current
+			 * TS.
+			 * Check ts_remain has to be >= 2 here. */
+			if (ts_remain < 2) {
+				printk(KERN_WARNING "Invalid payload packing: only %d "
+				       "bytes left in TS.  Resyncing.\n", ts_remain);
+				priv->ule_sndu_len = 0;
+				priv->need_pusi = 1;
+				ts += TS_SZ;
+				continue;
+			}
+
+			if (! priv->ule_sndu_len) {
+				/* Got at least two bytes, thus extrace the SNDU length. */
+				priv->ule_sndu_len = from_where[0] << 8 | from_where[1];
+				if (priv->ule_sndu_len & 0x8000) {
+					/* D-Bit is set: no dest mac present. */
+					priv->ule_sndu_len &= 0x7FFF;
+					priv->ule_dbit = 1;
+				} else
+					priv->ule_dbit = 0;
+
+				if (priv->ule_sndu_len < 5) {
+					printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. "
+					       "Resyncing.\n", priv->ts_count, priv->ule_sndu_len);
+					dev->stats.rx_errors++;
+					dev->stats.rx_length_errors++;
+					priv->ule_sndu_len = 0;
+					priv->need_pusi = 1;
+					new_ts = 1;
+					ts += TS_SZ;
+					priv->ts_count++;
+					continue;
+				}
+				ts_remain -= 2;	/* consume the 2 bytes SNDU length. */
+				from_where += 2;
+			}
+
+			priv->ule_sndu_remain = priv->ule_sndu_len + 2;
+			/*
+			 * State of current TS:
+			 *   ts_remain (remaining bytes in the current TS cell)
+			 *   0	ule_type is not available now, we need the next TS cell
+			 *   1	the first byte of the ule_type is present
+			 * >=2	full ULE header present, maybe some payload data as well.
+			 */
+			switch (ts_remain) {
+				case 1:
+					priv->ule_sndu_remain--;
+					priv->ule_sndu_type = from_where[0] << 8;
+					priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */
+					ts_remain -= 1; from_where += 1;
+					/* Continue w/ next TS. */
+				case 0:
+					new_ts = 1;
+					ts += TS_SZ;
+					priv->ts_count++;
+					continue;
+
+				default: /* complete ULE header is present in current TS. */
+					/* Extract ULE type field. */
+					if (priv->ule_sndu_type_1) {
+						priv->ule_sndu_type_1 = 0;
+						priv->ule_sndu_type |= from_where[0];
+						from_where += 1; /* points to payload start. */
+						ts_remain -= 1;
+					} else {
+						/* Complete type is present in new TS. */
+						priv->ule_sndu_type = from_where[0] << 8 | from_where[1];
+						from_where += 2; /* points to payload start. */
+						ts_remain -= 2;
+					}
+					break;
+			}
+
+			/* Allocate the skb (decoder target buffer) with the correct size, as follows:
+			 * prepare for the largest case: bridged SNDU with MAC address (dbit = 0). */
+			priv->ule_skb = dev_alloc_skb( priv->ule_sndu_len + ETH_HLEN + ETH_ALEN );
+			if (priv->ule_skb == NULL) {
+				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
+				       dev->name);
+				dev->stats.rx_dropped++;
+				return;
+			}
+
+			/* This includes the CRC32 _and_ dest mac, if !dbit. */
+			priv->ule_sndu_remain = priv->ule_sndu_len;
+			priv->ule_skb->dev = dev;
+			/* Leave space for Ethernet or bridged SNDU header (eth hdr plus one MAC addr). */
+			skb_reserve( priv->ule_skb, ETH_HLEN + ETH_ALEN );
+		}
+
+		/* Copy data into our current skb. */
+		how_much = min(priv->ule_sndu_remain, (int)ts_remain);
+		memcpy(skb_put(priv->ule_skb, how_much), from_where, how_much);
+		priv->ule_sndu_remain -= how_much;
+		ts_remain -= how_much;
+		from_where += how_much;
+
+		/* Check for complete payload. */
+		if (priv->ule_sndu_remain <= 0) {
+			/* Check CRC32, we've got it in our skb already. */
+			__be16 ulen = htons(priv->ule_sndu_len);
+			__be16 utype = htons(priv->ule_sndu_type);
+			const u8 *tail;
+			struct kvec iov[3] = {
+				{ &ulen, sizeof ulen },
+				{ &utype, sizeof utype },
+				{ priv->ule_skb->data, priv->ule_skb->len - 4 }
+			};
+			u32 ule_crc = ~0L, expected_crc;
+			if (priv->ule_dbit) {
+				/* Set D-bit for CRC32 verification,
+				 * if it was set originally. */
+				ulen |= htons(0x8000);
+			}
+
+			ule_crc = iov_crc32(ule_crc, iov, 3);
+			tail = skb_tail_pointer(priv->ule_skb);
+			expected_crc = *(tail - 4) << 24 |
+				       *(tail - 3) << 16 |
+				       *(tail - 2) << 8 |
+				       *(tail - 1);
+			if (ule_crc != expected_crc) {
+				printk(KERN_WARNING "%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n",
+				       priv->ts_count, ule_crc, expected_crc, priv->ule_sndu_len, priv->ule_sndu_type, ts_remain, ts_remain > 2 ? *(unsigned short *)from_where : 0);
+
+#ifdef ULE_DEBUG
+				hexdump( iov[0].iov_base, iov[0].iov_len );
+				hexdump( iov[1].iov_base, iov[1].iov_len );
+				hexdump( iov[2].iov_base, iov[2].iov_len );
+
+				if (ule_where == ule_hist) {
+					hexdump( &ule_hist[98*TS_SZ], TS_SZ );
+					hexdump( &ule_hist[99*TS_SZ], TS_SZ );
+				} else if (ule_where == &ule_hist[TS_SZ]) {
+					hexdump( &ule_hist[99*TS_SZ], TS_SZ );
+					hexdump( ule_hist, TS_SZ );
+				} else {
+					hexdump( ule_where - TS_SZ - TS_SZ, TS_SZ );
+					hexdump( ule_where - TS_SZ, TS_SZ );
+				}
+				ule_dump = 1;
+#endif
+
+				dev->stats.rx_errors++;
+				dev->stats.rx_crc_errors++;
+				dev_kfree_skb(priv->ule_skb);
+			} else {
+				/* CRC32 verified OK. */
+				u8 dest_addr[ETH_ALEN];
+				static const u8 bc_addr[ETH_ALEN] =
+					{ [ 0 ... ETH_ALEN-1] = 0xff };
+
+				/* CRC32 was OK. Remove it from skb. */
+				priv->ule_skb->tail -= 4;
+				priv->ule_skb->len -= 4;
+
+				if (!priv->ule_dbit) {
+					/*
+					 * The destination MAC address is the
+					 * next data in the skb.  It comes
+					 * before any extension headers.
+					 *
+					 * Check if the payload of this SNDU
+					 * should be passed up the stack.
+					 */
+					register int drop = 0;
+					if (priv->rx_mode != RX_MODE_PROMISC) {
+						if (priv->ule_skb->data[0] & 0x01) {
+							/* multicast or broadcast */
+							if (memcmp(priv->ule_skb->data, bc_addr, ETH_ALEN)) {
+								/* multicast */
+								if (priv->rx_mode == RX_MODE_MULTI) {
+									int i;
+									for(i = 0; i < priv->multi_num && memcmp(priv->ule_skb->data, priv->multi_macs[i], ETH_ALEN); i++)
+										;
+									if (i == priv->multi_num)
+										drop = 1;
+								} else if (priv->rx_mode != RX_MODE_ALL_MULTI)
+									drop = 1; /* no broadcast; */
+								/* else: all multicast mode: accept all multicast packets */
+							}
+							/* else: broadcast */
+						}
+						else if (memcmp(priv->ule_skb->data, dev->dev_addr, ETH_ALEN))
+							drop = 1;
+						/* else: destination address matches the MAC address of our receiver device */
+					}
+					/* else: promiscuous mode; pass everything up the stack */
+
+					if (drop) {
+#ifdef ULE_DEBUG
+						dprintk("Dropping SNDU: MAC destination address does not match: dest addr: "MAC_ADDR_PRINTFMT", dev addr: "MAC_ADDR_PRINTFMT"\n",
+							MAX_ADDR_PRINTFMT_ARGS(priv->ule_skb->data), MAX_ADDR_PRINTFMT_ARGS(dev->dev_addr));
+#endif
+						dev_kfree_skb(priv->ule_skb);
+						goto sndu_done;
+					}
+					else
+					{
+						skb_copy_from_linear_data(priv->ule_skb,
+							      dest_addr,
+							      ETH_ALEN);
+						skb_pull(priv->ule_skb, ETH_ALEN);
+					}
+				}
+
+				/* Handle ULE Extension Headers. */
+				if (priv->ule_sndu_type < 1536) {
+					/* There is an extension header.  Handle it accordingly. */
+					int l = handle_ule_extensions(priv);
+					if (l < 0) {
+						/* Mandatory extension header unknown or TEST SNDU.  Drop it. */
+						// printk( KERN_WARNING "Dropping SNDU, extension headers.\n" );
+						dev_kfree_skb(priv->ule_skb);
+						goto sndu_done;
+					}
+					skb_pull(priv->ule_skb, l);
+				}
+
+				/*
+				 * Construct/assure correct ethernet header.
+				 * Note: in bridged mode (priv->ule_bridged !=
+				 * 0) we already have the (original) ethernet
+				 * header at the start of the payload (after
+				 * optional dest. address and any extension
+				 * headers).
+				 */
+
+				if (!priv->ule_bridged) {
+					skb_push(priv->ule_skb, ETH_HLEN);
+					ethh = (struct ethhdr *)priv->ule_skb->data;
+					if (!priv->ule_dbit) {
+						 /* dest_addr buffer is only valid if priv->ule_dbit == 0 */
+						memcpy(ethh->h_dest, dest_addr, ETH_ALEN);
+						memset(ethh->h_source, 0, ETH_ALEN);
+					}
+					else /* zeroize source and dest */
+						memset( ethh, 0, ETH_ALEN*2 );
+
+					ethh->h_proto = htons(priv->ule_sndu_type);
+				}
+				/* else:  skb is in correct state; nothing to do. */
+				priv->ule_bridged = 0;
+
+				/* Stuff into kernel's protocol stack. */
+				priv->ule_skb->protocol = dvb_net_eth_type_trans(priv->ule_skb, dev);
+				/* If D-bit is set (i.e. destination MAC address not present),
+				 * receive the packet anyhow. */
+				/* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST)
+					priv->ule_skb->pkt_type = PACKET_HOST; */
+				dev->stats.rx_packets++;
+				dev->stats.rx_bytes += priv->ule_skb->len;
+				netif_rx(priv->ule_skb);
+			}
+			sndu_done:
+			/* Prepare for next SNDU. */
+			reset_ule(priv);
+		}
+
+		/* More data in current TS (look at the bytes following the CRC32)? */
+		if (ts_remain >= 2 && *((unsigned short *)from_where) != 0xFFFF) {
+			/* Next ULE SNDU starts right there. */
+			new_ts = 0;
+			priv->ule_skb = NULL;
+			priv->ule_sndu_type_1 = 0;
+			priv->ule_sndu_len = 0;
+			// printk(KERN_WARNING "More data in current TS: [%#x %#x %#x %#x]\n",
+			//	*(from_where + 0), *(from_where + 1),
+			//	*(from_where + 2), *(from_where + 3));
+			// printk(KERN_WARNING "ts @ %p, stopped @ %p:\n", ts, from_where + 0);
+			// hexdump(ts, 188);
+		} else {
+			new_ts = 1;
+			ts += TS_SZ;
+			priv->ts_count++;
+			if (priv->ule_skb == NULL) {
+				priv->need_pusi = 1;
+				priv->ule_sndu_type_1 = 0;
+				priv->ule_sndu_len = 0;
+			}
+		}
+	}	/* for all available TS cells */
+}
+
+static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len,
+			       const u8 *buffer2, size_t buffer2_len,
+			       struct dmx_ts_feed *feed, enum dmx_success success)
+{
+	struct net_device *dev = feed->priv;
+
+	if (buffer2)
+		printk(KERN_WARNING "buffer2 not NULL: %p.\n", buffer2);
+	if (buffer1_len > 32768)
+		printk(KERN_WARNING "length > 32k: %zu.\n", buffer1_len);
+	/* printk("TS callback: %u bytes, %u TS cells @ %p.\n",
+		  buffer1_len, buffer1_len / TS_SZ, buffer1); */
+	dvb_net_ule(dev, buffer1, buffer1_len);
+	return 0;
+}
+
+
+static void dvb_net_sec(struct net_device *dev,
+			const u8 *pkt, int pkt_len)
+{
+	u8 *eth;
+	struct sk_buff *skb;
+	struct net_device_stats *stats = &dev->stats;
+	int snap = 0;
+
+	/* note: pkt_len includes a 32bit checksum */
+	if (pkt_len < 16) {
+		printk("%s: IP/MPE packet length = %d too small.\n",
+			dev->name, pkt_len);
+		stats->rx_errors++;
+		stats->rx_length_errors++;
+		return;
+	}
+/* it seems some ISPs manage to screw up here, so we have to
+ * relax the error checks... */
+#if 0
+	if ((pkt[5] & 0xfd) != 0xc1) {
+		/* drop scrambled or broken packets */
+#else
+	if ((pkt[5] & 0x3c) != 0x00) {
+		/* drop scrambled */
+#endif
+		stats->rx_errors++;
+		stats->rx_crc_errors++;
+		return;
+	}
+	if (pkt[5] & 0x02) {
+		/* handle LLC/SNAP, see rfc-1042 */
+		if (pkt_len < 24 || memcmp(&pkt[12], "\xaa\xaa\x03\0\0\0", 6)) {
+			stats->rx_dropped++;
+			return;
+		}
+		snap = 8;
+	}
+	if (pkt[7]) {
+		/* FIXME: assemble datagram from multiple sections */
+		stats->rx_errors++;
+		stats->rx_frame_errors++;
+		return;
+	}
+
+	/* we have 14 byte ethernet header (ip header follows);
+	 * 12 byte MPE header; 4 byte checksum; + 2 byte alignment, 8 byte LLC/SNAP
+	 */
+	if (!(skb = dev_alloc_skb(pkt_len - 4 - 12 + 14 + 2 - snap))) {
+		//printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+		stats->rx_dropped++;
+		return;
+	}
+	skb_reserve(skb, 2);    /* longword align L3 header */
+	skb->dev = dev;
+
+	/* copy L3 payload */
+	eth = (u8 *) skb_put(skb, pkt_len - 12 - 4 + 14 - snap);
+	memcpy(eth + 14, pkt + 12 + snap, pkt_len - 12 - 4 - snap);
+
+	/* create ethernet header: */
+	eth[0]=pkt[0x0b];
+	eth[1]=pkt[0x0a];
+	eth[2]=pkt[0x09];
+	eth[3]=pkt[0x08];
+	eth[4]=pkt[0x04];
+	eth[5]=pkt[0x03];
+
+	eth[6]=eth[7]=eth[8]=eth[9]=eth[10]=eth[11]=0;
+
+	if (snap) {
+		eth[12] = pkt[18];
+		eth[13] = pkt[19];
+	} else {
+		/* protocol numbers are from rfc-1700 or
+		 * http://www.iana.org/assignments/ethernet-numbers
+		 */
+		if (pkt[12] >> 4 == 6) { /* version field from IP header */
+			eth[12] = 0x86;	/* IPv6 */
+			eth[13] = 0xdd;
+		} else {
+			eth[12] = 0x08;	/* IPv4 */
+			eth[13] = 0x00;
+		}
+	}
+
+	skb->protocol = dvb_net_eth_type_trans(skb, dev);
+
+	stats->rx_packets++;
+	stats->rx_bytes+=skb->len;
+	netif_rx(skb);
+}
+
+static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
+		 const u8 *buffer2, size_t buffer2_len,
+		 struct dmx_section_filter *filter,
+		 enum dmx_success success)
+{
+	struct net_device *dev = filter->priv;
+
+	/**
+	 * we rely on the DVB API definition where exactly one complete
+	 * section is delivered in buffer1
+	 */
+	dvb_net_sec (dev, buffer1, buffer1_len);
+	return 0;
+}
+
+static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	dev_kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static u8 mask_normal[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+static u8 mask_allmulti[6]={0xff, 0xff, 0xff, 0x00, 0x00, 0x00};
+static u8 mac_allmulti[6]={0x01, 0x00, 0x5e, 0x00, 0x00, 0x00};
+static u8 mask_promisc[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static int dvb_net_filter_sec_set(struct net_device *dev,
+		   struct dmx_section_filter **secfilter,
+		   u8 *mac, u8 *mac_mask)
+{
+	struct dvb_net_priv *priv = netdev_priv(dev);
+	int ret;
+
+	*secfilter=NULL;
+	ret = priv->secfeed->allocate_filter(priv->secfeed, secfilter);
+	if (ret<0) {
+		printk("%s: could not get filter\n", dev->name);
+		return ret;
+	}
+
+	(*secfilter)->priv=(void *) dev;
+
+	memset((*secfilter)->filter_value, 0x00, DMX_MAX_FILTER_SIZE);
+	memset((*secfilter)->filter_mask,  0x00, DMX_MAX_FILTER_SIZE);
+	memset((*secfilter)->filter_mode,  0xff, DMX_MAX_FILTER_SIZE);
+
+	(*secfilter)->filter_value[0]=0x3e;
+	(*secfilter)->filter_value[3]=mac[5];
+	(*secfilter)->filter_value[4]=mac[4];
+	(*secfilter)->filter_value[8]=mac[3];
+	(*secfilter)->filter_value[9]=mac[2];
+	(*secfilter)->filter_value[10]=mac[1];
+	(*secfilter)->filter_value[11]=mac[0];
+
+	(*secfilter)->filter_mask[0] = 0xff;
+	(*secfilter)->filter_mask[3] = mac_mask[5];
+	(*secfilter)->filter_mask[4] = mac_mask[4];
+	(*secfilter)->filter_mask[8] = mac_mask[3];
+	(*secfilter)->filter_mask[9] = mac_mask[2];
+	(*secfilter)->filter_mask[10] = mac_mask[1];
+	(*secfilter)->filter_mask[11]=mac_mask[0];
+
+	dprintk("%s: filter mac=%pM\n", dev->name, mac);
+	dprintk("%s: filter mask=%pM\n", dev->name, mac_mask);
+
+	return 0;
+}
+
+static int dvb_net_feed_start(struct net_device *dev)
+{
+	int ret = 0, i;
+	struct dvb_net_priv *priv = netdev_priv(dev);
+	struct dmx_demux *demux = priv->demux;
+	unsigned char *mac = (unsigned char *) dev->dev_addr;
+
+	dprintk("%s: rx_mode %i\n", __func__, priv->rx_mode);
+	mutex_lock(&priv->mutex);
+	if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0])
+		printk("%s: BUG %d\n", __func__, __LINE__);
+
+	priv->secfeed=NULL;
+	priv->secfilter=NULL;
+	priv->tsfeed = NULL;
+
+	if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
+		dprintk("%s: alloc secfeed\n", __func__);
+		ret=demux->allocate_section_feed(demux, &priv->secfeed,
+					 dvb_net_sec_callback);
+		if (ret<0) {
+			printk("%s: could not allocate section feed\n", dev->name);
+			goto error;
+		}
+
+		ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1);
+
+		if (ret<0) {
+			printk("%s: could not set section feed\n", dev->name);
+			priv->demux->release_section_feed(priv->demux, priv->secfeed);
+			priv->secfeed=NULL;
+			goto error;
+		}
+
+		if (priv->rx_mode != RX_MODE_PROMISC) {
+			dprintk("%s: set secfilter\n", __func__);
+			dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_normal);
+		}
+
+		switch (priv->rx_mode) {
+		case RX_MODE_MULTI:
+			for (i = 0; i < priv->multi_num; i++) {
+				dprintk("%s: set multi_secfilter[%d]\n", __func__, i);
+				dvb_net_filter_sec_set(dev, &priv->multi_secfilter[i],
+						       priv->multi_macs[i], mask_normal);
+			}
+			break;
+		case RX_MODE_ALL_MULTI:
+			priv->multi_num=1;
+			dprintk("%s: set multi_secfilter[0]\n", __func__);
+			dvb_net_filter_sec_set(dev, &priv->multi_secfilter[0],
+					       mac_allmulti, mask_allmulti);
+			break;
+		case RX_MODE_PROMISC:
+			priv->multi_num=0;
+			dprintk("%s: set secfilter\n", __func__);
+			dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_promisc);
+			break;
+		}
+
+		dprintk("%s: start filtering\n", __func__);
+		priv->secfeed->start_filtering(priv->secfeed);
+	} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
+		struct timespec timeout = { 0, 10000000 }; // 10 msec
+
+		/* we have payloads encapsulated in TS */
+		dprintk("%s: alloc tsfeed\n", __func__);
+		ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback);
+		if (ret < 0) {
+			printk("%s: could not allocate ts feed\n", dev->name);
+			goto error;
+		}
+
+		/* Set netdevice pointer for ts decaps callback. */
+		priv->tsfeed->priv = (void *)dev;
+		ret = priv->tsfeed->set(priv->tsfeed,
+					priv->pid, /* pid */
+					TS_PACKET, /* type */
+					DMX_TS_PES_OTHER, /* pes type */
+					32768,     /* circular buffer size */
+					timeout    /* timeout */
+					);
+
+		if (ret < 0) {
+			printk("%s: could not set ts feed\n", dev->name);
+			priv->demux->release_ts_feed(priv->demux, priv->tsfeed);
+			priv->tsfeed = NULL;
+			goto error;
+		}
+
+		dprintk("%s: start filtering\n", __func__);
+		priv->tsfeed->start_filtering(priv->tsfeed);
+	} else
+		ret = -EINVAL;
+
+error:
+	mutex_unlock(&priv->mutex);
+	return ret;
+}
+
+static int dvb_net_feed_stop(struct net_device *dev)
+{
+	struct dvb_net_priv *priv = netdev_priv(dev);
+	int i, ret = 0;
+
+	dprintk("%s\n", __func__);
+	mutex_lock(&priv->mutex);
+	if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
+		if (priv->secfeed) {
+			if (priv->secfeed->is_filtering) {
+				dprintk("%s: stop secfeed\n", __func__);
+				priv->secfeed->stop_filtering(priv->secfeed);
+			}
+
+			if (priv->secfilter) {
+				dprintk("%s: release secfilter\n", __func__);
+				priv->secfeed->release_filter(priv->secfeed,
+							      priv->secfilter);
+				priv->secfilter=NULL;
+			}
+
+			for (i=0; i<priv->multi_num; i++) {
+				if (priv->multi_secfilter[i]) {
+					dprintk("%s: release multi_filter[%d]\n",
+						__func__, i);
+					priv->secfeed->release_filter(priv->secfeed,
+								      priv->multi_secfilter[i]);
+					priv->multi_secfilter[i] = NULL;
+				}
+			}
+
+			priv->demux->release_section_feed(priv->demux, priv->secfeed);
+			priv->secfeed = NULL;
+		} else
+			printk("%s: no feed to stop\n", dev->name);
+	} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
+		if (priv->tsfeed) {
+			if (priv->tsfeed->is_filtering) {
+				dprintk("%s: stop tsfeed\n", __func__);
+				priv->tsfeed->stop_filtering(priv->tsfeed);
+			}
+			priv->demux->release_ts_feed(priv->demux, priv->tsfeed);
+			priv->tsfeed = NULL;
+		}
+		else
+			printk("%s: no ts feed to stop\n", dev->name);
+	} else
+		ret = -EINVAL;
+	mutex_unlock(&priv->mutex);
+	return ret;
+}
+
+
+static int dvb_set_mc_filter(struct net_device *dev, unsigned char *addr)
+{
+	struct dvb_net_priv *priv = netdev_priv(dev);
+
+	if (priv->multi_num == DVB_NET_MULTICAST_MAX)
+		return -ENOMEM;
+
+	memcpy(priv->multi_macs[priv->multi_num], addr, ETH_ALEN);
+
+	priv->multi_num++;
+	return 0;
+}
+
+
+static void wq_set_multicast_list (struct work_struct *work)
+{
+	struct dvb_net_priv *priv =
+		container_of(work, struct dvb_net_priv, set_multicast_list_wq);
+	struct net_device *dev = priv->net;
+
+	dvb_net_feed_stop(dev);
+	priv->rx_mode = RX_MODE_UNI;
+	netif_addr_lock_bh(dev);
+
+	if (dev->flags & IFF_PROMISC) {
+		dprintk("%s: promiscuous mode\n", dev->name);
+		priv->rx_mode = RX_MODE_PROMISC;
+	} else if ((dev->flags & IFF_ALLMULTI)) {
+		dprintk("%s: allmulti mode\n", dev->name);
+		priv->rx_mode = RX_MODE_ALL_MULTI;
+	} else if (!netdev_mc_empty(dev)) {
+		struct netdev_hw_addr *ha;
+
+		dprintk("%s: set_mc_list, %d entries\n",
+			dev->name, netdev_mc_count(dev));
+
+		priv->rx_mode = RX_MODE_MULTI;
+		priv->multi_num = 0;
+
+		netdev_for_each_mc_addr(ha, dev)
+			dvb_set_mc_filter(dev, ha->addr);
+	}
+
+	netif_addr_unlock_bh(dev);
+	dvb_net_feed_start(dev);
+}
+
+
+static void dvb_net_set_multicast_list (struct net_device *dev)
+{
+	struct dvb_net_priv *priv = netdev_priv(dev);
+	schedule_work(&priv->set_multicast_list_wq);
+}
+
+
+static void wq_restart_net_feed (struct work_struct *work)
+{
+	struct dvb_net_priv *priv =
+		container_of(work, struct dvb_net_priv, restart_net_feed_wq);
+	struct net_device *dev = priv->net;
+
+	if (netif_running(dev)) {
+		dvb_net_feed_stop(dev);
+		dvb_net_feed_start(dev);
+	}
+}
+
+
+static int dvb_net_set_mac (struct net_device *dev, void *p)
+{
+	struct dvb_net_priv *priv = netdev_priv(dev);
+	struct sockaddr *addr=p;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	if (netif_running(dev))
+		schedule_work(&priv->restart_net_feed_wq);
+
+	return 0;
+}
+
+
+static int dvb_net_open(struct net_device *dev)
+{
+	struct dvb_net_priv *priv = netdev_priv(dev);
+
+	priv->in_use++;
+	dvb_net_feed_start(dev);
+	return 0;
+}
+
+
+static int dvb_net_stop(struct net_device *dev)
+{
+	struct dvb_net_priv *priv = netdev_priv(dev);
+
+	priv->in_use--;
+	return dvb_net_feed_stop(dev);
+}
+
+static const struct header_ops dvb_header_ops = {
+	.create		= eth_header,
+	.parse		= eth_header_parse,
+	.rebuild	= eth_rebuild_header,
+};
+
+
+static const struct net_device_ops dvb_netdev_ops = {
+	.ndo_open		= dvb_net_open,
+	.ndo_stop		= dvb_net_stop,
+	.ndo_start_xmit		= dvb_net_tx,
+	.ndo_set_rx_mode	= dvb_net_set_multicast_list,
+	.ndo_set_mac_address    = dvb_net_set_mac,
+	.ndo_change_mtu		= eth_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+};
+
+static void dvb_net_setup(struct net_device *dev)
+{
+	ether_setup(dev);
+
+	dev->header_ops		= &dvb_header_ops;
+	dev->netdev_ops		= &dvb_netdev_ops;
+	dev->mtu		= 4096;
+
+	dev->flags |= IFF_NOARP;
+}
+
+static int get_if(struct dvb_net *dvbnet)
+{
+	int i;
+
+	for (i=0; i<DVB_NET_DEVICES_MAX; i++)
+		if (!dvbnet->state[i])
+			break;
+
+	if (i == DVB_NET_DEVICES_MAX)
+		return -1;
+
+	dvbnet->state[i]=1;
+	return i;
+}
+
+static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
+{
+	struct net_device *net;
+	struct dvb_net_priv *priv;
+	int result;
+	int if_num;
+
+	if (feedtype != DVB_NET_FEEDTYPE_MPE && feedtype != DVB_NET_FEEDTYPE_ULE)
+		return -EINVAL;
+	if ((if_num = get_if(dvbnet)) < 0)
+		return -EINVAL;
+
+	net = alloc_netdev(sizeof(struct dvb_net_priv), "dvb", dvb_net_setup);
+	if (!net)
+		return -ENOMEM;
+
+	if (dvbnet->dvbdev->id)
+		snprintf(net->name, IFNAMSIZ, "dvb%d%u%d",
+			 dvbnet->dvbdev->adapter->num, dvbnet->dvbdev->id, if_num);
+	else
+		/* compatibility fix to keep dvb0_0 format */
+		snprintf(net->name, IFNAMSIZ, "dvb%d_%d",
+			 dvbnet->dvbdev->adapter->num, if_num);
+
+	net->addr_len = 6;
+	memcpy(net->dev_addr, dvbnet->dvbdev->adapter->proposed_mac, 6);
+
+	dvbnet->device[if_num] = net;
+
+	priv = netdev_priv(net);
+	priv->net = net;
+	priv->demux = dvbnet->demux;
+	priv->pid = pid;
+	priv->rx_mode = RX_MODE_UNI;
+	priv->need_pusi = 1;
+	priv->tscc = 0;
+	priv->feedtype = feedtype;
+	reset_ule(priv);
+
+	INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list);
+	INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed);
+	mutex_init(&priv->mutex);
+
+	net->base_addr = pid;
+
+	if ((result = register_netdev(net)) < 0) {
+		dvbnet->device[if_num] = NULL;
+		free_netdev(net);
+		return result;
+	}
+	printk("dvb_net: created network interface %s\n", net->name);
+
+	return if_num;
+}
+
+static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)
+{
+	struct net_device *net = dvbnet->device[num];
+	struct dvb_net_priv *priv;
+
+	if (!dvbnet->state[num])
+		return -EINVAL;
+	priv = netdev_priv(net);
+	if (priv->in_use)
+		return -EBUSY;
+
+	dvb_net_stop(net);
+	flush_work_sync(&priv->set_multicast_list_wq);
+	flush_work_sync(&priv->restart_net_feed_wq);
+	printk("dvb_net: removed network interface %s\n", net->name);
+	unregister_netdev(net);
+	dvbnet->state[num]=0;
+	dvbnet->device[num] = NULL;
+	free_netdev(net);
+
+	return 0;
+}
+
+static int dvb_net_do_ioctl(struct file *file,
+		  unsigned int cmd, void *parg)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_net *dvbnet = dvbdev->priv;
+
+	if (((file->f_flags&O_ACCMODE)==O_RDONLY))
+		return -EPERM;
+
+	switch (cmd) {
+	case NET_ADD_IF:
+	{
+		struct dvb_net_if *dvbnetif = parg;
+		int result;
+
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+
+		if (!try_module_get(dvbdev->adapter->module))
+			return -EPERM;
+
+		result=dvb_net_add_if(dvbnet, dvbnetif->pid, dvbnetif->feedtype);
+		if (result<0) {
+			module_put(dvbdev->adapter->module);
+			return result;
+		}
+		dvbnetif->if_num=result;
+		break;
+	}
+	case NET_GET_IF:
+	{
+		struct net_device *netdev;
+		struct dvb_net_priv *priv_data;
+		struct dvb_net_if *dvbnetif = parg;
+
+		if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
+		    !dvbnet->state[dvbnetif->if_num])
+			return -EINVAL;
+
+		netdev = dvbnet->device[dvbnetif->if_num];
+
+		priv_data = netdev_priv(netdev);
+		dvbnetif->pid=priv_data->pid;
+		dvbnetif->feedtype=priv_data->feedtype;
+		break;
+	}
+	case NET_REMOVE_IF:
+	{
+		int ret;
+
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if ((unsigned long) parg >= DVB_NET_DEVICES_MAX)
+			return -EINVAL;
+		ret = dvb_net_remove_if(dvbnet, (unsigned long) parg);
+		if (!ret)
+			module_put(dvbdev->adapter->module);
+		return ret;
+	}
+
+	/* binary compatibility cruft */
+	case __NET_ADD_IF_OLD:
+	{
+		struct __dvb_net_if_old *dvbnetif = parg;
+		int result;
+
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+
+		if (!try_module_get(dvbdev->adapter->module))
+			return -EPERM;
+
+		result=dvb_net_add_if(dvbnet, dvbnetif->pid, DVB_NET_FEEDTYPE_MPE);
+		if (result<0) {
+			module_put(dvbdev->adapter->module);
+			return result;
+		}
+		dvbnetif->if_num=result;
+		break;
+	}
+	case __NET_GET_IF_OLD:
+	{
+		struct net_device *netdev;
+		struct dvb_net_priv *priv_data;
+		struct __dvb_net_if_old *dvbnetif = parg;
+
+		if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
+		    !dvbnet->state[dvbnetif->if_num])
+			return -EINVAL;
+
+		netdev = dvbnet->device[dvbnetif->if_num];
+
+		priv_data = netdev_priv(netdev);
+		dvbnetif->pid=priv_data->pid;
+		break;
+	}
+	default:
+		return -ENOTTY;
+	}
+	return 0;
+}
+
+static long dvb_net_ioctl(struct file *file,
+	      unsigned int cmd, unsigned long arg)
+{
+	return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl);
+}
+
+static int dvb_net_close(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_net *dvbnet = dvbdev->priv;
+
+	dvb_generic_release(inode, file);
+
+	if(dvbdev->users == 1 && dvbnet->exit == 1) {
+		fops_put(file->f_op);
+		file->f_op = NULL;
+		wake_up(&dvbdev->wait_queue);
+	}
+	return 0;
+}
+
+
+static const struct file_operations dvb_net_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = dvb_net_ioctl,
+	.open =	dvb_generic_open,
+	.release = dvb_net_close,
+	.llseek = noop_llseek,
+};
+
+static struct dvb_device dvbdev_net = {
+	.priv = NULL,
+	.users = 1,
+	.writers = 1,
+	.fops = &dvb_net_fops,
+};
+
+
+void dvb_net_release (struct dvb_net *dvbnet)
+{
+	int i;
+
+	dvbnet->exit = 1;
+	if (dvbnet->dvbdev->users < 1)
+		wait_event(dvbnet->dvbdev->wait_queue,
+				dvbnet->dvbdev->users==1);
+
+	dvb_unregister_device(dvbnet->dvbdev);
+
+	for (i=0; i<DVB_NET_DEVICES_MAX; i++) {
+		if (!dvbnet->state[i])
+			continue;
+		dvb_net_remove_if(dvbnet, i);
+	}
+}
+EXPORT_SYMBOL(dvb_net_release);
+
+
+int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
+		  struct dmx_demux *dmx)
+{
+	int i;
+
+	dvbnet->demux = dmx;
+
+	for (i=0; i<DVB_NET_DEVICES_MAX; i++)
+		dvbnet->state[i] = 0;
+
+	return dvb_register_device(adap, &dvbnet->dvbdev, &dvbdev_net,
+			     dvbnet, DVB_DEVICE_NET);
+}
+EXPORT_SYMBOL(dvb_net_init);
diff --git a/drivers/media/dvb-core/dvb_net.h b/drivers/media/dvb-core/dvb_net.h
new file mode 100644
index 0000000..1e53acd
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_net.h
@@ -0,0 +1,66 @@
+/*
+ * dvb_net.h
+ *
+ * Copyright (C) 2001 Ralph Metzler for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVB_NET_H_
+#define _DVB_NET_H_
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "dvbdev.h"
+
+#define DVB_NET_DEVICES_MAX 10
+
+#ifdef CONFIG_DVB_NET
+
+struct dvb_net {
+	struct dvb_device *dvbdev;
+	struct net_device *device[DVB_NET_DEVICES_MAX];
+	int state[DVB_NET_DEVICES_MAX];
+	unsigned int exit:1;
+	struct dmx_demux *demux;
+};
+
+void dvb_net_release(struct dvb_net *);
+int  dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *);
+
+#else
+
+struct dvb_net {
+	struct dvb_device *dvbdev;
+};
+
+static inline void dvb_net_release(struct dvb_net *dvbnet)
+{
+}
+
+static inline int dvb_net_init(struct dvb_adapter *adap,
+			       struct dvb_net *dvbnet, struct dmx_demux *dmx)
+{
+	return 0;
+}
+
+#endif /* ifdef CONFIG_DVB_NET */
+
+#endif
diff --git a/drivers/media/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb-core/dvb_ringbuffer.c
new file mode 100644
index 0000000..a5712cd
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_ringbuffer.c
@@ -0,0 +1,299 @@
+/*
+ *
+ * dvb_ringbuffer.c: ring buffer implementation for the dvb driver
+ *
+ * Copyright (C) 2003 Oliver Endriss
+ * Copyright (C) 2004 Andrew de Quincey
+ *
+ * based on code originally found in av7110.c & dvb_ci.c:
+ * Copyright (C) 1999-2003 Ralph  Metzler
+ *                       & Marcus Metzler for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+
+#include "dvb_ringbuffer.h"
+
+#define PKT_READY 0
+#define PKT_DISPOSED 1
+
+
+void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
+{
+	rbuf->pread=rbuf->pwrite=0;
+	rbuf->data=data;
+	rbuf->size=len;
+	rbuf->error=0;
+
+	init_waitqueue_head(&rbuf->queue);
+
+	spin_lock_init(&(rbuf->lock));
+}
+
+
+
+int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
+{
+	return (rbuf->pread==rbuf->pwrite);
+}
+
+
+
+ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf)
+{
+	ssize_t free;
+
+	free = rbuf->pread - rbuf->pwrite;
+	if (free <= 0)
+		free += rbuf->size;
+	return free-1;
+}
+
+
+
+ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
+{
+	ssize_t avail;
+
+	avail = rbuf->pwrite - rbuf->pread;
+	if (avail < 0)
+		avail += rbuf->size;
+	return avail;
+}
+
+
+
+void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
+{
+	rbuf->pread = rbuf->pwrite;
+	rbuf->error = 0;
+}
+EXPORT_SYMBOL(dvb_ringbuffer_flush);
+
+void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf)
+{
+	rbuf->pread = rbuf->pwrite = 0;
+	rbuf->error = 0;
+}
+
+void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&rbuf->lock, flags);
+	dvb_ringbuffer_flush(rbuf);
+	spin_unlock_irqrestore(&rbuf->lock, flags);
+
+	wake_up(&rbuf->queue);
+}
+
+ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, size_t len)
+{
+	size_t todo = len;
+	size_t split;
+
+	split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
+	if (split > 0) {
+		if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
+			return -EFAULT;
+		buf += split;
+		todo -= split;
+		rbuf->pread = 0;
+	}
+	if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
+		return -EFAULT;
+
+	rbuf->pread = (rbuf->pread + todo) % rbuf->size;
+
+	return len;
+}
+
+void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
+{
+	size_t todo = len;
+	size_t split;
+
+	split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
+	if (split > 0) {
+		memcpy(buf, rbuf->data+rbuf->pread, split);
+		buf += split;
+		todo -= split;
+		rbuf->pread = 0;
+	}
+	memcpy(buf, rbuf->data+rbuf->pread, todo);
+
+	rbuf->pread = (rbuf->pread + todo) % rbuf->size;
+}
+
+
+ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len)
+{
+	size_t todo = len;
+	size_t split;
+
+	split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
+
+	if (split > 0) {
+		memcpy(rbuf->data+rbuf->pwrite, buf, split);
+		buf += split;
+		todo -= split;
+		rbuf->pwrite = 0;
+	}
+	memcpy(rbuf->data+rbuf->pwrite, buf, todo);
+	rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
+
+	return len;
+}
+
+ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len)
+{
+	int status;
+	ssize_t oldpwrite = rbuf->pwrite;
+
+	DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8);
+	DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff);
+	DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY);
+	status = dvb_ringbuffer_write(rbuf, buf, len);
+
+	if (status < 0) rbuf->pwrite = oldpwrite;
+	return status;
+}
+
+ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
+				int offset, u8 __user *buf, size_t len)
+{
+	size_t todo;
+	size_t split;
+	size_t pktlen;
+
+	pktlen = rbuf->data[idx] << 8;
+	pktlen |= rbuf->data[(idx + 1) % rbuf->size];
+	if (offset > pktlen) return -EINVAL;
+	if ((offset + len) > pktlen) len = pktlen - offset;
+
+	idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
+	todo = len;
+	split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
+	if (split > 0) {
+		if (copy_to_user(buf, rbuf->data+idx, split))
+			return -EFAULT;
+		buf += split;
+		todo -= split;
+		idx = 0;
+	}
+	if (copy_to_user(buf, rbuf->data+idx, todo))
+		return -EFAULT;
+
+	return len;
+}
+
+ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
+				int offset, u8* buf, size_t len)
+{
+	size_t todo;
+	size_t split;
+	size_t pktlen;
+
+	pktlen = rbuf->data[idx] << 8;
+	pktlen |= rbuf->data[(idx + 1) % rbuf->size];
+	if (offset > pktlen) return -EINVAL;
+	if ((offset + len) > pktlen) len = pktlen - offset;
+
+	idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
+	todo = len;
+	split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
+	if (split > 0) {
+		memcpy(buf, rbuf->data+idx, split);
+		buf += split;
+		todo -= split;
+		idx = 0;
+	}
+	memcpy(buf, rbuf->data+idx, todo);
+	return len;
+}
+
+void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
+{
+	size_t pktlen;
+
+	rbuf->data[(idx + 2) % rbuf->size] = PKT_DISPOSED;
+
+	// clean up disposed packets
+	while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) {
+		if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) {
+			pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8;
+			pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1);
+			DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE);
+		} else {
+			// first packet is not disposed, so we stop cleaning now
+			break;
+		}
+	}
+}
+
+ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen)
+{
+	int consumed;
+	int curpktlen;
+	int curpktstatus;
+
+	if (idx == -1) {
+	       idx = rbuf->pread;
+	} else {
+		curpktlen = rbuf->data[idx] << 8;
+		curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
+		idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
+	}
+
+	consumed = (idx - rbuf->pread) % rbuf->size;
+
+	while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) {
+
+		curpktlen = rbuf->data[idx] << 8;
+		curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
+		curpktstatus = rbuf->data[(idx + 2) % rbuf->size];
+
+		if (curpktstatus == PKT_READY) {
+			*pktlen = curpktlen;
+			return idx;
+		}
+
+		consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE;
+		idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
+	}
+
+	// no packets available
+	return -1;
+}
+
+
+
+EXPORT_SYMBOL(dvb_ringbuffer_init);
+EXPORT_SYMBOL(dvb_ringbuffer_empty);
+EXPORT_SYMBOL(dvb_ringbuffer_free);
+EXPORT_SYMBOL(dvb_ringbuffer_avail);
+EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
+EXPORT_SYMBOL(dvb_ringbuffer_read_user);
+EXPORT_SYMBOL(dvb_ringbuffer_read);
+EXPORT_SYMBOL(dvb_ringbuffer_write);
diff --git a/drivers/media/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb-core/dvb_ringbuffer.h
new file mode 100644
index 0000000..41f04da
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_ringbuffer.h
@@ -0,0 +1,186 @@
+/*
+ *
+ * dvb_ringbuffer.h: ring buffer implementation for the dvb driver
+ *
+ * Copyright (C) 2003 Oliver Endriss
+ * Copyright (C) 2004 Andrew de Quincey
+ *
+ * based on code originally found in av7110.c & dvb_ci.c:
+ * Copyright (C) 1999-2003 Ralph Metzler & Marcus Metzler
+ *                         for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _DVB_RINGBUFFER_H_
+#define _DVB_RINGBUFFER_H_
+
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+struct dvb_ringbuffer {
+	u8               *data;
+	ssize_t           size;
+	ssize_t           pread;
+	ssize_t           pwrite;
+	int               error;
+
+	wait_queue_head_t queue;
+	spinlock_t        lock;
+};
+
+#define DVB_RINGBUFFER_PKTHDRSIZE 3
+
+
+/*
+** Notes:
+** ------
+** (1) For performance reasons read and write routines don't check buffer sizes
+**     and/or number of bytes free/available. This has to be done before these
+**     routines are called. For example:
+**
+**     *** write <buflen> bytes ***
+**     free = dvb_ringbuffer_free(rbuf);
+**     if (free >= buflen)
+**         count = dvb_ringbuffer_write(rbuf, buffer, buflen);
+**     else
+**         ...
+**
+**     *** read min. 1000, max. <bufsize> bytes ***
+**     avail = dvb_ringbuffer_avail(rbuf);
+**     if (avail >= 1000)
+**         count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize));
+**     else
+**         ...
+**
+** (2) If there is exactly one reader and one writer, there is no need
+**     to lock read or write operations.
+**     Two or more readers must be locked against each other.
+**     Flushing the buffer counts as a read operation.
+**     Resetting the buffer counts as a read and write operation.
+**     Two or more writers must be locked against each other.
+*/
+
+/* initialize ring buffer, lock and queue */
+extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len);
+
+/* test whether buffer is empty */
+extern int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf);
+
+/* return the number of free bytes in the buffer */
+extern ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf);
+
+/* return the number of bytes waiting in the buffer */
+extern ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf);
+
+
+/*
+** Reset the read and write pointers to zero and flush the buffer
+** This counts as a read and write operation
+*/
+extern void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf);
+
+
+/* read routines & macros */
+/* ---------------------- */
+/* flush buffer */
+extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf);
+
+/* flush buffer protected by spinlock and wake-up waiting task(s) */
+extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
+
+/* peek at byte <offs> in the buffer */
+#define DVB_RINGBUFFER_PEEK(rbuf,offs)	\
+			(rbuf)->data[((rbuf)->pread+(offs))%(rbuf)->size]
+
+/* advance read ptr by <num> bytes */
+#define DVB_RINGBUFFER_SKIP(rbuf,num)	\
+			(rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size
+
+/*
+** read <len> bytes from ring buffer into <buf>
+** <usermem> specifies whether <buf> resides in user space
+** returns number of bytes transferred or -EFAULT
+*/
+extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf,
+				   u8 __user *buf, size_t len);
+extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf,
+				   u8 *buf, size_t len);
+
+
+/* write routines & macros */
+/* ----------------------- */
+/* write single byte to ring buffer */
+#define DVB_RINGBUFFER_WRITE_BYTE(rbuf,byte)	\
+			{ (rbuf)->data[(rbuf)->pwrite]=(byte); \
+			(rbuf)->pwrite=((rbuf)->pwrite+1)%(rbuf)->size; }
+/*
+** write <len> bytes to ring buffer
+** <usermem> specifies whether <buf> resides in user space
+** returns number of bytes transferred or -EFAULT
+*/
+extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
+				    size_t len);
+
+
+/**
+ * Write a packet into the ringbuffer.
+ *
+ * <rbuf> Ringbuffer to write to.
+ * <buf> Buffer to write.
+ * <len> Length of buffer (currently limited to 65535 bytes max).
+ * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
+ */
+extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
+					size_t len);
+
+/**
+ * Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this
+ * does NOT update the read pointer in the ringbuffer. You must use
+ * dvb_ringbuffer_pkt_dispose() to mark a packet as no longer required.
+ *
+ * <rbuf> Ringbuffer concerned.
+ * <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
+ * <offset> Offset into packet to read from.
+ * <buf> Destination buffer for data.
+ * <len> Size of destination buffer.
+ * <usermem> Set to 1 if <buf> is in userspace.
+ * returns Number of bytes read, or -EFAULT.
+ */
+extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
+				       int offset, u8 __user *buf, size_t len);
+extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
+				       int offset, u8 *buf, size_t len);
+
+/**
+ * Dispose of a packet in the ring buffer.
+ *
+ * <rbuf> Ring buffer concerned.
+ * <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
+ */
+extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx);
+
+/**
+ * Get the index of the next packet in a ringbuffer.
+ *
+ * <rbuf> Ringbuffer concerned.
+ * <idx> Previous packet index, or -1 to return the first packet index.
+ * <pktlen> On success, will be updated to contain the length of the packet in bytes.
+ * returns Packet index (if >=0), or -1 if no packets available.
+ */
+extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen);
+
+
+#endif /* _DVB_RINGBUFFER_H_ */
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
new file mode 100644
index 0000000..39eab73
--- /dev/null
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -0,0 +1,507 @@
+/*
+ * dvbdev.c
+ *
+ * Copyright (C) 2000 Ralph  Metzler <ralph@convergence.de>
+ *                  & Marcus Metzler <marcus@convergence.de>
+ *                    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/mutex.h>
+#include "dvbdev.h"
+
+static DEFINE_MUTEX(dvbdev_mutex);
+static int dvbdev_debug;
+
+module_param(dvbdev_debug, int, 0644);
+MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off).");
+
+#define dprintk if (dvbdev_debug) printk
+
+static LIST_HEAD(dvb_adapter_list);
+static DEFINE_MUTEX(dvbdev_register_lock);
+
+static const char * const dnames[] = {
+	"video", "audio", "sec", "frontend", "demux", "dvr", "ca",
+	"net", "osd"
+};
+
+#ifdef CONFIG_DVB_DYNAMIC_MINORS
+#define MAX_DVB_MINORS		256
+#define DVB_MAX_IDS		MAX_DVB_MINORS
+#else
+#define DVB_MAX_IDS		4
+#define nums2minor(num,type,id)	((num << 6) | (id << 4) | type)
+#define MAX_DVB_MINORS		(DVB_MAX_ADAPTERS*64)
+#endif
+
+static struct class *dvb_class;
+
+static struct dvb_device *dvb_minors[MAX_DVB_MINORS];
+static DECLARE_RWSEM(minor_rwsem);
+
+static int dvb_device_open(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev;
+
+	mutex_lock(&dvbdev_mutex);
+	down_read(&minor_rwsem);
+	dvbdev = dvb_minors[iminor(inode)];
+
+	if (dvbdev && dvbdev->fops) {
+		int err = 0;
+		const struct file_operations *old_fops;
+
+		file->private_data = dvbdev;
+		old_fops = file->f_op;
+		file->f_op = fops_get(dvbdev->fops);
+		if (file->f_op == NULL) {
+			file->f_op = old_fops;
+			goto fail;
+		}
+		if(file->f_op->open)
+			err = file->f_op->open(inode,file);
+		if (err) {
+			fops_put(file->f_op);
+			file->f_op = fops_get(old_fops);
+		}
+		fops_put(old_fops);
+		up_read(&minor_rwsem);
+		mutex_unlock(&dvbdev_mutex);
+		return err;
+	}
+fail:
+	up_read(&minor_rwsem);
+	mutex_unlock(&dvbdev_mutex);
+	return -ENODEV;
+}
+
+
+static const struct file_operations dvb_device_fops =
+{
+	.owner =	THIS_MODULE,
+	.open =		dvb_device_open,
+	.llseek =	noop_llseek,
+};
+
+static struct cdev dvb_device_cdev;
+
+int dvb_generic_open(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev = file->private_data;
+
+	if (!dvbdev)
+		return -ENODEV;
+
+	if (!dvbdev->users)
+		return -EBUSY;
+
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+		if (!dvbdev->readers)
+			return -EBUSY;
+		dvbdev->readers--;
+	} else {
+		if (!dvbdev->writers)
+			return -EBUSY;
+		dvbdev->writers--;
+	}
+
+	dvbdev->users--;
+	return 0;
+}
+EXPORT_SYMBOL(dvb_generic_open);
+
+
+int dvb_generic_release(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev = file->private_data;
+
+	if (!dvbdev)
+		return -ENODEV;
+
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+		dvbdev->readers++;
+	} else {
+		dvbdev->writers++;
+	}
+
+	dvbdev->users++;
+	return 0;
+}
+EXPORT_SYMBOL(dvb_generic_release);
+
+
+long dvb_generic_ioctl(struct file *file,
+		       unsigned int cmd, unsigned long arg)
+{
+	struct dvb_device *dvbdev = file->private_data;
+
+	if (!dvbdev)
+		return -ENODEV;
+
+	if (!dvbdev->kernel_ioctl)
+		return -EINVAL;
+
+	return dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl);
+}
+EXPORT_SYMBOL(dvb_generic_ioctl);
+
+
+static int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
+{
+	u32 id = 0;
+
+	while (id < DVB_MAX_IDS) {
+		struct dvb_device *dev;
+		list_for_each_entry(dev, &adap->device_list, list_head)
+			if (dev->type == type && dev->id == id)
+				goto skip;
+		return id;
+skip:
+		id++;
+	}
+	return -ENFILE;
+}
+
+
+int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
+			const struct dvb_device *template, void *priv, int type)
+{
+	struct dvb_device *dvbdev;
+	struct file_operations *dvbdevfops;
+	struct device *clsdev;
+	int minor;
+	int id;
+
+	mutex_lock(&dvbdev_register_lock);
+
+	if ((id = dvbdev_get_free_id (adap, type)) < 0){
+		mutex_unlock(&dvbdev_register_lock);
+		*pdvbdev = NULL;
+		printk(KERN_ERR "%s: couldn't find free device id\n", __func__);
+		return -ENFILE;
+	}
+
+	*pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);
+
+	if (!dvbdev){
+		mutex_unlock(&dvbdev_register_lock);
+		return -ENOMEM;
+	}
+
+	dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
+
+	if (!dvbdevfops){
+		kfree (dvbdev);
+		mutex_unlock(&dvbdev_register_lock);
+		return -ENOMEM;
+	}
+
+	memcpy(dvbdev, template, sizeof(struct dvb_device));
+	dvbdev->type = type;
+	dvbdev->id = id;
+	dvbdev->adapter = adap;
+	dvbdev->priv = priv;
+	dvbdev->fops = dvbdevfops;
+	init_waitqueue_head (&dvbdev->wait_queue);
+
+	memcpy(dvbdevfops, template->fops, sizeof(struct file_operations));
+	dvbdevfops->owner = adap->module;
+
+	list_add_tail (&dvbdev->list_head, &adap->device_list);
+
+	down_write(&minor_rwsem);
+#ifdef CONFIG_DVB_DYNAMIC_MINORS
+	for (minor = 0; minor < MAX_DVB_MINORS; minor++)
+		if (dvb_minors[minor] == NULL)
+			break;
+
+	if (minor == MAX_DVB_MINORS) {
+		kfree(dvbdevfops);
+		kfree(dvbdev);
+		up_write(&minor_rwsem);
+		mutex_unlock(&dvbdev_register_lock);
+		return -EINVAL;
+	}
+#else
+	minor = nums2minor(adap->num, type, id);
+#endif
+
+	dvbdev->minor = minor;
+	dvb_minors[minor] = dvbdev;
+	up_write(&minor_rwsem);
+
+	mutex_unlock(&dvbdev_register_lock);
+
+	clsdev = device_create(dvb_class, adap->device,
+			       MKDEV(DVB_MAJOR, minor),
+			       dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
+	if (IS_ERR(clsdev)) {
+		printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
+		       __func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
+		return PTR_ERR(clsdev);
+	}
+
+	dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
+		adap->num, dnames[type], id, minor, minor);
+
+	return 0;
+}
+EXPORT_SYMBOL(dvb_register_device);
+
+
+void dvb_unregister_device(struct dvb_device *dvbdev)
+{
+	if (!dvbdev)
+		return;
+
+	down_write(&minor_rwsem);
+	dvb_minors[dvbdev->minor] = NULL;
+	up_write(&minor_rwsem);
+
+	device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
+
+	list_del (&dvbdev->list_head);
+	kfree (dvbdev->fops);
+	kfree (dvbdev);
+}
+EXPORT_SYMBOL(dvb_unregister_device);
+
+static int dvbdev_check_free_adapter_num(int num)
+{
+	struct list_head *entry;
+	list_for_each(entry, &dvb_adapter_list) {
+		struct dvb_adapter *adap;
+		adap = list_entry(entry, struct dvb_adapter, list_head);
+		if (adap->num == num)
+			return 0;
+	}
+	return 1;
+}
+
+static int dvbdev_get_free_adapter_num (void)
+{
+	int num = 0;
+
+	while (num < DVB_MAX_ADAPTERS) {
+		if (dvbdev_check_free_adapter_num(num))
+			return num;
+		num++;
+	}
+
+	return -ENFILE;
+}
+
+
+int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
+			 struct module *module, struct device *device,
+			 short *adapter_nums)
+{
+	int i, num;
+
+	mutex_lock(&dvbdev_register_lock);
+
+	for (i = 0; i < DVB_MAX_ADAPTERS; ++i) {
+		num = adapter_nums[i];
+		if (num >= 0  &&  num < DVB_MAX_ADAPTERS) {
+		/* use the one the driver asked for */
+			if (dvbdev_check_free_adapter_num(num))
+				break;
+		} else {
+			num = dvbdev_get_free_adapter_num();
+			break;
+		}
+		num = -1;
+	}
+
+	if (num < 0) {
+		mutex_unlock(&dvbdev_register_lock);
+		return -ENFILE;
+	}
+
+	memset (adap, 0, sizeof(struct dvb_adapter));
+	INIT_LIST_HEAD (&adap->device_list);
+
+	printk(KERN_INFO "DVB: registering new adapter (%s)\n", name);
+
+	adap->num = num;
+	adap->name = name;
+	adap->module = module;
+	adap->device = device;
+	adap->mfe_shared = 0;
+	adap->mfe_dvbdev = NULL;
+	mutex_init (&adap->mfe_lock);
+
+	list_add_tail (&adap->list_head, &dvb_adapter_list);
+
+	mutex_unlock(&dvbdev_register_lock);
+
+	return num;
+}
+EXPORT_SYMBOL(dvb_register_adapter);
+
+
+int dvb_unregister_adapter(struct dvb_adapter *adap)
+{
+	mutex_lock(&dvbdev_register_lock);
+	list_del (&adap->list_head);
+	mutex_unlock(&dvbdev_register_lock);
+	return 0;
+}
+EXPORT_SYMBOL(dvb_unregister_adapter);
+
+/* if the miracle happens and "generic_usercopy()" is included into
+   the kernel, then this can vanish. please don't make the mistake and
+   define this as video_usercopy(). this will introduce a dependecy
+   to the v4l "videodev.o" module, which is unnecessary for some
+   cards (ie. the budget dvb-cards don't need the v4l module...) */
+int dvb_usercopy(struct file *file,
+		     unsigned int cmd, unsigned long arg,
+		     int (*func)(struct file *file,
+		     unsigned int cmd, void *arg))
+{
+	char    sbuf[128];
+	void    *mbuf = NULL;
+	void    *parg = NULL;
+	int     err  = -EINVAL;
+
+	/*  Copy arguments into temp kernel buffer  */
+	switch (_IOC_DIR(cmd)) {
+	case _IOC_NONE:
+		/*
+		 * For this command, the pointer is actually an integer
+		 * argument.
+		 */
+		parg = (void *) arg;
+		break;
+	case _IOC_READ: /* some v4l ioctls are marked wrong ... */
+	case _IOC_WRITE:
+	case (_IOC_WRITE | _IOC_READ):
+		if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+			parg = sbuf;
+		} else {
+			/* too big to allocate from stack */
+			mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
+			if (NULL == mbuf)
+				return -ENOMEM;
+			parg = mbuf;
+		}
+
+		err = -EFAULT;
+		if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+			goto out;
+		break;
+	}
+
+	/* call driver */
+	mutex_lock(&dvbdev_mutex);
+	if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
+		err = -EINVAL;
+	mutex_unlock(&dvbdev_mutex);
+
+	if (err < 0)
+		goto out;
+
+	/*  Copy results into user buffer  */
+	switch (_IOC_DIR(cmd))
+	{
+	case _IOC_READ:
+	case (_IOC_WRITE | _IOC_READ):
+		if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+			err = -EFAULT;
+		break;
+	}
+
+out:
+	kfree(mbuf);
+	return err;
+}
+
+static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	struct dvb_device *dvbdev = dev_get_drvdata(dev);
+
+	add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num);
+	add_uevent_var(env, "DVB_DEVICE_TYPE=%s", dnames[dvbdev->type]);
+	add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id);
+	return 0;
+}
+
+static char *dvb_devnode(struct device *dev, umode_t *mode)
+{
+	struct dvb_device *dvbdev = dev_get_drvdata(dev);
+
+	return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d",
+		dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id);
+}
+
+
+static int __init init_dvbdev(void)
+{
+	int retval;
+	dev_t dev = MKDEV(DVB_MAJOR, 0);
+
+	if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
+		printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR);
+		return retval;
+	}
+
+	cdev_init(&dvb_device_cdev, &dvb_device_fops);
+	if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
+		printk(KERN_ERR "dvb-core: unable register character device\n");
+		goto error;
+	}
+
+	dvb_class = class_create(THIS_MODULE, "dvb");
+	if (IS_ERR(dvb_class)) {
+		retval = PTR_ERR(dvb_class);
+		goto error;
+	}
+	dvb_class->dev_uevent = dvb_uevent;
+	dvb_class->devnode = dvb_devnode;
+	return 0;
+
+error:
+	cdev_del(&dvb_device_cdev);
+	unregister_chrdev_region(dev, MAX_DVB_MINORS);
+	return retval;
+}
+
+
+static void __exit exit_dvbdev(void)
+{
+	class_destroy(dvb_class);
+	cdev_del(&dvb_device_cdev);
+	unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
+}
+
+subsys_initcall(init_dvbdev);
+module_exit(exit_dvbdev);
+
+MODULE_DESCRIPTION("DVB Core Driver");
+MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h
new file mode 100644
index 0000000..93a9470
--- /dev/null
+++ b/drivers/media/dvb-core/dvbdev.h
@@ -0,0 +1,146 @@
+/*
+ * dvbdev.h
+ *
+ * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
+ *                    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Lesser Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVBDEV_H_
+#define _DVBDEV_H_
+
+#include <linux/types.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+
+#define DVB_MAJOR 212
+
+#if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0
+  #define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS
+#else
+  #define DVB_MAX_ADAPTERS 8
+#endif
+
+#define DVB_UNSET (-1)
+
+#define DVB_DEVICE_VIDEO      0
+#define DVB_DEVICE_AUDIO      1
+#define DVB_DEVICE_SEC        2
+#define DVB_DEVICE_FRONTEND   3
+#define DVB_DEVICE_DEMUX      4
+#define DVB_DEVICE_DVR        5
+#define DVB_DEVICE_CA         6
+#define DVB_DEVICE_NET        7
+#define DVB_DEVICE_OSD        8
+
+#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \
+	static short adapter_nr[] = \
+		{[0 ... (DVB_MAX_ADAPTERS - 1)] = DVB_UNSET }; \
+	module_param_array(adapter_nr, short, NULL, 0444); \
+	MODULE_PARM_DESC(adapter_nr, "DVB adapter numbers")
+
+struct dvb_frontend;
+
+struct dvb_adapter {
+	int num;
+	struct list_head list_head;
+	struct list_head device_list;
+	const char *name;
+	u8 proposed_mac [6];
+	void* priv;
+
+	struct device *device;
+
+	struct module *module;
+
+	int mfe_shared;			/* indicates mutually exclusive frontends */
+	struct dvb_device *mfe_dvbdev;	/* frontend device in use */
+	struct mutex mfe_lock;		/* access lock for thread creation */
+};
+
+
+struct dvb_device {
+	struct list_head list_head;
+	const struct file_operations *fops;
+	struct dvb_adapter *adapter;
+	int type;
+	int minor;
+	u32 id;
+
+	/* in theory, 'users' can vanish now,
+	   but I don't want to change too much now... */
+	int readers;
+	int writers;
+	int users;
+
+	wait_queue_head_t	  wait_queue;
+	/* don't really need those !? -- FIXME: use video_usercopy  */
+	int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg);
+
+	void *priv;
+};
+
+
+extern int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
+				struct module *module, struct device *device,
+				short *adapter_nums);
+extern int dvb_unregister_adapter (struct dvb_adapter *adap);
+
+extern int dvb_register_device (struct dvb_adapter *adap,
+				struct dvb_device **pdvbdev,
+				const struct dvb_device *template,
+				void *priv,
+				int type);
+
+extern void dvb_unregister_device (struct dvb_device *dvbdev);
+
+extern int dvb_generic_open (struct inode *inode, struct file *file);
+extern int dvb_generic_release (struct inode *inode, struct file *file);
+extern long dvb_generic_ioctl (struct file *file,
+			      unsigned int cmd, unsigned long arg);
+
+/* we don't mess with video_usercopy() any more,
+we simply define out own dvb_usercopy(), which will hopefully become
+generic_usercopy()  someday... */
+
+extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+			    int (*func)(struct file *file, unsigned int cmd, void *arg));
+
+/** generic DVB attach function. */
+#ifdef CONFIG_MEDIA_ATTACH
+#define dvb_attach(FUNCTION, ARGS...) ({ \
+	void *__r = NULL; \
+	typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
+	if (__a) { \
+		__r = (void *) __a(ARGS); \
+		if (__r == NULL) \
+			symbol_put(FUNCTION); \
+	} else { \
+		printk(KERN_ERR "DVB: Unable to find symbol "#FUNCTION"()\n"); \
+	} \
+	__r; \
+})
+
+#else
+#define dvb_attach(FUNCTION, ARGS...) ({ \
+	FUNCTION(ARGS); \
+})
+
+#endif
+
+#endif /* #ifndef _DVBDEV_H_ */
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
new file mode 100644
index 0000000..a08c215
--- /dev/null
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -0,0 +1,756 @@
+config DVB_FE_CUSTOMISE
+	bool "Customise the frontend modules to build"
+	depends on DVB_CORE
+	depends on EXPERT
+	default y if EXPERT
+	help
+	  This allows the user to select/deselect frontend drivers for their
+	  hardware from the build.
+
+	  Use this option with care as deselecting frontends which are in fact
+	  necessary will result in DVB devices which cannot be tuned due to lack
+	  of driver support.
+
+	  If unsure say N.
+
+menu "Customise DVB Frontends"
+	visible if DVB_FE_CUSTOMISE
+
+comment "Multistandard (satellite) frontends"
+	depends on DVB_CORE
+
+config DVB_STB0899
+	tristate "STB0899 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S/S2/DSS Multistandard demodulator. Say Y when you want
+	  to support this demodulator based frontends
+
+config DVB_STB6100
+	tristate "STB6100 based tuners"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A Silicon tuner from ST used in conjunction with the STB0899
+	  demodulator. Say Y when you want to support this tuner.
+
+config DVB_STV090x
+	tristate "STV0900/STV0903(A/B) based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators.
+	  Say Y when you want to support these frontends.
+
+config DVB_STV6110x
+	tristate "STV6110/(A) based tuners"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A Silicon tuner that supports DVB-S and DVB-S2 modes
+
+comment "Multistandard (cable + terrestrial) frontends"
+	depends on DVB_CORE
+
+config DVB_DRXK
+	tristate "Micronas DRXK based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  Micronas DRX-K DVB-C/T demodulator.
+
+	  Say Y when you want to support this frontend.
+
+config DVB_TDA18271C2DD
+	tristate "NXP TDA18271C2 silicon tuner"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  NXP TDA18271 silicon tuner.
+
+	  Say Y when you want to support this tuner.
+
+comment "DVB-S (satellite) frontends"
+	depends on DVB_CORE
+
+config DVB_CX24110
+	tristate "Conexant CX24110 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_CX24123
+	tristate "Conexant CX24123 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_MT312
+	tristate "Zarlink VP310/MT312/ZL10313 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_ZL10036
+	tristate "Zarlink ZL10036 silicon tuner"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_ZL10039
+	tristate "Zarlink ZL10039 silicon tuner"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_S5H1420
+	tristate "Samsung S5H1420 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_STV0288
+	tristate "ST STV0288 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_STB6000
+	tristate "ST STB6000 silicon tuner"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	  help
+	  A DVB-S silicon tuner module. Say Y when you want to support this tuner.
+
+config DVB_STV0299
+	tristate "ST STV0299 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_STV6110
+	tristate "ST STV6110 silicon tuner"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	  help
+	  A DVB-S silicon tuner module. Say Y when you want to support this tuner.
+
+config DVB_STV0900
+	tristate "ST STV0900 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S/S2 demodulator. Say Y when you want to support this frontend.
+
+config DVB_TDA8083
+	tristate "Philips TDA8083 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_TDA10086
+	tristate "Philips TDA10086 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_TDA8261
+	tristate "Philips TDA8261 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_VES1X93
+	tristate "VLSI VES1893 or VES1993 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_TUNER_ITD1000
+	tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_TUNER_CX24113
+	tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+
+config DVB_TDA826X
+	tristate "Philips TDA826X silicon tuner"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S silicon tuner module. Say Y when you want to support this tuner.
+
+config DVB_TUA6100
+	tristate "Infineon TUA6100 PLL"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S PLL chip.
+
+config DVB_CX24116
+	tristate "Conexant CX24116 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
+
+config DVB_SI21XX
+	tristate "Silicon Labs SI21XX based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_DS3000
+	tristate "Montage Tehnology DS3000 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
+
+config DVB_MB86A16
+	tristate "Fujitsu MB86A16 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S/DSS Direct Conversion reveiver.
+	  Say Y when you want to support this frontend.
+
+config DVB_TDA10071
+	tristate "NXP TDA10071"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  Say Y when you want to support this frontend.
+
+comment "DVB-T (terrestrial) frontends"
+	depends on DVB_CORE
+
+config DVB_SP8870
+	tristate "Spase sp8870 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
+
+	  This driver needs external firmware. Please use the command
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to
+	  download/extract it, and then copy it to /usr/lib/hotplug/firmware
+	  or /lib/firmware (depending on configuration of firmware hotplug).
+
+config DVB_SP887X
+	tristate "Spase sp887x based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
+
+	  This driver needs external firmware. Please use the command
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
+	  download/extract it, and then copy it to /usr/lib/hotplug/firmware
+	  or /lib/firmware (depending on configuration of firmware hotplug).
+
+config DVB_CX22700
+	tristate "Conexant CX22700 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
+
+config DVB_CX22702
+	tristate "Conexant cx22702 demodulator (OFDM)"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
+
+config DVB_S5H1432
+	tristate "Samsung s5h1432 demodulator (OFDM)"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
+
+config DVB_DRXD
+	tristate "Micronas DRXD driver"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
+
+	  Note: this driver was based on vendor driver reference code (released
+	  under the GPL) as opposed to the existing drx397xd driver, which
+	  was written via reverse engineering.
+
+config DVB_L64781
+	tristate "LSI L64781"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
+
+config DVB_TDA1004X
+	tristate "Philips TDA10045H/TDA10046H based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
+
+	  This driver needs external firmware. Please use the commands
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
+	  download/extract them, and then copy them to /usr/lib/hotplug/firmware
+	  or /lib/firmware (depending on configuration of firmware hotplug).
+
+config DVB_NXT6000
+	tristate "NxtWave Communications NXT6000 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
+
+config DVB_MT352
+	tristate "Zarlink MT352 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
+
+config DVB_ZL10353
+	tristate "Zarlink ZL10353 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
+
+config DVB_DIB3000MB
+	tristate "DiBcom 3000M-B"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+	  to support this frontend.
+
+config DVB_DIB3000MC
+	tristate "DiBcom 3000P/M-C"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+	  to support this frontend.
+
+config DVB_DIB7000M
+	tristate "DiBcom 7000MA/MB/PA/PB/MC"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+	  to support this frontend.
+
+config DVB_DIB7000P
+	tristate "DiBcom 7000PC"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+	  to support this frontend.
+
+config DVB_DIB9000
+	tristate "DiBcom 9000"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+	  to support this frontend.
+
+config DVB_TDA10048
+	tristate "Philips TDA10048HN based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
+
+config DVB_AF9013
+	tristate "Afatech AF9013 demodulator"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  Say Y when you want to support this frontend.
+
+config DVB_EC100
+	tristate "E3C EC100"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  Say Y when you want to support this frontend.
+
+config DVB_HD29L2
+	tristate "HDIC HD29L2"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  Say Y when you want to support this frontend.
+
+config DVB_STV0367
+	tristate "ST STV0367 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T/C tuner module. Say Y when you want to support this frontend.
+
+config DVB_CXD2820R
+	tristate "Sony CXD2820R"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  Say Y when you want to support this frontend.
+
+config DVB_RTL2830
+	tristate "Realtek RTL2830 DVB-T"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  Say Y when you want to support this frontend.
+
+config DVB_RTL2832
+	tristate "Realtek RTL2832 DVB-T"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  Say Y when you want to support this frontend.
+
+comment "DVB-C (cable) frontends"
+	depends on DVB_CORE
+
+config DVB_VES1820
+	tristate "VLSI VES1820 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-C tuner module. Say Y when you want to support this frontend.
+
+config DVB_TDA10021
+	tristate "Philips TDA10021 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-C tuner module. Say Y when you want to support this frontend.
+
+config DVB_TDA10023
+	tristate "Philips TDA10023 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-C tuner module. Say Y when you want to support this frontend.
+
+config DVB_STV0297
+	tristate "ST STV0297 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-C tuner module. Say Y when you want to support this frontend.
+
+comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
+	depends on DVB_CORE
+
+config DVB_NXT200X
+	tristate "NxtWave Communications NXT2002/NXT2004 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+	  to support this frontend.
+
+	  This driver needs external firmware. Please use the commands
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" and
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
+	  download/extract them, and then copy them to /usr/lib/hotplug/firmware
+	  or /lib/firmware (depending on configuration of firmware hotplug).
+
+config DVB_OR51211
+	tristate "Oren OR51211 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
+
+	  This driver needs external firmware. Please use the command
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
+	  download it, and then copy it to /usr/lib/hotplug/firmware
+	  or /lib/firmware (depending on configuration of firmware hotplug).
+
+config DVB_OR51132
+	tristate "Oren OR51132 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+	  to support this frontend.
+
+	  This driver needs external firmware. Please use the commands
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_vsb" and/or
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_qam" to
+	  download firmwares for 8VSB and QAM64/256, respectively. Copy them to
+	  /usr/lib/hotplug/firmware or /lib/firmware (depending on
+	  configuration of firmware hotplug).
+
+config DVB_BCM3510
+	tristate "Broadcom BCM3510"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
+	  support this frontend.
+
+config DVB_LGDT330X
+	tristate "LG Electronics LGDT3302/LGDT3303 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+	  to support this frontend.
+
+config DVB_LGDT3305
+	tristate "LG Electronics LGDT3304 and LGDT3305 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+	  to support this frontend.
+
+config DVB_LG2160
+	tristate "LG Electronics LG216x based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An ATSC/MH demodulator module. Say Y when you want
+	  to support this frontend.
+
+config DVB_S5H1409
+	tristate "Samsung S5H1409 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+	  to support this frontend.
+
+config DVB_AU8522
+	depends on I2C
+	tristate
+
+config DVB_AU8522_DTV
+	tristate "Auvitek AU8522 based DTV demod"
+	depends on DVB_CORE && I2C
+	select DVB_AU8522
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
+	  you want to enable DTV demodulation support for this frontend.
+
+config DVB_AU8522_V4L
+	tristate "Auvitek AU8522 based ATV demod"
+	depends on VIDEO_V4L2 && I2C
+	select DVB_AU8522
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
+	  you want to enable ATV demodulation support for this frontend.
+
+config DVB_S5H1411
+	tristate "Samsung S5H1411 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+	  to support this frontend.
+
+comment "ISDB-T (terrestrial) frontends"
+	depends on DVB_CORE
+
+config DVB_S921
+	tristate "Sharp S921 frontend"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module.
+	  Say Y when you want to support this frontend.
+
+config DVB_DIB8000
+	tristate "DiBcom 8000MB/MC"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A driver for DiBcom's DiB8000 ISDB-T/ISDB-Tsb demodulator.
+	  Say Y when you want to support this frontend.
+
+config DVB_MB86A20S
+	tristate "Fujitsu mb86a20s"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator.
+	  Say Y when you want to support this frontend.
+
+comment "Digital terrestrial only tuners/PLL"
+	depends on DVB_CORE
+
+config DVB_PLL
+	tristate "Generic I2C PLL based tuners"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  This module drives a number of tuners based on PLL chips with a
+	  common I2C interface. Say Y when you want to support these tuners.
+
+config DVB_TUNER_DIB0070
+	tristate "DiBcom DiB0070 silicon base-band tuner"
+	depends on I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A driver for the silicon baseband tuner DiB0070 from DiBcom.
+	  This device is only used inside a SiP called together with a
+	  demodulator for now.
+
+config DVB_TUNER_DIB0090
+	tristate "DiBcom DiB0090 silicon base-band tuner"
+	depends on I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A driver for the silicon baseband tuner DiB0090 from DiBcom.
+	  This device is only used inside a SiP called together with a
+	  demodulator for now.
+
+comment "SEC control devices for DVB-S"
+	depends on DVB_CORE
+
+config DVB_LNBP21
+	tristate "LNBP21/LNBH24 SEC controllers"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An SEC control chips.
+
+config DVB_LNBP22
+	tristate "LNBP22 SEC controllers"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  LNB power supply and control voltage
+	  regulator chip with step-up converter
+	  and I2C interface.
+	  Say Y when you want to support this chip.
+
+config DVB_ISL6405
+	tristate "ISL6405 SEC controller"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An SEC control chip.
+
+config DVB_ISL6421
+	tristate "ISL6421 SEC controller"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An SEC control chip.
+
+config DVB_ISL6423
+	tristate "ISL6423 SEC controller"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A SEC controller chip from Intersil
+
+config DVB_A8293
+	tristate "Allegro A8293"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+
+config DVB_LGS8GL5
+	tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DMB-TH tuner module. Say Y when you want to support this frontend.
+
+config DVB_LGS8GXX
+	tristate "Legend Silicon LGS8913/LGS8GL5/LGS8GXX DMB-TH demodulator"
+	depends on DVB_CORE && I2C
+	select FW_LOADER
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DMB-TH tuner module. Say Y when you want to support this frontend.
+
+config DVB_ATBM8830
+	tristate "AltoBeam ATBM8830/8831 DMB-TH demodulator"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DMB-TH tuner module. Say Y when you want to support this frontend.
+
+config DVB_TDA665x
+	tristate "TDA665x tuner"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  Support for tuner modules based on Philips TDA6650/TDA6651 chips.
+	  Say Y when you want to support this chip.
+
+	  Currently supported tuners:
+	  * Panasonic ENV57H12D5 (ET-50DT)
+
+config DVB_IX2505V
+	tristate "Sharp IX2505V silicon tuner"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_IT913X_FE
+	tristate "it913x frontend and it9137 tuner"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T tuner module.
+	  Say Y when you want to support this frontend.
+
+config DVB_M88RS2000
+	tristate "M88RS2000 DVB-S demodulator and tuner"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module.
+	  Say Y when you want to support this frontend.
+
+config DVB_AF9033
+	tristate "Afatech AF9033 DVB-T demodulator"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+
+comment "Tools to develop new frontends"
+
+config DVB_DUMMY_FE
+	tristate "Dummy frontend driver"
+	default n
+endmenu
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
new file mode 100644
index 0000000..7eb73bb
--- /dev/null
+++ b/drivers/media/dvb-frontends/Makefile
@@ -0,0 +1,105 @@
+#
+# Makefile for the kernel DVB frontend device drivers.
+#
+
+ccflags-y += -I$(srctree)/drivers/media/dvb-core/
+ccflags-y += -I$(srctree)/drivers/media/tuners/
+
+stb0899-objs := stb0899_drv.o stb0899_algo.o
+stv0900-objs := stv0900_core.o stv0900_sw.o
+drxd-objs := drxd_firm.o drxd_hard.o
+cxd2820r-objs := cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o
+drxk-objs := drxk_hard.o
+
+obj-$(CONFIG_DVB_PLL) += dvb-pll.o
+obj-$(CONFIG_DVB_STV0299) += stv0299.o
+obj-$(CONFIG_DVB_STB0899) += stb0899.o
+obj-$(CONFIG_DVB_STB6100) += stb6100.o
+obj-$(CONFIG_DVB_SP8870) += sp8870.o
+obj-$(CONFIG_DVB_CX22700) += cx22700.o
+obj-$(CONFIG_DVB_S5H1432) += s5h1432.o
+obj-$(CONFIG_DVB_CX24110) += cx24110.o
+obj-$(CONFIG_DVB_TDA8083) += tda8083.o
+obj-$(CONFIG_DVB_L64781) += l64781.o
+obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o
+obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o
+obj-$(CONFIG_DVB_DIB7000M) += dib7000m.o dibx000_common.o
+obj-$(CONFIG_DVB_DIB7000P) += dib7000p.o dibx000_common.o
+obj-$(CONFIG_DVB_DIB8000) += dib8000.o dibx000_common.o
+obj-$(CONFIG_DVB_DIB9000) += dib9000.o dibx000_common.o
+obj-$(CONFIG_DVB_MT312) += mt312.o
+obj-$(CONFIG_DVB_VES1820) += ves1820.o
+obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
+obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o
+obj-$(CONFIG_DVB_SP887X) += sp887x.o
+obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
+obj-$(CONFIG_DVB_MT352) += mt352.o
+obj-$(CONFIG_DVB_ZL10036) += zl10036.o
+obj-$(CONFIG_DVB_ZL10039) += zl10039.o
+obj-$(CONFIG_DVB_ZL10353) += zl10353.o
+obj-$(CONFIG_DVB_CX22702) += cx22702.o
+obj-$(CONFIG_DVB_DRXD) += drxd.o
+obj-$(CONFIG_DVB_TDA10021) += tda10021.o
+obj-$(CONFIG_DVB_TDA10023) += tda10023.o
+obj-$(CONFIG_DVB_STV0297) += stv0297.o
+obj-$(CONFIG_DVB_NXT200X) += nxt200x.o
+obj-$(CONFIG_DVB_OR51211) += or51211.o
+obj-$(CONFIG_DVB_OR51132) += or51132.o
+obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
+obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
+obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
+obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
+obj-$(CONFIG_DVB_LG2160) += lg2160.o
+obj-$(CONFIG_DVB_CX24123) += cx24123.o
+obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
+obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
+obj-$(CONFIG_DVB_ISL6405) += isl6405.o
+obj-$(CONFIG_DVB_ISL6421) += isl6421.o
+obj-$(CONFIG_DVB_TDA10086) += tda10086.o
+obj-$(CONFIG_DVB_TDA826X) += tda826x.o
+obj-$(CONFIG_DVB_TDA8261) += tda8261.o
+obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
+obj-$(CONFIG_DVB_TUNER_DIB0090) += dib0090.o
+obj-$(CONFIG_DVB_TUA6100) += tua6100.o
+obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
+obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
+obj-$(CONFIG_DVB_AU8522) += au8522_common.o
+obj-$(CONFIG_DVB_AU8522_DTV) += au8522_dig.o
+obj-$(CONFIG_DVB_AU8522_V4L) += au8522_decoder.o
+obj-$(CONFIG_DVB_TDA10048) += tda10048.o
+obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
+obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
+obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
+obj-$(CONFIG_DVB_TDA665x) += tda665x.o
+obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o
+obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o
+obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
+obj-$(CONFIG_DVB_AF9013) += af9013.o
+obj-$(CONFIG_DVB_CX24116) += cx24116.o
+obj-$(CONFIG_DVB_SI21XX) += si21xx.o
+obj-$(CONFIG_DVB_STV0288) += stv0288.o
+obj-$(CONFIG_DVB_STB6000) += stb6000.o
+obj-$(CONFIG_DVB_S921) += s921.o
+obj-$(CONFIG_DVB_STV6110) += stv6110.o
+obj-$(CONFIG_DVB_STV0900) += stv0900.o
+obj-$(CONFIG_DVB_STV090x) += stv090x.o
+obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
+obj-$(CONFIG_DVB_ISL6423) += isl6423.o
+obj-$(CONFIG_DVB_EC100) += ec100.o
+obj-$(CONFIG_DVB_HD29L2) += hd29l2.o
+obj-$(CONFIG_DVB_DS3000) += ds3000.o
+obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
+obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
+obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
+obj-$(CONFIG_DVB_STV0367) += stv0367.o
+obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
+obj-$(CONFIG_DVB_DRXK) += drxk.o
+obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
+obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o
+obj-$(CONFIG_DVB_A8293) += a8293.o
+obj-$(CONFIG_DVB_TDA10071) += tda10071.o
+obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
+obj-$(CONFIG_DVB_RTL2832) += rtl2832.o
+obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
+obj-$(CONFIG_DVB_AF9033) += af9033.o
+
diff --git a/drivers/media/dvb-frontends/a8293.c b/drivers/media/dvb-frontends/a8293.c
new file mode 100644
index 0000000..cff44a3
--- /dev/null
+++ b/drivers/media/dvb-frontends/a8293.c
@@ -0,0 +1,167 @@
+/*
+ * Allegro A8293 SEC driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dvb_frontend.h"
+#include "a8293.h"
+
+struct a8293_priv {
+	struct i2c_adapter *i2c;
+	const struct a8293_config *cfg;
+	u8 reg[2];
+};
+
+static int a8293_i2c(struct a8293_priv *priv, u8 *val, int len, bool rd)
+{
+	int ret;
+	struct i2c_msg msg[1] = {
+		{
+			.addr = priv->cfg->i2c_addr,
+			.len = len,
+			.buf = val,
+		}
+	};
+
+	if (rd)
+		msg[0].flags = I2C_M_RD;
+	else
+		msg[0].flags = 0;
+
+	ret = i2c_transfer(priv->i2c, msg, 1);
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		dev_warn(&priv->i2c->dev, "%s: i2c failed=%d rd=%d\n",
+				KBUILD_MODNAME, ret, rd);
+		ret = -EREMOTEIO;
+	}
+
+	return ret;
+}
+
+static int a8293_wr(struct a8293_priv *priv, u8 *val, int len)
+{
+	return a8293_i2c(priv, val, len, 0);
+}
+
+static int a8293_rd(struct a8293_priv *priv, u8 *val, int len)
+{
+	return a8293_i2c(priv, val, len, 1);
+}
+
+static int a8293_set_voltage(struct dvb_frontend *fe,
+	fe_sec_voltage_t fe_sec_voltage)
+{
+	struct a8293_priv *priv = fe->sec_priv;
+	int ret;
+
+	dev_dbg(&priv->i2c->dev, "%s: fe_sec_voltage=%d\n", __func__,
+			fe_sec_voltage);
+
+	switch (fe_sec_voltage) {
+	case SEC_VOLTAGE_OFF:
+		/* ENB=0 */
+		priv->reg[0] = 0x10;
+		break;
+	case SEC_VOLTAGE_13:
+		/* VSEL0=1, VSEL1=0, VSEL2=0, VSEL3=0, ENB=1*/
+		priv->reg[0] = 0x31;
+		break;
+	case SEC_VOLTAGE_18:
+		/* VSEL0=0, VSEL1=0, VSEL2=0, VSEL3=1, ENB=1*/
+		priv->reg[0] = 0x38;
+		break;
+	default:
+		ret = -EINVAL;
+		goto err;
+	};
+
+	ret = a8293_wr(priv, &priv->reg[0], 1);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static void a8293_release_sec(struct dvb_frontend *fe)
+{
+	a8293_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+	kfree(fe->sec_priv);
+	fe->sec_priv = NULL;
+}
+
+struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c, const struct a8293_config *cfg)
+{
+	int ret;
+	struct a8293_priv *priv = NULL;
+	u8 buf[2];
+
+	/* allocate memory for the internal priv */
+	priv = kzalloc(sizeof(struct a8293_priv), GFP_KERNEL);
+	if (priv == NULL) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	/* setup the priv */
+	priv->i2c = i2c;
+	priv->cfg = cfg;
+	fe->sec_priv = priv;
+
+	/* check if the SEC is there */
+	ret = a8293_rd(priv, buf, 2);
+	if (ret)
+		goto err;
+
+	/* ENB=0 */
+	priv->reg[0] = 0x10;
+	ret = a8293_wr(priv, &priv->reg[0], 1);
+	if (ret)
+		goto err;
+
+	/* TMODE=0, TGATE=1 */
+	priv->reg[1] = 0x82;
+	ret = a8293_wr(priv, &priv->reg[1], 1);
+	if (ret)
+		goto err;
+
+	fe->ops.release_sec = a8293_release_sec;
+
+	/* override frontend ops */
+	fe->ops.set_voltage = a8293_set_voltage;
+
+	dev_info(&priv->i2c->dev, "%s: Allegro A8293 SEC attached\n",
+			KBUILD_MODNAME);
+
+	return fe;
+err:
+	dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
+	kfree(priv);
+	return NULL;
+}
+EXPORT_SYMBOL(a8293_attach);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Allegro A8293 SEC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/a8293.h b/drivers/media/dvb-frontends/a8293.h
new file mode 100644
index 0000000..ed29e55
--- /dev/null
+++ b/drivers/media/dvb-frontends/a8293.h
@@ -0,0 +1,41 @@
+/*
+ * Allegro A8293 SEC driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef A8293_H
+#define A8293_H
+
+struct a8293_config {
+	u8 i2c_addr;
+};
+
+#if defined(CONFIG_DVB_A8293) || \
+	(defined(CONFIG_DVB_A8293_MODULE) && defined(MODULE))
+extern struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c, const struct a8293_config *cfg);
+#else
+static inline struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c, const struct a8293_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* A8293_H */
diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c
new file mode 100644
index 0000000..5bc570d
--- /dev/null
+++ b/drivers/media/dvb-frontends/af9013.c
@@ -0,0 +1,1524 @@
+/*
+ * Afatech AF9013 demodulator driver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "af9013_priv.h"
+
+int af9013_debug;
+module_param_named(debug, af9013_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+struct af9013_state {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend fe;
+	struct af9013_config config;
+
+	/* tuner/demod RF and IF AGC limits used for signal strength calc */
+	u8 signal_strength_en, rf_50, rf_80, if_50, if_80;
+	u16 signal_strength;
+	u32 ber;
+	u32 ucblocks;
+	u16 snr;
+	u32 bandwidth_hz;
+	fe_status_t fe_status;
+	unsigned long set_frontend_jiffies;
+	unsigned long read_status_jiffies;
+	bool first_tune;
+	bool i2c_gate_state;
+	unsigned int statistics_step:3;
+	struct delayed_work statistics_work;
+};
+
+/* write multiple registers */
+static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg,
+	const u8 *val, int len)
+{
+	int ret;
+	u8 buf[3+len];
+	struct i2c_msg msg[1] = {
+		{
+			.addr = priv->config.i2c_addr,
+			.flags = 0,
+			.len = sizeof(buf),
+			.buf = buf,
+		}
+	};
+
+	buf[0] = (reg >> 8) & 0xff;
+	buf[1] = (reg >> 0) & 0xff;
+	buf[2] = mbox;
+	memcpy(&buf[3], val, len);
+
+	ret = i2c_transfer(priv->i2c, msg, 1);
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		warn("i2c wr failed=%d reg=%04x len=%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+/* read multiple registers */
+static int af9013_rd_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg,
+	u8 *val, int len)
+{
+	int ret;
+	u8 buf[3];
+	struct i2c_msg msg[2] = {
+		{
+			.addr = priv->config.i2c_addr,
+			.flags = 0,
+			.len = 3,
+			.buf = buf,
+		}, {
+			.addr = priv->config.i2c_addr,
+			.flags = I2C_M_RD,
+			.len = len,
+			.buf = val,
+		}
+	};
+
+	buf[0] = (reg >> 8) & 0xff;
+	buf[1] = (reg >> 0) & 0xff;
+	buf[2] = mbox;
+
+	ret = i2c_transfer(priv->i2c, msg, 2);
+	if (ret == 2) {
+		ret = 0;
+	} else {
+		warn("i2c rd failed=%d reg=%04x len=%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+/* write multiple registers */
+static int af9013_wr_regs(struct af9013_state *priv, u16 reg, const u8 *val,
+	int len)
+{
+	int ret, i;
+	u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(1 << 0);
+
+	if ((priv->config.ts_mode == AF9013_TS_USB) &&
+		((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) {
+		mbox |= ((len - 1) << 2);
+		ret = af9013_wr_regs_i2c(priv, mbox, reg, val, len);
+	} else {
+		for (i = 0; i < len; i++) {
+			ret = af9013_wr_regs_i2c(priv, mbox, reg+i, val+i, 1);
+			if (ret)
+				goto err;
+		}
+	}
+
+err:
+	return 0;
+}
+
+/* read multiple registers */
+static int af9013_rd_regs(struct af9013_state *priv, u16 reg, u8 *val, int len)
+{
+	int ret, i;
+	u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(0 << 0);
+
+	if ((priv->config.ts_mode == AF9013_TS_USB) &&
+		((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) {
+		mbox |= ((len - 1) << 2);
+		ret = af9013_rd_regs_i2c(priv, mbox, reg, val, len);
+	} else {
+		for (i = 0; i < len; i++) {
+			ret = af9013_rd_regs_i2c(priv, mbox, reg+i, val+i, 1);
+			if (ret)
+				goto err;
+		}
+	}
+
+err:
+	return 0;
+}
+
+/* write single register */
+static int af9013_wr_reg(struct af9013_state *priv, u16 reg, u8 val)
+{
+	return af9013_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+static int af9013_rd_reg(struct af9013_state *priv, u16 reg, u8 *val)
+{
+	return af9013_rd_regs(priv, reg, val, 1);
+}
+
+static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val,
+	u8 len)
+{
+	u8 mbox = (1 << 7)|(1 << 6)|((len - 1) << 2)|(1 << 1)|(1 << 0);
+	return af9013_wr_regs_i2c(state, mbox, reg, val, len);
+}
+
+static int af9013_wr_reg_bits(struct af9013_state *state, u16 reg, int pos,
+	int len, u8 val)
+{
+	int ret;
+	u8 tmp, mask;
+
+	/* no need for read if whole reg is written */
+	if (len != 8) {
+		ret = af9013_rd_reg(state, reg, &tmp);
+		if (ret)
+			return ret;
+
+		mask = (0xff >> (8 - len)) << pos;
+		val <<= pos;
+		tmp &= ~mask;
+		val |= tmp;
+	}
+
+	return af9013_wr_reg(state, reg, val);
+}
+
+static int af9013_rd_reg_bits(struct af9013_state *state, u16 reg, int pos,
+	int len, u8 *val)
+{
+	int ret;
+	u8 tmp;
+
+	ret = af9013_rd_reg(state, reg, &tmp);
+	if (ret)
+		return ret;
+
+	*val = (tmp >> pos);
+	*val &= (0xff >> (8 - len));
+
+	return 0;
+}
+
+static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval)
+{
+	int ret;
+	u8 pos;
+	u16 addr;
+
+	dbg("%s: gpio=%d gpioval=%02x", __func__, gpio, gpioval);
+
+	/*
+	 * GPIO0 & GPIO1 0xd735
+	 * GPIO2 & GPIO3 0xd736
+	 */
+
+	switch (gpio) {
+	case 0:
+	case 1:
+		addr = 0xd735;
+		break;
+	case 2:
+	case 3:
+		addr = 0xd736;
+		break;
+
+	default:
+		err("invalid gpio:%d\n", gpio);
+		ret = -EINVAL;
+		goto err;
+	};
+
+	switch (gpio) {
+	case 0:
+	case 2:
+		pos = 0;
+		break;
+	case 1:
+	case 3:
+	default:
+		pos = 4;
+		break;
+	};
+
+	ret = af9013_wr_reg_bits(state, addr, pos, 4, gpioval);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static u32 af913_div(u32 a, u32 b, u32 x)
+{
+	u32 r = 0, c = 0, i;
+
+	dbg("%s: a=%d b=%d x=%d", __func__, a, b, x);
+
+	if (a > b) {
+		c = a / b;
+		a = a - c * b;
+	}
+
+	for (i = 0; i < x; i++) {
+		if (a >= b) {
+			r += 1;
+			a -= b;
+		}
+		a <<= 1;
+		r <<= 1;
+	}
+	r = (c << (u32)x) + r;
+
+	dbg("%s: a=%d b=%d x=%d r=%x", __func__, a, b, x, r);
+	return r;
+}
+
+static int af9013_power_ctrl(struct af9013_state *state, u8 onoff)
+{
+	int ret, i;
+	u8 tmp;
+
+	dbg("%s: onoff=%d", __func__, onoff);
+
+	/* enable reset */
+	ret = af9013_wr_reg_bits(state, 0xd417, 4, 1, 1);
+	if (ret)
+		goto err;
+
+	/* start reset mechanism */
+	ret = af9013_wr_reg(state, 0xaeff, 1);
+	if (ret)
+		goto err;
+
+	/* wait reset performs */
+	for (i = 0; i < 150; i++) {
+		ret = af9013_rd_reg_bits(state, 0xd417, 1, 1, &tmp);
+		if (ret)
+			goto err;
+
+		if (tmp)
+			break; /* reset done */
+
+		usleep_range(5000, 25000);
+	}
+
+	if (!tmp)
+		return -ETIMEDOUT;
+
+	if (onoff) {
+		/* clear reset */
+		ret = af9013_wr_reg_bits(state, 0xd417, 1, 1, 0);
+		if (ret)
+			goto err;
+
+		/* disable reset */
+		ret = af9013_wr_reg_bits(state, 0xd417, 4, 1, 0);
+
+		/* power on */
+		ret = af9013_wr_reg_bits(state, 0xd73a, 3, 1, 0);
+	} else {
+		/* power off */
+		ret = af9013_wr_reg_bits(state, 0xd73a, 3, 1, 1);
+	}
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int af9013_statistics_ber_unc_start(struct dvb_frontend *fe)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret;
+
+	dbg("%s", __func__);
+
+	/* reset and start BER counter */
+	ret = af9013_wr_reg_bits(state, 0xd391, 4, 1, 1);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int af9013_statistics_ber_unc_result(struct dvb_frontend *fe)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret;
+	u8 buf[5];
+
+	dbg("%s", __func__);
+
+	/* check if error bit count is ready */
+	ret = af9013_rd_reg_bits(state, 0xd391, 4, 1, &buf[0]);
+	if (ret)
+		goto err;
+
+	if (!buf[0]) {
+		dbg("%s: not ready", __func__);
+		return 0;
+	}
+
+	ret = af9013_rd_regs(state, 0xd387, buf, 5);
+	if (ret)
+		goto err;
+
+	state->ber = (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	state->ucblocks += (buf[4] << 8) | buf[3];
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int af9013_statistics_snr_start(struct dvb_frontend *fe)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret;
+
+	dbg("%s", __func__);
+
+	/* start SNR meas */
+	ret = af9013_wr_reg_bits(state, 0xd2e1, 3, 1, 1);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int af9013_statistics_snr_result(struct dvb_frontend *fe)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret, i, len;
+	u8 buf[3], tmp;
+	u32 snr_val;
+	const struct af9013_snr *uninitialized_var(snr_lut);
+
+	dbg("%s", __func__);
+
+	/* check if SNR ready */
+	ret = af9013_rd_reg_bits(state, 0xd2e1, 3, 1, &tmp);
+	if (ret)
+		goto err;
+
+	if (!tmp) {
+		dbg("%s: not ready", __func__);
+		return 0;
+	}
+
+	/* read value */
+	ret = af9013_rd_regs(state, 0xd2e3, buf, 3);
+	if (ret)
+		goto err;
+
+	snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0];
+
+	/* read current modulation */
+	ret = af9013_rd_reg(state, 0xd3c1, &tmp);
+	if (ret)
+		goto err;
+
+	switch ((tmp >> 6) & 3) {
+	case 0:
+		len = ARRAY_SIZE(qpsk_snr_lut);
+		snr_lut = qpsk_snr_lut;
+		break;
+	case 1:
+		len = ARRAY_SIZE(qam16_snr_lut);
+		snr_lut = qam16_snr_lut;
+		break;
+	case 2:
+		len = ARRAY_SIZE(qam64_snr_lut);
+		snr_lut = qam64_snr_lut;
+		break;
+	default:
+		goto err;
+		break;
+	}
+
+	for (i = 0; i < len; i++) {
+		tmp = snr_lut[i].snr;
+
+		if (snr_val < snr_lut[i].val)
+			break;
+	}
+	state->snr = tmp * 10; /* dB/10 */
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int af9013_statistics_signal_strength(struct dvb_frontend *fe)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret = 0;
+	u8 buf[2], rf_gain, if_gain;
+	int signal_strength;
+
+	dbg("%s", __func__);
+
+	if (!state->signal_strength_en)
+		return 0;
+
+	ret = af9013_rd_regs(state, 0xd07c, buf, 2);
+	if (ret)
+		goto err;
+
+	rf_gain = buf[0];
+	if_gain = buf[1];
+
+	signal_strength = (0xffff / \
+		(9 * (state->rf_50 + state->if_50) - \
+		11 * (state->rf_80 + state->if_80))) * \
+		(10 * (rf_gain + if_gain) - \
+		11 * (state->rf_80 + state->if_80));
+	if (signal_strength < 0)
+		signal_strength = 0;
+	else if (signal_strength > 0xffff)
+		signal_strength = 0xffff;
+
+	state->signal_strength = signal_strength;
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static void af9013_statistics_work(struct work_struct *work)
+{
+	struct af9013_state *state = container_of(work,
+		struct af9013_state, statistics_work.work);
+	unsigned int next_msec;
+
+	/* update only signal strength when demod is not locked */
+	if (!(state->fe_status & FE_HAS_LOCK)) {
+		state->statistics_step = 0;
+		state->ber = 0;
+		state->snr = 0;
+	}
+
+	switch (state->statistics_step) {
+	default:
+		state->statistics_step = 0;
+	case 0:
+		af9013_statistics_signal_strength(&state->fe);
+		state->statistics_step++;
+		next_msec = 300;
+		break;
+	case 1:
+		af9013_statistics_snr_start(&state->fe);
+		state->statistics_step++;
+		next_msec = 200;
+		break;
+	case 2:
+		af9013_statistics_ber_unc_start(&state->fe);
+		state->statistics_step++;
+		next_msec = 1000;
+		break;
+	case 3:
+		af9013_statistics_snr_result(&state->fe);
+		state->statistics_step++;
+		next_msec = 400;
+		break;
+	case 4:
+		af9013_statistics_ber_unc_result(&state->fe);
+		state->statistics_step++;
+		next_msec = 100;
+		break;
+	}
+
+	schedule_delayed_work(&state->statistics_work,
+		msecs_to_jiffies(next_msec));
+}
+
+static int af9013_get_tune_settings(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *fesettings)
+{
+	fesettings->min_delay_ms = 800;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+
+	return 0;
+}
+
+static int af9013_set_frontend(struct dvb_frontend *fe)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i, sampling_freq;
+	bool auto_mode, spec_inv;
+	u8 buf[6];
+	u32 if_frequency, freq_cw;
+
+	dbg("%s: frequency=%d bandwidth_hz=%d", __func__,
+		c->frequency, c->bandwidth_hz);
+
+	/* program tuner */
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+
+	/* program CFOE coefficients */
+	if (c->bandwidth_hz != state->bandwidth_hz) {
+		for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) {
+			if (coeff_lut[i].clock == state->config.clock &&
+				coeff_lut[i].bandwidth_hz == c->bandwidth_hz) {
+				break;
+			}
+		}
+
+		ret = af9013_wr_regs(state, 0xae00, coeff_lut[i].val,
+			sizeof(coeff_lut[i].val));
+	}
+
+	/* program frequency control */
+	if (c->bandwidth_hz != state->bandwidth_hz || state->first_tune) {
+		/* get used IF frequency */
+		if (fe->ops.tuner_ops.get_if_frequency)
+			fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
+		else
+			if_frequency = state->config.if_frequency;
+
+		sampling_freq = if_frequency;
+
+		while (sampling_freq > (state->config.clock / 2))
+			sampling_freq -= state->config.clock;
+
+		if (sampling_freq < 0) {
+			sampling_freq *= -1;
+			spec_inv = state->config.spec_inv;
+		} else {
+			spec_inv = !state->config.spec_inv;
+		}
+
+		freq_cw = af913_div(sampling_freq, state->config.clock, 23);
+
+		if (spec_inv)
+			freq_cw = 0x800000 - freq_cw;
+
+		buf[0] = (freq_cw >>  0) & 0xff;
+		buf[1] = (freq_cw >>  8) & 0xff;
+		buf[2] = (freq_cw >> 16) & 0x7f;
+
+		freq_cw = 0x800000 - freq_cw;
+
+		buf[3] = (freq_cw >>  0) & 0xff;
+		buf[4] = (freq_cw >>  8) & 0xff;
+		buf[5] = (freq_cw >> 16) & 0x7f;
+
+		ret = af9013_wr_regs(state, 0xd140, buf, 3);
+		if (ret)
+			goto err;
+
+		ret = af9013_wr_regs(state, 0x9be7, buf, 6);
+		if (ret)
+			goto err;
+	}
+
+	/* clear TPS lock flag */
+	ret = af9013_wr_reg_bits(state, 0xd330, 3, 1, 1);
+	if (ret)
+		goto err;
+
+	/* clear MPEG2 lock flag */
+	ret = af9013_wr_reg_bits(state, 0xd507, 6, 1, 0);
+	if (ret)
+		goto err;
+
+	/* empty channel function */
+	ret = af9013_wr_reg_bits(state, 0x9bfe, 0, 1, 0);
+	if (ret)
+		goto err;
+
+	/* empty DVB-T channel function */
+	ret = af9013_wr_reg_bits(state, 0x9bc2, 0, 1, 0);
+	if (ret)
+		goto err;
+
+	/* transmission parameters */
+	auto_mode = false;
+	memset(buf, 0, 3);
+
+	switch (c->transmission_mode) {
+	case TRANSMISSION_MODE_AUTO:
+		auto_mode = 1;
+		break;
+	case TRANSMISSION_MODE_2K:
+		break;
+	case TRANSMISSION_MODE_8K:
+		buf[0] |= (1 << 0);
+		break;
+	default:
+		dbg("%s: invalid transmission_mode", __func__);
+		auto_mode = 1;
+	}
+
+	switch (c->guard_interval) {
+	case GUARD_INTERVAL_AUTO:
+		auto_mode = 1;
+		break;
+	case GUARD_INTERVAL_1_32:
+		break;
+	case GUARD_INTERVAL_1_16:
+		buf[0] |= (1 << 2);
+		break;
+	case GUARD_INTERVAL_1_8:
+		buf[0] |= (2 << 2);
+		break;
+	case GUARD_INTERVAL_1_4:
+		buf[0] |= (3 << 2);
+		break;
+	default:
+		dbg("%s: invalid guard_interval", __func__);
+		auto_mode = 1;
+	}
+
+	switch (c->hierarchy) {
+	case HIERARCHY_AUTO:
+		auto_mode = 1;
+		break;
+	case HIERARCHY_NONE:
+		break;
+	case HIERARCHY_1:
+		buf[0] |= (1 << 4);
+		break;
+	case HIERARCHY_2:
+		buf[0] |= (2 << 4);
+		break;
+	case HIERARCHY_4:
+		buf[0] |= (3 << 4);
+		break;
+	default:
+		dbg("%s: invalid hierarchy", __func__);
+		auto_mode = 1;
+	};
+
+	switch (c->modulation) {
+	case QAM_AUTO:
+		auto_mode = 1;
+		break;
+	case QPSK:
+		break;
+	case QAM_16:
+		buf[1] |= (1 << 6);
+		break;
+	case QAM_64:
+		buf[1] |= (2 << 6);
+		break;
+	default:
+		dbg("%s: invalid modulation", __func__);
+		auto_mode = 1;
+	}
+
+	/* Use HP. How and which case we can switch to LP? */
+	buf[1] |= (1 << 4);
+
+	switch (c->code_rate_HP) {
+	case FEC_AUTO:
+		auto_mode = 1;
+		break;
+	case FEC_1_2:
+		break;
+	case FEC_2_3:
+		buf[2] |= (1 << 0);
+		break;
+	case FEC_3_4:
+		buf[2] |= (2 << 0);
+		break;
+	case FEC_5_6:
+		buf[2] |= (3 << 0);
+		break;
+	case FEC_7_8:
+		buf[2] |= (4 << 0);
+		break;
+	default:
+		dbg("%s: invalid code_rate_HP", __func__);
+		auto_mode = 1;
+	}
+
+	switch (c->code_rate_LP) {
+	case FEC_AUTO:
+		auto_mode = 1;
+		break;
+	case FEC_1_2:
+		break;
+	case FEC_2_3:
+		buf[2] |= (1 << 3);
+		break;
+	case FEC_3_4:
+		buf[2] |= (2 << 3);
+		break;
+	case FEC_5_6:
+		buf[2] |= (3 << 3);
+		break;
+	case FEC_7_8:
+		buf[2] |= (4 << 3);
+		break;
+	case FEC_NONE:
+		break;
+	default:
+		dbg("%s: invalid code_rate_LP", __func__);
+		auto_mode = 1;
+	}
+
+	switch (c->bandwidth_hz) {
+	case 6000000:
+		break;
+	case 7000000:
+		buf[1] |= (1 << 2);
+		break;
+	case 8000000:
+		buf[1] |= (2 << 2);
+		break;
+	default:
+		dbg("%s: invalid bandwidth_hz", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	ret = af9013_wr_regs(state, 0xd3c0, buf, 3);
+	if (ret)
+		goto err;
+
+	if (auto_mode) {
+		/* clear easy mode flag */
+		ret = af9013_wr_reg(state, 0xaefd, 0);
+		if (ret)
+			goto err;
+
+		dbg("%s: auto params", __func__);
+	} else {
+		/* set easy mode flag */
+		ret = af9013_wr_reg(state, 0xaefd, 1);
+		if (ret)
+			goto err;
+
+		ret = af9013_wr_reg(state, 0xaefe, 0);
+		if (ret)
+			goto err;
+
+		dbg("%s: manual params", __func__);
+	}
+
+	/* tune */
+	ret = af9013_wr_reg(state, 0xffff, 0);
+	if (ret)
+		goto err;
+
+	state->bandwidth_hz = c->bandwidth_hz;
+	state->set_frontend_jiffies = jiffies;
+	state->first_tune = false;
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int af9013_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret;
+	u8 buf[3];
+
+	dbg("%s", __func__);
+
+	ret = af9013_rd_regs(state, 0xd3c0, buf, 3);
+	if (ret)
+		goto err;
+
+	switch ((buf[1] >> 6) & 3) {
+	case 0:
+		c->modulation = QPSK;
+		break;
+	case 1:
+		c->modulation = QAM_16;
+		break;
+	case 2:
+		c->modulation = QAM_64;
+		break;
+	}
+
+	switch ((buf[0] >> 0) & 3) {
+	case 0:
+		c->transmission_mode = TRANSMISSION_MODE_2K;
+		break;
+	case 1:
+		c->transmission_mode = TRANSMISSION_MODE_8K;
+	}
+
+	switch ((buf[0] >> 2) & 3) {
+	case 0:
+		c->guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		c->guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		c->guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		c->guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	}
+
+	switch ((buf[0] >> 4) & 7) {
+	case 0:
+		c->hierarchy = HIERARCHY_NONE;
+		break;
+	case 1:
+		c->hierarchy = HIERARCHY_1;
+		break;
+	case 2:
+		c->hierarchy = HIERARCHY_2;
+		break;
+	case 3:
+		c->hierarchy = HIERARCHY_4;
+		break;
+	}
+
+	switch ((buf[2] >> 0) & 7) {
+	case 0:
+		c->code_rate_HP = FEC_1_2;
+		break;
+	case 1:
+		c->code_rate_HP = FEC_2_3;
+		break;
+	case 2:
+		c->code_rate_HP = FEC_3_4;
+		break;
+	case 3:
+		c->code_rate_HP = FEC_5_6;
+		break;
+	case 4:
+		c->code_rate_HP = FEC_7_8;
+		break;
+	}
+
+	switch ((buf[2] >> 3) & 7) {
+	case 0:
+		c->code_rate_LP = FEC_1_2;
+		break;
+	case 1:
+		c->code_rate_LP = FEC_2_3;
+		break;
+	case 2:
+		c->code_rate_LP = FEC_3_4;
+		break;
+	case 3:
+		c->code_rate_LP = FEC_5_6;
+		break;
+	case 4:
+		c->code_rate_LP = FEC_7_8;
+		break;
+	}
+
+	switch ((buf[1] >> 2) & 3) {
+	case 0:
+		c->bandwidth_hz = 6000000;
+		break;
+	case 1:
+		c->bandwidth_hz = 7000000;
+		break;
+	case 2:
+		c->bandwidth_hz = 8000000;
+		break;
+	}
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret;
+	u8 tmp;
+
+	/*
+	 * Return status from the cache if it is younger than 2000ms with the
+	 * exception of last tune is done during 4000ms.
+	 */
+	if (time_is_after_jiffies(
+		state->read_status_jiffies + msecs_to_jiffies(2000)) &&
+		time_is_before_jiffies(
+		state->set_frontend_jiffies + msecs_to_jiffies(4000))
+	) {
+			*status = state->fe_status;
+			return 0;
+	} else {
+		*status = 0;
+	}
+
+	/* MPEG2 lock */
+	ret = af9013_rd_reg_bits(state, 0xd507, 6, 1, &tmp);
+	if (ret)
+		goto err;
+
+	if (tmp)
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+			FE_HAS_SYNC | FE_HAS_LOCK;
+
+	if (!*status) {
+		/* TPS lock */
+		ret = af9013_rd_reg_bits(state, 0xd330, 3, 1, &tmp);
+		if (ret)
+			goto err;
+
+		if (tmp)
+			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI;
+	}
+
+	state->fe_status = *status;
+	state->read_status_jiffies = jiffies;
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	*snr = state->snr;
+	return 0;
+}
+
+static int af9013_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	*strength = state->signal_strength;
+	return 0;
+}
+
+static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	*ber = state->ber;
+	return 0;
+}
+
+static int af9013_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	*ucblocks = state->ucblocks;
+	return 0;
+}
+
+static int af9013_init(struct dvb_frontend *fe)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret, i, len;
+	u8 buf[3], tmp;
+	u32 adc_cw;
+	const struct af9013_reg_bit *init;
+
+	dbg("%s", __func__);
+
+	/* power on */
+	ret = af9013_power_ctrl(state, 1);
+	if (ret)
+		goto err;
+
+	/* enable ADC */
+	ret = af9013_wr_reg(state, 0xd73a, 0xa4);
+	if (ret)
+		goto err;
+
+	/* write API version to firmware */
+	ret = af9013_wr_regs(state, 0x9bf2, state->config.api_version, 4);
+	if (ret)
+		goto err;
+
+	/* program ADC control */
+	switch (state->config.clock) {
+	case 28800000: /* 28.800 MHz */
+		tmp = 0;
+		break;
+	case 20480000: /* 20.480 MHz */
+		tmp = 1;
+		break;
+	case 28000000: /* 28.000 MHz */
+		tmp = 2;
+		break;
+	case 25000000: /* 25.000 MHz */
+		tmp = 3;
+		break;
+	default:
+		err("invalid clock");
+		return -EINVAL;
+	}
+
+	adc_cw = af913_div(state->config.clock, 1000000ul, 19);
+	buf[0] = (adc_cw >>  0) & 0xff;
+	buf[1] = (adc_cw >>  8) & 0xff;
+	buf[2] = (adc_cw >> 16) & 0xff;
+
+	ret = af9013_wr_regs(state, 0xd180, buf, 3);
+	if (ret)
+		goto err;
+
+	ret = af9013_wr_reg_bits(state, 0x9bd2, 0, 4, tmp);
+	if (ret)
+		goto err;
+
+	/* set I2C master clock */
+	ret = af9013_wr_reg(state, 0xd416, 0x14);
+	if (ret)
+		goto err;
+
+	/* set 16 embx */
+	ret = af9013_wr_reg_bits(state, 0xd700, 1, 1, 1);
+	if (ret)
+		goto err;
+
+	/* set no trigger */
+	ret = af9013_wr_reg_bits(state, 0xd700, 2, 1, 0);
+	if (ret)
+		goto err;
+
+	/* set read-update bit for constellation */
+	ret = af9013_wr_reg_bits(state, 0xd371, 1, 1, 1);
+	if (ret)
+		goto err;
+
+	/* settings for mp2if */
+	if (state->config.ts_mode == AF9013_TS_USB) {
+		/* AF9015 split PSB to 1.5k + 0.5k */
+		ret = af9013_wr_reg_bits(state, 0xd50b, 2, 1, 1);
+		if (ret)
+			goto err;
+	} else {
+		/* AF9013 change the output bit to data7 */
+		ret = af9013_wr_reg_bits(state, 0xd500, 3, 1, 1);
+		if (ret)
+			goto err;
+
+		/* AF9013 set mpeg to full speed */
+		ret = af9013_wr_reg_bits(state, 0xd502, 4, 1, 1);
+		if (ret)
+			goto err;
+	}
+
+	ret = af9013_wr_reg_bits(state, 0xd520, 4, 1, 1);
+	if (ret)
+		goto err;
+
+	/* load OFSM settings */
+	dbg("%s: load ofsm settings", __func__);
+	len = ARRAY_SIZE(ofsm_init);
+	init = ofsm_init;
+	for (i = 0; i < len; i++) {
+		ret = af9013_wr_reg_bits(state, init[i].addr, init[i].pos,
+			init[i].len, init[i].val);
+		if (ret)
+			goto err;
+	}
+
+	/* load tuner specific settings */
+	dbg("%s: load tuner specific settings", __func__);
+	switch (state->config.tuner) {
+	case AF9013_TUNER_MXL5003D:
+		len = ARRAY_SIZE(tuner_init_mxl5003d);
+		init = tuner_init_mxl5003d;
+		break;
+	case AF9013_TUNER_MXL5005D:
+	case AF9013_TUNER_MXL5005R:
+	case AF9013_TUNER_MXL5007T:
+		len = ARRAY_SIZE(tuner_init_mxl5005);
+		init = tuner_init_mxl5005;
+		break;
+	case AF9013_TUNER_ENV77H11D5:
+		len = ARRAY_SIZE(tuner_init_env77h11d5);
+		init = tuner_init_env77h11d5;
+		break;
+	case AF9013_TUNER_MT2060:
+		len = ARRAY_SIZE(tuner_init_mt2060);
+		init = tuner_init_mt2060;
+		break;
+	case AF9013_TUNER_MC44S803:
+		len = ARRAY_SIZE(tuner_init_mc44s803);
+		init = tuner_init_mc44s803;
+		break;
+	case AF9013_TUNER_QT1010:
+	case AF9013_TUNER_QT1010A:
+		len = ARRAY_SIZE(tuner_init_qt1010);
+		init = tuner_init_qt1010;
+		break;
+	case AF9013_TUNER_MT2060_2:
+		len = ARRAY_SIZE(tuner_init_mt2060_2);
+		init = tuner_init_mt2060_2;
+		break;
+	case AF9013_TUNER_TDA18271:
+	case AF9013_TUNER_TDA18218:
+		len = ARRAY_SIZE(tuner_init_tda18271);
+		init = tuner_init_tda18271;
+		break;
+	case AF9013_TUNER_UNKNOWN:
+	default:
+		len = ARRAY_SIZE(tuner_init_unknown);
+		init = tuner_init_unknown;
+		break;
+	}
+
+	for (i = 0; i < len; i++) {
+		ret = af9013_wr_reg_bits(state, init[i].addr, init[i].pos,
+			init[i].len, init[i].val);
+		if (ret)
+			goto err;
+	}
+
+	/* TS mode */
+	ret = af9013_wr_reg_bits(state, 0xd500, 1, 2, state->config.ts_mode);
+	if (ret)
+		goto err;
+
+	/* enable lock led */
+	ret = af9013_wr_reg_bits(state, 0xd730, 0, 1, 1);
+	if (ret)
+		goto err;
+
+	/* check if we support signal strength */
+	if (!state->signal_strength_en) {
+		ret = af9013_rd_reg_bits(state, 0x9bee, 0, 1,
+			&state->signal_strength_en);
+		if (ret)
+			goto err;
+	}
+
+	/* read values needed for signal strength calculation */
+	if (state->signal_strength_en && !state->rf_50) {
+		ret = af9013_rd_reg(state, 0x9bbd, &state->rf_50);
+		if (ret)
+			goto err;
+
+		ret = af9013_rd_reg(state, 0x9bd0, &state->rf_80);
+		if (ret)
+			goto err;
+
+		ret = af9013_rd_reg(state, 0x9be2, &state->if_50);
+		if (ret)
+			goto err;
+
+		ret = af9013_rd_reg(state, 0x9be4, &state->if_80);
+		if (ret)
+			goto err;
+	}
+
+	/* SNR */
+	ret = af9013_wr_reg(state, 0xd2e2, 1);
+	if (ret)
+		goto err;
+
+	/* BER / UCB */
+	buf[0] = (10000 >> 0) & 0xff;
+	buf[1] = (10000 >> 8) & 0xff;
+	ret = af9013_wr_regs(state, 0xd385, buf, 2);
+	if (ret)
+		goto err;
+
+	/* enable FEC monitor */
+	ret = af9013_wr_reg_bits(state, 0xd392, 1, 1, 1);
+	if (ret)
+		goto err;
+
+	state->first_tune = true;
+	schedule_delayed_work(&state->statistics_work, msecs_to_jiffies(400));
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int af9013_sleep(struct dvb_frontend *fe)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	int ret;
+
+	dbg("%s", __func__);
+
+	/* stop statistics polling */
+	cancel_delayed_work_sync(&state->statistics_work);
+
+	/* disable lock led */
+	ret = af9013_wr_reg_bits(state, 0xd730, 0, 1, 0);
+	if (ret)
+		goto err;
+
+	/* power off */
+	ret = af9013_power_ctrl(state, 0);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	int ret;
+	struct af9013_state *state = fe->demodulator_priv;
+
+	dbg("%s: enable=%d", __func__, enable);
+
+	/* gate already open or close */
+	if (state->i2c_gate_state == enable)
+		return 0;
+
+	if (state->config.ts_mode == AF9013_TS_USB)
+		ret = af9013_wr_reg_bits(state, 0xd417, 3, 1, enable);
+	else
+		ret = af9013_wr_reg_bits(state, 0xd607, 2, 1, enable);
+	if (ret)
+		goto err;
+
+	state->i2c_gate_state = enable;
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static void af9013_release(struct dvb_frontend *fe)
+{
+	struct af9013_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops af9013_ops;
+
+static int af9013_download_firmware(struct af9013_state *state)
+{
+	int i, len, remaining, ret;
+	const struct firmware *fw;
+	u16 checksum = 0;
+	u8 val;
+	u8 fw_params[4];
+	u8 *fw_file = AF9013_DEFAULT_FIRMWARE;
+
+	msleep(100);
+	/* check whether firmware is already running */
+	ret = af9013_rd_reg(state, 0x98be, &val);
+	if (ret)
+		goto err;
+	else
+		dbg("%s: firmware status=%02x", __func__, val);
+
+	if (val == 0x0c) /* fw is running, no need for download */
+		goto exit;
+
+	info("found a '%s' in cold state, will try to load a firmware",
+		af9013_ops.info.name);
+
+	/* request the firmware, this will block and timeout */
+	ret = request_firmware(&fw, fw_file, state->i2c->dev.parent);
+	if (ret) {
+		err("did not find the firmware file. (%s) "
+			"Please see linux/Documentation/dvb/ for more details" \
+			" on firmware-problems. (%d)",
+			fw_file, ret);
+		goto err;
+	}
+
+	info("downloading firmware from file '%s'", fw_file);
+
+	/* calc checksum */
+	for (i = 0; i < fw->size; i++)
+		checksum += fw->data[i];
+
+	fw_params[0] = checksum >> 8;
+	fw_params[1] = checksum & 0xff;
+	fw_params[2] = fw->size >> 8;
+	fw_params[3] = fw->size & 0xff;
+
+	/* write fw checksum & size */
+	ret = af9013_write_ofsm_regs(state, 0x50fc,
+		fw_params, sizeof(fw_params));
+	if (ret)
+		goto err_release;
+
+	#define FW_ADDR 0x5100 /* firmware start address */
+	#define LEN_MAX 16 /* max packet size */
+	for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) {
+		len = remaining;
+		if (len > LEN_MAX)
+			len = LEN_MAX;
+
+		ret = af9013_write_ofsm_regs(state,
+			FW_ADDR + fw->size - remaining,
+			(u8 *) &fw->data[fw->size - remaining], len);
+		if (ret) {
+			err("firmware download failed:%d", ret);
+			goto err_release;
+		}
+	}
+
+	/* request boot firmware */
+	ret = af9013_wr_reg(state, 0xe205, 1);
+	if (ret)
+		goto err_release;
+
+	for (i = 0; i < 15; i++) {
+		msleep(100);
+
+		/* check firmware status */
+		ret = af9013_rd_reg(state, 0x98be, &val);
+		if (ret)
+			goto err_release;
+
+		dbg("%s: firmware status=%02x", __func__, val);
+
+		if (val == 0x0c || val == 0x04) /* success or fail */
+			break;
+	}
+
+	if (val == 0x04) {
+		err("firmware did not run");
+		ret = -ENODEV;
+	} else if (val != 0x0c) {
+		err("firmware boot timeout");
+		ret = -ENODEV;
+	}
+
+err_release:
+	release_firmware(fw);
+err:
+exit:
+	if (!ret)
+		info("found a '%s' in warm state.", af9013_ops.info.name);
+	return ret;
+}
+
+struct dvb_frontend *af9013_attach(const struct af9013_config *config,
+	struct i2c_adapter *i2c)
+{
+	int ret;
+	struct af9013_state *state = NULL;
+	u8 buf[4], i;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct af9013_state), GFP_KERNEL);
+	if (state == NULL)
+		goto err;
+
+	/* setup the state */
+	state->i2c = i2c;
+	memcpy(&state->config, config, sizeof(struct af9013_config));
+
+	/* download firmware */
+	if (state->config.ts_mode != AF9013_TS_USB) {
+		ret = af9013_download_firmware(state);
+		if (ret)
+			goto err;
+	}
+
+	/* firmware version */
+	ret = af9013_rd_regs(state, 0x5103, buf, 4);
+	if (ret)
+		goto err;
+
+	info("firmware version %d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]);
+
+	/* set GPIOs */
+	for (i = 0; i < sizeof(state->config.gpio); i++) {
+		ret = af9013_set_gpio(state, i, state->config.gpio[i]);
+		if (ret)
+			goto err;
+	}
+
+	/* create dvb_frontend */
+	memcpy(&state->fe.ops, &af9013_ops,
+		sizeof(struct dvb_frontend_ops));
+	state->fe.demodulator_priv = state;
+
+	INIT_DELAYED_WORK(&state->statistics_work, af9013_statistics_work);
+
+	return &state->fe;
+err:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(af9013_attach);
+
+static struct dvb_frontend_ops af9013_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "Afatech AF9013",
+		.frequency_min = 174000000,
+		.frequency_max = 862000000,
+		.frequency_stepsize = 250000,
+		.frequency_tolerance = 0,
+		.caps =	FE_CAN_FEC_1_2 |
+			FE_CAN_FEC_2_3 |
+			FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 |
+			FE_CAN_FEC_7_8 |
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK |
+			FE_CAN_QAM_16 |
+			FE_CAN_QAM_64 |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_RECOVER |
+			FE_CAN_MUTE_TS
+	},
+
+	.release = af9013_release,
+
+	.init = af9013_init,
+	.sleep = af9013_sleep,
+
+	.get_tune_settings = af9013_get_tune_settings,
+	.set_frontend = af9013_set_frontend,
+	.get_frontend = af9013_get_frontend,
+
+	.read_status = af9013_read_status,
+	.read_snr = af9013_read_snr,
+	.read_signal_strength = af9013_read_signal_strength,
+	.read_ber = af9013_read_ber,
+	.read_ucblocks = af9013_read_ucblocks,
+
+	.i2c_gate_ctrl = af9013_i2c_gate_ctrl,
+};
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Afatech AF9013 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/af9013.h b/drivers/media/dvb-frontends/af9013.h
new file mode 100644
index 0000000..b973fc5
--- /dev/null
+++ b/drivers/media/dvb-frontends/af9013.h
@@ -0,0 +1,118 @@
+/*
+ * Afatech AF9013 demodulator driver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef AF9013_H
+#define AF9013_H
+
+#include <linux/dvb/frontend.h>
+
+/* AF9013/5 GPIOs (mostly guessed)
+   demod#1-gpio#0 - set demod#2 i2c-addr for dual devices
+   demod#1-gpio#1 - xtal setting (?)
+   demod#1-gpio#3 - tuner#1
+   demod#2-gpio#0 - tuner#2
+   demod#2-gpio#1 - xtal setting (?)
+*/
+
+struct af9013_config {
+	/*
+	 * I2C address
+	 */
+	u8 i2c_addr;
+
+	/*
+	 * clock
+	 * 20480000, 25000000, 28000000, 28800000
+	 */
+	u32 clock;
+
+	/*
+	 * tuner
+	 */
+#define AF9013_TUNER_MXL5003D      3 /* MaxLinear */
+#define AF9013_TUNER_MXL5005D     13 /* MaxLinear */
+#define AF9013_TUNER_MXL5005R     30 /* MaxLinear */
+#define AF9013_TUNER_ENV77H11D5  129 /* Panasonic */
+#define AF9013_TUNER_MT2060      130 /* Microtune */
+#define AF9013_TUNER_MC44S803    133 /* Freescale */
+#define AF9013_TUNER_QT1010      134 /* Quantek */
+#define AF9013_TUNER_UNKNOWN     140 /* for can tuners ? */
+#define AF9013_TUNER_MT2060_2    147 /* Microtune */
+#define AF9013_TUNER_TDA18271    156 /* NXP */
+#define AF9013_TUNER_QT1010A     162 /* Quantek */
+#define AF9013_TUNER_MXL5007T    177 /* MaxLinear */
+#define AF9013_TUNER_TDA18218    179 /* NXP */
+	u8 tuner;
+
+	/*
+	 * IF frequency
+	 */
+	u32 if_frequency;
+
+	/*
+	 * TS settings
+	 */
+#define AF9013_TS_USB       0
+#define AF9013_TS_PARALLEL  1
+#define AF9013_TS_SERIAL    2
+	u8 ts_mode:2;
+
+	/*
+	 * input spectrum inversion
+	 */
+	bool spec_inv;
+
+	/*
+	 * firmware API version
+	 */
+	u8 api_version[4];
+
+	/*
+	 * GPIOs
+	 */
+#define AF9013_GPIO_ON (1 << 0)
+#define AF9013_GPIO_EN (1 << 1)
+#define AF9013_GPIO_O  (1 << 2)
+#define AF9013_GPIO_I  (1 << 3)
+#define AF9013_GPIO_LO (AF9013_GPIO_ON|AF9013_GPIO_EN)
+#define AF9013_GPIO_HI (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O)
+#define AF9013_GPIO_TUNER_ON  (AF9013_GPIO_ON|AF9013_GPIO_EN)
+#define AF9013_GPIO_TUNER_OFF (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O)
+	u8 gpio[4];
+};
+
+#if defined(CONFIG_DVB_AF9013) || \
+	(defined(CONFIG_DVB_AF9013_MODULE) && defined(MODULE))
+extern struct dvb_frontend *af9013_attach(const struct af9013_config *config,
+	struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *af9013_attach(
+const struct af9013_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_AF9013 */
+
+#endif /* AF9013_H */
diff --git a/drivers/media/dvb-frontends/af9013_priv.h b/drivers/media/dvb-frontends/af9013_priv.h
new file mode 100644
index 0000000..fa848af
--- /dev/null
+++ b/drivers/media/dvb-frontends/af9013_priv.h
@@ -0,0 +1,922 @@
+/*
+ * Afatech AF9013 demodulator driver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef AF9013_PRIV_H
+#define AF9013_PRIV_H
+
+#include "dvb_frontend.h"
+#include "af9013.h"
+#include <linux/firmware.h>
+
+#define LOG_PREFIX "af9013"
+
+#undef dbg
+#define dbg(f, arg...) \
+	if (af9013_debug) \
+		printk(KERN_INFO   LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+#define AF9013_DEFAULT_FIRMWARE     "dvb-fe-af9013.fw"
+
+struct af9013_reg_bit {
+	u16 addr;
+	u8  pos:4;
+	u8  len:4;
+	u8  val;
+};
+
+struct af9013_snr {
+	u32 val;
+	u8 snr;
+};
+
+struct af9013_coeff {
+	u32 clock;
+	u32 bandwidth_hz;
+	u8 val[24];
+};
+
+/* pre-calculated coeff lookup table */
+static const struct af9013_coeff coeff_lut[] = {
+	/* 28.800 MHz */
+	{ 28800000, 8000000, { 0x02, 0x8a, 0x28, 0xa3, 0x05, 0x14,
+		0x51, 0x11, 0x00, 0xa2, 0x8f, 0x3d, 0x00, 0xa2, 0x8a,
+		0x29, 0x00, 0xa2, 0x85, 0x14, 0x01, 0x45, 0x14, 0x14 } },
+	{ 28800000, 7000000, { 0x02, 0x38, 0xe3, 0x8e, 0x04, 0x71,
+		0xc7, 0x07, 0x00, 0x8e, 0x3d, 0x55, 0x00, 0x8e, 0x38,
+		0xe4, 0x00, 0x8e, 0x34, 0x72, 0x01, 0x1c, 0x71, 0x32 } },
+	{ 28800000, 6000000, { 0x01, 0xe7, 0x9e, 0x7a, 0x03, 0xcf,
+		0x3c, 0x3d, 0x00, 0x79, 0xeb, 0x6e, 0x00, 0x79, 0xe7,
+		0x9e, 0x00, 0x79, 0xe3, 0xcf, 0x00, 0xf3, 0xcf, 0x0f } },
+	/* 20.480 MHz */
+	{ 20480000, 8000000, { 0x03, 0x92, 0x49, 0x26, 0x07, 0x24,
+		0x92, 0x13, 0x00, 0xe4, 0x99, 0x6e, 0x00, 0xe4, 0x92,
+		0x49, 0x00, 0xe4, 0x8b, 0x25, 0x01, 0xc9, 0x24, 0x25 } },
+	{ 20480000, 7000000, { 0x03, 0x20, 0x00, 0x01, 0x06, 0x40,
+		0x00, 0x00, 0x00, 0xc8, 0x06, 0x40, 0x00, 0xc8, 0x00,
+		0x00, 0x00, 0xc7, 0xf9, 0xc0, 0x01, 0x90, 0x00, 0x00 } },
+	{ 20480000, 6000000, { 0x02, 0xad, 0xb6, 0xdc, 0x05, 0x5b,
+		0x6d, 0x2e, 0x00, 0xab, 0x73, 0x13, 0x00, 0xab, 0x6d,
+		0xb7, 0x00, 0xab, 0x68, 0x5c, 0x01, 0x56, 0xdb, 0x1c } },
+	/* 28.000 MHz */
+	{ 28000000, 8000000, { 0x02, 0x9c, 0xbc, 0x15, 0x05, 0x39,
+		0x78, 0x0a, 0x00, 0xa7, 0x34, 0x3f, 0x00, 0xa7, 0x2f,
+		0x05, 0x00, 0xa7, 0x29, 0xcc, 0x01, 0x4e, 0x5e, 0x03 } },
+	{ 28000000, 7000000, { 0x02, 0x49, 0x24, 0x92, 0x04, 0x92,
+		0x49, 0x09, 0x00, 0x92, 0x4d, 0xb7, 0x00, 0x92, 0x49,
+		0x25, 0x00, 0x92, 0x44, 0x92, 0x01, 0x24, 0x92, 0x12 } },
+	{ 28000000, 6000000, { 0x01, 0xf5, 0x8d, 0x10, 0x03, 0xeb,
+		0x1a, 0x08, 0x00, 0x7d, 0x67, 0x2f, 0x00, 0x7d, 0x63,
+		0x44, 0x00, 0x7d, 0x5f, 0x59, 0x00, 0xfa, 0xc6, 0x22 } },
+	/* 25.000 MHz */
+	{ 25000000, 8000000, { 0x02, 0xec, 0xfb, 0x9d, 0x05, 0xd9,
+		0xf7, 0x0e, 0x00, 0xbb, 0x44, 0xc1, 0x00, 0xbb, 0x3e,
+		0xe7, 0x00, 0xbb, 0x39, 0x0d, 0x01, 0x76, 0x7d, 0x34 } },
+	{ 25000000, 7000000, { 0x02, 0x8f, 0x5c, 0x29, 0x05, 0x1e,
+		0xb8, 0x14, 0x00, 0xa3, 0xdc, 0x29, 0x00, 0xa3, 0xd7,
+		0x0a, 0x00, 0xa3, 0xd1, 0xec, 0x01, 0x47, 0xae, 0x05 } },
+	{ 25000000, 6000000, { 0x02, 0x31, 0xbc, 0xb5, 0x04, 0x63,
+		0x79, 0x1b, 0x00, 0x8c, 0x73, 0x91, 0x00, 0x8c, 0x6f,
+		0x2d, 0x00, 0x8c, 0x6a, 0xca, 0x01, 0x18, 0xde, 0x17 } },
+};
+
+/* QPSK SNR lookup table */
+static const struct af9013_snr qpsk_snr_lut[] = {
+	{ 0x000000,  0 },
+	{ 0x0b4771,  0 },
+	{ 0x0c1aed,  1 },
+	{ 0x0d0d27,  2 },
+	{ 0x0e4d19,  3 },
+	{ 0x0e5da8,  4 },
+	{ 0x107097,  5 },
+	{ 0x116975,  6 },
+	{ 0x1252d9,  7 },
+	{ 0x131fa4,  8 },
+	{ 0x13d5e1,  9 },
+	{ 0x148e53, 10 },
+	{ 0x15358b, 11 },
+	{ 0x15dd29, 12 },
+	{ 0x168112, 13 },
+	{ 0x170b61, 14 },
+	{ 0xffffff, 15 },
+};
+
+/* QAM16 SNR lookup table */
+static const struct af9013_snr qam16_snr_lut[] = {
+	{ 0x000000,  0 },
+	{ 0x05eb62,  5 },
+	{ 0x05fecf,  6 },
+	{ 0x060b80,  7 },
+	{ 0x062501,  8 },
+	{ 0x064865,  9 },
+	{ 0x069604, 10 },
+	{ 0x06f356, 11 },
+	{ 0x07706a, 12 },
+	{ 0x0804d3, 13 },
+	{ 0x089d1a, 14 },
+	{ 0x093e3d, 15 },
+	{ 0x09e35d, 16 },
+	{ 0x0a7c3c, 17 },
+	{ 0x0afaf8, 18 },
+	{ 0x0b719d, 19 },
+	{ 0xffffff, 20 },
+};
+
+/* QAM64 SNR lookup table */
+static const struct af9013_snr qam64_snr_lut[] = {
+	{ 0x000000,  0 },
+	{ 0x03109b, 12 },
+	{ 0x0310d4, 13 },
+	{ 0x031920, 14 },
+	{ 0x0322d0, 15 },
+	{ 0x0339fc, 16 },
+	{ 0x0364a1, 17 },
+	{ 0x038bcc, 18 },
+	{ 0x03c7d3, 19 },
+	{ 0x0408cc, 20 },
+	{ 0x043bed, 21 },
+	{ 0x048061, 22 },
+	{ 0x04be95, 23 },
+	{ 0x04fa7d, 24 },
+	{ 0x052405, 25 },
+	{ 0x05570d, 26 },
+	{ 0xffffff, 27 },
+};
+
+static const struct af9013_reg_bit ofsm_init[] = {
+	{ 0xd73a, 0, 8, 0xa1 },
+	{ 0xd73b, 0, 8, 0x1f },
+	{ 0xd73c, 4, 4, 0x0a },
+	{ 0xd732, 3, 1, 0x00 },
+	{ 0xd731, 4, 2, 0x03 },
+	{ 0xd73d, 7, 1, 0x01 },
+	{ 0xd740, 0, 1, 0x00 },
+	{ 0xd740, 1, 1, 0x00 },
+	{ 0xd740, 2, 1, 0x00 },
+	{ 0xd740, 3, 1, 0x01 },
+	{ 0xd3c1, 4, 1, 0x01 },
+	{ 0x9124, 0, 8, 0x58 },
+	{ 0x9125, 0, 2, 0x02 },
+	{ 0xd3a2, 0, 8, 0x00 },
+	{ 0xd3a3, 0, 8, 0x04 },
+	{ 0xd305, 0, 8, 0x32 },
+	{ 0xd306, 0, 8, 0x10 },
+	{ 0xd304, 0, 8, 0x04 },
+	{ 0x9112, 0, 1, 0x01 },
+	{ 0x911d, 0, 1, 0x01 },
+	{ 0x911a, 0, 1, 0x01 },
+	{ 0x911b, 0, 1, 0x01 },
+	{ 0x9bce, 0, 4, 0x02 },
+	{ 0x9116, 0, 1, 0x01 },
+	{ 0x9122, 0, 8, 0xd0 },
+	{ 0xd2e0, 0, 8, 0xd0 },
+	{ 0xd2e9, 0, 4, 0x0d },
+	{ 0xd38c, 0, 8, 0xfc },
+	{ 0xd38d, 0, 8, 0x00 },
+	{ 0xd38e, 0, 8, 0x7e },
+	{ 0xd38f, 0, 8, 0x00 },
+	{ 0xd390, 0, 8, 0x2f },
+	{ 0xd145, 4, 1, 0x01 },
+	{ 0xd1a9, 4, 1, 0x01 },
+	{ 0xd158, 5, 3, 0x01 },
+	{ 0xd159, 0, 6, 0x06 },
+	{ 0xd167, 0, 8, 0x00 },
+	{ 0xd168, 0, 4, 0x07 },
+	{ 0xd1c3, 5, 3, 0x00 },
+	{ 0xd1c4, 0, 6, 0x00 },
+	{ 0xd1c5, 0, 7, 0x10 },
+	{ 0xd1c6, 0, 3, 0x02 },
+	{ 0xd080, 2, 5, 0x03 },
+	{ 0xd081, 4, 4, 0x09 },
+	{ 0xd098, 4, 4, 0x0f },
+	{ 0xd098, 0, 4, 0x03 },
+	{ 0xdbc0, 4, 1, 0x01 },
+	{ 0xdbc7, 0, 8, 0x08 },
+	{ 0xdbc8, 4, 4, 0x00 },
+	{ 0xdbc9, 0, 5, 0x01 },
+	{ 0xd280, 0, 8, 0xe0 },
+	{ 0xd281, 0, 8, 0xff },
+	{ 0xd282, 0, 8, 0xff },
+	{ 0xd283, 0, 8, 0xc3 },
+	{ 0xd284, 0, 8, 0xff },
+	{ 0xd285, 0, 4, 0x01 },
+	{ 0xd0f0, 0, 7, 0x1a },
+	{ 0xd0f1, 4, 1, 0x01 },
+	{ 0xd0f2, 0, 8, 0x0c },
+	{ 0xd101, 5, 3, 0x06 },
+	{ 0xd103, 0, 4, 0x08 },
+	{ 0xd0f8, 0, 7, 0x20 },
+	{ 0xd111, 5, 1, 0x00 },
+	{ 0xd111, 6, 1, 0x00 },
+	{ 0x910b, 0, 8, 0x0a },
+	{ 0x9115, 0, 8, 0x02 },
+	{ 0x910c, 0, 8, 0x02 },
+	{ 0x910d, 0, 8, 0x08 },
+	{ 0x910e, 0, 8, 0x0a },
+	{ 0x9bf6, 0, 8, 0x06 },
+	{ 0x9bf8, 0, 8, 0x02 },
+	{ 0x9bf7, 0, 8, 0x05 },
+	{ 0x9bf9, 0, 8, 0x0f },
+	{ 0x9bfc, 0, 8, 0x13 },
+	{ 0x9bd3, 0, 8, 0xff },
+	{ 0x9bbe, 0, 1, 0x01 },
+	{ 0x9bcc, 0, 1, 0x01 },
+};
+
+/* Panasonic ENV77H11D5 tuner init
+   AF9013_TUNER_ENV77H11D5 = 129 */
+static const struct af9013_reg_bit tuner_init_env77h11d5[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x03 },
+	{ 0x9bbe, 0, 8, 0x01 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0x9bda, 0, 8, 0x00 },
+	{ 0x9be3, 0, 8, 0x00 },
+	{ 0xd015, 0, 8, 0x50 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x46 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0xd008, 0, 8, 0xdf },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x44 },
+	{ 0xd007, 0, 2, 0x01 },
+	{ 0xd00c, 0, 8, 0xeb },
+	{ 0xd00d, 0, 2, 0x02 },
+	{ 0xd00a, 0, 8, 0xf4 },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bba, 0, 8, 0xf9 },
+	{ 0x9bc3, 0, 8, 0xdf },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0xeb },
+	{ 0x9bc6, 0, 8, 0x02 },
+	{ 0x9bc9, 0, 8, 0x52 },
+	{ 0xd011, 0, 8, 0x3c },
+	{ 0xd012, 0, 2, 0x01 },
+	{ 0xd013, 0, 8, 0xf7 },
+	{ 0xd014, 0, 2, 0x02 },
+	{ 0xd040, 0, 8, 0x0b },
+	{ 0xd041, 0, 2, 0x02 },
+	{ 0xd042, 0, 8, 0x4d },
+	{ 0xd043, 0, 2, 0x00 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 1, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x50 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+};
+
+/* Microtune MT2060 tuner init
+   AF9013_TUNER_MT2060     = 130 */
+static const struct af9013_reg_bit tuner_init_mt2060[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x07 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0x9bda, 0, 8, 0x00 },
+	{ 0x9be3, 0, 8, 0x00 },
+	{ 0x9bbe, 0, 1, 0x00 },
+	{ 0x9bcc, 0, 1, 0x00 },
+	{ 0x9bb9, 0, 8, 0x75 },
+	{ 0x9bcd, 0, 8, 0x24 },
+	{ 0x9bff, 0, 8, 0x30 },
+	{ 0xd015, 0, 8, 0x46 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x46 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0xd008, 0, 8, 0x0f },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x32 },
+	{ 0xd007, 0, 2, 0x01 },
+	{ 0xd00c, 0, 8, 0x36 },
+	{ 0xd00d, 0, 2, 0x03 },
+	{ 0xd00a, 0, 8, 0x35 },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bc7, 0, 8, 0x07 },
+	{ 0x9bc8, 0, 8, 0x90 },
+	{ 0x9bc3, 0, 8, 0x0f },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0x36 },
+	{ 0x9bc6, 0, 8, 0x03 },
+	{ 0x9bba, 0, 8, 0xc9 },
+	{ 0x9bc9, 0, 8, 0x79 },
+	{ 0xd011, 0, 8, 0x10 },
+	{ 0xd012, 0, 2, 0x01 },
+	{ 0xd013, 0, 8, 0x45 },
+	{ 0xd014, 0, 2, 0x03 },
+	{ 0xd040, 0, 8, 0x98 },
+	{ 0xd041, 0, 2, 0x00 },
+	{ 0xd042, 0, 8, 0xcf },
+	{ 0xd043, 0, 2, 0x03 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 1, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x50 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+	{ 0x9bd0, 0, 8, 0xcc },
+	{ 0x9be4, 0, 8, 0xa0 },
+	{ 0x9bbd, 0, 8, 0x8e },
+	{ 0x9be2, 0, 8, 0x4d },
+	{ 0x9bee, 0, 1, 0x01 },
+};
+
+/* Microtune MT2060 tuner init
+   AF9013_TUNER_MT2060_2   = 147 */
+static const struct af9013_reg_bit tuner_init_mt2060_2[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x06 },
+	{ 0x9bbe, 0, 8, 0x01 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0xd015, 0, 8, 0x46 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x46 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0xd008, 0, 8, 0x0f },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x32 },
+	{ 0xd007, 0, 2, 0x01 },
+	{ 0xd00c, 0, 8, 0x36 },
+	{ 0xd00d, 0, 2, 0x03 },
+	{ 0xd00a, 0, 8, 0x35 },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bc7, 0, 8, 0x07 },
+	{ 0x9bc8, 0, 8, 0x90 },
+	{ 0x9bc3, 0, 8, 0x0f },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0x36 },
+	{ 0x9bc6, 0, 8, 0x03 },
+	{ 0x9bba, 0, 8, 0xc9 },
+	{ 0x9bc9, 0, 8, 0x79 },
+	{ 0xd011, 0, 8, 0x10 },
+	{ 0xd012, 0, 2, 0x01 },
+	{ 0xd013, 0, 8, 0x45 },
+	{ 0xd014, 0, 2, 0x03 },
+	{ 0xd040, 0, 8, 0x98 },
+	{ 0xd041, 0, 2, 0x00 },
+	{ 0xd042, 0, 8, 0xcf },
+	{ 0xd043, 0, 2, 0x03 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 8, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x96 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0xd045, 7, 1, 0x00 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+};
+
+/* MaxLinear MXL5003 tuner init
+   AF9013_TUNER_MXL5003D   =   3 */
+static const struct af9013_reg_bit tuner_init_mxl5003d[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x09 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0x9bda, 0, 8, 0x00 },
+	{ 0x9be3, 0, 8, 0x00 },
+	{ 0x9bfc, 0, 8, 0x0f },
+	{ 0x9bf6, 0, 8, 0x01 },
+	{ 0x9bbe, 0, 1, 0x01 },
+	{ 0xd015, 0, 8, 0x33 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x40 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0xd008, 0, 8, 0x0f },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x6c },
+	{ 0xd007, 0, 2, 0x00 },
+	{ 0xd00c, 0, 8, 0x3d },
+	{ 0xd00d, 0, 2, 0x00 },
+	{ 0xd00a, 0, 8, 0x45 },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bc7, 0, 8, 0x07 },
+	{ 0x9bc8, 0, 8, 0x52 },
+	{ 0x9bc3, 0, 8, 0x0f },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0x3d },
+	{ 0x9bc6, 0, 8, 0x00 },
+	{ 0x9bba, 0, 8, 0xa2 },
+	{ 0x9bc9, 0, 8, 0xa0 },
+	{ 0xd011, 0, 8, 0x56 },
+	{ 0xd012, 0, 2, 0x00 },
+	{ 0xd013, 0, 8, 0x50 },
+	{ 0xd014, 0, 2, 0x00 },
+	{ 0xd040, 0, 8, 0x56 },
+	{ 0xd041, 0, 2, 0x00 },
+	{ 0xd042, 0, 8, 0x50 },
+	{ 0xd043, 0, 2, 0x00 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 8, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x50 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+};
+
+/* MaxLinear MXL5005S & MXL5007T tuner init
+   AF9013_TUNER_MXL5005D   =  13
+   AF9013_TUNER_MXL5005R   =  30
+   AF9013_TUNER_MXL5007T   = 177 */
+static const struct af9013_reg_bit tuner_init_mxl5005[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x07 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0x9bda, 0, 8, 0x01 },
+	{ 0x9be3, 0, 8, 0x01 },
+	{ 0x9bbe, 0, 1, 0x01 },
+	{ 0x9bcc, 0, 1, 0x01 },
+	{ 0x9bb9, 0, 8, 0x00 },
+	{ 0x9bcd, 0, 8, 0x28 },
+	{ 0x9bff, 0, 8, 0x24 },
+	{ 0xd015, 0, 8, 0x40 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x40 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0xd008, 0, 8, 0x0f },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x73 },
+	{ 0xd007, 0, 2, 0x01 },
+	{ 0xd00c, 0, 8, 0xfa },
+	{ 0xd00d, 0, 2, 0x01 },
+	{ 0xd00a, 0, 8, 0xff },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bc7, 0, 8, 0x23 },
+	{ 0x9bc8, 0, 8, 0x55 },
+	{ 0x9bc3, 0, 8, 0x01 },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0xfa },
+	{ 0x9bc6, 0, 8, 0x01 },
+	{ 0x9bba, 0, 8, 0xff },
+	{ 0x9bc9, 0, 8, 0xff },
+	{ 0x9bd3, 0, 8, 0x95 },
+	{ 0xd011, 0, 8, 0x70 },
+	{ 0xd012, 0, 2, 0x01 },
+	{ 0xd013, 0, 8, 0xfb },
+	{ 0xd014, 0, 2, 0x01 },
+	{ 0xd040, 0, 8, 0x70 },
+	{ 0xd041, 0, 2, 0x01 },
+	{ 0xd042, 0, 8, 0xfb },
+	{ 0xd043, 0, 2, 0x01 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 1, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x50 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+	{ 0x9bd0, 0, 8, 0x93 },
+	{ 0x9be4, 0, 8, 0xfe },
+	{ 0x9bbd, 0, 8, 0x63 },
+	{ 0x9be2, 0, 8, 0xfe },
+	{ 0x9bee, 0, 1, 0x01 },
+};
+
+/* Quantek QT1010 tuner init
+   AF9013_TUNER_QT1010     = 134
+   AF9013_TUNER_QT1010A    = 162 */
+static const struct af9013_reg_bit tuner_init_qt1010[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x09 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0x9bda, 0, 8, 0x01 },
+	{ 0x9be3, 0, 8, 0x01 },
+	{ 0xd015, 0, 8, 0x46 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x46 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0x9bbe, 0, 1, 0x01 },
+	{ 0x9bcc, 0, 1, 0x01 },
+	{ 0x9bb9, 0, 8, 0x00 },
+	{ 0x9bcd, 0, 8, 0x28 },
+	{ 0x9bff, 0, 8, 0x20 },
+	{ 0xd008, 0, 8, 0x0f },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x99 },
+	{ 0xd007, 0, 2, 0x01 },
+	{ 0xd00c, 0, 8, 0x0f },
+	{ 0xd00d, 0, 2, 0x02 },
+	{ 0xd00a, 0, 8, 0x50 },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bc7, 0, 8, 0x00 },
+	{ 0x9bc8, 0, 8, 0x00 },
+	{ 0x9bc3, 0, 8, 0x0f },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0x0f },
+	{ 0x9bc6, 0, 8, 0x02 },
+	{ 0x9bba, 0, 8, 0xc5 },
+	{ 0x9bc9, 0, 8, 0xff },
+	{ 0xd011, 0, 8, 0x58 },
+	{ 0xd012, 0, 2, 0x02 },
+	{ 0xd013, 0, 8, 0x89 },
+	{ 0xd014, 0, 2, 0x01 },
+	{ 0xd040, 0, 8, 0x58 },
+	{ 0xd041, 0, 2, 0x02 },
+	{ 0xd042, 0, 8, 0x89 },
+	{ 0xd043, 0, 2, 0x01 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 1, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x50 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+	{ 0x9bd0, 0, 8, 0xcd },
+	{ 0x9be4, 0, 8, 0xbb },
+	{ 0x9bbd, 0, 8, 0x93 },
+	{ 0x9be2, 0, 8, 0x80 },
+	{ 0x9bee, 0, 1, 0x01 },
+};
+
+/* Freescale MC44S803 tuner init
+   AF9013_TUNER_MC44S803   = 133 */
+static const struct af9013_reg_bit tuner_init_mc44s803[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x06 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0x9bda, 0, 8, 0x00 },
+	{ 0x9be3, 0, 8, 0x00 },
+	{ 0x9bf6, 0, 8, 0x01 },
+	{ 0x9bf8, 0, 8, 0x02 },
+	{ 0x9bf9, 0, 8, 0x02 },
+	{ 0x9bfc, 0, 8, 0x1f },
+	{ 0x9bbe, 0, 1, 0x01 },
+	{ 0x9bcc, 0, 1, 0x01 },
+	{ 0x9bb9, 0, 8, 0x00 },
+	{ 0x9bcd, 0, 8, 0x24 },
+	{ 0x9bff, 0, 8, 0x24 },
+	{ 0xd015, 0, 8, 0x46 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x46 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0xd008, 0, 8, 0x01 },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x7b },
+	{ 0xd007, 0, 2, 0x00 },
+	{ 0xd00c, 0, 8, 0x7c },
+	{ 0xd00d, 0, 2, 0x02 },
+	{ 0xd00a, 0, 8, 0xfe },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bc7, 0, 8, 0x08 },
+	{ 0x9bc8, 0, 8, 0x9a },
+	{ 0x9bc3, 0, 8, 0x01 },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0x7c },
+	{ 0x9bc6, 0, 8, 0x02 },
+	{ 0x9bba, 0, 8, 0xfc },
+	{ 0x9bc9, 0, 8, 0xaa },
+	{ 0xd011, 0, 8, 0x6b },
+	{ 0xd012, 0, 2, 0x00 },
+	{ 0xd013, 0, 8, 0x88 },
+	{ 0xd014, 0, 2, 0x02 },
+	{ 0xd040, 0, 8, 0x6b },
+	{ 0xd041, 0, 2, 0x00 },
+	{ 0xd042, 0, 8, 0x7c },
+	{ 0xd043, 0, 2, 0x02 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 1, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x50 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+	{ 0x9bd0, 0, 8, 0x9e },
+	{ 0x9be4, 0, 8, 0xff },
+	{ 0x9bbd, 0, 8, 0x9e },
+	{ 0x9be2, 0, 8, 0x25 },
+	{ 0x9bee, 0, 1, 0x01 },
+	{ 0xd73b, 3, 1, 0x00 },
+};
+
+/* unknown, probably for tin can tuner, tuner init
+   AF9013_TUNER_UNKNOWN   = 140 */
+static const struct af9013_reg_bit tuner_init_unknown[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x02 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0x9bda, 0, 8, 0x01 },
+	{ 0x9be3, 0, 8, 0x01 },
+	{ 0xd1a0, 1, 1, 0x00 },
+	{ 0x9bbe, 0, 1, 0x01 },
+	{ 0x9bcc, 0, 1, 0x01 },
+	{ 0x9bb9, 0, 8, 0x00 },
+	{ 0x9bcd, 0, 8, 0x18 },
+	{ 0x9bff, 0, 8, 0x2c },
+	{ 0xd015, 0, 8, 0x46 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x46 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0xd008, 0, 8, 0xdf },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x44 },
+	{ 0xd007, 0, 2, 0x01 },
+	{ 0xd00c, 0, 8, 0x00 },
+	{ 0xd00d, 0, 2, 0x02 },
+	{ 0xd00a, 0, 8, 0xf6 },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bba, 0, 8, 0xf9 },
+	{ 0x9bc8, 0, 8, 0xaa },
+	{ 0x9bc3, 0, 8, 0xdf },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0x00 },
+	{ 0x9bc6, 0, 8, 0x02 },
+	{ 0x9bc9, 0, 8, 0xf0 },
+	{ 0xd011, 0, 8, 0x3c },
+	{ 0xd012, 0, 2, 0x01 },
+	{ 0xd013, 0, 8, 0xf7 },
+	{ 0xd014, 0, 2, 0x02 },
+	{ 0xd040, 0, 8, 0x0b },
+	{ 0xd041, 0, 2, 0x02 },
+	{ 0xd042, 0, 8, 0x4d },
+	{ 0xd043, 0, 2, 0x00 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 1, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x50 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+};
+
+/* NXP TDA18271 & TDA18218 tuner init
+   AF9013_TUNER_TDA18271   = 156
+   AF9013_TUNER_TDA18218   = 179 */
+static const struct af9013_reg_bit tuner_init_tda18271[] = {
+	{ 0x9bd5, 0, 8, 0x01 },
+	{ 0x9bd6, 0, 8, 0x04 },
+	{ 0xd1a0, 1, 1, 0x01 },
+	{ 0xd000, 0, 1, 0x01 },
+	{ 0xd000, 1, 1, 0x00 },
+	{ 0xd001, 1, 1, 0x01 },
+	{ 0xd001, 0, 1, 0x00 },
+	{ 0xd001, 5, 1, 0x00 },
+	{ 0xd002, 0, 5, 0x19 },
+	{ 0xd003, 0, 5, 0x1a },
+	{ 0xd004, 0, 5, 0x19 },
+	{ 0xd005, 0, 5, 0x1a },
+	{ 0xd00e, 0, 5, 0x10 },
+	{ 0xd00f, 0, 3, 0x04 },
+	{ 0xd00f, 3, 3, 0x05 },
+	{ 0xd010, 0, 3, 0x04 },
+	{ 0xd010, 3, 3, 0x05 },
+	{ 0xd016, 4, 4, 0x03 },
+	{ 0xd01f, 0, 6, 0x0a },
+	{ 0xd020, 0, 6, 0x0a },
+	{ 0x9bda, 0, 8, 0x01 },
+	{ 0x9be3, 0, 8, 0x01 },
+	{ 0xd1a0, 1, 1, 0x00 },
+	{ 0x9bbe, 0, 1, 0x01 },
+	{ 0x9bcc, 0, 1, 0x01 },
+	{ 0x9bb9, 0, 8, 0x00 },
+	{ 0x9bcd, 0, 8, 0x18 },
+	{ 0x9bff, 0, 8, 0x2c },
+	{ 0xd015, 0, 8, 0x46 },
+	{ 0xd016, 0, 1, 0x00 },
+	{ 0xd044, 0, 8, 0x46 },
+	{ 0xd045, 0, 1, 0x00 },
+	{ 0xd008, 0, 8, 0xdf },
+	{ 0xd009, 0, 2, 0x02 },
+	{ 0xd006, 0, 8, 0x44 },
+	{ 0xd007, 0, 2, 0x01 },
+	{ 0xd00c, 0, 8, 0x00 },
+	{ 0xd00d, 0, 2, 0x02 },
+	{ 0xd00a, 0, 8, 0xf6 },
+	{ 0xd00b, 0, 2, 0x01 },
+	{ 0x9bba, 0, 8, 0xf9 },
+	{ 0x9bc8, 0, 8, 0xaa },
+	{ 0x9bc3, 0, 8, 0xdf },
+	{ 0x9bc4, 0, 8, 0x02 },
+	{ 0x9bc5, 0, 8, 0x00 },
+	{ 0x9bc6, 0, 8, 0x02 },
+	{ 0x9bc9, 0, 8, 0xf0 },
+	{ 0xd011, 0, 8, 0x3c },
+	{ 0xd012, 0, 2, 0x01 },
+	{ 0xd013, 0, 8, 0xf7 },
+	{ 0xd014, 0, 2, 0x02 },
+	{ 0xd040, 0, 8, 0x0b },
+	{ 0xd041, 0, 2, 0x02 },
+	{ 0xd042, 0, 8, 0x4d },
+	{ 0xd043, 0, 2, 0x00 },
+	{ 0xd045, 1, 1, 0x00 },
+	{ 0x9bcf, 0, 1, 0x01 },
+	{ 0xd045, 2, 1, 0x01 },
+	{ 0xd04f, 0, 8, 0x9a },
+	{ 0xd050, 0, 1, 0x01 },
+	{ 0xd051, 0, 8, 0x5a },
+	{ 0xd052, 0, 1, 0x01 },
+	{ 0xd053, 0, 8, 0x50 },
+	{ 0xd054, 0, 8, 0x46 },
+	{ 0x9bd7, 0, 8, 0x0a },
+	{ 0x9bd8, 0, 8, 0x14 },
+	{ 0x9bd9, 0, 8, 0x08 },
+	{ 0x9bd0, 0, 8, 0xa8 },
+	{ 0x9be4, 0, 8, 0x7f },
+	{ 0x9bbd, 0, 8, 0xa8 },
+	{ 0x9be2, 0, 8, 0x20 },
+	{ 0x9bee, 0, 1, 0x01 },
+};
+
+#endif /* AF9013_PRIV_H */
diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c
new file mode 100644
index 0000000..a389982
--- /dev/null
+++ b/drivers/media/dvb-frontends/af9033.c
@@ -0,0 +1,980 @@
+/*
+ * Afatech AF9033 demodulator driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "af9033_priv.h"
+
+struct af9033_state {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend fe;
+	struct af9033_config cfg;
+
+	u32 bandwidth_hz;
+	bool ts_mode_parallel;
+	bool ts_mode_serial;
+
+	u32 ber;
+	u32 ucb;
+	unsigned long last_stat_check;
+};
+
+/* write multiple registers */
+static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val,
+		int len)
+{
+	int ret;
+	u8 buf[3 + len];
+	struct i2c_msg msg[1] = {
+		{
+			.addr = state->cfg.i2c_addr,
+			.flags = 0,
+			.len = sizeof(buf),
+			.buf = buf,
+		}
+	};
+
+	buf[0] = (reg >> 16) & 0xff;
+	buf[1] = (reg >>  8) & 0xff;
+	buf[2] = (reg >>  0) & 0xff;
+	memcpy(&buf[3], val, len);
+
+	ret = i2c_transfer(state->i2c, msg, 1);
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		printk(KERN_WARNING "%s: i2c wr failed=%d reg=%06x len=%d\n",
+				__func__, ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+
+	return ret;
+}
+
+/* read multiple registers */
+static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len)
+{
+	int ret;
+	u8 buf[3] = { (reg >> 16) & 0xff, (reg >> 8) & 0xff,
+			(reg >> 0) & 0xff };
+	struct i2c_msg msg[2] = {
+		{
+			.addr = state->cfg.i2c_addr,
+			.flags = 0,
+			.len = sizeof(buf),
+			.buf = buf
+		}, {
+			.addr = state->cfg.i2c_addr,
+			.flags = I2C_M_RD,
+			.len = len,
+			.buf = val
+		}
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+	if (ret == 2) {
+		ret = 0;
+	} else {
+		printk(KERN_WARNING "%s: i2c rd failed=%d reg=%06x len=%d\n",
+				__func__, ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+
+	return ret;
+}
+
+
+/* write single register */
+static int af9033_wr_reg(struct af9033_state *state, u32 reg, u8 val)
+{
+	return af9033_wr_regs(state, reg, &val, 1);
+}
+
+/* read single register */
+static int af9033_rd_reg(struct af9033_state *state, u32 reg, u8 *val)
+{
+	return af9033_rd_regs(state, reg, val, 1);
+}
+
+/* write single register with mask */
+static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val,
+		u8 mask)
+{
+	int ret;
+	u8 tmp;
+
+	/* no need for read if whole reg is written */
+	if (mask != 0xff) {
+		ret = af9033_rd_regs(state, reg, &tmp, 1);
+		if (ret)
+			return ret;
+
+		val &= mask;
+		tmp &= ~mask;
+		val |= tmp;
+	}
+
+	return af9033_wr_regs(state, reg, &val, 1);
+}
+
+/* read single register with mask */
+static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val,
+		u8 mask)
+{
+	int ret, i;
+	u8 tmp;
+
+	ret = af9033_rd_regs(state, reg, &tmp, 1);
+	if (ret)
+		return ret;
+
+	tmp &= mask;
+
+	/* find position of the first bit */
+	for (i = 0; i < 8; i++) {
+		if ((mask >> i) & 0x01)
+			break;
+	}
+	*val = tmp >> i;
+
+	return 0;
+}
+
+static u32 af9033_div(u32 a, u32 b, u32 x)
+{
+	u32 r = 0, c = 0, i;
+
+	pr_debug("%s: a=%d b=%d x=%d\n", __func__, a, b, x);
+
+	if (a > b) {
+		c = a / b;
+		a = a - c * b;
+	}
+
+	for (i = 0; i < x; i++) {
+		if (a >= b) {
+			r += 1;
+			a -= b;
+		}
+		a <<= 1;
+		r <<= 1;
+	}
+	r = (c << (u32)x) + r;
+
+	pr_debug("%s: a=%d b=%d x=%d r=%d r=%x\n", __func__, a, b, x, r, r);
+
+	return r;
+}
+
+static void af9033_release(struct dvb_frontend *fe)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+
+	kfree(state);
+}
+
+static int af9033_init(struct dvb_frontend *fe)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	int ret, i, len;
+	const struct reg_val *init;
+	u8 buf[4];
+	u32 adc_cw, clock_cw;
+	struct reg_val_mask tab[] = {
+		{ 0x80fb24, 0x00, 0x08 },
+		{ 0x80004c, 0x00, 0xff },
+		{ 0x00f641, state->cfg.tuner, 0xff },
+		{ 0x80f5ca, 0x01, 0x01 },
+		{ 0x80f715, 0x01, 0x01 },
+		{ 0x00f41f, 0x04, 0x04 },
+		{ 0x00f41a, 0x01, 0x01 },
+		{ 0x80f731, 0x00, 0x01 },
+		{ 0x00d91e, 0x00, 0x01 },
+		{ 0x00d919, 0x00, 0x01 },
+		{ 0x80f732, 0x00, 0x01 },
+		{ 0x00d91f, 0x00, 0x01 },
+		{ 0x00d91a, 0x00, 0x01 },
+		{ 0x80f730, 0x00, 0x01 },
+		{ 0x80f778, 0x00, 0xff },
+		{ 0x80f73c, 0x01, 0x01 },
+		{ 0x80f776, 0x00, 0x01 },
+		{ 0x00d8fd, 0x01, 0xff },
+		{ 0x00d830, 0x01, 0xff },
+		{ 0x00d831, 0x00, 0xff },
+		{ 0x00d832, 0x00, 0xff },
+		{ 0x80f985, state->ts_mode_serial, 0x01 },
+		{ 0x80f986, state->ts_mode_parallel, 0x01 },
+		{ 0x00d827, 0x00, 0xff },
+		{ 0x00d829, 0x00, 0xff },
+	};
+
+	/* program clock control */
+	clock_cw = af9033_div(state->cfg.clock, 1000000ul, 19ul);
+	buf[0] = (clock_cw >>  0) & 0xff;
+	buf[1] = (clock_cw >>  8) & 0xff;
+	buf[2] = (clock_cw >> 16) & 0xff;
+	buf[3] = (clock_cw >> 24) & 0xff;
+
+	pr_debug("%s: clock=%d clock_cw=%08x\n", __func__, state->cfg.clock,
+			clock_cw);
+
+	ret = af9033_wr_regs(state, 0x800025, buf, 4);
+	if (ret < 0)
+		goto err;
+
+	/* program ADC control */
+	for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) {
+		if (clock_adc_lut[i].clock == state->cfg.clock)
+			break;
+	}
+
+	adc_cw = af9033_div(clock_adc_lut[i].adc, 1000000ul, 19ul);
+	buf[0] = (adc_cw >>  0) & 0xff;
+	buf[1] = (adc_cw >>  8) & 0xff;
+	buf[2] = (adc_cw >> 16) & 0xff;
+
+	pr_debug("%s: adc=%d adc_cw=%06x\n", __func__, clock_adc_lut[i].adc,
+			adc_cw);
+
+	ret = af9033_wr_regs(state, 0x80f1cd, buf, 3);
+	if (ret < 0)
+		goto err;
+
+	/* program register table */
+	for (i = 0; i < ARRAY_SIZE(tab); i++) {
+		ret = af9033_wr_reg_mask(state, tab[i].reg, tab[i].val,
+				tab[i].mask);
+		if (ret < 0)
+			goto err;
+	}
+
+	/* settings for TS interface */
+	if (state->cfg.ts_mode == AF9033_TS_MODE_USB) {
+		ret = af9033_wr_reg_mask(state, 0x80f9a5, 0x00, 0x01);
+		if (ret < 0)
+			goto err;
+
+		ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x01, 0x01);
+		if (ret < 0)
+			goto err;
+	} else {
+		ret = af9033_wr_reg_mask(state, 0x80f990, 0x00, 0x01);
+		if (ret < 0)
+			goto err;
+
+		ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x00, 0x01);
+		if (ret < 0)
+			goto err;
+	}
+
+	/* load OFSM settings */
+	pr_debug("%s: load ofsm settings\n", __func__);
+	len = ARRAY_SIZE(ofsm_init);
+	init = ofsm_init;
+	for (i = 0; i < len; i++) {
+		ret = af9033_wr_reg(state, init[i].reg, init[i].val);
+		if (ret < 0)
+			goto err;
+	}
+
+	/* load tuner specific settings */
+	pr_debug("%s: load tuner specific settings\n",
+			__func__);
+	switch (state->cfg.tuner) {
+	case AF9033_TUNER_TUA9001:
+		len = ARRAY_SIZE(tuner_init_tua9001);
+		init = tuner_init_tua9001;
+		break;
+	case AF9033_TUNER_FC0011:
+		len = ARRAY_SIZE(tuner_init_fc0011);
+		init = tuner_init_fc0011;
+		break;
+	case AF9033_TUNER_MXL5007T:
+		len = ARRAY_SIZE(tuner_init_mxl5007t);
+		init = tuner_init_mxl5007t;
+		break;
+	case AF9033_TUNER_TDA18218:
+		len = ARRAY_SIZE(tuner_init_tda18218);
+		init = tuner_init_tda18218;
+		break;
+	default:
+		pr_debug("%s: unsupported tuner ID=%d\n", __func__,
+				state->cfg.tuner);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	for (i = 0; i < len; i++) {
+		ret = af9033_wr_reg(state, init[i].reg, init[i].val);
+		if (ret < 0)
+			goto err;
+	}
+
+	state->bandwidth_hz = 0; /* force to program all parameters */
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9033_sleep(struct dvb_frontend *fe)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	int ret, i;
+	u8 tmp;
+
+	ret = af9033_wr_reg(state, 0x80004c, 1);
+	if (ret < 0)
+		goto err;
+
+	ret = af9033_wr_reg(state, 0x800000, 0);
+	if (ret < 0)
+		goto err;
+
+	for (i = 100, tmp = 1; i && tmp; i--) {
+		ret = af9033_rd_reg(state, 0x80004c, &tmp);
+		if (ret < 0)
+			goto err;
+
+		usleep_range(200, 10000);
+	}
+
+	pr_debug("%s: loop=%d\n", __func__, i);
+
+	if (i == 0) {
+		ret = -ETIMEDOUT;
+		goto err;
+	}
+
+	ret = af9033_wr_reg_mask(state, 0x80fb24, 0x08, 0x08);
+	if (ret < 0)
+		goto err;
+
+	/* prevent current leak (?) */
+	if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
+		/* enable parallel TS */
+		ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01);
+		if (ret < 0)
+			goto err;
+
+		ret = af9033_wr_reg_mask(state, 0x00d916, 0x01, 0x01);
+		if (ret < 0)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9033_get_tune_settings(struct dvb_frontend *fe,
+		struct dvb_frontend_tune_settings *fesettings)
+{
+	fesettings->min_delay_ms = 800;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+
+	return 0;
+}
+
+static int af9033_set_frontend(struct dvb_frontend *fe)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i, spec_inv;
+	u8 tmp, buf[3], bandwidth_reg_val;
+	u32 if_frequency, freq_cw, adc_freq;
+
+	pr_debug("%s: frequency=%d bandwidth_hz=%d\n", __func__, c->frequency,
+			c->bandwidth_hz);
+
+	/* check bandwidth */
+	switch (c->bandwidth_hz) {
+	case 6000000:
+		bandwidth_reg_val = 0x00;
+		break;
+	case 7000000:
+		bandwidth_reg_val = 0x01;
+		break;
+	case 8000000:
+		bandwidth_reg_val = 0x02;
+		break;
+	default:
+		pr_debug("%s: invalid bandwidth_hz\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* program tuner */
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+
+	/* program CFOE coefficients */
+	if (c->bandwidth_hz != state->bandwidth_hz) {
+		for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) {
+			if (coeff_lut[i].clock == state->cfg.clock &&
+				coeff_lut[i].bandwidth_hz == c->bandwidth_hz) {
+				break;
+			}
+		}
+		ret =  af9033_wr_regs(state, 0x800001,
+				coeff_lut[i].val, sizeof(coeff_lut[i].val));
+	}
+
+	/* program frequency control */
+	if (c->bandwidth_hz != state->bandwidth_hz) {
+		spec_inv = state->cfg.spec_inv ? -1 : 1;
+
+		for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) {
+			if (clock_adc_lut[i].clock == state->cfg.clock)
+				break;
+		}
+		adc_freq = clock_adc_lut[i].adc;
+
+		/* get used IF frequency */
+		if (fe->ops.tuner_ops.get_if_frequency)
+			fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
+		else
+			if_frequency = 0;
+
+		while (if_frequency > (adc_freq / 2))
+			if_frequency -= adc_freq;
+
+		if (if_frequency >= 0)
+			spec_inv *= -1;
+		else
+			if_frequency *= -1;
+
+		freq_cw = af9033_div(if_frequency, adc_freq, 23ul);
+
+		if (spec_inv == -1)
+			freq_cw *= -1;
+
+		/* get adc multiplies */
+		ret = af9033_rd_reg(state, 0x800045, &tmp);
+		if (ret < 0)
+			goto err;
+
+		if (tmp == 1)
+			freq_cw /= 2;
+
+		buf[0] = (freq_cw >>  0) & 0xff;
+		buf[1] = (freq_cw >>  8) & 0xff;
+		buf[2] = (freq_cw >> 16) & 0x7f;
+		ret = af9033_wr_regs(state, 0x800029, buf, 3);
+		if (ret < 0)
+			goto err;
+
+		state->bandwidth_hz = c->bandwidth_hz;
+	}
+
+	ret = af9033_wr_reg_mask(state, 0x80f904, bandwidth_reg_val, 0x03);
+	if (ret < 0)
+		goto err;
+
+	ret = af9033_wr_reg(state, 0x800040, 0x00);
+	if (ret < 0)
+		goto err;
+
+	ret = af9033_wr_reg(state, 0x800047, 0x00);
+	if (ret < 0)
+		goto err;
+
+	ret = af9033_wr_reg_mask(state, 0x80f999, 0x00, 0x01);
+	if (ret < 0)
+		goto err;
+
+	if (c->frequency <= 230000000)
+		tmp = 0x00; /* VHF */
+	else
+		tmp = 0x01; /* UHF */
+
+	ret = af9033_wr_reg(state, 0x80004b, tmp);
+	if (ret < 0)
+		goto err;
+
+	ret = af9033_wr_reg(state, 0x800000, 0x00);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9033_get_frontend(struct dvb_frontend *fe)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret;
+	u8 buf[8];
+
+	pr_debug("%s\n", __func__);
+
+	/* read all needed registers */
+	ret = af9033_rd_regs(state, 0x80f900, buf, sizeof(buf));
+	if (ret < 0)
+		goto err;
+
+	switch ((buf[0] >> 0) & 3) {
+	case 0:
+		c->transmission_mode = TRANSMISSION_MODE_2K;
+		break;
+	case 1:
+		c->transmission_mode = TRANSMISSION_MODE_8K;
+		break;
+	}
+
+	switch ((buf[1] >> 0) & 3) {
+	case 0:
+		c->guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		c->guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		c->guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		c->guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	}
+
+	switch ((buf[2] >> 0) & 7) {
+	case 0:
+		c->hierarchy = HIERARCHY_NONE;
+		break;
+	case 1:
+		c->hierarchy = HIERARCHY_1;
+		break;
+	case 2:
+		c->hierarchy = HIERARCHY_2;
+		break;
+	case 3:
+		c->hierarchy = HIERARCHY_4;
+		break;
+	}
+
+	switch ((buf[3] >> 0) & 3) {
+	case 0:
+		c->modulation = QPSK;
+		break;
+	case 1:
+		c->modulation = QAM_16;
+		break;
+	case 2:
+		c->modulation = QAM_64;
+		break;
+	}
+
+	switch ((buf[4] >> 0) & 3) {
+	case 0:
+		c->bandwidth_hz = 6000000;
+		break;
+	case 1:
+		c->bandwidth_hz = 7000000;
+		break;
+	case 2:
+		c->bandwidth_hz = 8000000;
+		break;
+	}
+
+	switch ((buf[6] >> 0) & 7) {
+	case 0:
+		c->code_rate_HP = FEC_1_2;
+		break;
+	case 1:
+		c->code_rate_HP = FEC_2_3;
+		break;
+	case 2:
+		c->code_rate_HP = FEC_3_4;
+		break;
+	case 3:
+		c->code_rate_HP = FEC_5_6;
+		break;
+	case 4:
+		c->code_rate_HP = FEC_7_8;
+		break;
+	case 5:
+		c->code_rate_HP = FEC_NONE;
+		break;
+	}
+
+	switch ((buf[7] >> 0) & 7) {
+	case 0:
+		c->code_rate_LP = FEC_1_2;
+		break;
+	case 1:
+		c->code_rate_LP = FEC_2_3;
+		break;
+	case 2:
+		c->code_rate_LP = FEC_3_4;
+		break;
+	case 3:
+		c->code_rate_LP = FEC_5_6;
+		break;
+	case 4:
+		c->code_rate_LP = FEC_7_8;
+		break;
+	case 5:
+		c->code_rate_LP = FEC_NONE;
+		break;
+	}
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	int ret;
+	u8 tmp;
+
+	*status = 0;
+
+	/* radio channel status, 0=no result, 1=has signal, 2=no signal */
+	ret = af9033_rd_reg(state, 0x800047, &tmp);
+	if (ret < 0)
+		goto err;
+
+	/* has signal */
+	if (tmp == 0x01)
+		*status |= FE_HAS_SIGNAL;
+
+	if (tmp != 0x02) {
+		/* TPS lock */
+		ret = af9033_rd_reg_mask(state, 0x80f5a9, &tmp, 0x01);
+		if (ret < 0)
+			goto err;
+
+		if (tmp)
+			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+					FE_HAS_VITERBI;
+
+		/* full lock */
+		ret = af9033_rd_reg_mask(state, 0x80f999, &tmp, 0x01);
+		if (ret < 0)
+			goto err;
+
+		if (tmp)
+			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+					FE_HAS_VITERBI | FE_HAS_SYNC |
+					FE_HAS_LOCK;
+	}
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	int ret, i, len;
+	u8 buf[3], tmp;
+	u32 snr_val;
+	const struct val_snr *uninitialized_var(snr_lut);
+
+	/* read value */
+	ret = af9033_rd_regs(state, 0x80002c, buf, 3);
+	if (ret < 0)
+		goto err;
+
+	snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0];
+
+	/* read current modulation */
+	ret = af9033_rd_reg(state, 0x80f903, &tmp);
+	if (ret < 0)
+		goto err;
+
+	switch ((tmp >> 0) & 3) {
+	case 0:
+		len = ARRAY_SIZE(qpsk_snr_lut);
+		snr_lut = qpsk_snr_lut;
+		break;
+	case 1:
+		len = ARRAY_SIZE(qam16_snr_lut);
+		snr_lut = qam16_snr_lut;
+		break;
+	case 2:
+		len = ARRAY_SIZE(qam64_snr_lut);
+		snr_lut = qam64_snr_lut;
+		break;
+	default:
+		goto err;
+	}
+
+	for (i = 0; i < len; i++) {
+		tmp = snr_lut[i].snr;
+
+		if (snr_val < snr_lut[i].val)
+			break;
+	}
+
+	*snr = tmp * 10; /* dB/10 */
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	int ret;
+	u8 strength2;
+
+	/* read signal strength of 0-100 scale */
+	ret = af9033_rd_reg(state, 0x800048, &strength2);
+	if (ret < 0)
+		goto err;
+
+	/* scale value to 0x0000-0xffff */
+	*strength = strength2 * 0xffff / 100;
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9033_update_ch_stat(struct af9033_state *state)
+{
+	int ret = 0;
+	u32 err_cnt, bit_cnt;
+	u16 abort_cnt;
+	u8 buf[7];
+
+	/* only update data every half second */
+	if (time_after(jiffies, state->last_stat_check + msecs_to_jiffies(500))) {
+		ret = af9033_rd_regs(state, 0x800032, buf, sizeof(buf));
+		if (ret < 0)
+			goto err;
+		/* in 8 byte packets? */
+		abort_cnt = (buf[1] << 8) + buf[0];
+		/* in bits */
+		err_cnt = (buf[4] << 16) + (buf[3] << 8) + buf[2];
+		/* in 8 byte packets? always(?) 0x2710 = 10000 */
+		bit_cnt = (buf[6] << 8) + buf[5];
+
+		if (bit_cnt < abort_cnt) {
+			abort_cnt = 1000;
+			state->ber = 0xffffffff;
+		} else {
+			/* 8 byte packets, that have not been rejected already */
+			bit_cnt -= (u32)abort_cnt;
+			if (bit_cnt == 0) {
+				state->ber = 0xffffffff;
+			} else {
+				err_cnt -= (u32)abort_cnt * 8 * 8;
+				bit_cnt *= 8 * 8;
+				state->ber = err_cnt * (0xffffffff / bit_cnt);
+			}
+		}
+		state->ucb += abort_cnt;
+		state->last_stat_check = jiffies;
+	}
+
+	return 0;
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int af9033_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	int ret;
+
+	ret = af9033_update_ch_stat(state);
+	if (ret < 0)
+		return ret;
+
+	*ber = state->ber;
+
+	return 0;
+}
+
+static int af9033_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	int ret;
+
+	ret = af9033_update_ch_stat(state);
+	if (ret < 0)
+		return ret;
+
+	*ucblocks = state->ucb;
+
+	return 0;
+}
+
+static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct af9033_state *state = fe->demodulator_priv;
+	int ret;
+
+	pr_debug("%s: enable=%d\n", __func__, enable);
+
+	ret = af9033_wr_reg_mask(state, 0x00fa04, enable, 0x01);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static struct dvb_frontend_ops af9033_ops;
+
+struct dvb_frontend *af9033_attach(const struct af9033_config *config,
+		struct i2c_adapter *i2c)
+{
+	int ret;
+	struct af9033_state *state;
+	u8 buf[8];
+
+	pr_debug("%s:\n", __func__);
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct af9033_state), GFP_KERNEL);
+	if (state == NULL)
+		goto err;
+
+	/* setup the state */
+	state->i2c = i2c;
+	memcpy(&state->cfg, config, sizeof(struct af9033_config));
+
+	if (state->cfg.clock != 12000000) {
+		printk(KERN_INFO "af9033: unsupported clock=%d, only " \
+				"12000000 Hz is supported currently\n",
+				state->cfg.clock);
+		goto err;
+	}
+
+	/* firmware version */
+	ret = af9033_rd_regs(state, 0x0083e9, &buf[0], 4);
+	if (ret < 0)
+		goto err;
+
+	ret = af9033_rd_regs(state, 0x804191, &buf[4], 4);
+	if (ret < 0)
+		goto err;
+
+	printk(KERN_INFO "af9033: firmware version: LINK=%d.%d.%d.%d " \
+			"OFDM=%d.%d.%d.%d\n", buf[0], buf[1], buf[2], buf[3],
+			buf[4], buf[5], buf[6], buf[7]);
+
+	/* configure internal TS mode */
+	switch (state->cfg.ts_mode) {
+	case AF9033_TS_MODE_PARALLEL:
+		state->ts_mode_parallel = true;
+		break;
+	case AF9033_TS_MODE_SERIAL:
+		state->ts_mode_serial = true;
+		break;
+	case AF9033_TS_MODE_USB:
+		/* usb mode for AF9035 */
+	default:
+		break;
+	}
+
+	/* create dvb_frontend */
+	memcpy(&state->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops));
+	state->fe.demodulator_priv = state;
+
+	return &state->fe;
+
+err:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(af9033_attach);
+
+static struct dvb_frontend_ops af9033_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "Afatech AF9033 (DVB-T)",
+		.frequency_min = 174000000,
+		.frequency_max = 862000000,
+		.frequency_stepsize = 250000,
+		.frequency_tolerance = 0,
+		.caps =	FE_CAN_FEC_1_2 |
+			FE_CAN_FEC_2_3 |
+			FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 |
+			FE_CAN_FEC_7_8 |
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK |
+			FE_CAN_QAM_16 |
+			FE_CAN_QAM_64 |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_RECOVER |
+			FE_CAN_MUTE_TS
+	},
+
+	.release = af9033_release,
+
+	.init = af9033_init,
+	.sleep = af9033_sleep,
+
+	.get_tune_settings = af9033_get_tune_settings,
+	.set_frontend = af9033_set_frontend,
+	.get_frontend = af9033_get_frontend,
+
+	.read_status = af9033_read_status,
+	.read_snr = af9033_read_snr,
+	.read_signal_strength = af9033_read_signal_strength,
+	.read_ber = af9033_read_ber,
+	.read_ucblocks = af9033_read_ucblocks,
+
+	.i2c_gate_ctrl = af9033_i2c_gate_ctrl,
+};
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Afatech AF9033 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/af9033.h b/drivers/media/dvb-frontends/af9033.h
new file mode 100644
index 0000000..9e302c3
--- /dev/null
+++ b/drivers/media/dvb-frontends/af9033.h
@@ -0,0 +1,75 @@
+/*
+ * Afatech AF9033 demodulator driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef AF9033_H
+#define AF9033_H
+
+struct af9033_config {
+	/*
+	 * I2C address
+	 */
+	u8 i2c_addr;
+
+	/*
+	 * clock Hz
+	 * 12000000, 22000000, 24000000, 34000000, 32000000, 28000000, 26000000,
+	 * 30000000, 36000000, 20480000, 16384000
+	 */
+	u32 clock;
+
+	/*
+	 * tuner
+	 */
+#define AF9033_TUNER_TUA9001     0x27 /* Infineon TUA 9001 */
+#define AF9033_TUNER_FC0011      0x28 /* Fitipower FC0011 */
+#define AF9033_TUNER_MXL5007T    0xa0 /* MaxLinear MxL5007T */
+#define AF9033_TUNER_TDA18218    0xa1 /* NXP TDA 18218HN */
+	u8 tuner;
+
+	/*
+	 * TS settings
+	 */
+#define AF9033_TS_MODE_USB       0
+#define AF9033_TS_MODE_PARALLEL  1
+#define AF9033_TS_MODE_SERIAL    2
+	u8 ts_mode:2;
+
+	/*
+	 * input spectrum inversion
+	 */
+	bool spec_inv;
+};
+
+
+#if defined(CONFIG_DVB_AF9033) || \
+	(defined(CONFIG_DVB_AF9033_MODULE) && defined(MODULE))
+extern struct dvb_frontend *af9033_attach(const struct af9033_config *config,
+	struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *af9033_attach(
+	const struct af9033_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* AF9033_H */
diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h
new file mode 100644
index 0000000..0b783b9
--- /dev/null
+++ b/drivers/media/dvb-frontends/af9033_priv.h
@@ -0,0 +1,470 @@
+/*
+ * Afatech AF9033 demodulator driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef AF9033_PRIV_H
+#define AF9033_PRIV_H
+
+#include "dvb_frontend.h"
+#include "af9033.h"
+
+struct reg_val {
+	u32 reg;
+	u8  val;
+};
+
+struct reg_val_mask {
+	u32 reg;
+	u8  val;
+	u8  mask;
+};
+
+struct coeff {
+	u32 clock;
+	u32 bandwidth_hz;
+	u8 val[36];
+};
+
+struct clock_adc {
+	u32 clock;
+	u32 adc;
+};
+
+struct val_snr {
+	u32 val;
+	u8 snr;
+};
+
+/* Xtal clock vs. ADC clock lookup table */
+static const struct clock_adc clock_adc_lut[] = {
+	{ 16384000, 20480000 },
+	{ 20480000, 20480000 },
+	{ 36000000, 20250000 },
+	{ 30000000, 20156250 },
+	{ 26000000, 20583333 },
+	{ 28000000, 20416667 },
+	{ 32000000, 20500000 },
+	{ 34000000, 20187500 },
+	{ 24000000, 20500000 },
+	{ 22000000, 20625000 },
+	{ 12000000, 20250000 },
+};
+
+/* pre-calculated coeff lookup table */
+static const struct coeff coeff_lut[] = {
+	/* 12.000 MHz */
+	{ 12000000, 8000000, {
+		0x01, 0xce, 0x55, 0xc9, 0x00, 0xe7, 0x2a, 0xe4, 0x00, 0x73,
+		0x99, 0x0f, 0x00, 0x73, 0x95, 0x72, 0x00, 0x73, 0x91, 0xd5,
+		0x00, 0x39, 0xca, 0xb9, 0x00, 0xe7, 0x2a, 0xe4, 0x00, 0x73,
+		0x95, 0x72, 0x37, 0x02, 0xce, 0x01 }
+	},
+	{ 12000000, 7000000, {
+		0x01, 0x94, 0x8b, 0x10, 0x00, 0xca, 0x45, 0x88, 0x00, 0x65,
+		0x25, 0xed, 0x00, 0x65, 0x22, 0xc4, 0x00, 0x65, 0x1f, 0x9b,
+		0x00, 0x32, 0x91, 0x62, 0x00, 0xca, 0x45, 0x88, 0x00, 0x65,
+		0x22, 0xc4, 0x88, 0x02, 0x95, 0x01 }
+	},
+	{ 12000000, 6000000, {
+		0x01, 0x5a, 0xc0, 0x56, 0x00, 0xad, 0x60, 0x2b, 0x00, 0x56,
+		0xb2, 0xcb, 0x00, 0x56, 0xb0, 0x15, 0x00, 0x56, 0xad, 0x60,
+		0x00, 0x2b, 0x58, 0x0b, 0x00, 0xad, 0x60, 0x2b, 0x00, 0x56,
+		0xb0, 0x15, 0xf4, 0x02, 0x5b, 0x01 }
+	},
+};
+
+/* QPSK SNR lookup table */
+static const struct val_snr qpsk_snr_lut[] = {
+	{ 0x0b4771,  0 },
+	{ 0x0c1aed,  1 },
+	{ 0x0d0d27,  2 },
+	{ 0x0e4d19,  3 },
+	{ 0x0e5da8,  4 },
+	{ 0x107097,  5 },
+	{ 0x116975,  6 },
+	{ 0x1252d9,  7 },
+	{ 0x131fa4,  8 },
+	{ 0x13d5e1,  9 },
+	{ 0x148e53, 10 },
+	{ 0x15358b, 11 },
+	{ 0x15dd29, 12 },
+	{ 0x168112, 13 },
+	{ 0x170b61, 14 },
+	{ 0x17a532, 15 },
+	{ 0x180f94, 16 },
+	{ 0x186ed2, 17 },
+	{ 0x18b271, 18 },
+	{ 0x18e118, 19 },
+	{ 0x18ff4b, 20 },
+	{ 0x190af1, 21 },
+	{ 0x191451, 22 },
+	{ 0xffffff, 23 },
+};
+
+/* QAM16 SNR lookup table */
+static const struct val_snr qam16_snr_lut[] = {
+	{ 0x04f0d5,  0 },
+	{ 0x05387a,  1 },
+	{ 0x0573a4,  2 },
+	{ 0x05a99e,  3 },
+	{ 0x05cc80,  4 },
+	{ 0x05eb62,  5 },
+	{ 0x05fecf,  6 },
+	{ 0x060b80,  7 },
+	{ 0x062501,  8 },
+	{ 0x064865,  9 },
+	{ 0x069604, 10 },
+	{ 0x06f356, 11 },
+	{ 0x07706a, 12 },
+	{ 0x0804d3, 13 },
+	{ 0x089d1a, 14 },
+	{ 0x093e3d, 15 },
+	{ 0x09e35d, 16 },
+	{ 0x0a7c3c, 17 },
+	{ 0x0afaf8, 18 },
+	{ 0x0b719d, 19 },
+	{ 0x0bda6a, 20 },
+	{ 0x0c0c75, 21 },
+	{ 0x0c3f7d, 22 },
+	{ 0x0c5e62, 23 },
+	{ 0x0c6c31, 24 },
+	{ 0x0c7925, 25 },
+	{ 0xffffff, 26 },
+};
+
+/* QAM64 SNR lookup table */
+static const struct val_snr qam64_snr_lut[] = {
+	{ 0x0256d0,  0 },
+	{ 0x027a65,  1 },
+	{ 0x029873,  2 },
+	{ 0x02b7fe,  3 },
+	{ 0x02cf1e,  4 },
+	{ 0x02e234,  5 },
+	{ 0x02f409,  6 },
+	{ 0x030046,  7 },
+	{ 0x030844,  8 },
+	{ 0x030a02,  9 },
+	{ 0x030cde, 10 },
+	{ 0x031031, 11 },
+	{ 0x03144c, 12 },
+	{ 0x0315dd, 13 },
+	{ 0x031920, 14 },
+	{ 0x0322d0, 15 },
+	{ 0x0339fc, 16 },
+	{ 0x0364a1, 17 },
+	{ 0x038bcc, 18 },
+	{ 0x03c7d3, 19 },
+	{ 0x0408cc, 20 },
+	{ 0x043bed, 21 },
+	{ 0x048061, 22 },
+	{ 0x04be95, 23 },
+	{ 0x04fa7d, 24 },
+	{ 0x052405, 25 },
+	{ 0x05570d, 26 },
+	{ 0x059feb, 27 },
+	{ 0x05bf38, 28 },
+	{ 0xffffff, 29 },
+};
+
+static const struct reg_val ofsm_init[] = {
+	{ 0x800051, 0x01 },
+	{ 0x800070, 0x0a },
+	{ 0x80007e, 0x04 },
+	{ 0x800081, 0x0a },
+	{ 0x80008a, 0x01 },
+	{ 0x80008e, 0x01 },
+	{ 0x800092, 0x06 },
+	{ 0x800099, 0x01 },
+	{ 0x80009f, 0xe1 },
+	{ 0x8000a0, 0xcf },
+	{ 0x8000a3, 0x01 },
+	{ 0x8000a5, 0x01 },
+	{ 0x8000a6, 0x01 },
+	{ 0x8000a9, 0x00 },
+	{ 0x8000aa, 0x01 },
+	{ 0x8000ab, 0x01 },
+	{ 0x8000b0, 0x01 },
+	{ 0x8000c0, 0x05 },
+	{ 0x8000c4, 0x19 },
+	{ 0x80f000, 0x0f },
+	{ 0x80f016, 0x10 },
+	{ 0x80f017, 0x04 },
+	{ 0x80f018, 0x05 },
+	{ 0x80f019, 0x04 },
+	{ 0x80f01a, 0x05 },
+	{ 0x80f021, 0x03 },
+	{ 0x80f022, 0x0a },
+	{ 0x80f023, 0x0a },
+	{ 0x80f02b, 0x00 },
+	{ 0x80f02c, 0x01 },
+	{ 0x80f064, 0x03 },
+	{ 0x80f065, 0xf9 },
+	{ 0x80f066, 0x03 },
+	{ 0x80f067, 0x01 },
+	{ 0x80f06f, 0xe0 },
+	{ 0x80f070, 0x03 },
+	{ 0x80f072, 0x0f },
+	{ 0x80f073, 0x03 },
+	{ 0x80f078, 0x00 },
+	{ 0x80f087, 0x00 },
+	{ 0x80f09b, 0x3f },
+	{ 0x80f09c, 0x00 },
+	{ 0x80f09d, 0x20 },
+	{ 0x80f09e, 0x00 },
+	{ 0x80f09f, 0x0c },
+	{ 0x80f0a0, 0x00 },
+	{ 0x80f130, 0x04 },
+	{ 0x80f132, 0x04 },
+	{ 0x80f144, 0x1a },
+	{ 0x80f146, 0x00 },
+	{ 0x80f14a, 0x01 },
+	{ 0x80f14c, 0x00 },
+	{ 0x80f14d, 0x00 },
+	{ 0x80f14f, 0x04 },
+	{ 0x80f158, 0x7f },
+	{ 0x80f15a, 0x00 },
+	{ 0x80f15b, 0x08 },
+	{ 0x80f15d, 0x03 },
+	{ 0x80f15e, 0x05 },
+	{ 0x80f163, 0x05 },
+	{ 0x80f166, 0x01 },
+	{ 0x80f167, 0x40 },
+	{ 0x80f168, 0x0f },
+	{ 0x80f17a, 0x00 },
+	{ 0x80f17b, 0x00 },
+	{ 0x80f183, 0x01 },
+	{ 0x80f19d, 0x40 },
+	{ 0x80f1bc, 0x36 },
+	{ 0x80f1bd, 0x00 },
+	{ 0x80f1cb, 0xa0 },
+	{ 0x80f1cc, 0x01 },
+	{ 0x80f204, 0x10 },
+	{ 0x80f214, 0x00 },
+	{ 0x80f40e, 0x0a },
+	{ 0x80f40f, 0x40 },
+	{ 0x80f410, 0x08 },
+	{ 0x80f55f, 0x0a },
+	{ 0x80f561, 0x15 },
+	{ 0x80f562, 0x20 },
+	{ 0x80f5df, 0xfb },
+	{ 0x80f5e0, 0x00 },
+	{ 0x80f5e3, 0x09 },
+	{ 0x80f5e4, 0x01 },
+	{ 0x80f5e5, 0x01 },
+	{ 0x80f5f8, 0x01 },
+	{ 0x80f5fd, 0x01 },
+	{ 0x80f600, 0x05 },
+	{ 0x80f601, 0x08 },
+	{ 0x80f602, 0x0b },
+	{ 0x80f603, 0x0e },
+	{ 0x80f604, 0x11 },
+	{ 0x80f605, 0x14 },
+	{ 0x80f606, 0x17 },
+	{ 0x80f607, 0x1f },
+	{ 0x80f60e, 0x00 },
+	{ 0x80f60f, 0x04 },
+	{ 0x80f610, 0x32 },
+	{ 0x80f611, 0x10 },
+	{ 0x80f707, 0xfc },
+	{ 0x80f708, 0x00 },
+	{ 0x80f709, 0x37 },
+	{ 0x80f70a, 0x00 },
+	{ 0x80f78b, 0x01 },
+	{ 0x80f80f, 0x40 },
+	{ 0x80f810, 0x54 },
+	{ 0x80f811, 0x5a },
+	{ 0x80f905, 0x01 },
+	{ 0x80fb06, 0x03 },
+	{ 0x80fd8b, 0x00 },
+};
+
+/* Infineon TUA 9001 tuner init
+   AF9033_TUNER_TUA9001    = 0x27 */
+static const struct reg_val tuner_init_tua9001[] = {
+	{ 0x800046, 0x27 },
+	{ 0x800057, 0x00 },
+	{ 0x800058, 0x01 },
+	{ 0x80005f, 0x00 },
+	{ 0x800060, 0x00 },
+	{ 0x80006d, 0x00 },
+	{ 0x800071, 0x05 },
+	{ 0x800072, 0x02 },
+	{ 0x800074, 0x01 },
+	{ 0x800075, 0x03 },
+	{ 0x800076, 0x02 },
+	{ 0x800077, 0x00 },
+	{ 0x800078, 0x01 },
+	{ 0x800079, 0x00 },
+	{ 0x80007a, 0x7e },
+	{ 0x80007b, 0x3e },
+	{ 0x800093, 0x00 },
+	{ 0x800094, 0x01 },
+	{ 0x800095, 0x02 },
+	{ 0x800096, 0x01 },
+	{ 0x800098, 0x0a },
+	{ 0x80009b, 0x05 },
+	{ 0x80009c, 0x80 },
+	{ 0x8000b3, 0x00 },
+	{ 0x8000c1, 0x01 },
+	{ 0x8000c2, 0x00 },
+	{ 0x80f007, 0x00 },
+	{ 0x80f01f, 0x82 },
+	{ 0x80f020, 0x00 },
+	{ 0x80f029, 0x82 },
+	{ 0x80f02a, 0x00 },
+	{ 0x80f047, 0x00 },
+	{ 0x80f054, 0x00 },
+	{ 0x80f055, 0x00 },
+	{ 0x80f077, 0x01 },
+	{ 0x80f1e6, 0x00 },
+};
+
+/* Fitipower fc0011 tuner init
+   AF9033_TUNER_FC0011    = 0x28 */
+static const struct reg_val tuner_init_fc0011[] = {
+	{ 0x800046, AF9033_TUNER_FC0011 },
+	{ 0x800057, 0x00 },
+	{ 0x800058, 0x01 },
+	{ 0x80005f, 0x00 },
+	{ 0x800060, 0x00 },
+	{ 0x800068, 0xa5 },
+	{ 0x80006e, 0x01 },
+	{ 0x800071, 0x0A },
+	{ 0x800072, 0x02 },
+	{ 0x800074, 0x01 },
+	{ 0x800079, 0x01 },
+	{ 0x800093, 0x00 },
+	{ 0x800094, 0x00 },
+	{ 0x800095, 0x00 },
+	{ 0x800096, 0x00 },
+	{ 0x80009b, 0x2D },
+	{ 0x80009c, 0x60 },
+	{ 0x80009d, 0x23 },
+	{ 0x8000a4, 0x50 },
+	{ 0x8000ad, 0x50 },
+	{ 0x8000b3, 0x01 },
+	{ 0x8000b7, 0x88 },
+	{ 0x8000b8, 0xa6 },
+	{ 0x8000c3, 0x01 },
+	{ 0x8000c4, 0x01 },
+	{ 0x8000c7, 0x69 },
+	{ 0x80F007, 0x00 },
+	{ 0x80F00A, 0x1B },
+	{ 0x80F00B, 0x1B },
+	{ 0x80F00C, 0x1B },
+	{ 0x80F00D, 0x1B },
+	{ 0x80F00E, 0xFF },
+	{ 0x80F00F, 0x01 },
+	{ 0x80F010, 0x00 },
+	{ 0x80F011, 0x02 },
+	{ 0x80F012, 0xFF },
+	{ 0x80F013, 0x01 },
+	{ 0x80F014, 0x00 },
+	{ 0x80F015, 0x02 },
+	{ 0x80F01B, 0xEF },
+	{ 0x80F01C, 0x01 },
+	{ 0x80F01D, 0x0f },
+	{ 0x80F01E, 0x02 },
+	{ 0x80F01F, 0x6E },
+	{ 0x80F020, 0x00 },
+	{ 0x80F025, 0xDE },
+	{ 0x80F026, 0x00 },
+	{ 0x80F027, 0x0A },
+	{ 0x80F028, 0x03 },
+	{ 0x80F029, 0x6E },
+	{ 0x80F02A, 0x00 },
+	{ 0x80F047, 0x00 },
+	{ 0x80F054, 0x00 },
+	{ 0x80F055, 0x00 },
+	{ 0x80F077, 0x01 },
+	{ 0x80F1E6, 0x00 },
+};
+
+/* MaxLinear MxL5007T tuner init
+   AF9033_TUNER_MXL5007T    = 0xa0 */
+static const struct reg_val tuner_init_mxl5007t[] = {
+	{ 0x800046, 0x1b },
+	{ 0x800057, 0x01 },
+	{ 0x800058, 0x01 },
+	{ 0x80005f, 0x00 },
+	{ 0x800060, 0x00 },
+	{ 0x800068, 0x96 },
+	{ 0x800071, 0x05 },
+	{ 0x800072, 0x02 },
+	{ 0x800074, 0x01 },
+	{ 0x800079, 0x01 },
+	{ 0x800093, 0x00 },
+	{ 0x800094, 0x00 },
+	{ 0x800095, 0x00 },
+	{ 0x800096, 0x00 },
+	{ 0x8000b3, 0x01 },
+	{ 0x8000c1, 0x01 },
+	{ 0x8000c2, 0x00 },
+	{ 0x80f007, 0x00 },
+	{ 0x80f00c, 0x19 },
+	{ 0x80f00d, 0x1a },
+	{ 0x80f012, 0xda },
+	{ 0x80f013, 0x00 },
+	{ 0x80f014, 0x00 },
+	{ 0x80f015, 0x02 },
+	{ 0x80f01f, 0x82 },
+	{ 0x80f020, 0x00 },
+	{ 0x80f029, 0x82 },
+	{ 0x80f02a, 0x00 },
+	{ 0x80f077, 0x02 },
+	{ 0x80f1e6, 0x00 },
+};
+
+/* NXP TDA 18218HN tuner init
+   AF9033_TUNER_TDA18218    = 0xa1 */
+static const struct reg_val tuner_init_tda18218[] = {
+	{0x800046, 0xa1},
+	{0x800057, 0x01},
+	{0x800058, 0x01},
+	{0x80005f, 0x00},
+	{0x800060, 0x00},
+	{0x800071, 0x05},
+	{0x800072, 0x02},
+	{0x800074, 0x01},
+	{0x800079, 0x01},
+	{0x800093, 0x00},
+	{0x800094, 0x00},
+	{0x800095, 0x00},
+	{0x800096, 0x00},
+	{0x8000b3, 0x01},
+	{0x8000c3, 0x01},
+	{0x8000c4, 0x00},
+	{0x80f007, 0x00},
+	{0x80f00c, 0x19},
+	{0x80f00d, 0x1a},
+	{0x80f012, 0xda},
+	{0x80f013, 0x00},
+	{0x80f014, 0x00},
+	{0x80f015, 0x02},
+	{0x80f01f, 0x82},
+	{0x80f020, 0x00},
+	{0x80f029, 0x82},
+	{0x80f02a, 0x00},
+	{0x80f077, 0x02},
+	{0x80f1e6, 0x00},
+};
+
+#endif /* AF9033_PRIV_H */
+
diff --git a/drivers/media/dvb-frontends/atbm8830.c b/drivers/media/dvb-frontends/atbm8830.c
new file mode 100644
index 0000000..4e11dc4
--- /dev/null
+++ b/drivers/media/dvb-frontends/atbm8830.c
@@ -0,0 +1,508 @@
+/*
+ *    Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator
+ *    ATBM8830, ATBM8831
+ *
+ *    Copyright (C) 2009 David T.L. Wong <davidtlwong@gmail.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <asm/div64.h>
+#include "dvb_frontend.h"
+
+#include "atbm8830.h"
+#include "atbm8830_priv.h"
+
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG "atbm8830: " args); \
+	} while (0)
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+static int atbm8830_write_reg(struct atbm_state *priv, u16 reg, u8 data)
+{
+	int ret = 0;
+	u8 dev_addr;
+	u8 buf1[] = { reg >> 8, reg & 0xFF };
+	u8 buf2[] = { data };
+	struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 };
+	struct i2c_msg msg2 = { .flags = 0, .buf = buf2, .len = 1 };
+
+	dev_addr = priv->config->demod_address;
+	msg1.addr = dev_addr;
+	msg2.addr = dev_addr;
+
+	if (debug >= 2)
+		dprintk("%s: reg=0x%04X, data=0x%02X\n", __func__, reg, data);
+
+	ret = i2c_transfer(priv->i2c, &msg1, 1);
+	if (ret != 1)
+		return -EIO;
+
+	ret = i2c_transfer(priv->i2c, &msg2, 1);
+	return (ret != 1) ? -EIO : 0;
+}
+
+static int atbm8830_read_reg(struct atbm_state *priv, u16 reg, u8 *p_data)
+{
+	int ret;
+	u8 dev_addr;
+
+	u8 buf1[] = { reg >> 8, reg & 0xFF };
+	u8 buf2[] = { 0 };
+	struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 };
+	struct i2c_msg msg2 = { .flags = I2C_M_RD, .buf = buf2, .len = 1 };
+
+	dev_addr = priv->config->demod_address;
+	msg1.addr = dev_addr;
+	msg2.addr = dev_addr;
+
+	ret = i2c_transfer(priv->i2c, &msg1, 1);
+	if (ret != 1) {
+		dprintk("%s: error reg=0x%04x, ret=%i\n", __func__, reg, ret);
+		return -EIO;
+	}
+
+	ret = i2c_transfer(priv->i2c, &msg2, 1);
+	if (ret != 1)
+		return -EIO;
+
+	*p_data = buf2[0];
+	if (debug >= 2)
+		dprintk("%s: reg=0x%04X, data=0x%02X\n",
+			__func__, reg, buf2[0]);
+
+	return 0;
+}
+
+/* Lock register latch so that multi-register read is atomic */
+static inline int atbm8830_reglatch_lock(struct atbm_state *priv, int lock)
+{
+	return atbm8830_write_reg(priv, REG_READ_LATCH, lock ? 1 : 0);
+}
+
+static int set_osc_freq(struct atbm_state *priv, u32 freq /*in kHz*/)
+{
+	u32 val;
+	u64 t;
+
+	/* 0x100000 * freq / 30.4MHz */
+	t = (u64)0x100000 * freq;
+	do_div(t, 30400);
+	val = t;
+
+	atbm8830_write_reg(priv, REG_OSC_CLK, val);
+	atbm8830_write_reg(priv, REG_OSC_CLK + 1, val >> 8);
+	atbm8830_write_reg(priv, REG_OSC_CLK + 2, val >> 16);
+
+	return 0;
+}
+
+static int set_if_freq(struct atbm_state *priv, u32 freq /*in kHz*/)
+{
+
+	u32 fs = priv->config->osc_clk_freq;
+	u64 t;
+	u32 val;
+	u8 dat;
+
+	if (freq != 0) {
+		/* 2 * PI * (freq - fs) / fs * (2 ^ 22) */
+		t = (u64) 2 * 31416 * (freq - fs);
+		t <<= 22;
+		do_div(t, fs);
+		do_div(t, 1000);
+		val = t;
+
+		atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 1);
+		atbm8830_write_reg(priv, REG_IF_FREQ, val);
+		atbm8830_write_reg(priv, REG_IF_FREQ+1, val >> 8);
+		atbm8830_write_reg(priv, REG_IF_FREQ+2, val >> 16);
+
+		atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat);
+		dat &= 0xFC;
+		atbm8830_write_reg(priv, REG_ADC_CONFIG, dat);
+	} else {
+		/* Zero IF */
+		atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 0);
+
+		atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat);
+		dat &= 0xFC;
+		dat |= 0x02;
+		atbm8830_write_reg(priv, REG_ADC_CONFIG, dat);
+
+		if (priv->config->zif_swap_iq)
+			atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x03);
+		else
+			atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x01);
+	}
+
+	return 0;
+}
+
+static int is_locked(struct atbm_state *priv, u8 *locked)
+{
+	u8 status;
+
+	atbm8830_read_reg(priv, REG_LOCK_STATUS, &status);
+
+	if (locked != NULL)
+		*locked = (status == 1);
+	return 0;
+}
+
+static int set_agc_config(struct atbm_state *priv,
+	u8 min, u8 max, u8 hold_loop)
+{
+	/* no effect if both min and max are zero */
+	if (!min && !max)
+	    return 0;
+
+	atbm8830_write_reg(priv, REG_AGC_MIN, min);
+	atbm8830_write_reg(priv, REG_AGC_MAX, max);
+	atbm8830_write_reg(priv, REG_AGC_HOLD_LOOP, hold_loop);
+
+	return 0;
+}
+
+static int set_static_channel_mode(struct atbm_state *priv)
+{
+	int i;
+
+	for (i = 0; i < 5; i++)
+		atbm8830_write_reg(priv, 0x099B + i, 0x08);
+
+	atbm8830_write_reg(priv, 0x095B, 0x7F);
+	atbm8830_write_reg(priv, 0x09CB, 0x01);
+	atbm8830_write_reg(priv, 0x09CC, 0x7F);
+	atbm8830_write_reg(priv, 0x09CD, 0x7F);
+	atbm8830_write_reg(priv, 0x0E01, 0x20);
+
+	/* For single carrier */
+	atbm8830_write_reg(priv, 0x0B03, 0x0A);
+	atbm8830_write_reg(priv, 0x0935, 0x10);
+	atbm8830_write_reg(priv, 0x0936, 0x08);
+	atbm8830_write_reg(priv, 0x093E, 0x08);
+	atbm8830_write_reg(priv, 0x096E, 0x06);
+
+	/* frame_count_max0 */
+	atbm8830_write_reg(priv, 0x0B09, 0x00);
+	/* frame_count_max1 */
+	atbm8830_write_reg(priv, 0x0B0A, 0x08);
+
+	return 0;
+}
+
+static int set_ts_config(struct atbm_state *priv)
+{
+	const struct atbm8830_config *cfg = priv->config;
+
+	/*Set parallel/serial ts mode*/
+	atbm8830_write_reg(priv, REG_TS_SERIAL, cfg->serial_ts ? 1 : 0);
+	atbm8830_write_reg(priv, REG_TS_CLK_MODE, cfg->serial_ts ? 1 : 0);
+	/*Set ts sampling edge*/
+	atbm8830_write_reg(priv, REG_TS_SAMPLE_EDGE,
+		cfg->ts_sampling_edge ? 1 : 0);
+	/*Set ts clock freerun*/
+	atbm8830_write_reg(priv, REG_TS_CLK_FREERUN,
+		cfg->ts_clk_gated ? 0 : 1);
+
+	return 0;
+}
+
+static int atbm8830_init(struct dvb_frontend *fe)
+{
+	struct atbm_state *priv = fe->demodulator_priv;
+	const struct atbm8830_config *cfg = priv->config;
+
+	/*Set oscillator frequency*/
+	set_osc_freq(priv, cfg->osc_clk_freq);
+
+	/*Set IF frequency*/
+	set_if_freq(priv, cfg->if_freq);
+
+	/*Set AGC Config*/
+	set_agc_config(priv, cfg->agc_min, cfg->agc_max,
+		cfg->agc_hold_loop);
+
+	/*Set static channel mode*/
+	set_static_channel_mode(priv);
+
+	set_ts_config(priv);
+	/*Turn off DSP reset*/
+	atbm8830_write_reg(priv, 0x000A, 0);
+
+	/*SW version test*/
+	atbm8830_write_reg(priv, 0x020C, 11);
+
+	/* Run */
+	atbm8830_write_reg(priv, REG_DEMOD_RUN, 1);
+
+	return 0;
+}
+
+
+static void atbm8830_release(struct dvb_frontend *fe)
+{
+	struct atbm_state *state = fe->demodulator_priv;
+	dprintk("%s\n", __func__);
+
+	kfree(state);
+}
+
+static int atbm8830_set_fe(struct dvb_frontend *fe)
+{
+	struct atbm_state *priv = fe->demodulator_priv;
+	int i;
+	u8 locked = 0;
+	dprintk("%s\n", __func__);
+
+	/* set frequency */
+	if (fe->ops.tuner_ops.set_params) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	/* start auto lock */
+	for (i = 0; i < 10; i++) {
+		mdelay(100);
+		dprintk("Try %d\n", i);
+		is_locked(priv, &locked);
+		if (locked != 0) {
+			dprintk("ATBM8830 locked!\n");
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int atbm8830_get_fe(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	dprintk("%s\n", __func__);
+
+	/* TODO: get real readings from device */
+	/* inversion status */
+	c->inversion = INVERSION_OFF;
+
+	/* bandwidth */
+	c->bandwidth_hz = 8000000;
+
+	c->code_rate_HP = FEC_AUTO;
+	c->code_rate_LP = FEC_AUTO;
+
+	c->modulation = QAM_AUTO;
+
+	/* transmission mode */
+	c->transmission_mode = TRANSMISSION_MODE_AUTO;
+
+	/* guard interval */
+	c->guard_interval = GUARD_INTERVAL_AUTO;
+
+	/* hierarchy */
+	c->hierarchy = HIERARCHY_NONE;
+
+	return 0;
+}
+
+static int atbm8830_get_tune_settings(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *fesettings)
+{
+	fesettings->min_delay_ms = 0;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+	return 0;
+}
+
+static int atbm8830_read_status(struct dvb_frontend *fe, fe_status_t *fe_status)
+{
+	struct atbm_state *priv = fe->demodulator_priv;
+	u8 locked = 0;
+	u8 agc_locked = 0;
+
+	dprintk("%s\n", __func__);
+	*fe_status = 0;
+
+	is_locked(priv, &locked);
+	if (locked) {
+		*fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+			FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+	}
+	dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
+
+	atbm8830_read_reg(priv, REG_AGC_LOCK, &agc_locked);
+	dprintk("AGC Lock: %d\n", agc_locked);
+
+	return 0;
+}
+
+static int atbm8830_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct atbm_state *priv = fe->demodulator_priv;
+	u32 frame_err;
+	u8 t;
+
+	dprintk("%s\n", __func__);
+
+	atbm8830_reglatch_lock(priv, 1);
+
+	atbm8830_read_reg(priv, REG_FRAME_ERR_CNT + 1, &t);
+	frame_err = t & 0x7F;
+	frame_err <<= 8;
+	atbm8830_read_reg(priv, REG_FRAME_ERR_CNT, &t);
+	frame_err |= t;
+
+	atbm8830_reglatch_lock(priv, 0);
+
+	*ber = frame_err * 100 / 32767;
+
+	dprintk("%s: ber=0x%x\n", __func__, *ber);
+	return 0;
+}
+
+static int atbm8830_read_signal_strength(struct dvb_frontend *fe, u16 *signal)
+{
+	struct atbm_state *priv = fe->demodulator_priv;
+	u32 pwm;
+	u8 t;
+
+	dprintk("%s\n", __func__);
+	atbm8830_reglatch_lock(priv, 1);
+
+	atbm8830_read_reg(priv, REG_AGC_PWM_VAL + 1, &t);
+	pwm = t & 0x03;
+	pwm <<= 8;
+	atbm8830_read_reg(priv, REG_AGC_PWM_VAL, &t);
+	pwm |= t;
+
+	atbm8830_reglatch_lock(priv, 0);
+
+	dprintk("AGC PWM = 0x%02X\n", pwm);
+	pwm = 0x400 - pwm;
+
+	*signal = pwm * 0x10000 / 0x400;
+
+	return 0;
+}
+
+static int atbm8830_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	dprintk("%s\n", __func__);
+	*snr = 0;
+	return 0;
+}
+
+static int atbm8830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	dprintk("%s\n", __func__);
+	*ucblocks = 0;
+	return 0;
+}
+
+static int atbm8830_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct atbm_state *priv = fe->demodulator_priv;
+
+	return atbm8830_write_reg(priv, REG_I2C_GATE, enable ? 1 : 0);
+}
+
+static struct dvb_frontend_ops atbm8830_ops = {
+	.delsys = { SYS_DTMB },
+	.info = {
+		.name = "AltoBeam ATBM8830/8831 DMB-TH",
+		.frequency_min = 474000000,
+		.frequency_max = 858000000,
+		.frequency_stepsize = 10000,
+		.caps =
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO
+	},
+
+	.release = atbm8830_release,
+
+	.init = atbm8830_init,
+	.sleep = NULL,
+	.write = NULL,
+	.i2c_gate_ctrl = atbm8830_i2c_gate_ctrl,
+
+	.set_frontend = atbm8830_set_fe,
+	.get_frontend = atbm8830_get_fe,
+	.get_tune_settings = atbm8830_get_tune_settings,
+
+	.read_status = atbm8830_read_status,
+	.read_ber = atbm8830_read_ber,
+	.read_signal_strength = atbm8830_read_signal_strength,
+	.read_snr = atbm8830_read_snr,
+	.read_ucblocks = atbm8830_read_ucblocks,
+};
+
+struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
+	struct i2c_adapter *i2c)
+{
+	struct atbm_state *priv = NULL;
+	u8 data = 0;
+
+	dprintk("%s()\n", __func__);
+
+	if (config == NULL || i2c == NULL)
+		return NULL;
+
+	priv = kzalloc(sizeof(struct atbm_state), GFP_KERNEL);
+	if (priv == NULL)
+		goto error_out;
+
+	priv->config = config;
+	priv->i2c = i2c;
+
+	/* check if the demod is there */
+	if (atbm8830_read_reg(priv, REG_CHIP_ID, &data) != 0) {
+		dprintk("%s atbm8830/8831 not found at i2c addr 0x%02X\n",
+			__func__, priv->config->demod_address);
+		goto error_out;
+	}
+	dprintk("atbm8830 chip id: 0x%02X\n", data);
+
+	memcpy(&priv->frontend.ops, &atbm8830_ops,
+	       sizeof(struct dvb_frontend_ops));
+	priv->frontend.demodulator_priv = priv;
+
+	atbm8830_init(&priv->frontend);
+
+	atbm8830_i2c_gate_ctrl(&priv->frontend, 1);
+
+	return &priv->frontend;
+
+error_out:
+	dprintk("%s() error_out\n", __func__);
+	kfree(priv);
+	return NULL;
+
+}
+EXPORT_SYMBOL(atbm8830_attach);
+
+MODULE_DESCRIPTION("AltoBeam ATBM8830/8831 GB20600 demodulator driver");
+MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/atbm8830.h b/drivers/media/dvb-frontends/atbm8830.h
new file mode 100644
index 0000000..0242733
--- /dev/null
+++ b/drivers/media/dvb-frontends/atbm8830.h
@@ -0,0 +1,76 @@
+/*
+ *    Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator
+ *    ATBM8830, ATBM8831
+ *
+ *    Copyright (C) 2009 David T.L. Wong <davidtlwong@gmail.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ATBM8830_H__
+#define __ATBM8830_H__
+
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#define ATBM8830_PROD_8830 0
+#define ATBM8830_PROD_8831 1
+
+struct atbm8830_config {
+
+	/* product type */
+	u8 prod;
+
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* parallel or serial transport stream */
+	u8 serial_ts;
+
+	/* transport stream clock output only when receiving valid stream */
+	u8 ts_clk_gated;
+
+	/* Decoder sample TS data at rising edge of clock */
+	u8 ts_sampling_edge;
+
+	/* Oscillator clock frequency */
+	u32 osc_clk_freq; /* in kHz */
+
+	/* IF frequency */
+	u32 if_freq; /* in kHz */
+
+	/* Swap I/Q for zero IF */
+	u8 zif_swap_iq;
+
+	/* Tuner AGC settings */
+	u8 agc_min;
+	u8 agc_max;
+	u8 agc_hold_loop;
+};
+
+#if defined(CONFIG_DVB_ATBM8830) || \
+	(defined(CONFIG_DVB_ATBM8830_MODULE) && defined(MODULE))
+extern struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
+		struct i2c_adapter *i2c);
+#else
+static inline
+struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
+		struct i2c_adapter *i2c) {
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_ATBM8830 */
+
+#endif /* __ATBM8830_H__ */
diff --git a/drivers/media/dvb-frontends/atbm8830_priv.h b/drivers/media/dvb-frontends/atbm8830_priv.h
new file mode 100644
index 0000000..d460058
--- /dev/null
+++ b/drivers/media/dvb-frontends/atbm8830_priv.h
@@ -0,0 +1,75 @@
+/*
+ *    Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator
+ *    ATBM8830, ATBM8831
+ *
+ *    Copyright (C) 2009 David T.L. Wong <davidtlwong@gmail.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ATBM8830_PRIV_H
+#define __ATBM8830_PRIV_H
+
+struct atbm_state {
+	struct i2c_adapter *i2c;
+	/* configuration settings */
+	const struct atbm8830_config *config;
+	struct dvb_frontend frontend;
+};
+
+#define REG_CHIP_ID	0x0000
+#define REG_TUNER_BASEBAND	0x0001
+#define REG_DEMOD_RUN	0x0004
+#define REG_DSP_RESET	0x0005
+#define REG_RAM_RESET	0x0006
+#define REG_ADC_RESET	0x0007
+#define REG_TSPORT_RESET	0x0008
+#define REG_BLKERR_POL	0x000C
+#define REG_I2C_GATE	0x0103
+#define REG_TS_SAMPLE_EDGE	0x0301
+#define REG_TS_PKT_LEN_204	0x0302
+#define REG_TS_PKT_LEN_AUTO	0x0303
+#define REG_TS_SERIAL	0x0305
+#define REG_TS_CLK_FREERUN	0x0306
+#define REG_TS_VALID_MODE	0x0307
+#define REG_TS_CLK_MODE	0x030B /* 1 for serial, 0 for parallel */
+
+#define REG_TS_ERRBIT_USE	0x030C
+#define REG_LOCK_STATUS	0x030D
+#define REG_ADC_CONFIG	0x0602
+#define REG_CARRIER_OFFSET	0x0827 /* 0x0827-0x0829 little endian */
+#define REG_DETECTED_PN_MODE	0x082D
+#define REG_READ_LATCH	0x084D
+#define REG_IF_FREQ	0x0A00 /* 0x0A00-0x0A02 little endian */
+#define REG_OSC_CLK	0x0A03 /* 0x0A03-0x0A05 little endian */
+#define REG_BYPASS_CCI	0x0A06
+#define REG_ANALOG_LUMA_DETECTED	0x0A25
+#define REG_ANALOG_AUDIO_DETECTED	0x0A26
+#define REG_ANALOG_CHROMA_DETECTED	0x0A39
+#define REG_FRAME_ERR_CNT	0x0B04
+#define REG_USE_EXT_ADC	0x0C00
+#define REG_SWAP_I_Q	0x0C01
+#define REG_TPS_MANUAL	0x0D01
+#define REG_TPS_CONFIG	0x0D02
+#define REG_BYPASS_DEINTERLEAVER	0x0E00
+#define REG_AGC_TARGET	0x1003 /* 0x1003-0x1005 little endian */
+#define REG_AGC_MIN	0x1020
+#define REG_AGC_MAX	0x1023
+#define REG_AGC_LOCK	0x1027
+#define REG_AGC_PWM_VAL	0x1028 /* 0x1028-0x1029 little endian */
+#define REG_AGC_HOLD_LOOP	0x1031
+
+#endif
+
diff --git a/drivers/media/dvb-frontends/au8522.h b/drivers/media/dvb-frontends/au8522.h
new file mode 100644
index 0000000..565dcf3
--- /dev/null
+++ b/drivers/media/dvb-frontends/au8522.h
@@ -0,0 +1,98 @@
+/*
+    Auvitek AU8522 QAM/8VSB demodulator driver
+
+    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __AU8522_H__
+#define __AU8522_H__
+
+#include <linux/dvb/frontend.h>
+
+enum au8522_if_freq {
+	AU8522_IF_6MHZ = 0,
+	AU8522_IF_4MHZ,
+	AU8522_IF_3_25MHZ,
+};
+
+struct au8522_led_config {
+	u16 vsb8_strong;
+	u16 qam64_strong;
+	u16 qam256_strong;
+
+	u16 gpio_output;
+	/* unset hi bits, set low bits */
+	u16 gpio_output_enable;
+	u16 gpio_output_disable;
+
+	u16 gpio_leds;
+	u8 *led_states;
+	unsigned int num_led_states;
+};
+
+struct au8522_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* Return lock status based on tuner lock, or demod lock */
+#define AU8522_TUNERLOCKING 0
+#define AU8522_DEMODLOCKING 1
+	u8 status_mode;
+
+	struct au8522_led_config *led_cfg;
+
+	enum au8522_if_freq vsb_if;
+	enum au8522_if_freq qam_if;
+};
+
+#if defined(CONFIG_DVB_AU8522) || 				\
+	    (defined(CONFIG_DVB_AU8522_MODULE) && defined(MODULE))
+extern struct dvb_frontend *au8522_attach(const struct au8522_config *config,
+					  struct i2c_adapter *i2c);
+#else
+static inline
+struct dvb_frontend *au8522_attach(const struct au8522_config *config,
+				   struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_AU8522 */
+
+/* Other modes may need to be added later */
+enum au8522_video_input {
+	AU8522_COMPOSITE_CH1 = 1,
+	AU8522_COMPOSITE_CH2,
+	AU8522_COMPOSITE_CH3,
+	AU8522_COMPOSITE_CH4,
+	AU8522_COMPOSITE_CH4_SIF,
+	AU8522_SVIDEO_CH13,
+	AU8522_SVIDEO_CH24,
+};
+
+enum au8522_audio_input {
+	AU8522_AUDIO_NONE,
+	AU8522_AUDIO_SIF,
+};
+
+#endif /* __AU8522_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb-frontends/au8522_common.c b/drivers/media/dvb-frontends/au8522_common.c
new file mode 100644
index 0000000..3559ff2
--- /dev/null
+++ b/drivers/media/dvb-frontends/au8522_common.c
@@ -0,0 +1,277 @@
+/*
+    Auvitek AU8522 QAM/8VSB demodulator driver
+
+    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+    Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org>
+    Copyright (C) 2005-2008 Auvitek International, Ltd.
+    Copyright (C) 2012 Michael Krufky <mkrufky@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+#include "au8522_priv.h"
+
+static int debug;
+
+#define dprintk(arg...)\
+  do { if (debug)\
+	 printk(arg);\
+  } while (0)
+
+/* Despite the name "hybrid_tuner", the framework works just as well for
+   hybrid demodulators as well... */
+static LIST_HEAD(hybrid_tuner_instance_list);
+static DEFINE_MUTEX(au8522_list_mutex);
+
+/* 16 bit registers, 8 bit values */
+int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
+{
+	int ret;
+	u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
+
+	struct i2c_msg msg = { .addr = state->config->demod_address,
+			       .flags = 0, .buf = buf, .len = 3 };
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
+		       "ret == %i)\n", __func__, reg, data, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+EXPORT_SYMBOL(au8522_writereg);
+
+u8 au8522_readreg(struct au8522_state *state, u16 reg)
+{
+	int ret;
+	u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff };
+	u8 b1[] = { 0 };
+
+	struct i2c_msg msg[] = {
+		{ .addr = state->config->demod_address, .flags = 0,
+		  .buf = b0, .len = 2 },
+		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
+		  .buf = b1, .len = 1 } };
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+		       __func__, ret);
+	return b1[0];
+}
+EXPORT_SYMBOL(au8522_readreg);
+
+int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __func__, enable);
+
+	if (state->operational_mode == AU8522_ANALOG_MODE) {
+		/* We're being asked to manage the gate even though we're
+		   not in digital mode.  This can occur if we get switched
+		   over to analog mode before the dvb_frontend kernel thread
+		   has completely shutdown */
+		return 0;
+	}
+
+	if (enable)
+		return au8522_writereg(state, 0x106, 1);
+	else
+		return au8522_writereg(state, 0x106, 0);
+}
+EXPORT_SYMBOL(au8522_i2c_gate_ctrl);
+
+int au8522_analog_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __func__, enable);
+
+	if (enable)
+		return au8522_writereg(state, 0x106, 1);
+	else
+		return au8522_writereg(state, 0x106, 0);
+}
+EXPORT_SYMBOL(au8522_analog_i2c_gate_ctrl);
+
+/* Reset the demod hardware and reset all of the configuration registers
+   to a default state. */
+int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
+		     u8 client_address)
+{
+	int ret;
+
+	mutex_lock(&au8522_list_mutex);
+	ret = hybrid_tuner_request_state(struct au8522_state, (*state),
+					 hybrid_tuner_instance_list,
+					 i2c, client_address, "au8522");
+	mutex_unlock(&au8522_list_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(au8522_get_state);
+
+void au8522_release_state(struct au8522_state *state)
+{
+	mutex_lock(&au8522_list_mutex);
+	if (state != NULL)
+		hybrid_tuner_release_state(state);
+	mutex_unlock(&au8522_list_mutex);
+}
+EXPORT_SYMBOL(au8522_release_state);
+
+static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
+{
+	struct au8522_led_config *led_config = state->config->led_cfg;
+	u8 val;
+
+	/* bail out if we can't control an LED */
+	if (!led_config || !led_config->gpio_output ||
+	    !led_config->gpio_output_enable || !led_config->gpio_output_disable)
+		return 0;
+
+	val = au8522_readreg(state, 0x4000 |
+			     (led_config->gpio_output & ~0xc000));
+	if (onoff) {
+		/* enable GPIO output */
+		val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
+		val |=  (led_config->gpio_output_enable & 0xff);
+	} else {
+		/* disable GPIO output */
+		val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
+		val |=  (led_config->gpio_output_disable & 0xff);
+	}
+	return au8522_writereg(state, 0x8000 |
+			       (led_config->gpio_output & ~0xc000), val);
+}
+
+/* led = 0 | off
+ * led = 1 | signal ok
+ * led = 2 | signal strong
+ * led < 0 | only light led if leds are currently off
+ */
+int au8522_led_ctrl(struct au8522_state *state, int led)
+{
+	struct au8522_led_config *led_config = state->config->led_cfg;
+	int i, ret = 0;
+
+	/* bail out if we can't control an LED */
+	if (!led_config || !led_config->gpio_leds ||
+	    !led_config->num_led_states || !led_config->led_states)
+		return 0;
+
+	if (led < 0) {
+		/* if LED is already lit, then leave it as-is */
+		if (state->led_state)
+			return 0;
+		else
+			led *= -1;
+	}
+
+	/* toggle LED if changing state */
+	if (state->led_state != led) {
+		u8 val;
+
+		dprintk("%s: %d\n", __func__, led);
+
+		au8522_led_gpio_enable(state, 1);
+
+		val = au8522_readreg(state, 0x4000 |
+				     (led_config->gpio_leds & ~0xc000));
+
+		/* start with all leds off */
+		for (i = 0; i < led_config->num_led_states; i++)
+			val &= ~led_config->led_states[i];
+
+		/* set selected LED state */
+		if (led < led_config->num_led_states)
+			val |= led_config->led_states[led];
+		else if (led_config->num_led_states)
+			val |=
+			led_config->led_states[led_config->num_led_states - 1];
+
+		ret = au8522_writereg(state, 0x8000 |
+				      (led_config->gpio_leds & ~0xc000), val);
+		if (ret < 0)
+			return ret;
+
+		state->led_state = led;
+
+		if (led == 0)
+			au8522_led_gpio_enable(state, 0);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(au8522_led_ctrl);
+
+int au8522_init(struct dvb_frontend *fe)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	dprintk("%s()\n", __func__);
+
+	state->operational_mode = AU8522_DIGITAL_MODE;
+
+	/* Clear out any state associated with the digital side of the
+	   chip, so that when it gets powered back up it won't think
+	   that it is already tuned */
+	state->current_frequency = 0;
+
+	au8522_writereg(state, 0xa4, 1 << 5);
+
+	au8522_i2c_gate_ctrl(fe, 1);
+
+	return 0;
+}
+EXPORT_SYMBOL(au8522_init);
+
+int au8522_sleep(struct dvb_frontend *fe)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	dprintk("%s()\n", __func__);
+
+	/* Only power down if the digital side is currently using the chip */
+	if (state->operational_mode == AU8522_ANALOG_MODE) {
+		/* We're not in one of the expected power modes, which means
+		   that the DVB thread is probably telling us to go to sleep
+		   even though the analog frontend has already started using
+		   the chip.  So ignore the request */
+		return 0;
+	}
+
+	/* turn off led */
+	au8522_led_ctrl(state, 0);
+
+	/* Power down the chip */
+	au8522_writereg(state, 0xa4, 1 << 5);
+
+	state->current_frequency = 0;
+
+	return 0;
+}
+EXPORT_SYMBOL(au8522_sleep);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c
new file mode 100644
index 0000000..5243ba6
--- /dev/null
+++ b/drivers/media/dvb-frontends/au8522_decoder.c
@@ -0,0 +1,839 @@
+/*
+ * Auvitek AU8522 QAM/8VSB demodulator driver and video decoder
+ *
+ * Copyright (C) 2009 Devin Heitmueller <dheitmueller@linuxtv.org>
+ * Copyright (C) 2005-2008 Auvitek International, Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * As published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/* Developer notes:
+ *
+ * VBI support is not yet working
+ * Enough is implemented here for CVBS and S-Video inputs, but the actual
+ *  analog demodulator code isn't implemented (not needed for xc5000 since it
+ *  has its own demodulator and outputs CVBS)
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-device.h>
+#include "au8522.h"
+#include "au8522_priv.h"
+
+MODULE_AUTHOR("Devin Heitmueller");
+MODULE_LICENSE("GPL");
+
+static int au8522_analog_debug;
+
+
+module_param_named(analog_debug, au8522_analog_debug, int, 0644);
+
+MODULE_PARM_DESC(analog_debug,
+		 "Analog debugging messages [0=Off (default) 1=On]");
+
+struct au8522_register_config {
+	u16 reg_name;
+	u8 reg_val[8];
+};
+
+
+/* Video Decoder Filter Coefficients
+   The values are as follows from left to right
+   0="ATV RF" 1="ATV RF13" 2="CVBS" 3="S-Video" 4="PAL" 5=CVBS13" 6="SVideo13"
+*/
+static const struct au8522_register_config filter_coef[] = {
+	{AU8522_FILTER_COEF_R410, {0x25, 0x00, 0x25, 0x25, 0x00, 0x00, 0x00} },
+	{AU8522_FILTER_COEF_R411, {0x20, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00} },
+	{AU8522_FILTER_COEF_R412, {0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00} },
+	{AU8522_FILTER_COEF_R413, {0xe6, 0x00, 0xe6, 0xe6, 0x00, 0x00, 0x00} },
+	{AU8522_FILTER_COEF_R414, {0x40, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00} },
+	{AU8522_FILTER_COEF_R415, {0x1b, 0x00, 0x1b, 0x1b, 0x00, 0x00, 0x00} },
+	{AU8522_FILTER_COEF_R416, {0xc0, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x00} },
+	{AU8522_FILTER_COEF_R417, {0x04, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00} },
+	{AU8522_FILTER_COEF_R418, {0x8c, 0x00, 0x8c, 0x8c, 0x00, 0x00, 0x00} },
+	{AU8522_FILTER_COEF_R419, {0xa0, 0x40, 0xa0, 0xa0, 0x40, 0x40, 0x40} },
+	{AU8522_FILTER_COEF_R41A, {0x21, 0x09, 0x21, 0x21, 0x09, 0x09, 0x09} },
+	{AU8522_FILTER_COEF_R41B, {0x6c, 0x38, 0x6c, 0x6c, 0x38, 0x38, 0x38} },
+	{AU8522_FILTER_COEF_R41C, {0x03, 0xff, 0x03, 0x03, 0xff, 0xff, 0xff} },
+	{AU8522_FILTER_COEF_R41D, {0xbf, 0xc7, 0xbf, 0xbf, 0xc7, 0xc7, 0xc7} },
+	{AU8522_FILTER_COEF_R41E, {0xa0, 0xdf, 0xa0, 0xa0, 0xdf, 0xdf, 0xdf} },
+	{AU8522_FILTER_COEF_R41F, {0x10, 0x06, 0x10, 0x10, 0x06, 0x06, 0x06} },
+	{AU8522_FILTER_COEF_R420, {0xae, 0x30, 0xae, 0xae, 0x30, 0x30, 0x30} },
+	{AU8522_FILTER_COEF_R421, {0xc4, 0x01, 0xc4, 0xc4, 0x01, 0x01, 0x01} },
+	{AU8522_FILTER_COEF_R422, {0x54, 0xdd, 0x54, 0x54, 0xdd, 0xdd, 0xdd} },
+	{AU8522_FILTER_COEF_R423, {0xd0, 0xaf, 0xd0, 0xd0, 0xaf, 0xaf, 0xaf} },
+	{AU8522_FILTER_COEF_R424, {0x1c, 0xf7, 0x1c, 0x1c, 0xf7, 0xf7, 0xf7} },
+	{AU8522_FILTER_COEF_R425, {0x76, 0xdb, 0x76, 0x76, 0xdb, 0xdb, 0xdb} },
+	{AU8522_FILTER_COEF_R426, {0x61, 0xc0, 0x61, 0x61, 0xc0, 0xc0, 0xc0} },
+	{AU8522_FILTER_COEF_R427, {0xd1, 0x2f, 0xd1, 0xd1, 0x2f, 0x2f, 0x2f} },
+	{AU8522_FILTER_COEF_R428, {0x84, 0xd8, 0x84, 0x84, 0xd8, 0xd8, 0xd8} },
+	{AU8522_FILTER_COEF_R429, {0x06, 0xfb, 0x06, 0x06, 0xfb, 0xfb, 0xfb} },
+	{AU8522_FILTER_COEF_R42A, {0x21, 0xd5, 0x21, 0x21, 0xd5, 0xd5, 0xd5} },
+	{AU8522_FILTER_COEF_R42B, {0x0a, 0x3e, 0x0a, 0x0a, 0x3e, 0x3e, 0x3e} },
+	{AU8522_FILTER_COEF_R42C, {0xe6, 0x15, 0xe6, 0xe6, 0x15, 0x15, 0x15} },
+	{AU8522_FILTER_COEF_R42D, {0x01, 0x34, 0x01, 0x01, 0x34, 0x34, 0x34} },
+
+};
+#define NUM_FILTER_COEF (sizeof(filter_coef)\
+			 / sizeof(struct au8522_register_config))
+
+
+/* Registers 0x060b through 0x0652 are the LP Filter coefficients
+   The values are as follows from left to right
+   0="SIF" 1="ATVRF/ATVRF13"
+   Note: the "ATVRF/ATVRF13" mode has never been tested
+*/
+static const struct au8522_register_config lpfilter_coef[] = {
+	{0x060b, {0x21, 0x0b} },
+	{0x060c, {0xad, 0xad} },
+	{0x060d, {0x70, 0xf0} },
+	{0x060e, {0xea, 0xe9} },
+	{0x060f, {0xdd, 0xdd} },
+	{0x0610, {0x08, 0x64} },
+	{0x0611, {0x60, 0x60} },
+	{0x0612, {0xf8, 0xb2} },
+	{0x0613, {0x01, 0x02} },
+	{0x0614, {0xe4, 0xb4} },
+	{0x0615, {0x19, 0x02} },
+	{0x0616, {0xae, 0x2e} },
+	{0x0617, {0xee, 0xc5} },
+	{0x0618, {0x56, 0x56} },
+	{0x0619, {0x30, 0x58} },
+	{0x061a, {0xf9, 0xf8} },
+	{0x061b, {0x24, 0x64} },
+	{0x061c, {0x07, 0x07} },
+	{0x061d, {0x30, 0x30} },
+	{0x061e, {0xa9, 0xed} },
+	{0x061f, {0x09, 0x0b} },
+	{0x0620, {0x42, 0xc2} },
+	{0x0621, {0x1d, 0x2a} },
+	{0x0622, {0xd6, 0x56} },
+	{0x0623, {0x95, 0x8b} },
+	{0x0624, {0x2b, 0x2b} },
+	{0x0625, {0x30, 0x24} },
+	{0x0626, {0x3e, 0x3e} },
+	{0x0627, {0x62, 0xe2} },
+	{0x0628, {0xe9, 0xf5} },
+	{0x0629, {0x99, 0x19} },
+	{0x062a, {0xd4, 0x11} },
+	{0x062b, {0x03, 0x04} },
+	{0x062c, {0xb5, 0x85} },
+	{0x062d, {0x1e, 0x20} },
+	{0x062e, {0x2a, 0xea} },
+	{0x062f, {0xd7, 0xd2} },
+	{0x0630, {0x15, 0x15} },
+	{0x0631, {0xa3, 0xa9} },
+	{0x0632, {0x1f, 0x1f} },
+	{0x0633, {0xf9, 0xd1} },
+	{0x0634, {0xc0, 0xc3} },
+	{0x0635, {0x4d, 0x8d} },
+	{0x0636, {0x21, 0x31} },
+	{0x0637, {0x83, 0x83} },
+	{0x0638, {0x08, 0x8c} },
+	{0x0639, {0x19, 0x19} },
+	{0x063a, {0x45, 0xa5} },
+	{0x063b, {0xef, 0xec} },
+	{0x063c, {0x8a, 0x8a} },
+	{0x063d, {0xf4, 0xf6} },
+	{0x063e, {0x8f, 0x8f} },
+	{0x063f, {0x44, 0x0c} },
+	{0x0640, {0xef, 0xf0} },
+	{0x0641, {0x66, 0x66} },
+	{0x0642, {0xcc, 0xd2} },
+	{0x0643, {0x41, 0x41} },
+	{0x0644, {0x63, 0x93} },
+	{0x0645, {0x8e, 0x8e} },
+	{0x0646, {0xa2, 0x42} },
+	{0x0647, {0x7b, 0x7b} },
+	{0x0648, {0x04, 0x04} },
+	{0x0649, {0x00, 0x00} },
+	{0x064a, {0x40, 0x40} },
+	{0x064b, {0x8c, 0x98} },
+	{0x064c, {0x00, 0x00} },
+	{0x064d, {0x63, 0xc3} },
+	{0x064e, {0x04, 0x04} },
+	{0x064f, {0x20, 0x20} },
+	{0x0650, {0x00, 0x00} },
+	{0x0651, {0x40, 0x40} },
+	{0x0652, {0x01, 0x01} },
+};
+#define NUM_LPFILTER_COEF (sizeof(lpfilter_coef)\
+			   / sizeof(struct au8522_register_config))
+
+static inline struct au8522_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct au8522_state, sd);
+}
+
+static void setup_vbi(struct au8522_state *state, int aud_input)
+{
+	int i;
+
+	/* These are set to zero regardless of what mode we're in */
+	au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H, 0x00);
+	au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_L_REG018H, 0x00);
+	au8522_writereg(state, AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H, 0x00);
+	au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH, 0x00);
+	au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH, 0x00);
+	au8522_writereg(state, AU8522_TVDEC_VBI_USER_THRESH1_REG01CH, 0x00);
+	au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH, 0x00);
+	au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH, 0x00);
+	au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H, 0x00);
+	au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H,
+			0x00);
+	au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H,
+			0x00);
+	au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H,
+			0x00);
+
+	/* Setup the VBI registers */
+	for (i = 0x30; i < 0x60; i++)
+		au8522_writereg(state, i, 0x40);
+
+	/* For some reason, every register is 0x40 except register 0x44
+	   (confirmed via the HVR-950q USB capture) */
+	au8522_writereg(state, 0x44, 0x60);
+
+	/* Enable VBI (we always do this regardless of whether the user is
+	   viewing closed caption info) */
+	au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H,
+			AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON);
+
+}
+
+static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
+{
+	int i;
+	int filter_coef_type;
+
+	/* Provide reasonable defaults for picture tuning values */
+	au8522_writereg(state, AU8522_TVDEC_SHARPNESSREG009H, 0x07);
+	au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH, 0xed);
+	state->brightness = 0xed - 128;
+	au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH, 0x79);
+	state->contrast = 0x79;
+	au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, 0x80);
+	au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, 0x80);
+	state->saturation = 0x80;
+	au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, 0x00);
+	au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, 0x00);
+	state->hue = 0x00;
+
+	/* Other decoder registers */
+	au8522_writereg(state, AU8522_TVDEC_INT_MASK_REG010H, 0x00);
+
+	if (input_mode == 0x23) {
+		/* S-Video input mapping */
+		au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x04);
+	} else {
+		/* All other modes (CVBS/ATVRF etc.) */
+		au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x00);
+	}
+
+	au8522_writereg(state, AU8522_TVDEC_PGA_REG012H,
+			AU8522_TVDEC_PGA_REG012H_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_COMB_MODE_REG015H,
+			AU8522_TVDEC_COMB_MODE_REG015H_CVBS);
+	au8522_writereg(state, AU8522_TVDED_DBG_MODE_REG060H,
+			AU8522_TVDED_DBG_MODE_REG060H_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H,
+			AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525 |
+			AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492 |
+			AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_MN);
+	au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H,
+			AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_NTSC);
+	au8522_writereg(state, AU8522_TVDEC_VCR_DET_LLIM_REG063H,
+			AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_VCR_DET_HLIM_REG064H,
+			AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR1_REG065H,
+			AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR2_REG066H,
+			AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR3_REG067H,
+			AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_COMB_NOTCH_THR_REG068H,
+			AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR1_REG069H,
+			AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR2_REG06AH,
+			AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR3_REG06BH,
+			AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS);
+	if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 ||
+	    input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) {
+		au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
+				AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO);
+		au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
+				AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO);
+	} else {
+		au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
+				AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS);
+		au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
+				AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS);
+	}
+	au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH,
+			AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_UV_SEP_THR_REG06FH,
+			AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H,
+			AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS);
+	au8522_writereg(state, AU8522_REG071H, AU8522_REG071H_CVBS);
+	au8522_writereg(state, AU8522_REG072H, AU8522_REG072H_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H,
+			AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS);
+	au8522_writereg(state, AU8522_REG074H, AU8522_REG074H_CVBS);
+	au8522_writereg(state, AU8522_REG075H, AU8522_REG075H_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_DCAGC_CTRL_REG077H,
+			AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_PIC_START_ADJ_REG078H,
+			AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H,
+			AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH,
+			AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_INTRP_CTRL_REG07BH,
+			AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS);
+	au8522_writereg(state, AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H,
+			AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS);
+	au8522_writereg(state, AU8522_TOREGAAGC_REG0E5H,
+			AU8522_TOREGAAGC_REG0E5H_CVBS);
+	au8522_writereg(state, AU8522_REG016H, AU8522_REG016H_CVBS);
+
+	setup_vbi(state, 0);
+
+	if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 ||
+	    input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) {
+		/* Despite what the table says, for the HVR-950q we still need
+		   to be in CVBS mode for the S-Video input (reason unknown). */
+		/* filter_coef_type = 3; */
+		filter_coef_type = 5;
+	} else {
+		filter_coef_type = 5;
+	}
+
+	/* Load the Video Decoder Filter Coefficients */
+	for (i = 0; i < NUM_FILTER_COEF; i++) {
+		au8522_writereg(state, filter_coef[i].reg_name,
+				filter_coef[i].reg_val[filter_coef_type]);
+	}
+
+	/* It's not clear what these registers are for, but they are always
+	   set to the same value regardless of what mode we're in */
+	au8522_writereg(state, AU8522_REG42EH, 0x87);
+	au8522_writereg(state, AU8522_REG42FH, 0xa2);
+	au8522_writereg(state, AU8522_REG430H, 0xbf);
+	au8522_writereg(state, AU8522_REG431H, 0xcb);
+	au8522_writereg(state, AU8522_REG432H, 0xa1);
+	au8522_writereg(state, AU8522_REG433H, 0x41);
+	au8522_writereg(state, AU8522_REG434H, 0x88);
+	au8522_writereg(state, AU8522_REG435H, 0xc2);
+	au8522_writereg(state, AU8522_REG436H, 0x3c);
+}
+
+static void au8522_setup_cvbs_mode(struct au8522_state *state)
+{
+	/* here we're going to try the pre-programmed route */
+	au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
+			AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
+
+	/* PGA in automatic mode */
+	au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
+
+	/* Enable clamping control */
+	au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
+
+	au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
+			AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
+
+	setup_decoder_defaults(state, AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
+
+	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+			AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
+}
+
+static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state)
+{
+	/* here we're going to try the pre-programmed route */
+	au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
+			AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
+
+	/* It's not clear why we have to have the PGA in automatic mode while
+	   enabling clamp control, but it's what Windows does */
+	au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
+
+	/* Enable clamping control */
+	au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x0e);
+
+	/* Disable automatic PGA (since the CVBS is coming from the tuner) */
+	au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10);
+
+	/* Set input mode to CVBS on channel 4 with SIF audio input enabled */
+	au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
+			AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF);
+
+	setup_decoder_defaults(state,
+			       AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF);
+
+	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+			AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
+}
+
+static void au8522_setup_svideo_mode(struct au8522_state *state)
+{
+	au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
+			AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO);
+
+	/* Set input to Y on Channe1, C on Channel 3 */
+	au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
+			AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
+
+	/* PGA in automatic mode */
+	au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
+
+	/* Enable clamping control */
+	au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
+
+	setup_decoder_defaults(state,
+			       AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
+
+	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+			AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void disable_audio_input(struct au8522_state *state)
+{
+	au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00);
+	au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00);
+	au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00);
+
+	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x04);
+	au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0x02);
+
+	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+			AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO);
+}
+
+/* 0=disable, 1=SIF */
+static void set_audio_input(struct au8522_state *state, int aud_input)
+{
+	int i;
+
+	/* Note that this function needs to be used in conjunction with setting
+	   the input routing via register 0x81 */
+
+	if (aud_input == AU8522_AUDIO_NONE) {
+		disable_audio_input(state);
+		return;
+	}
+
+	if (aud_input != AU8522_AUDIO_SIF) {
+		/* The caller asked for a mode we don't currently support */
+		printk(KERN_ERR "Unsupported audio mode requested! mode=%d\n",
+		       aud_input);
+		return;
+	}
+
+	/* Load the Audio Decoder Filter Coefficients */
+	for (i = 0; i < NUM_LPFILTER_COEF; i++) {
+		au8522_writereg(state, lpfilter_coef[i].reg_name,
+				lpfilter_coef[i].reg_val[0]);
+	}
+
+	/* Setup audio */
+	au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00);
+	au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00);
+	au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00);
+	au8522_writereg(state, AU8522_I2C_CONTROL_REG1_REG091H, 0x80);
+	au8522_writereg(state, AU8522_I2C_CONTROL_REG0_REG090H, 0x84);
+	msleep(150);
+	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x00);
+	msleep(1);
+	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x9d);
+	msleep(50);
+	au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
+	au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
+	au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0xff);
+	msleep(80);
+	au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
+	au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
+	au8522_writereg(state, AU8522_REG0F9H, AU8522_REG0F9H_AUDIO);
+	au8522_writereg(state, AU8522_AUDIO_MODE_REG0F1H, 0x82);
+	msleep(70);
+	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x09);
+	au8522_writereg(state, AU8522_AUDIOFREQ_REG606H, 0x03);
+	au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0xc2);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int au8522_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	struct au8522_state *state = to_state(sd);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		state->brightness = ctrl->value;
+		au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH,
+				ctrl->value - 128);
+		break;
+	case V4L2_CID_CONTRAST:
+		state->contrast = ctrl->value;
+		au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH,
+				ctrl->value);
+		break;
+	case V4L2_CID_SATURATION:
+		state->saturation = ctrl->value;
+		au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH,
+				ctrl->value);
+		au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH,
+				ctrl->value);
+		break;
+	case V4L2_CID_HUE:
+		state->hue = ctrl->value;
+		au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH,
+				ctrl->value >> 8);
+		au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH,
+				ctrl->value & 0xFF);
+		break;
+	case V4L2_CID_AUDIO_VOLUME:
+	case V4L2_CID_AUDIO_BASS:
+	case V4L2_CID_AUDIO_TREBLE:
+	case V4L2_CID_AUDIO_BALANCE:
+	case V4L2_CID_AUDIO_MUTE:
+		/* Not yet implemented */
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int au8522_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	struct au8522_state *state = to_state(sd);
+
+	/* Note that we are using values cached in the state structure instead
+	   of reading the registers due to issues with i2c reads not working
+	   properly/consistently yet on the HVR-950q */
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		ctrl->value = state->brightness;
+		break;
+	case V4L2_CID_CONTRAST:
+		ctrl->value = state->contrast;
+		break;
+	case V4L2_CID_SATURATION:
+		ctrl->value = state->saturation;
+		break;
+	case V4L2_CID_HUE:
+		ctrl->value = state->hue;
+		break;
+	case V4L2_CID_AUDIO_VOLUME:
+	case V4L2_CID_AUDIO_BASS:
+	case V4L2_CID_AUDIO_TREBLE:
+	case V4L2_CID_AUDIO_BALANCE:
+	case V4L2_CID_AUDIO_MUTE:
+		/* Not yet supported */
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int au8522_g_register(struct v4l2_subdev *sd,
+			     struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct au8522_state *state = to_state(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	reg->val = au8522_readreg(state, reg->reg & 0xffff);
+	return 0;
+}
+
+static int au8522_s_register(struct v4l2_subdev *sd,
+			     struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct au8522_state *state = to_state(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	au8522_writereg(state, reg->reg, reg->val & 0xff);
+	return 0;
+}
+#endif
+
+static int au8522_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct au8522_state *state = to_state(sd);
+
+	if (enable) {
+		au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+				0x01);
+		msleep(1);
+		au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+				AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
+	} else {
+		/* This does not completely power down the device
+		   (it only reduces it from around 140ma to 80ma) */
+		au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+				1 << 5);
+	}
+	return 0;
+}
+
+static int au8522_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+	switch (qc->id) {
+	case V4L2_CID_CONTRAST:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1,
+					    AU8522_TVDEC_CONTRAST_REG00BH_CVBS);
+	case V4L2_CID_BRIGHTNESS:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 109);
+	case V4L2_CID_SATURATION:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
+	case V4L2_CID_HUE:
+		return v4l2_ctrl_query_fill(qc, -32768, 32768, 1, 0);
+	default:
+		break;
+	}
+
+	qc->type = 0;
+	return -EINVAL;
+}
+
+static int au8522_reset(struct v4l2_subdev *sd, u32 val)
+{
+	struct au8522_state *state = to_state(sd);
+
+	state->operational_mode = AU8522_ANALOG_MODE;
+
+	/* Clear out any state associated with the digital side of the
+	   chip, so that when it gets powered back up it won't think
+	   that it is already tuned */
+	state->current_frequency = 0;
+
+	au8522_writereg(state, 0xa4, 1 << 5);
+
+	return 0;
+}
+
+static int au8522_s_video_routing(struct v4l2_subdev *sd,
+					u32 input, u32 output, u32 config)
+{
+	struct au8522_state *state = to_state(sd);
+
+	au8522_reset(sd, 0);
+
+	if (input == AU8522_COMPOSITE_CH1) {
+		au8522_setup_cvbs_mode(state);
+	} else if (input == AU8522_SVIDEO_CH13) {
+		au8522_setup_svideo_mode(state);
+	} else if (input == AU8522_COMPOSITE_CH4_SIF) {
+		au8522_setup_cvbs_tuner_mode(state);
+	} else {
+		printk(KERN_ERR "au8522 mode not currently supported\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int au8522_s_audio_routing(struct v4l2_subdev *sd,
+					u32 input, u32 output, u32 config)
+{
+	struct au8522_state *state = to_state(sd);
+	set_audio_input(state, input);
+	return 0;
+}
+
+static int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	int val = 0;
+	struct au8522_state *state = to_state(sd);
+	u8 lock_status;
+
+	/* Interrogate the decoder to see if we are getting a real signal */
+	lock_status = au8522_readreg(state, 0x00);
+	if (lock_status == 0xa2)
+		vt->signal = 0xffff;
+	else
+		vt->signal = 0x00;
+
+	vt->capability |=
+		V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+		V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+
+	val = V4L2_TUNER_SUB_MONO;
+	vt->rxsubchans = val;
+	vt->audmode = V4L2_TUNER_MODE_STEREO;
+	return 0;
+}
+
+static int au8522_g_chip_ident(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_chip_ident *chip)
+{
+	struct au8522_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev);
+}
+
+static int au8522_log_status(struct v4l2_subdev *sd)
+{
+	/* FIXME: Add some status info here */
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops au8522_core_ops = {
+	.log_status = au8522_log_status,
+	.g_chip_ident = au8522_g_chip_ident,
+	.g_ctrl = au8522_g_ctrl,
+	.s_ctrl = au8522_s_ctrl,
+	.queryctrl = au8522_queryctrl,
+	.reset = au8522_reset,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = au8522_g_register,
+	.s_register = au8522_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops au8522_tuner_ops = {
+	.g_tuner = au8522_g_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops au8522_audio_ops = {
+	.s_routing = au8522_s_audio_routing,
+};
+
+static const struct v4l2_subdev_video_ops au8522_video_ops = {
+	.s_routing = au8522_s_video_routing,
+	.s_stream = au8522_s_stream,
+};
+
+static const struct v4l2_subdev_ops au8522_ops = {
+	.core = &au8522_core_ops,
+	.tuner = &au8522_tuner_ops,
+	.audio = &au8522_audio_ops,
+	.video = &au8522_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int au8522_probe(struct i2c_client *client,
+			const struct i2c_device_id *did)
+{
+	struct au8522_state *state;
+	struct v4l2_subdev *sd;
+	int instance;
+	struct au8522_config *demod_config;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_BYTE_DATA)) {
+		return -EIO;
+	}
+
+	/* allocate memory for the internal state */
+	instance = au8522_get_state(&state, client->adapter, client->addr);
+	switch (instance) {
+	case 0:
+		printk(KERN_ERR "au8522_decoder allocation failed\n");
+		return -EIO;
+	case 1:
+		/* new demod instance */
+		printk(KERN_INFO "au8522_decoder creating new instance...\n");
+		break;
+	default:
+		/* existing demod instance */
+		printk(KERN_INFO "au8522_decoder attach existing instance.\n");
+		break;
+	}
+
+	demod_config = kzalloc(sizeof(struct au8522_config), GFP_KERNEL);
+	if (demod_config == NULL) {
+		if (instance == 1)
+			kfree(state);
+		return -ENOMEM;
+	}
+	demod_config->demod_address = 0x8e >> 1;
+
+	state->config = demod_config;
+	state->i2c = client->adapter;
+
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &au8522_ops);
+
+	state->c = client;
+	state->vid_input = AU8522_COMPOSITE_CH1;
+	state->aud_input = AU8522_AUDIO_NONE;
+	state->id = 8522;
+	state->rev = 0;
+
+	/* Jam open the i2c gate to the tuner */
+	au8522_writereg(state, 0x106, 1);
+
+	return 0;
+}
+
+static int au8522_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	v4l2_device_unregister_subdev(sd);
+	au8522_release_state(to_state(sd));
+	return 0;
+}
+
+static const struct i2c_device_id au8522_id[] = {
+	{"au8522", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, au8522_id);
+
+static struct i2c_driver au8522_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "au8522",
+	},
+	.probe		= au8522_probe,
+	.remove		= au8522_remove,
+	.id_table	= au8522_id,
+};
+
+module_i2c_driver(au8522_driver);
diff --git a/drivers/media/dvb-frontends/au8522_dig.c b/drivers/media/dvb-frontends/au8522_dig.c
new file mode 100644
index 0000000..a68974f
--- /dev/null
+++ b/drivers/media/dvb-frontends/au8522_dig.c
@@ -0,0 +1,828 @@
+/*
+    Auvitek AU8522 QAM/8VSB demodulator driver
+
+    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "au8522.h"
+#include "au8522_priv.h"
+
+static int debug;
+
+#define dprintk(arg...)\
+	do { if (debug)\
+		printk(arg);\
+	} while (0)
+
+struct mse2snr_tab {
+	u16 val;
+	u16 data;
+};
+
+/* VSB SNR lookup table */
+static struct mse2snr_tab vsb_mse2snr_tab[] = {
+	{   0, 270 },
+	{   2, 250 },
+	{   3, 240 },
+	{   5, 230 },
+	{   7, 220 },
+	{   9, 210 },
+	{  12, 200 },
+	{  13, 195 },
+	{  15, 190 },
+	{  17, 185 },
+	{  19, 180 },
+	{  21, 175 },
+	{  24, 170 },
+	{  27, 165 },
+	{  31, 160 },
+	{  32, 158 },
+	{  33, 156 },
+	{  36, 152 },
+	{  37, 150 },
+	{  39, 148 },
+	{  40, 146 },
+	{  41, 144 },
+	{  43, 142 },
+	{  44, 140 },
+	{  48, 135 },
+	{  50, 130 },
+	{  43, 142 },
+	{  53, 125 },
+	{  56, 120 },
+	{ 256, 115 },
+};
+
+/* QAM64 SNR lookup table */
+static struct mse2snr_tab qam64_mse2snr_tab[] = {
+	{  15,   0 },
+	{  16, 290 },
+	{  17, 288 },
+	{  18, 286 },
+	{  19, 284 },
+	{  20, 282 },
+	{  21, 281 },
+	{  22, 279 },
+	{  23, 277 },
+	{  24, 275 },
+	{  25, 273 },
+	{  26, 271 },
+	{  27, 269 },
+	{  28, 268 },
+	{  29, 266 },
+	{  30, 264 },
+	{  31, 262 },
+	{  32, 260 },
+	{  33, 259 },
+	{  34, 258 },
+	{  35, 256 },
+	{  36, 255 },
+	{  37, 254 },
+	{  38, 252 },
+	{  39, 251 },
+	{  40, 250 },
+	{  41, 249 },
+	{  42, 248 },
+	{  43, 246 },
+	{  44, 245 },
+	{  45, 244 },
+	{  46, 242 },
+	{  47, 241 },
+	{  48, 240 },
+	{  50, 239 },
+	{  51, 238 },
+	{  53, 237 },
+	{  54, 236 },
+	{  56, 235 },
+	{  57, 234 },
+	{  59, 233 },
+	{  60, 232 },
+	{  62, 231 },
+	{  63, 230 },
+	{  65, 229 },
+	{  67, 228 },
+	{  68, 227 },
+	{  70, 226 },
+	{  71, 225 },
+	{  73, 224 },
+	{  74, 223 },
+	{  76, 222 },
+	{  78, 221 },
+	{  80, 220 },
+	{  82, 219 },
+	{  85, 218 },
+	{  88, 217 },
+	{  90, 216 },
+	{  92, 215 },
+	{  93, 214 },
+	{  94, 212 },
+	{  95, 211 },
+	{  97, 210 },
+	{  99, 209 },
+	{ 101, 208 },
+	{ 102, 207 },
+	{ 104, 206 },
+	{ 107, 205 },
+	{ 111, 204 },
+	{ 114, 203 },
+	{ 118, 202 },
+	{ 122, 201 },
+	{ 125, 200 },
+	{ 128, 199 },
+	{ 130, 198 },
+	{ 132, 197 },
+	{ 256, 190 },
+};
+
+/* QAM256 SNR lookup table */
+static struct mse2snr_tab qam256_mse2snr_tab[] = {
+	{  15,   0 },
+	{  16, 400 },
+	{  17, 398 },
+	{  18, 396 },
+	{  19, 394 },
+	{  20, 392 },
+	{  21, 390 },
+	{  22, 388 },
+	{  23, 386 },
+	{  24, 384 },
+	{  25, 382 },
+	{  26, 380 },
+	{  27, 379 },
+	{  28, 378 },
+	{  29, 377 },
+	{  30, 376 },
+	{  31, 375 },
+	{  32, 374 },
+	{  33, 373 },
+	{  34, 372 },
+	{  35, 371 },
+	{  36, 370 },
+	{  37, 362 },
+	{  38, 354 },
+	{  39, 346 },
+	{  40, 338 },
+	{  41, 330 },
+	{  42, 328 },
+	{  43, 326 },
+	{  44, 324 },
+	{  45, 322 },
+	{  46, 320 },
+	{  47, 319 },
+	{  48, 318 },
+	{  49, 317 },
+	{  50, 316 },
+	{  51, 315 },
+	{  52, 314 },
+	{  53, 313 },
+	{  54, 312 },
+	{  55, 311 },
+	{  56, 310 },
+	{  57, 308 },
+	{  58, 306 },
+	{  59, 304 },
+	{  60, 302 },
+	{  61, 300 },
+	{  62, 298 },
+	{  65, 295 },
+	{  68, 294 },
+	{  70, 293 },
+	{  73, 292 },
+	{  76, 291 },
+	{  78, 290 },
+	{  79, 289 },
+	{  81, 288 },
+	{  82, 287 },
+	{  83, 286 },
+	{  84, 285 },
+	{  85, 284 },
+	{  86, 283 },
+	{  88, 282 },
+	{  89, 281 },
+	{ 256, 280 },
+};
+
+static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
+				 u16 *snr)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __func__);
+
+	for (i = 0; i < sz; i++) {
+		if (mse < tab[i].val) {
+			*snr = tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	dprintk("%s() snr=%d\n", __func__, *snr);
+	return ret;
+}
+
+static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	u8 r0b5, r0b6, r0b7;
+	char *ifmhz;
+
+	switch (if_freq) {
+	case AU8522_IF_3_25MHZ:
+		ifmhz = "3.25";
+		r0b5 = 0x00;
+		r0b6 = 0x3d;
+		r0b7 = 0xa0;
+		break;
+	case AU8522_IF_4MHZ:
+		ifmhz = "4.00";
+		r0b5 = 0x00;
+		r0b6 = 0x4b;
+		r0b7 = 0xd9;
+		break;
+	case AU8522_IF_6MHZ:
+		ifmhz = "6.00";
+		r0b5 = 0xfb;
+		r0b6 = 0x8e;
+		r0b7 = 0x39;
+		break;
+	default:
+		dprintk("%s() IF Frequency not supported\n", __func__);
+		return -EINVAL;
+	}
+	dprintk("%s() %s MHz\n", __func__, ifmhz);
+	au8522_writereg(state, 0x80b5, r0b5);
+	au8522_writereg(state, 0x80b6, r0b6);
+	au8522_writereg(state, 0x80b7, r0b7);
+
+	return 0;
+}
+
+/* VSB Modulation table */
+static struct {
+	u16 reg;
+	u16 data;
+} VSB_mod_tab[] = {
+	{ 0x8090, 0x84 },
+	{ 0x4092, 0x11 },
+	{ 0x2005, 0x00 },
+	{ 0x8091, 0x80 },
+	{ 0x80a3, 0x0c },
+	{ 0x80a4, 0xe8 },
+	{ 0x8081, 0xc4 },
+	{ 0x80a5, 0x40 },
+	{ 0x80a7, 0x40 },
+	{ 0x80a6, 0x67 },
+	{ 0x8262, 0x20 },
+	{ 0x821c, 0x30 },
+	{ 0x80d8, 0x1a },
+	{ 0x8227, 0xa0 },
+	{ 0x8121, 0xff },
+	{ 0x80a8, 0xf0 },
+	{ 0x80a9, 0x05 },
+	{ 0x80aa, 0x77 },
+	{ 0x80ab, 0xf0 },
+	{ 0x80ac, 0x05 },
+	{ 0x80ad, 0x77 },
+	{ 0x80ae, 0x41 },
+	{ 0x80af, 0x66 },
+	{ 0x821b, 0xcc },
+	{ 0x821d, 0x80 },
+	{ 0x80a4, 0xe8 },
+	{ 0x8231, 0x13 },
+};
+
+/* QAM64 Modulation table */
+static struct {
+	u16 reg;
+	u16 data;
+} QAM64_mod_tab[] = {
+	{ 0x00a3, 0x09 },
+	{ 0x00a4, 0x00 },
+	{ 0x0081, 0xc4 },
+	{ 0x00a5, 0x40 },
+	{ 0x00aa, 0x77 },
+	{ 0x00ad, 0x77 },
+	{ 0x00a6, 0x67 },
+	{ 0x0262, 0x20 },
+	{ 0x021c, 0x30 },
+	{ 0x00b8, 0x3e },
+	{ 0x00b9, 0xf0 },
+	{ 0x00ba, 0x01 },
+	{ 0x00bb, 0x18 },
+	{ 0x00bc, 0x50 },
+	{ 0x00bd, 0x00 },
+	{ 0x00be, 0xea },
+	{ 0x00bf, 0xef },
+	{ 0x00c0, 0xfc },
+	{ 0x00c1, 0xbd },
+	{ 0x00c2, 0x1f },
+	{ 0x00c3, 0xfc },
+	{ 0x00c4, 0xdd },
+	{ 0x00c5, 0xaf },
+	{ 0x00c6, 0x00 },
+	{ 0x00c7, 0x38 },
+	{ 0x00c8, 0x30 },
+	{ 0x00c9, 0x05 },
+	{ 0x00ca, 0x4a },
+	{ 0x00cb, 0xd0 },
+	{ 0x00cc, 0x01 },
+	{ 0x00cd, 0xd9 },
+	{ 0x00ce, 0x6f },
+	{ 0x00cf, 0xf9 },
+	{ 0x00d0, 0x70 },
+	{ 0x00d1, 0xdf },
+	{ 0x00d2, 0xf7 },
+	{ 0x00d3, 0xc2 },
+	{ 0x00d4, 0xdf },
+	{ 0x00d5, 0x02 },
+	{ 0x00d6, 0x9a },
+	{ 0x00d7, 0xd0 },
+	{ 0x0250, 0x0d },
+	{ 0x0251, 0xcd },
+	{ 0x0252, 0xe0 },
+	{ 0x0253, 0x05 },
+	{ 0x0254, 0xa7 },
+	{ 0x0255, 0xff },
+	{ 0x0256, 0xed },
+	{ 0x0257, 0x5b },
+	{ 0x0258, 0xae },
+	{ 0x0259, 0xe6 },
+	{ 0x025a, 0x3d },
+	{ 0x025b, 0x0f },
+	{ 0x025c, 0x0d },
+	{ 0x025d, 0xea },
+	{ 0x025e, 0xf2 },
+	{ 0x025f, 0x51 },
+	{ 0x0260, 0xf5 },
+	{ 0x0261, 0x06 },
+	{ 0x021a, 0x00 },
+	{ 0x0546, 0x40 },
+	{ 0x0210, 0xc7 },
+	{ 0x0211, 0xaa },
+	{ 0x0212, 0xab },
+	{ 0x0213, 0x02 },
+	{ 0x0502, 0x00 },
+	{ 0x0121, 0x04 },
+	{ 0x0122, 0x04 },
+	{ 0x052e, 0x10 },
+	{ 0x00a4, 0xca },
+	{ 0x00a7, 0x40 },
+	{ 0x0526, 0x01 },
+};
+
+/* QAM256 Modulation table */
+static struct {
+	u16 reg;
+	u16 data;
+} QAM256_mod_tab[] = {
+	{ 0x80a3, 0x09 },
+	{ 0x80a4, 0x00 },
+	{ 0x8081, 0xc4 },
+	{ 0x80a5, 0x40 },
+	{ 0x80aa, 0x77 },
+	{ 0x80ad, 0x77 },
+	{ 0x80a6, 0x67 },
+	{ 0x8262, 0x20 },
+	{ 0x821c, 0x30 },
+	{ 0x80b8, 0x3e },
+	{ 0x80b9, 0xf0 },
+	{ 0x80ba, 0x01 },
+	{ 0x80bb, 0x18 },
+	{ 0x80bc, 0x50 },
+	{ 0x80bd, 0x00 },
+	{ 0x80be, 0xea },
+	{ 0x80bf, 0xef },
+	{ 0x80c0, 0xfc },
+	{ 0x80c1, 0xbd },
+	{ 0x80c2, 0x1f },
+	{ 0x80c3, 0xfc },
+	{ 0x80c4, 0xdd },
+	{ 0x80c5, 0xaf },
+	{ 0x80c6, 0x00 },
+	{ 0x80c7, 0x38 },
+	{ 0x80c8, 0x30 },
+	{ 0x80c9, 0x05 },
+	{ 0x80ca, 0x4a },
+	{ 0x80cb, 0xd0 },
+	{ 0x80cc, 0x01 },
+	{ 0x80cd, 0xd9 },
+	{ 0x80ce, 0x6f },
+	{ 0x80cf, 0xf9 },
+	{ 0x80d0, 0x70 },
+	{ 0x80d1, 0xdf },
+	{ 0x80d2, 0xf7 },
+	{ 0x80d3, 0xc2 },
+	{ 0x80d4, 0xdf },
+	{ 0x80d5, 0x02 },
+	{ 0x80d6, 0x9a },
+	{ 0x80d7, 0xd0 },
+	{ 0x8250, 0x0d },
+	{ 0x8251, 0xcd },
+	{ 0x8252, 0xe0 },
+	{ 0x8253, 0x05 },
+	{ 0x8254, 0xa7 },
+	{ 0x8255, 0xff },
+	{ 0x8256, 0xed },
+	{ 0x8257, 0x5b },
+	{ 0x8258, 0xae },
+	{ 0x8259, 0xe6 },
+	{ 0x825a, 0x3d },
+	{ 0x825b, 0x0f },
+	{ 0x825c, 0x0d },
+	{ 0x825d, 0xea },
+	{ 0x825e, 0xf2 },
+	{ 0x825f, 0x51 },
+	{ 0x8260, 0xf5 },
+	{ 0x8261, 0x06 },
+	{ 0x821a, 0x00 },
+	{ 0x8546, 0x40 },
+	{ 0x8210, 0x26 },
+	{ 0x8211, 0xf6 },
+	{ 0x8212, 0x84 },
+	{ 0x8213, 0x02 },
+	{ 0x8502, 0x01 },
+	{ 0x8121, 0x04 },
+	{ 0x8122, 0x04 },
+	{ 0x852e, 0x10 },
+	{ 0x80a4, 0xca },
+	{ 0x80a7, 0x40 },
+	{ 0x8526, 0x01 },
+};
+
+static int au8522_enable_modulation(struct dvb_frontend *fe,
+				    fe_modulation_t m)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	int i;
+
+	dprintk("%s(0x%08x)\n", __func__, m);
+
+	switch (m) {
+	case VSB_8:
+		dprintk("%s() VSB_8\n", __func__);
+		for (i = 0; i < ARRAY_SIZE(VSB_mod_tab); i++)
+			au8522_writereg(state,
+				VSB_mod_tab[i].reg,
+				VSB_mod_tab[i].data);
+		au8522_set_if(fe, state->config->vsb_if);
+		break;
+	case QAM_64:
+		dprintk("%s() QAM 64\n", __func__);
+		for (i = 0; i < ARRAY_SIZE(QAM64_mod_tab); i++)
+			au8522_writereg(state,
+				QAM64_mod_tab[i].reg,
+				QAM64_mod_tab[i].data);
+		au8522_set_if(fe, state->config->qam_if);
+		break;
+	case QAM_256:
+		dprintk("%s() QAM 256\n", __func__);
+		for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++)
+			au8522_writereg(state,
+				QAM256_mod_tab[i].reg,
+				QAM256_mod_tab[i].data);
+		au8522_set_if(fe, state->config->qam_if);
+		break;
+	default:
+		dprintk("%s() Invalid modulation\n", __func__);
+		return -EINVAL;
+	}
+
+	state->current_modulation = m;
+
+	return 0;
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int au8522_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct au8522_state *state = fe->demodulator_priv;
+	int ret = -EINVAL;
+
+	dprintk("%s(frequency=%d)\n", __func__, c->frequency);
+
+	if ((state->current_frequency == c->frequency) &&
+	    (state->current_modulation == c->modulation))
+		return 0;
+
+	if (fe->ops.tuner_ops.set_params) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		ret = fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	if (ret < 0)
+		return ret;
+
+	/* Allow the tuner to settle */
+	msleep(100);
+
+	au8522_enable_modulation(fe, c->modulation);
+
+	state->current_frequency = c->frequency;
+
+	return 0;
+}
+
+static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	u8 reg;
+	u32 tuner_status = 0;
+
+	*status = 0;
+
+	if (state->current_modulation == VSB_8) {
+		dprintk("%s() Checking VSB_8\n", __func__);
+		reg = au8522_readreg(state, 0x4088);
+		if ((reg & 0x03) == 0x03)
+			*status |= FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
+	} else {
+		dprintk("%s() Checking QAM\n", __func__);
+		reg = au8522_readreg(state, 0x4541);
+		if (reg & 0x80)
+			*status |= FE_HAS_VITERBI;
+		if (reg & 0x20)
+			*status |= FE_HAS_LOCK | FE_HAS_SYNC;
+	}
+
+	switch (state->config->status_mode) {
+	case AU8522_DEMODLOCKING:
+		dprintk("%s() DEMODLOCKING\n", __func__);
+		if (*status & FE_HAS_VITERBI)
+			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+		break;
+	case AU8522_TUNERLOCKING:
+		/* Get the tuner status */
+		dprintk("%s() TUNERLOCKING\n", __func__);
+		if (fe->ops.tuner_ops.get_status) {
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 1);
+
+			fe->ops.tuner_ops.get_status(fe, &tuner_status);
+
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+		if (tuner_status)
+			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+		break;
+	}
+	state->fe_status = *status;
+
+	if (*status & FE_HAS_LOCK)
+		/* turn on LED, if it isn't on already */
+		au8522_led_ctrl(state, -1);
+	else
+		/* turn off LED */
+		au8522_led_ctrl(state, 0);
+
+	dprintk("%s() status 0x%08x\n", __func__, *status);
+
+	return 0;
+}
+
+static int au8522_led_status(struct au8522_state *state, const u16 *snr)
+{
+	struct au8522_led_config *led_config = state->config->led_cfg;
+	int led;
+	u16 strong;
+
+	/* bail out if we can't control an LED */
+	if (!led_config)
+		return 0;
+
+	if (0 == (state->fe_status & FE_HAS_LOCK))
+		return au8522_led_ctrl(state, 0);
+	else if (state->current_modulation == QAM_256)
+		strong = led_config->qam256_strong;
+	else if (state->current_modulation == QAM_64)
+		strong = led_config->qam64_strong;
+	else /* (state->current_modulation == VSB_8) */
+		strong = led_config->vsb8_strong;
+
+	if (*snr >= strong)
+		led = 2;
+	else
+		led = 1;
+
+	if ((state->led_state) &&
+	    (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10))
+		/* snr didn't change enough to bother
+		 * changing the color of the led */
+		return 0;
+
+	return au8522_led_ctrl(state, led);
+}
+
+static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	int ret = -EINVAL;
+
+	dprintk("%s()\n", __func__);
+
+	if (state->current_modulation == QAM_256)
+		ret = au8522_mse2snr_lookup(qam256_mse2snr_tab,
+					    ARRAY_SIZE(qam256_mse2snr_tab),
+					    au8522_readreg(state, 0x4522),
+					    snr);
+	else if (state->current_modulation == QAM_64)
+		ret = au8522_mse2snr_lookup(qam64_mse2snr_tab,
+					    ARRAY_SIZE(qam64_mse2snr_tab),
+					    au8522_readreg(state, 0x4522),
+					    snr);
+	else /* VSB_8 */
+		ret = au8522_mse2snr_lookup(vsb_mse2snr_tab,
+					    ARRAY_SIZE(vsb_mse2snr_tab),
+					    au8522_readreg(state, 0x4311),
+					    snr);
+
+	if (state->config->led_cfg)
+		au8522_led_status(state, snr);
+
+	return ret;
+}
+
+static int au8522_read_signal_strength(struct dvb_frontend *fe,
+				       u16 *signal_strength)
+{
+	/* borrowed from lgdt330x.c
+	 *
+	 * Calculate strength from SNR up to 35dB
+	 * Even though the SNR can go higher than 35dB,
+	 * there is some comfort factor in having a range of
+	 * strong signals that can show at 100%
+	 */
+	u16 snr;
+	u32 tmp;
+	int ret = au8522_read_snr(fe, &snr);
+
+	*signal_strength = 0;
+
+	if (0 == ret) {
+		/* The following calculation method was chosen
+		 * purely for the sake of code re-use from the
+		 * other demod drivers that use this method */
+
+		/* Convert from SNR in dB * 10 to 8.24 fixed-point */
+		tmp = (snr * ((1 << 24) / 10));
+
+		/* Convert from 8.24 fixed-point to
+		 * scale the range 0 - 35*2^24 into 0 - 65535*/
+		if (tmp >= 8960 * 0x10000)
+			*signal_strength = 0xffff;
+		else
+			*signal_strength = tmp / 8960;
+	}
+
+	return ret;
+}
+
+static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+
+	if (state->current_modulation == VSB_8)
+		*ucblocks = au8522_readreg(state, 0x4087);
+	else
+		*ucblocks = au8522_readreg(state, 0x4543);
+
+	return 0;
+}
+
+static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	return au8522_read_ucblocks(fe, ber);
+}
+
+static int au8522_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct au8522_state *state = fe->demodulator_priv;
+
+	c->frequency = state->current_frequency;
+	c->modulation = state->current_modulation;
+
+	return 0;
+}
+
+static int au8522_get_tune_settings(struct dvb_frontend *fe,
+				    struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	return 0;
+}
+
+static struct dvb_frontend_ops au8522_ops;
+
+
+static void au8522_release(struct dvb_frontend *fe)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	au8522_release_state(state);
+}
+
+struct dvb_frontend *au8522_attach(const struct au8522_config *config,
+				   struct i2c_adapter *i2c)
+{
+	struct au8522_state *state = NULL;
+	int instance;
+
+	/* allocate memory for the internal state */
+	instance = au8522_get_state(&state, i2c, config->demod_address);
+	switch (instance) {
+	case 0:
+		dprintk("%s state allocation failed\n", __func__);
+		break;
+	case 1:
+		/* new demod instance */
+		dprintk("%s using new instance\n", __func__);
+		break;
+	default:
+		/* existing demod instance */
+		dprintk("%s using existing instance\n", __func__);
+		break;
+	}
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->operational_mode = AU8522_DIGITAL_MODE;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &au8522_ops,
+	       sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	state->frontend.ops.analog_ops.i2c_gate_ctrl = au8522_analog_i2c_gate_ctrl;
+
+	if (au8522_init(&state->frontend) != 0) {
+		printk(KERN_ERR "%s: Failed to initialize correctly\n",
+			__func__);
+		goto error;
+	}
+
+	/* Note: Leaving the I2C gate open here. */
+	au8522_i2c_gate_ctrl(&state->frontend, 1);
+
+	return &state->frontend;
+
+error:
+	au8522_release_state(state);
+	return NULL;
+}
+EXPORT_SYMBOL(au8522_attach);
+
+static struct dvb_frontend_ops au8522_ops = {
+	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
+	.info = {
+		.name			= "Auvitek AU8522 QAM/8VSB Frontend",
+		.frequency_min		= 54000000,
+		.frequency_max		= 858000000,
+		.frequency_stepsize	= 62500,
+		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+	},
+
+	.init                 = au8522_init,
+	.sleep                = au8522_sleep,
+	.i2c_gate_ctrl        = au8522_i2c_gate_ctrl,
+	.set_frontend         = au8522_set_frontend,
+	.get_frontend         = au8522_get_frontend,
+	.get_tune_settings    = au8522_get_tune_settings,
+	.read_status          = au8522_read_status,
+	.read_ber             = au8522_read_ber,
+	.read_signal_strength = au8522_read_signal_strength,
+	.read_snr             = au8522_read_snr,
+	.read_ucblocks        = au8522_read_ucblocks,
+	.release              = au8522_release,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/au8522_priv.h b/drivers/media/dvb-frontends/au8522_priv.h
new file mode 100644
index 0000000..0529699
--- /dev/null
+++ b/drivers/media/dvb-frontends/au8522_priv.h
@@ -0,0 +1,446 @@
+/*
+    Auvitek AU8522 QAM/8VSB demodulator driver
+
+    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+    Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org>
+    Copyright (C) 2005-2008 Auvitek International, Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+#include "au8522.h"
+#include "tuner-i2c.h"
+
+#define AU8522_ANALOG_MODE 0
+#define AU8522_DIGITAL_MODE 1
+
+struct au8522_state {
+	struct i2c_client *c;
+	struct i2c_adapter *i2c;
+
+	u8 operational_mode;
+
+	/* Used for sharing of the state between analog and digital mode */
+	struct tuner_i2c_props i2c_props;
+	struct list_head hybrid_tuner_instance_list;
+
+	/* configuration settings */
+	const struct au8522_config *config;
+
+	struct dvb_frontend frontend;
+
+	u32 current_frequency;
+	fe_modulation_t current_modulation;
+
+	u32 fe_status;
+	unsigned int led_state;
+
+	/* Analog settings */
+	struct v4l2_subdev sd;
+	v4l2_std_id std;
+	int vid_input;
+	int aud_input;
+	u32 id;
+	u32 rev;
+	u8 brightness;
+	u8 contrast;
+	u8 saturation;
+	s16 hue;
+};
+
+/* These are routines shared by both the VSB/QAM demodulator and the analog
+   decoder */
+int au8522_writereg(struct au8522_state *state, u16 reg, u8 data);
+u8 au8522_readreg(struct au8522_state *state, u16 reg);
+int au8522_init(struct dvb_frontend *fe);
+int au8522_sleep(struct dvb_frontend *fe);
+
+int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
+		     u8 client_address);
+void au8522_release_state(struct au8522_state *state);
+int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
+int au8522_analog_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
+int au8522_led_ctrl(struct au8522_state *state, int led);
+
+/* REGISTERS */
+#define AU8522_INPUT_CONTROL_REG081H			0x081
+#define AU8522_PGA_CONTROL_REG082H			0x082
+#define AU8522_CLAMPING_CONTROL_REG083H			0x083
+
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H		0x0A3
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H		0x0A4
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H		0x0A5
+#define AU8522_AGC_CONTROL_RANGE_REG0A6H		0x0A6
+#define AU8522_SYSTEM_GAIN_CONTROL_REG0A7H		0x0A7
+#define AU8522_TUNER_AGC_RF_STOP_REG0A8H  		0x0A8
+#define AU8522_TUNER_AGC_RF_START_REG0A9H		0x0A9
+#define AU8522_TUNER_RF_AGC_DEFAULT_REG0AAH		0x0AA
+#define AU8522_TUNER_AGC_IF_STOP_REG0ABH		0x0AB
+#define AU8522_TUNER_AGC_IF_START_REG0ACH		0x0AC
+#define AU8522_TUNER_AGC_IF_DEFAULT_REG0ADH		0x0AD
+#define AU8522_TUNER_AGC_STEP_REG0AEH			0x0AE
+#define AU8522_TUNER_GAIN_STEP_REG0AFH			0x0AF
+
+/* Receiver registers */
+#define AU8522_FRMREGTHRD1_REG0B0H			0x0B0
+#define AU8522_FRMREGAGC1H_REG0B1H 			0x0B1
+#define AU8522_FRMREGSHIFT1_REG0B2H 			0x0B2
+#define AU8522_TOREGAGC1_REG0B3H 			0x0B3
+#define AU8522_TOREGASHIFT1_REG0B4H 			0x0B4
+#define AU8522_FRMREGBBH_REG0B5H			0x0B5
+#define AU8522_FRMREGBBM_REG0B6H 			0x0B6
+#define AU8522_FRMREGBBL_REG0B7H     			0x0B7
+/* 0xB8 TO 0xD7 are the filter coefficients */
+#define AU8522_FRMREGTHRD2_REG0D8H 			0x0D8
+#define AU8522_FRMREGAGC2H_REG0D9H 			0x0D9
+#define AU8522_TOREGAGC2_REG0DAH 			0x0DA
+#define AU8522_TOREGSHIFT2_REG0DBH 			0x0DB
+#define AU8522_FRMREGPILOTH_REG0DCH			0x0DC
+#define AU8522_FRMREGPILOTM_REG0DDH			0x0DD
+#define AU8522_FRMREGPILOTL_REG0DEH			0x0DE
+#define AU8522_TOREGFREQ_REG0DFH			0x0DF
+
+#define AU8522_RX_PGA_RFOUT_REG0EBH			0x0EB
+#define AU8522_RX_PGA_IFOUT_REG0ECH			0x0EC
+#define AU8522_RX_PGA_PGAOUT_REG0EDH			0x0ED
+
+#define AU8522_CHIP_MODE_REG0FEH			0x0FE
+
+/* I2C bus control registers */
+#define AU8522_I2C_CONTROL_REG0_REG090H    		0x090
+#define AU8522_I2C_CONTROL_REG1_REG091H    		0x091
+#define AU8522_I2C_STATUS_REG092H          		0x092
+#define AU8522_I2C_WR_DATA0_REG093H			0x093
+#define AU8522_I2C_WR_DATA1_REG094H			0x094
+#define AU8522_I2C_WR_DATA2_REG095H			0x095
+#define AU8522_I2C_WR_DATA3_REG096H			0x096
+#define AU8522_I2C_WR_DATA4_REG097H			0x097
+#define AU8522_I2C_WR_DATA5_REG098H			0x098
+#define AU8522_I2C_WR_DATA6_REG099H			0x099
+#define AU8522_I2C_WR_DATA7_REG09AH			0x09A
+#define AU8522_I2C_RD_DATA0_REG09BH			0x09B
+#define AU8522_I2C_RD_DATA1_REG09CH			0x09C
+#define AU8522_I2C_RD_DATA2_REG09DH			0x09D
+#define AU8522_I2C_RD_DATA3_REG09EH			0x09E
+#define AU8522_I2C_RD_DATA4_REG09FH			0x09F
+#define AU8522_I2C_RD_DATA5_REG0A0H			0x0A0
+#define AU8522_I2C_RD_DATA6_REG0A1H			0x0A1
+#define AU8522_I2C_RD_DATA7_REG0A2H			0x0A2
+
+#define AU8522_ENA_USB_REG101H				0x101
+
+#define AU8522_I2S_CTRL_0_REG110H  			0x110
+#define AU8522_I2S_CTRL_1_REG111H 			0x111
+#define AU8522_I2S_CTRL_2_REG112H 			0x112
+
+#define AU8522_FRMREGFFECONTROL_REG121H    		0x121
+#define AU8522_FRMREGDFECONTROL_REG122H    		0x122
+
+#define AU8522_CARRFREQOFFSET0_REG201H 			0x201
+#define AU8522_CARRFREQOFFSET1_REG202H			0x202
+
+#define AU8522_DECIMATION_GAIN_REG21AH			0x21A
+#define AU8522_FRMREGIFSLP_REG21BH 			0x21B
+#define AU8522_FRMREGTHRDL2_REG21CH 			0x21C
+#define AU8522_FRMREGSTEP3DB_REG21DH 			0x21D
+#define AU8522_DAGC_GAIN_ADJUSTMENT_REG21EH		0x21E
+#define AU8522_FRMREGPLLMODE_REG21FH 			0x21F
+#define AU8522_FRMREGCSTHRD_REG220H 			0x220
+#define AU8522_FRMREGCRLOCKDMAX_REG221H 		0x221
+#define AU8522_FRMREGCRPERIODMASK_REG222H 		0x222
+#define AU8522_FRMREGCRLOCK0THH_REG223H 		0x223
+#define AU8522_FRMREGCRLOCK1THH_REG224H 		0x224
+#define AU8522_FRMREGCRLOCK0THL_REG225H 		0x225
+#define AU8522_FRMREGCRLOCK1THL_REG226H 		0x226
+#define AU_FRMREGPLLACQPHASESCL_REG227H			0x227
+#define AU8522_FRMREGFREQFBCTRL_REG228H 		0x228
+
+/* Analog TV Decoder */
+#define AU8522_TVDEC_STATUS_REG000H			0x000
+#define AU8522_TVDEC_INT_STATUS_REG001H			0x001
+#define AU8522_TVDEC_MACROVISION_STATUS_REG002H 	0x002
+#define AU8522_TVDEC_SHARPNESSREG009H			0x009
+#define AU8522_TVDEC_BRIGHTNESS_REG00AH			0x00A
+#define AU8522_TVDEC_CONTRAST_REG00BH			0x00B
+#define AU8522_TVDEC_SATURATION_CB_REG00CH		0x00C
+#define AU8522_TVDEC_SATURATION_CR_REG00DH		0x00D
+#define AU8522_TVDEC_HUE_H_REG00EH			0x00E
+#define AU8522_TVDEC_HUE_L_REG00FH                   	0x00F
+#define AU8522_TVDEC_INT_MASK_REG010H			0x010
+#define AU8522_VIDEO_MODE_REG011H			0x011
+#define AU8522_TVDEC_PGA_REG012H			0x012
+#define AU8522_TVDEC_COMB_MODE_REG015H			0x015
+#define AU8522_REG016H                            	0x016
+#define AU8522_TVDED_DBG_MODE_REG060H			0x060
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H		0x061
+#define AU8522_TVDEC_FORMAT_CTRL2_REG062H		0x062
+#define AU8522_TVDEC_VCR_DET_LLIM_REG063H		0x063
+#define AU8522_TVDEC_VCR_DET_HLIM_REG064H		0x064
+#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H		0x065
+#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H		0x066
+#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H		0x067
+#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H		0x068
+#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H   		0x069
+#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH		0x06A
+#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH   		0x06B
+#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH  		0x06C
+#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH 		0x06D
+#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH       	0x06E
+#define AU8522_TVDEC_UV_SEP_THR_REG06FH  		0x06F
+#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H		0x070
+#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H		0x073
+#define AU8522_TVDEC_DCAGC_CTRL_REG077H			0x077
+#define AU8522_TVDEC_PIC_START_ADJ_REG078H		0x078
+#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H		0x079
+#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH	0x07A
+#define AU8522_TVDEC_INTRP_CTRL_REG07BH			0x07B
+#define AU8522_TVDEC_PLL_STATUS_REG07EH			0x07E
+#define AU8522_TVDEC_FSC_FREQ_REG07FH			0x07F
+
+#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H		0x0E4
+#define AU8522_TOREGAAGC_REG0E5H			0x0E5
+
+#define AU8522_TVDEC_CHROMA_AGC_REG401H		0x401
+#define AU8522_TVDEC_CHROMA_SFT_REG402H		0x402
+#define AU8522_FILTER_COEF_R410     		0x410
+#define AU8522_FILTER_COEF_R411     		0x411
+#define AU8522_FILTER_COEF_R412     		0x412
+#define AU8522_FILTER_COEF_R413     		0x413
+#define AU8522_FILTER_COEF_R414     		0x414
+#define AU8522_FILTER_COEF_R415     		0x415
+#define AU8522_FILTER_COEF_R416     		0x416
+#define AU8522_FILTER_COEF_R417     		0x417
+#define AU8522_FILTER_COEF_R418     		0x418
+#define AU8522_FILTER_COEF_R419     		0x419
+#define AU8522_FILTER_COEF_R41A     		0x41A
+#define AU8522_FILTER_COEF_R41B     		0x41B
+#define AU8522_FILTER_COEF_R41C     		0x41C
+#define AU8522_FILTER_COEF_R41D     		0x41D
+#define AU8522_FILTER_COEF_R41E     		0x41E
+#define AU8522_FILTER_COEF_R41F     		0x41F
+#define AU8522_FILTER_COEF_R420     		0x420
+#define AU8522_FILTER_COEF_R421     		0x421
+#define AU8522_FILTER_COEF_R422     		0x422
+#define AU8522_FILTER_COEF_R423     		0x423
+#define AU8522_FILTER_COEF_R424     		0x424
+#define AU8522_FILTER_COEF_R425     		0x425
+#define AU8522_FILTER_COEF_R426     		0x426
+#define AU8522_FILTER_COEF_R427     		0x427
+#define AU8522_FILTER_COEF_R428     		0x428
+#define AU8522_FILTER_COEF_R429     		0x429
+#define AU8522_FILTER_COEF_R42A     		0x42A
+#define AU8522_FILTER_COEF_R42B     		0x42B
+#define AU8522_FILTER_COEF_R42C     		0x42C
+#define AU8522_FILTER_COEF_R42D     		0x42D
+
+/* VBI Control Registers */
+#define AU8522_TVDEC_VBI_RX_FIFO_CONTAIN_REG004H  	0x004
+#define AU8522_TVDEC_VBI_TX_FIFO_CONTAIN_REG005H  	0x005
+#define AU8522_TVDEC_VBI_RX_FIFO_READ_REG006H      	0x006
+#define AU8522_TVDEC_VBI_FIFO_STATUS_REG007H       	0x007
+#define AU8522_TVDEC_VBI_CTRL_H_REG017H			0x017
+#define AU8522_TVDEC_VBI_CTRL_L_REG018H			0x018
+#define AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H	0x019
+#define AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH		0x01A
+#define AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH		0x01B
+#define AU8522_TVDEC_VBI_USER_THRESH1_REG01CH		0x01C
+#define AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH	0x01E
+#define AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH   	0x01F
+#define AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H   	0x020
+#define AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H 	0x021
+#define AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H  	0x022
+#define AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H	0x023
+
+#define AU8522_REG071H					0x071
+#define AU8522_REG072H					0x072
+#define AU8522_REG074H					0x074
+#define AU8522_REG075H					0x075
+
+/* Digital Demodulator Registers */
+#define AU8522_FRAME_COUNT0_REG084H			0x084
+#define AU8522_RS_STATUS_G0_REG085H			0x085
+#define AU8522_RS_STATUS_B0_REG086H			0x086
+#define AU8522_RS_STATUS_E_REG087H			0x087
+#define AU8522_DEMODULATION_STATUS_REG088H		0x088
+#define AU8522_TOREGTRESTATUS_REG0E6H			0x0E6
+#define AU8522_TSPORT_CONTROL_REG10BH			0x10B
+#define AU8522_TSTHES_REG10CH				0x10C
+#define AU8522_FRMREGDFEKEEP_REG301H			0x301
+#define AU8522_DFE_AVERAGE_REG302H			0x302
+#define AU8522_FRMREGEQLERRWIN_REG303H			0x303
+#define AU8522_FRMREGFFEKEEP_REG304H			0x304
+#define AU8522_FRMREGDFECONTROL1_REG305H		0x305
+#define AU8522_FRMREGEQLERRLOW_REG306H			0x306
+
+#define AU8522_REG42EH				0x42E
+#define AU8522_REG42FH				0x42F
+#define AU8522_REG430H				0x430
+#define AU8522_REG431H				0x431
+#define AU8522_REG432H				0x432
+#define AU8522_REG433H				0x433
+#define AU8522_REG434H				0x434
+#define AU8522_REG435H				0x435
+#define AU8522_REG436H				0x436
+
+/* GPIO Registers */
+#define AU8522_GPIO_CONTROL_REG0E0H			0x0E0
+#define AU8522_GPIO_STATUS_REG0E1H			0x0E1
+#define AU8522_GPIO_DATA_REG0E2H			0x0E2
+
+/* Audio Control Registers */
+#define AU8522_AUDIOAGC_REG0EEH 			0x0EE
+#define AU8522_AUDIO_STATUS_REG0F0H 			0x0F0
+#define AU8522_AUDIO_MODE_REG0F1H 			0x0F1
+#define AU8522_AUDIO_VOLUME_L_REG0F2H 			0x0F2
+#define AU8522_AUDIO_VOLUME_R_REG0F3H 			0x0F3
+#define AU8522_AUDIO_VOLUME_REG0F4H 			0x0F4
+#define AU8522_FRMREGAUPHASE_REG0F7H 			0x0F7
+#define AU8522_REG0F9H					0x0F9
+
+#define AU8522_AUDIOAGC2_REG605H 			0x605
+#define AU8522_AUDIOFREQ_REG606H 			0x606
+
+
+/**************************************************************/
+
+/* Format control 1 */
+
+/* VCR Mode 7-6 */
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_VCR_MODE_YES		0x80
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_VCR_MODE_NO		0x40
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_VCR_MODE_AUTO		0x00
+/* Field len 5-4 */
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_625		0x20
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525		0x10
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_AUTO	0x00
+/* Line len (us) 3-2 */
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_64_000	0x0b
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492	0x08
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_556	0x04
+/* Subcarrier freq 1-0 */
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_AUTO	0x03
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_443	0x02
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_MN	0x01
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_50	0x00
+
+/* Format control 2 */
+#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_AUTODETECT	0x00
+#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_NTSC		0x01
+
+
+#define AU8522_INPUT_CONTROL_REG081H_ATSC               	0xC4
+#define AU8522_INPUT_CONTROL_REG081H_ATVRF			0xC4
+#define AU8522_INPUT_CONTROL_REG081H_ATVRF13			0xC4
+#define AU8522_INPUT_CONTROL_REG081H_J83B64             	0xC4
+#define AU8522_INPUT_CONTROL_REG081H_J83B256            	0xC4
+#define AU8522_INPUT_CONTROL_REG081H_CVBS               	0x20
+#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH1			0xA2
+#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH2			0xA0
+#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH3			0x69
+#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4			0x68
+#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF        	0x28
+/* CH1 AS Y,CH3 AS C */
+#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13        	0x23
+/* CH2 AS Y,CH4 AS C */
+#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24        	0x20
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATSC        	0x0C
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B64      	0x09
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B256    		0x09
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS        	0x12
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF       	0x1A
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF13		0x1A
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO		0x02
+
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CLEAR		0x00
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO		0x9C
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS     	0x9D
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATSC		0xE8
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B256 		0xCA
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B64  		0xCA
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF   		0xDD
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF13		0xDD
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_PAL		0xDD
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_FM		0xDD
+
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATSC		0x80
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B256 		0x80
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B64  		0x80
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_ATSC	0x40
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B256	0x40
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B64	0x40
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_CLEAR	0x00
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF		0x01
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF13		0x01
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_SVIDEO  		0x04
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_CVBS		0x01
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PWM     		0x03
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_IIS      	0x09
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PAL		0x01
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_FM		0x01
+
+/* STILL NEED TO BE REFACTORED @@@@@@@@@@@@@@ */
+#define AU8522_TVDEC_CONTRAST_REG00BH_CVBS			0x79
+#define AU8522_TVDEC_SATURATION_CB_REG00CH_CVBS			0x80
+#define AU8522_TVDEC_SATURATION_CR_REG00DH_CVBS			0x80
+#define AU8522_TVDEC_HUE_H_REG00EH_CVBS				0x00
+#define AU8522_TVDEC_HUE_L_REG00FH_CVBS				0x00
+#define AU8522_TVDEC_PGA_REG012H_CVBS				0x0F
+#define AU8522_TVDEC_COMB_MODE_REG015H_CVBS			0x00
+#define AU8522_REG016H_CVBS					0x00
+#define AU8522_TVDED_DBG_MODE_REG060H_CVBS			0x00
+#define AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS			0x19
+#define AU8522_REG0F9H_AUDIO					0x20
+#define AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS			0xA7
+#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS		0x0A
+#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS		0x32
+#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS		0x19
+#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS		0x23
+#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS		0x41
+#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS		0x0A
+#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS		0x32
+#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS		0x34
+#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO		0x2a
+#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS		0x05
+#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO		0x15
+#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS		0x6E
+#define AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS			0x0F
+#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS		0x80
+#define AU8522_REG071H_CVBS					0x18
+#define AU8522_REG072H_CVBS					0x30
+#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS		0xF0
+#define AU8522_REG074H_CVBS					0x80
+#define AU8522_REG075H_CVBS					0xF0
+#define AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS			0xFB
+#define AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS			0x04
+#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS		0x00
+#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS		0x00
+#define AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS			0xEE
+#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS			0xFE
+#define AU8522_TOREGAAGC_REG0E5H_CVBS				0x00
+#define AU8522_TVDEC_VBI6A_REG035H_CVBS				0x40
+
+/* Enables Closed captioning */
+#define AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON			0x21
diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c
new file mode 100644
index 0000000..033cd7a
--- /dev/null
+++ b/drivers/media/dvb-frontends/bcm3510.c
@@ -0,0 +1,856 @@
+/*
+ * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC)
+ *
+ *  Copyright (C) 2001-5, B2C2 inc.
+ *
+ *  GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de>
+ *
+ *  This driver is "hard-coded" to be used with the 1st generation of
+ *  Technisat/B2C2's Air2PC ATSC PCI/USB cards/boxes. The pll-programming
+ *  (Panasonic CT10S) is located here, which is actually wrong. Unless there is
+ *  another device with a BCM3510, this is no problem.
+ *
+ *  The driver works also with QAM64 DVB-C, but had an unreasonable high
+ *  UNC. (Tested with the Air2PC ATSC 1st generation)
+ *
+ *  You'll need a firmware for this driver in order to get it running. It is
+ *  called "dvb-fe-bcm3510-01.fw".
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+ * Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+
+#include "dvb_frontend.h"
+#include "bcm3510.h"
+#include "bcm3510_priv.h"
+
+struct bcm3510_state {
+
+	struct i2c_adapter* i2c;
+	const struct bcm3510_config* config;
+	struct dvb_frontend frontend;
+
+	/* demodulator private data */
+	struct mutex hab_mutex;
+	u8 firmware_loaded:1;
+
+	unsigned long next_status_check;
+	unsigned long status_check_interval;
+	struct bcm3510_hab_cmd_status1 status1;
+	struct bcm3510_hab_cmd_status2 status2;
+};
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c (|-able)).");
+
+#define dprintk(level,x...) if (level & debug) printk(x)
+#define dbufout(b,l,m) {\
+	    int i; \
+	    for (i = 0; i < l; i++) \
+		m("%02x ",b[i]); \
+}
+#define deb_info(args...) dprintk(0x01,args)
+#define deb_i2c(args...)  dprintk(0x02,args)
+#define deb_hab(args...)  dprintk(0x04,args)
+
+/* transfer functions */
+static int bcm3510_writebytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len)
+{
+	u8 b[256];
+	int err;
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = len + 1 };
+
+	b[0] = reg;
+	memcpy(&b[1],buf,len);
+
+	deb_i2c("i2c wr %02x: ",reg);
+	dbufout(buf,len,deb_i2c);
+	deb_i2c("\n");
+
+	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+
+		deb_info("%s: i2c write error (addr %02x, reg %02x, err == %i)\n",
+			__func__, state->config->demod_address, reg,  err);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int bcm3510_readbytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len)
+{
+	struct i2c_msg msg[] = {
+		{ .addr = state->config->demod_address, .flags = 0,        .buf = &reg, .len = 1 },
+		{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf,  .len = len }
+	};
+	int err;
+
+	memset(buf,0,len);
+
+	if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {
+		deb_info("%s: i2c read error (addr %02x, reg %02x, err == %i)\n",
+			__func__, state->config->demod_address, reg,  err);
+		return -EREMOTEIO;
+	}
+	deb_i2c("i2c rd %02x: ",reg);
+	dbufout(buf,len,deb_i2c);
+	deb_i2c("\n");
+
+	return 0;
+}
+
+static int bcm3510_writeB(struct bcm3510_state *state, u8 reg, bcm3510_register_value v)
+{
+	return bcm3510_writebytes(state,reg,&v.raw,1);
+}
+
+static int bcm3510_readB(struct bcm3510_state *state, u8 reg, bcm3510_register_value *v)
+{
+	return bcm3510_readbytes(state,reg,&v->raw,1);
+}
+
+/* Host Access Buffer transfers */
+static int bcm3510_hab_get_response(struct bcm3510_state *st, u8 *buf, int len)
+{
+	bcm3510_register_value v;
+	int ret,i;
+
+	v.HABADR_a6.HABADR = 0;
+	if ((ret = bcm3510_writeB(st,0xa6,v)) < 0)
+		return ret;
+
+	for (i = 0; i < len; i++) {
+		if ((ret = bcm3510_readB(st,0xa7,&v)) < 0)
+			return ret;
+		buf[i] = v.HABDATA_a7;
+	}
+	return 0;
+}
+
+static int bcm3510_hab_send_request(struct bcm3510_state *st, u8 *buf, int len)
+{
+	bcm3510_register_value v,hab;
+	int ret,i;
+	unsigned long t;
+
+/* Check if any previous HAB request still needs to be serviced by the
+ * Acquisition Processor before sending new request */
+	if ((ret = bcm3510_readB(st,0xa8,&v)) < 0)
+		return ret;
+	if (v.HABSTAT_a8.HABR) {
+		deb_info("HAB is running already - clearing it.\n");
+		v.HABSTAT_a8.HABR = 0;
+		bcm3510_writeB(st,0xa8,v);
+//		return -EBUSY;
+	}
+
+/* Send the start HAB Address (automatically incremented after write of
+ * HABDATA) and write the HAB Data */
+	hab.HABADR_a6.HABADR = 0;
+	if ((ret = bcm3510_writeB(st,0xa6,hab)) < 0)
+		return ret;
+
+	for (i = 0; i < len; i++) {
+		hab.HABDATA_a7 = buf[i];
+		if ((ret = bcm3510_writeB(st,0xa7,hab)) < 0)
+			return ret;
+	}
+
+/* Set the HABR bit to indicate AP request in progress (LBHABR allows HABR to
+ * be written) */
+	v.raw = 0; v.HABSTAT_a8.HABR = 1; v.HABSTAT_a8.LDHABR = 1;
+	if ((ret = bcm3510_writeB(st,0xa8,v)) < 0)
+		return ret;
+
+/* Polling method: Wait until the AP finishes processing the HAB request */
+	t = jiffies + 1*HZ;
+	while (time_before(jiffies, t)) {
+		deb_info("waiting for HAB to complete\n");
+		msleep(10);
+		if ((ret = bcm3510_readB(st,0xa8,&v)) < 0)
+			return ret;
+
+		if (!v.HABSTAT_a8.HABR)
+			return 0;
+	}
+
+	deb_info("send_request execution timed out.\n");
+	return -ETIMEDOUT;
+}
+
+static int bcm3510_do_hab_cmd(struct bcm3510_state *st, u8 cmd, u8 msgid, u8 *obuf, u8 olen, u8 *ibuf, u8 ilen)
+{
+	u8 ob[olen+2],ib[ilen+2];
+	int ret = 0;
+
+	ob[0] = cmd;
+	ob[1] = msgid;
+	memcpy(&ob[2],obuf,olen);
+
+	deb_hab("hab snd: ");
+	dbufout(ob,olen+2,deb_hab);
+	deb_hab("\n");
+
+	if (mutex_lock_interruptible(&st->hab_mutex) < 0)
+		return -EAGAIN;
+
+	if ((ret = bcm3510_hab_send_request(st, ob, olen+2)) < 0 ||
+		(ret = bcm3510_hab_get_response(st, ib, ilen+2)) < 0)
+		goto error;
+
+	deb_hab("hab get: ");
+	dbufout(ib,ilen+2,deb_hab);
+	deb_hab("\n");
+
+	memcpy(ibuf,&ib[2],ilen);
+error:
+	mutex_unlock(&st->hab_mutex);
+	return ret;
+}
+
+#if 0
+/* not needed, we use a semaphore to prevent HAB races */
+static int bcm3510_is_ap_ready(struct bcm3510_state *st)
+{
+	bcm3510_register_value ap,hab;
+	int ret;
+
+	if ((ret = bcm3510_readB(st,0xa8,&hab)) < 0 ||
+		(ret = bcm3510_readB(st,0xa2,&ap) < 0))
+		return ret;
+
+	if (ap.APSTAT1_a2.RESET || ap.APSTAT1_a2.IDLE || ap.APSTAT1_a2.STOP || hab.HABSTAT_a8.HABR) {
+		deb_info("AP is busy\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+#endif
+
+static int bcm3510_bert_reset(struct bcm3510_state *st)
+{
+	bcm3510_register_value b;
+	int ret;
+
+	if ((ret = bcm3510_readB(st,0xfa,&b)) < 0)
+		return ret;
+
+	b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b);
+	b.BERCTL_fa.RESYNC = 1; bcm3510_writeB(st,0xfa,b);
+	b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b);
+	b.BERCTL_fa.CNTCTL = 1; b.BERCTL_fa.BITCNT = 1; bcm3510_writeB(st,0xfa,b);
+
+	/* clear residual bit counter TODO  */
+	return 0;
+}
+
+static int bcm3510_refresh_state(struct bcm3510_state *st)
+{
+	if (time_after(jiffies,st->next_status_check)) {
+		bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS1, NULL,0, (u8 *)&st->status1, sizeof(st->status1));
+		bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS2, NULL,0, (u8 *)&st->status2, sizeof(st->status2));
+		st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
+	}
+	return 0;
+}
+
+static int bcm3510_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct bcm3510_state* st = fe->demodulator_priv;
+	bcm3510_refresh_state(st);
+
+	*status = 0;
+	if (st->status1.STATUS1.RECEIVER_LOCK)
+		*status |= FE_HAS_LOCK | FE_HAS_SYNC;
+
+	if (st->status1.STATUS1.FEC_LOCK)
+		*status |= FE_HAS_VITERBI;
+
+	if (st->status1.STATUS1.OUT_PLL_LOCK)
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+
+	if (*status & FE_HAS_LOCK)
+		st->status_check_interval = 1500;
+	else /* more frequently checks if no lock has been achieved yet */
+		st->status_check_interval = 500;
+
+	deb_info("real_status: %02x\n",*status);
+	return 0;
+}
+
+static int bcm3510_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct bcm3510_state* st = fe->demodulator_priv;
+	bcm3510_refresh_state(st);
+
+	*ber = (st->status2.LDBER0 << 16) | (st->status2.LDBER1 << 8) | st->status2.LDBER2;
+	return 0;
+}
+
+static int bcm3510_read_unc(struct dvb_frontend* fe, u32* unc)
+{
+	struct bcm3510_state* st = fe->demodulator_priv;
+	bcm3510_refresh_state(st);
+	*unc = (st->status2.LDUERC0 << 8) | st->status2.LDUERC1;
+	return 0;
+}
+
+static int bcm3510_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct bcm3510_state* st = fe->demodulator_priv;
+	s32 t;
+
+	bcm3510_refresh_state(st);
+	t = st->status2.SIGNAL;
+
+	if (t > 190)
+		t = 190;
+	if (t < 90)
+		t = 90;
+
+	t -= 90;
+	t = t * 0xff / 100;
+	/* normalize if necessary */
+	*strength = (t << 8) | t;
+	return 0;
+}
+
+static int bcm3510_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct bcm3510_state* st = fe->demodulator_priv;
+	bcm3510_refresh_state(st);
+
+	*snr = st->status1.SNR_EST0*1000 + ((st->status1.SNR_EST1*1000) >> 8);
+	return 0;
+}
+
+/* tuner frontend programming */
+static int bcm3510_tuner_cmd(struct bcm3510_state* st,u8 bc, u16 n, u8 a)
+{
+	struct bcm3510_hab_cmd_tune c;
+	memset(&c,0,sizeof(struct bcm3510_hab_cmd_tune));
+
+/* I2C Mode disabled,  set 16 control / Data pairs */
+	c.length = 0x10;
+	c.clock_width = 0;
+/* CS1, CS0, DATA, CLK bits control the tuner RF_AGC_SEL pin is set to
+ * logic high (as Configuration) */
+	c.misc = 0x10;
+/* Set duration of the initial state of TUNCTL = 3.34 micro Sec */
+	c.TUNCTL_state = 0x40;
+
+/* PRESCALER DIVIDE RATIO | BC1_2_3_4; (band switch), 1stosc REFERENCE COUNTER REF_S12 and REF_S11 */
+	c.ctl_dat[0].ctrl.size = BITS_8;
+	c.ctl_dat[0].data      = 0x80 | bc;
+
+/* Control DATA pin, 1stosc REFERENCE COUNTER REF_S10 to REF_S3 */
+	c.ctl_dat[1].ctrl.size = BITS_8;
+	c.ctl_dat[1].data      = 4;
+
+/* set CONTROL BIT 1 to 1, 1stosc REFERENCE COUNTER REF_S2 to REF_S1 */
+	c.ctl_dat[2].ctrl.size = BITS_3;
+	c.ctl_dat[2].data      = 0x20;
+
+/* control CS0 pin, pulse byte ? */
+	c.ctl_dat[3].ctrl.size = BITS_3;
+	c.ctl_dat[3].ctrl.clk_off = 1;
+	c.ctl_dat[3].ctrl.cs0  = 1;
+	c.ctl_dat[3].data      = 0x40;
+
+/* PGM_S18 to PGM_S11 */
+	c.ctl_dat[4].ctrl.size = BITS_8;
+	c.ctl_dat[4].data      = n >> 3;
+
+/* PGM_S10 to PGM_S8, SWL_S7 to SWL_S3 */
+	c.ctl_dat[5].ctrl.size = BITS_8;
+	c.ctl_dat[5].data      = ((n & 0x7) << 5) | (a >> 2);
+
+/* SWL_S2 and SWL_S1, set CONTROL BIT 2 to 0 */
+	c.ctl_dat[6].ctrl.size = BITS_3;
+	c.ctl_dat[6].data      = (a << 6) & 0xdf;
+
+/* control CS0 pin, pulse byte ? */
+	c.ctl_dat[7].ctrl.size = BITS_3;
+	c.ctl_dat[7].ctrl.clk_off = 1;
+	c.ctl_dat[7].ctrl.cs0  = 1;
+	c.ctl_dat[7].data      = 0x40;
+
+/* PRESCALER DIVIDE RATIO, 2ndosc REFERENCE COUNTER REF_S12 and REF_S11 */
+	c.ctl_dat[8].ctrl.size = BITS_8;
+	c.ctl_dat[8].data      = 0x80;
+
+/* 2ndosc REFERENCE COUNTER REF_S10 to REF_S3 */
+	c.ctl_dat[9].ctrl.size = BITS_8;
+	c.ctl_dat[9].data      = 0x10;
+
+/* set CONTROL BIT 1 to 1, 2ndosc REFERENCE COUNTER REF_S2 to REF_S1 */
+	c.ctl_dat[10].ctrl.size = BITS_3;
+	c.ctl_dat[10].data      = 0x20;
+
+/* pulse byte */
+	c.ctl_dat[11].ctrl.size = BITS_3;
+	c.ctl_dat[11].ctrl.clk_off = 1;
+	c.ctl_dat[11].ctrl.cs1  = 1;
+	c.ctl_dat[11].data      = 0x40;
+
+/* PGM_S18 to PGM_S11 */
+	c.ctl_dat[12].ctrl.size = BITS_8;
+	c.ctl_dat[12].data      = 0x2a;
+
+/* PGM_S10 to PGM_S8 and SWL_S7 to SWL_S3 */
+	c.ctl_dat[13].ctrl.size = BITS_8;
+	c.ctl_dat[13].data      = 0x8e;
+
+/* SWL_S2 and SWL_S1 and set CONTROL BIT 2 to 0 */
+	c.ctl_dat[14].ctrl.size = BITS_3;
+	c.ctl_dat[14].data      = 0;
+
+/* Pulse Byte */
+	c.ctl_dat[15].ctrl.size = BITS_3;
+	c.ctl_dat[15].ctrl.clk_off = 1;
+	c.ctl_dat[15].ctrl.cs1  = 1;
+	c.ctl_dat[15].data      = 0x40;
+
+	return bcm3510_do_hab_cmd(st,CMD_TUNE, MSGID_TUNE,(u8 *) &c,sizeof(c), NULL, 0);
+}
+
+static int bcm3510_set_freq(struct bcm3510_state* st,u32 freq)
+{
+	u8 bc,a;
+	u16 n;
+	s32 YIntercept,Tfvco1;
+
+	freq /= 1000;
+
+	deb_info("%dkHz:",freq);
+	/* set Band Switch */
+	if (freq <= 168000)
+		bc = 0x1c;
+	else if (freq <= 378000)
+		bc = 0x2c;
+	else
+		bc = 0x30;
+
+	if (freq >= 470000) {
+		freq -= 470001;
+		YIntercept = 18805;
+	} else if (freq >= 90000) {
+		freq -= 90001;
+		YIntercept = 15005;
+	} else if (freq >= 76000){
+		freq -= 76001;
+		YIntercept = 14865;
+	} else {
+		freq -= 54001;
+		YIntercept = 14645;
+	}
+
+	Tfvco1 = (((freq/6000)*60 + YIntercept)*4)/10;
+
+	n = Tfvco1 >> 6;
+	a = Tfvco1 & 0x3f;
+
+	deb_info(" BC1_2_3_4: %x, N: %x A: %x\n", bc, n, a);
+	if (n >= 16 && n <= 2047)
+		return bcm3510_tuner_cmd(st,bc,n,a);
+
+	return -EINVAL;
+}
+
+static int bcm3510_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct bcm3510_state* st = fe->demodulator_priv;
+	struct bcm3510_hab_cmd_ext_acquire cmd;
+	struct bcm3510_hab_cmd_bert_control bert;
+	int ret;
+
+	memset(&cmd,0,sizeof(cmd));
+	switch (c->modulation) {
+		case QAM_256:
+			cmd.ACQUIRE0.MODE = 0x1;
+			cmd.ACQUIRE1.SYM_RATE = 0x1;
+			cmd.ACQUIRE1.IF_FREQ = 0x1;
+			break;
+		case QAM_64:
+			cmd.ACQUIRE0.MODE = 0x2;
+			cmd.ACQUIRE1.SYM_RATE = 0x2;
+			cmd.ACQUIRE1.IF_FREQ = 0x1;
+			break;
+#if 0
+		case QAM_256:
+			cmd.ACQUIRE0.MODE = 0x3;
+			break;
+		case QAM_128:
+			cmd.ACQUIRE0.MODE = 0x4;
+			break;
+		case QAM_64:
+			cmd.ACQUIRE0.MODE = 0x5;
+			break;
+		case QAM_32:
+			cmd.ACQUIRE0.MODE = 0x6;
+			break;
+		case QAM_16:
+			cmd.ACQUIRE0.MODE = 0x7;
+			break;
+#endif
+		case VSB_8:
+			cmd.ACQUIRE0.MODE = 0x8;
+			cmd.ACQUIRE1.SYM_RATE = 0x0;
+			cmd.ACQUIRE1.IF_FREQ = 0x0;
+			break;
+		case VSB_16:
+			cmd.ACQUIRE0.MODE = 0x9;
+			cmd.ACQUIRE1.SYM_RATE = 0x0;
+			cmd.ACQUIRE1.IF_FREQ = 0x0;
+		default:
+			return -EINVAL;
+	};
+	cmd.ACQUIRE0.OFFSET = 0;
+	cmd.ACQUIRE0.NTSCSWEEP = 1;
+	cmd.ACQUIRE0.FA = 1;
+	cmd.ACQUIRE0.BW = 0;
+
+/*	if (enableOffset) {
+		cmd.IF_OFFSET0 = xx;
+		cmd.IF_OFFSET1 = xx;
+
+		cmd.SYM_OFFSET0 = xx;
+		cmd.SYM_OFFSET1 = xx;
+		if (enableNtscSweep) {
+			cmd.NTSC_OFFSET0;
+			cmd.NTSC_OFFSET1;
+		}
+	} */
+	bcm3510_do_hab_cmd(st, CMD_ACQUIRE, MSGID_EXT_TUNER_ACQUIRE, (u8 *) &cmd, sizeof(cmd), NULL, 0);
+
+/* doing it with different MSGIDs, data book and source differs */
+	bert.BE = 0;
+	bert.unused = 0;
+	bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_CONTROL, (u8 *) &bert, sizeof(bert), NULL, 0);
+	bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_SET, (u8 *) &bert, sizeof(bert), NULL, 0);
+
+	bcm3510_bert_reset(st);
+
+	ret = bcm3510_set_freq(st, c->frequency);
+	if (ret < 0)
+		return ret;
+
+	memset(&st->status1,0,sizeof(st->status1));
+	memset(&st->status2,0,sizeof(st->status2));
+	st->status_check_interval = 500;
+
+/* Give the AP some time */
+	msleep(200);
+
+	return 0;
+}
+
+static int bcm3510_sleep(struct dvb_frontend* fe)
+{
+	return 0;
+}
+
+static int bcm3510_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *s)
+{
+	s->min_delay_ms = 1000;
+	s->step_size = 0;
+	s->max_drift = 0;
+	return 0;
+}
+
+static void bcm3510_release(struct dvb_frontend* fe)
+{
+	struct bcm3510_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+/* firmware download:
+ * firmware file is build up like this:
+ * 16bit addr, 16bit length, 8byte of length
+ */
+#define BCM3510_DEFAULT_FIRMWARE "dvb-fe-bcm3510-01.fw"
+
+static int bcm3510_write_ram(struct bcm3510_state *st, u16 addr, const u8 *b,
+			     u16 len)
+{
+	int ret = 0,i;
+	bcm3510_register_value vH, vL,vD;
+
+	vH.MADRH_a9 = addr >> 8;
+	vL.MADRL_aa = addr;
+	if ((ret = bcm3510_writeB(st,0xa9,vH)) < 0) return ret;
+	if ((ret = bcm3510_writeB(st,0xaa,vL)) < 0) return ret;
+
+	for (i = 0; i < len; i++) {
+		vD.MDATA_ab = b[i];
+		if ((ret = bcm3510_writeB(st,0xab,vD)) < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int bcm3510_download_firmware(struct dvb_frontend* fe)
+{
+	struct bcm3510_state* st = fe->demodulator_priv;
+	const struct firmware *fw;
+	u16 addr,len;
+	const u8 *b;
+	int ret,i;
+
+	deb_info("requesting firmware\n");
+	if ((ret = st->config->request_firmware(fe, &fw, BCM3510_DEFAULT_FIRMWARE)) < 0) {
+		err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret);
+		return ret;
+	}
+	deb_info("got firmware: %zd\n",fw->size);
+
+	b = fw->data;
+	for (i = 0; i < fw->size;) {
+		addr = le16_to_cpu( *( (u16 *)&b[i] ) );
+		len  = le16_to_cpu( *( (u16 *)&b[i+2] ) );
+		deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size);
+		if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) {
+			err("firmware download failed: %d\n",ret);
+			return ret;
+		}
+		i += 4 + len;
+	}
+	release_firmware(fw);
+	deb_info("firmware download successfully completed\n");
+	return 0;
+}
+
+static int bcm3510_check_firmware_version(struct bcm3510_state *st)
+{
+	struct bcm3510_hab_cmd_get_version_info ver;
+	bcm3510_do_hab_cmd(st,CMD_GET_VERSION_INFO,MSGID_GET_VERSION_INFO,NULL,0,(u8*)&ver,sizeof(ver));
+
+	deb_info("Version information: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+		ver.microcode_version, ver.script_version, ver.config_version, ver.demod_version);
+
+	if (ver.script_version == BCM3510_DEF_SCRIPT_VERSION &&
+		ver.config_version == BCM3510_DEF_CONFIG_VERSION &&
+		ver.demod_version  == BCM3510_DEF_DEMOD_VERSION)
+		return 0;
+
+	deb_info("version check failed\n");
+	return -ENODEV;
+}
+
+/* (un)resetting the AP */
+static int bcm3510_reset(struct bcm3510_state *st)
+{
+	int ret;
+	unsigned long  t;
+	bcm3510_register_value v;
+
+	bcm3510_readB(st,0xa0,&v); v.HCTL1_a0.RESET = 1;
+	if ((ret = bcm3510_writeB(st,0xa0,v)) < 0)
+		return ret;
+
+    t = jiffies + 3*HZ;
+	while (time_before(jiffies, t)) {
+		msleep(10);
+		if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
+			return ret;
+
+		if (v.APSTAT1_a2.RESET)
+			return 0;
+	}
+	deb_info("reset timed out\n");
+	return -ETIMEDOUT;
+}
+
+static int bcm3510_clear_reset(struct bcm3510_state *st)
+{
+	bcm3510_register_value v;
+	int ret;
+	unsigned long t;
+
+	v.raw = 0;
+	if ((ret = bcm3510_writeB(st,0xa0,v)) < 0)
+		return ret;
+
+    t = jiffies + 3*HZ;
+	while (time_before(jiffies, t)) {
+		msleep(10);
+		if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
+			return ret;
+
+		/* verify that reset is cleared */
+		if (!v.APSTAT1_a2.RESET)
+			return 0;
+	}
+	deb_info("reset clear timed out\n");
+	return -ETIMEDOUT;
+}
+
+static int bcm3510_init_cold(struct bcm3510_state *st)
+{
+	int ret;
+	bcm3510_register_value v;
+
+	/* read Acquisation Processor status register and check it is not in RUN mode */
+	if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
+		return ret;
+	if (v.APSTAT1_a2.RUN) {
+		deb_info("AP is already running - firmware already loaded.\n");
+		return 0;
+	}
+
+	deb_info("reset?\n");
+	if ((ret = bcm3510_reset(st)) < 0)
+		return ret;
+
+	deb_info("tristate?\n");
+	/* tri-state */
+	v.TSTCTL_2e.CTL = 0;
+	if ((ret = bcm3510_writeB(st,0x2e,v)) < 0)
+		return ret;
+
+	deb_info("firmware?\n");
+	if ((ret = bcm3510_download_firmware(&st->frontend)) < 0 ||
+		(ret = bcm3510_clear_reset(st)) < 0)
+		return ret;
+
+	/* anything left here to Let the acquisition processor begin execution at program counter 0000 ??? */
+
+	return 0;
+}
+
+static int bcm3510_init(struct dvb_frontend* fe)
+{
+	struct bcm3510_state* st = fe->demodulator_priv;
+	bcm3510_register_value j;
+	struct bcm3510_hab_cmd_set_agc c;
+	int ret;
+
+	if ((ret = bcm3510_readB(st,0xca,&j)) < 0)
+		return ret;
+
+	deb_info("JDEC: %02x\n",j.raw);
+
+	switch (j.JDEC_ca.JDEC) {
+		case JDEC_WAIT_AT_RAM:
+			deb_info("attempting to download firmware\n");
+			if ((ret = bcm3510_init_cold(st)) < 0)
+				return ret;
+		case JDEC_EEPROM_LOAD_WAIT: /* fall-through is wanted */
+			deb_info("firmware is loaded\n");
+			bcm3510_check_firmware_version(st);
+			break;
+		default:
+			return -ENODEV;
+	}
+
+	memset(&c,0,1);
+	c.SEL = 1;
+	bcm3510_do_hab_cmd(st,CMD_AUTO_PARAM,MSGID_SET_RF_AGC_SEL,(u8 *)&c,sizeof(c),NULL,0);
+
+	return 0;
+}
+
+
+static struct dvb_frontend_ops bcm3510_ops;
+
+struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config,
+				   struct i2c_adapter *i2c)
+{
+	struct bcm3510_state* state = NULL;
+	int ret;
+	bcm3510_register_value v;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct bcm3510_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+
+	state->config = config;
+	state->i2c = i2c;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	mutex_init(&state->hab_mutex);
+
+	if ((ret = bcm3510_readB(state,0xe0,&v)) < 0)
+		goto error;
+
+	deb_info("Revision: 0x%1x, Layer: 0x%1x.\n",v.REVID_e0.REV,v.REVID_e0.LAYER);
+
+	if ((v.REVID_e0.REV != 0x1 && v.REVID_e0.LAYER != 0xb) && /* cold */
+		(v.REVID_e0.REV != 0x8 && v.REVID_e0.LAYER != 0x0))   /* warm */
+		goto error;
+
+	info("Revision: 0x%1x, Layer: 0x%1x.",v.REVID_e0.REV,v.REVID_e0.LAYER);
+
+	bcm3510_reset(state);
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(bcm3510_attach);
+
+static struct dvb_frontend_ops bcm3510_ops = {
+	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
+	.info = {
+		.name = "Broadcom BCM3510 VSB/QAM frontend",
+		.frequency_min =  54000000,
+		.frequency_max = 803000000,
+		/* stepsize is just a guess */
+		.frequency_stepsize = 0,
+		.caps =
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_8VSB | FE_CAN_16VSB |
+			FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256
+	},
+
+	.release = bcm3510_release,
+
+	.init = bcm3510_init,
+	.sleep = bcm3510_sleep,
+
+	.set_frontend = bcm3510_set_frontend,
+	.get_tune_settings = bcm3510_get_tune_settings,
+
+	.read_status = bcm3510_read_status,
+	.read_ber = bcm3510_read_ber,
+	.read_signal_strength = bcm3510_read_signal_strength,
+	.read_snr = bcm3510_read_snr,
+	.read_ucblocks = bcm3510_read_unc,
+};
+
+MODULE_DESCRIPTION("Broadcom BCM3510 ATSC (8VSB/16VSB & ITU J83 AnnexB FEC QAM64/256) demodulator driver");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/bcm3510.h b/drivers/media/dvb-frontends/bcm3510.h
new file mode 100644
index 0000000..f4575c0
--- /dev/null
+++ b/drivers/media/dvb-frontends/bcm3510.h
@@ -0,0 +1,49 @@
+/*
+ * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC)
+ *
+ *  Copyright (C) 2001-5, B2C2 inc.
+ *
+ *  GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef BCM3510_H
+#define BCM3510_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct bcm3510_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* request firmware for device */
+	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+};
+
+#if defined(CONFIG_DVB_BCM3510) || (defined(CONFIG_DVB_BCM3510_MODULE) && defined(MODULE))
+extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
+					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
+						  struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_BCM3510
+
+#endif
diff --git a/drivers/media/dvb-frontends/bcm3510_priv.h b/drivers/media/dvb-frontends/bcm3510_priv.h
new file mode 100644
index 0000000..3bb1bc2
--- /dev/null
+++ b/drivers/media/dvb-frontends/bcm3510_priv.h
@@ -0,0 +1,460 @@
+/*
+ * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC)
+ *
+ *  Copyright (C) 2001-5, B2C2 inc.
+ *
+ *  GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef __BCM3510_PRIV_H__
+#define __BCM3510_PRIV_H__
+
+#define PACKED __attribute__((packed))
+
+#undef err
+#define err(format, arg...)  printk(KERN_ERR     "bcm3510: " format "\n" , ## arg)
+#undef info
+#define info(format, arg...) printk(KERN_INFO    "bcm3510: " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) printk(KERN_WARNING "bcm3510: " format "\n" , ## arg)
+
+
+#define PANASONIC_FIRST_IF_BASE_IN_KHz  1407500
+#define BCM3510_SYMBOL_RATE             5381000
+
+typedef union {
+	u8 raw;
+
+	struct {
+		u8 CTL   :8;
+	} TSTCTL_2e;
+
+	u8 LDCERC_4e;
+	u8 LDUERC_4f;
+	u8 LD_BER0_65;
+	u8 LD_BER1_66;
+	u8 LD_BER2_67;
+	u8 LD_BER3_68;
+
+	struct {
+		u8 RESET :1;
+		u8 IDLE  :1;
+		u8 STOP  :1;
+		u8 HIRQ0 :1;
+		u8 HIRQ1 :1;
+		u8 na0   :1;
+		u8 HABAV :1;
+		u8 na1   :1;
+	} HCTL1_a0;
+
+	struct {
+		u8 na0    :1;
+		u8 IDLMSK :1;
+		u8 STMSK  :1;
+		u8 I0MSK  :1;
+		u8 I1MSK  :1;
+		u8 na1    :1;
+		u8 HABMSK :1;
+		u8 na2    :1;
+	} HCTLMSK_a1;
+
+	struct {
+		u8 RESET  :1;
+		u8 IDLE   :1;
+		u8 STOP   :1;
+		u8 RUN    :1;
+		u8 HABAV  :1;
+		u8 MEMAV  :1;
+		u8 ALDONE :1;
+		u8 REIRQ  :1;
+	} APSTAT1_a2;
+
+	struct {
+		u8 RSTMSK :1;
+		u8 IMSK   :1;
+		u8 SMSK   :1;
+		u8 RMSK   :1;
+		u8 HABMSK :1;
+		u8 MAVMSK :1;
+		u8 ALDMSK :1;
+		u8 REMSK  :1;
+	} APMSK1_a3;
+
+	u8 APSTAT2_a4;
+	u8 APMSK2_a5;
+
+	struct {
+		u8 HABADR :7;
+		u8 na     :1;
+	} HABADR_a6;
+
+	u8 HABDATA_a7;
+
+	struct {
+		u8 HABR   :1;
+		u8 LDHABR :1;
+		u8 APMSK  :1;
+		u8 HMSK   :1;
+		u8 LDMSK  :1;
+		u8 na     :3;
+	} HABSTAT_a8;
+
+	u8 MADRH_a9;
+	u8 MADRL_aa;
+	u8 MDATA_ab;
+
+	struct {
+#define JDEC_WAIT_AT_RAM      0x7
+#define JDEC_EEPROM_LOAD_WAIT 0x4
+		u8 JDEC   :3;
+		u8 na     :5;
+	} JDEC_ca;
+
+	struct {
+		u8 REV   :4;
+		u8 LAYER :4;
+	} REVID_e0;
+
+	struct {
+		u8 unk0   :1;
+		u8 CNTCTL :1;
+		u8 BITCNT :1;
+		u8 unk1   :1;
+		u8 RESYNC :1;
+		u8 unk2   :3;
+	} BERCTL_fa;
+
+	struct {
+		u8 CSEL0  :1;
+		u8 CLKED0 :1;
+		u8 CSEL1  :1;
+		u8 CLKED1 :1;
+		u8 CLKLEV :1;
+		u8 SPIVAR :1;
+		u8 na     :2;
+	} TUNSET_fc;
+
+	struct {
+		u8 CLK    :1;
+		u8 DATA   :1;
+		u8 CS0    :1;
+		u8 CS1    :1;
+		u8 AGCSEL :1;
+		u8 na0    :1;
+		u8 TUNSEL :1;
+		u8 na1    :1;
+	} TUNCTL_fd;
+
+	u8 TUNSEL0_fe;
+	u8 TUNSEL1_ff;
+
+} bcm3510_register_value;
+
+/* HAB commands */
+
+/* version */
+#define CMD_GET_VERSION_INFO   0x3D
+#define MSGID_GET_VERSION_INFO 0x15
+struct bcm3510_hab_cmd_get_version_info {
+	u8 microcode_version;
+	u8 script_version;
+	u8 config_version;
+	u8 demod_version;
+} PACKED;
+
+#define BCM3510_DEF_MICROCODE_VERSION 0x0E
+#define BCM3510_DEF_SCRIPT_VERSION    0x06
+#define BCM3510_DEF_CONFIG_VERSION    0x01
+#define BCM3510_DEF_DEMOD_VERSION     0xB1
+
+/* acquire */
+#define CMD_ACQUIRE            0x38
+
+#define MSGID_EXT_TUNER_ACQUIRE 0x0A
+struct bcm3510_hab_cmd_ext_acquire {
+	struct {
+		u8 MODE      :4;
+		u8 BW        :1;
+		u8 FA        :1;
+		u8 NTSCSWEEP :1;
+		u8 OFFSET    :1;
+	} PACKED ACQUIRE0; /* control_byte */
+
+	struct {
+		u8 IF_FREQ  :3;
+		u8 zero0    :1;
+		u8 SYM_RATE :3;
+		u8 zero1    :1;
+	} PACKED ACQUIRE1; /* sym_if */
+
+	u8 IF_OFFSET0;   /* IF_Offset_10hz */
+	u8 IF_OFFSET1;
+	u8 SYM_OFFSET0;  /* SymbolRateOffset */
+	u8 SYM_OFFSET1;
+	u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */
+	u8 NTSC_OFFSET1;
+} PACKED;
+
+#define MSGID_INT_TUNER_ACQUIRE 0x0B
+struct bcm3510_hab_cmd_int_acquire {
+	struct {
+		u8 MODE      :4;
+		u8 BW        :1;
+		u8 FA        :1;
+		u8 NTSCSWEEP :1;
+		u8 OFFSET    :1;
+	} PACKED ACQUIRE0; /* control_byte */
+
+	struct {
+		u8 IF_FREQ  :3;
+		u8 zero0    :1;
+		u8 SYM_RATE :3;
+		u8 zero1    :1;
+	} PACKED ACQUIRE1; /* sym_if */
+
+	u8 TUNER_FREQ0;
+	u8 TUNER_FREQ1;
+	u8 TUNER_FREQ2;
+	u8 TUNER_FREQ3;
+	u8 IF_OFFSET0;   /* IF_Offset_10hz */
+	u8 IF_OFFSET1;
+	u8 SYM_OFFSET0;  /* SymbolRateOffset */
+	u8 SYM_OFFSET1;
+	u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */
+	u8 NTSC_OFFSET1;
+} PACKED;
+
+/* modes */
+#define BCM3510_QAM16           =   0x01
+#define BCM3510_QAM32           =   0x02
+#define BCM3510_QAM64           =   0x03
+#define BCM3510_QAM128          =   0x04
+#define BCM3510_QAM256          =   0x05
+#define BCM3510_8VSB            =   0x0B
+#define BCM3510_16VSB           =   0x0D
+
+/* IF_FREQS */
+#define BCM3510_IF_TERRESTRIAL 0x0
+#define BCM3510_IF_CABLE       0x1
+#define BCM3510_IF_USE_CMD     0x7
+
+/* SYM_RATE */
+#define BCM3510_SR_8VSB        0x0 /* 5381119 s/sec */
+#define BCM3510_SR_256QAM      0x1 /* 5360537 s/sec */
+#define BCM3510_SR_16QAM       0x2 /* 5056971 s/sec */
+#define BCM3510_SR_MISC        0x3 /* 5000000 s/sec */
+#define BCM3510_SR_USE_CMD     0x7
+
+/* special symbol rate */
+#define CMD_SET_VALUE_NOT_LISTED  0x2d
+#define MSGID_SET_SYMBOL_RATE_NOT_LISTED 0x0c
+struct bcm3510_hab_cmd_set_sr_not_listed {
+	u8 HOST_SYM_RATE0;
+	u8 HOST_SYM_RATE1;
+	u8 HOST_SYM_RATE2;
+	u8 HOST_SYM_RATE3;
+} PACKED;
+
+/* special IF */
+#define MSGID_SET_IF_FREQ_NOT_LISTED 0x0d
+struct bcm3510_hab_cmd_set_if_freq_not_listed {
+	u8 HOST_IF_FREQ0;
+	u8 HOST_IF_FREQ1;
+	u8 HOST_IF_FREQ2;
+	u8 HOST_IF_FREQ3;
+} PACKED;
+
+/* auto reacquire */
+#define CMD_AUTO_PARAM       0x2a
+#define MSGID_AUTO_REACQUIRE 0x0e
+struct bcm3510_hab_cmd_auto_reacquire {
+	u8 ACQ    :1; /* on/off*/
+	u8 unused :7;
+} PACKED;
+
+#define MSGID_SET_RF_AGC_SEL 0x12
+struct bcm3510_hab_cmd_set_agc {
+	u8 LVL    :1;
+	u8 unused :6;
+	u8 SEL    :1;
+} PACKED;
+
+#define MSGID_SET_AUTO_INVERSION 0x14
+struct bcm3510_hab_cmd_auto_inversion {
+	u8 AI     :1;
+	u8 unused :7;
+} PACKED;
+
+
+/* bert control */
+#define CMD_STATE_CONTROL  0x12
+#define MSGID_BERT_CONTROL 0x0e
+#define MSGID_BERT_SET     0xfa
+struct bcm3510_hab_cmd_bert_control {
+	u8 BE     :1;
+	u8 unused :7;
+} PACKED;
+
+#define MSGID_TRI_STATE 0x2e
+struct bcm3510_hab_cmd_tri_state {
+	u8 RE :1; /* a/d ram port pins */
+	u8 PE :1; /* baud clock pin */
+	u8 AC :1; /* a/d clock pin */
+	u8 BE :1; /* baud clock pin */
+	u8 unused :4;
+} PACKED;
+
+
+/* tune */
+#define CMD_TUNE   0x38
+#define MSGID_TUNE 0x16
+struct bcm3510_hab_cmd_tune_ctrl_data_pair {
+	struct {
+#define BITS_8 0x07
+#define BITS_7 0x06
+#define BITS_6 0x05
+#define BITS_5 0x04
+#define BITS_4 0x03
+#define BITS_3 0x02
+#define BITS_2 0x01
+#define BITS_1 0x00
+		u8 size    :3;
+		u8 unk     :2;
+		u8 clk_off :1;
+		u8 cs0     :1;
+		u8 cs1     :1;
+
+	} PACKED ctrl;
+
+	u8 data;
+} PACKED;
+
+struct bcm3510_hab_cmd_tune {
+	u8 length;
+	u8 clock_width;
+	u8 misc;
+	u8 TUNCTL_state;
+
+	struct bcm3510_hab_cmd_tune_ctrl_data_pair ctl_dat[16];
+} PACKED;
+
+#define CMD_STATUS    0x38
+#define MSGID_STATUS1 0x08
+struct bcm3510_hab_cmd_status1 {
+	struct {
+		u8 EQ_MODE       :4;
+		u8 reserved      :2;
+		u8 QRE           :1; /* if QSE and the spectrum is inversed */
+		u8 QSE           :1; /* automatic spectral inversion */
+	} PACKED STATUS0;
+
+	struct {
+		u8 RECEIVER_LOCK :1;
+		u8 FEC_LOCK      :1;
+		u8 OUT_PLL_LOCK  :1;
+		u8 reserved      :5;
+	} PACKED STATUS1;
+
+	struct {
+		u8 reserved      :2;
+		u8 BW            :1;
+		u8 NTE           :1; /* NTSC filter sweep enabled */
+		u8 AQI           :1; /* currently acquiring */
+		u8 FA            :1; /* fast acquisition */
+		u8 ARI           :1; /* auto reacquire */
+		u8 TI            :1; /* programming the tuner */
+	} PACKED STATUS2;
+	u8 STATUS3;
+	u8 SNR_EST0;
+	u8 SNR_EST1;
+	u8 TUNER_FREQ0;
+	u8 TUNER_FREQ1;
+	u8 TUNER_FREQ2;
+	u8 TUNER_FREQ3;
+	u8 SYM_RATE0;
+	u8 SYM_RATE1;
+	u8 SYM_RATE2;
+	u8 SYM_RATE3;
+	u8 SYM_OFFSET0;
+	u8 SYM_OFFSET1;
+	u8 SYM_ERROR0;
+	u8 SYM_ERROR1;
+	u8 IF_FREQ0;
+	u8 IF_FREQ1;
+	u8 IF_FREQ2;
+	u8 IF_FREQ3;
+	u8 IF_OFFSET0;
+	u8 IF_OFFSET1;
+	u8 IF_ERROR0;
+	u8 IF_ERROR1;
+	u8 NTSC_FILTER0;
+	u8 NTSC_FILTER1;
+	u8 NTSC_FILTER2;
+	u8 NTSC_FILTER3;
+	u8 NTSC_OFFSET0;
+	u8 NTSC_OFFSET1;
+	u8 NTSC_ERROR0;
+	u8 NTSC_ERROR1;
+	u8 INT_AGC_LEVEL0;
+	u8 INT_AGC_LEVEL1;
+	u8 EXT_AGC_LEVEL0;
+	u8 EXT_AGC_LEVEL1;
+} PACKED;
+
+#define MSGID_STATUS2 0x14
+struct bcm3510_hab_cmd_status2 {
+	struct {
+		u8 EQ_MODE  :4;
+		u8 reserved :2;
+		u8 QRE      :1;
+		u8 QSR      :1;
+	} PACKED STATUS0;
+	struct {
+		u8 RL       :1;
+		u8 FL       :1;
+		u8 OL       :1;
+		u8 reserved :5;
+	} PACKED STATUS1;
+	u8 SYMBOL_RATE0;
+	u8 SYMBOL_RATE1;
+	u8 SYMBOL_RATE2;
+	u8 SYMBOL_RATE3;
+	u8 LDCERC0;
+	u8 LDCERC1;
+	u8 LDCERC2;
+	u8 LDCERC3;
+	u8 LDUERC0;
+	u8 LDUERC1;
+	u8 LDUERC2;
+	u8 LDUERC3;
+	u8 LDBER0;
+	u8 LDBER1;
+	u8 LDBER2;
+	u8 LDBER3;
+	struct {
+		u8 MODE_TYPE :4; /* acquire mode 0 */
+		u8 reservd   :4;
+	} MODE_TYPE;
+	u8 SNR_EST0;
+	u8 SNR_EST1;
+	u8 SIGNAL;
+} PACKED;
+
+#define CMD_SET_RF_BW_NOT_LISTED   0x3f
+#define MSGID_SET_RF_BW_NOT_LISTED 0x11
+/* TODO */
+
+#endif
diff --git a/drivers/media/dvb-frontends/bsbe1-d01a.h b/drivers/media/dvb-frontends/bsbe1-d01a.h
new file mode 100644
index 0000000..7ed3c42
--- /dev/null
+++ b/drivers/media/dvb-frontends/bsbe1-d01a.h
@@ -0,0 +1,146 @@
+/*
+ * bsbe1-d01a.h - ALPS BSBE1-D01A tuner support
+ *
+ * Copyright (C) 2011 Oliver Endriss <o.endriss@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef BSBE1_D01A_H
+#define BSBE1_D01A_H
+
+#include "stb6000.h"
+#include "stv0288.h"
+
+static u8 stv0288_bsbe1_d01a_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x20,
+	0x09, 0x0,
+	0x0a, 0x4,
+	0x0b, 0x0,
+	0x0c, 0x0,
+	0x0d, 0x0,
+	0x0e, 0xd4,
+	0x0f, 0x30,
+	0x11, 0x80,
+	0x12, 0x03,
+	0x13, 0x48,
+	0x14, 0x84,
+	0x15, 0x45,
+	0x16, 0xb7,
+	0x17, 0x9c,
+	0x18, 0x0,
+	0x19, 0xa6,
+	0x1a, 0x88,
+	0x1b, 0x8f,
+	0x1c, 0xf0,
+	0x20, 0x0b,
+	0x21, 0x54,
+	0x22, 0x0,
+	0x23, 0x0,
+	0x2b, 0xff,
+	0x2c, 0xf7,
+	0x30, 0x0,
+	0x31, 0x1e,
+	0x32, 0x14,
+	0x33, 0x0f,
+	0x34, 0x09,
+	0x35, 0x0c,
+	0x36, 0x05,
+	0x37, 0x2f,
+	0x38, 0x16,
+	0x39, 0xbd,
+	0x3a, 0x03,
+	0x3b, 0x13,
+	0x3c, 0x11,
+	0x3d, 0x30,
+	0x40, 0x63,
+	0x41, 0x04,
+	0x42, 0x60,
+	0x43, 0x00,
+	0x44, 0x00,
+	0x45, 0x00,
+	0x46, 0x00,
+	0x47, 0x00,
+	0x4a, 0x00,
+	0x50, 0x10,
+	0x51, 0x36,
+	0x52, 0x09,
+	0x53, 0x94,
+	0x54, 0x62,
+	0x55, 0x29,
+	0x56, 0x64,
+	0x57, 0x2b,
+	0x58, 0x54,
+	0x59, 0x86,
+	0x5a, 0x0,
+	0x5b, 0x9b,
+	0x5c, 0x08,
+	0x5d, 0x7f,
+	0x5e, 0x0,
+	0x5f, 0xff,
+	0x70, 0x0,
+	0x71, 0x0,
+	0x72, 0x0,
+	0x74, 0x0,
+	0x75, 0x0,
+	0x76, 0x0,
+	0x81, 0x0,
+	0x82, 0x3f,
+	0x83, 0x3f,
+	0x84, 0x0,
+	0x85, 0x0,
+	0x88, 0x0,
+	0x89, 0x0,
+	0x8a, 0x0,
+	0x8b, 0x0,
+	0x8c, 0x0,
+	0x90, 0x0,
+	0x91, 0x0,
+	0x92, 0x0,
+	0x93, 0x0,
+	0x94, 0x1c,
+	0x97, 0x0,
+	0xa0, 0x48,
+	0xa1, 0x0,
+	0xb0, 0xb8,
+	0xb1, 0x3a,
+	0xb2, 0x10,
+	0xb3, 0x82,
+	0xb4, 0x80,
+	0xb5, 0x82,
+	0xb6, 0x82,
+	0xb7, 0x82,
+	0xb8, 0x20,
+	0xb9, 0x0,
+	0xf0, 0x0,
+	0xf1, 0x0,
+	0xf2, 0xc0,
+	0xff, 0xff,
+};
+
+static struct stv0288_config stv0288_bsbe1_d01a_config = {
+	.demod_address = 0x68,
+	.min_delay_ms = 100,
+	.inittab = stv0288_bsbe1_d01a_inittab,
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/bsbe1.h b/drivers/media/dvb-frontends/bsbe1.h
new file mode 100644
index 0000000..53e4d0d
--- /dev/null
+++ b/drivers/media/dvb-frontends/bsbe1.h
@@ -0,0 +1,106 @@
+/*
+ * bsbe1.h - ALPS BSBE1 tuner support
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef BSBE1_H
+#define BSBE1_H
+
+static u8 alps_bsbe1_inittab[] = {
+	0x01, 0x15,   /* XTAL = 4MHz, VCO = 352 MHz */
+	0x02, 0x30,   /* MCLK = 88 MHz */
+	0x03, 0x00,   /* ACR output 0 */
+	0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+	0x05, 0x05,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
+	0x06, 0x00,   /* DAC output 0 */
+	0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
+	0x09, 0x00,   /* FIFO */
+	0x0c, 0x51,   /* OP1/OP0 normal, val = 1 (LNB power on) */
+	0x0d, 0x82,   /* DC offset compensation = on, beta_agc1 = 2 */
+	0x0f, 0x92,   /* AGC1R */
+	0x10, 0x34,   /* AGC2O */
+	0x11, 0x84,   /* TLSR */
+	0x12, 0xb9,   /* CFD */
+	0x15, 0xc9,   /* lock detector threshold */
+	0x28, 0x00,   /* out imp: normal, type: parallel, FEC mode: QPSK */
+	0x33, 0xfc,   /* RS control */
+	0x34, 0x93,   /* count viterbi bit errors per 2E18 bytes */
+	0xff, 0xff
+};
+
+
+static int alps_bsbe1_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+	u8 aclk = 0;
+	u8 bclk = 0;
+
+	if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
+	else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
+	else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
+	else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
+	else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
+	else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
+
+	stv0299_writereg(fe, 0x13, aclk);
+	stv0299_writereg(fe, 0x14, bclk);
+	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+	stv0299_writereg(fe, 0x20, (ratio >>  8) & 0xff);
+	stv0299_writereg(fe, 0x21, (ratio      ) & 0xf0);
+
+	return 0;
+}
+
+static int alps_bsbe1_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	int ret;
+	u8 data[4];
+	u32 div;
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+	struct i2c_adapter *i2c = fe->tuner_priv;
+
+	if ((p->frequency < 950000) || (p->frequency > 2150000))
+		return -EINVAL;
+
+	div = p->frequency / 1000;
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x80 | ((div & 0x18000) >> 10) | 0x1;
+	data[3] = 0xe0;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	ret = i2c_transfer(i2c, &msg, 1);
+	return (ret != 1) ? -EIO : 0;
+}
+
+static struct stv0299_config alps_bsbe1_config = {
+	.demod_address = 0x68,
+	.inittab = alps_bsbe1_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.skip_reinit = 0,
+	.min_delay_ms = 100,
+	.set_symbol_rate = alps_bsbe1_set_symbol_rate,
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/bsru6.h b/drivers/media/dvb-frontends/bsru6.h
new file mode 100644
index 0000000..c2a578e
--- /dev/null
+++ b/drivers/media/dvb-frontends/bsru6.h
@@ -0,0 +1,143 @@
+/*
+ * bsru6.h - ALPS BSRU6 tuner support (moved from budget-ci.c)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef BSRU6_H
+#define BSRU6_H
+
+static u8 alps_bsru6_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x30,
+	0x03, 0x00,
+	0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+	0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
+	0x06, 0x40,   /* DAC not used, set to high impendance mode */
+	0x07, 0x00,   /* DAC LSB */
+	0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
+	0x09, 0x00,   /* FIFO */
+	0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+	0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
+	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
+	0x10, 0x3f,   // AGC2  0x3d
+	0x11, 0x84,
+	0x12, 0xb9,
+	0x15, 0xc9,   // lock detector threshold
+	0x16, 0x00,
+	0x17, 0x00,
+	0x18, 0x00,
+	0x19, 0x00,
+	0x1a, 0x00,
+	0x1f, 0x50,
+	0x20, 0x00,
+	0x21, 0x00,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
+	0x29, 0x1e,  // 1/2 threshold
+	0x2a, 0x14,  // 2/3 threshold
+	0x2b, 0x0f,  // 3/4 threshold
+	0x2c, 0x09,  // 5/6 threshold
+	0x2d, 0x05,  // 7/8 threshold
+	0x2e, 0x01,
+	0x31, 0x1f,  // test all FECs
+	0x32, 0x19,  // viterbi and synchro search
+	0x33, 0xfc,  // rs control
+	0x34, 0x93,  // error control
+	0x0f, 0x52,
+	0xff, 0xff
+};
+
+static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
+{
+	u8 aclk = 0;
+	u8 bclk = 0;
+
+	if (srate < 1500000) {
+		aclk = 0xb7;
+		bclk = 0x47;
+	} else if (srate < 3000000) {
+		aclk = 0xb7;
+		bclk = 0x4b;
+	} else if (srate < 7000000) {
+		aclk = 0xb7;
+		bclk = 0x4f;
+	} else if (srate < 14000000) {
+		aclk = 0xb7;
+		bclk = 0x53;
+	} else if (srate < 30000000) {
+		aclk = 0xb6;
+		bclk = 0x53;
+	} else if (srate < 45000000) {
+		aclk = 0xb4;
+		bclk = 0x51;
+	}
+
+	stv0299_writereg(fe, 0x13, aclk);
+	stv0299_writereg(fe, 0x14, bclk);
+	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+	stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+	stv0299_writereg(fe, 0x21, ratio & 0xf0);
+
+	return 0;
+}
+
+static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	u8 buf[4];
+	u32 div;
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	struct i2c_adapter *i2c = fe->tuner_priv;
+
+	if ((p->frequency < 950000) || (p->frequency > 2150000))
+		return -EINVAL;
+
+	div = (p->frequency + (125 - 1)) / 125;	/* round correctly */
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+	buf[3] = 0xC4;
+
+	if (p->frequency > 1530000)
+		buf[3] = 0xc0;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(i2c, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static struct stv0299_config alps_bsru6_config = {
+	.demod_address = 0x68,
+	.inittab = alps_bsru6_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.skip_reinit = 0,
+	.lock_output = STV0299_LOCKOUTPUT_1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = alps_bsru6_set_symbol_rate,
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/cx22700.c b/drivers/media/dvb-frontends/cx22700.c
new file mode 100644
index 0000000..f2a90f9
--- /dev/null
+++ b/drivers/media/dvb-frontends/cx22700.c
@@ -0,0 +1,443 @@
+/*
+    Conexant cx22700 DVB OFDM demodulator driver
+
+    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
+	Holger Waechtler <holger@convergence.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "dvb_frontend.h"
+#include "cx22700.h"
+
+
+struct cx22700_state {
+
+	struct i2c_adapter* i2c;
+
+	const struct cx22700_config* config;
+
+	struct dvb_frontend frontend;
+};
+
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "cx22700: " args); \
+	} while (0)
+
+static u8 init_tab [] = {
+	0x04, 0x10,
+	0x05, 0x09,
+	0x06, 0x00,
+	0x08, 0x04,
+	0x09, 0x00,
+	0x0a, 0x01,
+	0x15, 0x40,
+	0x16, 0x10,
+	0x17, 0x87,
+	0x18, 0x17,
+	0x1a, 0x10,
+	0x25, 0x04,
+	0x2e, 0x00,
+	0x39, 0x00,
+	0x3a, 0x04,
+	0x45, 0x08,
+	0x46, 0x02,
+	0x47, 0x05,
+};
+
+
+static int cx22700_writereg (struct cx22700_state* state, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf [] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+
+	dprintk ("%s\n", __func__);
+
+	ret = i2c_transfer (state->i2c, &msg, 1);
+
+	if (ret != 1)
+		printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
+			__func__, reg, data, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+
+static int cx22700_readreg (struct cx22700_state* state, u8 reg)
+{
+	int ret;
+	u8 b0 [] = { reg };
+	u8 b1 [] = { 0 };
+	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+
+	dprintk ("%s\n", __func__);
+
+	ret = i2c_transfer (state->i2c, msg, 2);
+
+	if (ret != 2) return -EIO;
+
+	return b1[0];
+}
+
+static int cx22700_set_inversion (struct cx22700_state* state, int inversion)
+{
+	u8 val;
+
+	dprintk ("%s\n", __func__);
+
+	switch (inversion) {
+	case INVERSION_AUTO:
+		return -EOPNOTSUPP;
+	case INVERSION_ON:
+		val = cx22700_readreg (state, 0x09);
+		return cx22700_writereg (state, 0x09, val | 0x01);
+	case INVERSION_OFF:
+		val = cx22700_readreg (state, 0x09);
+		return cx22700_writereg (state, 0x09, val & 0xfe);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int cx22700_set_tps(struct cx22700_state *state,
+			   struct dtv_frontend_properties *p)
+{
+	static const u8 qam_tab [4] = { 0, 1, 0, 2 };
+	static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 };
+	u8 val;
+
+	dprintk ("%s\n", __func__);
+
+	if (p->code_rate_HP < FEC_1_2 || p->code_rate_HP > FEC_7_8)
+		return -EINVAL;
+
+	if (p->code_rate_LP < FEC_1_2 || p->code_rate_LP > FEC_7_8)
+		return -EINVAL;
+
+	if (p->code_rate_HP == FEC_4_5 || p->code_rate_LP == FEC_4_5)
+		return -EINVAL;
+
+	if (p->guard_interval < GUARD_INTERVAL_1_32 ||
+	    p->guard_interval > GUARD_INTERVAL_1_4)
+		return -EINVAL;
+
+	if (p->transmission_mode != TRANSMISSION_MODE_2K &&
+	    p->transmission_mode != TRANSMISSION_MODE_8K)
+		return -EINVAL;
+
+	if (p->modulation != QPSK &&
+	    p->modulation != QAM_16 &&
+	    p->modulation != QAM_64)
+		return -EINVAL;
+
+	if (p->hierarchy < HIERARCHY_NONE ||
+	    p->hierarchy > HIERARCHY_4)
+		return -EINVAL;
+
+	if (p->bandwidth_hz > 8000000 || p->bandwidth_hz < 6000000)
+		return -EINVAL;
+
+	if (p->bandwidth_hz == 7000000)
+		cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 | 0x10));
+	else
+		cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 & ~0x10));
+
+	val = qam_tab[p->modulation - QPSK];
+	val |= p->hierarchy - HIERARCHY_NONE;
+
+	cx22700_writereg (state, 0x04, val);
+
+	val = fec_tab[p->code_rate_HP - FEC_1_2] << 3;
+	val |= fec_tab[p->code_rate_LP - FEC_1_2];
+
+	cx22700_writereg (state, 0x05, val);
+
+	val = (p->guard_interval - GUARD_INTERVAL_1_32) << 2;
+	val |= p->transmission_mode - TRANSMISSION_MODE_2K;
+
+	cx22700_writereg (state, 0x06, val);
+
+	cx22700_writereg (state, 0x08, 0x04 | 0x02);  /* use user tps parameters */
+	cx22700_writereg (state, 0x08, 0x04);         /* restart acquisition */
+
+	return 0;
+}
+
+static int cx22700_get_tps(struct cx22700_state *state,
+			   struct dtv_frontend_properties *p)
+{
+	static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 };
+	static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4,
+						    FEC_5_6, FEC_7_8 };
+	u8 val;
+
+	dprintk ("%s\n", __func__);
+
+	if (!(cx22700_readreg(state, 0x07) & 0x20))  /*  tps valid? */
+		return -EAGAIN;
+
+	val = cx22700_readreg (state, 0x01);
+
+	if ((val & 0x7) > 4)
+		p->hierarchy = HIERARCHY_AUTO;
+	else
+		p->hierarchy = HIERARCHY_NONE + (val & 0x7);
+
+	if (((val >> 3) & 0x3) > 2)
+		p->modulation = QAM_AUTO;
+	else
+		p->modulation = qam_tab[(val >> 3) & 0x3];
+
+	val = cx22700_readreg (state, 0x02);
+
+	if (((val >> 3) & 0x07) > 4)
+		p->code_rate_HP = FEC_AUTO;
+	else
+		p->code_rate_HP = fec_tab[(val >> 3) & 0x07];
+
+	if ((val & 0x07) > 4)
+		p->code_rate_LP = FEC_AUTO;
+	else
+		p->code_rate_LP = fec_tab[val & 0x07];
+
+	val = cx22700_readreg (state, 0x03);
+
+	p->guard_interval = GUARD_INTERVAL_1_32 + ((val >> 6) & 0x3);
+	p->transmission_mode = TRANSMISSION_MODE_2K + ((val >> 5) & 0x1);
+
+	return 0;
+}
+
+static int cx22700_init (struct dvb_frontend* fe)
+
+{	struct cx22700_state* state = fe->demodulator_priv;
+	int i;
+
+	dprintk("cx22700_init: init chip\n");
+
+	cx22700_writereg (state, 0x00, 0x02);   /*  soft reset */
+	cx22700_writereg (state, 0x00, 0x00);
+
+	msleep(10);
+
+	for (i=0; i<sizeof(init_tab); i+=2)
+		cx22700_writereg (state, init_tab[i], init_tab[i+1]);
+
+	cx22700_writereg (state, 0x00, 0x01);
+
+	return 0;
+}
+
+static int cx22700_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct cx22700_state* state = fe->demodulator_priv;
+
+	u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
+		   | (cx22700_readreg (state, 0x0e) << 1);
+	u8 sync = cx22700_readreg (state, 0x07);
+
+	*status = 0;
+
+	if (rs_ber < 0xff00)
+		*status |= FE_HAS_SIGNAL;
+
+	if (sync & 0x20)
+		*status |= FE_HAS_CARRIER;
+
+	if (sync & 0x10)
+		*status |= FE_HAS_VITERBI;
+
+	if (sync & 0x10)
+		*status |= FE_HAS_SYNC;
+
+	if (*status == 0x0f)
+		*status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int cx22700_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct cx22700_state* state = fe->demodulator_priv;
+
+	*ber = cx22700_readreg (state, 0x0c) & 0x7f;
+	cx22700_writereg (state, 0x0c, 0x00);
+
+	return 0;
+}
+
+static int cx22700_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+{
+	struct cx22700_state* state = fe->demodulator_priv;
+
+	u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
+		   | (cx22700_readreg (state, 0x0e) << 1);
+	*signal_strength = ~rs_ber;
+
+	return 0;
+}
+
+static int cx22700_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct cx22700_state* state = fe->demodulator_priv;
+
+	u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
+		   | (cx22700_readreg (state, 0x0e) << 1);
+	*snr = ~rs_ber;
+
+	return 0;
+}
+
+static int cx22700_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct cx22700_state* state = fe->demodulator_priv;
+
+	*ucblocks = cx22700_readreg (state, 0x0f);
+	cx22700_writereg (state, 0x0f, 0x00);
+
+	return 0;
+}
+
+static int cx22700_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct cx22700_state* state = fe->demodulator_priv;
+
+	cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/
+	cx22700_writereg (state, 0x00, 0x00);
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	cx22700_set_inversion(state, c->inversion);
+	cx22700_set_tps(state, c);
+	cx22700_writereg (state, 0x37, 0x01);  /* PAL loop filter off */
+	cx22700_writereg (state, 0x00, 0x01);  /* restart acquire */
+
+	return 0;
+}
+
+static int cx22700_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct cx22700_state* state = fe->demodulator_priv;
+	u8 reg09 = cx22700_readreg (state, 0x09);
+
+	c->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF;
+	return cx22700_get_tps(state, c);
+}
+
+static int cx22700_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct cx22700_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		return cx22700_writereg(state, 0x0a, 0x00);
+	} else {
+		return cx22700_writereg(state, 0x0a, 0x01);
+	}
+}
+
+static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+	fesettings->min_delay_ms = 150;
+	fesettings->step_size = 166667;
+	fesettings->max_drift = 166667*2;
+	return 0;
+}
+
+static void cx22700_release(struct dvb_frontend* fe)
+{
+	struct cx22700_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops cx22700_ops;
+
+struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
+				    struct i2c_adapter* i2c)
+{
+	struct cx22700_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct cx22700_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+
+	/* check if the demod is there */
+	if (cx22700_readreg(state, 0x07) < 0) goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops cx22700_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name			= "Conexant CX22700 DVB-T",
+		.frequency_min		= 470000000,
+		.frequency_max		= 860000000,
+		.frequency_stepsize	= 166667,
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+		      FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+		      FE_CAN_RECOVER
+	},
+
+	.release = cx22700_release,
+
+	.init = cx22700_init,
+	.i2c_gate_ctrl = cx22700_i2c_gate_ctrl,
+
+	.set_frontend = cx22700_set_frontend,
+	.get_frontend = cx22700_get_frontend,
+	.get_tune_settings = cx22700_get_tune_settings,
+
+	.read_status = cx22700_read_status,
+	.read_ber = cx22700_read_ber,
+	.read_signal_strength = cx22700_read_signal_strength,
+	.read_snr = cx22700_read_snr,
+	.read_ucblocks = cx22700_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Conexant CX22700 DVB-T Demodulator driver");
+MODULE_AUTHOR("Holger Waechtler");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(cx22700_attach);
diff --git a/drivers/media/dvb-frontends/cx22700.h b/drivers/media/dvb-frontends/cx22700.h
new file mode 100644
index 0000000..4757a93
--- /dev/null
+++ b/drivers/media/dvb-frontends/cx22700.h
@@ -0,0 +1,46 @@
+/*
+    Conexant CX22700 DVB OFDM demodulator driver
+
+    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
+	Holger Waechtler <holger@convergence.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef CX22700_H
+#define CX22700_H
+
+#include <linux/dvb/frontend.h>
+
+struct cx22700_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+};
+
+#if defined(CONFIG_DVB_CX22700) || (defined(CONFIG_DVB_CX22700_MODULE) && defined(MODULE))
+extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
+					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_CX22700
+
+#endif // CX22700_H
diff --git a/drivers/media/dvb-frontends/cx22702.c b/drivers/media/dvb-frontends/cx22702.c
new file mode 100644
index 0000000..edc8eaf
--- /dev/null
+++ b/drivers/media/dvb-frontends/cx22702.c
@@ -0,0 +1,653 @@
+/*
+    Conexant 22702 DVB OFDM demodulator driver
+
+    based on:
+	Alps TDMB7 DVB OFDM demodulator driver
+
+    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
+	  Holger Waechtler <holger@convergence.de>
+
+    Copyright (C) 2004 Steven Toth <stoth@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "cx22702.h"
+
+struct cx22702_state {
+
+	struct i2c_adapter *i2c;
+
+	/* configuration settings */
+	const struct cx22702_config *config;
+
+	struct dvb_frontend frontend;
+
+	/* previous uncorrected block counter */
+	u8 prevUCBlocks;
+};
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+#define dprintk	if (debug) printk
+
+/* Register values to initialise the demod */
+static const u8 init_tab[] = {
+	0x00, 0x00, /* Stop acquisition */
+	0x0B, 0x06,
+	0x09, 0x01,
+	0x0D, 0x41,
+	0x16, 0x32,
+	0x20, 0x0A,
+	0x21, 0x17,
+	0x24, 0x3e,
+	0x26, 0xff,
+	0x27, 0x10,
+	0x28, 0x00,
+	0x29, 0x00,
+	0x2a, 0x10,
+	0x2b, 0x00,
+	0x2c, 0x10,
+	0x2d, 0x00,
+	0x48, 0xd4,
+	0x49, 0x56,
+	0x6b, 0x1e,
+	0xc8, 0x02,
+	0xf9, 0x00,
+	0xfa, 0x00,
+	0xfb, 0x00,
+	0xfc, 0x00,
+	0xfd, 0x00,
+};
+
+static int cx22702_writereg(struct cx22702_state *state, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = {
+		.addr = state->config->demod_address, .flags = 0,
+			.buf = buf, .len = 2 };
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (unlikely(ret != 1)) {
+		printk(KERN_ERR
+			"%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
+			__func__, reg, data, ret);
+		return -1;
+	}
+
+	return 0;
+}
+
+static u8 cx22702_readreg(struct cx22702_state *state, u8 reg)
+{
+	int ret;
+	u8 data;
+
+	struct i2c_msg msg[] = {
+		{ .addr = state->config->demod_address, .flags = 0,
+			.buf = &reg, .len = 1 },
+		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
+			.buf = &data, .len = 1 } };
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (unlikely(ret != 2)) {
+		printk(KERN_ERR "%s: error (reg == 0x%02x, ret == %i)\n",
+			__func__, reg, ret);
+		return 0;
+	}
+
+	return data;
+}
+
+static int cx22702_set_inversion(struct cx22702_state *state, int inversion)
+{
+	u8 val;
+
+	val = cx22702_readreg(state, 0x0C);
+	switch (inversion) {
+	case INVERSION_AUTO:
+		return -EOPNOTSUPP;
+	case INVERSION_ON:
+		val |= 0x01;
+		break;
+	case INVERSION_OFF:
+		val &= 0xfe;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return cx22702_writereg(state, 0x0C, val);
+}
+
+/* Retrieve the demod settings */
+static int cx22702_get_tps(struct cx22702_state *state,
+			   struct dtv_frontend_properties *p)
+{
+	u8 val;
+
+	/* Make sure the TPS regs are valid */
+	if (!(cx22702_readreg(state, 0x0A) & 0x20))
+		return -EAGAIN;
+
+	val = cx22702_readreg(state, 0x01);
+	switch ((val & 0x18) >> 3) {
+	case 0:
+		p->modulation = QPSK;
+		break;
+	case 1:
+		p->modulation = QAM_16;
+		break;
+	case 2:
+		p->modulation = QAM_64;
+		break;
+	}
+	switch (val & 0x07) {
+	case 0:
+		p->hierarchy = HIERARCHY_NONE;
+		break;
+	case 1:
+		p->hierarchy = HIERARCHY_1;
+		break;
+	case 2:
+		p->hierarchy = HIERARCHY_2;
+		break;
+	case 3:
+		p->hierarchy = HIERARCHY_4;
+		break;
+	}
+
+
+	val = cx22702_readreg(state, 0x02);
+	switch ((val & 0x38) >> 3) {
+	case 0:
+		p->code_rate_HP = FEC_1_2;
+		break;
+	case 1:
+		p->code_rate_HP = FEC_2_3;
+		break;
+	case 2:
+		p->code_rate_HP = FEC_3_4;
+		break;
+	case 3:
+		p->code_rate_HP = FEC_5_6;
+		break;
+	case 4:
+		p->code_rate_HP = FEC_7_8;
+		break;
+	}
+	switch (val & 0x07) {
+	case 0:
+		p->code_rate_LP = FEC_1_2;
+		break;
+	case 1:
+		p->code_rate_LP = FEC_2_3;
+		break;
+	case 2:
+		p->code_rate_LP = FEC_3_4;
+		break;
+	case 3:
+		p->code_rate_LP = FEC_5_6;
+		break;
+	case 4:
+		p->code_rate_LP = FEC_7_8;
+		break;
+	}
+
+	val = cx22702_readreg(state, 0x03);
+	switch ((val & 0x0c) >> 2) {
+	case 0:
+		p->guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		p->guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		p->guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		p->guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	}
+	switch (val & 0x03) {
+	case 0:
+		p->transmission_mode = TRANSMISSION_MODE_2K;
+		break;
+	case 1:
+		p->transmission_mode = TRANSMISSION_MODE_8K;
+		break;
+	}
+
+	return 0;
+}
+
+static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct cx22702_state *state = fe->demodulator_priv;
+	u8 val;
+
+	dprintk("%s(%d)\n", __func__, enable);
+	val = cx22702_readreg(state, 0x0D);
+	if (enable)
+		val &= 0xfe;
+	else
+		val |= 0x01;
+	return cx22702_writereg(state, 0x0D, val);
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int cx22702_set_tps(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	u8 val;
+	struct cx22702_state *state = fe->demodulator_priv;
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	/* set inversion */
+	cx22702_set_inversion(state, p->inversion);
+
+	/* set bandwidth */
+	val = cx22702_readreg(state, 0x0C) & 0xcf;
+	switch (p->bandwidth_hz) {
+	case 6000000:
+		val |= 0x20;
+		break;
+	case 7000000:
+		val |= 0x10;
+		break;
+	case 8000000:
+		break;
+	default:
+		dprintk("%s: invalid bandwidth\n", __func__);
+		return -EINVAL;
+	}
+	cx22702_writereg(state, 0x0C, val);
+
+	p->code_rate_LP = FEC_AUTO; /* temp hack as manual not working */
+
+	/* use auto configuration? */
+	if ((p->hierarchy == HIERARCHY_AUTO) ||
+	   (p->modulation == QAM_AUTO) ||
+	   (p->code_rate_HP == FEC_AUTO) ||
+	   (p->code_rate_LP == FEC_AUTO) ||
+	   (p->guard_interval == GUARD_INTERVAL_AUTO) ||
+	   (p->transmission_mode == TRANSMISSION_MODE_AUTO)) {
+
+		/* TPS Source - use hardware driven values */
+		cx22702_writereg(state, 0x06, 0x10);
+		cx22702_writereg(state, 0x07, 0x9);
+		cx22702_writereg(state, 0x08, 0xC1);
+		cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B)
+			& 0xfc);
+		cx22702_writereg(state, 0x0C,
+			(cx22702_readreg(state, 0x0C) & 0xBF) | 0x40);
+		cx22702_writereg(state, 0x00, 0x01); /* Begin acquisition */
+		dprintk("%s: Autodetecting\n", __func__);
+		return 0;
+	}
+
+	/* manually programmed values */
+	switch (p->modulation) {		/* mask 0x18 */
+	case QPSK:
+		val = 0x00;
+		break;
+	case QAM_16:
+		val = 0x08;
+		break;
+	case QAM_64:
+		val = 0x10;
+		break;
+	default:
+		dprintk("%s: invalid modulation\n", __func__);
+		return -EINVAL;
+	}
+	switch (p->hierarchy) {	/* mask 0x07 */
+	case HIERARCHY_NONE:
+		break;
+	case HIERARCHY_1:
+		val |= 0x01;
+		break;
+	case HIERARCHY_2:
+		val |= 0x02;
+		break;
+	case HIERARCHY_4:
+		val |= 0x03;
+		break;
+	default:
+		dprintk("%s: invalid hierarchy\n", __func__);
+		return -EINVAL;
+	}
+	cx22702_writereg(state, 0x06, val);
+
+	switch (p->code_rate_HP) {		/* mask 0x38 */
+	case FEC_NONE:
+	case FEC_1_2:
+		val = 0x00;
+		break;
+	case FEC_2_3:
+		val = 0x08;
+		break;
+	case FEC_3_4:
+		val = 0x10;
+		break;
+	case FEC_5_6:
+		val = 0x18;
+		break;
+	case FEC_7_8:
+		val = 0x20;
+		break;
+	default:
+		dprintk("%s: invalid code_rate_HP\n", __func__);
+		return -EINVAL;
+	}
+	switch (p->code_rate_LP) {		/* mask 0x07 */
+	case FEC_NONE:
+	case FEC_1_2:
+		break;
+	case FEC_2_3:
+		val |= 0x01;
+		break;
+	case FEC_3_4:
+		val |= 0x02;
+		break;
+	case FEC_5_6:
+		val |= 0x03;
+		break;
+	case FEC_7_8:
+		val |= 0x04;
+		break;
+	default:
+		dprintk("%s: invalid code_rate_LP\n", __func__);
+		return -EINVAL;
+	}
+	cx22702_writereg(state, 0x07, val);
+
+	switch (p->guard_interval) {		/* mask 0x0c */
+	case GUARD_INTERVAL_1_32:
+		val = 0x00;
+		break;
+	case GUARD_INTERVAL_1_16:
+		val = 0x04;
+		break;
+	case GUARD_INTERVAL_1_8:
+		val = 0x08;
+		break;
+	case GUARD_INTERVAL_1_4:
+		val = 0x0c;
+		break;
+	default:
+		dprintk("%s: invalid guard_interval\n", __func__);
+		return -EINVAL;
+	}
+	switch (p->transmission_mode) {		/* mask 0x03 */
+	case TRANSMISSION_MODE_2K:
+		break;
+	case TRANSMISSION_MODE_8K:
+		val |= 0x1;
+		break;
+	default:
+		dprintk("%s: invalid transmission_mode\n", __func__);
+		return -EINVAL;
+	}
+	cx22702_writereg(state, 0x08, val);
+	cx22702_writereg(state, 0x0B,
+		(cx22702_readreg(state, 0x0B) & 0xfc) | 0x02);
+	cx22702_writereg(state, 0x0C,
+		(cx22702_readreg(state, 0x0C) & 0xBF) | 0x40);
+
+	/* Begin channel acquisition */
+	cx22702_writereg(state, 0x00, 0x01);
+
+	return 0;
+}
+
+/* Reset the demod hardware and reset all of the configuration registers
+   to a default state. */
+static int cx22702_init(struct dvb_frontend *fe)
+{
+	int i;
+	struct cx22702_state *state = fe->demodulator_priv;
+
+	cx22702_writereg(state, 0x00, 0x02);
+
+	msleep(10);
+
+	for (i = 0; i < ARRAY_SIZE(init_tab); i += 2)
+		cx22702_writereg(state, init_tab[i], init_tab[i + 1]);
+
+	cx22702_writereg(state, 0xf8, (state->config->output_mode << 1)
+		& 0x02);
+
+	cx22702_i2c_gate_ctrl(fe, 0);
+
+	return 0;
+}
+
+static int cx22702_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct cx22702_state *state = fe->demodulator_priv;
+	u8 reg0A;
+	u8 reg23;
+
+	*status = 0;
+
+	reg0A = cx22702_readreg(state, 0x0A);
+	reg23 = cx22702_readreg(state, 0x23);
+
+	dprintk("%s: status demod=0x%02x agc=0x%02x\n"
+		, __func__, reg0A, reg23);
+
+	if (reg0A & 0x10) {
+		*status |= FE_HAS_LOCK;
+		*status |= FE_HAS_VITERBI;
+		*status |= FE_HAS_SYNC;
+	}
+
+	if (reg0A & 0x20)
+		*status |= FE_HAS_CARRIER;
+
+	if (reg23 < 0xf0)
+		*status |= FE_HAS_SIGNAL;
+
+	return 0;
+}
+
+static int cx22702_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct cx22702_state *state = fe->demodulator_priv;
+
+	if (cx22702_readreg(state, 0xE4) & 0x02) {
+		/* Realtime statistics */
+		*ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
+			| (cx22702_readreg(state, 0xDF) & 0x7F);
+	} else {
+		/* Averagtine statistics */
+		*ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
+			| cx22702_readreg(state, 0xDF);
+	}
+
+	return 0;
+}
+
+static int cx22702_read_signal_strength(struct dvb_frontend *fe,
+	u16 *signal_strength)
+{
+	struct cx22702_state *state = fe->demodulator_priv;
+	u8 reg23;
+
+	/*
+	 * Experience suggests that the strength signal register works as
+	 * follows:
+	 * - In the absence of signal, value is 0xff.
+	 * - In the presence of a weak signal, bit 7 is set, not sure what
+	 *   the lower 7 bits mean.
+	 * - In the presence of a strong signal, the register holds a 7-bit
+	 *   value (bit 7 is cleared), with greater values standing for
+	 *   weaker signals.
+	 */
+	reg23 = cx22702_readreg(state, 0x23);
+	if (reg23 & 0x80) {
+		*signal_strength = 0;
+	} else {
+		reg23 = ~reg23 & 0x7f;
+		/* Scale to 16 bit */
+		*signal_strength = (reg23 << 9) | (reg23 << 2) | (reg23 >> 5);
+	}
+
+	return 0;
+}
+
+static int cx22702_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct cx22702_state *state = fe->demodulator_priv;
+
+	u16 rs_ber;
+	if (cx22702_readreg(state, 0xE4) & 0x02) {
+		/* Realtime statistics */
+		rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
+			| (cx22702_readreg(state, 0xDF) & 0x7F);
+	} else {
+		/* Averagine statistics */
+		rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 8
+			| cx22702_readreg(state, 0xDF);
+	}
+	*snr = ~rs_ber;
+
+	return 0;
+}
+
+static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct cx22702_state *state = fe->demodulator_priv;
+
+	u8 _ucblocks;
+
+	/* RS Uncorrectable Packet Count then reset */
+	_ucblocks = cx22702_readreg(state, 0xE3);
+	if (state->prevUCBlocks < _ucblocks)
+		*ucblocks = (_ucblocks - state->prevUCBlocks);
+	else
+		*ucblocks = state->prevUCBlocks - _ucblocks;
+	state->prevUCBlocks = _ucblocks;
+
+	return 0;
+}
+
+static int cx22702_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct cx22702_state *state = fe->demodulator_priv;
+
+	u8 reg0C = cx22702_readreg(state, 0x0C);
+
+	c->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
+	return cx22702_get_tps(state, c);
+}
+
+static int cx22702_get_tune_settings(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	return 0;
+}
+
+static void cx22702_release(struct dvb_frontend *fe)
+{
+	struct cx22702_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static const struct dvb_frontend_ops cx22702_ops;
+
+struct dvb_frontend *cx22702_attach(const struct cx22702_config *config,
+	struct i2c_adapter *i2c)
+{
+	struct cx22702_state *state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct cx22702_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+
+	/* check if the demod is there */
+	if (cx22702_readreg(state, 0x1f) != 0x3)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &cx22702_ops,
+		sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(cx22702_attach);
+
+static const struct dvb_frontend_ops cx22702_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name			= "Conexant CX22702 DVB-T",
+		.frequency_min		= 177000000,
+		.frequency_max		= 858000000,
+		.frequency_stepsize	= 166666,
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+		FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+		FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+		FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
+	},
+
+	.release = cx22702_release,
+
+	.init = cx22702_init,
+	.i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
+
+	.set_frontend = cx22702_set_tps,
+	.get_frontend = cx22702_get_frontend,
+	.get_tune_settings = cx22702_get_tune_settings,
+
+	.read_status = cx22702_read_status,
+	.read_ber = cx22702_read_ber,
+	.read_signal_strength = cx22702_read_signal_strength,
+	.read_snr = cx22702_read_snr,
+	.read_ucblocks = cx22702_read_ucblocks,
+};
+
+MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/cx22702.h b/drivers/media/dvb-frontends/cx22702.h
new file mode 100644
index 0000000..f154e1f
--- /dev/null
+++ b/drivers/media/dvb-frontends/cx22702.h
@@ -0,0 +1,58 @@
+/*
+    Conexant 22702 DVB OFDM demodulator driver
+
+    based on:
+	Alps TDMB7 DVB OFDM demodulator driver
+
+    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
+	  Holger Waechtler <holger@convergence.de>
+
+    Copyright (C) 2004 Steven Toth <stoth@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef CX22702_H
+#define CX22702_H
+
+#include <linux/dvb/frontend.h>
+
+struct cx22702_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* serial/parallel output */
+#define CX22702_PARALLEL_OUTPUT 0
+#define CX22702_SERIAL_OUTPUT   1
+	u8 output_mode;
+};
+
+#if defined(CONFIG_DVB_CX22702) || (defined(CONFIG_DVB_CX22702_MODULE) \
+	&& defined(MODULE))
+extern struct dvb_frontend *cx22702_attach(
+	const struct cx22702_config *config,
+	struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *cx22702_attach(
+	const struct cx22702_config *config,
+	struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb-frontends/cx24110.c b/drivers/media/dvb-frontends/cx24110.c
new file mode 100644
index 0000000..3180f5b
--- /dev/null
+++ b/drivers/media/dvb-frontends/cx24110.c
@@ -0,0 +1,666 @@
+/*
+    cx24110 - Single Chip Satellite Channel Receiver driver module
+
+    Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> based on
+    work
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "dvb_frontend.h"
+#include "cx24110.h"
+
+
+struct cx24110_state {
+
+	struct i2c_adapter* i2c;
+
+	const struct cx24110_config* config;
+
+	struct dvb_frontend frontend;
+
+	u32 lastber;
+	u32 lastbler;
+	u32 lastesn0;
+};
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "cx24110: " args); \
+	} while (0)
+
+static struct {u8 reg; u8 data;} cx24110_regdata[]=
+		      /* Comments beginning with @ denote this value should
+			 be the default */
+	{{0x09,0x01}, /* SoftResetAll */
+	 {0x09,0x00}, /* release reset */
+	 {0x01,0xe8}, /* MSB of code rate 27.5MS/s */
+	 {0x02,0x17}, /* middle byte " */
+	 {0x03,0x29}, /* LSB         " */
+	 {0x05,0x03}, /* @ DVB mode, standard code rate 3/4 */
+	 {0x06,0xa5}, /* @ PLL 60MHz */
+	 {0x07,0x01}, /* @ Fclk, i.e. sampling clock, 60MHz */
+	 {0x0a,0x00}, /* @ partial chip disables, do not set */
+	 {0x0b,0x01}, /* set output clock in gapped mode, start signal low
+			 active for first byte */
+	 {0x0c,0x11}, /* no parity bytes, large hold time, serial data out */
+	 {0x0d,0x6f}, /* @ RS Sync/Unsync thresholds */
+	 {0x10,0x40}, /* chip doc is misleading here: write bit 6 as 1
+			 to avoid starting the BER counter. Reset the
+			 CRC test bit. Finite counting selected */
+	 {0x15,0xff}, /* @ size of the limited time window for RS BER
+			 estimation. It is <value>*256 RS blocks, this
+			 gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */
+	 {0x16,0x00}, /* @ enable all RS output ports */
+	 {0x17,0x04}, /* @ time window allowed for the RS to sync */
+	 {0x18,0xae}, /* @ allow all standard DVB code rates to be scanned
+			 for automatically */
+		      /* leave the current code rate and normalization
+			 registers as they are after reset... */
+	 {0x21,0x10}, /* @ during AutoAcq, search each viterbi setting
+			 only once */
+	 {0x23,0x18}, /* @ size of the limited time window for Viterbi BER
+			 estimation. It is <value>*65536 channel bits, i.e.
+			 approx. 38ms at 27.5MS/s, rate 3/4 */
+	 {0x24,0x24}, /* do not trigger Viterbi CRC test. Finite count window */
+		      /* leave front-end AGC parameters at default values */
+		      /* leave decimation AGC parameters at default values */
+	 {0x35,0x40}, /* disable all interrupts. They are not connected anyway */
+	 {0x36,0xff}, /* clear all interrupt pending flags */
+	 {0x37,0x00}, /* @ fully enable AutoAcqq state machine */
+	 {0x38,0x07}, /* @ enable fade recovery, but not autostart AutoAcq */
+		      /* leave the equalizer parameters on their default values */
+		      /* leave the final AGC parameters on their default values */
+	 {0x41,0x00}, /* @ MSB of front-end derotator frequency */
+	 {0x42,0x00}, /* @ middle bytes " */
+	 {0x43,0x00}, /* @ LSB          " */
+		      /* leave the carrier tracking loop parameters on default */
+		      /* leave the bit timing loop parameters at default */
+	 {0x56,0x4d}, /* set the filtune voltage to 2.7V, as recommended by */
+		      /* the cx24108 data sheet for symbol rates above 15MS/s */
+	 {0x57,0x00}, /* @ Filter sigma delta enabled, positive */
+	 {0x61,0x95}, /* GPIO pins 1-4 have special function */
+	 {0x62,0x05}, /* GPIO pin 5 has special function, pin 6 is GPIO */
+	 {0x63,0x00}, /* All GPIO pins use CMOS output characteristics */
+	 {0x64,0x20}, /* GPIO 6 is input, all others are outputs */
+	 {0x6d,0x30}, /* tuner auto mode clock freq 62kHz */
+	 {0x70,0x15}, /* use auto mode, tuner word is 21 bits long */
+	 {0x73,0x00}, /* @ disable several demod bypasses */
+	 {0x74,0x00}, /* @  " */
+	 {0x75,0x00}  /* @  " */
+		      /* the remaining registers are for SEC */
+	};
+
+
+static int cx24110_writereg (struct cx24110_state* state, int reg, int data)
+{
+	u8 buf [] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+	int err;
+
+	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+		dprintk ("%s: writereg error (err == %i, reg == 0x%02x,"
+			 " data == 0x%02x)\n", __func__, err, reg, data);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int cx24110_readreg (struct cx24110_state* state, u8 reg)
+{
+	int ret;
+	u8 b0 [] = { reg };
+	u8 b1 [] = { 0 };
+	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) return ret;
+
+	return b1[0];
+}
+
+static int cx24110_set_inversion (struct cx24110_state* state, fe_spectral_inversion_t inversion)
+{
+/* fixme (low): error handling */
+
+	switch (inversion) {
+	case INVERSION_OFF:
+		cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1);
+		/* AcqSpectrInvDis on. No idea why someone should want this */
+		cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)&0xf7);
+		/* Initial value 0 at start of acq */
+		cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)&0xef);
+		/* current value 0 */
+		/* The cx24110 manual tells us this reg is read-only.
+		   But what the heck... set it ayways */
+		break;
+	case INVERSION_ON:
+		cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1);
+		/* AcqSpectrInvDis on. No idea why someone should want this */
+		cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)|0x08);
+		/* Initial value 1 at start of acq */
+		cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)|0x10);
+		/* current value 1 */
+		break;
+	case INVERSION_AUTO:
+		cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xfe);
+		/* AcqSpectrInvDis off. Leave initial & current states as is */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cx24110_set_fec (struct cx24110_state* state, fe_code_rate_t fec)
+{
+/* fixme (low): error handling */
+
+	static const int rate[]={-1,1,2,3,5,7,-1};
+	static const int g1[]={-1,0x01,0x02,0x05,0x15,0x45,-1};
+	static const int g2[]={-1,0x01,0x03,0x06,0x1a,0x7a,-1};
+
+	/* Well, the AutoAcq engine of the cx24106 and 24110 automatically
+	   searches all enabled viterbi rates, and can handle non-standard
+	   rates as well. */
+
+	if (fec>FEC_AUTO)
+		fec=FEC_AUTO;
+
+	if (fec==FEC_AUTO) { /* (re-)establish AutoAcq behaviour */
+		cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xdf);
+		/* clear AcqVitDis bit */
+		cx24110_writereg(state,0x18,0xae);
+		/* allow all DVB standard code rates */
+		cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|0x3);
+		/* set nominal Viterbi rate 3/4 */
+		cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|0x3);
+		/* set current Viterbi rate 3/4 */
+		cx24110_writereg(state,0x1a,0x05); cx24110_writereg(state,0x1b,0x06);
+		/* set the puncture registers for code rate 3/4 */
+		return 0;
+	} else {
+		cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x20);
+		/* set AcqVitDis bit */
+		if(rate[fec]>0) {
+			cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|rate[fec]);
+			/* set nominal Viterbi rate */
+			cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|rate[fec]);
+			/* set current Viterbi rate */
+			cx24110_writereg(state,0x1a,g1[fec]);
+			cx24110_writereg(state,0x1b,g2[fec]);
+			/* not sure if this is the right way: I always used AutoAcq mode */
+	   } else
+		   return -EOPNOTSUPP;
+/* fixme (low): which is the correct return code? */
+	};
+	return 0;
+}
+
+static fe_code_rate_t cx24110_get_fec (struct cx24110_state* state)
+{
+	int i;
+
+	i=cx24110_readreg(state,0x22)&0x0f;
+	if(!(i&0x08)) {
+		return FEC_1_2 + i - 1;
+	} else {
+/* fixme (low): a special code rate has been selected. In theory, we need to
+   return a denominator value, a numerator value, and a pair of puncture
+   maps to correctly describe this mode. But this should never happen in
+   practice, because it cannot be set by cx24110_get_fec. */
+	   return FEC_NONE;
+	}
+}
+
+static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
+{
+/* fixme (low): add error handling */
+	u32 ratio;
+	u32 tmp, fclk, BDRI;
+
+	static const u32 bands[]={5000000UL,15000000UL,90999000UL/2};
+	int i;
+
+	dprintk("cx24110 debug: entering %s(%d)\n",__func__,srate);
+	if (srate>90999000UL/2)
+		srate=90999000UL/2;
+	if (srate<500000)
+		srate=500000;
+
+	for(i = 0; (i < ARRAY_SIZE(bands)) && (srate>bands[i]); i++)
+		;
+	/* first, check which sample rate is appropriate: 45, 60 80 or 90 MHz,
+	   and set the PLL accordingly (R07[1:0] Fclk, R06[7:4] PLLmult,
+	   R06[3:0] PLLphaseDetGain */
+	tmp=cx24110_readreg(state,0x07)&0xfc;
+	if(srate<90999000UL/4) { /* sample rate 45MHz*/
+		cx24110_writereg(state,0x07,tmp);
+		cx24110_writereg(state,0x06,0x78);
+		fclk=90999000UL/2;
+	} else if(srate<60666000UL/2) { /* sample rate 60MHz */
+		cx24110_writereg(state,0x07,tmp|0x1);
+		cx24110_writereg(state,0x06,0xa5);
+		fclk=60666000UL;
+	} else if(srate<80888000UL/2) { /* sample rate 80MHz */
+		cx24110_writereg(state,0x07,tmp|0x2);
+		cx24110_writereg(state,0x06,0x87);
+		fclk=80888000UL;
+	} else { /* sample rate 90MHz */
+		cx24110_writereg(state,0x07,tmp|0x3);
+		cx24110_writereg(state,0x06,0x78);
+		fclk=90999000UL;
+	};
+	dprintk("cx24110 debug: fclk %d Hz\n",fclk);
+	/* we need to divide two integers with approx. 27 bits in 32 bit
+	   arithmetic giving a 25 bit result */
+	/* the maximum dividend is 90999000/2, 0x02b6446c, this number is
+	   also the most complex divisor. Hence, the dividend has,
+	   assuming 32bit unsigned arithmetic, 6 clear bits on top, the
+	   divisor 2 unused bits at the bottom. Also, the quotient is
+	   always less than 1/2. Borrowed from VES1893.c, of course */
+
+	tmp=srate<<6;
+	BDRI=fclk>>2;
+	ratio=(tmp/BDRI);
+
+	tmp=(tmp%BDRI)<<8;
+	ratio=(ratio<<8)+(tmp/BDRI);
+
+	tmp=(tmp%BDRI)<<8;
+	ratio=(ratio<<8)+(tmp/BDRI);
+
+	tmp=(tmp%BDRI)<<1;
+	ratio=(ratio<<1)+(tmp/BDRI);
+
+	dprintk("srate= %d (range %d, up to %d)\n", srate,i,bands[i]);
+	dprintk("fclk = %d\n", fclk);
+	dprintk("ratio= %08x\n", ratio);
+
+	cx24110_writereg(state, 0x1, (ratio>>16)&0xff);
+	cx24110_writereg(state, 0x2, (ratio>>8)&0xff);
+	cx24110_writereg(state, 0x3, (ratio)&0xff);
+
+	return 0;
+
+}
+
+static int _cx24110_pll_write (struct dvb_frontend* fe, const u8 buf[], int len)
+{
+	struct cx24110_state *state = fe->demodulator_priv;
+
+	if (len != 3)
+		return -EINVAL;
+
+/* tuner data is 21 bits long, must be left-aligned in data */
+/* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */
+/* FIXME (low): add error handling, avoid infinite loops if HW fails... */
+
+	cx24110_writereg(state,0x6d,0x30); /* auto mode at 62kHz */
+	cx24110_writereg(state,0x70,0x15); /* auto mode 21 bits */
+
+	/* if the auto tuner writer is still busy, clear it out */
+	while (cx24110_readreg(state,0x6d)&0x80)
+		cx24110_writereg(state,0x72,0);
+
+	/* write the topmost 8 bits */
+	cx24110_writereg(state,0x72,buf[0]);
+
+	/* wait for the send to be completed */
+	while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
+		;
+
+	/* send another 8 bytes */
+	cx24110_writereg(state,0x72,buf[1]);
+	while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
+		;
+
+	/* and the topmost 5 bits of this byte */
+	cx24110_writereg(state,0x72,buf[2]);
+	while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
+		;
+
+	/* now strobe the enable line once */
+	cx24110_writereg(state,0x6d,0x32);
+	cx24110_writereg(state,0x6d,0x30);
+
+	return 0;
+}
+
+static int cx24110_initfe(struct dvb_frontend* fe)
+{
+	struct cx24110_state *state = fe->demodulator_priv;
+/* fixme (low): error handling */
+	int i;
+
+	dprintk("%s: init chip\n", __func__);
+
+	for(i = 0; i < ARRAY_SIZE(cx24110_regdata); i++) {
+		cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
+	};
+
+	return 0;
+}
+
+static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	struct cx24110_state *state = fe->demodulator_priv;
+
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0xc0);
+	case SEC_VOLTAGE_18:
+		return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0x40);
+	default:
+		return -EINVAL;
+	};
+}
+
+static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
+{
+	int rv, bit;
+	struct cx24110_state *state = fe->demodulator_priv;
+	unsigned long timeout;
+
+	if (burst == SEC_MINI_A)
+		bit = 0x00;
+	else if (burst == SEC_MINI_B)
+		bit = 0x08;
+	else
+		return -EINVAL;
+
+	rv = cx24110_readreg(state, 0x77);
+	if (!(rv & 0x04))
+		cx24110_writereg(state, 0x77, rv | 0x04);
+
+	rv = cx24110_readreg(state, 0x76);
+	cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40 | bit));
+	timeout = jiffies + msecs_to_jiffies(100);
+	while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40))
+		; /* wait for LNB ready */
+
+	return 0;
+}
+
+static int cx24110_send_diseqc_msg(struct dvb_frontend* fe,
+				   struct dvb_diseqc_master_cmd *cmd)
+{
+	int i, rv;
+	struct cx24110_state *state = fe->demodulator_priv;
+	unsigned long timeout;
+
+	if (cmd->msg_len < 3 || cmd->msg_len > 6)
+		return -EINVAL;  /* not implemented */
+
+	for (i = 0; i < cmd->msg_len; i++)
+		cx24110_writereg(state, 0x79 + i, cmd->msg[i]);
+
+	rv = cx24110_readreg(state, 0x77);
+	if (rv & 0x04) {
+		cx24110_writereg(state, 0x77, rv & ~0x04);
+		msleep(30); /* reportedly fixes switching problems */
+	}
+
+	rv = cx24110_readreg(state, 0x76);
+
+	cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3));
+	timeout = jiffies + msecs_to_jiffies(100);
+	while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40))
+		; /* wait for LNB ready */
+
+	return 0;
+}
+
+static int cx24110_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct cx24110_state *state = fe->demodulator_priv;
+
+	int sync = cx24110_readreg (state, 0x55);
+
+	*status = 0;
+
+	if (sync & 0x10)
+		*status |= FE_HAS_SIGNAL;
+
+	if (sync & 0x08)
+		*status |= FE_HAS_CARRIER;
+
+	sync = cx24110_readreg (state, 0x08);
+
+	if (sync & 0x40)
+		*status |= FE_HAS_VITERBI;
+
+	if (sync & 0x20)
+		*status |= FE_HAS_SYNC;
+
+	if ((sync & 0x60) == 0x60)
+		*status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int cx24110_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct cx24110_state *state = fe->demodulator_priv;
+
+	/* fixme (maybe): value range is 16 bit. Scale? */
+	if(cx24110_readreg(state,0x24)&0x10) {
+		/* the Viterbi error counter has finished one counting window */
+		cx24110_writereg(state,0x24,0x04); /* select the ber reg */
+		state->lastber=cx24110_readreg(state,0x25)|
+			(cx24110_readreg(state,0x26)<<8);
+		cx24110_writereg(state,0x24,0x04); /* start new count window */
+		cx24110_writereg(state,0x24,0x14);
+	}
+	*ber = state->lastber;
+
+	return 0;
+}
+
+static int cx24110_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+{
+	struct cx24110_state *state = fe->demodulator_priv;
+
+/* no provision in hardware. Read the frontend AGC accumulator. No idea how to scale this, but I know it is 2s complement */
+	u8 signal = cx24110_readreg (state, 0x27)+128;
+	*signal_strength = (signal << 8) | signal;
+
+	return 0;
+}
+
+static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct cx24110_state *state = fe->demodulator_priv;
+
+	/* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */
+	if(cx24110_readreg(state,0x6a)&0x80) {
+		/* the Es/N0 error counter has finished one counting window */
+		state->lastesn0=cx24110_readreg(state,0x69)|
+			(cx24110_readreg(state,0x68)<<8);
+		cx24110_writereg(state,0x6a,0x84); /* start new count window */
+	}
+	*snr = state->lastesn0;
+
+	return 0;
+}
+
+static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct cx24110_state *state = fe->demodulator_priv;
+
+	if(cx24110_readreg(state,0x10)&0x40) {
+		/* the RS error counter has finished one counting window */
+		cx24110_writereg(state,0x10,0x60); /* select the byer reg */
+		(void)(cx24110_readreg(state, 0x12) |
+			(cx24110_readreg(state, 0x13) << 8) |
+			(cx24110_readreg(state, 0x14) << 16));
+		cx24110_writereg(state,0x10,0x70); /* select the bler reg */
+		state->lastbler=cx24110_readreg(state,0x12)|
+			(cx24110_readreg(state,0x13)<<8)|
+			(cx24110_readreg(state,0x14)<<16);
+		cx24110_writereg(state,0x10,0x20); /* start new count window */
+	}
+	*ucblocks = state->lastbler;
+
+	return 0;
+}
+
+static int cx24110_set_frontend(struct dvb_frontend *fe)
+{
+	struct cx24110_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	cx24110_set_inversion(state, p->inversion);
+	cx24110_set_fec(state, p->fec_inner);
+	cx24110_set_symbolrate(state, p->symbol_rate);
+	cx24110_writereg(state,0x04,0x05); /* start acquisition */
+
+	return 0;
+}
+
+static int cx24110_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct cx24110_state *state = fe->demodulator_priv;
+	s32 afc; unsigned sclk;
+
+/* cannot read back tuner settings (freq). Need to have some private storage */
+
+	sclk = cx24110_readreg (state, 0x07) & 0x03;
+/* ok, real AFC (FEDR) freq. is afc/2^24*fsamp, fsamp=45/60/80/90MHz.
+ * Need 64 bit arithmetic. Is thiss possible in the kernel? */
+	if (sclk==0) sclk=90999000L/2L;
+	else if (sclk==1) sclk=60666000L;
+	else if (sclk==2) sclk=80888000L;
+	else sclk=90999000L;
+	sclk>>=8;
+	afc = sclk*(cx24110_readreg (state, 0x44)&0x1f)+
+	      ((sclk*cx24110_readreg (state, 0x45))>>8)+
+	      ((sclk*cx24110_readreg (state, 0x46))>>16);
+
+	p->frequency += afc;
+	p->inversion = (cx24110_readreg (state, 0x22) & 0x10) ?
+				INVERSION_ON : INVERSION_OFF;
+	p->fec_inner = cx24110_get_fec(state);
+
+	return 0;
+}
+
+static int cx24110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct cx24110_state *state = fe->demodulator_priv;
+
+	return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&~0x10)|(((tone==SEC_TONE_ON))?0x10:0));
+}
+
+static void cx24110_release(struct dvb_frontend* fe)
+{
+	struct cx24110_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops cx24110_ops;
+
+struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
+				    struct i2c_adapter* i2c)
+{
+	struct cx24110_state* state = NULL;
+	int ret;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct cx24110_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->lastber = 0;
+	state->lastbler = 0;
+	state->lastesn0 = 0;
+
+	/* check if the demod is there */
+	ret = cx24110_readreg(state, 0x00);
+	if ((ret != 0x5a) && (ret != 0x69)) goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops cx24110_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name = "Conexant CX24110 DVB-S",
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		.frequency_stepsize = 1011,  /* kHz for QPSK frontends */
+		.frequency_tolerance = 29500,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_RECOVER
+	},
+
+	.release = cx24110_release,
+
+	.init = cx24110_initfe,
+	.write = _cx24110_pll_write,
+	.set_frontend = cx24110_set_frontend,
+	.get_frontend = cx24110_get_frontend,
+	.read_status = cx24110_read_status,
+	.read_ber = cx24110_read_ber,
+	.read_signal_strength = cx24110_read_signal_strength,
+	.read_snr = cx24110_read_snr,
+	.read_ucblocks = cx24110_read_ucblocks,
+
+	.diseqc_send_master_cmd = cx24110_send_diseqc_msg,
+	.set_tone = cx24110_set_tone,
+	.set_voltage = cx24110_set_voltage,
+	.diseqc_send_burst = cx24110_diseqc_send_burst,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Conexant CX24110 DVB-S Demodulator driver");
+MODULE_AUTHOR("Peter Hettkamp");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(cx24110_attach);
diff --git a/drivers/media/dvb-frontends/cx24110.h b/drivers/media/dvb-frontends/cx24110.h
new file mode 100644
index 0000000..fdcceee
--- /dev/null
+++ b/drivers/media/dvb-frontends/cx24110.h
@@ -0,0 +1,61 @@
+/*
+    cx24110 - Single Chip Satellite Channel Receiver driver module
+
+    Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> based on
+    work
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef CX24110_H
+#define CX24110_H
+
+#include <linux/dvb/frontend.h>
+
+struct cx24110_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+};
+
+static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val)
+{
+	u8 buf[] = {
+		(u8)((val >> 24) & 0xff),
+		(u8)((val >> 16) & 0xff),
+		(u8)((val >> 8) & 0xff)
+	};
+
+	if (fe->ops.write)
+		return fe->ops.write(fe, buf, 3);
+	return 0;
+}
+
+#if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE))
+extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
+					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
+						  struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_CX24110
+
+#endif // CX24110_H
diff --git a/drivers/media/dvb-frontends/cx24113.c b/drivers/media/dvb-frontends/cx24113.c
new file mode 100644
index 0000000..3883c3b
--- /dev/null
+++ b/drivers/media/dvb-frontends/cx24113.c
@@ -0,0 +1,618 @@
+/*
+ *  Driver for Conexant CX24113/CX24128 Tuner (Satellite)
+ *
+ *  Copyright (C) 2007-8 Patrick Boettcher <pb@linuxtv.org>
+ *
+ *  Developed for BBTI / Technisat
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "dvb_frontend.h"
+#include "cx24113.h"
+
+static int debug;
+
+#define cx_info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0)
+#define cx_err(args...)  do { printk(KERN_ERR  "CX24113: " args); } while (0)
+
+#define dprintk(args...) \
+	do { \
+		if (debug) { \
+			printk(KERN_DEBUG "CX24113: %s: ", __func__); \
+			printk(args); \
+		} \
+	} while (0)
+
+struct cx24113_state {
+	struct i2c_adapter *i2c;
+	const struct cx24113_config *config;
+
+#define REV_CX24113 0x23
+	u8 rev;
+	u8 ver;
+
+	u8 icp_mode:1;
+
+#define ICP_LEVEL1 0
+#define ICP_LEVEL2 1
+#define ICP_LEVEL3 2
+#define ICP_LEVEL4 3
+	u8 icp_man:2;
+	u8 icp_auto_low:2;
+	u8 icp_auto_mlow:2;
+	u8 icp_auto_mhi:2;
+	u8 icp_auto_hi:2;
+	u8 icp_dig;
+
+#define LNA_MIN_GAIN 0
+#define LNA_MID_GAIN 1
+#define LNA_MAX_GAIN 2
+	u8 lna_gain:2;
+
+	u8 acp_on:1;
+
+	u8 vco_mode:2;
+	u8 vco_shift:1;
+#define VCOBANDSEL_6 0x80
+#define VCOBANDSEL_5 0x01
+#define VCOBANDSEL_4 0x02
+#define VCOBANDSEL_3 0x04
+#define VCOBANDSEL_2 0x08
+#define VCOBANDSEL_1 0x10
+	u8 vco_band;
+
+#define VCODIV4 4
+#define VCODIV2 2
+	u8 vcodiv;
+
+	u8 bs_delay:4;
+	u16 bs_freqcnt:13;
+	u16 bs_rdiv;
+	u8 prescaler_mode:1;
+
+	u8 rfvga_bias_ctrl;
+
+	s16 tuner_gain_thres;
+	u8  gain_level;
+
+	u32 frequency;
+
+	u8 refdiv;
+
+	u8 Fwindow_enabled;
+};
+
+static int cx24113_writereg(struct cx24113_state *state, int reg, int data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->i2c_addr,
+		.flags = 0, .buf = buf, .len = 2 };
+	int err = i2c_transfer(state->i2c, &msg, 1);
+	if (err != 1) {
+		printk(KERN_DEBUG "%s: writereg error(err == %i, reg == 0x%02x,"
+			 " data == 0x%02x)\n", __func__, err, reg, data);
+		return err;
+	}
+
+	return 0;
+}
+
+static int cx24113_readreg(struct cx24113_state *state, u8 reg)
+{
+	int ret;
+	u8 b;
+	struct i2c_msg msg[] = {
+		{ .addr = state->config->i2c_addr,
+			.flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = state->config->i2c_addr,
+			.flags = I2C_M_RD, .buf = &b, .len = 1 }
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		printk(KERN_DEBUG "%s: reg=0x%x (error=%d)\n",
+			__func__, reg, ret);
+		return ret;
+	}
+
+	return b;
+}
+
+static void cx24113_set_parameters(struct cx24113_state *state)
+{
+	u8 r;
+
+	r = cx24113_readreg(state, 0x10) & 0x82;
+	r |= state->icp_mode;
+	r |= state->icp_man << 4;
+	r |= state->icp_dig << 2;
+	r |= state->prescaler_mode << 5;
+	cx24113_writereg(state, 0x10, r);
+
+	r = (state->icp_auto_low  << 0) | (state->icp_auto_mlow << 2)
+		| (state->icp_auto_mhi << 4) | (state->icp_auto_hi << 6);
+	cx24113_writereg(state, 0x11, r);
+
+	if (state->rev == REV_CX24113) {
+		r = cx24113_readreg(state, 0x20) & 0xec;
+		r |= state->lna_gain;
+		r |= state->rfvga_bias_ctrl << 4;
+		cx24113_writereg(state, 0x20, r);
+	}
+
+	r = cx24113_readreg(state, 0x12) & 0x03;
+	r |= state->acp_on << 2;
+	r |= state->bs_delay << 4;
+	cx24113_writereg(state, 0x12, r);
+
+	r = cx24113_readreg(state, 0x18) & 0x40;
+	r |= state->vco_shift;
+	if (state->vco_band == VCOBANDSEL_6)
+		r |= (1 << 7);
+	else
+		r |= (state->vco_band << 1);
+	cx24113_writereg(state, 0x18, r);
+
+	r  = cx24113_readreg(state, 0x14) & 0x20;
+	r |= (state->vco_mode << 6) | ((state->bs_freqcnt >> 8) & 0x1f);
+	cx24113_writereg(state, 0x14, r);
+	cx24113_writereg(state, 0x15, (state->bs_freqcnt        & 0xff));
+
+	cx24113_writereg(state, 0x16, (state->bs_rdiv >> 4) & 0xff);
+	r = (cx24113_readreg(state, 0x17) & 0x0f) |
+		((state->bs_rdiv & 0x0f) << 4);
+	cx24113_writereg(state, 0x17, r);
+}
+
+#define VGA_0 0x00
+#define VGA_1 0x04
+#define VGA_2 0x02
+#define VGA_3 0x06
+#define VGA_4 0x01
+#define VGA_5 0x05
+#define VGA_6 0x03
+#define VGA_7 0x07
+
+#define RFVGA_0 0x00
+#define RFVGA_1 0x01
+#define RFVGA_2 0x02
+#define RFVGA_3 0x03
+
+static int cx24113_set_gain_settings(struct cx24113_state *state,
+		s16 power_estimation)
+{
+	u8 ampout = cx24113_readreg(state, 0x1d) & 0xf0,
+	   vga    = cx24113_readreg(state, 0x1f) & 0x3f,
+	   rfvga  = cx24113_readreg(state, 0x20) & 0xf3;
+	u8 gain_level = power_estimation >= state->tuner_gain_thres;
+
+	dprintk("power estimation: %d, thres: %d, gain_level: %d/%d\n",
+			power_estimation, state->tuner_gain_thres,
+			state->gain_level, gain_level);
+
+	if (gain_level == state->gain_level)
+		return 0; /* nothing to be done */
+
+	ampout |= 0xf;
+
+	if (gain_level) {
+		rfvga |= RFVGA_0 << 2;
+		vga   |= (VGA_7 << 3) | VGA_7;
+	} else {
+		rfvga |= RFVGA_2 << 2;
+		vga  |= (VGA_6 << 3) | VGA_2;
+	}
+	state->gain_level = gain_level;
+
+	cx24113_writereg(state, 0x1d, ampout);
+	cx24113_writereg(state, 0x1f, vga);
+	cx24113_writereg(state, 0x20, rfvga);
+
+	return 1; /* did something */
+}
+
+static int cx24113_set_Fref(struct cx24113_state *state, u8 high)
+{
+	u8 xtal = cx24113_readreg(state, 0x02);
+	if (state->rev == 0x43 && state->vcodiv == VCODIV4)
+		high = 1;
+
+	xtal &= ~0x2;
+	if (high)
+		xtal |= high << 1;
+	return cx24113_writereg(state, 0x02, xtal);
+}
+
+static int cx24113_enable(struct cx24113_state *state, u8 enable)
+{
+	u8 r21 = (cx24113_readreg(state, 0x21) & 0xc0) | enable;
+	if (state->rev == REV_CX24113)
+		r21 |= (1 << 1);
+	return cx24113_writereg(state, 0x21, r21);
+}
+
+static int cx24113_set_bandwidth(struct cx24113_state *state, u32 bandwidth_khz)
+{
+	u8 r;
+
+	if (bandwidth_khz <= 19000)
+		r = 0x03 << 6;
+	else if (bandwidth_khz <= 25000)
+		r = 0x02 << 6;
+	else
+		r = 0x01 << 6;
+
+	dprintk("bandwidth to be set: %d\n", bandwidth_khz);
+	bandwidth_khz *= 10;
+	bandwidth_khz -= 10000;
+	bandwidth_khz /= 1000;
+	bandwidth_khz += 5;
+	bandwidth_khz /= 10;
+
+	dprintk("bandwidth: %d %d\n", r >> 6, bandwidth_khz);
+
+	r |= bandwidth_khz & 0x3f;
+
+	return cx24113_writereg(state, 0x1e, r);
+}
+
+static int cx24113_set_clk_inversion(struct cx24113_state *state, u8 on)
+{
+	u8 r = (cx24113_readreg(state, 0x10) & 0x7f) | ((on & 0x1) << 7);
+	return cx24113_writereg(state, 0x10, r);
+}
+
+static int cx24113_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct cx24113_state *state = fe->tuner_priv;
+	u8 r = (cx24113_readreg(state, 0x10) & 0x02) >> 1;
+	if (r)
+		*status |= TUNER_STATUS_LOCKED;
+	dprintk("PLL locked: %d\n", r);
+	return 0;
+}
+
+static u8 cx24113_set_ref_div(struct cx24113_state *state, u8 refdiv)
+{
+	if (state->rev == 0x43 && state->vcodiv == VCODIV4)
+		refdiv = 2;
+	return state->refdiv = refdiv;
+}
+
+static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f)
+{
+	s32 N;
+	s64 F;
+	u64 dividend;
+	u8 R, r;
+	u8 vcodiv;
+	u8 factor;
+	s32 freq_hz = state->frequency * 1000;
+
+	if (state->config->xtal_khz < 20000)
+		factor = 1;
+	else
+		factor = 2;
+
+	if (state->rev == REV_CX24113) {
+		if (state->frequency >= 1100000)
+			vcodiv = VCODIV2;
+		else
+			vcodiv = VCODIV4;
+	} else {
+		if (state->frequency >= 1165000)
+			vcodiv = VCODIV2;
+		else
+			vcodiv = VCODIV4;
+	}
+	state->vcodiv = vcodiv;
+
+	dprintk("calculating N/F for %dHz with vcodiv %d\n", freq_hz, vcodiv);
+	R = 0;
+	do {
+		R = cx24113_set_ref_div(state, R + 1);
+
+		/* calculate tuner PLL settings: */
+		N =  (freq_hz / 100 * vcodiv) * R;
+		N /= (state->config->xtal_khz) * factor * 2;
+		N += 5;     /* For round up. */
+		N /= 10;
+		N -= 32;
+	} while (N < 6 && R < 3);
+
+	if (N < 6) {
+		cx_err("strange frequency: N < 6\n");
+		return;
+	}
+	F = freq_hz;
+	F *= (u64) (R * vcodiv * 262144);
+	dprintk("1 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
+	/* do_div needs an u64 as first argument */
+	dividend = F;
+	do_div(dividend, state->config->xtal_khz * 1000 * factor * 2);
+	F = dividend;
+	dprintk("2 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
+	F -= (N + 32) * 262144;
+
+	dprintk("3 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
+
+	if (state->Fwindow_enabled) {
+		if (F > (262144 / 2 - 1638))
+			F = 262144 / 2 - 1638;
+		if (F < (-262144 / 2 + 1638))
+			F = -262144 / 2 + 1638;
+		if ((F < 3277 && F > 0) || (F > -3277 && F < 0)) {
+			F = 0;
+			r = cx24113_readreg(state, 0x10);
+			cx24113_writereg(state, 0x10, r | (1 << 6));
+		}
+	}
+	dprintk("4 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
+
+	*n = (u16) N;
+	*f = (s32) F;
+}
+
+
+static void cx24113_set_nfr(struct cx24113_state *state, u16 n, s32 f, u8 r)
+{
+	u8 reg;
+	cx24113_writereg(state, 0x19, (n >> 1) & 0xff);
+
+	reg = ((n & 0x1) << 7) | ((f >> 11) & 0x7f);
+	cx24113_writereg(state, 0x1a, reg);
+
+	cx24113_writereg(state, 0x1b, (f >> 3) & 0xff);
+
+	reg = cx24113_readreg(state, 0x1c) & 0x1f;
+	cx24113_writereg(state, 0x1c, reg | ((f & 0x7) << 5));
+
+	cx24113_set_Fref(state, r - 1);
+}
+
+static int cx24113_set_frequency(struct cx24113_state *state, u32 frequency)
+{
+	u8 r = 1; /* or 2 */
+	u16 n = 6;
+	s32 f = 0;
+
+	r = cx24113_readreg(state, 0x14);
+	cx24113_writereg(state, 0x14, r & 0x3f);
+
+	r = cx24113_readreg(state, 0x10);
+	cx24113_writereg(state, 0x10, r & 0xbf);
+
+	state->frequency = frequency;
+
+	dprintk("tuning to frequency: %d\n", frequency);
+
+	cx24113_calc_pll_nf(state, &n, &f);
+	cx24113_set_nfr(state, n, f, state->refdiv);
+
+	r = cx24113_readreg(state, 0x18) & 0xbf;
+	if (state->vcodiv != VCODIV2)
+		r |= 1 << 6;
+	cx24113_writereg(state, 0x18, r);
+
+	/* The need for this sleep is not clear. But helps in some cases */
+	msleep(5);
+
+	r = cx24113_readreg(state, 0x1c) & 0xef;
+	cx24113_writereg(state, 0x1c, r | (1 << 4));
+	return 0;
+}
+
+static int cx24113_init(struct dvb_frontend *fe)
+{
+	struct cx24113_state *state = fe->tuner_priv;
+	int ret;
+
+	state->tuner_gain_thres = -50;
+	state->gain_level = 255; /* to force a gain-setting initialization */
+	state->icp_mode = 0;
+
+	if (state->config->xtal_khz < 11000) {
+		state->icp_auto_hi  = ICP_LEVEL4;
+		state->icp_auto_mhi  = ICP_LEVEL4;
+		state->icp_auto_mlow = ICP_LEVEL3;
+		state->icp_auto_low = ICP_LEVEL3;
+	} else {
+		state->icp_auto_hi  = ICP_LEVEL4;
+		state->icp_auto_mhi  = ICP_LEVEL4;
+		state->icp_auto_mlow = ICP_LEVEL3;
+		state->icp_auto_low = ICP_LEVEL2;
+	}
+
+	state->icp_dig = ICP_LEVEL3;
+	state->icp_man = ICP_LEVEL1;
+	state->acp_on  = 1;
+	state->vco_mode = 0;
+	state->vco_shift = 0;
+	state->vco_band = VCOBANDSEL_1;
+	state->bs_delay = 8;
+	state->bs_freqcnt = 0x0fff;
+	state->bs_rdiv = 0x0fff;
+	state->prescaler_mode = 0;
+	state->lna_gain = LNA_MAX_GAIN;
+	state->rfvga_bias_ctrl = 1;
+	state->Fwindow_enabled = 1;
+
+	cx24113_set_Fref(state, 0);
+	cx24113_enable(state, 0x3d);
+	cx24113_set_parameters(state);
+
+	cx24113_set_gain_settings(state, -30);
+
+	cx24113_set_bandwidth(state, 18025);
+	cx24113_set_clk_inversion(state, 1);
+
+	if (state->config->xtal_khz >= 40000)
+		ret = cx24113_writereg(state, 0x02,
+			(cx24113_readreg(state, 0x02) & 0xfb) | (1 << 2));
+	else
+		ret = cx24113_writereg(state, 0x02,
+			(cx24113_readreg(state, 0x02) & 0xfb) | (0 << 2));
+
+	return ret;
+}
+
+static int cx24113_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct cx24113_state *state = fe->tuner_priv;
+	/* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */
+	u32 roll_off = 675;
+	u32 bw;
+
+	bw  = ((c->symbol_rate/100) * roll_off) / 1000;
+	bw += (10000000/100) + 5;
+	bw /= 10;
+	bw += 1000;
+	cx24113_set_bandwidth(state, bw);
+
+	cx24113_set_frequency(state, c->frequency);
+	msleep(5);
+	return cx24113_get_status(fe, &bw);
+}
+
+static s8 cx24113_agc_table[2][10] = {
+	{-54, -41, -35, -30, -25, -21, -16, -10,  -6,  -2},
+	{-39, -35, -30, -25, -19, -15, -11,  -5,   1,   9},
+};
+
+void cx24113_agc_callback(struct dvb_frontend *fe)
+{
+	struct cx24113_state *state = fe->tuner_priv;
+	s16 s, i;
+	if (!fe->ops.read_signal_strength)
+		return;
+
+	do {
+		/* this only works with the current CX24123 implementation */
+		fe->ops.read_signal_strength(fe, (u16 *) &s);
+		s >>= 8;
+		dprintk("signal strength: %d\n", s);
+		for (i = 0; i < sizeof(cx24113_agc_table[0]); i++)
+			if (cx24113_agc_table[state->gain_level][i] > s)
+				break;
+		s = -25 - i*5;
+	} while (cx24113_set_gain_settings(state, s));
+}
+EXPORT_SYMBOL(cx24113_agc_callback);
+
+static int cx24113_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct cx24113_state *state = fe->tuner_priv;
+	*frequency = state->frequency;
+	return 0;
+}
+
+static int cx24113_release(struct dvb_frontend *fe)
+{
+	struct cx24113_state *state = fe->tuner_priv;
+	dprintk("\n");
+	fe->tuner_priv = NULL;
+	kfree(state);
+	return 0;
+}
+
+static const struct dvb_tuner_ops cx24113_tuner_ops = {
+	.info = {
+		.name           = "Conexant CX24113",
+		.frequency_min  = 950000,
+		.frequency_max  = 2150000,
+		.frequency_step = 125,
+	},
+
+	.release       = cx24113_release,
+
+	.init          = cx24113_init,
+
+	.set_params    = cx24113_set_params,
+	.get_frequency = cx24113_get_frequency,
+	.get_status    = cx24113_get_status,
+};
+
+struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
+		const struct cx24113_config *config, struct i2c_adapter *i2c)
+{
+	/* allocate memory for the internal state */
+	struct cx24113_state *state =
+		kzalloc(sizeof(struct cx24113_state), GFP_KERNEL);
+	int rc;
+	if (state == NULL) {
+		cx_err("Unable to kzalloc\n");
+		goto error;
+	}
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+
+	cx_info("trying to detect myself\n");
+
+	/* making a dummy read, because of some expected troubles
+	 * after power on */
+	cx24113_readreg(state, 0x00);
+
+	rc = cx24113_readreg(state, 0x00);
+	if (rc < 0) {
+		cx_info("CX24113 not found.\n");
+		goto error;
+	}
+	state->rev = rc;
+
+	switch (rc) {
+	case 0x43:
+		cx_info("detected CX24113 variant\n");
+		break;
+	case REV_CX24113:
+		cx_info("successfully detected\n");
+		break;
+	default:
+		cx_err("unsupported device id: %x\n", state->rev);
+		goto error;
+	}
+	state->ver = cx24113_readreg(state, 0x01);
+	cx_info("version: %x\n", state->ver);
+
+	/* create dvb_frontend */
+	memcpy(&fe->ops.tuner_ops, &cx24113_tuner_ops,
+			sizeof(struct dvb_tuner_ops));
+	fe->tuner_priv = state;
+	return fe;
+
+error:
+	kfree(state);
+
+	return NULL;
+}
+EXPORT_SYMBOL(cx24113_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>");
+MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24113/CX24128hardware");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/media/dvb-frontends/cx24113.h b/drivers/media/dvb-frontends/cx24113.h
new file mode 100644
index 0000000..01eb7b9
--- /dev/null
+++ b/drivers/media/dvb-frontends/cx24113.h
@@ -0,0 +1,53 @@
+/*
+ *  Driver for Conexant CX24113/CX24128 Tuner (Satellite)
+ *
+ *  Copyright (C) 2007-8 Patrick Boettcher <pb@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef CX24113_H
+#define CX24113_H
+
+struct dvb_frontend;
+
+struct cx24113_config {
+	u8 i2c_addr; /* 0x14 or 0x54 */
+
+	u32 xtal_khz;
+};
+
+#if defined(CONFIG_DVB_TUNER_CX24113) || \
+	(defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE))
+extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *,
+	const struct cx24113_config *config, struct i2c_adapter *i2c);
+
+extern void cx24113_agc_callback(struct dvb_frontend *fe);
+#else
+static inline struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
+	const struct cx24113_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline void cx24113_agc_callback(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+#endif
+
+#endif /* CX24113_H */
diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c
new file mode 100644
index 0000000..b488791
--- /dev/null
+++ b/drivers/media/dvb-frontends/cx24116.c
@@ -0,0 +1,1508 @@
+/*
+    Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver
+
+    Copyright (C) 2006-2008 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2006-2007 Georg Acher
+    Copyright (C) 2007-2008 Darron Broad
+	March 2007
+	    Fixed some bugs.
+	    Added diseqc support.
+	    Added corrected signal strength support.
+	August 2007
+	    Sync with legacy version.
+	    Some clean ups.
+    Copyright (C) 2008 Igor Liplianin
+	September, 9th 2008
+	    Fixed locking on high symbol rates (>30000).
+	    Implement MPEG initialization parameter.
+	January, 17th 2009
+	    Fill set_voltage with actually control voltage code.
+	    Correct set tone to not affect voltage.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+
+#include "dvb_frontend.h"
+#include "cx24116.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_INFO "cx24116: " args); \
+	} while (0)
+
+#define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw"
+#define CX24116_SEARCH_RANGE_KHZ 5000
+
+/* known registers */
+#define CX24116_REG_COMMAND (0x00)      /* command args 0x00..0x1e */
+#define CX24116_REG_EXECUTE (0x1f)      /* execute command */
+#define CX24116_REG_MAILBOX (0x96)      /* FW or multipurpose mailbox? */
+#define CX24116_REG_RESET   (0x20)      /* reset status > 0     */
+#define CX24116_REG_SIGNAL  (0x9e)      /* signal low           */
+#define CX24116_REG_SSTATUS (0x9d)      /* signal high / status */
+#define CX24116_REG_QUALITY8 (0xa3)
+#define CX24116_REG_QSTATUS (0xbc)
+#define CX24116_REG_QUALITY0 (0xd5)
+#define CX24116_REG_BER0    (0xc9)
+#define CX24116_REG_BER8    (0xc8)
+#define CX24116_REG_BER16   (0xc7)
+#define CX24116_REG_BER24   (0xc6)
+#define CX24116_REG_UCB0    (0xcb)
+#define CX24116_REG_UCB8    (0xca)
+#define CX24116_REG_CLKDIV  (0xf3)
+#define CX24116_REG_RATEDIV (0xf9)
+
+/* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */
+#define CX24116_REG_FECSTATUS (0x9c)
+
+/* FECSTATUS bits */
+/* mask to determine configured fec (not tuned) or actual fec (tuned) */
+#define CX24116_FEC_FECMASK   (0x1f)
+
+/* Select DVB-S demodulator, else DVB-S2 */
+#define CX24116_FEC_DVBS      (0x20)
+#define CX24116_FEC_UNKNOWN   (0x40)    /* Unknown/unused */
+
+/* Pilot mode requested when tuning else always reset when tuned */
+#define CX24116_FEC_PILOT     (0x80)
+
+/* arg buffer size */
+#define CX24116_ARGLEN (0x1e)
+
+/* rolloff */
+#define CX24116_ROLLOFF_020 (0x00)
+#define CX24116_ROLLOFF_025 (0x01)
+#define CX24116_ROLLOFF_035 (0x02)
+
+/* pilot bit */
+#define CX24116_PILOT_OFF (0x00)
+#define CX24116_PILOT_ON (0x40)
+
+/* signal status */
+#define CX24116_HAS_SIGNAL   (0x01)
+#define CX24116_HAS_CARRIER  (0x02)
+#define CX24116_HAS_VITERBI  (0x04)
+#define CX24116_HAS_SYNCLOCK (0x08)
+#define CX24116_HAS_UNKNOWN1 (0x10)
+#define CX24116_HAS_UNKNOWN2 (0x20)
+#define CX24116_STATUS_MASK  (0x0f)
+#define CX24116_SIGNAL_MASK  (0xc0)
+
+#define CX24116_DISEQC_TONEOFF   (0)    /* toneburst never sent */
+#define CX24116_DISEQC_TONECACHE (1)    /* toneburst cached     */
+#define CX24116_DISEQC_MESGCACHE (2)    /* message cached       */
+
+/* arg offset for DiSEqC */
+#define CX24116_DISEQC_BURST  (1)
+#define CX24116_DISEQC_ARG2_2 (2)   /* unknown value=2 */
+#define CX24116_DISEQC_ARG3_0 (3)   /* unknown value=0 */
+#define CX24116_DISEQC_ARG4_0 (4)   /* unknown value=0 */
+#define CX24116_DISEQC_MSGLEN (5)
+#define CX24116_DISEQC_MSGOFS (6)
+
+/* DiSEqC burst */
+#define CX24116_DISEQC_MINI_A (0)
+#define CX24116_DISEQC_MINI_B (1)
+
+/* DiSEqC tone burst */
+static int toneburst = 1;
+module_param(toneburst, int, 0644);
+MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, "\
+	"2=MESSAGE CACHE (default:1)");
+
+/* SNR measurements */
+static int esno_snr;
+module_param(esno_snr, int, 0644);
+MODULE_PARM_DESC(esno_snr, "SNR return units, 0=PERCENTAGE 0-100, "\
+	"1=ESNO(db * 10) (default:0)");
+
+enum cmds {
+	CMD_SET_VCO     = 0x10,
+	CMD_TUNEREQUEST = 0x11,
+	CMD_MPEGCONFIG  = 0x13,
+	CMD_TUNERINIT   = 0x14,
+	CMD_BANDWIDTH   = 0x15,
+	CMD_GETAGC      = 0x19,
+	CMD_LNBCONFIG   = 0x20,
+	CMD_LNBSEND     = 0x21, /* Formerly CMD_SEND_DISEQC */
+	CMD_LNBDCLEVEL  = 0x22,
+	CMD_SET_TONE    = 0x23,
+	CMD_UPDFWVERS   = 0x35,
+	CMD_TUNERSLEEP  = 0x36,
+	CMD_AGCCONTROL  = 0x3b, /* Unknown */
+};
+
+/* The Demod/Tuner can't easily provide these, we cache them */
+struct cx24116_tuning {
+	u32 frequency;
+	u32 symbol_rate;
+	fe_spectral_inversion_t inversion;
+	fe_code_rate_t fec;
+
+	fe_delivery_system_t delsys;
+	fe_modulation_t modulation;
+	fe_pilot_t pilot;
+	fe_rolloff_t rolloff;
+
+	/* Demod values */
+	u8 fec_val;
+	u8 fec_mask;
+	u8 inversion_val;
+	u8 pilot_val;
+	u8 rolloff_val;
+};
+
+/* Basic commands that are sent to the firmware */
+struct cx24116_cmd {
+	u8 len;
+	u8 args[CX24116_ARGLEN];
+};
+
+struct cx24116_state {
+	struct i2c_adapter *i2c;
+	const struct cx24116_config *config;
+
+	struct dvb_frontend frontend;
+
+	struct cx24116_tuning dcur;
+	struct cx24116_tuning dnxt;
+
+	u8 skip_fw_load;
+	u8 burst;
+	struct cx24116_cmd dsec_cmd;
+};
+
+static int cx24116_writereg(struct cx24116_state *state, int reg, int data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address,
+		.flags = 0, .buf = buf, .len = 2 };
+	int err;
+
+	if (debug > 1)
+		printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n",
+			__func__, reg, data);
+
+	err = i2c_transfer(state->i2c, &msg, 1);
+	if (err != 1) {
+		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
+			 " value == 0x%02x)\n", __func__, err, reg, data);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+/* Bulk byte writes to a single I2C address, for 32k firmware load */
+static int cx24116_writeregN(struct cx24116_state *state, int reg,
+			     const u8 *data, u16 len)
+{
+	int ret = -EREMOTEIO;
+	struct i2c_msg msg;
+	u8 *buf;
+
+	buf = kmalloc(len + 1, GFP_KERNEL);
+	if (buf == NULL) {
+		printk("Unable to kmalloc\n");
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	*(buf) = reg;
+	memcpy(buf + 1, data, len);
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.buf = buf;
+	msg.len = len + 1;
+
+	if (debug > 1)
+		printk(KERN_INFO "cx24116: %s:  write regN 0x%02x, len = %d\n",
+			__func__, reg, len);
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+	if (ret != 1) {
+		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n",
+			 __func__, ret, reg);
+		ret = -EREMOTEIO;
+	}
+
+error:
+	kfree(buf);
+
+	return ret;
+}
+
+static int cx24116_readreg(struct cx24116_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{ .addr = state->config->demod_address, .flags = 0,
+			.buf = b0, .len = 1 },
+		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
+			.buf = b1, .len = 1 }
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
+			__func__, reg, ret);
+		return ret;
+	}
+
+	if (debug > 1)
+		printk(KERN_INFO "cx24116: read reg 0x%02x, value 0x%02x\n",
+			reg, b1[0]);
+
+	return b1[0];
+}
+
+static int cx24116_set_inversion(struct cx24116_state *state,
+	fe_spectral_inversion_t inversion)
+{
+	dprintk("%s(%d)\n", __func__, inversion);
+
+	switch (inversion) {
+	case INVERSION_OFF:
+		state->dnxt.inversion_val = 0x00;
+		break;
+	case INVERSION_ON:
+		state->dnxt.inversion_val = 0x04;
+		break;
+	case INVERSION_AUTO:
+		state->dnxt.inversion_val = 0x0C;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	state->dnxt.inversion = inversion;
+
+	return 0;
+}
+
+/*
+ * modfec (modulation and FEC)
+ * ===========================
+ *
+ * MOD          FEC             mask/val    standard
+ * ----         --------        ----------- --------
+ * QPSK         FEC_1_2         0x02 0x02+X DVB-S
+ * QPSK         FEC_2_3         0x04 0x02+X DVB-S
+ * QPSK         FEC_3_4         0x08 0x02+X DVB-S
+ * QPSK         FEC_4_5         0x10 0x02+X DVB-S (?)
+ * QPSK         FEC_5_6         0x20 0x02+X DVB-S
+ * QPSK         FEC_6_7         0x40 0x02+X DVB-S
+ * QPSK         FEC_7_8         0x80 0x02+X DVB-S
+ * QPSK         FEC_8_9         0x01 0x02+X DVB-S (?) (NOT SUPPORTED?)
+ * QPSK         AUTO            0xff 0x02+X DVB-S
+ *
+ * For DVB-S high byte probably represents FEC
+ * and low byte selects the modulator. The high
+ * byte is search range mask. Bit 5 may turn
+ * on DVB-S and remaining bits represent some
+ * kind of calibration (how/what i do not know).
+ *
+ * Eg.(2/3) szap "Zone Horror"
+ *
+ * mask/val = 0x04, 0x20
+ * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 0 | FE_HAS_LOCK
+ *
+ * mask/val = 0x04, 0x30
+ * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 0 | FE_HAS_LOCK
+ *
+ * After tuning FECSTATUS contains actual FEC
+ * in use numbered 1 through to 8 for 1/2 .. 2/3 etc
+ *
+ * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only)
+ *
+ * NBC-QPSK     FEC_1_2         0x00, 0x04      DVB-S2
+ * NBC-QPSK     FEC_3_5         0x00, 0x05      DVB-S2
+ * NBC-QPSK     FEC_2_3         0x00, 0x06      DVB-S2
+ * NBC-QPSK     FEC_3_4         0x00, 0x07      DVB-S2
+ * NBC-QPSK     FEC_4_5         0x00, 0x08      DVB-S2
+ * NBC-QPSK     FEC_5_6         0x00, 0x09      DVB-S2
+ * NBC-QPSK     FEC_8_9         0x00, 0x0a      DVB-S2
+ * NBC-QPSK     FEC_9_10        0x00, 0x0b      DVB-S2
+ *
+ * NBC-8PSK     FEC_3_5         0x00, 0x0c      DVB-S2
+ * NBC-8PSK     FEC_2_3         0x00, 0x0d      DVB-S2
+ * NBC-8PSK     FEC_3_4         0x00, 0x0e      DVB-S2
+ * NBC-8PSK     FEC_5_6         0x00, 0x0f      DVB-S2
+ * NBC-8PSK     FEC_8_9         0x00, 0x10      DVB-S2
+ * NBC-8PSK     FEC_9_10        0x00, 0x11      DVB-S2
+ *
+ * For DVB-S2 low bytes selects both modulator
+ * and FEC. High byte is meaningless here. To
+ * set pilot, bit 6 (0x40) is set. When inspecting
+ * FECSTATUS bit 7 (0x80) represents the pilot
+ * selection whilst not tuned. When tuned, actual FEC
+ * in use is found in FECSTATUS as per above. Pilot
+ * value is reset.
+ */
+
+/* A table of modulation, fec and configuration bytes for the demod.
+ * Not all S2 mmodulation schemes are support and not all rates with
+ * a scheme are support. Especially, no auto detect when in S2 mode.
+ */
+static struct cx24116_modfec {
+	fe_delivery_system_t delivery_system;
+	fe_modulation_t modulation;
+	fe_code_rate_t fec;
+	u8 mask;	/* In DVBS mode this is used to autodetect */
+	u8 val;		/* Passed to the firmware to indicate mode selection */
+} CX24116_MODFEC_MODES[] = {
+ /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */
+
+ /*mod   fec       mask  val */
+ { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 },
+ { SYS_DVBS, QPSK, FEC_1_2,  0x02, 0x2e }, /* 00000010 00101110 */
+ { SYS_DVBS, QPSK, FEC_2_3,  0x04, 0x2f }, /* 00000100 00101111 */
+ { SYS_DVBS, QPSK, FEC_3_4,  0x08, 0x30 }, /* 00001000 00110000 */
+ { SYS_DVBS, QPSK, FEC_4_5,  0xfe, 0x30 }, /* 000?0000 ?        */
+ { SYS_DVBS, QPSK, FEC_5_6,  0x20, 0x31 }, /* 00100000 00110001 */
+ { SYS_DVBS, QPSK, FEC_6_7,  0xfe, 0x30 }, /* 0?000000 ?        */
+ { SYS_DVBS, QPSK, FEC_7_8,  0x80, 0x32 }, /* 10000000 00110010 */
+ { SYS_DVBS, QPSK, FEC_8_9,  0xfe, 0x30 }, /* 0000000? ?        */
+ { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 },
+ /* NBC-QPSK */
+ { SYS_DVBS2, QPSK, FEC_1_2,  0x00, 0x04 },
+ { SYS_DVBS2, QPSK, FEC_3_5,  0x00, 0x05 },
+ { SYS_DVBS2, QPSK, FEC_2_3,  0x00, 0x06 },
+ { SYS_DVBS2, QPSK, FEC_3_4,  0x00, 0x07 },
+ { SYS_DVBS2, QPSK, FEC_4_5,  0x00, 0x08 },
+ { SYS_DVBS2, QPSK, FEC_5_6,  0x00, 0x09 },
+ { SYS_DVBS2, QPSK, FEC_8_9,  0x00, 0x0a },
+ { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b },
+ /* 8PSK */
+ { SYS_DVBS2, PSK_8, FEC_3_5,  0x00, 0x0c },
+ { SYS_DVBS2, PSK_8, FEC_2_3,  0x00, 0x0d },
+ { SYS_DVBS2, PSK_8, FEC_3_4,  0x00, 0x0e },
+ { SYS_DVBS2, PSK_8, FEC_5_6,  0x00, 0x0f },
+ { SYS_DVBS2, PSK_8, FEC_8_9,  0x00, 0x10 },
+ { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 },
+ /*
+  * `val' can be found in the FECSTATUS register when tuning.
+  * FECSTATUS will give the actual FEC in use if tuning was successful.
+  */
+};
+
+static int cx24116_lookup_fecmod(struct cx24116_state *state,
+	fe_delivery_system_t d, fe_modulation_t m, fe_code_rate_t f)
+{
+	int i, ret = -EOPNOTSUPP;
+
+	dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
+
+	for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) {
+		if ((d == CX24116_MODFEC_MODES[i].delivery_system) &&
+			(m == CX24116_MODFEC_MODES[i].modulation) &&
+			(f == CX24116_MODFEC_MODES[i].fec)) {
+				ret = i;
+				break;
+			}
+	}
+
+	return ret;
+}
+
+static int cx24116_set_fec(struct cx24116_state *state,
+	fe_delivery_system_t delsys, fe_modulation_t mod, fe_code_rate_t fec)
+{
+	int ret = 0;
+
+	dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
+
+	ret = cx24116_lookup_fecmod(state, delsys, mod, fec);
+
+	if (ret < 0)
+		return ret;
+
+	state->dnxt.fec = fec;
+	state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val;
+	state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask;
+	dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__,
+		state->dnxt.fec_mask, state->dnxt.fec_val);
+
+	return 0;
+}
+
+static int cx24116_set_symbolrate(struct cx24116_state *state, u32 rate)
+{
+	dprintk("%s(%d)\n", __func__, rate);
+
+	/*  check if symbol rate is within limits */
+	if ((rate > state->frontend.ops.info.symbol_rate_max) ||
+	    (rate < state->frontend.ops.info.symbol_rate_min)) {
+		dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate);
+		return -EOPNOTSUPP;
+	}
+
+	state->dnxt.symbol_rate = rate;
+	dprintk("%s() symbol_rate = %d\n", __func__, rate);
+
+	return 0;
+}
+
+static int cx24116_load_firmware(struct dvb_frontend *fe,
+	const struct firmware *fw);
+
+static int cx24116_firmware_ondemand(struct dvb_frontend *fe)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	const struct firmware *fw;
+	int ret = 0;
+
+	dprintk("%s()\n", __func__);
+
+	if (cx24116_readreg(state, 0x20) > 0) {
+
+		if (state->skip_fw_load)
+			return 0;
+
+		/* Load firmware */
+		/* request the firmware, this will block until loaded */
+		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n",
+			__func__, CX24116_DEFAULT_FIRMWARE);
+		ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE,
+			state->i2c->dev.parent);
+		printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n",
+			__func__);
+		if (ret) {
+			printk(KERN_ERR "%s: No firmware uploaded "
+				"(timeout or file not found?)\n", __func__);
+			return ret;
+		}
+
+		/* Make sure we don't recurse back through here
+		 * during loading */
+		state->skip_fw_load = 1;
+
+		ret = cx24116_load_firmware(fe, fw);
+		if (ret)
+			printk(KERN_ERR "%s: Writing firmware to device failed\n",
+				__func__);
+
+		release_firmware(fw);
+
+		printk(KERN_INFO "%s: Firmware upload %s\n", __func__,
+			ret == 0 ? "complete" : "failed");
+
+		/* Ensure firmware is always loaded if required */
+		state->skip_fw_load = 0;
+	}
+
+	return ret;
+}
+
+/* Take a basic firmware command structure, format it
+ * and forward it for processing
+ */
+static int cx24116_cmd_execute(struct dvb_frontend *fe, struct cx24116_cmd *cmd)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	int i, ret;
+
+	dprintk("%s()\n", __func__);
+
+	/* Load the firmware if required */
+	ret = cx24116_firmware_ondemand(fe);
+	if (ret != 0) {
+		printk(KERN_ERR "%s(): Unable initialise the firmware\n",
+			__func__);
+		return ret;
+	}
+
+	/* Write the command */
+	for (i = 0; i < cmd->len ; i++) {
+		dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]);
+		cx24116_writereg(state, i, cmd->args[i]);
+	}
+
+	/* Start execution and wait for cmd to terminate */
+	cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01);
+	while (cx24116_readreg(state, CX24116_REG_EXECUTE)) {
+		msleep(10);
+		if (i++ > 64) {
+			/* Avoid looping forever if the firmware does
+				not respond */
+			printk(KERN_WARNING "%s() Firmware not responding\n",
+				__func__);
+			return -EREMOTEIO;
+		}
+	}
+	return 0;
+}
+
+static int cx24116_load_firmware(struct dvb_frontend *fe,
+	const struct firmware *fw)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	struct cx24116_cmd cmd;
+	int i, ret, len, max, remaining;
+	unsigned char vers[4];
+
+	dprintk("%s\n", __func__);
+	dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
+			fw->size,
+			fw->data[0],
+			fw->data[1],
+			fw->data[fw->size-2],
+			fw->data[fw->size-1]);
+
+	/* Toggle 88x SRST pin to reset demod */
+	if (state->config->reset_device)
+		state->config->reset_device(fe);
+
+	/* Begin the firmware load process */
+	/* Prepare the demod, load the firmware, cleanup after load */
+
+	/* Init PLL */
+	cx24116_writereg(state, 0xE5, 0x00);
+	cx24116_writereg(state, 0xF1, 0x08);
+	cx24116_writereg(state, 0xF2, 0x13);
+
+	/* Start PLL */
+	cx24116_writereg(state, 0xe0, 0x03);
+	cx24116_writereg(state, 0xe0, 0x00);
+
+	/* Unknown */
+	cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
+	cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
+
+	/* Unknown */
+	cx24116_writereg(state, 0xF0, 0x03);
+	cx24116_writereg(state, 0xF4, 0x81);
+	cx24116_writereg(state, 0xF5, 0x00);
+	cx24116_writereg(state, 0xF6, 0x00);
+
+	/* Split firmware to the max I2C write len and write.
+	 * Writes whole firmware as one write when i2c_wr_max is set to 0. */
+	if (state->config->i2c_wr_max)
+		max = state->config->i2c_wr_max;
+	else
+		max = INT_MAX; /* enough for 32k firmware */
+
+	for (remaining = fw->size; remaining > 0; remaining -= max - 1) {
+		len = remaining;
+		if (len > max - 1)
+			len = max - 1;
+
+		cx24116_writeregN(state, 0xF7, &fw->data[fw->size - remaining],
+			len);
+	}
+
+	cx24116_writereg(state, 0xF4, 0x10);
+	cx24116_writereg(state, 0xF0, 0x00);
+	cx24116_writereg(state, 0xF8, 0x06);
+
+	/* Firmware CMD 10: VCO config */
+	cmd.args[0x00] = CMD_SET_VCO;
+	cmd.args[0x01] = 0x05;
+	cmd.args[0x02] = 0xdc;
+	cmd.args[0x03] = 0xda;
+	cmd.args[0x04] = 0xae;
+	cmd.args[0x05] = 0xaa;
+	cmd.args[0x06] = 0x04;
+	cmd.args[0x07] = 0x9d;
+	cmd.args[0x08] = 0xfc;
+	cmd.args[0x09] = 0x06;
+	cmd.len = 0x0a;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if (ret != 0)
+		return ret;
+
+	cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00);
+
+	/* Firmware CMD 14: Tuner config */
+	cmd.args[0x00] = CMD_TUNERINIT;
+	cmd.args[0x01] = 0x00;
+	cmd.args[0x02] = 0x00;
+	cmd.len = 0x03;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if (ret != 0)
+		return ret;
+
+	cx24116_writereg(state, 0xe5, 0x00);
+
+	/* Firmware CMD 13: MPEG config */
+	cmd.args[0x00] = CMD_MPEGCONFIG;
+	cmd.args[0x01] = 0x01;
+	cmd.args[0x02] = 0x75;
+	cmd.args[0x03] = 0x00;
+	if (state->config->mpg_clk_pos_pol)
+		cmd.args[0x04] = state->config->mpg_clk_pos_pol;
+	else
+		cmd.args[0x04] = 0x02;
+	cmd.args[0x05] = 0x00;
+	cmd.len = 0x06;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if (ret != 0)
+		return ret;
+
+	/* Firmware CMD 35: Get firmware version */
+	cmd.args[0x00] = CMD_UPDFWVERS;
+	cmd.len = 0x02;
+	for (i = 0; i < 4; i++) {
+		cmd.args[0x01] = i;
+		ret = cx24116_cmd_execute(fe, &cmd);
+		if (ret != 0)
+			return ret;
+		vers[i] = cx24116_readreg(state, CX24116_REG_MAILBOX);
+	}
+	printk(KERN_INFO "%s: FW version %i.%i.%i.%i\n", __func__,
+		vers[0], vers[1], vers[2], vers[3]);
+
+	return 0;
+}
+
+static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+
+	int lock = cx24116_readreg(state, CX24116_REG_SSTATUS) &
+		CX24116_STATUS_MASK;
+
+	dprintk("%s: status = 0x%02x\n", __func__, lock);
+
+	*status = 0;
+
+	if (lock & CX24116_HAS_SIGNAL)
+		*status |= FE_HAS_SIGNAL;
+	if (lock & CX24116_HAS_CARRIER)
+		*status |= FE_HAS_CARRIER;
+	if (lock & CX24116_HAS_VITERBI)
+		*status |= FE_HAS_VITERBI;
+	if (lock & CX24116_HAS_SYNCLOCK)
+		*status |= FE_HAS_SYNC | FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int cx24116_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __func__);
+
+	*ber =  (cx24116_readreg(state, CX24116_REG_BER24) << 24) |
+		(cx24116_readreg(state, CX24116_REG_BER16) << 16) |
+		(cx24116_readreg(state, CX24116_REG_BER8)  << 8)  |
+		 cx24116_readreg(state, CX24116_REG_BER0);
+
+	return 0;
+}
+
+/* TODO Determine function and scale appropriately */
+static int cx24116_read_signal_strength(struct dvb_frontend *fe,
+	u16 *signal_strength)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	struct cx24116_cmd cmd;
+	int ret;
+	u16 sig_reading;
+
+	dprintk("%s()\n", __func__);
+
+	/* Firmware CMD 19: Get AGC */
+	cmd.args[0x00] = CMD_GETAGC;
+	cmd.len = 0x01;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if (ret != 0)
+		return ret;
+
+	sig_reading =
+		(cx24116_readreg(state,
+			CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK) |
+		(cx24116_readreg(state, CX24116_REG_SIGNAL) << 6);
+	*signal_strength = 0 - sig_reading;
+
+	dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n",
+		__func__, sig_reading, *signal_strength);
+
+	return 0;
+}
+
+/* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */
+static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	u8 snr_reading;
+	static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
+		0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667,
+		0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667,
+		0x10000, 0x1199A, 0x13333, 0x14ccD, 0x16667,
+		0x18000 };
+
+	dprintk("%s()\n", __func__);
+
+	snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0);
+
+	if (snr_reading >= 0xa0 /* 100% */)
+		*snr = 0xffff;
+	else
+		*snr = snr_tab[(snr_reading & 0xf0) >> 4] +
+			(snr_tab[(snr_reading & 0x0f)] >> 4);
+
+	dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
+		snr_reading, *snr);
+
+	return 0;
+}
+
+/* The reelbox patches show the value in the registers represents
+ * ESNO, from 0->30db (values 0->300). We provide this value by
+ * default.
+ */
+static int cx24116_read_snr_esno(struct dvb_frontend *fe, u16 *snr)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __func__);
+
+	*snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 |
+		cx24116_readreg(state, CX24116_REG_QUALITY0);
+
+	dprintk("%s: raw 0x%04x\n", __func__, *snr);
+
+	return 0;
+}
+
+static int cx24116_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	if (esno_snr == 1)
+		return cx24116_read_snr_esno(fe, snr);
+	else
+		return cx24116_read_snr_pct(fe, snr);
+}
+
+static int cx24116_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __func__);
+
+	*ucblocks = (cx24116_readreg(state, CX24116_REG_UCB8) << 8) |
+		cx24116_readreg(state, CX24116_REG_UCB0);
+
+	return 0;
+}
+
+/* Overwrite the current tuning params, we are about to tune */
+static void cx24116_clone_params(struct dvb_frontend *fe)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
+}
+
+/* Wait for LNB */
+static int cx24116_wait_for_lnb(struct dvb_frontend *fe)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	int i;
+
+	dprintk("%s() qstatus = 0x%02x\n", __func__,
+		cx24116_readreg(state, CX24116_REG_QSTATUS));
+
+	/* Wait for up to 300 ms */
+	for (i = 0; i < 30 ; i++) {
+		if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20)
+			return 0;
+		msleep(10);
+	}
+
+	dprintk("%s(): LNB not ready\n", __func__);
+
+	return -ETIMEDOUT; /* -EBUSY ? */
+}
+
+static int cx24116_set_voltage(struct dvb_frontend *fe,
+	fe_sec_voltage_t voltage)
+{
+	struct cx24116_cmd cmd;
+	int ret;
+
+	dprintk("%s: %s\n", __func__,
+		voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+		voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
+
+	/* Wait for LNB ready */
+	ret = cx24116_wait_for_lnb(fe);
+	if (ret != 0)
+		return ret;
+
+	/* Wait for voltage/min repeat delay */
+	msleep(100);
+
+	cmd.args[0x00] = CMD_LNBDCLEVEL;
+	cmd.args[0x01] = (voltage == SEC_VOLTAGE_18 ? 0x01 : 0x00);
+	cmd.len = 0x02;
+
+	/* Min delay time before DiSEqC send */
+	msleep(15);
+
+	return cx24116_cmd_execute(fe, &cmd);
+}
+
+static int cx24116_set_tone(struct dvb_frontend *fe,
+	fe_sec_tone_mode_t tone)
+{
+	struct cx24116_cmd cmd;
+	int ret;
+
+	dprintk("%s(%d)\n", __func__, tone);
+	if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
+		printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
+		return -EINVAL;
+	}
+
+	/* Wait for LNB ready */
+	ret = cx24116_wait_for_lnb(fe);
+	if (ret != 0)
+		return ret;
+
+	/* Min delay time after DiSEqC send */
+	msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
+
+	/* Now we set the tone */
+	cmd.args[0x00] = CMD_SET_TONE;
+	cmd.args[0x01] = 0x00;
+	cmd.args[0x02] = 0x00;
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		dprintk("%s: setting tone on\n", __func__);
+		cmd.args[0x03] = 0x01;
+		break;
+	case SEC_TONE_OFF:
+		dprintk("%s: setting tone off\n", __func__);
+		cmd.args[0x03] = 0x00;
+		break;
+	}
+	cmd.len = 0x04;
+
+	/* Min delay time before DiSEqC send */
+	msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
+
+	return cx24116_cmd_execute(fe, &cmd);
+}
+
+/* Initialise DiSEqC */
+static int cx24116_diseqc_init(struct dvb_frontend *fe)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	struct cx24116_cmd cmd;
+	int ret;
+
+	/* Firmware CMD 20: LNB/DiSEqC config */
+	cmd.args[0x00] = CMD_LNBCONFIG;
+	cmd.args[0x01] = 0x00;
+	cmd.args[0x02] = 0x10;
+	cmd.args[0x03] = 0x00;
+	cmd.args[0x04] = 0x8f;
+	cmd.args[0x05] = 0x28;
+	cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01;
+	cmd.args[0x07] = 0x01;
+	cmd.len = 0x08;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if (ret != 0)
+		return ret;
+
+	/* Prepare a DiSEqC command */
+	state->dsec_cmd.args[0x00] = CMD_LNBSEND;
+
+	/* DiSEqC burst */
+	state->dsec_cmd.args[CX24116_DISEQC_BURST]  = CX24116_DISEQC_MINI_A;
+
+	/* Unknown */
+	state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02;
+	state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00;
+	/* Continuation flag? */
+	state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00;
+
+	/* DiSEqC message length */
+	state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00;
+
+	/* Command length */
+	state->dsec_cmd.len = CX24116_DISEQC_MSGOFS;
+
+	return 0;
+}
+
+/* Send DiSEqC message with derived burst (hack) || previous burst */
+static int cx24116_send_diseqc_msg(struct dvb_frontend *fe,
+	struct dvb_diseqc_master_cmd *d)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	int i, ret;
+
+	/* Dump DiSEqC message */
+	if (debug) {
+		printk(KERN_INFO "cx24116: %s(", __func__);
+		for (i = 0 ; i < d->msg_len ;) {
+			printk(KERN_INFO "0x%02x", d->msg[i]);
+			if (++i < d->msg_len)
+				printk(KERN_INFO ", ");
+		}
+		printk(") toneburst=%d\n", toneburst);
+	}
+
+	/* Validate length */
+	if (d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS))
+		return -EINVAL;
+
+	/* DiSEqC message */
+	for (i = 0; i < d->msg_len; i++)
+		state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i];
+
+	/* DiSEqC message length */
+	state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len;
+
+	/* Command length */
+	state->dsec_cmd.len = CX24116_DISEQC_MSGOFS +
+		state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
+
+	/* DiSEqC toneburst */
+	if (toneburst == CX24116_DISEQC_MESGCACHE)
+		/* Message is cached */
+		return 0;
+
+	else if (toneburst == CX24116_DISEQC_TONEOFF)
+		/* Message is sent without burst */
+		state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0;
+
+	else if (toneburst == CX24116_DISEQC_TONECACHE) {
+		/*
+		 * Message is sent with derived else cached burst
+		 *
+		 * WRITE PORT GROUP COMMAND 38
+		 *
+		 * 0/A/A: E0 10 38 F0..F3
+		 * 1/B/B: E0 10 38 F4..F7
+		 * 2/C/A: E0 10 38 F8..FB
+		 * 3/D/B: E0 10 38 FC..FF
+		 *
+		 * databyte[3]= 8421:8421
+		 *              ABCD:WXYZ
+		 *              CLR :SET
+		 *
+		 *              WX= PORT SELECT 0..3    (X=TONEBURST)
+		 *              Y = VOLTAGE             (0=13V, 1=18V)
+		 *              Z = BAND                (0=LOW, 1=HIGH(22K))
+		 */
+		if (d->msg_len >= 4 && d->msg[2] == 0x38)
+			state->dsec_cmd.args[CX24116_DISEQC_BURST] =
+				((d->msg[3] & 4) >> 2);
+		if (debug)
+			dprintk("%s burst=%d\n", __func__,
+				state->dsec_cmd.args[CX24116_DISEQC_BURST]);
+	}
+
+	/* Wait for LNB ready */
+	ret = cx24116_wait_for_lnb(fe);
+	if (ret != 0)
+		return ret;
+
+	/* Wait for voltage/min repeat delay */
+	msleep(100);
+
+	/* Command */
+	ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
+	if (ret != 0)
+		return ret;
+	/*
+	 * Wait for send
+	 *
+	 * Eutelsat spec:
+	 * >15ms delay          + (XXX determine if FW does this, see set_tone)
+	 *  13.5ms per byte     +
+	 * >15ms delay          +
+	 *  12.5ms burst        +
+	 * >15ms delay            (XXX determine if FW does this, see set_tone)
+	 */
+	msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) +
+		((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60));
+
+	return 0;
+}
+
+/* Send DiSEqC burst */
+static int cx24116_diseqc_send_burst(struct dvb_frontend *fe,
+	fe_sec_mini_cmd_t burst)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	int ret;
+
+	dprintk("%s(%d) toneburst=%d\n", __func__, burst, toneburst);
+
+	/* DiSEqC burst */
+	if (burst == SEC_MINI_A)
+		state->dsec_cmd.args[CX24116_DISEQC_BURST] =
+			CX24116_DISEQC_MINI_A;
+	else if (burst == SEC_MINI_B)
+		state->dsec_cmd.args[CX24116_DISEQC_BURST] =
+			CX24116_DISEQC_MINI_B;
+	else
+		return -EINVAL;
+
+	/* DiSEqC toneburst */
+	if (toneburst != CX24116_DISEQC_MESGCACHE)
+		/* Burst is cached */
+		return 0;
+
+	/* Burst is to be sent with cached message */
+
+	/* Wait for LNB ready */
+	ret = cx24116_wait_for_lnb(fe);
+	if (ret != 0)
+		return ret;
+
+	/* Wait for voltage/min repeat delay */
+	msleep(100);
+
+	/* Command */
+	ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
+	if (ret != 0)
+		return ret;
+
+	/*
+	 * Wait for send
+	 *
+	 * Eutelsat spec:
+	 * >15ms delay          + (XXX determine if FW does this, see set_tone)
+	 *  13.5ms per byte     +
+	 * >15ms delay          +
+	 *  12.5ms burst        +
+	 * >15ms delay            (XXX determine if FW does this, see set_tone)
+	 */
+	msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60);
+
+	return 0;
+}
+
+static void cx24116_release(struct dvb_frontend *fe)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	dprintk("%s\n", __func__);
+	kfree(state);
+}
+
+static struct dvb_frontend_ops cx24116_ops;
+
+struct dvb_frontend *cx24116_attach(const struct cx24116_config *config,
+	struct i2c_adapter *i2c)
+{
+	struct cx24116_state *state = NULL;
+	int ret;
+
+	dprintk("%s\n", __func__);
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct cx24116_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error1;
+
+	state->config = config;
+	state->i2c = i2c;
+
+	/* check if the demod is present */
+	ret = (cx24116_readreg(state, 0xFF) << 8) |
+		cx24116_readreg(state, 0xFE);
+	if (ret != 0x0501) {
+		printk(KERN_INFO "Invalid probe, probably not a CX24116 device\n");
+		goto error2;
+	}
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &cx24116_ops,
+		sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error2: kfree(state);
+error1: return NULL;
+}
+EXPORT_SYMBOL(cx24116_attach);
+
+/*
+ * Initialise or wake up device
+ *
+ * Power config will reset and load initial firmware if required
+ */
+static int cx24116_initfe(struct dvb_frontend *fe)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	struct cx24116_cmd cmd;
+	int ret;
+
+	dprintk("%s()\n", __func__);
+
+	/* Power on */
+	cx24116_writereg(state, 0xe0, 0);
+	cx24116_writereg(state, 0xe1, 0);
+	cx24116_writereg(state, 0xea, 0);
+
+	/* Firmware CMD 36: Power config */
+	cmd.args[0x00] = CMD_TUNERSLEEP;
+	cmd.args[0x01] = 0;
+	cmd.len = 0x02;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if (ret != 0)
+		return ret;
+
+	ret = cx24116_diseqc_init(fe);
+	if (ret != 0)
+		return ret;
+
+	/* HVR-4000 needs this */
+	return cx24116_set_voltage(fe, SEC_VOLTAGE_13);
+}
+
+/*
+ * Put device to sleep
+ */
+static int cx24116_sleep(struct dvb_frontend *fe)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	struct cx24116_cmd cmd;
+	int ret;
+
+	dprintk("%s()\n", __func__);
+
+	/* Firmware CMD 36: Power config */
+	cmd.args[0x00] = CMD_TUNERSLEEP;
+	cmd.args[0x01] = 1;
+	cmd.len = 0x02;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if (ret != 0)
+		return ret;
+
+	/* Power off (Shutdown clocks) */
+	cx24116_writereg(state, 0xea, 0xff);
+	cx24116_writereg(state, 0xe1, 1);
+	cx24116_writereg(state, 0xe0, 1);
+
+	return 0;
+}
+
+/* dvb-core told us to tune, the tv property cache will be complete,
+ * it's safe for is to pull values and use them for tuning purposes.
+ */
+static int cx24116_set_frontend(struct dvb_frontend *fe)
+{
+	struct cx24116_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct cx24116_cmd cmd;
+	fe_status_t tunerstat;
+	int i, status, ret, retune = 1;
+
+	dprintk("%s()\n", __func__);
+
+	switch (c->delivery_system) {
+	case SYS_DVBS:
+		dprintk("%s: DVB-S delivery system selected\n", __func__);
+
+		/* Only QPSK is supported for DVB-S */
+		if (c->modulation != QPSK) {
+			dprintk("%s: unsupported modulation selected (%d)\n",
+				__func__, c->modulation);
+			return -EOPNOTSUPP;
+		}
+
+		/* Pilot doesn't exist in DVB-S, turn bit off */
+		state->dnxt.pilot_val = CX24116_PILOT_OFF;
+
+		/* DVB-S only supports 0.35 */
+		if (c->rolloff != ROLLOFF_35) {
+			dprintk("%s: unsupported rolloff selected (%d)\n",
+				__func__, c->rolloff);
+			return -EOPNOTSUPP;
+		}
+		state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
+		break;
+
+	case SYS_DVBS2:
+		dprintk("%s: DVB-S2 delivery system selected\n", __func__);
+
+		/*
+		 * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2,
+		 * but not hardware auto detection
+		 */
+		if (c->modulation != PSK_8 && c->modulation != QPSK) {
+			dprintk("%s: unsupported modulation selected (%d)\n",
+				__func__, c->modulation);
+			return -EOPNOTSUPP;
+		}
+
+		switch (c->pilot) {
+		case PILOT_AUTO:	/* Not supported but emulated */
+			state->dnxt.pilot_val = (c->modulation == QPSK)
+				? CX24116_PILOT_OFF : CX24116_PILOT_ON;
+			retune++;
+			break;
+		case PILOT_OFF:
+			state->dnxt.pilot_val = CX24116_PILOT_OFF;
+			break;
+		case PILOT_ON:
+			state->dnxt.pilot_val = CX24116_PILOT_ON;
+			break;
+		default:
+			dprintk("%s: unsupported pilot mode selected (%d)\n",
+				__func__, c->pilot);
+			return -EOPNOTSUPP;
+		}
+
+		switch (c->rolloff) {
+		case ROLLOFF_20:
+			state->dnxt.rolloff_val = CX24116_ROLLOFF_020;
+			break;
+		case ROLLOFF_25:
+			state->dnxt.rolloff_val = CX24116_ROLLOFF_025;
+			break;
+		case ROLLOFF_35:
+			state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
+			break;
+		case ROLLOFF_AUTO:	/* Rolloff must be explicit */
+		default:
+			dprintk("%s: unsupported rolloff selected (%d)\n",
+				__func__, c->rolloff);
+			return -EOPNOTSUPP;
+		}
+		break;
+
+	default:
+		dprintk("%s: unsupported delivery system selected (%d)\n",
+			__func__, c->delivery_system);
+		return -EOPNOTSUPP;
+	}
+	state->dnxt.delsys = c->delivery_system;
+	state->dnxt.modulation = c->modulation;
+	state->dnxt.frequency = c->frequency;
+	state->dnxt.pilot = c->pilot;
+	state->dnxt.rolloff = c->rolloff;
+
+	ret = cx24116_set_inversion(state, c->inversion);
+	if (ret !=  0)
+		return ret;
+
+	/* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */
+	ret = cx24116_set_fec(state, c->delivery_system, c->modulation, c->fec_inner);
+	if (ret !=  0)
+		return ret;
+
+	ret = cx24116_set_symbolrate(state, c->symbol_rate);
+	if (ret !=  0)
+		return ret;
+
+	/* discard the 'current' tuning parameters and prepare to tune */
+	cx24116_clone_params(fe);
+
+	dprintk("%s:   delsys      = %d\n", __func__, state->dcur.delsys);
+	dprintk("%s:   modulation  = %d\n", __func__, state->dcur.modulation);
+	dprintk("%s:   frequency   = %d\n", __func__, state->dcur.frequency);
+	dprintk("%s:   pilot       = %d (val = 0x%02x)\n", __func__,
+		state->dcur.pilot, state->dcur.pilot_val);
+	dprintk("%s:   retune      = %d\n", __func__, retune);
+	dprintk("%s:   rolloff     = %d (val = 0x%02x)\n", __func__,
+		state->dcur.rolloff, state->dcur.rolloff_val);
+	dprintk("%s:   symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
+	dprintk("%s:   FEC         = %d (mask/val = 0x%02x/0x%02x)\n", __func__,
+		state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val);
+	dprintk("%s:   Inversion   = %d (val = 0x%02x)\n", __func__,
+		state->dcur.inversion, state->dcur.inversion_val);
+
+	/* This is also done in advise/acquire on HVR4000 but not on LITE */
+	if (state->config->set_ts_params)
+		state->config->set_ts_params(fe, 0);
+
+	/* Set/Reset B/W */
+	cmd.args[0x00] = CMD_BANDWIDTH;
+	cmd.args[0x01] = 0x01;
+	cmd.len = 0x02;
+	ret = cx24116_cmd_execute(fe, &cmd);
+	if (ret != 0)
+		return ret;
+
+	/* Prepare a tune request */
+	cmd.args[0x00] = CMD_TUNEREQUEST;
+
+	/* Frequency */
+	cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16;
+	cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8;
+	cmd.args[0x03] = (state->dcur.frequency & 0x0000ff);
+
+	/* Symbol Rate */
+	cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8;
+	cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff);
+
+	/* Automatic Inversion */
+	cmd.args[0x06] = state->dcur.inversion_val;
+
+	/* Modulation / FEC / Pilot */
+	cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val;
+
+	cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8;
+	cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff;
+	cmd.args[0x0a] = 0x00;
+	cmd.args[0x0b] = 0x00;
+	cmd.args[0x0c] = state->dcur.rolloff_val;
+	cmd.args[0x0d] = state->dcur.fec_mask;
+
+	if (state->dcur.symbol_rate > 30000000) {
+		cmd.args[0x0e] = 0x04;
+		cmd.args[0x0f] = 0x00;
+		cmd.args[0x10] = 0x01;
+		cmd.args[0x11] = 0x77;
+		cmd.args[0x12] = 0x36;
+		cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44);
+		cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01);
+	} else {
+		cmd.args[0x0e] = 0x06;
+		cmd.args[0x0f] = 0x00;
+		cmd.args[0x10] = 0x00;
+		cmd.args[0x11] = 0xFA;
+		cmd.args[0x12] = 0x24;
+		cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
+		cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
+	}
+
+	cmd.len = 0x13;
+
+	/* We need to support pilot and non-pilot tuning in the
+	 * driver automatically. This is a workaround for because
+	 * the demod does not support autodetect.
+	 */
+	do {
+		/* Reset status register */
+		status = cx24116_readreg(state, CX24116_REG_SSTATUS)
+			& CX24116_SIGNAL_MASK;
+		cx24116_writereg(state, CX24116_REG_SSTATUS, status);
+
+		/* Tune */
+		ret = cx24116_cmd_execute(fe, &cmd);
+		if (ret != 0)
+			break;
+
+		/*
+		 * Wait for up to 500 ms before retrying
+		 *
+		 * If we are able to tune then generally it occurs within 100ms.
+		 * If it takes longer, try a different toneburst setting.
+		 */
+		for (i = 0; i < 50 ; i++) {
+			cx24116_read_status(fe, &tunerstat);
+			status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC);
+			if (status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
+				dprintk("%s: Tuned\n", __func__);
+				goto tuned;
+			}
+			msleep(10);
+		}
+
+		dprintk("%s: Not tuned\n", __func__);
+
+		/* Toggle pilot bit when in auto-pilot */
+		if (state->dcur.pilot == PILOT_AUTO)
+			cmd.args[0x07] ^= CX24116_PILOT_ON;
+	} while (--retune);
+
+tuned:  /* Set/Reset B/W */
+	cmd.args[0x00] = CMD_BANDWIDTH;
+	cmd.args[0x01] = 0x00;
+	cmd.len = 0x02;
+	return cx24116_cmd_execute(fe, &cmd);
+}
+
+static int cx24116_tune(struct dvb_frontend *fe, bool re_tune,
+	unsigned int mode_flags, unsigned int *delay, fe_status_t *status)
+{
+	/*
+	 * It is safe to discard "params" here, as the DVB core will sync
+	 * fe->dtv_property_cache with fepriv->parameters_in, where the
+	 * DVBv3 params are stored. The only practical usage for it indicate
+	 * that re-tuning is needed, e. g. (fepriv->state & FESTATE_RETUNE) is
+	 * true.
+	 */
+
+	*delay = HZ / 5;
+	if (re_tune) {
+		int ret = cx24116_set_frontend(fe);
+		if (ret)
+			return ret;
+	}
+	return cx24116_read_status(fe, status);
+}
+
+static int cx24116_get_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_HW;
+}
+
+static struct dvb_frontend_ops cx24116_ops = {
+	.delsys = { SYS_DVBS, SYS_DVBS2 },
+	.info = {
+		.name = "Conexant CX24116/CX24118",
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		.frequency_stepsize = 1011, /* kHz for QPSK frontends */
+		.frequency_tolerance = 5000,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_2G_MODULATION |
+			FE_CAN_QPSK | FE_CAN_RECOVER
+	},
+
+	.release = cx24116_release,
+
+	.init = cx24116_initfe,
+	.sleep = cx24116_sleep,
+	.read_status = cx24116_read_status,
+	.read_ber = cx24116_read_ber,
+	.read_signal_strength = cx24116_read_signal_strength,
+	.read_snr = cx24116_read_snr,
+	.read_ucblocks = cx24116_read_ucblocks,
+	.set_tone = cx24116_set_tone,
+	.set_voltage = cx24116_set_voltage,
+	.diseqc_send_master_cmd = cx24116_send_diseqc_msg,
+	.diseqc_send_burst = cx24116_diseqc_send_burst,
+	.get_frontend_algo = cx24116_get_algo,
+	.tune = cx24116_tune,
+
+	.set_frontend = cx24116_set_frontend,
+};
+
+MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/media/dvb-frontends/cx24116.h b/drivers/media/dvb-frontends/cx24116.h
new file mode 100644
index 0000000..7d90ab9
--- /dev/null
+++ b/drivers/media/dvb-frontends/cx24116.h
@@ -0,0 +1,58 @@
+/*
+    Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver
+
+    Copyright (C) 2006 Steven Toth <stoth@linuxtv.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef CX24116_H
+#define CX24116_H
+
+#include <linux/dvb/frontend.h>
+
+struct cx24116_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* Need to set device param for start_dma */
+	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
+
+	/* Need to reset device during firmware loading */
+	int (*reset_device)(struct dvb_frontend *fe);
+
+	/* Need to set MPEG parameters */
+	u8 mpg_clk_pos_pol:0x02;
+
+	/* max bytes I2C provider can write at once */
+	u16 i2c_wr_max;
+};
+
+#if defined(CONFIG_DVB_CX24116) || \
+	(defined(CONFIG_DVB_CX24116_MODULE) && defined(MODULE))
+extern struct dvb_frontend *cx24116_attach(
+	const struct cx24116_config *config,
+	struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *cx24116_attach(
+	const struct cx24116_config *config,
+	struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* CX24116_H */
diff --git a/drivers/media/dvb-frontends/cx24123.c b/drivers/media/dvb-frontends/cx24123.c
new file mode 100644
index 0000000..7e28b4e
--- /dev/null
+++ b/drivers/media/dvb-frontends/cx24123.c
@@ -0,0 +1,1165 @@
+/*
+ *   Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
+ *
+ *   Copyright (C) 2005 Steven Toth <stoth@linuxtv.org>
+ *
+ *   Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc>
+ *
+ *   Support for CX24123/CX24113-NIM by Patrick Boettcher <pb@linuxtv.org>
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License as
+ *   published by the Free Software Foundation; either version 2 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "dvb_frontend.h"
+#include "cx24123.h"
+
+#define XTAL 10111000
+
+static int force_band;
+module_param(force_band, int, 0644);
+MODULE_PARM_DESC(force_band, "Force a specific band select "\
+	"(1-9, default:off).");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+#define info(args...) do { printk(KERN_INFO "CX24123: " args); } while (0)
+#define err(args...)  do { printk(KERN_ERR  "CX24123: " args); } while (0)
+
+#define dprintk(args...) \
+	do { \
+		if (debug) { \
+			printk(KERN_DEBUG "CX24123: %s: ", __func__); \
+			printk(args); \
+		} \
+	} while (0)
+
+struct cx24123_state {
+	struct i2c_adapter *i2c;
+	const struct cx24123_config *config;
+
+	struct dvb_frontend frontend;
+
+	/* Some PLL specifics for tuning */
+	u32 VCAarg;
+	u32 VGAarg;
+	u32 bandselectarg;
+	u32 pllarg;
+	u32 FILTune;
+
+	struct i2c_adapter tuner_i2c_adapter;
+
+	u8 demod_rev;
+
+	/* The Demod/Tuner can't easily provide these, we cache them */
+	u32 currentfreq;
+	u32 currentsymbolrate;
+};
+
+/* Various tuner defaults need to be established for a given symbol rate Sps */
+static struct cx24123_AGC_val {
+	u32 symbolrate_low;
+	u32 symbolrate_high;
+	u32 VCAprogdata;
+	u32 VGAprogdata;
+	u32 FILTune;
+} cx24123_AGC_vals[] =
+{
+	{
+		.symbolrate_low		= 1000000,
+		.symbolrate_high	= 4999999,
+		/* the specs recommend other values for VGA offsets,
+		   but tests show they are wrong */
+		.VGAprogdata		= (1 << 19) | (0x180 << 9) | 0x1e0,
+		.VCAprogdata		= (2 << 19) | (0x07 << 9) | 0x07,
+		.FILTune		= 0x27f /* 0.41 V */
+	},
+	{
+		.symbolrate_low		=  5000000,
+		.symbolrate_high	= 14999999,
+		.VGAprogdata		= (1 << 19) | (0x180 << 9) | 0x1e0,
+		.VCAprogdata		= (2 << 19) | (0x07 << 9) | 0x1f,
+		.FILTune		= 0x317 /* 0.90 V */
+	},
+	{
+		.symbolrate_low		= 15000000,
+		.symbolrate_high	= 45000000,
+		.VGAprogdata		= (1 << 19) | (0x100 << 9) | 0x180,
+		.VCAprogdata		= (2 << 19) | (0x07 << 9) | 0x3f,
+		.FILTune		= 0x145 /* 2.70 V */
+	},
+};
+
+/*
+ * Various tuner defaults need to be established for a given frequency kHz.
+ * fixme: The bounds on the bands do not match the doc in real life.
+ * fixme: Some of them have been moved, other might need adjustment.
+ */
+static struct cx24123_bandselect_val {
+	u32 freq_low;
+	u32 freq_high;
+	u32 VCOdivider;
+	u32 progdata;
+} cx24123_bandselect_vals[] =
+{
+	/* band 1 */
+	{
+		.freq_low	= 950000,
+		.freq_high	= 1074999,
+		.VCOdivider	= 4,
+		.progdata	= (0 << 19) | (0 << 9) | 0x40,
+	},
+
+	/* band 2 */
+	{
+		.freq_low	= 1075000,
+		.freq_high	= 1177999,
+		.VCOdivider	= 4,
+		.progdata	= (0 << 19) | (0 << 9) | 0x80,
+	},
+
+	/* band 3 */
+	{
+		.freq_low	= 1178000,
+		.freq_high	= 1295999,
+		.VCOdivider	= 2,
+		.progdata	= (0 << 19) | (1 << 9) | 0x01,
+	},
+
+	/* band 4 */
+	{
+		.freq_low	= 1296000,
+		.freq_high	= 1431999,
+		.VCOdivider	= 2,
+		.progdata	= (0 << 19) | (1 << 9) | 0x02,
+	},
+
+	/* band 5 */
+	{
+		.freq_low	= 1432000,
+		.freq_high	= 1575999,
+		.VCOdivider	= 2,
+		.progdata	= (0 << 19) | (1 << 9) | 0x04,
+	},
+
+	/* band 6 */
+	{
+		.freq_low	= 1576000,
+		.freq_high	= 1717999,
+		.VCOdivider	= 2,
+		.progdata	= (0 << 19) | (1 << 9) | 0x08,
+	},
+
+	/* band 7 */
+	{
+		.freq_low	= 1718000,
+		.freq_high	= 1855999,
+		.VCOdivider	= 2,
+		.progdata	= (0 << 19) | (1 << 9) | 0x10,
+	},
+
+	/* band 8 */
+	{
+		.freq_low	= 1856000,
+		.freq_high	= 2035999,
+		.VCOdivider	= 2,
+		.progdata	= (0 << 19) | (1 << 9) | 0x20,
+	},
+
+	/* band 9 */
+	{
+		.freq_low	= 2036000,
+		.freq_high	= 2150000,
+		.VCOdivider	= 2,
+		.progdata	= (0 << 19) | (1 << 9) | 0x40,
+	},
+};
+
+static struct {
+	u8 reg;
+	u8 data;
+} cx24123_regdata[] =
+{
+	{0x00, 0x03}, /* Reset system */
+	{0x00, 0x00}, /* Clear reset */
+	{0x03, 0x07}, /* QPSK, DVB, Auto Acquisition (default) */
+	{0x04, 0x10}, /* MPEG */
+	{0x05, 0x04}, /* MPEG */
+	{0x06, 0x31}, /* MPEG (default) */
+	{0x0b, 0x00}, /* Freq search start point (default) */
+	{0x0c, 0x00}, /* Demodulator sample gain (default) */
+	{0x0d, 0x7f}, /* Force driver to shift until the maximum (+-10 MHz) */
+	{0x0e, 0x03}, /* Default non-inverted, FEC 3/4 (default) */
+	{0x0f, 0xfe}, /* FEC search mask (all supported codes) */
+	{0x10, 0x01}, /* Default search inversion, no repeat (default) */
+	{0x16, 0x00}, /* Enable reading of frequency */
+	{0x17, 0x01}, /* Enable EsNO Ready Counter */
+	{0x1c, 0x80}, /* Enable error counter */
+	{0x20, 0x00}, /* Tuner burst clock rate = 500KHz */
+	{0x21, 0x15}, /* Tuner burst mode, word length = 0x15 */
+	{0x28, 0x00}, /* Enable FILTERV with positive pol., DiSEqC 2.x off */
+	{0x29, 0x00}, /* DiSEqC LNB_DC off */
+	{0x2a, 0xb0}, /* DiSEqC Parameters (default) */
+	{0x2b, 0x73}, /* DiSEqC Tone Frequency (default) */
+	{0x2c, 0x00}, /* DiSEqC Message (0x2c - 0x31) */
+	{0x2d, 0x00},
+	{0x2e, 0x00},
+	{0x2f, 0x00},
+	{0x30, 0x00},
+	{0x31, 0x00},
+	{0x32, 0x8c}, /* DiSEqC Parameters (default) */
+	{0x33, 0x00}, /* Interrupts off (0x33 - 0x34) */
+	{0x34, 0x00},
+	{0x35, 0x03}, /* DiSEqC Tone Amplitude (default) */
+	{0x36, 0x02}, /* DiSEqC Parameters (default) */
+	{0x37, 0x3a}, /* DiSEqC Parameters (default) */
+	{0x3a, 0x00}, /* Enable AGC accumulator (for signal strength) */
+	{0x44, 0x00}, /* Constellation (default) */
+	{0x45, 0x00}, /* Symbol count (default) */
+	{0x46, 0x0d}, /* Symbol rate estimator on (default) */
+	{0x56, 0xc1}, /* Error Counter = Viterbi BER */
+	{0x57, 0xff}, /* Error Counter Window (default) */
+	{0x5c, 0x20}, /* Acquisition AFC Expiration window (default is 0x10) */
+	{0x67, 0x83}, /* Non-DCII symbol clock */
+};
+
+static int cx24123_i2c_writereg(struct cx24123_state *state,
+	u8 i2c_addr, int reg, int data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = {
+		.addr = i2c_addr, .flags = 0, .buf = buf, .len = 2
+	};
+	int err;
+
+	/* printk(KERN_DEBUG "wr(%02x): %02x %02x\n", i2c_addr, reg, data); */
+
+	err = i2c_transfer(state->i2c, &msg, 1);
+	if (err != 1) {
+		printk("%s: writereg error(err == %i, reg == 0x%02x,"
+			 " data == 0x%02x)\n", __func__, err, reg, data);
+		return err;
+	}
+
+	return 0;
+}
+
+static int cx24123_i2c_readreg(struct cx24123_state *state, u8 i2c_addr, u8 reg)
+{
+	int ret;
+	u8 b = 0;
+	struct i2c_msg msg[] = {
+		{ .addr = i2c_addr, .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = i2c_addr, .flags = I2C_M_RD, .buf = &b, .len = 1 }
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		err("%s: reg=0x%x (error=%d)\n", __func__, reg, ret);
+		return ret;
+	}
+
+	/* printk(KERN_DEBUG "rd(%02x): %02x %02x\n", i2c_addr, reg, b); */
+
+	return b;
+}
+
+#define cx24123_readreg(state, reg) \
+	cx24123_i2c_readreg(state, state->config->demod_address, reg)
+#define cx24123_writereg(state, reg, val) \
+	cx24123_i2c_writereg(state, state->config->demod_address, reg, val)
+
+static int cx24123_set_inversion(struct cx24123_state *state,
+	fe_spectral_inversion_t inversion)
+{
+	u8 nom_reg = cx24123_readreg(state, 0x0e);
+	u8 auto_reg = cx24123_readreg(state, 0x10);
+
+	switch (inversion) {
+	case INVERSION_OFF:
+		dprintk("inversion off\n");
+		cx24123_writereg(state, 0x0e, nom_reg & ~0x80);
+		cx24123_writereg(state, 0x10, auto_reg | 0x80);
+		break;
+	case INVERSION_ON:
+		dprintk("inversion on\n");
+		cx24123_writereg(state, 0x0e, nom_reg | 0x80);
+		cx24123_writereg(state, 0x10, auto_reg | 0x80);
+		break;
+	case INVERSION_AUTO:
+		dprintk("inversion auto\n");
+		cx24123_writereg(state, 0x10, auto_reg & ~0x80);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cx24123_get_inversion(struct cx24123_state *state,
+	fe_spectral_inversion_t *inversion)
+{
+	u8 val;
+
+	val = cx24123_readreg(state, 0x1b) >> 7;
+
+	if (val == 0) {
+		dprintk("read inversion off\n");
+		*inversion = INVERSION_OFF;
+	} else {
+		dprintk("read inversion on\n");
+		*inversion = INVERSION_ON;
+	}
+
+	return 0;
+}
+
+static int cx24123_set_fec(struct cx24123_state *state, fe_code_rate_t fec)
+{
+	u8 nom_reg = cx24123_readreg(state, 0x0e) & ~0x07;
+
+	if ((fec < FEC_NONE) || (fec > FEC_AUTO))
+		fec = FEC_AUTO;
+
+	/* Set the soft decision threshold */
+	if (fec == FEC_1_2)
+		cx24123_writereg(state, 0x43,
+			cx24123_readreg(state, 0x43) | 0x01);
+	else
+		cx24123_writereg(state, 0x43,
+			cx24123_readreg(state, 0x43) & ~0x01);
+
+	switch (fec) {
+	case FEC_1_2:
+		dprintk("set FEC to 1/2\n");
+		cx24123_writereg(state, 0x0e, nom_reg | 0x01);
+		cx24123_writereg(state, 0x0f, 0x02);
+		break;
+	case FEC_2_3:
+		dprintk("set FEC to 2/3\n");
+		cx24123_writereg(state, 0x0e, nom_reg | 0x02);
+		cx24123_writereg(state, 0x0f, 0x04);
+		break;
+	case FEC_3_4:
+		dprintk("set FEC to 3/4\n");
+		cx24123_writereg(state, 0x0e, nom_reg | 0x03);
+		cx24123_writereg(state, 0x0f, 0x08);
+		break;
+	case FEC_4_5:
+		dprintk("set FEC to 4/5\n");
+		cx24123_writereg(state, 0x0e, nom_reg | 0x04);
+		cx24123_writereg(state, 0x0f, 0x10);
+		break;
+	case FEC_5_6:
+		dprintk("set FEC to 5/6\n");
+		cx24123_writereg(state, 0x0e, nom_reg | 0x05);
+		cx24123_writereg(state, 0x0f, 0x20);
+		break;
+	case FEC_6_7:
+		dprintk("set FEC to 6/7\n");
+		cx24123_writereg(state, 0x0e, nom_reg | 0x06);
+		cx24123_writereg(state, 0x0f, 0x40);
+		break;
+	case FEC_7_8:
+		dprintk("set FEC to 7/8\n");
+		cx24123_writereg(state, 0x0e, nom_reg | 0x07);
+		cx24123_writereg(state, 0x0f, 0x80);
+		break;
+	case FEC_AUTO:
+		dprintk("set FEC to auto\n");
+		cx24123_writereg(state, 0x0f, 0xfe);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int cx24123_get_fec(struct cx24123_state *state, fe_code_rate_t *fec)
+{
+	int ret;
+
+	ret = cx24123_readreg(state, 0x1b);
+	if (ret < 0)
+		return ret;
+	ret = ret & 0x07;
+
+	switch (ret) {
+	case 1:
+		*fec = FEC_1_2;
+		break;
+	case 2:
+		*fec = FEC_2_3;
+		break;
+	case 3:
+		*fec = FEC_3_4;
+		break;
+	case 4:
+		*fec = FEC_4_5;
+		break;
+	case 5:
+		*fec = FEC_5_6;
+		break;
+	case 6:
+		*fec = FEC_6_7;
+		break;
+	case 7:
+		*fec = FEC_7_8;
+		break;
+	default:
+		/* this can happen when there's no lock */
+		*fec = FEC_NONE;
+	}
+
+	return 0;
+}
+
+/* Approximation of closest integer of log2(a/b). It actually gives the
+   lowest integer i such that 2^i >= round(a/b) */
+static u32 cx24123_int_log2(u32 a, u32 b)
+{
+	u32 exp, nearest = 0;
+	u32 div = a / b;
+	if (a % b >= b / 2)
+		++div;
+	if (div < (1 << 31)) {
+		for (exp = 1; div > exp; nearest++)
+			exp += exp;
+	}
+	return nearest;
+}
+
+static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate)
+{
+	u32 tmp, sample_rate, ratio, sample_gain;
+	u8 pll_mult;
+
+	/*  check if symbol rate is within limits */
+	if ((srate > state->frontend.ops.info.symbol_rate_max) ||
+	    (srate < state->frontend.ops.info.symbol_rate_min))
+		return -EOPNOTSUPP;
+
+	/* choose the sampling rate high enough for the required operation,
+	   while optimizing the power consumed by the demodulator */
+	if (srate < (XTAL*2)/2)
+		pll_mult = 2;
+	else if (srate < (XTAL*3)/2)
+		pll_mult = 3;
+	else if (srate < (XTAL*4)/2)
+		pll_mult = 4;
+	else if (srate < (XTAL*5)/2)
+		pll_mult = 5;
+	else if (srate < (XTAL*6)/2)
+		pll_mult = 6;
+	else if (srate < (XTAL*7)/2)
+		pll_mult = 7;
+	else if (srate < (XTAL*8)/2)
+		pll_mult = 8;
+	else
+		pll_mult = 9;
+
+
+	sample_rate = pll_mult * XTAL;
+
+	/*
+	    SYSSymbolRate[21:0] = (srate << 23) / sample_rate
+
+	    We have to use 32 bit unsigned arithmetic without precision loss.
+	    The maximum srate is 45000000 or 0x02AEA540. This number has
+	    only 6 clear bits on top, hence we can shift it left only 6 bits
+	    at a time. Borrowed from cx24110.c
+	*/
+
+	tmp = srate << 6;
+	ratio = tmp / sample_rate;
+
+	tmp = (tmp % sample_rate) << 6;
+	ratio = (ratio << 6) + (tmp / sample_rate);
+
+	tmp = (tmp % sample_rate) << 6;
+	ratio = (ratio << 6) + (tmp / sample_rate);
+
+	tmp = (tmp % sample_rate) << 5;
+	ratio = (ratio << 5) + (tmp / sample_rate);
+
+
+	cx24123_writereg(state, 0x01, pll_mult * 6);
+
+	cx24123_writereg(state, 0x08, (ratio >> 16) & 0x3f);
+	cx24123_writereg(state, 0x09, (ratio >> 8) & 0xff);
+	cx24123_writereg(state, 0x0a, ratio & 0xff);
+
+	/* also set the demodulator sample gain */
+	sample_gain = cx24123_int_log2(sample_rate, srate);
+	tmp = cx24123_readreg(state, 0x0c) & ~0xe0;
+	cx24123_writereg(state, 0x0c, tmp | sample_gain << 5);
+
+	dprintk("srate=%d, ratio=0x%08x, sample_rate=%i sample_gain=%d\n",
+		srate, ratio, sample_rate, sample_gain);
+
+	return 0;
+}
+
+/*
+ * Based on the required frequency and symbolrate, the tuner AGC has
+ * to be configured and the correct band selected.
+ * Calculate those values.
+ */
+static int cx24123_pll_calculate(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct cx24123_state *state = fe->demodulator_priv;
+	u32 ndiv = 0, adiv = 0, vco_div = 0;
+	int i = 0;
+	int pump = 2;
+	int band = 0;
+	int num_bands = ARRAY_SIZE(cx24123_bandselect_vals);
+	struct cx24123_bandselect_val *bsv = NULL;
+	struct cx24123_AGC_val *agcv = NULL;
+
+	/* Defaults for low freq, low rate */
+	state->VCAarg = cx24123_AGC_vals[0].VCAprogdata;
+	state->VGAarg = cx24123_AGC_vals[0].VGAprogdata;
+	state->bandselectarg = cx24123_bandselect_vals[0].progdata;
+	vco_div = cx24123_bandselect_vals[0].VCOdivider;
+
+	/* For the given symbol rate, determine the VCA, VGA and
+	 * FILTUNE programming bits */
+	for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++) {
+		agcv = &cx24123_AGC_vals[i];
+		if ((agcv->symbolrate_low <= p->symbol_rate) &&
+		    (agcv->symbolrate_high >= p->symbol_rate)) {
+			state->VCAarg = agcv->VCAprogdata;
+			state->VGAarg = agcv->VGAprogdata;
+			state->FILTune = agcv->FILTune;
+		}
+	}
+
+	/* determine the band to use */
+	if (force_band < 1 || force_band > num_bands) {
+		for (i = 0; i < num_bands; i++) {
+			bsv = &cx24123_bandselect_vals[i];
+			if ((bsv->freq_low <= p->frequency) &&
+				(bsv->freq_high >= p->frequency))
+				band = i;
+		}
+	} else
+		band = force_band - 1;
+
+	state->bandselectarg = cx24123_bandselect_vals[band].progdata;
+	vco_div = cx24123_bandselect_vals[band].VCOdivider;
+
+	/* determine the charge pump current */
+	if (p->frequency < (cx24123_bandselect_vals[band].freq_low +
+		cx24123_bandselect_vals[band].freq_high) / 2)
+		pump = 0x01;
+	else
+		pump = 0x02;
+
+	/* Determine the N/A dividers for the requested lband freq (in kHz). */
+	/* Note: the reference divider R=10, frequency is in KHz,
+	 * XTAL is in Hz */
+	ndiv = (((p->frequency * vco_div * 10) /
+		(2 * XTAL / 1000)) / 32) & 0x1ff;
+	adiv = (((p->frequency * vco_div * 10) /
+		(2 * XTAL / 1000)) % 32) & 0x1f;
+
+	if (adiv == 0 && ndiv > 0)
+		ndiv--;
+
+	/* control bits 11, refdiv 11, charge pump polarity 1,
+	 * charge pump current, ndiv, adiv */
+	state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) |
+		(pump << 14) | (ndiv << 5) | adiv;
+
+	return 0;
+}
+
+/*
+ * Tuner data is 21 bits long, must be left-aligned in data.
+ * Tuner cx24109 is written through a dedicated 3wire interface
+ * on the demod chip.
+ */
+static int cx24123_pll_writereg(struct dvb_frontend *fe, u32 data)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	unsigned long timeout;
+
+	dprintk("pll writereg called, data=0x%08x\n", data);
+
+	/* align the 21 bytes into to bit23 boundary */
+	data = data << 3;
+
+	/* Reset the demod pll word length to 0x15 bits */
+	cx24123_writereg(state, 0x21, 0x15);
+
+	/* write the msb 8 bits, wait for the send to be completed */
+	timeout = jiffies + msecs_to_jiffies(40);
+	cx24123_writereg(state, 0x22, (data >> 16) & 0xff);
+	while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
+		if (time_after(jiffies, timeout)) {
+			err("%s:  demodulator is not responding, "\
+				"possibly hung, aborting.\n", __func__);
+			return -EREMOTEIO;
+		}
+		msleep(10);
+	}
+
+	/* send another 8 bytes, wait for the send to be completed */
+	timeout = jiffies + msecs_to_jiffies(40);
+	cx24123_writereg(state, 0x22, (data >> 8) & 0xff);
+	while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
+		if (time_after(jiffies, timeout)) {
+			err("%s:  demodulator is not responding, "\
+				"possibly hung, aborting.\n", __func__);
+			return -EREMOTEIO;
+		}
+		msleep(10);
+	}
+
+	/* send the lower 5 bits of this byte, padded with 3 LBB,
+	 * wait for the send to be completed */
+	timeout = jiffies + msecs_to_jiffies(40);
+	cx24123_writereg(state, 0x22, (data) & 0xff);
+	while ((cx24123_readreg(state, 0x20) & 0x80)) {
+		if (time_after(jiffies, timeout)) {
+			err("%s:  demodulator is not responding," \
+				"possibly hung, aborting.\n", __func__);
+			return -EREMOTEIO;
+		}
+		msleep(10);
+	}
+
+	/* Trigger the demod to configure the tuner */
+	cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) | 2);
+	cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) & 0xfd);
+
+	return 0;
+}
+
+static int cx24123_pll_tune(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct cx24123_state *state = fe->demodulator_priv;
+	u8 val;
+
+	dprintk("frequency=%i\n", p->frequency);
+
+	if (cx24123_pll_calculate(fe) != 0) {
+		err("%s: cx24123_pll_calcutate failed\n", __func__);
+		return -EINVAL;
+	}
+
+	/* Write the new VCO/VGA */
+	cx24123_pll_writereg(fe, state->VCAarg);
+	cx24123_pll_writereg(fe, state->VGAarg);
+
+	/* Write the new bandselect and pll args */
+	cx24123_pll_writereg(fe, state->bandselectarg);
+	cx24123_pll_writereg(fe, state->pllarg);
+
+	/* set the FILTUNE voltage */
+	val = cx24123_readreg(state, 0x28) & ~0x3;
+	cx24123_writereg(state, 0x27, state->FILTune >> 2);
+	cx24123_writereg(state, 0x28, val | (state->FILTune & 0x3));
+
+	dprintk("pll tune VCA=%d, band=%d, pll=%d\n", state->VCAarg,
+			state->bandselectarg, state->pllarg);
+
+	return 0;
+}
+
+
+/*
+ * 0x23:
+ *    [7:7] = BTI enabled
+ *    [6:6] = I2C repeater enabled
+ *    [5:5] = I2C repeater start
+ *    [0:0] = BTI start
+ */
+
+/* mode == 1 -> i2c-repeater, 0 -> bti */
+static int cx24123_repeater_mode(struct cx24123_state *state, u8 mode, u8 start)
+{
+	u8 r = cx24123_readreg(state, 0x23) & 0x1e;
+	if (mode)
+		r |= (1 << 6) | (start << 5);
+	else
+		r |= (1 << 7) | (start);
+	return cx24123_writereg(state, 0x23, r);
+}
+
+static int cx24123_initfe(struct dvb_frontend *fe)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	int i;
+
+	dprintk("init frontend\n");
+
+	/* Configure the demod to a good set of defaults */
+	for (i = 0; i < ARRAY_SIZE(cx24123_regdata); i++)
+		cx24123_writereg(state, cx24123_regdata[i].reg,
+			cx24123_regdata[i].data);
+
+	/* Set the LNB polarity */
+	if (state->config->lnb_polarity)
+		cx24123_writereg(state, 0x32,
+			cx24123_readreg(state, 0x32) | 0x02);
+
+	if (state->config->dont_use_pll)
+		cx24123_repeater_mode(state, 1, 0);
+
+	return 0;
+}
+
+static int cx24123_set_voltage(struct dvb_frontend *fe,
+	fe_sec_voltage_t voltage)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	u8 val;
+
+	val = cx24123_readreg(state, 0x29) & ~0x40;
+
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		dprintk("setting voltage 13V\n");
+		return cx24123_writereg(state, 0x29, val & 0x7f);
+	case SEC_VOLTAGE_18:
+		dprintk("setting voltage 18V\n");
+		return cx24123_writereg(state, 0x29, val | 0x80);
+	case SEC_VOLTAGE_OFF:
+		/* already handled in cx88-dvb */
+		return 0;
+	default:
+		return -EINVAL;
+	};
+
+	return 0;
+}
+
+/* wait for diseqc queue to become ready (or timeout) */
+static void cx24123_wait_for_diseqc(struct cx24123_state *state)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(200);
+	while (!(cx24123_readreg(state, 0x29) & 0x40)) {
+		if (time_after(jiffies, timeout)) {
+			err("%s: diseqc queue not ready, " \
+				"command may be lost.\n", __func__);
+			break;
+		}
+		msleep(10);
+	}
+}
+
+static int cx24123_send_diseqc_msg(struct dvb_frontend *fe,
+	struct dvb_diseqc_master_cmd *cmd)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	int i, val, tone;
+
+	dprintk("\n");
+
+	/* stop continuous tone if enabled */
+	tone = cx24123_readreg(state, 0x29);
+	if (tone & 0x10)
+		cx24123_writereg(state, 0x29, tone & ~0x50);
+
+	/* wait for diseqc queue ready */
+	cx24123_wait_for_diseqc(state);
+
+	/* select tone mode */
+	cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
+
+	for (i = 0; i < cmd->msg_len; i++)
+		cx24123_writereg(state, 0x2C + i, cmd->msg[i]);
+
+	val = cx24123_readreg(state, 0x29);
+	cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40) |
+		((cmd->msg_len-3) & 3));
+
+	/* wait for diseqc message to finish sending */
+	cx24123_wait_for_diseqc(state);
+
+	/* restart continuous tone if enabled */
+	if (tone & 0x10)
+		cx24123_writereg(state, 0x29, tone & ~0x40);
+
+	return 0;
+}
+
+static int cx24123_diseqc_send_burst(struct dvb_frontend *fe,
+	fe_sec_mini_cmd_t burst)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	int val, tone;
+
+	dprintk("\n");
+
+	/* stop continuous tone if enabled */
+	tone = cx24123_readreg(state, 0x29);
+	if (tone & 0x10)
+		cx24123_writereg(state, 0x29, tone & ~0x50);
+
+	/* wait for diseqc queue ready */
+	cx24123_wait_for_diseqc(state);
+
+	/* select tone mode */
+	cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) | 0x4);
+	msleep(30);
+	val = cx24123_readreg(state, 0x29);
+	if (burst == SEC_MINI_A)
+		cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00));
+	else if (burst == SEC_MINI_B)
+		cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x08));
+	else
+		return -EINVAL;
+
+	cx24123_wait_for_diseqc(state);
+	cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
+
+	/* restart continuous tone if enabled */
+	if (tone & 0x10)
+		cx24123_writereg(state, 0x29, tone & ~0x40);
+
+	return 0;
+}
+
+static int cx24123_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	int sync = cx24123_readreg(state, 0x14);
+
+	*status = 0;
+	if (state->config->dont_use_pll) {
+		u32 tun_status = 0;
+		if (fe->ops.tuner_ops.get_status)
+			fe->ops.tuner_ops.get_status(fe, &tun_status);
+		if (tun_status & TUNER_STATUS_LOCKED)
+			*status |= FE_HAS_SIGNAL;
+	} else {
+		int lock = cx24123_readreg(state, 0x20);
+		if (lock & 0x01)
+			*status |= FE_HAS_SIGNAL;
+	}
+
+	if (sync & 0x02)
+		*status |= FE_HAS_CARRIER;	/* Phase locked */
+	if (sync & 0x04)
+		*status |= FE_HAS_VITERBI;
+
+	/* Reed-Solomon Status */
+	if (sync & 0x08)
+		*status |= FE_HAS_SYNC;
+	if (sync & 0x80)
+		*status |= FE_HAS_LOCK;		/*Full Sync */
+
+	return 0;
+}
+
+/*
+ * Configured to return the measurement of errors in blocks,
+ * because no UCBLOCKS value is available, so this value doubles up
+ * to satisfy both measurements.
+ */
+static int cx24123_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+
+	/* The true bit error rate is this value divided by
+	   the window size (set as 256 * 255) */
+	*ber = ((cx24123_readreg(state, 0x1c) & 0x3f) << 16) |
+		(cx24123_readreg(state, 0x1d) << 8 |
+		 cx24123_readreg(state, 0x1e));
+
+	dprintk("BER = %d\n", *ber);
+
+	return 0;
+}
+
+static int cx24123_read_signal_strength(struct dvb_frontend *fe,
+	u16 *signal_strength)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+
+	/* larger = better */
+	*signal_strength = cx24123_readreg(state, 0x3b) << 8;
+
+	dprintk("Signal strength = %d\n", *signal_strength);
+
+	return 0;
+}
+
+static int cx24123_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+
+	/* Inverted raw Es/N0 count, totally bogus but better than the
+	   BER threshold. */
+	*snr = 65535 - (((u16)cx24123_readreg(state, 0x18) << 8) |
+			 (u16)cx24123_readreg(state, 0x19));
+
+	dprintk("read S/N index = %d\n", *snr);
+
+	return 0;
+}
+
+static int cx24123_set_frontend(struct dvb_frontend *fe)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+	dprintk("\n");
+
+	if (state->config->set_ts_params)
+		state->config->set_ts_params(fe, 0);
+
+	state->currentfreq = p->frequency;
+	state->currentsymbolrate = p->symbol_rate;
+
+	cx24123_set_inversion(state, p->inversion);
+	cx24123_set_fec(state, p->fec_inner);
+	cx24123_set_symbolrate(state, p->symbol_rate);
+
+	if (!state->config->dont_use_pll)
+		cx24123_pll_tune(fe);
+	else if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+	else
+		err("it seems I don't have a tuner...");
+
+	/* Enable automatic acquisition and reset cycle */
+	cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07));
+	cx24123_writereg(state, 0x00, 0x10);
+	cx24123_writereg(state, 0x00, 0);
+
+	if (state->config->agc_callback)
+		state->config->agc_callback(fe);
+
+	return 0;
+}
+
+static int cx24123_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct cx24123_state *state = fe->demodulator_priv;
+
+	dprintk("\n");
+
+	if (cx24123_get_inversion(state, &p->inversion) != 0) {
+		err("%s: Failed to get inversion status\n", __func__);
+		return -EREMOTEIO;
+	}
+	if (cx24123_get_fec(state, &p->fec_inner) != 0) {
+		err("%s: Failed to get fec status\n", __func__);
+		return -EREMOTEIO;
+	}
+	p->frequency = state->currentfreq;
+	p->symbol_rate = state->currentsymbolrate;
+
+	return 0;
+}
+
+static int cx24123_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	u8 val;
+
+	/* wait for diseqc queue ready */
+	cx24123_wait_for_diseqc(state);
+
+	val = cx24123_readreg(state, 0x29) & ~0x40;
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		dprintk("setting tone on\n");
+		return cx24123_writereg(state, 0x29, val | 0x10);
+	case SEC_TONE_OFF:
+		dprintk("setting tone off\n");
+		return cx24123_writereg(state, 0x29, val & 0xef);
+	default:
+		err("CASE reached default with tone=%d\n", tone);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cx24123_tune(struct dvb_frontend *fe,
+			bool re_tune,
+			unsigned int mode_flags,
+			unsigned int *delay,
+			fe_status_t *status)
+{
+	int retval = 0;
+
+	if (re_tune)
+		retval = cx24123_set_frontend(fe);
+
+	if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
+		cx24123_read_status(fe, status);
+	*delay = HZ/10;
+
+	return retval;
+}
+
+static int cx24123_get_algo(struct dvb_frontend *fe)
+{
+	return 1; /* FE_ALGO_HW */
+}
+
+static void cx24123_release(struct dvb_frontend *fe)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	dprintk("\n");
+	i2c_del_adapter(&state->tuner_i2c_adapter);
+	kfree(state);
+}
+
+static int cx24123_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap,
+	struct i2c_msg msg[], int num)
+{
+	struct cx24123_state *state = i2c_get_adapdata(i2c_adap);
+	/* this repeater closes after the first stop */
+	cx24123_repeater_mode(state, 1, 1);
+	return i2c_transfer(state->i2c, msg, num);
+}
+
+static u32 cx24123_tuner_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm cx24123_tuner_i2c_algo = {
+	.master_xfer   = cx24123_tuner_i2c_tuner_xfer,
+	.functionality = cx24123_tuner_i2c_func,
+};
+
+struct i2c_adapter *
+	cx24123_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	return &state->tuner_i2c_adapter;
+}
+EXPORT_SYMBOL(cx24123_get_tuner_i2c_adapter);
+
+static struct dvb_frontend_ops cx24123_ops;
+
+struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
+				    struct i2c_adapter *i2c)
+{
+	/* allocate memory for the internal state */
+	struct cx24123_state *state =
+		kzalloc(sizeof(struct cx24123_state), GFP_KERNEL);
+
+	dprintk("\n");
+	if (state == NULL) {
+		err("Unable to kzalloc\n");
+		goto error;
+	}
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+
+	/* check if the demod is there */
+	state->demod_rev = cx24123_readreg(state, 0x00);
+	switch (state->demod_rev) {
+	case 0xe1:
+		info("detected CX24123C\n");
+		break;
+	case 0xd1:
+		info("detected CX24123\n");
+		break;
+	default:
+		err("wrong demod revision: %x\n", state->demod_rev);
+		goto error;
+	}
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &cx24123_ops,
+		sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	/* create tuner i2c adapter */
+	if (config->dont_use_pll)
+		cx24123_repeater_mode(state, 1, 0);
+
+	strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus",
+		sizeof(state->tuner_i2c_adapter.name));
+	state->tuner_i2c_adapter.algo      = &cx24123_tuner_i2c_algo;
+	state->tuner_i2c_adapter.algo_data = NULL;
+	i2c_set_adapdata(&state->tuner_i2c_adapter, state);
+	if (i2c_add_adapter(&state->tuner_i2c_adapter) < 0) {
+		err("tuner i2c bus could not be initialized\n");
+		goto error;
+	}
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+
+	return NULL;
+}
+EXPORT_SYMBOL(cx24123_attach);
+
+static struct dvb_frontend_ops cx24123_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name = "Conexant CX24123/CX24109",
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		.frequency_stepsize = 1011, /* kHz for QPSK frontends */
+		.frequency_tolerance = 5000,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_RECOVER
+	},
+
+	.release = cx24123_release,
+
+	.init = cx24123_initfe,
+	.set_frontend = cx24123_set_frontend,
+	.get_frontend = cx24123_get_frontend,
+	.read_status = cx24123_read_status,
+	.read_ber = cx24123_read_ber,
+	.read_signal_strength = cx24123_read_signal_strength,
+	.read_snr = cx24123_read_snr,
+	.diseqc_send_master_cmd = cx24123_send_diseqc_msg,
+	.diseqc_send_burst = cx24123_diseqc_send_burst,
+	.set_tone = cx24123_set_tone,
+	.set_voltage = cx24123_set_voltage,
+	.tune = cx24123_tune,
+	.get_frontend_algo = cx24123_get_algo,
+};
+
+MODULE_DESCRIPTION("DVB Frontend module for Conexant " \
+	"CX24123/CX24109/CX24113 hardware");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/media/dvb-frontends/cx24123.h b/drivers/media/dvb-frontends/cx24123.h
new file mode 100644
index 0000000..51ae866
--- /dev/null
+++ b/drivers/media/dvb-frontends/cx24123.h
@@ -0,0 +1,61 @@
+/*
+    Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
+
+    Copyright (C) 2005 Steven Toth <stoth@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef CX24123_H
+#define CX24123_H
+
+#include <linux/dvb/frontend.h>
+
+struct cx24123_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* Need to set device param for start_dma */
+	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
+
+	/* 0 = LNB voltage normal, 1 = LNB voltage inverted */
+	int lnb_polarity;
+
+	/* this device has another tuner */
+	u8 dont_use_pll;
+	void (*agc_callback) (struct dvb_frontend *);
+};
+
+#if defined(CONFIG_DVB_CX24123) || (defined(CONFIG_DVB_CX24123_MODULE) \
+	&& defined(MODULE))
+extern struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
+					   struct i2c_adapter *i2c);
+extern struct i2c_adapter *cx24123_get_tuner_i2c_adapter(struct dvb_frontend *);
+#else
+static inline struct dvb_frontend *cx24123_attach(
+	const struct cx24123_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+static struct i2c_adapter *
+	cx24123_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* CX24123_H */
diff --git a/drivers/media/dvb-frontends/cxd2820r.h b/drivers/media/dvb-frontends/cxd2820r.h
new file mode 100644
index 0000000..5aa306e
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2820r.h
@@ -0,0 +1,94 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#ifndef CXD2820R_H
+#define CXD2820R_H
+
+#include <linux/dvb/frontend.h>
+
+#define CXD2820R_GPIO_D (0 << 0) /* disable */
+#define CXD2820R_GPIO_E (1 << 0) /* enable */
+#define CXD2820R_GPIO_O (0 << 1) /* output */
+#define CXD2820R_GPIO_I (1 << 1) /* input */
+#define CXD2820R_GPIO_L (0 << 2) /* output low */
+#define CXD2820R_GPIO_H (1 << 2) /* output high */
+
+#define CXD2820R_TS_SERIAL        0x08
+#define CXD2820R_TS_SERIAL_MSB    0x28
+#define CXD2820R_TS_PARALLEL      0x30
+#define CXD2820R_TS_PARALLEL_MSB  0x70
+
+struct cxd2820r_config {
+	/* Demodulator I2C address.
+	 * Driver determines DVB-C slave I2C address automatically from master
+	 * address.
+	 * Default: none, must set
+	 * Values: 0x6c, 0x6d
+	 */
+	u8 i2c_address;
+
+	/* TS output mode.
+	 * Default: none, must set.
+	 * Values:
+	 */
+	u8 ts_mode;
+
+	/* IF AGC polarity.
+	 * Default: 0
+	 * Values: 0, 1
+	 */
+	bool if_agc_polarity;
+
+	/* Spectrum inversion.
+	 * Default: 0
+	 * Values: 0, 1
+	 */
+	bool spec_inv;
+
+	/* GPIOs for all used modes.
+	 * Default: none, disabled
+	 * Values: <see above>
+	 */
+	u8 gpio_dvbt[3];
+	u8 gpio_dvbt2[3];
+	u8 gpio_dvbc[3];
+};
+
+
+#if defined(CONFIG_DVB_CXD2820R) || \
+	(defined(CONFIG_DVB_CXD2820R_MODULE) && defined(MODULE))
+extern struct dvb_frontend *cxd2820r_attach(
+	const struct cxd2820r_config *config,
+	struct i2c_adapter *i2c
+);
+#else
+static inline struct dvb_frontend *cxd2820r_attach(
+	const struct cxd2820r_config *config,
+	struct i2c_adapter *i2c
+)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+#endif
+
+#endif /* CXD2820R_H */
diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c
new file mode 100644
index 0000000..ed3b0ba6
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2820r_c.c
@@ -0,0 +1,346 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include "cxd2820r_priv.h"
+
+int cxd2820r_set_frontend_c(struct dvb_frontend *fe)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i;
+	u8 buf[2];
+	u32 if_freq;
+	u16 if_ctl;
+	u64 num;
+	struct reg_val_mask tab[] = {
+		{ 0x00080, 0x01, 0xff },
+		{ 0x00081, 0x05, 0xff },
+		{ 0x00085, 0x07, 0xff },
+		{ 0x00088, 0x01, 0xff },
+
+		{ 0x00082, 0x20, 0x60 },
+		{ 0x1016a, 0x48, 0xff },
+		{ 0x100a5, 0x00, 0x01 },
+		{ 0x10020, 0x06, 0x07 },
+		{ 0x10059, 0x50, 0xff },
+		{ 0x10087, 0x0c, 0x3c },
+		{ 0x1008b, 0x07, 0xff },
+		{ 0x1001f, priv->cfg.if_agc_polarity << 7, 0x80 },
+		{ 0x10070, priv->cfg.ts_mode, 0xff },
+	};
+
+	dbg("%s: RF=%d SR=%d", __func__, c->frequency, c->symbol_rate);
+
+	/* update GPIOs */
+	ret = cxd2820r_gpio(fe);
+	if (ret)
+		goto error;
+
+	/* program tuner */
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+
+	if (priv->delivery_system !=  SYS_DVBC_ANNEX_A) {
+		for (i = 0; i < ARRAY_SIZE(tab); i++) {
+			ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
+				tab[i].val, tab[i].mask);
+			if (ret)
+				goto error;
+		}
+	}
+
+	priv->delivery_system = SYS_DVBC_ANNEX_A;
+	priv->ber_running = 0; /* tune stops BER counter */
+
+	/* program IF frequency */
+	if (fe->ops.tuner_ops.get_if_frequency) {
+		ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
+		if (ret)
+			goto error;
+	} else
+		if_freq = 0;
+
+	dbg("%s: if_freq=%d", __func__, if_freq);
+
+	num = if_freq / 1000; /* Hz => kHz */
+	num *= 0x4000;
+	if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
+	buf[0] = (if_ctl >> 8) & 0x3f;
+	buf[1] = (if_ctl >> 0) & 0xff;
+
+	ret = cxd2820r_wr_regs(priv, 0x10042, buf, 2);
+	if (ret)
+		goto error;
+
+	ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
+	if (ret)
+		goto error;
+
+	ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
+	if (ret)
+		goto error;
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_get_frontend_c(struct dvb_frontend *fe)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret;
+	u8 buf[2];
+
+	ret = cxd2820r_rd_regs(priv, 0x1001a, buf, 2);
+	if (ret)
+		goto error;
+
+	c->symbol_rate = 2500 * ((buf[0] & 0x0f) << 8 | buf[1]);
+
+	ret = cxd2820r_rd_reg(priv, 0x10019, &buf[0]);
+	if (ret)
+		goto error;
+
+	switch ((buf[0] >> 0) & 0x07) {
+	case 0:
+		c->modulation = QAM_16;
+		break;
+	case 1:
+		c->modulation = QAM_32;
+		break;
+	case 2:
+		c->modulation = QAM_64;
+		break;
+	case 3:
+		c->modulation = QAM_128;
+		break;
+	case 4:
+		c->modulation = QAM_256;
+		break;
+	}
+
+	switch ((buf[0] >> 7) & 0x01) {
+	case 0:
+		c->inversion = INVERSION_OFF;
+		break;
+	case 1:
+		c->inversion = INVERSION_ON;
+		break;
+	}
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 buf[3], start_ber = 0;
+	*ber = 0;
+
+	if (priv->ber_running) {
+		ret = cxd2820r_rd_regs(priv, 0x10076, buf, sizeof(buf));
+		if (ret)
+			goto error;
+
+		if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) {
+			*ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0];
+			start_ber = 1;
+		}
+	} else {
+		priv->ber_running = 1;
+		start_ber = 1;
+	}
+
+	if (start_ber) {
+		/* (re)start BER */
+		ret = cxd2820r_wr_reg(priv, 0x10079, 0x01);
+		if (ret)
+			goto error;
+	}
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_read_signal_strength_c(struct dvb_frontend *fe,
+	u16 *strength)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 buf[2];
+	u16 tmp;
+
+	ret = cxd2820r_rd_regs(priv, 0x10049, buf, sizeof(buf));
+	if (ret)
+		goto error;
+
+	tmp = (buf[0] & 0x03) << 8 | buf[1];
+	tmp = (~tmp & 0x03ff);
+
+	if (tmp == 512)
+		/* ~no signal */
+		tmp = 0;
+	else if (tmp > 350)
+		tmp = 350;
+
+	/* scale value to 0x0000-0xffff */
+	*strength = tmp * 0xffff / (350-0);
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_read_snr_c(struct dvb_frontend *fe, u16 *snr)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 tmp;
+	unsigned int A, B;
+	/* report SNR in dB * 10 */
+
+	ret = cxd2820r_rd_reg(priv, 0x10019, &tmp);
+	if (ret)
+		goto error;
+
+	if (((tmp >> 0) & 0x03) % 2) {
+		A = 875;
+		B = 650;
+	} else {
+		A = 950;
+		B = 760;
+	}
+
+	ret = cxd2820r_rd_reg(priv, 0x1004d, &tmp);
+	if (ret)
+		goto error;
+
+	#define CXD2820R_LOG2_E_24 24204406 /* log2(e) << 24 */
+	if (tmp)
+		*snr = A * (intlog2(B / tmp) >> 5) / (CXD2820R_LOG2_E_24 >> 5)
+			/ 10;
+	else
+		*snr = 0;
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	*ucblocks = 0;
+	/* no way to read ? */
+	return 0;
+}
+
+int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 buf[2];
+	*status = 0;
+
+	ret = cxd2820r_rd_regs(priv, 0x10088, buf, sizeof(buf));
+	if (ret)
+		goto error;
+
+	if (((buf[0] >> 0) & 0x01) == 1) {
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+			FE_HAS_VITERBI | FE_HAS_SYNC;
+
+		if (((buf[1] >> 3) & 0x01) == 1) {
+			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+		}
+	}
+
+	dbg("%s: lock=%02x %02x", __func__, buf[0], buf[1]);
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_init_c(struct dvb_frontend *fe)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret;
+
+	ret = cxd2820r_wr_reg(priv, 0x00085, 0x07);
+	if (ret)
+		goto error;
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_sleep_c(struct dvb_frontend *fe)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret, i;
+	struct reg_val_mask tab[] = {
+		{ 0x000ff, 0x1f, 0xff },
+		{ 0x00085, 0x00, 0xff },
+		{ 0x00088, 0x01, 0xff },
+		{ 0x00081, 0x00, 0xff },
+		{ 0x00080, 0x00, 0xff },
+	};
+
+	dbg("%s", __func__);
+
+	priv->delivery_system = SYS_UNDEFINED;
+
+	for (i = 0; i < ARRAY_SIZE(tab); i++) {
+		ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
+			tab[i].mask);
+		if (ret)
+			goto error;
+	}
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *s)
+{
+	s->min_delay_ms = 500;
+	s->step_size = 0; /* no zigzag */
+	s->max_drift = 0;
+
+	return 0;
+}
diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c
new file mode 100644
index 0000000..3bba37d
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2820r_core.c
@@ -0,0 +1,646 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include "cxd2820r_priv.h"
+
+int cxd2820r_debug;
+module_param_named(debug, cxd2820r_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+/* write multiple registers */
+static int cxd2820r_wr_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg,
+	u8 *val, int len)
+{
+	int ret;
+	u8 buf[len+1];
+	struct i2c_msg msg[1] = {
+		{
+			.addr = i2c,
+			.flags = 0,
+			.len = sizeof(buf),
+			.buf = buf,
+		}
+	};
+
+	buf[0] = reg;
+	memcpy(&buf[1], val, len);
+
+	ret = i2c_transfer(priv->i2c, msg, 1);
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+/* read multiple registers */
+static int cxd2820r_rd_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg,
+	u8 *val, int len)
+{
+	int ret;
+	u8 buf[len];
+	struct i2c_msg msg[2] = {
+		{
+			.addr = i2c,
+			.flags = 0,
+			.len = 1,
+			.buf = &reg,
+		}, {
+			.addr = i2c,
+			.flags = I2C_M_RD,
+			.len = sizeof(buf),
+			.buf = buf,
+		}
+	};
+
+	ret = i2c_transfer(priv->i2c, msg, 2);
+	if (ret == 2) {
+		memcpy(val, buf, len);
+		ret = 0;
+	} else {
+		warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+
+	return ret;
+}
+
+/* write multiple registers */
+int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
+	int len)
+{
+	int ret;
+	u8 i2c_addr;
+	u8 reg = (reginfo >> 0) & 0xff;
+	u8 bank = (reginfo >> 8) & 0xff;
+	u8 i2c = (reginfo >> 16) & 0x01;
+
+	/* select I2C */
+	if (i2c)
+		i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */
+	else
+		i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */
+
+	/* switch bank if needed */
+	if (bank != priv->bank[i2c]) {
+		ret = cxd2820r_wr_regs_i2c(priv, i2c_addr, 0x00, &bank, 1);
+		if (ret)
+			return ret;
+		priv->bank[i2c] = bank;
+	}
+	return cxd2820r_wr_regs_i2c(priv, i2c_addr, reg, val, len);
+}
+
+/* read multiple registers */
+int cxd2820r_rd_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
+	int len)
+{
+	int ret;
+	u8 i2c_addr;
+	u8 reg = (reginfo >> 0) & 0xff;
+	u8 bank = (reginfo >> 8) & 0xff;
+	u8 i2c = (reginfo >> 16) & 0x01;
+
+	/* select I2C */
+	if (i2c)
+		i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */
+	else
+		i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */
+
+	/* switch bank if needed */
+	if (bank != priv->bank[i2c]) {
+		ret = cxd2820r_wr_regs_i2c(priv, i2c_addr, 0x00, &bank, 1);
+		if (ret)
+			return ret;
+		priv->bank[i2c] = bank;
+	}
+	return cxd2820r_rd_regs_i2c(priv, i2c_addr, reg, val, len);
+}
+
+/* write single register */
+int cxd2820r_wr_reg(struct cxd2820r_priv *priv, u32 reg, u8 val)
+{
+	return cxd2820r_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val)
+{
+	return cxd2820r_rd_regs(priv, reg, val, 1);
+}
+
+/* write single register with mask */
+int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val,
+	u8 mask)
+{
+	int ret;
+	u8 tmp;
+
+	/* no need for read if whole reg is written */
+	if (mask != 0xff) {
+		ret = cxd2820r_rd_reg(priv, reg, &tmp);
+		if (ret)
+			return ret;
+
+		val &= mask;
+		tmp &= ~mask;
+		val |= tmp;
+	}
+
+	return cxd2820r_wr_reg(priv, reg, val);
+}
+
+int cxd2820r_gpio(struct dvb_frontend *fe)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret, i;
+	u8 *gpio, tmp0, tmp1;
+	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+	switch (fe->dtv_property_cache.delivery_system) {
+	case SYS_DVBT:
+		gpio = priv->cfg.gpio_dvbt;
+		break;
+	case SYS_DVBT2:
+		gpio = priv->cfg.gpio_dvbt2;
+		break;
+	case SYS_DVBC_ANNEX_AC:
+		gpio = priv->cfg.gpio_dvbc;
+		break;
+	default:
+		ret = -EINVAL;
+		goto error;
+	}
+
+	/* update GPIOs only when needed */
+	if (!memcmp(gpio, priv->gpio, sizeof(priv->gpio)))
+		return 0;
+
+	tmp0 = 0x00;
+	tmp1 = 0x00;
+	for (i = 0; i < sizeof(priv->gpio); i++) {
+		/* enable / disable */
+		if (gpio[i] & CXD2820R_GPIO_E)
+			tmp0 |= (2 << 6) >> (2 * i);
+		else
+			tmp0 |= (1 << 6) >> (2 * i);
+
+		/* input / output */
+		if (gpio[i] & CXD2820R_GPIO_I)
+			tmp1 |= (1 << (3 + i));
+		else
+			tmp1 |= (0 << (3 + i));
+
+		/* high / low */
+		if (gpio[i] & CXD2820R_GPIO_H)
+			tmp1 |= (1 << (0 + i));
+		else
+			tmp1 |= (0 << (0 + i));
+
+		dbg("%s: GPIO i=%d %02x %02x", __func__, i, tmp0, tmp1);
+	}
+
+	dbg("%s: wr gpio=%02x %02x", __func__, tmp0, tmp1);
+
+	/* write bits [7:2] */
+	ret = cxd2820r_wr_reg_mask(priv, 0x00089, tmp0, 0xfc);
+	if (ret)
+		goto error;
+
+	/* write bits [5:0] */
+	ret = cxd2820r_wr_reg_mask(priv, 0x0008e, tmp1, 0x3f);
+	if (ret)
+		goto error;
+
+	memcpy(priv->gpio, gpio, sizeof(priv->gpio));
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+/* 64 bit div with round closest, like DIV_ROUND_CLOSEST but 64 bit */
+u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor)
+{
+	return div_u64(dividend + (divisor / 2), divisor);
+}
+
+static int cxd2820r_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret;
+
+	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+	switch (c->delivery_system) {
+	case SYS_DVBT:
+		ret = cxd2820r_init_t(fe);
+		if (ret < 0)
+			goto err;
+		ret = cxd2820r_set_frontend_t(fe);
+		if (ret < 0)
+			goto err;
+		break;
+	case SYS_DVBT2:
+		ret = cxd2820r_init_t(fe);
+		if (ret < 0)
+			goto err;
+		ret = cxd2820r_set_frontend_t2(fe);
+		if (ret < 0)
+			goto err;
+		break;
+	case SYS_DVBC_ANNEX_A:
+		ret = cxd2820r_init_c(fe);
+		if (ret < 0)
+			goto err;
+		ret = cxd2820r_set_frontend_c(fe);
+		if (ret < 0)
+			goto err;
+		break;
+	default:
+		dbg("%s: error state=%d", __func__, fe->dtv_property_cache.delivery_system);
+		ret = -EINVAL;
+		break;
+	}
+err:
+	return ret;
+}
+static int cxd2820r_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	int ret;
+
+	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+	switch (fe->dtv_property_cache.delivery_system) {
+	case SYS_DVBT:
+		ret = cxd2820r_read_status_t(fe, status);
+		break;
+	case SYS_DVBT2:
+		ret = cxd2820r_read_status_t2(fe, status);
+		break;
+	case SYS_DVBC_ANNEX_A:
+		ret = cxd2820r_read_status_c(fe, status);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int cxd2820r_get_frontend(struct dvb_frontend *fe)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret;
+
+	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+	if (priv->delivery_system == SYS_UNDEFINED)
+		return 0;
+
+	switch (fe->dtv_property_cache.delivery_system) {
+	case SYS_DVBT:
+		ret = cxd2820r_get_frontend_t(fe);
+		break;
+	case SYS_DVBT2:
+		ret = cxd2820r_get_frontend_t2(fe);
+		break;
+	case SYS_DVBC_ANNEX_A:
+		ret = cxd2820r_get_frontend_c(fe);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int cxd2820r_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	int ret;
+
+	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+	switch (fe->dtv_property_cache.delivery_system) {
+	case SYS_DVBT:
+		ret = cxd2820r_read_ber_t(fe, ber);
+		break;
+	case SYS_DVBT2:
+		ret = cxd2820r_read_ber_t2(fe, ber);
+		break;
+	case SYS_DVBC_ANNEX_A:
+		ret = cxd2820r_read_ber_c(fe, ber);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int cxd2820r_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	int ret;
+
+	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+	switch (fe->dtv_property_cache.delivery_system) {
+	case SYS_DVBT:
+		ret = cxd2820r_read_signal_strength_t(fe, strength);
+		break;
+	case SYS_DVBT2:
+		ret = cxd2820r_read_signal_strength_t2(fe, strength);
+		break;
+	case SYS_DVBC_ANNEX_A:
+		ret = cxd2820r_read_signal_strength_c(fe, strength);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int cxd2820r_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	int ret;
+
+	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+	switch (fe->dtv_property_cache.delivery_system) {
+	case SYS_DVBT:
+		ret = cxd2820r_read_snr_t(fe, snr);
+		break;
+	case SYS_DVBT2:
+		ret = cxd2820r_read_snr_t2(fe, snr);
+		break;
+	case SYS_DVBC_ANNEX_A:
+		ret = cxd2820r_read_snr_c(fe, snr);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int cxd2820r_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	int ret;
+
+	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+	switch (fe->dtv_property_cache.delivery_system) {
+	case SYS_DVBT:
+		ret = cxd2820r_read_ucblocks_t(fe, ucblocks);
+		break;
+	case SYS_DVBT2:
+		ret = cxd2820r_read_ucblocks_t2(fe, ucblocks);
+		break;
+	case SYS_DVBC_ANNEX_A:
+		ret = cxd2820r_read_ucblocks_c(fe, ucblocks);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int cxd2820r_init(struct dvb_frontend *fe)
+{
+	return 0;
+}
+
+static int cxd2820r_sleep(struct dvb_frontend *fe)
+{
+	int ret;
+
+	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+	switch (fe->dtv_property_cache.delivery_system) {
+	case SYS_DVBT:
+		ret = cxd2820r_sleep_t(fe);
+		break;
+	case SYS_DVBT2:
+		ret = cxd2820r_sleep_t2(fe);
+		break;
+	case SYS_DVBC_ANNEX_A:
+		ret = cxd2820r_sleep_c(fe);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int cxd2820r_get_tune_settings(struct dvb_frontend *fe,
+				      struct dvb_frontend_tune_settings *s)
+{
+	int ret;
+
+	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+	switch (fe->dtv_property_cache.delivery_system) {
+	case SYS_DVBT:
+		ret = cxd2820r_get_tune_settings_t(fe, s);
+		break;
+	case SYS_DVBT2:
+		ret = cxd2820r_get_tune_settings_t2(fe, s);
+		break;
+	case SYS_DVBC_ANNEX_A:
+		ret = cxd2820r_get_tune_settings_c(fe, s);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i;
+	fe_status_t status = 0;
+	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+	/* switch between DVB-T and DVB-T2 when tune fails */
+	if (priv->last_tune_failed) {
+		if (priv->delivery_system == SYS_DVBT) {
+			ret = cxd2820r_sleep_t(fe);
+			if (ret)
+				goto error;
+
+			c->delivery_system = SYS_DVBT2;
+		} else if (priv->delivery_system == SYS_DVBT2) {
+			ret = cxd2820r_sleep_t2(fe);
+			if (ret)
+				goto error;
+
+			c->delivery_system = SYS_DVBT;
+		}
+	}
+
+	/* set frontend */
+	ret = cxd2820r_set_frontend(fe);
+	if (ret)
+		goto error;
+
+
+	/* frontend lock wait loop count */
+	switch (priv->delivery_system) {
+	case SYS_DVBT:
+	case SYS_DVBC_ANNEX_A:
+		i = 20;
+		break;
+	case SYS_DVBT2:
+		i = 40;
+		break;
+	case SYS_UNDEFINED:
+	default:
+		i = 0;
+		break;
+	}
+
+	/* wait frontend lock */
+	for (; i > 0; i--) {
+		dbg("%s: LOOP=%d", __func__, i);
+		msleep(50);
+		ret = cxd2820r_read_status(fe, &status);
+		if (ret)
+			goto error;
+
+		if (status & FE_HAS_LOCK)
+			break;
+	}
+
+	/* check if we have a valid signal */
+	if (status & FE_HAS_LOCK) {
+		priv->last_tune_failed = 0;
+		return DVBFE_ALGO_SEARCH_SUCCESS;
+	} else {
+		priv->last_tune_failed = 1;
+		return DVBFE_ALGO_SEARCH_AGAIN;
+	}
+
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return DVBFE_ALGO_SEARCH_ERROR;
+}
+
+static int cxd2820r_get_frontend_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_CUSTOM;
+}
+
+static void cxd2820r_release(struct dvb_frontend *fe)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	dbg("%s", __func__);
+
+	kfree(priv);
+	return;
+}
+
+static int cxd2820r_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	dbg("%s: %d", __func__, enable);
+
+	/* Bit 0 of reg 0xdb in bank 0x00 controls I2C repeater */
+	return cxd2820r_wr_reg_mask(priv, 0xdb, enable ? 1 : 0, 0x1);
+}
+
+static const struct dvb_frontend_ops cxd2820r_ops = {
+	.delsys = { SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A },
+	/* default: DVB-T/T2 */
+	.info = {
+		.name = "Sony CXD2820R",
+
+		.caps =	FE_CAN_FEC_1_2			|
+			FE_CAN_FEC_2_3			|
+			FE_CAN_FEC_3_4			|
+			FE_CAN_FEC_5_6			|
+			FE_CAN_FEC_7_8			|
+			FE_CAN_FEC_AUTO			|
+			FE_CAN_QPSK			|
+			FE_CAN_QAM_16			|
+			FE_CAN_QAM_32			|
+			FE_CAN_QAM_64			|
+			FE_CAN_QAM_128			|
+			FE_CAN_QAM_256			|
+			FE_CAN_QAM_AUTO			|
+			FE_CAN_TRANSMISSION_MODE_AUTO	|
+			FE_CAN_GUARD_INTERVAL_AUTO	|
+			FE_CAN_HIERARCHY_AUTO		|
+			FE_CAN_MUTE_TS			|
+			FE_CAN_2G_MODULATION
+		},
+
+	.release		= cxd2820r_release,
+	.init			= cxd2820r_init,
+	.sleep			= cxd2820r_sleep,
+
+	.get_tune_settings	= cxd2820r_get_tune_settings,
+	.i2c_gate_ctrl		= cxd2820r_i2c_gate_ctrl,
+
+	.get_frontend		= cxd2820r_get_frontend,
+
+	.get_frontend_algo	= cxd2820r_get_frontend_algo,
+	.search			= cxd2820r_search,
+
+	.read_status		= cxd2820r_read_status,
+	.read_snr		= cxd2820r_read_snr,
+	.read_ber		= cxd2820r_read_ber,
+	.read_ucblocks		= cxd2820r_read_ucblocks,
+	.read_signal_strength	= cxd2820r_read_signal_strength,
+};
+
+struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg,
+		struct i2c_adapter *i2c)
+{
+	struct cxd2820r_priv *priv = NULL;
+	int ret;
+	u8 tmp;
+
+	priv = kzalloc(sizeof (struct cxd2820r_priv), GFP_KERNEL);
+	if (!priv)
+		goto error;
+
+	priv->i2c = i2c;
+	memcpy(&priv->cfg, cfg, sizeof (struct cxd2820r_config));
+
+	priv->bank[0] = priv->bank[1] = 0xff;
+	ret = cxd2820r_rd_reg(priv, 0x000fd, &tmp);
+	dbg("%s: chip id=%02x", __func__, tmp);
+	if (ret || tmp != 0xe1)
+		goto error;
+
+	memcpy(&priv->fe.ops, &cxd2820r_ops, sizeof (struct dvb_frontend_ops));
+	priv->fe.demodulator_priv = priv;
+	return &priv->fe;
+error:
+	kfree(priv);
+	return NULL;
+}
+EXPORT_SYMBOL(cxd2820r_attach);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Sony CXD2820R demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/cxd2820r_priv.h b/drivers/media/dvb-frontends/cxd2820r_priv.h
new file mode 100644
index 0000000..9a9822c
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2820r_priv.h
@@ -0,0 +1,156 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#ifndef CXD2820R_PRIV_H
+#define CXD2820R_PRIV_H
+
+#include <linux/dvb/version.h>
+#include "dvb_frontend.h"
+#include "dvb_math.h"
+#include "cxd2820r.h"
+
+#define LOG_PREFIX "cxd2820r"
+
+#undef dbg
+#define dbg(f, arg...) \
+	if (cxd2820r_debug) \
+		printk(KERN_INFO   LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct reg_val_mask {
+	u32 reg;
+	u8  val;
+	u8  mask;
+};
+
+struct cxd2820r_priv {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend fe;
+	struct cxd2820r_config cfg;
+
+	bool ber_running;
+
+	u8 bank[2];
+	u8 gpio[3];
+
+	fe_delivery_system_t delivery_system;
+	bool last_tune_failed; /* for switch between T and T2 tune */
+};
+
+/* cxd2820r_core.c */
+
+extern int cxd2820r_debug;
+
+int cxd2820r_gpio(struct dvb_frontend *fe);
+
+int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val,
+	u8 mask);
+
+int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
+	int len);
+
+u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor);
+
+int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
+	int len);
+
+int cxd2820r_rd_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
+	int len);
+
+int cxd2820r_wr_reg(struct cxd2820r_priv *priv, u32 reg, u8 val);
+
+int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val);
+
+/* cxd2820r_c.c */
+
+int cxd2820r_get_frontend_c(struct dvb_frontend *fe);
+
+int cxd2820r_set_frontend_c(struct dvb_frontend *fe);
+
+int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status);
+
+int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber);
+
+int cxd2820r_read_signal_strength_c(struct dvb_frontend *fe, u16 *strength);
+
+int cxd2820r_read_snr_c(struct dvb_frontend *fe, u16 *snr);
+
+int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks);
+
+int cxd2820r_init_c(struct dvb_frontend *fe);
+
+int cxd2820r_sleep_c(struct dvb_frontend *fe);
+
+int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *s);
+
+/* cxd2820r_t.c */
+
+int cxd2820r_get_frontend_t(struct dvb_frontend *fe);
+
+int cxd2820r_set_frontend_t(struct dvb_frontend *fe);
+
+int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status);
+
+int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber);
+
+int cxd2820r_read_signal_strength_t(struct dvb_frontend *fe, u16 *strength);
+
+int cxd2820r_read_snr_t(struct dvb_frontend *fe, u16 *snr);
+
+int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks);
+
+int cxd2820r_init_t(struct dvb_frontend *fe);
+
+int cxd2820r_sleep_t(struct dvb_frontend *fe);
+
+int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *s);
+
+/* cxd2820r_t2.c */
+
+int cxd2820r_get_frontend_t2(struct dvb_frontend *fe);
+
+int cxd2820r_set_frontend_t2(struct dvb_frontend *fe);
+
+int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status);
+
+int cxd2820r_read_ber_t2(struct dvb_frontend *fe, u32 *ber);
+
+int cxd2820r_read_signal_strength_t2(struct dvb_frontend *fe, u16 *strength);
+
+int cxd2820r_read_snr_t2(struct dvb_frontend *fe, u16 *snr);
+
+int cxd2820r_read_ucblocks_t2(struct dvb_frontend *fe, u32 *ucblocks);
+
+int cxd2820r_init_t2(struct dvb_frontend *fe);
+
+int cxd2820r_sleep_t2(struct dvb_frontend *fe);
+
+int cxd2820r_get_tune_settings_t2(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *s);
+
+#endif /* CXD2820R_PRIV_H */
diff --git a/drivers/media/dvb-frontends/cxd2820r_t.c b/drivers/media/dvb-frontends/cxd2820r_t.c
new file mode 100644
index 0000000..e5dd22b
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2820r_t.c
@@ -0,0 +1,452 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include "cxd2820r_priv.h"
+
+int cxd2820r_set_frontend_t(struct dvb_frontend *fe)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i, bw_i;
+	u32 if_freq, if_ctl;
+	u64 num;
+	u8 buf[3], bw_param;
+	u8 bw_params1[][5] = {
+		{ 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */
+		{ 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */
+		{ 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */
+	};
+	u8 bw_params2[][2] = {
+		{ 0x1f, 0xdc }, /* 6 MHz */
+		{ 0x12, 0xf8 }, /* 7 MHz */
+		{ 0x01, 0xe0 }, /* 8 MHz */
+	};
+	struct reg_val_mask tab[] = {
+		{ 0x00080, 0x00, 0xff },
+		{ 0x00081, 0x03, 0xff },
+		{ 0x00085, 0x07, 0xff },
+		{ 0x00088, 0x01, 0xff },
+
+		{ 0x00070, priv->cfg.ts_mode, 0xff },
+		{ 0x000cb, priv->cfg.if_agc_polarity << 6, 0x40 },
+		{ 0x000a5, 0x00, 0x01 },
+		{ 0x00082, 0x20, 0x60 },
+		{ 0x000c2, 0xc3, 0xff },
+		{ 0x0016a, 0x50, 0xff },
+		{ 0x00427, 0x41, 0xff },
+	};
+
+	dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz);
+
+	switch (c->bandwidth_hz) {
+	case 6000000:
+		bw_i = 0;
+		bw_param = 2;
+		break;
+	case 7000000:
+		bw_i = 1;
+		bw_param = 1;
+		break;
+	case 8000000:
+		bw_i = 2;
+		bw_param = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* update GPIOs */
+	ret = cxd2820r_gpio(fe);
+	if (ret)
+		goto error;
+
+	/* program tuner */
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+
+	if (priv->delivery_system != SYS_DVBT) {
+		for (i = 0; i < ARRAY_SIZE(tab); i++) {
+			ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
+				tab[i].val, tab[i].mask);
+			if (ret)
+				goto error;
+		}
+	}
+
+	priv->delivery_system = SYS_DVBT;
+	priv->ber_running = 0; /* tune stops BER counter */
+
+	/* program IF frequency */
+	if (fe->ops.tuner_ops.get_if_frequency) {
+		ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
+		if (ret)
+			goto error;
+	} else
+		if_freq = 0;
+
+	dbg("%s: if_freq=%d", __func__, if_freq);
+
+	num = if_freq / 1000; /* Hz => kHz */
+	num *= 0x1000000;
+	if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
+	buf[0] = ((if_ctl >> 16) & 0xff);
+	buf[1] = ((if_ctl >>  8) & 0xff);
+	buf[2] = ((if_ctl >>  0) & 0xff);
+
+	ret = cxd2820r_wr_regs(priv, 0x000b6, buf, 3);
+	if (ret)
+		goto error;
+
+	ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[bw_i], 5);
+	if (ret)
+		goto error;
+
+	ret = cxd2820r_wr_reg_mask(priv, 0x000d7, bw_param << 6, 0xc0);
+	if (ret)
+		goto error;
+
+	ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[bw_i], 2);
+	if (ret)
+		goto error;
+
+	ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
+	if (ret)
+		goto error;
+
+	ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
+	if (ret)
+		goto error;
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_get_frontend_t(struct dvb_frontend *fe)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret;
+	u8 buf[2];
+
+	ret = cxd2820r_rd_regs(priv, 0x0002f, buf, sizeof(buf));
+	if (ret)
+		goto error;
+
+	switch ((buf[0] >> 6) & 0x03) {
+	case 0:
+		c->modulation = QPSK;
+		break;
+	case 1:
+		c->modulation = QAM_16;
+		break;
+	case 2:
+		c->modulation = QAM_64;
+		break;
+	}
+
+	switch ((buf[1] >> 1) & 0x03) {
+	case 0:
+		c->transmission_mode = TRANSMISSION_MODE_2K;
+		break;
+	case 1:
+		c->transmission_mode = TRANSMISSION_MODE_8K;
+		break;
+	}
+
+	switch ((buf[1] >> 3) & 0x03) {
+	case 0:
+		c->guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		c->guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		c->guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		c->guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	}
+
+	switch ((buf[0] >> 3) & 0x07) {
+	case 0:
+		c->hierarchy = HIERARCHY_NONE;
+		break;
+	case 1:
+		c->hierarchy = HIERARCHY_1;
+		break;
+	case 2:
+		c->hierarchy = HIERARCHY_2;
+		break;
+	case 3:
+		c->hierarchy = HIERARCHY_4;
+		break;
+	}
+
+	switch ((buf[0] >> 0) & 0x07) {
+	case 0:
+		c->code_rate_HP = FEC_1_2;
+		break;
+	case 1:
+		c->code_rate_HP = FEC_2_3;
+		break;
+	case 2:
+		c->code_rate_HP = FEC_3_4;
+		break;
+	case 3:
+		c->code_rate_HP = FEC_5_6;
+		break;
+	case 4:
+		c->code_rate_HP = FEC_7_8;
+		break;
+	}
+
+	switch ((buf[1] >> 5) & 0x07) {
+	case 0:
+		c->code_rate_LP = FEC_1_2;
+		break;
+	case 1:
+		c->code_rate_LP = FEC_2_3;
+		break;
+	case 2:
+		c->code_rate_LP = FEC_3_4;
+		break;
+	case 3:
+		c->code_rate_LP = FEC_5_6;
+		break;
+	case 4:
+		c->code_rate_LP = FEC_7_8;
+		break;
+	}
+
+	ret = cxd2820r_rd_reg(priv, 0x007c6, &buf[0]);
+	if (ret)
+		goto error;
+
+	switch ((buf[0] >> 0) & 0x01) {
+	case 0:
+		c->inversion = INVERSION_OFF;
+		break;
+	case 1:
+		c->inversion = INVERSION_ON;
+		break;
+	}
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 buf[3], start_ber = 0;
+	*ber = 0;
+
+	if (priv->ber_running) {
+		ret = cxd2820r_rd_regs(priv, 0x00076, buf, sizeof(buf));
+		if (ret)
+			goto error;
+
+		if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) {
+			*ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0];
+			start_ber = 1;
+		}
+	} else {
+		priv->ber_running = 1;
+		start_ber = 1;
+	}
+
+	if (start_ber) {
+		/* (re)start BER */
+		ret = cxd2820r_wr_reg(priv, 0x00079, 0x01);
+		if (ret)
+			goto error;
+	}
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_read_signal_strength_t(struct dvb_frontend *fe,
+	u16 *strength)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 buf[2];
+	u16 tmp;
+
+	ret = cxd2820r_rd_regs(priv, 0x00026, buf, sizeof(buf));
+	if (ret)
+		goto error;
+
+	tmp = (buf[0] & 0x0f) << 8 | buf[1];
+	tmp = ~tmp & 0x0fff;
+
+	/* scale value to 0x0000-0xffff from 0x0000-0x0fff */
+	*strength = tmp * 0xffff / 0x0fff;
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_read_snr_t(struct dvb_frontend *fe, u16 *snr)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 buf[2];
+	u16 tmp;
+	/* report SNR in dB * 10 */
+
+	ret = cxd2820r_rd_regs(priv, 0x00028, buf, sizeof(buf));
+	if (ret)
+		goto error;
+
+	tmp = (buf[0] & 0x1f) << 8 | buf[1];
+	#define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */
+	if (tmp)
+		*snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24)
+			/ 100);
+	else
+		*snr = 0;
+
+	dbg("%s: dBx10=%d val=%04x", __func__, *snr, tmp);
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	*ucblocks = 0;
+	/* no way to read ? */
+	return 0;
+}
+
+int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 buf[4];
+	*status = 0;
+
+	ret = cxd2820r_rd_reg(priv, 0x00010, &buf[0]);
+	if (ret)
+		goto error;
+
+	if ((buf[0] & 0x07) == 6) {
+		ret = cxd2820r_rd_reg(priv, 0x00073, &buf[1]);
+		if (ret)
+			goto error;
+
+		if (((buf[1] >> 3) & 0x01) == 1) {
+			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+		} else {
+			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI | FE_HAS_SYNC;
+		}
+	} else {
+		ret = cxd2820r_rd_reg(priv, 0x00014, &buf[2]);
+		if (ret)
+			goto error;
+
+		if ((buf[2] & 0x0f) >= 4) {
+			ret = cxd2820r_rd_reg(priv, 0x00a14, &buf[3]);
+			if (ret)
+				goto error;
+
+			if (((buf[3] >> 4) & 0x01) == 1)
+				*status |= FE_HAS_SIGNAL;
+		}
+	}
+
+	dbg("%s: lock=%*ph", __func__, 4, buf);
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_init_t(struct dvb_frontend *fe)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret;
+
+	ret = cxd2820r_wr_reg(priv, 0x00085, 0x07);
+	if (ret)
+		goto error;
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_sleep_t(struct dvb_frontend *fe)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret, i;
+	struct reg_val_mask tab[] = {
+		{ 0x000ff, 0x1f, 0xff },
+		{ 0x00085, 0x00, 0xff },
+		{ 0x00088, 0x01, 0xff },
+		{ 0x00081, 0x00, 0xff },
+		{ 0x00080, 0x00, 0xff },
+	};
+
+	dbg("%s", __func__);
+
+	priv->delivery_system = SYS_UNDEFINED;
+
+	for (i = 0; i < ARRAY_SIZE(tab); i++) {
+		ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
+			tab[i].mask);
+		if (ret)
+			goto error;
+	}
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *s)
+{
+	s->min_delay_ms = 500;
+	s->step_size = fe->ops.info.frequency_stepsize * 2;
+	s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+
+	return 0;
+}
diff --git a/drivers/media/dvb-frontends/cxd2820r_t2.c b/drivers/media/dvb-frontends/cxd2820r_t2.c
new file mode 100644
index 0000000..3a5759e
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2820r_t2.c
@@ -0,0 +1,426 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include "cxd2820r_priv.h"
+
+int cxd2820r_set_frontend_t2(struct dvb_frontend *fe)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i, bw_i;
+	u32 if_freq, if_ctl;
+	u64 num;
+	u8 buf[3], bw_param;
+	u8 bw_params1[][5] = {
+		{ 0x1c, 0xb3, 0x33, 0x33, 0x33 }, /* 5 MHz */
+		{ 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */
+		{ 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */
+		{ 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */
+	};
+	struct reg_val_mask tab[] = {
+		{ 0x00080, 0x02, 0xff },
+		{ 0x00081, 0x20, 0xff },
+		{ 0x00085, 0x07, 0xff },
+		{ 0x00088, 0x01, 0xff },
+		{ 0x02069, 0x01, 0xff },
+
+		{ 0x0207f, 0x2a, 0xff },
+		{ 0x02082, 0x0a, 0xff },
+		{ 0x02083, 0x0a, 0xff },
+		{ 0x020cb, priv->cfg.if_agc_polarity << 6, 0x40 },
+		{ 0x02070, priv->cfg.ts_mode, 0xff },
+		{ 0x020b5, priv->cfg.spec_inv << 4, 0x10 },
+		{ 0x02567, 0x07, 0x0f },
+		{ 0x02569, 0x03, 0x03 },
+		{ 0x02595, 0x1a, 0xff },
+		{ 0x02596, 0x50, 0xff },
+		{ 0x02a8c, 0x00, 0xff },
+		{ 0x02a8d, 0x34, 0xff },
+		{ 0x02a45, 0x06, 0x07 },
+		{ 0x03f10, 0x0d, 0xff },
+		{ 0x03f11, 0x02, 0xff },
+		{ 0x03f12, 0x01, 0xff },
+		{ 0x03f23, 0x2c, 0xff },
+		{ 0x03f51, 0x13, 0xff },
+		{ 0x03f52, 0x01, 0xff },
+		{ 0x03f53, 0x00, 0xff },
+		{ 0x027e6, 0x14, 0xff },
+		{ 0x02786, 0x02, 0x07 },
+		{ 0x02787, 0x40, 0xe0 },
+		{ 0x027ef, 0x10, 0x18 },
+	};
+
+	dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz);
+
+	switch (c->bandwidth_hz) {
+	case 5000000:
+		bw_i = 0;
+		bw_param = 3;
+		break;
+	case 6000000:
+		bw_i = 1;
+		bw_param = 2;
+		break;
+	case 7000000:
+		bw_i = 2;
+		bw_param = 1;
+		break;
+	case 8000000:
+		bw_i = 3;
+		bw_param = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* update GPIOs */
+	ret = cxd2820r_gpio(fe);
+	if (ret)
+		goto error;
+
+	/* program tuner */
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+
+	if (priv->delivery_system != SYS_DVBT2) {
+		for (i = 0; i < ARRAY_SIZE(tab); i++) {
+			ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
+				tab[i].val, tab[i].mask);
+			if (ret)
+				goto error;
+		}
+	}
+
+	priv->delivery_system = SYS_DVBT2;
+
+	/* program IF frequency */
+	if (fe->ops.tuner_ops.get_if_frequency) {
+		ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
+		if (ret)
+			goto error;
+	} else
+		if_freq = 0;
+
+	dbg("%s: if_freq=%d", __func__, if_freq);
+
+	num = if_freq / 1000; /* Hz => kHz */
+	num *= 0x1000000;
+	if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
+	buf[0] = ((if_ctl >> 16) & 0xff);
+	buf[1] = ((if_ctl >>  8) & 0xff);
+	buf[2] = ((if_ctl >>  0) & 0xff);
+
+	ret = cxd2820r_wr_regs(priv, 0x020b6, buf, 3);
+	if (ret)
+		goto error;
+
+	ret = cxd2820r_wr_regs(priv, 0x0209f, bw_params1[bw_i], 5);
+	if (ret)
+		goto error;
+
+	ret = cxd2820r_wr_reg_mask(priv, 0x020d7, bw_param << 6, 0xc0);
+	if (ret)
+		goto error;
+
+	ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
+	if (ret)
+		goto error;
+
+	ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
+	if (ret)
+		goto error;
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+
+}
+
+int cxd2820r_get_frontend_t2(struct dvb_frontend *fe)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret;
+	u8 buf[2];
+
+	ret = cxd2820r_rd_regs(priv, 0x0205c, buf, 2);
+	if (ret)
+		goto error;
+
+	switch ((buf[0] >> 0) & 0x07) {
+	case 0:
+		c->transmission_mode = TRANSMISSION_MODE_2K;
+		break;
+	case 1:
+		c->transmission_mode = TRANSMISSION_MODE_8K;
+		break;
+	case 2:
+		c->transmission_mode = TRANSMISSION_MODE_4K;
+		break;
+	case 3:
+		c->transmission_mode = TRANSMISSION_MODE_1K;
+		break;
+	case 4:
+		c->transmission_mode = TRANSMISSION_MODE_16K;
+		break;
+	case 5:
+		c->transmission_mode = TRANSMISSION_MODE_32K;
+		break;
+	}
+
+	switch ((buf[1] >> 4) & 0x07) {
+	case 0:
+		c->guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		c->guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		c->guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		c->guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	case 4:
+		c->guard_interval = GUARD_INTERVAL_1_128;
+		break;
+	case 5:
+		c->guard_interval = GUARD_INTERVAL_19_128;
+		break;
+	case 6:
+		c->guard_interval = GUARD_INTERVAL_19_256;
+		break;
+	}
+
+	ret = cxd2820r_rd_regs(priv, 0x0225b, buf, 2);
+	if (ret)
+		goto error;
+
+	switch ((buf[0] >> 0) & 0x07) {
+	case 0:
+		c->fec_inner = FEC_1_2;
+		break;
+	case 1:
+		c->fec_inner = FEC_3_5;
+		break;
+	case 2:
+		c->fec_inner = FEC_2_3;
+		break;
+	case 3:
+		c->fec_inner = FEC_3_4;
+		break;
+	case 4:
+		c->fec_inner = FEC_4_5;
+		break;
+	case 5:
+		c->fec_inner = FEC_5_6;
+		break;
+	}
+
+	switch ((buf[1] >> 0) & 0x07) {
+	case 0:
+		c->modulation = QPSK;
+		break;
+	case 1:
+		c->modulation = QAM_16;
+		break;
+	case 2:
+		c->modulation = QAM_64;
+		break;
+	case 3:
+		c->modulation = QAM_256;
+		break;
+	}
+
+	ret = cxd2820r_rd_reg(priv, 0x020b5, &buf[0]);
+	if (ret)
+		goto error;
+
+	switch ((buf[0] >> 4) & 0x01) {
+	case 0:
+		c->inversion = INVERSION_OFF;
+		break;
+	case 1:
+		c->inversion = INVERSION_ON;
+		break;
+	}
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 buf[1];
+	*status = 0;
+
+	ret = cxd2820r_rd_reg(priv, 0x02010 , &buf[0]);
+	if (ret)
+		goto error;
+
+	if ((buf[0] & 0x07) == 6) {
+		if (((buf[0] >> 5) & 0x01) == 1) {
+			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+		} else {
+			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI | FE_HAS_SYNC;
+		}
+	}
+
+	dbg("%s: lock=%02x", __func__, buf[0]);
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_read_ber_t2(struct dvb_frontend *fe, u32 *ber)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 buf[4];
+	unsigned int errbits;
+	*ber = 0;
+	/* FIXME: correct calculation */
+
+	ret = cxd2820r_rd_regs(priv, 0x02039, buf, sizeof(buf));
+	if (ret)
+		goto error;
+
+	if ((buf[0] >> 4) & 0x01) {
+		errbits = (buf[0] & 0x0f) << 24 | buf[1] << 16 |
+			buf[2] << 8 | buf[3];
+
+		if (errbits)
+			*ber = errbits * 64 / 16588800;
+	}
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_read_signal_strength_t2(struct dvb_frontend *fe,
+	u16 *strength)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 buf[2];
+	u16 tmp;
+
+	ret = cxd2820r_rd_regs(priv, 0x02026, buf, sizeof(buf));
+	if (ret)
+		goto error;
+
+	tmp = (buf[0] & 0x0f) << 8 | buf[1];
+	tmp = ~tmp & 0x0fff;
+
+	/* scale value to 0x0000-0xffff from 0x0000-0x0fff */
+	*strength = tmp * 0xffff / 0x0fff;
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_read_snr_t2(struct dvb_frontend *fe, u16 *snr)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 buf[2];
+	u16 tmp;
+	/* report SNR in dB * 10 */
+
+	ret = cxd2820r_rd_regs(priv, 0x02028, buf, sizeof(buf));
+	if (ret)
+		goto error;
+
+	tmp = (buf[0] & 0x0f) << 8 | buf[1];
+	#define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */
+	if (tmp)
+		*snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24)
+			/ 100);
+	else
+		*snr = 0;
+
+	dbg("%s: dBx10=%d val=%04x", __func__, *snr, tmp);
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_read_ucblocks_t2(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	*ucblocks = 0;
+	/* no way to read ? */
+	return 0;
+}
+
+int cxd2820r_sleep_t2(struct dvb_frontend *fe)
+{
+	struct cxd2820r_priv *priv = fe->demodulator_priv;
+	int ret, i;
+	struct reg_val_mask tab[] = {
+		{ 0x000ff, 0x1f, 0xff },
+		{ 0x00085, 0x00, 0xff },
+		{ 0x00088, 0x01, 0xff },
+		{ 0x02069, 0x00, 0xff },
+		{ 0x00081, 0x00, 0xff },
+		{ 0x00080, 0x00, 0xff },
+	};
+
+	dbg("%s", __func__);
+
+	for (i = 0; i < ARRAY_SIZE(tab); i++) {
+		ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
+			tab[i].mask);
+		if (ret)
+			goto error;
+	}
+
+	priv->delivery_system = SYS_UNDEFINED;
+
+	return ret;
+error:
+	dbg("%s: failed:%d", __func__, ret);
+	return ret;
+}
+
+int cxd2820r_get_tune_settings_t2(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *s)
+{
+	s->min_delay_ms = 1500;
+	s->step_size = fe->ops.info.frequency_stepsize * 2;
+	s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+
+	return 0;
+}
diff --git a/drivers/media/dvb-frontends/dib0070.c b/drivers/media/dvb-frontends/dib0070.c
new file mode 100644
index 0000000..3b024bf
--- /dev/null
+++ b/drivers/media/dvb-frontends/dib0070.c
@@ -0,0 +1,780 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
+ *
+ * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * This code is more or less generated from another driver, please
+ * excuse some codingstyle oddities.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+#include "dvb_frontend.h"
+
+#include "dib0070.h"
+#include "dibx000_common.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { \
+	if (debug) { \
+		printk(KERN_DEBUG "DiB0070: "); \
+		printk(args); \
+		printk("\n"); \
+	} \
+} while (0)
+
+#define DIB0070_P1D  0x00
+#define DIB0070_P1F  0x01
+#define DIB0070_P1G  0x03
+#define DIB0070S_P1A 0x02
+
+struct dib0070_state {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend *fe;
+	const struct dib0070_config *cfg;
+	u16 wbd_ff_offset;
+	u8 revision;
+
+    enum frontend_tune_state tune_state;
+    u32 current_rf;
+
+    /* for the captrim binary search */
+	s8 step;
+	u16 adc_diff;
+
+	s8 captrim;
+	s8 fcaptrim;
+	u16 lo4;
+
+	const struct dib0070_tuning *current_tune_table_index;
+	const struct dib0070_lna_match *lna_match;
+
+    u8  wbd_gain_current;
+	u16 wbd_offset_3_3[2];
+
+	/* for the I2C transfer */
+	struct i2c_msg msg[2];
+	u8 i2c_write_buffer[3];
+	u8 i2c_read_buffer[2];
+	struct mutex i2c_buffer_lock;
+};
+
+static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg)
+{
+	u16 ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return 0;
+	}
+
+	state->i2c_write_buffer[0] = reg;
+
+	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+	state->msg[0].addr = state->cfg->i2c_address;
+	state->msg[0].flags = 0;
+	state->msg[0].buf = state->i2c_write_buffer;
+	state->msg[0].len = 1;
+	state->msg[1].addr = state->cfg->i2c_address;
+	state->msg[1].flags = I2C_M_RD;
+	state->msg[1].buf = state->i2c_read_buffer;
+	state->msg[1].len = 2;
+
+	if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
+		printk(KERN_WARNING "DiB0070 I2C read failed\n");
+		ret = 0;
+	} else
+		ret = (state->i2c_read_buffer[0] << 8)
+			| state->i2c_read_buffer[1];
+
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
+}
+
+static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
+{
+	int ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+	state->i2c_write_buffer[0] = reg;
+	state->i2c_write_buffer[1] = val >> 8;
+	state->i2c_write_buffer[2] = val & 0xff;
+
+	memset(state->msg, 0, sizeof(struct i2c_msg));
+	state->msg[0].addr = state->cfg->i2c_address;
+	state->msg[0].flags = 0;
+	state->msg[0].buf = state->i2c_write_buffer;
+	state->msg[0].len = 3;
+
+	if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
+		printk(KERN_WARNING "DiB0070 I2C write failed\n");
+		ret = -EREMOTEIO;
+	} else
+		ret = 0;
+
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
+}
+
+#define HARD_RESET(state) do { \
+    state->cfg->sleep(state->fe, 0); \
+    if (state->cfg->reset) { \
+	state->cfg->reset(state->fe,1); msleep(10); \
+	state->cfg->reset(state->fe,0); msleep(10); \
+    } \
+} while (0)
+
+static int dib0070_set_bandwidth(struct dvb_frontend *fe)
+{
+    struct dib0070_state *state = fe->tuner_priv;
+    u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff;
+
+    if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 7000)
+	tmp |= (0 << 14);
+    else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 6000)
+	tmp |= (1 << 14);
+    else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 5000)
+	tmp |= (2 << 14);
+    else
+	tmp |= (3 << 14);
+
+    dib0070_write_reg(state, 0x02, tmp);
+
+    /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */
+    if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) {
+	u16 value = dib0070_read_reg(state, 0x17);
+
+	dib0070_write_reg(state, 0x17, value & 0xfffc);
+	tmp = dib0070_read_reg(state, 0x01) & 0x01ff;
+	dib0070_write_reg(state, 0x01, tmp | (60 << 9));
+
+	dib0070_write_reg(state, 0x17, value);
+    }
+	return 0;
+}
+
+static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state *tune_state)
+{
+	int8_t step_sign;
+	u16 adc;
+	int ret = 0;
+
+	if (*tune_state == CT_TUNER_STEP_0) {
+
+		dib0070_write_reg(state, 0x0f, 0xed10);
+		dib0070_write_reg(state, 0x17,    0x0034);
+
+		dib0070_write_reg(state, 0x18, 0x0032);
+		state->step = state->captrim = state->fcaptrim = 64;
+		state->adc_diff = 3000;
+		ret = 20;
+
+	*tune_state = CT_TUNER_STEP_1;
+	} else if (*tune_state == CT_TUNER_STEP_1) {
+		state->step /= 2;
+		dib0070_write_reg(state, 0x14, state->lo4 | state->captrim);
+		ret = 15;
+
+		*tune_state = CT_TUNER_STEP_2;
+	} else if (*tune_state == CT_TUNER_STEP_2) {
+
+		adc = dib0070_read_reg(state, 0x19);
+
+		dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->captrim, adc, (u32) adc*(u32)1800/(u32)1024);
+
+		if (adc >= 400) {
+			adc -= 400;
+			step_sign = -1;
+		} else {
+			adc = 400 - adc;
+			step_sign = 1;
+		}
+
+		if (adc < state->adc_diff) {
+			dprintk("CAPTRIM=%hd is closer to target (%hd/%hd)", state->captrim, adc, state->adc_diff);
+			state->adc_diff = adc;
+			state->fcaptrim = state->captrim;
+
+
+
+		}
+		state->captrim += (step_sign * state->step);
+
+		if (state->step >= 1)
+			*tune_state = CT_TUNER_STEP_1;
+		else
+			*tune_state = CT_TUNER_STEP_3;
+
+	} else if (*tune_state == CT_TUNER_STEP_3) {
+		dib0070_write_reg(state, 0x14, state->lo4 | state->fcaptrim);
+		dib0070_write_reg(state, 0x18, 0x07ff);
+		*tune_state = CT_TUNER_STEP_4;
+	}
+
+	return ret;
+}
+
+static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt)
+{
+	struct dib0070_state *state = fe->tuner_priv;
+    u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
+	dprintk("CTRL_LO5: 0x%x", lo5);
+	return dib0070_write_reg(state, 0x15, lo5);
+}
+
+void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open)
+{
+	struct dib0070_state *state = fe->tuner_priv;
+
+	if (open) {
+		dib0070_write_reg(state, 0x1b, 0xff00);
+		dib0070_write_reg(state, 0x1a, 0x0000);
+	} else {
+		dib0070_write_reg(state, 0x1b, 0x4112);
+	if (state->cfg->vga_filter != 0) {
+		dib0070_write_reg(state, 0x1a, state->cfg->vga_filter);
+		dprintk("vga filter register is set to %x", state->cfg->vga_filter);
+	} else
+		dib0070_write_reg(state, 0x1a, 0x0009);
+	}
+}
+
+EXPORT_SYMBOL(dib0070_ctrl_agc_filter);
+struct dib0070_tuning {
+    u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
+    u8 switch_trim;
+    u8 vco_band;
+    u8 hfdiv;
+    u8 vco_multi;
+    u8 presc;
+    u8 wbdmux;
+    u16 tuner_enable;
+};
+
+struct dib0070_lna_match {
+    u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
+    u8 lna_band;
+};
+
+static const struct dib0070_tuning dib0070s_tuning_table[] = {
+    {     570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */
+    {     700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 },
+    {     863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 },
+    {    1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */
+    {    1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
+    {    2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
+    { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */
+};
+
+static const struct dib0070_tuning dib0070_tuning_table[] = {
+    {     115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */
+    {     179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */
+    {     189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 },
+    {     250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 },
+    {     569999, 2, 1, 5,  6, 2, 2, 0x4000 | 0x0800 }, /* UHF */
+    {     699999, 2, 0, 1,  4, 2, 2, 0x4000 | 0x0800 },
+    {     863999, 2, 1, 1,  4, 2, 2, 0x4000 | 0x0800 },
+    { 0xffffffff, 0, 1, 0,  2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */
+};
+
+static const struct dib0070_lna_match dib0070_lna_flip_chip[] = {
+    {     180000, 0 }, /* VHF */
+    {     188000, 1 },
+    {     196400, 2 },
+    {     250000, 3 },
+    {     550000, 0 }, /* UHF */
+    {     590000, 1 },
+    {     666000, 3 },
+    {     864000, 5 },
+    {    1500000, 0 }, /* LBAND or everything higher than UHF */
+    {    1600000, 1 },
+    {    2000000, 3 },
+    { 0xffffffff, 7 },
+};
+
+static const struct dib0070_lna_match dib0070_lna[] = {
+    {     180000, 0 }, /* VHF */
+    {     188000, 1 },
+    {     196400, 2 },
+    {     250000, 3 },
+    {     550000, 2 }, /* UHF */
+    {     650000, 3 },
+    {     750000, 5 },
+    {     850000, 6 },
+    {     864000, 7 },
+    {    1500000, 0 }, /* LBAND or everything higher than UHF */
+    {    1600000, 1 },
+    {    2000000, 3 },
+    { 0xffffffff, 7 },
+};
+
+#define LPF	100
+static int dib0070_tune_digital(struct dvb_frontend *fe)
+{
+    struct dib0070_state *state = fe->tuner_priv;
+
+    const struct dib0070_tuning *tune;
+    const struct dib0070_lna_match *lna_match;
+
+    enum frontend_tune_state *tune_state = &state->tune_state;
+    int ret = 10; /* 1ms is the default delay most of the time */
+
+    u8  band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000);
+    u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf);
+
+#ifdef CONFIG_SYS_ISDBT
+    if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1)
+		if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2)
+		     && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
+		    || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
+			&& (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2)))
+		    || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
+			&& (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))))
+			freq += 850;
+#endif
+    if (state->current_rf != freq) {
+
+	switch (state->revision) {
+	case DIB0070S_P1A:
+	    tune = dib0070s_tuning_table;
+	    lna_match = dib0070_lna;
+	    break;
+	default:
+	    tune = dib0070_tuning_table;
+	    if (state->cfg->flip_chip)
+		lna_match = dib0070_lna_flip_chip;
+	    else
+		lna_match = dib0070_lna;
+	    break;
+	}
+	while (freq > tune->max_freq) /* find the right one */
+	    tune++;
+	while (freq > lna_match->max_freq) /* find the right one */
+	    lna_match++;
+
+	state->current_tune_table_index = tune;
+	state->lna_match = lna_match;
+    }
+
+    if (*tune_state == CT_TUNER_START) {
+	dprintk("Tuning for Band: %hd (%d kHz)", band, freq);
+	if (state->current_rf != freq) {
+		u8 REFDIV;
+		u32 FBDiv, Rest, FREF, VCOF_kHz;
+		u8 Den;
+
+		state->current_rf = freq;
+		state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7);
+
+
+		dib0070_write_reg(state, 0x17, 0x30);
+
+
+		VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2;
+
+		switch (band) {
+		case BAND_VHF:
+			REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000);
+			break;
+		case BAND_FM:
+			REFDIV = (u8) ((state->cfg->clock_khz) / 1000);
+			break;
+		default:
+			REFDIV = (u8) (state->cfg->clock_khz  / 10000);
+			break;
+		}
+		FREF = state->cfg->clock_khz / REFDIV;
+
+
+
+		switch (state->revision) {
+		case DIB0070S_P1A:
+			FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF);
+			Rest  = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF;
+			break;
+
+		case DIB0070_P1G:
+		case DIB0070_P1F:
+		default:
+			FBDiv = (freq / (FREF / 2));
+			Rest  = 2 * freq - FBDiv * FREF;
+			break;
+		}
+
+		if (Rest < LPF)
+			Rest = 0;
+		else if (Rest < 2 * LPF)
+			Rest = 2 * LPF;
+		else if (Rest > (FREF - LPF)) {
+			Rest = 0;
+			FBDiv += 1;
+		} else if (Rest > (FREF - 2 * LPF))
+			Rest = FREF - 2 * LPF;
+		Rest = (Rest * 6528) / (FREF / 10);
+
+		Den = 1;
+		if (Rest > 0) {
+			state->lo4 |= (1 << 14) | (1 << 12);
+			Den = 255;
+		}
+
+
+		dib0070_write_reg(state, 0x11, (u16)FBDiv);
+		dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV);
+		dib0070_write_reg(state, 0x13, (u16) Rest);
+
+		if (state->revision == DIB0070S_P1A) {
+
+			if (band == BAND_SBAND) {
+				dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
+				dib0070_write_reg(state, 0x1d, 0xFFFF);
+			} else
+				dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1);
+		}
+
+		dib0070_write_reg(state, 0x20,
+			0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable);
+
+		dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF);
+		dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest);
+		dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1);
+		dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv);
+		dprintk("VCO = %hd", state->current_tune_table_index->vco_band);
+		dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq);
+
+		*tune_state = CT_TUNER_STEP_0;
+	} else { /* we are already tuned to this frequency - the configuration is correct  */
+		ret = 50; /* wakeup time */
+		*tune_state = CT_TUNER_STEP_5;
+	}
+    } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) {
+
+	ret = dib0070_captrim(state, tune_state);
+
+    } else if (*tune_state == CT_TUNER_STEP_4) {
+	const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
+	if (tmp != NULL) {
+		while (freq/1000 > tmp->freq) /* find the right one */
+			tmp++;
+		dib0070_write_reg(state, 0x0f,
+			(0 << 15) | (1 << 14) | (3 << 12)
+			| (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7)
+			| (state->current_tune_table_index->wbdmux << 0));
+		state->wbd_gain_current = tmp->wbd_gain_val;
+	} else {
+			dib0070_write_reg(state, 0x0f,
+					  (0 << 15) | (1 << 14) | (3 << 12) | (6 << 9) | (0 << 8) | (1 << 7) | (state->current_tune_table_index->
+														wbdmux << 0));
+	    state->wbd_gain_current = 6;
+	}
+
+	dib0070_write_reg(state, 0x06, 0x3fff);
+		dib0070_write_reg(state, 0x07,
+				  (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0));
+	dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127));
+	dib0070_write_reg(state, 0x0d, 0x0d80);
+
+
+	dib0070_write_reg(state, 0x18,   0x07ff);
+	dib0070_write_reg(state, 0x17, 0x0033);
+
+
+	*tune_state = CT_TUNER_STEP_5;
+    } else if (*tune_state == CT_TUNER_STEP_5) {
+	dib0070_set_bandwidth(fe);
+	*tune_state = CT_TUNER_STOP;
+    } else {
+	ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */
+    }
+    return ret;
+}
+
+
+static int dib0070_tune(struct dvb_frontend *fe)
+{
+    struct dib0070_state *state = fe->tuner_priv;
+    uint32_t ret;
+
+    state->tune_state = CT_TUNER_START;
+
+    do {
+	ret = dib0070_tune_digital(fe);
+	if (ret != FE_CALLBACK_TIME_NEVER)
+		msleep(ret/10);
+	else
+	    break;
+    } while (state->tune_state != CT_TUNER_STOP);
+
+    return 0;
+}
+
+static int dib0070_wakeup(struct dvb_frontend *fe)
+{
+	struct dib0070_state *state = fe->tuner_priv;
+	if (state->cfg->sleep)
+		state->cfg->sleep(fe, 0);
+	return 0;
+}
+
+static int dib0070_sleep(struct dvb_frontend *fe)
+{
+	struct dib0070_state *state = fe->tuner_priv;
+	if (state->cfg->sleep)
+		state->cfg->sleep(fe, 1);
+	return 0;
+}
+
+u8 dib0070_get_rf_output(struct dvb_frontend *fe)
+{
+	struct dib0070_state *state = fe->tuner_priv;
+	return (dib0070_read_reg(state, 0x07) >> 11) & 0x3;
+}
+EXPORT_SYMBOL(dib0070_get_rf_output);
+
+int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no)
+{
+	struct dib0070_state *state = fe->tuner_priv;
+	u16 rxrf2 = dib0070_read_reg(state, 0x07) & 0xfe7ff;
+	if (no > 3)
+		no = 3;
+	if (no < 1)
+		no = 1;
+	return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11));
+}
+EXPORT_SYMBOL(dib0070_set_rf_output);
+
+static const u16 dib0070_p1f_defaults[] =
+
+{
+	7, 0x02,
+		0x0008,
+		0x0000,
+		0x0000,
+		0x0000,
+		0x0000,
+		0x0002,
+		0x0100,
+
+	3, 0x0d,
+		0x0d80,
+		0x0001,
+		0x0000,
+
+	4, 0x11,
+		0x0000,
+		0x0103,
+		0x0000,
+		0x0000,
+
+	3, 0x16,
+		0x0004 | 0x0040,
+		0x0030,
+		0x07ff,
+
+	6, 0x1b,
+		0x4112,
+		0xff00,
+		0xc07f,
+		0x0000,
+		0x0180,
+		0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
+
+	0,
+};
+
+static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain)
+{
+    u16 tuner_en = dib0070_read_reg(state, 0x20);
+    u16 offset;
+
+    dib0070_write_reg(state, 0x18, 0x07ff);
+    dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
+    dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0));
+    msleep(9);
+    offset = dib0070_read_reg(state, 0x19);
+    dib0070_write_reg(state, 0x20, tuner_en);
+    return offset;
+}
+
+static void dib0070_wbd_offset_calibration(struct dib0070_state *state)
+{
+    u8 gain;
+    for (gain = 6; gain < 8; gain++) {
+	state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2);
+	dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain-6]);
+    }
+}
+
+u16 dib0070_wbd_offset(struct dvb_frontend *fe)
+{
+    struct dib0070_state *state = fe->tuner_priv;
+    const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
+    u32 freq = fe->dtv_property_cache.frequency/1000;
+
+    if (tmp != NULL) {
+	while (freq/1000 > tmp->freq) /* find the right one */
+	    tmp++;
+	state->wbd_gain_current = tmp->wbd_gain_val;
+	} else
+	state->wbd_gain_current = 6;
+
+    return state->wbd_offset_3_3[state->wbd_gain_current - 6];
+}
+EXPORT_SYMBOL(dib0070_wbd_offset);
+
+#define pgm_read_word(w) (*w)
+static int dib0070_reset(struct dvb_frontend *fe)
+{
+    struct dib0070_state *state = fe->tuner_priv;
+	u16 l, r, *n;
+
+	HARD_RESET(state);
+
+
+#ifndef FORCE_SBAND_TUNER
+	if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
+		state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
+	else
+#else
+#warning forcing SBAND
+#endif
+		state->revision = DIB0070S_P1A;
+
+	/* P1F or not */
+	dprintk("Revision: %x", state->revision);
+
+	if (state->revision == DIB0070_P1D) {
+		dprintk("Error: this driver is not to be used meant for P1D or earlier");
+		return -EINVAL;
+	}
+
+	n = (u16 *) dib0070_p1f_defaults;
+	l = pgm_read_word(n++);
+	while (l) {
+		r = pgm_read_word(n++);
+		do {
+			dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
+			r++;
+		} while (--l);
+		l = pgm_read_word(n++);
+	}
+
+	if (state->cfg->force_crystal_mode != 0)
+		r = state->cfg->force_crystal_mode;
+	else if (state->cfg->clock_khz >= 24000)
+		r = 1;
+	else
+		r = 2;
+
+
+	r |= state->cfg->osc_buffer_state << 3;
+
+	dib0070_write_reg(state, 0x10, r);
+	dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5));
+
+	if (state->cfg->invert_iq) {
+		r = dib0070_read_reg(state, 0x02) & 0xffdf;
+		dib0070_write_reg(state, 0x02, r | (1 << 5));
+	}
+
+    if (state->revision == DIB0070S_P1A)
+	dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
+    else
+		dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, state->cfg->enable_third_order_filter);
+
+	dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
+
+    dib0070_wbd_offset_calibration(state);
+
+    return 0;
+}
+
+static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+    struct dib0070_state *state = fe->tuner_priv;
+
+    *frequency = 1000 * state->current_rf;
+    return 0;
+}
+
+static int dib0070_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static const struct dvb_tuner_ops dib0070_ops = {
+	.info = {
+		.name           = "DiBcom DiB0070",
+		.frequency_min  =  45000000,
+		.frequency_max  = 860000000,
+		.frequency_step =      1000,
+	},
+	.release       = dib0070_release,
+
+	.init          = dib0070_wakeup,
+	.sleep         = dib0070_sleep,
+	.set_params    = dib0070_tune,
+
+	.get_frequency = dib0070_get_frequency,
+//      .get_bandwidth = dib0070_get_bandwidth
+};
+
+struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
+{
+	struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
+	if (state == NULL)
+		return NULL;
+
+	state->cfg = cfg;
+	state->i2c = i2c;
+	state->fe  = fe;
+	mutex_init(&state->i2c_buffer_lock);
+	fe->tuner_priv = state;
+
+	if (dib0070_reset(fe) != 0)
+		goto free_mem;
+
+	printk(KERN_INFO "DiB0070: successfully identified\n");
+	memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = state;
+	return fe;
+
+free_mem:
+	kfree(state);
+	fe->tuner_priv = NULL;
+	return NULL;
+}
+EXPORT_SYMBOL(dib0070_attach);
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/dib0070.h b/drivers/media/dvb-frontends/dib0070.h
new file mode 100644
index 0000000..45c31fa
--- /dev/null
+++ b/drivers/media/dvb-frontends/dib0070.h
@@ -0,0 +1,76 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
+ *
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
+ *
+ * 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, version 2.
+ */
+#ifndef DIB0070_H
+#define DIB0070_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+#define DEFAULT_DIB0070_I2C_ADDRESS 0x60
+
+struct dib0070_wbd_gain_cfg {
+	u16 freq;
+	u16 wbd_gain_val;
+};
+
+struct dib0070_config {
+	u8 i2c_address;
+
+	/* tuner pins controlled externally */
+	int (*reset) (struct dvb_frontend *, int);
+	int (*sleep) (struct dvb_frontend *, int);
+
+	/*  offset in kHz */
+	int freq_offset_khz_uhf;
+	int freq_offset_khz_vhf;
+
+	u8 osc_buffer_state;	/* 0= normal, 1= tri-state */
+	u32 clock_khz;
+	u8 clock_pad_drive;	/* (Drive + 1) * 2mA */
+
+	u8 invert_iq;		/* invert Q - in case I or Q is inverted on the board */
+
+	u8 force_crystal_mode;	/* if == 0 -> decision is made in the driver default: <24 -> 2, >=24 -> 1 */
+
+	u8 flip_chip;
+	u8 enable_third_order_filter;
+	u8 charge_pump;
+
+	const struct dib0070_wbd_gain_cfg *wbd_gain;
+
+	u8 vga_filter;
+};
+
+#if defined(CONFIG_DVB_TUNER_DIB0070) || (defined(CONFIG_DVB_TUNER_DIB0070_MODULE) && defined(MODULE))
+extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg);
+extern u16 dib0070_wbd_offset(struct dvb_frontend *);
+extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, u8 open);
+extern u8 dib0070_get_rf_output(struct dvb_frontend *fe);
+extern int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no);
+#else
+static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return 0;
+}
+
+static inline void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c
new file mode 100644
index 0000000..d9fe60b
--- /dev/null
+++ b/drivers/media/dvb-frontends/dib0090.c
@@ -0,0 +1,2686 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner.
+ *
+ * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * This code is more or less generated from another driver, please
+ * excuse some codingstyle oddities.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+#include "dvb_frontend.h"
+
+#include "dib0090.h"
+#include "dibx000_common.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { \
+	if (debug) { \
+		printk(KERN_DEBUG "DiB0090: "); \
+		printk(args); \
+		printk("\n"); \
+	} \
+} while (0)
+
+#define CONFIG_SYS_DVBT
+#define CONFIG_SYS_ISDBT
+#define CONFIG_BAND_CBAND
+#define CONFIG_BAND_VHF
+#define CONFIG_BAND_UHF
+#define CONFIG_DIB0090_USE_PWM_AGC
+
+#define EN_LNA0      0x8000
+#define EN_LNA1      0x4000
+#define EN_LNA2      0x2000
+#define EN_LNA3      0x1000
+#define EN_MIX0      0x0800
+#define EN_MIX1      0x0400
+#define EN_MIX2      0x0200
+#define EN_MIX3      0x0100
+#define EN_IQADC     0x0040
+#define EN_PLL       0x0020
+#define EN_TX        0x0010
+#define EN_BB        0x0008
+#define EN_LO        0x0004
+#define EN_BIAS      0x0001
+
+#define EN_IQANA     0x0002
+#define EN_DIGCLK    0x0080	/* not in the 0x24 reg, only in 0x1b */
+#define EN_CRYSTAL   0x0002
+
+#define EN_UHF		 0x22E9
+#define EN_VHF		 0x44E9
+#define EN_LBD		 0x11E9
+#define EN_SBD		 0x44E9
+#define EN_CAB		 0x88E9
+
+/* Calibration defines */
+#define      DC_CAL 0x1
+#define     WBD_CAL 0x2
+#define    TEMP_CAL 0x4
+#define CAPTRIM_CAL 0x8
+
+#define KROSUS_PLL_LOCKED   0x800
+#define KROSUS              0x2
+
+/* Use those defines to identify SOC version */
+#define SOC               0x02
+#define SOC_7090_P1G_11R1 0x82
+#define SOC_7090_P1G_21R1 0x8a
+#define SOC_8090_P1G_11R1 0x86
+#define SOC_8090_P1G_21R1 0x8e
+
+/* else use thos ones to check */
+#define P1A_B      0x0
+#define P1C	   0x1
+#define P1D_E_F    0x3
+#define P1G	   0x7
+#define P1G_21R2   0xf
+
+#define MP001 0x1		/* Single 9090/8096 */
+#define MP005 0x4		/* Single Sband */
+#define MP008 0x6		/* Dual diversity VHF-UHF-LBAND */
+#define MP009 0x7		/* Dual diversity 29098 CBAND-UHF-LBAND-SBAND */
+
+#define pgm_read_word(w) (*w)
+
+struct dc_calibration;
+
+struct dib0090_tuning {
+	u32 max_freq;		/* for every frequency less than or equal to that field: this information is correct */
+	u8 switch_trim;
+	u8 lna_tune;
+	u16 lna_bias;
+	u16 v2i;
+	u16 mix;
+	u16 load;
+	u16 tuner_enable;
+};
+
+struct dib0090_pll {
+	u32 max_freq;		/* for every frequency less than or equal to that field: this information is correct */
+	u8 vco_band;
+	u8 hfdiv_code;
+	u8 hfdiv;
+	u8 topresc;
+};
+
+struct dib0090_identity {
+	u8 version;
+	u8 product;
+	u8 p1g;
+	u8 in_soc;
+};
+
+struct dib0090_state {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend *fe;
+	const struct dib0090_config *config;
+
+	u8 current_band;
+	enum frontend_tune_state tune_state;
+	u32 current_rf;
+
+	u16 wbd_offset;
+	s16 wbd_target;		/* in dB */
+
+	s16 rf_gain_limit;	/* take-over-point: where to split between bb and rf gain */
+	s16 current_gain;	/* keeps the currently programmed gain */
+	u8 agc_step;		/* new binary search */
+
+	u16 gain[2];		/* for channel monitoring */
+
+	const u16 *rf_ramp;
+	const u16 *bb_ramp;
+
+	/* for the software AGC ramps */
+	u16 bb_1_def;
+	u16 rf_lt_def;
+	u16 gain_reg[4];
+
+	/* for the captrim/dc-offset search */
+	s8 step;
+	s16 adc_diff;
+	s16 min_adc_diff;
+
+	s8 captrim;
+	s8 fcaptrim;
+
+	const struct dc_calibration *dc;
+	u16 bb6, bb7;
+
+	const struct dib0090_tuning *current_tune_table_index;
+	const struct dib0090_pll *current_pll_table_index;
+
+	u8 tuner_is_tuned;
+	u8 agc_freeze;
+
+	struct dib0090_identity identity;
+
+	u32 rf_request;
+	u8 current_standard;
+
+	u8 calibrate;
+	u32 rest;
+	u16 bias;
+	s16 temperature;
+
+	u8 wbd_calibration_gain;
+	const struct dib0090_wbd_slope *current_wbd_table;
+	u16 wbdmux;
+
+	/* for the I2C transfer */
+	struct i2c_msg msg[2];
+	u8 i2c_write_buffer[3];
+	u8 i2c_read_buffer[2];
+	struct mutex i2c_buffer_lock;
+};
+
+struct dib0090_fw_state {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend *fe;
+	struct dib0090_identity identity;
+	const struct dib0090_config *config;
+
+	/* for the I2C transfer */
+	struct i2c_msg msg;
+	u8 i2c_write_buffer[2];
+	u8 i2c_read_buffer[2];
+	struct mutex i2c_buffer_lock;
+};
+
+static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
+{
+	u16 ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return 0;
+	}
+
+	state->i2c_write_buffer[0] = reg;
+
+	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+	state->msg[0].addr = state->config->i2c_address;
+	state->msg[0].flags = 0;
+	state->msg[0].buf = state->i2c_write_buffer;
+	state->msg[0].len = 1;
+	state->msg[1].addr = state->config->i2c_address;
+	state->msg[1].flags = I2C_M_RD;
+	state->msg[1].buf = state->i2c_read_buffer;
+	state->msg[1].len = 2;
+
+	if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
+		printk(KERN_WARNING "DiB0090 I2C read failed\n");
+		ret = 0;
+	} else
+		ret = (state->i2c_read_buffer[0] << 8)
+			| state->i2c_read_buffer[1];
+
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
+}
+
+static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
+{
+	int ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+
+	state->i2c_write_buffer[0] = reg & 0xff;
+	state->i2c_write_buffer[1] = val >> 8;
+	state->i2c_write_buffer[2] = val & 0xff;
+
+	memset(state->msg, 0, sizeof(struct i2c_msg));
+	state->msg[0].addr = state->config->i2c_address;
+	state->msg[0].flags = 0;
+	state->msg[0].buf = state->i2c_write_buffer;
+	state->msg[0].len = 3;
+
+	if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
+		printk(KERN_WARNING "DiB0090 I2C write failed\n");
+		ret = -EREMOTEIO;
+	} else
+		ret = 0;
+
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
+}
+
+static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
+{
+	u16 ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return 0;
+	}
+
+	state->i2c_write_buffer[0] = reg;
+
+	memset(&state->msg, 0, sizeof(struct i2c_msg));
+	state->msg.addr = reg;
+	state->msg.flags = I2C_M_RD;
+	state->msg.buf = state->i2c_read_buffer;
+	state->msg.len = 2;
+	if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
+		printk(KERN_WARNING "DiB0090 I2C read failed\n");
+		ret = 0;
+	} else
+		ret = (state->i2c_read_buffer[0] << 8)
+			| state->i2c_read_buffer[1];
+
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
+}
+
+static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
+{
+	int ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+
+	state->i2c_write_buffer[0] = val >> 8;
+	state->i2c_write_buffer[1] = val & 0xff;
+
+	memset(&state->msg, 0, sizeof(struct i2c_msg));
+	state->msg.addr = reg;
+	state->msg.flags = 0;
+	state->msg.buf = state->i2c_write_buffer;
+	state->msg.len = 2;
+	if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
+		printk(KERN_WARNING "DiB0090 I2C write failed\n");
+		ret = -EREMOTEIO;
+	} else
+		ret = 0;
+
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
+}
+
+#define HARD_RESET(state) do {  if (cfg->reset) {  if (cfg->sleep) cfg->sleep(fe, 0); msleep(10);  cfg->reset(fe, 1); msleep(10);  cfg->reset(fe, 0); msleep(10);  }  } while (0)
+#define ADC_TARGET -220
+#define GAIN_ALPHA 5
+#define WBD_ALPHA 6
+#define LPF	100
+static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, u8 c)
+{
+	do {
+		dib0090_write_reg(state, r++, *b++);
+	} while (--c);
+}
+
+static int dib0090_identify(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	u16 v;
+	struct dib0090_identity *identity = &state->identity;
+
+	v = dib0090_read_reg(state, 0x1a);
+
+	identity->p1g = 0;
+	identity->in_soc = 0;
+
+	dprintk("Tuner identification (Version = 0x%04x)", v);
+
+	/* without PLL lock info */
+	v &= ~KROSUS_PLL_LOCKED;
+
+	identity->version = v & 0xff;
+	identity->product = (v >> 8) & 0xf;
+
+	if (identity->product != KROSUS)
+		goto identification_error;
+
+	if ((identity->version & 0x3) == SOC) {
+		identity->in_soc = 1;
+		switch (identity->version) {
+		case SOC_8090_P1G_11R1:
+			dprintk("SOC 8090 P1-G11R1 Has been detected");
+			identity->p1g = 1;
+			break;
+		case SOC_8090_P1G_21R1:
+			dprintk("SOC 8090 P1-G21R1 Has been detected");
+			identity->p1g = 1;
+			break;
+		case SOC_7090_P1G_11R1:
+			dprintk("SOC 7090 P1-G11R1 Has been detected");
+			identity->p1g = 1;
+			break;
+		case SOC_7090_P1G_21R1:
+			dprintk("SOC 7090 P1-G21R1 Has been detected");
+			identity->p1g = 1;
+			break;
+		default:
+			goto identification_error;
+		}
+	} else {
+		switch ((identity->version >> 5) & 0x7) {
+		case MP001:
+			dprintk("MP001 : 9090/8096");
+			break;
+		case MP005:
+			dprintk("MP005 : Single Sband");
+			break;
+		case MP008:
+			dprintk("MP008 : diversity VHF-UHF-LBAND");
+			break;
+		case MP009:
+			dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND");
+			break;
+		default:
+			goto identification_error;
+		}
+
+		switch (identity->version & 0x1f) {
+		case P1G_21R2:
+			dprintk("P1G_21R2 detected");
+			identity->p1g = 1;
+			break;
+		case P1G:
+			dprintk("P1G detected");
+			identity->p1g = 1;
+			break;
+		case P1D_E_F:
+			dprintk("P1D/E/F detected");
+			break;
+		case P1C:
+			dprintk("P1C detected");
+			break;
+		case P1A_B:
+			dprintk("P1-A/B detected: driver is deactivated - not available");
+			goto identification_error;
+			break;
+		default:
+			goto identification_error;
+		}
+	}
+
+	return 0;
+
+identification_error:
+	return -EIO;
+}
+
+static int dib0090_fw_identify(struct dvb_frontend *fe)
+{
+	struct dib0090_fw_state *state = fe->tuner_priv;
+	struct dib0090_identity *identity = &state->identity;
+
+	u16 v = dib0090_fw_read_reg(state, 0x1a);
+	identity->p1g = 0;
+	identity->in_soc = 0;
+
+	dprintk("FE: Tuner identification (Version = 0x%04x)", v);
+
+	/* without PLL lock info */
+	v &= ~KROSUS_PLL_LOCKED;
+
+	identity->version = v & 0xff;
+	identity->product = (v >> 8) & 0xf;
+
+	if (identity->product != KROSUS)
+		goto identification_error;
+
+	if ((identity->version & 0x3) == SOC) {
+		identity->in_soc = 1;
+		switch (identity->version) {
+		case SOC_8090_P1G_11R1:
+			dprintk("SOC 8090 P1-G11R1 Has been detected");
+			identity->p1g = 1;
+			break;
+		case SOC_8090_P1G_21R1:
+			dprintk("SOC 8090 P1-G21R1 Has been detected");
+			identity->p1g = 1;
+			break;
+		case SOC_7090_P1G_11R1:
+			dprintk("SOC 7090 P1-G11R1 Has been detected");
+			identity->p1g = 1;
+			break;
+		case SOC_7090_P1G_21R1:
+			dprintk("SOC 7090 P1-G21R1 Has been detected");
+			identity->p1g = 1;
+			break;
+		default:
+			goto identification_error;
+		}
+	} else {
+		switch ((identity->version >> 5) & 0x7) {
+		case MP001:
+			dprintk("MP001 : 9090/8096");
+			break;
+		case MP005:
+			dprintk("MP005 : Single Sband");
+			break;
+		case MP008:
+			dprintk("MP008 : diversity VHF-UHF-LBAND");
+			break;
+		case MP009:
+			dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND");
+			break;
+		default:
+			goto identification_error;
+		}
+
+		switch (identity->version & 0x1f) {
+		case P1G_21R2:
+			dprintk("P1G_21R2 detected");
+			identity->p1g = 1;
+			break;
+		case P1G:
+			dprintk("P1G detected");
+			identity->p1g = 1;
+			break;
+		case P1D_E_F:
+			dprintk("P1D/E/F detected");
+			break;
+		case P1C:
+			dprintk("P1C detected");
+			break;
+		case P1A_B:
+			dprintk("P1-A/B detected: driver is deactivated - not available");
+			goto identification_error;
+			break;
+		default:
+			goto identification_error;
+		}
+	}
+
+	return 0;
+
+identification_error:
+	return -EIO;
+}
+
+static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	u16 PllCfg, i, v;
+
+	HARD_RESET(state);
+
+	dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
+	dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL);	/* PLL, DIG_CLK and CRYSTAL remain */
+
+	if (!cfg->in_soc) {
+		/* adcClkOutRatio=8->7, release reset */
+		dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0);
+		if (cfg->clkoutdrive != 0)
+			dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
+					  | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
+		else
+			dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
+					  | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
+	}
+
+	/* Read Pll current config * */
+	PllCfg = dib0090_read_reg(state, 0x21);
+
+	/** Reconfigure PLL if current setting is different from default setting **/
+	if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && (!cfg->in_soc)
+			&& !cfg->io.pll_bypass) {
+
+		/* Set Bypass mode */
+		PllCfg |= (1 << 15);
+		dib0090_write_reg(state, 0x21, PllCfg);
+
+		/* Set Reset Pll */
+		PllCfg &= ~(1 << 13);
+		dib0090_write_reg(state, 0x21, PllCfg);
+
+	/*** Set new Pll configuration in bypass and reset state ***/
+		PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
+		dib0090_write_reg(state, 0x21, PllCfg);
+
+		/* Remove Reset Pll */
+		PllCfg |= (1 << 13);
+		dib0090_write_reg(state, 0x21, PllCfg);
+
+	/*** Wait for PLL lock ***/
+		i = 100;
+		do {
+			v = !!(dib0090_read_reg(state, 0x1a) & 0x800);
+			if (v)
+				break;
+		} while (--i);
+
+		if (i == 0) {
+			dprintk("Pll: Unable to lock Pll");
+			return;
+		}
+
+		/* Finally Remove Bypass mode */
+		PllCfg &= ~(1 << 15);
+		dib0090_write_reg(state, 0x21, PllCfg);
+	}
+
+	if (cfg->io.pll_bypass) {
+		PllCfg |= (cfg->io.pll_bypass << 15);
+		dib0090_write_reg(state, 0x21, PllCfg);
+	}
+}
+
+static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
+{
+	struct dib0090_fw_state *state = fe->tuner_priv;
+	u16 PllCfg;
+	u16 v;
+	int i;
+
+	dprintk("fw reset digital");
+	HARD_RESET(state);
+
+	dib0090_fw_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
+	dib0090_fw_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL);	/* PLL, DIG_CLK and CRYSTAL remain */
+
+	dib0090_fw_write_reg(state, 0x20,
+			((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (cfg->data_tx_drv << 4) | cfg->ls_cfg_pad_drv);
+
+	v = (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 9) | (0 << 8) | (cfg->clkouttobamse << 4) | (0 << 2) | (0);
+	if (cfg->clkoutdrive != 0)
+		v |= cfg->clkoutdrive << 5;
+	else
+		v |= 7 << 5;
+
+	v |= 2 << 10;
+	dib0090_fw_write_reg(state, 0x23, v);
+
+	/* Read Pll current config * */
+	PllCfg = dib0090_fw_read_reg(state, 0x21);
+
+	/** Reconfigure PLL if current setting is different from default setting **/
+	if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && !cfg->io.pll_bypass) {
+
+		/* Set Bypass mode */
+		PllCfg |= (1 << 15);
+		dib0090_fw_write_reg(state, 0x21, PllCfg);
+
+		/* Set Reset Pll */
+		PllCfg &= ~(1 << 13);
+		dib0090_fw_write_reg(state, 0x21, PllCfg);
+
+	/*** Set new Pll configuration in bypass and reset state ***/
+		PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
+		dib0090_fw_write_reg(state, 0x21, PllCfg);
+
+		/* Remove Reset Pll */
+		PllCfg |= (1 << 13);
+		dib0090_fw_write_reg(state, 0x21, PllCfg);
+
+	/*** Wait for PLL lock ***/
+		i = 100;
+		do {
+			v = !!(dib0090_fw_read_reg(state, 0x1a) & 0x800);
+			if (v)
+				break;
+		} while (--i);
+
+		if (i == 0) {
+			dprintk("Pll: Unable to lock Pll");
+			return -EIO;
+		}
+
+		/* Finally Remove Bypass mode */
+		PllCfg &= ~(1 << 15);
+		dib0090_fw_write_reg(state, 0x21, PllCfg);
+	}
+
+	if (cfg->io.pll_bypass) {
+		PllCfg |= (cfg->io.pll_bypass << 15);
+		dib0090_fw_write_reg(state, 0x21, PllCfg);
+	}
+
+	return dib0090_fw_identify(fe);
+}
+
+static int dib0090_wakeup(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	if (state->config->sleep)
+		state->config->sleep(fe, 0);
+
+	/* enable dataTX in case we have been restarted in the wrong moment */
+	dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
+	return 0;
+}
+
+static int dib0090_sleep(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	if (state->config->sleep)
+		state->config->sleep(fe, 1);
+	return 0;
+}
+
+void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	if (fast)
+		dib0090_write_reg(state, 0x04, 0);
+	else
+		dib0090_write_reg(state, 0x04, 1);
+}
+
+EXPORT_SYMBOL(dib0090_dcc_freq);
+
+static const u16 bb_ramp_pwm_normal_socs[] = {
+	550,			/* max BB gain in 10th of dB */
+	(1 << 9) | 8,		/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
+	440,
+	(4 << 9) | 0,		/* BB_RAMP3 = 26dB */
+	(0 << 9) | 208,		/* BB_RAMP4 */
+	(4 << 9) | 208,		/* BB_RAMP5 = 29dB */
+	(0 << 9) | 440,		/* BB_RAMP6 */
+};
+
+static const u16 rf_ramp_pwm_cband_7090[] = {
+	280,			/* max RF gain in 10th of dB */
+	18,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+	504,			/* ramp_max = maximum X used on the ramp */
+	(29 << 10) | 364,	/* RF_RAMP5, LNA 1 = 8dB */
+	(0 << 10) | 504,	/* RF_RAMP6, LNA 1 */
+	(60 << 10) | 228,	/* RF_RAMP7, LNA 2 = 7.7dB */
+	(0 << 10) | 364,	/* RF_RAMP8, LNA 2 */
+	(34 << 10) | 109,	/* GAIN_4_1, LNA 3 = 6.8dB */
+	(0 << 10) | 228,	/* GAIN_4_2, LNA 3 */
+	(37 << 10) | 0,		/* RF_RAMP3, LNA 4 = 6.2dB */
+	(0 << 10) | 109,	/* RF_RAMP4, LNA 4 */
+};
+
+static const uint16_t rf_ramp_pwm_cband_7090e_sensitivity[] = {
+	186,
+	40,
+	746,
+	(10 << 10) | 345,
+	(0  << 10) | 746,
+	(0 << 10) | 0,
+	(0  << 10) | 0,
+	(28 << 10) | 200,
+	(0  << 10) | 345,
+	(20 << 10) | 0,
+	(0  << 10) | 200,
+};
+
+static const uint16_t rf_ramp_pwm_cband_7090e_aci[] = {
+	86,
+	40,
+	345,
+	(0 << 10) | 0,
+	(0 << 10) | 0,
+	(0 << 10) | 0,
+	(0 << 10) | 0,
+	(28 << 10) | 200,
+	(0  << 10) | 345,
+	(20 << 10) | 0,
+	(0  << 10) | 200,
+};
+
+static const u16 rf_ramp_pwm_cband_8090[] = {
+	345,			/* max RF gain in 10th of dB */
+	29,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+	1000,			/* ramp_max = maximum X used on the ramp */
+	(35 << 10) | 772,	/* RF_RAMP3, LNA 1 = 8dB */
+	(0 << 10) | 1000,	/* RF_RAMP4, LNA 1 */
+	(58 << 10) | 496,	/* RF_RAMP5, LNA 2 = 9.5dB */
+	(0 << 10) | 772,	/* RF_RAMP6, LNA 2 */
+	(27 << 10) | 200,	/* RF_RAMP7, LNA 3 = 10.5dB */
+	(0 << 10) | 496,	/* RF_RAMP8, LNA 3 */
+	(40 << 10) | 0,		/* GAIN_4_1, LNA 4 = 7dB */
+	(0 << 10) | 200,	/* GAIN_4_2, LNA 4 */
+};
+
+static const u16 rf_ramp_pwm_uhf_7090[] = {
+	407,			/* max RF gain in 10th of dB */
+	13,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+	529,			/* ramp_max = maximum X used on the ramp */
+	(23 << 10) | 0,		/* RF_RAMP3, LNA 1 = 14.7dB */
+	(0 << 10) | 176,	/* RF_RAMP4, LNA 1 */
+	(63 << 10) | 400,	/* RF_RAMP5, LNA 2 = 8dB */
+	(0 << 10) | 529,	/* RF_RAMP6, LNA 2 */
+	(48 << 10) | 316,	/* RF_RAMP7, LNA 3 = 6.8dB */
+	(0 << 10) | 400,	/* RF_RAMP8, LNA 3 */
+	(29 << 10) | 176,	/* GAIN_4_1, LNA 4 = 11.5dB */
+	(0 << 10) | 316,	/* GAIN_4_2, LNA 4 */
+};
+
+static const u16 rf_ramp_pwm_uhf_8090[] = {
+	388,			/* max RF gain in 10th of dB */
+	26,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+	1008,			/* ramp_max = maximum X used on the ramp */
+	(11 << 10) | 0,		/* RF_RAMP3, LNA 1 = 14.7dB */
+	(0 << 10) | 369,	/* RF_RAMP4, LNA 1 */
+	(41 << 10) | 809,	/* RF_RAMP5, LNA 2 = 8dB */
+	(0 << 10) | 1008,	/* RF_RAMP6, LNA 2 */
+	(27 << 10) | 659,	/* RF_RAMP7, LNA 3 = 6dB */
+	(0 << 10) | 809,	/* RF_RAMP8, LNA 3 */
+	(14 << 10) | 369,	/* GAIN_4_1, LNA 4 = 11.5dB */
+	(0 << 10) | 659,	/* GAIN_4_2, LNA 4 */
+};
+
+static const u16 rf_ramp_pwm_cband[] = {
+	0,			/* max RF gain in 10th of dB */
+	0,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
+	0,			/* ramp_max = maximum X used on the ramp */
+	(0 << 10) | 0,		/* 0x2c, LNA 1 = 0dB */
+	(0 << 10) | 0,		/* 0x2d, LNA 1 */
+	(0 << 10) | 0,		/* 0x2e, LNA 2 = 0dB */
+	(0 << 10) | 0,		/* 0x2f, LNA 2 */
+	(0 << 10) | 0,		/* 0x30, LNA 3 = 0dB */
+	(0 << 10) | 0,		/* 0x31, LNA 3 */
+	(0 << 10) | 0,		/* GAIN_4_1, LNA 4 = 0dB */
+	(0 << 10) | 0,		/* GAIN_4_2, LNA 4 */
+};
+
+static const u16 rf_ramp_vhf[] = {
+	412,			/* max RF gain in 10th of dB */
+	132, 307, 127,		/* LNA1,  13.2dB */
+	105, 412, 255,		/* LNA2,  10.5dB */
+	50, 50, 127,		/* LNA3,  5dB */
+	125, 175, 127,		/* LNA4,  12.5dB */
+	0, 0, 127,		/* CBAND, 0dB */
+};
+
+static const u16 rf_ramp_uhf[] = {
+	412,			/* max RF gain in 10th of dB */
+	132, 307, 127,		/* LNA1  : total gain = 13.2dB, point on the ramp where this amp is full gain, value to write to get full gain */
+	105, 412, 255,		/* LNA2  : 10.5 dB */
+	50, 50, 127,		/* LNA3  :  5.0 dB */
+	125, 175, 127,		/* LNA4  : 12.5 dB */
+	0, 0, 127,		/* CBAND :  0.0 dB */
+};
+
+static const u16 rf_ramp_cband_broadmatching[] =	/* for p1G only */
+{
+	314,			/* Calibrated at 200MHz order has been changed g4-g3-g2-g1 */
+	84, 314, 127,		/* LNA1 */
+	80, 230, 255,		/* LNA2 */
+	80, 150, 127,		/* LNA3  It was measured 12dB, do not lock if 120 */
+	70, 70, 127,		/* LNA4 */
+	0, 0, 127,		/* CBAND */
+};
+
+static const u16 rf_ramp_cband[] = {
+	332,			/* max RF gain in 10th of dB */
+	132, 252, 127,		/* LNA1,  dB */
+	80, 332, 255,		/* LNA2,  dB */
+	0, 0, 127,		/* LNA3,  dB */
+	0, 0, 127,		/* LNA4,  dB */
+	120, 120, 127,		/* LT1 CBAND */
+};
+
+static const u16 rf_ramp_pwm_vhf[] = {
+	404,			/* max RF gain in 10th of dB */
+	25,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
+	1011,			/* ramp_max = maximum X used on the ramp */
+	(6 << 10) | 417,	/* 0x2c, LNA 1 = 13.2dB */
+	(0 << 10) | 756,	/* 0x2d, LNA 1 */
+	(16 << 10) | 756,	/* 0x2e, LNA 2 = 10.5dB */
+	(0 << 10) | 1011,	/* 0x2f, LNA 2 */
+	(16 << 10) | 290,	/* 0x30, LNA 3 = 5dB */
+	(0 << 10) | 417,	/* 0x31, LNA 3 */
+	(7 << 10) | 0,		/* GAIN_4_1, LNA 4 = 12.5dB */
+	(0 << 10) | 290,	/* GAIN_4_2, LNA 4 */
+};
+
+static const u16 rf_ramp_pwm_uhf[] = {
+	404,			/* max RF gain in 10th of dB */
+	25,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
+	1011,			/* ramp_max = maximum X used on the ramp */
+	(6 << 10) | 417,	/* 0x2c, LNA 1 = 13.2dB */
+	(0 << 10) | 756,	/* 0x2d, LNA 1 */
+	(16 << 10) | 756,	/* 0x2e, LNA 2 = 10.5dB */
+	(0 << 10) | 1011,	/* 0x2f, LNA 2 */
+	(16 << 10) | 0,		/* 0x30, LNA 3 = 5dB */
+	(0 << 10) | 127,	/* 0x31, LNA 3 */
+	(7 << 10) | 127,	/* GAIN_4_1, LNA 4 = 12.5dB */
+	(0 << 10) | 417,	/* GAIN_4_2, LNA 4 */
+};
+
+static const u16 bb_ramp_boost[] = {
+	550,			/* max BB gain in 10th of dB */
+	260, 260, 26,		/* BB1, 26dB */
+	290, 550, 29,		/* BB2, 29dB */
+};
+
+static const u16 bb_ramp_pwm_normal[] = {
+	500,			/* max RF gain in 10th of dB */
+	8,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */
+	400,
+	(2 << 9) | 0,		/* 0x35 = 21dB */
+	(0 << 9) | 168,		/* 0x36 */
+	(2 << 9) | 168,		/* 0x37 = 29dB */
+	(0 << 9) | 400,		/* 0x38 */
+};
+
+struct slope {
+	s16 range;
+	s16 slope;
+};
+static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val)
+{
+	u8 i;
+	u16 rest;
+	u16 ret = 0;
+	for (i = 0; i < num; i++) {
+		if (val > slopes[i].range)
+			rest = slopes[i].range;
+		else
+			rest = val;
+		ret += (rest * slopes[i].slope) / slopes[i].range;
+		val -= rest;
+	}
+	return ret;
+}
+
+static const struct slope dib0090_wbd_slopes[3] = {
+	{66, 120},		/* -64,-52: offset -   65 */
+	{600, 170},		/* -52,-35: 65     -  665 */
+	{170, 250},		/* -45,-10: 665    - 835 */
+};
+
+static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd)
+{
+	wbd &= 0x3ff;
+	if (wbd < state->wbd_offset)
+		wbd = 0;
+	else
+		wbd -= state->wbd_offset;
+	/* -64dB is the floor */
+	return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd);
+}
+
+static void dib0090_wbd_target(struct dib0090_state *state, u32 rf)
+{
+	u16 offset = 250;
+
+	/* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */
+
+	if (state->current_band == BAND_VHF)
+		offset = 650;
+#ifndef FIRMWARE_FIREFLY
+	if (state->current_band == BAND_VHF)
+		offset = state->config->wbd_vhf_offset;
+	if (state->current_band == BAND_CBAND)
+		offset = state->config->wbd_cband_offset;
+#endif
+
+	state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset);
+	dprintk("wbd-target: %d dB", (u32) state->wbd_target);
+}
+
+static const int gain_reg_addr[4] = {
+	0x08, 0x0a, 0x0f, 0x01
+};
+
+static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force)
+{
+	u16 rf, bb, ref;
+	u16 i, v, gain_reg[4] = { 0 }, gain;
+	const u16 *g;
+
+	if (top_delta < -511)
+		top_delta = -511;
+	if (top_delta > 511)
+		top_delta = 511;
+
+	if (force) {
+		top_delta *= (1 << WBD_ALPHA);
+		gain_delta *= (1 << GAIN_ALPHA);
+	}
+
+	if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit))	/* overflow */
+		state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
+	else
+		state->rf_gain_limit += top_delta;
+
+	if (state->rf_gain_limit < 0)	/*underflow */
+		state->rf_gain_limit = 0;
+
+	/* use gain as a temporary variable and correct current_gain */
+	gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA;
+	if (gain_delta >= ((s16) gain - state->current_gain))	/* overflow */
+		state->current_gain = gain;
+	else
+		state->current_gain += gain_delta;
+	/* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */
+	if (state->current_gain < 0)
+		state->current_gain = 0;
+
+	/* now split total gain to rf and bb gain */
+	gain = state->current_gain >> GAIN_ALPHA;
+
+	/* requested gain is bigger than rf gain limit - ACI/WBD adjustment */
+	if (gain > (state->rf_gain_limit >> WBD_ALPHA)) {
+		rf = state->rf_gain_limit >> WBD_ALPHA;
+		bb = gain - rf;
+		if (bb > state->bb_ramp[0])
+			bb = state->bb_ramp[0];
+	} else {		/* high signal level -> all gains put on RF */
+		rf = gain;
+		bb = 0;
+	}
+
+	state->gain[0] = rf;
+	state->gain[1] = bb;
+
+	/* software ramp */
+	/* Start with RF gains */
+	g = state->rf_ramp + 1;	/* point on RF LNA1 max gain */
+	ref = rf;
+	for (i = 0; i < 7; i++) {	/* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */
+		if (g[0] == 0 || ref < (g[1] - g[0]))	/* if total gain of the current amp is null or this amp is not concerned because it starts to work from an higher gain value */
+			v = 0;	/* force the gain to write for the current amp to be null */
+		else if (ref >= g[1])	/* Gain to set is higher than the high working point of this amp */
+			v = g[2];	/* force this amp to be full gain */
+		else		/* compute the value to set to this amp because we are somewhere in his range */
+			v = ((ref - (g[1] - g[0])) * g[2]) / g[0];
+
+		if (i == 0)	/* LNA 1 reg mapping */
+			gain_reg[0] = v;
+		else if (i == 1)	/* LNA 2 reg mapping */
+			gain_reg[0] |= v << 7;
+		else if (i == 2)	/* LNA 3 reg mapping */
+			gain_reg[1] = v;
+		else if (i == 3)	/* LNA 4 reg mapping */
+			gain_reg[1] |= v << 7;
+		else if (i == 4)	/* CBAND LNA reg mapping */
+			gain_reg[2] = v | state->rf_lt_def;
+		else if (i == 5)	/* BB gain 1 reg mapping */
+			gain_reg[3] = v << 3;
+		else if (i == 6)	/* BB gain 2 reg mapping */
+			gain_reg[3] |= v << 8;
+
+		g += 3;		/* go to next gain bloc */
+
+		/* When RF is finished, start with BB */
+		if (i == 4) {
+			g = state->bb_ramp + 1;	/* point on BB gain 1 max gain */
+			ref = bb;
+		}
+	}
+	gain_reg[3] |= state->bb_1_def;
+	gain_reg[3] |= ((bb % 10) * 100) / 125;
+
+#ifdef DEBUG_AGC
+	dprintk("GA CALC: DB: %3d(rf) + %3d(bb) = %3d gain_reg[0]=%04x gain_reg[1]=%04x gain_reg[2]=%04x gain_reg[0]=%04x", rf, bb, rf + bb,
+		gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]);
+#endif
+
+	/* Write the amplifier regs */
+	for (i = 0; i < 4; i++) {
+		v = gain_reg[i];
+		if (force || state->gain_reg[i] != v) {
+			state->gain_reg[i] = v;
+			dib0090_write_reg(state, gain_reg_addr[i], v);
+		}
+	}
+}
+
+static void dib0090_set_boost(struct dib0090_state *state, int onoff)
+{
+	state->bb_1_def &= 0xdfff;
+	state->bb_1_def |= onoff << 13;
+}
+
+static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg)
+{
+	state->rf_ramp = cfg;
+}
+
+static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg)
+{
+	state->rf_ramp = cfg;
+
+	dib0090_write_reg(state, 0x2a, 0xffff);
+
+	dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a));
+
+	dib0090_write_regs(state, 0x2c, cfg + 3, 6);
+	dib0090_write_regs(state, 0x3e, cfg + 9, 2);
+}
+
+static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg)
+{
+	state->bb_ramp = cfg;
+	dib0090_set_boost(state, cfg[0] > 500);	/* we want the boost if the gain is higher that 50dB */
+}
+
+static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)
+{
+	state->bb_ramp = cfg;
+
+	dib0090_set_boost(state, cfg[0] > 500);	/* we want the boost if the gain is higher that 50dB */
+
+	dib0090_write_reg(state, 0x33, 0xffff);
+	dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33));
+	dib0090_write_regs(state, 0x35, cfg + 3, 4);
+}
+
+void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	/* reset the AGC */
+
+	if (state->config->use_pwm_agc) {
+#ifdef CONFIG_BAND_SBAND
+		if (state->current_band == BAND_SBAND) {
+			dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband);
+			dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost);
+		} else
+#endif
+#ifdef CONFIG_BAND_CBAND
+		if (state->current_band == BAND_CBAND) {
+			if (state->identity.in_soc) {
+				dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
+				if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
+					dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090);
+				else if (state->identity.version == SOC_7090_P1G_11R1
+						|| state->identity.version == SOC_7090_P1G_21R1) {
+					if (state->config->is_dib7090e) {
+						if (state->rf_ramp == NULL)
+							dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090e_sensitivity);
+						else
+							dib0090_set_rframp_pwm(state, state->rf_ramp);
+					} else
+						dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090);
+				}
+			} else {
+				dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband);
+				dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
+			}
+		} else
+#endif
+#ifdef CONFIG_BAND_VHF
+		if (state->current_band == BAND_VHF) {
+			if (state->identity.in_soc) {
+				dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
+			} else {
+				dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf);
+				dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
+			}
+		} else
+#endif
+		{
+			if (state->identity.in_soc) {
+				if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
+					dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_8090);
+				else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
+					dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_7090);
+				dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
+			} else {
+				dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf);
+				dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
+			}
+		}
+
+		if (state->rf_ramp[0] != 0)
+			dib0090_write_reg(state, 0x32, (3 << 11));
+		else
+			dib0090_write_reg(state, 0x32, (0 << 11));
+
+		dib0090_write_reg(state, 0x04, 0x03);
+		dib0090_write_reg(state, 0x39, (1 << 10));
+	}
+}
+
+EXPORT_SYMBOL(dib0090_pwm_gain_reset);
+
+void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	if (DC_servo_cutoff < 4)
+		dib0090_write_reg(state, 0x04, DC_servo_cutoff);
+}
+EXPORT_SYMBOL(dib0090_set_dc_servo);
+
+static u32 dib0090_get_slow_adc_val(struct dib0090_state *state)
+{
+	u16 adc_val = dib0090_read_reg(state, 0x1d);
+	if (state->identity.in_soc)
+		adc_val >>= 2;
+	return adc_val;
+}
+
+int dib0090_gain_control(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	enum frontend_tune_state *tune_state = &state->tune_state;
+	int ret = 10;
+
+	u16 wbd_val = 0;
+	u8 apply_gain_immediatly = 1;
+	s16 wbd_error = 0, adc_error = 0;
+
+	if (*tune_state == CT_AGC_START) {
+		state->agc_freeze = 0;
+		dib0090_write_reg(state, 0x04, 0x0);
+
+#ifdef CONFIG_BAND_SBAND
+		if (state->current_band == BAND_SBAND) {
+			dib0090_set_rframp(state, rf_ramp_sband);
+			dib0090_set_bbramp(state, bb_ramp_boost);
+		} else
+#endif
+#ifdef CONFIG_BAND_VHF
+		if (state->current_band == BAND_VHF && !state->identity.p1g) {
+			dib0090_set_rframp(state, rf_ramp_vhf);
+			dib0090_set_bbramp(state, bb_ramp_boost);
+		} else
+#endif
+#ifdef CONFIG_BAND_CBAND
+		if (state->current_band == BAND_CBAND && !state->identity.p1g) {
+			dib0090_set_rframp(state, rf_ramp_cband);
+			dib0090_set_bbramp(state, bb_ramp_boost);
+		} else
+#endif
+		if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) {
+			dib0090_set_rframp(state, rf_ramp_cband_broadmatching);
+			dib0090_set_bbramp(state, bb_ramp_boost);
+		} else {
+			dib0090_set_rframp(state, rf_ramp_uhf);
+			dib0090_set_bbramp(state, bb_ramp_boost);
+		}
+
+		dib0090_write_reg(state, 0x32, 0);
+		dib0090_write_reg(state, 0x39, 0);
+
+		dib0090_wbd_target(state, state->current_rf);
+
+		state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
+		state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA;
+
+		*tune_state = CT_AGC_STEP_0;
+	} else if (!state->agc_freeze) {
+		s16 wbd = 0, i, cnt;
+
+		int adc;
+		wbd_val = dib0090_get_slow_adc_val(state);
+
+		if (*tune_state == CT_AGC_STEP_0)
+			cnt = 5;
+		else
+			cnt = 1;
+
+		for (i = 0; i < cnt; i++) {
+			wbd_val = dib0090_get_slow_adc_val(state);
+			wbd += dib0090_wbd_to_db(state, wbd_val);
+		}
+		wbd /= cnt;
+		wbd_error = state->wbd_target - wbd;
+
+		if (*tune_state == CT_AGC_STEP_0) {
+			if (wbd_error < 0 && state->rf_gain_limit > 0 && !state->identity.p1g) {
+#ifdef CONFIG_BAND_CBAND
+				/* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */
+				u8 ltg2 = (state->rf_lt_def >> 10) & 0x7;
+				if (state->current_band == BAND_CBAND && ltg2) {
+					ltg2 >>= 1;
+					state->rf_lt_def &= ltg2 << 10;	/* reduce in 3 steps from 7 to 0 */
+				}
+#endif
+			} else {
+				state->agc_step = 0;
+				*tune_state = CT_AGC_STEP_1;
+			}
+		} else {
+			/* calc the adc power */
+			adc = state->config->get_adc_power(fe);
+			adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21;	/* included in [0:-700] */
+
+			adc_error = (s16) (((s32) ADC_TARGET) - adc);
+#ifdef CONFIG_STANDARD_DAB
+			if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB)
+				adc_error -= 10;
+#endif
+#ifdef CONFIG_STANDARD_DVBT
+			if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT &&
+					(state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16))
+				adc_error += 60;
+#endif
+#ifdef CONFIG_SYS_ISDBT
+			if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) && (((state->fe->dtv_property_cache.layer[0].segment_count >
+								0)
+							&&
+							((state->fe->dtv_property_cache.layer[0].modulation ==
+							  QAM_64)
+							 || (state->fe->dtv_property_cache.
+								 layer[0].modulation == QAM_16)))
+						||
+						((state->fe->dtv_property_cache.layer[1].segment_count >
+						  0)
+						 &&
+						 ((state->fe->dtv_property_cache.layer[1].modulation ==
+						   QAM_64)
+						  || (state->fe->dtv_property_cache.
+							  layer[1].modulation == QAM_16)))
+						||
+						((state->fe->dtv_property_cache.layer[2].segment_count >
+						  0)
+						 &&
+						 ((state->fe->dtv_property_cache.layer[2].modulation ==
+						   QAM_64)
+						  || (state->fe->dtv_property_cache.
+							  layer[2].modulation == QAM_16)))
+						)
+				)
+				adc_error += 60;
+#endif
+
+			if (*tune_state == CT_AGC_STEP_1) {	/* quickly go to the correct range of the ADC power */
+				if (ABS(adc_error) < 50 || state->agc_step++ > 5) {
+
+#ifdef CONFIG_STANDARD_DAB
+					if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) {
+						dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63));	/* cap value = 63 : narrow BB filter : Fc = 1.8MHz */
+						dib0090_write_reg(state, 0x04, 0x0);
+					} else
+#endif
+					{
+						dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32));
+						dib0090_write_reg(state, 0x04, 0x01);	/*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */
+					}
+
+					*tune_state = CT_AGC_STOP;
+				}
+			} else {
+				/* everything higher than or equal to CT_AGC_STOP means tracking */
+				ret = 100;	/* 10ms interval */
+				apply_gain_immediatly = 0;
+			}
+		}
+#ifdef DEBUG_AGC
+		dprintk
+			("tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm",
+			 (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val,
+			 (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA));
+#endif
+	}
+
+	/* apply gain */
+	if (!state->agc_freeze)
+		dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly);
+	return ret;
+}
+
+EXPORT_SYMBOL(dib0090_gain_control);
+
+void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	if (rf)
+		*rf = state->gain[0];
+	if (bb)
+		*bb = state->gain[1];
+	if (rf_gain_limit)
+		*rf_gain_limit = state->rf_gain_limit;
+	if (rflt)
+		*rflt = (state->rf_lt_def >> 10) & 0x7;
+}
+
+EXPORT_SYMBOL(dib0090_get_current_gain);
+
+u16 dib0090_get_wbd_target(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000;
+	s32 current_temp = state->temperature;
+	s32 wbd_thot, wbd_tcold;
+	const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
+
+	while (f_MHz > wbd->max_freq)
+		wbd++;
+
+	dprintk("using wbd-table-entry with max freq %d", wbd->max_freq);
+
+	if (current_temp < 0)
+		current_temp = 0;
+	if (current_temp > 128)
+		current_temp = 128;
+
+	state->wbdmux &= ~(7 << 13);
+	if (wbd->wbd_gain != 0)
+		state->wbdmux |= (wbd->wbd_gain << 13);
+	else
+		state->wbdmux |= (4 << 13);
+
+	dib0090_write_reg(state, 0x10, state->wbdmux);
+
+	wbd_thot = wbd->offset_hot - (((u32) wbd->slope_hot * f_MHz) >> 6);
+	wbd_tcold = wbd->offset_cold - (((u32) wbd->slope_cold * f_MHz) >> 6);
+
+	wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7;
+
+	state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold);
+	dprintk("wbd-target: %d dB", (u32) state->wbd_target);
+	dprintk("wbd offset applied is %d", wbd_tcold);
+
+	return state->wbd_offset + wbd_tcold;
+}
+EXPORT_SYMBOL(dib0090_get_wbd_target);
+
+u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	return state->wbd_offset;
+}
+EXPORT_SYMBOL(dib0090_get_wbd_offset);
+
+int dib0090_set_switch(struct dvb_frontend *fe, u8 sw1, u8 sw2, u8 sw3)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+
+	dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xfff8)
+			| ((sw3 & 1) << 2) | ((sw2 & 1) << 1) | (sw1 & 1));
+
+	return 0;
+}
+EXPORT_SYMBOL(dib0090_set_switch);
+
+int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+
+	dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x7fff)
+			| ((onoff & 1) << 15));
+	return 0;
+}
+EXPORT_SYMBOL(dib0090_set_vga);
+
+int dib0090_update_rframp_7090(struct dvb_frontend *fe, u8 cfg_sensitivity)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+
+	if ((!state->identity.p1g) || (!state->identity.in_soc)
+			|| ((state->identity.version != SOC_7090_P1G_21R1)
+				&& (state->identity.version != SOC_7090_P1G_11R1))) {
+		dprintk("%s() function can only be used for dib7090P", __func__);
+		return -ENODEV;
+	}
+
+	if (cfg_sensitivity)
+		state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_sensitivity;
+	else
+		state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_aci;
+	dib0090_pwm_gain_reset(fe);
+
+	return 0;
+}
+EXPORT_SYMBOL(dib0090_update_rframp_7090);
+
+static const u16 dib0090_defaults[] = {
+
+	25, 0x01,
+	0x0000,
+	0x99a0,
+	0x6008,
+	0x0000,
+	0x8bcb,
+	0x0000,
+	0x0405,
+	0x0000,
+	0x0000,
+	0x0000,
+	0xb802,
+	0x0300,
+	0x2d12,
+	0xbac0,
+	0x7c00,
+	0xdbb9,
+	0x0954,
+	0x0743,
+	0x8000,
+	0x0001,
+	0x0040,
+	0x0100,
+	0x0000,
+	0xe910,
+	0x149e,
+
+	1, 0x1c,
+	0xff2d,
+
+	1, 0x39,
+	0x0000,
+
+	2, 0x1e,
+	0x07FF,
+	0x0007,
+
+	1, 0x24,
+	EN_UHF | EN_CRYSTAL,
+
+	2, 0x3c,
+	0x3ff,
+	0x111,
+	0
+};
+
+static const u16 dib0090_p1g_additionnal_defaults[] = {
+	1, 0x05,
+	0xabcd,
+
+	1, 0x11,
+	0x00b4,
+
+	1, 0x1c,
+	0xfffd,
+
+	1, 0x40,
+	0x108,
+	0
+};
+
+static void dib0090_set_default_config(struct dib0090_state *state, const u16 * n)
+{
+	u16 l, r;
+
+	l = pgm_read_word(n++);
+	while (l) {
+		r = pgm_read_word(n++);
+		do {
+			dib0090_write_reg(state, r, pgm_read_word(n++));
+			r++;
+		} while (--l);
+		l = pgm_read_word(n++);
+	}
+}
+
+#define CAP_VALUE_MIN (u8)  9
+#define CAP_VALUE_MAX (u8) 40
+#define HR_MIN	      (u8) 25
+#define HR_MAX	      (u8) 40
+#define POLY_MIN      (u8)  0
+#define POLY_MAX      (u8)  8
+
+static void dib0090_set_EFUSE(struct dib0090_state *state)
+{
+	u8 c, h, n;
+	u16 e2, e4;
+	u16 cal;
+
+	e2 = dib0090_read_reg(state, 0x26);
+	e4 = dib0090_read_reg(state, 0x28);
+
+	if ((state->identity.version == P1D_E_F) ||
+			(state->identity.version == P1G) || (e2 == 0xffff)) {
+
+		dib0090_write_reg(state, 0x22, 0x10);
+		cal = (dib0090_read_reg(state, 0x22) >> 6) & 0x3ff;
+
+		if ((cal < 670) || (cal == 1023))
+			cal = 850;
+		n = 165 - ((cal * 10)>>6) ;
+		e2 = e4 = (3<<12) | (34<<6) | (n);
+	}
+
+	if (e2 != e4)
+		e2 &= e4; /* Remove the redundancy  */
+
+	if (e2 != 0xffff) {
+		c = e2 & 0x3f;
+		n = (e2 >> 12) & 0xf;
+		h = (e2 >> 6) & 0x3f;
+
+		if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN))
+			c = 32;
+		if ((h >= HR_MAX) || (h <= HR_MIN))
+			h = 34;
+		if ((n >= POLY_MAX) || (n <= POLY_MIN))
+			n = 3;
+
+		dib0090_write_reg(state, 0x13, (h << 10)) ;
+		e2 = (n<<11) | ((h>>2)<<6) | (c);
+		dib0090_write_reg(state, 0x2, e2) ; /* Load the BB_2 */
+	}
+}
+
+static int dib0090_reset(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+
+	dib0090_reset_digital(fe, state->config);
+	if (dib0090_identify(fe) < 0)
+		return -EIO;
+
+#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT
+	if (!(state->identity.version & 0x1))	/* it is P1B - reset is already done */
+		return 0;
+#endif
+
+	if (!state->identity.in_soc) {
+		if ((dib0090_read_reg(state, 0x1a) >> 5) & 0x2)
+			dib0090_write_reg(state, 0x1b, (EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL));
+		else
+			dib0090_write_reg(state, 0x1b, (EN_DIGCLK | EN_PLL | EN_CRYSTAL));
+	}
+
+	dib0090_set_default_config(state, dib0090_defaults);
+
+	if (state->identity.in_soc)
+		dib0090_write_reg(state, 0x18, 0x2910);  /* charge pump current = 0 */
+
+	if (state->identity.p1g)
+		dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults);
+
+	/* Update the efuse : Only available for KROSUS > P1C  and SOC as well*/
+	if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc))
+		dib0090_set_EFUSE(state);
+
+	/* Congigure in function of the crystal */
+	if (state->config->force_crystal_mode != 0)
+		dib0090_write_reg(state, 0x14,
+				state->config->force_crystal_mode & 3);
+	else if (state->config->io.clock_khz >= 24000)
+		dib0090_write_reg(state, 0x14, 1);
+	else
+		dib0090_write_reg(state, 0x14, 2);
+	dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1);
+
+	state->calibrate = DC_CAL | WBD_CAL | TEMP_CAL;	/* enable iq-offset-calibration and wbd-calibration when tuning next time */
+
+	return 0;
+}
+
+#define steps(u) (((u) > 15) ? ((u)-16) : (u))
+#define INTERN_WAIT 10
+static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state)
+{
+	int ret = INTERN_WAIT * 10;
+
+	switch (*tune_state) {
+	case CT_TUNER_STEP_2:
+		/* Turns to positive */
+		dib0090_write_reg(state, 0x1f, 0x7);
+		*tune_state = CT_TUNER_STEP_3;
+		break;
+
+	case CT_TUNER_STEP_3:
+		state->adc_diff = dib0090_read_reg(state, 0x1d);
+
+		/* Turns to negative */
+		dib0090_write_reg(state, 0x1f, 0x4);
+		*tune_state = CT_TUNER_STEP_4;
+		break;
+
+	case CT_TUNER_STEP_4:
+		state->adc_diff -= dib0090_read_reg(state, 0x1d);
+		*tune_state = CT_TUNER_STEP_5;
+		ret = 0;
+		break;
+
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+struct dc_calibration {
+	u8 addr;
+	u8 offset;
+	u8 pga:1;
+	u16 bb1;
+	u8 i:1;
+};
+
+static const struct dc_calibration dc_table[] = {
+	/* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
+	{0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1},
+	{0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0},
+	/* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
+	{0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1},
+	{0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0},
+	{0},
+};
+
+static const struct dc_calibration dc_p1g_table[] = {
+	/* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
+	/* addr ; trim reg offset ; pga ; CTRL_BB1 value ; i or q */
+	{0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1},
+	{0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0},
+	/* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
+	{0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1},
+	{0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0},
+	{0},
+};
+
+static void dib0090_set_trim(struct dib0090_state *state)
+{
+	u16 *val;
+
+	if (state->dc->addr == 0x07)
+		val = &state->bb7;
+	else
+		val = &state->bb6;
+
+	*val &= ~(0x1f << state->dc->offset);
+	*val |= state->step << state->dc->offset;
+
+	dib0090_write_reg(state, state->dc->addr, *val);
+}
+
+static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
+{
+	int ret = 0;
+	u16 reg;
+
+	switch (*tune_state) {
+	case CT_TUNER_START:
+		dprintk("Start DC offset calibration");
+
+		/* force vcm2 = 0.8V */
+		state->bb6 = 0;
+		state->bb7 = 0x040d;
+
+		/* the LNA AND LO are off */
+		reg = dib0090_read_reg(state, 0x24) & 0x0ffb;	/* shutdown lna and lo */
+		dib0090_write_reg(state, 0x24, reg);
+
+		state->wbdmux = dib0090_read_reg(state, 0x10);
+		dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3);
+		dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
+
+		state->dc = dc_table;
+
+		if (state->identity.p1g)
+			state->dc = dc_p1g_table;
+		*tune_state = CT_TUNER_STEP_0;
+
+		/* fall through */
+
+	case CT_TUNER_STEP_0:
+		dprintk("Sart/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q");
+		dib0090_write_reg(state, 0x01, state->dc->bb1);
+		dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7));
+
+		state->step = 0;
+		state->min_adc_diff = 1023;
+		*tune_state = CT_TUNER_STEP_1;
+		ret = 50;
+		break;
+
+	case CT_TUNER_STEP_1:
+		dib0090_set_trim(state);
+		*tune_state = CT_TUNER_STEP_2;
+		break;
+
+	case CT_TUNER_STEP_2:
+	case CT_TUNER_STEP_3:
+	case CT_TUNER_STEP_4:
+		ret = dib0090_get_offset(state, tune_state);
+		break;
+
+	case CT_TUNER_STEP_5:	/* found an offset */
+		dprintk("adc_diff = %d, current step= %d", (u32) state->adc_diff, state->step);
+		if (state->step == 0 && state->adc_diff < 0) {
+			state->min_adc_diff = -1023;
+			dprintk("Change of sign of the minimum adc diff");
+		}
+
+		dprintk("adc_diff = %d, min_adc_diff = %d current_step = %d", state->adc_diff, state->min_adc_diff, state->step);
+
+		/* first turn for this frequency */
+		if (state->step == 0) {
+			if (state->dc->pga && state->adc_diff < 0)
+				state->step = 0x10;
+			if (state->dc->pga == 0 && state->adc_diff > 0)
+				state->step = 0x10;
+		}
+
+		/* Look for a change of Sign in the Adc_diff.min_adc_diff is used to STORE the setp N-1 */
+		if ((state->adc_diff & 0x8000) == (state->min_adc_diff & 0x8000) && steps(state->step) < 15) {
+			/* stop search when the delta the sign is changing and Steps =15 and Step=0 is force for continuance */
+			state->step++;
+			state->min_adc_diff = state->adc_diff;
+			*tune_state = CT_TUNER_STEP_1;
+		} else {
+			/* the minimum was what we have seen in the step before */
+			if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) {
+				dprintk("Since adc_diff N = %d  > adc_diff step N-1 = %d, Come back one step", state->adc_diff, state->min_adc_diff);
+				state->step--;
+			}
+
+			dib0090_set_trim(state);
+			dprintk("BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->dc->addr, state->adc_diff, state->step);
+
+			state->dc++;
+			if (state->dc->addr == 0)	/* done */
+				*tune_state = CT_TUNER_STEP_6;
+			else
+				*tune_state = CT_TUNER_STEP_0;
+
+		}
+		break;
+
+	case CT_TUNER_STEP_6:
+		dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008);
+		dib0090_write_reg(state, 0x1f, 0x7);
+		*tune_state = CT_TUNER_START;	/* reset done -> real tuning can now begin */
+		state->calibrate &= ~DC_CAL;
+	default:
+		break;
+	}
+	return ret;
+}
+
+static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
+{
+	u8 wbd_gain;
+	const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
+
+	switch (*tune_state) {
+	case CT_TUNER_START:
+		while (state->current_rf / 1000 > wbd->max_freq)
+			wbd++;
+		if (wbd->wbd_gain != 0)
+			wbd_gain = wbd->wbd_gain;
+		else {
+			wbd_gain = 4;
+#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND)
+			if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND))
+				wbd_gain = 2;
+#endif
+		}
+
+		if (wbd_gain == state->wbd_calibration_gain) {	/* the WBD calibration has already been done */
+			*tune_state = CT_TUNER_START;
+			state->calibrate &= ~WBD_CAL;
+			return 0;
+		}
+
+		dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3));
+
+		dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1)));
+		*tune_state = CT_TUNER_STEP_0;
+		state->wbd_calibration_gain = wbd_gain;
+		return 90;	/* wait for the WBDMUX to switch and for the ADC to sample */
+
+	case CT_TUNER_STEP_0:
+		state->wbd_offset = dib0090_get_slow_adc_val(state);
+		dprintk("WBD calibration offset = %d", state->wbd_offset);
+		*tune_state = CT_TUNER_START;	/* reset done -> real tuning can now begin */
+		state->calibrate &= ~WBD_CAL;
+		break;
+
+	default:
+		break;
+	}
+	return 0;
+}
+
+static void dib0090_set_bandwidth(struct dib0090_state *state)
+{
+	u16 tmp;
+
+	if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000)
+		tmp = (3 << 14);
+	else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000)
+		tmp = (2 << 14);
+	else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000)
+		tmp = (1 << 14);
+	else
+		tmp = (0 << 14);
+
+	state->bb_1_def &= 0x3fff;
+	state->bb_1_def |= tmp;
+
+	dib0090_write_reg(state, 0x01, state->bb_1_def);	/* be sure that we have the right bb-filter */
+
+	dib0090_write_reg(state, 0x03, 0x6008);	/* = 0x6008 : vcm3_trim = 1 ; filter2_gm1_trim = 8 ; filter2_cutoff_freq = 0 */
+	dib0090_write_reg(state, 0x04, 0x1);	/* 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast */
+	if (state->identity.in_soc) {
+		dib0090_write_reg(state, 0x05, 0x9bcf); /* attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 1 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 15 */
+	} else {
+		dib0090_write_reg(state, 0x02, (5 << 11) | (8 << 6) | (22 & 0x3f));	/* 22 = cap_value */
+		dib0090_write_reg(state, 0x05, 0xabcd);	/* = 0xabcd : attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 2 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 13 */
+	}
+}
+
+static const struct dib0090_pll dib0090_pll_table[] = {
+#ifdef CONFIG_BAND_CBAND
+	{56000, 0, 9, 48, 6},
+	{70000, 1, 9, 48, 6},
+	{87000, 0, 8, 32, 4},
+	{105000, 1, 8, 32, 4},
+	{115000, 0, 7, 24, 6},
+	{140000, 1, 7, 24, 6},
+	{170000, 0, 6, 16, 4},
+#endif
+#ifdef CONFIG_BAND_VHF
+	{200000, 1, 6, 16, 4},
+	{230000, 0, 5, 12, 6},
+	{280000, 1, 5, 12, 6},
+	{340000, 0, 4, 8, 4},
+	{380000, 1, 4, 8, 4},
+	{450000, 0, 3, 6, 6},
+#endif
+#ifdef CONFIG_BAND_UHF
+	{580000, 1, 3, 6, 6},
+	{700000, 0, 2, 4, 4},
+	{860000, 1, 2, 4, 4},
+#endif
+#ifdef CONFIG_BAND_LBAND
+	{1800000, 1, 0, 2, 4},
+#endif
+#ifdef CONFIG_BAND_SBAND
+	{2900000, 0, 14, 1, 4},
+#endif
+};
+
+static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = {
+
+#ifdef CONFIG_BAND_CBAND
+	{184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
+	{227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
+	{380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
+#endif
+#ifdef CONFIG_BAND_UHF
+	{520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+#endif
+#ifdef CONFIG_BAND_LBAND
+	{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+	{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+	{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+#endif
+#ifdef CONFIG_BAND_SBAND
+	{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
+	{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
+#endif
+};
+
+static const struct dib0090_tuning dib0090_tuning_table[] = {
+
+#ifdef CONFIG_BAND_CBAND
+	{170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
+#endif
+#ifdef CONFIG_BAND_VHF
+	{184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
+	{227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
+	{380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
+#endif
+#ifdef CONFIG_BAND_UHF
+	{520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+#endif
+#ifdef CONFIG_BAND_LBAND
+	{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+	{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+	{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+#endif
+#ifdef CONFIG_BAND_SBAND
+	{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
+	{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
+#endif
+};
+
+static const struct dib0090_tuning dib0090_p1g_tuning_table[] = {
+#ifdef CONFIG_BAND_CBAND
+	{170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB},
+#endif
+#ifdef CONFIG_BAND_VHF
+	{184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
+	{227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
+	{380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
+#endif
+#ifdef CONFIG_BAND_UHF
+	{510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+#endif
+#ifdef CONFIG_BAND_LBAND
+	{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+	{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+	{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+#endif
+#ifdef CONFIG_BAND_SBAND
+	{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
+	{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
+#endif
+};
+
+static const struct dib0090_pll dib0090_p1g_pll_table[] = {
+#ifdef CONFIG_BAND_CBAND
+	{57000, 0, 11, 48, 6},
+	{70000, 1, 11, 48, 6},
+	{86000, 0, 10, 32, 4},
+	{105000, 1, 10, 32, 4},
+	{115000, 0, 9, 24, 6},
+	{140000, 1, 9, 24, 6},
+	{170000, 0, 8, 16, 4},
+#endif
+#ifdef CONFIG_BAND_VHF
+	{200000, 1, 8, 16, 4},
+	{230000, 0, 7, 12, 6},
+	{280000, 1, 7, 12, 6},
+	{340000, 0, 6, 8, 4},
+	{380000, 1, 6, 8, 4},
+	{455000, 0, 5, 6, 6},
+#endif
+#ifdef CONFIG_BAND_UHF
+	{580000, 1, 5, 6, 6},
+	{680000, 0, 4, 4, 4},
+	{860000, 1, 4, 4, 4},
+#endif
+#ifdef CONFIG_BAND_LBAND
+	{1800000, 1, 2, 2, 4},
+#endif
+#ifdef CONFIG_BAND_SBAND
+	{2900000, 0, 1, 1, 6},
+#endif
+};
+
+static const struct dib0090_tuning dib0090_p1g_tuning_table_fm_vhf_on_cband[] = {
+#ifdef CONFIG_BAND_CBAND
+	{184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
+	{227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
+	{380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
+#endif
+#ifdef CONFIG_BAND_UHF
+	{520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+#endif
+#ifdef CONFIG_BAND_LBAND
+	{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+	{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+	{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+#endif
+#ifdef CONFIG_BAND_SBAND
+	{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
+	{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
+#endif
+};
+
+static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = {
+#ifdef CONFIG_BAND_CBAND
+	{300000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
+	{380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
+	{570000, 4, 10, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
+	{858000, 4, 5, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
+#endif
+};
+
+static const struct dib0090_tuning dib0090_tuning_table_cband_7090e_sensitivity[] = {
+#ifdef CONFIG_BAND_CBAND
+	{ 300000,  0 ,  3,  0x8105, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
+	{ 380000,  0 ,  10, 0x810F, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
+	{ 600000,  0 ,  10, 0x815E, 0x280, 0x2d12, 0xb84e, EN_CAB },
+	{ 660000,  0 ,  5,  0x85E3, 0x280, 0x2d12, 0xb84e, EN_CAB },
+	{ 720000,  0 ,  5,  0x852E, 0x280, 0x2d12, 0xb84e, EN_CAB },
+	{ 860000,  0 ,  4,  0x85E5, 0x280, 0x2d12, 0xb84e, EN_CAB },
+#endif
+};
+
+int dib0090_update_tuning_table_7090(struct dvb_frontend *fe,
+		u8 cfg_sensitivity)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	const struct dib0090_tuning *tune =
+		dib0090_tuning_table_cband_7090e_sensitivity;
+	const struct dib0090_tuning dib0090_tuning_table_cband_7090e_aci[] = {
+		{ 300000,  0 ,  3,  0x8165, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
+		{ 650000,  0 ,  4,  0x815B, 0x280, 0x2d12, 0xb84e, EN_CAB },
+		{ 860000,  0 ,  5,  0x84EF, 0x280, 0x2d12, 0xb84e, EN_CAB },
+	};
+
+	if ((!state->identity.p1g) || (!state->identity.in_soc)
+			|| ((state->identity.version != SOC_7090_P1G_21R1)
+				&& (state->identity.version != SOC_7090_P1G_11R1))) {
+		dprintk("%s() function can only be used for dib7090", __func__);
+		return -ENODEV;
+	}
+
+	if (cfg_sensitivity)
+		tune = dib0090_tuning_table_cband_7090e_sensitivity;
+	else
+		tune = dib0090_tuning_table_cband_7090e_aci;
+
+	while (state->rf_request > tune->max_freq)
+		tune++;
+
+	dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x8000)
+			| (tune->lna_bias & 0x7fff));
+	dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xf83f)
+			| ((tune->lna_tune << 6) & 0x07c0));
+	return 0;
+}
+EXPORT_SYMBOL(dib0090_update_tuning_table_7090);
+
+static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state)
+{
+	int ret = 0;
+	u16 lo4 = 0xe900;
+
+	s16 adc_target;
+	u16 adc;
+	s8 step_sign;
+	u8 force_soft_search = 0;
+
+	if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
+		force_soft_search = 1;
+
+	if (*tune_state == CT_TUNER_START) {
+		dprintk("Start Captrim search : %s", (force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO");
+		dib0090_write_reg(state, 0x10, 0x2B1);
+		dib0090_write_reg(state, 0x1e, 0x0032);
+
+		if (!state->tuner_is_tuned) {
+			/* prepare a complete captrim */
+			if (!state->identity.p1g || force_soft_search)
+				state->step = state->captrim = state->fcaptrim = 64;
+
+			state->current_rf = state->rf_request;
+		} else {	/* we are already tuned to this frequency - the configuration is correct  */
+			if (!state->identity.p1g || force_soft_search) {
+				/* do a minimal captrim even if the frequency has not changed */
+				state->step = 4;
+				state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f;
+			}
+		}
+		state->adc_diff = 3000;
+		*tune_state = CT_TUNER_STEP_0;
+
+	} else if (*tune_state == CT_TUNER_STEP_0) {
+		if (state->identity.p1g && !force_soft_search) {
+			u8 ratio = 31;
+
+			dib0090_write_reg(state, 0x40, (3 << 7) | (ratio << 2) | (1 << 1) | 1);
+			dib0090_read_reg(state, 0x40);
+			ret = 50;
+		} else {
+			state->step /= 2;
+			dib0090_write_reg(state, 0x18, lo4 | state->captrim);
+
+			if (state->identity.in_soc)
+				ret = 25;
+		}
+		*tune_state = CT_TUNER_STEP_1;
+
+	} else if (*tune_state == CT_TUNER_STEP_1) {
+		if (state->identity.p1g && !force_soft_search) {
+			dib0090_write_reg(state, 0x40, 0x18c | (0 << 1) | 0);
+			dib0090_read_reg(state, 0x40);
+
+			state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F;
+			dprintk("***Final Captrim= 0x%x", state->fcaptrim);
+			*tune_state = CT_TUNER_STEP_3;
+
+		} else {
+			/* MERGE for all krosus before P1G */
+			adc = dib0090_get_slow_adc_val(state);
+			dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024);
+
+			if (state->rest == 0 || state->identity.in_soc) {	/* Just for 8090P SOCS where auto captrim HW bug : TO CHECK IN ACI for SOCS !!! if 400 for 8090p SOC => tune issue !!! */
+				adc_target = 200;
+			} else
+				adc_target = 400;
+
+			if (adc >= adc_target) {
+				adc -= adc_target;
+				step_sign = -1;
+			} else {
+				adc = adc_target - adc;
+				step_sign = 1;
+			}
+
+			if (adc < state->adc_diff) {
+				dprintk("CAPTRIM=%d is closer to target (%d/%d)", (u32) state->captrim, (u32) adc, (u32) state->adc_diff);
+				state->adc_diff = adc;
+				state->fcaptrim = state->captrim;
+			}
+
+			state->captrim += step_sign * state->step;
+			if (state->step >= 1)
+				*tune_state = CT_TUNER_STEP_0;
+			else
+				*tune_state = CT_TUNER_STEP_2;
+
+			ret = 25;
+		}
+	} else if (*tune_state == CT_TUNER_STEP_2) {	/* this step is only used by krosus < P1G */
+		/*write the final cptrim config */
+		dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim);
+
+		*tune_state = CT_TUNER_STEP_3;
+
+	} else if (*tune_state == CT_TUNER_STEP_3) {
+		state->calibrate &= ~CAPTRIM_CAL;
+		*tune_state = CT_TUNER_STEP_0;
+	}
+
+	return ret;
+}
+
+static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tune_state *tune_state)
+{
+	int ret = 15;
+	s16 val;
+
+	switch (*tune_state) {
+	case CT_TUNER_START:
+		state->wbdmux = dib0090_read_reg(state, 0x10);
+		dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3));
+
+		state->bias = dib0090_read_reg(state, 0x13);
+		dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8));
+
+		*tune_state = CT_TUNER_STEP_0;
+		/* wait for the WBDMUX to switch and for the ADC to sample */
+		break;
+
+	case CT_TUNER_STEP_0:
+		state->adc_diff = dib0090_get_slow_adc_val(state);
+		dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8));
+		*tune_state = CT_TUNER_STEP_1;
+		break;
+
+	case CT_TUNER_STEP_1:
+		val = dib0090_get_slow_adc_val(state);
+		state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55;
+
+		dprintk("temperature: %d C", state->temperature - 30);
+
+		*tune_state = CT_TUNER_STEP_2;
+		break;
+
+	case CT_TUNER_STEP_2:
+		dib0090_write_reg(state, 0x13, state->bias);
+		dib0090_write_reg(state, 0x10, state->wbdmux);	/* write back original WBDMUX */
+
+		*tune_state = CT_TUNER_START;
+		state->calibrate &= ~TEMP_CAL;
+		if (state->config->analog_output == 0)
+			dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
+
+		break;
+
+	default:
+		ret = 0;
+		break;
+	}
+	return ret;
+}
+
+#define WBD     0x781		/* 1 1 1 1 0000 0 0 1 */
+static int dib0090_tune(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	const struct dib0090_tuning *tune = state->current_tune_table_index;
+	const struct dib0090_pll *pll = state->current_pll_table_index;
+	enum frontend_tune_state *tune_state = &state->tune_state;
+
+	u16 lo5, lo6, Den, tmp;
+	u32 FBDiv, Rest, FREF, VCOF_kHz = 0;
+	int ret = 10;		/* 1ms is the default delay most of the time */
+	u8 c, i;
+
+	/************************* VCO ***************************/
+	/* Default values for FG                                 */
+	/* from these are needed :                               */
+	/* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv             */
+
+	/* in any case we first need to do a calibration if needed */
+	if (*tune_state == CT_TUNER_START) {
+		/* deactivate DataTX before some calibrations */
+		if (state->calibrate & (DC_CAL | TEMP_CAL | WBD_CAL))
+			dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
+		else
+			/* Activate DataTX in case a calibration has been done before */
+			if (state->config->analog_output == 0)
+				dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
+	}
+
+	if (state->calibrate & DC_CAL)
+		return dib0090_dc_offset_calibration(state, tune_state);
+	else if (state->calibrate & WBD_CAL) {
+		if (state->current_rf == 0)
+			state->current_rf = state->fe->dtv_property_cache.frequency / 1000;
+		return dib0090_wbd_calibration(state, tune_state);
+	} else if (state->calibrate & TEMP_CAL)
+		return dib0090_get_temperature(state, tune_state);
+	else if (state->calibrate & CAPTRIM_CAL)
+		return dib0090_captrim_search(state, tune_state);
+
+	if (*tune_state == CT_TUNER_START) {
+		/* if soc and AGC pwm control, disengage mux to be able to R/W access to 0x01 register to set the right filter (cutoff_freq_select) during the tune sequence, otherwise, SOC SERPAR error when accessing to 0x01 */
+		if (state->config->use_pwm_agc && state->identity.in_soc) {
+			tmp = dib0090_read_reg(state, 0x39);
+			if ((tmp >> 10) & 0x1)
+				dib0090_write_reg(state, 0x39, tmp & ~(1 << 10));
+		}
+
+		state->current_band = (u8) BAND_OF_FREQUENCY(state->fe->dtv_property_cache.frequency / 1000);
+		state->rf_request =
+			state->fe->dtv_property_cache.frequency / 1000 + (state->current_band ==
+					BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->
+					freq_offset_khz_vhf);
+
+		/* in ISDB-T 1seg we shift tuning frequency */
+		if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1
+					&& state->fe->dtv_property_cache.isdbt_partial_reception == 0)) {
+			const struct dib0090_low_if_offset_table *LUT_offset = state->config->low_if;
+			u8 found_offset = 0;
+			u32 margin_khz = 100;
+
+			if (LUT_offset != NULL) {
+				while (LUT_offset->RF_freq != 0xffff) {
+					if (((state->rf_request > (LUT_offset->RF_freq - margin_khz))
+								&& (state->rf_request < (LUT_offset->RF_freq + margin_khz)))
+							&& LUT_offset->std == state->fe->dtv_property_cache.delivery_system) {
+						state->rf_request += LUT_offset->offset_khz;
+						found_offset = 1;
+						break;
+					}
+					LUT_offset++;
+				}
+			}
+
+			if (found_offset == 0)
+				state->rf_request += 400;
+		}
+		if (state->current_rf != state->rf_request || (state->current_standard != state->fe->dtv_property_cache.delivery_system)) {
+			state->tuner_is_tuned = 0;
+			state->current_rf = 0;
+			state->current_standard = 0;
+
+			tune = dib0090_tuning_table;
+			if (state->identity.p1g)
+				tune = dib0090_p1g_tuning_table;
+
+			tmp = (state->identity.version >> 5) & 0x7;
+
+			if (state->identity.in_soc) {
+				if (state->config->force_cband_input) {	/* Use the CBAND input for all band */
+					if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF
+							|| state->current_band & BAND_UHF) {
+						state->current_band = BAND_CBAND;
+						if (state->config->is_dib7090e)
+							tune = dib0090_tuning_table_cband_7090e_sensitivity;
+						else
+							tune = dib0090_tuning_table_cband_7090;
+					}
+				} else {	/* Use the CBAND input for all band under UHF */
+					if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) {
+						state->current_band = BAND_CBAND;
+						if (state->config->is_dib7090e)
+							tune = dib0090_tuning_table_cband_7090e_sensitivity;
+						else
+							tune = dib0090_tuning_table_cband_7090;
+					}
+				}
+			} else
+			 if (tmp == 0x4 || tmp == 0x7) {
+				/* CBAND tuner version for VHF */
+				if (state->current_band == BAND_FM || state->current_band == BAND_CBAND || state->current_band == BAND_VHF) {
+					state->current_band = BAND_CBAND;	/* Force CBAND */
+
+					tune = dib0090_tuning_table_fm_vhf_on_cband;
+					if (state->identity.p1g)
+						tune = dib0090_p1g_tuning_table_fm_vhf_on_cband;
+				}
+			}
+
+			pll = dib0090_pll_table;
+			if (state->identity.p1g)
+				pll = dib0090_p1g_pll_table;
+
+			/* Look for the interval */
+			while (state->rf_request > tune->max_freq)
+				tune++;
+			while (state->rf_request > pll->max_freq)
+				pll++;
+
+			state->current_tune_table_index = tune;
+			state->current_pll_table_index = pll;
+
+			dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim));
+
+			VCOF_kHz = (pll->hfdiv * state->rf_request) * 2;
+
+			FREF = state->config->io.clock_khz;
+			if (state->config->fref_clock_ratio != 0)
+				FREF /= state->config->fref_clock_ratio;
+
+			FBDiv = (VCOF_kHz / pll->topresc / FREF);
+			Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF;
+
+			if (Rest < LPF)
+				Rest = 0;
+			else if (Rest < 2 * LPF)
+				Rest = 2 * LPF;
+			else if (Rest > (FREF - LPF)) {
+				Rest = 0;
+				FBDiv += 1;
+			} else if (Rest > (FREF - 2 * LPF))
+				Rest = FREF - 2 * LPF;
+			Rest = (Rest * 6528) / (FREF / 10);
+			state->rest = Rest;
+
+			/* external loop filter, otherwise:
+			 * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4;
+			 * lo6 = 0x0e34 */
+
+			if (Rest == 0) {
+				if (pll->vco_band)
+					lo5 = 0x049f;
+				else
+					lo5 = 0x041f;
+			} else {
+				if (pll->vco_band)
+					lo5 = 0x049e;
+				else if (state->config->analog_output)
+					lo5 = 0x041d;
+				else
+					lo5 = 0x041c;
+			}
+
+			if (state->identity.p1g) {	/* Bias is done automatically in P1G */
+				if (state->identity.in_soc) {
+					if (state->identity.version == SOC_8090_P1G_11R1)
+						lo5 = 0x46f;
+					else
+						lo5 = 0x42f;
+				} else
+					lo5 = 0x42c;
+			}
+
+			lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7);	/* bit 15 is the split to the slave, we do not do it here */
+
+			if (!state->config->io.pll_int_loop_filt) {
+				if (state->identity.in_soc)
+					lo6 = 0xff98;
+				else if (state->identity.p1g || (Rest == 0))
+					lo6 = 0xfff8;
+				else
+					lo6 = 0xff28;
+			} else
+				lo6 = (state->config->io.pll_int_loop_filt << 3);
+
+			Den = 1;
+
+			if (Rest > 0) {
+				if (state->config->analog_output)
+					lo6 |= (1 << 2) | 2;
+				else {
+					if (state->identity.in_soc)
+						lo6 |= (1 << 2) | 2;
+					else
+						lo6 |= (1 << 2) | 2;
+				}
+				Den = 255;
+			}
+			dib0090_write_reg(state, 0x15, (u16) FBDiv);
+			if (state->config->fref_clock_ratio != 0)
+				dib0090_write_reg(state, 0x16, (Den << 8) | state->config->fref_clock_ratio);
+			else
+				dib0090_write_reg(state, 0x16, (Den << 8) | 1);
+			dib0090_write_reg(state, 0x17, (u16) Rest);
+			dib0090_write_reg(state, 0x19, lo5);
+			dib0090_write_reg(state, 0x1c, lo6);
+
+			lo6 = tune->tuner_enable;
+			if (state->config->analog_output)
+				lo6 = (lo6 & 0xff9f) | 0x2;
+
+			dib0090_write_reg(state, 0x24, lo6 | EN_LO | state->config->use_pwm_agc * EN_CRYSTAL);
+
+		}
+
+		state->current_rf = state->rf_request;
+		state->current_standard = state->fe->dtv_property_cache.delivery_system;
+
+		ret = 20;
+		state->calibrate = CAPTRIM_CAL;	/* captrim serach now */
+	}
+
+	else if (*tune_state == CT_TUNER_STEP_0) {	/* Warning : because of captrim cal, if you change this step, change it also in _cal.c file because it is the step following captrim cal state machine */
+		const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
+
+		while (state->current_rf / 1000 > wbd->max_freq)
+			wbd++;
+
+		dib0090_write_reg(state, 0x1e, 0x07ff);
+		dprintk("Final Captrim: %d", (u32) state->fcaptrim);
+		dprintk("HFDIV code: %d", (u32) pll->hfdiv_code);
+		dprintk("VCO = %d", (u32) pll->vco_band);
+		dprintk("VCOF in kHz: %d ((%d*%d) << 1))", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request);
+		dprintk("REFDIV: %d, FREF: %d", (u32) 1, (u32) state->config->io.clock_khz);
+		dprintk("FBDIV: %d, Rest: %d", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17));
+		dprintk("Num: %d, Den: %d, SD: %d", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8),
+			(u32) dib0090_read_reg(state, 0x1c) & 0x3);
+
+#define WBD     0x781		/* 1 1 1 1 0000 0 0 1 */
+		c = 4;
+		i = 3;
+
+		if (wbd->wbd_gain != 0)
+			c = wbd->wbd_gain;
+
+		state->wbdmux = (c << 13) | (i << 11) | (WBD | (state->config->use_pwm_agc << 1));
+		dib0090_write_reg(state, 0x10, state->wbdmux);
+
+		if ((tune->tuner_enable == EN_CAB) && state->identity.p1g) {
+			dprintk("P1G : The cable band is selected and lna_tune = %d", tune->lna_tune);
+			dib0090_write_reg(state, 0x09, tune->lna_bias);
+			dib0090_write_reg(state, 0x0b, 0xb800 | (tune->lna_tune << 6) | (tune->switch_trim));
+		} else
+			dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | tune->lna_bias);
+
+		dib0090_write_reg(state, 0x0c, tune->v2i);
+		dib0090_write_reg(state, 0x0d, tune->mix);
+		dib0090_write_reg(state, 0x0e, tune->load);
+		*tune_state = CT_TUNER_STEP_1;
+
+	} else if (*tune_state == CT_TUNER_STEP_1) {
+		/* initialize the lt gain register */
+		state->rf_lt_def = 0x7c00;
+
+		dib0090_set_bandwidth(state);
+		state->tuner_is_tuned = 1;
+
+		state->calibrate |= WBD_CAL;
+		state->calibrate |= TEMP_CAL;
+		*tune_state = CT_TUNER_STOP;
+	} else
+		ret = FE_CALLBACK_TIME_NEVER;
+	return ret;
+}
+
+static int dib0090_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+
+	return state->tune_state;
+}
+
+EXPORT_SYMBOL(dib0090_get_tune_state);
+
+int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+
+	state->tune_state = tune_state;
+	return 0;
+}
+
+EXPORT_SYMBOL(dib0090_set_tune_state);
+
+static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+
+	*frequency = 1000 * state->current_rf;
+	return 0;
+}
+
+static int dib0090_set_params(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	u32 ret;
+
+	state->tune_state = CT_TUNER_START;
+
+	do {
+		ret = dib0090_tune(fe);
+		if (ret != FE_CALLBACK_TIME_NEVER)
+			msleep(ret / 10);
+		else
+			break;
+	} while (state->tune_state != CT_TUNER_STOP);
+
+	return 0;
+}
+
+static const struct dvb_tuner_ops dib0090_ops = {
+	.info = {
+		 .name = "DiBcom DiB0090",
+		 .frequency_min = 45000000,
+		 .frequency_max = 860000000,
+		 .frequency_step = 1000,
+		 },
+	.release = dib0090_release,
+
+	.init = dib0090_wakeup,
+	.sleep = dib0090_sleep,
+	.set_params = dib0090_set_params,
+	.get_frequency = dib0090_get_frequency,
+};
+
+static const struct dvb_tuner_ops dib0090_fw_ops = {
+	.info = {
+		 .name = "DiBcom DiB0090",
+		 .frequency_min = 45000000,
+		 .frequency_max = 860000000,
+		 .frequency_step = 1000,
+		 },
+	.release = dib0090_release,
+
+	.init = NULL,
+	.sleep = NULL,
+	.set_params = NULL,
+	.get_frequency = NULL,
+};
+
+static const struct dib0090_wbd_slope dib0090_wbd_table_default[] = {
+	{470, 0, 250, 0, 100, 4},
+	{860, 51, 866, 21, 375, 4},
+	{1700, 0, 800, 0, 850, 4},
+	{2900, 0, 250, 0, 100, 6},
+	{0xFFFF, 0, 0, 0, 0, 0},
+};
+
+struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
+{
+	struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL);
+	if (st == NULL)
+		return NULL;
+
+	st->config = config;
+	st->i2c = i2c;
+	st->fe = fe;
+	mutex_init(&st->i2c_buffer_lock);
+	fe->tuner_priv = st;
+
+	if (config->wbd == NULL)
+		st->current_wbd_table = dib0090_wbd_table_default;
+	else
+		st->current_wbd_table = config->wbd;
+
+	if (dib0090_reset(fe) != 0)
+		goto free_mem;
+
+	printk(KERN_INFO "DiB0090: successfully identified\n");
+	memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops));
+
+	return fe;
+ free_mem:
+	kfree(st);
+	fe->tuner_priv = NULL;
+	return NULL;
+}
+
+EXPORT_SYMBOL(dib0090_register);
+
+struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
+{
+	struct dib0090_fw_state *st = kzalloc(sizeof(struct dib0090_fw_state), GFP_KERNEL);
+	if (st == NULL)
+		return NULL;
+
+	st->config = config;
+	st->i2c = i2c;
+	st->fe = fe;
+	mutex_init(&st->i2c_buffer_lock);
+	fe->tuner_priv = st;
+
+	if (dib0090_fw_reset_digital(fe, st->config) != 0)
+		goto free_mem;
+
+	dprintk("DiB0090 FW: successfully identified");
+	memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops));
+
+	return fe;
+free_mem:
+	kfree(st);
+	fe->tuner_priv = NULL;
+	return NULL;
+}
+EXPORT_SYMBOL(dib0090_fw_register);
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_AUTHOR("Olivier Grenie <olivier.grenie@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/dib0090.h b/drivers/media/dvb-frontends/dib0090.h
new file mode 100644
index 0000000..781dc49
--- /dev/null
+++ b/drivers/media/dvb-frontends/dib0090.h
@@ -0,0 +1,187 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner.
+ *
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
+ *
+ * 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, version 2.
+ */
+#ifndef DIB0090_H
+#define DIB0090_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+#define DEFAULT_DIB0090_I2C_ADDRESS 0x60
+
+struct dib0090_io_config {
+	u32 clock_khz;
+
+	u8 pll_bypass:1;
+	u8 pll_range:1;
+	u8 pll_prediv:6;
+	u8 pll_loopdiv:6;
+
+	u8 adc_clock_ratio;	/* valid is 8, 7 ,6 */
+	u16 pll_int_loop_filt;
+};
+
+struct dib0090_wbd_slope {
+	u16 max_freq;		/* for every frequency less than or equal to that field: this information is correct */
+	u16 slope_cold;
+	u16 offset_cold;
+	u16 slope_hot;
+	u16 offset_hot;
+	u8 wbd_gain;
+};
+
+struct dib0090_low_if_offset_table {
+	int std;
+	u32 RF_freq;
+	s32 offset_khz;
+};
+
+struct dib0090_config {
+	struct dib0090_io_config io;
+	int (*reset) (struct dvb_frontend *, int);
+	int (*sleep) (struct dvb_frontend *, int);
+
+	/*  offset in kHz */
+	int freq_offset_khz_uhf;
+	int freq_offset_khz_vhf;
+
+	int (*get_adc_power) (struct dvb_frontend *);
+
+	u8 clkouttobamse:1;	/* activate or deactivate clock output */
+	u8 analog_output;
+
+	u8 i2c_address;
+	/* add drives and other things if necessary */
+	u16 wbd_vhf_offset;
+	u16 wbd_cband_offset;
+	u8 use_pwm_agc;
+	u8 clkoutdrive;
+
+	u8 ls_cfg_pad_drv;
+	u8 data_tx_drv;
+
+	u8 in_soc;
+	const struct dib0090_low_if_offset_table *low_if;
+	u8 fref_clock_ratio;
+	u16 force_cband_input;
+	struct dib0090_wbd_slope *wbd;
+	u8 is_dib7090e;
+	u8 force_crystal_mode;
+};
+
+#if defined(CONFIG_DVB_TUNER_DIB0090) || (defined(CONFIG_DVB_TUNER_DIB0090_MODULE) && defined(MODULE))
+extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config);
+extern struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config);
+extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast);
+extern void dib0090_pwm_gain_reset(struct dvb_frontend *fe);
+extern u16 dib0090_get_wbd_target(struct dvb_frontend *tuner);
+extern u16 dib0090_get_wbd_offset(struct dvb_frontend *fe);
+extern int dib0090_gain_control(struct dvb_frontend *fe);
+extern enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe);
+extern int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state);
+extern void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt);
+extern void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff);
+extern int dib0090_set_switch(struct dvb_frontend *fe, u8 sw1, u8 sw2, u8 sw3);
+extern int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff);
+extern int dib0090_update_rframp_7090(struct dvb_frontend *fe,
+		u8 cfg_sensitivity);
+extern int dib0090_update_tuning_table_7090(struct dvb_frontend *fe,
+		u8 cfg_sensitivity);
+#else
+static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0090_config *config)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+
+static inline void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+
+static inline u16 dib0090_get_wbd_target(struct dvb_frontend *tuner)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return 0;
+}
+
+static inline u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return 0;
+}
+
+static inline int dib0090_gain_control(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return CT_DONE;
+}
+
+static inline int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+
+static inline void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+
+static inline int dib0090_set_switch(struct dvb_frontend *fe,
+		u8 sw1, u8 sw2, u8 sw3)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib0090_update_rframp_7090(struct dvb_frontend *fe,
+		u8 cfg_sensitivity)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib0090_update_tuning_table_7090(struct dvb_frontend *fe,
+		u8 cfg_sensitivity)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb-frontends/dib3000.h b/drivers/media/dvb-frontends/dib3000.h
new file mode 100644
index 0000000..404f63a
--- /dev/null
+++ b/drivers/media/dvb-frontends/dib3000.h
@@ -0,0 +1,56 @@
+/*
+ * public header file of the frontend drivers for mobile DVB-T demodulators
+ * DiBcom 3000M-B and DiBcom 3000P/M-C (http://www.dibcom.fr/)
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * based on GPL code from DibCom, which has
+ *
+ * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+ *
+ *	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, version 2.
+ *
+ * Acknowledgements
+ *
+ *  Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
+ *  sources, on which this driver (and the dvb-dibusb) are based.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ *
+ */
+
+#ifndef DIB3000_H
+#define DIB3000_H
+
+#include <linux/dvb/frontend.h>
+
+struct dib3000_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+};
+
+struct dib_fe_xfer_ops
+{
+	/* pid and transfer handling is done in the demodulator */
+	int (*pid_parse)(struct dvb_frontend *fe, int onoff);
+	int (*fifo_ctrl)(struct dvb_frontend *fe, int onoff);
+	int (*pid_ctrl)(struct dvb_frontend *fe, int index, int pid, int onoff);
+	int (*tuner_pass_ctrl)(struct dvb_frontend *fe, int onoff, u8 pll_ctrl);
+};
+
+#if defined(CONFIG_DVB_DIB3000MB) || (defined(CONFIG_DVB_DIB3000MB_MODULE) && defined(MODULE))
+extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
+					     struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops);
+#else
+static inline struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
+					     struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_DIB3000MB
+
+#endif // DIB3000_H
diff --git a/drivers/media/dvb-frontends/dib3000mb.c b/drivers/media/dvb-frontends/dib3000mb.c
new file mode 100644
index 0000000..af91e0c
--- /dev/null
+++ b/drivers/media/dvb-frontends/dib3000mb.c
@@ -0,0 +1,829 @@
+/*
+ * Frontend driver for mobile DVB-T demodulator DiBcom 3000M-B
+ * DiBcom (http://www.dibcom.fr/)
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * based on GPL code from DibCom, which has
+ *
+ * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+ *
+ *	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, version 2.
+ *
+ * Acknowledgements
+ *
+ *  Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
+ *  sources, on which this driver (and the dvb-dibusb) are based.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+
+#include "dib3000.h"
+#include "dib3000mb_priv.h"
+
+/* Version information */
+#define DRIVER_VERSION "0.1"
+#define DRIVER_DESC "DiBcom 3000M-B DVB-T demodulator"
+#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able)).");
+
+#define deb_info(args...) dprintk(0x01,args)
+#define deb_i2c(args...)  dprintk(0x02,args)
+#define deb_srch(args...) dprintk(0x04,args)
+#define deb_info(args...) dprintk(0x01,args)
+#define deb_xfer(args...) dprintk(0x02,args)
+#define deb_setf(args...) dprintk(0x04,args)
+#define deb_getf(args...) dprintk(0x08,args)
+
+static int dib3000_read_reg(struct dib3000_state *state, u16 reg)
+{
+	u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
+	u8 rb[2];
+	struct i2c_msg msg[] = {
+		{ .addr = state->config.demod_address, .flags = 0,        .buf = wb, .len = 2 },
+		{ .addr = state->config.demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 },
+	};
+
+	if (i2c_transfer(state->i2c, msg, 2) != 2)
+		deb_i2c("i2c read error\n");
+
+	deb_i2c("reading i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,
+			(rb[0] << 8) | rb[1],(rb[0] << 8) | rb[1]);
+
+	return (rb[0] << 8) | rb[1];
+}
+
+static int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val)
+{
+	u8 b[] = {
+		(reg >> 8) & 0xff, reg & 0xff,
+		(val >> 8) & 0xff, val & 0xff,
+	};
+	struct i2c_msg msg[] = {
+		{ .addr = state->config.demod_address, .flags = 0, .buf = b, .len = 4 }
+	};
+	deb_i2c("writing i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,val,val);
+
+	return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0;
+}
+
+static int dib3000_search_status(u16 irq,u16 lock)
+{
+	if (irq & 0x02) {
+		if (lock & 0x01) {
+			deb_srch("auto search succeeded\n");
+			return 1; // auto search succeeded
+		} else {
+			deb_srch("auto search not successful\n");
+			return 0; // auto search failed
+		}
+	} else if (irq & 0x01)  {
+		deb_srch("auto search failed\n");
+		return 0; // auto search failed
+	}
+	return -1; // try again
+}
+
+/* for auto search */
+static u16 dib3000_seq[2][2][2] =     /* fft,gua,   inv   */
+	{ /* fft */
+		{ /* gua */
+			{ 0, 1 },                   /*  0   0   { 0,1 } */
+			{ 3, 9 },                   /*  0   1   { 0,1 } */
+		},
+		{
+			{ 2, 5 },                   /*  1   0   { 0,1 } */
+			{ 6, 11 },                  /*  1   1   { 0,1 } */
+		}
+	};
+
+static int dib3000mb_get_frontend(struct dvb_frontend* fe);
+
+static int dib3000mb_set_frontend(struct dvb_frontend *fe, int tuner)
+{
+	struct dib3000_state* state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	fe_code_rate_t fe_cr = FEC_NONE;
+	int search_state, seq;
+
+	if (tuner && fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+
+		deb_setf("bandwidth: ");
+		switch (c->bandwidth_hz) {
+			case 8000000:
+				deb_setf("8 MHz\n");
+				wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]);
+				wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz);
+				break;
+			case 7000000:
+				deb_setf("7 MHz\n");
+				wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[1]);
+				wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_7mhz);
+				break;
+			case 6000000:
+				deb_setf("6 MHz\n");
+				wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[0]);
+				wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_6mhz);
+				break;
+			case 0:
+				return -EOPNOTSUPP;
+			default:
+				err("unknown bandwidth value.");
+				return -EINVAL;
+		}
+	}
+	wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4);
+
+	deb_setf("transmission mode: ");
+	switch (c->transmission_mode) {
+		case TRANSMISSION_MODE_2K:
+			deb_setf("2k\n");
+			wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_2K);
+			break;
+		case TRANSMISSION_MODE_8K:
+			deb_setf("8k\n");
+			wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_8K);
+			break;
+		case TRANSMISSION_MODE_AUTO:
+			deb_setf("auto\n");
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	deb_setf("guard: ");
+	switch (c->guard_interval) {
+		case GUARD_INTERVAL_1_32:
+			deb_setf("1_32\n");
+			wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_32);
+			break;
+		case GUARD_INTERVAL_1_16:
+			deb_setf("1_16\n");
+			wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_16);
+			break;
+		case GUARD_INTERVAL_1_8:
+			deb_setf("1_8\n");
+			wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_8);
+			break;
+		case GUARD_INTERVAL_1_4:
+			deb_setf("1_4\n");
+			wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_4);
+			break;
+		case GUARD_INTERVAL_AUTO:
+			deb_setf("auto\n");
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	deb_setf("inversion: ");
+	switch (c->inversion) {
+		case INVERSION_OFF:
+			deb_setf("off\n");
+			wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_OFF);
+			break;
+		case INVERSION_AUTO:
+			deb_setf("auto ");
+			break;
+		case INVERSION_ON:
+			deb_setf("on\n");
+			wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_ON);
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	deb_setf("modulation: ");
+	switch (c->modulation) {
+		case QPSK:
+			deb_setf("qpsk\n");
+			wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_QPSK);
+			break;
+		case QAM_16:
+			deb_setf("qam16\n");
+			wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_16QAM);
+			break;
+		case QAM_64:
+			deb_setf("qam64\n");
+			wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_64QAM);
+			break;
+		case QAM_AUTO:
+			break;
+		default:
+			return -EINVAL;
+	}
+	deb_setf("hierarchy: ");
+	switch (c->hierarchy) {
+		case HIERARCHY_NONE:
+			deb_setf("none ");
+			/* fall through */
+		case HIERARCHY_1:
+			deb_setf("alpha=1\n");
+			wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_1);
+			break;
+		case HIERARCHY_2:
+			deb_setf("alpha=2\n");
+			wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_2);
+			break;
+		case HIERARCHY_4:
+			deb_setf("alpha=4\n");
+			wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_4);
+			break;
+		case HIERARCHY_AUTO:
+			deb_setf("alpha=auto\n");
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	deb_setf("hierarchy: ");
+	if (c->hierarchy == HIERARCHY_NONE) {
+		deb_setf("none\n");
+		wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_OFF);
+		wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_HP);
+		fe_cr = c->code_rate_HP;
+	} else if (c->hierarchy != HIERARCHY_AUTO) {
+		deb_setf("on\n");
+		wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_ON);
+		wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_LP);
+		fe_cr = c->code_rate_LP;
+	}
+	deb_setf("fec: ");
+	switch (fe_cr) {
+		case FEC_1_2:
+			deb_setf("1_2\n");
+			wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_1_2);
+			break;
+		case FEC_2_3:
+			deb_setf("2_3\n");
+			wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_2_3);
+			break;
+		case FEC_3_4:
+			deb_setf("3_4\n");
+			wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_3_4);
+			break;
+		case FEC_5_6:
+			deb_setf("5_6\n");
+			wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_5_6);
+			break;
+		case FEC_7_8:
+			deb_setf("7_8\n");
+			wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_7_8);
+			break;
+		case FEC_NONE:
+			deb_setf("none ");
+			break;
+		case FEC_AUTO:
+			deb_setf("auto\n");
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	seq = dib3000_seq
+		[c->transmission_mode == TRANSMISSION_MODE_AUTO]
+		[c->guard_interval == GUARD_INTERVAL_AUTO]
+		[c->inversion == INVERSION_AUTO];
+
+	deb_setf("seq? %d\n", seq);
+
+	wr(DIB3000MB_REG_SEQ, seq);
+
+	wr(DIB3000MB_REG_ISI, seq ? DIB3000MB_ISI_INHIBIT : DIB3000MB_ISI_ACTIVATE);
+
+	if (c->transmission_mode == TRANSMISSION_MODE_2K) {
+		if (c->guard_interval == GUARD_INTERVAL_1_8) {
+			wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_2K_1_8);
+		} else {
+			wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_DEFAULT);
+		}
+
+		wr(DIB3000MB_REG_UNK_121, DIB3000MB_UNK_121_2K);
+	} else {
+		wr(DIB3000MB_REG_UNK_121, DIB3000MB_UNK_121_DEFAULT);
+	}
+
+	wr(DIB3000MB_REG_MOBILE_ALGO, DIB3000MB_MOBILE_ALGO_OFF);
+	wr(DIB3000MB_REG_MOBILE_MODE_QAM, DIB3000MB_MOBILE_MODE_QAM_OFF);
+	wr(DIB3000MB_REG_MOBILE_MODE, DIB3000MB_MOBILE_MODE_OFF);
+
+	wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_high);
+
+	wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_ACTIVATE);
+
+	wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC + DIB3000MB_RESTART_CTRL);
+	wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF);
+
+	/* wait for AGC lock */
+	msleep(70);
+
+	wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low);
+
+	/* something has to be auto searched */
+	if (c->modulation == QAM_AUTO ||
+		c->hierarchy == HIERARCHY_AUTO ||
+		fe_cr == FEC_AUTO ||
+		c->inversion == INVERSION_AUTO) {
+		int as_count=0;
+
+		deb_setf("autosearch enabled.\n");
+
+		wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_INHIBIT);
+
+		wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AUTO_SEARCH);
+		wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF);
+
+		while ((search_state =
+				dib3000_search_status(
+					rd(DIB3000MB_REG_AS_IRQ_PENDING),
+					rd(DIB3000MB_REG_LOCK2_VALUE))) < 0 && as_count++ < 100)
+			msleep(1);
+
+		deb_setf("search_state after autosearch %d after %d checks\n",search_state,as_count);
+
+		if (search_state == 1) {
+			if (dib3000mb_get_frontend(fe) == 0) {
+				deb_setf("reading tuning data from frontend succeeded.\n");
+				return dib3000mb_set_frontend(fe, 0);
+			}
+		}
+
+	} else {
+		wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_CTRL);
+		wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF);
+	}
+
+	return 0;
+}
+
+static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
+{
+	struct dib3000_state* state = fe->demodulator_priv;
+
+	deb_info("dib3000mb is getting up.\n");
+	wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_UP);
+
+	wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC);
+
+	wr(DIB3000MB_REG_RESET_DEVICE, DIB3000MB_RESET_DEVICE);
+	wr(DIB3000MB_REG_RESET_DEVICE, DIB3000MB_RESET_DEVICE_RST);
+
+	wr(DIB3000MB_REG_CLOCK, DIB3000MB_CLOCK_DEFAULT);
+
+	wr(DIB3000MB_REG_ELECT_OUT_MODE, DIB3000MB_ELECT_OUT_MODE_ON);
+
+	wr(DIB3000MB_REG_DDS_FREQ_MSB, DIB3000MB_DDS_FREQ_MSB);
+	wr(DIB3000MB_REG_DDS_FREQ_LSB, DIB3000MB_DDS_FREQ_LSB);
+
+	wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]);
+
+	wr_foreach(dib3000mb_reg_impulse_noise,
+			dib3000mb_impulse_noise_values[DIB3000MB_IMPNOISE_OFF]);
+
+	wr_foreach(dib3000mb_reg_agc_gain, dib3000mb_default_agc_gain);
+
+	wr(DIB3000MB_REG_PHASE_NOISE, DIB3000MB_PHASE_NOISE_DEFAULT);
+
+	wr_foreach(dib3000mb_reg_phase_noise, dib3000mb_default_noise_phase);
+
+	wr_foreach(dib3000mb_reg_lock_duration, dib3000mb_default_lock_duration);
+
+	wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low);
+
+	wr(DIB3000MB_REG_LOCK0_MASK, DIB3000MB_LOCK0_DEFAULT);
+	wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4);
+	wr(DIB3000MB_REG_LOCK2_MASK, DIB3000MB_LOCK2_DEFAULT);
+	wr(DIB3000MB_REG_SEQ, dib3000_seq[1][1][1]);
+
+	wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz);
+
+	wr(DIB3000MB_REG_UNK_68, DIB3000MB_UNK_68);
+	wr(DIB3000MB_REG_UNK_69, DIB3000MB_UNK_69);
+	wr(DIB3000MB_REG_UNK_71, DIB3000MB_UNK_71);
+	wr(DIB3000MB_REG_UNK_77, DIB3000MB_UNK_77);
+	wr(DIB3000MB_REG_UNK_78, DIB3000MB_UNK_78);
+	wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_INHIBIT);
+	wr(DIB3000MB_REG_UNK_92, DIB3000MB_UNK_92);
+	wr(DIB3000MB_REG_UNK_96, DIB3000MB_UNK_96);
+	wr(DIB3000MB_REG_UNK_97, DIB3000MB_UNK_97);
+	wr(DIB3000MB_REG_UNK_106, DIB3000MB_UNK_106);
+	wr(DIB3000MB_REG_UNK_107, DIB3000MB_UNK_107);
+	wr(DIB3000MB_REG_UNK_108, DIB3000MB_UNK_108);
+	wr(DIB3000MB_REG_UNK_122, DIB3000MB_UNK_122);
+	wr(DIB3000MB_REG_MOBILE_MODE_QAM, DIB3000MB_MOBILE_MODE_QAM_OFF);
+	wr(DIB3000MB_REG_BERLEN, DIB3000MB_BERLEN_DEFAULT);
+
+	wr_foreach(dib3000mb_reg_filter_coeffs, dib3000mb_filter_coeffs);
+
+	wr(DIB3000MB_REG_MOBILE_ALGO, DIB3000MB_MOBILE_ALGO_ON);
+	wr(DIB3000MB_REG_MULTI_DEMOD_MSB, DIB3000MB_MULTI_DEMOD_MSB);
+	wr(DIB3000MB_REG_MULTI_DEMOD_LSB, DIB3000MB_MULTI_DEMOD_LSB);
+
+	wr(DIB3000MB_REG_OUTPUT_MODE, DIB3000MB_OUTPUT_MODE_SLAVE);
+
+	wr(DIB3000MB_REG_FIFO_142, DIB3000MB_FIFO_142);
+	wr(DIB3000MB_REG_MPEG2_OUT_MODE, DIB3000MB_MPEG2_OUT_MODE_188);
+	wr(DIB3000MB_REG_PID_PARSE, DIB3000MB_PID_PARSE_ACTIVATE);
+	wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_INHIBIT);
+	wr(DIB3000MB_REG_FIFO_146, DIB3000MB_FIFO_146);
+	wr(DIB3000MB_REG_FIFO_147, DIB3000MB_FIFO_147);
+
+	wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF);
+
+	return 0;
+}
+
+static int dib3000mb_get_frontend(struct dvb_frontend* fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct dib3000_state* state = fe->demodulator_priv;
+	fe_code_rate_t *cr;
+	u16 tps_val;
+	int inv_test1,inv_test2;
+	u32 dds_val, threshold = 0x800000;
+
+	if (!rd(DIB3000MB_REG_TPS_LOCK))
+		return 0;
+
+	dds_val = ((rd(DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_VALUE_LSB);
+	deb_getf("DDS_VAL: %x %x %x",dds_val, rd(DIB3000MB_REG_DDS_VALUE_MSB), rd(DIB3000MB_REG_DDS_VALUE_LSB));
+	if (dds_val < threshold)
+		inv_test1 = 0;
+	else if (dds_val == threshold)
+		inv_test1 = 1;
+	else
+		inv_test1 = 2;
+
+	dds_val = ((rd(DIB3000MB_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_FREQ_LSB);
+	deb_getf("DDS_FREQ: %x %x %x",dds_val, rd(DIB3000MB_REG_DDS_FREQ_MSB), rd(DIB3000MB_REG_DDS_FREQ_LSB));
+	if (dds_val < threshold)
+		inv_test2 = 0;
+	else if (dds_val == threshold)
+		inv_test2 = 1;
+	else
+		inv_test2 = 2;
+
+	c->inversion =
+		((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) ||
+		((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ?
+		INVERSION_ON : INVERSION_OFF;
+
+	deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, c->inversion);
+
+	switch ((tps_val = rd(DIB3000MB_REG_TPS_QAM))) {
+		case DIB3000_CONSTELLATION_QPSK:
+			deb_getf("QPSK ");
+			c->modulation = QPSK;
+			break;
+		case DIB3000_CONSTELLATION_16QAM:
+			deb_getf("QAM16 ");
+			c->modulation = QAM_16;
+			break;
+		case DIB3000_CONSTELLATION_64QAM:
+			deb_getf("QAM64 ");
+			c->modulation = QAM_64;
+			break;
+		default:
+			err("Unexpected constellation returned by TPS (%d)", tps_val);
+			break;
+	}
+	deb_getf("TPS: %d\n", tps_val);
+
+	if (rd(DIB3000MB_REG_TPS_HRCH)) {
+		deb_getf("HRCH ON\n");
+		cr = &c->code_rate_LP;
+		c->code_rate_HP = FEC_NONE;
+		switch ((tps_val = rd(DIB3000MB_REG_TPS_VIT_ALPHA))) {
+			case DIB3000_ALPHA_0:
+				deb_getf("HIERARCHY_NONE ");
+				c->hierarchy = HIERARCHY_NONE;
+				break;
+			case DIB3000_ALPHA_1:
+				deb_getf("HIERARCHY_1 ");
+				c->hierarchy = HIERARCHY_1;
+				break;
+			case DIB3000_ALPHA_2:
+				deb_getf("HIERARCHY_2 ");
+				c->hierarchy = HIERARCHY_2;
+				break;
+			case DIB3000_ALPHA_4:
+				deb_getf("HIERARCHY_4 ");
+				c->hierarchy = HIERARCHY_4;
+				break;
+			default:
+				err("Unexpected ALPHA value returned by TPS (%d)", tps_val);
+				break;
+		}
+		deb_getf("TPS: %d\n", tps_val);
+
+		tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP);
+	} else {
+		deb_getf("HRCH OFF\n");
+		cr = &c->code_rate_HP;
+		c->code_rate_LP = FEC_NONE;
+		c->hierarchy = HIERARCHY_NONE;
+
+		tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP);
+	}
+
+	switch (tps_val) {
+		case DIB3000_FEC_1_2:
+			deb_getf("FEC_1_2 ");
+			*cr = FEC_1_2;
+			break;
+		case DIB3000_FEC_2_3:
+			deb_getf("FEC_2_3 ");
+			*cr = FEC_2_3;
+			break;
+		case DIB3000_FEC_3_4:
+			deb_getf("FEC_3_4 ");
+			*cr = FEC_3_4;
+			break;
+		case DIB3000_FEC_5_6:
+			deb_getf("FEC_5_6 ");
+			*cr = FEC_4_5;
+			break;
+		case DIB3000_FEC_7_8:
+			deb_getf("FEC_7_8 ");
+			*cr = FEC_7_8;
+			break;
+		default:
+			err("Unexpected FEC returned by TPS (%d)", tps_val);
+			break;
+	}
+	deb_getf("TPS: %d\n",tps_val);
+
+	switch ((tps_val = rd(DIB3000MB_REG_TPS_GUARD_TIME))) {
+		case DIB3000_GUARD_TIME_1_32:
+			deb_getf("GUARD_INTERVAL_1_32 ");
+			c->guard_interval = GUARD_INTERVAL_1_32;
+			break;
+		case DIB3000_GUARD_TIME_1_16:
+			deb_getf("GUARD_INTERVAL_1_16 ");
+			c->guard_interval = GUARD_INTERVAL_1_16;
+			break;
+		case DIB3000_GUARD_TIME_1_8:
+			deb_getf("GUARD_INTERVAL_1_8 ");
+			c->guard_interval = GUARD_INTERVAL_1_8;
+			break;
+		case DIB3000_GUARD_TIME_1_4:
+			deb_getf("GUARD_INTERVAL_1_4 ");
+			c->guard_interval = GUARD_INTERVAL_1_4;
+			break;
+		default:
+			err("Unexpected Guard Time returned by TPS (%d)", tps_val);
+			break;
+	}
+	deb_getf("TPS: %d\n", tps_val);
+
+	switch ((tps_val = rd(DIB3000MB_REG_TPS_FFT))) {
+		case DIB3000_TRANSMISSION_MODE_2K:
+			deb_getf("TRANSMISSION_MODE_2K ");
+			c->transmission_mode = TRANSMISSION_MODE_2K;
+			break;
+		case DIB3000_TRANSMISSION_MODE_8K:
+			deb_getf("TRANSMISSION_MODE_8K ");
+			c->transmission_mode = TRANSMISSION_MODE_8K;
+			break;
+		default:
+			err("unexpected transmission mode return by TPS (%d)", tps_val);
+			break;
+	}
+	deb_getf("TPS: %d\n", tps_val);
+
+	return 0;
+}
+
+static int dib3000mb_read_status(struct dvb_frontend* fe, fe_status_t *stat)
+{
+	struct dib3000_state* state = fe->demodulator_priv;
+
+	*stat = 0;
+
+	if (rd(DIB3000MB_REG_AGC_LOCK))
+		*stat |= FE_HAS_SIGNAL;
+	if (rd(DIB3000MB_REG_CARRIER_LOCK))
+		*stat |= FE_HAS_CARRIER;
+	if (rd(DIB3000MB_REG_VIT_LCK))
+		*stat |= FE_HAS_VITERBI;
+	if (rd(DIB3000MB_REG_TS_SYNC_LOCK))
+		*stat |= (FE_HAS_SYNC | FE_HAS_LOCK);
+
+	deb_getf("actual status is %2x\n",*stat);
+
+	deb_getf("autoval: tps: %d, qam: %d, hrch: %d, alpha: %d, hp: %d, lp: %d, guard: %d, fft: %d cell: %d\n",
+			rd(DIB3000MB_REG_TPS_LOCK),
+			rd(DIB3000MB_REG_TPS_QAM),
+			rd(DIB3000MB_REG_TPS_HRCH),
+			rd(DIB3000MB_REG_TPS_VIT_ALPHA),
+			rd(DIB3000MB_REG_TPS_CODE_RATE_HP),
+			rd(DIB3000MB_REG_TPS_CODE_RATE_LP),
+			rd(DIB3000MB_REG_TPS_GUARD_TIME),
+			rd(DIB3000MB_REG_TPS_FFT),
+			rd(DIB3000MB_REG_TPS_CELL_ID));
+
+	//*stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+	return 0;
+}
+
+static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+	struct dib3000_state* state = fe->demodulator_priv;
+
+	*ber = ((rd(DIB3000MB_REG_BER_MSB) << 16) | rd(DIB3000MB_REG_BER_LSB));
+	return 0;
+}
+
+/* see dib3000-watch dvb-apps for exact calcuations of signal_strength and snr */
+static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+	struct dib3000_state* state = fe->demodulator_priv;
+
+	*strength = rd(DIB3000MB_REG_SIGNAL_POWER) * 0xffff / 0x170;
+	return 0;
+}
+
+static int dib3000mb_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+	struct dib3000_state* state = fe->demodulator_priv;
+	short sigpow = rd(DIB3000MB_REG_SIGNAL_POWER);
+	int icipow = ((rd(DIB3000MB_REG_NOISE_POWER_MSB) & 0xff) << 16) |
+		rd(DIB3000MB_REG_NOISE_POWER_LSB);
+	*snr = (sigpow << 8) / ((icipow > 0) ? icipow : 1);
+	return 0;
+}
+
+static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+	struct dib3000_state* state = fe->demodulator_priv;
+
+	*unc = rd(DIB3000MB_REG_PACKET_ERROR_RATE);
+	return 0;
+}
+
+static int dib3000mb_sleep(struct dvb_frontend* fe)
+{
+	struct dib3000_state* state = fe->demodulator_priv;
+	deb_info("dib3000mb is going to bed.\n");
+	wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_DOWN);
+	return 0;
+}
+
+static int dib3000mb_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 800;
+	return 0;
+}
+
+static int dib3000mb_fe_init_nonmobile(struct dvb_frontend* fe)
+{
+	return dib3000mb_fe_init(fe, 0);
+}
+
+static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend *fe)
+{
+	return dib3000mb_set_frontend(fe, 1);
+}
+
+static void dib3000mb_release(struct dvb_frontend* fe)
+{
+	struct dib3000_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+/* pid filter and transfer stuff */
+static int dib3000mb_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff)
+{
+	struct dib3000_state *state = fe->demodulator_priv;
+	pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0);
+	wr(index+DIB3000MB_REG_FIRST_PID,pid);
+	return 0;
+}
+
+static int dib3000mb_fifo_control(struct dvb_frontend *fe, int onoff)
+{
+	struct dib3000_state *state = fe->demodulator_priv;
+
+	deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling");
+	if (onoff) {
+		wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_ACTIVATE);
+	} else {
+		wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_INHIBIT);
+	}
+	return 0;
+}
+
+static int dib3000mb_pid_parse(struct dvb_frontend *fe, int onoff)
+{
+	struct dib3000_state *state = fe->demodulator_priv;
+	deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling");
+	wr(DIB3000MB_REG_PID_PARSE,onoff);
+	return 0;
+}
+
+static int dib3000mb_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr)
+{
+	struct dib3000_state *state = fe->demodulator_priv;
+	if (onoff) {
+		wr(DIB3000MB_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr));
+	} else {
+		wr(DIB3000MB_REG_TUNER, DIB3000_TUNER_WRITE_DISABLE(pll_addr));
+	}
+	return 0;
+}
+
+static struct dvb_frontend_ops dib3000mb_ops;
+
+struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
+				      struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops)
+{
+	struct dib3000_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct dib3000_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->i2c = i2c;
+	memcpy(&state->config,config,sizeof(struct dib3000_config));
+
+	/* check for the correct demod */
+	if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
+		goto error;
+
+	if (rd(DIB3000_REG_DEVICE_ID) != DIB3000MB_DEVICE_ID)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	/* set the xfer operations */
+	xfer_ops->pid_parse = dib3000mb_pid_parse;
+	xfer_ops->fifo_ctrl = dib3000mb_fifo_control;
+	xfer_ops->pid_ctrl = dib3000mb_pid_control;
+	xfer_ops->tuner_pass_ctrl = dib3000mb_tuner_pass_ctrl;
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops dib3000mb_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name			= "DiBcom 3000M-B DVB-T",
+		.frequency_min		= 44250000,
+		.frequency_max		= 867250000,
+		.frequency_stepsize	= 62500,
+		.caps = FE_CAN_INVERSION_AUTO |
+				FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+				FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+				FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+				FE_CAN_TRANSMISSION_MODE_AUTO |
+				FE_CAN_GUARD_INTERVAL_AUTO |
+				FE_CAN_RECOVER |
+				FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.release = dib3000mb_release,
+
+	.init = dib3000mb_fe_init_nonmobile,
+	.sleep = dib3000mb_sleep,
+
+	.set_frontend = dib3000mb_set_frontend_and_tuner,
+	.get_frontend = dib3000mb_get_frontend,
+	.get_tune_settings = dib3000mb_fe_get_tune_settings,
+
+	.read_status = dib3000mb_read_status,
+	.read_ber = dib3000mb_read_ber,
+	.read_signal_strength = dib3000mb_read_signal_strength,
+	.read_snr = dib3000mb_read_snr,
+	.read_ucblocks = dib3000mb_read_unc_blocks,
+};
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(dib3000mb_attach);
diff --git a/drivers/media/dvb-frontends/dib3000mb_priv.h b/drivers/media/dvb-frontends/dib3000mb_priv.h
new file mode 100644
index 0000000..9dc235a
--- /dev/null
+++ b/drivers/media/dvb-frontends/dib3000mb_priv.h
@@ -0,0 +1,556 @@
+/*
+ * dib3000mb_priv.h
+ *
+ * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2.
+ *
+ * for more information see dib3000mb.c .
+ */
+
+#ifndef __DIB3000MB_PRIV_H_INCLUDED__
+#define __DIB3000MB_PRIV_H_INCLUDED__
+
+/* info and err, taken from usb.h, if there is anything available like by default. */
+#define err(format, arg...)  printk(KERN_ERR     "dib3000: " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO    "dib3000: " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "dib3000: " format "\n" , ## arg)
+
+/* handy shortcuts */
+#define rd(reg) dib3000_read_reg(state,reg)
+
+#define wr(reg,val) if (dib3000_write_reg(state,reg,val)) \
+	{ err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; }
+
+#define wr_foreach(a,v) { int i; \
+	if (sizeof(a) != sizeof(v)) \
+		err("sizeof: %zu %zu is different",sizeof(a),sizeof(v));\
+	for (i=0; i < sizeof(a)/sizeof(u16); i++) \
+		wr(a[i],v[i]); \
+	}
+
+#define set_or(reg,val) wr(reg,rd(reg) | val)
+
+#define set_and(reg,val) wr(reg,rd(reg) & val)
+
+/* debug */
+
+#define dprintk(level,args...) \
+    do { if ((debug & level)) { printk(args); } } while (0)
+
+/* mask for enabling a specific pid for the pid_filter */
+#define DIB3000_ACTIVATE_PID_FILTERING	(0x2000)
+
+/* common values for tuning */
+#define DIB3000_ALPHA_0					(     0)
+#define DIB3000_ALPHA_1					(     1)
+#define DIB3000_ALPHA_2					(     2)
+#define DIB3000_ALPHA_4					(     4)
+
+#define DIB3000_CONSTELLATION_QPSK		(     0)
+#define DIB3000_CONSTELLATION_16QAM		(     1)
+#define DIB3000_CONSTELLATION_64QAM		(     2)
+
+#define DIB3000_GUARD_TIME_1_32			(     0)
+#define DIB3000_GUARD_TIME_1_16			(     1)
+#define DIB3000_GUARD_TIME_1_8			(     2)
+#define DIB3000_GUARD_TIME_1_4			(     3)
+
+#define DIB3000_TRANSMISSION_MODE_2K	(     0)
+#define DIB3000_TRANSMISSION_MODE_8K	(     1)
+
+#define DIB3000_SELECT_LP				(     0)
+#define DIB3000_SELECT_HP				(     1)
+
+#define DIB3000_FEC_1_2					(     1)
+#define DIB3000_FEC_2_3					(     2)
+#define DIB3000_FEC_3_4					(     3)
+#define DIB3000_FEC_5_6					(     5)
+#define DIB3000_FEC_7_8					(     7)
+
+#define DIB3000_HRCH_OFF				(     0)
+#define DIB3000_HRCH_ON					(     1)
+
+#define DIB3000_DDS_INVERSION_OFF		(     0)
+#define DIB3000_DDS_INVERSION_ON		(     1)
+
+#define DIB3000_TUNER_WRITE_ENABLE(a)	(0xffff & (a << 8))
+#define DIB3000_TUNER_WRITE_DISABLE(a)	(0xffff & ((a << 8) | (1 << 7)))
+
+#define DIB3000_REG_MANUFACTOR_ID		(  1025)
+#define DIB3000_I2C_ID_DIBCOM			(0x01b3)
+
+#define DIB3000_REG_DEVICE_ID			(  1026)
+#define DIB3000MB_DEVICE_ID				(0x3000)
+#define DIB3000MC_DEVICE_ID				(0x3001)
+#define DIB3000P_DEVICE_ID				(0x3002)
+
+/* frontend state */
+struct dib3000_state {
+	struct i2c_adapter* i2c;
+
+/* configuration settings */
+	struct dib3000_config config;
+
+	struct dvb_frontend frontend;
+	int timing_offset;
+	int timing_offset_comp_done;
+
+	u32 last_tuned_bw;
+	u32 last_tuned_freq;
+};
+
+/* register addresses and some of their default values */
+
+/* restart subsystems */
+#define DIB3000MB_REG_RESTART			(     0)
+
+#define DIB3000MB_RESTART_OFF			(     0)
+#define DIB3000MB_RESTART_AUTO_SEARCH		(1 << 1)
+#define DIB3000MB_RESTART_CTRL				(1 << 2)
+#define DIB3000MB_RESTART_AGC				(1 << 3)
+
+/* FFT size */
+#define DIB3000MB_REG_FFT				(     1)
+
+/* Guard time */
+#define DIB3000MB_REG_GUARD_TIME		(     2)
+
+/* QAM */
+#define DIB3000MB_REG_QAM				(     3)
+
+/* Alpha coefficient high priority Viterbi algorithm */
+#define DIB3000MB_REG_VIT_ALPHA			(     4)
+
+/* spectrum inversion */
+#define DIB3000MB_REG_DDS_INV			(     5)
+
+/* DDS frequency value (IF position) ad ? values don't match reg_3000mb.txt */
+#define DIB3000MB_REG_DDS_FREQ_MSB		(     6)
+#define DIB3000MB_REG_DDS_FREQ_LSB		(     7)
+#define DIB3000MB_DDS_FREQ_MSB				(   178)
+#define DIB3000MB_DDS_FREQ_LSB				(  8990)
+
+/* timing frequency (carrier spacing) */
+static u16 dib3000mb_reg_timing_freq[] = { 8,9 };
+static u16 dib3000mb_timing_freq[][2] = {
+	{ 126 , 48873 }, /* 6 MHz */
+	{ 147 , 57019 }, /* 7 MHz */
+	{ 168 , 65164 }, /* 8 MHz */
+};
+
+/* impulse noise parameter */
+/* 36 ??? */
+
+static u16 dib3000mb_reg_impulse_noise[] = { 10,11,12,15,36 };
+
+enum dib3000mb_impulse_noise_type {
+	DIB3000MB_IMPNOISE_OFF,
+	DIB3000MB_IMPNOISE_MOBILE,
+	DIB3000MB_IMPNOISE_FIXED,
+	DIB3000MB_IMPNOISE_DEFAULT
+};
+
+static u16 dib3000mb_impulse_noise_values[][5] = {
+	{ 0x0000, 0x0004, 0x0014, 0x01ff, 0x0399 }, /* off */
+	{ 0x0001, 0x0004, 0x0014, 0x01ff, 0x037b }, /* mobile */
+	{ 0x0001, 0x0004, 0x0020, 0x01bd, 0x0399 }, /* fixed */
+	{ 0x0000, 0x0002, 0x000a, 0x01ff, 0x0399 }, /* default */
+};
+
+/*
+ * Dual Automatic-Gain-Control
+ * - gains RF in tuner (AGC1)
+ * - gains IF after filtering (AGC2)
+ */
+
+/* also from 16 to 18 */
+static u16 dib3000mb_reg_agc_gain[] = {
+	19,20,21,22,23,24,25,26,27,28,29,30,31,32
+};
+
+static u16 dib3000mb_default_agc_gain[] =
+	{ 0x0001, 52429,   623, 128, 166, 195, 61,   /* RF ??? */
+	  0x0001, 53766, 38011,   0,  90,  33, 23 }; /* IF ??? */
+
+/* phase noise */
+/* 36 is set when setting the impulse noise */
+static u16 dib3000mb_reg_phase_noise[] = { 33,34,35,37,38 };
+
+static u16 dib3000mb_default_noise_phase[] = { 2, 544, 0, 5, 4 };
+
+/* lock duration */
+static u16 dib3000mb_reg_lock_duration[] = { 39,40 };
+static u16 dib3000mb_default_lock_duration[] = { 135, 135 };
+
+/* AGC loop bandwidth */
+static u16 dib3000mb_reg_agc_bandwidth[] = { 43,44,45,46,47,48,49,50 };
+
+static u16 dib3000mb_agc_bandwidth_low[]  =
+	{ 2088, 10, 2088, 10, 3448, 5, 3448, 5 };
+static u16 dib3000mb_agc_bandwidth_high[] =
+	{ 2349,  5, 2349,  5, 2586, 2, 2586, 2 };
+
+/*
+ * lock0 definition (coff_lock)
+ */
+#define DIB3000MB_REG_LOCK0_MASK		(    51)
+#define DIB3000MB_LOCK0_DEFAULT				(     4)
+
+/*
+ * lock1 definition (cpil_lock)
+ * for auto search
+ * which values hide behind the lock masks
+ */
+#define DIB3000MB_REG_LOCK1_MASK		(    52)
+#define DIB3000MB_LOCK1_SEARCH_4			(0x0004)
+#define DIB3000MB_LOCK1_SEARCH_2048			(0x0800)
+#define DIB3000MB_LOCK1_DEFAULT				(0x0001)
+
+/*
+ * lock2 definition (fec_lock) */
+#define DIB3000MB_REG_LOCK2_MASK		(    53)
+#define DIB3000MB_LOCK2_DEFAULT				(0x0080)
+
+/*
+ * SEQ ? what was that again ... :)
+ * changes when, inversion, guard time and fft is
+ * either automatically detected or not
+ */
+#define DIB3000MB_REG_SEQ				(    54)
+
+/* bandwidth */
+static u16 dib3000mb_reg_bandwidth[] = { 55,56,57,58,59,60,61,62,63,64,65,66,67 };
+static u16 dib3000mb_bandwidth_6mhz[] =
+	{ 0, 33, 53312, 112, 46635, 563, 36565, 0, 1000, 0, 1010, 1, 45264 };
+
+static u16 dib3000mb_bandwidth_7mhz[] =
+	{ 0, 28, 64421,  96, 39973, 483,  3255, 0, 1000, 0, 1010, 1, 45264 };
+
+static u16 dib3000mb_bandwidth_8mhz[] =
+	{ 0, 25, 23600,  84, 34976, 422, 43808, 0, 1000, 0, 1010, 1, 45264 };
+
+#define DIB3000MB_REG_UNK_68				(    68)
+#define DIB3000MB_UNK_68						(     0)
+
+#define DIB3000MB_REG_UNK_69				(    69)
+#define DIB3000MB_UNK_69						(     0)
+
+#define DIB3000MB_REG_UNK_71				(    71)
+#define DIB3000MB_UNK_71						(     0)
+
+#define DIB3000MB_REG_UNK_77				(    77)
+#define DIB3000MB_UNK_77						(     6)
+
+#define DIB3000MB_REG_UNK_78				(    78)
+#define DIB3000MB_UNK_78						(0x0080)
+
+/* isi */
+#define DIB3000MB_REG_ISI				(    79)
+#define DIB3000MB_ISI_ACTIVATE				(     0)
+#define DIB3000MB_ISI_INHIBIT				(     1)
+
+/* sync impovement */
+#define DIB3000MB_REG_SYNC_IMPROVEMENT	(    84)
+#define DIB3000MB_SYNC_IMPROVE_2K_1_8		(     3)
+#define DIB3000MB_SYNC_IMPROVE_DEFAULT		(     0)
+
+/* phase noise compensation inhibition */
+#define DIB3000MB_REG_PHASE_NOISE		(    87)
+#define DIB3000MB_PHASE_NOISE_DEFAULT	(     0)
+
+#define DIB3000MB_REG_UNK_92				(    92)
+#define DIB3000MB_UNK_92						(0x0080)
+
+#define DIB3000MB_REG_UNK_96				(    96)
+#define DIB3000MB_UNK_96						(0x0010)
+
+#define DIB3000MB_REG_UNK_97				(    97)
+#define DIB3000MB_UNK_97						(0x0009)
+
+/* mobile mode ??? */
+#define DIB3000MB_REG_MOBILE_MODE		(   101)
+#define DIB3000MB_MOBILE_MODE_ON			(     1)
+#define DIB3000MB_MOBILE_MODE_OFF			(     0)
+
+#define DIB3000MB_REG_UNK_106			(   106)
+#define DIB3000MB_UNK_106					(0x0080)
+
+#define DIB3000MB_REG_UNK_107			(   107)
+#define DIB3000MB_UNK_107					(0x0080)
+
+#define DIB3000MB_REG_UNK_108			(   108)
+#define DIB3000MB_UNK_108					(0x0080)
+
+/* fft */
+#define DIB3000MB_REG_UNK_121			(   121)
+#define DIB3000MB_UNK_121_2K				(     7)
+#define DIB3000MB_UNK_121_DEFAULT			(     5)
+
+#define DIB3000MB_REG_UNK_122			(   122)
+#define DIB3000MB_UNK_122					(  2867)
+
+/* QAM for mobile mode */
+#define DIB3000MB_REG_MOBILE_MODE_QAM	(   126)
+#define DIB3000MB_MOBILE_MODE_QAM_64		(     3)
+#define DIB3000MB_MOBILE_MODE_QAM_QPSK_16	(     1)
+#define DIB3000MB_MOBILE_MODE_QAM_OFF		(     0)
+
+/*
+ * data diversity when having more than one chip on-board
+ * see also DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY
+ */
+#define DIB3000MB_REG_DATA_IN_DIVERSITY		(   127)
+#define DIB3000MB_DATA_DIVERSITY_IN_OFF			(     0)
+#define DIB3000MB_DATA_DIVERSITY_IN_ON			(     2)
+
+/* vit hrch */
+#define DIB3000MB_REG_VIT_HRCH			(   128)
+
+/* vit code rate */
+#define DIB3000MB_REG_VIT_CODE_RATE		(   129)
+
+/* vit select hp */
+#define DIB3000MB_REG_VIT_HP			(   130)
+
+/* time frame for Bit-Error-Rate calculation */
+#define DIB3000MB_REG_BERLEN			(   135)
+#define DIB3000MB_BERLEN_LONG				(     0)
+#define DIB3000MB_BERLEN_DEFAULT			(     1)
+#define DIB3000MB_BERLEN_MEDIUM				(     2)
+#define DIB3000MB_BERLEN_SHORT				(     3)
+
+/* 142 - 152 FIFO parameters
+ * which is what ?
+ */
+
+#define DIB3000MB_REG_FIFO_142			(   142)
+#define DIB3000MB_FIFO_142					(     0)
+
+/* MPEG2 TS output mode */
+#define DIB3000MB_REG_MPEG2_OUT_MODE	(   143)
+#define DIB3000MB_MPEG2_OUT_MODE_204		(     0)
+#define DIB3000MB_MPEG2_OUT_MODE_188		(     1)
+
+#define DIB3000MB_REG_PID_PARSE			(   144)
+#define DIB3000MB_PID_PARSE_INHIBIT		(     0)
+#define DIB3000MB_PID_PARSE_ACTIVATE	(     1)
+
+#define DIB3000MB_REG_FIFO				(   145)
+#define DIB3000MB_FIFO_INHIBIT				(     1)
+#define DIB3000MB_FIFO_ACTIVATE				(     0)
+
+#define DIB3000MB_REG_FIFO_146			(   146)
+#define DIB3000MB_FIFO_146					(     3)
+
+#define DIB3000MB_REG_FIFO_147			(   147)
+#define DIB3000MB_FIFO_147					(0x0100)
+
+/*
+ * pidfilter
+ * it is not a hardware pidfilter but a filter which drops all pids
+ * except the ones set. Necessary because of the limited USB1.1 bandwidth.
+ * regs 153-168
+ */
+
+#define DIB3000MB_REG_FIRST_PID			(   153)
+#define DIB3000MB_NUM_PIDS				(    16)
+
+/*
+ * output mode
+ * USB devices have to use 'slave'-mode
+ * see also DIB3000MB_REG_ELECT_OUT_MODE
+ */
+#define DIB3000MB_REG_OUTPUT_MODE		(   169)
+#define DIB3000MB_OUTPUT_MODE_GATED_CLK		(     0)
+#define DIB3000MB_OUTPUT_MODE_CONT_CLK		(     1)
+#define DIB3000MB_OUTPUT_MODE_SERIAL		(     2)
+#define DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY	(     5)
+#define DIB3000MB_OUTPUT_MODE_SLAVE			(     6)
+
+/* irq event mask */
+#define DIB3000MB_REG_IRQ_EVENT_MASK		(   170)
+#define DIB3000MB_IRQ_EVENT_MASK				(     0)
+
+/* filter coefficients */
+static u16 dib3000mb_reg_filter_coeffs[] = {
+	171, 172, 173, 174, 175, 176, 177, 178,
+	179, 180, 181, 182, 183, 184, 185, 186,
+	188, 189, 190, 191, 192, 194
+};
+
+static u16 dib3000mb_filter_coeffs[] = {
+	 226,  160,   29,
+	 979,  998,   19,
+	  22, 1019, 1006,
+	1022,   12,    6,
+	1017, 1017,    3,
+	   6,       1019,
+	1021,    2,    3,
+	   1,          0,
+};
+
+/*
+ * mobile algorithm (when you are moving with your device)
+ * but not faster than 90 km/h
+ */
+#define DIB3000MB_REG_MOBILE_ALGO		(   195)
+#define DIB3000MB_MOBILE_ALGO_ON			(     0)
+#define DIB3000MB_MOBILE_ALGO_OFF			(     1)
+
+/* multiple demodulators algorithm */
+#define DIB3000MB_REG_MULTI_DEMOD_MSB	(   206)
+#define DIB3000MB_REG_MULTI_DEMOD_LSB	(   207)
+
+/* terminator, no more demods */
+#define DIB3000MB_MULTI_DEMOD_MSB			( 32767)
+#define DIB3000MB_MULTI_DEMOD_LSB			(  4095)
+
+/* bring the device into a known  */
+#define DIB3000MB_REG_RESET_DEVICE		(  1024)
+#define DIB3000MB_RESET_DEVICE				(0x812c)
+#define DIB3000MB_RESET_DEVICE_RST			(     0)
+
+/* hardware clock configuration */
+#define DIB3000MB_REG_CLOCK				(  1027)
+#define DIB3000MB_CLOCK_DEFAULT				(0x9000)
+#define DIB3000MB_CLOCK_DIVERSITY			(0x92b0)
+
+/* power down config */
+#define DIB3000MB_REG_POWER_CONTROL		(  1028)
+#define DIB3000MB_POWER_DOWN				(     1)
+#define DIB3000MB_POWER_UP					(     0)
+
+/* electrical output mode */
+#define DIB3000MB_REG_ELECT_OUT_MODE	(  1029)
+#define DIB3000MB_ELECT_OUT_MODE_OFF		(     0)
+#define DIB3000MB_ELECT_OUT_MODE_ON			(     1)
+
+/* set the tuner i2c address */
+#define DIB3000MB_REG_TUNER				(  1089)
+
+/* monitoring registers (read only) */
+
+/* agc loop locked (size: 1) */
+#define DIB3000MB_REG_AGC_LOCK			(   324)
+
+/* agc power (size: 16) */
+#define DIB3000MB_REG_AGC_POWER			(   325)
+
+/* agc1 value (16) */
+#define DIB3000MB_REG_AGC1_VALUE		(   326)
+
+/* agc2 value (16) */
+#define DIB3000MB_REG_AGC2_VALUE		(   327)
+
+/* total RF power (16), can be used for signal strength */
+#define DIB3000MB_REG_RF_POWER			(   328)
+
+/* dds_frequency with offset (24) */
+#define DIB3000MB_REG_DDS_VALUE_MSB		(   339)
+#define DIB3000MB_REG_DDS_VALUE_LSB		(   340)
+
+/* timing offset signed (24) */
+#define DIB3000MB_REG_TIMING_OFFSET_MSB	(   341)
+#define DIB3000MB_REG_TIMING_OFFSET_LSB	(   342)
+
+/* fft start position (13) */
+#define DIB3000MB_REG_FFT_WINDOW_POS	(   353)
+
+/* carriers locked (1) */
+#define DIB3000MB_REG_CARRIER_LOCK		(   355)
+
+/* noise power (24) */
+#define DIB3000MB_REG_NOISE_POWER_MSB	(   372)
+#define DIB3000MB_REG_NOISE_POWER_LSB	(   373)
+
+#define DIB3000MB_REG_MOBILE_NOISE_MSB	(   374)
+#define DIB3000MB_REG_MOBILE_NOISE_LSB	(   375)
+
+/*
+ * signal power (16), this and the above can be
+ * used to calculate the signal/noise - ratio
+ */
+#define DIB3000MB_REG_SIGNAL_POWER		(   380)
+
+/* mer (24) */
+#define DIB3000MB_REG_MER_MSB			(   381)
+#define DIB3000MB_REG_MER_LSB			(   382)
+
+/*
+ * Transmission Parameter Signalling (TPS)
+ * the following registers can be used to get TPS-information.
+ * The values are according to the DVB-T standard.
+ */
+
+/* TPS locked (1) */
+#define DIB3000MB_REG_TPS_LOCK			(   394)
+
+/* QAM from TPS (2) (values according to DIB3000MB_REG_QAM) */
+#define DIB3000MB_REG_TPS_QAM			(   398)
+
+/* hierarchy from TPS (1) */
+#define DIB3000MB_REG_TPS_HRCH			(   399)
+
+/* alpha from TPS (3) (values according to DIB3000MB_REG_VIT_ALPHA) */
+#define DIB3000MB_REG_TPS_VIT_ALPHA		(   400)
+
+/* code rate high priority from TPS (3) (values according to DIB3000MB_FEC_*) */
+#define DIB3000MB_REG_TPS_CODE_RATE_HP	(   401)
+
+/* code rate low priority from TPS (3) if DIB3000MB_REG_TPS_VIT_ALPHA */
+#define DIB3000MB_REG_TPS_CODE_RATE_LP	(   402)
+
+/* guard time from TPS (2) (values according to DIB3000MB_REG_GUARD_TIME */
+#define DIB3000MB_REG_TPS_GUARD_TIME	(   403)
+
+/* fft size from TPS (2) (values according to DIB3000MB_REG_FFT) */
+#define DIB3000MB_REG_TPS_FFT			(   404)
+
+/* cell id from TPS (16) */
+#define DIB3000MB_REG_TPS_CELL_ID		(   406)
+
+/* TPS (68) */
+#define DIB3000MB_REG_TPS_1				(   408)
+#define DIB3000MB_REG_TPS_2				(   409)
+#define DIB3000MB_REG_TPS_3				(   410)
+#define DIB3000MB_REG_TPS_4				(   411)
+#define DIB3000MB_REG_TPS_5				(   412)
+
+/* bit error rate (before RS correction) (21) */
+#define DIB3000MB_REG_BER_MSB			(   414)
+#define DIB3000MB_REG_BER_LSB			(   415)
+
+/* packet error rate (uncorrected TS packets) (16) */
+#define DIB3000MB_REG_PACKET_ERROR_RATE	(   417)
+
+/* uncorrected packet count (16) */
+#define DIB3000MB_REG_UNC				(   420)
+
+/* viterbi locked (1) */
+#define DIB3000MB_REG_VIT_LCK			(   421)
+
+/* viterbi inidcator (16) */
+#define DIB3000MB_REG_VIT_INDICATOR		(   422)
+
+/* transport stream sync lock (1) */
+#define DIB3000MB_REG_TS_SYNC_LOCK		(   423)
+
+/* transport stream RS lock (1) */
+#define DIB3000MB_REG_TS_RS_LOCK		(   424)
+
+/* lock mask 0 value (1) */
+#define DIB3000MB_REG_LOCK0_VALUE		(   425)
+
+/* lock mask 1 value (1) */
+#define DIB3000MB_REG_LOCK1_VALUE		(   426)
+
+/* lock mask 2 value (1) */
+#define DIB3000MB_REG_LOCK2_VALUE		(   427)
+
+/* interrupt pending for auto search */
+#define DIB3000MB_REG_AS_IRQ_PENDING	(   434)
+
+#endif
diff --git a/drivers/media/dvb-frontends/dib3000mc.c b/drivers/media/dvb-frontends/dib3000mc.c
new file mode 100644
index 0000000..ffad181
--- /dev/null
+++ b/drivers/media/dvb-frontends/dib3000mc.c
@@ -0,0 +1,940 @@
+/*
+ * Driver for DiBcom DiB3000MC/P-demodulator.
+ *
+ * Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * This code is partially based on the previous dib3000mc.c .
+ *
+ * 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, version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "dib3000mc.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+static int buggy_sfn_workaround;
+module_param(buggy_sfn_workaround, int, 0644);
+MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0)
+
+struct dib3000mc_state {
+	struct dvb_frontend demod;
+	struct dib3000mc_config *cfg;
+
+	u8 i2c_addr;
+	struct i2c_adapter *i2c_adap;
+
+	struct dibx000_i2c_master i2c_master;
+
+	u32 timf;
+
+	u32 current_bandwidth;
+
+	u16 dev_id;
+
+	u8 sfn_workaround_active :1;
+};
+
+static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg)
+{
+	u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff };
+	u8 rb[2];
+	struct i2c_msg msg[2] = {
+		{ .addr = state->i2c_addr >> 1, .flags = 0,        .buf = wb, .len = 2 },
+		{ .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
+	};
+
+	if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
+		dprintk("i2c read error on %d\n",reg);
+
+	return (rb[0] << 8) | rb[1];
+}
+
+static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val)
+{
+	u8 b[4] = {
+		(reg >> 8) & 0xff, reg & 0xff,
+		(val >> 8) & 0xff, val & 0xff,
+	};
+	struct i2c_msg msg = {
+		.addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
+	};
+	return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+}
+
+static int dib3000mc_identify(struct dib3000mc_state *state)
+{
+	u16 value;
+	if ((value = dib3000mc_read_word(state, 1025)) != 0x01b3) {
+		dprintk("-E-  DiB3000MC/P: wrong Vendor ID (read=0x%x)\n",value);
+		return -EREMOTEIO;
+	}
+
+	value = dib3000mc_read_word(state, 1026);
+	if (value != 0x3001 && value != 0x3002) {
+		dprintk("-E-  DiB3000MC/P: wrong Device ID (%x)\n",value);
+		return -EREMOTEIO;
+	}
+	state->dev_id = value;
+
+	dprintk("-I-  found DiB3000MC/P: %x\n",state->dev_id);
+
+	return 0;
+}
+
+static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset)
+{
+	u32 timf;
+
+	if (state->timf == 0) {
+		timf = 1384402; // default value for 8MHz
+		if (update_offset)
+			msleep(200); // first time we do an update
+	} else
+		timf = state->timf;
+
+	timf *= (bw / 1000);
+
+	if (update_offset) {
+		s16 tim_offs = dib3000mc_read_word(state, 416);
+
+		if (tim_offs &  0x2000)
+			tim_offs -= 0x4000;
+
+		if (nfft == TRANSMISSION_MODE_2K)
+			tim_offs *= 4;
+
+		timf += tim_offs;
+		state->timf = timf / (bw / 1000);
+	}
+
+	dprintk("timf: %d\n", timf);
+
+	dib3000mc_write_word(state, 23, (u16) (timf >> 16));
+	dib3000mc_write_word(state, 24, (u16) (timf      ) & 0xffff);
+
+	return 0;
+}
+
+static int dib3000mc_setup_pwm_state(struct dib3000mc_state *state)
+{
+	u16 reg_51, reg_52 = state->cfg->agc->setup & 0xfefb;
+    if (state->cfg->pwm3_inversion) {
+		reg_51 =  (2 << 14) | (0 << 10) | (7 << 6) | (2 << 2) | (2 << 0);
+		reg_52 |= (1 << 2);
+	} else {
+		reg_51 = (2 << 14) | (4 << 10) | (7 << 6) | (2 << 2) | (2 << 0);
+		reg_52 |= (1 << 8);
+	}
+	dib3000mc_write_word(state, 51, reg_51);
+	dib3000mc_write_word(state, 52, reg_52);
+
+    if (state->cfg->use_pwm3)
+		dib3000mc_write_word(state, 245, (1 << 3) | (1 << 0));
+	else
+		dib3000mc_write_word(state, 245, 0);
+
+    dib3000mc_write_word(state, 1040, 0x3);
+	return 0;
+}
+
+static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode)
+{
+	int    ret = 0;
+	u16 fifo_threshold = 1792;
+	u16 outreg = 0;
+	u16 outmode = 0;
+	u16 elecout = 1;
+	u16 smo_reg = dib3000mc_read_word(state, 206) & 0x0010; /* keep the pid_parse bit */
+
+	dprintk("-I-  Setting output mode for demod %p to %d\n",
+			&state->demod, mode);
+
+	switch (mode) {
+		case OUTMODE_HIGH_Z:  // disable
+			elecout = 0;
+			break;
+		case OUTMODE_MPEG2_PAR_GATED_CLK:   // STBs with parallel gated clock
+			outmode = 0;
+			break;
+		case OUTMODE_MPEG2_PAR_CONT_CLK:    // STBs with parallel continues clock
+			outmode = 1;
+			break;
+		case OUTMODE_MPEG2_SERIAL:          // STBs with serial input
+			outmode = 2;
+			break;
+		case OUTMODE_MPEG2_FIFO:            // e.g. USB feeding
+			elecout = 3;
+			/*ADDR @ 206 :
+			P_smo_error_discard  [1;6:6] = 0
+			P_smo_rs_discard     [1;5:5] = 0
+			P_smo_pid_parse      [1;4:4] = 0
+			P_smo_fifo_flush     [1;3:3] = 0
+			P_smo_mode           [2;2:1] = 11
+			P_smo_ovf_prot       [1;0:0] = 0
+			*/
+			smo_reg |= 3 << 1;
+			fifo_threshold = 512;
+			outmode = 5;
+			break;
+		case OUTMODE_DIVERSITY:
+			outmode = 4;
+			elecout = 1;
+			break;
+		default:
+			dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
+			outmode = 0;
+			break;
+	}
+
+	if ((state->cfg->output_mpeg2_in_188_bytes))
+		smo_reg |= (1 << 5); // P_smo_rs_discard     [1;5:5] = 1
+
+	outreg = dib3000mc_read_word(state, 244) & 0x07FF;
+	outreg |= (outmode << 11);
+	ret |= dib3000mc_write_word(state,  244, outreg);
+	ret |= dib3000mc_write_word(state,  206, smo_reg);   /*smo_ mode*/
+	ret |= dib3000mc_write_word(state,  207, fifo_threshold); /* synchronous fread */
+	ret |= dib3000mc_write_word(state, 1040, elecout);         /* P_out_cfg */
+	return ret;
+}
+
+static int dib3000mc_set_bandwidth(struct dib3000mc_state *state, u32 bw)
+{
+	u16 bw_cfg[6] = { 0 };
+	u16 imp_bw_cfg[3] = { 0 };
+	u16 reg;
+
+/* settings here are for 27.7MHz */
+	switch (bw) {
+		case 8000:
+			bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20;
+			imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7;
+			break;
+
+		case 7000:
+			bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7;
+			imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0;
+			break;
+
+		case 6000:
+			bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5;
+			imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089;
+			break;
+
+		case 5000:
+			bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500;
+			imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072;
+			break;
+
+		default: return -EINVAL;
+	}
+
+	for (reg = 6; reg < 12; reg++)
+		dib3000mc_write_word(state, reg, bw_cfg[reg - 6]);
+	dib3000mc_write_word(state, 12, 0x0000);
+	dib3000mc_write_word(state, 13, 0x03e8);
+	dib3000mc_write_word(state, 14, 0x0000);
+	dib3000mc_write_word(state, 15, 0x03f2);
+	dib3000mc_write_word(state, 16, 0x0001);
+	dib3000mc_write_word(state, 17, 0xb0d0);
+	// P_sec_len
+	dib3000mc_write_word(state, 18, 0x0393);
+	dib3000mc_write_word(state, 19, 0x8700);
+
+	for (reg = 55; reg < 58; reg++)
+		dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]);
+
+	// Timing configuration
+	dib3000mc_set_timing(state, TRANSMISSION_MODE_2K, bw, 0);
+
+	return 0;
+}
+
+static u16 impulse_noise_val[29] =
+
+{
+	0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c, 0x3ffe, 0x7f3,
+	0x2d94, 0x76, 0x53d, 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3, 0x3feb, 0x7d2,
+	0x365e, 0x76, 0x48c, 0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0000, 0xd
+};
+
+static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, s16 nfft)
+{
+	u16 i;
+	for (i = 58; i < 87; i++)
+		dib3000mc_write_word(state, i, impulse_noise_val[i-58]);
+
+	if (nfft == TRANSMISSION_MODE_8K) {
+		dib3000mc_write_word(state, 58, 0x3b);
+		dib3000mc_write_word(state, 84, 0x00);
+		dib3000mc_write_word(state, 85, 0x8200);
+	}
+
+	dib3000mc_write_word(state, 34, 0x1294);
+	dib3000mc_write_word(state, 35, 0x1ff8);
+	if (mode == 1)
+		dib3000mc_write_word(state, 55, dib3000mc_read_word(state, 55) | (1 << 10));
+}
+
+static int dib3000mc_init(struct dvb_frontend *demod)
+{
+	struct dib3000mc_state *state = demod->demodulator_priv;
+	struct dibx000_agc_config *agc = state->cfg->agc;
+
+	// Restart Configuration
+	dib3000mc_write_word(state, 1027, 0x8000);
+	dib3000mc_write_word(state, 1027, 0x0000);
+
+	// power up the demod + mobility configuration
+	dib3000mc_write_word(state, 140, 0x0000);
+	dib3000mc_write_word(state, 1031, 0);
+
+	if (state->cfg->mobile_mode) {
+		dib3000mc_write_word(state, 139,  0x0000);
+		dib3000mc_write_word(state, 141,  0x0000);
+		dib3000mc_write_word(state, 175,  0x0002);
+		dib3000mc_write_word(state, 1032, 0x0000);
+	} else {
+		dib3000mc_write_word(state, 139,  0x0001);
+		dib3000mc_write_word(state, 141,  0x0000);
+		dib3000mc_write_word(state, 175,  0x0000);
+		dib3000mc_write_word(state, 1032, 0x012C);
+	}
+	dib3000mc_write_word(state, 1033, 0x0000);
+
+	// P_clk_cfg
+	dib3000mc_write_word(state, 1037, 0x3130);
+
+	// other configurations
+
+	// P_ctrl_sfreq
+	dib3000mc_write_word(state, 33, (5 << 0));
+	dib3000mc_write_word(state, 88, (1 << 10) | (0x10 << 0));
+
+	// Phase noise control
+	// P_fft_phacor_inh, P_fft_phacor_cpe, P_fft_powrange
+	dib3000mc_write_word(state, 99, (1 << 9) | (0x20 << 0));
+
+	if (state->cfg->phase_noise_mode == 0)
+		dib3000mc_write_word(state, 111, 0x00);
+	else
+		dib3000mc_write_word(state, 111, 0x02);
+
+	// P_agc_global
+	dib3000mc_write_word(state, 50, 0x8000);
+
+	// agc setup misc
+	dib3000mc_setup_pwm_state(state);
+
+	// P_agc_counter_lock
+	dib3000mc_write_word(state, 53, 0x87);
+	// P_agc_counter_unlock
+	dib3000mc_write_word(state, 54, 0x87);
+
+	/* agc */
+	dib3000mc_write_word(state, 36, state->cfg->max_time);
+	dib3000mc_write_word(state, 37, (state->cfg->agc_command1 << 13) | (state->cfg->agc_command2 << 12) | (0x1d << 0));
+	dib3000mc_write_word(state, 38, state->cfg->pwm3_value);
+	dib3000mc_write_word(state, 39, state->cfg->ln_adc_level);
+
+	// set_agc_loop_Bw
+	dib3000mc_write_word(state, 40, 0x0179);
+	dib3000mc_write_word(state, 41, 0x03f0);
+
+	dib3000mc_write_word(state, 42, agc->agc1_max);
+	dib3000mc_write_word(state, 43, agc->agc1_min);
+	dib3000mc_write_word(state, 44, agc->agc2_max);
+	dib3000mc_write_word(state, 45, agc->agc2_min);
+	dib3000mc_write_word(state, 46, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
+	dib3000mc_write_word(state, 47, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
+	dib3000mc_write_word(state, 48, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
+	dib3000mc_write_word(state, 49, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
+
+// Begin: TimeOut registers
+	// P_pha3_thres
+	dib3000mc_write_word(state, 110, 3277);
+	// P_timf_alpha = 6, P_corm_alpha = 6, P_corm_thres = 0x80
+	dib3000mc_write_word(state,  26, 0x6680);
+	// lock_mask0
+	dib3000mc_write_word(state, 1, 4);
+	// lock_mask1
+	dib3000mc_write_word(state, 2, 4);
+	// lock_mask2
+	dib3000mc_write_word(state, 3, 0x1000);
+	// P_search_maxtrial=1
+	dib3000mc_write_word(state, 5, 1);
+
+	dib3000mc_set_bandwidth(state, 8000);
+
+	// div_lock_mask
+	dib3000mc_write_word(state,  4, 0x814);
+
+	dib3000mc_write_word(state, 21, (1 << 9) | 0x164);
+	dib3000mc_write_word(state, 22, 0x463d);
+
+	// Spurious rm cfg
+	// P_cspu_regul, P_cspu_win_cut
+	dib3000mc_write_word(state, 120, 0x200f);
+	// P_adp_selec_monit
+	dib3000mc_write_word(state, 134, 0);
+
+	// Fec cfg
+	dib3000mc_write_word(state, 195, 0x10);
+
+	// diversity register: P_dvsy_sync_wait..
+	dib3000mc_write_word(state, 180, 0x2FF0);
+
+	// Impulse noise configuration
+	dib3000mc_set_impulse_noise(state, 0, TRANSMISSION_MODE_8K);
+
+	// output mode set-up
+	dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
+
+	/* close the i2c-gate */
+	dib3000mc_write_word(state, 769, (1 << 7) );
+
+	return 0;
+}
+
+static int dib3000mc_sleep(struct dvb_frontend *demod)
+{
+	struct dib3000mc_state *state = demod->demodulator_priv;
+
+	dib3000mc_write_word(state, 1031, 0xFFFF);
+	dib3000mc_write_word(state, 1032, 0xFFFF);
+	dib3000mc_write_word(state, 1033, 0xFFF0);
+
+    return 0;
+}
+
+static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
+{
+	u16 cfg[4] = { 0 },reg;
+	switch (qam) {
+		case QPSK:
+			cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0;
+			break;
+		case QAM_16:
+			cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0;
+			break;
+		case QAM_64:
+			cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8;
+			break;
+	}
+	for (reg = 129; reg < 133; reg++)
+		dib3000mc_write_word(state, reg, cfg[reg - 129]);
+}
+
+static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state,
+				      struct dtv_frontend_properties *ch, u16 seq)
+{
+	u16 value;
+	u32 bw = BANDWIDTH_TO_KHZ(ch->bandwidth_hz);
+
+	dib3000mc_set_bandwidth(state, bw);
+	dib3000mc_set_timing(state, ch->transmission_mode, bw, 0);
+
+//	if (boost)
+//		dib3000mc_write_word(state, 100, (11 << 6) + 6);
+//	else
+		dib3000mc_write_word(state, 100, (16 << 6) + 9);
+
+	dib3000mc_write_word(state, 1027, 0x0800);
+	dib3000mc_write_word(state, 1027, 0x0000);
+
+	//Default cfg isi offset adp
+	dib3000mc_write_word(state, 26,  0x6680);
+	dib3000mc_write_word(state, 29,  0x1273);
+	dib3000mc_write_word(state, 33,       5);
+	dib3000mc_set_adp_cfg(state, QAM_16);
+	dib3000mc_write_word(state, 133,  15564);
+
+	dib3000mc_write_word(state, 12 , 0x0);
+	dib3000mc_write_word(state, 13 , 0x3e8);
+	dib3000mc_write_word(state, 14 , 0x0);
+	dib3000mc_write_word(state, 15 , 0x3f2);
+
+	dib3000mc_write_word(state, 93,0);
+	dib3000mc_write_word(state, 94,0);
+	dib3000mc_write_word(state, 95,0);
+	dib3000mc_write_word(state, 96,0);
+	dib3000mc_write_word(state, 97,0);
+	dib3000mc_write_word(state, 98,0);
+
+	dib3000mc_set_impulse_noise(state, 0, ch->transmission_mode);
+
+	value = 0;
+	switch (ch->transmission_mode) {
+		case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
+		default:
+		case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
+	}
+	switch (ch->guard_interval) {
+		case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
+		case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
+		case GUARD_INTERVAL_1_4:  value |= (3 << 5); break;
+		default:
+		case GUARD_INTERVAL_1_8:  value |= (2 << 5); break;
+	}
+	switch (ch->modulation) {
+		case QPSK:  value |= (0 << 3); break;
+		case QAM_16: value |= (1 << 3); break;
+		default:
+		case QAM_64: value |= (2 << 3); break;
+	}
+	switch (HIERARCHY_1) {
+		case HIERARCHY_2: value |= 2; break;
+		case HIERARCHY_4: value |= 4; break;
+		default:
+		case HIERARCHY_1: value |= 1; break;
+	}
+	dib3000mc_write_word(state, 0, value);
+	dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4));
+
+	value = 0;
+	if (ch->hierarchy == 1)
+		value |= (1 << 4);
+	if (1 == 1)
+		value |= 1;
+	switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
+		case FEC_2_3: value |= (2 << 1); break;
+		case FEC_3_4: value |= (3 << 1); break;
+		case FEC_5_6: value |= (5 << 1); break;
+		case FEC_7_8: value |= (7 << 1); break;
+		default:
+		case FEC_1_2: value |= (1 << 1); break;
+	}
+	dib3000mc_write_word(state, 181, value);
+
+	// diversity synchro delay add 50% SFN margin
+	switch (ch->transmission_mode) {
+		case TRANSMISSION_MODE_8K: value = 256; break;
+		case TRANSMISSION_MODE_2K:
+		default: value = 64; break;
+	}
+	switch (ch->guard_interval) {
+		case GUARD_INTERVAL_1_16: value *= 2; break;
+		case GUARD_INTERVAL_1_8:  value *= 4; break;
+		case GUARD_INTERVAL_1_4:  value *= 8; break;
+		default:
+		case GUARD_INTERVAL_1_32: value *= 1; break;
+	}
+	value <<= 4;
+	value |= dib3000mc_read_word(state, 180) & 0x000f;
+	dib3000mc_write_word(state, 180, value);
+
+	// restart demod
+	value = dib3000mc_read_word(state, 0);
+	dib3000mc_write_word(state, 0, value | (1 << 9));
+	dib3000mc_write_word(state, 0, value);
+
+	msleep(30);
+
+	dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->transmission_mode);
+}
+
+static int dib3000mc_autosearch_start(struct dvb_frontend *demod)
+{
+	struct dtv_frontend_properties *chan = &demod->dtv_property_cache;
+	struct dib3000mc_state *state = demod->demodulator_priv;
+	u16 reg;
+//	u32 val;
+	struct dtv_frontend_properties schan;
+
+	schan = *chan;
+
+	/* TODO what is that ? */
+
+	/* a channel for autosearch */
+	schan.transmission_mode = TRANSMISSION_MODE_8K;
+	schan.guard_interval = GUARD_INTERVAL_1_32;
+	schan.modulation = QAM_64;
+	schan.code_rate_HP = FEC_2_3;
+	schan.code_rate_LP = FEC_2_3;
+	schan.hierarchy = 0;
+
+	dib3000mc_set_channel_cfg(state, &schan, 11);
+
+	reg = dib3000mc_read_word(state, 0);
+	dib3000mc_write_word(state, 0, reg | (1 << 8));
+	dib3000mc_read_word(state, 511);
+	dib3000mc_write_word(state, 0, reg);
+
+	return 0;
+}
+
+static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod)
+{
+	struct dib3000mc_state *state = demod->demodulator_priv;
+	u16 irq_pending = dib3000mc_read_word(state, 511);
+
+	if (irq_pending & 0x1) // failed
+		return 1;
+
+	if (irq_pending & 0x2) // succeeded
+		return 2;
+
+	return 0; // still pending
+}
+
+static int dib3000mc_tune(struct dvb_frontend *demod)
+{
+	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
+	struct dib3000mc_state *state = demod->demodulator_priv;
+
+	// ** configure demod **
+	dib3000mc_set_channel_cfg(state, ch, 0);
+
+	// activates isi
+	if (state->sfn_workaround_active) {
+		dprintk("SFN workaround is active\n");
+		dib3000mc_write_word(state, 29, 0x1273);
+		dib3000mc_write_word(state, 108, 0x4000); // P_pha3_force_pha_shift
+	} else {
+		dib3000mc_write_word(state, 29, 0x1073);
+		dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift
+	}
+
+	dib3000mc_set_adp_cfg(state, (u8)ch->modulation);
+	if (ch->transmission_mode == TRANSMISSION_MODE_8K) {
+		dib3000mc_write_word(state, 26, 38528);
+		dib3000mc_write_word(state, 33, 8);
+	} else {
+		dib3000mc_write_word(state, 26, 30336);
+		dib3000mc_write_word(state, 33, 6);
+	}
+
+	if (dib3000mc_read_word(state, 509) & 0x80)
+		dib3000mc_set_timing(state, ch->transmission_mode,
+				     BANDWIDTH_TO_KHZ(ch->bandwidth_hz), 1);
+
+	return 0;
+}
+
+struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating)
+{
+	struct dib3000mc_state *st = demod->demodulator_priv;
+	return dibx000_get_i2c_adapter(&st->i2c_master, DIBX000_I2C_INTERFACE_TUNER, gating);
+}
+
+EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master);
+
+static int dib3000mc_get_frontend(struct dvb_frontend* fe)
+{
+	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	u16 tps = dib3000mc_read_word(state,458);
+
+	fep->inversion = INVERSION_AUTO;
+
+	fep->bandwidth_hz = state->current_bandwidth;
+
+	switch ((tps >> 8) & 0x1) {
+		case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break;
+		case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break;
+	}
+
+	switch (tps & 0x3) {
+		case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break;
+		case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break;
+		case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break;
+		case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break;
+	}
+
+	switch ((tps >> 13) & 0x3) {
+		case 0: fep->modulation = QPSK; break;
+		case 1: fep->modulation = QAM_16; break;
+		case 2:
+		default: fep->modulation = QAM_64; break;
+	}
+
+	/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
+	/* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */
+
+	fep->hierarchy = HIERARCHY_NONE;
+	switch ((tps >> 5) & 0x7) {
+		case 1: fep->code_rate_HP = FEC_1_2; break;
+		case 2: fep->code_rate_HP = FEC_2_3; break;
+		case 3: fep->code_rate_HP = FEC_3_4; break;
+		case 5: fep->code_rate_HP = FEC_5_6; break;
+		case 7:
+		default: fep->code_rate_HP = FEC_7_8; break;
+
+	}
+
+	switch ((tps >> 2) & 0x7) {
+		case 1: fep->code_rate_LP = FEC_1_2; break;
+		case 2: fep->code_rate_LP = FEC_2_3; break;
+		case 3: fep->code_rate_LP = FEC_3_4; break;
+		case 5: fep->code_rate_LP = FEC_5_6; break;
+		case 7:
+		default: fep->code_rate_LP = FEC_7_8; break;
+	}
+
+	return 0;
+}
+
+static int dib3000mc_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	int ret;
+
+	dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
+
+	state->current_bandwidth = fep->bandwidth_hz;
+	dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz));
+
+	/* maybe the parameter has been changed */
+	state->sfn_workaround_active = buggy_sfn_workaround;
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		msleep(100);
+	}
+
+	if (fep->transmission_mode  == TRANSMISSION_MODE_AUTO ||
+	    fep->guard_interval == GUARD_INTERVAL_AUTO ||
+	    fep->modulation     == QAM_AUTO ||
+	    fep->code_rate_HP   == FEC_AUTO) {
+		int i = 1000, found;
+
+		dib3000mc_autosearch_start(fe);
+		do {
+			msleep(1);
+			found = dib3000mc_autosearch_is_irq(fe);
+		} while (found == 0 && i--);
+
+		dprintk("autosearch returns: %d\n",found);
+		if (found == 0 || found == 1)
+			return 0; // no channel found
+
+		dib3000mc_get_frontend(fe);
+	}
+
+	ret = dib3000mc_tune(fe);
+
+	/* make this a config parameter */
+	dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
+	return ret;
+}
+
+static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+{
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	u16 lock = dib3000mc_read_word(state, 509);
+
+	*stat = 0;
+
+	if (lock & 0x8000)
+		*stat |= FE_HAS_SIGNAL;
+	if (lock & 0x3000)
+		*stat |= FE_HAS_CARRIER;
+	if (lock & 0x0100)
+		*stat |= FE_HAS_VITERBI;
+	if (lock & 0x0010)
+		*stat |= FE_HAS_SYNC;
+	if (lock & 0x0008)
+		*stat |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int dib3000mc_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	*ber = (dib3000mc_read_word(state, 500) << 16) | dib3000mc_read_word(state, 501);
+	return 0;
+}
+
+static int dib3000mc_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
+{
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	*unc = dib3000mc_read_word(state, 508);
+	return 0;
+}
+
+static int dib3000mc_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	u16 val = dib3000mc_read_word(state, 392);
+	*strength = 65535 - val;
+	return 0;
+}
+
+static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+	*snr = 0x0000;
+	return 0;
+}
+
+static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	return 0;
+}
+
+static void dib3000mc_release(struct dvb_frontend *fe)
+{
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	dibx000_exit_i2c_master(&state->i2c_master);
+	kfree(state);
+}
+
+int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff)
+{
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	dib3000mc_write_word(state, 212 + index,  onoff ? (1 << 13) | pid : 0);
+	return 0;
+}
+EXPORT_SYMBOL(dib3000mc_pid_control);
+
+int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
+{
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	u16 tmp = dib3000mc_read_word(state, 206) & ~(1 << 4);
+	tmp |= (onoff << 4);
+	return dib3000mc_write_word(state, 206, tmp);
+}
+EXPORT_SYMBOL(dib3000mc_pid_parse);
+
+void dib3000mc_set_config(struct dvb_frontend *fe, struct dib3000mc_config *cfg)
+{
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	state->cfg = cfg;
+}
+EXPORT_SYMBOL(dib3000mc_set_config);
+
+int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib3000mc_config cfg[])
+{
+	struct dib3000mc_state *dmcst;
+	int k;
+	u8 new_addr;
+
+	static u8 DIB3000MC_I2C_ADDRESS[] = {20,22,24,26};
+
+	dmcst = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);
+	if (dmcst == NULL)
+		return -ENOMEM;
+
+	dmcst->i2c_adap = i2c;
+
+	for (k = no_of_demods-1; k >= 0; k--) {
+		dmcst->cfg = &cfg[k];
+
+		/* designated i2c address */
+		new_addr          = DIB3000MC_I2C_ADDRESS[k];
+		dmcst->i2c_addr = new_addr;
+		if (dib3000mc_identify(dmcst) != 0) {
+			dmcst->i2c_addr = default_addr;
+			if (dib3000mc_identify(dmcst) != 0) {
+				dprintk("-E-  DiB3000P/MC #%d: not identified\n", k);
+				kfree(dmcst);
+				return -ENODEV;
+			}
+		}
+
+		dib3000mc_set_output_mode(dmcst, OUTMODE_MPEG2_PAR_CONT_CLK);
+
+		// set new i2c address and force divstr (Bit 1) to value 0 (Bit 0)
+		dib3000mc_write_word(dmcst, 1024, (new_addr << 3) | 0x1);
+		dmcst->i2c_addr = new_addr;
+	}
+
+	for (k = 0; k < no_of_demods; k++) {
+		dmcst->cfg = &cfg[k];
+		dmcst->i2c_addr = DIB3000MC_I2C_ADDRESS[k];
+
+		dib3000mc_write_word(dmcst, 1024, dmcst->i2c_addr << 3);
+
+		/* turn off data output */
+		dib3000mc_set_output_mode(dmcst, OUTMODE_HIGH_Z);
+	}
+
+	kfree(dmcst);
+	return 0;
+}
+EXPORT_SYMBOL(dib3000mc_i2c_enumeration);
+
+static struct dvb_frontend_ops dib3000mc_ops;
+
+struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg)
+{
+	struct dvb_frontend *demod;
+	struct dib3000mc_state *st;
+	st = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);
+	if (st == NULL)
+		return NULL;
+
+	st->cfg = cfg;
+	st->i2c_adap = i2c_adap;
+	st->i2c_addr = i2c_addr;
+
+	demod                   = &st->demod;
+	demod->demodulator_priv = st;
+	memcpy(&st->demod.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
+
+	if (dib3000mc_identify(st) != 0)
+		goto error;
+
+	dibx000_init_i2c_master(&st->i2c_master, DIB3000MC, st->i2c_adap, st->i2c_addr);
+
+	dib3000mc_write_word(st, 1037, 0x3130);
+
+	return demod;
+
+error:
+	kfree(st);
+	return NULL;
+}
+EXPORT_SYMBOL(dib3000mc_attach);
+
+static struct dvb_frontend_ops dib3000mc_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "DiBcom 3000MC/P",
+		.frequency_min      = 44250000,
+		.frequency_max      = 867250000,
+		.frequency_stepsize = 62500,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_RECOVER |
+			FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.release              = dib3000mc_release,
+
+	.init                 = dib3000mc_init,
+	.sleep                = dib3000mc_sleep,
+
+	.set_frontend         = dib3000mc_set_frontend,
+	.get_tune_settings    = dib3000mc_fe_get_tune_settings,
+	.get_frontend         = dib3000mc_get_frontend,
+
+	.read_status          = dib3000mc_read_status,
+	.read_ber             = dib3000mc_read_ber,
+	.read_signal_strength = dib3000mc_read_signal_strength,
+	.read_snr             = dib3000mc_read_snr,
+	.read_ucblocks        = dib3000mc_read_unc_blocks,
+};
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 3000MC/P COFDM demodulator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/dib3000mc.h b/drivers/media/dvb-frontends/dib3000mc.h
new file mode 100644
index 0000000..d75ffad
--- /dev/null
+++ b/drivers/media/dvb-frontends/dib3000mc.h
@@ -0,0 +1,85 @@
+/*
+ * Driver for DiBcom DiB3000MC/P-demodulator.
+ *
+ * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher\@desy.de)
+ *
+ * This code is partially based on the previous dib3000mc.c .
+ *
+ * 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, version 2.
+ */
+#ifndef DIB3000MC_H
+#define DIB3000MC_H
+
+#include "dibx000_common.h"
+
+struct dib3000mc_config {
+	struct dibx000_agc_config *agc;
+
+	u8 phase_noise_mode;
+	u8 impulse_noise_mode;
+
+	u8  pwm3_inversion;
+	u8  use_pwm3;
+	u16 pwm3_value;
+
+	u16 max_time;
+	u16 ln_adc_level;
+
+	u8 agc_command1 :1;
+	u8 agc_command2 :1;
+
+	u8 mobile_mode;
+
+	u8 output_mpeg2_in_188_bytes;
+};
+
+#define DEFAULT_DIB3000MC_I2C_ADDRESS 16
+#define DEFAULT_DIB3000P_I2C_ADDRESS  24
+
+#if defined(CONFIG_DVB_DIB3000MC) || (defined(CONFIG_DVB_DIB3000MC_MODULE) && \
+				      defined(MODULE))
+extern struct dvb_frontend *dib3000mc_attach(struct i2c_adapter *i2c_adap,
+					     u8 i2c_addr,
+					     struct dib3000mc_config *cfg);
+extern int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c,
+				     int no_of_demods, u8 default_addr,
+				     struct dib3000mc_config cfg[]);
+extern
+struct i2c_adapter *dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod,
+						   int gating);
+#else
+static inline
+struct dvb_frontend *dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
+				      struct dib3000mc_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline
+int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c,
+			      int no_of_demods, u8 default_addr,
+			      struct dib3000mc_config cfg[])
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline
+struct i2c_adapter *dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod,
+						   int gating)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_DIB3000MC
+
+extern int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff);
+extern int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff);
+
+extern void dib3000mc_set_config(struct dvb_frontend *, struct dib3000mc_config *);
+
+#endif
diff --git a/drivers/media/dvb-frontends/dib7000m.c b/drivers/media/dvb-frontends/dib7000m.c
new file mode 100644
index 0000000..148bf79
--- /dev/null
+++ b/drivers/media/dvb-frontends/dib7000m.c
@@ -0,0 +1,1473 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB7000M and
+ *              first generation DiB7000P-demodulator-family.
+ *
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
+ *
+ * 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, version 2.
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+#include "dvb_frontend.h"
+
+#include "dib7000m.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M: "); printk(args); printk("\n"); } } while (0)
+
+struct dib7000m_state {
+	struct dvb_frontend demod;
+    struct dib7000m_config cfg;
+
+	u8 i2c_addr;
+	struct i2c_adapter   *i2c_adap;
+
+	struct dibx000_i2c_master i2c_master;
+
+/* offset is 1 in case of the 7000MC */
+	u8 reg_offs;
+
+	u16 wbd_ref;
+
+	u8 current_band;
+	u32 current_bandwidth;
+	struct dibx000_agc_config *current_agc;
+	u32 timf;
+	u32 timf_default;
+	u32 internal_clk;
+
+	u8 div_force_off : 1;
+	u8 div_state : 1;
+	u16 div_sync_wait;
+
+	u16 revision;
+
+	u8 agc_state;
+
+	/* for the I2C transfer */
+	struct i2c_msg msg[2];
+	u8 i2c_write_buffer[4];
+	u8 i2c_read_buffer[2];
+	struct mutex i2c_buffer_lock;
+};
+
+enum dib7000m_power_mode {
+	DIB7000M_POWER_ALL = 0,
+
+	DIB7000M_POWER_NO,
+	DIB7000M_POWER_INTERF_ANALOG_AGC,
+	DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD,
+	DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD,
+	DIB7000M_POWER_INTERFACE_ONLY,
+};
+
+static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
+{
+	u16 ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return 0;
+	}
+
+	state->i2c_write_buffer[0] = (reg >> 8) | 0x80;
+	state->i2c_write_buffer[1] = reg & 0xff;
+
+	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+	state->msg[0].addr = state->i2c_addr >> 1;
+	state->msg[0].flags = 0;
+	state->msg[0].buf = state->i2c_write_buffer;
+	state->msg[0].len = 2;
+	state->msg[1].addr = state->i2c_addr >> 1;
+	state->msg[1].flags = I2C_M_RD;
+	state->msg[1].buf = state->i2c_read_buffer;
+	state->msg[1].len = 2;
+
+	if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
+		dprintk("i2c read error on %d",reg);
+
+	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+	mutex_unlock(&state->i2c_buffer_lock);
+
+	return ret;
+}
+
+static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
+{
+	int ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+
+	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+	state->i2c_write_buffer[1] = reg & 0xff;
+	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+	state->i2c_write_buffer[3] = val & 0xff;
+
+	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
+	state->msg[0].addr = state->i2c_addr >> 1;
+	state->msg[0].flags = 0;
+	state->msg[0].buf = state->i2c_write_buffer;
+	state->msg[0].len = 4;
+
+	ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
+			-EREMOTEIO : 0);
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
+}
+static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
+{
+	u16 l = 0, r, *n;
+	n = buf;
+	l = *n++;
+	while (l) {
+		r = *n++;
+
+		if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC
+			r++;
+
+		do {
+			dib7000m_write_word(state, r, *n++);
+			r++;
+		} while (--l);
+		l = *n++;
+	}
+}
+
+static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
+{
+	int    ret = 0;
+	u16 outreg, fifo_threshold, smo_mode,
+		sram = 0x0005; /* by default SRAM output is disabled */
+
+	outreg = 0;
+	fifo_threshold = 1792;
+	smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1);
+
+	dprintk( "setting output mode for demod %p to %d", &state->demod, mode);
+
+	switch (mode) {
+		case OUTMODE_MPEG2_PAR_GATED_CLK:   // STBs with parallel gated clock
+			outreg = (1 << 10);  /* 0x0400 */
+			break;
+		case OUTMODE_MPEG2_PAR_CONT_CLK:    // STBs with parallel continues clock
+			outreg = (1 << 10) | (1 << 6); /* 0x0440 */
+			break;
+		case OUTMODE_MPEG2_SERIAL:          // STBs with serial input
+			outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
+			break;
+		case OUTMODE_DIVERSITY:
+			if (state->cfg.hostbus_diversity)
+				outreg = (1 << 10) | (4 << 6); /* 0x0500 */
+			else
+				sram   |= 0x0c00;
+			break;
+		case OUTMODE_MPEG2_FIFO:            // e.g. USB feeding
+			smo_mode |= (3 << 1);
+			fifo_threshold = 512;
+			outreg = (1 << 10) | (5 << 6);
+			break;
+		case OUTMODE_HIGH_Z:  // disable
+			outreg = 0;
+			break;
+		default:
+			dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod);
+			break;
+	}
+
+	if (state->cfg.output_mpeg2_in_188_bytes)
+		smo_mode |= (1 << 5) ;
+
+	ret |= dib7000m_write_word(state,  294 + state->reg_offs, smo_mode);
+	ret |= dib7000m_write_word(state,  295 + state->reg_offs, fifo_threshold); /* synchronous fread */
+	ret |= dib7000m_write_word(state, 1795, outreg);
+	ret |= dib7000m_write_word(state, 1805, sram);
+
+	if (state->revision == 0x4003) {
+		u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd;
+		if (mode == OUTMODE_DIVERSITY)
+			clk_cfg1 |= (1 << 1); // P_O_CLK_en
+		dib7000m_write_word(state, 909, clk_cfg1);
+	}
+	return ret;
+}
+
+static void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode)
+{
+	/* by default everything is going to be powered off */
+	u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906  = 0x3fff;
+	u8  offset = 0;
+
+	/* now, depending on the requested mode, we power on */
+	switch (mode) {
+		/* power up everything in the demod */
+		case DIB7000M_POWER_ALL:
+			reg_903 = 0x0000; reg_904 = 0x0000; reg_905 = 0x0000; reg_906 = 0x0000;
+			break;
+
+		/* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */
+		case DIB7000M_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */
+			reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2));
+			break;
+
+		case DIB7000M_POWER_INTERF_ANALOG_AGC:
+			reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10));
+			reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2));
+			reg_906 &= ~((1 << 0));
+			break;
+
+		case DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD:
+			reg_903 = 0x0000; reg_904 = 0x801f; reg_905 = 0x0000; reg_906 = 0x0000;
+			break;
+
+		case DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD:
+			reg_903 = 0x0000; reg_904 = 0x8000; reg_905 = 0x010b; reg_906 = 0x0000;
+			break;
+		case DIB7000M_POWER_NO:
+			break;
+	}
+
+	/* always power down unused parts */
+	if (!state->cfg.mobile_mode)
+		reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1);
+
+	/* P_sdio_select_clk = 0 on MC and after*/
+	if (state->revision != 0x4000)
+		reg_906 <<= 1;
+
+	if (state->revision == 0x4003)
+		offset = 1;
+
+	dib7000m_write_word(state, 903 + offset, reg_903);
+	dib7000m_write_word(state, 904 + offset, reg_904);
+	dib7000m_write_word(state, 905 + offset, reg_905);
+	dib7000m_write_word(state, 906 + offset, reg_906);
+}
+
+static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no)
+{
+	int ret = 0;
+	u16 reg_913 = dib7000m_read_word(state, 913),
+	       reg_914 = dib7000m_read_word(state, 914);
+
+	switch (no) {
+		case DIBX000_SLOW_ADC_ON:
+			reg_914 |= (1 << 1) | (1 << 0);
+			ret |= dib7000m_write_word(state, 914, reg_914);
+			reg_914 &= ~(1 << 1);
+			break;
+
+		case DIBX000_SLOW_ADC_OFF:
+			reg_914 |=  (1 << 1) | (1 << 0);
+			break;
+
+		case DIBX000_ADC_ON:
+			if (state->revision == 0x4000) { // workaround for PA/MA
+				// power-up ADC
+				dib7000m_write_word(state, 913, 0);
+				dib7000m_write_word(state, 914, reg_914 & 0x3);
+				// power-down bandgag
+				dib7000m_write_word(state, 913, (1 << 15));
+				dib7000m_write_word(state, 914, reg_914 & 0x3);
+			}
+
+			reg_913 &= 0x0fff;
+			reg_914 &= 0x0003;
+			break;
+
+		case DIBX000_ADC_OFF: // leave the VBG voltage on
+			reg_913 |= (1 << 14) | (1 << 13) | (1 << 12);
+			reg_914 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
+			break;
+
+		case DIBX000_VBG_ENABLE:
+			reg_913 &= ~(1 << 15);
+			break;
+
+		case DIBX000_VBG_DISABLE:
+			reg_913 |= (1 << 15);
+			break;
+
+		default:
+			break;
+	}
+
+//	dprintk( "913: %x, 914: %x", reg_913, reg_914);
+	ret |= dib7000m_write_word(state, 913, reg_913);
+	ret |= dib7000m_write_word(state, 914, reg_914);
+
+	return ret;
+}
+
+static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw)
+{
+	u32 timf;
+
+	if (!bw)
+		bw = 8000;
+
+	// store the current bandwidth for later use
+	state->current_bandwidth = bw;
+
+	if (state->timf == 0) {
+		dprintk( "using default timf");
+		timf = state->timf_default;
+	} else {
+		dprintk( "using updated timf");
+		timf = state->timf;
+	}
+
+	timf = timf * (bw / 50) / 160;
+
+	dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
+	dib7000m_write_word(state, 24, (u16) ((timf      ) & 0xffff));
+
+	return 0;
+}
+
+static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff)
+{
+	struct dib7000m_state *state = demod->demodulator_priv;
+
+	if (state->div_force_off) {
+		dprintk( "diversity combination deactivated - forced by COFDM parameters");
+		onoff = 0;
+	}
+	state->div_state = (u8)onoff;
+
+	if (onoff) {
+		dib7000m_write_word(state, 263 + state->reg_offs, 6);
+		dib7000m_write_word(state, 264 + state->reg_offs, 6);
+		dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
+	} else {
+		dib7000m_write_word(state, 263 + state->reg_offs, 1);
+		dib7000m_write_word(state, 264 + state->reg_offs, 0);
+		dib7000m_write_word(state, 266 + state->reg_offs, 0);
+	}
+
+	return 0;
+}
+
+static int dib7000m_sad_calib(struct dib7000m_state *state)
+{
+
+/* internal */
+//	dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
+	dib7000m_write_word(state, 929, (0 << 1) | (0 << 0));
+	dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096
+
+	/* do the calibration */
+	dib7000m_write_word(state, 929, (1 << 0));
+	dib7000m_write_word(state, 929, (0 << 0));
+
+	msleep(1);
+
+	return 0;
+}
+
+static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw)
+{
+	dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
+	dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000)        & 0xffff));
+	dib7000m_write_word(state, 21, (u16) ( (bw->ifreq          >> 16) & 0xffff));
+	dib7000m_write_word(state, 22, (u16) (  bw->ifreq                 & 0xffff));
+
+	dib7000m_write_word(state, 928, bw->sad_cfg);
+}
+
+static void dib7000m_reset_pll(struct dib7000m_state *state)
+{
+	const struct dibx000_bandwidth_config *bw = state->cfg.bw;
+	u16 reg_907,reg_910;
+
+	/* default */
+	reg_907 = (bw->pll_bypass << 15) | (bw->modulo << 7) |
+		(bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) |
+		(bw->enable_refdiv << 1) | (0 << 0);
+	reg_910 = (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset;
+
+	// for this oscillator frequency should be 30 MHz for the Master (default values in the board_parameters give that value)
+	// this is only working only for 30 MHz crystals
+	if (!state->cfg.quartz_direct) {
+		reg_910 |= (1 << 5);  // forcing the predivider to 1
+
+		// if the previous front-end is baseband, its output frequency is 15 MHz (prev freq divided by 2)
+		if(state->cfg.input_clk_is_div_2)
+			reg_907 |= (16 << 9);
+		else // otherwise the previous front-end puts out its input (default 30MHz) - no extra division necessary
+			reg_907 |= (8 << 9);
+	} else {
+		reg_907 |= (bw->pll_ratio & 0x3f) << 9;
+		reg_910 |= (bw->pll_prediv << 5);
+	}
+
+	dib7000m_write_word(state, 910, reg_910); // pll cfg
+	dib7000m_write_word(state, 907, reg_907); // clk cfg0
+	dib7000m_write_word(state, 908, 0x0006);  // clk_cfg1
+
+	dib7000m_reset_pll_common(state, bw);
+}
+
+static void dib7000mc_reset_pll(struct dib7000m_state *state)
+{
+	const struct dibx000_bandwidth_config *bw = state->cfg.bw;
+	u16 clk_cfg1;
+
+	// clk_cfg0
+	dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0));
+
+	// clk_cfg1
+	//dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) |
+	clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) |
+			(bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) |
+			(1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0);
+	dib7000m_write_word(state, 908, clk_cfg1);
+	clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3);
+	dib7000m_write_word(state, 908, clk_cfg1);
+
+	// smpl_cfg
+	dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7));
+
+	dib7000m_reset_pll_common(state, bw);
+}
+
+static int dib7000m_reset_gpio(struct dib7000m_state *st)
+{
+	/* reset the GPIOs */
+	dib7000m_write_word(st, 773, st->cfg.gpio_dir);
+	dib7000m_write_word(st, 774, st->cfg.gpio_val);
+
+	/* TODO 782 is P_gpio_od */
+
+	dib7000m_write_word(st, 775, st->cfg.gpio_pwm_pos);
+
+	dib7000m_write_word(st, 780, st->cfg.pwm_freq_div);
+	return 0;
+}
+
+static u16 dib7000m_defaults_common[] =
+
+{
+	// auto search configuration
+	3, 2,
+		0x0004,
+		0x1000,
+		0x0814,
+
+	12, 6,
+		0x001b,
+		0x7740,
+		0x005b,
+		0x8d80,
+		0x01c9,
+		0xc380,
+		0x0000,
+		0x0080,
+		0x0000,
+		0x0090,
+		0x0001,
+		0xd4c0,
+
+	1, 26,
+		0x6680, // P_corm_thres Lock algorithms configuration
+
+	1, 170,
+		0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on
+
+	8, 173,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+
+	1, 182,
+		8192, // P_fft_nb_to_cut
+
+	2, 195,
+		0x0ccd, // P_pha3_thres
+		0,      // P_cti_use_cpe, P_cti_use_prog
+
+	1, 205,
+		0x200f, // P_cspu_regul, P_cspu_win_cut
+
+	5, 214,
+		0x023d, // P_adp_regul_cnt
+		0x00a4, // P_adp_noise_cnt
+		0x00a4, // P_adp_regul_ext
+		0x7ff0, // P_adp_noise_ext
+		0x3ccc, // P_adp_fil
+
+	1, 226,
+		0, // P_2d_byp_ti_num
+
+	1, 255,
+		0x800, // P_equal_thres_wgn
+
+	1, 263,
+		0x0001,
+
+	1, 281,
+		0x0010, // P_fec_*
+
+	1, 294,
+		0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
+
+	0
+};
+
+static u16 dib7000m_defaults[] =
+
+{
+	/* set ADC level to -16 */
+	11, 76,
+		(1 << 13) - 825 - 117,
+		(1 << 13) - 837 - 117,
+		(1 << 13) - 811 - 117,
+		(1 << 13) - 766 - 117,
+		(1 << 13) - 737 - 117,
+		(1 << 13) - 693 - 117,
+		(1 << 13) - 648 - 117,
+		(1 << 13) - 619 - 117,
+		(1 << 13) - 575 - 117,
+		(1 << 13) - 531 - 117,
+		(1 << 13) - 501 - 117,
+
+	// Tuner IO bank: max drive (14mA)
+	1, 912,
+		0x2c8a,
+
+	1, 1817,
+		1,
+
+	0,
+};
+
+static int dib7000m_demod_reset(struct dib7000m_state *state)
+{
+	dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
+
+	/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
+	dib7000m_set_adc_state(state, DIBX000_VBG_ENABLE);
+
+	/* restart all parts */
+	dib7000m_write_word(state,  898, 0xffff);
+	dib7000m_write_word(state,  899, 0xffff);
+	dib7000m_write_word(state,  900, 0xff0f);
+	dib7000m_write_word(state,  901, 0xfffc);
+
+	dib7000m_write_word(state,  898, 0);
+	dib7000m_write_word(state,  899, 0);
+	dib7000m_write_word(state,  900, 0);
+	dib7000m_write_word(state,  901, 0);
+
+	if (state->revision == 0x4000)
+		dib7000m_reset_pll(state);
+	else
+		dib7000mc_reset_pll(state);
+
+	if (dib7000m_reset_gpio(state) != 0)
+		dprintk( "GPIO reset was not successful.");
+
+	if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
+		dprintk( "OUTPUT_MODE could not be reset.");
+
+	/* unforce divstr regardless whether i2c enumeration was done or not */
+	dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) );
+
+	dib7000m_set_bandwidth(state, 8000);
+
+	dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON);
+	dib7000m_sad_calib(state);
+	dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
+
+	if (state->cfg.dvbt_mode)
+		dib7000m_write_word(state, 1796, 0x0); // select DVB-T output
+
+	if (state->cfg.mobile_mode)
+		dib7000m_write_word(state, 261 + state->reg_offs, 2);
+	else
+		dib7000m_write_word(state, 224 + state->reg_offs, 1);
+
+	// P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
+	if(state->cfg.tuner_is_baseband)
+		dib7000m_write_word(state, 36, 0x0755);
+	else
+		dib7000m_write_word(state, 36, 0x1f55);
+
+	// P_divclksel=3 P_divbitsel=1
+	if (state->revision == 0x4000)
+		dib7000m_write_word(state, 909, (3 << 10) | (1 << 6));
+	else
+		dib7000m_write_word(state, 909, (3 << 4) | 1);
+
+	dib7000m_write_tab(state, dib7000m_defaults_common);
+	dib7000m_write_tab(state, dib7000m_defaults);
+
+	dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY);
+
+	state->internal_clk = state->cfg.bw->internal;
+
+	return 0;
+}
+
+static void dib7000m_restart_agc(struct dib7000m_state *state)
+{
+	// P_restart_iqc & P_restart_agc
+	dib7000m_write_word(state, 898, 0x0c00);
+	dib7000m_write_word(state, 898, 0x0000);
+}
+
+static int dib7000m_agc_soft_split(struct dib7000m_state *state)
+{
+	u16 agc,split_offset;
+
+	if(!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
+		return 0;
+
+	// n_agc_global
+	agc = dib7000m_read_word(state, 390);
+
+	if (agc > state->current_agc->split.min_thres)
+		split_offset = state->current_agc->split.min;
+	else if (agc < state->current_agc->split.max_thres)
+		split_offset = state->current_agc->split.max;
+	else
+		split_offset = state->current_agc->split.max *
+			(agc - state->current_agc->split.min_thres) /
+			(state->current_agc->split.max_thres - state->current_agc->split.min_thres);
+
+	dprintk( "AGC split_offset: %d",split_offset);
+
+	// P_agc_force_split and P_agc_split_offset
+	return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset);
+}
+
+static int dib7000m_update_lna(struct dib7000m_state *state)
+{
+	u16 dyn_gain;
+
+	if (state->cfg.update_lna) {
+		// read dyn_gain here (because it is demod-dependent and not fe)
+		dyn_gain = dib7000m_read_word(state, 390);
+
+		if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
+			dib7000m_restart_agc(state);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
+{
+	struct dibx000_agc_config *agc = NULL;
+	int i;
+	if (state->current_band == band && state->current_agc != NULL)
+		return 0;
+	state->current_band = band;
+
+	for (i = 0; i < state->cfg.agc_config_count; i++)
+		if (state->cfg.agc[i].band_caps & band) {
+			agc = &state->cfg.agc[i];
+			break;
+		}
+
+	if (agc == NULL) {
+		dprintk( "no valid AGC configuration found for band 0x%02x",band);
+		return -EINVAL;
+	}
+
+	state->current_agc = agc;
+
+	/* AGC */
+	dib7000m_write_word(state, 72 ,  agc->setup);
+	dib7000m_write_word(state, 73 ,  agc->inv_gain);
+	dib7000m_write_word(state, 74 ,  agc->time_stabiliz);
+	dib7000m_write_word(state, 97 , (agc->alpha_level << 12) | agc->thlock);
+
+	// Demod AGC loop configuration
+	dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp);
+	dib7000m_write_word(state, 99, (agc->beta_mant  << 6) | agc->beta_exp);
+
+	dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",
+		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
+
+	/* AGC continued */
+	if (state->wbd_ref != 0)
+		dib7000m_write_word(state, 102, state->wbd_ref);
+	else // use default
+		dib7000m_write_word(state, 102, agc->wbd_ref);
+
+	dib7000m_write_word(state, 103, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) );
+	dib7000m_write_word(state, 104,  agc->agc1_max);
+	dib7000m_write_word(state, 105,  agc->agc1_min);
+	dib7000m_write_word(state, 106,  agc->agc2_max);
+	dib7000m_write_word(state, 107,  agc->agc2_min);
+	dib7000m_write_word(state, 108, (agc->agc1_pt1 << 8) | agc->agc1_pt2 );
+	dib7000m_write_word(state, 109, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
+	dib7000m_write_word(state, 110, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
+	dib7000m_write_word(state, 111, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
+
+	if (state->revision > 0x4000) { // settings for the MC
+		dib7000m_write_word(state, 71,   agc->agc1_pt3);
+//		dprintk( "929: %x %d %d",
+//			(dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel);
+		dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
+	} else {
+		// wrong default values
+		u16 b[9] = { 676, 696, 717, 737, 758, 778, 799, 819, 840 };
+		for (i = 0; i < 9; i++)
+			dib7000m_write_word(state, 88 + i, b[i]);
+	}
+	return 0;
+}
+
+static void dib7000m_update_timf(struct dib7000m_state *state)
+{
+	u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437);
+	state->timf = timf * 160 / (state->current_bandwidth / 50);
+	dib7000m_write_word(state, 23, (u16) (timf >> 16));
+	dib7000m_write_word(state, 24, (u16) (timf & 0xffff));
+	dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default);
+}
+
+static int dib7000m_agc_startup(struct dvb_frontend *demod)
+{
+	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
+	struct dib7000m_state *state = demod->demodulator_priv;
+	u16 cfg_72 = dib7000m_read_word(state, 72);
+	int ret = -1;
+	u8 *agc_state = &state->agc_state;
+	u8 agc_split;
+
+	switch (state->agc_state) {
+		case 0:
+			// set power-up level: interf+analog+AGC
+			dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC);
+			dib7000m_set_adc_state(state, DIBX000_ADC_ON);
+
+			if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
+				return -1;
+
+			ret = 7; /* ADC power up */
+			(*agc_state)++;
+			break;
+
+		case 1:
+			/* AGC initialization */
+			if (state->cfg.agc_control)
+				state->cfg.agc_control(&state->demod, 1);
+
+			dib7000m_write_word(state, 75, 32768);
+			if (!state->current_agc->perform_agc_softsplit) {
+				/* we are using the wbd - so slow AGC startup */
+				dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */
+				(*agc_state)++;
+				ret = 5;
+			} else {
+				/* default AGC startup */
+				(*agc_state) = 4;
+				/* wait AGC rough lock time */
+				ret = 7;
+			}
+
+			dib7000m_restart_agc(state);
+			break;
+
+		case 2: /* fast split search path after 5sec */
+			dib7000m_write_word(state,  72, cfg_72 | (1 << 4)); /* freeze AGC loop */
+			dib7000m_write_word(state, 103, 2 << 9);            /* fast split search 0.25kHz */
+			(*agc_state)++;
+			ret = 14;
+			break;
+
+	case 3: /* split search ended */
+			agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */
+			dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */
+
+			dib7000m_write_word(state, 72,  cfg_72 & ~(1 << 4));   /* std AGC loop */
+			dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
+
+			dib7000m_restart_agc(state);
+
+			dprintk( "SPLIT %p: %hd", demod, agc_split);
+
+			(*agc_state)++;
+			ret = 5;
+			break;
+
+		case 4: /* LNA startup */
+			/* wait AGC accurate lock time */
+			ret = 7;
+
+			if (dib7000m_update_lna(state))
+				// wait only AGC rough lock time
+				ret = 5;
+			else
+				(*agc_state)++;
+			break;
+
+		case 5:
+			dib7000m_agc_soft_split(state);
+
+			if (state->cfg.agc_control)
+				state->cfg.agc_control(&state->demod, 0);
+
+			(*agc_state)++;
+			break;
+
+		default:
+			break;
+	}
+	return ret;
+}
+
+static void dib7000m_set_channel(struct dib7000m_state *state, struct dtv_frontend_properties *ch,
+				 u8 seq)
+{
+	u16 value, est[4];
+
+	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
+
+	/* nfft, guard, qam, alpha */
+	value = 0;
+	switch (ch->transmission_mode) {
+		case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
+		case TRANSMISSION_MODE_4K: value |= (2 << 7); break;
+		default:
+		case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
+	}
+	switch (ch->guard_interval) {
+		case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
+		case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
+		case GUARD_INTERVAL_1_4:  value |= (3 << 5); break;
+		default:
+		case GUARD_INTERVAL_1_8:  value |= (2 << 5); break;
+	}
+	switch (ch->modulation) {
+		case QPSK:  value |= (0 << 3); break;
+		case QAM_16: value |= (1 << 3); break;
+		default:
+		case QAM_64: value |= (2 << 3); break;
+	}
+	switch (HIERARCHY_1) {
+		case HIERARCHY_2: value |= 2; break;
+		case HIERARCHY_4: value |= 4; break;
+		default:
+		case HIERARCHY_1: value |= 1; break;
+	}
+	dib7000m_write_word(state, 0, value);
+	dib7000m_write_word(state, 5, (seq << 4));
+
+	/* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
+	value = 0;
+	if (1 != 0)
+		value |= (1 << 6);
+	if (ch->hierarchy == 1)
+		value |= (1 << 4);
+	if (1 == 1)
+		value |= 1;
+	switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
+		case FEC_2_3: value |= (2 << 1); break;
+		case FEC_3_4: value |= (3 << 1); break;
+		case FEC_5_6: value |= (5 << 1); break;
+		case FEC_7_8: value |= (7 << 1); break;
+		default:
+		case FEC_1_2: value |= (1 << 1); break;
+	}
+	dib7000m_write_word(state, 267 + state->reg_offs, value);
+
+	/* offset loop parameters */
+
+	/* P_timf_alpha = 6, P_corm_alpha=6, P_corm_thres=0x80 */
+	dib7000m_write_word(state, 26, (6 << 12) | (6 << 8) | 0x80);
+
+	/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=1, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
+	dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (1 << 9) | (3 << 5) | (1 << 4) | (0x3));
+
+	/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max=3 */
+	dib7000m_write_word(state, 32, (0 << 4) | 0x3);
+
+	/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step=5 */
+	dib7000m_write_word(state, 33, (0 << 4) | 0x5);
+
+	/* P_dvsy_sync_wait */
+	switch (ch->transmission_mode) {
+		case TRANSMISSION_MODE_8K: value = 256; break;
+		case TRANSMISSION_MODE_4K: value = 128; break;
+		case TRANSMISSION_MODE_2K:
+		default: value = 64; break;
+	}
+	switch (ch->guard_interval) {
+		case GUARD_INTERVAL_1_16: value *= 2; break;
+		case GUARD_INTERVAL_1_8:  value *= 4; break;
+		case GUARD_INTERVAL_1_4:  value *= 8; break;
+		default:
+		case GUARD_INTERVAL_1_32: value *= 1; break;
+	}
+	state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO
+
+	/* deactive the possibility of diversity reception if extended interleave - not for 7000MC */
+	/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
+	if (1 == 1 || state->revision > 0x4000)
+		state->div_force_off = 0;
+	else
+		state->div_force_off = 1;
+	dib7000m_set_diversity_in(&state->demod, state->div_state);
+
+	/* channel estimation fine configuration */
+	switch (ch->modulation) {
+		case QAM_64:
+			est[0] = 0x0148;       /* P_adp_regul_cnt 0.04 */
+			est[1] = 0xfff0;       /* P_adp_noise_cnt -0.002 */
+			est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
+			est[3] = 0xfff8;       /* P_adp_noise_ext -0.001 */
+			break;
+		case QAM_16:
+			est[0] = 0x023d;       /* P_adp_regul_cnt 0.07 */
+			est[1] = 0xffdf;       /* P_adp_noise_cnt -0.004 */
+			est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
+			est[3] = 0xfff0;       /* P_adp_noise_ext -0.002 */
+			break;
+		default:
+			est[0] = 0x099a;       /* P_adp_regul_cnt 0.3 */
+			est[1] = 0xffae;       /* P_adp_noise_cnt -0.01 */
+			est[2] = 0x0333;       /* P_adp_regul_ext 0.1 */
+			est[3] = 0xfff8;       /* P_adp_noise_ext -0.002 */
+			break;
+	}
+	for (value = 0; value < 4; value++)
+		dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]);
+
+	// set power-up level: autosearch
+	dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD);
+}
+
+static int dib7000m_autosearch_start(struct dvb_frontend *demod)
+{
+	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
+	struct dib7000m_state *state = demod->demodulator_priv;
+	struct dtv_frontend_properties schan;
+	int ret = 0;
+	u32 value, factor;
+
+	schan = *ch;
+
+	schan.modulation = QAM_64;
+	schan.guard_interval        = GUARD_INTERVAL_1_32;
+	schan.transmission_mode         = TRANSMISSION_MODE_8K;
+	schan.code_rate_HP = FEC_2_3;
+	schan.code_rate_LP = FEC_3_4;
+	schan.hierarchy    = 0;
+
+	dib7000m_set_channel(state, &schan, 7);
+
+	factor = BANDWIDTH_TO_KHZ(schan.bandwidth_hz);
+	if (factor >= 5000)
+		factor = 1;
+	else
+		factor = 6;
+
+	// always use the setting for 8MHz here lock_time for 7,6 MHz are longer
+	value = 30 * state->internal_clk * factor;
+	ret |= dib7000m_write_word(state, 6,  (u16) ((value >> 16) & 0xffff)); // lock0 wait time
+	ret |= dib7000m_write_word(state, 7,  (u16)  (value        & 0xffff)); // lock0 wait time
+	value = 100 * state->internal_clk * factor;
+	ret |= dib7000m_write_word(state, 8,  (u16) ((value >> 16) & 0xffff)); // lock1 wait time
+	ret |= dib7000m_write_word(state, 9,  (u16)  (value        & 0xffff)); // lock1 wait time
+	value = 500 * state->internal_clk * factor;
+	ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
+	ret |= dib7000m_write_word(state, 11, (u16)  (value        & 0xffff)); // lock2 wait time
+
+	// start search
+	value = dib7000m_read_word(state, 0);
+	ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9)));
+
+	/* clear n_irq_pending */
+	if (state->revision == 0x4000)
+		dib7000m_write_word(state, 1793, 0);
+	else
+		dib7000m_read_word(state, 537);
+
+	ret |= dib7000m_write_word(state, 0, (u16) value);
+
+	return ret;
+}
+
+static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg)
+{
+	u16 irq_pending = dib7000m_read_word(state, reg);
+
+	if (irq_pending & 0x1) { // failed
+		dprintk( "autosearch failed");
+		return 1;
+	}
+
+	if (irq_pending & 0x2) { // succeeded
+		dprintk( "autosearch succeeded");
+		return 2;
+	}
+	return 0; // still pending
+}
+
+static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod)
+{
+	struct dib7000m_state *state = demod->demodulator_priv;
+	if (state->revision == 0x4000)
+		return dib7000m_autosearch_irq(state, 1793);
+	else
+		return dib7000m_autosearch_irq(state, 537);
+}
+
+static int dib7000m_tune(struct dvb_frontend *demod)
+{
+	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
+	struct dib7000m_state *state = demod->demodulator_priv;
+	int ret = 0;
+	u16 value;
+
+	// we are already tuned - just resuming from suspend
+	if (ch != NULL)
+		dib7000m_set_channel(state, ch, 0);
+	else
+		return -EINVAL;
+
+	// restart demod
+	ret |= dib7000m_write_word(state, 898, 0x4000);
+	ret |= dib7000m_write_word(state, 898, 0x0000);
+	msleep(45);
+
+	dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD);
+	/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
+	ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
+
+	// never achieved a lock before - wait for timfreq to update
+	if (state->timf == 0)
+		msleep(200);
+
+	//dump_reg(state);
+	/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
+	value = (6 << 8) | 0x80;
+	switch (ch->transmission_mode) {
+		case TRANSMISSION_MODE_2K: value |= (7 << 12); break;
+		case TRANSMISSION_MODE_4K: value |= (8 << 12); break;
+		default:
+		case TRANSMISSION_MODE_8K: value |= (9 << 12); break;
+	}
+	ret |= dib7000m_write_word(state, 26, value);
+
+	/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
+	value = (0 << 4);
+	switch (ch->transmission_mode) {
+		case TRANSMISSION_MODE_2K: value |= 0x6; break;
+		case TRANSMISSION_MODE_4K: value |= 0x7; break;
+		default:
+		case TRANSMISSION_MODE_8K: value |= 0x8; break;
+	}
+	ret |= dib7000m_write_word(state, 32, value);
+
+	/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
+	value = (0 << 4);
+	switch (ch->transmission_mode) {
+		case TRANSMISSION_MODE_2K: value |= 0x6; break;
+		case TRANSMISSION_MODE_4K: value |= 0x7; break;
+		default:
+		case TRANSMISSION_MODE_8K: value |= 0x8; break;
+	}
+	ret |= dib7000m_write_word(state, 33,  value);
+
+	// we achieved a lock - it's time to update the timf freq
+	if ((dib7000m_read_word(state, 535) >> 6)  & 0x1)
+		dib7000m_update_timf(state);
+
+	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
+	return ret;
+}
+
+static int dib7000m_wakeup(struct dvb_frontend *demod)
+{
+	struct dib7000m_state *state = demod->demodulator_priv;
+
+	dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
+
+	if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
+		dprintk( "could not start Slow ADC");
+
+	return 0;
+}
+
+static int dib7000m_sleep(struct dvb_frontend *demod)
+{
+	struct dib7000m_state *st = demod->demodulator_priv;
+	dib7000m_set_output_mode(st, OUTMODE_HIGH_Z);
+	dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY);
+	return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) |
+		dib7000m_set_adc_state(st, DIBX000_ADC_OFF);
+}
+
+static int dib7000m_identify(struct dib7000m_state *state)
+{
+	u16 value;
+
+	if ((value = dib7000m_read_word(state, 896)) != 0x01b3) {
+		dprintk( "wrong Vendor ID (0x%x)",value);
+		return -EREMOTEIO;
+	}
+
+	state->revision = dib7000m_read_word(state, 897);
+	if (state->revision != 0x4000 &&
+		state->revision != 0x4001 &&
+		state->revision != 0x4002 &&
+		state->revision != 0x4003) {
+		dprintk( "wrong Device ID (0x%x)",value);
+		return -EREMOTEIO;
+	}
+
+	/* protect this driver to be used with 7000PC */
+	if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) {
+		dprintk( "this driver does not work with DiB7000PC");
+		return -EREMOTEIO;
+	}
+
+	switch (state->revision) {
+		case 0x4000: dprintk( "found DiB7000MA/PA/MB/PB"); break;
+		case 0x4001: state->reg_offs = 1; dprintk( "found DiB7000HC"); break;
+		case 0x4002: state->reg_offs = 1; dprintk( "found DiB7000MC"); break;
+		case 0x4003: state->reg_offs = 1; dprintk( "found DiB9000"); break;
+	}
+
+	return 0;
+}
+
+
+static int dib7000m_get_frontend(struct dvb_frontend* fe)
+{
+	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
+	struct dib7000m_state *state = fe->demodulator_priv;
+	u16 tps = dib7000m_read_word(state,480);
+
+	fep->inversion = INVERSION_AUTO;
+
+	fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
+
+	switch ((tps >> 8) & 0x3) {
+		case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break;
+		case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break;
+		/* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
+	}
+
+	switch (tps & 0x3) {
+		case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break;
+		case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break;
+		case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break;
+		case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break;
+	}
+
+	switch ((tps >> 14) & 0x3) {
+		case 0: fep->modulation = QPSK; break;
+		case 1: fep->modulation = QAM_16; break;
+		case 2:
+		default: fep->modulation = QAM_64; break;
+	}
+
+	/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
+	/* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
+
+	fep->hierarchy = HIERARCHY_NONE;
+	switch ((tps >> 5) & 0x7) {
+		case 1: fep->code_rate_HP = FEC_1_2; break;
+		case 2: fep->code_rate_HP = FEC_2_3; break;
+		case 3: fep->code_rate_HP = FEC_3_4; break;
+		case 5: fep->code_rate_HP = FEC_5_6; break;
+		case 7:
+		default: fep->code_rate_HP = FEC_7_8; break;
+
+	}
+
+	switch ((tps >> 2) & 0x7) {
+		case 1: fep->code_rate_LP = FEC_1_2; break;
+		case 2: fep->code_rate_LP = FEC_2_3; break;
+		case 3: fep->code_rate_LP = FEC_3_4; break;
+		case 5: fep->code_rate_LP = FEC_5_6; break;
+		case 7:
+		default: fep->code_rate_LP = FEC_7_8; break;
+	}
+
+	/* native interleaver: (dib7000m_read_word(state, 481) >>  5) & 0x1 */
+
+	return 0;
+}
+
+static int dib7000m_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
+	struct dib7000m_state *state = fe->demodulator_priv;
+	int time, ret;
+
+	dib7000m_set_output_mode(state, OUTMODE_HIGH_Z);
+
+	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz));
+
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+
+	/* start up the AGC */
+	state->agc_state = 0;
+	do {
+		time = dib7000m_agc_startup(fe);
+		if (time != -1)
+			msleep(time);
+	} while (time != -1);
+
+	if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
+		fep->guard_interval    == GUARD_INTERVAL_AUTO ||
+		fep->modulation        == QAM_AUTO ||
+		fep->code_rate_HP      == FEC_AUTO) {
+		int i = 800, found;
+
+		dib7000m_autosearch_start(fe);
+		do {
+			msleep(1);
+			found = dib7000m_autosearch_is_irq(fe);
+		} while (found == 0 && i--);
+
+		dprintk("autosearch returns: %d",found);
+		if (found == 0 || found == 1)
+			return 0; // no channel found
+
+		dib7000m_get_frontend(fe);
+	}
+
+	ret = dib7000m_tune(fe);
+
+	/* make this a config parameter */
+	dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
+	return ret;
+}
+
+static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+{
+	struct dib7000m_state *state = fe->demodulator_priv;
+	u16 lock = dib7000m_read_word(state, 535);
+
+	*stat = 0;
+
+	if (lock & 0x8000)
+		*stat |= FE_HAS_SIGNAL;
+	if (lock & 0x3000)
+		*stat |= FE_HAS_CARRIER;
+	if (lock & 0x0100)
+		*stat |= FE_HAS_VITERBI;
+	if (lock & 0x0010)
+		*stat |= FE_HAS_SYNC;
+	if (lock & 0x0008)
+		*stat |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int dib7000m_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct dib7000m_state *state = fe->demodulator_priv;
+	*ber = (dib7000m_read_word(state, 526) << 16) | dib7000m_read_word(state, 527);
+	return 0;
+}
+
+static int dib7000m_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
+{
+	struct dib7000m_state *state = fe->demodulator_priv;
+	*unc = dib7000m_read_word(state, 534);
+	return 0;
+}
+
+static int dib7000m_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct dib7000m_state *state = fe->demodulator_priv;
+	u16 val = dib7000m_read_word(state, 390);
+	*strength = 65535 - val;
+	return 0;
+}
+
+static int dib7000m_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+	*snr = 0x0000;
+	return 0;
+}
+
+static int dib7000m_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	return 0;
+}
+
+static void dib7000m_release(struct dvb_frontend *demod)
+{
+	struct dib7000m_state *st = demod->demodulator_priv;
+	dibx000_exit_i2c_master(&st->i2c_master);
+	kfree(st);
+}
+
+struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
+{
+	struct dib7000m_state *st = demod->demodulator_priv;
+	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
+}
+EXPORT_SYMBOL(dib7000m_get_i2c_master);
+
+int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+{
+	struct dib7000m_state *state = fe->demodulator_priv;
+	u16 val = dib7000m_read_word(state, 294 + state->reg_offs) & 0xffef;
+	val |= (onoff & 0x1) << 4;
+	dprintk("PID filter enabled %d", onoff);
+	return dib7000m_write_word(state, 294 + state->reg_offs, val);
+}
+EXPORT_SYMBOL(dib7000m_pid_filter_ctrl);
+
+int dib7000m_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+{
+	struct dib7000m_state *state = fe->demodulator_priv;
+	dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
+	return dib7000m_write_word(state, 300 + state->reg_offs + id,
+			onoff ? (1 << 13) | pid : 0);
+}
+EXPORT_SYMBOL(dib7000m_pid_filter);
+
+#if 0
+/* used with some prototype boards */
+int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods,
+		u8 default_addr, struct dib7000m_config cfg[])
+{
+	struct dib7000m_state st = { .i2c_adap = i2c };
+	int k = 0;
+	u8 new_addr = 0;
+
+	for (k = no_of_demods-1; k >= 0; k--) {
+		st.cfg = cfg[k];
+
+		/* designated i2c address */
+		new_addr          = (0x40 + k) << 1;
+		st.i2c_addr = new_addr;
+		if (dib7000m_identify(&st) != 0) {
+			st.i2c_addr = default_addr;
+			if (dib7000m_identify(&st) != 0) {
+				dprintk("DiB7000M #%d: not identified", k);
+				return -EIO;
+			}
+		}
+
+		/* start diversity to pull_down div_str - just for i2c-enumeration */
+		dib7000m_set_output_mode(&st, OUTMODE_DIVERSITY);
+
+		dib7000m_write_word(&st, 1796, 0x0); // select DVB-T output
+
+		/* set new i2c address and force divstart */
+		dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2);
+
+		dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
+	}
+
+	for (k = 0; k < no_of_demods; k++) {
+		st.cfg = cfg[k];
+		st.i2c_addr = (0x40 + k) << 1;
+
+		// unforce divstr
+		dib7000m_write_word(&st,1794, st.i2c_addr << 2);
+
+		/* deactivate div - it was just for i2c-enumeration */
+		dib7000m_set_output_mode(&st, OUTMODE_HIGH_Z);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(dib7000m_i2c_enumeration);
+#endif
+
+static struct dvb_frontend_ops dib7000m_ops;
+struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg)
+{
+	struct dvb_frontend *demod;
+	struct dib7000m_state *st;
+	st = kzalloc(sizeof(struct dib7000m_state), GFP_KERNEL);
+	if (st == NULL)
+		return NULL;
+
+	memcpy(&st->cfg, cfg, sizeof(struct dib7000m_config));
+	st->i2c_adap = i2c_adap;
+	st->i2c_addr = i2c_addr;
+
+	demod                   = &st->demod;
+	demod->demodulator_priv = st;
+	memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
+	mutex_init(&st->i2c_buffer_lock);
+
+	st->timf_default = cfg->bw->timf;
+
+	if (dib7000m_identify(st) != 0)
+		goto error;
+
+	if (st->revision == 0x4000)
+		dibx000_init_i2c_master(&st->i2c_master, DIB7000, st->i2c_adap, st->i2c_addr);
+	else
+		dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c_adap, st->i2c_addr);
+
+	dib7000m_demod_reset(st);
+
+	return demod;
+
+error:
+	kfree(st);
+	return NULL;
+}
+EXPORT_SYMBOL(dib7000m_attach);
+
+static struct dvb_frontend_ops dib7000m_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "DiBcom 7000MA/MB/PA/PB/MC",
+		.frequency_min      = 44250000,
+		.frequency_max      = 867250000,
+		.frequency_stepsize = 62500,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_RECOVER |
+			FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.release              = dib7000m_release,
+
+	.init                 = dib7000m_wakeup,
+	.sleep                = dib7000m_sleep,
+
+	.set_frontend         = dib7000m_set_frontend,
+	.get_tune_settings    = dib7000m_fe_get_tune_settings,
+	.get_frontend         = dib7000m_get_frontend,
+
+	.read_status          = dib7000m_read_status,
+	.read_ber             = dib7000m_read_ber,
+	.read_signal_strength = dib7000m_read_signal_strength,
+	.read_snr             = dib7000m_read_snr,
+	.read_ucblocks        = dib7000m_read_unc_blocks,
+};
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 7000MA/MB/PA/PB/MC COFDM demodulator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/dib7000m.h b/drivers/media/dvb-frontends/dib7000m.h
new file mode 100644
index 0000000..81fcf22
--- /dev/null
+++ b/drivers/media/dvb-frontends/dib7000m.h
@@ -0,0 +1,90 @@
+#ifndef DIB7000M_H
+#define DIB7000M_H
+
+#include "dibx000_common.h"
+
+struct dib7000m_config {
+	u8 dvbt_mode;
+	u8 output_mpeg2_in_188_bytes;
+	u8 hostbus_diversity;
+	u8 tuner_is_baseband;
+	u8 mobile_mode;
+	int (*update_lna) (struct dvb_frontend *, u16 agc_global);
+
+	u8 agc_config_count;
+	struct dibx000_agc_config *agc;
+
+	struct dibx000_bandwidth_config *bw;
+
+#define DIB7000M_GPIO_DEFAULT_DIRECTIONS 0xffff
+	u16 gpio_dir;
+#define DIB7000M_GPIO_DEFAULT_VALUES     0x0000
+	u16 gpio_val;
+#define DIB7000M_GPIO_PWM_POS0(v)        ((v & 0xf) << 12)
+#define DIB7000M_GPIO_PWM_POS1(v)        ((v & 0xf) << 8 )
+#define DIB7000M_GPIO_PWM_POS2(v)        ((v & 0xf) << 4 )
+#define DIB7000M_GPIO_PWM_POS3(v)         (v & 0xf)
+#define DIB7000M_GPIO_DEFAULT_PWM_POS    0xffff
+	u16 gpio_pwm_pos;
+
+	u16 pwm_freq_div;
+
+	u8 quartz_direct;
+
+	u8 input_clk_is_div_2;
+
+	int (*agc_control) (struct dvb_frontend *, u8 before);
+};
+
+#define DEFAULT_DIB7000M_I2C_ADDRESS 18
+
+#if defined(CONFIG_DVB_DIB7000M) || (defined(CONFIG_DVB_DIB7000M_MODULE) && \
+				     defined(MODULE))
+extern struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap,
+					    u8 i2c_addr,
+					    struct dib7000m_config *cfg);
+extern struct i2c_adapter *dib7000m_get_i2c_master(struct dvb_frontend *,
+						   enum dibx000_i2c_interface,
+						   int);
+extern int dib7000m_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
+extern int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff);
+#else
+static inline
+struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap,
+				     u8 i2c_addr, struct dib7000m_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline
+struct i2c_adapter *dib7000m_get_i2c_master(struct dvb_frontend *demod,
+					    enum dibx000_i2c_interface intf,
+					    int gating)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+static inline int dib7000m_pid_filter(struct dvb_frontend *fe, u8 id,
+						u16 pid, u8 onoff)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe,
+						uint8_t onoff)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+#endif
+
+/* TODO
+extern INT dib7000m_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val);
+extern INT dib7000m_enable_vbg_voltage(struct dibDemod *demod);
+extern void dib7000m_set_hostbus_diversity(struct dibDemod *demod, UCHAR onoff);
+extern USHORT dib7000m_get_current_agc_global(struct dibDemod *demod);
+*/
+
+#endif
diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c
new file mode 100644
index 0000000..3e1eefa
--- /dev/null
+++ b/drivers/media/dvb-frontends/dib7000p.c
@@ -0,0 +1,2457 @@
+/*
+ * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).
+ *
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
+ *
+ * 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, version 2.
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+#include "dvb_math.h"
+#include "dvb_frontend.h"
+
+#include "dib7000p.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+static int buggy_sfn_workaround;
+module_param(buggy_sfn_workaround, int, 0644);
+MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)
+
+struct i2c_device {
+	struct i2c_adapter *i2c_adap;
+	u8 i2c_addr;
+};
+
+struct dib7000p_state {
+	struct dvb_frontend demod;
+	struct dib7000p_config cfg;
+
+	u8 i2c_addr;
+	struct i2c_adapter *i2c_adap;
+
+	struct dibx000_i2c_master i2c_master;
+
+	u16 wbd_ref;
+
+	u8 current_band;
+	u32 current_bandwidth;
+	struct dibx000_agc_config *current_agc;
+	u32 timf;
+
+	u8 div_force_off:1;
+	u8 div_state:1;
+	u16 div_sync_wait;
+
+	u8 agc_state;
+
+	u16 gpio_dir;
+	u16 gpio_val;
+
+	u8 sfn_workaround_active:1;
+
+#define SOC7090 0x7090
+	u16 version;
+
+	u16 tuner_enable;
+	struct i2c_adapter dib7090_tuner_adap;
+
+	/* for the I2C transfer */
+	struct i2c_msg msg[2];
+	u8 i2c_write_buffer[4];
+	u8 i2c_read_buffer[2];
+	struct mutex i2c_buffer_lock;
+
+	u8 input_mode_mpeg;
+};
+
+enum dib7000p_power_mode {
+	DIB7000P_POWER_ALL = 0,
+	DIB7000P_POWER_ANALOG_ADC,
+	DIB7000P_POWER_INTERFACE_ONLY,
+};
+
+/* dib7090 specific fonctions */
+static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
+static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
+static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode);
+static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode);
+
+static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
+{
+	u16 ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return 0;
+	}
+
+	state->i2c_write_buffer[0] = reg >> 8;
+	state->i2c_write_buffer[1] = reg & 0xff;
+
+	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+	state->msg[0].addr = state->i2c_addr >> 1;
+	state->msg[0].flags = 0;
+	state->msg[0].buf = state->i2c_write_buffer;
+	state->msg[0].len = 2;
+	state->msg[1].addr = state->i2c_addr >> 1;
+	state->msg[1].flags = I2C_M_RD;
+	state->msg[1].buf = state->i2c_read_buffer;
+	state->msg[1].len = 2;
+
+	if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
+		dprintk("i2c read error on %d", reg);
+
+	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
+}
+
+static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
+{
+	int ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+
+	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+	state->i2c_write_buffer[1] = reg & 0xff;
+	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+	state->i2c_write_buffer[3] = val & 0xff;
+
+	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
+	state->msg[0].addr = state->i2c_addr >> 1;
+	state->msg[0].flags = 0;
+	state->msg[0].buf = state->i2c_write_buffer;
+	state->msg[0].len = 4;
+
+	ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
+			-EREMOTEIO : 0);
+	mutex_unlock(&state->i2c_buffer_lock);
+	return ret;
+}
+
+static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
+{
+	u16 l = 0, r, *n;
+	n = buf;
+	l = *n++;
+	while (l) {
+		r = *n++;
+
+		do {
+			dib7000p_write_word(state, r, *n++);
+			r++;
+		} while (--l);
+		l = *n++;
+	}
+}
+
+static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
+{
+	int ret = 0;
+	u16 outreg, fifo_threshold, smo_mode;
+
+	outreg = 0;
+	fifo_threshold = 1792;
+	smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
+
+	dprintk("setting output mode for demod %p to %d", &state->demod, mode);
+
+	switch (mode) {
+	case OUTMODE_MPEG2_PAR_GATED_CLK:
+		outreg = (1 << 10);	/* 0x0400 */
+		break;
+	case OUTMODE_MPEG2_PAR_CONT_CLK:
+		outreg = (1 << 10) | (1 << 6);	/* 0x0440 */
+		break;
+	case OUTMODE_MPEG2_SERIAL:
+		outreg = (1 << 10) | (2 << 6) | (0 << 1);	/* 0x0480 */
+		break;
+	case OUTMODE_DIVERSITY:
+		if (state->cfg.hostbus_diversity)
+			outreg = (1 << 10) | (4 << 6);	/* 0x0500 */
+		else
+			outreg = (1 << 11);
+		break;
+	case OUTMODE_MPEG2_FIFO:
+		smo_mode |= (3 << 1);
+		fifo_threshold = 512;
+		outreg = (1 << 10) | (5 << 6);
+		break;
+	case OUTMODE_ANALOG_ADC:
+		outreg = (1 << 10) | (3 << 6);
+		break;
+	case OUTMODE_HIGH_Z:
+		outreg = 0;
+		break;
+	default:
+		dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod);
+		break;
+	}
+
+	if (state->cfg.output_mpeg2_in_188_bytes)
+		smo_mode |= (1 << 5);
+
+	ret |= dib7000p_write_word(state, 235, smo_mode);
+	ret |= dib7000p_write_word(state, 236, fifo_threshold);	/* synchronous fread */
+	if (state->version != SOC7090)
+		ret |= dib7000p_write_word(state, 1286, outreg);	/* P_Div_active */
+
+	return ret;
+}
+
+static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
+{
+	struct dib7000p_state *state = demod->demodulator_priv;
+
+	if (state->div_force_off) {
+		dprintk("diversity combination deactivated - forced by COFDM parameters");
+		onoff = 0;
+		dib7000p_write_word(state, 207, 0);
+	} else
+		dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
+
+	state->div_state = (u8) onoff;
+
+	if (onoff) {
+		dib7000p_write_word(state, 204, 6);
+		dib7000p_write_word(state, 205, 16);
+		/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
+	} else {
+		dib7000p_write_word(state, 204, 1);
+		dib7000p_write_word(state, 205, 0);
+	}
+
+	return 0;
+}
+
+static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
+{
+	/* by default everything is powered off */
+	u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
+
+	/* now, depending on the requested mode, we power on */
+	switch (mode) {
+		/* power up everything in the demod */
+	case DIB7000P_POWER_ALL:
+		reg_774 = 0x0000;
+		reg_775 = 0x0000;
+		reg_776 = 0x0;
+		reg_899 = 0x0;
+		if (state->version == SOC7090)
+			reg_1280 &= 0x001f;
+		else
+			reg_1280 &= 0x01ff;
+		break;
+
+	case DIB7000P_POWER_ANALOG_ADC:
+		/* dem, cfg, iqc, sad, agc */
+		reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
+		/* nud */
+		reg_776 &= ~((1 << 0));
+		/* Dout */
+		if (state->version != SOC7090)
+			reg_1280 &= ~((1 << 11));
+		reg_1280 &= ~(1 << 6);
+		/* fall through wanted to enable the interfaces */
+
+		/* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
+	case DIB7000P_POWER_INTERFACE_ONLY:	/* TODO power up either SDIO or I2C */
+		if (state->version == SOC7090)
+			reg_1280 &= ~((1 << 7) | (1 << 5));
+		else
+			reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
+		break;
+
+/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
+	}
+
+	dib7000p_write_word(state, 774, reg_774);
+	dib7000p_write_word(state, 775, reg_775);
+	dib7000p_write_word(state, 776, reg_776);
+	dib7000p_write_word(state, 1280, reg_1280);
+	if (state->version != SOC7090)
+		dib7000p_write_word(state, 899, reg_899);
+
+	return 0;
+}
+
+static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
+{
+	u16 reg_908 = 0, reg_909 = 0;
+	u16 reg;
+
+	if (state->version != SOC7090) {
+		reg_908 = dib7000p_read_word(state, 908);
+		reg_909 = dib7000p_read_word(state, 909);
+	}
+
+	switch (no) {
+	case DIBX000_SLOW_ADC_ON:
+		if (state->version == SOC7090) {
+			reg = dib7000p_read_word(state, 1925);
+
+			dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2));	/* en_slowAdc = 1 & reset_sladc = 1 */
+
+			reg = dib7000p_read_word(state, 1925);	/* read acces to make it works... strange ... */
+			msleep(200);
+			dib7000p_write_word(state, 1925, reg & ~(1 << 4));	/* en_slowAdc = 1 & reset_sladc = 0 */
+
+			reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));
+			dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524);	/* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */
+		} else {
+			reg_909 |= (1 << 1) | (1 << 0);
+			dib7000p_write_word(state, 909, reg_909);
+			reg_909 &= ~(1 << 1);
+		}
+		break;
+
+	case DIBX000_SLOW_ADC_OFF:
+		if (state->version == SOC7090) {
+			reg = dib7000p_read_word(state, 1925);
+			dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4));	/* reset_sladc = 1 en_slowAdc = 0 */
+		} else
+			reg_909 |= (1 << 1) | (1 << 0);
+		break;
+
+	case DIBX000_ADC_ON:
+		reg_908 &= 0x0fff;
+		reg_909 &= 0x0003;
+		break;
+
+	case DIBX000_ADC_OFF:
+		reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
+		reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
+		break;
+
+	case DIBX000_VBG_ENABLE:
+		reg_908 &= ~(1 << 15);
+		break;
+
+	case DIBX000_VBG_DISABLE:
+		reg_908 |= (1 << 15);
+		break;
+
+	default:
+		break;
+	}
+
+//	dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
+
+	reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
+	reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
+
+	if (state->version != SOC7090) {
+		dib7000p_write_word(state, 908, reg_908);
+		dib7000p_write_word(state, 909, reg_909);
+	}
+}
+
+static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
+{
+	u32 timf;
+
+	// store the current bandwidth for later use
+	state->current_bandwidth = bw;
+
+	if (state->timf == 0) {
+		dprintk("using default timf");
+		timf = state->cfg.bw->timf;
+	} else {
+		dprintk("using updated timf");
+		timf = state->timf;
+	}
+
+	timf = timf * (bw / 50) / 160;
+
+	dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
+	dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));
+
+	return 0;
+}
+
+static int dib7000p_sad_calib(struct dib7000p_state *state)
+{
+/* internal */
+	dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
+
+	if (state->version == SOC7090)
+		dib7000p_write_word(state, 74, 2048);
+	else
+		dib7000p_write_word(state, 74, 776);
+
+	/* do the calibration */
+	dib7000p_write_word(state, 73, (1 << 0));
+	dib7000p_write_word(state, 73, (0 << 0));
+
+	msleep(1);
+
+	return 0;
+}
+
+int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
+{
+	struct dib7000p_state *state = demod->demodulator_priv;
+	if (value > 4095)
+		value = 4095;
+	state->wbd_ref = value;
+	return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
+}
+EXPORT_SYMBOL(dib7000p_set_wbd_ref);
+
+int dib7000p_get_agc_values(struct dvb_frontend *fe,
+		u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
+{
+	struct dib7000p_state *state = fe->demodulator_priv;
+
+	if (agc_global != NULL)
+		*agc_global = dib7000p_read_word(state, 394);
+	if (agc1 != NULL)
+		*agc1 = dib7000p_read_word(state, 392);
+	if (agc2 != NULL)
+		*agc2 = dib7000p_read_word(state, 393);
+	if (wbd != NULL)
+		*wbd = dib7000p_read_word(state, 397);
+
+	return 0;
+}
+EXPORT_SYMBOL(dib7000p_get_agc_values);
+
+static void dib7000p_reset_pll(struct dib7000p_state *state)
+{
+	struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
+	u16 clk_cfg0;
+
+	if (state->version == SOC7090) {
+		dib7000p_write_word(state, 1856, (!bw->pll_reset << 13) | (bw->pll_range << 12) | (bw->pll_ratio << 6) | (bw->pll_prediv));
+
+		while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
+			;
+
+		dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
+	} else {
+		/* force PLL bypass */
+		clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
+			(bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
+
+		dib7000p_write_word(state, 900, clk_cfg0);
+
+		/* P_pll_cfg */
+		dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
+		clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
+		dib7000p_write_word(state, 900, clk_cfg0);
+	}
+
+	dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
+	dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
+	dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
+	dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
+
+	dib7000p_write_word(state, 72, bw->sad_cfg);
+}
+
+static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
+{
+	u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
+	internal |= (u32) dib7000p_read_word(state, 19);
+	internal /= 1000;
+
+	return internal;
+}
+
+int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
+{
+	struct dib7000p_state *state = fe->demodulator_priv;
+	u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
+	u8 loopdiv, prediv;
+	u32 internal, xtal;
+
+	/* get back old values */
+	prediv = reg_1856 & 0x3f;
+	loopdiv = (reg_1856 >> 6) & 0x3f;
+
+	if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
+		dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
+		reg_1856 &= 0xf000;
+		reg_1857 = dib7000p_read_word(state, 1857);
+		dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
+
+		dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
+
+		/* write new system clk into P_sec_len */
+		internal = dib7000p_get_internal_freq(state);
+		xtal = (internal / loopdiv) * prediv;
+		internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio;	/* new internal */
+		dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
+		dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
+
+		dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
+
+		while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
+			dprintk("Waiting for PLL to lock");
+
+		return 0;
+	}
+	return -EIO;
+}
+EXPORT_SYMBOL(dib7000p_update_pll);
+
+static int dib7000p_reset_gpio(struct dib7000p_state *st)
+{
+	/* reset the GPIOs */
+	dprintk("gpio dir: %x: val: %x, pwm_pos: %x", st->gpio_dir, st->gpio_val, st->cfg.gpio_pwm_pos);
+
+	dib7000p_write_word(st, 1029, st->gpio_dir);
+	dib7000p_write_word(st, 1030, st->gpio_val);
+
+	/* TODO 1031 is P_gpio_od */
+
+	dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
+
+	dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
+	return 0;
+}
+
+static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
+{
+	st->gpio_dir = dib7000p_read_word(st, 1029);
+	st->gpio_dir &= ~(1 << num);	/* reset the direction bit */
+	st->gpio_dir |= (dir & 0x1) << num;	/* set the new direction */
+	dib7000p_write_word(st, 1029, st->gpio_dir);
+
+	st->gpio_val = dib7000p_read_word(st, 1030);
+	st->gpio_val &= ~(1 << num);	/* reset the direction bit */
+	st->gpio_val |= (val & 0x01) << num;	/* set the new value */
+	dib7000p_write_word(st, 1030, st->gpio_val);
+
+	return 0;
+}
+
+int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
+{
+	struct dib7000p_state *state = demod->demodulator_priv;
+	return dib7000p_cfg_gpio(state, num, dir, val);
+}
+EXPORT_SYMBOL(dib7000p_set_gpio);
+
+static u16 dib7000p_defaults[] = {
+	// auto search configuration
+	3, 2,
+	0x0004,
+	(1<<3)|(1<<11)|(1<<12)|(1<<13),
+	0x0814,			/* Equal Lock */
+
+	12, 6,
+	0x001b,
+	0x7740,
+	0x005b,
+	0x8d80,
+	0x01c9,
+	0xc380,
+	0x0000,
+	0x0080,
+	0x0000,
+	0x0090,
+	0x0001,
+	0xd4c0,
+
+	1, 26,
+	0x6680,
+
+	/* set ADC level to -16 */
+	11, 79,
+	(1 << 13) - 825 - 117,
+	(1 << 13) - 837 - 117,
+	(1 << 13) - 811 - 117,
+	(1 << 13) - 766 - 117,
+	(1 << 13) - 737 - 117,
+	(1 << 13) - 693 - 117,
+	(1 << 13) - 648 - 117,
+	(1 << 13) - 619 - 117,
+	(1 << 13) - 575 - 117,
+	(1 << 13) - 531 - 117,
+	(1 << 13) - 501 - 117,
+
+	1, 142,
+	0x0410,
+
+	/* disable power smoothing */
+	8, 145,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+
+	1, 154,
+	1 << 13,
+
+	1, 168,
+	0x0ccd,
+
+	1, 183,
+	0x200f,
+
+	1, 212,
+		0x169,
+
+	5, 187,
+	0x023d,
+	0x00a4,
+	0x00a4,
+	0x7ff0,
+	0x3ccc,
+
+	1, 198,
+	0x800,
+
+	1, 222,
+	0x0010,
+
+	1, 235,
+	0x0062,
+
+	0,
+};
+
+static int dib7000p_demod_reset(struct dib7000p_state *state)
+{
+	dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
+
+	if (state->version == SOC7090)
+		dibx000_reset_i2c_master(&state->i2c_master);
+
+	dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
+
+	/* restart all parts */
+	dib7000p_write_word(state, 770, 0xffff);
+	dib7000p_write_word(state, 771, 0xffff);
+	dib7000p_write_word(state, 772, 0x001f);
+	dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
+
+	dib7000p_write_word(state, 770, 0);
+	dib7000p_write_word(state, 771, 0);
+	dib7000p_write_word(state, 772, 0);
+	dib7000p_write_word(state, 1280, 0);
+
+	if (state->version != SOC7090) {
+		dib7000p_write_word(state,  898, 0x0003);
+		dib7000p_write_word(state,  898, 0);
+	}
+
+	/* default */
+	dib7000p_reset_pll(state);
+
+	if (dib7000p_reset_gpio(state) != 0)
+		dprintk("GPIO reset was not successful.");
+
+	if (state->version == SOC7090) {
+		dib7000p_write_word(state, 899, 0);
+
+		/* impulse noise */
+		dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
+		dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
+		dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
+		dib7000p_write_word(state, 273, (0<<6) | 30);
+	}
+	if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
+		dprintk("OUTPUT_MODE could not be reset.");
+
+	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
+	dib7000p_sad_calib(state);
+	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
+
+	/* unforce divstr regardless whether i2c enumeration was done or not */
+	dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
+
+	dib7000p_set_bandwidth(state, 8000);
+
+	if (state->version == SOC7090) {
+		dib7000p_write_word(state, 36, 0x0755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
+	} else {
+		if (state->cfg.tuner_is_baseband)
+			dib7000p_write_word(state, 36, 0x0755);
+		else
+			dib7000p_write_word(state, 36, 0x1f55);
+	}
+
+	dib7000p_write_tab(state, dib7000p_defaults);
+	if (state->version != SOC7090) {
+		dib7000p_write_word(state, 901, 0x0006);
+		dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
+		dib7000p_write_word(state, 905, 0x2c8e);
+	}
+
+	dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
+
+	return 0;
+}
+
+static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
+{
+	u16 tmp = 0;
+	tmp = dib7000p_read_word(state, 903);
+	dib7000p_write_word(state, 903, (tmp | 0x1));
+	tmp = dib7000p_read_word(state, 900);
+	dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
+}
+
+static void dib7000p_restart_agc(struct dib7000p_state *state)
+{
+	// P_restart_iqc & P_restart_agc
+	dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
+	dib7000p_write_word(state, 770, 0x0000);
+}
+
+static int dib7000p_update_lna(struct dib7000p_state *state)
+{
+	u16 dyn_gain;
+
+	if (state->cfg.update_lna) {
+		dyn_gain = dib7000p_read_word(state, 394);
+		if (state->cfg.update_lna(&state->demod, dyn_gain)) {
+			dib7000p_restart_agc(state);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
+{
+	struct dibx000_agc_config *agc = NULL;
+	int i;
+	if (state->current_band == band && state->current_agc != NULL)
+		return 0;
+	state->current_band = band;
+
+	for (i = 0; i < state->cfg.agc_config_count; i++)
+		if (state->cfg.agc[i].band_caps & band) {
+			agc = &state->cfg.agc[i];
+			break;
+		}
+
+	if (agc == NULL) {
+		dprintk("no valid AGC configuration found for band 0x%02x", band);
+		return -EINVAL;
+	}
+
+	state->current_agc = agc;
+
+	/* AGC */
+	dib7000p_write_word(state, 75, agc->setup);
+	dib7000p_write_word(state, 76, agc->inv_gain);
+	dib7000p_write_word(state, 77, agc->time_stabiliz);
+	dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
+
+	// Demod AGC loop configuration
+	dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
+	dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
+
+	/* AGC continued */
+	dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
+		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
+
+	if (state->wbd_ref != 0)
+		dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
+	else
+		dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
+
+	dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
+
+	dib7000p_write_word(state, 107, agc->agc1_max);
+	dib7000p_write_word(state, 108, agc->agc1_min);
+	dib7000p_write_word(state, 109, agc->agc2_max);
+	dib7000p_write_word(state, 110, agc->agc2_min);
+	dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
+	dib7000p_write_word(state, 112, agc->agc1_pt3);
+	dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
+	dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
+	dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
+	return 0;
+}
+
+static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
+{
+	u32 internal = dib7000p_get_internal_freq(state);
+	s32 unit_khz_dds_val = 67108864 / (internal);	/* 2**26 / Fsampling is the unit 1KHz offset */
+	u32 abs_offset_khz = ABS(offset_khz);
+	u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
+	u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
+
+	dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert);
+
+	if (offset_khz < 0)
+		unit_khz_dds_val *= -1;
+
+	/* IF tuner */
+	if (invert)
+		dds -= (abs_offset_khz * unit_khz_dds_val);	/* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */
+	else
+		dds += (abs_offset_khz * unit_khz_dds_val);
+
+	if (abs_offset_khz <= (internal / 2)) {	/* Max dds offset is the half of the demod freq */
+		dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
+		dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
+	}
+}
+
+static int dib7000p_agc_startup(struct dvb_frontend *demod)
+{
+	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
+	struct dib7000p_state *state = demod->demodulator_priv;
+	int ret = -1;
+	u8 *agc_state = &state->agc_state;
+	u8 agc_split;
+	u16 reg;
+	u32 upd_demod_gain_period = 0x1000;
+
+	switch (state->agc_state) {
+	case 0:
+		dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
+		if (state->version == SOC7090) {
+			reg = dib7000p_read_word(state, 0x79b) & 0xff00;
+			dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF);	/* lsb */
+			dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
+
+			/* enable adc i & q */
+			reg = dib7000p_read_word(state, 0x780);
+			dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
+		} else {
+			dib7000p_set_adc_state(state, DIBX000_ADC_ON);
+			dib7000p_pll_clk_cfg(state);
+		}
+
+		if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
+			return -1;
+
+		dib7000p_set_dds(state, 0);
+		ret = 7;
+		(*agc_state)++;
+		break;
+
+	case 1:
+		if (state->cfg.agc_control)
+			state->cfg.agc_control(&state->demod, 1);
+
+		dib7000p_write_word(state, 78, 32768);
+		if (!state->current_agc->perform_agc_softsplit) {
+			/* we are using the wbd - so slow AGC startup */
+			/* force 0 split on WBD and restart AGC */
+			dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
+			(*agc_state)++;
+			ret = 5;
+		} else {
+			/* default AGC startup */
+			(*agc_state) = 4;
+			/* wait AGC rough lock time */
+			ret = 7;
+		}
+
+		dib7000p_restart_agc(state);
+		break;
+
+	case 2:		/* fast split search path after 5sec */
+		dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4));	/* freeze AGC loop */
+		dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8));	/* fast split search 0.25kHz */
+		(*agc_state)++;
+		ret = 14;
+		break;
+
+	case 3:		/* split search ended */
+		agc_split = (u8) dib7000p_read_word(state, 396);	/* store the split value for the next time */
+		dib7000p_write_word(state, 78, dib7000p_read_word(state, 394));	/* set AGC gain start value */
+
+		dib7000p_write_word(state, 75, state->current_agc->setup);	/* std AGC loop */
+		dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split);	/* standard split search */
+
+		dib7000p_restart_agc(state);
+
+		dprintk("SPLIT %p: %hd", demod, agc_split);
+
+		(*agc_state)++;
+		ret = 5;
+		break;
+
+	case 4:		/* LNA startup */
+		ret = 7;
+
+		if (dib7000p_update_lna(state))
+			ret = 5;
+		else
+			(*agc_state)++;
+		break;
+
+	case 5:
+		if (state->cfg.agc_control)
+			state->cfg.agc_control(&state->demod, 0);
+		(*agc_state)++;
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+static void dib7000p_update_timf(struct dib7000p_state *state)
+{
+	u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
+	state->timf = timf * 160 / (state->current_bandwidth / 50);
+	dib7000p_write_word(state, 23, (u16) (timf >> 16));
+	dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
+	dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf);
+
+}
+
+u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
+{
+	struct dib7000p_state *state = fe->demodulator_priv;
+	switch (op) {
+	case DEMOD_TIMF_SET:
+		state->timf = timf;
+		break;
+	case DEMOD_TIMF_UPDATE:
+		dib7000p_update_timf(state);
+		break;
+	case DEMOD_TIMF_GET:
+		break;
+	}
+	dib7000p_set_bandwidth(state, state->current_bandwidth);
+	return state->timf;
+}
+EXPORT_SYMBOL(dib7000p_ctrl_timf);
+
+static void dib7000p_set_channel(struct dib7000p_state *state,
+				 struct dtv_frontend_properties *ch, u8 seq)
+{
+	u16 value, est[4];
+
+	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
+
+	/* nfft, guard, qam, alpha */
+	value = 0;
+	switch (ch->transmission_mode) {
+	case TRANSMISSION_MODE_2K:
+		value |= (0 << 7);
+		break;
+	case TRANSMISSION_MODE_4K:
+		value |= (2 << 7);
+		break;
+	default:
+	case TRANSMISSION_MODE_8K:
+		value |= (1 << 7);
+		break;
+	}
+	switch (ch->guard_interval) {
+	case GUARD_INTERVAL_1_32:
+		value |= (0 << 5);
+		break;
+	case GUARD_INTERVAL_1_16:
+		value |= (1 << 5);
+		break;
+	case GUARD_INTERVAL_1_4:
+		value |= (3 << 5);
+		break;
+	default:
+	case GUARD_INTERVAL_1_8:
+		value |= (2 << 5);
+		break;
+	}
+	switch (ch->modulation) {
+	case QPSK:
+		value |= (0 << 3);
+		break;
+	case QAM_16:
+		value |= (1 << 3);
+		break;
+	default:
+	case QAM_64:
+		value |= (2 << 3);
+		break;
+	}
+	switch (HIERARCHY_1) {
+	case HIERARCHY_2:
+		value |= 2;
+		break;
+	case HIERARCHY_4:
+		value |= 4;
+		break;
+	default:
+	case HIERARCHY_1:
+		value |= 1;
+		break;
+	}
+	dib7000p_write_word(state, 0, value);
+	dib7000p_write_word(state, 5, (seq << 4) | 1);	/* do not force tps, search list 0 */
+
+	/* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
+	value = 0;
+	if (1 != 0)
+		value |= (1 << 6);
+	if (ch->hierarchy == 1)
+		value |= (1 << 4);
+	if (1 == 1)
+		value |= 1;
+	switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
+	case FEC_2_3:
+		value |= (2 << 1);
+		break;
+	case FEC_3_4:
+		value |= (3 << 1);
+		break;
+	case FEC_5_6:
+		value |= (5 << 1);
+		break;
+	case FEC_7_8:
+		value |= (7 << 1);
+		break;
+	default:
+	case FEC_1_2:
+		value |= (1 << 1);
+		break;
+	}
+	dib7000p_write_word(state, 208, value);
+
+	/* offset loop parameters */
+	dib7000p_write_word(state, 26, 0x6680);
+	dib7000p_write_word(state, 32, 0x0003);
+	dib7000p_write_word(state, 29, 0x1273);
+	dib7000p_write_word(state, 33, 0x0005);
+
+	/* P_dvsy_sync_wait */
+	switch (ch->transmission_mode) {
+	case TRANSMISSION_MODE_8K:
+		value = 256;
+		break;
+	case TRANSMISSION_MODE_4K:
+		value = 128;
+		break;
+	case TRANSMISSION_MODE_2K:
+	default:
+		value = 64;
+		break;
+	}
+	switch (ch->guard_interval) {
+	case GUARD_INTERVAL_1_16:
+		value *= 2;
+		break;
+	case GUARD_INTERVAL_1_8:
+		value *= 4;
+		break;
+	case GUARD_INTERVAL_1_4:
+		value *= 8;
+		break;
+	default:
+	case GUARD_INTERVAL_1_32:
+		value *= 1;
+		break;
+	}
+	if (state->cfg.diversity_delay == 0)
+		state->div_sync_wait = (value * 3) / 2 + 48;
+	else
+		state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
+
+	/* deactive the possibility of diversity reception if extended interleaver */
+	state->div_force_off = !1 && ch->transmission_mode != TRANSMISSION_MODE_8K;
+	dib7000p_set_diversity_in(&state->demod, state->div_state);
+
+	/* channel estimation fine configuration */
+	switch (ch->modulation) {
+	case QAM_64:
+		est[0] = 0x0148;	/* P_adp_regul_cnt 0.04 */
+		est[1] = 0xfff0;	/* P_adp_noise_cnt -0.002 */
+		est[2] = 0x00a4;	/* P_adp_regul_ext 0.02 */
+		est[3] = 0xfff8;	/* P_adp_noise_ext -0.001 */
+		break;
+	case QAM_16:
+		est[0] = 0x023d;	/* P_adp_regul_cnt 0.07 */
+		est[1] = 0xffdf;	/* P_adp_noise_cnt -0.004 */
+		est[2] = 0x00a4;	/* P_adp_regul_ext 0.02 */
+		est[3] = 0xfff0;	/* P_adp_noise_ext -0.002 */
+		break;
+	default:
+		est[0] = 0x099a;	/* P_adp_regul_cnt 0.3 */
+		est[1] = 0xffae;	/* P_adp_noise_cnt -0.01 */
+		est[2] = 0x0333;	/* P_adp_regul_ext 0.1 */
+		est[3] = 0xfff8;	/* P_adp_noise_ext -0.002 */
+		break;
+	}
+	for (value = 0; value < 4; value++)
+		dib7000p_write_word(state, 187 + value, est[value]);
+}
+
+static int dib7000p_autosearch_start(struct dvb_frontend *demod)
+{
+	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
+	struct dib7000p_state *state = demod->demodulator_priv;
+	struct dtv_frontend_properties schan;
+	u32 value, factor;
+	u32 internal = dib7000p_get_internal_freq(state);
+
+	schan = *ch;
+	schan.modulation = QAM_64;
+	schan.guard_interval = GUARD_INTERVAL_1_32;
+	schan.transmission_mode = TRANSMISSION_MODE_8K;
+	schan.code_rate_HP = FEC_2_3;
+	schan.code_rate_LP = FEC_3_4;
+	schan.hierarchy = 0;
+
+	dib7000p_set_channel(state, &schan, 7);
+
+	factor = BANDWIDTH_TO_KHZ(ch->bandwidth_hz);
+	if (factor >= 5000) {
+		if (state->version == SOC7090)
+			factor = 2;
+		else
+			factor = 1;
+	} else
+		factor = 6;
+
+	value = 30 * internal * factor;
+	dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
+	dib7000p_write_word(state, 7, (u16) (value & 0xffff));
+	value = 100 * internal * factor;
+	dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
+	dib7000p_write_word(state, 9, (u16) (value & 0xffff));
+	value = 500 * internal * factor;
+	dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
+	dib7000p_write_word(state, 11, (u16) (value & 0xffff));
+
+	value = dib7000p_read_word(state, 0);
+	dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
+	dib7000p_read_word(state, 1284);
+	dib7000p_write_word(state, 0, (u16) value);
+
+	return 0;
+}
+
+static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
+{
+	struct dib7000p_state *state = demod->demodulator_priv;
+	u16 irq_pending = dib7000p_read_word(state, 1284);
+
+	if (irq_pending & 0x1)
+		return 1;
+
+	if (irq_pending & 0x2)
+		return 2;
+
+	return 0;
+}
+
+static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
+{
+	static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
+	static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
+		24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
+		53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
+		82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
+		107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
+		128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
+		147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
+		166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
+		183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
+		199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
+		213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
+		225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
+		235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
+		244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
+		250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
+		254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255
+	};
+
+	u32 xtal = state->cfg.bw->xtal_hz / 1000;
+	int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
+	int k;
+	int coef_re[8], coef_im[8];
+	int bw_khz = bw;
+	u32 pha;
+
+	dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
+
+	if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
+		return;
+
+	bw_khz /= 100;
+
+	dib7000p_write_word(state, 142, 0x0610);
+
+	for (k = 0; k < 8; k++) {
+		pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
+
+		if (pha == 0) {
+			coef_re[k] = 256;
+			coef_im[k] = 0;
+		} else if (pha < 256) {
+			coef_re[k] = sine[256 - (pha & 0xff)];
+			coef_im[k] = sine[pha & 0xff];
+		} else if (pha == 256) {
+			coef_re[k] = 0;
+			coef_im[k] = 256;
+		} else if (pha < 512) {
+			coef_re[k] = -sine[pha & 0xff];
+			coef_im[k] = sine[256 - (pha & 0xff)];
+		} else if (pha == 512) {
+			coef_re[k] = -256;
+			coef_im[k] = 0;
+		} else if (pha < 768) {
+			coef_re[k] = -sine[256 - (pha & 0xff)];
+			coef_im[k] = -sine[pha & 0xff];
+		} else if (pha == 768) {
+			coef_re[k] = 0;
+			coef_im[k] = -256;
+		} else {
+			coef_re[k] = sine[pha & 0xff];
+			coef_im[k] = -sine[256 - (pha & 0xff)];
+		}
+
+		coef_re[k] *= notch[k];
+		coef_re[k] += (1 << 14);
+		if (coef_re[k] >= (1 << 24))
+			coef_re[k] = (1 << 24) - 1;
+		coef_re[k] /= (1 << 15);
+
+		coef_im[k] *= notch[k];
+		coef_im[k] += (1 << 14);
+		if (coef_im[k] >= (1 << 24))
+			coef_im[k] = (1 << 24) - 1;
+		coef_im[k] /= (1 << 15);
+
+		dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
+
+		dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
+		dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
+		dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
+	}
+	dib7000p_write_word(state, 143, 0);
+}
+
+static int dib7000p_tune(struct dvb_frontend *demod)
+{
+	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
+	struct dib7000p_state *state = demod->demodulator_priv;
+	u16 tmp = 0;
+
+	if (ch != NULL)
+		dib7000p_set_channel(state, ch, 0);
+	else
+		return -EINVAL;
+
+	// restart demod
+	dib7000p_write_word(state, 770, 0x4000);
+	dib7000p_write_word(state, 770, 0x0000);
+	msleep(45);
+
+	/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
+	tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
+	if (state->sfn_workaround_active) {
+		dprintk("SFN workaround is active");
+		tmp |= (1 << 9);
+		dib7000p_write_word(state, 166, 0x4000);
+	} else {
+		dib7000p_write_word(state, 166, 0x0000);
+	}
+	dib7000p_write_word(state, 29, tmp);
+
+	// never achieved a lock with that bandwidth so far - wait for osc-freq to update
+	if (state->timf == 0)
+		msleep(200);
+
+	/* offset loop parameters */
+
+	/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
+	tmp = (6 << 8) | 0x80;
+	switch (ch->transmission_mode) {
+	case TRANSMISSION_MODE_2K:
+		tmp |= (2 << 12);
+		break;
+	case TRANSMISSION_MODE_4K:
+		tmp |= (3 << 12);
+		break;
+	default:
+	case TRANSMISSION_MODE_8K:
+		tmp |= (4 << 12);
+		break;
+	}
+	dib7000p_write_word(state, 26, tmp);	/* timf_a(6xxx) */
+
+	/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
+	tmp = (0 << 4);
+	switch (ch->transmission_mode) {
+	case TRANSMISSION_MODE_2K:
+		tmp |= 0x6;
+		break;
+	case TRANSMISSION_MODE_4K:
+		tmp |= 0x7;
+		break;
+	default:
+	case TRANSMISSION_MODE_8K:
+		tmp |= 0x8;
+		break;
+	}
+	dib7000p_write_word(state, 32, tmp);
+
+	/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
+	tmp = (0 << 4);
+	switch (ch->transmission_mode) {
+	case TRANSMISSION_MODE_2K:
+		tmp |= 0x6;
+		break;
+	case TRANSMISSION_MODE_4K:
+		tmp |= 0x7;
+		break;
+	default:
+	case TRANSMISSION_MODE_8K:
+		tmp |= 0x8;
+		break;
+	}
+	dib7000p_write_word(state, 33, tmp);
+
+	tmp = dib7000p_read_word(state, 509);
+	if (!((tmp >> 6) & 0x1)) {
+		/* restart the fec */
+		tmp = dib7000p_read_word(state, 771);
+		dib7000p_write_word(state, 771, tmp | (1 << 1));
+		dib7000p_write_word(state, 771, tmp);
+		msleep(40);
+		tmp = dib7000p_read_word(state, 509);
+	}
+	// we achieved a lock - it's time to update the osc freq
+	if ((tmp >> 6) & 0x1) {
+		dib7000p_update_timf(state);
+		/* P_timf_alpha += 2 */
+		tmp = dib7000p_read_word(state, 26);
+		dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
+	}
+
+	if (state->cfg.spur_protect)
+		dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
+
+	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
+	return 0;
+}
+
+static int dib7000p_wakeup(struct dvb_frontend *demod)
+{
+	struct dib7000p_state *state = demod->demodulator_priv;
+	dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
+	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
+	if (state->version == SOC7090)
+		dib7000p_sad_calib(state);
+	return 0;
+}
+
+static int dib7000p_sleep(struct dvb_frontend *demod)
+{
+	struct dib7000p_state *state = demod->demodulator_priv;
+	if (state->version == SOC7090)
+		return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
+	return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
+}
+
+static int dib7000p_identify(struct dib7000p_state *st)
+{
+	u16 value;
+	dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr);
+
+	if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
+		dprintk("wrong Vendor ID (read=0x%x)", value);
+		return -EREMOTEIO;
+	}
+
+	if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
+		dprintk("wrong Device ID (%x)", value);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int dib7000p_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
+	struct dib7000p_state *state = fe->demodulator_priv;
+	u16 tps = dib7000p_read_word(state, 463);
+
+	fep->inversion = INVERSION_AUTO;
+
+	fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
+
+	switch ((tps >> 8) & 0x3) {
+	case 0:
+		fep->transmission_mode = TRANSMISSION_MODE_2K;
+		break;
+	case 1:
+		fep->transmission_mode = TRANSMISSION_MODE_8K;
+		break;
+	/* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
+	}
+
+	switch (tps & 0x3) {
+	case 0:
+		fep->guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		fep->guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		fep->guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		fep->guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	}
+
+	switch ((tps >> 14) & 0x3) {
+	case 0:
+		fep->modulation = QPSK;
+		break;
+	case 1:
+		fep->modulation = QAM_16;
+		break;
+	case 2:
+	default:
+		fep->modulation = QAM_64;
+		break;
+	}
+
+	/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
+	/* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
+
+	fep->hierarchy = HIERARCHY_NONE;
+	switch ((tps >> 5) & 0x7) {
+	case 1:
+		fep->code_rate_HP = FEC_1_2;
+		break;
+	case 2:
+		fep->code_rate_HP = FEC_2_3;
+		break;
+	case 3:
+		fep->code_rate_HP = FEC_3_4;
+		break;
+	case 5:
+		fep->code_rate_HP = FEC_5_6;
+		break;
+	case 7:
+	default:
+		fep->code_rate_HP = FEC_7_8;
+		break;
+
+	}
+
+	switch ((tps >> 2) & 0x7) {
+	case 1:
+		fep->code_rate_LP = FEC_1_2;
+		break;
+	case 2:
+		fep->code_rate_LP = FEC_2_3;
+		break;
+	case 3:
+		fep->code_rate_LP = FEC_3_4;
+		break;
+	case 5:
+		fep->code_rate_LP = FEC_5_6;
+		break;
+	case 7:
+	default:
+		fep->code_rate_LP = FEC_7_8;
+		break;
+	}
+
+	/* native interleaver: (dib7000p_read_word(state, 464) >>  5) & 0x1 */
+
+	return 0;
+}
+
+static int dib7000p_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
+	struct dib7000p_state *state = fe->demodulator_priv;
+	int time, ret;
+
+	if (state->version == SOC7090)
+		dib7090_set_diversity_in(fe, 0);
+	else
+		dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
+
+	/* maybe the parameter has been changed */
+	state->sfn_workaround_active = buggy_sfn_workaround;
+
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+
+	/* start up the AGC */
+	state->agc_state = 0;
+	do {
+		time = dib7000p_agc_startup(fe);
+		if (time != -1)
+			msleep(time);
+	} while (time != -1);
+
+	if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
+		fep->guard_interval == GUARD_INTERVAL_AUTO || fep->modulation == QAM_AUTO || fep->code_rate_HP == FEC_AUTO) {
+		int i = 800, found;
+
+		dib7000p_autosearch_start(fe);
+		do {
+			msleep(1);
+			found = dib7000p_autosearch_is_irq(fe);
+		} while (found == 0 && i--);
+
+		dprintk("autosearch returns: %d", found);
+		if (found == 0 || found == 1)
+			return 0;
+
+		dib7000p_get_frontend(fe);
+	}
+
+	ret = dib7000p_tune(fe);
+
+	/* make this a config parameter */
+	if (state->version == SOC7090) {
+		dib7090_set_output_mode(fe, state->cfg.output_mode);
+		if (state->cfg.enMpegOutput == 0) {
+			dib7090_setDibTxMux(state, MPEG_ON_DIBTX);
+			dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
+		}
+	} else
+		dib7000p_set_output_mode(state, state->cfg.output_mode);
+
+	return ret;
+}
+
+static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
+{
+	struct dib7000p_state *state = fe->demodulator_priv;
+	u16 lock = dib7000p_read_word(state, 509);
+
+	*stat = 0;
+
+	if (lock & 0x8000)
+		*stat |= FE_HAS_SIGNAL;
+	if (lock & 0x3000)
+		*stat |= FE_HAS_CARRIER;
+	if (lock & 0x0100)
+		*stat |= FE_HAS_VITERBI;
+	if (lock & 0x0010)
+		*stat |= FE_HAS_SYNC;
+	if ((lock & 0x0038) == 0x38)
+		*stat |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
+{
+	struct dib7000p_state *state = fe->demodulator_priv;
+	*ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
+	return 0;
+}
+
+static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
+{
+	struct dib7000p_state *state = fe->demodulator_priv;
+	*unc = dib7000p_read_word(state, 506);
+	return 0;
+}
+
+static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+{
+	struct dib7000p_state *state = fe->demodulator_priv;
+	u16 val = dib7000p_read_word(state, 394);
+	*strength = 65535 - val;
+	return 0;
+}
+
+static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+	struct dib7000p_state *state = fe->demodulator_priv;
+	u16 val;
+	s32 signal_mant, signal_exp, noise_mant, noise_exp;
+	u32 result = 0;
+
+	val = dib7000p_read_word(state, 479);
+	noise_mant = (val >> 4) & 0xff;
+	noise_exp = ((val & 0xf) << 2);
+	val = dib7000p_read_word(state, 480);
+	noise_exp += ((val >> 14) & 0x3);
+	if ((noise_exp & 0x20) != 0)
+		noise_exp -= 0x40;
+
+	signal_mant = (val >> 6) & 0xFF;
+	signal_exp = (val & 0x3F);
+	if ((signal_exp & 0x20) != 0)
+		signal_exp -= 0x40;
+
+	if (signal_mant != 0)
+		result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
+	else
+		result = intlog10(2) * 10 * signal_exp - 100;
+
+	if (noise_mant != 0)
+		result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
+	else
+		result -= intlog10(2) * 10 * noise_exp - 100;
+
+	*snr = result / ((1 << 24) / 10);
+	return 0;
+}
+
+static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	return 0;
+}
+
+static void dib7000p_release(struct dvb_frontend *demod)
+{
+	struct dib7000p_state *st = demod->demodulator_priv;
+	dibx000_exit_i2c_master(&st->i2c_master);
+	i2c_del_adapter(&st->dib7090_tuner_adap);
+	kfree(st);
+}
+
+int dib7000pc_detection(struct i2c_adapter *i2c_adap)
+{
+	u8 *tx, *rx;
+	struct i2c_msg msg[2] = {
+		{.addr = 18 >> 1, .flags = 0, .len = 2},
+		{.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
+	};
+	int ret = 0;
+
+	tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
+	if (!tx)
+		return -ENOMEM;
+	rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
+	if (!rx) {
+		ret = -ENOMEM;
+		goto rx_memory_error;
+	}
+
+	msg[0].buf = tx;
+	msg[1].buf = rx;
+
+	tx[0] = 0x03;
+	tx[1] = 0x00;
+
+	if (i2c_transfer(i2c_adap, msg, 2) == 2)
+		if (rx[0] == 0x01 && rx[1] == 0xb3) {
+			dprintk("-D-  DiB7000PC detected");
+			return 1;
+		}
+
+	msg[0].addr = msg[1].addr = 0x40;
+
+	if (i2c_transfer(i2c_adap, msg, 2) == 2)
+		if (rx[0] == 0x01 && rx[1] == 0xb3) {
+			dprintk("-D-  DiB7000PC detected");
+			return 1;
+		}
+
+	dprintk("-D-  DiB7000PC not detected");
+
+	kfree(rx);
+rx_memory_error:
+	kfree(tx);
+	return ret;
+}
+EXPORT_SYMBOL(dib7000pc_detection);
+
+struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
+{
+	struct dib7000p_state *st = demod->demodulator_priv;
+	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
+}
+EXPORT_SYMBOL(dib7000p_get_i2c_master);
+
+int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+{
+	struct dib7000p_state *state = fe->demodulator_priv;
+	u16 val = dib7000p_read_word(state, 235) & 0xffef;
+	val |= (onoff & 0x1) << 4;
+	dprintk("PID filter enabled %d", onoff);
+	return dib7000p_write_word(state, 235, val);
+}
+EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
+
+int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+{
+	struct dib7000p_state *state = fe->demodulator_priv;
+	dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
+	return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
+}
+EXPORT_SYMBOL(dib7000p_pid_filter);
+
+int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
+{
+	struct dib7000p_state *dpst;
+	int k = 0;
+	u8 new_addr = 0;
+
+	dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
+	if (!dpst)
+		return -ENOMEM;
+
+	dpst->i2c_adap = i2c;
+	mutex_init(&dpst->i2c_buffer_lock);
+
+	for (k = no_of_demods - 1; k >= 0; k--) {
+		dpst->cfg = cfg[k];
+
+		/* designated i2c address */
+		if (cfg[k].default_i2c_addr != 0)
+			new_addr = cfg[k].default_i2c_addr + (k << 1);
+		else
+			new_addr = (0x40 + k) << 1;
+		dpst->i2c_addr = new_addr;
+		dib7000p_write_word(dpst, 1287, 0x0003);	/* sram lead in, rdy */
+		if (dib7000p_identify(dpst) != 0) {
+			dpst->i2c_addr = default_addr;
+			dib7000p_write_word(dpst, 1287, 0x0003);	/* sram lead in, rdy */
+			if (dib7000p_identify(dpst) != 0) {
+				dprintk("DiB7000P #%d: not identified\n", k);
+				kfree(dpst);
+				return -EIO;
+			}
+		}
+
+		/* start diversity to pull_down div_str - just for i2c-enumeration */
+		dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
+
+		/* set new i2c address and force divstart */
+		dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
+
+		dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
+	}
+
+	for (k = 0; k < no_of_demods; k++) {
+		dpst->cfg = cfg[k];
+		if (cfg[k].default_i2c_addr != 0)
+			dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
+		else
+			dpst->i2c_addr = (0x40 + k) << 1;
+
+		// unforce divstr
+		dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
+
+		/* deactivate div - it was just for i2c-enumeration */
+		dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
+	}
+
+	kfree(dpst);
+	return 0;
+}
+EXPORT_SYMBOL(dib7000p_i2c_enumeration);
+
+static const s32 lut_1000ln_mant[] = {
+	6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
+};
+
+static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
+{
+	struct dib7000p_state *state = fe->demodulator_priv;
+	u32 tmp_val = 0, exp = 0, mant = 0;
+	s32 pow_i;
+	u16 buf[2];
+	u8 ix = 0;
+
+	buf[0] = dib7000p_read_word(state, 0x184);
+	buf[1] = dib7000p_read_word(state, 0x185);
+	pow_i = (buf[0] << 16) | buf[1];
+	dprintk("raw pow_i = %d", pow_i);
+
+	tmp_val = pow_i;
+	while (tmp_val >>= 1)
+		exp++;
+
+	mant = (pow_i * 1000 / (1 << exp));
+	dprintk(" mant = %d exp = %d", mant / 1000, exp);
+
+	ix = (u8) ((mant - 1000) / 100);	/* index of the LUT */
+	dprintk(" ix = %d", ix);
+
+	pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
+	pow_i = (pow_i << 8) / 1000;
+	dprintk(" pow_i = %d", pow_i);
+
+	return pow_i;
+}
+
+static int map_addr_to_serpar_number(struct i2c_msg *msg)
+{
+	if ((msg->buf[0] <= 15))
+		msg->buf[0] -= 1;
+	else if (msg->buf[0] == 17)
+		msg->buf[0] = 15;
+	else if (msg->buf[0] == 16)
+		msg->buf[0] = 17;
+	else if (msg->buf[0] == 19)
+		msg->buf[0] = 16;
+	else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
+		msg->buf[0] -= 3;
+	else if (msg->buf[0] == 28)
+		msg->buf[0] = 23;
+	else
+		return -EINVAL;
+	return 0;
+}
+
+static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
+	u8 n_overflow = 1;
+	u16 i = 1000;
+	u16 serpar_num = msg[0].buf[0];
+
+	while (n_overflow == 1 && i) {
+		n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
+		i--;
+		if (i == 0)
+			dprintk("Tuner ITF: write busy (overflow)");
+	}
+	dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
+	dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
+
+	return num;
+}
+
+static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
+	u8 n_overflow = 1, n_empty = 1;
+	u16 i = 1000;
+	u16 serpar_num = msg[0].buf[0];
+	u16 read_word;
+
+	while (n_overflow == 1 && i) {
+		n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
+		i--;
+		if (i == 0)
+			dprintk("TunerITF: read busy (overflow)");
+	}
+	dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
+
+	i = 1000;
+	while (n_empty == 1 && i) {
+		n_empty = dib7000p_read_word(state, 1984) & 0x1;
+		i--;
+		if (i == 0)
+			dprintk("TunerITF: read busy (empty)");
+	}
+	read_word = dib7000p_read_word(state, 1987);
+	msg[1].buf[0] = (read_word >> 8) & 0xff;
+	msg[1].buf[1] = (read_word) & 0xff;
+
+	return num;
+}
+
+static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+	if (map_addr_to_serpar_number(&msg[0]) == 0) {	/* else = Tuner regs to ignore : DIG_CFG, CTRL_RF_LT, PLL_CFG, PWM1_REG, ADCCLK, DIG_CFG_3; SLEEP_EN... */
+		if (num == 1) {	/* write */
+			return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
+		} else {	/* read */
+			return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
+		}
+	}
+	return num;
+}
+
+static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap,
+		struct i2c_msg msg[], int num, u16 apb_address)
+{
+	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
+	u16 word;
+
+	if (num == 1) {		/* write */
+		dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
+	} else {
+		word = dib7000p_read_word(state, apb_address);
+		msg[1].buf[0] = (word >> 8) & 0xff;
+		msg[1].buf[1] = (word) & 0xff;
+	}
+
+	return num;
+}
+
+static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
+
+	u16 apb_address = 0, word;
+	int i = 0;
+	switch (msg[0].buf[0]) {
+	case 0x12:
+		apb_address = 1920;
+		break;
+	case 0x14:
+		apb_address = 1921;
+		break;
+	case 0x24:
+		apb_address = 1922;
+		break;
+	case 0x1a:
+		apb_address = 1923;
+		break;
+	case 0x22:
+		apb_address = 1924;
+		break;
+	case 0x33:
+		apb_address = 1926;
+		break;
+	case 0x34:
+		apb_address = 1927;
+		break;
+	case 0x35:
+		apb_address = 1928;
+		break;
+	case 0x36:
+		apb_address = 1929;
+		break;
+	case 0x37:
+		apb_address = 1930;
+		break;
+	case 0x38:
+		apb_address = 1931;
+		break;
+	case 0x39:
+		apb_address = 1932;
+		break;
+	case 0x2a:
+		apb_address = 1935;
+		break;
+	case 0x2b:
+		apb_address = 1936;
+		break;
+	case 0x2c:
+		apb_address = 1937;
+		break;
+	case 0x2d:
+		apb_address = 1938;
+		break;
+	case 0x2e:
+		apb_address = 1939;
+		break;
+	case 0x2f:
+		apb_address = 1940;
+		break;
+	case 0x30:
+		apb_address = 1941;
+		break;
+	case 0x31:
+		apb_address = 1942;
+		break;
+	case 0x32:
+		apb_address = 1943;
+		break;
+	case 0x3e:
+		apb_address = 1944;
+		break;
+	case 0x3f:
+		apb_address = 1945;
+		break;
+	case 0x40:
+		apb_address = 1948;
+		break;
+	case 0x25:
+		apb_address = 914;
+		break;
+	case 0x26:
+		apb_address = 915;
+		break;
+	case 0x27:
+		apb_address = 917;
+		break;
+	case 0x28:
+		apb_address = 916;
+		break;
+	case 0x1d:
+		i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
+		word = dib7000p_read_word(state, 384 + i);
+		msg[1].buf[0] = (word >> 8) & 0xff;
+		msg[1].buf[1] = (word) & 0xff;
+		return num;
+	case 0x1f:
+		if (num == 1) {	/* write */
+			word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
+			word &= 0x3;
+			word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
+			dib7000p_write_word(state, 72, word);	/* Set the proper input */
+			return num;
+		}
+	}
+
+	if (apb_address != 0)	/* R/W acces via APB */
+		return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
+	else			/* R/W access via SERPAR  */
+		return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
+
+	return 0;
+}
+
+static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dib7090_tuner_xfer_algo = {
+	.master_xfer = dib7090_tuner_xfer,
+	.functionality = dib7000p_i2c_func,
+};
+
+struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
+{
+	struct dib7000p_state *st = fe->demodulator_priv;
+	return &st->dib7090_tuner_adap;
+}
+EXPORT_SYMBOL(dib7090_get_i2c_tuner);
+
+static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
+{
+	u16 reg;
+
+	/* drive host bus 2, 3, 4 */
+	reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
+	reg |= (drive << 12) | (drive << 6) | drive;
+	dib7000p_write_word(state, 1798, reg);
+
+	/* drive host bus 5,6 */
+	reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
+	reg |= (drive << 8) | (drive << 2);
+	dib7000p_write_word(state, 1799, reg);
+
+	/* drive host bus 7, 8, 9 */
+	reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
+	reg |= (drive << 12) | (drive << 6) | drive;
+	dib7000p_write_word(state, 1800, reg);
+
+	/* drive host bus 10, 11 */
+	reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
+	reg |= (drive << 8) | (drive << 2);
+	dib7000p_write_word(state, 1801, reg);
+
+	/* drive host bus 12, 13, 14 */
+	reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
+	reg |= (drive << 12) | (drive << 6) | drive;
+	dib7000p_write_word(state, 1802, reg);
+
+	return 0;
+}
+
+static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
+{
+	u32 quantif = 3;
+	u32 nom = (insertExtSynchro * P_Kin + syncSize);
+	u32 denom = P_Kout;
+	u32 syncFreq = ((nom << quantif) / denom);
+
+	if ((syncFreq & ((1 << quantif) - 1)) != 0)
+		syncFreq = (syncFreq >> quantif) + 1;
+	else
+		syncFreq = (syncFreq >> quantif);
+
+	if (syncFreq != 0)
+		syncFreq = syncFreq - 1;
+
+	return syncFreq;
+}
+
+static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
+{
+	dprintk("Configure DibStream Tx");
+
+	dib7000p_write_word(state, 1615, 1);
+	dib7000p_write_word(state, 1603, P_Kin);
+	dib7000p_write_word(state, 1605, P_Kout);
+	dib7000p_write_word(state, 1606, insertExtSynchro);
+	dib7000p_write_word(state, 1608, synchroMode);
+	dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
+	dib7000p_write_word(state, 1610, syncWord & 0xffff);
+	dib7000p_write_word(state, 1612, syncSize);
+	dib7000p_write_word(state, 1615, 0);
+
+	return 0;
+}
+
+static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,
+		u32 dataOutRate)
+{
+	u32 syncFreq;
+
+	dprintk("Configure DibStream Rx");
+	if ((P_Kin != 0) && (P_Kout != 0)) {
+		syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
+		dib7000p_write_word(state, 1542, syncFreq);
+	}
+	dib7000p_write_word(state, 1554, 1);
+	dib7000p_write_word(state, 1536, P_Kin);
+	dib7000p_write_word(state, 1537, P_Kout);
+	dib7000p_write_word(state, 1539, synchroMode);
+	dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
+	dib7000p_write_word(state, 1541, syncWord & 0xffff);
+	dib7000p_write_word(state, 1543, syncSize);
+	dib7000p_write_word(state, 1544, dataOutRate);
+	dib7000p_write_word(state, 1554, 0);
+
+	return 0;
+}
+
+static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff)
+{
+	u16 reg_1287 = dib7000p_read_word(state, 1287);
+
+	switch (onoff) {
+	case 1:
+			reg_1287 &= ~(1<<7);
+			break;
+	case 0:
+			reg_1287 |= (1<<7);
+			break;
+	}
+
+	dib7000p_write_word(state, 1287, reg_1287);
+}
+
+static void dib7090_configMpegMux(struct dib7000p_state *state,
+		u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
+{
+	dprintk("Enable Mpeg mux");
+
+	dib7090_enMpegMux(state, 0);
+
+	/* If the input mode is MPEG do not divide the serial clock */
+	if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
+		enSerialClkDiv2 = 0;
+
+	dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2)
+			| ((enSerialMode & 0x1) << 1)
+			| (enSerialClkDiv2 & 0x1));
+
+	dib7090_enMpegMux(state, 1);
+}
+
+static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode)
+{
+	u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7);
+
+	switch (mode) {
+	case MPEG_ON_DIBTX:
+			dprintk("SET MPEG ON DIBSTREAM TX");
+			dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
+			reg_1288 |= (1<<9);
+			break;
+	case DIV_ON_DIBTX:
+			dprintk("SET DIV_OUT ON DIBSTREAM TX");
+			dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
+			reg_1288 |= (1<<8);
+			break;
+	case ADC_ON_DIBTX:
+			dprintk("SET ADC_OUT ON DIBSTREAM TX");
+			dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
+			reg_1288 |= (1<<7);
+			break;
+	default:
+			break;
+	}
+	dib7000p_write_word(state, 1288, reg_1288);
+}
+
+static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
+{
+	u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4);
+
+	switch (mode) {
+	case DEMOUT_ON_HOSTBUS:
+			dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
+			dib7090_enMpegMux(state, 0);
+			reg_1288 |= (1<<6);
+			break;
+	case DIBTX_ON_HOSTBUS:
+			dprintk("SET DIBSTREAM TX ON HOST BUS");
+			dib7090_enMpegMux(state, 0);
+			reg_1288 |= (1<<5);
+			break;
+	case MPEG_ON_HOSTBUS:
+			dprintk("SET MPEG MUX ON HOST BUS");
+			reg_1288 |= (1<<4);
+			break;
+	default:
+			break;
+	}
+	dib7000p_write_word(state, 1288, reg_1288);
+}
+
+int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
+{
+	struct dib7000p_state *state = fe->demodulator_priv;
+	u16 reg_1287;
+
+	switch (onoff) {
+	case 0: /* only use the internal way - not the diversity input */
+			dprintk("%s mode OFF : by default Enable Mpeg INPUT", __func__);
+			dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
+
+			/* Do not divide the serial clock of MPEG MUX */
+			/* in SERIAL MODE in case input mode MPEG is used */
+			reg_1287 = dib7000p_read_word(state, 1287);
+			/* enSerialClkDiv2 == 1 ? */
+			if ((reg_1287 & 0x1) == 1) {
+				/* force enSerialClkDiv2 = 0 */
+				reg_1287 &= ~0x1;
+				dib7000p_write_word(state, 1287, reg_1287);
+			}
+			state->input_mode_mpeg = 1;
+			break;
+	case 1: /* both ways */
+	case 2: /* only the diversity input */
+			dprintk("%s ON : Enable diversity INPUT", __func__);
+			dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
+			state->input_mode_mpeg = 0;
+			break;
+	}
+
+	dib7000p_set_diversity_in(&state->demod, onoff);
+	return 0;
+}
+
+static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
+{
+	struct dib7000p_state *state = fe->demodulator_priv;
+
+	u16 outreg, smo_mode, fifo_threshold;
+	u8 prefer_mpeg_mux_use = 1;
+	int ret = 0;
+
+	dib7090_host_bus_drive(state, 1);
+
+	fifo_threshold = 1792;
+	smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
+	outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
+
+	switch (mode) {
+	case OUTMODE_HIGH_Z:
+		outreg = 0;
+		break;
+
+	case OUTMODE_MPEG2_SERIAL:
+		if (prefer_mpeg_mux_use) {
+			dprintk("setting output mode TS_SERIAL using Mpeg Mux");
+			dib7090_configMpegMux(state, 3, 1, 1);
+			dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
+		} else {/* Use Smooth block */
+			dprintk("setting output mode TS_SERIAL using Smooth bloc");
+			dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+			outreg |= (2<<6) | (0 << 1);
+		}
+		break;
+
+	case OUTMODE_MPEG2_PAR_GATED_CLK:
+		if (prefer_mpeg_mux_use) {
+			dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux");
+			dib7090_configMpegMux(state, 2, 0, 0);
+			dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
+		} else { /* Use Smooth block */
+			dprintk("setting output mode TS_PARALLEL_GATED using Smooth block");
+			dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+			outreg |= (0<<6);
+		}
+		break;
+
+	case OUTMODE_MPEG2_PAR_CONT_CLK:	/* Using Smooth block only */
+		dprintk("setting output mode TS_PARALLEL_CONT using Smooth block");
+		dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+		outreg |= (1<<6);
+		break;
+
+	case OUTMODE_MPEG2_FIFO:	/* Using Smooth block because not supported by new Mpeg Mux bloc */
+		dprintk("setting output mode TS_FIFO using Smooth block");
+		dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+		outreg |= (5<<6);
+		smo_mode |= (3 << 1);
+		fifo_threshold = 512;
+		break;
+
+	case OUTMODE_DIVERSITY:
+		dprintk("setting output mode MODE_DIVERSITY");
+		dib7090_setDibTxMux(state, DIV_ON_DIBTX);
+		dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
+		break;
+
+	case OUTMODE_ANALOG_ADC:
+		dprintk("setting output mode MODE_ANALOG_ADC");
+		dib7090_setDibTxMux(state, ADC_ON_DIBTX);
+		dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
+		break;
+	}
+	if (mode != OUTMODE_HIGH_Z)
+		outreg |= (1 << 10);
+
+	if (state->cfg.output_mpeg2_in_188_bytes)
+		smo_mode |= (1 << 5);
+
+	ret |= dib7000p_write_word(state, 235, smo_mode);
+	ret |= dib7000p_write_word(state, 236, fifo_threshold);	/* synchronous fread */
+	ret |= dib7000p_write_word(state, 1286, outreg);
+
+	return ret;
+}
+
+int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+	struct dib7000p_state *state = fe->demodulator_priv;
+	u16 en_cur_state;
+
+	dprintk("sleep dib7090: %d", onoff);
+
+	en_cur_state = dib7000p_read_word(state, 1922);
+
+	if (en_cur_state > 0xff)
+		state->tuner_enable = en_cur_state;
+
+	if (onoff)
+		en_cur_state &= 0x00ff;
+	else {
+		if (state->tuner_enable != 0)
+			en_cur_state = state->tuner_enable;
+	}
+
+	dib7000p_write_word(state, 1922, en_cur_state);
+
+	return 0;
+}
+EXPORT_SYMBOL(dib7090_tuner_sleep);
+
+int dib7090_get_adc_power(struct dvb_frontend *fe)
+{
+	return dib7000p_get_adc_power(fe);
+}
+EXPORT_SYMBOL(dib7090_get_adc_power);
+
+int dib7090_slave_reset(struct dvb_frontend *fe)
+{
+	struct dib7000p_state *state = fe->demodulator_priv;
+	u16 reg;
+
+	reg = dib7000p_read_word(state, 1794);
+	dib7000p_write_word(state, 1794, reg | (4 << 12));
+
+	dib7000p_write_word(state, 1032, 0xffff);
+	return 0;
+}
+EXPORT_SYMBOL(dib7090_slave_reset);
+
+static struct dvb_frontend_ops dib7000p_ops;
+struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
+{
+	struct dvb_frontend *demod;
+	struct dib7000p_state *st;
+	st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
+	if (st == NULL)
+		return NULL;
+
+	memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
+	st->i2c_adap = i2c_adap;
+	st->i2c_addr = i2c_addr;
+	st->gpio_val = cfg->gpio_val;
+	st->gpio_dir = cfg->gpio_dir;
+
+	/* Ensure the output mode remains at the previous default if it's
+	 * not specifically set by the caller.
+	 */
+	if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
+		st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
+
+	demod = &st->demod;
+	demod->demodulator_priv = st;
+	memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
+	mutex_init(&st->i2c_buffer_lock);
+
+	dib7000p_write_word(st, 1287, 0x0003);	/* sram lead in, rdy */
+
+	if (dib7000p_identify(st) != 0)
+		goto error;
+
+	st->version = dib7000p_read_word(st, 897);
+
+	/* FIXME: make sure the dev.parent field is initialized, or else
+	   request_firmware() will hit an OOPS (this should be moved somewhere
+	   more common) */
+	st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
+
+	dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
+
+	/* init 7090 tuner adapter */
+	strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));
+	st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
+	st->dib7090_tuner_adap.algo_data = NULL;
+	st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
+	i2c_set_adapdata(&st->dib7090_tuner_adap, st);
+	i2c_add_adapter(&st->dib7090_tuner_adap);
+
+	dib7000p_demod_reset(st);
+
+	if (st->version == SOC7090) {
+		dib7090_set_output_mode(demod, st->cfg.output_mode);
+		dib7090_set_diversity_in(demod, 0);
+	}
+
+	return demod;
+
+error:
+	kfree(st);
+	return NULL;
+}
+EXPORT_SYMBOL(dib7000p_attach);
+
+static struct dvb_frontend_ops dib7000p_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		 .name = "DiBcom 7000PC",
+		 .frequency_min = 44250000,
+		 .frequency_max = 867250000,
+		 .frequency_stepsize = 62500,
+		 .caps = FE_CAN_INVERSION_AUTO |
+		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
+		 },
+
+	.release = dib7000p_release,
+
+	.init = dib7000p_wakeup,
+	.sleep = dib7000p_sleep,
+
+	.set_frontend = dib7000p_set_frontend,
+	.get_tune_settings = dib7000p_fe_get_tune_settings,
+	.get_frontend = dib7000p_get_frontend,
+
+	.read_status = dib7000p_read_status,
+	.read_ber = dib7000p_read_ber,
+	.read_signal_strength = dib7000p_read_signal_strength,
+	.read_snr = dib7000p_read_snr,
+	.read_ucblocks = dib7000p_read_unc_blocks,
+};
+
+MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/dib7000p.h b/drivers/media/dvb-frontends/dib7000p.h
new file mode 100644
index 0000000..b61b03a
--- /dev/null
+++ b/drivers/media/dvb-frontends/dib7000p.h
@@ -0,0 +1,158 @@
+#ifndef DIB7000P_H
+#define DIB7000P_H
+
+#include "dibx000_common.h"
+
+struct dib7000p_config {
+	u8 output_mpeg2_in_188_bytes;
+	u8 hostbus_diversity;
+	u8 tuner_is_baseband;
+	int (*update_lna) (struct dvb_frontend *, u16 agc_global);
+
+	u8 agc_config_count;
+	struct dibx000_agc_config *agc;
+	struct dibx000_bandwidth_config *bw;
+
+#define DIB7000P_GPIO_DEFAULT_DIRECTIONS 0xffff
+	u16 gpio_dir;
+#define DIB7000P_GPIO_DEFAULT_VALUES     0x0000
+	u16 gpio_val;
+#define DIB7000P_GPIO_PWM_POS0(v)        ((v & 0xf) << 12)
+#define DIB7000P_GPIO_PWM_POS1(v)        ((v & 0xf) << 8 )
+#define DIB7000P_GPIO_PWM_POS2(v)        ((v & 0xf) << 4 )
+#define DIB7000P_GPIO_PWM_POS3(v)         (v & 0xf)
+#define DIB7000P_GPIO_DEFAULT_PWM_POS    0xffff
+	u16 gpio_pwm_pos;
+
+	u16 pwm_freq_div;
+
+	u8 quartz_direct;
+
+	u8 spur_protect;
+
+	int (*agc_control) (struct dvb_frontend *, u8 before);
+
+	u8 output_mode;
+	u8 disable_sample_and_hold:1;
+
+	u8 enable_current_mirror:1;
+	u16 diversity_delay;
+
+	u8 default_i2c_addr;
+	u8 enMpegOutput:1;
+};
+
+#define DEFAULT_DIB7000P_I2C_ADDRESS 18
+
+#if defined(CONFIG_DVB_DIB7000P) || (defined(CONFIG_DVB_DIB7000P_MODULE) && \
+					defined(MODULE))
+extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg);
+extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
+extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
+extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
+extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
+extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
+extern int dib7000p_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
+extern int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff);
+extern int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw);
+extern u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf);
+extern int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff);
+extern int dib7090_get_adc_power(struct dvb_frontend *fe);
+extern struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe);
+extern int dib7090_slave_reset(struct dvb_frontend *fe);
+extern int dib7000p_get_agc_values(struct dvb_frontend *fe,
+		u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd);
+#else
+static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface i, int x)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib7000pc_detection(struct i2c_adapter *i2c_adap)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, uint8_t onoff)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return 0;
+}
+
+static inline int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib7090_get_adc_power(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline int dib7090_slave_reset(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib7000p_get_agc_values(struct dvb_frontend *fe,
+		u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c
new file mode 100644
index 0000000..1f3bcb5
--- /dev/null
+++ b/drivers/media/dvb-frontends/dib8000.c
@@ -0,0 +1,3560 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB8000 chip (ISDB-T).
+ *
+ * Copyright (C) 2009 DiBcom (http://www.dibcom.fr/)
+ *
+ * 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, version 2.
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+#include "dvb_math.h"
+
+#include "dvb_frontend.h"
+
+#include "dib8000.h"
+
+#define LAYER_ALL -1
+#define LAYER_A   1
+#define LAYER_B   2
+#define LAYER_C   3
+
+#define FE_CALLBACK_TIME_NEVER 0xffffffff
+#define MAX_NUMBER_OF_FRONTENDS 6
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0)
+
+#define FE_STATUS_TUNE_FAILED 0
+
+struct i2c_device {
+	struct i2c_adapter *adap;
+	u8 addr;
+	u8 *i2c_write_buffer;
+	u8 *i2c_read_buffer;
+	struct mutex *i2c_buffer_lock;
+};
+
+struct dib8000_state {
+	struct dib8000_config cfg;
+
+	struct i2c_device i2c;
+
+	struct dibx000_i2c_master i2c_master;
+
+	u16 wbd_ref;
+
+	u8 current_band;
+	u32 current_bandwidth;
+	struct dibx000_agc_config *current_agc;
+	u32 timf;
+	u32 timf_default;
+
+	u8 div_force_off:1;
+	u8 div_state:1;
+	u16 div_sync_wait;
+
+	u8 agc_state;
+	u8 differential_constellation;
+	u8 diversity_onoff;
+
+	s16 ber_monitored_layer;
+	u16 gpio_dir;
+	u16 gpio_val;
+
+	u16 revision;
+	u8 isdbt_cfg_loaded;
+	enum frontend_tune_state tune_state;
+	u32 status;
+
+	struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
+
+	/* for the I2C transfer */
+	struct i2c_msg msg[2];
+	u8 i2c_write_buffer[4];
+	u8 i2c_read_buffer[2];
+	struct mutex i2c_buffer_lock;
+	u8 input_mode_mpeg;
+
+	u16 tuner_enable;
+	struct i2c_adapter dib8096p_tuner_adap;
+};
+
+enum dib8000_power_mode {
+	DIB8000_POWER_ALL = 0,
+	DIB8000_POWER_INTERFACE_ONLY,
+};
+
+static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
+{
+	u16 ret;
+	struct i2c_msg msg[2] = {
+		{.addr = i2c->addr >> 1, .flags = 0, .len = 2},
+		{.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
+	};
+
+	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return 0;
+	}
+
+	msg[0].buf    = i2c->i2c_write_buffer;
+	msg[0].buf[0] = reg >> 8;
+	msg[0].buf[1] = reg & 0xff;
+	msg[1].buf    = i2c->i2c_read_buffer;
+
+	if (i2c_transfer(i2c->adap, msg, 2) != 2)
+		dprintk("i2c read error on %d", reg);
+
+	ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
+	mutex_unlock(i2c->i2c_buffer_lock);
+	return ret;
+}
+
+static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
+{
+	u16 ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return 0;
+	}
+
+	state->i2c_write_buffer[0] = reg >> 8;
+	state->i2c_write_buffer[1] = reg & 0xff;
+
+	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+	state->msg[0].addr = state->i2c.addr >> 1;
+	state->msg[0].flags = 0;
+	state->msg[0].buf = state->i2c_write_buffer;
+	state->msg[0].len = 2;
+	state->msg[1].addr = state->i2c.addr >> 1;
+	state->msg[1].flags = I2C_M_RD;
+	state->msg[1].buf = state->i2c_read_buffer;
+	state->msg[1].len = 2;
+
+	if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
+		dprintk("i2c read error on %d", reg);
+
+	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+	mutex_unlock(&state->i2c_buffer_lock);
+
+	return ret;
+}
+
+static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
+{
+	u16 rw[2];
+
+	rw[0] = dib8000_read_word(state, reg + 0);
+	rw[1] = dib8000_read_word(state, reg + 1);
+
+	return ((rw[0] << 16) | (rw[1]));
+}
+
+static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
+{
+	struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
+	int ret = 0;
+
+	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+
+	msg.buf    = i2c->i2c_write_buffer;
+	msg.buf[0] = (reg >> 8) & 0xff;
+	msg.buf[1] = reg & 0xff;
+	msg.buf[2] = (val >> 8) & 0xff;
+	msg.buf[3] = val & 0xff;
+
+	ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+	mutex_unlock(i2c->i2c_buffer_lock);
+
+	return ret;
+}
+
+static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
+{
+	int ret;
+
+	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+
+	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+	state->i2c_write_buffer[1] = reg & 0xff;
+	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+	state->i2c_write_buffer[3] = val & 0xff;
+
+	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
+	state->msg[0].addr = state->i2c.addr >> 1;
+	state->msg[0].flags = 0;
+	state->msg[0].buf = state->i2c_write_buffer;
+	state->msg[0].len = 4;
+
+	ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
+			-EREMOTEIO : 0);
+	mutex_unlock(&state->i2c_buffer_lock);
+
+	return ret;
+}
+
+static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
+	(769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c,
+		(920 << 5) | 0x09
+};
+
+static const s16 coeff_2k_sb_1seg[8] = {
+	(692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
+};
+
+static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
+	(832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11,
+		(-931 << 5) | 0x0f
+};
+
+static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {
+	(622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e,
+		(982 << 5) | 0x0c
+};
+
+static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {
+	(699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12,
+		(-720 << 5) | 0x0d
+};
+
+static const s16 coeff_2k_sb_3seg[8] = {
+	(664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e,
+		(-610 << 5) | 0x0a
+};
+
+static const s16 coeff_4k_sb_1seg_dqpsk[8] = {
+	(-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f,
+		(-922 << 5) | 0x0d
+};
+
+static const s16 coeff_4k_sb_1seg[8] = {
+	(638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d,
+		(-655 << 5) | 0x0a
+};
+
+static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
+	(-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14,
+		(-958 << 5) | 0x13
+};
+
+static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {
+	(-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12,
+		(-568 << 5) | 0x0f
+};
+
+static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {
+	(-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14,
+		(-848 << 5) | 0x13
+};
+
+static const s16 coeff_4k_sb_3seg[8] = {
+	(612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12,
+		(-869 << 5) | 0x13
+};
+
+static const s16 coeff_8k_sb_1seg_dqpsk[8] = {
+	(-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13,
+		(-598 << 5) | 0x10
+};
+
+static const s16 coeff_8k_sb_1seg[8] = {
+	(673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f,
+		(585 << 5) | 0x0f
+};
+
+static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
+	(863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18,
+		(0 << 5) | 0x14
+};
+
+static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {
+	(-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15,
+		(-877 << 5) | 0x15
+};
+
+static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {
+	(-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18,
+		(-921 << 5) | 0x14
+};
+
+static const s16 coeff_8k_sb_3seg[8] = {
+	(514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15,
+		(690 << 5) | 0x14
+};
+
+static const s16 ana_fe_coeff_3seg[24] = {
+	81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017
+};
+
+static const s16 ana_fe_coeff_1seg[24] = {
+	249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003
+};
+
+static const s16 ana_fe_coeff_13seg[24] = {
+	396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1
+};
+
+static u16 fft_to_mode(struct dib8000_state *state)
+{
+	u16 mode;
+	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
+	case TRANSMISSION_MODE_2K:
+		mode = 1;
+		break;
+	case TRANSMISSION_MODE_4K:
+		mode = 2;
+		break;
+	default:
+	case TRANSMISSION_MODE_AUTO:
+	case TRANSMISSION_MODE_8K:
+		mode = 3;
+		break;
+	}
+	return mode;
+}
+
+static void dib8000_set_acquisition_mode(struct dib8000_state *state)
+{
+	u16 nud = dib8000_read_word(state, 298);
+	nud |= (1 << 3) | (1 << 0);
+	dprintk("acquisition mode activated");
+	dib8000_write_word(state, 298, nud);
+}
+static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+
+	u16 outreg, fifo_threshold, smo_mode, sram = 0x0205;	/* by default SDRAM deintlv is enabled */
+
+	outreg = 0;
+	fifo_threshold = 1792;
+	smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
+
+	dprintk("-I-	Setting output mode for demod %p to %d",
+			&state->fe[0], mode);
+
+	switch (mode) {
+	case OUTMODE_MPEG2_PAR_GATED_CLK:	// STBs with parallel gated clock
+		outreg = (1 << 10);	/* 0x0400 */
+		break;
+	case OUTMODE_MPEG2_PAR_CONT_CLK:	// STBs with parallel continues clock
+		outreg = (1 << 10) | (1 << 6);	/* 0x0440 */
+		break;
+	case OUTMODE_MPEG2_SERIAL:	// STBs with serial input
+		outreg = (1 << 10) | (2 << 6) | (0 << 1);	/* 0x0482 */
+		break;
+	case OUTMODE_DIVERSITY:
+		if (state->cfg.hostbus_diversity) {
+			outreg = (1 << 10) | (4 << 6);	/* 0x0500 */
+			sram &= 0xfdff;
+		} else
+			sram |= 0x0c00;
+		break;
+	case OUTMODE_MPEG2_FIFO:	// e.g. USB feeding
+		smo_mode |= (3 << 1);
+		fifo_threshold = 512;
+		outreg = (1 << 10) | (5 << 6);
+		break;
+	case OUTMODE_HIGH_Z:	// disable
+		outreg = 0;
+		break;
+
+	case OUTMODE_ANALOG_ADC:
+		outreg = (1 << 10) | (3 << 6);
+		dib8000_set_acquisition_mode(state);
+		break;
+
+	default:
+		dprintk("Unhandled output_mode passed to be set for demod %p",
+				&state->fe[0]);
+		return -EINVAL;
+	}
+
+	if (state->cfg.output_mpeg2_in_188_bytes)
+		smo_mode |= (1 << 5);
+
+	dib8000_write_word(state, 299, smo_mode);
+	dib8000_write_word(state, 300, fifo_threshold);	/* synchronous fread */
+	dib8000_write_word(state, 1286, outreg);
+	dib8000_write_word(state, 1291, sram);
+
+	return 0;
+}
+
+static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u16 sync_wait = dib8000_read_word(state, 273) & 0xfff0;
+
+	if (!state->differential_constellation) {
+		dib8000_write_word(state, 272, 1 << 9);	//dvsy_off_lmod4 = 1
+		dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2);	// sync_enable = 1; comb_mode = 2
+	} else {
+		dib8000_write_word(state, 272, 0);	//dvsy_off_lmod4 = 0
+		dib8000_write_word(state, 273, sync_wait);	// sync_enable = 0; comb_mode = 0
+	}
+	state->diversity_onoff = onoff;
+
+	switch (onoff) {
+	case 0:		/* only use the internal way - not the diversity input */
+		dib8000_write_word(state, 270, 1);
+		dib8000_write_word(state, 271, 0);
+		break;
+	case 1:		/* both ways */
+		dib8000_write_word(state, 270, 6);
+		dib8000_write_word(state, 271, 6);
+		break;
+	case 2:		/* only the diversity input */
+		dib8000_write_word(state, 270, 0);
+		dib8000_write_word(state, 271, 1);
+		break;
+	}
+	return 0;
+}
+
+static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)
+{
+	/* by default everything is going to be powered off */
+	u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
+		reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
+		reg_1280;
+
+	if (state->revision != 0x8090)
+		reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
+	else
+		reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80;
+
+	/* now, depending on the requested mode, we power on */
+	switch (mode) {
+		/* power up everything in the demod */
+	case DIB8000_POWER_ALL:
+		reg_774 = 0x0000;
+		reg_775 = 0x0000;
+		reg_776 = 0x0000;
+		reg_900 &= 0xfffc;
+		if (state->revision != 0x8090)
+			reg_1280 &= 0x00ff;
+		else
+			reg_1280 &= 0x707f;
+		break;
+	case DIB8000_POWER_INTERFACE_ONLY:
+		if (state->revision != 0x8090)
+			reg_1280 &= 0x00ff;
+		else
+			reg_1280 &= 0xfa7b;
+		break;
+	}
+
+	dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280);
+	dib8000_write_word(state, 774, reg_774);
+	dib8000_write_word(state, 775, reg_775);
+	dib8000_write_word(state, 776, reg_776);
+	dib8000_write_word(state, 900, reg_900);
+	dib8000_write_word(state, 1280, reg_1280);
+}
+
+static int dib8000_init_sdram(struct dib8000_state *state)
+{
+	u16 reg = 0;
+	dprintk("Init sdram");
+
+	reg = dib8000_read_word(state, 274)&0xfff0;
+	/* P_dintlv_delay_ram = 7 because of MobileSdram */
+	dib8000_write_word(state, 274, reg | 0x7);
+
+	dib8000_write_word(state, 1803, (7<<2));
+
+	reg = dib8000_read_word(state, 1280);
+	/* force restart P_restart_sdram */
+	dib8000_write_word(state, 1280,  reg | (1<<2));
+
+	/* release restart P_restart_sdram */
+	dib8000_write_word(state, 1280,  reg);
+
+	return 0;
+}
+
+static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
+{
+	int ret = 0;
+	u16 reg, reg_907 = dib8000_read_word(state, 907);
+	u16 reg_908 = dib8000_read_word(state, 908);
+
+	switch (no) {
+	case DIBX000_SLOW_ADC_ON:
+		if (state->revision != 0x8090) {
+			reg_908 |= (1 << 1) | (1 << 0);
+			ret |= dib8000_write_word(state, 908, reg_908);
+			reg_908 &= ~(1 << 1);
+		} else {
+			reg = dib8000_read_word(state, 1925);
+			/* en_slowAdc = 1 & reset_sladc = 1 */
+			dib8000_write_word(state, 1925, reg |
+					(1<<4) | (1<<2));
+
+			/* read acces to make it works... strange ... */
+			reg = dib8000_read_word(state, 1925);
+			msleep(20);
+			/* en_slowAdc = 1 & reset_sladc = 0 */
+			dib8000_write_word(state, 1925, reg & ~(1<<4));
+
+			reg = dib8000_read_word(state, 921) & ~((0x3 << 14)
+					| (0x3 << 12));
+			/* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ;
+			   (Vin2 = Vcm) */
+			dib8000_write_word(state, 921, reg | (1 << 14)
+					| (3 << 12));
+		}
+		break;
+
+	case DIBX000_SLOW_ADC_OFF:
+		if (state->revision == 0x8090) {
+			reg = dib8000_read_word(state, 1925);
+			/* reset_sladc = 1 en_slowAdc = 0 */
+			dib8000_write_word(state, 1925,
+					(reg & ~(1<<2)) | (1<<4));
+		}
+		reg_908 |= (1 << 1) | (1 << 0);
+		break;
+
+	case DIBX000_ADC_ON:
+		reg_907 &= 0x0fff;
+		reg_908 &= 0x0003;
+		break;
+
+	case DIBX000_ADC_OFF:	// leave the VBG voltage on
+		reg_907 |= (1 << 14) | (1 << 13) | (1 << 12);
+		reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
+		break;
+
+	case DIBX000_VBG_ENABLE:
+		reg_907 &= ~(1 << 15);
+		break;
+
+	case DIBX000_VBG_DISABLE:
+		reg_907 |= (1 << 15);
+		break;
+
+	default:
+		break;
+	}
+
+	ret |= dib8000_write_word(state, 907, reg_907);
+	ret |= dib8000_write_word(state, 908, reg_908);
+
+	return ret;
+}
+
+static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u32 timf;
+
+	if (bw == 0)
+		bw = 6000;
+
+	if (state->timf == 0) {
+		dprintk("using default timf");
+		timf = state->timf_default;
+	} else {
+		dprintk("using updated timf");
+		timf = state->timf;
+	}
+
+	dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));
+	dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));
+
+	return 0;
+}
+
+static int dib8000_sad_calib(struct dib8000_state *state)
+{
+	if (state->revision == 0x8090) {
+		dprintk("%s: the sad calibration is not needed for the dib8096P",
+				__func__);
+		return 0;
+	}
+	/* internal */
+	dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
+	dib8000_write_word(state, 924, 776);	// 0.625*3.3 / 4096
+
+	/* do the calibration */
+	dib8000_write_word(state, 923, (1 << 0));
+	dib8000_write_word(state, 923, (0 << 0));
+
+	msleep(1);
+	return 0;
+}
+
+int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	if (value > 4095)
+		value = 4095;
+	state->wbd_ref = value;
+	return dib8000_write_word(state, 106, value);
+}
+
+EXPORT_SYMBOL(dib8000_set_wbd_ref);
+static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
+{
+	dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
+	if (state->revision != 0x8090) {
+		dib8000_write_word(state, 23,
+				(u16) (((bw->internal * 1000) >> 16) & 0xffff));
+		dib8000_write_word(state, 24,
+				(u16) ((bw->internal * 1000) & 0xffff));
+	} else {
+		dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff));
+		dib8000_write_word(state, 24,
+				(u16) ((bw->internal  / 2 * 1000) & 0xffff));
+	}
+	dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
+	dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
+	dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
+
+	if (state->revision != 0x8090)
+		dib8000_write_word(state, 922, bw->sad_cfg);
+}
+
+static void dib8000_reset_pll(struct dib8000_state *state)
+{
+	const struct dibx000_bandwidth_config *pll = state->cfg.pll;
+	u16 clk_cfg1, reg;
+
+	if (state->revision != 0x8090) {
+		dib8000_write_word(state, 901,
+				(pll->pll_prediv << 8) | (pll->pll_ratio << 0));
+
+		clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
+			(pll->bypclk_div << 5) | (pll->enable_refdiv << 4) |
+			(1 << 3) | (pll->pll_range << 1) |
+			(pll->pll_reset << 0);
+
+		dib8000_write_word(state, 902, clk_cfg1);
+		clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
+		dib8000_write_word(state, 902, clk_cfg1);
+
+		dprintk("clk_cfg1: 0x%04x", clk_cfg1);
+
+		/* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
+		if (state->cfg.pll->ADClkSrc == 0)
+			dib8000_write_word(state, 904,
+					(0 << 15) | (0 << 12) | (0 << 10) |
+					(pll->modulo << 8) |
+					(pll->ADClkSrc << 7) | (0 << 1));
+		else if (state->cfg.refclksel != 0)
+			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
+					((state->cfg.refclksel & 0x3) << 10) |
+					(pll->modulo << 8) |
+					(pll->ADClkSrc << 7) | (0 << 1));
+		else
+			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
+					(3 << 10) | (pll->modulo << 8) |
+					(pll->ADClkSrc << 7) | (0 << 1));
+	} else {
+		dib8000_write_word(state, 1856, (!pll->pll_reset<<13) |
+				(pll->pll_range<<12) | (pll->pll_ratio<<6) |
+				(pll->pll_prediv));
+
+		reg = dib8000_read_word(state, 1857);
+		dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15));
+
+		reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */
+		dib8000_write_word(state, 1858, reg | 1);
+
+		dib8000_write_word(state, 904, (pll->modulo << 8));
+	}
+
+	dib8000_reset_pll_common(state, pll);
+}
+
+int dib8000_update_pll(struct dvb_frontend *fe,
+		struct dibx000_bandwidth_config *pll)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
+	u8 loopdiv, prediv;
+	u32 internal, xtal;
+
+	/* get back old values */
+	prediv = reg_1856 & 0x3f;
+	loopdiv = (reg_1856 >> 6) & 0x3f;
+
+	if ((pll != NULL) && (pll->pll_prediv != prediv ||
+				pll->pll_ratio != loopdiv)) {
+		dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
+		reg_1856 &= 0xf000;
+		reg_1857 = dib8000_read_word(state, 1857);
+		/* disable PLL */
+		dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15));
+
+		dib8000_write_word(state, 1856, reg_1856 |
+				((pll->pll_ratio & 0x3f) << 6) |
+				(pll->pll_prediv & 0x3f));
+
+		/* write new system clk into P_sec_len */
+		internal = dib8000_read32(state, 23) / 1000;
+		dprintk("Old Internal = %d", internal);
+		xtal = 2 * (internal / loopdiv) * prediv;
+		internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio;
+		dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d", xtal, internal/1000, internal/2000, internal/8000);
+		dprintk("New Internal = %d", internal);
+
+		dib8000_write_word(state, 23,
+				(u16) (((internal / 2) >> 16) & 0xffff));
+		dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff));
+		/* enable PLL */
+		dib8000_write_word(state, 1857, reg_1857 | (1 << 15));
+
+		while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1)
+			dprintk("Waiting for PLL to lock");
+
+		/* verify */
+		reg_1856 = dib8000_read_word(state, 1856);
+		dprintk("PLL Updated with prediv = %d and loopdiv = %d",
+				reg_1856&0x3f, (reg_1856>>6)&0x3f);
+
+		return 0;
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL(dib8000_update_pll);
+
+
+static int dib8000_reset_gpio(struct dib8000_state *st)
+{
+	/* reset the GPIOs */
+	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
+	dib8000_write_word(st, 1030, st->cfg.gpio_val);
+
+	/* TODO 782 is P_gpio_od */
+
+	dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
+
+	dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
+	return 0;
+}
+
+static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
+{
+	st->cfg.gpio_dir = dib8000_read_word(st, 1029);
+	st->cfg.gpio_dir &= ~(1 << num);	/* reset the direction bit */
+	st->cfg.gpio_dir |= (dir & 0x1) << num;	/* set the new direction */
+	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
+
+	st->cfg.gpio_val = dib8000_read_word(st, 1030);
+	st->cfg.gpio_val &= ~(1 << num);	/* reset the direction bit */
+	st->cfg.gpio_val |= (val & 0x01) << num;	/* set the new value */
+	dib8000_write_word(st, 1030, st->cfg.gpio_val);
+
+	dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val);
+
+	return 0;
+}
+
+int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	return dib8000_cfg_gpio(state, num, dir, val);
+}
+
+EXPORT_SYMBOL(dib8000_set_gpio);
+static const u16 dib8000_defaults[] = {
+	/* auto search configuration - lock0 by default waiting
+	 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
+	3, 7,
+	0x0004,
+	0x0400,
+	0x0814,
+
+	12, 11,
+	0x001b,
+	0x7740,
+	0x005b,
+	0x8d80,
+	0x01c9,
+	0xc380,
+	0x0000,
+	0x0080,
+	0x0000,
+	0x0090,
+	0x0001,
+	0xd4c0,
+
+	/*1, 32,
+		0x6680 // P_corm_thres Lock algorithms configuration */
+
+	11, 80,			/* set ADC level to -16 */
+	(1 << 13) - 825 - 117,
+	(1 << 13) - 837 - 117,
+	(1 << 13) - 811 - 117,
+	(1 << 13) - 766 - 117,
+	(1 << 13) - 737 - 117,
+	(1 << 13) - 693 - 117,
+	(1 << 13) - 648 - 117,
+	(1 << 13) - 619 - 117,
+	(1 << 13) - 575 - 117,
+	(1 << 13) - 531 - 117,
+	(1 << 13) - 501 - 117,
+
+	4, 108,
+	0,
+	0,
+	0,
+	0,
+
+	1, 175,
+	0x0410,
+	1, 179,
+	8192,			// P_fft_nb_to_cut
+
+	6, 181,
+	0x2800,			// P_coff_corthres_ ( 2k 4k 8k ) 0x2800
+	0x2800,
+	0x2800,
+	0x2800,			// P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
+	0x2800,
+	0x2800,
+
+	2, 193,
+	0x0666,			// P_pha3_thres
+	0x0000,			// P_cti_use_cpe, P_cti_use_prog
+
+	2, 205,
+	0x200f,			// P_cspu_regul, P_cspu_win_cut
+	0x000f,			// P_des_shift_work
+
+	5, 215,
+	0x023d,			// P_adp_regul_cnt
+	0x00a4,			// P_adp_noise_cnt
+	0x00a4,			// P_adp_regul_ext
+	0x7ff0,			// P_adp_noise_ext
+	0x3ccc,			// P_adp_fil
+
+	1, 230,
+	0x0000,			// P_2d_byp_ti_num
+
+	1, 263,
+	0x800,			//P_equal_thres_wgn
+
+	1, 268,
+	(2 << 9) | 39,		// P_equal_ctrl_synchro, P_equal_speedmode
+
+	1, 270,
+	0x0001,			// P_div_lock0_wait
+	1, 285,
+	0x0020,			//p_fec_
+	1, 299,
+	0x0062,			/* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */
+
+	1, 338,
+	(1 << 12) |		// P_ctrl_corm_thres4pre_freq_inh=1
+		(1 << 10) |
+		(0 << 9) |		/* P_ctrl_pre_freq_inh=0 */
+		(3 << 5) |		/* P_ctrl_pre_freq_step=3 */
+		(1 << 0),		/* P_pre_freq_win_len=1 */
+
+	0,
+};
+
+static u16 dib8000_identify(struct i2c_device *client)
+{
+	u16 value;
+
+	//because of glitches sometimes
+	value = dib8000_i2c_read16(client, 896);
+
+	if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
+		dprintk("wrong Vendor ID (read=0x%x)", value);
+		return 0;
+	}
+
+	value = dib8000_i2c_read16(client, 897);
+	if (value != 0x8000 && value != 0x8001 &&
+			value != 0x8002 && value != 0x8090) {
+		dprintk("wrong Device ID (%x)", value);
+		return 0;
+	}
+
+	switch (value) {
+	case 0x8000:
+		dprintk("found DiB8000A");
+		break;
+	case 0x8001:
+		dprintk("found DiB8000B");
+		break;
+	case 0x8002:
+		dprintk("found DiB8000C");
+		break;
+	case 0x8090:
+		dprintk("found DiB8096P");
+		break;
+	}
+	return value;
+}
+
+static int dib8000_reset(struct dvb_frontend *fe)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+
+	if ((state->revision = dib8000_identify(&state->i2c)) == 0)
+		return -EINVAL;
+
+	/* sram lead in, rdy */
+	if (state->revision != 0x8090)
+		dib8000_write_word(state, 1287, 0x0003);
+
+	if (state->revision == 0x8000)
+		dprintk("error : dib8000 MA not supported");
+
+	dibx000_reset_i2c_master(&state->i2c_master);
+
+	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
+
+	/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
+	dib8000_set_adc_state(state, DIBX000_VBG_ENABLE);
+
+	/* restart all parts */
+	dib8000_write_word(state, 770, 0xffff);
+	dib8000_write_word(state, 771, 0xffff);
+	dib8000_write_word(state, 772, 0xfffc);
+	if (state->revision == 0x8090)
+		dib8000_write_word(state, 1280, 0x0045);
+	else
+		dib8000_write_word(state, 1280, 0x004d);
+	dib8000_write_word(state, 1281, 0x000c);
+
+	dib8000_write_word(state, 770, 0x0000);
+	dib8000_write_word(state, 771, 0x0000);
+	dib8000_write_word(state, 772, 0x0000);
+	dib8000_write_word(state, 898, 0x0004);	// sad
+	dib8000_write_word(state, 1280, 0x0000);
+	dib8000_write_word(state, 1281, 0x0000);
+
+	/* drives */
+	if (state->revision != 0x8090) {
+		if (state->cfg.drives)
+			dib8000_write_word(state, 906, state->cfg.drives);
+		else {
+			dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
+			/* min drive SDRAM - not optimal - adjust */
+			dib8000_write_word(state, 906, 0x2d98);
+		}
+	}
+
+	dib8000_reset_pll(state);
+	if (state->revision != 0x8090)
+		dib8000_write_word(state, 898, 0x0004);
+
+	if (dib8000_reset_gpio(state) != 0)
+		dprintk("GPIO reset was not successful.");
+
+	if ((state->revision != 0x8090) &&
+			(dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0))
+		dprintk("OUTPUT_MODE could not be resetted.");
+
+	state->current_agc = NULL;
+
+	// P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
+	/* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
+	if (state->cfg.pll->ifreq == 0)
+		dib8000_write_word(state, 40, 0x0755);	/* P_iqc_corr_inh = 0 enable IQcorr block */
+	else
+		dib8000_write_word(state, 40, 0x1f55);	/* P_iqc_corr_inh = 1 disable IQcorr block */
+
+	{
+		u16 l = 0, r;
+		const u16 *n;
+		n = dib8000_defaults;
+		l = *n++;
+		while (l) {
+			r = *n++;
+			do {
+				dib8000_write_word(state, r, *n++);
+				r++;
+			} while (--l);
+			l = *n++;
+		}
+	}
+	if (state->revision != 0x8090)
+		dib8000_write_word(state, 903, (0 << 4) | 2);
+	state->isdbt_cfg_loaded = 0;
+
+	//div_cfg override for special configs
+	if (state->cfg.div_cfg != 0)
+		dib8000_write_word(state, 903, state->cfg.div_cfg);
+
+	/* unforce divstr regardless whether i2c enumeration was done or not */
+	dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
+
+	dib8000_set_bandwidth(fe, 6000);
+
+	dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
+	if (state->revision != 0x8090) {
+		dib8000_sad_calib(state);
+		dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
+	}
+
+	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
+
+	return 0;
+}
+
+static void dib8000_restart_agc(struct dib8000_state *state)
+{
+	// P_restart_iqc & P_restart_agc
+	dib8000_write_word(state, 770, 0x0a00);
+	dib8000_write_word(state, 770, 0x0000);
+}
+
+static int dib8000_update_lna(struct dib8000_state *state)
+{
+	u16 dyn_gain;
+
+	if (state->cfg.update_lna) {
+		// read dyn_gain here (because it is demod-dependent and not tuner)
+		dyn_gain = dib8000_read_word(state, 390);
+
+		if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
+			dib8000_restart_agc(state);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
+{
+	struct dibx000_agc_config *agc = NULL;
+	int i;
+	u16 reg;
+
+	if (state->current_band == band && state->current_agc != NULL)
+		return 0;
+	state->current_band = band;
+
+	for (i = 0; i < state->cfg.agc_config_count; i++)
+		if (state->cfg.agc[i].band_caps & band) {
+			agc = &state->cfg.agc[i];
+			break;
+		}
+
+	if (agc == NULL) {
+		dprintk("no valid AGC configuration found for band 0x%02x", band);
+		return -EINVAL;
+	}
+
+	state->current_agc = agc;
+
+	/* AGC */
+	dib8000_write_word(state, 76, agc->setup);
+	dib8000_write_word(state, 77, agc->inv_gain);
+	dib8000_write_word(state, 78, agc->time_stabiliz);
+	dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
+
+	// Demod AGC loop configuration
+	dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
+	dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
+
+	dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
+		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
+
+	/* AGC continued */
+	if (state->wbd_ref != 0)
+		dib8000_write_word(state, 106, state->wbd_ref);
+	else			// use default
+		dib8000_write_word(state, 106, agc->wbd_ref);
+
+	if (state->revision == 0x8090) {
+		reg = dib8000_read_word(state, 922) & (0x3 << 2);
+		dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2));
+	}
+
+	dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
+	dib8000_write_word(state, 108, agc->agc1_max);
+	dib8000_write_word(state, 109, agc->agc1_min);
+	dib8000_write_word(state, 110, agc->agc2_max);
+	dib8000_write_word(state, 111, agc->agc2_min);
+	dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
+	dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
+	dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
+	dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
+
+	dib8000_write_word(state, 75, agc->agc1_pt3);
+	if (state->revision != 0x8090)
+		dib8000_write_word(state, 923,
+				(dib8000_read_word(state, 923) & 0xffe3) |
+				(agc->wbd_inv << 4) | (agc->wbd_sel << 2));
+
+	return 0;
+}
+
+void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	dib8000_set_adc_state(state, DIBX000_ADC_ON);
+	dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
+}
+EXPORT_SYMBOL(dib8000_pwm_agc_reset);
+
+static int dib8000_agc_soft_split(struct dib8000_state *state)
+{
+	u16 agc, split_offset;
+
+	if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
+		return FE_CALLBACK_TIME_NEVER;
+
+	// n_agc_global
+	agc = dib8000_read_word(state, 390);
+
+	if (agc > state->current_agc->split.min_thres)
+		split_offset = state->current_agc->split.min;
+	else if (agc < state->current_agc->split.max_thres)
+		split_offset = state->current_agc->split.max;
+	else
+		split_offset = state->current_agc->split.max *
+			(agc - state->current_agc->split.min_thres) /
+			(state->current_agc->split.max_thres - state->current_agc->split.min_thres);
+
+	dprintk("AGC split_offset: %d", split_offset);
+
+	// P_agc_force_split and P_agc_split_offset
+	dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
+	return 5000;
+}
+
+static int dib8000_agc_startup(struct dvb_frontend *fe)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	enum frontend_tune_state *tune_state = &state->tune_state;
+	int ret = 0;
+	u16 reg, upd_demod_gain_period = 0x8000;
+
+	switch (*tune_state) {
+	case CT_AGC_START:
+		// set power-up level: interf+analog+AGC
+
+		if (state->revision != 0x8090)
+			dib8000_set_adc_state(state, DIBX000_ADC_ON);
+		else {
+			dib8000_set_power_mode(state, DIB8000_POWER_ALL);
+
+			reg = dib8000_read_word(state, 1947)&0xff00;
+			dib8000_write_word(state, 1946,
+					upd_demod_gain_period & 0xFFFF);
+			/* bit 14 = enDemodGain */
+			dib8000_write_word(state, 1947, reg | (1<<14) |
+					((upd_demod_gain_period >> 16) & 0xFF));
+
+			/* enable adc i & q */
+			reg = dib8000_read_word(state, 1920);
+			dib8000_write_word(state, 1920, (reg | 0x3) &
+					(~(1 << 7)));
+		}
+
+		if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
+			*tune_state = CT_AGC_STOP;
+			state->status = FE_STATUS_TUNE_FAILED;
+			break;
+		}
+
+		ret = 70;
+		*tune_state = CT_AGC_STEP_0;
+		break;
+
+	case CT_AGC_STEP_0:
+		//AGC initialization
+		if (state->cfg.agc_control)
+			state->cfg.agc_control(fe, 1);
+
+		dib8000_restart_agc(state);
+
+		// wait AGC rough lock time
+		ret = 50;
+		*tune_state = CT_AGC_STEP_1;
+		break;
+
+	case CT_AGC_STEP_1:
+		// wait AGC accurate lock time
+		ret = 70;
+
+		if (dib8000_update_lna(state))
+			// wait only AGC rough lock time
+			ret = 50;
+		else
+			*tune_state = CT_AGC_STEP_2;
+		break;
+
+	case CT_AGC_STEP_2:
+		dib8000_agc_soft_split(state);
+
+		if (state->cfg.agc_control)
+			state->cfg.agc_control(fe, 0);
+
+		*tune_state = CT_AGC_STOP;
+		break;
+	default:
+		ret = dib8000_agc_soft_split(state);
+		break;
+	}
+	return ret;
+
+}
+
+static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive)
+{
+	u16 reg;
+
+	drive &= 0x7;
+
+	/* drive host bus 2, 3, 4 */
+	reg = dib8000_read_word(state, 1798) &
+		~(0x7 | (0x7 << 6) | (0x7 << 12));
+	reg |= (drive<<12) | (drive<<6) | drive;
+	dib8000_write_word(state, 1798, reg);
+
+	/* drive host bus 5,6 */
+	reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
+	reg |= (drive<<8) | (drive<<2);
+	dib8000_write_word(state, 1799, reg);
+
+	/* drive host bus 7, 8, 9 */
+	reg = dib8000_read_word(state, 1800) &
+		~(0x7 | (0x7 << 6) | (0x7 << 12));
+	reg |= (drive<<12) | (drive<<6) | drive;
+	dib8000_write_word(state, 1800, reg);
+
+	/* drive host bus 10, 11 */
+	reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
+	reg |= (drive<<8) | (drive<<2);
+	dib8000_write_word(state, 1801, reg);
+
+	/* drive host bus 12, 13, 14 */
+	reg = dib8000_read_word(state, 1802) &
+		~(0x7 | (0x7 << 6) | (0x7 << 12));
+	reg |= (drive<<12) | (drive<<6) | drive;
+	dib8000_write_word(state, 1802, reg);
+}
+
+static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout,
+		u32 insertExtSynchro, u32 syncSize)
+{
+	u32 quantif = 3;
+	u32 nom = (insertExtSynchro * P_Kin+syncSize);
+	u32 denom = P_Kout;
+	u32 syncFreq = ((nom << quantif) / denom);
+
+	if ((syncFreq & ((1 << quantif) - 1)) != 0)
+		syncFreq = (syncFreq >> quantif) + 1;
+	else
+		syncFreq = (syncFreq >> quantif);
+
+	if (syncFreq != 0)
+		syncFreq = syncFreq - 1;
+
+	return syncFreq;
+}
+
+static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin,
+		u32 P_Kout, u32 insertExtSynchro, u32 synchroMode,
+		u32 syncWord, u32 syncSize)
+{
+	dprintk("Configure DibStream Tx");
+
+	dib8000_write_word(state, 1615, 1);
+	dib8000_write_word(state, 1603, P_Kin);
+	dib8000_write_word(state, 1605, P_Kout);
+	dib8000_write_word(state, 1606, insertExtSynchro);
+	dib8000_write_word(state, 1608, synchroMode);
+	dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff);
+	dib8000_write_word(state, 1610, syncWord & 0xffff);
+	dib8000_write_word(state, 1612, syncSize);
+	dib8000_write_word(state, 1615, 0);
+}
+
+static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin,
+		u32 P_Kout, u32 synchroMode, u32 insertExtSynchro,
+		u32 syncWord, u32 syncSize, u32 dataOutRate)
+{
+	u32 syncFreq;
+
+	dprintk("Configure DibStream Rx synchroMode = %d", synchroMode);
+
+	if ((P_Kin != 0) && (P_Kout != 0)) {
+		syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout,
+				insertExtSynchro, syncSize);
+		dib8000_write_word(state, 1542, syncFreq);
+	}
+
+	dib8000_write_word(state, 1554, 1);
+	dib8000_write_word(state, 1536, P_Kin);
+	dib8000_write_word(state, 1537, P_Kout);
+	dib8000_write_word(state, 1539, synchroMode);
+	dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff);
+	dib8000_write_word(state, 1541, syncWord & 0xffff);
+	dib8000_write_word(state, 1543, syncSize);
+	dib8000_write_word(state, 1544, dataOutRate);
+	dib8000_write_word(state, 1554, 0);
+}
+
+static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff)
+{
+	u16 reg_1287;
+
+	reg_1287 = dib8000_read_word(state, 1287);
+
+	switch (onoff) {
+	case 1:
+			reg_1287 &= ~(1 << 8);
+			break;
+	case 0:
+			reg_1287 |= (1 << 8);
+			break;
+	}
+
+	dib8000_write_word(state, 1287, reg_1287);
+}
+
+static void dib8096p_configMpegMux(struct dib8000_state *state,
+		u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
+{
+	u16 reg_1287;
+
+	dprintk("Enable Mpeg mux");
+
+	dib8096p_enMpegMux(state, 0);
+
+	/* If the input mode is MPEG do not divide the serial clock */
+	if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
+		enSerialClkDiv2 = 0;
+
+	reg_1287 = ((pulseWidth & 0x1f) << 3) |
+		((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1);
+	dib8000_write_word(state, 1287, reg_1287);
+
+	dib8096p_enMpegMux(state, 1);
+}
+
+static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode)
+{
+	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7);
+
+	switch (mode) {
+	case MPEG_ON_DIBTX:
+			dprintk("SET MPEG ON DIBSTREAM TX");
+			dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
+			reg_1288 |= (1 << 9); break;
+	case DIV_ON_DIBTX:
+			dprintk("SET DIV_OUT ON DIBSTREAM TX");
+			dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
+			reg_1288 |= (1 << 8); break;
+	case ADC_ON_DIBTX:
+			dprintk("SET ADC_OUT ON DIBSTREAM TX");
+			dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
+			reg_1288 |= (1 << 7); break;
+	default:
+			break;
+	}
+	dib8000_write_word(state, 1288, reg_1288);
+}
+
+static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode)
+{
+	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4);
+
+	switch (mode) {
+	case DEMOUT_ON_HOSTBUS:
+			dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
+			dib8096p_enMpegMux(state, 0);
+			reg_1288 |= (1 << 6);
+			break;
+	case DIBTX_ON_HOSTBUS:
+			dprintk("SET DIBSTREAM TX ON HOST BUS");
+			dib8096p_enMpegMux(state, 0);
+			reg_1288 |= (1 << 5);
+			break;
+	case MPEG_ON_HOSTBUS:
+			dprintk("SET MPEG MUX ON HOST BUS");
+			reg_1288 |= (1 << 4);
+			break;
+	default:
+			break;
+	}
+	dib8000_write_word(state, 1288, reg_1288);
+}
+
+static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u16 reg_1287;
+
+	switch (onoff) {
+	case 0: /* only use the internal way - not the diversity input */
+			dprintk("%s mode OFF : by default Enable Mpeg INPUT",
+					__func__);
+			/* outputRate = 8 */
+			dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
+
+			/* Do not divide the serial clock of MPEG MUX in
+			   SERIAL MODE in case input mode MPEG is used */
+			reg_1287 = dib8000_read_word(state, 1287);
+			/* enSerialClkDiv2 == 1 ? */
+			if ((reg_1287 & 0x1) == 1) {
+				/* force enSerialClkDiv2 = 0 */
+				reg_1287 &= ~0x1;
+				dib8000_write_word(state, 1287, reg_1287);
+			}
+			state->input_mode_mpeg = 1;
+			break;
+	case 1: /* both ways */
+	case 2: /* only the diversity input */
+			dprintk("%s ON : Enable diversity INPUT", __func__);
+			dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
+			state->input_mode_mpeg = 0;
+			break;
+	}
+
+	dib8000_set_diversity_in(state->fe[0], onoff);
+	return 0;
+}
+
+static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u16 outreg, smo_mode, fifo_threshold;
+	u8 prefer_mpeg_mux_use = 1;
+	int ret = 0;
+
+	dib8096p_host_bus_drive(state, 1);
+
+	fifo_threshold = 1792;
+	smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
+	outreg   = dib8000_read_word(state, 1286) &
+		~((1 << 10) | (0x7 << 6) | (1 << 1));
+
+	switch (mode) {
+	case OUTMODE_HIGH_Z:
+			outreg = 0;
+			break;
+
+	case OUTMODE_MPEG2_SERIAL:
+			if (prefer_mpeg_mux_use) {
+				dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux");
+				dib8096p_configMpegMux(state, 3, 1, 1);
+				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
+			} else {/* Use Smooth block */
+				dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc");
+				dib8096p_setHostBusMux(state,
+						DEMOUT_ON_HOSTBUS);
+				outreg |= (2 << 6) | (0 << 1);
+			}
+			break;
+
+	case OUTMODE_MPEG2_PAR_GATED_CLK:
+			if (prefer_mpeg_mux_use) {
+				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
+				dib8096p_configMpegMux(state, 2, 0, 0);
+				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
+			} else { /* Use Smooth block */
+				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block");
+				dib8096p_setHostBusMux(state,
+						DEMOUT_ON_HOSTBUS);
+				outreg |= (0 << 6);
+			}
+			break;
+
+	case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
+			dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block");
+			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+			outreg |= (1 << 6);
+			break;
+
+	case OUTMODE_MPEG2_FIFO:
+			/* Using Smooth block because not supported
+			   by new Mpeg Mux bloc */
+			dprintk("dib8096P setting output mode TS_FIFO using Smooth block");
+			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+			outreg |= (5 << 6);
+			smo_mode |= (3 << 1);
+			fifo_threshold = 512;
+			break;
+
+	case OUTMODE_DIVERSITY:
+			dprintk("dib8096P setting output mode MODE_DIVERSITY");
+			dib8096p_setDibTxMux(state, DIV_ON_DIBTX);
+			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
+			break;
+
+	case OUTMODE_ANALOG_ADC:
+			dprintk("dib8096P setting output mode MODE_ANALOG_ADC");
+			dib8096p_setDibTxMux(state, ADC_ON_DIBTX);
+			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
+			break;
+	}
+
+	if (mode != OUTMODE_HIGH_Z)
+		outreg |= (1<<10);
+
+	dprintk("output_mpeg2_in_188_bytes = %d",
+			state->cfg.output_mpeg2_in_188_bytes);
+	if (state->cfg.output_mpeg2_in_188_bytes)
+		smo_mode |= (1 << 5);
+
+	ret |= dib8000_write_word(state, 299, smo_mode);
+	/* synchronous fread */
+	ret |= dib8000_write_word(state, 299 + 1, fifo_threshold);
+	ret |= dib8000_write_word(state, 1286, outreg);
+
+	return ret;
+}
+
+static int map_addr_to_serpar_number(struct i2c_msg *msg)
+{
+	if (msg->buf[0] <= 15)
+		msg->buf[0] -= 1;
+	else if (msg->buf[0] == 17)
+		msg->buf[0] = 15;
+	else if (msg->buf[0] == 16)
+		msg->buf[0] = 17;
+	else if (msg->buf[0] == 19)
+		msg->buf[0] = 16;
+	else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
+		msg->buf[0] -= 3;
+	else if (msg->buf[0] == 28)
+		msg->buf[0] = 23;
+	else if (msg->buf[0] == 99)
+		msg->buf[0] = 99;
+	else
+		return -EINVAL;
+	return 0;
+}
+
+static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap,
+		struct i2c_msg msg[], int num)
+{
+	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
+	u8 n_overflow = 1;
+	u16 i = 1000;
+	u16 serpar_num = msg[0].buf[0];
+
+	while (n_overflow == 1 && i) {
+		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
+		i--;
+		if (i == 0)
+			dprintk("Tuner ITF: write busy (overflow)");
+	}
+	dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
+	dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
+
+	return num;
+}
+
+static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap,
+		struct i2c_msg msg[], int num)
+{
+	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
+	u8 n_overflow = 1, n_empty = 1;
+	u16 i = 1000;
+	u16 serpar_num = msg[0].buf[0];
+	u16 read_word;
+
+	while (n_overflow == 1 && i) {
+		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
+		i--;
+		if (i == 0)
+			dprintk("TunerITF: read busy (overflow)");
+	}
+	dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f));
+
+	i = 1000;
+	while (n_empty == 1 && i) {
+		n_empty = dib8000_read_word(state, 1984)&0x1;
+		i--;
+		if (i == 0)
+			dprintk("TunerITF: read busy (empty)");
+	}
+
+	read_word = dib8000_read_word(state, 1987);
+	msg[1].buf[0] = (read_word >> 8) & 0xff;
+	msg[1].buf[1] = (read_word) & 0xff;
+
+	return num;
+}
+
+static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap,
+		struct i2c_msg msg[], int num)
+{
+	if (map_addr_to_serpar_number(&msg[0]) == 0) {
+		if (num == 1) /* write */
+			return dib8096p_tuner_write_serpar(i2c_adap, msg, 1);
+		else /* read */
+			return dib8096p_tuner_read_serpar(i2c_adap, msg, 2);
+	}
+	return num;
+}
+
+static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap,
+		struct i2c_msg msg[], int num, u16 apb_address)
+{
+	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
+	u16 word;
+
+	if (num == 1) {		/* write */
+		dib8000_write_word(state, apb_address,
+				((msg[0].buf[1] << 8) | (msg[0].buf[2])));
+	} else {
+		word = dib8000_read_word(state, apb_address);
+		msg[1].buf[0] = (word >> 8) & 0xff;
+		msg[1].buf[1] = (word) & 0xff;
+	}
+	return num;
+}
+
+static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap,
+		struct i2c_msg msg[], int num)
+{
+	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
+	u16 apb_address = 0, word;
+	int i = 0;
+
+	switch (msg[0].buf[0]) {
+	case 0x12:
+			apb_address = 1920;
+			break;
+	case 0x14:
+			apb_address = 1921;
+			break;
+	case 0x24:
+			apb_address = 1922;
+			break;
+	case 0x1a:
+			apb_address = 1923;
+			break;
+	case 0x22:
+			apb_address = 1924;
+			break;
+	case 0x33:
+			apb_address = 1926;
+			break;
+	case 0x34:
+			apb_address = 1927;
+			break;
+	case 0x35:
+			apb_address = 1928;
+			break;
+	case 0x36:
+			apb_address = 1929;
+			break;
+	case 0x37:
+			apb_address = 1930;
+			break;
+	case 0x38:
+			apb_address = 1931;
+			break;
+	case 0x39:
+			apb_address = 1932;
+			break;
+	case 0x2a:
+			apb_address = 1935;
+			break;
+	case 0x2b:
+			apb_address = 1936;
+			break;
+	case 0x2c:
+			apb_address = 1937;
+			break;
+	case 0x2d:
+			apb_address = 1938;
+			break;
+	case 0x2e:
+			apb_address = 1939;
+			break;
+	case 0x2f:
+			apb_address = 1940;
+			break;
+	case 0x30:
+			apb_address = 1941;
+			break;
+	case 0x31:
+			apb_address = 1942;
+			break;
+	case 0x32:
+			apb_address = 1943;
+			break;
+	case 0x3e:
+			apb_address = 1944;
+			break;
+	case 0x3f:
+			apb_address = 1945;
+			break;
+	case 0x40:
+			apb_address = 1948;
+			break;
+	case 0x25:
+			apb_address = 936;
+			break;
+	case 0x26:
+			apb_address = 937;
+			break;
+	case 0x27:
+			apb_address = 938;
+			break;
+	case 0x28:
+			apb_address = 939;
+			break;
+	case 0x1d:
+			/* get sad sel request */
+			i = ((dib8000_read_word(state, 921) >> 12)&0x3);
+			word = dib8000_read_word(state, 924+i);
+			msg[1].buf[0] = (word >> 8) & 0xff;
+			msg[1].buf[1] = (word) & 0xff;
+			return num;
+	case 0x1f:
+			if (num == 1) {	/* write */
+				word = (u16) ((msg[0].buf[1] << 8) |
+						msg[0].buf[2]);
+				/* in the VGAMODE Sel are located on bit 0/1 */
+				word &= 0x3;
+				word = (dib8000_read_word(state, 921) &
+						~(3<<12)) | (word<<12);
+				/* Set the proper input */
+				dib8000_write_word(state, 921, word);
+				return num;
+			}
+	}
+
+	if (apb_address != 0) /* R/W acces via APB */
+		return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address);
+	else  /* R/W access via SERPAR  */
+		return dib8096p_tuner_rw_serpar(i2c_adap, msg, num);
+
+	return 0;
+}
+
+static u32 dib8096p_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dib8096p_tuner_xfer_algo = {
+	.master_xfer = dib8096p_tuner_xfer,
+	.functionality = dib8096p_i2c_func,
+};
+
+struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
+{
+	struct dib8000_state *st = fe->demodulator_priv;
+	return &st->dib8096p_tuner_adap;
+}
+EXPORT_SYMBOL(dib8096p_get_i2c_tuner);
+
+int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u16 en_cur_state;
+
+	dprintk("sleep dib8096p: %d", onoff);
+
+	en_cur_state = dib8000_read_word(state, 1922);
+
+	/* LNAs and MIX are ON and therefore it is a valid configuration */
+	if (en_cur_state > 0xff)
+		state->tuner_enable = en_cur_state ;
+
+	if (onoff)
+		en_cur_state &= 0x00ff;
+	else {
+		if (state->tuner_enable != 0)
+			en_cur_state = state->tuner_enable;
+	}
+
+	dib8000_write_word(state, 1922, en_cur_state);
+
+	return 0;
+}
+EXPORT_SYMBOL(dib8096p_tuner_sleep);
+
+static const s32 lut_1000ln_mant[] =
+{
+	908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
+};
+
+s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
+	s32 val;
+
+	val = dib8000_read32(state, 384);
+	if (mode) {
+		tmp_val = val;
+		while (tmp_val >>= 1)
+			exp++;
+		mant = (val * 1000 / (1<<exp));
+		ix = (u8)((mant-1000)/100); /* index of the LUT */
+		val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
+		val = (val*256)/1000;
+	}
+	return val;
+}
+EXPORT_SYMBOL(dib8000_get_adc_power);
+
+int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	int val = 0;
+
+	switch (IQ) {
+	case 1:
+			val = dib8000_read_word(state, 403);
+			break;
+	case 0:
+			val = dib8000_read_word(state, 404);
+			break;
+	}
+	if (val  & 0x200)
+		val -= 1024;
+
+	return val;
+}
+EXPORT_SYMBOL(dib8090p_get_dc_power);
+
+static void dib8000_update_timf(struct dib8000_state *state)
+{
+	u32 timf = state->timf = dib8000_read32(state, 435);
+
+	dib8000_write_word(state, 29, (u16) (timf >> 16));
+	dib8000_write_word(state, 30, (u16) (timf & 0xffff));
+	dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
+}
+
+u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+
+	switch (op) {
+	case DEMOD_TIMF_SET:
+			state->timf = timf;
+			break;
+	case DEMOD_TIMF_UPDATE:
+			dib8000_update_timf(state);
+			break;
+	case DEMOD_TIMF_GET:
+			break;
+	}
+	dib8000_set_bandwidth(state->fe[0], 6000);
+
+	return state->timf;
+}
+EXPORT_SYMBOL(dib8000_ctrl_timf);
+
+static const u16 adc_target_16dB[11] = {
+	(1 << 13) - 825 - 117,
+	(1 << 13) - 837 - 117,
+	(1 << 13) - 811 - 117,
+	(1 << 13) - 766 - 117,
+	(1 << 13) - 737 - 117,
+	(1 << 13) - 693 - 117,
+	(1 << 13) - 648 - 117,
+	(1 << 13) - 619 - 117,
+	(1 << 13) - 575 - 117,
+	(1 << 13) - 531 - 117,
+	(1 << 13) - 501 - 117
+};
+static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
+
+static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
+{
+	u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0;
+	u8 guard, crate, constellation, timeI;
+	u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff;	// All 13 segments enabled
+	const s16 *ncoeff = NULL, *ana_fe;
+	u16 tmcc_pow = 0;
+	u16 coff_pow = 0x2800;
+	u16 init_prbs = 0xfff;
+	u16 ana_gain = 0;
+
+	if (state->revision == 0x8090)
+		dib8000_init_sdram(state);
+
+	if (state->ber_monitored_layer != LAYER_ALL)
+		dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer);
+	else
+		dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
+
+	i = dib8000_read_word(state, 26) & 1;	// P_dds_invspec
+	dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion^i);
+
+	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
+		//compute new dds_freq for the seg and adjust prbs
+		int seg_offset =
+			state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx -
+			(state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) -
+			(state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2);
+		int clk = state->cfg.pll->internal;
+		u32 segtodds = ((u32) (430 << 23) / clk) << 3;	// segtodds = SegBW / Fclk * pow(2,26)
+		int dds_offset = seg_offset * segtodds;
+		int new_dds, sub_channel;
+		if ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
+			dds_offset -= (int)(segtodds / 2);
+
+		if (state->cfg.pll->ifreq == 0) {
+			if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) {
+				dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
+				new_dds = dds_offset;
+			} else
+				new_dds = dds_offset;
+
+			// We shift tuning frequency if the wanted segment is :
+			//  - the segment of center frequency with an odd total number of segments
+			//  - the segment to the left of center frequency with an even total number of segments
+			//  - the segment to the right of center frequency with an even total number of segments
+			if ((state->fe[0]->dtv_property_cache.delivery_system == SYS_ISDBT)
+				&& (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
+					&& (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
+					  && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
+				  ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
+					 || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
+						 && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2)))
+					 || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
+						 && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
+							 ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
+					)) {
+				new_dds -= ((u32) (850 << 22) / clk) << 4;	// new_dds = 850 (freq shift in KHz) / Fclk * pow(2,26)
+			}
+		} else {
+			if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0)
+				new_dds = state->cfg.pll->ifreq - dds_offset;
+			else
+				new_dds = state->cfg.pll->ifreq + dds_offset;
+		}
+		dib8000_write_word(state, 27, (u16) ((new_dds >> 16) & 0x01ff));
+		dib8000_write_word(state, 28, (u16) (new_dds & 0xffff));
+		if (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
+			sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3;
+		else
+			sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3;
+		sub_channel -= 6;
+
+		if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K
+				|| state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) {
+			dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1);	//adp_pass =1
+			dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14));	//pha3_force_pha_shift = 1
+		} else {
+			dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe);	//adp_pass =0
+			dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff);	//pha3_force_pha_shift = 0
+		}
+
+		switch (state->fe[0]->dtv_property_cache.transmission_mode) {
+		case TRANSMISSION_MODE_2K:
+			switch (sub_channel) {
+			case -6:
+				init_prbs = 0x0;
+				break;	// 41, 0, 1
+			case -5:
+				init_prbs = 0x423;
+				break;	// 02~04
+			case -4:
+				init_prbs = 0x9;
+				break;	// 05~07
+			case -3:
+				init_prbs = 0x5C7;
+				break;	// 08~10
+			case -2:
+				init_prbs = 0x7A6;
+				break;	// 11~13
+			case -1:
+				init_prbs = 0x3D8;
+				break;	// 14~16
+			case 0:
+				init_prbs = 0x527;
+				break;	// 17~19
+			case 1:
+				init_prbs = 0x7FF;
+				break;	// 20~22
+			case 2:
+				init_prbs = 0x79B;
+				break;	// 23~25
+			case 3:
+				init_prbs = 0x3D6;
+				break;	// 26~28
+			case 4:
+				init_prbs = 0x3A2;
+				break;	// 29~31
+			case 5:
+				init_prbs = 0x53B;
+				break;	// 32~34
+			case 6:
+				init_prbs = 0x2F4;
+				break;	// 35~37
+			default:
+			case 7:
+				init_prbs = 0x213;
+				break;	// 38~40
+			}
+			break;
+
+		case TRANSMISSION_MODE_4K:
+			switch (sub_channel) {
+			case -6:
+				init_prbs = 0x0;
+				break;	// 41, 0, 1
+			case -5:
+				init_prbs = 0x208;
+				break;	// 02~04
+			case -4:
+				init_prbs = 0xC3;
+				break;	// 05~07
+			case -3:
+				init_prbs = 0x7B9;
+				break;	// 08~10
+			case -2:
+				init_prbs = 0x423;
+				break;	// 11~13
+			case -1:
+				init_prbs = 0x5C7;
+				break;	// 14~16
+			case 0:
+				init_prbs = 0x3D8;
+				break;	// 17~19
+			case 1:
+				init_prbs = 0x7FF;
+				break;	// 20~22
+			case 2:
+				init_prbs = 0x3D6;
+				break;	// 23~25
+			case 3:
+				init_prbs = 0x53B;
+				break;	// 26~28
+			case 4:
+				init_prbs = 0x213;
+				break;	// 29~31
+			case 5:
+				init_prbs = 0x29;
+				break;	// 32~34
+			case 6:
+				init_prbs = 0xD0;
+				break;	// 35~37
+			default:
+			case 7:
+				init_prbs = 0x48E;
+				break;	// 38~40
+			}
+			break;
+
+		default:
+		case TRANSMISSION_MODE_8K:
+			switch (sub_channel) {
+			case -6:
+				init_prbs = 0x0;
+				break;	// 41, 0, 1
+			case -5:
+				init_prbs = 0x740;
+				break;	// 02~04
+			case -4:
+				init_prbs = 0x069;
+				break;	// 05~07
+			case -3:
+				init_prbs = 0x7DD;
+				break;	// 08~10
+			case -2:
+				init_prbs = 0x208;
+				break;	// 11~13
+			case -1:
+				init_prbs = 0x7B9;
+				break;	// 14~16
+			case 0:
+				init_prbs = 0x5C7;
+				break;	// 17~19
+			case 1:
+				init_prbs = 0x7FF;
+				break;	// 20~22
+			case 2:
+				init_prbs = 0x53B;
+				break;	// 23~25
+			case 3:
+				init_prbs = 0x29;
+				break;	// 26~28
+			case 4:
+				init_prbs = 0x48E;
+				break;	// 29~31
+			case 5:
+				init_prbs = 0x4C4;
+				break;	// 32~34
+			case 6:
+				init_prbs = 0x367;
+				break;	// 33~37
+			default:
+			case 7:
+				init_prbs = 0x684;
+				break;	// 38~40
+			}
+			break;
+		}
+	} else {
+		dib8000_write_word(state, 27, (u16) ((state->cfg.pll->ifreq >> 16) & 0x01ff));
+		dib8000_write_word(state, 28, (u16) (state->cfg.pll->ifreq & 0xffff));
+		dib8000_write_word(state, 26, (u16) ((state->cfg.pll->ifreq >> 25) & 0x0003));
+	}
+	/*P_mode == ?? */
+	dib8000_write_word(state, 10, (seq << 4));
+	//  dib8000_write_word(state, 287, (dib8000_read_word(state, 287) & 0xe000) | 0x1000);
+
+	switch (state->fe[0]->dtv_property_cache.guard_interval) {
+	case GUARD_INTERVAL_1_32:
+		guard = 0;
+		break;
+	case GUARD_INTERVAL_1_16:
+		guard = 1;
+		break;
+	case GUARD_INTERVAL_1_8:
+		guard = 2;
+		break;
+	case GUARD_INTERVAL_1_4:
+	default:
+		guard = 3;
+		break;
+	}
+
+	dib8000_write_word(state, 1, (init_prbs << 2) | (guard & 0x3));	// ADDR 1
+
+	max_constellation = DQPSK;
+	for (i = 0; i < 3; i++) {
+		switch (state->fe[0]->dtv_property_cache.layer[i].modulation) {
+		case DQPSK:
+			constellation = 0;
+			break;
+		case QPSK:
+			constellation = 1;
+			break;
+		case QAM_16:
+			constellation = 2;
+			break;
+		case QAM_64:
+		default:
+			constellation = 3;
+			break;
+		}
+
+		switch (state->fe[0]->dtv_property_cache.layer[i].fec) {
+		case FEC_1_2:
+			crate = 1;
+			break;
+		case FEC_2_3:
+			crate = 2;
+			break;
+		case FEC_3_4:
+			crate = 3;
+			break;
+		case FEC_5_6:
+			crate = 5;
+			break;
+		case FEC_7_8:
+		default:
+			crate = 7;
+			break;
+		}
+
+		if ((state->fe[0]->dtv_property_cache.layer[i].interleaving > 0) &&
+				((state->fe[0]->dtv_property_cache.layer[i].interleaving <= 3) ||
+				 (state->fe[0]->dtv_property_cache.layer[i].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1))
+			)
+			timeI = state->fe[0]->dtv_property_cache.layer[i].interleaving;
+		else
+			timeI = 0;
+		dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[i].segment_count & 0xf) << 6) |
+					(crate << 3) | timeI);
+		if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) {
+			switch (max_constellation) {
+			case DQPSK:
+			case QPSK:
+				if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_16 ||
+					state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
+					max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
+				break;
+			case QAM_16:
+				if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
+					max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
+				break;
+			}
+		}
+	}
+
+	mode = fft_to_mode(state);
+
+	//dib8000_write_word(state, 5, 13); /*p_last_seg = 13*/
+
+	dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) |
+				((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache.
+												 isdbt_sb_mode & 1) << 4));
+
+	dprintk("mode = %d ; guard = %d", mode, state->fe[0]->dtv_property_cache.guard_interval);
+
+	/* signal optimization parameter */
+
+	if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) {
+		seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0];
+		for (i = 1; i < 3; i++)
+			nbseg_diff +=
+				(state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
+		for (i = 0; i < nbseg_diff; i++)
+			seg_diff_mask |= 1 << permu_seg[i + 1];
+	} else {
+		for (i = 0; i < 3; i++)
+			nbseg_diff +=
+				(state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
+		for (i = 0; i < nbseg_diff; i++)
+			seg_diff_mask |= 1 << permu_seg[i];
+	}
+	dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask);
+
+	state->differential_constellation = (seg_diff_mask != 0);
+	if (state->revision != 0x8090)
+		dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
+	else
+		dib8096p_set_diversity_in(state->fe[0], state->diversity_onoff);
+
+	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
+		if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
+			seg_mask13 = 0x00E0;
+		else		// 1-segment
+			seg_mask13 = 0x0040;
+	} else
+		seg_mask13 = 0x1fff;
+
+	// WRITE: Mode & Diff mask
+	dib8000_write_word(state, 0, (mode << 13) | seg_diff_mask);
+
+	if ((seg_diff_mask) || (state->fe[0]->dtv_property_cache.isdbt_sb_mode))
+		dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
+	else
+		dib8000_write_word(state, 268, (2 << 9) | 39);	//init value
+
+	// ---- SMALL ----
+	// P_small_seg_diff
+	dib8000_write_word(state, 352, seg_diff_mask);	// ADDR 352
+
+	dib8000_write_word(state, 353, seg_mask13);	// ADDR 353
+
+/*	// P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */
+
+	// ---- SMALL ----
+	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
+		switch (state->fe[0]->dtv_property_cache.transmission_mode) {
+		case TRANSMISSION_MODE_2K:
+			if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
+				if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
+					ncoeff = coeff_2k_sb_1seg_dqpsk;
+				else	// QPSK or QAM
+					ncoeff = coeff_2k_sb_1seg;
+			} else {	// 3-segments
+				if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
+					if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
+						ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
+					else	// QPSK or QAM on external segments
+						ncoeff = coeff_2k_sb_3seg_0dqpsk;
+				} else {	// QPSK or QAM on central segment
+					if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
+						ncoeff = coeff_2k_sb_3seg_1dqpsk;
+					else	// QPSK or QAM on external segments
+						ncoeff = coeff_2k_sb_3seg;
+				}
+			}
+			break;
+
+		case TRANSMISSION_MODE_4K:
+			if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
+				if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
+					ncoeff = coeff_4k_sb_1seg_dqpsk;
+				else	// QPSK or QAM
+					ncoeff = coeff_4k_sb_1seg;
+			} else {	// 3-segments
+				if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
+					if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
+						ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
+					} else {	// QPSK or QAM on external segments
+						ncoeff = coeff_4k_sb_3seg_0dqpsk;
+					}
+				} else {	// QPSK or QAM on central segment
+					if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
+						ncoeff = coeff_4k_sb_3seg_1dqpsk;
+					} else	// QPSK or QAM on external segments
+						ncoeff = coeff_4k_sb_3seg;
+				}
+			}
+			break;
+
+		case TRANSMISSION_MODE_AUTO:
+		case TRANSMISSION_MODE_8K:
+		default:
+			if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
+				if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
+					ncoeff = coeff_8k_sb_1seg_dqpsk;
+				else	// QPSK or QAM
+					ncoeff = coeff_8k_sb_1seg;
+			} else {	// 3-segments
+				if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
+					if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
+						ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
+					} else {	// QPSK or QAM on external segments
+						ncoeff = coeff_8k_sb_3seg_0dqpsk;
+					}
+				} else {	// QPSK or QAM on central segment
+					if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
+						ncoeff = coeff_8k_sb_3seg_1dqpsk;
+					} else	// QPSK or QAM on external segments
+						ncoeff = coeff_8k_sb_3seg;
+				}
+			}
+			break;
+		}
+		for (i = 0; i < 8; i++)
+			dib8000_write_word(state, 343 + i, ncoeff[i]);
+	}
+
+	// P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5
+	dib8000_write_word(state, 351,
+				(state->fe[0]->dtv_property_cache.isdbt_sb_mode << 9) | (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5);
+
+	// ---- COFF ----
+	// Carloff, the most robust
+	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
+
+		// P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64
+		// P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1
+		dib8000_write_word(state, 187,
+					(4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2)
+					| 0x3);
+
+/*		// P_small_coef_ext_enable = 1 */
+/*		dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */
+
+		if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
+
+			// P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width= (P_mode == 3) , P_coff_one_seg_sym= (P_mode-1)
+			if (mode == 3)
+				dib8000_write_word(state, 180, 0x1fcf | ((mode - 1) << 14));
+			else
+				dib8000_write_word(state, 180, 0x0fcf | ((mode - 1) << 14));
+			// P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1,
+			// P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4
+			dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
+			// P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8
+			dib8000_write_word(state, 340, (16 << 6) | (8 << 0));
+			// P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1
+			dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
+
+			// P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k
+			dib8000_write_word(state, 181, 300);
+			dib8000_write_word(state, 182, 150);
+			dib8000_write_word(state, 183, 80);
+			dib8000_write_word(state, 184, 300);
+			dib8000_write_word(state, 185, 150);
+			dib8000_write_word(state, 186, 80);
+		} else {	// Sound Broadcasting mode 3 seg
+			// P_coff_one_seg_sym= 1, P_coff_one_seg_width= 1, P_coff_winlen=63, P_coff_thres_lock=15
+			/*	if (mode == 3) */
+			/*		dib8000_write_word(state, 180, 0x2fca | ((0) << 14)); */
+			/*	else */
+			/*		dib8000_write_word(state, 180, 0x2fca | ((1) << 14)); */
+			dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
+
+			// P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1,
+			// P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4
+			dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
+			// P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8
+			dib8000_write_word(state, 340, (16 << 6) | (8 << 0));
+			//P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1
+			dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
+
+			// P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k
+			dib8000_write_word(state, 181, 350);
+			dib8000_write_word(state, 182, 300);
+			dib8000_write_word(state, 183, 250);
+			dib8000_write_word(state, 184, 350);
+			dib8000_write_word(state, 185, 300);
+			dib8000_write_word(state, 186, 250);
+		}
+
+	} else if (state->isdbt_cfg_loaded == 0) {	// if not Sound Broadcasting mode : put default values for 13 segments
+		dib8000_write_word(state, 180, (16 << 6) | 9);
+		dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
+		coff_pow = 0x2800;
+		for (i = 0; i < 6; i++)
+			dib8000_write_word(state, 181 + i, coff_pow);
+
+		// P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1,
+		// P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=1
+		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
+
+		// P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6
+		dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
+		// P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1
+		dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
+	}
+	// ---- FFT ----
+	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 && state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
+		dib8000_write_word(state, 178, 64);	// P_fft_powrange=64
+	else
+		dib8000_write_word(state, 178, 32);	// P_fft_powrange=32
+
+	/* make the cpil_coff_lock more robust but slower p_coff_winlen
+	 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
+	 */
+	/* if ( ( nbseg_diff>0)&&(nbseg_diff<13))
+		dib8000_write_word(state, 187, (dib8000_read_word(state, 187) & 0xfffb) | (1 << 3)); */
+
+	dib8000_write_word(state, 189, ~seg_mask13 | seg_diff_mask);	/* P_lmod4_seg_inh       */
+	dib8000_write_word(state, 192, ~seg_mask13 | seg_diff_mask);	/* P_pha3_seg_inh        */
+	dib8000_write_word(state, 225, ~seg_mask13 | seg_diff_mask);	/* P_tac_seg_inh         */
+	if ((!state->fe[0]->dtv_property_cache.isdbt_sb_mode) && (state->cfg.pll->ifreq == 0))
+		dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask | 0x40);	/* P_equal_noise_seg_inh */
+	else
+		dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask);	/* P_equal_noise_seg_inh */
+	dib8000_write_word(state, 287, ~seg_mask13 | 0x1000);	/* P_tmcc_seg_inh        */
+	//dib8000_write_word(state, 288, ~seg_mask13 | seg_diff_mask); /* P_tmcc_seg_eq_inh */
+	if (!autosearching)
+		dib8000_write_word(state, 288, (~seg_mask13 | seg_diff_mask) & 0x1fff);	/* P_tmcc_seg_eq_inh */
+	else
+		dib8000_write_word(state, 288, 0x1fff);	//disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels.
+	dprintk("287 = %X (%d)", ~seg_mask13 | 0x1000, ~seg_mask13 | 0x1000);
+
+	dib8000_write_word(state, 211, seg_mask13 & (~seg_diff_mask));	/* P_des_seg_enabled     */
+
+	/* offset loop parameters */
+	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
+		if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
+			/* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */
+			dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x40);
+
+		else		// Sound Broadcasting mode 3 seg
+			/* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */
+			dib8000_write_word(state, 32, ((10 - mode) << 12) | (6 << 8) | 0x60);
+	} else
+		// TODO in 13 seg, timf_alpha can always be the same or not ?
+		/* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
+		dib8000_write_word(state, 32, ((9 - mode) << 12) | (6 << 8) | 0x80);
+
+	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
+		if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
+			/* P_ctrl_pha_off_max=3   P_ctrl_sfreq_inh =0  P_ctrl_sfreq_step = (11-P_mode)  */
+			dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (10 - mode));
+
+		else		// Sound Broadcasting mode 3 seg
+			/* P_ctrl_pha_off_max=3   P_ctrl_sfreq_inh =0  P_ctrl_sfreq_step = (10-P_mode)  */
+			dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (9 - mode));
+	} else
+		/* P_ctrl_pha_off_max=3   P_ctrl_sfreq_inh =0  P_ctrl_sfreq_step = 9  */
+		dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (8 - mode));
+
+	/* P_dvsy_sync_wait - reuse mode */
+	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
+	case TRANSMISSION_MODE_8K:
+		mode = 256;
+		break;
+	case TRANSMISSION_MODE_4K:
+		mode = 128;
+		break;
+	default:
+	case TRANSMISSION_MODE_2K:
+		mode = 64;
+		break;
+	}
+	if (state->cfg.diversity_delay == 0)
+		mode = (mode * (1 << (guard)) * 3) / 2 + 48;	// add 50% SFN margin + compensate for one DVSY-fifo
+	else
+		mode = (mode * (1 << (guard)) * 3) / 2 + state->cfg.diversity_delay;	// add 50% SFN margin + compensate for DVSY-fifo
+	mode <<= 4;
+	dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | mode);
+
+	/* channel estimation fine configuration */
+	switch (max_constellation) {
+	case QAM_64:
+		ana_gain = 0x7;	// -1 : avoid def_est saturation when ADC target is -16dB
+		coeff[0] = 0x0148;	/* P_adp_regul_cnt 0.04 */
+		coeff[1] = 0xfff0;	/* P_adp_noise_cnt -0.002 */
+		coeff[2] = 0x00a4;	/* P_adp_regul_ext 0.02 */
+		coeff[3] = 0xfff8;	/* P_adp_noise_ext -0.001 */
+		//if (!state->cfg.hostbus_diversity) //if diversity, we should prehaps use the configuration of the max_constallation -1
+		break;
+	case QAM_16:
+		ana_gain = 0x7;	// -1 : avoid def_est saturation when ADC target is -16dB
+		coeff[0] = 0x023d;	/* P_adp_regul_cnt 0.07 */
+		coeff[1] = 0xffdf;	/* P_adp_noise_cnt -0.004 */
+		coeff[2] = 0x00a4;	/* P_adp_regul_ext 0.02 */
+		coeff[3] = 0xfff0;	/* P_adp_noise_ext -0.002 */
+		//if (!((state->cfg.hostbus_diversity) && (max_constellation == QAM_16)))
+		break;
+	default:
+		ana_gain = 0;	// 0 : goes along with ADC target at -22dB to keep good mobile performance and lock at sensitivity level
+		coeff[0] = 0x099a;	/* P_adp_regul_cnt 0.3 */
+		coeff[1] = 0xffae;	/* P_adp_noise_cnt -0.01 */
+		coeff[2] = 0x0333;	/* P_adp_regul_ext 0.1 */
+		coeff[3] = 0xfff8;	/* P_adp_noise_ext -0.002 */
+		break;
+	}
+	for (mode = 0; mode < 4; mode++)
+		dib8000_write_word(state, 215 + mode, coeff[mode]);
+
+	// update ana_gain depending on max constellation
+	dib8000_write_word(state, 116, ana_gain);
+	// update ADC target depending on ana_gain
+	if (ana_gain) {		// set -16dB ADC target for ana_gain=-1
+		for (i = 0; i < 10; i++)
+			dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
+	} else {		// set -22dB ADC target for ana_gain=0
+		for (i = 0; i < 10; i++)
+			dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
+	}
+
+	// ---- ANA_FE ----
+	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
+		if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
+			ana_fe = ana_fe_coeff_3seg;
+		else		// 1-segment
+			ana_fe = ana_fe_coeff_1seg;
+	} else
+		ana_fe = ana_fe_coeff_13seg;
+
+	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 || state->isdbt_cfg_loaded == 0)
+		for (mode = 0; mode < 24; mode++)
+			dib8000_write_word(state, 117 + mode, ana_fe[mode]);
+
+	// ---- CHAN_BLK ----
+	for (i = 0; i < 13; i++) {
+		if ((((~seg_diff_mask) >> i) & 1) == 1) {
+			P_cfr_left_edge += (1 << i) * ((i == 0) || ((((seg_mask13 & (~seg_diff_mask)) >> (i - 1)) & 1) == 0));
+			P_cfr_right_edge += (1 << i) * ((i == 12) || ((((seg_mask13 & (~seg_diff_mask)) >> (i + 1)) & 1) == 0));
+		}
+	}
+	dib8000_write_word(state, 222, P_cfr_left_edge);	// P_cfr_left_edge
+	dib8000_write_word(state, 223, P_cfr_right_edge);	// P_cfr_right_edge
+	// "P_cspu_left_edge"  not used => do not care
+	// "P_cspu_right_edge" not used => do not care
+
+	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
+		dib8000_write_word(state, 228, 1);	// P_2d_mode_byp=1
+		dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0);	// P_cspu_win_cut = 0
+		if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0
+			&& state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) {
+			//dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); // P_adp_pass = 0
+			dib8000_write_word(state, 265, 15);	// P_equal_noise_sel = 15
+		}
+	} else if (state->isdbt_cfg_loaded == 0) {
+		dib8000_write_word(state, 228, 0);	// default value
+		dib8000_write_word(state, 265, 31);	// default value
+		dib8000_write_word(state, 205, 0x200f);	// init value
+	}
+	// ---- TMCC ----
+	for (i = 0; i < 3; i++)
+		tmcc_pow +=
+			(((state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe[0]->dtv_property_cache.layer[i].segment_count);
+	// Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9);
+	// Threshold is set at 1/4 of max power.
+	tmcc_pow *= (1 << (9 - 2));
+
+	dib8000_write_word(state, 290, tmcc_pow);	// P_tmcc_dec_thres_2k
+	dib8000_write_word(state, 291, tmcc_pow);	// P_tmcc_dec_thres_4k
+	dib8000_write_word(state, 292, tmcc_pow);	// P_tmcc_dec_thres_8k
+	//dib8000_write_word(state, 287, (1 << 13) | 0x1000 );
+	// ---- PHA3 ----
+
+	if (state->isdbt_cfg_loaded == 0)
+		dib8000_write_word(state, 250, 3285);	/*p_2d_hspeed_thr0 */
+
+	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
+		state->isdbt_cfg_loaded = 0;
+	else
+		state->isdbt_cfg_loaded = 1;
+
+}
+
+static int dib8000_autosearch_start(struct dvb_frontend *fe)
+{
+	u8 factor;
+	u32 value;
+	struct dib8000_state *state = fe->demodulator_priv;
+
+	int slist = 0;
+
+	state->fe[0]->dtv_property_cache.inversion = 0;
+	if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode)
+		state->fe[0]->dtv_property_cache.layer[0].segment_count = 13;
+	state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64;
+	state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3;
+	state->fe[0]->dtv_property_cache.layer[0].interleaving = 0;
+
+	//choose the right list, in sb, always do everything
+	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
+		state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
+		state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
+		slist = 7;
+		dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
+	} else {
+		if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) {
+			if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
+				slist = 7;
+				dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));	// P_mode = 1 to have autosearch start ok with mode2
+			} else
+				slist = 3;
+		} else {
+			if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
+				slist = 2;
+				dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));	// P_mode = 1
+			} else
+				slist = 0;
+		}
+
+		if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO)
+			state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
+		if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO)
+			state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
+
+		dprintk("using list for autosearch : %d", slist);
+		dib8000_set_channel(state, (unsigned char)slist, 1);
+		//dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));  // P_mode = 1
+
+		factor = 1;
+
+		//set lock_mask values
+		dib8000_write_word(state, 6, 0x4);
+		dib8000_write_word(state, 7, 0x8);
+		dib8000_write_word(state, 8, 0x1000);
+
+		//set lock_mask wait time values
+		value = 50 * state->cfg.pll->internal * factor;
+		dib8000_write_word(state, 11, (u16) ((value >> 16) & 0xffff));	// lock0 wait time
+		dib8000_write_word(state, 12, (u16) (value & 0xffff));	// lock0 wait time
+		value = 100 * state->cfg.pll->internal * factor;
+		dib8000_write_word(state, 13, (u16) ((value >> 16) & 0xffff));	// lock1 wait time
+		dib8000_write_word(state, 14, (u16) (value & 0xffff));	// lock1 wait time
+		value = 1000 * state->cfg.pll->internal * factor;
+		dib8000_write_word(state, 15, (u16) ((value >> 16) & 0xffff));	// lock2 wait time
+		dib8000_write_word(state, 16, (u16) (value & 0xffff));	// lock2 wait time
+
+		value = dib8000_read_word(state, 0);
+		dib8000_write_word(state, 0, (u16) ((1 << 15) | value));
+		dib8000_read_word(state, 1284);	// reset the INT. n_irq_pending
+		dib8000_write_word(state, 0, (u16) value);
+
+	}
+
+	return 0;
+}
+
+static int dib8000_autosearch_irq(struct dvb_frontend *fe)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u16 irq_pending = dib8000_read_word(state, 1284);
+
+	if (irq_pending & 0x1) {	// failed
+		dprintk("dib8000_autosearch_irq failed");
+		return 1;
+	}
+
+	if (irq_pending & 0x2) {	// succeeded
+		dprintk("dib8000_autosearch_irq succeeded");
+		return 2;
+	}
+
+	return 0;		// still pending
+}
+
+static int dib8000_tune(struct dvb_frontend *fe)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	int ret = 0;
+	u16 lock, value, mode;
+
+	// we are already tuned - just resuming from suspend
+	if (state == NULL)
+		return -EINVAL;
+
+	mode = fft_to_mode(state);
+
+	dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000);
+	dib8000_set_channel(state, 0, 0);
+
+	// restart demod
+	ret |= dib8000_write_word(state, 770, 0x4000);
+	ret |= dib8000_write_word(state, 770, 0x0000);
+	msleep(45);
+
+	/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3 */
+	/*  ret |= dib8000_write_word(state, 29, (0 << 9) | (4 << 5) | (0 << 4) | (3 << 0) );  workaround inh_isi stays at 1 */
+
+	// never achieved a lock before - wait for timfreq to update
+	if (state->timf == 0) {
+		if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
+			if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
+				msleep(300);
+			else	// Sound Broadcasting mode 3 seg
+				msleep(500);
+		} else		// 13 seg
+			msleep(200);
+	}
+	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
+		if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
+
+			/* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40  alpha to check on board */
+			dib8000_write_word(state, 32, ((13 - mode) << 12) | (6 << 8) | 0x40);
+			//dib8000_write_word(state, 32, (8 << 12) | (6 << 8) | 0x80);
+
+			/*  P_ctrl_sfreq_step= (12-P_mode)   P_ctrl_sfreq_inh =0     P_ctrl_pha_off_max  */
+			ret |= dib8000_write_word(state, 37, (12 - mode) | ((5 + mode) << 5));
+
+		} else {	// Sound Broadcasting mode 3 seg
+
+			/* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60  alpha to check on board */
+			dib8000_write_word(state, 32, ((12 - mode) << 12) | (6 << 8) | 0x60);
+
+			ret |= dib8000_write_word(state, 37, (11 - mode) | ((5 + mode) << 5));
+		}
+
+	} else {		// 13 seg
+		/* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80  alpha to check on board */
+		dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x80);
+
+		ret |= dib8000_write_word(state, 37, (10 - mode) | ((5 + mode) << 5));
+
+	}
+
+	// we achieved a coff_cpil_lock - it's time to update the timf
+	if (state->revision != 0x8090)
+		lock = dib8000_read_word(state, 568);
+	else
+		lock = dib8000_read_word(state, 570);
+	if ((lock >> 11) & 0x1)
+		dib8000_update_timf(state);
+
+	//now that tune is finished, lock0 should lock on fec_mpeg to output this lock on MP_LOCK. It's changed in autosearch start
+	dib8000_write_word(state, 6, 0x200);
+
+	if (state->revision == 0x8002) {
+		value = dib8000_read_word(state, 903);
+		dib8000_write_word(state, 903, value & ~(1 << 3));
+		msleep(1);
+		dib8000_write_word(state, 903, value | (1 << 3));
+	}
+
+	return ret;
+}
+
+static int dib8000_wakeup(struct dvb_frontend *fe)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u8 index_frontend;
+	int ret;
+
+	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
+	dib8000_set_adc_state(state, DIBX000_ADC_ON);
+	if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
+		dprintk("could not start Slow ADC");
+
+	if (state->revision != 0x8090)
+		dib8000_sad_calib(state);
+
+	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+		ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int dib8000_sleep(struct dvb_frontend *fe)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u8 index_frontend;
+	int ret;
+
+	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+		ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (state->revision != 0x8090)
+		dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
+	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
+	return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
+}
+
+enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	return state->tune_state;
+}
+EXPORT_SYMBOL(dib8000_get_tune_state);
+
+int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	state->tune_state = tune_state;
+	return 0;
+}
+EXPORT_SYMBOL(dib8000_set_tune_state);
+
+static int dib8000_get_frontend(struct dvb_frontend *fe)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u16 i, val = 0;
+	fe_status_t stat;
+	u8 index_frontend, sub_index_frontend;
+
+	fe->dtv_property_cache.bandwidth_hz = 6000000;
+
+	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+		state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
+		if (stat&FE_HAS_SYNC) {
+			dprintk("TMCC lock on the slave%i", index_frontend);
+			/* synchronize the cache with the other frontends */
+			state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]);
+			for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) {
+				if (sub_index_frontend != index_frontend) {
+					state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
+					state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
+					state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
+					state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
+					state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
+					for (i = 0; i < 3; i++) {
+						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
+						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
+						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
+						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
+					}
+				}
+			}
+			return 0;
+		}
+	}
+
+	fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
+
+	if (state->revision == 0x8090)
+		val = dib8000_read_word(state, 572);
+	else
+		val = dib8000_read_word(state, 570);
+	fe->dtv_property_cache.inversion = (val & 0x40) >> 6;
+	switch ((val & 0x30) >> 4) {
+	case 1:
+		fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
+		break;
+	case 3:
+	default:
+		fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
+		break;
+	}
+
+	switch (val & 0x3) {
+	case 0:
+		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
+		dprintk("dib8000_get_frontend GI = 1/32 ");
+		break;
+	case 1:
+		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
+		dprintk("dib8000_get_frontend GI = 1/16 ");
+		break;
+	case 2:
+		dprintk("dib8000_get_frontend GI = 1/8 ");
+		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		dprintk("dib8000_get_frontend GI = 1/4 ");
+		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	}
+
+	val = dib8000_read_word(state, 505);
+	fe->dtv_property_cache.isdbt_partial_reception = val & 1;
+	dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
+
+	for (i = 0; i < 3; i++) {
+		val = dib8000_read_word(state, 493 + i);
+		fe->dtv_property_cache.layer[i].segment_count = val & 0x0F;
+		dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count);
+
+		val = dib8000_read_word(state, 499 + i);
+		fe->dtv_property_cache.layer[i].interleaving = val & 0x3;
+		dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving);
+
+		val = dib8000_read_word(state, 481 + i);
+		switch (val & 0x7) {
+		case 1:
+			fe->dtv_property_cache.layer[i].fec = FEC_1_2;
+			dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i);
+			break;
+		case 2:
+			fe->dtv_property_cache.layer[i].fec = FEC_2_3;
+			dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i);
+			break;
+		case 3:
+			fe->dtv_property_cache.layer[i].fec = FEC_3_4;
+			dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i);
+			break;
+		case 5:
+			fe->dtv_property_cache.layer[i].fec = FEC_5_6;
+			dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i);
+			break;
+		default:
+			fe->dtv_property_cache.layer[i].fec = FEC_7_8;
+			dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i);
+			break;
+		}
+
+		val = dib8000_read_word(state, 487 + i);
+		switch (val & 0x3) {
+		case 0:
+			dprintk("dib8000_get_frontend : Layer %d DQPSK ", i);
+			fe->dtv_property_cache.layer[i].modulation = DQPSK;
+			break;
+		case 1:
+			fe->dtv_property_cache.layer[i].modulation = QPSK;
+			dprintk("dib8000_get_frontend : Layer %d QPSK ", i);
+			break;
+		case 2:
+			fe->dtv_property_cache.layer[i].modulation = QAM_16;
+			dprintk("dib8000_get_frontend : Layer %d QAM16 ", i);
+			break;
+		case 3:
+		default:
+			dprintk("dib8000_get_frontend : Layer %d QAM64 ", i);
+			fe->dtv_property_cache.layer[i].modulation = QAM_64;
+			break;
+		}
+	}
+
+	/* synchronize the cache with the other frontends */
+	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+		state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode;
+		state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
+		state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
+		state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
+		state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception;
+		for (i = 0; i < 3; i++) {
+			state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count;
+			state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving;
+			state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec;
+			state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation;
+		}
+	}
+	return 0;
+}
+
+static int dib8000_set_frontend(struct dvb_frontend *fe)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u8 nbr_pending, exit_condition, index_frontend;
+	s8 index_frontend_success = -1;
+	int time, ret;
+	int  time_slave = FE_CALLBACK_TIME_NEVER;
+
+	if (state->fe[0]->dtv_property_cache.frequency == 0) {
+		dprintk("dib8000: must at least specify frequency ");
+		return 0;
+	}
+
+	if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) {
+		dprintk("dib8000: no bandwidth specified, set to default ");
+		state->fe[0]->dtv_property_cache.bandwidth_hz = 6000000;
+	}
+
+	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+		/* synchronization of the cache */
+		state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
+		memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
+
+		if (state->revision != 0x8090)
+			dib8000_set_output_mode(state->fe[index_frontend],
+					OUTMODE_HIGH_Z);
+		else
+			dib8096p_set_output_mode(state->fe[index_frontend],
+					OUTMODE_HIGH_Z);
+		if (state->fe[index_frontend]->ops.tuner_ops.set_params)
+			state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
+
+		dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
+	}
+
+	/* start up the AGC */
+	do {
+		time = dib8000_agc_startup(state->fe[0]);
+		for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+			time_slave = dib8000_agc_startup(state->fe[index_frontend]);
+			if (time == FE_CALLBACK_TIME_NEVER)
+				time = time_slave;
+			else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time))
+				time = time_slave;
+		}
+		if (time != FE_CALLBACK_TIME_NEVER)
+			msleep(time / 10);
+		else
+			break;
+		exit_condition = 1;
+		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+			if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
+				exit_condition = 0;
+				break;
+			}
+		}
+	} while (exit_condition == 0);
+
+	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+		dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
+
+	if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) ||
+			(state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) ||
+			(state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) ||
+			(state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) ||
+			(((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) &&
+			 (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) &&
+			 (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) &&
+			 ((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) ||
+			  (state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) ||
+			(((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) &&
+			 (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) &&
+			 (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) &&
+			 ((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) ||
+			  (state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) ||
+			(((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) &&
+			 (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) &&
+			 (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) &&
+			 ((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) ||
+			  (state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) ||
+			(((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) ||
+			  ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) &&
+			 ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) ||
+			  ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) &&
+			 ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) {
+		int i = 100;
+		u8 found = 0;
+		u8 tune_failed = 0;
+
+		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+			dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000);
+			dib8000_autosearch_start(state->fe[index_frontend]);
+		}
+
+		do {
+			msleep(20);
+			nbr_pending = 0;
+			exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */
+			for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+				if (((tune_failed >> index_frontend) & 0x1) == 0) {
+					found = dib8000_autosearch_irq(state->fe[index_frontend]);
+					switch (found) {
+					case 0: /* tune pending */
+						 nbr_pending++;
+						 break;
+					case 2:
+						 dprintk("autosearch succeed on the frontend%i", index_frontend);
+						 exit_condition = 2;
+						 index_frontend_success = index_frontend;
+						 break;
+					default:
+						 dprintk("unhandled autosearch result");
+					case 1:
+						 tune_failed |= (1 << index_frontend);
+						 dprintk("autosearch failed for the frontend%i", index_frontend);
+						 break;
+					}
+				}
+			}
+
+			/* if all tune are done and no success, exit: tune failed */
+			if ((nbr_pending == 0) && (exit_condition == 0))
+				exit_condition = 1;
+		} while ((exit_condition == 0) && i--);
+
+		if (exit_condition == 1) { /* tune failed */
+			dprintk("tune failed");
+			return 0;
+		}
+
+		dprintk("tune success on frontend%i", index_frontend_success);
+
+		dib8000_get_frontend(fe);
+	}
+
+	for (index_frontend = 0, ret = 0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+		ret = dib8000_tune(state->fe[index_frontend]);
+
+	/* set output mode and diversity input */
+	if (state->revision != 0x8090) {
+		dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
+		for (index_frontend = 1;
+				(index_frontend < MAX_NUMBER_OF_FRONTENDS) &&
+				(state->fe[index_frontend] != NULL);
+				index_frontend++) {
+			dib8000_set_output_mode(state->fe[index_frontend],
+					OUTMODE_DIVERSITY);
+			dib8000_set_diversity_in(state->fe[index_frontend-1], 1);
+		}
+
+		/* turn off the diversity of the last chip */
+		dib8000_set_diversity_in(state->fe[index_frontend-1], 0);
+	} else {
+		dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
+		if (state->cfg.enMpegOutput == 0) {
+			dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
+			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
+		}
+		for (index_frontend = 1;
+				(index_frontend < MAX_NUMBER_OF_FRONTENDS) &&
+				(state->fe[index_frontend] != NULL);
+				index_frontend++) {
+			dib8096p_set_output_mode(state->fe[index_frontend],
+					OUTMODE_DIVERSITY);
+			dib8096p_set_diversity_in(state->fe[index_frontend-1], 1);
+		}
+
+		/* turn off the diversity of the last chip */
+		dib8096p_set_diversity_in(state->fe[index_frontend-1], 0);
+	}
+
+	return ret;
+}
+
+static u16 dib8000_read_lock(struct dvb_frontend *fe)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+
+	if (state->revision == 0x8090)
+		return dib8000_read_word(state, 570);
+	return dib8000_read_word(state, 568);
+}
+
+static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u16 lock_slave = 0, lock;
+	u8 index_frontend;
+
+	if (state->revision == 0x8090)
+		lock = dib8000_read_word(state, 570);
+	else
+		lock = dib8000_read_word(state, 568);
+
+	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+		lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
+
+	*stat = 0;
+
+	if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
+		*stat |= FE_HAS_SIGNAL;
+
+	if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
+		*stat |= FE_HAS_CARRIER;
+
+	if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
+		*stat |= FE_HAS_SYNC;
+
+	if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
+		*stat |= FE_HAS_LOCK;
+
+	if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
+		lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
+		if (lock & 0x01)
+			*stat |= FE_HAS_VITERBI;
+
+		lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
+		if (lock & 0x01)
+			*stat |= FE_HAS_VITERBI;
+
+		lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
+		if (lock & 0x01)
+			*stat |= FE_HAS_VITERBI;
+	}
+
+	return 0;
+}
+
+static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+
+	/* 13 segments */
+	if (state->revision == 0x8090)
+		*ber = (dib8000_read_word(state, 562) << 16) |
+			dib8000_read_word(state, 563);
+	else
+		*ber = (dib8000_read_word(state, 560) << 16) |
+			dib8000_read_word(state, 561);
+	return 0;
+}
+
+static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+
+	/* packet error on 13 seg */
+	if (state->revision == 0x8090)
+		*unc = dib8000_read_word(state, 567);
+	else
+		*unc = dib8000_read_word(state, 565);
+	return 0;
+}
+
+static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u8 index_frontend;
+	u16 val;
+
+	*strength = 0;
+	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+		state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
+		if (val > 65535 - *strength)
+			*strength = 65535;
+		else
+			*strength += val;
+	}
+
+	val = 65535 - dib8000_read_word(state, 390);
+	if (val > 65535 - *strength)
+		*strength = 65535;
+	else
+		*strength += val;
+	return 0;
+}
+
+static u32 dib8000_get_snr(struct dvb_frontend *fe)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u32 n, s, exp;
+	u16 val;
+
+	if (state->revision != 0x8090)
+		val = dib8000_read_word(state, 542);
+	else
+		val = dib8000_read_word(state, 544);
+	n = (val >> 6) & 0xff;
+	exp = (val & 0x3f);
+	if ((exp & 0x20) != 0)
+		exp -= 0x40;
+	n <<= exp+16;
+
+	if (state->revision != 0x8090)
+		val = dib8000_read_word(state, 543);
+	else
+		val = dib8000_read_word(state, 545);
+	s = (val >> 6) & 0xff;
+	exp = (val & 0x3f);
+	if ((exp & 0x20) != 0)
+		exp -= 0x40;
+	s <<= exp+16;
+
+	if (n > 0) {
+		u32 t = (s/n) << 16;
+		return t + ((s << 16) - n*t) / n;
+	}
+	return 0xffffffff;
+}
+
+static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u8 index_frontend;
+	u32 snr_master;
+
+	snr_master = dib8000_get_snr(fe);
+	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+		snr_master += dib8000_get_snr(state->fe[index_frontend]);
+
+	if ((snr_master >> 16) != 0) {
+		snr_master = 10*intlog10(snr_master>>16);
+		*snr = snr_master / ((1 << 24) / 10);
+	}
+	else
+		*snr = 0;
+
+	return 0;
+}
+
+int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u8 index_frontend = 1;
+
+	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
+		index_frontend++;
+	if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
+		dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
+		state->fe[index_frontend] = fe_slave;
+		return 0;
+	}
+
+	dprintk("too many slave frontend");
+	return -ENOMEM;
+}
+EXPORT_SYMBOL(dib8000_set_slave_frontend);
+
+int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	u8 index_frontend = 1;
+
+	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
+		index_frontend++;
+	if (index_frontend != 1) {
+		dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1);
+		state->fe[index_frontend] = NULL;
+		return 0;
+	}
+
+	dprintk("no frontend to be removed");
+	return -ENODEV;
+}
+EXPORT_SYMBOL(dib8000_remove_slave_frontend);
+
+struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+
+	if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
+		return NULL;
+	return state->fe[slave_index];
+}
+EXPORT_SYMBOL(dib8000_get_slave_frontend);
+
+
+int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
+		u8 default_addr, u8 first_addr, u8 is_dib8096p)
+{
+	int k = 0, ret = 0;
+	u8 new_addr = 0;
+	struct i2c_device client = {.adap = host };
+
+	client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
+	if (!client.i2c_write_buffer) {
+		dprintk("%s: not enough memory", __func__);
+		return -ENOMEM;
+	}
+	client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
+	if (!client.i2c_read_buffer) {
+		dprintk("%s: not enough memory", __func__);
+		ret = -ENOMEM;
+		goto error_memory_read;
+	}
+	client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
+	if (!client.i2c_buffer_lock) {
+		dprintk("%s: not enough memory", __func__);
+		ret = -ENOMEM;
+		goto error_memory_lock;
+	}
+	mutex_init(client.i2c_buffer_lock);
+
+	for (k = no_of_demods - 1; k >= 0; k--) {
+		/* designated i2c address */
+		new_addr = first_addr + (k << 1);
+
+		client.addr = new_addr;
+		if (!is_dib8096p)
+			dib8000_i2c_write16(&client, 1287, 0x0003);	/* sram lead in, rdy */
+		if (dib8000_identify(&client) == 0) {
+			/* sram lead in, rdy */
+			if (!is_dib8096p)
+				dib8000_i2c_write16(&client, 1287, 0x0003);
+			client.addr = default_addr;
+			if (dib8000_identify(&client) == 0) {
+				dprintk("#%d: not identified", k);
+				ret  = -EINVAL;
+				goto error;
+			}
+		}
+
+		/* start diversity to pull_down div_str - just for i2c-enumeration */
+		dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
+
+		/* set new i2c address and force divstart */
+		dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
+		client.addr = new_addr;
+		dib8000_identify(&client);
+
+		dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
+	}
+
+	for (k = 0; k < no_of_demods; k++) {
+		new_addr = first_addr | (k << 1);
+		client.addr = new_addr;
+
+		// unforce divstr
+		dib8000_i2c_write16(&client, 1285, new_addr << 2);
+
+		/* deactivate div - it was just for i2c-enumeration */
+		dib8000_i2c_write16(&client, 1286, 0);
+	}
+
+error:
+	kfree(client.i2c_buffer_lock);
+error_memory_lock:
+	kfree(client.i2c_read_buffer);
+error_memory_read:
+	kfree(client.i2c_write_buffer);
+
+	return ret;
+}
+
+EXPORT_SYMBOL(dib8000_i2c_enumeration);
+static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	tune->step_size = 0;
+	tune->max_drift = 0;
+	return 0;
+}
+
+static void dib8000_release(struct dvb_frontend *fe)
+{
+	struct dib8000_state *st = fe->demodulator_priv;
+	u8 index_frontend;
+
+	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
+		dvb_frontend_detach(st->fe[index_frontend]);
+
+	dibx000_exit_i2c_master(&st->i2c_master);
+	i2c_del_adapter(&st->dib8096p_tuner_adap);
+	kfree(st->fe[0]);
+	kfree(st);
+}
+
+struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
+{
+	struct dib8000_state *st = fe->demodulator_priv;
+	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
+}
+
+EXPORT_SYMBOL(dib8000_get_i2c_master);
+
+int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+{
+	struct dib8000_state *st = fe->demodulator_priv;
+	u16 val = dib8000_read_word(st, 299) & 0xffef;
+	val |= (onoff & 0x1) << 4;
+
+	dprintk("pid filter enabled %d", onoff);
+	return dib8000_write_word(st, 299, val);
+}
+EXPORT_SYMBOL(dib8000_pid_filter_ctrl);
+
+int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+{
+	struct dib8000_state *st = fe->demodulator_priv;
+	dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
+	return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
+}
+EXPORT_SYMBOL(dib8000_pid_filter);
+
+static const struct dvb_frontend_ops dib8000_ops = {
+	.delsys = { SYS_ISDBT },
+	.info = {
+		 .name = "DiBcom 8000 ISDB-T",
+		 .frequency_min = 44250000,
+		 .frequency_max = 867250000,
+		 .frequency_stepsize = 62500,
+		 .caps = FE_CAN_INVERSION_AUTO |
+		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
+		 },
+
+	.release = dib8000_release,
+
+	.init = dib8000_wakeup,
+	.sleep = dib8000_sleep,
+
+	.set_frontend = dib8000_set_frontend,
+	.get_tune_settings = dib8000_fe_get_tune_settings,
+	.get_frontend = dib8000_get_frontend,
+
+	.read_status = dib8000_read_status,
+	.read_ber = dib8000_read_ber,
+	.read_signal_strength = dib8000_read_signal_strength,
+	.read_snr = dib8000_read_snr,
+	.read_ucblocks = dib8000_read_unc_blocks,
+};
+
+struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
+{
+	struct dvb_frontend *fe;
+	struct dib8000_state *state;
+
+	dprintk("dib8000_attach");
+
+	state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
+	if (state == NULL)
+		return NULL;
+	fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
+	if (fe == NULL)
+		goto error;
+
+	memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
+	state->i2c.adap = i2c_adap;
+	state->i2c.addr = i2c_addr;
+	state->i2c.i2c_write_buffer = state->i2c_write_buffer;
+	state->i2c.i2c_read_buffer = state->i2c_read_buffer;
+	mutex_init(&state->i2c_buffer_lock);
+	state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
+	state->gpio_val = cfg->gpio_val;
+	state->gpio_dir = cfg->gpio_dir;
+
+	/* Ensure the output mode remains at the previous default if it's
+	 * not specifically set by the caller.
+	 */
+	if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
+		state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
+
+	state->fe[0] = fe;
+	fe->demodulator_priv = state;
+	memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
+
+	state->timf_default = cfg->pll->timf;
+
+	if (dib8000_identify(&state->i2c) == 0)
+		goto error;
+
+	dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
+
+	/* init 8096p tuner adapter */
+	strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface",
+			sizeof(state->dib8096p_tuner_adap.name));
+	state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo;
+	state->dib8096p_tuner_adap.algo_data = NULL;
+	state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent;
+	i2c_set_adapdata(&state->dib8096p_tuner_adap, state);
+	i2c_add_adapter(&state->dib8096p_tuner_adap);
+
+	dib8000_reset(fe);
+
+	dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));	/* ber_rs_len = 3 */
+
+	return fe;
+
+ error:
+	kfree(state);
+	return NULL;
+}
+
+EXPORT_SYMBOL(dib8000_attach);
+
+MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/dib8000.h b/drivers/media/dvb-frontends/dib8000.h
new file mode 100644
index 0000000..39591bb
--- /dev/null
+++ b/drivers/media/dvb-frontends/dib8000.h
@@ -0,0 +1,174 @@
+#ifndef DIB8000_H
+#define DIB8000_H
+
+#include "dibx000_common.h"
+
+struct dib8000_config {
+	u8 output_mpeg2_in_188_bytes;
+	u8 hostbus_diversity;
+	u8 tuner_is_baseband;
+	int (*update_lna) (struct dvb_frontend *, u16 agc_global);
+
+	u8 agc_config_count;
+	struct dibx000_agc_config *agc;
+	struct dibx000_bandwidth_config *pll;
+
+#define DIB8000_GPIO_DEFAULT_DIRECTIONS 0xffff
+	u16 gpio_dir;
+#define DIB8000_GPIO_DEFAULT_VALUES     0x0000
+	u16 gpio_val;
+#define DIB8000_GPIO_PWM_POS0(v)        ((v & 0xf) << 12)
+#define DIB8000_GPIO_PWM_POS1(v)        ((v & 0xf) << 8 )
+#define DIB8000_GPIO_PWM_POS2(v)        ((v & 0xf) << 4 )
+#define DIB8000_GPIO_PWM_POS3(v)         (v & 0xf)
+#define DIB8000_GPIO_DEFAULT_PWM_POS    0xffff
+	u16 gpio_pwm_pos;
+	u16 pwm_freq_div;
+
+	void (*agc_control) (struct dvb_frontend *, u8 before);
+
+	u16 drives;
+	u16 diversity_delay;
+	u8 div_cfg;
+	u8 output_mode;
+	u8 refclksel;
+	u8 enMpegOutput:1;
+};
+
+#define DEFAULT_DIB8000_I2C_ADDRESS 18
+
+#if defined(CONFIG_DVB_DIB8000) || (defined(CONFIG_DVB_DIB8000_MODULE) && defined(MODULE))
+extern struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg);
+extern struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
+
+extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
+		u8 default_addr, u8 first_addr, u8 is_dib8096p);
+
+extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
+extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value);
+extern int dib8000_pid_filter_ctrl(struct dvb_frontend *, u8 onoff);
+extern int dib8000_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
+extern int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state);
+extern enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe);
+extern void dib8000_pwm_agc_reset(struct dvb_frontend *fe);
+extern s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode);
+extern struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe);
+extern int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff);
+extern int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ);
+extern u32 dib8000_ctrl_timf(struct dvb_frontend *fe,
+		uint8_t op, uint32_t timf);
+extern int dib8000_update_pll(struct dvb_frontend *fe,
+		struct dibx000_bandwidth_config *pll);
+extern int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave);
+extern int dib8000_remove_slave_frontend(struct dvb_frontend *fe);
+extern struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index);
+#else
+static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface i, int x)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline int dib8000_i2c_enumeration(struct i2c_adapter *host,
+		int no_of_demods, u8 default_addr, u8 first_addr,
+		u8 is_dib8096p)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+static inline int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+static inline enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return CT_SHUTDOWN;
+}
+static inline void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+static inline struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+static inline int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return 0;
+}
+static inline s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return 0;
+}
+static inline int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return 0;
+}
+static inline u32 dib8000_ctrl_timf(struct dvb_frontend *fe,
+		uint8_t op, uint32_t timf)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return 0;
+}
+static inline int dib8000_update_pll(struct dvb_frontend *fe,
+		struct dibx000_bandwidth_config *pll)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+static inline int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb-frontends/dib9000.c b/drivers/media/dvb-frontends/dib9000.c
new file mode 100644
index 0000000..6201c59
--- /dev/null
+++ b/drivers/media/dvb-frontends/dib9000.c
@@ -0,0 +1,2590 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB9000 and demodulator-family.
+ *
+ * Copyright (C) 2005-10 DiBcom (http://www.dibcom.fr/)
+ *
+ * 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, version 2.
+ */
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+#include "dvb_math.h"
+#include "dvb_frontend.h"
+
+#include "dib9000.h"
+#include "dibx000_common.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB9000: "); printk(args); printk("\n"); } } while (0)
+#define MAX_NUMBER_OF_FRONTENDS 6
+
+struct i2c_device {
+	struct i2c_adapter *i2c_adap;
+	u8 i2c_addr;
+	u8 *i2c_read_buffer;
+	u8 *i2c_write_buffer;
+};
+
+struct dib9000_pid_ctrl {
+#define DIB9000_PID_FILTER_CTRL 0
+#define DIB9000_PID_FILTER      1
+	u8 cmd;
+	u8 id;
+	u16 pid;
+	u8 onoff;
+};
+
+struct dib9000_state {
+	struct i2c_device i2c;
+
+	struct dibx000_i2c_master i2c_master;
+	struct i2c_adapter tuner_adap;
+	struct i2c_adapter component_bus;
+
+	u16 revision;
+	u8 reg_offs;
+
+	enum frontend_tune_state tune_state;
+	u32 status;
+	struct dvb_frontend_parametersContext channel_status;
+
+	u8 fe_id;
+
+#define DIB9000_GPIO_DEFAULT_DIRECTIONS 0xffff
+	u16 gpio_dir;
+#define DIB9000_GPIO_DEFAULT_VALUES     0x0000
+	u16 gpio_val;
+#define DIB9000_GPIO_DEFAULT_PWM_POS    0xffff
+	u16 gpio_pwm_pos;
+
+	union {			/* common for all chips */
+		struct {
+			u8 mobile_mode:1;
+		} host;
+
+		struct {
+			struct dib9000_fe_memory_map {
+				u16 addr;
+				u16 size;
+			} fe_mm[18];
+			u8 memcmd;
+
+			struct mutex mbx_if_lock;	/* to protect read/write operations */
+			struct mutex mbx_lock;	/* to protect the whole mailbox handling */
+
+			struct mutex mem_lock;	/* to protect the memory accesses */
+			struct mutex mem_mbx_lock;	/* to protect the memory-based mailbox */
+
+#define MBX_MAX_WORDS (256 - 200 - 2)
+#define DIB9000_MSG_CACHE_SIZE 2
+			u16 message_cache[DIB9000_MSG_CACHE_SIZE][MBX_MAX_WORDS];
+			u8 fw_is_running;
+		} risc;
+	} platform;
+
+	union {			/* common for all platforms */
+		struct {
+			struct dib9000_config cfg;
+		} d9;
+	} chip;
+
+	struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
+	u16 component_bus_speed;
+
+	/* for the I2C transfer */
+	struct i2c_msg msg[2];
+	u8 i2c_write_buffer[255];
+	u8 i2c_read_buffer[255];
+	struct mutex demod_lock;
+	u8 get_frontend_internal;
+	struct dib9000_pid_ctrl pid_ctrl[10];
+	s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */
+};
+
+static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0
+};
+
+enum dib9000_power_mode {
+	DIB9000_POWER_ALL = 0,
+
+	DIB9000_POWER_NO,
+	DIB9000_POWER_INTERF_ANALOG_AGC,
+	DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD,
+	DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD,
+	DIB9000_POWER_INTERFACE_ONLY,
+};
+
+enum dib9000_out_messages {
+	OUT_MSG_HBM_ACK,
+	OUT_MSG_HOST_BUF_FAIL,
+	OUT_MSG_REQ_VERSION,
+	OUT_MSG_BRIDGE_I2C_W,
+	OUT_MSG_BRIDGE_I2C_R,
+	OUT_MSG_BRIDGE_APB_W,
+	OUT_MSG_BRIDGE_APB_R,
+	OUT_MSG_SCAN_CHANNEL,
+	OUT_MSG_MONIT_DEMOD,
+	OUT_MSG_CONF_GPIO,
+	OUT_MSG_DEBUG_HELP,
+	OUT_MSG_SUBBAND_SEL,
+	OUT_MSG_ENABLE_TIME_SLICE,
+	OUT_MSG_FE_FW_DL,
+	OUT_MSG_FE_CHANNEL_SEARCH,
+	OUT_MSG_FE_CHANNEL_TUNE,
+	OUT_MSG_FE_SLEEP,
+	OUT_MSG_FE_SYNC,
+	OUT_MSG_CTL_MONIT,
+
+	OUT_MSG_CONF_SVC,
+	OUT_MSG_SET_HBM,
+	OUT_MSG_INIT_DEMOD,
+	OUT_MSG_ENABLE_DIVERSITY,
+	OUT_MSG_SET_OUTPUT_MODE,
+	OUT_MSG_SET_PRIORITARY_CHANNEL,
+	OUT_MSG_ACK_FRG,
+	OUT_MSG_INIT_PMU,
+};
+
+enum dib9000_in_messages {
+	IN_MSG_DATA,
+	IN_MSG_FRAME_INFO,
+	IN_MSG_CTL_MONIT,
+	IN_MSG_ACK_FREE_ITEM,
+	IN_MSG_DEBUG_BUF,
+	IN_MSG_MPE_MONITOR,
+	IN_MSG_RAWTS_MONITOR,
+	IN_MSG_END_BRIDGE_I2C_RW,
+	IN_MSG_END_BRIDGE_APB_RW,
+	IN_MSG_VERSION,
+	IN_MSG_END_OF_SCAN,
+	IN_MSG_MONIT_DEMOD,
+	IN_MSG_ERROR,
+	IN_MSG_FE_FW_DL_DONE,
+	IN_MSG_EVENT,
+	IN_MSG_ACK_CHANGE_SVC,
+	IN_MSG_HBM_PROF,
+};
+
+/* memory_access requests */
+#define FE_MM_W_CHANNEL                   0
+#define FE_MM_W_FE_INFO                   1
+#define FE_MM_RW_SYNC                     2
+
+#define FE_SYNC_CHANNEL          1
+#define FE_SYNC_W_GENERIC_MONIT	 2
+#define FE_SYNC_COMPONENT_ACCESS 3
+
+#define FE_MM_R_CHANNEL_SEARCH_STATE      3
+#define FE_MM_R_CHANNEL_UNION_CONTEXT     4
+#define FE_MM_R_FE_INFO                   5
+#define FE_MM_R_FE_MONITOR                6
+
+#define FE_MM_W_CHANNEL_HEAD              7
+#define FE_MM_W_CHANNEL_UNION             8
+#define FE_MM_W_CHANNEL_CONTEXT           9
+#define FE_MM_R_CHANNEL_UNION            10
+#define FE_MM_R_CHANNEL_CONTEXT          11
+#define FE_MM_R_CHANNEL_TUNE_STATE       12
+
+#define FE_MM_R_GENERIC_MONITORING_SIZE	 13
+#define FE_MM_W_GENERIC_MONITORING	     14
+#define FE_MM_R_GENERIC_MONITORING	     15
+
+#define FE_MM_W_COMPONENT_ACCESS         16
+#define FE_MM_RW_COMPONENT_ACCESS_BUFFER 17
+static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len);
+static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len);
+
+static u16 to_fw_output_mode(u16 mode)
+{
+	switch (mode) {
+	case OUTMODE_HIGH_Z:
+		return 0;
+	case OUTMODE_MPEG2_PAR_GATED_CLK:
+		return 4;
+	case OUTMODE_MPEG2_PAR_CONT_CLK:
+		return 8;
+	case OUTMODE_MPEG2_SERIAL:
+		return 16;
+	case OUTMODE_DIVERSITY:
+		return 128;
+	case OUTMODE_MPEG2_FIFO:
+		return 2;
+	case OUTMODE_ANALOG_ADC:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static u16 dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 * b, u32 len, u16 attribute)
+{
+	u32 chunk_size = 126;
+	u32 l;
+	int ret;
+
+	if (state->platform.risc.fw_is_running && (reg < 1024))
+		return dib9000_risc_apb_access_read(state, reg, attribute, NULL, 0, b, len);
+
+	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+	state->msg[0].addr = state->i2c.i2c_addr >> 1;
+	state->msg[0].flags = 0;
+	state->msg[0].buf = state->i2c_write_buffer;
+	state->msg[0].len = 2;
+	state->msg[1].addr = state->i2c.i2c_addr >> 1;
+	state->msg[1].flags = I2C_M_RD;
+	state->msg[1].buf = b;
+	state->msg[1].len = len;
+
+	state->i2c_write_buffer[0] = reg >> 8;
+	state->i2c_write_buffer[1] = reg & 0xff;
+
+	if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
+		state->i2c_write_buffer[0] |= (1 << 5);
+	if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
+		state->i2c_write_buffer[0] |= (1 << 4);
+
+	do {
+		l = len < chunk_size ? len : chunk_size;
+		state->msg[1].len = l;
+		state->msg[1].buf = b;
+		ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 2) != 2 ? -EREMOTEIO : 0;
+		if (ret != 0) {
+			dprintk("i2c read error on %d", reg);
+			return -EREMOTEIO;
+		}
+
+		b += l;
+		len -= l;
+
+		if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT))
+			reg += l / 2;
+	} while ((ret == 0) && len);
+
+	return 0;
+}
+
+static u16 dib9000_i2c_read16(struct i2c_device *i2c, u16 reg)
+{
+	struct i2c_msg msg[2] = {
+		{.addr = i2c->i2c_addr >> 1, .flags = 0,
+			.buf = i2c->i2c_write_buffer, .len = 2},
+		{.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD,
+			.buf = i2c->i2c_read_buffer, .len = 2},
+	};
+
+	i2c->i2c_write_buffer[0] = reg >> 8;
+	i2c->i2c_write_buffer[1] = reg & 0xff;
+
+	if (i2c_transfer(i2c->i2c_adap, msg, 2) != 2) {
+		dprintk("read register %x error", reg);
+		return 0;
+	}
+
+	return (i2c->i2c_read_buffer[0] << 8) | i2c->i2c_read_buffer[1];
+}
+
+static inline u16 dib9000_read_word(struct dib9000_state *state, u16 reg)
+{
+	if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2, 0) != 0)
+		return 0;
+	return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+}
+
+static inline u16 dib9000_read_word_attr(struct dib9000_state *state, u16 reg, u16 attribute)
+{
+	if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2,
+				attribute) != 0)
+		return 0;
+	return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+}
+
+#define dib9000_read16_noinc_attr(state, reg, b, len, attribute) dib9000_read16_attr(state, reg, b, len, (attribute) | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
+
+static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 * buf, u32 len, u16 attribute)
+{
+	u32 chunk_size = 126;
+	u32 l;
+	int ret;
+
+	if (state->platform.risc.fw_is_running && (reg < 1024)) {
+		if (dib9000_risc_apb_access_write
+		    (state, reg, DATA_BUS_ACCESS_MODE_16BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | attribute, buf, len) != 0)
+			return -EINVAL;
+		return 0;
+	}
+
+	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
+	state->msg[0].addr = state->i2c.i2c_addr >> 1;
+	state->msg[0].flags = 0;
+	state->msg[0].buf = state->i2c_write_buffer;
+	state->msg[0].len = len + 2;
+
+	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+	state->i2c_write_buffer[1] = (reg) & 0xff;
+
+	if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
+		state->i2c_write_buffer[0] |= (1 << 5);
+	if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
+		state->i2c_write_buffer[0] |= (1 << 4);
+
+	do {
+		l = len < chunk_size ? len : chunk_size;
+		state->msg[0].len = l + 2;
+		memcpy(&state->i2c_write_buffer[2], buf, l);
+
+		ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
+
+		buf += l;
+		len -= l;
+
+		if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT))
+			reg += l / 2;
+	} while ((ret == 0) && len);
+
+	return ret;
+}
+
+static int dib9000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
+{
+	struct i2c_msg msg = {
+		.addr = i2c->i2c_addr >> 1, .flags = 0,
+		.buf = i2c->i2c_write_buffer, .len = 4
+	};
+
+	i2c->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+	i2c->i2c_write_buffer[1] = reg & 0xff;
+	i2c->i2c_write_buffer[2] = (val >> 8) & 0xff;
+	i2c->i2c_write_buffer[3] = val & 0xff;
+
+	return i2c_transfer(i2c->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+}
+
+static inline int dib9000_write_word(struct dib9000_state *state, u16 reg, u16 val)
+{
+	u8 b[2] = { val >> 8, val & 0xff };
+	return dib9000_write16_attr(state, reg, b, 2, 0);
+}
+
+static inline int dib9000_write_word_attr(struct dib9000_state *state, u16 reg, u16 val, u16 attribute)
+{
+	u8 b[2] = { val >> 8, val & 0xff };
+	return dib9000_write16_attr(state, reg, b, 2, attribute);
+}
+
+#define dib9000_write(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, 0)
+#define dib9000_write16_noinc(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
+#define dib9000_write16_noinc_attr(state, reg, buf, len, attribute) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | (attribute))
+
+#define dib9000_mbx_send(state, id, data, len) dib9000_mbx_send_attr(state, id, data, len, 0)
+#define dib9000_mbx_get_message(state, id, msg, len) dib9000_mbx_get_message_attr(state, id, msg, len, 0)
+
+#define MAC_IRQ      (1 << 1)
+#define IRQ_POL_MSK  (1 << 4)
+
+#define dib9000_risc_mem_read_chunks(state, b, len) dib9000_read16_attr(state, 1063, b, len, DATA_BUS_ACCESS_MODE_8BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
+#define dib9000_risc_mem_write_chunks(state, buf, len) dib9000_write16_attr(state, 1063, buf, len, DATA_BUS_ACCESS_MODE_8BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
+
+static void dib9000_risc_mem_setup_cmd(struct dib9000_state *state, u32 addr, u32 len, u8 reading)
+{
+	u8 b[14] = { 0 };
+
+/*      dprintk("%d memcmd: %d %d %d\n", state->fe_id, addr, addr+len, len); */
+/*      b[0] = 0 << 7; */
+	b[1] = 1;
+
+/*      b[2] = 0; */
+/*      b[3] = 0; */
+	b[4] = (u8) (addr >> 8);
+	b[5] = (u8) (addr & 0xff);
+
+/*      b[10] = 0; */
+/*      b[11] = 0; */
+	b[12] = (u8) (addr >> 8);
+	b[13] = (u8) (addr & 0xff);
+
+	addr += len;
+/*      b[6] = 0; */
+/*      b[7] = 0; */
+	b[8] = (u8) (addr >> 8);
+	b[9] = (u8) (addr & 0xff);
+
+	dib9000_write(state, 1056, b, 14);
+	if (reading)
+		dib9000_write_word(state, 1056, (1 << 15) | 1);
+	state->platform.risc.memcmd = -1;	/* if it was called directly reset it - to force a future setup-call to set it */
+}
+
+static void dib9000_risc_mem_setup(struct dib9000_state *state, u8 cmd)
+{
+	struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd & 0x7f];
+	/* decide whether we need to "refresh" the memory controller */
+	if (state->platform.risc.memcmd == cmd &&	/* same command */
+	    !(cmd & 0x80 && m->size < 67))	/* and we do not want to read something with less than 67 bytes looping - working around a bug in the memory controller */
+		return;
+	dib9000_risc_mem_setup_cmd(state, m->addr, m->size, cmd & 0x80);
+	state->platform.risc.memcmd = cmd;
+}
+
+static int dib9000_risc_mem_read(struct dib9000_state *state, u8 cmd, u8 * b, u16 len)
+{
+	if (!state->platform.risc.fw_is_running)
+		return -EIO;
+
+	if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
+	dib9000_risc_mem_setup(state, cmd | 0x80);
+	dib9000_risc_mem_read_chunks(state, b, len);
+	mutex_unlock(&state->platform.risc.mem_lock);
+	return 0;
+}
+
+static int dib9000_risc_mem_write(struct dib9000_state *state, u8 cmd, const u8 * b)
+{
+	struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd];
+	if (!state->platform.risc.fw_is_running)
+		return -EIO;
+
+	if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
+	dib9000_risc_mem_setup(state, cmd);
+	dib9000_risc_mem_write_chunks(state, b, m->size);
+	mutex_unlock(&state->platform.risc.mem_lock);
+	return 0;
+}
+
+static int dib9000_firmware_download(struct dib9000_state *state, u8 risc_id, u16 key, const u8 * code, u32 len)
+{
+	u16 offs;
+
+	if (risc_id == 1)
+		offs = 16;
+	else
+		offs = 0;
+
+	/* config crtl reg */
+	dib9000_write_word(state, 1024 + offs, 0x000f);
+	dib9000_write_word(state, 1025 + offs, 0);
+	dib9000_write_word(state, 1031 + offs, key);
+
+	dprintk("going to download %dB of microcode", len);
+	if (dib9000_write16_noinc(state, 1026 + offs, (u8 *) code, (u16) len) != 0) {
+		dprintk("error while downloading microcode for RISC %c", 'A' + risc_id);
+		return -EIO;
+	}
+
+	dprintk("Microcode for RISC %c loaded", 'A' + risc_id);
+
+	return 0;
+}
+
+static int dib9000_mbx_host_init(struct dib9000_state *state, u8 risc_id)
+{
+	u16 mbox_offs;
+	u16 reset_reg;
+	u16 tries = 1000;
+
+	if (risc_id == 1)
+		mbox_offs = 16;
+	else
+		mbox_offs = 0;
+
+	/* Reset mailbox  */
+	dib9000_write_word(state, 1027 + mbox_offs, 0x8000);
+
+	/* Read reset status */
+	do {
+		reset_reg = dib9000_read_word(state, 1027 + mbox_offs);
+		msleep(100);
+	} while ((reset_reg & 0x8000) && --tries);
+
+	if (reset_reg & 0x8000) {
+		dprintk("MBX: init ERROR, no response from RISC %c", 'A' + risc_id);
+		return -EIO;
+	}
+	dprintk("MBX: initialized");
+	return 0;
+}
+
+#define MAX_MAILBOX_TRY 100
+static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, u8 len, u16 attr)
+{
+	u8 *d, b[2];
+	u16 tmp;
+	u16 size;
+	u32 i;
+	int ret = 0;
+
+	if (!state->platform.risc.fw_is_running)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
+	tmp = MAX_MAILBOX_TRY;
+	do {
+		size = dib9000_read_word_attr(state, 1043, attr) & 0xff;
+		if ((size + len + 1) > MBX_MAX_WORDS && --tmp) {
+			dprintk("MBX: RISC mbx full, retrying");
+			msleep(100);
+		} else
+			break;
+	} while (1);
+
+	/*dprintk( "MBX: size: %d", size); */
+
+	if (tmp == 0) {
+		ret = -EINVAL;
+		goto out;
+	}
+#ifdef DUMP_MSG
+	dprintk("--> %02x %d ", id, len + 1);
+	for (i = 0; i < len; i++)
+		dprintk("%04x ", data[i]);
+	dprintk("\n");
+#endif
+
+	/* byte-order conversion - works on big (where it is not necessary) or little endian */
+	d = (u8 *) data;
+	for (i = 0; i < len; i++) {
+		tmp = data[i];
+		*d++ = tmp >> 8;
+		*d++ = tmp & 0xff;
+	}
+
+	/* write msg */
+	b[0] = id;
+	b[1] = len + 1;
+	if (dib9000_write16_noinc_attr(state, 1045, b, 2, attr) != 0 || dib9000_write16_noinc_attr(state, 1045, (u8 *) data, len * 2, attr) != 0) {
+		ret = -EIO;
+		goto out;
+	}
+
+	/* update register nb_mes_in_RX */
+	ret = (u8) dib9000_write_word_attr(state, 1043, 1 << 14, attr);
+
+out:
+	mutex_unlock(&state->platform.risc.mbx_if_lock);
+
+	return ret;
+}
+
+static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id, u16 attr)
+{
+#ifdef DUMP_MSG
+	u16 *d = data;
+#endif
+
+	u16 tmp, i;
+	u8 size;
+	u8 mc_base;
+
+	if (!state->platform.risc.fw_is_running)
+		return 0;
+
+	if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) {
+		dprintk("could not get the lock");
+		return 0;
+	}
+	if (risc_id == 1)
+		mc_base = 16;
+	else
+		mc_base = 0;
+
+	/* Length and type in the first word */
+	*data = dib9000_read_word_attr(state, 1029 + mc_base, attr);
+
+	size = *data & 0xff;
+	if (size <= MBX_MAX_WORDS) {
+		data++;
+		size--;		/* Initial word already read */
+
+		dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, size * 2, attr);
+
+		/* to word conversion */
+		for (i = 0; i < size; i++) {
+			tmp = *data;
+			*data = (tmp >> 8) | (tmp << 8);
+			data++;
+		}
+
+#ifdef DUMP_MSG
+		dprintk("<-- ");
+		for (i = 0; i < size + 1; i++)
+			dprintk("%04x ", d[i]);
+		dprintk("\n");
+#endif
+	} else {
+		dprintk("MBX: message is too big for message cache (%d), flushing message", size);
+		size--;		/* Initial word already read */
+		while (size--)
+			dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, 2, attr);
+	}
+	/* Update register nb_mes_in_TX */
+	dib9000_write_word_attr(state, 1028 + mc_base, 1 << 14, attr);
+
+	mutex_unlock(&state->platform.risc.mbx_if_lock);
+
+	return size + 1;
+}
+
+static int dib9000_risc_debug_buf(struct dib9000_state *state, u16 * data, u8 size)
+{
+	u32 ts = data[1] << 16 | data[0];
+	char *b = (char *)&data[2];
+
+	b[2 * (size - 2) - 1] = '\0';	/* Bullet proof the buffer */
+	if (*b == '~') {
+		b++;
+		dprintk(b);
+	} else
+		dprintk("RISC%d: %d.%04d %s", state->fe_id, ts / 10000, ts % 10000, *b ? b : "<emtpy>");
+	return 1;
+}
+
+static int dib9000_mbx_fetch_to_cache(struct dib9000_state *state, u16 attr)
+{
+	int i;
+	u8 size;
+	u16 *block;
+	/* find a free slot */
+	for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) {
+		block = state->platform.risc.message_cache[i];
+		if (*block == 0) {
+			size = dib9000_mbx_read(state, block, 1, attr);
+
+/*                      dprintk( "MBX: fetched %04x message to cache", *block); */
+
+			switch (*block >> 8) {
+			case IN_MSG_DEBUG_BUF:
+				dib9000_risc_debug_buf(state, block + 1, size);	/* debug-messages are going to be printed right away */
+				*block = 0;	/* free the block */
+				break;
+#if 0
+			case IN_MSG_DATA:	/* FE-TRACE */
+				dib9000_risc_data_process(state, block + 1, size);
+				*block = 0;
+				break;
+#endif
+			default:
+				break;
+			}
+
+			return 1;
+		}
+	}
+	dprintk("MBX: no free cache-slot found for new message...");
+	return -1;
+}
+
+static u8 dib9000_mbx_count(struct dib9000_state *state, u8 risc_id, u16 attr)
+{
+	if (risc_id == 0)
+		return (u8) (dib9000_read_word_attr(state, 1028, attr) >> 10) & 0x1f;	/* 5 bit field */
+	else
+		return (u8) (dib9000_read_word_attr(state, 1044, attr) >> 8) & 0x7f;	/* 7 bit field */
+}
+
+static int dib9000_mbx_process(struct dib9000_state *state, u16 attr)
+{
+	int ret = 0;
+
+	if (!state->platform.risc.fw_is_running)
+		return -1;
+
+	if (mutex_lock_interruptible(&state->platform.risc.mbx_lock) < 0) {
+		dprintk("could not get the lock");
+		return -1;
+	}
+
+	if (dib9000_mbx_count(state, 1, attr))	/* 1=RiscB */
+		ret = dib9000_mbx_fetch_to_cache(state, attr);
+
+	dib9000_read_word_attr(state, 1229, attr);	/* Clear the IRQ */
+/*      if (tmp) */
+/*              dprintk( "cleared IRQ: %x", tmp); */
+	mutex_unlock(&state->platform.risc.mbx_lock);
+
+	return ret;
+}
+
+static int dib9000_mbx_get_message_attr(struct dib9000_state *state, u16 id, u16 * msg, u8 * size, u16 attr)
+{
+	u8 i;
+	u16 *block;
+	u16 timeout = 30;
+
+	*msg = 0;
+	do {
+		/* dib9000_mbx_get_from_cache(); */
+		for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) {
+			block = state->platform.risc.message_cache[i];
+			if ((*block >> 8) == id) {
+				*size = (*block & 0xff) - 1;
+				memcpy(msg, block + 1, (*size) * 2);
+				*block = 0;	/* free the block */
+				i = 0;	/* signal that we found a message */
+				break;
+			}
+		}
+
+		if (i == 0)
+			break;
+
+		if (dib9000_mbx_process(state, attr) == -1)	/* try to fetch one message - if any */
+			return -1;
+
+	} while (--timeout);
+
+	if (timeout == 0) {
+		dprintk("waiting for message %d timed out", id);
+		return -1;
+	}
+
+	return i == 0;
+}
+
+static int dib9000_risc_check_version(struct dib9000_state *state)
+{
+	u8 r[4];
+	u8 size;
+	u16 fw_version = 0;
+
+	if (dib9000_mbx_send(state, OUT_MSG_REQ_VERSION, &fw_version, 1) != 0)
+		return -EIO;
+
+	if (dib9000_mbx_get_message(state, IN_MSG_VERSION, (u16 *) r, &size) < 0)
+		return -EIO;
+
+	fw_version = (r[0] << 8) | r[1];
+	dprintk("RISC: ver: %d.%02d (IC: %d)", fw_version >> 10, fw_version & 0x3ff, (r[2] << 8) | r[3]);
+
+	if ((fw_version >> 10) != 7)
+		return -EINVAL;
+
+	switch (fw_version & 0x3ff) {
+	case 11:
+	case 12:
+	case 14:
+	case 15:
+	case 16:
+	case 17:
+		break;
+	default:
+		dprintk("RISC: invalid firmware version");
+		return -EINVAL;
+	}
+
+	dprintk("RISC: valid firmware version");
+	return 0;
+}
+
+static int dib9000_fw_boot(struct dib9000_state *state, const u8 * codeA, u32 lenA, const u8 * codeB, u32 lenB)
+{
+	/* Reconfig pool mac ram */
+	dib9000_write_word(state, 1225, 0x02);	/* A: 8k C, 4 k D - B: 32k C 6 k D - IRAM 96k */
+	dib9000_write_word(state, 1226, 0x05);
+
+	/* Toggles IP crypto to Host APB interface. */
+	dib9000_write_word(state, 1542, 1);
+
+	/* Set jump and no jump in the dma box */
+	dib9000_write_word(state, 1074, 0);
+	dib9000_write_word(state, 1075, 0);
+
+	/* Set MAC as APB Master. */
+	dib9000_write_word(state, 1237, 0);
+
+	/* Reset the RISCs */
+	if (codeA != NULL)
+		dib9000_write_word(state, 1024, 2);
+	else
+		dib9000_write_word(state, 1024, 15);
+	if (codeB != NULL)
+		dib9000_write_word(state, 1040, 2);
+
+	if (codeA != NULL)
+		dib9000_firmware_download(state, 0, 0x1234, codeA, lenA);
+	if (codeB != NULL)
+		dib9000_firmware_download(state, 1, 0x1234, codeB, lenB);
+
+	/* Run the RISCs */
+	if (codeA != NULL)
+		dib9000_write_word(state, 1024, 0);
+	if (codeB != NULL)
+		dib9000_write_word(state, 1040, 0);
+
+	if (codeA != NULL)
+		if (dib9000_mbx_host_init(state, 0) != 0)
+			return -EIO;
+	if (codeB != NULL)
+		if (dib9000_mbx_host_init(state, 1) != 0)
+			return -EIO;
+
+	msleep(100);
+	state->platform.risc.fw_is_running = 1;
+
+	if (dib9000_risc_check_version(state) != 0)
+		return -EINVAL;
+
+	state->platform.risc.memcmd = 0xff;
+	return 0;
+}
+
+static u16 dib9000_identify(struct i2c_device *client)
+{
+	u16 value;
+
+	value = dib9000_i2c_read16(client, 896);
+	if (value != 0x01b3) {
+		dprintk("wrong Vendor ID (0x%x)", value);
+		return 0;
+	}
+
+	value = dib9000_i2c_read16(client, 897);
+	if (value != 0x4000 && value != 0x4001 && value != 0x4002 && value != 0x4003 && value != 0x4004 && value != 0x4005) {
+		dprintk("wrong Device ID (0x%x)", value);
+		return 0;
+	}
+
+	/* protect this driver to be used with 7000PC */
+	if (value == 0x4000 && dib9000_i2c_read16(client, 769) == 0x4000) {
+		dprintk("this driver does not work with DiB7000PC");
+		return 0;
+	}
+
+	switch (value) {
+	case 0x4000:
+		dprintk("found DiB7000MA/PA/MB/PB");
+		break;
+	case 0x4001:
+		dprintk("found DiB7000HC");
+		break;
+	case 0x4002:
+		dprintk("found DiB7000MC");
+		break;
+	case 0x4003:
+		dprintk("found DiB9000A");
+		break;
+	case 0x4004:
+		dprintk("found DiB9000H");
+		break;
+	case 0x4005:
+		dprintk("found DiB9000M");
+		break;
+	}
+
+	return value;
+}
+
+static void dib9000_set_power_mode(struct dib9000_state *state, enum dib9000_power_mode mode)
+{
+	/* by default everything is going to be powered off */
+	u16 reg_903 = 0x3fff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906;
+	u8 offset;
+
+	if (state->revision == 0x4003 || state->revision == 0x4004 || state->revision == 0x4005)
+		offset = 1;
+	else
+		offset = 0;
+
+	reg_906 = dib9000_read_word(state, 906 + offset) | 0x3;	/* keep settings for RISC */
+
+	/* now, depending on the requested mode, we power on */
+	switch (mode) {
+		/* power up everything in the demod */
+	case DIB9000_POWER_ALL:
+		reg_903 = 0x0000;
+		reg_904 = 0x0000;
+		reg_905 = 0x0000;
+		reg_906 = 0x0000;
+		break;
+
+		/* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */
+	case DIB9000_POWER_INTERFACE_ONLY:	/* TODO power up either SDIO or I2C or SRAM */
+		reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2));
+		break;
+
+	case DIB9000_POWER_INTERF_ANALOG_AGC:
+		reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10));
+		reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2));
+		reg_906 &= ~((1 << 0));
+		break;
+
+	case DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD:
+		reg_903 = 0x0000;
+		reg_904 = 0x801f;
+		reg_905 = 0x0000;
+		reg_906 &= ~((1 << 0));
+		break;
+
+	case DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD:
+		reg_903 = 0x0000;
+		reg_904 = 0x8000;
+		reg_905 = 0x010b;
+		reg_906 &= ~((1 << 0));
+		break;
+	default:
+	case DIB9000_POWER_NO:
+		break;
+	}
+
+	/* always power down unused parts */
+	if (!state->platform.host.mobile_mode)
+		reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1);
+
+	/* P_sdio_select_clk = 0 on MC and after */
+	if (state->revision != 0x4000)
+		reg_906 <<= 1;
+
+	dib9000_write_word(state, 903 + offset, reg_903);
+	dib9000_write_word(state, 904 + offset, reg_904);
+	dib9000_write_word(state, 905 + offset, reg_905);
+	dib9000_write_word(state, 906 + offset, reg_906);
+}
+
+static int dib9000_fw_reset(struct dvb_frontend *fe)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+
+	dib9000_write_word(state, 1817, 0x0003);
+
+	dib9000_write_word(state, 1227, 1);
+	dib9000_write_word(state, 1227, 0);
+
+	switch ((state->revision = dib9000_identify(&state->i2c))) {
+	case 0x4003:
+	case 0x4004:
+	case 0x4005:
+		state->reg_offs = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* reset the i2c-master to use the host interface */
+	dibx000_reset_i2c_master(&state->i2c_master);
+
+	dib9000_set_power_mode(state, DIB9000_POWER_ALL);
+
+	/* unforce divstr regardless whether i2c enumeration was done or not */
+	dib9000_write_word(state, 1794, dib9000_read_word(state, 1794) & ~(1 << 1));
+	dib9000_write_word(state, 1796, 0);
+	dib9000_write_word(state, 1805, 0x805);
+
+	/* restart all parts */
+	dib9000_write_word(state, 898, 0xffff);
+	dib9000_write_word(state, 899, 0xffff);
+	dib9000_write_word(state, 900, 0x0001);
+	dib9000_write_word(state, 901, 0xff19);
+	dib9000_write_word(state, 902, 0x003c);
+
+	dib9000_write_word(state, 898, 0);
+	dib9000_write_word(state, 899, 0);
+	dib9000_write_word(state, 900, 0);
+	dib9000_write_word(state, 901, 0);
+	dib9000_write_word(state, 902, 0);
+
+	dib9000_write_word(state, 911, state->chip.d9.cfg.if_drives);
+
+	dib9000_set_power_mode(state, DIB9000_POWER_INTERFACE_ONLY);
+
+	return 0;
+}
+
+static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len)
+{
+	u16 mb[10];
+	u8 i, s;
+
+	if (address >= 1024 || !state->platform.risc.fw_is_running)
+		return -EINVAL;
+
+	/* dprintk( "APB access thru rd fw %d %x", address, attribute); */
+
+	mb[0] = (u16) address;
+	mb[1] = len / 2;
+	dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_R, mb, 2, attribute);
+	switch (dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute)) {
+	case 1:
+		s--;
+		for (i = 0; i < s; i++) {
+			b[i * 2] = (mb[i + 1] >> 8) & 0xff;
+			b[i * 2 + 1] = (mb[i + 1]) & 0xff;
+		}
+		return 0;
+	default:
+		return -EIO;
+	}
+	return -EIO;
+}
+
+static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len)
+{
+	u16 mb[10];
+	u8 s, i;
+
+	if (address >= 1024 || !state->platform.risc.fw_is_running)
+		return -EINVAL;
+
+	/* dprintk( "APB access thru wr fw %d %x", address, attribute); */
+
+	mb[0] = (unsigned short)address;
+	for (i = 0; i < len && i < 20; i += 2)
+		mb[1 + (i / 2)] = (b[i] << 8 | b[i + 1]);
+
+	dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_W, mb, 1 + len / 2, attribute);
+	return dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute) == 1 ? 0 : -EINVAL;
+}
+
+static int dib9000_fw_memmbx_sync(struct dib9000_state *state, u8 i)
+{
+	u8 index_loop = 10;
+
+	if (!state->platform.risc.fw_is_running)
+		return 0;
+	dib9000_risc_mem_write(state, FE_MM_RW_SYNC, &i);
+	do {
+		dib9000_risc_mem_read(state, FE_MM_RW_SYNC, state->i2c_read_buffer, 1);
+	} while (state->i2c_read_buffer[0] && index_loop--);
+
+	if (index_loop > 0)
+		return 0;
+	return -EIO;
+}
+
+static int dib9000_fw_init(struct dib9000_state *state)
+{
+	struct dibGPIOFunction *f;
+	u16 b[40] = { 0 };
+	u8 i;
+	u8 size;
+
+	if (dib9000_fw_boot(state, NULL, 0, state->chip.d9.cfg.microcode_B_fe_buffer, state->chip.d9.cfg.microcode_B_fe_size) != 0)
+		return -EIO;
+
+	/* initialize the firmware */
+	for (i = 0; i < ARRAY_SIZE(state->chip.d9.cfg.gpio_function); i++) {
+		f = &state->chip.d9.cfg.gpio_function[i];
+		if (f->mask) {
+			switch (f->function) {
+			case BOARD_GPIO_FUNCTION_COMPONENT_ON:
+				b[0] = (u16) f->mask;
+				b[1] = (u16) f->direction;
+				b[2] = (u16) f->value;
+				break;
+			case BOARD_GPIO_FUNCTION_COMPONENT_OFF:
+				b[3] = (u16) f->mask;
+				b[4] = (u16) f->direction;
+				b[5] = (u16) f->value;
+				break;
+			}
+		}
+	}
+	if (dib9000_mbx_send(state, OUT_MSG_CONF_GPIO, b, 15) != 0)
+		return -EIO;
+
+	/* subband */
+	b[0] = state->chip.d9.cfg.subband.size;	/* type == 0 -> GPIO - PWM not yet supported */
+	for (i = 0; i < state->chip.d9.cfg.subband.size; i++) {
+		b[1 + i * 4] = state->chip.d9.cfg.subband.subband[i].f_mhz;
+		b[2 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.mask;
+		b[3 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.direction;
+		b[4 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.value;
+	}
+	b[1 + i * 4] = 0;	/* fe_id */
+	if (dib9000_mbx_send(state, OUT_MSG_SUBBAND_SEL, b, 2 + 4 * i) != 0)
+		return -EIO;
+
+	/* 0 - id, 1 - no_of_frontends */
+	b[0] = (0 << 8) | 1;
+	/* 0 = i2c-address demod, 0 = tuner */
+	b[1] = (0 << 8) | (0);
+	b[2] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000) >> 16) & 0xffff);
+	b[3] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000)) & 0xffff);
+	b[4] = (u16) ((state->chip.d9.cfg.vcxo_timer >> 16) & 0xffff);
+	b[5] = (u16) ((state->chip.d9.cfg.vcxo_timer) & 0xffff);
+	b[6] = (u16) ((state->chip.d9.cfg.timing_frequency >> 16) & 0xffff);
+	b[7] = (u16) ((state->chip.d9.cfg.timing_frequency) & 0xffff);
+	b[29] = state->chip.d9.cfg.if_drives;
+	if (dib9000_mbx_send(state, OUT_MSG_INIT_DEMOD, b, ARRAY_SIZE(b)) != 0)
+		return -EIO;
+
+	if (dib9000_mbx_send(state, OUT_MSG_FE_FW_DL, NULL, 0) != 0)
+		return -EIO;
+
+	if (dib9000_mbx_get_message(state, IN_MSG_FE_FW_DL_DONE, b, &size) < 0)
+		return -EIO;
+
+	if (size > ARRAY_SIZE(b)) {
+		dprintk("error : firmware returned %dbytes needed but the used buffer has only %dbytes\n Firmware init ABORTED", size,
+			(int)ARRAY_SIZE(b));
+		return -EINVAL;
+	}
+
+	for (i = 0; i < size; i += 2) {
+		state->platform.risc.fe_mm[i / 2].addr = b[i + 0];
+		state->platform.risc.fe_mm[i / 2].size = b[i + 1];
+	}
+
+	return 0;
+}
+
+static void dib9000_fw_set_channel_head(struct dib9000_state *state)
+{
+	u8 b[9];
+	u32 freq = state->fe[0]->dtv_property_cache.frequency / 1000;
+	if (state->fe_id % 2)
+		freq += 101;
+
+	b[0] = (u8) ((freq >> 0) & 0xff);
+	b[1] = (u8) ((freq >> 8) & 0xff);
+	b[2] = (u8) ((freq >> 16) & 0xff);
+	b[3] = (u8) ((freq >> 24) & 0xff);
+	b[4] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 0) & 0xff);
+	b[5] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 8) & 0xff);
+	b[6] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 16) & 0xff);
+	b[7] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 24) & 0xff);
+	b[8] = 0x80;		/* do not wait for CELL ID when doing autosearch */
+	if (state->fe[0]->dtv_property_cache.delivery_system == SYS_DVBT)
+		b[8] |= 1;
+	dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_HEAD, b);
+}
+
+static int dib9000_fw_get_channel(struct dvb_frontend *fe)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	struct dibDVBTChannel {
+		s8 spectrum_inversion;
+
+		s8 nfft;
+		s8 guard;
+		s8 constellation;
+
+		s8 hrch;
+		s8 alpha;
+		s8 code_rate_hp;
+		s8 code_rate_lp;
+		s8 select_hp;
+
+		s8 intlv_native;
+	};
+	struct dibDVBTChannel *ch;
+	int ret = 0;
+
+	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
+	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+		ret = -EIO;
+		goto error;
+	}
+
+	dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION,
+			state->i2c_read_buffer, sizeof(struct dibDVBTChannel));
+	ch = (struct dibDVBTChannel *)state->i2c_read_buffer;
+
+
+	switch (ch->spectrum_inversion & 0x7) {
+	case 1:
+		state->fe[0]->dtv_property_cache.inversion = INVERSION_ON;
+		break;
+	case 0:
+		state->fe[0]->dtv_property_cache.inversion = INVERSION_OFF;
+		break;
+	default:
+	case -1:
+		state->fe[0]->dtv_property_cache.inversion = INVERSION_AUTO;
+		break;
+	}
+	switch (ch->nfft) {
+	case 0:
+		state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
+		break;
+	case 2:
+		state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_4K;
+		break;
+	case 1:
+		state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
+		break;
+	default:
+	case -1:
+		state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
+		break;
+	}
+	switch (ch->guard) {
+	case 0:
+		state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	default:
+	case -1:
+		state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
+		break;
+	}
+	switch (ch->constellation) {
+	case 2:
+		state->fe[0]->dtv_property_cache.modulation = QAM_64;
+		break;
+	case 1:
+		state->fe[0]->dtv_property_cache.modulation = QAM_16;
+		break;
+	case 0:
+		state->fe[0]->dtv_property_cache.modulation = QPSK;
+		break;
+	default:
+	case -1:
+		state->fe[0]->dtv_property_cache.modulation = QAM_AUTO;
+		break;
+	}
+	switch (ch->hrch) {
+	case 0:
+		state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_NONE;
+		break;
+	case 1:
+		state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_1;
+		break;
+	default:
+	case -1:
+		state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_AUTO;
+		break;
+	}
+	switch (ch->code_rate_hp) {
+	case 1:
+		state->fe[0]->dtv_property_cache.code_rate_HP = FEC_1_2;
+		break;
+	case 2:
+		state->fe[0]->dtv_property_cache.code_rate_HP = FEC_2_3;
+		break;
+	case 3:
+		state->fe[0]->dtv_property_cache.code_rate_HP = FEC_3_4;
+		break;
+	case 5:
+		state->fe[0]->dtv_property_cache.code_rate_HP = FEC_5_6;
+		break;
+	case 7:
+		state->fe[0]->dtv_property_cache.code_rate_HP = FEC_7_8;
+		break;
+	default:
+	case -1:
+		state->fe[0]->dtv_property_cache.code_rate_HP = FEC_AUTO;
+		break;
+	}
+	switch (ch->code_rate_lp) {
+	case 1:
+		state->fe[0]->dtv_property_cache.code_rate_LP = FEC_1_2;
+		break;
+	case 2:
+		state->fe[0]->dtv_property_cache.code_rate_LP = FEC_2_3;
+		break;
+	case 3:
+		state->fe[0]->dtv_property_cache.code_rate_LP = FEC_3_4;
+		break;
+	case 5:
+		state->fe[0]->dtv_property_cache.code_rate_LP = FEC_5_6;
+		break;
+	case 7:
+		state->fe[0]->dtv_property_cache.code_rate_LP = FEC_7_8;
+		break;
+	default:
+	case -1:
+		state->fe[0]->dtv_property_cache.code_rate_LP = FEC_AUTO;
+		break;
+	}
+
+error:
+	mutex_unlock(&state->platform.risc.mem_mbx_lock);
+	return ret;
+}
+
+static int dib9000_fw_set_channel_union(struct dvb_frontend *fe)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	struct dibDVBTChannel {
+		s8 spectrum_inversion;
+
+		s8 nfft;
+		s8 guard;
+		s8 constellation;
+
+		s8 hrch;
+		s8 alpha;
+		s8 code_rate_hp;
+		s8 code_rate_lp;
+		s8 select_hp;
+
+		s8 intlv_native;
+	};
+	struct dibDVBTChannel ch;
+
+	switch (state->fe[0]->dtv_property_cache.inversion) {
+	case INVERSION_ON:
+		ch.spectrum_inversion = 1;
+		break;
+	case INVERSION_OFF:
+		ch.spectrum_inversion = 0;
+		break;
+	default:
+	case INVERSION_AUTO:
+		ch.spectrum_inversion = -1;
+		break;
+	}
+	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
+	case TRANSMISSION_MODE_2K:
+		ch.nfft = 0;
+		break;
+	case TRANSMISSION_MODE_4K:
+		ch.nfft = 2;
+		break;
+	case TRANSMISSION_MODE_8K:
+		ch.nfft = 1;
+		break;
+	default:
+	case TRANSMISSION_MODE_AUTO:
+		ch.nfft = 1;
+		break;
+	}
+	switch (state->fe[0]->dtv_property_cache.guard_interval) {
+	case GUARD_INTERVAL_1_32:
+		ch.guard = 0;
+		break;
+	case GUARD_INTERVAL_1_16:
+		ch.guard = 1;
+		break;
+	case GUARD_INTERVAL_1_8:
+		ch.guard = 2;
+		break;
+	case GUARD_INTERVAL_1_4:
+		ch.guard = 3;
+		break;
+	default:
+	case GUARD_INTERVAL_AUTO:
+		ch.guard = -1;
+		break;
+	}
+	switch (state->fe[0]->dtv_property_cache.modulation) {
+	case QAM_64:
+		ch.constellation = 2;
+		break;
+	case QAM_16:
+		ch.constellation = 1;
+		break;
+	case QPSK:
+		ch.constellation = 0;
+		break;
+	default:
+	case QAM_AUTO:
+		ch.constellation = -1;
+		break;
+	}
+	switch (state->fe[0]->dtv_property_cache.hierarchy) {
+	case HIERARCHY_NONE:
+		ch.hrch = 0;
+		break;
+	case HIERARCHY_1:
+	case HIERARCHY_2:
+	case HIERARCHY_4:
+		ch.hrch = 1;
+		break;
+	default:
+	case HIERARCHY_AUTO:
+		ch.hrch = -1;
+		break;
+	}
+	ch.alpha = 1;
+	switch (state->fe[0]->dtv_property_cache.code_rate_HP) {
+	case FEC_1_2:
+		ch.code_rate_hp = 1;
+		break;
+	case FEC_2_3:
+		ch.code_rate_hp = 2;
+		break;
+	case FEC_3_4:
+		ch.code_rate_hp = 3;
+		break;
+	case FEC_5_6:
+		ch.code_rate_hp = 5;
+		break;
+	case FEC_7_8:
+		ch.code_rate_hp = 7;
+		break;
+	default:
+	case FEC_AUTO:
+		ch.code_rate_hp = -1;
+		break;
+	}
+	switch (state->fe[0]->dtv_property_cache.code_rate_LP) {
+	case FEC_1_2:
+		ch.code_rate_lp = 1;
+		break;
+	case FEC_2_3:
+		ch.code_rate_lp = 2;
+		break;
+	case FEC_3_4:
+		ch.code_rate_lp = 3;
+		break;
+	case FEC_5_6:
+		ch.code_rate_lp = 5;
+		break;
+	case FEC_7_8:
+		ch.code_rate_lp = 7;
+		break;
+	default:
+	case FEC_AUTO:
+		ch.code_rate_lp = -1;
+		break;
+	}
+	ch.select_hp = 1;
+	ch.intlv_native = 1;
+
+	dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_UNION, (u8 *) &ch);
+
+	return 0;
+}
+
+static int dib9000_fw_tune(struct dvb_frontend *fe)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	int ret = 10, search = state->channel_status.status == CHANNEL_STATUS_PARAMETERS_UNKNOWN;
+	s8 i;
+
+	switch (state->tune_state) {
+	case CT_DEMOD_START:
+		dib9000_fw_set_channel_head(state);
+
+		/* write the channel context - a channel is initialized to 0, so it is OK */
+		dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_CONTEXT, (u8 *) fe_info);
+		dib9000_risc_mem_write(state, FE_MM_W_FE_INFO, (u8 *) fe_info);
+
+		if (search)
+			dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_SEARCH, NULL, 0);
+		else {
+			dib9000_fw_set_channel_union(fe);
+			dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_TUNE, NULL, 0);
+		}
+		state->tune_state = CT_DEMOD_STEP_1;
+		break;
+	case CT_DEMOD_STEP_1:
+		if (search)
+			dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, state->i2c_read_buffer, 1);
+		else
+			dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, state->i2c_read_buffer, 1);
+		i = (s8)state->i2c_read_buffer[0];
+		switch (i) {	/* something happened */
+		case 0:
+			break;
+		case -2:	/* tps locks are "slower" than MPEG locks -> even in autosearch data is OK here */
+			if (search)
+				state->status = FE_STATUS_DEMOD_SUCCESS;
+			else {
+				state->tune_state = CT_DEMOD_STOP;
+				state->status = FE_STATUS_LOCKED;
+			}
+			break;
+		default:
+			state->status = FE_STATUS_TUNE_FAILED;
+			state->tune_state = CT_DEMOD_STOP;
+			break;
+		}
+		break;
+	default:
+		ret = FE_CALLBACK_TIME_NEVER;
+		break;
+	}
+
+	return ret;
+}
+
+static int dib9000_fw_set_diversity_in(struct dvb_frontend *fe, int onoff)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	u16 mode = (u16) onoff;
+	return dib9000_mbx_send(state, OUT_MSG_ENABLE_DIVERSITY, &mode, 1);
+}
+
+static int dib9000_fw_set_output_mode(struct dvb_frontend *fe, int mode)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	u16 outreg, smo_mode;
+
+	dprintk("setting output mode for demod %p to %d", fe, mode);
+
+	switch (mode) {
+	case OUTMODE_MPEG2_PAR_GATED_CLK:
+		outreg = (1 << 10);	/* 0x0400 */
+		break;
+	case OUTMODE_MPEG2_PAR_CONT_CLK:
+		outreg = (1 << 10) | (1 << 6);	/* 0x0440 */
+		break;
+	case OUTMODE_MPEG2_SERIAL:
+		outreg = (1 << 10) | (2 << 6) | (0 << 1);	/* 0x0482 */
+		break;
+	case OUTMODE_DIVERSITY:
+		outreg = (1 << 10) | (4 << 6);	/* 0x0500 */
+		break;
+	case OUTMODE_MPEG2_FIFO:
+		outreg = (1 << 10) | (5 << 6);
+		break;
+	case OUTMODE_HIGH_Z:
+		outreg = 0;
+		break;
+	default:
+		dprintk("Unhandled output_mode passed to be set for demod %p", &state->fe[0]);
+		return -EINVAL;
+	}
+
+	dib9000_write_word(state, 1795, outreg);
+
+	switch (mode) {
+	case OUTMODE_MPEG2_PAR_GATED_CLK:
+	case OUTMODE_MPEG2_PAR_CONT_CLK:
+	case OUTMODE_MPEG2_SERIAL:
+	case OUTMODE_MPEG2_FIFO:
+		smo_mode = (dib9000_read_word(state, 295) & 0x0010) | (1 << 1);
+		if (state->chip.d9.cfg.output_mpeg2_in_188_bytes)
+			smo_mode |= (1 << 5);
+		dib9000_write_word(state, 295, smo_mode);
+		break;
+	}
+
+	outreg = to_fw_output_mode(mode);
+	return dib9000_mbx_send(state, OUT_MSG_SET_OUTPUT_MODE, &outreg, 1);
+}
+
+static int dib9000_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+	struct dib9000_state *state = i2c_get_adapdata(i2c_adap);
+	u16 i, len, t, index_msg;
+
+	for (index_msg = 0; index_msg < num; index_msg++) {
+		if (msg[index_msg].flags & I2C_M_RD) {	/* read */
+			len = msg[index_msg].len;
+			if (len > 16)
+				len = 16;
+
+			if (dib9000_read_word(state, 790) != 0)
+				dprintk("TunerITF: read busy");
+
+			dib9000_write_word(state, 784, (u16) (msg[index_msg].addr));
+			dib9000_write_word(state, 787, (len / 2) - 1);
+			dib9000_write_word(state, 786, 1);	/* start read */
+
+			i = 1000;
+			while (dib9000_read_word(state, 790) != (len / 2) && i)
+				i--;
+
+			if (i == 0)
+				dprintk("TunerITF: read failed");
+
+			for (i = 0; i < len; i += 2) {
+				t = dib9000_read_word(state, 785);
+				msg[index_msg].buf[i] = (t >> 8) & 0xff;
+				msg[index_msg].buf[i + 1] = (t) & 0xff;
+			}
+			if (dib9000_read_word(state, 790) != 0)
+				dprintk("TunerITF: read more data than expected");
+		} else {
+			i = 1000;
+			while (dib9000_read_word(state, 789) && i)
+				i--;
+			if (i == 0)
+				dprintk("TunerITF: write busy");
+
+			len = msg[index_msg].len;
+			if (len > 16)
+				len = 16;
+
+			for (i = 0; i < len; i += 2)
+				dib9000_write_word(state, 785, (msg[index_msg].buf[i] << 8) | msg[index_msg].buf[i + 1]);
+			dib9000_write_word(state, 784, (u16) msg[index_msg].addr);
+			dib9000_write_word(state, 787, (len / 2) - 1);
+			dib9000_write_word(state, 786, 0);	/* start write */
+
+			i = 1000;
+			while (dib9000_read_word(state, 791) > 0 && i)
+				i--;
+			if (i == 0)
+				dprintk("TunerITF: write failed");
+		}
+	}
+	return num;
+}
+
+int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+
+	state->component_bus_speed = speed;
+	return 0;
+}
+EXPORT_SYMBOL(dib9000_fw_set_component_bus_speed);
+
+static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+	struct dib9000_state *state = i2c_get_adapdata(i2c_adap);
+	u8 type = 0;		/* I2C */
+	u8 port = DIBX000_I2C_INTERFACE_GPIO_3_4;
+	u16 scl = state->component_bus_speed;	/* SCL frequency */
+	struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[FE_MM_RW_COMPONENT_ACCESS_BUFFER];
+	u8 p[13] = { 0 };
+
+	p[0] = type;
+	p[1] = port;
+	p[2] = msg[0].addr << 1;
+
+	p[3] = (u8) scl & 0xff;	/* scl */
+	p[4] = (u8) (scl >> 8);
+
+	p[7] = 0;
+	p[8] = 0;
+
+	p[9] = (u8) (msg[0].len);
+	p[10] = (u8) (msg[0].len >> 8);
+	if ((num > 1) && (msg[1].flags & I2C_M_RD)) {
+		p[11] = (u8) (msg[1].len);
+		p[12] = (u8) (msg[1].len >> 8);
+	} else {
+		p[11] = 0;
+		p[12] = 0;
+	}
+
+	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
+		dprintk("could not get the lock");
+		return 0;
+	}
+
+	dib9000_risc_mem_write(state, FE_MM_W_COMPONENT_ACCESS, p);
+
+	{			/* write-part */
+		dib9000_risc_mem_setup_cmd(state, m->addr, msg[0].len, 0);
+		dib9000_risc_mem_write_chunks(state, msg[0].buf, msg[0].len);
+	}
+
+	/* do the transaction */
+	if (dib9000_fw_memmbx_sync(state, FE_SYNC_COMPONENT_ACCESS) < 0) {
+		mutex_unlock(&state->platform.risc.mem_mbx_lock);
+		return 0;
+	}
+
+	/* read back any possible result */
+	if ((num > 1) && (msg[1].flags & I2C_M_RD))
+		dib9000_risc_mem_read(state, FE_MM_RW_COMPONENT_ACCESS_BUFFER, msg[1].buf, msg[1].len);
+
+	mutex_unlock(&state->platform.risc.mem_mbx_lock);
+
+	return num;
+}
+
+static u32 dib9000_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dib9000_tuner_algo = {
+	.master_xfer = dib9000_tuner_xfer,
+	.functionality = dib9000_i2c_func,
+};
+
+static struct i2c_algorithm dib9000_component_bus_algo = {
+	.master_xfer = dib9000_fw_component_bus_xfer,
+	.functionality = dib9000_i2c_func,
+};
+
+struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe)
+{
+	struct dib9000_state *st = fe->demodulator_priv;
+	return &st->tuner_adap;
+}
+EXPORT_SYMBOL(dib9000_get_tuner_interface);
+
+struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe)
+{
+	struct dib9000_state *st = fe->demodulator_priv;
+	return &st->component_bus;
+}
+EXPORT_SYMBOL(dib9000_get_component_bus_interface);
+
+struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
+{
+	struct dib9000_state *st = fe->demodulator_priv;
+	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
+}
+EXPORT_SYMBOL(dib9000_get_i2c_master);
+
+int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c)
+{
+	struct dib9000_state *st = fe->demodulator_priv;
+
+	st->i2c.i2c_adap = i2c;
+	return 0;
+}
+EXPORT_SYMBOL(dib9000_set_i2c_adapter);
+
+static int dib9000_cfg_gpio(struct dib9000_state *st, u8 num, u8 dir, u8 val)
+{
+	st->gpio_dir = dib9000_read_word(st, 773);
+	st->gpio_dir &= ~(1 << num);	/* reset the direction bit */
+	st->gpio_dir |= (dir & 0x1) << num;	/* set the new direction */
+	dib9000_write_word(st, 773, st->gpio_dir);
+
+	st->gpio_val = dib9000_read_word(st, 774);
+	st->gpio_val &= ~(1 << num);	/* reset the direction bit */
+	st->gpio_val |= (val & 0x01) << num;	/* set the new value */
+	dib9000_write_word(st, 774, st->gpio_val);
+
+	dprintk("gpio dir: %04x: gpio val: %04x", st->gpio_dir, st->gpio_val);
+
+	return 0;
+}
+
+int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	return dib9000_cfg_gpio(state, num, dir, val);
+}
+EXPORT_SYMBOL(dib9000_set_gpio);
+
+int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	u16 val;
+	int ret;
+
+	if ((state->pid_ctrl_index != -2) && (state->pid_ctrl_index < 9)) {
+		/* postpone the pid filtering cmd */
+		dprintk("pid filter cmd postpone");
+		state->pid_ctrl_index++;
+		state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER_CTRL;
+		state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
+		return 0;
+	}
+
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
+
+	val = dib9000_read_word(state, 294 + 1) & 0xffef;
+	val |= (onoff & 0x1) << 4;
+
+	dprintk("PID filter enabled %d", onoff);
+	ret = dib9000_write_word(state, 294 + 1, val);
+	mutex_unlock(&state->demod_lock);
+	return ret;
+
+}
+EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl);
+
+int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	int ret;
+
+	if (state->pid_ctrl_index != -2) {
+		/* postpone the pid filtering cmd */
+		dprintk("pid filter postpone");
+		if (state->pid_ctrl_index < 9) {
+			state->pid_ctrl_index++;
+			state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER;
+			state->pid_ctrl[state->pid_ctrl_index].id = id;
+			state->pid_ctrl[state->pid_ctrl_index].pid = pid;
+			state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
+		} else
+			dprintk("can not add any more pid ctrl cmd");
+		return 0;
+	}
+
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
+	dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
+	ret = dib9000_write_word(state, 300 + 1 + id,
+			onoff ? (1 << 13) | pid : 0);
+	mutex_unlock(&state->demod_lock);
+	return ret;
+}
+EXPORT_SYMBOL(dib9000_fw_pid_filter);
+
+int dib9000_firmware_post_pll_init(struct dvb_frontend *fe)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	return dib9000_fw_init(state);
+}
+EXPORT_SYMBOL(dib9000_firmware_post_pll_init);
+
+static void dib9000_release(struct dvb_frontend *demod)
+{
+	struct dib9000_state *st = demod->demodulator_priv;
+	u8 index_frontend;
+
+	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
+		dvb_frontend_detach(st->fe[index_frontend]);
+
+	dibx000_exit_i2c_master(&st->i2c_master);
+
+	i2c_del_adapter(&st->tuner_adap);
+	i2c_del_adapter(&st->component_bus);
+	kfree(st->fe[0]);
+	kfree(st);
+}
+
+static int dib9000_wakeup(struct dvb_frontend *fe)
+{
+	return 0;
+}
+
+static int dib9000_sleep(struct dvb_frontend *fe)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	u8 index_frontend;
+	int ret = 0;
+
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
+	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+		ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
+		if (ret < 0)
+			goto error;
+	}
+	ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0);
+
+error:
+	mutex_unlock(&state->demod_lock);
+	return ret;
+}
+
+static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	return 0;
+}
+
+static int dib9000_get_frontend(struct dvb_frontend *fe)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	u8 index_frontend, sub_index_frontend;
+	fe_status_t stat;
+	int ret = 0;
+
+	if (state->get_frontend_internal == 0) {
+		if (mutex_lock_interruptible(&state->demod_lock) < 0) {
+			dprintk("could not get the lock");
+			return -EINTR;
+		}
+	}
+
+	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+		state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
+		if (stat & FE_HAS_SYNC) {
+			dprintk("TPS lock on the slave%i", index_frontend);
+
+			/* synchronize the cache with the other frontends */
+			state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]);
+			for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL);
+			     sub_index_frontend++) {
+				if (sub_index_frontend != index_frontend) {
+					state->fe[sub_index_frontend]->dtv_property_cache.modulation =
+					    state->fe[index_frontend]->dtv_property_cache.modulation;
+					state->fe[sub_index_frontend]->dtv_property_cache.inversion =
+					    state->fe[index_frontend]->dtv_property_cache.inversion;
+					state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode =
+					    state->fe[index_frontend]->dtv_property_cache.transmission_mode;
+					state->fe[sub_index_frontend]->dtv_property_cache.guard_interval =
+					    state->fe[index_frontend]->dtv_property_cache.guard_interval;
+					state->fe[sub_index_frontend]->dtv_property_cache.hierarchy =
+					    state->fe[index_frontend]->dtv_property_cache.hierarchy;
+					state->fe[sub_index_frontend]->dtv_property_cache.code_rate_HP =
+					    state->fe[index_frontend]->dtv_property_cache.code_rate_HP;
+					state->fe[sub_index_frontend]->dtv_property_cache.code_rate_LP =
+					    state->fe[index_frontend]->dtv_property_cache.code_rate_LP;
+					state->fe[sub_index_frontend]->dtv_property_cache.rolloff =
+					    state->fe[index_frontend]->dtv_property_cache.rolloff;
+				}
+			}
+			ret = 0;
+			goto return_value;
+		}
+	}
+
+	/* get the channel from master chip */
+	ret = dib9000_fw_get_channel(fe);
+	if (ret != 0)
+		goto return_value;
+
+	/* synchronize the cache with the other frontends */
+	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+		state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
+		state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
+		state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
+		state->fe[index_frontend]->dtv_property_cache.modulation = fe->dtv_property_cache.modulation;
+		state->fe[index_frontend]->dtv_property_cache.hierarchy = fe->dtv_property_cache.hierarchy;
+		state->fe[index_frontend]->dtv_property_cache.code_rate_HP = fe->dtv_property_cache.code_rate_HP;
+		state->fe[index_frontend]->dtv_property_cache.code_rate_LP = fe->dtv_property_cache.code_rate_LP;
+		state->fe[index_frontend]->dtv_property_cache.rolloff = fe->dtv_property_cache.rolloff;
+	}
+	ret = 0;
+
+return_value:
+	if (state->get_frontend_internal == 0)
+		mutex_unlock(&state->demod_lock);
+	return ret;
+}
+
+static int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	state->tune_state = tune_state;
+	if (tune_state == CT_DEMOD_START)
+		state->status = FE_STATUS_TUNE_PENDING;
+
+	return 0;
+}
+
+static u32 dib9000_get_status(struct dvb_frontend *fe)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	return state->status;
+}
+
+static int dib9000_set_channel_status(struct dvb_frontend *fe, struct dvb_frontend_parametersContext *channel_status)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+
+	memcpy(&state->channel_status, channel_status, sizeof(struct dvb_frontend_parametersContext));
+	return 0;
+}
+
+static int dib9000_set_frontend(struct dvb_frontend *fe)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	int sleep_time, sleep_time_slave;
+	u32 frontend_status;
+	u8 nbr_pending, exit_condition, index_frontend, index_frontend_success;
+	struct dvb_frontend_parametersContext channel_status;
+
+	/* check that the correct parameters are set */
+	if (state->fe[0]->dtv_property_cache.frequency == 0) {
+		dprintk("dib9000: must specify frequency ");
+		return 0;
+	}
+
+	if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) {
+		dprintk("dib9000: must specify bandwidth ");
+		return 0;
+	}
+
+	state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return 0;
+	}
+
+	fe->dtv_property_cache.delivery_system = SYS_DVBT;
+
+	/* set the master status */
+	if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO ||
+	    state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO ||
+	    state->fe[0]->dtv_property_cache.modulation == QAM_AUTO ||
+	    state->fe[0]->dtv_property_cache.code_rate_HP == FEC_AUTO) {
+		/* no channel specified, autosearch the channel */
+		state->channel_status.status = CHANNEL_STATUS_PARAMETERS_UNKNOWN;
+	} else
+		state->channel_status.status = CHANNEL_STATUS_PARAMETERS_SET;
+
+	/* set mode and status for the different frontends */
+	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+		dib9000_fw_set_diversity_in(state->fe[index_frontend], 1);
+
+		/* synchronization of the cache */
+		memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
+
+		state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_DVBT;
+		dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z);
+
+		dib9000_set_channel_status(state->fe[index_frontend], &state->channel_status);
+		dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
+	}
+
+	/* actual tune */
+	exit_condition = 0;	/* 0: tune pending; 1: tune failed; 2:tune success */
+	index_frontend_success = 0;
+	do {
+		sleep_time = dib9000_fw_tune(state->fe[0]);
+		for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+			sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]);
+			if (sleep_time == FE_CALLBACK_TIME_NEVER)
+				sleep_time = sleep_time_slave;
+			else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time))
+				sleep_time = sleep_time_slave;
+		}
+		if (sleep_time != FE_CALLBACK_TIME_NEVER)
+			msleep(sleep_time / 10);
+		else
+			break;
+
+		nbr_pending = 0;
+		exit_condition = 0;
+		index_frontend_success = 0;
+		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+			frontend_status = -dib9000_get_status(state->fe[index_frontend]);
+			if (frontend_status > -FE_STATUS_TUNE_PENDING) {
+				exit_condition = 2;	/* tune success */
+				index_frontend_success = index_frontend;
+				break;
+			}
+			if (frontend_status == -FE_STATUS_TUNE_PENDING)
+				nbr_pending++;	/* some frontends are still tuning */
+		}
+		if ((exit_condition != 2) && (nbr_pending == 0))
+			exit_condition = 1;	/* if all tune are done and no success, exit: tune failed */
+
+	} while (exit_condition == 0);
+
+	/* check the tune result */
+	if (exit_condition == 1) {	/* tune failed */
+		dprintk("tune failed");
+		mutex_unlock(&state->demod_lock);
+		/* tune failed; put all the pid filtering cmd to junk */
+		state->pid_ctrl_index = -1;
+		return 0;
+	}
+
+	dprintk("tune success on frontend%i", index_frontend_success);
+
+	/* synchronize all the channel cache */
+	state->get_frontend_internal = 1;
+	dib9000_get_frontend(state->fe[0]);
+	state->get_frontend_internal = 0;
+
+	/* retune the other frontends with the found channel */
+	channel_status.status = CHANNEL_STATUS_PARAMETERS_SET;
+	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+		/* only retune the frontends which was not tuned success */
+		if (index_frontend != index_frontend_success) {
+			dib9000_set_channel_status(state->fe[index_frontend], &channel_status);
+			dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
+		}
+	}
+	do {
+		sleep_time = FE_CALLBACK_TIME_NEVER;
+		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+			if (index_frontend != index_frontend_success) {
+				sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]);
+				if (sleep_time == FE_CALLBACK_TIME_NEVER)
+					sleep_time = sleep_time_slave;
+				else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time))
+					sleep_time = sleep_time_slave;
+			}
+		}
+		if (sleep_time != FE_CALLBACK_TIME_NEVER)
+			msleep(sleep_time / 10);
+		else
+			break;
+
+		nbr_pending = 0;
+		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+			if (index_frontend != index_frontend_success) {
+				frontend_status = -dib9000_get_status(state->fe[index_frontend]);
+				if ((index_frontend != index_frontend_success) && (frontend_status == -FE_STATUS_TUNE_PENDING))
+					nbr_pending++;	/* some frontends are still tuning */
+			}
+		}
+	} while (nbr_pending != 0);
+
+	/* set the output mode */
+	dib9000_fw_set_output_mode(state->fe[0], state->chip.d9.cfg.output_mode);
+	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+		dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY);
+
+	/* turn off the diversity for the last frontend */
+	dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0);
+
+	mutex_unlock(&state->demod_lock);
+	if (state->pid_ctrl_index >= 0) {
+		u8 index_pid_filter_cmd;
+		u8 pid_ctrl_index = state->pid_ctrl_index;
+
+		state->pid_ctrl_index = -2;
+		for (index_pid_filter_cmd = 0;
+				index_pid_filter_cmd <= pid_ctrl_index;
+				index_pid_filter_cmd++) {
+			if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER_CTRL)
+				dib9000_fw_pid_filter_ctrl(state->fe[0],
+						state->pid_ctrl[index_pid_filter_cmd].onoff);
+			else if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER)
+				dib9000_fw_pid_filter(state->fe[0],
+						state->pid_ctrl[index_pid_filter_cmd].id,
+						state->pid_ctrl[index_pid_filter_cmd].pid,
+						state->pid_ctrl[index_pid_filter_cmd].onoff);
+		}
+	}
+	/* do not postpone any more the pid filtering */
+	state->pid_ctrl_index = -2;
+
+	return 0;
+}
+
+static u16 dib9000_read_lock(struct dvb_frontend *fe)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+
+	return dib9000_read_word(state, 535);
+}
+
+static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	u8 index_frontend;
+	u16 lock = 0, lock_slave = 0;
+
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
+	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+		lock_slave |= dib9000_read_lock(state->fe[index_frontend]);
+
+	lock = dib9000_read_word(state, 535);
+
+	*stat = 0;
+
+	if ((lock & 0x8000) || (lock_slave & 0x8000))
+		*stat |= FE_HAS_SIGNAL;
+	if ((lock & 0x3000) || (lock_slave & 0x3000))
+		*stat |= FE_HAS_CARRIER;
+	if ((lock & 0x0100) || (lock_slave & 0x0100))
+		*stat |= FE_HAS_VITERBI;
+	if (((lock & 0x0038) == 0x38) || ((lock_slave & 0x0038) == 0x38))
+		*stat |= FE_HAS_SYNC;
+	if ((lock & 0x0008) || (lock_slave & 0x0008))
+		*stat |= FE_HAS_LOCK;
+
+	mutex_unlock(&state->demod_lock);
+
+	return 0;
+}
+
+static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	u16 *c;
+	int ret = 0;
+
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
+	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
+		dprintk("could not get the lock");
+		ret = -EINTR;
+		goto error;
+	}
+	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+		mutex_unlock(&state->platform.risc.mem_mbx_lock);
+		ret = -EIO;
+		goto error;
+	}
+	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR,
+			state->i2c_read_buffer, 16 * 2);
+	mutex_unlock(&state->platform.risc.mem_mbx_lock);
+
+	c = (u16 *)state->i2c_read_buffer;
+
+	*ber = c[10] << 16 | c[11];
+
+error:
+	mutex_unlock(&state->demod_lock);
+	return ret;
+}
+
+static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	u8 index_frontend;
+	u16 *c = (u16 *)state->i2c_read_buffer;
+	u16 val;
+	int ret = 0;
+
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
+	*strength = 0;
+	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+		state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
+		if (val > 65535 - *strength)
+			*strength = 65535;
+		else
+			*strength += val;
+	}
+
+	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
+		dprintk("could not get the lock");
+		ret = -EINTR;
+		goto error;
+	}
+	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+		mutex_unlock(&state->platform.risc.mem_mbx_lock);
+		ret = -EIO;
+		goto error;
+	}
+	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
+	mutex_unlock(&state->platform.risc.mem_mbx_lock);
+
+	val = 65535 - c[4];
+	if (val > 65535 - *strength)
+		*strength = 65535;
+	else
+		*strength += val;
+
+error:
+	mutex_unlock(&state->demod_lock);
+	return ret;
+}
+
+static u32 dib9000_get_snr(struct dvb_frontend *fe)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	u16 *c = (u16 *)state->i2c_read_buffer;
+	u32 n, s, exp;
+	u16 val;
+
+	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
+		dprintk("could not get the lock");
+		return 0;
+	}
+	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+		mutex_unlock(&state->platform.risc.mem_mbx_lock);
+		return 0;
+	}
+	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
+	mutex_unlock(&state->platform.risc.mem_mbx_lock);
+
+	val = c[7];
+	n = (val >> 4) & 0xff;
+	exp = ((val & 0xf) << 2);
+	val = c[8];
+	exp += ((val >> 14) & 0x3);
+	if ((exp & 0x20) != 0)
+		exp -= 0x40;
+	n <<= exp + 16;
+
+	s = (val >> 6) & 0xFF;
+	exp = (val & 0x3F);
+	if ((exp & 0x20) != 0)
+		exp -= 0x40;
+	s <<= exp + 16;
+
+	if (n > 0) {
+		u32 t = (s / n) << 16;
+		return t + ((s << 16) - n * t) / n;
+	}
+	return 0xffffffff;
+}
+
+static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	u8 index_frontend;
+	u32 snr_master;
+
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
+	snr_master = dib9000_get_snr(fe);
+	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+		snr_master += dib9000_get_snr(state->fe[index_frontend]);
+
+	if ((snr_master >> 16) != 0) {
+		snr_master = 10 * intlog10(snr_master >> 16);
+		*snr = snr_master / ((1 << 24) / 10);
+	} else
+		*snr = 0;
+
+	mutex_unlock(&state->demod_lock);
+
+	return 0;
+}
+
+static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	u16 *c = (u16 *)state->i2c_read_buffer;
+	int ret = 0;
+
+	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
+	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
+		dprintk("could not get the lock");
+		ret = -EINTR;
+		goto error;
+	}
+	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+		mutex_unlock(&state->platform.risc.mem_mbx_lock);
+		ret = -EIO;
+		goto error;
+	}
+	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
+	mutex_unlock(&state->platform.risc.mem_mbx_lock);
+
+	*unc = c[12];
+
+error:
+	mutex_unlock(&state->demod_lock);
+	return ret;
+}
+
+int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr)
+{
+	int k = 0, ret = 0;
+	u8 new_addr = 0;
+	struct i2c_device client = {.i2c_adap = i2c };
+
+	client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
+	if (!client.i2c_write_buffer) {
+		dprintk("%s: not enough memory", __func__);
+		return -ENOMEM;
+	}
+	client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
+	if (!client.i2c_read_buffer) {
+		dprintk("%s: not enough memory", __func__);
+		ret = -ENOMEM;
+		goto error_memory;
+	}
+
+	client.i2c_addr = default_addr + 16;
+	dib9000_i2c_write16(&client, 1796, 0x0);
+
+	for (k = no_of_demods - 1; k >= 0; k--) {
+		/* designated i2c address */
+		new_addr = first_addr + (k << 1);
+		client.i2c_addr = default_addr;
+
+		dib9000_i2c_write16(&client, 1817, 3);
+		dib9000_i2c_write16(&client, 1796, 0);
+		dib9000_i2c_write16(&client, 1227, 1);
+		dib9000_i2c_write16(&client, 1227, 0);
+
+		client.i2c_addr = new_addr;
+		dib9000_i2c_write16(&client, 1817, 3);
+		dib9000_i2c_write16(&client, 1796, 0);
+		dib9000_i2c_write16(&client, 1227, 1);
+		dib9000_i2c_write16(&client, 1227, 0);
+
+		if (dib9000_identify(&client) == 0) {
+			client.i2c_addr = default_addr;
+			if (dib9000_identify(&client) == 0) {
+				dprintk("DiB9000 #%d: not identified", k);
+				ret = -EIO;
+				goto error;
+			}
+		}
+
+		dib9000_i2c_write16(&client, 1795, (1 << 10) | (4 << 6));
+		dib9000_i2c_write16(&client, 1794, (new_addr << 2) | 2);
+
+		dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
+	}
+
+	for (k = 0; k < no_of_demods; k++) {
+		new_addr = first_addr | (k << 1);
+		client.i2c_addr = new_addr;
+
+		dib9000_i2c_write16(&client, 1794, (new_addr << 2));
+		dib9000_i2c_write16(&client, 1795, 0);
+	}
+
+error:
+	kfree(client.i2c_read_buffer);
+error_memory:
+	kfree(client.i2c_write_buffer);
+
+	return ret;
+}
+EXPORT_SYMBOL(dib9000_i2c_enumeration);
+
+int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	u8 index_frontend = 1;
+
+	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
+		index_frontend++;
+	if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
+		dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
+		state->fe[index_frontend] = fe_slave;
+		return 0;
+	}
+
+	dprintk("too many slave frontend");
+	return -ENOMEM;
+}
+EXPORT_SYMBOL(dib9000_set_slave_frontend);
+
+int dib9000_remove_slave_frontend(struct dvb_frontend *fe)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+	u8 index_frontend = 1;
+
+	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
+		index_frontend++;
+	if (index_frontend != 1) {
+		dprintk("remove slave fe %p (index %i)", state->fe[index_frontend - 1], index_frontend - 1);
+		state->fe[index_frontend] = NULL;
+		return 0;
+	}
+
+	dprintk("no frontend to be removed");
+	return -ENODEV;
+}
+EXPORT_SYMBOL(dib9000_remove_slave_frontend);
+
+struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
+{
+	struct dib9000_state *state = fe->demodulator_priv;
+
+	if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
+		return NULL;
+	return state->fe[slave_index];
+}
+EXPORT_SYMBOL(dib9000_get_slave_frontend);
+
+static struct dvb_frontend_ops dib9000_ops;
+struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg)
+{
+	struct dvb_frontend *fe;
+	struct dib9000_state *st;
+	st = kzalloc(sizeof(struct dib9000_state), GFP_KERNEL);
+	if (st == NULL)
+		return NULL;
+	fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
+	if (fe == NULL) {
+		kfree(st);
+		return NULL;
+	}
+
+	memcpy(&st->chip.d9.cfg, cfg, sizeof(struct dib9000_config));
+	st->i2c.i2c_adap = i2c_adap;
+	st->i2c.i2c_addr = i2c_addr;
+	st->i2c.i2c_write_buffer = st->i2c_write_buffer;
+	st->i2c.i2c_read_buffer = st->i2c_read_buffer;
+
+	st->gpio_dir = DIB9000_GPIO_DEFAULT_DIRECTIONS;
+	st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES;
+	st->gpio_pwm_pos = DIB9000_GPIO_DEFAULT_PWM_POS;
+
+	mutex_init(&st->platform.risc.mbx_if_lock);
+	mutex_init(&st->platform.risc.mbx_lock);
+	mutex_init(&st->platform.risc.mem_lock);
+	mutex_init(&st->platform.risc.mem_mbx_lock);
+	mutex_init(&st->demod_lock);
+	st->get_frontend_internal = 0;
+
+	st->pid_ctrl_index = -2;
+
+	st->fe[0] = fe;
+	fe->demodulator_priv = st;
+	memcpy(&st->fe[0]->ops, &dib9000_ops, sizeof(struct dvb_frontend_ops));
+
+	/* Ensure the output mode remains at the previous default if it's
+	 * not specifically set by the caller.
+	 */
+	if ((st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
+		st->chip.d9.cfg.output_mode = OUTMODE_MPEG2_FIFO;
+
+	if (dib9000_identify(&st->i2c) == 0)
+		goto error;
+
+	dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c.i2c_adap, st->i2c.i2c_addr);
+
+	st->tuner_adap.dev.parent = i2c_adap->dev.parent;
+	strncpy(st->tuner_adap.name, "DIB9000_FW TUNER ACCESS", sizeof(st->tuner_adap.name));
+	st->tuner_adap.algo = &dib9000_tuner_algo;
+	st->tuner_adap.algo_data = NULL;
+	i2c_set_adapdata(&st->tuner_adap, st);
+	if (i2c_add_adapter(&st->tuner_adap) < 0)
+		goto error;
+
+	st->component_bus.dev.parent = i2c_adap->dev.parent;
+	strncpy(st->component_bus.name, "DIB9000_FW COMPONENT BUS ACCESS", sizeof(st->component_bus.name));
+	st->component_bus.algo = &dib9000_component_bus_algo;
+	st->component_bus.algo_data = NULL;
+	st->component_bus_speed = 340;
+	i2c_set_adapdata(&st->component_bus, st);
+	if (i2c_add_adapter(&st->component_bus) < 0)
+		goto component_bus_add_error;
+
+	dib9000_fw_reset(fe);
+
+	return fe;
+
+component_bus_add_error:
+	i2c_del_adapter(&st->tuner_adap);
+error:
+	kfree(st);
+	return NULL;
+}
+EXPORT_SYMBOL(dib9000_attach);
+
+static struct dvb_frontend_ops dib9000_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		 .name = "DiBcom 9000",
+		 .frequency_min = 44250000,
+		 .frequency_max = 867250000,
+		 .frequency_stepsize = 62500,
+		 .caps = FE_CAN_INVERSION_AUTO |
+		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
+		 },
+
+	.release = dib9000_release,
+
+	.init = dib9000_wakeup,
+	.sleep = dib9000_sleep,
+
+	.set_frontend = dib9000_set_frontend,
+	.get_tune_settings = dib9000_fe_get_tune_settings,
+	.get_frontend = dib9000_get_frontend,
+
+	.read_status = dib9000_read_status,
+	.read_ber = dib9000_read_ber,
+	.read_signal_strength = dib9000_read_signal_strength,
+	.read_snr = dib9000_read_snr,
+	.read_ucblocks = dib9000_read_unc_blocks,
+};
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 9000 COFDM demodulator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/dib9000.h b/drivers/media/dvb-frontends/dib9000.h
new file mode 100644
index 0000000..b5781a4
--- /dev/null
+++ b/drivers/media/dvb-frontends/dib9000.h
@@ -0,0 +1,131 @@
+#ifndef DIB9000_H
+#define DIB9000_H
+
+#include "dibx000_common.h"
+
+struct dib9000_config {
+	u8 dvbt_mode;
+	u8 output_mpeg2_in_188_bytes;
+	u8 hostbus_diversity;
+	struct dibx000_bandwidth_config *bw;
+
+	u16 if_drives;
+
+	u32 timing_frequency;
+	u32 xtal_clock_khz;
+	u32 vcxo_timer;
+	u32 demod_clock_khz;
+
+	const u8 *microcode_B_fe_buffer;
+	u32 microcode_B_fe_size;
+
+	struct dibGPIOFunction gpio_function[2];
+	struct dibSubbandSelection subband;
+
+	u8 output_mode;
+};
+
+#define DEFAULT_DIB9000_I2C_ADDRESS 18
+
+#if defined(CONFIG_DVB_DIB9000) || (defined(CONFIG_DVB_DIB9000_MODULE) && defined(MODULE))
+extern struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg);
+extern int dib9000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr);
+extern struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe);
+extern struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating);
+extern int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val);
+extern int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff);
+extern int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff);
+extern int dib9000_firmware_post_pll_init(struct dvb_frontend *fe);
+extern int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave);
+extern int dib9000_remove_slave_frontend(struct dvb_frontend *fe);
+extern struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index);
+extern struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe);
+extern int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c);
+extern int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed);
+#else
+static inline struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib9000_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline int dib9000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib9000_firmware_post_pll_init(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+int dib9000_remove_slave_frontend(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb-frontends/dibx000_common.c b/drivers/media/dvb-frontends/dibx000_common.c
new file mode 100644
index 0000000..43be723
--- /dev/null
+++ b/drivers/media/dvb-frontends/dibx000_common.c
@@ -0,0 +1,515 @@
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+
+#include "dibx000_common.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); printk("\n"); } } while (0)
+
+static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
+{
+	int ret;
+
+	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+
+	mst->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+	mst->i2c_write_buffer[1] = reg & 0xff;
+	mst->i2c_write_buffer[2] = (val >> 8) & 0xff;
+	mst->i2c_write_buffer[3] = val & 0xff;
+
+	memset(mst->msg, 0, sizeof(struct i2c_msg));
+	mst->msg[0].addr = mst->i2c_addr;
+	mst->msg[0].flags = 0;
+	mst->msg[0].buf = mst->i2c_write_buffer;
+	mst->msg[0].len = 4;
+
+	ret = i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0;
+	mutex_unlock(&mst->i2c_buffer_lock);
+
+	return ret;
+}
+
+static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg)
+{
+	u16 ret;
+
+	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return 0;
+	}
+
+	mst->i2c_write_buffer[0] = reg >> 8;
+	mst->i2c_write_buffer[1] = reg & 0xff;
+
+	memset(mst->msg, 0, 2 * sizeof(struct i2c_msg));
+	mst->msg[0].addr = mst->i2c_addr;
+	mst->msg[0].flags = 0;
+	mst->msg[0].buf = mst->i2c_write_buffer;
+	mst->msg[0].len = 2;
+	mst->msg[1].addr = mst->i2c_addr;
+	mst->msg[1].flags = I2C_M_RD;
+	mst->msg[1].buf = mst->i2c_read_buffer;
+	mst->msg[1].len = 2;
+
+	if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2)
+		dprintk("i2c read error on %d", reg);
+
+	ret = (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1];
+	mutex_unlock(&mst->i2c_buffer_lock);
+
+	return ret;
+}
+
+static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst)
+{
+	int i = 100;
+	u16 status;
+
+	while (((status = dibx000_read_word(mst, mst->base_reg + 2)) & 0x0100) == 0 && --i > 0)
+		;
+
+	/* i2c timed out */
+	if (i == 0)
+		return -EREMOTEIO;
+
+	/* no acknowledge */
+	if ((status & 0x0080) == 0)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int dibx000_master_i2c_write(struct dibx000_i2c_master *mst, struct i2c_msg *msg, u8 stop)
+{
+	u16 data;
+	u16 da;
+	u16 i;
+	u16 txlen = msg->len, len;
+	const u8 *b = msg->buf;
+
+	while (txlen) {
+		dibx000_read_word(mst, mst->base_reg + 2);
+
+		len = txlen > 8 ? 8 : txlen;
+		for (i = 0; i < len; i += 2) {
+			data = *b++ << 8;
+			if (i+1 < len)
+				data |= *b++;
+			dibx000_write_word(mst, mst->base_reg, data);
+		}
+		da = (((u8) (msg->addr))  << 9) |
+			(1           << 8) |
+			(1           << 7) |
+			(0           << 6) |
+			(0           << 5) |
+			((len & 0x7) << 2) |
+			(0           << 1) |
+			(0           << 0);
+
+		if (txlen == msg->len)
+			da |= 1 << 5; /* start */
+
+		if (txlen-len == 0 && stop)
+			da |= 1 << 6; /* stop */
+
+		dibx000_write_word(mst, mst->base_reg+1, da);
+
+		if (dibx000_is_i2c_done(mst) != 0)
+			return -EREMOTEIO;
+		txlen -= len;
+	}
+
+	return 0;
+}
+
+static int dibx000_master_i2c_read(struct dibx000_i2c_master *mst, struct i2c_msg *msg)
+{
+	u16 da;
+	u8 *b = msg->buf;
+	u16 rxlen = msg->len, len;
+
+	while (rxlen) {
+		len = rxlen > 8 ? 8 : rxlen;
+		da = (((u8) (msg->addr)) << 9) |
+			(1           << 8) |
+			(1           << 7) |
+			(0           << 6) |
+			(0           << 5) |
+			((len & 0x7) << 2) |
+			(1           << 1) |
+			(0           << 0);
+
+		if (rxlen == msg->len)
+			da |= 1 << 5; /* start */
+
+		if (rxlen-len == 0)
+			da |= 1 << 6; /* stop */
+		dibx000_write_word(mst, mst->base_reg+1, da);
+
+		if (dibx000_is_i2c_done(mst) != 0)
+			return -EREMOTEIO;
+
+		rxlen -= len;
+
+		while (len) {
+			da = dibx000_read_word(mst, mst->base_reg);
+			*b++ = (da >> 8) & 0xff;
+			len--;
+			if (len >= 1) {
+				*b++ =  da   & 0xff;
+				len--;
+			}
+		}
+	}
+
+	return 0;
+}
+
+int dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed)
+{
+	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
+
+	if (mst->device_rev < DIB7000MC && speed < 235)
+		speed = 235;
+	return dibx000_write_word(mst, mst->base_reg + 3, (u16)(60000 / speed));
+
+}
+EXPORT_SYMBOL(dibx000_i2c_set_speed);
+
+static u32 dibx000_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst,
+					enum dibx000_i2c_interface intf)
+{
+	if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) {
+		dprintk("selecting interface: %d", intf);
+		mst->selected_interface = intf;
+		return dibx000_write_word(mst, mst->base_reg + 4, intf);
+	}
+	return 0;
+}
+
+static int dibx000_i2c_master_xfer_gpio12(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
+	int msg_index;
+	int ret = 0;
+
+	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_1_2);
+	for (msg_index = 0; msg_index < num; msg_index++) {
+		if (msg[msg_index].flags & I2C_M_RD) {
+			ret = dibx000_master_i2c_read(mst, &msg[msg_index]);
+			if (ret != 0)
+				return 0;
+		} else {
+			ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1);
+			if (ret != 0)
+				return 0;
+		}
+	}
+
+	return num;
+}
+
+static int dibx000_i2c_master_xfer_gpio34(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
+	int msg_index;
+	int ret = 0;
+
+	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_3_4);
+	for (msg_index = 0; msg_index < num; msg_index++) {
+		if (msg[msg_index].flags & I2C_M_RD) {
+			ret = dibx000_master_i2c_read(mst, &msg[msg_index]);
+			if (ret != 0)
+				return 0;
+		} else {
+			ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1);
+			if (ret != 0)
+				return 0;
+		}
+	}
+
+	return num;
+}
+
+static struct i2c_algorithm dibx000_i2c_master_gpio12_xfer_algo = {
+	.master_xfer = dibx000_i2c_master_xfer_gpio12,
+	.functionality = dibx000_i2c_func,
+};
+
+static struct i2c_algorithm dibx000_i2c_master_gpio34_xfer_algo = {
+	.master_xfer = dibx000_i2c_master_xfer_gpio34,
+	.functionality = dibx000_i2c_func,
+};
+
+static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4],
+				 u8 addr, int onoff)
+{
+	u16 val;
+
+
+	if (onoff)
+		val = addr << 8;	// bit 7 = use master or not, if 0, the gate is open
+	else
+		val = 1 << 7;
+
+	if (mst->device_rev > DIB7000)
+		val <<= 1;
+
+	tx[0] = (((mst->base_reg + 1) >> 8) & 0xff);
+	tx[1] = ((mst->base_reg + 1) & 0xff);
+	tx[2] = val >> 8;
+	tx[3] = val & 0xff;
+
+	return 0;
+}
+
+static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap,
+					struct i2c_msg msg[], int num)
+{
+	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
+	int ret;
+
+	if (num > 32) {
+		dprintk("%s: too much I2C message to be transmitted (%i).\
+				Maximum is 32", __func__, num);
+		return -ENOMEM;
+	}
+
+	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7);
+
+	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+
+	memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
+
+	/* open the gate */
+	dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
+	mst->msg[0].addr = mst->i2c_addr;
+	mst->msg[0].buf = &mst->i2c_write_buffer[0];
+	mst->msg[0].len = 4;
+
+	memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num);
+
+	/* close the gate */
+	dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0);
+	mst->msg[num + 1].addr = mst->i2c_addr;
+	mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
+	mst->msg[num + 1].len = 4;
+
+	ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ?
+			num : -EIO);
+
+	mutex_unlock(&mst->i2c_buffer_lock);
+	return ret;
+}
+
+static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = {
+	.master_xfer = dibx000_i2c_gated_gpio67_xfer,
+	.functionality = dibx000_i2c_func,
+};
+
+static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap,
+					struct i2c_msg msg[], int num)
+{
+	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
+	int ret;
+
+	if (num > 32) {
+		dprintk("%s: too much I2C message to be transmitted (%i).\
+				Maximum is 32", __func__, num);
+		return -ENOMEM;
+	}
+
+	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
+
+	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+	memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
+
+	/* open the gate */
+	dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
+	mst->msg[0].addr = mst->i2c_addr;
+	mst->msg[0].buf = &mst->i2c_write_buffer[0];
+	mst->msg[0].len = 4;
+
+	memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num);
+
+	/* close the gate */
+	dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0);
+	mst->msg[num + 1].addr = mst->i2c_addr;
+	mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
+	mst->msg[num + 1].len = 4;
+
+	ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ?
+			num : -EIO);
+	mutex_unlock(&mst->i2c_buffer_lock);
+	return ret;
+}
+
+static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
+	.master_xfer = dibx000_i2c_gated_tuner_xfer,
+	.functionality = dibx000_i2c_func,
+};
+
+struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst,
+						enum dibx000_i2c_interface intf,
+						int gating)
+{
+	struct i2c_adapter *i2c = NULL;
+
+	switch (intf) {
+	case DIBX000_I2C_INTERFACE_TUNER:
+		if (gating)
+			i2c = &mst->gated_tuner_i2c_adap;
+		break;
+	case DIBX000_I2C_INTERFACE_GPIO_1_2:
+		if (!gating)
+			i2c = &mst->master_i2c_adap_gpio12;
+		break;
+	case DIBX000_I2C_INTERFACE_GPIO_3_4:
+		if (!gating)
+			i2c = &mst->master_i2c_adap_gpio34;
+		break;
+	case DIBX000_I2C_INTERFACE_GPIO_6_7:
+		if (gating)
+			i2c = &mst->master_i2c_adap_gpio67;
+		break;
+	default:
+		printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n");
+		break;
+	}
+
+	return i2c;
+}
+
+EXPORT_SYMBOL(dibx000_get_i2c_adapter);
+
+void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst)
+{
+	/* initialize the i2c-master by closing the gate */
+	u8 tx[4];
+	struct i2c_msg m = {.addr = mst->i2c_addr,.buf = tx,.len = 4 };
+
+	dibx000_i2c_gate_ctrl(mst, tx, 0, 0);
+	i2c_transfer(mst->i2c_adap, &m, 1);
+	mst->selected_interface = 0xff;	// the first time force a select of the I2C
+	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
+}
+
+EXPORT_SYMBOL(dibx000_reset_i2c_master);
+
+static int i2c_adapter_init(struct i2c_adapter *i2c_adap,
+				struct i2c_algorithm *algo, const char *name,
+				struct dibx000_i2c_master *mst)
+{
+	strncpy(i2c_adap->name, name, sizeof(i2c_adap->name));
+	i2c_adap->algo = algo;
+	i2c_adap->algo_data = NULL;
+	i2c_set_adapdata(i2c_adap, mst);
+	if (i2c_add_adapter(i2c_adap) < 0)
+		return -ENODEV;
+	return 0;
+}
+
+int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev,
+				struct i2c_adapter *i2c_adap, u8 i2c_addr)
+{
+	int ret;
+
+	mutex_init(&mst->i2c_buffer_lock);
+	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
+		dprintk("could not acquire lock");
+		return -EINVAL;
+	}
+	memset(mst->msg, 0, sizeof(struct i2c_msg));
+	mst->msg[0].addr = i2c_addr >> 1;
+	mst->msg[0].flags = 0;
+	mst->msg[0].buf = mst->i2c_write_buffer;
+	mst->msg[0].len = 4;
+
+	mst->device_rev = device_rev;
+	mst->i2c_adap = i2c_adap;
+	mst->i2c_addr = i2c_addr >> 1;
+
+	if (device_rev == DIB7000P || device_rev == DIB8000)
+		mst->base_reg = 1024;
+	else
+		mst->base_reg = 768;
+
+	mst->gated_tuner_i2c_adap.dev.parent = mst->i2c_adap->dev.parent;
+	if (i2c_adapter_init
+			(&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo,
+			 "DiBX000 tuner I2C bus", mst) != 0)
+		printk(KERN_ERR
+				"DiBX000: could not initialize the tuner i2c_adapter\n");
+
+	mst->master_i2c_adap_gpio12.dev.parent = mst->i2c_adap->dev.parent;
+	if (i2c_adapter_init
+			(&mst->master_i2c_adap_gpio12, &dibx000_i2c_master_gpio12_xfer_algo,
+			 "DiBX000 master GPIO12 I2C bus", mst) != 0)
+		printk(KERN_ERR
+				"DiBX000: could not initialize the master i2c_adapter\n");
+
+	mst->master_i2c_adap_gpio34.dev.parent = mst->i2c_adap->dev.parent;
+	if (i2c_adapter_init
+			(&mst->master_i2c_adap_gpio34, &dibx000_i2c_master_gpio34_xfer_algo,
+			 "DiBX000 master GPIO34 I2C bus", mst) != 0)
+		printk(KERN_ERR
+				"DiBX000: could not initialize the master i2c_adapter\n");
+
+	mst->master_i2c_adap_gpio67.dev.parent = mst->i2c_adap->dev.parent;
+	if (i2c_adapter_init
+			(&mst->master_i2c_adap_gpio67, &dibx000_i2c_gated_gpio67_algo,
+			 "DiBX000 master GPIO67 I2C bus", mst) != 0)
+		printk(KERN_ERR
+				"DiBX000: could not initialize the master i2c_adapter\n");
+
+	/* initialize the i2c-master by closing the gate */
+	dibx000_i2c_gate_ctrl(mst, mst->i2c_write_buffer, 0, 0);
+
+	ret = (i2c_transfer(i2c_adap, mst->msg, 1) == 1);
+	mutex_unlock(&mst->i2c_buffer_lock);
+
+	return ret;
+}
+
+EXPORT_SYMBOL(dibx000_init_i2c_master);
+
+void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst)
+{
+	i2c_del_adapter(&mst->gated_tuner_i2c_adap);
+	i2c_del_adapter(&mst->master_i2c_adap_gpio12);
+	i2c_del_adapter(&mst->master_i2c_adap_gpio34);
+	i2c_del_adapter(&mst->master_i2c_adap_gpio67);
+}
+EXPORT_SYMBOL(dibx000_exit_i2c_master);
+
+
+u32 systime(void)
+{
+	struct timespec t;
+
+	t = current_kernel_time();
+	return (t.tv_sec * 10000) + (t.tv_nsec / 100000);
+}
+EXPORT_SYMBOL(systime);
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Common function the DiBcom demodulator family");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/dibx000_common.h b/drivers/media/dvb-frontends/dibx000_common.h
new file mode 100644
index 0000000..5f48488
--- /dev/null
+++ b/drivers/media/dvb-frontends/dibx000_common.h
@@ -0,0 +1,280 @@
+#ifndef DIBX000_COMMON_H
+#define DIBX000_COMMON_H
+
+enum dibx000_i2c_interface {
+	DIBX000_I2C_INTERFACE_TUNER = 0,
+	DIBX000_I2C_INTERFACE_GPIO_1_2 = 1,
+	DIBX000_I2C_INTERFACE_GPIO_3_4 = 2,
+	DIBX000_I2C_INTERFACE_GPIO_6_7 = 3
+};
+
+struct dibx000_i2c_master {
+#define DIB3000MC 1
+#define DIB7000   2
+#define DIB7000P  11
+#define DIB7000MC 12
+#define DIB8000   13
+	u16 device_rev;
+
+	enum dibx000_i2c_interface selected_interface;
+
+/*	struct i2c_adapter  tuner_i2c_adap; */
+	struct i2c_adapter gated_tuner_i2c_adap;
+	struct i2c_adapter master_i2c_adap_gpio12;
+	struct i2c_adapter master_i2c_adap_gpio34;
+	struct i2c_adapter master_i2c_adap_gpio67;
+
+	struct i2c_adapter *i2c_adap;
+	u8 i2c_addr;
+
+	u16 base_reg;
+
+	/* for the I2C transfer */
+	struct i2c_msg msg[34];
+	u8 i2c_write_buffer[8];
+	u8 i2c_read_buffer[2];
+	struct mutex i2c_buffer_lock;
+};
+
+extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst,
+					u16 device_rev, struct i2c_adapter *i2c_adap,
+					u8 i2c_addr);
+extern struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master
+							*mst,
+							enum dibx000_i2c_interface
+							intf, int gating);
+extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst);
+extern void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst);
+extern int dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed);
+
+extern u32 systime(void);
+
+#define BAND_LBAND 0x01
+#define BAND_UHF   0x02
+#define BAND_VHF   0x04
+#define BAND_SBAND 0x08
+#define BAND_FM	   0x10
+#define BAND_CBAND 0x20
+
+#define BAND_OF_FREQUENCY(freq_kHz) ((freq_kHz) <= 170000 ? BAND_CBAND : \
+									(freq_kHz) <= 115000 ? BAND_FM : \
+									(freq_kHz) <= 250000 ? BAND_VHF : \
+									(freq_kHz) <= 863000 ? BAND_UHF : \
+									(freq_kHz) <= 2000000 ? BAND_LBAND : BAND_SBAND )
+
+struct dibx000_agc_config {
+	/* defines the capabilities of this AGC-setting - using the BAND_-defines */
+	u8 band_caps;
+
+	u16 setup;
+
+	u16 inv_gain;
+	u16 time_stabiliz;
+
+	u8 alpha_level;
+	u16 thlock;
+
+	u8 wbd_inv;
+	u16 wbd_ref;
+	u8 wbd_sel;
+	u8 wbd_alpha;
+
+	u16 agc1_max;
+	u16 agc1_min;
+	u16 agc2_max;
+	u16 agc2_min;
+
+	u8 agc1_pt1;
+	u8 agc1_pt2;
+	u8 agc1_pt3;
+
+	u8 agc1_slope1;
+	u8 agc1_slope2;
+
+	u8 agc2_pt1;
+	u8 agc2_pt2;
+
+	u8 agc2_slope1;
+	u8 agc2_slope2;
+
+	u8 alpha_mant;
+	u8 alpha_exp;
+
+	u8 beta_mant;
+	u8 beta_exp;
+
+	u8 perform_agc_softsplit;
+
+	struct {
+		u16 min;
+		u16 max;
+		u16 min_thres;
+		u16 max_thres;
+	} split;
+};
+
+struct dibx000_bandwidth_config {
+	u32 internal;
+	u32 sampling;
+
+	u8 pll_prediv;
+	u8 pll_ratio;
+	u8 pll_range;
+	u8 pll_reset;
+	u8 pll_bypass;
+
+	u8 enable_refdiv;
+	u8 bypclk_div;
+	u8 IO_CLK_en_core;
+	u8 ADClkSrc;
+	u8 modulo;
+
+	u16 sad_cfg;
+
+	u32 ifreq;
+	u32 timf;
+
+	u32 xtal_hz;
+};
+
+enum dibx000_adc_states {
+	DIBX000_SLOW_ADC_ON = 0,
+	DIBX000_SLOW_ADC_OFF,
+	DIBX000_ADC_ON,
+	DIBX000_ADC_OFF,
+	DIBX000_VBG_ENABLE,
+	DIBX000_VBG_DISABLE,
+};
+
+#define BANDWIDTH_TO_KHZ(v)	((v) / 1000)
+#define BANDWIDTH_TO_HZ(v)	((v) * 1000)
+
+/* Chip output mode. */
+#define OUTMODE_HIGH_Z              0
+#define OUTMODE_MPEG2_PAR_GATED_CLK 1
+#define OUTMODE_MPEG2_PAR_CONT_CLK  2
+#define OUTMODE_MPEG2_SERIAL        7
+#define OUTMODE_DIVERSITY           4
+#define OUTMODE_MPEG2_FIFO          5
+#define OUTMODE_ANALOG_ADC          6
+
+#define INPUT_MODE_OFF                0x11
+#define INPUT_MODE_DIVERSITY          0x12
+#define INPUT_MODE_MPEG               0x13
+
+enum frontend_tune_state {
+	CT_TUNER_START = 10,
+	CT_TUNER_STEP_0,
+	CT_TUNER_STEP_1,
+	CT_TUNER_STEP_2,
+	CT_TUNER_STEP_3,
+	CT_TUNER_STEP_4,
+	CT_TUNER_STEP_5,
+	CT_TUNER_STEP_6,
+	CT_TUNER_STEP_7,
+	CT_TUNER_STOP,
+
+	CT_AGC_START = 20,
+	CT_AGC_STEP_0,
+	CT_AGC_STEP_1,
+	CT_AGC_STEP_2,
+	CT_AGC_STEP_3,
+	CT_AGC_STEP_4,
+	CT_AGC_STOP,
+
+	CT_DEMOD_START = 30,
+	CT_DEMOD_STEP_1,
+	CT_DEMOD_STEP_2,
+	CT_DEMOD_STEP_3,
+	CT_DEMOD_STEP_4,
+	CT_DEMOD_STEP_5,
+	CT_DEMOD_STEP_6,
+	CT_DEMOD_STEP_7,
+	CT_DEMOD_STEP_8,
+	CT_DEMOD_STEP_9,
+	CT_DEMOD_STEP_10,
+	CT_DEMOD_SEARCH_NEXT = 41,
+	CT_DEMOD_STEP_LOCKED,
+	CT_DEMOD_STOP,
+
+	CT_DONE = 100,
+	CT_SHUTDOWN,
+
+};
+
+struct dvb_frontend_parametersContext {
+#define CHANNEL_STATUS_PARAMETERS_UNKNOWN   0x01
+#define CHANNEL_STATUS_PARAMETERS_SET       0x02
+	u8 status;
+	u32 tune_time_estimation[2];
+	s32 tps_available;
+	u16 tps[9];
+};
+
+#define FE_STATUS_TUNE_FAILED          0
+#define FE_STATUS_TUNE_TIMED_OUT      -1
+#define FE_STATUS_TUNE_TIME_TOO_SHORT -2
+#define FE_STATUS_TUNE_PENDING        -3
+#define FE_STATUS_STD_SUCCESS         -4
+#define FE_STATUS_FFT_SUCCESS         -5
+#define FE_STATUS_DEMOD_SUCCESS       -6
+#define FE_STATUS_LOCKED              -7
+#define FE_STATUS_DATA_LOCKED         -8
+
+#define FE_CALLBACK_TIME_NEVER 0xffffffff
+
+#define ABS(x) ((x < 0) ? (-x) : (x))
+
+#define DATA_BUS_ACCESS_MODE_8BIT                 0x01
+#define DATA_BUS_ACCESS_MODE_16BIT                0x02
+#define DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT 0x10
+
+struct dibGPIOFunction {
+#define BOARD_GPIO_COMPONENT_BUS_ADAPTER 1
+#define BOARD_GPIO_COMPONENT_DEMOD       2
+	u8 component;
+
+#define BOARD_GPIO_FUNCTION_BOARD_ON      1
+#define BOARD_GPIO_FUNCTION_BOARD_OFF     2
+#define BOARD_GPIO_FUNCTION_COMPONENT_ON  3
+#define BOARD_GPIO_FUNCTION_COMPONENT_OFF 4
+#define BOARD_GPIO_FUNCTION_SUBBAND_PWM   5
+#define BOARD_GPIO_FUNCTION_SUBBAND_GPIO   6
+	u8 function;
+
+/* mask, direction and value are used specify which GPIO to change GPIO0
+ * is LSB and possible GPIO31 is MSB.  The same bit-position as in the
+ * mask is used for the direction and the value. Direction == 1 is OUT,
+ * 0 == IN. For direction "OUT" value is either 1 or 0, for direction IN
+ * value has no meaning.
+ *
+ * In case of BOARD_GPIO_FUNCTION_PWM mask is giving the GPIO to be
+ * used to do the PWM. Direction gives the PWModulator to be used.
+ * Value gives the PWM value in device-dependent scale.
+ */
+	u32 mask;
+	u32 direction;
+	u32 value;
+};
+
+#define MAX_NB_SUBBANDS   8
+struct dibSubbandSelection {
+	u8  size; /* Actual number of subbands. */
+	struct {
+		u16 f_mhz;
+		struct dibGPIOFunction gpio;
+	} subband[MAX_NB_SUBBANDS];
+};
+
+#define DEMOD_TIMF_SET    0x00
+#define DEMOD_TIMF_GET    0x01
+#define DEMOD_TIMF_UPDATE 0x02
+
+#define MPEG_ON_DIBTX		1
+#define DIV_ON_DIBTX		2
+#define ADC_ON_DIBTX		3
+#define DEMOUT_ON_HOSTBUS	4
+#define DIBTX_ON_HOSTBUS	5
+#define MPEG_ON_HOSTBUS		6
+
+#endif
diff --git a/drivers/media/dvb-frontends/drxd.h b/drivers/media/dvb-frontends/drxd.h
new file mode 100644
index 0000000..216c8c3
--- /dev/null
+++ b/drivers/media/dvb-frontends/drxd.h
@@ -0,0 +1,73 @@
+/*
+ * drxd.h: DRXD DVB-T demodulator driver
+ *
+ * Copyright (C) 2005-2007 Micronas
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _DRXD_H_
+#define _DRXD_H_
+
+#include <linux/types.h>
+#include <linux/i2c.h>
+
+struct drxd_config {
+	u8 index;
+
+	u8 pll_address;
+	u8 pll_type;
+#define DRXD_PLL_NONE     0
+#define DRXD_PLL_DTT7520X 1
+#define DRXD_PLL_MT3X0823 2
+
+	u32 clock;
+	u8 insert_rs_byte;
+
+	u8 demod_address;
+	u8 demoda_address;
+	u8 demod_revision;
+
+	/* If the tuner is not behind an i2c gate, be sure to flip this bit
+	   or else the i2c bus could get wedged */
+	u8 disable_i2c_gate_ctrl;
+
+	u32 IF;
+	 s16(*osc_deviation) (void *priv, s16 dev, int flag);
+};
+
+#if defined(CONFIG_DVB_DRXD) || \
+			(defined(CONFIG_DVB_DRXD_MODULE) && defined(MODULE))
+extern
+struct dvb_frontend *drxd_attach(const struct drxd_config *config,
+				 void *priv, struct i2c_adapter *i2c,
+				 struct device *dev);
+#else
+static inline
+struct dvb_frontend *drxd_attach(const struct drxd_config *config,
+				 void *priv, struct i2c_adapter *i2c,
+				 struct device *dev)
+{
+	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+	       __func__);
+	return NULL;
+}
+#endif
+
+extern int drxd_config_i2c(struct dvb_frontend *, int);
+#endif
diff --git a/drivers/media/dvb-frontends/drxd_firm.c b/drivers/media/dvb-frontends/drxd_firm.c
new file mode 100644
index 0000000..5418b0b
--- /dev/null
+++ b/drivers/media/dvb-frontends/drxd_firm.c
@@ -0,0 +1,929 @@
+/*
+ * drxd_firm.c : DRXD firmware tables
+ *
+ * Copyright (C) 2006-2007 Micronas
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+/* TODO: generate this file with a script from a settings file */
+
+/* Contains A2 firmware version: 1.4.2
+ * Contains B1 firmware version: 3.3.33
+ * Contains settings from driver 1.4.23
+*/
+
+#include "drxd_firm.h"
+
+#define ADDRESS(x)     ((x) & 0xFF), (((x)>>8) & 0xFF), (((x)>>16) & 0xFF), (((x)>>24) & 0xFF)
+#define LENGTH(x)      ((x) & 0xFF), (((x)>>8) & 0xFF)
+
+/* Is written via block write, must be little endian */
+#define DATA16(x)      ((x) & 0xFF), (((x)>>8) & 0xFF)
+
+#define WRBLOCK(a, l) ADDRESS(a), LENGTH(l)
+#define WR16(a, d) ADDRESS(a), LENGTH(1), DATA16(d)
+
+#define END_OF_TABLE      0xFF, 0xFF, 0xFF, 0xFF
+
+/* HI firmware patches */
+
+#define HI_TR_FUNC_ADDR HI_IF_RAM_USR_BEGIN__A
+#define HI_TR_FUNC_SIZE 9	/* size of this function in instruction words */
+
+u8 DRXD_InitAtomicRead[] = {
+	WRBLOCK(HI_TR_FUNC_ADDR, HI_TR_FUNC_SIZE),
+	0x26, 0x00,		/* 0         -> ring.rdy;           */
+	0x60, 0x04,		/* r0rami.dt -> ring.xba;           */
+	0x61, 0x04,		/* r0rami.dt -> ring.xad;           */
+	0xE3, 0x07,		/* HI_RA_RAM_USR_BEGIN -> ring.iad; */
+	0x40, 0x00,		/* (long immediate)                 */
+	0x64, 0x04,		/* r0rami.dt -> ring.len;           */
+	0x65, 0x04,		/* r0rami.dt -> ring.ctl;           */
+	0x26, 0x00,		/* 0         -> ring.rdy;           */
+	0x38, 0x00,		/* 0         -> jumps.ad;           */
+	END_OF_TABLE
+};
+
+/* Pins D0 and D1 of the parallel MPEG output can be used
+   to set the I2C address of a device. */
+
+#define HI_RST_FUNC_ADDR (HI_IF_RAM_USR_BEGIN__A + HI_TR_FUNC_SIZE)
+#define HI_RST_FUNC_SIZE 54	/* size of this function in instruction words */
+
+/* D0 Version */
+u8 DRXD_HiI2cPatch_1[] = {
+	WRBLOCK(HI_RST_FUNC_ADDR, HI_RST_FUNC_SIZE),
+	0xC8, 0x07, 0x01, 0x00,	/* MASK      -> reg0.dt;                        */
+	0xE0, 0x07, 0x15, 0x02,	/* (EC__BLK << 6) + EC_OC_REG__BNK -> ring.xba; */
+	0xE1, 0x07, 0x12, 0x00,	/* EC_OC_REG_OC_MPG_SIO__A -> ring.xad;         */
+	0xA2, 0x00,		/* M_BNK_ID_DAT -> ring.iba;                    */
+	0x23, 0x00,		/* &data     -> ring.iad;                       */
+	0x24, 0x00,		/* 0         -> ring.len;                       */
+	0xA5, 0x02,		/* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl;   */
+	0x26, 0x00,		/* 0         -> ring.rdy;                       */
+	0x42, 0x00,		/* &data+1   -> w0ram.ad;                       */
+	0xC0, 0x07, 0xFF, 0x0F,	/* -1        -> w0ram.dt;                       */
+	0x63, 0x00,		/* &data+1   -> ring.iad;                       */
+	0x65, 0x02,		/* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl;  */
+	0x26, 0x00,		/* 0         -> ring.rdy;                       */
+	0xE1, 0x07, 0x38, 0x00,	/* EC_OC_REG_OCR_MPG_USR_DAT__A -> ring.xad;    */
+	0xA5, 0x02,		/* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl;   */
+	0x26, 0x00,		/* 0         -> ring.rdy;                       */
+	0xE1, 0x07, 0x12, 0x00,	/* EC_OC_REG_OC_MPG_SIO__A -> ring.xad;         */
+	0x23, 0x00,		/* &data     -> ring.iad;                       */
+	0x65, 0x02,		/* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl;  */
+	0x26, 0x00,		/* 0         -> ring.rdy;                       */
+	0x42, 0x00,		/* &data+1   -> w0ram.ad;                       */
+	0x0F, 0x04,		/* r0ram.dt  -> and.op;                         */
+	0x1C, 0x06,		/* reg0.dt   -> and.tr;                         */
+	0xCF, 0x04,		/* and.rs    -> add.op;                         */
+	0xD0, 0x07, 0x70, 0x00,	/* DEF_DEV_ID -> add.tr;                        */
+	0xD0, 0x04,		/* add.rs    -> add.tr;                         */
+	0xC8, 0x04,		/* add.rs    -> reg0.dt;                        */
+	0x60, 0x00,		/* reg0.dt   -> w0ram.dt;                       */
+	0xC2, 0x07, 0x10, 0x00,	/* SLV0_BASE -> w0rami.ad;                      */
+	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
+	0x01, 0x06,		/* reg0.dt   -> w0rami.dt;                      */
+	0xC2, 0x07, 0x20, 0x00,	/* SLV1_BASE -> w0rami.ad;                      */
+	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
+	0x01, 0x06,		/* reg0.dt   -> w0rami.dt;                      */
+	0xC2, 0x07, 0x30, 0x00,	/* CMD_BASE  -> w0rami.ad;                      */
+	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
+	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
+	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
+	0x68, 0x00,		/* M_IC_SEL_PT1 -> i2c.sel;                     */
+	0x29, 0x00,		/* M_IC_CMD_RESET -> i2c.cmd;                   */
+	0x28, 0x00,		/* M_IC_SEL_PT0 -> i2c.sel;                     */
+	0x29, 0x00,		/* M_IC_CMD_RESET -> i2c.cmd;                   */
+	0xF8, 0x07, 0x2F, 0x00,	/* 0x2F      -> jumps.ad;                       */
+
+	WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 0) + 1)),
+	     (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+	WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 1) + 1)),
+	     (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+	WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 2) + 1)),
+	     (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+	WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 3) + 1)),
+	     (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+
+	/* Force quick and dirty reset */
+	WR16(B_HI_CT_REG_COMM_STATE__A, 0),
+	END_OF_TABLE
+};
+
+/* D0,D1 Version */
+u8 DRXD_HiI2cPatch_3[] = {
+	WRBLOCK(HI_RST_FUNC_ADDR, HI_RST_FUNC_SIZE),
+	0xC8, 0x07, 0x03, 0x00,	/* MASK      -> reg0.dt;                        */
+	0xE0, 0x07, 0x15, 0x02,	/* (EC__BLK << 6) + EC_OC_REG__BNK -> ring.xba; */
+	0xE1, 0x07, 0x12, 0x00,	/* EC_OC_REG_OC_MPG_SIO__A -> ring.xad;         */
+	0xA2, 0x00,		/* M_BNK_ID_DAT -> ring.iba;                    */
+	0x23, 0x00,		/* &data     -> ring.iad;                       */
+	0x24, 0x00,		/* 0         -> ring.len;                       */
+	0xA5, 0x02,		/* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl;   */
+	0x26, 0x00,		/* 0         -> ring.rdy;                       */
+	0x42, 0x00,		/* &data+1   -> w0ram.ad;                       */
+	0xC0, 0x07, 0xFF, 0x0F,	/* -1        -> w0ram.dt;                       */
+	0x63, 0x00,		/* &data+1   -> ring.iad;                       */
+	0x65, 0x02,		/* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl;  */
+	0x26, 0x00,		/* 0         -> ring.rdy;                       */
+	0xE1, 0x07, 0x38, 0x00,	/* EC_OC_REG_OCR_MPG_USR_DAT__A -> ring.xad;    */
+	0xA5, 0x02,		/* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl;   */
+	0x26, 0x00,		/* 0         -> ring.rdy;                       */
+	0xE1, 0x07, 0x12, 0x00,	/* EC_OC_REG_OC_MPG_SIO__A -> ring.xad;         */
+	0x23, 0x00,		/* &data     -> ring.iad;                       */
+	0x65, 0x02,		/* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl;  */
+	0x26, 0x00,		/* 0         -> ring.rdy;                       */
+	0x42, 0x00,		/* &data+1   -> w0ram.ad;                       */
+	0x0F, 0x04,		/* r0ram.dt  -> and.op;                         */
+	0x1C, 0x06,		/* reg0.dt   -> and.tr;                         */
+	0xCF, 0x04,		/* and.rs    -> add.op;                         */
+	0xD0, 0x07, 0x70, 0x00,	/* DEF_DEV_ID -> add.tr;                        */
+	0xD0, 0x04,		/* add.rs    -> add.tr;                         */
+	0xC8, 0x04,		/* add.rs    -> reg0.dt;                        */
+	0x60, 0x00,		/* reg0.dt   -> w0ram.dt;                       */
+	0xC2, 0x07, 0x10, 0x00,	/* SLV0_BASE -> w0rami.ad;                      */
+	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
+	0x01, 0x06,		/* reg0.dt   -> w0rami.dt;                      */
+	0xC2, 0x07, 0x20, 0x00,	/* SLV1_BASE -> w0rami.ad;                      */
+	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
+	0x01, 0x06,		/* reg0.dt   -> w0rami.dt;                      */
+	0xC2, 0x07, 0x30, 0x00,	/* CMD_BASE  -> w0rami.ad;                      */
+	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
+	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
+	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
+	0x68, 0x00,		/* M_IC_SEL_PT1 -> i2c.sel;                     */
+	0x29, 0x00,		/* M_IC_CMD_RESET -> i2c.cmd;                   */
+	0x28, 0x00,		/* M_IC_SEL_PT0 -> i2c.sel;                     */
+	0x29, 0x00,		/* M_IC_CMD_RESET -> i2c.cmd;                   */
+	0xF8, 0x07, 0x2F, 0x00,	/* 0x2F      -> jumps.ad;                       */
+
+	WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 0) + 1)),
+	     (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+	WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 1) + 1)),
+	     (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+	WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 2) + 1)),
+	     (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+	WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 3) + 1)),
+	     (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+
+	/* Force quick and dirty reset */
+	WR16(B_HI_CT_REG_COMM_STATE__A, 0),
+	END_OF_TABLE
+};
+
+u8 DRXD_ResetCEFR[] = {
+	WRBLOCK(CE_REG_FR_TREAL00__A, 57),
+	0x52, 0x00,		/* CE_REG_FR_TREAL00__A */
+	0x00, 0x00,		/* CE_REG_FR_TIMAG00__A */
+	0x52, 0x00,		/* CE_REG_FR_TREAL01__A */
+	0x00, 0x00,		/* CE_REG_FR_TIMAG01__A */
+	0x52, 0x00,		/* CE_REG_FR_TREAL02__A */
+	0x00, 0x00,		/* CE_REG_FR_TIMAG02__A */
+	0x52, 0x00,		/* CE_REG_FR_TREAL03__A */
+	0x00, 0x00,		/* CE_REG_FR_TIMAG03__A */
+	0x52, 0x00,		/* CE_REG_FR_TREAL04__A */
+	0x00, 0x00,		/* CE_REG_FR_TIMAG04__A */
+	0x52, 0x00,		/* CE_REG_FR_TREAL05__A */
+	0x00, 0x00,		/* CE_REG_FR_TIMAG05__A */
+	0x52, 0x00,		/* CE_REG_FR_TREAL06__A */
+	0x00, 0x00,		/* CE_REG_FR_TIMAG06__A */
+	0x52, 0x00,		/* CE_REG_FR_TREAL07__A */
+	0x00, 0x00,		/* CE_REG_FR_TIMAG07__A */
+	0x52, 0x00,		/* CE_REG_FR_TREAL08__A */
+	0x00, 0x00,		/* CE_REG_FR_TIMAG08__A */
+	0x52, 0x00,		/* CE_REG_FR_TREAL09__A */
+	0x00, 0x00,		/* CE_REG_FR_TIMAG09__A */
+	0x52, 0x00,		/* CE_REG_FR_TREAL10__A */
+	0x00, 0x00,		/* CE_REG_FR_TIMAG10__A */
+	0x52, 0x00,		/* CE_REG_FR_TREAL11__A */
+	0x00, 0x00,		/* CE_REG_FR_TIMAG11__A */
+
+	0x52, 0x00,		/* CE_REG_FR_MID_TAP__A */
+
+	0x0B, 0x00,		/* CE_REG_FR_SQS_G00__A */
+	0x0B, 0x00,		/* CE_REG_FR_SQS_G01__A */
+	0x0B, 0x00,		/* CE_REG_FR_SQS_G02__A */
+	0x0B, 0x00,		/* CE_REG_FR_SQS_G03__A */
+	0x0B, 0x00,		/* CE_REG_FR_SQS_G04__A */
+	0x0B, 0x00,		/* CE_REG_FR_SQS_G05__A */
+	0x0B, 0x00,		/* CE_REG_FR_SQS_G06__A */
+	0x0B, 0x00,		/* CE_REG_FR_SQS_G07__A */
+	0x0B, 0x00,		/* CE_REG_FR_SQS_G08__A */
+	0x0B, 0x00,		/* CE_REG_FR_SQS_G09__A */
+	0x0B, 0x00,		/* CE_REG_FR_SQS_G10__A */
+	0x0B, 0x00,		/* CE_REG_FR_SQS_G11__A */
+	0x0B, 0x00,		/* CE_REG_FR_SQS_G12__A */
+
+	0xFF, 0x01,		/* CE_REG_FR_RIO_G00__A */
+	0x90, 0x01,		/* CE_REG_FR_RIO_G01__A */
+	0x0B, 0x01,		/* CE_REG_FR_RIO_G02__A */
+	0xC8, 0x00,		/* CE_REG_FR_RIO_G03__A */
+	0xA0, 0x00,		/* CE_REG_FR_RIO_G04__A */
+	0x85, 0x00,		/* CE_REG_FR_RIO_G05__A */
+	0x72, 0x00,		/* CE_REG_FR_RIO_G06__A */
+	0x64, 0x00,		/* CE_REG_FR_RIO_G07__A */
+	0x59, 0x00,		/* CE_REG_FR_RIO_G08__A */
+	0x50, 0x00,		/* CE_REG_FR_RIO_G09__A */
+	0x49, 0x00,		/* CE_REG_FR_RIO_G10__A */
+
+	0x10, 0x00,		/* CE_REG_FR_MODE__A     */
+	0x78, 0x00,		/* CE_REG_FR_SQS_TRH__A  */
+	0x00, 0x00,		/* CE_REG_FR_RIO_GAIN__A */
+	0x00, 0x02,		/* CE_REG_FR_BYPASS__A   */
+	0x0D, 0x00,		/* CE_REG_FR_PM_SET__A   */
+	0x07, 0x00,		/* CE_REG_FR_ERR_SH__A   */
+	0x04, 0x00,		/* CE_REG_FR_MAN_SH__A   */
+	0x06, 0x00,		/* CE_REG_FR_TAP_SH__A   */
+
+	END_OF_TABLE
+};
+
+u8 DRXD_InitFEA2_1[] = {
+	WRBLOCK(FE_AD_REG_PD__A, 3),
+	0x00, 0x00,		/* FE_AD_REG_PD__A          */
+	0x01, 0x00,		/* FE_AD_REG_INVEXT__A      */
+	0x00, 0x00,		/* FE_AD_REG_CLKNEG__A      */
+
+	WRBLOCK(FE_AG_REG_DCE_AUR_CNT__A, 2),
+	0x10, 0x00,		/* FE_AG_REG_DCE_AUR_CNT__A */
+	0x10, 0x00,		/* FE_AG_REG_DCE_RUR_CNT__A */
+
+	WRBLOCK(FE_AG_REG_ACE_AUR_CNT__A, 2),
+	0x0E, 0x00,		/* FE_AG_REG_ACE_AUR_CNT__A */
+	0x00, 0x00,		/* FE_AG_REG_ACE_RUR_CNT__A */
+
+	WRBLOCK(FE_AG_REG_EGC_FLA_RGN__A, 5),
+	0x04, 0x00,		/* FE_AG_REG_EGC_FLA_RGN__A */
+	0x1F, 0x00,		/* FE_AG_REG_EGC_SLO_RGN__A */
+	0x00, 0x00,		/* FE_AG_REG_EGC_JMP_PSN__A */
+	0x00, 0x00,		/* FE_AG_REG_EGC_FLA_INC__A */
+	0x00, 0x00,		/* FE_AG_REG_EGC_FLA_DEC__A */
+
+	WRBLOCK(FE_AG_REG_GC1_AGC_MAX__A, 2),
+	0xFF, 0x01,		/* FE_AG_REG_GC1_AGC_MAX__A */
+	0x00, 0xFE,		/* FE_AG_REG_GC1_AGC_MIN__A */
+
+	WRBLOCK(FE_AG_REG_IND_WIN__A, 29),
+	0x00, 0x00,		/* FE_AG_REG_IND_WIN__A     */
+	0x05, 0x00,		/* FE_AG_REG_IND_THD_LOL__A */
+	0x0F, 0x00,		/* FE_AG_REG_IND_THD_HIL__A */
+	0x00, 0x00,		/* FE_AG_REG_IND_DEL__A     don't care */
+	0x1E, 0x00,		/* FE_AG_REG_IND_PD1_WRI__A */
+	0x0C, 0x00,		/* FE_AG_REG_PDA_AUR_CNT__A */
+	0x00, 0x00,		/* FE_AG_REG_PDA_RUR_CNT__A */
+	0x00, 0x00,		/* FE_AG_REG_PDA_AVE_DAT__A don't care  */
+	0x00, 0x00,		/* FE_AG_REG_PDC_RUR_CNT__A */
+	0x01, 0x00,		/* FE_AG_REG_PDC_SET_LVL__A */
+	0x02, 0x00,		/* FE_AG_REG_PDC_FLA_RGN__A */
+	0x00, 0x00,		/* FE_AG_REG_PDC_JMP_PSN__A don't care  */
+	0xFF, 0xFF,		/* FE_AG_REG_PDC_FLA_STP__A */
+	0xFF, 0xFF,		/* FE_AG_REG_PDC_SLO_STP__A */
+	0x00, 0x1F,		/* FE_AG_REG_PDC_PD2_WRI__A don't care  */
+	0x00, 0x00,		/* FE_AG_REG_PDC_MAP_DAT__A don't care  */
+	0x02, 0x00,		/* FE_AG_REG_PDC_MAX__A     */
+	0x0C, 0x00,		/* FE_AG_REG_TGA_AUR_CNT__A */
+	0x00, 0x00,		/* FE_AG_REG_TGA_RUR_CNT__A */
+	0x00, 0x00,		/* FE_AG_REG_TGA_AVE_DAT__A don't care  */
+	0x00, 0x00,		/* FE_AG_REG_TGC_RUR_CNT__A */
+	0x22, 0x00,		/* FE_AG_REG_TGC_SET_LVL__A */
+	0x15, 0x00,		/* FE_AG_REG_TGC_FLA_RGN__A */
+	0x00, 0x00,		/* FE_AG_REG_TGC_JMP_PSN__A don't care  */
+	0x01, 0x00,		/* FE_AG_REG_TGC_FLA_STP__A */
+	0x0A, 0x00,		/* FE_AG_REG_TGC_SLO_STP__A */
+	0x00, 0x00,		/* FE_AG_REG_TGC_MAP_DAT__A don't care  */
+	0x10, 0x00,		/* FE_AG_REG_FGA_AUR_CNT__A */
+	0x10, 0x00,		/* FE_AG_REG_FGA_RUR_CNT__A */
+
+	WRBLOCK(FE_AG_REG_BGC_FGC_WRI__A, 2),
+	0x00, 0x00,		/* FE_AG_REG_BGC_FGC_WRI__A */
+	0x00, 0x00,		/* FE_AG_REG_BGC_CGC_WRI__A */
+
+	WRBLOCK(FE_FD_REG_SCL__A, 3),
+	0x05, 0x00,		/* FE_FD_REG_SCL__A         */
+	0x03, 0x00,		/* FE_FD_REG_MAX_LEV__A     */
+	0x05, 0x00,		/* FE_FD_REG_NR__A          */
+
+	WRBLOCK(FE_CF_REG_SCL__A, 5),
+	0x16, 0x00,		/* FE_CF_REG_SCL__A         */
+	0x04, 0x00,		/* FE_CF_REG_MAX_LEV__A     */
+	0x06, 0x00,		/* FE_CF_REG_NR__A          */
+	0x00, 0x00,		/* FE_CF_REG_IMP_VAL__A     */
+	0x01, 0x00,		/* FE_CF_REG_MEAS_VAL__A    */
+
+	WRBLOCK(FE_CU_REG_FRM_CNT_RST__A, 2),
+	0x00, 0x08,		/* FE_CU_REG_FRM_CNT_RST__A */
+	0x00, 0x00,		/* FE_CU_REG_FRM_CNT_STR__A */
+
+	END_OF_TABLE
+};
+
+   /* with PGA */
+/*   WR16COND( DRXD_WITH_PGA, FE_AG_REG_AG_PGA_MODE__A   , 0x0004), */
+   /* without PGA */
+/*   WR16COND( DRXD_WITHOUT_PGA, FE_AG_REG_AG_PGA_MODE__A   , 0x0001), */
+/*   WR16(FE_AG_REG_AG_AGC_SIO__A,  (extAttr -> FeAgRegAgAgcSio), 0x0000 );*/
+/*   WR16(FE_AG_REG_AG_PWD__A        ,(extAttr -> FeAgRegAgPwd), 0x0000 );*/
+
+u8 DRXD_InitFEA2_2[] = {
+	WR16(FE_AG_REG_CDR_RUR_CNT__A, 0x0010),
+	WR16(FE_AG_REG_FGM_WRI__A, 48),
+	/* Activate measurement, activate scale */
+	WR16(FE_FD_REG_MEAS_VAL__A, 0x0001),
+
+	WR16(FE_CU_REG_COMM_EXEC__A, 0x0001),
+	WR16(FE_CF_REG_COMM_EXEC__A, 0x0001),
+	WR16(FE_IF_REG_COMM_EXEC__A, 0x0001),
+	WR16(FE_FD_REG_COMM_EXEC__A, 0x0001),
+	WR16(FE_FS_REG_COMM_EXEC__A, 0x0001),
+	WR16(FE_AD_REG_COMM_EXEC__A, 0x0001),
+	WR16(FE_AG_REG_COMM_EXEC__A, 0x0001),
+	WR16(FE_AG_REG_AG_MODE_LOP__A, 0x895E),
+
+	END_OF_TABLE
+};
+
+u8 DRXD_InitFEB1_1[] = {
+	WR16(B_FE_AD_REG_PD__A, 0x0000),
+	WR16(B_FE_AD_REG_CLKNEG__A, 0x0000),
+	WR16(B_FE_AG_REG_BGC_FGC_WRI__A, 0x0000),
+	WR16(B_FE_AG_REG_BGC_CGC_WRI__A, 0x0000),
+	WR16(B_FE_AG_REG_AG_MODE_LOP__A, 0x000a),
+	WR16(B_FE_AG_REG_IND_PD1_WRI__A, 35),
+	WR16(B_FE_AG_REG_IND_WIN__A, 0),
+	WR16(B_FE_AG_REG_IND_THD_LOL__A, 8),
+	WR16(B_FE_AG_REG_IND_THD_HIL__A, 8),
+	WR16(B_FE_CF_REG_IMP_VAL__A, 1),
+	WR16(B_FE_AG_REG_EGC_FLA_RGN__A, 7),
+	END_OF_TABLE
+};
+
+	/* with PGA */
+/*      WR16(B_FE_AG_REG_AG_PGA_MODE__A   , 0x0000, 0x0000); */
+       /* without PGA */
+/*      WR16(B_FE_AG_REG_AG_PGA_MODE__A   ,
+	     B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN, 0x0000);*/
+									     /*   WR16(B_FE_AG_REG_AG_AGC_SIO__A,(extAttr -> FeAgRegAgAgcSio), 0x0000 );*//*added HS 23-05-2005 */
+/*   WR16(B_FE_AG_REG_AG_PWD__A    ,(extAttr -> FeAgRegAgPwd), 0x0000 );*/
+
+u8 DRXD_InitFEB1_2[] = {
+	WR16(B_FE_COMM_EXEC__A, 0x0001),
+
+	/* RF-AGC setup */
+	WR16(B_FE_AG_REG_PDA_AUR_CNT__A, 0x0C),
+	WR16(B_FE_AG_REG_PDC_SET_LVL__A, 0x01),
+	WR16(B_FE_AG_REG_PDC_FLA_RGN__A, 0x02),
+	WR16(B_FE_AG_REG_PDC_FLA_STP__A, 0xFFFF),
+	WR16(B_FE_AG_REG_PDC_SLO_STP__A, 0xFFFF),
+	WR16(B_FE_AG_REG_PDC_MAX__A, 0x02),
+	WR16(B_FE_AG_REG_TGA_AUR_CNT__A, 0x0C),
+	WR16(B_FE_AG_REG_TGC_SET_LVL__A, 0x22),
+	WR16(B_FE_AG_REG_TGC_FLA_RGN__A, 0x15),
+	WR16(B_FE_AG_REG_TGC_FLA_STP__A, 0x01),
+	WR16(B_FE_AG_REG_TGC_SLO_STP__A, 0x0A),
+
+	WR16(B_FE_CU_REG_DIV_NFC_CLP__A, 0),
+	WR16(B_FE_CU_REG_CTR_NFC_OCR__A, 25000),
+	WR16(B_FE_CU_REG_CTR_NFC_ICR__A, 1),
+	END_OF_TABLE
+};
+
+u8 DRXD_InitCPA2[] = {
+	WRBLOCK(CP_REG_BR_SPL_OFFSET__A, 2),
+	0x07, 0x00,		/* CP_REG_BR_SPL_OFFSET__A  */
+	0x0A, 0x00,		/* CP_REG_BR_STR_DEL__A     */
+
+	WRBLOCK(CP_REG_RT_ANG_INC0__A, 4),
+	0x00, 0x00,		/* CP_REG_RT_ANG_INC0__A    */
+	0x00, 0x00,		/* CP_REG_RT_ANG_INC1__A    */
+	0x03, 0x00,		/* CP_REG_RT_DETECT_ENA__A  */
+	0x03, 0x00,		/* CP_REG_RT_DETECT_TRH__A  */
+
+	WRBLOCK(CP_REG_AC_NEXP_OFFS__A, 5),
+	0x32, 0x00,		/* CP_REG_AC_NEXP_OFFS__A   */
+	0x62, 0x00,		/* CP_REG_AC_AVER_POW__A    */
+	0x82, 0x00,		/* CP_REG_AC_MAX_POW__A     */
+	0x26, 0x00,		/* CP_REG_AC_WEIGHT_MAN__A  */
+	0x0F, 0x00,		/* CP_REG_AC_WEIGHT_EXP__A  */
+
+	WRBLOCK(CP_REG_AC_AMP_MODE__A, 2),
+	0x02, 0x00,		/* CP_REG_AC_AMP_MODE__A    */
+	0x01, 0x00,		/* CP_REG_AC_AMP_FIX__A     */
+
+	WR16(CP_REG_INTERVAL__A, 0x0005),
+	WR16(CP_REG_RT_EXP_MARG__A, 0x0004),
+	WR16(CP_REG_AC_ANG_MODE__A, 0x0003),
+
+	WR16(CP_REG_COMM_EXEC__A, 0x0001),
+	END_OF_TABLE
+};
+
+u8 DRXD_InitCPB1[] = {
+	WR16(B_CP_REG_BR_SPL_OFFSET__A, 0x0008),
+	WR16(B_CP_COMM_EXEC__A, 0x0001),
+	END_OF_TABLE
+};
+
+u8 DRXD_InitCEA2[] = {
+	WRBLOCK(CE_REG_AVG_POW__A, 4),
+	0x62, 0x00,		/* CE_REG_AVG_POW__A        */
+	0x78, 0x00,		/* CE_REG_MAX_POW__A        */
+	0x62, 0x00,		/* CE_REG_ATT__A            */
+	0x17, 0x00,		/* CE_REG_NRED__A           */
+
+	WRBLOCK(CE_REG_NE_ERR_SELECT__A, 2),
+	0x07, 0x00,		/* CE_REG_NE_ERR_SELECT__A  */
+	0xEB, 0xFF,		/* CE_REG_NE_TD_CAL__A      */
+
+	WRBLOCK(CE_REG_NE_MIXAVG__A, 2),
+	0x06, 0x00,		/* CE_REG_NE_MIXAVG__A      */
+	0x00, 0x00,		/* CE_REG_NE_NUPD_OFS__A    */
+
+	WRBLOCK(CE_REG_PE_NEXP_OFFS__A, 2),
+	0x00, 0x00,		/* CE_REG_PE_NEXP_OFFS__A   */
+	0x00, 0x00,		/* CE_REG_PE_TIMESHIFT__A   */
+
+	WRBLOCK(CE_REG_TP_A0_TAP_NEW__A, 3),
+	0x00, 0x01,		/* CE_REG_TP_A0_TAP_NEW__A       */
+	0x01, 0x00,		/* CE_REG_TP_A0_TAP_NEW_VALID__A */
+	0x0E, 0x00,		/* CE_REG_TP_A0_MU_LMS_STEP__A   */
+
+	WRBLOCK(CE_REG_TP_A1_TAP_NEW__A, 3),
+	0x00, 0x00,		/* CE_REG_TP_A1_TAP_NEW__A        */
+	0x01, 0x00,		/* CE_REG_TP_A1_TAP_NEW_VALID__A  */
+	0x0A, 0x00,		/* CE_REG_TP_A1_MU_LMS_STEP__A    */
+
+	WRBLOCK(CE_REG_FI_SHT_INCR__A, 2),
+	0x12, 0x00,		/* CE_REG_FI_SHT_INCR__A          */
+	0x0C, 0x00,		/* CE_REG_FI_EXP_NORM__A          */
+
+	WRBLOCK(CE_REG_IR_INPUTSEL__A, 3),
+	0x00, 0x00,		/* CE_REG_IR_INPUTSEL__A          */
+	0x00, 0x00,		/* CE_REG_IR_STARTPOS__A          */
+	0xFF, 0x00,		/* CE_REG_IR_NEXP_THRES__A        */
+
+	WR16(CE_REG_TI_NEXP_OFFS__A, 0x0000),
+
+	END_OF_TABLE
+};
+
+u8 DRXD_InitCEB1[] = {
+	WR16(B_CE_REG_TI_PHN_ENABLE__A, 0x0001),
+	WR16(B_CE_REG_FR_PM_SET__A, 0x000D),
+
+	END_OF_TABLE
+};
+
+u8 DRXD_InitEQA2[] = {
+	WRBLOCK(EQ_REG_OT_QNT_THRES0__A, 4),
+	0x1E, 0x00,		/* EQ_REG_OT_QNT_THRES0__A        */
+	0x1F, 0x00,		/* EQ_REG_OT_QNT_THRES1__A        */
+	0x06, 0x00,		/* EQ_REG_OT_CSI_STEP__A          */
+	0x02, 0x00,		/* EQ_REG_OT_CSI_OFFSET__A        */
+
+	WR16(EQ_REG_TD_REQ_SMB_CNT__A, 0x0200),
+	WR16(EQ_REG_IS_CLIP_EXP__A, 0x001F),
+	WR16(EQ_REG_SN_OFFSET__A, (u16) (-7)),
+	WR16(EQ_REG_RC_SEL_CAR__A, 0x0002),
+	WR16(EQ_REG_COMM_EXEC__A, 0x0001),
+	END_OF_TABLE
+};
+
+u8 DRXD_InitEQB1[] = {
+	WR16(B_EQ_REG_COMM_EXEC__A, 0x0001),
+	END_OF_TABLE
+};
+
+u8 DRXD_ResetECRAM[] = {
+	/* Reset packet sync bytes in EC_VD ram */
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000),
+
+	/* Reset packet sync bytes in EC_RS ram */
+	WR16(EC_RS_EC_RAM__A, 0x0000),
+	WR16(EC_RS_EC_RAM__A + 204, 0x0000),
+	END_OF_TABLE
+};
+
+u8 DRXD_InitECA2[] = {
+	WRBLOCK(EC_SB_REG_CSI_HI__A, 6),
+	0x1F, 0x00,		/* EC_SB_REG_CSI_HI__A            */
+	0x1E, 0x00,		/* EC_SB_REG_CSI_LO__A            */
+	0x01, 0x00,		/* EC_SB_REG_SMB_TGL__A           */
+	0x7F, 0x00,		/* EC_SB_REG_SNR_HI__A            */
+	0x7F, 0x00,		/* EC_SB_REG_SNR_MID__A           */
+	0x7F, 0x00,		/* EC_SB_REG_SNR_LO__A            */
+
+	WRBLOCK(EC_RS_REG_REQ_PCK_CNT__A, 2),
+	0x00, 0x10,		/* EC_RS_REG_REQ_PCK_CNT__A       */
+	DATA16(EC_RS_REG_VAL_PCK),	/* EC_RS_REG_VAL__A               */
+
+	WRBLOCK(EC_OC_REG_TMD_TOP_MODE__A, 5),
+	0x03, 0x00,		/* EC_OC_REG_TMD_TOP_MODE__A      */
+	0xF4, 0x01,		/* EC_OC_REG_TMD_TOP_CNT__A       */
+	0xC0, 0x03,		/* EC_OC_REG_TMD_HIL_MAR__A       */
+	0x40, 0x00,		/* EC_OC_REG_TMD_LOL_MAR__A       */
+	0x03, 0x00,		/* EC_OC_REG_TMD_CUR_CNT__A       */
+
+	WRBLOCK(EC_OC_REG_AVR_ASH_CNT__A, 2),
+	0x06, 0x00,		/* EC_OC_REG_AVR_ASH_CNT__A       */
+	0x02, 0x00,		/* EC_OC_REG_AVR_BSH_CNT__A       */
+
+	WRBLOCK(EC_OC_REG_RCN_MODE__A, 7),
+	0x07, 0x00,		/* EC_OC_REG_RCN_MODE__A          */
+	0x00, 0x00,		/* EC_OC_REG_RCN_CRA_LOP__A       */
+	0xc0, 0x00,		/* EC_OC_REG_RCN_CRA_HIP__A       */
+	0x00, 0x10,		/* EC_OC_REG_RCN_CST_LOP__A       */
+	0x00, 0x00,		/* EC_OC_REG_RCN_CST_HIP__A       */
+	0xFF, 0x01,		/* EC_OC_REG_RCN_SET_LVL__A       */
+	0x0D, 0x00,		/* EC_OC_REG_RCN_GAI_LVL__A       */
+
+	WRBLOCK(EC_OC_REG_RCN_CLP_LOP__A, 2),
+	0x00, 0x00,		/* EC_OC_REG_RCN_CLP_LOP__A       */
+	0xC0, 0x00,		/* EC_OC_REG_RCN_CLP_HIP__A       */
+
+	WR16(EC_SB_REG_CSI_OFS__A, 0x0001),
+	WR16(EC_VD_REG_FORCE__A, 0x0002),
+	WR16(EC_VD_REG_REQ_SMB_CNT__A, 0x0001),
+	WR16(EC_VD_REG_RLK_ENA__A, 0x0001),
+	WR16(EC_OD_REG_SYNC__A, 0x0664),
+	WR16(EC_OC_REG_OC_MON_SIO__A, 0x0000),
+	WR16(EC_OC_REG_SNC_ISC_LVL__A, 0x0D0C),
+	/* Output zero on monitorbus pads, power saving */
+	WR16(EC_OC_REG_OCR_MON_UOS__A,
+	     (EC_OC_REG_OCR_MON_UOS_DAT_0_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_1_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_2_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_3_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_4_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_5_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_6_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_7_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_8_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_9_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_VAL_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_CLK_ENABLE)),
+	WR16(EC_OC_REG_OCR_MON_WRI__A,
+	     EC_OC_REG_OCR_MON_WRI_INIT),
+
+/*   CHK_ERROR(ResetECRAM(demod)); */
+	/* Reset packet sync bytes in EC_VD ram */
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000),
+
+	/* Reset packet sync bytes in EC_RS ram */
+	WR16(EC_RS_EC_RAM__A, 0x0000),
+	WR16(EC_RS_EC_RAM__A + 204, 0x0000),
+
+	WR16(EC_SB_REG_COMM_EXEC__A, 0x0001),
+	WR16(EC_VD_REG_COMM_EXEC__A, 0x0001),
+	WR16(EC_OD_REG_COMM_EXEC__A, 0x0001),
+	WR16(EC_RS_REG_COMM_EXEC__A, 0x0001),
+	END_OF_TABLE
+};
+
+u8 DRXD_InitECB1[] = {
+	WR16(B_EC_SB_REG_CSI_OFS0__A, 0x0001),
+	WR16(B_EC_SB_REG_CSI_OFS1__A, 0x0001),
+	WR16(B_EC_SB_REG_CSI_OFS2__A, 0x0001),
+	WR16(B_EC_SB_REG_CSI_LO__A, 0x000c),
+	WR16(B_EC_SB_REG_CSI_HI__A, 0x0018),
+	WR16(B_EC_SB_REG_SNR_HI__A, 0x007f),
+	WR16(B_EC_SB_REG_SNR_MID__A, 0x007f),
+	WR16(B_EC_SB_REG_SNR_LO__A, 0x007f),
+
+	WR16(B_EC_OC_REG_DTO_CLKMODE__A, 0x0002),
+	WR16(B_EC_OC_REG_DTO_PER__A, 0x0006),
+	WR16(B_EC_OC_REG_DTO_BUR__A, 0x0001),
+	WR16(B_EC_OC_REG_RCR_CLKMODE__A, 0x0000),
+	WR16(B_EC_OC_REG_RCN_GAI_LVL__A, 0x000D),
+	WR16(B_EC_OC_REG_OC_MPG_SIO__A, 0x0000),
+
+	/* Needed because shadow registers do not have correct default value */
+	WR16(B_EC_OC_REG_RCN_CST_LOP__A, 0x1000),
+	WR16(B_EC_OC_REG_RCN_CST_HIP__A, 0x0000),
+	WR16(B_EC_OC_REG_RCN_CRA_LOP__A, 0x0000),
+	WR16(B_EC_OC_REG_RCN_CRA_HIP__A, 0x00C0),
+	WR16(B_EC_OC_REG_RCN_CLP_LOP__A, 0x0000),
+	WR16(B_EC_OC_REG_RCN_CLP_HIP__A, 0x00C0),
+	WR16(B_EC_OC_REG_DTO_INC_LOP__A, 0x0000),
+	WR16(B_EC_OC_REG_DTO_INC_HIP__A, 0x00C0),
+
+	WR16(B_EC_OD_REG_SYNC__A, 0x0664),
+	WR16(B_EC_RS_REG_REQ_PCK_CNT__A, 0x1000),
+
+/*   CHK_ERROR(ResetECRAM(demod)); */
+	/* Reset packet sync bytes in EC_VD ram */
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000),
+
+	/* Reset packet sync bytes in EC_RS ram */
+	WR16(EC_RS_EC_RAM__A, 0x0000),
+	WR16(EC_RS_EC_RAM__A + 204, 0x0000),
+
+	WR16(B_EC_SB_REG_COMM_EXEC__A, 0x0001),
+	WR16(B_EC_VD_REG_COMM_EXEC__A, 0x0001),
+	WR16(B_EC_OD_REG_COMM_EXEC__A, 0x0001),
+	WR16(B_EC_RS_REG_COMM_EXEC__A, 0x0001),
+	END_OF_TABLE
+};
+
+u8 DRXD_ResetECA2[] = {
+
+	WR16(EC_OC_REG_COMM_EXEC__A, 0x0000),
+	WR16(EC_OD_REG_COMM_EXEC__A, 0x0000),
+
+	WRBLOCK(EC_OC_REG_TMD_TOP_MODE__A, 5),
+	0x03, 0x00,		/* EC_OC_REG_TMD_TOP_MODE__A      */
+	0xF4, 0x01,		/* EC_OC_REG_TMD_TOP_CNT__A       */
+	0xC0, 0x03,		/* EC_OC_REG_TMD_HIL_MAR__A       */
+	0x40, 0x00,		/* EC_OC_REG_TMD_LOL_MAR__A       */
+	0x03, 0x00,		/* EC_OC_REG_TMD_CUR_CNT__A       */
+
+	WRBLOCK(EC_OC_REG_AVR_ASH_CNT__A, 2),
+	0x06, 0x00,		/* EC_OC_REG_AVR_ASH_CNT__A       */
+	0x02, 0x00,		/* EC_OC_REG_AVR_BSH_CNT__A       */
+
+	WRBLOCK(EC_OC_REG_RCN_MODE__A, 7),
+	0x07, 0x00,		/* EC_OC_REG_RCN_MODE__A          */
+	0x00, 0x00,		/* EC_OC_REG_RCN_CRA_LOP__A       */
+	0xc0, 0x00,		/* EC_OC_REG_RCN_CRA_HIP__A       */
+	0x00, 0x10,		/* EC_OC_REG_RCN_CST_LOP__A       */
+	0x00, 0x00,		/* EC_OC_REG_RCN_CST_HIP__A       */
+	0xFF, 0x01,		/* EC_OC_REG_RCN_SET_LVL__A       */
+	0x0D, 0x00,		/* EC_OC_REG_RCN_GAI_LVL__A       */
+
+	WRBLOCK(EC_OC_REG_RCN_CLP_LOP__A, 2),
+	0x00, 0x00,		/* EC_OC_REG_RCN_CLP_LOP__A       */
+	0xC0, 0x00,		/* EC_OC_REG_RCN_CLP_HIP__A       */
+
+	WR16(EC_OD_REG_SYNC__A, 0x0664),
+	WR16(EC_OC_REG_OC_MON_SIO__A, 0x0000),
+	WR16(EC_OC_REG_SNC_ISC_LVL__A, 0x0D0C),
+	/* Output zero on monitorbus pads, power saving */
+	WR16(EC_OC_REG_OCR_MON_UOS__A,
+	     (EC_OC_REG_OCR_MON_UOS_DAT_0_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_1_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_2_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_3_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_4_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_5_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_6_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_7_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_8_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_DAT_9_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_VAL_ENABLE |
+	      EC_OC_REG_OCR_MON_UOS_CLK_ENABLE)),
+	WR16(EC_OC_REG_OCR_MON_WRI__A,
+	     EC_OC_REG_OCR_MON_WRI_INIT),
+
+/*   CHK_ERROR(ResetECRAM(demod)); */
+	/* Reset packet sync bytes in EC_VD ram */
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000),
+	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000),
+
+	/* Reset packet sync bytes in EC_RS ram */
+	WR16(EC_RS_EC_RAM__A, 0x0000),
+	WR16(EC_RS_EC_RAM__A + 204, 0x0000),
+
+	WR16(EC_OD_REG_COMM_EXEC__A, 0x0001),
+	END_OF_TABLE
+};
+
+u8 DRXD_InitSC[] = {
+	WR16(SC_COMM_EXEC__A, 0),
+	WR16(SC_COMM_STATE__A, 0),
+
+#ifdef COMPILE_FOR_QT
+	WR16(SC_RA_RAM_BE_OPT_DELAY__A, 0x100),
+#endif
+
+	/* SC is not started, this is done in SetChannels() */
+	END_OF_TABLE
+};
+
+/* Diversity settings */
+
+u8 DRXD_InitDiversityFront[] = {
+	/* Start demod ********* RF in , diversity out **************************** */
+	WR16(B_SC_RA_RAM_CONFIG__A, B_SC_RA_RAM_CONFIG_FR_ENABLE__M |
+	     B_SC_RA_RAM_CONFIG_FREQSCAN__M),
+
+	WR16(B_SC_RA_RAM_LC_ABS_2K__A, 0x7),
+	WR16(B_SC_RA_RAM_LC_ABS_8K__A, 0x7),
+	WR16(B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A, IRLEN_COARSE_8K),
+	WR16(B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A, 1 << (11 - IRLEN_COARSE_8K)),
+	WR16(B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A, 1 << (17 - IRLEN_COARSE_8K)),
+	WR16(B_SC_RA_RAM_IR_FINE_8K_LENGTH__A, IRLEN_FINE_8K),
+	WR16(B_SC_RA_RAM_IR_FINE_8K_FREQINC__A, 1 << (11 - IRLEN_FINE_8K)),
+	WR16(B_SC_RA_RAM_IR_FINE_8K_KAISINC__A, 1 << (17 - IRLEN_FINE_8K)),
+
+	WR16(B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A, IRLEN_COARSE_2K),
+	WR16(B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A, 1 << (11 - IRLEN_COARSE_2K)),
+	WR16(B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A, 1 << (17 - IRLEN_COARSE_2K)),
+	WR16(B_SC_RA_RAM_IR_FINE_2K_LENGTH__A, IRLEN_FINE_2K),
+	WR16(B_SC_RA_RAM_IR_FINE_2K_FREQINC__A, 1 << (11 - IRLEN_FINE_2K)),
+	WR16(B_SC_RA_RAM_IR_FINE_2K_KAISINC__A, 1 << (17 - IRLEN_FINE_2K)),
+
+	WR16(B_LC_RA_RAM_FILTER_CRMM_A__A, 7),
+	WR16(B_LC_RA_RAM_FILTER_CRMM_B__A, 4),
+	WR16(B_LC_RA_RAM_FILTER_SRMM_A__A, 7),
+	WR16(B_LC_RA_RAM_FILTER_SRMM_B__A, 4),
+	WR16(B_LC_RA_RAM_FILTER_SYM_SET__A, 500),
+
+	WR16(B_CC_REG_DIVERSITY__A, 0x0001),
+	WR16(B_EC_OC_REG_OC_MODE_HIP__A, 0x0010),
+	WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_PASS_B_CE |
+	     B_EQ_REG_RC_SEL_CAR_LOCAL_B_CE | B_EQ_REG_RC_SEL_CAR_MEAS_B_CE),
+
+	/*    0x2a ), *//* CE to PASS mux */
+
+	END_OF_TABLE
+};
+
+u8 DRXD_InitDiversityEnd[] = {
+	/* End demod *********** combining RF in and diversity in, MPEG TS out **** */
+	/* disable near/far; switch on timing slave mode */
+	WR16(B_SC_RA_RAM_CONFIG__A, B_SC_RA_RAM_CONFIG_FR_ENABLE__M |
+	     B_SC_RA_RAM_CONFIG_FREQSCAN__M |
+	     B_SC_RA_RAM_CONFIG_DIV_ECHO_ENABLE__M |
+	     B_SC_RA_RAM_CONFIG_SLAVE__M |
+	     B_SC_RA_RAM_CONFIG_DIV_BLANK_ENABLE__M
+/* MV from CtrlDiversity */
+	    ),
+#ifdef DRXDDIV_SRMM_SLAVING
+	WR16(SC_RA_RAM_LC_ABS_2K__A, 0x3c7),
+	WR16(SC_RA_RAM_LC_ABS_8K__A, 0x3c7),
+#else
+	WR16(SC_RA_RAM_LC_ABS_2K__A, 0x7),
+	WR16(SC_RA_RAM_LC_ABS_8K__A, 0x7),
+#endif
+
+	WR16(B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A, IRLEN_COARSE_8K),
+	WR16(B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A, 1 << (11 - IRLEN_COARSE_8K)),
+	WR16(B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A, 1 << (17 - IRLEN_COARSE_8K)),
+	WR16(B_SC_RA_RAM_IR_FINE_8K_LENGTH__A, IRLEN_FINE_8K),
+	WR16(B_SC_RA_RAM_IR_FINE_8K_FREQINC__A, 1 << (11 - IRLEN_FINE_8K)),
+	WR16(B_SC_RA_RAM_IR_FINE_8K_KAISINC__A, 1 << (17 - IRLEN_FINE_8K)),
+
+	WR16(B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A, IRLEN_COARSE_2K),
+	WR16(B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A, 1 << (11 - IRLEN_COARSE_2K)),
+	WR16(B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A, 1 << (17 - IRLEN_COARSE_2K)),
+	WR16(B_SC_RA_RAM_IR_FINE_2K_LENGTH__A, IRLEN_FINE_2K),
+	WR16(B_SC_RA_RAM_IR_FINE_2K_FREQINC__A, 1 << (11 - IRLEN_FINE_2K)),
+	WR16(B_SC_RA_RAM_IR_FINE_2K_KAISINC__A, 1 << (17 - IRLEN_FINE_2K)),
+
+	WR16(B_LC_RA_RAM_FILTER_CRMM_A__A, 7),
+	WR16(B_LC_RA_RAM_FILTER_CRMM_B__A, 4),
+	WR16(B_LC_RA_RAM_FILTER_SRMM_A__A, 7),
+	WR16(B_LC_RA_RAM_FILTER_SRMM_B__A, 4),
+	WR16(B_LC_RA_RAM_FILTER_SYM_SET__A, 500),
+
+	WR16(B_CC_REG_DIVERSITY__A, 0x0001),
+	END_OF_TABLE
+};
+
+u8 DRXD_DisableDiversity[] = {
+	WR16(B_SC_RA_RAM_LC_ABS_2K__A, B_SC_RA_RAM_LC_ABS_2K__PRE),
+	WR16(B_SC_RA_RAM_LC_ABS_8K__A, B_SC_RA_RAM_LC_ABS_8K__PRE),
+	WR16(B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A,
+	     B_SC_RA_RAM_IR_COARSE_8K_LENGTH__PRE),
+	WR16(B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A,
+	     B_SC_RA_RAM_IR_COARSE_8K_FREQINC__PRE),
+	WR16(B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A,
+	     B_SC_RA_RAM_IR_COARSE_8K_KAISINC__PRE),
+	WR16(B_SC_RA_RAM_IR_FINE_8K_LENGTH__A,
+	     B_SC_RA_RAM_IR_FINE_8K_LENGTH__PRE),
+	WR16(B_SC_RA_RAM_IR_FINE_8K_FREQINC__A,
+	     B_SC_RA_RAM_IR_FINE_8K_FREQINC__PRE),
+	WR16(B_SC_RA_RAM_IR_FINE_8K_KAISINC__A,
+	     B_SC_RA_RAM_IR_FINE_8K_KAISINC__PRE),
+
+	WR16(B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A,
+	     B_SC_RA_RAM_IR_COARSE_2K_LENGTH__PRE),
+	WR16(B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A,
+	     B_SC_RA_RAM_IR_COARSE_2K_FREQINC__PRE),
+	WR16(B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A,
+	     B_SC_RA_RAM_IR_COARSE_2K_KAISINC__PRE),
+	WR16(B_SC_RA_RAM_IR_FINE_2K_LENGTH__A,
+	     B_SC_RA_RAM_IR_FINE_2K_LENGTH__PRE),
+	WR16(B_SC_RA_RAM_IR_FINE_2K_FREQINC__A,
+	     B_SC_RA_RAM_IR_FINE_2K_FREQINC__PRE),
+	WR16(B_SC_RA_RAM_IR_FINE_2K_KAISINC__A,
+	     B_SC_RA_RAM_IR_FINE_2K_KAISINC__PRE),
+
+	WR16(B_LC_RA_RAM_FILTER_CRMM_A__A, B_LC_RA_RAM_FILTER_CRMM_A__PRE),
+	WR16(B_LC_RA_RAM_FILTER_CRMM_B__A, B_LC_RA_RAM_FILTER_CRMM_B__PRE),
+	WR16(B_LC_RA_RAM_FILTER_SRMM_A__A, B_LC_RA_RAM_FILTER_SRMM_A__PRE),
+	WR16(B_LC_RA_RAM_FILTER_SRMM_B__A, B_LC_RA_RAM_FILTER_SRMM_B__PRE),
+	WR16(B_LC_RA_RAM_FILTER_SYM_SET__A, B_LC_RA_RAM_FILTER_SYM_SET__PRE),
+
+	WR16(B_CC_REG_DIVERSITY__A, 0x0000),
+	WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_INIT),	/* combining disabled */
+
+	END_OF_TABLE
+};
+
+u8 DRXD_StartDiversityFront[] = {
+	/* Start demod, RF in and diversity out, no combining */
+	WR16(B_FE_CF_REG_IMP_VAL__A, 0x0),
+	WR16(B_FE_AD_REG_FDB_IN__A, 0x0),
+	WR16(B_FE_AD_REG_INVEXT__A, 0x0),
+	WR16(B_EQ_REG_COMM_MB__A, 0x12),	/* EQ to MB out */
+	WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_PASS_B_CE |	/* CE to PASS mux */
+	     B_EQ_REG_RC_SEL_CAR_LOCAL_B_CE | B_EQ_REG_RC_SEL_CAR_MEAS_B_CE),
+
+	WR16(SC_RA_RAM_ECHO_SHIFT_LIM__A, 2),
+
+	END_OF_TABLE
+};
+
+u8 DRXD_StartDiversityEnd[] = {
+	/* End demod, combining RF in and diversity in, MPEG TS out */
+	WR16(B_FE_CF_REG_IMP_VAL__A, 0x0),	/* disable impulse noise cruncher */
+	WR16(B_FE_AD_REG_INVEXT__A, 0x0),	/* clock inversion (for sohard board) */
+	WR16(B_CP_REG_BR_STR_DEL__A, 10),	/* apperently no mb delay matching is best */
+
+	WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_DIV_ON |	/* org = 0x81 combining enabled */
+	     B_EQ_REG_RC_SEL_CAR_MEAS_A_CC |
+	     B_EQ_REG_RC_SEL_CAR_PASS_A_CC | B_EQ_REG_RC_SEL_CAR_LOCAL_A_CC),
+
+	END_OF_TABLE
+};
+
+u8 DRXD_DiversityDelay8MHZ[] = {
+	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_32__A, 1150 - 50),
+	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_16__A, 1100 - 50),
+	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_8__A, 1000 - 50),
+	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_4__A, 800 - 50),
+	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_32__A, 5420 - 50),
+	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_16__A, 5200 - 50),
+	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_8__A, 4800 - 50),
+	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_4__A, 4000 - 50),
+	END_OF_TABLE
+};
+
+u8 DRXD_DiversityDelay6MHZ[] =	/* also used ok for 7 MHz */
+{
+	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_32__A, 1100 - 50),
+	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_16__A, 1000 - 50),
+	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_8__A, 900 - 50),
+	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_4__A, 600 - 50),
+	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_32__A, 5300 - 50),
+	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_16__A, 5000 - 50),
+	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_8__A, 4500 - 50),
+	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_4__A, 3500 - 50),
+	END_OF_TABLE
+};
diff --git a/drivers/media/dvb-frontends/drxd_firm.h b/drivers/media/dvb-frontends/drxd_firm.h
new file mode 100644
index 0000000..41597e8
--- /dev/null
+++ b/drivers/media/dvb-frontends/drxd_firm.h
@@ -0,0 +1,115 @@
+/*
+ * drxd_firm.h
+ *
+ * Copyright (C) 2006-2007 Micronas
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _DRXD_FIRM_H_
+#define _DRXD_FIRM_H_
+
+#include <linux/types.h>
+#include "drxd_map_firm.h"
+
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 4
+#define VERSION_PATCH 23
+
+#define HI_TR_FUNC_ADDR HI_IF_RAM_USR_BEGIN__A
+
+#define DRXD_MAX_RETRIES (1000)
+#define HI_I2C_DELAY     84
+#define HI_I2C_BRIDGE_DELAY   750
+
+#define EQ_TD_TPS_PWR_UNKNOWN          0x00C0	/* Unknown configurations */
+#define EQ_TD_TPS_PWR_QPSK             0x016a
+#define EQ_TD_TPS_PWR_QAM16_ALPHAN     0x0195
+#define EQ_TD_TPS_PWR_QAM16_ALPHA1     0x0195
+#define EQ_TD_TPS_PWR_QAM16_ALPHA2     0x011E
+#define EQ_TD_TPS_PWR_QAM16_ALPHA4     0x01CE
+#define EQ_TD_TPS_PWR_QAM64_ALPHAN     0x019F
+#define EQ_TD_TPS_PWR_QAM64_ALPHA1     0x019F
+#define EQ_TD_TPS_PWR_QAM64_ALPHA2     0x00F8
+#define EQ_TD_TPS_PWR_QAM64_ALPHA4     0x014D
+
+#define DRXD_DEF_AG_PWD_CONSUMER 0x000E
+#define DRXD_DEF_AG_PWD_PRO 0x0000
+#define DRXD_DEF_AG_AGC_SIO 0x0000
+
+#define DRXD_FE_CTRL_MAX 1023
+
+#define DRXD_OSCDEV_DO_SCAN  (16)
+
+#define DRXD_OSCDEV_DONT_SCAN  (0)
+
+#define DRXD_OSCDEV_STEP  (275)
+
+#define DRXD_SCAN_TIMEOUT    (650)
+
+#define DRXD_BANDWIDTH_8MHZ_IN_HZ  (0x8B8249L)
+#define DRXD_BANDWIDTH_7MHZ_IN_HZ  (0x7A1200L)
+#define DRXD_BANDWIDTH_6MHZ_IN_HZ  (0x68A1B6L)
+
+#define IRLEN_COARSE_8K       (10)
+#define IRLEN_FINE_8K         (10)
+#define IRLEN_COARSE_2K       (7)
+#define IRLEN_FINE_2K         (9)
+#define DIFF_INVALID          (511)
+#define DIFF_TARGET           (4)
+#define DIFF_MARGIN           (1)
+
+extern u8 DRXD_InitAtomicRead[];
+extern u8 DRXD_HiI2cPatch_1[];
+extern u8 DRXD_HiI2cPatch_3[];
+
+extern u8 DRXD_InitSC[];
+
+extern u8 DRXD_ResetCEFR[];
+extern u8 DRXD_InitFEA2_1[];
+extern u8 DRXD_InitFEA2_2[];
+extern u8 DRXD_InitCPA2[];
+extern u8 DRXD_InitCEA2[];
+extern u8 DRXD_InitEQA2[];
+extern u8 DRXD_InitECA2[];
+extern u8 DRXD_ResetECA2[];
+extern u8 DRXD_ResetECRAM[];
+
+extern u8 DRXD_A2_microcode[];
+extern u32 DRXD_A2_microcode_length;
+
+extern u8 DRXD_InitFEB1_1[];
+extern u8 DRXD_InitFEB1_2[];
+extern u8 DRXD_InitCPB1[];
+extern u8 DRXD_InitCEB1[];
+extern u8 DRXD_InitEQB1[];
+extern u8 DRXD_InitECB1[];
+
+extern u8 DRXD_InitDiversityFront[];
+extern u8 DRXD_InitDiversityEnd[];
+extern u8 DRXD_DisableDiversity[];
+extern u8 DRXD_StartDiversityFront[];
+extern u8 DRXD_StartDiversityEnd[];
+
+extern u8 DRXD_DiversityDelay8MHZ[];
+extern u8 DRXD_DiversityDelay6MHZ[];
+
+extern u8 DRXD_B1_microcode[];
+extern u32 DRXD_B1_microcode_length;
+
+#endif
diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c
new file mode 100644
index 0000000..f380eb4
--- /dev/null
+++ b/drivers/media/dvb-frontends/drxd_hard.c
@@ -0,0 +1,2992 @@
+/*
+ * drxd_hard.c: DVB-T Demodulator Micronas DRX3975D-A2,DRX397xD-B1
+ *
+ * Copyright (C) 2003-2007 Micronas
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "drxd.h"
+#include "drxd_firm.h"
+
+#define DRX_FW_FILENAME_A2 "drxd-a2-1.1.fw"
+#define DRX_FW_FILENAME_B1 "drxd-b1-1.1.fw"
+
+#define CHUNK_SIZE 48
+
+#define DRX_I2C_RMW           0x10
+#define DRX_I2C_BROADCAST     0x20
+#define DRX_I2C_CLEARCRC      0x80
+#define DRX_I2C_SINGLE_MASTER 0xC0
+#define DRX_I2C_MODEFLAGS     0xC0
+#define DRX_I2C_FLAGS         0xF0
+
+#ifndef SIZEOF_ARRAY
+#define SIZEOF_ARRAY(array) (sizeof((array))/sizeof((array)[0]))
+#endif
+
+#define DEFAULT_LOCK_TIMEOUT    1100
+
+#define DRX_CHANNEL_AUTO 0
+#define DRX_CHANNEL_HIGH 1
+#define DRX_CHANNEL_LOW  2
+
+#define DRX_LOCK_MPEG  1
+#define DRX_LOCK_FEC   2
+#define DRX_LOCK_DEMOD 4
+
+/****************************************************************************/
+
+enum CSCDState {
+	CSCD_INIT = 0,
+	CSCD_SET,
+	CSCD_SAVED
+};
+
+enum CDrxdState {
+	DRXD_UNINITIALIZED = 0,
+	DRXD_STOPPED,
+	DRXD_STARTED
+};
+
+enum AGC_CTRL_MODE {
+	AGC_CTRL_AUTO = 0,
+	AGC_CTRL_USER,
+	AGC_CTRL_OFF
+};
+
+enum OperationMode {
+	OM_Default,
+	OM_DVBT_Diversity_Front,
+	OM_DVBT_Diversity_End
+};
+
+struct SCfgAgc {
+	enum AGC_CTRL_MODE ctrlMode;
+	u16 outputLevel;	/* range [0, ... , 1023], 1/n of fullscale range */
+	u16 settleLevel;	/* range [0, ... , 1023], 1/n of fullscale range */
+	u16 minOutputLevel;	/* range [0, ... , 1023], 1/n of fullscale range */
+	u16 maxOutputLevel;	/* range [0, ... , 1023], 1/n of fullscale range */
+	u16 speed;		/* range [0, ... , 1023], 1/n of fullscale range */
+
+	u16 R1;
+	u16 R2;
+	u16 R3;
+};
+
+struct SNoiseCal {
+	int cpOpt;
+	short cpNexpOfs;
+	short tdCal2k;
+	short tdCal8k;
+};
+
+enum app_env {
+	APPENV_STATIC = 0,
+	APPENV_PORTABLE = 1,
+	APPENV_MOBILE = 2
+};
+
+enum EIFFilter {
+	IFFILTER_SAW = 0,
+	IFFILTER_DISCRETE = 1
+};
+
+struct drxd_state {
+	struct dvb_frontend frontend;
+	struct dvb_frontend_ops ops;
+	struct dtv_frontend_properties props;
+
+	const struct firmware *fw;
+	struct device *dev;
+
+	struct i2c_adapter *i2c;
+	void *priv;
+	struct drxd_config config;
+
+	int i2c_access;
+	int init_done;
+	struct mutex mutex;
+
+	u8 chip_adr;
+	u16 hi_cfg_timing_div;
+	u16 hi_cfg_bridge_delay;
+	u16 hi_cfg_wakeup_key;
+	u16 hi_cfg_ctrl;
+
+	u16 intermediate_freq;
+	u16 osc_clock_freq;
+
+	enum CSCDState cscd_state;
+	enum CDrxdState drxd_state;
+
+	u16 sys_clock_freq;
+	s16 osc_clock_deviation;
+	u16 expected_sys_clock_freq;
+
+	u16 insert_rs_byte;
+	u16 enable_parallel;
+
+	int operation_mode;
+
+	struct SCfgAgc if_agc_cfg;
+	struct SCfgAgc rf_agc_cfg;
+
+	struct SNoiseCal noise_cal;
+
+	u32 fe_fs_add_incr;
+	u32 org_fe_fs_add_incr;
+	u16 current_fe_if_incr;
+
+	u16 m_FeAgRegAgPwd;
+	u16 m_FeAgRegAgAgcSio;
+
+	u16 m_EcOcRegOcModeLop;
+	u16 m_EcOcRegSncSncLvl;
+	u8 *m_InitAtomicRead;
+	u8 *m_HiI2cPatch;
+
+	u8 *m_ResetCEFR;
+	u8 *m_InitFE_1;
+	u8 *m_InitFE_2;
+	u8 *m_InitCP;
+	u8 *m_InitCE;
+	u8 *m_InitEQ;
+	u8 *m_InitSC;
+	u8 *m_InitEC;
+	u8 *m_ResetECRAM;
+	u8 *m_InitDiversityFront;
+	u8 *m_InitDiversityEnd;
+	u8 *m_DisableDiversity;
+	u8 *m_StartDiversityFront;
+	u8 *m_StartDiversityEnd;
+
+	u8 *m_DiversityDelay8MHZ;
+	u8 *m_DiversityDelay6MHZ;
+
+	u8 *microcode;
+	u32 microcode_length;
+
+	int type_A;
+	int PGA;
+	int diversity;
+	int tuner_mirrors;
+
+	enum app_env app_env_default;
+	enum app_env app_env_diversity;
+
+};
+
+/****************************************************************************/
+/* I2C **********************************************************************/
+/****************************************************************************/
+
+static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 * data, int len)
+{
+	struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len };
+
+	if (i2c_transfer(adap, &msg, 1) != 1)
+		return -1;
+	return 0;
+}
+
+static int i2c_read(struct i2c_adapter *adap,
+		    u8 adr, u8 *msg, int len, u8 *answ, int alen)
+{
+	struct i2c_msg msgs[2] = {
+		{
+			.addr = adr, .flags = 0,
+			.buf = msg, .len = len
+		}, {
+			.addr = adr, .flags = I2C_M_RD,
+			.buf = answ, .len = alen
+		}
+	};
+	if (i2c_transfer(adap, msgs, 2) != 2)
+		return -1;
+	return 0;
+}
+
+static inline u32 MulDiv32(u32 a, u32 b, u32 c)
+{
+	u64 tmp64;
+
+	tmp64 = (u64)a * (u64)b;
+	do_div(tmp64, c);
+
+	return (u32) tmp64;
+}
+
+static int Read16(struct drxd_state *state, u32 reg, u16 *data, u8 flags)
+{
+	u8 adr = state->config.demod_address;
+	u8 mm1[4] = { reg & 0xff, (reg >> 16) & 0xff,
+		flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff
+	};
+	u8 mm2[2];
+	if (i2c_read(state->i2c, adr, mm1, 4, mm2, 2) < 0)
+		return -1;
+	if (data)
+		*data = mm2[0] | (mm2[1] << 8);
+	return mm2[0] | (mm2[1] << 8);
+}
+
+static int Read32(struct drxd_state *state, u32 reg, u32 *data, u8 flags)
+{
+	u8 adr = state->config.demod_address;
+	u8 mm1[4] = { reg & 0xff, (reg >> 16) & 0xff,
+		flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff
+	};
+	u8 mm2[4];
+
+	if (i2c_read(state->i2c, adr, mm1, 4, mm2, 4) < 0)
+		return -1;
+	if (data)
+		*data =
+		    mm2[0] | (mm2[1] << 8) | (mm2[2] << 16) | (mm2[3] << 24);
+	return 0;
+}
+
+static int Write16(struct drxd_state *state, u32 reg, u16 data, u8 flags)
+{
+	u8 adr = state->config.demod_address;
+	u8 mm[6] = { reg & 0xff, (reg >> 16) & 0xff,
+		flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff,
+		data & 0xff, (data >> 8) & 0xff
+	};
+
+	if (i2c_write(state->i2c, adr, mm, 6) < 0)
+		return -1;
+	return 0;
+}
+
+static int Write32(struct drxd_state *state, u32 reg, u32 data, u8 flags)
+{
+	u8 adr = state->config.demod_address;
+	u8 mm[8] = { reg & 0xff, (reg >> 16) & 0xff,
+		flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff,
+		data & 0xff, (data >> 8) & 0xff,
+		(data >> 16) & 0xff, (data >> 24) & 0xff
+	};
+
+	if (i2c_write(state->i2c, adr, mm, 8) < 0)
+		return -1;
+	return 0;
+}
+
+static int write_chunk(struct drxd_state *state,
+		       u32 reg, u8 *data, u32 len, u8 flags)
+{
+	u8 adr = state->config.demod_address;
+	u8 mm[CHUNK_SIZE + 4] = { reg & 0xff, (reg >> 16) & 0xff,
+		flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff
+	};
+	int i;
+
+	for (i = 0; i < len; i++)
+		mm[4 + i] = data[i];
+	if (i2c_write(state->i2c, adr, mm, 4 + len) < 0) {
+		printk(KERN_ERR "error in write_chunk\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int WriteBlock(struct drxd_state *state,
+		      u32 Address, u16 BlockSize, u8 *pBlock, u8 Flags)
+{
+	while (BlockSize > 0) {
+		u16 Chunk = BlockSize > CHUNK_SIZE ? CHUNK_SIZE : BlockSize;
+
+		if (write_chunk(state, Address, pBlock, Chunk, Flags) < 0)
+			return -1;
+		pBlock += Chunk;
+		Address += (Chunk >> 1);
+		BlockSize -= Chunk;
+	}
+	return 0;
+}
+
+static int WriteTable(struct drxd_state *state, u8 * pTable)
+{
+	int status = 0;
+
+	if (pTable == NULL)
+		return 0;
+
+	while (!status) {
+		u16 Length;
+		u32 Address = pTable[0] | (pTable[1] << 8) |
+		    (pTable[2] << 16) | (pTable[3] << 24);
+
+		if (Address == 0xFFFFFFFF)
+			break;
+		pTable += sizeof(u32);
+
+		Length = pTable[0] | (pTable[1] << 8);
+		pTable += sizeof(u16);
+		if (!Length)
+			break;
+		status = WriteBlock(state, Address, Length * 2, pTable, 0);
+		pTable += (Length * 2);
+	}
+	return status;
+}
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static int ResetCEFR(struct drxd_state *state)
+{
+	return WriteTable(state, state->m_ResetCEFR);
+}
+
+static int InitCP(struct drxd_state *state)
+{
+	return WriteTable(state, state->m_InitCP);
+}
+
+static int InitCE(struct drxd_state *state)
+{
+	int status;
+	enum app_env AppEnv = state->app_env_default;
+
+	do {
+		status = WriteTable(state, state->m_InitCE);
+		if (status < 0)
+			break;
+
+		if (state->operation_mode == OM_DVBT_Diversity_Front ||
+		    state->operation_mode == OM_DVBT_Diversity_End) {
+			AppEnv = state->app_env_diversity;
+		}
+		if (AppEnv == APPENV_STATIC) {
+			status = Write16(state, CE_REG_TAPSET__A, 0x0000, 0);
+			if (status < 0)
+				break;
+		} else if (AppEnv == APPENV_PORTABLE) {
+			status = Write16(state, CE_REG_TAPSET__A, 0x0001, 0);
+			if (status < 0)
+				break;
+		} else if (AppEnv == APPENV_MOBILE && state->type_A) {
+			status = Write16(state, CE_REG_TAPSET__A, 0x0002, 0);
+			if (status < 0)
+				break;
+		} else if (AppEnv == APPENV_MOBILE && !state->type_A) {
+			status = Write16(state, CE_REG_TAPSET__A, 0x0006, 0);
+			if (status < 0)
+				break;
+		}
+
+		/* start ce */
+		status = Write16(state, B_CE_REG_COMM_EXEC__A, 0x0001, 0);
+		if (status < 0)
+			break;
+	} while (0);
+	return status;
+}
+
+static int StopOC(struct drxd_state *state)
+{
+	int status = 0;
+	u16 ocSyncLvl = 0;
+	u16 ocModeLop = state->m_EcOcRegOcModeLop;
+	u16 dtoIncLop = 0;
+	u16 dtoIncHip = 0;
+
+	do {
+		/* Store output configuration */
+		status = Read16(state, EC_OC_REG_SNC_ISC_LVL__A, &ocSyncLvl, 0);
+		if (status < 0)
+			break;
+		/* CHK_ERROR(Read16(EC_OC_REG_OC_MODE_LOP__A, &ocModeLop)); */
+		state->m_EcOcRegSncSncLvl = ocSyncLvl;
+		/* m_EcOcRegOcModeLop = ocModeLop; */
+
+		/* Flush FIFO (byte-boundary) at fixed rate */
+		status = Read16(state, EC_OC_REG_RCN_MAP_LOP__A, &dtoIncLop, 0);
+		if (status < 0)
+			break;
+		status = Read16(state, EC_OC_REG_RCN_MAP_HIP__A, &dtoIncHip, 0);
+		if (status < 0)
+			break;
+		status = Write16(state, EC_OC_REG_DTO_INC_LOP__A, dtoIncLop, 0);
+		if (status < 0)
+			break;
+		status = Write16(state, EC_OC_REG_DTO_INC_HIP__A, dtoIncHip, 0);
+		if (status < 0)
+			break;
+		ocModeLop &= ~(EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC__M);
+		ocModeLop |= EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC_STATIC;
+		status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, ocModeLop, 0);
+		if (status < 0)
+			break;
+		status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_HOLD, 0);
+		if (status < 0)
+			break;
+
+		msleep(1);
+		/* Output pins to '0' */
+		status = Write16(state, EC_OC_REG_OCR_MPG_UOS__A, EC_OC_REG_OCR_MPG_UOS__M, 0);
+		if (status < 0)
+			break;
+
+		/* Force the OC out of sync */
+		ocSyncLvl &= ~(EC_OC_REG_SNC_ISC_LVL_OSC__M);
+		status = Write16(state, EC_OC_REG_SNC_ISC_LVL__A, ocSyncLvl, 0);
+		if (status < 0)
+			break;
+		ocModeLop &= ~(EC_OC_REG_OC_MODE_LOP_PAR_ENA__M);
+		ocModeLop |= EC_OC_REG_OC_MODE_LOP_PAR_ENA_ENABLE;
+		ocModeLop |= 0x2;	/* Magically-out-of-sync */
+		status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, ocModeLop, 0);
+		if (status < 0)
+			break;
+		status = Write16(state, EC_OC_REG_COMM_INT_STA__A, 0x0, 0);
+		if (status < 0)
+			break;
+		status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_ACTIVE, 0);
+		if (status < 0)
+			break;
+	} while (0);
+
+	return status;
+}
+
+static int StartOC(struct drxd_state *state)
+{
+	int status = 0;
+
+	do {
+		/* Stop OC */
+		status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_HOLD, 0);
+		if (status < 0)
+			break;
+
+		/* Restore output configuration */
+		status = Write16(state, EC_OC_REG_SNC_ISC_LVL__A, state->m_EcOcRegSncSncLvl, 0);
+		if (status < 0)
+			break;
+		status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, state->m_EcOcRegOcModeLop, 0);
+		if (status < 0)
+			break;
+
+		/* Output pins active again */
+		status = Write16(state, EC_OC_REG_OCR_MPG_UOS__A, EC_OC_REG_OCR_MPG_UOS_INIT, 0);
+		if (status < 0)
+			break;
+
+		/* Start OC */
+		status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_ACTIVE, 0);
+		if (status < 0)
+			break;
+	} while (0);
+	return status;
+}
+
+static int InitEQ(struct drxd_state *state)
+{
+	return WriteTable(state, state->m_InitEQ);
+}
+
+static int InitEC(struct drxd_state *state)
+{
+	return WriteTable(state, state->m_InitEC);
+}
+
+static int InitSC(struct drxd_state *state)
+{
+	return WriteTable(state, state->m_InitSC);
+}
+
+static int InitAtomicRead(struct drxd_state *state)
+{
+	return WriteTable(state, state->m_InitAtomicRead);
+}
+
+static int CorrectSysClockDeviation(struct drxd_state *state);
+
+static int DRX_GetLockStatus(struct drxd_state *state, u32 * pLockStatus)
+{
+	u16 ScRaRamLock = 0;
+	const u16 mpeg_lock_mask = (SC_RA_RAM_LOCK_MPEG__M |
+				    SC_RA_RAM_LOCK_FEC__M |
+				    SC_RA_RAM_LOCK_DEMOD__M);
+	const u16 fec_lock_mask = (SC_RA_RAM_LOCK_FEC__M |
+				   SC_RA_RAM_LOCK_DEMOD__M);
+	const u16 demod_lock_mask = SC_RA_RAM_LOCK_DEMOD__M;
+
+	int status;
+
+	*pLockStatus = 0;
+
+	status = Read16(state, SC_RA_RAM_LOCK__A, &ScRaRamLock, 0x0000);
+	if (status < 0) {
+		printk(KERN_ERR "Can't read SC_RA_RAM_LOCK__A status = %08x\n", status);
+		return status;
+	}
+
+	if (state->drxd_state != DRXD_STARTED)
+		return 0;
+
+	if ((ScRaRamLock & mpeg_lock_mask) == mpeg_lock_mask) {
+		*pLockStatus |= DRX_LOCK_MPEG;
+		CorrectSysClockDeviation(state);
+	}
+
+	if ((ScRaRamLock & fec_lock_mask) == fec_lock_mask)
+		*pLockStatus |= DRX_LOCK_FEC;
+
+	if ((ScRaRamLock & demod_lock_mask) == demod_lock_mask)
+		*pLockStatus |= DRX_LOCK_DEMOD;
+	return 0;
+}
+
+/****************************************************************************/
+
+static int SetCfgIfAgc(struct drxd_state *state, struct SCfgAgc *cfg)
+{
+	int status;
+
+	if (cfg->outputLevel > DRXD_FE_CTRL_MAX)
+		return -1;
+
+	if (cfg->ctrlMode == AGC_CTRL_USER) {
+		do {
+			u16 FeAgRegPm1AgcWri;
+			u16 FeAgRegAgModeLop;
+
+			status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &FeAgRegAgModeLop, 0);
+			if (status < 0)
+				break;
+			FeAgRegAgModeLop &= (~FE_AG_REG_AG_MODE_LOP_MODE_4__M);
+			FeAgRegAgModeLop |= FE_AG_REG_AG_MODE_LOP_MODE_4_STATIC;
+			status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, FeAgRegAgModeLop, 0);
+			if (status < 0)
+				break;
+
+			FeAgRegPm1AgcWri = (u16) (cfg->outputLevel &
+						  FE_AG_REG_PM1_AGC_WRI__M);
+			status = Write16(state, FE_AG_REG_PM1_AGC_WRI__A, FeAgRegPm1AgcWri, 0);
+			if (status < 0)
+				break;
+		} while (0);
+	} else if (cfg->ctrlMode == AGC_CTRL_AUTO) {
+		if (((cfg->maxOutputLevel) < (cfg->minOutputLevel)) ||
+		    ((cfg->maxOutputLevel) > DRXD_FE_CTRL_MAX) ||
+		    ((cfg->speed) > DRXD_FE_CTRL_MAX) ||
+		    ((cfg->settleLevel) > DRXD_FE_CTRL_MAX)
+		    )
+			return -1;
+		do {
+			u16 FeAgRegAgModeLop;
+			u16 FeAgRegEgcSetLvl;
+			u16 slope, offset;
+
+			/* == Mode == */
+
+			status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &FeAgRegAgModeLop, 0);
+			if (status < 0)
+				break;
+			FeAgRegAgModeLop &= (~FE_AG_REG_AG_MODE_LOP_MODE_4__M);
+			FeAgRegAgModeLop |=
+			    FE_AG_REG_AG_MODE_LOP_MODE_4_DYNAMIC;
+			status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, FeAgRegAgModeLop, 0);
+			if (status < 0)
+				break;
+
+			/* == Settle level == */
+
+			FeAgRegEgcSetLvl = (u16) ((cfg->settleLevel >> 1) &
+						  FE_AG_REG_EGC_SET_LVL__M);
+			status = Write16(state, FE_AG_REG_EGC_SET_LVL__A, FeAgRegEgcSetLvl, 0);
+			if (status < 0)
+				break;
+
+			/* == Min/Max == */
+
+			slope = (u16) ((cfg->maxOutputLevel -
+					cfg->minOutputLevel) / 2);
+			offset = (u16) ((cfg->maxOutputLevel +
+					 cfg->minOutputLevel) / 2 - 511);
+
+			status = Write16(state, FE_AG_REG_GC1_AGC_RIC__A, slope, 0);
+			if (status < 0)
+				break;
+			status = Write16(state, FE_AG_REG_GC1_AGC_OFF__A, offset, 0);
+			if (status < 0)
+				break;
+
+			/* == Speed == */
+			{
+				const u16 maxRur = 8;
+				const u16 slowIncrDecLUT[] = { 3, 4, 4, 5, 6 };
+				const u16 fastIncrDecLUT[] = { 14, 15, 15, 16,
+					17, 18, 18, 19,
+					20, 21, 22, 23,
+					24, 26, 27, 28,
+					29, 31
+				};
+
+				u16 fineSteps = (DRXD_FE_CTRL_MAX + 1) /
+				    (maxRur + 1);
+				u16 fineSpeed = (u16) (cfg->speed -
+						       ((cfg->speed /
+							 fineSteps) *
+							fineSteps));
+				u16 invRurCount = (u16) (cfg->speed /
+							 fineSteps);
+				u16 rurCount;
+				if (invRurCount > maxRur) {
+					rurCount = 0;
+					fineSpeed += fineSteps;
+				} else {
+					rurCount = maxRur - invRurCount;
+				}
+
+				/*
+				   fastInc = default *
+				   (2^(fineSpeed/fineSteps))
+				   => range[default...2*default>
+				   slowInc = default *
+				   (2^(fineSpeed/fineSteps))
+				 */
+				{
+					u16 fastIncrDec =
+					    fastIncrDecLUT[fineSpeed /
+							   ((fineSteps /
+							     (14 + 1)) + 1)];
+					u16 slowIncrDec =
+					    slowIncrDecLUT[fineSpeed /
+							   (fineSteps /
+							    (3 + 1))];
+
+					status = Write16(state, FE_AG_REG_EGC_RUR_CNT__A, rurCount, 0);
+					if (status < 0)
+						break;
+					status = Write16(state, FE_AG_REG_EGC_FAS_INC__A, fastIncrDec, 0);
+					if (status < 0)
+						break;
+					status = Write16(state, FE_AG_REG_EGC_FAS_DEC__A, fastIncrDec, 0);
+					if (status < 0)
+						break;
+					status = Write16(state, FE_AG_REG_EGC_SLO_INC__A, slowIncrDec, 0);
+					if (status < 0)
+						break;
+					status = Write16(state, FE_AG_REG_EGC_SLO_DEC__A, slowIncrDec, 0);
+					if (status < 0)
+						break;
+				}
+			}
+		} while (0);
+
+	} else {
+		/* No OFF mode for IF control */
+		return -1;
+	}
+	return status;
+}
+
+static int SetCfgRfAgc(struct drxd_state *state, struct SCfgAgc *cfg)
+{
+	int status = 0;
+
+	if (cfg->outputLevel > DRXD_FE_CTRL_MAX)
+		return -1;
+
+	if (cfg->ctrlMode == AGC_CTRL_USER) {
+		do {
+			u16 AgModeLop = 0;
+			u16 level = (cfg->outputLevel);
+
+			if (level == DRXD_FE_CTRL_MAX)
+				level++;
+
+			status = Write16(state, FE_AG_REG_PM2_AGC_WRI__A, level, 0x0000);
+			if (status < 0)
+				break;
+
+			/*==== Mode ====*/
+
+			/* Powerdown PD2, WRI source */
+			state->m_FeAgRegAgPwd &= ~(FE_AG_REG_AG_PWD_PWD_PD2__M);
+			state->m_FeAgRegAgPwd |=
+			    FE_AG_REG_AG_PWD_PWD_PD2_DISABLE;
+			status = Write16(state, FE_AG_REG_AG_PWD__A, state->m_FeAgRegAgPwd, 0x0000);
+			if (status < 0)
+				break;
+
+			status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
+			if (status < 0)
+				break;
+			AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M |
+					FE_AG_REG_AG_MODE_LOP_MODE_E__M));
+			AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC |
+				      FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC);
+			status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
+			if (status < 0)
+				break;
+
+			/* enable AGC2 pin */
+			{
+				u16 FeAgRegAgAgcSio = 0;
+				status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000);
+				if (status < 0)
+					break;
+				FeAgRegAgAgcSio &=
+				    ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M);
+				FeAgRegAgAgcSio |=
+				    FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT;
+				status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000);
+				if (status < 0)
+					break;
+			}
+
+		} while (0);
+	} else if (cfg->ctrlMode == AGC_CTRL_AUTO) {
+		u16 AgModeLop = 0;
+
+		do {
+			u16 level;
+			/* Automatic control */
+			/* Powerup PD2, AGC2 as output, TGC source */
+			(state->m_FeAgRegAgPwd) &=
+			    ~(FE_AG_REG_AG_PWD_PWD_PD2__M);
+			(state->m_FeAgRegAgPwd) |=
+			    FE_AG_REG_AG_PWD_PWD_PD2_DISABLE;
+			status = Write16(state, FE_AG_REG_AG_PWD__A, (state->m_FeAgRegAgPwd), 0x0000);
+			if (status < 0)
+				break;
+
+			status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
+			if (status < 0)
+				break;
+			AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M |
+					FE_AG_REG_AG_MODE_LOP_MODE_E__M));
+			AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC |
+				      FE_AG_REG_AG_MODE_LOP_MODE_E_DYNAMIC);
+			status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
+			if (status < 0)
+				break;
+			/* Settle level */
+			level = (((cfg->settleLevel) >> 4) &
+				 FE_AG_REG_TGC_SET_LVL__M);
+			status = Write16(state, FE_AG_REG_TGC_SET_LVL__A, level, 0x0000);
+			if (status < 0)
+				break;
+
+			/* Min/max: don't care */
+
+			/* Speed: TODO */
+
+			/* enable AGC2 pin */
+			{
+				u16 FeAgRegAgAgcSio = 0;
+				status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000);
+				if (status < 0)
+					break;
+				FeAgRegAgAgcSio &=
+				    ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M);
+				FeAgRegAgAgcSio |=
+				    FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT;
+				status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000);
+				if (status < 0)
+					break;
+			}
+
+		} while (0);
+	} else {
+		u16 AgModeLop = 0;
+
+		do {
+			/* No RF AGC control */
+			/* Powerdown PD2, AGC2 as output, WRI source */
+			(state->m_FeAgRegAgPwd) &=
+			    ~(FE_AG_REG_AG_PWD_PWD_PD2__M);
+			(state->m_FeAgRegAgPwd) |=
+			    FE_AG_REG_AG_PWD_PWD_PD2_ENABLE;
+			status = Write16(state, FE_AG_REG_AG_PWD__A, (state->m_FeAgRegAgPwd), 0x0000);
+			if (status < 0)
+				break;
+
+			status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
+			if (status < 0)
+				break;
+			AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M |
+					FE_AG_REG_AG_MODE_LOP_MODE_E__M));
+			AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC |
+				      FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC);
+			status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
+			if (status < 0)
+				break;
+
+			/* set FeAgRegAgAgcSio AGC2 (RF) as input */
+			{
+				u16 FeAgRegAgAgcSio = 0;
+				status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000);
+				if (status < 0)
+					break;
+				FeAgRegAgAgcSio &=
+				    ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M);
+				FeAgRegAgAgcSio |=
+				    FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_INPUT;
+				status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000);
+				if (status < 0)
+					break;
+			}
+		} while (0);
+	}
+	return status;
+}
+
+static int ReadIFAgc(struct drxd_state *state, u32 * pValue)
+{
+	int status = 0;
+
+	*pValue = 0;
+	if (state->if_agc_cfg.ctrlMode != AGC_CTRL_OFF) {
+		u16 Value;
+		status = Read16(state, FE_AG_REG_GC1_AGC_DAT__A, &Value, 0);
+		Value &= FE_AG_REG_GC1_AGC_DAT__M;
+		if (status >= 0) {
+			/*           3.3V
+			   |
+			   R1
+			   |
+			   Vin - R3 - * -- Vout
+			   |
+			   R2
+			   |
+			   GND
+			 */
+			u32 R1 = state->if_agc_cfg.R1;
+			u32 R2 = state->if_agc_cfg.R2;
+			u32 R3 = state->if_agc_cfg.R3;
+
+			u32 Vmax, Rpar, Vmin, Vout;
+
+			if (R2 == 0 && (R1 == 0 || R3 == 0))
+				return 0;
+
+			Vmax = (3300 * R2) / (R1 + R2);
+			Rpar = (R2 * R3) / (R3 + R2);
+			Vmin = (3300 * Rpar) / (R1 + Rpar);
+			Vout = Vmin + ((Vmax - Vmin) * Value) / 1024;
+
+			*pValue = Vout;
+		}
+	}
+	return status;
+}
+
+static int load_firmware(struct drxd_state *state, const char *fw_name)
+{
+	const struct firmware *fw;
+
+	if (request_firmware(&fw, fw_name, state->dev) < 0) {
+		printk(KERN_ERR "drxd: firmware load failure [%s]\n", fw_name);
+		return -EIO;
+	}
+
+	state->microcode = kmemdup(fw->data, fw->size, GFP_KERNEL);
+	if (state->microcode == NULL) {
+		release_firmware(fw);
+		printk(KERN_ERR "drxd: firmware load failure: no memory\n");
+		return -ENOMEM;
+	}
+
+	state->microcode_length = fw->size;
+	release_firmware(fw);
+	return 0;
+}
+
+static int DownloadMicrocode(struct drxd_state *state,
+			     const u8 *pMCImage, u32 Length)
+{
+	u8 *pSrc;
+	u32 Address;
+	u16 nBlocks;
+	u16 BlockSize;
+	u32 offset = 0;
+	int i, status = 0;
+
+	pSrc = (u8 *) pMCImage;
+	/* We're not using Flags */
+	/* Flags = (pSrc[0] << 8) | pSrc[1]; */
+	pSrc += sizeof(u16);
+	offset += sizeof(u16);
+	nBlocks = (pSrc[0] << 8) | pSrc[1];
+	pSrc += sizeof(u16);
+	offset += sizeof(u16);
+
+	for (i = 0; i < nBlocks; i++) {
+		Address = (pSrc[0] << 24) | (pSrc[1] << 16) |
+		    (pSrc[2] << 8) | pSrc[3];
+		pSrc += sizeof(u32);
+		offset += sizeof(u32);
+
+		BlockSize = ((pSrc[0] << 8) | pSrc[1]) * sizeof(u16);
+		pSrc += sizeof(u16);
+		offset += sizeof(u16);
+
+		/* We're not using Flags */
+		/* u16 Flags = (pSrc[0] << 8) | pSrc[1]; */
+		pSrc += sizeof(u16);
+		offset += sizeof(u16);
+
+		/* We're not using BlockCRC */
+		/* u16 BlockCRC = (pSrc[0] << 8) | pSrc[1]; */
+		pSrc += sizeof(u16);
+		offset += sizeof(u16);
+
+		status = WriteBlock(state, Address, BlockSize,
+				    pSrc, DRX_I2C_CLEARCRC);
+		if (status < 0)
+			break;
+		pSrc += BlockSize;
+		offset += BlockSize;
+	}
+
+	return status;
+}
+
+static int HI_Command(struct drxd_state *state, u16 cmd, u16 * pResult)
+{
+	u32 nrRetries = 0;
+	u16 waitCmd;
+	int status;
+
+	status = Write16(state, HI_RA_RAM_SRV_CMD__A, cmd, 0);
+	if (status < 0)
+		return status;
+
+	do {
+		nrRetries += 1;
+		if (nrRetries > DRXD_MAX_RETRIES) {
+			status = -1;
+			break;
+		};
+		status = Read16(state, HI_RA_RAM_SRV_CMD__A, &waitCmd, 0);
+	} while (waitCmd != 0);
+
+	if (status >= 0)
+		status = Read16(state, HI_RA_RAM_SRV_RES__A, pResult, 0);
+	return status;
+}
+
+static int HI_CfgCommand(struct drxd_state *state)
+{
+	int status = 0;
+
+	mutex_lock(&state->mutex);
+	Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, HI_RA_RAM_SRV_RST_KEY_ACT, 0);
+	Write16(state, HI_RA_RAM_SRV_CFG_DIV__A, state->hi_cfg_timing_div, 0);
+	Write16(state, HI_RA_RAM_SRV_CFG_BDL__A, state->hi_cfg_bridge_delay, 0);
+	Write16(state, HI_RA_RAM_SRV_CFG_WUP__A, state->hi_cfg_wakeup_key, 0);
+	Write16(state, HI_RA_RAM_SRV_CFG_ACT__A, state->hi_cfg_ctrl, 0);
+
+	Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, HI_RA_RAM_SRV_RST_KEY_ACT, 0);
+
+	if ((state->hi_cfg_ctrl & HI_RA_RAM_SRV_CFG_ACT_PWD_EXE) ==
+	    HI_RA_RAM_SRV_CFG_ACT_PWD_EXE)
+		status = Write16(state, HI_RA_RAM_SRV_CMD__A,
+				 HI_RA_RAM_SRV_CMD_CONFIG, 0);
+	else
+		status = HI_Command(state, HI_RA_RAM_SRV_CMD_CONFIG, 0);
+	mutex_unlock(&state->mutex);
+	return status;
+}
+
+static int InitHI(struct drxd_state *state)
+{
+	state->hi_cfg_wakeup_key = (state->chip_adr);
+	/* port/bridge/power down ctrl */
+	state->hi_cfg_ctrl = HI_RA_RAM_SRV_CFG_ACT_SLV0_ON;
+	return HI_CfgCommand(state);
+}
+
+static int HI_ResetCommand(struct drxd_state *state)
+{
+	int status;
+
+	mutex_lock(&state->mutex);
+	status = Write16(state, HI_RA_RAM_SRV_RST_KEY__A,
+			 HI_RA_RAM_SRV_RST_KEY_ACT, 0);
+	if (status == 0)
+		status = HI_Command(state, HI_RA_RAM_SRV_CMD_RESET, 0);
+	mutex_unlock(&state->mutex);
+	msleep(1);
+	return status;
+}
+
+static int DRX_ConfigureI2CBridge(struct drxd_state *state, int bEnableBridge)
+{
+	state->hi_cfg_ctrl &= (~HI_RA_RAM_SRV_CFG_ACT_BRD__M);
+	if (bEnableBridge)
+		state->hi_cfg_ctrl |= HI_RA_RAM_SRV_CFG_ACT_BRD_ON;
+	else
+		state->hi_cfg_ctrl |= HI_RA_RAM_SRV_CFG_ACT_BRD_OFF;
+
+	return HI_CfgCommand(state);
+}
+
+#define HI_TR_WRITE      0x9
+#define HI_TR_READ       0xA
+#define HI_TR_READ_WRITE 0xB
+#define HI_TR_BROADCAST  0x4
+
+#if 0
+static int AtomicReadBlock(struct drxd_state *state,
+			   u32 Addr, u16 DataSize, u8 *pData, u8 Flags)
+{
+	int status;
+	int i = 0;
+
+	/* Parameter check */
+	if ((!pData) || ((DataSize & 1) != 0))
+		return -1;
+
+	mutex_lock(&state->mutex);
+
+	do {
+		/* Instruct HI to read n bytes */
+		/* TODO use proper names forthese egisters */
+		status = Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, (HI_TR_FUNC_ADDR & 0xFFFF), 0);
+		if (status < 0)
+			break;
+		status = Write16(state, HI_RA_RAM_SRV_CFG_DIV__A, (u16) (Addr >> 16), 0);
+		if (status < 0)
+			break;
+		status = Write16(state, HI_RA_RAM_SRV_CFG_BDL__A, (u16) (Addr & 0xFFFF), 0);
+		if (status < 0)
+			break;
+		status = Write16(state, HI_RA_RAM_SRV_CFG_WUP__A, (u16) ((DataSize / 2) - 1), 0);
+		if (status < 0)
+			break;
+		status = Write16(state, HI_RA_RAM_SRV_CFG_ACT__A, HI_TR_READ, 0);
+		if (status < 0)
+			break;
+
+		status = HI_Command(state, HI_RA_RAM_SRV_CMD_EXECUTE, 0);
+		if (status < 0)
+			break;
+
+	} while (0);
+
+	if (status >= 0) {
+		for (i = 0; i < (DataSize / 2); i += 1) {
+			u16 word;
+
+			status = Read16(state, (HI_RA_RAM_USR_BEGIN__A + i),
+					&word, 0);
+			if (status < 0)
+				break;
+			pData[2 * i] = (u8) (word & 0xFF);
+			pData[(2 * i) + 1] = (u8) (word >> 8);
+		}
+	}
+	mutex_unlock(&state->mutex);
+	return status;
+}
+
+static int AtomicReadReg32(struct drxd_state *state,
+			   u32 Addr, u32 *pData, u8 Flags)
+{
+	u8 buf[sizeof(u32)];
+	int status;
+
+	if (!pData)
+		return -1;
+	status = AtomicReadBlock(state, Addr, sizeof(u32), buf, Flags);
+	*pData = (((u32) buf[0]) << 0) +
+	    (((u32) buf[1]) << 8) +
+	    (((u32) buf[2]) << 16) + (((u32) buf[3]) << 24);
+	return status;
+}
+#endif
+
+static int StopAllProcessors(struct drxd_state *state)
+{
+	return Write16(state, HI_COMM_EXEC__A,
+		       SC_COMM_EXEC_CTL_STOP, DRX_I2C_BROADCAST);
+}
+
+static int EnableAndResetMB(struct drxd_state *state)
+{
+	if (state->type_A) {
+		/* disable? monitor bus observe @ EC_OC */
+		Write16(state, EC_OC_REG_OC_MON_SIO__A, 0x0000, 0x0000);
+	}
+
+	/* do inverse broadcast, followed by explicit write to HI */
+	Write16(state, HI_COMM_MB__A, 0x0000, DRX_I2C_BROADCAST);
+	Write16(state, HI_COMM_MB__A, 0x0000, 0x0000);
+	return 0;
+}
+
+static int InitCC(struct drxd_state *state)
+{
+	if (state->osc_clock_freq == 0 ||
+	    state->osc_clock_freq > 20000 ||
+	    (state->osc_clock_freq % 4000) != 0) {
+		printk(KERN_ERR "invalid osc frequency %d\n", state->osc_clock_freq);
+		return -1;
+	}
+
+	Write16(state, CC_REG_OSC_MODE__A, CC_REG_OSC_MODE_M20, 0);
+	Write16(state, CC_REG_PLL_MODE__A, CC_REG_PLL_MODE_BYPASS_PLL |
+		CC_REG_PLL_MODE_PUMP_CUR_12, 0);
+	Write16(state, CC_REG_REF_DIVIDE__A, state->osc_clock_freq / 4000, 0);
+	Write16(state, CC_REG_PWD_MODE__A, CC_REG_PWD_MODE_DOWN_PLL, 0);
+	Write16(state, CC_REG_UPDATE__A, CC_REG_UPDATE_KEY, 0);
+
+	return 0;
+}
+
+static int ResetECOD(struct drxd_state *state)
+{
+	int status = 0;
+
+	if (state->type_A)
+		status = Write16(state, EC_OD_REG_SYNC__A, 0x0664, 0);
+	else
+		status = Write16(state, B_EC_OD_REG_SYNC__A, 0x0664, 0);
+
+	if (!(status < 0))
+		status = WriteTable(state, state->m_ResetECRAM);
+	if (!(status < 0))
+		status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0001, 0);
+	return status;
+}
+
+/* Configure PGA switch */
+
+static int SetCfgPga(struct drxd_state *state, int pgaSwitch)
+{
+	int status;
+	u16 AgModeLop = 0;
+	u16 AgModeHip = 0;
+	do {
+		if (pgaSwitch) {
+			/* PGA on */
+			/* fine gain */
+			status = Read16(state, B_FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
+			if (status < 0)
+				break;
+			AgModeLop &= (~(B_FE_AG_REG_AG_MODE_LOP_MODE_C__M));
+			AgModeLop |= B_FE_AG_REG_AG_MODE_LOP_MODE_C_DYNAMIC;
+			status = Write16(state, B_FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
+			if (status < 0)
+				break;
+
+			/* coarse gain */
+			status = Read16(state, B_FE_AG_REG_AG_MODE_HIP__A, &AgModeHip, 0x0000);
+			if (status < 0)
+				break;
+			AgModeHip &= (~(B_FE_AG_REG_AG_MODE_HIP_MODE_J__M));
+			AgModeHip |= B_FE_AG_REG_AG_MODE_HIP_MODE_J_DYNAMIC;
+			status = Write16(state, B_FE_AG_REG_AG_MODE_HIP__A, AgModeHip, 0x0000);
+			if (status < 0)
+				break;
+
+			/* enable fine and coarse gain, enable AAF,
+			   no ext resistor */
+			status = Write16(state, B_FE_AG_REG_AG_PGA_MODE__A, B_FE_AG_REG_AG_PGA_MODE_PFY_PCY_AFY_REN, 0x0000);
+			if (status < 0)
+				break;
+		} else {
+			/* PGA off, bypass */
+
+			/* fine gain */
+			status = Read16(state, B_FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
+			if (status < 0)
+				break;
+			AgModeLop &= (~(B_FE_AG_REG_AG_MODE_LOP_MODE_C__M));
+			AgModeLop |= B_FE_AG_REG_AG_MODE_LOP_MODE_C_STATIC;
+			status = Write16(state, B_FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
+			if (status < 0)
+				break;
+
+			/* coarse gain */
+			status = Read16(state, B_FE_AG_REG_AG_MODE_HIP__A, &AgModeHip, 0x0000);
+			if (status < 0)
+				break;
+			AgModeHip &= (~(B_FE_AG_REG_AG_MODE_HIP_MODE_J__M));
+			AgModeHip |= B_FE_AG_REG_AG_MODE_HIP_MODE_J_STATIC;
+			status = Write16(state, B_FE_AG_REG_AG_MODE_HIP__A, AgModeHip, 0x0000);
+			if (status < 0)
+				break;
+
+			/* disable fine and coarse gain, enable AAF,
+			   no ext resistor */
+			status = Write16(state, B_FE_AG_REG_AG_PGA_MODE__A, B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN, 0x0000);
+			if (status < 0)
+				break;
+		}
+	} while (0);
+	return status;
+}
+
+static int InitFE(struct drxd_state *state)
+{
+	int status;
+
+	do {
+		status = WriteTable(state, state->m_InitFE_1);
+		if (status < 0)
+			break;
+
+		if (state->type_A) {
+			status = Write16(state, FE_AG_REG_AG_PGA_MODE__A,
+					 FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN,
+					 0);
+		} else {
+			if (state->PGA)
+				status = SetCfgPga(state, 0);
+			else
+				status =
+				    Write16(state, B_FE_AG_REG_AG_PGA_MODE__A,
+					    B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN,
+					    0);
+		}
+
+		if (status < 0)
+			break;
+		status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, state->m_FeAgRegAgAgcSio, 0x0000);
+		if (status < 0)
+			break;
+		status = Write16(state, FE_AG_REG_AG_PWD__A, state->m_FeAgRegAgPwd, 0x0000);
+		if (status < 0)
+			break;
+
+		status = WriteTable(state, state->m_InitFE_2);
+		if (status < 0)
+			break;
+
+	} while (0);
+
+	return status;
+}
+
+static int InitFT(struct drxd_state *state)
+{
+	/*
+	   norm OFFSET,  MB says =2 voor 8K en =3 voor 2K waarschijnlijk
+	   SC stuff
+	 */
+	return Write16(state, FT_REG_COMM_EXEC__A, 0x0001, 0x0000);
+}
+
+static int SC_WaitForReady(struct drxd_state *state)
+{
+	u16 curCmd;
+	int i;
+
+	for (i = 0; i < DRXD_MAX_RETRIES; i += 1) {
+		int status = Read16(state, SC_RA_RAM_CMD__A, &curCmd, 0);
+		if (status == 0 || curCmd == 0)
+			return status;
+	}
+	return -1;
+}
+
+static int SC_SendCommand(struct drxd_state *state, u16 cmd)
+{
+	int status = 0;
+	u16 errCode;
+
+	Write16(state, SC_RA_RAM_CMD__A, cmd, 0);
+	SC_WaitForReady(state);
+
+	Read16(state, SC_RA_RAM_CMD_ADDR__A, &errCode, 0);
+
+	if (errCode == 0xFFFF) {
+		printk(KERN_ERR "Command Error\n");
+		status = -1;
+	}
+
+	return status;
+}
+
+static int SC_ProcStartCommand(struct drxd_state *state,
+			       u16 subCmd, u16 param0, u16 param1)
+{
+	int status = 0;
+	u16 scExec;
+
+	mutex_lock(&state->mutex);
+	do {
+		Read16(state, SC_COMM_EXEC__A, &scExec, 0);
+		if (scExec != 1) {
+			status = -1;
+			break;
+		}
+		SC_WaitForReady(state);
+		Write16(state, SC_RA_RAM_CMD_ADDR__A, subCmd, 0);
+		Write16(state, SC_RA_RAM_PARAM1__A, param1, 0);
+		Write16(state, SC_RA_RAM_PARAM0__A, param0, 0);
+
+		SC_SendCommand(state, SC_RA_RAM_CMD_PROC_START);
+	} while (0);
+	mutex_unlock(&state->mutex);
+	return status;
+}
+
+static int SC_SetPrefParamCommand(struct drxd_state *state,
+				  u16 subCmd, u16 param0, u16 param1)
+{
+	int status;
+
+	mutex_lock(&state->mutex);
+	do {
+		status = SC_WaitForReady(state);
+		if (status < 0)
+			break;
+		status = Write16(state, SC_RA_RAM_CMD_ADDR__A, subCmd, 0);
+		if (status < 0)
+			break;
+		status = Write16(state, SC_RA_RAM_PARAM1__A, param1, 0);
+		if (status < 0)
+			break;
+		status = Write16(state, SC_RA_RAM_PARAM0__A, param0, 0);
+		if (status < 0)
+			break;
+
+		status = SC_SendCommand(state, SC_RA_RAM_CMD_SET_PREF_PARAM);
+		if (status < 0)
+			break;
+	} while (0);
+	mutex_unlock(&state->mutex);
+	return status;
+}
+
+#if 0
+static int SC_GetOpParamCommand(struct drxd_state *state, u16 * result)
+{
+	int status = 0;
+
+	mutex_lock(&state->mutex);
+	do {
+		status = SC_WaitForReady(state);
+		if (status < 0)
+			break;
+		status = SC_SendCommand(state, SC_RA_RAM_CMD_GET_OP_PARAM);
+		if (status < 0)
+			break;
+		status = Read16(state, SC_RA_RAM_PARAM0__A, result, 0);
+		if (status < 0)
+			break;
+	} while (0);
+	mutex_unlock(&state->mutex);
+	return status;
+}
+#endif
+
+static int ConfigureMPEGOutput(struct drxd_state *state, int bEnableOutput)
+{
+	int status;
+
+	do {
+		u16 EcOcRegIprInvMpg = 0;
+		u16 EcOcRegOcModeLop = 0;
+		u16 EcOcRegOcModeHip = 0;
+		u16 EcOcRegOcMpgSio = 0;
+
+		/*CHK_ERROR(Read16(state, EC_OC_REG_OC_MODE_LOP__A, &EcOcRegOcModeLop, 0)); */
+
+		if (state->operation_mode == OM_DVBT_Diversity_Front) {
+			if (bEnableOutput) {
+				EcOcRegOcModeHip |=
+				    B_EC_OC_REG_OC_MODE_HIP_MPG_BUS_SRC_MONITOR;
+			} else
+				EcOcRegOcMpgSio |= EC_OC_REG_OC_MPG_SIO__M;
+			EcOcRegOcModeLop |=
+			    EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE;
+		} else {
+			EcOcRegOcModeLop = state->m_EcOcRegOcModeLop;
+
+			if (bEnableOutput)
+				EcOcRegOcMpgSio &= (~(EC_OC_REG_OC_MPG_SIO__M));
+			else
+				EcOcRegOcMpgSio |= EC_OC_REG_OC_MPG_SIO__M;
+
+			/* Don't Insert RS Byte */
+			if (state->insert_rs_byte) {
+				EcOcRegOcModeLop &=
+				    (~(EC_OC_REG_OC_MODE_LOP_PAR_ENA__M));
+				EcOcRegOcModeHip &=
+				    (~EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M);
+				EcOcRegOcModeHip |=
+				    EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_ENABLE;
+			} else {
+				EcOcRegOcModeLop |=
+				    EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE;
+				EcOcRegOcModeHip &=
+				    (~EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M);
+				EcOcRegOcModeHip |=
+				    EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_DISABLE;
+			}
+
+			/* Mode = Parallel */
+			if (state->enable_parallel)
+				EcOcRegOcModeLop &=
+				    (~(EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE__M));
+			else
+				EcOcRegOcModeLop |=
+				    EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE_SERIAL;
+		}
+		/* Invert Data */
+		/* EcOcRegIprInvMpg |= 0x00FF; */
+		EcOcRegIprInvMpg &= (~(0x00FF));
+
+		/* Invert Error ( we don't use the pin ) */
+		/*  EcOcRegIprInvMpg |= 0x0100; */
+		EcOcRegIprInvMpg &= (~(0x0100));
+
+		/* Invert Start ( we don't use the pin ) */
+		/* EcOcRegIprInvMpg |= 0x0200; */
+		EcOcRegIprInvMpg &= (~(0x0200));
+
+		/* Invert Valid ( we don't use the pin ) */
+		/* EcOcRegIprInvMpg |= 0x0400; */
+		EcOcRegIprInvMpg &= (~(0x0400));
+
+		/* Invert Clock */
+		/* EcOcRegIprInvMpg |= 0x0800; */
+		EcOcRegIprInvMpg &= (~(0x0800));
+
+		/* EcOcRegOcModeLop =0x05; */
+		status = Write16(state, EC_OC_REG_IPR_INV_MPG__A, EcOcRegIprInvMpg, 0);
+		if (status < 0)
+			break;
+		status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, EcOcRegOcModeLop, 0);
+		if (status < 0)
+			break;
+		status = Write16(state, EC_OC_REG_OC_MODE_HIP__A, EcOcRegOcModeHip, 0x0000);
+		if (status < 0)
+			break;
+		status = Write16(state, EC_OC_REG_OC_MPG_SIO__A, EcOcRegOcMpgSio, 0);
+		if (status < 0)
+			break;
+	} while (0);
+	return status;
+}
+
+static int SetDeviceTypeId(struct drxd_state *state)
+{
+	int status = 0;
+	u16 deviceId = 0;
+
+	do {
+		status = Read16(state, CC_REG_JTAGID_L__A, &deviceId, 0);
+		if (status < 0)
+			break;
+		/* TODO: why twice? */
+		status = Read16(state, CC_REG_JTAGID_L__A, &deviceId, 0);
+		if (status < 0)
+			break;
+		printk(KERN_INFO "drxd: deviceId = %04x\n", deviceId);
+
+		state->type_A = 0;
+		state->PGA = 0;
+		state->diversity = 0;
+		if (deviceId == 0) {	/* on A2 only 3975 available */
+			state->type_A = 1;
+			printk(KERN_INFO "DRX3975D-A2\n");
+		} else {
+			deviceId >>= 12;
+			printk(KERN_INFO "DRX397%dD-B1\n", deviceId);
+			switch (deviceId) {
+			case 4:
+				state->diversity = 1;
+			case 3:
+			case 7:
+				state->PGA = 1;
+				break;
+			case 6:
+				state->diversity = 1;
+			case 5:
+			case 8:
+				break;
+			default:
+				status = -1;
+				break;
+			}
+		}
+	} while (0);
+
+	if (status < 0)
+		return status;
+
+	/* Init Table selection */
+	state->m_InitAtomicRead = DRXD_InitAtomicRead;
+	state->m_InitSC = DRXD_InitSC;
+	state->m_ResetECRAM = DRXD_ResetECRAM;
+	if (state->type_A) {
+		state->m_ResetCEFR = DRXD_ResetCEFR;
+		state->m_InitFE_1 = DRXD_InitFEA2_1;
+		state->m_InitFE_2 = DRXD_InitFEA2_2;
+		state->m_InitCP = DRXD_InitCPA2;
+		state->m_InitCE = DRXD_InitCEA2;
+		state->m_InitEQ = DRXD_InitEQA2;
+		state->m_InitEC = DRXD_InitECA2;
+		if (load_firmware(state, DRX_FW_FILENAME_A2))
+			return -EIO;
+	} else {
+		state->m_ResetCEFR = NULL;
+		state->m_InitFE_1 = DRXD_InitFEB1_1;
+		state->m_InitFE_2 = DRXD_InitFEB1_2;
+		state->m_InitCP = DRXD_InitCPB1;
+		state->m_InitCE = DRXD_InitCEB1;
+		state->m_InitEQ = DRXD_InitEQB1;
+		state->m_InitEC = DRXD_InitECB1;
+		if (load_firmware(state, DRX_FW_FILENAME_B1))
+			return -EIO;
+	}
+	if (state->diversity) {
+		state->m_InitDiversityFront = DRXD_InitDiversityFront;
+		state->m_InitDiversityEnd = DRXD_InitDiversityEnd;
+		state->m_DisableDiversity = DRXD_DisableDiversity;
+		state->m_StartDiversityFront = DRXD_StartDiversityFront;
+		state->m_StartDiversityEnd = DRXD_StartDiversityEnd;
+		state->m_DiversityDelay8MHZ = DRXD_DiversityDelay8MHZ;
+		state->m_DiversityDelay6MHZ = DRXD_DiversityDelay6MHZ;
+	} else {
+		state->m_InitDiversityFront = NULL;
+		state->m_InitDiversityEnd = NULL;
+		state->m_DisableDiversity = NULL;
+		state->m_StartDiversityFront = NULL;
+		state->m_StartDiversityEnd = NULL;
+		state->m_DiversityDelay8MHZ = NULL;
+		state->m_DiversityDelay6MHZ = NULL;
+	}
+
+	return status;
+}
+
+static int CorrectSysClockDeviation(struct drxd_state *state)
+{
+	int status;
+	s32 incr = 0;
+	s32 nomincr = 0;
+	u32 bandwidth = 0;
+	u32 sysClockInHz = 0;
+	u32 sysClockFreq = 0;	/* in kHz */
+	s16 oscClockDeviation;
+	s16 Diff;
+
+	do {
+		/* Retrieve bandwidth and incr, sanity check */
+
+		/* These accesses should be AtomicReadReg32, but that
+		   causes trouble (at least for diversity */
+		status = Read32(state, LC_RA_RAM_IFINCR_NOM_L__A, ((u32 *) &nomincr), 0);
+		if (status < 0)
+			break;
+		status = Read32(state, FE_IF_REG_INCR0__A, (u32 *) &incr, 0);
+		if (status < 0)
+			break;
+
+		if (state->type_A) {
+			if ((nomincr - incr < -500) || (nomincr - incr > 500))
+				break;
+		} else {
+			if ((nomincr - incr < -2000) || (nomincr - incr > 2000))
+				break;
+		}
+
+		switch (state->props.bandwidth_hz) {
+		case 8000000:
+			bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ;
+			break;
+		case 7000000:
+			bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ;
+			break;
+		case 6000000:
+			bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ;
+			break;
+		default:
+			return -1;
+			break;
+		}
+
+		/* Compute new sysclock value
+		   sysClockFreq = (((incr + 2^23)*bandwidth)/2^21)/1000 */
+		incr += (1 << 23);
+		sysClockInHz = MulDiv32(incr, bandwidth, 1 << 21);
+		sysClockFreq = (u32) (sysClockInHz / 1000);
+		/* rounding */
+		if ((sysClockInHz % 1000) > 500)
+			sysClockFreq++;
+
+		/* Compute clock deviation in ppm */
+		oscClockDeviation = (u16) ((((s32) (sysClockFreq) -
+					     (s32)
+					     (state->expected_sys_clock_freq)) *
+					    1000000L) /
+					   (s32)
+					   (state->expected_sys_clock_freq));
+
+		Diff = oscClockDeviation - state->osc_clock_deviation;
+		/*printk(KERN_INFO "sysclockdiff=%d\n", Diff); */
+		if (Diff >= -200 && Diff <= 200) {
+			state->sys_clock_freq = (u16) sysClockFreq;
+			if (oscClockDeviation != state->osc_clock_deviation) {
+				if (state->config.osc_deviation) {
+					state->config.osc_deviation(state->priv,
+								    oscClockDeviation,
+								    1);
+					state->osc_clock_deviation =
+					    oscClockDeviation;
+				}
+			}
+			/* switch OFF SRMM scan in SC */
+			status = Write16(state, SC_RA_RAM_SAMPLE_RATE_COUNT__A, DRXD_OSCDEV_DONT_SCAN, 0);
+			if (status < 0)
+				break;
+			/* overrule FE_IF internal value for
+			   proper re-locking */
+			status = Write16(state, SC_RA_RAM_IF_SAVE__AX, state->current_fe_if_incr, 0);
+			if (status < 0)
+				break;
+			state->cscd_state = CSCD_SAVED;
+		}
+	} while (0);
+
+	return status;
+}
+
+static int DRX_Stop(struct drxd_state *state)
+{
+	int status;
+
+	if (state->drxd_state != DRXD_STARTED)
+		return 0;
+
+	do {
+		if (state->cscd_state != CSCD_SAVED) {
+			u32 lock;
+			status = DRX_GetLockStatus(state, &lock);
+			if (status < 0)
+				break;
+		}
+
+		status = StopOC(state);
+		if (status < 0)
+			break;
+
+		state->drxd_state = DRXD_STOPPED;
+
+		status = ConfigureMPEGOutput(state, 0);
+		if (status < 0)
+			break;
+
+		if (state->type_A) {
+			/* Stop relevant processors off the device */
+			status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0000, 0x0000);
+			if (status < 0)
+				break;
+
+			status = Write16(state, SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+			if (status < 0)
+				break;
+			status = Write16(state, LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+			if (status < 0)
+				break;
+		} else {
+			/* Stop all processors except HI & CC & FE */
+			status = Write16(state, B_SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+			if (status < 0)
+				break;
+			status = Write16(state, B_LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+			if (status < 0)
+				break;
+			status = Write16(state, B_FT_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+			if (status < 0)
+				break;
+			status = Write16(state, B_CP_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+			if (status < 0)
+				break;
+			status = Write16(state, B_CE_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+			if (status < 0)
+				break;
+			status = Write16(state, B_EQ_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+			if (status < 0)
+				break;
+			status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0000, 0);
+			if (status < 0)
+				break;
+		}
+
+	} while (0);
+	return status;
+}
+
+int SetOperationMode(struct drxd_state *state, int oMode)
+{
+	int status;
+
+	do {
+		if (state->drxd_state != DRXD_STOPPED) {
+			status = -1;
+			break;
+		}
+
+		if (oMode == state->operation_mode) {
+			status = 0;
+			break;
+		}
+
+		if (oMode != OM_Default && !state->diversity) {
+			status = -1;
+			break;
+		}
+
+		switch (oMode) {
+		case OM_DVBT_Diversity_Front:
+			status = WriteTable(state, state->m_InitDiversityFront);
+			break;
+		case OM_DVBT_Diversity_End:
+			status = WriteTable(state, state->m_InitDiversityEnd);
+			break;
+		case OM_Default:
+			/* We need to check how to
+			   get DRXD out of diversity */
+		default:
+			status = WriteTable(state, state->m_DisableDiversity);
+			break;
+		}
+	} while (0);
+
+	if (!status)
+		state->operation_mode = oMode;
+	return status;
+}
+
+static int StartDiversity(struct drxd_state *state)
+{
+	int status = 0;
+	u16 rcControl;
+
+	do {
+		if (state->operation_mode == OM_DVBT_Diversity_Front) {
+			status = WriteTable(state, state->m_StartDiversityFront);
+			if (status < 0)
+				break;
+		} else if (state->operation_mode == OM_DVBT_Diversity_End) {
+			status = WriteTable(state, state->m_StartDiversityEnd);
+			if (status < 0)
+				break;
+			if (state->props.bandwidth_hz == 8000000) {
+				status = WriteTable(state, state->m_DiversityDelay8MHZ);
+				if (status < 0)
+					break;
+			} else {
+				status = WriteTable(state, state->m_DiversityDelay6MHZ);
+				if (status < 0)
+					break;
+			}
+
+			status = Read16(state, B_EQ_REG_RC_SEL_CAR__A, &rcControl, 0);
+			if (status < 0)
+				break;
+			rcControl &= ~(B_EQ_REG_RC_SEL_CAR_FFTMODE__M);
+			rcControl |= B_EQ_REG_RC_SEL_CAR_DIV_ON |
+			    /*  combining enabled */
+			    B_EQ_REG_RC_SEL_CAR_MEAS_A_CC |
+			    B_EQ_REG_RC_SEL_CAR_PASS_A_CC |
+			    B_EQ_REG_RC_SEL_CAR_LOCAL_A_CC;
+			status = Write16(state, B_EQ_REG_RC_SEL_CAR__A, rcControl, 0);
+			if (status < 0)
+				break;
+		}
+	} while (0);
+	return status;
+}
+
+static int SetFrequencyShift(struct drxd_state *state,
+			     u32 offsetFreq, int channelMirrored)
+{
+	int negativeShift = (state->tuner_mirrors == channelMirrored);
+
+	/* Handle all mirroring
+	 *
+	 * Note: ADC mirroring (aliasing) is implictly handled by limiting
+	 * feFsRegAddInc to 28 bits below
+	 * (if the result before masking is more than 28 bits, this means
+	 *  that the ADC is mirroring.
+	 * The masking is in fact the aliasing of the ADC)
+	 *
+	 */
+
+	/* Compute register value, unsigned computation */
+	state->fe_fs_add_incr = MulDiv32(state->intermediate_freq +
+					 offsetFreq,
+					 1 << 28, state->sys_clock_freq);
+	/* Remove integer part */
+	state->fe_fs_add_incr &= 0x0FFFFFFFL;
+	if (negativeShift)
+		state->fe_fs_add_incr = ((1 << 28) - state->fe_fs_add_incr);
+
+	/* Save the frequency shift without tunerOffset compensation
+	   for CtrlGetChannel. */
+	state->org_fe_fs_add_incr = MulDiv32(state->intermediate_freq,
+					     1 << 28, state->sys_clock_freq);
+	/* Remove integer part */
+	state->org_fe_fs_add_incr &= 0x0FFFFFFFL;
+	if (negativeShift)
+		state->org_fe_fs_add_incr = ((1L << 28) -
+					     state->org_fe_fs_add_incr);
+
+	return Write32(state, FE_FS_REG_ADD_INC_LOP__A,
+		       state->fe_fs_add_incr, 0);
+}
+
+static int SetCfgNoiseCalibration(struct drxd_state *state,
+				  struct SNoiseCal *noiseCal)
+{
+	u16 beOptEna;
+	int status = 0;
+
+	do {
+		status = Read16(state, SC_RA_RAM_BE_OPT_ENA__A, &beOptEna, 0);
+		if (status < 0)
+			break;
+		if (noiseCal->cpOpt) {
+			beOptEna |= (1 << SC_RA_RAM_BE_OPT_ENA_CP_OPT);
+		} else {
+			beOptEna &= ~(1 << SC_RA_RAM_BE_OPT_ENA_CP_OPT);
+			status = Write16(state, CP_REG_AC_NEXP_OFFS__A, noiseCal->cpNexpOfs, 0);
+			if (status < 0)
+				break;
+		}
+		status = Write16(state, SC_RA_RAM_BE_OPT_ENA__A, beOptEna, 0);
+		if (status < 0)
+			break;
+
+		if (!state->type_A) {
+			status = Write16(state, B_SC_RA_RAM_CO_TD_CAL_2K__A, noiseCal->tdCal2k, 0);
+			if (status < 0)
+				break;
+			status = Write16(state, B_SC_RA_RAM_CO_TD_CAL_8K__A, noiseCal->tdCal8k, 0);
+			if (status < 0)
+				break;
+		}
+	} while (0);
+
+	return status;
+}
+
+static int DRX_Start(struct drxd_state *state, s32 off)
+{
+	struct dtv_frontend_properties *p = &state->props;
+	int status;
+
+	u16 transmissionParams = 0;
+	u16 operationMode = 0;
+	u16 qpskTdTpsPwr = 0;
+	u16 qam16TdTpsPwr = 0;
+	u16 qam64TdTpsPwr = 0;
+	u32 feIfIncr = 0;
+	u32 bandwidth = 0;
+	int mirrorFreqSpect;
+
+	u16 qpskSnCeGain = 0;
+	u16 qam16SnCeGain = 0;
+	u16 qam64SnCeGain = 0;
+	u16 qpskIsGainMan = 0;
+	u16 qam16IsGainMan = 0;
+	u16 qam64IsGainMan = 0;
+	u16 qpskIsGainExp = 0;
+	u16 qam16IsGainExp = 0;
+	u16 qam64IsGainExp = 0;
+	u16 bandwidthParam = 0;
+
+	if (off < 0)
+		off = (off - 500) / 1000;
+	else
+		off = (off + 500) / 1000;
+
+	do {
+		if (state->drxd_state != DRXD_STOPPED)
+			return -1;
+		status = ResetECOD(state);
+		if (status < 0)
+			break;
+		if (state->type_A) {
+			status = InitSC(state);
+			if (status < 0)
+				break;
+		} else {
+			status = InitFT(state);
+			if (status < 0)
+				break;
+			status = InitCP(state);
+			if (status < 0)
+				break;
+			status = InitCE(state);
+			if (status < 0)
+				break;
+			status = InitEQ(state);
+			if (status < 0)
+				break;
+			status = InitSC(state);
+			if (status < 0)
+				break;
+		}
+
+		/* Restore current IF & RF AGC settings */
+
+		status = SetCfgIfAgc(state, &state->if_agc_cfg);
+		if (status < 0)
+			break;
+		status = SetCfgRfAgc(state, &state->rf_agc_cfg);
+		if (status < 0)
+			break;
+
+		mirrorFreqSpect = (state->props.inversion == INVERSION_ON);
+
+		switch (p->transmission_mode) {
+		default:	/* Not set, detect it automatically */
+			operationMode |= SC_RA_RAM_OP_AUTO_MODE__M;
+			/* fall through , try first guess DRX_FFTMODE_8K */
+		case TRANSMISSION_MODE_8K:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_MODE_8K;
+			if (state->type_A) {
+				status = Write16(state, EC_SB_REG_TR_MODE__A, EC_SB_REG_TR_MODE_8K, 0x0000);
+				if (status < 0)
+					break;
+				qpskSnCeGain = 99;
+				qam16SnCeGain = 83;
+				qam64SnCeGain = 67;
+			}
+			break;
+		case TRANSMISSION_MODE_2K:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_MODE_2K;
+			if (state->type_A) {
+				status = Write16(state, EC_SB_REG_TR_MODE__A, EC_SB_REG_TR_MODE_2K, 0x0000);
+				if (status < 0)
+					break;
+				qpskSnCeGain = 97;
+				qam16SnCeGain = 71;
+				qam64SnCeGain = 65;
+			}
+			break;
+		}
+
+		switch (p->guard_interval) {
+		case GUARD_INTERVAL_1_4:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_4;
+			break;
+		case GUARD_INTERVAL_1_8:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_8;
+			break;
+		case GUARD_INTERVAL_1_16:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_16;
+			break;
+		case GUARD_INTERVAL_1_32:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_32;
+			break;
+		default:	/* Not set, detect it automatically */
+			operationMode |= SC_RA_RAM_OP_AUTO_GUARD__M;
+			/* try first guess 1/4 */
+			transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_4;
+			break;
+		}
+
+		switch (p->hierarchy) {
+		case HIERARCHY_1:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A1;
+			if (state->type_A) {
+				status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0001, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EC_SB_REG_ALPHA__A, 0x0001, 0x0000);
+				if (status < 0)
+					break;
+
+				qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN;
+				qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA1;
+				qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA1;
+
+				qpskIsGainMan =
+				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE;
+				qam16IsGainMan =
+				    SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE;
+				qam64IsGainMan =
+				    SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE;
+
+				qpskIsGainExp =
+				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE;
+				qam16IsGainExp =
+				    SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE;
+				qam64IsGainExp =
+				    SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE;
+			}
+			break;
+
+		case HIERARCHY_2:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A2;
+			if (state->type_A) {
+				status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0002, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EC_SB_REG_ALPHA__A, 0x0002, 0x0000);
+				if (status < 0)
+					break;
+
+				qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN;
+				qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA2;
+				qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA2;
+
+				qpskIsGainMan =
+				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE;
+				qam16IsGainMan =
+				    SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_MAN__PRE;
+				qam64IsGainMan =
+				    SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_MAN__PRE;
+
+				qpskIsGainExp =
+				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE;
+				qam16IsGainExp =
+				    SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_EXP__PRE;
+				qam64IsGainExp =
+				    SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_EXP__PRE;
+			}
+			break;
+		case HIERARCHY_4:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A4;
+			if (state->type_A) {
+				status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0003, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EC_SB_REG_ALPHA__A, 0x0003, 0x0000);
+				if (status < 0)
+					break;
+
+				qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN;
+				qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA4;
+				qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA4;
+
+				qpskIsGainMan =
+				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE;
+				qam16IsGainMan =
+				    SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_MAN__PRE;
+				qam64IsGainMan =
+				    SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_MAN__PRE;
+
+				qpskIsGainExp =
+				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE;
+				qam16IsGainExp =
+				    SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_EXP__PRE;
+				qam64IsGainExp =
+				    SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_EXP__PRE;
+			}
+			break;
+		case HIERARCHY_AUTO:
+		default:
+			/* Not set, detect it automatically, start with none */
+			operationMode |= SC_RA_RAM_OP_AUTO_HIER__M;
+			transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_NO;
+			if (state->type_A) {
+				status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0000, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EC_SB_REG_ALPHA__A, 0x0000, 0x0000);
+				if (status < 0)
+					break;
+
+				qpskTdTpsPwr = EQ_TD_TPS_PWR_QPSK;
+				qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHAN;
+				qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHAN;
+
+				qpskIsGainMan =
+				    SC_RA_RAM_EQ_IS_GAIN_QPSK_MAN__PRE;
+				qam16IsGainMan =
+				    SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE;
+				qam64IsGainMan =
+				    SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE;
+
+				qpskIsGainExp =
+				    SC_RA_RAM_EQ_IS_GAIN_QPSK_EXP__PRE;
+				qam16IsGainExp =
+				    SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE;
+				qam64IsGainExp =
+				    SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE;
+			}
+			break;
+		}
+		status = status;
+		if (status < 0)
+			break;
+
+		switch (p->modulation) {
+		default:
+			operationMode |= SC_RA_RAM_OP_AUTO_CONST__M;
+			/* fall through , try first guess
+			   DRX_CONSTELLATION_QAM64 */
+		case QAM_64:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QAM64;
+			if (state->type_A) {
+				status = Write16(state, EQ_REG_OT_CONST__A, 0x0002, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_64QAM, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0020, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0008, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0002, 0x0000);
+				if (status < 0)
+					break;
+
+				status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qam64TdTpsPwr, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EQ_REG_SN_CEGAIN__A, qam64SnCeGain, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qam64IsGainMan, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qam64IsGainExp, 0x0000);
+				if (status < 0)
+					break;
+			}
+			break;
+		case QPSK:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QPSK;
+			if (state->type_A) {
+				status = Write16(state, EQ_REG_OT_CONST__A, 0x0000, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_QPSK, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0010, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0000, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0000, 0x0000);
+				if (status < 0)
+					break;
+
+				status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qpskTdTpsPwr, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EQ_REG_SN_CEGAIN__A, qpskSnCeGain, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qpskIsGainMan, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qpskIsGainExp, 0x0000);
+				if (status < 0)
+					break;
+			}
+			break;
+
+		case QAM_16:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QAM16;
+			if (state->type_A) {
+				status = Write16(state, EQ_REG_OT_CONST__A, 0x0001, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_16QAM, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0010, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0004, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0000, 0x0000);
+				if (status < 0)
+					break;
+
+				status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qam16TdTpsPwr, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EQ_REG_SN_CEGAIN__A, qam16SnCeGain, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qam16IsGainMan, 0x0000);
+				if (status < 0)
+					break;
+				status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qam16IsGainExp, 0x0000);
+				if (status < 0)
+					break;
+			}
+			break;
+
+		}
+		status = status;
+		if (status < 0)
+			break;
+
+		switch (DRX_CHANNEL_HIGH) {
+		default:
+		case DRX_CHANNEL_AUTO:
+		case DRX_CHANNEL_LOW:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_PRIO_LO;
+			status = Write16(state, EC_SB_REG_PRIOR__A, EC_SB_REG_PRIOR_LO, 0x0000);
+			if (status < 0)
+				break;
+			break;
+		case DRX_CHANNEL_HIGH:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_PRIO_HI;
+			status = Write16(state, EC_SB_REG_PRIOR__A, EC_SB_REG_PRIOR_HI, 0x0000);
+			if (status < 0)
+				break;
+			break;
+
+		}
+
+		switch (p->code_rate_HP) {
+		case FEC_1_2:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_1_2;
+			if (state->type_A) {
+				status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C1_2, 0x0000);
+				if (status < 0)
+					break;
+			}
+			break;
+		default:
+			operationMode |= SC_RA_RAM_OP_AUTO_RATE__M;
+		case FEC_2_3:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_2_3;
+			if (state->type_A) {
+				status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C2_3, 0x0000);
+				if (status < 0)
+					break;
+			}
+			break;
+		case FEC_3_4:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_3_4;
+			if (state->type_A) {
+				status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C3_4, 0x0000);
+				if (status < 0)
+					break;
+			}
+			break;
+		case FEC_5_6:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_5_6;
+			if (state->type_A) {
+				status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C5_6, 0x0000);
+				if (status < 0)
+					break;
+			}
+			break;
+		case FEC_7_8:
+			transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_7_8;
+			if (state->type_A) {
+				status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C7_8, 0x0000);
+				if (status < 0)
+					break;
+			}
+			break;
+		}
+		status = status;
+		if (status < 0)
+			break;
+
+		/* First determine real bandwidth (Hz) */
+		/* Also set delay for impulse noise cruncher (only A2) */
+		/* Also set parameters for EC_OC fix, note
+		   EC_OC_REG_TMD_HIL_MAR is changed
+		   by SC for fix for some 8K,1/8 guard but is restored by
+		   InitEC and ResetEC
+		   functions */
+		switch (p->bandwidth_hz) {
+		case 0:
+			p->bandwidth_hz = 8000000;
+			/* fall through */
+		case 8000000:
+			/* (64/7)*(8/8)*1000000 */
+			bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ;
+
+			bandwidthParam = 0;
+			status = Write16(state,
+					 FE_AG_REG_IND_DEL__A, 50, 0x0000);
+			break;
+		case 7000000:
+			/* (64/7)*(7/8)*1000000 */
+			bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ;
+			bandwidthParam = 0x4807;	/*binary:0100 1000 0000 0111 */
+			status = Write16(state,
+					 FE_AG_REG_IND_DEL__A, 59, 0x0000);
+			break;
+		case 6000000:
+			/* (64/7)*(6/8)*1000000 */
+			bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ;
+			bandwidthParam = 0x0F07;	/*binary: 0000 1111 0000 0111 */
+			status = Write16(state,
+					 FE_AG_REG_IND_DEL__A, 71, 0x0000);
+			break;
+		default:
+			status = -EINVAL;
+		}
+		if (status < 0)
+			break;
+
+		status = Write16(state, SC_RA_RAM_BAND__A, bandwidthParam, 0x0000);
+		if (status < 0)
+			break;
+
+		{
+			u16 sc_config;
+			status = Read16(state, SC_RA_RAM_CONFIG__A, &sc_config, 0);
+			if (status < 0)
+				break;
+
+			/* enable SLAVE mode in 2k 1/32 to
+			   prevent timing change glitches */
+			if ((p->transmission_mode == TRANSMISSION_MODE_2K) &&
+			    (p->guard_interval == GUARD_INTERVAL_1_32)) {
+				/* enable slave */
+				sc_config |= SC_RA_RAM_CONFIG_SLAVE__M;
+			} else {
+				/* disable slave */
+				sc_config &= ~SC_RA_RAM_CONFIG_SLAVE__M;
+			}
+			status = Write16(state, SC_RA_RAM_CONFIG__A, sc_config, 0);
+			if (status < 0)
+				break;
+		}
+
+		status = SetCfgNoiseCalibration(state, &state->noise_cal);
+		if (status < 0)
+			break;
+
+		if (state->cscd_state == CSCD_INIT) {
+			/* switch on SRMM scan in SC */
+			status = Write16(state, SC_RA_RAM_SAMPLE_RATE_COUNT__A, DRXD_OSCDEV_DO_SCAN, 0x0000);
+			if (status < 0)
+				break;
+/*            CHK_ERROR(Write16(SC_RA_RAM_SAMPLE_RATE_STEP__A, DRXD_OSCDEV_STEP, 0x0000));*/
+			state->cscd_state = CSCD_SET;
+		}
+
+		/* Now compute FE_IF_REG_INCR */
+		/*((( SysFreq/BandWidth)/2)/2) -1) * 2^23) =>
+		   ((SysFreq / BandWidth) * (2^21) ) - (2^23) */
+		feIfIncr = MulDiv32(state->sys_clock_freq * 1000,
+				    (1ULL << 21), bandwidth) - (1 << 23);
+		status = Write16(state, FE_IF_REG_INCR0__A, (u16) (feIfIncr & FE_IF_REG_INCR0__M), 0x0000);
+		if (status < 0)
+			break;
+		status = Write16(state, FE_IF_REG_INCR1__A, (u16) ((feIfIncr >> FE_IF_REG_INCR0__W) & FE_IF_REG_INCR1__M), 0x0000);
+		if (status < 0)
+			break;
+		/* Bandwidth setting done */
+
+		/* Mirror & frequency offset */
+		SetFrequencyShift(state, off, mirrorFreqSpect);
+
+		/* Start SC, write channel settings to SC */
+
+		/* Enable SC after setting all other parameters */
+		status = Write16(state, SC_COMM_STATE__A, 0, 0x0000);
+		if (status < 0)
+			break;
+		status = Write16(state, SC_COMM_EXEC__A, 1, 0x0000);
+		if (status < 0)
+			break;
+
+		/* Write SC parameter registers, operation mode */
+#if 1
+		operationMode = (SC_RA_RAM_OP_AUTO_MODE__M |
+				 SC_RA_RAM_OP_AUTO_GUARD__M |
+				 SC_RA_RAM_OP_AUTO_CONST__M |
+				 SC_RA_RAM_OP_AUTO_HIER__M |
+				 SC_RA_RAM_OP_AUTO_RATE__M);
+#endif
+		status = SC_SetPrefParamCommand(state, 0x0000, transmissionParams, operationMode);
+		if (status < 0)
+			break;
+
+		/* Start correct processes to get in lock */
+		status = SC_ProcStartCommand(state, SC_RA_RAM_PROC_LOCKTRACK, SC_RA_RAM_SW_EVENT_RUN_NMASK__M, SC_RA_RAM_LOCKTRACK_MIN);
+		if (status < 0)
+			break;
+
+		status = StartOC(state);
+		if (status < 0)
+			break;
+
+		if (state->operation_mode != OM_Default) {
+			status = StartDiversity(state);
+			if (status < 0)
+				break;
+		}
+
+		state->drxd_state = DRXD_STARTED;
+	} while (0);
+
+	return status;
+}
+
+static int CDRXD(struct drxd_state *state, u32 IntermediateFrequency)
+{
+	u32 ulRfAgcOutputLevel = 0xffffffff;
+	u32 ulRfAgcSettleLevel = 528;	/* Optimum value for MT2060 */
+	u32 ulRfAgcMinLevel = 0;	/* Currently unused */
+	u32 ulRfAgcMaxLevel = DRXD_FE_CTRL_MAX;	/* Currently unused */
+	u32 ulRfAgcSpeed = 0;	/* Currently unused */
+	u32 ulRfAgcMode = 0;	/*2;   Off */
+	u32 ulRfAgcR1 = 820;
+	u32 ulRfAgcR2 = 2200;
+	u32 ulRfAgcR3 = 150;
+	u32 ulIfAgcMode = 0;	/* Auto */
+	u32 ulIfAgcOutputLevel = 0xffffffff;
+	u32 ulIfAgcSettleLevel = 0xffffffff;
+	u32 ulIfAgcMinLevel = 0xffffffff;
+	u32 ulIfAgcMaxLevel = 0xffffffff;
+	u32 ulIfAgcSpeed = 0xffffffff;
+	u32 ulIfAgcR1 = 820;
+	u32 ulIfAgcR2 = 2200;
+	u32 ulIfAgcR3 = 150;
+	u32 ulClock = state->config.clock;
+	u32 ulSerialMode = 0;
+	u32 ulEcOcRegOcModeLop = 4;	/* Dynamic DTO source */
+	u32 ulHiI2cDelay = HI_I2C_DELAY;
+	u32 ulHiI2cBridgeDelay = HI_I2C_BRIDGE_DELAY;
+	u32 ulHiI2cPatch = 0;
+	u32 ulEnvironment = APPENV_PORTABLE;
+	u32 ulEnvironmentDiversity = APPENV_MOBILE;
+	u32 ulIFFilter = IFFILTER_SAW;
+
+	state->if_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
+	state->if_agc_cfg.outputLevel = 0;
+	state->if_agc_cfg.settleLevel = 140;
+	state->if_agc_cfg.minOutputLevel = 0;
+	state->if_agc_cfg.maxOutputLevel = 1023;
+	state->if_agc_cfg.speed = 904;
+
+	if (ulIfAgcMode == 1 && ulIfAgcOutputLevel <= DRXD_FE_CTRL_MAX) {
+		state->if_agc_cfg.ctrlMode = AGC_CTRL_USER;
+		state->if_agc_cfg.outputLevel = (u16) (ulIfAgcOutputLevel);
+	}
+
+	if (ulIfAgcMode == 0 &&
+	    ulIfAgcSettleLevel <= DRXD_FE_CTRL_MAX &&
+	    ulIfAgcMinLevel <= DRXD_FE_CTRL_MAX &&
+	    ulIfAgcMaxLevel <= DRXD_FE_CTRL_MAX &&
+	    ulIfAgcSpeed <= DRXD_FE_CTRL_MAX) {
+		state->if_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
+		state->if_agc_cfg.settleLevel = (u16) (ulIfAgcSettleLevel);
+		state->if_agc_cfg.minOutputLevel = (u16) (ulIfAgcMinLevel);
+		state->if_agc_cfg.maxOutputLevel = (u16) (ulIfAgcMaxLevel);
+		state->if_agc_cfg.speed = (u16) (ulIfAgcSpeed);
+	}
+
+	state->if_agc_cfg.R1 = (u16) (ulIfAgcR1);
+	state->if_agc_cfg.R2 = (u16) (ulIfAgcR2);
+	state->if_agc_cfg.R3 = (u16) (ulIfAgcR3);
+
+	state->rf_agc_cfg.R1 = (u16) (ulRfAgcR1);
+	state->rf_agc_cfg.R2 = (u16) (ulRfAgcR2);
+	state->rf_agc_cfg.R3 = (u16) (ulRfAgcR3);
+
+	state->rf_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
+	/* rest of the RFAgcCfg structure currently unused */
+	if (ulRfAgcMode == 1 && ulRfAgcOutputLevel <= DRXD_FE_CTRL_MAX) {
+		state->rf_agc_cfg.ctrlMode = AGC_CTRL_USER;
+		state->rf_agc_cfg.outputLevel = (u16) (ulRfAgcOutputLevel);
+	}
+
+	if (ulRfAgcMode == 0 &&
+	    ulRfAgcSettleLevel <= DRXD_FE_CTRL_MAX &&
+	    ulRfAgcMinLevel <= DRXD_FE_CTRL_MAX &&
+	    ulRfAgcMaxLevel <= DRXD_FE_CTRL_MAX &&
+	    ulRfAgcSpeed <= DRXD_FE_CTRL_MAX) {
+		state->rf_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
+		state->rf_agc_cfg.settleLevel = (u16) (ulRfAgcSettleLevel);
+		state->rf_agc_cfg.minOutputLevel = (u16) (ulRfAgcMinLevel);
+		state->rf_agc_cfg.maxOutputLevel = (u16) (ulRfAgcMaxLevel);
+		state->rf_agc_cfg.speed = (u16) (ulRfAgcSpeed);
+	}
+
+	if (ulRfAgcMode == 2)
+		state->rf_agc_cfg.ctrlMode = AGC_CTRL_OFF;
+
+	if (ulEnvironment <= 2)
+		state->app_env_default = (enum app_env)
+		    (ulEnvironment);
+	if (ulEnvironmentDiversity <= 2)
+		state->app_env_diversity = (enum app_env)
+		    (ulEnvironmentDiversity);
+
+	if (ulIFFilter == IFFILTER_DISCRETE) {
+		/* discrete filter */
+		state->noise_cal.cpOpt = 0;
+		state->noise_cal.cpNexpOfs = 40;
+		state->noise_cal.tdCal2k = -40;
+		state->noise_cal.tdCal8k = -24;
+	} else {
+		/* SAW filter */
+		state->noise_cal.cpOpt = 1;
+		state->noise_cal.cpNexpOfs = 0;
+		state->noise_cal.tdCal2k = -21;
+		state->noise_cal.tdCal8k = -24;
+	}
+	state->m_EcOcRegOcModeLop = (u16) (ulEcOcRegOcModeLop);
+
+	state->chip_adr = (state->config.demod_address << 1) | 1;
+	switch (ulHiI2cPatch) {
+	case 1:
+		state->m_HiI2cPatch = DRXD_HiI2cPatch_1;
+		break;
+	case 3:
+		state->m_HiI2cPatch = DRXD_HiI2cPatch_3;
+		break;
+	default:
+		state->m_HiI2cPatch = NULL;
+	}
+
+	/* modify tuner and clock attributes */
+	state->intermediate_freq = (u16) (IntermediateFrequency / 1000);
+	/* expected system clock frequency in kHz */
+	state->expected_sys_clock_freq = 48000;
+	/* real system clock frequency in kHz */
+	state->sys_clock_freq = 48000;
+	state->osc_clock_freq = (u16) ulClock;
+	state->osc_clock_deviation = 0;
+	state->cscd_state = CSCD_INIT;
+	state->drxd_state = DRXD_UNINITIALIZED;
+
+	state->PGA = 0;
+	state->type_A = 0;
+	state->tuner_mirrors = 0;
+
+	/* modify MPEG output attributes */
+	state->insert_rs_byte = state->config.insert_rs_byte;
+	state->enable_parallel = (ulSerialMode != 1);
+
+	/* Timing div, 250ns/Psys */
+	/* Timing div, = ( delay (nano seconds) * sysclk (kHz) )/ 1000 */
+
+	state->hi_cfg_timing_div = (u16) ((state->sys_clock_freq / 1000) *
+					  ulHiI2cDelay) / 1000;
+	/* Bridge delay, uses oscilator clock */
+	/* Delay = ( delay (nano seconds) * oscclk (kHz) )/ 1000 */
+	state->hi_cfg_bridge_delay = (u16) ((state->osc_clock_freq / 1000) *
+					    ulHiI2cBridgeDelay) / 1000;
+
+	state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_CONSUMER;
+	/* state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_PRO; */
+	state->m_FeAgRegAgAgcSio = DRXD_DEF_AG_AGC_SIO;
+	return 0;
+}
+
+int DRXD_init(struct drxd_state *state, const u8 * fw, u32 fw_size)
+{
+	int status = 0;
+	u32 driverVersion;
+
+	if (state->init_done)
+		return 0;
+
+	CDRXD(state, state->config.IF ? state->config.IF : 36000000);
+
+	do {
+		state->operation_mode = OM_Default;
+
+		status = SetDeviceTypeId(state);
+		if (status < 0)
+			break;
+
+		/* Apply I2c address patch to B1 */
+		if (!state->type_A && state->m_HiI2cPatch != NULL)
+			status = WriteTable(state, state->m_HiI2cPatch);
+			if (status < 0)
+				break;
+
+		if (state->type_A) {
+			/* HI firmware patch for UIO readout,
+			   avoid clearing of result register */
+			status = Write16(state, 0x43012D, 0x047f, 0);
+			if (status < 0)
+				break;
+		}
+
+		status = HI_ResetCommand(state);
+		if (status < 0)
+			break;
+
+		status = StopAllProcessors(state);
+		if (status < 0)
+			break;
+		status = InitCC(state);
+		if (status < 0)
+			break;
+
+		state->osc_clock_deviation = 0;
+
+		if (state->config.osc_deviation)
+			state->osc_clock_deviation =
+			    state->config.osc_deviation(state->priv, 0, 0);
+		{
+			/* Handle clock deviation */
+			s32 devB;
+			s32 devA = (s32) (state->osc_clock_deviation) *
+			    (s32) (state->expected_sys_clock_freq);
+			/* deviation in kHz */
+			s32 deviation = (devA / (1000000L));
+			/* rounding, signed */
+			if (devA > 0)
+				devB = (2);
+			else
+				devB = (-2);
+			if ((devB * (devA % 1000000L) > 1000000L)) {
+				/* add +1 or -1 */
+				deviation += (devB / 2);
+			}
+
+			state->sys_clock_freq =
+			    (u16) ((state->expected_sys_clock_freq) +
+				   deviation);
+		}
+		status = InitHI(state);
+		if (status < 0)
+			break;
+		status = InitAtomicRead(state);
+		if (status < 0)
+			break;
+
+		status = EnableAndResetMB(state);
+		if (status < 0)
+			break;
+		if (state->type_A)
+			status = ResetCEFR(state);
+			if (status < 0)
+				break;
+
+		if (fw) {
+			status = DownloadMicrocode(state, fw, fw_size);
+			if (status < 0)
+				break;
+		} else {
+			status = DownloadMicrocode(state, state->microcode, state->microcode_length);
+			if (status < 0)
+				break;
+		}
+
+		if (state->PGA) {
+			state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_PRO;
+			SetCfgPga(state, 0);	/* PGA = 0 dB */
+		} else {
+			state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_CONSUMER;
+		}
+
+		state->m_FeAgRegAgAgcSio = DRXD_DEF_AG_AGC_SIO;
+
+		status = InitFE(state);
+		if (status < 0)
+			break;
+		status = InitFT(state);
+		if (status < 0)
+			break;
+		status = InitCP(state);
+		if (status < 0)
+			break;
+		status = InitCE(state);
+		if (status < 0)
+			break;
+		status = InitEQ(state);
+		if (status < 0)
+			break;
+		status = InitEC(state);
+		if (status < 0)
+			break;
+		status = InitSC(state);
+		if (status < 0)
+			break;
+
+		status = SetCfgIfAgc(state, &state->if_agc_cfg);
+		if (status < 0)
+			break;
+		status = SetCfgRfAgc(state, &state->rf_agc_cfg);
+		if (status < 0)
+			break;
+
+		state->cscd_state = CSCD_INIT;
+		status = Write16(state, SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+		if (status < 0)
+			break;
+		status = Write16(state, LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+		if (status < 0)
+			break;
+
+		driverVersion = (((VERSION_MAJOR / 10) << 4) +
+				 (VERSION_MAJOR % 10)) << 24;
+		driverVersion += (((VERSION_MINOR / 10) << 4) +
+				  (VERSION_MINOR % 10)) << 16;
+		driverVersion += ((VERSION_PATCH / 1000) << 12) +
+		    ((VERSION_PATCH / 100) << 8) +
+		    ((VERSION_PATCH / 10) << 4) + (VERSION_PATCH % 10);
+
+		status = Write32(state, SC_RA_RAM_DRIVER_VERSION__AX, driverVersion, 0);
+		if (status < 0)
+			break;
+
+		status = StopOC(state);
+		if (status < 0)
+			break;
+
+		state->drxd_state = DRXD_STOPPED;
+		state->init_done = 1;
+		status = 0;
+	} while (0);
+	return status;
+}
+
+int DRXD_status(struct drxd_state *state, u32 * pLockStatus)
+{
+	DRX_GetLockStatus(state, pLockStatus);
+
+	/*if (*pLockStatus&DRX_LOCK_MPEG) */
+	if (*pLockStatus & DRX_LOCK_FEC) {
+		ConfigureMPEGOutput(state, 1);
+		/* Get status again, in case we have MPEG lock now */
+		/*DRX_GetLockStatus(state, pLockStatus); */
+	}
+
+	return 0;
+}
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static int drxd_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+{
+	struct drxd_state *state = fe->demodulator_priv;
+	u32 value;
+	int res;
+
+	res = ReadIFAgc(state, &value);
+	if (res < 0)
+		*strength = 0;
+	else
+		*strength = 0xffff - (value << 4);
+	return 0;
+}
+
+static int drxd_read_status(struct dvb_frontend *fe, fe_status_t * status)
+{
+	struct drxd_state *state = fe->demodulator_priv;
+	u32 lock;
+
+	DRXD_status(state, &lock);
+	*status = 0;
+	/* No MPEG lock in V255 firmware, bug ? */
+#if 1
+	if (lock & DRX_LOCK_MPEG)
+		*status |= FE_HAS_LOCK;
+#else
+	if (lock & DRX_LOCK_FEC)
+		*status |= FE_HAS_LOCK;
+#endif
+	if (lock & DRX_LOCK_FEC)
+		*status |= FE_HAS_VITERBI | FE_HAS_SYNC;
+	if (lock & DRX_LOCK_DEMOD)
+		*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+
+	return 0;
+}
+
+static int drxd_init(struct dvb_frontend *fe)
+{
+	struct drxd_state *state = fe->demodulator_priv;
+	int err = 0;
+
+/*	if (request_firmware(&state->fw, "drxd.fw", state->dev)<0) */
+	return DRXD_init(state, 0, 0);
+
+	err = DRXD_init(state, state->fw->data, state->fw->size);
+	release_firmware(state->fw);
+	return err;
+}
+
+int drxd_config_i2c(struct dvb_frontend *fe, int onoff)
+{
+	struct drxd_state *state = fe->demodulator_priv;
+
+	if (state->config.disable_i2c_gate_ctrl == 1)
+		return 0;
+
+	return DRX_ConfigureI2CBridge(state, onoff);
+}
+EXPORT_SYMBOL(drxd_config_i2c);
+
+static int drxd_get_tune_settings(struct dvb_frontend *fe,
+				  struct dvb_frontend_tune_settings *sets)
+{
+	sets->min_delay_ms = 10000;
+	sets->max_drift = 0;
+	sets->step_size = 0;
+	return 0;
+}
+
+static int drxd_read_ber(struct dvb_frontend *fe, u32 * ber)
+{
+	*ber = 0;
+	return 0;
+}
+
+static int drxd_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+	*snr = 0;
+	return 0;
+}
+
+static int drxd_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
+{
+	*ucblocks = 0;
+	return 0;
+}
+
+static int drxd_sleep(struct dvb_frontend *fe)
+{
+	struct drxd_state *state = fe->demodulator_priv;
+
+	ConfigureMPEGOutput(state, 0);
+	return 0;
+}
+
+static int drxd_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	return drxd_config_i2c(fe, enable);
+}
+
+static int drxd_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct drxd_state *state = fe->demodulator_priv;
+	s32 off = 0;
+
+	state->props = *p;
+	DRX_Stop(state);
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	msleep(200);
+
+	return DRX_Start(state, off);
+}
+
+static void drxd_release(struct dvb_frontend *fe)
+{
+	struct drxd_state *state = fe->demodulator_priv;
+
+	kfree(state);
+}
+
+static struct dvb_frontend_ops drxd_ops = {
+	.delsys = { SYS_DVBT},
+	.info = {
+		 .name = "Micronas DRXD DVB-T",
+		 .frequency_min = 47125000,
+		 .frequency_max = 855250000,
+		 .frequency_stepsize = 166667,
+		 .frequency_tolerance = 0,
+		 .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+		 FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+		 FE_CAN_FEC_AUTO |
+		 FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+		 FE_CAN_QAM_AUTO |
+		 FE_CAN_TRANSMISSION_MODE_AUTO |
+		 FE_CAN_GUARD_INTERVAL_AUTO |
+		 FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS},
+
+	.release = drxd_release,
+	.init = drxd_init,
+	.sleep = drxd_sleep,
+	.i2c_gate_ctrl = drxd_i2c_gate_ctrl,
+
+	.set_frontend = drxd_set_frontend,
+	.get_tune_settings = drxd_get_tune_settings,
+
+	.read_status = drxd_read_status,
+	.read_ber = drxd_read_ber,
+	.read_signal_strength = drxd_read_signal_strength,
+	.read_snr = drxd_read_snr,
+	.read_ucblocks = drxd_read_ucblocks,
+};
+
+struct dvb_frontend *drxd_attach(const struct drxd_config *config,
+				 void *priv, struct i2c_adapter *i2c,
+				 struct device *dev)
+{
+	struct drxd_state *state = NULL;
+
+	state = kmalloc(sizeof(struct drxd_state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+	memset(state, 0, sizeof(*state));
+
+	memcpy(&state->ops, &drxd_ops, sizeof(struct dvb_frontend_ops));
+	state->dev = dev;
+	state->config = *config;
+	state->i2c = i2c;
+	state->priv = priv;
+
+	mutex_init(&state->mutex);
+
+	if (Read16(state, 0, 0, 0) < 0)
+		goto error;
+
+	memcpy(&state->frontend.ops, &drxd_ops,
+	       sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	ConfigureMPEGOutput(state, 0);
+	return &state->frontend;
+
+error:
+	printk(KERN_ERR "drxd: not found\n");
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(drxd_attach);
+
+MODULE_DESCRIPTION("DRXD driver");
+MODULE_AUTHOR("Micronas");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/drxd_map_firm.h b/drivers/media/dvb-frontends/drxd_map_firm.h
new file mode 100644
index 0000000..6bc553a
--- /dev/null
+++ b/drivers/media/dvb-frontends/drxd_map_firm.h
@@ -0,0 +1,1013 @@
+/*
+ * drx3973d_map_firm.h
+ *
+ * Copyright (C) 2006-2007 Micronas
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __DRX3973D_MAP__H__
+#define __DRX3973D_MAP__H__
+
+/*
+ * Note: originally, this file contained 12000+ lines of data
+ * Probably a few lines for every firwmare assembler instruction. However,
+ * only a few defines were actually used. So, removed all uneeded lines.
+ * If ever needed, the other lines can be easily obtained via git history.
+ */
+
+#define HI_COMM_EXEC__A                                              0x400000
+#define HI_COMM_MB__A                                                0x400002
+#define HI_CT_REG_COMM_STATE__A                                      0x410001
+#define HI_RA_RAM_SRV_RES__A                                         0x420031
+#define HI_RA_RAM_SRV_CMD__A                                         0x420032
+#define   HI_RA_RAM_SRV_CMD_RESET                                    0x2
+#define   HI_RA_RAM_SRV_CMD_CONFIG                                   0x3
+#define   HI_RA_RAM_SRV_CMD_EXECUTE                                  0x6
+#define HI_RA_RAM_SRV_RST_KEY__A                                     0x420033
+#define   HI_RA_RAM_SRV_RST_KEY_ACT                                  0x3973
+#define HI_RA_RAM_SRV_CFG_KEY__A                                     0x420033
+#define HI_RA_RAM_SRV_CFG_DIV__A                                     0x420034
+#define HI_RA_RAM_SRV_CFG_BDL__A                                     0x420035
+#define HI_RA_RAM_SRV_CFG_WUP__A                                     0x420036
+#define HI_RA_RAM_SRV_CFG_ACT__A                                     0x420037
+#define     HI_RA_RAM_SRV_CFG_ACT_SLV0_ON                            0x1
+#define   HI_RA_RAM_SRV_CFG_ACT_BRD__M                               0x4
+#define     HI_RA_RAM_SRV_CFG_ACT_BRD_OFF                            0x0
+#define     HI_RA_RAM_SRV_CFG_ACT_BRD_ON                             0x4
+#define     HI_RA_RAM_SRV_CFG_ACT_PWD_EXE                            0x8
+#define HI_RA_RAM_USR_BEGIN__A                                       0x420040
+#define HI_IF_RAM_TRP_BPT0__AX                                       0x430000
+#define HI_IF_RAM_USR_BEGIN__A                                       0x430200
+#define SC_COMM_EXEC__A                                              0x800000
+#define     SC_COMM_EXEC_CTL_STOP                                    0x0
+#define SC_COMM_STATE__A                                             0x800001
+#define SC_RA_RAM_PARAM0__A                                          0x820040
+#define SC_RA_RAM_PARAM1__A                                          0x820041
+#define SC_RA_RAM_CMD_ADDR__A                                        0x820042
+#define SC_RA_RAM_CMD__A                                             0x820043
+#define   SC_RA_RAM_CMD_PROC_START                                   0x1
+#define   SC_RA_RAM_CMD_SET_PREF_PARAM                               0x3
+#define   SC_RA_RAM_CMD_GET_OP_PARAM                                 0x5
+#define   SC_RA_RAM_SW_EVENT_RUN_NMASK__M                            0x1
+#define   SC_RA_RAM_LOCKTRACK_MIN                                    0x1
+#define     SC_RA_RAM_OP_PARAM_MODE_2K                               0x0
+#define     SC_RA_RAM_OP_PARAM_MODE_8K                               0x1
+#define     SC_RA_RAM_OP_PARAM_GUARD_32                              0x0
+#define     SC_RA_RAM_OP_PARAM_GUARD_16                              0x4
+#define     SC_RA_RAM_OP_PARAM_GUARD_8                               0x8
+#define     SC_RA_RAM_OP_PARAM_GUARD_4                               0xC
+#define     SC_RA_RAM_OP_PARAM_CONST_QPSK                            0x0
+#define     SC_RA_RAM_OP_PARAM_CONST_QAM16                           0x10
+#define     SC_RA_RAM_OP_PARAM_CONST_QAM64                           0x20
+#define     SC_RA_RAM_OP_PARAM_HIER_NO                               0x0
+#define     SC_RA_RAM_OP_PARAM_HIER_A1                               0x40
+#define     SC_RA_RAM_OP_PARAM_HIER_A2                               0x80
+#define     SC_RA_RAM_OP_PARAM_HIER_A4                               0xC0
+#define     SC_RA_RAM_OP_PARAM_RATE_1_2                              0x0
+#define     SC_RA_RAM_OP_PARAM_RATE_2_3                              0x200
+#define     SC_RA_RAM_OP_PARAM_RATE_3_4                              0x400
+#define     SC_RA_RAM_OP_PARAM_RATE_5_6                              0x600
+#define     SC_RA_RAM_OP_PARAM_RATE_7_8                              0x800
+#define     SC_RA_RAM_OP_PARAM_PRIO_HI                               0x0
+#define     SC_RA_RAM_OP_PARAM_PRIO_LO                               0x1000
+#define   SC_RA_RAM_OP_AUTO_MODE__M                                  0x1
+#define   SC_RA_RAM_OP_AUTO_GUARD__M                                 0x2
+#define   SC_RA_RAM_OP_AUTO_CONST__M                                 0x4
+#define   SC_RA_RAM_OP_AUTO_HIER__M                                  0x8
+#define   SC_RA_RAM_OP_AUTO_RATE__M                                  0x10
+#define SC_RA_RAM_LOCK__A                                            0x82004B
+#define   SC_RA_RAM_LOCK_DEMOD__M                                    0x1
+#define   SC_RA_RAM_LOCK_FEC__M                                      0x2
+#define   SC_RA_RAM_LOCK_MPEG__M                                     0x4
+#define SC_RA_RAM_BE_OPT_ENA__A                                      0x82004C
+#define   SC_RA_RAM_BE_OPT_ENA_CP_OPT                                0x1
+#define SC_RA_RAM_BE_OPT_DELAY__A                                    0x82004D
+#define SC_RA_RAM_CONFIG__A                                          0x820050
+#define   SC_RA_RAM_CONFIG_FR_ENABLE__M                              0x4
+#define   SC_RA_RAM_CONFIG_FREQSCAN__M                               0x10
+#define   SC_RA_RAM_CONFIG_SLAVE__M                                  0x20
+#define SC_RA_RAM_IF_SAVE__AX                                        0x82008E
+#define SC_RA_RAM_IR_COARSE_2K_LENGTH__A                             0x8200D1
+#define SC_RA_RAM_IR_COARSE_2K_LENGTH__PRE                           0x9
+#define SC_RA_RAM_IR_COARSE_2K_FREQINC__A                            0x8200D2
+#define SC_RA_RAM_IR_COARSE_2K_FREQINC__PRE                          0x4
+#define SC_RA_RAM_IR_COARSE_2K_KAISINC__A                            0x8200D3
+#define SC_RA_RAM_IR_COARSE_2K_KAISINC__PRE                          0x100
+#define SC_RA_RAM_IR_COARSE_8K_LENGTH__A                             0x8200D4
+#define SC_RA_RAM_IR_COARSE_8K_LENGTH__PRE                           0x8
+#define SC_RA_RAM_IR_COARSE_8K_FREQINC__A                            0x8200D5
+#define SC_RA_RAM_IR_COARSE_8K_FREQINC__PRE                          0x8
+#define SC_RA_RAM_IR_COARSE_8K_KAISINC__A                            0x8200D6
+#define SC_RA_RAM_IR_COARSE_8K_KAISINC__PRE                          0x200
+#define SC_RA_RAM_IR_FINE_2K_LENGTH__A                               0x8200D7
+#define SC_RA_RAM_IR_FINE_2K_LENGTH__PRE                             0x9
+#define SC_RA_RAM_IR_FINE_2K_FREQINC__A                              0x8200D8
+#define SC_RA_RAM_IR_FINE_2K_FREQINC__PRE                            0x4
+#define SC_RA_RAM_IR_FINE_2K_KAISINC__A                              0x8200D9
+#define SC_RA_RAM_IR_FINE_2K_KAISINC__PRE                            0x100
+#define SC_RA_RAM_IR_FINE_8K_LENGTH__A                               0x8200DA
+#define SC_RA_RAM_IR_FINE_8K_LENGTH__PRE                             0xB
+#define SC_RA_RAM_IR_FINE_8K_FREQINC__A                              0x8200DB
+#define SC_RA_RAM_IR_FINE_8K_FREQINC__PRE                            0x1
+#define SC_RA_RAM_IR_FINE_8K_KAISINC__A                              0x8200DC
+#define SC_RA_RAM_IR_FINE_8K_KAISINC__PRE                            0x40
+#define SC_RA_RAM_ECHO_SHIFT_LIM__A                                  0x8200DD
+#define SC_RA_RAM_SAMPLE_RATE_COUNT__A                               0x8200E8
+#define SC_RA_RAM_SAMPLE_RATE_STEP__A                                0x8200E9
+#define SC_RA_RAM_BAND__A                                            0x8200EC
+#define SC_RA_RAM_LC_ABS_2K__A                                       0x8200F4
+#define SC_RA_RAM_LC_ABS_2K__PRE                                     0x1F
+#define SC_RA_RAM_LC_ABS_8K__A                                       0x8200F5
+#define SC_RA_RAM_LC_ABS_8K__PRE                                     0x1F
+#define SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE                        0x1D6
+#define SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE                        0x4
+#define SC_RA_RAM_EQ_IS_GAIN_QPSK_MAN__PRE                           0x1BB
+#define SC_RA_RAM_EQ_IS_GAIN_QPSK_EXP__PRE                           0x5
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE                          0x1EF
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE                          0x5
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_MAN__PRE                       0x15E
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_EXP__PRE                       0x5
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_MAN__PRE                       0x11A
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_EXP__PRE                       0x6
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE                          0x1FB
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE                          0x5
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_MAN__PRE                       0x12F
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_EXP__PRE                       0x5
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_MAN__PRE                       0x197
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_EXP__PRE                       0x5
+#define SC_RA_RAM_DRIVER_VERSION__AX                                 0x8201FE
+#define   SC_RA_RAM_PROC_LOCKTRACK                                   0x0
+#define FE_COMM_EXEC__A                                              0xC00000
+#define FE_AD_REG_COMM_EXEC__A                                       0xC10000
+#define FE_AD_REG_FDB_IN__A                                          0xC10012
+#define FE_AD_REG_PD__A                                              0xC10013
+#define FE_AD_REG_INVEXT__A                                          0xC10014
+#define FE_AD_REG_CLKNEG__A                                          0xC10015
+#define FE_AG_REG_COMM_EXEC__A                                       0xC20000
+#define FE_AG_REG_AG_MODE_LOP__A                                     0xC20010
+#define   FE_AG_REG_AG_MODE_LOP_MODE_4__M                            0x10
+#define     FE_AG_REG_AG_MODE_LOP_MODE_4_STATIC                      0x0
+#define     FE_AG_REG_AG_MODE_LOP_MODE_4_DYNAMIC                     0x10
+#define   FE_AG_REG_AG_MODE_LOP_MODE_5__M                            0x20
+#define     FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC                      0x0
+#define   FE_AG_REG_AG_MODE_LOP_MODE_C__M                            0x1000
+#define     FE_AG_REG_AG_MODE_LOP_MODE_C_STATIC                      0x0
+#define     FE_AG_REG_AG_MODE_LOP_MODE_C_DYNAMIC                     0x1000
+#define   FE_AG_REG_AG_MODE_LOP_MODE_E__M                            0x4000
+#define     FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC                      0x0
+#define     FE_AG_REG_AG_MODE_LOP_MODE_E_DYNAMIC                     0x4000
+#define FE_AG_REG_AG_MODE_HIP__A                                     0xC20011
+#define FE_AG_REG_AG_PGA_MODE__A                                     0xC20012
+#define   FE_AG_REG_AG_PGA_MODE_PFY_PCY_AFY_REN                      0x0
+#define   FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN                      0x1
+#define FE_AG_REG_AG_AGC_SIO__A                                      0xC20013
+#define   FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M                          0x2
+#define     FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT                    0x0
+#define     FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_INPUT                     0x2
+#define FE_AG_REG_AG_PWD__A                                          0xC20015
+#define   FE_AG_REG_AG_PWD_PWD_PD2__M                                0x2
+#define     FE_AG_REG_AG_PWD_PWD_PD2_DISABLE                         0x0
+#define     FE_AG_REG_AG_PWD_PWD_PD2_ENABLE                          0x2
+#define FE_AG_REG_DCE_AUR_CNT__A                                     0xC20016
+#define FE_AG_REG_DCE_RUR_CNT__A                                     0xC20017
+#define FE_AG_REG_ACE_AUR_CNT__A                                     0xC2001A
+#define FE_AG_REG_ACE_RUR_CNT__A                                     0xC2001B
+#define FE_AG_REG_CDR_RUR_CNT__A                                     0xC20020
+#define FE_AG_REG_EGC_RUR_CNT__A                                     0xC20024
+#define FE_AG_REG_EGC_SET_LVL__A                                     0xC20025
+#define FE_AG_REG_EGC_SET_LVL__M                                     0x1FF
+#define FE_AG_REG_EGC_FLA_RGN__A                                     0xC20026
+#define FE_AG_REG_EGC_SLO_RGN__A                                     0xC20027
+#define FE_AG_REG_EGC_JMP_PSN__A                                     0xC20028
+#define FE_AG_REG_EGC_FLA_INC__A                                     0xC20029
+#define FE_AG_REG_EGC_FLA_DEC__A                                     0xC2002A
+#define FE_AG_REG_EGC_SLO_INC__A                                     0xC2002B
+#define FE_AG_REG_EGC_SLO_DEC__A                                     0xC2002C
+#define FE_AG_REG_EGC_FAS_INC__A                                     0xC2002D
+#define FE_AG_REG_EGC_FAS_DEC__A                                     0xC2002E
+#define FE_AG_REG_PM1_AGC_WRI__A                                     0xC20030
+#define FE_AG_REG_PM1_AGC_WRI__M                                     0x7FF
+#define FE_AG_REG_GC1_AGC_RIC__A                                     0xC20031
+#define FE_AG_REG_GC1_AGC_OFF__A                                     0xC20032
+#define FE_AG_REG_GC1_AGC_MAX__A                                     0xC20033
+#define FE_AG_REG_GC1_AGC_MIN__A                                     0xC20034
+#define FE_AG_REG_GC1_AGC_DAT__A                                     0xC20035
+#define FE_AG_REG_GC1_AGC_DAT__M                                     0x3FF
+#define FE_AG_REG_PM2_AGC_WRI__A                                     0xC20036
+#define FE_AG_REG_IND_WIN__A                                         0xC2003C
+#define FE_AG_REG_IND_THD_LOL__A                                     0xC2003D
+#define FE_AG_REG_IND_THD_HIL__A                                     0xC2003E
+#define FE_AG_REG_IND_DEL__A                                         0xC2003F
+#define FE_AG_REG_IND_PD1_WRI__A                                     0xC20040
+#define FE_AG_REG_PDA_AUR_CNT__A                                     0xC20041
+#define FE_AG_REG_PDA_RUR_CNT__A                                     0xC20042
+#define FE_AG_REG_PDA_AVE_DAT__A                                     0xC20043
+#define FE_AG_REG_PDC_RUR_CNT__A                                     0xC20044
+#define FE_AG_REG_PDC_SET_LVL__A                                     0xC20045
+#define FE_AG_REG_PDC_FLA_RGN__A                                     0xC20046
+#define FE_AG_REG_PDC_JMP_PSN__A                                     0xC20047
+#define FE_AG_REG_PDC_FLA_STP__A                                     0xC20048
+#define FE_AG_REG_PDC_SLO_STP__A                                     0xC20049
+#define FE_AG_REG_PDC_PD2_WRI__A                                     0xC2004A
+#define FE_AG_REG_PDC_MAP_DAT__A                                     0xC2004B
+#define FE_AG_REG_PDC_MAX__A                                         0xC2004C
+#define FE_AG_REG_TGA_AUR_CNT__A                                     0xC2004D
+#define FE_AG_REG_TGA_RUR_CNT__A                                     0xC2004E
+#define FE_AG_REG_TGA_AVE_DAT__A                                     0xC2004F
+#define FE_AG_REG_TGC_RUR_CNT__A                                     0xC20050
+#define FE_AG_REG_TGC_SET_LVL__A                                     0xC20051
+#define FE_AG_REG_TGC_SET_LVL__M                                     0x3F
+#define FE_AG_REG_TGC_FLA_RGN__A                                     0xC20052
+#define FE_AG_REG_TGC_JMP_PSN__A                                     0xC20053
+#define FE_AG_REG_TGC_FLA_STP__A                                     0xC20054
+#define FE_AG_REG_TGC_SLO_STP__A                                     0xC20055
+#define FE_AG_REG_TGC_MAP_DAT__A                                     0xC20056
+#define FE_AG_REG_FGA_AUR_CNT__A                                     0xC20057
+#define FE_AG_REG_FGA_RUR_CNT__A                                     0xC20058
+#define FE_AG_REG_FGM_WRI__A                                         0xC20061
+#define FE_AG_REG_BGC_FGC_WRI__A                                     0xC20068
+#define FE_AG_REG_BGC_CGC_WRI__A                                     0xC20069
+#define FE_FS_REG_COMM_EXEC__A                                       0xC30000
+#define FE_FS_REG_ADD_INC_LOP__A                                     0xC30010
+#define FE_FD_REG_COMM_EXEC__A                                       0xC40000
+#define FE_FD_REG_SCL__A                                             0xC40010
+#define FE_FD_REG_MAX_LEV__A                                         0xC40011
+#define FE_FD_REG_NR__A                                              0xC40012
+#define FE_FD_REG_MEAS_VAL__A                                        0xC40014
+#define FE_IF_REG_COMM_EXEC__A                                       0xC50000
+#define FE_IF_REG_INCR0__A                                           0xC50010
+#define FE_IF_REG_INCR0__W                                           16
+#define FE_IF_REG_INCR0__M                                           0xFFFF
+#define FE_IF_REG_INCR1__A                                           0xC50011
+#define FE_IF_REG_INCR1__M                                           0xFF
+#define FE_CF_REG_COMM_EXEC__A                                       0xC60000
+#define FE_CF_REG_SCL__A                                             0xC60010
+#define FE_CF_REG_MAX_LEV__A                                         0xC60011
+#define FE_CF_REG_NR__A                                              0xC60012
+#define FE_CF_REG_IMP_VAL__A                                         0xC60013
+#define FE_CF_REG_MEAS_VAL__A                                        0xC60014
+#define FE_CU_REG_COMM_EXEC__A                                       0xC70000
+#define FE_CU_REG_FRM_CNT_RST__A                                     0xC70011
+#define FE_CU_REG_FRM_CNT_STR__A                                     0xC70012
+#define FT_COMM_EXEC__A                                              0x1000000
+#define FT_REG_COMM_EXEC__A                                          0x1010000
+#define CP_COMM_EXEC__A                                              0x1400000
+#define CP_REG_COMM_EXEC__A                                          0x1410000
+#define CP_REG_INTERVAL__A                                           0x1410011
+#define CP_REG_BR_SPL_OFFSET__A                                      0x1410023
+#define CP_REG_BR_STR_DEL__A                                         0x1410024
+#define CP_REG_RT_ANG_INC0__A                                        0x1410030
+#define CP_REG_RT_ANG_INC1__A                                        0x1410031
+#define CP_REG_RT_DETECT_ENA__A                                      0x1410032
+#define CP_REG_RT_DETECT_TRH__A                                      0x1410033
+#define CP_REG_RT_EXP_MARG__A                                        0x141003E
+#define CP_REG_AC_NEXP_OFFS__A                                       0x1410040
+#define CP_REG_AC_AVER_POW__A                                        0x1410041
+#define CP_REG_AC_MAX_POW__A                                         0x1410042
+#define CP_REG_AC_WEIGHT_MAN__A                                      0x1410043
+#define CP_REG_AC_WEIGHT_EXP__A                                      0x1410044
+#define CP_REG_AC_AMP_MODE__A                                        0x1410047
+#define CP_REG_AC_AMP_FIX__A                                         0x1410048
+#define CP_REG_AC_ANG_MODE__A                                        0x141004A
+#define CE_COMM_EXEC__A                                              0x1800000
+#define CE_REG_COMM_EXEC__A                                          0x1810000
+#define CE_REG_TAPSET__A                                             0x1810011
+#define CE_REG_AVG_POW__A                                            0x1810012
+#define CE_REG_MAX_POW__A                                            0x1810013
+#define CE_REG_ATT__A                                                0x1810014
+#define CE_REG_NRED__A                                               0x1810015
+#define CE_REG_NE_ERR_SELECT__A                                      0x1810043
+#define CE_REG_NE_TD_CAL__A                                          0x1810044
+#define CE_REG_NE_MIXAVG__A                                          0x1810046
+#define CE_REG_NE_NUPD_OFS__A                                        0x1810047
+#define CE_REG_PE_NEXP_OFFS__A                                       0x1810050
+#define CE_REG_PE_TIMESHIFT__A                                       0x1810051
+#define CE_REG_TP_A0_TAP_NEW__A                                      0x1810064
+#define CE_REG_TP_A0_TAP_NEW_VALID__A                                0x1810065
+#define CE_REG_TP_A0_MU_LMS_STEP__A                                  0x1810066
+#define CE_REG_TP_A1_TAP_NEW__A                                      0x1810068
+#define CE_REG_TP_A1_TAP_NEW_VALID__A                                0x1810069
+#define CE_REG_TP_A1_MU_LMS_STEP__A                                  0x181006A
+#define CE_REG_TI_NEXP_OFFS__A                                       0x1810070
+#define CE_REG_FI_SHT_INCR__A                                        0x1810090
+#define CE_REG_FI_EXP_NORM__A                                        0x1810091
+#define CE_REG_IR_INPUTSEL__A                                        0x18100A0
+#define CE_REG_IR_STARTPOS__A                                        0x18100A1
+#define CE_REG_IR_NEXP_THRES__A                                      0x18100A2
+#define CE_REG_FR_TREAL00__A                                         0x1820010
+#define CE_REG_FR_TIMAG00__A                                         0x1820011
+#define CE_REG_FR_TREAL01__A                                         0x1820012
+#define CE_REG_FR_TIMAG01__A                                         0x1820013
+#define CE_REG_FR_TREAL02__A                                         0x1820014
+#define CE_REG_FR_TIMAG02__A                                         0x1820015
+#define CE_REG_FR_TREAL03__A                                         0x1820016
+#define CE_REG_FR_TIMAG03__A                                         0x1820017
+#define CE_REG_FR_TREAL04__A                                         0x1820018
+#define CE_REG_FR_TIMAG04__A                                         0x1820019
+#define CE_REG_FR_TREAL05__A                                         0x182001A
+#define CE_REG_FR_TIMAG05__A                                         0x182001B
+#define CE_REG_FR_TREAL06__A                                         0x182001C
+#define CE_REG_FR_TIMAG06__A                                         0x182001D
+#define CE_REG_FR_TREAL07__A                                         0x182001E
+#define CE_REG_FR_TIMAG07__A                                         0x182001F
+#define CE_REG_FR_TREAL08__A                                         0x1820020
+#define CE_REG_FR_TIMAG08__A                                         0x1820021
+#define CE_REG_FR_TREAL09__A                                         0x1820022
+#define CE_REG_FR_TIMAG09__A                                         0x1820023
+#define CE_REG_FR_TREAL10__A                                         0x1820024
+#define CE_REG_FR_TIMAG10__A                                         0x1820025
+#define CE_REG_FR_TREAL11__A                                         0x1820026
+#define CE_REG_FR_TIMAG11__A                                         0x1820027
+#define CE_REG_FR_MID_TAP__A                                         0x1820028
+#define CE_REG_FR_SQS_G00__A                                         0x1820029
+#define CE_REG_FR_SQS_G01__A                                         0x182002A
+#define CE_REG_FR_SQS_G02__A                                         0x182002B
+#define CE_REG_FR_SQS_G03__A                                         0x182002C
+#define CE_REG_FR_SQS_G04__A                                         0x182002D
+#define CE_REG_FR_SQS_G05__A                                         0x182002E
+#define CE_REG_FR_SQS_G06__A                                         0x182002F
+#define CE_REG_FR_SQS_G07__A                                         0x1820030
+#define CE_REG_FR_SQS_G08__A                                         0x1820031
+#define CE_REG_FR_SQS_G09__A                                         0x1820032
+#define CE_REG_FR_SQS_G10__A                                         0x1820033
+#define CE_REG_FR_SQS_G11__A                                         0x1820034
+#define CE_REG_FR_SQS_G12__A                                         0x1820035
+#define CE_REG_FR_RIO_G00__A                                         0x1820036
+#define CE_REG_FR_RIO_G01__A                                         0x1820037
+#define CE_REG_FR_RIO_G02__A                                         0x1820038
+#define CE_REG_FR_RIO_G03__A                                         0x1820039
+#define CE_REG_FR_RIO_G04__A                                         0x182003A
+#define CE_REG_FR_RIO_G05__A                                         0x182003B
+#define CE_REG_FR_RIO_G06__A                                         0x182003C
+#define CE_REG_FR_RIO_G07__A                                         0x182003D
+#define CE_REG_FR_RIO_G08__A                                         0x182003E
+#define CE_REG_FR_RIO_G09__A                                         0x182003F
+#define CE_REG_FR_RIO_G10__A                                         0x1820040
+#define CE_REG_FR_MODE__A                                            0x1820041
+#define CE_REG_FR_SQS_TRH__A                                         0x1820042
+#define CE_REG_FR_RIO_GAIN__A                                        0x1820043
+#define CE_REG_FR_BYPASS__A                                          0x1820044
+#define CE_REG_FR_PM_SET__A                                          0x1820045
+#define CE_REG_FR_ERR_SH__A                                          0x1820046
+#define CE_REG_FR_MAN_SH__A                                          0x1820047
+#define CE_REG_FR_TAP_SH__A                                          0x1820048
+#define EQ_COMM_EXEC__A                                              0x1C00000
+#define EQ_REG_COMM_EXEC__A                                          0x1C10000
+#define EQ_REG_COMM_MB__A                                            0x1C10002
+#define EQ_REG_IS_GAIN_MAN__A                                        0x1C10015
+#define EQ_REG_IS_GAIN_EXP__A                                        0x1C10016
+#define EQ_REG_IS_CLIP_EXP__A                                        0x1C10017
+#define EQ_REG_SN_CEGAIN__A                                          0x1C1002A
+#define EQ_REG_SN_OFFSET__A                                          0x1C1002B
+#define EQ_REG_RC_SEL_CAR__A                                         0x1C10032
+#define   EQ_REG_RC_SEL_CAR_INIT                                     0x0
+#define     EQ_REG_RC_SEL_CAR_DIV_ON                                 0x1
+#define     EQ_REG_RC_SEL_CAR_PASS_A_CC                              0x0
+#define     EQ_REG_RC_SEL_CAR_PASS_B_CE                              0x2
+#define     EQ_REG_RC_SEL_CAR_LOCAL_A_CC                             0x0
+#define     EQ_REG_RC_SEL_CAR_LOCAL_B_CE                             0x8
+#define     EQ_REG_RC_SEL_CAR_MEAS_A_CC                              0x0
+#define     EQ_REG_RC_SEL_CAR_MEAS_B_CE                              0x20
+#define EQ_REG_OT_CONST__A                                           0x1C10046
+#define EQ_REG_OT_ALPHA__A                                           0x1C10047
+#define EQ_REG_OT_QNT_THRES0__A                                      0x1C10048
+#define EQ_REG_OT_QNT_THRES1__A                                      0x1C10049
+#define EQ_REG_OT_CSI_STEP__A                                        0x1C1004A
+#define EQ_REG_OT_CSI_OFFSET__A                                      0x1C1004B
+#define EQ_REG_TD_REQ_SMB_CNT__A                                     0x1C10061
+#define EQ_REG_TD_TPS_PWR_OFS__A                                     0x1C10062
+#define EC_SB_REG_COMM_EXEC__A                                       0x2010000
+#define EC_SB_REG_TR_MODE__A                                         0x2010010
+#define   EC_SB_REG_TR_MODE_8K                                       0x0
+#define   EC_SB_REG_TR_MODE_2K                                       0x1
+#define EC_SB_REG_CONST__A                                           0x2010011
+#define   EC_SB_REG_CONST_QPSK                                       0x0
+#define   EC_SB_REG_CONST_16QAM                                      0x1
+#define   EC_SB_REG_CONST_64QAM                                      0x2
+#define EC_SB_REG_ALPHA__A                                           0x2010012
+#define EC_SB_REG_PRIOR__A                                           0x2010013
+#define   EC_SB_REG_PRIOR_HI                                         0x0
+#define   EC_SB_REG_PRIOR_LO                                         0x1
+#define EC_SB_REG_CSI_HI__A                                          0x2010014
+#define EC_SB_REG_CSI_LO__A                                          0x2010015
+#define EC_SB_REG_SMB_TGL__A                                         0x2010016
+#define EC_SB_REG_SNR_HI__A                                          0x2010017
+#define EC_SB_REG_SNR_MID__A                                         0x2010018
+#define EC_SB_REG_SNR_LO__A                                          0x2010019
+#define EC_SB_REG_SCALE_MSB__A                                       0x201001A
+#define EC_SB_REG_SCALE_BIT2__A                                      0x201001B
+#define EC_SB_REG_SCALE_LSB__A                                       0x201001C
+#define EC_SB_REG_CSI_OFS__A                                         0x201001D
+#define EC_VD_REG_COMM_EXEC__A                                       0x2090000
+#define EC_VD_REG_FORCE__A                                           0x2090010
+#define EC_VD_REG_SET_CODERATE__A                                    0x2090011
+#define   EC_VD_REG_SET_CODERATE_C1_2                                0x0
+#define   EC_VD_REG_SET_CODERATE_C2_3                                0x1
+#define   EC_VD_REG_SET_CODERATE_C3_4                                0x2
+#define   EC_VD_REG_SET_CODERATE_C5_6                                0x3
+#define   EC_VD_REG_SET_CODERATE_C7_8                                0x4
+#define EC_VD_REG_REQ_SMB_CNT__A                                     0x2090012
+#define EC_VD_REG_RLK_ENA__A                                         0x2090014
+#define EC_OD_REG_COMM_EXEC__A                                       0x2110000
+#define EC_OD_REG_SYNC__A                                            0x2110010
+#define EC_OD_DEINT_RAM__A                                           0x2120000
+#define EC_RS_REG_COMM_EXEC__A                                       0x2130000
+#define EC_RS_REG_REQ_PCK_CNT__A                                     0x2130010
+#define EC_RS_REG_VAL__A                                             0x2130011
+#define   EC_RS_REG_VAL_PCK                                          0x1
+#define EC_RS_EC_RAM__A                                              0x2140000
+#define EC_OC_REG_COMM_EXEC__A                                       0x2150000
+#define     EC_OC_REG_COMM_EXEC_CTL_ACTIVE                           0x1
+#define     EC_OC_REG_COMM_EXEC_CTL_HOLD                             0x2
+#define EC_OC_REG_COMM_INT_STA__A                                    0x2150007
+#define EC_OC_REG_OC_MODE_LOP__A                                     0x2150010
+#define   EC_OC_REG_OC_MODE_LOP_PAR_ENA__M                           0x1
+#define     EC_OC_REG_OC_MODE_LOP_PAR_ENA_ENABLE                     0x0
+#define     EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE                    0x1
+#define   EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC__M                       0x4
+#define     EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC_STATIC                 0x0
+#define   EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE__M                       0x80
+#define     EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE_SERIAL                 0x80
+#define EC_OC_REG_OC_MODE_HIP__A                                     0x2150011
+#define     EC_OC_REG_OC_MODE_HIP_MPG_BUS_SRC_MONITOR                0x10
+#define   EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M                       0x200
+#define     EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_DISABLE                0x0
+#define     EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_ENABLE                 0x200
+#define EC_OC_REG_OC_MPG_SIO__A                                      0x2150012
+#define EC_OC_REG_OC_MPG_SIO__M                                      0xFFF
+#define EC_OC_REG_OC_MON_SIO__A                                      0x2150013
+#define EC_OC_REG_DTO_INC_LOP__A                                     0x2150014
+#define EC_OC_REG_DTO_INC_HIP__A                                     0x2150015
+#define EC_OC_REG_SNC_ISC_LVL__A                                     0x2150016
+#define   EC_OC_REG_SNC_ISC_LVL_OSC__M                               0xF0
+#define EC_OC_REG_TMD_TOP_MODE__A                                    0x215001D
+#define EC_OC_REG_TMD_TOP_CNT__A                                     0x215001E
+#define EC_OC_REG_TMD_HIL_MAR__A                                     0x215001F
+#define EC_OC_REG_TMD_LOL_MAR__A                                     0x2150020
+#define EC_OC_REG_TMD_CUR_CNT__A                                     0x2150021
+#define EC_OC_REG_AVR_ASH_CNT__A                                     0x2150023
+#define EC_OC_REG_AVR_BSH_CNT__A                                     0x2150024
+#define EC_OC_REG_RCN_MODE__A                                        0x2150027
+#define EC_OC_REG_RCN_CRA_LOP__A                                     0x2150028
+#define EC_OC_REG_RCN_CRA_HIP__A                                     0x2150029
+#define EC_OC_REG_RCN_CST_LOP__A                                     0x215002A
+#define EC_OC_REG_RCN_CST_HIP__A                                     0x215002B
+#define EC_OC_REG_RCN_SET_LVL__A                                     0x215002C
+#define EC_OC_REG_RCN_GAI_LVL__A                                     0x215002D
+#define EC_OC_REG_RCN_CLP_LOP__A                                     0x2150032
+#define EC_OC_REG_RCN_CLP_HIP__A                                     0x2150033
+#define EC_OC_REG_RCN_MAP_LOP__A                                     0x2150034
+#define EC_OC_REG_RCN_MAP_HIP__A                                     0x2150035
+#define EC_OC_REG_OCR_MPG_UOS__A                                     0x2150036
+#define EC_OC_REG_OCR_MPG_UOS__M                                     0xFFF
+#define   EC_OC_REG_OCR_MPG_UOS_INIT                                 0x0
+#define EC_OC_REG_OCR_MPG_USR_DAT__A                                 0x2150038
+#define EC_OC_REG_OCR_MON_UOS__A                                     0x2150039
+#define     EC_OC_REG_OCR_MON_UOS_DAT_0_ENABLE                       0x1
+#define     EC_OC_REG_OCR_MON_UOS_DAT_1_ENABLE                       0x2
+#define     EC_OC_REG_OCR_MON_UOS_DAT_2_ENABLE                       0x4
+#define     EC_OC_REG_OCR_MON_UOS_DAT_3_ENABLE                       0x8
+#define     EC_OC_REG_OCR_MON_UOS_DAT_4_ENABLE                       0x10
+#define     EC_OC_REG_OCR_MON_UOS_DAT_5_ENABLE                       0x20
+#define     EC_OC_REG_OCR_MON_UOS_DAT_6_ENABLE                       0x40
+#define     EC_OC_REG_OCR_MON_UOS_DAT_7_ENABLE                       0x80
+#define     EC_OC_REG_OCR_MON_UOS_DAT_8_ENABLE                       0x100
+#define     EC_OC_REG_OCR_MON_UOS_DAT_9_ENABLE                       0x200
+#define     EC_OC_REG_OCR_MON_UOS_VAL_ENABLE                         0x400
+#define     EC_OC_REG_OCR_MON_UOS_CLK_ENABLE                         0x800
+#define EC_OC_REG_OCR_MON_WRI__A                                     0x215003A
+#define   EC_OC_REG_OCR_MON_WRI_INIT                                 0x0
+#define EC_OC_REG_IPR_INV_MPG__A                                     0x2150045
+#define CC_REG_OSC_MODE__A                                           0x2410010
+#define   CC_REG_OSC_MODE_M20                                        0x1
+#define CC_REG_PLL_MODE__A                                           0x2410011
+#define     CC_REG_PLL_MODE_BYPASS_PLL                               0x1
+#define     CC_REG_PLL_MODE_PUMP_CUR_12                              0x14
+#define CC_REG_REF_DIVIDE__A                                         0x2410012
+#define CC_REG_PWD_MODE__A                                           0x2410015
+#define   CC_REG_PWD_MODE_DOWN_PLL                                   0x2
+#define CC_REG_UPDATE__A                                             0x2410017
+#define   CC_REG_UPDATE_KEY                                          0x3973
+#define CC_REG_JTAGID_L__A                                           0x2410019
+#define LC_COMM_EXEC__A                                              0x2800000
+#define LC_RA_RAM_IFINCR_NOM_L__A                                    0x282000C
+#define LC_RA_RAM_FILTER_SYM_SET__A                                  0x282001A
+#define LC_RA_RAM_FILTER_SYM_SET__PRE                                0x3E8
+#define LC_RA_RAM_FILTER_CRMM_A__A                                   0x2820060
+#define LC_RA_RAM_FILTER_CRMM_A__PRE                                 0x4
+#define LC_RA_RAM_FILTER_CRMM_B__A                                   0x2820061
+#define LC_RA_RAM_FILTER_CRMM_B__PRE                                 0x1
+#define LC_RA_RAM_FILTER_SRMM_A__A                                   0x2820068
+#define LC_RA_RAM_FILTER_SRMM_A__PRE                                 0x4
+#define LC_RA_RAM_FILTER_SRMM_B__A                                   0x2820069
+#define LC_RA_RAM_FILTER_SRMM_B__PRE                                 0x1
+#define B_HI_COMM_EXEC__A                                            0x400000
+#define B_HI_COMM_MB__A                                              0x400002
+#define B_HI_CT_REG_COMM_STATE__A                                    0x410001
+#define B_HI_RA_RAM_SRV_RES__A                                       0x420031
+#define B_HI_RA_RAM_SRV_CMD__A                                       0x420032
+#define   B_HI_RA_RAM_SRV_CMD_RESET                                  0x2
+#define   B_HI_RA_RAM_SRV_CMD_CONFIG                                 0x3
+#define   B_HI_RA_RAM_SRV_CMD_EXECUTE                                0x6
+#define B_HI_RA_RAM_SRV_RST_KEY__A                                   0x420033
+#define   B_HI_RA_RAM_SRV_RST_KEY_ACT                                0x3973
+#define B_HI_RA_RAM_SRV_CFG_KEY__A                                   0x420033
+#define B_HI_RA_RAM_SRV_CFG_DIV__A                                   0x420034
+#define B_HI_RA_RAM_SRV_CFG_BDL__A                                   0x420035
+#define B_HI_RA_RAM_SRV_CFG_WUP__A                                   0x420036
+#define B_HI_RA_RAM_SRV_CFG_ACT__A                                   0x420037
+#define     B_HI_RA_RAM_SRV_CFG_ACT_SLV0_ON                          0x1
+#define   B_HI_RA_RAM_SRV_CFG_ACT_BRD__M                             0x4
+#define     B_HI_RA_RAM_SRV_CFG_ACT_BRD_OFF                          0x0
+#define     B_HI_RA_RAM_SRV_CFG_ACT_BRD_ON                           0x4
+#define     B_HI_RA_RAM_SRV_CFG_ACT_PWD_EXE                          0x8
+#define B_HI_RA_RAM_USR_BEGIN__A                                     0x420040
+#define B_HI_IF_RAM_TRP_BPT0__AX                                     0x430000
+#define B_HI_IF_RAM_USR_BEGIN__A                                     0x430200
+#define B_SC_COMM_EXEC__A                                            0x800000
+#define     B_SC_COMM_EXEC_CTL_STOP                                  0x0
+#define B_SC_COMM_STATE__A                                           0x800001
+#define B_SC_RA_RAM_PARAM0__A                                        0x820040
+#define B_SC_RA_RAM_PARAM1__A                                        0x820041
+#define B_SC_RA_RAM_CMD_ADDR__A                                      0x820042
+#define B_SC_RA_RAM_CMD__A                                           0x820043
+#define   B_SC_RA_RAM_CMD_PROC_START                                 0x1
+#define   B_SC_RA_RAM_CMD_SET_PREF_PARAM                             0x3
+#define   B_SC_RA_RAM_CMD_GET_OP_PARAM                               0x5
+#define   B_SC_RA_RAM_SW_EVENT_RUN_NMASK__M                          0x1
+#define   B_SC_RA_RAM_LOCKTRACK_MIN                                  0x1
+#define     B_SC_RA_RAM_OP_PARAM_MODE_2K                             0x0
+#define     B_SC_RA_RAM_OP_PARAM_MODE_8K                             0x1
+#define     B_SC_RA_RAM_OP_PARAM_GUARD_32                            0x0
+#define     B_SC_RA_RAM_OP_PARAM_GUARD_16                            0x4
+#define     B_SC_RA_RAM_OP_PARAM_GUARD_8                             0x8
+#define     B_SC_RA_RAM_OP_PARAM_GUARD_4                             0xC
+#define     B_SC_RA_RAM_OP_PARAM_CONST_QPSK                          0x0
+#define     B_SC_RA_RAM_OP_PARAM_CONST_QAM16                         0x10
+#define     B_SC_RA_RAM_OP_PARAM_CONST_QAM64                         0x20
+#define     B_SC_RA_RAM_OP_PARAM_HIER_NO                             0x0
+#define     B_SC_RA_RAM_OP_PARAM_HIER_A1                             0x40
+#define     B_SC_RA_RAM_OP_PARAM_HIER_A2                             0x80
+#define     B_SC_RA_RAM_OP_PARAM_HIER_A4                             0xC0
+#define     B_SC_RA_RAM_OP_PARAM_RATE_1_2                            0x0
+#define     B_SC_RA_RAM_OP_PARAM_RATE_2_3                            0x200
+#define     B_SC_RA_RAM_OP_PARAM_RATE_3_4                            0x400
+#define     B_SC_RA_RAM_OP_PARAM_RATE_5_6                            0x600
+#define     B_SC_RA_RAM_OP_PARAM_RATE_7_8                            0x800
+#define     B_SC_RA_RAM_OP_PARAM_PRIO_HI                             0x0
+#define     B_SC_RA_RAM_OP_PARAM_PRIO_LO                             0x1000
+#define   B_SC_RA_RAM_OP_AUTO_MODE__M                                0x1
+#define   B_SC_RA_RAM_OP_AUTO_GUARD__M                               0x2
+#define   B_SC_RA_RAM_OP_AUTO_CONST__M                               0x4
+#define   B_SC_RA_RAM_OP_AUTO_HIER__M                                0x8
+#define   B_SC_RA_RAM_OP_AUTO_RATE__M                                0x10
+#define B_SC_RA_RAM_LOCK__A                                          0x82004B
+#define   B_SC_RA_RAM_LOCK_DEMOD__M                                  0x1
+#define   B_SC_RA_RAM_LOCK_FEC__M                                    0x2
+#define   B_SC_RA_RAM_LOCK_MPEG__M                                   0x4
+#define B_SC_RA_RAM_BE_OPT_ENA__A                                    0x82004C
+#define   B_SC_RA_RAM_BE_OPT_ENA_CP_OPT                              0x1
+#define B_SC_RA_RAM_BE_OPT_DELAY__A                                  0x82004D
+#define B_SC_RA_RAM_CONFIG__A                                        0x820050
+#define   B_SC_RA_RAM_CONFIG_FR_ENABLE__M                            0x4
+#define   B_SC_RA_RAM_CONFIG_FREQSCAN__M                             0x10
+#define   B_SC_RA_RAM_CONFIG_SLAVE__M                                0x20
+#define   B_SC_RA_RAM_CONFIG_DIV_BLANK_ENABLE__M                     0x200
+#define   B_SC_RA_RAM_CONFIG_DIV_ECHO_ENABLE__M                      0x400
+#define B_SC_RA_RAM_CO_TD_CAL_2K__A                                  0x82005D
+#define B_SC_RA_RAM_CO_TD_CAL_8K__A                                  0x82005E
+#define B_SC_RA_RAM_IF_SAVE__AX                                      0x82008E
+#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_32__A                         0x820098
+#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_16__A                         0x820099
+#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_8__A                          0x82009A
+#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_4__A                          0x82009B
+#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_32__A                         0x82009C
+#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_16__A                         0x82009D
+#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_8__A                          0x82009E
+#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_4__A                          0x82009F
+#define B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A                           0x8200D1
+#define B_SC_RA_RAM_IR_COARSE_2K_LENGTH__PRE                         0x9
+#define B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A                          0x8200D2
+#define B_SC_RA_RAM_IR_COARSE_2K_FREQINC__PRE                        0x4
+#define B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A                          0x8200D3
+#define B_SC_RA_RAM_IR_COARSE_2K_KAISINC__PRE                        0x100
+#define B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A                           0x8200D4
+#define B_SC_RA_RAM_IR_COARSE_8K_LENGTH__PRE                         0x8
+#define B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A                          0x8200D5
+#define B_SC_RA_RAM_IR_COARSE_8K_FREQINC__PRE                        0x8
+#define B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A                          0x8200D6
+#define B_SC_RA_RAM_IR_COARSE_8K_KAISINC__PRE                        0x200
+#define B_SC_RA_RAM_IR_FINE_2K_LENGTH__A                             0x8200D7
+#define B_SC_RA_RAM_IR_FINE_2K_LENGTH__PRE                           0x9
+#define B_SC_RA_RAM_IR_FINE_2K_FREQINC__A                            0x8200D8
+#define B_SC_RA_RAM_IR_FINE_2K_FREQINC__PRE                          0x4
+#define B_SC_RA_RAM_IR_FINE_2K_KAISINC__A                            0x8200D9
+#define B_SC_RA_RAM_IR_FINE_2K_KAISINC__PRE                          0x100
+#define B_SC_RA_RAM_IR_FINE_8K_LENGTH__A                             0x8200DA
+#define B_SC_RA_RAM_IR_FINE_8K_LENGTH__PRE                           0xB
+#define B_SC_RA_RAM_IR_FINE_8K_FREQINC__A                            0x8200DB
+#define B_SC_RA_RAM_IR_FINE_8K_FREQINC__PRE                          0x1
+#define B_SC_RA_RAM_IR_FINE_8K_KAISINC__A                            0x8200DC
+#define B_SC_RA_RAM_IR_FINE_8K_KAISINC__PRE                          0x40
+#define B_SC_RA_RAM_ECHO_SHIFT_LIM__A                                0x8200DD
+#define B_SC_RA_RAM_SAMPLE_RATE_COUNT__A                             0x8200E8
+#define B_SC_RA_RAM_SAMPLE_RATE_STEP__A                              0x8200E9
+#define B_SC_RA_RAM_BAND__A                                          0x8200EC
+#define B_SC_RA_RAM_LC_ABS_2K__A                                     0x8200F4
+#define B_SC_RA_RAM_LC_ABS_2K__PRE                                   0x1F
+#define B_SC_RA_RAM_LC_ABS_8K__A                                     0x8200F5
+#define B_SC_RA_RAM_LC_ABS_8K__PRE                                   0x1F
+#define B_SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE                      0x100
+#define B_SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE                      0x4
+#define B_SC_RA_RAM_EQ_IS_GAIN_QPSK_MAN__PRE                         0x1E2
+#define B_SC_RA_RAM_EQ_IS_GAIN_QPSK_EXP__PRE                         0x4
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE                        0x10D
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE                        0x5
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_MAN__PRE                     0x17D
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_EXP__PRE                     0x4
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_MAN__PRE                     0x133
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_EXP__PRE                     0x5
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE                        0x114
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE                        0x5
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_MAN__PRE                     0x14A
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_EXP__PRE                     0x4
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_MAN__PRE                     0x1BB
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_EXP__PRE                     0x4
+#define B_SC_RA_RAM_DRIVER_VERSION__AX                               0x8201FE
+#define   B_SC_RA_RAM_PROC_LOCKTRACK                                 0x0
+#define B_FE_COMM_EXEC__A                                            0xC00000
+#define B_FE_AD_REG_COMM_EXEC__A                                     0xC10000
+#define B_FE_AD_REG_FDB_IN__A                                        0xC10012
+#define B_FE_AD_REG_PD__A                                            0xC10013
+#define B_FE_AD_REG_INVEXT__A                                        0xC10014
+#define B_FE_AD_REG_CLKNEG__A                                        0xC10015
+#define B_FE_AG_REG_COMM_EXEC__A                                     0xC20000
+#define B_FE_AG_REG_AG_MODE_LOP__A                                   0xC20010
+#define   B_FE_AG_REG_AG_MODE_LOP_MODE_4__M                          0x10
+#define     B_FE_AG_REG_AG_MODE_LOP_MODE_4_STATIC                    0x0
+#define     B_FE_AG_REG_AG_MODE_LOP_MODE_4_DYNAMIC                   0x10
+#define   B_FE_AG_REG_AG_MODE_LOP_MODE_5__M                          0x20
+#define     B_FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC                    0x0
+#define   B_FE_AG_REG_AG_MODE_LOP_MODE_C__M                          0x1000
+#define     B_FE_AG_REG_AG_MODE_LOP_MODE_C_STATIC                    0x0
+#define     B_FE_AG_REG_AG_MODE_LOP_MODE_C_DYNAMIC                   0x1000
+#define   B_FE_AG_REG_AG_MODE_LOP_MODE_E__M                          0x4000
+#define     B_FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC                    0x0
+#define     B_FE_AG_REG_AG_MODE_LOP_MODE_E_DYNAMIC                   0x4000
+#define B_FE_AG_REG_AG_MODE_HIP__A                                   0xC20011
+#define   B_FE_AG_REG_AG_MODE_HIP_MODE_J__M                          0x8
+#define     B_FE_AG_REG_AG_MODE_HIP_MODE_J_STATIC                    0x0
+#define     B_FE_AG_REG_AG_MODE_HIP_MODE_J_DYNAMIC                   0x8
+#define B_FE_AG_REG_AG_PGA_MODE__A                                   0xC20012
+#define   B_FE_AG_REG_AG_PGA_MODE_PFY_PCY_AFY_REN                    0x0
+#define   B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN                    0x1
+#define B_FE_AG_REG_AG_AGC_SIO__A                                    0xC20013
+#define   B_FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M                        0x2
+#define     B_FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT                  0x0
+#define     B_FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_INPUT                   0x2
+#define B_FE_AG_REG_AG_PWD__A                                        0xC20015
+#define   B_FE_AG_REG_AG_PWD_PWD_PD2__M                              0x2
+#define     B_FE_AG_REG_AG_PWD_PWD_PD2_DISABLE                       0x0
+#define     B_FE_AG_REG_AG_PWD_PWD_PD2_ENABLE                        0x2
+#define B_FE_AG_REG_DCE_AUR_CNT__A                                   0xC20016
+#define B_FE_AG_REG_DCE_RUR_CNT__A                                   0xC20017
+#define B_FE_AG_REG_ACE_AUR_CNT__A                                   0xC2001A
+#define B_FE_AG_REG_ACE_RUR_CNT__A                                   0xC2001B
+#define B_FE_AG_REG_CDR_RUR_CNT__A                                   0xC20020
+#define B_FE_AG_REG_EGC_RUR_CNT__A                                   0xC20024
+#define B_FE_AG_REG_EGC_SET_LVL__A                                   0xC20025
+#define B_FE_AG_REG_EGC_SET_LVL__M                                   0x1FF
+#define B_FE_AG_REG_EGC_FLA_RGN__A                                   0xC20026
+#define B_FE_AG_REG_EGC_SLO_RGN__A                                   0xC20027
+#define B_FE_AG_REG_EGC_JMP_PSN__A                                   0xC20028
+#define B_FE_AG_REG_EGC_FLA_INC__A                                   0xC20029
+#define B_FE_AG_REG_EGC_FLA_DEC__A                                   0xC2002A
+#define B_FE_AG_REG_EGC_SLO_INC__A                                   0xC2002B
+#define B_FE_AG_REG_EGC_SLO_DEC__A                                   0xC2002C
+#define B_FE_AG_REG_EGC_FAS_INC__A                                   0xC2002D
+#define B_FE_AG_REG_EGC_FAS_DEC__A                                   0xC2002E
+#define B_FE_AG_REG_PM1_AGC_WRI__A                                   0xC20030
+#define B_FE_AG_REG_PM1_AGC_WRI__M                                   0x7FF
+#define B_FE_AG_REG_GC1_AGC_RIC__A                                   0xC20031
+#define B_FE_AG_REG_GC1_AGC_OFF__A                                   0xC20032
+#define B_FE_AG_REG_GC1_AGC_MAX__A                                   0xC20033
+#define B_FE_AG_REG_GC1_AGC_MIN__A                                   0xC20034
+#define B_FE_AG_REG_GC1_AGC_DAT__A                                   0xC20035
+#define B_FE_AG_REG_GC1_AGC_DAT__M                                   0x3FF
+#define B_FE_AG_REG_PM2_AGC_WRI__A                                   0xC20036
+#define B_FE_AG_REG_IND_WIN__A                                       0xC2003C
+#define B_FE_AG_REG_IND_THD_LOL__A                                   0xC2003D
+#define B_FE_AG_REG_IND_THD_HIL__A                                   0xC2003E
+#define B_FE_AG_REG_IND_DEL__A                                       0xC2003F
+#define B_FE_AG_REG_IND_PD1_WRI__A                                   0xC20040
+#define B_FE_AG_REG_PDA_AUR_CNT__A                                   0xC20041
+#define B_FE_AG_REG_PDA_RUR_CNT__A                                   0xC20042
+#define B_FE_AG_REG_PDA_AVE_DAT__A                                   0xC20043
+#define B_FE_AG_REG_PDC_RUR_CNT__A                                   0xC20044
+#define B_FE_AG_REG_PDC_SET_LVL__A                                   0xC20045
+#define B_FE_AG_REG_PDC_FLA_RGN__A                                   0xC20046
+#define B_FE_AG_REG_PDC_JMP_PSN__A                                   0xC20047
+#define B_FE_AG_REG_PDC_FLA_STP__A                                   0xC20048
+#define B_FE_AG_REG_PDC_SLO_STP__A                                   0xC20049
+#define B_FE_AG_REG_PDC_PD2_WRI__A                                   0xC2004A
+#define B_FE_AG_REG_PDC_MAP_DAT__A                                   0xC2004B
+#define B_FE_AG_REG_PDC_MAX__A                                       0xC2004C
+#define B_FE_AG_REG_TGA_AUR_CNT__A                                   0xC2004D
+#define B_FE_AG_REG_TGA_RUR_CNT__A                                   0xC2004E
+#define B_FE_AG_REG_TGA_AVE_DAT__A                                   0xC2004F
+#define B_FE_AG_REG_TGC_RUR_CNT__A                                   0xC20050
+#define B_FE_AG_REG_TGC_SET_LVL__A                                   0xC20051
+#define B_FE_AG_REG_TGC_SET_LVL__M                                   0x3F
+#define B_FE_AG_REG_TGC_FLA_RGN__A                                   0xC20052
+#define B_FE_AG_REG_TGC_JMP_PSN__A                                   0xC20053
+#define B_FE_AG_REG_TGC_FLA_STP__A                                   0xC20054
+#define B_FE_AG_REG_TGC_SLO_STP__A                                   0xC20055
+#define B_FE_AG_REG_TGC_MAP_DAT__A                                   0xC20056
+#define B_FE_AG_REG_FGM_WRI__A                                       0xC20061
+#define B_FE_AG_REG_BGC_FGC_WRI__A                                   0xC20068
+#define B_FE_AG_REG_BGC_CGC_WRI__A                                   0xC20069
+#define B_FE_FS_REG_COMM_EXEC__A                                     0xC30000
+#define B_FE_FS_REG_ADD_INC_LOP__A                                   0xC30010
+#define B_FE_FD_REG_COMM_EXEC__A                                     0xC40000
+#define B_FE_FD_REG_SCL__A                                           0xC40010
+#define B_FE_FD_REG_MAX_LEV__A                                       0xC40011
+#define B_FE_FD_REG_NR__A                                            0xC40012
+#define B_FE_FD_REG_MEAS_VAL__A                                      0xC40014
+#define B_FE_IF_REG_COMM_EXEC__A                                     0xC50000
+#define B_FE_IF_REG_INCR0__A                                         0xC50010
+#define B_FE_IF_REG_INCR0__W                                         16
+#define B_FE_IF_REG_INCR0__M                                         0xFFFF
+#define B_FE_IF_REG_INCR1__A                                         0xC50011
+#define B_FE_IF_REG_INCR1__M                                         0xFF
+#define B_FE_CF_REG_COMM_EXEC__A                                     0xC60000
+#define B_FE_CF_REG_SCL__A                                           0xC60010
+#define B_FE_CF_REG_MAX_LEV__A                                       0xC60011
+#define B_FE_CF_REG_NR__A                                            0xC60012
+#define B_FE_CF_REG_IMP_VAL__A                                       0xC60013
+#define B_FE_CF_REG_MEAS_VAL__A                                      0xC60014
+#define B_FE_CU_REG_COMM_EXEC__A                                     0xC70000
+#define B_FE_CU_REG_FRM_CNT_RST__A                                   0xC70011
+#define B_FE_CU_REG_FRM_CNT_STR__A                                   0xC70012
+#define B_FE_CU_REG_CTR_NFC_ICR__A                                   0xC70020
+#define B_FE_CU_REG_CTR_NFC_OCR__A                                   0xC70021
+#define B_FE_CU_REG_DIV_NFC_CLP__A                                   0xC70027
+#define B_FT_COMM_EXEC__A                                            0x1000000
+#define B_FT_REG_COMM_EXEC__A                                        0x1010000
+#define B_CP_COMM_EXEC__A                                            0x1400000
+#define B_CP_REG_COMM_EXEC__A                                        0x1410000
+#define B_CP_REG_INTERVAL__A                                         0x1410011
+#define B_CP_REG_BR_SPL_OFFSET__A                                    0x1410023
+#define B_CP_REG_BR_STR_DEL__A                                       0x1410024
+#define B_CP_REG_RT_ANG_INC0__A                                      0x1410030
+#define B_CP_REG_RT_ANG_INC1__A                                      0x1410031
+#define B_CP_REG_RT_DETECT_TRH__A                                    0x1410033
+#define B_CP_REG_AC_NEXP_OFFS__A                                     0x1410040
+#define B_CP_REG_AC_AVER_POW__A                                      0x1410041
+#define B_CP_REG_AC_MAX_POW__A                                       0x1410042
+#define B_CP_REG_AC_WEIGHT_MAN__A                                    0x1410043
+#define B_CP_REG_AC_WEIGHT_EXP__A                                    0x1410044
+#define B_CP_REG_AC_AMP_MODE__A                                      0x1410047
+#define B_CP_REG_AC_AMP_FIX__A                                       0x1410048
+#define B_CP_REG_AC_ANG_MODE__A                                      0x141004A
+#define B_CE_COMM_EXEC__A                                            0x1800000
+#define B_CE_REG_COMM_EXEC__A                                        0x1810000
+#define B_CE_REG_TAPSET__A                                           0x1810011
+#define B_CE_REG_AVG_POW__A                                          0x1810012
+#define B_CE_REG_MAX_POW__A                                          0x1810013
+#define B_CE_REG_ATT__A                                              0x1810014
+#define B_CE_REG_NRED__A                                             0x1810015
+#define B_CE_REG_NE_ERR_SELECT__A                                    0x1810043
+#define B_CE_REG_NE_TD_CAL__A                                        0x1810044
+#define B_CE_REG_NE_MIXAVG__A                                        0x1810046
+#define B_CE_REG_NE_NUPD_OFS__A                                      0x1810047
+#define B_CE_REG_PE_NEXP_OFFS__A                                     0x1810050
+#define B_CE_REG_PE_TIMESHIFT__A                                     0x1810051
+#define B_CE_REG_TP_A0_TAP_NEW__A                                    0x1810064
+#define B_CE_REG_TP_A0_TAP_NEW_VALID__A                              0x1810065
+#define B_CE_REG_TP_A0_MU_LMS_STEP__A                                0x1810066
+#define B_CE_REG_TP_A1_TAP_NEW__A                                    0x1810068
+#define B_CE_REG_TP_A1_TAP_NEW_VALID__A                              0x1810069
+#define B_CE_REG_TP_A1_MU_LMS_STEP__A                                0x181006A
+#define B_CE_REG_TI_PHN_ENABLE__A                                    0x1810073
+#define B_CE_REG_FI_SHT_INCR__A                                      0x1810090
+#define B_CE_REG_FI_EXP_NORM__A                                      0x1810091
+#define B_CE_REG_IR_INPUTSEL__A                                      0x18100A0
+#define B_CE_REG_IR_STARTPOS__A                                      0x18100A1
+#define B_CE_REG_IR_NEXP_THRES__A                                    0x18100A2
+#define B_CE_REG_FR_TREAL00__A                                       0x1820010
+#define B_CE_REG_FR_TIMAG00__A                                       0x1820011
+#define B_CE_REG_FR_TREAL01__A                                       0x1820012
+#define B_CE_REG_FR_TIMAG01__A                                       0x1820013
+#define B_CE_REG_FR_TREAL02__A                                       0x1820014
+#define B_CE_REG_FR_TIMAG02__A                                       0x1820015
+#define B_CE_REG_FR_TREAL03__A                                       0x1820016
+#define B_CE_REG_FR_TIMAG03__A                                       0x1820017
+#define B_CE_REG_FR_TREAL04__A                                       0x1820018
+#define B_CE_REG_FR_TIMAG04__A                                       0x1820019
+#define B_CE_REG_FR_TREAL05__A                                       0x182001A
+#define B_CE_REG_FR_TIMAG05__A                                       0x182001B
+#define B_CE_REG_FR_TREAL06__A                                       0x182001C
+#define B_CE_REG_FR_TIMAG06__A                                       0x182001D
+#define B_CE_REG_FR_TREAL07__A                                       0x182001E
+#define B_CE_REG_FR_TIMAG07__A                                       0x182001F
+#define B_CE_REG_FR_TREAL08__A                                       0x1820020
+#define B_CE_REG_FR_TIMAG08__A                                       0x1820021
+#define B_CE_REG_FR_TREAL09__A                                       0x1820022
+#define B_CE_REG_FR_TIMAG09__A                                       0x1820023
+#define B_CE_REG_FR_TREAL10__A                                       0x1820024
+#define B_CE_REG_FR_TIMAG10__A                                       0x1820025
+#define B_CE_REG_FR_TREAL11__A                                       0x1820026
+#define B_CE_REG_FR_TIMAG11__A                                       0x1820027
+#define B_CE_REG_FR_MID_TAP__A                                       0x1820028
+#define B_CE_REG_FR_SQS_G00__A                                       0x1820029
+#define B_CE_REG_FR_SQS_G01__A                                       0x182002A
+#define B_CE_REG_FR_SQS_G02__A                                       0x182002B
+#define B_CE_REG_FR_SQS_G03__A                                       0x182002C
+#define B_CE_REG_FR_SQS_G04__A                                       0x182002D
+#define B_CE_REG_FR_SQS_G05__A                                       0x182002E
+#define B_CE_REG_FR_SQS_G06__A                                       0x182002F
+#define B_CE_REG_FR_SQS_G07__A                                       0x1820030
+#define B_CE_REG_FR_SQS_G08__A                                       0x1820031
+#define B_CE_REG_FR_SQS_G09__A                                       0x1820032
+#define B_CE_REG_FR_SQS_G10__A                                       0x1820033
+#define B_CE_REG_FR_SQS_G11__A                                       0x1820034
+#define B_CE_REG_FR_SQS_G12__A                                       0x1820035
+#define B_CE_REG_FR_RIO_G00__A                                       0x1820036
+#define B_CE_REG_FR_RIO_G01__A                                       0x1820037
+#define B_CE_REG_FR_RIO_G02__A                                       0x1820038
+#define B_CE_REG_FR_RIO_G03__A                                       0x1820039
+#define B_CE_REG_FR_RIO_G04__A                                       0x182003A
+#define B_CE_REG_FR_RIO_G05__A                                       0x182003B
+#define B_CE_REG_FR_RIO_G06__A                                       0x182003C
+#define B_CE_REG_FR_RIO_G07__A                                       0x182003D
+#define B_CE_REG_FR_RIO_G08__A                                       0x182003E
+#define B_CE_REG_FR_RIO_G09__A                                       0x182003F
+#define B_CE_REG_FR_RIO_G10__A                                       0x1820040
+#define B_CE_REG_FR_MODE__A                                          0x1820041
+#define B_CE_REG_FR_SQS_TRH__A                                       0x1820042
+#define B_CE_REG_FR_RIO_GAIN__A                                      0x1820043
+#define B_CE_REG_FR_BYPASS__A                                        0x1820044
+#define B_CE_REG_FR_PM_SET__A                                        0x1820045
+#define B_CE_REG_FR_ERR_SH__A                                        0x1820046
+#define B_CE_REG_FR_MAN_SH__A                                        0x1820047
+#define B_CE_REG_FR_TAP_SH__A                                        0x1820048
+#define B_EQ_COMM_EXEC__A                                            0x1C00000
+#define B_EQ_REG_COMM_EXEC__A                                        0x1C10000
+#define B_EQ_REG_COMM_MB__A                                          0x1C10002
+#define B_EQ_REG_IS_GAIN_MAN__A                                      0x1C10015
+#define B_EQ_REG_IS_GAIN_EXP__A                                      0x1C10016
+#define B_EQ_REG_IS_CLIP_EXP__A                                      0x1C10017
+#define B_EQ_REG_SN_CEGAIN__A                                        0x1C1002A
+#define B_EQ_REG_SN_OFFSET__A                                        0x1C1002B
+#define B_EQ_REG_RC_SEL_CAR__A                                       0x1C10032
+#define   B_EQ_REG_RC_SEL_CAR_INIT                                   0x2
+#define     B_EQ_REG_RC_SEL_CAR_DIV_ON                               0x1
+#define     B_EQ_REG_RC_SEL_CAR_PASS_A_CC                            0x0
+#define     B_EQ_REG_RC_SEL_CAR_PASS_B_CE                            0x2
+#define     B_EQ_REG_RC_SEL_CAR_LOCAL_A_CC                           0x0
+#define     B_EQ_REG_RC_SEL_CAR_LOCAL_B_CE                           0x8
+#define     B_EQ_REG_RC_SEL_CAR_MEAS_A_CC                            0x0
+#define     B_EQ_REG_RC_SEL_CAR_MEAS_B_CE                            0x20
+#define   B_EQ_REG_RC_SEL_CAR_FFTMODE__M                             0x80
+#define B_EQ_REG_OT_CONST__A                                         0x1C10046
+#define B_EQ_REG_OT_ALPHA__A                                         0x1C10047
+#define B_EQ_REG_OT_QNT_THRES0__A                                    0x1C10048
+#define B_EQ_REG_OT_QNT_THRES1__A                                    0x1C10049
+#define B_EQ_REG_OT_CSI_STEP__A                                      0x1C1004A
+#define B_EQ_REG_OT_CSI_OFFSET__A                                    0x1C1004B
+#define B_EQ_REG_TD_REQ_SMB_CNT__A                                   0x1C10061
+#define B_EQ_REG_TD_TPS_PWR_OFS__A                                   0x1C10062
+#define B_EC_SB_REG_COMM_EXEC__A                                     0x2010000
+#define B_EC_SB_REG_TR_MODE__A                                       0x2010010
+#define   B_EC_SB_REG_TR_MODE_8K                                     0x0
+#define   B_EC_SB_REG_TR_MODE_2K                                     0x1
+#define B_EC_SB_REG_CONST__A                                         0x2010011
+#define   B_EC_SB_REG_CONST_QPSK                                     0x0
+#define   B_EC_SB_REG_CONST_16QAM                                    0x1
+#define   B_EC_SB_REG_CONST_64QAM                                    0x2
+#define B_EC_SB_REG_ALPHA__A                                         0x2010012
+#define B_EC_SB_REG_PRIOR__A                                         0x2010013
+#define   B_EC_SB_REG_PRIOR_HI                                       0x0
+#define   B_EC_SB_REG_PRIOR_LO                                       0x1
+#define B_EC_SB_REG_CSI_HI__A                                        0x2010014
+#define B_EC_SB_REG_CSI_LO__A                                        0x2010015
+#define B_EC_SB_REG_SMB_TGL__A                                       0x2010016
+#define B_EC_SB_REG_SNR_HI__A                                        0x2010017
+#define B_EC_SB_REG_SNR_MID__A                                       0x2010018
+#define B_EC_SB_REG_SNR_LO__A                                        0x2010019
+#define B_EC_SB_REG_SCALE_MSB__A                                     0x201001A
+#define B_EC_SB_REG_SCALE_BIT2__A                                    0x201001B
+#define B_EC_SB_REG_SCALE_LSB__A                                     0x201001C
+#define B_EC_SB_REG_CSI_OFS0__A                                      0x201001D
+#define B_EC_SB_REG_CSI_OFS1__A                                      0x201001E
+#define B_EC_SB_REG_CSI_OFS2__A                                      0x201001F
+#define B_EC_VD_REG_COMM_EXEC__A                                     0x2090000
+#define B_EC_VD_REG_FORCE__A                                         0x2090010
+#define B_EC_VD_REG_SET_CODERATE__A                                  0x2090011
+#define   B_EC_VD_REG_SET_CODERATE_C1_2                              0x0
+#define   B_EC_VD_REG_SET_CODERATE_C2_3                              0x1
+#define   B_EC_VD_REG_SET_CODERATE_C3_4                              0x2
+#define   B_EC_VD_REG_SET_CODERATE_C5_6                              0x3
+#define   B_EC_VD_REG_SET_CODERATE_C7_8                              0x4
+#define B_EC_VD_REG_REQ_SMB_CNT__A                                   0x2090012
+#define B_EC_VD_REG_RLK_ENA__A                                       0x2090014
+#define B_EC_OD_REG_COMM_EXEC__A                                     0x2110000
+#define B_EC_OD_REG_SYNC__A                                          0x2110664
+#define B_EC_OD_DEINT_RAM__A                                         0x2120000
+#define B_EC_RS_REG_COMM_EXEC__A                                     0x2130000
+#define B_EC_RS_REG_REQ_PCK_CNT__A                                   0x2130010
+#define B_EC_RS_REG_VAL__A                                           0x2130011
+#define   B_EC_RS_REG_VAL_PCK                                        0x1
+#define B_EC_RS_EC_RAM__A                                            0x2140000
+#define B_EC_OC_REG_COMM_EXEC__A                                     0x2150000
+#define     B_EC_OC_REG_COMM_EXEC_CTL_ACTIVE                         0x1
+#define     B_EC_OC_REG_COMM_EXEC_CTL_HOLD                           0x2
+#define B_EC_OC_REG_COMM_INT_STA__A                                  0x2150007
+#define B_EC_OC_REG_OC_MODE_LOP__A                                   0x2150010
+#define   B_EC_OC_REG_OC_MODE_LOP_PAR_ENA__M                         0x1
+#define     B_EC_OC_REG_OC_MODE_LOP_PAR_ENA_ENABLE                   0x0
+#define     B_EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE                  0x1
+#define   B_EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC__M                     0x4
+#define     B_EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC_STATIC               0x0
+#define   B_EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE__M                     0x80
+#define     B_EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE_SERIAL               0x80
+#define B_EC_OC_REG_OC_MODE_HIP__A                                   0x2150011
+#define     B_EC_OC_REG_OC_MODE_HIP_MPG_BUS_SRC_MONITOR              0x10
+#define   B_EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M                     0x200
+#define     B_EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_DISABLE              0x0
+#define     B_EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_ENABLE               0x200
+#define B_EC_OC_REG_OC_MPG_SIO__A                                    0x2150012
+#define B_EC_OC_REG_OC_MPG_SIO__M                                    0xFFF
+#define B_EC_OC_REG_DTO_INC_LOP__A                                   0x2150014
+#define B_EC_OC_REG_DTO_INC_HIP__A                                   0x2150015
+#define B_EC_OC_REG_SNC_ISC_LVL__A                                   0x2150016
+#define   B_EC_OC_REG_SNC_ISC_LVL_OSC__M                             0xF0
+#define B_EC_OC_REG_TMD_TOP_MODE__A                                  0x215001D
+#define B_EC_OC_REG_TMD_TOP_CNT__A                                   0x215001E
+#define B_EC_OC_REG_TMD_HIL_MAR__A                                   0x215001F
+#define B_EC_OC_REG_TMD_LOL_MAR__A                                   0x2150020
+#define B_EC_OC_REG_TMD_CUR_CNT__A                                   0x2150021
+#define B_EC_OC_REG_AVR_ASH_CNT__A                                   0x2150023
+#define B_EC_OC_REG_AVR_BSH_CNT__A                                   0x2150024
+#define B_EC_OC_REG_RCN_MODE__A                                      0x2150027
+#define B_EC_OC_REG_RCN_CRA_LOP__A                                   0x2150028
+#define B_EC_OC_REG_RCN_CRA_HIP__A                                   0x2150029
+#define B_EC_OC_REG_RCN_CST_LOP__A                                   0x215002A
+#define B_EC_OC_REG_RCN_CST_HIP__A                                   0x215002B
+#define B_EC_OC_REG_RCN_SET_LVL__A                                   0x215002C
+#define B_EC_OC_REG_RCN_GAI_LVL__A                                   0x215002D
+#define B_EC_OC_REG_RCN_CLP_LOP__A                                   0x2150032
+#define B_EC_OC_REG_RCN_CLP_HIP__A                                   0x2150033
+#define B_EC_OC_REG_RCN_MAP_LOP__A                                   0x2150034
+#define B_EC_OC_REG_RCN_MAP_HIP__A                                   0x2150035
+#define B_EC_OC_REG_OCR_MPG_UOS__A                                   0x2150036
+#define B_EC_OC_REG_OCR_MPG_UOS__M                                   0xFFF
+#define   B_EC_OC_REG_OCR_MPG_UOS_INIT                               0x0
+#define B_EC_OC_REG_OCR_MPG_USR_DAT__A                               0x2150038
+#define B_EC_OC_REG_IPR_INV_MPG__A                                   0x2150045
+#define B_EC_OC_REG_DTO_CLKMODE__A                                   0x2150047
+#define B_EC_OC_REG_DTO_PER__A                                       0x2150048
+#define B_EC_OC_REG_DTO_BUR__A                                       0x2150049
+#define B_EC_OC_REG_RCR_CLKMODE__A                                   0x215004A
+#define B_CC_REG_OSC_MODE__A                                         0x2410010
+#define   B_CC_REG_OSC_MODE_M20                                      0x1
+#define B_CC_REG_PLL_MODE__A                                         0x2410011
+#define     B_CC_REG_PLL_MODE_BYPASS_PLL                             0x1
+#define     B_CC_REG_PLL_MODE_PUMP_CUR_12                            0x14
+#define B_CC_REG_REF_DIVIDE__A                                       0x2410012
+#define B_CC_REG_PWD_MODE__A                                         0x2410015
+#define   B_CC_REG_PWD_MODE_DOWN_PLL                                 0x2
+#define B_CC_REG_UPDATE__A                                           0x2410017
+#define   B_CC_REG_UPDATE_KEY                                        0x3973
+#define B_CC_REG_JTAGID_L__A                                         0x2410019
+#define B_CC_REG_DIVERSITY__A                                        0x241001B
+#define B_LC_COMM_EXEC__A                                            0x2800000
+#define B_LC_RA_RAM_IFINCR_NOM_L__A                                  0x282000C
+#define B_LC_RA_RAM_FILTER_SYM_SET__A                                0x282001A
+#define B_LC_RA_RAM_FILTER_SYM_SET__PRE                              0x3E8
+#define B_LC_RA_RAM_FILTER_CRMM_A__A                                 0x2820060
+#define B_LC_RA_RAM_FILTER_CRMM_A__PRE                               0x4
+#define B_LC_RA_RAM_FILTER_CRMM_B__A                                 0x2820061
+#define B_LC_RA_RAM_FILTER_CRMM_B__PRE                               0x1
+#define B_LC_RA_RAM_FILTER_SRMM_A__A                                 0x2820068
+#define B_LC_RA_RAM_FILTER_SRMM_A__PRE                               0x4
+#define B_LC_RA_RAM_FILTER_SRMM_B__A                                 0x2820069
+#define B_LC_RA_RAM_FILTER_SRMM_B__PRE                               0x1
+
+#endif
diff --git a/drivers/media/dvb-frontends/drxk.h b/drivers/media/dvb-frontends/drxk.h
new file mode 100644
index 0000000..d615d7d
--- /dev/null
+++ b/drivers/media/dvb-frontends/drxk.h
@@ -0,0 +1,66 @@
+#ifndef _DRXK_H_
+#define _DRXK_H_
+
+#include <linux/types.h>
+#include <linux/i2c.h>
+
+/**
+ * struct drxk_config - Configure the initial parameters for DRX-K
+ *
+ * @adr:		I2C Address of the DRX-K
+ * @parallel_ts:	True means that the device uses parallel TS,
+ * 			Serial otherwise.
+ * @dynamic_clk:	True means that the clock will be dynamically
+ *			adjusted. Static clock otherwise.
+ * @enable_merr_cfg:	Enable SIO_PDR_PERR_CFG/SIO_PDR_MVAL_CFG.
+ * @single_master:	Device is on the single master mode
+ * @no_i2c_bridge:	Don't switch the I2C bridge to talk with tuner
+ * @antenna_gpio:	GPIO bit used to control the antenna
+ * @antenna_dvbt:	GPIO bit for changing antenna to DVB-C. A value of 1
+ *			means that 1=DVBC, 0 = DVBT. Zero means the opposite.
+ * @mpeg_out_clk_strength: DRXK Mpeg output clock drive strength.
+ * @microcode_name:	Name of the firmware file with the microcode
+ * @qam_demod_parameter_count:	The number of parameters used for the command
+ *				to set the demodulator parameters. All
+ *				firmwares are using the 2-parameter commmand.
+ *				An exception is the "drxk_a3.mc" firmware,
+ *				which uses the 4-parameter command.
+ *				A value of 0 (default) or lower indicates that
+ *				the correct number of parameters will be
+ *				automatically detected.
+ *
+ * On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is
+ * UIO-3.
+ */
+struct drxk_config {
+	u8	adr;
+	bool	single_master;
+	bool	no_i2c_bridge;
+	bool	parallel_ts;
+	bool	dynamic_clk;
+	bool	enable_merr_cfg;
+
+	bool	antenna_dvbt;
+	u16	antenna_gpio;
+
+	u8	mpeg_out_clk_strength;
+	int	chunk_size;
+
+	const char	*microcode_name;
+	int		 qam_demod_parameter_count;
+};
+
+#if defined(CONFIG_DVB_DRXK) || (defined(CONFIG_DVB_DRXK_MODULE) \
+        && defined(MODULE))
+extern struct dvb_frontend *drxk_attach(const struct drxk_config *config,
+					struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *drxk_attach(const struct drxk_config *config,
+					struct i2c_adapter *i2c)
+{
+        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+        return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c
new file mode 100644
index 0000000..1ab8154
--- /dev/null
+++ b/drivers/media/dvb-frontends/drxk_hard.c
@@ -0,0 +1,6637 @@
+/*
+ * drxk_hard: DRX-K DVB-C/T demodulator driver
+ *
+ * Copyright (C) 2010-2011 Digital Devices GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/hardirq.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "drxk.h"
+#include "drxk_hard.h"
+
+static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode);
+static int PowerDownQAM(struct drxk_state *state);
+static int SetDVBTStandard(struct drxk_state *state,
+			   enum OperationMode oMode);
+static int SetQAMStandard(struct drxk_state *state,
+			  enum OperationMode oMode);
+static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
+		  s32 tunerFreqOffset);
+static int SetDVBTStandard(struct drxk_state *state,
+			   enum OperationMode oMode);
+static int DVBTStart(struct drxk_state *state);
+static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
+		   s32 tunerFreqOffset);
+static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus);
+static int GetDVBTLockStatus(struct drxk_state *state, u32 *pLockStatus);
+static int SwitchAntennaToQAM(struct drxk_state *state);
+static int SwitchAntennaToDVBT(struct drxk_state *state);
+
+static bool IsDVBT(struct drxk_state *state)
+{
+	return state->m_OperationMode == OM_DVBT;
+}
+
+static bool IsQAM(struct drxk_state *state)
+{
+	return state->m_OperationMode == OM_QAM_ITU_A ||
+	    state->m_OperationMode == OM_QAM_ITU_B ||
+	    state->m_OperationMode == OM_QAM_ITU_C;
+}
+
+bool IsA1WithPatchCode(struct drxk_state *state)
+{
+	return state->m_DRXK_A1_PATCH_CODE;
+}
+
+bool IsA1WithRomCode(struct drxk_state *state)
+{
+	return state->m_DRXK_A1_ROM_CODE;
+}
+
+#define NOA1ROM 0
+
+#define DRXDAP_FASI_SHORT_FORMAT(addr) (((addr) & 0xFC30FF80) == 0)
+#define DRXDAP_FASI_LONG_FORMAT(addr)  (((addr) & 0xFC30FF80) != 0)
+
+#define DEFAULT_MER_83  165
+#define DEFAULT_MER_93  250
+
+#ifndef DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH
+#define DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH (0x02)
+#endif
+
+#ifndef DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH
+#define DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH (0x03)
+#endif
+
+#define DEFAULT_DRXK_MPEG_LOCK_TIMEOUT 700
+#define DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT 500
+
+#ifndef DRXK_KI_RAGC_ATV
+#define DRXK_KI_RAGC_ATV   4
+#endif
+#ifndef DRXK_KI_IAGC_ATV
+#define DRXK_KI_IAGC_ATV   6
+#endif
+#ifndef DRXK_KI_DAGC_ATV
+#define DRXK_KI_DAGC_ATV   7
+#endif
+
+#ifndef DRXK_KI_RAGC_QAM
+#define DRXK_KI_RAGC_QAM   3
+#endif
+#ifndef DRXK_KI_IAGC_QAM
+#define DRXK_KI_IAGC_QAM   4
+#endif
+#ifndef DRXK_KI_DAGC_QAM
+#define DRXK_KI_DAGC_QAM   7
+#endif
+#ifndef DRXK_KI_RAGC_DVBT
+#define DRXK_KI_RAGC_DVBT  (IsA1WithPatchCode(state) ? 3 : 2)
+#endif
+#ifndef DRXK_KI_IAGC_DVBT
+#define DRXK_KI_IAGC_DVBT  (IsA1WithPatchCode(state) ? 4 : 2)
+#endif
+#ifndef DRXK_KI_DAGC_DVBT
+#define DRXK_KI_DAGC_DVBT  (IsA1WithPatchCode(state) ? 10 : 7)
+#endif
+
+#ifndef DRXK_AGC_DAC_OFFSET
+#define DRXK_AGC_DAC_OFFSET (0x800)
+#endif
+
+#ifndef DRXK_BANDWIDTH_8MHZ_IN_HZ
+#define DRXK_BANDWIDTH_8MHZ_IN_HZ  (0x8B8249L)
+#endif
+
+#ifndef DRXK_BANDWIDTH_7MHZ_IN_HZ
+#define DRXK_BANDWIDTH_7MHZ_IN_HZ  (0x7A1200L)
+#endif
+
+#ifndef DRXK_BANDWIDTH_6MHZ_IN_HZ
+#define DRXK_BANDWIDTH_6MHZ_IN_HZ  (0x68A1B6L)
+#endif
+
+#ifndef DRXK_QAM_SYMBOLRATE_MAX
+#define DRXK_QAM_SYMBOLRATE_MAX         (7233000)
+#endif
+
+#define DRXK_BL_ROM_OFFSET_TAPS_DVBT    56
+#define DRXK_BL_ROM_OFFSET_TAPS_ITU_A   64
+#define DRXK_BL_ROM_OFFSET_TAPS_ITU_C   0x5FE0
+#define DRXK_BL_ROM_OFFSET_TAPS_BG      24
+#define DRXK_BL_ROM_OFFSET_TAPS_DKILLP  32
+#define DRXK_BL_ROM_OFFSET_TAPS_NTSC    40
+#define DRXK_BL_ROM_OFFSET_TAPS_FM      48
+#define DRXK_BL_ROM_OFFSET_UCODE        0
+
+#define DRXK_BLC_TIMEOUT                100
+
+#define DRXK_BLCC_NR_ELEMENTS_TAPS      2
+#define DRXK_BLCC_NR_ELEMENTS_UCODE     6
+
+#define DRXK_BLDC_NR_ELEMENTS_TAPS      28
+
+#ifndef DRXK_OFDM_NE_NOTCH_WIDTH
+#define DRXK_OFDM_NE_NOTCH_WIDTH             (4)
+#endif
+
+#define DRXK_QAM_SL_SIG_POWER_QAM16       (40960)
+#define DRXK_QAM_SL_SIG_POWER_QAM32       (20480)
+#define DRXK_QAM_SL_SIG_POWER_QAM64       (43008)
+#define DRXK_QAM_SL_SIG_POWER_QAM128      (20992)
+#define DRXK_QAM_SL_SIG_POWER_QAM256      (43520)
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+#define dprintk(level, fmt, arg...) do {			\
+if (debug >= level)						\
+	printk(KERN_DEBUG "drxk: %s" fmt, __func__, ## arg);	\
+} while (0)
+
+
+static inline u32 MulDiv32(u32 a, u32 b, u32 c)
+{
+	u64 tmp64;
+
+	tmp64 = (u64) a * (u64) b;
+	do_div(tmp64, c);
+
+	return (u32) tmp64;
+}
+
+inline u32 Frac28a(u32 a, u32 c)
+{
+	int i = 0;
+	u32 Q1 = 0;
+	u32 R0 = 0;
+
+	R0 = (a % c) << 4;	/* 32-28 == 4 shifts possible at max */
+	Q1 = a / c;		/* integer part, only the 4 least significant bits
+				   will be visible in the result */
+
+	/* division using radix 16, 7 nibbles in the result */
+	for (i = 0; i < 7; i++) {
+		Q1 = (Q1 << 4) | (R0 / c);
+		R0 = (R0 % c) << 4;
+	}
+	/* rounding */
+	if ((R0 >> 3) >= c)
+		Q1++;
+
+	return Q1;
+}
+
+static u32 Log10Times100(u32 x)
+{
+	static const u8 scale = 15;
+	static const u8 indexWidth = 5;
+	u8 i = 0;
+	u32 y = 0;
+	u32 d = 0;
+	u32 k = 0;
+	u32 r = 0;
+	/*
+	   log2lut[n] = (1<<scale) * 200 * log2(1.0 + ((1.0/(1<<INDEXWIDTH)) * n))
+	   0 <= n < ((1<<INDEXWIDTH)+1)
+	 */
+
+	static const u32 log2lut[] = {
+		0,		/* 0.000000 */
+		290941,		/* 290941.300628 */
+		573196,		/* 573196.476418 */
+		847269,		/* 847269.179851 */
+		1113620,	/* 1113620.489452 */
+		1372674,	/* 1372673.576986 */
+		1624818,	/* 1624817.752104 */
+		1870412,	/* 1870411.981536 */
+		2109788,	/* 2109787.962654 */
+		2343253,	/* 2343252.817465 */
+		2571091,	/* 2571091.461923 */
+		2793569,	/* 2793568.696416 */
+		3010931,	/* 3010931.055901 */
+		3223408,	/* 3223408.452106 */
+		3431216,	/* 3431215.635215 */
+		3634553,	/* 3634553.498355 */
+		3833610,	/* 3833610.244726 */
+		4028562,	/* 4028562.434393 */
+		4219576,	/* 4219575.925308 */
+		4406807,	/* 4406806.721144 */
+		4590402,	/* 4590401.736809 */
+		4770499,	/* 4770499.491025 */
+		4947231,	/* 4947230.734179 */
+		5120719,	/* 5120719.018555 */
+		5291081,	/* 5291081.217197 */
+		5458428,	/* 5458427.996830 */
+		5622864,	/* 5622864.249668 */
+		5784489,	/* 5784489.488298 */
+		5943398,	/* 5943398.207380 */
+		6099680,	/* 6099680.215452 */
+		6253421,	/* 6253420.939751 */
+		6404702,	/* 6404701.706649 */
+		6553600,	/* 6553600.000000 */
+	};
+
+
+	if (x == 0)
+		return 0;
+
+	/* Scale x (normalize) */
+	/* computing y in log(x/y) = log(x) - log(y) */
+	if ((x & ((0xffffffff) << (scale + 1))) == 0) {
+		for (k = scale; k > 0; k--) {
+			if (x & (((u32) 1) << scale))
+				break;
+			x <<= 1;
+		}
+	} else {
+		for (k = scale; k < 31; k++) {
+			if ((x & (((u32) (-1)) << (scale + 1))) == 0)
+				break;
+			x >>= 1;
+		}
+	}
+	/*
+	   Now x has binary point between bit[scale] and bit[scale-1]
+	   and 1.0 <= x < 2.0 */
+
+	/* correction for divison: log(x) = log(x/y)+log(y) */
+	y = k * ((((u32) 1) << scale) * 200);
+
+	/* remove integer part */
+	x &= ((((u32) 1) << scale) - 1);
+	/* get index */
+	i = (u8) (x >> (scale - indexWidth));
+	/* compute delta (x - a) */
+	d = x & ((((u32) 1) << (scale - indexWidth)) - 1);
+	/* compute log, multiplication (d* (..)) must be within range ! */
+	y += log2lut[i] +
+	    ((d * (log2lut[i + 1] - log2lut[i])) >> (scale - indexWidth));
+	/* Conver to log10() */
+	y /= 108853;		/* (log2(10) << scale) */
+	r = (y >> 1);
+	/* rounding */
+	if (y & ((u32) 1))
+		r++;
+	return r;
+}
+
+/****************************************************************************/
+/* I2C **********************************************************************/
+/****************************************************************************/
+
+static int drxk_i2c_lock(struct drxk_state *state)
+{
+	i2c_lock_adapter(state->i2c);
+	state->drxk_i2c_exclusive_lock = true;
+
+	return 0;
+}
+
+static void drxk_i2c_unlock(struct drxk_state *state)
+{
+	if (!state->drxk_i2c_exclusive_lock)
+		return;
+
+	i2c_unlock_adapter(state->i2c);
+	state->drxk_i2c_exclusive_lock = false;
+}
+
+static int drxk_i2c_transfer(struct drxk_state *state, struct i2c_msg *msgs,
+			     unsigned len)
+{
+	if (state->drxk_i2c_exclusive_lock)
+		return __i2c_transfer(state->i2c, msgs, len);
+	else
+		return i2c_transfer(state->i2c, msgs, len);
+}
+
+static int i2c_read1(struct drxk_state *state, u8 adr, u8 *val)
+{
+	struct i2c_msg msgs[1] = { {.addr = adr, .flags = I2C_M_RD,
+				    .buf = val, .len = 1}
+	};
+
+	return drxk_i2c_transfer(state, msgs, 1);
+}
+
+static int i2c_write(struct drxk_state *state, u8 adr, u8 *data, int len)
+{
+	int status;
+	struct i2c_msg msg = {
+	    .addr = adr, .flags = 0, .buf = data, .len = len };
+
+	dprintk(3, ":");
+	if (debug > 2) {
+		int i;
+		for (i = 0; i < len; i++)
+			printk(KERN_CONT " %02x", data[i]);
+		printk(KERN_CONT "\n");
+	}
+	status = drxk_i2c_transfer(state, &msg, 1);
+	if (status >= 0 && status != 1)
+		status = -EIO;
+
+	if (status < 0)
+		printk(KERN_ERR "drxk: i2c write error at addr 0x%02x\n", adr);
+
+	return status;
+}
+
+static int i2c_read(struct drxk_state *state,
+		    u8 adr, u8 *msg, int len, u8 *answ, int alen)
+{
+	int status;
+	struct i2c_msg msgs[2] = {
+		{.addr = adr, .flags = 0,
+				    .buf = msg, .len = len},
+		{.addr = adr, .flags = I2C_M_RD,
+		 .buf = answ, .len = alen}
+	};
+
+	status = drxk_i2c_transfer(state, msgs, 2);
+	if (status != 2) {
+		if (debug > 2)
+			printk(KERN_CONT ": ERROR!\n");
+		if (status >= 0)
+			status = -EIO;
+
+		printk(KERN_ERR "drxk: i2c read error at addr 0x%02x\n", adr);
+		return status;
+	}
+	if (debug > 2) {
+		int i;
+		dprintk(2, ": read from");
+		for (i = 0; i < len; i++)
+			printk(KERN_CONT " %02x", msg[i]);
+		printk(KERN_CONT ", value = ");
+		for (i = 0; i < alen; i++)
+			printk(KERN_CONT " %02x", answ[i]);
+		printk(KERN_CONT "\n");
+	}
+	return 0;
+}
+
+static int read16_flags(struct drxk_state *state, u32 reg, u16 *data, u8 flags)
+{
+	int status;
+	u8 adr = state->demod_address, mm1[4], mm2[2], len;
+
+	if (state->single_master)
+		flags |= 0xC0;
+
+	if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
+		mm1[0] = (((reg << 1) & 0xFF) | 0x01);
+		mm1[1] = ((reg >> 16) & 0xFF);
+		mm1[2] = ((reg >> 24) & 0xFF) | flags;
+		mm1[3] = ((reg >> 7) & 0xFF);
+		len = 4;
+	} else {
+		mm1[0] = ((reg << 1) & 0xFF);
+		mm1[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
+		len = 2;
+	}
+	dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags);
+	status = i2c_read(state, adr, mm1, len, mm2, 2);
+	if (status < 0)
+		return status;
+	if (data)
+		*data = mm2[0] | (mm2[1] << 8);
+
+	return 0;
+}
+
+static int read16(struct drxk_state *state, u32 reg, u16 *data)
+{
+	return read16_flags(state, reg, data, 0);
+}
+
+static int read32_flags(struct drxk_state *state, u32 reg, u32 *data, u8 flags)
+{
+	int status;
+	u8 adr = state->demod_address, mm1[4], mm2[4], len;
+
+	if (state->single_master)
+		flags |= 0xC0;
+
+	if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
+		mm1[0] = (((reg << 1) & 0xFF) | 0x01);
+		mm1[1] = ((reg >> 16) & 0xFF);
+		mm1[2] = ((reg >> 24) & 0xFF) | flags;
+		mm1[3] = ((reg >> 7) & 0xFF);
+		len = 4;
+	} else {
+		mm1[0] = ((reg << 1) & 0xFF);
+		mm1[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
+		len = 2;
+	}
+	dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags);
+	status = i2c_read(state, adr, mm1, len, mm2, 4);
+	if (status < 0)
+		return status;
+	if (data)
+		*data = mm2[0] | (mm2[1] << 8) |
+		    (mm2[2] << 16) | (mm2[3] << 24);
+
+	return 0;
+}
+
+static int read32(struct drxk_state *state, u32 reg, u32 *data)
+{
+	return read32_flags(state, reg, data, 0);
+}
+
+static int write16_flags(struct drxk_state *state, u32 reg, u16 data, u8 flags)
+{
+	u8 adr = state->demod_address, mm[6], len;
+
+	if (state->single_master)
+		flags |= 0xC0;
+	if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
+		mm[0] = (((reg << 1) & 0xFF) | 0x01);
+		mm[1] = ((reg >> 16) & 0xFF);
+		mm[2] = ((reg >> 24) & 0xFF) | flags;
+		mm[3] = ((reg >> 7) & 0xFF);
+		len = 4;
+	} else {
+		mm[0] = ((reg << 1) & 0xFF);
+		mm[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
+		len = 2;
+	}
+	mm[len] = data & 0xff;
+	mm[len + 1] = (data >> 8) & 0xff;
+
+	dprintk(2, "(0x%08x, 0x%04x, 0x%02x)\n", reg, data, flags);
+	return i2c_write(state, adr, mm, len + 2);
+}
+
+static int write16(struct drxk_state *state, u32 reg, u16 data)
+{
+	return write16_flags(state, reg, data, 0);
+}
+
+static int write32_flags(struct drxk_state *state, u32 reg, u32 data, u8 flags)
+{
+	u8 adr = state->demod_address, mm[8], len;
+
+	if (state->single_master)
+		flags |= 0xC0;
+	if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
+		mm[0] = (((reg << 1) & 0xFF) | 0x01);
+		mm[1] = ((reg >> 16) & 0xFF);
+		mm[2] = ((reg >> 24) & 0xFF) | flags;
+		mm[3] = ((reg >> 7) & 0xFF);
+		len = 4;
+	} else {
+		mm[0] = ((reg << 1) & 0xFF);
+		mm[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
+		len = 2;
+	}
+	mm[len] = data & 0xff;
+	mm[len + 1] = (data >> 8) & 0xff;
+	mm[len + 2] = (data >> 16) & 0xff;
+	mm[len + 3] = (data >> 24) & 0xff;
+	dprintk(2, "(0x%08x, 0x%08x, 0x%02x)\n", reg, data, flags);
+
+	return i2c_write(state, adr, mm, len + 4);
+}
+
+static int write32(struct drxk_state *state, u32 reg, u32 data)
+{
+	return write32_flags(state, reg, data, 0);
+}
+
+static int write_block(struct drxk_state *state, u32 Address,
+		      const int BlockSize, const u8 pBlock[])
+{
+	int status = 0, BlkSize = BlockSize;
+	u8 Flags = 0;
+
+	if (state->single_master)
+		Flags |= 0xC0;
+
+	while (BlkSize > 0) {
+		int Chunk = BlkSize > state->m_ChunkSize ?
+		    state->m_ChunkSize : BlkSize;
+		u8 *AdrBuf = &state->Chunk[0];
+		u32 AdrLength = 0;
+
+		if (DRXDAP_FASI_LONG_FORMAT(Address) || (Flags != 0)) {
+			AdrBuf[0] = (((Address << 1) & 0xFF) | 0x01);
+			AdrBuf[1] = ((Address >> 16) & 0xFF);
+			AdrBuf[2] = ((Address >> 24) & 0xFF);
+			AdrBuf[3] = ((Address >> 7) & 0xFF);
+			AdrBuf[2] |= Flags;
+			AdrLength = 4;
+			if (Chunk == state->m_ChunkSize)
+				Chunk -= 2;
+		} else {
+			AdrBuf[0] = ((Address << 1) & 0xFF);
+			AdrBuf[1] = (((Address >> 16) & 0x0F) |
+				     ((Address >> 18) & 0xF0));
+			AdrLength = 2;
+		}
+		memcpy(&state->Chunk[AdrLength], pBlock, Chunk);
+		dprintk(2, "(0x%08x, 0x%02x)\n", Address, Flags);
+		if (debug > 1) {
+			int i;
+			if (pBlock)
+				for (i = 0; i < Chunk; i++)
+					printk(KERN_CONT " %02x", pBlock[i]);
+			printk(KERN_CONT "\n");
+		}
+		status = i2c_write(state, state->demod_address,
+				   &state->Chunk[0], Chunk + AdrLength);
+		if (status < 0) {
+			printk(KERN_ERR "drxk: %s: i2c write error at addr 0x%02x\n",
+			       __func__, Address);
+			break;
+		}
+		pBlock += Chunk;
+		Address += (Chunk >> 1);
+		BlkSize -= Chunk;
+	}
+	return status;
+}
+
+#ifndef DRXK_MAX_RETRIES_POWERUP
+#define DRXK_MAX_RETRIES_POWERUP 20
+#endif
+
+int PowerUpDevice(struct drxk_state *state)
+{
+	int status;
+	u8 data = 0;
+	u16 retryCount = 0;
+
+	dprintk(1, "\n");
+
+	status = i2c_read1(state, state->demod_address, &data);
+	if (status < 0) {
+		do {
+			data = 0;
+			status = i2c_write(state, state->demod_address,
+					   &data, 1);
+			msleep(10);
+			retryCount++;
+			if (status < 0)
+				continue;
+			status = i2c_read1(state, state->demod_address,
+					   &data);
+		} while (status < 0 &&
+			 (retryCount < DRXK_MAX_RETRIES_POWERUP));
+		if (status < 0 && retryCount >= DRXK_MAX_RETRIES_POWERUP)
+			goto error;
+	}
+
+	/* Make sure all clk domains are active */
+	status = write16(state, SIO_CC_PWD_MODE__A, SIO_CC_PWD_MODE_LEVEL_NONE);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
+	if (status < 0)
+		goto error;
+	/* Enable pll lock tests */
+	status = write16(state, SIO_CC_PLL_LOCK__A, 1);
+	if (status < 0)
+		goto error;
+
+	state->m_currentPowerMode = DRX_POWER_UP;
+
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+	return status;
+}
+
+
+static int init_state(struct drxk_state *state)
+{
+	/*
+	 * FIXME: most (all?) of the values bellow should be moved into
+	 * struct drxk_config, as they are probably board-specific
+	 */
+	u32 ulVSBIfAgcMode = DRXK_AGC_CTRL_AUTO;
+	u32 ulVSBIfAgcOutputLevel = 0;
+	u32 ulVSBIfAgcMinLevel = 0;
+	u32 ulVSBIfAgcMaxLevel = 0x7FFF;
+	u32 ulVSBIfAgcSpeed = 3;
+
+	u32 ulVSBRfAgcMode = DRXK_AGC_CTRL_AUTO;
+	u32 ulVSBRfAgcOutputLevel = 0;
+	u32 ulVSBRfAgcMinLevel = 0;
+	u32 ulVSBRfAgcMaxLevel = 0x7FFF;
+	u32 ulVSBRfAgcSpeed = 3;
+	u32 ulVSBRfAgcTop = 9500;
+	u32 ulVSBRfAgcCutOffCurrent = 4000;
+
+	u32 ulATVIfAgcMode = DRXK_AGC_CTRL_AUTO;
+	u32 ulATVIfAgcOutputLevel = 0;
+	u32 ulATVIfAgcMinLevel = 0;
+	u32 ulATVIfAgcMaxLevel = 0;
+	u32 ulATVIfAgcSpeed = 3;
+
+	u32 ulATVRfAgcMode = DRXK_AGC_CTRL_OFF;
+	u32 ulATVRfAgcOutputLevel = 0;
+	u32 ulATVRfAgcMinLevel = 0;
+	u32 ulATVRfAgcMaxLevel = 0;
+	u32 ulATVRfAgcTop = 9500;
+	u32 ulATVRfAgcCutOffCurrent = 4000;
+	u32 ulATVRfAgcSpeed = 3;
+
+	u32 ulQual83 = DEFAULT_MER_83;
+	u32 ulQual93 = DEFAULT_MER_93;
+
+	u32 ulMpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
+	u32 ulDemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
+
+	/* io_pad_cfg register (8 bit reg.) MSB bit is 1 (default value) */
+	/* io_pad_cfg_mode output mode is drive always */
+	/* io_pad_cfg_drive is set to power 2 (23 mA) */
+	u32 ulGPIOCfg = 0x0113;
+	u32 ulInvertTSClock = 0;
+	u32 ulTSDataStrength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH;
+	u32 ulDVBTBitrate = 50000000;
+	u32 ulDVBCBitrate = DRXK_QAM_SYMBOLRATE_MAX * 8;
+
+	u32 ulInsertRSByte = 0;
+
+	u32 ulRfMirror = 1;
+	u32 ulPowerDown = 0;
+
+	dprintk(1, "\n");
+
+	state->m_hasLNA = false;
+	state->m_hasDVBT = false;
+	state->m_hasDVBC = false;
+	state->m_hasATV = false;
+	state->m_hasOOB = false;
+	state->m_hasAudio = false;
+
+	if (!state->m_ChunkSize)
+		state->m_ChunkSize = 124;
+
+	state->m_oscClockFreq = 0;
+	state->m_smartAntInverted = false;
+	state->m_bPDownOpenBridge = false;
+
+	/* real system clock frequency in kHz */
+	state->m_sysClockFreq = 151875;
+	/* Timing div, 250ns/Psys */
+	/* Timing div, = (delay (nano seconds) * sysclk (kHz))/ 1000 */
+	state->m_HICfgTimingDiv = ((state->m_sysClockFreq / 1000) *
+				   HI_I2C_DELAY) / 1000;
+	/* Clipping */
+	if (state->m_HICfgTimingDiv > SIO_HI_RA_RAM_PAR_2_CFG_DIV__M)
+		state->m_HICfgTimingDiv = SIO_HI_RA_RAM_PAR_2_CFG_DIV__M;
+	state->m_HICfgWakeUpKey = (state->demod_address << 1);
+	/* port/bridge/power down ctrl */
+	state->m_HICfgCtrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;
+
+	state->m_bPowerDown = (ulPowerDown != 0);
+
+	state->m_DRXK_A1_PATCH_CODE = false;
+	state->m_DRXK_A1_ROM_CODE = false;
+	state->m_DRXK_A2_ROM_CODE = false;
+	state->m_DRXK_A3_ROM_CODE = false;
+	state->m_DRXK_A2_PATCH_CODE = false;
+	state->m_DRXK_A3_PATCH_CODE = false;
+
+	/* Init AGC and PGA parameters */
+	/* VSB IF */
+	state->m_vsbIfAgcCfg.ctrlMode = (ulVSBIfAgcMode);
+	state->m_vsbIfAgcCfg.outputLevel = (ulVSBIfAgcOutputLevel);
+	state->m_vsbIfAgcCfg.minOutputLevel = (ulVSBIfAgcMinLevel);
+	state->m_vsbIfAgcCfg.maxOutputLevel = (ulVSBIfAgcMaxLevel);
+	state->m_vsbIfAgcCfg.speed = (ulVSBIfAgcSpeed);
+	state->m_vsbPgaCfg = 140;
+
+	/* VSB RF */
+	state->m_vsbRfAgcCfg.ctrlMode = (ulVSBRfAgcMode);
+	state->m_vsbRfAgcCfg.outputLevel = (ulVSBRfAgcOutputLevel);
+	state->m_vsbRfAgcCfg.minOutputLevel = (ulVSBRfAgcMinLevel);
+	state->m_vsbRfAgcCfg.maxOutputLevel = (ulVSBRfAgcMaxLevel);
+	state->m_vsbRfAgcCfg.speed = (ulVSBRfAgcSpeed);
+	state->m_vsbRfAgcCfg.top = (ulVSBRfAgcTop);
+	state->m_vsbRfAgcCfg.cutOffCurrent = (ulVSBRfAgcCutOffCurrent);
+	state->m_vsbPreSawCfg.reference = 0x07;
+	state->m_vsbPreSawCfg.usePreSaw = true;
+
+	state->m_Quality83percent = DEFAULT_MER_83;
+	state->m_Quality93percent = DEFAULT_MER_93;
+	if (ulQual93 <= 500 && ulQual83 < ulQual93) {
+		state->m_Quality83percent = ulQual83;
+		state->m_Quality93percent = ulQual93;
+	}
+
+	/* ATV IF */
+	state->m_atvIfAgcCfg.ctrlMode = (ulATVIfAgcMode);
+	state->m_atvIfAgcCfg.outputLevel = (ulATVIfAgcOutputLevel);
+	state->m_atvIfAgcCfg.minOutputLevel = (ulATVIfAgcMinLevel);
+	state->m_atvIfAgcCfg.maxOutputLevel = (ulATVIfAgcMaxLevel);
+	state->m_atvIfAgcCfg.speed = (ulATVIfAgcSpeed);
+
+	/* ATV RF */
+	state->m_atvRfAgcCfg.ctrlMode = (ulATVRfAgcMode);
+	state->m_atvRfAgcCfg.outputLevel = (ulATVRfAgcOutputLevel);
+	state->m_atvRfAgcCfg.minOutputLevel = (ulATVRfAgcMinLevel);
+	state->m_atvRfAgcCfg.maxOutputLevel = (ulATVRfAgcMaxLevel);
+	state->m_atvRfAgcCfg.speed = (ulATVRfAgcSpeed);
+	state->m_atvRfAgcCfg.top = (ulATVRfAgcTop);
+	state->m_atvRfAgcCfg.cutOffCurrent = (ulATVRfAgcCutOffCurrent);
+	state->m_atvPreSawCfg.reference = 0x04;
+	state->m_atvPreSawCfg.usePreSaw = true;
+
+
+	/* DVBT RF */
+	state->m_dvbtRfAgcCfg.ctrlMode = DRXK_AGC_CTRL_OFF;
+	state->m_dvbtRfAgcCfg.outputLevel = 0;
+	state->m_dvbtRfAgcCfg.minOutputLevel = 0;
+	state->m_dvbtRfAgcCfg.maxOutputLevel = 0xFFFF;
+	state->m_dvbtRfAgcCfg.top = 0x2100;
+	state->m_dvbtRfAgcCfg.cutOffCurrent = 4000;
+	state->m_dvbtRfAgcCfg.speed = 1;
+
+
+	/* DVBT IF */
+	state->m_dvbtIfAgcCfg.ctrlMode = DRXK_AGC_CTRL_AUTO;
+	state->m_dvbtIfAgcCfg.outputLevel = 0;
+	state->m_dvbtIfAgcCfg.minOutputLevel = 0;
+	state->m_dvbtIfAgcCfg.maxOutputLevel = 9000;
+	state->m_dvbtIfAgcCfg.top = 13424;
+	state->m_dvbtIfAgcCfg.cutOffCurrent = 0;
+	state->m_dvbtIfAgcCfg.speed = 3;
+	state->m_dvbtIfAgcCfg.FastClipCtrlDelay = 30;
+	state->m_dvbtIfAgcCfg.IngainTgtMax = 30000;
+	/* state->m_dvbtPgaCfg = 140; */
+
+	state->m_dvbtPreSawCfg.reference = 4;
+	state->m_dvbtPreSawCfg.usePreSaw = false;
+
+	/* QAM RF */
+	state->m_qamRfAgcCfg.ctrlMode = DRXK_AGC_CTRL_OFF;
+	state->m_qamRfAgcCfg.outputLevel = 0;
+	state->m_qamRfAgcCfg.minOutputLevel = 6023;
+	state->m_qamRfAgcCfg.maxOutputLevel = 27000;
+	state->m_qamRfAgcCfg.top = 0x2380;
+	state->m_qamRfAgcCfg.cutOffCurrent = 4000;
+	state->m_qamRfAgcCfg.speed = 3;
+
+	/* QAM IF */
+	state->m_qamIfAgcCfg.ctrlMode = DRXK_AGC_CTRL_AUTO;
+	state->m_qamIfAgcCfg.outputLevel = 0;
+	state->m_qamIfAgcCfg.minOutputLevel = 0;
+	state->m_qamIfAgcCfg.maxOutputLevel = 9000;
+	state->m_qamIfAgcCfg.top = 0x0511;
+	state->m_qamIfAgcCfg.cutOffCurrent = 0;
+	state->m_qamIfAgcCfg.speed = 3;
+	state->m_qamIfAgcCfg.IngainTgtMax = 5119;
+	state->m_qamIfAgcCfg.FastClipCtrlDelay = 50;
+
+	state->m_qamPgaCfg = 140;
+	state->m_qamPreSawCfg.reference = 4;
+	state->m_qamPreSawCfg.usePreSaw = false;
+
+	state->m_OperationMode = OM_NONE;
+	state->m_DrxkState = DRXK_UNINITIALIZED;
+
+	/* MPEG output configuration */
+	state->m_enableMPEGOutput = true;	/* If TRUE; enable MPEG ouput */
+	state->m_insertRSByte = false;	/* If TRUE; insert RS byte */
+	state->m_invertDATA = false;	/* If TRUE; invert DATA signals */
+	state->m_invertERR = false;	/* If TRUE; invert ERR signal */
+	state->m_invertSTR = false;	/* If TRUE; invert STR signals */
+	state->m_invertVAL = false;	/* If TRUE; invert VAL signals */
+	state->m_invertCLK = (ulInvertTSClock != 0);	/* If TRUE; invert CLK signals */
+
+	/* If TRUE; static MPEG clockrate will be used;
+	   otherwise clockrate will adapt to the bitrate of the TS */
+
+	state->m_DVBTBitrate = ulDVBTBitrate;
+	state->m_DVBCBitrate = ulDVBCBitrate;
+
+	state->m_TSDataStrength = (ulTSDataStrength & 0x07);
+
+	/* Maximum bitrate in b/s in case static clockrate is selected */
+	state->m_mpegTsStaticBitrate = 19392658;
+	state->m_disableTEIhandling = false;
+
+	if (ulInsertRSByte)
+		state->m_insertRSByte = true;
+
+	state->m_MpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
+	if (ulMpegLockTimeOut < 10000)
+		state->m_MpegLockTimeOut = ulMpegLockTimeOut;
+	state->m_DemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
+	if (ulDemodLockTimeOut < 10000)
+		state->m_DemodLockTimeOut = ulDemodLockTimeOut;
+
+	/* QAM defaults */
+	state->m_Constellation = DRX_CONSTELLATION_AUTO;
+	state->m_qamInterleaveMode = DRXK_QAM_I12_J17;
+	state->m_fecRsPlen = 204 * 8;	/* fecRsPlen  annex A */
+	state->m_fecRsPrescale = 1;
+
+	state->m_sqiSpeed = DRXK_DVBT_SQI_SPEED_MEDIUM;
+	state->m_agcFastClipCtrlDelay = 0;
+
+	state->m_GPIOCfg = (ulGPIOCfg);
+
+	state->m_bPowerDown = false;
+	state->m_currentPowerMode = DRX_POWER_DOWN;
+
+	state->m_rfmirror = (ulRfMirror == 0);
+	state->m_IfAgcPol = false;
+	return 0;
+}
+
+static int DRXX_Open(struct drxk_state *state)
+{
+	int status = 0;
+	u32 jtag = 0;
+	u16 bid = 0;
+	u16 key = 0;
+
+	dprintk(1, "\n");
+	/* stop lock indicator process */
+	status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+	if (status < 0)
+		goto error;
+	/* Check device id */
+	status = read16(state, SIO_TOP_COMM_KEY__A, &key);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY);
+	if (status < 0)
+		goto error;
+	status = read32(state, SIO_TOP_JTAGID_LO__A, &jtag);
+	if (status < 0)
+		goto error;
+	status = read16(state, SIO_PDR_UIO_IN_HI__A, &bid);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_TOP_COMM_KEY__A, key);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int GetDeviceCapabilities(struct drxk_state *state)
+{
+	u16 sioPdrOhwCfg = 0;
+	u32 sioTopJtagidLo = 0;
+	int status;
+	const char *spin = "";
+
+	dprintk(1, "\n");
+
+	/* driver 0.9.0 */
+	/* stop lock indicator process */
+	status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_TOP_COMM_KEY__A, 0xFABA);
+	if (status < 0)
+		goto error;
+	status = read16(state, SIO_PDR_OHW_CFG__A, &sioPdrOhwCfg);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
+	if (status < 0)
+		goto error;
+
+	switch ((sioPdrOhwCfg & SIO_PDR_OHW_CFG_FREF_SEL__M)) {
+	case 0:
+		/* ignore (bypass ?) */
+		break;
+	case 1:
+		/* 27 MHz */
+		state->m_oscClockFreq = 27000;
+		break;
+	case 2:
+		/* 20.25 MHz */
+		state->m_oscClockFreq = 20250;
+		break;
+	case 3:
+		/* 4 MHz */
+		state->m_oscClockFreq = 20250;
+		break;
+	default:
+		printk(KERN_ERR "drxk: Clock Frequency is unkonwn\n");
+		return -EINVAL;
+	}
+	/*
+		Determine device capabilities
+		Based on pinning v14
+		*/
+	status = read32(state, SIO_TOP_JTAGID_LO__A, &sioTopJtagidLo);
+	if (status < 0)
+		goto error;
+
+	printk(KERN_INFO "drxk: status = 0x%08x\n", sioTopJtagidLo);
+
+	/* driver 0.9.0 */
+	switch ((sioTopJtagidLo >> 29) & 0xF) {
+	case 0:
+		state->m_deviceSpin = DRXK_SPIN_A1;
+		spin = "A1";
+		break;
+	case 2:
+		state->m_deviceSpin = DRXK_SPIN_A2;
+		spin = "A2";
+		break;
+	case 3:
+		state->m_deviceSpin = DRXK_SPIN_A3;
+		spin = "A3";
+		break;
+	default:
+		state->m_deviceSpin = DRXK_SPIN_UNKNOWN;
+		status = -EINVAL;
+		printk(KERN_ERR "drxk: Spin %d unknown\n",
+		       (sioTopJtagidLo >> 29) & 0xF);
+		goto error2;
+	}
+	switch ((sioTopJtagidLo >> 12) & 0xFF) {
+	case 0x13:
+		/* typeId = DRX3913K_TYPE_ID */
+		state->m_hasLNA = false;
+		state->m_hasOOB = false;
+		state->m_hasATV = false;
+		state->m_hasAudio = false;
+		state->m_hasDVBT = true;
+		state->m_hasDVBC = true;
+		state->m_hasSAWSW = true;
+		state->m_hasGPIO2 = false;
+		state->m_hasGPIO1 = false;
+		state->m_hasIRQN = false;
+		break;
+	case 0x15:
+		/* typeId = DRX3915K_TYPE_ID */
+		state->m_hasLNA = false;
+		state->m_hasOOB = false;
+		state->m_hasATV = true;
+		state->m_hasAudio = false;
+		state->m_hasDVBT = true;
+		state->m_hasDVBC = false;
+		state->m_hasSAWSW = true;
+		state->m_hasGPIO2 = true;
+		state->m_hasGPIO1 = true;
+		state->m_hasIRQN = false;
+		break;
+	case 0x16:
+		/* typeId = DRX3916K_TYPE_ID */
+		state->m_hasLNA = false;
+		state->m_hasOOB = false;
+		state->m_hasATV = true;
+		state->m_hasAudio = false;
+		state->m_hasDVBT = true;
+		state->m_hasDVBC = false;
+		state->m_hasSAWSW = true;
+		state->m_hasGPIO2 = true;
+		state->m_hasGPIO1 = true;
+		state->m_hasIRQN = false;
+		break;
+	case 0x18:
+		/* typeId = DRX3918K_TYPE_ID */
+		state->m_hasLNA = false;
+		state->m_hasOOB = false;
+		state->m_hasATV = true;
+		state->m_hasAudio = true;
+		state->m_hasDVBT = true;
+		state->m_hasDVBC = false;
+		state->m_hasSAWSW = true;
+		state->m_hasGPIO2 = true;
+		state->m_hasGPIO1 = true;
+		state->m_hasIRQN = false;
+		break;
+	case 0x21:
+		/* typeId = DRX3921K_TYPE_ID */
+		state->m_hasLNA = false;
+		state->m_hasOOB = false;
+		state->m_hasATV = true;
+		state->m_hasAudio = true;
+		state->m_hasDVBT = true;
+		state->m_hasDVBC = true;
+		state->m_hasSAWSW = true;
+		state->m_hasGPIO2 = true;
+		state->m_hasGPIO1 = true;
+		state->m_hasIRQN = false;
+		break;
+	case 0x23:
+		/* typeId = DRX3923K_TYPE_ID */
+		state->m_hasLNA = false;
+		state->m_hasOOB = false;
+		state->m_hasATV = true;
+		state->m_hasAudio = true;
+		state->m_hasDVBT = true;
+		state->m_hasDVBC = true;
+		state->m_hasSAWSW = true;
+		state->m_hasGPIO2 = true;
+		state->m_hasGPIO1 = true;
+		state->m_hasIRQN = false;
+		break;
+	case 0x25:
+		/* typeId = DRX3925K_TYPE_ID */
+		state->m_hasLNA = false;
+		state->m_hasOOB = false;
+		state->m_hasATV = true;
+		state->m_hasAudio = true;
+		state->m_hasDVBT = true;
+		state->m_hasDVBC = true;
+		state->m_hasSAWSW = true;
+		state->m_hasGPIO2 = true;
+		state->m_hasGPIO1 = true;
+		state->m_hasIRQN = false;
+		break;
+	case 0x26:
+		/* typeId = DRX3926K_TYPE_ID */
+		state->m_hasLNA = false;
+		state->m_hasOOB = false;
+		state->m_hasATV = true;
+		state->m_hasAudio = false;
+		state->m_hasDVBT = true;
+		state->m_hasDVBC = true;
+		state->m_hasSAWSW = true;
+		state->m_hasGPIO2 = true;
+		state->m_hasGPIO1 = true;
+		state->m_hasIRQN = false;
+		break;
+	default:
+		printk(KERN_ERR "drxk: DeviceID 0x%02x not supported\n",
+			((sioTopJtagidLo >> 12) & 0xFF));
+		status = -EINVAL;
+		goto error2;
+	}
+
+	printk(KERN_INFO
+	       "drxk: detected a drx-39%02xk, spin %s, xtal %d.%03d MHz\n",
+	       ((sioTopJtagidLo >> 12) & 0xFF), spin,
+	       state->m_oscClockFreq / 1000,
+	       state->m_oscClockFreq % 1000);
+
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+error2:
+	return status;
+}
+
+static int HI_Command(struct drxk_state *state, u16 cmd, u16 *pResult)
+{
+	int status;
+	bool powerdown_cmd;
+
+	dprintk(1, "\n");
+
+	/* Write command */
+	status = write16(state, SIO_HI_RA_RAM_CMD__A, cmd);
+	if (status < 0)
+		goto error;
+	if (cmd == SIO_HI_RA_RAM_CMD_RESET)
+		msleep(1);
+
+	powerdown_cmd =
+	    (bool) ((cmd == SIO_HI_RA_RAM_CMD_CONFIG) &&
+		    ((state->m_HICfgCtrl) &
+		     SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M) ==
+		    SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ);
+	if (powerdown_cmd == false) {
+		/* Wait until command rdy */
+		u32 retryCount = 0;
+		u16 waitCmd;
+
+		do {
+			msleep(1);
+			retryCount += 1;
+			status = read16(state, SIO_HI_RA_RAM_CMD__A,
+					  &waitCmd);
+		} while ((status < 0) && (retryCount < DRXK_MAX_RETRIES)
+			 && (waitCmd != 0));
+		if (status < 0)
+			goto error;
+		status = read16(state, SIO_HI_RA_RAM_RES__A, pResult);
+	}
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+	return status;
+}
+
+static int HI_CfgCommand(struct drxk_state *state)
+{
+	int status;
+
+	dprintk(1, "\n");
+
+	mutex_lock(&state->mutex);
+
+	status = write16(state, SIO_HI_RA_RAM_PAR_6__A, state->m_HICfgTimeout);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_HI_RA_RAM_PAR_5__A, state->m_HICfgCtrl);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_HI_RA_RAM_PAR_4__A, state->m_HICfgWakeUpKey);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_HI_RA_RAM_PAR_3__A, state->m_HICfgBridgeDelay);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_HI_RA_RAM_PAR_2__A, state->m_HICfgTimingDiv);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_HI_RA_RAM_PAR_1__A, SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
+	if (status < 0)
+		goto error;
+	status = HI_Command(state, SIO_HI_RA_RAM_CMD_CONFIG, 0);
+	if (status < 0)
+		goto error;
+
+	state->m_HICfgCtrl &= ~SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
+error:
+	mutex_unlock(&state->mutex);
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int InitHI(struct drxk_state *state)
+{
+	dprintk(1, "\n");
+
+	state->m_HICfgWakeUpKey = (state->demod_address << 1);
+	state->m_HICfgTimeout = 0x96FF;
+	/* port/bridge/power down ctrl */
+	state->m_HICfgCtrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;
+
+	return HI_CfgCommand(state);
+}
+
+static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
+{
+	int status = -1;
+	u16 sioPdrMclkCfg = 0;
+	u16 sioPdrMdxCfg = 0;
+	u16 err_cfg = 0;
+
+	dprintk(1, ": mpeg %s, %s mode\n",
+		mpegEnable ? "enable" : "disable",
+		state->m_enableParallel ? "parallel" : "serial");
+
+	/* stop lock indicator process */
+	status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+	if (status < 0)
+		goto error;
+
+	/*  MPEG TS pad configuration */
+	status = write16(state, SIO_TOP_COMM_KEY__A, 0xFABA);
+	if (status < 0)
+		goto error;
+
+	if (mpegEnable == false) {
+		/*  Set MPEG TS pads to inputmode */
+		status = write16(state, SIO_PDR_MSTRT_CFG__A, 0x0000);
+		if (status < 0)
+			goto error;
+		status = write16(state, SIO_PDR_MERR_CFG__A, 0x0000);
+		if (status < 0)
+			goto error;
+		status = write16(state, SIO_PDR_MCLK_CFG__A, 0x0000);
+		if (status < 0)
+			goto error;
+		status = write16(state, SIO_PDR_MVAL_CFG__A, 0x0000);
+		if (status < 0)
+			goto error;
+		status = write16(state, SIO_PDR_MD0_CFG__A, 0x0000);
+		if (status < 0)
+			goto error;
+		status = write16(state, SIO_PDR_MD1_CFG__A, 0x0000);
+		if (status < 0)
+			goto error;
+		status = write16(state, SIO_PDR_MD2_CFG__A, 0x0000);
+		if (status < 0)
+			goto error;
+		status = write16(state, SIO_PDR_MD3_CFG__A, 0x0000);
+		if (status < 0)
+			goto error;
+		status = write16(state, SIO_PDR_MD4_CFG__A, 0x0000);
+		if (status < 0)
+			goto error;
+		status = write16(state, SIO_PDR_MD5_CFG__A, 0x0000);
+		if (status < 0)
+			goto error;
+		status = write16(state, SIO_PDR_MD6_CFG__A, 0x0000);
+		if (status < 0)
+			goto error;
+		status = write16(state, SIO_PDR_MD7_CFG__A, 0x0000);
+		if (status < 0)
+			goto error;
+	} else {
+		/* Enable MPEG output */
+		sioPdrMdxCfg =
+			((state->m_TSDataStrength <<
+			SIO_PDR_MD0_CFG_DRIVE__B) | 0x0003);
+		sioPdrMclkCfg = ((state->m_TSClockkStrength <<
+					SIO_PDR_MCLK_CFG_DRIVE__B) |
+					0x0003);
+
+		status = write16(state, SIO_PDR_MSTRT_CFG__A, sioPdrMdxCfg);
+		if (status < 0)
+			goto error;
+
+		if (state->enable_merr_cfg)
+			err_cfg = sioPdrMdxCfg;
+
+		status = write16(state, SIO_PDR_MERR_CFG__A, err_cfg);
+		if (status < 0)
+			goto error;
+		status = write16(state, SIO_PDR_MVAL_CFG__A, err_cfg);
+		if (status < 0)
+			goto error;
+
+		if (state->m_enableParallel == true) {
+			/* paralel -> enable MD1 to MD7 */
+			status = write16(state, SIO_PDR_MD1_CFG__A, sioPdrMdxCfg);
+			if (status < 0)
+				goto error;
+			status = write16(state, SIO_PDR_MD2_CFG__A, sioPdrMdxCfg);
+			if (status < 0)
+				goto error;
+			status = write16(state, SIO_PDR_MD3_CFG__A, sioPdrMdxCfg);
+			if (status < 0)
+				goto error;
+			status = write16(state, SIO_PDR_MD4_CFG__A, sioPdrMdxCfg);
+			if (status < 0)
+				goto error;
+			status = write16(state, SIO_PDR_MD5_CFG__A, sioPdrMdxCfg);
+			if (status < 0)
+				goto error;
+			status = write16(state, SIO_PDR_MD6_CFG__A, sioPdrMdxCfg);
+			if (status < 0)
+				goto error;
+			status = write16(state, SIO_PDR_MD7_CFG__A, sioPdrMdxCfg);
+			if (status < 0)
+				goto error;
+		} else {
+			sioPdrMdxCfg = ((state->m_TSDataStrength <<
+						SIO_PDR_MD0_CFG_DRIVE__B)
+					| 0x0003);
+			/* serial -> disable MD1 to MD7 */
+			status = write16(state, SIO_PDR_MD1_CFG__A, 0x0000);
+			if (status < 0)
+				goto error;
+			status = write16(state, SIO_PDR_MD2_CFG__A, 0x0000);
+			if (status < 0)
+				goto error;
+			status = write16(state, SIO_PDR_MD3_CFG__A, 0x0000);
+			if (status < 0)
+				goto error;
+			status = write16(state, SIO_PDR_MD4_CFG__A, 0x0000);
+			if (status < 0)
+				goto error;
+			status = write16(state, SIO_PDR_MD5_CFG__A, 0x0000);
+			if (status < 0)
+				goto error;
+			status = write16(state, SIO_PDR_MD6_CFG__A, 0x0000);
+			if (status < 0)
+				goto error;
+			status = write16(state, SIO_PDR_MD7_CFG__A, 0x0000);
+			if (status < 0)
+				goto error;
+		}
+		status = write16(state, SIO_PDR_MCLK_CFG__A, sioPdrMclkCfg);
+		if (status < 0)
+			goto error;
+		status = write16(state, SIO_PDR_MD0_CFG__A, sioPdrMdxCfg);
+		if (status < 0)
+			goto error;
+	}
+	/*  Enable MB output over MPEG pads and ctl input */
+	status = write16(state, SIO_PDR_MON_CFG__A, 0x0000);
+	if (status < 0)
+		goto error;
+	/*  Write nomagic word to enable pdr reg write */
+	status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int MPEGTSDisable(struct drxk_state *state)
+{
+	dprintk(1, "\n");
+
+	return MPEGTSConfigurePins(state, false);
+}
+
+static int BLChainCmd(struct drxk_state *state,
+		      u16 romOffset, u16 nrOfElements, u32 timeOut)
+{
+	u16 blStatus = 0;
+	int status;
+	unsigned long end;
+
+	dprintk(1, "\n");
+	mutex_lock(&state->mutex);
+	status = write16(state, SIO_BL_MODE__A, SIO_BL_MODE_CHAIN);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_BL_CHAIN_ADDR__A, romOffset);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_BL_CHAIN_LEN__A, nrOfElements);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_BL_ENABLE__A, SIO_BL_ENABLE_ON);
+	if (status < 0)
+		goto error;
+
+	end = jiffies + msecs_to_jiffies(timeOut);
+	do {
+		msleep(1);
+		status = read16(state, SIO_BL_STATUS__A, &blStatus);
+		if (status < 0)
+			goto error;
+	} while ((blStatus == 0x1) &&
+			((time_is_after_jiffies(end))));
+
+	if (blStatus == 0x1) {
+		printk(KERN_ERR "drxk: SIO not ready\n");
+		status = -EINVAL;
+		goto error2;
+	}
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+error2:
+	mutex_unlock(&state->mutex);
+	return status;
+}
+
+
+static int DownloadMicrocode(struct drxk_state *state,
+			     const u8 pMCImage[], u32 Length)
+{
+	const u8 *pSrc = pMCImage;
+	u32 Address;
+	u16 nBlocks;
+	u16 BlockSize;
+	u32 offset = 0;
+	u32 i;
+	int status = 0;
+
+	dprintk(1, "\n");
+
+	/* down the drain (we don't care about MAGIC_WORD) */
+#if 0
+	/* For future reference */
+	Drain = (pSrc[0] << 8) | pSrc[1];
+#endif
+	pSrc += sizeof(u16);
+	offset += sizeof(u16);
+	nBlocks = (pSrc[0] << 8) | pSrc[1];
+	pSrc += sizeof(u16);
+	offset += sizeof(u16);
+
+	for (i = 0; i < nBlocks; i += 1) {
+		Address = (pSrc[0] << 24) | (pSrc[1] << 16) |
+		    (pSrc[2] << 8) | pSrc[3];
+		pSrc += sizeof(u32);
+		offset += sizeof(u32);
+
+		BlockSize = ((pSrc[0] << 8) | pSrc[1]) * sizeof(u16);
+		pSrc += sizeof(u16);
+		offset += sizeof(u16);
+
+#if 0
+		/* For future reference */
+		Flags = (pSrc[0] << 8) | pSrc[1];
+#endif
+		pSrc += sizeof(u16);
+		offset += sizeof(u16);
+
+#if 0
+		/* For future reference */
+		BlockCRC = (pSrc[0] << 8) | pSrc[1];
+#endif
+		pSrc += sizeof(u16);
+		offset += sizeof(u16);
+
+		if (offset + BlockSize > Length) {
+			printk(KERN_ERR "drxk: Firmware is corrupted.\n");
+			return -EINVAL;
+		}
+
+		status = write_block(state, Address, BlockSize, pSrc);
+		if (status < 0) {
+			printk(KERN_ERR "drxk: Error %d while loading firmware\n", status);
+			break;
+		}
+		pSrc += BlockSize;
+		offset += BlockSize;
+	}
+	return status;
+}
+
+static int DVBTEnableOFDMTokenRing(struct drxk_state *state, bool enable)
+{
+	int status;
+	u16 data = 0;
+	u16 desiredCtrl = SIO_OFDM_SH_OFDM_RING_ENABLE_ON;
+	u16 desiredStatus = SIO_OFDM_SH_OFDM_RING_STATUS_ENABLED;
+	unsigned long end;
+
+	dprintk(1, "\n");
+
+	if (enable == false) {
+		desiredCtrl = SIO_OFDM_SH_OFDM_RING_ENABLE_OFF;
+		desiredStatus = SIO_OFDM_SH_OFDM_RING_STATUS_DOWN;
+	}
+
+	status = read16(state, SIO_OFDM_SH_OFDM_RING_STATUS__A, &data);
+	if (status >= 0 && data == desiredStatus) {
+		/* tokenring already has correct status */
+		return status;
+	}
+	/* Disable/enable dvbt tokenring bridge   */
+	status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, desiredCtrl);
+
+	end = jiffies + msecs_to_jiffies(DRXK_OFDM_TR_SHUTDOWN_TIMEOUT);
+	do {
+		status = read16(state, SIO_OFDM_SH_OFDM_RING_STATUS__A, &data);
+		if ((status >= 0 && data == desiredStatus) || time_is_after_jiffies(end))
+			break;
+		msleep(1);
+	} while (1);
+	if (data != desiredStatus) {
+		printk(KERN_ERR "drxk: SIO not ready\n");
+		return -EINVAL;
+	}
+	return status;
+}
+
+static int MPEGTSStop(struct drxk_state *state)
+{
+	int status = 0;
+	u16 fecOcSncMode = 0;
+	u16 fecOcIprMode = 0;
+
+	dprintk(1, "\n");
+
+	/* Gracefull shutdown (byte boundaries) */
+	status = read16(state, FEC_OC_SNC_MODE__A, &fecOcSncMode);
+	if (status < 0)
+		goto error;
+	fecOcSncMode |= FEC_OC_SNC_MODE_SHUTDOWN__M;
+	status = write16(state, FEC_OC_SNC_MODE__A, fecOcSncMode);
+	if (status < 0)
+		goto error;
+
+	/* Suppress MCLK during absence of data */
+	status = read16(state, FEC_OC_IPR_MODE__A, &fecOcIprMode);
+	if (status < 0)
+		goto error;
+	fecOcIprMode |= FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__M;
+	status = write16(state, FEC_OC_IPR_MODE__A, fecOcIprMode);
+
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+	return status;
+}
+
+static int scu_command(struct drxk_state *state,
+		       u16 cmd, u8 parameterLen,
+		       u16 *parameter, u8 resultLen, u16 *result)
+{
+#if (SCU_RAM_PARAM_0__A - SCU_RAM_PARAM_15__A) != 15
+#error DRXK register mapping no longer compatible with this routine!
+#endif
+	u16 curCmd = 0;
+	int status = -EINVAL;
+	unsigned long end;
+	u8 buffer[34];
+	int cnt = 0, ii;
+	const char *p;
+	char errname[30];
+
+	dprintk(1, "\n");
+
+	if ((cmd == 0) || ((parameterLen > 0) && (parameter == NULL)) ||
+	    ((resultLen > 0) && (result == NULL))) {
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+		return status;
+	}
+
+	mutex_lock(&state->mutex);
+
+	/* assume that the command register is ready
+		since it is checked afterwards */
+	for (ii = parameterLen - 1; ii >= 0; ii -= 1) {
+		buffer[cnt++] = (parameter[ii] & 0xFF);
+		buffer[cnt++] = ((parameter[ii] >> 8) & 0xFF);
+	}
+	buffer[cnt++] = (cmd & 0xFF);
+	buffer[cnt++] = ((cmd >> 8) & 0xFF);
+
+	write_block(state, SCU_RAM_PARAM_0__A -
+			(parameterLen - 1), cnt, buffer);
+	/* Wait until SCU has processed command */
+	end = jiffies + msecs_to_jiffies(DRXK_MAX_WAITTIME);
+	do {
+		msleep(1);
+		status = read16(state, SCU_RAM_COMMAND__A, &curCmd);
+		if (status < 0)
+			goto error;
+	} while (!(curCmd == DRX_SCU_READY) && (time_is_after_jiffies(end)));
+	if (curCmd != DRX_SCU_READY) {
+		printk(KERN_ERR "drxk: SCU not ready\n");
+		status = -EIO;
+		goto error2;
+	}
+	/* read results */
+	if ((resultLen > 0) && (result != NULL)) {
+		s16 err;
+		int ii;
+
+		for (ii = resultLen - 1; ii >= 0; ii -= 1) {
+			status = read16(state, SCU_RAM_PARAM_0__A - ii, &result[ii]);
+			if (status < 0)
+				goto error;
+		}
+
+		/* Check if an error was reported by SCU */
+		err = (s16)result[0];
+		if (err >= 0)
+			goto error;
+
+		/* check for the known error codes */
+		switch (err) {
+		case SCU_RESULT_UNKCMD:
+			p = "SCU_RESULT_UNKCMD";
+			break;
+		case SCU_RESULT_UNKSTD:
+			p = "SCU_RESULT_UNKSTD";
+			break;
+		case SCU_RESULT_SIZE:
+			p = "SCU_RESULT_SIZE";
+			break;
+		case SCU_RESULT_INVPAR:
+			p = "SCU_RESULT_INVPAR";
+			break;
+		default: /* Other negative values are errors */
+			sprintf(errname, "ERROR: %d\n", err);
+			p = errname;
+		}
+		printk(KERN_ERR "drxk: %s while sending cmd 0x%04x with params:", p, cmd);
+		print_hex_dump_bytes("drxk: ", DUMP_PREFIX_NONE, buffer, cnt);
+		status = -EINVAL;
+		goto error2;
+	}
+
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+error2:
+	mutex_unlock(&state->mutex);
+	return status;
+}
+
+static int SetIqmAf(struct drxk_state *state, bool active)
+{
+	u16 data = 0;
+	int status;
+
+	dprintk(1, "\n");
+
+	/* Configure IQM */
+	status = read16(state, IQM_AF_STDBY__A, &data);
+	if (status < 0)
+		goto error;
+
+	if (!active) {
+		data |= (IQM_AF_STDBY_STDBY_ADC_STANDBY
+				| IQM_AF_STDBY_STDBY_AMP_STANDBY
+				| IQM_AF_STDBY_STDBY_PD_STANDBY
+				| IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY
+				| IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY);
+	} else {
+		data &= ((~IQM_AF_STDBY_STDBY_ADC_STANDBY)
+				& (~IQM_AF_STDBY_STDBY_AMP_STANDBY)
+				& (~IQM_AF_STDBY_STDBY_PD_STANDBY)
+				& (~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY)
+				& (~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY)
+			);
+	}
+	status = write16(state, IQM_AF_STDBY__A, data);
+
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int CtrlPowerMode(struct drxk_state *state, enum DRXPowerMode *mode)
+{
+	int status = 0;
+	u16 sioCcPwdMode = 0;
+
+	dprintk(1, "\n");
+
+	/* Check arguments */
+	if (mode == NULL)
+		return -EINVAL;
+
+	switch (*mode) {
+	case DRX_POWER_UP:
+		sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_NONE;
+		break;
+	case DRXK_POWER_DOWN_OFDM:
+		sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_OFDM;
+		break;
+	case DRXK_POWER_DOWN_CORE:
+		sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_CLOCK;
+		break;
+	case DRXK_POWER_DOWN_PLL:
+		sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_PLL;
+		break;
+	case DRX_POWER_DOWN:
+		sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_OSC;
+		break;
+	default:
+		/* Unknow sleep mode */
+		return -EINVAL;
+	}
+
+	/* If already in requested power mode, do nothing */
+	if (state->m_currentPowerMode == *mode)
+		return 0;
+
+	/* For next steps make sure to start from DRX_POWER_UP mode */
+	if (state->m_currentPowerMode != DRX_POWER_UP) {
+		status = PowerUpDevice(state);
+		if (status < 0)
+			goto error;
+		status = DVBTEnableOFDMTokenRing(state, true);
+		if (status < 0)
+			goto error;
+	}
+
+	if (*mode == DRX_POWER_UP) {
+		/* Restore analog & pin configuartion */
+	} else {
+		/* Power down to requested mode */
+		/* Backup some register settings */
+		/* Set pins with possible pull-ups connected
+		   to them in input mode */
+		/* Analog power down */
+		/* ADC power down */
+		/* Power down device */
+		/* stop all comm_exec */
+		/* Stop and power down previous standard */
+		switch (state->m_OperationMode) {
+		case OM_DVBT:
+			status = MPEGTSStop(state);
+			if (status < 0)
+				goto error;
+			status = PowerDownDVBT(state, false);
+			if (status < 0)
+				goto error;
+			break;
+		case OM_QAM_ITU_A:
+		case OM_QAM_ITU_C:
+			status = MPEGTSStop(state);
+			if (status < 0)
+				goto error;
+			status = PowerDownQAM(state);
+			if (status < 0)
+				goto error;
+			break;
+		default:
+			break;
+		}
+		status = DVBTEnableOFDMTokenRing(state, false);
+		if (status < 0)
+			goto error;
+		status = write16(state, SIO_CC_PWD_MODE__A, sioCcPwdMode);
+		if (status < 0)
+			goto error;
+		status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
+		if (status < 0)
+			goto error;
+
+		if (*mode != DRXK_POWER_DOWN_OFDM) {
+			state->m_HICfgCtrl |=
+				SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
+			status = HI_CfgCommand(state);
+			if (status < 0)
+				goto error;
+		}
+	}
+	state->m_currentPowerMode = *mode;
+
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+	return status;
+}
+
+static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode)
+{
+	enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
+	u16 cmdResult = 0;
+	u16 data = 0;
+	int status;
+
+	dprintk(1, "\n");
+
+	status = read16(state, SCU_COMM_EXEC__A, &data);
+	if (status < 0)
+		goto error;
+	if (data == SCU_COMM_EXEC_ACTIVE) {
+		/* Send OFDM stop command */
+		status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
+		if (status < 0)
+			goto error;
+		/* Send OFDM reset command */
+		status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
+		if (status < 0)
+			goto error;
+	}
+
+	/* Reset datapath for OFDM, processors first */
+	status = write16(state, OFDM_SC_COMM_EXEC__A, OFDM_SC_COMM_EXEC_STOP);
+	if (status < 0)
+		goto error;
+	status = write16(state, OFDM_LC_COMM_EXEC__A, OFDM_LC_COMM_EXEC_STOP);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_STOP);
+	if (status < 0)
+		goto error;
+
+	/* powerdown AFE                   */
+	status = SetIqmAf(state, false);
+	if (status < 0)
+		goto error;
+
+	/* powerdown to OFDM mode          */
+	if (setPowerMode) {
+		status = CtrlPowerMode(state, &powerMode);
+		if (status < 0)
+			goto error;
+	}
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int SetOperationMode(struct drxk_state *state,
+			    enum OperationMode oMode)
+{
+	int status = 0;
+
+	dprintk(1, "\n");
+	/*
+	   Stop and power down previous standard
+	   TODO investigate total power down instead of partial
+	   power down depending on "previous" standard.
+	 */
+
+	/* disable HW lock indicator */
+	status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+	if (status < 0)
+		goto error;
+
+	/* Device is already at the required mode */
+	if (state->m_OperationMode == oMode)
+		return 0;
+
+	switch (state->m_OperationMode) {
+		/* OM_NONE was added for start up */
+	case OM_NONE:
+		break;
+	case OM_DVBT:
+		status = MPEGTSStop(state);
+		if (status < 0)
+			goto error;
+		status = PowerDownDVBT(state, true);
+		if (status < 0)
+			goto error;
+		state->m_OperationMode = OM_NONE;
+		break;
+	case OM_QAM_ITU_A:	/* fallthrough */
+	case OM_QAM_ITU_C:
+		status = MPEGTSStop(state);
+		if (status < 0)
+			goto error;
+		status = PowerDownQAM(state);
+		if (status < 0)
+			goto error;
+		state->m_OperationMode = OM_NONE;
+		break;
+	case OM_QAM_ITU_B:
+	default:
+		status = -EINVAL;
+		goto error;
+	}
+
+	/*
+		Power up new standard
+		*/
+	switch (oMode) {
+	case OM_DVBT:
+		dprintk(1, ": DVB-T\n");
+		state->m_OperationMode = oMode;
+		status = SetDVBTStandard(state, oMode);
+		if (status < 0)
+			goto error;
+		break;
+	case OM_QAM_ITU_A:	/* fallthrough */
+	case OM_QAM_ITU_C:
+		dprintk(1, ": DVB-C Annex %c\n",
+			(state->m_OperationMode == OM_QAM_ITU_A) ? 'A' : 'C');
+		state->m_OperationMode = oMode;
+		status = SetQAMStandard(state, oMode);
+		if (status < 0)
+			goto error;
+		break;
+	case OM_QAM_ITU_B:
+	default:
+		status = -EINVAL;
+	}
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int Start(struct drxk_state *state, s32 offsetFreq,
+		 s32 IntermediateFrequency)
+{
+	int status = -EINVAL;
+
+	u16 IFreqkHz;
+	s32 OffsetkHz = offsetFreq / 1000;
+
+	dprintk(1, "\n");
+	if (state->m_DrxkState != DRXK_STOPPED &&
+		state->m_DrxkState != DRXK_DTV_STARTED)
+		goto error;
+
+	state->m_bMirrorFreqSpect = (state->props.inversion == INVERSION_ON);
+
+	if (IntermediateFrequency < 0) {
+		state->m_bMirrorFreqSpect = !state->m_bMirrorFreqSpect;
+		IntermediateFrequency = -IntermediateFrequency;
+	}
+
+	switch (state->m_OperationMode) {
+	case OM_QAM_ITU_A:
+	case OM_QAM_ITU_C:
+		IFreqkHz = (IntermediateFrequency / 1000);
+		status = SetQAM(state, IFreqkHz, OffsetkHz);
+		if (status < 0)
+			goto error;
+		state->m_DrxkState = DRXK_DTV_STARTED;
+		break;
+	case OM_DVBT:
+		IFreqkHz = (IntermediateFrequency / 1000);
+		status = MPEGTSStop(state);
+		if (status < 0)
+			goto error;
+		status = SetDVBT(state, IFreqkHz, OffsetkHz);
+		if (status < 0)
+			goto error;
+		status = DVBTStart(state);
+		if (status < 0)
+			goto error;
+		state->m_DrxkState = DRXK_DTV_STARTED;
+		break;
+	default:
+		break;
+	}
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int ShutDown(struct drxk_state *state)
+{
+	dprintk(1, "\n");
+
+	MPEGTSStop(state);
+	return 0;
+}
+
+static int GetLockStatus(struct drxk_state *state, u32 *pLockStatus,
+			 u32 Time)
+{
+	int status = -EINVAL;
+
+	dprintk(1, "\n");
+
+	if (pLockStatus == NULL)
+		goto error;
+
+	*pLockStatus = NOT_LOCKED;
+
+	/* define the SCU command code */
+	switch (state->m_OperationMode) {
+	case OM_QAM_ITU_A:
+	case OM_QAM_ITU_B:
+	case OM_QAM_ITU_C:
+		status = GetQAMLockStatus(state, pLockStatus);
+		break;
+	case OM_DVBT:
+		status = GetDVBTLockStatus(state, pLockStatus);
+		break;
+	default:
+		break;
+	}
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int MPEGTSStart(struct drxk_state *state)
+{
+	int status;
+
+	u16 fecOcSncMode = 0;
+
+	/* Allow OC to sync again */
+	status = read16(state, FEC_OC_SNC_MODE__A, &fecOcSncMode);
+	if (status < 0)
+		goto error;
+	fecOcSncMode &= ~FEC_OC_SNC_MODE_SHUTDOWN__M;
+	status = write16(state, FEC_OC_SNC_MODE__A, fecOcSncMode);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_SNC_UNLOCK__A, 1);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int MPEGTSDtoInit(struct drxk_state *state)
+{
+	int status;
+
+	dprintk(1, "\n");
+
+	/* Rate integration settings */
+	status = write16(state, FEC_OC_RCN_CTL_STEP_LO__A, 0x0000);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_RCN_CTL_STEP_HI__A, 0x000C);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_RCN_GAIN__A, 0x000A);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_AVR_PARM_A__A, 0x0008);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_AVR_PARM_B__A, 0x0006);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_TMD_HI_MARGIN__A, 0x0680);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_TMD_LO_MARGIN__A, 0x0080);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_TMD_COUNT__A, 0x03F4);
+	if (status < 0)
+		goto error;
+
+	/* Additional configuration */
+	status = write16(state, FEC_OC_OCR_INVERT__A, 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_SNC_LWM__A, 2);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_SNC_HWM__A, 12);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+	return status;
+}
+
+static int MPEGTSDtoSetup(struct drxk_state *state,
+			  enum OperationMode oMode)
+{
+	int status;
+
+	u16 fecOcRegMode = 0;	/* FEC_OC_MODE       register value */
+	u16 fecOcRegIprMode = 0;	/* FEC_OC_IPR_MODE   register value */
+	u16 fecOcDtoMode = 0;	/* FEC_OC_IPR_INVERT register value */
+	u16 fecOcFctMode = 0;	/* FEC_OC_IPR_INVERT register value */
+	u16 fecOcDtoPeriod = 2;	/* FEC_OC_IPR_INVERT register value */
+	u16 fecOcDtoBurstLen = 188;	/* FEC_OC_IPR_INVERT register value */
+	u32 fecOcRcnCtlRate = 0;	/* FEC_OC_IPR_INVERT register value */
+	u16 fecOcTmdMode = 0;
+	u16 fecOcTmdIntUpdRate = 0;
+	u32 maxBitRate = 0;
+	bool staticCLK = false;
+
+	dprintk(1, "\n");
+
+	/* Check insertion of the Reed-Solomon parity bytes */
+	status = read16(state, FEC_OC_MODE__A, &fecOcRegMode);
+	if (status < 0)
+		goto error;
+	status = read16(state, FEC_OC_IPR_MODE__A, &fecOcRegIprMode);
+	if (status < 0)
+		goto error;
+	fecOcRegMode &= (~FEC_OC_MODE_PARITY__M);
+	fecOcRegIprMode &= (~FEC_OC_IPR_MODE_MVAL_DIS_PAR__M);
+	if (state->m_insertRSByte == true) {
+		/* enable parity symbol forward */
+		fecOcRegMode |= FEC_OC_MODE_PARITY__M;
+		/* MVAL disable during parity bytes */
+		fecOcRegIprMode |= FEC_OC_IPR_MODE_MVAL_DIS_PAR__M;
+		/* TS burst length to 204 */
+		fecOcDtoBurstLen = 204;
+	}
+
+	/* Check serial or parrallel output */
+	fecOcRegIprMode &= (~(FEC_OC_IPR_MODE_SERIAL__M));
+	if (state->m_enableParallel == false) {
+		/* MPEG data output is serial -> set ipr_mode[0] */
+		fecOcRegIprMode |= FEC_OC_IPR_MODE_SERIAL__M;
+	}
+
+	switch (oMode) {
+	case OM_DVBT:
+		maxBitRate = state->m_DVBTBitrate;
+		fecOcTmdMode = 3;
+		fecOcRcnCtlRate = 0xC00000;
+		staticCLK = state->m_DVBTStaticCLK;
+		break;
+	case OM_QAM_ITU_A:	/* fallthrough */
+	case OM_QAM_ITU_C:
+		fecOcTmdMode = 0x0004;
+		fecOcRcnCtlRate = 0xD2B4EE;	/* good for >63 Mb/s */
+		maxBitRate = state->m_DVBCBitrate;
+		staticCLK = state->m_DVBCStaticCLK;
+		break;
+	default:
+		status = -EINVAL;
+	}		/* switch (standard) */
+	if (status < 0)
+		goto error;
+
+	/* Configure DTO's */
+	if (staticCLK) {
+		u32 bitRate = 0;
+
+		/* Rational DTO for MCLK source (static MCLK rate),
+			Dynamic DTO for optimal grouping
+			(avoid intra-packet gaps),
+			DTO offset enable to sync TS burst with MSTRT */
+		fecOcDtoMode = (FEC_OC_DTO_MODE_DYNAMIC__M |
+				FEC_OC_DTO_MODE_OFFSET_ENABLE__M);
+		fecOcFctMode = (FEC_OC_FCT_MODE_RAT_ENA__M |
+				FEC_OC_FCT_MODE_VIRT_ENA__M);
+
+		/* Check user defined bitrate */
+		bitRate = maxBitRate;
+		if (bitRate > 75900000UL) {	/* max is 75.9 Mb/s */
+			bitRate = 75900000UL;
+		}
+		/* Rational DTO period:
+			dto_period = (Fsys / bitrate) - 2
+
+			Result should be floored,
+			to make sure >= requested bitrate
+			*/
+		fecOcDtoPeriod = (u16) (((state->m_sysClockFreq)
+						* 1000) / bitRate);
+		if (fecOcDtoPeriod <= 2)
+			fecOcDtoPeriod = 0;
+		else
+			fecOcDtoPeriod -= 2;
+		fecOcTmdIntUpdRate = 8;
+	} else {
+		/* (commonAttr->staticCLK == false) => dynamic mode */
+		fecOcDtoMode = FEC_OC_DTO_MODE_DYNAMIC__M;
+		fecOcFctMode = FEC_OC_FCT_MODE__PRE;
+		fecOcTmdIntUpdRate = 5;
+	}
+
+	/* Write appropriate registers with requested configuration */
+	status = write16(state, FEC_OC_DTO_BURST_LEN__A, fecOcDtoBurstLen);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_DTO_PERIOD__A, fecOcDtoPeriod);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_DTO_MODE__A, fecOcDtoMode);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_FCT_MODE__A, fecOcFctMode);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_MODE__A, fecOcRegMode);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_IPR_MODE__A, fecOcRegIprMode);
+	if (status < 0)
+		goto error;
+
+	/* Rate integration settings */
+	status = write32(state, FEC_OC_RCN_CTL_RATE_LO__A, fecOcRcnCtlRate);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_TMD_INT_UPD_RATE__A, fecOcTmdIntUpdRate);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_TMD_MODE__A, fecOcTmdMode);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int MPEGTSConfigurePolarity(struct drxk_state *state)
+{
+	u16 fecOcRegIprInvert = 0;
+
+	/* Data mask for the output data byte */
+	u16 InvertDataMask =
+	    FEC_OC_IPR_INVERT_MD7__M | FEC_OC_IPR_INVERT_MD6__M |
+	    FEC_OC_IPR_INVERT_MD5__M | FEC_OC_IPR_INVERT_MD4__M |
+	    FEC_OC_IPR_INVERT_MD3__M | FEC_OC_IPR_INVERT_MD2__M |
+	    FEC_OC_IPR_INVERT_MD1__M | FEC_OC_IPR_INVERT_MD0__M;
+
+	dprintk(1, "\n");
+
+	/* Control selective inversion of output bits */
+	fecOcRegIprInvert &= (~(InvertDataMask));
+	if (state->m_invertDATA == true)
+		fecOcRegIprInvert |= InvertDataMask;
+	fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MERR__M));
+	if (state->m_invertERR == true)
+		fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MERR__M;
+	fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MSTRT__M));
+	if (state->m_invertSTR == true)
+		fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MSTRT__M;
+	fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MVAL__M));
+	if (state->m_invertVAL == true)
+		fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MVAL__M;
+	fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MCLK__M));
+	if (state->m_invertCLK == true)
+		fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MCLK__M;
+
+	return write16(state, FEC_OC_IPR_INVERT__A, fecOcRegIprInvert);
+}
+
+#define   SCU_RAM_AGC_KI_INV_RF_POL__M 0x4000
+
+static int SetAgcRf(struct drxk_state *state,
+		    struct SCfgAgc *pAgcCfg, bool isDTV)
+{
+	int status = -EINVAL;
+	u16 data = 0;
+	struct SCfgAgc *pIfAgcSettings;
+
+	dprintk(1, "\n");
+
+	if (pAgcCfg == NULL)
+		goto error;
+
+	switch (pAgcCfg->ctrlMode) {
+	case DRXK_AGC_CTRL_AUTO:
+		/* Enable RF AGC DAC */
+		status = read16(state, IQM_AF_STDBY__A, &data);
+		if (status < 0)
+			goto error;
+		data &= ~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY;
+		status = write16(state, IQM_AF_STDBY__A, data);
+		if (status < 0)
+			goto error;
+		status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+		if (status < 0)
+			goto error;
+
+		/* Enable SCU RF AGC loop */
+		data &= ~SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
+
+		/* Polarity */
+		if (state->m_RfAgcPol)
+			data |= SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
+		else
+			data &= ~SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
+		status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+		if (status < 0)
+			goto error;
+
+		/* Set speed (using complementary reduction value) */
+		status = read16(state, SCU_RAM_AGC_KI_RED__A, &data);
+		if (status < 0)
+			goto error;
+
+		data &= ~SCU_RAM_AGC_KI_RED_RAGC_RED__M;
+		data |= (~(pAgcCfg->speed <<
+				SCU_RAM_AGC_KI_RED_RAGC_RED__B)
+				& SCU_RAM_AGC_KI_RED_RAGC_RED__M);
+
+		status = write16(state, SCU_RAM_AGC_KI_RED__A, data);
+		if (status < 0)
+			goto error;
+
+		if (IsDVBT(state))
+			pIfAgcSettings = &state->m_dvbtIfAgcCfg;
+		else if (IsQAM(state))
+			pIfAgcSettings = &state->m_qamIfAgcCfg;
+		else
+			pIfAgcSettings = &state->m_atvIfAgcCfg;
+		if (pIfAgcSettings == NULL) {
+			status = -EINVAL;
+			goto error;
+		}
+
+		/* Set TOP, only if IF-AGC is in AUTO mode */
+		if (pIfAgcSettings->ctrlMode == DRXK_AGC_CTRL_AUTO)
+			status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pAgcCfg->top);
+			if (status < 0)
+				goto error;
+
+		/* Cut-Off current */
+		status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, pAgcCfg->cutOffCurrent);
+		if (status < 0)
+			goto error;
+
+		/* Max. output level */
+		status = write16(state, SCU_RAM_AGC_RF_MAX__A, pAgcCfg->maxOutputLevel);
+		if (status < 0)
+			goto error;
+
+		break;
+
+	case DRXK_AGC_CTRL_USER:
+		/* Enable RF AGC DAC */
+		status = read16(state, IQM_AF_STDBY__A, &data);
+		if (status < 0)
+			goto error;
+		data &= ~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY;
+		status = write16(state, IQM_AF_STDBY__A, data);
+		if (status < 0)
+			goto error;
+
+		/* Disable SCU RF AGC loop */
+		status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+		if (status < 0)
+			goto error;
+		data |= SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
+		if (state->m_RfAgcPol)
+			data |= SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
+		else
+			data &= ~SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
+		status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+		if (status < 0)
+			goto error;
+
+		/* SCU c.o.c. to 0, enabling full control range */
+		status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, 0);
+		if (status < 0)
+			goto error;
+
+		/* Write value to output pin */
+		status = write16(state, SCU_RAM_AGC_RF_IACCU_HI__A, pAgcCfg->outputLevel);
+		if (status < 0)
+			goto error;
+		break;
+
+	case DRXK_AGC_CTRL_OFF:
+		/* Disable RF AGC DAC */
+		status = read16(state, IQM_AF_STDBY__A, &data);
+		if (status < 0)
+			goto error;
+		data |= IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY;
+		status = write16(state, IQM_AF_STDBY__A, data);
+		if (status < 0)
+			goto error;
+
+		/* Disable SCU RF AGC loop */
+		status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+		if (status < 0)
+			goto error;
+		data |= SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
+		status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+		if (status < 0)
+			goto error;
+		break;
+
+	default:
+		status = -EINVAL;
+
+	}
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+#define SCU_RAM_AGC_KI_INV_IF_POL__M 0x2000
+
+static int SetAgcIf(struct drxk_state *state,
+		    struct SCfgAgc *pAgcCfg, bool isDTV)
+{
+	u16 data = 0;
+	int status = 0;
+	struct SCfgAgc *pRfAgcSettings;
+
+	dprintk(1, "\n");
+
+	switch (pAgcCfg->ctrlMode) {
+	case DRXK_AGC_CTRL_AUTO:
+
+		/* Enable IF AGC DAC */
+		status = read16(state, IQM_AF_STDBY__A, &data);
+		if (status < 0)
+			goto error;
+		data &= ~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY;
+		status = write16(state, IQM_AF_STDBY__A, data);
+		if (status < 0)
+			goto error;
+
+		status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+		if (status < 0)
+			goto error;
+
+		/* Enable SCU IF AGC loop */
+		data &= ~SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;
+
+		/* Polarity */
+		if (state->m_IfAgcPol)
+			data |= SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
+		else
+			data &= ~SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
+		status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+		if (status < 0)
+			goto error;
+
+		/* Set speed (using complementary reduction value) */
+		status = read16(state, SCU_RAM_AGC_KI_RED__A, &data);
+		if (status < 0)
+			goto error;
+		data &= ~SCU_RAM_AGC_KI_RED_IAGC_RED__M;
+		data |= (~(pAgcCfg->speed <<
+				SCU_RAM_AGC_KI_RED_IAGC_RED__B)
+				& SCU_RAM_AGC_KI_RED_IAGC_RED__M);
+
+		status = write16(state, SCU_RAM_AGC_KI_RED__A, data);
+		if (status < 0)
+			goto error;
+
+		if (IsQAM(state))
+			pRfAgcSettings = &state->m_qamRfAgcCfg;
+		else
+			pRfAgcSettings = &state->m_atvRfAgcCfg;
+		if (pRfAgcSettings == NULL)
+			return -1;
+		/* Restore TOP */
+		status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pRfAgcSettings->top);
+		if (status < 0)
+			goto error;
+		break;
+
+	case DRXK_AGC_CTRL_USER:
+
+		/* Enable IF AGC DAC */
+		status = read16(state, IQM_AF_STDBY__A, &data);
+		if (status < 0)
+			goto error;
+		data &= ~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY;
+		status = write16(state, IQM_AF_STDBY__A, data);
+		if (status < 0)
+			goto error;
+
+		status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+		if (status < 0)
+			goto error;
+
+		/* Disable SCU IF AGC loop */
+		data |= SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;
+
+		/* Polarity */
+		if (state->m_IfAgcPol)
+			data |= SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
+		else
+			data &= ~SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
+		status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+		if (status < 0)
+			goto error;
+
+		/* Write value to output pin */
+		status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pAgcCfg->outputLevel);
+		if (status < 0)
+			goto error;
+		break;
+
+	case DRXK_AGC_CTRL_OFF:
+
+		/* Disable If AGC DAC */
+		status = read16(state, IQM_AF_STDBY__A, &data);
+		if (status < 0)
+			goto error;
+		data |= IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY;
+		status = write16(state, IQM_AF_STDBY__A, data);
+		if (status < 0)
+			goto error;
+
+		/* Disable SCU IF AGC loop */
+		status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+		if (status < 0)
+			goto error;
+		data |= SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;
+		status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+		if (status < 0)
+			goto error;
+		break;
+	}		/* switch (agcSettingsIf->ctrlMode) */
+
+	/* always set the top to support
+		configurations without if-loop */
+	status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, pAgcCfg->top);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int ReadIFAgc(struct drxk_state *state, u32 *pValue)
+{
+	u16 agcDacLvl;
+	int status;
+	u16 Level = 0;
+
+	dprintk(1, "\n");
+
+	status = read16(state, IQM_AF_AGC_IF__A, &agcDacLvl);
+	if (status < 0) {
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+		return status;
+	}
+
+	*pValue = 0;
+
+	if (agcDacLvl > DRXK_AGC_DAC_OFFSET)
+		Level = agcDacLvl - DRXK_AGC_DAC_OFFSET;
+	if (Level < 14000)
+		*pValue = (14000 - Level) / 4;
+	else
+		*pValue = 0;
+
+	return status;
+}
+
+static int GetQAMSignalToNoise(struct drxk_state *state,
+			       s32 *pSignalToNoise)
+{
+	int status = 0;
+	u16 qamSlErrPower = 0;	/* accum. error between
+					raw and sliced symbols */
+	u32 qamSlSigPower = 0;	/* used for MER, depends of
+					QAM modulation */
+	u32 qamSlMer = 0;	/* QAM MER */
+
+	dprintk(1, "\n");
+
+	/* MER calculation */
+
+	/* get the register value needed for MER */
+	status = read16(state, QAM_SL_ERR_POWER__A, &qamSlErrPower);
+	if (status < 0) {
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+		return -EINVAL;
+	}
+
+	switch (state->props.modulation) {
+	case QAM_16:
+		qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM16 << 2;
+		break;
+	case QAM_32:
+		qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM32 << 2;
+		break;
+	case QAM_64:
+		qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM64 << 2;
+		break;
+	case QAM_128:
+		qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM128 << 2;
+		break;
+	default:
+	case QAM_256:
+		qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM256 << 2;
+		break;
+	}
+
+	if (qamSlErrPower > 0) {
+		qamSlMer = Log10Times100(qamSlSigPower) -
+			Log10Times100((u32) qamSlErrPower);
+	}
+	*pSignalToNoise = qamSlMer;
+
+	return status;
+}
+
+static int GetDVBTSignalToNoise(struct drxk_state *state,
+				s32 *pSignalToNoise)
+{
+	int status;
+	u16 regData = 0;
+	u32 EqRegTdSqrErrI = 0;
+	u32 EqRegTdSqrErrQ = 0;
+	u16 EqRegTdSqrErrExp = 0;
+	u16 EqRegTdTpsPwrOfs = 0;
+	u16 EqRegTdReqSmbCnt = 0;
+	u32 tpsCnt = 0;
+	u32 SqrErrIQ = 0;
+	u32 a = 0;
+	u32 b = 0;
+	u32 c = 0;
+	u32 iMER = 0;
+	u16 transmissionParams = 0;
+
+	dprintk(1, "\n");
+
+	status = read16(state, OFDM_EQ_TOP_TD_TPS_PWR_OFS__A, &EqRegTdTpsPwrOfs);
+	if (status < 0)
+		goto error;
+	status = read16(state, OFDM_EQ_TOP_TD_REQ_SMB_CNT__A, &EqRegTdReqSmbCnt);
+	if (status < 0)
+		goto error;
+	status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_EXP__A, &EqRegTdSqrErrExp);
+	if (status < 0)
+		goto error;
+	status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_I__A, &regData);
+	if (status < 0)
+		goto error;
+	/* Extend SQR_ERR_I operational range */
+	EqRegTdSqrErrI = (u32) regData;
+	if ((EqRegTdSqrErrExp > 11) &&
+		(EqRegTdSqrErrI < 0x00000FFFUL)) {
+		EqRegTdSqrErrI += 0x00010000UL;
+	}
+	status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_Q__A, &regData);
+	if (status < 0)
+		goto error;
+	/* Extend SQR_ERR_Q operational range */
+	EqRegTdSqrErrQ = (u32) regData;
+	if ((EqRegTdSqrErrExp > 11) &&
+		(EqRegTdSqrErrQ < 0x00000FFFUL))
+		EqRegTdSqrErrQ += 0x00010000UL;
+
+	status = read16(state, OFDM_SC_RA_RAM_OP_PARAM__A, &transmissionParams);
+	if (status < 0)
+		goto error;
+
+	/* Check input data for MER */
+
+	/* MER calculation (in 0.1 dB) without math.h */
+	if ((EqRegTdTpsPwrOfs == 0) || (EqRegTdReqSmbCnt == 0))
+		iMER = 0;
+	else if ((EqRegTdSqrErrI + EqRegTdSqrErrQ) == 0) {
+		/* No error at all, this must be the HW reset value
+			* Apparently no first measurement yet
+			* Set MER to 0.0 */
+		iMER = 0;
+	} else {
+		SqrErrIQ = (EqRegTdSqrErrI + EqRegTdSqrErrQ) <<
+			EqRegTdSqrErrExp;
+		if ((transmissionParams &
+			OFDM_SC_RA_RAM_OP_PARAM_MODE__M)
+			== OFDM_SC_RA_RAM_OP_PARAM_MODE_2K)
+			tpsCnt = 17;
+		else
+			tpsCnt = 68;
+
+		/* IMER = 100 * log10 (x)
+			where x = (EqRegTdTpsPwrOfs^2 *
+			EqRegTdReqSmbCnt * tpsCnt)/SqrErrIQ
+
+			=> IMER = a + b -c
+			where a = 100 * log10 (EqRegTdTpsPwrOfs^2)
+			b = 100 * log10 (EqRegTdReqSmbCnt * tpsCnt)
+			c = 100 * log10 (SqrErrIQ)
+			*/
+
+		/* log(x) x = 9bits * 9bits->18 bits  */
+		a = Log10Times100(EqRegTdTpsPwrOfs *
+					EqRegTdTpsPwrOfs);
+		/* log(x) x = 16bits * 7bits->23 bits  */
+		b = Log10Times100(EqRegTdReqSmbCnt * tpsCnt);
+		/* log(x) x = (16bits + 16bits) << 15 ->32 bits  */
+		c = Log10Times100(SqrErrIQ);
+
+		iMER = a + b;
+		/* No negative MER, clip to zero */
+		if (iMER > c)
+			iMER -= c;
+		else
+			iMER = 0;
+	}
+	*pSignalToNoise = iMER;
+
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int GetSignalToNoise(struct drxk_state *state, s32 *pSignalToNoise)
+{
+	dprintk(1, "\n");
+
+	*pSignalToNoise = 0;
+	switch (state->m_OperationMode) {
+	case OM_DVBT:
+		return GetDVBTSignalToNoise(state, pSignalToNoise);
+	case OM_QAM_ITU_A:
+	case OM_QAM_ITU_C:
+		return GetQAMSignalToNoise(state, pSignalToNoise);
+	default:
+		break;
+	}
+	return 0;
+}
+
+#if 0
+static int GetDVBTQuality(struct drxk_state *state, s32 *pQuality)
+{
+	/* SNR Values for quasi errorfree reception rom Nordig 2.2 */
+	int status = 0;
+
+	dprintk(1, "\n");
+
+	static s32 QE_SN[] = {
+		51,		/* QPSK 1/2 */
+		69,		/* QPSK 2/3 */
+		79,		/* QPSK 3/4 */
+		89,		/* QPSK 5/6 */
+		97,		/* QPSK 7/8 */
+		108,		/* 16-QAM 1/2 */
+		131,		/* 16-QAM 2/3 */
+		146,		/* 16-QAM 3/4 */
+		156,		/* 16-QAM 5/6 */
+		160,		/* 16-QAM 7/8 */
+		165,		/* 64-QAM 1/2 */
+		187,		/* 64-QAM 2/3 */
+		202,		/* 64-QAM 3/4 */
+		216,		/* 64-QAM 5/6 */
+		225,		/* 64-QAM 7/8 */
+	};
+
+	*pQuality = 0;
+
+	do {
+		s32 SignalToNoise = 0;
+		u16 Constellation = 0;
+		u16 CodeRate = 0;
+		u32 SignalToNoiseRel;
+		u32 BERQuality;
+
+		status = GetDVBTSignalToNoise(state, &SignalToNoise);
+		if (status < 0)
+			break;
+		status = read16(state, OFDM_EQ_TOP_TD_TPS_CONST__A, &Constellation);
+		if (status < 0)
+			break;
+		Constellation &= OFDM_EQ_TOP_TD_TPS_CONST__M;
+
+		status = read16(state, OFDM_EQ_TOP_TD_TPS_CODE_HP__A, &CodeRate);
+		if (status < 0)
+			break;
+		CodeRate &= OFDM_EQ_TOP_TD_TPS_CODE_HP__M;
+
+		if (Constellation > OFDM_EQ_TOP_TD_TPS_CONST_64QAM ||
+		    CodeRate > OFDM_EQ_TOP_TD_TPS_CODE_LP_7_8)
+			break;
+		SignalToNoiseRel = SignalToNoise -
+		    QE_SN[Constellation * 5 + CodeRate];
+		BERQuality = 100;
+
+		if (SignalToNoiseRel < -70)
+			*pQuality = 0;
+		else if (SignalToNoiseRel < 30)
+			*pQuality = ((SignalToNoiseRel + 70) *
+				     BERQuality) / 100;
+		else
+			*pQuality = BERQuality;
+	} while (0);
+	return 0;
+};
+
+static int GetDVBCQuality(struct drxk_state *state, s32 *pQuality)
+{
+	int status = 0;
+	*pQuality = 0;
+
+	dprintk(1, "\n");
+
+	do {
+		u32 SignalToNoise = 0;
+		u32 BERQuality = 100;
+		u32 SignalToNoiseRel = 0;
+
+		status = GetQAMSignalToNoise(state, &SignalToNoise);
+		if (status < 0)
+			break;
+
+		switch (state->props.modulation) {
+		case QAM_16:
+			SignalToNoiseRel = SignalToNoise - 200;
+			break;
+		case QAM_32:
+			SignalToNoiseRel = SignalToNoise - 230;
+			break;	/* Not in NorDig */
+		case QAM_64:
+			SignalToNoiseRel = SignalToNoise - 260;
+			break;
+		case QAM_128:
+			SignalToNoiseRel = SignalToNoise - 290;
+			break;
+		default:
+		case QAM_256:
+			SignalToNoiseRel = SignalToNoise - 320;
+			break;
+		}
+
+		if (SignalToNoiseRel < -70)
+			*pQuality = 0;
+		else if (SignalToNoiseRel < 30)
+			*pQuality = ((SignalToNoiseRel + 70) *
+				     BERQuality) / 100;
+		else
+			*pQuality = BERQuality;
+	} while (0);
+
+	return status;
+}
+
+static int GetQuality(struct drxk_state *state, s32 *pQuality)
+{
+	dprintk(1, "\n");
+
+	switch (state->m_OperationMode) {
+	case OM_DVBT:
+		return GetDVBTQuality(state, pQuality);
+	case OM_QAM_ITU_A:
+		return GetDVBCQuality(state, pQuality);
+	default:
+		break;
+	}
+
+	return 0;
+}
+#endif
+
+/* Free data ram in SIO HI */
+#define SIO_HI_RA_RAM_USR_BEGIN__A 0x420040
+#define SIO_HI_RA_RAM_USR_END__A   0x420060
+
+#define DRXK_HI_ATOMIC_BUF_START (SIO_HI_RA_RAM_USR_BEGIN__A)
+#define DRXK_HI_ATOMIC_BUF_END   (SIO_HI_RA_RAM_USR_BEGIN__A + 7)
+#define DRXK_HI_ATOMIC_READ      SIO_HI_RA_RAM_PAR_3_ACP_RW_READ
+#define DRXK_HI_ATOMIC_WRITE     SIO_HI_RA_RAM_PAR_3_ACP_RW_WRITE
+
+#define DRXDAP_FASI_ADDR2BLOCK(addr)  (((addr) >> 22) & 0x3F)
+#define DRXDAP_FASI_ADDR2BANK(addr)   (((addr) >> 16) & 0x3F)
+#define DRXDAP_FASI_ADDR2OFFSET(addr) ((addr) & 0x7FFF)
+
+static int ConfigureI2CBridge(struct drxk_state *state, bool bEnableBridge)
+{
+	int status = -EINVAL;
+
+	dprintk(1, "\n");
+
+	if (state->m_DrxkState == DRXK_UNINITIALIZED)
+		return 0;
+	if (state->m_DrxkState == DRXK_POWERED_DOWN)
+		goto error;
+
+	if (state->no_i2c_bridge)
+		return 0;
+
+	status = write16(state, SIO_HI_RA_RAM_PAR_1__A, SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
+	if (status < 0)
+		goto error;
+	if (bEnableBridge) {
+		status = write16(state, SIO_HI_RA_RAM_PAR_2__A, SIO_HI_RA_RAM_PAR_2_BRD_CFG_CLOSED);
+		if (status < 0)
+			goto error;
+	} else {
+		status = write16(state, SIO_HI_RA_RAM_PAR_2__A, SIO_HI_RA_RAM_PAR_2_BRD_CFG_OPEN);
+		if (status < 0)
+			goto error;
+	}
+
+	status = HI_Command(state, SIO_HI_RA_RAM_CMD_BRDCTRL, 0);
+
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int SetPreSaw(struct drxk_state *state,
+		     struct SCfgPreSaw *pPreSawCfg)
+{
+	int status = -EINVAL;
+
+	dprintk(1, "\n");
+
+	if ((pPreSawCfg == NULL)
+	    || (pPreSawCfg->reference > IQM_AF_PDREF__M))
+		goto error;
+
+	status = write16(state, IQM_AF_PDREF__A, pPreSawCfg->reference);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int BLDirectCmd(struct drxk_state *state, u32 targetAddr,
+		       u16 romOffset, u16 nrOfElements, u32 timeOut)
+{
+	u16 blStatus = 0;
+	u16 offset = (u16) ((targetAddr >> 0) & 0x00FFFF);
+	u16 blockbank = (u16) ((targetAddr >> 16) & 0x000FFF);
+	int status;
+	unsigned long end;
+
+	dprintk(1, "\n");
+
+	mutex_lock(&state->mutex);
+	status = write16(state, SIO_BL_MODE__A, SIO_BL_MODE_DIRECT);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_BL_TGT_HDR__A, blockbank);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_BL_TGT_ADDR__A, offset);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_BL_SRC_ADDR__A, romOffset);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_BL_SRC_LEN__A, nrOfElements);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_BL_ENABLE__A, SIO_BL_ENABLE_ON);
+	if (status < 0)
+		goto error;
+
+	end = jiffies + msecs_to_jiffies(timeOut);
+	do {
+		status = read16(state, SIO_BL_STATUS__A, &blStatus);
+		if (status < 0)
+			goto error;
+	} while ((blStatus == 0x1) && time_is_after_jiffies(end));
+	if (blStatus == 0x1) {
+		printk(KERN_ERR "drxk: SIO not ready\n");
+		status = -EINVAL;
+		goto error2;
+	}
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+error2:
+	mutex_unlock(&state->mutex);
+	return status;
+
+}
+
+static int ADCSyncMeasurement(struct drxk_state *state, u16 *count)
+{
+	u16 data = 0;
+	int status;
+
+	dprintk(1, "\n");
+
+	/* Start measurement */
+	status = write16(state, IQM_AF_COMM_EXEC__A, IQM_AF_COMM_EXEC_ACTIVE);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_AF_START_LOCK__A, 1);
+	if (status < 0)
+		goto error;
+
+	*count = 0;
+	status = read16(state, IQM_AF_PHASE0__A, &data);
+	if (status < 0)
+		goto error;
+	if (data == 127)
+		*count = *count + 1;
+	status = read16(state, IQM_AF_PHASE1__A, &data);
+	if (status < 0)
+		goto error;
+	if (data == 127)
+		*count = *count + 1;
+	status = read16(state, IQM_AF_PHASE2__A, &data);
+	if (status < 0)
+		goto error;
+	if (data == 127)
+		*count = *count + 1;
+
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int ADCSynchronization(struct drxk_state *state)
+{
+	u16 count = 0;
+	int status;
+
+	dprintk(1, "\n");
+
+	status = ADCSyncMeasurement(state, &count);
+	if (status < 0)
+		goto error;
+
+	if (count == 1) {
+		/* Try sampling on a diffrent edge */
+		u16 clkNeg = 0;
+
+		status = read16(state, IQM_AF_CLKNEG__A, &clkNeg);
+		if (status < 0)
+			goto error;
+		if ((clkNeg & IQM_AF_CLKNEG_CLKNEGDATA__M) ==
+			IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS) {
+			clkNeg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
+			clkNeg |=
+				IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_NEG;
+		} else {
+			clkNeg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
+			clkNeg |=
+				IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS;
+		}
+		status = write16(state, IQM_AF_CLKNEG__A, clkNeg);
+		if (status < 0)
+			goto error;
+		status = ADCSyncMeasurement(state, &count);
+		if (status < 0)
+			goto error;
+	}
+
+	if (count < 2)
+		status = -EINVAL;
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int SetFrequencyShifter(struct drxk_state *state,
+			       u16 intermediateFreqkHz,
+			       s32 tunerFreqOffset, bool isDTV)
+{
+	bool selectPosImage = false;
+	u32 rfFreqResidual = tunerFreqOffset;
+	u32 fmFrequencyShift = 0;
+	bool tunerMirror = !state->m_bMirrorFreqSpect;
+	u32 adcFreq;
+	bool adcFlip;
+	int status;
+	u32 ifFreqActual;
+	u32 samplingFrequency = (u32) (state->m_sysClockFreq / 3);
+	u32 frequencyShift;
+	bool imageToSelect;
+
+	dprintk(1, "\n");
+
+	/*
+	   Program frequency shifter
+	   No need to account for mirroring on RF
+	 */
+	if (isDTV) {
+		if ((state->m_OperationMode == OM_QAM_ITU_A) ||
+		    (state->m_OperationMode == OM_QAM_ITU_C) ||
+		    (state->m_OperationMode == OM_DVBT))
+			selectPosImage = true;
+		else
+			selectPosImage = false;
+	}
+	if (tunerMirror)
+		/* tuner doesn't mirror */
+		ifFreqActual = intermediateFreqkHz +
+		    rfFreqResidual + fmFrequencyShift;
+	else
+		/* tuner mirrors */
+		ifFreqActual = intermediateFreqkHz -
+		    rfFreqResidual - fmFrequencyShift;
+	if (ifFreqActual > samplingFrequency / 2) {
+		/* adc mirrors */
+		adcFreq = samplingFrequency - ifFreqActual;
+		adcFlip = true;
+	} else {
+		/* adc doesn't mirror */
+		adcFreq = ifFreqActual;
+		adcFlip = false;
+	}
+
+	frequencyShift = adcFreq;
+	imageToSelect = state->m_rfmirror ^ tunerMirror ^
+	    adcFlip ^ selectPosImage;
+	state->m_IqmFsRateOfs =
+	    Frac28a((frequencyShift), samplingFrequency);
+
+	if (imageToSelect)
+		state->m_IqmFsRateOfs = ~state->m_IqmFsRateOfs + 1;
+
+	/* Program frequency shifter with tuner offset compensation */
+	/* frequencyShift += tunerFreqOffset; TODO */
+	status = write32(state, IQM_FS_RATE_OFS_LO__A,
+			 state->m_IqmFsRateOfs);
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int InitAGC(struct drxk_state *state, bool isDTV)
+{
+	u16 ingainTgt = 0;
+	u16 ingainTgtMin = 0;
+	u16 ingainTgtMax = 0;
+	u16 clpCyclen = 0;
+	u16 clpSumMin = 0;
+	u16 clpDirTo = 0;
+	u16 snsSumMin = 0;
+	u16 snsSumMax = 0;
+	u16 clpSumMax = 0;
+	u16 snsDirTo = 0;
+	u16 kiInnergainMin = 0;
+	u16 ifIaccuHiTgt = 0;
+	u16 ifIaccuHiTgtMin = 0;
+	u16 ifIaccuHiTgtMax = 0;
+	u16 data = 0;
+	u16 fastClpCtrlDelay = 0;
+	u16 clpCtrlMode = 0;
+	int status = 0;
+
+	dprintk(1, "\n");
+
+	/* Common settings */
+	snsSumMax = 1023;
+	ifIaccuHiTgtMin = 2047;
+	clpCyclen = 500;
+	clpSumMax = 1023;
+
+	/* AGCInit() not available for DVBT; init done in microcode */
+	if (!IsQAM(state)) {
+		printk(KERN_ERR "drxk: %s: mode %d is not DVB-C\n", __func__, state->m_OperationMode);
+		return -EINVAL;
+	}
+
+	/* FIXME: Analog TV AGC require different settings */
+
+	/* Standard specific settings */
+	clpSumMin = 8;
+	clpDirTo = (u16) -9;
+	clpCtrlMode = 0;
+	snsSumMin = 8;
+	snsDirTo = (u16) -9;
+	kiInnergainMin = (u16) -1030;
+	ifIaccuHiTgtMax = 0x2380;
+	ifIaccuHiTgt = 0x2380;
+	ingainTgtMin = 0x0511;
+	ingainTgt = 0x0511;
+	ingainTgtMax = 5119;
+	fastClpCtrlDelay = state->m_qamIfAgcCfg.FastClipCtrlDelay;
+
+	status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A, fastClpCtrlDelay);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, SCU_RAM_AGC_CLP_CTRL_MODE__A, clpCtrlMode);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_INGAIN_TGT__A, ingainTgt);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, ingainTgtMin);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A, ingainTgtMax);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__A, ifIaccuHiTgtMin);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, ifIaccuHiTgtMax);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_IF_IACCU_HI__A, 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_IF_IACCU_LO__A, 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_RF_IACCU_HI__A, 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_RF_IACCU_LO__A, 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_CLP_SUM_MAX__A, clpSumMax);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_SNS_SUM_MAX__A, snsSumMax);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, SCU_RAM_AGC_KI_INNERGAIN_MIN__A, kiInnergainMin);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT__A, ifIaccuHiTgt);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_CLP_CYCLEN__A, clpCyclen);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, SCU_RAM_AGC_RF_SNS_DEV_MAX__A, 1023);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_RF_SNS_DEV_MIN__A, (u16) -1023);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_FAST_SNS_CTRL_DELAY__A, 50);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, SCU_RAM_AGC_KI_MAXMINGAIN_TH__A, 20);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_CLP_SUM_MIN__A, clpSumMin);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_SNS_SUM_MIN__A, snsSumMin);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_CLP_DIR_TO__A, clpDirTo);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_SNS_DIR_TO__A, snsDirTo);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_KI_MINGAIN__A, 0x7fff);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_KI_MAXGAIN__A, 0x0);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_KI_MIN__A, 0x0117);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_KI_MAX__A, 0x0657);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_CLP_SUM__A, 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_CLP_CYCCNT__A, 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_CLP_DIR_WD__A, 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_CLP_DIR_STP__A, 1);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_SNS_SUM__A, 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_SNS_CYCCNT__A, 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_SNS_DIR_WD__A, 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_SNS_DIR_STP__A, 1);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_SNS_CYCLEN__A, 500);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_KI_CYCLEN__A, 500);
+	if (status < 0)
+		goto error;
+
+	/* Initialize inner-loop KI gain factors */
+	status = read16(state, SCU_RAM_AGC_KI__A, &data);
+	if (status < 0)
+		goto error;
+
+	data = 0x0657;
+	data &= ~SCU_RAM_AGC_KI_RF__M;
+	data |= (DRXK_KI_RAGC_QAM << SCU_RAM_AGC_KI_RF__B);
+	data &= ~SCU_RAM_AGC_KI_IF__M;
+	data |= (DRXK_KI_IAGC_QAM << SCU_RAM_AGC_KI_IF__B);
+
+	status = write16(state, SCU_RAM_AGC_KI__A, data);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int DVBTQAMGetAccPktErr(struct drxk_state *state, u16 *packetErr)
+{
+	int status;
+
+	dprintk(1, "\n");
+	if (packetErr == NULL)
+		status = write16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, 0);
+	else
+		status = read16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, packetErr);
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int DVBTScCommand(struct drxk_state *state,
+			 u16 cmd, u16 subcmd,
+			 u16 param0, u16 param1, u16 param2,
+			 u16 param3, u16 param4)
+{
+	u16 curCmd = 0;
+	u16 errCode = 0;
+	u16 retryCnt = 0;
+	u16 scExec = 0;
+	int status;
+
+	dprintk(1, "\n");
+	status = read16(state, OFDM_SC_COMM_EXEC__A, &scExec);
+	if (scExec != 1) {
+		/* SC is not running */
+		status = -EINVAL;
+	}
+	if (status < 0)
+		goto error;
+
+	/* Wait until sc is ready to receive command */
+	retryCnt = 0;
+	do {
+		msleep(1);
+		status = read16(state, OFDM_SC_RA_RAM_CMD__A, &curCmd);
+		retryCnt++;
+	} while ((curCmd != 0) && (retryCnt < DRXK_MAX_RETRIES));
+	if (retryCnt >= DRXK_MAX_RETRIES && (status < 0))
+		goto error;
+
+	/* Write sub-command */
+	switch (cmd) {
+		/* All commands using sub-cmd */
+	case OFDM_SC_RA_RAM_CMD_PROC_START:
+	case OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM:
+	case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM:
+		status = write16(state, OFDM_SC_RA_RAM_CMD_ADDR__A, subcmd);
+		if (status < 0)
+			goto error;
+		break;
+	default:
+		/* Do nothing */
+		break;
+	}
+
+	/* Write needed parameters and the command */
+	switch (cmd) {
+		/* All commands using 5 parameters */
+		/* All commands using 4 parameters */
+		/* All commands using 3 parameters */
+		/* All commands using 2 parameters */
+	case OFDM_SC_RA_RAM_CMD_PROC_START:
+	case OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM:
+	case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM:
+		status = write16(state, OFDM_SC_RA_RAM_PARAM1__A, param1);
+		/* All commands using 1 parameters */
+	case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING:
+	case OFDM_SC_RA_RAM_CMD_USER_IO:
+		status = write16(state, OFDM_SC_RA_RAM_PARAM0__A, param0);
+		/* All commands using 0 parameters */
+	case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM:
+	case OFDM_SC_RA_RAM_CMD_NULL:
+		/* Write command */
+		status = write16(state, OFDM_SC_RA_RAM_CMD__A, cmd);
+		break;
+	default:
+		/* Unknown command */
+		status = -EINVAL;
+	}
+	if (status < 0)
+		goto error;
+
+	/* Wait until sc is ready processing command */
+	retryCnt = 0;
+	do {
+		msleep(1);
+		status = read16(state, OFDM_SC_RA_RAM_CMD__A, &curCmd);
+		retryCnt++;
+	} while ((curCmd != 0) && (retryCnt < DRXK_MAX_RETRIES));
+	if (retryCnt >= DRXK_MAX_RETRIES && (status < 0))
+		goto error;
+
+	/* Check for illegal cmd */
+	status = read16(state, OFDM_SC_RA_RAM_CMD_ADDR__A, &errCode);
+	if (errCode == 0xFFFF) {
+		/* illegal command */
+		status = -EINVAL;
+	}
+	if (status < 0)
+		goto error;
+
+	/* Retreive results parameters from SC */
+	switch (cmd) {
+		/* All commands yielding 5 results */
+		/* All commands yielding 4 results */
+		/* All commands yielding 3 results */
+		/* All commands yielding 2 results */
+		/* All commands yielding 1 result */
+	case OFDM_SC_RA_RAM_CMD_USER_IO:
+	case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM:
+		status = read16(state, OFDM_SC_RA_RAM_PARAM0__A, &(param0));
+		/* All commands yielding 0 results */
+	case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING:
+	case OFDM_SC_RA_RAM_CMD_SET_TIMER:
+	case OFDM_SC_RA_RAM_CMD_PROC_START:
+	case OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM:
+	case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM:
+	case OFDM_SC_RA_RAM_CMD_NULL:
+		break;
+	default:
+		/* Unknown command */
+		status = -EINVAL;
+		break;
+	}			/* switch (cmd->cmd) */
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int PowerUpDVBT(struct drxk_state *state)
+{
+	enum DRXPowerMode powerMode = DRX_POWER_UP;
+	int status;
+
+	dprintk(1, "\n");
+	status = CtrlPowerMode(state, &powerMode);
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int DVBTCtrlSetIncEnable(struct drxk_state *state, bool *enabled)
+{
+	int status;
+
+	dprintk(1, "\n");
+	if (*enabled == true)
+		status = write16(state, IQM_CF_BYPASSDET__A, 0);
+	else
+		status = write16(state, IQM_CF_BYPASSDET__A, 1);
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+#define DEFAULT_FR_THRES_8K     4000
+static int DVBTCtrlSetFrEnable(struct drxk_state *state, bool *enabled)
+{
+
+	int status;
+
+	dprintk(1, "\n");
+	if (*enabled == true) {
+		/* write mask to 1 */
+		status = write16(state, OFDM_SC_RA_RAM_FR_THRES_8K__A,
+				   DEFAULT_FR_THRES_8K);
+	} else {
+		/* write mask to 0 */
+		status = write16(state, OFDM_SC_RA_RAM_FR_THRES_8K__A, 0);
+	}
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+	return status;
+}
+
+static int DVBTCtrlSetEchoThreshold(struct drxk_state *state,
+				    struct DRXKCfgDvbtEchoThres_t *echoThres)
+{
+	u16 data = 0;
+	int status;
+
+	dprintk(1, "\n");
+	status = read16(state, OFDM_SC_RA_RAM_ECHO_THRES__A, &data);
+	if (status < 0)
+		goto error;
+
+	switch (echoThres->fftMode) {
+	case DRX_FFTMODE_2K:
+		data &= ~OFDM_SC_RA_RAM_ECHO_THRES_2K__M;
+		data |= ((echoThres->threshold <<
+			OFDM_SC_RA_RAM_ECHO_THRES_2K__B)
+			& (OFDM_SC_RA_RAM_ECHO_THRES_2K__M));
+		break;
+	case DRX_FFTMODE_8K:
+		data &= ~OFDM_SC_RA_RAM_ECHO_THRES_8K__M;
+		data |= ((echoThres->threshold <<
+			OFDM_SC_RA_RAM_ECHO_THRES_8K__B)
+			& (OFDM_SC_RA_RAM_ECHO_THRES_8K__M));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	status = write16(state, OFDM_SC_RA_RAM_ECHO_THRES__A, data);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int DVBTCtrlSetSqiSpeed(struct drxk_state *state,
+			       enum DRXKCfgDvbtSqiSpeed *speed)
+{
+	int status = -EINVAL;
+
+	dprintk(1, "\n");
+
+	switch (*speed) {
+	case DRXK_DVBT_SQI_SPEED_FAST:
+	case DRXK_DVBT_SQI_SPEED_MEDIUM:
+	case DRXK_DVBT_SQI_SPEED_SLOW:
+		break;
+	default:
+		goto error;
+	}
+	status = write16(state, SCU_RAM_FEC_PRE_RS_BER_FILTER_SH__A,
+			   (u16) *speed);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief Activate DVBT specific presets
+* \param demod instance of demodulator.
+* \return DRXStatus_t.
+*
+* Called in DVBTSetStandard
+*
+*/
+static int DVBTActivatePresets(struct drxk_state *state)
+{
+	int status;
+	bool setincenable = false;
+	bool setfrenable = true;
+
+	struct DRXKCfgDvbtEchoThres_t echoThres2k = { 0, DRX_FFTMODE_2K };
+	struct DRXKCfgDvbtEchoThres_t echoThres8k = { 0, DRX_FFTMODE_8K };
+
+	dprintk(1, "\n");
+	status = DVBTCtrlSetIncEnable(state, &setincenable);
+	if (status < 0)
+		goto error;
+	status = DVBTCtrlSetFrEnable(state, &setfrenable);
+	if (status < 0)
+		goto error;
+	status = DVBTCtrlSetEchoThreshold(state, &echoThres2k);
+	if (status < 0)
+		goto error;
+	status = DVBTCtrlSetEchoThreshold(state, &echoThres8k);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A, state->m_dvbtIfAgcCfg.IngainTgtMax);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief Initialize channelswitch-independent settings for DVBT.
+* \param demod instance of demodulator.
+* \return DRXStatus_t.
+*
+* For ROM code channel filter taps are loaded from the bootloader. For microcode
+* the DVB-T taps from the drxk_filters.h are used.
+*/
+static int SetDVBTStandard(struct drxk_state *state,
+			   enum OperationMode oMode)
+{
+	u16 cmdResult = 0;
+	u16 data = 0;
+	int status;
+
+	dprintk(1, "\n");
+
+	PowerUpDVBT(state);
+	/* added antenna switch */
+	SwitchAntennaToDVBT(state);
+	/* send OFDM reset command */
+	status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
+	if (status < 0)
+		goto error;
+
+	/* send OFDM setenv command */
+	status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV, 0, NULL, 1, &cmdResult);
+	if (status < 0)
+		goto error;
+
+	/* reset datapath for OFDM, processors first */
+	status = write16(state, OFDM_SC_COMM_EXEC__A, OFDM_SC_COMM_EXEC_STOP);
+	if (status < 0)
+		goto error;
+	status = write16(state, OFDM_LC_COMM_EXEC__A, OFDM_LC_COMM_EXEC_STOP);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_STOP);
+	if (status < 0)
+		goto error;
+
+	/* IQM setup */
+	/* synchronize on ofdstate->m_festart */
+	status = write16(state, IQM_AF_UPD_SEL__A, 1);
+	if (status < 0)
+		goto error;
+	/* window size for clipping ADC detection */
+	status = write16(state, IQM_AF_CLP_LEN__A, 0);
+	if (status < 0)
+		goto error;
+	/* window size for for sense pre-SAW detection */
+	status = write16(state, IQM_AF_SNS_LEN__A, 0);
+	if (status < 0)
+		goto error;
+	/* sense threshold for sense pre-SAW detection */
+	status = write16(state, IQM_AF_AMUX__A, IQM_AF_AMUX_SIGNAL2ADC);
+	if (status < 0)
+		goto error;
+	status = SetIqmAf(state, true);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, IQM_AF_AGC_RF__A, 0);
+	if (status < 0)
+		goto error;
+
+	/* Impulse noise cruncher setup */
+	status = write16(state, IQM_AF_INC_LCT__A, 0);	/* crunch in IQM_CF */
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_CF_DET_LCT__A, 0);	/* detect in IQM_CF */
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_CF_WND_LEN__A, 3);	/* peak detector window length */
+	if (status < 0)
+		goto error;
+
+	status = write16(state, IQM_RC_STRETCH__A, 16);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_CF_OUT_ENA__A, 0x4);	/* enable output 2 */
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_CF_DS_ENA__A, 0x4);	/* decimate output 2 */
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_CF_SCALE__A, 1600);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_CF_SCALE_SH__A, 0);
+	if (status < 0)
+		goto error;
+
+	/* virtual clipping threshold for clipping ADC detection */
+	status = write16(state, IQM_AF_CLP_TH__A, 448);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_CF_DATATH__A, 495);	/* crunching threshold */
+	if (status < 0)
+		goto error;
+
+	status = BLChainCmd(state, DRXK_BL_ROM_OFFSET_TAPS_DVBT, DRXK_BLCC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, IQM_CF_PKDTH__A, 2);	/* peak detector threshold */
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_CF_POW_MEAS_LEN__A, 2);
+	if (status < 0)
+		goto error;
+	/* enable power measurement interrupt */
+	status = write16(state, IQM_CF_COMM_INT_MSK__A, 1);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_ACTIVE);
+	if (status < 0)
+		goto error;
+
+	/* IQM will not be reset from here, sync ADC and update/init AGC */
+	status = ADCSynchronization(state);
+	if (status < 0)
+		goto error;
+	status = SetPreSaw(state, &state->m_dvbtPreSawCfg);
+	if (status < 0)
+		goto error;
+
+	/* Halt SCU to enable safe non-atomic accesses */
+	status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD);
+	if (status < 0)
+		goto error;
+
+	status = SetAgcRf(state, &state->m_dvbtRfAgcCfg, true);
+	if (status < 0)
+		goto error;
+	status = SetAgcIf(state, &state->m_dvbtIfAgcCfg, true);
+	if (status < 0)
+		goto error;
+
+	/* Set Noise Estimation notch width and enable DC fix */
+	status = read16(state, OFDM_SC_RA_RAM_CONFIG__A, &data);
+	if (status < 0)
+		goto error;
+	data |= OFDM_SC_RA_RAM_CONFIG_NE_FIX_ENABLE__M;
+	status = write16(state, OFDM_SC_RA_RAM_CONFIG__A, data);
+	if (status < 0)
+		goto error;
+
+	/* Activate SCU to enable SCU commands */
+	status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
+	if (status < 0)
+		goto error;
+
+	if (!state->m_DRXK_A3_ROM_CODE) {
+		/* AGCInit() is not done for DVBT, so set agcFastClipCtrlDelay  */
+		status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A, state->m_dvbtIfAgcCfg.FastClipCtrlDelay);
+		if (status < 0)
+			goto error;
+	}
+
+	/* OFDM_SC setup */
+#ifdef COMPILE_FOR_NONRT
+	status = write16(state, OFDM_SC_RA_RAM_BE_OPT_DELAY__A, 1);
+	if (status < 0)
+		goto error;
+	status = write16(state, OFDM_SC_RA_RAM_BE_OPT_INIT_DELAY__A, 2);
+	if (status < 0)
+		goto error;
+#endif
+
+	/* FEC setup */
+	status = write16(state, FEC_DI_INPUT_CTL__A, 1);	/* OFDM input */
+	if (status < 0)
+		goto error;
+
+
+#ifdef COMPILE_FOR_NONRT
+	status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, 0x400);
+	if (status < 0)
+		goto error;
+#else
+	status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, 0x1000);
+	if (status < 0)
+		goto error;
+#endif
+	status = write16(state, FEC_RS_MEASUREMENT_PRESCALE__A, 0x0001);
+	if (status < 0)
+		goto error;
+
+	/* Setup MPEG bus */
+	status = MPEGTSDtoSetup(state, OM_DVBT);
+	if (status < 0)
+		goto error;
+	/* Set DVBT Presets */
+	status = DVBTActivatePresets(state);
+	if (status < 0)
+		goto error;
+
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+/*============================================================================*/
+/**
+* \brief Start dvbt demodulating for channel.
+* \param demod instance of demodulator.
+* \return DRXStatus_t.
+*/
+static int DVBTStart(struct drxk_state *state)
+{
+	u16 param1;
+	int status;
+	/* DRXKOfdmScCmd_t scCmd; */
+
+	dprintk(1, "\n");
+	/* Start correct processes to get in lock */
+	/* DRXK: OFDM_SC_RA_RAM_PROC_LOCKTRACK is no longer in mapfile! */
+	param1 = OFDM_SC_RA_RAM_LOCKTRACK_MIN;
+	status = DVBTScCommand(state, OFDM_SC_RA_RAM_CMD_PROC_START, 0, OFDM_SC_RA_RAM_SW_EVENT_RUN_NMASK__M, param1, 0, 0, 0);
+	if (status < 0)
+		goto error;
+	/* Start FEC OC */
+	status = MPEGTSStart(state);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_ACTIVE);
+	if (status < 0)
+		goto error;
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+
+/*============================================================================*/
+
+/**
+* \brief Set up dvbt demodulator for channel.
+* \param demod instance of demodulator.
+* \return DRXStatus_t.
+* // original DVBTSetChannel()
+*/
+static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
+		   s32 tunerFreqOffset)
+{
+	u16 cmdResult = 0;
+	u16 transmissionParams = 0;
+	u16 operationMode = 0;
+	u32 iqmRcRateOfs = 0;
+	u32 bandwidth = 0;
+	u16 param1;
+	int status;
+
+	dprintk(1, "IF =%d, TFO = %d\n", IntermediateFreqkHz, tunerFreqOffset);
+
+	status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
+	if (status < 0)
+		goto error;
+
+	/* Halt SCU to enable safe non-atomic accesses */
+	status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD);
+	if (status < 0)
+		goto error;
+
+	/* Stop processors */
+	status = write16(state, OFDM_SC_COMM_EXEC__A, OFDM_SC_COMM_EXEC_STOP);
+	if (status < 0)
+		goto error;
+	status = write16(state, OFDM_LC_COMM_EXEC__A, OFDM_LC_COMM_EXEC_STOP);
+	if (status < 0)
+		goto error;
+
+	/* Mandatory fix, always stop CP, required to set spl offset back to
+		hardware default (is set to 0 by ucode during pilot detection */
+	status = write16(state, OFDM_CP_COMM_EXEC__A, OFDM_CP_COMM_EXEC_STOP);
+	if (status < 0)
+		goto error;
+
+	/*== Write channel settings to device =====================================*/
+
+	/* mode */
+	switch (state->props.transmission_mode) {
+	case TRANSMISSION_MODE_AUTO:
+	default:
+		operationMode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M;
+		/* fall through , try first guess DRX_FFTMODE_8K */
+	case TRANSMISSION_MODE_8K:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_8K;
+		break;
+	case TRANSMISSION_MODE_2K:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_2K;
+		break;
+	}
+
+	/* guard */
+	switch (state->props.guard_interval) {
+	default:
+	case GUARD_INTERVAL_AUTO:
+		operationMode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M;
+		/* fall through , try first guess DRX_GUARD_1DIV4 */
+	case GUARD_INTERVAL_1_4:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_4;
+		break;
+	case GUARD_INTERVAL_1_32:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_32;
+		break;
+	case GUARD_INTERVAL_1_16:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_16;
+		break;
+	case GUARD_INTERVAL_1_8:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_8;
+		break;
+	}
+
+	/* hierarchy */
+	switch (state->props.hierarchy) {
+	case HIERARCHY_AUTO:
+	case HIERARCHY_NONE:
+	default:
+		operationMode |= OFDM_SC_RA_RAM_OP_AUTO_HIER__M;
+		/* fall through , try first guess SC_RA_RAM_OP_PARAM_HIER_NO */
+		/* transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_NO; */
+		/* break; */
+	case HIERARCHY_1:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A1;
+		break;
+	case HIERARCHY_2:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A2;
+		break;
+	case HIERARCHY_4:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A4;
+		break;
+	}
+
+
+	/* modulation */
+	switch (state->props.modulation) {
+	case QAM_AUTO:
+	default:
+		operationMode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M;
+		/* fall through , try first guess DRX_CONSTELLATION_QAM64 */
+	case QAM_64:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64;
+		break;
+	case QPSK:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QPSK;
+		break;
+	case QAM_16:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM16;
+		break;
+	}
+#if 0
+	/* No hierachical channels support in BDA */
+	/* Priority (only for hierarchical channels) */
+	switch (channel->priority) {
+	case DRX_PRIORITY_LOW:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_LO;
+		WR16(devAddr, OFDM_EC_SB_PRIOR__A,
+			OFDM_EC_SB_PRIOR_LO);
+		break;
+	case DRX_PRIORITY_HIGH:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI;
+		WR16(devAddr, OFDM_EC_SB_PRIOR__A,
+			OFDM_EC_SB_PRIOR_HI));
+		break;
+	case DRX_PRIORITY_UNKNOWN:	/* fall through */
+	default:
+		status = -EINVAL;
+		goto error;
+	}
+#else
+	/* Set Priorty high */
+	transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI;
+	status = write16(state, OFDM_EC_SB_PRIOR__A, OFDM_EC_SB_PRIOR_HI);
+	if (status < 0)
+		goto error;
+#endif
+
+	/* coderate */
+	switch (state->props.code_rate_HP) {
+	case FEC_AUTO:
+	default:
+		operationMode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M;
+		/* fall through , try first guess DRX_CODERATE_2DIV3 */
+	case FEC_2_3:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3;
+		break;
+	case FEC_1_2:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_1_2;
+		break;
+	case FEC_3_4:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_3_4;
+		break;
+	case FEC_5_6:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_5_6;
+		break;
+	case FEC_7_8:
+		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_7_8;
+		break;
+	}
+
+	/* SAW filter selection: normaly not necesarry, but if wanted
+		the application can select a SAW filter via the driver by using UIOs */
+	/* First determine real bandwidth (Hz) */
+	/* Also set delay for impulse noise cruncher */
+	/* Also set parameters for EC_OC fix, note EC_OC_REG_TMD_HIL_MAR is changed
+		by SC for fix for some 8K,1/8 guard but is restored by InitEC and ResetEC
+		functions */
+	switch (state->props.bandwidth_hz) {
+	case 0:
+		state->props.bandwidth_hz = 8000000;
+		/* fall though */
+	case 8000000:
+		bandwidth = DRXK_BANDWIDTH_8MHZ_IN_HZ;
+		status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3052);
+		if (status < 0)
+			goto error;
+		/* cochannel protection for PAL 8 MHz */
+		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 7);
+		if (status < 0)
+			goto error;
+		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 7);
+		if (status < 0)
+			goto error;
+		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 7);
+		if (status < 0)
+			goto error;
+		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
+		if (status < 0)
+			goto error;
+		break;
+	case 7000000:
+		bandwidth = DRXK_BANDWIDTH_7MHZ_IN_HZ;
+		status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3491);
+		if (status < 0)
+			goto error;
+		/* cochannel protection for PAL 7 MHz */
+		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 8);
+		if (status < 0)
+			goto error;
+		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 8);
+		if (status < 0)
+			goto error;
+		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 4);
+		if (status < 0)
+			goto error;
+		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
+		if (status < 0)
+			goto error;
+		break;
+	case 6000000:
+		bandwidth = DRXK_BANDWIDTH_6MHZ_IN_HZ;
+		status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 4073);
+		if (status < 0)
+			goto error;
+		/* cochannel protection for NTSC 6 MHz */
+		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 19);
+		if (status < 0)
+			goto error;
+		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 19);
+		if (status < 0)
+			goto error;
+		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 14);
+		if (status < 0)
+			goto error;
+		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
+		if (status < 0)
+			goto error;
+		break;
+	default:
+		status = -EINVAL;
+		goto error;
+	}
+
+	if (iqmRcRateOfs == 0) {
+		/* Now compute IQM_RC_RATE_OFS
+			(((SysFreq/BandWidth)/2)/2) -1) * 2^23)
+			=>
+			((SysFreq / BandWidth) * (2^21)) - (2^23)
+			*/
+		/* (SysFreq / BandWidth) * (2^28)  */
+		/* assert (MAX(sysClk)/MIN(bandwidth) < 16)
+			=> assert(MAX(sysClk) < 16*MIN(bandwidth))
+			=> assert(109714272 > 48000000) = true so Frac 28 can be used  */
+		iqmRcRateOfs = Frac28a((u32)
+					((state->m_sysClockFreq *
+						1000) / 3), bandwidth);
+		/* (SysFreq / BandWidth) * (2^21), rounding before truncating  */
+		if ((iqmRcRateOfs & 0x7fL) >= 0x40)
+			iqmRcRateOfs += 0x80L;
+		iqmRcRateOfs = iqmRcRateOfs >> 7;
+		/* ((SysFreq / BandWidth) * (2^21)) - (2^23)  */
+		iqmRcRateOfs = iqmRcRateOfs - (1 << 23);
+	}
+
+	iqmRcRateOfs &=
+		((((u32) IQM_RC_RATE_OFS_HI__M) <<
+		IQM_RC_RATE_OFS_LO__W) | IQM_RC_RATE_OFS_LO__M);
+	status = write32(state, IQM_RC_RATE_OFS_LO__A, iqmRcRateOfs);
+	if (status < 0)
+		goto error;
+
+	/* Bandwidth setting done */
+
+#if 0
+	status = DVBTSetFrequencyShift(demod, channel, tunerOffset);
+	if (status < 0)
+		goto error;
+#endif
+	status = SetFrequencyShifter(state, IntermediateFreqkHz, tunerFreqOffset, true);
+	if (status < 0)
+		goto error;
+
+	/*== Start SC, write channel settings to SC ===============================*/
+
+	/* Activate SCU to enable SCU commands */
+	status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
+	if (status < 0)
+		goto error;
+
+	/* Enable SC after setting all other parameters */
+	status = write16(state, OFDM_SC_COMM_STATE__A, 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, OFDM_SC_COMM_EXEC__A, 1);
+	if (status < 0)
+		goto error;
+
+
+	status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_START, 0, NULL, 1, &cmdResult);
+	if (status < 0)
+		goto error;
+
+	/* Write SC parameter registers, set all AUTO flags in operation mode */
+	param1 = (OFDM_SC_RA_RAM_OP_AUTO_MODE__M |
+			OFDM_SC_RA_RAM_OP_AUTO_GUARD__M |
+			OFDM_SC_RA_RAM_OP_AUTO_CONST__M |
+			OFDM_SC_RA_RAM_OP_AUTO_HIER__M |
+			OFDM_SC_RA_RAM_OP_AUTO_RATE__M);
+	status = DVBTScCommand(state, OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM,
+				0, transmissionParams, param1, 0, 0, 0);
+	if (status < 0)
+		goto error;
+
+	if (!state->m_DRXK_A3_ROM_CODE)
+		status = DVBTCtrlSetSqiSpeed(state, &state->m_sqiSpeed);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+	return status;
+}
+
+
+/*============================================================================*/
+
+/**
+* \brief Retreive lock status .
+* \param demod    Pointer to demodulator instance.
+* \param lockStat Pointer to lock status structure.
+* \return DRXStatus_t.
+*
+*/
+static int GetDVBTLockStatus(struct drxk_state *state, u32 *pLockStatus)
+{
+	int status;
+	const u16 mpeg_lock_mask = (OFDM_SC_RA_RAM_LOCK_MPEG__M |
+				    OFDM_SC_RA_RAM_LOCK_FEC__M);
+	const u16 fec_lock_mask = (OFDM_SC_RA_RAM_LOCK_FEC__M);
+	const u16 demod_lock_mask = OFDM_SC_RA_RAM_LOCK_DEMOD__M;
+
+	u16 ScRaRamLock = 0;
+	u16 ScCommExec = 0;
+
+	dprintk(1, "\n");
+
+	*pLockStatus = NOT_LOCKED;
+	/* driver 0.9.0 */
+	/* Check if SC is running */
+	status = read16(state, OFDM_SC_COMM_EXEC__A, &ScCommExec);
+	if (status < 0)
+		goto end;
+	if (ScCommExec == OFDM_SC_COMM_EXEC_STOP)
+		goto end;
+
+	status = read16(state, OFDM_SC_RA_RAM_LOCK__A, &ScRaRamLock);
+	if (status < 0)
+		goto end;
+
+	if ((ScRaRamLock & mpeg_lock_mask) == mpeg_lock_mask)
+		*pLockStatus = MPEG_LOCK;
+	else if ((ScRaRamLock & fec_lock_mask) == fec_lock_mask)
+		*pLockStatus = FEC_LOCK;
+	else if ((ScRaRamLock & demod_lock_mask) == demod_lock_mask)
+		*pLockStatus = DEMOD_LOCK;
+	else if (ScRaRamLock & OFDM_SC_RA_RAM_LOCK_NODVBT__M)
+		*pLockStatus = NEVER_LOCK;
+end:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+	return status;
+}
+
+static int PowerUpQAM(struct drxk_state *state)
+{
+	enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
+	int status;
+
+	dprintk(1, "\n");
+	status = CtrlPowerMode(state, &powerMode);
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+	return status;
+}
+
+
+/** Power Down QAM */
+static int PowerDownQAM(struct drxk_state *state)
+{
+	u16 data = 0;
+	u16 cmdResult;
+	int status = 0;
+
+	dprintk(1, "\n");
+	status = read16(state, SCU_COMM_EXEC__A, &data);
+	if (status < 0)
+		goto error;
+	if (data == SCU_COMM_EXEC_ACTIVE) {
+		/*
+			STOP demodulator
+			QAM and HW blocks
+			*/
+		/* stop all comstate->m_exec */
+		status = write16(state, QAM_COMM_EXEC__A, QAM_COMM_EXEC_STOP);
+		if (status < 0)
+			goto error;
+		status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
+		if (status < 0)
+			goto error;
+	}
+	/* powerdown AFE                   */
+	status = SetIqmAf(state, false);
+
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+	return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief Setup of the QAM Measurement intervals for signal quality
+* \param demod instance of demod.
+* \param modulation current modulation.
+* \return DRXStatus_t.
+*
+*  NOTE:
+*  Take into account that for certain settings the errorcounters can overflow.
+*  The implementation does not check this.
+*
+*/
+static int SetQAMMeasurement(struct drxk_state *state,
+			     enum EDrxkConstellation modulation,
+			     u32 symbolRate)
+{
+	u32 fecBitsDesired = 0;	/* BER accounting period */
+	u32 fecRsPeriodTotal = 0;	/* Total period */
+	u16 fecRsPrescale = 0;	/* ReedSolomon Measurement Prescale */
+	u16 fecRsPeriod = 0;	/* Value for corresponding I2C register */
+	int status = 0;
+
+	dprintk(1, "\n");
+
+	fecRsPrescale = 1;
+	/* fecBitsDesired = symbolRate [kHz] *
+		FrameLenght [ms] *
+		(modulation + 1) *
+		SyncLoss (== 1) *
+		ViterbiLoss (==1)
+		*/
+	switch (modulation) {
+	case DRX_CONSTELLATION_QAM16:
+		fecBitsDesired = 4 * symbolRate;
+		break;
+	case DRX_CONSTELLATION_QAM32:
+		fecBitsDesired = 5 * symbolRate;
+		break;
+	case DRX_CONSTELLATION_QAM64:
+		fecBitsDesired = 6 * symbolRate;
+		break;
+	case DRX_CONSTELLATION_QAM128:
+		fecBitsDesired = 7 * symbolRate;
+		break;
+	case DRX_CONSTELLATION_QAM256:
+		fecBitsDesired = 8 * symbolRate;
+		break;
+	default:
+		status = -EINVAL;
+	}
+	if (status < 0)
+		goto error;
+
+	fecBitsDesired /= 1000;	/* symbolRate [Hz] -> symbolRate [kHz]  */
+	fecBitsDesired *= 500;	/* meas. period [ms] */
+
+	/* Annex A/C: bits/RsPeriod = 204 * 8 = 1632 */
+	/* fecRsPeriodTotal = fecBitsDesired / 1632 */
+	fecRsPeriodTotal = (fecBitsDesired / 1632UL) + 1;	/* roughly ceil */
+
+	/* fecRsPeriodTotal =  fecRsPrescale * fecRsPeriod  */
+	fecRsPrescale = 1 + (u16) (fecRsPeriodTotal >> 16);
+	if (fecRsPrescale == 0) {
+		/* Divide by zero (though impossible) */
+		status = -EINVAL;
+		if (status < 0)
+			goto error;
+	}
+	fecRsPeriod =
+		((u16) fecRsPeriodTotal +
+		(fecRsPrescale >> 1)) / fecRsPrescale;
+
+	/* write corresponding registers */
+	status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, fecRsPeriod);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_RS_MEASUREMENT_PRESCALE__A, fecRsPrescale);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_OC_SNC_FAIL_PERIOD__A, fecRsPeriod);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int SetQAM16(struct drxk_state *state)
+{
+	int status = 0;
+
+	dprintk(1, "\n");
+	/* QAM Equalizer Setup */
+	/* Equalizer */
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 13517);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 13517);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 13517);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 13517);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 13517);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 13517);
+	if (status < 0)
+		goto error;
+	/* Decision Feedback Equalizer */
+	status = write16(state, QAM_DQ_QUAL_FUN0__A, 2);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN1__A, 2);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN2__A, 2);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN3__A, 2);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN4__A, 2);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, QAM_SY_SYNC_HWM__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_SY_SYNC_AWM__A, 4);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_SY_SYNC_LWM__A, 3);
+	if (status < 0)
+		goto error;
+
+	/* QAM Slicer Settings */
+	status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM16);
+	if (status < 0)
+		goto error;
+
+	/* QAM Loop Controller Coeficients */
+	status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 20);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 80);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 20);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 50);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 16);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 32);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 10);
+	if (status < 0)
+		goto error;
+
+
+	/* QAM State Machine (FSM) Thresholds */
+
+	status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 140);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 50);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 95);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 120);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 230);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 105);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 24);
+	if (status < 0)
+		goto error;
+
+
+	/* QAM FSM Tracking Parameters */
+
+	status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 16);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 220);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 25);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 6);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -24);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -65);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -127);
+	if (status < 0)
+		goto error;
+
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief QAM32 specific setup
+* \param demod instance of demod.
+* \return DRXStatus_t.
+*/
+static int SetQAM32(struct drxk_state *state)
+{
+	int status = 0;
+
+	dprintk(1, "\n");
+
+	/* QAM Equalizer Setup */
+	/* Equalizer */
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 6707);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 6707);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 6707);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 6707);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 6707);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 6707);
+	if (status < 0)
+		goto error;
+
+	/* Decision Feedback Equalizer */
+	status = write16(state, QAM_DQ_QUAL_FUN0__A, 3);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN1__A, 3);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN2__A, 3);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN3__A, 3);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN4__A, 3);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, QAM_SY_SYNC_HWM__A, 6);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_SY_SYNC_AWM__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_SY_SYNC_LWM__A, 3);
+	if (status < 0)
+		goto error;
+
+	/* QAM Slicer Settings */
+
+	status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM32);
+	if (status < 0)
+		goto error;
+
+
+	/* QAM Loop Controller Coeficients */
+
+	status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 20);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 80);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 20);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 50);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 16);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 16);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 0);
+	if (status < 0)
+		goto error;
+
+
+	/* QAM State Machine (FSM) Thresholds */
+
+	status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 90);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 50);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 100);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 170);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 100);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 10);
+	if (status < 0)
+		goto error;
+
+
+	/* QAM FSM Tracking Parameters */
+
+	status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 12);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 140);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) -8);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) -16);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -26);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -56);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -86);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief QAM64 specific setup
+* \param demod instance of demod.
+* \return DRXStatus_t.
+*/
+static int SetQAM64(struct drxk_state *state)
+{
+	int status = 0;
+
+	dprintk(1, "\n");
+	/* QAM Equalizer Setup */
+	/* Equalizer */
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 13336);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 12618);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 11988);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 13809);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 13809);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 15609);
+	if (status < 0)
+		goto error;
+
+	/* Decision Feedback Equalizer */
+	status = write16(state, QAM_DQ_QUAL_FUN0__A, 4);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN1__A, 4);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN2__A, 4);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN3__A, 4);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN4__A, 3);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, QAM_SY_SYNC_HWM__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_SY_SYNC_AWM__A, 4);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_SY_SYNC_LWM__A, 3);
+	if (status < 0)
+		goto error;
+
+	/* QAM Slicer Settings */
+	status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM64);
+	if (status < 0)
+		goto error;
+
+
+	/* QAM Loop Controller Coeficients */
+
+	status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 30);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 100);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 30);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 50);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 25);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 48);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 10);
+	if (status < 0)
+		goto error;
+
+
+	/* QAM State Machine (FSM) Thresholds */
+
+	status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 100);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 60);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 110);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 200);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 95);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 15);
+	if (status < 0)
+		goto error;
+
+
+	/* QAM FSM Tracking Parameters */
+
+	status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 12);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 141);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 7);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -15);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -45);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -80);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+	return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief QAM128 specific setup
+* \param demod: instance of demod.
+* \return DRXStatus_t.
+*/
+static int SetQAM128(struct drxk_state *state)
+{
+	int status = 0;
+
+	dprintk(1, "\n");
+	/* QAM Equalizer Setup */
+	/* Equalizer */
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 6564);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 6598);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 6394);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 6409);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 6656);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 7238);
+	if (status < 0)
+		goto error;
+
+	/* Decision Feedback Equalizer */
+	status = write16(state, QAM_DQ_QUAL_FUN0__A, 6);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN1__A, 6);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN2__A, 6);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN3__A, 6);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN4__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, QAM_SY_SYNC_HWM__A, 6);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_SY_SYNC_AWM__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_SY_SYNC_LWM__A, 3);
+	if (status < 0)
+		goto error;
+
+
+	/* QAM Slicer Settings */
+
+	status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM128);
+	if (status < 0)
+		goto error;
+
+
+	/* QAM Loop Controller Coeficients */
+
+	status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 40);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 120);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 40);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 60);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 25);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 64);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 0);
+	if (status < 0)
+		goto error;
+
+
+	/* QAM State Machine (FSM) Thresholds */
+
+	status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 50);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 60);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 100);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 140);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 100);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 5);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 12);
+	if (status < 0)
+		goto error;
+
+	/* QAM FSM Tracking Parameters */
+
+	status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 8);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 65);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 3);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -1);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -12);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -23);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+	return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief QAM256 specific setup
+* \param demod: instance of demod.
+* \return DRXStatus_t.
+*/
+static int SetQAM256(struct drxk_state *state)
+{
+	int status = 0;
+
+	dprintk(1, "\n");
+	/* QAM Equalizer Setup */
+	/* Equalizer */
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 11502);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 12084);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 12543);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 12931);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 13629);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 15385);
+	if (status < 0)
+		goto error;
+
+	/* Decision Feedback Equalizer */
+	status = write16(state, QAM_DQ_QUAL_FUN0__A, 8);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN1__A, 8);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN2__A, 8);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN3__A, 8);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN4__A, 6);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, QAM_SY_SYNC_HWM__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_SY_SYNC_AWM__A, 4);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_SY_SYNC_LWM__A, 3);
+	if (status < 0)
+		goto error;
+
+	/* QAM Slicer Settings */
+
+	status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM256);
+	if (status < 0)
+		goto error;
+
+
+	/* QAM Loop Controller Coeficients */
+
+	status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 50);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 250);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 50);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 125);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 25);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 48);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 10);
+	if (status < 0)
+		goto error;
+
+
+	/* QAM State Machine (FSM) Thresholds */
+
+	status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 50);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 60);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 100);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 150);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 110);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 12);
+	if (status < 0)
+		goto error;
+
+
+	/* QAM FSM Tracking Parameters */
+
+	status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 8);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 74);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 18);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 13);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) 7);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -8);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+
+/*============================================================================*/
+/**
+* \brief Reset QAM block.
+* \param demod:   instance of demod.
+* \param channel: pointer to channel data.
+* \return DRXStatus_t.
+*/
+static int QAMResetQAM(struct drxk_state *state)
+{
+	int status;
+	u16 cmdResult;
+
+	dprintk(1, "\n");
+	/* Stop QAM comstate->m_exec */
+	status = write16(state, QAM_COMM_EXEC__A, QAM_COMM_EXEC_STOP);
+	if (status < 0)
+		goto error;
+
+	status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief Set QAM symbolrate.
+* \param demod:   instance of demod.
+* \param channel: pointer to channel data.
+* \return DRXStatus_t.
+*/
+static int QAMSetSymbolrate(struct drxk_state *state)
+{
+	u32 adcFrequency = 0;
+	u32 symbFreq = 0;
+	u32 iqmRcRate = 0;
+	u16 ratesel = 0;
+	u32 lcSymbRate = 0;
+	int status;
+
+	dprintk(1, "\n");
+	/* Select & calculate correct IQM rate */
+	adcFrequency = (state->m_sysClockFreq * 1000) / 3;
+	ratesel = 0;
+	/* printk(KERN_DEBUG "drxk: SR %d\n", state->props.symbol_rate); */
+	if (state->props.symbol_rate <= 1188750)
+		ratesel = 3;
+	else if (state->props.symbol_rate <= 2377500)
+		ratesel = 2;
+	else if (state->props.symbol_rate <= 4755000)
+		ratesel = 1;
+	status = write16(state, IQM_FD_RATESEL__A, ratesel);
+	if (status < 0)
+		goto error;
+
+	/*
+		IqmRcRate = ((Fadc / (symbolrate * (4<<ratesel))) - 1) * (1<<23)
+		*/
+	symbFreq = state->props.symbol_rate * (1 << ratesel);
+	if (symbFreq == 0) {
+		/* Divide by zero */
+		status = -EINVAL;
+		goto error;
+	}
+	iqmRcRate = (adcFrequency / symbFreq) * (1 << 21) +
+		(Frac28a((adcFrequency % symbFreq), symbFreq) >> 7) -
+		(1 << 23);
+	status = write32(state, IQM_RC_RATE_OFS_LO__A, iqmRcRate);
+	if (status < 0)
+		goto error;
+	state->m_iqmRcRate = iqmRcRate;
+	/*
+		LcSymbFreq = round (.125 *  symbolrate / adcFreq * (1<<15))
+		*/
+	symbFreq = state->props.symbol_rate;
+	if (adcFrequency == 0) {
+		/* Divide by zero */
+		status = -EINVAL;
+		goto error;
+	}
+	lcSymbRate = (symbFreq / adcFrequency) * (1 << 12) +
+		(Frac28a((symbFreq % adcFrequency), adcFrequency) >>
+		16);
+	if (lcSymbRate > 511)
+		lcSymbRate = 511;
+	status = write16(state, QAM_LC_SYMBOL_FREQ__A, (u16) lcSymbRate);
+
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief Get QAM lock status.
+* \param demod:   instance of demod.
+* \param channel: pointer to channel data.
+* \return DRXStatus_t.
+*/
+
+static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus)
+{
+	int status;
+	u16 Result[2] = { 0, 0 };
+
+	dprintk(1, "\n");
+	*pLockStatus = NOT_LOCKED;
+	status = scu_command(state,
+			SCU_RAM_COMMAND_STANDARD_QAM |
+			SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK, 0, NULL, 2,
+			Result);
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+	if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED) {
+		/* 0x0000 NOT LOCKED */
+	} else if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_LOCKED) {
+		/* 0x4000 DEMOD LOCKED */
+		*pLockStatus = DEMOD_LOCK;
+	} else if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_NEVER_LOCK) {
+		/* 0x8000 DEMOD + FEC LOCKED (system lock) */
+		*pLockStatus = MPEG_LOCK;
+	} else {
+		/* 0xC000 NEVER LOCKED */
+		/* (system will never be able to lock to the signal) */
+		/* TODO: check this, intermediate & standard specific lock states are not
+		   taken into account here */
+		*pLockStatus = NEVER_LOCK;
+	}
+	return status;
+}
+
+#define QAM_MIRROR__M         0x03
+#define QAM_MIRROR_NORMAL     0x00
+#define QAM_MIRRORED          0x01
+#define QAM_MIRROR_AUTO_ON    0x02
+#define QAM_LOCKRANGE__M      0x10
+#define QAM_LOCKRANGE_NORMAL  0x10
+
+static int QAMDemodulatorCommand(struct drxk_state *state,
+				 int numberOfParameters)
+{
+	int status;
+	u16 cmdResult;
+	u16 setParamParameters[4] = { 0, 0, 0, 0 };
+
+	setParamParameters[0] = state->m_Constellation;	/* modulation     */
+	setParamParameters[1] = DRXK_QAM_I12_J17;	/* interleave mode   */
+
+	if (numberOfParameters == 2) {
+		u16 setEnvParameters[1] = { 0 };
+
+		if (state->m_OperationMode == OM_QAM_ITU_C)
+			setEnvParameters[0] = QAM_TOP_ANNEX_C;
+		else
+			setEnvParameters[0] = QAM_TOP_ANNEX_A;
+
+		status = scu_command(state,
+				     SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV,
+				     1, setEnvParameters, 1, &cmdResult);
+		if (status < 0)
+			goto error;
+
+		status = scu_command(state,
+				     SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM,
+				     numberOfParameters, setParamParameters,
+				     1, &cmdResult);
+	} else if (numberOfParameters == 4) {
+		if (state->m_OperationMode == OM_QAM_ITU_C)
+			setParamParameters[2] = QAM_TOP_ANNEX_C;
+		else
+			setParamParameters[2] = QAM_TOP_ANNEX_A;
+
+		setParamParameters[3] |= (QAM_MIRROR_AUTO_ON);
+		/* Env parameters */
+		/* check for LOCKRANGE Extented */
+		/* setParamParameters[3] |= QAM_LOCKRANGE_NORMAL; */
+
+		status = scu_command(state,
+				     SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM,
+				     numberOfParameters, setParamParameters,
+				     1, &cmdResult);
+	} else {
+		printk(KERN_WARNING "drxk: Unknown QAM demodulator parameter "
+			"count %d\n", numberOfParameters);
+	}
+
+error:
+	if (status < 0)
+		printk(KERN_WARNING "drxk: Warning %d on %s\n",
+		       status, __func__);
+	return status;
+}
+
+static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
+		  s32 tunerFreqOffset)
+{
+	int status;
+	u16 cmdResult;
+	int qamDemodParamCount = state->qam_demod_parameter_count;
+
+	dprintk(1, "\n");
+	/*
+	 * STEP 1: reset demodulator
+	 *	resets FEC DI and FEC RS
+	 *	resets QAM block
+	 *	resets SCU variables
+	 */
+	status = write16(state, FEC_DI_COMM_EXEC__A, FEC_DI_COMM_EXEC_STOP);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_RS_COMM_EXEC__A, FEC_RS_COMM_EXEC_STOP);
+	if (status < 0)
+		goto error;
+	status = QAMResetQAM(state);
+	if (status < 0)
+		goto error;
+
+	/*
+	 * STEP 2: configure demodulator
+	 *	-set params; resets IQM,QAM,FEC HW; initializes some
+	 *       SCU variables
+	 */
+	status = QAMSetSymbolrate(state);
+	if (status < 0)
+		goto error;
+
+	/* Set params */
+	switch (state->props.modulation) {
+	case QAM_256:
+		state->m_Constellation = DRX_CONSTELLATION_QAM256;
+		break;
+	case QAM_AUTO:
+	case QAM_64:
+		state->m_Constellation = DRX_CONSTELLATION_QAM64;
+		break;
+	case QAM_16:
+		state->m_Constellation = DRX_CONSTELLATION_QAM16;
+		break;
+	case QAM_32:
+		state->m_Constellation = DRX_CONSTELLATION_QAM32;
+		break;
+	case QAM_128:
+		state->m_Constellation = DRX_CONSTELLATION_QAM128;
+		break;
+	default:
+		status = -EINVAL;
+		break;
+	}
+	if (status < 0)
+		goto error;
+
+	/* Use the 4-parameter if it's requested or we're probing for
+	 * the correct command. */
+	if (state->qam_demod_parameter_count == 4
+		|| !state->qam_demod_parameter_count) {
+		qamDemodParamCount = 4;
+		status = QAMDemodulatorCommand(state, qamDemodParamCount);
+	}
+
+	/* Use the 2-parameter command if it was requested or if we're
+	 * probing for the correct command and the 4-parameter command
+	 * failed. */
+	if (state->qam_demod_parameter_count == 2
+		|| (!state->qam_demod_parameter_count && status < 0)) {
+		qamDemodParamCount = 2;
+		status = QAMDemodulatorCommand(state, qamDemodParamCount);
+	}
+
+	if (status < 0) {
+		dprintk(1, "Could not set demodulator parameters. Make "
+			"sure qam_demod_parameter_count (%d) is correct for "
+			"your firmware (%s).\n",
+			state->qam_demod_parameter_count,
+			state->microcode_name);
+		goto error;
+	} else if (!state->qam_demod_parameter_count) {
+		dprintk(1, "Auto-probing the correct QAM demodulator command "
+			"parameters was successful - using %d parameters.\n",
+			qamDemodParamCount);
+
+		/*
+		 * One of our commands was successful. We don't need to
+		 * auto-probe anymore, now that we got the correct command.
+		 */
+		state->qam_demod_parameter_count = qamDemodParamCount;
+	}
+
+	/*
+	 * STEP 3: enable the system in a mode where the ADC provides valid
+	 * signal setup modulation independent registers
+	 */
+#if 0
+	status = SetFrequency(channel, tunerFreqOffset));
+	if (status < 0)
+		goto error;
+#endif
+	status = SetFrequencyShifter(state, IntermediateFreqkHz, tunerFreqOffset, true);
+	if (status < 0)
+		goto error;
+
+	/* Setup BER measurement */
+	status = SetQAMMeasurement(state, state->m_Constellation, state->props.symbol_rate);
+	if (status < 0)
+		goto error;
+
+	/* Reset default values */
+	status = write16(state, IQM_CF_SCALE_SH__A, IQM_CF_SCALE_SH__PRE);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_SY_TIMEOUT__A, QAM_SY_TIMEOUT__PRE);
+	if (status < 0)
+		goto error;
+
+	/* Reset default LC values */
+	status = write16(state, QAM_LC_RATE_LIMIT__A, 3);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_LC_LPF_FACTORP__A, 4);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_LC_LPF_FACTORI__A, 4);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_LC_MODE__A, 7);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, QAM_LC_QUAL_TAB0__A, 1);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_LC_QUAL_TAB1__A, 1);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_LC_QUAL_TAB2__A, 1);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_LC_QUAL_TAB3__A, 1);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_LC_QUAL_TAB4__A, 2);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_LC_QUAL_TAB5__A, 2);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_LC_QUAL_TAB6__A, 2);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_LC_QUAL_TAB8__A, 2);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_LC_QUAL_TAB9__A, 2);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_LC_QUAL_TAB10__A, 2);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_LC_QUAL_TAB12__A, 2);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_LC_QUAL_TAB15__A, 3);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_LC_QUAL_TAB16__A, 3);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_LC_QUAL_TAB20__A, 4);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_LC_QUAL_TAB25__A, 4);
+	if (status < 0)
+		goto error;
+
+	/* Mirroring, QAM-block starting point not inverted */
+	status = write16(state, QAM_SY_SP_INV__A, QAM_SY_SP_INV_SPECTRUM_INV_DIS);
+	if (status < 0)
+		goto error;
+
+	/* Halt SCU to enable safe non-atomic accesses */
+	status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD);
+	if (status < 0)
+		goto error;
+
+	/* STEP 4: modulation specific setup */
+	switch (state->props.modulation) {
+	case QAM_16:
+		status = SetQAM16(state);
+		break;
+	case QAM_32:
+		status = SetQAM32(state);
+		break;
+	case QAM_AUTO:
+	case QAM_64:
+		status = SetQAM64(state);
+		break;
+	case QAM_128:
+		status = SetQAM128(state);
+		break;
+	case QAM_256:
+		status = SetQAM256(state);
+		break;
+	default:
+		status = -EINVAL;
+		break;
+	}
+	if (status < 0)
+		goto error;
+
+	/* Activate SCU to enable SCU commands */
+	status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
+	if (status < 0)
+		goto error;
+
+	/* Re-configure MPEG output, requires knowledge of channel bitrate */
+	/* extAttr->currentChannel.modulation = channel->modulation; */
+	/* extAttr->currentChannel.symbolrate    = channel->symbolrate; */
+	status = MPEGTSDtoSetup(state, state->m_OperationMode);
+	if (status < 0)
+		goto error;
+
+	/* Start processes */
+	status = MPEGTSStart(state);
+	if (status < 0)
+		goto error;
+	status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_ACTIVE);
+	if (status < 0)
+		goto error;
+	status = write16(state, QAM_COMM_EXEC__A, QAM_COMM_EXEC_ACTIVE);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_ACTIVE);
+	if (status < 0)
+		goto error;
+
+	/* STEP 5: start QAM demodulator (starts FEC, QAM and IQM HW) */
+	status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_START, 0, NULL, 1, &cmdResult);
+	if (status < 0)
+		goto error;
+
+	/* update global DRXK data container */
+/*?     extAttr->qamInterleaveMode = DRXK_QAM_I12_J17; */
+
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int SetQAMStandard(struct drxk_state *state,
+			  enum OperationMode oMode)
+{
+	int status;
+#ifdef DRXK_QAM_TAPS
+#define DRXK_QAMA_TAPS_SELECT
+#include "drxk_filters.h"
+#undef DRXK_QAMA_TAPS_SELECT
+#endif
+
+	dprintk(1, "\n");
+
+	/* added antenna switch */
+	SwitchAntennaToQAM(state);
+
+	/* Ensure correct power-up mode */
+	status = PowerUpQAM(state);
+	if (status < 0)
+		goto error;
+	/* Reset QAM block */
+	status = QAMResetQAM(state);
+	if (status < 0)
+		goto error;
+
+	/* Setup IQM */
+
+	status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_STOP);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_AF_AMUX__A, IQM_AF_AMUX_SIGNAL2ADC);
+	if (status < 0)
+		goto error;
+
+	/* Upload IQM Channel Filter settings by
+		boot loader from ROM table */
+	switch (oMode) {
+	case OM_QAM_ITU_A:
+		status = BLChainCmd(state, DRXK_BL_ROM_OFFSET_TAPS_ITU_A, DRXK_BLCC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+		break;
+	case OM_QAM_ITU_C:
+		status = BLDirectCmd(state, IQM_CF_TAP_RE0__A, DRXK_BL_ROM_OFFSET_TAPS_ITU_C, DRXK_BLDC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+		if (status < 0)
+			goto error;
+		status = BLDirectCmd(state, IQM_CF_TAP_IM0__A, DRXK_BL_ROM_OFFSET_TAPS_ITU_C, DRXK_BLDC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+		break;
+	default:
+		status = -EINVAL;
+	}
+	if (status < 0)
+		goto error;
+
+	status = write16(state, IQM_CF_OUT_ENA__A, (1 << IQM_CF_OUT_ENA_QAM__B));
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_CF_SYMMETRIC__A, 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_CF_MIDTAP__A, ((1 << IQM_CF_MIDTAP_RE__B) | (1 << IQM_CF_MIDTAP_IM__B)));
+	if (status < 0)
+		goto error;
+
+	status = write16(state, IQM_RC_STRETCH__A, 21);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_AF_CLP_LEN__A, 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_AF_CLP_TH__A, 448);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_AF_SNS_LEN__A, 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_CF_POW_MEAS_LEN__A, 0);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, IQM_FS_ADJ_SEL__A, 1);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_RC_ADJ_SEL__A, 1);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_CF_ADJ_SEL__A, 1);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_AF_UPD_SEL__A, 0);
+	if (status < 0)
+		goto error;
+
+	/* IQM Impulse Noise Processing Unit */
+	status = write16(state, IQM_CF_CLP_VAL__A, 500);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_CF_DATATH__A, 1000);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_CF_BYPASSDET__A, 1);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_CF_DET_LCT__A, 0);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_CF_WND_LEN__A, 1);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_CF_PKDTH__A, 1);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_AF_INC_BYPASS__A, 1);
+	if (status < 0)
+		goto error;
+
+	/* turn on IQMAF. Must be done before setAgc**() */
+	status = SetIqmAf(state, true);
+	if (status < 0)
+		goto error;
+	status = write16(state, IQM_AF_START_LOCK__A, 0x01);
+	if (status < 0)
+		goto error;
+
+	/* IQM will not be reset from here, sync ADC and update/init AGC */
+	status = ADCSynchronization(state);
+	if (status < 0)
+		goto error;
+
+	/* Set the FSM step period */
+	status = write16(state, SCU_RAM_QAM_FSM_STEP_PERIOD__A, 2000);
+	if (status < 0)
+		goto error;
+
+	/* Halt SCU to enable safe non-atomic accesses */
+	status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD);
+	if (status < 0)
+		goto error;
+
+	/* No more resets of the IQM, current standard correctly set =>
+		now AGCs can be configured. */
+
+	status = InitAGC(state, true);
+	if (status < 0)
+		goto error;
+	status = SetPreSaw(state, &(state->m_qamPreSawCfg));
+	if (status < 0)
+		goto error;
+
+	/* Configure AGC's */
+	status = SetAgcRf(state, &(state->m_qamRfAgcCfg), true);
+	if (status < 0)
+		goto error;
+	status = SetAgcIf(state, &(state->m_qamIfAgcCfg), true);
+	if (status < 0)
+		goto error;
+
+	/* Activate SCU to enable SCU commands */
+	status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int WriteGPIO(struct drxk_state *state)
+{
+	int status;
+	u16 value = 0;
+
+	dprintk(1, "\n");
+	/* stop lock indicator process */
+	status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+	if (status < 0)
+		goto error;
+
+	/*  Write magic word to enable pdr reg write               */
+	status = write16(state, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY);
+	if (status < 0)
+		goto error;
+
+	if (state->m_hasSAWSW) {
+		if (state->UIO_mask & 0x0001) { /* UIO-1 */
+			/* write to io pad configuration register - output mode */
+			status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg);
+			if (status < 0)
+				goto error;
+
+			/* use corresponding bit in io data output registar */
+			status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
+			if (status < 0)
+				goto error;
+			if ((state->m_GPIO & 0x0001) == 0)
+				value &= 0x7FFF;	/* write zero to 15th bit - 1st UIO */
+			else
+				value |= 0x8000;	/* write one to 15th bit - 1st UIO */
+			/* write back to io data output register */
+			status = write16(state, SIO_PDR_UIO_OUT_LO__A, value);
+			if (status < 0)
+				goto error;
+		}
+		if (state->UIO_mask & 0x0002) { /* UIO-2 */
+			/* write to io pad configuration register - output mode */
+			status = write16(state, SIO_PDR_SMA_RX_CFG__A, state->m_GPIOCfg);
+			if (status < 0)
+				goto error;
+
+			/* use corresponding bit in io data output registar */
+			status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
+			if (status < 0)
+				goto error;
+			if ((state->m_GPIO & 0x0002) == 0)
+				value &= 0xBFFF;	/* write zero to 14th bit - 2st UIO */
+			else
+				value |= 0x4000;	/* write one to 14th bit - 2st UIO */
+			/* write back to io data output register */
+			status = write16(state, SIO_PDR_UIO_OUT_LO__A, value);
+			if (status < 0)
+				goto error;
+		}
+		if (state->UIO_mask & 0x0004) { /* UIO-3 */
+			/* write to io pad configuration register - output mode */
+			status = write16(state, SIO_PDR_GPIO_CFG__A, state->m_GPIOCfg);
+			if (status < 0)
+				goto error;
+
+			/* use corresponding bit in io data output registar */
+			status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
+			if (status < 0)
+				goto error;
+			if ((state->m_GPIO & 0x0004) == 0)
+				value &= 0xFFFB;            /* write zero to 2nd bit - 3rd UIO */
+			else
+				value |= 0x0004;            /* write one to 2nd bit - 3rd UIO */
+			/* write back to io data output register */
+			status = write16(state, SIO_PDR_UIO_OUT_LO__A, value);
+			if (status < 0)
+				goto error;
+		}
+	}
+	/*  Write magic word to disable pdr reg write               */
+	status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int SwitchAntennaToQAM(struct drxk_state *state)
+{
+	int status = 0;
+	bool gpio_state;
+
+	dprintk(1, "\n");
+
+	if (!state->antenna_gpio)
+		return 0;
+
+	gpio_state = state->m_GPIO & state->antenna_gpio;
+
+	if (state->antenna_dvbt ^ gpio_state) {
+		/* Antenna is on DVB-T mode. Switch */
+		if (state->antenna_dvbt)
+			state->m_GPIO &= ~state->antenna_gpio;
+		else
+			state->m_GPIO |= state->antenna_gpio;
+		status = WriteGPIO(state);
+	}
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+static int SwitchAntennaToDVBT(struct drxk_state *state)
+{
+	int status = 0;
+	bool gpio_state;
+
+	dprintk(1, "\n");
+
+	if (!state->antenna_gpio)
+		return 0;
+
+	gpio_state = state->m_GPIO & state->antenna_gpio;
+
+	if (!(state->antenna_dvbt ^ gpio_state)) {
+		/* Antenna is on DVB-C mode. Switch */
+		if (state->antenna_dvbt)
+			state->m_GPIO |= state->antenna_gpio;
+		else
+			state->m_GPIO &= ~state->antenna_gpio;
+		status = WriteGPIO(state);
+	}
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	return status;
+}
+
+
+static int PowerDownDevice(struct drxk_state *state)
+{
+	/* Power down to requested mode */
+	/* Backup some register settings */
+	/* Set pins with possible pull-ups connected to them in input mode */
+	/* Analog power down */
+	/* ADC power down */
+	/* Power down device */
+	int status;
+
+	dprintk(1, "\n");
+	if (state->m_bPDownOpenBridge) {
+		/* Open I2C bridge before power down of DRXK */
+		status = ConfigureI2CBridge(state, true);
+		if (status < 0)
+			goto error;
+	}
+	/* driver 0.9.0 */
+	status = DVBTEnableOFDMTokenRing(state, false);
+	if (status < 0)
+		goto error;
+
+	status = write16(state, SIO_CC_PWD_MODE__A, SIO_CC_PWD_MODE_LEVEL_CLOCK);
+	if (status < 0)
+		goto error;
+	status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
+	if (status < 0)
+		goto error;
+	state->m_HICfgCtrl |= SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
+	status = HI_CfgCommand(state);
+error:
+	if (status < 0)
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+	return status;
+}
+
+static int init_drxk(struct drxk_state *state)
+{
+	int status = 0, n = 0;
+	enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
+	u16 driverVersion;
+
+	dprintk(1, "\n");
+	if ((state->m_DrxkState == DRXK_UNINITIALIZED)) {
+		drxk_i2c_lock(state);
+		status = PowerUpDevice(state);
+		if (status < 0)
+			goto error;
+		status = DRXX_Open(state);
+		if (status < 0)
+			goto error;
+		/* Soft reset of OFDM-, sys- and osc-clockdomain */
+		status = write16(state, SIO_CC_SOFT_RST__A, SIO_CC_SOFT_RST_OFDM__M | SIO_CC_SOFT_RST_SYS__M | SIO_CC_SOFT_RST_OSC__M);
+		if (status < 0)
+			goto error;
+		status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
+		if (status < 0)
+			goto error;
+		/* TODO is this needed, if yes how much delay in worst case scenario */
+		msleep(1);
+		state->m_DRXK_A3_PATCH_CODE = true;
+		status = GetDeviceCapabilities(state);
+		if (status < 0)
+			goto error;
+
+		/* Bridge delay, uses oscilator clock */
+		/* Delay = (delay (nano seconds) * oscclk (kHz))/ 1000 */
+		/* SDA brdige delay */
+		state->m_HICfgBridgeDelay =
+			(u16) ((state->m_oscClockFreq / 1000) *
+				HI_I2C_BRIDGE_DELAY) / 1000;
+		/* Clipping */
+		if (state->m_HICfgBridgeDelay >
+			SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M) {
+			state->m_HICfgBridgeDelay =
+				SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M;
+		}
+		/* SCL bridge delay, same as SDA for now */
+		state->m_HICfgBridgeDelay +=
+			state->m_HICfgBridgeDelay <<
+			SIO_HI_RA_RAM_PAR_3_CFG_DBL_SCL__B;
+
+		status = InitHI(state);
+		if (status < 0)
+			goto error;
+		/* disable various processes */
+#if NOA1ROM
+		if (!(state->m_DRXK_A1_ROM_CODE)
+			&& !(state->m_DRXK_A2_ROM_CODE))
+#endif
+		{
+			status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+			if (status < 0)
+				goto error;
+		}
+
+		/* disable MPEG port */
+		status = MPEGTSDisable(state);
+		if (status < 0)
+			goto error;
+
+		/* Stop AUD and SCU */
+		status = write16(state, AUD_COMM_EXEC__A, AUD_COMM_EXEC_STOP);
+		if (status < 0)
+			goto error;
+		status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_STOP);
+		if (status < 0)
+			goto error;
+
+		/* enable token-ring bus through OFDM block for possible ucode upload */
+		status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_ON);
+		if (status < 0)
+			goto error;
+
+		/* include boot loader section */
+		status = write16(state, SIO_BL_COMM_EXEC__A, SIO_BL_COMM_EXEC_ACTIVE);
+		if (status < 0)
+			goto error;
+		status = BLChainCmd(state, 0, 6, 100);
+		if (status < 0)
+			goto error;
+
+		if (state->fw) {
+			status = DownloadMicrocode(state, state->fw->data,
+						   state->fw->size);
+			if (status < 0)
+				goto error;
+		}
+
+		/* disable token-ring bus through OFDM block for possible ucode upload */
+		status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_OFF);
+		if (status < 0)
+			goto error;
+
+		/* Run SCU for a little while to initialize microcode version numbers */
+		status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
+		if (status < 0)
+			goto error;
+		status = DRXX_Open(state);
+		if (status < 0)
+			goto error;
+		/* added for test */
+		msleep(30);
+
+		powerMode = DRXK_POWER_DOWN_OFDM;
+		status = CtrlPowerMode(state, &powerMode);
+		if (status < 0)
+			goto error;
+
+		/* Stamp driver version number in SCU data RAM in BCD code
+			Done to enable field application engineers to retreive drxdriver version
+			via I2C from SCU RAM.
+			Not using SCU command interface for SCU register access since no
+			microcode may be present.
+			*/
+		driverVersion =
+			(((DRXK_VERSION_MAJOR / 100) % 10) << 12) +
+			(((DRXK_VERSION_MAJOR / 10) % 10) << 8) +
+			((DRXK_VERSION_MAJOR % 10) << 4) +
+			(DRXK_VERSION_MINOR % 10);
+		status = write16(state, SCU_RAM_DRIVER_VER_HI__A, driverVersion);
+		if (status < 0)
+			goto error;
+		driverVersion =
+			(((DRXK_VERSION_PATCH / 1000) % 10) << 12) +
+			(((DRXK_VERSION_PATCH / 100) % 10) << 8) +
+			(((DRXK_VERSION_PATCH / 10) % 10) << 4) +
+			(DRXK_VERSION_PATCH % 10);
+		status = write16(state, SCU_RAM_DRIVER_VER_LO__A, driverVersion);
+		if (status < 0)
+			goto error;
+
+		printk(KERN_INFO "DRXK driver version %d.%d.%d\n",
+			DRXK_VERSION_MAJOR, DRXK_VERSION_MINOR,
+			DRXK_VERSION_PATCH);
+
+		/* Dirty fix of default values for ROM/PATCH microcode
+			Dirty because this fix makes it impossible to setup suitable values
+			before calling DRX_Open. This solution requires changes to RF AGC speed
+			to be done via the CTRL function after calling DRX_Open */
+
+		/* m_dvbtRfAgcCfg.speed = 3; */
+
+		/* Reset driver debug flags to 0 */
+		status = write16(state, SCU_RAM_DRIVER_DEBUG__A, 0);
+		if (status < 0)
+			goto error;
+		/* driver 0.9.0 */
+		/* Setup FEC OC:
+			NOTE: No more full FEC resets allowed afterwards!! */
+		status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_STOP);
+		if (status < 0)
+			goto error;
+		/* MPEGTS functions are still the same */
+		status = MPEGTSDtoInit(state);
+		if (status < 0)
+			goto error;
+		status = MPEGTSStop(state);
+		if (status < 0)
+			goto error;
+		status = MPEGTSConfigurePolarity(state);
+		if (status < 0)
+			goto error;
+		status = MPEGTSConfigurePins(state, state->m_enableMPEGOutput);
+		if (status < 0)
+			goto error;
+		/* added: configure GPIO */
+		status = WriteGPIO(state);
+		if (status < 0)
+			goto error;
+
+		state->m_DrxkState = DRXK_STOPPED;
+
+		if (state->m_bPowerDown) {
+			status = PowerDownDevice(state);
+			if (status < 0)
+				goto error;
+			state->m_DrxkState = DRXK_POWERED_DOWN;
+		} else
+			state->m_DrxkState = DRXK_STOPPED;
+
+		/* Initialize the supported delivery systems */
+		n = 0;
+		if (state->m_hasDVBC) {
+			state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_A;
+			state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_C;
+			strlcat(state->frontend.ops.info.name, " DVB-C",
+				sizeof(state->frontend.ops.info.name));
+		}
+		if (state->m_hasDVBT) {
+			state->frontend.ops.delsys[n++] = SYS_DVBT;
+			strlcat(state->frontend.ops.info.name, " DVB-T",
+				sizeof(state->frontend.ops.info.name));
+		}
+		drxk_i2c_unlock(state);
+	}
+error:
+	if (status < 0) {
+		state->m_DrxkState = DRXK_NO_DEV;
+		drxk_i2c_unlock(state);
+		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+	}
+
+	return status;
+}
+
+static void load_firmware_cb(const struct firmware *fw,
+			     void *context)
+{
+	struct drxk_state *state = context;
+
+	dprintk(1, ": %s\n", fw ? "firmware loaded" : "firmware not loaded");
+	if (!fw) {
+		printk(KERN_ERR
+		       "drxk: Could not load firmware file %s.\n",
+			state->microcode_name);
+		printk(KERN_INFO
+		       "drxk: Copy %s to your hotplug directory!\n",
+			state->microcode_name);
+		state->microcode_name = NULL;
+
+		/*
+		 * As firmware is now load asynchronous, it is not possible
+		 * anymore to fail at frontend attach. We might silently
+		 * return here, and hope that the driver won't crash.
+		 * We might also change all DVB callbacks to return -ENODEV
+		 * if the device is not initialized.
+		 * As the DRX-K devices have their own internal firmware,
+		 * let's just hope that it will match a firmware revision
+		 * compatible with this driver and proceed.
+		 */
+	}
+	state->fw = fw;
+
+	init_drxk(state);
+}
+
+static void drxk_release(struct dvb_frontend *fe)
+{
+	struct drxk_state *state = fe->demodulator_priv;
+
+	dprintk(1, "\n");
+	if (state->fw)
+		release_firmware(state->fw);
+
+	kfree(state);
+}
+
+static int drxk_sleep(struct dvb_frontend *fe)
+{
+	struct drxk_state *state = fe->demodulator_priv;
+
+	dprintk(1, "\n");
+
+	if (state->m_DrxkState == DRXK_NO_DEV)
+		return -ENODEV;
+	if (state->m_DrxkState == DRXK_UNINITIALIZED)
+		return 0;
+
+	ShutDown(state);
+	return 0;
+}
+
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct drxk_state *state = fe->demodulator_priv;
+
+	dprintk(1, ": %s\n", enable ? "enable" : "disable");
+
+	if (state->m_DrxkState == DRXK_NO_DEV)
+		return -ENODEV;
+
+	return ConfigureI2CBridge(state, enable ? true : false);
+}
+
+static int drxk_set_parameters(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	u32 delsys  = p->delivery_system, old_delsys;
+	struct drxk_state *state = fe->demodulator_priv;
+	u32 IF;
+
+	dprintk(1, "\n");
+
+	if (state->m_DrxkState == DRXK_NO_DEV)
+		return -ENODEV;
+
+	if (state->m_DrxkState == DRXK_UNINITIALIZED)
+		return -EAGAIN;
+
+	if (!fe->ops.tuner_ops.get_if_frequency) {
+		printk(KERN_ERR
+		       "drxk: Error: get_if_frequency() not defined at tuner. Can't work without it!\n");
+		return -EINVAL;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	old_delsys = state->props.delivery_system;
+	state->props = *p;
+
+	if (old_delsys != delsys) {
+		ShutDown(state);
+		switch (delsys) {
+		case SYS_DVBC_ANNEX_A:
+		case SYS_DVBC_ANNEX_C:
+			if (!state->m_hasDVBC)
+				return -EINVAL;
+			state->m_itut_annex_c = (delsys == SYS_DVBC_ANNEX_C) ? true : false;
+			if (state->m_itut_annex_c)
+				SetOperationMode(state, OM_QAM_ITU_C);
+			else
+				SetOperationMode(state, OM_QAM_ITU_A);
+			break;
+		case SYS_DVBT:
+			if (!state->m_hasDVBT)
+				return -EINVAL;
+			SetOperationMode(state, OM_DVBT);
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	fe->ops.tuner_ops.get_if_frequency(fe, &IF);
+	Start(state, 0, IF);
+
+	/* printk(KERN_DEBUG "drxk: %s IF=%d done\n", __func__, IF); */
+
+	return 0;
+}
+
+static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct drxk_state *state = fe->demodulator_priv;
+	u32 stat;
+
+	dprintk(1, "\n");
+
+	if (state->m_DrxkState == DRXK_NO_DEV)
+		return -ENODEV;
+	if (state->m_DrxkState == DRXK_UNINITIALIZED)
+		return -EAGAIN;
+
+	*status = 0;
+	GetLockStatus(state, &stat, 0);
+	if (stat == MPEG_LOCK)
+		*status |= 0x1f;
+	if (stat == FEC_LOCK)
+		*status |= 0x0f;
+	if (stat == DEMOD_LOCK)
+		*status |= 0x07;
+	return 0;
+}
+
+static int drxk_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct drxk_state *state = fe->demodulator_priv;
+
+	dprintk(1, "\n");
+
+	if (state->m_DrxkState == DRXK_NO_DEV)
+		return -ENODEV;
+	if (state->m_DrxkState == DRXK_UNINITIALIZED)
+		return -EAGAIN;
+
+	*ber = 0;
+	return 0;
+}
+
+static int drxk_read_signal_strength(struct dvb_frontend *fe,
+				     u16 *strength)
+{
+	struct drxk_state *state = fe->demodulator_priv;
+	u32 val = 0;
+
+	dprintk(1, "\n");
+
+	if (state->m_DrxkState == DRXK_NO_DEV)
+		return -ENODEV;
+	if (state->m_DrxkState == DRXK_UNINITIALIZED)
+		return -EAGAIN;
+
+	ReadIFAgc(state, &val);
+	*strength = val & 0xffff;
+	return 0;
+}
+
+static int drxk_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct drxk_state *state = fe->demodulator_priv;
+	s32 snr2;
+
+	dprintk(1, "\n");
+
+	if (state->m_DrxkState == DRXK_NO_DEV)
+		return -ENODEV;
+	if (state->m_DrxkState == DRXK_UNINITIALIZED)
+		return -EAGAIN;
+
+	GetSignalToNoise(state, &snr2);
+	*snr = snr2 & 0xffff;
+	return 0;
+}
+
+static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct drxk_state *state = fe->demodulator_priv;
+	u16 err;
+
+	dprintk(1, "\n");
+
+	if (state->m_DrxkState == DRXK_NO_DEV)
+		return -ENODEV;
+	if (state->m_DrxkState == DRXK_UNINITIALIZED)
+		return -EAGAIN;
+
+	DVBTQAMGetAccPktErr(state, &err);
+	*ucblocks = (u32) err;
+	return 0;
+}
+
+static int drxk_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings
+				    *sets)
+{
+	struct drxk_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+	dprintk(1, "\n");
+
+	if (state->m_DrxkState == DRXK_NO_DEV)
+		return -ENODEV;
+	if (state->m_DrxkState == DRXK_UNINITIALIZED)
+		return -EAGAIN;
+
+	switch (p->delivery_system) {
+	case SYS_DVBC_ANNEX_A:
+	case SYS_DVBC_ANNEX_C:
+	case SYS_DVBT:
+		sets->min_delay_ms = 3000;
+		sets->max_drift = 0;
+		sets->step_size = 0;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static struct dvb_frontend_ops drxk_ops = {
+	/* .delsys will be filled dynamically */
+	.info = {
+		.name = "DRXK",
+		.frequency_min = 47000000,
+		.frequency_max = 865000000,
+		 /* For DVB-C */
+		.symbol_rate_min = 870000,
+		.symbol_rate_max = 11700000,
+		/* For DVB-T */
+		.frequency_stepsize = 166667,
+
+		.caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+			FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_MUTE_TS |
+			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER |
+			FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO
+	},
+
+	.release = drxk_release,
+	.sleep = drxk_sleep,
+	.i2c_gate_ctrl = drxk_gate_ctrl,
+
+	.set_frontend = drxk_set_parameters,
+	.get_tune_settings = drxk_get_tune_settings,
+
+	.read_status = drxk_read_status,
+	.read_ber = drxk_read_ber,
+	.read_signal_strength = drxk_read_signal_strength,
+	.read_snr = drxk_read_snr,
+	.read_ucblocks = drxk_read_ucblocks,
+};
+
+struct dvb_frontend *drxk_attach(const struct drxk_config *config,
+				 struct i2c_adapter *i2c)
+{
+	struct drxk_state *state = NULL;
+	u8 adr = config->adr;
+	int status;
+
+	dprintk(1, "\n");
+	state = kzalloc(sizeof(struct drxk_state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	state->i2c = i2c;
+	state->demod_address = adr;
+	state->single_master = config->single_master;
+	state->microcode_name = config->microcode_name;
+	state->qam_demod_parameter_count = config->qam_demod_parameter_count;
+	state->no_i2c_bridge = config->no_i2c_bridge;
+	state->antenna_gpio = config->antenna_gpio;
+	state->antenna_dvbt = config->antenna_dvbt;
+	state->m_ChunkSize = config->chunk_size;
+	state->enable_merr_cfg = config->enable_merr_cfg;
+
+	if (config->dynamic_clk) {
+		state->m_DVBTStaticCLK = 0;
+		state->m_DVBCStaticCLK = 0;
+	} else {
+		state->m_DVBTStaticCLK = 1;
+		state->m_DVBCStaticCLK = 1;
+	}
+
+
+	if (config->mpeg_out_clk_strength)
+		state->m_TSClockkStrength = config->mpeg_out_clk_strength & 0x07;
+	else
+		state->m_TSClockkStrength = 0x06;
+
+	if (config->parallel_ts)
+		state->m_enableParallel = true;
+	else
+		state->m_enableParallel = false;
+
+	/* NOTE: as more UIO bits will be used, add them to the mask */
+	state->UIO_mask = config->antenna_gpio;
+
+	/* Default gpio to DVB-C */
+	if (!state->antenna_dvbt && state->antenna_gpio)
+		state->m_GPIO |= state->antenna_gpio;
+	else
+		state->m_GPIO &= ~state->antenna_gpio;
+
+	mutex_init(&state->mutex);
+
+	memcpy(&state->frontend.ops, &drxk_ops, sizeof(drxk_ops));
+	state->frontend.demodulator_priv = state;
+
+	init_state(state);
+
+	/* Load firmware and initialize DRX-K */
+	if (state->microcode_name) {
+		status = request_firmware_nowait(THIS_MODULE, 1,
+					      state->microcode_name,
+					      state->i2c->dev.parent,
+					      GFP_KERNEL,
+					      state, load_firmware_cb);
+		if (status < 0) {
+			printk(KERN_ERR
+			"drxk: failed to request a firmware\n");
+			return NULL;
+		}
+	} else if (init_drxk(state) < 0)
+		goto error;
+
+	printk(KERN_INFO "drxk: frontend initialized.\n");
+	return &state->frontend;
+
+error:
+	printk(KERN_ERR "drxk: not found\n");
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(drxk_attach);
+
+MODULE_DESCRIPTION("DRX-K driver");
+MODULE_AUTHOR("Ralph Metzler");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/drxk_hard.h b/drivers/media/dvb-frontends/drxk_hard.h
new file mode 100644
index 0000000..6bb9fc4
--- /dev/null
+++ b/drivers/media/dvb-frontends/drxk_hard.h
@@ -0,0 +1,364 @@
+#include "drxk_map.h"
+
+#define DRXK_VERSION_MAJOR 0
+#define DRXK_VERSION_MINOR 9
+#define DRXK_VERSION_PATCH 4300
+
+#define HI_I2C_DELAY        42
+#define HI_I2C_BRIDGE_DELAY 350
+#define DRXK_MAX_RETRIES    100
+
+#define DRIVER_4400 1
+
+#define DRXX_JTAGID   0x039210D9
+#define DRXX_J_JTAGID 0x239310D9
+#define DRXX_K_JTAGID 0x039210D9
+
+#define DRX_UNKNOWN     254
+#define DRX_AUTO        255
+
+#define DRX_SCU_READY   0
+#define DRXK_MAX_WAITTIME (200)
+#define SCU_RESULT_OK      0
+#define SCU_RESULT_SIZE   -4
+#define SCU_RESULT_INVPAR -3
+#define SCU_RESULT_UNKSTD -2
+#define SCU_RESULT_UNKCMD -1
+
+#ifndef DRXK_OFDM_TR_SHUTDOWN_TIMEOUT
+#define DRXK_OFDM_TR_SHUTDOWN_TIMEOUT (200)
+#endif
+
+#define DRXK_8VSB_MPEG_BIT_RATE     19392658UL  /*bps*/
+#define DRXK_DVBT_MPEG_BIT_RATE     32000000UL  /*bps*/
+#define DRXK_QAM16_MPEG_BIT_RATE    27000000UL  /*bps*/
+#define DRXK_QAM32_MPEG_BIT_RATE    33000000UL  /*bps*/
+#define DRXK_QAM64_MPEG_BIT_RATE    40000000UL  /*bps*/
+#define DRXK_QAM128_MPEG_BIT_RATE   46000000UL  /*bps*/
+#define DRXK_QAM256_MPEG_BIT_RATE   52000000UL  /*bps*/
+#define DRXK_MAX_MPEG_BIT_RATE      52000000UL  /*bps*/
+
+#define   IQM_CF_OUT_ENA_OFDM__M                                            0x4
+#define     IQM_FS_ADJ_SEL_B_QAM                                            0x1
+#define     IQM_FS_ADJ_SEL_B_OFF                                            0x0
+#define     IQM_FS_ADJ_SEL_B_VSB                                            0x2
+#define     IQM_RC_ADJ_SEL_B_OFF                                            0x0
+#define     IQM_RC_ADJ_SEL_B_QAM                                            0x1
+#define     IQM_RC_ADJ_SEL_B_VSB                                            0x2
+
+enum OperationMode {
+	OM_NONE,
+	OM_QAM_ITU_A,
+	OM_QAM_ITU_B,
+	OM_QAM_ITU_C,
+	OM_DVBT
+};
+
+enum DRXPowerMode {
+	DRX_POWER_UP = 0,
+	DRX_POWER_MODE_1,
+	DRX_POWER_MODE_2,
+	DRX_POWER_MODE_3,
+	DRX_POWER_MODE_4,
+	DRX_POWER_MODE_5,
+	DRX_POWER_MODE_6,
+	DRX_POWER_MODE_7,
+	DRX_POWER_MODE_8,
+
+	DRX_POWER_MODE_9,
+	DRX_POWER_MODE_10,
+	DRX_POWER_MODE_11,
+	DRX_POWER_MODE_12,
+	DRX_POWER_MODE_13,
+	DRX_POWER_MODE_14,
+	DRX_POWER_MODE_15,
+	DRX_POWER_MODE_16,
+	DRX_POWER_DOWN = 255
+};
+
+
+/** /brief Intermediate power mode for DRXK, power down OFDM clock domain */
+#ifndef DRXK_POWER_DOWN_OFDM
+#define DRXK_POWER_DOWN_OFDM        DRX_POWER_MODE_1
+#endif
+
+/** /brief Intermediate power mode for DRXK, power down core (sysclk) */
+#ifndef DRXK_POWER_DOWN_CORE
+#define DRXK_POWER_DOWN_CORE        DRX_POWER_MODE_9
+#endif
+
+/** /brief Intermediate power mode for DRXK, power down pll (only osc runs) */
+#ifndef DRXK_POWER_DOWN_PLL
+#define DRXK_POWER_DOWN_PLL         DRX_POWER_MODE_10
+#endif
+
+
+enum AGC_CTRL_MODE { DRXK_AGC_CTRL_AUTO = 0, DRXK_AGC_CTRL_USER, DRXK_AGC_CTRL_OFF };
+enum EDrxkState {
+	DRXK_UNINITIALIZED = 0,
+	DRXK_STOPPED,
+	DRXK_DTV_STARTED,
+	DRXK_ATV_STARTED,
+	DRXK_POWERED_DOWN,
+	DRXK_NO_DEV			/* If drxk init failed */
+};
+
+enum EDrxkCoefArrayIndex {
+	DRXK_COEF_IDX_MN = 0,
+	DRXK_COEF_IDX_FM    ,
+	DRXK_COEF_IDX_L     ,
+	DRXK_COEF_IDX_LP    ,
+	DRXK_COEF_IDX_BG    ,
+	DRXK_COEF_IDX_DK    ,
+	DRXK_COEF_IDX_I     ,
+	DRXK_COEF_IDX_MAX
+};
+enum EDrxkSifAttenuation {
+	DRXK_SIF_ATTENUATION_0DB,
+	DRXK_SIF_ATTENUATION_3DB,
+	DRXK_SIF_ATTENUATION_6DB,
+	DRXK_SIF_ATTENUATION_9DB
+};
+enum EDrxkConstellation {
+	DRX_CONSTELLATION_BPSK = 0,
+	DRX_CONSTELLATION_QPSK,
+	DRX_CONSTELLATION_PSK8,
+	DRX_CONSTELLATION_QAM16,
+	DRX_CONSTELLATION_QAM32,
+	DRX_CONSTELLATION_QAM64,
+	DRX_CONSTELLATION_QAM128,
+	DRX_CONSTELLATION_QAM256,
+	DRX_CONSTELLATION_QAM512,
+	DRX_CONSTELLATION_QAM1024,
+	DRX_CONSTELLATION_UNKNOWN = DRX_UNKNOWN,
+	DRX_CONSTELLATION_AUTO    = DRX_AUTO
+};
+enum EDrxkInterleaveMode {
+	DRXK_QAM_I12_J17    = 16,
+	DRXK_QAM_I_UNKNOWN  = DRX_UNKNOWN
+};
+enum {
+	DRXK_SPIN_A1 = 0,
+	DRXK_SPIN_A2,
+	DRXK_SPIN_A3,
+	DRXK_SPIN_UNKNOWN
+};
+
+enum DRXKCfgDvbtSqiSpeed {
+	DRXK_DVBT_SQI_SPEED_FAST = 0,
+	DRXK_DVBT_SQI_SPEED_MEDIUM,
+	DRXK_DVBT_SQI_SPEED_SLOW,
+	DRXK_DVBT_SQI_SPEED_UNKNOWN = DRX_UNKNOWN
+} ;
+
+enum DRXFftmode_t {
+	DRX_FFTMODE_2K = 0,
+	DRX_FFTMODE_4K,
+	DRX_FFTMODE_8K,
+	DRX_FFTMODE_UNKNOWN = DRX_UNKNOWN,
+	DRX_FFTMODE_AUTO    = DRX_AUTO
+};
+
+enum DRXMPEGStrWidth_t {
+	DRX_MPEG_STR_WIDTH_1,
+	DRX_MPEG_STR_WIDTH_8
+};
+
+enum DRXQamLockRange_t {
+	DRX_QAM_LOCKRANGE_NORMAL,
+	DRX_QAM_LOCKRANGE_EXTENDED
+};
+
+struct DRXKCfgDvbtEchoThres_t {
+	u16             threshold;
+	enum DRXFftmode_t      fftMode;
+} ;
+
+struct SCfgAgc {
+	enum AGC_CTRL_MODE     ctrlMode;        /* off, user, auto */
+	u16            outputLevel;     /* range dependent on AGC */
+	u16            minOutputLevel;  /* range dependent on AGC */
+	u16            maxOutputLevel;  /* range dependent on AGC */
+	u16            speed;           /* range dependent on AGC */
+	u16            top;             /* rf-agc take over point */
+	u16            cutOffCurrent;   /* rf-agc is accelerated if output current
+					   is below cut-off current */
+	u16            IngainTgtMax;
+	u16            FastClipCtrlDelay;
+};
+
+struct SCfgPreSaw {
+	u16        reference; /* pre SAW reference value, range 0 .. 31 */
+	bool          usePreSaw; /* TRUE algorithms must use pre SAW sense */
+};
+
+struct DRXKOfdmScCmd_t {
+	u16 cmd;        /**< Command number */
+	u16 subcmd;     /**< Sub-command parameter*/
+	u16 param0;     /**< General purpous param */
+	u16 param1;     /**< General purpous param */
+	u16 param2;     /**< General purpous param */
+	u16 param3;     /**< General purpous param */
+	u16 param4;     /**< General purpous param */
+};
+
+struct drxk_state {
+	struct dvb_frontend frontend;
+	struct dtv_frontend_properties props;
+	struct device *dev;
+
+	struct i2c_adapter *i2c;
+	u8     demod_address;
+	void  *priv;
+
+	struct mutex mutex;
+
+	u32    m_Instance;           /**< Channel 1,2,3 or 4 */
+
+	int    m_ChunkSize;
+	u8 Chunk[256];
+
+	bool   m_hasLNA;
+	bool   m_hasDVBT;
+	bool   m_hasDVBC;
+	bool   m_hasAudio;
+	bool   m_hasATV;
+	bool   m_hasOOB;
+	bool   m_hasSAWSW;         /**< TRUE if mat_tx is available */
+	bool   m_hasGPIO1;         /**< TRUE if mat_rx is available */
+	bool   m_hasGPIO2;         /**< TRUE if GPIO is available */
+	bool   m_hasIRQN;          /**< TRUE if IRQN is available */
+	u16    m_oscClockFreq;
+	u16    m_HICfgTimingDiv;
+	u16    m_HICfgBridgeDelay;
+	u16    m_HICfgWakeUpKey;
+	u16    m_HICfgTimeout;
+	u16    m_HICfgCtrl;
+	s32    m_sysClockFreq;      /**< system clock frequency in kHz */
+
+	enum EDrxkState    m_DrxkState;      /**< State of Drxk (init,stopped,started) */
+	enum OperationMode m_OperationMode;  /**< digital standards */
+	struct SCfgAgc     m_vsbRfAgcCfg;    /**< settings for VSB RF-AGC */
+	struct SCfgAgc     m_vsbIfAgcCfg;    /**< settings for VSB IF-AGC */
+	u16                m_vsbPgaCfg;      /**< settings for VSB PGA */
+	struct SCfgPreSaw  m_vsbPreSawCfg;   /**< settings for pre SAW sense */
+	s32    m_Quality83percent;  /**< MER level (*0.1 dB) for 83% quality indication */
+	s32    m_Quality93percent;  /**< MER level (*0.1 dB) for 93% quality indication */
+	bool   m_smartAntInverted;
+	bool   m_bDebugEnableBridge;
+	bool   m_bPDownOpenBridge;  /**< only open DRXK bridge before power-down once it has been accessed */
+	bool   m_bPowerDown;        /**< Power down when not used */
+
+	u32    m_IqmFsRateOfs;      /**< frequency shift as written to DRXK register (28bit fixpoint) */
+
+	bool   m_enableMPEGOutput;  /**< If TRUE, enable MPEG output */
+	bool   m_insertRSByte;      /**< If TRUE, insert RS byte */
+	bool   m_enableParallel;    /**< If TRUE, parallel out otherwise serial */
+	bool   m_invertDATA;        /**< If TRUE, invert DATA signals */
+	bool   m_invertERR;         /**< If TRUE, invert ERR signal */
+	bool   m_invertSTR;         /**< If TRUE, invert STR signals */
+	bool   m_invertVAL;         /**< If TRUE, invert VAL signals */
+	bool   m_invertCLK;         /**< If TRUE, invert CLK signals */
+	bool   m_DVBCStaticCLK;
+	bool   m_DVBTStaticCLK;     /**< If TRUE, static MPEG clockrate will
+					 be used, otherwise clockrate will
+					 adapt to the bitrate of the TS */
+	u32    m_DVBTBitrate;
+	u32    m_DVBCBitrate;
+
+	u8     m_TSDataStrength;
+	u8     m_TSClockkStrength;
+
+	bool   m_itut_annex_c;      /* If true, uses ITU-T DVB-C Annex C, instead of Annex A */
+
+	enum DRXMPEGStrWidth_t  m_widthSTR;    /**< MPEG start width */
+	u32    m_mpegTsStaticBitrate;          /**< Maximum bitrate in b/s in case
+						    static clockrate is selected */
+
+	/* LARGE_INTEGER   m_StartTime; */     /**< Contains the time of the last demod start */
+	s32    m_MpegLockTimeOut;      /**< WaitForLockStatus Timeout (counts from start time) */
+	s32    m_DemodLockTimeOut;     /**< WaitForLockStatus Timeout (counts from start time) */
+
+	bool   m_disableTEIhandling;
+
+	bool   m_RfAgcPol;
+	bool   m_IfAgcPol;
+
+	struct SCfgAgc    m_atvRfAgcCfg;  /**< settings for ATV RF-AGC */
+	struct SCfgAgc    m_atvIfAgcCfg;  /**< settings for ATV IF-AGC */
+	struct SCfgPreSaw m_atvPreSawCfg; /**< settings for ATV pre SAW sense */
+	bool              m_phaseCorrectionBypass;
+	s16               m_atvTopVidPeak;
+	u16               m_atvTopNoiseTh;
+	enum EDrxkSifAttenuation m_sifAttenuation;
+	bool              m_enableCVBSOutput;
+	bool              m_enableSIFOutput;
+	bool              m_bMirrorFreqSpect;
+	enum EDrxkConstellation  m_Constellation; /**< Constellation type of the channel */
+	u32               m_CurrSymbolRate;       /**< Current QAM symbol rate */
+	struct SCfgAgc    m_qamRfAgcCfg;          /**< settings for QAM RF-AGC */
+	struct SCfgAgc    m_qamIfAgcCfg;          /**< settings for QAM IF-AGC */
+	u16               m_qamPgaCfg;            /**< settings for QAM PGA */
+	struct SCfgPreSaw m_qamPreSawCfg;         /**< settings for QAM pre SAW sense */
+	enum EDrxkInterleaveMode m_qamInterleaveMode; /**< QAM Interleave mode */
+	u16               m_fecRsPlen;
+	u16               m_fecRsPrescale;
+
+	enum DRXKCfgDvbtSqiSpeed m_sqiSpeed;
+
+	u16               m_GPIO;
+	u16               m_GPIOCfg;
+
+	struct SCfgAgc    m_dvbtRfAgcCfg;     /**< settings for QAM RF-AGC */
+	struct SCfgAgc    m_dvbtIfAgcCfg;     /**< settings for QAM IF-AGC */
+	struct SCfgPreSaw m_dvbtPreSawCfg;    /**< settings for QAM pre SAW sense */
+
+	u16               m_agcFastClipCtrlDelay;
+	bool              m_adcCompPassed;
+	u16               m_adcCompCoef[64];
+	u16               m_adcState;
+
+	u8               *m_microcode;
+	int               m_microcode_length;
+	bool              m_DRXK_A1_PATCH_CODE;
+	bool              m_DRXK_A1_ROM_CODE;
+	bool              m_DRXK_A2_ROM_CODE;
+	bool              m_DRXK_A3_ROM_CODE;
+	bool              m_DRXK_A2_PATCH_CODE;
+	bool              m_DRXK_A3_PATCH_CODE;
+
+	bool              m_rfmirror;
+	u8                m_deviceSpin;
+	u32               m_iqmRcRate;
+
+	enum DRXPowerMode m_currentPowerMode;
+
+	/* when true, avoids other devices to use the I2C bus */
+	bool		  drxk_i2c_exclusive_lock;
+
+	/*
+	 * Configurable parameters at the driver. They stores the values found
+	 * at struct drxk_config.
+	 */
+
+	u16	UIO_mask;	/* Bits used by UIO */
+
+	bool	enable_merr_cfg;
+	bool	single_master;
+	bool	no_i2c_bridge;
+	bool	antenna_dvbt;
+	u16	antenna_gpio;
+
+	/* Firmware */
+	const char *microcode_name;
+	struct completion fw_wait_load;
+	const struct firmware *fw;
+	int qam_demod_parameter_count;
+};
+
+#define NEVER_LOCK 0
+#define NOT_LOCKED 1
+#define DEMOD_LOCK 2
+#define FEC_LOCK   3
+#define MPEG_LOCK  4
+
diff --git a/drivers/media/dvb-frontends/drxk_map.h b/drivers/media/dvb-frontends/drxk_map.h
new file mode 100644
index 0000000..23e16c1
--- /dev/null
+++ b/drivers/media/dvb-frontends/drxk_map.h
@@ -0,0 +1,451 @@
+#define  AUD_COMM_EXEC__A                                                  0x1000000
+#define    AUD_COMM_EXEC_STOP                                              0x0
+#define  FEC_COMM_EXEC__A                                                  0x1C00000
+#define    FEC_COMM_EXEC_STOP                                              0x0
+#define    FEC_COMM_EXEC_ACTIVE                                            0x1
+#define  FEC_DI_COMM_EXEC__A                                               0x1C20000
+#define    FEC_DI_COMM_EXEC_STOP                                           0x0
+#define  FEC_DI_INPUT_CTL__A                                               0x1C20016
+#define  FEC_RS_COMM_EXEC__A                                               0x1C30000
+#define    FEC_RS_COMM_EXEC_STOP                                           0x0
+#define  FEC_RS_MEASUREMENT_PERIOD__A                                      0x1C30012
+#define  FEC_RS_MEASUREMENT_PRESCALE__A                                    0x1C30013
+#define  FEC_OC_MODE__A                                                    0x1C40011
+#define    FEC_OC_MODE_PARITY__M                                           0x1
+#define  FEC_OC_DTO_MODE__A                                                0x1C40014
+#define    FEC_OC_DTO_MODE_DYNAMIC__M                                      0x1
+#define    FEC_OC_DTO_MODE_OFFSET_ENABLE__M                                0x4
+#define  FEC_OC_DTO_PERIOD__A                                              0x1C40015
+#define  FEC_OC_DTO_BURST_LEN__A                                           0x1C40018
+#define  FEC_OC_FCT_MODE__A                                                0x1C4001A
+#define  FEC_OC_FCT_MODE__PRE                                              0x0
+#define    FEC_OC_FCT_MODE_RAT_ENA__M                                      0x1
+#define    FEC_OC_FCT_MODE_VIRT_ENA__M                                     0x2
+#define  FEC_OC_TMD_MODE__A                                                0x1C4001E
+#define  FEC_OC_TMD_COUNT__A                                               0x1C4001F
+#define  FEC_OC_TMD_HI_MARGIN__A                                           0x1C40020
+#define  FEC_OC_TMD_LO_MARGIN__A                                           0x1C40021
+#define  FEC_OC_TMD_INT_UPD_RATE__A                                        0x1C40023
+#define  FEC_OC_AVR_PARM_A__A                                              0x1C40026
+#define  FEC_OC_AVR_PARM_B__A                                              0x1C40027
+#define  FEC_OC_RCN_GAIN__A                                                0x1C4002E
+#define  FEC_OC_RCN_CTL_RATE_LO__A                                         0x1C40030
+#define  FEC_OC_RCN_CTL_STEP_LO__A                                         0x1C40032
+#define  FEC_OC_RCN_CTL_STEP_HI__A                                         0x1C40033
+#define  FEC_OC_SNC_MODE__A                                                0x1C40040
+#define    FEC_OC_SNC_MODE_SHUTDOWN__M                                     0x10
+#define  FEC_OC_SNC_LWM__A                                                 0x1C40041
+#define  FEC_OC_SNC_HWM__A                                                 0x1C40042
+#define  FEC_OC_SNC_UNLOCK__A                                              0x1C40043
+#define  FEC_OC_SNC_FAIL_PERIOD__A                                         0x1C40046
+#define  FEC_OC_IPR_MODE__A                                                0x1C40048
+#define    FEC_OC_IPR_MODE_SERIAL__M                                       0x1
+#define    FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__M                             0x4
+#define    FEC_OC_IPR_MODE_MVAL_DIS_PAR__M                                 0x10
+#define  FEC_OC_IPR_INVERT__A                                              0x1C40049
+#define    FEC_OC_IPR_INVERT_MD0__M                                        0x1
+#define    FEC_OC_IPR_INVERT_MD1__M                                        0x2
+#define    FEC_OC_IPR_INVERT_MD2__M                                        0x4
+#define    FEC_OC_IPR_INVERT_MD3__M                                        0x8
+#define    FEC_OC_IPR_INVERT_MD4__M                                        0x10
+#define    FEC_OC_IPR_INVERT_MD5__M                                        0x20
+#define    FEC_OC_IPR_INVERT_MD6__M                                        0x40
+#define    FEC_OC_IPR_INVERT_MD7__M                                        0x80
+#define    FEC_OC_IPR_INVERT_MERR__M                                       0x100
+#define    FEC_OC_IPR_INVERT_MSTRT__M                                      0x200
+#define    FEC_OC_IPR_INVERT_MVAL__M                                       0x400
+#define    FEC_OC_IPR_INVERT_MCLK__M                                       0x800
+#define  FEC_OC_OCR_INVERT__A                                              0x1C40052
+#define  IQM_COMM_EXEC__A                                                  0x1800000
+#define      IQM_COMM_EXEC_B_STOP                                          0x0
+#define      IQM_COMM_EXEC_B_ACTIVE                                        0x1
+#define  IQM_FS_RATE_OFS_LO__A                                             0x1820010
+#define  IQM_FS_ADJ_SEL__A                                                 0x1820014
+#define      IQM_FS_ADJ_SEL_B_OFF                                          0x0
+#define      IQM_FS_ADJ_SEL_B_QAM                                          0x1
+#define      IQM_FS_ADJ_SEL_B_VSB                                          0x2
+#define  IQM_FD_RATESEL__A                                                 0x1830010
+#define  IQM_RC_RATE_OFS_LO__A                                             0x1840010
+#define  IQM_RC_RATE_OFS_LO__W                                             16
+#define  IQM_RC_RATE_OFS_LO__M                                             0xFFFF
+#define  IQM_RC_RATE_OFS_HI__M                                             0xFF
+#define  IQM_RC_ADJ_SEL__A                                                 0x1840014
+#define      IQM_RC_ADJ_SEL_B_OFF                                          0x0
+#define      IQM_RC_ADJ_SEL_B_QAM                                          0x1
+#define      IQM_RC_ADJ_SEL_B_VSB                                          0x2
+#define  IQM_RC_STRETCH__A                                                 0x1840016
+#define  IQM_CF_COMM_INT_MSK__A                                            0x1860006
+#define  IQM_CF_SYMMETRIC__A                                               0x1860010
+#define  IQM_CF_MIDTAP__A                                                  0x1860011
+#define    IQM_CF_MIDTAP_RE__B                                             0
+#define    IQM_CF_MIDTAP_IM__B                                             1
+#define  IQM_CF_OUT_ENA__A                                                 0x1860012
+#define    IQM_CF_OUT_ENA_QAM__B                                           1
+#define    IQM_CF_OUT_ENA_OFDM__M                                          0x4
+#define  IQM_CF_ADJ_SEL__A                                                 0x1860013
+#define  IQM_CF_SCALE__A                                                   0x1860014
+#define  IQM_CF_SCALE_SH__A                                                0x1860015
+#define  IQM_CF_SCALE_SH__PRE                                              0x0
+#define  IQM_CF_POW_MEAS_LEN__A                                            0x1860017
+#define  IQM_CF_DS_ENA__A                                                  0x1860019
+#define  IQM_CF_TAP_RE0__A                                                 0x1860020
+#define  IQM_CF_TAP_IM0__A                                                 0x1860040
+#define  IQM_CF_CLP_VAL__A                                                 0x1860060
+#define  IQM_CF_DATATH__A                                                  0x1860061
+#define  IQM_CF_PKDTH__A                                                   0x1860062
+#define  IQM_CF_WND_LEN__A                                                 0x1860063
+#define  IQM_CF_DET_LCT__A                                                 0x1860064
+#define  IQM_CF_BYPASSDET__A                                               0x1860067
+#define  IQM_AF_COMM_EXEC__A                                               0x1870000
+#define    IQM_AF_COMM_EXEC_ACTIVE                                         0x1
+#define  IQM_AF_CLKNEG__A                                                  0x1870012
+#define    IQM_AF_CLKNEG_CLKNEGDATA__M                                     0x2
+#define      IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS                     0x0
+#define      IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_NEG                     0x2
+#define  IQM_AF_START_LOCK__A                                              0x187001B
+#define  IQM_AF_PHASE0__A                                                  0x187001C
+#define  IQM_AF_PHASE1__A                                                  0x187001D
+#define  IQM_AF_PHASE2__A                                                  0x187001E
+#define  IQM_AF_CLP_LEN__A                                                 0x1870023
+#define  IQM_AF_CLP_TH__A                                                  0x1870024
+#define  IQM_AF_SNS_LEN__A                                                 0x1870026
+#define  IQM_AF_AGC_IF__A                                                  0x1870028
+#define  IQM_AF_AGC_RF__A                                                  0x1870029
+#define  IQM_AF_PDREF__A                                                   0x187002B
+#define  IQM_AF_PDREF__M                                                   0x1F
+#define  IQM_AF_STDBY__A                                                   0x187002C
+#define      IQM_AF_STDBY_STDBY_ADC_STANDBY                                0x2
+#define      IQM_AF_STDBY_STDBY_AMP_STANDBY                                0x4
+#define      IQM_AF_STDBY_STDBY_PD_STANDBY                                 0x8
+#define      IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY                            0x10
+#define      IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY                            0x20
+#define  IQM_AF_AMUX__A                                                    0x187002D
+#define    IQM_AF_AMUX_SIGNAL2ADC                                          0x1
+#define  IQM_AF_UPD_SEL__A                                                 0x187002F
+#define  IQM_AF_INC_LCT__A                                                 0x1870034
+#define  IQM_AF_INC_BYPASS__A                                              0x1870036
+#define  OFDM_CP_COMM_EXEC__A                                              0x2800000
+#define    OFDM_CP_COMM_EXEC_STOP                                          0x0
+#define  OFDM_EC_SB_PRIOR__A                                               0x3410013
+#define    OFDM_EC_SB_PRIOR_HI                                             0x0
+#define    OFDM_EC_SB_PRIOR_LO                                             0x1
+#define  OFDM_EQ_TOP_TD_TPS_CONST__A                                       0x3010054
+#define  OFDM_EQ_TOP_TD_TPS_CONST__M                                       0x3
+#define    OFDM_EQ_TOP_TD_TPS_CONST_64QAM                                  0x2
+#define  OFDM_EQ_TOP_TD_TPS_CODE_HP__A                                     0x3010056
+#define  OFDM_EQ_TOP_TD_TPS_CODE_HP__M                                     0x7
+#define    OFDM_EQ_TOP_TD_TPS_CODE_LP_7_8                                  0x4
+#define  OFDM_EQ_TOP_TD_SQR_ERR_I__A                                       0x301005E
+#define  OFDM_EQ_TOP_TD_SQR_ERR_Q__A                                       0x301005F
+#define  OFDM_EQ_TOP_TD_SQR_ERR_EXP__A                                     0x3010060
+#define  OFDM_EQ_TOP_TD_REQ_SMB_CNT__A                                     0x3010061
+#define  OFDM_EQ_TOP_TD_TPS_PWR_OFS__A                                     0x3010062
+#define  OFDM_LC_COMM_EXEC__A                                              0x3800000
+#define    OFDM_LC_COMM_EXEC_STOP                                          0x0
+#define  OFDM_SC_COMM_EXEC__A                                              0x3C00000
+#define    OFDM_SC_COMM_EXEC_STOP                                          0x0
+#define  OFDM_SC_COMM_STATE__A                                             0x3C00001
+#define  OFDM_SC_RA_RAM_PARAM0__A                                          0x3C20040
+#define  OFDM_SC_RA_RAM_PARAM1__A                                          0x3C20041
+#define  OFDM_SC_RA_RAM_CMD_ADDR__A                                        0x3C20042
+#define  OFDM_SC_RA_RAM_CMD__A                                             0x3C20043
+#define    OFDM_SC_RA_RAM_CMD_NULL                                         0x0
+#define    OFDM_SC_RA_RAM_CMD_PROC_START                                   0x1
+#define    OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM                               0x3
+#define    OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM                                0x4
+#define    OFDM_SC_RA_RAM_CMD_GET_OP_PARAM                                 0x5
+#define    OFDM_SC_RA_RAM_CMD_USER_IO                                      0x6
+#define    OFDM_SC_RA_RAM_CMD_SET_TIMER                                    0x7
+#define    OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING                              0x8
+#define    OFDM_SC_RA_RAM_SW_EVENT_RUN_NMASK__M                            0x1
+#define    OFDM_SC_RA_RAM_LOCKTRACK_MIN                                    0x1
+#define  OFDM_SC_RA_RAM_OP_PARAM__A                                        0x3C20048
+#define    OFDM_SC_RA_RAM_OP_PARAM_MODE__M                                 0x3
+#define      OFDM_SC_RA_RAM_OP_PARAM_MODE_2K                               0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_MODE_8K                               0x1
+#define      OFDM_SC_RA_RAM_OP_PARAM_GUARD_32                              0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_GUARD_16                              0x4
+#define      OFDM_SC_RA_RAM_OP_PARAM_GUARD_8                               0x8
+#define      OFDM_SC_RA_RAM_OP_PARAM_GUARD_4                               0xC
+#define      OFDM_SC_RA_RAM_OP_PARAM_CONST_QPSK                            0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM16                           0x10
+#define      OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64                           0x20
+#define      OFDM_SC_RA_RAM_OP_PARAM_HIER_NO                               0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_HIER_A1                               0x40
+#define      OFDM_SC_RA_RAM_OP_PARAM_HIER_A2                               0x80
+#define      OFDM_SC_RA_RAM_OP_PARAM_HIER_A4                               0xC0
+#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_1_2                              0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3                              0x200
+#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_3_4                              0x400
+#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_5_6                              0x600
+#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_7_8                              0x800
+#define      OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI                               0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_PRIO_LO                               0x1000
+#define    OFDM_SC_RA_RAM_OP_AUTO_MODE__M                                  0x1
+#define    OFDM_SC_RA_RAM_OP_AUTO_GUARD__M                                 0x2
+#define    OFDM_SC_RA_RAM_OP_AUTO_CONST__M                                 0x4
+#define    OFDM_SC_RA_RAM_OP_AUTO_HIER__M                                  0x8
+#define    OFDM_SC_RA_RAM_OP_AUTO_RATE__M                                  0x10
+#define  OFDM_SC_RA_RAM_LOCK__A                                            0x3C2004B
+#define    OFDM_SC_RA_RAM_LOCK_DEMOD__M                                    0x1
+#define    OFDM_SC_RA_RAM_LOCK_FEC__M                                      0x2
+#define    OFDM_SC_RA_RAM_LOCK_MPEG__M                                     0x4
+#define    OFDM_SC_RA_RAM_LOCK_NODVBT__M                                   0x8
+#define  OFDM_SC_RA_RAM_BE_OPT_DELAY__A                                    0x3C2004D
+#define  OFDM_SC_RA_RAM_BE_OPT_INIT_DELAY__A                               0x3C2004E
+#define  OFDM_SC_RA_RAM_ECHO_THRES__A                                      0x3C2004F
+#define    OFDM_SC_RA_RAM_ECHO_THRES_8K__B                                 0
+#define    OFDM_SC_RA_RAM_ECHO_THRES_8K__M                                 0xFF
+#define    OFDM_SC_RA_RAM_ECHO_THRES_2K__B                                 8
+#define    OFDM_SC_RA_RAM_ECHO_THRES_2K__M                                 0xFF00
+#define  OFDM_SC_RA_RAM_CONFIG__A                                          0x3C20050
+#define    OFDM_SC_RA_RAM_CONFIG_NE_FIX_ENABLE__M                          0x800
+#define  OFDM_SC_RA_RAM_FR_THRES_8K__A                                     0x3C2007D
+#define  OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A                             0x3C200E0
+#define  OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A                            0x3C200E1
+#define  OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A                             0x3C200E3
+#define  OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A                            0x3C200E4
+#define  OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A                                0x3C200F8
+#define  QAM_COMM_EXEC__A                                                  0x1400000
+#define    QAM_COMM_EXEC_STOP                                              0x0
+#define    QAM_COMM_EXEC_ACTIVE                                            0x1
+#define    QAM_TOP_ANNEX_A                                                 0x0
+#define    QAM_TOP_ANNEX_C                                                 0x2
+#define  QAM_SL_ERR_POWER__A                                               0x1430017
+#define  QAM_DQ_QUAL_FUN0__A                                               0x1440018
+#define  QAM_DQ_QUAL_FUN1__A                                               0x1440019
+#define  QAM_DQ_QUAL_FUN2__A                                               0x144001A
+#define  QAM_DQ_QUAL_FUN3__A                                               0x144001B
+#define  QAM_DQ_QUAL_FUN4__A                                               0x144001C
+#define  QAM_DQ_QUAL_FUN5__A                                               0x144001D
+#define  QAM_LC_MODE__A                                                    0x1450010
+#define  QAM_LC_QUAL_TAB0__A                                               0x1450018
+#define  QAM_LC_QUAL_TAB1__A                                               0x1450019
+#define  QAM_LC_QUAL_TAB2__A                                               0x145001A
+#define  QAM_LC_QUAL_TAB3__A                                               0x145001B
+#define  QAM_LC_QUAL_TAB4__A                                               0x145001C
+#define  QAM_LC_QUAL_TAB5__A                                               0x145001D
+#define  QAM_LC_QUAL_TAB6__A                                               0x145001E
+#define  QAM_LC_QUAL_TAB8__A                                               0x145001F
+#define  QAM_LC_QUAL_TAB9__A                                               0x1450020
+#define  QAM_LC_QUAL_TAB10__A                                              0x1450021
+#define  QAM_LC_QUAL_TAB12__A                                              0x1450022
+#define  QAM_LC_QUAL_TAB15__A                                              0x1450023
+#define  QAM_LC_QUAL_TAB16__A                                              0x1450024
+#define  QAM_LC_QUAL_TAB20__A                                              0x1450025
+#define  QAM_LC_QUAL_TAB25__A                                              0x1450026
+#define  QAM_LC_LPF_FACTORP__A                                             0x1450028
+#define  QAM_LC_LPF_FACTORI__A                                             0x1450029
+#define  QAM_LC_RATE_LIMIT__A                                              0x145002A
+#define  QAM_LC_SYMBOL_FREQ__A                                             0x145002B
+#define  QAM_SY_TIMEOUT__A                                                 0x1470011
+#define  QAM_SY_TIMEOUT__PRE                                               0x3A98
+#define  QAM_SY_SYNC_LWM__A                                                0x1470012
+#define  QAM_SY_SYNC_AWM__A                                                0x1470013
+#define  QAM_SY_SYNC_HWM__A                                                0x1470014
+#define  QAM_SY_SP_INV__A                                                  0x1470017
+#define    QAM_SY_SP_INV_SPECTRUM_INV_DIS                                  0x0
+#define  SCU_COMM_EXEC__A                                                  0x800000
+#define    SCU_COMM_EXEC_STOP                                              0x0
+#define    SCU_COMM_EXEC_ACTIVE                                            0x1
+#define    SCU_COMM_EXEC_HOLD                                              0x2
+#define  SCU_RAM_DRIVER_DEBUG__A                                           0x831EBF
+#define  SCU_RAM_QAM_FSM_STEP_PERIOD__A                                    0x831EC4
+#define  SCU_RAM_GPIO__A                                                   0x831EC7
+#define      SCU_RAM_GPIO_HW_LOCK_IND_DISABLE                              0x0
+#define  SCU_RAM_AGC_CLP_CTRL_MODE__A                                      0x831EC8
+#define  SCU_RAM_FEC_ACCUM_PKT_FAILURES__A                                 0x831ECB
+#define  SCU_RAM_FEC_PRE_RS_BER_FILTER_SH__A                               0x831F05
+#define  SCU_RAM_AGC_FAST_SNS_CTRL_DELAY__A                                0x831F15
+#define  SCU_RAM_AGC_KI_CYCLEN__A                                          0x831F17
+#define  SCU_RAM_AGC_SNS_CYCLEN__A                                         0x831F18
+#define  SCU_RAM_AGC_RF_SNS_DEV_MAX__A                                     0x831F19
+#define  SCU_RAM_AGC_RF_SNS_DEV_MIN__A                                     0x831F1A
+#define  SCU_RAM_AGC_RF_MAX__A                                             0x831F1B
+#define  SCU_RAM_AGC_CONFIG__A                                             0x831F24
+#define    SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M                            0x1
+#define    SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M                            0x2
+#define    SCU_RAM_AGC_CONFIG_INV_IF_POL__M                                0x100
+#define    SCU_RAM_AGC_CONFIG_INV_RF_POL__M                                0x200
+#define  SCU_RAM_AGC_KI__A                                                 0x831F25
+#define    SCU_RAM_AGC_KI_RF__B                                            4
+#define    SCU_RAM_AGC_KI_RF__M                                            0xF0
+#define    SCU_RAM_AGC_KI_IF__B                                            8
+#define    SCU_RAM_AGC_KI_IF__M                                            0xF00
+#define  SCU_RAM_AGC_KI_RED__A                                             0x831F26
+#define    SCU_RAM_AGC_KI_RED_RAGC_RED__B                                  2
+#define    SCU_RAM_AGC_KI_RED_RAGC_RED__M                                  0xC
+#define    SCU_RAM_AGC_KI_RED_IAGC_RED__B                                  4
+#define    SCU_RAM_AGC_KI_RED_IAGC_RED__M                                  0x30
+#define  SCU_RAM_AGC_KI_INNERGAIN_MIN__A                                   0x831F27
+#define  SCU_RAM_AGC_KI_MINGAIN__A                                         0x831F28
+#define  SCU_RAM_AGC_KI_MAXGAIN__A                                         0x831F29
+#define  SCU_RAM_AGC_KI_MAXMINGAIN_TH__A                                   0x831F2A
+#define  SCU_RAM_AGC_KI_MIN__A                                             0x831F2B
+#define  SCU_RAM_AGC_KI_MAX__A                                             0x831F2C
+#define  SCU_RAM_AGC_CLP_SUM__A                                            0x831F2D
+#define  SCU_RAM_AGC_CLP_SUM_MIN__A                                        0x831F2E
+#define  SCU_RAM_AGC_CLP_SUM_MAX__A                                        0x831F2F
+#define  SCU_RAM_AGC_CLP_CYCLEN__A                                         0x831F30
+#define  SCU_RAM_AGC_CLP_CYCCNT__A                                         0x831F31
+#define  SCU_RAM_AGC_CLP_DIR_TO__A                                         0x831F32
+#define  SCU_RAM_AGC_CLP_DIR_WD__A                                         0x831F33
+#define  SCU_RAM_AGC_CLP_DIR_STP__A                                        0x831F34
+#define  SCU_RAM_AGC_SNS_SUM__A                                            0x831F35
+#define  SCU_RAM_AGC_SNS_SUM_MIN__A                                        0x831F36
+#define  SCU_RAM_AGC_SNS_SUM_MAX__A                                        0x831F37
+#define  SCU_RAM_AGC_SNS_CYCCNT__A                                         0x831F38
+#define  SCU_RAM_AGC_SNS_DIR_TO__A                                         0x831F39
+#define  SCU_RAM_AGC_SNS_DIR_WD__A                                         0x831F3A
+#define  SCU_RAM_AGC_SNS_DIR_STP__A                                        0x831F3B
+#define  SCU_RAM_AGC_INGAIN_TGT__A                                         0x831F3D
+#define  SCU_RAM_AGC_INGAIN_TGT_MIN__A                                     0x831F3E
+#define  SCU_RAM_AGC_INGAIN_TGT_MAX__A                                     0x831F3F
+#define  SCU_RAM_AGC_IF_IACCU_HI__A                                        0x831F40
+#define  SCU_RAM_AGC_IF_IACCU_LO__A                                        0x831F41
+#define  SCU_RAM_AGC_IF_IACCU_HI_TGT__A                                    0x831F42
+#define  SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__A                                0x831F43
+#define  SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A                                0x831F44
+#define  SCU_RAM_AGC_RF_IACCU_HI__A                                        0x831F45
+#define  SCU_RAM_AGC_RF_IACCU_LO__A                                        0x831F46
+#define  SCU_RAM_AGC_RF_IACCU_HI_CO__A                                     0x831F47
+#define  SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A                                 0x831F84
+#define  SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A                                0x831F85
+#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A                                  0x831F86
+#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A                                  0x831F87
+#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A                                  0x831F88
+#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A                                  0x831F89
+#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A                                  0x831F8A
+#define  SCU_RAM_QAM_FSM_RTH__A                                            0x831F8E
+#define  SCU_RAM_QAM_FSM_FTH__A                                            0x831F8F
+#define  SCU_RAM_QAM_FSM_PTH__A                                            0x831F90
+#define  SCU_RAM_QAM_FSM_MTH__A                                            0x831F91
+#define  SCU_RAM_QAM_FSM_CTH__A                                            0x831F92
+#define  SCU_RAM_QAM_FSM_QTH__A                                            0x831F93
+#define  SCU_RAM_QAM_FSM_RATE_LIM__A                                       0x831F94
+#define  SCU_RAM_QAM_FSM_FREQ_LIM__A                                       0x831F95
+#define  SCU_RAM_QAM_FSM_COUNT_LIM__A                                      0x831F96
+#define  SCU_RAM_QAM_LC_CA_COARSE__A                                       0x831F97
+#define  SCU_RAM_QAM_LC_CA_FINE__A                                         0x831F99
+#define  SCU_RAM_QAM_LC_CP_COARSE__A                                       0x831F9A
+#define  SCU_RAM_QAM_LC_CP_MEDIUM__A                                       0x831F9B
+#define  SCU_RAM_QAM_LC_CP_FINE__A                                         0x831F9C
+#define  SCU_RAM_QAM_LC_CI_COARSE__A                                       0x831F9D
+#define  SCU_RAM_QAM_LC_CI_MEDIUM__A                                       0x831F9E
+#define  SCU_RAM_QAM_LC_CI_FINE__A                                         0x831F9F
+#define  SCU_RAM_QAM_LC_EP_COARSE__A                                       0x831FA0
+#define  SCU_RAM_QAM_LC_EP_MEDIUM__A                                       0x831FA1
+#define  SCU_RAM_QAM_LC_EP_FINE__A                                         0x831FA2
+#define  SCU_RAM_QAM_LC_EI_COARSE__A                                       0x831FA3
+#define  SCU_RAM_QAM_LC_EI_MEDIUM__A                                       0x831FA4
+#define  SCU_RAM_QAM_LC_EI_FINE__A                                         0x831FA5
+#define  SCU_RAM_QAM_LC_CF_COARSE__A                                       0x831FA6
+#define  SCU_RAM_QAM_LC_CF_MEDIUM__A                                       0x831FA7
+#define  SCU_RAM_QAM_LC_CF_FINE__A                                         0x831FA8
+#define  SCU_RAM_QAM_LC_CF1_COARSE__A                                      0x831FA9
+#define  SCU_RAM_QAM_LC_CF1_MEDIUM__A                                      0x831FAA
+#define  SCU_RAM_QAM_LC_CF1_FINE__A                                        0x831FAB
+#define  SCU_RAM_QAM_SL_SIG_POWER__A                                       0x831FAC
+#define  SCU_RAM_QAM_EQ_CMA_RAD0__A                                        0x831FAD
+#define  SCU_RAM_QAM_EQ_CMA_RAD1__A                                        0x831FAE
+#define  SCU_RAM_QAM_EQ_CMA_RAD2__A                                        0x831FAF
+#define  SCU_RAM_QAM_EQ_CMA_RAD3__A                                        0x831FB0
+#define  SCU_RAM_QAM_EQ_CMA_RAD4__A                                        0x831FB1
+#define  SCU_RAM_QAM_EQ_CMA_RAD5__A                                        0x831FB2
+#define      SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED                        0x4000
+#define      SCU_RAM_QAM_LOCKED_LOCKED_LOCKED                              0x8000
+#define      SCU_RAM_QAM_LOCKED_LOCKED_NEVER_LOCK                          0xC000
+#define  SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A                                0x831FEA
+#define  SCU_RAM_DRIVER_VER_HI__A                                          0x831FEB
+#define  SCU_RAM_DRIVER_VER_LO__A                                          0x831FEC
+#define  SCU_RAM_PARAM_15__A                                               0x831FED
+#define  SCU_RAM_PARAM_0__A                                                0x831FFC
+#define  SCU_RAM_COMMAND__A                                                0x831FFD
+#define    SCU_RAM_COMMAND_CMD_DEMOD_RESET                                 0x1
+#define    SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV                               0x2
+#define    SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM                             0x3
+#define    SCU_RAM_COMMAND_CMD_DEMOD_START                                 0x4
+#define    SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK                              0x5
+#define    SCU_RAM_COMMAND_CMD_DEMOD_STOP                                  0x9
+#define      SCU_RAM_COMMAND_STANDARD_QAM                                  0x200
+#define      SCU_RAM_COMMAND_STANDARD_OFDM                                 0x400
+#define  SIO_TOP_COMM_KEY__A                                               0x41000F
+#define    SIO_TOP_COMM_KEY_KEY                                            0xFABA
+#define  SIO_TOP_JTAGID_LO__A                                              0x410012
+#define  SIO_HI_RA_RAM_RES__A                                              0x420031
+#define  SIO_HI_RA_RAM_CMD__A                                              0x420032
+#define    SIO_HI_RA_RAM_CMD_RESET                                         0x2
+#define    SIO_HI_RA_RAM_CMD_CONFIG                                        0x3
+#define    SIO_HI_RA_RAM_CMD_BRDCTRL                                       0x7
+#define  SIO_HI_RA_RAM_PAR_1__A                                            0x420033
+#define      SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY                              0x3945
+#define  SIO_HI_RA_RAM_PAR_2__A                                            0x420034
+#define    SIO_HI_RA_RAM_PAR_2_CFG_DIV__M                                  0x7F
+#define      SIO_HI_RA_RAM_PAR_2_BRD_CFG_OPEN                              0x0
+#define      SIO_HI_RA_RAM_PAR_2_BRD_CFG_CLOSED                            0x4
+#define  SIO_HI_RA_RAM_PAR_3__A                                            0x420035
+#define    SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M                              0x7F
+#define    SIO_HI_RA_RAM_PAR_3_CFG_DBL_SCL__B                              7
+#define      SIO_HI_RA_RAM_PAR_3_ACP_RW_READ                               0x0
+#define      SIO_HI_RA_RAM_PAR_3_ACP_RW_WRITE                              0x8
+#define  SIO_HI_RA_RAM_PAR_4__A                                            0x420036
+#define  SIO_HI_RA_RAM_PAR_5__A                                            0x420037
+#define      SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE                            0x1
+#define    SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M                                0x8
+#define      SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ                             0x8
+#define  SIO_HI_RA_RAM_PAR_6__A                                            0x420038
+#define  SIO_CC_PLL_LOCK__A                                                0x450012
+#define  SIO_CC_PWD_MODE__A                                                0x450015
+#define      SIO_CC_PWD_MODE_LEVEL_NONE                                    0x0
+#define      SIO_CC_PWD_MODE_LEVEL_OFDM                                    0x1
+#define      SIO_CC_PWD_MODE_LEVEL_CLOCK                                   0x2
+#define      SIO_CC_PWD_MODE_LEVEL_PLL                                     0x3
+#define      SIO_CC_PWD_MODE_LEVEL_OSC                                     0x4
+#define  SIO_CC_SOFT_RST__A                                                0x450016
+#define    SIO_CC_SOFT_RST_OFDM__M                                         0x1
+#define    SIO_CC_SOFT_RST_SYS__M                                          0x2
+#define    SIO_CC_SOFT_RST_OSC__M                                          0x4
+#define  SIO_CC_UPDATE__A                                                  0x450017
+#define    SIO_CC_UPDATE_KEY                                               0xFABA
+#define  SIO_OFDM_SH_OFDM_RING_ENABLE__A                                   0x470010
+#define    SIO_OFDM_SH_OFDM_RING_ENABLE_OFF                                0x0
+#define    SIO_OFDM_SH_OFDM_RING_ENABLE_ON                                 0x1
+#define  SIO_OFDM_SH_OFDM_RING_STATUS__A                                   0x470012
+#define    SIO_OFDM_SH_OFDM_RING_STATUS_DOWN                               0x0
+#define    SIO_OFDM_SH_OFDM_RING_STATUS_ENABLED                            0x1
+#define  SIO_BL_COMM_EXEC__A                                               0x480000
+#define    SIO_BL_COMM_EXEC_ACTIVE                                         0x1
+#define  SIO_BL_STATUS__A                                                  0x480010
+#define  SIO_BL_MODE__A                                                    0x480011
+#define    SIO_BL_MODE_DIRECT                                              0x0
+#define    SIO_BL_MODE_CHAIN                                               0x1
+#define  SIO_BL_ENABLE__A                                                  0x480012
+#define    SIO_BL_ENABLE_ON                                                0x1
+#define  SIO_BL_TGT_HDR__A                                                 0x480014
+#define  SIO_BL_TGT_ADDR__A                                                0x480015
+#define  SIO_BL_SRC_ADDR__A                                                0x480016
+#define  SIO_BL_SRC_LEN__A                                                 0x480017
+#define  SIO_BL_CHAIN_ADDR__A                                              0x480018
+#define  SIO_BL_CHAIN_LEN__A                                               0x480019
+#define  SIO_PDR_MON_CFG__A                                                0x7F0010
+#define  SIO_PDR_UIO_IN_HI__A                                              0x7F0015
+#define  SIO_PDR_UIO_OUT_LO__A                                             0x7F0016
+#define  SIO_PDR_OHW_CFG__A                                                0x7F001F
+#define    SIO_PDR_OHW_CFG_FREF_SEL__M                                     0x3
+#define  SIO_PDR_GPIO_CFG__A                                               0x7F0021
+#define  SIO_PDR_MSTRT_CFG__A                                              0x7F0025
+#define  SIO_PDR_MERR_CFG__A                                               0x7F0026
+#define  SIO_PDR_MCLK_CFG__A                                               0x7F0028
+#define    SIO_PDR_MCLK_CFG_DRIVE__B                                       3
+#define  SIO_PDR_MVAL_CFG__A                                               0x7F0029
+#define  SIO_PDR_MD0_CFG__A                                                0x7F002A
+#define    SIO_PDR_MD0_CFG_DRIVE__B                                        3
+#define  SIO_PDR_MD1_CFG__A                                                0x7F002B
+#define  SIO_PDR_MD2_CFG__A                                                0x7F002C
+#define  SIO_PDR_MD3_CFG__A                                                0x7F002D
+#define  SIO_PDR_MD4_CFG__A                                                0x7F002F
+#define  SIO_PDR_MD5_CFG__A                                                0x7F0030
+#define  SIO_PDR_MD6_CFG__A                                                0x7F0031
+#define  SIO_PDR_MD7_CFG__A                                                0x7F0032
+#define  SIO_PDR_SMA_RX_CFG__A                                             0x7F0037
+#define  SIO_PDR_SMA_TX_CFG__A                                             0x7F0038
diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c
new file mode 100644
index 0000000..4c8ac26
--- /dev/null
+++ b/drivers/media/dvb-frontends/ds3000.c
@@ -0,0 +1,1312 @@
+/*
+    Montage Technology DS3000/TS2020 - DVBS/S2 Demodulator/Tuner driver
+    Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
+
+    Copyright (C) 2009 TurboSight.com
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+
+#include "dvb_frontend.h"
+#include "ds3000.h"
+
+static int debug;
+
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(args); \
+	} while (0)
+
+/* as of March 2009 current DS3000 firmware version is 1.78 */
+/* DS3000 FW v1.78 MD5: a32d17910c4f370073f9346e71d34b80 */
+#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds3000.fw"
+
+#define DS3000_SAMPLE_RATE 96000 /* in kHz */
+#define DS3000_XTAL_FREQ   27000 /* in kHz */
+
+/* Register values to initialise the demod in DVB-S mode */
+static u8 ds3000_dvbs_init_tab[] = {
+	0x23, 0x05,
+	0x08, 0x03,
+	0x0c, 0x00,
+	0x21, 0x54,
+	0x25, 0x82,
+	0x27, 0x31,
+	0x30, 0x08,
+	0x31, 0x40,
+	0x32, 0x32,
+	0x33, 0x35,
+	0x35, 0xff,
+	0x3a, 0x00,
+	0x37, 0x10,
+	0x38, 0x10,
+	0x39, 0x02,
+	0x42, 0x60,
+	0x4a, 0x40,
+	0x4b, 0x04,
+	0x4d, 0x91,
+	0x5d, 0xc8,
+	0x50, 0x77,
+	0x51, 0x77,
+	0x52, 0x36,
+	0x53, 0x36,
+	0x56, 0x01,
+	0x63, 0x43,
+	0x64, 0x30,
+	0x65, 0x40,
+	0x68, 0x26,
+	0x69, 0x4c,
+	0x70, 0x20,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x40,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x60,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x80,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0xa0,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x1f,
+	0x76, 0x00,
+	0x77, 0xd1,
+	0x78, 0x0c,
+	0x79, 0x80,
+	0x7f, 0x04,
+	0x7c, 0x00,
+	0x80, 0x86,
+	0x81, 0xa6,
+	0x85, 0x04,
+	0xcd, 0xf4,
+	0x90, 0x33,
+	0xa0, 0x44,
+	0xc0, 0x18,
+	0xc3, 0x10,
+	0xc4, 0x08,
+	0xc5, 0x80,
+	0xc6, 0x80,
+	0xc7, 0x0a,
+	0xc8, 0x1a,
+	0xc9, 0x80,
+	0xfe, 0x92,
+	0xe0, 0xf8,
+	0xe6, 0x8b,
+	0xd0, 0x40,
+	0xf8, 0x20,
+	0xfa, 0x0f,
+	0xfd, 0x20,
+	0xad, 0x20,
+	0xae, 0x07,
+	0xb8, 0x00,
+};
+
+/* Register values to initialise the demod in DVB-S2 mode */
+static u8 ds3000_dvbs2_init_tab[] = {
+	0x23, 0x0f,
+	0x08, 0x07,
+	0x0c, 0x00,
+	0x21, 0x54,
+	0x25, 0x82,
+	0x27, 0x31,
+	0x30, 0x08,
+	0x31, 0x32,
+	0x32, 0x32,
+	0x33, 0x35,
+	0x35, 0xff,
+	0x3a, 0x00,
+	0x37, 0x10,
+	0x38, 0x10,
+	0x39, 0x02,
+	0x42, 0x60,
+	0x4a, 0x80,
+	0x4b, 0x04,
+	0x4d, 0x81,
+	0x5d, 0x88,
+	0x50, 0x36,
+	0x51, 0x36,
+	0x52, 0x36,
+	0x53, 0x36,
+	0x63, 0x60,
+	0x64, 0x10,
+	0x65, 0x10,
+	0x68, 0x04,
+	0x69, 0x29,
+	0x70, 0x20,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x40,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x60,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x80,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0xa0,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x1f,
+	0xa0, 0x44,
+	0xc0, 0x08,
+	0xc1, 0x10,
+	0xc2, 0x08,
+	0xc3, 0x10,
+	0xc4, 0x08,
+	0xc5, 0xf0,
+	0xc6, 0xf0,
+	0xc7, 0x0a,
+	0xc8, 0x1a,
+	0xc9, 0x80,
+	0xca, 0x23,
+	0xcb, 0x24,
+	0xce, 0x74,
+	0x90, 0x03,
+	0x76, 0x80,
+	0x77, 0x42,
+	0x78, 0x0a,
+	0x79, 0x80,
+	0xad, 0x40,
+	0xae, 0x07,
+	0x7f, 0xd4,
+	0x7c, 0x00,
+	0x80, 0xa8,
+	0x81, 0xda,
+	0x7c, 0x01,
+	0x80, 0xda,
+	0x81, 0xec,
+	0x7c, 0x02,
+	0x80, 0xca,
+	0x81, 0xeb,
+	0x7c, 0x03,
+	0x80, 0xba,
+	0x81, 0xdb,
+	0x85, 0x08,
+	0x86, 0x00,
+	0x87, 0x02,
+	0x89, 0x80,
+	0x8b, 0x44,
+	0x8c, 0xaa,
+	0x8a, 0x10,
+	0xba, 0x00,
+	0xf5, 0x04,
+	0xfe, 0x44,
+	0xd2, 0x32,
+	0xb8, 0x00,
+};
+
+struct ds3000_state {
+	struct i2c_adapter *i2c;
+	const struct ds3000_config *config;
+	struct dvb_frontend frontend;
+	u8 skip_fw_load;
+	/* previous uncorrected block counter for DVB-S2 */
+	u16 prevUCBS2;
+};
+
+static int ds3000_writereg(struct ds3000_state *state, int reg, int data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address,
+		.flags = 0, .buf = buf, .len = 2 };
+	int err;
+
+	dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data);
+
+	err = i2c_transfer(state->i2c, &msg, 1);
+	if (err != 1) {
+		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
+			 " value == 0x%02x)\n", __func__, err, reg, data);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int ds3000_tuner_writereg(struct ds3000_state *state, int reg, int data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = 0x60,
+		.flags = 0, .buf = buf, .len = 2 };
+	int err;
+
+	dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data);
+
+	ds3000_writereg(state, 0x03, 0x11);
+	err = i2c_transfer(state->i2c, &msg, 1);
+	if (err != 1) {
+		printk("%s: writereg error(err == %i, reg == 0x%02x,"
+			 " value == 0x%02x)\n", __func__, err, reg, data);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+/* I2C write for 8k firmware load */
+static int ds3000_writeFW(struct ds3000_state *state, int reg,
+				const u8 *data, u16 len)
+{
+	int i, ret = -EREMOTEIO;
+	struct i2c_msg msg;
+	u8 *buf;
+
+	buf = kmalloc(33, GFP_KERNEL);
+	if (buf == NULL) {
+		printk(KERN_ERR "Unable to kmalloc\n");
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	*(buf) = reg;
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.buf = buf;
+	msg.len = 33;
+
+	for (i = 0; i < len; i += 32) {
+		memcpy(buf + 1, data + i, 32);
+
+		dprintk("%s: write reg 0x%02x, len = %d\n", __func__, reg, len);
+
+		ret = i2c_transfer(state->i2c, &msg, 1);
+		if (ret != 1) {
+			printk(KERN_ERR "%s: write error(err == %i, "
+				"reg == 0x%02x\n", __func__, ret, reg);
+			ret = -EREMOTEIO;
+		}
+	}
+
+error:
+	kfree(buf);
+
+	return ret;
+}
+
+static int ds3000_readreg(struct ds3000_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{
+			.addr = state->config->demod_address,
+			.flags = 0,
+			.buf = b0,
+			.len = 1
+		}, {
+			.addr = state->config->demod_address,
+			.flags = I2C_M_RD,
+			.buf = b1,
+			.len = 1
+		}
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
+		return ret;
+	}
+
+	dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]);
+
+	return b1[0];
+}
+
+static int ds3000_tuner_readreg(struct ds3000_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{
+			.addr = 0x60,
+			.flags = 0,
+			.buf = b0,
+			.len = 1
+		}, {
+			.addr = 0x60,
+			.flags = I2C_M_RD,
+			.buf = b1,
+			.len = 1
+		}
+	};
+
+	ds3000_writereg(state, 0x03, 0x12);
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
+		return ret;
+	}
+
+	dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]);
+
+	return b1[0];
+}
+
+static int ds3000_load_firmware(struct dvb_frontend *fe,
+					const struct firmware *fw);
+
+static int ds3000_firmware_ondemand(struct dvb_frontend *fe)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	const struct firmware *fw;
+	int ret = 0;
+
+	dprintk("%s()\n", __func__);
+
+	if (ds3000_readreg(state, 0xb2) <= 0)
+		return ret;
+
+	if (state->skip_fw_load)
+		return 0;
+	/* Load firmware */
+	/* request the firmware, this will block until someone uploads it */
+	printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
+				DS3000_DEFAULT_FIRMWARE);
+	ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE,
+				state->i2c->dev.parent);
+	printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__);
+	if (ret) {
+		printk(KERN_ERR "%s: No firmware uploaded (timeout or file not "
+				"found?)\n", __func__);
+		return ret;
+	}
+
+	/* Make sure we don't recurse back through here during loading */
+	state->skip_fw_load = 1;
+
+	ret = ds3000_load_firmware(fe, fw);
+	if (ret)
+		printk("%s: Writing firmware to device failed\n", __func__);
+
+	release_firmware(fw);
+
+	dprintk("%s: Firmware upload %s\n", __func__,
+			ret == 0 ? "complete" : "failed");
+
+	/* Ensure firmware is always loaded if required */
+	state->skip_fw_load = 0;
+
+	return ret;
+}
+
+static int ds3000_load_firmware(struct dvb_frontend *fe,
+					const struct firmware *fw)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+	dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
+			fw->size,
+			fw->data[0],
+			fw->data[1],
+			fw->data[fw->size - 2],
+			fw->data[fw->size - 1]);
+
+	/* Begin the firmware load process */
+	ds3000_writereg(state, 0xb2, 0x01);
+	/* write the entire firmware */
+	ds3000_writeFW(state, 0xb0, fw->data, fw->size);
+	ds3000_writereg(state, 0xb2, 0x00);
+
+	return 0;
+}
+
+static int ds3000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	u8 data;
+
+	dprintk("%s(%d)\n", __func__, voltage);
+
+	data = ds3000_readreg(state, 0xa2);
+	data |= 0x03; /* bit0 V/H, bit1 off/on */
+
+	switch (voltage) {
+	case SEC_VOLTAGE_18:
+		data &= ~0x03;
+		break;
+	case SEC_VOLTAGE_13:
+		data &= ~0x03;
+		data |= 0x01;
+		break;
+	case SEC_VOLTAGE_OFF:
+		break;
+	}
+
+	ds3000_writereg(state, 0xa2, data);
+
+	return 0;
+}
+
+static int ds3000_read_status(struct dvb_frontend *fe, fe_status_t* status)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int lock;
+
+	*status = 0;
+
+	switch (c->delivery_system) {
+	case SYS_DVBS:
+		lock = ds3000_readreg(state, 0xd1);
+		if ((lock & 0x07) == 0x07)
+			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI | FE_HAS_SYNC |
+				FE_HAS_LOCK;
+
+		break;
+	case SYS_DVBS2:
+		lock = ds3000_readreg(state, 0x0d);
+		if ((lock & 0x8f) == 0x8f)
+			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI | FE_HAS_SYNC |
+				FE_HAS_LOCK;
+
+		break;
+	default:
+		return 1;
+	}
+
+	dprintk("%s: status = 0x%02x\n", __func__, lock);
+
+	return 0;
+}
+
+/* read DS3000 BER value */
+static int ds3000_read_ber(struct dvb_frontend *fe, u32* ber)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u8 data;
+	u32 ber_reading, lpdc_frames;
+
+	dprintk("%s()\n", __func__);
+
+	switch (c->delivery_system) {
+	case SYS_DVBS:
+		/* set the number of bytes checked during
+		BER estimation */
+		ds3000_writereg(state, 0xf9, 0x04);
+		/* read BER estimation status */
+		data = ds3000_readreg(state, 0xf8);
+		/* check if BER estimation is ready */
+		if ((data & 0x10) == 0) {
+			/* this is the number of error bits,
+			to calculate the bit error rate
+			divide to 8388608 */
+			*ber = (ds3000_readreg(state, 0xf7) << 8) |
+				ds3000_readreg(state, 0xf6);
+			/* start counting error bits */
+			/* need to be set twice
+			otherwise it fails sometimes */
+			data |= 0x10;
+			ds3000_writereg(state, 0xf8, data);
+			ds3000_writereg(state, 0xf8, data);
+		} else
+			/* used to indicate that BER estimation
+			is not ready, i.e. BER is unknown */
+			*ber = 0xffffffff;
+		break;
+	case SYS_DVBS2:
+		/* read the number of LPDC decoded frames */
+		lpdc_frames = (ds3000_readreg(state, 0xd7) << 16) |
+				(ds3000_readreg(state, 0xd6) << 8) |
+				ds3000_readreg(state, 0xd5);
+		/* read the number of packets with bad CRC */
+		ber_reading = (ds3000_readreg(state, 0xf8) << 8) |
+				ds3000_readreg(state, 0xf7);
+		if (lpdc_frames > 750) {
+			/* clear LPDC frame counters */
+			ds3000_writereg(state, 0xd1, 0x01);
+			/* clear bad packets counter */
+			ds3000_writereg(state, 0xf9, 0x01);
+			/* enable bad packets counter */
+			ds3000_writereg(state, 0xf9, 0x00);
+			/* enable LPDC frame counters */
+			ds3000_writereg(state, 0xd1, 0x00);
+			*ber = ber_reading;
+		} else
+			/* used to indicate that BER estimation is not ready,
+			i.e. BER is unknown */
+			*ber = 0xffffffff;
+		break;
+	default:
+		return 1;
+	}
+
+	return 0;
+}
+
+/* read TS2020 signal strength */
+static int ds3000_read_signal_strength(struct dvb_frontend *fe,
+						u16 *signal_strength)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	u16 sig_reading, sig_strength;
+	u8 rfgain, bbgain;
+
+	dprintk("%s()\n", __func__);
+
+	rfgain = ds3000_tuner_readreg(state, 0x3d) & 0x1f;
+	bbgain = ds3000_tuner_readreg(state, 0x21) & 0x1f;
+
+	if (rfgain > 15)
+		rfgain = 15;
+	if (bbgain > 13)
+		bbgain = 13;
+
+	sig_reading = rfgain * 2 + bbgain * 3;
+
+	sig_strength = 40 + (64 - sig_reading) * 50 / 64 ;
+
+	/* cook the value to be suitable for szap-s2 human readable output */
+	*signal_strength = sig_strength * 1000;
+
+	dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__,
+			sig_reading, *signal_strength);
+
+	return 0;
+}
+
+/* calculate DS3000 snr value in dB */
+static int ds3000_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u8 snr_reading, snr_value;
+	u32 dvbs2_signal_reading, dvbs2_noise_reading, tmp;
+	static const u16 dvbs_snr_tab[] = { /* 20 x Table (rounded up) */
+		0x0000, 0x1b13, 0x2aea, 0x3627, 0x3ede, 0x45fe, 0x4c03,
+		0x513a, 0x55d4, 0x59f2, 0x5dab, 0x6111, 0x6431, 0x6717,
+		0x69c9, 0x6c4e, 0x6eac, 0x70e8, 0x7304, 0x7505
+	};
+	static const u16 dvbs2_snr_tab[] = { /* 80 x Table (rounded up) */
+		0x0000, 0x0bc2, 0x12a3, 0x1785, 0x1b4e, 0x1e65, 0x2103,
+		0x2347, 0x2546, 0x2710, 0x28ae, 0x2a28, 0x2b83, 0x2cc5,
+		0x2df1, 0x2f09, 0x3010, 0x3109, 0x31f4, 0x32d2, 0x33a6,
+		0x3470, 0x3531, 0x35ea, 0x369b, 0x3746, 0x37ea, 0x3888,
+		0x3920, 0x39b3, 0x3a42, 0x3acc, 0x3b51, 0x3bd3, 0x3c51,
+		0x3ccb, 0x3d42, 0x3db6, 0x3e27, 0x3e95, 0x3f00, 0x3f68,
+		0x3fcf, 0x4033, 0x4094, 0x40f4, 0x4151, 0x41ac, 0x4206,
+		0x425e, 0x42b4, 0x4308, 0x435b, 0x43ac, 0x43fc, 0x444a,
+		0x4497, 0x44e2, 0x452d, 0x4576, 0x45bd, 0x4604, 0x4649,
+		0x468e, 0x46d1, 0x4713, 0x4755, 0x4795, 0x47d4, 0x4813,
+		0x4851, 0x488d, 0x48c9, 0x4904, 0x493f, 0x4978, 0x49b1,
+		0x49e9, 0x4a20, 0x4a57
+	};
+
+	dprintk("%s()\n", __func__);
+
+	switch (c->delivery_system) {
+	case SYS_DVBS:
+		snr_reading = ds3000_readreg(state, 0xff);
+		snr_reading /= 8;
+		if (snr_reading == 0)
+			*snr = 0x0000;
+		else {
+			if (snr_reading > 20)
+				snr_reading = 20;
+			snr_value = dvbs_snr_tab[snr_reading - 1] * 10 / 23026;
+			/* cook the value to be suitable for szap-s2
+			human readable output */
+			*snr = snr_value * 8 * 655;
+		}
+		dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
+				snr_reading, *snr);
+		break;
+	case SYS_DVBS2:
+		dvbs2_noise_reading = (ds3000_readreg(state, 0x8c) & 0x3f) +
+				(ds3000_readreg(state, 0x8d) << 4);
+		dvbs2_signal_reading = ds3000_readreg(state, 0x8e);
+		tmp = dvbs2_signal_reading * dvbs2_signal_reading >> 1;
+		if (tmp == 0) {
+			*snr = 0x0000;
+			return 0;
+		}
+		if (dvbs2_noise_reading == 0) {
+			snr_value = 0x0013;
+			/* cook the value to be suitable for szap-s2
+			human readable output */
+			*snr = 0xffff;
+			return 0;
+		}
+		if (tmp > dvbs2_noise_reading) {
+			snr_reading = tmp / dvbs2_noise_reading;
+			if (snr_reading > 80)
+				snr_reading = 80;
+			snr_value = dvbs2_snr_tab[snr_reading - 1] / 1000;
+			/* cook the value to be suitable for szap-s2
+			human readable output */
+			*snr = snr_value * 5 * 655;
+		} else {
+			snr_reading = dvbs2_noise_reading / tmp;
+			if (snr_reading > 80)
+				snr_reading = 80;
+			*snr = -(dvbs2_snr_tab[snr_reading] / 1000);
+		}
+		dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
+				snr_reading, *snr);
+		break;
+	default:
+		return 1;
+	}
+
+	return 0;
+}
+
+/* read DS3000 uncorrected blocks */
+static int ds3000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u8 data;
+	u16 _ucblocks;
+
+	dprintk("%s()\n", __func__);
+
+	switch (c->delivery_system) {
+	case SYS_DVBS:
+		*ucblocks = (ds3000_readreg(state, 0xf5) << 8) |
+				ds3000_readreg(state, 0xf4);
+		data = ds3000_readreg(state, 0xf8);
+		/* clear packet counters */
+		data &= ~0x20;
+		ds3000_writereg(state, 0xf8, data);
+		/* enable packet counters */
+		data |= 0x20;
+		ds3000_writereg(state, 0xf8, data);
+		break;
+	case SYS_DVBS2:
+		_ucblocks = (ds3000_readreg(state, 0xe2) << 8) |
+				ds3000_readreg(state, 0xe1);
+		if (_ucblocks > state->prevUCBS2)
+			*ucblocks = _ucblocks - state->prevUCBS2;
+		else
+			*ucblocks = state->prevUCBS2 - _ucblocks;
+		state->prevUCBS2 = _ucblocks;
+		break;
+	default:
+		return 1;
+	}
+
+	return 0;
+}
+
+static int ds3000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	u8 data;
+
+	dprintk("%s(%d)\n", __func__, tone);
+	if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
+		printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
+		return -EINVAL;
+	}
+
+	data = ds3000_readreg(state, 0xa2);
+	data &= ~0xc0;
+	ds3000_writereg(state, 0xa2, data);
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		dprintk("%s: setting tone on\n", __func__);
+		data = ds3000_readreg(state, 0xa1);
+		data &= ~0x43;
+		data |= 0x04;
+		ds3000_writereg(state, 0xa1, data);
+		break;
+	case SEC_TONE_OFF:
+		dprintk("%s: setting tone off\n", __func__);
+		data = ds3000_readreg(state, 0xa2);
+		data |= 0x80;
+		ds3000_writereg(state, 0xa2, data);
+		break;
+	}
+
+	return 0;
+}
+
+static int ds3000_send_diseqc_msg(struct dvb_frontend *fe,
+				struct dvb_diseqc_master_cmd *d)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	int i;
+	u8 data;
+
+	/* Dump DiSEqC message */
+	dprintk("%s(", __func__);
+	for (i = 0 ; i < d->msg_len;) {
+		dprintk("0x%02x", d->msg[i]);
+		if (++i < d->msg_len)
+			dprintk(", ");
+	}
+
+	/* enable DiSEqC message send pin */
+	data = ds3000_readreg(state, 0xa2);
+	data &= ~0xc0;
+	ds3000_writereg(state, 0xa2, data);
+
+	/* DiSEqC message */
+	for (i = 0; i < d->msg_len; i++)
+		ds3000_writereg(state, 0xa3 + i, d->msg[i]);
+
+	data = ds3000_readreg(state, 0xa1);
+	/* clear DiSEqC message length and status,
+	enable DiSEqC message send */
+	data &= ~0xf8;
+	/* set DiSEqC mode, modulation active during 33 pulses,
+	set DiSEqC message length */
+	data |= ((d->msg_len - 1) << 3) | 0x07;
+	ds3000_writereg(state, 0xa1, data);
+
+	/* wait up to 150ms for DiSEqC transmission to complete */
+	for (i = 0; i < 15; i++) {
+		data = ds3000_readreg(state, 0xa1);
+		if ((data & 0x40) == 0)
+			break;
+		msleep(10);
+	}
+
+	/* DiSEqC timeout after 150ms */
+	if (i == 15) {
+		data = ds3000_readreg(state, 0xa1);
+		data &= ~0x80;
+		data |= 0x40;
+		ds3000_writereg(state, 0xa1, data);
+
+		data = ds3000_readreg(state, 0xa2);
+		data &= ~0xc0;
+		data |= 0x80;
+		ds3000_writereg(state, 0xa2, data);
+
+		return 1;
+	}
+
+	data = ds3000_readreg(state, 0xa2);
+	data &= ~0xc0;
+	data |= 0x80;
+	ds3000_writereg(state, 0xa2, data);
+
+	return 0;
+}
+
+/* Send DiSEqC burst */
+static int ds3000_diseqc_send_burst(struct dvb_frontend *fe,
+					fe_sec_mini_cmd_t burst)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	int i;
+	u8 data;
+
+	dprintk("%s()\n", __func__);
+
+	data = ds3000_readreg(state, 0xa2);
+	data &= ~0xc0;
+	ds3000_writereg(state, 0xa2, data);
+
+	/* DiSEqC burst */
+	if (burst == SEC_MINI_A)
+		/* Unmodulated tone burst */
+		ds3000_writereg(state, 0xa1, 0x02);
+	else if (burst == SEC_MINI_B)
+		/* Modulated tone burst */
+		ds3000_writereg(state, 0xa1, 0x01);
+	else
+		return -EINVAL;
+
+	msleep(13);
+	for (i = 0; i < 5; i++) {
+		data = ds3000_readreg(state, 0xa1);
+		if ((data & 0x40) == 0)
+			break;
+		msleep(1);
+	}
+
+	if (i == 5) {
+		data = ds3000_readreg(state, 0xa1);
+		data &= ~0x80;
+		data |= 0x40;
+		ds3000_writereg(state, 0xa1, data);
+
+		data = ds3000_readreg(state, 0xa2);
+		data &= ~0xc0;
+		data |= 0x80;
+		ds3000_writereg(state, 0xa2, data);
+
+		return 1;
+	}
+
+	data = ds3000_readreg(state, 0xa2);
+	data &= ~0xc0;
+	data |= 0x80;
+	ds3000_writereg(state, 0xa2, data);
+
+	return 0;
+}
+
+static void ds3000_release(struct dvb_frontend *fe)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	dprintk("%s\n", __func__);
+	kfree(state);
+}
+
+static struct dvb_frontend_ops ds3000_ops;
+
+struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct ds3000_state *state = NULL;
+	int ret;
+
+	dprintk("%s\n", __func__);
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct ds3000_state), GFP_KERNEL);
+	if (state == NULL) {
+		printk(KERN_ERR "Unable to kmalloc\n");
+		goto error2;
+	}
+
+	state->config = config;
+	state->i2c = i2c;
+	state->prevUCBS2 = 0;
+
+	/* check if the demod is present */
+	ret = ds3000_readreg(state, 0x00) & 0xfe;
+	if (ret != 0xe0) {
+		printk(KERN_ERR "Invalid probe, probably not a DS3000\n");
+		goto error3;
+	}
+
+	printk(KERN_INFO "DS3000 chip version: %d.%d attached.\n",
+			ds3000_readreg(state, 0x02),
+			ds3000_readreg(state, 0x01));
+
+	memcpy(&state->frontend.ops, &ds3000_ops,
+			sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error3:
+	kfree(state);
+error2:
+	return NULL;
+}
+EXPORT_SYMBOL(ds3000_attach);
+
+static int ds3000_set_carrier_offset(struct dvb_frontend *fe,
+					s32 carrier_offset_khz)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	s32 tmp;
+
+	tmp = carrier_offset_khz;
+	tmp *= 65536;
+	tmp = (2 * tmp + DS3000_SAMPLE_RATE) / (2 * DS3000_SAMPLE_RATE);
+
+	if (tmp < 0)
+		tmp += 65536;
+
+	ds3000_writereg(state, 0x5f, tmp >> 8);
+	ds3000_writereg(state, 0x5e, tmp & 0xff);
+
+	return 0;
+}
+
+static int ds3000_set_frontend(struct dvb_frontend *fe)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+	int i;
+	fe_status_t status;
+	u8 mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf, div4;
+	s32 offset_khz;
+	u16 value, ndiv;
+	u32 f3db;
+
+	dprintk("%s() ", __func__);
+
+	if (state->config->set_ts_params)
+		state->config->set_ts_params(fe, 0);
+	/* Tune */
+	/* unknown */
+	ds3000_tuner_writereg(state, 0x07, 0x02);
+	ds3000_tuner_writereg(state, 0x10, 0x00);
+	ds3000_tuner_writereg(state, 0x60, 0x79);
+	ds3000_tuner_writereg(state, 0x08, 0x01);
+	ds3000_tuner_writereg(state, 0x00, 0x01);
+	div4 = 0;
+
+	/* calculate and set freq divider */
+	if (c->frequency < 1146000) {
+		ds3000_tuner_writereg(state, 0x10, 0x11);
+		div4 = 1;
+		ndiv = ((c->frequency * (6 + 8) * 4) +
+				(DS3000_XTAL_FREQ / 2)) /
+				DS3000_XTAL_FREQ - 1024;
+	} else {
+		ds3000_tuner_writereg(state, 0x10, 0x01);
+		ndiv = ((c->frequency * (6 + 8) * 2) +
+				(DS3000_XTAL_FREQ / 2)) /
+				DS3000_XTAL_FREQ - 1024;
+	}
+
+	ds3000_tuner_writereg(state, 0x01, (ndiv & 0x0f00) >> 8);
+	ds3000_tuner_writereg(state, 0x02, ndiv & 0x00ff);
+
+	/* set pll */
+	ds3000_tuner_writereg(state, 0x03, 0x06);
+	ds3000_tuner_writereg(state, 0x51, 0x0f);
+	ds3000_tuner_writereg(state, 0x51, 0x1f);
+	ds3000_tuner_writereg(state, 0x50, 0x10);
+	ds3000_tuner_writereg(state, 0x50, 0x00);
+	msleep(5);
+
+	/* unknown */
+	ds3000_tuner_writereg(state, 0x51, 0x17);
+	ds3000_tuner_writereg(state, 0x51, 0x1f);
+	ds3000_tuner_writereg(state, 0x50, 0x08);
+	ds3000_tuner_writereg(state, 0x50, 0x00);
+	msleep(5);
+
+	value = ds3000_tuner_readreg(state, 0x3d);
+	value &= 0x0f;
+	if ((value > 4) && (value < 15)) {
+		value -= 3;
+		if (value < 4)
+			value = 4;
+		value = ((value << 3) | 0x01) & 0x79;
+	}
+
+	ds3000_tuner_writereg(state, 0x60, value);
+	ds3000_tuner_writereg(state, 0x51, 0x17);
+	ds3000_tuner_writereg(state, 0x51, 0x1f);
+	ds3000_tuner_writereg(state, 0x50, 0x08);
+	ds3000_tuner_writereg(state, 0x50, 0x00);
+
+	/* set low-pass filter period */
+	ds3000_tuner_writereg(state, 0x04, 0x2e);
+	ds3000_tuner_writereg(state, 0x51, 0x1b);
+	ds3000_tuner_writereg(state, 0x51, 0x1f);
+	ds3000_tuner_writereg(state, 0x50, 0x04);
+	ds3000_tuner_writereg(state, 0x50, 0x00);
+	msleep(5);
+
+	f3db = ((c->symbol_rate / 1000) << 2) / 5 + 2000;
+	if ((c->symbol_rate / 1000) < 5000)
+		f3db += 3000;
+	if (f3db < 7000)
+		f3db = 7000;
+	if (f3db > 40000)
+		f3db = 40000;
+
+	/* set low-pass filter baseband */
+	value = ds3000_tuner_readreg(state, 0x26);
+	mlpf = 0x2e * 207 / ((value << 1) + 151);
+	mlpf_max = mlpf * 135 / 100;
+	mlpf_min = mlpf * 78 / 100;
+	if (mlpf_max > 63)
+		mlpf_max = 63;
+
+	/* rounded to the closest integer */
+	nlpf = ((mlpf * f3db * 1000) + (2766 * DS3000_XTAL_FREQ / 2))
+			/ (2766 * DS3000_XTAL_FREQ);
+	if (nlpf > 23)
+		nlpf = 23;
+	if (nlpf < 1)
+		nlpf = 1;
+
+	/* rounded to the closest integer */
+	mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
+			(1000 * f3db / 2)) / (1000 * f3db);
+
+	if (mlpf_new < mlpf_min) {
+		nlpf++;
+		mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
+				(1000 * f3db / 2)) / (1000 * f3db);
+	}
+
+	if (mlpf_new > mlpf_max)
+		mlpf_new = mlpf_max;
+
+	ds3000_tuner_writereg(state, 0x04, mlpf_new);
+	ds3000_tuner_writereg(state, 0x06, nlpf);
+	ds3000_tuner_writereg(state, 0x51, 0x1b);
+	ds3000_tuner_writereg(state, 0x51, 0x1f);
+	ds3000_tuner_writereg(state, 0x50, 0x04);
+	ds3000_tuner_writereg(state, 0x50, 0x00);
+	msleep(5);
+
+	/* unknown */
+	ds3000_tuner_writereg(state, 0x51, 0x1e);
+	ds3000_tuner_writereg(state, 0x51, 0x1f);
+	ds3000_tuner_writereg(state, 0x50, 0x01);
+	ds3000_tuner_writereg(state, 0x50, 0x00);
+	msleep(60);
+
+	offset_khz = (ndiv - ndiv % 2 + 1024) * DS3000_XTAL_FREQ
+		/ (6 + 8) / (div4 + 1) / 2 - c->frequency;
+
+	/* ds3000 global reset */
+	ds3000_writereg(state, 0x07, 0x80);
+	ds3000_writereg(state, 0x07, 0x00);
+	/* ds3000 build-in uC reset */
+	ds3000_writereg(state, 0xb2, 0x01);
+	/* ds3000 software reset */
+	ds3000_writereg(state, 0x00, 0x01);
+
+	switch (c->delivery_system) {
+	case SYS_DVBS:
+		/* initialise the demod in DVB-S mode */
+		for (i = 0; i < sizeof(ds3000_dvbs_init_tab); i += 2)
+			ds3000_writereg(state,
+				ds3000_dvbs_init_tab[i],
+				ds3000_dvbs_init_tab[i + 1]);
+		value = ds3000_readreg(state, 0xfe);
+		value &= 0xc0;
+		value |= 0x1b;
+		ds3000_writereg(state, 0xfe, value);
+		break;
+	case SYS_DVBS2:
+		/* initialise the demod in DVB-S2 mode */
+		for (i = 0; i < sizeof(ds3000_dvbs2_init_tab); i += 2)
+			ds3000_writereg(state,
+				ds3000_dvbs2_init_tab[i],
+				ds3000_dvbs2_init_tab[i + 1]);
+		if (c->symbol_rate >= 30000000)
+			ds3000_writereg(state, 0xfe, 0x54);
+		else
+			ds3000_writereg(state, 0xfe, 0x98);
+		break;
+	default:
+		return 1;
+	}
+
+	/* enable 27MHz clock output */
+	ds3000_writereg(state, 0x29, 0x80);
+	/* enable ac coupling */
+	ds3000_writereg(state, 0x25, 0x8a);
+
+	/* enhance symbol rate performance */
+	if ((c->symbol_rate / 1000) <= 5000) {
+		value = 29777 / (c->symbol_rate / 1000) + 1;
+		if (value % 2 != 0)
+			value++;
+		ds3000_writereg(state, 0xc3, 0x0d);
+		ds3000_writereg(state, 0xc8, value);
+		ds3000_writereg(state, 0xc4, 0x10);
+		ds3000_writereg(state, 0xc7, 0x0e);
+	} else if ((c->symbol_rate / 1000) <= 10000) {
+		value = 92166 / (c->symbol_rate / 1000) + 1;
+		if (value % 2 != 0)
+			value++;
+		ds3000_writereg(state, 0xc3, 0x07);
+		ds3000_writereg(state, 0xc8, value);
+		ds3000_writereg(state, 0xc4, 0x09);
+		ds3000_writereg(state, 0xc7, 0x12);
+	} else if ((c->symbol_rate / 1000) <= 20000) {
+		value = 64516 / (c->symbol_rate / 1000) + 1;
+		ds3000_writereg(state, 0xc3, value);
+		ds3000_writereg(state, 0xc8, 0x0e);
+		ds3000_writereg(state, 0xc4, 0x07);
+		ds3000_writereg(state, 0xc7, 0x18);
+	} else {
+		value = 129032 / (c->symbol_rate / 1000) + 1;
+		ds3000_writereg(state, 0xc3, value);
+		ds3000_writereg(state, 0xc8, 0x0a);
+		ds3000_writereg(state, 0xc4, 0x05);
+		ds3000_writereg(state, 0xc7, 0x24);
+	}
+
+	/* normalized symbol rate rounded to the closest integer */
+	value = (((c->symbol_rate / 1000) << 16) +
+			(DS3000_SAMPLE_RATE / 2)) / DS3000_SAMPLE_RATE;
+	ds3000_writereg(state, 0x61, value & 0x00ff);
+	ds3000_writereg(state, 0x62, (value & 0xff00) >> 8);
+
+	/* co-channel interference cancellation disabled */
+	ds3000_writereg(state, 0x56, 0x00);
+
+	/* equalizer disabled */
+	ds3000_writereg(state, 0x76, 0x00);
+
+	/*ds3000_writereg(state, 0x08, 0x03);
+	ds3000_writereg(state, 0xfd, 0x22);
+	ds3000_writereg(state, 0x08, 0x07);
+	ds3000_writereg(state, 0xfd, 0x42);
+	ds3000_writereg(state, 0x08, 0x07);*/
+
+	if (state->config->ci_mode) {
+		switch (c->delivery_system) {
+		case SYS_DVBS:
+		default:
+			ds3000_writereg(state, 0xfd, 0x80);
+		break;
+		case SYS_DVBS2:
+			ds3000_writereg(state, 0xfd, 0x01);
+			break;
+		}
+	}
+
+	/* ds3000 out of software reset */
+	ds3000_writereg(state, 0x00, 0x00);
+	/* start ds3000 build-in uC */
+	ds3000_writereg(state, 0xb2, 0x00);
+
+	ds3000_set_carrier_offset(fe, offset_khz);
+
+	for (i = 0; i < 30 ; i++) {
+		ds3000_read_status(fe, &status);
+		if (status & FE_HAS_LOCK)
+			break;
+
+		msleep(10);
+	}
+
+	return 0;
+}
+
+static int ds3000_tune(struct dvb_frontend *fe,
+			bool re_tune,
+			unsigned int mode_flags,
+			unsigned int *delay,
+			fe_status_t *status)
+{
+	if (re_tune) {
+		int ret = ds3000_set_frontend(fe);
+		if (ret)
+			return ret;
+	}
+
+	*delay = HZ / 5;
+
+	return ds3000_read_status(fe, status);
+}
+
+static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe)
+{
+	dprintk("%s()\n", __func__);
+	return DVBFE_ALGO_HW;
+}
+
+/*
+ * Initialise or wake up device
+ *
+ * Power config will reset and load initial firmware if required
+ */
+static int ds3000_initfe(struct dvb_frontend *fe)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	int ret;
+
+	dprintk("%s()\n", __func__);
+	/* hard reset */
+	ds3000_writereg(state, 0x08, 0x01 | ds3000_readreg(state, 0x08));
+	msleep(1);
+
+	/* TS2020 init */
+	ds3000_tuner_writereg(state, 0x42, 0x73);
+	ds3000_tuner_writereg(state, 0x05, 0x01);
+	ds3000_tuner_writereg(state, 0x62, 0xf5);
+	/* Load the firmware if required */
+	ret = ds3000_firmware_ondemand(fe);
+	if (ret != 0) {
+		printk(KERN_ERR "%s: Unable initialize firmware\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+/* Put device to sleep */
+static int ds3000_sleep(struct dvb_frontend *fe)
+{
+	dprintk("%s()\n", __func__);
+	return 0;
+}
+
+static struct dvb_frontend_ops ds3000_ops = {
+	.delsys = { SYS_DVBS, SYS_DVBS2},
+	.info = {
+		.name = "Montage Technology DS3000/TS2020",
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		.frequency_stepsize = 1011, /* kHz for QPSK frontends */
+		.frequency_tolerance = 5000,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_2G_MODULATION |
+			FE_CAN_QPSK | FE_CAN_RECOVER
+	},
+
+	.release = ds3000_release,
+
+	.init = ds3000_initfe,
+	.sleep = ds3000_sleep,
+	.read_status = ds3000_read_status,
+	.read_ber = ds3000_read_ber,
+	.read_signal_strength = ds3000_read_signal_strength,
+	.read_snr = ds3000_read_snr,
+	.read_ucblocks = ds3000_read_ucblocks,
+	.set_voltage = ds3000_set_voltage,
+	.set_tone = ds3000_set_tone,
+	.diseqc_send_master_cmd = ds3000_send_diseqc_msg,
+	.diseqc_send_burst = ds3000_diseqc_send_burst,
+	.get_frontend_algo = ds3000_get_algo,
+
+	.set_frontend = ds3000_set_frontend,
+	.tune = ds3000_tune,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+MODULE_DESCRIPTION("DVB Frontend module for Montage Technology "
+			"DS3000/TS2020 hardware");
+MODULE_AUTHOR("Konstantin Dimitrov");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/ds3000.h b/drivers/media/dvb-frontends/ds3000.h
new file mode 100644
index 0000000..1b73688
--- /dev/null
+++ b/drivers/media/dvb-frontends/ds3000.h
@@ -0,0 +1,48 @@
+/*
+    Montage Technology DS3000/TS2020 - DVBS/S2 Satellite demod/tuner driver
+    Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
+
+    Copyright (C) 2009 TurboSight.com
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef DS3000_H
+#define DS3000_H
+
+#include <linux/dvb/frontend.h>
+
+struct ds3000_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+	u8 ci_mode;
+	/* Set device param to start dma */
+	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
+};
+
+#if defined(CONFIG_DVB_DS3000) || \
+			(defined(CONFIG_DVB_DS3000_MODULE) && defined(MODULE))
+extern struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
+					struct i2c_adapter *i2c);
+#else
+static inline
+struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
+					struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_DS3000 */
+#endif /* DS3000_H */
diff --git a/drivers/media/dvb-frontends/dvb-pll.c b/drivers/media/dvb-frontends/dvb-pll.c
new file mode 100644
index 0000000..6d8fe88
--- /dev/null
+++ b/drivers/media/dvb-frontends/dvb-pll.c
@@ -0,0 +1,820 @@
+/*
+ * descriptions + helper functions for simple dvb plls.
+ *
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <asm/types.h>
+
+#include "dvb-pll.h"
+
+struct dvb_pll_priv {
+	/* pll number */
+	int nr;
+
+	/* i2c details */
+	int pll_i2c_address;
+	struct i2c_adapter *i2c;
+
+	/* the PLL descriptor */
+	struct dvb_pll_desc *pll_desc;
+
+	/* cached frequency/bandwidth */
+	u32 frequency;
+	u32 bandwidth;
+};
+
+#define DVB_PLL_MAX 64
+
+static unsigned int dvb_pll_devcount;
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+static unsigned int id[DVB_PLL_MAX] =
+	{ [ 0 ... (DVB_PLL_MAX-1) ] = DVB_PLL_UNDEFINED };
+module_param_array(id, int, NULL, 0644);
+MODULE_PARM_DESC(id, "force pll id to use (DEBUG ONLY)");
+
+/* ----------------------------------------------------------- */
+
+struct dvb_pll_desc {
+	char *name;
+	u32  min;
+	u32  max;
+	u32  iffreq;
+	void (*set)(struct dvb_frontend *fe, u8 *buf);
+	u8   *initdata;
+	u8   *initdata2;
+	u8   *sleepdata;
+	int  count;
+	struct {
+		u32 limit;
+		u32 stepsize;
+		u8  config;
+		u8  cb;
+	} entries[12];
+};
+
+/* ----------------------------------------------------------- */
+/* descriptions                                                */
+
+static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
+	.name  = "Thomson dtt7579",
+	.min   = 177000000,
+	.max   = 858000000,
+	.iffreq= 36166667,
+	.sleepdata = (u8[]){ 2, 0xb4, 0x03 },
+	.count = 4,
+	.entries = {
+		{  443250000, 166667, 0xb4, 0x02 },
+		{  542000000, 166667, 0xb4, 0x08 },
+		{  771000000, 166667, 0xbc, 0x08 },
+		{  999999999, 166667, 0xf4, 0x08 },
+	},
+};
+
+static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf)
+{
+	u32 bw = fe->dtv_property_cache.bandwidth_hz;
+	if (bw == 7000000)
+		buf[3] |= 0x10;
+}
+
+static struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
+	.name  = "Thomson dtt759x",
+	.min   = 177000000,
+	.max   = 896000000,
+	.set   = thomson_dtt759x_bw,
+	.iffreq= 36166667,
+	.sleepdata = (u8[]){ 2, 0x84, 0x03 },
+	.count = 5,
+	.entries = {
+		{  264000000, 166667, 0xb4, 0x02 },
+		{  470000000, 166667, 0xbc, 0x02 },
+		{  735000000, 166667, 0xbc, 0x08 },
+		{  835000000, 166667, 0xf4, 0x08 },
+		{  999999999, 166667, 0xfc, 0x08 },
+	},
+};
+
+static void thomson_dtt7520x_bw(struct dvb_frontend *fe, u8 *buf)
+{
+	u32 bw = fe->dtv_property_cache.bandwidth_hz;
+	if (bw == 8000000)
+		buf[3] ^= 0x10;
+}
+
+static struct dvb_pll_desc dvb_pll_thomson_dtt7520x = {
+	.name  = "Thomson dtt7520x",
+	.min   = 185000000,
+	.max   = 900000000,
+	.set   = thomson_dtt7520x_bw,
+	.iffreq = 36166667,
+	.count = 7,
+	.entries = {
+		{  305000000, 166667, 0xb4, 0x12 },
+		{  405000000, 166667, 0xbc, 0x12 },
+		{  445000000, 166667, 0xbc, 0x12 },
+		{  465000000, 166667, 0xf4, 0x18 },
+		{  735000000, 166667, 0xfc, 0x18 },
+		{  835000000, 166667, 0xbc, 0x18 },
+		{  999999999, 166667, 0xfc, 0x18 },
+	},
+};
+
+static struct dvb_pll_desc dvb_pll_lg_z201 = {
+	.name  = "LG z201",
+	.min   = 174000000,
+	.max   = 862000000,
+	.iffreq= 36166667,
+	.sleepdata = (u8[]){ 2, 0xbc, 0x03 },
+	.count = 5,
+	.entries = {
+		{  157500000, 166667, 0xbc, 0x01 },
+		{  443250000, 166667, 0xbc, 0x02 },
+		{  542000000, 166667, 0xbc, 0x04 },
+		{  830000000, 166667, 0xf4, 0x04 },
+		{  999999999, 166667, 0xfc, 0x04 },
+	},
+};
+
+static struct dvb_pll_desc dvb_pll_unknown_1 = {
+	.name  = "unknown 1", /* used by dntv live dvb-t */
+	.min   = 174000000,
+	.max   = 862000000,
+	.iffreq= 36166667,
+	.count = 9,
+	.entries = {
+		{  150000000, 166667, 0xb4, 0x01 },
+		{  173000000, 166667, 0xbc, 0x01 },
+		{  250000000, 166667, 0xb4, 0x02 },
+		{  400000000, 166667, 0xbc, 0x02 },
+		{  420000000, 166667, 0xf4, 0x02 },
+		{  470000000, 166667, 0xfc, 0x02 },
+		{  600000000, 166667, 0xbc, 0x08 },
+		{  730000000, 166667, 0xf4, 0x08 },
+		{  999999999, 166667, 0xfc, 0x08 },
+	},
+};
+
+/* Infineon TUA6010XS
+ * used in Thomson Cable Tuner
+ */
+static struct dvb_pll_desc dvb_pll_tua6010xs = {
+	.name  = "Infineon TUA6010XS",
+	.min   =  44250000,
+	.max   = 858000000,
+	.iffreq= 36125000,
+	.count = 3,
+	.entries = {
+		{  115750000, 62500, 0x8e, 0x03 },
+		{  403250000, 62500, 0x8e, 0x06 },
+		{  999999999, 62500, 0x8e, 0x85 },
+	},
+};
+
+/* Panasonic env57h1xd5 (some Philips PLL ?) */
+static struct dvb_pll_desc dvb_pll_env57h1xd5 = {
+	.name  = "Panasonic ENV57H1XD5",
+	.min   =  44250000,
+	.max   = 858000000,
+	.iffreq= 36125000,
+	.count = 4,
+	.entries = {
+		{  153000000, 166667, 0xc2, 0x41 },
+		{  470000000, 166667, 0xc2, 0x42 },
+		{  526000000, 166667, 0xc2, 0x84 },
+		{  999999999, 166667, 0xc2, 0xa4 },
+	},
+};
+
+/* Philips TDA6650/TDA6651
+ * used in Panasonic ENV77H11D5
+ */
+static void tda665x_bw(struct dvb_frontend *fe, u8 *buf)
+{
+	u32 bw = fe->dtv_property_cache.bandwidth_hz;
+	if (bw == 8000000)
+		buf[3] |= 0x08;
+}
+
+static struct dvb_pll_desc dvb_pll_tda665x = {
+	.name  = "Philips TDA6650/TDA6651",
+	.min   =  44250000,
+	.max   = 858000000,
+	.set   = tda665x_bw,
+	.iffreq= 36166667,
+	.initdata = (u8[]){ 4, 0x0b, 0xf5, 0x85, 0xab },
+	.count = 12,
+	.entries = {
+		{   93834000, 166667, 0xca, 0x61 /* 011 0 0 0  01 */ },
+		{  123834000, 166667, 0xca, 0xa1 /* 101 0 0 0  01 */ },
+		{  161000000, 166667, 0xca, 0xa1 /* 101 0 0 0  01 */ },
+		{  163834000, 166667, 0xca, 0xc2 /* 110 0 0 0  10 */ },
+		{  253834000, 166667, 0xca, 0x62 /* 011 0 0 0  10 */ },
+		{  383834000, 166667, 0xca, 0xa2 /* 101 0 0 0  10 */ },
+		{  443834000, 166667, 0xca, 0xc2 /* 110 0 0 0  10 */ },
+		{  444000000, 166667, 0xca, 0xc4 /* 110 0 0 1  00 */ },
+		{  583834000, 166667, 0xca, 0x64 /* 011 0 0 1  00 */ },
+		{  793834000, 166667, 0xca, 0xa4 /* 101 0 0 1  00 */ },
+		{  444834000, 166667, 0xca, 0xc4 /* 110 0 0 1  00 */ },
+		{  861000000, 166667, 0xca, 0xe4 /* 111 0 0 1  00 */ },
+	}
+};
+
+/* Infineon TUA6034
+ * used in LG TDTP E102P
+ */
+static void tua6034_bw(struct dvb_frontend *fe, u8 *buf)
+{
+	u32 bw = fe->dtv_property_cache.bandwidth_hz;
+	if (bw == 7000000)
+		buf[3] |= 0x08;
+}
+
+static struct dvb_pll_desc dvb_pll_tua6034 = {
+	.name  = "Infineon TUA6034",
+	.min   =  44250000,
+	.max   = 858000000,
+	.iffreq= 36166667,
+	.count = 3,
+	.set   = tua6034_bw,
+	.entries = {
+		{  174500000, 62500, 0xce, 0x01 },
+		{  230000000, 62500, 0xce, 0x02 },
+		{  999999999, 62500, 0xce, 0x04 },
+	},
+};
+
+/* ALPS TDED4
+ * used in Nebula-Cards and USB boxes
+ */
+static void tded4_bw(struct dvb_frontend *fe, u8 *buf)
+{
+	u32 bw = fe->dtv_property_cache.bandwidth_hz;
+	if (bw == 8000000)
+		buf[3] |= 0x04;
+}
+
+static struct dvb_pll_desc dvb_pll_tded4 = {
+	.name = "ALPS TDED4",
+	.min = 47000000,
+	.max = 863000000,
+	.iffreq= 36166667,
+	.set   = tded4_bw,
+	.count = 4,
+	.entries = {
+		{ 153000000, 166667, 0x85, 0x01 },
+		{ 470000000, 166667, 0x85, 0x02 },
+		{ 823000000, 166667, 0x85, 0x08 },
+		{ 999999999, 166667, 0x85, 0x88 },
+	}
+};
+
+/* ALPS TDHU2
+ * used in AverTVHD MCE A180
+ */
+static struct dvb_pll_desc dvb_pll_tdhu2 = {
+	.name = "ALPS TDHU2",
+	.min = 54000000,
+	.max = 864000000,
+	.iffreq= 44000000,
+	.count = 4,
+	.entries = {
+		{ 162000000, 62500, 0x85, 0x01 },
+		{ 426000000, 62500, 0x85, 0x02 },
+		{ 782000000, 62500, 0x85, 0x08 },
+		{ 999999999, 62500, 0x85, 0x88 },
+	}
+};
+
+/* Samsung TBMV30111IN / TBMV30712IN1
+ * used in Air2PC ATSC - 2nd generation (nxt2002)
+ */
+static struct dvb_pll_desc dvb_pll_samsung_tbmv = {
+	.name = "Samsung TBMV30111IN / TBMV30712IN1",
+	.min = 54000000,
+	.max = 860000000,
+	.iffreq= 44000000,
+	.count = 6,
+	.entries = {
+		{ 172000000, 166667, 0xb4, 0x01 },
+		{ 214000000, 166667, 0xb4, 0x02 },
+		{ 467000000, 166667, 0xbc, 0x02 },
+		{ 721000000, 166667, 0xbc, 0x08 },
+		{ 841000000, 166667, 0xf4, 0x08 },
+		{ 999999999, 166667, 0xfc, 0x02 },
+	}
+};
+
+/*
+ * Philips SD1878 Tuner.
+ */
+static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
+	.name  = "Philips SD1878",
+	.min   =  950000,
+	.max   = 2150000,
+	.iffreq= 249, /* zero-IF, offset 249 is to round up */
+	.count = 4,
+	.entries = {
+		{ 1250000, 500, 0xc4, 0x00},
+		{ 1450000, 500, 0xc4, 0x40},
+		{ 2050000, 500, 0xc4, 0x80},
+		{ 2150000, 500, 0xc4, 0xc0},
+	},
+};
+
+static void opera1_bw(struct dvb_frontend *fe, u8 *buf)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	u32 b_w  = (c->symbol_rate * 27) / 32000;
+	struct i2c_msg msg = {
+		.addr = priv->pll_i2c_address,
+		.flags = 0,
+		.buf = buf,
+		.len = 4
+	};
+	int result;
+	u8 lpf;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	result = i2c_transfer(priv->i2c, &msg, 1);
+	if (result != 1)
+		printk(KERN_ERR "%s: i2c_transfer failed:%d",
+			__func__, result);
+
+	if (b_w <= 10000)
+		lpf = 0xc;
+	else if (b_w <= 12000)
+		lpf = 0x2;
+	else if (b_w <= 14000)
+		lpf = 0xa;
+	else if (b_w <= 16000)
+		lpf = 0x6;
+	else if (b_w <= 18000)
+		lpf = 0xe;
+	else if (b_w <= 20000)
+		lpf = 0x1;
+	else if (b_w <= 22000)
+		lpf = 0x9;
+	else if (b_w <= 24000)
+		lpf = 0x5;
+	else if (b_w <= 26000)
+		lpf = 0xd;
+	else if (b_w <= 28000)
+		lpf = 0x3;
+		else
+		lpf = 0xb;
+	buf[2] ^= 0x1c; /* Flip bits 3-5 */
+	/* Set lpf */
+	buf[2] |= ((lpf >> 2) & 0x3) << 3;
+	buf[3] |= (lpf & 0x3) << 2;
+
+	return;
+}
+
+static struct dvb_pll_desc dvb_pll_opera1 = {
+	.name  = "Opera Tuner",
+	.min   =  900000,
+	.max   = 2250000,
+	.initdata = (u8[]){ 4, 0x08, 0xe5, 0xe1, 0x00 },
+	.initdata2 = (u8[]){ 4, 0x08, 0xe5, 0xe5, 0x00 },
+	.iffreq= 0,
+	.set   = opera1_bw,
+	.count = 8,
+	.entries = {
+		{ 1064000, 500, 0xf9, 0xc2 },
+		{ 1169000, 500, 0xf9, 0xe2 },
+		{ 1299000, 500, 0xf9, 0x20 },
+		{ 1444000, 500, 0xf9, 0x40 },
+		{ 1606000, 500, 0xf9, 0x60 },
+		{ 1777000, 500, 0xf9, 0x80 },
+		{ 1941000, 500, 0xf9, 0xa0 },
+		{ 2250000, 500, 0xf9, 0xc0 },
+	}
+};
+
+static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	struct i2c_msg msg = {
+		.addr = priv->pll_i2c_address,
+		.flags = 0,
+		.buf = buf,
+		.len = 4
+	};
+	int result;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	result = i2c_transfer(priv->i2c, &msg, 1);
+	if (result != 1)
+		printk(KERN_ERR "%s: i2c_transfer failed:%d",
+			__func__, result);
+
+	buf[2] = 0x9e;
+	buf[3] = 0x90;
+
+	return;
+}
+
+/* unknown pll used in Samsung DTOS403IH102A DVB-C tuner */
+static struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = {
+	.name   = "Samsung DTOS403IH102A",
+	.min    =  44250000,
+	.max    = 858000000,
+	.iffreq =  36125000,
+	.count  = 8,
+	.set    = samsung_dtos403ih102a_set,
+	.entries = {
+		{ 135000000, 62500, 0xbe, 0x01 },
+		{ 177000000, 62500, 0xf6, 0x01 },
+		{ 370000000, 62500, 0xbe, 0x02 },
+		{ 450000000, 62500, 0xf6, 0x02 },
+		{ 466000000, 62500, 0xfe, 0x02 },
+		{ 538000000, 62500, 0xbe, 0x08 },
+		{ 826000000, 62500, 0xf6, 0x08 },
+		{ 999999999, 62500, 0xfe, 0x08 },
+	}
+};
+
+/* Samsung TDTC9251DH0 DVB-T NIM, as used on AirStar 2 */
+static struct dvb_pll_desc dvb_pll_samsung_tdtc9251dh0 = {
+	.name	= "Samsung TDTC9251DH0",
+	.min	=  48000000,
+	.max	= 863000000,
+	.iffreq	=  36166667,
+	.count	= 3,
+	.entries = {
+		{ 157500000, 166667, 0xcc, 0x09 },
+		{ 443000000, 166667, 0xcc, 0x0a },
+		{ 863000000, 166667, 0xcc, 0x08 },
+	}
+};
+
+/* Samsung TBDU18132 DVB-S NIM with TSA5059 PLL, used in SkyStar2 DVB-S 2.3 */
+static struct dvb_pll_desc dvb_pll_samsung_tbdu18132 = {
+	.name = "Samsung TBDU18132",
+	.min	=  950000,
+	.max	= 2150000, /* guesses */
+	.iffreq = 0,
+	.count = 2,
+	.entries = {
+		{ 1550000, 125, 0x84, 0x82 },
+		{ 4095937, 125, 0x84, 0x80 },
+	}
+	/* TSA5059 PLL has a 17 bit divisor rather than the 15 bits supported
+	 * by this driver.  The two extra bits are 0x60 in the third byte.  15
+	 * bits is enough for over 4 GHz, which is enough to cover the range
+	 * of this tuner.  We could use the additional divisor bits by adding
+	 * more entries, e.g.
+	 { 0x0ffff * 125 + 125/2, 125, 0x84 | 0x20, },
+	 { 0x17fff * 125 + 125/2, 125, 0x84 | 0x40, },
+	 { 0x1ffff * 125 + 125/2, 125, 0x84 | 0x60, }, */
+};
+
+/* Samsung TBMU24112 DVB-S NIM with SL1935 zero-IF tuner */
+static struct dvb_pll_desc dvb_pll_samsung_tbmu24112 = {
+	.name = "Samsung TBMU24112",
+	.min	=  950000,
+	.max	= 2150000, /* guesses */
+	.iffreq = 0,
+	.count = 2,
+	.entries = {
+		{ 1500000, 125, 0x84, 0x18 },
+		{ 9999999, 125, 0x84, 0x08 },
+	}
+};
+
+/* Alps TDEE4 DVB-C NIM, used on Cablestar 2 */
+/* byte 4 : 1  *   *   AGD R3  R2  R1  R0
+ * byte 5 : C1 *   RE  RTS BS4 BS3 BS2 BS1
+ * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95
+ * Range(MHz)  C1 *  RE RTS BS4 BS3 BS2 BS1  Byte 5
+ *  47 - 153   0  *  0   0   0   0   0   1   0x01
+ * 153 - 430   0  *  0   0   0   0   1   0   0x02
+ * 430 - 822   0  *  0   0   1   0   0   0   0x08
+ * 822 - 862   1  *  0   0   1   0   0   0   0x88 */
+static struct dvb_pll_desc dvb_pll_alps_tdee4 = {
+	.name = "ALPS TDEE4",
+	.min	=  47000000,
+	.max	= 862000000,
+	.iffreq	=  36125000,
+	.count = 4,
+	.entries = {
+		{ 153000000, 62500, 0x95, 0x01 },
+		{ 430000000, 62500, 0x95, 0x02 },
+		{ 822000000, 62500, 0x95, 0x08 },
+		{ 999999999, 62500, 0x95, 0x88 },
+	}
+};
+
+/* ----------------------------------------------------------- */
+
+static struct dvb_pll_desc *pll_list[] = {
+	[DVB_PLL_UNDEFINED]              = NULL,
+	[DVB_PLL_THOMSON_DTT7579]        = &dvb_pll_thomson_dtt7579,
+	[DVB_PLL_THOMSON_DTT759X]        = &dvb_pll_thomson_dtt759x,
+	[DVB_PLL_THOMSON_DTT7520X]       = &dvb_pll_thomson_dtt7520x,
+	[DVB_PLL_LG_Z201]                = &dvb_pll_lg_z201,
+	[DVB_PLL_UNKNOWN_1]              = &dvb_pll_unknown_1,
+	[DVB_PLL_TUA6010XS]              = &dvb_pll_tua6010xs,
+	[DVB_PLL_ENV57H1XD5]             = &dvb_pll_env57h1xd5,
+	[DVB_PLL_TUA6034]                = &dvb_pll_tua6034,
+	[DVB_PLL_TDA665X]                = &dvb_pll_tda665x,
+	[DVB_PLL_TDED4]                  = &dvb_pll_tded4,
+	[DVB_PLL_TDEE4]                  = &dvb_pll_alps_tdee4,
+	[DVB_PLL_TDHU2]                  = &dvb_pll_tdhu2,
+	[DVB_PLL_SAMSUNG_TBMV]           = &dvb_pll_samsung_tbmv,
+	[DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
+	[DVB_PLL_OPERA1]                 = &dvb_pll_opera1,
+	[DVB_PLL_SAMSUNG_DTOS403IH102A]  = &dvb_pll_samsung_dtos403ih102a,
+	[DVB_PLL_SAMSUNG_TDTC9251DH0]    = &dvb_pll_samsung_tdtc9251dh0,
+	[DVB_PLL_SAMSUNG_TBDU18132]	 = &dvb_pll_samsung_tbdu18132,
+	[DVB_PLL_SAMSUNG_TBMU24112]      = &dvb_pll_samsung_tbmu24112,
+};
+
+/* ----------------------------------------------------------- */
+/* code                                                        */
+
+static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf,
+			     const u32 frequency)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	struct dvb_pll_desc *desc = priv->pll_desc;
+	u32 div;
+	int i;
+
+	if (frequency && (frequency < desc->min || frequency > desc->max))
+		return -EINVAL;
+
+	for (i = 0; i < desc->count; i++) {
+		if (frequency > desc->entries[i].limit)
+			continue;
+		break;
+	}
+
+	if (debug)
+		printk("pll: %s: freq=%d | i=%d/%d\n", desc->name,
+		       frequency, i, desc->count);
+	if (i == desc->count)
+		return -EINVAL;
+
+	div = (frequency + desc->iffreq +
+	       desc->entries[i].stepsize/2) / desc->entries[i].stepsize;
+	buf[0] = div >> 8;
+	buf[1] = div & 0xff;
+	buf[2] = desc->entries[i].config;
+	buf[3] = desc->entries[i].cb;
+
+	if (desc->set)
+		desc->set(fe, buf);
+
+	if (debug)
+		printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
+		       desc->name, div, buf[0], buf[1], buf[2], buf[3]);
+
+	// calculate the frequency we set it to
+	return (div * desc->entries[i].stepsize) - desc->iffreq;
+}
+
+static int dvb_pll_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int dvb_pll_sleep(struct dvb_frontend *fe)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+
+	if (priv->i2c == NULL)
+		return -EINVAL;
+
+	if (priv->pll_desc->sleepdata) {
+		struct i2c_msg msg = { .flags = 0,
+			.addr = priv->pll_i2c_address,
+			.buf = priv->pll_desc->sleepdata + 1,
+			.len = priv->pll_desc->sleepdata[0] };
+
+		int result;
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+			return result;
+		}
+		return 0;
+	}
+	/* Shouldn't be called when initdata is NULL, maybe BUG()? */
+	return -EINVAL;
+}
+
+static int dvb_pll_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	u8 buf[4];
+	struct i2c_msg msg =
+		{ .addr = priv->pll_i2c_address, .flags = 0,
+		  .buf = buf, .len = sizeof(buf) };
+	int result;
+	u32 frequency = 0;
+
+	if (priv->i2c == NULL)
+		return -EINVAL;
+
+	result = dvb_pll_configure(fe, buf, c->frequency);
+	if (result < 0)
+		return result;
+	else
+		frequency = result;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+		return result;
+	}
+
+	priv->frequency = frequency;
+	priv->bandwidth = c->bandwidth_hz;
+
+	return 0;
+}
+
+static int dvb_pll_calc_regs(struct dvb_frontend *fe,
+			     u8 *buf, int buf_len)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	int result;
+	u32 frequency = 0;
+
+	if (buf_len < 5)
+		return -EINVAL;
+
+	result = dvb_pll_configure(fe, buf + 1, c->frequency);
+	if (result < 0)
+		return result;
+	else
+		frequency = result;
+
+	buf[0] = priv->pll_i2c_address;
+
+	priv->frequency = frequency;
+	priv->bandwidth = c->bandwidth_hz;
+
+	return 5;
+}
+
+static int dvb_pll_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+static int dvb_pll_init(struct dvb_frontend *fe)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+
+	if (priv->i2c == NULL)
+		return -EINVAL;
+
+	if (priv->pll_desc->initdata) {
+		struct i2c_msg msg = { .flags = 0,
+			.addr = priv->pll_i2c_address,
+			.buf = priv->pll_desc->initdata + 1,
+			.len = priv->pll_desc->initdata[0] };
+
+		int result;
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		result = i2c_transfer(priv->i2c, &msg, 1);
+		if (result != 1)
+			return result;
+		if (priv->pll_desc->initdata2) {
+			msg.buf = priv->pll_desc->initdata2 + 1;
+			msg.len = priv->pll_desc->initdata2[0];
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 1);
+			result = i2c_transfer(priv->i2c, &msg, 1);
+			if (result != 1)
+				return result;
+		}
+		return 0;
+	}
+	/* Shouldn't be called when initdata is NULL, maybe BUG()? */
+	return -EINVAL;
+}
+
+static struct dvb_tuner_ops dvb_pll_tuner_ops = {
+	.release = dvb_pll_release,
+	.sleep = dvb_pll_sleep,
+	.init = dvb_pll_init,
+	.set_params = dvb_pll_set_params,
+	.calc_regs = dvb_pll_calc_regs,
+	.get_frequency = dvb_pll_get_frequency,
+	.get_bandwidth = dvb_pll_get_bandwidth,
+};
+
+struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
+				    struct i2c_adapter *i2c,
+				    unsigned int pll_desc_id)
+{
+	u8 b1 [] = { 0 };
+	struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD,
+			       .buf = b1, .len = 1 };
+	struct dvb_pll_priv *priv = NULL;
+	int ret;
+	struct dvb_pll_desc *desc;
+
+	if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) &&
+	    (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list)))
+		pll_desc_id = id[dvb_pll_devcount];
+
+	BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list));
+
+	desc = pll_list[pll_desc_id];
+
+	if (i2c != NULL) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		ret = i2c_transfer (i2c, &msg, 1);
+		if (ret != 1)
+			return NULL;
+		if (fe->ops.i2c_gate_ctrl)
+			     fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->pll_i2c_address = pll_addr;
+	priv->i2c = i2c;
+	priv->pll_desc = desc;
+	priv->nr = dvb_pll_devcount++;
+
+	memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+	strncpy(fe->ops.tuner_ops.info.name, desc->name,
+		sizeof(fe->ops.tuner_ops.info.name));
+	fe->ops.tuner_ops.info.frequency_min = desc->min;
+	fe->ops.tuner_ops.info.frequency_max = desc->max;
+	if (!desc->initdata)
+		fe->ops.tuner_ops.init = NULL;
+	if (!desc->sleepdata)
+		fe->ops.tuner_ops.sleep = NULL;
+
+	fe->tuner_priv = priv;
+
+	if ((debug) || (id[priv->nr] == pll_desc_id)) {
+		printk("dvb-pll[%d]", priv->nr);
+		if (i2c != NULL)
+			printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr);
+		printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name,
+		       id[priv->nr] == pll_desc_id ?
+				"insmod option" : "autodetected");
+	}
+
+	return fe;
+}
+EXPORT_SYMBOL(dvb_pll_attach);
+
+MODULE_DESCRIPTION("dvb pll library");
+MODULE_AUTHOR("Gerd Knorr");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/dvb-pll.h b/drivers/media/dvb-frontends/dvb-pll.h
new file mode 100644
index 0000000..4de754f
--- /dev/null
+++ b/drivers/media/dvb-frontends/dvb-pll.h
@@ -0,0 +1,57 @@
+/*
+ * descriptions + helper functions for simple dvb plls.
+ */
+
+#ifndef __DVB_PLL_H__
+#define __DVB_PLL_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+#define DVB_PLL_UNDEFINED               0
+#define DVB_PLL_THOMSON_DTT7579         1
+#define DVB_PLL_THOMSON_DTT759X         2
+#define DVB_PLL_LG_Z201                 3
+#define DVB_PLL_UNKNOWN_1               4
+#define DVB_PLL_TUA6010XS               5
+#define DVB_PLL_ENV57H1XD5              6
+#define DVB_PLL_TUA6034                 7
+#define DVB_PLL_TDA665X                 8
+#define DVB_PLL_TDED4                   9
+#define DVB_PLL_TDHU2                  10
+#define DVB_PLL_SAMSUNG_TBMV           11
+#define DVB_PLL_PHILIPS_SD1878_TDA8261 12
+#define DVB_PLL_OPERA1                 13
+#define DVB_PLL_SAMSUNG_DTOS403IH102A  14
+#define DVB_PLL_SAMSUNG_TDTC9251DH0    15
+#define DVB_PLL_SAMSUNG_TBDU18132      16
+#define DVB_PLL_SAMSUNG_TBMU24112      17
+#define DVB_PLL_TDEE4		       18
+#define DVB_PLL_THOMSON_DTT7520X       19
+
+/**
+ * Attach a dvb-pll to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param pll_addr i2c address of the PLL (if used).
+ * @param i2c i2c adapter to use (set to NULL if not used).
+ * @param pll_desc_id dvb_pll_desc to use.
+ * @return Frontend pointer on success, NULL on failure
+ */
+#if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE))
+extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
+					   int pll_addr,
+					   struct i2c_adapter *i2c,
+					   unsigned int pll_desc_id);
+#else
+static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
+					   int pll_addr,
+					   struct i2c_adapter *i2c,
+					   unsigned int pll_desc_id)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb-frontends/dvb_dummy_fe.c b/drivers/media/dvb-frontends/dvb_dummy_fe.c
new file mode 100644
index 0000000..dcfc902
--- /dev/null
+++ b/drivers/media/dvb-frontends/dvb_dummy_fe.c
@@ -0,0 +1,276 @@
+/*
+ *  Driver for Dummy Frontend
+ *
+ *  Written by Emard <emard@softhome.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "dvb_dummy_fe.h"
+
+
+struct dvb_dummy_fe_state {
+	struct dvb_frontend frontend;
+};
+
+
+static int dvb_dummy_fe_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	*status = FE_HAS_SIGNAL
+		| FE_HAS_CARRIER
+		| FE_HAS_VITERBI
+		| FE_HAS_SYNC
+		| FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int dvb_dummy_fe_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	*ber = 0;
+	return 0;
+}
+
+static int dvb_dummy_fe_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	*strength = 0;
+	return 0;
+}
+
+static int dvb_dummy_fe_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	*snr = 0;
+	return 0;
+}
+
+static int dvb_dummy_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	*ucblocks = 0;
+	return 0;
+}
+
+/*
+ * Only needed if it actually reads something from the hardware
+ */
+static int dvb_dummy_fe_get_frontend(struct dvb_frontend *fe)
+{
+	return 0;
+}
+
+static int dvb_dummy_fe_set_frontend(struct dvb_frontend *fe)
+{
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	return 0;
+}
+
+static int dvb_dummy_fe_sleep(struct dvb_frontend* fe)
+{
+	return 0;
+}
+
+static int dvb_dummy_fe_init(struct dvb_frontend* fe)
+{
+	return 0;
+}
+
+static int dvb_dummy_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	return 0;
+}
+
+static int dvb_dummy_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	return 0;
+}
+
+static void dvb_dummy_fe_release(struct dvb_frontend* fe)
+{
+	struct dvb_dummy_fe_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops;
+
+struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void)
+{
+	struct dvb_dummy_fe_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops;
+
+struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void)
+{
+	struct dvb_dummy_fe_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops dvb_dummy_fe_qam_ops;
+
+struct dvb_frontend *dvb_dummy_fe_qam_attach(void)
+{
+	struct dvb_dummy_fe_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name			= "Dummy DVB-T",
+		.frequency_min		= 0,
+		.frequency_max		= 863250000,
+		.frequency_stepsize	= 62500,
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+				FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+				FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
+				FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+				FE_CAN_TRANSMISSION_MODE_AUTO |
+				FE_CAN_GUARD_INTERVAL_AUTO |
+				FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.release = dvb_dummy_fe_release,
+
+	.init = dvb_dummy_fe_init,
+	.sleep = dvb_dummy_fe_sleep,
+
+	.set_frontend = dvb_dummy_fe_set_frontend,
+	.get_frontend = dvb_dummy_fe_get_frontend,
+
+	.read_status = dvb_dummy_fe_read_status,
+	.read_ber = dvb_dummy_fe_read_ber,
+	.read_signal_strength = dvb_dummy_fe_read_signal_strength,
+	.read_snr = dvb_dummy_fe_read_snr,
+	.read_ucblocks = dvb_dummy_fe_read_ucblocks,
+};
+
+static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = {
+	.delsys = { SYS_DVBC_ANNEX_A },
+	.info = {
+		.name			= "Dummy DVB-C",
+		.frequency_stepsize	= 62500,
+		.frequency_min		= 51000000,
+		.frequency_max		= 858000000,
+		.symbol_rate_min	= (57840000/2)/64,     /* SACLK/64 == (XIN/2)/64 */
+		.symbol_rate_max	= (57840000/2)/4,      /* SACLK/4 */
+		.caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+			FE_CAN_QAM_128 | FE_CAN_QAM_256 |
+			FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO
+	},
+
+	.release = dvb_dummy_fe_release,
+
+	.init = dvb_dummy_fe_init,
+	.sleep = dvb_dummy_fe_sleep,
+
+	.set_frontend = dvb_dummy_fe_set_frontend,
+	.get_frontend = dvb_dummy_fe_get_frontend,
+
+	.read_status = dvb_dummy_fe_read_status,
+	.read_ber = dvb_dummy_fe_read_ber,
+	.read_signal_strength = dvb_dummy_fe_read_signal_strength,
+	.read_snr = dvb_dummy_fe_read_snr,
+	.read_ucblocks = dvb_dummy_fe_read_ucblocks,
+};
+
+static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name			= "Dummy DVB-S",
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 250,           /* kHz for QPSK frontends */
+		.frequency_tolerance	= 29500,
+		.symbol_rate_min	= 1000000,
+		.symbol_rate_max	= 45000000,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK
+	},
+
+	.release = dvb_dummy_fe_release,
+
+	.init = dvb_dummy_fe_init,
+	.sleep = dvb_dummy_fe_sleep,
+
+	.set_frontend = dvb_dummy_fe_set_frontend,
+	.get_frontend = dvb_dummy_fe_get_frontend,
+
+	.read_status = dvb_dummy_fe_read_status,
+	.read_ber = dvb_dummy_fe_read_ber,
+	.read_signal_strength = dvb_dummy_fe_read_signal_strength,
+	.read_snr = dvb_dummy_fe_read_snr,
+	.read_ucblocks = dvb_dummy_fe_read_ucblocks,
+
+	.set_voltage = dvb_dummy_fe_set_voltage,
+	.set_tone = dvb_dummy_fe_set_tone,
+};
+
+MODULE_DESCRIPTION("DVB DUMMY Frontend");
+MODULE_AUTHOR("Emard");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(dvb_dummy_fe_ofdm_attach);
+EXPORT_SYMBOL(dvb_dummy_fe_qam_attach);
+EXPORT_SYMBOL(dvb_dummy_fe_qpsk_attach);
diff --git a/drivers/media/dvb-frontends/dvb_dummy_fe.h b/drivers/media/dvb-frontends/dvb_dummy_fe.h
new file mode 100644
index 0000000..1fcb987
--- /dev/null
+++ b/drivers/media/dvb-frontends/dvb_dummy_fe.h
@@ -0,0 +1,51 @@
+/*
+ *  Driver for Dummy Frontend
+ *
+ *  Written by Emard <emard@softhome.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef DVB_DUMMY_FE_H
+#define DVB_DUMMY_FE_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_DVB_DUMMY_FE) || (defined(CONFIG_DVB_DUMMY_FE_MODULE) && \
+defined(MODULE))
+extern struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void);
+extern struct dvb_frontend* dvb_dummy_fe_qpsk_attach(void);
+extern struct dvb_frontend* dvb_dummy_fe_qam_attach(void);
+#else
+static inline struct dvb_frontend *dvb_dummy_fe_ofdm_attach(void)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+static inline struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+static inline struct dvb_frontend *dvb_dummy_fe_qam_attach(void)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_DUMMY_FE */
+
+#endif // DVB_DUMMY_FE_H
diff --git a/drivers/media/dvb-frontends/ec100.c b/drivers/media/dvb-frontends/ec100.c
new file mode 100644
index 0000000..c56fddb
--- /dev/null
+++ b/drivers/media/dvb-frontends/ec100.c
@@ -0,0 +1,335 @@
+/*
+ * E3C EC100 demodulator driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "dvb_frontend.h"
+#include "ec100_priv.h"
+#include "ec100.h"
+
+int ec100_debug;
+module_param_named(debug, ec100_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+struct ec100_state {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend frontend;
+	struct ec100_config config;
+
+	u16 ber;
+};
+
+/* write single register */
+static int ec100_write_reg(struct ec100_state *state, u8 reg, u8 val)
+{
+	u8 buf[2] = {reg, val};
+	struct i2c_msg msg = {
+		.addr = state->config.demod_address,
+		.flags = 0,
+		.len = 2,
+		.buf = buf};
+
+	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+		warn("I2C write failed reg:%02x", reg);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+/* read single register */
+static int ec100_read_reg(struct ec100_state *state, u8 reg, u8 *val)
+{
+	struct i2c_msg msg[2] = {
+		{
+			.addr = state->config.demod_address,
+			.flags = 0,
+			.len = 1,
+			.buf = &reg
+		}, {
+			.addr = state->config.demod_address,
+			.flags = I2C_M_RD,
+			.len = 1,
+			.buf = val
+		}
+	};
+
+	if (i2c_transfer(state->i2c, msg, 2) != 2) {
+		warn("I2C read failed reg:%02x", reg);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int ec100_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct ec100_state *state = fe->demodulator_priv;
+	int ret;
+	u8 tmp, tmp2;
+
+	deb_info("%s: freq:%d bw:%d\n", __func__, c->frequency,
+		c->bandwidth_hz);
+
+	/* program tuner */
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+
+	ret = ec100_write_reg(state, 0x04, 0x06);
+	if (ret)
+		goto error;
+	ret = ec100_write_reg(state, 0x67, 0x58);
+	if (ret)
+		goto error;
+	ret = ec100_write_reg(state, 0x05, 0x18);
+	if (ret)
+		goto error;
+
+	/* reg/bw |   6  |   7  |   8
+	   -------+------+------+------
+	   A 0x1b | 0xa1 | 0xe7 | 0x2c
+	   A 0x1c | 0x55 | 0x63 | 0x72
+	   -------+------+------+------
+	   B 0x1b | 0xb7 | 0x00 | 0x49
+	   B 0x1c | 0x55 | 0x64 | 0x72 */
+
+	switch (c->bandwidth_hz) {
+	case 6000000:
+		tmp = 0xb7;
+		tmp2 = 0x55;
+		break;
+	case 7000000:
+		tmp = 0x00;
+		tmp2 = 0x64;
+		break;
+	case 8000000:
+	default:
+		tmp = 0x49;
+		tmp2 = 0x72;
+	}
+
+	ret = ec100_write_reg(state, 0x1b, tmp);
+	if (ret)
+		goto error;
+	ret = ec100_write_reg(state, 0x1c, tmp2);
+	if (ret)
+		goto error;
+
+	ret = ec100_write_reg(state, 0x0c, 0xbb); /* if freq */
+	if (ret)
+		goto error;
+	ret = ec100_write_reg(state, 0x0d, 0x31); /* if freq */
+	if (ret)
+		goto error;
+
+	ret = ec100_write_reg(state, 0x08, 0x24);
+	if (ret)
+		goto error;
+
+	ret = ec100_write_reg(state, 0x00, 0x00); /* go */
+	if (ret)
+		goto error;
+	ret = ec100_write_reg(state, 0x00, 0x20); /* go */
+	if (ret)
+		goto error;
+
+	return ret;
+error:
+	deb_info("%s: failed:%d\n", __func__, ret);
+	return ret;
+}
+
+static int ec100_get_tune_settings(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *fesettings)
+{
+	fesettings->min_delay_ms = 300;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+
+	return 0;
+}
+
+static int ec100_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct ec100_state *state = fe->demodulator_priv;
+	int ret;
+	u8 tmp;
+	*status = 0;
+
+	ret = ec100_read_reg(state, 0x42, &tmp);
+	if (ret)
+		goto error;
+
+	if (tmp & 0x80) {
+		/* bit7 set - have lock */
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+			FE_HAS_SYNC | FE_HAS_LOCK;
+	} else {
+		ret = ec100_read_reg(state, 0x01, &tmp);
+		if (ret)
+			goto error;
+
+		if (tmp & 0x10) {
+			/* bit4 set - have signal */
+			*status |= FE_HAS_SIGNAL;
+			if (!(tmp & 0x01)) {
+				/* bit0 clear - have ~valid signal */
+				*status |= FE_HAS_CARRIER |  FE_HAS_VITERBI;
+			}
+		}
+	}
+
+	return ret;
+error:
+	deb_info("%s: failed:%d\n", __func__, ret);
+	return ret;
+}
+
+static int ec100_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct ec100_state *state = fe->demodulator_priv;
+	int ret;
+	u8 tmp, tmp2;
+	u16 ber2;
+
+	*ber = 0;
+
+	ret = ec100_read_reg(state, 0x65, &tmp);
+	if (ret)
+		goto error;
+	ret = ec100_read_reg(state, 0x66, &tmp2);
+	if (ret)
+		goto error;
+
+	ber2 = (tmp2 << 8) | tmp;
+
+	/* if counter overflow or clear */
+	if (ber2 < state->ber)
+		*ber = ber2;
+	else
+		*ber = ber2 - state->ber;
+
+	state->ber = ber2;
+
+	return ret;
+error:
+	deb_info("%s: failed:%d\n", __func__, ret);
+	return ret;
+}
+
+static int ec100_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct ec100_state *state = fe->demodulator_priv;
+	int ret;
+	u8 tmp;
+
+	ret = ec100_read_reg(state, 0x24, &tmp);
+	if (ret) {
+		*strength = 0;
+		goto error;
+	}
+
+	*strength = ((tmp << 8) | tmp);
+
+	return ret;
+error:
+	deb_info("%s: failed:%d\n", __func__, ret);
+	return ret;
+}
+
+static int ec100_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	*snr = 0;
+	return 0;
+}
+
+static int ec100_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	*ucblocks = 0;
+	return 0;
+}
+
+static void ec100_release(struct dvb_frontend *fe)
+{
+	struct ec100_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops ec100_ops;
+
+struct dvb_frontend *ec100_attach(const struct ec100_config *config,
+	struct i2c_adapter *i2c)
+{
+	int ret;
+	struct ec100_state *state = NULL;
+	u8 tmp;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct ec100_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->i2c = i2c;
+	memcpy(&state->config, config, sizeof(struct ec100_config));
+
+	/* check if the demod is there */
+	ret = ec100_read_reg(state, 0x33, &tmp);
+	if (ret || tmp != 0x0b)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &ec100_ops,
+		sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	return &state->frontend;
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(ec100_attach);
+
+static struct dvb_frontend_ops ec100_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "E3C EC100 DVB-T",
+		.caps =
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_QAM_16 |
+			FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_MUTE_TS
+	},
+
+	.release = ec100_release,
+	.set_frontend = ec100_set_frontend,
+	.get_tune_settings = ec100_get_tune_settings,
+	.read_status = ec100_read_status,
+	.read_ber = ec100_read_ber,
+	.read_signal_strength = ec100_read_signal_strength,
+	.read_snr = ec100_read_snr,
+	.read_ucblocks = ec100_read_ucblocks,
+};
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("E3C EC100 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/ec100.h b/drivers/media/dvb-frontends/ec100.h
new file mode 100644
index 0000000..ee8e524
--- /dev/null
+++ b/drivers/media/dvb-frontends/ec100.h
@@ -0,0 +1,46 @@
+/*
+ * E3C EC100 demodulator driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef EC100_H
+#define EC100_H
+
+#include <linux/dvb/frontend.h>
+
+struct ec100_config {
+	/* demodulator's I2C address */
+	u8 demod_address;
+};
+
+
+#if defined(CONFIG_DVB_EC100) || \
+	(defined(CONFIG_DVB_EC100_MODULE) && defined(MODULE))
+extern struct dvb_frontend *ec100_attach(const struct ec100_config *config,
+	struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *ec100_attach(
+	const struct ec100_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* EC100_H */
diff --git a/drivers/media/dvb-frontends/ec100_priv.h b/drivers/media/dvb-frontends/ec100_priv.h
new file mode 100644
index 0000000..5c99014
--- /dev/null
+++ b/drivers/media/dvb-frontends/ec100_priv.h
@@ -0,0 +1,39 @@
+/*
+ * E3C EC100 demodulator driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef EC100_PRIV
+#define EC100_PRIV
+
+#define LOG_PREFIX "ec100"
+
+#define dprintk(var, level, args...) \
+	do { if ((var & level)) printk(args); } while (0)
+
+#define deb_info(args...) dprintk(ec100_debug, 0x01, args)
+
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+#endif /* EC100_PRIV */
diff --git a/drivers/media/dvb-frontends/eds1547.h b/drivers/media/dvb-frontends/eds1547.h
new file mode 100644
index 0000000..c983f2f
--- /dev/null
+++ b/drivers/media/dvb-frontends/eds1547.h
@@ -0,0 +1,133 @@
+/* eds1547.h Earda EDS-1547 tuner support
+*
+* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+*
+*	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, version 2.
+*
+* see Documentation/dvb/README.dvb-usb for more information
+*/
+
+#ifndef EDS1547
+#define EDS1547
+
+static u8 stv0288_earda_inittab[] = {
+	0x01, 0x57,
+	0x02, 0x20,
+	0x03, 0x8e,
+	0x04, 0x8e,
+	0x05, 0x12,
+	0x06, 0x00,
+	0x07, 0x00,
+	0x09, 0x00,
+	0x0a, 0x04,
+	0x0b, 0x00,
+	0x0c, 0x00,
+	0x0d, 0x00,
+	0x0e, 0xd4,
+	0x0f, 0x30,
+	0x11, 0x44,
+	0x12, 0x03,
+	0x13, 0x48,
+	0x14, 0x84,
+	0x15, 0x45,
+	0x16, 0xb7,
+	0x17, 0x9c,
+	0x18, 0x00,
+	0x19, 0xa6,
+	0x1a, 0x88,
+	0x1b, 0x8f,
+	0x1c, 0xf0,
+	0x20, 0x0b,
+	0x21, 0x54,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x2b, 0xff,
+	0x2c, 0xf7,
+	0x30, 0x00,
+	0x31, 0x1e,
+	0x32, 0x14,
+	0x33, 0x0f,
+	0x34, 0x09,
+	0x35, 0x0c,
+	0x36, 0x05,
+	0x37, 0x2f,
+	0x38, 0x16,
+	0x39, 0xbd,
+	0x3a, 0x00,
+	0x3b, 0x13,
+	0x3c, 0x11,
+	0x3d, 0x30,
+	0x40, 0x63,
+	0x41, 0x04,
+	0x42, 0x20,
+	0x43, 0x00,
+	0x44, 0x00,
+	0x45, 0x00,
+	0x46, 0x00,
+	0x47, 0x00,
+	0x4a, 0x00,
+	0x50, 0x10,
+	0x51, 0x36,
+	0x52, 0x09,
+	0x53, 0x94,
+	0x54, 0x62,
+	0x55, 0x29,
+	0x56, 0x64,
+	0x57, 0x2b,
+	0x58, 0x54,
+	0x59, 0x86,
+	0x5a, 0x00,
+	0x5b, 0x9b,
+	0x5c, 0x08,
+	0x5d, 0x7f,
+	0x5e, 0x00,
+	0x5f, 0xff,
+	0x70, 0x00,
+	0x71, 0x00,
+	0x72, 0x00,
+	0x74, 0x00,
+	0x75, 0x00,
+	0x76, 0x00,
+	0x81, 0x00,
+	0x82, 0x3f,
+	0x83, 0x3f,
+	0x84, 0x00,
+	0x85, 0x00,
+	0x88, 0x00,
+	0x89, 0x00,
+	0x8a, 0x00,
+	0x8b, 0x00,
+	0x8c, 0x00,
+	0x90, 0x00,
+	0x91, 0x00,
+	0x92, 0x00,
+	0x93, 0x00,
+	0x94, 0x1c,
+	0x97, 0x00,
+	0xa0, 0x48,
+	0xa1, 0x00,
+	0xb0, 0xb8,
+	0xb1, 0x3a,
+	0xb2, 0x10,
+	0xb3, 0x82,
+	0xb4, 0x80,
+	0xb5, 0x82,
+	0xb6, 0x82,
+	0xb7, 0x82,
+	0xb8, 0x20,
+	0xb9, 0x00,
+	0xf0, 0x00,
+	0xf1, 0x00,
+	0xf2, 0xc0,
+	0xff,0xff,
+};
+
+static struct stv0288_config earda_config = {
+	.demod_address = 0x68,
+	.min_delay_ms = 100,
+	.inittab = stv0288_earda_inittab,
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/hd29l2.c b/drivers/media/dvb-frontends/hd29l2.c
new file mode 100644
index 0000000..a003181
--- /dev/null
+++ b/drivers/media/dvb-frontends/hd29l2.c
@@ -0,0 +1,861 @@
+/*
+ * HDIC HD29L2 DMB-TH demodulator driver
+ *
+ * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D
+ *
+ * Author: Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "hd29l2_priv.h"
+
+int hd29l2_debug;
+module_param_named(debug, hd29l2_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+/* write multiple registers */
+static int hd29l2_wr_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len)
+{
+	int ret;
+	u8 buf[2 + len];
+	struct i2c_msg msg[1] = {
+		{
+			.addr = priv->cfg.i2c_addr,
+			.flags = 0,
+			.len = sizeof(buf),
+			.buf = buf,
+		}
+	};
+
+	buf[0] = 0x00;
+	buf[1] = reg;
+	memcpy(&buf[2], val, len);
+
+	ret = i2c_transfer(priv->i2c, msg, 1);
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+
+	return ret;
+}
+
+/* read multiple registers */
+static int hd29l2_rd_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len)
+{
+	int ret;
+	u8 buf[2] = { 0x00, reg };
+	struct i2c_msg msg[2] = {
+		{
+			.addr = priv->cfg.i2c_addr,
+			.flags = 0,
+			.len = 2,
+			.buf = buf,
+		}, {
+			.addr = priv->cfg.i2c_addr,
+			.flags = I2C_M_RD,
+			.len = len,
+			.buf = val,
+		}
+	};
+
+	ret = i2c_transfer(priv->i2c, msg, 2);
+	if (ret == 2) {
+		ret = 0;
+	} else {
+		warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+
+	return ret;
+}
+
+/* write single register */
+static int hd29l2_wr_reg(struct hd29l2_priv *priv, u8 reg, u8 val)
+{
+	return hd29l2_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+static int hd29l2_rd_reg(struct hd29l2_priv *priv, u8 reg, u8 *val)
+{
+	return hd29l2_rd_regs(priv, reg, val, 1);
+}
+
+/* write single register with mask */
+static int hd29l2_wr_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 val, u8 mask)
+{
+	int ret;
+	u8 tmp;
+
+	/* no need for read if whole reg is written */
+	if (mask != 0xff) {
+		ret = hd29l2_rd_regs(priv, reg, &tmp, 1);
+		if (ret)
+			return ret;
+
+		val &= mask;
+		tmp &= ~mask;
+		val |= tmp;
+	}
+
+	return hd29l2_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register with mask */
+int hd29l2_rd_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 *val, u8 mask)
+{
+	int ret, i;
+	u8 tmp;
+
+	ret = hd29l2_rd_regs(priv, reg, &tmp, 1);
+	if (ret)
+		return ret;
+
+	tmp &= mask;
+
+	/* find position of the first bit */
+	for (i = 0; i < 8; i++) {
+		if ((mask >> i) & 0x01)
+			break;
+	}
+	*val = tmp >> i;
+
+	return 0;
+}
+
+static int hd29l2_soft_reset(struct hd29l2_priv *priv)
+{
+	int ret;
+	u8 tmp;
+
+	ret = hd29l2_rd_reg(priv, 0x26, &tmp);
+	if (ret)
+		goto err;
+
+	ret = hd29l2_wr_reg(priv, 0x26, 0x0d);
+	if (ret)
+		goto err;
+
+	usleep_range(10000, 20000);
+
+	ret = hd29l2_wr_reg(priv, 0x26, tmp);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int hd29l2_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	int ret, i;
+	struct hd29l2_priv *priv = fe->demodulator_priv;
+	u8 tmp;
+
+	dbg("%s: enable=%d", __func__, enable);
+
+	/* set tuner address for demod */
+	if (!priv->tuner_i2c_addr_programmed && enable) {
+		/* no need to set tuner address every time, once is enough */
+		ret = hd29l2_wr_reg(priv, 0x9d, priv->cfg.tuner_i2c_addr << 1);
+		if (ret)
+			goto err;
+
+		priv->tuner_i2c_addr_programmed = true;
+	}
+
+	/* open / close gate */
+	ret = hd29l2_wr_reg(priv, 0x9f, enable);
+	if (ret)
+		goto err;
+
+	/* wait demod ready */
+	for (i = 10; i; i--) {
+		ret = hd29l2_rd_reg(priv, 0x9e, &tmp);
+		if (ret)
+			goto err;
+
+		if (tmp == enable)
+			break;
+
+		usleep_range(5000, 10000);
+	}
+
+	dbg("%s: loop=%d", __func__, i);
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int hd29l2_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	int ret;
+	struct hd29l2_priv *priv = fe->demodulator_priv;
+	u8 buf[2];
+
+	*status = 0;
+
+	ret = hd29l2_rd_reg(priv, 0x05, &buf[0]);
+	if (ret)
+		goto err;
+
+	if (buf[0] & 0x01) {
+		/* full lock */
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+			FE_HAS_SYNC | FE_HAS_LOCK;
+	} else {
+		ret = hd29l2_rd_reg(priv, 0x0d, &buf[1]);
+		if (ret)
+			goto err;
+
+		if ((buf[1] & 0xfe) == 0x78)
+			/* partial lock */
+			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI | FE_HAS_SYNC;
+	}
+
+	priv->fe_status = *status;
+
+	return 0;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int hd29l2_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	int ret;
+	struct hd29l2_priv *priv = fe->demodulator_priv;
+	u8 buf[2];
+	u16 tmp;
+
+	if (!(priv->fe_status & FE_HAS_LOCK)) {
+		*snr = 0;
+		ret = 0;
+		goto err;
+	}
+
+	ret = hd29l2_rd_regs(priv, 0x0b, buf, 2);
+	if (ret)
+		goto err;
+
+	tmp = (buf[0] << 8) | buf[1];
+
+	/* report SNR in dB * 10 */
+	#define LOG10_20736_24 72422627 /* log10(20736) << 24 */
+	if (tmp)
+		*snr = (LOG10_20736_24 - intlog10(tmp)) / ((1 << 24) / 100);
+	else
+		*snr = 0;
+
+	return 0;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int hd29l2_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	int ret;
+	struct hd29l2_priv *priv = fe->demodulator_priv;
+	u8 buf[2];
+	u16 tmp;
+
+	*strength = 0;
+
+	ret = hd29l2_rd_regs(priv, 0xd5, buf, 2);
+	if (ret)
+		goto err;
+
+	tmp = buf[0] << 8 | buf[1];
+	tmp = ~tmp & 0x0fff;
+
+	/* scale value to 0x0000-0xffff from 0x0000-0x0fff */
+	*strength = tmp * 0xffff / 0x0fff;
+
+	return 0;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int hd29l2_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	int ret;
+	struct hd29l2_priv *priv = fe->demodulator_priv;
+	u8 buf[2];
+
+	if (!(priv->fe_status & FE_HAS_SYNC)) {
+		*ber = 0;
+		ret = 0;
+		goto err;
+	}
+
+	ret = hd29l2_rd_regs(priv, 0xd9, buf, 2);
+	if (ret) {
+		*ber = 0;
+		goto err;
+	}
+
+	/* LDPC BER */
+	*ber = ((buf[0] & 0x0f) << 8) | buf[1];
+
+	return 0;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int hd29l2_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	/* no way to read? */
+	*ucblocks = 0;
+	return 0;
+}
+
+static enum dvbfe_search hd29l2_search(struct dvb_frontend *fe)
+{
+	int ret, i;
+	struct hd29l2_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u8 tmp, buf[3];
+	u8 modulation, carrier, guard_interval, interleave, code_rate;
+	u64 num64;
+	u32 if_freq, if_ctl;
+	bool auto_mode;
+
+	dbg("%s: delivery_system=%d frequency=%d bandwidth_hz=%d " \
+		"modulation=%d inversion=%d fec_inner=%d guard_interval=%d",
+		 __func__,
+		c->delivery_system, c->frequency, c->bandwidth_hz,
+		c->modulation, c->inversion, c->fec_inner, c->guard_interval);
+
+	/* as for now we detect always params automatically */
+	auto_mode = true;
+
+	/* program tuner */
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+
+	/* get and program IF */
+	if (fe->ops.tuner_ops.get_if_frequency)
+		fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
+	else
+		if_freq = 0;
+
+	if (if_freq) {
+		/* normal IF */
+
+		/* calc IF control value */
+		num64 = if_freq;
+		num64 *= 0x800000;
+		num64 = div_u64(num64, HD29L2_XTAL);
+		num64 -= 0x800000;
+		if_ctl = num64;
+
+		tmp = 0xfc; /* tuner type normal */
+	} else {
+		/* zero IF */
+		if_ctl = 0;
+		tmp = 0xfe; /* tuner type Zero-IF */
+	}
+
+	buf[0] = ((if_ctl >>  0) & 0xff);
+	buf[1] = ((if_ctl >>  8) & 0xff);
+	buf[2] = ((if_ctl >> 16) & 0xff);
+
+	/* program IF control */
+	ret = hd29l2_wr_regs(priv, 0x14, buf, 3);
+	if (ret)
+		goto err;
+
+	/* program tuner type */
+	ret = hd29l2_wr_reg(priv, 0xab, tmp);
+	if (ret)
+		goto err;
+
+	dbg("%s: if_freq=%d if_ctl=%x", __func__, if_freq, if_ctl);
+
+	if (auto_mode) {
+		/*
+		 * use auto mode
+		 */
+
+		/* disable quick mode */
+		ret = hd29l2_wr_reg_mask(priv, 0xac, 0 << 7, 0x80);
+		if (ret)
+			goto err;
+
+		ret = hd29l2_wr_reg_mask(priv, 0x82, 1 << 1, 0x02);
+		if (ret)
+			goto err;
+
+		/* enable auto mode */
+		ret = hd29l2_wr_reg_mask(priv, 0x7d, 1 << 6, 0x40);
+		if (ret)
+			goto err;
+
+		ret = hd29l2_wr_reg_mask(priv, 0x81, 1 << 3, 0x08);
+		if (ret)
+			goto err;
+
+		/* soft reset */
+		ret = hd29l2_soft_reset(priv);
+		if (ret)
+			goto err;
+
+		/* detect modulation */
+		for (i = 30; i; i--) {
+			msleep(100);
+
+			ret = hd29l2_rd_reg(priv, 0x0d, &tmp);
+			if (ret)
+				goto err;
+
+			if ((((tmp & 0xf0) >= 0x10) &&
+				((tmp & 0x0f) == 0x08)) || (tmp >= 0x2c))
+				break;
+		}
+
+		dbg("%s: loop=%d", __func__, i);
+
+		if (i == 0)
+			/* detection failed */
+			return DVBFE_ALGO_SEARCH_FAILED;
+
+		/* read modulation */
+		ret = hd29l2_rd_reg_mask(priv, 0x7d, &modulation, 0x07);
+		if (ret)
+			goto err;
+	} else {
+		/*
+		 * use manual mode
+		 */
+
+		modulation = HD29L2_QAM64;
+		carrier = HD29L2_CARRIER_MULTI;
+		guard_interval = HD29L2_PN945;
+		interleave = HD29L2_INTERLEAVER_420;
+		code_rate = HD29L2_CODE_RATE_08;
+
+		tmp = (code_rate << 3) | modulation;
+		ret = hd29l2_wr_reg_mask(priv, 0x7d, tmp, 0x5f);
+		if (ret)
+			goto err;
+
+		tmp = (carrier << 2) | guard_interval;
+		ret = hd29l2_wr_reg_mask(priv, 0x81, tmp, 0x0f);
+		if (ret)
+			goto err;
+
+		tmp = interleave;
+		ret = hd29l2_wr_reg_mask(priv, 0x82, tmp, 0x03);
+		if (ret)
+			goto err;
+	}
+
+	/* ensure modulation validy */
+	/* 0=QAM4_NR, 1=QAM4, 2=QAM16, 3=QAM32, 4=QAM64 */
+	if (modulation > (ARRAY_SIZE(reg_mod_vals_tab[0].val) - 1)) {
+		dbg("%s: modulation=%d not valid", __func__, modulation);
+		goto err;
+	}
+
+	/* program registers according to modulation */
+	for (i = 0; i < ARRAY_SIZE(reg_mod_vals_tab); i++) {
+		ret = hd29l2_wr_reg(priv, reg_mod_vals_tab[i].reg,
+			reg_mod_vals_tab[i].val[modulation]);
+		if (ret)
+			goto err;
+	}
+
+	/* read guard interval */
+	ret = hd29l2_rd_reg_mask(priv, 0x81, &guard_interval, 0x03);
+	if (ret)
+		goto err;
+
+	/* read carrier mode */
+	ret = hd29l2_rd_reg_mask(priv, 0x81, &carrier, 0x04);
+	if (ret)
+		goto err;
+
+	dbg("%s: modulation=%d guard_interval=%d carrier=%d",
+		__func__, modulation, guard_interval, carrier);
+
+	if ((carrier == HD29L2_CARRIER_MULTI) && (modulation == HD29L2_QAM64) &&
+		(guard_interval == HD29L2_PN945)) {
+		dbg("%s: C=3780 && QAM64 && PN945", __func__);
+
+		ret = hd29l2_wr_reg(priv, 0x42, 0x33);
+		if (ret)
+			goto err;
+
+		ret = hd29l2_wr_reg(priv, 0xdd, 0x01);
+		if (ret)
+			goto err;
+	}
+
+	usleep_range(10000, 20000);
+
+	/* soft reset */
+	ret = hd29l2_soft_reset(priv);
+	if (ret)
+		goto err;
+
+	/* wait demod lock */
+	for (i = 30; i; i--) {
+		msleep(100);
+
+		/* read lock bit */
+		ret = hd29l2_rd_reg_mask(priv, 0x05, &tmp, 0x01);
+		if (ret)
+			goto err;
+
+		if (tmp)
+			break;
+	}
+
+	dbg("%s: loop=%d", __func__, i);
+
+	if (i == 0)
+		return DVBFE_ALGO_SEARCH_AGAIN;
+
+	return DVBFE_ALGO_SEARCH_SUCCESS;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return DVBFE_ALGO_SEARCH_ERROR;
+}
+
+static int hd29l2_get_frontend_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_CUSTOM;
+}
+
+static int hd29l2_get_frontend(struct dvb_frontend *fe)
+{
+	int ret;
+	struct hd29l2_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u8 buf[3];
+	u32 if_ctl;
+	char *str_constellation, *str_code_rate, *str_constellation_code_rate,
+		*str_guard_interval, *str_carrier, *str_guard_interval_carrier,
+		*str_interleave, *str_interleave_;
+
+	ret = hd29l2_rd_reg(priv, 0x7d, &buf[0]);
+	if (ret)
+		goto err;
+
+	ret = hd29l2_rd_regs(priv, 0x81, &buf[1], 2);
+	if (ret)
+		goto err;
+
+	/* constellation, 0x7d[2:0] */
+	switch ((buf[0] >> 0) & 0x07) {
+	case 0: /* QAM4NR */
+		str_constellation = "QAM4NR";
+		c->modulation = QAM_AUTO; /* FIXME */
+		break;
+	case 1: /* QAM4 */
+		str_constellation = "QAM4";
+		c->modulation = QPSK; /* FIXME */
+		break;
+	case 2:
+		str_constellation = "QAM16";
+		c->modulation = QAM_16;
+		break;
+	case 3:
+		str_constellation = "QAM32";
+		c->modulation = QAM_32;
+		break;
+	case 4:
+		str_constellation = "QAM64";
+		c->modulation = QAM_64;
+		break;
+	default:
+		str_constellation = "?";
+	}
+
+	/* LDPC code rate, 0x7d[4:3] */
+	switch ((buf[0] >> 3) & 0x03) {
+	case 0: /* 0.4 */
+		str_code_rate = "0.4";
+		c->fec_inner = FEC_AUTO; /* FIXME */
+		break;
+	case 1: /* 0.6 */
+		str_code_rate = "0.6";
+		c->fec_inner = FEC_3_5;
+		break;
+	case 2: /* 0.8 */
+		str_code_rate = "0.8";
+		c->fec_inner = FEC_4_5;
+		break;
+	default:
+		str_code_rate = "?";
+	}
+
+	/* constellation & code rate set, 0x7d[6] */
+	switch ((buf[0] >> 6) & 0x01) {
+	case 0:
+		str_constellation_code_rate = "manual";
+		break;
+	case 1:
+		str_constellation_code_rate = "auto";
+		break;
+	default:
+		str_constellation_code_rate = "?";
+	}
+
+	/* frame header, 0x81[1:0] */
+	switch ((buf[1] >> 0) & 0x03) {
+	case 0: /* PN945 */
+		str_guard_interval = "PN945";
+		c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */
+		break;
+	case 1: /* PN595 */
+		str_guard_interval = "PN595";
+		c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */
+		break;
+	case 2: /* PN420 */
+		str_guard_interval = "PN420";
+		c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */
+		break;
+	default:
+		str_guard_interval = "?";
+	}
+
+	/* carrier, 0x81[2] */
+	switch ((buf[1] >> 2) & 0x01) {
+	case 0:
+		str_carrier = "C=1";
+		break;
+	case 1:
+		str_carrier = "C=3780";
+		break;
+	default:
+		str_carrier = "?";
+	}
+
+	/* frame header & carrier set, 0x81[3] */
+	switch ((buf[1] >> 3) & 0x01) {
+	case 0:
+		str_guard_interval_carrier = "manual";
+		break;
+	case 1:
+		str_guard_interval_carrier = "auto";
+		break;
+	default:
+		str_guard_interval_carrier = "?";
+	}
+
+	/* interleave, 0x82[0] */
+	switch ((buf[2] >> 0) & 0x01) {
+	case 0:
+		str_interleave = "M=720";
+		break;
+	case 1:
+		str_interleave = "M=240";
+		break;
+	default:
+		str_interleave = "?";
+	}
+
+	/* interleave set, 0x82[1] */
+	switch ((buf[2] >> 1) & 0x01) {
+	case 0:
+		str_interleave_ = "manual";
+		break;
+	case 1:
+		str_interleave_ = "auto";
+		break;
+	default:
+		str_interleave_ = "?";
+	}
+
+	/*
+	 * We can read out current detected NCO and use that value next
+	 * time instead of calculating new value from targed IF.
+	 * I think it will not effect receiver sensitivity but gaining lock
+	 * after tune could be easier...
+	 */
+	ret = hd29l2_rd_regs(priv, 0xb1, &buf[0], 3);
+	if (ret)
+		goto err;
+
+	if_ctl = (buf[0] << 16) | ((buf[1] - 7) << 8) | buf[2];
+
+	dbg("%s: %s %s %s | %s %s %s | %s %s | NCO=%06x", __func__,
+		str_constellation, str_code_rate, str_constellation_code_rate,
+		str_guard_interval, str_carrier, str_guard_interval_carrier,
+		str_interleave, str_interleave_, if_ctl);
+
+	return 0;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int hd29l2_init(struct dvb_frontend *fe)
+{
+	int ret, i;
+	struct hd29l2_priv *priv = fe->demodulator_priv;
+	u8 tmp;
+	static const struct reg_val tab[] = {
+		{ 0x3a, 0x06 },
+		{ 0x3b, 0x03 },
+		{ 0x3c, 0x04 },
+		{ 0xaf, 0x06 },
+		{ 0xb0, 0x1b },
+		{ 0x80, 0x64 },
+		{ 0x10, 0x38 },
+	};
+
+	dbg("%s:", __func__);
+
+	/* reset demod */
+	/* it is recommended to HW reset chip using RST_N pin */
+	if (fe->callback) {
+		ret = fe->callback(fe, DVB_FRONTEND_COMPONENT_DEMOD, 0, 0);
+		if (ret)
+			goto err;
+
+		/* reprogramming needed because HW reset clears registers */
+		priv->tuner_i2c_addr_programmed = false;
+	}
+
+	/* init */
+	for (i = 0; i < ARRAY_SIZE(tab); i++) {
+		ret = hd29l2_wr_reg(priv, tab[i].reg, tab[i].val);
+		if (ret)
+			goto err;
+	}
+
+	/* TS params */
+	ret = hd29l2_rd_reg(priv, 0x36, &tmp);
+	if (ret)
+		goto err;
+
+	tmp &= 0x1b;
+	tmp |= priv->cfg.ts_mode;
+	ret = hd29l2_wr_reg(priv, 0x36, tmp);
+	if (ret)
+		goto err;
+
+	ret = hd29l2_rd_reg(priv, 0x31, &tmp);
+	tmp &= 0xef;
+
+	if (!(priv->cfg.ts_mode >> 7))
+		/* set b4 for serial TS */
+		tmp |= 0x10;
+
+	ret = hd29l2_wr_reg(priv, 0x31, tmp);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static void hd29l2_release(struct dvb_frontend *fe)
+{
+	struct hd29l2_priv *priv = fe->demodulator_priv;
+	kfree(priv);
+}
+
+static struct dvb_frontend_ops hd29l2_ops;
+
+struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config,
+	struct i2c_adapter *i2c)
+{
+	int ret;
+	struct hd29l2_priv *priv = NULL;
+	u8 tmp;
+
+	/* allocate memory for the internal state */
+	priv = kzalloc(sizeof(struct hd29l2_priv), GFP_KERNEL);
+	if (priv == NULL)
+		goto err;
+
+	/* setup the state */
+	priv->i2c = i2c;
+	memcpy(&priv->cfg, config, sizeof(struct hd29l2_config));
+
+
+	/* check if the demod is there */
+	ret = hd29l2_rd_reg(priv, 0x00, &tmp);
+	if (ret)
+		goto err;
+
+	/* create dvb_frontend */
+	memcpy(&priv->fe.ops, &hd29l2_ops, sizeof(struct dvb_frontend_ops));
+	priv->fe.demodulator_priv = priv;
+
+	return &priv->fe;
+err:
+	kfree(priv);
+	return NULL;
+}
+EXPORT_SYMBOL(hd29l2_attach);
+
+static struct dvb_frontend_ops hd29l2_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "HDIC HD29L2 DMB-TH",
+		.frequency_min = 474000000,
+		.frequency_max = 858000000,
+		.frequency_stepsize = 10000,
+		.caps = FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK |
+			FE_CAN_QAM_16 |
+			FE_CAN_QAM_32 |
+			FE_CAN_QAM_64 |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_BANDWIDTH_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_RECOVER
+	},
+
+	.release = hd29l2_release,
+
+	.init = hd29l2_init,
+
+	.get_frontend_algo = hd29l2_get_frontend_algo,
+	.search = hd29l2_search,
+	.get_frontend = hd29l2_get_frontend,
+
+	.read_status = hd29l2_read_status,
+	.read_snr = hd29l2_read_snr,
+	.read_signal_strength = hd29l2_read_signal_strength,
+	.read_ber = hd29l2_read_ber,
+	.read_ucblocks = hd29l2_read_ucblocks,
+
+	.i2c_gate_ctrl = hd29l2_i2c_gate_ctrl,
+};
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("HDIC HD29L2 DMB-TH demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/hd29l2.h b/drivers/media/dvb-frontends/hd29l2.h
new file mode 100644
index 0000000..a7a6443
--- /dev/null
+++ b/drivers/media/dvb-frontends/hd29l2.h
@@ -0,0 +1,66 @@
+/*
+ * HDIC HD29L2 DMB-TH demodulator driver
+ *
+ * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D
+ *
+ * Author: Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef HD29L2_H
+#define HD29L2_H
+
+#include <linux/dvb/frontend.h>
+
+struct hd29l2_config {
+	/*
+	 * demodulator I2C address
+	 */
+	u8 i2c_addr;
+
+	/*
+	 * tuner I2C address
+	 * only needed when tuner is behind demod I2C-gate
+	 */
+	u8 tuner_i2c_addr;
+
+	/*
+	 * TS settings
+	 */
+#define HD29L2_TS_SERIAL            0x00
+#define HD29L2_TS_PARALLEL          0x80
+#define HD29L2_TS_CLK_NORMAL        0x40
+#define HD29L2_TS_CLK_INVERTED      0x00
+#define HD29L2_TS_CLK_GATED         0x20
+#define HD29L2_TS_CLK_FREE          0x00
+	u8 ts_mode;
+};
+
+
+#if defined(CONFIG_DVB_HD29L2) || \
+	(defined(CONFIG_DVB_HD29L2_MODULE) && defined(MODULE))
+extern struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config,
+	struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *hd29l2_attach(
+const struct hd29l2_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* HD29L2_H */
diff --git a/drivers/media/dvb-frontends/hd29l2_priv.h b/drivers/media/dvb-frontends/hd29l2_priv.h
new file mode 100644
index 0000000..ba16dc3
--- /dev/null
+++ b/drivers/media/dvb-frontends/hd29l2_priv.h
@@ -0,0 +1,314 @@
+/*
+ * HDIC HD29L2 DMB-TH demodulator driver
+ *
+ * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D
+ *
+ * Author: Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef HD29L2_PRIV
+#define HD29L2_PRIV
+
+#include <linux/dvb/version.h>
+#include "dvb_frontend.h"
+#include "dvb_math.h"
+#include "hd29l2.h"
+
+#define LOG_PREFIX "hd29l2"
+
+#undef dbg
+#define dbg(f, arg...) \
+	if (hd29l2_debug) \
+		printk(KERN_INFO   LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+#define HD29L2_XTAL 30400000 /* Hz */
+
+
+#define HD29L2_QAM4NR 0x00
+#define HD29L2_QAM4   0x01
+#define HD29L2_QAM16  0x02
+#define HD29L2_QAM32  0x03
+#define HD29L2_QAM64  0x04
+
+#define HD29L2_CODE_RATE_04 0x00
+#define HD29L2_CODE_RATE_06 0x08
+#define HD29L2_CODE_RATE_08 0x10
+
+#define HD29L2_PN945 0x00
+#define HD29L2_PN595 0x01
+#define HD29L2_PN420 0x02
+
+#define HD29L2_CARRIER_SINGLE 0x00
+#define HD29L2_CARRIER_MULTI  0x01
+
+#define HD29L2_INTERLEAVER_720 0x00
+#define HD29L2_INTERLEAVER_420 0x01
+
+struct reg_val {
+	u8 reg;
+	u8 val;
+};
+
+struct reg_mod_vals {
+	u8 reg;
+	u8 val[5];
+};
+
+struct hd29l2_priv {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend fe;
+	struct hd29l2_config cfg;
+	u8 tuner_i2c_addr_programmed:1;
+
+	fe_status_t fe_status;
+};
+
+static const struct reg_mod_vals reg_mod_vals_tab[] = {
+	/* REG, QAM4NR, QAM4,QAM16,QAM32,QAM64 */
+	{ 0x01, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
+	{ 0x02, { 0x07, 0x07, 0x07, 0x07, 0x07 } },
+	{ 0x03, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
+	{ 0x04, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0x05, { 0x61, 0x60, 0x60, 0x61, 0x60 } },
+	{ 0x06, { 0xff, 0xff, 0xff, 0xff, 0xff } },
+	{ 0x07, { 0xff, 0xff, 0xff, 0xff, 0xff } },
+	{ 0x08, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0x09, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0x0a, { 0x15, 0x15, 0x03, 0x03, 0x03 } },
+	{ 0x0d, { 0x78, 0x78, 0x88, 0x78, 0x78 } },
+	{ 0x0e, { 0xa0, 0x90, 0xa0, 0xa0, 0xa0 } },
+	{ 0x0f, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0x10, { 0xa0, 0xa0, 0x58, 0x38, 0x38 } },
+	{ 0x11, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0x12, { 0x5a, 0x5a, 0x5a, 0x5a, 0x5a } },
+	{ 0x13, { 0xa2, 0xa2, 0xa2, 0xa2, 0xa2 } },
+	{ 0x17, { 0x40, 0x40, 0x40, 0x40, 0x40 } },
+	{ 0x18, { 0x21, 0x21, 0x42, 0x52, 0x42 } },
+	{ 0x19, { 0x21, 0x21, 0x62, 0x72, 0x62 } },
+	{ 0x1a, { 0x32, 0x43, 0xa9, 0xb9, 0xa9 } },
+	{ 0x1b, { 0x32, 0x43, 0xb9, 0xd8, 0xb9 } },
+	{ 0x1c, { 0x02, 0x02, 0x03, 0x02, 0x03 } },
+	{ 0x1d, { 0x0c, 0x0c, 0x01, 0x02, 0x02 } },
+	{ 0x1e, { 0x02, 0x02, 0x02, 0x01, 0x02 } },
+	{ 0x1f, { 0x02, 0x02, 0x01, 0x02, 0x04 } },
+	{ 0x20, { 0x01, 0x02, 0x01, 0x01, 0x01 } },
+	{ 0x21, { 0x08, 0x08, 0x0a, 0x0a, 0x0a } },
+	{ 0x22, { 0x06, 0x06, 0x04, 0x05, 0x05 } },
+	{ 0x23, { 0x06, 0x06, 0x05, 0x03, 0x05 } },
+	{ 0x24, { 0x08, 0x08, 0x05, 0x07, 0x07 } },
+	{ 0x25, { 0x16, 0x10, 0x10, 0x0a, 0x10 } },
+	{ 0x26, { 0x14, 0x14, 0x04, 0x04, 0x04 } },
+	{ 0x27, { 0x58, 0x58, 0x58, 0x5c, 0x58 } },
+	{ 0x28, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+	{ 0x29, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+	{ 0x2a, { 0x08, 0x0a, 0x08, 0x08, 0x08 } },
+	{ 0x2b, { 0x08, 0x08, 0x08, 0x08, 0x08 } },
+	{ 0x2c, { 0x06, 0x06, 0x06, 0x06, 0x06 } },
+	{ 0x2d, { 0x05, 0x06, 0x06, 0x06, 0x06 } },
+	{ 0x2e, { 0x21, 0x21, 0x21, 0x21, 0x21 } },
+	{ 0x2f, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0x30, { 0x14, 0x14, 0x14, 0x14, 0x14 } },
+	{ 0x33, { 0xb7, 0xb7, 0xb7, 0xb7, 0xb7 } },
+	{ 0x34, { 0x81, 0x81, 0x81, 0x81, 0x81 } },
+	{ 0x35, { 0x80, 0x80, 0x80, 0x80, 0x80 } },
+	{ 0x37, { 0x70, 0x70, 0x70, 0x70, 0x70 } },
+	{ 0x38, { 0x04, 0x04, 0x02, 0x02, 0x02 } },
+	{ 0x39, { 0x07, 0x07, 0x05, 0x05, 0x05 } },
+	{ 0x3a, { 0x06, 0x06, 0x06, 0x06, 0x06 } },
+	{ 0x3b, { 0x03, 0x03, 0x03, 0x03, 0x03 } },
+	{ 0x3c, { 0x07, 0x06, 0x04, 0x04, 0x04 } },
+	{ 0x3d, { 0xf0, 0xf0, 0xf0, 0xf0, 0x80 } },
+	{ 0x3e, { 0x60, 0x60, 0x60, 0x60, 0xff } },
+	{ 0x3f, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0x40, { 0x5b, 0x5b, 0x5b, 0x57, 0x50 } },
+	{ 0x41, { 0x30, 0x30, 0x30, 0x30, 0x18 } },
+	{ 0x42, { 0x20, 0x20, 0x20, 0x00, 0x30 } },
+	{ 0x43, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0x44, { 0x3f, 0x3f, 0x3f, 0x3f, 0x3f } },
+	{ 0x45, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0x46, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+	{ 0x47, { 0x00, 0x00, 0x95, 0x00, 0x95 } },
+	{ 0x48, { 0xc0, 0xc0, 0xc0, 0xc0, 0xc0 } },
+	{ 0x49, { 0xc0, 0xc0, 0xc0, 0xc0, 0xc0 } },
+	{ 0x4a, { 0x40, 0x40, 0x33, 0x11, 0x11 } },
+	{ 0x4b, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
+	{ 0x4c, { 0x40, 0x40, 0x99, 0x11, 0x11 } },
+	{ 0x4d, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
+	{ 0x4e, { 0x40, 0x40, 0x66, 0x77, 0x77 } },
+	{ 0x4f, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
+	{ 0x50, { 0x40, 0x40, 0x88, 0x33, 0x11 } },
+	{ 0x51, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
+	{ 0x52, { 0x40, 0x40, 0x88, 0x02, 0x02 } },
+	{ 0x53, { 0x40, 0x40, 0x00, 0x02, 0x02 } },
+	{ 0x54, { 0x00, 0x00, 0x88, 0x33, 0x33 } },
+	{ 0x55, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
+	{ 0x56, { 0x00, 0x00, 0x00, 0x0b, 0x00 } },
+	{ 0x57, { 0x40, 0x40, 0x0a, 0x0b, 0x0a } },
+	{ 0x58, { 0xaa, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0x59, { 0x7a, 0x40, 0x02, 0x02, 0x02 } },
+	{ 0x5a, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
+	{ 0x5b, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
+	{ 0x5c, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
+	{ 0x5d, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
+	{ 0x5e, { 0xc0, 0xc0, 0xc0, 0xff, 0xc0 } },
+	{ 0x5f, { 0xc0, 0xc0, 0xc0, 0xff, 0xc0 } },
+	{ 0x60, { 0x40, 0x40, 0x00, 0x30, 0x30 } },
+	{ 0x61, { 0x40, 0x40, 0x10, 0x30, 0x30 } },
+	{ 0x62, { 0x40, 0x40, 0x00, 0x30, 0x30 } },
+	{ 0x63, { 0x40, 0x40, 0x05, 0x30, 0x30 } },
+	{ 0x64, { 0x40, 0x40, 0x06, 0x00, 0x30 } },
+	{ 0x65, { 0x40, 0x40, 0x06, 0x08, 0x30 } },
+	{ 0x66, { 0x40, 0x40, 0x00, 0x00, 0x20 } },
+	{ 0x67, { 0x40, 0x40, 0x01, 0x04, 0x20 } },
+	{ 0x68, { 0x00, 0x00, 0x30, 0x00, 0x20 } },
+	{ 0x69, { 0xa0, 0xa0, 0x00, 0x08, 0x20 } },
+	{ 0x6a, { 0x00, 0x00, 0x30, 0x00, 0x25 } },
+	{ 0x6b, { 0xa0, 0xa0, 0x00, 0x06, 0x25 } },
+	{ 0x6c, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0x6d, { 0xa0, 0x60, 0x0c, 0x03, 0x0c } },
+	{ 0x6e, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0x6f, { 0xa0, 0x60, 0x04, 0x01, 0x04 } },
+	{ 0x70, { 0x58, 0x58, 0xaa, 0xaa, 0xaa } },
+	{ 0x71, { 0x58, 0x58, 0xaa, 0xaa, 0xaa } },
+	{ 0x72, { 0x58, 0x58, 0xff, 0xff, 0xff } },
+	{ 0x73, { 0x58, 0x58, 0xff, 0xff, 0xff } },
+	{ 0x74, { 0x06, 0x06, 0x09, 0x05, 0x05 } },
+	{ 0x75, { 0x06, 0x06, 0x0a, 0x10, 0x10 } },
+	{ 0x76, { 0x10, 0x10, 0x06, 0x0a, 0x0a } },
+	{ 0x77, { 0x12, 0x18, 0x28, 0x10, 0x28 } },
+	{ 0x78, { 0xf8, 0xf8, 0xf8, 0xf8, 0xf8 } },
+	{ 0x79, { 0x15, 0x15, 0x03, 0x03, 0x03 } },
+	{ 0x7a, { 0x02, 0x02, 0x01, 0x04, 0x03 } },
+	{ 0x7b, { 0x01, 0x02, 0x03, 0x03, 0x03 } },
+	{ 0x7c, { 0x28, 0x28, 0x28, 0x28, 0x28 } },
+	{ 0x7f, { 0x25, 0x92, 0x5f, 0x17, 0x2d } },
+	{ 0x80, { 0x64, 0x64, 0x64, 0x74, 0x64 } },
+	{ 0x83, { 0x06, 0x03, 0x04, 0x04, 0x04 } },
+	{ 0x84, { 0xff, 0xff, 0xff, 0xff, 0xff } },
+	{ 0x85, { 0x05, 0x05, 0x05, 0x05, 0x05 } },
+	{ 0x86, { 0x00, 0x00, 0x11, 0x11, 0x11 } },
+	{ 0x87, { 0x03, 0x03, 0x03, 0x03, 0x03 } },
+	{ 0x88, { 0x09, 0x09, 0x09, 0x09, 0x09 } },
+	{ 0x89, { 0x20, 0x20, 0x30, 0x20, 0x20 } },
+	{ 0x8a, { 0x03, 0x03, 0x02, 0x03, 0x02 } },
+	{ 0x8b, { 0x00, 0x07, 0x09, 0x00, 0x09 } },
+	{ 0x8c, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0x8d, { 0x4f, 0x4f, 0x4f, 0x3f, 0x4f } },
+	{ 0x8e, { 0xf0, 0xf0, 0x60, 0xf0, 0xa0 } },
+	{ 0x8f, { 0xe8, 0xe8, 0xe8, 0xe8, 0xe8 } },
+	{ 0x90, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
+	{ 0x91, { 0x40, 0x40, 0x70, 0x70, 0x10 } },
+	{ 0x92, { 0x00, 0x00, 0x00, 0x00, 0x04 } },
+	{ 0x93, { 0x60, 0x60, 0x60, 0x60, 0x60 } },
+	{ 0x94, { 0x00, 0x00, 0x00, 0x00, 0x03 } },
+	{ 0x95, { 0x09, 0x09, 0x47, 0x47, 0x47 } },
+	{ 0x96, { 0x80, 0xa0, 0xa0, 0x40, 0xa0 } },
+	{ 0x97, { 0x60, 0x60, 0x60, 0x60, 0x60 } },
+	{ 0x98, { 0x50, 0x50, 0x50, 0x30, 0x50 } },
+	{ 0x99, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
+	{ 0x9a, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0x9b, { 0x40, 0x40, 0x40, 0x30, 0x40 } },
+	{ 0x9c, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xa0, { 0xf0, 0xf0, 0xf0, 0xf0, 0xf0 } },
+	{ 0xa1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xa2, { 0x30, 0x30, 0x00, 0x30, 0x00 } },
+	{ 0xa3, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xa4, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xa5, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xa6, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xa7, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xa8, { 0x77, 0x77, 0x77, 0x77, 0x77 } },
+	{ 0xa9, { 0x02, 0x02, 0x02, 0x02, 0x02 } },
+	{ 0xaa, { 0x40, 0x40, 0x40, 0x40, 0x40 } },
+	{ 0xac, { 0x1f, 0x1f, 0x1f, 0x1f, 0x1f } },
+	{ 0xad, { 0x14, 0x14, 0x14, 0x14, 0x14 } },
+	{ 0xae, { 0x78, 0x78, 0x78, 0x78, 0x78 } },
+	{ 0xaf, { 0x06, 0x06, 0x06, 0x06, 0x07 } },
+	{ 0xb0, { 0x1b, 0x1b, 0x1b, 0x19, 0x1b } },
+	{ 0xb1, { 0x18, 0x17, 0x17, 0x18, 0x17 } },
+	{ 0xb2, { 0x35, 0x82, 0x82, 0x38, 0x82 } },
+	{ 0xb3, { 0xb6, 0xce, 0xc7, 0x5c, 0xb0 } },
+	{ 0xb4, { 0x3f, 0x3e, 0x3e, 0x3f, 0x3e } },
+	{ 0xb5, { 0x70, 0x58, 0x50, 0x68, 0x50 } },
+	{ 0xb6, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xb7, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xb8, { 0x03, 0x03, 0x01, 0x01, 0x01 } },
+	{ 0xb9, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xba, { 0x06, 0x06, 0x0a, 0x05, 0x0a } },
+	{ 0xbb, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xbc, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xbd, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xbe, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xbf, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xc0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xc1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xc2, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xc3, { 0x00, 0x00, 0x88, 0x66, 0x88 } },
+	{ 0xc4, { 0x10, 0x10, 0x00, 0x00, 0x00 } },
+	{ 0xc5, { 0x00, 0x00, 0x44, 0x60, 0x44 } },
+	{ 0xc6, { 0x10, 0x0a, 0x00, 0x00, 0x00 } },
+	{ 0xc7, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xc8, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xc9, { 0x90, 0x04, 0x00, 0x00, 0x00 } },
+	{ 0xca, { 0x90, 0x08, 0x01, 0x01, 0x01 } },
+	{ 0xcb, { 0xa0, 0x04, 0x00, 0x44, 0x00 } },
+	{ 0xcc, { 0xa0, 0x10, 0x03, 0x00, 0x03 } },
+	{ 0xcd, { 0x06, 0x06, 0x06, 0x05, 0x06 } },
+	{ 0xce, { 0x05, 0x05, 0x01, 0x01, 0x01 } },
+	{ 0xcf, { 0x40, 0x20, 0x18, 0x18, 0x18 } },
+	{ 0xd0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xd1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xd2, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xd3, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xd4, { 0x05, 0x05, 0x05, 0x05, 0x05 } },
+	{ 0xd5, { 0x05, 0x05, 0x05, 0x03, 0x05 } },
+	{ 0xd6, { 0xac, 0x22, 0xca, 0x8f, 0xca } },
+	{ 0xd7, { 0x20, 0x20, 0x20, 0x20, 0x20 } },
+	{ 0xd8, { 0x01, 0x01, 0x01, 0x01, 0x01 } },
+	{ 0xd9, { 0x00, 0x00, 0x0f, 0x00, 0x0f } },
+	{ 0xda, { 0x00, 0xff, 0xff, 0x0e, 0xff } },
+	{ 0xdb, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+	{ 0xdc, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+	{ 0xdd, { 0x05, 0x05, 0x05, 0x05, 0x05 } },
+	{ 0xde, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+	{ 0xdf, { 0x42, 0x42, 0x44, 0x44, 0x04 } },
+	{ 0xe0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xe1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xe2, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xe3, { 0x00, 0x00, 0x26, 0x06, 0x26 } },
+	{ 0xe4, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xe5, { 0x01, 0x0a, 0x01, 0x01, 0x01 } },
+	{ 0xe6, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xe7, { 0x08, 0x08, 0x08, 0x08, 0x08 } },
+	{ 0xe8, { 0x63, 0x63, 0x63, 0x63, 0x63 } },
+	{ 0xe9, { 0x59, 0x59, 0x59, 0x59, 0x59 } },
+	{ 0xea, { 0x80, 0x80, 0x20, 0x80, 0x80 } },
+	{ 0xeb, { 0x37, 0x37, 0x78, 0x37, 0x77 } },
+	{ 0xec, { 0x1f, 0x1f, 0x25, 0x25, 0x25 } },
+	{ 0xed, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+	{ 0xee, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+	{ 0xef, { 0x70, 0x70, 0x58, 0x38, 0x58 } },
+	{ 0xf0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+};
+
+#endif /* HD29L2_PRIV */
diff --git a/drivers/media/dvb-frontends/isl6405.c b/drivers/media/dvb-frontends/isl6405.c
new file mode 100644
index 0000000..33d33f4
--- /dev/null
+++ b/drivers/media/dvb-frontends/isl6405.c
@@ -0,0 +1,164 @@
+/*
+ * isl6405.c - driver for dual lnb supply and control ic ISL6405
+ *
+ * Copyright (C) 2008 Hartmut Hackmann
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "isl6405.h"
+
+struct isl6405 {
+	u8			config;
+	u8			override_or;
+	u8			override_and;
+	struct i2c_adapter	*i2c;
+	u8			i2c_addr;
+};
+
+static int isl6405_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv;
+	struct i2c_msg msg = {	.addr = isl6405->i2c_addr, .flags = 0,
+				.buf = &isl6405->config,
+				.len = sizeof(isl6405->config) };
+
+	if (isl6405->override_or & 0x80) {
+		isl6405->config &= ~(ISL6405_VSEL2 | ISL6405_EN2);
+		switch (voltage) {
+		case SEC_VOLTAGE_OFF:
+			break;
+		case SEC_VOLTAGE_13:
+			isl6405->config |= ISL6405_EN2;
+			break;
+		case SEC_VOLTAGE_18:
+			isl6405->config |= (ISL6405_EN2 | ISL6405_VSEL2);
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		isl6405->config &= ~(ISL6405_VSEL1 | ISL6405_EN1);
+		switch (voltage) {
+		case SEC_VOLTAGE_OFF:
+			break;
+		case SEC_VOLTAGE_13:
+			isl6405->config |= ISL6405_EN1;
+			break;
+		case SEC_VOLTAGE_18:
+			isl6405->config |= (ISL6405_EN1 | ISL6405_VSEL1);
+			break;
+		default:
+			return -EINVAL;
+		};
+	}
+	isl6405->config |= isl6405->override_or;
+	isl6405->config &= isl6405->override_and;
+
+	return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int isl6405_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+	struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv;
+	struct i2c_msg msg = {	.addr = isl6405->i2c_addr, .flags = 0,
+				.buf = &isl6405->config,
+				.len = sizeof(isl6405->config) };
+
+	if (isl6405->override_or & 0x80) {
+		if (arg)
+			isl6405->config |= ISL6405_LLC2;
+		else
+			isl6405->config &= ~ISL6405_LLC2;
+	} else {
+		if (arg)
+			isl6405->config |= ISL6405_LLC1;
+		else
+			isl6405->config &= ~ISL6405_LLC1;
+	}
+	isl6405->config |= isl6405->override_or;
+	isl6405->config &= isl6405->override_and;
+
+	return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void isl6405_release(struct dvb_frontend *fe)
+{
+	/* power off */
+	isl6405_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+	/* free */
+	kfree(fe->sec_priv);
+	fe->sec_priv = NULL;
+}
+
+struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c,
+				    u8 i2c_addr, u8 override_set, u8 override_clear)
+{
+	struct isl6405 *isl6405 = kmalloc(sizeof(struct isl6405), GFP_KERNEL);
+	if (!isl6405)
+		return NULL;
+
+	/* default configuration */
+	if (override_set & 0x80)
+		isl6405->config = ISL6405_ISEL2;
+	else
+		isl6405->config = ISL6405_ISEL1;
+	isl6405->i2c = i2c;
+	isl6405->i2c_addr = i2c_addr;
+	fe->sec_priv = isl6405;
+
+	/* bits which should be forced to '1' */
+	isl6405->override_or = override_set;
+
+	/* bits which should be forced to '0' */
+	isl6405->override_and = ~override_clear;
+
+	/* detect if it is present or not */
+	if (isl6405_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+		kfree(isl6405);
+		fe->sec_priv = NULL;
+		return NULL;
+	}
+
+	/* install release callback */
+	fe->ops.release_sec = isl6405_release;
+
+	/* override frontend ops */
+	fe->ops.set_voltage = isl6405_set_voltage;
+	fe->ops.enable_high_lnb_voltage = isl6405_enable_high_lnb_voltage;
+
+	return fe;
+}
+EXPORT_SYMBOL(isl6405_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6405");
+MODULE_AUTHOR("Hartmut Hackmann & Oliver Endriss");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/isl6405.h b/drivers/media/dvb-frontends/isl6405.h
new file mode 100644
index 0000000..1c793d3
--- /dev/null
+++ b/drivers/media/dvb-frontends/isl6405.h
@@ -0,0 +1,74 @@
+/*
+ * isl6405.h - driver for dual lnb supply and control ic ISL6405
+ *
+ * Copyright (C) 2008 Hartmut Hackmann
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _ISL6405_H
+#define _ISL6405_H
+
+#include <linux/dvb/frontend.h>
+
+/* system register bits */
+
+/* this bit selects register (control) 1 or 2
+   note that the bit maps are different */
+
+#define ISL6405_SR	0x80
+
+/* SR = 0 */
+#define ISL6405_OLF1	0x01
+#define ISL6405_EN1	0x02
+#define ISL6405_VSEL1	0x04
+#define ISL6405_LLC1	0x08
+#define ISL6405_ENT1	0x10
+#define ISL6405_ISEL1	0x20
+#define ISL6405_DCL	0x40
+
+/* SR = 1 */
+#define ISL6405_OLF2	0x01
+#define ISL6405_OTF	0x02
+#define ISL6405_EN2	0x04
+#define ISL6405_VSEL2	0x08
+#define ISL6405_LLC2	0x10
+#define ISL6405_ENT2	0x20
+#define ISL6405_ISEL2	0x40
+
+#if defined(CONFIG_DVB_ISL6405) || (defined(CONFIG_DVB_ISL6405_MODULE) && defined(MODULE))
+/* override_set and override_clear control which system register bits (above)
+ * to always set & clear
+ */
+extern struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c,
+					   u8 i2c_addr, u8 override_set, u8 override_clear);
+#else
+static inline struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe,
+						  struct i2c_adapter *i2c, u8 i2c_addr,
+						  u8 override_set, u8 override_clear)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_ISL6405 */
+
+#endif
diff --git a/drivers/media/dvb-frontends/isl6421.c b/drivers/media/dvb-frontends/isl6421.c
new file mode 100644
index 0000000..684c8ec
--- /dev/null
+++ b/drivers/media/dvb-frontends/isl6421.c
@@ -0,0 +1,141 @@
+/*
+ * isl6421.h - driver for lnb supply and control ic ISL6421
+ *
+ * Copyright (C) 2006 Andrew de Quincey
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "isl6421.h"
+
+struct isl6421 {
+	u8			config;
+	u8			override_or;
+	u8			override_and;
+	struct i2c_adapter	*i2c;
+	u8			i2c_addr;
+};
+
+static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv;
+	struct i2c_msg msg = {	.addr = isl6421->i2c_addr, .flags = 0,
+				.buf = &isl6421->config,
+				.len = sizeof(isl6421->config) };
+
+	isl6421->config &= ~(ISL6421_VSEL1 | ISL6421_EN1);
+
+	switch(voltage) {
+	case SEC_VOLTAGE_OFF:
+		break;
+	case SEC_VOLTAGE_13:
+		isl6421->config |= ISL6421_EN1;
+		break;
+	case SEC_VOLTAGE_18:
+		isl6421->config |= (ISL6421_EN1 | ISL6421_VSEL1);
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	isl6421->config |= isl6421->override_or;
+	isl6421->config &= isl6421->override_and;
+
+	return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+	struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv;
+	struct i2c_msg msg = {	.addr = isl6421->i2c_addr, .flags = 0,
+				.buf = &isl6421->config,
+				.len = sizeof(isl6421->config) };
+
+	if (arg)
+		isl6421->config |= ISL6421_LLC1;
+	else
+		isl6421->config &= ~ISL6421_LLC1;
+
+	isl6421->config |= isl6421->override_or;
+	isl6421->config &= isl6421->override_and;
+
+	return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void isl6421_release(struct dvb_frontend *fe)
+{
+	/* power off */
+	isl6421_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+	/* free */
+	kfree(fe->sec_priv);
+	fe->sec_priv = NULL;
+}
+
+struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+		   u8 override_set, u8 override_clear)
+{
+	struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL);
+	if (!isl6421)
+		return NULL;
+
+	/* default configuration */
+	isl6421->config = ISL6421_ISEL1;
+	isl6421->i2c = i2c;
+	isl6421->i2c_addr = i2c_addr;
+	fe->sec_priv = isl6421;
+
+	/* bits which should be forced to '1' */
+	isl6421->override_or = override_set;
+
+	/* bits which should be forced to '0' */
+	isl6421->override_and = ~override_clear;
+
+	/* detect if it is present or not */
+	if (isl6421_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+		kfree(isl6421);
+		fe->sec_priv = NULL;
+		return NULL;
+	}
+
+	/* install release callback */
+	fe->ops.release_sec = isl6421_release;
+
+	/* override frontend ops */
+	fe->ops.set_voltage = isl6421_set_voltage;
+	fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage;
+
+	return fe;
+}
+EXPORT_SYMBOL(isl6421_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6421");
+MODULE_AUTHOR("Andrew de Quincey & Oliver Endriss");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/isl6421.h b/drivers/media/dvb-frontends/isl6421.h
new file mode 100644
index 0000000..47e4518
--- /dev/null
+++ b/drivers/media/dvb-frontends/isl6421.h
@@ -0,0 +1,55 @@
+/*
+ * isl6421.h - driver for lnb supply and control ic ISL6421
+ *
+ * Copyright (C) 2006 Andrew de Quincey
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _ISL6421_H
+#define _ISL6421_H
+
+#include <linux/dvb/frontend.h>
+
+/* system register bits */
+#define ISL6421_OLF1	0x01
+#define ISL6421_EN1	0x02
+#define ISL6421_VSEL1	0x04
+#define ISL6421_LLC1	0x08
+#define ISL6421_ENT1	0x10
+#define ISL6421_ISEL1	0x20
+#define ISL6421_DCL	0x40
+
+#if defined(CONFIG_DVB_ISL6421) || (defined(CONFIG_DVB_ISL6421_MODULE) && defined(MODULE))
+/* override_set and override_clear control which system register bits (above) to always set & clear */
+extern struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+			  u8 override_set, u8 override_clear);
+#else
+static inline struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+						  u8 override_set, u8 override_clear)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_ISL6421
+
+#endif
diff --git a/drivers/media/dvb-frontends/isl6423.c b/drivers/media/dvb-frontends/isl6423.c
new file mode 100644
index 0000000..dca5beb
--- /dev/null
+++ b/drivers/media/dvb-frontends/isl6423.c
@@ -0,0 +1,308 @@
+/*
+	Intersil ISL6423 SEC and LNB Power supply controller
+
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "isl6423.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "Set Verbosity level");
+
+#define FE_ERROR				0
+#define FE_NOTICE				1
+#define FE_INFO					2
+#define FE_DEBUG				3
+#define FE_DEBUGREG				4
+
+#define dprintk(__y, __z, format, arg...) do {						\
+	if (__z) {									\
+		if	((verbose > FE_ERROR) && (verbose > __y))			\
+			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);		\
+		else if	((verbose > FE_NOTICE) && (verbose > __y))			\
+			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
+		else if ((verbose > FE_INFO) && (verbose > __y))			\
+			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);		\
+		else if ((verbose > FE_DEBUG) && (verbose > __y))			\
+			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
+	} else {									\
+		if (verbose > __y)							\
+			printk(format, ##arg);						\
+	}										\
+} while (0)
+
+struct isl6423_dev {
+	const struct isl6423_config	*config;
+	struct i2c_adapter		*i2c;
+
+	u8 reg_3;
+	u8 reg_4;
+
+	unsigned int verbose;
+};
+
+static int isl6423_write(struct isl6423_dev *isl6423, u8 reg)
+{
+	struct i2c_adapter *i2c = isl6423->i2c;
+	u8 addr			= isl6423->config->addr;
+	int err = 0;
+
+	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = &reg, .len = 1 };
+
+	dprintk(FE_DEBUG, 1, "write reg %02X", reg);
+	err = i2c_transfer(i2c, &msg, 1);
+	if (err < 0)
+		goto exit;
+	return 0;
+
+exit:
+	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+	return err;
+}
+
+static int isl6423_set_modulation(struct dvb_frontend *fe)
+{
+	struct isl6423_dev *isl6423		= (struct isl6423_dev *) fe->sec_priv;
+	const struct isl6423_config *config	= isl6423->config;
+	int err = 0;
+	u8 reg_2 = 0;
+
+	reg_2 = 0x01 << 5;
+
+	if (config->mod_extern)
+		reg_2 |= (1 << 3);
+	else
+		reg_2 |= (1 << 4);
+
+	err = isl6423_write(isl6423, reg_2);
+	if (err < 0)
+		goto exit;
+	return 0;
+
+exit:
+	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+	return err;
+}
+
+static int isl6423_voltage_boost(struct dvb_frontend *fe, long arg)
+{
+	struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
+	u8 reg_3 = isl6423->reg_3;
+	u8 reg_4 = isl6423->reg_4;
+	int err = 0;
+
+	if (arg) {
+		/* EN = 1, VSPEN = 1, VBOT = 1 */
+		reg_4 |= (1 << 4);
+		reg_4 |= 0x1;
+		reg_3 |= (1 << 3);
+	} else {
+		/* EN = 1, VSPEN = 1, VBOT = 0 */
+		reg_4 |= (1 << 4);
+		reg_4 &= ~0x1;
+		reg_3 |= (1 << 3);
+	}
+	err = isl6423_write(isl6423, reg_3);
+	if (err < 0)
+		goto exit;
+
+	err = isl6423_write(isl6423, reg_4);
+	if (err < 0)
+		goto exit;
+
+	isl6423->reg_3 = reg_3;
+	isl6423->reg_4 = reg_4;
+
+	return 0;
+exit:
+	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+	return err;
+}
+
+
+static int isl6423_set_voltage(struct dvb_frontend *fe,
+			       enum fe_sec_voltage voltage)
+{
+	struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
+	u8 reg_3 = isl6423->reg_3;
+	u8 reg_4 = isl6423->reg_4;
+	int err = 0;
+
+	switch (voltage) {
+	case SEC_VOLTAGE_OFF:
+		/* EN = 0 */
+		reg_4 &= ~(1 << 4);
+		break;
+
+	case SEC_VOLTAGE_13:
+		/* EN = 1, VSPEN = 1, VTOP = 0, VBOT = 0 */
+		reg_4 |= (1 << 4);
+		reg_4 &= ~0x3;
+		reg_3 |= (1 << 3);
+		break;
+
+	case SEC_VOLTAGE_18:
+		/* EN = 1, VSPEN = 1, VTOP = 1, VBOT = 0 */
+		reg_4 |= (1 << 4);
+		reg_4 |=  0x2;
+		reg_4 &= ~0x1;
+		reg_3 |= (1 << 3);
+		break;
+
+	default:
+		break;
+	}
+	err = isl6423_write(isl6423, reg_3);
+	if (err < 0)
+		goto exit;
+
+	err = isl6423_write(isl6423, reg_4);
+	if (err < 0)
+		goto exit;
+
+	isl6423->reg_3 = reg_3;
+	isl6423->reg_4 = reg_4;
+
+	return 0;
+exit:
+	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+	return err;
+}
+
+static int isl6423_set_current(struct dvb_frontend *fe)
+{
+	struct isl6423_dev *isl6423		= (struct isl6423_dev *) fe->sec_priv;
+	u8 reg_3 = isl6423->reg_3;
+	const struct isl6423_config *config	= isl6423->config;
+	int err = 0;
+
+	switch (config->current_max) {
+	case SEC_CURRENT_275m:
+		/* 275mA */
+		/* ISELH = 0, ISELL = 0 */
+		reg_3 &= ~0x3;
+		break;
+
+	case SEC_CURRENT_515m:
+		/* 515mA */
+		/* ISELH = 0, ISELL = 1 */
+		reg_3 &= ~0x2;
+		reg_3 |=  0x1;
+		break;
+
+	case SEC_CURRENT_635m:
+		/* 635mA */
+		/* ISELH = 1, ISELL = 0 */
+		reg_3 &= ~0x1;
+		reg_3 |=  0x2;
+		break;
+
+	case SEC_CURRENT_800m:
+		/* 800mA */
+		/* ISELH = 1, ISELL = 1 */
+		reg_3 |= 0x3;
+		break;
+	}
+
+	err = isl6423_write(isl6423, reg_3);
+	if (err < 0)
+		goto exit;
+
+	switch (config->curlim) {
+	case SEC_CURRENT_LIM_ON:
+		/* DCL = 0 */
+		reg_3 &= ~0x10;
+		break;
+
+	case SEC_CURRENT_LIM_OFF:
+		/* DCL = 1 */
+		reg_3 |= 0x10;
+		break;
+	}
+
+	err = isl6423_write(isl6423, reg_3);
+	if (err < 0)
+		goto exit;
+
+	isl6423->reg_3 = reg_3;
+
+	return 0;
+exit:
+	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+	return err;
+}
+
+static void isl6423_release(struct dvb_frontend *fe)
+{
+	isl6423_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+	kfree(fe->sec_priv);
+	fe->sec_priv = NULL;
+}
+
+struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
+				    struct i2c_adapter *i2c,
+				    const struct isl6423_config *config)
+{
+	struct isl6423_dev *isl6423;
+
+	isl6423 = kzalloc(sizeof(struct isl6423_dev), GFP_KERNEL);
+	if (!isl6423)
+		return NULL;
+
+	isl6423->config	= config;
+	isl6423->i2c	= i2c;
+	fe->sec_priv	= isl6423;
+
+	/* SR3H = 0, SR3M = 1, SR3L = 0 */
+	isl6423->reg_3 = 0x02 << 5;
+	/* SR4H = 0, SR4M = 1, SR4L = 1 */
+	isl6423->reg_4 = 0x03 << 5;
+
+	if (isl6423_set_current(fe))
+		goto exit;
+
+	if (isl6423_set_modulation(fe))
+		goto exit;
+
+	fe->ops.release_sec		= isl6423_release;
+	fe->ops.set_voltage		= isl6423_set_voltage;
+	fe->ops.enable_high_lnb_voltage = isl6423_voltage_boost;
+	isl6423->verbose		= verbose;
+
+	return fe;
+
+exit:
+	kfree(isl6423);
+	fe->sec_priv = NULL;
+	return NULL;
+}
+EXPORT_SYMBOL(isl6423_attach);
+
+MODULE_DESCRIPTION("ISL6423 SEC");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/isl6423.h b/drivers/media/dvb-frontends/isl6423.h
new file mode 100644
index 0000000..e1a37fb
--- /dev/null
+++ b/drivers/media/dvb-frontends/isl6423.h
@@ -0,0 +1,63 @@
+/*
+	Intersil ISL6423 SEC and LNB Power supply controller
+
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __ISL_6423_H
+#define __ISL_6423_H
+
+#include <linux/dvb/frontend.h>
+
+enum isl6423_current {
+	SEC_CURRENT_275m = 0,
+	SEC_CURRENT_515m,
+	SEC_CURRENT_635m,
+	SEC_CURRENT_800m,
+};
+
+enum isl6423_curlim {
+	SEC_CURRENT_LIM_ON = 1,
+	SEC_CURRENT_LIM_OFF
+};
+
+struct isl6423_config {
+	enum isl6423_current current_max;
+	enum isl6423_curlim curlim;
+	u8 addr;
+	u8 mod_extern;
+};
+
+#if defined(CONFIG_DVB_ISL6423) || (defined(CONFIG_DVB_ISL6423_MODULE) && defined(MODULE))
+
+
+extern struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
+					   struct i2c_adapter *i2c,
+					   const struct isl6423_config *config);
+
+#else
+static inline struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
+						  struct i2c_adapter *i2c,
+						  const struct isl6423_config *config)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+#endif /* CONFIG_DVB_ISL6423 */
+
+#endif /* __ISL_6423_H */
diff --git a/drivers/media/dvb-frontends/it913x-fe-priv.h b/drivers/media/dvb-frontends/it913x-fe-priv.h
new file mode 100644
index 0000000..eb6fd8a
--- /dev/null
+++ b/drivers/media/dvb-frontends/it913x-fe-priv.h
@@ -0,0 +1,1051 @@
+
+struct it913xset {	u32 pro;
+			u32 address;
+			u8 reg[15];
+			u8 count;
+};
+
+struct adctable {	u32 adcFrequency;
+			u32 bandwidth;
+			u32 coeff_1_2048;
+			u32 coeff_1_4096;
+			u32 coeff_1_8191;
+			u32 coeff_1_8192;
+			u32 coeff_1_8193;
+			u32 coeff_2_2k;
+			u32 coeff_2_4k;
+			u32 coeff_2_8k;
+			u16 bfsfcw_fftinx_ratio;
+			u16 fftinx_bfsfcw_ratio;
+};
+
+/* clock and coeff tables only table 3 is used with IT9137*/
+/* TODO other tables relate AF9035 may be removed */
+static struct adctable tab1[] = {
+	{	20156250, 6000000,
+		0x02b8ba6e, 0x015c5d37, 0x00ae340d, 0x00ae2e9b, 0x00ae292a,
+		0x015c5d37, 0x00ae2e9b, 0x0057174e, 0x02f1, 0x015c	},
+	{	20156250, 7000000,
+		0x032cd980, 0x01966cc0, 0x00cb3cba, 0x00cb3660, 0x00cb3007,
+		0x01966cc0, 0x00cb3660, 0x00659b30, 0x0285, 0x0196	},
+	{	20156250, 8000000,
+		0x03a0f893, 0x01d07c49, 0x00e84567, 0x00e83e25, 0x00e836e3,
+		0x01d07c49, 0x00e83e25, 0x00741f12, 0x0234, 0x01d0	},
+	{	20156250, 5000000,
+		0x02449b5c, 0x01224dae, 0x00912b60, 0x009126d7, 0x0091224e,
+		0x01224dae, 0x009126d7, 0x0048936b, 0x0387, 0x0122	}
+};
+
+static struct adctable tab2[] = {
+	{	20187500, 6000000,
+		0x02b7a654, 0x015bd32a, 0x00adef04, 0x00ade995, 0x00ade426,
+		0x015bd32a, 0x00ade995, 0x0056f4ca, 0x02f2, 0x015c	},
+	{	20187500, 7000000,
+		0x032b9761, 0x0195cbb1, 0x00caec30, 0x00cae5d8, 0x00cadf81,
+		0x0195cbb1, 0x00cae5d8, 0x006572ec, 0x0286, 0x0196	},
+	{	20187500, 8000000,
+		0x039f886f, 0x01cfc438, 0x00e7e95b, 0x00e7e21c, 0x00e7dadd,
+		0x01cfc438, 0x00e7e21c, 0x0073f10e, 0x0235, 0x01d0	},
+	{	20187500, 5000000,
+		0x0243b546, 0x0121daa3, 0x0090f1d9, 0x0090ed51, 0x0090e8ca,
+		0x0121daa3, 0x0090ed51, 0x004876a9, 0x0388, 0x0122	}
+
+};
+
+static struct adctable tab3[] = {
+	{	20250000, 6000000,
+		0x02b580ad, 0x015ac057, 0x00ad6597, 0x00ad602b, 0x00ad5ac1,
+		0x015ac057, 0x00ad602b, 0x0056b016, 0x02f4, 0x015b	},
+	{	20250000, 7000000,
+		0x03291620, 0x01948b10, 0x00ca4bda, 0x00ca4588, 0x00ca3f36,
+		0x01948b10, 0x00ca4588, 0x006522c4, 0x0288, 0x0195	},
+	{	20250000, 8000000,
+		0x039cab92, 0x01ce55c9, 0x00e7321e, 0x00e72ae4, 0x00e723ab,
+		0x01ce55c9, 0x00e72ae4, 0x00739572, 0x0237, 0x01ce	},
+	{	20250000, 5000000,
+		0x0241eb3b, 0x0120f59e, 0x00907f53, 0x00907acf, 0x0090764b,
+		0x0120f59e, 0x00907acf, 0x00483d67, 0x038b, 0x0121	}
+
+};
+
+static struct adctable tab4[] = {
+	{	20583333, 6000000,
+		0x02aa4598, 0x015522cc, 0x00aa96bb, 0x00aa9166, 0x00aa8c12,
+		0x015522cc, 0x00aa9166, 0x005548b3, 0x0300, 0x0155	},
+	{	20583333, 7000000,
+		0x031bfbdc, 0x018dfdee, 0x00c7052f, 0x00c6fef7, 0x00c6f8bf,
+		0x018dfdee, 0x00c6fef7, 0x00637f7b, 0x0293, 0x018e	},
+	{	20583333, 8000000,
+		0x038db21f, 0x01c6d910, 0x00e373a3, 0x00e36c88, 0x00e3656d,
+		0x01c6d910, 0x00e36c88, 0x0071b644, 0x0240, 0x01c7	},
+	{	20583333, 5000000,
+		0x02388f54, 0x011c47aa, 0x008e2846, 0x008e23d5, 0x008e1f64,
+		0x011c47aa, 0x008e23d5, 0x004711ea, 0x039a, 0x011c	}
+
+};
+
+static struct adctable tab5[] = {
+	{	20416667, 6000000,
+		0x02afd765, 0x0157ebb3, 0x00abfb39, 0x00abf5d9, 0x00abf07a,
+		0x0157ebb3, 0x00abf5d9, 0x0055faed, 0x02fa, 0x0158	},
+	{	20416667, 7000000,
+		0x03227b4b, 0x01913da6, 0x00c8a518, 0x00c89ed3, 0x00c8988e,
+		0x01913da6, 0x00c89ed3, 0x00644f69, 0x028d, 0x0191	},
+	{	20416667, 8000000,
+		0x03951f32, 0x01ca8f99, 0x00e54ef7, 0x00e547cc, 0x00e540a2,
+		0x01ca8f99, 0x00e547cc, 0x0072a3e6, 0x023c, 0x01cb	},
+	{	20416667, 5000000,
+		0x023d337f, 0x011e99c0, 0x008f515a, 0x008f4ce0, 0x008f4865,
+		0x011e99c0, 0x008f4ce0, 0x0047a670, 0x0393, 0x011f	}
+
+};
+
+static struct adctable tab6[] = {
+	{	20480000, 6000000,
+		0x02adb6db, 0x0156db6e, 0x00ab7312, 0x00ab6db7, 0x00ab685c,
+		0x0156db6e, 0x00ab6db7, 0x0055b6db, 0x02fd, 0x0157	},
+	{	20480000, 7000000,
+		0x03200000, 0x01900000, 0x00c80640, 0x00c80000, 0x00c7f9c0,
+		0x01900000, 0x00c80000, 0x00640000, 0x028f, 0x0190	},
+	{	20480000, 8000000,
+		0x03924925, 0x01c92492, 0x00e4996e, 0x00e49249, 0x00e48b25,
+		0x01c92492, 0x00e49249, 0x00724925, 0x023d, 0x01c9	},
+	{	20480000, 5000000,
+		0x023b6db7, 0x011db6db, 0x008edfe5, 0x008edb6e, 0x008ed6f7,
+		0x011db6db, 0x008edb6e, 0x00476db7, 0x0396, 0x011e	}
+};
+
+static struct adctable tab7[] = {
+	{	20500000, 6000000,
+		0x02ad0b99, 0x015685cc, 0x00ab4840, 0x00ab42e6, 0x00ab3d8c,
+		0x015685cc, 0x00ab42e6, 0x0055a173, 0x02fd, 0x0157	},
+	{	20500000, 7000000,
+		0x031f3832, 0x018f9c19, 0x00c7d44b, 0x00c7ce0c, 0x00c7c7ce,
+		0x018f9c19, 0x00c7ce0c, 0x0063e706, 0x0290, 0x0190	},
+	{	20500000, 8000000,
+		0x039164cb, 0x01c8b266, 0x00e46056, 0x00e45933, 0x00e45210,
+		0x01c8b266, 0x00e45933, 0x00722c99, 0x023e, 0x01c9	},
+	{	20500000, 5000000,
+		0x023adeff, 0x011d6f80, 0x008ebc36, 0x008eb7c0, 0x008eb34a,
+		0x011d6f80, 0x008eb7c0, 0x00475be0, 0x0396, 0x011d	}
+
+};
+
+static struct adctable tab8[] = {
+	{	20625000, 6000000,
+		0x02a8e4bd, 0x0154725e, 0x00aa3e81, 0x00aa392f, 0x00aa33de,
+		0x0154725e, 0x00aa392f, 0x00551c98, 0x0302, 0x0154	},
+	{	20625000, 7000000,
+		0x031a6032, 0x018d3019, 0x00c69e41, 0x00c6980c, 0x00c691d8,
+		0x018d3019, 0x00c6980c, 0x00634c06, 0x0294, 0x018d	},
+	{	20625000, 8000000,
+		0x038bdba6, 0x01c5edd3, 0x00e2fe02, 0x00e2f6ea, 0x00e2efd2,
+		0x01c5edd3, 0x00e2f6ea, 0x00717b75, 0x0242, 0x01c6	},
+	{	20625000, 5000000,
+		0x02376948, 0x011bb4a4, 0x008ddec1, 0x008dda52, 0x008dd5e3,
+		0x011bb4a4, 0x008dda52, 0x0046ed29, 0x039c, 0x011c	}
+
+};
+
+struct table {
+		u32 xtal;
+		struct adctable *table;
+};
+
+static struct table fe_clockTable[] = {
+		{12000000, tab3},	/* 12.00MHz */
+		{20480000, tab6},	/* 20.48MHz */
+		{36000000, tab3},	/* 36.00MHz */
+		{30000000, tab1},	/* 30.00MHz */
+		{26000000, tab4},	/* 26.00MHz */
+		{28000000, tab5},	/* 28.00MHz */
+		{32000000, tab7},	/* 32.00MHz */
+		{34000000, tab2},	/* 34.00MHz */
+		{24000000, tab1},	/* 24.00MHz */
+		{22000000, tab8},	/* 22.00MHz */
+};
+
+/* fe get */
+fe_code_rate_t fe_code[] = {
+	FEC_1_2,
+	FEC_2_3,
+	FEC_3_4,
+	FEC_5_6,
+	FEC_7_8,
+	FEC_NONE,
+};
+
+fe_guard_interval_t fe_gi[] = {
+	GUARD_INTERVAL_1_32,
+	GUARD_INTERVAL_1_16,
+	GUARD_INTERVAL_1_8,
+	GUARD_INTERVAL_1_4,
+};
+
+fe_hierarchy_t fe_hi[] = {
+	HIERARCHY_NONE,
+	HIERARCHY_1,
+	HIERARCHY_2,
+	HIERARCHY_4,
+};
+
+fe_transmit_mode_t fe_mode[] = {
+	TRANSMISSION_MODE_2K,
+	TRANSMISSION_MODE_8K,
+	TRANSMISSION_MODE_4K,
+};
+
+fe_modulation_t fe_con[] = {
+	QPSK,
+	QAM_16,
+	QAM_64,
+};
+
+enum {
+	PRIORITY_HIGH = 0,	/* High-priority stream */
+	PRIORITY_LOW,	/* Low-priority stream */
+};
+
+/* Standard demodulator functions */
+static struct it913xset set_solo_fe[] = {
+	{PRO_LINK, GPIOH5_EN, {0x01}, 0x01},
+	{PRO_LINK, GPIOH5_ON, {0x01}, 0x01},
+	{PRO_LINK, GPIOH5_O, {0x00}, 0x01},
+	{PRO_LINK, GPIOH5_O, {0x01}, 0x01},
+	{PRO_LINK, DVBT_INTEN, {0x04}, 0x01},
+	{PRO_LINK, DVBT_ENABLE, {0x05}, 0x01},
+	{PRO_DMOD, MP2IF_MPEG_PAR_MODE, {0x00}, 0x01},
+	{PRO_LINK, HOSTB_MPEG_SER_MODE, {0x00}, 0x01},
+	{PRO_LINK, HOSTB_MPEG_PAR_MODE, {0x00}, 0x01},
+	{PRO_DMOD, DCA_UPPER_CHIP, {0x00}, 0x01},
+	{PRO_LINK, HOSTB_DCA_UPPER, {0x00}, 0x01},
+	{PRO_DMOD, DCA_LOWER_CHIP, {0x00}, 0x01},
+	{PRO_LINK, HOSTB_DCA_LOWER, {0x00}, 0x01},
+	{PRO_DMOD, DCA_PLATCH, {0x00}, 0x01},
+	{PRO_DMOD, DCA_FPGA_LATCH, {0x00}, 0x01},
+	{PRO_DMOD, DCA_STAND_ALONE, {0x01}, 0x01},
+	{PRO_DMOD, DCA_ENABLE, {0x00}, 0x01},
+	{PRO_DMOD, MP2IF_MPEG_PAR_MODE, {0x00}, 0x01},
+	{PRO_DMOD, BFS_FCW, {0x00, 0x00, 0x00}, 0x03},
+	{0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
+};
+
+
+static struct it913xset init_1[] = {
+	{PRO_LINK, LOCK3_OUT, {0x01}, 0x01},
+	{PRO_LINK, PADMISCDRSR, {0x01}, 0x01},
+	{PRO_LINK, PADMISCDR2, {0x00}, 0x01},
+	{PRO_DMOD, 0xec57, {0x00, 0x00}, 0x02},
+	{PRO_LINK, PADMISCDR4, {0x00}, 0x01}, /* Power up */
+	{PRO_LINK, PADMISCDR8, {0x00}, 0x01},
+	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+
+/* Version 1 types */
+static struct it913xset it9135_v1[] = {
+	{PRO_DMOD, 0x0051, {0x01}, 0x01},
+	{PRO_DMOD, 0x0070, {0x0a}, 0x01},
+	{PRO_DMOD, 0x007e, {0x04}, 0x01},
+	{PRO_DMOD, 0x0081, {0x0a}, 0x01},
+	{PRO_DMOD, 0x008a, {0x01}, 0x01},
+	{PRO_DMOD, 0x008e, {0x01}, 0x01},
+	{PRO_DMOD, 0x0092, {0x06}, 0x01},
+	{PRO_DMOD, 0x0099, {0x01}, 0x01},
+	{PRO_DMOD, 0x009f, {0xe1}, 0x01},
+	{PRO_DMOD, 0x00a0, {0xcf}, 0x01},
+	{PRO_DMOD, 0x00a3, {0x01}, 0x01},
+	{PRO_DMOD, 0x00a5, {0x01}, 0x01},
+	{PRO_DMOD, 0x00a6, {0x01}, 0x01},
+	{PRO_DMOD, 0x00a9, {0x00}, 0x01},
+	{PRO_DMOD, 0x00aa, {0x01}, 0x01},
+	{PRO_DMOD, 0x00b0, {0x01}, 0x01},
+	{PRO_DMOD, 0x00c2, {0x05}, 0x01},
+	{PRO_DMOD, 0x00c6, {0x19}, 0x01},
+	{PRO_DMOD, 0xf000, {0x0f}, 0x01},
+	{PRO_DMOD, 0xf016, {0x10}, 0x01},
+	{PRO_DMOD, 0xf017, {0x04}, 0x01},
+	{PRO_DMOD, 0xf018, {0x05}, 0x01},
+	{PRO_DMOD, 0xf019, {0x04}, 0x01},
+	{PRO_DMOD, 0xf01a, {0x05}, 0x01},
+	{PRO_DMOD, 0xf021, {0x03}, 0x01},
+	{PRO_DMOD, 0xf022, {0x0a}, 0x01},
+	{PRO_DMOD, 0xf023, {0x0a}, 0x01},
+	{PRO_DMOD, 0xf02b, {0x00}, 0x01},
+	{PRO_DMOD, 0xf02c, {0x01}, 0x01},
+	{PRO_DMOD, 0xf064, {0x03}, 0x01},
+	{PRO_DMOD, 0xf065, {0xf9}, 0x01},
+	{PRO_DMOD, 0xf066, {0x03}, 0x01},
+	{PRO_DMOD, 0xf067, {0x01}, 0x01},
+	{PRO_DMOD, 0xf06f, {0xe0}, 0x01},
+	{PRO_DMOD, 0xf070, {0x03}, 0x01},
+	{PRO_DMOD, 0xf072, {0x0f}, 0x01},
+	{PRO_DMOD, 0xf073, {0x03}, 0x01},
+	{PRO_DMOD, 0xf078, {0x00}, 0x01},
+	{PRO_DMOD, 0xf087, {0x00}, 0x01},
+	{PRO_DMOD, 0xf09b, {0x3f}, 0x01},
+	{PRO_DMOD, 0xf09c, {0x00}, 0x01},
+	{PRO_DMOD, 0xf09d, {0x20}, 0x01},
+	{PRO_DMOD, 0xf09e, {0x00}, 0x01},
+	{PRO_DMOD, 0xf09f, {0x0c}, 0x01},
+	{PRO_DMOD, 0xf0a0, {0x00}, 0x01},
+	{PRO_DMOD, 0xf130, {0x04}, 0x01},
+	{PRO_DMOD, 0xf132, {0x04}, 0x01},
+	{PRO_DMOD, 0xf144, {0x1a}, 0x01},
+	{PRO_DMOD, 0xf146, {0x00}, 0x01},
+	{PRO_DMOD, 0xf14a, {0x01}, 0x01},
+	{PRO_DMOD, 0xf14c, {0x00}, 0x01},
+	{PRO_DMOD, 0xf14d, {0x00}, 0x01},
+	{PRO_DMOD, 0xf14f, {0x04}, 0x01},
+	{PRO_DMOD, 0xf158, {0x7f}, 0x01},
+	{PRO_DMOD, 0xf15a, {0x00}, 0x01},
+	{PRO_DMOD, 0xf15b, {0x08}, 0x01},
+	{PRO_DMOD, 0xf15d, {0x03}, 0x01},
+	{PRO_DMOD, 0xf15e, {0x05}, 0x01},
+	{PRO_DMOD, 0xf163, {0x05}, 0x01},
+	{PRO_DMOD, 0xf166, {0x01}, 0x01},
+	{PRO_DMOD, 0xf167, {0x40}, 0x01},
+	{PRO_DMOD, 0xf168, {0x0f}, 0x01},
+	{PRO_DMOD, 0xf17a, {0x00}, 0x01},
+	{PRO_DMOD, 0xf17b, {0x00}, 0x01},
+	{PRO_DMOD, 0xf183, {0x01}, 0x01},
+	{PRO_DMOD, 0xf19d, {0x40}, 0x01},
+	{PRO_DMOD, 0xf1bc, {0x36}, 0x01},
+	{PRO_DMOD, 0xf1bd, {0x00}, 0x01},
+	{PRO_DMOD, 0xf1cb, {0xa0}, 0x01},
+	{PRO_DMOD, 0xf1cc, {0x01}, 0x01},
+	{PRO_DMOD, 0xf204, {0x10}, 0x01},
+	{PRO_DMOD, 0xf214, {0x00}, 0x01},
+	{PRO_DMOD, 0xf40e, {0x0a}, 0x01},
+	{PRO_DMOD, 0xf40f, {0x40}, 0x01},
+	{PRO_DMOD, 0xf410, {0x08}, 0x01},
+	{PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+	{PRO_DMOD, 0xf561, {0x15}, 0x01},
+	{PRO_DMOD, 0xf562, {0x20}, 0x01},
+	{PRO_DMOD, 0xf5df, {0xfb}, 0x01},
+	{PRO_DMOD, 0xf5e0, {0x00}, 0x01},
+	{PRO_DMOD, 0xf5e3, {0x09}, 0x01},
+	{PRO_DMOD, 0xf5e4, {0x01}, 0x01},
+	{PRO_DMOD, 0xf5e5, {0x01}, 0x01},
+	{PRO_DMOD, 0xf5f8, {0x01}, 0x01},
+	{PRO_DMOD, 0xf5fd, {0x01}, 0x01},
+	{PRO_DMOD, 0xf600, {0x05}, 0x01},
+	{PRO_DMOD, 0xf601, {0x08}, 0x01},
+	{PRO_DMOD, 0xf602, {0x0b}, 0x01},
+	{PRO_DMOD, 0xf603, {0x0e}, 0x01},
+	{PRO_DMOD, 0xf604, {0x11}, 0x01},
+	{PRO_DMOD, 0xf605, {0x14}, 0x01},
+	{PRO_DMOD, 0xf606, {0x17}, 0x01},
+	{PRO_DMOD, 0xf607, {0x1f}, 0x01},
+	{PRO_DMOD, 0xf60e, {0x00}, 0x01},
+	{PRO_DMOD, 0xf60f, {0x04}, 0x01},
+	{PRO_DMOD, 0xf610, {0x32}, 0x01},
+	{PRO_DMOD, 0xf611, {0x10}, 0x01},
+	{PRO_DMOD, 0xf707, {0xfc}, 0x01},
+	{PRO_DMOD, 0xf708, {0x00}, 0x01},
+	{PRO_DMOD, 0xf709, {0x37}, 0x01},
+	{PRO_DMOD, 0xf70a, {0x00}, 0x01},
+	{PRO_DMOD, 0xf78b, {0x01}, 0x01},
+	{PRO_DMOD, 0xf80f, {0x40}, 0x01},
+	{PRO_DMOD, 0xf810, {0x54}, 0x01},
+	{PRO_DMOD, 0xf811, {0x5a}, 0x01},
+	{PRO_DMOD, 0xf905, {0x01}, 0x01},
+	{PRO_DMOD, 0xfb06, {0x03}, 0x01},
+	{PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+static struct it913xset it9135_38[] = {
+	{PRO_DMOD, 0x0043, {0x00}, 0x01},
+	{PRO_DMOD, 0x0046, {0x38}, 0x01},
+	{PRO_DMOD, 0x0051, {0x01}, 0x01},
+	{PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0x0068, {0x0a}, 0x01},
+	{PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
+	{PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05},
+	{PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02},
+	{PRO_DMOD, 0x0081, {	0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc8, 0xb8,
+				0xd0, 0xc3, 0x01}, 0x0a},
+	{PRO_DMOD, 0x008e, {0x01}, 0x01},
+	{PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
+	{PRO_DMOD, 0x0099, {0x01}, 0x01},
+	{PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
+	{PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
+	{PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
+	{PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
+	{PRO_DMOD, 0x00b0, {0x01}, 0x01},
+	{PRO_DMOD, 0x00b3, {0x02, 0x32}, 0x02},
+	{PRO_DMOD, 0x00b6, {0x14}, 0x01},
+	{PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03},
+	{PRO_DMOD, 0x00c4, {0x00}, 0x01},
+	{PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
+	{PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03},
+	{PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03},
+	{PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
+	{PRO_DMOD, 0x00fc, {	0x02, 0x02, 0x02, 0x09, 0x50, 0x7b, 0x77,
+				0x00, 0x02, 0xc8, 0x05, 0x7b}, 0x0c},
+	{PRO_DMOD, 0x0109, {0x02}, 0x01},
+	{PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04},
+	{PRO_DMOD, 0x011a, {0xc8, 0x7b, 0x8a, 0xa0}, 0x04},
+	{PRO_DMOD, 0x0122, {0x02, 0x18, 0xc3}, 0x03},
+	{PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02},
+	{PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
+	{PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05},
+	{PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc8, 0x59}, 0x05},
+	{PRO_DMOD, 0xf000, {0x0f}, 0x01},
+	{PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05},
+	{PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05},
+	{PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04},
+	{PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+	{PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+	{PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+	{PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+	{PRO_DMOD, 0xf085, {0x00, 0x02, 0x00}, 0x03},
+	{PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
+	{PRO_DMOD, 0xf130, {0x04}, 0x01},
+	{PRO_DMOD, 0xf132, {0x04}, 0x01},
+	{PRO_DMOD, 0xf144, {0x1a}, 0x01},
+	{PRO_DMOD, 0xf146, {0x00}, 0x01},
+	{PRO_DMOD, 0xf14a, {0x01}, 0x01},
+	{PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0xf14f, {0x04}, 0x01},
+	{PRO_DMOD, 0xf158, {0x7f}, 0x01},
+	{PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
+	{PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
+	{PRO_DMOD, 0xf163, {0x05}, 0x01},
+	{PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
+	{PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0xf183, {0x01}, 0x01},
+	{PRO_DMOD, 0xf19d, {0x40}, 0x01},
+	{PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
+	{PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
+	{PRO_DMOD, 0xf204, {0x10}, 0x01},
+	{PRO_DMOD, 0xf214, {0x00}, 0x01},
+	{PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
+	{PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
+	{PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
+	{PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
+	{PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+	{PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
+	{PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02},
+	{PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
+	{PRO_DMOD, 0xf5f8, {0x01}, 0x01},
+	{PRO_DMOD, 0xf5fd, {0x01}, 0x01},
+	{PRO_DMOD, 0xf600, {	0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
+				0x1f}, 0x08},
+	{PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
+	{PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
+	{PRO_DMOD, 0xf78b, {0x01}, 0x01},
+	{PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
+	{PRO_DMOD, 0xf905, {0x01}, 0x01},
+	{PRO_DMOD, 0xfb06, {0x03}, 0x01},
+	{PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+static struct it913xset it9135_51[] = {
+	{PRO_DMOD, 0x0043, {0x00}, 0x01},
+	{PRO_DMOD, 0x0046, {0x51}, 0x01},
+	{PRO_DMOD, 0x0051, {0x01}, 0x01},
+	{PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0x0068, {0x0a}, 0x01},
+	{PRO_DMOD, 0x0070, {0x0a, 0x06, 0x02}, 0x03},
+	{PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05},
+	{PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02},
+	{PRO_DMOD, 0x0081, {	0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc0, 0x96,
+				0xcf, 0xc3, 0x01}, 0x0a},
+	{PRO_DMOD, 0x008e, {0x01}, 0x01},
+	{PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
+	{PRO_DMOD, 0x0099, {0x01}, 0x01},
+	{PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
+	{PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
+	{PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
+	{PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
+	{PRO_DMOD, 0x00b0, {0x01}, 0x01},
+	{PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02},
+	{PRO_DMOD, 0x00b6, {0x14}, 0x01},
+	{PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03},
+	{PRO_DMOD, 0x00c4, {0x00}, 0x01},
+	{PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
+	{PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03},
+	{PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03},
+	{PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
+	{PRO_DMOD, 0x00fc, {	0x03, 0x02, 0x02, 0x09, 0x50, 0x7a, 0x77,
+				0x01, 0x02, 0xb0, 0x02, 0x7a}, 0x0c},
+	{PRO_DMOD, 0x0109, {0x02}, 0x01},
+	{PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04},
+	{PRO_DMOD, 0x011a, {0xc0, 0x7a, 0xac, 0x8c}, 0x04},
+	{PRO_DMOD, 0x0122, {0x02, 0x70, 0xa4}, 0x03},
+	{PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02},
+	{PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
+	{PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05},
+	{PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc0, 0x59}, 0x05},
+	{PRO_DMOD, 0xf000, {0x0f}, 0x01},
+	{PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05},
+	{PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05},
+	{PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04},
+	{PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+	{PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+	{PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+	{PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+	{PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03},
+	{PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
+	{PRO_DMOD, 0xf130, {0x04}, 0x01},
+	{PRO_DMOD, 0xf132, {0x04}, 0x01},
+	{PRO_DMOD, 0xf144, {0x1a}, 0x01},
+	{PRO_DMOD, 0xf146, {0x00}, 0x01},
+	{PRO_DMOD, 0xf14a, {0x01}, 0x01},
+	{PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0xf14f, {0x04}, 0x01},
+	{PRO_DMOD, 0xf158, {0x7f}, 0x01},
+	{PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
+	{PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
+	{PRO_DMOD, 0xf163, {0x05}, 0x01},
+	{PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
+	{PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0xf183, {0x01}, 0x01},
+	{PRO_DMOD, 0xf19d, {0x40}, 0x01},
+	{PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
+	{PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
+	{PRO_DMOD, 0xf204, {0x10}, 0x01},
+	{PRO_DMOD, 0xf214, {0x00}, 0x01},
+	{PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
+	{PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
+	{PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
+	{PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
+	{PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+	{PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
+	{PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02},
+	{PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
+	{PRO_DMOD, 0xf5f8, {0x01}, 0x01},
+	{PRO_DMOD, 0xf5fd, {0x01}, 0x01},
+	{PRO_DMOD, 0xf600, {	0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
+				0x1f}, 0x08},
+	{PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
+	{PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
+	{PRO_DMOD, 0xf78b, {0x01}, 0x01},
+	{PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
+	{PRO_DMOD, 0xf905, {0x01}, 0x01},
+	{PRO_DMOD, 0xfb06, {0x03}, 0x01},
+	{PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+static struct it913xset it9135_52[] = {
+	{PRO_DMOD, 0x0043, {0x00}, 0x01},
+	{PRO_DMOD, 0x0046, {0x52}, 0x01},
+	{PRO_DMOD, 0x0051, {0x01}, 0x01},
+	{PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0x0068, {0x10}, 0x01},
+	{PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
+	{PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xa0, 0x01}, 0x05},
+	{PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02},
+	{PRO_DMOD, 0x0081, {	0x0a, 0x12, 0x03, 0x0a, 0x03, 0xb3, 0x97,
+				0xc0, 0x9e, 0x01}, 0x0a},
+	{PRO_DMOD, 0x008e, {0x01}, 0x01},
+	{PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
+	{PRO_DMOD, 0x0099, {0x01}, 0x01},
+	{PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
+	{PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
+	{PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04},
+	{PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
+	{PRO_DMOD, 0x00b0, {0x01}, 0x01},
+	{PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02},
+	{PRO_DMOD, 0x00b6, {0x14}, 0x01},
+	{PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03},
+	{PRO_DMOD, 0x00c4, {0x00}, 0x01},
+	{PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
+	{PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03},
+	{PRO_DMOD, 0x00f3, {0x05, 0x91, 0x8c}, 0x03},
+	{PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
+	{PRO_DMOD, 0x00fc, {	0x03, 0x02, 0x02, 0x09, 0x50, 0x74, 0x77,
+				0x02, 0x02, 0xae, 0x02, 0x6e}, 0x0c},
+	{PRO_DMOD, 0x0109, {0x02}, 0x01},
+	{PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04},
+	{PRO_DMOD, 0x011a, {0xcd, 0x62, 0xa4, 0x8c}, 0x04},
+	{PRO_DMOD, 0x0122, {0x03, 0x18, 0x9e}, 0x03},
+	{PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02},
+	{PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
+	{PRO_DMOD, 0x0137, {0x00, 0x00, 0x07, 0x00, 0x06}, 0x05},
+	{PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xb6, 0x59}, 0x05},
+	{PRO_DMOD, 0xf000, {0x0f}, 0x01},
+	{PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05},
+	{PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05},
+	{PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04},
+	{PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+	{PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+	{PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+	{PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+	{PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03},
+	{PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
+	{PRO_DMOD, 0xf130, {0x04}, 0x01},
+	{PRO_DMOD, 0xf132, {0x04}, 0x01},
+	{PRO_DMOD, 0xf144, {0x1a}, 0x01},
+	{PRO_DMOD, 0xf146, {0x00}, 0x01},
+	{PRO_DMOD, 0xf14a, {0x01}, 0x01},
+	{PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0xf14f, {0x04}, 0x01},
+	{PRO_DMOD, 0xf158, {0x7f}, 0x01},
+	{PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
+	{PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
+	{PRO_DMOD, 0xf163, {0x05}, 0x01},
+	{PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
+	{PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0xf183, {0x01}, 0x01},
+	{PRO_DMOD, 0xf19d, {0x40}, 0x01},
+	{PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
+	{PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
+	{PRO_DMOD, 0xf204, {0x10}, 0x01},
+	{PRO_DMOD, 0xf214, {0x00}, 0x01},
+	{PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
+	{PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
+	{PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
+	{PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
+	{PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+	{PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
+	{PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02},
+	{PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
+	{PRO_DMOD, 0xf5f8, {0x01}, 0x01},
+	{PRO_DMOD, 0xf5fd, {0x01}, 0x01},
+	{PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
+				0x1f}, 0x08},
+	{PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
+	{PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
+	{PRO_DMOD, 0xf78b, {0x01}, 0x01},
+	{PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
+	{PRO_DMOD, 0xf905, {0x01}, 0x01},
+	{PRO_DMOD, 0xfb06, {0x03}, 0x01},
+	{PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+/* Version 2 types */
+static struct it913xset it9135_v2[] = {
+	{PRO_DMOD, 0x0051, {0x01}, 0x01},
+	{PRO_DMOD, 0x0070, {0x0a}, 0x01},
+	{PRO_DMOD, 0x007e, {0x04}, 0x01},
+	{PRO_DMOD, 0x0081, {0x0a}, 0x01},
+	{PRO_DMOD, 0x008a, {0x01}, 0x01},
+	{PRO_DMOD, 0x008e, {0x01}, 0x01},
+	{PRO_DMOD, 0x0092, {0x06}, 0x01},
+	{PRO_DMOD, 0x0099, {0x01}, 0x01},
+	{PRO_DMOD, 0x009f, {0xe1}, 0x01},
+	{PRO_DMOD, 0x00a0, {0xcf}, 0x01},
+	{PRO_DMOD, 0x00a3, {0x01}, 0x01},
+	{PRO_DMOD, 0x00a5, {0x01}, 0x01},
+	{PRO_DMOD, 0x00a6, {0x01}, 0x01},
+	{PRO_DMOD, 0x00a9, {0x00}, 0x01},
+	{PRO_DMOD, 0x00aa, {0x01}, 0x01},
+	{PRO_DMOD, 0x00b0, {0x01}, 0x01},
+	{PRO_DMOD, 0x00c2, {0x05}, 0x01},
+	{PRO_DMOD, 0x00c6, {0x19}, 0x01},
+	{PRO_DMOD, 0xf000, {0x0f}, 0x01},
+	{PRO_DMOD, 0xf02b, {0x00}, 0x01},
+	{PRO_DMOD, 0xf064, {0x03}, 0x01},
+	{PRO_DMOD, 0xf065, {0xf9}, 0x01},
+	{PRO_DMOD, 0xf066, {0x03}, 0x01},
+	{PRO_DMOD, 0xf067, {0x01}, 0x01},
+	{PRO_DMOD, 0xf06f, {0xe0}, 0x01},
+	{PRO_DMOD, 0xf070, {0x03}, 0x01},
+	{PRO_DMOD, 0xf072, {0x0f}, 0x01},
+	{PRO_DMOD, 0xf073, {0x03}, 0x01},
+	{PRO_DMOD, 0xf078, {0x00}, 0x01},
+	{PRO_DMOD, 0xf087, {0x00}, 0x01},
+	{PRO_DMOD, 0xf09b, {0x3f}, 0x01},
+	{PRO_DMOD, 0xf09c, {0x00}, 0x01},
+	{PRO_DMOD, 0xf09d, {0x20}, 0x01},
+	{PRO_DMOD, 0xf09e, {0x00}, 0x01},
+	{PRO_DMOD, 0xf09f, {0x0c}, 0x01},
+	{PRO_DMOD, 0xf0a0, {0x00}, 0x01},
+	{PRO_DMOD, 0xf130, {0x04}, 0x01},
+	{PRO_DMOD, 0xf132, {0x04}, 0x01},
+	{PRO_DMOD, 0xf144, {0x1a}, 0x01},
+	{PRO_DMOD, 0xf146, {0x00}, 0x01},
+	{PRO_DMOD, 0xf14a, {0x01}, 0x01},
+	{PRO_DMOD, 0xf14c, {0x00}, 0x01},
+	{PRO_DMOD, 0xf14d, {0x00}, 0x01},
+	{PRO_DMOD, 0xf14f, {0x04}, 0x01},
+	{PRO_DMOD, 0xf158, {0x7f}, 0x01},
+	{PRO_DMOD, 0xf15a, {0x00}, 0x01},
+	{PRO_DMOD, 0xf15b, {0x08}, 0x01},
+	{PRO_DMOD, 0xf15d, {0x03}, 0x01},
+	{PRO_DMOD, 0xf15e, {0x05}, 0x01},
+	{PRO_DMOD, 0xf163, {0x05}, 0x01},
+	{PRO_DMOD, 0xf166, {0x01}, 0x01},
+	{PRO_DMOD, 0xf167, {0x40}, 0x01},
+	{PRO_DMOD, 0xf168, {0x0f}, 0x01},
+	{PRO_DMOD, 0xf17a, {0x00}, 0x01},
+	{PRO_DMOD, 0xf17b, {0x00}, 0x01},
+	{PRO_DMOD, 0xf183, {0x01}, 0x01},
+	{PRO_DMOD, 0xf19d, {0x40}, 0x01},
+	{PRO_DMOD, 0xf1bc, {0x36}, 0x01},
+	{PRO_DMOD, 0xf1bd, {0x00}, 0x01},
+	{PRO_DMOD, 0xf1cb, {0xa0}, 0x01},
+	{PRO_DMOD, 0xf1cc, {0x01}, 0x01},
+	{PRO_DMOD, 0xf204, {0x10}, 0x01},
+	{PRO_DMOD, 0xf214, {0x00}, 0x01},
+	{PRO_DMOD, 0xf40e, {0x0a}, 0x01},
+	{PRO_DMOD, 0xf40f, {0x40}, 0x01},
+	{PRO_DMOD, 0xf410, {0x08}, 0x01},
+	{PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+	{PRO_DMOD, 0xf561, {0x15}, 0x01},
+	{PRO_DMOD, 0xf562, {0x20}, 0x01},
+	{PRO_DMOD, 0xf5e3, {0x09}, 0x01},
+	{PRO_DMOD, 0xf5e4, {0x01}, 0x01},
+	{PRO_DMOD, 0xf5e5, {0x01}, 0x01},
+	{PRO_DMOD, 0xf600, {0x05}, 0x01},
+	{PRO_DMOD, 0xf601, {0x08}, 0x01},
+	{PRO_DMOD, 0xf602, {0x0b}, 0x01},
+	{PRO_DMOD, 0xf603, {0x0e}, 0x01},
+	{PRO_DMOD, 0xf604, {0x11}, 0x01},
+	{PRO_DMOD, 0xf605, {0x14}, 0x01},
+	{PRO_DMOD, 0xf606, {0x17}, 0x01},
+	{PRO_DMOD, 0xf607, {0x1f}, 0x01},
+	{PRO_DMOD, 0xf60e, {0x00}, 0x01},
+	{PRO_DMOD, 0xf60f, {0x04}, 0x01},
+	{PRO_DMOD, 0xf610, {0x32}, 0x01},
+	{PRO_DMOD, 0xf611, {0x10}, 0x01},
+	{PRO_DMOD, 0xf707, {0xfc}, 0x01},
+	{PRO_DMOD, 0xf708, {0x00}, 0x01},
+	{PRO_DMOD, 0xf709, {0x37}, 0x01},
+	{PRO_DMOD, 0xf70a, {0x00}, 0x01},
+	{PRO_DMOD, 0xf78b, {0x01}, 0x01},
+	{PRO_DMOD, 0xf80f, {0x40}, 0x01},
+	{PRO_DMOD, 0xf810, {0x54}, 0x01},
+	{PRO_DMOD, 0xf811, {0x5a}, 0x01},
+	{PRO_DMOD, 0xf905, {0x01}, 0x01},
+	{PRO_DMOD, 0xfb06, {0x03}, 0x01},
+	{PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+static struct it913xset it9135_60[] = {
+	{PRO_DMOD, 0x0043, {0x00}, 0x01},
+	{PRO_DMOD, 0x0046, {0x60}, 0x01},
+	{PRO_DMOD, 0x0051, {0x01}, 0x01},
+	{PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0x0068, {0x0a}, 0x01},
+	{PRO_DMOD, 0x006a, {0x03}, 0x01},
+	{PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
+	{PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05},
+	{PRO_DMOD, 0x007e, {0x04}, 0x01},
+	{PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02},
+	{PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbe, 0xa0, 0xc6, 0xb6, 0x01}, 0x07},
+	{PRO_DMOD, 0x008e, {0x01}, 0x01},
+	{PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
+	{PRO_DMOD, 0x0099, {0x01}, 0x01},
+	{PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
+	{PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
+	{PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
+	{PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
+	{PRO_DMOD, 0x00b0, {0x01}, 0x01},
+	{PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02},
+	{PRO_DMOD, 0x00b6, {0x14}, 0x01},
+	{PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05},
+	{PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
+	{PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04},
+	{PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03},
+	{PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
+	{PRO_DMOD, 0x00fc, {	0x03, 0x03, 0x02, 0x0a, 0x50, 0x7b, 0x8c,
+				0x00, 0x02, 0xbe, 0x00}, 0x0b},
+	{PRO_DMOD, 0x0109, {0x02}, 0x01},
+	{PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
+	{PRO_DMOD, 0x011a, {0xbe}, 0x01},
+	{PRO_DMOD, 0x0124, {0xae}, 0x01},
+	{PRO_DMOD, 0x0127, {0x00}, 0x01},
+	{PRO_DMOD, 0x012a, {0x56, 0x50, 0x47, 0x42}, 0x04},
+	{PRO_DMOD, 0x0137, {0x00}, 0x01},
+	{PRO_DMOD, 0x013b, {0x08}, 0x01},
+	{PRO_DMOD, 0x013f, {0x5b}, 0x01},
+	{PRO_DMOD, 0x0141, {	0x59, 0xf9, 0x19, 0x19, 0x8c, 0x8c, 0x8c,
+				0x6e, 0x8c, 0x50, 0x8c, 0x8c, 0xac, 0xc6,
+				0x33}, 0x0f},
+	{PRO_DMOD, 0x0151, {0x28}, 0x01},
+	{PRO_DMOD, 0x0153, {0xbc}, 0x01},
+	{PRO_DMOD, 0x0178, {0x09}, 0x01},
+	{PRO_DMOD, 0x0181, {0x94, 0x6e}, 0x02},
+	{PRO_DMOD, 0x0185, {0x24}, 0x01},
+	{PRO_DMOD, 0x0187, {0x00, 0x00, 0xbe, 0x02, 0x80}, 0x05},
+	{PRO_DMOD, 0xed02, {0xff}, 0x01},
+	{PRO_DMOD, 0xee42, {0xff}, 0x01},
+	{PRO_DMOD, 0xee82, {0xff}, 0x01},
+	{PRO_DMOD, 0xf000, {0x0f}, 0x01},
+	{PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02},
+	{PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03},
+	{PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+	{PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+	{PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+	{PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+	{PRO_DMOD, 0xf087, {0x00}, 0x01},
+	{PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
+	{PRO_DMOD, 0xf130, {0x04}, 0x01},
+	{PRO_DMOD, 0xf132, {0x04}, 0x01},
+	{PRO_DMOD, 0xf144, {0x1a}, 0x01},
+	{PRO_DMOD, 0xf146, {0x00}, 0x01},
+	{PRO_DMOD, 0xf14a, {0x01}, 0x01},
+	{PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0xf14f, {0x04}, 0x01},
+	{PRO_DMOD, 0xf158, {0x7f}, 0x01},
+	{PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
+	{PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
+	{PRO_DMOD, 0xf163, {0x05}, 0x01},
+	{PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
+	{PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0xf183, {0x01}, 0x01},
+	{PRO_DMOD, 0xf19d, {0x40}, 0x01},
+	{PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
+	{PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
+	{PRO_DMOD, 0xf204, {0x10}, 0x01},
+	{PRO_DMOD, 0xf214, {0x00}, 0x01},
+	{PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
+	{PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
+	{PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
+	{PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
+	{PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+	{PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
+	{PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
+	{PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17
+		, 0x1f}, 0x08},
+	{PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
+	{PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
+	{PRO_DMOD, 0xf78b, {0x01}, 0x01},
+	{PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
+	{PRO_DMOD, 0xf905, {0x01}, 0x01},
+	{PRO_DMOD, 0xfb06, {0x03}, 0x01},
+	{PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+static struct it913xset it9135_61[] = {
+	{PRO_DMOD, 0x0043, {0x00}, 0x01},
+	{PRO_DMOD, 0x0046, {0x61}, 0x01},
+	{PRO_DMOD, 0x0051, {0x01}, 0x01},
+	{PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0x0068, {0x06}, 0x01},
+	{PRO_DMOD, 0x006a, {0x03}, 0x01},
+	{PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
+	{PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x90, 0x01}, 0x05},
+	{PRO_DMOD, 0x007e, {0x04}, 0x01},
+	{PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02},
+	{PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbc, 0x9c, 0xcc, 0xa8, 0x01}, 0x07},
+	{PRO_DMOD, 0x008e, {0x01}, 0x01},
+	{PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
+	{PRO_DMOD, 0x0099, {0x01}, 0x01},
+	{PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
+	{PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
+	{PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04},
+	{PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
+	{PRO_DMOD, 0x00b0, {0x01}, 0x01},
+	{PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02},
+	{PRO_DMOD, 0x00b6, {0x14}, 0x01},
+	{PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05},
+	{PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
+	{PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04},
+	{PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03},
+	{PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
+	{PRO_DMOD, 0x00fc, {	0x03, 0x03, 0x02, 0x08, 0x50, 0x7b, 0x8c,
+				0x01, 0x02, 0xc8, 0x00}, 0x0b},
+	{PRO_DMOD, 0x0109, {0x02}, 0x01},
+	{PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
+	{PRO_DMOD, 0x011a, {0xc6}, 0x01},
+	{PRO_DMOD, 0x0124, {0xa8}, 0x01},
+	{PRO_DMOD, 0x0127, {0x00}, 0x01},
+	{PRO_DMOD, 0x012a, {0x59, 0x50, 0x47, 0x42}, 0x04},
+	{PRO_DMOD, 0x0137, {0x00}, 0x01},
+	{PRO_DMOD, 0x013b, {0x05}, 0x01},
+	{PRO_DMOD, 0x013f, {0x5b}, 0x01},
+	{PRO_DMOD, 0x0141, {	0x59, 0xf9, 0x59, 0x59, 0x8c, 0x8c, 0x8c,
+				0x7b, 0x8c, 0x50, 0x8c, 0x8c, 0xa8, 0xc6,
+				0x33}, 0x0f},
+	{PRO_DMOD, 0x0151, {0x28}, 0x01},
+	{PRO_DMOD, 0x0153, {0xcc}, 0x01},
+	{PRO_DMOD, 0x0178, {0x09}, 0x01},
+	{PRO_DMOD, 0x0181, {0x9c, 0x76}, 0x02},
+	{PRO_DMOD, 0x0185, {0x28}, 0x01},
+	{PRO_DMOD, 0x0187, {0x01, 0x00, 0xaa, 0x02, 0x80}, 0x05},
+	{PRO_DMOD, 0xed02, {0xff}, 0x01},
+	{PRO_DMOD, 0xee42, {0xff}, 0x01},
+	{PRO_DMOD, 0xee82, {0xff}, 0x01},
+	{PRO_DMOD, 0xf000, {0x0f}, 0x01},
+	{PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02},
+	{PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03},
+	{PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+	{PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+	{PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+	{PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+	{PRO_DMOD, 0xf087, {0x00}, 0x01},
+	{PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
+	{PRO_DMOD, 0xf130, {0x04}, 0x01},
+	{PRO_DMOD, 0xf132, {0x04}, 0x01},
+	{PRO_DMOD, 0xf144, {0x1a}, 0x01},
+	{PRO_DMOD, 0xf146, {0x00}, 0x01},
+	{PRO_DMOD, 0xf14a, {0x01}, 0x01},
+	{PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0xf14f, {0x04}, 0x01},
+	{PRO_DMOD, 0xf158, {0x7f}, 0x01},
+	{PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
+	{PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
+	{PRO_DMOD, 0xf163, {0x05}, 0x01},
+	{PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
+	{PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0xf183, {0x01}, 0x01},
+	{PRO_DMOD, 0xf19d, {0x40}, 0x01},
+	{PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
+	{PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
+	{PRO_DMOD, 0xf204, {0x10}, 0x01},
+	{PRO_DMOD, 0xf214, {0x00}, 0x01},
+	{PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
+	{PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
+	{PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
+	{PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
+	{PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+	{PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
+	{PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
+	{PRO_DMOD, 0xf600, {	0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
+				0x1f}, 0x08},
+	{PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
+	{PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
+	{PRO_DMOD, 0xf78b, {0x01}, 0x01},
+	{PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
+	{PRO_DMOD, 0xf905, {0x01}, 0x01},
+	{PRO_DMOD, 0xfb06, {0x03}, 0x01},
+	{PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+static struct it913xset it9135_62[] = {
+	{PRO_DMOD, 0x0043, {0x00}, 0x01},
+	{PRO_DMOD, 0x0046, {0x62}, 0x01},
+	{PRO_DMOD, 0x0051, {0x01}, 0x01},
+	{PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0x0068, {0x0a}, 0x01},
+	{PRO_DMOD, 0x006a, {0x03}, 0x01},
+	{PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
+	{PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05},
+	{PRO_DMOD, 0x007e, {0x04}, 0x01},
+	{PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02},
+	{PRO_DMOD, 0x0084, {	0x0a, 0x33, 0xb8, 0x9c, 0xb2, 0xa6, 0x01},
+				0x07},
+	{PRO_DMOD, 0x008e, {0x01}, 0x01},
+	{PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
+	{PRO_DMOD, 0x0099, {0x01}, 0x01},
+	{PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
+	{PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
+	{PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
+	{PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
+	{PRO_DMOD, 0x00b0, {0x01}, 0x01},
+	{PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02},
+	{PRO_DMOD, 0x00b6, {0x14}, 0x01},
+	{PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05},
+	{PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
+	{PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04},
+	{PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03},
+	{PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
+	{PRO_DMOD, 0x00fc, {	0x02, 0x03, 0x02, 0x09, 0x50, 0x6e, 0x8c,
+				0x02, 0x02, 0xc2, 0x00}, 0x0b},
+	{PRO_DMOD, 0x0109, {0x02}, 0x01},
+	{PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
+	{PRO_DMOD, 0x011a, {0xb8}, 0x01},
+	{PRO_DMOD, 0x0124, {0xa8}, 0x01},
+	{PRO_DMOD, 0x0127, {0x00}, 0x01},
+	{PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
+	{PRO_DMOD, 0x0137, {0x00}, 0x01},
+	{PRO_DMOD, 0x013b, {0x05}, 0x01},
+	{PRO_DMOD, 0x013f, {0x5b}, 0x01},
+	{PRO_DMOD, 0x0141, {	0x59, 0xf9, 0x59, 0x19, 0x8c, 0x8c, 0x8c,
+				0x7b, 0x8c, 0x50, 0x70, 0x8c, 0x96, 0xd0,
+				0x33}, 0x0f},
+	{PRO_DMOD, 0x0151, {0x28}, 0x01},
+	{PRO_DMOD, 0x0153, {0xb2}, 0x01},
+	{PRO_DMOD, 0x0178, {0x09}, 0x01},
+	{PRO_DMOD, 0x0181, {0x9c, 0x6e}, 0x02},
+	{PRO_DMOD, 0x0185, {0x24}, 0x01},
+	{PRO_DMOD, 0x0187, {0x00, 0x00, 0xb8, 0x02, 0x80}, 0x05},
+	{PRO_DMOD, 0xed02, {0xff}, 0x01},
+	{PRO_DMOD, 0xee42, {0xff}, 0x01},
+	{PRO_DMOD, 0xee82, {0xff}, 0x01},
+	{PRO_DMOD, 0xf000, {0x0f}, 0x01},
+	{PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02},
+	{PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03},
+	{PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+	{PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+	{PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+	{PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+	{PRO_DMOD, 0xf087, {0x00}, 0x01},
+	{PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
+	{PRO_DMOD, 0xf130, {0x04}, 0x01},
+	{PRO_DMOD, 0xf132, {0x04}, 0x01},
+	{PRO_DMOD, 0xf144, {0x1a}, 0x01},
+	{PRO_DMOD, 0xf146, {0x00}, 0x01},
+	{PRO_DMOD, 0xf14a, {0x01}, 0x01},
+	{PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0xf14f, {0x04}, 0x01},
+	{PRO_DMOD, 0xf158, {0x7f}, 0x01},
+	{PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
+	{PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
+	{PRO_DMOD, 0xf163, {0x05}, 0x01},
+	{PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
+	{PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
+	{PRO_DMOD, 0xf183, {0x01}, 0x01},
+	{PRO_DMOD, 0xf19d, {0x40}, 0x01},
+	{PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
+	{PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
+	{PRO_DMOD, 0xf204, {0x10}, 0x01},
+	{PRO_DMOD, 0xf214, {0x00}, 0x01},
+	{PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
+	{PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
+	{PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
+	{PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
+	{PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+	{PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
+	{PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
+	{PRO_DMOD, 0xf600, {	0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
+				0x1f}, 0x08},
+	{PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
+	{PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
+	{PRO_DMOD, 0xf78b, {0x01}, 0x01},
+	{PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
+	{PRO_DMOD, 0xf905, {0x01}, 0x01},
+	{PRO_DMOD, 0xfb06, {0x03}, 0x01},
+	{PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+/* Tuner setting scripts (still keeping it9137) */
+static struct it913xset it9137_tuner_off[] = {
+	{PRO_DMOD, 0xfba8, {0x01}, 0x01}, /* Tuner Clock Off  */
+	{PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */
+	{PRO_DMOD, 0xec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04},
+	{PRO_DMOD, 0xec06, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00}, 0x0c},
+	{PRO_DMOD, 0xec12, {0x00, 0x00, 0x00, 0x00}, 0x04},
+	{PRO_DMOD, 0xec17, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00}, 0x09},
+	{PRO_DMOD, 0xec22, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00}, 0x0a},
+	{PRO_DMOD, 0xec20, {0x00}, 0x01},
+	{PRO_DMOD, 0xec3f, {0x01}, 0x01},
+	{0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
+};
+
+static struct it913xset set_it9135_template[] = {
+	{PRO_DMOD, 0xee06, {0x00}, 0x01},
+	{PRO_DMOD, 0xec56, {0x00}, 0x01},
+	{PRO_DMOD, 0xec4c, {0x00}, 0x01},
+	{PRO_DMOD, 0xec4d, {0x00}, 0x01},
+	{PRO_DMOD, 0xec4e, {0x00}, 0x01},
+	{PRO_DMOD, 0x011e, {0x00}, 0x01}, /* Older Devices */
+	{PRO_DMOD, 0x011f, {0x00}, 0x01},
+	{0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
+};
+
+static struct it913xset set_it9137_template[] = {
+	{PRO_DMOD, 0xee06, {0x00}, 0x01},
+	{PRO_DMOD, 0xec56, {0x00}, 0x01},
+	{PRO_DMOD, 0xec4c, {0x00}, 0x01},
+	{PRO_DMOD, 0xec4d, {0x00}, 0x01},
+	{PRO_DMOD, 0xec4e, {0x00}, 0x01},
+	{PRO_DMOD, 0xec4f, {0x00}, 0x01},
+	{PRO_DMOD, 0xec50, {0x00}, 0x01},
+	{0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
+};
diff --git a/drivers/media/dvb-frontends/it913x-fe.c b/drivers/media/dvb-frontends/it913x-fe.c
new file mode 100644
index 0000000..6e1c6eb
--- /dev/null
+++ b/drivers/media/dvb-frontends/it913x-fe.c
@@ -0,0 +1,1045 @@
+/*
+ *  Driver for it913x-fe Frontend
+ *
+ *  with support for on chip it9137 integral tuner
+ *
+ *  Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
+ *  IT9137 Copyright (C) ITE Tech Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "dvb_frontend.h"
+#include "it913x-fe.h"
+#include "it913x-fe-priv.h"
+
+static int it913x_debug;
+
+module_param_named(debug, it913x_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
+
+#define dprintk(level, args...) do { \
+	if (level & it913x_debug) \
+		printk(KERN_DEBUG "it913x-fe: " args); \
+} while (0)
+
+#define deb_info(args...)  dprintk(0x01, args)
+#define debug_data_snipet(level, name, p) \
+	  dprintk(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \
+		*p, *(p+1), *(p+2), *(p+3), *(p+4), \
+			*(p+5), *(p+6), *(p+7));
+#define info(format, arg...) \
+	printk(KERN_INFO "it913x-fe: " format "\n" , ## arg)
+
+struct it913x_fe_state {
+	struct dvb_frontend frontend;
+	struct i2c_adapter *i2c_adap;
+	struct ite_config *config;
+	u8 i2c_addr;
+	u32 frequency;
+	fe_modulation_t constellation;
+	fe_transmit_mode_t transmission_mode;
+	u8 priority;
+	u32 crystalFrequency;
+	u32 adcFrequency;
+	u8 tuner_type;
+	struct adctable *table;
+	fe_status_t it913x_status;
+	u16 tun_xtal;
+	u8 tun_fdiv;
+	u8 tun_clk_mode;
+	u32 tun_fn_min;
+	u32 ucblocks;
+};
+
+static int it913x_read_reg(struct it913x_fe_state *state,
+		u32 reg, u8 *data, u8 count)
+{
+	int ret;
+	u8 pro = PRO_DMOD; /* All reads from demodulator */
+	u8 b[4];
+	struct i2c_msg msg[2] = {
+		{ .addr = state->i2c_addr + (pro << 1), .flags = 0,
+			.buf = b, .len = sizeof(b) },
+		{ .addr = state->i2c_addr + (pro << 1), .flags = I2C_M_RD,
+			.buf = data, .len = count }
+	};
+	b[0] = (u8) reg >> 24;
+	b[1] = (u8)(reg >> 16) & 0xff;
+	b[2] = (u8)(reg >> 8) & 0xff;
+	b[3] = (u8) reg & 0xff;
+
+	ret = i2c_transfer(state->i2c_adap, msg, 2);
+
+	return ret;
+}
+
+static int it913x_read_reg_u8(struct it913x_fe_state *state, u32 reg)
+{
+	int ret;
+	u8 b[1];
+	ret = it913x_read_reg(state, reg, &b[0], sizeof(b));
+	return (ret < 0) ? -ENODEV : b[0];
+}
+
+static int it913x_write(struct it913x_fe_state *state,
+		u8 pro, u32 reg, u8 buf[], u8 count)
+{
+	u8 b[256];
+	struct i2c_msg msg[1] = {
+		{ .addr = state->i2c_addr + (pro << 1), .flags = 0,
+		  .buf = b, .len = count + 4 }
+	};
+	int ret;
+
+	b[0] = (u8) reg >> 24;
+	b[1] = (u8)(reg >> 16) & 0xff;
+	b[2] = (u8)(reg >> 8) & 0xff;
+	b[3] = (u8) reg & 0xff;
+	memcpy(&b[4], buf, count);
+
+	ret = i2c_transfer(state->i2c_adap, msg, 1);
+
+	if (ret < 0)
+		return -EIO;
+
+	return 0;
+}
+
+static int it913x_write_reg(struct it913x_fe_state *state,
+		u8 pro, u32 reg, u32 data)
+{
+	int ret;
+	u8 b[4];
+	u8 s;
+
+	b[0] = data >> 24;
+	b[1] = (data >> 16) & 0xff;
+	b[2] = (data >> 8) & 0xff;
+	b[3] = data & 0xff;
+	/* expand write as needed */
+	if (data < 0x100)
+		s = 3;
+	else if (data < 0x1000)
+		s = 2;
+	else if (data < 0x100000)
+		s = 1;
+	else
+		s = 0;
+
+	ret = it913x_write(state, pro, reg, &b[s], sizeof(b) - s);
+
+	return ret;
+}
+
+static int it913x_fe_script_loader(struct it913x_fe_state *state,
+		struct it913xset *loadscript)
+{
+	int ret, i;
+	if (loadscript == NULL)
+		return -EINVAL;
+
+	for (i = 0; i < 1000; ++i) {
+		if (loadscript[i].pro == 0xff)
+			break;
+		ret = it913x_write(state, loadscript[i].pro,
+			loadscript[i].address,
+			loadscript[i].reg, loadscript[i].count);
+		if (ret < 0)
+			return -ENODEV;
+	}
+	return 0;
+}
+
+static int it913x_init_tuner(struct it913x_fe_state *state)
+{
+	int ret, i, reg;
+	u8 val, nv_val;
+	u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2};
+	u8 b[2];
+
+	reg = it913x_read_reg_u8(state, 0xec86);
+	switch (reg) {
+	case 0:
+		state->tun_clk_mode = reg;
+		state->tun_xtal = 2000;
+		state->tun_fdiv = 3;
+		val = 16;
+		break;
+	case -ENODEV:
+		return -ENODEV;
+	case 1:
+	default:
+		state->tun_clk_mode = reg;
+		state->tun_xtal = 640;
+		state->tun_fdiv = 1;
+		val = 6;
+		break;
+	}
+
+	reg = it913x_read_reg_u8(state, 0xed03);
+
+	if (reg < 0)
+		return -ENODEV;
+	else if (reg < ARRAY_SIZE(nv))
+		nv_val = nv[reg];
+	else
+		nv_val = 2;
+
+	for (i = 0; i < 50; i++) {
+		ret = it913x_read_reg(state, 0xed23, &b[0], sizeof(b));
+		reg = (b[1] << 8) + b[0];
+		if (reg > 0)
+			break;
+		if (ret < 0)
+			return -ENODEV;
+		udelay(2000);
+	}
+	state->tun_fn_min = state->tun_xtal * reg;
+	state->tun_fn_min /= (state->tun_fdiv * nv_val);
+	deb_info("Tuner fn_min %d", state->tun_fn_min);
+
+	if (state->config->chip_ver > 1)
+		msleep(50);
+	else {
+		for (i = 0; i < 50; i++) {
+			reg = it913x_read_reg_u8(state, 0xec82);
+			if (reg > 0)
+				break;
+			if (reg < 0)
+				return -ENODEV;
+			udelay(2000);
+		}
+	}
+
+	return it913x_write_reg(state, PRO_DMOD, 0xed81, val);
+}
+
+static int it9137_set_tuner(struct it913x_fe_state *state,
+		u32 bandwidth, u32 frequency_m)
+{
+	struct it913xset *set_tuner = set_it9137_template;
+	int ret, reg;
+	u32 frequency = frequency_m / 1000;
+	u32 freq, temp_f, tmp;
+	u16 iqik_m_cal;
+	u16 n_div;
+	u8 n;
+	u8 l_band;
+	u8 lna_band;
+	u8 bw;
+
+	if (state->config->firmware_ver == 1)
+		set_tuner = set_it9135_template;
+	else
+		set_tuner = set_it9137_template;
+
+	deb_info("Tuner Frequency %d Bandwidth %d", frequency, bandwidth);
+
+	if (frequency >= 51000 && frequency <= 440000) {
+		l_band = 0;
+		lna_band = 0;
+	} else if (frequency > 440000 && frequency <= 484000) {
+		l_band = 1;
+		lna_band = 1;
+	} else if (frequency > 484000 && frequency <= 533000) {
+		l_band = 1;
+		lna_band = 2;
+	} else if (frequency > 533000 && frequency <= 587000) {
+		l_band = 1;
+		lna_band = 3;
+	} else if (frequency > 587000 && frequency <= 645000) {
+		l_band = 1;
+		lna_band = 4;
+	} else if (frequency > 645000 && frequency <= 710000) {
+		l_band = 1;
+		lna_band = 5;
+	} else if (frequency > 710000 && frequency <= 782000) {
+		l_band = 1;
+		lna_band = 6;
+	} else if (frequency > 782000 && frequency <= 860000) {
+		l_band = 1;
+		lna_band = 7;
+	} else if (frequency > 1450000 && frequency <= 1492000) {
+		l_band = 1;
+		lna_band = 0;
+	} else if (frequency > 1660000 && frequency <= 1685000) {
+		l_band = 1;
+		lna_band = 1;
+	} else
+		return -EINVAL;
+	set_tuner[0].reg[0] = lna_band;
+
+	switch (bandwidth) {
+	case 5000000:
+		bw = 0;
+		break;
+	case 6000000:
+		bw = 2;
+		break;
+	case 7000000:
+		bw = 4;
+		break;
+	default:
+	case 8000000:
+		bw = 6;
+		break;
+	}
+
+	set_tuner[1].reg[0] = bw;
+	set_tuner[2].reg[0] = 0xa0 | (l_band << 3);
+
+	if (frequency > 53000 && frequency <= 74000) {
+		n_div = 48;
+		n = 0;
+	} else if (frequency > 74000 && frequency <= 111000) {
+		n_div = 32;
+		n = 1;
+	} else if (frequency > 111000 && frequency <= 148000) {
+		n_div = 24;
+		n = 2;
+	} else if (frequency > 148000 && frequency <= 222000) {
+		n_div = 16;
+		n = 3;
+	} else if (frequency > 222000 && frequency <= 296000) {
+		n_div = 12;
+		n = 4;
+	} else if (frequency > 296000 && frequency <= 445000) {
+		n_div = 8;
+		n = 5;
+	} else if (frequency > 445000 && frequency <= state->tun_fn_min) {
+		n_div = 6;
+		n = 6;
+	} else if (frequency > state->tun_fn_min && frequency <= 950000) {
+		n_div = 4;
+		n = 7;
+	} else if (frequency > 1450000 && frequency <= 1680000) {
+		n_div = 2;
+		n = 0;
+	} else
+		return -EINVAL;
+
+	reg = it913x_read_reg_u8(state, 0xed81);
+	iqik_m_cal = (u16)reg * n_div;
+
+	if (reg < 0x20) {
+		if (state->tun_clk_mode == 0)
+			iqik_m_cal = (iqik_m_cal * 9) >> 5;
+		else
+			iqik_m_cal >>= 1;
+	} else {
+		iqik_m_cal = 0x40 - iqik_m_cal;
+		if (state->tun_clk_mode == 0)
+			iqik_m_cal = ~((iqik_m_cal * 9) >> 5);
+		else
+			iqik_m_cal = ~(iqik_m_cal >> 1);
+	}
+
+	temp_f = frequency * (u32)n_div * (u32)state->tun_fdiv;
+	freq = temp_f / state->tun_xtal;
+	tmp = freq * state->tun_xtal;
+
+	if ((temp_f - tmp) >= (state->tun_xtal >> 1))
+		freq++;
+
+	freq += (u32) n << 13;
+	/* Frequency OMEGA_IQIK_M_CAL_MID*/
+	temp_f = freq + (u32)iqik_m_cal;
+
+	set_tuner[3].reg[0] =  temp_f & 0xff;
+	set_tuner[4].reg[0] =  (temp_f >> 8) & 0xff;
+
+	deb_info("High Frequency = %04x", temp_f);
+
+	/* Lower frequency */
+	set_tuner[5].reg[0] =  freq & 0xff;
+	set_tuner[6].reg[0] =  (freq >> 8) & 0xff;
+
+	deb_info("low Frequency = %04x", freq);
+
+	ret = it913x_fe_script_loader(state, set_tuner);
+
+	return (ret < 0) ? -ENODEV : 0;
+}
+
+static int it913x_fe_select_bw(struct it913x_fe_state *state,
+			u32 bandwidth, u32 adcFrequency)
+{
+	int ret, i;
+	u8 buffer[256];
+	u32 coeff[8];
+	u16 bfsfcw_fftinx_ratio;
+	u16 fftinx_bfsfcw_ratio;
+	u8 count;
+	u8 bw;
+	u8 adcmultiplier;
+
+	deb_info("Bandwidth %d Adc %d", bandwidth, adcFrequency);
+
+	switch (bandwidth) {
+	case 5000000:
+		bw = 3;
+		break;
+	case 6000000:
+		bw = 0;
+		break;
+	case 7000000:
+		bw = 1;
+		break;
+	default:
+	case 8000000:
+		bw = 2;
+		break;
+	}
+	ret = it913x_write_reg(state, PRO_DMOD, REG_BW, bw);
+
+	if (state->table == NULL)
+		return -EINVAL;
+
+	/* In write order */
+	coeff[0] = state->table[bw].coeff_1_2048;
+	coeff[1] = state->table[bw].coeff_2_2k;
+	coeff[2] = state->table[bw].coeff_1_8191;
+	coeff[3] = state->table[bw].coeff_1_8192;
+	coeff[4] = state->table[bw].coeff_1_8193;
+	coeff[5] = state->table[bw].coeff_2_8k;
+	coeff[6] = state->table[bw].coeff_1_4096;
+	coeff[7] = state->table[bw].coeff_2_4k;
+	bfsfcw_fftinx_ratio = state->table[bw].bfsfcw_fftinx_ratio;
+	fftinx_bfsfcw_ratio = state->table[bw].fftinx_bfsfcw_ratio;
+
+	/* ADC multiplier */
+	ret = it913x_read_reg_u8(state, ADC_X_2);
+	if (ret < 0)
+		return -EINVAL;
+
+	adcmultiplier = ret;
+
+	count = 0;
+
+	/*  Build Buffer for COEFF Registers */
+	for (i = 0; i < 8; i++) {
+		if (adcmultiplier == 1)
+			coeff[i] /= 2;
+		buffer[count++] = (coeff[i] >> 24) & 0x3;
+		buffer[count++] = (coeff[i] >> 16) & 0xff;
+		buffer[count++] = (coeff[i] >> 8) & 0xff;
+		buffer[count++] = coeff[i] & 0xff;
+	}
+
+	/* bfsfcw_fftinx_ratio register 0x21-0x22 */
+	buffer[count++] = bfsfcw_fftinx_ratio & 0xff;
+	buffer[count++] = (bfsfcw_fftinx_ratio >> 8) & 0xff;
+	/* fftinx_bfsfcw_ratio register 0x23-0x24 */
+	buffer[count++] = fftinx_bfsfcw_ratio & 0xff;
+	buffer[count++] = (fftinx_bfsfcw_ratio >> 8) & 0xff;
+	/* start at COEFF_1_2048 and write through to fftinx_bfsfcw_ratio*/
+	ret = it913x_write(state, PRO_DMOD, COEFF_1_2048, buffer, count);
+
+	for (i = 0; i < 42; i += 8)
+		debug_data_snipet(0x1, "Buffer", &buffer[i]);
+
+	return ret;
+}
+
+
+
+static int it913x_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct it913x_fe_state *state = fe->demodulator_priv;
+	int ret, i;
+	fe_status_t old_status = state->it913x_status;
+	*status = 0;
+
+	if (state->it913x_status == 0) {
+		ret = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS);
+		if (ret == 0x1) {
+			*status |= FE_HAS_SIGNAL;
+			for (i = 0; i < 40; i++) {
+				ret = it913x_read_reg_u8(state, MP2IF_SYNC_LK);
+				if (ret == 0x1)
+					break;
+				msleep(25);
+			}
+			if (ret == 0x1)
+				*status |= FE_HAS_CARRIER
+					| FE_HAS_VITERBI
+					| FE_HAS_SYNC;
+			state->it913x_status = *status;
+		}
+	}
+
+	if (state->it913x_status & FE_HAS_SYNC) {
+		ret = it913x_read_reg_u8(state, TPSD_LOCK);
+		if (ret == 0x1)
+			*status |= FE_HAS_LOCK
+				| state->it913x_status;
+		else
+			state->it913x_status = 0;
+		if (old_status != state->it913x_status)
+			ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, ret);
+	}
+
+	return 0;
+}
+
+/* FEC values based on fe_code_rate_t non supported values 0*/
+int it913x_qpsk_pval[] = {0, -93, -91, -90, 0, -89, -88};
+int it913x_16qam_pval[] = {0, -87, -85, -84, 0, -83, -82};
+int it913x_64qam_pval[] = {0, -82, -80, -78, 0, -77, -76};
+
+static int it913x_get_signal_strength(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct it913x_fe_state *state = fe->demodulator_priv;
+	u8 code_rate;
+	int ret, temp;
+	u8 lna_gain_os;
+
+	ret = it913x_read_reg_u8(state, VAR_P_INBAND);
+	if (ret < 0)
+		return ret;
+
+	/* VHF/UHF gain offset */
+	if (state->frequency < 300000000)
+		lna_gain_os = 7;
+	else
+		lna_gain_os = 14;
+
+	temp = (ret - 100) - lna_gain_os;
+
+	if (state->priority == PRIORITY_HIGH)
+		code_rate = p->code_rate_HP;
+	else
+		code_rate = p->code_rate_LP;
+
+	if (code_rate >= ARRAY_SIZE(it913x_qpsk_pval))
+		return -EINVAL;
+
+	deb_info("Reg VAR_P_INBAND:%d Calc Offset Value:%d", ret, temp);
+
+	/* Apply FEC offset values*/
+	switch (p->modulation) {
+	case QPSK:
+		temp -= it913x_qpsk_pval[code_rate];
+		break;
+	case QAM_16:
+		temp -= it913x_16qam_pval[code_rate];
+		break;
+	case QAM_64:
+		temp -= it913x_64qam_pval[code_rate];
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (temp < -15)
+		ret = 0;
+	else if ((-15 <= temp) && (temp < 0))
+		ret = (2 * (temp + 15)) / 3;
+	else if ((0 <= temp) && (temp < 20))
+		ret = 4 * temp + 10;
+	else if ((20 <= temp) && (temp < 35))
+		ret = (2 * (temp - 20)) / 3 + 90;
+	else if (temp >= 35)
+		ret = 100;
+
+	deb_info("Signal Strength :%d", ret);
+
+	return ret;
+}
+
+static int it913x_fe_read_signal_strength(struct dvb_frontend *fe,
+		u16 *strength)
+{
+	struct it913x_fe_state *state = fe->demodulator_priv;
+	int ret = 0;
+	if (state->config->read_slevel) {
+		if (state->it913x_status & FE_HAS_SIGNAL)
+			ret = it913x_read_reg_u8(state, SIGNAL_LEVEL);
+	} else
+		ret = it913x_get_signal_strength(fe);
+
+	if (ret >= 0)
+		*strength = (u16)((u32)ret * 0xffff / 0x64);
+
+	return (ret < 0) ? -ENODEV : 0;
+}
+
+static int it913x_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct it913x_fe_state *state = fe->demodulator_priv;
+	int ret;
+	u8 reg[3];
+	u32 snr_val, snr_min, snr_max;
+	u32 temp;
+
+	ret = it913x_read_reg(state, 0x2c, reg, sizeof(reg));
+
+	snr_val = (u32)(reg[2] << 16) | (reg[1] << 8) | reg[0];
+
+	ret |= it913x_read_reg(state, 0xf78b, reg, 1);
+	if (reg[0])
+		snr_val /= reg[0];
+
+	if (state->transmission_mode == TRANSMISSION_MODE_2K)
+		snr_val *= 4;
+	else if (state->transmission_mode == TRANSMISSION_MODE_4K)
+		snr_val *= 2;
+
+	if (state->constellation == QPSK) {
+		snr_min = 0xb4711;
+		snr_max = 0x191451;
+	} else if (state->constellation == QAM_16) {
+		snr_min = 0x4f0d5;
+		snr_max = 0xc7925;
+	} else if (state->constellation == QAM_64) {
+		snr_min = 0x256d0;
+		snr_max = 0x626be;
+	} else
+		return -EINVAL;
+
+	if (snr_val < snr_min)
+		*snr = 0;
+	else if (snr_val < snr_max) {
+		temp = (snr_val - snr_min) >> 5;
+		temp *= 0xffff;
+		temp /= (snr_max - snr_min) >> 5;
+		*snr = (u16)temp;
+	} else
+		*snr = 0xffff;
+
+	return (ret < 0) ? -ENODEV : 0;
+}
+
+static int it913x_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct it913x_fe_state *state = fe->demodulator_priv;
+	u8 reg[5];
+	/* Read Aborted Packets and Pre-Viterbi error rate 5 bytes */
+	it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg));
+	state->ucblocks += (u32)(reg[1] << 8) | reg[0];
+	*ber = (u32)(reg[4] << 16) | (reg[3] << 8) | reg[2];
+	return 0;
+}
+
+static int it913x_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct it913x_fe_state *state = fe->demodulator_priv;
+	int ret;
+	u8 reg[2];
+	/* Aborted Packets */
+	ret = it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg));
+	state->ucblocks += (u32)(reg[1] << 8) | reg[0];
+	*ucblocks = state->ucblocks;
+	return ret;
+}
+
+static int it913x_fe_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct it913x_fe_state *state = fe->demodulator_priv;
+	u8 reg[8];
+
+	it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg));
+
+	if (reg[3] < 3)
+		p->modulation = fe_con[reg[3]];
+
+	if (reg[0] < 3)
+		p->transmission_mode = fe_mode[reg[0]];
+
+	if (reg[1] < 4)
+		p->guard_interval = fe_gi[reg[1]];
+
+	if (reg[2] < 4)
+		p->hierarchy = fe_hi[reg[2]];
+
+	state->priority = reg[5];
+
+	p->code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE;
+	p->code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE;
+
+	/* Update internal state to reflect the autodetected props */
+	state->constellation = p->modulation;
+	state->transmission_mode = p->transmission_mode;
+
+	return 0;
+}
+
+static int it913x_fe_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct it913x_fe_state *state = fe->demodulator_priv;
+	int i;
+	u8 empty_ch, last_ch;
+
+	state->it913x_status = 0;
+
+	/* Set bw*/
+	it913x_fe_select_bw(state, p->bandwidth_hz,
+		state->adcFrequency);
+
+	/* Training Mode Off */
+	it913x_write_reg(state, PRO_LINK, TRAINING_MODE, 0x0);
+
+	/* Clear Empty Channel */
+	it913x_write_reg(state, PRO_DMOD, EMPTY_CHANNEL_STATUS, 0x0);
+
+	/* Clear bits */
+	it913x_write_reg(state, PRO_DMOD, MP2IF_SYNC_LK, 0x0);
+	/* LED on */
+	it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1);
+	/* Select Band*/
+	if ((p->frequency >= 51000000) && (p->frequency <= 230000000))
+		i = 0;
+	else if ((p->frequency >= 350000000) && (p->frequency <= 900000000))
+			i = 1;
+	else if ((p->frequency >= 1450000000) && (p->frequency <= 1680000000))
+			i = 2;
+	else
+		return -EOPNOTSUPP;
+
+	it913x_write_reg(state, PRO_DMOD, FREE_BAND, i);
+
+	deb_info("Frontend Set Tuner Type %02x", state->tuner_type);
+	switch (state->tuner_type) {
+	case IT9135_38:
+	case IT9135_51:
+	case IT9135_52:
+	case IT9135_60:
+	case IT9135_61:
+	case IT9135_62:
+		it9137_set_tuner(state,
+			p->bandwidth_hz, p->frequency);
+		break;
+	default:
+		if (fe->ops.tuner_ops.set_params) {
+			fe->ops.tuner_ops.set_params(fe);
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+		break;
+	}
+	/* LED off */
+	it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0);
+	/* Trigger ofsm */
+	it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0);
+	last_ch = 2;
+	for (i = 0; i < 40; ++i) {
+		empty_ch = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS);
+		if (last_ch == 1 && empty_ch == 1)
+			break;
+		if (last_ch == 2 && empty_ch == 2)
+			return 0;
+		last_ch = empty_ch;
+		msleep(25);
+	}
+	for (i = 0; i < 40; ++i) {
+		if (it913x_read_reg_u8(state, D_TPSD_LOCK) == 1)
+			break;
+		msleep(25);
+	}
+
+	state->frequency = p->frequency;
+	return 0;
+}
+
+static int it913x_fe_suspend(struct it913x_fe_state *state)
+{
+	int ret, i;
+	u8 b;
+
+	ret = it913x_write_reg(state, PRO_DMOD, SUSPEND_FLAG, 0x1);
+
+	ret |= it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0);
+
+	for (i = 0; i < 128; i++) {
+		ret = it913x_read_reg(state, SUSPEND_FLAG, &b, 1);
+		if (ret < 0)
+			return -ENODEV;
+		if (b == 0)
+			break;
+
+	}
+
+	ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x8);
+	/* Turn LED off */
+	ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0);
+
+	ret |= it913x_fe_script_loader(state, it9137_tuner_off);
+
+	return (ret < 0) ? -ENODEV : 0;
+}
+
+/* Power sequence */
+/* Power Up	Tuner on -> Frontend suspend off -> Tuner clk on */
+/* Power Down	Frontend suspend on -> Tuner clk off -> Tuner off */
+
+static int it913x_fe_sleep(struct dvb_frontend *fe)
+{
+	struct it913x_fe_state *state = fe->demodulator_priv;
+	return it913x_fe_suspend(state);
+}
+
+static u32 compute_div(u32 a, u32 b, u32 x)
+{
+	u32 res = 0;
+	u32 c = 0;
+	u32 i = 0;
+
+	if (a > b) {
+		c = a / b;
+		a = a - c * b;
+	}
+
+	for (i = 0; i < x; i++) {
+		if (a >= b) {
+			res += 1;
+			a -= b;
+		}
+		a <<= 1;
+		res <<= 1;
+	}
+
+	res = (c << x) + res;
+
+	return res;
+}
+
+static int it913x_fe_start(struct it913x_fe_state *state)
+{
+	struct it913xset *set_lna;
+	struct it913xset *set_mode;
+	int ret;
+	u8 adf = (state->config->adf & 0xf);
+	u32 adc, xtal;
+	u8 b[4];
+
+	if (state->config->chip_ver == 1)
+		ret = it913x_init_tuner(state);
+
+	info("ADF table value	:%02x", adf);
+
+	if (adf < 10) {
+		state->crystalFrequency = fe_clockTable[adf].xtal ;
+		state->table = fe_clockTable[adf].table;
+		state->adcFrequency = state->table->adcFrequency;
+
+		adc = compute_div(state->adcFrequency, 1000000ul, 19ul);
+		xtal = compute_div(state->crystalFrequency, 1000000ul, 19ul);
+
+	} else
+		return -EINVAL;
+
+	/* Set LED indicator on GPIOH3 */
+	ret = it913x_write_reg(state, PRO_LINK, GPIOH3_EN, 0x1);
+	ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_ON, 0x1);
+	ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1);
+
+	ret |= it913x_write_reg(state, PRO_LINK, 0xf641, state->tuner_type);
+	ret |= it913x_write_reg(state, PRO_DMOD, 0xf5ca, 0x01);
+	ret |= it913x_write_reg(state, PRO_DMOD, 0xf715, 0x01);
+
+	b[0] = xtal & 0xff;
+	b[1] = (xtal >> 8) & 0xff;
+	b[2] = (xtal >> 16) & 0xff;
+	b[3] = (xtal >> 24);
+	ret |= it913x_write(state, PRO_DMOD, XTAL_CLK, b , 4);
+
+	b[0] = adc & 0xff;
+	b[1] = (adc >> 8) & 0xff;
+	b[2] = (adc >> 16) & 0xff;
+	ret |= it913x_write(state, PRO_DMOD, ADC_FREQ, b, 3);
+
+	if (state->config->adc_x2)
+		ret |= it913x_write_reg(state, PRO_DMOD, ADC_X_2, 0x01);
+	b[0] = 0;
+	b[1] = 0;
+	b[2] = 0;
+	ret |= it913x_write(state, PRO_DMOD, 0x0029, b, 3);
+
+	info("Crystal Frequency :%d Adc Frequency :%d ADC X2: %02x",
+		state->crystalFrequency, state->adcFrequency,
+			state->config->adc_x2);
+	deb_info("Xtal value :%04x Adc value :%04x", xtal, adc);
+
+	if (ret < 0)
+		return -ENODEV;
+
+	/* v1 or v2 tuner script */
+	if (state->config->chip_ver > 1)
+		ret = it913x_fe_script_loader(state, it9135_v2);
+	else
+		ret = it913x_fe_script_loader(state, it9135_v1);
+	if (ret < 0)
+		return ret;
+
+	/* LNA Scripts */
+	switch (state->tuner_type) {
+	case IT9135_51:
+		set_lna = it9135_51;
+		break;
+	case IT9135_52:
+		set_lna = it9135_52;
+		break;
+	case IT9135_60:
+		set_lna = it9135_60;
+		break;
+	case IT9135_61:
+		set_lna = it9135_61;
+		break;
+	case IT9135_62:
+		set_lna = it9135_62;
+		break;
+	case IT9135_38:
+	default:
+		set_lna = it9135_38;
+	}
+	info("Tuner LNA type :%02x", state->tuner_type);
+
+	ret = it913x_fe_script_loader(state, set_lna);
+	if (ret < 0)
+		return ret;
+
+	if (state->config->chip_ver == 2) {
+		ret = it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x1);
+		ret |= it913x_write_reg(state, PRO_LINK, PADODPU, 0x0);
+		ret |= it913x_write_reg(state, PRO_LINK, AGC_O_D, 0x0);
+		ret |= it913x_init_tuner(state);
+	}
+	if (ret < 0)
+		return -ENODEV;
+
+	/* Always solo frontend */
+	set_mode = set_solo_fe;
+	ret |= it913x_fe_script_loader(state, set_mode);
+
+	ret |= it913x_fe_suspend(state);
+	return (ret < 0) ? -ENODEV : 0;
+}
+
+static int it913x_fe_init(struct dvb_frontend *fe)
+{
+	struct it913x_fe_state *state = fe->demodulator_priv;
+	int ret = 0;
+	/* Power Up Tuner - common all versions */
+	ret = it913x_write_reg(state, PRO_DMOD, 0xec40, 0x1);
+
+	ret |= it913x_fe_script_loader(state, init_1);
+
+	ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0);
+
+	ret |= it913x_write_reg(state, PRO_DMOD, 0xfba8, 0x0);
+
+	return (ret < 0) ? -ENODEV : 0;
+}
+
+static void it913x_fe_release(struct dvb_frontend *fe)
+{
+	struct it913x_fe_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops it913x_fe_ofdm_ops;
+
+struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap,
+		u8 i2c_addr, struct ite_config *config)
+{
+	struct it913x_fe_state *state = NULL;
+	int ret;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct it913x_fe_state), GFP_KERNEL);
+	if (state == NULL)
+		return NULL;
+	if (config == NULL)
+		goto error;
+
+	state->i2c_adap = i2c_adap;
+	state->i2c_addr = i2c_addr;
+	state->config = config;
+
+	switch (state->config->tuner_id_0) {
+	case IT9135_51:
+	case IT9135_52:
+	case IT9135_60:
+	case IT9135_61:
+	case IT9135_62:
+		state->tuner_type = state->config->tuner_id_0;
+		break;
+	default:
+	case IT9135_38:
+		state->tuner_type = IT9135_38;
+	}
+
+	ret = it913x_fe_start(state);
+	if (ret < 0)
+		goto error;
+
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &it913x_fe_ofdm_ops,
+			sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	return &state->frontend;
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(it913x_fe_attach);
+
+static struct dvb_frontend_ops it913x_fe_ofdm_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name			= "it913x-fe DVB-T",
+		.frequency_min		= 51000000,
+		.frequency_max		= 1680000000,
+		.frequency_stepsize	= 62500,
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+			FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
+			FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.release = it913x_fe_release,
+
+	.init = it913x_fe_init,
+	.sleep = it913x_fe_sleep,
+
+	.set_frontend = it913x_fe_set_frontend,
+	.get_frontend = it913x_fe_get_frontend,
+
+	.read_status = it913x_fe_read_status,
+	.read_signal_strength = it913x_fe_read_signal_strength,
+	.read_snr = it913x_fe_read_snr,
+	.read_ber = it913x_fe_read_ber,
+	.read_ucblocks = it913x_fe_read_ucblocks,
+};
+
+MODULE_DESCRIPTION("it913x Frontend and it9137 tuner");
+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
+MODULE_VERSION("1.15");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/it913x-fe.h b/drivers/media/dvb-frontends/it913x-fe.h
new file mode 100644
index 0000000..07fa459
--- /dev/null
+++ b/drivers/media/dvb-frontends/it913x-fe.h
@@ -0,0 +1,237 @@
+/*
+ *  Driver for it913x Frontend
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef IT913X_FE_H
+#define IT913X_FE_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct ite_config {
+	u8 chip_ver;
+	u16 chip_type;
+	u32 firmware;
+	u8 firmware_ver;
+	u8 adc_x2;
+	u8 tuner_id_0;
+	u8 tuner_id_1;
+	u8 dual_mode;
+	u8 adf;
+	/* option to read SIGNAL_LEVEL */
+	u8 read_slevel;
+};
+
+#if defined(CONFIG_DVB_IT913X_FE) || (defined(CONFIG_DVB_IT913X_FE_MODULE) && \
+defined(MODULE))
+extern struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap,
+			u8 i2c_addr, struct ite_config *config);
+#else
+static inline struct dvb_frontend *it913x_fe_attach(
+		struct i2c_adapter *i2c_adap,
+			u8 i2c_addr, struct ite_config *config)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_IT913X_FE */
+#define I2C_BASE_ADDR		0x10
+#define DEV_0			0x0
+#define DEV_1			0x10
+#define PRO_LINK		0x0
+#define PRO_DMOD		0x1
+#define DEV_0_DMOD		(PRO_DMOD << 0x7)
+#define DEV_1_DMOD		(DEV_0_DMOD | DEV_1)
+#define CHIP2_I2C_ADDR		0x3a
+
+#define AFE_MEM0		0xfb24
+
+#define MP2_SW_RST		0xf99d
+#define MP2IF2_SW_RST		0xf9a4
+
+#define	PADODPU			0xd827
+#define THIRDODPU		0xd828
+#define AGC_O_D			0xd829
+
+#define EP0_TX_EN		0xdd11
+#define EP0_TX_NAK		0xdd13
+#define EP4_TX_LEN_LSB		0xdd88
+#define EP4_TX_LEN_MSB		0xdd89
+#define EP4_MAX_PKT		0xdd0c
+#define EP5_TX_LEN_LSB		0xdd8a
+#define EP5_TX_LEN_MSB		0xdd8b
+#define EP5_MAX_PKT		0xdd0d
+
+#define IO_MUX_POWER_CLK	0xd800
+#define CLK_O_EN		0xd81a
+#define I2C_CLK			0xf103
+#define I2C_CLK_100		0x7
+#define I2C_CLK_400		0x1a
+
+#define D_TPSD_LOCK		0xf5a9
+#define MP2IF2_EN		0xf9a3
+#define MP2IF_SERIAL		0xf985
+#define TSIS_ENABLE		0xf9cd
+#define MP2IF2_HALF_PSB		0xf9a5
+#define MP2IF_STOP_EN		0xf9b5
+#define MPEG_FULL_SPEED		0xf990
+#define TOP_HOSTB_SER_MODE	0xd91c
+
+#define PID_RST			0xf992
+#define PID_EN			0xf993
+#define PID_INX_EN		0xf994
+#define PID_INX			0xf995
+#define PID_LSB			0xf996
+#define PID_MSB			0xf997
+
+#define MP2IF_MPEG_PAR_MODE	0xf986
+#define DCA_UPPER_CHIP		0xf731
+#define DCA_LOWER_CHIP		0xf732
+#define DCA_PLATCH		0xf730
+#define DCA_FPGA_LATCH		0xf778
+#define DCA_STAND_ALONE		0xf73c
+#define DCA_ENABLE		0xf776
+
+#define DVBT_INTEN		0xf41f
+#define DVBT_ENABLE		0xf41a
+#define HOSTB_DCA_LOWER		0xd91f
+#define HOSTB_MPEG_PAR_MODE	0xd91b
+#define HOSTB_MPEG_SER_MODE	0xd91c
+#define HOSTB_MPEG_SER_DO7	0xd91d
+#define HOSTB_DCA_UPPER		0xd91e
+#define PADMISCDR2		0xd830
+#define PADMISCDR4		0xd831
+#define PADMISCDR8		0xd832
+#define PADMISCDRSR		0xd833
+#define LOCK3_OUT		0xd8fd
+
+#define GPIOH1_O		0xd8af
+#define GPIOH1_EN		0xd8b0
+#define GPIOH1_ON		0xd8b1
+#define GPIOH3_O		0xd8b3
+#define GPIOH3_EN		0xd8b4
+#define GPIOH3_ON		0xd8b5
+#define GPIOH5_O		0xd8bb
+#define GPIOH5_EN		0xd8bc
+#define GPIOH5_ON		0xd8bd
+
+#define AFE_MEM0		0xfb24
+
+#define REG_TPSD_TX_MODE	0xf900
+#define REG_TPSD_GI		0xf901
+#define REG_TPSD_HIER		0xf902
+#define REG_TPSD_CONST		0xf903
+#define REG_BW			0xf904
+#define REG_PRIV		0xf905
+#define REG_TPSD_HP_CODE	0xf906
+#define REG_TPSD_LP_CODE	0xf907
+
+#define MP2IF_SYNC_LK		0xf999
+#define ADC_FREQ		0xf1cd
+
+#define TRIGGER_OFSM		0x0000
+/* COEFF Registers start at 0x0001 to 0x0020 */
+#define COEFF_1_2048		0x0001
+#define XTAL_CLK		0x0025
+#define BFS_FCW			0x0029
+
+/* Error Regs */
+#define RSD_ABORT_PKT_LSB	0x0032
+#define RSD_ABORT_PKT_MSB	0x0033
+#define RSD_BIT_ERR_0_7		0x0034
+#define RSD_BIT_ERR_8_15	0x0035
+#define RSD_BIT_ERR_23_16	0x0036
+#define RSD_BIT_COUNT_LSB	0x0037
+#define RSD_BIT_COUNT_MSB	0x0038
+
+#define TPSD_LOCK		0x003c
+#define TRAINING_MODE		0x0040
+#define ADC_X_2			0x0045
+#define TUNER_ID		0x0046
+#define EMPTY_CHANNEL_STATUS	0x0047
+#define SIGNAL_LEVEL		0x0048
+#define SIGNAL_QUALITY		0x0049
+#define EST_SIGNAL_LEVEL	0x004a
+#define FREE_BAND		0x004b
+#define SUSPEND_FLAG		0x004c
+#define VAR_P_INBAND		0x00f7
+
+/* Build in tuner types */
+#define IT9137 0x38
+#define IT9135_38 0x38
+#define IT9135_51 0x51
+#define IT9135_52 0x52
+#define IT9135_60 0x60
+#define IT9135_61 0x61
+#define IT9135_62 0x62
+
+enum {
+	CMD_DEMOD_READ = 0,
+	CMD_DEMOD_WRITE,
+	CMD_TUNER_READ,
+	CMD_TUNER_WRITE,
+	CMD_REG_EEPROM_READ,
+	CMD_REG_EEPROM_WRITE,
+	CMD_DATA_READ,
+	CMD_VAR_READ = 8,
+	CMD_VAR_WRITE,
+	CMD_PLATFORM_GET,
+	CMD_PLATFORM_SET,
+	CMD_IP_CACHE,
+	CMD_IP_ADD,
+	CMD_IP_REMOVE,
+	CMD_PID_ADD,
+	CMD_PID_REMOVE,
+	CMD_SIPSI_GET,
+	CMD_SIPSI_MPE_RESET,
+	CMD_H_PID_ADD = 0x15,
+	CMD_H_PID_REMOVE,
+	CMD_ABORT,
+	CMD_IR_GET,
+	CMD_IR_SET,
+	CMD_FW_DOWNLOAD = 0x21,
+	CMD_QUERYINFO,
+	CMD_BOOT,
+	CMD_FW_DOWNLOAD_BEGIN,
+	CMD_FW_DOWNLOAD_END,
+	CMD_RUN_CODE,
+	CMD_SCATTER_READ = 0x28,
+	CMD_SCATTER_WRITE,
+	CMD_GENERIC_READ,
+	CMD_GENERIC_WRITE
+};
+
+enum {
+	READ_LONG,
+	WRITE_LONG,
+	READ_SHORT,
+	WRITE_SHORT,
+	READ_DATA,
+	WRITE_DATA,
+	WRITE_CMD,
+};
+
+enum {
+	IT9135_AUTO = 0,
+	IT9137_FW,
+	IT9135_V1_FW,
+	IT9135_V2_FW,
+};
+
+#endif /* IT913X_FE_H */
diff --git a/drivers/media/dvb-frontends/itd1000.c b/drivers/media/dvb-frontends/itd1000.c
new file mode 100644
index 0000000..3164575
--- /dev/null
+++ b/drivers/media/dvb-frontends/itd1000.c
@@ -0,0 +1,399 @@
+/*
+ *  Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite"
+ *
+ *  Copyright (c) 2007-8 Patrick Boettcher <pb@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+
+#include "itd1000.h"
+#include "itd1000_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define itd_dbg(args...)  do { \
+	if (debug) { \
+		printk(KERN_DEBUG   "ITD1000: " args);\
+	} \
+} while (0)
+
+#define itd_warn(args...) do { \
+	printk(KERN_WARNING "ITD1000: " args); \
+} while (0)
+
+#define itd_info(args...) do { \
+	printk(KERN_INFO    "ITD1000: " args); \
+} while (0)
+
+/* don't write more than one byte with flexcop behind */
+static int itd1000_write_regs(struct itd1000_state *state, u8 reg, u8 v[], u8 len)
+{
+	u8 buf[1+len];
+	struct i2c_msg msg = {
+		.addr = state->cfg->i2c_address, .flags = 0, .buf = buf, .len = len+1
+	};
+	buf[0] = reg;
+	memcpy(&buf[1], v, len);
+
+	/* itd_dbg("wr %02x: %02x\n", reg, v[0]); */
+
+	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "itd1000 I2C write failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int itd1000_read_reg(struct itd1000_state *state, u8 reg)
+{
+	u8 val;
+	struct i2c_msg msg[2] = {
+		{ .addr = state->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
+		{ .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = &val, .len = 1 },
+	};
+
+	/* ugly flexcop workaround */
+	itd1000_write_regs(state, (reg - 1) & 0xff, &state->shadow[(reg - 1) & 0xff], 1);
+
+	if (i2c_transfer(state->i2c, msg, 2) != 2) {
+		itd_warn("itd1000 I2C read failed\n");
+		return -EREMOTEIO;
+	}
+	return val;
+}
+
+static inline int itd1000_write_reg(struct itd1000_state *state, u8 r, u8 v)
+{
+	int ret = itd1000_write_regs(state, r, &v, 1);
+	state->shadow[r] = v;
+	return ret;
+}
+
+
+static struct {
+	u32 symbol_rate;
+	u8  pgaext  : 4; /* PLLFH */
+	u8  bbgvmin : 4; /* BBGVMIN */
+} itd1000_lpf_pga[] = {
+	{        0, 0x8, 0x3 },
+	{  5200000, 0x8, 0x3 },
+	{ 12200000, 0x4, 0x3 },
+	{ 15400000, 0x2, 0x3 },
+	{ 19800000, 0x2, 0x3 },
+	{ 21500000, 0x2, 0x3 },
+	{ 24500000, 0x2, 0x3 },
+	{ 28400000, 0x2, 0x3 },
+	{ 33400000, 0x2, 0x3 },
+	{ 34400000, 0x1, 0x4 },
+	{ 34400000, 0x1, 0x4 },
+	{ 38400000, 0x1, 0x4 },
+	{ 38400000, 0x1, 0x4 },
+	{ 40400000, 0x1, 0x4 },
+	{ 45400000, 0x1, 0x4 },
+};
+
+static void itd1000_set_lpf_bw(struct itd1000_state *state, u32 symbol_rate)
+{
+	u8 i;
+	u8 con1    = itd1000_read_reg(state, CON1)    & 0xfd;
+	u8 pllfh   = itd1000_read_reg(state, PLLFH)   & 0x0f;
+	u8 bbgvmin = itd1000_read_reg(state, BBGVMIN) & 0xf0;
+	u8 bw      = itd1000_read_reg(state, BW)      & 0xf0;
+
+	itd_dbg("symbol_rate = %d\n", symbol_rate);
+
+	/* not sure what is that ? - starting to download the table */
+	itd1000_write_reg(state, CON1, con1 | (1 << 1));
+
+	for (i = 0; i < ARRAY_SIZE(itd1000_lpf_pga); i++)
+		if (symbol_rate < itd1000_lpf_pga[i].symbol_rate) {
+			itd_dbg("symrate: index: %d pgaext: %x, bbgvmin: %x\n", i, itd1000_lpf_pga[i].pgaext, itd1000_lpf_pga[i].bbgvmin);
+			itd1000_write_reg(state, PLLFH,   pllfh | (itd1000_lpf_pga[i].pgaext << 4));
+			itd1000_write_reg(state, BBGVMIN, bbgvmin | (itd1000_lpf_pga[i].bbgvmin));
+			itd1000_write_reg(state, BW,      bw | (i & 0x0f));
+			break;
+		}
+
+	itd1000_write_reg(state, CON1, con1 | (0 << 1));
+}
+
+static struct {
+	u8 vcorg;
+	u32 fmax_rg;
+} itd1000_vcorg[] = {
+	{  1,  920000 },
+	{  2,  971000 },
+	{  3, 1031000 },
+	{  4, 1091000 },
+	{  5, 1171000 },
+	{  6, 1281000 },
+	{  7, 1381000 },
+	{  8,  500000 },	/* this is intentional. */
+	{  9, 1451000 },
+	{ 10, 1531000 },
+	{ 11, 1631000 },
+	{ 12, 1741000 },
+	{ 13, 1891000 },
+	{ 14, 2071000 },
+	{ 15, 2250000 },
+};
+
+static void itd1000_set_vco(struct itd1000_state *state, u32 freq_khz)
+{
+	u8 i;
+	u8 gvbb_i2c     = itd1000_read_reg(state, GVBB_I2C) & 0xbf;
+	u8 vco_chp1_i2c = itd1000_read_reg(state, VCO_CHP1_I2C) & 0x0f;
+	u8 adcout;
+
+	/* reserved bit again (reset ?) */
+	itd1000_write_reg(state, GVBB_I2C, gvbb_i2c | (1 << 6));
+
+	for (i = 0; i < ARRAY_SIZE(itd1000_vcorg); i++) {
+		if (freq_khz < itd1000_vcorg[i].fmax_rg) {
+			itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | (itd1000_vcorg[i].vcorg << 4));
+			msleep(1);
+
+			adcout = itd1000_read_reg(state, PLLLOCK) & 0x0f;
+
+			itd_dbg("VCO: %dkHz: %d -> ADCOUT: %d %02x\n", freq_khz, itd1000_vcorg[i].vcorg, adcout, vco_chp1_i2c);
+
+			if (adcout > 13) {
+				if (!(itd1000_vcorg[i].vcorg == 7 || itd1000_vcorg[i].vcorg == 15))
+					itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | ((itd1000_vcorg[i].vcorg + 1) << 4));
+			} else if (adcout < 2) {
+				if (!(itd1000_vcorg[i].vcorg == 1 || itd1000_vcorg[i].vcorg == 9))
+					itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | ((itd1000_vcorg[i].vcorg - 1) << 4));
+			}
+			break;
+		}
+	}
+}
+
+static const struct {
+	u32 freq;
+	u8 values[10]; /* RFTR, RFST1 - RFST9 */
+} itd1000_fre_values[] = {
+	{ 1075000, { 0x59, 0x1d, 0x1c, 0x17, 0x16, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
+	{ 1250000, { 0x89, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
+	{ 1450000, { 0x89, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
+	{ 1650000, { 0x69, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
+	{ 1750000, { 0x69, 0x1e, 0x17, 0x15, 0x14, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
+	{ 1850000, { 0x69, 0x1d, 0x17, 0x16, 0x14, 0x0f, 0x0e, 0x0d, 0x0b, 0x0a } },
+	{ 1900000, { 0x69, 0x1d, 0x17, 0x15, 0x14, 0x0f, 0x0e, 0x0d, 0x0b, 0x0a } },
+	{ 1950000, { 0x69, 0x1d, 0x17, 0x16, 0x14, 0x13, 0x0e, 0x0d, 0x0b, 0x0a } },
+	{ 2050000, { 0x69, 0x1e, 0x1d, 0x17, 0x16, 0x14, 0x13, 0x0e, 0x0b, 0x0a } },
+	{ 2150000, { 0x69, 0x1d, 0x1c, 0x17, 0x15, 0x14, 0x13, 0x0f, 0x0e, 0x0b } }
+};
+
+
+#define FREF 16
+
+static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz)
+{
+	int i, j;
+	u32 plln, pllf;
+	u64 tmp;
+
+	plln = (freq_khz * 1000) / 2 / FREF;
+
+	/* Compute the factional part times 1000 */
+	tmp  = plln % 1000000;
+	plln /= 1000000;
+
+	tmp *= 1048576;
+	do_div(tmp, 1000000);
+	pllf = (u32) tmp;
+
+	state->frequency = ((plln * 1000) + (pllf * 1000)/1048576) * 2*FREF;
+	itd_dbg("frequency: %dkHz (wanted) %dkHz (set), PLLF = %d, PLLN = %d\n", freq_khz, state->frequency, pllf, plln);
+
+	itd1000_write_reg(state, PLLNH, 0x80); /* PLLNH */;
+	itd1000_write_reg(state, PLLNL, plln & 0xff);
+	itd1000_write_reg(state, PLLFH, (itd1000_read_reg(state, PLLFH) & 0xf0) | ((pllf >> 16) & 0x0f));
+	itd1000_write_reg(state, PLLFM, (pllf >> 8) & 0xff);
+	itd1000_write_reg(state, PLLFL, (pllf >> 0) & 0xff);
+
+	for (i = 0; i < ARRAY_SIZE(itd1000_fre_values); i++) {
+		if (freq_khz <= itd1000_fre_values[i].freq) {
+			itd_dbg("fre_values: %d\n", i);
+			itd1000_write_reg(state, RFTR, itd1000_fre_values[i].values[0]);
+			for (j = 0; j < 9; j++)
+				itd1000_write_reg(state, RFST1+j, itd1000_fre_values[i].values[j+1]);
+			break;
+		}
+	}
+
+	itd1000_set_vco(state, freq_khz);
+}
+
+static int itd1000_set_parameters(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct itd1000_state *state = fe->tuner_priv;
+	u8 pllcon1;
+
+	itd1000_set_lo(state, c->frequency);
+	itd1000_set_lpf_bw(state, c->symbol_rate);
+
+	pllcon1 = itd1000_read_reg(state, PLLCON1) & 0x7f;
+	itd1000_write_reg(state, PLLCON1, pllcon1 | (1 << 7));
+	itd1000_write_reg(state, PLLCON1, pllcon1);
+
+	return 0;
+}
+
+static int itd1000_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct itd1000_state *state = fe->tuner_priv;
+	*frequency = state->frequency;
+	return 0;
+}
+
+static int itd1000_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	return 0;
+}
+
+static u8 itd1000_init_tab[][2] = {
+	{ PLLCON1,       0x65 }, /* Register does not change */
+	{ PLLNH,         0x80 }, /* Bits [7:6] do not change */
+	{ RESERVED_0X6D, 0x3b },
+	{ VCO_CHP2_I2C,  0x12 },
+	{ 0x72,          0xf9 }, /* No such regsister defined */
+	{ RESERVED_0X73, 0xff },
+	{ RESERVED_0X74, 0xb2 },
+	{ RESERVED_0X75, 0xc7 },
+	{ EXTGVBBRF,     0xf0 },
+	{ DIVAGCCK,      0x80 },
+	{ BBTR,          0xa0 },
+	{ RESERVED_0X7E, 0x4f },
+	{ 0x82,          0x88 }, /* No such regsister defined */
+	{ 0x83,          0x80 }, /* No such regsister defined */
+	{ 0x84,          0x80 }, /* No such regsister defined */
+	{ RESERVED_0X85, 0x74 },
+	{ RESERVED_0X86, 0xff },
+	{ RESERVED_0X88, 0x02 },
+	{ RESERVED_0X89, 0x16 },
+	{ RFST0,         0x1f },
+	{ RESERVED_0X94, 0x66 },
+	{ RESERVED_0X95, 0x66 },
+	{ RESERVED_0X96, 0x77 },
+	{ RESERVED_0X97, 0x99 },
+	{ RESERVED_0X98, 0xff },
+	{ RESERVED_0X99, 0xfc },
+	{ RESERVED_0X9A, 0xba },
+	{ RESERVED_0X9B, 0xaa },
+};
+
+static u8 itd1000_reinit_tab[][2] = {
+	{ VCO_CHP1_I2C, 0x8a },
+	{ BW,           0x87 },
+	{ GVBB_I2C,     0x03 },
+	{ BBGVMIN,      0x03 },
+	{ CON1,         0x2e },
+};
+
+
+static int itd1000_init(struct dvb_frontend *fe)
+{
+	struct itd1000_state *state = fe->tuner_priv;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(itd1000_init_tab); i++)
+		itd1000_write_reg(state, itd1000_init_tab[i][0], itd1000_init_tab[i][1]);
+
+	for (i = 0; i < ARRAY_SIZE(itd1000_reinit_tab); i++)
+		itd1000_write_reg(state, itd1000_reinit_tab[i][0], itd1000_reinit_tab[i][1]);
+
+	return 0;
+}
+
+static int itd1000_sleep(struct dvb_frontend *fe)
+{
+	return 0;
+}
+
+static int itd1000_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static const struct dvb_tuner_ops itd1000_tuner_ops = {
+	.info = {
+		.name           = "Integrant ITD1000",
+		.frequency_min  = 950000,
+		.frequency_max  = 2150000,
+		.frequency_step = 125,     /* kHz for QPSK frontends */
+	},
+
+	.release       = itd1000_release,
+
+	.init          = itd1000_init,
+	.sleep         = itd1000_sleep,
+
+	.set_params    = itd1000_set_parameters,
+	.get_frequency = itd1000_get_frequency,
+	.get_bandwidth = itd1000_get_bandwidth
+};
+
+
+struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg)
+{
+	struct itd1000_state *state = NULL;
+	u8 i = 0;
+
+	state = kzalloc(sizeof(struct itd1000_state), GFP_KERNEL);
+	if (state == NULL)
+		return NULL;
+
+	state->cfg = cfg;
+	state->i2c = i2c;
+
+	i = itd1000_read_reg(state, 0);
+	if (i != 0) {
+		kfree(state);
+		return NULL;
+	}
+	itd_info("successfully identified (ID: %d)\n", i);
+
+	memset(state->shadow, 0xff, sizeof(state->shadow));
+	for (i = 0x65; i < 0x9c; i++)
+		state->shadow[i] = itd1000_read_reg(state, i);
+
+	memcpy(&fe->ops.tuner_ops, &itd1000_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = state;
+
+	return fe;
+}
+EXPORT_SYMBOL(itd1000_attach);
+
+MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>");
+MODULE_DESCRIPTION("Integrant ITD1000 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/itd1000.h b/drivers/media/dvb-frontends/itd1000.h
new file mode 100644
index 0000000..5e18df0
--- /dev/null
+++ b/drivers/media/dvb-frontends/itd1000.h
@@ -0,0 +1,42 @@
+/*
+ *  Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite"
+ *
+ *  Copyright (c) 2007 Patrick Boettcher <pb@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef ITD1000_H
+#define ITD1000_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct itd1000_config {
+	u8 i2c_address;
+};
+
+#if defined(CONFIG_DVB_TUNER_ITD1000) || (defined(CONFIG_DVB_TUNER_ITD1000_MODULE) && defined(MODULE))
+extern struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg);
+#else
+static inline struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb-frontends/itd1000_priv.h b/drivers/media/dvb-frontends/itd1000_priv.h
new file mode 100644
index 0000000..08ca851
--- /dev/null
+++ b/drivers/media/dvb-frontends/itd1000_priv.h
@@ -0,0 +1,88 @@
+/*
+ *  Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite"
+ *
+ *  Copyright (c) 2007 Patrick Boettcher <pb@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef ITD1000_PRIV_H
+#define ITD1000_PRIV_H
+
+struct itd1000_state {
+	struct itd1000_config *cfg;
+	struct i2c_adapter    *i2c;
+
+	u32 frequency; /* contains the value resulting from the LO-setting */
+
+	/* ugly workaround for flexcop's incapable i2c-controller
+	 * FIXME, if possible
+	 */
+	u8 shadow[256];
+};
+
+enum itd1000_register {
+	VCO_CHP1 = 0x65,
+	VCO_CHP2,
+	PLLCON1,
+	PLLNH,
+	PLLNL,
+	PLLFH,
+	PLLFM,
+	PLLFL,
+	RESERVED_0X6D,
+	PLLLOCK,
+	VCO_CHP2_I2C,
+	VCO_CHP1_I2C,
+	BW,
+	RESERVED_0X73 = 0x73,
+	RESERVED_0X74,
+	RESERVED_0X75,
+	GVBB,
+	GVRF,
+	GVBB_I2C,
+	EXTGVBBRF,
+	DIVAGCCK,
+	BBTR,
+	RFTR,
+	BBGVMIN,
+	RESERVED_0X7E,
+	RESERVED_0X85 = 0x85,
+	RESERVED_0X86,
+	CON1,
+	RESERVED_0X88,
+	RESERVED_0X89,
+	RFST0,
+	RFST1,
+	RFST2,
+	RFST3,
+	RFST4,
+	RFST5,
+	RFST6,
+	RFST7,
+	RFST8,
+	RFST9,
+	RESERVED_0X94,
+	RESERVED_0X95,
+	RESERVED_0X96,
+	RESERVED_0X97,
+	RESERVED_0X98,
+	RESERVED_0X99,
+	RESERVED_0X9A,
+	RESERVED_0X9B,
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/ix2505v.c b/drivers/media/dvb-frontends/ix2505v.c
new file mode 100644
index 0000000..bc5a820
--- /dev/null
+++ b/drivers/media/dvb-frontends/ix2505v.c
@@ -0,0 +1,325 @@
+/**
+ * Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner
+ *
+ * Copyright (C) 2010 Malcolm Priestley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "ix2505v.h"
+
+static int ix2505v_debug;
+#define dprintk(level, args...) do { \
+	if (ix2505v_debug & level) \
+		printk(KERN_DEBUG "ix2505v: " args); \
+} while (0)
+
+#define deb_info(args...)  dprintk(0x01, args)
+#define deb_i2c(args...)  dprintk(0x02, args)
+
+struct ix2505v_state {
+	struct i2c_adapter *i2c;
+	const struct ix2505v_config *config;
+	u32 frequency;
+};
+
+/**
+ *  Data read format of the Sharp IX2505V B0017
+ *
+ *  byte1:   1   |   1   |   0   |   0   |   0   |  MA1  |  MA0  |  1
+ *  byte2:  POR  |   FL  |  RD2  |  RD1  |  RD0  |   X   |   X   |  X
+ *
+ *  byte1 = address
+ *  byte2;
+ *	POR = Power on Reset (VCC H=<2.2v L=>2.2v)
+ *	FL  = Phase Lock (H=lock L=unlock)
+ *	RD0-2 = Reserved internal operations
+ *
+ * Only POR can be used to check the tuner is present
+ *
+ * Caution: after byte2 the I2C reverts to write mode continuing to read
+ *          may corrupt tuning data.
+ *
+ */
+
+static int ix2505v_read_status_reg(struct ix2505v_state *state)
+{
+	u8 addr = state->config->tuner_address;
+	u8 b2[] = {0};
+	int ret;
+
+	struct i2c_msg msg[1] = {
+		{ .addr = addr, .flags = I2C_M_RD, .buf = b2, .len = 1 }
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 1);
+	deb_i2c("Read %s ", __func__);
+
+	return (ret == 1) ? (int) b2[0] : -1;
+}
+
+static int ix2505v_write(struct ix2505v_state *state, u8 buf[], u8 count)
+{
+	struct i2c_msg msg[1] = {
+		{ .addr = state->config->tuner_address, .flags = 0,
+		  .buf = buf, .len = count },
+	};
+
+	int ret;
+
+	ret = i2c_transfer(state->i2c, msg, 1);
+
+	if (ret != 1) {
+		deb_i2c("%s: i2c error, ret=%d\n", __func__, ret);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int ix2505v_release(struct dvb_frontend *fe)
+{
+	struct ix2505v_state *state = fe->tuner_priv;
+
+	fe->tuner_priv = NULL;
+	kfree(state);
+
+	return 0;
+}
+
+/**
+ *  Data write format of the Sharp IX2505V B0017
+ *
+ *  byte1:   1   |   1   |   0   |   0   |   0   | 0(MA1)| 0(MA0)|  0
+ *  byte2:   0   |  BG1  |  BG2  |   N8  |   N7  |   N6  |  N5   |  N4
+ *  byte3:   N3  |   N2  |   N1  |   A5  |   A4  |   A3  |   A2  |  A1
+ *  byte4:   1   | 1(C1) | 1(C0) |  PD5  |  PD4  |   TM  | 0(RTS)| 1(REF)
+ *  byte5:   BA2 |   BA1 |  BA0  |  PSC  |  PD3  |PD2/TS2|DIV/TS1|PD0/TS0
+ *
+ *  byte1 = address
+ *
+ *  Write order
+ *  1) byte1 -> byte2 -> byte3 -> byte4 -> byte5
+ *  2) byte1 -> byte4 -> byte5 -> byte2 -> byte3
+ *  3) byte1 -> byte2 -> byte3 -> byte4
+ *  4) byte1 -> byte4 -> byte5 -> byte2
+ *  5) byte1 -> byte2 -> byte3
+ *  6) byte1 -> byte4 -> byte5
+ *  7) byte1 -> byte2
+ *  8) byte1 -> byte4
+ *
+ *  Recommended Setup
+ *  1 -> 8 -> 6
+ */
+
+static int ix2505v_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct ix2505v_state *state = fe->tuner_priv;
+	u32 frequency = c->frequency;
+	u32 b_w  = (c->symbol_rate * 27) / 32000;
+	u32 div_factor, N , A, x;
+	int ret = 0, len;
+	u8 gain, cc, ref, psc, local_osc, lpf;
+	u8 data[4] = {0};
+
+	if ((frequency < fe->ops.info.frequency_min)
+	||  (frequency > fe->ops.info.frequency_max))
+		return -EINVAL;
+
+	if (state->config->tuner_gain)
+		gain = (state->config->tuner_gain < 4)
+			? state->config->tuner_gain : 0;
+	else
+		gain = 0x0;
+
+	if (state->config->tuner_chargepump)
+		cc = state->config->tuner_chargepump;
+	else
+		cc = 0x3;
+
+	ref = 8; /* REF =1 */
+	psc = 32; /* PSC = 0 */
+
+	div_factor = (frequency * ref) / 40; /* local osc = 4Mhz */
+	x = div_factor / psc;
+	N = x/100;
+	A = ((x - (N * 100)) * psc) / 100;
+
+	data[0] = ((gain & 0x3) << 5) | (N >> 3);
+	data[1] = (N << 5) | (A & 0x1f);
+	data[2] = 0x81 | ((cc & 0x3) << 5) ; /*PD5,PD4 & TM = 0|C1,C0|REF=1*/
+
+	deb_info("Frq=%d x=%d N=%d A=%d\n", frequency, x, N, A);
+
+	if (frequency <= 1065000)
+		local_osc = (6 << 5) | 2;
+	else if (frequency <= 1170000)
+		local_osc = (7 << 5) | 2;
+	else if (frequency <= 1300000)
+		local_osc = (1 << 5);
+	else if (frequency <= 1445000)
+		local_osc = (2 << 5);
+	else if (frequency <= 1607000)
+		local_osc = (3 << 5);
+	else if (frequency <= 1778000)
+		local_osc = (4 << 5);
+	else if (frequency <= 1942000)
+		local_osc = (5 << 5);
+	else		/*frequency up to 2150000*/
+		local_osc = (6 << 5);
+
+	data[3] = local_osc; /* all other bits set 0 */
+
+	if (b_w <= 10000)
+		lpf = 0xc;
+	else if (b_w <= 12000)
+		lpf = 0x2;
+	else if (b_w <= 14000)
+		lpf = 0xa;
+	else if (b_w <= 16000)
+		lpf = 0x6;
+	else if (b_w <= 18000)
+		lpf = 0xe;
+	else if (b_w <= 20000)
+		lpf = 0x1;
+	else if (b_w <= 22000)
+		lpf = 0x9;
+	else if (b_w <= 24000)
+		lpf = 0x5;
+	else if (b_w <= 26000)
+		lpf = 0xd;
+	else if (b_w <= 28000)
+		lpf = 0x3;
+		else
+		lpf = 0xb;
+
+	deb_info("Osc=%x b_w=%x lpf=%x\n", local_osc, b_w, lpf);
+	deb_info("Data 0=[%x%x%x%x]\n", data[0], data[1], data[2], data[3]);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	len = sizeof(data);
+	ret |= ix2505v_write(state, data, len);
+
+	data[2] |= 0x4; /* set TM = 1 other bits same */
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	len = 1;
+	ret |= ix2505v_write(state, &data[2], len); /* write byte 4 only */
+
+	msleep(10);
+
+	data[2] |= ((lpf >> 2) & 0x3) << 3; /* lpf */
+	data[3] |= (lpf & 0x3) << 2;
+
+	deb_info("Data 2=[%x%x]\n", data[2], data[3]);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	len = 2;
+	ret |= ix2505v_write(state, &data[2], len); /* write byte 4 & 5 */
+
+	if (state->config->min_delay_ms)
+		msleep(state->config->min_delay_ms);
+
+	state->frequency = frequency;
+
+	return ret;
+}
+
+static int ix2505v_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct ix2505v_state *state = fe->tuner_priv;
+
+	*frequency = state->frequency;
+
+	return 0;
+}
+
+static struct dvb_tuner_ops ix2505v_tuner_ops = {
+	.info = {
+		.name = "Sharp IX2505V (B0017)",
+		.frequency_min = 950000,
+		.frequency_max = 2175000
+	},
+	.release = ix2505v_release,
+	.set_params = ix2505v_set_params,
+	.get_frequency = ix2505v_get_frequency,
+};
+
+struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
+				    const struct ix2505v_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct ix2505v_state *state = NULL;
+	int ret;
+
+	if (NULL == config) {
+		deb_i2c("%s: no config ", __func__);
+		goto error;
+	}
+
+	state = kzalloc(sizeof(struct ix2505v_state), GFP_KERNEL);
+	if (NULL == state)
+		return NULL;
+
+	state->config = config;
+	state->i2c = i2c;
+
+	if (state->config->tuner_write_only) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		ret = ix2505v_read_status_reg(state);
+
+		if (ret & 0x80) {
+			deb_i2c("%s: No IX2505V found\n", __func__);
+			goto error;
+		}
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	fe->tuner_priv = state;
+
+	memcpy(&fe->ops.tuner_ops, &ix2505v_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+	deb_i2c("%s: initialization (%s addr=0x%02x) ok\n",
+		__func__, fe->ops.tuner_ops.info.name, config->tuner_address);
+
+	return fe;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(ix2505v_attach);
+
+module_param_named(debug, ix2505v_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+MODULE_DESCRIPTION("DVB IX2505V tuner driver");
+MODULE_AUTHOR("Malcolm Priestley");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/ix2505v.h b/drivers/media/dvb-frontends/ix2505v.h
new file mode 100644
index 0000000..67e89d6
--- /dev/null
+++ b/drivers/media/dvb-frontends/ix2505v.h
@@ -0,0 +1,64 @@
+/**
+ * Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner
+ *
+ * Copyright (C) 2010 Malcolm Priestley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DVB_IX2505V_H
+#define DVB_IX2505V_H
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/**
+ * Attach a ix2505v tuner to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param config ix2505v_config structure
+ * @return FE pointer on success, NULL on failure.
+ */
+
+struct ix2505v_config {
+	u8 tuner_address;
+
+	/*Baseband AMP gain control 0/1=0dB(default) 2=-2bB 3=-4dB */
+	u8 tuner_gain;
+
+	/*Charge pump output +/- 0=120 1=260 2=555 3=1200(default) */
+	u8 tuner_chargepump;
+
+	/* delay after tune */
+	int min_delay_ms;
+
+	/* disables reads*/
+	u8 tuner_write_only;
+
+};
+
+#if defined(CONFIG_DVB_IX2505V) || \
+	(defined(CONFIG_DVB_IX2505V_MODULE) && defined(MODULE))
+extern struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
+	const struct ix2505v_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
+	const struct ix2505v_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* DVB_IX2505V_H */
diff --git a/drivers/media/dvb-frontends/l64781.c b/drivers/media/dvb-frontends/l64781.c
new file mode 100644
index 0000000..36fcf55
--- /dev/null
+++ b/drivers/media/dvb-frontends/l64781.c
@@ -0,0 +1,609 @@
+/*
+    driver for LSI L64781 COFDM demodulator
+
+    Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH
+		       Marko Kohtala <marko.kohtala@luukku.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "dvb_frontend.h"
+#include "l64781.h"
+
+
+struct l64781_state {
+	struct i2c_adapter* i2c;
+	const struct l64781_config* config;
+	struct dvb_frontend frontend;
+
+	/* private demodulator data */
+	unsigned int first:1;
+};
+
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "l64781: " args); \
+	} while (0)
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+
+static int l64781_writereg (struct l64781_state* state, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf [] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+
+	if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1)
+		dprintk ("%s: write_reg error (reg == %02x) = %02x!\n",
+			 __func__, reg, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+
+static int l64781_readreg (struct l64781_state* state, u8 reg)
+{
+	int ret;
+	u8 b0 [] = { reg };
+	u8 b1 [] = { 0 };
+	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) return ret;
+
+	return b1[0];
+}
+
+static void apply_tps (struct l64781_state* state)
+{
+	l64781_writereg (state, 0x2a, 0x00);
+	l64781_writereg (state, 0x2a, 0x01);
+
+	/* This here is a little bit questionable because it enables
+	   the automatic update of TPS registers. I think we'd need to
+	   handle the IRQ from FE to update some other registers as
+	   well, or at least implement some magic to tuning to correct
+	   to the TPS received from transmission. */
+	l64781_writereg (state, 0x2a, 0x02);
+}
+
+
+static void reset_afc (struct l64781_state* state)
+{
+	/* Set AFC stall for the AFC_INIT_FRQ setting, TIM_STALL for
+	   timing offset */
+	l64781_writereg (state, 0x07, 0x9e); /* stall AFC */
+	l64781_writereg (state, 0x08, 0);    /* AFC INIT FREQ */
+	l64781_writereg (state, 0x09, 0);
+	l64781_writereg (state, 0x0a, 0);
+	l64781_writereg (state, 0x07, 0x8e);
+	l64781_writereg (state, 0x0e, 0);    /* AGC gain to zero in beginning */
+	l64781_writereg (state, 0x11, 0x80); /* stall TIM */
+	l64781_writereg (state, 0x10, 0);    /* TIM_OFFSET_LSB */
+	l64781_writereg (state, 0x12, 0);
+	l64781_writereg (state, 0x13, 0);
+	l64781_writereg (state, 0x11, 0x00);
+}
+
+static int reset_and_configure (struct l64781_state* state)
+{
+	u8 buf [] = { 0x06 };
+	struct i2c_msg msg = { .addr = 0x00, .flags = 0, .buf = buf, .len = 1 };
+	// NOTE: this is correct in writing to address 0x00
+
+	return (i2c_transfer(state->i2c, &msg, 1) == 1) ? 0 : -ENODEV;
+}
+
+static int apply_frontend_param(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct l64781_state* state = fe->demodulator_priv;
+	/* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */
+	static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 };
+	/* QPSK, QAM_16, QAM_64 */
+	static const u8 qam_tab [] = { 2, 4, 0, 6 };
+	static const u8 guard_tab [] = { 1, 2, 4, 8 };
+	/* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */
+	static const u32 ppm = 8000;
+	u32 ddfs_offset_fixed;
+/*	u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */
+/*			bw_tab[p->bandWidth]<<10)/15625; */
+	u32 init_freq;
+	u32 spi_bias;
+	u8 val0x04;
+	u8 val0x05;
+	u8 val0x06;
+	int bw;
+
+	switch (p->bandwidth_hz) {
+	case 8000000:
+		bw = 8;
+		break;
+	case 7000000:
+		bw = 7;
+		break;
+	case 6000000:
+		bw = 6;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	if (p->inversion != INVERSION_ON &&
+	    p->inversion != INVERSION_OFF)
+		return -EINVAL;
+
+	if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 &&
+	    p->code_rate_HP != FEC_3_4 && p->code_rate_HP != FEC_5_6 &&
+	    p->code_rate_HP != FEC_7_8)
+		return -EINVAL;
+
+	if (p->hierarchy != HIERARCHY_NONE &&
+	    (p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 &&
+	     p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 &&
+	     p->code_rate_LP != FEC_7_8))
+		return -EINVAL;
+
+	if (p->modulation != QPSK && p->modulation != QAM_16 &&
+	    p->modulation != QAM_64)
+		return -EINVAL;
+
+	if (p->transmission_mode != TRANSMISSION_MODE_2K &&
+	    p->transmission_mode != TRANSMISSION_MODE_8K)
+		return -EINVAL;
+
+	if (p->guard_interval < GUARD_INTERVAL_1_32 ||
+	    p->guard_interval > GUARD_INTERVAL_1_4)
+		return -EINVAL;
+
+	if (p->hierarchy < HIERARCHY_NONE ||
+	    p->hierarchy > HIERARCHY_4)
+		return -EINVAL;
+
+	ddfs_offset_fixed = 0x4000-(ppm<<16)/bw/1000000;
+
+	/* This works up to 20000 ppm, it overflows if too large ppm! */
+	init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) /
+			bw & 0xFFFFFF);
+
+	/* SPI bias calculation is slightly modified to fit in 32bit */
+	/* will work for high ppm only... */
+	spi_bias = 378 * (1 << 10);
+	spi_bias *= 16;
+	spi_bias *= bw;
+	spi_bias *= qam_tab[p->modulation];
+	spi_bias /= p->code_rate_HP + 1;
+	spi_bias /= (guard_tab[p->guard_interval] + 32);
+	spi_bias *= 1000;
+	spi_bias /= 1000 + ppm/1000;
+	spi_bias *= p->code_rate_HP;
+
+	val0x04 = (p->transmission_mode << 2) | p->guard_interval;
+	val0x05 = fec_tab[p->code_rate_HP];
+
+	if (p->hierarchy != HIERARCHY_NONE)
+		val0x05 |= (p->code_rate_LP - FEC_1_2) << 3;
+
+	val0x06 = (p->hierarchy << 2) | p->modulation;
+
+	l64781_writereg (state, 0x04, val0x04);
+	l64781_writereg (state, 0x05, val0x05);
+	l64781_writereg (state, 0x06, val0x06);
+
+	reset_afc (state);
+
+	/* Technical manual section 2.6.1, TIM_IIR_GAIN optimal values */
+	l64781_writereg (state, 0x15,
+			 p->transmission_mode == TRANSMISSION_MODE_2K ? 1 : 3);
+	l64781_writereg (state, 0x16, init_freq & 0xff);
+	l64781_writereg (state, 0x17, (init_freq >> 8) & 0xff);
+	l64781_writereg (state, 0x18, (init_freq >> 16) & 0xff);
+
+	l64781_writereg (state, 0x1b, spi_bias & 0xff);
+	l64781_writereg (state, 0x1c, (spi_bias >> 8) & 0xff);
+	l64781_writereg (state, 0x1d, ((spi_bias >> 16) & 0x7f) |
+		(p->inversion == INVERSION_ON ? 0x80 : 0x00));
+
+	l64781_writereg (state, 0x22, ddfs_offset_fixed & 0xff);
+	l64781_writereg (state, 0x23, (ddfs_offset_fixed >> 8) & 0x3f);
+
+	l64781_readreg (state, 0x00);  /*  clear interrupt registers... */
+	l64781_readreg (state, 0x01);  /*  dto. */
+
+	apply_tps (state);
+
+	return 0;
+}
+
+static int get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct l64781_state* state = fe->demodulator_priv;
+	int tmp;
+
+
+	tmp = l64781_readreg(state, 0x04);
+	switch(tmp & 3) {
+	case 0:
+		p->guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		p->guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		p->guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		p->guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	}
+	switch((tmp >> 2) & 3) {
+	case 0:
+		p->transmission_mode = TRANSMISSION_MODE_2K;
+		break;
+	case 1:
+		p->transmission_mode = TRANSMISSION_MODE_8K;
+		break;
+	default:
+		printk(KERN_WARNING "Unexpected value for transmission_mode\n");
+	}
+
+	tmp = l64781_readreg(state, 0x05);
+	switch(tmp & 7) {
+	case 0:
+		p->code_rate_HP = FEC_1_2;
+		break;
+	case 1:
+		p->code_rate_HP = FEC_2_3;
+		break;
+	case 2:
+		p->code_rate_HP = FEC_3_4;
+		break;
+	case 3:
+		p->code_rate_HP = FEC_5_6;
+		break;
+	case 4:
+		p->code_rate_HP = FEC_7_8;
+		break;
+	default:
+		printk("Unexpected value for code_rate_HP\n");
+	}
+	switch((tmp >> 3) & 7) {
+	case 0:
+		p->code_rate_LP = FEC_1_2;
+		break;
+	case 1:
+		p->code_rate_LP = FEC_2_3;
+		break;
+	case 2:
+		p->code_rate_LP = FEC_3_4;
+		break;
+	case 3:
+		p->code_rate_LP = FEC_5_6;
+		break;
+	case 4:
+		p->code_rate_LP = FEC_7_8;
+		break;
+	default:
+		printk("Unexpected value for code_rate_LP\n");
+	}
+
+	tmp = l64781_readreg(state, 0x06);
+	switch(tmp & 3) {
+	case 0:
+		p->modulation = QPSK;
+		break;
+	case 1:
+		p->modulation = QAM_16;
+		break;
+	case 2:
+		p->modulation = QAM_64;
+		break;
+	default:
+		printk(KERN_WARNING "Unexpected value for modulation\n");
+	}
+	switch((tmp >> 2) & 7) {
+	case 0:
+		p->hierarchy = HIERARCHY_NONE;
+		break;
+	case 1:
+		p->hierarchy = HIERARCHY_1;
+		break;
+	case 2:
+		p->hierarchy = HIERARCHY_2;
+		break;
+	case 3:
+		p->hierarchy = HIERARCHY_4;
+		break;
+	default:
+		printk("Unexpected value for hierarchy\n");
+	}
+
+
+	tmp = l64781_readreg (state, 0x1d);
+	p->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF;
+
+	tmp = (int) (l64781_readreg (state, 0x08) |
+		     (l64781_readreg (state, 0x09) << 8) |
+		     (l64781_readreg (state, 0x0a) << 16));
+	p->frequency += tmp;
+
+	return 0;
+}
+
+static int l64781_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct l64781_state* state = fe->demodulator_priv;
+	int sync = l64781_readreg (state, 0x32);
+	int gain = l64781_readreg (state, 0x0e);
+
+	l64781_readreg (state, 0x00);  /*  clear interrupt registers... */
+	l64781_readreg (state, 0x01);  /*  dto. */
+
+	*status = 0;
+
+	if (gain > 5)
+		*status |= FE_HAS_SIGNAL;
+
+	if (sync & 0x02) /* VCXO locked, this criteria should be ok */
+		*status |= FE_HAS_CARRIER;
+
+	if (sync & 0x20)
+		*status |= FE_HAS_VITERBI;
+
+	if (sync & 0x40)
+		*status |= FE_HAS_SYNC;
+
+	if (sync == 0x7f)
+		*status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int l64781_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct l64781_state* state = fe->demodulator_priv;
+
+	/*   XXX FIXME: set up counting period (reg 0x26...0x28)
+	 */
+	*ber = l64781_readreg (state, 0x39)
+	    | (l64781_readreg (state, 0x3a) << 8);
+
+	return 0;
+}
+
+static int l64781_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+{
+	struct l64781_state* state = fe->demodulator_priv;
+
+	u8 gain = l64781_readreg (state, 0x0e);
+	*signal_strength = (gain << 8) | gain;
+
+	return 0;
+}
+
+static int l64781_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct l64781_state* state = fe->demodulator_priv;
+
+	u8 avg_quality = 0xff - l64781_readreg (state, 0x33);
+	*snr = (avg_quality << 8) | avg_quality; /* not exact, but...*/
+
+	return 0;
+}
+
+static int l64781_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct l64781_state* state = fe->demodulator_priv;
+
+	*ucblocks = l64781_readreg (state, 0x37)
+	   | (l64781_readreg (state, 0x38) << 8);
+
+	return 0;
+}
+
+static int l64781_sleep(struct dvb_frontend* fe)
+{
+	struct l64781_state* state = fe->demodulator_priv;
+
+	/* Power down */
+	return l64781_writereg (state, 0x3e, 0x5a);
+}
+
+static int l64781_init(struct dvb_frontend* fe)
+{
+	struct l64781_state* state = fe->demodulator_priv;
+
+	reset_and_configure (state);
+
+	/* Power up */
+	l64781_writereg (state, 0x3e, 0xa5);
+
+	/* Reset hard */
+	l64781_writereg (state, 0x2a, 0x04);
+	l64781_writereg (state, 0x2a, 0x00);
+
+	/* Set tuner specific things */
+	/* AFC_POL, set also in reset_afc */
+	l64781_writereg (state, 0x07, 0x8e);
+
+	/* Use internal ADC */
+	l64781_writereg (state, 0x0b, 0x81);
+
+	/* AGC loop gain, and polarity is positive */
+	l64781_writereg (state, 0x0c, 0x84);
+
+	/* Internal ADC outputs two's complement */
+	l64781_writereg (state, 0x0d, 0x8c);
+
+	/* With ppm=8000, it seems the DTR_SENSITIVITY will result in
+	   value of 2 with all possible bandwidths and guard
+	   intervals, which is the initial value anyway. */
+	/*l64781_writereg (state, 0x19, 0x92);*/
+
+	/* Everything is two's complement, soft bit and CSI_OUT too */
+	l64781_writereg (state, 0x1e, 0x09);
+
+	/* delay a bit after first init attempt */
+	if (state->first) {
+		state->first = 0;
+		msleep(200);
+	}
+
+	return 0;
+}
+
+static int l64781_get_tune_settings(struct dvb_frontend* fe,
+				    struct dvb_frontend_tune_settings* fesettings)
+{
+	fesettings->min_delay_ms = 4000;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+	return 0;
+}
+
+static void l64781_release(struct dvb_frontend* fe)
+{
+	struct l64781_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops l64781_ops;
+
+struct dvb_frontend* l64781_attach(const struct l64781_config* config,
+				   struct i2c_adapter* i2c)
+{
+	struct l64781_state* state = NULL;
+	int reg0x3e = -1;
+	u8 b0 [] = { 0x1a };
+	u8 b1 [] = { 0x00 };
+	struct i2c_msg msg [] = { { .addr = config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+			   { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct l64781_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->first = 1;
+
+	/**
+	 *  the L64781 won't show up before we send the reset_and_configure()
+	 *  broadcast. If nothing responds there is no L64781 on the bus...
+	 */
+	if (reset_and_configure(state) < 0) {
+		dprintk("No response to reset and configure broadcast...\n");
+		goto error;
+	}
+
+	/* The chip always responds to reads */
+	if (i2c_transfer(state->i2c, msg, 2) != 2) {
+		dprintk("No response to read on I2C bus\n");
+		goto error;
+	}
+
+	/* Save current register contents for bailout */
+	reg0x3e = l64781_readreg(state, 0x3e);
+
+	/* Reading the POWER_DOWN register always returns 0 */
+	if (reg0x3e != 0) {
+		dprintk("Device doesn't look like L64781\n");
+		goto error;
+	}
+
+	/* Turn the chip off */
+	l64781_writereg (state, 0x3e, 0x5a);
+
+	/* Responds to all reads with 0 */
+	if (l64781_readreg(state, 0x1a) != 0) {
+		dprintk("Read 1 returned unexpcted value\n");
+		goto error;
+	}
+
+	/* Turn the chip on */
+	l64781_writereg (state, 0x3e, 0xa5);
+
+	/* Responds with register default value */
+	if (l64781_readreg(state, 0x1a) != 0xa1) {
+		dprintk("Read 2 returned unexpcted value\n");
+		goto error;
+	}
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	if (reg0x3e >= 0)
+		l64781_writereg (state, 0x3e, reg0x3e);  /* restore reg 0x3e */
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops l64781_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "LSI L64781 DVB-T",
+	/*	.frequency_min = ???,*/
+	/*	.frequency_max = ???,*/
+		.frequency_stepsize = 166666,
+	/*      .frequency_tolerance = ???,*/
+	/*      .symbol_rate_tolerance = ???,*/
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+		      FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+		      FE_CAN_MUTE_TS
+	},
+
+	.release = l64781_release,
+
+	.init = l64781_init,
+	.sleep = l64781_sleep,
+
+	.set_frontend = apply_frontend_param,
+	.get_frontend = get_frontend,
+	.get_tune_settings = l64781_get_tune_settings,
+
+	.read_status = l64781_read_status,
+	.read_ber = l64781_read_ber,
+	.read_signal_strength = l64781_read_signal_strength,
+	.read_snr = l64781_read_snr,
+	.read_ucblocks = l64781_read_ucblocks,
+};
+
+MODULE_DESCRIPTION("LSI L64781 DVB-T Demodulator driver");
+MODULE_AUTHOR("Holger Waechtler, Marko Kohtala");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(l64781_attach);
diff --git a/drivers/media/dvb-frontends/l64781.h b/drivers/media/dvb-frontends/l64781.h
new file mode 100644
index 0000000..1305a9e
--- /dev/null
+++ b/drivers/media/dvb-frontends/l64781.h
@@ -0,0 +1,46 @@
+/*
+    driver for LSI L64781 COFDM demodulator
+
+    Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH
+		       Marko Kohtala <marko.kohtala@luukku.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef L64781_H
+#define L64781_H
+
+#include <linux/dvb/frontend.h>
+
+struct l64781_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+};
+
+#if defined(CONFIG_DVB_L64781) || (defined(CONFIG_DVB_L64781_MODULE) && defined(MODULE))
+extern struct dvb_frontend* l64781_attach(const struct l64781_config* config,
+					  struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* l64781_attach(const struct l64781_config* config,
+					  struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_L64781
+
+#endif // L64781_H
diff --git a/drivers/media/dvb-frontends/lg2160.c b/drivers/media/dvb-frontends/lg2160.c
new file mode 100644
index 0000000..cc11260
--- /dev/null
+++ b/drivers/media/dvb-frontends/lg2160.c
@@ -0,0 +1,1468 @@
+/*
+ *    Support for LG2160 - ATSC/MH
+ *
+ *    Copyright (C) 2010 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/jiffies.h>
+#include <linux/dvb/frontend.h>
+#include "lg2160.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))");
+
+#define DBG_INFO 1
+#define DBG_REG  2
+
+#define lg_printk(kern, fmt, arg...)					\
+	printk(kern "%s: " fmt, __func__, ##arg)
+
+#define lg_info(fmt, arg...)	printk(KERN_INFO "lg2160: " fmt, ##arg)
+#define lg_warn(fmt, arg...)	lg_printk(KERN_WARNING,       fmt, ##arg)
+#define lg_err(fmt, arg...)	lg_printk(KERN_ERR,           fmt, ##arg)
+#define lg_dbg(fmt, arg...) if (debug & DBG_INFO)			\
+				lg_printk(KERN_DEBUG,         fmt, ##arg)
+#define lg_reg(fmt, arg...) if (debug & DBG_REG)			\
+				lg_printk(KERN_DEBUG,         fmt, ##arg)
+
+#define lg_fail(ret)							\
+({									\
+	int __ret;							\
+	__ret = (ret < 0);						\
+	if (__ret)							\
+		lg_err("error %d on line %d\n",	ret, __LINE__);		\
+	__ret;								\
+})
+
+struct lg216x_state {
+	struct i2c_adapter *i2c_adap;
+	const struct lg2160_config *cfg;
+
+	struct dvb_frontend frontend;
+
+	u32 current_frequency;
+	u8 parade_id;
+	u8 fic_ver;
+	unsigned int last_reset;
+};
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_write_reg(struct lg216x_state *state, u16 reg, u8 val)
+{
+	int ret;
+	u8 buf[] = { reg >> 8, reg & 0xff, val };
+	struct i2c_msg msg = {
+		.addr = state->cfg->i2c_addr, .flags = 0,
+		.buf = buf, .len = 3,
+	};
+
+	lg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val);
+
+	ret = i2c_transfer(state->i2c_adap, &msg, 1);
+
+	if (ret != 1) {
+		lg_err("error (addr %02x %02x <- %02x, err = %i)\n",
+		       msg.buf[0], msg.buf[1], msg.buf[2], ret);
+		if (ret < 0)
+			return ret;
+		else
+			return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int lg216x_read_reg(struct lg216x_state *state, u16 reg, u8 *val)
+{
+	int ret;
+	u8 reg_buf[] = { reg >> 8, reg & 0xff };
+	struct i2c_msg msg[] = {
+		{ .addr = state->cfg->i2c_addr,
+		  .flags = 0, .buf = reg_buf, .len = 2 },
+		{ .addr = state->cfg->i2c_addr,
+		  .flags = I2C_M_RD, .buf = val, .len = 1 },
+	};
+
+	lg_reg("reg: 0x%04x\n", reg);
+
+	ret = i2c_transfer(state->i2c_adap, msg, 2);
+
+	if (ret != 2) {
+		lg_err("error (addr %02x reg %04x error (ret == %i)\n",
+		       state->cfg->i2c_addr, reg, ret);
+		if (ret < 0)
+			return ret;
+		else
+			return -EREMOTEIO;
+	}
+	return 0;
+}
+
+struct lg216x_reg {
+	u16 reg;
+	u8 val;
+};
+
+static int lg216x_write_regs(struct lg216x_state *state,
+			     struct lg216x_reg *regs, int len)
+{
+	int i, ret;
+
+	lg_reg("writing %d registers...\n", len);
+
+	for (i = 0; i < len; i++) {
+		ret = lg216x_write_reg(state, regs[i].reg, regs[i].val);
+		if (lg_fail(ret))
+			return ret;
+	}
+	return 0;
+}
+
+static int lg216x_set_reg_bit(struct lg216x_state *state,
+			      u16 reg, int bit, int onoff)
+{
+	u8 val;
+	int ret;
+
+	lg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff);
+
+	ret = lg216x_read_reg(state, reg, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= ~(1 << bit);
+	val |= (onoff & 1) << bit;
+
+	ret = lg216x_write_reg(state, reg, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct lg216x_state *state = fe->demodulator_priv;
+	int ret;
+
+	if (state->cfg->deny_i2c_rptr)
+		return 0;
+
+	lg_dbg("(%d)\n", enable);
+
+	ret = lg216x_set_reg_bit(state, 0x0000, 0, enable ? 0 : 1);
+
+	msleep(1);
+
+	return ret;
+}
+
+static int lg216x_soft_reset(struct lg216x_state *state)
+{
+	int ret;
+
+	lg_dbg("\n");
+
+	ret = lg216x_write_reg(state, 0x0002, 0x00);
+	if (lg_fail(ret))
+		goto fail;
+
+	msleep(20);
+	ret = lg216x_write_reg(state, 0x0002, 0x01);
+	if (lg_fail(ret))
+		goto fail;
+
+	state->last_reset = jiffies_to_msecs(jiffies);
+fail:
+	return ret;
+}
+
+static int lg216x_initialize(struct lg216x_state *state)
+{
+	int ret;
+
+	static struct lg216x_reg lg2160_init[] = {
+#if 0
+		{ .reg = 0x0015, .val = 0xe6 },
+#else
+		{ .reg = 0x0015, .val = 0xf7 },
+		{ .reg = 0x001b, .val = 0x52 },
+		{ .reg = 0x0208, .val = 0x00 },
+		{ .reg = 0x0209, .val = 0x82 },
+		{ .reg = 0x0210, .val = 0xf9 },
+		{ .reg = 0x020a, .val = 0x00 },
+		{ .reg = 0x020b, .val = 0x82 },
+		{ .reg = 0x020d, .val = 0x28 },
+		{ .reg = 0x020f, .val = 0x14 },
+#endif
+	};
+
+	static struct lg216x_reg lg2161_init[] = {
+		{ .reg = 0x0000, .val = 0x41 },
+		{ .reg = 0x0001, .val = 0xfb },
+		{ .reg = 0x0216, .val = 0x00 },
+		{ .reg = 0x0219, .val = 0x00 },
+		{ .reg = 0x021b, .val = 0x55 },
+		{ .reg = 0x0606, .val = 0x0a },
+	};
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg216x_write_regs(state,
+					lg2160_init, ARRAY_SIZE(lg2160_init));
+		break;
+	case LG2161:
+		ret = lg216x_write_regs(state,
+					lg2161_init, ARRAY_SIZE(lg2161_init));
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_soft_reset(state);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_set_if(struct lg216x_state *state)
+{
+	u8 val;
+	int ret;
+
+	lg_dbg("%d KHz\n", state->cfg->if_khz);
+
+	ret = lg216x_read_reg(state, 0x0132, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xfb;
+	val |= (0 == state->cfg->if_khz) ? 0x04 : 0x00;
+
+	ret = lg216x_write_reg(state, 0x0132, val);
+	lg_fail(ret);
+
+	/* if NOT zero IF, 6 MHz is the default */
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg2160_agc_fix(struct lg216x_state *state,
+			  int if_agc_fix, int rf_agc_fix)
+{
+	u8 val;
+	int ret;
+
+	ret = lg216x_read_reg(state, 0x0100, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xf3;
+	val |= (if_agc_fix) ? 0x08 : 0x00;
+	val |= (rf_agc_fix) ? 0x04 : 0x00;
+
+	ret = lg216x_write_reg(state, 0x0100, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+#if 0
+static int lg2160_agc_freeze(struct lg216x_state *state,
+			     int if_agc_freeze, int rf_agc_freeze)
+{
+	u8 val;
+	int ret;
+
+	ret = lg216x_read_reg(state, 0x0100, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xcf;
+	val |= (if_agc_freeze) ? 0x20 : 0x00;
+	val |= (rf_agc_freeze) ? 0x10 : 0x00;
+
+	ret = lg216x_write_reg(state, 0x0100, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+#endif
+
+static int lg2160_agc_polarity(struct lg216x_state *state,
+			       int if_agc_polarity, int rf_agc_polarity)
+{
+	u8 val;
+	int ret;
+
+	ret = lg216x_read_reg(state, 0x0100, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xfc;
+	val |= (if_agc_polarity) ? 0x02 : 0x00;
+	val |= (rf_agc_polarity) ? 0x01 : 0x00;
+
+	ret = lg216x_write_reg(state, 0x0100, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+static int lg2160_tuner_pwr_save_polarity(struct lg216x_state *state,
+					  int polarity)
+{
+	u8 val;
+	int ret;
+
+	ret = lg216x_read_reg(state, 0x0008, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xfe;
+	val |= (polarity) ? 0x01 : 0x00;
+
+	ret = lg216x_write_reg(state, 0x0008, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+static int lg2160_spectrum_polarity(struct lg216x_state *state,
+				    int inverted)
+{
+	u8 val;
+	int ret;
+
+	ret = lg216x_read_reg(state, 0x0132, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xfd;
+	val |= (inverted) ? 0x02 : 0x00;
+
+	ret = lg216x_write_reg(state, 0x0132, val);
+	lg_fail(ret);
+fail:
+	return lg216x_soft_reset(state);
+}
+
+static int lg2160_tuner_pwr_save(struct lg216x_state *state, int onoff)
+{
+	u8 val;
+	int ret;
+
+	ret = lg216x_read_reg(state, 0x0007, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xbf;
+	val |= (onoff) ? 0x40 : 0x00;
+
+	ret = lg216x_write_reg(state, 0x0007, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+static int lg216x_set_parade(struct lg216x_state *state, int id)
+{
+	int ret;
+
+	ret = lg216x_write_reg(state, 0x013e, id & 0x7f);
+	if (lg_fail(ret))
+		goto fail;
+
+	state->parade_id = id & 0x7f;
+fail:
+	return ret;
+}
+
+static int lg216x_set_ensemble(struct lg216x_state *state, int id)
+{
+	int ret;
+	u16 reg;
+	u8 val;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		reg = 0x0400;
+		break;
+	case LG2161:
+	default:
+		reg = 0x0500;
+		break;
+	}
+
+	ret = lg216x_read_reg(state, reg, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xfe;
+	val |= (id) ? 0x01 : 0x00;
+
+	ret = lg216x_write_reg(state, reg, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+static int lg2160_set_spi_clock(struct lg216x_state *state)
+{
+	u8 val;
+	int ret;
+
+	ret = lg216x_read_reg(state, 0x0014, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0xf3;
+	val |= (state->cfg->spi_clock << 2);
+
+	ret = lg216x_write_reg(state, 0x0014, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+static int lg2161_set_output_interface(struct lg216x_state *state)
+{
+	u8 val;
+	int ret;
+
+	ret = lg216x_read_reg(state, 0x0014, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= ~0x07;
+	val |= state->cfg->output_if; /* FIXME: needs sanity check */
+
+	ret = lg216x_write_reg(state, 0x0014, val);
+	lg_fail(ret);
+fail:
+	return ret;
+}
+
+static int lg216x_enable_fic(struct lg216x_state *state, int onoff)
+{
+	int ret;
+
+	ret = lg216x_write_reg(state, 0x0017, 0x23);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_write_reg(state, 0x0016, 0xfc);
+	if (lg_fail(ret))
+		goto fail;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg216x_write_reg(state, 0x0016,
+				       0xfc | ((onoff) ? 0x02 : 0x00));
+		break;
+	case LG2161:
+		ret = lg216x_write_reg(state, 0x0016, (onoff) ? 0x10 : 0x00);
+		break;
+	}
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_initialize(state);
+	if (lg_fail(ret))
+		goto fail;
+
+	if (onoff) {
+		ret = lg216x_write_reg(state, 0x0017, 0x03);
+		lg_fail(ret);
+	}
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_get_fic_version(struct lg216x_state *state, u8 *ficver)
+{
+	u8 val;
+	int ret;
+
+	*ficver = 0xff; /* invalid value */
+
+	ret = lg216x_read_reg(state, 0x0128, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*ficver = (val >> 3) & 0x1f;
+fail:
+	return ret;
+}
+
+#if 0
+static int lg2160_get_parade_id(struct lg216x_state *state, u8 *id)
+{
+	u8 val;
+	int ret;
+
+	*id = 0xff; /* invalid value */
+
+	ret = lg216x_read_reg(state, 0x0123, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*id = val & 0x7f;
+fail:
+	return ret;
+}
+#endif
+
+static int lg216x_get_nog(struct lg216x_state *state, u8 *nog)
+{
+	u8 val;
+	int ret;
+
+	*nog = 0xff; /* invalid value */
+
+	ret = lg216x_read_reg(state, 0x0124, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*nog = ((val >> 4) & 0x07) + 1;
+fail:
+	return ret;
+}
+
+static int lg216x_get_tnog(struct lg216x_state *state, u8 *tnog)
+{
+	u8 val;
+	int ret;
+
+	*tnog = 0xff; /* invalid value */
+
+	ret = lg216x_read_reg(state, 0x0125, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*tnog = val & 0x1f;
+fail:
+	return ret;
+}
+
+static int lg216x_get_sgn(struct lg216x_state *state, u8 *sgn)
+{
+	u8 val;
+	int ret;
+
+	*sgn = 0xff; /* invalid value */
+
+	ret = lg216x_read_reg(state, 0x0124, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*sgn = val & 0x0f;
+fail:
+	return ret;
+}
+
+static int lg216x_get_prc(struct lg216x_state *state, u8 *prc)
+{
+	u8 val;
+	int ret;
+
+	*prc = 0xff; /* invalid value */
+
+	ret = lg216x_read_reg(state, 0x0125, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*prc = ((val >> 5) & 0x07) + 1;
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_get_rs_frame_mode(struct lg216x_state *state,
+				    enum atscmh_rs_frame_mode *rs_framemode)
+{
+	u8 val;
+	int ret;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg216x_read_reg(state, 0x0410, &val);
+		break;
+	case LG2161:
+		ret = lg216x_read_reg(state, 0x0513, &val);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	if (lg_fail(ret))
+		goto fail;
+
+	switch ((val >> 4) & 0x03) {
+#if 1
+	default:
+#endif
+	case 0x00:
+		*rs_framemode = ATSCMH_RSFRAME_PRI_ONLY;
+		break;
+	case 0x01:
+		*rs_framemode = ATSCMH_RSFRAME_PRI_SEC;
+		break;
+#if 0
+	default:
+		*rs_framemode = ATSCMH_RSFRAME_RES;
+		break;
+#endif
+	}
+fail:
+	return ret;
+}
+
+static
+int lg216x_get_rs_frame_ensemble(struct lg216x_state *state,
+				 enum atscmh_rs_frame_ensemble *rs_frame_ens)
+{
+	u8 val;
+	int ret;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg216x_read_reg(state, 0x0400, &val);
+		break;
+	case LG2161:
+		ret = lg216x_read_reg(state, 0x0500, &val);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= 0x01;
+	*rs_frame_ens = (enum atscmh_rs_frame_ensemble) val;
+fail:
+	return ret;
+}
+
+static int lg216x_get_rs_code_mode(struct lg216x_state *state,
+				   enum atscmh_rs_code_mode *rs_code_pri,
+				   enum atscmh_rs_code_mode *rs_code_sec)
+{
+	u8 val;
+	int ret;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg216x_read_reg(state, 0x0410, &val);
+		break;
+	case LG2161:
+		ret = lg216x_read_reg(state, 0x0513, &val);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	if (lg_fail(ret))
+		goto fail;
+
+	*rs_code_pri = (enum atscmh_rs_code_mode) ((val >> 2) & 0x03);
+	*rs_code_sec = (enum atscmh_rs_code_mode) (val & 0x03);
+fail:
+	return ret;
+}
+
+static int lg216x_get_sccc_block_mode(struct lg216x_state *state,
+				      enum atscmh_sccc_block_mode *sccc_block)
+{
+	u8 val;
+	int ret;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg216x_read_reg(state, 0x0315, &val);
+		break;
+	case LG2161:
+		ret = lg216x_read_reg(state, 0x0511, &val);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	if (lg_fail(ret))
+		goto fail;
+
+	switch (val & 0x03) {
+	case 0x00:
+		*sccc_block = ATSCMH_SCCC_BLK_SEP;
+		break;
+	case 0x01:
+		*sccc_block = ATSCMH_SCCC_BLK_COMB;
+		break;
+	default:
+		*sccc_block = ATSCMH_SCCC_BLK_RES;
+		break;
+	}
+fail:
+	return ret;
+}
+
+static int lg216x_get_sccc_code_mode(struct lg216x_state *state,
+				     enum atscmh_sccc_code_mode *mode_a,
+				     enum atscmh_sccc_code_mode *mode_b,
+				     enum atscmh_sccc_code_mode *mode_c,
+				     enum atscmh_sccc_code_mode *mode_d)
+{
+	u8 val;
+	int ret;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg216x_read_reg(state, 0x0316, &val);
+		break;
+	case LG2161:
+		ret = lg216x_read_reg(state, 0x0512, &val);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	if (lg_fail(ret))
+		goto fail;
+
+	switch ((val >> 6) & 0x03) {
+	case 0x00:
+		*mode_a = ATSCMH_SCCC_CODE_HLF;
+		break;
+	case 0x01:
+		*mode_a = ATSCMH_SCCC_CODE_QTR;
+		break;
+	default:
+		*mode_a = ATSCMH_SCCC_CODE_RES;
+		break;
+	}
+
+	switch ((val >> 4) & 0x03) {
+	case 0x00:
+		*mode_b = ATSCMH_SCCC_CODE_HLF;
+		break;
+	case 0x01:
+		*mode_b = ATSCMH_SCCC_CODE_QTR;
+		break;
+	default:
+		*mode_b = ATSCMH_SCCC_CODE_RES;
+		break;
+	}
+
+	switch ((val >> 2) & 0x03) {
+	case 0x00:
+		*mode_c = ATSCMH_SCCC_CODE_HLF;
+		break;
+	case 0x01:
+		*mode_c = ATSCMH_SCCC_CODE_QTR;
+		break;
+	default:
+		*mode_c = ATSCMH_SCCC_CODE_RES;
+		break;
+	}
+
+	switch (val & 0x03) {
+	case 0x00:
+		*mode_d = ATSCMH_SCCC_CODE_HLF;
+		break;
+	case 0x01:
+		*mode_d = ATSCMH_SCCC_CODE_QTR;
+		break;
+	default:
+		*mode_d = ATSCMH_SCCC_CODE_RES;
+		break;
+	}
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+#if 0
+static int lg216x_read_fic_err_count(struct lg216x_state *state, u8 *err)
+{
+	u8 fic_err;
+	int ret;
+
+	*err = 0;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg216x_read_reg(state, 0x0012, &fic_err);
+		break;
+	case LG2161:
+		ret = lg216x_read_reg(state, 0x001e, &fic_err);
+		break;
+	}
+	if (lg_fail(ret))
+		goto fail;
+
+	*err = fic_err;
+fail:
+	return ret;
+}
+
+static int lg2160_read_crc_err_count(struct lg216x_state *state, u16 *err)
+{
+	u8 crc_err1, crc_err2;
+	int ret;
+
+	*err = 0;
+
+	ret = lg216x_read_reg(state, 0x0411, &crc_err1);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_read_reg(state, 0x0412, &crc_err2);
+	if (lg_fail(ret))
+		goto fail;
+
+	*err = (u16)(((crc_err2 & 0x0f) << 8) | crc_err1);
+fail:
+	return ret;
+}
+
+static int lg2161_read_crc_err_count(struct lg216x_state *state, u16 *err)
+{
+	u8 crc_err;
+	int ret;
+
+	*err = 0;
+
+	ret = lg216x_read_reg(state, 0x0612, &crc_err);
+	if (lg_fail(ret))
+		goto fail;
+
+	*err = (u16)crc_err;
+fail:
+	return ret;
+}
+
+static int lg216x_read_crc_err_count(struct lg216x_state *state, u16 *err)
+{
+	int ret;
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg2160_read_crc_err_count(state, err);
+		break;
+	case LG2161:
+		ret = lg2161_read_crc_err_count(state, err);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int lg2160_read_rs_err_count(struct lg216x_state *state, u16 *err)
+{
+	u8 rs_err1, rs_err2;
+	int ret;
+
+	*err = 0;
+
+	ret = lg216x_read_reg(state, 0x0413, &rs_err1);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_read_reg(state, 0x0414, &rs_err2);
+	if (lg_fail(ret))
+		goto fail;
+
+	*err = (u16)(((rs_err2 & 0x0f) << 8) | rs_err1);
+fail:
+	return ret;
+}
+
+static int lg2161_read_rs_err_count(struct lg216x_state *state, u16 *err)
+{
+	u8 rs_err1, rs_err2;
+	int ret;
+
+	*err = 0;
+
+	ret = lg216x_read_reg(state, 0x0613, &rs_err1);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_read_reg(state, 0x0614, &rs_err2);
+	if (lg_fail(ret))
+		goto fail;
+
+	*err = (u16)((rs_err1 << 8) | rs_err2);
+fail:
+	return ret;
+}
+
+static int lg216x_read_rs_err_count(struct lg216x_state *state, u16 *err)
+{
+	int ret;
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg2160_read_rs_err_count(state, err);
+		break;
+	case LG2161:
+		ret = lg2161_read_rs_err_count(state, err);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_get_frontend(struct dvb_frontend *fe)
+{
+	struct lg216x_state *state = fe->demodulator_priv;
+	int ret;
+
+	lg_dbg("\n");
+
+	fe->dtv_property_cache.modulation = VSB_8;
+	fe->dtv_property_cache.frequency = state->current_frequency;
+	fe->dtv_property_cache.delivery_system = SYS_ATSCMH;
+
+	ret = lg216x_get_fic_version(state,
+				     &fe->dtv_property_cache.atscmh_fic_ver);
+	if (lg_fail(ret))
+		goto fail;
+	if (state->fic_ver != fe->dtv_property_cache.atscmh_fic_ver) {
+		state->fic_ver = fe->dtv_property_cache.atscmh_fic_ver;
+
+#if 0
+		ret = lg2160_get_parade_id(state,
+				&fe->dtv_property_cache.atscmh_parade_id);
+		if (lg_fail(ret))
+			goto fail;
+/* #else */
+		fe->dtv_property_cache.atscmh_parade_id = state->parade_id;
+#endif
+		ret = lg216x_get_nog(state,
+				     &fe->dtv_property_cache.atscmh_nog);
+		if (lg_fail(ret))
+			goto fail;
+		ret = lg216x_get_tnog(state,
+				      &fe->dtv_property_cache.atscmh_tnog);
+		if (lg_fail(ret))
+			goto fail;
+		ret = lg216x_get_sgn(state,
+				     &fe->dtv_property_cache.atscmh_sgn);
+		if (lg_fail(ret))
+			goto fail;
+		ret = lg216x_get_prc(state,
+				     &fe->dtv_property_cache.atscmh_prc);
+		if (lg_fail(ret))
+			goto fail;
+
+		ret = lg216x_get_rs_frame_mode(state,
+			(enum atscmh_rs_frame_mode *)
+			&fe->dtv_property_cache.atscmh_rs_frame_mode);
+		if (lg_fail(ret))
+			goto fail;
+		ret = lg216x_get_rs_frame_ensemble(state,
+			(enum atscmh_rs_frame_ensemble *)
+			&fe->dtv_property_cache.atscmh_rs_frame_ensemble);
+		if (lg_fail(ret))
+			goto fail;
+		ret = lg216x_get_rs_code_mode(state,
+			(enum atscmh_rs_code_mode *)
+			&fe->dtv_property_cache.atscmh_rs_code_mode_pri,
+			(enum atscmh_rs_code_mode *)
+			&fe->dtv_property_cache.atscmh_rs_code_mode_sec);
+		if (lg_fail(ret))
+			goto fail;
+		ret = lg216x_get_sccc_block_mode(state,
+			(enum atscmh_sccc_block_mode *)
+			&fe->dtv_property_cache.atscmh_sccc_block_mode);
+		if (lg_fail(ret))
+			goto fail;
+		ret = lg216x_get_sccc_code_mode(state,
+			(enum atscmh_sccc_code_mode *)
+			&fe->dtv_property_cache.atscmh_sccc_code_mode_a,
+			(enum atscmh_sccc_code_mode *)
+			&fe->dtv_property_cache.atscmh_sccc_code_mode_b,
+			(enum atscmh_sccc_code_mode *)
+			&fe->dtv_property_cache.atscmh_sccc_code_mode_c,
+			(enum atscmh_sccc_code_mode *)
+			&fe->dtv_property_cache.atscmh_sccc_code_mode_d);
+		if (lg_fail(ret))
+			goto fail;
+	}
+#if 0
+	ret = lg216x_read_fic_err_count(state,
+				(u8 *)&fe->dtv_property_cache.atscmh_fic_err);
+	if (lg_fail(ret))
+		goto fail;
+	ret = lg216x_read_crc_err_count(state,
+				&fe->dtv_property_cache.atscmh_crc_err);
+	if (lg_fail(ret))
+		goto fail;
+	ret = lg216x_read_rs_err_count(state,
+				&fe->dtv_property_cache.atscmh_rs_err);
+	if (lg_fail(ret))
+		goto fail;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		if (((fe->dtv_property_cache.atscmh_rs_err >= 240) &&
+		     (fe->dtv_property_cache.atscmh_crc_err >= 240)) &&
+		    ((jiffies_to_msecs(jiffies) - state->last_reset) > 6000))
+			ret = lg216x_soft_reset(state);
+		break;
+	case LG2161:
+		/* no fix needed here (as far as we know) */
+		ret = 0;
+		break;
+	}
+	lg_fail(ret);
+#endif
+fail:
+	return ret;
+}
+
+static int lg216x_get_property(struct dvb_frontend *fe,
+			       struct dtv_property *tvp)
+{
+	return (DTV_ATSCMH_FIC_VER == tvp->cmd) ?
+		lg216x_get_frontend(fe) : 0;
+}
+
+
+static int lg2160_set_frontend(struct dvb_frontend *fe)
+{
+	struct lg216x_state *state = fe->demodulator_priv;
+	int ret;
+
+	lg_dbg("(%d)\n", fe->dtv_property_cache.frequency);
+
+	if (fe->ops.tuner_ops.set_params) {
+		ret = fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+		if (lg_fail(ret))
+			goto fail;
+		state->current_frequency = fe->dtv_property_cache.frequency;
+	}
+
+	ret = lg2160_agc_fix(state, 0, 0);
+	if (lg_fail(ret))
+		goto fail;
+	ret = lg2160_agc_polarity(state, 0, 0);
+	if (lg_fail(ret))
+		goto fail;
+	ret = lg2160_tuner_pwr_save_polarity(state, 1);
+	if (lg_fail(ret))
+		goto fail;
+	ret = lg216x_set_if(state);
+	if (lg_fail(ret))
+		goto fail;
+	ret = lg2160_spectrum_polarity(state, state->cfg->spectral_inversion);
+	if (lg_fail(ret))
+		goto fail;
+
+	/* be tuned before this point */
+	ret = lg216x_soft_reset(state);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg2160_tuner_pwr_save(state, 0);
+	if (lg_fail(ret))
+		goto fail;
+
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg2160_set_spi_clock(state);
+		if (lg_fail(ret))
+			goto fail;
+		break;
+	case LG2161:
+		ret = lg2161_set_output_interface(state);
+		if (lg_fail(ret))
+			goto fail;
+		break;
+	}
+
+	ret = lg216x_set_parade(state, fe->dtv_property_cache.atscmh_parade_id);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_set_ensemble(state,
+			fe->dtv_property_cache.atscmh_rs_frame_ensemble);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_initialize(state);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_enable_fic(state, 1);
+	lg_fail(ret);
+
+	lg216x_get_frontend(fe);
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg2160_read_lock_status(struct lg216x_state *state,
+				   int *acq_lock, int *sync_lock)
+{
+	u8 val;
+	int ret;
+
+	*acq_lock = 0;
+	*sync_lock = 0;
+
+	ret = lg216x_read_reg(state, 0x011b, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*sync_lock = (val & 0x20) ? 0 : 1;
+	*acq_lock  = (val & 0x40) ? 0 : 1;
+fail:
+	return ret;
+}
+
+#ifdef USE_LG2161_LOCK_BITS
+static int lg2161_read_lock_status(struct lg216x_state *state,
+				   int *acq_lock, int *sync_lock)
+{
+	u8 val;
+	int ret;
+
+	*acq_lock = 0;
+	*sync_lock = 0;
+
+	ret = lg216x_read_reg(state, 0x0304, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*sync_lock = (val & 0x80) ? 0 : 1;
+
+	ret = lg216x_read_reg(state, 0x011b, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	*acq_lock  = (val & 0x40) ? 0 : 1;
+fail:
+	return ret;
+}
+#endif
+
+static int lg216x_read_lock_status(struct lg216x_state *state,
+				   int *acq_lock, int *sync_lock)
+{
+#ifdef USE_LG2161_LOCK_BITS
+	int ret;
+	switch (state->cfg->lg_chip) {
+	case LG2160:
+		ret = lg2160_read_lock_status(state, acq_lock, sync_lock);
+		break;
+	case LG2161:
+		ret = lg2161_read_lock_status(state, acq_lock, sync_lock);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+#else
+	return lg2160_read_lock_status(state, acq_lock, sync_lock);
+#endif
+}
+
+static int lg216x_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct lg216x_state *state = fe->demodulator_priv;
+	int ret, acq_lock, sync_lock;
+
+	*status = 0;
+
+	ret = lg216x_read_lock_status(state, &acq_lock, &sync_lock);
+	if (lg_fail(ret))
+		goto fail;
+
+	lg_dbg("%s%s\n",
+	       acq_lock  ? "SIGNALEXIST " : "",
+	       sync_lock ? "SYNCLOCK"     : "");
+
+	if (acq_lock)
+		*status |= FE_HAS_SIGNAL;
+	if (sync_lock)
+		*status |= FE_HAS_SYNC;
+
+	if (*status)
+		*status |= FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK;
+
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg2160_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct lg216x_state *state = fe->demodulator_priv;
+	u8 snr1, snr2;
+	int ret;
+
+	*snr = 0;
+
+	ret = lg216x_read_reg(state, 0x0202, &snr1);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_read_reg(state, 0x0203, &snr2);
+	if (lg_fail(ret))
+		goto fail;
+
+	if ((snr1 == 0xba) || (snr2 == 0xdf))
+		*snr = 0;
+	else
+#if 1
+	*snr =  ((snr1 >> 4) * 100) + ((snr1 & 0x0f) * 10) + (snr2 >> 4);
+#else /* BCD */
+	*snr =  (snr2 | (snr1 << 8));
+#endif
+fail:
+	return ret;
+}
+
+static int lg2161_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct lg216x_state *state = fe->demodulator_priv;
+	u8 snr1, snr2;
+	int ret;
+
+	*snr = 0;
+
+	ret = lg216x_read_reg(state, 0x0302, &snr1);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lg216x_read_reg(state, 0x0303, &snr2);
+	if (lg_fail(ret))
+		goto fail;
+
+	if ((snr1 == 0xba) || (snr2 == 0xfd))
+		*snr = 0;
+	else
+
+	*snr =  ((snr1 >> 4) * 100) + ((snr1 & 0x0f) * 10) + (snr2 & 0x0f);
+fail:
+	return ret;
+}
+
+static int lg216x_read_signal_strength(struct dvb_frontend *fe,
+				       u16 *strength)
+{
+#if 0
+	/* borrowed from lgdt330x.c
+	 *
+	 * Calculate strength from SNR up to 35dB
+	 * Even though the SNR can go higher than 35dB,
+	 * there is some comfort factor in having a range of
+	 * strong signals that can show at 100%
+	 */
+	struct lg216x_state *state = fe->demodulator_priv;
+	u16 snr;
+	int ret;
+#endif
+	*strength = 0;
+#if 0
+	ret = fe->ops.read_snr(fe, &snr);
+	if (lg_fail(ret))
+		goto fail;
+	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
+	/* scale the range 0 - 35*2^24 into 0 - 65535 */
+	if (state->snr >= 8960 * 0x10000)
+		*strength = 0xffff;
+	else
+		*strength = state->snr / 8960;
+fail:
+	return ret;
+#else
+	return 0;
+#endif
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+#if 0
+	struct lg216x_state *state = fe->demodulator_priv;
+	int ret;
+
+	ret = lg216x_read_rs_err_count(state,
+				       &fe->dtv_property_cache.atscmh_rs_err);
+	if (lg_fail(ret))
+		goto fail;
+
+	*ucblocks = fe->dtv_property_cache.atscmh_rs_err;
+fail:
+#else
+	*ucblocks = 0;
+#endif
+	return 0;
+}
+
+static int lg216x_get_tune_settings(struct dvb_frontend *fe,
+				    struct dvb_frontend_tune_settings
+				    *fe_tune_settings)
+{
+	fe_tune_settings->min_delay_ms = 500;
+	lg_dbg("\n");
+	return 0;
+}
+
+static void lg216x_release(struct dvb_frontend *fe)
+{
+	struct lg216x_state *state = fe->demodulator_priv;
+	lg_dbg("\n");
+	kfree(state);
+}
+
+static struct dvb_frontend_ops lg2160_ops = {
+	.delsys = { SYS_ATSCMH },
+	.info = {
+		.name = "LG Electronics LG2160 ATSC/MH Frontend",
+		.frequency_min      = 54000000,
+		.frequency_max      = 858000000,
+		.frequency_stepsize = 62500,
+	},
+	.i2c_gate_ctrl        = lg216x_i2c_gate_ctrl,
+#if 0
+	.init                 = lg216x_init,
+	.sleep                = lg216x_sleep,
+#endif
+	.get_property         = lg216x_get_property,
+
+	.set_frontend         = lg2160_set_frontend,
+	.get_frontend         = lg216x_get_frontend,
+	.get_tune_settings    = lg216x_get_tune_settings,
+	.read_status          = lg216x_read_status,
+#if 0
+	.read_ber             = lg216x_read_ber,
+#endif
+	.read_signal_strength = lg216x_read_signal_strength,
+	.read_snr             = lg2160_read_snr,
+	.read_ucblocks        = lg216x_read_ucblocks,
+	.release              = lg216x_release,
+};
+
+static struct dvb_frontend_ops lg2161_ops = {
+	.delsys = { SYS_ATSCMH },
+	.info = {
+		.name = "LG Electronics LG2161 ATSC/MH Frontend",
+		.frequency_min      = 54000000,
+		.frequency_max      = 858000000,
+		.frequency_stepsize = 62500,
+	},
+	.i2c_gate_ctrl        = lg216x_i2c_gate_ctrl,
+#if 0
+	.init                 = lg216x_init,
+	.sleep                = lg216x_sleep,
+#endif
+	.get_property         = lg216x_get_property,
+
+	.set_frontend         = lg2160_set_frontend,
+	.get_frontend         = lg216x_get_frontend,
+	.get_tune_settings    = lg216x_get_tune_settings,
+	.read_status          = lg216x_read_status,
+#if 0
+	.read_ber             = lg216x_read_ber,
+#endif
+	.read_signal_strength = lg216x_read_signal_strength,
+	.read_snr             = lg2161_read_snr,
+	.read_ucblocks        = lg216x_read_ucblocks,
+	.release              = lg216x_release,
+};
+
+struct dvb_frontend *lg2160_attach(const struct lg2160_config *config,
+				   struct i2c_adapter *i2c_adap)
+{
+	struct lg216x_state *state = NULL;
+
+	lg_dbg("(%d-%04x)\n",
+	       i2c_adap ? i2c_adapter_id(i2c_adap) : 0,
+	       config ? config->i2c_addr : 0);
+
+	state = kzalloc(sizeof(struct lg216x_state), GFP_KERNEL);
+	if (state == NULL)
+		goto fail;
+
+	state->cfg = config;
+	state->i2c_adap = i2c_adap;
+	state->fic_ver = 0xff;
+	state->parade_id = 0xff;
+
+	switch (config->lg_chip) {
+	default:
+		lg_warn("invalid chip requested, defaulting to LG2160");
+		/* fall-thru */
+	case LG2160:
+		memcpy(&state->frontend.ops, &lg2160_ops,
+		       sizeof(struct dvb_frontend_ops));
+		break;
+	case LG2161:
+		memcpy(&state->frontend.ops, &lg2161_ops,
+		       sizeof(struct dvb_frontend_ops));
+		break;
+	}
+
+	state->frontend.demodulator_priv = state;
+	state->current_frequency = -1;
+	/* parade 1 by default */
+	state->frontend.dtv_property_cache.atscmh_parade_id = 1;
+
+	return &state->frontend;
+fail:
+	lg_warn("unable to detect LG216x hardware\n");
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(lg2160_attach);
+
+MODULE_DESCRIPTION("LG Electronics LG216x ATSC/MH Demodulator Driver");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.3");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb-frontends/lg2160.h b/drivers/media/dvb-frontends/lg2160.h
new file mode 100644
index 0000000..9e2c0f4
--- /dev/null
+++ b/drivers/media/dvb-frontends/lg2160.h
@@ -0,0 +1,84 @@
+/*
+ *    Support for LG2160 - ATSC/MH
+ *
+ *    Copyright (C) 2010 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _LG2160_H_
+#define _LG2160_H_
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+enum lg_chip_type {
+	LG2160 = 0,
+	LG2161 = 1,
+};
+
+#define LG2161_1019 LG2161
+#define LG2161_1040 LG2161
+
+enum lg2160_spi_clock {
+	LG2160_SPI_3_125_MHZ = 0,
+	LG2160_SPI_6_25_MHZ = 1,
+	LG2160_SPI_12_5_MHZ = 2,
+};
+
+#if 0
+enum lg2161_oif {
+	LG2161_OIF_EBI2_SLA  = 1,
+	LG2161_OIF_SDIO_SLA  = 2,
+	LG2161_OIF_SPI_SLA   = 3,
+	LG2161_OIF_SPI_MAS   = 4,
+	LG2161_OIF_SERIAL_TS = 7,
+};
+#endif
+
+struct lg2160_config {
+	u8 i2c_addr;
+
+	/* user defined IF frequency in KHz */
+	u16 if_khz;
+
+	/* disable i2c repeater - 0:repeater enabled 1:repeater disabled */
+	int deny_i2c_rptr:1;
+
+	/* spectral inversion - 0:disabled 1:enabled */
+	int spectral_inversion:1;
+
+	unsigned int output_if;
+	enum lg2160_spi_clock spi_clock;
+	enum lg_chip_type lg_chip;
+};
+
+#if defined(CONFIG_DVB_LG2160) || (defined(CONFIG_DVB_LG2160_MODULE) && \
+				     defined(MODULE))
+extern
+struct dvb_frontend *lg2160_attach(const struct lg2160_config *config,
+				     struct i2c_adapter *i2c_adap);
+#else
+static inline
+struct dvb_frontend *lg2160_attach(const struct lg2160_config *config,
+				     struct i2c_adapter *i2c_adap)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_LG2160 */
+
+#endif /* _LG2160_H_ */
diff --git a/drivers/media/dvb-frontends/lgdt3305.c b/drivers/media/dvb-frontends/lgdt3305.c
new file mode 100644
index 0000000..1d2c473
--- /dev/null
+++ b/drivers/media/dvb-frontends/lgdt3305.c
@@ -0,0 +1,1222 @@
+/*
+ *    Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM
+ *
+ *    Copyright (C) 2008, 2009, 2010 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *    LGDT3304 support by Jarod Wilson <jarod@redhat.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <asm/div64.h>
+#include <linux/dvb/frontend.h>
+#include <linux/slab.h>
+#include "dvb_math.h"
+#include "lgdt3305.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))");
+
+#define DBG_INFO 1
+#define DBG_REG  2
+
+#define lg_printk(kern, fmt, arg...)					\
+	printk(kern "%s: " fmt, __func__, ##arg)
+
+#define lg_info(fmt, arg...)	printk(KERN_INFO "lgdt3305: " fmt, ##arg)
+#define lg_warn(fmt, arg...)	lg_printk(KERN_WARNING,       fmt, ##arg)
+#define lg_err(fmt, arg...)	lg_printk(KERN_ERR,           fmt, ##arg)
+#define lg_dbg(fmt, arg...) if (debug & DBG_INFO)			\
+				lg_printk(KERN_DEBUG,         fmt, ##arg)
+#define lg_reg(fmt, arg...) if (debug & DBG_REG)			\
+				lg_printk(KERN_DEBUG,         fmt, ##arg)
+
+#define lg_fail(ret)							\
+({									\
+	int __ret;							\
+	__ret = (ret < 0);						\
+	if (__ret)							\
+		lg_err("error %d on line %d\n",	ret, __LINE__);		\
+	__ret;								\
+})
+
+struct lgdt3305_state {
+	struct i2c_adapter *i2c_adap;
+	const struct lgdt3305_config *cfg;
+
+	struct dvb_frontend frontend;
+
+	fe_modulation_t current_modulation;
+	u32 current_frequency;
+	u32 snr;
+};
+
+/* ------------------------------------------------------------------------ */
+
+/* FIXME: verify & document the LGDT3304 registers */
+
+#define LGDT3305_GEN_CTRL_1                   0x0000
+#define LGDT3305_GEN_CTRL_2                   0x0001
+#define LGDT3305_GEN_CTRL_3                   0x0002
+#define LGDT3305_GEN_STATUS                   0x0003
+#define LGDT3305_GEN_CONTROL                  0x0007
+#define LGDT3305_GEN_CTRL_4                   0x000a
+#define LGDT3305_DGTL_AGC_REF_1               0x0012
+#define LGDT3305_DGTL_AGC_REF_2               0x0013
+#define LGDT3305_CR_CTR_FREQ_1                0x0106
+#define LGDT3305_CR_CTR_FREQ_2                0x0107
+#define LGDT3305_CR_CTR_FREQ_3                0x0108
+#define LGDT3305_CR_CTR_FREQ_4                0x0109
+#define LGDT3305_CR_MSE_1                     0x011b
+#define LGDT3305_CR_MSE_2                     0x011c
+#define LGDT3305_CR_LOCK_STATUS               0x011d
+#define LGDT3305_CR_CTRL_7                    0x0126
+#define LGDT3305_AGC_POWER_REF_1              0x0300
+#define LGDT3305_AGC_POWER_REF_2              0x0301
+#define LGDT3305_AGC_DELAY_PT_1               0x0302
+#define LGDT3305_AGC_DELAY_PT_2               0x0303
+#define LGDT3305_RFAGC_LOOP_FLTR_BW_1         0x0306
+#define LGDT3305_RFAGC_LOOP_FLTR_BW_2         0x0307
+#define LGDT3305_IFBW_1                       0x0308
+#define LGDT3305_IFBW_2                       0x0309
+#define LGDT3305_AGC_CTRL_1                   0x030c
+#define LGDT3305_AGC_CTRL_4                   0x0314
+#define LGDT3305_EQ_MSE_1                     0x0413
+#define LGDT3305_EQ_MSE_2                     0x0414
+#define LGDT3305_EQ_MSE_3                     0x0415
+#define LGDT3305_PT_MSE_1                     0x0417
+#define LGDT3305_PT_MSE_2                     0x0418
+#define LGDT3305_PT_MSE_3                     0x0419
+#define LGDT3305_FEC_BLOCK_CTRL               0x0504
+#define LGDT3305_FEC_LOCK_STATUS              0x050a
+#define LGDT3305_FEC_PKT_ERR_1                0x050c
+#define LGDT3305_FEC_PKT_ERR_2                0x050d
+#define LGDT3305_TP_CTRL_1                    0x050e
+#define LGDT3305_BERT_PERIOD                  0x0801
+#define LGDT3305_BERT_ERROR_COUNT_1           0x080a
+#define LGDT3305_BERT_ERROR_COUNT_2           0x080b
+#define LGDT3305_BERT_ERROR_COUNT_3           0x080c
+#define LGDT3305_BERT_ERROR_COUNT_4           0x080d
+
+static int lgdt3305_write_reg(struct lgdt3305_state *state, u16 reg, u8 val)
+{
+	int ret;
+	u8 buf[] = { reg >> 8, reg & 0xff, val };
+	struct i2c_msg msg = {
+		.addr = state->cfg->i2c_addr, .flags = 0,
+		.buf = buf, .len = 3,
+	};
+
+	lg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val);
+
+	ret = i2c_transfer(state->i2c_adap, &msg, 1);
+
+	if (ret != 1) {
+		lg_err("error (addr %02x %02x <- %02x, err = %i)\n",
+		       msg.buf[0], msg.buf[1], msg.buf[2], ret);
+		if (ret < 0)
+			return ret;
+		else
+			return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int lgdt3305_read_reg(struct lgdt3305_state *state, u16 reg, u8 *val)
+{
+	int ret;
+	u8 reg_buf[] = { reg >> 8, reg & 0xff };
+	struct i2c_msg msg[] = {
+		{ .addr = state->cfg->i2c_addr,
+		  .flags = 0, .buf = reg_buf, .len = 2 },
+		{ .addr = state->cfg->i2c_addr,
+		  .flags = I2C_M_RD, .buf = val, .len = 1 },
+	};
+
+	lg_reg("reg: 0x%04x\n", reg);
+
+	ret = i2c_transfer(state->i2c_adap, msg, 2);
+
+	if (ret != 2) {
+		lg_err("error (addr %02x reg %04x error (ret == %i)\n",
+		       state->cfg->i2c_addr, reg, ret);
+		if (ret < 0)
+			return ret;
+		else
+			return -EREMOTEIO;
+	}
+	return 0;
+}
+
+#define read_reg(state, reg)						\
+({									\
+	u8 __val;							\
+	int ret = lgdt3305_read_reg(state, reg, &__val);		\
+	if (lg_fail(ret))						\
+		__val = 0;						\
+	__val;								\
+})
+
+static int lgdt3305_set_reg_bit(struct lgdt3305_state *state,
+				u16 reg, int bit, int onoff)
+{
+	u8 val;
+	int ret;
+
+	lg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff);
+
+	ret = lgdt3305_read_reg(state, reg, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= ~(1 << bit);
+	val |= (onoff & 1) << bit;
+
+	ret = lgdt3305_write_reg(state, reg, val);
+fail:
+	return ret;
+}
+
+struct lgdt3305_reg {
+	u16 reg;
+	u8 val;
+};
+
+static int lgdt3305_write_regs(struct lgdt3305_state *state,
+			       struct lgdt3305_reg *regs, int len)
+{
+	int i, ret;
+
+	lg_reg("writing %d registers...\n", len);
+
+	for (i = 0; i < len - 1; i++) {
+		ret = lgdt3305_write_reg(state, regs[i].reg, regs[i].val);
+		if (lg_fail(ret))
+			return ret;
+	}
+	return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lgdt3305_soft_reset(struct lgdt3305_state *state)
+{
+	int ret;
+
+	lg_dbg("\n");
+
+	ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 0);
+	if (lg_fail(ret))
+		goto fail;
+
+	msleep(20);
+	ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 1);
+fail:
+	return ret;
+}
+
+static inline int lgdt3305_mpeg_mode(struct lgdt3305_state *state,
+				     enum lgdt3305_mpeg_mode mode)
+{
+	lg_dbg("(%d)\n", mode);
+	return lgdt3305_set_reg_bit(state, LGDT3305_TP_CTRL_1, 5, mode);
+}
+
+static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state,
+				       enum lgdt3305_tp_clock_edge edge,
+				       enum lgdt3305_tp_valid_polarity valid)
+{
+	u8 val;
+	int ret;
+
+	lg_dbg("edge = %d, valid = %d\n", edge, valid);
+
+	ret = lgdt3305_read_reg(state, LGDT3305_TP_CTRL_1, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	val &= ~0x09;
+
+	if (edge)
+		val |= 0x08;
+	if (valid)
+		val |= 0x01;
+
+	ret = lgdt3305_write_reg(state, LGDT3305_TP_CTRL_1, val);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lgdt3305_soft_reset(state);
+fail:
+	return ret;
+}
+
+static int lgdt3305_set_modulation(struct lgdt3305_state *state,
+				   struct dtv_frontend_properties *p)
+{
+	u8 opermode;
+	int ret;
+
+	lg_dbg("\n");
+
+	ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_1, &opermode);
+	if (lg_fail(ret))
+		goto fail;
+
+	opermode &= ~0x03;
+
+	switch (p->modulation) {
+	case VSB_8:
+		opermode |= 0x03;
+		break;
+	case QAM_64:
+		opermode |= 0x00;
+		break;
+	case QAM_256:
+		opermode |= 0x01;
+		break;
+	default:
+		return -EINVAL;
+	}
+	ret = lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_1, opermode);
+fail:
+	return ret;
+}
+
+static int lgdt3305_set_filter_extension(struct lgdt3305_state *state,
+					 struct dtv_frontend_properties *p)
+{
+	int val;
+
+	switch (p->modulation) {
+	case VSB_8:
+		val = 0;
+		break;
+	case QAM_64:
+	case QAM_256:
+		val = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+	lg_dbg("val = %d\n", val);
+
+	return lgdt3305_set_reg_bit(state, 0x043f, 2, val);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lgdt3305_passband_digital_agc(struct lgdt3305_state *state,
+					 struct dtv_frontend_properties *p)
+{
+	u16 agc_ref;
+
+	switch (p->modulation) {
+	case VSB_8:
+		agc_ref = 0x32c4;
+		break;
+	case QAM_64:
+		agc_ref = 0x2a00;
+		break;
+	case QAM_256:
+		agc_ref = 0x2a80;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	lg_dbg("agc ref: 0x%04x\n", agc_ref);
+
+	lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_1, agc_ref >> 8);
+	lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_2, agc_ref & 0xff);
+
+	return 0;
+}
+
+static int lgdt3305_rfagc_loop(struct lgdt3305_state *state,
+			       struct dtv_frontend_properties *p)
+{
+	u16 ifbw, rfbw, agcdelay;
+
+	switch (p->modulation) {
+	case VSB_8:
+		agcdelay = 0x04c0;
+		rfbw     = 0x8000;
+		ifbw     = 0x8000;
+		break;
+	case QAM_64:
+	case QAM_256:
+		agcdelay = 0x046b;
+		rfbw     = 0x8889;
+		/* FIXME: investigate optimal ifbw & rfbw values for the
+		 *        DT3304 and re-write this switch..case block */
+		if (state->cfg->demod_chip == LGDT3304)
+			ifbw = 0x6666;
+		else /* (state->cfg->demod_chip == LGDT3305) */
+			ifbw = 0x8888;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (state->cfg->rf_agc_loop) {
+		lg_dbg("agcdelay: 0x%04x, rfbw: 0x%04x\n", agcdelay, rfbw);
+
+		/* rf agc loop filter bandwidth */
+		lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_1,
+				   agcdelay >> 8);
+		lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_2,
+				   agcdelay & 0xff);
+
+		lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_1,
+				   rfbw >> 8);
+		lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_2,
+				   rfbw & 0xff);
+	} else {
+		lg_dbg("ifbw: 0x%04x\n", ifbw);
+
+		/* if agc loop filter bandwidth */
+		lgdt3305_write_reg(state, LGDT3305_IFBW_1, ifbw >> 8);
+		lgdt3305_write_reg(state, LGDT3305_IFBW_2, ifbw & 0xff);
+	}
+
+	return 0;
+}
+
+static int lgdt3305_agc_setup(struct lgdt3305_state *state,
+			      struct dtv_frontend_properties *p)
+{
+	int lockdten, acqen;
+
+	switch (p->modulation) {
+	case VSB_8:
+		lockdten = 0;
+		acqen = 0;
+		break;
+	case QAM_64:
+	case QAM_256:
+		lockdten = 1;
+		acqen = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	lg_dbg("lockdten = %d, acqen = %d\n", lockdten, acqen);
+
+	/* control agc function */
+	switch (state->cfg->demod_chip) {
+	case LGDT3304:
+		lgdt3305_write_reg(state, 0x0314, 0xe1 | lockdten << 1);
+		lgdt3305_set_reg_bit(state, 0x030e, 2, acqen);
+		break;
+	case LGDT3305:
+		lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1);
+		lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return lgdt3305_rfagc_loop(state, p);
+}
+
+static int lgdt3305_set_agc_power_ref(struct lgdt3305_state *state,
+				      struct dtv_frontend_properties *p)
+{
+	u16 usref = 0;
+
+	switch (p->modulation) {
+	case VSB_8:
+		if (state->cfg->usref_8vsb)
+			usref = state->cfg->usref_8vsb;
+		break;
+	case QAM_64:
+		if (state->cfg->usref_qam64)
+			usref = state->cfg->usref_qam64;
+		break;
+	case QAM_256:
+		if (state->cfg->usref_qam256)
+			usref = state->cfg->usref_qam256;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (usref) {
+		lg_dbg("set manual mode: 0x%04x\n", usref);
+
+		lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 3, 1);
+
+		lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_1,
+				   0xff & (usref >> 8));
+		lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_2,
+				   0xff & (usref >> 0));
+	}
+	return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lgdt3305_spectral_inversion(struct lgdt3305_state *state,
+				       struct dtv_frontend_properties *p,
+				       int inversion)
+{
+	int ret;
+
+	lg_dbg("(%d)\n", inversion);
+
+	switch (p->modulation) {
+	case VSB_8:
+		ret = lgdt3305_write_reg(state, LGDT3305_CR_CTRL_7,
+					 inversion ? 0xf9 : 0x79);
+		break;
+	case QAM_64:
+	case QAM_256:
+		ret = lgdt3305_write_reg(state, LGDT3305_FEC_BLOCK_CTRL,
+					 inversion ? 0xfd : 0xff);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int lgdt3305_set_if(struct lgdt3305_state *state,
+			   struct dtv_frontend_properties *p)
+{
+	u16 if_freq_khz;
+	u8 nco1, nco2, nco3, nco4;
+	u64 nco;
+
+	switch (p->modulation) {
+	case VSB_8:
+		if_freq_khz = state->cfg->vsb_if_khz;
+		break;
+	case QAM_64:
+	case QAM_256:
+		if_freq_khz = state->cfg->qam_if_khz;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	nco = if_freq_khz / 10;
+
+	switch (p->modulation) {
+	case VSB_8:
+		nco <<= 24;
+		do_div(nco, 625);
+		break;
+	case QAM_64:
+	case QAM_256:
+		nco <<= 28;
+		do_div(nco, 625);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	nco1 = (nco >> 24) & 0x3f;
+	nco1 |= 0x40;
+	nco2 = (nco >> 16) & 0xff;
+	nco3 = (nco >> 8) & 0xff;
+	nco4 = nco & 0xff;
+
+	lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, nco1);
+	lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, nco2);
+	lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, nco3);
+	lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, nco4);
+
+	lg_dbg("%d KHz -> [%02x%02x%02x%02x]\n",
+	       if_freq_khz, nco1, nco2, nco3, nco4);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lgdt3305_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct lgdt3305_state *state = fe->demodulator_priv;
+
+	if (state->cfg->deny_i2c_rptr)
+		return 0;
+
+	lg_dbg("(%d)\n", enable);
+
+	return lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_2, 5,
+				    enable ? 0 : 1);
+}
+
+static int lgdt3305_sleep(struct dvb_frontend *fe)
+{
+	struct lgdt3305_state *state = fe->demodulator_priv;
+	u8 gen_ctrl_3, gen_ctrl_4;
+
+	lg_dbg("\n");
+
+	gen_ctrl_3 = read_reg(state, LGDT3305_GEN_CTRL_3);
+	gen_ctrl_4 = read_reg(state, LGDT3305_GEN_CTRL_4);
+
+	/* hold in software reset while sleeping */
+	gen_ctrl_3 &= ~0x01;
+	/* tristate the IF-AGC pin */
+	gen_ctrl_3 |=  0x02;
+	/* tristate the RF-AGC pin */
+	gen_ctrl_3 |=  0x04;
+
+	/* disable vsb/qam module */
+	gen_ctrl_4 &= ~0x01;
+	/* disable adc module */
+	gen_ctrl_4 &= ~0x02;
+
+	lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_3, gen_ctrl_3);
+	lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_4, gen_ctrl_4);
+
+	return 0;
+}
+
+static int lgdt3305_init(struct dvb_frontend *fe)
+{
+	struct lgdt3305_state *state = fe->demodulator_priv;
+	int ret;
+
+	static struct lgdt3305_reg lgdt3304_init_data[] = {
+		{ .reg = LGDT3305_GEN_CTRL_1,           .val = 0x03, },
+		{ .reg = 0x000d,                        .val = 0x02, },
+		{ .reg = 0x000e,                        .val = 0x02, },
+		{ .reg = LGDT3305_DGTL_AGC_REF_1,       .val = 0x32, },
+		{ .reg = LGDT3305_DGTL_AGC_REF_2,       .val = 0xc4, },
+		{ .reg = LGDT3305_CR_CTR_FREQ_1,        .val = 0x00, },
+		{ .reg = LGDT3305_CR_CTR_FREQ_2,        .val = 0x00, },
+		{ .reg = LGDT3305_CR_CTR_FREQ_3,        .val = 0x00, },
+		{ .reg = LGDT3305_CR_CTR_FREQ_4,        .val = 0x00, },
+		{ .reg = LGDT3305_CR_CTRL_7,            .val = 0xf9, },
+		{ .reg = 0x0112,                        .val = 0x17, },
+		{ .reg = 0x0113,                        .val = 0x15, },
+		{ .reg = 0x0114,                        .val = 0x18, },
+		{ .reg = 0x0115,                        .val = 0xff, },
+		{ .reg = 0x0116,                        .val = 0x3c, },
+		{ .reg = 0x0214,                        .val = 0x67, },
+		{ .reg = 0x0424,                        .val = 0x8d, },
+		{ .reg = 0x0427,                        .val = 0x12, },
+		{ .reg = 0x0428,                        .val = 0x4f, },
+		{ .reg = LGDT3305_IFBW_1,               .val = 0x80, },
+		{ .reg = LGDT3305_IFBW_2,               .val = 0x00, },
+		{ .reg = 0x030a,                        .val = 0x08, },
+		{ .reg = 0x030b,                        .val = 0x9b, },
+		{ .reg = 0x030d,                        .val = 0x00, },
+		{ .reg = 0x030e,                        .val = 0x1c, },
+		{ .reg = 0x0314,                        .val = 0xe1, },
+		{ .reg = 0x000d,                        .val = 0x82, },
+		{ .reg = LGDT3305_TP_CTRL_1,            .val = 0x5b, },
+		{ .reg = LGDT3305_TP_CTRL_1,            .val = 0x5b, },
+	};
+
+	static struct lgdt3305_reg lgdt3305_init_data[] = {
+		{ .reg = LGDT3305_GEN_CTRL_1,           .val = 0x03, },
+		{ .reg = LGDT3305_GEN_CTRL_2,           .val = 0xb0, },
+		{ .reg = LGDT3305_GEN_CTRL_3,           .val = 0x01, },
+		{ .reg = LGDT3305_GEN_CONTROL,          .val = 0x6f, },
+		{ .reg = LGDT3305_GEN_CTRL_4,           .val = 0x03, },
+		{ .reg = LGDT3305_DGTL_AGC_REF_1,       .val = 0x32, },
+		{ .reg = LGDT3305_DGTL_AGC_REF_2,       .val = 0xc4, },
+		{ .reg = LGDT3305_CR_CTR_FREQ_1,        .val = 0x00, },
+		{ .reg = LGDT3305_CR_CTR_FREQ_2,        .val = 0x00, },
+		{ .reg = LGDT3305_CR_CTR_FREQ_3,        .val = 0x00, },
+		{ .reg = LGDT3305_CR_CTR_FREQ_4,        .val = 0x00, },
+		{ .reg = LGDT3305_CR_CTRL_7,            .val = 0x79, },
+		{ .reg = LGDT3305_AGC_POWER_REF_1,      .val = 0x32, },
+		{ .reg = LGDT3305_AGC_POWER_REF_2,      .val = 0xc4, },
+		{ .reg = LGDT3305_AGC_DELAY_PT_1,       .val = 0x0d, },
+		{ .reg = LGDT3305_AGC_DELAY_PT_2,       .val = 0x30, },
+		{ .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_1, .val = 0x80, },
+		{ .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_2, .val = 0x00, },
+		{ .reg = LGDT3305_IFBW_1,               .val = 0x80, },
+		{ .reg = LGDT3305_IFBW_2,               .val = 0x00, },
+		{ .reg = LGDT3305_AGC_CTRL_1,           .val = 0x30, },
+		{ .reg = LGDT3305_AGC_CTRL_4,           .val = 0x61, },
+		{ .reg = LGDT3305_FEC_BLOCK_CTRL,       .val = 0xff, },
+		{ .reg = LGDT3305_TP_CTRL_1,            .val = 0x1b, },
+	};
+
+	lg_dbg("\n");
+
+	switch (state->cfg->demod_chip) {
+	case LGDT3304:
+		ret = lgdt3305_write_regs(state, lgdt3304_init_data,
+					  ARRAY_SIZE(lgdt3304_init_data));
+		break;
+	case LGDT3305:
+		ret = lgdt3305_write_regs(state, lgdt3305_init_data,
+					  ARRAY_SIZE(lgdt3305_init_data));
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lgdt3305_soft_reset(state);
+fail:
+	return ret;
+}
+
+static int lgdt3304_set_parameters(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct lgdt3305_state *state = fe->demodulator_priv;
+	int ret;
+
+	lg_dbg("(%d, %d)\n", p->frequency, p->modulation);
+
+	if (fe->ops.tuner_ops.set_params) {
+		ret = fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+		if (lg_fail(ret))
+			goto fail;
+		state->current_frequency = p->frequency;
+	}
+
+	ret = lgdt3305_set_modulation(state, p);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lgdt3305_passband_digital_agc(state, p);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lgdt3305_agc_setup(state, p);
+	if (lg_fail(ret))
+		goto fail;
+
+	/* reg 0x030d is 3304-only... seen in vsb and qam usbsnoops... */
+	switch (p->modulation) {
+	case VSB_8:
+		lgdt3305_write_reg(state, 0x030d, 0x00);
+		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, 0x4f);
+		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, 0x0c);
+		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, 0xac);
+		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, 0xba);
+		break;
+	case QAM_64:
+	case QAM_256:
+		lgdt3305_write_reg(state, 0x030d, 0x14);
+		ret = lgdt3305_set_if(state, p);
+		if (lg_fail(ret))
+			goto fail;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+
+	ret = lgdt3305_spectral_inversion(state, p,
+					  state->cfg->spectral_inversion
+					  ? 1 : 0);
+	if (lg_fail(ret))
+		goto fail;
+
+	state->current_modulation = p->modulation;
+
+	ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
+	if (lg_fail(ret))
+		goto fail;
+
+	/* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
+	ret = lgdt3305_mpeg_mode_polarity(state,
+					  state->cfg->tpclk_edge,
+					  state->cfg->tpvalid_polarity);
+fail:
+	return ret;
+}
+
+static int lgdt3305_set_parameters(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct lgdt3305_state *state = fe->demodulator_priv;
+	int ret;
+
+	lg_dbg("(%d, %d)\n", p->frequency, p->modulation);
+
+	if (fe->ops.tuner_ops.set_params) {
+		ret = fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+		if (lg_fail(ret))
+			goto fail;
+		state->current_frequency = p->frequency;
+	}
+
+	ret = lgdt3305_set_modulation(state, p);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lgdt3305_passband_digital_agc(state, p);
+	if (lg_fail(ret))
+		goto fail;
+	ret = lgdt3305_set_agc_power_ref(state, p);
+	if (lg_fail(ret))
+		goto fail;
+	ret = lgdt3305_agc_setup(state, p);
+	if (lg_fail(ret))
+		goto fail;
+
+	/* low if */
+	ret = lgdt3305_write_reg(state, LGDT3305_GEN_CONTROL, 0x2f);
+	if (lg_fail(ret))
+		goto fail;
+	ret = lgdt3305_set_reg_bit(state, LGDT3305_CR_CTR_FREQ_1, 6, 1);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lgdt3305_set_if(state, p);
+	if (lg_fail(ret))
+		goto fail;
+	ret = lgdt3305_spectral_inversion(state, p,
+					  state->cfg->spectral_inversion
+					  ? 1 : 0);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lgdt3305_set_filter_extension(state, p);
+	if (lg_fail(ret))
+		goto fail;
+
+	state->current_modulation = p->modulation;
+
+	ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
+	if (lg_fail(ret))
+		goto fail;
+
+	/* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
+	ret = lgdt3305_mpeg_mode_polarity(state,
+					  state->cfg->tpclk_edge,
+					  state->cfg->tpvalid_polarity);
+fail:
+	return ret;
+}
+
+static int lgdt3305_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct lgdt3305_state *state = fe->demodulator_priv;
+
+	lg_dbg("\n");
+
+	p->modulation = state->current_modulation;
+	p->frequency = state->current_frequency;
+	return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lgdt3305_read_cr_lock_status(struct lgdt3305_state *state,
+					int *locked)
+{
+	u8 val;
+	int ret;
+	char *cr_lock_state = "";
+
+	*locked = 0;
+
+	ret = lgdt3305_read_reg(state, LGDT3305_CR_LOCK_STATUS, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	switch (state->current_modulation) {
+	case QAM_256:
+	case QAM_64:
+		if (val & (1 << 1))
+			*locked = 1;
+
+		switch (val & 0x07) {
+		case 0:
+			cr_lock_state = "QAM UNLOCK";
+			break;
+		case 4:
+			cr_lock_state = "QAM 1stLock";
+			break;
+		case 6:
+			cr_lock_state = "QAM 2ndLock";
+			break;
+		case 7:
+			cr_lock_state = "QAM FinalLock";
+			break;
+		default:
+			cr_lock_state = "CLOCKQAM-INVALID!";
+			break;
+		}
+		break;
+	case VSB_8:
+		if (val & (1 << 7)) {
+			*locked = 1;
+			cr_lock_state = "CLOCKVSB";
+		}
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	lg_dbg("(%d) %s\n", *locked, cr_lock_state);
+fail:
+	return ret;
+}
+
+static int lgdt3305_read_fec_lock_status(struct lgdt3305_state *state,
+					 int *locked)
+{
+	u8 val;
+	int ret, mpeg_lock, fec_lock, viterbi_lock;
+
+	*locked = 0;
+
+	switch (state->current_modulation) {
+	case QAM_256:
+	case QAM_64:
+		ret = lgdt3305_read_reg(state,
+					LGDT3305_FEC_LOCK_STATUS, &val);
+		if (lg_fail(ret))
+			goto fail;
+
+		mpeg_lock    = (val & (1 << 0)) ? 1 : 0;
+		fec_lock     = (val & (1 << 2)) ? 1 : 0;
+		viterbi_lock = (val & (1 << 3)) ? 1 : 0;
+
+		*locked = mpeg_lock && fec_lock && viterbi_lock;
+
+		lg_dbg("(%d) %s%s%s\n", *locked,
+		       mpeg_lock    ? "mpeg lock  "  : "",
+		       fec_lock     ? "fec lock  "   : "",
+		       viterbi_lock ? "viterbi lock" : "");
+		break;
+	case VSB_8:
+	default:
+		ret = -EINVAL;
+	}
+fail:
+	return ret;
+}
+
+static int lgdt3305_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct lgdt3305_state *state = fe->demodulator_priv;
+	u8 val;
+	int ret, signal, inlock, nofecerr, snrgood,
+		cr_lock, fec_lock, sync_lock;
+
+	*status = 0;
+
+	ret = lgdt3305_read_reg(state, LGDT3305_GEN_STATUS, &val);
+	if (lg_fail(ret))
+		goto fail;
+
+	signal    = (val & (1 << 4)) ? 1 : 0;
+	inlock    = (val & (1 << 3)) ? 0 : 1;
+	sync_lock = (val & (1 << 2)) ? 1 : 0;
+	nofecerr  = (val & (1 << 1)) ? 1 : 0;
+	snrgood   = (val & (1 << 0)) ? 1 : 0;
+
+	lg_dbg("%s%s%s%s%s\n",
+	       signal    ? "SIGNALEXIST " : "",
+	       inlock    ? "INLOCK "      : "",
+	       sync_lock ? "SYNCLOCK "    : "",
+	       nofecerr  ? "NOFECERR "    : "",
+	       snrgood   ? "SNRGOOD "     : "");
+
+	ret = lgdt3305_read_cr_lock_status(state, &cr_lock);
+	if (lg_fail(ret))
+		goto fail;
+
+	if (signal)
+		*status |= FE_HAS_SIGNAL;
+	if (cr_lock)
+		*status |= FE_HAS_CARRIER;
+	if (nofecerr)
+		*status |= FE_HAS_VITERBI;
+	if (sync_lock)
+		*status |= FE_HAS_SYNC;
+
+	switch (state->current_modulation) {
+	case QAM_256:
+	case QAM_64:
+		/* signal bit is unreliable on the DT3304 in QAM mode */
+		if (((LGDT3304 == state->cfg->demod_chip)) && (cr_lock))
+			*status |= FE_HAS_SIGNAL;
+
+		ret = lgdt3305_read_fec_lock_status(state, &fec_lock);
+		if (lg_fail(ret))
+			goto fail;
+
+		if (fec_lock)
+			*status |= FE_HAS_LOCK;
+		break;
+	case VSB_8:
+		if (inlock)
+			*status |= FE_HAS_LOCK;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* borrowed from lgdt330x.c */
+static u32 calculate_snr(u32 mse, u32 c)
+{
+	if (mse == 0) /* no signal */
+		return 0;
+
+	mse = intlog10(mse);
+	if (mse > c) {
+		/* Negative SNR, which is possible, but realisticly the
+		demod will lose lock before the signal gets this bad.  The
+		API only allows for unsigned values, so just return 0 */
+		return 0;
+	}
+	return 10*(c - mse);
+}
+
+static int lgdt3305_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct lgdt3305_state *state = fe->demodulator_priv;
+	u32 noise;	/* noise value */
+	u32 c;		/* per-modulation SNR calculation constant */
+
+	switch (state->current_modulation) {
+	case VSB_8:
+#ifdef USE_PTMSE
+		/* Use Phase Tracker Mean-Square Error Register */
+		/* SNR for ranges from -13.11 to +44.08 */
+		noise =	((read_reg(state, LGDT3305_PT_MSE_1) & 0x07) << 16) |
+			(read_reg(state, LGDT3305_PT_MSE_2) << 8) |
+			(read_reg(state, LGDT3305_PT_MSE_3) & 0xff);
+		c = 73957994; /* log10(25*32^2)*2^24 */
+#else
+		/* Use Equalizer Mean-Square Error Register */
+		/* SNR for ranges from -16.12 to +44.08 */
+		noise =	((read_reg(state, LGDT3305_EQ_MSE_1) & 0x0f) << 16) |
+			(read_reg(state, LGDT3305_EQ_MSE_2) << 8) |
+			(read_reg(state, LGDT3305_EQ_MSE_3) & 0xff);
+		c = 73957994; /* log10(25*32^2)*2^24 */
+#endif
+		break;
+	case QAM_64:
+	case QAM_256:
+		noise = (read_reg(state, LGDT3305_CR_MSE_1) << 8) |
+			(read_reg(state, LGDT3305_CR_MSE_2) & 0xff);
+
+		c = (state->current_modulation == QAM_64) ?
+			97939837 : 98026066;
+		/* log10(688128)*2^24 and log10(696320)*2^24 */
+		break;
+	default:
+		return -EINVAL;
+	}
+	state->snr = calculate_snr(noise, c);
+	/* report SNR in dB * 10 */
+	*snr = (state->snr / ((1 << 24) / 10));
+	lg_dbg("noise = 0x%08x, snr = %d.%02d dB\n", noise,
+	       state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
+
+	return 0;
+}
+
+static int lgdt3305_read_signal_strength(struct dvb_frontend *fe,
+					 u16 *strength)
+{
+	/* borrowed from lgdt330x.c
+	 *
+	 * Calculate strength from SNR up to 35dB
+	 * Even though the SNR can go higher than 35dB,
+	 * there is some comfort factor in having a range of
+	 * strong signals that can show at 100%
+	 */
+	struct lgdt3305_state *state = fe->demodulator_priv;
+	u16 snr;
+	int ret;
+
+	*strength = 0;
+
+	ret = fe->ops.read_snr(fe, &snr);
+	if (lg_fail(ret))
+		goto fail;
+	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
+	/* scale the range 0 - 35*2^24 into 0 - 65535 */
+	if (state->snr >= 8960 * 0x10000)
+		*strength = 0xffff;
+	else
+		*strength = state->snr / 8960;
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lgdt3305_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	*ber = 0;
+	return 0;
+}
+
+static int lgdt3305_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct lgdt3305_state *state = fe->demodulator_priv;
+
+	*ucblocks =
+		(read_reg(state, LGDT3305_FEC_PKT_ERR_1) << 8) |
+		(read_reg(state, LGDT3305_FEC_PKT_ERR_2) & 0xff);
+
+	return 0;
+}
+
+static int lgdt3305_get_tune_settings(struct dvb_frontend *fe,
+				      struct dvb_frontend_tune_settings
+					*fe_tune_settings)
+{
+	fe_tune_settings->min_delay_ms = 500;
+	lg_dbg("\n");
+	return 0;
+}
+
+static void lgdt3305_release(struct dvb_frontend *fe)
+{
+	struct lgdt3305_state *state = fe->demodulator_priv;
+	lg_dbg("\n");
+	kfree(state);
+}
+
+static struct dvb_frontend_ops lgdt3304_ops;
+static struct dvb_frontend_ops lgdt3305_ops;
+
+struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
+				     struct i2c_adapter *i2c_adap)
+{
+	struct lgdt3305_state *state = NULL;
+	int ret;
+	u8 val;
+
+	lg_dbg("(%d-%04x)\n",
+	       i2c_adap ? i2c_adapter_id(i2c_adap) : 0,
+	       config ? config->i2c_addr : 0);
+
+	state = kzalloc(sizeof(struct lgdt3305_state), GFP_KERNEL);
+	if (state == NULL)
+		goto fail;
+
+	state->cfg = config;
+	state->i2c_adap = i2c_adap;
+
+	switch (config->demod_chip) {
+	case LGDT3304:
+		memcpy(&state->frontend.ops, &lgdt3304_ops,
+		       sizeof(struct dvb_frontend_ops));
+		break;
+	case LGDT3305:
+		memcpy(&state->frontend.ops, &lgdt3305_ops,
+		       sizeof(struct dvb_frontend_ops));
+		break;
+	default:
+		goto fail;
+	}
+	state->frontend.demodulator_priv = state;
+
+	/* verify that we're talking to a lg dt3304/5 */
+	ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_2, &val);
+	if ((lg_fail(ret)) | (val == 0))
+		goto fail;
+	ret = lgdt3305_write_reg(state, 0x0808, 0x80);
+	if (lg_fail(ret))
+		goto fail;
+	ret = lgdt3305_read_reg(state, 0x0808, &val);
+	if ((lg_fail(ret)) | (val != 0x80))
+		goto fail;
+	ret = lgdt3305_write_reg(state, 0x0808, 0x00);
+	if (lg_fail(ret))
+		goto fail;
+
+	state->current_frequency = -1;
+	state->current_modulation = -1;
+
+	return &state->frontend;
+fail:
+	lg_warn("unable to detect %s hardware\n",
+		config->demod_chip ? "LGDT3304" : "LGDT3305");
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(lgdt3305_attach);
+
+static struct dvb_frontend_ops lgdt3304_ops = {
+	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
+	.info = {
+		.name = "LG Electronics LGDT3304 VSB/QAM Frontend",
+		.frequency_min      = 54000000,
+		.frequency_max      = 858000000,
+		.frequency_stepsize = 62500,
+		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+	},
+	.i2c_gate_ctrl        = lgdt3305_i2c_gate_ctrl,
+	.init                 = lgdt3305_init,
+	.set_frontend         = lgdt3304_set_parameters,
+	.get_frontend         = lgdt3305_get_frontend,
+	.get_tune_settings    = lgdt3305_get_tune_settings,
+	.read_status          = lgdt3305_read_status,
+	.read_ber             = lgdt3305_read_ber,
+	.read_signal_strength = lgdt3305_read_signal_strength,
+	.read_snr             = lgdt3305_read_snr,
+	.read_ucblocks        = lgdt3305_read_ucblocks,
+	.release              = lgdt3305_release,
+};
+
+static struct dvb_frontend_ops lgdt3305_ops = {
+	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
+	.info = {
+		.name = "LG Electronics LGDT3305 VSB/QAM Frontend",
+		.frequency_min      = 54000000,
+		.frequency_max      = 858000000,
+		.frequency_stepsize = 62500,
+		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+	},
+	.i2c_gate_ctrl        = lgdt3305_i2c_gate_ctrl,
+	.init                 = lgdt3305_init,
+	.sleep                = lgdt3305_sleep,
+	.set_frontend         = lgdt3305_set_parameters,
+	.get_frontend         = lgdt3305_get_frontend,
+	.get_tune_settings    = lgdt3305_get_tune_settings,
+	.read_status          = lgdt3305_read_status,
+	.read_ber             = lgdt3305_read_ber,
+	.read_signal_strength = lgdt3305_read_signal_strength,
+	.read_snr             = lgdt3305_read_snr,
+	.read_ucblocks        = lgdt3305_read_ucblocks,
+	.release              = lgdt3305_release,
+};
+
+MODULE_DESCRIPTION("LG Electronics LGDT3304/5 ATSC/QAM-B Demodulator Driver");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.2");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb-frontends/lgdt3305.h b/drivers/media/dvb-frontends/lgdt3305.h
new file mode 100644
index 0000000..02172ec
--- /dev/null
+++ b/drivers/media/dvb-frontends/lgdt3305.h
@@ -0,0 +1,91 @@
+/*
+ *    Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM
+ *
+ *    Copyright (C) 2008, 2009, 2010 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _LGDT3305_H_
+#define _LGDT3305_H_
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+
+enum lgdt3305_mpeg_mode {
+	LGDT3305_MPEG_PARALLEL = 0,
+	LGDT3305_MPEG_SERIAL = 1,
+};
+
+enum lgdt3305_tp_clock_edge {
+	LGDT3305_TPCLK_RISING_EDGE = 0,
+	LGDT3305_TPCLK_FALLING_EDGE = 1,
+};
+
+enum lgdt3305_tp_valid_polarity {
+	LGDT3305_TP_VALID_LOW = 0,
+	LGDT3305_TP_VALID_HIGH = 1,
+};
+
+enum lgdt_demod_chip_type {
+	LGDT3305 = 0,
+	LGDT3304 = 1,
+};
+
+struct lgdt3305_config {
+	u8 i2c_addr;
+
+	/* user defined IF frequency in KHz */
+	u16 qam_if_khz;
+	u16 vsb_if_khz;
+
+	/* AGC Power reference - defaults are used if left unset */
+	u16 usref_8vsb;   /* default: 0x32c4 */
+	u16 usref_qam64;  /* default: 0x5400 */
+	u16 usref_qam256; /* default: 0x2a80 */
+
+	/* disable i2c repeater - 0:repeater enabled 1:repeater disabled */
+	unsigned int deny_i2c_rptr:1;
+
+	/* spectral inversion - 0:disabled 1:enabled */
+	unsigned int spectral_inversion:1;
+
+	/* use RF AGC loop - 0:disabled 1:enabled */
+	unsigned int rf_agc_loop:1;
+
+	enum lgdt3305_mpeg_mode mpeg_mode;
+	enum lgdt3305_tp_clock_edge tpclk_edge;
+	enum lgdt3305_tp_valid_polarity tpvalid_polarity;
+	enum lgdt_demod_chip_type demod_chip;
+};
+
+#if defined(CONFIG_DVB_LGDT3305) || (defined(CONFIG_DVB_LGDT3305_MODULE) && \
+				     defined(MODULE))
+extern
+struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
+				     struct i2c_adapter *i2c_adap);
+#else
+static inline
+struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
+				     struct i2c_adapter *i2c_adap)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_LGDT3305 */
+
+#endif /* _LGDT3305_H_ */
diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c
new file mode 100644
index 0000000..e046622
--- /dev/null
+++ b/drivers/media/dvb-frontends/lgdt330x.c
@@ -0,0 +1,831 @@
+/*
+ *    Support for LGDT3302 and LGDT3303 - VSB/QAM
+ *
+ *    Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.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.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ *                      NOTES ABOUT THIS DRIVER
+ *
+ * This Linux driver supports:
+ *   DViCO FusionHDTV 3 Gold-Q
+ *   DViCO FusionHDTV 3 Gold-T
+ *   DViCO FusionHDTV 5 Gold
+ *   DViCO FusionHDTV 5 Lite
+ *   DViCO FusionHDTV 5 USB Gold
+ *   Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
+ *   pcHDTV HD5500
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <asm/byteorder.h>
+
+#include "dvb_frontend.h"
+#include "dvb_math.h"
+#include "lgdt330x_priv.h"
+#include "lgdt330x.h"
+
+/* Use Equalizer Mean Squared Error instead of Phaser Tracker MSE */
+/* #define USE_EQMSE */
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"Turn on/off lgdt330x frontend debugging (default:off).");
+#define dprintk(args...) \
+do { \
+if (debug) printk(KERN_DEBUG "lgdt330x: " args); \
+} while (0)
+
+struct lgdt330x_state
+{
+	struct i2c_adapter* i2c;
+
+	/* Configuration settings */
+	const struct lgdt330x_config* config;
+
+	struct dvb_frontend frontend;
+
+	/* Demodulator private data */
+	fe_modulation_t current_modulation;
+	u32 snr; /* Result of last SNR calculation */
+
+	/* Tuner private data */
+	u32 current_frequency;
+};
+
+static int i2c_write_demod_bytes (struct lgdt330x_state* state,
+				  u8 *buf, /* data bytes to send */
+				  int len  /* number of bytes to send */ )
+{
+	struct i2c_msg msg =
+		{ .addr = state->config->demod_address,
+		  .flags = 0,
+		  .buf = buf,
+		  .len = 2 };
+	int i;
+	int err;
+
+	for (i=0; i<len-1; i+=2){
+		if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+			printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n", __func__, msg.buf[0], msg.buf[1], err);
+			if (err < 0)
+				return err;
+			else
+				return -EREMOTEIO;
+		}
+		msg.buf += 2;
+	}
+	return 0;
+}
+
+/*
+ * This routine writes the register (reg) to the demod bus
+ * then reads the data returned for (len) bytes.
+ */
+
+static int i2c_read_demod_bytes(struct lgdt330x_state *state,
+				enum I2C_REG reg, u8 *buf, int len)
+{
+	u8 wr [] = { reg };
+	struct i2c_msg msg [] = {
+		{ .addr = state->config->demod_address,
+		  .flags = 0, .buf = wr,  .len = 1 },
+		{ .addr = state->config->demod_address,
+		  .flags = I2C_M_RD, .buf = buf, .len = len },
+	};
+	int ret;
+	ret = i2c_transfer(state->i2c, msg, 2);
+	if (ret != 2) {
+		printk(KERN_WARNING "lgdt330x: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __func__, state->config->demod_address, reg, ret);
+		if (ret >= 0)
+			ret = -EIO;
+	} else {
+		ret = 0;
+	}
+	return ret;
+}
+
+/* Software reset */
+static int lgdt3302_SwReset(struct lgdt330x_state* state)
+{
+	u8 ret;
+	u8 reset[] = {
+		IRQ_MASK,
+		0x00 /* bit 6 is active low software reset
+		      *	bits 5-0 are 1 to mask interrupts */
+	};
+
+	ret = i2c_write_demod_bytes(state,
+				    reset, sizeof(reset));
+	if (ret == 0) {
+
+		/* force reset high (inactive) and unmask interrupts */
+		reset[1] = 0x7f;
+		ret = i2c_write_demod_bytes(state,
+					    reset, sizeof(reset));
+	}
+	return ret;
+}
+
+static int lgdt3303_SwReset(struct lgdt330x_state* state)
+{
+	u8 ret;
+	u8 reset[] = {
+		0x02,
+		0x00 /* bit 0 is active low software reset */
+	};
+
+	ret = i2c_write_demod_bytes(state,
+				    reset, sizeof(reset));
+	if (ret == 0) {
+
+		/* force reset high (inactive) */
+		reset[1] = 0x01;
+		ret = i2c_write_demod_bytes(state,
+					    reset, sizeof(reset));
+	}
+	return ret;
+}
+
+static int lgdt330x_SwReset(struct lgdt330x_state* state)
+{
+	switch (state->config->demod_chip) {
+	case LGDT3302:
+		return lgdt3302_SwReset(state);
+	case LGDT3303:
+		return lgdt3303_SwReset(state);
+	default:
+		return -ENODEV;
+	}
+}
+
+static int lgdt330x_init(struct dvb_frontend* fe)
+{
+	/* Hardware reset is done using gpio[0] of cx23880x chip.
+	 * I'd like to do it here, but don't know how to find chip address.
+	 * cx88-cards.c arranges for the reset bit to be inactive (high).
+	 * Maybe there needs to be a callable function in cx88-core or
+	 * the caller of this function needs to do it. */
+
+	/*
+	 * Array of byte pairs <address, value>
+	 * to initialize each different chip
+	 */
+	static u8 lgdt3302_init_data[] = {
+		/* Use 50MHz parameter values from spec sheet since xtal is 50 */
+		/* Change the value of NCOCTFV[25:0] of carrier
+		   recovery center frequency register */
+		VSB_CARRIER_FREQ0, 0x00,
+		VSB_CARRIER_FREQ1, 0x87,
+		VSB_CARRIER_FREQ2, 0x8e,
+		VSB_CARRIER_FREQ3, 0x01,
+		/* Change the TPCLK pin polarity
+		   data is valid on falling clock */
+		DEMUX_CONTROL, 0xfb,
+		/* Change the value of IFBW[11:0] of
+		   AGC IF/RF loop filter bandwidth register */
+		AGC_RF_BANDWIDTH0, 0x40,
+		AGC_RF_BANDWIDTH1, 0x93,
+		AGC_RF_BANDWIDTH2, 0x00,
+		/* Change the value of bit 6, 'nINAGCBY' and
+		   'NSSEL[1:0] of ACG function control register 2 */
+		AGC_FUNC_CTRL2, 0xc6,
+		/* Change the value of bit 6 'RFFIX'
+		   of AGC function control register 3 */
+		AGC_FUNC_CTRL3, 0x40,
+		/* Set the value of 'INLVTHD' register 0x2a/0x2c
+		   to 0x7fe */
+		AGC_DELAY0, 0x07,
+		AGC_DELAY2, 0xfe,
+		/* Change the value of IAGCBW[15:8]
+		   of inner AGC loop filter bandwidth */
+		AGC_LOOP_BANDWIDTH0, 0x08,
+		AGC_LOOP_BANDWIDTH1, 0x9a
+	};
+
+	static u8 lgdt3303_init_data[] = {
+		0x4c, 0x14
+	};
+
+	static u8 flip_1_lgdt3303_init_data[] = {
+		0x4c, 0x14,
+		0x87, 0xf3
+	};
+
+	static u8 flip_2_lgdt3303_init_data[] = {
+		0x4c, 0x14,
+		0x87, 0xda
+	};
+
+	struct lgdt330x_state* state = fe->demodulator_priv;
+	char  *chip_name;
+	int    err;
+
+	switch (state->config->demod_chip) {
+	case LGDT3302:
+		chip_name = "LGDT3302";
+		err = i2c_write_demod_bytes(state, lgdt3302_init_data,
+					    sizeof(lgdt3302_init_data));
+		break;
+	case LGDT3303:
+		chip_name = "LGDT3303";
+		switch (state->config->clock_polarity_flip) {
+		case 2:
+			err = i2c_write_demod_bytes(state,
+					flip_2_lgdt3303_init_data,
+					sizeof(flip_2_lgdt3303_init_data));
+			break;
+		case 1:
+			err = i2c_write_demod_bytes(state,
+					flip_1_lgdt3303_init_data,
+					sizeof(flip_1_lgdt3303_init_data));
+			break;
+		case 0:
+		default:
+			err = i2c_write_demod_bytes(state, lgdt3303_init_data,
+						    sizeof(lgdt3303_init_data));
+		}
+		break;
+	default:
+		chip_name = "undefined";
+		printk (KERN_WARNING "Only LGDT3302 and LGDT3303 are supported chips.\n");
+		err = -ENODEV;
+	}
+	dprintk("%s entered as %s\n", __func__, chip_name);
+	if (err < 0)
+		return err;
+	return lgdt330x_SwReset(state);
+}
+
+static int lgdt330x_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	*ber = 0; /* Not supplied by the demod chips */
+	return 0;
+}
+
+static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct lgdt330x_state* state = fe->demodulator_priv;
+	int err;
+	u8 buf[2];
+
+	*ucblocks = 0;
+
+	switch (state->config->demod_chip) {
+	case LGDT3302:
+		err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1,
+					   buf, sizeof(buf));
+		break;
+	case LGDT3303:
+		err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1,
+					   buf, sizeof(buf));
+		break;
+	default:
+		printk(KERN_WARNING
+		       "Only LGDT3302 and LGDT3303 are supported chips.\n");
+		err = -ENODEV;
+	}
+	if (err < 0)
+		return err;
+
+	*ucblocks = (buf[0] << 8) | buf[1];
+	return 0;
+}
+
+static int lgdt330x_set_parameters(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	/*
+	 * Array of byte pairs <address, value>
+	 * to initialize 8VSB for lgdt3303 chip 50 MHz IF
+	 */
+	static u8 lgdt3303_8vsb_44_data[] = {
+		0x04, 0x00,
+		0x0d, 0x40,
+		0x0e, 0x87,
+		0x0f, 0x8e,
+		0x10, 0x01,
+		0x47, 0x8b };
+
+	/*
+	 * Array of byte pairs <address, value>
+	 * to initialize QAM for lgdt3303 chip
+	 */
+	static u8 lgdt3303_qam_data[] = {
+		0x04, 0x00,
+		0x0d, 0x00,
+		0x0e, 0x00,
+		0x0f, 0x00,
+		0x10, 0x00,
+		0x51, 0x63,
+		0x47, 0x66,
+		0x48, 0x66,
+		0x4d, 0x1a,
+		0x49, 0x08,
+		0x4a, 0x9b };
+
+	struct lgdt330x_state* state = fe->demodulator_priv;
+
+	static u8 top_ctrl_cfg[]   = { TOP_CONTROL, 0x03 };
+
+	int err = 0;
+	/* Change only if we are actually changing the modulation */
+	if (state->current_modulation != p->modulation) {
+		switch (p->modulation) {
+		case VSB_8:
+			dprintk("%s: VSB_8 MODE\n", __func__);
+
+			/* Select VSB mode */
+			top_ctrl_cfg[1] = 0x03;
+
+			/* Select ANT connector if supported by card */
+			if (state->config->pll_rf_set)
+				state->config->pll_rf_set(fe, 1);
+
+			if (state->config->demod_chip == LGDT3303) {
+				err = i2c_write_demod_bytes(state, lgdt3303_8vsb_44_data,
+							    sizeof(lgdt3303_8vsb_44_data));
+			}
+			break;
+
+		case QAM_64:
+			dprintk("%s: QAM_64 MODE\n", __func__);
+
+			/* Select QAM_64 mode */
+			top_ctrl_cfg[1] = 0x00;
+
+			/* Select CABLE connector if supported by card */
+			if (state->config->pll_rf_set)
+				state->config->pll_rf_set(fe, 0);
+
+			if (state->config->demod_chip == LGDT3303) {
+				err = i2c_write_demod_bytes(state, lgdt3303_qam_data,
+											sizeof(lgdt3303_qam_data));
+			}
+			break;
+
+		case QAM_256:
+			dprintk("%s: QAM_256 MODE\n", __func__);
+
+			/* Select QAM_256 mode */
+			top_ctrl_cfg[1] = 0x01;
+
+			/* Select CABLE connector if supported by card */
+			if (state->config->pll_rf_set)
+				state->config->pll_rf_set(fe, 0);
+
+			if (state->config->demod_chip == LGDT3303) {
+				err = i2c_write_demod_bytes(state, lgdt3303_qam_data,
+											sizeof(lgdt3303_qam_data));
+			}
+			break;
+		default:
+			printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __func__, p->modulation);
+			return -1;
+		}
+		if (err < 0)
+			printk(KERN_WARNING "lgdt330x: %s: error blasting "
+			       "bytes to lgdt3303 for modulation type(%d)\n",
+			       __func__, p->modulation);
+
+		/*
+		 * select serial or parallel MPEG harware interface
+		 * Serial:   0x04 for LGDT3302 or 0x40 for LGDT3303
+		 * Parallel: 0x00
+		 */
+		top_ctrl_cfg[1] |= state->config->serial_mpeg;
+
+		/* Select the requested mode */
+		i2c_write_demod_bytes(state, top_ctrl_cfg,
+				      sizeof(top_ctrl_cfg));
+		if (state->config->set_ts_params)
+			state->config->set_ts_params(fe, 0);
+		state->current_modulation = p->modulation;
+	}
+
+	/* Tune to the specified frequency */
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	/* Keep track of the new frequency */
+	/* FIXME this is the wrong way to do this...           */
+	/* The tuner is shared with the video4linux analog API */
+	state->current_frequency = p->frequency;
+
+	lgdt330x_SwReset(state);
+	return 0;
+}
+
+static int lgdt330x_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct lgdt330x_state *state = fe->demodulator_priv;
+	p->frequency = state->current_frequency;
+	return 0;
+}
+
+static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct lgdt330x_state* state = fe->demodulator_priv;
+	u8 buf[3];
+
+	*status = 0; /* Reset status result */
+
+	/* AGC status register */
+	i2c_read_demod_bytes(state, AGC_STATUS, buf, 1);
+	dprintk("%s: AGC_STATUS = 0x%02x\n", __func__, buf[0]);
+	if ((buf[0] & 0x0c) == 0x8){
+		/* Test signal does not exist flag */
+		/* as well as the AGC lock flag.   */
+		*status |= FE_HAS_SIGNAL;
+	}
+
+	/*
+	 * You must set the Mask bits to 1 in the IRQ_MASK in order
+	 * to see that status bit in the IRQ_STATUS register.
+	 * This is done in SwReset();
+	 */
+	/* signal status */
+	i2c_read_demod_bytes(state, TOP_CONTROL, buf, sizeof(buf));
+	dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __func__, buf[0], buf[1], buf[2]);
+
+
+	/* sync status */
+	if ((buf[2] & 0x03) == 0x01) {
+		*status |= FE_HAS_SYNC;
+	}
+
+	/* FEC error status */
+	if ((buf[2] & 0x0c) == 0x08) {
+		*status |= FE_HAS_LOCK;
+		*status |= FE_HAS_VITERBI;
+	}
+
+	/* Carrier Recovery Lock Status Register */
+	i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1);
+	dprintk("%s: CARRIER_LOCK = 0x%02x\n", __func__, buf[0]);
+	switch (state->current_modulation) {
+	case QAM_256:
+	case QAM_64:
+		/* Need to understand why there are 3 lock levels here */
+		if ((buf[0] & 0x07) == 0x07)
+			*status |= FE_HAS_CARRIER;
+		break;
+	case VSB_8:
+		if ((buf[0] & 0x80) == 0x80)
+			*status |= FE_HAS_CARRIER;
+		break;
+	default:
+		printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __func__);
+	}
+
+	return 0;
+}
+
+static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct lgdt330x_state* state = fe->demodulator_priv;
+	int err;
+	u8 buf[3];
+
+	*status = 0; /* Reset status result */
+
+	/* lgdt3303 AGC status register */
+	err = i2c_read_demod_bytes(state, 0x58, buf, 1);
+	if (err < 0)
+		return err;
+
+	dprintk("%s: AGC_STATUS = 0x%02x\n", __func__, buf[0]);
+	if ((buf[0] & 0x21) == 0x01){
+		/* Test input signal does not exist flag */
+		/* as well as the AGC lock flag.   */
+		*status |= FE_HAS_SIGNAL;
+	}
+
+	/* Carrier Recovery Lock Status Register */
+	i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1);
+	dprintk("%s: CARRIER_LOCK = 0x%02x\n", __func__, buf[0]);
+	switch (state->current_modulation) {
+	case QAM_256:
+	case QAM_64:
+		/* Need to understand why there are 3 lock levels here */
+		if ((buf[0] & 0x07) == 0x07)
+			*status |= FE_HAS_CARRIER;
+		else
+			break;
+		i2c_read_demod_bytes(state, 0x8a, buf, 1);
+		if ((buf[0] & 0x04) == 0x04)
+			*status |= FE_HAS_SYNC;
+		if ((buf[0] & 0x01) == 0x01)
+			*status |= FE_HAS_LOCK;
+		if ((buf[0] & 0x08) == 0x08)
+			*status |= FE_HAS_VITERBI;
+		break;
+	case VSB_8:
+		if ((buf[0] & 0x80) == 0x80)
+			*status |= FE_HAS_CARRIER;
+		else
+			break;
+		i2c_read_demod_bytes(state, 0x38, buf, 1);
+		if ((buf[0] & 0x02) == 0x00)
+			*status |= FE_HAS_SYNC;
+		if ((buf[0] & 0x01) == 0x01) {
+			*status |= FE_HAS_LOCK;
+			*status |= FE_HAS_VITERBI;
+		}
+		break;
+	default:
+		printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __func__);
+	}
+	return 0;
+}
+
+/* Calculate SNR estimation (scaled by 2^24)
+
+   8-VSB SNR equations from LGDT3302 and LGDT3303 datasheets, QAM
+   equations from LGDT3303 datasheet.  VSB is the same between the '02
+   and '03, so maybe QAM is too?  Perhaps someone with a newer datasheet
+   that has QAM information could verify?
+
+   For 8-VSB: (two ways, take your pick)
+   LGDT3302:
+     SNR_EQ = 10 * log10(25 * 24^2 / EQ_MSE)
+   LGDT3303:
+     SNR_EQ = 10 * log10(25 * 32^2 / EQ_MSE)
+   LGDT3302 & LGDT3303:
+     SNR_PT = 10 * log10(25 * 32^2 / PT_MSE)  (we use this one)
+   For 64-QAM:
+     SNR    = 10 * log10( 688128   / MSEQAM)
+   For 256-QAM:
+     SNR    = 10 * log10( 696320   / MSEQAM)
+
+   We re-write the snr equation as:
+     SNR * 2^24 = 10*(c - intlog10(MSE))
+   Where for 256-QAM, c = log10(696320) * 2^24, and so on. */
+
+static u32 calculate_snr(u32 mse, u32 c)
+{
+	if (mse == 0) /* No signal */
+		return 0;
+
+	mse = intlog10(mse);
+	if (mse > c) {
+		/* Negative SNR, which is possible, but realisticly the
+		demod will lose lock before the signal gets this bad.  The
+		API only allows for unsigned values, so just return 0 */
+		return 0;
+	}
+	return 10*(c - mse);
+}
+
+static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
+	u8 buf[5];	/* read data buffer */
+	u32 noise;	/* noise value */
+	u32 c;		/* per-modulation SNR calculation constant */
+
+	switch(state->current_modulation) {
+	case VSB_8:
+		i2c_read_demod_bytes(state, LGDT3302_EQPH_ERR0, buf, 5);
+#ifdef USE_EQMSE
+		/* Use Equalizer Mean-Square Error Register */
+		/* SNR for ranges from -15.61 to +41.58 */
+		noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
+		c = 69765745; /* log10(25*24^2)*2^24 */
+#else
+		/* Use Phase Tracker Mean-Square Error Register */
+		/* SNR for ranges from -13.11 to +44.08 */
+		noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
+		c = 73957994; /* log10(25*32^2)*2^24 */
+#endif
+		break;
+	case QAM_64:
+	case QAM_256:
+		i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
+		noise = ((buf[0] & 3) << 8) | buf[1];
+		c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
+		/* log10(688128)*2^24 and log10(696320)*2^24 */
+		break;
+	default:
+		printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n",
+		       __func__);
+		return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
+	}
+
+	state->snr = calculate_snr(noise, c);
+	*snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
+
+	dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise,
+		state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
+
+	return 0;
+}
+
+static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
+	u8 buf[5];	/* read data buffer */
+	u32 noise;	/* noise value */
+	u32 c;		/* per-modulation SNR calculation constant */
+
+	switch(state->current_modulation) {
+	case VSB_8:
+		i2c_read_demod_bytes(state, LGDT3303_EQPH_ERR0, buf, 5);
+#ifdef USE_EQMSE
+		/* Use Equalizer Mean-Square Error Register */
+		/* SNR for ranges from -16.12 to +44.08 */
+		noise = ((buf[0] & 0x78) << 13) | (buf[1] << 8) | buf[2];
+		c = 73957994; /* log10(25*32^2)*2^24 */
+#else
+		/* Use Phase Tracker Mean-Square Error Register */
+		/* SNR for ranges from -13.11 to +44.08 */
+		noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4];
+		c = 73957994; /* log10(25*32^2)*2^24 */
+#endif
+		break;
+	case QAM_64:
+	case QAM_256:
+		i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
+		noise = (buf[0] << 8) | buf[1];
+		c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
+		/* log10(688128)*2^24 and log10(696320)*2^24 */
+		break;
+	default:
+		printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n",
+		       __func__);
+		return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
+	}
+
+	state->snr = calculate_snr(noise, c);
+	*snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
+
+	dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise,
+		state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
+
+	return 0;
+}
+
+static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	/* Calculate Strength from SNR up to 35dB */
+	/* Even though the SNR can go higher than 35dB, there is some comfort */
+	/* factor in having a range of strong signals that can show at 100%   */
+	struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
+	u16 snr;
+	int ret;
+
+	ret = fe->ops.read_snr(fe, &snr);
+	if (ret != 0)
+		return ret;
+	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
+	/* scale the range 0 - 35*2^24 into 0 - 65535 */
+	if (state->snr >= 8960 * 0x10000)
+		*strength = 0xffff;
+	else
+		*strength = state->snr / 8960;
+
+	return 0;
+}
+
+static int lgdt330x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings)
+{
+	/* I have no idea about this - it may not be needed */
+	fe_tune_settings->min_delay_ms = 500;
+	fe_tune_settings->step_size = 0;
+	fe_tune_settings->max_drift = 0;
+	return 0;
+}
+
+static void lgdt330x_release(struct dvb_frontend* fe)
+{
+	struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops lgdt3302_ops;
+static struct dvb_frontend_ops lgdt3303_ops;
+
+struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
+				     struct i2c_adapter* i2c)
+{
+	struct lgdt330x_state* state = NULL;
+	u8 buf[1];
+
+	/* Allocate memory for the internal state */
+	state = kzalloc(sizeof(struct lgdt330x_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* Setup the state */
+	state->config = config;
+	state->i2c = i2c;
+
+	/* Create dvb_frontend */
+	switch (config->demod_chip) {
+	case LGDT3302:
+		memcpy(&state->frontend.ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
+		break;
+	case LGDT3303:
+		memcpy(&state->frontend.ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops));
+		break;
+	default:
+		goto error;
+	}
+	state->frontend.demodulator_priv = state;
+
+	/* Verify communication with demod chip */
+	if (i2c_read_demod_bytes(state, 2, buf, 1))
+		goto error;
+
+	state->current_frequency = -1;
+	state->current_modulation = -1;
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	dprintk("%s: ERROR\n",__func__);
+	return NULL;
+}
+
+static struct dvb_frontend_ops lgdt3302_ops = {
+	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
+	.info = {
+		.name= "LG Electronics LGDT3302 VSB/QAM Frontend",
+		.frequency_min= 54000000,
+		.frequency_max= 858000000,
+		.frequency_stepsize= 62500,
+		.symbol_rate_min    = 5056941,	/* QAM 64 */
+		.symbol_rate_max    = 10762000,	/* VSB 8  */
+		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+	},
+	.init                 = lgdt330x_init,
+	.set_frontend         = lgdt330x_set_parameters,
+	.get_frontend         = lgdt330x_get_frontend,
+	.get_tune_settings    = lgdt330x_get_tune_settings,
+	.read_status          = lgdt3302_read_status,
+	.read_ber             = lgdt330x_read_ber,
+	.read_signal_strength = lgdt330x_read_signal_strength,
+	.read_snr             = lgdt3302_read_snr,
+	.read_ucblocks        = lgdt330x_read_ucblocks,
+	.release              = lgdt330x_release,
+};
+
+static struct dvb_frontend_ops lgdt3303_ops = {
+	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
+	.info = {
+		.name= "LG Electronics LGDT3303 VSB/QAM Frontend",
+		.frequency_min= 54000000,
+		.frequency_max= 858000000,
+		.frequency_stepsize= 62500,
+		.symbol_rate_min    = 5056941,	/* QAM 64 */
+		.symbol_rate_max    = 10762000,	/* VSB 8  */
+		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+	},
+	.init                 = lgdt330x_init,
+	.set_frontend         = lgdt330x_set_parameters,
+	.get_frontend         = lgdt330x_get_frontend,
+	.get_tune_settings    = lgdt330x_get_tune_settings,
+	.read_status          = lgdt3303_read_status,
+	.read_ber             = lgdt330x_read_ber,
+	.read_signal_strength = lgdt330x_read_signal_strength,
+	.read_snr             = lgdt3303_read_snr,
+	.read_ucblocks        = lgdt330x_read_ucblocks,
+	.release              = lgdt330x_release,
+};
+
+MODULE_DESCRIPTION("LGDT330X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
+MODULE_AUTHOR("Wilson Michaels");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(lgdt330x_attach);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb-frontends/lgdt330x.h b/drivers/media/dvb-frontends/lgdt330x.h
new file mode 100644
index 0000000..9012504
--- /dev/null
+++ b/drivers/media/dvb-frontends/lgdt330x.h
@@ -0,0 +1,73 @@
+/*
+ *    Support for LGDT3302 and LGDT3303 - VSB/QAM
+ *
+ *    Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.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.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef LGDT330X_H
+#define LGDT330X_H
+
+#include <linux/dvb/frontend.h>
+
+typedef enum lg_chip_t {
+		UNDEFINED,
+		LGDT3302,
+		LGDT3303
+}lg_chip_type;
+
+struct lgdt330x_config
+{
+	/* The demodulator's i2c address */
+	u8 demod_address;
+
+	/* LG demodulator chip LGDT3302 or LGDT3303 */
+	lg_chip_type demod_chip;
+
+	/* MPEG hardware interface - 0:parallel 1:serial */
+	int serial_mpeg;
+
+	/* PLL interface */
+	int (*pll_rf_set) (struct dvb_frontend* fe, int index);
+
+	/* Need to set device param for start_dma */
+	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+
+	/* Flip the polarity of the mpeg data transfer clock using alternate init data
+	 * This option applies ONLY to LGDT3303 - 0:disabled (default) 1:enabled */
+	int clock_polarity_flip;
+};
+
+#if defined(CONFIG_DVB_LGDT330X) || (defined(CONFIG_DVB_LGDT330X_MODULE) && defined(MODULE))
+extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
+					    struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
+					    struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_LGDT330X
+
+#endif /* LGDT330X_H */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb-frontends/lgdt330x_priv.h b/drivers/media/dvb-frontends/lgdt330x_priv.h
new file mode 100644
index 0000000..38c7669
--- /dev/null
+++ b/drivers/media/dvb-frontends/lgdt330x_priv.h
@@ -0,0 +1,77 @@
+/*
+ *    Support for LGDT3302 and LGDT3303 - VSB/QAM
+ *
+ *    Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.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.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _LGDT330X_PRIV_
+#define _LGDT330X_PRIV_
+
+/* i2c control register addresses */
+enum I2C_REG {
+	TOP_CONTROL= 0x00,
+	IRQ_MASK= 0x01,
+	IRQ_STATUS= 0x02,
+	VSB_CARRIER_FREQ0= 0x16,
+	VSB_CARRIER_FREQ1= 0x17,
+	VSB_CARRIER_FREQ2= 0x18,
+	VSB_CARRIER_FREQ3= 0x19,
+	CARRIER_MSEQAM1= 0x1a,
+	CARRIER_MSEQAM2= 0x1b,
+	CARRIER_LOCK= 0x1c,
+	TIMING_RECOVERY= 0x1d,
+	AGC_DELAY0= 0x2a,
+	AGC_DELAY1= 0x2b,
+	AGC_DELAY2= 0x2c,
+	AGC_RF_BANDWIDTH0= 0x2d,
+	AGC_RF_BANDWIDTH1= 0x2e,
+	AGC_RF_BANDWIDTH2= 0x2f,
+	AGC_LOOP_BANDWIDTH0= 0x30,
+	AGC_LOOP_BANDWIDTH1= 0x31,
+	AGC_FUNC_CTRL1= 0x32,
+	AGC_FUNC_CTRL2= 0x33,
+	AGC_FUNC_CTRL3= 0x34,
+	AGC_RFIF_ACC0= 0x39,
+	AGC_RFIF_ACC1= 0x3a,
+	AGC_RFIF_ACC2= 0x3b,
+	AGC_STATUS= 0x3f,
+	SYNC_STATUS_VSB= 0x43,
+	DEMUX_CONTROL= 0x66,
+	LGDT3302_EQPH_ERR0= 0x47,
+	LGDT3302_EQ_ERR1= 0x48,
+	LGDT3302_EQ_ERR2= 0x49,
+	LGDT3302_PH_ERR1= 0x4a,
+	LGDT3302_PH_ERR2= 0x4b,
+	LGDT3302_PACKET_ERR_COUNTER1= 0x6a,
+	LGDT3302_PACKET_ERR_COUNTER2= 0x6b,
+	LGDT3303_EQPH_ERR0= 0x6e,
+	LGDT3303_EQ_ERR1= 0x6f,
+	LGDT3303_EQ_ERR2= 0x70,
+	LGDT3303_PH_ERR1= 0x71,
+	LGDT3303_PH_ERR2= 0x72,
+	LGDT3303_PACKET_ERR_COUNTER1= 0x8b,
+	LGDT3303_PACKET_ERR_COUNTER2= 0x8c,
+};
+
+#endif /* _LGDT330X_PRIV_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb-frontends/lgs8gl5.c b/drivers/media/dvb-frontends/lgs8gl5.c
new file mode 100644
index 0000000..416cce3
--- /dev/null
+++ b/drivers/media/dvb-frontends/lgs8gl5.c
@@ -0,0 +1,453 @@
+/*
+    Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
+
+    Copyright (C) 2008 Sirius International (Hong Kong) Limited
+	Timothy Lee <timothy.lee@siriushk.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "dvb_frontend.h"
+#include "lgs8gl5.h"
+
+
+#define REG_RESET		0x02
+#define REG_RESET_OFF			0x01
+#define REG_03			0x03
+#define REG_04			0x04
+#define REG_07			0x07
+#define REG_09			0x09
+#define REG_0A			0x0a
+#define REG_0B			0x0b
+#define REG_0C			0x0c
+#define REG_37			0x37
+#define REG_STRENGTH		0x4b
+#define REG_STRENGTH_MASK		0x7f
+#define REG_STRENGTH_CARRIER		0x80
+#define REG_INVERSION		0x7c
+#define REG_INVERSION_ON		0x80
+#define REG_7D			0x7d
+#define REG_7E			0x7e
+#define REG_A2			0xa2
+#define REG_STATUS		0xa4
+#define REG_STATUS_SYNC		0x04
+#define REG_STATUS_LOCK		0x01
+
+
+struct lgs8gl5_state {
+	struct i2c_adapter *i2c;
+	const struct lgs8gl5_config *config;
+	struct dvb_frontend frontend;
+};
+
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG "lgs8gl5: " args); \
+	} while (0)
+
+
+/* Writes into demod's register */
+static int
+lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf[] = {reg, data};
+	struct i2c_msg msg = {
+		.addr  = state->config->demod_address,
+		.flags = 0,
+		.buf   = buf,
+		.len   = 2
+	};
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+	if (ret != 1)
+		dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n",
+			__func__, reg, data, ret);
+	return (ret != 1) ? -1 : 0;
+}
+
+
+/* Reads from demod's register */
+static int
+lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[] = {reg};
+	u8 b1[] = {0};
+	struct i2c_msg msg[2] = {
+		{
+			.addr  = state->config->demod_address,
+			.flags = 0,
+			.buf   = b0,
+			.len   = 1
+		},
+		{
+			.addr  = state->config->demod_address,
+			.flags = I2C_M_RD,
+			.buf   = b1,
+			.len   = 1
+		}
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+	if (ret != 2)
+		return -EIO;
+
+	return b1[0];
+}
+
+
+static int
+lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
+{
+	lgs8gl5_read_reg(state, reg);
+	lgs8gl5_write_reg(state, reg, data);
+	return 0;
+}
+
+
+/* Writes into alternate device's register */
+/* TODO:  Find out what that device is for! */
+static int
+lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
+{
+	int ret;
+	u8 b0[] = {reg};
+	u8 b1[] = {0};
+	u8 b2[] = {reg, data};
+	struct i2c_msg msg[3] = {
+		{
+			.addr  = state->config->demod_address + 2,
+			.flags = 0,
+			.buf   = b0,
+			.len   = 1
+		},
+		{
+			.addr  = state->config->demod_address + 2,
+			.flags = I2C_M_RD,
+			.buf   = b1,
+			.len   = 1
+		},
+		{
+			.addr  = state->config->demod_address + 2,
+			.flags = 0,
+			.buf   = b2,
+			.len   = 2
+		},
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 3);
+	return (ret != 3) ? -1 : 0;
+}
+
+
+static void
+lgs8gl5_soft_reset(struct lgs8gl5_state *state)
+{
+	u8 val;
+
+	dprintk("%s\n", __func__);
+
+	val = lgs8gl5_read_reg(state, REG_RESET);
+	lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF);
+	lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF);
+	msleep(5);
+}
+
+
+/* Starts demodulation */
+static void
+lgs8gl5_start_demod(struct lgs8gl5_state *state)
+{
+	u8  val;
+	int n;
+
+	dprintk("%s\n", __func__);
+
+	lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
+	lgs8gl5_soft_reset(state);
+	lgs8gl5_update_reg(state, REG_07, 0x10);
+	lgs8gl5_update_reg(state, REG_07, 0x10);
+	lgs8gl5_write_reg(state, REG_09, 0x0e);
+	lgs8gl5_write_reg(state, REG_0A, 0xe5);
+	lgs8gl5_write_reg(state, REG_0B, 0x35);
+	lgs8gl5_write_reg(state, REG_0C, 0x30);
+
+	lgs8gl5_update_reg(state, REG_03, 0x00);
+	lgs8gl5_update_reg(state, REG_7E, 0x01);
+	lgs8gl5_update_alt_reg(state, 0xc5, 0x00);
+	lgs8gl5_update_reg(state, REG_04, 0x02);
+	lgs8gl5_update_reg(state, REG_37, 0x01);
+	lgs8gl5_soft_reset(state);
+
+	/* Wait for carrier */
+	for (n = 0;  n < 10;  n++) {
+		val = lgs8gl5_read_reg(state, REG_STRENGTH);
+		dprintk("Wait for carrier[%d] 0x%02X\n", n, val);
+		if (val & REG_STRENGTH_CARRIER)
+			break;
+		msleep(4);
+	}
+	if (!(val & REG_STRENGTH_CARRIER))
+		return;
+
+	/* Wait for lock */
+	for (n = 0;  n < 20;  n++) {
+		val = lgs8gl5_read_reg(state, REG_STATUS);
+		dprintk("Wait for lock[%d] 0x%02X\n", n, val);
+		if (val & REG_STATUS_LOCK)
+			break;
+		msleep(12);
+	}
+	if (!(val & REG_STATUS_LOCK))
+		return;
+
+	lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2));
+	lgs8gl5_soft_reset(state);
+}
+
+
+static int
+lgs8gl5_init(struct dvb_frontend *fe)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
+	lgs8gl5_soft_reset(state);
+	lgs8gl5_update_reg(state, REG_07, 0x10);
+	lgs8gl5_update_reg(state, REG_07, 0x10);
+	lgs8gl5_write_reg(state, REG_09, 0x0e);
+	lgs8gl5_write_reg(state, REG_0A, 0xe5);
+	lgs8gl5_write_reg(state, REG_0B, 0x35);
+	lgs8gl5_write_reg(state, REG_0C, 0x30);
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+	u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+	u8 flags = lgs8gl5_read_reg(state, REG_STATUS);
+
+	*status = 0;
+
+	if ((level & REG_STRENGTH_MASK) > 0)
+		*status |= FE_HAS_SIGNAL;
+	if (level & REG_STRENGTH_CARRIER)
+		*status |= FE_HAS_CARRIER;
+	if (flags & REG_STATUS_SYNC)
+		*status |= FE_HAS_SYNC;
+	if (flags & REG_STATUS_LOCK)
+		*status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	*ber = 0;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+	u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+	*signal_strength = (level & REG_STRENGTH_MASK) << 8;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+	u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+	*snr = (level & REG_STRENGTH_MASK) << 8;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	*ucblocks = 0;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	if (p->bandwidth_hz != 8000000)
+		return -EINVAL;
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	/* lgs8gl5_set_inversion(state, p->inversion); */
+
+	lgs8gl5_start_demod(state);
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+	u8 inv = lgs8gl5_read_reg(state, REG_INVERSION);
+
+	p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF;
+
+	p->code_rate_HP = FEC_1_2;
+	p->code_rate_LP = FEC_7_8;
+	p->guard_interval = GUARD_INTERVAL_1_32;
+	p->transmission_mode = TRANSMISSION_MODE_2K;
+	p->modulation = QAM_64;
+	p->hierarchy = HIERARCHY_NONE;
+	p->bandwidth_hz = 8000000;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_get_tune_settings(struct dvb_frontend *fe,
+		struct dvb_frontend_tune_settings *fesettings)
+{
+	fesettings->min_delay_ms = 240;
+	fesettings->step_size    = 0;
+	fesettings->max_drift    = 0;
+	return 0;
+}
+
+
+static void
+lgs8gl5_release(struct dvb_frontend *fe)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+
+static struct dvb_frontend_ops lgs8gl5_ops;
+
+
+struct dvb_frontend*
+lgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c)
+{
+	struct lgs8gl5_state *state = NULL;
+
+	dprintk("%s\n", __func__);
+
+	/* Allocate memory for the internal state */
+	state = kzalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* Setup the state */
+	state->config = config;
+	state->i2c    = i2c;
+
+	/* Check if the demod is there */
+	if (lgs8gl5_read_reg(state, REG_RESET) < 0)
+		goto error;
+
+	/* Create dvb_frontend */
+	memcpy(&state->frontend.ops, &lgs8gl5_ops,
+		sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(lgs8gl5_attach);
+
+
+static struct dvb_frontend_ops lgs8gl5_ops = {
+	.delsys = { SYS_DTMB },
+	.info = {
+		.name			= "Legend Silicon LGS-8GL5 DMB-TH",
+		.frequency_min		= 474000000,
+		.frequency_max		= 858000000,
+		.frequency_stepsize	= 10000,
+		.frequency_tolerance	= 0,
+		.caps = FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
+			FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_BANDWIDTH_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_RECOVER
+	},
+
+	.release = lgs8gl5_release,
+
+	.init = lgs8gl5_init,
+
+	.set_frontend = lgs8gl5_set_frontend,
+	.get_frontend = lgs8gl5_get_frontend,
+	.get_tune_settings = lgs8gl5_get_tune_settings,
+
+	.read_status = lgs8gl5_read_status,
+	.read_ber = lgs8gl5_read_ber,
+	.read_signal_strength = lgs8gl5_read_signal_strength,
+	.read_snr = lgs8gl5_read_snr,
+	.read_ucblocks = lgs8gl5_read_ucblocks,
+};
+
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver");
+MODULE_AUTHOR("Timothy Lee");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/lgs8gl5.h b/drivers/media/dvb-frontends/lgs8gl5.h
new file mode 100644
index 0000000..d1417678
--- /dev/null
+++ b/drivers/media/dvb-frontends/lgs8gl5.h
@@ -0,0 +1,45 @@
+/*
+    Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
+
+    Copyright (C) 2008 Sirius International (Hong Kong) Limited
+	Timothy Lee <timothy.lee@siriushk.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef LGS8GL5_H
+#define LGS8GL5_H
+
+#include <linux/dvb/frontend.h>
+
+struct lgs8gl5_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+};
+
+#if defined(CONFIG_DVB_LGS8GL5) || \
+	(defined(CONFIG_DVB_LGS8GL5_MODULE) && defined(MODULE))
+extern struct dvb_frontend *lgs8gl5_attach(
+	const struct lgs8gl5_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *lgs8gl5_attach(
+	const struct lgs8gl5_config *config, struct i2c_adapter *i2c) {
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_LGS8GL5 */
+
+#endif /* LGS8GL5_H */
diff --git a/drivers/media/dvb-frontends/lgs8gxx.c b/drivers/media/dvb-frontends/lgs8gxx.c
new file mode 100644
index 0000000..3c92f36
--- /dev/null
+++ b/drivers/media/dvb-frontends/lgs8gxx.c
@@ -0,0 +1,1075 @@
+/*
+ *    Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
+ *    LGS8913, LGS8GL5, LGS8G75
+ *    experimental support LGS8G42, LGS8G52
+ *
+ *    Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
+ *    Copyright (C) 2008 Sirius International (Hong Kong) Limited
+ *    Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <asm/div64.h>
+#include <linux/firmware.h>
+
+#include "dvb_frontend.h"
+
+#include "lgs8gxx.h"
+#include "lgs8gxx_priv.h"
+
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG "lgs8gxx: " args); \
+	} while (0)
+
+static int debug;
+static int fake_signal_str = 1;
+
+#define LGS8GXX_FIRMWARE "lgs8g75.fw"
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+module_param(fake_signal_str, int, 0644);
+MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
+"Signal strength calculation is slow.(default:on).");
+
+/* LGS8GXX internal helper functions */
+
+static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
+
+	msg.addr = priv->config->demod_address;
+	if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
+		msg.addr += 0x02;
+
+	if (debug >= 2)
+		dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data);
+
+	ret = i2c_transfer(priv->i2c, &msg, 1);
+
+	if (ret != 1)
+		dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
+			__func__, reg, data, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+
+static int lgs8gxx_read_reg(struct lgs8gxx_state *priv, u8 reg, u8 *p_data)
+{
+	int ret;
+	u8 dev_addr;
+
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{ .flags = 0, .buf = b0, .len = 1 },
+		{ .flags = I2C_M_RD, .buf = b1, .len = 1 },
+	};
+
+	dev_addr = priv->config->demod_address;
+	if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
+		dev_addr += 0x02;
+	msg[1].addr =  msg[0].addr = dev_addr;
+
+	ret = i2c_transfer(priv->i2c, msg, 2);
+	if (ret != 2) {
+		dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret);
+		return -1;
+	}
+
+	*p_data = b1[0];
+	if (debug >= 2)
+		dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, b1[0]);
+	return 0;
+}
+
+static int lgs8gxx_soft_reset(struct lgs8gxx_state *priv)
+{
+	lgs8gxx_write_reg(priv, 0x02, 0x00);
+	msleep(1);
+	lgs8gxx_write_reg(priv, 0x02, 0x01);
+	msleep(100);
+
+	return 0;
+}
+
+static int wait_reg_mask(struct lgs8gxx_state *priv, u8 reg, u8 mask,
+	u8 val, u8 delay, u8 tries)
+{
+	u8 t;
+	int i;
+
+	for (i = 0; i < tries; i++) {
+		lgs8gxx_read_reg(priv, reg, &t);
+
+		if ((t & mask) == val)
+			return 0;
+		msleep(delay);
+	}
+
+	return 1;
+}
+
+static int lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv)
+{
+	const struct lgs8gxx_config *config = priv->config;
+	u8 if_conf;
+
+	if_conf = 0x10; /* AGC output on, RF_AGC output off; */
+
+	if_conf |=
+		((config->ext_adc) ? 0x80 : 0x00) |
+		((config->if_neg_center) ? 0x04 : 0x00) |
+		((config->if_freq == 0) ? 0x08 : 0x00) | /* Baseband */
+		((config->adc_signed) ? 0x02 : 0x00) |
+		((config->if_neg_edge) ? 0x01 : 0x00);
+
+	if (config->ext_adc &&
+		(config->prod == LGS8GXX_PROD_LGS8G52)) {
+		lgs8gxx_write_reg(priv, 0xBA, 0x40);
+	}
+
+	lgs8gxx_write_reg(priv, 0x07, if_conf);
+
+	return 0;
+}
+
+static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/)
+{
+	u64 val;
+	u32 v32;
+	u32 if_clk;
+
+	if_clk = priv->config->if_clk_freq;
+
+	val = freq;
+	if (freq != 0) {
+		val <<= 32;
+		if (if_clk != 0)
+			do_div(val, if_clk);
+		v32 = val & 0xFFFFFFFF;
+		dprintk("Set IF Freq to %dkHz\n", freq);
+	} else {
+		v32 = 0;
+		dprintk("Set IF Freq to baseband\n");
+	}
+	dprintk("AFC_INIT_FREQ = 0x%08X\n", v32);
+
+	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+		lgs8gxx_write_reg(priv, 0x08, 0xFF & (v32));
+		lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32 >> 8));
+		lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 16));
+		lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 24));
+	} else {
+		lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32));
+		lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8));
+		lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16));
+		lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24));
+	}
+
+	return 0;
+}
+
+static int lgs8gxx_get_afc_phase(struct lgs8gxx_state *priv)
+{
+	u64 val;
+	u32 v32 = 0;
+	u8 reg_addr, t;
+	int i;
+
+	if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+		reg_addr = 0x23;
+	else
+		reg_addr = 0x48;
+
+	for (i = 0; i < 4; i++) {
+		lgs8gxx_read_reg(priv, reg_addr, &t);
+		v32 <<= 8;
+		v32 |= t;
+		reg_addr--;
+	}
+
+	val = v32;
+	val *= priv->config->if_clk_freq;
+	val >>= 32;
+	dprintk("AFC = %u kHz\n", (u32)val);
+	return 0;
+}
+
+static int lgs8gxx_set_mode_auto(struct lgs8gxx_state *priv)
+{
+	u8 t;
+	u8 prod = priv->config->prod;
+
+	if (prod == LGS8GXX_PROD_LGS8913)
+		lgs8gxx_write_reg(priv, 0xC6, 0x01);
+
+	if (prod == LGS8GXX_PROD_LGS8G75) {
+		lgs8gxx_read_reg(priv, 0x0C, &t);
+		t &= (~0x04);
+		lgs8gxx_write_reg(priv, 0x0C, t | 0x80);
+		lgs8gxx_write_reg(priv, 0x39, 0x00);
+		lgs8gxx_write_reg(priv, 0x3D, 0x04);
+	} else if (prod == LGS8GXX_PROD_LGS8913 ||
+		prod == LGS8GXX_PROD_LGS8GL5 ||
+		prod == LGS8GXX_PROD_LGS8G42 ||
+		prod == LGS8GXX_PROD_LGS8G52 ||
+		prod == LGS8GXX_PROD_LGS8G54) {
+		lgs8gxx_read_reg(priv, 0x7E, &t);
+		lgs8gxx_write_reg(priv, 0x7E, t | 0x01);
+
+		/* clear FEC self reset */
+		lgs8gxx_read_reg(priv, 0xC5, &t);
+		lgs8gxx_write_reg(priv, 0xC5, t & 0xE0);
+	}
+
+	if (prod == LGS8GXX_PROD_LGS8913) {
+		/* FEC auto detect */
+		lgs8gxx_write_reg(priv, 0xC1, 0x03);
+
+		lgs8gxx_read_reg(priv, 0x7C, &t);
+		t = (t & 0x8C) | 0x03;
+		lgs8gxx_write_reg(priv, 0x7C, t);
+
+		/* BER test mode */
+		lgs8gxx_read_reg(priv, 0xC3, &t);
+		t = (t & 0xEF) |  0x10;
+		lgs8gxx_write_reg(priv, 0xC3, t);
+	}
+
+	if (priv->config->prod == LGS8GXX_PROD_LGS8G52)
+		lgs8gxx_write_reg(priv, 0xD9, 0x40);
+
+	return 0;
+}
+
+static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv)
+{
+	u8 t;
+
+	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+		u8 t2;
+		lgs8gxx_read_reg(priv, 0x0C, &t);
+		t &= (~0x80);
+		lgs8gxx_write_reg(priv, 0x0C, t);
+
+		lgs8gxx_read_reg(priv, 0x0C, &t);
+		lgs8gxx_read_reg(priv, 0x19, &t2);
+
+		if (((t&0x03) == 0x01) && (t2&0x01)) {
+			lgs8gxx_write_reg(priv, 0x6E, 0x05);
+			lgs8gxx_write_reg(priv, 0x39, 0x02);
+			lgs8gxx_write_reg(priv, 0x39, 0x03);
+			lgs8gxx_write_reg(priv, 0x3D, 0x05);
+			lgs8gxx_write_reg(priv, 0x3E, 0x28);
+			lgs8gxx_write_reg(priv, 0x53, 0x80);
+		} else {
+			lgs8gxx_write_reg(priv, 0x6E, 0x3F);
+			lgs8gxx_write_reg(priv, 0x39, 0x00);
+			lgs8gxx_write_reg(priv, 0x3D, 0x04);
+		}
+
+		lgs8gxx_soft_reset(priv);
+		return 0;
+	}
+
+	/* turn off auto-detect; manual settings */
+	lgs8gxx_write_reg(priv, 0x7E, 0);
+	if (priv->config->prod == LGS8GXX_PROD_LGS8913)
+		lgs8gxx_write_reg(priv, 0xC1, 0);
+
+	lgs8gxx_read_reg(priv, 0xC5, &t);
+	t = (t & 0xE0) | 0x06;
+	lgs8gxx_write_reg(priv, 0xC5, t);
+
+	lgs8gxx_soft_reset(priv);
+
+	return 0;
+}
+
+static int lgs8gxx_is_locked(struct lgs8gxx_state *priv, u8 *locked)
+{
+	int ret = 0;
+	u8 t;
+
+	if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+		ret = lgs8gxx_read_reg(priv, 0x13, &t);
+	else
+		ret = lgs8gxx_read_reg(priv, 0x4B, &t);
+	if (ret != 0)
+		return ret;
+
+	if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+		*locked = ((t & 0x80) == 0x80) ? 1 : 0;
+	else
+		*locked = ((t & 0xC0) == 0xC0) ? 1 : 0;
+	return 0;
+}
+
+/* Wait for Code Acquisition Lock */
+static int lgs8gxx_wait_ca_lock(struct lgs8gxx_state *priv, u8 *locked)
+{
+	int ret = 0;
+	u8 reg, mask, val;
+
+	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+		reg = 0x13;
+		mask = 0x80;
+		val = 0x80;
+	} else {
+		reg = 0x4B;
+		mask = 0xC0;
+		val = 0xC0;
+	}
+
+	ret = wait_reg_mask(priv, reg, mask, val, 50, 40);
+	*locked = (ret == 0) ? 1 : 0;
+
+	return 0;
+}
+
+static int lgs8gxx_is_autodetect_finished(struct lgs8gxx_state *priv,
+					  u8 *finished)
+{
+	int ret = 0;
+	u8 reg, mask, val;
+
+	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+		reg = 0x1f;
+		mask = 0xC0;
+		val = 0x80;
+	} else {
+		reg = 0xA4;
+		mask = 0x03;
+		val = 0x01;
+	}
+
+	ret = wait_reg_mask(priv, reg, mask, val, 10, 20);
+	*finished = (ret == 0) ? 1 : 0;
+
+	return 0;
+}
+
+static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 cpn,
+	u8 *locked)
+{
+	int err = 0;
+	u8 ad_fini = 0;
+	u8 t1, t2;
+
+	if (gi == GI_945)
+		dprintk("try GI 945\n");
+	else if (gi == GI_595)
+		dprintk("try GI 595\n");
+	else if (gi == GI_420)
+		dprintk("try GI 420\n");
+	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+		lgs8gxx_read_reg(priv, 0x0C, &t1);
+		lgs8gxx_read_reg(priv, 0x18, &t2);
+		t1 &= ~(GI_MASK);
+		t1 |= gi;
+		t2 &= 0xFE;
+		t2 |= cpn ? 0x01 : 0x00;
+		lgs8gxx_write_reg(priv, 0x0C, t1);
+		lgs8gxx_write_reg(priv, 0x18, t2);
+	} else {
+		lgs8gxx_write_reg(priv, 0x04, gi);
+	}
+	lgs8gxx_soft_reset(priv);
+	err = lgs8gxx_wait_ca_lock(priv, locked);
+	if (err || !(*locked))
+		return err;
+	err = lgs8gxx_is_autodetect_finished(priv, &ad_fini);
+	if (err != 0)
+		return err;
+	if (ad_fini) {
+		dprintk("auto detect finished\n");
+	} else
+		*locked = 0;
+
+	return 0;
+}
+
+static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv,
+			       u8 *detected_param, u8 *gi)
+{
+	int i, j;
+	int err = 0;
+	u8 locked = 0, tmp_gi;
+
+	dprintk("%s\n", __func__);
+
+	lgs8gxx_set_mode_auto(priv);
+	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+		lgs8gxx_write_reg(priv, 0x67, 0xAA);
+		lgs8gxx_write_reg(priv, 0x6E, 0x3F);
+	} else {
+		/* Guard Interval */
+		lgs8gxx_write_reg(priv, 0x03, 00);
+	}
+
+	for (i = 0; i < 2; i++) {
+		for (j = 0; j < 2; j++) {
+			tmp_gi = GI_945;
+			err = lgs8gxx_autolock_gi(priv, GI_945, j, &locked);
+			if (err)
+				goto out;
+			if (locked)
+				goto locked;
+		}
+		for (j = 0; j < 2; j++) {
+			tmp_gi = GI_420;
+			err = lgs8gxx_autolock_gi(priv, GI_420, j, &locked);
+			if (err)
+				goto out;
+			if (locked)
+				goto locked;
+		}
+		tmp_gi = GI_595;
+		err = lgs8gxx_autolock_gi(priv, GI_595, 1, &locked);
+		if (err)
+			goto out;
+		if (locked)
+			goto locked;
+	}
+
+locked:
+	if ((err == 0) && (locked == 1)) {
+		u8 t;
+
+		if (priv->config->prod != LGS8GXX_PROD_LGS8G75) {
+			lgs8gxx_read_reg(priv, 0xA2, &t);
+			*detected_param = t;
+		} else {
+			lgs8gxx_read_reg(priv, 0x1F, &t);
+			*detected_param = t & 0x3F;
+		}
+
+		if (tmp_gi == GI_945)
+			dprintk("GI 945 locked\n");
+		else if (tmp_gi == GI_595)
+			dprintk("GI 595 locked\n");
+		else if (tmp_gi == GI_420)
+			dprintk("GI 420 locked\n");
+		*gi = tmp_gi;
+	}
+	if (!locked)
+		err = -1;
+
+out:
+	return err;
+}
+
+static void lgs8gxx_auto_lock(struct lgs8gxx_state *priv)
+{
+	s8 err;
+	u8 gi = 0x2;
+	u8 detected_param = 0;
+
+	err = lgs8gxx_auto_detect(priv, &detected_param, &gi);
+
+	if (err != 0) {
+		dprintk("lgs8gxx_auto_detect failed\n");
+	} else
+		dprintk("detected param = 0x%02X\n", detected_param);
+
+	/* Apply detected parameters */
+	if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
+		u8 inter_leave_len = detected_param & TIM_MASK ;
+		/* Fix 8913 time interleaver detection bug */
+		inter_leave_len = (inter_leave_len == TIM_MIDDLE) ? 0x60 : 0x40;
+		detected_param &= CF_MASK | SC_MASK  | LGS_FEC_MASK;
+		detected_param |= inter_leave_len;
+	}
+	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+		u8 t;
+		lgs8gxx_read_reg(priv, 0x19, &t);
+		t &= 0x81;
+		t |= detected_param << 1;
+		lgs8gxx_write_reg(priv, 0x19, t);
+	} else {
+		lgs8gxx_write_reg(priv, 0x7D, detected_param);
+		if (priv->config->prod == LGS8GXX_PROD_LGS8913)
+			lgs8gxx_write_reg(priv, 0xC0, detected_param);
+	}
+	/* lgs8gxx_soft_reset(priv); */
+
+	/* Enter manual mode */
+	lgs8gxx_set_mode_manual(priv);
+
+	switch (gi) {
+	case GI_945:
+		priv->curr_gi = 945; break;
+	case GI_595:
+		priv->curr_gi = 595; break;
+	case GI_420:
+		priv->curr_gi = 420; break;
+	default:
+		priv->curr_gi = 945; break;
+	}
+}
+
+static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv,
+	u8 serial, u8 clk_pol, u8 clk_gated)
+{
+	int ret = 0;
+	u8 t, reg_addr;
+
+	reg_addr = (priv->config->prod == LGS8GXX_PROD_LGS8G75) ? 0x30 : 0xC2;
+	ret = lgs8gxx_read_reg(priv, reg_addr, &t);
+	if (ret != 0)
+		return ret;
+
+	t &= 0xF8;
+	t |= serial ? TS_SERIAL : TS_PARALLEL;
+	t |= clk_pol ? TS_CLK_INVERTED : TS_CLK_NORMAL;
+	t |= clk_gated ? TS_CLK_GATED : TS_CLK_FREERUN;
+
+	ret = lgs8gxx_write_reg(priv, reg_addr, t);
+	if (ret != 0)
+		return ret;
+
+	return 0;
+}
+
+/* A/D input peak-to-peak voltage range */
+static int lgs8g75_set_adc_vpp(struct lgs8gxx_state *priv,
+	u8 sel)
+{
+	u8 r26 = 0x73, r27 = 0x90;
+
+	if (priv->config->prod != LGS8GXX_PROD_LGS8G75)
+		return 0;
+
+	r26 |= (sel & 0x01) << 7;
+	r27 |= (sel & 0x02) >> 1;
+	lgs8gxx_write_reg(priv, 0x26, r26);
+	lgs8gxx_write_reg(priv, 0x27, r27);
+
+	return 0;
+}
+
+/* LGS8913 demod frontend functions */
+
+static int lgs8913_init(struct lgs8gxx_state *priv)
+{
+	u8 t;
+
+	/* LGS8913 specific */
+	lgs8gxx_write_reg(priv, 0xc1, 0x3);
+
+	lgs8gxx_read_reg(priv, 0x7c, &t);
+	lgs8gxx_write_reg(priv, 0x7c, (t&0x8c) | 0x3);
+
+	/* LGS8913 specific */
+	lgs8gxx_read_reg(priv, 0xc3, &t);
+	lgs8gxx_write_reg(priv, 0xc3, t&0x10);
+
+
+	return 0;
+}
+
+static int lgs8g75_init_data(struct lgs8gxx_state *priv)
+{
+	const struct firmware *fw;
+	int rc;
+	int i;
+
+	rc = request_firmware(&fw, LGS8GXX_FIRMWARE, &priv->i2c->dev);
+	if (rc)
+		return rc;
+
+	lgs8gxx_write_reg(priv, 0xC6, 0x40);
+
+	lgs8gxx_write_reg(priv, 0x3D, 0x04);
+	lgs8gxx_write_reg(priv, 0x39, 0x00);
+
+	lgs8gxx_write_reg(priv, 0x3A, 0x00);
+	lgs8gxx_write_reg(priv, 0x38, 0x00);
+	lgs8gxx_write_reg(priv, 0x3B, 0x00);
+	lgs8gxx_write_reg(priv, 0x38, 0x00);
+
+	for (i = 0; i < fw->size; i++) {
+		lgs8gxx_write_reg(priv, 0x38, 0x00);
+		lgs8gxx_write_reg(priv, 0x3A, (u8)(i&0xff));
+		lgs8gxx_write_reg(priv, 0x3B, (u8)(i>>8));
+		lgs8gxx_write_reg(priv, 0x3C, fw->data[i]);
+	}
+
+	lgs8gxx_write_reg(priv, 0x38, 0x00);
+
+	release_firmware(fw);
+	return 0;
+}
+
+static int lgs8gxx_init(struct dvb_frontend *fe)
+{
+	struct lgs8gxx_state *priv =
+		(struct lgs8gxx_state *)fe->demodulator_priv;
+	const struct lgs8gxx_config *config = priv->config;
+	u8 data = 0;
+	s8 err;
+	dprintk("%s\n", __func__);
+
+	lgs8gxx_read_reg(priv, 0, &data);
+	dprintk("reg 0 = 0x%02X\n", data);
+
+	if (config->prod == LGS8GXX_PROD_LGS8G75)
+		lgs8g75_set_adc_vpp(priv, config->adc_vpp);
+
+	/* Setup MPEG output format */
+	err = lgs8gxx_set_mpeg_mode(priv, config->serial_ts,
+				    config->ts_clk_pol,
+				    config->ts_clk_gated);
+	if (err != 0)
+		return -EIO;
+
+	if (config->prod == LGS8GXX_PROD_LGS8913)
+		lgs8913_init(priv);
+	lgs8gxx_set_if_freq(priv, priv->config->if_freq);
+	lgs8gxx_set_ad_mode(priv);
+
+	return 0;
+}
+
+static void lgs8gxx_release(struct dvb_frontend *fe)
+{
+	struct lgs8gxx_state *state = fe->demodulator_priv;
+	dprintk("%s\n", __func__);
+
+	kfree(state);
+}
+
+
+static int lgs8gxx_write(struct dvb_frontend *fe, const u8 buf[], int len)
+{
+	struct lgs8gxx_state *priv = fe->demodulator_priv;
+
+	if (len != 2)
+		return -EINVAL;
+
+	return lgs8gxx_write_reg(priv, buf[0], buf[1]);
+}
+
+static int lgs8gxx_set_fe(struct dvb_frontend *fe)
+{
+
+	struct lgs8gxx_state *priv = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	/* set frequency */
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	/* start auto lock */
+	lgs8gxx_auto_lock(priv);
+
+	msleep(10);
+
+	return 0;
+}
+
+static int lgs8gxx_get_fe(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
+	dprintk("%s\n", __func__);
+
+	/* TODO: get real readings from device */
+	/* inversion status */
+	fe_params->inversion = INVERSION_OFF;
+
+	/* bandwidth */
+	fe_params->bandwidth_hz = 8000000;
+
+	fe_params->code_rate_HP = FEC_AUTO;
+	fe_params->code_rate_LP = FEC_AUTO;
+
+	fe_params->modulation = QAM_AUTO;
+
+	/* transmission mode */
+	fe_params->transmission_mode = TRANSMISSION_MODE_AUTO;
+
+	/* guard interval */
+	fe_params->guard_interval = GUARD_INTERVAL_AUTO;
+
+	/* hierarchy */
+	fe_params->hierarchy = HIERARCHY_NONE;
+
+	return 0;
+}
+
+static
+int lgs8gxx_get_tune_settings(struct dvb_frontend *fe,
+			      struct dvb_frontend_tune_settings *fesettings)
+{
+	/* FIXME: copy from tda1004x.c */
+	fesettings->min_delay_ms = 800;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+	return 0;
+}
+
+static int lgs8gxx_read_status(struct dvb_frontend *fe, fe_status_t *fe_status)
+{
+	struct lgs8gxx_state *priv = fe->demodulator_priv;
+	s8 ret;
+	u8 t, locked = 0;
+
+	dprintk("%s\n", __func__);
+	*fe_status = 0;
+
+	lgs8gxx_get_afc_phase(priv);
+	lgs8gxx_is_locked(priv, &locked);
+	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+		if (locked)
+			*fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+		return 0;
+	}
+
+	ret = lgs8gxx_read_reg(priv, 0x4B, &t);
+	if (ret != 0)
+		return -EIO;
+
+	dprintk("Reg 0x4B: 0x%02X\n", t);
+
+	*fe_status = 0;
+	if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
+		if ((t & 0x40) == 0x40)
+			*fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+		if ((t & 0x80) == 0x80)
+			*fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC |
+				FE_HAS_LOCK;
+	} else {
+		if ((t & 0x80) == 0x80)
+			*fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+	}
+
+	/* success */
+	dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
+	return 0;
+}
+
+static int lgs8gxx_read_signal_agc(struct lgs8gxx_state *priv, u16 *signal)
+{
+	u16 v;
+	u8 agc_lvl[2], cat;
+
+	dprintk("%s()\n", __func__);
+	lgs8gxx_read_reg(priv, 0x3F, &agc_lvl[0]);
+	lgs8gxx_read_reg(priv, 0x3E, &agc_lvl[1]);
+
+	v = agc_lvl[0];
+	v <<= 8;
+	v |= agc_lvl[1];
+
+	dprintk("agc_lvl: 0x%04X\n", v);
+
+	if (v < 0x100)
+		cat = 0;
+	else if (v < 0x190)
+		cat = 5;
+	else if (v < 0x2A8)
+		cat = 4;
+	else if (v < 0x381)
+		cat = 3;
+	else if (v < 0x400)
+		cat = 2;
+	else if (v == 0x400)
+		cat = 1;
+	else
+		cat = 0;
+
+	*signal = cat * 65535 / 5;
+
+	return 0;
+}
+
+static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
+{
+	u8 t; s8 ret;
+	s16 max_strength = 0;
+	u8 str;
+	u16 i, gi = priv->curr_gi;
+
+	dprintk("%s\n", __func__);
+
+	ret = lgs8gxx_read_reg(priv, 0x4B, &t);
+	if (ret != 0)
+		return -EIO;
+
+	if (fake_signal_str) {
+		if ((t & 0xC0) == 0xC0) {
+			dprintk("Fake signal strength\n");
+			*signal = 0x7FFF;
+		} else
+			*signal = 0;
+		return 0;
+	}
+
+	dprintk("gi = %d\n", gi);
+	for (i = 0; i < gi; i++) {
+
+		if ((i & 0xFF) == 0)
+			lgs8gxx_write_reg(priv, 0x84, 0x03 & (i >> 8));
+		lgs8gxx_write_reg(priv, 0x83, i & 0xFF);
+
+		lgs8gxx_read_reg(priv, 0x94, &str);
+		if (max_strength < str)
+			max_strength = str;
+	}
+
+	*signal = max_strength;
+	dprintk("%s: signal=0x%02X\n", __func__, *signal);
+
+	lgs8gxx_read_reg(priv, 0x95, &t);
+	dprintk("%s: AVG Noise=0x%02X\n", __func__, t);
+
+	return 0;
+}
+
+static int lgs8g75_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
+{
+	u8 t;
+	s16 v = 0;
+
+	dprintk("%s\n", __func__);
+
+	lgs8gxx_read_reg(priv, 0xB1, &t);
+	v |= t;
+	v <<= 8;
+	lgs8gxx_read_reg(priv, 0xB0, &t);
+	v |= t;
+
+	*signal = v;
+	dprintk("%s: signal=0x%02X\n", __func__, *signal);
+
+	return 0;
+}
+
+static int lgs8gxx_read_signal_strength(struct dvb_frontend *fe, u16 *signal)
+{
+	struct lgs8gxx_state *priv = fe->demodulator_priv;
+
+	if (priv->config->prod == LGS8GXX_PROD_LGS8913)
+		return lgs8913_read_signal_strength(priv, signal);
+	else if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+		return lgs8g75_read_signal_strength(priv, signal);
+	else
+		return lgs8gxx_read_signal_agc(priv, signal);
+}
+
+static int lgs8gxx_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct lgs8gxx_state *priv = fe->demodulator_priv;
+	u8 t;
+	*snr = 0;
+
+	if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+		lgs8gxx_read_reg(priv, 0x34, &t);
+	else
+		lgs8gxx_read_reg(priv, 0x95, &t);
+	dprintk("AVG Noise=0x%02X\n", t);
+	*snr = 256 - t;
+	*snr <<= 8;
+	dprintk("snr=0x%x\n", *snr);
+
+	return 0;
+}
+
+static int lgs8gxx_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	*ucblocks = 0;
+	dprintk("%s: ucblocks=0x%x\n", __func__, *ucblocks);
+	return 0;
+}
+
+static void packet_counter_start(struct lgs8gxx_state *priv)
+{
+	u8 orig, t;
+
+	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+		lgs8gxx_read_reg(priv, 0x30, &orig);
+		orig &= 0xE7;
+		t = orig | 0x10;
+		lgs8gxx_write_reg(priv, 0x30, t);
+		t = orig | 0x18;
+		lgs8gxx_write_reg(priv, 0x30, t);
+		t = orig | 0x10;
+		lgs8gxx_write_reg(priv, 0x30, t);
+	} else {
+		lgs8gxx_write_reg(priv, 0xC6, 0x01);
+		lgs8gxx_write_reg(priv, 0xC6, 0x41);
+		lgs8gxx_write_reg(priv, 0xC6, 0x01);
+	}
+}
+
+static void packet_counter_stop(struct lgs8gxx_state *priv)
+{
+	u8 t;
+
+	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+		lgs8gxx_read_reg(priv, 0x30, &t);
+		t &= 0xE7;
+		lgs8gxx_write_reg(priv, 0x30, t);
+	} else {
+		lgs8gxx_write_reg(priv, 0xC6, 0x81);
+	}
+}
+
+static int lgs8gxx_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct lgs8gxx_state *priv = fe->demodulator_priv;
+	u8 reg_err, reg_total, t;
+	u32 total_cnt = 0, err_cnt = 0;
+	int i;
+
+	dprintk("%s\n", __func__);
+
+	packet_counter_start(priv);
+	msleep(200);
+	packet_counter_stop(priv);
+
+	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+		reg_total = 0x28; reg_err = 0x2C;
+	} else {
+		reg_total = 0xD0; reg_err = 0xD4;
+	}
+
+	for (i = 0; i < 4; i++) {
+		total_cnt <<= 8;
+		lgs8gxx_read_reg(priv, reg_total+3-i, &t);
+		total_cnt |= t;
+	}
+	for (i = 0; i < 4; i++) {
+		err_cnt <<= 8;
+		lgs8gxx_read_reg(priv, reg_err+3-i, &t);
+		err_cnt |= t;
+	}
+	dprintk("error=%d total=%d\n", err_cnt, total_cnt);
+
+	if (total_cnt == 0)
+		*ber = 0;
+	else
+		*ber = err_cnt * 100 / total_cnt;
+
+	dprintk("%s: ber=0x%x\n", __func__, *ber);
+	return 0;
+}
+
+static int lgs8gxx_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct lgs8gxx_state *priv = fe->demodulator_priv;
+
+	if (priv->config->tuner_address == 0)
+		return 0;
+	if (enable) {
+		u8 v = 0x80 | priv->config->tuner_address;
+		return lgs8gxx_write_reg(priv, 0x01, v);
+	}
+	return lgs8gxx_write_reg(priv, 0x01, 0);
+}
+
+static struct dvb_frontend_ops lgs8gxx_ops = {
+	.delsys = { SYS_DTMB },
+	.info = {
+		.name = "Legend Silicon LGS8913/LGS8GXX DMB-TH",
+		.frequency_min = 474000000,
+		.frequency_max = 858000000,
+		.frequency_stepsize = 10000,
+		.caps =
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO
+	},
+
+	.release = lgs8gxx_release,
+
+	.init = lgs8gxx_init,
+	.write = lgs8gxx_write,
+	.i2c_gate_ctrl = lgs8gxx_i2c_gate_ctrl,
+
+	.set_frontend = lgs8gxx_set_fe,
+	.get_frontend = lgs8gxx_get_fe,
+	.get_tune_settings = lgs8gxx_get_tune_settings,
+
+	.read_status = lgs8gxx_read_status,
+	.read_ber = lgs8gxx_read_ber,
+	.read_signal_strength = lgs8gxx_read_signal_strength,
+	.read_snr = lgs8gxx_read_snr,
+	.read_ucblocks = lgs8gxx_read_ucblocks,
+};
+
+struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,
+	struct i2c_adapter *i2c)
+{
+	struct lgs8gxx_state *priv = NULL;
+	u8 data = 0;
+
+	dprintk("%s()\n", __func__);
+
+	if (config == NULL || i2c == NULL)
+		return NULL;
+
+	priv = kzalloc(sizeof(struct lgs8gxx_state), GFP_KERNEL);
+	if (priv == NULL)
+		goto error_out;
+
+	priv->config = config;
+	priv->i2c = i2c;
+
+	/* check if the demod is there */
+	if (lgs8gxx_read_reg(priv, 0, &data) != 0) {
+		dprintk("%s lgs8gxx not found at i2c addr 0x%02X\n",
+			__func__, priv->config->demod_address);
+		goto error_out;
+	}
+
+	lgs8gxx_read_reg(priv, 1, &data);
+
+	memcpy(&priv->frontend.ops, &lgs8gxx_ops,
+	       sizeof(struct dvb_frontend_ops));
+	priv->frontend.demodulator_priv = priv;
+
+	if (config->prod == LGS8GXX_PROD_LGS8G75)
+		lgs8g75_init_data(priv);
+
+	return &priv->frontend;
+
+error_out:
+	dprintk("%s() error_out\n", __func__);
+	kfree(priv);
+	return NULL;
+
+}
+EXPORT_SYMBOL(lgs8gxx_attach);
+
+MODULE_DESCRIPTION("Legend Silicon LGS8913/LGS8GXX DMB-TH demodulator driver");
+MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(LGS8GXX_FIRMWARE);
diff --git a/drivers/media/dvb-frontends/lgs8gxx.h b/drivers/media/dvb-frontends/lgs8gxx.h
new file mode 100644
index 0000000..33c3c5e
--- /dev/null
+++ b/drivers/media/dvb-frontends/lgs8gxx.h
@@ -0,0 +1,95 @@
+/*
+ *    Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
+ *    LGS8913, LGS8GL5, LGS8G75
+ *    experimental support LGS8G42, LGS8G52
+ *
+ *    Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
+ *    Copyright (C) 2008 Sirius International (Hong Kong) Limited
+ *    Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LGS8GXX_H__
+#define __LGS8GXX_H__
+
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#define LGS8GXX_PROD_LGS8913 0
+#define LGS8GXX_PROD_LGS8GL5 1
+#define LGS8GXX_PROD_LGS8G42 3
+#define LGS8GXX_PROD_LGS8G52 4
+#define LGS8GXX_PROD_LGS8G54 5
+#define LGS8GXX_PROD_LGS8G75 6
+
+struct lgs8gxx_config {
+
+	/* product type */
+	u8 prod;
+
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* parallel or serial transport stream */
+	u8 serial_ts;
+
+	/* transport stream polarity*/
+	u8 ts_clk_pol;
+
+	/* transport stream clock gated by ts_valid */
+	u8 ts_clk_gated;
+
+	/* A/D Clock frequency */
+	u32 if_clk_freq; /* in kHz */
+
+	/* IF frequency */
+	u32 if_freq; /* in kHz */
+
+	/*Use External ADC*/
+	u8 ext_adc;
+
+	/*External ADC output two's complement*/
+	u8 adc_signed;
+
+	/*Sample IF data at falling edge of IF_CLK*/
+	u8 if_neg_edge;
+
+	/*IF use Negative center frequency*/
+	u8 if_neg_center;
+
+	/*8G75 internal ADC input range selection*/
+	/*0: 0.8Vpp, 1: 1.0Vpp, 2: 1.6Vpp, 3: 2.0Vpp*/
+	u8 adc_vpp;
+
+	/* slave address and configuration of the tuner */
+	u8 tuner_address;
+};
+
+#if defined(CONFIG_DVB_LGS8GXX) || \
+	(defined(CONFIG_DVB_LGS8GXX_MODULE) && defined(MODULE))
+extern struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,
+					   struct i2c_adapter *i2c);
+#else
+static inline
+struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,
+				    struct i2c_adapter *i2c) {
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_LGS8GXX */
+
+#endif /* __LGS8GXX_H__ */
diff --git a/drivers/media/dvb-frontends/lgs8gxx_priv.h b/drivers/media/dvb-frontends/lgs8gxx_priv.h
new file mode 100644
index 0000000..8ef376f
--- /dev/null
+++ b/drivers/media/dvb-frontends/lgs8gxx_priv.h
@@ -0,0 +1,70 @@
+/*
+ *    Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
+ *    LGS8913, LGS8GL5, LGS8G75
+ *    experimental support LGS8G42, LGS8G52
+ *
+ *    Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
+ *    Copyright (C) 2008 Sirius International (Hong Kong) Limited
+ *    Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef LGS8913_PRIV_H
+#define LGS8913_PRIV_H
+
+struct lgs8gxx_state {
+	struct i2c_adapter *i2c;
+	/* configuration settings */
+	const struct lgs8gxx_config *config;
+	struct dvb_frontend frontend;
+	u16 curr_gi; /* current guard interval */
+};
+
+#define SC_MASK		0x1C	/* Sub-Carrier Modulation Mask */
+#define SC_QAM64	0x10	/* 64QAM modulation */
+#define SC_QAM32	0x0C	/* 32QAM modulation */
+#define SC_QAM16	0x08	/* 16QAM modulation */
+#define SC_QAM4NR	0x04	/* 4QAM-NR modulation */
+#define SC_QAM4		0x00	/* 4QAM modulation */
+
+#define LGS_FEC_MASK	0x03	/* FEC Rate Mask */
+#define LGS_FEC_0_4	0x00	/* FEC Rate 0.4 */
+#define LGS_FEC_0_6	0x01	/* FEC Rate 0.6 */
+#define LGS_FEC_0_8	0x02	/* FEC Rate 0.8 */
+
+#define TIM_MASK	  0x20	/* Time Interleave Length Mask */
+#define TIM_LONG	  0x20	/* Time Interleave Length = 720 */
+#define TIM_MIDDLE     0x00   /* Time Interleave Length = 240 */
+
+#define CF_MASK	0x80	/* Control Frame Mask */
+#define CF_EN	0x80	/* Control Frame On */
+
+#define GI_MASK	0x03	/* Guard Interval Mask */
+#define GI_420	0x00	/* 1/9 Guard Interval */
+#define GI_595	0x01	/* */
+#define GI_945	0x02	/* 1/4 Guard Interval */
+
+
+#define TS_PARALLEL	0x00	/* Parallel TS Output a.k.a. SPI */
+#define TS_SERIAL	0x01	/* Serial TS Output a.k.a. SSI */
+#define TS_CLK_NORMAL		0x00	/* MPEG Clock Normal */
+#define TS_CLK_INVERTED		0x02	/* MPEG Clock Inverted */
+#define TS_CLK_GATED		0x00	/* MPEG clock gated */
+#define TS_CLK_FREERUN		0x04	/* MPEG clock free running*/
+
+
+#endif
diff --git a/drivers/media/dvb-frontends/lnbh24.h b/drivers/media/dvb-frontends/lnbh24.h
new file mode 100644
index 0000000..c059b16
--- /dev/null
+++ b/drivers/media/dvb-frontends/lnbh24.h
@@ -0,0 +1,55 @@
+/*
+ * lnbh24.h - driver for lnb supply and control ic lnbh24
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _LNBH24_H
+#define _LNBH24_H
+
+/* system register bits */
+#define LNBH24_OLF	0x01
+#define LNBH24_OTF	0x02
+#define LNBH24_EN	0x04
+#define LNBH24_VSEL	0x08
+#define LNBH24_LLC	0x10
+#define LNBH24_TEN	0x20
+#define LNBH24_TTX	0x40
+#define LNBH24_PCL	0x80
+
+#include <linux/dvb/frontend.h>
+
+#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) \
+							&& defined(MODULE))
+/* override_set and override_clear control which
+   system register bits (above) to always set & clear */
+extern struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,
+				struct i2c_adapter *i2c, u8 override_set,
+				u8 override_clear, u8 i2c_addr);
+#else
+static inline struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,
+				struct i2c_adapter *i2c, u8 override_set,
+				u8 override_clear, u8 i2c_addr)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb-frontends/lnbp21.c b/drivers/media/dvb-frontends/lnbp21.c
new file mode 100644
index 0000000..1343725
--- /dev/null
+++ b/drivers/media/dvb-frontends/lnbp21.c
@@ -0,0 +1,188 @@
+/*
+ * lnbp21.c - driver for lnb supply and control ic lnbp21
+ *
+ * Copyright (C) 2006, 2009 Oliver Endriss <o.endriss@gmx.de>
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "lnbp21.h"
+#include "lnbh24.h"
+
+struct lnbp21 {
+	u8			config;
+	u8			override_or;
+	u8			override_and;
+	struct i2c_adapter	*i2c;
+	u8			i2c_addr;
+};
+
+static int lnbp21_set_voltage(struct dvb_frontend *fe,
+					fe_sec_voltage_t voltage)
+{
+	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
+	struct i2c_msg msg = {	.addr = lnbp21->i2c_addr, .flags = 0,
+				.buf = &lnbp21->config,
+				.len = sizeof(lnbp21->config) };
+
+	lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
+
+	switch(voltage) {
+	case SEC_VOLTAGE_OFF:
+		break;
+	case SEC_VOLTAGE_13:
+		lnbp21->config |= LNBP21_EN;
+		break;
+	case SEC_VOLTAGE_18:
+		lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	lnbp21->config |= lnbp21->override_or;
+	lnbp21->config &= lnbp21->override_and;
+
+	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
+	struct i2c_msg msg = {	.addr = lnbp21->i2c_addr, .flags = 0,
+				.buf = &lnbp21->config,
+				.len = sizeof(lnbp21->config) };
+
+	if (arg)
+		lnbp21->config |= LNBP21_LLC;
+	else
+		lnbp21->config &= ~LNBP21_LLC;
+
+	lnbp21->config |= lnbp21->override_or;
+	lnbp21->config &= lnbp21->override_and;
+
+	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int lnbp21_set_tone(struct dvb_frontend *fe,
+				fe_sec_tone_mode_t tone)
+{
+	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
+	struct i2c_msg msg = {	.addr = lnbp21->i2c_addr, .flags = 0,
+				.buf = &lnbp21->config,
+				.len = sizeof(lnbp21->config) };
+
+	switch (tone) {
+	case SEC_TONE_OFF:
+		lnbp21->config &= ~LNBP21_TEN;
+		break;
+	case SEC_TONE_ON:
+		lnbp21->config |= LNBP21_TEN;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	lnbp21->config |= lnbp21->override_or;
+	lnbp21->config &= lnbp21->override_and;
+
+	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void lnbp21_release(struct dvb_frontend *fe)
+{
+	/* LNBP power off */
+	lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+	/* free data */
+	kfree(fe->sec_priv);
+	fe->sec_priv = NULL;
+}
+
+static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe,
+				struct i2c_adapter *i2c, u8 override_set,
+				u8 override_clear, u8 i2c_addr, u8 config)
+{
+	struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
+	if (!lnbp21)
+		return NULL;
+
+	/* default configuration */
+	lnbp21->config = config;
+	lnbp21->i2c = i2c;
+	lnbp21->i2c_addr = i2c_addr;
+	fe->sec_priv = lnbp21;
+
+	/* bits which should be forced to '1' */
+	lnbp21->override_or = override_set;
+
+	/* bits which should be forced to '0' */
+	lnbp21->override_and = ~override_clear;
+
+	/* detect if it is present or not */
+	if (lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+		kfree(lnbp21);
+		return NULL;
+	}
+
+	/* install release callback */
+	fe->ops.release_sec = lnbp21_release;
+
+	/* override frontend ops */
+	fe->ops.set_voltage = lnbp21_set_voltage;
+	fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+	if (!(override_clear & LNBH24_TEN)) /*22kHz logic controlled by demod*/
+		fe->ops.set_tone = lnbp21_set_tone;
+	printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr);
+
+	return fe;
+}
+
+struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,
+				struct i2c_adapter *i2c, u8 override_set,
+				u8 override_clear, u8 i2c_addr)
+{
+	return lnbx2x_attach(fe, i2c, override_set, override_clear,
+							i2c_addr, LNBH24_TTX);
+}
+EXPORT_SYMBOL(lnbh24_attach);
+
+struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
+				struct i2c_adapter *i2c, u8 override_set,
+				u8 override_clear)
+{
+	return lnbx2x_attach(fe, i2c, override_set, override_clear,
+							0x08, LNBP21_ISEL);
+}
+EXPORT_SYMBOL(lnbp21_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21, lnbh24");
+MODULE_AUTHOR("Oliver Endriss, Igor M. Liplianin");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/lnbp21.h b/drivers/media/dvb-frontends/lnbp21.h
new file mode 100644
index 0000000..fcdf1c6
--- /dev/null
+++ b/drivers/media/dvb-frontends/lnbp21.h
@@ -0,0 +1,75 @@
+/*
+ * lnbp21.h - driver for lnb supply and control ic lnbp21
+ *
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _LNBP21_H
+#define _LNBP21_H
+
+/* system register bits */
+/* [RO] 0=OK; 1=over current limit flag */
+#define LNBP21_OLF	0x01
+/* [RO] 0=OK; 1=over temperature flag (150 C) */
+#define LNBP21_OTF	0x02
+/* [RW] 0=disable LNB power, enable loopthrough
+	1=enable LNB power, disable loopthrough */
+#define LNBP21_EN	0x04
+/* [RW] 0=low voltage (13/14V, vert pol)
+	1=high voltage (18/19V,horiz pol) */
+#define LNBP21_VSEL	0x08
+/* [RW] increase LNB voltage by 1V:
+	0=13/18V; 1=14/19V */
+#define LNBP21_LLC	0x10
+/* [RW] 0=tone controlled by DSQIN pin
+	1=tone enable, disable DSQIN */
+#define LNBP21_TEN	0x20
+/* [RW] current limit select:
+	0:Iout=500-650mA Isc=300mA
+	1:Iout=400-550mA Isc=200mA */
+#define LNBP21_ISEL	0x40
+/* [RW] short-circuit protect:
+	0=pulsed (dynamic) curr limiting
+	1=static curr limiting */
+#define LNBP21_PCL	0x80
+
+#include <linux/dvb/frontend.h>
+
+#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) \
+							&& defined(MODULE))
+/* override_set and override_clear control which
+ system register bits (above) to always set & clear */
+extern struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
+				struct i2c_adapter *i2c, u8 override_set,
+				u8 override_clear);
+#else
+static inline struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
+				struct i2c_adapter *i2c, u8 override_set,
+				u8 override_clear)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb-frontends/lnbp22.c b/drivers/media/dvb-frontends/lnbp22.c
new file mode 100644
index 0000000..84ad039
--- /dev/null
+++ b/drivers/media/dvb-frontends/lnbp22.c
@@ -0,0 +1,148 @@
+/*
+ * lnbp22.h - driver for lnb supply and control ic lnbp22
+ *
+ * Copyright (C) 2006 Dominik Kuhlen
+ * Based on lnbp21 driver
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "lnbp22.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+
+#define dprintk(lvl, arg...) if (debug >= (lvl)) printk(arg)
+
+struct lnbp22 {
+	u8		    config[4];
+	struct i2c_adapter *i2c;
+};
+
+static int lnbp22_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct lnbp22 *lnbp22 = (struct lnbp22 *)fe->sec_priv;
+	struct i2c_msg msg = {
+		.addr = 0x08,
+		.flags = 0,
+		.buf = (char *)&lnbp22->config,
+		.len = sizeof(lnbp22->config),
+	};
+
+	dprintk(1, "%s: %d (18V=%d 13V=%d)\n", __func__, voltage,
+	       SEC_VOLTAGE_18, SEC_VOLTAGE_13);
+
+	lnbp22->config[3] = 0x60; /* Power down */
+	switch (voltage) {
+	case SEC_VOLTAGE_OFF:
+		break;
+	case SEC_VOLTAGE_13:
+		lnbp22->config[3] |= LNBP22_EN;
+		break;
+	case SEC_VOLTAGE_18:
+		lnbp22->config[3] |= (LNBP22_EN | LNBP22_VSEL);
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	dprintk(1, "%s: 0x%02x)\n", __func__, lnbp22->config[3]);
+	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int lnbp22_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+	struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
+	struct i2c_msg msg = {
+		.addr = 0x08,
+		.flags = 0,
+		.buf = (char *)&lnbp22->config,
+		.len = sizeof(lnbp22->config),
+	};
+
+	dprintk(1, "%s: %d\n", __func__, (int)arg);
+	if (arg)
+		lnbp22->config[3] |= LNBP22_LLC;
+	else
+		lnbp22->config[3] &= ~LNBP22_LLC;
+
+	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void lnbp22_release(struct dvb_frontend *fe)
+{
+	dprintk(1, "%s\n", __func__);
+	/* LNBP power off */
+	lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+	/* free data */
+	kfree(fe->sec_priv);
+	fe->sec_priv = NULL;
+}
+
+struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe,
+					struct i2c_adapter *i2c)
+{
+	struct lnbp22 *lnbp22 = kmalloc(sizeof(struct lnbp22), GFP_KERNEL);
+	if (!lnbp22)
+		return NULL;
+
+	/* default configuration */
+	lnbp22->config[0] = 0x00; /* ? */
+	lnbp22->config[1] = 0x28; /* ? */
+	lnbp22->config[2] = 0x48; /* ? */
+	lnbp22->config[3] = 0x60; /* Power down */
+	lnbp22->i2c = i2c;
+	fe->sec_priv = lnbp22;
+
+	/* detect if it is present or not */
+	if (lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+		dprintk(0, "%s LNBP22 not found\n", __func__);
+		kfree(lnbp22);
+		fe->sec_priv = NULL;
+		return NULL;
+	}
+
+	/* install release callback */
+	fe->ops.release_sec = lnbp22_release;
+
+	/* override frontend ops */
+	fe->ops.set_voltage = lnbp22_set_voltage;
+	fe->ops.enable_high_lnb_voltage = lnbp22_enable_high_lnb_voltage;
+
+	return fe;
+}
+EXPORT_SYMBOL(lnbp22_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp22");
+MODULE_AUTHOR("Dominik Kuhlen");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/lnbp22.h b/drivers/media/dvb-frontends/lnbp22.h
new file mode 100644
index 0000000..63e2dec
--- /dev/null
+++ b/drivers/media/dvb-frontends/lnbp22.h
@@ -0,0 +1,57 @@
+/*
+ * lnbp22.h - driver for lnb supply and control ic lnbp22
+ *
+ * Copyright (C) 2006 Dominik Kuhlen
+ * Based on lnbp21.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _LNBP22_H
+#define _LNBP22_H
+
+/* Enable */
+#define LNBP22_EN	  0x10
+/* Voltage selection */
+#define LNBP22_VSEL	0x02
+/* Plus 1 Volt Bit */
+#define LNBP22_LLC	0x01
+
+#include <linux/dvb/frontend.h>
+
+#if defined(CONFIG_DVB_LNBP22) || \
+		(defined(CONFIG_DVB_LNBP22_MODULE) && defined(MODULE))
+/*
+ * override_set and override_clear control which system register bits (above)
+ * to always set & clear
+ */
+extern struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe,
+						struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe,
+						struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_LNBP22 */
+
+#endif /* _LNBP22_H */
diff --git a/drivers/media/dvb-frontends/m88rs2000.c b/drivers/media/dvb-frontends/m88rs2000.c
new file mode 100644
index 0000000..633815e
--- /dev/null
+++ b/drivers/media/dvb-frontends/m88rs2000.c
@@ -0,0 +1,919 @@
+/*
+	Driver for M88RS2000 demodulator and tuner
+
+	Copyright (C) 2012 Malcolm Priestley (tvboxspy@gmail.com)
+	Beta Driver
+
+	Include various calculation code from DS3000 driver.
+	Copyright (C) 2009 Konstantin Dimitrov.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+
+#include "dvb_frontend.h"
+#include "m88rs2000.h"
+
+struct m88rs2000_state {
+	struct i2c_adapter *i2c;
+	const struct m88rs2000_config *config;
+	struct dvb_frontend frontend;
+	u8 no_lock_count;
+	u32 tuner_frequency;
+	u32 symbol_rate;
+	fe_code_rate_t fec_inner;
+	u8 tuner_level;
+	int errmode;
+};
+
+static int m88rs2000_debug;
+
+module_param_named(debug, m88rs2000_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
+
+#define dprintk(level, args...) do { \
+	if (level & m88rs2000_debug) \
+		printk(KERN_DEBUG "m88rs2000-fe: " args); \
+} while (0)
+
+#define deb_info(args...)  dprintk(0x01, args)
+#define info(format, arg...) \
+	printk(KERN_INFO "m88rs2000-fe: " format "\n" , ## arg)
+
+static int m88rs2000_writereg(struct m88rs2000_state *state, u8 tuner,
+	u8 reg, u8 data)
+{
+	int ret;
+	u8 addr = (tuner == 0) ? state->config->tuner_addr :
+		state->config->demod_addr;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = {
+		.addr = addr,
+		.flags = 0,
+		.buf = buf,
+		.len = 2
+	};
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		deb_info("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
+			"ret == %i)\n", __func__, reg, data, ret);
+
+	return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int m88rs2000_demod_write(struct m88rs2000_state *state, u8 reg, u8 data)
+{
+	return m88rs2000_writereg(state, 1, reg, data);
+}
+
+static int m88rs2000_tuner_write(struct m88rs2000_state *state, u8 reg, u8 data)
+{
+	m88rs2000_demod_write(state, 0x81, 0x84);
+	udelay(10);
+	return m88rs2000_writereg(state, 0, reg, data);
+
+}
+
+static int m88rs2000_write(struct dvb_frontend *fe, const u8 buf[], int len)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+
+	if (len != 2)
+		return -EINVAL;
+
+	return m88rs2000_writereg(state, 1, buf[0], buf[1]);
+}
+
+static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 tuner, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	u8 addr = (tuner == 0) ? state->config->tuner_addr :
+		state->config->demod_addr;
+	struct i2c_msg msg[] = {
+		{
+			.addr = addr,
+			.flags = 0,
+			.buf = b0,
+			.len = 1
+		}, {
+			.addr = addr,
+			.flags = I2C_M_RD,
+			.buf = b1,
+			.len = 1
+		}
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		deb_info("%s: readreg error (reg == 0x%02x, ret == %i)\n",
+				__func__, reg, ret);
+
+	return b1[0];
+}
+
+static u8 m88rs2000_demod_read(struct m88rs2000_state *state, u8 reg)
+{
+	return m88rs2000_readreg(state, 1, reg);
+}
+
+static u8 m88rs2000_tuner_read(struct m88rs2000_state *state, u8 reg)
+{
+	m88rs2000_demod_write(state, 0x81, 0x85);
+	udelay(10);
+	return m88rs2000_readreg(state, 0, reg);
+}
+
+static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	int ret;
+	u32 temp;
+	u8 b[3];
+
+	if ((srate < 1000000) || (srate > 45000000))
+		return -EINVAL;
+
+	temp = srate / 1000;
+	temp *= 11831;
+	temp /= 68;
+	temp -= 3;
+
+	b[0] = (u8) (temp >> 16) & 0xff;
+	b[1] = (u8) (temp >> 8) & 0xff;
+	b[2] = (u8) temp & 0xff;
+	ret = m88rs2000_demod_write(state, 0x93, b[2]);
+	ret |= m88rs2000_demod_write(state, 0x94, b[1]);
+	ret |= m88rs2000_demod_write(state, 0x95, b[0]);
+
+	deb_info("m88rs2000: m88rs2000_set_symbolrate\n");
+	return ret;
+}
+
+static int m88rs2000_send_diseqc_msg(struct dvb_frontend *fe,
+				    struct dvb_diseqc_master_cmd *m)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+
+	int i;
+	u8 reg;
+	deb_info("%s\n", __func__);
+	m88rs2000_demod_write(state, 0x9a, 0x30);
+	reg = m88rs2000_demod_read(state, 0xb2);
+	reg &= 0x3f;
+	m88rs2000_demod_write(state, 0xb2, reg);
+	for (i = 0; i <  m->msg_len; i++)
+		m88rs2000_demod_write(state, 0xb3 + i, m->msg[i]);
+
+	reg = m88rs2000_demod_read(state, 0xb1);
+	reg &= 0x87;
+	reg |= ((m->msg_len - 1) << 3) | 0x07;
+	reg &= 0x7f;
+	m88rs2000_demod_write(state, 0xb1, reg);
+
+	for (i = 0; i < 15; i++) {
+		if ((m88rs2000_demod_read(state, 0xb1) & 0x40) == 0x0)
+			break;
+		msleep(20);
+	}
+
+	reg = m88rs2000_demod_read(state, 0xb1);
+	if ((reg & 0x40) > 0x0) {
+		reg &= 0x7f;
+		reg |= 0x40;
+		m88rs2000_demod_write(state, 0xb1, reg);
+	}
+
+	reg = m88rs2000_demod_read(state, 0xb2);
+	reg &= 0x3f;
+	reg |= 0x80;
+	m88rs2000_demod_write(state, 0xb2, reg);
+	m88rs2000_demod_write(state, 0x9a, 0xb0);
+
+
+	return 0;
+}
+
+static int m88rs2000_send_diseqc_burst(struct dvb_frontend *fe,
+						fe_sec_mini_cmd_t burst)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	u8 reg0, reg1;
+	deb_info("%s\n", __func__);
+	m88rs2000_demod_write(state, 0x9a, 0x30);
+	msleep(50);
+	reg0 = m88rs2000_demod_read(state, 0xb1);
+	reg1 = m88rs2000_demod_read(state, 0xb2);
+	/* TODO complete this section */
+	m88rs2000_demod_write(state, 0xb2, reg1);
+	m88rs2000_demod_write(state, 0xb1, reg0);
+	m88rs2000_demod_write(state, 0x9a, 0xb0);
+
+	return 0;
+}
+
+static int m88rs2000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	u8 reg0, reg1;
+	m88rs2000_demod_write(state, 0x9a, 0x30);
+	reg0 = m88rs2000_demod_read(state, 0xb1);
+	reg1 = m88rs2000_demod_read(state, 0xb2);
+
+	reg1 &= 0x3f;
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		reg0 |= 0x4;
+		reg0 &= 0xbc;
+		break;
+	case SEC_TONE_OFF:
+		reg1 |= 0x80;
+		break;
+	default:
+		break;
+	}
+	m88rs2000_demod_write(state, 0xb2, reg1);
+	m88rs2000_demod_write(state, 0xb1, reg0);
+	m88rs2000_demod_write(state, 0x9a, 0xb0);
+	return 0;
+}
+
+struct inittab {
+	u8 cmd;
+	u8 reg;
+	u8 val;
+};
+
+struct inittab m88rs2000_setup[] = {
+	{DEMOD_WRITE, 0x9a, 0x30},
+	{DEMOD_WRITE, 0x00, 0x01},
+	{WRITE_DELAY, 0x19, 0x00},
+	{DEMOD_WRITE, 0x00, 0x00},
+	{DEMOD_WRITE, 0x9a, 0xb0},
+	{DEMOD_WRITE, 0x81, 0xc1},
+	{TUNER_WRITE, 0x42, 0x73},
+	{TUNER_WRITE, 0x05, 0x07},
+	{TUNER_WRITE, 0x20, 0x27},
+	{TUNER_WRITE, 0x07, 0x02},
+	{TUNER_WRITE, 0x11, 0xff},
+	{TUNER_WRITE, 0x60, 0xf9},
+	{TUNER_WRITE, 0x08, 0x01},
+	{TUNER_WRITE, 0x00, 0x41},
+	{DEMOD_WRITE, 0x81, 0x81},
+	{DEMOD_WRITE, 0x86, 0xc6},
+	{DEMOD_WRITE, 0x9a, 0x30},
+	{DEMOD_WRITE, 0xf0, 0x22},
+	{DEMOD_WRITE, 0xf1, 0xbf},
+	{DEMOD_WRITE, 0xb0, 0x45},
+	{DEMOD_WRITE, 0xb2, 0x01}, /* set voltage pin always set 1*/
+	{DEMOD_WRITE, 0x9a, 0xb0},
+	{0xff, 0xaa, 0xff}
+};
+
+struct inittab m88rs2000_shutdown[] = {
+	{DEMOD_WRITE, 0x9a, 0x30},
+	{DEMOD_WRITE, 0xb0, 0x00},
+	{DEMOD_WRITE, 0xf1, 0x89},
+	{DEMOD_WRITE, 0x00, 0x01},
+	{DEMOD_WRITE, 0x9a, 0xb0},
+	{TUNER_WRITE, 0x00, 0x40},
+	{DEMOD_WRITE, 0x81, 0x81},
+	{0xff, 0xaa, 0xff}
+};
+
+struct inittab tuner_reset[] = {
+	{TUNER_WRITE, 0x42, 0x73},
+	{TUNER_WRITE, 0x05, 0x07},
+	{TUNER_WRITE, 0x20, 0x27},
+	{TUNER_WRITE, 0x07, 0x02},
+	{TUNER_WRITE, 0x11, 0xff},
+	{TUNER_WRITE, 0x60, 0xf9},
+	{TUNER_WRITE, 0x08, 0x01},
+	{TUNER_WRITE, 0x00, 0x41},
+	{0xff, 0xaa, 0xff}
+};
+
+struct inittab fe_reset[] = {
+	{DEMOD_WRITE, 0x00, 0x01},
+	{DEMOD_WRITE, 0xf1, 0xbf},
+	{DEMOD_WRITE, 0x00, 0x01},
+	{DEMOD_WRITE, 0x20, 0x81},
+	{DEMOD_WRITE, 0x21, 0x80},
+	{DEMOD_WRITE, 0x10, 0x33},
+	{DEMOD_WRITE, 0x11, 0x44},
+	{DEMOD_WRITE, 0x12, 0x07},
+	{DEMOD_WRITE, 0x18, 0x20},
+	{DEMOD_WRITE, 0x28, 0x04},
+	{DEMOD_WRITE, 0x29, 0x8e},
+	{DEMOD_WRITE, 0x3b, 0xff},
+	{DEMOD_WRITE, 0x32, 0x10},
+	{DEMOD_WRITE, 0x33, 0x02},
+	{DEMOD_WRITE, 0x34, 0x30},
+	{DEMOD_WRITE, 0x35, 0xff},
+	{DEMOD_WRITE, 0x38, 0x50},
+	{DEMOD_WRITE, 0x39, 0x68},
+	{DEMOD_WRITE, 0x3c, 0x7f},
+	{DEMOD_WRITE, 0x3d, 0x0f},
+	{DEMOD_WRITE, 0x45, 0x20},
+	{DEMOD_WRITE, 0x46, 0x24},
+	{DEMOD_WRITE, 0x47, 0x7c},
+	{DEMOD_WRITE, 0x48, 0x16},
+	{DEMOD_WRITE, 0x49, 0x04},
+	{DEMOD_WRITE, 0x4a, 0x01},
+	{DEMOD_WRITE, 0x4b, 0x78},
+	{DEMOD_WRITE, 0X4d, 0xd2},
+	{DEMOD_WRITE, 0x4e, 0x6d},
+	{DEMOD_WRITE, 0x50, 0x30},
+	{DEMOD_WRITE, 0x51, 0x30},
+	{DEMOD_WRITE, 0x54, 0x7b},
+	{DEMOD_WRITE, 0x56, 0x09},
+	{DEMOD_WRITE, 0x58, 0x59},
+	{DEMOD_WRITE, 0x59, 0x37},
+	{DEMOD_WRITE, 0x63, 0xfa},
+	{0xff, 0xaa, 0xff}
+};
+
+struct inittab fe_trigger[] = {
+	{DEMOD_WRITE, 0x97, 0x04},
+	{DEMOD_WRITE, 0x99, 0x77},
+	{DEMOD_WRITE, 0x9b, 0x64},
+	{DEMOD_WRITE, 0x9e, 0x00},
+	{DEMOD_WRITE, 0x9f, 0xf8},
+	{DEMOD_WRITE, 0xa0, 0x20},
+	{DEMOD_WRITE, 0xa1, 0xe0},
+	{DEMOD_WRITE, 0xa3, 0x38},
+	{DEMOD_WRITE, 0x98, 0xff},
+	{DEMOD_WRITE, 0xc0, 0x0f},
+	{DEMOD_WRITE, 0x89, 0x01},
+	{DEMOD_WRITE, 0x00, 0x00},
+	{WRITE_DELAY, 0x0a, 0x00},
+	{DEMOD_WRITE, 0x00, 0x01},
+	{DEMOD_WRITE, 0x00, 0x00},
+	{DEMOD_WRITE, 0x9a, 0xb0},
+	{0xff, 0xaa, 0xff}
+};
+
+static int m88rs2000_tab_set(struct m88rs2000_state *state,
+		struct inittab *tab)
+{
+	int ret = 0;
+	u8 i;
+	if (tab == NULL)
+		return -EINVAL;
+
+	for (i = 0; i < 255; i++) {
+		switch (tab[i].cmd) {
+		case 0x01:
+			ret = m88rs2000_demod_write(state, tab[i].reg,
+				tab[i].val);
+			break;
+		case 0x02:
+			ret = m88rs2000_tuner_write(state, tab[i].reg,
+				tab[i].val);
+			break;
+		case 0x10:
+			if (tab[i].reg > 0)
+				mdelay(tab[i].reg);
+			break;
+		case 0xff:
+			if (tab[i].reg == 0xaa && tab[i].val == 0xff)
+				return 0;
+		case 0x00:
+			break;
+		default:
+			return -EINVAL;
+		}
+		if (ret < 0)
+			return -ENODEV;
+	}
+	return 0;
+}
+
+static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	u8 data;
+
+	data = m88rs2000_demod_read(state, 0xb2);
+	data |= 0x03; /* bit0 V/H, bit1 off/on */
+
+	switch (volt) {
+	case SEC_VOLTAGE_18:
+		data &= ~0x03;
+		break;
+	case SEC_VOLTAGE_13:
+		data &= ~0x03;
+		data |= 0x01;
+		break;
+	case SEC_VOLTAGE_OFF:
+		break;
+	}
+
+	m88rs2000_demod_write(state, 0xb2, data);
+
+	return 0;
+}
+
+static int m88rs2000_startup(struct m88rs2000_state *state)
+{
+	int ret = 0;
+	u8 reg;
+
+	reg = m88rs2000_tuner_read(state, 0x00);
+	if ((reg & 0x40) == 0)
+		ret = -ENODEV;
+
+	return ret;
+}
+
+static int m88rs2000_init(struct dvb_frontend *fe)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	int ret;
+
+	deb_info("m88rs2000: init chip\n");
+	/* Setup frontend from shutdown/cold */
+	ret = m88rs2000_tab_set(state, m88rs2000_setup);
+
+	return ret;
+}
+
+static int m88rs2000_sleep(struct dvb_frontend *fe)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	int ret;
+	/* Shutdown the frondend */
+	ret = m88rs2000_tab_set(state, m88rs2000_shutdown);
+	return ret;
+}
+
+static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	u8 reg = m88rs2000_demod_read(state, 0x8c);
+
+	*status = 0;
+
+	if ((reg & 0x7) == 0x7) {
+		*status = FE_HAS_CARRIER | FE_HAS_SIGNAL | FE_HAS_VITERBI
+			| FE_HAS_SYNC | FE_HAS_LOCK;
+		if (state->config->set_ts_params)
+			state->config->set_ts_params(fe, CALL_IS_READ);
+	}
+	return 0;
+}
+
+/* Extact code for these unknown but lmedm04 driver uses interupt callbacks */
+
+static int m88rs2000_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	deb_info("m88rs2000_read_ber %d\n", *ber);
+	*ber = 0;
+	return 0;
+}
+
+static int m88rs2000_read_signal_strength(struct dvb_frontend *fe,
+	u16 *strength)
+{
+	*strength = 0;
+	return 0;
+}
+
+static int m88rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	deb_info("m88rs2000_read_snr %d\n", *snr);
+	*snr = 0;
+	return 0;
+}
+
+static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	deb_info("m88rs2000_read_ber %d\n", *ucblocks);
+	*ucblocks = 0;
+	return 0;
+}
+
+static int m88rs2000_tuner_gate_ctrl(struct m88rs2000_state *state, u8 offset)
+{
+	int ret;
+	ret = m88rs2000_tuner_write(state, 0x51, 0x1f - offset);
+	ret |= m88rs2000_tuner_write(state, 0x51, 0x1f);
+	ret |= m88rs2000_tuner_write(state, 0x50, offset);
+	ret |= m88rs2000_tuner_write(state, 0x50, 0x00);
+	msleep(20);
+	return ret;
+}
+
+static int m88rs2000_set_tuner_rf(struct dvb_frontend *fe)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	int reg;
+	reg = m88rs2000_tuner_read(state, 0x3d);
+	reg &= 0x7f;
+	if (reg < 0x16)
+		reg = 0xa1;
+	else if (reg == 0x16)
+		reg = 0x99;
+	else
+		reg = 0xf9;
+
+	m88rs2000_tuner_write(state, 0x60, reg);
+	reg = m88rs2000_tuner_gate_ctrl(state, 0x08);
+
+	if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	return reg;
+}
+
+static int m88rs2000_set_tuner(struct dvb_frontend *fe, u16 *offset)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	int ret;
+	u32 frequency = c->frequency;
+	s32 offset_khz;
+	s32 tmp;
+	u32 symbol_rate = (c->symbol_rate / 1000);
+	u32 f3db, gdiv28;
+	u16 value, ndiv, lpf_coeff;
+	u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf;
+	u8 lo = 0x01, div4 = 0x0;
+
+	/* Reset Tuner */
+	ret = m88rs2000_tab_set(state, tuner_reset);
+
+	/* Calculate frequency divider */
+	if (frequency < 1060000) {
+		lo |= 0x10;
+		div4 = 0x1;
+		ndiv = (frequency * 14 * 4) / FE_CRYSTAL_KHZ;
+	} else
+		ndiv = (frequency * 14 * 2) / FE_CRYSTAL_KHZ;
+	ndiv = ndiv + ndiv % 2;
+	ndiv = ndiv - 1024;
+
+	ret = m88rs2000_tuner_write(state, 0x10, 0x80 | lo);
+
+	/* Set frequency divider */
+	ret |= m88rs2000_tuner_write(state, 0x01, (ndiv >> 8) & 0xf);
+	ret |= m88rs2000_tuner_write(state, 0x02, ndiv & 0xff);
+
+	ret |= m88rs2000_tuner_write(state, 0x03, 0x06);
+	ret |= m88rs2000_tuner_gate_ctrl(state, 0x10);
+	if (ret < 0)
+		return -ENODEV;
+
+	/* Tuner Frequency Range */
+	ret = m88rs2000_tuner_write(state, 0x10, lo);
+
+	ret |= m88rs2000_tuner_gate_ctrl(state, 0x08);
+
+	/* Tuner RF */
+	ret |= m88rs2000_set_tuner_rf(fe);
+
+	gdiv28 = (FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000;
+	ret |= m88rs2000_tuner_write(state, 0x04, gdiv28 & 0xff);
+	ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
+	if (ret < 0)
+		return -ENODEV;
+
+	value = m88rs2000_tuner_read(state, 0x26);
+
+	f3db = (symbol_rate * 135) / 200 + 2000;
+	f3db += FREQ_OFFSET_LOW_SYM_RATE;
+	if (f3db < 7000)
+		f3db = 7000;
+	if (f3db > 40000)
+		f3db = 40000;
+
+	gdiv28 = gdiv28 * 207 / (value * 2 + 151);
+	mlpf_max = gdiv28 * 135 / 100;
+	mlpf_min = gdiv28 * 78 / 100;
+	if (mlpf_max > 63)
+		mlpf_max = 63;
+
+	lpf_coeff = 2766;
+
+	nlpf = (f3db * gdiv28 * 2 / lpf_coeff /
+		(FE_CRYSTAL_KHZ / 1000)  + 1) / 2;
+	if (nlpf > 23)
+		nlpf = 23;
+	if (nlpf < 1)
+		nlpf = 1;
+
+	lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000)
+		* lpf_coeff * 2  / f3db + 1) / 2;
+
+	if (lpf_mxdiv < mlpf_min) {
+		nlpf++;
+		lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000)
+			* lpf_coeff * 2  / f3db + 1) / 2;
+	}
+
+	if (lpf_mxdiv > mlpf_max)
+		lpf_mxdiv = mlpf_max;
+
+	ret = m88rs2000_tuner_write(state, 0x04, lpf_mxdiv);
+	ret |= m88rs2000_tuner_write(state, 0x06, nlpf);
+
+	ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
+
+	ret |= m88rs2000_tuner_gate_ctrl(state, 0x01);
+
+	msleep(80);
+	/* calculate offset assuming 96000kHz*/
+	offset_khz = (ndiv - ndiv % 2 + 1024) * FE_CRYSTAL_KHZ
+		/ 14 / (div4 + 1) / 2;
+
+	offset_khz -= frequency;
+
+	tmp = offset_khz;
+	tmp *= 65536;
+
+	tmp = (2 * tmp + 96000) / (2 * 96000);
+	if (tmp < 0)
+		tmp += 65536;
+
+	*offset = tmp & 0xffff;
+
+	if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return (ret < 0) ? -EINVAL : 0;
+}
+
+static int m88rs2000_set_fec(struct m88rs2000_state *state,
+		fe_code_rate_t fec)
+{
+	u16 fec_set;
+	switch (fec) {
+	/* This is not confirmed kept for reference */
+/*	case FEC_1_2:
+		fec_set = 0x88;
+		break;
+	case FEC_2_3:
+		fec_set = 0x68;
+		break;
+	case FEC_3_4:
+		fec_set = 0x48;
+		break;
+	case FEC_5_6:
+		fec_set = 0x28;
+		break;
+	case FEC_7_8:
+		fec_set = 0x18;
+		break; */
+	case FEC_AUTO:
+	default:
+		fec_set = 0x08;
+	}
+	m88rs2000_demod_write(state, 0x76, fec_set);
+
+	return 0;
+}
+
+
+static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state)
+{
+	u8 reg;
+	m88rs2000_demod_write(state, 0x9a, 0x30);
+	reg = m88rs2000_demod_read(state, 0x76);
+	m88rs2000_demod_write(state, 0x9a, 0xb0);
+
+	switch (reg) {
+	case 0x88:
+		return FEC_1_2;
+	case 0x68:
+		return FEC_2_3;
+	case 0x48:
+		return FEC_3_4;
+	case 0x28:
+		return FEC_5_6;
+	case 0x18:
+		return FEC_7_8;
+	case 0x08:
+	default:
+		break;
+	}
+
+	return FEC_AUTO;
+}
+
+static int m88rs2000_set_frontend(struct dvb_frontend *fe)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	fe_status_t status;
+	int i, ret;
+	u16 offset = 0;
+	u8 reg;
+
+	state->no_lock_count = 0;
+
+	if (c->delivery_system != SYS_DVBS) {
+			deb_info("%s: unsupported delivery "
+				"system selected (%d)\n",
+				__func__, c->delivery_system);
+			return -EOPNOTSUPP;
+	}
+
+	/* Set Tuner */
+	ret = m88rs2000_set_tuner(fe, &offset);
+	if (ret < 0)
+		return -ENODEV;
+
+	ret = m88rs2000_demod_write(state, 0x9a, 0x30);
+	/* Unknown usually 0xc6 sometimes 0xc1 */
+	reg = m88rs2000_demod_read(state, 0x86);
+	ret |= m88rs2000_demod_write(state, 0x86, reg);
+	/* Offset lower nibble always 0 */
+	ret |= m88rs2000_demod_write(state, 0x9c, (offset >> 8));
+	ret |= m88rs2000_demod_write(state, 0x9d, offset & 0xf0);
+
+
+	/* Reset Demod */
+	ret = m88rs2000_tab_set(state, fe_reset);
+	if (ret < 0)
+		return -ENODEV;
+
+	/* Unknown */
+	reg = m88rs2000_demod_read(state, 0x70);
+	ret = m88rs2000_demod_write(state, 0x70, reg);
+
+	/* Set FEC */
+	ret |= m88rs2000_set_fec(state, c->fec_inner);
+	ret |= m88rs2000_demod_write(state, 0x85, 0x1);
+	ret |= m88rs2000_demod_write(state, 0x8a, 0xbf);
+	ret |= m88rs2000_demod_write(state, 0x8d, 0x1e);
+	ret |= m88rs2000_demod_write(state, 0x90, 0xf1);
+	ret |= m88rs2000_demod_write(state, 0x91, 0x08);
+
+	if (ret < 0)
+		return -ENODEV;
+
+	/* Set Symbol Rate */
+	ret = m88rs2000_set_symbolrate(fe, c->symbol_rate);
+	if (ret < 0)
+		return -ENODEV;
+
+	/* Set up Demod */
+	ret = m88rs2000_tab_set(state, fe_trigger);
+	if (ret < 0)
+		return -ENODEV;
+
+	for (i = 0; i < 25; i++) {
+		reg = m88rs2000_demod_read(state, 0x8c);
+		if ((reg & 0x7) == 0x7) {
+			status = FE_HAS_LOCK;
+			break;
+		}
+		state->no_lock_count++;
+		if (state->no_lock_count == 15) {
+			reg = m88rs2000_demod_read(state, 0x70);
+			reg ^= 0x4;
+			m88rs2000_demod_write(state, 0x70, reg);
+			state->no_lock_count = 0;
+		}
+		if (state->no_lock_count == 20)
+			m88rs2000_set_tuner_rf(fe);
+		msleep(20);
+	}
+
+	if (status & FE_HAS_LOCK) {
+		state->fec_inner = m88rs2000_get_fec(state);
+		/* Uknown suspect SNR level */
+		reg = m88rs2000_demod_read(state, 0x65);
+	}
+
+	state->tuner_frequency = c->frequency;
+	state->symbol_rate = c->symbol_rate;
+	return 0;
+}
+
+static int m88rs2000_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	c->fec_inner = state->fec_inner;
+	c->frequency = state->tuner_frequency;
+	c->symbol_rate = state->symbol_rate;
+	return 0;
+}
+
+static int m88rs2000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+
+	if (enable)
+		m88rs2000_demod_write(state, 0x81, 0x84);
+	else
+		m88rs2000_demod_write(state, 0x81, 0x81);
+	udelay(10);
+	return 0;
+}
+
+static void m88rs2000_release(struct dvb_frontend *fe)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops m88rs2000_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name			= "M88RS2000 DVB-S",
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 1000,	 /* kHz for QPSK frontends */
+		.frequency_tolerance	= 5000,
+		.symbol_rate_min	= 1000000,
+		.symbol_rate_max	= 45000000,
+		.symbol_rate_tolerance	= 500,	/* ppm */
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+		      FE_CAN_QPSK |
+		      FE_CAN_FEC_AUTO
+	},
+
+	.release = m88rs2000_release,
+	.init = m88rs2000_init,
+	.sleep = m88rs2000_sleep,
+	.write = m88rs2000_write,
+	.i2c_gate_ctrl = m88rs2000_i2c_gate_ctrl,
+	.read_status = m88rs2000_read_status,
+	.read_ber = m88rs2000_read_ber,
+	.read_signal_strength = m88rs2000_read_signal_strength,
+	.read_snr = m88rs2000_read_snr,
+	.read_ucblocks = m88rs2000_read_ucblocks,
+	.diseqc_send_master_cmd = m88rs2000_send_diseqc_msg,
+	.diseqc_send_burst = m88rs2000_send_diseqc_burst,
+	.set_tone = m88rs2000_set_tone,
+	.set_voltage = m88rs2000_set_voltage,
+
+	.set_frontend = m88rs2000_set_frontend,
+	.get_frontend = m88rs2000_get_frontend,
+};
+
+struct dvb_frontend *m88rs2000_attach(const struct m88rs2000_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct m88rs2000_state *state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct m88rs2000_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->tuner_frequency = 0;
+	state->symbol_rate = 0;
+	state->fec_inner = 0;
+
+	if (m88rs2000_startup(state) < 0)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &m88rs2000_ops,
+			sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+
+	return NULL;
+}
+EXPORT_SYMBOL(m88rs2000_attach);
+
+MODULE_DESCRIPTION("M88RS2000 DVB-S Demodulator driver");
+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.13");
+
diff --git a/drivers/media/dvb-frontends/m88rs2000.h b/drivers/media/dvb-frontends/m88rs2000.h
new file mode 100644
index 0000000..59acdb6
--- /dev/null
+++ b/drivers/media/dvb-frontends/m88rs2000.h
@@ -0,0 +1,66 @@
+/*
+	Driver for M88RS2000 demodulator
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef M88RS2000_H
+#define M88RS2000_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct m88rs2000_config {
+	/* Demodulator i2c address */
+	u8 demod_addr;
+	/* Tuner address */
+	u8 tuner_addr;
+
+	u8 *inittab;
+
+	/* minimum delay before retuning */
+	int min_delay_ms;
+
+	int (*set_ts_params)(struct dvb_frontend *, int);
+};
+
+enum {
+	CALL_IS_SET_FRONTEND = 0x0,
+	CALL_IS_READ,
+};
+
+#if defined(CONFIG_DVB_M88RS2000) || (defined(CONFIG_DVB_M88RS2000_MODULE) && \
+							defined(MODULE))
+extern struct dvb_frontend *m88rs2000_attach(
+	const struct m88rs2000_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *m88rs2000_attach(
+	const struct m88rs2000_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_M88RS2000 */
+
+#define FE_CRYSTAL_KHZ 27000
+#define FREQ_OFFSET_LOW_SYM_RATE 3000
+
+enum {
+	DEMOD_WRITE = 0x1,
+	TUNER_WRITE,
+	WRITE_DELAY = 0x10,
+};
+#endif /* M88RS2000_H */
diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c
new file mode 100644
index 0000000..9ae40ab
--- /dev/null
+++ b/drivers/media/dvb-frontends/mb86a16.c
@@ -0,0 +1,1878 @@
+/*
+	Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "mb86a16.h"
+#include "mb86a16_priv.h"
+
+unsigned int verbose = 5;
+module_param(verbose, int, 0644);
+
+#define ABS(x)		((x) < 0 ? (-x) : (x))
+
+struct mb86a16_state {
+	struct i2c_adapter		*i2c_adap;
+	const struct mb86a16_config	*config;
+	struct dvb_frontend		frontend;
+
+	/* tuning parameters */
+	int				frequency;
+	int				srate;
+
+	/* Internal stuff */
+	int				master_clk;
+	int				deci;
+	int				csel;
+	int				rsel;
+};
+
+#define MB86A16_ERROR		0
+#define MB86A16_NOTICE		1
+#define MB86A16_INFO		2
+#define MB86A16_DEBUG		3
+
+#define dprintk(x, y, z, format, arg...) do {						\
+	if (z) {									\
+		if	((x > MB86A16_ERROR) && (x > y))				\
+			printk(KERN_ERR "%s: " format "\n", __func__, ##arg);		\
+		else if ((x > MB86A16_NOTICE) && (x > y))				\
+			printk(KERN_NOTICE "%s: " format "\n", __func__, ##arg);	\
+		else if ((x > MB86A16_INFO) && (x > y))					\
+			printk(KERN_INFO "%s: " format "\n", __func__, ##arg);		\
+		else if ((x > MB86A16_DEBUG) && (x > y))				\
+			printk(KERN_DEBUG "%s: " format "\n", __func__, ##arg);		\
+	} else {									\
+		if (x > y)								\
+			printk(format, ##arg);						\
+	}										\
+} while (0)
+
+#define TRACE_IN	dprintk(verbose, MB86A16_DEBUG, 1, "-->()")
+#define TRACE_OUT	dprintk(verbose, MB86A16_DEBUG, 1, "()-->")
+
+static int mb86a16_write(struct mb86a16_state *state, u8 reg, u8 val)
+{
+	int ret;
+	u8 buf[] = { reg, val };
+
+	struct i2c_msg msg = {
+		.addr = state->config->demod_address,
+		.flags = 0,
+		.buf = buf,
+		.len = 2
+	};
+
+	dprintk(verbose, MB86A16_DEBUG, 1,
+		"writing to [0x%02x],Reg[0x%02x],Data[0x%02x]",
+		state->config->demod_address, buf[0], buf[1]);
+
+	ret = i2c_transfer(state->i2c_adap, &msg, 1);
+
+	return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int mb86a16_read(struct mb86a16_state *state, u8 reg, u8 *val)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+
+	struct i2c_msg msg[] = {
+		{
+			.addr = state->config->demod_address,
+			.flags = 0,
+			.buf = b0,
+			.len = 1
+		}, {
+			.addr = state->config->demod_address,
+			.flags = I2C_M_RD,
+			.buf = b1,
+			.len = 1
+		}
+	};
+	ret = i2c_transfer(state->i2c_adap, msg, 2);
+	if (ret != 2) {
+		dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=0x%i)",
+			reg, ret);
+
+		return -EREMOTEIO;
+	}
+	*val = b1[0];
+
+	return ret;
+}
+
+static int CNTM_set(struct mb86a16_state *state,
+		    unsigned char timint1,
+		    unsigned char timint2,
+		    unsigned char cnext)
+{
+	unsigned char val;
+
+	val = (timint1 << 4) | (timint2 << 2) | cnext;
+	if (mb86a16_write(state, MB86A16_CNTMR, val) < 0)
+		goto err;
+
+	return 0;
+
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+}
+
+static int smrt_set(struct mb86a16_state *state, int rate)
+{
+	int tmp ;
+	int m ;
+	unsigned char STOFS0, STOFS1;
+
+	m = 1 << state->deci;
+	tmp = (8192 * state->master_clk - 2 * m * rate * 8192 + state->master_clk / 2) / state->master_clk;
+
+	STOFS0 = tmp & 0x0ff;
+	STOFS1 = (tmp & 0xf00) >> 8;
+
+	if (mb86a16_write(state, MB86A16_SRATE1, (state->deci << 2) |
+				       (state->csel << 1) |
+					state->rsel) < 0)
+		goto err;
+	if (mb86a16_write(state, MB86A16_SRATE2, STOFS0) < 0)
+		goto err;
+	if (mb86a16_write(state, MB86A16_SRATE3, STOFS1) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -1;
+}
+
+static int srst(struct mb86a16_state *state)
+{
+	if (mb86a16_write(state, MB86A16_RESET, 0x04) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+
+}
+
+static int afcex_data_set(struct mb86a16_state *state,
+			  unsigned char AFCEX_L,
+			  unsigned char AFCEX_H)
+{
+	if (mb86a16_write(state, MB86A16_AFCEXL, AFCEX_L) < 0)
+		goto err;
+	if (mb86a16_write(state, MB86A16_AFCEXH, AFCEX_H) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+
+	return -1;
+}
+
+static int afcofs_data_set(struct mb86a16_state *state,
+			   unsigned char AFCEX_L,
+			   unsigned char AFCEX_H)
+{
+	if (mb86a16_write(state, 0x58, AFCEX_L) < 0)
+		goto err;
+	if (mb86a16_write(state, 0x59, AFCEX_H) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+}
+
+static int stlp_set(struct mb86a16_state *state,
+		    unsigned char STRAS,
+		    unsigned char STRBS)
+{
+	if (mb86a16_write(state, MB86A16_STRFILTCOEF1, (STRBS << 3) | (STRAS)) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+}
+
+static int Vi_set(struct mb86a16_state *state, unsigned char ETH, unsigned char VIA)
+{
+	if (mb86a16_write(state, MB86A16_VISET2, 0x04) < 0)
+		goto err;
+	if (mb86a16_write(state, MB86A16_VISET3, 0xf5) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+}
+
+static int initial_set(struct mb86a16_state *state)
+{
+	if (stlp_set(state, 5, 7))
+		goto err;
+
+	udelay(100);
+	if (afcex_data_set(state, 0, 0))
+		goto err;
+
+	udelay(100);
+	if (afcofs_data_set(state, 0, 0))
+		goto err;
+
+	udelay(100);
+	if (mb86a16_write(state, MB86A16_CRLFILTCOEF1, 0x16) < 0)
+		goto err;
+	if (mb86a16_write(state, 0x2f, 0x21) < 0)
+		goto err;
+	if (mb86a16_write(state, MB86A16_VIMAG, 0x38) < 0)
+		goto err;
+	if (mb86a16_write(state, MB86A16_FAGCS1, 0x00) < 0)
+		goto err;
+	if (mb86a16_write(state, MB86A16_FAGCS2, 0x1c) < 0)
+		goto err;
+	if (mb86a16_write(state, MB86A16_FAGCS3, 0x20) < 0)
+		goto err;
+	if (mb86a16_write(state, MB86A16_FAGCS4, 0x1e) < 0)
+		goto err;
+	if (mb86a16_write(state, MB86A16_FAGCS5, 0x23) < 0)
+		goto err;
+	if (mb86a16_write(state, 0x54, 0xff) < 0)
+		goto err;
+	if (mb86a16_write(state, MB86A16_TSOUT, 0x00) < 0)
+		goto err;
+
+	return 0;
+
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+}
+
+static int S01T_set(struct mb86a16_state *state,
+		    unsigned char s1t,
+		    unsigned s0t)
+{
+	if (mb86a16_write(state, 0x33, (s1t << 3) | s0t) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+}
+
+
+static int EN_set(struct mb86a16_state *state,
+		  int cren,
+		  int afcen)
+{
+	unsigned char val;
+
+	val = 0x7a | (cren << 7) | (afcen << 2);
+	if (mb86a16_write(state, 0x49, val) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+}
+
+static int AFCEXEN_set(struct mb86a16_state *state,
+		       int afcexen,
+		       int smrt)
+{
+	unsigned char AFCA ;
+
+	if (smrt > 18875)
+		AFCA = 4;
+	else if (smrt > 9375)
+		AFCA = 3;
+	else if (smrt > 2250)
+		AFCA = 2;
+	else
+		AFCA = 1;
+
+	if (mb86a16_write(state, 0x2a, 0x02 | (afcexen << 5) | (AFCA << 2)) < 0)
+		goto err;
+
+	return 0;
+
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+}
+
+static int DAGC_data_set(struct mb86a16_state *state,
+			 unsigned char DAGCA,
+			 unsigned char DAGCW)
+{
+	if (mb86a16_write(state, 0x2d, (DAGCA << 3) | DAGCW) < 0)
+		goto err;
+
+	return 0;
+
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+}
+
+static void smrt_info_get(struct mb86a16_state *state, int rate)
+{
+	if (rate >= 37501) {
+		state->deci = 0; state->csel = 0; state->rsel = 0;
+	} else if (rate >= 30001) {
+		state->deci = 0; state->csel = 0; state->rsel = 1;
+	} else if (rate >= 26251) {
+		state->deci = 0; state->csel = 1; state->rsel = 0;
+	} else if (rate >= 22501) {
+		state->deci = 0; state->csel = 1; state->rsel = 1;
+	} else if (rate >= 18751) {
+		state->deci = 1; state->csel = 0; state->rsel = 0;
+	} else if (rate >= 15001) {
+		state->deci = 1; state->csel = 0; state->rsel = 1;
+	} else if (rate >= 13126) {
+		state->deci = 1; state->csel = 1; state->rsel = 0;
+	} else if (rate >= 11251) {
+		state->deci = 1; state->csel = 1; state->rsel = 1;
+	} else if (rate >= 9376) {
+		state->deci = 2; state->csel = 0; state->rsel = 0;
+	} else if (rate >= 7501) {
+		state->deci = 2; state->csel = 0; state->rsel = 1;
+	} else if (rate >= 6563) {
+		state->deci = 2; state->csel = 1; state->rsel = 0;
+	} else if (rate >= 5626) {
+		state->deci = 2; state->csel = 1; state->rsel = 1;
+	} else if (rate >= 4688) {
+		state->deci = 3; state->csel = 0; state->rsel = 0;
+	} else if (rate >= 3751) {
+		state->deci = 3; state->csel = 0; state->rsel = 1;
+	} else if (rate >= 3282) {
+		state->deci = 3; state->csel = 1; state->rsel = 0;
+	} else if (rate >= 2814) {
+		state->deci = 3; state->csel = 1; state->rsel = 1;
+	} else if (rate >= 2344) {
+		state->deci = 4; state->csel = 0; state->rsel = 0;
+	} else if (rate >= 1876) {
+		state->deci = 4; state->csel = 0; state->rsel = 1;
+	} else if (rate >= 1641) {
+		state->deci = 4; state->csel = 1; state->rsel = 0;
+	} else if (rate >= 1407) {
+		state->deci = 4; state->csel = 1; state->rsel = 1;
+	} else if (rate >= 1172) {
+		state->deci = 5; state->csel = 0; state->rsel = 0;
+	} else if (rate >=  939) {
+		state->deci = 5; state->csel = 0; state->rsel = 1;
+	} else if (rate >=  821) {
+		state->deci = 5; state->csel = 1; state->rsel = 0;
+	} else {
+		state->deci = 5; state->csel = 1; state->rsel = 1;
+	}
+
+	if (state->csel == 0)
+		state->master_clk = 92000;
+	else
+		state->master_clk = 61333;
+
+}
+
+static int signal_det(struct mb86a16_state *state,
+		      int smrt,
+		      unsigned char *SIG)
+{
+
+	int ret ;
+	int smrtd ;
+	int wait_sym ;
+
+	u32 wait_t;
+	unsigned char S[3] ;
+	int i ;
+
+	if (*SIG > 45) {
+		if (CNTM_set(state, 2, 1, 2) < 0) {
+			dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
+			return -1;
+		}
+		wait_sym = 40000;
+	} else {
+		if (CNTM_set(state, 3, 1, 2) < 0) {
+			dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
+			return -1;
+		}
+		wait_sym = 80000;
+	}
+	for (i = 0; i < 3; i++) {
+		if (i == 0)
+			smrtd = smrt * 98 / 100;
+		else if (i == 1)
+			smrtd = smrt;
+		else
+			smrtd = smrt * 102 / 100;
+		smrt_info_get(state, smrtd);
+		smrt_set(state, smrtd);
+		srst(state);
+		wait_t = (wait_sym + 99 * smrtd / 100) / smrtd;
+		if (wait_t == 0)
+			wait_t = 1;
+		msleep_interruptible(10);
+		if (mb86a16_read(state, 0x37, &(S[i])) != 2) {
+			dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+			return -EREMOTEIO;
+		}
+	}
+	if ((S[1] > S[0] * 112 / 100) &&
+	    (S[1] > S[2] * 112 / 100)) {
+
+		ret = 1;
+	} else {
+		ret = 0;
+	}
+	*SIG = S[1];
+
+	if (CNTM_set(state, 0, 1, 2) < 0) {
+		dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
+		return -1;
+	}
+
+	return ret;
+}
+
+static int rf_val_set(struct mb86a16_state *state,
+		      int f,
+		      int smrt,
+		      unsigned char R)
+{
+	unsigned char C, F, B;
+	int M;
+	unsigned char rf_val[5];
+	int ack = -1;
+
+	if (smrt > 37750)
+		C = 1;
+	else if (smrt > 18875)
+		C = 2;
+	else if (smrt > 5500)
+		C = 3;
+	else
+		C = 4;
+
+	if (smrt > 30500)
+		F = 3;
+	else if (smrt > 9375)
+		F = 1;
+	else if (smrt > 4625)
+		F = 0;
+	else
+		F = 2;
+
+	if (f < 1060)
+		B = 0;
+	else if (f < 1175)
+		B = 1;
+	else if (f < 1305)
+		B = 2;
+	else if (f < 1435)
+		B = 3;
+	else if (f < 1570)
+		B = 4;
+	else if (f < 1715)
+		B = 5;
+	else if (f < 1845)
+		B = 6;
+	else if (f < 1980)
+		B = 7;
+	else if (f < 2080)
+		B = 8;
+	else
+		B = 9;
+
+	M = f * (1 << R) / 2;
+
+	rf_val[0] = 0x01 | (C << 3) | (F << 1);
+	rf_val[1] = (R << 5) | ((M & 0x1f000) >> 12);
+	rf_val[2] = (M & 0x00ff0) >> 4;
+	rf_val[3] = ((M & 0x0000f) << 4) | B;
+
+	/* Frequency Set */
+	if (mb86a16_write(state, 0x21, rf_val[0]) < 0)
+		ack = 0;
+	if (mb86a16_write(state, 0x22, rf_val[1]) < 0)
+		ack = 0;
+	if (mb86a16_write(state, 0x23, rf_val[2]) < 0)
+		ack = 0;
+	if (mb86a16_write(state, 0x24, rf_val[3]) < 0)
+		ack = 0;
+	if (mb86a16_write(state, 0x25, 0x01) < 0)
+		ack = 0;
+	if (ack == 0) {
+		dprintk(verbose, MB86A16_ERROR, 1, "RF Setup - I2C transfer error");
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int afcerr_chk(struct mb86a16_state *state)
+{
+	unsigned char AFCM_L, AFCM_H ;
+	int AFCM ;
+	int afcm, afcerr ;
+
+	if (mb86a16_read(state, 0x0e, &AFCM_L) != 2)
+		goto err;
+	if (mb86a16_read(state, 0x0f, &AFCM_H) != 2)
+		goto err;
+
+	AFCM = (AFCM_H << 8) + AFCM_L;
+
+	if (AFCM > 2048)
+		afcm = AFCM - 4096;
+	else
+		afcm = AFCM;
+	afcerr = afcm * state->master_clk / 8192;
+
+	return afcerr;
+
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+}
+
+static int dagcm_val_get(struct mb86a16_state *state)
+{
+	int DAGCM;
+	unsigned char DAGCM_H, DAGCM_L;
+
+	if (mb86a16_read(state, 0x45, &DAGCM_L) != 2)
+		goto err;
+	if (mb86a16_read(state, 0x46, &DAGCM_H) != 2)
+		goto err;
+
+	DAGCM = (DAGCM_H << 8) + DAGCM_L;
+
+	return DAGCM;
+
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+}
+
+static int mb86a16_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	u8 stat, stat2;
+	struct mb86a16_state *state = fe->demodulator_priv;
+
+	*status = 0;
+
+	if (mb86a16_read(state, MB86A16_SIG1, &stat) != 2)
+		goto err;
+	if (mb86a16_read(state, MB86A16_SIG2, &stat2) != 2)
+		goto err;
+	if ((stat > 25) && (stat2 > 25))
+		*status |= FE_HAS_SIGNAL;
+	if ((stat > 45) && (stat2 > 45))
+		*status |= FE_HAS_CARRIER;
+
+	if (mb86a16_read(state, MB86A16_STATUS, &stat) != 2)
+		goto err;
+
+	if (stat & 0x01)
+		*status |= FE_HAS_SYNC;
+	if (stat & 0x01)
+		*status |= FE_HAS_VITERBI;
+
+	if (mb86a16_read(state, MB86A16_FRAMESYNC, &stat) != 2)
+		goto err;
+
+	if ((stat & 0x0f) && (*status & FE_HAS_VITERBI))
+		*status |= FE_HAS_LOCK;
+
+	return 0;
+
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+}
+
+static int sync_chk(struct mb86a16_state *state,
+		    unsigned char *VIRM)
+{
+	unsigned char val;
+	int sync;
+
+	if (mb86a16_read(state, 0x0d, &val) != 2)
+		goto err;
+
+	dprintk(verbose, MB86A16_INFO, 1, "Status = %02x,", val);
+	sync = val & 0x01;
+	*VIRM = (val & 0x1c) >> 2;
+
+	return sync;
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+
+}
+
+static int freqerr_chk(struct mb86a16_state *state,
+		       int fTP,
+		       int smrt,
+		       int unit)
+{
+	unsigned char CRM, AFCML, AFCMH;
+	unsigned char temp1, temp2, temp3;
+	int crm, afcm, AFCM;
+	int crrerr, afcerr;		/* kHz */
+	int frqerr;			/* MHz */
+	int afcen, afcexen = 0;
+	int R, M, fOSC, fOSC_OFS;
+
+	if (mb86a16_read(state, 0x43, &CRM) != 2)
+		goto err;
+
+	if (CRM > 127)
+		crm = CRM - 256;
+	else
+		crm = CRM;
+
+	crrerr = smrt * crm / 256;
+	if (mb86a16_read(state, 0x49, &temp1) != 2)
+		goto err;
+
+	afcen = (temp1 & 0x04) >> 2;
+	if (afcen == 0) {
+		if (mb86a16_read(state, 0x2a, &temp1) != 2)
+			goto err;
+		afcexen = (temp1 & 0x20) >> 5;
+	}
+
+	if (afcen == 1) {
+		if (mb86a16_read(state, 0x0e, &AFCML) != 2)
+			goto err;
+		if (mb86a16_read(state, 0x0f, &AFCMH) != 2)
+			goto err;
+	} else if (afcexen == 1) {
+		if (mb86a16_read(state, 0x2b, &AFCML) != 2)
+			goto err;
+		if (mb86a16_read(state, 0x2c, &AFCMH) != 2)
+			goto err;
+	}
+	if ((afcen == 1) || (afcexen == 1)) {
+		smrt_info_get(state, smrt);
+		AFCM = ((AFCMH & 0x01) << 8) + AFCML;
+		if (AFCM > 255)
+			afcm = AFCM - 512;
+		else
+			afcm = AFCM;
+
+		afcerr = afcm * state->master_clk / 8192;
+	} else
+		afcerr = 0;
+
+	if (mb86a16_read(state, 0x22, &temp1) != 2)
+		goto err;
+	if (mb86a16_read(state, 0x23, &temp2) != 2)
+		goto err;
+	if (mb86a16_read(state, 0x24, &temp3) != 2)
+		goto err;
+
+	R = (temp1 & 0xe0) >> 5;
+	M = ((temp1 & 0x1f) << 12) + (temp2 << 4) + (temp3 >> 4);
+	if (R == 0)
+		fOSC = 2 * M;
+	else
+		fOSC = M;
+
+	fOSC_OFS = fOSC - fTP;
+
+	if (unit == 0) {	/* MHz */
+		if (crrerr + afcerr + fOSC_OFS * 1000 >= 0)
+			frqerr = (crrerr + afcerr + fOSC_OFS * 1000 + 500) / 1000;
+		else
+			frqerr = (crrerr + afcerr + fOSC_OFS * 1000 - 500) / 1000;
+	} else {	/* kHz */
+		frqerr = crrerr + afcerr + fOSC_OFS * 1000;
+	}
+
+	return frqerr;
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+}
+
+static unsigned char vco_dev_get(struct mb86a16_state *state, int smrt)
+{
+	unsigned char R;
+
+	if (smrt > 9375)
+		R = 0;
+	else
+		R = 1;
+
+	return R;
+}
+
+static void swp_info_get(struct mb86a16_state *state,
+			 int fOSC_start,
+			 int smrt,
+			 int v, int R,
+			 int swp_ofs,
+			 int *fOSC,
+			 int *afcex_freq,
+			 unsigned char *AFCEX_L,
+			 unsigned char *AFCEX_H)
+{
+	int AFCEX ;
+	int crnt_swp_freq ;
+
+	crnt_swp_freq = fOSC_start * 1000 + v * swp_ofs;
+
+	if (R == 0)
+		*fOSC = (crnt_swp_freq + 1000) / 2000 * 2;
+	else
+		*fOSC = (crnt_swp_freq + 500) / 1000;
+
+	if (*fOSC >= crnt_swp_freq)
+		*afcex_freq = *fOSC * 1000 - crnt_swp_freq;
+	else
+		*afcex_freq = crnt_swp_freq - *fOSC * 1000;
+
+	AFCEX = *afcex_freq * 8192 / state->master_clk;
+	*AFCEX_L =  AFCEX & 0x00ff;
+	*AFCEX_H = (AFCEX & 0x0f00) >> 8;
+}
+
+
+static int swp_freq_calcuation(struct mb86a16_state *state, int i, int v, int *V,  int vmax, int vmin,
+			       int SIGMIN, int fOSC, int afcex_freq, int swp_ofs, unsigned char *SIG1)
+{
+	int swp_freq ;
+
+	if ((i % 2 == 1) && (v <= vmax)) {
+		/* positive v (case 1) */
+		if ((v - 1 == vmin)				&&
+		    (*(V + 30 + v) >= 0)			&&
+		    (*(V + 30 + v - 1) >= 0)			&&
+		    (*(V + 30 + v - 1) > *(V + 30 + v))		&&
+		    (*(V + 30 + v - 1) > SIGMIN)) {
+
+			swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
+			*SIG1 = *(V + 30 + v - 1);
+		} else if ((v == vmax)				&&
+			   (*(V + 30 + v) >= 0)			&&
+			   (*(V + 30 + v - 1) >= 0)		&&
+			   (*(V + 30 + v) > *(V + 30 + v - 1))	&&
+			   (*(V + 30 + v) > SIGMIN)) {
+			/* (case 2) */
+			swp_freq = fOSC * 1000 + afcex_freq;
+			*SIG1 = *(V + 30 + v);
+		} else if ((*(V + 30 + v) > 0)			&&
+			   (*(V + 30 + v - 1) > 0)		&&
+			   (*(V + 30 + v - 2) > 0)		&&
+			   (*(V + 30 + v - 3) > 0)		&&
+			   (*(V + 30 + v - 1) > *(V + 30 + v))	&&
+			   (*(V + 30 + v - 2) > *(V + 30 + v - 3)) &&
+			   ((*(V + 30 + v - 1) > SIGMIN)	||
+			   (*(V + 30 + v - 2) > SIGMIN))) {
+			/* (case 3) */
+			if (*(V + 30 + v - 1) >= *(V + 30 + v - 2)) {
+				swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
+				*SIG1 = *(V + 30 + v - 1);
+			} else {
+				swp_freq = fOSC * 1000 + afcex_freq - swp_ofs * 2;
+				*SIG1 = *(V + 30 + v - 2);
+			}
+		} else if ((v == vmax)				&&
+			   (*(V + 30 + v) >= 0)			&&
+			   (*(V + 30 + v - 1) >= 0)		&&
+			   (*(V + 30 + v - 2) >= 0)		&&
+			   (*(V + 30 + v) > *(V + 30 + v - 2))	&&
+			   (*(V + 30 + v - 1) > *(V + 30 + v - 2)) &&
+			   ((*(V + 30 + v) > SIGMIN)		||
+			   (*(V + 30 + v - 1) > SIGMIN))) {
+			/* (case 4) */
+			if (*(V + 30 + v) >= *(V + 30 + v - 1)) {
+				swp_freq = fOSC * 1000 + afcex_freq;
+				*SIG1 = *(V + 30 + v);
+			} else {
+				swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
+				*SIG1 = *(V + 30 + v - 1);
+			}
+		} else  {
+			swp_freq = -1 ;
+		}
+	} else if ((i % 2 == 0) && (v >= vmin)) {
+		/* Negative v (case 1) */
+		if ((*(V + 30 + v) > 0)				&&
+		    (*(V + 30 + v + 1) > 0)			&&
+		    (*(V + 30 + v + 2) > 0)			&&
+		    (*(V + 30 + v + 1) > *(V + 30 + v))		&&
+		    (*(V + 30 + v + 1) > *(V + 30 + v + 2))	&&
+		    (*(V + 30 + v + 1) > SIGMIN)) {
+
+			swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+			*SIG1 = *(V + 30 + v + 1);
+		} else if ((v + 1 == vmax)			&&
+			   (*(V + 30 + v) >= 0)			&&
+			   (*(V + 30 + v + 1) >= 0)		&&
+			   (*(V + 30 + v + 1) > *(V + 30 + v))	&&
+			   (*(V + 30 + v + 1) > SIGMIN)) {
+			/* (case 2) */
+			swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+			*SIG1 = *(V + 30 + v);
+		} else if ((v == vmin)				&&
+			   (*(V + 30 + v) > 0)			&&
+			   (*(V + 30 + v + 1) > 0)		&&
+			   (*(V + 30 + v + 2) > 0)		&&
+			   (*(V + 30 + v) > *(V + 30 + v + 1))	&&
+			   (*(V + 30 + v) > *(V + 30 + v + 2))	&&
+			   (*(V + 30 + v) > SIGMIN)) {
+			/* (case 3) */
+			swp_freq = fOSC * 1000 + afcex_freq;
+			*SIG1 = *(V + 30 + v);
+		} else if ((*(V + 30 + v) >= 0)			&&
+			   (*(V + 30 + v + 1) >= 0)		&&
+			   (*(V + 30 + v + 2) >= 0)		&&
+			   (*(V + 30 + v + 3) >= 0)		&&
+			   (*(V + 30 + v + 1) > *(V + 30 + v))	&&
+			   (*(V + 30 + v + 2) > *(V + 30 + v + 3)) &&
+			   ((*(V + 30 + v + 1) > SIGMIN)	||
+			    (*(V + 30 + v + 2) > SIGMIN))) {
+			/* (case 4) */
+			if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) {
+				swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+				*SIG1 = *(V + 30 + v + 1);
+			} else {
+				swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2;
+				*SIG1 = *(V + 30 + v + 2);
+			}
+		} else if ((*(V + 30 + v) >= 0)			&&
+			   (*(V + 30 + v + 1) >= 0)		&&
+			   (*(V + 30 + v + 2) >= 0)		&&
+			   (*(V + 30 + v + 3) >= 0)		&&
+			   (*(V + 30 + v) > *(V + 30 + v + 2))	&&
+			   (*(V + 30 + v + 1) > *(V + 30 + v + 2)) &&
+			   (*(V + 30 + v) > *(V + 30 + v + 3))	&&
+			   (*(V + 30 + v + 1) > *(V + 30 + v + 3)) &&
+			   ((*(V + 30 + v) > SIGMIN)		||
+			    (*(V + 30 + v + 1) > SIGMIN))) {
+			/* (case 5) */
+			if (*(V + 30 + v) >= *(V + 30 + v + 1)) {
+				swp_freq = fOSC * 1000 + afcex_freq;
+				*SIG1 = *(V + 30 + v);
+			} else {
+				swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+				*SIG1 = *(V + 30 + v + 1);
+			}
+		} else if ((v + 2 == vmin)			&&
+			   (*(V + 30 + v) >= 0)			&&
+			   (*(V + 30 + v + 1) >= 0)		&&
+			   (*(V + 30 + v + 2) >= 0)		&&
+			   (*(V + 30 + v + 1) > *(V + 30 + v))	&&
+			   (*(V + 30 + v + 2) > *(V + 30 + v))	&&
+			   ((*(V + 30 + v + 1) > SIGMIN)	||
+			    (*(V + 30 + v + 2) > SIGMIN))) {
+			/* (case 6) */
+			if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) {
+				swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+				*SIG1 = *(V + 30 + v + 1);
+			} else {
+				swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2;
+				*SIG1 = *(V + 30 + v + 2);
+			}
+		} else if ((vmax == 0) && (vmin == 0) && (*(V + 30 + v) > SIGMIN)) {
+			swp_freq = fOSC * 1000;
+			*SIG1 = *(V + 30 + v);
+		} else
+			swp_freq = -1;
+	} else
+		swp_freq = -1;
+
+	return swp_freq;
+}
+
+static void swp_info_get2(struct mb86a16_state *state,
+			  int smrt,
+			  int R,
+			  int swp_freq,
+			  int *afcex_freq,
+			  int *fOSC,
+			  unsigned char *AFCEX_L,
+			  unsigned char *AFCEX_H)
+{
+	int AFCEX ;
+
+	if (R == 0)
+		*fOSC = (swp_freq + 1000) / 2000 * 2;
+	else
+		*fOSC = (swp_freq + 500) / 1000;
+
+	if (*fOSC >= swp_freq)
+		*afcex_freq = *fOSC * 1000 - swp_freq;
+	else
+		*afcex_freq = swp_freq - *fOSC * 1000;
+
+	AFCEX = *afcex_freq * 8192 / state->master_clk;
+	*AFCEX_L =  AFCEX & 0x00ff;
+	*AFCEX_H = (AFCEX & 0x0f00) >> 8;
+}
+
+static void afcex_info_get(struct mb86a16_state *state,
+			   int afcex_freq,
+			   unsigned char *AFCEX_L,
+			   unsigned char *AFCEX_H)
+{
+	int AFCEX ;
+
+	AFCEX = afcex_freq * 8192 / state->master_clk;
+	*AFCEX_L =  AFCEX & 0x00ff;
+	*AFCEX_H = (AFCEX & 0x0f00) >> 8;
+}
+
+static int SEQ_set(struct mb86a16_state *state, unsigned char loop)
+{
+	/* SLOCK0 = 0 */
+	if (mb86a16_write(state, 0x32, 0x02 | (loop << 2)) < 0) {
+		dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int iq_vt_set(struct mb86a16_state *state, unsigned char IQINV)
+{
+	/* Viterbi Rate, IQ Settings */
+	if (mb86a16_write(state, 0x06, 0xdf | (IQINV << 5)) < 0) {
+		dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int FEC_srst(struct mb86a16_state *state)
+{
+	if (mb86a16_write(state, MB86A16_RESET, 0x02) < 0) {
+		dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int S2T_set(struct mb86a16_state *state, unsigned char S2T)
+{
+	if (mb86a16_write(state, 0x34, 0x70 | S2T) < 0) {
+		dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int S45T_set(struct mb86a16_state *state, unsigned char S4T, unsigned char S5T)
+{
+	if (mb86a16_write(state, 0x35, 0x00 | (S5T << 4) | S4T) < 0) {
+		dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+
+static int mb86a16_set_fe(struct mb86a16_state *state)
+{
+	u8 agcval, cnmval;
+
+	int i, j;
+	int fOSC = 0;
+	int fOSC_start = 0;
+	int wait_t;
+	int fcp;
+	int swp_ofs;
+	int V[60];
+	u8 SIG1MIN;
+
+	unsigned char CREN, AFCEN, AFCEXEN;
+	unsigned char SIG1;
+	unsigned char TIMINT1, TIMINT2, TIMEXT;
+	unsigned char S0T, S1T;
+	unsigned char S2T;
+/*	unsigned char S2T, S3T; */
+	unsigned char S4T, S5T;
+	unsigned char AFCEX_L, AFCEX_H;
+	unsigned char R;
+	unsigned char VIRM;
+	unsigned char ETH, VIA;
+	unsigned char junk;
+
+	int loop;
+	int ftemp;
+	int v, vmax, vmin;
+	int vmax_his, vmin_his;
+	int swp_freq, prev_swp_freq[20];
+	int prev_freq_num;
+	int signal_dupl;
+	int afcex_freq;
+	int signal;
+	int afcerr;
+	int temp_freq, delta_freq;
+	int dagcm[4];
+	int smrt_d;
+/*	int freq_err; */
+	int n;
+	int ret = -1;
+	int sync;
+
+	dprintk(verbose, MB86A16_INFO, 1, "freq=%d Mhz, symbrt=%d Ksps", state->frequency, state->srate);
+
+	fcp = 3000;
+	swp_ofs = state->srate / 4;
+
+	for (i = 0; i < 60; i++)
+		V[i] = -1;
+
+	for (i = 0; i < 20; i++)
+		prev_swp_freq[i] = 0;
+
+	SIG1MIN = 25;
+
+	for (n = 0; ((n < 3) && (ret == -1)); n++) {
+		SEQ_set(state, 0);
+		iq_vt_set(state, 0);
+
+		CREN = 0;
+		AFCEN = 0;
+		AFCEXEN = 1;
+		TIMINT1 = 0;
+		TIMINT2 = 1;
+		TIMEXT = 2;
+		S1T = 0;
+		S0T = 0;
+
+		if (initial_set(state) < 0) {
+			dprintk(verbose, MB86A16_ERROR, 1, "initial set failed");
+			return -1;
+		}
+		if (DAGC_data_set(state, 3, 2) < 0) {
+			dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
+			return -1;
+		}
+		if (EN_set(state, CREN, AFCEN) < 0) {
+			dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
+			return -1; /* (0, 0) */
+		}
+		if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
+			dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+			return -1; /* (1, smrt) = (1, symbolrate) */
+		}
+		if (CNTM_set(state, TIMINT1, TIMINT2, TIMEXT) < 0) {
+			dprintk(verbose, MB86A16_ERROR, 1, "CNTM set error");
+			return -1; /* (0, 1, 2) */
+		}
+		if (S01T_set(state, S1T, S0T) < 0) {
+			dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
+			return -1; /* (0, 0) */
+		}
+		smrt_info_get(state, state->srate);
+		if (smrt_set(state, state->srate) < 0) {
+			dprintk(verbose, MB86A16_ERROR, 1, "smrt info get error");
+			return -1;
+		}
+
+		R = vco_dev_get(state, state->srate);
+		if (R == 1)
+			fOSC_start = state->frequency;
+
+		else if (R == 0) {
+			if (state->frequency % 2 == 0) {
+				fOSC_start = state->frequency;
+			} else {
+				fOSC_start = state->frequency + 1;
+				if (fOSC_start > 2150)
+					fOSC_start = state->frequency - 1;
+			}
+		}
+		loop = 1;
+		ftemp = fOSC_start * 1000;
+		vmax = 0 ;
+		while (loop == 1) {
+			ftemp = ftemp + swp_ofs;
+			vmax++;
+
+			/* Upper bound */
+			if (ftemp > 2150000) {
+				loop = 0;
+				vmax--;
+			} else {
+				if ((ftemp == 2150000) ||
+				    (ftemp - state->frequency * 1000 >= fcp + state->srate / 4))
+					loop = 0;
+			}
+		}
+
+		loop = 1;
+		ftemp = fOSC_start * 1000;
+		vmin = 0 ;
+		while (loop == 1) {
+			ftemp = ftemp - swp_ofs;
+			vmin--;
+
+			/* Lower bound */
+			if (ftemp < 950000) {
+				loop = 0;
+				vmin++;
+			} else {
+				if ((ftemp == 950000) ||
+				    (state->frequency * 1000 - ftemp >= fcp + state->srate / 4))
+					loop = 0;
+			}
+		}
+
+		wait_t = (8000 + state->srate / 2) / state->srate;
+		if (wait_t == 0)
+			wait_t = 1;
+
+		i = 0;
+		j = 0;
+		prev_freq_num = 0;
+		loop = 1;
+		signal = 0;
+		vmax_his = 0;
+		vmin_his = 0;
+		v = 0;
+
+		while (loop == 1) {
+			swp_info_get(state, fOSC_start, state->srate,
+				     v, R, swp_ofs, &fOSC,
+				     &afcex_freq, &AFCEX_L, &AFCEX_H);
+
+			udelay(100);
+			if (rf_val_set(state, fOSC, state->srate, R) < 0) {
+				dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+				return -1;
+			}
+			udelay(100);
+			if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+				dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+				return -1;
+			}
+			if (srst(state) < 0) {
+				dprintk(verbose, MB86A16_ERROR, 1, "srst error");
+				return -1;
+			}
+			msleep_interruptible(wait_t);
+
+			if (mb86a16_read(state, 0x37, &SIG1) != 2) {
+				dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+				return -1;
+			}
+			V[30 + v] = SIG1 ;
+			swp_freq = swp_freq_calcuation(state, i, v, V, vmax, vmin,
+						      SIG1MIN, fOSC, afcex_freq,
+						      swp_ofs, &SIG1);	/* changed */
+
+			signal_dupl = 0;
+			for (j = 0; j < prev_freq_num; j++) {
+				if ((ABS(prev_swp_freq[j] - swp_freq)) < (swp_ofs * 3 / 2)) {
+					signal_dupl = 1;
+					dprintk(verbose, MB86A16_INFO, 1, "Probably Duplicate Signal, j = %d", j);
+				}
+			}
+			if ((signal_dupl == 0) && (swp_freq > 0) && (ABS(swp_freq - state->frequency * 1000) < fcp + state->srate / 6)) {
+				dprintk(verbose, MB86A16_DEBUG, 1, "------ Signal detect ------ [swp_freq=[%07d, srate=%05d]]", swp_freq, state->srate);
+				prev_swp_freq[prev_freq_num] = swp_freq;
+				prev_freq_num++;
+				swp_info_get2(state, state->srate, R, swp_freq,
+					      &afcex_freq, &fOSC,
+					      &AFCEX_L, &AFCEX_H);
+
+				if (rf_val_set(state, fOSC, state->srate, R) < 0) {
+					dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+					return -1;
+				}
+				if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+					dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+					return -1;
+				}
+				signal = signal_det(state, state->srate, &SIG1);
+				if (signal == 1) {
+					dprintk(verbose, MB86A16_ERROR, 1, "***** Signal Found *****");
+					loop = 0;
+				} else {
+					dprintk(verbose, MB86A16_ERROR, 1, "!!!!! No signal !!!!!, try again...");
+					smrt_info_get(state, state->srate);
+					if (smrt_set(state, state->srate) < 0) {
+						dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+						return -1;
+					}
+				}
+			}
+			if (v > vmax)
+				vmax_his = 1 ;
+			if (v < vmin)
+				vmin_his = 1 ;
+			i++;
+
+			if ((i % 2 == 1) && (vmax_his == 1))
+				i++;
+			if ((i % 2 == 0) && (vmin_his == 1))
+				i++;
+
+			if (i % 2 == 1)
+				v = (i + 1) / 2;
+			else
+				v = -i / 2;
+
+			if ((vmax_his == 1) && (vmin_his == 1))
+				loop = 0 ;
+		}
+
+		if (signal == 1) {
+			dprintk(verbose, MB86A16_INFO, 1, " Start Freq Error Check");
+			S1T = 7 ;
+			S0T = 1 ;
+			CREN = 0 ;
+			AFCEN = 1 ;
+			AFCEXEN = 0 ;
+
+			if (S01T_set(state, S1T, S0T) < 0) {
+				dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
+				return -1;
+			}
+			smrt_info_get(state, state->srate);
+			if (smrt_set(state, state->srate) < 0) {
+				dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+				return -1;
+			}
+			if (EN_set(state, CREN, AFCEN) < 0) {
+				dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
+				return -1;
+			}
+			if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
+				dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+				return -1;
+			}
+			afcex_info_get(state, afcex_freq, &AFCEX_L, &AFCEX_H);
+			if (afcofs_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+				dprintk(verbose, MB86A16_ERROR, 1, "AFCOFS data set error");
+				return -1;
+			}
+			if (srst(state) < 0) {
+				dprintk(verbose, MB86A16_ERROR, 1, "srst error");
+				return -1;
+			}
+			/* delay 4~200 */
+			wait_t = 200000 / state->master_clk + 200000 / state->srate;
+			msleep(wait_t);
+			afcerr = afcerr_chk(state);
+			if (afcerr == -1)
+				return -1;
+
+			swp_freq = fOSC * 1000 + afcerr ;
+			AFCEXEN = 1 ;
+			if (state->srate >= 1500)
+				smrt_d = state->srate / 3;
+			else
+				smrt_d = state->srate / 2;
+			smrt_info_get(state, smrt_d);
+			if (smrt_set(state, smrt_d) < 0) {
+				dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+				return -1;
+			}
+			if (AFCEXEN_set(state, AFCEXEN, smrt_d) < 0) {
+				dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+				return -1;
+			}
+			R = vco_dev_get(state, smrt_d);
+			if (DAGC_data_set(state, 2, 0) < 0) {
+				dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
+				return -1;
+			}
+			for (i = 0; i < 3; i++) {
+				temp_freq = swp_freq + (i - 1) * state->srate / 8;
+				swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+				if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
+					dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+					return -1;
+				}
+				if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+					dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+					return -1;
+				}
+				wait_t = 200000 / state->master_clk + 40000 / smrt_d;
+				msleep(wait_t);
+				dagcm[i] = dagcm_val_get(state);
+			}
+			if ((dagcm[0] > dagcm[1]) &&
+			    (dagcm[0] > dagcm[2]) &&
+			    (dagcm[0] - dagcm[1] > 2 * (dagcm[2] - dagcm[1]))) {
+
+				temp_freq = swp_freq - 2 * state->srate / 8;
+				swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+				if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
+					dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+					return -1;
+				}
+				if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+					dprintk(verbose, MB86A16_ERROR, 1, "afcex data set");
+					return -1;
+				}
+				wait_t = 200000 / state->master_clk + 40000 / smrt_d;
+				msleep(wait_t);
+				dagcm[3] = dagcm_val_get(state);
+				if (dagcm[3] > dagcm[1])
+					delta_freq = (dagcm[2] - dagcm[0] + dagcm[1] - dagcm[3]) * state->srate / 300;
+				else
+					delta_freq = 0;
+			} else if ((dagcm[2] > dagcm[1]) &&
+				   (dagcm[2] > dagcm[0]) &&
+				   (dagcm[2] - dagcm[1] > 2 * (dagcm[0] - dagcm[1]))) {
+
+				temp_freq = swp_freq + 2 * state->srate / 8;
+				swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+				if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
+					dprintk(verbose, MB86A16_ERROR, 1, "rf val set");
+					return -1;
+				}
+				if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+					dprintk(verbose, MB86A16_ERROR, 1, "afcex data set");
+					return -1;
+				}
+				wait_t = 200000 / state->master_clk + 40000 / smrt_d;
+				msleep(wait_t);
+				dagcm[3] = dagcm_val_get(state);
+				if (dagcm[3] > dagcm[1])
+					delta_freq = (dagcm[2] - dagcm[0] + dagcm[3] - dagcm[1]) * state->srate / 300;
+				else
+					delta_freq = 0 ;
+
+			} else {
+				delta_freq = 0 ;
+			}
+			dprintk(verbose, MB86A16_INFO, 1, "SWEEP Frequency = %d", swp_freq);
+			swp_freq += delta_freq;
+			dprintk(verbose, MB86A16_INFO, 1, "Adjusting .., DELTA Freq = %d, SWEEP Freq=%d", delta_freq, swp_freq);
+			if (ABS(state->frequency * 1000 - swp_freq) > 3800) {
+				dprintk(verbose, MB86A16_INFO, 1, "NO  --  SIGNAL !");
+			} else {
+
+				S1T = 0;
+				S0T = 3;
+				CREN = 1;
+				AFCEN = 0;
+				AFCEXEN = 1;
+
+				if (S01T_set(state, S1T, S0T) < 0) {
+					dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
+					return -1;
+				}
+				if (DAGC_data_set(state, 0, 0) < 0) {
+					dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
+					return -1;
+				}
+				R = vco_dev_get(state, state->srate);
+				smrt_info_get(state, state->srate);
+				if (smrt_set(state, state->srate) < 0) {
+					dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+					return -1;
+				}
+				if (EN_set(state, CREN, AFCEN) < 0) {
+					dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
+					return -1;
+				}
+				if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
+					dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+					return -1;
+				}
+				swp_info_get2(state, state->srate, R, swp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+				if (rf_val_set(state, fOSC, state->srate, R) < 0) {
+					dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+					return -1;
+				}
+				if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+					dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+					return -1;
+				}
+				if (srst(state) < 0) {
+					dprintk(verbose, MB86A16_ERROR, 1, "srst error");
+					return -1;
+				}
+				wait_t = 7 + (10000 + state->srate / 2) / state->srate;
+				if (wait_t == 0)
+					wait_t = 1;
+				msleep_interruptible(wait_t);
+				if (mb86a16_read(state, 0x37, &SIG1) != 2) {
+					dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+					return -EREMOTEIO;
+				}
+
+				if (SIG1 > 110) {
+					S2T = 4; S4T = 1; S5T = 6; ETH = 4; VIA = 6;
+					wait_t = 7 + (917504 + state->srate / 2) / state->srate;
+				} else if (SIG1 > 105) {
+					S2T = 4; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+					wait_t = 7 + (1048576 + state->srate / 2) / state->srate;
+				} else if (SIG1 > 85) {
+					S2T = 5; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+					wait_t = 7 + (1310720 + state->srate / 2) / state->srate;
+				} else if (SIG1 > 65) {
+					S2T = 6; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+					wait_t = 7 + (1572864 + state->srate / 2) / state->srate;
+				} else {
+					S2T = 7; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+					wait_t = 7 + (2097152 + state->srate / 2) / state->srate;
+				}
+				wait_t *= 2; /* FOS */
+				S2T_set(state, S2T);
+				S45T_set(state, S4T, S5T);
+				Vi_set(state, ETH, VIA);
+				srst(state);
+				msleep_interruptible(wait_t);
+				sync = sync_chk(state, &VIRM);
+				dprintk(verbose, MB86A16_INFO, 1, "-------- Viterbi=[%d] SYNC=[%d] ---------", VIRM, sync);
+				if (VIRM) {
+					if (VIRM == 4) {
+						/* 5/6 */
+						if (SIG1 > 110)
+							wait_t = (786432 + state->srate / 2) / state->srate;
+						else
+							wait_t = (1572864 + state->srate / 2) / state->srate;
+						if (state->srate < 5000)
+							/* FIXME ! , should be a long wait ! */
+							msleep_interruptible(wait_t);
+						else
+							msleep_interruptible(wait_t);
+
+						if (sync_chk(state, &junk) == 0) {
+							iq_vt_set(state, 1);
+							FEC_srst(state);
+						}
+					}
+					/* 1/2, 2/3, 3/4, 7/8 */
+					if (SIG1 > 110)
+						wait_t = (786432 + state->srate / 2) / state->srate;
+					else
+						wait_t = (1572864 + state->srate / 2) / state->srate;
+					msleep_interruptible(wait_t);
+					SEQ_set(state, 1);
+				} else {
+					dprintk(verbose, MB86A16_INFO, 1, "NO  -- SYNC");
+					SEQ_set(state, 1);
+					ret = -1;
+				}
+			}
+		} else {
+			dprintk(verbose, MB86A16_INFO, 1, "NO  -- SIGNAL");
+			ret = -1;
+		}
+
+		sync = sync_chk(state, &junk);
+		if (sync) {
+			dprintk(verbose, MB86A16_INFO, 1, "******* SYNC *******");
+			freqerr_chk(state, state->frequency, state->srate, 1);
+			ret = 0;
+			break;
+		}
+	}
+
+	mb86a16_read(state, 0x15, &agcval);
+	mb86a16_read(state, 0x26, &cnmval);
+	dprintk(verbose, MB86A16_INFO, 1, "AGC = %02x CNM = %02x", agcval, cnmval);
+
+	return ret;
+}
+
+static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe,
+				   struct dvb_diseqc_master_cmd *cmd)
+{
+	struct mb86a16_state *state = fe->demodulator_priv;
+	int i;
+	u8 regs;
+
+	if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0)
+		goto err;
+	if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0)
+		goto err;
+	if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0)
+		goto err;
+
+	regs = 0x18;
+
+	if (cmd->msg_len > 5 || cmd->msg_len < 4)
+		return -EINVAL;
+
+	for (i = 0; i < cmd->msg_len; i++) {
+		if (mb86a16_write(state, regs, cmd->msg[i]) < 0)
+			goto err;
+
+		regs++;
+	}
+	i += 0x90;
+
+	msleep_interruptible(10);
+
+	if (mb86a16_write(state, MB86A16_DCC1, i) < 0)
+		goto err;
+	if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+		goto err;
+
+	return 0;
+
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+}
+
+static int mb86a16_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
+{
+	struct mb86a16_state *state = fe->demodulator_priv;
+
+	switch (burst) {
+	case SEC_MINI_A:
+		if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
+						       MB86A16_DCC1_TBEN  |
+						       MB86A16_DCC1_TBO) < 0)
+			goto err;
+		if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+			goto err;
+		break;
+	case SEC_MINI_B:
+		if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
+						       MB86A16_DCC1_TBEN) < 0)
+			goto err;
+		if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+			goto err;
+		break;
+	}
+
+	return 0;
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+}
+
+static int mb86a16_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct mb86a16_state *state = fe->demodulator_priv;
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		if (mb86a16_write(state, MB86A16_TONEOUT2, 0x00) < 0)
+			goto err;
+		if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
+						       MB86A16_DCC1_CTOE) < 0)
+
+			goto err;
+		if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+			goto err;
+		break;
+	case SEC_TONE_OFF:
+		if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0)
+			goto err;
+		if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0)
+			goto err;
+		if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0)
+			goto err;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+}
+
+static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct mb86a16_state *state = fe->demodulator_priv;
+
+	state->frequency = p->frequency / 1000;
+	state->srate = p->symbol_rate / 1000;
+
+	if (!mb86a16_set_fe(state)) {
+		dprintk(verbose, MB86A16_ERROR, 1, "Successfully acquired LOCK");
+		return DVBFE_ALGO_SEARCH_SUCCESS;
+	}
+
+	dprintk(verbose, MB86A16_ERROR, 1, "Lock acquisition failed!");
+	return DVBFE_ALGO_SEARCH_FAILED;
+}
+
+static void mb86a16_release(struct dvb_frontend *fe)
+{
+	struct mb86a16_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static int mb86a16_init(struct dvb_frontend *fe)
+{
+	return 0;
+}
+
+static int mb86a16_sleep(struct dvb_frontend *fe)
+{
+	return 0;
+}
+
+static int mb86a16_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	u8 ber_mon, ber_tab, ber_lsb, ber_mid, ber_msb, ber_tim, ber_rst;
+	u32 timer;
+
+	struct mb86a16_state *state = fe->demodulator_priv;
+
+	*ber = 0;
+	if (mb86a16_read(state, MB86A16_BERMON, &ber_mon) != 2)
+		goto err;
+	if (mb86a16_read(state, MB86A16_BERTAB, &ber_tab) != 2)
+		goto err;
+	if (mb86a16_read(state, MB86A16_BERLSB, &ber_lsb) != 2)
+		goto err;
+	if (mb86a16_read(state, MB86A16_BERMID, &ber_mid) != 2)
+		goto err;
+	if (mb86a16_read(state, MB86A16_BERMSB, &ber_msb) != 2)
+		goto err;
+	/* BER monitor invalid when BER_EN = 0	*/
+	if (ber_mon & 0x04) {
+		/* coarse, fast calculation	*/
+		*ber = ber_tab & 0x1f;
+		dprintk(verbose, MB86A16_DEBUG, 1, "BER coarse=[0x%02x]", *ber);
+		if (ber_mon & 0x01) {
+			/*
+			 * BER_SEL = 1, The monitored BER is the estimated
+			 * value with a Reed-Solomon decoder error amount at
+			 * the deinterleaver output.
+			 * monitored BER is expressed as a 20 bit output in total
+			 */
+			ber_rst = ber_mon >> 3;
+			*ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb;
+			if (ber_rst == 0)
+				timer =  12500000;
+			if (ber_rst == 1)
+				timer =  25000000;
+			if (ber_rst == 2)
+				timer =  50000000;
+			if (ber_rst == 3)
+				timer = 100000000;
+
+			*ber /= timer;
+			dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber);
+		} else {
+			/*
+			 * BER_SEL = 0, The monitored BER is the estimated
+			 * value with a Viterbi decoder error amount at the
+			 * QPSK demodulator output.
+			 * monitored BER is expressed as a 24 bit output in total
+			 */
+			ber_tim = ber_mon >> 1;
+			*ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb;
+			if (ber_tim == 0)
+				timer = 16;
+			if (ber_tim == 1)
+				timer = 24;
+
+			*ber /= 2 ^ timer;
+			dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber);
+		}
+	}
+	return 0;
+err:
+	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+	return -EREMOTEIO;
+}
+
+static int mb86a16_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	u8 agcm = 0;
+	struct mb86a16_state *state = fe->demodulator_priv;
+
+	*strength = 0;
+	if (mb86a16_read(state, MB86A16_AGCM, &agcm) != 2) {
+		dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+		return -EREMOTEIO;
+	}
+
+	*strength = ((0xff - agcm) * 100) / 256;
+	dprintk(verbose, MB86A16_DEBUG, 1, "Signal strength=[%d %%]", (u8) *strength);
+	*strength = (0xffff - 0xff) + agcm;
+
+	return 0;
+}
+
+struct cnr {
+	u8 cn_reg;
+	u8 cn_val;
+};
+
+static const struct cnr cnr_tab[] = {
+	{  35,  2 },
+	{  40,  3 },
+	{  50,  4 },
+	{  60,  5 },
+	{  70,  6 },
+	{  80,  7 },
+	{  92,  8 },
+	{ 103,  9 },
+	{ 115, 10 },
+	{ 138, 12 },
+	{ 162, 15 },
+	{ 180, 18 },
+	{ 185, 19 },
+	{ 189, 20 },
+	{ 195, 22 },
+	{ 199, 24 },
+	{ 201, 25 },
+	{ 202, 26 },
+	{ 203, 27 },
+	{ 205, 28 },
+	{ 208, 30 }
+};
+
+static int mb86a16_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct mb86a16_state *state = fe->demodulator_priv;
+	int i = 0;
+	int low_tide = 2, high_tide = 30, q_level;
+	u8  cn;
+
+	*snr = 0;
+	if (mb86a16_read(state, 0x26, &cn) != 2) {
+		dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+		return -EREMOTEIO;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cnr_tab); i++) {
+		if (cn < cnr_tab[i].cn_reg) {
+			*snr = cnr_tab[i].cn_val;
+			break;
+		}
+	}
+	q_level = (*snr * 100) / (high_tide - low_tide);
+	dprintk(verbose, MB86A16_ERROR, 1, "SNR (Quality) = [%d dB], Level=%d %%", *snr, q_level);
+	*snr = (0xffff - 0xff) + *snr;
+
+	return 0;
+}
+
+static int mb86a16_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	u8 dist;
+	struct mb86a16_state *state = fe->demodulator_priv;
+
+	if (mb86a16_read(state, MB86A16_DISTMON, &dist) != 2) {
+		dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+		return -EREMOTEIO;
+	}
+	*ucblocks = dist;
+
+	return 0;
+}
+
+static enum dvbfe_algo mb86a16_frontend_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_CUSTOM;
+}
+
+static struct dvb_frontend_ops mb86a16_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name			= "Fujitsu MB86A16 DVB-S",
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 3000,
+		.frequency_tolerance	= 0,
+		.symbol_rate_min	= 1000000,
+		.symbol_rate_max	= 45000000,
+		.symbol_rate_tolerance	= 500,
+		.caps			= FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+					  FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
+					  FE_CAN_FEC_7_8 | FE_CAN_QPSK    |
+					  FE_CAN_FEC_AUTO
+	},
+	.release			= mb86a16_release,
+
+	.get_frontend_algo		= mb86a16_frontend_algo,
+	.search				= mb86a16_search,
+	.init				= mb86a16_init,
+	.sleep				= mb86a16_sleep,
+	.read_status			= mb86a16_read_status,
+
+	.read_ber			= mb86a16_read_ber,
+	.read_signal_strength		= mb86a16_read_signal_strength,
+	.read_snr			= mb86a16_read_snr,
+	.read_ucblocks			= mb86a16_read_ucblocks,
+
+	.diseqc_send_master_cmd		= mb86a16_send_diseqc_msg,
+	.diseqc_send_burst		= mb86a16_send_diseqc_burst,
+	.set_tone			= mb86a16_set_tone,
+};
+
+struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
+				    struct i2c_adapter *i2c_adap)
+{
+	u8 dev_id = 0;
+	struct mb86a16_state *state = NULL;
+
+	state = kmalloc(sizeof(struct mb86a16_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	state->config = config;
+	state->i2c_adap = i2c_adap;
+
+	mb86a16_read(state, 0x7f, &dev_id);
+	if (dev_id != 0xfe)
+		goto error;
+
+	memcpy(&state->frontend.ops, &mb86a16_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	state->frontend.ops.set_voltage = state->config->set_voltage;
+
+	return &state->frontend;
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(mb86a16_attach);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Manu Abraham");
diff --git a/drivers/media/dvb-frontends/mb86a16.h b/drivers/media/dvb-frontends/mb86a16.h
new file mode 100644
index 0000000..6ea8c37
--- /dev/null
+++ b/drivers/media/dvb-frontends/mb86a16.h
@@ -0,0 +1,52 @@
+/*
+	Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MB86A16_H
+#define __MB86A16_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+
+struct mb86a16_config {
+	u8 demod_address;
+
+	int (*set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+};
+
+
+
+#if defined(CONFIG_DVB_MB86A16) || (defined(CONFIG_DVB_MB86A16_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
+					   struct i2c_adapter *i2c_adap);
+
+#else
+
+static inline struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
+					   struct i2c_adapter *i2c_adap)
+{
+	printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+#endif /* CONFIG_DVB_MB86A16 */
+
+#endif /* __MB86A16_H */
diff --git a/drivers/media/dvb-frontends/mb86a16_priv.h b/drivers/media/dvb-frontends/mb86a16_priv.h
new file mode 100644
index 0000000..360a35a
--- /dev/null
+++ b/drivers/media/dvb-frontends/mb86a16_priv.h
@@ -0,0 +1,151 @@
+/*
+	Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MB86A16_PRIV_H
+#define __MB86A16_PRIV_H
+
+#define MB86A16_TSOUT		0x00
+#define MB86A16_TSOUT_HIZSEL	(0x01 << 5)
+#define MB86A16_TSOUT_HIZCNTI	(0x01 << 4)
+#define MB86A16_TSOUT_MODE	(0x01 << 3)
+#define MB86A16_TSOUT_ORDER	(0x01 << 2)
+#define MB86A16_TSOUT_ERROR	(0x01 << 1)
+#define Mb86A16_TSOUT_EDGE	(0x01 << 0)
+
+#define MB86A16_FEC		0x01
+#define MB86A16_FEC_FSYNC	(0x01 << 5)
+#define MB86A16_FEC_PCKB8	(0x01 << 4)
+#define MB86A16_FEC_DVDS	(0x01 << 3)
+#define MB86A16_FEC_EREN	(0x01 << 2)
+#define Mb86A16_FEC_RSEN	(0x01 << 1)
+#define MB86A16_FEC_DIEN	(0x01 << 0)
+
+#define MB86A16_AGC		0x02
+#define MB86A16_AGC_AGMD	(0x01 << 6)
+#define MB86A16_AGC_AGCW	(0x0f << 2)
+#define MB86A16_AGC_AGCP	(0x01 << 1)
+#define MB86A16_AGC_AGCR	(0x01 << 0)
+
+#define MB86A16_SRATE1		0x03
+#define MB86A16_SRATE1_DECI	(0x07 << 2)
+#define MB86A16_SRATE1_CSEL	(0x01 << 1)
+#define MB86A16_SRATE1_RSEL	(0x01 << 0)
+
+#define MB86A16_SRATE2		0x04
+#define MB86A16_SRATE2_STOFSL	(0xff << 0)
+
+#define MB86A16_SRATE3		0x05
+#define MB86A16_SRATE2_STOFSH	(0xff << 0)
+
+#define MB86A16_VITERBI		0x06
+#define MB86A16_FRAMESYNC	0x07
+#define MB86A16_CRLFILTCOEF1	0x08
+#define MB86A16_CRLFILTCOEF2	0x09
+#define MB86A16_STRFILTCOEF1	0x0a
+#define MB86A16_STRFILTCOEF2	0x0b
+#define MB86A16_RESET		0x0c
+#define MB86A16_STATUS		0x0d
+#define MB86A16_AFCML		0x0e
+#define MB86A16_AFCMH		0x0f
+#define MB86A16_BERMON		0x10
+#define MB86A16_BERTAB		0x11
+#define MB86A16_BERLSB		0x12
+#define MB86A16_BERMID		0x13
+#define MB86A16_BERMSB		0x14
+#define MB86A16_AGCM		0x15
+
+#define MB86A16_DCC1		0x16
+#define MB86A16_DCC1_DISTA	(0x01 << 7)
+#define MB86A16_DCC1_PRTY	(0x01 << 6)
+#define MB86A16_DCC1_CTOE	(0x01 << 5)
+#define MB86A16_DCC1_TBEN	(0x01 << 4)
+#define MB86A16_DCC1_TBO	(0x01 << 3)
+#define MB86A16_DCC1_NUM	(0x07 << 0)
+
+#define MB86A16_DCC2		0x17
+#define MB86A16_DCC2_DCBST	(0x01 << 0)
+
+#define MB86A16_DCC3		0x18
+#define MB86A16_DCC3_CODE0	(0xff << 0)
+
+#define MB86A16_DCC4		0x19
+#define MB86A16_DCC4_CODE1	(0xff << 0)
+
+#define MB86A16_DCC5		0x1a
+#define MB86A16_DCC5_CODE2	(0xff << 0)
+
+#define MB86A16_DCC6		0x1b
+#define MB86A16_DCC6_CODE3	(0xff << 0)
+
+#define MB86A16_DCC7		0x1c
+#define MB86A16_DCC7_CODE4	(0xff << 0)
+
+#define MB86A16_DCC8		0x1d
+#define MB86A16_DCC8_CODE5	(0xff << 0)
+
+#define MB86A16_DCCOUT		0x1e
+#define MB86A16_DCCOUT_DISEN	(0x01 << 0)
+
+#define MB86A16_TONEOUT1	0x1f
+#define MB86A16_TONE_TDIVL	(0xff << 0)
+
+#define MB86A16_TONEOUT2	0x20
+#define MB86A16_TONE_TMD	(0x03 << 2)
+#define MB86A16_TONE_TDIVH	(0x03 << 0)
+
+#define MB86A16_FREQ1		0x21
+#define MB86A16_FREQ2		0x22
+#define MB86A16_FREQ3		0x23
+#define MB86A16_FREQ4		0x24
+#define MB86A16_FREQSET		0x25
+#define MB86A16_CNM		0x26
+#define MB86A16_PORT0		0x27
+#define MB86A16_PORT1		0x28
+#define MB86A16_DRCFILT		0x29
+#define MB86A16_AFC		0x2a
+#define MB86A16_AFCEXL		0x2b
+#define MB86A16_AFCEXH		0x2c
+#define MB86A16_DAGC		0x2d
+#define MB86A16_SEQMODE		0x32
+#define MB86A16_S0S1T		0x33
+#define MB86A16_S2S3T		0x34
+#define MB86A16_S4S5T		0x35
+#define MB86A16_CNTMR		0x36
+#define MB86A16_SIG1		0x37
+#define MB86A16_SIG2		0x38
+#define MB86A16_VIMAG		0x39
+#define MB86A16_VISET1		0x3a
+#define MB86A16_VISET2		0x3b
+#define MB86A16_VISET3		0x3c
+#define MB86A16_FAGCS1		0x3d
+#define MB86A16_FAGCS2		0x3e
+#define MB86A16_FAGCS3		0x3f
+#define MB86A16_FAGCS4		0x40
+#define MB86A16_FAGCS5		0x41
+#define MB86A16_FAGCS6		0x42
+#define MB86A16_CRM		0x43
+#define MB86A16_STRM		0x44
+#define MB86A16_DAGCML		0x45
+#define MB86A16_DAGCMH		0x46
+#define MB86A16_QPSKTST		0x49
+#define MB86A16_DISTMON		0x52
+#define MB86A16_VERSION		0x7f
+
+#endif /* __MB86A16_PRIV_H */
diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c
new file mode 100644
index 0000000..fade566
--- /dev/null
+++ b/drivers/media/dvb-frontends/mb86a20s.c
@@ -0,0 +1,701 @@
+/*
+ *   Fujitu mb86a20s ISDB-T/ISDB-Tsb Module driver
+ *
+ *   Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *   Copyright (C) 2009-2010 Douglas Landgraf <dougsland@redhat.com>
+ *
+ *   FIXME: Need to port to DVB v5.2 API
+ *
+ *   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 version 2.
+ *
+ *   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 <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "mb86a20s.h"
+
+static int debug = 1;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+#define rc(args...)  do {						\
+	printk(KERN_ERR  "mb86a20s: " args);				\
+} while (0)
+
+#define dprintk(args...)						\
+	do {								\
+		if (debug) {						\
+			printk(KERN_DEBUG "mb86a20s: %s: ", __func__);	\
+			printk(args);					\
+		}							\
+	} while (0)
+
+struct mb86a20s_state {
+	struct i2c_adapter *i2c;
+	const struct mb86a20s_config *config;
+
+	struct dvb_frontend frontend;
+
+	bool need_init;
+};
+
+struct regdata {
+	u8 reg;
+	u8 data;
+};
+
+/*
+ * Initialization sequence: Use whatevere default values that PV SBTVD
+ * does on its initialisation, obtained via USB snoop
+ */
+static struct regdata mb86a20s_init[] = {
+	{ 0x70, 0x0f },
+	{ 0x70, 0xff },
+	{ 0x08, 0x01 },
+	{ 0x09, 0x3e },
+	{ 0x50, 0xd1 }, { 0x51, 0x22 },
+	{ 0x39, 0x01 },
+	{ 0x71, 0x00 },
+	{ 0x28, 0x2a }, { 0x29, 0x00 }, { 0x2a, 0xff }, { 0x2b, 0x80 },
+	{ 0x28, 0x20 }, { 0x29, 0x33 }, { 0x2a, 0xdf }, { 0x2b, 0xa9 },
+	{ 0x28, 0x22 }, { 0x29, 0x00 }, { 0x2a, 0x1f }, { 0x2b, 0xf0 },
+	{ 0x3b, 0x21 },
+	{ 0x3c, 0x3a },
+	{ 0x01, 0x0d },
+	{ 0x04, 0x08 }, { 0x05, 0x05 },
+	{ 0x04, 0x0e }, { 0x05, 0x00 },
+	{ 0x04, 0x0f }, { 0x05, 0x14 },
+	{ 0x04, 0x0b }, { 0x05, 0x8c },
+	{ 0x04, 0x00 }, { 0x05, 0x00 },
+	{ 0x04, 0x01 }, { 0x05, 0x07 },
+	{ 0x04, 0x02 }, { 0x05, 0x0f },
+	{ 0x04, 0x03 }, { 0x05, 0xa0 },
+	{ 0x04, 0x09 }, { 0x05, 0x00 },
+	{ 0x04, 0x0a }, { 0x05, 0xff },
+	{ 0x04, 0x27 }, { 0x05, 0x64 },
+	{ 0x04, 0x28 }, { 0x05, 0x00 },
+	{ 0x04, 0x1e }, { 0x05, 0xff },
+	{ 0x04, 0x29 }, { 0x05, 0x0a },
+	{ 0x04, 0x32 }, { 0x05, 0x0a },
+	{ 0x04, 0x14 }, { 0x05, 0x02 },
+	{ 0x04, 0x04 }, { 0x05, 0x00 },
+	{ 0x04, 0x05 }, { 0x05, 0x22 },
+	{ 0x04, 0x06 }, { 0x05, 0x0e },
+	{ 0x04, 0x07 }, { 0x05, 0xd8 },
+	{ 0x04, 0x12 }, { 0x05, 0x00 },
+	{ 0x04, 0x13 }, { 0x05, 0xff },
+	{ 0x04, 0x15 }, { 0x05, 0x4e },
+	{ 0x04, 0x16 }, { 0x05, 0x20 },
+	{ 0x52, 0x01 },
+	{ 0x50, 0xa7 }, { 0x51, 0xff },
+	{ 0x50, 0xa8 }, { 0x51, 0xff },
+	{ 0x50, 0xa9 }, { 0x51, 0xff },
+	{ 0x50, 0xaa }, { 0x51, 0xff },
+	{ 0x50, 0xab }, { 0x51, 0xff },
+	{ 0x50, 0xac }, { 0x51, 0xff },
+	{ 0x50, 0xad }, { 0x51, 0xff },
+	{ 0x50, 0xae }, { 0x51, 0xff },
+	{ 0x50, 0xaf }, { 0x51, 0xff },
+	{ 0x5e, 0x07 },
+	{ 0x50, 0xdc }, { 0x51, 0x01 },
+	{ 0x50, 0xdd }, { 0x51, 0xf4 },
+	{ 0x50, 0xde }, { 0x51, 0x01 },
+	{ 0x50, 0xdf }, { 0x51, 0xf4 },
+	{ 0x50, 0xe0 }, { 0x51, 0x01 },
+	{ 0x50, 0xe1 }, { 0x51, 0xf4 },
+	{ 0x50, 0xb0 }, { 0x51, 0x07 },
+	{ 0x50, 0xb2 }, { 0x51, 0xff },
+	{ 0x50, 0xb3 }, { 0x51, 0xff },
+	{ 0x50, 0xb4 }, { 0x51, 0xff },
+	{ 0x50, 0xb5 }, { 0x51, 0xff },
+	{ 0x50, 0xb6 }, { 0x51, 0xff },
+	{ 0x50, 0xb7 }, { 0x51, 0xff },
+	{ 0x50, 0x50 }, { 0x51, 0x02 },
+	{ 0x50, 0x51 }, { 0x51, 0x04 },
+	{ 0x45, 0x04 },
+	{ 0x48, 0x04 },
+	{ 0x50, 0xd5 }, { 0x51, 0x01 },		/* Serial */
+	{ 0x50, 0xd6 }, { 0x51, 0x1f },
+	{ 0x50, 0xd2 }, { 0x51, 0x03 },
+	{ 0x50, 0xd7 }, { 0x51, 0x3f },
+	{ 0x28, 0x74 }, { 0x29, 0x00 }, { 0x28, 0x74 }, { 0x29, 0x40 },
+	{ 0x28, 0x46 }, { 0x29, 0x2c }, { 0x28, 0x46 }, { 0x29, 0x0c },
+	{ 0x04, 0x40 }, { 0x05, 0x01 },
+	{ 0x28, 0x00 }, { 0x29, 0x10 },
+	{ 0x28, 0x05 }, { 0x29, 0x02 },
+	{ 0x1c, 0x01 },
+	{ 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x03 },
+	{ 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0d },
+	{ 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 },
+	{ 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x01 },
+	{ 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x21 },
+	{ 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x29 },
+	{ 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 },
+	{ 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x31 },
+	{ 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0e },
+	{ 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x4e },
+	{ 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x46 },
+	{ 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f },
+	{ 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x56 },
+	{ 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x35 },
+	{ 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbe },
+	{ 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0x84 },
+	{ 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x03 }, { 0x2b, 0xee },
+	{ 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x98 },
+	{ 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x9f },
+	{ 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xb2 },
+	{ 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0xc2 },
+	{ 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0x4a },
+	{ 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbc },
+	{ 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x04 }, { 0x2b, 0xba },
+	{ 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0x14 },
+	{ 0x50, 0x1e }, { 0x51, 0x5d },
+	{ 0x50, 0x22 }, { 0x51, 0x00 },
+	{ 0x50, 0x23 }, { 0x51, 0xc8 },
+	{ 0x50, 0x24 }, { 0x51, 0x00 },
+	{ 0x50, 0x25 }, { 0x51, 0xf0 },
+	{ 0x50, 0x26 }, { 0x51, 0x00 },
+	{ 0x50, 0x27 }, { 0x51, 0xc3 },
+	{ 0x50, 0x39 }, { 0x51, 0x02 },
+	{ 0x28, 0x6a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x00 },
+	{ 0xd0, 0x00 },
+};
+
+static struct regdata mb86a20s_reset_reception[] = {
+	{ 0x70, 0xf0 },
+	{ 0x70, 0xff },
+	{ 0x08, 0x01 },
+	{ 0x08, 0x00 },
+};
+
+static int mb86a20s_i2c_writereg(struct mb86a20s_state *state,
+			     u8 i2c_addr, int reg, int data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = {
+		.addr = i2c_addr, .flags = 0, .buf = buf, .len = 2
+	};
+	int rc;
+
+	rc = i2c_transfer(state->i2c, &msg, 1);
+	if (rc != 1) {
+		printk("%s: writereg error (rc == %i, reg == 0x%02x,"
+			 " data == 0x%02x)\n", __func__, rc, reg, data);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int mb86a20s_i2c_writeregdata(struct mb86a20s_state *state,
+				     u8 i2c_addr, struct regdata *rd, int size)
+{
+	int i, rc;
+
+	for (i = 0; i < size; i++) {
+		rc = mb86a20s_i2c_writereg(state, i2c_addr, rd[i].reg,
+					   rd[i].data);
+		if (rc < 0)
+			return rc;
+	}
+	return 0;
+}
+
+static int mb86a20s_i2c_readreg(struct mb86a20s_state *state,
+				u8 i2c_addr, u8 reg)
+{
+	u8 val;
+	int rc;
+	struct i2c_msg msg[] = {
+		{ .addr = i2c_addr, .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
+	};
+
+	rc = i2c_transfer(state->i2c, msg, 2);
+
+	if (rc != 2) {
+		rc("%s: reg=0x%x (error=%d)\n", __func__, reg, rc);
+		return rc;
+	}
+
+	return val;
+}
+
+#define mb86a20s_readreg(state, reg) \
+	mb86a20s_i2c_readreg(state, state->config->demod_address, reg)
+#define mb86a20s_writereg(state, reg, val) \
+	mb86a20s_i2c_writereg(state, state->config->demod_address, reg, val)
+#define mb86a20s_writeregdata(state, regdata) \
+	mb86a20s_i2c_writeregdata(state, state->config->demod_address, \
+	regdata, ARRAY_SIZE(regdata))
+
+static int mb86a20s_initfe(struct dvb_frontend *fe)
+{
+	struct mb86a20s_state *state = fe->demodulator_priv;
+	int rc;
+	u8  regD5 = 1;
+
+	dprintk("\n");
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	/* Initialize the frontend */
+	rc = mb86a20s_writeregdata(state, mb86a20s_init);
+	if (rc < 0)
+		goto err;
+
+	if (!state->config->is_serial) {
+		regD5 &= ~1;
+
+		rc = mb86a20s_writereg(state, 0x50, 0xd5);
+		if (rc < 0)
+			goto err;
+		rc = mb86a20s_writereg(state, 0x51, regD5);
+		if (rc < 0)
+			goto err;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+err:
+	if (rc < 0) {
+		state->need_init = true;
+		printk(KERN_INFO "mb86a20s: Init failed. Will try again later\n");
+	} else {
+		state->need_init = false;
+		dprintk("Initialization succeeded.\n");
+	}
+	return rc;
+}
+
+static int mb86a20s_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct mb86a20s_state *state = fe->demodulator_priv;
+	unsigned rf_max, rf_min, rf;
+	u8	 val;
+
+	dprintk("\n");
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	/* Does a binary search to get RF strength */
+	rf_max = 0xfff;
+	rf_min = 0;
+	do {
+		rf = (rf_max + rf_min) / 2;
+		mb86a20s_writereg(state, 0x04, 0x1f);
+		mb86a20s_writereg(state, 0x05, rf >> 8);
+		mb86a20s_writereg(state, 0x04, 0x20);
+		mb86a20s_writereg(state, 0x04, rf);
+
+		val = mb86a20s_readreg(state, 0x02);
+		if (val & 0x08)
+			rf_min = (rf_max + rf_min) / 2;
+		else
+			rf_max = (rf_max + rf_min) / 2;
+		if (rf_max - rf_min < 4) {
+			*strength = (((rf_max + rf_min) / 2) * 65535) / 4095;
+			break;
+		}
+	} while (1);
+
+	dprintk("signal strength = %d\n", *strength);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	return 0;
+}
+
+static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct mb86a20s_state *state = fe->demodulator_priv;
+	u8 val;
+
+	dprintk("\n");
+	*status = 0;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+	val = mb86a20s_readreg(state, 0x0a) & 0xf;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	if (val >= 2)
+		*status |= FE_HAS_SIGNAL;
+
+	if (val >= 4)
+		*status |= FE_HAS_CARRIER;
+
+	if (val >= 5)
+		*status |= FE_HAS_VITERBI;
+
+	if (val >= 7)
+		*status |= FE_HAS_SYNC;
+
+	if (val >= 8)				/* Maybe 9? */
+		*status |= FE_HAS_LOCK;
+
+	dprintk("val = %d, status = 0x%02x\n", val, *status);
+
+	return 0;
+}
+
+static int mb86a20s_set_frontend(struct dvb_frontend *fe)
+{
+	struct mb86a20s_state *state = fe->demodulator_priv;
+	int rc;
+#if 0
+	/*
+	 * FIXME: Properly implement the set frontend properties
+	 */
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+#endif
+
+	dprintk("\n");
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	dprintk("Calling tuner set parameters\n");
+	fe->ops.tuner_ops.set_params(fe);
+
+	/*
+	 * Make it more reliable: if, for some reason, the initial
+	 * device initialization doesn't happen, initialize it when
+	 * a SBTVD parameters are adjusted.
+	 *
+	 * Unfortunately, due to a hard to track bug at tda829x/tda18271,
+	 * the agc callback logic is not called during DVB attach time,
+	 * causing mb86a20s to not be initialized with Kworld SBTVD.
+	 * So, this hack is needed, in order to make Kworld SBTVD to work.
+	 */
+	if (state->need_init)
+		mb86a20s_initfe(fe);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+	rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	return rc;
+}
+
+static int mb86a20s_get_modulation(struct mb86a20s_state *state,
+				   unsigned layer)
+{
+	int rc;
+	static unsigned char reg[] = {
+		[0] = 0x86,	/* Layer A */
+		[1] = 0x8a,	/* Layer B */
+		[2] = 0x8e,	/* Layer C */
+	};
+
+	if (layer >= ARRAY_SIZE(reg))
+		return -EINVAL;
+	rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
+	if (rc < 0)
+		return rc;
+	rc = mb86a20s_readreg(state, 0x6e);
+	if (rc < 0)
+		return rc;
+	switch ((rc & 0x70) >> 4) {
+	case 0:
+		return DQPSK;
+	case 1:
+		return QPSK;
+	case 2:
+		return QAM_16;
+	case 3:
+		return QAM_64;
+	default:
+		return QAM_AUTO;
+	}
+}
+
+static int mb86a20s_get_fec(struct mb86a20s_state *state,
+			    unsigned layer)
+{
+	int rc;
+
+	static unsigned char reg[] = {
+		[0] = 0x87,	/* Layer A */
+		[1] = 0x8b,	/* Layer B */
+		[2] = 0x8f,	/* Layer C */
+	};
+
+	if (layer >= ARRAY_SIZE(reg))
+		return -EINVAL;
+	rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
+	if (rc < 0)
+		return rc;
+	rc = mb86a20s_readreg(state, 0x6e);
+	if (rc < 0)
+		return rc;
+	switch (rc) {
+	case 0:
+		return FEC_1_2;
+	case 1:
+		return FEC_2_3;
+	case 2:
+		return FEC_3_4;
+	case 3:
+		return FEC_5_6;
+	case 4:
+		return FEC_7_8;
+	default:
+		return FEC_AUTO;
+	}
+}
+
+static int mb86a20s_get_interleaving(struct mb86a20s_state *state,
+				     unsigned layer)
+{
+	int rc;
+
+	static unsigned char reg[] = {
+		[0] = 0x88,	/* Layer A */
+		[1] = 0x8c,	/* Layer B */
+		[2] = 0x90,	/* Layer C */
+	};
+
+	if (layer >= ARRAY_SIZE(reg))
+		return -EINVAL;
+	rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
+	if (rc < 0)
+		return rc;
+	rc = mb86a20s_readreg(state, 0x6e);
+	if (rc < 0)
+		return rc;
+	if (rc > 3)
+		return -EINVAL;	/* Not used */
+	return rc;
+}
+
+static int mb86a20s_get_segment_count(struct mb86a20s_state *state,
+				      unsigned layer)
+{
+	int rc, count;
+
+	static unsigned char reg[] = {
+		[0] = 0x89,	/* Layer A */
+		[1] = 0x8d,	/* Layer B */
+		[2] = 0x91,	/* Layer C */
+	};
+
+	if (layer >= ARRAY_SIZE(reg))
+		return -EINVAL;
+	rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
+	if (rc < 0)
+		return rc;
+	rc = mb86a20s_readreg(state, 0x6e);
+	if (rc < 0)
+		return rc;
+	count = (rc >> 4) & 0x0f;
+
+	return count;
+}
+
+static int mb86a20s_get_frontend(struct dvb_frontend *fe)
+{
+	struct mb86a20s_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	int i, rc;
+
+	/* Fixed parameters */
+	p->delivery_system = SYS_ISDBT;
+	p->bandwidth_hz = 6000000;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	/* Check for partial reception */
+	rc = mb86a20s_writereg(state, 0x6d, 0x85);
+	if (rc >= 0)
+		rc = mb86a20s_readreg(state, 0x6e);
+	if (rc >= 0)
+		p->isdbt_partial_reception = (rc & 0x10) ? 1 : 0;
+
+	/* Get per-layer data */
+	p->isdbt_layer_enabled = 0;
+	for (i = 0; i < 3; i++) {
+		rc = mb86a20s_get_segment_count(state, i);
+			if (rc >= 0 && rc < 14)
+				p->layer[i].segment_count = rc;
+		if (rc == 0x0f)
+			continue;
+		p->isdbt_layer_enabled |= 1 << i;
+		rc = mb86a20s_get_modulation(state, i);
+			if (rc >= 0)
+				p->layer[i].modulation = rc;
+		rc = mb86a20s_get_fec(state, i);
+			if (rc >= 0)
+				p->layer[i].fec = rc;
+		rc = mb86a20s_get_interleaving(state, i);
+			if (rc >= 0)
+				p->layer[i].interleaving = rc;
+	}
+
+	p->isdbt_sb_mode = 0;
+	rc = mb86a20s_writereg(state, 0x6d, 0x84);
+	if ((rc >= 0) && ((rc & 0x60) == 0x20)) {
+		p->isdbt_sb_mode = 1;
+		/* At least, one segment should exist */
+		if (!p->isdbt_sb_segment_count)
+			p->isdbt_sb_segment_count = 1;
+	} else
+		p->isdbt_sb_segment_count = 0;
+
+	/* Get transmission mode and guard interval */
+	p->transmission_mode = TRANSMISSION_MODE_AUTO;
+	p->guard_interval = GUARD_INTERVAL_AUTO;
+	rc = mb86a20s_readreg(state, 0x07);
+	if (rc >= 0) {
+		if ((rc & 0x60) == 0x20) {
+			switch (rc & 0x0c >> 2) {
+			case 0:
+				p->transmission_mode = TRANSMISSION_MODE_2K;
+				break;
+			case 1:
+				p->transmission_mode = TRANSMISSION_MODE_4K;
+				break;
+			case 2:
+				p->transmission_mode = TRANSMISSION_MODE_8K;
+				break;
+			}
+		}
+		if (!(rc & 0x10)) {
+			switch (rc & 0x3) {
+			case 0:
+				p->guard_interval = GUARD_INTERVAL_1_4;
+				break;
+			case 1:
+				p->guard_interval = GUARD_INTERVAL_1_8;
+				break;
+			case 2:
+				p->guard_interval = GUARD_INTERVAL_1_16;
+				break;
+			}
+		}
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	return 0;
+}
+
+static int mb86a20s_tune(struct dvb_frontend *fe,
+			bool re_tune,
+			unsigned int mode_flags,
+			unsigned int *delay,
+			fe_status_t *status)
+{
+	int rc = 0;
+
+	dprintk("\n");
+
+	if (re_tune)
+		rc = mb86a20s_set_frontend(fe);
+
+	if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
+		mb86a20s_read_status(fe, status);
+
+	return rc;
+}
+
+static void mb86a20s_release(struct dvb_frontend *fe)
+{
+	struct mb86a20s_state *state = fe->demodulator_priv;
+
+	dprintk("\n");
+
+	kfree(state);
+}
+
+static struct dvb_frontend_ops mb86a20s_ops;
+
+struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
+				    struct i2c_adapter *i2c)
+{
+	u8	rev;
+
+	/* allocate memory for the internal state */
+	struct mb86a20s_state *state =
+		kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL);
+
+	dprintk("\n");
+	if (state == NULL) {
+		rc("Unable to kzalloc\n");
+		goto error;
+	}
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &mb86a20s_ops,
+		sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	/* Check if it is a mb86a20s frontend */
+	rev = mb86a20s_readreg(state, 0);
+
+	if (rev == 0x13) {
+		printk(KERN_INFO "Detected a Fujitsu mb86a20s frontend\n");
+	} else {
+		printk(KERN_ERR "Frontend revision %d is unknown - aborting.\n",
+		       rev);
+		goto error;
+	}
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(mb86a20s_attach);
+
+static struct dvb_frontend_ops mb86a20s_ops = {
+	.delsys = { SYS_ISDBT },
+	/* Use dib8000 values per default */
+	.info = {
+		.name = "Fujitsu mb86A20s",
+		.caps = FE_CAN_INVERSION_AUTO | FE_CAN_RECOVER |
+			FE_CAN_FEC_1_2  | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6  | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK     | FE_CAN_QAM_16  | FE_CAN_QAM_64 |
+			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_QAM_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO    | FE_CAN_HIERARCHY_AUTO,
+		/* Actually, those values depend on the used tuner */
+		.frequency_min = 45000000,
+		.frequency_max = 864000000,
+		.frequency_stepsize = 62500,
+	},
+
+	.release = mb86a20s_release,
+
+	.init = mb86a20s_initfe,
+	.set_frontend = mb86a20s_set_frontend,
+	.get_frontend = mb86a20s_get_frontend,
+	.read_status = mb86a20s_read_status,
+	.read_signal_strength = mb86a20s_read_signal_strength,
+	.tune = mb86a20s_tune,
+};
+
+MODULE_DESCRIPTION("DVB Frontend module for Fujitsu mb86A20s hardware");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/mb86a20s.h b/drivers/media/dvb-frontends/mb86a20s.h
new file mode 100644
index 0000000..bf22e77
--- /dev/null
+++ b/drivers/media/dvb-frontends/mb86a20s.h
@@ -0,0 +1,52 @@
+/*
+ *   Fujitsu mb86a20s driver
+ *
+ *   Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License as
+ *   published by the Free Software Foundation version 2.
+ *
+ *   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 MB86A20S_H
+#define MB86A20S_H
+
+#include <linux/dvb/frontend.h>
+
+/**
+ * struct mb86a20s_config - Define the per-device attributes of the frontend
+ *
+ * @demod_address:	the demodulator's i2c address
+ */
+
+struct mb86a20s_config {
+	u8 demod_address;
+	bool is_serial;
+};
+
+#if defined(CONFIG_DVB_MB86A20S) || (defined(CONFIG_DVB_MB86A20S_MODULE) \
+	&& defined(MODULE))
+extern struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
+					   struct i2c_adapter *i2c);
+extern struct i2c_adapter *mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *);
+#else
+static inline struct dvb_frontend *mb86a20s_attach(
+	const struct mb86a20s_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+static struct i2c_adapter *
+	mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* MB86A20S */
diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c
new file mode 100644
index 0000000..e20bf13
--- /dev/null
+++ b/drivers/media/dvb-frontends/mt312.c
@@ -0,0 +1,839 @@
+/*
+    Driver for Zarlink VP310/MT312/ZL10313 Satellite Channel Decoder
+
+    Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
+    Copyright (C) 2008 Matthias Schwarzott <zzam@gentoo.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    References:
+    http://products.zarlink.com/product_profiles/MT312.htm
+    http://products.zarlink.com/product_profiles/SL1935.htm
+*/
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "mt312_priv.h"
+#include "mt312.h"
+
+
+struct mt312_state {
+	struct i2c_adapter *i2c;
+	/* configuration settings */
+	const struct mt312_config *config;
+	struct dvb_frontend frontend;
+
+	u8 id;
+	unsigned long xtal;
+	u8 freq_mult;
+};
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG "mt312: " args); \
+	} while (0)
+
+#define MT312_PLL_CLK		10000000UL	/* 10 MHz */
+#define MT312_PLL_CLK_10_111	10111000UL	/* 10.111 MHz */
+
+static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
+		      u8 *buf, const size_t count)
+{
+	int ret;
+	struct i2c_msg msg[2];
+	u8 regbuf[1] = { reg };
+
+	msg[0].addr = state->config->demod_address;
+	msg[0].flags = 0;
+	msg[0].buf = regbuf;
+	msg[0].len = 1;
+	msg[1].addr = state->config->demod_address;
+	msg[1].flags = I2C_M_RD;
+	msg[1].buf = buf;
+	msg[1].len = count;
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		printk(KERN_DEBUG "%s: ret == %d\n", __func__, ret);
+		return -EREMOTEIO;
+	}
+
+	if (debug) {
+		int i;
+		dprintk("R(%d):", reg & 0x7f);
+		for (i = 0; i < count; i++)
+			printk(KERN_CONT " %02x", buf[i]);
+		printk("\n");
+	}
+
+	return 0;
+}
+
+static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
+		       const u8 *src, const size_t count)
+{
+	int ret;
+	u8 buf[count + 1];
+	struct i2c_msg msg;
+
+	if (debug) {
+		int i;
+		dprintk("W(%d):", reg & 0x7f);
+		for (i = 0; i < count; i++)
+			printk(KERN_CONT " %02x", src[i]);
+		printk("\n");
+	}
+
+	buf[0] = reg;
+	memcpy(&buf[1], src, count);
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.buf = buf;
+	msg.len = count + 1;
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1) {
+		dprintk("%s: ret == %d\n", __func__, ret);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static inline int mt312_readreg(struct mt312_state *state,
+				const enum mt312_reg_addr reg, u8 *val)
+{
+	return mt312_read(state, reg, val, 1);
+}
+
+static inline int mt312_writereg(struct mt312_state *state,
+				 const enum mt312_reg_addr reg, const u8 val)
+{
+	return mt312_write(state, reg, &val, 1);
+}
+
+static inline u32 mt312_div(u32 a, u32 b)
+{
+	return (a + (b / 2)) / b;
+}
+
+static int mt312_reset(struct mt312_state *state, const u8 full)
+{
+	return mt312_writereg(state, RESET, full ? 0x80 : 0x40);
+}
+
+static int mt312_get_inversion(struct mt312_state *state,
+			       fe_spectral_inversion_t *i)
+{
+	int ret;
+	u8 vit_mode;
+
+	ret = mt312_readreg(state, VIT_MODE, &vit_mode);
+	if (ret < 0)
+		return ret;
+
+	if (vit_mode & 0x80)	/* auto inversion was used */
+		*i = (vit_mode & 0x40) ? INVERSION_ON : INVERSION_OFF;
+
+	return 0;
+}
+
+static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr)
+{
+	int ret;
+	u8 sym_rate_h;
+	u8 dec_ratio;
+	u16 sym_rat_op;
+	u16 monitor;
+	u8 buf[2];
+
+	ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h);
+	if (ret < 0)
+		return ret;
+
+	if (sym_rate_h & 0x80) {
+		/* symbol rate search was used */
+		ret = mt312_writereg(state, MON_CTRL, 0x03);
+		if (ret < 0)
+			return ret;
+
+		ret = mt312_read(state, MONITOR_H, buf, sizeof(buf));
+		if (ret < 0)
+			return ret;
+
+		monitor = (buf[0] << 8) | buf[1];
+
+		dprintk("sr(auto) = %u\n",
+		       mt312_div(monitor * 15625, 4));
+	} else {
+		ret = mt312_writereg(state, MON_CTRL, 0x05);
+		if (ret < 0)
+			return ret;
+
+		ret = mt312_read(state, MONITOR_H, buf, sizeof(buf));
+		if (ret < 0)
+			return ret;
+
+		dec_ratio = ((buf[0] >> 5) & 0x07) * 32;
+
+		ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf));
+		if (ret < 0)
+			return ret;
+
+		sym_rat_op = (buf[0] << 8) | buf[1];
+
+		dprintk("sym_rat_op=%d dec_ratio=%d\n",
+		       sym_rat_op, dec_ratio);
+		dprintk("*sr(manual) = %lu\n",
+		       (((state->xtal * 8192) / (sym_rat_op + 8192)) *
+			2) - dec_ratio);
+	}
+
+	return 0;
+}
+
+static int mt312_get_code_rate(struct mt312_state *state, fe_code_rate_t *cr)
+{
+	const fe_code_rate_t fec_tab[8] =
+	    { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8,
+		FEC_AUTO, FEC_AUTO };
+
+	int ret;
+	u8 fec_status;
+
+	ret = mt312_readreg(state, FEC_STATUS, &fec_status);
+	if (ret < 0)
+		return ret;
+
+	*cr = fec_tab[(fec_status >> 4) & 0x07];
+
+	return 0;
+}
+
+static int mt312_initfe(struct dvb_frontend *fe)
+{
+	struct mt312_state *state = fe->demodulator_priv;
+	int ret;
+	u8 buf[2];
+
+	/* wake up */
+	ret = mt312_writereg(state, CONFIG,
+			(state->freq_mult == 6 ? 0x88 : 0x8c));
+	if (ret < 0)
+		return ret;
+
+	/* wait at least 150 usec */
+	udelay(150);
+
+	/* full reset */
+	ret = mt312_reset(state, 1);
+	if (ret < 0)
+		return ret;
+
+/* Per datasheet, write correct values. 09/28/03 ACCJr.
+ * If we don't do this, we won't get FE_HAS_VITERBI in the VP310. */
+	{
+		u8 buf_def[8] = { 0x14, 0x12, 0x03, 0x02,
+				  0x01, 0x00, 0x00, 0x00 };
+
+		ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def));
+		if (ret < 0)
+			return ret;
+	}
+
+	switch (state->id) {
+	case ID_ZL10313:
+		/* enable ADC */
+		ret = mt312_writereg(state, GPP_CTRL, 0x80);
+		if (ret < 0)
+			return ret;
+
+		/* configure ZL10313 for optimal ADC performance */
+		buf[0] = 0x80;
+		buf[1] = 0xB0;
+		ret = mt312_write(state, HW_CTRL, buf, 2);
+		if (ret < 0)
+			return ret;
+
+		/* enable MPEG output and ADCs */
+		ret = mt312_writereg(state, HW_CTRL, 0x00);
+		if (ret < 0)
+			return ret;
+
+		ret = mt312_writereg(state, MPEG_CTRL, 0x00);
+		if (ret < 0)
+			return ret;
+
+		break;
+	}
+
+	/* SYS_CLK */
+	buf[0] = mt312_div(state->xtal * state->freq_mult * 2, 1000000);
+
+	/* DISEQC_RATIO */
+	buf[1] = mt312_div(state->xtal, 22000 * 4);
+
+	ret = mt312_write(state, SYS_CLK, buf, sizeof(buf));
+	if (ret < 0)
+		return ret;
+
+	ret = mt312_writereg(state, SNR_THS_HIGH, 0x32);
+	if (ret < 0)
+		return ret;
+
+	/* different MOCLK polarity */
+	switch (state->id) {
+	case ID_ZL10313:
+		buf[0] = 0x33;
+		break;
+	default:
+		buf[0] = 0x53;
+		break;
+	}
+
+	ret = mt312_writereg(state, OP_CTRL, buf[0]);
+	if (ret < 0)
+		return ret;
+
+	/* TS_SW_LIM */
+	buf[0] = 0x8c;
+	buf[1] = 0x98;
+
+	ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf));
+	if (ret < 0)
+		return ret;
+
+	ret = mt312_writereg(state, CS_SW_LIM, 0x69);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int mt312_send_master_cmd(struct dvb_frontend *fe,
+				 struct dvb_diseqc_master_cmd *c)
+{
+	struct mt312_state *state = fe->demodulator_priv;
+	int ret;
+	u8 diseqc_mode;
+
+	if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg)))
+		return -EINVAL;
+
+	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
+	if (ret < 0)
+		return ret;
+
+	ret = mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len);
+	if (ret < 0)
+		return ret;
+
+	ret = mt312_writereg(state, DISEQC_MODE,
+			     (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3)
+			     | 0x04);
+	if (ret < 0)
+		return ret;
+
+	/* is there a better way to wait for message to be transmitted */
+	msleep(100);
+
+	/* set DISEQC_MODE[2:0] to zero if a return message is expected */
+	if (c->msg[0] & 0x02) {
+		ret = mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40));
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int mt312_send_burst(struct dvb_frontend *fe, const fe_sec_mini_cmd_t c)
+{
+	struct mt312_state *state = fe->demodulator_priv;
+	const u8 mini_tab[2] = { 0x02, 0x03 };
+
+	int ret;
+	u8 diseqc_mode;
+
+	if (c > SEC_MINI_B)
+		return -EINVAL;
+
+	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
+	if (ret < 0)
+		return ret;
+
+	ret = mt312_writereg(state, DISEQC_MODE,
+			     (diseqc_mode & 0x40) | mini_tab[c]);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int mt312_set_tone(struct dvb_frontend *fe, const fe_sec_tone_mode_t t)
+{
+	struct mt312_state *state = fe->demodulator_priv;
+	const u8 tone_tab[2] = { 0x01, 0x00 };
+
+	int ret;
+	u8 diseqc_mode;
+
+	if (t > SEC_TONE_OFF)
+		return -EINVAL;
+
+	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
+	if (ret < 0)
+		return ret;
+
+	ret = mt312_writereg(state, DISEQC_MODE,
+			     (diseqc_mode & 0x40) | tone_tab[t]);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int mt312_set_voltage(struct dvb_frontend *fe, const fe_sec_voltage_t v)
+{
+	struct mt312_state *state = fe->demodulator_priv;
+	const u8 volt_tab[3] = { 0x00, 0x40, 0x00 };
+	u8 val;
+
+	if (v > SEC_VOLTAGE_OFF)
+		return -EINVAL;
+
+	val = volt_tab[v];
+	if (state->config->voltage_inverted)
+		val ^= 0x40;
+
+	return mt312_writereg(state, DISEQC_MODE, val);
+}
+
+static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s)
+{
+	struct mt312_state *state = fe->demodulator_priv;
+	int ret;
+	u8 status[3];
+
+	*s = 0;
+
+	ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status));
+	if (ret < 0)
+		return ret;
+
+	dprintk("QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x,"
+		" FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]);
+
+	if (status[0] & 0xc0)
+		*s |= FE_HAS_SIGNAL;	/* signal noise ratio */
+	if (status[0] & 0x04)
+		*s |= FE_HAS_CARRIER;	/* qpsk carrier lock */
+	if (status[2] & 0x02)
+		*s |= FE_HAS_VITERBI;	/* viterbi lock */
+	if (status[2] & 0x04)
+		*s |= FE_HAS_SYNC;	/* byte align lock */
+	if (status[0] & 0x01)
+		*s |= FE_HAS_LOCK;	/* qpsk lock */
+
+	return 0;
+}
+
+static int mt312_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct mt312_state *state = fe->demodulator_priv;
+	int ret;
+	u8 buf[3];
+
+	ret = mt312_read(state, RS_BERCNT_H, buf, 3);
+	if (ret < 0)
+		return ret;
+
+	*ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64;
+
+	return 0;
+}
+
+static int mt312_read_signal_strength(struct dvb_frontend *fe,
+				      u16 *signal_strength)
+{
+	struct mt312_state *state = fe->demodulator_priv;
+	int ret;
+	u8 buf[3];
+	u16 agc;
+	s16 err_db;
+
+	ret = mt312_read(state, AGC_H, buf, sizeof(buf));
+	if (ret < 0)
+		return ret;
+
+	agc = (buf[0] << 6) | (buf[1] >> 2);
+	err_db = (s16) (((buf[1] & 0x03) << 14) | buf[2] << 6) >> 6;
+
+	*signal_strength = agc;
+
+	dprintk("agc=%08x err_db=%hd\n", agc, err_db);
+
+	return 0;
+}
+
+static int mt312_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct mt312_state *state = fe->demodulator_priv;
+	int ret;
+	u8 buf[2];
+
+	ret = mt312_read(state, M_SNR_H, buf, sizeof(buf));
+	if (ret < 0)
+		return ret;
+
+	*snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1);
+
+	return 0;
+}
+
+static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc)
+{
+	struct mt312_state *state = fe->demodulator_priv;
+	int ret;
+	u8 buf[2];
+
+	ret = mt312_read(state, RS_UBC_H, buf, sizeof(buf));
+	if (ret < 0)
+		return ret;
+
+	*ubc = (buf[0] << 8) | buf[1];
+
+	return 0;
+}
+
+static int mt312_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct mt312_state *state = fe->demodulator_priv;
+	int ret;
+	u8 buf[5], config_val;
+	u16 sr;
+
+	const u8 fec_tab[10] =
+	    { 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10, 0x20, 0x3f, 0x3f };
+	const u8 inv_tab[3] = { 0x00, 0x40, 0x80 };
+
+	dprintk("%s: Freq %d\n", __func__, p->frequency);
+
+	if ((p->frequency < fe->ops.info.frequency_min)
+	    || (p->frequency > fe->ops.info.frequency_max))
+		return -EINVAL;
+
+	if ((p->inversion < INVERSION_OFF)
+	    || (p->inversion > INVERSION_ON))
+		return -EINVAL;
+
+	if ((p->symbol_rate < fe->ops.info.symbol_rate_min)
+	    || (p->symbol_rate > fe->ops.info.symbol_rate_max))
+		return -EINVAL;
+
+	if ((p->fec_inner < FEC_NONE)
+	    || (p->fec_inner > FEC_AUTO))
+		return -EINVAL;
+
+	if ((p->fec_inner == FEC_4_5)
+	    || (p->fec_inner == FEC_8_9))
+		return -EINVAL;
+
+	switch (state->id) {
+	case ID_VP310:
+	/* For now we will do this only for the VP310.
+	 * It should be better for the mt312 as well,
+	 * but tuning will be slower. ACCJr 09/29/03
+	 */
+		ret = mt312_readreg(state, CONFIG, &config_val);
+		if (ret < 0)
+			return ret;
+		if (p->symbol_rate >= 30000000) {
+			/* Note that 30MS/s should use 90MHz */
+			if (state->freq_mult == 6) {
+				/* We are running 60MHz */
+				state->freq_mult = 9;
+				ret = mt312_initfe(fe);
+				if (ret < 0)
+					return ret;
+			}
+		} else {
+			if (state->freq_mult == 9) {
+				/* We are running 90MHz */
+				state->freq_mult = 6;
+				ret = mt312_initfe(fe);
+				if (ret < 0)
+					return ret;
+			}
+		}
+		break;
+
+	case ID_MT312:
+	case ID_ZL10313:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	/* sr = (u16)(sr * 256.0 / 1000000.0) */
+	sr = mt312_div(p->symbol_rate * 4, 15625);
+
+	/* SYM_RATE */
+	buf[0] = (sr >> 8) & 0x3f;
+	buf[1] = (sr >> 0) & 0xff;
+
+	/* VIT_MODE */
+	buf[2] = inv_tab[p->inversion] | fec_tab[p->fec_inner];
+
+	/* QPSK_CTRL */
+	buf[3] = 0x40;		/* swap I and Q before QPSK demodulation */
+
+	if (p->symbol_rate < 10000000)
+		buf[3] |= 0x04;	/* use afc mode */
+
+	/* GO */
+	buf[4] = 0x01;
+
+	ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf));
+	if (ret < 0)
+		return ret;
+
+	mt312_reset(state, 0);
+
+	return 0;
+}
+
+static int mt312_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct mt312_state *state = fe->demodulator_priv;
+	int ret;
+
+	ret = mt312_get_inversion(state, &p->inversion);
+	if (ret < 0)
+		return ret;
+
+	ret = mt312_get_symbol_rate(state, &p->symbol_rate);
+	if (ret < 0)
+		return ret;
+
+	ret = mt312_get_code_rate(state, &p->fec_inner);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int mt312_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct mt312_state *state = fe->demodulator_priv;
+
+	u8 val = 0x00;
+	int ret;
+
+	switch (state->id) {
+	case ID_ZL10313:
+		ret = mt312_readreg(state, GPP_CTRL, &val);
+		if (ret < 0)
+			goto error;
+
+		/* preserve this bit to not accidentally shutdown ADC */
+		val &= 0x80;
+		break;
+	}
+
+	if (enable)
+		val |= 0x40;
+	else
+		val &= ~0x40;
+
+	ret = mt312_writereg(state, GPP_CTRL, val);
+
+error:
+	return ret;
+}
+
+static int mt312_sleep(struct dvb_frontend *fe)
+{
+	struct mt312_state *state = fe->demodulator_priv;
+	int ret;
+	u8 config;
+
+	/* reset all registers to defaults */
+	ret = mt312_reset(state, 1);
+	if (ret < 0)
+		return ret;
+
+	if (state->id == ID_ZL10313) {
+		/* reset ADC */
+		ret = mt312_writereg(state, GPP_CTRL, 0x00);
+		if (ret < 0)
+			return ret;
+
+		/* full shutdown of ADCs, mpeg bus tristated */
+		ret = mt312_writereg(state, HW_CTRL, 0x0d);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = mt312_readreg(state, CONFIG, &config);
+	if (ret < 0)
+		return ret;
+
+	/* enter standby */
+	ret = mt312_writereg(state, CONFIG, config & 0x7f);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int mt312_get_tune_settings(struct dvb_frontend *fe,
+		struct dvb_frontend_tune_settings *fesettings)
+{
+	fesettings->min_delay_ms = 50;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+	return 0;
+}
+
+static void mt312_release(struct dvb_frontend *fe)
+{
+	struct mt312_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+#define MT312_SYS_CLK		90000000UL	/* 90 MHz */
+static struct dvb_frontend_ops mt312_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name = "Zarlink ???? DVB-S",
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		/* FIXME: adjust freq to real used xtal */
+		.frequency_stepsize = (MT312_PLL_CLK / 1000) / 128,
+		.symbol_rate_min = MT312_SYS_CLK / 128, /* FIXME as above */
+		.symbol_rate_max = MT312_SYS_CLK / 2,
+		.caps =
+		    FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+		    FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+		    FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_MUTE_TS |
+		    FE_CAN_RECOVER
+	},
+
+	.release = mt312_release,
+
+	.init = mt312_initfe,
+	.sleep = mt312_sleep,
+	.i2c_gate_ctrl = mt312_i2c_gate_ctrl,
+
+	.set_frontend = mt312_set_frontend,
+	.get_frontend = mt312_get_frontend,
+	.get_tune_settings = mt312_get_tune_settings,
+
+	.read_status = mt312_read_status,
+	.read_ber = mt312_read_ber,
+	.read_signal_strength = mt312_read_signal_strength,
+	.read_snr = mt312_read_snr,
+	.read_ucblocks = mt312_read_ucblocks,
+
+	.diseqc_send_master_cmd = mt312_send_master_cmd,
+	.diseqc_send_burst = mt312_send_burst,
+	.set_tone = mt312_set_tone,
+	.set_voltage = mt312_set_voltage,
+};
+
+struct dvb_frontend *mt312_attach(const struct mt312_config *config,
+					struct i2c_adapter *i2c)
+{
+	struct mt312_state *state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct mt312_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+
+	/* check if the demod is there */
+	if (mt312_readreg(state, ID, &state->id) < 0)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &mt312_ops,
+		sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	switch (state->id) {
+	case ID_VP310:
+		strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S");
+		state->xtal = MT312_PLL_CLK;
+		state->freq_mult = 9;
+		break;
+	case ID_MT312:
+		strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S");
+		state->xtal = MT312_PLL_CLK;
+		state->freq_mult = 6;
+		break;
+	case ID_ZL10313:
+		strcpy(state->frontend.ops.info.name, "Zarlink ZL10313 DVB-S");
+		state->xtal = MT312_PLL_CLK_10_111;
+		state->freq_mult = 9;
+		break;
+	default:
+		printk(KERN_WARNING "Only Zarlink VP310/MT312/ZL10313"
+			" are supported chips.\n");
+		goto error;
+	}
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(mt312_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Zarlink VP310/MT312/ZL10313 DVB-S Demodulator driver");
+MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
+MODULE_AUTHOR("Matthias Schwarzott <zzam@gentoo.org>");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/media/dvb-frontends/mt312.h b/drivers/media/dvb-frontends/mt312.h
new file mode 100644
index 0000000..29e3bb5
--- /dev/null
+++ b/drivers/media/dvb-frontends/mt312.h
@@ -0,0 +1,51 @@
+/*
+    Driver for Zarlink MT312 Satellite Channel Decoder
+
+    Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    References:
+    http://products.zarlink.com/product_profiles/MT312.htm
+    http://products.zarlink.com/product_profiles/SL1935.htm
+*/
+
+#ifndef MT312_H
+#define MT312_H
+
+#include <linux/dvb/frontend.h>
+
+struct mt312_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* inverted voltage setting */
+	unsigned int voltage_inverted:1;
+};
+
+#if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE))
+struct dvb_frontend *mt312_attach(const struct mt312_config *config,
+					struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *mt312_attach(
+	const struct mt312_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_MT312 */
+
+#endif /* MT312_H */
diff --git a/drivers/media/dvb-frontends/mt312_priv.h b/drivers/media/dvb-frontends/mt312_priv.h
new file mode 100644
index 0000000..a3959f9
--- /dev/null
+++ b/drivers/media/dvb-frontends/mt312_priv.h
@@ -0,0 +1,165 @@
+/*
+    Driver for Zarlink MT312 QPSK Frontend
+
+    Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef _DVB_FRONTENDS_MT312_PRIV
+#define _DVB_FRONTENDS_MT312_PRIV
+
+enum mt312_reg_addr {
+	QPSK_INT_H = 0,
+	QPSK_INT_M = 1,
+	QPSK_INT_L = 2,
+	FEC_INT = 3,
+	QPSK_STAT_H = 4,
+	QPSK_STAT_L = 5,
+	FEC_STATUS = 6,
+	LNB_FREQ_H = 7,
+	LNB_FREQ_L = 8,
+	M_SNR_H = 9,
+	M_SNR_L = 10,
+	VIT_ERRCNT_H = 11,
+	VIT_ERRCNT_M = 12,
+	VIT_ERRCNT_L = 13,
+	RS_BERCNT_H = 14,
+	RS_BERCNT_M = 15,
+	RS_BERCNT_L = 16,
+	RS_UBC_H = 17,
+	RS_UBC_L = 18,
+	SIG_LEVEL = 19,
+	GPP_CTRL = 20,
+	RESET = 21,
+	DISEQC_MODE = 22,
+	SYM_RATE_H = 23,
+	SYM_RATE_L = 24,
+	VIT_MODE = 25,
+	QPSK_CTRL = 26,
+	GO = 27,
+	IE_QPSK_H = 28,
+	IE_QPSK_M = 29,
+	IE_QPSK_L = 30,
+	IE_FEC = 31,
+	QPSK_STAT_EN = 32,
+	FEC_STAT_EN = 33,
+	SYS_CLK = 34,
+	DISEQC_RATIO = 35,
+	DISEQC_INSTR = 36,
+	FR_LIM = 37,
+	FR_OFF = 38,
+	AGC_CTRL = 39,
+	AGC_INIT = 40,
+	AGC_REF = 41,
+	AGC_MAX = 42,
+	AGC_MIN = 43,
+	AGC_LK_TH = 44,
+	TS_AGC_LK_TH = 45,
+	AGC_PWR_SET = 46,
+	QPSK_MISC = 47,
+	SNR_THS_LOW = 48,
+	SNR_THS_HIGH = 49,
+	TS_SW_RATE = 50,
+	TS_SW_LIM_L = 51,
+	TS_SW_LIM_H = 52,
+	CS_SW_RATE_1 = 53,
+	CS_SW_RATE_2 = 54,
+	CS_SW_RATE_3 = 55,
+	CS_SW_RATE_4 = 56,
+	CS_SW_LIM = 57,
+	TS_LPK = 58,
+	TS_LPK_M = 59,
+	TS_LPK_L = 60,
+	CS_KPROP_H = 61,
+	CS_KPROP_L = 62,
+	CS_KINT_H = 63,
+	CS_KINT_L = 64,
+	QPSK_SCALE = 65,
+	TLD_OUTCLK_TH = 66,
+	TLD_INCLK_TH = 67,
+	FLD_TH = 68,
+	PLD_OUTLK3 = 69,
+	PLD_OUTLK2 = 70,
+	PLD_OUTLK1 = 71,
+	PLD_OUTLK0 = 72,
+	PLD_INLK3 = 73,
+	PLD_INLK2 = 74,
+	PLD_INLK1 = 75,
+	PLD_INLK0 = 76,
+	PLD_ACC_TIME = 77,
+	SWEEP_PAR = 78,
+	STARTUP_TIME = 79,
+	LOSSLOCK_TH = 80,
+	FEC_LOCK_TM = 81,
+	LOSSLOCK_TM = 82,
+	VIT_ERRPER_H = 83,
+	VIT_ERRPER_M = 84,
+	VIT_ERRPER_L = 85,
+	HW_CTRL = 84,	/* ZL10313 only */
+	MPEG_CTRL = 85,	/* ZL10313 only */
+	VIT_SETUP = 86,
+	VIT_REF0 = 87,
+	VIT_REF1 = 88,
+	VIT_REF2 = 89,
+	VIT_REF3 = 90,
+	VIT_REF4 = 91,
+	VIT_REF5 = 92,
+	VIT_REF6 = 93,
+	VIT_MAXERR = 94,
+	BA_SETUPT = 95,
+	OP_CTRL = 96,
+	FEC_SETUP = 97,
+	PROG_SYNC = 98,
+	AFC_SEAR_TH = 99,
+	CSACC_DIF_TH = 100,
+	QPSK_LK_CT = 101,
+	QPSK_ST_CT = 102,
+	MON_CTRL = 103,
+	QPSK_RESET = 104,
+	QPSK_TST_CT = 105,
+	QPSK_TST_ST = 106,
+	TEST_R = 107,
+	AGC_H = 108,
+	AGC_M = 109,
+	AGC_L = 110,
+	FREQ_ERR1_H = 111,
+	FREQ_ERR1_M = 112,
+	FREQ_ERR1_L = 113,
+	FREQ_ERR2_H = 114,
+	FREQ_ERR2_L = 115,
+	SYM_RAT_OP_H = 116,
+	SYM_RAT_OP_L = 117,
+	DESEQC2_INT = 118,
+	DISEQC2_STAT = 119,
+	DISEQC2_FIFO = 120,
+	DISEQC2_CTRL1 = 121,
+	DISEQC2_CTRL2 = 122,
+	MONITOR_H = 123,
+	MONITOR_L = 124,
+	TEST_MODE = 125,
+	ID = 126,
+	CONFIG = 127
+};
+
+enum mt312_model_id {
+	ID_VP310 = 1,
+	ID_MT312 = 3,
+	ID_ZL10313 = 5,
+};
+
+#endif				/* DVB_FRONTENDS_MT312_PRIV */
diff --git a/drivers/media/dvb-frontends/mt352.c b/drivers/media/dvb-frontends/mt352.c
new file mode 100644
index 0000000..2c3b50e
--- /dev/null
+++ b/drivers/media/dvb-frontends/mt352.c
@@ -0,0 +1,610 @@
+/*
+ *  Driver for Zarlink DVB-T MT352 demodulator
+ *
+ *  Written by Holger Waechtler <holger@qanu.de>
+ *	 and Daniel Mack <daniel@qanu.de>
+ *
+ *  AVerMedia AVerTV DVB-T 771 support by
+ *       Wolfram Joost <dbox2@frokaschwei.de>
+ *
+ *  Support for Samsung TDTC9251DH01C(M) tuner
+ *  Copyright (C) 2004 Antonio Mancuso <antonio.mancuso@digitaltelevision.it>
+ *                     Amauri  Celani  <acelani@essegi.net>
+ *
+ *  DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by
+ *       Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "mt352_priv.h"
+#include "mt352.h"
+
+struct mt352_state {
+	struct i2c_adapter* i2c;
+	struct dvb_frontend frontend;
+
+	/* configuration settings */
+	struct mt352_config config;
+};
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "mt352: " args); \
+	} while (0)
+
+static int mt352_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
+{
+	struct mt352_state* state = fe->demodulator_priv;
+	u8 buf[2] = { reg, val };
+	struct i2c_msg msg = { .addr = state->config.demod_address, .flags = 0,
+			       .buf = buf, .len = 2 };
+	int err = i2c_transfer(state->i2c, &msg, 1);
+	if (err != 1) {
+		printk("mt352_write() to reg %x failed (err = %d)!\n", reg, err);
+		return err;
+	}
+	return 0;
+}
+
+static int _mt352_write(struct dvb_frontend* fe, const u8 ibuf[], int ilen)
+{
+	int err,i;
+	for (i=0; i < ilen-1; i++)
+		if ((err = mt352_single_write(fe,ibuf[0]+i,ibuf[i+1])))
+			return err;
+
+	return 0;
+}
+
+static int mt352_read_register(struct mt352_state* state, u8 reg)
+{
+	int ret;
+	u8 b0 [] = { reg };
+	u8 b1 [] = { 0 };
+	struct i2c_msg msg [] = { { .addr = state->config.demod_address,
+				    .flags = 0,
+				    .buf = b0, .len = 1 },
+				  { .addr = state->config.demod_address,
+				    .flags = I2C_M_RD,
+				    .buf = b1, .len = 1 } };
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		printk("%s: readreg error (reg=%d, ret==%i)\n",
+		       __func__, reg, ret);
+		return ret;
+	}
+
+	return b1[0];
+}
+
+static int mt352_sleep(struct dvb_frontend* fe)
+{
+	static u8 mt352_softdown[] = { CLOCK_CTL, 0x20, 0x08 };
+
+	_mt352_write(fe, mt352_softdown, sizeof(mt352_softdown));
+	return 0;
+}
+
+static void mt352_calc_nominal_rate(struct mt352_state* state,
+				    u32 bandwidth,
+				    unsigned char *buf)
+{
+	u32 adc_clock = 20480; /* 20.340 MHz */
+	u32 bw,value;
+
+	switch (bandwidth) {
+	case 6000000:
+		bw = 6;
+		break;
+	case 7000000:
+		bw = 7;
+		break;
+	case 8000000:
+	default:
+		bw = 8;
+		break;
+	}
+	if (state->config.adc_clock)
+		adc_clock = state->config.adc_clock;
+
+	value = 64 * bw * (1<<16) / (7 * 8);
+	value = value * 1000 / adc_clock;
+	dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
+		__func__, bw, adc_clock, value);
+	buf[0] = msb(value);
+	buf[1] = lsb(value);
+}
+
+static void mt352_calc_input_freq(struct mt352_state* state,
+				  unsigned char *buf)
+{
+	int adc_clock = 20480; /* 20.480000 MHz */
+	int if2       = 36167; /* 36.166667 MHz */
+	int ife,value;
+
+	if (state->config.adc_clock)
+		adc_clock = state->config.adc_clock;
+	if (state->config.if2)
+		if2 = state->config.if2;
+
+	if (adc_clock >= if2 * 2)
+		ife = if2;
+	else {
+		ife = adc_clock - (if2 % adc_clock);
+		if (ife > adc_clock / 2)
+			ife = adc_clock - ife;
+	}
+	value = -16374 * ife / adc_clock;
+	dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
+		__func__, if2, ife, adc_clock, value, value & 0x3fff);
+	buf[0] = msb(value);
+	buf[1] = lsb(value);
+}
+
+static int mt352_set_parameters(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *op = &fe->dtv_property_cache;
+	struct mt352_state* state = fe->demodulator_priv;
+	unsigned char buf[13];
+	static unsigned char tuner_go[] = { 0x5d, 0x01 };
+	static unsigned char fsm_go[]   = { 0x5e, 0x01 };
+	unsigned int tps = 0;
+
+	switch (op->code_rate_HP) {
+		case FEC_2_3:
+			tps |= (1 << 7);
+			break;
+		case FEC_3_4:
+			tps |= (2 << 7);
+			break;
+		case FEC_5_6:
+			tps |= (3 << 7);
+			break;
+		case FEC_7_8:
+			tps |= (4 << 7);
+			break;
+		case FEC_1_2:
+		case FEC_AUTO:
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	switch (op->code_rate_LP) {
+		case FEC_2_3:
+			tps |= (1 << 4);
+			break;
+		case FEC_3_4:
+			tps |= (2 << 4);
+			break;
+		case FEC_5_6:
+			tps |= (3 << 4);
+			break;
+		case FEC_7_8:
+			tps |= (4 << 4);
+			break;
+		case FEC_1_2:
+		case FEC_AUTO:
+			break;
+		case FEC_NONE:
+			if (op->hierarchy == HIERARCHY_AUTO ||
+			    op->hierarchy == HIERARCHY_NONE)
+				break;
+		default:
+			return -EINVAL;
+	}
+
+	switch (op->modulation) {
+		case QPSK:
+			break;
+		case QAM_AUTO:
+		case QAM_16:
+			tps |= (1 << 13);
+			break;
+		case QAM_64:
+			tps |= (2 << 13);
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	switch (op->transmission_mode) {
+		case TRANSMISSION_MODE_2K:
+		case TRANSMISSION_MODE_AUTO:
+			break;
+		case TRANSMISSION_MODE_8K:
+			tps |= (1 << 0);
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	switch (op->guard_interval) {
+		case GUARD_INTERVAL_1_32:
+		case GUARD_INTERVAL_AUTO:
+			break;
+		case GUARD_INTERVAL_1_16:
+			tps |= (1 << 2);
+			break;
+		case GUARD_INTERVAL_1_8:
+			tps |= (2 << 2);
+			break;
+		case GUARD_INTERVAL_1_4:
+			tps |= (3 << 2);
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	switch (op->hierarchy) {
+		case HIERARCHY_AUTO:
+		case HIERARCHY_NONE:
+			break;
+		case HIERARCHY_1:
+			tps |= (1 << 10);
+			break;
+		case HIERARCHY_2:
+			tps |= (2 << 10);
+			break;
+		case HIERARCHY_4:
+			tps |= (3 << 10);
+			break;
+		default:
+			return -EINVAL;
+	}
+
+
+	buf[0] = TPS_GIVEN_1; /* TPS_GIVEN_1 and following registers */
+
+	buf[1] = msb(tps);      /* TPS_GIVEN_(1|0) */
+	buf[2] = lsb(tps);
+
+	buf[3] = 0x50;  // old
+//	buf[3] = 0xf4;  // pinnacle
+
+	mt352_calc_nominal_rate(state, op->bandwidth_hz, buf+4);
+	mt352_calc_input_freq(state, buf+6);
+
+	if (state->config.no_tuner) {
+		if (fe->ops.tuner_ops.set_params) {
+			fe->ops.tuner_ops.set_params(fe);
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+
+		_mt352_write(fe, buf, 8);
+		_mt352_write(fe, fsm_go, 2);
+	} else {
+		if (fe->ops.tuner_ops.calc_regs) {
+			fe->ops.tuner_ops.calc_regs(fe, buf+8, 5);
+			buf[8] <<= 1;
+			_mt352_write(fe, buf, sizeof(buf));
+			_mt352_write(fe, tuner_go, 2);
+		}
+	}
+
+	return 0;
+}
+
+static int mt352_get_parameters(struct dvb_frontend* fe)
+{
+	struct dtv_frontend_properties *op = &fe->dtv_property_cache;
+	struct mt352_state* state = fe->demodulator_priv;
+	u16 tps;
+	u16 div;
+	u8 trl;
+	static const u8 tps_fec_to_api[8] =
+	{
+		FEC_1_2,
+		FEC_2_3,
+		FEC_3_4,
+		FEC_5_6,
+		FEC_7_8,
+		FEC_AUTO,
+		FEC_AUTO,
+		FEC_AUTO
+	};
+
+	if ( (mt352_read_register(state,0x00) & 0xC0) != 0xC0 )
+		return -EINVAL;
+
+	/* Use TPS_RECEIVED-registers, not the TPS_CURRENT-registers because
+	 * the mt352 sometimes works with the wrong parameters
+	 */
+	tps = (mt352_read_register(state, TPS_RECEIVED_1) << 8) | mt352_read_register(state, TPS_RECEIVED_0);
+	div = (mt352_read_register(state, CHAN_START_1) << 8) | mt352_read_register(state, CHAN_START_0);
+	trl = mt352_read_register(state, TRL_NOMINAL_RATE_1);
+
+	op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7];
+	op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7];
+
+	switch ( (tps >> 13) & 3)
+	{
+		case 0:
+			op->modulation = QPSK;
+			break;
+		case 1:
+			op->modulation = QAM_16;
+			break;
+		case 2:
+			op->modulation = QAM_64;
+			break;
+		default:
+			op->modulation = QAM_AUTO;
+			break;
+	}
+
+	op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K : TRANSMISSION_MODE_2K;
+
+	switch ( (tps >> 2) & 3)
+	{
+		case 0:
+			op->guard_interval = GUARD_INTERVAL_1_32;
+			break;
+		case 1:
+			op->guard_interval = GUARD_INTERVAL_1_16;
+			break;
+		case 2:
+			op->guard_interval = GUARD_INTERVAL_1_8;
+			break;
+		case 3:
+			op->guard_interval = GUARD_INTERVAL_1_4;
+			break;
+		default:
+			op->guard_interval = GUARD_INTERVAL_AUTO;
+			break;
+	}
+
+	switch ( (tps >> 10) & 7)
+	{
+		case 0:
+			op->hierarchy = HIERARCHY_NONE;
+			break;
+		case 1:
+			op->hierarchy = HIERARCHY_1;
+			break;
+		case 2:
+			op->hierarchy = HIERARCHY_2;
+			break;
+		case 3:
+			op->hierarchy = HIERARCHY_4;
+			break;
+		default:
+			op->hierarchy = HIERARCHY_AUTO;
+			break;
+	}
+
+	op->frequency = (500 * (div - IF_FREQUENCYx6)) / 3 * 1000;
+
+	if (trl == 0x72)
+		op->bandwidth_hz = 8000000;
+	else if (trl == 0x64)
+		op->bandwidth_hz = 7000000;
+	else
+		op->bandwidth_hz = 6000000;
+
+
+	if (mt352_read_register(state, STATUS_2) & 0x02)
+		op->inversion = INVERSION_OFF;
+	else
+		op->inversion = INVERSION_ON;
+
+	return 0;
+}
+
+static int mt352_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct mt352_state* state = fe->demodulator_priv;
+	int s0, s1, s3;
+
+	/* FIXME:
+	 *
+	 * The MT352 design manual from Zarlink states (page 46-47):
+	 *
+	 * Notes about the TUNER_GO register:
+	 *
+	 * If the Read_Tuner_Byte (bit-1) is activated, then the tuner status
+	 * byte is copied from the tuner to the STATUS_3 register and
+	 * completion of the read operation is indicated by bit-5 of the
+	 * INTERRUPT_3 register.
+	 */
+
+	if ((s0 = mt352_read_register(state, STATUS_0)) < 0)
+		return -EREMOTEIO;
+	if ((s1 = mt352_read_register(state, STATUS_1)) < 0)
+		return -EREMOTEIO;
+	if ((s3 = mt352_read_register(state, STATUS_3)) < 0)
+		return -EREMOTEIO;
+
+	*status = 0;
+	if (s0 & (1 << 4))
+		*status |= FE_HAS_CARRIER;
+	if (s0 & (1 << 1))
+		*status |= FE_HAS_VITERBI;
+	if (s0 & (1 << 5))
+		*status |= FE_HAS_LOCK;
+	if (s1 & (1 << 1))
+		*status |= FE_HAS_SYNC;
+	if (s3 & (1 << 6))
+		*status |= FE_HAS_SIGNAL;
+
+	if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
+		      (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
+		*status &= ~FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int mt352_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct mt352_state* state = fe->demodulator_priv;
+
+	*ber = (mt352_read_register (state, RS_ERR_CNT_2) << 16) |
+	       (mt352_read_register (state, RS_ERR_CNT_1) << 8) |
+	       (mt352_read_register (state, RS_ERR_CNT_0));
+
+	return 0;
+}
+
+static int mt352_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct mt352_state* state = fe->demodulator_priv;
+
+	/* align the 12 bit AGC gain with the most significant bits */
+	u16 signal = ((mt352_read_register(state, AGC_GAIN_1) & 0x0f) << 12) |
+		(mt352_read_register(state, AGC_GAIN_0) << 4);
+
+	/* inverse of gain is signal strength */
+	*strength = ~signal;
+	return 0;
+}
+
+static int mt352_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct mt352_state* state = fe->demodulator_priv;
+
+	u8 _snr = mt352_read_register (state, SNR);
+	*snr = (_snr << 8) | _snr;
+
+	return 0;
+}
+
+static int mt352_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct mt352_state* state = fe->demodulator_priv;
+
+	*ucblocks = (mt352_read_register (state,  RS_UBC_1) << 8) |
+		    (mt352_read_register (state,  RS_UBC_0));
+
+	return 0;
+}
+
+static int mt352_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings)
+{
+	fe_tune_settings->min_delay_ms = 800;
+	fe_tune_settings->step_size = 0;
+	fe_tune_settings->max_drift = 0;
+
+	return 0;
+}
+
+static int mt352_init(struct dvb_frontend* fe)
+{
+	struct mt352_state* state = fe->demodulator_priv;
+
+	static u8 mt352_reset_attach [] = { RESET, 0xC0 };
+
+	dprintk("%s: hello\n",__func__);
+
+	if ((mt352_read_register(state, CLOCK_CTL) & 0x10) == 0 ||
+	    (mt352_read_register(state, CONFIG) & 0x20) == 0) {
+
+		/* Do a "hard" reset */
+		_mt352_write(fe, mt352_reset_attach, sizeof(mt352_reset_attach));
+		return state->config.demod_init(fe);
+	}
+
+	return 0;
+}
+
+static void mt352_release(struct dvb_frontend* fe)
+{
+	struct mt352_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops mt352_ops;
+
+struct dvb_frontend* mt352_attach(const struct mt352_config* config,
+				  struct i2c_adapter* i2c)
+{
+	struct mt352_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct mt352_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->i2c = i2c;
+	memcpy(&state->config,config,sizeof(struct mt352_config));
+
+	/* check if the demod is there */
+	if (mt352_read_register(state, CHIP_ID) != ID_MT352) goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &mt352_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops mt352_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name			= "Zarlink MT352 DVB-T",
+		.frequency_min		= 174000000,
+		.frequency_max		= 862000000,
+		.frequency_stepsize	= 166667,
+		.frequency_tolerance	= 0,
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+			FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER |
+			FE_CAN_MUTE_TS
+	},
+
+	.release = mt352_release,
+
+	.init = mt352_init,
+	.sleep = mt352_sleep,
+	.write = _mt352_write,
+
+	.set_frontend = mt352_set_parameters,
+	.get_frontend = mt352_get_parameters,
+	.get_tune_settings = mt352_get_tune_settings,
+
+	.read_status = mt352_read_status,
+	.read_ber = mt352_read_ber,
+	.read_signal_strength = mt352_read_signal_strength,
+	.read_snr = mt352_read_snr,
+	.read_ucblocks = mt352_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Zarlink MT352 DVB-T Demodulator driver");
+MODULE_AUTHOR("Holger Waechtler, Daniel Mack, Antonio Mancuso");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(mt352_attach);
diff --git a/drivers/media/dvb-frontends/mt352.h b/drivers/media/dvb-frontends/mt352.h
new file mode 100644
index 0000000..ca2562d
--- /dev/null
+++ b/drivers/media/dvb-frontends/mt352.h
@@ -0,0 +1,73 @@
+/*
+ *  Driver for Zarlink DVB-T MT352 demodulator
+ *
+ *  Written by Holger Waechtler <holger@qanu.de>
+ *	 and Daniel Mack <daniel@qanu.de>
+ *
+ *  AVerMedia AVerTV DVB-T 771 support by
+ *       Wolfram Joost <dbox2@frokaschwei.de>
+ *
+ *  Support for Samsung TDTC9251DH01C(M) tuner
+ *  Copyright (C) 2004 Antonio Mancuso <antonio.mancuso@digitaltelevision.it>
+ *                     Amauri  Celani  <acelani@essegi.net>
+ *
+ *  DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by
+ *       Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef MT352_H
+#define MT352_H
+
+#include <linux/dvb/frontend.h>
+
+struct mt352_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* frequencies in kHz */
+	int adc_clock;  // default: 20480
+	int if2;        // default: 36166
+
+	/* set if no pll is connected to the secondary i2c bus */
+	int no_tuner;
+
+	/* Initialise the demodulator and PLL. Cannot be NULL */
+	int (*demod_init)(struct dvb_frontend* fe);
+};
+
+#if defined(CONFIG_DVB_MT352) || (defined(CONFIG_DVB_MT352_MODULE) && defined(MODULE))
+extern struct dvb_frontend* mt352_attach(const struct mt352_config* config,
+					 struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* mt352_attach(const struct mt352_config* config,
+					 struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_MT352
+
+static inline int mt352_write(struct dvb_frontend *fe, const u8 buf[], int len) {
+	int r = 0;
+	if (fe->ops.write)
+		r = fe->ops.write(fe, buf, len);
+	return r;
+}
+
+#endif // MT352_H
diff --git a/drivers/media/dvb-frontends/mt352_priv.h b/drivers/media/dvb-frontends/mt352_priv.h
new file mode 100644
index 0000000..44ad0d4
--- /dev/null
+++ b/drivers/media/dvb-frontends/mt352_priv.h
@@ -0,0 +1,127 @@
+/*
+ *  Driver for Zarlink DVB-T MT352 demodulator
+ *
+ *  Written by Holger Waechtler <holger@qanu.de>
+ *	 and Daniel Mack <daniel@qanu.de>
+ *
+ *  AVerMedia AVerTV DVB-T 771 support by
+ *       Wolfram Joost <dbox2@frokaschwei.de>
+ *
+ *  Support for Samsung TDTC9251DH01C(M) tuner
+ *  Copyright (C) 2004 Antonio Mancuso <antonio.mancuso@digitaltelevision.it>
+ *                     Amauri  Celani  <acelani@essegi.net>
+ *
+ *  DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by
+ *       Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef _MT352_PRIV_
+#define _MT352_PRIV_
+
+#define ID_MT352        0x13
+
+#define msb(x) (((x) >> 8) & 0xff)
+#define lsb(x) ((x) & 0xff)
+
+enum mt352_reg_addr {
+	STATUS_0           = 0x00,
+	STATUS_1           = 0x01,
+	STATUS_2           = 0x02,
+	STATUS_3           = 0x03,
+	STATUS_4           = 0x04,
+	INTERRUPT_0        = 0x05,
+	INTERRUPT_1        = 0x06,
+	INTERRUPT_2        = 0x07,
+	INTERRUPT_3        = 0x08,
+	SNR                = 0x09,
+	VIT_ERR_CNT_2      = 0x0A,
+	VIT_ERR_CNT_1      = 0x0B,
+	VIT_ERR_CNT_0      = 0x0C,
+	RS_ERR_CNT_2       = 0x0D,
+	RS_ERR_CNT_1       = 0x0E,
+	RS_ERR_CNT_0       = 0x0F,
+	RS_UBC_1           = 0x10,
+	RS_UBC_0           = 0x11,
+	AGC_GAIN_3         = 0x12,
+	AGC_GAIN_2         = 0x13,
+	AGC_GAIN_1         = 0x14,
+	AGC_GAIN_0         = 0x15,
+	FREQ_OFFSET_2      = 0x17,
+	FREQ_OFFSET_1      = 0x18,
+	FREQ_OFFSET_0      = 0x19,
+	TIMING_OFFSET_1    = 0x1A,
+	TIMING_OFFSET_0    = 0x1B,
+	CHAN_FREQ_1        = 0x1C,
+	CHAN_FREQ_0        = 0x1D,
+	TPS_RECEIVED_1     = 0x1E,
+	TPS_RECEIVED_0     = 0x1F,
+	TPS_CURRENT_1      = 0x20,
+	TPS_CURRENT_0      = 0x21,
+	TPS_CELL_ID_1      = 0x22,
+	TPS_CELL_ID_0      = 0x23,
+	TPS_MISC_DATA_2    = 0x24,
+	TPS_MISC_DATA_1    = 0x25,
+	TPS_MISC_DATA_0    = 0x26,
+	RESET              = 0x50,
+	TPS_GIVEN_1        = 0x51,
+	TPS_GIVEN_0        = 0x52,
+	ACQ_CTL            = 0x53,
+	TRL_NOMINAL_RATE_1 = 0x54,
+	TRL_NOMINAL_RATE_0 = 0x55,
+	INPUT_FREQ_1       = 0x56,
+	INPUT_FREQ_0       = 0x57,
+	TUNER_ADDR         = 0x58,
+	CHAN_START_1       = 0x59,
+	CHAN_START_0       = 0x5A,
+	CONT_1             = 0x5B,
+	CONT_0             = 0x5C,
+	TUNER_GO           = 0x5D,
+	STATUS_EN_0        = 0x5F,
+	STATUS_EN_1        = 0x60,
+	INTERRUPT_EN_0     = 0x61,
+	INTERRUPT_EN_1     = 0x62,
+	INTERRUPT_EN_2     = 0x63,
+	INTERRUPT_EN_3     = 0x64,
+	AGC_TARGET         = 0x67,
+	AGC_CTL            = 0x68,
+	CAPT_RANGE         = 0x75,
+	SNR_SELECT_1       = 0x79,
+	SNR_SELECT_0       = 0x7A,
+	RS_ERR_PER_1       = 0x7C,
+	RS_ERR_PER_0       = 0x7D,
+	CHIP_ID            = 0x7F,
+	CHAN_STOP_1        = 0x80,
+	CHAN_STOP_0        = 0x81,
+	CHAN_STEP_1        = 0x82,
+	CHAN_STEP_0        = 0x83,
+	FEC_LOCK_TIME      = 0x85,
+	OFDM_LOCK_TIME     = 0x86,
+	ACQ_DELAY          = 0x87,
+	SCAN_CTL           = 0x88,
+	CLOCK_CTL          = 0x89,
+	CONFIG             = 0x8A,
+	MCLK_RATIO         = 0x8B,
+	GPP_CTL            = 0x8C,
+	ADC_CTL_1          = 0x8E,
+	ADC_CTL_0          = 0x8F
+};
+
+/* here we assume 1/6MHz == 166.66kHz stepsize */
+#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
+
+#endif                          /* _MT352_PRIV_ */
diff --git a/drivers/media/dvb-frontends/nxt200x.c b/drivers/media/dvb-frontends/nxt200x.c
new file mode 100644
index 0000000..8e28894
--- /dev/null
+++ b/drivers/media/dvb-frontends/nxt200x.c
@@ -0,0 +1,1242 @@
+/*
+ *    Support for NXT2002 and NXT2004 - VSB/QAM
+ *
+ *    Copyright (C) 2005 Kirk Lapray <kirk.lapray@gmail.com>
+ *    Copyright (C) 2006 Michael Krufky <mkrufky@m1k.net>
+ *    based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net>
+ *    and nxt2004 by Jean-Francois Thibert <jeanfrancois@sagetv.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+/*
+ *                      NOTES ABOUT THIS DRIVER
+ *
+ * This Linux driver supports:
+ *   B2C2/BBTI Technisat Air2PC - ATSC (NXT2002)
+ *   AverTVHD MCE A180 (NXT2004)
+ *   ATI HDTV Wonder (NXT2004)
+ *
+ * This driver needs external firmware. Please use the command
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" or
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
+ * download/extract the appropriate firmware, and then copy it to
+ * /usr/lib/hotplug/firmware/ or /lib/firmware/
+ * (depending on configuration of firmware hotplug).
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
+#define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw"
+#define CRC_CCIT_MASK 0x1021
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "dvb_frontend.h"
+#include "nxt200x.h"
+
+struct nxt200x_state {
+
+	struct i2c_adapter* i2c;
+	const struct nxt200x_config* config;
+	struct dvb_frontend frontend;
+
+	/* demodulator private data */
+	nxt_chip_type demod_chip;
+	u8 initialised:1;
+};
+
+static int debug;
+#define dprintk(args...)	do { if (debug) pr_debug(args); } while (0)
+
+static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len)
+{
+	int err;
+	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len };
+
+	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+		pr_warn("%s: i2c write error (addr 0x%02x, err == %i)\n",
+			__func__, addr, err);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int i2c_readbytes(struct nxt200x_state *state, u8 addr, u8 *buf, u8 len)
+{
+	int err;
+	struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len };
+
+	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+		pr_warn("%s: i2c read error (addr 0x%02x, err == %i)\n",
+			__func__, addr, err);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg,
+			       const u8 *buf, u8 len)
+{
+	u8 buf2 [len+1];
+	int err;
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 };
+
+	buf2[0] = reg;
+	memcpy(&buf2[1], buf, len);
+
+	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+		pr_warn("%s: i2c write error (addr 0x%02x, err == %i)\n",
+			__func__, state->config->demod_address, err);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int nxt200x_readbytes(struct nxt200x_state *state, u8 reg, u8 *buf, u8 len)
+{
+	u8 reg2 [] = { reg };
+
+	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = reg2, .len = 1 },
+			{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } };
+
+	int err;
+
+	if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {
+		pr_warn("%s: i2c read error (addr 0x%02x, err == %i)\n",
+			__func__, state->config->demod_address, err);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static u16 nxt200x_crc(u16 crc, u8 c)
+{
+	u8 i;
+	u16 input = (u16) c & 0xFF;
+
+	input<<=8;
+	for(i=0; i<8; i++) {
+		if((crc^input) & 0x8000)
+			crc=(crc<<1)^CRC_CCIT_MASK;
+		else
+			crc<<=1;
+		input<<=1;
+	}
+	return crc;
+}
+
+static int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len)
+{
+	u8 attr, len2, buf;
+	dprintk("%s\n", __func__);
+
+	/* set mutli register register */
+	nxt200x_writebytes(state, 0x35, &reg, 1);
+
+	/* send the actual data */
+	nxt200x_writebytes(state, 0x36, data, len);
+
+	switch (state->demod_chip) {
+		case NXT2002:
+			len2 = len;
+			buf = 0x02;
+			break;
+		case NXT2004:
+			/* probably not right, but gives correct values */
+			attr = 0x02;
+			if (reg & 0x80) {
+				attr = attr << 1;
+				if (reg & 0x04)
+					attr = attr >> 1;
+			}
+			/* set write bit */
+			len2 = ((attr << 4) | 0x10) | len;
+			buf = 0x80;
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+
+	/* set multi register length */
+	nxt200x_writebytes(state, 0x34, &len2, 1);
+
+	/* toggle the multireg write bit */
+	nxt200x_writebytes(state, 0x21, &buf, 1);
+
+	nxt200x_readbytes(state, 0x21, &buf, 1);
+
+	switch (state->demod_chip) {
+		case NXT2002:
+			if ((buf & 0x02) == 0)
+				return 0;
+			break;
+		case NXT2004:
+			if (buf == 0)
+				return 0;
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+
+	pr_warn("Error writing multireg register 0x%02X\n", reg);
+
+	return 0;
+}
+
+static int nxt200x_readreg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len)
+{
+	int i;
+	u8 buf, len2, attr;
+	dprintk("%s\n", __func__);
+
+	/* set mutli register register */
+	nxt200x_writebytes(state, 0x35, &reg, 1);
+
+	switch (state->demod_chip) {
+		case NXT2002:
+			/* set multi register length */
+			len2 = len & 0x80;
+			nxt200x_writebytes(state, 0x34, &len2, 1);
+
+			/* read the actual data */
+			nxt200x_readbytes(state, reg, data, len);
+			return 0;
+			break;
+		case NXT2004:
+			/* probably not right, but gives correct values */
+			attr = 0x02;
+			if (reg & 0x80) {
+				attr = attr << 1;
+				if (reg & 0x04)
+					attr = attr >> 1;
+			}
+
+			/* set multi register length */
+			len2 = (attr << 4) | len;
+			nxt200x_writebytes(state, 0x34, &len2, 1);
+
+			/* toggle the multireg bit*/
+			buf = 0x80;
+			nxt200x_writebytes(state, 0x21, &buf, 1);
+
+			/* read the actual data */
+			for(i = 0; i < len; i++) {
+				nxt200x_readbytes(state, 0x36 + i, &data[i], 1);
+			}
+			return 0;
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+}
+
+static void nxt200x_microcontroller_stop (struct nxt200x_state* state)
+{
+	u8 buf, stopval, counter = 0;
+	dprintk("%s\n", __func__);
+
+	/* set correct stop value */
+	switch (state->demod_chip) {
+		case NXT2002:
+			stopval = 0x40;
+			break;
+		case NXT2004:
+			stopval = 0x10;
+			break;
+		default:
+			stopval = 0;
+			break;
+	}
+
+	buf = 0x80;
+	nxt200x_writebytes(state, 0x22, &buf, 1);
+
+	while (counter < 20) {
+		nxt200x_readbytes(state, 0x31, &buf, 1);
+		if (buf & stopval)
+			return;
+		msleep(10);
+		counter++;
+	}
+
+	pr_warn("Timeout waiting for nxt200x to stop. This is ok after "
+		"firmware upload.\n");
+	return;
+}
+
+static void nxt200x_microcontroller_start (struct nxt200x_state* state)
+{
+	u8 buf;
+	dprintk("%s\n", __func__);
+
+	buf = 0x00;
+	nxt200x_writebytes(state, 0x22, &buf, 1);
+}
+
+static void nxt2004_microcontroller_init (struct nxt200x_state* state)
+{
+	u8 buf[9];
+	u8 counter = 0;
+	dprintk("%s\n", __func__);
+
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0x2b, buf, 1);
+	buf[0] = 0x70;
+	nxt200x_writebytes(state, 0x34, buf, 1);
+	buf[0] = 0x04;
+	nxt200x_writebytes(state, 0x35, buf, 1);
+	buf[0] = 0x01; buf[1] = 0x23; buf[2] = 0x45; buf[3] = 0x67; buf[4] = 0x89;
+	buf[5] = 0xAB; buf[6] = 0xCD; buf[7] = 0xEF; buf[8] = 0xC0;
+	nxt200x_writebytes(state, 0x36, buf, 9);
+	buf[0] = 0x80;
+	nxt200x_writebytes(state, 0x21, buf, 1);
+
+	while (counter < 20) {
+		nxt200x_readbytes(state, 0x21, buf, 1);
+		if (buf[0] == 0)
+			return;
+		msleep(10);
+		counter++;
+	}
+
+	pr_warn("Timeout waiting for nxt2004 to init.\n");
+
+	return;
+}
+
+static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
+{
+	u8 buf, count = 0;
+
+	dprintk("%s\n", __func__);
+
+	dprintk("Tuner Bytes: %*ph\n", 4, data + 1);
+
+	/* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip.
+	 * direct write is required for Philips TUV1236D and ALPS TDHU2 */
+	switch (state->demod_chip) {
+		case NXT2004:
+			if (i2c_writebytes(state, data[0], data+1, 4))
+				pr_warn("error writing to tuner\n");
+			/* wait until we have a lock */
+			while (count < 20) {
+				i2c_readbytes(state, data[0], &buf, 1);
+				if (buf & 0x40)
+					return 0;
+				msleep(100);
+				count++;
+			}
+			pr_warn("timeout waiting for tuner lock\n");
+			break;
+		case NXT2002:
+			/* set the i2c transfer speed to the tuner */
+			buf = 0x03;
+			nxt200x_writebytes(state, 0x20, &buf, 1);
+
+			/* setup to transfer 4 bytes via i2c */
+			buf = 0x04;
+			nxt200x_writebytes(state, 0x34, &buf, 1);
+
+			/* write actual tuner bytes */
+			nxt200x_writebytes(state, 0x36, data+1, 4);
+
+			/* set tuner i2c address */
+			buf = data[0] << 1;
+			nxt200x_writebytes(state, 0x35, &buf, 1);
+
+			/* write UC Opmode to begin transfer */
+			buf = 0x80;
+			nxt200x_writebytes(state, 0x21, &buf, 1);
+
+			while (count < 20) {
+				nxt200x_readbytes(state, 0x21, &buf, 1);
+				if ((buf & 0x80)== 0x00)
+					return 0;
+				msleep(100);
+				count++;
+			}
+			pr_warn("timeout error writing to tuner\n");
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+	return 0;
+}
+
+static void nxt200x_agc_reset(struct nxt200x_state* state)
+{
+	u8 buf;
+	dprintk("%s\n", __func__);
+
+	switch (state->demod_chip) {
+		case NXT2002:
+			buf = 0x08;
+			nxt200x_writebytes(state, 0x08, &buf, 1);
+			buf = 0x00;
+			nxt200x_writebytes(state, 0x08, &buf, 1);
+			break;
+		case NXT2004:
+			nxt200x_readreg_multibyte(state, 0x08, &buf, 1);
+			buf = 0x08;
+			nxt200x_writereg_multibyte(state, 0x08, &buf, 1);
+			buf = 0x00;
+			nxt200x_writereg_multibyte(state, 0x08, &buf, 1);
+			break;
+		default:
+			break;
+	}
+	return;
+}
+
+static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
+{
+
+	struct nxt200x_state* state = fe->demodulator_priv;
+	u8 buf[3], written = 0, chunkpos = 0;
+	u16 rambase, position, crc = 0;
+
+	dprintk("%s\n", __func__);
+	dprintk("Firmware is %zu bytes\n", fw->size);
+
+	/* Get the RAM base for this nxt2002 */
+	nxt200x_readbytes(state, 0x10, buf, 1);
+
+	if (buf[0] & 0x10)
+		rambase = 0x1000;
+	else
+		rambase = 0x0000;
+
+	dprintk("rambase on this nxt2002 is %04X\n", rambase);
+
+	/* Hold the micro in reset while loading firmware */
+	buf[0] = 0x80;
+	nxt200x_writebytes(state, 0x2B, buf, 1);
+
+	for (position = 0; position < fw->size; position++) {
+		if (written == 0) {
+			crc = 0;
+			chunkpos = 0x28;
+			buf[0] = ((rambase + position) >> 8);
+			buf[1] = (rambase + position) & 0xFF;
+			buf[2] = 0x81;
+			/* write starting address */
+			nxt200x_writebytes(state, 0x29, buf, 3);
+		}
+		written++;
+		chunkpos++;
+
+		if ((written % 4) == 0)
+			nxt200x_writebytes(state, chunkpos, &fw->data[position-3], 4);
+
+		crc = nxt200x_crc(crc, fw->data[position]);
+
+		if ((written == 255) || (position+1 == fw->size)) {
+			/* write remaining bytes of firmware */
+			nxt200x_writebytes(state, chunkpos+4-(written %4),
+				&fw->data[position-(written %4) + 1],
+				written %4);
+			buf[0] = crc << 8;
+			buf[1] = crc & 0xFF;
+
+			/* write crc */
+			nxt200x_writebytes(state, 0x2C, buf, 2);
+
+			/* do a read to stop things */
+			nxt200x_readbytes(state, 0x2A, buf, 1);
+
+			/* set transfer mode to complete */
+			buf[0] = 0x80;
+			nxt200x_writebytes(state, 0x2B, buf, 1);
+
+			written = 0;
+		}
+	}
+
+	return 0;
+};
+
+static int nxt2004_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
+{
+
+	struct nxt200x_state* state = fe->demodulator_priv;
+	u8 buf[3];
+	u16 rambase, position, crc=0;
+
+	dprintk("%s\n", __func__);
+	dprintk("Firmware is %zu bytes\n", fw->size);
+
+	/* set rambase */
+	rambase = 0x1000;
+
+	/* hold the micro in reset while loading firmware */
+	buf[0] = 0x80;
+	nxt200x_writebytes(state, 0x2B, buf,1);
+
+	/* calculate firmware CRC */
+	for (position = 0; position < fw->size; position++) {
+		crc = nxt200x_crc(crc, fw->data[position]);
+	}
+
+	buf[0] = rambase >> 8;
+	buf[1] = rambase & 0xFF;
+	buf[2] = 0x81;
+	/* write starting address */
+	nxt200x_writebytes(state,0x29,buf,3);
+
+	for (position = 0; position < fw->size;) {
+		nxt200x_writebytes(state, 0x2C, &fw->data[position],
+			fw->size-position > 255 ? 255 : fw->size-position);
+		position += (fw->size-position > 255 ? 255 : fw->size-position);
+	}
+	buf[0] = crc >> 8;
+	buf[1] = crc & 0xFF;
+
+	dprintk("firmware crc is 0x%02X 0x%02X\n", buf[0], buf[1]);
+
+	/* write crc */
+	nxt200x_writebytes(state, 0x2C, buf,2);
+
+	/* do a read to stop things */
+	nxt200x_readbytes(state, 0x2C, buf, 1);
+
+	/* set transfer mode to complete */
+	buf[0] = 0x80;
+	nxt200x_writebytes(state, 0x2B, buf,1);
+
+	return 0;
+};
+
+static int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct nxt200x_state* state = fe->demodulator_priv;
+	u8 buf[5];
+
+	/* stop the micro first */
+	nxt200x_microcontroller_stop(state);
+
+	if (state->demod_chip == NXT2004) {
+		/* make sure demod is set to digital */
+		buf[0] = 0x04;
+		nxt200x_writebytes(state, 0x14, buf, 1);
+		buf[0] = 0x00;
+		nxt200x_writebytes(state, 0x17, buf, 1);
+	}
+
+	/* set additional params */
+	switch (p->modulation) {
+		case QAM_64:
+		case QAM_256:
+			/* Set punctured clock for QAM */
+			/* This is just a guess since I am unable to test it */
+			if (state->config->set_ts_params)
+				state->config->set_ts_params(fe, 1);
+			break;
+		case VSB_8:
+			/* Set non-punctured clock for VSB */
+			if (state->config->set_ts_params)
+				state->config->set_ts_params(fe, 0);
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+
+	if (fe->ops.tuner_ops.calc_regs) {
+		/* get tuning information */
+		fe->ops.tuner_ops.calc_regs(fe, buf, 5);
+
+		/* write frequency information */
+		nxt200x_writetuner(state, buf);
+	}
+
+	/* reset the agc now that tuning has been completed */
+	nxt200x_agc_reset(state);
+
+	/* set target power level */
+	switch (p->modulation) {
+		case QAM_64:
+		case QAM_256:
+			buf[0] = 0x74;
+			break;
+		case VSB_8:
+			buf[0] = 0x70;
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+	nxt200x_writebytes(state, 0x42, buf, 1);
+
+	/* configure sdm */
+	switch (state->demod_chip) {
+		case NXT2002:
+			buf[0] = 0x87;
+			break;
+		case NXT2004:
+			buf[0] = 0x07;
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+	nxt200x_writebytes(state, 0x57, buf, 1);
+
+	/* write sdm1 input */
+	buf[0] = 0x10;
+	buf[1] = 0x00;
+	switch (state->demod_chip) {
+		case NXT2002:
+			nxt200x_writereg_multibyte(state, 0x58, buf, 2);
+			break;
+		case NXT2004:
+			nxt200x_writebytes(state, 0x58, buf, 2);
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+
+	/* write sdmx input */
+	switch (p->modulation) {
+		case QAM_64:
+				buf[0] = 0x68;
+				break;
+		case QAM_256:
+				buf[0] = 0x64;
+				break;
+		case VSB_8:
+				buf[0] = 0x60;
+				break;
+		default:
+				return -EINVAL;
+				break;
+	}
+	buf[1] = 0x00;
+	switch (state->demod_chip) {
+		case NXT2002:
+			nxt200x_writereg_multibyte(state, 0x5C, buf, 2);
+			break;
+		case NXT2004:
+			nxt200x_writebytes(state, 0x5C, buf, 2);
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+
+	/* write adc power lpf fc */
+	buf[0] = 0x05;
+	nxt200x_writebytes(state, 0x43, buf, 1);
+
+	if (state->demod_chip == NXT2004) {
+		/* write ??? */
+		buf[0] = 0x00;
+		buf[1] = 0x00;
+		nxt200x_writebytes(state, 0x46, buf, 2);
+	}
+
+	/* write accumulator2 input */
+	buf[0] = 0x80;
+	buf[1] = 0x00;
+	switch (state->demod_chip) {
+		case NXT2002:
+			nxt200x_writereg_multibyte(state, 0x4B, buf, 2);
+			break;
+		case NXT2004:
+			nxt200x_writebytes(state, 0x4B, buf, 2);
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+
+	/* write kg1 */
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0x4D, buf, 1);
+
+	/* write sdm12 lpf fc */
+	buf[0] = 0x44;
+	nxt200x_writebytes(state, 0x55, buf, 1);
+
+	/* write agc control reg */
+	buf[0] = 0x04;
+	nxt200x_writebytes(state, 0x41, buf, 1);
+
+	if (state->demod_chip == NXT2004) {
+		nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+		buf[0] = 0x24;
+		nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+		/* soft reset? */
+		nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+		buf[0] = 0x10;
+		nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+		nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+		buf[0] = 0x00;
+		nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+		nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+		buf[0] = 0x04;
+		nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+		buf[0] = 0x00;
+		nxt200x_writereg_multibyte(state, 0x81, buf, 1);
+		buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00;
+		nxt200x_writereg_multibyte(state, 0x82, buf, 3);
+		nxt200x_readreg_multibyte(state, 0x88, buf, 1);
+		buf[0] = 0x11;
+		nxt200x_writereg_multibyte(state, 0x88, buf, 1);
+		nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+		buf[0] = 0x44;
+		nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+	}
+
+	/* write agc ucgp0 */
+	switch (p->modulation) {
+		case QAM_64:
+				buf[0] = 0x02;
+				break;
+		case QAM_256:
+				buf[0] = 0x03;
+				break;
+		case VSB_8:
+				buf[0] = 0x00;
+				break;
+		default:
+				return -EINVAL;
+				break;
+	}
+	nxt200x_writebytes(state, 0x30, buf, 1);
+
+	/* write agc control reg */
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0x41, buf, 1);
+
+	/* write accumulator2 input */
+	buf[0] = 0x80;
+	buf[1] = 0x00;
+	switch (state->demod_chip) {
+		case NXT2002:
+			nxt200x_writereg_multibyte(state, 0x49, buf, 2);
+			nxt200x_writereg_multibyte(state, 0x4B, buf, 2);
+			break;
+		case NXT2004:
+			nxt200x_writebytes(state, 0x49, buf, 2);
+			nxt200x_writebytes(state, 0x4B, buf, 2);
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+
+	/* write agc control reg */
+	buf[0] = 0x04;
+	nxt200x_writebytes(state, 0x41, buf, 1);
+
+	nxt200x_microcontroller_start(state);
+
+	if (state->demod_chip == NXT2004) {
+		nxt2004_microcontroller_init(state);
+
+		/* ???? */
+		buf[0] = 0xF0;
+		buf[1] = 0x00;
+		nxt200x_writebytes(state, 0x5C, buf, 2);
+	}
+
+	/* adjacent channel detection should be done here, but I don't
+	have any stations with this need so I cannot test it */
+
+	return 0;
+}
+
+static int nxt200x_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct nxt200x_state* state = fe->demodulator_priv;
+	u8 lock;
+	nxt200x_readbytes(state, 0x31, &lock, 1);
+
+	*status = 0;
+	if (lock & 0x20) {
+		*status |= FE_HAS_SIGNAL;
+		*status |= FE_HAS_CARRIER;
+		*status |= FE_HAS_VITERBI;
+		*status |= FE_HAS_SYNC;
+		*status |= FE_HAS_LOCK;
+	}
+	return 0;
+}
+
+static int nxt200x_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct nxt200x_state* state = fe->demodulator_priv;
+	u8 b[3];
+
+	nxt200x_readreg_multibyte(state, 0xE6, b, 3);
+
+	*ber = ((b[0] << 8) + b[1]) * 8;
+
+	return 0;
+}
+
+static int nxt200x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct nxt200x_state* state = fe->demodulator_priv;
+	u8 b[2];
+	u16 temp = 0;
+
+	/* setup to read cluster variance */
+	b[0] = 0x00;
+	nxt200x_writebytes(state, 0xA1, b, 1);
+
+	/* get multreg val */
+	nxt200x_readreg_multibyte(state, 0xA6, b, 2);
+
+	temp = (b[0] << 8) | b[1];
+	*strength = ((0x7FFF - temp) & 0x0FFF) * 16;
+
+	return 0;
+}
+
+static int nxt200x_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+
+	struct nxt200x_state* state = fe->demodulator_priv;
+	u8 b[2];
+	u16 temp = 0, temp2;
+	u32 snrdb = 0;
+
+	/* setup to read cluster variance */
+	b[0] = 0x00;
+	nxt200x_writebytes(state, 0xA1, b, 1);
+
+	/* get multreg val from 0xA6 */
+	nxt200x_readreg_multibyte(state, 0xA6, b, 2);
+
+	temp = (b[0] << 8) | b[1];
+	temp2 = 0x7FFF - temp;
+
+	/* snr will be in db */
+	if (temp2 > 0x7F00)
+		snrdb = 1000*24 + ( 1000*(30-24) * ( temp2 - 0x7F00 ) / ( 0x7FFF - 0x7F00 ) );
+	else if (temp2 > 0x7EC0)
+		snrdb = 1000*18 + ( 1000*(24-18) * ( temp2 - 0x7EC0 ) / ( 0x7F00 - 0x7EC0 ) );
+	else if (temp2 > 0x7C00)
+		snrdb = 1000*12 + ( 1000*(18-12) * ( temp2 - 0x7C00 ) / ( 0x7EC0 - 0x7C00 ) );
+	else
+		snrdb = 1000*0 + ( 1000*(12-0) * ( temp2 - 0 ) / ( 0x7C00 - 0 ) );
+
+	/* the value reported back from the frontend will be FFFF=32db 0000=0db */
+	*snr = snrdb * (0xFFFF/32000);
+
+	return 0;
+}
+
+static int nxt200x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct nxt200x_state* state = fe->demodulator_priv;
+	u8 b[3];
+
+	nxt200x_readreg_multibyte(state, 0xE6, b, 3);
+	*ucblocks = b[2];
+
+	return 0;
+}
+
+static int nxt200x_sleep(struct dvb_frontend* fe)
+{
+	return 0;
+}
+
+static int nxt2002_init(struct dvb_frontend* fe)
+{
+	struct nxt200x_state* state = fe->demodulator_priv;
+	const struct firmware *fw;
+	int ret;
+	u8 buf[2];
+
+	/* request the firmware, this will block until someone uploads it */
+	pr_debug("%s: Waiting for firmware upload (%s)...\n",
+		 __func__, NXT2002_DEFAULT_FIRMWARE);
+	ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE,
+			       state->i2c->dev.parent);
+	pr_debug("%s: Waiting for firmware upload(2)...\n", __func__);
+	if (ret) {
+		pr_err("%s: No firmware uploaded (timeout or file not found?)"
+		       "\n", __func__);
+		return ret;
+	}
+
+	ret = nxt2002_load_firmware(fe, fw);
+	release_firmware(fw);
+	if (ret) {
+		pr_err("%s: Writing firmware to device failed\n", __func__);
+		return ret;
+	}
+	pr_info("%s: Firmware upload complete\n", __func__);
+
+	/* Put the micro into reset */
+	nxt200x_microcontroller_stop(state);
+
+	/* ensure transfer is complete */
+	buf[0]=0x00;
+	nxt200x_writebytes(state, 0x2B, buf, 1);
+
+	/* Put the micro into reset for real this time */
+	nxt200x_microcontroller_stop(state);
+
+	/* soft reset everything (agc,frontend,eq,fec)*/
+	buf[0] = 0x0F;
+	nxt200x_writebytes(state, 0x08, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0x08, buf, 1);
+
+	/* write agc sdm configure */
+	buf[0] = 0xF1;
+	nxt200x_writebytes(state, 0x57, buf, 1);
+
+	/* write mod output format */
+	buf[0] = 0x20;
+	nxt200x_writebytes(state, 0x09, buf, 1);
+
+	/* write fec mpeg mode */
+	buf[0] = 0x7E;
+	buf[1] = 0x00;
+	nxt200x_writebytes(state, 0xE9, buf, 2);
+
+	/* write mux selection */
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0xCC, buf, 1);
+
+	return 0;
+}
+
+static int nxt2004_init(struct dvb_frontend* fe)
+{
+	struct nxt200x_state* state = fe->demodulator_priv;
+	const struct firmware *fw;
+	int ret;
+	u8 buf[3];
+
+	/* ??? */
+	buf[0]=0x00;
+	nxt200x_writebytes(state, 0x1E, buf, 1);
+
+	/* request the firmware, this will block until someone uploads it */
+	pr_debug("%s: Waiting for firmware upload (%s)...\n",
+		 __func__, NXT2004_DEFAULT_FIRMWARE);
+	ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE,
+			       state->i2c->dev.parent);
+	pr_debug("%s: Waiting for firmware upload(2)...\n", __func__);
+	if (ret) {
+		pr_err("%s: No firmware uploaded (timeout or file not found?)"
+		       "\n", __func__);
+		return ret;
+	}
+
+	ret = nxt2004_load_firmware(fe, fw);
+	release_firmware(fw);
+	if (ret) {
+		pr_err("%s: Writing firmware to device failed\n", __func__);
+		return ret;
+	}
+	pr_info("%s: Firmware upload complete\n", __func__);
+
+	/* ensure transfer is complete */
+	buf[0] = 0x01;
+	nxt200x_writebytes(state, 0x19, buf, 1);
+
+	nxt2004_microcontroller_init(state);
+	nxt200x_microcontroller_stop(state);
+	nxt200x_microcontroller_stop(state);
+	nxt2004_microcontroller_init(state);
+	nxt200x_microcontroller_stop(state);
+
+	/* soft reset everything (agc,frontend,eq,fec)*/
+	buf[0] = 0xFF;
+	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+	/* write agc sdm configure */
+	buf[0] = 0xD7;
+	nxt200x_writebytes(state, 0x57, buf, 1);
+
+	/* ???*/
+	buf[0] = 0x07;
+	buf[1] = 0xfe;
+	nxt200x_writebytes(state, 0x35, buf, 2);
+	buf[0] = 0x12;
+	nxt200x_writebytes(state, 0x34, buf, 1);
+	buf[0] = 0x80;
+	nxt200x_writebytes(state, 0x21, buf, 1);
+
+	/* ???*/
+	buf[0] = 0x21;
+	nxt200x_writebytes(state, 0x0A, buf, 1);
+
+	/* ???*/
+	buf[0] = 0x01;
+	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+	/* write fec mpeg mode */
+	buf[0] = 0x7E;
+	buf[1] = 0x00;
+	nxt200x_writebytes(state, 0xE9, buf, 2);
+
+	/* write mux selection */
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0xCC, buf, 1);
+
+	/* ???*/
+	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+	/* soft reset? */
+	nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+	buf[0] = 0x10;
+	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+	nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+	/* ???*/
+	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x01;
+	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x70;
+	nxt200x_writereg_multibyte(state, 0x81, buf, 1);
+	buf[0] = 0x31; buf[1] = 0x5E; buf[2] = 0x66;
+	nxt200x_writereg_multibyte(state, 0x82, buf, 3);
+
+	nxt200x_readreg_multibyte(state, 0x88, buf, 1);
+	buf[0] = 0x11;
+	nxt200x_writereg_multibyte(state, 0x88, buf, 1);
+	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x40;
+	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+	nxt200x_readbytes(state, 0x10, buf, 1);
+	buf[0] = 0x10;
+	nxt200x_writebytes(state, 0x10, buf, 1);
+	nxt200x_readbytes(state, 0x0A, buf, 1);
+	buf[0] = 0x21;
+	nxt200x_writebytes(state, 0x0A, buf, 1);
+
+	nxt2004_microcontroller_init(state);
+
+	buf[0] = 0x21;
+	nxt200x_writebytes(state, 0x0A, buf, 1);
+	buf[0] = 0x7E;
+	nxt200x_writebytes(state, 0xE9, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0xEA, buf, 1);
+
+	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+	/* soft reset? */
+	nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+	buf[0] = 0x10;
+	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+	nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x04;
+	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writereg_multibyte(state, 0x81, buf, 1);
+	buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00;
+	nxt200x_writereg_multibyte(state, 0x82, buf, 3);
+
+	nxt200x_readreg_multibyte(state, 0x88, buf, 1);
+	buf[0] = 0x11;
+	nxt200x_writereg_multibyte(state, 0x88, buf, 1);
+
+	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x44;
+	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+	/* initialize tuner */
+	nxt200x_readbytes(state, 0x10, buf, 1);
+	buf[0] = 0x12;
+	nxt200x_writebytes(state, 0x10, buf, 1);
+	buf[0] = 0x04;
+	nxt200x_writebytes(state, 0x13, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0x16, buf, 1);
+	buf[0] = 0x04;
+	nxt200x_writebytes(state, 0x14, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0x14, buf, 1);
+	nxt200x_writebytes(state, 0x17, buf, 1);
+	nxt200x_writebytes(state, 0x14, buf, 1);
+	nxt200x_writebytes(state, 0x17, buf, 1);
+
+	return 0;
+}
+
+static int nxt200x_init(struct dvb_frontend* fe)
+{
+	struct nxt200x_state* state = fe->demodulator_priv;
+	int ret = 0;
+
+	if (!state->initialised) {
+		switch (state->demod_chip) {
+			case NXT2002:
+				ret = nxt2002_init(fe);
+				break;
+			case NXT2004:
+				ret = nxt2004_init(fe);
+				break;
+			default:
+				return -EINVAL;
+				break;
+		}
+		state->initialised = 1;
+	}
+	return ret;
+}
+
+static int nxt200x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+	fesettings->min_delay_ms = 500;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+	return 0;
+}
+
+static void nxt200x_release(struct dvb_frontend* fe)
+{
+	struct nxt200x_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops nxt200x_ops;
+
+struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
+				   struct i2c_adapter* i2c)
+{
+	struct nxt200x_state* state = NULL;
+	u8 buf [] = {0,0,0,0,0};
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct nxt200x_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->initialised = 0;
+
+	/* read card id */
+	nxt200x_readbytes(state, 0x00, buf, 5);
+	dprintk("NXT info: %*ph\n", 5, buf);
+
+	/* set demod chip */
+	switch (buf[0]) {
+		case 0x04:
+			state->demod_chip = NXT2002;
+			pr_info("NXT2002 Detected\n");
+			break;
+		case 0x05:
+			state->demod_chip = NXT2004;
+			pr_info("NXT2004 Detected\n");
+			break;
+		default:
+			goto error;
+	}
+
+	/* make sure demod chip is supported */
+	switch (state->demod_chip) {
+		case NXT2002:
+			if (buf[0] != 0x04) goto error;		/* device id */
+			if (buf[1] != 0x02) goto error;		/* fab id */
+			if (buf[2] != 0x11) goto error;		/* month */
+			if (buf[3] != 0x20) goto error;		/* year msb */
+			if (buf[4] != 0x00) goto error;		/* year lsb */
+			break;
+		case NXT2004:
+			if (buf[0] != 0x05) goto error;		/* device id */
+			break;
+		default:
+			goto error;
+	}
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	pr_err("Unknown/Unsupported NXT chip: %*ph\n", 5, buf);
+	return NULL;
+}
+
+static struct dvb_frontend_ops nxt200x_ops = {
+	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
+	.info = {
+		.name = "Nextwave NXT200X VSB/QAM frontend",
+		.frequency_min =  54000000,
+		.frequency_max = 860000000,
+		.frequency_stepsize = 166666,	/* stepsize is just a guess */
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_8VSB | FE_CAN_QAM_64 | FE_CAN_QAM_256
+	},
+
+	.release = nxt200x_release,
+
+	.init = nxt200x_init,
+	.sleep = nxt200x_sleep,
+
+	.set_frontend = nxt200x_setup_frontend_parameters,
+	.get_tune_settings = nxt200x_get_tune_settings,
+
+	.read_status = nxt200x_read_status,
+	.read_ber = nxt200x_read_ber,
+	.read_signal_strength = nxt200x_read_signal_strength,
+	.read_snr = nxt200x_read_snr,
+	.read_ucblocks = nxt200x_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("NXT200X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
+MODULE_AUTHOR("Kirk Lapray, Michael Krufky, Jean-Francois Thibert, and Taylor Jacob");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(nxt200x_attach);
+
diff --git a/drivers/media/dvb-frontends/nxt200x.h b/drivers/media/dvb-frontends/nxt200x.h
new file mode 100644
index 0000000..f3c8458
--- /dev/null
+++ b/drivers/media/dvb-frontends/nxt200x.h
@@ -0,0 +1,63 @@
+/*
+ *    Support for NXT2002 and NXT2004 - VSB/QAM
+ *
+ *    Copyright (C) 2005 Kirk Lapray (kirk.lapray@gmail.com)
+ *    based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net>
+ *    and nxt2004 by Jean-Francois Thibert (jeanfrancois@sagetv.com)
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+#ifndef NXT200X_H
+#define NXT200X_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+typedef enum nxt_chip_t {
+		NXTUNDEFINED,
+		NXT2002,
+		NXT2004
+}nxt_chip_type;
+
+struct nxt200x_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* need to set device param for start_dma */
+	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+};
+
+#if defined(CONFIG_DVB_NXT200X) || (defined(CONFIG_DVB_NXT200X_MODULE) && defined(MODULE))
+extern struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
+					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_NXT200X
+
+#endif /* NXT200X_H */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb-frontends/nxt6000.c b/drivers/media/dvb-frontends/nxt6000.c
new file mode 100644
index 0000000..90ae6c7
--- /dev/null
+++ b/drivers/media/dvb-frontends/nxt6000.c
@@ -0,0 +1,616 @@
+/*
+	NxtWave Communications - NXT6000 demodulator driver
+
+    Copyright (C) 2002-2003 Florian Schirmer <jolt@tuxbox.org>
+    Copyright (C) 2003 Paul Andreassen <paul@andreassen.com.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "nxt6000_priv.h"
+#include "nxt6000.h"
+
+
+
+struct nxt6000_state {
+	struct i2c_adapter* i2c;
+	/* configuration settings */
+	const struct nxt6000_config* config;
+	struct dvb_frontend frontend;
+};
+
+static int debug;
+#define dprintk if (debug) printk
+
+static int nxt6000_writereg(struct nxt6000_state* state, u8 reg, u8 data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 2 };
+	int ret;
+
+	if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1)
+		dprintk("nxt6000: nxt6000_write error (reg: 0x%02X, data: 0x%02X, ret: %d)\n", reg, data, ret);
+
+	return (ret != 1) ? -EIO : 0;
+}
+
+static u8 nxt6000_readreg(struct nxt6000_state* state, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msgs[] = {
+		{.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1},
+		{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
+	};
+
+	ret = i2c_transfer(state->i2c, msgs, 2);
+
+	if (ret != 2)
+		dprintk("nxt6000: nxt6000_read error (reg: 0x%02X, ret: %d)\n", reg, ret);
+
+	return b1[0];
+}
+
+static void nxt6000_reset(struct nxt6000_state* state)
+{
+	u8 val;
+
+	val = nxt6000_readreg(state, OFDM_COR_CTL);
+
+	nxt6000_writereg(state, OFDM_COR_CTL, val & ~COREACT);
+	nxt6000_writereg(state, OFDM_COR_CTL, val | COREACT);
+}
+
+static int nxt6000_set_bandwidth(struct nxt6000_state *state, u32 bandwidth)
+{
+	u16 nominal_rate;
+	int result;
+
+	switch (bandwidth) {
+	case 6000000:
+		nominal_rate = 0x55B7;
+		break;
+
+	case 7000000:
+		nominal_rate = 0x6400;
+		break;
+
+	case 8000000:
+		nominal_rate = 0x7249;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if ((result = nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_1, nominal_rate & 0xFF)) < 0)
+		return result;
+
+	return nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, (nominal_rate >> 8) & 0xFF);
+}
+
+static int nxt6000_set_guard_interval(struct nxt6000_state* state, fe_guard_interval_t guard_interval)
+{
+	switch (guard_interval) {
+
+	case GUARD_INTERVAL_1_32:
+		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x00 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
+
+	case GUARD_INTERVAL_1_16:
+		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x01 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
+
+	case GUARD_INTERVAL_AUTO:
+	case GUARD_INTERVAL_1_8:
+		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x02 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
+
+	case GUARD_INTERVAL_1_4:
+		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x03 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int nxt6000_set_inversion(struct nxt6000_state* state, fe_spectral_inversion_t inversion)
+{
+	switch (inversion) {
+
+	case INVERSION_OFF:
+		return nxt6000_writereg(state, OFDM_ITB_CTL, 0x00);
+
+	case INVERSION_ON:
+		return nxt6000_writereg(state, OFDM_ITB_CTL, ITBINV);
+
+	default:
+		return -EINVAL;
+
+	}
+}
+
+static int nxt6000_set_transmission_mode(struct nxt6000_state* state, fe_transmit_mode_t transmission_mode)
+{
+	int result;
+
+	switch (transmission_mode) {
+
+	case TRANSMISSION_MODE_2K:
+		if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x00 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0)
+			return result;
+
+		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x00 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04));
+
+	case TRANSMISSION_MODE_8K:
+	case TRANSMISSION_MODE_AUTO:
+		if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x02 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0)
+			return result;
+
+		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x01 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04));
+
+	default:
+		return -EINVAL;
+
+	}
+}
+
+static void nxt6000_setup(struct dvb_frontend* fe)
+{
+	struct nxt6000_state* state = fe->demodulator_priv;
+
+	nxt6000_writereg(state, RS_COR_SYNC_PARAM, SYNC_PARAM);
+	nxt6000_writereg(state, BER_CTRL, /*(1 << 2) | */ (0x01 << 1) | 0x01);
+	nxt6000_writereg(state, VIT_BERTIME_2, 0x00);  // BER Timer = 0x000200 * 256 = 131072 bits
+	nxt6000_writereg(state, VIT_BERTIME_1, 0x02);  //
+	nxt6000_writereg(state, VIT_BERTIME_0, 0x00);  //
+	nxt6000_writereg(state, VIT_COR_INTEN, 0x98); // Enable BER interrupts
+	nxt6000_writereg(state, VIT_COR_CTL, 0x82);   // Enable BER measurement
+	nxt6000_writereg(state, VIT_COR_CTL, VIT_COR_RESYNC | 0x02 );
+	nxt6000_writereg(state, OFDM_COR_CTL, (0x01 << 5) | (nxt6000_readreg(state, OFDM_COR_CTL) & 0x0F));
+	nxt6000_writereg(state, OFDM_COR_MODEGUARD, FORCEMODE8K | 0x02);
+	nxt6000_writereg(state, OFDM_AGC_CTL, AGCLAST | INITIAL_AGC_BW);
+	nxt6000_writereg(state, OFDM_ITB_FREQ_1, 0x06);
+	nxt6000_writereg(state, OFDM_ITB_FREQ_2, 0x31);
+	nxt6000_writereg(state, OFDM_CAS_CTL, (0x01 << 7) | (0x02 << 3) | 0x04);
+	nxt6000_writereg(state, CAS_FREQ, 0xBB);	/* CHECKME */
+	nxt6000_writereg(state, OFDM_SYR_CTL, 1 << 2);
+	nxt6000_writereg(state, OFDM_PPM_CTL_1, PPM256);
+	nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_1, 0x49);
+	nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, 0x72);
+	nxt6000_writereg(state, ANALOG_CONTROL_0, 1 << 5);
+	nxt6000_writereg(state, EN_DMD_RACQ, (1 << 7) | (3 << 4) | 2);
+	nxt6000_writereg(state, DIAG_CONFIG, TB_SET);
+
+	if (state->config->clock_inversion)
+		nxt6000_writereg(state, SUB_DIAG_MODE_SEL, CLKINVERSION);
+	else
+		nxt6000_writereg(state, SUB_DIAG_MODE_SEL, 0);
+
+	nxt6000_writereg(state, TS_FORMAT, 0);
+}
+
+static void nxt6000_dump_status(struct nxt6000_state *state)
+{
+	u8 val;
+
+/*
+	printk("RS_COR_STAT: 0x%02X\n", nxt6000_readreg(fe, RS_COR_STAT));
+	printk("VIT_SYNC_STATUS: 0x%02X\n", nxt6000_readreg(fe, VIT_SYNC_STATUS));
+	printk("OFDM_COR_STAT: 0x%02X\n", nxt6000_readreg(fe, OFDM_COR_STAT));
+	printk("OFDM_SYR_STAT: 0x%02X\n", nxt6000_readreg(fe, OFDM_SYR_STAT));
+	printk("OFDM_TPS_RCVD_1: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_1));
+	printk("OFDM_TPS_RCVD_2: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_2));
+	printk("OFDM_TPS_RCVD_3: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_3));
+	printk("OFDM_TPS_RCVD_4: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_4));
+	printk("OFDM_TPS_RESERVED_1: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RESERVED_1));
+	printk("OFDM_TPS_RESERVED_2: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RESERVED_2));
+*/
+	printk("NXT6000 status:");
+
+	val = nxt6000_readreg(state, RS_COR_STAT);
+
+	printk(" DATA DESCR LOCK: %d,", val & 0x01);
+	printk(" DATA SYNC LOCK: %d,", (val >> 1) & 0x01);
+
+	val = nxt6000_readreg(state, VIT_SYNC_STATUS);
+
+	printk(" VITERBI LOCK: %d,", (val >> 7) & 0x01);
+
+	switch ((val >> 4) & 0x07) {
+
+	case 0x00:
+		printk(" VITERBI CODERATE: 1/2,");
+		break;
+
+	case 0x01:
+		printk(" VITERBI CODERATE: 2/3,");
+		break;
+
+	case 0x02:
+		printk(" VITERBI CODERATE: 3/4,");
+		break;
+
+	case 0x03:
+		printk(" VITERBI CODERATE: 5/6,");
+		break;
+
+	case 0x04:
+		printk(" VITERBI CODERATE: 7/8,");
+		break;
+
+	default:
+		printk(" VITERBI CODERATE: Reserved,");
+
+	}
+
+	val = nxt6000_readreg(state, OFDM_COR_STAT);
+
+	printk(" CHCTrack: %d,", (val >> 7) & 0x01);
+	printk(" TPSLock: %d,", (val >> 6) & 0x01);
+	printk(" SYRLock: %d,", (val >> 5) & 0x01);
+	printk(" AGCLock: %d,", (val >> 4) & 0x01);
+
+	switch (val & 0x0F) {
+
+	case 0x00:
+		printk(" CoreState: IDLE,");
+		break;
+
+	case 0x02:
+		printk(" CoreState: WAIT_AGC,");
+		break;
+
+	case 0x03:
+		printk(" CoreState: WAIT_SYR,");
+		break;
+
+	case 0x04:
+		printk(" CoreState: WAIT_PPM,");
+		break;
+
+	case 0x01:
+		printk(" CoreState: WAIT_TRL,");
+		break;
+
+	case 0x05:
+		printk(" CoreState: WAIT_TPS,");
+		break;
+
+	case 0x06:
+		printk(" CoreState: MONITOR_TPS,");
+		break;
+
+	default:
+		printk(" CoreState: Reserved,");
+
+	}
+
+	val = nxt6000_readreg(state, OFDM_SYR_STAT);
+
+	printk(" SYRLock: %d,", (val >> 4) & 0x01);
+	printk(" SYRMode: %s,", (val >> 2) & 0x01 ? "8K" : "2K");
+
+	switch ((val >> 4) & 0x03) {
+
+	case 0x00:
+		printk(" SYRGuard: 1/32,");
+		break;
+
+	case 0x01:
+		printk(" SYRGuard: 1/16,");
+		break;
+
+	case 0x02:
+		printk(" SYRGuard: 1/8,");
+		break;
+
+	case 0x03:
+		printk(" SYRGuard: 1/4,");
+		break;
+	}
+
+	val = nxt6000_readreg(state, OFDM_TPS_RCVD_3);
+
+	switch ((val >> 4) & 0x07) {
+
+	case 0x00:
+		printk(" TPSLP: 1/2,");
+		break;
+
+	case 0x01:
+		printk(" TPSLP: 2/3,");
+		break;
+
+	case 0x02:
+		printk(" TPSLP: 3/4,");
+		break;
+
+	case 0x03:
+		printk(" TPSLP: 5/6,");
+		break;
+
+	case 0x04:
+		printk(" TPSLP: 7/8,");
+		break;
+
+	default:
+		printk(" TPSLP: Reserved,");
+
+	}
+
+	switch (val & 0x07) {
+
+	case 0x00:
+		printk(" TPSHP: 1/2,");
+		break;
+
+	case 0x01:
+		printk(" TPSHP: 2/3,");
+		break;
+
+	case 0x02:
+		printk(" TPSHP: 3/4,");
+		break;
+
+	case 0x03:
+		printk(" TPSHP: 5/6,");
+		break;
+
+	case 0x04:
+		printk(" TPSHP: 7/8,");
+		break;
+
+	default:
+		printk(" TPSHP: Reserved,");
+
+	}
+
+	val = nxt6000_readreg(state, OFDM_TPS_RCVD_4);
+
+	printk(" TPSMode: %s,", val & 0x01 ? "8K" : "2K");
+
+	switch ((val >> 4) & 0x03) {
+
+	case 0x00:
+		printk(" TPSGuard: 1/32,");
+		break;
+
+	case 0x01:
+		printk(" TPSGuard: 1/16,");
+		break;
+
+	case 0x02:
+		printk(" TPSGuard: 1/8,");
+		break;
+
+	case 0x03:
+		printk(" TPSGuard: 1/4,");
+		break;
+
+	}
+
+	/* Strange magic required to gain access to RF_AGC_STATUS */
+	nxt6000_readreg(state, RF_AGC_VAL_1);
+	val = nxt6000_readreg(state, RF_AGC_STATUS);
+	val = nxt6000_readreg(state, RF_AGC_STATUS);
+
+	printk(" RF AGC LOCK: %d,", (val >> 4) & 0x01);
+	printk("\n");
+}
+
+static int nxt6000_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	u8 core_status;
+	struct nxt6000_state* state = fe->demodulator_priv;
+
+	*status = 0;
+
+	core_status = nxt6000_readreg(state, OFDM_COR_STAT);
+
+	if (core_status & AGCLOCKED)
+		*status |= FE_HAS_SIGNAL;
+
+	if (nxt6000_readreg(state, OFDM_SYR_STAT) & GI14_SYR_LOCK)
+		*status |= FE_HAS_CARRIER;
+
+	if (nxt6000_readreg(state, VIT_SYNC_STATUS) & VITINSYNC)
+		*status |= FE_HAS_VITERBI;
+
+	if (nxt6000_readreg(state, RS_COR_STAT) & RSCORESTATUS)
+		*status |= FE_HAS_SYNC;
+
+	if ((core_status & TPSLOCKED) && (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)))
+		*status |= FE_HAS_LOCK;
+
+	if (debug)
+		nxt6000_dump_status(state);
+
+	return 0;
+}
+
+static int nxt6000_init(struct dvb_frontend* fe)
+{
+	struct nxt6000_state* state = fe->demodulator_priv;
+
+	nxt6000_reset(state);
+	nxt6000_setup(fe);
+
+	return 0;
+}
+
+static int nxt6000_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct nxt6000_state* state = fe->demodulator_priv;
+	int result;
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	result = nxt6000_set_bandwidth(state, p->bandwidth_hz);
+	if (result < 0)
+		return result;
+
+	result = nxt6000_set_guard_interval(state, p->guard_interval);
+	if (result < 0)
+		return result;
+
+	result = nxt6000_set_transmission_mode(state, p->transmission_mode);
+	if (result < 0)
+		return result;
+
+	result = nxt6000_set_inversion(state, p->inversion);
+	if (result < 0)
+		return result;
+
+	msleep(500);
+	return 0;
+}
+
+static void nxt6000_release(struct dvb_frontend* fe)
+{
+	struct nxt6000_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static int nxt6000_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct nxt6000_state* state = fe->demodulator_priv;
+
+	*snr = nxt6000_readreg( state, OFDM_CHC_SNR) / 8;
+
+	return 0;
+}
+
+static int nxt6000_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct nxt6000_state* state = fe->demodulator_priv;
+
+	nxt6000_writereg( state, VIT_COR_INTSTAT, 0x18 );
+
+	*ber = (nxt6000_readreg( state, VIT_BER_1 ) << 8 ) |
+		nxt6000_readreg( state, VIT_BER_0 );
+
+	nxt6000_writereg( state, VIT_COR_INTSTAT, 0x18); // Clear BER Done interrupts
+
+	return 0;
+}
+
+static int nxt6000_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+{
+	struct nxt6000_state* state = fe->demodulator_priv;
+
+	*signal_strength = (short) (511 -
+		(nxt6000_readreg(state, AGC_GAIN_1) +
+		((nxt6000_readreg(state, AGC_GAIN_2) & 0x03) << 8)));
+
+	return 0;
+}
+
+static int nxt6000_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 500;
+	return 0;
+}
+
+static int nxt6000_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct nxt6000_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01);
+	} else {
+		return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00);
+	}
+}
+
+static struct dvb_frontend_ops nxt6000_ops;
+
+struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
+				    struct i2c_adapter* i2c)
+{
+	struct nxt6000_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct nxt6000_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+
+	/* check if the demod is there */
+	if (nxt6000_readreg(state, OFDM_MSC_REV) != NXT6000ASICDEVICE) goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops nxt6000_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "NxtWave NXT6000 DVB-T",
+		.frequency_min = 0,
+		.frequency_max = 863250000,
+		.frequency_stepsize = 62500,
+		/*.frequency_tolerance = *//* FIXME: 12% of SR */
+		.symbol_rate_min = 0,	/* FIXME */
+		.symbol_rate_max = 9360000,	/* FIXME */
+		.symbol_rate_tolerance = 4000,
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+			FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
+			FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.release = nxt6000_release,
+
+	.init = nxt6000_init,
+	.i2c_gate_ctrl = nxt6000_i2c_gate_ctrl,
+
+	.get_tune_settings = nxt6000_fe_get_tune_settings,
+
+	.set_frontend = nxt6000_set_frontend,
+
+	.read_status = nxt6000_read_status,
+	.read_ber = nxt6000_read_ber,
+	.read_signal_strength = nxt6000_read_signal_strength,
+	.read_snr = nxt6000_read_snr,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("NxtWave NXT6000 DVB-T demodulator driver");
+MODULE_AUTHOR("Florian Schirmer");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(nxt6000_attach);
diff --git a/drivers/media/dvb-frontends/nxt6000.h b/drivers/media/dvb-frontends/nxt6000.h
new file mode 100644
index 0000000..878eb38
--- /dev/null
+++ b/drivers/media/dvb-frontends/nxt6000.h
@@ -0,0 +1,48 @@
+/*
+	NxtWave Communications - NXT6000 demodulator driver
+
+    Copyright (C) 2002-2003 Florian Schirmer <jolt@tuxbox.org>
+    Copyright (C) 2003 Paul Andreassen <paul@andreassen.com.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef NXT6000_H
+#define NXT6000_H
+
+#include <linux/dvb/frontend.h>
+
+struct nxt6000_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* should clock inversion be used? */
+	u8 clock_inversion:1;
+};
+
+#if defined(CONFIG_DVB_NXT6000) || (defined(CONFIG_DVB_NXT6000_MODULE) && defined(MODULE))
+extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
+					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_NXT6000
+
+#endif // NXT6000_H
diff --git a/drivers/media/dvb-frontends/nxt6000_priv.h b/drivers/media/dvb-frontends/nxt6000_priv.h
new file mode 100644
index 0000000..0422e58
--- /dev/null
+++ b/drivers/media/dvb-frontends/nxt6000_priv.h
@@ -0,0 +1,286 @@
+/*
+ * Public Include File for DRV6000 users
+ * (ie. NxtWave Communications - NXT6000 demodulator driver)
+ *
+ * Copyright (C) 2001 NxtWave Communications, Inc.
+ *
+ */
+
+/*  Nxt6000 Register Addresses and Bit Masks */
+
+/* Maximum Register Number */
+#define MAXNXT6000REG          (0x9A)
+
+/* 0x1B A_VIT_BER_0  aka 0x3A */
+#define A_VIT_BER_0            (0x1B)
+
+/* 0x1D A_VIT_BER_TIMER_0 aka 0x38 */
+#define A_VIT_BER_TIMER_0      (0x1D)
+
+/* 0x21 RS_COR_STAT */
+#define RS_COR_STAT            (0x21)
+#define RSCORESTATUS           (0x03)
+
+/* 0x22 RS_COR_INTEN */
+#define RS_COR_INTEN           (0x22)
+
+/* 0x23 RS_COR_INSTAT */
+#define RS_COR_INSTAT          (0x23)
+#define INSTAT_ERROR           (0x04)
+#define LOCK_LOSS_BITS         (0x03)
+
+/* 0x24 RS_COR_SYNC_PARAM */
+#define RS_COR_SYNC_PARAM      (0x24)
+#define SYNC_PARAM             (0x03)
+
+/* 0x25 BER_CTRL */
+#define BER_CTRL               (0x25)
+#define BER_ENABLE             (0x02)
+#define BER_RESET              (0x01)
+
+/* 0x26 BER_PAY */
+#define BER_PAY                (0x26)
+
+/* 0x27 BER_PKT_L */
+#define BER_PKT_L              (0x27)
+#define BER_PKTOVERFLOW        (0x80)
+
+/* 0x30 VIT_COR_CTL */
+#define VIT_COR_CTL            (0x30)
+#define BER_CONTROL            (0x02)
+#define VIT_COR_MASK           (0x82)
+#define VIT_COR_RESYNC         (0x80)
+
+
+/* 0x32 VIT_SYNC_STATUS */
+#define VIT_SYNC_STATUS        (0x32)
+#define VITINSYNC              (0x80)
+
+/* 0x33 VIT_COR_INTEN */
+#define VIT_COR_INTEN          (0x33)
+#define GLOBAL_ENABLE          (0x80)
+
+/* 0x34 VIT_COR_INTSTAT */
+#define VIT_COR_INTSTAT        (0x34)
+#define BER_DONE               (0x08)
+#define BER_OVERFLOW           (0x10)
+
+/* 0x38 VIT_BERTIME_2 */
+#define VIT_BERTIME_2      (0x38)
+
+/* 0x39 VIT_BERTIME_1 */
+#define VIT_BERTIME_1      (0x39)
+
+/* 0x3A VIT_BERTIME_0 */
+#define VIT_BERTIME_0      (0x3a)
+
+			     /* 0x38 OFDM_BERTimer *//* Use the alias registers */
+#define A_VIT_BER_TIMER_0      (0x1D)
+
+			     /* 0x3A VIT_BER_TIMER_0 *//* Use the alias registers */
+#define A_VIT_BER_0            (0x1B)
+
+/* 0x3B VIT_BER_1 */
+#define VIT_BER_1              (0x3b)
+
+/* 0x3C VIT_BER_0 */
+#define VIT_BER_0              (0x3c)
+
+/* 0x40 OFDM_COR_CTL */
+#define OFDM_COR_CTL           (0x40)
+#define COREACT                (0x20)
+#define HOLDSM                 (0x10)
+#define WAIT_AGC               (0x02)
+#define WAIT_SYR               (0x03)
+
+/* 0x41 OFDM_COR_STAT */
+#define OFDM_COR_STAT          (0x41)
+#define COR_STATUS             (0x0F)
+#define MONITOR_TPS            (0x06)
+#define TPSLOCKED              (0x40)
+#define AGCLOCKED              (0x10)
+
+/* 0x42 OFDM_COR_INTEN */
+#define OFDM_COR_INTEN         (0x42)
+#define TPSRCVBAD              (0x04)
+#define TPSRCVCHANGED         (0x02)
+#define TPSRCVUPDATE           (0x01)
+
+/* 0x43 OFDM_COR_INSTAT */
+#define OFDM_COR_INSTAT        (0x43)
+
+/* 0x44 OFDM_COR_MODEGUARD */
+#define OFDM_COR_MODEGUARD     (0x44)
+#define FORCEMODE              (0x08)
+#define FORCEMODE8K			   (0x04)
+
+/* 0x45 OFDM_AGC_CTL */
+#define OFDM_AGC_CTL           (0x45)
+#define INITIAL_AGC_BW		   (0x08)
+#define AGCNEG                 (0x02)
+#define AGCLAST				   (0x10)
+
+/* 0x48 OFDM_AGC_TARGET */
+#define OFDM_AGC_TARGET		   (0x48)
+#define OFDM_AGC_TARGET_DEFAULT (0x28)
+#define OFDM_AGC_TARGET_IMPULSE (0x38)
+
+/* 0x49 OFDM_AGC_GAIN_1 */
+#define OFDM_AGC_GAIN_1        (0x49)
+
+/* 0x4B OFDM_ITB_CTL */
+#define OFDM_ITB_CTL           (0x4B)
+#define ITBINV                 (0x01)
+
+/* 0x49 AGC_GAIN_1 */
+#define AGC_GAIN_1             (0x49)
+
+/* 0x4A AGC_GAIN_2 */
+#define AGC_GAIN_2             (0x4A)
+
+/* 0x4C OFDM_ITB_FREQ_1 */
+#define OFDM_ITB_FREQ_1        (0x4C)
+
+/* 0x4D OFDM_ITB_FREQ_2 */
+#define OFDM_ITB_FREQ_2        (0x4D)
+
+/* 0x4E  OFDM_CAS_CTL */
+#define OFDM_CAS_CTL           (0x4E)
+#define ACSDIS                 (0x40)
+#define CCSEN                  (0x80)
+
+/* 0x4F CAS_FREQ */
+#define CAS_FREQ               (0x4F)
+
+/* 0x51 OFDM_SYR_CTL */
+#define OFDM_SYR_CTL           (0x51)
+#define SIXTH_ENABLE           (0x80)
+#define SYR_TRACKING_DISABLE   (0x01)
+
+/* 0x52 OFDM_SYR_STAT */
+#define OFDM_SYR_STAT		   (0x52)
+#define GI14_2K_SYR_LOCK	   (0x13)
+#define GI14_8K_SYR_LOCK	   (0x17)
+#define GI14_SYR_LOCK		   (0x10)
+
+/* 0x55 OFDM_SYR_OFFSET_1 */
+#define OFDM_SYR_OFFSET_1      (0x55)
+
+/* 0x56 OFDM_SYR_OFFSET_2 */
+#define OFDM_SYR_OFFSET_2      (0x56)
+
+/* 0x58 OFDM_SCR_CTL */
+#define OFDM_SCR_CTL           (0x58)
+#define SYR_ADJ_DECAY_MASK     (0x70)
+#define SYR_ADJ_DECAY          (0x30)
+
+/* 0x59 OFDM_PPM_CTL_1 */
+#define OFDM_PPM_CTL_1         (0x59)
+#define PPMMAX_MASK            (0x30)
+#define PPM256				   (0x30)
+
+/* 0x5B OFDM_TRL_NOMINALRATE_1 */
+#define OFDM_TRL_NOMINALRATE_1 (0x5B)
+
+/* 0x5C OFDM_TRL_NOMINALRATE_2 */
+#define OFDM_TRL_NOMINALRATE_2 (0x5C)
+
+/* 0x5D OFDM_TRL_TIME_1 */
+#define OFDM_TRL_TIME_1        (0x5D)
+
+/* 0x60 OFDM_CRL_FREQ_1 */
+#define OFDM_CRL_FREQ_1        (0x60)
+
+/* 0x63 OFDM_CHC_CTL_1 */
+#define OFDM_CHC_CTL_1         (0x63)
+#define MANMEAN1               (0xF0);
+#define CHCFIR                 (0x01)
+
+/* 0x64 OFDM_CHC_SNR */
+#define OFDM_CHC_SNR           (0x64)
+
+/* 0x65 OFDM_BDI_CTL */
+#define OFDM_BDI_CTL           (0x65)
+#define LP_SELECT              (0x02)
+
+/* 0x67 OFDM_TPS_RCVD_1 */
+#define OFDM_TPS_RCVD_1        (0x67)
+#define TPSFRAME               (0x03)
+
+/* 0x68 OFDM_TPS_RCVD_2 */
+#define OFDM_TPS_RCVD_2        (0x68)
+
+/* 0x69 OFDM_TPS_RCVD_3 */
+#define OFDM_TPS_RCVD_3        (0x69)
+
+/* 0x6A OFDM_TPS_RCVD_4 */
+#define OFDM_TPS_RCVD_4        (0x6A)
+
+/* 0x6B OFDM_TPS_RESERVED_1 */
+#define OFDM_TPS_RESERVED_1    (0x6B)
+
+/* 0x6C OFDM_TPS_RESERVED_2 */
+#define OFDM_TPS_RESERVED_2    (0x6C)
+
+/* 0x73 OFDM_MSC_REV */
+#define OFDM_MSC_REV           (0x73)
+
+/* 0x76 OFDM_SNR_CARRIER_2 */
+#define OFDM_SNR_CARRIER_2     (0x76)
+#define MEAN_MASK              (0x80)
+#define MEANBIT                (0x80)
+
+/* 0x80 ANALOG_CONTROL_0 */
+#define ANALOG_CONTROL_0       (0x80)
+#define POWER_DOWN_ADC         (0x40)
+
+/* 0x81 ENABLE_TUNER_IIC */
+#define ENABLE_TUNER_IIC       (0x81)
+#define ENABLE_TUNER_BIT       (0x01)
+
+/* 0x82 EN_DMD_RACQ */
+#define EN_DMD_RACQ            (0x82)
+#define EN_DMD_RACQ_REG_VAL    (0x81)
+#define EN_DMD_RACQ_REG_VAL_14 (0x01)
+
+/* 0x84 SNR_COMMAND */
+#define SNR_COMMAND            (0x84)
+#define SNRStat                (0x80)
+
+/* 0x85 SNRCARRIERNUMBER_LSB */
+#define SNRCARRIERNUMBER_LSB   (0x85)
+
+/* 0x87 SNRMINTHRESHOLD_LSB */
+#define SNRMINTHRESHOLD_LSB    (0x87)
+
+/* 0x89 SNR_PER_CARRIER_LSB */
+#define SNR_PER_CARRIER_LSB    (0x89)
+
+/* 0x8B SNRBELOWTHRESHOLD_LSB */
+#define SNRBELOWTHRESHOLD_LSB  (0x8B)
+
+/* 0x91 RF_AGC_VAL_1 */
+#define RF_AGC_VAL_1           (0x91)
+
+/* 0x92 RF_AGC_STATUS */
+#define RF_AGC_STATUS          (0x92)
+
+/* 0x98 DIAG_CONFIG */
+#define DIAG_CONFIG            (0x98)
+#define DIAG_MASK              (0x70)
+#define TB_SET                 (0x10)
+#define TRAN_SELECT            (0x07)
+#define SERIAL_SELECT          (0x01)
+
+/* 0x99 SUB_DIAG_MODE_SEL */
+#define SUB_DIAG_MODE_SEL      (0x99)
+#define CLKINVERSION           (0x01)
+
+/* 0x9A TS_FORMAT */
+#define TS_FORMAT              (0x9A)
+#define ERROR_SENSE            (0x08)
+#define VALID_SENSE            (0x04)
+#define SYNC_SENSE             (0x02)
+#define GATED_CLOCK            (0x01)
+
+#define NXT6000ASICDEVICE      (0x0b)
diff --git a/drivers/media/dvb-frontends/or51132.c b/drivers/media/dvb-frontends/or51132.c
new file mode 100644
index 0000000..5ef9218
--- /dev/null
+++ b/drivers/media/dvb-frontends/or51132.c
@@ -0,0 +1,631 @@
+/*
+ *    Support for OR51132 (pcHDTV HD-3000) - VSB/QAM
+ *
+ *
+ *    Copyright (C) 2007 Trent Piepho <xyzzy@speakeasy.org>
+ *
+ *    Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com>
+ *
+ *    Based on code from Jack Kelliher (kelliher@xmission.com)
+ *                           Copyright (C) 2002 & pcHDTV, inc.
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+/*
+ * This driver needs two external firmware files. Please copy
+ * "dvb-fe-or51132-vsb.fw" and "dvb-fe-or51132-qam.fw" to
+ * /usr/lib/hotplug/firmware/ or /lib/firmware/
+ * (depending on configuration of firmware hotplug).
+ */
+#define OR51132_VSB_FIRMWARE "dvb-fe-or51132-vsb.fw"
+#define OR51132_QAM_FIRMWARE "dvb-fe-or51132-qam.fw"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <asm/byteorder.h>
+
+#include "dvb_math.h"
+#include "dvb_frontend.h"
+#include "or51132.h"
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "or51132: " args); \
+	} while (0)
+
+
+struct or51132_state
+{
+	struct i2c_adapter* i2c;
+
+	/* Configuration settings */
+	const struct or51132_config* config;
+
+	struct dvb_frontend frontend;
+
+	/* Demodulator private data */
+	fe_modulation_t current_modulation;
+	u32 snr; /* Result of last SNR calculation */
+
+	/* Tuner private data */
+	u32 current_frequency;
+};
+
+
+/* Write buffer to demod */
+static int or51132_writebuf(struct or51132_state *state, const u8 *buf, int len)
+{
+	int err;
+	struct i2c_msg msg = { .addr = state->config->demod_address,
+			       .flags = 0, .buf = (u8*)buf, .len = len };
+
+	/* msleep(20); */ /* doesn't appear to be necessary */
+	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+		printk(KERN_WARNING "or51132: I2C write (addr 0x%02x len %d) error: %d\n",
+		       msg.addr, msg.len, err);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+/* Write constant bytes, e.g. or51132_writebytes(state, 0x04, 0x42, 0x00);
+   Less code and more efficient that loading a buffer on the stack with
+   the bytes to send and then calling or51132_writebuf() on that. */
+#define or51132_writebytes(state, data...)  \
+	({ static const u8 _data[] = {data}; \
+	or51132_writebuf(state, _data, sizeof(_data)); })
+
+/* Read data from demod into buffer.  Returns 0 on success. */
+static int or51132_readbuf(struct or51132_state *state, u8 *buf, int len)
+{
+	int err;
+	struct i2c_msg msg = { .addr = state->config->demod_address,
+			       .flags = I2C_M_RD, .buf = buf, .len = len };
+
+	/* msleep(20); */ /* doesn't appear to be necessary */
+	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+		printk(KERN_WARNING "or51132: I2C read (addr 0x%02x len %d) error: %d\n",
+		       msg.addr, msg.len, err);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+/* Reads a 16-bit demod register.  Returns <0 on error. */
+static int or51132_readreg(struct or51132_state *state, u8 reg)
+{
+	u8 buf[2] = { 0x04, reg };
+	struct i2c_msg msg[2] = {
+		{.addr = state->config->demod_address, .flags = 0,
+		 .buf = buf, .len = 2 },
+		{.addr = state->config->demod_address, .flags = I2C_M_RD,
+		 .buf = buf, .len = 2 }};
+	int err;
+
+	if ((err = i2c_transfer(state->i2c, msg, 2)) != 2) {
+		printk(KERN_WARNING "or51132: I2C error reading register %d: %d\n",
+		       reg, err);
+		return -EREMOTEIO;
+	}
+	return buf[0] | (buf[1] << 8);
+}
+
+static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
+{
+	struct or51132_state* state = fe->demodulator_priv;
+	static const u8 run_buf[] = {0x7F,0x01};
+	u8 rec_buf[8];
+	u32 firmwareAsize, firmwareBsize;
+	int i,ret;
+
+	dprintk("Firmware is %Zd bytes\n",fw->size);
+
+	/* Get size of firmware A and B */
+	firmwareAsize = le32_to_cpu(*((__le32*)fw->data));
+	dprintk("FirmwareA is %i bytes\n",firmwareAsize);
+	firmwareBsize = le32_to_cpu(*((__le32*)(fw->data+4)));
+	dprintk("FirmwareB is %i bytes\n",firmwareBsize);
+
+	/* Upload firmware */
+	if ((ret = or51132_writebuf(state, &fw->data[8], firmwareAsize))) {
+		printk(KERN_WARNING "or51132: load_firmware error 1\n");
+		return ret;
+	}
+	if ((ret = or51132_writebuf(state, &fw->data[8+firmwareAsize],
+				    firmwareBsize))) {
+		printk(KERN_WARNING "or51132: load_firmware error 2\n");
+		return ret;
+	}
+
+	if ((ret = or51132_writebuf(state, run_buf, 2))) {
+		printk(KERN_WARNING "or51132: load_firmware error 3\n");
+		return ret;
+	}
+	if ((ret = or51132_writebuf(state, run_buf, 2))) {
+		printk(KERN_WARNING "or51132: load_firmware error 4\n");
+		return ret;
+	}
+
+	/* 50ms for operation to begin */
+	msleep(50);
+
+	/* Read back ucode version to besure we loaded correctly and are really up and running */
+	/* Get uCode version */
+	if ((ret = or51132_writebytes(state, 0x10, 0x10, 0x00))) {
+		printk(KERN_WARNING "or51132: load_firmware error a\n");
+		return ret;
+	}
+	if ((ret = or51132_writebytes(state, 0x04, 0x17))) {
+		printk(KERN_WARNING "or51132: load_firmware error b\n");
+		return ret;
+	}
+	if ((ret = or51132_writebytes(state, 0x00, 0x00))) {
+		printk(KERN_WARNING "or51132: load_firmware error c\n");
+		return ret;
+	}
+	for (i=0;i<4;i++) {
+		/* Once upon a time, this command might have had something
+		   to do with getting the firmware version, but it's
+		   not used anymore:
+		   {0x04,0x00,0x30,0x00,i+1} */
+		/* Read 8 bytes, two bytes at a time */
+		if ((ret = or51132_readbuf(state, &rec_buf[i*2], 2))) {
+			printk(KERN_WARNING
+			       "or51132: load_firmware error d - %d\n",i);
+			return ret;
+		}
+	}
+
+	printk(KERN_WARNING
+	       "or51132: Version: %02X%02X%02X%02X-%02X%02X%02X%02X (%02X%01X-%01X-%02X%01X-%01X)\n",
+	       rec_buf[1],rec_buf[0],rec_buf[3],rec_buf[2],
+	       rec_buf[5],rec_buf[4],rec_buf[7],rec_buf[6],
+	       rec_buf[3],rec_buf[2]>>4,rec_buf[2]&0x0f,
+	       rec_buf[5],rec_buf[4]>>4,rec_buf[4]&0x0f);
+
+	if ((ret = or51132_writebytes(state, 0x10, 0x00, 0x00))) {
+		printk(KERN_WARNING "or51132: load_firmware error e\n");
+		return ret;
+	}
+	return 0;
+};
+
+static int or51132_init(struct dvb_frontend* fe)
+{
+	return 0;
+}
+
+static int or51132_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	*ber = 0;
+	return 0;
+}
+
+static int or51132_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	*ucblocks = 0;
+	return 0;
+}
+
+static int or51132_sleep(struct dvb_frontend* fe)
+{
+	return 0;
+}
+
+static int or51132_setmode(struct dvb_frontend* fe)
+{
+	struct or51132_state* state = fe->demodulator_priv;
+	u8 cmd_buf1[3] = {0x04, 0x01, 0x5f};
+	u8 cmd_buf2[3] = {0x1c, 0x00, 0 };
+
+	dprintk("setmode %d\n",(int)state->current_modulation);
+
+	switch (state->current_modulation) {
+	case VSB_8:
+		/* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high */
+		cmd_buf1[2] = 0x50;
+		/* REC MODE inv IF spectrum, Normal */
+		cmd_buf2[1] = 0x03;
+		/* Channel MODE ATSC/VSB8 */
+		cmd_buf2[2] = 0x06;
+		break;
+	/* All QAM modes are:
+	   Auto-deinterleave; MPEGser, MPEG2tr, phase noise-high
+	   REC MODE Normal Carrier Lock */
+	case QAM_AUTO:
+		/* Channel MODE Auto QAM64/256 */
+		cmd_buf2[2] = 0x4f;
+		break;
+	case QAM_256:
+		/* Channel MODE QAM256 */
+		cmd_buf2[2] = 0x45;
+		break;
+	case QAM_64:
+		/* Channel MODE QAM64 */
+		cmd_buf2[2] = 0x43;
+		break;
+	default:
+		printk(KERN_WARNING
+		       "or51132: setmode: Modulation set to unsupported value (%d)\n",
+		       state->current_modulation);
+		return -EINVAL;
+	}
+
+	/* Set Receiver 1 register */
+	if (or51132_writebuf(state, cmd_buf1, 3)) {
+		printk(KERN_WARNING "or51132: set_mode error 1\n");
+		return -EREMOTEIO;
+	}
+	dprintk("set #1 to %02x\n", cmd_buf1[2]);
+
+	/* Set operation mode in Receiver 6 register */
+	if (or51132_writebuf(state, cmd_buf2, 3)) {
+		printk(KERN_WARNING "or51132: set_mode error 2\n");
+		return -EREMOTEIO;
+	}
+	dprintk("set #6 to 0x%02x%02x\n", cmd_buf2[1], cmd_buf2[2]);
+
+	return 0;
+}
+
+/* Some modulations use the same firmware.  This classifies modulations
+   by the firmware they use. */
+#define MOD_FWCLASS_UNKNOWN	0
+#define MOD_FWCLASS_VSB		1
+#define MOD_FWCLASS_QAM		2
+static int modulation_fw_class(fe_modulation_t modulation)
+{
+	switch(modulation) {
+	case VSB_8:
+		return MOD_FWCLASS_VSB;
+	case QAM_AUTO:
+	case QAM_64:
+	case QAM_256:
+		return MOD_FWCLASS_QAM;
+	default:
+		return MOD_FWCLASS_UNKNOWN;
+	}
+}
+
+static int or51132_set_parameters(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	int ret;
+	struct or51132_state* state = fe->demodulator_priv;
+	const struct firmware *fw;
+	const char *fwname;
+	int clock_mode;
+
+	/* Upload new firmware only if we need a different one */
+	if (modulation_fw_class(state->current_modulation) !=
+	    modulation_fw_class(p->modulation)) {
+		switch (modulation_fw_class(p->modulation)) {
+		case MOD_FWCLASS_VSB:
+			dprintk("set_parameters VSB MODE\n");
+			fwname = OR51132_VSB_FIRMWARE;
+
+			/* Set non-punctured clock for VSB */
+			clock_mode = 0;
+			break;
+		case MOD_FWCLASS_QAM:
+			dprintk("set_parameters QAM MODE\n");
+			fwname = OR51132_QAM_FIRMWARE;
+
+			/* Set punctured clock for QAM */
+			clock_mode = 1;
+			break;
+		default:
+			printk("or51132: Modulation type(%d) UNSUPPORTED\n",
+			       p->modulation);
+			return -1;
+		}
+		printk("or51132: Waiting for firmware upload(%s)...\n",
+		       fwname);
+		ret = request_firmware(&fw, fwname, state->i2c->dev.parent);
+		if (ret) {
+			printk(KERN_WARNING "or51132: No firmware up"
+			       "loaded(timeout or file not found?)\n");
+			return ret;
+		}
+		ret = or51132_load_firmware(fe, fw);
+		release_firmware(fw);
+		if (ret) {
+			printk(KERN_WARNING "or51132: Writing firmware to "
+			       "device failed!\n");
+			return ret;
+		}
+		printk("or51132: Firmware upload complete.\n");
+		state->config->set_ts_params(fe, clock_mode);
+	}
+	/* Change only if we are actually changing the modulation */
+	if (state->current_modulation != p->modulation) {
+		state->current_modulation = p->modulation;
+		or51132_setmode(fe);
+	}
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	/* Set to current mode */
+	or51132_setmode(fe);
+
+	/* Update current frequency */
+	state->current_frequency = p->frequency;
+	return 0;
+}
+
+static int or51132_get_parameters(struct dvb_frontend* fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct or51132_state* state = fe->demodulator_priv;
+	int status;
+	int retry = 1;
+
+start:
+	/* Receiver Status */
+	if ((status = or51132_readreg(state, 0x00)) < 0) {
+		printk(KERN_WARNING "or51132: get_parameters: error reading receiver status\n");
+		return -EREMOTEIO;
+	}
+	switch(status&0xff) {
+	case 0x06:
+		p->modulation = VSB_8;
+		break;
+	case 0x43:
+		p->modulation = QAM_64;
+		break;
+	case 0x45:
+		p->modulation = QAM_256;
+		break;
+	default:
+		if (retry--)
+			goto start;
+		printk(KERN_WARNING "or51132: unknown status 0x%02x\n",
+		       status&0xff);
+		return -EREMOTEIO;
+	}
+
+	/* FIXME: Read frequency from frontend, take AFC into account */
+	p->frequency = state->current_frequency;
+
+	/* FIXME: How to read inversion setting? Receiver 6 register? */
+	p->inversion = INVERSION_AUTO;
+
+	return 0;
+}
+
+static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct or51132_state* state = fe->demodulator_priv;
+	int reg;
+
+	/* Receiver Status */
+	if ((reg = or51132_readreg(state, 0x00)) < 0) {
+		printk(KERN_WARNING "or51132: read_status: error reading receiver status: %d\n", reg);
+		*status = 0;
+		return -EREMOTEIO;
+	}
+	dprintk("%s: read_status %04x\n", __func__, reg);
+
+	if (reg & 0x0100) /* Receiver Lock */
+		*status = FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI|
+			  FE_HAS_SYNC|FE_HAS_LOCK;
+	else
+		*status = 0;
+	return 0;
+}
+
+/* Calculate SNR estimation (scaled by 2^24)
+
+   8-VSB SNR and QAM equations from Oren datasheets
+
+   For 8-VSB:
+     SNR[dB] = 10 * log10(897152044.8282 / MSE^2 ) - K
+
+     Where K = 0 if NTSC rejection filter is OFF; and
+	   K = 3 if NTSC rejection filter is ON
+
+   For QAM64:
+     SNR[dB] = 10 * log10(897152044.8282 / MSE^2 )
+
+   For QAM256:
+     SNR[dB] = 10 * log10(907832426.314266  / MSE^2 )
+
+   We re-write the snr equation as:
+     SNR * 2^24 = 10*(c - 2*intlog10(MSE))
+   Where for QAM256, c = log10(907832426.314266) * 2^24
+   and for 8-VSB and QAM64, c = log10(897152044.8282) * 2^24 */
+
+static u32 calculate_snr(u32 mse, u32 c)
+{
+	if (mse == 0) /* No signal */
+		return 0;
+
+	mse = 2*intlog10(mse);
+	if (mse > c) {
+		/* Negative SNR, which is possible, but realisticly the
+		demod will lose lock before the signal gets this bad.  The
+		API only allows for unsigned values, so just return 0 */
+		return 0;
+	}
+	return 10*(c - mse);
+}
+
+static int or51132_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct or51132_state* state = fe->demodulator_priv;
+	int noise, reg;
+	u32 c, usK = 0;
+	int retry = 1;
+
+start:
+	/* SNR after Equalizer */
+	noise = or51132_readreg(state, 0x02);
+	if (noise < 0) {
+		printk(KERN_WARNING "or51132: read_snr: error reading equalizer\n");
+		return -EREMOTEIO;
+	}
+	dprintk("read_snr noise (%d)\n", noise);
+
+	/* Read status, contains modulation type for QAM_AUTO and
+	   NTSC filter for VSB */
+	reg = or51132_readreg(state, 0x00);
+	if (reg < 0) {
+		printk(KERN_WARNING "or51132: read_snr: error reading receiver status\n");
+		return -EREMOTEIO;
+	}
+
+	switch (reg&0xff) {
+	case 0x06:
+		if (reg & 0x1000) usK = 3 << 24;
+		/* Fall through to QAM64 case */
+	case 0x43:
+		c = 150204167;
+		break;
+	case 0x45:
+		c = 150290396;
+		break;
+	default:
+		printk(KERN_WARNING "or51132: unknown status 0x%02x\n", reg&0xff);
+		if (retry--) goto start;
+		return -EREMOTEIO;
+	}
+	dprintk("%s: modulation %02x, NTSC rej O%s\n", __func__,
+		reg&0xff, reg&0x1000?"n":"ff");
+
+	/* Calculate SNR using noise, c, and NTSC rejection correction */
+	state->snr = calculate_snr(noise, c) - usK;
+	*snr = (state->snr) >> 16;
+
+	dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise,
+		state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
+
+	return 0;
+}
+
+static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	/* Calculate Strength from SNR up to 35dB */
+	/* Even though the SNR can go higher than 35dB, there is some comfort */
+	/* factor in having a range of strong signals that can show at 100%   */
+	struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv;
+	u16 snr;
+	int ret;
+
+	ret = fe->ops.read_snr(fe, &snr);
+	if (ret != 0)
+		return ret;
+	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
+	/* scale the range 0 - 35*2^24 into 0 - 65535 */
+	if (state->snr >= 8960 * 0x10000)
+		*strength = 0xffff;
+	else
+		*strength = state->snr / 8960;
+
+	return 0;
+}
+
+static int or51132_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings)
+{
+	fe_tune_settings->min_delay_ms = 500;
+	fe_tune_settings->step_size = 0;
+	fe_tune_settings->max_drift = 0;
+
+	return 0;
+}
+
+static void or51132_release(struct dvb_frontend* fe)
+{
+	struct or51132_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops or51132_ops;
+
+struct dvb_frontend* or51132_attach(const struct or51132_config* config,
+				    struct i2c_adapter* i2c)
+{
+	struct or51132_state* state = NULL;
+
+	/* Allocate memory for the internal state */
+	state = kzalloc(sizeof(struct or51132_state), GFP_KERNEL);
+	if (state == NULL)
+		return NULL;
+
+	/* Setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->current_frequency = -1;
+	state->current_modulation = -1;
+
+	/* Create dvb_frontend */
+	memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+}
+
+static struct dvb_frontend_ops or51132_ops = {
+	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
+	.info = {
+		.name			= "Oren OR51132 VSB/QAM Frontend",
+		.frequency_min		= 44000000,
+		.frequency_max		= 958000000,
+		.frequency_stepsize	= 166666,
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO |
+			FE_CAN_8VSB
+	},
+
+	.release = or51132_release,
+
+	.init = or51132_init,
+	.sleep = or51132_sleep,
+
+	.set_frontend = or51132_set_parameters,
+	.get_frontend = or51132_get_parameters,
+	.get_tune_settings = or51132_get_tune_settings,
+
+	.read_status = or51132_read_status,
+	.read_ber = or51132_read_ber,
+	.read_signal_strength = or51132_read_signal_strength,
+	.read_snr = or51132_read_snr,
+	.read_ucblocks = or51132_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("OR51132 ATSC [pcHDTV HD-3000] (8VSB & ITU J83 AnnexB FEC QAM64/256) Demodulator Driver");
+MODULE_AUTHOR("Kirk Lapray");
+MODULE_AUTHOR("Trent Piepho");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(or51132_attach);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb-frontends/or51132.h b/drivers/media/dvb-frontends/or51132.h
new file mode 100644
index 0000000..1b8e04d
--- /dev/null
+++ b/drivers/media/dvb-frontends/or51132.h
@@ -0,0 +1,55 @@
+/*
+ *    Support for OR51132 (pcHDTV HD-3000) - VSB/QAM
+ *
+ *    Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+#ifndef OR51132_H
+#define OR51132_H
+
+#include <linux/firmware.h>
+#include <linux/dvb/frontend.h>
+
+struct or51132_config
+{
+	/* The demodulator's i2c address */
+	u8 demod_address;
+
+	/* Need to set device param for start_dma */
+	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+};
+
+#if defined(CONFIG_DVB_OR51132) || (defined(CONFIG_DVB_OR51132_MODULE) && defined(MODULE))
+extern struct dvb_frontend* or51132_attach(const struct or51132_config* config,
+					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* or51132_attach(const struct or51132_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_OR51132
+
+#endif // OR51132_H
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb-frontends/or51211.c b/drivers/media/dvb-frontends/or51211.c
new file mode 100644
index 0000000..c625b57
--- /dev/null
+++ b/drivers/media/dvb-frontends/or51211.c
@@ -0,0 +1,581 @@
+/*
+ *    Support for OR51211 (pcHDTV HD-2000) - VSB
+ *
+ *    Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com>
+ *
+ *    Based on code from Jack Kelliher (kelliher@xmission.com)
+ *                           Copyright (C) 2002 & pcHDTV, inc.
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+/*
+ * This driver needs external firmware. Please use the command
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
+ */
+#define OR51211_DEFAULT_FIRMWARE "dvb-fe-or51211.fw"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <asm/byteorder.h>
+
+#include "dvb_math.h"
+#include "dvb_frontend.h"
+#include "or51211.h"
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "or51211: " args); \
+	} while (0)
+
+static u8 run_buf[] = {0x7f,0x01};
+static u8 cmd_buf[] = {0x04,0x01,0x50,0x80,0x06}; // ATSC
+
+struct or51211_state {
+
+	struct i2c_adapter* i2c;
+
+	/* Configuration settings */
+	const struct or51211_config* config;
+
+	struct dvb_frontend frontend;
+	struct bt878* bt;
+
+	/* Demodulator private data */
+	u8 initialized:1;
+	u32 snr; /* Result of last SNR claculation */
+
+	/* Tuner private data */
+	u32 current_frequency;
+};
+
+static int i2c_writebytes (struct or51211_state* state, u8 reg, const u8 *buf,
+			   int len)
+{
+	int err;
+	struct i2c_msg msg;
+	msg.addr	= reg;
+	msg.flags	= 0;
+	msg.len		= len;
+	msg.buf		= (u8 *)buf;
+
+	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+		printk(KERN_WARNING "or51211: i2c_writebytes error "
+		       "(addr %02x, err == %i)\n", reg, err);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int i2c_readbytes(struct or51211_state *state, u8 reg, u8 *buf, int len)
+{
+	int err;
+	struct i2c_msg msg;
+	msg.addr	= reg;
+	msg.flags	= I2C_M_RD;
+	msg.len		= len;
+	msg.buf		= buf;
+
+	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+		printk(KERN_WARNING "or51211: i2c_readbytes error "
+		       "(addr %02x, err == %i)\n", reg, err);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int or51211_load_firmware (struct dvb_frontend* fe,
+				  const struct firmware *fw)
+{
+	struct or51211_state* state = fe->demodulator_priv;
+	u8 tudata[585];
+	int i;
+
+	dprintk("Firmware is %zd bytes\n",fw->size);
+
+	/* Get eprom data */
+	tudata[0] = 17;
+	if (i2c_writebytes(state,0x50,tudata,1)) {
+		printk(KERN_WARNING "or51211:load_firmware error eprom addr\n");
+		return -1;
+	}
+	if (i2c_readbytes(state,0x50,&tudata[145],192)) {
+		printk(KERN_WARNING "or51211: load_firmware error eprom\n");
+		return -1;
+	}
+
+	/* Create firmware buffer */
+	for (i = 0; i < 145; i++)
+		tudata[i] = fw->data[i];
+
+	for (i = 0; i < 248; i++)
+		tudata[i+337] = fw->data[145+i];
+
+	state->config->reset(fe);
+
+	if (i2c_writebytes(state,state->config->demod_address,tudata,585)) {
+		printk(KERN_WARNING "or51211: load_firmware error 1\n");
+		return -1;
+	}
+	msleep(1);
+
+	if (i2c_writebytes(state,state->config->demod_address,
+			   &fw->data[393],8125)) {
+		printk(KERN_WARNING "or51211: load_firmware error 2\n");
+		return -1;
+	}
+	msleep(1);
+
+	if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
+		printk(KERN_WARNING "or51211: load_firmware error 3\n");
+		return -1;
+	}
+
+	/* Wait at least 5 msec */
+	msleep(10);
+	if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
+		printk(KERN_WARNING "or51211: load_firmware error 4\n");
+		return -1;
+	}
+	msleep(10);
+
+	printk("or51211: Done.\n");
+	return 0;
+};
+
+static int or51211_setmode(struct dvb_frontend* fe, int mode)
+{
+	struct or51211_state* state = fe->demodulator_priv;
+	u8 rec_buf[14];
+
+	state->config->setmode(fe, mode);
+
+	if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
+		printk(KERN_WARNING "or51211: setmode error 1\n");
+		return -1;
+	}
+
+	/* Wait at least 5 msec */
+	msleep(10);
+	if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
+		printk(KERN_WARNING "or51211: setmode error 2\n");
+		return -1;
+	}
+
+	msleep(10);
+
+	/* Set operation mode in Receiver 1 register;
+	 * type 1:
+	 * data 0x50h  Automatic sets receiver channel conditions
+	 *             Automatic NTSC rejection filter
+	 *             Enable  MPEG serial data output
+	 *             MPEG2tr
+	 *             High tuner phase noise
+	 *             normal +/-150kHz Carrier acquisition range
+	 */
+	if (i2c_writebytes(state,state->config->demod_address,cmd_buf,3)) {
+		printk(KERN_WARNING "or51211: setmode error 3\n");
+		return -1;
+	}
+
+	rec_buf[0] = 0x04;
+	rec_buf[1] = 0x00;
+	rec_buf[2] = 0x03;
+	rec_buf[3] = 0x00;
+	msleep(20);
+	if (i2c_writebytes(state,state->config->demod_address,rec_buf,3)) {
+		printk(KERN_WARNING "or51211: setmode error 5\n");
+	}
+	msleep(3);
+	if (i2c_readbytes(state,state->config->demod_address,&rec_buf[10],2)) {
+		printk(KERN_WARNING "or51211: setmode error 6");
+		return -1;
+	}
+	dprintk("setmode rec status %02x %02x\n",rec_buf[10],rec_buf[11]);
+
+	return 0;
+}
+
+static int or51211_set_parameters(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct or51211_state* state = fe->demodulator_priv;
+
+	/* Change only if we are actually changing the channel */
+	if (state->current_frequency != p->frequency) {
+		if (fe->ops.tuner_ops.set_params) {
+			fe->ops.tuner_ops.set_params(fe);
+			if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+
+		/* Set to ATSC mode */
+		or51211_setmode(fe,0);
+
+		/* Update current frequency */
+		state->current_frequency = p->frequency;
+	}
+	return 0;
+}
+
+static int or51211_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct or51211_state* state = fe->demodulator_priv;
+	unsigned char rec_buf[2];
+	unsigned char snd_buf[] = {0x04,0x00,0x03,0x00};
+	*status = 0;
+
+	/* Receiver Status */
+	if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
+		printk(KERN_WARNING "or51132: read_status write error\n");
+		return -1;
+	}
+	msleep(3);
+	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
+		printk(KERN_WARNING "or51132: read_status read error\n");
+		return -1;
+	}
+	dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]);
+
+	if (rec_buf[0] &  0x01) { /* Receiver Lock */
+		*status |= FE_HAS_SIGNAL;
+		*status |= FE_HAS_CARRIER;
+		*status |= FE_HAS_VITERBI;
+		*status |= FE_HAS_SYNC;
+		*status |= FE_HAS_LOCK;
+	}
+	return 0;
+}
+
+/* Calculate SNR estimation (scaled by 2^24)
+
+   8-VSB SNR equation from Oren datasheets
+
+   For 8-VSB:
+     SNR[dB] = 10 * log10(219037.9454 / MSE^2 )
+
+   We re-write the snr equation as:
+     SNR * 2^24 = 10*(c - 2*intlog10(MSE))
+   Where for 8-VSB, c = log10(219037.9454) * 2^24 */
+
+static u32 calculate_snr(u32 mse, u32 c)
+{
+	if (mse == 0) /* No signal */
+		return 0;
+
+	mse = 2*intlog10(mse);
+	if (mse > c) {
+		/* Negative SNR, which is possible, but realisticly the
+		demod will lose lock before the signal gets this bad.  The
+		API only allows for unsigned values, so just return 0 */
+		return 0;
+	}
+	return 10*(c - mse);
+}
+
+static int or51211_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct or51211_state* state = fe->demodulator_priv;
+	u8 rec_buf[2];
+	u8 snd_buf[3];
+
+	/* SNR after Equalizer */
+	snd_buf[0] = 0x04;
+	snd_buf[1] = 0x00;
+	snd_buf[2] = 0x04;
+
+	if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
+		printk(KERN_WARNING "%s: error writing snr reg\n",
+		       __func__);
+		return -1;
+	}
+	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
+		printk(KERN_WARNING "%s: read_status read error\n",
+		       __func__);
+		return -1;
+	}
+
+	state->snr = calculate_snr(rec_buf[0], 89599047);
+	*snr = (state->snr) >> 16;
+
+	dprintk("%s: noise = 0x%02x, snr = %d.%02d dB\n", __func__, rec_buf[0],
+		state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
+
+	return 0;
+}
+
+static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	/* Calculate Strength from SNR up to 35dB */
+	/* Even though the SNR can go higher than 35dB, there is some comfort */
+	/* factor in having a range of strong signals that can show at 100%   */
+	struct or51211_state* state = (struct or51211_state*)fe->demodulator_priv;
+	u16 snr;
+	int ret;
+
+	ret = fe->ops.read_snr(fe, &snr);
+	if (ret != 0)
+		return ret;
+	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
+	/* scale the range 0 - 35*2^24 into 0 - 65535 */
+	if (state->snr >= 8960 * 0x10000)
+		*strength = 0xffff;
+	else
+		*strength = state->snr / 8960;
+
+	return 0;
+}
+
+static int or51211_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	*ber = -ENOSYS;
+	return 0;
+}
+
+static int or51211_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	*ucblocks = -ENOSYS;
+	return 0;
+}
+
+static int or51211_sleep(struct dvb_frontend* fe)
+{
+	return 0;
+}
+
+static int or51211_init(struct dvb_frontend* fe)
+{
+	struct or51211_state* state = fe->demodulator_priv;
+	const struct or51211_config* config = state->config;
+	const struct firmware* fw;
+	unsigned char get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00};
+	unsigned char rec_buf[14];
+	int ret,i;
+
+	if (!state->initialized) {
+		/* Request the firmware, this will block until it uploads */
+		printk(KERN_INFO "or51211: Waiting for firmware upload "
+		       "(%s)...\n", OR51211_DEFAULT_FIRMWARE);
+		ret = config->request_firmware(fe, &fw,
+					       OR51211_DEFAULT_FIRMWARE);
+		printk(KERN_INFO "or51211:Got Hotplug firmware\n");
+		if (ret) {
+			printk(KERN_WARNING "or51211: No firmware uploaded "
+			       "(timeout or file not found?)\n");
+			return ret;
+		}
+
+		ret = or51211_load_firmware(fe, fw);
+		release_firmware(fw);
+		if (ret) {
+			printk(KERN_WARNING "or51211: Writing firmware to "
+			       "device failed!\n");
+			return ret;
+		}
+		printk(KERN_INFO "or51211: Firmware upload complete.\n");
+
+		/* Set operation mode in Receiver 1 register;
+		 * type 1:
+		 * data 0x50h  Automatic sets receiver channel conditions
+		 *             Automatic NTSC rejection filter
+		 *             Enable  MPEG serial data output
+		 *             MPEG2tr
+		 *             High tuner phase noise
+		 *             normal +/-150kHz Carrier acquisition range
+		 */
+		if (i2c_writebytes(state,state->config->demod_address,
+				   cmd_buf,3)) {
+			printk(KERN_WARNING "or51211: Load DVR Error 5\n");
+			return -1;
+		}
+
+		/* Read back ucode version to besure we loaded correctly */
+		/* and are really up and running */
+		rec_buf[0] = 0x04;
+		rec_buf[1] = 0x00;
+		rec_buf[2] = 0x03;
+		rec_buf[3] = 0x00;
+		msleep(30);
+		if (i2c_writebytes(state,state->config->demod_address,
+				   rec_buf,3)) {
+			printk(KERN_WARNING "or51211: Load DVR Error A\n");
+			return -1;
+		}
+		msleep(3);
+		if (i2c_readbytes(state,state->config->demod_address,
+				  &rec_buf[10],2)) {
+			printk(KERN_WARNING "or51211: Load DVR Error B\n");
+			return -1;
+		}
+
+		rec_buf[0] = 0x04;
+		rec_buf[1] = 0x00;
+		rec_buf[2] = 0x01;
+		rec_buf[3] = 0x00;
+		msleep(20);
+		if (i2c_writebytes(state,state->config->demod_address,
+				   rec_buf,3)) {
+			printk(KERN_WARNING "or51211: Load DVR Error C\n");
+			return -1;
+		}
+		msleep(3);
+		if (i2c_readbytes(state,state->config->demod_address,
+				  &rec_buf[12],2)) {
+			printk(KERN_WARNING "or51211: Load DVR Error D\n");
+			return -1;
+		}
+
+		for (i = 0; i < 8; i++)
+			rec_buf[i]=0xed;
+
+		for (i = 0; i < 5; i++) {
+			msleep(30);
+			get_ver_buf[4] = i+1;
+			if (i2c_writebytes(state,state->config->demod_address,
+					   get_ver_buf,5)) {
+				printk(KERN_WARNING "or51211:Load DVR Error 6"
+				       " - %d\n",i);
+				return -1;
+			}
+			msleep(3);
+
+			if (i2c_readbytes(state,state->config->demod_address,
+					  &rec_buf[i*2],2)) {
+				printk(KERN_WARNING "or51211:Load DVR Error 7"
+				       " - %d\n",i);
+				return -1;
+			}
+			/* If we didn't receive the right index, try again */
+			if ((int)rec_buf[i*2+1]!=i+1){
+			  i--;
+			}
+		}
+		dprintk("read_fwbits %x %x %x %x %x %x %x %x %x %x\n",
+			rec_buf[0], rec_buf[1], rec_buf[2], rec_buf[3],
+			rec_buf[4], rec_buf[5], rec_buf[6], rec_buf[7],
+			rec_buf[8], rec_buf[9]);
+
+		printk(KERN_INFO "or51211: ver TU%02x%02x%02x VSB mode %02x"
+		       " Status %02x\n",
+		       rec_buf[2], rec_buf[4],rec_buf[6],
+		       rec_buf[12],rec_buf[10]);
+
+		rec_buf[0] = 0x04;
+		rec_buf[1] = 0x00;
+		rec_buf[2] = 0x03;
+		rec_buf[3] = 0x00;
+		msleep(20);
+		if (i2c_writebytes(state,state->config->demod_address,
+				   rec_buf,3)) {
+			printk(KERN_WARNING "or51211: Load DVR Error 8\n");
+			return -1;
+		}
+		msleep(20);
+		if (i2c_readbytes(state,state->config->demod_address,
+				  &rec_buf[8],2)) {
+			printk(KERN_WARNING "or51211: Load DVR Error 9\n");
+			return -1;
+		}
+		state->initialized = 1;
+	}
+
+	return 0;
+}
+
+static int or51211_get_tune_settings(struct dvb_frontend* fe,
+				     struct dvb_frontend_tune_settings* fesettings)
+{
+	fesettings->min_delay_ms = 500;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+	return 0;
+}
+
+static void or51211_release(struct dvb_frontend* fe)
+{
+	struct or51211_state* state = fe->demodulator_priv;
+	state->config->sleep(fe);
+	kfree(state);
+}
+
+static struct dvb_frontend_ops or51211_ops;
+
+struct dvb_frontend* or51211_attach(const struct or51211_config* config,
+				    struct i2c_adapter* i2c)
+{
+	struct or51211_state* state = NULL;
+
+	/* Allocate memory for the internal state */
+	state = kzalloc(sizeof(struct or51211_state), GFP_KERNEL);
+	if (state == NULL)
+		return NULL;
+
+	/* Setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->initialized = 0;
+	state->current_frequency = 0;
+
+	/* Create dvb_frontend */
+	memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+}
+
+static struct dvb_frontend_ops or51211_ops = {
+	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
+	.info = {
+		.name               = "Oren OR51211 VSB Frontend",
+		.frequency_min      = 44000000,
+		.frequency_max      = 958000000,
+		.frequency_stepsize = 166666,
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_8VSB
+	},
+
+	.release = or51211_release,
+
+	.init = or51211_init,
+	.sleep = or51211_sleep,
+
+	.set_frontend = or51211_set_parameters,
+	.get_tune_settings = or51211_get_tune_settings,
+
+	.read_status = or51211_read_status,
+	.read_ber = or51211_read_ber,
+	.read_signal_strength = or51211_read_signal_strength,
+	.read_snr = or51211_read_snr,
+	.read_ucblocks = or51211_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Oren OR51211 VSB [pcHDTV HD-2000] Demodulator Driver");
+MODULE_AUTHOR("Kirk Lapray");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(or51211_attach);
+
diff --git a/drivers/media/dvb-frontends/or51211.h b/drivers/media/dvb-frontends/or51211.h
new file mode 100644
index 0000000..3ce0508
--- /dev/null
+++ b/drivers/media/dvb-frontends/or51211.h
@@ -0,0 +1,53 @@
+/*
+ *    Support for OR51211 (pcHDTV HD-2000) - VSB
+ *
+ *    Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+#ifndef OR51211_H
+#define OR51211_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct or51211_config
+{
+	/* The demodulator's i2c address */
+	u8 demod_address;
+
+	/* Request firmware for device */
+	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+	void (*setmode)(struct dvb_frontend * fe, int mode);
+	void (*reset)(struct dvb_frontend * fe);
+	void (*sleep)(struct dvb_frontend * fe);
+};
+
+#if defined(CONFIG_DVB_OR51211) || (defined(CONFIG_DVB_OR51211_MODULE) && defined(MODULE))
+extern struct dvb_frontend* or51211_attach(const struct or51211_config* config,
+					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* or51211_attach(const struct or51211_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_OR51211
+
+#endif // OR51211_H
+
diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c
new file mode 100644
index 0000000..8fa8b08
--- /dev/null
+++ b/drivers/media/dvb-frontends/rtl2830.c
@@ -0,0 +1,757 @@
+/*
+ * Realtek RTL2830 DVB-T demodulator driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+/*
+ * Driver implements own I2C-adapter for tuner I2C access. That's since chip
+ * have unusual I2C-gate control which closes gate automatically after each
+ * I2C transfer. Using own I2C adapter we can workaround that.
+ */
+
+#include "rtl2830_priv.h"
+
+int rtl2830_debug;
+module_param_named(debug, rtl2830_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+/* write multiple hardware registers */
+static int rtl2830_wr(struct rtl2830_priv *priv, u8 reg, u8 *val, int len)
+{
+	int ret;
+	u8 buf[1+len];
+	struct i2c_msg msg[1] = {
+		{
+			.addr = priv->cfg.i2c_addr,
+			.flags = 0,
+			.len = 1+len,
+			.buf = buf,
+		}
+	};
+
+	buf[0] = reg;
+	memcpy(&buf[1], val, len);
+
+	ret = i2c_transfer(priv->i2c, msg, 1);
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+/* read multiple hardware registers */
+static int rtl2830_rd(struct rtl2830_priv *priv, u8 reg, u8 *val, int len)
+{
+	int ret;
+	struct i2c_msg msg[2] = {
+		{
+			.addr = priv->cfg.i2c_addr,
+			.flags = 0,
+			.len = 1,
+			.buf = &reg,
+		}, {
+			.addr = priv->cfg.i2c_addr,
+			.flags = I2C_M_RD,
+			.len = len,
+			.buf = val,
+		}
+	};
+
+	ret = i2c_transfer(priv->i2c, msg, 2);
+	if (ret == 2) {
+		ret = 0;
+	} else {
+		warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+/* write multiple registers */
+static int rtl2830_wr_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len)
+{
+	int ret;
+	u8 reg2 = (reg >> 0) & 0xff;
+	u8 page = (reg >> 8) & 0xff;
+
+	/* switch bank if needed */
+	if (page != priv->page) {
+		ret = rtl2830_wr(priv, 0x00, &page, 1);
+		if (ret)
+			return ret;
+
+		priv->page = page;
+	}
+
+	return rtl2830_wr(priv, reg2, val, len);
+}
+
+/* read multiple registers */
+static int rtl2830_rd_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len)
+{
+	int ret;
+	u8 reg2 = (reg >> 0) & 0xff;
+	u8 page = (reg >> 8) & 0xff;
+
+	/* switch bank if needed */
+	if (page != priv->page) {
+		ret = rtl2830_wr(priv, 0x00, &page, 1);
+		if (ret)
+			return ret;
+
+		priv->page = page;
+	}
+
+	return rtl2830_rd(priv, reg2, val, len);
+}
+
+#if 0 /* currently not used */
+/* write single register */
+static int rtl2830_wr_reg(struct rtl2830_priv *priv, u16 reg, u8 val)
+{
+	return rtl2830_wr_regs(priv, reg, &val, 1);
+}
+#endif
+
+/* read single register */
+static int rtl2830_rd_reg(struct rtl2830_priv *priv, u16 reg, u8 *val)
+{
+	return rtl2830_rd_regs(priv, reg, val, 1);
+}
+
+/* write single register with mask */
+int rtl2830_wr_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 val, u8 mask)
+{
+	int ret;
+	u8 tmp;
+
+	/* no need for read if whole reg is written */
+	if (mask != 0xff) {
+		ret = rtl2830_rd_regs(priv, reg, &tmp, 1);
+		if (ret)
+			return ret;
+
+		val &= mask;
+		tmp &= ~mask;
+		val |= tmp;
+	}
+
+	return rtl2830_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register with mask */
+int rtl2830_rd_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 *val, u8 mask)
+{
+	int ret, i;
+	u8 tmp;
+
+	ret = rtl2830_rd_regs(priv, reg, &tmp, 1);
+	if (ret)
+		return ret;
+
+	tmp &= mask;
+
+	/* find position of the first bit */
+	for (i = 0; i < 8; i++) {
+		if ((mask >> i) & 0x01)
+			break;
+	}
+	*val = tmp >> i;
+
+	return 0;
+}
+
+static int rtl2830_init(struct dvb_frontend *fe)
+{
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	int ret, i;
+	u64 num;
+	u8 buf[3], tmp;
+	u32 if_ctl;
+	struct rtl2830_reg_val_mask tab[] = {
+		{ 0x00d, 0x01, 0x03 },
+		{ 0x00d, 0x10, 0x10 },
+		{ 0x104, 0x00, 0x1e },
+		{ 0x105, 0x80, 0x80 },
+		{ 0x110, 0x02, 0x03 },
+		{ 0x110, 0x08, 0x0c },
+		{ 0x17b, 0x00, 0x40 },
+		{ 0x17d, 0x05, 0x0f },
+		{ 0x17d, 0x50, 0xf0 },
+		{ 0x18c, 0x08, 0x0f },
+		{ 0x18d, 0x00, 0xc0 },
+		{ 0x188, 0x05, 0x0f },
+		{ 0x189, 0x00, 0xfc },
+		{ 0x2d5, 0x02, 0x02 },
+		{ 0x2f1, 0x02, 0x06 },
+		{ 0x2f1, 0x20, 0xf8 },
+		{ 0x16d, 0x00, 0x01 },
+		{ 0x1a6, 0x00, 0x80 },
+		{ 0x106, priv->cfg.vtop, 0x3f },
+		{ 0x107, priv->cfg.krf, 0x3f },
+		{ 0x112, 0x28, 0xff },
+		{ 0x103, priv->cfg.agc_targ_val, 0xff },
+		{ 0x00a, 0x02, 0x07 },
+		{ 0x140, 0x0c, 0x3c },
+		{ 0x140, 0x40, 0xc0 },
+		{ 0x15b, 0x05, 0x07 },
+		{ 0x15b, 0x28, 0x38 },
+		{ 0x15c, 0x05, 0x07 },
+		{ 0x15c, 0x28, 0x38 },
+		{ 0x115, priv->cfg.spec_inv, 0x01 },
+		{ 0x16f, 0x01, 0x07 },
+		{ 0x170, 0x18, 0x38 },
+		{ 0x172, 0x0f, 0x0f },
+		{ 0x173, 0x08, 0x38 },
+		{ 0x175, 0x01, 0x07 },
+		{ 0x176, 0x00, 0xc0 },
+	};
+
+	for (i = 0; i < ARRAY_SIZE(tab); i++) {
+		ret = rtl2830_wr_reg_mask(priv, tab[i].reg, tab[i].val,
+			tab[i].mask);
+		if (ret)
+			goto err;
+	}
+
+	ret = rtl2830_wr_regs(priv, 0x18f, "\x28\x00", 2);
+	if (ret)
+		goto err;
+
+	ret = rtl2830_wr_regs(priv, 0x195,
+		"\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8);
+	if (ret)
+		goto err;
+
+	num = priv->cfg.if_dvbt % priv->cfg.xtal;
+	num *= 0x400000;
+	num = div_u64(num, priv->cfg.xtal);
+	num = -num;
+	if_ctl = num & 0x3fffff;
+	dbg("%s: if_ctl=%08x", __func__, if_ctl);
+
+	ret = rtl2830_rd_reg_mask(priv, 0x119, &tmp, 0xc0); /* b[7:6] */
+	if (ret)
+		goto err;
+
+	buf[0] = tmp << 6;
+	buf[0] = (if_ctl >> 16) & 0x3f;
+	buf[1] = (if_ctl >>  8) & 0xff;
+	buf[2] = (if_ctl >>  0) & 0xff;
+
+	ret = rtl2830_wr_regs(priv, 0x119, buf, 3);
+	if (ret)
+		goto err;
+
+	/* TODO: spec init */
+
+	/* soft reset */
+	ret = rtl2830_wr_reg_mask(priv, 0x101, 0x04, 0x04);
+	if (ret)
+		goto err;
+
+	ret = rtl2830_wr_reg_mask(priv, 0x101, 0x00, 0x04);
+	if (ret)
+		goto err;
+
+	priv->sleeping = false;
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2830_sleep(struct dvb_frontend *fe)
+{
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	priv->sleeping = true;
+	return 0;
+}
+
+int rtl2830_get_tune_settings(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *s)
+{
+	s->min_delay_ms = 500;
+	s->step_size = fe->ops.info.frequency_stepsize * 2;
+	s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+
+	return 0;
+}
+
+static int rtl2830_set_frontend(struct dvb_frontend *fe)
+{
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i;
+	static u8 bw_params1[3][34] = {
+		{
+		0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xfa, 0x00, 0x17, 0x00, 0x41,
+		0x00, 0x64, 0x00, 0x67, 0x00, 0x38, 0x1f, 0xde, 0x1f, 0x7a,
+		0x1f, 0x47, 0x1f, 0x7c, 0x00, 0x30, 0x01, 0x4b, 0x02, 0x82,
+		0x03, 0x73, 0x03, 0xcf, /* 6 MHz */
+		}, {
+		0x1f, 0xfa, 0x1f, 0xda, 0x1f, 0xc1, 0x1f, 0xb3, 0x1f, 0xca,
+		0x00, 0x07, 0x00, 0x4d, 0x00, 0x6d, 0x00, 0x40, 0x1f, 0xca,
+		0x1f, 0x4d, 0x1f, 0x2a, 0x1f, 0xb2, 0x00, 0xec, 0x02, 0x7e,
+		0x03, 0xd0, 0x04, 0x53, /* 7 MHz */
+		}, {
+		0x00, 0x10, 0x00, 0x0e, 0x1f, 0xf7, 0x1f, 0xc9, 0x1f, 0xa0,
+		0x1f, 0xa6, 0x1f, 0xec, 0x00, 0x4e, 0x00, 0x7d, 0x00, 0x3a,
+		0x1f, 0x98, 0x1f, 0x10, 0x1f, 0x40, 0x00, 0x75, 0x02, 0x5f,
+		0x04, 0x24, 0x04, 0xdb, /* 8 MHz */
+		},
+	};
+	static u8 bw_params2[3][6] = {
+		{0xc3, 0x0c, 0x44, 0x33, 0x33, 0x30,}, /* 6 MHz */
+		{0xb8, 0xe3, 0x93, 0x99, 0x99, 0x98,}, /* 7 MHz */
+		{0xae, 0xba, 0xf3, 0x26, 0x66, 0x64,}, /* 8 MHz */
+	};
+
+
+	dbg("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__,
+		c->frequency, c->bandwidth_hz, c->inversion);
+
+	/* program tuner */
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+
+	switch (c->bandwidth_hz) {
+	case 6000000:
+		i = 0;
+		break;
+	case 7000000:
+		i = 1;
+		break;
+	case 8000000:
+		i = 2;
+		break;
+	default:
+		dbg("invalid bandwidth");
+		return -EINVAL;
+	}
+
+	ret = rtl2830_wr_reg_mask(priv, 0x008, i << 1, 0x06);
+	if (ret)
+		goto err;
+
+	/* 1/2 split I2C write */
+	ret = rtl2830_wr_regs(priv, 0x11c, &bw_params1[i][0], 17);
+	if (ret)
+		goto err;
+
+	/* 2/2 split I2C write */
+	ret = rtl2830_wr_regs(priv, 0x12d, &bw_params1[i][17], 17);
+	if (ret)
+		goto err;
+
+	ret = rtl2830_wr_regs(priv, 0x19d, bw_params2[i], 6);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2830_get_frontend(struct dvb_frontend *fe)
+{
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret;
+	u8 buf[3];
+
+	if (priv->sleeping)
+		return 0;
+
+	ret = rtl2830_rd_regs(priv, 0x33c, buf, 2);
+	if (ret)
+		goto err;
+
+	ret = rtl2830_rd_reg(priv, 0x351, &buf[2]);
+	if (ret)
+		goto err;
+
+	dbg("%s: TPS=%*ph", __func__, 3, buf);
+
+	switch ((buf[0] >> 2) & 3) {
+	case 0:
+		c->modulation = QPSK;
+		break;
+	case 1:
+		c->modulation = QAM_16;
+		break;
+	case 2:
+		c->modulation = QAM_64;
+		break;
+	}
+
+	switch ((buf[2] >> 2) & 1) {
+	case 0:
+		c->transmission_mode = TRANSMISSION_MODE_2K;
+		break;
+	case 1:
+		c->transmission_mode = TRANSMISSION_MODE_8K;
+	}
+
+	switch ((buf[2] >> 0) & 3) {
+	case 0:
+		c->guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		c->guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		c->guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		c->guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	}
+
+	switch ((buf[0] >> 4) & 7) {
+	case 0:
+		c->hierarchy = HIERARCHY_NONE;
+		break;
+	case 1:
+		c->hierarchy = HIERARCHY_1;
+		break;
+	case 2:
+		c->hierarchy = HIERARCHY_2;
+		break;
+	case 3:
+		c->hierarchy = HIERARCHY_4;
+		break;
+	}
+
+	switch ((buf[1] >> 3) & 7) {
+	case 0:
+		c->code_rate_HP = FEC_1_2;
+		break;
+	case 1:
+		c->code_rate_HP = FEC_2_3;
+		break;
+	case 2:
+		c->code_rate_HP = FEC_3_4;
+		break;
+	case 3:
+		c->code_rate_HP = FEC_5_6;
+		break;
+	case 4:
+		c->code_rate_HP = FEC_7_8;
+		break;
+	}
+
+	switch ((buf[1] >> 0) & 7) {
+	case 0:
+		c->code_rate_LP = FEC_1_2;
+		break;
+	case 1:
+		c->code_rate_LP = FEC_2_3;
+		break;
+	case 2:
+		c->code_rate_LP = FEC_3_4;
+		break;
+	case 3:
+		c->code_rate_LP = FEC_5_6;
+		break;
+	case 4:
+		c->code_rate_LP = FEC_7_8;
+		break;
+	}
+
+	return 0;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 tmp;
+	*status = 0;
+
+	if (priv->sleeping)
+		return 0;
+
+	ret = rtl2830_rd_reg_mask(priv, 0x351, &tmp, 0x78); /* [6:3] */
+	if (ret)
+		goto err;
+
+	if (tmp == 11) {
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+			FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+	} else if (tmp == 10) {
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+			FE_HAS_VITERBI;
+	}
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	int ret, hierarchy, constellation;
+	u8 buf[2], tmp;
+	u16 tmp16;
+#define CONSTELLATION_NUM 3
+#define HIERARCHY_NUM 4
+	static const u32 snr_constant[CONSTELLATION_NUM][HIERARCHY_NUM] = {
+		{ 70705899, 70705899, 70705899, 70705899 },
+		{ 82433173, 82433173, 87483115, 94445660 },
+		{ 92888734, 92888734, 95487525, 99770748 },
+	};
+
+	if (priv->sleeping)
+		return 0;
+
+	/* reports SNR in resolution of 0.1 dB */
+
+	ret = rtl2830_rd_reg(priv, 0x33c, &tmp);
+	if (ret)
+		goto err;
+
+	constellation = (tmp >> 2) & 0x03; /* [3:2] */
+	if (constellation > CONSTELLATION_NUM - 1)
+		goto err;
+
+	hierarchy = (tmp >> 4) & 0x07; /* [6:4] */
+	if (hierarchy > HIERARCHY_NUM - 1)
+		goto err;
+
+	ret = rtl2830_rd_regs(priv, 0x40c, buf, 2);
+	if (ret)
+		goto err;
+
+	tmp16 = buf[0] << 8 | buf[1];
+
+	if (tmp16)
+		*snr = (snr_constant[constellation][hierarchy] -
+				intlog10(tmp16)) / ((1 << 24) / 100);
+	else
+		*snr = 0;
+
+	return 0;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 buf[2];
+
+	if (priv->sleeping)
+		return 0;
+
+	ret = rtl2830_rd_regs(priv, 0x34e, buf, 2);
+	if (ret)
+		goto err;
+
+	*ber = buf[0] << 8 | buf[1];
+
+	return 0;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	*ucblocks = 0;
+	return 0;
+}
+
+static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 buf[2];
+	u16 if_agc_raw, if_agc;
+
+	if (priv->sleeping)
+		return 0;
+
+	ret = rtl2830_rd_regs(priv, 0x359, buf, 2);
+	if (ret)
+		goto err;
+
+	if_agc_raw = (buf[0] << 8 | buf[1]) & 0x3fff;
+
+	if (if_agc_raw & (1 << 9))
+		if_agc = -(~(if_agc_raw - 1) & 0x1ff);
+	else
+		if_agc = if_agc_raw;
+
+	*strength = (u8) (55 - if_agc / 182);
+	*strength |= *strength << 8;
+
+	return 0;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static struct dvb_frontend_ops rtl2830_ops;
+
+static u32 rtl2830_tuner_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static int rtl2830_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
+	struct i2c_msg msg[], int num)
+{
+	struct rtl2830_priv *priv = i2c_get_adapdata(i2c_adap);
+	int ret;
+
+	/* open i2c-gate */
+	ret = rtl2830_wr_reg_mask(priv, 0x101, 0x08, 0x08);
+	if (ret)
+		goto err;
+
+	ret = i2c_transfer(priv->i2c, msg, num);
+	if (ret < 0)
+		warn("tuner i2c failed=%d", ret);
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static struct i2c_algorithm rtl2830_tuner_i2c_algo = {
+	.master_xfer   = rtl2830_tuner_i2c_xfer,
+	.functionality = rtl2830_tuner_i2c_func,
+};
+
+struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	return &priv->tuner_i2c_adapter;
+}
+EXPORT_SYMBOL(rtl2830_get_tuner_i2c_adapter);
+
+static void rtl2830_release(struct dvb_frontend *fe)
+{
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+
+	i2c_del_adapter(&priv->tuner_i2c_adapter);
+	kfree(priv);
+}
+
+struct dvb_frontend *rtl2830_attach(const struct rtl2830_config *cfg,
+	struct i2c_adapter *i2c)
+{
+	struct rtl2830_priv *priv = NULL;
+	int ret = 0;
+	u8 tmp;
+
+	/* allocate memory for the internal state */
+	priv = kzalloc(sizeof(struct rtl2830_priv), GFP_KERNEL);
+	if (priv == NULL)
+		goto err;
+
+	/* setup the priv */
+	priv->i2c = i2c;
+	memcpy(&priv->cfg, cfg, sizeof(struct rtl2830_config));
+
+	/* check if the demod is there */
+	ret = rtl2830_rd_reg(priv, 0x000, &tmp);
+	if (ret)
+		goto err;
+
+	/* create dvb_frontend */
+	memcpy(&priv->fe.ops, &rtl2830_ops, sizeof(struct dvb_frontend_ops));
+	priv->fe.demodulator_priv = priv;
+
+	/* create tuner i2c adapter */
+	strlcpy(priv->tuner_i2c_adapter.name, "RTL2830 tuner I2C adapter",
+		sizeof(priv->tuner_i2c_adapter.name));
+	priv->tuner_i2c_adapter.algo = &rtl2830_tuner_i2c_algo;
+	priv->tuner_i2c_adapter.algo_data = NULL;
+	i2c_set_adapdata(&priv->tuner_i2c_adapter, priv);
+	if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) {
+		err("tuner I2C bus could not be initialized");
+		goto err;
+	}
+
+	priv->sleeping = true;
+
+	return &priv->fe;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	kfree(priv);
+	return NULL;
+}
+EXPORT_SYMBOL(rtl2830_attach);
+
+static struct dvb_frontend_ops rtl2830_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "Realtek RTL2830 (DVB-T)",
+		.caps = FE_CAN_FEC_1_2 |
+			FE_CAN_FEC_2_3 |
+			FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 |
+			FE_CAN_FEC_7_8 |
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK |
+			FE_CAN_QAM_16 |
+			FE_CAN_QAM_64 |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_RECOVER |
+			FE_CAN_MUTE_TS
+	},
+
+	.release = rtl2830_release,
+
+	.init = rtl2830_init,
+	.sleep = rtl2830_sleep,
+
+	.get_tune_settings = rtl2830_get_tune_settings,
+
+	.set_frontend = rtl2830_set_frontend,
+	.get_frontend = rtl2830_get_frontend,
+
+	.read_status = rtl2830_read_status,
+	.read_snr = rtl2830_read_snr,
+	.read_ber = rtl2830_read_ber,
+	.read_ucblocks = rtl2830_read_ucblocks,
+	.read_signal_strength = rtl2830_read_signal_strength,
+};
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/rtl2830.h b/drivers/media/dvb-frontends/rtl2830.h
new file mode 100644
index 0000000..1c6ee91
--- /dev/null
+++ b/drivers/media/dvb-frontends/rtl2830.h
@@ -0,0 +1,97 @@
+/*
+ * Realtek RTL2830 DVB-T demodulator driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RTL2830_H
+#define RTL2830_H
+
+#include <linux/dvb/frontend.h>
+
+struct rtl2830_config {
+	/*
+	 * Demodulator I2C address.
+	 */
+	u8 i2c_addr;
+
+	/*
+	 * Xtal frequency.
+	 * Hz
+	 * 4000000, 16000000, 25000000, 28800000
+	 */
+	u32 xtal;
+
+	/*
+	 * TS output mode.
+	 */
+	u8 ts_mode;
+
+	/*
+	 * Spectrum inversion.
+	 */
+	bool spec_inv;
+
+	/*
+	 * IFs for all used modes.
+	 * Hz
+	 * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000
+	 */
+	u32 if_dvbt;
+
+	/*
+	 */
+	u8 vtop;
+
+	/*
+	 */
+	u8 krf;
+
+	/*
+	 */
+	u8 agc_targ_val;
+};
+
+#if defined(CONFIG_DVB_RTL2830) || \
+	(defined(CONFIG_DVB_RTL2830_MODULE) && defined(MODULE))
+extern struct dvb_frontend *rtl2830_attach(
+	const struct rtl2830_config *config,
+	struct i2c_adapter *i2c
+);
+
+extern struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(
+	struct dvb_frontend *fe
+);
+#else
+static inline struct dvb_frontend *rtl2830_attach(
+	const struct rtl2830_config *config,
+	struct i2c_adapter *i2c
+)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(
+	struct dvb_frontend *fe
+)
+{
+	return NULL;
+}
+#endif
+
+#endif /* RTL2830_H */
diff --git a/drivers/media/dvb-frontends/rtl2830_priv.h b/drivers/media/dvb-frontends/rtl2830_priv.h
new file mode 100644
index 0000000..9b20557
--- /dev/null
+++ b/drivers/media/dvb-frontends/rtl2830_priv.h
@@ -0,0 +1,58 @@
+/*
+ * Realtek RTL2830 DVB-T demodulator driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RTL2830_PRIV_H
+#define RTL2830_PRIV_H
+
+#include "dvb_frontend.h"
+#include "dvb_math.h"
+#include "rtl2830.h"
+
+#define LOG_PREFIX "rtl2830"
+
+#undef dbg
+#define dbg(f, arg...) \
+	if (rtl2830_debug) \
+		printk(KERN_INFO            LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct rtl2830_priv {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend fe;
+	struct rtl2830_config cfg;
+	struct i2c_adapter tuner_i2c_adapter;
+
+	bool sleeping;
+
+	u8 page; /* active register page */
+};
+
+struct rtl2830_reg_val_mask {
+	u16 reg;
+	u8  val;
+	u8  mask;
+};
+
+#endif /* RTL2830_PRIV_H */
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
new file mode 100644
index 0000000..28269cc
--- /dev/null
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -0,0 +1,789 @@
+/*
+ * Realtek RTL2832 DVB-T demodulator driver
+ *
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License along
+ *	with this program; if not, write to the Free Software Foundation, Inc.,
+ *	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "rtl2832_priv.h"
+#include <linux/bitops.h>
+
+int rtl2832_debug;
+module_param_named(debug, rtl2832_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+#define REG_MASK(b) (BIT(b + 1) - 1)
+
+static const struct rtl2832_reg_entry registers[] = {
+	[DVBT_SOFT_RST]		= {0x1, 0x1,   2, 2},
+	[DVBT_IIC_REPEAT]	= {0x1, 0x1,   3, 3},
+	[DVBT_TR_WAIT_MIN_8K]	= {0x1, 0x88, 11, 2},
+	[DVBT_RSD_BER_FAIL_VAL]	= {0x1, 0x8f, 15, 0},
+	[DVBT_EN_BK_TRK]	= {0x1, 0xa6,  7, 7},
+	[DVBT_AD_EN_REG]	= {0x0, 0x8,   7, 7},
+	[DVBT_AD_EN_REG1]	= {0x0, 0x8,   6, 6},
+	[DVBT_EN_BBIN]		= {0x1, 0xb1,  0, 0},
+	[DVBT_MGD_THD0]		= {0x1, 0x95,  7, 0},
+	[DVBT_MGD_THD1]		= {0x1, 0x96,  7, 0},
+	[DVBT_MGD_THD2]		= {0x1, 0x97,  7, 0},
+	[DVBT_MGD_THD3]		= {0x1, 0x98,  7, 0},
+	[DVBT_MGD_THD4]		= {0x1, 0x99,  7, 0},
+	[DVBT_MGD_THD5]		= {0x1, 0x9a,  7, 0},
+	[DVBT_MGD_THD6]		= {0x1, 0x9b,  7, 0},
+	[DVBT_MGD_THD7]		= {0x1, 0x9c,  7, 0},
+	[DVBT_EN_CACQ_NOTCH]	= {0x1, 0x61,  4, 4},
+	[DVBT_AD_AV_REF]	= {0x0, 0x9,   6, 0},
+	[DVBT_REG_PI]		= {0x0, 0xa,   2, 0},
+	[DVBT_PIP_ON]		= {0x0, 0x21,  3, 3},
+	[DVBT_SCALE1_B92]	= {0x2, 0x92,  7, 0},
+	[DVBT_SCALE1_B93]	= {0x2, 0x93,  7, 0},
+	[DVBT_SCALE1_BA7]	= {0x2, 0xa7,  7, 0},
+	[DVBT_SCALE1_BA9]	= {0x2, 0xa9,  7, 0},
+	[DVBT_SCALE1_BAA]	= {0x2, 0xaa,  7, 0},
+	[DVBT_SCALE1_BAB]	= {0x2, 0xab,  7, 0},
+	[DVBT_SCALE1_BAC]	= {0x2, 0xac,  7, 0},
+	[DVBT_SCALE1_BB0]	= {0x2, 0xb0,  7, 0},
+	[DVBT_SCALE1_BB1]	= {0x2, 0xb1,  7, 0},
+	[DVBT_KB_P1]		= {0x1, 0x64,  3, 1},
+	[DVBT_KB_P2]		= {0x1, 0x64,  6, 4},
+	[DVBT_KB_P3]		= {0x1, 0x65,  2, 0},
+	[DVBT_OPT_ADC_IQ]	= {0x0, 0x6,   5, 4},
+	[DVBT_AD_AVI]		= {0x0, 0x9,   1, 0},
+	[DVBT_AD_AVQ]		= {0x0, 0x9,   3, 2},
+	[DVBT_K1_CR_STEP12]	= {0x2, 0xad,  9, 4},
+	[DVBT_TRK_KS_P2]	= {0x1, 0x6f,  2, 0},
+	[DVBT_TRK_KS_I2]	= {0x1, 0x70,  5, 3},
+	[DVBT_TR_THD_SET2]	= {0x1, 0x72,  3, 0},
+	[DVBT_TRK_KC_P2]	= {0x1, 0x73,  5, 3},
+	[DVBT_TRK_KC_I2]	= {0x1, 0x75,  2, 0},
+	[DVBT_CR_THD_SET2]	= {0x1, 0x76,  7, 6},
+	[DVBT_PSET_IFFREQ]	= {0x1, 0x19, 21, 0},
+	[DVBT_SPEC_INV]		= {0x1, 0x15,  0, 0},
+	[DVBT_RSAMP_RATIO]	= {0x1, 0x9f, 27, 2},
+	[DVBT_CFREQ_OFF_RATIO]	= {0x1, 0x9d, 23, 4},
+	[DVBT_FSM_STAGE]	= {0x3, 0x51,  6, 3},
+	[DVBT_RX_CONSTEL]	= {0x3, 0x3c,  3, 2},
+	[DVBT_RX_HIER]		= {0x3, 0x3c,  6, 4},
+	[DVBT_RX_C_RATE_LP]	= {0x3, 0x3d,  2, 0},
+	[DVBT_RX_C_RATE_HP]	= {0x3, 0x3d,  5, 3},
+	[DVBT_GI_IDX]		= {0x3, 0x51,  1, 0},
+	[DVBT_FFT_MODE_IDX]	= {0x3, 0x51,  2, 2},
+	[DVBT_RSD_BER_EST]	= {0x3, 0x4e, 15, 0},
+	[DVBT_CE_EST_EVM]	= {0x4, 0xc,  15, 0},
+	[DVBT_RF_AGC_VAL]	= {0x3, 0x5b, 13, 0},
+	[DVBT_IF_AGC_VAL]	= {0x3, 0x59, 13, 0},
+	[DVBT_DAGC_VAL]		= {0x3, 0x5,   7, 0},
+	[DVBT_SFREQ_OFF]	= {0x3, 0x18, 13, 0},
+	[DVBT_CFREQ_OFF]	= {0x3, 0x5f, 17, 0},
+	[DVBT_POLAR_RF_AGC]	= {0x0, 0xe,   1, 1},
+	[DVBT_POLAR_IF_AGC]	= {0x0, 0xe,   0, 0},
+	[DVBT_AAGC_HOLD]	= {0x1, 0x4,   5, 5},
+	[DVBT_EN_RF_AGC]	= {0x1, 0x4,   6, 6},
+	[DVBT_EN_IF_AGC]	= {0x1, 0x4,   7, 7},
+	[DVBT_IF_AGC_MIN]	= {0x1, 0x8,   7, 0},
+	[DVBT_IF_AGC_MAX]	= {0x1, 0x9,   7, 0},
+	[DVBT_RF_AGC_MIN]	= {0x1, 0xa,   7, 0},
+	[DVBT_RF_AGC_MAX]	= {0x1, 0xb,   7, 0},
+	[DVBT_IF_AGC_MAN]	= {0x1, 0xc,   6, 6},
+	[DVBT_IF_AGC_MAN_VAL]	= {0x1, 0xc,  13, 0},
+	[DVBT_RF_AGC_MAN]	= {0x1, 0xe,   6, 6},
+	[DVBT_RF_AGC_MAN_VAL]	= {0x1, 0xe,  13, 0},
+	[DVBT_DAGC_TRG_VAL]	= {0x1, 0x12,  7, 0},
+	[DVBT_AGC_TARG_VAL_0]	= {0x1, 0x2,   0, 0},
+	[DVBT_AGC_TARG_VAL_8_1]	= {0x1, 0x3,   7, 0},
+	[DVBT_AAGC_LOOP_GAIN]	= {0x1, 0xc7,  5, 1},
+	[DVBT_LOOP_GAIN2_3_0]	= {0x1, 0x4,   4, 1},
+	[DVBT_LOOP_GAIN2_4]	= {0x1, 0x5,   7, 7},
+	[DVBT_LOOP_GAIN3]	= {0x1, 0xc8,  4, 0},
+	[DVBT_VTOP1]		= {0x1, 0x6,   5, 0},
+	[DVBT_VTOP2]		= {0x1, 0xc9,  5, 0},
+	[DVBT_VTOP3]		= {0x1, 0xca,  5, 0},
+	[DVBT_KRF1]		= {0x1, 0xcb,  7, 0},
+	[DVBT_KRF2]		= {0x1, 0x7,   7, 0},
+	[DVBT_KRF3]		= {0x1, 0xcd,  7, 0},
+	[DVBT_KRF4]		= {0x1, 0xce,  7, 0},
+	[DVBT_EN_GI_PGA]	= {0x1, 0xe5,  0, 0},
+	[DVBT_THD_LOCK_UP]	= {0x1, 0xd9,  8, 0},
+	[DVBT_THD_LOCK_DW]	= {0x1, 0xdb,  8, 0},
+	[DVBT_THD_UP1]		= {0x1, 0xdd,  7, 0},
+	[DVBT_THD_DW1]		= {0x1, 0xde,  7, 0},
+	[DVBT_INTER_CNT_LEN]	= {0x1, 0xd8,  3, 0},
+	[DVBT_GI_PGA_STATE]	= {0x1, 0xe6,  3, 3},
+	[DVBT_EN_AGC_PGA]	= {0x1, 0xd7,  0, 0},
+	[DVBT_CKOUTPAR]		= {0x1, 0x7b,  5, 5},
+	[DVBT_CKOUT_PWR]	= {0x1, 0x7b,  6, 6},
+	[DVBT_SYNC_DUR]		= {0x1, 0x7b,  7, 7},
+	[DVBT_ERR_DUR]		= {0x1, 0x7c,  0, 0},
+	[DVBT_SYNC_LVL]		= {0x1, 0x7c,  1, 1},
+	[DVBT_ERR_LVL]		= {0x1, 0x7c,  2, 2},
+	[DVBT_VAL_LVL]		= {0x1, 0x7c,  3, 3},
+	[DVBT_SERIAL]		= {0x1, 0x7c,  4, 4},
+	[DVBT_SER_LSB]		= {0x1, 0x7c,  5, 5},
+	[DVBT_CDIV_PH0]		= {0x1, 0x7d,  3, 0},
+	[DVBT_CDIV_PH1]		= {0x1, 0x7d,  7, 4},
+	[DVBT_MPEG_IO_OPT_2_2]	= {0x0, 0x6,   7, 7},
+	[DVBT_MPEG_IO_OPT_1_0]	= {0x0, 0x7,   7, 6},
+	[DVBT_CKOUTPAR_PIP]	= {0x0, 0xb7,  4, 4},
+	[DVBT_CKOUT_PWR_PIP]	= {0x0, 0xb7,  3, 3},
+	[DVBT_SYNC_LVL_PIP]	= {0x0, 0xb7,  2, 2},
+	[DVBT_ERR_LVL_PIP]	= {0x0, 0xb7,  1, 1},
+	[DVBT_VAL_LVL_PIP]	= {0x0, 0xb7,  0, 0},
+	[DVBT_CKOUTPAR_PID]	= {0x0, 0xb9,  4, 4},
+	[DVBT_CKOUT_PWR_PID]	= {0x0, 0xb9,  3, 3},
+	[DVBT_SYNC_LVL_PID]	= {0x0, 0xb9,  2, 2},
+	[DVBT_ERR_LVL_PID]	= {0x0, 0xb9,  1, 1},
+	[DVBT_VAL_LVL_PID]	= {0x0, 0xb9,  0, 0},
+	[DVBT_SM_PASS]		= {0x1, 0x93, 11, 0},
+	[DVBT_AD7_SETTING]	= {0x0, 0x11, 15, 0},
+	[DVBT_RSSI_R]		= {0x3, 0x1,   6, 0},
+	[DVBT_ACI_DET_IND]	= {0x3, 0x12,  0, 0},
+	[DVBT_REG_MON]		= {0x0, 0xd,   1, 0},
+	[DVBT_REG_MONSEL]	= {0x0, 0xd,   2, 2},
+	[DVBT_REG_GPE]		= {0x0, 0xd,   7, 7},
+	[DVBT_REG_GPO]		= {0x0, 0x10,  0, 0},
+	[DVBT_REG_4MSEL]	= {0x0, 0x13,  0, 0},
+};
+
+/* write multiple hardware registers */
+static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
+{
+	int ret;
+	u8 buf[1+len];
+	struct i2c_msg msg[1] = {
+		{
+			.addr = priv->cfg.i2c_addr,
+			.flags = 0,
+			.len = 1+len,
+			.buf = buf,
+		}
+	};
+
+	buf[0] = reg;
+	memcpy(&buf[1], val, len);
+
+	ret = i2c_transfer(priv->i2c, msg, 1);
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+/* read multiple hardware registers */
+static int rtl2832_rd(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
+{
+	int ret;
+	struct i2c_msg msg[2] = {
+		{
+			.addr = priv->cfg.i2c_addr,
+			.flags = 0,
+			.len = 1,
+			.buf = &reg,
+		}, {
+			.addr = priv->cfg.i2c_addr,
+			.flags = I2C_M_RD,
+			.len = len,
+			.buf = val,
+		}
+	};
+
+	ret = i2c_transfer(priv->i2c, msg, 2);
+	if (ret == 2) {
+		ret = 0;
+	} else {
+		warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
+		ret = -EREMOTEIO;
+}
+return ret;
+}
+
+/* write multiple registers */
+static int rtl2832_wr_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val,
+	int len)
+{
+	int ret;
+
+
+	/* switch bank if needed */
+	if (page != priv->page) {
+		ret = rtl2832_wr(priv, 0x00, &page, 1);
+		if (ret)
+			return ret;
+
+		priv->page = page;
+}
+
+return rtl2832_wr(priv, reg, val, len);
+}
+
+/* read multiple registers */
+static int rtl2832_rd_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val,
+	int len)
+{
+	int ret;
+
+	/* switch bank if needed */
+	if (page != priv->page) {
+		ret = rtl2832_wr(priv, 0x00, &page, 1);
+		if (ret)
+			return ret;
+
+		priv->page = page;
+	}
+
+	return rtl2832_rd(priv, reg, val, len);
+}
+
+#if 0 /* currently not used */
+/* write single register */
+static int rtl2832_wr_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 val)
+{
+	return rtl2832_wr_regs(priv, reg, page, &val, 1);
+}
+#endif
+
+/* read single register */
+static int rtl2832_rd_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val)
+{
+	return rtl2832_rd_regs(priv, reg, page, val, 1);
+}
+
+int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val)
+{
+	int ret;
+
+	u8 reg_start_addr;
+	u8 msb, lsb;
+	u8 page;
+	u8 reading[4];
+	u32 reading_tmp;
+	int i;
+
+	u8 len;
+	u32 mask;
+
+	reg_start_addr = registers[reg].start_address;
+	msb = registers[reg].msb;
+	lsb = registers[reg].lsb;
+	page = registers[reg].page;
+
+	len = (msb >> 3) + 1;
+	mask = REG_MASK(msb - lsb);
+
+	ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
+	if (ret)
+		goto err;
+
+	reading_tmp = 0;
+	for (i = 0; i < len; i++)
+		reading_tmp |= reading[i] << ((len - 1 - i) * 8);
+
+	*val = (reading_tmp >> lsb) & mask;
+
+	return ret;
+
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+
+}
+
+int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val)
+{
+	int ret, i;
+	u8 len;
+	u8 reg_start_addr;
+	u8 msb, lsb;
+	u8 page;
+	u32 mask;
+
+
+	u8 reading[4];
+	u8 writing[4];
+	u32 reading_tmp;
+	u32 writing_tmp;
+
+
+	reg_start_addr = registers[reg].start_address;
+	msb = registers[reg].msb;
+	lsb = registers[reg].lsb;
+	page = registers[reg].page;
+
+	len = (msb >> 3) + 1;
+	mask = REG_MASK(msb - lsb);
+
+
+	ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
+	if (ret)
+		goto err;
+
+	reading_tmp = 0;
+	for (i = 0; i < len; i++)
+		reading_tmp |= reading[i] << ((len - 1 - i) * 8);
+
+	writing_tmp = reading_tmp & ~(mask << lsb);
+	writing_tmp |= ((val & mask) << lsb);
+
+
+	for (i = 0; i < len; i++)
+		writing[i] = (writing_tmp >> ((len - 1 - i) * 8)) & 0xff;
+
+	ret = rtl2832_wr_regs(priv, reg_start_addr, page, &writing[0], len);
+	if (ret)
+		goto err;
+
+	return ret;
+
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+
+}
+
+
+static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	int ret;
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+
+	dbg("%s: enable=%d", __func__, enable);
+
+	/* gate already open or close */
+	if (priv->i2c_gate_state == enable)
+		return 0;
+
+	ret = rtl2832_wr_demod_reg(priv, DVBT_IIC_REPEAT, (enable ? 0x1 : 0x0));
+	if (ret)
+		goto err;
+
+	priv->i2c_gate_state = enable;
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+
+
+static int rtl2832_init(struct dvb_frontend *fe)
+{
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+	int i, ret;
+
+	u8 en_bbin;
+	u64 pset_iffreq;
+
+	/* initialization values for the demodulator registers */
+	struct rtl2832_reg_value rtl2832_initial_regs[] = {
+		{DVBT_AD_EN_REG,		0x1},
+		{DVBT_AD_EN_REG1,		0x1},
+		{DVBT_RSD_BER_FAIL_VAL,		0x2800},
+		{DVBT_MGD_THD0,			0x10},
+		{DVBT_MGD_THD1,			0x20},
+		{DVBT_MGD_THD2,			0x20},
+		{DVBT_MGD_THD3,			0x40},
+		{DVBT_MGD_THD4,			0x22},
+		{DVBT_MGD_THD5,			0x32},
+		{DVBT_MGD_THD6,			0x37},
+		{DVBT_MGD_THD7,			0x39},
+		{DVBT_EN_BK_TRK,		0x0},
+		{DVBT_EN_CACQ_NOTCH,		0x0},
+		{DVBT_AD_AV_REF,		0x2a},
+		{DVBT_REG_PI,			0x6},
+		{DVBT_PIP_ON,			0x0},
+		{DVBT_CDIV_PH0,			0x8},
+		{DVBT_CDIV_PH1,			0x8},
+		{DVBT_SCALE1_B92,		0x4},
+		{DVBT_SCALE1_B93,		0xb0},
+		{DVBT_SCALE1_BA7,		0x78},
+		{DVBT_SCALE1_BA9,		0x28},
+		{DVBT_SCALE1_BAA,		0x59},
+		{DVBT_SCALE1_BAB,		0x83},
+		{DVBT_SCALE1_BAC,		0xd4},
+		{DVBT_SCALE1_BB0,		0x65},
+		{DVBT_SCALE1_BB1,		0x43},
+		{DVBT_KB_P1,			0x1},
+		{DVBT_KB_P2,			0x4},
+		{DVBT_KB_P3,			0x7},
+		{DVBT_K1_CR_STEP12,		0xa},
+		{DVBT_REG_GPE,			0x1},
+		{DVBT_SERIAL,			0x0},
+		{DVBT_CDIV_PH0,			0x9},
+		{DVBT_CDIV_PH1,			0x9},
+		{DVBT_MPEG_IO_OPT_2_2,		0x0},
+		{DVBT_MPEG_IO_OPT_1_0,		0x0},
+		{DVBT_TRK_KS_P2,		0x4},
+		{DVBT_TRK_KS_I2,		0x7},
+		{DVBT_TR_THD_SET2,		0x6},
+		{DVBT_TRK_KC_I2,		0x5},
+		{DVBT_CR_THD_SET2,		0x1},
+		{DVBT_SPEC_INV,			0x0},
+		{DVBT_DAGC_TRG_VAL,		0x5a},
+		{DVBT_AGC_TARG_VAL_0,		0x0},
+		{DVBT_AGC_TARG_VAL_8_1,		0x5a},
+		{DVBT_AAGC_LOOP_GAIN,		0x16},
+		{DVBT_LOOP_GAIN2_3_0,		0x6},
+		{DVBT_LOOP_GAIN2_4,		0x1},
+		{DVBT_LOOP_GAIN3,		0x16},
+		{DVBT_VTOP1,			0x35},
+		{DVBT_VTOP2,			0x21},
+		{DVBT_VTOP3,			0x21},
+		{DVBT_KRF1,			0x0},
+		{DVBT_KRF2,			0x40},
+		{DVBT_KRF3,			0x10},
+		{DVBT_KRF4,			0x10},
+		{DVBT_IF_AGC_MIN,		0x80},
+		{DVBT_IF_AGC_MAX,		0x7f},
+		{DVBT_RF_AGC_MIN,		0x80},
+		{DVBT_RF_AGC_MAX,		0x7f},
+		{DVBT_POLAR_RF_AGC,		0x0},
+		{DVBT_POLAR_IF_AGC,		0x0},
+		{DVBT_AD7_SETTING,		0xe9bf},
+		{DVBT_EN_GI_PGA,		0x0},
+		{DVBT_THD_LOCK_UP,		0x0},
+		{DVBT_THD_LOCK_DW,		0x0},
+		{DVBT_THD_UP1,			0x11},
+		{DVBT_THD_DW1,			0xef},
+		{DVBT_INTER_CNT_LEN,		0xc},
+		{DVBT_GI_PGA_STATE,		0x0},
+		{DVBT_EN_AGC_PGA,		0x1},
+		{DVBT_IF_AGC_MAN,		0x0},
+	};
+
+
+	dbg("%s", __func__);
+
+	en_bbin = (priv->cfg.if_dvbt == 0 ? 0x1 : 0x0);
+
+	/*
+	* PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22)
+	*		/ CrystalFreqHz)
+	*/
+	pset_iffreq = priv->cfg.if_dvbt % priv->cfg.xtal;
+	pset_iffreq *= 0x400000;
+	pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal);
+	pset_iffreq = pset_iffreq & 0x3fffff;
+
+
+
+	for (i = 0; i < ARRAY_SIZE(rtl2832_initial_regs); i++) {
+		ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs[i].reg,
+			rtl2832_initial_regs[i].value);
+		if (ret)
+			goto err;
+	}
+
+	/* if frequency settings */
+	ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin);
+		if (ret)
+			goto err;
+
+	ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq);
+		if (ret)
+			goto err;
+
+	priv->sleeping = false;
+
+	return ret;
+
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2832_sleep(struct dvb_frontend *fe)
+{
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+
+	dbg("%s", __func__);
+	priv->sleeping = true;
+	return 0;
+}
+
+int rtl2832_get_tune_settings(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *s)
+{
+	dbg("%s", __func__);
+	s->min_delay_ms = 1000;
+	s->step_size = fe->ops.info.frequency_stepsize * 2;
+	s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+	return 0;
+}
+
+static int rtl2832_set_frontend(struct dvb_frontend *fe)
+{
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i, j;
+	u64 bw_mode, num, num2;
+	u32 resamp_ratio, cfreq_off_ratio;
+
+
+	static u8 bw_params[3][32] = {
+	/* 6 MHz bandwidth */
+		{
+		0xf5, 0xff, 0x15, 0x38, 0x5d, 0x6d, 0x52, 0x07, 0xfa, 0x2f,
+		0x53, 0xf5, 0x3f, 0xca, 0x0b, 0x91, 0xea, 0x30, 0x63, 0xb2,
+		0x13, 0xda, 0x0b, 0xc4, 0x18, 0x7e, 0x16, 0x66, 0x08, 0x67,
+		0x19, 0xe0,
+		},
+
+	/*  7 MHz bandwidth */
+		{
+		0xe7, 0xcc, 0xb5, 0xba, 0xe8, 0x2f, 0x67, 0x61, 0x00, 0xaf,
+		0x86, 0xf2, 0xbf, 0x59, 0x04, 0x11, 0xb6, 0x33, 0xa4, 0x30,
+		0x15, 0x10, 0x0a, 0x42, 0x18, 0xf8, 0x17, 0xd9, 0x07, 0x22,
+		0x19, 0x10,
+		},
+
+	/*  8 MHz bandwidth */
+		{
+		0x09, 0xf6, 0xd2, 0xa7, 0x9a, 0xc9, 0x27, 0x77, 0x06, 0xbf,
+		0xec, 0xf4, 0x4f, 0x0b, 0xfc, 0x01, 0x63, 0x35, 0x54, 0xa7,
+		0x16, 0x66, 0x08, 0xb4, 0x19, 0x6e, 0x19, 0x65, 0x05, 0xc8,
+		0x19, 0xe0,
+		},
+	};
+
+
+	dbg("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__,
+		c->frequency, c->bandwidth_hz, c->inversion);
+
+
+	/* program tuner */
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+
+
+	switch (c->bandwidth_hz) {
+	case 6000000:
+		i = 0;
+		bw_mode = 48000000;
+		break;
+	case 7000000:
+		i = 1;
+		bw_mode = 56000000;
+		break;
+	case 8000000:
+		i = 2;
+		bw_mode = 64000000;
+		break;
+	default:
+		dbg("invalid bandwidth");
+		return -EINVAL;
+	}
+
+	for (j = 0; j < sizeof(bw_params[0]); j++) {
+		ret = rtl2832_wr_regs(priv, 0x1c+j, 1, &bw_params[i][j], 1);
+		if (ret)
+			goto err;
+	}
+
+	/* calculate and set resample ratio
+	* RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22)
+	*	/ ConstWithBandwidthMode)
+	*/
+	num = priv->cfg.xtal * 7;
+	num *= 0x400000;
+	num = div_u64(num, bw_mode);
+	resamp_ratio =  num & 0x3ffffff;
+	ret = rtl2832_wr_demod_reg(priv, DVBT_RSAMP_RATIO, resamp_ratio);
+	if (ret)
+		goto err;
+
+	/* calculate and set cfreq off ratio
+	* CFREQ_OFF_RATIO = - floor(ConstWithBandwidthMode * pow(2, 20)
+	*	/ (CrystalFreqHz * 7))
+	*/
+	num = bw_mode << 20;
+	num2 = priv->cfg.xtal * 7;
+	num = div_u64(num, num2);
+	num = -num;
+	cfreq_off_ratio = num & 0xfffff;
+	ret = rtl2832_wr_demod_reg(priv, DVBT_CFREQ_OFF_RATIO, cfreq_off_ratio);
+	if (ret)
+		goto err;
+
+
+	/* soft reset */
+	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
+	if (ret)
+		goto err;
+
+	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	info("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2832_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+	int ret;
+	u32 tmp;
+	*status = 0;
+
+
+	dbg("%s", __func__);
+	if (priv->sleeping)
+		return 0;
+
+	ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &tmp);
+	if (ret)
+		goto err;
+
+	if (tmp == 11) {
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+	}
+	/* TODO find out if this is also true for rtl2832? */
+	/*else if (tmp == 10) {
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI;
+	}*/
+
+	return ret;
+err:
+	info("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	*snr = 0;
+	return 0;
+}
+
+static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	*ber = 0;
+	return 0;
+}
+
+static int rtl2832_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	*ucblocks = 0;
+	return 0;
+}
+
+
+static int rtl2832_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	*strength = 0;
+	return 0;
+}
+
+static struct dvb_frontend_ops rtl2832_ops;
+
+static void rtl2832_release(struct dvb_frontend *fe)
+{
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+
+	dbg("%s", __func__);
+	kfree(priv);
+}
+
+struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg,
+	struct i2c_adapter *i2c)
+{
+	struct rtl2832_priv *priv = NULL;
+	int ret = 0;
+	u8 tmp;
+
+	dbg("%s", __func__);
+
+	/* allocate memory for the internal state */
+	priv = kzalloc(sizeof(struct rtl2832_priv), GFP_KERNEL);
+	if (priv == NULL)
+		goto err;
+
+	/* setup the priv */
+	priv->i2c = i2c;
+	priv->tuner = cfg->tuner;
+	memcpy(&priv->cfg, cfg, sizeof(struct rtl2832_config));
+
+	/* check if the demod is there */
+	ret = rtl2832_rd_reg(priv, 0x00, 0x0, &tmp);
+	if (ret)
+		goto err;
+
+	/* create dvb_frontend */
+	memcpy(&priv->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
+	priv->fe.demodulator_priv = priv;
+
+	/* TODO implement sleep mode */
+	priv->sleeping = true;
+
+	return &priv->fe;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	kfree(priv);
+	return NULL;
+}
+EXPORT_SYMBOL(rtl2832_attach);
+
+static struct dvb_frontend_ops rtl2832_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "Realtek RTL2832 (DVB-T)",
+		.frequency_min	  = 174000000,
+		.frequency_max	  = 862000000,
+		.frequency_stepsize = 166667,
+		.caps = FE_CAN_FEC_1_2 |
+			FE_CAN_FEC_2_3 |
+			FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 |
+			FE_CAN_FEC_7_8 |
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK |
+			FE_CAN_QAM_16 |
+			FE_CAN_QAM_64 |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_RECOVER |
+			FE_CAN_MUTE_TS
+	 },
+
+	.release = rtl2832_release,
+
+	.init = rtl2832_init,
+	.sleep = rtl2832_sleep,
+
+	.get_tune_settings = rtl2832_get_tune_settings,
+
+	.set_frontend = rtl2832_set_frontend,
+
+	.read_status = rtl2832_read_status,
+	.read_snr = rtl2832_read_snr,
+	.read_ber = rtl2832_read_ber,
+	.read_ucblocks = rtl2832_read_ucblocks,
+	.read_signal_strength = rtl2832_read_signal_strength,
+	.i2c_gate_ctrl = rtl2832_i2c_gate_ctrl,
+};
+
+MODULE_AUTHOR("Thomas Mair <mair.thomas86@gmail.com>");
+MODULE_DESCRIPTION("Realtek RTL2832 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.5");
diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h
new file mode 100644
index 0000000..d94dc9a
--- /dev/null
+++ b/drivers/media/dvb-frontends/rtl2832.h
@@ -0,0 +1,74 @@
+/*
+ * Realtek RTL2832 DVB-T demodulator driver
+ *
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License along
+ *	with this program; if not, write to the Free Software Foundation, Inc.,
+ *	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RTL2832_H
+#define RTL2832_H
+
+#include <linux/dvb/frontend.h>
+
+struct rtl2832_config {
+	/*
+	 * Demodulator I2C address.
+	 */
+	u8 i2c_addr;
+
+	/*
+	 * Xtal frequency.
+	 * Hz
+	 * 4000000, 16000000, 25000000, 28800000
+	 */
+	u32 xtal;
+
+	/*
+	 * IFs for all used modes.
+	 * Hz
+	 * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000
+	 */
+	u32 if_dvbt;
+
+	/*
+	 */
+	u8 tuner;
+};
+
+
+#if defined(CONFIG_DVB_RTL2832) || \
+	(defined(CONFIG_DVB_RTL2832_MODULE) && defined(MODULE))
+extern struct dvb_frontend *rtl2832_attach(
+	const struct rtl2832_config *cfg,
+	struct i2c_adapter *i2c
+);
+
+extern struct i2c_adapter *rtl2832_get_tuner_i2c_adapter(
+	struct dvb_frontend *fe
+);
+#else
+static inline struct dvb_frontend *rtl2832_attach(
+	const struct rtl2832_config *config,
+	struct i2c_adapter *i2c
+)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+
+#endif /* RTL2832_H */
diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h
new file mode 100644
index 0000000..0ce9502
--- /dev/null
+++ b/drivers/media/dvb-frontends/rtl2832_priv.h
@@ -0,0 +1,260 @@
+/*
+ * Realtek RTL2832 DVB-T demodulator driver
+ *
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License along
+ *	with this program; if not, write to the Free Software Foundation, Inc.,
+ *	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RTL2832_PRIV_H
+#define RTL2832_PRIV_H
+
+#include "dvb_frontend.h"
+#include "rtl2832.h"
+
+#define LOG_PREFIX "rtl2832"
+
+#undef dbg
+#define dbg(f, arg...) \
+do { \
+	if (rtl2832_debug)  \
+		printk(KERN_INFO     LOG_PREFIX": " f "\n" , ## arg); \
+} while (0)
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct rtl2832_priv {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend fe;
+	struct rtl2832_config cfg;
+
+	bool i2c_gate_state;
+	bool sleeping;
+
+	u8 tuner;
+	u8 page; /* active register page */
+};
+
+struct rtl2832_reg_entry {
+	u8 page;
+	u8 start_address;
+	u8 msb;
+	u8 lsb;
+};
+
+struct rtl2832_reg_value {
+	int reg;
+	u32 value;
+};
+
+
+/* Demod register bit names */
+enum DVBT_REG_BIT_NAME {
+	DVBT_SOFT_RST,
+	DVBT_IIC_REPEAT,
+	DVBT_TR_WAIT_MIN_8K,
+	DVBT_RSD_BER_FAIL_VAL,
+	DVBT_EN_BK_TRK,
+	DVBT_REG_PI,
+	DVBT_REG_PFREQ_1_0,
+	DVBT_PD_DA8,
+	DVBT_LOCK_TH,
+	DVBT_BER_PASS_SCAL,
+	DVBT_CE_FFSM_BYPASS,
+	DVBT_ALPHAIIR_N,
+	DVBT_ALPHAIIR_DIF,
+	DVBT_EN_TRK_SPAN,
+	DVBT_LOCK_TH_LEN,
+	DVBT_CCI_THRE,
+	DVBT_CCI_MON_SCAL,
+	DVBT_CCI_M0,
+	DVBT_CCI_M1,
+	DVBT_CCI_M2,
+	DVBT_CCI_M3,
+	DVBT_SPEC_INIT_0,
+	DVBT_SPEC_INIT_1,
+	DVBT_SPEC_INIT_2,
+	DVBT_AD_EN_REG,
+	DVBT_AD_EN_REG1,
+	DVBT_EN_BBIN,
+	DVBT_MGD_THD0,
+	DVBT_MGD_THD1,
+	DVBT_MGD_THD2,
+	DVBT_MGD_THD3,
+	DVBT_MGD_THD4,
+	DVBT_MGD_THD5,
+	DVBT_MGD_THD6,
+	DVBT_MGD_THD7,
+	DVBT_EN_CACQ_NOTCH,
+	DVBT_AD_AV_REF,
+	DVBT_PIP_ON,
+	DVBT_SCALE1_B92,
+	DVBT_SCALE1_B93,
+	DVBT_SCALE1_BA7,
+	DVBT_SCALE1_BA9,
+	DVBT_SCALE1_BAA,
+	DVBT_SCALE1_BAB,
+	DVBT_SCALE1_BAC,
+	DVBT_SCALE1_BB0,
+	DVBT_SCALE1_BB1,
+	DVBT_KB_P1,
+	DVBT_KB_P2,
+	DVBT_KB_P3,
+	DVBT_OPT_ADC_IQ,
+	DVBT_AD_AVI,
+	DVBT_AD_AVQ,
+	DVBT_K1_CR_STEP12,
+	DVBT_TRK_KS_P2,
+	DVBT_TRK_KS_I2,
+	DVBT_TR_THD_SET2,
+	DVBT_TRK_KC_P2,
+	DVBT_TRK_KC_I2,
+	DVBT_CR_THD_SET2,
+	DVBT_PSET_IFFREQ,
+	DVBT_SPEC_INV,
+	DVBT_BW_INDEX,
+	DVBT_RSAMP_RATIO,
+	DVBT_CFREQ_OFF_RATIO,
+	DVBT_FSM_STAGE,
+	DVBT_RX_CONSTEL,
+	DVBT_RX_HIER,
+	DVBT_RX_C_RATE_LP,
+	DVBT_RX_C_RATE_HP,
+	DVBT_GI_IDX,
+	DVBT_FFT_MODE_IDX,
+	DVBT_RSD_BER_EST,
+	DVBT_CE_EST_EVM,
+	DVBT_RF_AGC_VAL,
+	DVBT_IF_AGC_VAL,
+	DVBT_DAGC_VAL,
+	DVBT_SFREQ_OFF,
+	DVBT_CFREQ_OFF,
+	DVBT_POLAR_RF_AGC,
+	DVBT_POLAR_IF_AGC,
+	DVBT_AAGC_HOLD,
+	DVBT_EN_RF_AGC,
+	DVBT_EN_IF_AGC,
+	DVBT_IF_AGC_MIN,
+	DVBT_IF_AGC_MAX,
+	DVBT_RF_AGC_MIN,
+	DVBT_RF_AGC_MAX,
+	DVBT_IF_AGC_MAN,
+	DVBT_IF_AGC_MAN_VAL,
+	DVBT_RF_AGC_MAN,
+	DVBT_RF_AGC_MAN_VAL,
+	DVBT_DAGC_TRG_VAL,
+	DVBT_AGC_TARG_VAL,
+	DVBT_LOOP_GAIN_3_0,
+	DVBT_LOOP_GAIN_4,
+	DVBT_VTOP,
+	DVBT_KRF,
+	DVBT_AGC_TARG_VAL_0,
+	DVBT_AGC_TARG_VAL_8_1,
+	DVBT_AAGC_LOOP_GAIN,
+	DVBT_LOOP_GAIN2_3_0,
+	DVBT_LOOP_GAIN2_4,
+	DVBT_LOOP_GAIN3,
+	DVBT_VTOP1,
+	DVBT_VTOP2,
+	DVBT_VTOP3,
+	DVBT_KRF1,
+	DVBT_KRF2,
+	DVBT_KRF3,
+	DVBT_KRF4,
+	DVBT_EN_GI_PGA,
+	DVBT_THD_LOCK_UP,
+	DVBT_THD_LOCK_DW,
+	DVBT_THD_UP1,
+	DVBT_THD_DW1,
+	DVBT_INTER_CNT_LEN,
+	DVBT_GI_PGA_STATE,
+	DVBT_EN_AGC_PGA,
+	DVBT_CKOUTPAR,
+	DVBT_CKOUT_PWR,
+	DVBT_SYNC_DUR,
+	DVBT_ERR_DUR,
+	DVBT_SYNC_LVL,
+	DVBT_ERR_LVL,
+	DVBT_VAL_LVL,
+	DVBT_SERIAL,
+	DVBT_SER_LSB,
+	DVBT_CDIV_PH0,
+	DVBT_CDIV_PH1,
+	DVBT_MPEG_IO_OPT_2_2,
+	DVBT_MPEG_IO_OPT_1_0,
+	DVBT_CKOUTPAR_PIP,
+	DVBT_CKOUT_PWR_PIP,
+	DVBT_SYNC_LVL_PIP,
+	DVBT_ERR_LVL_PIP,
+	DVBT_VAL_LVL_PIP,
+	DVBT_CKOUTPAR_PID,
+	DVBT_CKOUT_PWR_PID,
+	DVBT_SYNC_LVL_PID,
+	DVBT_ERR_LVL_PID,
+	DVBT_VAL_LVL_PID,
+	DVBT_SM_PASS,
+	DVBT_UPDATE_REG_2,
+	DVBT_BTHD_P3,
+	DVBT_BTHD_D3,
+	DVBT_FUNC4_REG0,
+	DVBT_FUNC4_REG1,
+	DVBT_FUNC4_REG2,
+	DVBT_FUNC4_REG3,
+	DVBT_FUNC4_REG4,
+	DVBT_FUNC4_REG5,
+	DVBT_FUNC4_REG6,
+	DVBT_FUNC4_REG7,
+	DVBT_FUNC4_REG8,
+	DVBT_FUNC4_REG9,
+	DVBT_FUNC4_REG10,
+	DVBT_FUNC5_REG0,
+	DVBT_FUNC5_REG1,
+	DVBT_FUNC5_REG2,
+	DVBT_FUNC5_REG3,
+	DVBT_FUNC5_REG4,
+	DVBT_FUNC5_REG5,
+	DVBT_FUNC5_REG6,
+	DVBT_FUNC5_REG7,
+	DVBT_FUNC5_REG8,
+	DVBT_FUNC5_REG9,
+	DVBT_FUNC5_REG10,
+	DVBT_FUNC5_REG11,
+	DVBT_FUNC5_REG12,
+	DVBT_FUNC5_REG13,
+	DVBT_FUNC5_REG14,
+	DVBT_FUNC5_REG15,
+	DVBT_FUNC5_REG16,
+	DVBT_FUNC5_REG17,
+	DVBT_FUNC5_REG18,
+	DVBT_AD7_SETTING,
+	DVBT_RSSI_R,
+	DVBT_ACI_DET_IND,
+	DVBT_REG_MON,
+	DVBT_REG_MONSEL,
+	DVBT_REG_GPE,
+	DVBT_REG_GPO,
+	DVBT_REG_4MSEL,
+	DVBT_TEST_REG_1,
+	DVBT_TEST_REG_2,
+	DVBT_TEST_REG_3,
+	DVBT_TEST_REG_4,
+	DVBT_REG_BIT_NAME_ITEM_TERMINATOR,
+};
+
+#endif /* RTL2832_PRIV_H */
diff --git a/drivers/media/dvb-frontends/s5h1409.c b/drivers/media/dvb-frontends/s5h1409.c
new file mode 100644
index 0000000..f71b062
--- /dev/null
+++ b/drivers/media/dvb-frontends/s5h1409.c
@@ -0,0 +1,1029 @@
+/*
+    Samsung S5H1409 VSB/QAM demodulator driver
+
+    Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "s5h1409.h"
+
+struct s5h1409_state {
+
+	struct i2c_adapter *i2c;
+
+	/* configuration settings */
+	const struct s5h1409_config *config;
+
+	struct dvb_frontend frontend;
+
+	/* previous uncorrected block counter */
+	fe_modulation_t current_modulation;
+
+	u32 current_frequency;
+	int if_freq;
+
+	u32 is_qam_locked;
+
+	/* QAM tuning state goes through the following state transitions */
+#define QAM_STATE_UNTUNED 0
+#define QAM_STATE_TUNING_STARTED 1
+#define QAM_STATE_INTERLEAVE_SET 2
+#define QAM_STATE_QAM_OPTIMIZED_L1 3
+#define QAM_STATE_QAM_OPTIMIZED_L2 4
+#define QAM_STATE_QAM_OPTIMIZED_L3 5
+	u8  qam_state;
+};
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+#define dprintk	if (debug) printk
+
+/* Register values to initialise the demod, this will set VSB by default */
+static struct init_tab {
+	u8	reg;
+	u16	data;
+} init_tab[] = {
+	{ 0x00, 0x0071, },
+	{ 0x01, 0x3213, },
+	{ 0x09, 0x0025, },
+	{ 0x1c, 0x001d, },
+	{ 0x1f, 0x002d, },
+	{ 0x20, 0x001d, },
+	{ 0x22, 0x0022, },
+	{ 0x23, 0x0020, },
+	{ 0x29, 0x110f, },
+	{ 0x2a, 0x10b4, },
+	{ 0x2b, 0x10ae, },
+	{ 0x2c, 0x0031, },
+	{ 0x31, 0x010d, },
+	{ 0x32, 0x0100, },
+	{ 0x44, 0x0510, },
+	{ 0x54, 0x0104, },
+	{ 0x58, 0x2222, },
+	{ 0x59, 0x1162, },
+	{ 0x5a, 0x3211, },
+	{ 0x5d, 0x0370, },
+	{ 0x5e, 0x0296, },
+	{ 0x61, 0x0010, },
+	{ 0x63, 0x4a00, },
+	{ 0x65, 0x0800, },
+	{ 0x71, 0x0003, },
+	{ 0x72, 0x0470, },
+	{ 0x81, 0x0002, },
+	{ 0x82, 0x0600, },
+	{ 0x86, 0x0002, },
+	{ 0x8a, 0x2c38, },
+	{ 0x8b, 0x2a37, },
+	{ 0x92, 0x302f, },
+	{ 0x93, 0x3332, },
+	{ 0x96, 0x000c, },
+	{ 0x99, 0x0101, },
+	{ 0x9c, 0x2e37, },
+	{ 0x9d, 0x2c37, },
+	{ 0x9e, 0x2c37, },
+	{ 0xab, 0x0100, },
+	{ 0xac, 0x1003, },
+	{ 0xad, 0x103f, },
+	{ 0xe2, 0x0100, },
+	{ 0xe3, 0x1000, },
+	{ 0x28, 0x1010, },
+	{ 0xb1, 0x000e, },
+};
+
+/* VSB SNR lookup table */
+static struct vsb_snr_tab {
+	u16	val;
+	u16	data;
+} vsb_snr_tab[] = {
+	{  924, 300, },
+	{  923, 300, },
+	{  918, 295, },
+	{  915, 290, },
+	{  911, 285, },
+	{  906, 280, },
+	{  901, 275, },
+	{  896, 270, },
+	{  891, 265, },
+	{  885, 260, },
+	{  879, 255, },
+	{  873, 250, },
+	{  864, 245, },
+	{  858, 240, },
+	{  850, 235, },
+	{  841, 230, },
+	{  832, 225, },
+	{  823, 220, },
+	{  812, 215, },
+	{  802, 210, },
+	{  788, 205, },
+	{  778, 200, },
+	{  767, 195, },
+	{  753, 190, },
+	{  740, 185, },
+	{  725, 180, },
+	{  707, 175, },
+	{  689, 170, },
+	{  671, 165, },
+	{  656, 160, },
+	{  637, 155, },
+	{  616, 150, },
+	{  542, 145, },
+	{  519, 140, },
+	{  507, 135, },
+	{  497, 130, },
+	{  492, 125, },
+	{  474, 120, },
+	{  300, 111, },
+	{    0,   0, },
+};
+
+/* QAM64 SNR lookup table */
+static struct qam64_snr_tab {
+	u16	val;
+	u16	data;
+} qam64_snr_tab[] = {
+	{    1,   0, },
+	{   12, 300, },
+	{   15, 290, },
+	{   18, 280, },
+	{   22, 270, },
+	{   23, 268, },
+	{   24, 266, },
+	{   25, 264, },
+	{   27, 262, },
+	{   28, 260, },
+	{   29, 258, },
+	{   30, 256, },
+	{   32, 254, },
+	{   33, 252, },
+	{   34, 250, },
+	{   35, 249, },
+	{   36, 248, },
+	{   37, 247, },
+	{   38, 246, },
+	{   39, 245, },
+	{   40, 244, },
+	{   41, 243, },
+	{   42, 241, },
+	{   43, 240, },
+	{   44, 239, },
+	{   45, 238, },
+	{   46, 237, },
+	{   47, 236, },
+	{   48, 235, },
+	{   49, 234, },
+	{   50, 233, },
+	{   51, 232, },
+	{   52, 231, },
+	{   53, 230, },
+	{   55, 229, },
+	{   56, 228, },
+	{   57, 227, },
+	{   58, 226, },
+	{   59, 225, },
+	{   60, 224, },
+	{   62, 223, },
+	{   63, 222, },
+	{   65, 221, },
+	{   66, 220, },
+	{   68, 219, },
+	{   69, 218, },
+	{   70, 217, },
+	{   72, 216, },
+	{   73, 215, },
+	{   75, 214, },
+	{   76, 213, },
+	{   78, 212, },
+	{   80, 211, },
+	{   81, 210, },
+	{   83, 209, },
+	{   84, 208, },
+	{   85, 207, },
+	{   87, 206, },
+	{   89, 205, },
+	{   91, 204, },
+	{   93, 203, },
+	{   95, 202, },
+	{   96, 201, },
+	{  104, 200, },
+	{  255,   0, },
+};
+
+/* QAM256 SNR lookup table */
+static struct qam256_snr_tab {
+	u16	val;
+	u16	data;
+} qam256_snr_tab[] = {
+	{    1,   0, },
+	{   12, 400, },
+	{   13, 390, },
+	{   15, 380, },
+	{   17, 360, },
+	{   19, 350, },
+	{   22, 348, },
+	{   23, 346, },
+	{   24, 344, },
+	{   25, 342, },
+	{   26, 340, },
+	{   27, 336, },
+	{   28, 334, },
+	{   29, 332, },
+	{   30, 330, },
+	{   31, 328, },
+	{   32, 326, },
+	{   33, 325, },
+	{   34, 322, },
+	{   35, 320, },
+	{   37, 318, },
+	{   39, 316, },
+	{   40, 314, },
+	{   41, 312, },
+	{   42, 310, },
+	{   43, 308, },
+	{   46, 306, },
+	{   47, 304, },
+	{   49, 302, },
+	{   51, 300, },
+	{   53, 298, },
+	{   54, 297, },
+	{   55, 296, },
+	{   56, 295, },
+	{   57, 294, },
+	{   59, 293, },
+	{   60, 292, },
+	{   61, 291, },
+	{   63, 290, },
+	{   64, 289, },
+	{   65, 288, },
+	{   66, 287, },
+	{   68, 286, },
+	{   69, 285, },
+	{   71, 284, },
+	{   72, 283, },
+	{   74, 282, },
+	{   75, 281, },
+	{   76, 280, },
+	{   77, 279, },
+	{   78, 278, },
+	{   81, 277, },
+	{   83, 276, },
+	{   84, 275, },
+	{   86, 274, },
+	{   87, 273, },
+	{   89, 272, },
+	{   90, 271, },
+	{   92, 270, },
+	{   93, 269, },
+	{   95, 268, },
+	{   96, 267, },
+	{   98, 266, },
+	{  100, 265, },
+	{  102, 264, },
+	{  104, 263, },
+	{  105, 262, },
+	{  106, 261, },
+	{  110, 260, },
+	{  255,   0, },
+};
+
+/* 8 bit registers, 16 bit values */
+static int s5h1409_writereg(struct s5h1409_state *state, u8 reg, u16 data)
+{
+	int ret;
+	u8 buf[] = { reg, data >> 8,  data & 0xff };
+
+	struct i2c_msg msg = { .addr = state->config->demod_address,
+			       .flags = 0, .buf = buf, .len = 3 };
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		printk(KERN_ERR "%s: error (reg == 0x%02x, val == 0x%04x, "
+		       "ret == %i)\n", __func__, reg, data, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+
+static u16 s5h1409_readreg(struct s5h1409_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0, 0 };
+
+	struct i2c_msg msg[] = {
+		{ .addr = state->config->demod_address, .flags = 0,
+		  .buf = b0, .len = 1 },
+		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
+		  .buf = b1, .len = 2 } };
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		printk("%s: readreg error (ret == %i)\n", __func__, ret);
+	return (b1[0] << 8) | b1[1];
+}
+
+static int s5h1409_softreset(struct dvb_frontend *fe)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __func__);
+
+	s5h1409_writereg(state, 0xf5, 0);
+	s5h1409_writereg(state, 0xf5, 1);
+	state->is_qam_locked = 0;
+	state->qam_state = QAM_STATE_UNTUNED;
+	return 0;
+}
+
+#define S5H1409_VSB_IF_FREQ 5380
+#define S5H1409_QAM_IF_FREQ (state->config->qam_if)
+
+static int s5h1409_set_if_freq(struct dvb_frontend *fe, int KHz)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+
+	dprintk("%s(%d KHz)\n", __func__, KHz);
+
+	switch (KHz) {
+	case 4000:
+		s5h1409_writereg(state, 0x87, 0x014b);
+		s5h1409_writereg(state, 0x88, 0x0cb5);
+		s5h1409_writereg(state, 0x89, 0x03e2);
+		break;
+	case 5380:
+	case 44000:
+	default:
+		s5h1409_writereg(state, 0x87, 0x01be);
+		s5h1409_writereg(state, 0x88, 0x0436);
+		s5h1409_writereg(state, 0x89, 0x054d);
+		break;
+	}
+	state->if_freq = KHz;
+
+	return 0;
+}
+
+static int s5h1409_set_spectralinversion(struct dvb_frontend *fe, int inverted)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __func__, inverted);
+
+	if (inverted == 1)
+		return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */
+	else
+		return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */
+}
+
+static int s5h1409_enable_modulation(struct dvb_frontend *fe,
+				     fe_modulation_t m)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+
+	dprintk("%s(0x%08x)\n", __func__, m);
+
+	switch (m) {
+	case VSB_8:
+		dprintk("%s() VSB_8\n", __func__);
+		if (state->if_freq != S5H1409_VSB_IF_FREQ)
+			s5h1409_set_if_freq(fe, S5H1409_VSB_IF_FREQ);
+		s5h1409_writereg(state, 0xf4, 0);
+		break;
+	case QAM_64:
+	case QAM_256:
+	case QAM_AUTO:
+		dprintk("%s() QAM_AUTO (64/256)\n", __func__);
+		if (state->if_freq != S5H1409_QAM_IF_FREQ)
+			s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ);
+		s5h1409_writereg(state, 0xf4, 1);
+		s5h1409_writereg(state, 0x85, 0x110);
+		break;
+	default:
+		dprintk("%s() Invalid modulation\n", __func__);
+		return -EINVAL;
+	}
+
+	state->current_modulation = m;
+	s5h1409_softreset(fe);
+
+	return 0;
+}
+
+static int s5h1409_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __func__, enable);
+
+	if (enable)
+		return s5h1409_writereg(state, 0xf3, 1);
+	else
+		return s5h1409_writereg(state, 0xf3, 0);
+}
+
+static int s5h1409_set_gpio(struct dvb_frontend *fe, int enable)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __func__, enable);
+
+	if (enable)
+		return s5h1409_writereg(state, 0xe3,
+			s5h1409_readreg(state, 0xe3) | 0x1100);
+	else
+		return s5h1409_writereg(state, 0xe3,
+			s5h1409_readreg(state, 0xe3) & 0xfeff);
+}
+
+static int s5h1409_sleep(struct dvb_frontend *fe, int enable)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __func__, enable);
+
+	return s5h1409_writereg(state, 0xf2, enable);
+}
+
+static int s5h1409_register_reset(struct dvb_frontend *fe)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __func__);
+
+	return s5h1409_writereg(state, 0xfa, 0);
+}
+
+static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+	u16 reg;
+
+	if (state->qam_state < QAM_STATE_INTERLEAVE_SET) {
+		/* We should not perform amhum optimization until
+		   the interleave mode has been configured */
+		return;
+	}
+
+	if (state->qam_state == QAM_STATE_QAM_OPTIMIZED_L3) {
+		/* We've already reached the maximum optimization level, so
+		   dont bother banging on the status registers */
+		return;
+	}
+
+	/* QAM EQ lock check */
+	reg = s5h1409_readreg(state, 0xf0);
+
+	if ((reg >> 13) & 0x1) {
+		reg &= 0xff;
+
+		s5h1409_writereg(state, 0x96, 0x000c);
+		if (reg < 0x68) {
+			if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L3) {
+				dprintk("%s() setting QAM state to OPT_L3\n",
+					__func__);
+				s5h1409_writereg(state, 0x93, 0x3130);
+				s5h1409_writereg(state, 0x9e, 0x2836);
+				state->qam_state = QAM_STATE_QAM_OPTIMIZED_L3;
+			}
+		} else {
+			if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L2) {
+				dprintk("%s() setting QAM state to OPT_L2\n",
+					__func__);
+				s5h1409_writereg(state, 0x93, 0x3332);
+				s5h1409_writereg(state, 0x9e, 0x2c37);
+				state->qam_state = QAM_STATE_QAM_OPTIMIZED_L2;
+			}
+		}
+
+	} else {
+		if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L1) {
+			dprintk("%s() setting QAM state to OPT_L1\n", __func__);
+			s5h1409_writereg(state, 0x96, 0x0008);
+			s5h1409_writereg(state, 0x93, 0x3332);
+			s5h1409_writereg(state, 0x9e, 0x2c37);
+			state->qam_state = QAM_STATE_QAM_OPTIMIZED_L1;
+		}
+	}
+}
+
+static void s5h1409_set_qam_amhum_mode_legacy(struct dvb_frontend *fe)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+	u16 reg;
+
+	if (state->is_qam_locked)
+		return;
+
+	/* QAM EQ lock check */
+	reg = s5h1409_readreg(state, 0xf0);
+
+	if ((reg >> 13) & 0x1) {
+
+		state->is_qam_locked = 1;
+		reg &= 0xff;
+
+		s5h1409_writereg(state, 0x96, 0x00c);
+		if ((reg < 0x38) || (reg > 0x68)) {
+			s5h1409_writereg(state, 0x93, 0x3332);
+			s5h1409_writereg(state, 0x9e, 0x2c37);
+		} else {
+			s5h1409_writereg(state, 0x93, 0x3130);
+			s5h1409_writereg(state, 0x9e, 0x2836);
+		}
+
+	} else {
+		s5h1409_writereg(state, 0x96, 0x0008);
+		s5h1409_writereg(state, 0x93, 0x3332);
+		s5h1409_writereg(state, 0x9e, 0x2c37);
+	}
+}
+
+static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+	u16 reg, reg1, reg2;
+
+	if (state->qam_state >= QAM_STATE_INTERLEAVE_SET) {
+		/* We've done the optimization already */
+		return;
+	}
+
+	reg = s5h1409_readreg(state, 0xf1);
+
+	/* Master lock */
+	if ((reg >> 15) & 0x1) {
+		if (state->qam_state == QAM_STATE_UNTUNED ||
+		    state->qam_state == QAM_STATE_TUNING_STARTED) {
+			dprintk("%s() setting QAM state to INTERLEAVE_SET\n",
+				__func__);
+			reg1 = s5h1409_readreg(state, 0xb2);
+			reg2 = s5h1409_readreg(state, 0xad);
+
+			s5h1409_writereg(state, 0x96, 0x0020);
+			s5h1409_writereg(state, 0xad,
+				(((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)));
+			state->qam_state = QAM_STATE_INTERLEAVE_SET;
+		}
+	} else {
+		if (state->qam_state == QAM_STATE_UNTUNED) {
+			dprintk("%s() setting QAM state to TUNING_STARTED\n",
+				__func__);
+			s5h1409_writereg(state, 0x96, 0x08);
+			s5h1409_writereg(state, 0xab,
+				s5h1409_readreg(state, 0xab) | 0x1001);
+			state->qam_state = QAM_STATE_TUNING_STARTED;
+		}
+	}
+}
+
+static void s5h1409_set_qam_interleave_mode_legacy(struct dvb_frontend *fe)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+	u16 reg, reg1, reg2;
+
+	reg = s5h1409_readreg(state, 0xf1);
+
+	/* Master lock */
+	if ((reg >> 15) & 0x1) {
+		if (state->qam_state != 2) {
+			state->qam_state = 2;
+			reg1 = s5h1409_readreg(state, 0xb2);
+			reg2 = s5h1409_readreg(state, 0xad);
+
+			s5h1409_writereg(state, 0x96, 0x20);
+			s5h1409_writereg(state, 0xad,
+				(((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)));
+			s5h1409_writereg(state, 0xab,
+				s5h1409_readreg(state, 0xab) & 0xeffe);
+		}
+	} else {
+		if (state->qam_state != 1) {
+			state->qam_state = 1;
+			s5h1409_writereg(state, 0x96, 0x08);
+			s5h1409_writereg(state, 0xab,
+				s5h1409_readreg(state, 0xab) | 0x1001);
+		}
+	}
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int s5h1409_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct s5h1409_state *state = fe->demodulator_priv;
+
+	dprintk("%s(frequency=%d)\n", __func__, p->frequency);
+
+	s5h1409_softreset(fe);
+
+	state->current_frequency = p->frequency;
+
+	s5h1409_enable_modulation(fe, p->modulation);
+
+	if (fe->ops.tuner_ops.set_params) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	/* Issue a reset to the demod so it knows to resync against the
+	   newly tuned frequency */
+	s5h1409_softreset(fe);
+
+	/* Optimize the demod for QAM */
+	if (state->current_modulation != VSB_8) {
+		/* This almost certainly applies to all boards, but for now
+		   only do it for the HVR-1600.  Once the other boards are
+		   tested, the "legacy" versions can just go away */
+		if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
+			s5h1409_set_qam_interleave_mode(fe);
+			s5h1409_set_qam_amhum_mode(fe);
+		} else {
+			s5h1409_set_qam_amhum_mode_legacy(fe);
+			s5h1409_set_qam_interleave_mode_legacy(fe);
+		}
+	}
+
+	return 0;
+}
+
+static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+	u16 val;
+
+	dprintk("%s(%d)\n", __func__, mode);
+
+	val = s5h1409_readreg(state, 0xac) & 0xcfff;
+	switch (mode) {
+	case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK:
+		val |= 0x0000;
+		break;
+	case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK:
+		dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode);
+		val |= 0x1000;
+		break;
+	case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK:
+		val |= 0x2000;
+		break;
+	case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK:
+		val |= 0x3000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Configure MPEG Signal Timing charactistics */
+	return s5h1409_writereg(state, 0xac, val);
+}
+
+/* Reset the demod hardware and reset all of the configuration registers
+   to a default state. */
+static int s5h1409_init(struct dvb_frontend *fe)
+{
+	int i;
+
+	struct s5h1409_state *state = fe->demodulator_priv;
+	dprintk("%s()\n", __func__);
+
+	s5h1409_sleep(fe, 0);
+	s5h1409_register_reset(fe);
+
+	for (i = 0; i < ARRAY_SIZE(init_tab); i++)
+		s5h1409_writereg(state, init_tab[i].reg, init_tab[i].data);
+
+	/* The datasheet says that after initialisation, VSB is default */
+	state->current_modulation = VSB_8;
+
+	/* Optimize for the HVR-1600 if appropriate.  Note that some of these
+	   may get folded into the generic case after testing with other
+	   devices */
+	if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
+		/* VSB AGC REF */
+		s5h1409_writereg(state, 0x09, 0x0050);
+
+		/* Unknown but Windows driver does it... */
+		s5h1409_writereg(state, 0x21, 0x0001);
+		s5h1409_writereg(state, 0x50, 0x030e);
+
+		/* QAM AGC REF */
+		s5h1409_writereg(state, 0x82, 0x0800);
+	}
+
+	if (state->config->output_mode == S5H1409_SERIAL_OUTPUT)
+		s5h1409_writereg(state, 0xab,
+			s5h1409_readreg(state, 0xab) | 0x100); /* Serial */
+	else
+		s5h1409_writereg(state, 0xab,
+			s5h1409_readreg(state, 0xab) & 0xfeff); /* Parallel */
+
+	s5h1409_set_spectralinversion(fe, state->config->inversion);
+	s5h1409_set_if_freq(fe, state->if_freq);
+	s5h1409_set_gpio(fe, state->config->gpio);
+	s5h1409_set_mpeg_timing(fe, state->config->mpeg_timing);
+	s5h1409_softreset(fe);
+
+	/* Note: Leaving the I2C gate closed. */
+	s5h1409_i2c_gate_ctrl(fe, 0);
+
+	return 0;
+}
+
+static int s5h1409_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+	u16 reg;
+	u32 tuner_status = 0;
+
+	*status = 0;
+
+	/* Optimize the demod for QAM */
+	if (state->current_modulation != VSB_8) {
+		/* This almost certainly applies to all boards, but for now
+		   only do it for the HVR-1600.  Once the other boards are
+		   tested, the "legacy" versions can just go away */
+		if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
+			s5h1409_set_qam_interleave_mode(fe);
+			s5h1409_set_qam_amhum_mode(fe);
+		}
+	}
+
+	/* Get the demodulator status */
+	reg = s5h1409_readreg(state, 0xf1);
+	if (reg & 0x1000)
+		*status |= FE_HAS_VITERBI;
+	if (reg & 0x8000)
+		*status |= FE_HAS_LOCK | FE_HAS_SYNC;
+
+	switch (state->config->status_mode) {
+	case S5H1409_DEMODLOCKING:
+		if (*status & FE_HAS_VITERBI)
+			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+		break;
+	case S5H1409_TUNERLOCKING:
+		/* Get the tuner status */
+		if (fe->ops.tuner_ops.get_status) {
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 1);
+
+			fe->ops.tuner_ops.get_status(fe, &tuner_status);
+
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+		if (tuner_status)
+			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+		break;
+	}
+
+	dprintk("%s() status 0x%08x\n", __func__, *status);
+
+	return 0;
+}
+
+static int s5h1409_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __func__);
+
+	for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
+		if (v < qam256_snr_tab[i].val) {
+			*snr = qam256_snr_tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	return ret;
+}
+
+static int s5h1409_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __func__);
+
+	for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
+		if (v < qam64_snr_tab[i].val) {
+			*snr = qam64_snr_tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	return ret;
+}
+
+static int s5h1409_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __func__);
+
+	for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
+		if (v > vsb_snr_tab[i].val) {
+			*snr = vsb_snr_tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	dprintk("%s() snr=%d\n", __func__, *snr);
+	return ret;
+}
+
+static int s5h1409_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+	u16 reg;
+	dprintk("%s()\n", __func__);
+
+	switch (state->current_modulation) {
+	case QAM_64:
+		reg = s5h1409_readreg(state, 0xf0) & 0xff;
+		return s5h1409_qam64_lookup_snr(fe, snr, reg);
+	case QAM_256:
+		reg = s5h1409_readreg(state, 0xf0) & 0xff;
+		return s5h1409_qam256_lookup_snr(fe, snr, reg);
+	case VSB_8:
+		reg = s5h1409_readreg(state, 0xf1) & 0x3ff;
+		return s5h1409_vsb_lookup_snr(fe, snr, reg);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int s5h1409_read_signal_strength(struct dvb_frontend *fe,
+					u16 *signal_strength)
+{
+	/* borrowed from lgdt330x.c
+	 *
+	 * Calculate strength from SNR up to 35dB
+	 * Even though the SNR can go higher than 35dB,
+	 * there is some comfort factor in having a range of
+	 * strong signals that can show at 100%
+	 */
+	u16 snr;
+	u32 tmp;
+	int ret = s5h1409_read_snr(fe, &snr);
+
+	*signal_strength = 0;
+
+	if (0 == ret) {
+		/* The following calculation method was chosen
+		 * purely for the sake of code re-use from the
+		 * other demod drivers that use this method */
+
+		/* Convert from SNR in dB * 10 to 8.24 fixed-point */
+		tmp = (snr * ((1 << 24) / 10));
+
+		/* Convert from 8.24 fixed-point to
+		 * scale the range 0 - 35*2^24 into 0 - 65535*/
+		if (tmp >= 8960 * 0x10000)
+			*signal_strength = 0xffff;
+		else
+			*signal_strength = tmp / 8960;
+	}
+
+	return ret;
+}
+
+static int s5h1409_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+
+	*ucblocks = s5h1409_readreg(state, 0xb5);
+
+	return 0;
+}
+
+static int s5h1409_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	return s5h1409_read_ucblocks(fe, ber);
+}
+
+static int s5h1409_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct s5h1409_state *state = fe->demodulator_priv;
+
+	p->frequency = state->current_frequency;
+	p->modulation = state->current_modulation;
+
+	return 0;
+}
+
+static int s5h1409_get_tune_settings(struct dvb_frontend *fe,
+				     struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	return 0;
+}
+
+static void s5h1409_release(struct dvb_frontend *fe)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops s5h1409_ops;
+
+struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct s5h1409_state *state = NULL;
+	u16 reg;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct s5h1409_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->current_modulation = 0;
+	state->if_freq = S5H1409_VSB_IF_FREQ;
+
+	/* check if the demod exists */
+	reg = s5h1409_readreg(state, 0x04);
+	if ((reg != 0x0066) && (reg != 0x007f))
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &s5h1409_ops,
+	       sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	if (s5h1409_init(&state->frontend) != 0) {
+		printk(KERN_ERR "%s: Failed to initialize correctly\n",
+			__func__);
+		goto error;
+	}
+
+	/* Note: Leaving the I2C gate open here. */
+	s5h1409_i2c_gate_ctrl(&state->frontend, 1);
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(s5h1409_attach);
+
+static struct dvb_frontend_ops s5h1409_ops = {
+	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
+	.info = {
+		.name			= "Samsung S5H1409 QAM/8VSB Frontend",
+		.frequency_min		= 54000000,
+		.frequency_max		= 858000000,
+		.frequency_stepsize	= 62500,
+		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+	},
+
+	.init                 = s5h1409_init,
+	.i2c_gate_ctrl        = s5h1409_i2c_gate_ctrl,
+	.set_frontend         = s5h1409_set_frontend,
+	.get_frontend         = s5h1409_get_frontend,
+	.get_tune_settings    = s5h1409_get_tune_settings,
+	.read_status          = s5h1409_read_status,
+	.read_ber             = s5h1409_read_ber,
+	.read_signal_strength = s5h1409_read_signal_strength,
+	.read_snr             = s5h1409_read_snr,
+	.read_ucblocks        = s5h1409_read_ucblocks,
+	.release              = s5h1409_release,
+};
+
+MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb-frontends/s5h1409.h b/drivers/media/dvb-frontends/s5h1409.h
new file mode 100644
index 0000000..91f2ebd
--- /dev/null
+++ b/drivers/media/dvb-frontends/s5h1409.h
@@ -0,0 +1,88 @@
+/*
+    Samsung S5H1409 VSB/QAM demodulator driver
+
+    Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __S5H1409_H__
+#define __S5H1409_H__
+
+#include <linux/dvb/frontend.h>
+
+struct s5h1409_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* serial/parallel output */
+#define S5H1409_PARALLEL_OUTPUT 0
+#define S5H1409_SERIAL_OUTPUT   1
+	u8 output_mode;
+
+	/* GPIO Setting */
+#define S5H1409_GPIO_OFF 0
+#define S5H1409_GPIO_ON  1
+	u8 gpio;
+
+	/* IF Freq for QAM in KHz, VSB is hardcoded to 5380 */
+	u16 qam_if;
+
+	/* Spectral Inversion */
+#define S5H1409_INVERSION_OFF 0
+#define S5H1409_INVERSION_ON  1
+	u8 inversion;
+
+	/* Return lock status based on tuner lock, or demod lock */
+#define S5H1409_TUNERLOCKING 0
+#define S5H1409_DEMODLOCKING 1
+	u8 status_mode;
+
+	/* MPEG signal timing */
+#define S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK       0
+#define S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK    1
+#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK    2
+#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
+	u16 mpeg_timing;
+
+	/* HVR-1600 optimizations (to better work with MXL5005s)
+	   Note: some of these are likely to be folded into the generic driver
+	   after being regression tested with other boards */
+#define S5H1409_HVR1600_NOOPTIMIZE 0
+#define S5H1409_HVR1600_OPTIMIZE   1
+	u8 hvr1600_opt;
+};
+
+#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) \
+	&& defined(MODULE))
+extern struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config,
+					   struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *s5h1409_attach(
+	const struct s5h1409_config *config,
+	struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_S5H1409 */
+
+#endif /* __S5H1409_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb-frontends/s5h1411.c b/drivers/media/dvb-frontends/s5h1411.c
new file mode 100644
index 0000000..6cc4b7a
--- /dev/null
+++ b/drivers/media/dvb-frontends/s5h1411.c
@@ -0,0 +1,951 @@
+/*
+    Samsung S5H1411 VSB/QAM demodulator driver
+
+    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "s5h1411.h"
+
+struct s5h1411_state {
+
+	struct i2c_adapter *i2c;
+
+	/* configuration settings */
+	const struct s5h1411_config *config;
+
+	struct dvb_frontend frontend;
+
+	fe_modulation_t current_modulation;
+	unsigned int first_tune:1;
+
+	u32 current_frequency;
+	int if_freq;
+
+	u8 inversion;
+};
+
+static int debug;
+
+#define dprintk(arg...) do {	\
+	if (debug)		\
+		printk(arg);	\
+	} while (0)
+
+/* Register values to initialise the demod, defaults to VSB */
+static struct init_tab {
+	u8	addr;
+	u8	reg;
+	u16	data;
+} init_tab[] = {
+	{ S5H1411_I2C_TOP_ADDR, 0x00, 0x0071, },
+	{ S5H1411_I2C_TOP_ADDR, 0x08, 0x0047, },
+	{ S5H1411_I2C_TOP_ADDR, 0x1c, 0x0400, },
+	{ S5H1411_I2C_TOP_ADDR, 0x1e, 0x0370, },
+	{ S5H1411_I2C_TOP_ADDR, 0x1f, 0x342c, },
+	{ S5H1411_I2C_TOP_ADDR, 0x24, 0x0231, },
+	{ S5H1411_I2C_TOP_ADDR, 0x25, 0x1011, },
+	{ S5H1411_I2C_TOP_ADDR, 0x26, 0x0f07, },
+	{ S5H1411_I2C_TOP_ADDR, 0x27, 0x0f04, },
+	{ S5H1411_I2C_TOP_ADDR, 0x28, 0x070f, },
+	{ S5H1411_I2C_TOP_ADDR, 0x29, 0x2820, },
+	{ S5H1411_I2C_TOP_ADDR, 0x2a, 0x102e, },
+	{ S5H1411_I2C_TOP_ADDR, 0x2b, 0x0220, },
+	{ S5H1411_I2C_TOP_ADDR, 0x2e, 0x0d0e, },
+	{ S5H1411_I2C_TOP_ADDR, 0x2f, 0x1013, },
+	{ S5H1411_I2C_TOP_ADDR, 0x31, 0x171b, },
+	{ S5H1411_I2C_TOP_ADDR, 0x32, 0x0e0f, },
+	{ S5H1411_I2C_TOP_ADDR, 0x33, 0x0f10, },
+	{ S5H1411_I2C_TOP_ADDR, 0x34, 0x170e, },
+	{ S5H1411_I2C_TOP_ADDR, 0x35, 0x4b10, },
+	{ S5H1411_I2C_TOP_ADDR, 0x36, 0x0f17, },
+	{ S5H1411_I2C_TOP_ADDR, 0x3c, 0x1577, },
+	{ S5H1411_I2C_TOP_ADDR, 0x3d, 0x081a, },
+	{ S5H1411_I2C_TOP_ADDR, 0x3e, 0x77ee, },
+	{ S5H1411_I2C_TOP_ADDR, 0x40, 0x1e09, },
+	{ S5H1411_I2C_TOP_ADDR, 0x41, 0x0f0c, },
+	{ S5H1411_I2C_TOP_ADDR, 0x42, 0x1f10, },
+	{ S5H1411_I2C_TOP_ADDR, 0x4d, 0x0509, },
+	{ S5H1411_I2C_TOP_ADDR, 0x4e, 0x0a00, },
+	{ S5H1411_I2C_TOP_ADDR, 0x50, 0x0000, },
+	{ S5H1411_I2C_TOP_ADDR, 0x5b, 0x0000, },
+	{ S5H1411_I2C_TOP_ADDR, 0x5c, 0x0008, },
+	{ S5H1411_I2C_TOP_ADDR, 0x57, 0x1101, },
+	{ S5H1411_I2C_TOP_ADDR, 0x65, 0x007c, },
+	{ S5H1411_I2C_TOP_ADDR, 0x68, 0x0512, },
+	{ S5H1411_I2C_TOP_ADDR, 0x69, 0x0258, },
+	{ S5H1411_I2C_TOP_ADDR, 0x70, 0x0004, },
+	{ S5H1411_I2C_TOP_ADDR, 0x71, 0x0007, },
+	{ S5H1411_I2C_TOP_ADDR, 0x76, 0x00a9, },
+	{ S5H1411_I2C_TOP_ADDR, 0x78, 0x3141, },
+	{ S5H1411_I2C_TOP_ADDR, 0x7a, 0x3141, },
+	{ S5H1411_I2C_TOP_ADDR, 0xb3, 0x8003, },
+	{ S5H1411_I2C_TOP_ADDR, 0xb5, 0xa6bb, },
+	{ S5H1411_I2C_TOP_ADDR, 0xb6, 0x0609, },
+	{ S5H1411_I2C_TOP_ADDR, 0xb7, 0x2f06, },
+	{ S5H1411_I2C_TOP_ADDR, 0xb8, 0x003f, },
+	{ S5H1411_I2C_TOP_ADDR, 0xb9, 0x2700, },
+	{ S5H1411_I2C_TOP_ADDR, 0xba, 0xfac8, },
+	{ S5H1411_I2C_TOP_ADDR, 0xbe, 0x1003, },
+	{ S5H1411_I2C_TOP_ADDR, 0xbf, 0x103f, },
+	{ S5H1411_I2C_TOP_ADDR, 0xce, 0x2000, },
+	{ S5H1411_I2C_TOP_ADDR, 0xcf, 0x0800, },
+	{ S5H1411_I2C_TOP_ADDR, 0xd0, 0x0800, },
+	{ S5H1411_I2C_TOP_ADDR, 0xd1, 0x0400, },
+	{ S5H1411_I2C_TOP_ADDR, 0xd2, 0x0800, },
+	{ S5H1411_I2C_TOP_ADDR, 0xd3, 0x2000, },
+	{ S5H1411_I2C_TOP_ADDR, 0xd4, 0x3000, },
+	{ S5H1411_I2C_TOP_ADDR, 0xdb, 0x4a9b, },
+	{ S5H1411_I2C_TOP_ADDR, 0xdc, 0x1000, },
+	{ S5H1411_I2C_TOP_ADDR, 0xde, 0x0001, },
+	{ S5H1411_I2C_TOP_ADDR, 0xdf, 0x0000, },
+	{ S5H1411_I2C_TOP_ADDR, 0xe3, 0x0301, },
+	{ S5H1411_I2C_QAM_ADDR, 0xf3, 0x0000, },
+	{ S5H1411_I2C_QAM_ADDR, 0xf3, 0x0001, },
+	{ S5H1411_I2C_QAM_ADDR, 0x08, 0x0600, },
+	{ S5H1411_I2C_QAM_ADDR, 0x18, 0x4201, },
+	{ S5H1411_I2C_QAM_ADDR, 0x1e, 0x6476, },
+	{ S5H1411_I2C_QAM_ADDR, 0x21, 0x0830, },
+	{ S5H1411_I2C_QAM_ADDR, 0x0c, 0x5679, },
+	{ S5H1411_I2C_QAM_ADDR, 0x0d, 0x579b, },
+	{ S5H1411_I2C_QAM_ADDR, 0x24, 0x0102, },
+	{ S5H1411_I2C_QAM_ADDR, 0x31, 0x7488, },
+	{ S5H1411_I2C_QAM_ADDR, 0x32, 0x0a08, },
+	{ S5H1411_I2C_QAM_ADDR, 0x3d, 0x8689, },
+	{ S5H1411_I2C_QAM_ADDR, 0x49, 0x0048, },
+	{ S5H1411_I2C_QAM_ADDR, 0x57, 0x2012, },
+	{ S5H1411_I2C_QAM_ADDR, 0x5d, 0x7676, },
+	{ S5H1411_I2C_QAM_ADDR, 0x04, 0x0400, },
+	{ S5H1411_I2C_QAM_ADDR, 0x58, 0x00c0, },
+	{ S5H1411_I2C_QAM_ADDR, 0x5b, 0x0100, },
+};
+
+/* VSB SNR lookup table */
+static struct vsb_snr_tab {
+	u16	val;
+	u16	data;
+} vsb_snr_tab[] = {
+	{  0x39f, 300, },
+	{  0x39b, 295, },
+	{  0x397, 290, },
+	{  0x394, 285, },
+	{  0x38f, 280, },
+	{  0x38b, 275, },
+	{  0x387, 270, },
+	{  0x382, 265, },
+	{  0x37d, 260, },
+	{  0x377, 255, },
+	{  0x370, 250, },
+	{  0x36a, 245, },
+	{  0x364, 240, },
+	{  0x35b, 235, },
+	{  0x353, 230, },
+	{  0x349, 225, },
+	{  0x340, 320, },
+	{  0x337, 215, },
+	{  0x327, 210, },
+	{  0x31b, 205, },
+	{  0x310, 200, },
+	{  0x302, 195, },
+	{  0x2f3, 190, },
+	{  0x2e4, 185, },
+	{  0x2d7, 180, },
+	{  0x2cd, 175, },
+	{  0x2bb, 170, },
+	{  0x2a9, 165, },
+	{  0x29e, 160, },
+	{  0x284, 155, },
+	{  0x27a, 150, },
+	{  0x260, 145, },
+	{  0x23a, 140, },
+	{  0x224, 135, },
+	{  0x213, 130, },
+	{  0x204, 125, },
+	{  0x1fe, 120, },
+	{      0,   0, },
+};
+
+/* QAM64 SNR lookup table */
+static struct qam64_snr_tab {
+	u16	val;
+	u16	data;
+} qam64_snr_tab[] = {
+	{  0x0001,   0, },
+	{  0x0af0, 300, },
+	{  0x0d80, 290, },
+	{  0x10a0, 280, },
+	{  0x14b5, 270, },
+	{  0x1590, 268, },
+	{  0x1680, 266, },
+	{  0x17b0, 264, },
+	{  0x18c0, 262, },
+	{  0x19b0, 260, },
+	{  0x1ad0, 258, },
+	{  0x1d00, 256, },
+	{  0x1da0, 254, },
+	{  0x1ef0, 252, },
+	{  0x2050, 250, },
+	{  0x20f0, 249, },
+	{  0x21d0, 248, },
+	{  0x22b0, 247, },
+	{  0x23a0, 246, },
+	{  0x2470, 245, },
+	{  0x24f0, 244, },
+	{  0x25a0, 243, },
+	{  0x26c0, 242, },
+	{  0x27b0, 241, },
+	{  0x28d0, 240, },
+	{  0x29b0, 239, },
+	{  0x2ad0, 238, },
+	{  0x2ba0, 237, },
+	{  0x2c80, 236, },
+	{  0x2d20, 235, },
+	{  0x2e00, 234, },
+	{  0x2f10, 233, },
+	{  0x3050, 232, },
+	{  0x3190, 231, },
+	{  0x3300, 230, },
+	{  0x3340, 229, },
+	{  0x3200, 228, },
+	{  0x3550, 227, },
+	{  0x3610, 226, },
+	{  0x3600, 225, },
+	{  0x3700, 224, },
+	{  0x3800, 223, },
+	{  0x3920, 222, },
+	{  0x3a20, 221, },
+	{  0x3b30, 220, },
+	{  0x3d00, 219, },
+	{  0x3e00, 218, },
+	{  0x4000, 217, },
+	{  0x4100, 216, },
+	{  0x4300, 215, },
+	{  0x4400, 214, },
+	{  0x4600, 213, },
+	{  0x4700, 212, },
+	{  0x4800, 211, },
+	{  0x4a00, 210, },
+	{  0x4b00, 209, },
+	{  0x4d00, 208, },
+	{  0x4f00, 207, },
+	{  0x5050, 206, },
+	{  0x5200, 205, },
+	{  0x53c0, 204, },
+	{  0x5450, 203, },
+	{  0x5650, 202, },
+	{  0x5820, 201, },
+	{  0x6000, 200, },
+	{  0xffff,   0, },
+};
+
+/* QAM256 SNR lookup table */
+static struct qam256_snr_tab {
+	u16	val;
+	u16	data;
+} qam256_snr_tab[] = {
+	{  0x0001,   0, },
+	{  0x0970, 400, },
+	{  0x0a90, 390, },
+	{  0x0b90, 380, },
+	{  0x0d90, 370, },
+	{  0x0ff0, 360, },
+	{  0x1240, 350, },
+	{  0x1345, 348, },
+	{  0x13c0, 346, },
+	{  0x14c0, 344, },
+	{  0x1500, 342, },
+	{  0x1610, 340, },
+	{  0x1700, 338, },
+	{  0x1800, 336, },
+	{  0x18b0, 334, },
+	{  0x1900, 332, },
+	{  0x1ab0, 330, },
+	{  0x1bc0, 328, },
+	{  0x1cb0, 326, },
+	{  0x1db0, 324, },
+	{  0x1eb0, 322, },
+	{  0x2030, 320, },
+	{  0x2200, 318, },
+	{  0x2280, 316, },
+	{  0x2410, 314, },
+	{  0x25b0, 312, },
+	{  0x27a0, 310, },
+	{  0x2840, 308, },
+	{  0x29d0, 306, },
+	{  0x2b10, 304, },
+	{  0x2d30, 302, },
+	{  0x2f20, 300, },
+	{  0x30c0, 298, },
+	{  0x3260, 297, },
+	{  0x32c0, 296, },
+	{  0x3300, 295, },
+	{  0x33b0, 294, },
+	{  0x34b0, 293, },
+	{  0x35a0, 292, },
+	{  0x3650, 291, },
+	{  0x3800, 290, },
+	{  0x3900, 289, },
+	{  0x3a50, 288, },
+	{  0x3b30, 287, },
+	{  0x3cb0, 286, },
+	{  0x3e20, 285, },
+	{  0x3fa0, 284, },
+	{  0x40a0, 283, },
+	{  0x41c0, 282, },
+	{  0x42f0, 281, },
+	{  0x44a0, 280, },
+	{  0x4600, 279, },
+	{  0x47b0, 278, },
+	{  0x4900, 277, },
+	{  0x4a00, 276, },
+	{  0x4ba0, 275, },
+	{  0x4d00, 274, },
+	{  0x4f00, 273, },
+	{  0x5000, 272, },
+	{  0x51f0, 272, },
+	{  0x53a0, 270, },
+	{  0x5520, 269, },
+	{  0x5700, 268, },
+	{  0x5800, 267, },
+	{  0x5a00, 266, },
+	{  0x5c00, 265, },
+	{  0x5d00, 264, },
+	{  0x5f00, 263, },
+	{  0x6000, 262, },
+	{  0x6200, 261, },
+	{  0x6400, 260, },
+	{  0xffff,   0, },
+};
+
+/* 8 bit registers, 16 bit values */
+static int s5h1411_writereg(struct s5h1411_state *state,
+	u8 addr, u8 reg, u16 data)
+{
+	int ret;
+	u8 buf[] = { reg, data >> 8,  data & 0xff };
+
+	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, "
+		       "ret == %i)\n", __func__, addr, reg, data, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+
+static u16 s5h1411_readreg(struct s5h1411_state *state, u8 addr, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0, 0 };
+
+	struct i2c_msg msg[] = {
+		{ .addr = addr, .flags = 0, .buf = b0, .len = 1 },
+		{ .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+			__func__, ret);
+	return (b1[0] << 8) | b1[1];
+}
+
+static int s5h1411_softreset(struct dvb_frontend *fe)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __func__);
+
+	s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 0);
+	s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 1);
+	return 0;
+}
+
+static int s5h1411_set_if_freq(struct dvb_frontend *fe, int KHz)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	dprintk("%s(%d KHz)\n", __func__, KHz);
+
+	switch (KHz) {
+	case 3250:
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x10d5);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x5342);
+		s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x10d9);
+		break;
+	case 3500:
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1225);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x1e96);
+		s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1225);
+		break;
+	case 4000:
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x14bc);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0xb53e);
+		s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x14bd);
+		break;
+	default:
+		dprintk("%s(%d KHz) Invalid, defaulting to 5380\n",
+			__func__, KHz);
+		/* no break, need to continue */
+	case 5380:
+	case 44000:
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1be4);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x3655);
+		s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1be4);
+		break;
+	}
+
+	state->if_freq = KHz;
+
+	return 0;
+}
+
+static int s5h1411_set_mpeg_timing(struct dvb_frontend *fe, int mode)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+	u16 val;
+
+	dprintk("%s(%d)\n", __func__, mode);
+
+	val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbe) & 0xcfff;
+	switch (mode) {
+	case S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK:
+		val |= 0x0000;
+		break;
+	case S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK:
+		dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode);
+		val |= 0x1000;
+		break;
+	case S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK:
+		val |= 0x2000;
+		break;
+	case S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK:
+		val |= 0x3000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Configure MPEG Signal Timing charactistics */
+	return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbe, val);
+}
+
+static int s5h1411_set_spectralinversion(struct dvb_frontend *fe, int inversion)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+	u16 val;
+
+	dprintk("%s(%d)\n", __func__, inversion);
+	val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x24) & ~0x1000;
+
+	if (inversion == 1)
+		val |= 0x1000; /* Inverted */
+
+	state->inversion = inversion;
+	return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x24, val);
+}
+
+static int s5h1411_set_serialmode(struct dvb_frontend *fe, int serial)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+	u16 val;
+
+	dprintk("%s(%d)\n", __func__, serial);
+	val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbd) & ~0x100;
+
+	if (serial == 1)
+		val |= 0x100;
+
+	return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, val);
+}
+
+static int s5h1411_enable_modulation(struct dvb_frontend *fe,
+				     fe_modulation_t m)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	dprintk("%s(0x%08x)\n", __func__, m);
+
+	if ((state->first_tune == 0) && (m == state->current_modulation)) {
+		dprintk("%s() Already at desired modulation.  Skipping...\n",
+			__func__);
+		return 0;
+	}
+
+	switch (m) {
+	case VSB_8:
+		dprintk("%s() VSB_8\n", __func__);
+		s5h1411_set_if_freq(fe, state->config->vsb_if);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x71);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x00);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0xf1);
+		break;
+	case QAM_64:
+	case QAM_256:
+	case QAM_AUTO:
+		dprintk("%s() QAM_AUTO (64/256)\n", __func__);
+		s5h1411_set_if_freq(fe, state->config->qam_if);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x0171);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x0001);
+		s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x16, 0x1101);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0x00f0);
+		break;
+	default:
+		dprintk("%s() Invalid modulation\n", __func__);
+		return -EINVAL;
+	}
+
+	state->current_modulation = m;
+	state->first_tune = 0;
+	s5h1411_softreset(fe);
+
+	return 0;
+}
+
+static int s5h1411_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __func__, enable);
+
+	if (enable)
+		return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1);
+	else
+		return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 0);
+}
+
+static int s5h1411_set_gpio(struct dvb_frontend *fe, int enable)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+	u16 val;
+
+	dprintk("%s(%d)\n", __func__, enable);
+
+	val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xe0) & ~0x02;
+
+	if (enable)
+		return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0,
+				val | 0x02);
+	else
+		return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0, val);
+}
+
+static int s5h1411_set_powerstate(struct dvb_frontend *fe, int enable)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __func__, enable);
+
+	if (enable)
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 1);
+	else {
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 0);
+		s5h1411_softreset(fe);
+	}
+
+	return 0;
+}
+
+static int s5h1411_sleep(struct dvb_frontend *fe)
+{
+	return s5h1411_set_powerstate(fe, 1);
+}
+
+static int s5h1411_register_reset(struct dvb_frontend *fe)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __func__);
+
+	return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf3, 0);
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int s5h1411_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	dprintk("%s(frequency=%d)\n", __func__, p->frequency);
+
+	s5h1411_softreset(fe);
+
+	state->current_frequency = p->frequency;
+
+	s5h1411_enable_modulation(fe, p->modulation);
+
+	if (fe->ops.tuner_ops.set_params) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		fe->ops.tuner_ops.set_params(fe);
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	/* Issue a reset to the demod so it knows to resync against the
+	   newly tuned frequency */
+	s5h1411_softreset(fe);
+
+	return 0;
+}
+
+/* Reset the demod hardware and reset all of the configuration registers
+   to a default state. */
+static int s5h1411_init(struct dvb_frontend *fe)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+	int i;
+
+	dprintk("%s()\n", __func__);
+
+	s5h1411_set_powerstate(fe, 0);
+	s5h1411_register_reset(fe);
+
+	for (i = 0; i < ARRAY_SIZE(init_tab); i++)
+		s5h1411_writereg(state, init_tab[i].addr,
+			init_tab[i].reg,
+			init_tab[i].data);
+
+	/* The datasheet says that after initialisation, VSB is default */
+	state->current_modulation = VSB_8;
+
+	/* Although the datasheet says it's in VSB, empirical evidence
+	   shows problems getting lock on the first tuning request.  Make
+	   sure we call enable_modulation the first time around */
+	state->first_tune = 1;
+
+	if (state->config->output_mode == S5H1411_SERIAL_OUTPUT)
+		/* Serial */
+		s5h1411_set_serialmode(fe, 1);
+	else
+		/* Parallel */
+		s5h1411_set_serialmode(fe, 0);
+
+	s5h1411_set_spectralinversion(fe, state->config->inversion);
+	s5h1411_set_if_freq(fe, state->config->vsb_if);
+	s5h1411_set_gpio(fe, state->config->gpio);
+	s5h1411_set_mpeg_timing(fe, state->config->mpeg_timing);
+	s5h1411_softreset(fe);
+
+	/* Note: Leaving the I2C gate closed. */
+	s5h1411_i2c_gate_ctrl(fe, 0);
+
+	return 0;
+}
+
+static int s5h1411_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+	u16 reg;
+	u32 tuner_status = 0;
+
+	*status = 0;
+
+	/* Register F2 bit 15 = Master Lock, removed */
+
+	switch (state->current_modulation) {
+	case QAM_64:
+	case QAM_256:
+		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf0);
+		if (reg & 0x10) /* QAM FEC Lock */
+			*status |= FE_HAS_SYNC | FE_HAS_LOCK;
+		if (reg & 0x100) /* QAM EQ Lock */
+			*status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
+
+		break;
+	case VSB_8:
+		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2);
+		if (reg & 0x1000) /* FEC Lock */
+			*status |= FE_HAS_SYNC | FE_HAS_LOCK;
+		if (reg & 0x2000) /* EQ Lock */
+			*status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
+
+		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x53);
+		if (reg & 0x1) /* AFC Lock */
+			*status |= FE_HAS_SIGNAL;
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (state->config->status_mode) {
+	case S5H1411_DEMODLOCKING:
+		if (*status & FE_HAS_VITERBI)
+			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+		break;
+	case S5H1411_TUNERLOCKING:
+		/* Get the tuner status */
+		if (fe->ops.tuner_ops.get_status) {
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 1);
+
+			fe->ops.tuner_ops.get_status(fe, &tuner_status);
+
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+		if (tuner_status)
+			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+		break;
+	}
+
+	dprintk("%s() status 0x%08x\n", __func__, *status);
+
+	return 0;
+}
+
+static int s5h1411_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __func__);
+
+	for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
+		if (v < qam256_snr_tab[i].val) {
+			*snr = qam256_snr_tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	return ret;
+}
+
+static int s5h1411_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __func__);
+
+	for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
+		if (v < qam64_snr_tab[i].val) {
+			*snr = qam64_snr_tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	return ret;
+}
+
+static int s5h1411_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __func__);
+
+	for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
+		if (v > vsb_snr_tab[i].val) {
+			*snr = vsb_snr_tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	dprintk("%s() snr=%d\n", __func__, *snr);
+	return ret;
+}
+
+static int s5h1411_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+	u16 reg;
+	dprintk("%s()\n", __func__);
+
+	switch (state->current_modulation) {
+	case QAM_64:
+		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1);
+		return s5h1411_qam64_lookup_snr(fe, snr, reg);
+	case QAM_256:
+		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1);
+		return s5h1411_qam256_lookup_snr(fe, snr, reg);
+	case VSB_8:
+		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR,
+			0xf2) & 0x3ff;
+		return s5h1411_vsb_lookup_snr(fe, snr, reg);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int s5h1411_read_signal_strength(struct dvb_frontend *fe,
+	u16 *signal_strength)
+{
+	/* borrowed from lgdt330x.c
+	 *
+	 * Calculate strength from SNR up to 35dB
+	 * Even though the SNR can go higher than 35dB,
+	 * there is some comfort factor in having a range of
+	 * strong signals that can show at 100%
+	 */
+	u16 snr;
+	u32 tmp;
+	int ret = s5h1411_read_snr(fe, &snr);
+
+	*signal_strength = 0;
+
+	if (0 == ret) {
+		/* The following calculation method was chosen
+		 * purely for the sake of code re-use from the
+		 * other demod drivers that use this method */
+
+		/* Convert from SNR in dB * 10 to 8.24 fixed-point */
+		tmp = (snr * ((1 << 24) / 10));
+
+		/* Convert from 8.24 fixed-point to
+		 * scale the range 0 - 35*2^24 into 0 - 65535*/
+		if (tmp >= 8960 * 0x10000)
+			*signal_strength = 0xffff;
+		else
+			*signal_strength = tmp / 8960;
+	}
+
+	return ret;
+}
+
+static int s5h1411_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	*ucblocks = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xc9);
+
+	return 0;
+}
+
+static int s5h1411_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	return s5h1411_read_ucblocks(fe, ber);
+}
+
+static int s5h1411_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	p->frequency = state->current_frequency;
+	p->modulation = state->current_modulation;
+
+	return 0;
+}
+
+static int s5h1411_get_tune_settings(struct dvb_frontend *fe,
+				     struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	return 0;
+}
+
+static void s5h1411_release(struct dvb_frontend *fe)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops s5h1411_ops;
+
+struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct s5h1411_state *state = NULL;
+	u16 reg;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct s5h1411_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->current_modulation = VSB_8;
+	state->inversion = state->config->inversion;
+
+	/* check if the demod exists */
+	reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x05);
+	if (reg != 0x0066)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &s5h1411_ops,
+	       sizeof(struct dvb_frontend_ops));
+
+	state->frontend.demodulator_priv = state;
+
+	if (s5h1411_init(&state->frontend) != 0) {
+		printk(KERN_ERR "%s: Failed to initialize correctly\n",
+			__func__);
+		goto error;
+	}
+
+	/* Note: Leaving the I2C gate open here. */
+	s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1);
+
+	/* Put the device into low-power mode until first use */
+	s5h1411_set_powerstate(&state->frontend, 1);
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(s5h1411_attach);
+
+static struct dvb_frontend_ops s5h1411_ops = {
+	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
+	.info = {
+		.name			= "Samsung S5H1411 QAM/8VSB Frontend",
+		.frequency_min		= 54000000,
+		.frequency_max		= 858000000,
+		.frequency_stepsize	= 62500,
+		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+	},
+
+	.init                 = s5h1411_init,
+	.sleep                = s5h1411_sleep,
+	.i2c_gate_ctrl        = s5h1411_i2c_gate_ctrl,
+	.set_frontend         = s5h1411_set_frontend,
+	.get_frontend         = s5h1411_get_frontend,
+	.get_tune_settings    = s5h1411_get_tune_settings,
+	.read_status          = s5h1411_read_status,
+	.read_ber             = s5h1411_read_ber,
+	.read_signal_strength = s5h1411_read_signal_strength,
+	.read_snr             = s5h1411_read_snr,
+	.read_ucblocks        = s5h1411_read_ucblocks,
+	.release              = s5h1411_release,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Samsung S5H1411 QAM-B/ATSC Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb-frontends/s5h1411.h b/drivers/media/dvb-frontends/s5h1411.h
new file mode 100644
index 0000000..45ec0f8
--- /dev/null
+++ b/drivers/media/dvb-frontends/s5h1411.h
@@ -0,0 +1,90 @@
+/*
+    Samsung S5H1411 VSB/QAM demodulator driver
+
+    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __S5H1411_H__
+#define __S5H1411_H__
+
+#include <linux/dvb/frontend.h>
+
+#define S5H1411_I2C_TOP_ADDR (0x32 >> 1)
+#define S5H1411_I2C_QAM_ADDR (0x34 >> 1)
+
+struct s5h1411_config {
+
+	/* serial/parallel output */
+#define S5H1411_PARALLEL_OUTPUT 0
+#define S5H1411_SERIAL_OUTPUT   1
+	u8 output_mode;
+
+	/* GPIO Setting */
+#define S5H1411_GPIO_OFF 0
+#define S5H1411_GPIO_ON  1
+	u8 gpio;
+
+	/* MPEG signal timing */
+#define S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK       0
+#define S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK    1
+#define S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK    2
+#define S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
+	u16 mpeg_timing;
+
+	/* IF Freq for QAM and VSB in KHz */
+#define S5H1411_IF_3250  3250
+#define S5H1411_IF_3500  3500
+#define S5H1411_IF_4000  4000
+#define S5H1411_IF_5380  5380
+#define S5H1411_IF_44000 44000
+#define S5H1411_VSB_IF_DEFAULT S5H1411_IF_44000
+#define S5H1411_QAM_IF_DEFAULT S5H1411_IF_44000
+	u16 qam_if;
+	u16 vsb_if;
+
+	/* Spectral Inversion */
+#define S5H1411_INVERSION_OFF 0
+#define S5H1411_INVERSION_ON  1
+	u8 inversion;
+
+	/* Return lock status based on tuner lock, or demod lock */
+#define S5H1411_TUNERLOCKING 0
+#define S5H1411_DEMODLOCKING 1
+	u8 status_mode;
+};
+
+#if defined(CONFIG_DVB_S5H1411) || \
+	(defined(CONFIG_DVB_S5H1411_MODULE) && defined(MODULE))
+extern struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config,
+					   struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *s5h1411_attach(
+	const struct s5h1411_config *config,
+	struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_S5H1411 */
+
+#endif /* __S5H1411_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb-frontends/s5h1420.c b/drivers/media/dvb-frontends/s5h1420.c
new file mode 100644
index 0000000..e2fec9e
--- /dev/null
+++ b/drivers/media/dvb-frontends/s5h1420.c
@@ -0,0 +1,960 @@
+/*
+ * Driver for
+ *    Samsung S5H1420 and
+ *    PnpNetwork PN1010 QPSK Demodulator
+ *
+ * Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
+ * Copyright (C) 2005-8 Patrick Boettcher <pb@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <asm/div64.h>
+
+#include <linux/i2c.h>
+
+
+#include "dvb_frontend.h"
+#include "s5h1420.h"
+#include "s5h1420_priv.h"
+
+#define TONE_FREQ 22000
+
+struct s5h1420_state {
+	struct i2c_adapter* i2c;
+	const struct s5h1420_config* config;
+
+	struct dvb_frontend frontend;
+	struct i2c_adapter tuner_i2c_adapter;
+
+	u8 CON_1_val;
+
+	u8 postlocked:1;
+	u32 fclk;
+	u32 tunedfreq;
+	fe_code_rate_t fec_inner;
+	u32 symbol_rate;
+
+	/* FIXME: ugly workaround for flexcop's incapable i2c-controller
+	 * it does not support repeated-start, workaround: write addr-1
+	 * and then read
+	 */
+	u8 shadow[256];
+};
+
+static u32 s5h1420_getsymbolrate(struct s5h1420_state* state);
+static int s5h1420_get_tune_settings(struct dvb_frontend* fe,
+				     struct dvb_frontend_tune_settings* fesettings);
+
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debugging");
+
+#define dprintk(x...) do { \
+	if (debug) \
+		printk(KERN_DEBUG "S5H1420: " x); \
+} while (0)
+
+static u8 s5h1420_readreg(struct s5h1420_state *state, u8 reg)
+{
+	int ret;
+	u8 b[2];
+	struct i2c_msg msg[] = {
+		{ .addr = state->config->demod_address, .flags = 0, .buf = b, .len = 2 },
+		{ .addr = state->config->demod_address, .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = 1 },
+	};
+
+	b[0] = (reg - 1) & 0xff;
+	b[1] = state->shadow[(reg - 1) & 0xff];
+
+	if (state->config->repeated_start_workaround) {
+		ret = i2c_transfer(state->i2c, msg, 3);
+		if (ret != 3)
+			return ret;
+	} else {
+		ret = i2c_transfer(state->i2c, &msg[1], 1);
+		if (ret != 1)
+			return ret;
+		ret = i2c_transfer(state->i2c, &msg[2], 1);
+		if (ret != 1)
+			return ret;
+	}
+
+	/* dprintk("rd(%02x): %02x %02x\n", state->config->demod_address, reg, b[0]); */
+
+	return b[0];
+}
+
+static int s5h1420_writereg (struct s5h1420_state* state, u8 reg, u8 data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+	int err;
+
+	/* dprintk("wr(%02x): %02x %02x\n", state->config->demod_address, reg, data); */
+	err = i2c_transfer(state->i2c, &msg, 1);
+	if (err != 1) {
+		dprintk("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
+		return -EREMOTEIO;
+	}
+	state->shadow[reg] = data;
+
+	return 0;
+}
+
+static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+
+	dprintk("enter %s\n", __func__);
+
+	switch(voltage) {
+	case SEC_VOLTAGE_13:
+		s5h1420_writereg(state, 0x3c,
+				 (s5h1420_readreg(state, 0x3c) & 0xfe) | 0x02);
+		break;
+
+	case SEC_VOLTAGE_18:
+		s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) | 0x03);
+		break;
+
+	case SEC_VOLTAGE_OFF:
+		s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) & 0xfd);
+		break;
+	}
+
+	dprintk("leave %s\n", __func__);
+	return 0;
+}
+
+static int s5h1420_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+
+	dprintk("enter %s\n", __func__);
+	switch(tone) {
+	case SEC_TONE_ON:
+		s5h1420_writereg(state, 0x3b,
+				 (s5h1420_readreg(state, 0x3b) & 0x74) | 0x08);
+		break;
+
+	case SEC_TONE_OFF:
+		s5h1420_writereg(state, 0x3b,
+				 (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01);
+		break;
+	}
+	dprintk("leave %s\n", __func__);
+
+	return 0;
+}
+
+static int s5h1420_send_master_cmd (struct dvb_frontend* fe,
+				    struct dvb_diseqc_master_cmd* cmd)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+	u8 val;
+	int i;
+	unsigned long timeout;
+	int result = 0;
+
+	dprintk("enter %s\n", __func__);
+	if (cmd->msg_len > 8)
+		return -EINVAL;
+
+	/* setup for DISEQC */
+	val = s5h1420_readreg(state, 0x3b);
+	s5h1420_writereg(state, 0x3b, 0x02);
+	msleep(15);
+
+	/* write the DISEQC command bytes */
+	for(i=0; i< cmd->msg_len; i++) {
+		s5h1420_writereg(state, 0x3d + i, cmd->msg[i]);
+	}
+
+	/* kick off transmission */
+	s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) |
+				      ((cmd->msg_len-1) << 4) | 0x08);
+
+	/* wait for transmission to complete */
+	timeout = jiffies + ((100*HZ) / 1000);
+	while(time_before(jiffies, timeout)) {
+		if (!(s5h1420_readreg(state, 0x3b) & 0x08))
+			break;
+
+		msleep(5);
+	}
+	if (time_after(jiffies, timeout))
+		result = -ETIMEDOUT;
+
+	/* restore original settings */
+	s5h1420_writereg(state, 0x3b, val);
+	msleep(15);
+	dprintk("leave %s\n", __func__);
+	return result;
+}
+
+static int s5h1420_recv_slave_reply (struct dvb_frontend* fe,
+				     struct dvb_diseqc_slave_reply* reply)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+	u8 val;
+	int i;
+	int length;
+	unsigned long timeout;
+	int result = 0;
+
+	/* setup for DISEQC receive */
+	val = s5h1420_readreg(state, 0x3b);
+	s5h1420_writereg(state, 0x3b, 0x82); /* FIXME: guess - do we need to set DIS_RDY(0x08) in receive mode? */
+	msleep(15);
+
+	/* wait for reception to complete */
+	timeout = jiffies + ((reply->timeout*HZ) / 1000);
+	while(time_before(jiffies, timeout)) {
+		if (!(s5h1420_readreg(state, 0x3b) & 0x80)) /* FIXME: do we test DIS_RDY(0x08) or RCV_EN(0x80)? */
+			break;
+
+		msleep(5);
+	}
+	if (time_after(jiffies, timeout)) {
+		result = -ETIMEDOUT;
+		goto exit;
+	}
+
+	/* check error flag - FIXME: not sure what this does - docs do not describe
+	 * beyond "error flag for diseqc receive data :( */
+	if (s5h1420_readreg(state, 0x49)) {
+		result = -EIO;
+		goto exit;
+	}
+
+	/* check length */
+	length = (s5h1420_readreg(state, 0x3b) & 0x70) >> 4;
+	if (length > sizeof(reply->msg)) {
+		result = -EOVERFLOW;
+		goto exit;
+	}
+	reply->msg_len = length;
+
+	/* extract data */
+	for(i=0; i< length; i++) {
+		reply->msg[i] = s5h1420_readreg(state, 0x3d + i);
+	}
+
+exit:
+	/* restore original settings */
+	s5h1420_writereg(state, 0x3b, val);
+	msleep(15);
+	return result;
+}
+
+static int s5h1420_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+	u8 val;
+	int result = 0;
+	unsigned long timeout;
+
+	/* setup for tone burst */
+	val = s5h1420_readreg(state, 0x3b);
+	s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x70) | 0x01);
+
+	/* set value for B position if requested */
+	if (minicmd == SEC_MINI_B) {
+		s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x04);
+	}
+	msleep(15);
+
+	/* start transmission */
+	s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x08);
+
+	/* wait for transmission to complete */
+	timeout = jiffies + ((100*HZ) / 1000);
+	while(time_before(jiffies, timeout)) {
+		if (!(s5h1420_readreg(state, 0x3b) & 0x08))
+			break;
+
+		msleep(5);
+	}
+	if (time_after(jiffies, timeout))
+		result = -ETIMEDOUT;
+
+	/* restore original settings */
+	s5h1420_writereg(state, 0x3b, val);
+	msleep(15);
+	return result;
+}
+
+static fe_status_t s5h1420_get_status_bits(struct s5h1420_state* state)
+{
+	u8 val;
+	fe_status_t status = 0;
+
+	val = s5h1420_readreg(state, 0x14);
+	if (val & 0x02)
+		status |=  FE_HAS_SIGNAL;
+	if (val & 0x01)
+		status |=  FE_HAS_CARRIER;
+	val = s5h1420_readreg(state, 0x36);
+	if (val & 0x01)
+		status |=  FE_HAS_VITERBI;
+	if (val & 0x20)
+		status |=  FE_HAS_SYNC;
+	if (status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI|FE_HAS_SYNC))
+		status |=  FE_HAS_LOCK;
+
+	return status;
+}
+
+static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+	u8 val;
+
+	dprintk("enter %s\n", __func__);
+
+	if (status == NULL)
+		return -EINVAL;
+
+	/* determine lock state */
+	*status = s5h1420_get_status_bits(state);
+
+	/* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert
+	the inversion, wait a bit and check again */
+	if (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI)) {
+		val = s5h1420_readreg(state, Vit10);
+		if ((val & 0x07) == 0x03) {
+			if (val & 0x08)
+				s5h1420_writereg(state, Vit09, 0x13);
+			else
+				s5h1420_writereg(state, Vit09, 0x1b);
+
+			/* wait a bit then update lock status */
+			mdelay(200);
+			*status = s5h1420_get_status_bits(state);
+		}
+	}
+
+	/* perform post lock setup */
+	if ((*status & FE_HAS_LOCK) && !state->postlocked) {
+
+		/* calculate the data rate */
+		u32 tmp = s5h1420_getsymbolrate(state);
+		switch (s5h1420_readreg(state, Vit10) & 0x07) {
+		case 0: tmp = (tmp * 2 * 1) / 2; break;
+		case 1: tmp = (tmp * 2 * 2) / 3; break;
+		case 2: tmp = (tmp * 2 * 3) / 4; break;
+		case 3: tmp = (tmp * 2 * 5) / 6; break;
+		case 4: tmp = (tmp * 2 * 6) / 7; break;
+		case 5: tmp = (tmp * 2 * 7) / 8; break;
+		}
+
+		if (tmp == 0) {
+			printk(KERN_ERR "s5h1420: avoided division by 0\n");
+			tmp = 1;
+		}
+		tmp = state->fclk / tmp;
+
+
+		/* set the MPEG_CLK_INTL for the calculated data rate */
+		if (tmp < 2)
+			val = 0x00;
+		else if (tmp < 5)
+			val = 0x01;
+		else if (tmp < 9)
+			val = 0x02;
+		else if (tmp < 13)
+			val = 0x03;
+		else if (tmp < 17)
+			val = 0x04;
+		else if (tmp < 25)
+			val = 0x05;
+		else if (tmp < 33)
+			val = 0x06;
+		else
+			val = 0x07;
+		dprintk("for MPEG_CLK_INTL %d %x\n", tmp, val);
+
+		s5h1420_writereg(state, FEC01, 0x18);
+		s5h1420_writereg(state, FEC01, 0x10);
+		s5h1420_writereg(state, FEC01, val);
+
+		/* Enable "MPEG_Out" */
+		val = s5h1420_readreg(state, Mpeg02);
+		s5h1420_writereg(state, Mpeg02, val | (1 << 6));
+
+		/* kicker disable */
+		val = s5h1420_readreg(state, QPSK01) & 0x7f;
+		s5h1420_writereg(state, QPSK01, val);
+
+		/* DC freeze TODO it was never activated by default or it can stay activated */
+
+		if (s5h1420_getsymbolrate(state) >= 20000000) {
+			s5h1420_writereg(state, Loop04, 0x8a);
+			s5h1420_writereg(state, Loop05, 0x6a);
+		} else {
+			s5h1420_writereg(state, Loop04, 0x58);
+			s5h1420_writereg(state, Loop05, 0x27);
+		}
+
+		/* post-lock processing has been done! */
+		state->postlocked = 1;
+	}
+
+	dprintk("leave %s\n", __func__);
+
+	return 0;
+}
+
+static int s5h1420_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+
+	s5h1420_writereg(state, 0x46, 0x1d);
+	mdelay(25);
+
+	*ber = (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47);
+
+	return 0;
+}
+
+static int s5h1420_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+
+	u8 val = s5h1420_readreg(state, 0x15);
+
+	*strength =  (u16) ((val << 8) | val);
+
+	return 0;
+}
+
+static int s5h1420_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+
+	s5h1420_writereg(state, 0x46, 0x1f);
+	mdelay(25);
+
+	*ucblocks = (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47);
+
+	return 0;
+}
+
+static void s5h1420_reset(struct s5h1420_state* state)
+{
+	dprintk("%s\n", __func__);
+	s5h1420_writereg (state, 0x01, 0x08);
+	s5h1420_writereg (state, 0x01, 0x00);
+	udelay(10);
+}
+
+static void s5h1420_setsymbolrate(struct s5h1420_state* state,
+				  struct dtv_frontend_properties *p)
+{
+	u8 v;
+	u64 val;
+
+	dprintk("enter %s\n", __func__);
+
+	val = ((u64) p->symbol_rate / 1000ULL) * (1ULL<<24);
+	if (p->symbol_rate < 29000000)
+		val *= 2;
+	do_div(val, (state->fclk / 1000));
+
+	dprintk("symbol rate register: %06llx\n", (unsigned long long)val);
+
+	v = s5h1420_readreg(state, Loop01);
+	s5h1420_writereg(state, Loop01, v & 0x7f);
+	s5h1420_writereg(state, Tnco01, val >> 16);
+	s5h1420_writereg(state, Tnco02, val >> 8);
+	s5h1420_writereg(state, Tnco03, val & 0xff);
+	s5h1420_writereg(state, Loop01,  v | 0x80);
+	dprintk("leave %s\n", __func__);
+}
+
+static u32 s5h1420_getsymbolrate(struct s5h1420_state* state)
+{
+	return state->symbol_rate;
+}
+
+static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset)
+{
+	int val;
+	u8 v;
+
+	dprintk("enter %s\n", __func__);
+
+	/* remember freqoffset is in kHz, but the chip wants the offset in Hz, so
+	 * divide fclk by 1000000 to get the correct value. */
+	val = -(int) ((freqoffset * (1<<24)) / (state->fclk / 1000000));
+
+	dprintk("phase rotator/freqoffset: %d %06x\n", freqoffset, val);
+
+	v = s5h1420_readreg(state, Loop01);
+	s5h1420_writereg(state, Loop01, v & 0xbf);
+	s5h1420_writereg(state, Pnco01, val >> 16);
+	s5h1420_writereg(state, Pnco02, val >> 8);
+	s5h1420_writereg(state, Pnco03, val & 0xff);
+	s5h1420_writereg(state, Loop01, v | 0x40);
+	dprintk("leave %s\n", __func__);
+}
+
+static int s5h1420_getfreqoffset(struct s5h1420_state* state)
+{
+	int val;
+
+	s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08);
+	val  = s5h1420_readreg(state, 0x0e) << 16;
+	val |= s5h1420_readreg(state, 0x0f) << 8;
+	val |= s5h1420_readreg(state, 0x10);
+	s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7);
+
+	if (val & 0x800000)
+		val |= 0xff000000;
+
+	/* remember freqoffset is in kHz, but the chip wants the offset in Hz, so
+	 * divide fclk by 1000000 to get the correct value. */
+	val = (((-val) * (state->fclk/1000000)) / (1<<24));
+
+	return val;
+}
+
+static void s5h1420_setfec_inversion(struct s5h1420_state* state,
+				     struct dtv_frontend_properties *p)
+{
+	u8 inversion = 0;
+	u8 vit08, vit09;
+
+	dprintk("enter %s\n", __func__);
+
+	if (p->inversion == INVERSION_OFF)
+		inversion = state->config->invert ? 0x08 : 0;
+	else if (p->inversion == INVERSION_ON)
+		inversion = state->config->invert ? 0 : 0x08;
+
+	if ((p->fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {
+		vit08 = 0x3f;
+		vit09 = 0;
+	} else {
+		switch (p->fec_inner) {
+		case FEC_1_2:
+			vit08 = 0x01; vit09 = 0x10;
+			break;
+
+		case FEC_2_3:
+			vit08 = 0x02; vit09 = 0x11;
+			break;
+
+		case FEC_3_4:
+			vit08 = 0x04; vit09 = 0x12;
+			break;
+
+		case FEC_5_6:
+			vit08 = 0x08; vit09 = 0x13;
+			break;
+
+		case FEC_6_7:
+			vit08 = 0x10; vit09 = 0x14;
+			break;
+
+		case FEC_7_8:
+			vit08 = 0x20; vit09 = 0x15;
+			break;
+
+		default:
+			return;
+		}
+	}
+	vit09 |= inversion;
+	dprintk("fec: %02x %02x\n", vit08, vit09);
+	s5h1420_writereg(state, Vit08, vit08);
+	s5h1420_writereg(state, Vit09, vit09);
+	dprintk("leave %s\n", __func__);
+}
+
+static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state)
+{
+	switch(s5h1420_readreg(state, 0x32) & 0x07) {
+	case 0:
+		return FEC_1_2;
+
+	case 1:
+		return FEC_2_3;
+
+	case 2:
+		return FEC_3_4;
+
+	case 3:
+		return FEC_5_6;
+
+	case 4:
+		return FEC_6_7;
+
+	case 5:
+		return FEC_7_8;
+	}
+
+	return FEC_NONE;
+}
+
+static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state)
+{
+	if (s5h1420_readreg(state, 0x32) & 0x08)
+		return INVERSION_ON;
+
+	return INVERSION_OFF;
+}
+
+static int s5h1420_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct s5h1420_state* state = fe->demodulator_priv;
+	int frequency_delta;
+	struct dvb_frontend_tune_settings fesettings;
+
+	dprintk("enter %s\n", __func__);
+
+	/* check if we should do a fast-tune */
+	s5h1420_get_tune_settings(fe, &fesettings);
+	frequency_delta = p->frequency - state->tunedfreq;
+	if ((frequency_delta > -fesettings.max_drift) &&
+			(frequency_delta < fesettings.max_drift) &&
+			(frequency_delta != 0) &&
+			(state->fec_inner == p->fec_inner) &&
+			(state->symbol_rate == p->symbol_rate)) {
+
+		if (fe->ops.tuner_ops.set_params) {
+			fe->ops.tuner_ops.set_params(fe);
+			if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+		if (fe->ops.tuner_ops.get_frequency) {
+			u32 tmp;
+			fe->ops.tuner_ops.get_frequency(fe, &tmp);
+			if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+			s5h1420_setfreqoffset(state, p->frequency - tmp);
+		} else {
+			s5h1420_setfreqoffset(state, 0);
+		}
+		dprintk("simple tune\n");
+		return 0;
+	}
+	dprintk("tuning demod\n");
+
+	/* first of all, software reset */
+	s5h1420_reset(state);
+
+	/* set s5h1420 fclk PLL according to desired symbol rate */
+	if (p->symbol_rate > 33000000)
+		state->fclk = 80000000;
+	else if (p->symbol_rate > 28500000)
+		state->fclk = 59000000;
+	else if (p->symbol_rate > 25000000)
+		state->fclk = 86000000;
+	else if (p->symbol_rate > 1900000)
+		state->fclk = 88000000;
+	else
+		state->fclk = 44000000;
+
+	dprintk("pll01: %d, ToneFreq: %d\n", state->fclk/1000000 - 8, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
+	s5h1420_writereg(state, PLL01, state->fclk/1000000 - 8);
+	s5h1420_writereg(state, PLL02, 0x40);
+	s5h1420_writereg(state, DiS01, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
+
+	/* TODO DC offset removal, config parameter ? */
+	if (p->symbol_rate > 29000000)
+		s5h1420_writereg(state, QPSK01, 0xae | 0x10);
+	else
+		s5h1420_writereg(state, QPSK01, 0xac | 0x10);
+
+	/* set misc registers */
+	s5h1420_writereg(state, CON_1, 0x00);
+	s5h1420_writereg(state, QPSK02, 0x00);
+	s5h1420_writereg(state, Pre01, 0xb0);
+
+	s5h1420_writereg(state, Loop01, 0xF0);
+	s5h1420_writereg(state, Loop02, 0x2a); /* e7 for s5h1420 */
+	s5h1420_writereg(state, Loop03, 0x79); /* 78 for s5h1420 */
+	if (p->symbol_rate > 20000000)
+		s5h1420_writereg(state, Loop04, 0x79);
+	else
+		s5h1420_writereg(state, Loop04, 0x58);
+	s5h1420_writereg(state, Loop05, 0x6b);
+
+	if (p->symbol_rate >= 8000000)
+		s5h1420_writereg(state, Post01, (0 << 6) | 0x10);
+	else if (p->symbol_rate >= 4000000)
+		s5h1420_writereg(state, Post01, (1 << 6) | 0x10);
+	else
+		s5h1420_writereg(state, Post01, (3 << 6) | 0x10);
+
+	s5h1420_writereg(state, Monitor12, 0x00); /* unfreeze DC compensation */
+
+	s5h1420_writereg(state, Sync01, 0x33);
+	s5h1420_writereg(state, Mpeg01, state->config->cdclk_polarity);
+	s5h1420_writereg(state, Mpeg02, 0x3d); /* Parallel output more, disabled -> enabled later */
+	s5h1420_writereg(state, Err01, 0x03); /* 0x1d for s5h1420 */
+
+	s5h1420_writereg(state, Vit06, 0x6e); /* 0x8e for s5h1420 */
+	s5h1420_writereg(state, DiS03, 0x00);
+	s5h1420_writereg(state, Rf01, 0x61); /* Tuner i2c address - for the gate controller */
+
+	/* set tuner PLL */
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+		s5h1420_setfreqoffset(state, 0);
+	}
+
+	/* set the reset of the parameters */
+	s5h1420_setsymbolrate(state, p);
+	s5h1420_setfec_inversion(state, p);
+
+	/* start QPSK */
+	s5h1420_writereg(state, QPSK01, s5h1420_readreg(state, QPSK01) | 1);
+
+	state->fec_inner = p->fec_inner;
+	state->symbol_rate = p->symbol_rate;
+	state->postlocked = 0;
+	state->tunedfreq = p->frequency;
+
+	dprintk("leave %s\n", __func__);
+	return 0;
+}
+
+static int s5h1420_get_frontend(struct dvb_frontend* fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct s5h1420_state* state = fe->demodulator_priv;
+
+	p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state);
+	p->inversion = s5h1420_getinversion(state);
+	p->symbol_rate = s5h1420_getsymbolrate(state);
+	p->fec_inner = s5h1420_getfec(state);
+
+	return 0;
+}
+
+static int s5h1420_get_tune_settings(struct dvb_frontend* fe,
+				     struct dvb_frontend_tune_settings* fesettings)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	if (p->symbol_rate > 20000000) {
+		fesettings->min_delay_ms = 50;
+		fesettings->step_size = 2000;
+		fesettings->max_drift = 8000;
+	} else if (p->symbol_rate > 12000000) {
+		fesettings->min_delay_ms = 100;
+		fesettings->step_size = 1500;
+		fesettings->max_drift = 9000;
+	} else if (p->symbol_rate > 8000000) {
+		fesettings->min_delay_ms = 100;
+		fesettings->step_size = 1000;
+		fesettings->max_drift = 8000;
+	} else if (p->symbol_rate > 4000000) {
+		fesettings->min_delay_ms = 100;
+		fesettings->step_size = 500;
+		fesettings->max_drift = 7000;
+	} else if (p->symbol_rate > 2000000) {
+		fesettings->min_delay_ms = 200;
+		fesettings->step_size = (p->symbol_rate / 8000);
+		fesettings->max_drift = 14 * fesettings->step_size;
+	} else {
+		fesettings->min_delay_ms = 200;
+		fesettings->step_size = (p->symbol_rate / 8000);
+		fesettings->max_drift = 18 * fesettings->step_size;
+	}
+
+	return 0;
+}
+
+static int s5h1420_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+
+	if (enable)
+		return s5h1420_writereg(state, 0x02, state->CON_1_val | 1);
+	else
+		return s5h1420_writereg(state, 0x02, state->CON_1_val & 0xfe);
+}
+
+static int s5h1420_init (struct dvb_frontend* fe)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+
+	/* disable power down and do reset */
+	state->CON_1_val = state->config->serial_mpeg << 4;
+	s5h1420_writereg(state, 0x02, state->CON_1_val);
+	msleep(10);
+	s5h1420_reset(state);
+
+	return 0;
+}
+
+static int s5h1420_sleep(struct dvb_frontend* fe)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+	state->CON_1_val = 0x12;
+	return s5h1420_writereg(state, 0x02, state->CON_1_val);
+}
+
+static void s5h1420_release(struct dvb_frontend* fe)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+	i2c_del_adapter(&state->tuner_i2c_adapter);
+	kfree(state);
+}
+
+static u32 s5h1420_tuner_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static int s5h1420_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+	struct s5h1420_state *state = i2c_get_adapdata(i2c_adap);
+	struct i2c_msg m[1 + num];
+	u8 tx_open[2] = { CON_1, state->CON_1_val | 1 }; /* repeater stops once there was a stop condition */
+
+	memset(m, 0, sizeof(struct i2c_msg) * (1 + num));
+
+	m[0].addr = state->config->demod_address;
+	m[0].buf  = tx_open;
+	m[0].len  = 2;
+
+	memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
+
+	return i2c_transfer(state->i2c, m, 1+num) == 1 + num ? num : -EIO;
+}
+
+static struct i2c_algorithm s5h1420_tuner_i2c_algo = {
+	.master_xfer   = s5h1420_tuner_i2c_tuner_xfer,
+	.functionality = s5h1420_tuner_i2c_func,
+};
+
+struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+	struct s5h1420_state *state = fe->demodulator_priv;
+	return &state->tuner_i2c_adapter;
+}
+EXPORT_SYMBOL(s5h1420_get_tuner_i2c_adapter);
+
+static struct dvb_frontend_ops s5h1420_ops;
+
+struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
+				    struct i2c_adapter *i2c)
+{
+	/* allocate memory for the internal state */
+	struct s5h1420_state *state = kzalloc(sizeof(struct s5h1420_state), GFP_KERNEL);
+	u8 i;
+
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->postlocked = 0;
+	state->fclk = 88000000;
+	state->tunedfreq = 0;
+	state->fec_inner = FEC_NONE;
+	state->symbol_rate = 0;
+
+	/* check if the demod is there + identify it */
+	i = s5h1420_readreg(state, ID01);
+	if (i != 0x03)
+		goto error;
+
+	memset(state->shadow, 0xff, sizeof(state->shadow));
+
+	for (i = 0; i < 0x50; i++)
+		state->shadow[i] = s5h1420_readreg(state, i);
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	/* create tuner i2c adapter */
+	strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus",
+		sizeof(state->tuner_i2c_adapter.name));
+	state->tuner_i2c_adapter.algo      = &s5h1420_tuner_i2c_algo;
+	state->tuner_i2c_adapter.algo_data = NULL;
+	i2c_set_adapdata(&state->tuner_i2c_adapter, state);
+	if (i2c_add_adapter(&state->tuner_i2c_adapter) < 0) {
+		printk(KERN_ERR "S5H1420/PN1010: tuner i2c bus could not be initialized\n");
+		goto error;
+	}
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(s5h1420_attach);
+
+static struct dvb_frontend_ops s5h1420_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name     = "Samsung S5H1420/PnpNetwork PN1010 DVB-S",
+		.frequency_min    = 950000,
+		.frequency_max    = 2150000,
+		.frequency_stepsize = 125,     /* kHz for QPSK frontends */
+		.frequency_tolerance  = 29500,
+		.symbol_rate_min  = 1000000,
+		.symbol_rate_max  = 45000000,
+		/*  .symbol_rate_tolerance  = ???,*/
+		.caps = FE_CAN_INVERSION_AUTO |
+		FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+		FE_CAN_QPSK
+	},
+
+	.release = s5h1420_release,
+
+	.init = s5h1420_init,
+	.sleep = s5h1420_sleep,
+	.i2c_gate_ctrl = s5h1420_i2c_gate_ctrl,
+
+	.set_frontend = s5h1420_set_frontend,
+	.get_frontend = s5h1420_get_frontend,
+	.get_tune_settings = s5h1420_get_tune_settings,
+
+	.read_status = s5h1420_read_status,
+	.read_ber = s5h1420_read_ber,
+	.read_signal_strength = s5h1420_read_signal_strength,
+	.read_ucblocks = s5h1420_read_ucblocks,
+
+	.diseqc_send_master_cmd = s5h1420_send_master_cmd,
+	.diseqc_recv_slave_reply = s5h1420_recv_slave_reply,
+	.diseqc_send_burst = s5h1420_send_burst,
+	.set_tone = s5h1420_set_tone,
+	.set_voltage = s5h1420_set_voltage,
+};
+
+MODULE_DESCRIPTION("Samsung S5H1420/PnpNetwork PN1010 DVB-S Demodulator driver");
+MODULE_AUTHOR("Andrew de Quincey, Patrick Boettcher");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/s5h1420.h b/drivers/media/dvb-frontends/s5h1420.h
new file mode 100644
index 0000000..ff30813
--- /dev/null
+++ b/drivers/media/dvb-frontends/s5h1420.h
@@ -0,0 +1,61 @@
+/*
+ * Driver for
+ *    Samsung S5H1420 and
+ *    PnpNetwork PN1010 QPSK Demodulator
+ *
+ * Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
+ * Copyright (C) 2005-8 Patrick Boettcher <pb@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef S5H1420_H
+#define S5H1420_H
+
+#include <linux/dvb/frontend.h>
+
+struct s5h1420_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* does the inversion require inversion? */
+	u8 invert:1;
+
+	u8 repeated_start_workaround:1;
+	u8 cdclk_polarity:1; /* 1 == falling edge, 0 == raising edge */
+
+	u8 serial_mpeg:1;
+};
+
+#if defined(CONFIG_DVB_S5H1420) || (defined(CONFIG_DVB_S5H1420_MODULE) && defined(MODULE))
+extern struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
+	     struct i2c_adapter *i2c);
+extern struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe);
+#else
+static inline struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
+					   struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+	return NULL;
+}
+#endif // CONFIG_DVB_S5H1420
+
+#endif // S5H1420_H
diff --git a/drivers/media/dvb-frontends/s5h1420_priv.h b/drivers/media/dvb-frontends/s5h1420_priv.h
new file mode 100644
index 0000000..d9c58d2
--- /dev/null
+++ b/drivers/media/dvb-frontends/s5h1420_priv.h
@@ -0,0 +1,102 @@
+/*
+ * Driver for
+ *    Samsung S5H1420 and
+ *    PnpNetwork PN1010 QPSK Demodulator
+ *
+ * Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
+ * Copyright (C) 2005 Patrick Boettcher <pb@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+ * Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef S5H1420_PRIV
+#define S5H1420_PRIV
+
+#include <asm/types.h>
+
+enum s5h1420_register {
+	ID01      = 0x00,
+	CON_0     = 0x01,
+	CON_1     = 0x02,
+	PLL01     = 0x03,
+	PLL02     = 0x04,
+	QPSK01    = 0x05,
+	QPSK02    = 0x06,
+	Pre01     = 0x07,
+	Post01    = 0x08,
+	Loop01    = 0x09,
+	Loop02    = 0x0a,
+	Loop03    = 0x0b,
+	Loop04    = 0x0c,
+	Loop05    = 0x0d,
+	Pnco01    = 0x0e,
+	Pnco02    = 0x0f,
+	Pnco03    = 0x10,
+	Tnco01    = 0x11,
+	Tnco02    = 0x12,
+	Tnco03    = 0x13,
+	Monitor01 = 0x14,
+	Monitor02 = 0x15,
+	Monitor03 = 0x16,
+	Monitor04 = 0x17,
+	Monitor05 = 0x18,
+	Monitor06 = 0x19,
+	Monitor07 = 0x1a,
+	Monitor12 = 0x1f,
+
+	FEC01     = 0x22,
+	Soft01    = 0x23,
+	Soft02    = 0x24,
+	Soft03    = 0x25,
+	Soft04    = 0x26,
+	Soft05    = 0x27,
+	Soft06    = 0x28,
+	Vit01     = 0x29,
+	Vit02     = 0x2a,
+	Vit03     = 0x2b,
+	Vit04     = 0x2c,
+	Vit05     = 0x2d,
+	Vit06     = 0x2e,
+	Vit07     = 0x2f,
+	Vit08     = 0x30,
+	Vit09     = 0x31,
+	Vit10     = 0x32,
+	Vit11     = 0x33,
+	Vit12     = 0x34,
+	Sync01    = 0x35,
+	Sync02    = 0x36,
+	Rs01      = 0x37,
+	Mpeg01    = 0x38,
+	Mpeg02    = 0x39,
+	DiS01     = 0x3a,
+	DiS02     = 0x3b,
+	DiS03     = 0x3c,
+	DiS04     = 0x3d,
+	DiS05     = 0x3e,
+	DiS06     = 0x3f,
+	DiS07     = 0x40,
+	DiS08     = 0x41,
+	DiS09     = 0x42,
+	DiS10     = 0x43,
+	DiS11     = 0x44,
+	Rf01      = 0x45,
+	Err01     = 0x46,
+	Err02     = 0x47,
+	Err03     = 0x48,
+	Err04     = 0x49,
+};
+
+
+#endif
diff --git a/drivers/media/dvb-frontends/s5h1432.c b/drivers/media/dvb-frontends/s5h1432.c
new file mode 100644
index 0000000..8352ce1
--- /dev/null
+++ b/drivers/media/dvb-frontends/s5h1432.c
@@ -0,0 +1,407 @@
+/*
+ *  Samsung s5h1432 DVB-T demodulator driver
+ *
+ *  Copyright (C) 2009 Bill Liu <Bill.Liu@Conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "s5h1432.h"
+
+struct s5h1432_state {
+
+	struct i2c_adapter *i2c;
+
+	/* configuration settings */
+	const struct s5h1432_config *config;
+
+	struct dvb_frontend frontend;
+
+	fe_modulation_t current_modulation;
+	unsigned int first_tune:1;
+
+	u32 current_frequency;
+	int if_freq;
+
+	u8 inversion;
+};
+
+static int debug;
+
+#define dprintk(arg...) do {	\
+	if (debug)		\
+		printk(arg);	\
+	} while (0)
+
+static int s5h1432_writereg(struct s5h1432_state *state,
+			    u8 addr, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf[] = { reg, data };
+
+	struct i2c_msg msg = {.addr = addr, .flags = 0, .buf = buf, .len = 2 };
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, "
+		       "ret == %i)\n", __func__, addr, reg, data, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+
+static u8 s5h1432_readreg(struct s5h1432_state *state, u8 addr, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+
+	struct i2c_msg msg[] = {
+		{.addr = addr, .flags = 0, .buf = b0, .len = 1},
+		{.addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 1}
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+		       __func__, ret);
+	return b1[0];
+}
+
+static int s5h1432_sleep(struct dvb_frontend *fe)
+{
+	return 0;
+}
+
+static int s5h1432_set_channel_bandwidth(struct dvb_frontend *fe,
+					 u32 bandwidth)
+{
+	struct s5h1432_state *state = fe->demodulator_priv;
+
+	u8 reg = 0;
+
+	/* Register [0x2E] bit 3:2 : 8MHz = 0; 7MHz = 1; 6MHz = 2 */
+	reg = s5h1432_readreg(state, S5H1432_I2C_TOP_ADDR, 0x2E);
+	reg &= ~(0x0C);
+	switch (bandwidth) {
+	case 6:
+		reg |= 0x08;
+		break;
+	case 7:
+		reg |= 0x04;
+		break;
+	case 8:
+		reg |= 0x00;
+		break;
+	default:
+		return 0;
+	}
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x2E, reg);
+	return 1;
+}
+
+static int s5h1432_set_IF(struct dvb_frontend *fe, u32 ifFreqHz)
+{
+	struct s5h1432_state *state = fe->demodulator_priv;
+
+	switch (ifFreqHz) {
+	case TAIWAN_HI_IF_FREQ_44_MHZ:
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x55);
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x55);
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0x15);
+		break;
+	case EUROPE_HI_IF_FREQ_36_MHZ:
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x00);
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x00);
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0x40);
+		break;
+	case IF_FREQ_6_MHZ:
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x00);
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x00);
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xe0);
+		break;
+	case IF_FREQ_3point3_MHZ:
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x66);
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x66);
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEE);
+		break;
+	case IF_FREQ_3point5_MHZ:
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x55);
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x55);
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xED);
+		break;
+	case IF_FREQ_4_MHZ:
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0xAA);
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0xAA);
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEA);
+		break;
+	default:
+		{
+			u32 value = 0;
+			value = (u32) (((48000 - (ifFreqHz / 1000)) * 512 *
+					(u32) 32768) / (48 * 1000));
+			printk(KERN_INFO
+			       "Default IFFreq %d :reg value = 0x%x\n",
+			       ifFreqHz, value);
+			s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4,
+					 (u8) value & 0xFF);
+			s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5,
+					 (u8) (value >> 8) & 0xFF);
+			s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7,
+					 (u8) (value >> 16) & 0xFF);
+			break;
+		}
+
+	}
+
+	return 1;
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int s5h1432_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	u32 dvb_bandwidth = 8;
+	struct s5h1432_state *state = fe->demodulator_priv;
+
+	if (p->frequency == state->current_frequency) {
+		/*current_frequency = p->frequency; */
+		/*state->current_frequency = p->frequency; */
+	} else {
+		fe->ops.tuner_ops.set_params(fe);
+		msleep(300);
+		s5h1432_set_channel_bandwidth(fe, dvb_bandwidth);
+		switch (p->bandwidth_hz) {
+		case 6000000:
+			dvb_bandwidth = 6;
+			s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+			break;
+		case 7000000:
+			dvb_bandwidth = 7;
+			s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+			break;
+		case 8000000:
+			dvb_bandwidth = 8;
+			s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+			break;
+		default:
+			return 0;
+		}
+		/*fe->ops.tuner_ops.set_params(fe); */
+/*Soft Reset chip*/
+		msleep(30);
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
+		msleep(30);
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
+
+		s5h1432_set_channel_bandwidth(fe, dvb_bandwidth);
+		switch (p->bandwidth_hz) {
+		case 6000000:
+			dvb_bandwidth = 6;
+			s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+			break;
+		case 7000000:
+			dvb_bandwidth = 7;
+			s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+			break;
+		case 8000000:
+			dvb_bandwidth = 8;
+			s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+			break;
+		default:
+			return 0;
+		}
+		/*fe->ops.tuner_ops.set_params(fe); */
+		/*Soft Reset chip*/
+		msleep(30);
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
+		msleep(30);
+		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
+
+	}
+
+	state->current_frequency = p->frequency;
+
+	return 0;
+}
+
+static int s5h1432_init(struct dvb_frontend *fe)
+{
+	struct s5h1432_state *state = fe->demodulator_priv;
+
+	u8 reg = 0;
+	state->current_frequency = 0;
+	printk(KERN_INFO " s5h1432_init().\n");
+
+	/*Set VSB mode as default, this also does a soft reset */
+	/*Initialize registers */
+
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x04, 0xa8);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x05, 0x01);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x07, 0x70);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x19, 0x80);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1b, 0x9D);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1c, 0x30);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1d, 0x20);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1e, 0x1B);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x2e, 0x40);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x42, 0x84);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x50, 0x5a);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x5a, 0xd3);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x68, 0x50);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xb8, 0x3c);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xc4, 0x10);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xcc, 0x9c);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xDA, 0x00);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe1, 0x94);
+	/* s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xf4, 0xa1); */
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xf9, 0x00);
+
+	/*For NXP tuner*/
+
+	/*Set 3.3MHz as default IF frequency */
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x66);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x66);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEE);
+	/* Set reg 0x1E to get the full dynamic range */
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1e, 0x31);
+
+	/* Mode setting in demod */
+	reg = s5h1432_readreg(state, S5H1432_I2C_TOP_ADDR, 0x42);
+	reg |= 0x80;
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x42, reg);
+	/* Serial mode */
+
+	/* Soft Reset chip */
+
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
+	msleep(30);
+	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
+
+
+	return 0;
+}
+
+static int s5h1432_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	return 0;
+}
+
+static int s5h1432_read_signal_strength(struct dvb_frontend *fe,
+					u16 *signal_strength)
+{
+	return 0;
+}
+
+static int s5h1432_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	return 0;
+}
+
+static int s5h1432_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+
+	return 0;
+}
+
+static int s5h1432_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	return 0;
+}
+
+static int s5h1432_get_tune_settings(struct dvb_frontend *fe,
+				     struct dvb_frontend_tune_settings *tune)
+{
+	return 0;
+}
+
+static void s5h1432_release(struct dvb_frontend *fe)
+{
+	struct s5h1432_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops s5h1432_ops;
+
+struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct s5h1432_state *state = NULL;
+
+	printk(KERN_INFO " Enter s5h1432_attach(). attach success!\n");
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct s5h1432_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->current_modulation = QAM_16;
+	state->inversion = state->config->inversion;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &s5h1432_ops,
+	       sizeof(struct dvb_frontend_ops));
+
+	state->frontend.demodulator_priv = state;
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(s5h1432_attach);
+
+static struct dvb_frontend_ops s5h1432_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		 .name = "Samsung s5h1432 DVB-T Frontend",
+		 .frequency_min = 177000000,
+		 .frequency_max = 858000000,
+		 .frequency_stepsize = 166666,
+		 .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+		 FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER},
+
+	.init = s5h1432_init,
+	.sleep = s5h1432_sleep,
+	.set_frontend = s5h1432_set_frontend,
+	.get_tune_settings = s5h1432_get_tune_settings,
+	.read_status = s5h1432_read_status,
+	.read_ber = s5h1432_read_ber,
+	.read_signal_strength = s5h1432_read_signal_strength,
+	.read_snr = s5h1432_read_snr,
+	.read_ucblocks = s5h1432_read_ucblocks,
+	.release = s5h1432_release,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Samsung s5h1432 DVB-T Demodulator driver");
+MODULE_AUTHOR("Bill Liu");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/s5h1432.h b/drivers/media/dvb-frontends/s5h1432.h
new file mode 100644
index 0000000..b57438c
--- /dev/null
+++ b/drivers/media/dvb-frontends/s5h1432.h
@@ -0,0 +1,91 @@
+/*
+ *  Samsung s5h1432 VSB/QAM demodulator driver
+ *
+ *  Copyright (C) 2009 Bill Liu <Bill.Liu@Conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __S5H1432_H__
+#define __S5H1432_H__
+
+#include <linux/dvb/frontend.h>
+
+#define S5H1432_I2C_TOP_ADDR (0x02 >> 1)
+
+#define TAIWAN_HI_IF_FREQ_44_MHZ 44000000
+#define EUROPE_HI_IF_FREQ_36_MHZ 36000000
+#define IF_FREQ_6_MHZ             6000000
+#define IF_FREQ_3point3_MHZ       3300000
+#define IF_FREQ_3point5_MHZ       3500000
+#define IF_FREQ_4_MHZ             4000000
+
+struct s5h1432_config {
+
+	/* serial/parallel output */
+#define S5H1432_PARALLEL_OUTPUT 0
+#define S5H1432_SERIAL_OUTPUT   1
+	u8 output_mode;
+
+	/* GPIO Setting */
+#define S5H1432_GPIO_OFF 0
+#define S5H1432_GPIO_ON  1
+	u8 gpio;
+
+	/* MPEG signal timing */
+#define S5H1432_MPEGTIMING_CONTINOUS_INVERTING_CLOCK       0
+#define S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK    1
+#define S5H1432_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK    2
+#define S5H1432_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
+	u16 mpeg_timing;
+
+	/* IF Freq for QAM and VSB in KHz */
+#define S5H1432_IF_3250  3250
+#define S5H1432_IF_3500  3500
+#define S5H1432_IF_4000  4000
+#define S5H1432_IF_5380  5380
+#define S5H1432_IF_44000 44000
+#define S5H1432_VSB_IF_DEFAULT s5h1432_IF_44000
+#define S5H1432_QAM_IF_DEFAULT s5h1432_IF_44000
+	u16 qam_if;
+	u16 vsb_if;
+
+	/* Spectral Inversion */
+#define S5H1432_INVERSION_OFF 0
+#define S5H1432_INVERSION_ON  1
+	u8 inversion;
+
+	/* Return lock status based on tuner lock, or demod lock */
+#define S5H1432_TUNERLOCKING 0
+#define S5H1432_DEMODLOCKING 1
+	u8 status_mode;
+};
+
+#if defined(CONFIG_DVB_S5H1432) || \
+	(defined(CONFIG_DVB_S5H1432_MODULE) && defined(MODULE))
+extern struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config,
+					   struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *s5h1432_attach(const struct s5h1432_config
+						  *config,
+						  struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_s5h1432 */
+
+#endif /* __s5h1432_H__ */
diff --git a/drivers/media/dvb-frontends/s921.c b/drivers/media/dvb-frontends/s921.c
new file mode 100644
index 0000000..cd2288c
--- /dev/null
+++ b/drivers/media/dvb-frontends/s921.c
@@ -0,0 +1,549 @@
+/*
+ *   Sharp VA3A5JZ921 One Seg Broadcast Module driver
+ *   This device is labeled as just S. 921 at the top of the frontend can
+ *
+ *   Copyright (C) 2009-2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *   Copyright (C) 2009-2010 Douglas Landgraf <dougsland@redhat.com>
+ *
+ *   Developed for Leadership SBTVD 1seg device sold in Brazil
+ *
+ *   Frontend module based on cx24123 driver, getting some info from
+ *	the old s921 driver.
+ *
+ *   FIXME: Need to port to DVB v5.2 API
+ *
+ *   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 version 2.
+ *
+ *   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 <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "s921.h"
+
+static int debug = 1;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+#define rc(args...)  do {						\
+	printk(KERN_ERR  "s921: " args);				\
+} while (0)
+
+#define dprintk(args...)						\
+	do {								\
+		if (debug) {						\
+			printk(KERN_DEBUG "s921: %s: ", __func__);	\
+			printk(args);					\
+		}							\
+	} while (0)
+
+struct s921_state {
+	struct i2c_adapter *i2c;
+	const struct s921_config *config;
+
+	struct dvb_frontend frontend;
+
+	/* The Demod can't easily provide these, we cache them */
+	u32 currentfreq;
+};
+
+/*
+ * Various tuner defaults need to be established for a given frequency kHz.
+ * fixme: The bounds on the bands do not match the doc in real life.
+ * fixme: Some of them have been moved, other might need adjustment.
+ */
+static struct s921_bandselect_val {
+	u32 freq_low;
+	u8  band_reg;
+} s921_bandselect[] = {
+	{         0, 0x7b },
+	{ 485140000, 0x5b },
+	{ 515140000, 0x3b },
+	{ 545140000, 0x1b },
+	{ 599140000, 0xfb },
+	{ 623140000, 0xdb },
+	{ 659140000, 0xbb },
+	{ 713140000, 0x9b },
+};
+
+struct regdata {
+	u8 reg;
+	u8 data;
+};
+
+static struct regdata s921_init[] = {
+	{ 0x01, 0x80 },		/* Probably, a reset sequence */
+	{ 0x01, 0x40 },
+	{ 0x01, 0x80 },
+	{ 0x01, 0x40 },
+
+	{ 0x02, 0x00 },
+	{ 0x03, 0x40 },
+	{ 0x04, 0x01 },
+	{ 0x05, 0x00 },
+	{ 0x06, 0x00 },
+	{ 0x07, 0x00 },
+	{ 0x08, 0x00 },
+	{ 0x09, 0x00 },
+	{ 0x0a, 0x00 },
+	{ 0x0b, 0x5a },
+	{ 0x0c, 0x00 },
+	{ 0x0d, 0x00 },
+	{ 0x0f, 0x00 },
+	{ 0x13, 0x1b },
+	{ 0x14, 0x80 },
+	{ 0x15, 0x40 },
+	{ 0x17, 0x70 },
+	{ 0x18, 0x01 },
+	{ 0x19, 0x12 },
+	{ 0x1a, 0x01 },
+	{ 0x1b, 0x12 },
+	{ 0x1c, 0xa0 },
+	{ 0x1d, 0x00 },
+	{ 0x1e, 0x0a },
+	{ 0x1f, 0x08 },
+	{ 0x20, 0x40 },
+	{ 0x21, 0xff },
+	{ 0x22, 0x4c },
+	{ 0x23, 0x4e },
+	{ 0x24, 0x4c },
+	{ 0x25, 0x00 },
+	{ 0x26, 0x00 },
+	{ 0x27, 0xf4 },
+	{ 0x28, 0x60 },
+	{ 0x29, 0x88 },
+	{ 0x2a, 0x40 },
+	{ 0x2b, 0x40 },
+	{ 0x2c, 0xff },
+	{ 0x2d, 0x00 },
+	{ 0x2e, 0xff },
+	{ 0x2f, 0x00 },
+	{ 0x30, 0x20 },
+	{ 0x31, 0x06 },
+	{ 0x32, 0x0c },
+	{ 0x34, 0x0f },
+	{ 0x37, 0xfe },
+	{ 0x38, 0x00 },
+	{ 0x39, 0x63 },
+	{ 0x3a, 0x10 },
+	{ 0x3b, 0x10 },
+	{ 0x47, 0x00 },
+	{ 0x49, 0xe5 },
+	{ 0x4b, 0x00 },
+	{ 0x50, 0xc0 },
+	{ 0x52, 0x20 },
+	{ 0x54, 0x5a },
+	{ 0x55, 0x5b },
+	{ 0x56, 0x40 },
+	{ 0x57, 0x70 },
+	{ 0x5c, 0x50 },
+	{ 0x5d, 0x00 },
+	{ 0x62, 0x17 },
+	{ 0x63, 0x2f },
+	{ 0x64, 0x6f },
+	{ 0x68, 0x00 },
+	{ 0x69, 0x89 },
+	{ 0x6a, 0x00 },
+	{ 0x6b, 0x00 },
+	{ 0x6c, 0x00 },
+	{ 0x6d, 0x00 },
+	{ 0x6e, 0x00 },
+	{ 0x70, 0x10 },
+	{ 0x71, 0x00 },
+	{ 0x75, 0x00 },
+	{ 0x76, 0x30 },
+	{ 0x77, 0x01 },
+	{ 0xaf, 0x00 },
+	{ 0xb0, 0xa0 },
+	{ 0xb2, 0x3d },
+	{ 0xb3, 0x25 },
+	{ 0xb4, 0x8b },
+	{ 0xb5, 0x4b },
+	{ 0xb6, 0x3f },
+	{ 0xb7, 0xff },
+	{ 0xb8, 0xff },
+	{ 0xb9, 0xfc },
+	{ 0xba, 0x00 },
+	{ 0xbb, 0x00 },
+	{ 0xbc, 0x00 },
+	{ 0xd0, 0x30 },
+	{ 0xe4, 0x84 },
+	{ 0xf0, 0x48 },
+	{ 0xf1, 0x19 },
+	{ 0xf2, 0x5a },
+	{ 0xf3, 0x8e },
+	{ 0xf4, 0x2d },
+	{ 0xf5, 0x07 },
+	{ 0xf6, 0x5a },
+	{ 0xf7, 0xba },
+	{ 0xf8, 0xd7 },
+};
+
+static struct regdata s921_prefreq[] = {
+	{ 0x47, 0x60 },
+	{ 0x68, 0x00 },
+	{ 0x69, 0x89 },
+	{ 0xf0, 0x48 },
+	{ 0xf1, 0x19 },
+};
+
+static struct regdata s921_postfreq[] = {
+	{ 0xf5, 0xae },
+	{ 0xf6, 0xb7 },
+	{ 0xf7, 0xba },
+	{ 0xf8, 0xd7 },
+	{ 0x68, 0x0a },
+	{ 0x69, 0x09 },
+};
+
+static int s921_i2c_writereg(struct s921_state *state,
+			     u8 i2c_addr, int reg, int data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = {
+		.addr = i2c_addr, .flags = 0, .buf = buf, .len = 2
+	};
+	int rc;
+
+	rc = i2c_transfer(state->i2c, &msg, 1);
+	if (rc != 1) {
+		printk("%s: writereg rcor(rc == %i, reg == 0x%02x,"
+			 " data == 0x%02x)\n", __func__, rc, reg, data);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int s921_i2c_writeregdata(struct s921_state *state, u8 i2c_addr,
+				 struct regdata *rd, int size)
+{
+	int i, rc;
+
+	for (i = 0; i < size; i++) {
+		rc = s921_i2c_writereg(state, i2c_addr, rd[i].reg, rd[i].data);
+		if (rc < 0)
+			return rc;
+	}
+	return 0;
+}
+
+static int s921_i2c_readreg(struct s921_state *state, u8 i2c_addr, u8 reg)
+{
+	u8 val;
+	int rc;
+	struct i2c_msg msg[] = {
+		{ .addr = i2c_addr, .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
+	};
+
+	rc = i2c_transfer(state->i2c, msg, 2);
+
+	if (rc != 2) {
+		rc("%s: reg=0x%x (rcor=%d)\n", __func__, reg, rc);
+		return rc;
+	}
+
+	return val;
+}
+
+#define s921_readreg(state, reg) \
+	s921_i2c_readreg(state, state->config->demod_address, reg)
+#define s921_writereg(state, reg, val) \
+	s921_i2c_writereg(state, state->config->demod_address, reg, val)
+#define s921_writeregdata(state, regdata) \
+	s921_i2c_writeregdata(state, state->config->demod_address, \
+	regdata, ARRAY_SIZE(regdata))
+
+static int s921_pll_tune(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct s921_state *state = fe->demodulator_priv;
+	int band, rc, i;
+	unsigned long f_offset;
+	u8 f_switch;
+	u64 offset;
+
+	dprintk("frequency=%i\n", p->frequency);
+
+	for (band = 0; band < ARRAY_SIZE(s921_bandselect); band++)
+		if (p->frequency < s921_bandselect[band].freq_low)
+			break;
+	band--;
+
+	if (band < 0) {
+		rc("%s: frequency out of range\n", __func__);
+		return -EINVAL;
+	}
+
+	f_switch = s921_bandselect[band].band_reg;
+
+	offset = ((u64)p->frequency) * 258;
+	do_div(offset, 6000000);
+	f_offset = ((unsigned long)offset) + 2321;
+
+	rc = s921_writeregdata(state, s921_prefreq);
+	if (rc < 0)
+		return rc;
+
+	rc = s921_writereg(state, 0xf2, (f_offset >> 8) & 0xff);
+	if (rc < 0)
+		return rc;
+
+	rc = s921_writereg(state, 0xf3, f_offset & 0xff);
+	if (rc < 0)
+		return rc;
+
+	rc = s921_writereg(state, 0xf4, f_switch);
+	if (rc < 0)
+		return rc;
+
+	rc = s921_writeregdata(state, s921_postfreq);
+	if (rc < 0)
+		return rc;
+
+	for (i = 0 ; i < 6; i++) {
+		rc = s921_readreg(state, 0x80);
+		dprintk("status 0x80: %02x\n", rc);
+	}
+	rc = s921_writereg(state, 0x01, 0x40);
+	if (rc < 0)
+		return rc;
+
+	rc = s921_readreg(state, 0x01);
+	dprintk("status 0x01: %02x\n", rc);
+
+	rc = s921_readreg(state, 0x80);
+	dprintk("status 0x80: %02x\n", rc);
+
+	rc = s921_readreg(state, 0x80);
+	dprintk("status 0x80: %02x\n", rc);
+
+	rc = s921_readreg(state, 0x32);
+	dprintk("status 0x32: %02x\n", rc);
+
+	dprintk("pll tune band=%d, pll=%d\n", f_switch, (int)f_offset);
+
+	return 0;
+}
+
+static int s921_initfe(struct dvb_frontend *fe)
+{
+	struct s921_state *state = fe->demodulator_priv;
+	int rc;
+
+	dprintk("\n");
+
+	rc = s921_writeregdata(state, s921_init);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct s921_state *state = fe->demodulator_priv;
+	int regstatus, rc;
+
+	*status = 0;
+
+	rc = s921_readreg(state, 0x81);
+	if (rc < 0)
+		return rc;
+
+	regstatus = rc << 8;
+
+	rc = s921_readreg(state, 0x82);
+	if (rc < 0)
+		return rc;
+
+	regstatus |= rc;
+
+	dprintk("status = %04x\n", regstatus);
+
+	/* Full Sync - We don't know what each bit means on regs 0x81/0x82 */
+	if ((regstatus & 0xff) == 0x40) {
+		*status = FE_HAS_SIGNAL  |
+			  FE_HAS_CARRIER |
+			  FE_HAS_VITERBI |
+			  FE_HAS_SYNC    |
+			  FE_HAS_LOCK;
+	} else if (regstatus & 0x40) {
+		/* This is close to Full Sync, but not enough to get useful info */
+		*status = FE_HAS_SIGNAL  |
+			  FE_HAS_CARRIER |
+			  FE_HAS_VITERBI |
+			  FE_HAS_SYNC;
+	}
+
+	return 0;
+}
+
+static int s921_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	fe_status_t	status;
+	struct s921_state *state = fe->demodulator_priv;
+	int rc;
+
+	/* FIXME: Use the proper register for it... 0x80? */
+	rc = s921_read_status(fe, &status);
+	if (rc < 0)
+		return rc;
+
+	*strength = (status & FE_HAS_LOCK) ? 0xffff : 0;
+
+	dprintk("strength = 0x%04x\n", *strength);
+
+	rc = s921_readreg(state, 0x01);
+	dprintk("status 0x01: %02x\n", rc);
+
+	rc = s921_readreg(state, 0x80);
+	dprintk("status 0x80: %02x\n", rc);
+
+	rc = s921_readreg(state, 0x32);
+	dprintk("status 0x32: %02x\n", rc);
+
+	return 0;
+}
+
+static int s921_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct s921_state *state = fe->demodulator_priv;
+	int rc;
+
+	dprintk("\n");
+
+	/* FIXME: We don't know how to use non-auto mode */
+
+	rc = s921_pll_tune(fe);
+	if (rc < 0)
+		return rc;
+
+	state->currentfreq = p->frequency;
+
+	return 0;
+}
+
+static int s921_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct s921_state *state = fe->demodulator_priv;
+
+	/* FIXME: Probably it is possible to get it from regs f1 and f2 */
+	p->frequency = state->currentfreq;
+	p->delivery_system = SYS_ISDBT;
+
+	return 0;
+}
+
+static int s921_tune(struct dvb_frontend *fe,
+			bool re_tune,
+			unsigned int mode_flags,
+			unsigned int *delay,
+			fe_status_t *status)
+{
+	int rc = 0;
+
+	dprintk("\n");
+
+	if (re_tune)
+		rc = s921_set_frontend(fe);
+
+	if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
+		s921_read_status(fe, status);
+
+	return rc;
+}
+
+static int s921_get_algo(struct dvb_frontend *fe)
+{
+	return 1; /* FE_ALGO_HW */
+}
+
+static void s921_release(struct dvb_frontend *fe)
+{
+	struct s921_state *state = fe->demodulator_priv;
+
+	dprintk("\n");
+	kfree(state);
+}
+
+static struct dvb_frontend_ops s921_ops;
+
+struct dvb_frontend *s921_attach(const struct s921_config *config,
+				    struct i2c_adapter *i2c)
+{
+	/* allocate memory for the internal state */
+	struct s921_state *state =
+		kzalloc(sizeof(struct s921_state), GFP_KERNEL);
+
+	dprintk("\n");
+	if (state == NULL) {
+		rc("Unable to kzalloc\n");
+		goto rcor;
+	}
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &s921_ops,
+		sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	return &state->frontend;
+
+rcor:
+	kfree(state);
+
+	return NULL;
+}
+EXPORT_SYMBOL(s921_attach);
+
+static struct dvb_frontend_ops s921_ops = {
+	.delsys = { SYS_ISDBT },
+	/* Use dib8000 values per default */
+	.info = {
+		.name = "Sharp S921",
+		.frequency_min = 470000000,
+		/*
+		 * Max should be 770MHz instead, according with Sharp docs,
+		 * but Leadership doc says it works up to 806 MHz. This is
+		 * required to get channel 69, used in Brazil
+		 */
+		.frequency_max = 806000000,
+		.frequency_tolerance = 0,
+		 .caps = FE_CAN_INVERSION_AUTO |
+			 FE_CAN_FEC_1_2  | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			 FE_CAN_FEC_5_6  | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			 FE_CAN_QPSK     | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+			 FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+			 FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER |
+			 FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.release = s921_release,
+
+	.init = s921_initfe,
+	.set_frontend = s921_set_frontend,
+	.get_frontend = s921_get_frontend,
+	.read_status = s921_read_status,
+	.read_signal_strength = s921_read_signal_strength,
+	.tune = s921_tune,
+	.get_frontend_algo = s921_get_algo,
+};
+
+MODULE_DESCRIPTION("DVB Frontend module for Sharp S921 hardware");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Douglas Landgraf <dougsland@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/s921.h b/drivers/media/dvb-frontends/s921.h
new file mode 100644
index 0000000..f220d82
--- /dev/null
+++ b/drivers/media/dvb-frontends/s921.h
@@ -0,0 +1,47 @@
+/*
+ *   Sharp s921 driver
+ *
+ *   Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *   Copyright (C) 2009 Douglas Landgraf <dougsland@redhat.com>
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License as
+ *   published by the Free Software Foundation version 2.
+ *
+ *   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 S921_H
+#define S921_H
+
+#include <linux/dvb/frontend.h>
+
+struct s921_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+};
+
+#if defined(CONFIG_DVB_S921) || (defined(CONFIG_DVB_S921_MODULE) \
+	&& defined(MODULE))
+extern struct dvb_frontend *s921_attach(const struct s921_config *config,
+					   struct i2c_adapter *i2c);
+extern struct i2c_adapter *s921_get_tuner_i2c_adapter(struct dvb_frontend *);
+#else
+static inline struct dvb_frontend *s921_attach(
+	const struct s921_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+static struct i2c_adapter *
+	s921_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* S921_H */
diff --git a/drivers/media/dvb-frontends/si21xx.c b/drivers/media/dvb-frontends/si21xx.c
new file mode 100644
index 0000000..a68a648
--- /dev/null
+++ b/drivers/media/dvb-frontends/si21xx.c
@@ -0,0 +1,951 @@
+/* DVB compliant Linux driver for the DVB-S si2109/2110 demodulator
+*
+* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+*
+*	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.
+*
+*/
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "si21xx.h"
+
+#define	REVISION_REG			0x00
+#define	SYSTEM_MODE_REG			0x01
+#define	TS_CTRL_REG_1			0x02
+#define	TS_CTRL_REG_2			0x03
+#define	PIN_CTRL_REG_1			0x04
+#define	PIN_CTRL_REG_2			0x05
+#define	LOCK_STATUS_REG_1		0x0f
+#define	LOCK_STATUS_REG_2		0x10
+#define	ACQ_STATUS_REG			0x11
+#define	ACQ_CTRL_REG_1			0x13
+#define	ACQ_CTRL_REG_2			0x14
+#define	PLL_DIVISOR_REG			0x15
+#define	COARSE_TUNE_REG			0x16
+#define	FINE_TUNE_REG_L			0x17
+#define	FINE_TUNE_REG_H			0x18
+
+#define	ANALOG_AGC_POWER_LEVEL_REG	0x28
+#define	CFO_ESTIMATOR_CTRL_REG_1	0x29
+#define	CFO_ESTIMATOR_CTRL_REG_2	0x2a
+#define	CFO_ESTIMATOR_CTRL_REG_3	0x2b
+
+#define	SYM_RATE_ESTIMATE_REG_L		0x31
+#define	SYM_RATE_ESTIMATE_REG_M		0x32
+#define	SYM_RATE_ESTIMATE_REG_H		0x33
+
+#define	CFO_ESTIMATOR_OFFSET_REG_L	0x36
+#define	CFO_ESTIMATOR_OFFSET_REG_H	0x37
+#define	CFO_ERROR_REG_L			0x38
+#define	CFO_ERROR_REG_H			0x39
+#define	SYM_RATE_ESTIMATOR_CTRL_REG	0x3a
+
+#define	SYM_RATE_REG_L			0x3f
+#define	SYM_RATE_REG_M			0x40
+#define	SYM_RATE_REG_H			0x41
+#define	SYM_RATE_ESTIMATOR_MAXIMUM_REG	0x42
+#define	SYM_RATE_ESTIMATOR_MINIMUM_REG	0x43
+
+#define	C_N_ESTIMATOR_CTRL_REG		0x7c
+#define	C_N_ESTIMATOR_THRSHLD_REG	0x7d
+#define	C_N_ESTIMATOR_LEVEL_REG_L	0x7e
+#define	C_N_ESTIMATOR_LEVEL_REG_H	0x7f
+
+#define	BLIND_SCAN_CTRL_REG		0x80
+
+#define	LSA_CTRL_REG_1			0x8D
+#define	SPCTRM_TILT_CORR_THRSHLD_REG	0x8f
+#define	ONE_DB_BNDWDTH_THRSHLD_REG	0x90
+#define	TWO_DB_BNDWDTH_THRSHLD_REG	0x91
+#define	THREE_DB_BNDWDTH_THRSHLD_REG	0x92
+#define	INBAND_POWER_THRSHLD_REG	0x93
+#define	REF_NOISE_LVL_MRGN_THRSHLD_REG	0x94
+
+#define	VIT_SRCH_CTRL_REG_1		0xa0
+#define	VIT_SRCH_CTRL_REG_2		0xa1
+#define	VIT_SRCH_CTRL_REG_3		0xa2
+#define	VIT_SRCH_STATUS_REG		0xa3
+#define	VITERBI_BER_COUNT_REG_L		0xab
+#define	REED_SOLOMON_CTRL_REG		0xb0
+#define	REED_SOLOMON_ERROR_COUNT_REG_L	0xb1
+#define	PRBS_CTRL_REG			0xb5
+
+#define	LNB_CTRL_REG_1			0xc0
+#define	LNB_CTRL_REG_2			0xc1
+#define	LNB_CTRL_REG_3			0xc2
+#define	LNB_CTRL_REG_4			0xc3
+#define	LNB_CTRL_STATUS_REG		0xc4
+#define	LNB_FIFO_REGS_0			0xc5
+#define	LNB_FIFO_REGS_1			0xc6
+#define	LNB_FIFO_REGS_2			0xc7
+#define	LNB_FIFO_REGS_3			0xc8
+#define	LNB_FIFO_REGS_4			0xc9
+#define	LNB_FIFO_REGS_5			0xca
+#define	LNB_SUPPLY_CTRL_REG_1		0xcb
+#define	LNB_SUPPLY_CTRL_REG_2		0xcc
+#define	LNB_SUPPLY_CTRL_REG_3		0xcd
+#define	LNB_SUPPLY_CTRL_REG_4		0xce
+#define	LNB_SUPPLY_STATUS_REG		0xcf
+
+#define FAIL	-1
+#define PASS	0
+
+#define ALLOWABLE_FS_COUNT	10
+#define STATUS_BER		0
+#define STATUS_UCBLOCKS		1
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG "si21xx: " args); \
+	} while (0)
+
+enum {
+	ACTIVE_HIGH,
+	ACTIVE_LOW
+};
+enum {
+	BYTE_WIDE,
+	BIT_WIDE
+};
+enum {
+	CLK_GAPPED_MODE,
+	CLK_CONTINUOUS_MODE
+};
+enum {
+	RISING_EDGE,
+	FALLING_EDGE
+};
+enum {
+	MSB_FIRST,
+	LSB_FIRST
+};
+enum {
+	SERIAL,
+	PARALLEL
+};
+
+struct si21xx_state {
+	struct i2c_adapter *i2c;
+	const struct si21xx_config *config;
+	struct dvb_frontend frontend;
+	u8 initialised:1;
+	int errmode;
+	int fs;			/*Sampling rate of the ADC in MHz*/
+};
+
+/*	register default initialization */
+static u8 serit_sp1511lhb_inittab[] = {
+	0x01, 0x28,	/* set i2c_inc_disable */
+	0x20, 0x03,
+	0x27, 0x20,
+	0xe0, 0x45,
+	0xe1, 0x08,
+	0xfe, 0x01,
+	0x01, 0x28,
+	0x89, 0x09,
+	0x04, 0x80,
+	0x05, 0x01,
+	0x06, 0x00,
+	0x20, 0x03,
+	0x24, 0x88,
+	0x29, 0x09,
+	0x2a, 0x0f,
+	0x2c, 0x10,
+	0x2d, 0x19,
+	0x2e, 0x08,
+	0x2f, 0x10,
+	0x30, 0x19,
+	0x34, 0x20,
+	0x35, 0x03,
+	0x45, 0x02,
+	0x46, 0x45,
+	0x47, 0xd0,
+	0x48, 0x00,
+	0x49, 0x40,
+	0x4a, 0x03,
+	0x4c, 0xfd,
+	0x4f, 0x2e,
+	0x50, 0x2e,
+	0x51, 0x10,
+	0x52, 0x10,
+	0x56, 0x92,
+	0x59, 0x00,
+	0x5a, 0x2d,
+	0x5b, 0x33,
+	0x5c, 0x1f,
+	0x5f, 0x76,
+	0x62, 0xc0,
+	0x63, 0xc0,
+	0x64, 0xf3,
+	0x65, 0xf3,
+	0x79, 0x40,
+	0x6a, 0x40,
+	0x6b, 0x0a,
+	0x6c, 0x80,
+	0x6d, 0x27,
+	0x71, 0x06,
+	0x75, 0x60,
+	0x78, 0x00,
+	0x79, 0xb5,
+	0x7c, 0x05,
+	0x7d, 0x1a,
+	0x87, 0x55,
+	0x88, 0x72,
+	0x8f, 0x08,
+	0x90, 0xe0,
+	0x94, 0x40,
+	0xa0, 0x3f,
+	0xa1, 0xc0,
+	0xa4, 0xcc,
+	0xa5, 0x66,
+	0xa6, 0x66,
+	0xa7, 0x7b,
+	0xa8, 0x7b,
+	0xa9, 0x7b,
+	0xaa, 0x9a,
+	0xed, 0x04,
+	0xad, 0x00,
+	0xae, 0x03,
+	0xcc, 0xab,
+	0x01, 0x08,
+	0xff, 0xff
+};
+
+/*	low level read/writes */
+static int si21_writeregs(struct si21xx_state *state, u8 reg1,
+							u8 *data, int len)
+{
+	int ret;
+	u8 buf[60];/* = { reg1, data };*/
+	struct i2c_msg msg = {
+				.addr = state->config->demod_address,
+				.flags = 0,
+				.buf = buf,
+				.len = len + 1
+	};
+
+	msg.buf[0] =  reg1;
+	memcpy(msg.buf + 1, data, len);
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		dprintk("%s: writereg error (reg1 == 0x%02x, data == 0x%02x, "
+			"ret == %i)\n", __func__, reg1, data[0], ret);
+
+	return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = {
+				.addr = state->config->demod_address,
+				.flags = 0,
+				.buf = buf,
+				.len = 2
+	};
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		dprintk("%s: writereg error (reg == 0x%02x, data == 0x%02x, "
+			"ret == %i)\n", __func__, reg, data, ret);
+
+	return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int si21_write(struct dvb_frontend *fe, const u8 buf[], int len)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+
+	if (len != 2)
+		return -EINVAL;
+
+	return si21_writereg(state, buf[0], buf[1]);
+}
+
+static u8 si21_readreg(struct si21xx_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{
+			.addr = state->config->demod_address,
+			.flags = 0,
+			.buf = b0,
+			.len = 1
+		}, {
+			.addr = state->config->demod_address,
+			.flags = I2C_M_RD,
+			.buf = b1,
+			.len = 1
+		}
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
+			__func__, reg, ret);
+
+	return b1[0];
+}
+
+static int si21_readregs(struct si21xx_state *state, u8 reg1, u8 *b, u8 len)
+{
+	int ret;
+	struct i2c_msg msg[] = {
+		{
+			.addr = state->config->demod_address,
+			.flags = 0,
+			.buf = &reg1,
+			.len = 1
+		}, {
+			.addr = state->config->demod_address,
+			.flags = I2C_M_RD,
+			.buf = b,
+			.len = len
+		}
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
+
+	return ret == 2 ? 0 : -1;
+}
+
+static int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout)
+{
+	unsigned long start = jiffies;
+
+	dprintk("%s\n", __func__);
+
+	while ((si21_readreg(state, LNB_CTRL_REG_1) & 0x8) == 8) {
+		if (jiffies - start > timeout) {
+			dprintk("%s: timeout!!\n", __func__);
+			return -ETIMEDOUT;
+		}
+		msleep(10);
+	};
+
+	return 0;
+}
+
+static int si21xx_set_symbolrate(struct dvb_frontend *fe, u32 srate)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+	u32 sym_rate, data_rate;
+	int i;
+	u8 sym_rate_bytes[3];
+
+	dprintk("%s : srate = %i\n", __func__ , srate);
+
+	if ((srate < 1000000) || (srate > 45000000))
+		return -EINVAL;
+
+	data_rate = srate;
+	sym_rate = 0;
+
+	for (i = 0; i < 4; ++i) {
+		sym_rate /= 100;
+		sym_rate = sym_rate + ((data_rate % 100) * 0x800000) /
+								state->fs;
+		data_rate /= 100;
+	}
+	for (i = 0; i < 3; ++i)
+		sym_rate_bytes[i] = (u8)((sym_rate >> (i * 8)) & 0xff);
+
+	si21_writeregs(state, SYM_RATE_REG_L, sym_rate_bytes, 0x03);
+
+	return 0;
+}
+
+static int si21xx_send_diseqc_msg(struct dvb_frontend *fe,
+					struct dvb_diseqc_master_cmd *m)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+	u8 lnb_status;
+	u8 LNB_CTRL_1;
+	int status;
+
+	dprintk("%s\n", __func__);
+
+	status = PASS;
+	LNB_CTRL_1 = 0;
+
+	status |= si21_readregs(state, LNB_CTRL_STATUS_REG, &lnb_status, 0x01);
+	status |= si21_readregs(state, LNB_CTRL_REG_1, &lnb_status, 0x01);
+
+	/*fill the FIFO*/
+	status |= si21_writeregs(state, LNB_FIFO_REGS_0, m->msg, m->msg_len);
+
+	LNB_CTRL_1 = (lnb_status & 0x70);
+	LNB_CTRL_1 |= m->msg_len;
+
+	LNB_CTRL_1 |= 0x80;	/* begin LNB signaling */
+
+	status |= si21_writeregs(state, LNB_CTRL_REG_1, &LNB_CTRL_1, 0x01);
+
+	return status;
+}
+
+static int si21xx_send_diseqc_burst(struct dvb_frontend *fe,
+						fe_sec_mini_cmd_t burst)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+	u8 val;
+
+	dprintk("%s\n", __func__);
+
+	if (si21xx_wait_diseqc_idle(state, 100) < 0)
+		return -ETIMEDOUT;
+
+	val = (0x80 | si21_readreg(state, 0xc1));
+	if (si21_writereg(state, LNB_CTRL_REG_1,
+			burst == SEC_MINI_A ? (val & ~0x10) : (val | 0x10)))
+		return -EREMOTEIO;
+
+	if (si21xx_wait_diseqc_idle(state, 100) < 0)
+		return -ETIMEDOUT;
+
+	if (si21_writereg(state, LNB_CTRL_REG_1, val))
+		return -EREMOTEIO;
+
+	return 0;
+}
+/*	30.06.2008 */
+static int si21xx_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+	u8 val;
+
+	dprintk("%s\n", __func__);
+	val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1));
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		return si21_writereg(state, LNB_CTRL_REG_1, val | 0x20);
+
+	case SEC_TONE_OFF:
+		return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x20));
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int si21xx_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+
+	u8 val;
+	dprintk("%s: %s\n", __func__,
+		volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+		volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
+
+
+	val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1));
+
+	switch (volt) {
+	case SEC_VOLTAGE_18:
+		return si21_writereg(state, LNB_CTRL_REG_1, val | 0x40);
+		break;
+	case SEC_VOLTAGE_13:
+		return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x40));
+		break;
+	default:
+		return -EINVAL;
+	};
+}
+
+static int si21xx_init(struct dvb_frontend *fe)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+	int i;
+	int status = 0;
+	u8 reg1;
+	u8 val;
+	u8 reg2[2];
+
+	dprintk("%s\n", __func__);
+
+	for (i = 0; ; i += 2) {
+		reg1 = serit_sp1511lhb_inittab[i];
+		val = serit_sp1511lhb_inittab[i+1];
+		if (reg1 == 0xff && val == 0xff)
+			break;
+		si21_writeregs(state, reg1, &val, 1);
+	}
+
+	/*DVB QPSK SYSTEM MODE REG*/
+	reg1 = 0x08;
+	si21_writeregs(state, SYSTEM_MODE_REG, &reg1, 0x01);
+
+	/*transport stream config*/
+	/*
+	mode = PARALLEL;
+	sdata_form = LSB_FIRST;
+	clk_edge = FALLING_EDGE;
+	clk_mode = CLK_GAPPED_MODE;
+	strt_len = BYTE_WIDE;
+	sync_pol = ACTIVE_HIGH;
+	val_pol = ACTIVE_HIGH;
+	err_pol = ACTIVE_HIGH;
+	sclk_rate = 0x00;
+	parity = 0x00 ;
+	data_delay = 0x00;
+	clk_delay = 0x00;
+	pclk_smooth = 0x00;
+	*/
+	reg2[0] =
+		PARALLEL + (LSB_FIRST << 1)
+		+ (FALLING_EDGE << 2) + (CLK_GAPPED_MODE << 3)
+		+ (BYTE_WIDE << 4) + (ACTIVE_HIGH << 5)
+		+ (ACTIVE_HIGH << 6) + (ACTIVE_HIGH << 7);
+
+	reg2[1] = 0;
+	/*	sclk_rate + (parity << 2)
+		+ (data_delay << 3) + (clk_delay << 4)
+		+ (pclk_smooth << 5);
+	*/
+	status |= si21_writeregs(state, TS_CTRL_REG_1, reg2, 0x02);
+	if (status != 0)
+		dprintk(" %s : TS Set Error\n", __func__);
+
+	return 0;
+
+}
+
+static int si21_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+	u8 regs_read[2];
+	u8 reg_read;
+	u8 i;
+	u8 lock;
+	u8 signal = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG);
+
+	si21_readregs(state, LOCK_STATUS_REG_1, regs_read, 0x02);
+	reg_read = 0;
+
+	for (i = 0; i < 7; ++i)
+		reg_read |= ((regs_read[0] >> i) & 0x01) << (6 - i);
+
+	lock = ((reg_read & 0x7f) | (regs_read[1] & 0x80));
+
+	dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, lock);
+	*status = 0;
+
+	if (signal > 10)
+		*status |= FE_HAS_SIGNAL;
+
+	if (lock & 0x2)
+		*status |= FE_HAS_CARRIER;
+
+	if (lock & 0x20)
+		*status |= FE_HAS_VITERBI;
+
+	if (lock & 0x40)
+		*status |= FE_HAS_SYNC;
+
+	if ((lock & 0x7b) == 0x7b)
+		*status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int si21_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+
+	/*status = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG,
+						(u8*)agclevel, 0x01);*/
+
+	u16 signal = (3 * si21_readreg(state, 0x27) *
+					si21_readreg(state, 0x28));
+
+	dprintk("%s : AGCPWR: 0x%02x%02x, signal=0x%04x\n", __func__,
+		si21_readreg(state, 0x27),
+		si21_readreg(state, 0x28), (int) signal);
+
+	signal  <<= 4;
+	*strength = signal;
+
+	return 0;
+}
+
+static int si21_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	if (state->errmode != STATUS_BER)
+		return 0;
+
+	*ber = (si21_readreg(state, 0x1d) << 8) |
+				si21_readreg(state, 0x1e);
+
+	return 0;
+}
+
+static int si21_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+
+	s32 xsnr = 0xffff - ((si21_readreg(state, 0x24) << 8) |
+					si21_readreg(state, 0x25));
+	xsnr = 3 * (xsnr - 0xa100);
+	*snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
+
+	dprintk("%s\n", __func__);
+
+	return 0;
+}
+
+static int si21_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	if (state->errmode != STATUS_UCBLOCKS)
+		*ucblocks = 0;
+	else
+		*ucblocks = (si21_readreg(state, 0x1d) << 8) |
+					si21_readreg(state, 0x1e);
+
+	return 0;
+}
+
+/*	initiates a channel acquisition sequence
+	using the specified symbol rate and code rate */
+static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate,
+						fe_code_rate_t crate)
+{
+
+	struct si21xx_state *state = fe->demodulator_priv;
+	u8 coderates[] = {
+				0x0, 0x01, 0x02, 0x04, 0x00,
+				0x8, 0x10, 0x20, 0x00, 0x3f
+	};
+
+	u8 coderate_ptr;
+	int status;
+	u8 start_acq = 0x80;
+	u8 reg, regs[3];
+
+	dprintk("%s\n", __func__);
+
+	status = PASS;
+	coderate_ptr = coderates[crate];
+
+	si21xx_set_symbolrate(fe, symbrate);
+
+	/* write code rates to use in the Viterbi search */
+	status |= si21_writeregs(state,
+				VIT_SRCH_CTRL_REG_1,
+				&coderate_ptr, 0x01);
+
+	/* clear acq_start bit */
+	status |= si21_readregs(state, ACQ_CTRL_REG_2, &reg, 0x01);
+	reg &= ~start_acq;
+	status |= si21_writeregs(state, ACQ_CTRL_REG_2, &reg, 0x01);
+
+	/* use new Carrier Frequency Offset Estimator (QuickLock) */
+	regs[0] = 0xCB;
+	regs[1] = 0x40;
+	regs[2] = 0xCB;
+
+	status |= si21_writeregs(state,
+				TWO_DB_BNDWDTH_THRSHLD_REG,
+				&regs[0], 0x03);
+	reg = 0x56;
+	status |= si21_writeregs(state,
+				LSA_CTRL_REG_1, &reg, 1);
+	reg = 0x05;
+	status |= si21_writeregs(state,
+				BLIND_SCAN_CTRL_REG, &reg, 1);
+	/* start automatic acq */
+	status |= si21_writeregs(state,
+				ACQ_CTRL_REG_2, &start_acq, 0x01);
+
+	return status;
+}
+
+static int si21xx_set_frontend(struct dvb_frontend *fe)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+	/* freq		Channel carrier frequency in KHz (i.e. 1550000 KHz)
+	 datarate	Channel symbol rate in Sps (i.e. 22500000 Sps)*/
+
+	/* in MHz */
+	unsigned char coarse_tune_freq;
+	int fine_tune_freq;
+	unsigned char sample_rate = 0;
+	/* boolean */
+	bool inband_interferer_ind;
+
+	/* INTERMEDIATE VALUES */
+	int icoarse_tune_freq; /* MHz */
+	int ifine_tune_freq; /* MHz */
+	unsigned int band_high;
+	unsigned int band_low;
+	unsigned int x1;
+	unsigned int x2;
+	int i;
+	bool inband_interferer_div2[ALLOWABLE_FS_COUNT];
+	bool inband_interferer_div4[ALLOWABLE_FS_COUNT];
+	int status;
+
+	/* allowable sample rates for ADC in MHz */
+	int afs[ALLOWABLE_FS_COUNT] = { 200, 192, 193, 194, 195,
+					196, 204, 205, 206, 207
+	};
+	/* in MHz */
+	int if_limit_high;
+	int if_limit_low;
+	int lnb_lo;
+	int lnb_uncertanity;
+
+	int rf_freq;
+	int data_rate;
+	unsigned char regs[4];
+
+	dprintk("%s : FE_SET_FRONTEND\n", __func__);
+
+	if (c->delivery_system != SYS_DVBS) {
+			dprintk("%s: unsupported delivery system selected (%d)\n",
+				__func__, c->delivery_system);
+			return -EOPNOTSUPP;
+	}
+
+	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i)
+		inband_interferer_div2[i] = inband_interferer_div4[i] = false;
+
+	if_limit_high = -700000;
+	if_limit_low = -100000;
+	/* in MHz */
+	lnb_lo = 0;
+	lnb_uncertanity = 0;
+
+	rf_freq = 10 * c->frequency ;
+	data_rate = c->symbol_rate / 100;
+
+	status = PASS;
+
+	band_low = (rf_freq - lnb_lo) - ((lnb_uncertanity * 200)
+					+ (data_rate * 135)) / 200;
+
+	band_high = (rf_freq - lnb_lo) + ((lnb_uncertanity * 200)
+					+ (data_rate * 135)) / 200;
+
+
+	icoarse_tune_freq = 100000 *
+				(((rf_freq - lnb_lo) -
+					(if_limit_low + if_limit_high) / 2)
+								/ 100000);
+
+	ifine_tune_freq = (rf_freq - lnb_lo) - icoarse_tune_freq ;
+
+	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
+		x1 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) *
+					(afs[i] * 2500) + afs[i] * 2500;
+
+		x2 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) *
+							(afs[i] * 2500);
+
+		if (((band_low < x1) && (x1 < band_high)) ||
+					((band_low < x2) && (x2 < band_high)))
+					inband_interferer_div4[i] = true;
+
+	}
+
+	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
+		x1 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) *
+					(afs[i] * 5000) + afs[i] * 5000;
+
+		x2 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) *
+					(afs[i] * 5000);
+
+		if (((band_low < x1) && (x1 < band_high)) ||
+					((band_low < x2) && (x2 < band_high)))
+					inband_interferer_div2[i] = true;
+	}
+
+	inband_interferer_ind = true;
+	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
+		if (inband_interferer_div2[i] || inband_interferer_div4[i]) {
+			inband_interferer_ind = false;
+			break;
+		}
+	}
+
+	if (inband_interferer_ind) {
+		for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
+			if (!inband_interferer_div2[i]) {
+				sample_rate = (u8) afs[i];
+				break;
+			}
+		}
+	} else {
+		for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
+			if ((inband_interferer_div2[i] ||
+			     !inband_interferer_div4[i])) {
+				sample_rate = (u8) afs[i];
+				break;
+			}
+		}
+
+	}
+
+	if (sample_rate > 207 || sample_rate < 192)
+		sample_rate = 200;
+
+	fine_tune_freq = ((0x4000 * (ifine_tune_freq / 10)) /
+					((sample_rate) * 1000));
+
+	coarse_tune_freq = (u8)(icoarse_tune_freq / 100000);
+
+	regs[0] = sample_rate;
+	regs[1] = coarse_tune_freq;
+	regs[2] = fine_tune_freq & 0xFF;
+	regs[3] = fine_tune_freq >> 8 & 0xFF;
+
+	status |= si21_writeregs(state, PLL_DIVISOR_REG, &regs[0], 0x04);
+
+	state->fs = sample_rate;/*ADC MHz*/
+	si21xx_setacquire(fe, c->symbol_rate, c->fec_inner);
+
+	return 0;
+}
+
+static int si21xx_sleep(struct dvb_frontend *fe)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+	u8 regdata;
+
+	dprintk("%s\n", __func__);
+
+	si21_readregs(state, SYSTEM_MODE_REG, &regdata, 0x01);
+	regdata |= 1 << 6;
+	si21_writeregs(state, SYSTEM_MODE_REG, &regdata, 0x01);
+	state->initialised = 0;
+
+	return 0;
+}
+
+static void si21xx_release(struct dvb_frontend *fe)
+{
+	struct si21xx_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	kfree(state);
+}
+
+static struct dvb_frontend_ops si21xx_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name			= "SL SI21XX DVB-S",
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 125,	 /* kHz for QPSK frontends */
+		.frequency_tolerance	= 0,
+		.symbol_rate_min	= 1000000,
+		.symbol_rate_max	= 45000000,
+		.symbol_rate_tolerance	= 500,	/* ppm */
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+		FE_CAN_QPSK |
+		FE_CAN_FEC_AUTO
+	},
+
+	.release = si21xx_release,
+	.init = si21xx_init,
+	.sleep = si21xx_sleep,
+	.write = si21_write,
+	.read_status = si21_read_status,
+	.read_ber = si21_read_ber,
+	.read_signal_strength = si21_read_signal_strength,
+	.read_snr = si21_read_snr,
+	.read_ucblocks = si21_read_ucblocks,
+	.diseqc_send_master_cmd = si21xx_send_diseqc_msg,
+	.diseqc_send_burst = si21xx_send_diseqc_burst,
+	.set_tone = si21xx_set_tone,
+	.set_voltage = si21xx_set_voltage,
+
+	.set_frontend = si21xx_set_frontend,
+};
+
+struct dvb_frontend *si21xx_attach(const struct si21xx_config *config,
+						struct i2c_adapter *i2c)
+{
+	struct si21xx_state *state = NULL;
+	int id;
+
+	dprintk("%s\n", __func__);
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct si21xx_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->initialised = 0;
+	state->errmode = STATUS_BER;
+
+	/* check if the demod is there */
+	id = si21_readreg(state, SYSTEM_MODE_REG);
+	si21_writereg(state, SYSTEM_MODE_REG, id | 0x40); /* standby off */
+	msleep(200);
+	id = si21_readreg(state, 0x00);
+
+	/* register 0x00 contains:
+		0x34 for SI2107
+		0x24 for SI2108
+		0x14 for SI2109
+		0x04 for SI2110
+	*/
+	if (id != 0x04 && id != 0x14)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &si21xx_ops,
+					sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(si21xx_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("SL SI21XX DVB Demodulator driver");
+MODULE_AUTHOR("Igor M. Liplianin");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/si21xx.h b/drivers/media/dvb-frontends/si21xx.h
new file mode 100644
index 0000000..141b5b8
--- /dev/null
+++ b/drivers/media/dvb-frontends/si21xx.h
@@ -0,0 +1,37 @@
+#ifndef SI21XX_H
+#define SI21XX_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct si21xx_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* minimum delay before retuning */
+	int min_delay_ms;
+};
+
+#if defined(CONFIG_DVB_SI21XX) || \
+		(defined(CONFIG_DVB_SI21XX_MODULE) && defined(MODULE))
+extern struct dvb_frontend *si21xx_attach(const struct si21xx_config *config,
+						struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *si21xx_attach(
+		const struct si21xx_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+static inline int si21xx_writeregister(struct dvb_frontend *fe, u8 reg, u8 val)
+{
+	int r = 0;
+	u8 buf[] = {reg, val};
+	if (fe->ops.write)
+		r = fe->ops.write(fe, buf, 2);
+	return r;
+}
+
+#endif
diff --git a/drivers/media/dvb-frontends/sp8870.c b/drivers/media/dvb-frontends/sp8870.c
new file mode 100644
index 0000000..e37274c
--- /dev/null
+++ b/drivers/media/dvb-frontends/sp8870.c
@@ -0,0 +1,620 @@
+/*
+    Driver for Spase SP8870 demodulator
+
+    Copyright (C) 1999 Juergen Peitz
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+/*
+ * This driver needs external firmware. Please use the command
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
+ */
+#define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw"
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "sp8870.h"
+
+
+struct sp8870_state {
+
+	struct i2c_adapter* i2c;
+
+	const struct sp8870_config* config;
+
+	struct dvb_frontend frontend;
+
+	/* demodulator private data */
+	u8 initialised:1;
+};
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "sp8870: " args); \
+	} while (0)
+
+/* firmware size for sp8870 */
+#define SP8870_FIRMWARE_SIZE 16382
+
+/* starting point for firmware in file 'Sc_main.mc' */
+#define SP8870_FIRMWARE_OFFSET 0x0A
+
+static int sp8870_writereg (struct sp8870_state* state, u16 reg, u16 data)
+{
+	u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff };
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 4 };
+	int err;
+
+	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+		dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int sp8870_readreg (struct sp8870_state* state, u16 reg)
+{
+	int ret;
+	u8 b0 [] = { reg >> 8 , reg & 0xff };
+	u8 b1 [] = { 0, 0 };
+	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
+			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
+
+	ret = i2c_transfer (state->i2c, msg, 2);
+
+	if (ret != 2) {
+		dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
+		return -1;
+	}
+
+	return (b1[0] << 8 | b1[1]);
+}
+
+static int sp8870_firmware_upload (struct sp8870_state* state, const struct firmware *fw)
+{
+	struct i2c_msg msg;
+	const char *fw_buf = fw->data;
+	int fw_pos;
+	u8 tx_buf[255];
+	int tx_len;
+	int err = 0;
+
+	dprintk ("%s: ...\n", __func__);
+
+	if (fw->size < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET)
+		return -EINVAL;
+
+	// system controller stop
+	sp8870_writereg(state, 0x0F00, 0x0000);
+
+	// instruction RAM register hiword
+	sp8870_writereg(state, 0x8F08, ((SP8870_FIRMWARE_SIZE / 2) & 0xFFFF));
+
+	// instruction RAM MWR
+	sp8870_writereg(state, 0x8F0A, ((SP8870_FIRMWARE_SIZE / 2) >> 16));
+
+	// do firmware upload
+	fw_pos = SP8870_FIRMWARE_OFFSET;
+	while (fw_pos < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET){
+		tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - 252) ? 252 : SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - fw_pos;
+		// write register 0xCF0A
+		tx_buf[0] = 0xCF;
+		tx_buf[1] = 0x0A;
+		memcpy(&tx_buf[2], fw_buf + fw_pos, tx_len);
+		msg.addr = state->config->demod_address;
+		msg.flags = 0;
+		msg.buf = tx_buf;
+		msg.len = tx_len + 2;
+		if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+			printk("%s: firmware upload failed!\n", __func__);
+			printk ("%s: i2c error (err == %i)\n", __func__, err);
+			return err;
+		}
+		fw_pos += tx_len;
+	}
+
+	dprintk ("%s: done!\n", __func__);
+	return 0;
+};
+
+static void sp8870_microcontroller_stop (struct sp8870_state* state)
+{
+	sp8870_writereg(state, 0x0F08, 0x000);
+	sp8870_writereg(state, 0x0F09, 0x000);
+
+	// microcontroller STOP
+	sp8870_writereg(state, 0x0F00, 0x000);
+}
+
+static void sp8870_microcontroller_start (struct sp8870_state* state)
+{
+	sp8870_writereg(state, 0x0F08, 0x000);
+	sp8870_writereg(state, 0x0F09, 0x000);
+
+	// microcontroller START
+	sp8870_writereg(state, 0x0F00, 0x001);
+	// not documented but if we don't read 0x0D01 out here
+	// we don't get a correct data valid signal
+	sp8870_readreg(state, 0x0D01);
+}
+
+static int sp8870_read_data_valid_signal(struct sp8870_state* state)
+{
+	return (sp8870_readreg(state, 0x0D02) > 0);
+}
+
+static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05)
+{
+	int known_parameters = 1;
+
+	*reg0xc05 = 0x000;
+
+	switch (p->modulation) {
+	case QPSK:
+		break;
+	case QAM_16:
+		*reg0xc05 |= (1 << 10);
+		break;
+	case QAM_64:
+		*reg0xc05 |= (2 << 10);
+		break;
+	case QAM_AUTO:
+		known_parameters = 0;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	switch (p->hierarchy) {
+	case HIERARCHY_NONE:
+		break;
+	case HIERARCHY_1:
+		*reg0xc05 |= (1 << 7);
+		break;
+	case HIERARCHY_2:
+		*reg0xc05 |= (2 << 7);
+		break;
+	case HIERARCHY_4:
+		*reg0xc05 |= (3 << 7);
+		break;
+	case HIERARCHY_AUTO:
+		known_parameters = 0;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	switch (p->code_rate_HP) {
+	case FEC_1_2:
+		break;
+	case FEC_2_3:
+		*reg0xc05 |= (1 << 3);
+		break;
+	case FEC_3_4:
+		*reg0xc05 |= (2 << 3);
+		break;
+	case FEC_5_6:
+		*reg0xc05 |= (3 << 3);
+		break;
+	case FEC_7_8:
+		*reg0xc05 |= (4 << 3);
+		break;
+	case FEC_AUTO:
+		known_parameters = 0;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	if (known_parameters)
+		*reg0xc05 |= (2 << 1);	/* use specified parameters */
+	else
+		*reg0xc05 |= (1 << 1);	/* enable autoprobing */
+
+	return 0;
+}
+
+static int sp8870_wake_up(struct sp8870_state* state)
+{
+	// enable TS output and interface pins
+	return sp8870_writereg(state, 0xC18, 0x00D);
+}
+
+static int sp8870_set_frontend_parameters(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct sp8870_state* state = fe->demodulator_priv;
+	int  err;
+	u16 reg0xc05;
+
+	if ((err = configure_reg0xc05(p, &reg0xc05)))
+		return err;
+
+	// system controller stop
+	sp8870_microcontroller_stop(state);
+
+	// set tuner parameters
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	// sample rate correction bit [23..17]
+	sp8870_writereg(state, 0x0319, 0x000A);
+
+	// sample rate correction bit [16..0]
+	sp8870_writereg(state, 0x031A, 0x0AAB);
+
+	// integer carrier offset
+	sp8870_writereg(state, 0x0309, 0x0400);
+
+	// fractional carrier offset
+	sp8870_writereg(state, 0x030A, 0x0000);
+
+	// filter for 6/7/8 Mhz channel
+	if (p->bandwidth_hz == 6000000)
+		sp8870_writereg(state, 0x0311, 0x0002);
+	else if (p->bandwidth_hz == 7000000)
+		sp8870_writereg(state, 0x0311, 0x0001);
+	else
+		sp8870_writereg(state, 0x0311, 0x0000);
+
+	// scan order: 2k first = 0x0000, 8k first = 0x0001
+	if (p->transmission_mode == TRANSMISSION_MODE_2K)
+		sp8870_writereg(state, 0x0338, 0x0000);
+	else
+		sp8870_writereg(state, 0x0338, 0x0001);
+
+	sp8870_writereg(state, 0xc05, reg0xc05);
+
+	// read status reg in order to clear pending irqs
+	sp8870_readreg(state, 0x200);
+
+	// system controller start
+	sp8870_microcontroller_start(state);
+
+	return 0;
+}
+
+static int sp8870_init (struct dvb_frontend* fe)
+{
+	struct sp8870_state* state = fe->demodulator_priv;
+	const struct firmware *fw = NULL;
+
+	sp8870_wake_up(state);
+	if (state->initialised) return 0;
+	state->initialised = 1;
+
+	dprintk ("%s\n", __func__);
+
+
+	/* request the firmware, this will block until someone uploads it */
+	printk("sp8870: waiting for firmware upload (%s)...\n", SP8870_DEFAULT_FIRMWARE);
+	if (state->config->request_firmware(fe, &fw, SP8870_DEFAULT_FIRMWARE)) {
+		printk("sp8870: no firmware upload (timeout or file not found?)\n");
+		return -EIO;
+	}
+
+	if (sp8870_firmware_upload(state, fw)) {
+		printk("sp8870: writing firmware to device failed\n");
+		release_firmware(fw);
+		return -EIO;
+	}
+	release_firmware(fw);
+	printk("sp8870: firmware upload complete\n");
+
+	/* enable TS output and interface pins */
+	sp8870_writereg(state, 0xc18, 0x00d);
+
+	// system controller stop
+	sp8870_microcontroller_stop(state);
+
+	// ADC mode
+	sp8870_writereg(state, 0x0301, 0x0003);
+
+	// Reed Solomon parity bytes passed to output
+	sp8870_writereg(state, 0x0C13, 0x0001);
+
+	// MPEG clock is suppressed if no valid data
+	sp8870_writereg(state, 0x0C14, 0x0001);
+
+	/* bit 0x010: enable data valid signal */
+	sp8870_writereg(state, 0x0D00, 0x010);
+	sp8870_writereg(state, 0x0D01, 0x000);
+
+	return 0;
+}
+
+static int sp8870_read_status (struct dvb_frontend* fe, fe_status_t * fe_status)
+{
+	struct sp8870_state* state = fe->demodulator_priv;
+	int status;
+	int signal;
+
+	*fe_status = 0;
+
+	status = sp8870_readreg (state, 0x0200);
+	if (status < 0)
+		return -EIO;
+
+	signal = sp8870_readreg (state, 0x0303);
+	if (signal < 0)
+		return -EIO;
+
+	if (signal > 0x0F)
+		*fe_status |= FE_HAS_SIGNAL;
+	if (status & 0x08)
+		*fe_status |= FE_HAS_SYNC;
+	if (status & 0x04)
+		*fe_status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_VITERBI;
+
+	return 0;
+}
+
+static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber)
+{
+	struct sp8870_state* state = fe->demodulator_priv;
+	int ret;
+	u32 tmp;
+
+	*ber = 0;
+
+	ret = sp8870_readreg(state, 0xC08);
+	if (ret < 0)
+		return -EIO;
+
+	tmp = ret & 0x3F;
+
+	ret = sp8870_readreg(state, 0xC07);
+	if (ret < 0)
+		return -EIO;
+
+	 tmp = ret << 6;
+
+	if (tmp >= 0x3FFF0)
+		tmp = ~0;
+
+	*ber = tmp;
+
+	return 0;
+}
+
+static int sp8870_read_signal_strength(struct dvb_frontend* fe,  u16 * signal)
+{
+	struct sp8870_state* state = fe->demodulator_priv;
+	int ret;
+	u16 tmp;
+
+	*signal = 0;
+
+	ret = sp8870_readreg (state, 0x306);
+	if (ret < 0)
+		return -EIO;
+
+	tmp = ret << 8;
+
+	ret = sp8870_readreg (state, 0x303);
+	if (ret < 0)
+		return -EIO;
+
+	tmp |= ret;
+
+	if (tmp)
+		*signal = 0xFFFF - tmp;
+
+	return 0;
+}
+
+static int sp8870_read_uncorrected_blocks (struct dvb_frontend* fe, u32* ublocks)
+{
+	struct sp8870_state* state = fe->demodulator_priv;
+	int ret;
+
+	*ublocks = 0;
+
+	ret = sp8870_readreg(state, 0xC0C);
+	if (ret < 0)
+		return -EIO;
+
+	if (ret == 0xFFFF)
+		ret = ~0;
+
+	*ublocks = ret;
+
+	return 0;
+}
+
+/* number of trials to recover from lockup */
+#define MAXTRIALS 5
+/* maximum checks for data valid signal */
+#define MAXCHECKS 100
+
+/* only for debugging: counter for detected lockups */
+static int lockups;
+/* only for debugging: counter for channel switches */
+static int switches;
+
+static int sp8870_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct sp8870_state* state = fe->demodulator_priv;
+
+	/*
+	    The firmware of the sp8870 sometimes locks up after setting frontend parameters.
+	    We try to detect this by checking the data valid signal.
+	    If it is not set after MAXCHECKS we try to recover the lockup by setting
+	    the frontend parameters again.
+	*/
+
+	int err = 0;
+	int valid = 0;
+	int trials = 0;
+	int check_count = 0;
+
+	dprintk("%s: frequency = %i\n", __func__, p->frequency);
+
+	for (trials = 1; trials <= MAXTRIALS; trials++) {
+
+		err = sp8870_set_frontend_parameters(fe);
+		if (err)
+			return err;
+
+		for (check_count = 0; check_count < MAXCHECKS; check_count++) {
+//			valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0);
+			valid = sp8870_read_data_valid_signal(state);
+			if (valid) {
+				dprintk("%s: delay = %i usec\n",
+					__func__, check_count * 10);
+				break;
+			}
+			udelay(10);
+		}
+		if (valid)
+			break;
+	}
+
+	if (!valid) {
+		printk("%s: firmware crash!!!!!!\n", __func__);
+		return -EIO;
+	}
+
+	if (debug) {
+		if (valid) {
+			if (trials > 1) {
+				printk("%s: firmware lockup!!!\n", __func__);
+				printk("%s: recovered after %i trial(s))\n",  __func__, trials - 1);
+				lockups++;
+			}
+		}
+		switches++;
+		printk("%s: switches = %i lockups = %i\n", __func__, switches, lockups);
+	}
+
+	return 0;
+}
+
+static int sp8870_sleep(struct dvb_frontend* fe)
+{
+	struct sp8870_state* state = fe->demodulator_priv;
+
+	// tristate TS output and disable interface pins
+	return sp8870_writereg(state, 0xC18, 0x000);
+}
+
+static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+	fesettings->min_delay_ms = 350;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+	return 0;
+}
+
+static int sp8870_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct sp8870_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		return sp8870_writereg(state, 0x206, 0x001);
+	} else {
+		return sp8870_writereg(state, 0x206, 0x000);
+	}
+}
+
+static void sp8870_release(struct dvb_frontend* fe)
+{
+	struct sp8870_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops sp8870_ops;
+
+struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
+				   struct i2c_adapter* i2c)
+{
+	struct sp8870_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct sp8870_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->initialised = 0;
+
+	/* check if the demod is there */
+	if (sp8870_readreg(state, 0x0200) < 0) goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops sp8870_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name			= "Spase SP8870 DVB-T",
+		.frequency_min		= 470000000,
+		.frequency_max		= 860000000,
+		.frequency_stepsize	= 166666,
+		.caps			= FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+					  FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
+					  FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+					  FE_CAN_QPSK | FE_CAN_QAM_16 |
+					  FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+					  FE_CAN_HIERARCHY_AUTO |  FE_CAN_RECOVER
+	},
+
+	.release = sp8870_release,
+
+	.init = sp8870_init,
+	.sleep = sp8870_sleep,
+	.i2c_gate_ctrl = sp8870_i2c_gate_ctrl,
+
+	.set_frontend = sp8870_set_frontend,
+	.get_tune_settings = sp8870_get_tune_settings,
+
+	.read_status = sp8870_read_status,
+	.read_ber = sp8870_read_ber,
+	.read_signal_strength = sp8870_read_signal_strength,
+	.read_ucblocks = sp8870_read_uncorrected_blocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Spase SP8870 DVB-T Demodulator driver");
+MODULE_AUTHOR("Juergen Peitz");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(sp8870_attach);
diff --git a/drivers/media/dvb-frontends/sp8870.h b/drivers/media/dvb-frontends/sp8870.h
new file mode 100644
index 0000000..a764a79
--- /dev/null
+++ b/drivers/media/dvb-frontends/sp8870.h
@@ -0,0 +1,50 @@
+/*
+    Driver for Spase SP8870 demodulator
+
+    Copyright (C) 1999 Juergen Peitz
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef SP8870_H
+#define SP8870_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct sp8870_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* request firmware for device */
+	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+};
+
+#if defined(CONFIG_DVB_SP8870) || (defined(CONFIG_DVB_SP8870_MODULE) && defined(MODULE))
+extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
+					  struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
+					  struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_SP8870
+
+#endif // SP8870_H
diff --git a/drivers/media/dvb-frontends/sp887x.c b/drivers/media/dvb-frontends/sp887x.c
new file mode 100644
index 0000000..f4096cc
--- /dev/null
+++ b/drivers/media/dvb-frontends/sp887x.c
@@ -0,0 +1,629 @@
+/*
+   Driver for the Spase sp887x demodulator
+*/
+
+/*
+ * This driver needs external firmware. Please use the command
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
+ */
+#define SP887X_DEFAULT_FIRMWARE "dvb-fe-sp887x.fw"
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "sp887x.h"
+
+
+struct sp887x_state {
+	struct i2c_adapter* i2c;
+	const struct sp887x_config* config;
+	struct dvb_frontend frontend;
+
+	/* demodulator private data */
+	u8 initialised:1;
+};
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "sp887x: " args); \
+	} while (0)
+
+static int i2c_writebytes (struct sp887x_state* state, u8 *buf, u8 len)
+{
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = len };
+	int err;
+
+	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+		printk ("%s: i2c write error (addr %02x, err == %i)\n",
+			__func__, state->config->demod_address, err);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int sp887x_writereg (struct sp887x_state* state, u16 reg, u16 data)
+{
+	u8 b0 [] = { reg >> 8 , reg & 0xff, data >> 8, data & 0xff };
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 4 };
+	int ret;
+
+	if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+		/**
+		 *  in case of soft reset we ignore ACK errors...
+		 */
+		if (!(reg == 0xf1a && data == 0x000 &&
+			(ret == -EREMOTEIO || ret == -EFAULT)))
+		{
+			printk("%s: writereg error "
+			       "(reg %03x, data %03x, ret == %i)\n",
+			       __func__, reg & 0xffff, data & 0xffff, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int sp887x_readreg (struct sp887x_state* state, u16 reg)
+{
+	u8 b0 [] = { reg >> 8 , reg & 0xff };
+	u8 b1 [2];
+	int ret;
+	struct i2c_msg msg[] = {{ .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
+			 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 }};
+
+	if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
+		printk("%s: readreg error (ret == %i)\n", __func__, ret);
+		return -1;
+	}
+
+	return (((b1[0] << 8) | b1[1]) & 0xfff);
+}
+
+static void sp887x_microcontroller_stop (struct sp887x_state* state)
+{
+	dprintk("%s\n", __func__);
+	sp887x_writereg(state, 0xf08, 0x000);
+	sp887x_writereg(state, 0xf09, 0x000);
+
+	/* microcontroller STOP */
+	sp887x_writereg(state, 0xf00, 0x000);
+}
+
+static void sp887x_microcontroller_start (struct sp887x_state* state)
+{
+	dprintk("%s\n", __func__);
+	sp887x_writereg(state, 0xf08, 0x000);
+	sp887x_writereg(state, 0xf09, 0x000);
+
+	/* microcontroller START */
+	sp887x_writereg(state, 0xf00, 0x001);
+}
+
+static void sp887x_setup_agc (struct sp887x_state* state)
+{
+	/* setup AGC parameters */
+	dprintk("%s\n", __func__);
+	sp887x_writereg(state, 0x33c, 0x054);
+	sp887x_writereg(state, 0x33b, 0x04c);
+	sp887x_writereg(state, 0x328, 0x000);
+	sp887x_writereg(state, 0x327, 0x005);
+	sp887x_writereg(state, 0x326, 0x001);
+	sp887x_writereg(state, 0x325, 0x001);
+	sp887x_writereg(state, 0x324, 0x001);
+	sp887x_writereg(state, 0x318, 0x050);
+	sp887x_writereg(state, 0x317, 0x3fe);
+	sp887x_writereg(state, 0x316, 0x001);
+	sp887x_writereg(state, 0x313, 0x005);
+	sp887x_writereg(state, 0x312, 0x002);
+	sp887x_writereg(state, 0x306, 0x000);
+	sp887x_writereg(state, 0x303, 0x000);
+}
+
+#define BLOCKSIZE 30
+#define FW_SIZE 0x4000
+/**
+ *  load firmware and setup MPEG interface...
+ */
+static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware *fw)
+{
+	struct sp887x_state* state = fe->demodulator_priv;
+	u8 buf [BLOCKSIZE+2];
+	int i;
+	int fw_size = fw->size;
+	const unsigned char *mem = fw->data;
+
+	dprintk("%s\n", __func__);
+
+	/* ignore the first 10 bytes, then we expect 0x4000 bytes of firmware */
+	if (fw_size < FW_SIZE+10)
+		return -ENODEV;
+
+	mem = fw->data + 10;
+
+	/* soft reset */
+	sp887x_writereg(state, 0xf1a, 0x000);
+
+	sp887x_microcontroller_stop (state);
+
+	printk ("%s: firmware upload... ", __func__);
+
+	/* setup write pointer to -1 (end of memory) */
+	/* bit 0x8000 in address is set to enable 13bit mode */
+	sp887x_writereg(state, 0x8f08, 0x1fff);
+
+	/* dummy write (wrap around to start of memory) */
+	sp887x_writereg(state, 0x8f0a, 0x0000);
+
+	for (i = 0; i < FW_SIZE; i += BLOCKSIZE) {
+		int c = BLOCKSIZE;
+		int err;
+
+		if (i+c > FW_SIZE)
+			c = FW_SIZE - i;
+
+		/* bit 0x8000 in address is set to enable 13bit mode */
+		/* bit 0x4000 enables multibyte read/write transfers */
+		/* write register is 0xf0a */
+		buf[0] = 0xcf;
+		buf[1] = 0x0a;
+
+		memcpy(&buf[2], mem + i, c);
+
+		if ((err = i2c_writebytes (state, buf, c+2)) < 0) {
+			printk ("failed.\n");
+			printk ("%s: i2c error (err == %i)\n", __func__, err);
+			return err;
+		}
+	}
+
+	/* don't write RS bytes between packets */
+	sp887x_writereg(state, 0xc13, 0x001);
+
+	/* suppress clock if (!data_valid) */
+	sp887x_writereg(state, 0xc14, 0x000);
+
+	/* setup MPEG interface... */
+	sp887x_writereg(state, 0xc1a, 0x872);
+	sp887x_writereg(state, 0xc1b, 0x001);
+	sp887x_writereg(state, 0xc1c, 0x000); /* parallel mode (serial mode == 1) */
+	sp887x_writereg(state, 0xc1a, 0x871);
+
+	/* ADC mode, 2 for MT8872, 3 for SP8870/SP8871 */
+	sp887x_writereg(state, 0x301, 0x002);
+
+	sp887x_setup_agc(state);
+
+	/* bit 0x010: enable data valid signal */
+	sp887x_writereg(state, 0xd00, 0x010);
+	sp887x_writereg(state, 0x0d1, 0x000);
+	return 0;
+};
+
+static int configure_reg0xc05(struct dtv_frontend_properties *p, u16 *reg0xc05)
+{
+	int known_parameters = 1;
+
+	*reg0xc05 = 0x000;
+
+	switch (p->modulation) {
+	case QPSK:
+		break;
+	case QAM_16:
+		*reg0xc05 |= (1 << 10);
+		break;
+	case QAM_64:
+		*reg0xc05 |= (2 << 10);
+		break;
+	case QAM_AUTO:
+		known_parameters = 0;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	switch (p->hierarchy) {
+	case HIERARCHY_NONE:
+		break;
+	case HIERARCHY_1:
+		*reg0xc05 |= (1 << 7);
+		break;
+	case HIERARCHY_2:
+		*reg0xc05 |= (2 << 7);
+		break;
+	case HIERARCHY_4:
+		*reg0xc05 |= (3 << 7);
+		break;
+	case HIERARCHY_AUTO:
+		known_parameters = 0;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	switch (p->code_rate_HP) {
+	case FEC_1_2:
+		break;
+	case FEC_2_3:
+		*reg0xc05 |= (1 << 3);
+		break;
+	case FEC_3_4:
+		*reg0xc05 |= (2 << 3);
+		break;
+	case FEC_5_6:
+		*reg0xc05 |= (3 << 3);
+		break;
+	case FEC_7_8:
+		*reg0xc05 |= (4 << 3);
+		break;
+	case FEC_AUTO:
+		known_parameters = 0;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	if (known_parameters)
+		*reg0xc05 |= (2 << 1);	/* use specified parameters */
+	else
+		*reg0xc05 |= (1 << 1);	/* enable autoprobing */
+
+	return 0;
+}
+
+/**
+ *  estimates division of two 24bit numbers,
+ *  derived from the ves1820/stv0299 driver code
+ */
+static void divide (int n, int d, int *quotient_i, int *quotient_f)
+{
+	unsigned int q, r;
+
+	r = (n % d) << 8;
+	q = (r / d);
+
+	if (quotient_i)
+		*quotient_i = q;
+
+	if (quotient_f) {
+		r = (r % d) << 8;
+		q = (q << 8) | (r / d);
+		r = (r % d) << 8;
+		*quotient_f = (q << 8) | (r / d);
+	}
+}
+
+static void sp887x_correct_offsets (struct sp887x_state* state,
+				    struct dtv_frontend_properties *p,
+				    int actual_freq)
+{
+	static const u32 srate_correction [] = { 1879617, 4544878, 8098561 };
+	int bw_index;
+	int freq_offset = actual_freq - p->frequency;
+	int sysclock = 61003; //[kHz]
+	int ifreq = 36000000;
+	int freq;
+	int frequency_shift;
+
+	switch (p->bandwidth_hz) {
+	default:
+	case 8000000:
+		bw_index = 0;
+		break;
+	case 7000000:
+		bw_index = 1;
+		break;
+	case 6000000:
+		bw_index = 2;
+		break;
+	}
+
+	if (p->inversion == INVERSION_ON)
+		freq = ifreq - freq_offset;
+	else
+		freq = ifreq + freq_offset;
+
+	divide(freq / 333, sysclock, NULL, &frequency_shift);
+
+	if (p->inversion == INVERSION_ON)
+		frequency_shift = -frequency_shift;
+
+	/* sample rate correction */
+	sp887x_writereg(state, 0x319, srate_correction[bw_index] >> 12);
+	sp887x_writereg(state, 0x31a, srate_correction[bw_index] & 0xfff);
+
+	/* carrier offset correction */
+	sp887x_writereg(state, 0x309, frequency_shift >> 12);
+	sp887x_writereg(state, 0x30a, frequency_shift & 0xfff);
+}
+
+static int sp887x_setup_frontend_parameters(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct sp887x_state* state = fe->demodulator_priv;
+	unsigned actual_freq;
+	int err;
+	u16 val, reg0xc05;
+
+	if (p->bandwidth_hz != 8000000 &&
+	    p->bandwidth_hz != 7000000 &&
+	    p->bandwidth_hz != 6000000)
+		return -EINVAL;
+
+	if ((err = configure_reg0xc05(p, &reg0xc05)))
+		return err;
+
+	sp887x_microcontroller_stop(state);
+
+	/* setup the PLL */
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+	if (fe->ops.tuner_ops.get_frequency) {
+		fe->ops.tuner_ops.get_frequency(fe, &actual_freq);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	} else {
+		actual_freq = p->frequency;
+	}
+
+	/* read status reg in order to clear <pending irqs */
+	sp887x_readreg(state, 0x200);
+
+	sp887x_correct_offsets(state, p, actual_freq);
+
+	/* filter for 6/7/8 Mhz channel */
+	if (p->bandwidth_hz == 6000000)
+		val = 2;
+	else if (p->bandwidth_hz == 7000000)
+		val = 1;
+	else
+		val = 0;
+
+	sp887x_writereg(state, 0x311, val);
+
+	/* scan order: 2k first = 0, 8k first = 1 */
+	if (p->transmission_mode == TRANSMISSION_MODE_2K)
+		sp887x_writereg(state, 0x338, 0x000);
+	else
+		sp887x_writereg(state, 0x338, 0x001);
+
+	sp887x_writereg(state, 0xc05, reg0xc05);
+
+	if (p->bandwidth_hz == 6000000)
+		val = 2 << 3;
+	else if (p->bandwidth_hz == 7000000)
+		val = 3 << 3;
+	else
+		val = 0 << 3;
+
+	/* enable OFDM and SAW bits as lock indicators in sync register 0xf17,
+	 * optimize algorithm for given bandwidth...
+	 */
+	sp887x_writereg(state, 0xf14, 0x160 | val);
+	sp887x_writereg(state, 0xf15, 0x000);
+
+	sp887x_microcontroller_start(state);
+	return 0;
+}
+
+static int sp887x_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct sp887x_state* state = fe->demodulator_priv;
+	u16 snr12 = sp887x_readreg(state, 0xf16);
+	u16 sync0x200 = sp887x_readreg(state, 0x200);
+	u16 sync0xf17 = sp887x_readreg(state, 0xf17);
+
+	*status = 0;
+
+	if (snr12 > 0x00f)
+		*status |= FE_HAS_SIGNAL;
+
+	//if (sync0x200 & 0x004)
+	//	*status |= FE_HAS_SYNC | FE_HAS_CARRIER;
+
+	//if (sync0x200 & 0x008)
+	//	*status |= FE_HAS_VITERBI;
+
+	if ((sync0xf17 & 0x00f) == 0x002) {
+		*status |= FE_HAS_LOCK;
+		*status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_CARRIER;
+	}
+
+	if (sync0x200 & 0x001) {	/* tuner adjustment requested...*/
+		int steps = (sync0x200 >> 4) & 0x00f;
+		if (steps & 0x008)
+			steps = -steps;
+		dprintk("sp887x: implement tuner adjustment (%+i steps)!!\n",
+		       steps);
+	}
+
+	return 0;
+}
+
+static int sp887x_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct sp887x_state* state = fe->demodulator_priv;
+
+	*ber = (sp887x_readreg(state, 0xc08) & 0x3f) |
+	       (sp887x_readreg(state, 0xc07) << 6);
+	sp887x_writereg(state, 0xc08, 0x000);
+	sp887x_writereg(state, 0xc07, 0x000);
+	if (*ber >= 0x3fff0)
+		*ber = ~0;
+
+	return 0;
+}
+
+static int sp887x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct sp887x_state* state = fe->demodulator_priv;
+
+	u16 snr12 = sp887x_readreg(state, 0xf16);
+	u32 signal = 3 * (snr12 << 4);
+	*strength = (signal < 0xffff) ? signal : 0xffff;
+
+	return 0;
+}
+
+static int sp887x_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct sp887x_state* state = fe->demodulator_priv;
+
+	u16 snr12 = sp887x_readreg(state, 0xf16);
+	*snr = (snr12 << 4) | (snr12 >> 8);
+
+	return 0;
+}
+
+static int sp887x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct sp887x_state* state = fe->demodulator_priv;
+
+	*ucblocks = sp887x_readreg(state, 0xc0c);
+	if (*ucblocks == 0xfff)
+		*ucblocks = ~0;
+
+	return 0;
+}
+
+static int sp887x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct sp887x_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		return sp887x_writereg(state, 0x206, 0x001);
+	} else {
+		return sp887x_writereg(state, 0x206, 0x000);
+	}
+}
+
+static int sp887x_sleep(struct dvb_frontend* fe)
+{
+	struct sp887x_state* state = fe->demodulator_priv;
+
+	/* tristate TS output and disable interface pins */
+	sp887x_writereg(state, 0xc18, 0x000);
+
+	return 0;
+}
+
+static int sp887x_init(struct dvb_frontend* fe)
+{
+	struct sp887x_state* state = fe->demodulator_priv;
+	const struct firmware *fw = NULL;
+	int ret;
+
+	if (!state->initialised) {
+		/* request the firmware, this will block until someone uploads it */
+		printk("sp887x: waiting for firmware upload (%s)...\n", SP887X_DEFAULT_FIRMWARE);
+		ret = state->config->request_firmware(fe, &fw, SP887X_DEFAULT_FIRMWARE);
+		if (ret) {
+			printk("sp887x: no firmware upload (timeout or file not found?)\n");
+			return ret;
+		}
+
+		ret = sp887x_initial_setup(fe, fw);
+		release_firmware(fw);
+		if (ret) {
+			printk("sp887x: writing firmware to device failed\n");
+			return ret;
+		}
+		printk("sp887x: firmware upload complete\n");
+		state->initialised = 1;
+	}
+
+	/* enable TS output and interface pins */
+	sp887x_writereg(state, 0xc18, 0x00d);
+
+	return 0;
+}
+
+static int sp887x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+	fesettings->min_delay_ms = 350;
+	fesettings->step_size = 166666*2;
+	fesettings->max_drift = (166666*2)+1;
+	return 0;
+}
+
+static void sp887x_release(struct dvb_frontend* fe)
+{
+	struct sp887x_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops sp887x_ops;
+
+struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
+				   struct i2c_adapter* i2c)
+{
+	struct sp887x_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct sp887x_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->initialised = 0;
+
+	/* check if the demod is there */
+	if (sp887x_readreg(state, 0x0200) < 0) goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &sp887x_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops sp887x_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "Spase SP887x DVB-T",
+		.frequency_min =  50500000,
+		.frequency_max = 858000000,
+		.frequency_stepsize = 166666,
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+			FE_CAN_RECOVER
+	},
+
+	.release = sp887x_release,
+
+	.init = sp887x_init,
+	.sleep = sp887x_sleep,
+	.i2c_gate_ctrl = sp887x_i2c_gate_ctrl,
+
+	.set_frontend = sp887x_setup_frontend_parameters,
+	.get_tune_settings = sp887x_get_tune_settings,
+
+	.read_status = sp887x_read_status,
+	.read_ber = sp887x_read_ber,
+	.read_signal_strength = sp887x_read_signal_strength,
+	.read_snr = sp887x_read_snr,
+	.read_ucblocks = sp887x_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Spase sp887x DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(sp887x_attach);
diff --git a/drivers/media/dvb-frontends/sp887x.h b/drivers/media/dvb-frontends/sp887x.h
new file mode 100644
index 0000000..04eff6e
--- /dev/null
+++ b/drivers/media/dvb-frontends/sp887x.h
@@ -0,0 +1,32 @@
+/*
+   Driver for the Spase sp887x demodulator
+*/
+
+#ifndef SP887X_H
+#define SP887X_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct sp887x_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* request firmware for device */
+	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+};
+
+#if defined(CONFIG_DVB_SP887X) || (defined(CONFIG_DVB_SP887X_MODULE) && defined(MODULE))
+extern struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
+					  struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
+					  struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_SP887X
+
+#endif // SP887X_H
diff --git a/drivers/media/dvb-frontends/stb0899_algo.c b/drivers/media/dvb-frontends/stb0899_algo.c
new file mode 100644
index 0000000..117a569
--- /dev/null
+++ b/drivers/media/dvb-frontends/stb0899_algo.c
@@ -0,0 +1,1525 @@
+/*
+	STB0899 Multistandard Frontend driver
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "stb0899_drv.h"
+#include "stb0899_priv.h"
+#include "stb0899_reg.h"
+
+static inline u32 stb0899_do_div(u64 n, u32 d)
+{
+	/* wrap do_div() for ease of use */
+
+	do_div(n, d);
+	return n;
+}
+
+#if 0
+/* These functions are currently unused */
+/*
+ * stb0899_calc_srate
+ * Compute symbol rate
+ */
+static u32 stb0899_calc_srate(u32 master_clk, u8 *sfr)
+{
+	u64 tmp;
+
+	/* srate = (SFR * master_clk) >> 20 */
+
+	/* sfr is of size 20 bit, stored with an offset of 4 bit */
+	tmp = (((u32)sfr[0]) << 16) | (((u32)sfr[1]) << 8) | sfr[2];
+	tmp &= ~0xf;
+	tmp *= master_clk;
+	tmp >>= 24;
+
+	return tmp;
+}
+
+/*
+ * stb0899_get_srate
+ * Get the current symbol rate
+ */
+static u32 stb0899_get_srate(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal = &state->internal;
+	u8 sfr[3];
+
+	stb0899_read_regs(state, STB0899_SFRH, sfr, 3);
+
+	return stb0899_calc_srate(internal->master_clk, sfr);
+}
+#endif
+
+/*
+ * stb0899_set_srate
+ * Set symbol frequency
+ * MasterClock: master clock frequency (hz)
+ * SymbolRate: symbol rate (bauds)
+ * return symbol frequency
+ */
+static u32 stb0899_set_srate(struct stb0899_state *state, u32 master_clk, u32 srate)
+{
+	u32 tmp;
+	u8 sfr[3];
+
+	dprintk(state->verbose, FE_DEBUG, 1, "-->");
+	/*
+	 * in order to have the maximum precision, the symbol rate entered into
+	 * the chip is computed as the closest value of the "true value".
+	 * In this purpose, the symbol rate value is rounded (1 is added on the bit
+	 * below the LSB )
+	 *
+	 * srate = (SFR * master_clk) >> 20
+	 *      <=>
+	 *   SFR = srate << 20 / master_clk
+	 *
+	 * rounded:
+	 *   SFR = (srate << 21 + master_clk) / (2 * master_clk)
+	 *
+	 * stored as 20 bit number with an offset of 4 bit:
+	 *   sfr = SFR << 4;
+	 */
+
+	tmp = stb0899_do_div((((u64)srate) << 21) + master_clk, 2 * master_clk);
+	tmp <<= 4;
+
+	sfr[0] = tmp >> 16;
+	sfr[1] = tmp >>  8;
+	sfr[2] = tmp;
+
+	stb0899_write_regs(state, STB0899_SFRH, sfr, 3);
+
+	return srate;
+}
+
+/*
+ * stb0899_calc_derot_time
+ * Compute the amount of time needed by the derotator to lock
+ * SymbolRate: Symbol rate
+ * return: derotator time constant (ms)
+ */
+static long stb0899_calc_derot_time(long srate)
+{
+	if (srate > 0)
+		return (100000 / (srate / 1000));
+	else
+		return 0;
+}
+
+/*
+ * stb0899_carr_width
+ * Compute the width of the carrier
+ * return: width of carrier (kHz or Mhz)
+ */
+long stb0899_carr_width(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal = &state->internal;
+
+	return (internal->srate + (internal->srate * internal->rolloff) / 100);
+}
+
+/*
+ * stb0899_first_subrange
+ * Compute the first subrange of the search
+ */
+static void stb0899_first_subrange(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal	= &state->internal;
+	struct stb0899_params *params		= &state->params;
+	struct stb0899_config *config		=  state->config;
+
+	int range = 0;
+	u32 bandwidth = 0;
+
+	if (config->tuner_get_bandwidth) {
+		stb0899_i2c_gate_ctrl(&state->frontend, 1);
+		config->tuner_get_bandwidth(&state->frontend, &bandwidth);
+		stb0899_i2c_gate_ctrl(&state->frontend, 0);
+		range = bandwidth - stb0899_carr_width(state) / 2;
+	}
+
+	if (range > 0)
+		internal->sub_range = min(internal->srch_range, range);
+	else
+		internal->sub_range = 0;
+
+	internal->freq = params->freq;
+	internal->tuner_offst = 0L;
+	internal->sub_dir = 1;
+}
+
+/*
+ * stb0899_check_tmg
+ * check for timing lock
+ * internal.Ttiming: time to wait for loop lock
+ */
+static enum stb0899_status stb0899_check_tmg(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal = &state->internal;
+	int lock;
+	u8 reg;
+	s8 timing;
+
+	msleep(internal->t_derot);
+
+	stb0899_write_reg(state, STB0899_RTF, 0xf2);
+	reg = stb0899_read_reg(state, STB0899_TLIR);
+	lock = STB0899_GETFIELD(TLIR_TMG_LOCK_IND, reg);
+	timing = stb0899_read_reg(state, STB0899_RTF);
+
+	if (lock >= 42) {
+		if ((lock > 48) && (abs(timing) >= 110)) {
+			internal->status = ANALOGCARRIER;
+			dprintk(state->verbose, FE_DEBUG, 1, "-->ANALOG Carrier !");
+		} else {
+			internal->status = TIMINGOK;
+			dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK !");
+		}
+	} else {
+		internal->status = NOTIMING;
+		dprintk(state->verbose, FE_DEBUG, 1, "-->NO TIMING !");
+	}
+	return internal->status;
+}
+
+/*
+ * stb0899_search_tmg
+ * perform a fs/2 zig-zag to find timing
+ */
+static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal = &state->internal;
+	struct stb0899_params *params = &state->params;
+
+	short int derot_step, derot_freq = 0, derot_limit, next_loop = 3;
+	int index = 0;
+	u8 cfr[2];
+
+	internal->status = NOTIMING;
+
+	/* timing loop computation & symbol rate optimisation	*/
+	derot_limit = (internal->sub_range / 2L) / internal->mclk;
+	derot_step = (params->srate / 2L) / internal->mclk;
+
+	while ((stb0899_check_tmg(state) != TIMINGOK) && next_loop) {
+		index++;
+		derot_freq += index * internal->direction * derot_step;	/* next derot zig zag position	*/
+
+		if (abs(derot_freq) > derot_limit)
+			next_loop--;
+
+		if (next_loop) {
+			STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
+			STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
+			stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency		*/
+		}
+		internal->direction = -internal->direction;	/* Change zigzag direction		*/
+	}
+
+	if (internal->status == TIMINGOK) {
+		stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency		*/
+		internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
+		dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK ! Derot Freq = %d", internal->derot_freq);
+	}
+
+	return internal->status;
+}
+
+/*
+ * stb0899_check_carrier
+ * Check for carrier found
+ */
+static enum stb0899_status stb0899_check_carrier(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal = &state->internal;
+	u8 reg;
+
+	msleep(internal->t_derot); /* wait for derotator ok	*/
+
+	reg = stb0899_read_reg(state, STB0899_CFD);
+	STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
+	stb0899_write_reg(state, STB0899_CFD, reg);
+
+	reg = stb0899_read_reg(state, STB0899_DSTATUS);
+	dprintk(state->verbose, FE_DEBUG, 1, "--------------------> STB0899_DSTATUS=[0x%02x]", reg);
+	if (STB0899_GETFIELD(CARRIER_FOUND, reg)) {
+		internal->status = CARRIEROK;
+		dprintk(state->verbose, FE_DEBUG, 1, "-------------> CARRIEROK !");
+	} else {
+		internal->status = NOCARRIER;
+		dprintk(state->verbose, FE_DEBUG, 1, "-------------> NOCARRIER !");
+	}
+
+	return internal->status;
+}
+
+/*
+ * stb0899_search_carrier
+ * Search for a QPSK carrier with the derotator
+ */
+static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal = &state->internal;
+
+	short int derot_freq = 0, last_derot_freq = 0, derot_limit, next_loop = 3;
+	int index = 0;
+	u8 cfr[2];
+	u8 reg;
+
+	internal->status = NOCARRIER;
+	derot_limit = (internal->sub_range / 2L) / internal->mclk;
+	derot_freq = internal->derot_freq;
+
+	reg = stb0899_read_reg(state, STB0899_CFD);
+	STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
+	stb0899_write_reg(state, STB0899_CFD, reg);
+
+	do {
+		dprintk(state->verbose, FE_DEBUG, 1, "Derot Freq=%d, mclk=%d", derot_freq, internal->mclk);
+		if (stb0899_check_carrier(state) == NOCARRIER) {
+			index++;
+			last_derot_freq = derot_freq;
+			derot_freq += index * internal->direction * internal->derot_step; /* next zig zag derotator position */
+
+			if(abs(derot_freq) > derot_limit)
+				next_loop--;
+
+			if (next_loop) {
+				reg = stb0899_read_reg(state, STB0899_CFD);
+				STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
+				stb0899_write_reg(state, STB0899_CFD, reg);
+
+				STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
+				STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
+				stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency	*/
+			}
+		}
+
+		internal->direction = -internal->direction; /* Change zigzag direction */
+	} while ((internal->status != CARRIEROK) && next_loop);
+
+	if (internal->status == CARRIEROK) {
+		stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */
+		internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
+		dprintk(state->verbose, FE_DEBUG, 1, "----> CARRIER OK !, Derot Freq=%d", internal->derot_freq);
+	} else {
+		internal->derot_freq = last_derot_freq;
+	}
+
+	return internal->status;
+}
+
+/*
+ * stb0899_check_data
+ * Check for data found
+ */
+static enum stb0899_status stb0899_check_data(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal = &state->internal;
+	struct stb0899_params *params = &state->params;
+
+	int lock = 0, index = 0, dataTime = 500, loop;
+	u8 reg;
+
+	internal->status = NODATA;
+
+	/* RESET FEC	*/
+	reg = stb0899_read_reg(state, STB0899_TSTRES);
+	STB0899_SETFIELD_VAL(FRESACS, reg, 1);
+	stb0899_write_reg(state, STB0899_TSTRES, reg);
+	msleep(1);
+	reg = stb0899_read_reg(state, STB0899_TSTRES);
+	STB0899_SETFIELD_VAL(FRESACS, reg, 0);
+	stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+	if (params->srate <= 2000000)
+		dataTime = 2000;
+	else if (params->srate <= 5000000)
+		dataTime = 1500;
+	else if (params->srate <= 15000000)
+		dataTime = 1000;
+	else
+		dataTime = 500;
+
+	/* clear previous failed END_LOOPVIT */
+	stb0899_read_reg(state, STB0899_VSTATUS);
+
+	stb0899_write_reg(state, STB0899_DSTATUS2, 0x00); /* force search loop	*/
+	while (1) {
+		/* WARNING! VIT LOCKED has to be tested before VIT_END_LOOOP	*/
+		reg = stb0899_read_reg(state, STB0899_VSTATUS);
+		lock = STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg);
+		loop = STB0899_GETFIELD(VSTATUS_END_LOOPVIT, reg);
+
+		if (lock || loop || (index > dataTime))
+			break;
+		index++;
+	}
+
+	if (lock) {	/* DATA LOCK indicator	*/
+		internal->status = DATAOK;
+		dprintk(state->verbose, FE_DEBUG, 1, "-----------------> DATA OK !");
+	}
+
+	return internal->status;
+}
+
+/*
+ * stb0899_search_data
+ * Search for a QPSK carrier with the derotator
+ */
+static enum stb0899_status stb0899_search_data(struct stb0899_state *state)
+{
+	short int derot_freq, derot_step, derot_limit, next_loop = 3;
+	u8 cfr[2];
+	u8 reg;
+	int index = 1;
+
+	struct stb0899_internal *internal = &state->internal;
+	struct stb0899_params *params = &state->params;
+
+	derot_step = (params->srate / 4L) / internal->mclk;
+	derot_limit = (internal->sub_range / 2L) / internal->mclk;
+	derot_freq = internal->derot_freq;
+
+	do {
+		if ((internal->status != CARRIEROK) || (stb0899_check_data(state) != DATAOK)) {
+
+			derot_freq += index * internal->direction * derot_step;	/* next zig zag derotator position */
+			if (abs(derot_freq) > derot_limit)
+				next_loop--;
+
+			if (next_loop) {
+				dprintk(state->verbose, FE_DEBUG, 1, "Derot freq=%d, mclk=%d", derot_freq, internal->mclk);
+				reg = stb0899_read_reg(state, STB0899_CFD);
+				STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
+				stb0899_write_reg(state, STB0899_CFD, reg);
+
+				STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
+				STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
+				stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency	*/
+
+				stb0899_check_carrier(state);
+				index++;
+			}
+		}
+		internal->direction = -internal->direction; /* change zig zag direction */
+	} while ((internal->status != DATAOK) && next_loop);
+
+	if (internal->status == DATAOK) {
+		stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */
+		internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
+		dprintk(state->verbose, FE_DEBUG, 1, "------> DATAOK ! Derot Freq=%d", internal->derot_freq);
+	}
+
+	return internal->status;
+}
+
+/*
+ * stb0899_check_range
+ * check if the found frequency is in the correct range
+ */
+static enum stb0899_status stb0899_check_range(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal = &state->internal;
+	struct stb0899_params *params = &state->params;
+
+	int range_offst, tp_freq;
+
+	range_offst = internal->srch_range / 2000;
+	tp_freq = internal->freq + (internal->derot_freq * internal->mclk) / 1000;
+
+	if ((tp_freq >= params->freq - range_offst) && (tp_freq <= params->freq + range_offst)) {
+		internal->status = RANGEOK;
+		dprintk(state->verbose, FE_DEBUG, 1, "----> RANGEOK !");
+	} else {
+		internal->status = OUTOFRANGE;
+		dprintk(state->verbose, FE_DEBUG, 1, "----> OUT OF RANGE !");
+	}
+
+	return internal->status;
+}
+
+/*
+ * NextSubRange
+ * Compute the next subrange of the search
+ */
+static void next_sub_range(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal = &state->internal;
+	struct stb0899_params *params = &state->params;
+
+	long old_sub_range;
+
+	if (internal->sub_dir > 0) {
+		old_sub_range = internal->sub_range;
+		internal->sub_range = min((internal->srch_range / 2) -
+					  (internal->tuner_offst + internal->sub_range / 2),
+					   internal->sub_range);
+
+		if (internal->sub_range < 0)
+			internal->sub_range = 0;
+
+		internal->tuner_offst += (old_sub_range + internal->sub_range) / 2;
+	}
+
+	internal->freq = params->freq + (internal->sub_dir * internal->tuner_offst) / 1000;
+	internal->sub_dir = -internal->sub_dir;
+}
+
+/*
+ * stb0899_dvbs_algo
+ * Search for a signal, timing, carrier and data for a
+ * given frequency in a given range
+ */
+enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state)
+{
+	struct stb0899_params *params		= &state->params;
+	struct stb0899_internal *internal	= &state->internal;
+	struct stb0899_config *config		= state->config;
+
+	u8 bclc, reg;
+	u8 cfr[2];
+	u8 eq_const[10];
+	s32 clnI = 3;
+	u32 bandwidth = 0;
+
+	/* BETA values rated @ 99MHz	*/
+	s32 betaTab[5][4] = {
+	       /*  5   10   20   30MBps */
+		{ 37,  34,  32,  31 }, /* QPSK 1/2	*/
+		{ 37,  35,  33,  31 }, /* QPSK 2/3	*/
+		{ 37,  35,  33,  31 }, /* QPSK 3/4	*/
+		{ 37,  36,  33,	 32 }, /* QPSK 5/6	*/
+		{ 37,  36,  33,	 32 }  /* QPSK 7/8	*/
+	};
+
+	internal->direction = 1;
+
+	stb0899_set_srate(state, internal->master_clk, params->srate);
+	/* Carrier loop optimization versus symbol rate for acquisition*/
+	if (params->srate <= 5000000) {
+		stb0899_write_reg(state, STB0899_ACLC, 0x89);
+		bclc = stb0899_read_reg(state, STB0899_BCLC);
+		STB0899_SETFIELD_VAL(BETA, bclc, 0x1c);
+		stb0899_write_reg(state, STB0899_BCLC, bclc);
+		clnI = 0;
+	} else if (params->srate <= 15000000) {
+		stb0899_write_reg(state, STB0899_ACLC, 0xc9);
+		bclc = stb0899_read_reg(state, STB0899_BCLC);
+		STB0899_SETFIELD_VAL(BETA, bclc, 0x22);
+		stb0899_write_reg(state, STB0899_BCLC, bclc);
+		clnI = 1;
+	} else if(params->srate <= 25000000) {
+		stb0899_write_reg(state, STB0899_ACLC, 0x89);
+		bclc = stb0899_read_reg(state, STB0899_BCLC);
+		STB0899_SETFIELD_VAL(BETA, bclc, 0x27);
+		stb0899_write_reg(state, STB0899_BCLC, bclc);
+		clnI = 2;
+	} else {
+		stb0899_write_reg(state, STB0899_ACLC, 0xc8);
+		bclc = stb0899_read_reg(state, STB0899_BCLC);
+		STB0899_SETFIELD_VAL(BETA, bclc, 0x29);
+		stb0899_write_reg(state, STB0899_BCLC, bclc);
+		clnI = 3;
+	}
+
+	dprintk(state->verbose, FE_DEBUG, 1, "Set the timing loop to acquisition");
+	/* Set the timing loop to acquisition	*/
+	stb0899_write_reg(state, STB0899_RTC, 0x46);
+	stb0899_write_reg(state, STB0899_CFD, 0xee);
+
+	/* !! WARNING !!
+	 * Do not read any status variables while acquisition,
+	 * If any needed, read before the acquisition starts
+	 * querying status while acquiring causes the
+	 * acquisition to go bad and hence no locks.
+	 */
+	dprintk(state->verbose, FE_DEBUG, 1, "Derot Percent=%d Srate=%d mclk=%d",
+		internal->derot_percent, params->srate, internal->mclk);
+
+	/* Initial calculations	*/
+	internal->derot_step = internal->derot_percent * (params->srate / 1000L) / internal->mclk; /* DerotStep/1000 * Fsymbol	*/
+	internal->t_derot = stb0899_calc_derot_time(params->srate);
+	internal->t_data = 500;
+
+	dprintk(state->verbose, FE_DEBUG, 1, "RESET stream merger");
+	/* RESET Stream merger	*/
+	reg = stb0899_read_reg(state, STB0899_TSTRES);
+	STB0899_SETFIELD_VAL(FRESRS, reg, 1);
+	stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+	/*
+	 * Set KDIVIDER to an intermediate value between
+	 * 1/2 and 7/8 for acquisition
+	 */
+	reg = stb0899_read_reg(state, STB0899_DEMAPVIT);
+	STB0899_SETFIELD_VAL(DEMAPVIT_KDIVIDER, reg, 60);
+	stb0899_write_reg(state, STB0899_DEMAPVIT, reg);
+
+	stb0899_write_reg(state, STB0899_EQON, 0x01); /* Equalizer OFF while acquiring */
+	stb0899_write_reg(state, STB0899_VITSYNC, 0x19);
+
+	stb0899_first_subrange(state);
+	do {
+		/* Initialisations */
+		cfr[0] = cfr[1] = 0;
+		stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* RESET derotator frequency	*/
+
+		stb0899_write_reg(state, STB0899_RTF, 0);
+		reg = stb0899_read_reg(state, STB0899_CFD);
+		STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
+		stb0899_write_reg(state, STB0899_CFD, reg);
+
+		internal->derot_freq = 0;
+		internal->status = NOAGC1;
+
+		/* enable tuner I/O */
+		stb0899_i2c_gate_ctrl(&state->frontend, 1);
+
+		/* Move tuner to frequency */
+		dprintk(state->verbose, FE_DEBUG, 1, "Tuner set frequency");
+		if (state->config->tuner_set_frequency)
+			state->config->tuner_set_frequency(&state->frontend, internal->freq);
+
+		if (state->config->tuner_get_frequency)
+			state->config->tuner_get_frequency(&state->frontend, &internal->freq);
+
+		msleep(internal->t_agc1 + internal->t_agc2 + internal->t_derot); /* AGC1, AGC2 and timing loop	*/
+		dprintk(state->verbose, FE_DEBUG, 1, "current derot freq=%d", internal->derot_freq);
+		internal->status = AGC1OK;
+
+		/* There is signal in the band	*/
+		if (config->tuner_get_bandwidth)
+			config->tuner_get_bandwidth(&state->frontend, &bandwidth);
+
+		/* disable tuner I/O */
+		stb0899_i2c_gate_ctrl(&state->frontend, 0);
+
+		if (params->srate <= bandwidth / 2)
+			stb0899_search_tmg(state); /* For low rates (SCPC)	*/
+		else
+			stb0899_check_tmg(state); /* For high rates (MCPC)	*/
+
+		if (internal->status == TIMINGOK) {
+			dprintk(state->verbose, FE_DEBUG, 1,
+				"TIMING OK ! Derot freq=%d, mclk=%d",
+				internal->derot_freq, internal->mclk);
+
+			if (stb0899_search_carrier(state) == CARRIEROK) {	/* Search for carrier	*/
+				dprintk(state->verbose, FE_DEBUG, 1,
+					"CARRIER OK ! Derot freq=%d, mclk=%d",
+					internal->derot_freq, internal->mclk);
+
+				if (stb0899_search_data(state) == DATAOK) {	/* Check for data	*/
+					dprintk(state->verbose, FE_DEBUG, 1,
+						"DATA OK ! Derot freq=%d, mclk=%d",
+						internal->derot_freq, internal->mclk);
+
+					if (stb0899_check_range(state) == RANGEOK) {
+						dprintk(state->verbose, FE_DEBUG, 1,
+							"RANGE OK ! derot freq=%d, mclk=%d",
+							internal->derot_freq, internal->mclk);
+
+						internal->freq = params->freq + ((internal->derot_freq * internal->mclk) / 1000);
+						reg = stb0899_read_reg(state, STB0899_PLPARM);
+						internal->fecrate = STB0899_GETFIELD(VITCURPUN, reg);
+						dprintk(state->verbose, FE_DEBUG, 1,
+							"freq=%d, internal resultant freq=%d",
+							params->freq, internal->freq);
+
+						dprintk(state->verbose, FE_DEBUG, 1,
+							"internal puncture rate=%d",
+							internal->fecrate);
+					}
+				}
+			}
+		}
+		if (internal->status != RANGEOK)
+			next_sub_range(state);
+
+	} while (internal->sub_range && internal->status != RANGEOK);
+
+	/* Set the timing loop to tracking	*/
+	stb0899_write_reg(state, STB0899_RTC, 0x33);
+	stb0899_write_reg(state, STB0899_CFD, 0xf7);
+	/* if locked and range ok, set Kdiv	*/
+	if (internal->status == RANGEOK) {
+		dprintk(state->verbose, FE_DEBUG, 1, "Locked & Range OK !");
+		stb0899_write_reg(state, STB0899_EQON, 0x41);		/* Equalizer OFF while acquiring	*/
+		stb0899_write_reg(state, STB0899_VITSYNC, 0x39);	/* SN to b'11 for acquisition		*/
+
+		/*
+		 * Carrier loop optimization versus
+		 * symbol Rate/Puncture Rate for Tracking
+		 */
+		reg = stb0899_read_reg(state, STB0899_BCLC);
+		switch (internal->fecrate) {
+		case STB0899_FEC_1_2:		/* 13	*/
+			stb0899_write_reg(state, STB0899_DEMAPVIT, 0x1a);
+			STB0899_SETFIELD_VAL(BETA, reg, betaTab[0][clnI]);
+			stb0899_write_reg(state, STB0899_BCLC, reg);
+			break;
+		case STB0899_FEC_2_3:		/* 18	*/
+			stb0899_write_reg(state, STB0899_DEMAPVIT, 44);
+			STB0899_SETFIELD_VAL(BETA, reg, betaTab[1][clnI]);
+			stb0899_write_reg(state, STB0899_BCLC, reg);
+			break;
+		case STB0899_FEC_3_4:		/* 21	*/
+			stb0899_write_reg(state, STB0899_DEMAPVIT, 60);
+			STB0899_SETFIELD_VAL(BETA, reg, betaTab[2][clnI]);
+			stb0899_write_reg(state, STB0899_BCLC, reg);
+			break;
+		case STB0899_FEC_5_6:		/* 24	*/
+			stb0899_write_reg(state, STB0899_DEMAPVIT, 75);
+			STB0899_SETFIELD_VAL(BETA, reg, betaTab[3][clnI]);
+			stb0899_write_reg(state, STB0899_BCLC, reg);
+			break;
+		case STB0899_FEC_6_7:		/* 25	*/
+			stb0899_write_reg(state, STB0899_DEMAPVIT, 88);
+			stb0899_write_reg(state, STB0899_ACLC, 0x88);
+			stb0899_write_reg(state, STB0899_BCLC, 0x9a);
+			break;
+		case STB0899_FEC_7_8:		/* 26	*/
+			stb0899_write_reg(state, STB0899_DEMAPVIT, 94);
+			STB0899_SETFIELD_VAL(BETA, reg, betaTab[4][clnI]);
+			stb0899_write_reg(state, STB0899_BCLC, reg);
+			break;
+		default:
+			dprintk(state->verbose, FE_DEBUG, 1, "Unsupported Puncture Rate");
+			break;
+		}
+		/* release stream merger RESET	*/
+		reg = stb0899_read_reg(state, STB0899_TSTRES);
+		STB0899_SETFIELD_VAL(FRESRS, reg, 0);
+		stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+		/* disable carrier detector	*/
+		reg = stb0899_read_reg(state, STB0899_CFD);
+		STB0899_SETFIELD_VAL(CFD_ON, reg, 0);
+		stb0899_write_reg(state, STB0899_CFD, reg);
+
+		stb0899_read_regs(state, STB0899_EQUAI1, eq_const, 10);
+	}
+
+	return internal->status;
+}
+
+/*
+ * stb0899_dvbs2_config_uwp
+ * Configure UWP state machine
+ */
+static void stb0899_dvbs2_config_uwp(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal = &state->internal;
+	struct stb0899_config *config = state->config;
+	u32 uwp1, uwp2, uwp3, reg;
+
+	uwp1 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL1);
+	uwp2 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL2);
+	uwp3 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL3);
+
+	STB0899_SETFIELD_VAL(UWP_ESN0_AVE, uwp1, config->esno_ave);
+	STB0899_SETFIELD_VAL(UWP_ESN0_QUANT, uwp1, config->esno_quant);
+	STB0899_SETFIELD_VAL(UWP_TH_SOF, uwp1, config->uwp_threshold_sof);
+
+	STB0899_SETFIELD_VAL(FE_COARSE_TRK, uwp2, internal->av_frame_coarse);
+	STB0899_SETFIELD_VAL(FE_FINE_TRK, uwp2, internal->av_frame_fine);
+	STB0899_SETFIELD_VAL(UWP_MISS_TH, uwp2, config->miss_threshold);
+
+	STB0899_SETFIELD_VAL(UWP_TH_ACQ, uwp3, config->uwp_threshold_acq);
+	STB0899_SETFIELD_VAL(UWP_TH_TRACK, uwp3, config->uwp_threshold_track);
+
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL1, STB0899_OFF0_UWP_CNTRL1, uwp1);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL2, STB0899_OFF0_UWP_CNTRL2, uwp2);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL3, STB0899_OFF0_UWP_CNTRL3, uwp3);
+
+	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, SOF_SRCH_TO);
+	STB0899_SETFIELD_VAL(SOF_SEARCH_TIMEOUT, reg, config->sof_search_timeout);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_SOF_SRCH_TO, STB0899_OFF0_SOF_SRCH_TO, reg);
+}
+
+/*
+ * stb0899_dvbs2_config_csm_auto
+ * Set CSM to AUTO mode
+ */
+static void stb0899_dvbs2_config_csm_auto(struct stb0899_state *state)
+{
+	u32 reg;
+
+	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
+	STB0899_SETFIELD_VAL(CSM_AUTO_PARAM, reg, 1);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, reg);
+}
+
+static long Log2Int(int number)
+{
+	int i;
+
+	i = 0;
+	while ((1 << i) <= abs(number))
+		i++;
+
+	if (number == 0)
+		i = 1;
+
+	return i - 1;
+}
+
+/*
+ * stb0899_dvbs2_calc_srate
+ * compute BTR_NOM_FREQ for the symbol rate
+ */
+static u32 stb0899_dvbs2_calc_srate(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal	= &state->internal;
+	struct stb0899_config *config		= state->config;
+
+	u32 dec_ratio, dec_rate, decim, remain, intval, btr_nom_freq;
+	u32 master_clk, srate;
+
+	dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
+	dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
+	dec_rate = Log2Int(dec_ratio);
+	decim = 1 << dec_rate;
+	master_clk = internal->master_clk / 1000;
+	srate = internal->srate / 1000;
+
+	if (decim <= 4) {
+		intval = (decim * (1 << (config->btr_nco_bits - 1))) / master_clk;
+		remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk;
+	} else {
+		intval = (1 << (config->btr_nco_bits - 1)) / (master_clk / 100) * decim / 100;
+		remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk;
+	}
+	btr_nom_freq = (intval * srate) + ((remain * srate) / master_clk);
+
+	return btr_nom_freq;
+}
+
+/*
+ * stb0899_dvbs2_calc_dev
+ * compute the correction to be applied to symbol rate
+ */
+static u32 stb0899_dvbs2_calc_dev(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal = &state->internal;
+	u32 dec_ratio, correction, master_clk, srate;
+
+	dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
+	dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
+
+	master_clk = internal->master_clk / 1000;	/* for integer Caculation*/
+	srate = internal->srate / 1000;	/* for integer Caculation*/
+	correction = (512 * master_clk) / (2 * dec_ratio * srate);
+
+	return	correction;
+}
+
+/*
+ * stb0899_dvbs2_set_srate
+ * Set DVBS2 symbol rate
+ */
+static void stb0899_dvbs2_set_srate(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal = &state->internal;
+
+	u32 dec_ratio, dec_rate, win_sel, decim, f_sym, btr_nom_freq;
+	u32 correction, freq_adj, band_lim, decim_cntrl, reg;
+	u8 anti_alias;
+
+	/*set decimation to 1*/
+	dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
+	dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
+	dec_rate = Log2Int(dec_ratio);
+
+	win_sel = 0;
+	if (dec_rate >= 5)
+		win_sel = dec_rate - 4;
+
+	decim = (1 << dec_rate);
+	/* (FSamp/Fsymbol *100) for integer Caculation */
+	f_sym = internal->master_clk / ((decim * internal->srate) / 1000);
+
+	if (f_sym <= 2250)	/* don't band limit signal going into btr block*/
+		band_lim = 1;
+	else
+		band_lim = 0;	/* band limit signal going into btr block*/
+
+	decim_cntrl = ((win_sel << 3) & 0x18) + ((band_lim << 5) & 0x20) + (dec_rate & 0x7);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DECIM_CNTRL, STB0899_OFF0_DECIM_CNTRL, decim_cntrl);
+
+	if (f_sym <= 3450)
+		anti_alias = 0;
+	else if (f_sym <= 4250)
+		anti_alias = 1;
+	else
+		anti_alias = 2;
+
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ANTI_ALIAS_SEL, STB0899_OFF0_ANTI_ALIAS_SEL, anti_alias);
+	btr_nom_freq = stb0899_dvbs2_calc_srate(state);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_NOM_FREQ, STB0899_OFF0_BTR_NOM_FREQ, btr_nom_freq);
+
+	correction = stb0899_dvbs2_calc_dev(state);
+	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL);
+	STB0899_SETFIELD_VAL(BTR_FREQ_CORR, reg, correction);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg);
+
+	/* scale UWP+CSM frequency to sample rate*/
+	freq_adj =  internal->srate / (internal->master_clk / 4096);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_FREQ_ADJ_SCALE, STB0899_OFF0_FREQ_ADJ_SCALE, freq_adj);
+}
+
+/*
+ * stb0899_dvbs2_set_btr_loopbw
+ * set bit timing loop bandwidth as a percentage of the symbol rate
+ */
+static void stb0899_dvbs2_set_btr_loopbw(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal	= &state->internal;
+	struct stb0899_config *config		= state->config;
+
+	u32 sym_peak = 23, zeta = 707, loopbw_percent = 60;
+	s32 dec_ratio, dec_rate, k_btr1_rshft, k_btr1, k_btr0_rshft;
+	s32 k_btr0, k_btr2_rshft, k_direct_shift, k_indirect_shift;
+	u32 decim, K, wn, k_direct, k_indirect;
+	u32 reg;
+
+	dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
+	dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
+	dec_rate = Log2Int(dec_ratio);
+	decim = (1 << dec_rate);
+
+	sym_peak *= 576000;
+	K = (1 << config->btr_nco_bits) / (internal->master_clk / 1000);
+	K *= (internal->srate / 1000000) * decim; /*k=k 10^-8*/
+
+	if (K != 0) {
+		K = sym_peak / K;
+		wn = (4 * zeta * zeta) + 1000000;
+		wn = (2 * (loopbw_percent * 1000) * 40 * zeta) /wn;  /*wn =wn 10^-8*/
+
+		k_indirect = (wn * wn) / K;
+		k_indirect = k_indirect;	  /*kindirect = kindirect 10^-6*/
+		k_direct   = (2 * wn * zeta) / K;	/*kDirect = kDirect 10^-2*/
+		k_direct  *= 100;
+
+		k_direct_shift = Log2Int(k_direct) - Log2Int(10000) - 2;
+		k_btr1_rshft = (-1 * k_direct_shift) + config->btr_gain_shift_offset;
+		k_btr1 = k_direct / (1 << k_direct_shift);
+		k_btr1 /= 10000;
+
+		k_indirect_shift = Log2Int(k_indirect + 15) - 20 /*- 2*/;
+		k_btr0_rshft = (-1 * k_indirect_shift) + config->btr_gain_shift_offset;
+		k_btr0 = k_indirect * (1 << (-k_indirect_shift));
+		k_btr0 /= 1000000;
+
+		k_btr2_rshft = 0;
+		if (k_btr0_rshft > 15) {
+			k_btr2_rshft = k_btr0_rshft - 15;
+			k_btr0_rshft = 15;
+		}
+		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_LOOP_GAIN);
+		STB0899_SETFIELD_VAL(KBTR0_RSHFT, reg, k_btr0_rshft);
+		STB0899_SETFIELD_VAL(KBTR0, reg, k_btr0);
+		STB0899_SETFIELD_VAL(KBTR1_RSHFT, reg, k_btr1_rshft);
+		STB0899_SETFIELD_VAL(KBTR1, reg, k_btr1);
+		STB0899_SETFIELD_VAL(KBTR2_RSHFT, reg, k_btr2_rshft);
+		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, reg);
+	} else
+		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, 0xc4c4f);
+}
+
+/*
+ * stb0899_dvbs2_set_carr_freq
+ * set nominal frequency for carrier search
+ */
+static void stb0899_dvbs2_set_carr_freq(struct stb0899_state *state, s32 carr_freq, u32 master_clk)
+{
+	struct stb0899_config *config = state->config;
+	s32 crl_nom_freq;
+	u32 reg;
+
+	crl_nom_freq = (1 << config->crl_nco_bits) / master_clk;
+	crl_nom_freq *= carr_freq;
+	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ);
+	STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, crl_nom_freq);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg);
+}
+
+/*
+ * stb0899_dvbs2_init_calc
+ * Initialize DVBS2 UWP, CSM, carrier and timing loops
+ */
+static void stb0899_dvbs2_init_calc(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal = &state->internal;
+	s32 steps, step_size;
+	u32 range, reg;
+
+	/* config uwp and csm */
+	stb0899_dvbs2_config_uwp(state);
+	stb0899_dvbs2_config_csm_auto(state);
+
+	/* initialize BTR	*/
+	stb0899_dvbs2_set_srate(state);
+	stb0899_dvbs2_set_btr_loopbw(state);
+
+	if (internal->srate / 1000000 >= 15)
+		step_size = (1 << 17) / 5;
+	else if (internal->srate / 1000000 >= 10)
+		step_size = (1 << 17) / 7;
+	else if (internal->srate / 1000000 >= 5)
+		step_size = (1 << 17) / 10;
+	else
+		step_size = (1 << 17) / 4;
+
+	range = internal->srch_range / 1000000;
+	steps = (10 * range * (1 << 17)) / (step_size * (internal->srate / 1000000));
+	steps = (steps + 6) / 10;
+	steps = (steps == 0) ? 1 : steps;
+	if (steps % 2 == 0)
+		stb0899_dvbs2_set_carr_freq(state, internal->center_freq -
+					   (internal->step_size * (internal->srate / 20000000)),
+					   (internal->master_clk) / 1000000);
+	else
+		stb0899_dvbs2_set_carr_freq(state, internal->center_freq, (internal->master_clk) / 1000000);
+
+	/*Set Carrier Search params (zigzag, num steps and freq step size*/
+	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, ACQ_CNTRL2);
+	STB0899_SETFIELD_VAL(ZIGZAG, reg, 1);
+	STB0899_SETFIELD_VAL(NUM_STEPS, reg, steps);
+	STB0899_SETFIELD_VAL(FREQ_STEPSIZE, reg, step_size);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQ_CNTRL2, STB0899_OFF0_ACQ_CNTRL2, reg);
+}
+
+/*
+ * stb0899_dvbs2_btr_init
+ * initialize the timing loop
+ */
+static void stb0899_dvbs2_btr_init(struct stb0899_state *state)
+{
+	u32 reg;
+
+	/* set enable BTR loopback	*/
+	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL);
+	STB0899_SETFIELD_VAL(INTRP_PHS_SENSE, reg, 1);
+	STB0899_SETFIELD_VAL(BTR_ERR_ENA, reg, 1);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg);
+
+	/* fix btr freq accum at 0	*/
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x10000000);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x00000000);
+
+	/* fix btr freq accum at 0	*/
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x10000000);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x00000000);
+}
+
+/*
+ * stb0899_dvbs2_reacquire
+ * trigger a DVB-S2 acquisition
+ */
+static void stb0899_dvbs2_reacquire(struct stb0899_state *state)
+{
+	u32 reg = 0;
+
+	/* demod soft reset	*/
+	STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 1);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg);
+
+	/*Reset Timing Loop	*/
+	stb0899_dvbs2_btr_init(state);
+
+	/* reset Carrier loop	*/
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, (1 << 30));
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, 0);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_LOOP_GAIN, STB0899_OFF0_CRL_LOOP_GAIN, 0);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, (1 << 30));
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, 0);
+
+	/*release demod soft reset	*/
+	reg = 0;
+	STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 0);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg);
+
+	/* start acquisition process	*/
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQUIRE_TRIG, STB0899_OFF0_ACQUIRE_TRIG, 1);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_LOCK_LOST, STB0899_OFF0_LOCK_LOST, 0);
+
+	/* equalizer Init	*/
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 1);
+
+	/*Start equilizer	*/
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 0);
+
+	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL);
+	STB0899_SETFIELD_VAL(EQ_SHIFT, reg, 0);
+	STB0899_SETFIELD_VAL(EQ_DISABLE_UPDATE, reg, 0);
+	STB0899_SETFIELD_VAL(EQ_DELAY, reg, 0x05);
+	STB0899_SETFIELD_VAL(EQ_ADAPT_MODE, reg, 0x01);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg);
+
+	/* RESET Packet delineator	*/
+	stb0899_write_reg(state, STB0899_PDELCTRL, 0x4a);
+}
+
+/*
+ * stb0899_dvbs2_get_dmd_status
+ * get DVB-S2 Demod LOCK status
+ */
+static enum stb0899_status stb0899_dvbs2_get_dmd_status(struct stb0899_state *state, int timeout)
+{
+	int time = -10, lock = 0, uwp, csm;
+	u32 reg;
+
+	do {
+		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STATUS);
+		dprintk(state->verbose, FE_DEBUG, 1, "DMD_STATUS=[0x%02x]", reg);
+		if (STB0899_GETFIELD(IF_AGC_LOCK, reg))
+			dprintk(state->verbose, FE_DEBUG, 1, "------------->IF AGC LOCKED !");
+		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STAT2);
+		dprintk(state->verbose, FE_DEBUG, 1, "----------->DMD STAT2=[0x%02x]", reg);
+		uwp = STB0899_GETFIELD(UWP_LOCK, reg);
+		csm = STB0899_GETFIELD(CSM_LOCK, reg);
+		if (uwp && csm)
+			lock = 1;
+
+		time += 10;
+		msleep(10);
+
+	} while ((!lock) && (time <= timeout));
+
+	if (lock) {
+		dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 LOCK !");
+		return DVBS2_DEMOD_LOCK;
+	} else {
+		return DVBS2_DEMOD_NOLOCK;
+	}
+}
+
+/*
+ * stb0899_dvbs2_get_data_lock
+ * get FEC status
+ */
+static int stb0899_dvbs2_get_data_lock(struct stb0899_state *state, int timeout)
+{
+	int time = 0, lock = 0;
+	u8 reg;
+
+	while ((!lock) && (time < timeout)) {
+		reg = stb0899_read_reg(state, STB0899_CFGPDELSTATUS1);
+		dprintk(state->verbose, FE_DEBUG, 1, "---------> CFGPDELSTATUS=[0x%02x]", reg);
+		lock = STB0899_GETFIELD(CFGPDELSTATUS_LOCK, reg);
+		time++;
+	}
+
+	return lock;
+}
+
+/*
+ * stb0899_dvbs2_get_fec_status
+ * get DVB-S2 FEC LOCK status
+ */
+static enum stb0899_status stb0899_dvbs2_get_fec_status(struct stb0899_state *state, int timeout)
+{
+	int time = 0, Locked;
+
+	do {
+		Locked = stb0899_dvbs2_get_data_lock(state, 1);
+		time++;
+		msleep(1);
+
+	} while ((!Locked) && (time < timeout));
+
+	if (Locked) {
+		dprintk(state->verbose, FE_DEBUG, 1, "---------->DVB-S2 FEC LOCK !");
+		return DVBS2_FEC_LOCK;
+	} else {
+		return DVBS2_FEC_NOLOCK;
+	}
+}
+
+
+/*
+ * stb0899_dvbs2_init_csm
+ * set parameters for manual mode
+ */
+static void stb0899_dvbs2_init_csm(struct stb0899_state *state, int pilots, enum stb0899_modcod modcod)
+{
+	struct stb0899_internal *internal = &state->internal;
+
+	s32 dvt_tbl = 1, two_pass = 0, agc_gain = 6, agc_shift = 0, loop_shift = 0, phs_diff_thr = 0x80;
+	s32 gamma_acq, gamma_rho_acq, gamma_trk, gamma_rho_trk, lock_count_thr;
+	u32 csm1, csm2, csm3, csm4;
+
+	if (((internal->master_clk / internal->srate) <= 4) && (modcod <= 11) && (pilots == 1)) {
+		switch (modcod) {
+		case STB0899_QPSK_12:
+			gamma_acq		= 25;
+			gamma_rho_acq		= 2700;
+			gamma_trk		= 12;
+			gamma_rho_trk		= 180;
+			lock_count_thr		= 8;
+			break;
+		case STB0899_QPSK_35:
+			gamma_acq		= 38;
+			gamma_rho_acq		= 7182;
+			gamma_trk		= 14;
+			gamma_rho_trk		= 308;
+			lock_count_thr		= 8;
+			break;
+		case STB0899_QPSK_23:
+			gamma_acq		= 42;
+			gamma_rho_acq		= 9408;
+			gamma_trk		= 17;
+			gamma_rho_trk		= 476;
+			lock_count_thr		= 8;
+			break;
+		case STB0899_QPSK_34:
+			gamma_acq		= 53;
+			gamma_rho_acq		= 16642;
+			gamma_trk		= 19;
+			gamma_rho_trk		= 646;
+			lock_count_thr		= 8;
+			break;
+		case STB0899_QPSK_45:
+			gamma_acq		= 53;
+			gamma_rho_acq		= 17119;
+			gamma_trk		= 22;
+			gamma_rho_trk		= 880;
+			lock_count_thr		= 8;
+			break;
+		case STB0899_QPSK_56:
+			gamma_acq		= 55;
+			gamma_rho_acq		= 19250;
+			gamma_trk		= 23;
+			gamma_rho_trk		= 989;
+			lock_count_thr		= 8;
+			break;
+		case STB0899_QPSK_89:
+			gamma_acq		= 60;
+			gamma_rho_acq		= 24240;
+			gamma_trk		= 24;
+			gamma_rho_trk		= 1176;
+			lock_count_thr		= 8;
+			break;
+		case STB0899_QPSK_910:
+			gamma_acq		= 66;
+			gamma_rho_acq		= 29634;
+			gamma_trk		= 24;
+			gamma_rho_trk		= 1176;
+			lock_count_thr		= 8;
+			break;
+		default:
+			gamma_acq		= 66;
+			gamma_rho_acq		= 29634;
+			gamma_trk		= 24;
+			gamma_rho_trk		= 1176;
+			lock_count_thr		= 8;
+			break;
+		}
+
+		csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
+		STB0899_SETFIELD_VAL(CSM_AUTO_PARAM, csm1, 0);
+		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1);
+
+		csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
+		csm2 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL2);
+		csm3 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL3);
+		csm4 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL4);
+
+		STB0899_SETFIELD_VAL(CSM_DVT_TABLE, csm1, dvt_tbl);
+		STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, two_pass);
+		STB0899_SETFIELD_VAL(CSM_AGC_GAIN, csm1, agc_gain);
+		STB0899_SETFIELD_VAL(CSM_AGC_SHIFT, csm1, agc_shift);
+		STB0899_SETFIELD_VAL(FE_LOOP_SHIFT, csm1, loop_shift);
+		STB0899_SETFIELD_VAL(CSM_GAMMA_ACQ, csm2, gamma_acq);
+		STB0899_SETFIELD_VAL(CSM_GAMMA_RHOACQ, csm2, gamma_rho_acq);
+		STB0899_SETFIELD_VAL(CSM_GAMMA_TRACK, csm3, gamma_trk);
+		STB0899_SETFIELD_VAL(CSM_GAMMA_RHOTRACK, csm3, gamma_rho_trk);
+		STB0899_SETFIELD_VAL(CSM_LOCKCOUNT_THRESH, csm4, lock_count_thr);
+		STB0899_SETFIELD_VAL(CSM_PHASEDIFF_THRESH, csm4, phs_diff_thr);
+
+		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1);
+		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL2, STB0899_OFF0_CSM_CNTRL2, csm2);
+		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL3, STB0899_OFF0_CSM_CNTRL3, csm3);
+		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL4, STB0899_OFF0_CSM_CNTRL4, csm4);
+	}
+}
+
+/*
+ * stb0899_dvbs2_get_srate
+ * get DVB-S2 Symbol Rate
+ */
+static u32 stb0899_dvbs2_get_srate(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal = &state->internal;
+	struct stb0899_config *config = state->config;
+
+	u32 bTrNomFreq, srate, decimRate, intval1, intval2, reg;
+	int div1, div2, rem1, rem2;
+
+	div1 = config->btr_nco_bits / 2;
+	div2 = config->btr_nco_bits - div1 - 1;
+
+	bTrNomFreq = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_NOM_FREQ);
+
+	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DECIM_CNTRL);
+	decimRate = STB0899_GETFIELD(DECIM_RATE, reg);
+	decimRate = (1 << decimRate);
+
+	intval1 = internal->master_clk / (1 << div1);
+	intval2 = bTrNomFreq / (1 << div2);
+
+	rem1 = internal->master_clk % (1 << div1);
+	rem2 = bTrNomFreq % (1 << div2);
+	/* only for integer calculation	*/
+	srate = (intval1 * intval2) + ((intval1 * rem2) / (1 << div2)) + ((intval2 * rem1) / (1 << div1));
+	srate /= decimRate;	/*symbrate = (btrnomfreq_register_val*MasterClock)/2^(27+decim_rate_field) */
+
+	return	srate;
+}
+
+/*
+ * stb0899_dvbs2_algo
+ * Search for signal, timing, carrier and data for a given
+ * frequency in a given range
+ */
+enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal = &state->internal;
+	enum stb0899_modcod modcod;
+
+	s32 offsetfreq, searchTime, FecLockTime, pilots, iqSpectrum;
+	int i = 0;
+	u32 reg, csm1;
+
+	if (internal->srate <= 2000000) {
+		searchTime	= 5000;	/* 5000 ms max time to lock UWP and CSM, SYMB <= 2Mbs		*/
+		FecLockTime	= 350;	/* 350  ms max time to lock FEC, SYMB <= 2Mbs			*/
+	} else if (internal->srate <= 5000000) {
+		searchTime	= 2500;	/* 2500 ms max time to lock UWP and CSM, 2Mbs < SYMB <= 5Mbs	*/
+		FecLockTime	= 170;	/* 170  ms max time to lock FEC, 2Mbs< SYMB <= 5Mbs		*/
+	} else if (internal->srate <= 10000000) {
+		searchTime	= 1500;	/* 1500 ms max time to lock UWP and CSM, 5Mbs <SYMB <= 10Mbs	*/
+		FecLockTime	= 80;	/* 80  ms max time to lock FEC, 5Mbs< SYMB <= 10Mbs		*/
+	} else if (internal->srate <= 15000000) {
+		searchTime	= 500;	/* 500 ms max time to lock UWP and CSM, 10Mbs <SYMB <= 15Mbs	*/
+		FecLockTime	= 50;	/* 50  ms max time to lock FEC, 10Mbs< SYMB <= 15Mbs		*/
+	} else if (internal->srate <= 20000000) {
+		searchTime	= 300;	/* 300 ms max time to lock UWP and CSM, 15Mbs < SYMB <= 20Mbs	*/
+		FecLockTime	= 30;	/* 50  ms max time to lock FEC, 15Mbs< SYMB <= 20Mbs		*/
+	} else if (internal->srate <= 25000000) {
+		searchTime	= 250;	/* 250 ms max time to lock UWP and CSM, 20 Mbs < SYMB <= 25Mbs	*/
+		FecLockTime	= 25;	/* 25 ms max time to lock FEC, 20Mbs< SYMB <= 25Mbs		*/
+	} else {
+		searchTime	= 150;	/* 150 ms max time to lock UWP and CSM, SYMB > 25Mbs		*/
+		FecLockTime	= 20;	/* 20 ms max time to lock FEC, 20Mbs< SYMB <= 25Mbs		*/
+	}
+
+	/* Maintain Stream Merger in reset during acquisition	*/
+	reg = stb0899_read_reg(state, STB0899_TSTRES);
+	STB0899_SETFIELD_VAL(FRESRS, reg, 1);
+	stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+	/* enable tuner I/O */
+	stb0899_i2c_gate_ctrl(&state->frontend, 1);
+
+	/* Move tuner to frequency	*/
+	if (state->config->tuner_set_frequency)
+		state->config->tuner_set_frequency(&state->frontend, internal->freq);
+	if (state->config->tuner_get_frequency)
+		state->config->tuner_get_frequency(&state->frontend, &internal->freq);
+
+	/* disable tuner I/O */
+	stb0899_i2c_gate_ctrl(&state->frontend, 0);
+
+	/* Set IF AGC to acquisition	*/
+	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL);
+	STB0899_SETFIELD_VAL(IF_LOOP_GAIN, reg,  4);
+	STB0899_SETFIELD_VAL(IF_AGC_REF, reg, 32);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg);
+
+	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL2);
+	STB0899_SETFIELD_VAL(IF_AGC_DUMP_PER, reg, 0);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL2, STB0899_OFF0_IF_AGC_CNTRL2, reg);
+
+	/* Initialisation	*/
+	stb0899_dvbs2_init_calc(state);
+
+	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
+	switch (internal->inversion) {
+	case IQ_SWAP_OFF:
+		STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 0);
+		break;
+	case IQ_SWAP_ON:
+		STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1);
+		break;
+	case IQ_SWAP_AUTO:	/* use last successful search first	*/
+		STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1);
+		break;
+	}
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg);
+	stb0899_dvbs2_reacquire(state);
+
+	/* Wait for demod lock (UWP and CSM)	*/
+	internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime);
+
+	if (internal->status == DVBS2_DEMOD_LOCK) {
+		dprintk(state->verbose, FE_DEBUG, 1, "------------> DVB-S2 DEMOD LOCK !");
+		i = 0;
+		/* Demod Locked, check FEC status	*/
+		internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
+
+		/*If false lock (UWP and CSM Locked but no FEC) try 3 time max*/
+		while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) {
+			/*	Read the frequency offset*/
+			offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
+
+			/* Set the Nominal frequency to the found frequency offset for the next reacquire*/
+			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ);
+			STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq);
+			stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg);
+			stb0899_dvbs2_reacquire(state);
+			internal->status = stb0899_dvbs2_get_fec_status(state, searchTime);
+			i++;
+		}
+	}
+
+	if (internal->status != DVBS2_FEC_LOCK) {
+		if (internal->inversion == IQ_SWAP_AUTO) {
+			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
+			iqSpectrum = STB0899_GETFIELD(SPECTRUM_INVERT, reg);
+			/* IQ Spectrum Inversion	*/
+			STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, !iqSpectrum);
+			stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg);
+			/* start acquistion process	*/
+			stb0899_dvbs2_reacquire(state);
+
+			/* Wait for demod lock (UWP and CSM)	*/
+			internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime);
+			if (internal->status == DVBS2_DEMOD_LOCK) {
+				i = 0;
+				/* Demod Locked, check FEC	*/
+				internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
+				/*try thrice for false locks, (UWP and CSM Locked but no FEC)	*/
+				while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) {
+					/*	Read the frequency offset*/
+					offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
+
+					/* Set the Nominal frequency to the found frequency offset for the next reacquire*/
+					reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ);
+					STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq);
+					stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg);
+
+					stb0899_dvbs2_reacquire(state);
+					internal->status = stb0899_dvbs2_get_fec_status(state, searchTime);
+					i++;
+				}
+			}
+/*
+			if (pParams->DVBS2State == FE_DVBS2_FEC_LOCKED)
+				pParams->IQLocked = !iqSpectrum;
+*/
+		}
+	}
+	if (internal->status == DVBS2_FEC_LOCK) {
+		dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 FEC Lock !");
+		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2);
+		modcod = STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 2;
+		pilots = STB0899_GETFIELD(UWP_DECODE_MOD, reg) & 0x01;
+
+		if ((((10 * internal->master_clk) / (internal->srate / 10)) <= 410) &&
+		      (INRANGE(STB0899_QPSK_23, modcod, STB0899_QPSK_910)) &&
+		      (pilots == 1)) {
+
+			stb0899_dvbs2_init_csm(state, pilots, modcod);
+			/* Wait for UWP,CSM and data LOCK 20ms max	*/
+			internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
+
+			i = 0;
+			while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) {
+				csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
+				STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, 1);
+				stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1);
+				csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
+				STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, 0);
+				stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1);
+
+				internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
+				i++;
+			}
+		}
+
+		if ((((10 * internal->master_clk) / (internal->srate / 10)) <= 410) &&
+		      (INRANGE(STB0899_QPSK_12, modcod, STB0899_QPSK_35)) &&
+		      (pilots == 1)) {
+
+			/* Equalizer Disable update	 */
+			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL);
+			STB0899_SETFIELD_VAL(EQ_DISABLE_UPDATE, reg, 1);
+			stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg);
+		}
+
+		/* slow down the Equalizer once locked	*/
+		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL);
+		STB0899_SETFIELD_VAL(EQ_SHIFT, reg, 0x02);
+		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg);
+
+		/* Store signal parameters	*/
+		offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
+
+		offsetfreq = offsetfreq / ((1 << 30) / 1000);
+		offsetfreq *= (internal->master_clk / 1000000);
+		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
+		if (STB0899_GETFIELD(SPECTRUM_INVERT, reg))
+			offsetfreq *= -1;
+
+		internal->freq = internal->freq - offsetfreq;
+		internal->srate = stb0899_dvbs2_get_srate(state);
+
+		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2);
+		internal->modcod = STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 2;
+		internal->pilots = STB0899_GETFIELD(UWP_DECODE_MOD, reg) & 0x01;
+		internal->frame_length = (STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 1) & 0x01;
+
+		 /* Set IF AGC to tracking	*/
+		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL);
+		STB0899_SETFIELD_VAL(IF_LOOP_GAIN, reg,  3);
+
+		/* if QPSK 1/2,QPSK 3/5 or QPSK 2/3 set IF AGC reference to 16 otherwise 32*/
+		if (INRANGE(STB0899_QPSK_12, internal->modcod, STB0899_QPSK_23))
+			STB0899_SETFIELD_VAL(IF_AGC_REF, reg, 16);
+
+		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg);
+
+		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL2);
+		STB0899_SETFIELD_VAL(IF_AGC_DUMP_PER, reg, 7);
+		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL2, STB0899_OFF0_IF_AGC_CNTRL2, reg);
+	}
+
+	/* Release Stream Merger Reset		*/
+	reg = stb0899_read_reg(state, STB0899_TSTRES);
+	STB0899_SETFIELD_VAL(FRESRS, reg, 0);
+	stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+	return internal->status;
+}
diff --git a/drivers/media/dvb-frontends/stb0899_cfg.h b/drivers/media/dvb-frontends/stb0899_cfg.h
new file mode 100644
index 0000000..0867906
--- /dev/null
+++ b/drivers/media/dvb-frontends/stb0899_cfg.h
@@ -0,0 +1,287 @@
+/*
+	STB0899 Multistandard Frontend driver
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __STB0899_CFG_H
+#define __STB0899_CFG_H
+
+static const struct stb0899_s2_reg  stb0899_s2_init_2[] = {
+
+	{ STB0899_OFF0_DMD_STATUS	, STB0899_BASE_DMD_STATUS	, 0x00000103 },	/* DMDSTATUS	*/
+	{ STB0899_OFF0_CRL_FREQ		, STB0899_BASE_CRL_FREQ		, 0x3ed1da56 },	/* CRLFREQ	*/
+	{ STB0899_OFF0_BTR_FREQ		, STB0899_BASE_BTR_FREQ		, 0x00004000 },	/* BTRFREQ	*/
+	{ STB0899_OFF0_IF_AGC_GAIN	, STB0899_BASE_IF_AGC_GAIN	, 0x00002ade },	/* IFAGCGAIN	*/
+	{ STB0899_OFF0_BB_AGC_GAIN	, STB0899_BASE_BB_AGC_GAIN	, 0x000001bc },	/* BBAGCGAIN	*/
+	{ STB0899_OFF0_DC_OFFSET	, STB0899_BASE_DC_OFFSET	, 0x00000200 },	/* DCOFFSET	*/
+	{ STB0899_OFF0_DMD_CNTRL	, STB0899_BASE_DMD_CNTRL	, 0x0000000f },	/* DMDCNTRL	*/
+
+	{ STB0899_OFF0_IF_AGC_CNTRL	, STB0899_BASE_IF_AGC_CNTRL	, 0x03fb4a20 },	/* IFAGCCNTRL	*/
+	{ STB0899_OFF0_BB_AGC_CNTRL	, STB0899_BASE_BB_AGC_CNTRL	, 0x00200c97 },	/* BBAGCCNTRL	*/
+
+	{ STB0899_OFF0_CRL_CNTRL	, STB0899_BASE_CRL_CNTRL	, 0x00000016 },	/* CRLCNTRL	*/
+	{ STB0899_OFF0_CRL_PHS_INIT	, STB0899_BASE_CRL_PHS_INIT	, 0x00000000 },	/* CRLPHSINIT	*/
+	{ STB0899_OFF0_CRL_FREQ_INIT	, STB0899_BASE_CRL_FREQ_INIT	, 0x00000000 },	/* CRLFREQINIT	*/
+	{ STB0899_OFF0_CRL_LOOP_GAIN	, STB0899_BASE_CRL_LOOP_GAIN	, 0x00000000 },	/* CRLLOOPGAIN	*/
+	{ STB0899_OFF0_CRL_NOM_FREQ	, STB0899_BASE_CRL_NOM_FREQ	, 0x3ed097b6 },	/* CRLNOMFREQ	*/
+	{ STB0899_OFF0_CRL_SWP_RATE	, STB0899_BASE_CRL_SWP_RATE	, 0x00000000 },	/* CRLSWPRATE	*/
+	{ STB0899_OFF0_CRL_MAX_SWP	, STB0899_BASE_CRL_MAX_SWP	, 0x00000000 },	/* CRLMAXSWP	*/
+	{ STB0899_OFF0_CRL_LK_CNTRL	, STB0899_BASE_CRL_LK_CNTRL	, 0x0f6cdc01 },	/* CRLLKCNTRL	*/
+	{ STB0899_OFF0_DECIM_CNTRL	, STB0899_BASE_DECIM_CNTRL	, 0x00000000 },	/* DECIMCNTRL	*/
+	{ STB0899_OFF0_BTR_CNTRL	, STB0899_BASE_BTR_CNTRL	, 0x00003993 },	/* BTRCNTRL	*/
+	{ STB0899_OFF0_BTR_LOOP_GAIN	, STB0899_BASE_BTR_LOOP_GAIN	, 0x000d3c6f },	/* BTRLOOPGAIN	*/
+	{ STB0899_OFF0_BTR_PHS_INIT	, STB0899_BASE_BTR_PHS_INIT	, 0x00000000 },	/* BTRPHSINIT	*/
+	{ STB0899_OFF0_BTR_FREQ_INIT	, STB0899_BASE_BTR_FREQ_INIT	, 0x00000000 },	/* BTRFREQINIT	*/
+	{ STB0899_OFF0_BTR_NOM_FREQ	, STB0899_BASE_BTR_NOM_FREQ	, 0x0238e38e },	/* BTRNOMFREQ	*/
+	{ STB0899_OFF0_BTR_LK_CNTRL	, STB0899_BASE_BTR_LK_CNTRL	, 0x00000000 },	/* BTRLKCNTRL	*/
+	{ STB0899_OFF0_DECN_CNTRL	, STB0899_BASE_DECN_CNTRL	, 0x00000000 },	/* DECNCNTRL	*/
+	{ STB0899_OFF0_TP_CNTRL		, STB0899_BASE_TP_CNTRL		, 0x00000000 },	/* TPCNTRL	*/
+	{ STB0899_OFF0_TP_BUF_STATUS	, STB0899_BASE_TP_BUF_STATUS	, 0x00000000 },	/* TPBUFSTATUS	*/
+	{ STB0899_OFF0_DC_ESTIM		, STB0899_BASE_DC_ESTIM		, 0x00000000 },	/* DCESTIM	*/
+	{ STB0899_OFF0_FLL_CNTRL	, STB0899_BASE_FLL_CNTRL	, 0x00000000 },	/* FLLCNTRL	*/
+	{ STB0899_OFF0_FLL_FREQ_WD	, STB0899_BASE_FLL_FREQ_WD	, 0x40070000 },	/* FLLFREQWD	*/
+	{ STB0899_OFF0_ANTI_ALIAS_SEL	, STB0899_BASE_ANTI_ALIAS_SEL	, 0x00000001 },	/* ANTIALIASSEL */
+	{ STB0899_OFF0_RRC_ALPHA	, STB0899_BASE_RRC_ALPHA	, 0x00000002 },	/* RRCALPHA	*/
+	{ STB0899_OFF0_DC_ADAPT_LSHFT	, STB0899_BASE_DC_ADAPT_LSHFT	, 0x00000000 },	/* DCADAPTISHFT */
+	{ STB0899_OFF0_IMB_OFFSET	, STB0899_BASE_IMB_OFFSET	, 0x0000fe01 },	/* IMBOFFSET	*/
+	{ STB0899_OFF0_IMB_ESTIMATE	, STB0899_BASE_IMB_ESTIMATE	, 0x00000000 },	/* IMBESTIMATE	*/
+	{ STB0899_OFF0_IMB_CNTRL	, STB0899_BASE_IMB_CNTRL	, 0x00000001 },	/* IMBCNTRL	*/
+	{ STB0899_OFF0_IF_AGC_CNTRL2	, STB0899_BASE_IF_AGC_CNTRL2	, 0x00005007 },	/* IFAGCCNTRL2	*/
+	{ STB0899_OFF0_DMD_CNTRL2	, STB0899_BASE_DMD_CNTRL2	, 0x00000002 },	/* DMDCNTRL2	*/
+	{ STB0899_OFF0_TP_BUFFER	, STB0899_BASE_TP_BUFFER	, 0x00000000 },	/* TPBUFFER	*/
+	{ STB0899_OFF0_TP_BUFFER1	, STB0899_BASE_TP_BUFFER1	, 0x00000000 },	/* TPBUFFER1	*/
+	{ STB0899_OFF0_TP_BUFFER2	, STB0899_BASE_TP_BUFFER2	, 0x00000000 },	/* TPBUFFER2	*/
+	{ STB0899_OFF0_TP_BUFFER3	, STB0899_BASE_TP_BUFFER3	, 0x00000000 },	/* TPBUFFER3	*/
+	{ STB0899_OFF0_TP_BUFFER4	, STB0899_BASE_TP_BUFFER4	, 0x00000000 },	/* TPBUFFER4	*/
+	{ STB0899_OFF0_TP_BUFFER5	, STB0899_BASE_TP_BUFFER5	, 0x00000000 },	/* TPBUFFER5	*/
+	{ STB0899_OFF0_TP_BUFFER6	, STB0899_BASE_TP_BUFFER6	, 0x00000000 },	/* TPBUFFER6	*/
+	{ STB0899_OFF0_TP_BUFFER7	, STB0899_BASE_TP_BUFFER7	, 0x00000000 },	/* TPBUFFER7	*/
+	{ STB0899_OFF0_TP_BUFFER8	, STB0899_BASE_TP_BUFFER8	, 0x00000000 },	/* TPBUFFER8	*/
+	{ STB0899_OFF0_TP_BUFFER9	, STB0899_BASE_TP_BUFFER9	, 0x00000000 },	/* TPBUFFER9	*/
+	{ STB0899_OFF0_TP_BUFFER10	, STB0899_BASE_TP_BUFFER10	, 0x00000000 },	/* TPBUFFER10	*/
+	{ STB0899_OFF0_TP_BUFFER11	, STB0899_BASE_TP_BUFFER11	, 0x00000000 },	/* TPBUFFER11	*/
+	{ STB0899_OFF0_TP_BUFFER12	, STB0899_BASE_TP_BUFFER12	, 0x00000000 },	/* TPBUFFER12	*/
+	{ STB0899_OFF0_TP_BUFFER13	, STB0899_BASE_TP_BUFFER13	, 0x00000000 },	/* TPBUFFER13	*/
+	{ STB0899_OFF0_TP_BUFFER14	, STB0899_BASE_TP_BUFFER14	, 0x00000000 },	/* TPBUFFER14	*/
+	{ STB0899_OFF0_TP_BUFFER15	, STB0899_BASE_TP_BUFFER15	, 0x00000000 },	/* TPBUFFER15	*/
+	{ STB0899_OFF0_TP_BUFFER16	, STB0899_BASE_TP_BUFFER16	, 0x0000ff00 },	/* TPBUFFER16	*/
+	{ STB0899_OFF0_TP_BUFFER17	, STB0899_BASE_TP_BUFFER17	, 0x00000100 },	/* TPBUFFER17	*/
+	{ STB0899_OFF0_TP_BUFFER18	, STB0899_BASE_TP_BUFFER18	, 0x0000fe01 },	/* TPBUFFER18	*/
+	{ STB0899_OFF0_TP_BUFFER19	, STB0899_BASE_TP_BUFFER19	, 0x000004fe },	/* TPBUFFER19	*/
+	{ STB0899_OFF0_TP_BUFFER20	, STB0899_BASE_TP_BUFFER20	, 0x0000cfe7 },	/* TPBUFFER20	*/
+	{ STB0899_OFF0_TP_BUFFER21	, STB0899_BASE_TP_BUFFER21	, 0x0000bec6 },	/* TPBUFFER21	*/
+	{ STB0899_OFF0_TP_BUFFER22	, STB0899_BASE_TP_BUFFER22	, 0x0000c2bf },	/* TPBUFFER22	*/
+	{ STB0899_OFF0_TP_BUFFER23	, STB0899_BASE_TP_BUFFER23	, 0x0000c1c1 },	/* TPBUFFER23	*/
+	{ STB0899_OFF0_TP_BUFFER24	, STB0899_BASE_TP_BUFFER24	, 0x0000c1c1 },	/* TPBUFFER24	*/
+	{ STB0899_OFF0_TP_BUFFER25	, STB0899_BASE_TP_BUFFER25	, 0x0000c1c1 },	/* TPBUFFER25	*/
+	{ STB0899_OFF0_TP_BUFFER26	, STB0899_BASE_TP_BUFFER26	, 0x0000c1c1 },	/* TPBUFFER26	*/
+	{ STB0899_OFF0_TP_BUFFER27	, STB0899_BASE_TP_BUFFER27	, 0x0000c1c0 },	/* TPBUFFER27	*/
+	{ STB0899_OFF0_TP_BUFFER28	, STB0899_BASE_TP_BUFFER28	, 0x0000c0c0 },	/* TPBUFFER28	*/
+	{ STB0899_OFF0_TP_BUFFER29	, STB0899_BASE_TP_BUFFER29	, 0x0000c1c1 },	/* TPBUFFER29	*/
+	{ STB0899_OFF0_TP_BUFFER30	, STB0899_BASE_TP_BUFFER30	, 0x0000c1c1 },	/* TPBUFFER30	*/
+	{ STB0899_OFF0_TP_BUFFER31	, STB0899_BASE_TP_BUFFER31	, 0x0000c0c1 },	/* TPBUFFER31	*/
+	{ STB0899_OFF0_TP_BUFFER32	, STB0899_BASE_TP_BUFFER32	, 0x0000c0c1 },	/* TPBUFFER32	*/
+	{ STB0899_OFF0_TP_BUFFER33	, STB0899_BASE_TP_BUFFER33	, 0x0000c1c1 },	/* TPBUFFER33	*/
+	{ STB0899_OFF0_TP_BUFFER34	, STB0899_BASE_TP_BUFFER34	, 0x0000c1c1 },	/* TPBUFFER34	*/
+	{ STB0899_OFF0_TP_BUFFER35	, STB0899_BASE_TP_BUFFER35	, 0x0000c0c1 },	/* TPBUFFER35	*/
+	{ STB0899_OFF0_TP_BUFFER36	, STB0899_BASE_TP_BUFFER36	, 0x0000c1c1 },	/* TPBUFFER36	*/
+	{ STB0899_OFF0_TP_BUFFER37	, STB0899_BASE_TP_BUFFER37	, 0x0000c0c1 },	/* TPBUFFER37	*/
+	{ STB0899_OFF0_TP_BUFFER38	, STB0899_BASE_TP_BUFFER38	, 0x0000c1c1 },	/* TPBUFFER38	*/
+	{ STB0899_OFF0_TP_BUFFER39	, STB0899_BASE_TP_BUFFER39	, 0x0000c0c0 },	/* TPBUFFER39	*/
+	{ STB0899_OFF0_TP_BUFFER40	, STB0899_BASE_TP_BUFFER40	, 0x0000c1c0 },	/* TPBUFFER40	*/
+	{ STB0899_OFF0_TP_BUFFER41	, STB0899_BASE_TP_BUFFER41	, 0x0000c1c1 },	/* TPBUFFER41	*/
+	{ STB0899_OFF0_TP_BUFFER42	, STB0899_BASE_TP_BUFFER42	, 0x0000c0c0 },	/* TPBUFFER42	*/
+	{ STB0899_OFF0_TP_BUFFER43	, STB0899_BASE_TP_BUFFER43	, 0x0000c1c0 },	/* TPBUFFER43	*/
+	{ STB0899_OFF0_TP_BUFFER44	, STB0899_BASE_TP_BUFFER44	, 0x0000c0c1 },	/* TPBUFFER44	*/
+	{ STB0899_OFF0_TP_BUFFER45	, STB0899_BASE_TP_BUFFER45	, 0x0000c1be },	/* TPBUFFER45	*/
+	{ STB0899_OFF0_TP_BUFFER46	, STB0899_BASE_TP_BUFFER46	, 0x0000c1c9 },	/* TPBUFFER46	*/
+	{ STB0899_OFF0_TP_BUFFER47	, STB0899_BASE_TP_BUFFER47	, 0x0000c0da },	/* TPBUFFER47	*/
+	{ STB0899_OFF0_TP_BUFFER48	, STB0899_BASE_TP_BUFFER48	, 0x0000c0ba },	/* TPBUFFER48	*/
+	{ STB0899_OFF0_TP_BUFFER49	, STB0899_BASE_TP_BUFFER49	, 0x0000c1c4 },	/* TPBUFFER49	*/
+	{ STB0899_OFF0_TP_BUFFER50	, STB0899_BASE_TP_BUFFER50	, 0x0000c1bf },	/* TPBUFFER50	*/
+	{ STB0899_OFF0_TP_BUFFER51	, STB0899_BASE_TP_BUFFER51	, 0x0000c0c1 },	/* TPBUFFER51	*/
+	{ STB0899_OFF0_TP_BUFFER52	, STB0899_BASE_TP_BUFFER52	, 0x0000c1c0 },	/* TPBUFFER52	*/
+	{ STB0899_OFF0_TP_BUFFER53	, STB0899_BASE_TP_BUFFER53	, 0x0000c0c1 },	/* TPBUFFER53	*/
+	{ STB0899_OFF0_TP_BUFFER54	, STB0899_BASE_TP_BUFFER54	, 0x0000c1c1 },	/* TPBUFFER54	*/
+	{ STB0899_OFF0_TP_BUFFER55	, STB0899_BASE_TP_BUFFER55	, 0x0000c1c1 },	/* TPBUFFER55	*/
+	{ STB0899_OFF0_TP_BUFFER56	, STB0899_BASE_TP_BUFFER56	, 0x0000c1c1 },	/* TPBUFFER56	*/
+	{ STB0899_OFF0_TP_BUFFER57	, STB0899_BASE_TP_BUFFER57	, 0x0000c1c1 },	/* TPBUFFER57	*/
+	{ STB0899_OFF0_TP_BUFFER58	, STB0899_BASE_TP_BUFFER58	, 0x0000c1c1 },	/* TPBUFFER58	*/
+	{ STB0899_OFF0_TP_BUFFER59	, STB0899_BASE_TP_BUFFER59	, 0x0000c1c1 },	/* TPBUFFER59	*/
+	{ STB0899_OFF0_TP_BUFFER60	, STB0899_BASE_TP_BUFFER60	, 0x0000c1c1 },	/* TPBUFFER60	*/
+	{ STB0899_OFF0_TP_BUFFER61	, STB0899_BASE_TP_BUFFER61	, 0x0000c1c1 },	/* TPBUFFER61	*/
+	{ STB0899_OFF0_TP_BUFFER62	, STB0899_BASE_TP_BUFFER62	, 0x0000c1c1 },	/* TPBUFFER62	*/
+	{ STB0899_OFF0_TP_BUFFER63	, STB0899_BASE_TP_BUFFER63	, 0x0000c1c0 },	/* TPBUFFER63	*/
+	{ STB0899_OFF0_RESET_CNTRL	, STB0899_BASE_RESET_CNTRL	, 0x00000001 },	/* RESETCNTRL	*/
+	{ STB0899_OFF0_ACM_ENABLE	, STB0899_BASE_ACM_ENABLE	, 0x00005654 },	/* ACMENABLE	*/
+	{ STB0899_OFF0_DESCR_CNTRL	, STB0899_BASE_DESCR_CNTRL	, 0x00000000 },	/* DESCRCNTRL	*/
+	{ STB0899_OFF0_CSM_CNTRL1	, STB0899_BASE_CSM_CNTRL1	, 0x00020019 },	/* CSMCNTRL1	*/
+	{ STB0899_OFF0_CSM_CNTRL2	, STB0899_BASE_CSM_CNTRL2	, 0x004b3237 },	/* CSMCNTRL2	*/
+	{ STB0899_OFF0_CSM_CNTRL3	, STB0899_BASE_CSM_CNTRL3	, 0x0003dd17 },	/* CSMCNTRL3	*/
+	{ STB0899_OFF0_CSM_CNTRL4	, STB0899_BASE_CSM_CNTRL4	, 0x00008008 },	/* CSMCNTRL4	*/
+	{ STB0899_OFF0_UWP_CNTRL1	, STB0899_BASE_UWP_CNTRL1	, 0x002a3106 },	/* UWPCNTRL1	*/
+	{ STB0899_OFF0_UWP_CNTRL2	, STB0899_BASE_UWP_CNTRL2	, 0x0006140a },	/* UWPCNTRL2	*/
+	{ STB0899_OFF0_UWP_STAT1	, STB0899_BASE_UWP_STAT1	, 0x00008000 },	/* UWPSTAT1	*/
+	{ STB0899_OFF0_UWP_STAT2	, STB0899_BASE_UWP_STAT2	, 0x00000000 },	/* UWPSTAT2	*/
+	{ STB0899_OFF0_DMD_STAT2	, STB0899_BASE_DMD_STAT2	, 0x00000000 },	/* DMDSTAT2	*/
+	{ STB0899_OFF0_FREQ_ADJ_SCALE	, STB0899_BASE_FREQ_ADJ_SCALE	, 0x00000471 },	/* FREQADJSCALE */
+	{ STB0899_OFF0_UWP_CNTRL3	, STB0899_BASE_UWP_CNTRL3	, 0x017b0465 },	/* UWPCNTRL3	*/
+	{ STB0899_OFF0_SYM_CLK_SEL	, STB0899_BASE_SYM_CLK_SEL	, 0x00000002 },	/* SYMCLKSEL	*/
+	{ STB0899_OFF0_SOF_SRCH_TO	, STB0899_BASE_SOF_SRCH_TO	, 0x00196464 },	/* SOFSRCHTO	*/
+	{ STB0899_OFF0_ACQ_CNTRL1	, STB0899_BASE_ACQ_CNTRL1	, 0x00000603 },	/* ACQCNTRL1	*/
+	{ STB0899_OFF0_ACQ_CNTRL2	, STB0899_BASE_ACQ_CNTRL2	, 0x02046666 },	/* ACQCNTRL2	*/
+	{ STB0899_OFF0_ACQ_CNTRL3	, STB0899_BASE_ACQ_CNTRL3	, 0x10046583 },	/* ACQCNTRL3	*/
+	{ STB0899_OFF0_FE_SETTLE	, STB0899_BASE_FE_SETTLE	, 0x00010404 },	/* FESETTLE	*/
+	{ STB0899_OFF0_AC_DWELL		, STB0899_BASE_AC_DWELL		, 0x0002aa8a },	/* ACDWELL	*/
+	{ STB0899_OFF0_ACQUIRE_TRIG	, STB0899_BASE_ACQUIRE_TRIG	, 0x00000000 },	/* ACQUIRETRIG	*/
+	{ STB0899_OFF0_LOCK_LOST	, STB0899_BASE_LOCK_LOST	, 0x00000001 },	/* LOCKLOST	*/
+	{ STB0899_OFF0_ACQ_STAT1	, STB0899_BASE_ACQ_STAT1	, 0x00000500 },	/* ACQSTAT1	*/
+	{ STB0899_OFF0_ACQ_TIMEOUT	, STB0899_BASE_ACQ_TIMEOUT	, 0x0028a0a0 },	/* ACQTIMEOUT	*/
+	{ STB0899_OFF0_ACQ_TIME		, STB0899_BASE_ACQ_TIME		, 0x00000000 },	/* ACQTIME	*/
+	{ STB0899_OFF0_FINAL_AGC_CNTRL	, STB0899_BASE_FINAL_AGC_CNTRL	, 0x00800c17 },	/* FINALAGCCNTRL*/
+	{ STB0899_OFF0_FINAL_AGC_GAIN	, STB0899_BASE_FINAL_AGC_GAIN	, 0x00000000 },	/* FINALAGCCGAIN*/
+	{ STB0899_OFF0_EQUALIZER_INIT	, STB0899_BASE_EQUALIZER_INIT	, 0x00000000 },	/* EQUILIZERINIT*/
+	{ STB0899_OFF0_EQ_CNTRL		, STB0899_BASE_EQ_CNTRL		, 0x00054802 },	/* EQCNTL	*/
+	{ STB0899_OFF0_EQ_I_INIT_COEFF_0, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF0 */
+	{ STB0899_OFF1_EQ_I_INIT_COEFF_1, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF1 */
+	{ STB0899_OFF2_EQ_I_INIT_COEFF_2, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF2 */
+	{ STB0899_OFF3_EQ_I_INIT_COEFF_3, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF3 */
+	{ STB0899_OFF4_EQ_I_INIT_COEFF_4, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF4 */
+	{ STB0899_OFF5_EQ_I_INIT_COEFF_5, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000400 },	/* EQIINITCOEFF5 */
+	{ STB0899_OFF6_EQ_I_INIT_COEFF_6, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF6 */
+	{ STB0899_OFF7_EQ_I_INIT_COEFF_7, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF7 */
+	{ STB0899_OFF8_EQ_I_INIT_COEFF_8, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF8 */
+	{ STB0899_OFF9_EQ_I_INIT_COEFF_9, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF9 */
+	{ STB0899_OFFa_EQ_I_INIT_COEFF_10,STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF10*/
+	{ STB0899_OFF0_EQ_Q_INIT_COEFF_0, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF0 */
+	{ STB0899_OFF1_EQ_Q_INIT_COEFF_1, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF1 */
+	{ STB0899_OFF2_EQ_Q_INIT_COEFF_2, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF2 */
+	{ STB0899_OFF3_EQ_Q_INIT_COEFF_3, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF3 */
+	{ STB0899_OFF4_EQ_Q_INIT_COEFF_4, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF4 */
+	{ STB0899_OFF5_EQ_Q_INIT_COEFF_5, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF5 */
+	{ STB0899_OFF6_EQ_Q_INIT_COEFF_6, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF6 */
+	{ STB0899_OFF7_EQ_Q_INIT_COEFF_7, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF7 */
+	{ STB0899_OFF8_EQ_Q_INIT_COEFF_8, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF8 */
+	{ STB0899_OFF9_EQ_Q_INIT_COEFF_9, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF9 */
+	{ STB0899_OFFa_EQ_Q_INIT_COEFF_10,STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF10*/
+	{ STB0899_OFF0_EQ_I_OUT_COEFF_0	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT0 */
+	{ STB0899_OFF1_EQ_I_OUT_COEFF_1	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT1 */
+	{ STB0899_OFF2_EQ_I_OUT_COEFF_2	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT2 */
+	{ STB0899_OFF3_EQ_I_OUT_COEFF_3	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT3 */
+	{ STB0899_OFF4_EQ_I_OUT_COEFF_4	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT4 */
+	{ STB0899_OFF5_EQ_I_OUT_COEFF_5	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT5 */
+	{ STB0899_OFF6_EQ_I_OUT_COEFF_6	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT6 */
+	{ STB0899_OFF7_EQ_I_OUT_COEFF_7	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT7 */
+	{ STB0899_OFF8_EQ_I_OUT_COEFF_8	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT8 */
+	{ STB0899_OFF9_EQ_I_OUT_COEFF_9	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT9 */
+	{ STB0899_OFFa_EQ_I_OUT_COEFF_10,STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT10*/
+	{ STB0899_OFF0_EQ_Q_OUT_COEFF_0	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT0 */
+	{ STB0899_OFF1_EQ_Q_OUT_COEFF_1	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT1 */
+	{ STB0899_OFF2_EQ_Q_OUT_COEFF_2	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT2 */
+	{ STB0899_OFF3_EQ_Q_OUT_COEFF_3	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT3 */
+	{ STB0899_OFF4_EQ_Q_OUT_COEFF_4	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT4 */
+	{ STB0899_OFF5_EQ_Q_OUT_COEFF_5	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT5 */
+	{ STB0899_OFF6_EQ_Q_OUT_COEFF_6 , STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT6 */
+	{ STB0899_OFF7_EQ_Q_OUT_COEFF_7	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT7 */
+	{ STB0899_OFF8_EQ_Q_OUT_COEFF_8	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT8 */
+	{ STB0899_OFF9_EQ_Q_OUT_COEFF_9	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT9 */
+	{ STB0899_OFFa_EQ_Q_OUT_COEFF_10, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT10*/
+	{ 0xffff			, 0xffffffff			, 0xffffffff },
+};
+static const struct stb0899_s2_reg stb0899_s2_init_4[] = {
+	{ STB0899_OFF0_BLOCK_LNGTH	, STB0899_BASE_BLOCK_LNGTH	, 0x00000008 },	/* BLOCKLNGTH	*/
+	{ STB0899_OFF0_ROW_STR		, STB0899_BASE_ROW_STR		, 0x000000b4 },	/* ROWSTR	*/
+	{ STB0899_OFF0_BN_END_ADDR	, STB0899_BASE_BN_END_ADDR	, 0x000004b5 },	/* BNANDADDR	*/
+	{ STB0899_OFF0_CN_END_ADDR	, STB0899_BASE_CN_END_ADDR	, 0x00000b4b },	/* CNANDADDR	*/
+	{ STB0899_OFF0_INFO_LENGTH	, STB0899_BASE_INFO_LENGTH	, 0x00000078 },	/* INFOLENGTH	*/
+	{ STB0899_OFF0_BOT_ADDR		, STB0899_BASE_BOT_ADDR		, 0x000001e0 },	/* BOT_ADDR	*/
+	{ STB0899_OFF0_BCH_BLK_LN	, STB0899_BASE_BCH_BLK_LN	, 0x0000a8c0 },	/* BCHBLKLN	*/
+	{ STB0899_OFF0_BCH_T		, STB0899_BASE_BCH_T		, 0x0000000c },	/* BCHT		*/
+	{ STB0899_OFF0_CNFG_MODE	, STB0899_BASE_CNFG_MODE	, 0x00000001 },	/* CNFGMODE	*/
+	{ STB0899_OFF0_LDPC_STAT	, STB0899_BASE_LDPC_STAT	, 0x0000000d },	/* LDPCSTAT	*/
+	{ STB0899_OFF0_ITER_SCALE	, STB0899_BASE_ITER_SCALE	, 0x00000040 },	/* ITERSCALE	*/
+	{ STB0899_OFF0_INPUT_MODE	, STB0899_BASE_INPUT_MODE	, 0x00000000 },	/* INPUTMODE	*/
+	{ STB0899_OFF0_LDPCDECRST	, STB0899_BASE_LDPCDECRST	, 0x00000000 },	/* LDPCDECRST	*/
+	{ STB0899_OFF0_CLK_PER_BYTE_RW	, STB0899_BASE_CLK_PER_BYTE_RW	, 0x00000008 },	/* CLKPERBYTE	*/
+	{ STB0899_OFF0_BCH_ERRORS	, STB0899_BASE_BCH_ERRORS	, 0x00000000 },	/* BCHERRORS	*/
+	{ STB0899_OFF0_LDPC_ERRORS	, STB0899_BASE_LDPC_ERRORS	, 0x00000000 },	/* LDPCERRORS	*/
+	{ STB0899_OFF0_BCH_MODE		, STB0899_BASE_BCH_MODE		, 0x00000000 },	/* BCHMODE	*/
+	{ STB0899_OFF0_ERR_ACC_PER	, STB0899_BASE_ERR_ACC_PER	, 0x00000008 },	/* ERRACCPER	*/
+	{ STB0899_OFF0_BCH_ERR_ACC	, STB0899_BASE_BCH_ERR_ACC	, 0x00000000 },	/* BCHERRACC	*/
+	{ STB0899_OFF0_FEC_TP_SEL	, STB0899_BASE_FEC_TP_SEL	, 0x00000000 },	/* FECTPSEL	*/
+	{ 0xffff			, 0xffffffff			, 0xffffffff },
+};
+
+static const struct stb0899_s1_reg stb0899_s1_init_5[] = {
+	{ STB0899_TSTCK		, 0x00 },
+	{ STB0899_TSTRES	, 0x00 },
+	{ STB0899_TSTOUT	, 0x00 },
+	{ STB0899_TSTIN		, 0x00 },
+	{ STB0899_TSTSYS	, 0x00 },
+	{ STB0899_TSTCHIP	, 0x00 },
+	{ STB0899_TSTFREE	, 0x00 },
+	{ STB0899_TSTI2C	, 0x00 },
+	{ STB0899_BITSPEEDM	, 0x00 },
+	{ STB0899_BITSPEEDL	, 0x00 },
+	{ STB0899_TBUSBIT	, 0x00 },
+	{ STB0899_TSTDIS	, 0x00 },
+	{ STB0899_TSTDISRX	, 0x00 },
+	{ STB0899_TSTJETON	, 0x00 },
+	{ STB0899_TSTDCADJ	, 0x00 },
+	{ STB0899_TSTAGC1	, 0x00 },
+	{ STB0899_TSTAGC1N	, 0x00 },
+	{ STB0899_TSTPOLYPH	, 0x00 },
+	{ STB0899_TSTR		, 0x00 },
+	{ STB0899_TSTAGC2	, 0x00 },
+	{ STB0899_TSTCTL1	, 0x00 },
+	{ STB0899_TSTCTL2	, 0x00 },
+	{ STB0899_TSTCTL3	, 0x00 },
+	{ STB0899_TSTDEMAP	, 0x00 },
+	{ STB0899_TSTDEMAP2	, 0x00 },
+	{ STB0899_TSTDEMMON	, 0x00 },
+	{ STB0899_TSTRATE	, 0x00 },
+	{ STB0899_TSTSELOUT	, 0x00 },
+	{ STB0899_TSYNC		, 0x00 },
+	{ STB0899_TSTERR	, 0x00 },
+	{ STB0899_TSTRAM1	, 0x00 },
+	{ STB0899_TSTVSELOUT	, 0x00 },
+	{ STB0899_TSTFORCEIN	, 0x00 },
+	{ STB0899_TSTRS1	, 0x00 },
+	{ STB0899_TSTRS2	, 0x00 },
+	{ STB0899_TSTRS3	, 0x00 },
+	{ STB0899_GHOSTREG	, 0x81 },
+	{ 0xffff		, 0xff },
+};
+
+#define STB0899_DVBS2_ESNO_AVE			3
+#define STB0899_DVBS2_ESNO_QUANT		32
+#define STB0899_DVBS2_AVFRAMES_COARSE		10
+#define STB0899_DVBS2_AVFRAMES_FINE		20
+#define STB0899_DVBS2_MISS_THRESHOLD		6
+#define STB0899_DVBS2_UWP_THRESHOLD_ACQ		1125
+#define STB0899_DVBS2_UWP_THRESHOLD_TRACK	758
+#define STB0899_DVBS2_UWP_THRESHOLD_SOF		1350
+#define STB0899_DVBS2_SOF_SEARCH_TIMEOUT	1664100
+
+#define STB0899_DVBS2_BTR_NCO_BITS		28
+#define STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET	15
+#define STB0899_DVBS2_CRL_NCO_BITS		30
+#define STB0899_DVBS2_LDPC_MAX_ITER		70
+
+#endif //__STB0899_CFG_H
diff --git a/drivers/media/dvb-frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c
new file mode 100644
index 0000000..5d7f8a9
--- /dev/null
+++ b/drivers/media/dvb-frontends/stb0899_drv.c
@@ -0,0 +1,1651 @@
+/*
+	STB0899 Multistandard Frontend driver
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+#include "stb0899_drv.h"
+#include "stb0899_priv.h"
+#include "stb0899_reg.h"
+
+static unsigned int verbose = 0;//1;
+module_param(verbose, int, 0644);
+
+/* C/N in dB/10, NIRM/NIRL */
+static const struct stb0899_tab stb0899_cn_tab[] = {
+	{ 200,	2600 },
+	{ 190,	2700 },
+	{ 180,	2860 },
+	{ 170,	3020 },
+	{ 160,	3210 },
+	{ 150,	3440 },
+	{ 140,	3710 },
+	{ 130,	4010 },
+	{ 120,	4360 },
+	{ 110,	4740 },
+	{ 100,	5190 },
+	{ 90,	5670 },
+	{ 80,	6200 },
+	{ 70,	6770 },
+	{ 60,	7360 },
+	{ 50,	7970 },
+	{ 40,	8250 },
+	{ 30,	9000 },
+	{ 20,	9450 },
+	{ 15,	9600 },
+};
+
+/* DVB-S AGCIQ_VALUE vs. signal level in dBm/10.
+ * As measured, connected to a modulator.
+ * -8.0 to -50.0 dBm directly connected,
+ * -52.0 to -74.8 with extra attenuation.
+ * Cut-off to AGCIQ_VALUE = 0x80 below -74.8dBm.
+ * Crude linear extrapolation below -84.8dBm and above -8.0dBm.
+ */
+static const struct stb0899_tab stb0899_dvbsrf_tab[] = {
+	{ -750,	-128 },
+	{ -748,	 -94 },
+	{ -745,	 -92 },
+	{ -735,	 -90 },
+	{ -720,	 -87 },
+	{ -670,	 -77 },
+	{ -640,	 -70 },
+	{ -610,	 -62 },
+	{ -600,	 -60 },
+	{ -590,	 -56 },
+	{ -560,	 -41 },
+	{ -540,	 -25 },
+	{ -530,	 -17 },
+	{ -520,	 -11 },
+	{ -500,	   1 },
+	{ -490,	   6 },
+	{ -480,	  10 },
+	{ -440,	  22 },
+	{ -420,	  27 },
+	{ -400,	  31 },
+	{ -380,	  34 },
+	{ -340,	  40 },
+	{ -320,	  43 },
+	{ -280,	  48 },
+	{ -250,	  52 },
+	{ -230,	  55 },
+	{ -180,	  61 },
+	{ -140,	  66 },
+	{  -90,	  73 },
+	{  -80,	  74 },
+	{  500,	 127 }
+};
+
+/* DVB-S2 IF_AGC_GAIN vs. signal level in dBm/10.
+ * As measured, connected to a modulator.
+ * -8.0 to -50.1 dBm directly connected,
+ * -53.0 to -76.6 with extra attenuation.
+ * Cut-off to IF_AGC_GAIN = 0x3fff below -76.6dBm.
+ * Crude linear extrapolation below -76.6dBm and above -8.0dBm.
+ */
+static const struct stb0899_tab stb0899_dvbs2rf_tab[] = {
+	{  700,	    0 },
+	{  -80,	 3217 },
+	{ -150,	 3893 },
+	{ -190,	 4217 },
+	{ -240,	 4621 },
+	{ -280,	 4945 },
+	{ -320,	 5273 },
+	{ -350,	 5545 },
+	{ -370,	 5741 },
+	{ -410,	 6147 },
+	{ -450,	 6671 },
+	{ -490,	 7413 },
+	{ -501,	 7665 },
+	{ -530,	 8767 },
+	{ -560,	10219 },
+	{ -580,	10939 },
+	{ -590,	11518 },
+	{ -600,	11723 },
+	{ -650,	12659 },
+	{ -690,	13219 },
+	{ -730,	13645 },
+	{ -750,	13909 },
+	{ -766,	14153 },
+	{ -950,	16383 }
+};
+
+/* DVB-S2 Es/N0 quant in dB/100 vs read value * 100*/
+static struct stb0899_tab stb0899_quant_tab[] = {
+	{    0,	    0 },
+	{    0,	  100 },
+	{  600,	  200 },
+	{  950,	  299 },
+	{ 1200,	  398 },
+	{ 1400,	  501 },
+	{ 1560,	  603 },
+	{ 1690,	  700 },
+	{ 1810,	  804 },
+	{ 1910,	  902 },
+	{ 2000,	 1000 },
+	{ 2080,	 1096 },
+	{ 2160,	 1202 },
+	{ 2230,	 1303 },
+	{ 2350,	 1496 },
+	{ 2410,	 1603 },
+	{ 2460,	 1698 },
+	{ 2510,	 1799 },
+	{ 2600,	 1995 },
+	{ 2650,	 2113 },
+	{ 2690,  2213 },
+	{ 2720,	 2291 },
+	{ 2760,	 2399 },
+	{ 2800,	 2512 },
+	{ 2860,	 2692 },
+	{ 2930,	 2917 },
+	{ 2960,	 3020 },
+	{ 3010,	 3199 },
+	{ 3040,	 3311 },
+	{ 3060,	 3388 },
+	{ 3120,	 3631 },
+	{ 3190,	 3936 },
+	{ 3400,	 5012 },
+	{ 3610,	 6383 },
+	{ 3800,	 7943 },
+	{ 4210,	12735 },
+	{ 4500,	17783 },
+	{ 4690,	22131 },
+	{ 4810,	25410 }
+};
+
+/* DVB-S2 Es/N0 estimate in dB/100 vs read value */
+static struct stb0899_tab stb0899_est_tab[] = {
+	{    0,	     0 },
+	{    0,	     1 },
+	{  301,	     2 },
+	{ 1204,	    16 },
+	{ 1806,	    64 },
+	{ 2408,	   256 },
+	{ 2709,	   512 },
+	{ 3010,	  1023 },
+	{ 3311,	  2046 },
+	{ 3612,	  4093 },
+	{ 3823,	  6653 },
+	{ 3913,	  8185 },
+	{ 4010,	 10233 },
+	{ 4107,	 12794 },
+	{ 4214,	 16368 },
+	{ 4266,	 18450 },
+	{ 4311,	 20464 },
+	{ 4353,	 22542 },
+	{ 4391,	 24604 },
+	{ 4425,	 26607 },
+	{ 4457,	 28642 },
+	{ 4487,	 30690 },
+	{ 4515,	 32734 },
+	{ 4612,	 40926 },
+	{ 4692,	 49204 },
+	{ 4816,	 65464 },
+	{ 4913,	 81846 },
+	{ 4993,	 98401 },
+	{ 5060,	114815 },
+	{ 5118,	131220 },
+	{ 5200,	158489 },
+	{ 5300,	199526 },
+	{ 5400,	251189 },
+	{ 5500,	316228 },
+	{ 5600,	398107 },
+	{ 5720,	524807 },
+	{ 5721,	526017 },
+};
+
+static int _stb0899_read_reg(struct stb0899_state *state, unsigned int reg)
+{
+	int ret;
+
+	u8 b0[] = { reg >> 8, reg & 0xff };
+	u8 buf;
+
+	struct i2c_msg msg[] = {
+		{
+			.addr	= state->config->demod_address,
+			.flags	= 0,
+			.buf	= b0,
+			.len	= 2
+		},{
+			.addr	= state->config->demod_address,
+			.flags	= I2C_M_RD,
+			.buf	= &buf,
+			.len	= 1
+		}
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+	if (ret != 2) {
+		if (ret != -ERESTARTSYS)
+			dprintk(state->verbose, FE_ERROR, 1,
+				"Read error, Reg=[0x%02x], Status=%d",
+				reg, ret);
+
+		return ret < 0 ? ret : -EREMOTEIO;
+	}
+	if (unlikely(*state->verbose >= FE_DEBUGREG))
+		dprintk(state->verbose, FE_ERROR, 1, "Reg=[0x%02x], data=%02x",
+			reg, buf);
+
+	return (unsigned int)buf;
+}
+
+int stb0899_read_reg(struct stb0899_state *state, unsigned int reg)
+{
+	int result;
+
+	result = _stb0899_read_reg(state, reg);
+	/*
+	 * Bug ID 9:
+	 * access to 0xf2xx/0xf6xx
+	 * must be followed by read from 0xf2ff/0xf6ff.
+	 */
+	if ((reg != 0xf2ff) && (reg != 0xf6ff) &&
+	    (((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600)))
+		_stb0899_read_reg(state, (reg | 0x00ff));
+
+	return result;
+}
+
+u32 _stb0899_read_s2reg(struct stb0899_state *state,
+			u32 stb0899_i2cdev,
+			u32 stb0899_base_addr,
+			u16 stb0899_reg_offset)
+{
+	int status;
+	u32 data;
+	u8 buf[7] = { 0 };
+	u16 tmpaddr;
+
+	u8 buf_0[] = {
+		GETBYTE(stb0899_i2cdev, BYTE1),		/* 0xf3	S2 Base Address (MSB)	*/
+		GETBYTE(stb0899_i2cdev, BYTE0),		/* 0xfc	S2 Base Address (LSB)	*/
+		GETBYTE(stb0899_base_addr, BYTE0),	/* 0x00	Base Address (LSB)	*/
+		GETBYTE(stb0899_base_addr, BYTE1),	/* 0x04	Base Address (LSB)	*/
+		GETBYTE(stb0899_base_addr, BYTE2),	/* 0x00	Base Address (MSB)	*/
+		GETBYTE(stb0899_base_addr, BYTE3),	/* 0x00	Base Address (MSB)	*/
+	};
+	u8 buf_1[] = {
+		0x00,	/* 0xf3	Reg Offset	*/
+		0x00,	/* 0x44	Reg Offset	*/
+	};
+
+	struct i2c_msg msg_0 = {
+		.addr	= state->config->demod_address,
+		.flags	= 0,
+		.buf	= buf_0,
+		.len	= 6
+	};
+
+	struct i2c_msg msg_1 = {
+		.addr	= state->config->demod_address,
+		.flags	= 0,
+		.buf	= buf_1,
+		.len	= 2
+	};
+
+	struct i2c_msg msg_r = {
+		.addr	= state->config->demod_address,
+		.flags	= I2C_M_RD,
+		.buf	= buf,
+		.len	= 4
+	};
+
+	tmpaddr = stb0899_reg_offset & 0xff00;
+	if (!(stb0899_reg_offset & 0x8))
+		tmpaddr = stb0899_reg_offset | 0x20;
+
+	buf_1[0] = GETBYTE(tmpaddr, BYTE1);
+	buf_1[1] = GETBYTE(tmpaddr, BYTE0);
+
+	status = i2c_transfer(state->i2c, &msg_0, 1);
+	if (status < 1) {
+		if (status != -ERESTARTSYS)
+			printk(KERN_ERR "%s ERR(1), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n",
+			       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status);
+
+		goto err;
+	}
+
+	/* Dummy	*/
+	status = i2c_transfer(state->i2c, &msg_1, 1);
+	if (status < 1)
+		goto err;
+
+	status = i2c_transfer(state->i2c, &msg_r, 1);
+	if (status < 1)
+		goto err;
+
+	buf_1[0] = GETBYTE(stb0899_reg_offset, BYTE1);
+	buf_1[1] = GETBYTE(stb0899_reg_offset, BYTE0);
+
+	/* Actual	*/
+	status = i2c_transfer(state->i2c, &msg_1, 1);
+	if (status < 1) {
+		if (status != -ERESTARTSYS)
+			printk(KERN_ERR "%s ERR(2), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n",
+			       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status);
+		goto err;
+	}
+
+	status = i2c_transfer(state->i2c, &msg_r, 1);
+	if (status < 1) {
+		if (status != -ERESTARTSYS)
+			printk(KERN_ERR "%s ERR(3), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n",
+			       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status);
+		return status < 0 ? status : -EREMOTEIO;
+	}
+
+	data = MAKEWORD32(buf[3], buf[2], buf[1], buf[0]);
+	if (unlikely(*state->verbose >= FE_DEBUGREG))
+		printk(KERN_DEBUG "%s Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Data=[0x%08x]\n",
+		       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, data);
+
+	return data;
+
+err:
+	return status < 0 ? status : -EREMOTEIO;
+}
+
+int stb0899_write_s2reg(struct stb0899_state *state,
+			u32 stb0899_i2cdev,
+			u32 stb0899_base_addr,
+			u16 stb0899_reg_offset,
+			u32 stb0899_data)
+{
+	int status;
+
+	/* Base Address Setup	*/
+	u8 buf_0[] = {
+		GETBYTE(stb0899_i2cdev, BYTE1),		/* 0xf3	S2 Base Address (MSB)	*/
+		GETBYTE(stb0899_i2cdev, BYTE0),		/* 0xfc	S2 Base Address (LSB)	*/
+		GETBYTE(stb0899_base_addr, BYTE0),	/* 0x00	Base Address (LSB)	*/
+		GETBYTE(stb0899_base_addr, BYTE1),	/* 0x04	Base Address (LSB)	*/
+		GETBYTE(stb0899_base_addr, BYTE2),	/* 0x00	Base Address (MSB)	*/
+		GETBYTE(stb0899_base_addr, BYTE3),	/* 0x00	Base Address (MSB)	*/
+	};
+	u8 buf_1[] = {
+		0x00,	/* 0xf3	Reg Offset	*/
+		0x00,	/* 0x44	Reg Offset	*/
+		0x00,	/* data			*/
+		0x00,	/* data			*/
+		0x00,	/* data			*/
+		0x00,	/* data			*/
+	};
+
+	struct i2c_msg msg_0 = {
+		.addr	= state->config->demod_address,
+		.flags	= 0,
+		.buf	= buf_0,
+		.len	= 6
+	};
+
+	struct i2c_msg msg_1 = {
+		.addr	= state->config->demod_address,
+		.flags	= 0,
+		.buf	= buf_1,
+		.len	= 6
+	};
+
+	buf_1[0] = GETBYTE(stb0899_reg_offset, BYTE1);
+	buf_1[1] = GETBYTE(stb0899_reg_offset, BYTE0);
+	buf_1[2] = GETBYTE(stb0899_data, BYTE0);
+	buf_1[3] = GETBYTE(stb0899_data, BYTE1);
+	buf_1[4] = GETBYTE(stb0899_data, BYTE2);
+	buf_1[5] = GETBYTE(stb0899_data, BYTE3);
+
+	if (unlikely(*state->verbose >= FE_DEBUGREG))
+		printk(KERN_DEBUG "%s Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x]\n",
+		       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data);
+
+	status = i2c_transfer(state->i2c, &msg_0, 1);
+	if (unlikely(status < 1)) {
+		if (status != -ERESTARTSYS)
+			printk(KERN_ERR "%s ERR (1), Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x], status=%d\n",
+			       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data, status);
+		goto err;
+	}
+	status = i2c_transfer(state->i2c, &msg_1, 1);
+	if (unlikely(status < 1)) {
+		if (status != -ERESTARTSYS)
+			printk(KERN_ERR "%s ERR (2), Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x], status=%d\n",
+			       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data, status);
+
+		return status < 0 ? status : -EREMOTEIO;
+	}
+
+	return 0;
+
+err:
+	return status < 0 ? status : -EREMOTEIO;
+}
+
+int stb0899_read_regs(struct stb0899_state *state, unsigned int reg, u8 *buf, u32 count)
+{
+	int status;
+
+	u8 b0[] = { reg >> 8, reg & 0xff };
+
+	struct i2c_msg msg[] = {
+		{
+			.addr	= state->config->demod_address,
+			.flags	= 0,
+			.buf	= b0,
+			.len	= 2
+		},{
+			.addr	= state->config->demod_address,
+			.flags	= I2C_M_RD,
+			.buf	= buf,
+			.len	= count
+		}
+	};
+
+	status = i2c_transfer(state->i2c, msg, 2);
+	if (status != 2) {
+		if (status != -ERESTARTSYS)
+			printk(KERN_ERR "%s Read error, Reg=[0x%04x], Count=%u, Status=%d\n",
+			       __func__, reg, count, status);
+		goto err;
+	}
+	/*
+	 * Bug ID 9:
+	 * access to 0xf2xx/0xf6xx
+	 * must be followed by read from 0xf2ff/0xf6ff.
+	 */
+	if ((reg != 0xf2ff) && (reg != 0xf6ff) &&
+	    (((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600)))
+		_stb0899_read_reg(state, (reg | 0x00ff));
+
+	if (unlikely(*state->verbose >= FE_DEBUGREG)) {
+		int i;
+
+		printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg);
+		for (i = 0; i < count; i++) {
+			printk(" %02x", buf[i]);
+		}
+		printk("\n");
+	}
+
+	return 0;
+err:
+	return status < 0 ? status : -EREMOTEIO;
+}
+
+int stb0899_write_regs(struct stb0899_state *state, unsigned int reg, u8 *data, u32 count)
+{
+	int ret;
+	u8 buf[2 + count];
+	struct i2c_msg i2c_msg = {
+		.addr	= state->config->demod_address,
+		.flags	= 0,
+		.buf	= buf,
+		.len	= 2 + count
+	};
+
+	buf[0] = reg >> 8;
+	buf[1] = reg & 0xff;
+	memcpy(&buf[2], data, count);
+
+	if (unlikely(*state->verbose >= FE_DEBUGREG)) {
+		int i;
+
+		printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg);
+		for (i = 0; i < count; i++)
+			printk(" %02x", data[i]);
+		printk("\n");
+	}
+	ret = i2c_transfer(state->i2c, &i2c_msg, 1);
+
+	/*
+	 * Bug ID 9:
+	 * access to 0xf2xx/0xf6xx
+	 * must be followed by read from 0xf2ff/0xf6ff.
+	 */
+	if ((((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600)))
+		stb0899_read_reg(state, (reg | 0x00ff));
+
+	if (ret != 1) {
+		if (ret != -ERESTARTSYS)
+			dprintk(state->verbose, FE_ERROR, 1, "Reg=[0x%04x], Data=[0x%02x ...], Count=%u, Status=%d",
+				reg, data[0], count, ret);
+		return ret < 0 ? ret : -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+int stb0899_write_reg(struct stb0899_state *state, unsigned int reg, u8 data)
+{
+	return stb0899_write_regs(state, reg, &data, 1);
+}
+
+/*
+ * stb0899_get_mclk
+ * Get STB0899 master clock frequency
+ * ExtClk: external clock frequency (Hz)
+ */
+static u32 stb0899_get_mclk(struct stb0899_state *state)
+{
+	u32 mclk = 0, div = 0;
+
+	div = stb0899_read_reg(state, STB0899_NCOARSE);
+	mclk = (div + 1) * state->config->xtal_freq / 6;
+	dprintk(state->verbose, FE_DEBUG, 1, "div=%d, mclk=%d", div, mclk);
+
+	return mclk;
+}
+
+/*
+ * stb0899_set_mclk
+ * Set STB0899 master Clock frequency
+ * Mclk: demodulator master clock
+ * ExtClk: external clock frequency (Hz)
+ */
+static void stb0899_set_mclk(struct stb0899_state *state, u32 Mclk)
+{
+	struct stb0899_internal *internal = &state->internal;
+	u8 mdiv = 0;
+
+	dprintk(state->verbose, FE_DEBUG, 1, "state->config=%p", state->config);
+	mdiv = ((6 * Mclk) / state->config->xtal_freq) - 1;
+	dprintk(state->verbose, FE_DEBUG, 1, "mdiv=%d", mdiv);
+
+	stb0899_write_reg(state, STB0899_NCOARSE, mdiv);
+	internal->master_clk = stb0899_get_mclk(state);
+
+	dprintk(state->verbose, FE_DEBUG, 1, "MasterCLOCK=%d", internal->master_clk);
+}
+
+static int stb0899_postproc(struct stb0899_state *state, u8 ctl, int enable)
+{
+	struct stb0899_config *config		= state->config;
+	const struct stb0899_postproc *postproc	= config->postproc;
+
+	/* post process event */
+	if (postproc) {
+		if (enable) {
+			if (postproc[ctl].level == STB0899_GPIOPULLUP)
+				stb0899_write_reg(state, postproc[ctl].gpio, 0x02);
+			else
+				stb0899_write_reg(state, postproc[ctl].gpio, 0x82);
+		} else {
+			if (postproc[ctl].level == STB0899_GPIOPULLUP)
+				stb0899_write_reg(state, postproc[ctl].gpio, 0x82);
+			else
+				stb0899_write_reg(state, postproc[ctl].gpio, 0x02);
+		}
+	}
+	return 0;
+}
+
+static void stb0899_release(struct dvb_frontend *fe)
+{
+	struct stb0899_state *state = fe->demodulator_priv;
+
+	dprintk(state->verbose, FE_DEBUG, 1, "Release Frontend");
+	/* post process event */
+	stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 0);
+	kfree(state);
+}
+
+/*
+ * stb0899_get_alpha
+ * return: rolloff
+ */
+static int stb0899_get_alpha(struct stb0899_state *state)
+{
+	u8 mode_coeff;
+
+	mode_coeff = stb0899_read_reg(state, STB0899_DEMOD);
+
+	if (STB0899_GETFIELD(MODECOEFF, mode_coeff) == 1)
+		return 20;
+	else
+		return 35;
+}
+
+/*
+ * stb0899_init_calc
+ */
+static void stb0899_init_calc(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal = &state->internal;
+	int master_clk;
+	u8 agc[2];
+	u32 reg;
+
+	/* Read registers (in burst mode)	*/
+	stb0899_read_regs(state, STB0899_AGC1REF, agc, 2); /* AGC1R and AGC2O	*/
+
+	/* Initial calculations	*/
+	master_clk			= stb0899_get_mclk(state);
+	internal->t_agc1		= 0;
+	internal->t_agc2		= 0;
+	internal->master_clk		= master_clk;
+	internal->mclk			= master_clk / 65536L;
+	internal->rolloff		= stb0899_get_alpha(state);
+
+	/* DVBS2 Initial calculations	*/
+	/* Set AGC value to the middle	*/
+	internal->agc_gain		= 8154;
+	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL);
+	STB0899_SETFIELD_VAL(IF_GAIN_INIT, reg, internal->agc_gain);
+	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg);
+
+	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, RRC_ALPHA);
+	internal->rrc_alpha		= STB0899_GETFIELD(RRC_ALPHA, reg);
+
+	internal->center_freq		= 0;
+	internal->av_frame_coarse	= 10;
+	internal->av_frame_fine		= 20;
+	internal->step_size		= 2;
+/*
+	if ((pParams->SpectralInv == FE_IQ_NORMAL) || (pParams->SpectralInv == FE_IQ_AUTO))
+		pParams->IQLocked = 0;
+	else
+		pParams->IQLocked = 1;
+*/
+}
+
+static int stb0899_wait_diseqc_fifo_empty(struct stb0899_state *state, int timeout)
+{
+	u8 reg = 0;
+	unsigned long start = jiffies;
+
+	while (1) {
+		reg = stb0899_read_reg(state, STB0899_DISSTATUS);
+		if (!STB0899_GETFIELD(FIFOFULL, reg))
+			break;
+		if ((jiffies - start) > timeout) {
+			dprintk(state->verbose, FE_ERROR, 1, "timed out !!");
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+static int stb0899_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd)
+{
+	struct stb0899_state *state = fe->demodulator_priv;
+	u8 reg, i;
+
+	if (cmd->msg_len > 8)
+		return -EINVAL;
+
+	/* enable FIFO precharge	*/
+	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
+	STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 1);
+	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
+	for (i = 0; i < cmd->msg_len; i++) {
+		/* wait for FIFO empty	*/
+		if (stb0899_wait_diseqc_fifo_empty(state, 100) < 0)
+			return -ETIMEDOUT;
+
+		stb0899_write_reg(state, STB0899_DISFIFO, cmd->msg[i]);
+	}
+	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
+	STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0);
+	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
+	msleep(100);
+	return 0;
+}
+
+static int stb0899_wait_diseqc_rxidle(struct stb0899_state *state, int timeout)
+{
+	u8 reg = 0;
+	unsigned long start = jiffies;
+
+	while (!STB0899_GETFIELD(RXEND, reg)) {
+		reg = stb0899_read_reg(state, STB0899_DISRX_ST0);
+		if (jiffies - start > timeout) {
+			dprintk(state->verbose, FE_ERROR, 1, "timed out!!");
+			return -ETIMEDOUT;
+		}
+		msleep(10);
+	}
+
+	return 0;
+}
+
+static int stb0899_recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_slave_reply *reply)
+{
+	struct stb0899_state *state = fe->demodulator_priv;
+	u8 reg, length = 0, i;
+	int result;
+
+	if (stb0899_wait_diseqc_rxidle(state, 100) < 0)
+		return -ETIMEDOUT;
+
+	reg = stb0899_read_reg(state, STB0899_DISRX_ST0);
+	if (STB0899_GETFIELD(RXEND, reg)) {
+
+		reg = stb0899_read_reg(state, STB0899_DISRX_ST1);
+		length = STB0899_GETFIELD(FIFOBYTENBR, reg);
+
+		if (length > sizeof (reply->msg)) {
+			result = -EOVERFLOW;
+			goto exit;
+		}
+		reply->msg_len = length;
+
+		/* extract data */
+		for (i = 0; i < length; i++)
+			reply->msg[i] = stb0899_read_reg(state, STB0899_DISFIFO);
+	}
+
+	return 0;
+exit:
+
+	return result;
+}
+
+static int stb0899_wait_diseqc_txidle(struct stb0899_state *state, int timeout)
+{
+	u8 reg = 0;
+	unsigned long start = jiffies;
+
+	while (!STB0899_GETFIELD(TXIDLE, reg)) {
+		reg = stb0899_read_reg(state, STB0899_DISSTATUS);
+		if (jiffies - start > timeout) {
+			dprintk(state->verbose, FE_ERROR, 1, "timed out!!");
+			return -ETIMEDOUT;
+		}
+		msleep(10);
+	}
+	return 0;
+}
+
+static int stb0899_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
+{
+	struct stb0899_state *state = fe->demodulator_priv;
+	u8 reg, old_state;
+
+	/* wait for diseqc idle	*/
+	if (stb0899_wait_diseqc_txidle(state, 100) < 0)
+		return -ETIMEDOUT;
+
+	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
+	old_state = reg;
+	/* set to burst mode	*/
+	STB0899_SETFIELD_VAL(DISEQCMODE, reg, 0x03);
+	STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0x01);
+	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
+	switch (burst) {
+	case SEC_MINI_A:
+		/* unmodulated	*/
+		stb0899_write_reg(state, STB0899_DISFIFO, 0x00);
+		break;
+	case SEC_MINI_B:
+		/* modulated	*/
+		stb0899_write_reg(state, STB0899_DISFIFO, 0xff);
+		break;
+	}
+	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
+	STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0x00);
+	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
+	/* wait for diseqc idle	*/
+	if (stb0899_wait_diseqc_txidle(state, 100) < 0)
+		return -ETIMEDOUT;
+
+	/* restore state	*/
+	stb0899_write_reg(state, STB0899_DISCNTRL1, old_state);
+
+	return 0;
+}
+
+static int stb0899_diseqc_init(struct stb0899_state *state)
+{
+/*
+	struct dvb_diseqc_slave_reply rx_data;
+*/
+	u8 f22_tx, reg;
+
+	u32 mclk, tx_freq = 22000;/* count = 0, i; */
+	reg = stb0899_read_reg(state, STB0899_DISCNTRL2);
+	STB0899_SETFIELD_VAL(ONECHIP_TRX, reg, 0);
+	stb0899_write_reg(state, STB0899_DISCNTRL2, reg);
+
+	/* disable Tx spy	*/
+	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
+	STB0899_SETFIELD_VAL(DISEQCRESET, reg, 1);
+	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
+
+	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
+	STB0899_SETFIELD_VAL(DISEQCRESET, reg, 0);
+	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
+
+	mclk = stb0899_get_mclk(state);
+	f22_tx = mclk / (tx_freq * 32);
+	stb0899_write_reg(state, STB0899_DISF22, f22_tx); /* DiSEqC Tx freq	*/
+	state->rx_freq = 20000;
+
+	return 0;
+}
+
+static int stb0899_sleep(struct dvb_frontend *fe)
+{
+	struct stb0899_state *state = fe->demodulator_priv;
+/*
+	u8 reg;
+*/
+	dprintk(state->verbose, FE_DEBUG, 1, "Going to Sleep .. (Really tired .. :-))");
+	/* post process event */
+	stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 0);
+
+	return 0;
+}
+
+static int stb0899_wakeup(struct dvb_frontend *fe)
+{
+	int rc;
+	struct stb0899_state *state = fe->demodulator_priv;
+
+	if ((rc = stb0899_write_reg(state, STB0899_SYNTCTRL, STB0899_SELOSCI)))
+		return rc;
+	/* Activate all clocks; DVB-S2 registers are inaccessible otherwise. */
+	if ((rc = stb0899_write_reg(state, STB0899_STOPCLK1, 0x00)))
+		return rc;
+	if ((rc = stb0899_write_reg(state, STB0899_STOPCLK2, 0x00)))
+		return rc;
+
+	/* post process event */
+	stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 1);
+
+	return 0;
+}
+
+static int stb0899_init(struct dvb_frontend *fe)
+{
+	int i;
+	struct stb0899_state *state = fe->demodulator_priv;
+	struct stb0899_config *config = state->config;
+
+	dprintk(state->verbose, FE_DEBUG, 1, "Initializing STB0899 ... ");
+
+	/* init device		*/
+	dprintk(state->verbose, FE_DEBUG, 1, "init device");
+	for (i = 0; config->init_dev[i].address != 0xffff; i++)
+		stb0899_write_reg(state, config->init_dev[i].address, config->init_dev[i].data);
+
+	dprintk(state->verbose, FE_DEBUG, 1, "init S2 demod");
+	/* init S2 demod	*/
+	for (i = 0; config->init_s2_demod[i].offset != 0xffff; i++)
+		stb0899_write_s2reg(state, STB0899_S2DEMOD,
+				    config->init_s2_demod[i].base_address,
+				    config->init_s2_demod[i].offset,
+				    config->init_s2_demod[i].data);
+
+	dprintk(state->verbose, FE_DEBUG, 1, "init S1 demod");
+	/* init S1 demod	*/
+	for (i = 0; config->init_s1_demod[i].address != 0xffff; i++)
+		stb0899_write_reg(state, config->init_s1_demod[i].address, config->init_s1_demod[i].data);
+
+	dprintk(state->verbose, FE_DEBUG, 1, "init S2 FEC");
+	/* init S2 fec		*/
+	for (i = 0; config->init_s2_fec[i].offset != 0xffff; i++)
+		stb0899_write_s2reg(state, STB0899_S2FEC,
+				    config->init_s2_fec[i].base_address,
+				    config->init_s2_fec[i].offset,
+				    config->init_s2_fec[i].data);
+
+	dprintk(state->verbose, FE_DEBUG, 1, "init TST");
+	/* init test		*/
+	for (i = 0; config->init_tst[i].address != 0xffff; i++)
+		stb0899_write_reg(state, config->init_tst[i].address, config->init_tst[i].data);
+
+	stb0899_init_calc(state);
+	stb0899_diseqc_init(state);
+
+	return 0;
+}
+
+static int stb0899_table_lookup(const struct stb0899_tab *tab, int max, int val)
+{
+	int res = 0;
+	int min = 0, med;
+
+	if (val < tab[min].read)
+		res = tab[min].real;
+	else if (val >= tab[max].read)
+		res = tab[max].real;
+	else {
+		while ((max - min) > 1) {
+			med = (max + min) / 2;
+			if (val >= tab[min].read && val < tab[med].read)
+				max = med;
+			else
+				min = med;
+		}
+		res = ((val - tab[min].read) *
+		       (tab[max].real - tab[min].real) /
+		       (tab[max].read - tab[min].read)) +
+			tab[min].real;
+	}
+
+	return res;
+}
+
+static int stb0899_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct stb0899_state *state		= fe->demodulator_priv;
+	struct stb0899_internal *internal	= &state->internal;
+
+	int val;
+	u32 reg;
+	*strength = 0;
+	switch (state->delsys) {
+	case SYS_DVBS:
+	case SYS_DSS:
+		if (internal->lock) {
+			reg  = stb0899_read_reg(state, STB0899_VSTATUS);
+			if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) {
+
+				reg = stb0899_read_reg(state, STB0899_AGCIQIN);
+				val = (s32)(s8)STB0899_GETFIELD(AGCIQVALUE, reg);
+
+				*strength = stb0899_table_lookup(stb0899_dvbsrf_tab, ARRAY_SIZE(stb0899_dvbsrf_tab) - 1, val);
+				*strength += 750;
+				dprintk(state->verbose, FE_DEBUG, 1, "AGCIQVALUE = 0x%02x, C = %d * 0.1 dBm",
+					val & 0xff, *strength);
+			}
+		}
+		break;
+	case SYS_DVBS2:
+		if (internal->lock) {
+			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_GAIN);
+			val = STB0899_GETFIELD(IF_AGC_GAIN, reg);
+
+			*strength = stb0899_table_lookup(stb0899_dvbs2rf_tab, ARRAY_SIZE(stb0899_dvbs2rf_tab) - 1, val);
+			*strength += 950;
+			dprintk(state->verbose, FE_DEBUG, 1, "IF_AGC_GAIN = 0x%04x, C = %d * 0.1 dBm",
+				val & 0x3fff, *strength);
+		}
+		break;
+	default:
+		dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int stb0899_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct stb0899_state *state		= fe->demodulator_priv;
+	struct stb0899_internal *internal	= &state->internal;
+
+	unsigned int val, quant, quantn = -1, est, estn = -1;
+	u8 buf[2];
+	u32 reg;
+
+	*snr = 0;
+	reg  = stb0899_read_reg(state, STB0899_VSTATUS);
+	switch (state->delsys) {
+	case SYS_DVBS:
+	case SYS_DSS:
+		if (internal->lock) {
+			if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) {
+
+				stb0899_read_regs(state, STB0899_NIRM, buf, 2);
+				val = MAKEWORD16(buf[0], buf[1]);
+
+				*snr = stb0899_table_lookup(stb0899_cn_tab, ARRAY_SIZE(stb0899_cn_tab) - 1, val);
+				dprintk(state->verbose, FE_DEBUG, 1, "NIR = 0x%02x%02x = %u, C/N = %d * 0.1 dBm\n",
+					buf[0], buf[1], val, *snr);
+			}
+		}
+		break;
+	case SYS_DVBS2:
+		if (internal->lock) {
+			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL1);
+			quant = STB0899_GETFIELD(UWP_ESN0_QUANT, reg);
+			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2);
+			est = STB0899_GETFIELD(ESN0_EST, reg);
+			if (est == 1)
+				val = 301; /* C/N = 30.1 dB */
+			else if (est == 2)
+				val = 270; /* C/N = 27.0 dB */
+			else {
+				/* quantn = 100 * log(quant^2) */
+				quantn = stb0899_table_lookup(stb0899_quant_tab, ARRAY_SIZE(stb0899_quant_tab) - 1, quant * 100);
+				/* estn = 100 * log(est) */
+				estn = stb0899_table_lookup(stb0899_est_tab, ARRAY_SIZE(stb0899_est_tab) - 1, est);
+				/* snr(dBm/10) = -10*(log(est)-log(quant^2)) => snr(dBm/10) = (100*log(quant^2)-100*log(est))/10 */
+				val = (quantn - estn) / 10;
+			}
+			*snr = val;
+			dprintk(state->verbose, FE_DEBUG, 1, "Es/N0 quant = %d (%d) estimate = %u (%d), C/N = %d * 0.1 dBm",
+				quant, quantn, est, estn, val);
+		}
+		break;
+	default:
+		dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int stb0899_read_status(struct dvb_frontend *fe, enum fe_status *status)
+{
+	struct stb0899_state *state		= fe->demodulator_priv;
+	struct stb0899_internal *internal	= &state->internal;
+	u8 reg;
+	*status = 0;
+
+	switch (state->delsys) {
+	case SYS_DVBS:
+	case SYS_DSS:
+		dprintk(state->verbose, FE_DEBUG, 1, "Delivery system DVB-S/DSS");
+		if (internal->lock) {
+			reg  = stb0899_read_reg(state, STB0899_VSTATUS);
+			if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) {
+				dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_CARRIER | FE_HAS_LOCK");
+				*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
+
+				reg = stb0899_read_reg(state, STB0899_PLPARM);
+				if (STB0899_GETFIELD(VITCURPUN, reg)) {
+					dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_VITERBI | FE_HAS_SYNC");
+					*status |= FE_HAS_VITERBI | FE_HAS_SYNC;
+					/* post process event */
+					stb0899_postproc(state, STB0899_POSTPROC_GPIO_LOCK, 1);
+				}
+			}
+		}
+		break;
+	case SYS_DVBS2:
+		dprintk(state->verbose, FE_DEBUG, 1, "Delivery system DVB-S2");
+		if (internal->lock) {
+			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STAT2);
+			if (STB0899_GETFIELD(UWP_LOCK, reg) && STB0899_GETFIELD(CSM_LOCK, reg)) {
+				*status |= FE_HAS_CARRIER;
+				dprintk(state->verbose, FE_DEBUG, 1,
+					"UWP & CSM Lock ! ---> DVB-S2 FE_HAS_CARRIER");
+
+				reg = stb0899_read_reg(state, STB0899_CFGPDELSTATUS1);
+				if (STB0899_GETFIELD(CFGPDELSTATUS_LOCK, reg)) {
+					*status |= FE_HAS_LOCK;
+					dprintk(state->verbose, FE_DEBUG, 1,
+						"Packet Delineator Locked ! -----> DVB-S2 FE_HAS_LOCK");
+
+				}
+				if (STB0899_GETFIELD(CONTINUOUS_STREAM, reg)) {
+					*status |= FE_HAS_VITERBI;
+					dprintk(state->verbose, FE_DEBUG, 1,
+						"Packet Delineator found VITERBI ! -----> DVB-S2 FE_HAS_VITERBI");
+				}
+				if (STB0899_GETFIELD(ACCEPTED_STREAM, reg)) {
+					*status |= FE_HAS_SYNC;
+					dprintk(state->verbose, FE_DEBUG, 1,
+						"Packet Delineator found SYNC ! -----> DVB-S2 FE_HAS_SYNC");
+					/* post process event */
+					stb0899_postproc(state, STB0899_POSTPROC_GPIO_LOCK, 1);
+				}
+			}
+		}
+		break;
+	default:
+		dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * stb0899_get_error
+ * viterbi error for DVB-S/DSS
+ * packet error for DVB-S2
+ * Bit Error Rate or Packet Error Rate * 10 ^ 7
+ */
+static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct stb0899_state *state		= fe->demodulator_priv;
+	struct stb0899_internal *internal	= &state->internal;
+
+	u8  lsb, msb;
+
+	*ber = 0;
+
+	switch (state->delsys) {
+	case SYS_DVBS:
+	case SYS_DSS:
+		if (internal->lock) {
+			lsb = stb0899_read_reg(state, STB0899_ECNT1L);
+			msb = stb0899_read_reg(state, STB0899_ECNT1M);
+			*ber = MAKEWORD16(msb, lsb);
+			/* Viterbi Check	*/
+			if (STB0899_GETFIELD(VSTATUS_PRFVIT, internal->v_status)) {
+				/* Error Rate		*/
+				*ber *= 9766;
+				/* ber = ber * 10 ^ 7	*/
+				*ber /= (-1 + (1 << (2 * STB0899_GETFIELD(NOE, internal->err_ctrl))));
+				*ber /= 8;
+			}
+		}
+		break;
+	case SYS_DVBS2:
+		if (internal->lock) {
+			lsb = stb0899_read_reg(state, STB0899_ECNT1L);
+			msb = stb0899_read_reg(state, STB0899_ECNT1M);
+			*ber = MAKEWORD16(msb, lsb);
+			/* ber = ber * 10 ^ 7	*/
+			*ber *= 10000000;
+			*ber /= (-1 + (1 << (4 + 2 * STB0899_GETFIELD(NOE, internal->err_ctrl))));
+		}
+		break;
+	default:
+		dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int stb0899_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct stb0899_state *state = fe->demodulator_priv;
+
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		stb0899_write_reg(state, STB0899_GPIO00CFG, 0x82);
+		stb0899_write_reg(state, STB0899_GPIO01CFG, 0x02);
+		stb0899_write_reg(state, STB0899_GPIO02CFG, 0x00);
+		break;
+	case SEC_VOLTAGE_18:
+		stb0899_write_reg(state, STB0899_GPIO00CFG, 0x02);
+		stb0899_write_reg(state, STB0899_GPIO01CFG, 0x02);
+		stb0899_write_reg(state, STB0899_GPIO02CFG, 0x82);
+		break;
+	case SEC_VOLTAGE_OFF:
+		stb0899_write_reg(state, STB0899_GPIO00CFG, 0x82);
+		stb0899_write_reg(state, STB0899_GPIO01CFG, 0x82);
+		stb0899_write_reg(state, STB0899_GPIO02CFG, 0x82);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int stb0899_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct stb0899_state *state = fe->demodulator_priv;
+	struct stb0899_internal *internal = &state->internal;
+
+	u8 div, reg;
+
+	/* wait for diseqc idle	*/
+	if (stb0899_wait_diseqc_txidle(state, 100) < 0)
+		return -ETIMEDOUT;
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		div = (internal->master_clk / 100) / 5632;
+		div = (div + 5) / 10;
+		stb0899_write_reg(state, STB0899_DISEQCOCFG, 0x66);
+		reg = stb0899_read_reg(state, STB0899_ACRPRESC);
+		STB0899_SETFIELD_VAL(ACRPRESC, reg, 0x03);
+		stb0899_write_reg(state, STB0899_ACRPRESC, reg);
+		stb0899_write_reg(state, STB0899_ACRDIV1, div);
+		break;
+	case SEC_TONE_OFF:
+		stb0899_write_reg(state, STB0899_DISEQCOCFG, 0x20);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	int i2c_stat;
+	struct stb0899_state *state = fe->demodulator_priv;
+
+	i2c_stat = stb0899_read_reg(state, STB0899_I2CRPT);
+	if (i2c_stat < 0)
+		goto err;
+
+	if (enable) {
+		dprintk(state->verbose, FE_DEBUG, 1, "Enabling I2C Repeater ...");
+		i2c_stat |=  STB0899_I2CTON;
+		if (stb0899_write_reg(state, STB0899_I2CRPT, i2c_stat) < 0)
+			goto err;
+	} else {
+		dprintk(state->verbose, FE_DEBUG, 1, "Disabling I2C Repeater ...");
+		i2c_stat &= ~STB0899_I2CTON;
+		if (stb0899_write_reg(state, STB0899_I2CRPT, i2c_stat) < 0)
+			goto err;
+	}
+	return 0;
+err:
+	dprintk(state->verbose, FE_ERROR, 1, "I2C Repeater control failed");
+	return -EREMOTEIO;
+}
+
+
+static inline void CONVERT32(u32 x, char *str)
+{
+	*str++	= (x >> 24) & 0xff;
+	*str++	= (x >> 16) & 0xff;
+	*str++	= (x >>  8) & 0xff;
+	*str++	= (x >>  0) & 0xff;
+	*str	= '\0';
+}
+
+int stb0899_get_dev_id(struct stb0899_state *state)
+{
+	u8 chip_id, release;
+	u16 id;
+	u32 demod_ver = 0, fec_ver = 0;
+	char demod_str[5] = { 0 };
+	char fec_str[5] = { 0 };
+
+	id = stb0899_read_reg(state, STB0899_DEV_ID);
+	dprintk(state->verbose, FE_DEBUG, 1, "ID reg=[0x%02x]", id);
+	chip_id = STB0899_GETFIELD(CHIP_ID, id);
+	release = STB0899_GETFIELD(CHIP_REL, id);
+
+	dprintk(state->verbose, FE_ERROR, 1, "Device ID=[%d], Release=[%d]",
+		chip_id, release);
+
+	CONVERT32(STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CORE_ID), (char *)&demod_str);
+
+	demod_ver = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_VERSION_ID);
+	dprintk(state->verbose, FE_ERROR, 1, "Demodulator Core ID=[%s], Version=[%d]", (char *) &demod_str, demod_ver);
+	CONVERT32(STB0899_READ_S2REG(STB0899_S2FEC, FEC_CORE_ID_REG), (char *)&fec_str);
+	fec_ver = STB0899_READ_S2REG(STB0899_S2FEC, FEC_VER_ID_REG);
+	if (! (chip_id > 0)) {
+		dprintk(state->verbose, FE_ERROR, 1, "couldn't find a STB 0899");
+
+		return -ENODEV;
+	}
+	dprintk(state->verbose, FE_ERROR, 1, "FEC Core ID=[%s], Version=[%d]", (char*) &fec_str, fec_ver);
+
+	return 0;
+}
+
+static void stb0899_set_delivery(struct stb0899_state *state)
+{
+	u8 reg;
+	u8 stop_clk[2];
+
+	stop_clk[0] = stb0899_read_reg(state, STB0899_STOPCLK1);
+	stop_clk[1] = stb0899_read_reg(state, STB0899_STOPCLK2);
+
+	switch (state->delsys) {
+	case SYS_DVBS:
+		dprintk(state->verbose, FE_DEBUG, 1, "Delivery System -- DVB-S");
+		/* FECM/Viterbi ON	*/
+		reg = stb0899_read_reg(state, STB0899_FECM);
+		STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 0);
+		STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 1);
+		stb0899_write_reg(state, STB0899_FECM, reg);
+
+		stb0899_write_reg(state, STB0899_RSULC, 0xb1);
+		stb0899_write_reg(state, STB0899_TSULC, 0x40);
+		stb0899_write_reg(state, STB0899_RSLLC, 0x42);
+		stb0899_write_reg(state, STB0899_TSLPL, 0x12);
+
+		reg = stb0899_read_reg(state, STB0899_TSTRES);
+		STB0899_SETFIELD_VAL(FRESLDPC, reg, 1);
+		stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+		STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1);
+		STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 1);
+		STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 1);
+
+		STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 1);
+		STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 1);
+
+		STB0899_SETFIELD_VAL(STOP_CKINTBUF216, stop_clk[0], 1);
+		STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0);
+
+		STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 1);
+		break;
+	case SYS_DVBS2:
+		/* FECM/Viterbi OFF	*/
+		reg = stb0899_read_reg(state, STB0899_FECM);
+		STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 0);
+		STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 0);
+		stb0899_write_reg(state, STB0899_FECM, reg);
+
+		stb0899_write_reg(state, STB0899_RSULC, 0xb1);
+		stb0899_write_reg(state, STB0899_TSULC, 0x42);
+		stb0899_write_reg(state, STB0899_RSLLC, 0x40);
+		stb0899_write_reg(state, STB0899_TSLPL, 0x02);
+
+		reg = stb0899_read_reg(state, STB0899_TSTRES);
+		STB0899_SETFIELD_VAL(FRESLDPC, reg, 0);
+		stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+		STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1);
+		STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 0);
+		STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 0);
+
+		STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 0);
+		STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 0);
+
+		STB0899_SETFIELD_VAL(STOP_CKINTBUF216, stop_clk[0], 0);
+		STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0);
+
+		STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 0);
+		break;
+	case SYS_DSS:
+		/* FECM/Viterbi ON	*/
+		reg = stb0899_read_reg(state, STB0899_FECM);
+		STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 1);
+		STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 1);
+		stb0899_write_reg(state, STB0899_FECM, reg);
+
+		stb0899_write_reg(state, STB0899_RSULC, 0xa1);
+		stb0899_write_reg(state, STB0899_TSULC, 0x61);
+		stb0899_write_reg(state, STB0899_RSLLC, 0x42);
+
+		reg = stb0899_read_reg(state, STB0899_TSTRES);
+		STB0899_SETFIELD_VAL(FRESLDPC, reg, 1);
+		stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+		STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1);
+		STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 1);
+		STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 1);
+
+		STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 1);
+		STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 1);
+
+		STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0);
+
+		STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 1);
+		break;
+	default:
+		dprintk(state->verbose, FE_ERROR, 1, "Unsupported delivery system");
+		break;
+	}
+	STB0899_SETFIELD_VAL(STOP_CKADCI108, stop_clk[0], 0);
+	stb0899_write_regs(state, STB0899_STOPCLK1, stop_clk, 2);
+}
+
+/*
+ * stb0899_set_iterations
+ * set the LDPC iteration scale function
+ */
+static void stb0899_set_iterations(struct stb0899_state *state)
+{
+	struct stb0899_internal *internal = &state->internal;
+	struct stb0899_config *config = state->config;
+
+	s32 iter_scale;
+	u32 reg;
+
+	iter_scale = 17 * (internal->master_clk / 1000);
+	iter_scale += 410000;
+	iter_scale /= (internal->srate / 1000000);
+	iter_scale /= 1000;
+
+	if (iter_scale > config->ldpc_max_iter)
+		iter_scale = config->ldpc_max_iter;
+
+	reg = STB0899_READ_S2REG(STB0899_S2FEC, MAX_ITER);
+	STB0899_SETFIELD_VAL(MAX_ITERATIONS, reg, iter_scale);
+	stb0899_write_s2reg(state, STB0899_S2FEC, STB0899_BASE_MAX_ITER, STB0899_OFF0_MAX_ITER, reg);
+}
+
+static enum dvbfe_search stb0899_search(struct dvb_frontend *fe)
+{
+	struct stb0899_state *state = fe->demodulator_priv;
+	struct stb0899_params *i_params = &state->params;
+	struct stb0899_internal *internal = &state->internal;
+	struct stb0899_config *config = state->config;
+	struct dtv_frontend_properties *props = &fe->dtv_property_cache;
+
+	u32 SearchRange, gain;
+
+	i_params->freq	= props->frequency;
+	i_params->srate = props->symbol_rate;
+	state->delsys = props->delivery_system;
+	dprintk(state->verbose, FE_DEBUG, 1, "delivery system=%d", state->delsys);
+
+	SearchRange = 10000000;
+	dprintk(state->verbose, FE_DEBUG, 1, "Frequency=%d, Srate=%d", i_params->freq, i_params->srate);
+	/* checking Search Range is meaningless for a fixed 3 Mhz			*/
+	if (INRANGE(i_params->srate, 1000000, 45000000)) {
+		dprintk(state->verbose, FE_DEBUG, 1, "Parameters IN RANGE");
+		stb0899_set_delivery(state);
+
+		if (state->config->tuner_set_rfsiggain) {
+			if (internal->srate > 15000000)
+				gain =  8; /* 15Mb < srate < 45Mb, gain = 8dB	*/
+			else if (internal->srate > 5000000)
+				gain = 12; /*  5Mb < srate < 15Mb, gain = 12dB	*/
+			else
+				gain = 14; /*  1Mb < srate <  5Mb, gain = 14db	*/
+			state->config->tuner_set_rfsiggain(fe, gain);
+		}
+
+		if (i_params->srate <= 5000000)
+			stb0899_set_mclk(state, config->lo_clk);
+		else
+			stb0899_set_mclk(state, config->hi_clk);
+
+		switch (state->delsys) {
+		case SYS_DVBS:
+		case SYS_DSS:
+			dprintk(state->verbose, FE_DEBUG, 1, "DVB-S delivery system");
+			internal->freq	= i_params->freq;
+			internal->srate	= i_params->srate;
+			/*
+			 * search = user search range +
+			 *	    500Khz +
+			 *	    2 * Tuner_step_size +
+			 *	    10% of the symbol rate
+			 */
+			internal->srch_range	= SearchRange + 1500000 + (i_params->srate / 5);
+			internal->derot_percent	= 30;
+
+			/* What to do for tuners having no bandwidth setup ?	*/
+			/* enable tuner I/O */
+			stb0899_i2c_gate_ctrl(&state->frontend, 1);
+
+			if (state->config->tuner_set_bandwidth)
+				state->config->tuner_set_bandwidth(fe, (13 * (stb0899_carr_width(state) + SearchRange)) / 10);
+			if (state->config->tuner_get_bandwidth)
+				state->config->tuner_get_bandwidth(fe, &internal->tuner_bw);
+
+			/* disable tuner I/O */
+			stb0899_i2c_gate_ctrl(&state->frontend, 0);
+
+			/* Set DVB-S1 AGC		*/
+			stb0899_write_reg(state, STB0899_AGCRFCFG, 0x11);
+
+			/* Run the search algorithm	*/
+			dprintk(state->verbose, FE_DEBUG, 1, "running DVB-S search algo ..");
+			if (stb0899_dvbs_algo(state)	== RANGEOK) {
+				internal->lock		= 1;
+				dprintk(state->verbose, FE_DEBUG, 1,
+					"-------------------------------------> DVB-S LOCK !");
+
+//				stb0899_write_reg(state, STB0899_ERRCTRL1, 0x3d); /* Viterbi Errors	*/
+//				internal->v_status = stb0899_read_reg(state, STB0899_VSTATUS);
+//				internal->err_ctrl = stb0899_read_reg(state, STB0899_ERRCTRL1);
+//				dprintk(state->verbose, FE_DEBUG, 1, "VSTATUS=0x%02x", internal->v_status);
+//				dprintk(state->verbose, FE_DEBUG, 1, "ERR_CTRL=0x%02x", internal->err_ctrl);
+
+				return DVBFE_ALGO_SEARCH_SUCCESS;
+			} else {
+				internal->lock		= 0;
+
+				return DVBFE_ALGO_SEARCH_FAILED;
+			}
+			break;
+		case SYS_DVBS2:
+			internal->freq			= i_params->freq;
+			internal->srate			= i_params->srate;
+			internal->srch_range		= SearchRange;
+
+			/* enable tuner I/O */
+			stb0899_i2c_gate_ctrl(&state->frontend, 1);
+
+			if (state->config->tuner_set_bandwidth)
+				state->config->tuner_set_bandwidth(fe, (stb0899_carr_width(state) + SearchRange));
+			if (state->config->tuner_get_bandwidth)
+				state->config->tuner_get_bandwidth(fe, &internal->tuner_bw);
+
+			/* disable tuner I/O */
+			stb0899_i2c_gate_ctrl(&state->frontend, 0);
+
+//			pParams->SpectralInv		= pSearch->IQ_Inversion;
+
+			/* Set DVB-S2 AGC		*/
+			stb0899_write_reg(state, STB0899_AGCRFCFG, 0x1c);
+
+			/* Set IterScale =f(MCLK,SYMB)	*/
+			stb0899_set_iterations(state);
+
+			/* Run the search algorithm	*/
+			dprintk(state->verbose, FE_DEBUG, 1, "running DVB-S2 search algo ..");
+			if (stb0899_dvbs2_algo(state)	== DVBS2_FEC_LOCK) {
+				internal->lock		= 1;
+				dprintk(state->verbose, FE_DEBUG, 1,
+					"-------------------------------------> DVB-S2 LOCK !");
+
+//				stb0899_write_reg(state, STB0899_ERRCTRL1, 0xb6); /* Packet Errors	*/
+//				internal->v_status = stb0899_read_reg(state, STB0899_VSTATUS);
+//				internal->err_ctrl = stb0899_read_reg(state, STB0899_ERRCTRL1);
+
+				return DVBFE_ALGO_SEARCH_SUCCESS;
+			} else {
+				internal->lock		= 0;
+
+				return DVBFE_ALGO_SEARCH_FAILED;
+			}
+			break;
+		default:
+			dprintk(state->verbose, FE_ERROR, 1, "Unsupported delivery system");
+			return DVBFE_ALGO_SEARCH_INVALID;
+		}
+	}
+
+	return DVBFE_ALGO_SEARCH_ERROR;
+}
+
+static int stb0899_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct stb0899_state *state		= fe->demodulator_priv;
+	struct stb0899_internal *internal	= &state->internal;
+
+	dprintk(state->verbose, FE_DEBUG, 1, "Get params");
+	p->symbol_rate = internal->srate;
+
+	return 0;
+}
+
+static enum dvbfe_algo stb0899_frontend_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_CUSTOM;
+}
+
+static struct dvb_frontend_ops stb0899_ops = {
+	.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
+	.info = {
+		.name 			= "STB0899 Multistandard",
+		.frequency_min		= 950000,
+		.frequency_max 		= 2150000,
+		.frequency_stepsize	= 0,
+		.frequency_tolerance	= 0,
+		.symbol_rate_min 	=  5000000,
+		.symbol_rate_max 	= 45000000,
+
+		.caps 			= FE_CAN_INVERSION_AUTO	|
+					  FE_CAN_FEC_AUTO	|
+					  FE_CAN_2G_MODULATION	|
+					  FE_CAN_QPSK
+	},
+
+	.release			= stb0899_release,
+	.init				= stb0899_init,
+	.sleep				= stb0899_sleep,
+//	.wakeup				= stb0899_wakeup,
+
+	.i2c_gate_ctrl			= stb0899_i2c_gate_ctrl,
+
+	.get_frontend_algo		= stb0899_frontend_algo,
+	.search				= stb0899_search,
+	.get_frontend                   = stb0899_get_frontend,
+
+
+	.read_status			= stb0899_read_status,
+	.read_snr			= stb0899_read_snr,
+	.read_signal_strength		= stb0899_read_signal_strength,
+	.read_ber			= stb0899_read_ber,
+
+	.set_voltage			= stb0899_set_voltage,
+	.set_tone			= stb0899_set_tone,
+
+	.diseqc_send_master_cmd		= stb0899_send_diseqc_msg,
+	.diseqc_recv_slave_reply	= stb0899_recv_slave_reply,
+	.diseqc_send_burst		= stb0899_send_diseqc_burst,
+};
+
+struct dvb_frontend *stb0899_attach(struct stb0899_config *config, struct i2c_adapter *i2c)
+{
+	struct stb0899_state *state = NULL;
+	enum stb0899_inversion inversion;
+
+	state = kzalloc(sizeof (struct stb0899_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	inversion				= config->inversion;
+	state->verbose				= &verbose;
+	state->config				= config;
+	state->i2c				= i2c;
+	state->frontend.ops			= stb0899_ops;
+	state->frontend.demodulator_priv	= state;
+	state->internal.inversion		= inversion;
+
+	stb0899_wakeup(&state->frontend);
+	if (stb0899_get_dev_id(state) == -ENODEV) {
+		printk("%s: Exiting .. !\n", __func__);
+		goto error;
+	}
+
+	printk("%s: Attaching STB0899 \n", __func__);
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(stb0899_attach);
+MODULE_PARM_DESC(verbose, "Set Verbosity level");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_DESCRIPTION("STB0899 Multi-Std frontend");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/stb0899_drv.h b/drivers/media/dvb-frontends/stb0899_drv.h
new file mode 100644
index 0000000..98b200c
--- /dev/null
+++ b/drivers/media/dvb-frontends/stb0899_drv.h
@@ -0,0 +1,162 @@
+/*
+	STB0899 Multistandard Frontend driver
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __STB0899_DRV_H
+#define __STB0899_DRV_H
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "dvb_frontend.h"
+
+#define STB0899_TSMODE_SERIAL		1
+#define STB0899_CLKPOL_FALLING		2
+#define STB0899_CLKNULL_PARITY		3
+#define STB0899_SYNC_FORCED		4
+#define STB0899_FECMODE_DSS		5
+
+struct stb0899_s1_reg {
+	u16	address;
+	u8	data;
+};
+
+struct stb0899_s2_reg {
+	u16	offset;
+	u32	base_address;
+	u32	data;
+};
+
+enum stb0899_inversion {
+	IQ_SWAP_OFF	= 0,
+	IQ_SWAP_ON,
+	IQ_SWAP_AUTO
+};
+
+#define STB0899_GPIO00				0xf140
+#define STB0899_GPIO01				0xf141
+#define STB0899_GPIO02				0xf142
+#define STB0899_GPIO03				0xf143
+#define STB0899_GPIO04				0xf144
+#define STB0899_GPIO05				0xf145
+#define STB0899_GPIO06				0xf146
+#define STB0899_GPIO07				0xf147
+#define STB0899_GPIO08				0xf148
+#define STB0899_GPIO09				0xf149
+#define STB0899_GPIO10				0xf14a
+#define STB0899_GPIO11				0xf14b
+#define STB0899_GPIO12				0xf14c
+#define STB0899_GPIO13				0xf14d
+#define STB0899_GPIO14				0xf14e
+#define STB0899_GPIO15				0xf14f
+#define STB0899_GPIO16				0xf150
+#define STB0899_GPIO17				0xf151
+#define STB0899_GPIO18				0xf152
+#define STB0899_GPIO19				0xf153
+#define STB0899_GPIO20				0xf154
+
+#define STB0899_GPIOPULLUP			0x01 /* Output device is connected to Vdd */
+#define STB0899_GPIOPULLDN			0x00 /* Output device is connected to Vss */
+
+#define STB0899_POSTPROC_GPIO_POWER		0x00
+#define STB0899_POSTPROC_GPIO_LOCK		0x01
+
+/*
+ * Post process output configuration control
+ * 1. POWER ON/OFF		(index 0)
+ * 2. FE_HAS_LOCK/LOCK_LOSS	(index 1)
+ *
+ * @gpio 	= one of the above listed GPIO's
+ * @level	= output state: pulled up or low
+ */
+struct stb0899_postproc {
+	u16	gpio;
+	u8	level;
+};
+
+struct stb0899_config {
+	const struct stb0899_s1_reg	*init_dev;
+	const struct stb0899_s2_reg	*init_s2_demod;
+	const struct stb0899_s1_reg	*init_s1_demod;
+	const struct stb0899_s2_reg	*init_s2_fec;
+	const struct stb0899_s1_reg	*init_tst;
+
+	const struct stb0899_postproc	*postproc;
+
+	enum stb0899_inversion		inversion;
+
+	u32	xtal_freq;
+
+	u8	demod_address;
+	u8	ts_output_mode;
+	u8	block_sync_mode;
+	u8	ts_pfbit_toggle;
+
+	u8	clock_polarity;
+	u8	data_clk_parity;
+	u8	fec_mode;
+	u8	data_output_ctl;
+	u8	data_fifo_mode;
+	u8	out_rate_comp;
+	u8	i2c_repeater;
+//	int	inversion;
+	int	lo_clk;
+	int	hi_clk;
+
+	u32	esno_ave;
+	u32	esno_quant;
+	u32	avframes_coarse;
+	u32	avframes_fine;
+	u32	miss_threshold;
+	u32	uwp_threshold_acq;
+	u32	uwp_threshold_track;
+	u32	uwp_threshold_sof;
+	u32	sof_search_timeout;
+
+	u32	btr_nco_bits;
+	u32	btr_gain_shift_offset;
+	u32	crl_nco_bits;
+	u32	ldpc_max_iter;
+
+	int (*tuner_set_frequency)(struct dvb_frontend *fe, u32 frequency);
+	int (*tuner_get_frequency)(struct dvb_frontend *fe, u32 *frequency);
+	int (*tuner_set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
+	int (*tuner_get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
+	int (*tuner_set_rfsiggain)(struct dvb_frontend *fe, u32 rf_gain);
+};
+
+#if defined(CONFIG_DVB_STB0899) || (defined(CONFIG_DVB_STB0899_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *stb0899_attach(struct stb0899_config *config,
+					   struct i2c_adapter *i2c);
+
+#else
+
+static inline struct dvb_frontend *stb0899_attach(struct stb0899_config *config,
+						  struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+#endif //CONFIG_DVB_STB0899
+
+
+#endif
diff --git a/drivers/media/dvb-frontends/stb0899_priv.h b/drivers/media/dvb-frontends/stb0899_priv.h
new file mode 100644
index 0000000..82395b9
--- /dev/null
+++ b/drivers/media/dvb-frontends/stb0899_priv.h
@@ -0,0 +1,263 @@
+/*
+	STB0899 Multistandard Frontend driver
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __STB0899_PRIV_H
+#define __STB0899_PRIV_H
+
+#include "dvb_frontend.h"
+#include "stb0899_drv.h"
+
+#define FE_ERROR				0
+#define FE_NOTICE				1
+#define FE_INFO					2
+#define FE_DEBUG				3
+#define FE_DEBUGREG				4
+
+#define dprintk(x, y, z, format, arg...) do {						\
+	if (z) {									\
+		if	((*x > FE_ERROR) && (*x > y))					\
+			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);		\
+		else if	((*x > FE_NOTICE) && (*x > y))					\
+			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
+		else if ((*x > FE_INFO) && (*x > y))					\
+			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);		\
+		else if ((*x > FE_DEBUG) && (*x > y))					\
+			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
+	} else {									\
+		if (*x > y)								\
+			printk(format, ##arg);						\
+	}										\
+} while(0)
+
+#define INRANGE(val, x, y)			(((x <= val) && (val <= y)) ||		\
+						 ((y <= val) && (val <= x)) ? 1 : 0)
+
+#define BYTE0					0
+#define BYTE1					8
+#define BYTE2					16
+#define BYTE3					24
+
+#define GETBYTE(x, y)				(((x) >> (y)) & 0xff)
+#define MAKEWORD32(a, b, c, d)			(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
+#define MAKEWORD16(a, b)			(((a) << 8) | (b))
+
+#define LSB(x)					((x & 0xff))
+#define MSB(y)					((y >> 8) & 0xff)
+
+
+#define STB0899_GETFIELD(bitf, val)		((val >> STB0899_OFFST_##bitf) & ((1 << STB0899_WIDTH_##bitf) - 1))
+
+
+#define STB0899_SETFIELD(mask, val, width, offset)      (mask & (~(((1 << width) - 1) <<	\
+							 offset))) | ((val &			\
+							 ((1 << width) - 1)) << offset)
+
+#define STB0899_SETFIELD_VAL(bitf, mask, val)	(mask = (mask & (~(((1 << STB0899_WIDTH_##bitf) - 1) <<\
+							 STB0899_OFFST_##bitf))) | \
+							 (val << STB0899_OFFST_##bitf))
+
+
+enum stb0899_status {
+	NOAGC1	= 0,
+	AGC1OK,
+	NOTIMING,
+	ANALOGCARRIER,
+	TIMINGOK,
+	NOAGC2,
+	AGC2OK,
+	NOCARRIER,
+	CARRIEROK,
+	NODATA,
+	FALSELOCK,
+	DATAOK,
+	OUTOFRANGE,
+	RANGEOK,
+	DVBS2_DEMOD_LOCK,
+	DVBS2_DEMOD_NOLOCK,
+	DVBS2_FEC_LOCK,
+	DVBS2_FEC_NOLOCK
+};
+
+enum stb0899_modcod {
+	STB0899_DUMMY_PLF,
+	STB0899_QPSK_14,
+	STB0899_QPSK_13,
+	STB0899_QPSK_25,
+	STB0899_QPSK_12,
+	STB0899_QPSK_35,
+	STB0899_QPSK_23,
+	STB0899_QPSK_34,
+	STB0899_QPSK_45,
+	STB0899_QPSK_56,
+	STB0899_QPSK_89,
+	STB0899_QPSK_910,
+	STB0899_8PSK_35,
+	STB0899_8PSK_23,
+	STB0899_8PSK_34,
+	STB0899_8PSK_56,
+	STB0899_8PSK_89,
+	STB0899_8PSK_910,
+	STB0899_16APSK_23,
+	STB0899_16APSK_34,
+	STB0899_16APSK_45,
+	STB0899_16APSK_56,
+	STB0899_16APSK_89,
+	STB0899_16APSK_910,
+	STB0899_32APSK_34,
+	STB0899_32APSK_45,
+	STB0899_32APSK_56,
+	STB0899_32APSK_89,
+	STB0899_32APSK_910
+};
+
+enum stb0899_frame {
+	STB0899_LONG_FRAME,
+	STB0899_SHORT_FRAME
+};
+
+enum stb0899_alpha {
+	RRC_20,
+	RRC_25,
+	RRC_35
+};
+
+struct stb0899_tab {
+	s32 real;
+	s32 read;
+};
+
+enum stb0899_fec {
+	STB0899_FEC_1_2			= 13,
+	STB0899_FEC_2_3			= 18,
+	STB0899_FEC_3_4			= 21,
+	STB0899_FEC_5_6			= 24,
+	STB0899_FEC_6_7			= 25,
+	STB0899_FEC_7_8			= 26
+};
+
+struct stb0899_params {
+	u32	freq;					/* Frequency	*/
+	u32	srate;					/* Symbol rate	*/
+	enum fe_code_rate fecrate;
+};
+
+struct stb0899_internal {
+	u32			master_clk;
+	u32			freq;			/* Demod internal Frequency		*/
+	u32			srate;			/* Demod internal Symbol rate		*/
+	enum stb0899_fec	fecrate;		/* Demod internal FEC rate		*/
+	s32			srch_range;		/* Demod internal Search Range		*/
+	s32			sub_range;		/* Demod current sub range (Hz)		*/
+	s32			tuner_step;		/* Tuner step (Hz)			*/
+	s32			tuner_offst;		/* Relative offset to carrier (Hz)	*/
+	u32			tuner_bw;		/* Current bandwidth of the tuner (Hz)	*/
+
+	s32			mclk;			/* Masterclock Divider factor (binary)	*/
+	s32			rolloff;		/* Current RollOff of the filter (x100)	*/
+
+	s16			derot_freq;		/* Current derotator frequency (Hz)	*/
+	s16			derot_percent;
+
+	s16			direction;		/* Current derotator search direction	*/
+	s16			derot_step;		/* Derotator step (binary value)	*/
+	s16			t_derot;		/* Derotator time constant (ms)		*/
+	s16			t_data;			/* Data recovery time constant (ms)	*/
+	s16			sub_dir;		/* Direction of the next sub range	*/
+
+	s16			t_agc1;			/* Agc1 time constant (ms)		*/
+	s16			t_agc2;			/* Agc2 time constant (ms)		*/
+
+	u32			lock;			/* Demod internal lock state		*/
+	enum stb0899_status	status;			/* Demod internal status		*/
+
+	/* DVB-S2 */
+	s32			agc_gain;		/* RF AGC Gain				*/
+	s32			center_freq;		/* Nominal carrier frequency		*/
+	s32			av_frame_coarse;	/* Coarse carrier freq search frames	*/
+	s32			av_frame_fine;		/* Fine carrier freq search frames	*/
+
+	s16			step_size;		/* Carrier frequency search step size	*/
+
+	enum stb0899_alpha	rrc_alpha;
+	enum stb0899_inversion	inversion;
+	enum stb0899_modcod	modcod;
+	u8			pilots;			/* Pilots found				*/
+
+	enum stb0899_frame	frame_length;
+	u8			v_status;		/* VSTATUS				*/
+	u8			err_ctrl;		/* ERRCTRLn				*/
+};
+
+struct stb0899_state {
+	struct i2c_adapter		*i2c;
+	struct stb0899_config		*config;
+	struct dvb_frontend		frontend;
+
+	u32				*verbose;	/* Cached module verbosity level	*/
+
+	struct stb0899_internal		internal;	/* Device internal parameters		*/
+
+	/*	cached params from API	*/
+	enum fe_delivery_system		delsys;
+	struct stb0899_params		params;
+
+	u32				rx_freq;	/* DiSEqC 2.0 receiver freq		*/
+	struct mutex			search_lock;
+};
+/* stb0899.c		*/
+extern int stb0899_read_reg(struct stb0899_state *state,
+			    unsigned int reg);
+
+extern u32 _stb0899_read_s2reg(struct stb0899_state *state,
+			       u32 stb0899_i2cdev,
+			       u32 stb0899_base_addr,
+			       u16 stb0899_reg_offset);
+
+extern int stb0899_read_regs(struct stb0899_state *state,
+			     unsigned int reg, u8 *buf,
+			     u32 count);
+
+extern int stb0899_write_regs(struct stb0899_state *state,
+			      unsigned int reg, u8 *data,
+			      u32 count);
+
+extern int stb0899_write_reg(struct stb0899_state *state,
+			     unsigned int reg,
+			     u8 data);
+
+extern int stb0899_write_s2reg(struct stb0899_state *state,
+			       u32 stb0899_i2cdev,
+			       u32 stb0899_base_addr,
+			       u16 stb0899_reg_offset,
+			       u32 stb0899_data);
+
+extern int stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
+
+
+#define STB0899_READ_S2REG(DEVICE, REG) 	(_stb0899_read_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG))
+//#define STB0899_WRITE_S2REG(DEVICE, REG, DATA)	(_stb0899_write_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG, DATA))
+
+/* stb0899_algo.c	*/
+extern enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state);
+extern enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state);
+extern long stb0899_carr_width(struct stb0899_state *state);
+
+#endif //__STB0899_PRIV_H
diff --git a/drivers/media/dvb-frontends/stb0899_reg.h b/drivers/media/dvb-frontends/stb0899_reg.h
new file mode 100644
index 0000000..ba1ed56
--- /dev/null
+++ b/drivers/media/dvb-frontends/stb0899_reg.h
@@ -0,0 +1,2027 @@
+/*
+	STB0899 Multistandard Frontend driver
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __STB0899_REG_H
+#define __STB0899_REG_H
+
+/*	S1	*/
+#define STB0899_DEV_ID				0xf000
+#define STB0899_CHIP_ID				(0x0f << 4)
+#define STB0899_OFFST_CHIP_ID			4
+#define STB0899_WIDTH_CHIP_ID			4
+#define STB0899_CHIP_REL			(0x0f << 0)
+#define STB0899_OFFST_CHIP_REL			0
+#define STB0899_WIDTH_CHIP_REL			4
+
+#define STB0899_DEMOD				0xf40e
+#define STB0899_MODECOEFF			(0x01 << 0)
+#define STB0899_OFFST_MODECOEFF			0
+#define STB0899_WIDTH_MODECOEFF			1
+
+#define STB0899_RCOMPC				0xf410
+#define STB0899_AGC1CN				0xf412
+#define STB0899_AGC1REF				0xf413
+#define STB0899_RTC				0xf417
+#define STB0899_TMGCFG				0xf418
+#define STB0899_AGC2REF				0xf419
+#define STB0899_TLSR				0xf41a
+
+#define STB0899_CFD				0xf41b
+#define STB0899_CFD_ON				(0x01 << 7)
+#define STB0899_OFFST_CFD_ON			7
+#define STB0899_WIDTH_CFD_ON			1
+
+#define STB0899_ACLC				0xf41c
+
+#define STB0899_BCLC				0xf41d
+#define STB0899_OFFST_ALGO			6
+#define STB0899_WIDTH_ALGO_QPSK2		2
+#define STB0899_ALGO_QPSK2			(2 << 6)
+#define STB0899_ALGO_QPSK1			(1 << 6)
+#define STB0899_ALGO_BPSK			(0 << 6)
+#define STB0899_OFFST_BETA			0
+#define STB0899_WIDTH_BETA			6
+
+#define STB0899_EQON				0xf41e
+#define STB0899_LDT				0xf41f
+#define STB0899_LDT2				0xf420
+#define STB0899_EQUALREF			0xf425
+#define STB0899_TMGRAMP				0xf426
+#define STB0899_TMGTHD				0xf427
+#define STB0899_IDCCOMP				0xf428
+#define STB0899_QDCCOMP				0xf429
+#define STB0899_POWERI				0xf42a
+#define STB0899_POWERQ				0xf42b
+#define STB0899_RCOMP				0xf42c
+
+#define STB0899_AGCIQIN				0xf42e
+#define STB0899_AGCIQVALUE			(0xff << 0)
+#define STB0899_OFFST_AGCIQVALUE		0
+#define STB0899_WIDTH_AGCIQVALUE		8
+
+#define STB0899_AGC2I1				0xf436
+#define STB0899_AGC2I2				0xf437
+
+#define STB0899_TLIR				0xf438
+#define STB0899_TLIR_TMG_LOCK_IND		(0xff << 0)
+#define STB0899_OFFST_TLIR_TMG_LOCK_IND		0
+#define STB0899_WIDTH_TLIR_TMG_LOCK_IND		8
+
+#define STB0899_RTF				0xf439
+#define STB0899_RTF_TIMING_LOOP_FREQ		(0xff << 0)
+#define STB0899_OFFST_RTF_TIMING_LOOP_FREQ	0
+#define STB0899_WIDTH_RTF_TIMING_LOOP_FREQ	8
+
+#define STB0899_DSTATUS				0xf43a
+#define STB0899_CARRIER_FOUND			(0x01 << 7)
+#define STB0899_OFFST_CARRIER_FOUND		7
+#define STB0899_WIDTH_CARRIER_FOUND		1
+#define STB0899_TMG_LOCK			(0x01 << 6)
+#define STB0899_OFFST_TMG_LOCK			6
+#define STB0899_WIDTH_TMG_LOCK			1
+#define STB0899_DEMOD_LOCK			(0x01 << 5)
+#define STB0899_OFFST_DEMOD_LOCK		5
+#define STB0899_WIDTH_DEMOD_LOCK		1
+#define STB0899_TMG_AUTO			(0x01 << 4)
+#define STB0899_OFFST_TMG_AUTO			4
+#define STB0899_WIDTH_TMG_AUTO			1
+#define STB0899_END_MAIN			(0x01 << 3)
+#define STB0899_OFFST_END_MAIN			3
+#define STB0899_WIDTH_END_MAIN			1
+
+#define STB0899_LDI				0xf43b
+#define STB0899_OFFST_LDI			0
+#define STB0899_WIDTH_LDI			8
+
+#define STB0899_CFRM				0xf43e
+#define STB0899_OFFST_CFRM			0
+#define STB0899_WIDTH_CFRM			8
+
+#define STB0899_CFRL				0xf43f
+#define STB0899_OFFST_CFRL			0
+#define STB0899_WIDTH_CFRL			8
+
+#define STB0899_NIRM				0xf440
+#define STB0899_OFFST_NIRM			0
+#define STB0899_WIDTH_NIRM			8
+
+#define STB0899_NIRL				0xf441
+#define STB0899_OFFST_NIRL			0
+#define STB0899_WIDTH_NIRL			8
+
+#define STB0899_ISYMB				0xf444
+#define STB0899_QSYMB				0xf445
+
+#define STB0899_SFRH				0xf446
+#define STB0899_OFFST_SFRH			0
+#define STB0899_WIDTH_SFRH			8
+
+#define STB0899_SFRM				0xf447
+#define STB0899_OFFST_SFRM			0
+#define STB0899_WIDTH_SFRM			8
+
+#define STB0899_SFRL				0xf448
+#define STB0899_OFFST_SFRL			4
+#define STB0899_WIDTH_SFRL			4
+
+#define STB0899_SFRUPH				0xf44c
+#define STB0899_SFRUPM				0xf44d
+#define STB0899_SFRUPL				0xf44e
+
+#define STB0899_EQUAI1				0xf4e0
+#define STB0899_EQUAQ1				0xf4e1
+#define STB0899_EQUAI2				0xf4e2
+#define STB0899_EQUAQ2				0xf4e3
+#define STB0899_EQUAI3				0xf4e4
+#define STB0899_EQUAQ3				0xf4e5
+#define STB0899_EQUAI4				0xf4e6
+#define STB0899_EQUAQ4				0xf4e7
+#define STB0899_EQUAI5				0xf4e8
+#define STB0899_EQUAQ5				0xf4e9
+
+#define STB0899_DSTATUS2			0xf50c
+#define STB0899_DS2_TMG_AUTOSRCH		(0x01 << 7)
+#define STB8999_OFFST_DS2_TMG_AUTOSRCH		7
+#define STB0899_WIDTH_DS2_TMG_AUTOSRCH		1
+#define STB0899_DS2_END_MAINLOOP		(0x01 << 6)
+#define STB0899_OFFST_DS2_END_MAINLOOP		6
+#define STB0899_WIDTH_DS2_END_MAINLOOP		1
+#define STB0899_DS2_CFSYNC			(0x01 << 5)
+#define STB0899_OFFST_DS2_CFSYNC		5
+#define STB0899_WIDTH_DS2_CFSYNC		1
+#define STB0899_DS2_TMGLOCK			(0x01 << 4)
+#define STB0899_OFFST_DS2_TMGLOCK		4
+#define STB0899_WIDTH_DS2_TMGLOCK		1
+#define STB0899_DS2_DEMODWAIT			(0x01 << 3)
+#define STB0899_OFFST_DS2_DEMODWAIT		3
+#define STB0899_WIDTH_DS2_DEMODWAIT		1
+#define STB0899_DS2_FECON			(0x01 << 1)
+#define STB0899_OFFST_DS2_FECON			1
+#define STB0899_WIDTH_DS2_FECON			1
+
+/*	S1 FEC	*/
+#define STB0899_VSTATUS				0xf50d
+#define STB0899_VSTATUS_VITERBI_ON		(0x01 << 7)
+#define STB0899_OFFST_VSTATUS_VITERBI_ON	7
+#define STB0899_WIDTH_VSTATUS_VITERBI_ON	1
+#define STB0899_VSTATUS_END_LOOPVIT		(0x01 << 6)
+#define STB0899_OFFST_VSTATUS_END_LOOPVIT	6
+#define STB0899_WIDTH_VSTATUS_END_LOOPVIT	1
+#define STB0899_VSTATUS_PRFVIT			(0x01 << 4)
+#define STB0899_OFFST_VSTATUS_PRFVIT		4
+#define STB0899_WIDTH_VSTATUS_PRFVIT		1
+#define STB0899_VSTATUS_LOCKEDVIT		(0x01 << 3)
+#define STB0899_OFFST_VSTATUS_LOCKEDVIT		3
+#define STB0899_WIDTH_VSTATUS_LOCKEDVIT		1
+
+#define STB0899_VERROR				0xf50f
+
+#define STB0899_IQSWAP				0xf523
+#define STB0899_SYM				(0x01 << 3)
+#define STB0899_OFFST_SYM			3
+#define STB0899_WIDTH_SYM			1
+
+#define STB0899_FECAUTO1			0xf530
+#define STB0899_DSSSRCH				(0x01 << 3)
+#define STB0899_OFFST_DSSSRCH			3
+#define STB0899_WIDTH_DSSSRCH			1
+#define STB0899_SYMSRCH				(0x01 << 2)
+#define STB0899_OFFST_SYMSRCH			2
+#define STB0899_WIDTH_SYMSRCH			1
+#define STB0899_QPSKSRCH			(0x01 << 1)
+#define STB0899_OFFST_QPSKSRCH			1
+#define STB0899_WIDTH_QPSKSRCH			1
+#define STB0899_BPSKSRCH			(0x01 << 0)
+#define STB0899_OFFST_BPSKSRCH			0
+#define STB0899_WIDTH_BPSKSRCH			1
+
+#define STB0899_FECM				0xf533
+#define STB0899_FECM_NOT_DVB			(0x01 << 7)
+#define STB0899_OFFST_FECM_NOT_DVB		7
+#define STB0899_WIDTH_FECM_NOT_DVB		1
+#define STB0899_FECM_RSVD1			(0x07 << 4)
+#define STB0899_OFFST_FECM_RSVD1		4
+#define STB0899_WIDTH_FECM_RSVD1		3
+#define STB0899_FECM_VITERBI_ON			(0x01 << 3)
+#define STB0899_OFFST_FECM_VITERBI_ON		3
+#define STB0899_WIDTH_FECM_VITERBI_ON		1
+#define STB0899_FECM_RSVD0			(0x01 << 2)
+#define STB0899_OFFST_FECM_RSVD0		2
+#define STB0899_WIDTH_FECM_RSVD0		1
+#define STB0899_FECM_SYNCDIS			(0x01 << 1)
+#define STB0899_OFFST_FECM_SYNCDIS		1
+#define STB0899_WIDTH_FECM_SYNCDIS		1
+#define STB0899_FECM_SYMI			(0x01 << 0)
+#define STB0899_OFFST_FECM_SYMI			0
+#define STB0899_WIDTH_FECM_SYMI			1
+
+#define STB0899_VTH12				0xf534
+#define STB0899_VTH23				0xf535
+#define STB0899_VTH34				0xf536
+#define STB0899_VTH56				0xf537
+#define STB0899_VTH67				0xf538
+#define STB0899_VTH78				0xf539
+
+#define STB0899_PRVIT				0xf53c
+#define STB0899_PR_7_8				(0x01 << 5)
+#define STB0899_OFFST_PR_7_8			5
+#define STB0899_WIDTH_PR_7_8			1
+#define STB0899_PR_6_7				(0x01 << 4)
+#define STB0899_OFFST_PR_6_7			4
+#define STB0899_WIDTH_PR_6_7			1
+#define STB0899_PR_5_6				(0x01 << 3)
+#define STB0899_OFFST_PR_5_6			3
+#define STB0899_WIDTH_PR_5_6			1
+#define STB0899_PR_3_4				(0x01 << 2)
+#define STB0899_OFFST_PR_3_4			2
+#define STB0899_WIDTH_PR_3_4			1
+#define STB0899_PR_2_3				(0x01 << 1)
+#define STB0899_OFFST_PR_2_3			1
+#define STB0899_WIDTH_PR_2_3			1
+#define STB0899_PR_1_2				(0x01 << 0)
+#define STB0899_OFFST_PR_1_2			0
+#define STB0899_WIDTH_PR_1_2			1
+
+#define STB0899_VITSYNC				0xf53d
+#define STB0899_AM				(0x01 << 7)
+#define STB0899_OFFST_AM			7
+#define STB0899_WIDTH_AM			1
+#define STB0899_FREEZE				(0x01 << 6)
+#define STB0899_OFFST_FREEZE			6
+#define STB0899_WIDTH_FREEZE			1
+#define STB0899_SN_65536			(0x03 << 4)
+#define STB0899_OFFST_SN_65536			4
+#define STB0899_WIDTH_SN_65536			2
+#define STB0899_SN_16384			(0x01 << 5)
+#define STB0899_OFFST_SN_16384			5
+#define STB0899_WIDTH_SN_16384			1
+#define STB0899_SN_4096				(0x01 << 4)
+#define STB0899_OFFST_SN_4096			4
+#define STB0899_WIDTH_SN_4096			1
+#define STB0899_SN_1024				(0x00 << 4)
+#define STB0899_OFFST_SN_1024			4
+#define STB0899_WIDTH_SN_1024			0
+#define STB0899_TO_128				(0x03 << 2)
+#define STB0899_OFFST_TO_128			2
+#define STB0899_WIDTH_TO_128			2
+#define STB0899_TO_64				(0x01 << 3)
+#define STB0899_OFFST_TO_64			3
+#define STB0899_WIDTH_TO_64			1
+#define STB0899_TO_32				(0x01 << 2)
+#define STB0899_OFFST_TO_32			2
+#define STB0899_WIDTH_TO_32			1
+#define STB0899_TO_16				(0x00 << 2)
+#define STB0899_OFFST_TO_16			2
+#define STB0899_WIDTH_TO_16			0
+#define STB0899_HYST_128			(0x03 << 1)
+#define STB0899_OFFST_HYST_128			1
+#define STB0899_WIDTH_HYST_128			2
+#define STB0899_HYST_64				(0x01 << 1)
+#define STB0899_OFFST_HYST_64			1
+#define STB0899_WIDTH_HYST_64			1
+#define STB0899_HYST_32				(0x01 << 0)
+#define STB0899_OFFST_HYST_32			0
+#define STB0899_WIDTH_HYST_32			1
+#define STB0899_HYST_16				(0x00 << 0)
+#define STB0899_OFFST_HYST_16			0
+#define STB0899_WIDTH_HYST_16			0
+
+#define STB0899_RSULC				0xf548
+#define STB0899_ULDIL_ON			(0x01 << 7)
+#define STB0899_OFFST_ULDIL_ON			7
+#define STB0899_WIDTH_ULDIL_ON			1
+#define STB0899_ULAUTO_ON			(0x01 << 6)
+#define STB0899_OFFST_ULAUTO_ON			6
+#define STB0899_WIDTH_ULAUTO_ON			1
+#define STB0899_ULRS_ON				(0x01 << 5)
+#define STB0899_OFFST_ULRS_ON			5
+#define STB0899_WIDTH_ULRS_ON			1
+#define STB0899_ULDESCRAM_ON			(0x01 << 4)
+#define STB0899_OFFST_ULDESCRAM_ON		4
+#define STB0899_WIDTH_ULDESCRAM_ON		1
+#define STB0899_UL_DISABLE			(0x01 << 2)
+#define STB0899_OFFST_UL_DISABLE		2
+#define STB0899_WIDTH_UL_DISABLE		1
+#define STB0899_NOFTHRESHOLD			(0x01 << 0)
+#define STB0899_OFFST_NOFTHRESHOLD		0
+#define STB0899_WIDTH_NOFTHRESHOLD		1
+
+#define STB0899_RSLLC				0xf54a
+#define STB0899_DEMAPVIT			0xf583
+#define STB0899_DEMAPVIT_RSVD			(0x01 << 7)
+#define STB0899_OFFST_DEMAPVIT_RSVD		7
+#define STB0899_WIDTH_DEMAPVIT_RSVD		1
+#define STB0899_DEMAPVIT_KDIVIDER		(0x7f << 0)
+#define STB0899_OFFST_DEMAPVIT_KDIVIDER		0
+#define STB0899_WIDTH_DEMAPVIT_KDIVIDER		7
+
+#define STB0899_PLPARM				0xf58c
+#define STB0899_VITMAPPING			(0x07 << 5)
+#define STB0899_OFFST_VITMAPPING		5
+#define STB0899_WIDTH_VITMAPPING		3
+#define STB0899_VITMAPPING_BPSK			(0x01 << 5)
+#define STB0899_OFFST_VITMAPPING_BPSK		5
+#define STB0899_WIDTH_VITMAPPING_BPSK		1
+#define STB0899_VITMAPPING_QPSK			(0x00 << 5)
+#define STB0899_OFFST_VITMAPPING_QPSK		5
+#define STB0899_WIDTH_VITMAPPING_QPSK		0
+#define STB0899_VITCURPUN			(0x1f << 0)
+#define STB0899_OFFST_VITCURPUN			0
+#define STB0899_WIDTH_VITCURPUN			5
+#define STB0899_VITCURPUN_1_2			(0x0d << 0)
+#define STB0899_VITCURPUN_2_3			(0x12 << 0)
+#define STB0899_VITCURPUN_3_4			(0x15 << 0)
+#define STB0899_VITCURPUN_5_6			(0x18 << 0)
+#define STB0899_VITCURPUN_6_7			(0x19 << 0)
+#define STB0899_VITCURPUN_7_8			(0x1a << 0)
+
+/*	S2 DEMOD	*/
+#define STB0899_OFF0_DMD_STATUS			0xf300
+#define STB0899_BASE_DMD_STATUS			0x00000000
+#define STB0899_IF_AGC_LOCK			(0x01 << 8)
+#define STB0899_OFFST_IF_AGC_LOCK		0
+#define STB0899_WIDTH_IF_AGC_LOCK		1
+
+#define STB0899_OFF0_CRL_FREQ			0xf304
+#define STB0899_BASE_CRL_FREQ			0x00000000
+#define STB0899_CARR_FREQ			(0x3fffffff << 0)
+#define STB0899_OFFST_CARR_FREQ			0
+#define STB0899_WIDTH_CARR_FREQ			30
+
+#define STB0899_OFF0_BTR_FREQ			0xf308
+#define STB0899_BASE_BTR_FREQ			0x00000000
+#define STB0899_BTR_FREQ			(0xfffffff << 0)
+#define STB0899_OFFST_BTR_FREQ			0
+#define STB0899_WIDTH_BTR_FREQ			28
+
+#define STB0899_OFF0_IF_AGC_GAIN		0xf30c
+#define STB0899_BASE_IF_AGC_GAIN		0x00000000
+#define STB0899_IF_AGC_GAIN			(0x3fff < 0)
+#define STB0899_OFFST_IF_AGC_GAIN		0
+#define STB0899_WIDTH_IF_AGC_GAIN		14
+
+#define STB0899_OFF0_BB_AGC_GAIN		0xf310
+#define STB0899_BASE_BB_AGC_GAIN		0x00000000
+#define STB0899_BB_AGC_GAIN			(0x3fff < 0)
+#define STB0899_OFFST_BB_AGC_GAIN		0
+#define STB0899_WIDTH_BB_AGC_GAIN		14
+
+#define STB0899_OFF0_DC_OFFSET			0xf314
+#define STB0899_BASE_DC_OFFSET			0x00000000
+#define STB0899_I				(0xff < 8)
+#define STB0899_OFFST_I				8
+#define STB0899_WIDTH_I				8
+#define STB0899_Q				(0xff < 0)
+#define STB0899_OFFST_Q				8
+#define STB0899_WIDTH_Q				8
+
+#define STB0899_OFF0_DMD_CNTRL			0xf31c
+#define STB0899_BASE_DMD_CNTRL			0x00000000
+#define STB0899_ADC0_PINS1IN			(0x01 << 6)
+#define STB0899_OFFST_ADC0_PINS1IN              6
+#define STB0899_WIDTH_ADC0_PINS1IN              1
+#define STB0899_IN2COMP1_OFFBIN0		(0x01 << 3)
+#define STB0899_OFFST_IN2COMP1_OFFBIN0          3
+#define STB0899_WIDTH_IN2COMP1_OFFBIN0          1
+#define STB0899_DC_COMP				(0x01 << 2)
+#define STB0899_OFFST_DC_COMP			2
+#define STB0899_WIDTH_DC_COMP			1
+#define STB0899_MODMODE				(0x03 << 0)
+#define STB0899_OFFST_MODMODE			0
+#define STB0899_WIDTH_MODMODE			2
+
+#define STB0899_OFF0_IF_AGC_CNTRL		0xf320
+#define STB0899_BASE_IF_AGC_CNTRL		0x00000000
+#define STB0899_IF_GAIN_INIT			(0x3fff << 13)
+#define STB0899_OFFST_IF_GAIN_INIT		13
+#define STB0899_WIDTH_IF_GAIN_INIT		14
+#define STB0899_IF_GAIN_SENSE			(0x01 << 12)
+#define STB0899_OFFST_IF_GAIN_SENSE		12
+#define STB0899_WIDTH_IF_GAIN_SENSE		1
+#define STB0899_IF_LOOP_GAIN			(0x0f << 8)
+#define STB0899_OFFST_IF_LOOP_GAIN		8
+#define STB0899_WIDTH_IF_LOOP_GAIN		4
+#define STB0899_IF_LD_GAIN_INIT			(0x01 << 7)
+#define STB0899_OFFST_IF_LD_GAIN_INIT		7
+#define STB0899_WIDTH_IF_LD_GAIN_INIT		1
+#define STB0899_IF_AGC_REF			(0x7f << 0)
+#define STB0899_OFFST_IF_AGC_REF		0
+#define STB0899_WIDTH_IF_AGC_REF		7
+
+#define STB0899_OFF0_BB_AGC_CNTRL		0xf324
+#define STB0899_BASE_BB_AGC_CNTRL		0x00000000
+#define STB0899_BB_GAIN_INIT			(0x3fff << 12)
+#define STB0899_OFFST_BB_GAIN_INIT		12
+#define STB0899_WIDTH_BB_GAIN_INIT		14
+#define STB0899_BB_LOOP_GAIN			(0x0f << 8)
+#define STB0899_OFFST_BB_LOOP_GAIN		8
+#define STB0899_WIDTH_BB_LOOP_GAIN		4
+#define STB0899_BB_LD_GAIN_INIT			(0x01 << 7)
+#define STB0899_OFFST_BB_LD_GAIN_INIT		7
+#define STB0899_WIDTH_BB_LD_GAIN_INIT		1
+#define STB0899_BB_AGC_REF			(0x7f << 0)
+#define STB0899_OFFST_BB_AGC_REF		0
+#define STB0899_WIDTH_BB_AGC_REF		7
+
+#define STB0899_OFF0_CRL_CNTRL			0xf328
+#define STB0899_BASE_CRL_CNTRL			0x00000000
+#define STB0899_CRL_LOCK_CLEAR			(0x01 << 5)
+#define STB0899_OFFST_CRL_LOCK_CLEAR		5
+#define STB0899_WIDTH_CRL_LOCK_CLEAR		1
+#define STB0899_CRL_SWPR_CLEAR			(0x01 << 4)
+#define STB0899_OFFST_CRL_SWPR_CLEAR		4
+#define STB0899_WIDTH_CRL_SWPR_CLEAR		1
+#define STB0899_CRL_SWP_ENA			(0x01 << 3)
+#define STB0899_OFFST_CRL_SWP_ENA		3
+#define STB0899_WIDTH_CRL_SWP_ENA		1
+#define STB0899_CRL_DET_SEL			(0x01 << 2)
+#define STB0899_OFFST_CRL_DET_SEL		2
+#define STB0899_WIDTH_CRL_DET_SEL		1
+#define STB0899_CRL_SENSE			(0x01 << 1)
+#define STB0899_OFFST_CRL_SENSE			1
+#define STB0899_WIDTH_CRL_SENSE			1
+#define STB0899_CRL_PHSERR_CLEAR		(0x01 << 0)
+#define STB0899_OFFST_CRL_PHSERR_CLEAR		0
+#define STB0899_WIDTH_CRL_PHSERR_CLEAR		1
+
+#define STB0899_OFF0_CRL_PHS_INIT		0xf32c
+#define STB0899_BASE_CRL_PHS_INIT		0x00000000
+#define STB0899_CRL_PHS_INIT_31			(0x1 << 30)
+#define STB0899_OFFST_CRL_PHS_INIT_31		30
+#define STB0899_WIDTH_CRL_PHS_INIT_31		1
+#define STB0899_CRL_LD_INIT_PHASE		(0x1 << 24)
+#define STB0899_OFFST_CRL_LD_INIT_PHASE		24
+#define STB0899_WIDTH_CRL_LD_INIT_PHASE		1
+#define STB0899_CRL_INIT_PHASE			(0xffffff << 0)
+#define STB0899_OFFST_CRL_INIT_PHASE		0
+#define STB0899_WIDTH_CRL_INIT_PHASE		24
+
+#define STB0899_OFF0_CRL_FREQ_INIT		0xf330
+#define STB0899_BASE_CRL_FREQ_INIT		0x00000000
+#define STB0899_CRL_FREQ_INIT_31		(0x1 << 30)
+#define STB0899_OFFST_CRL_FREQ_INIT_31		30
+#define STB0899_WIDTH_CRL_FREQ_INIT_31		1
+#define STB0899_CRL_LD_FREQ_INIT		(0x1 << 24)
+#define STB0899_OFFST_CRL_LD_FREQ_INIT		24
+#define STB0899_WIDTH_CRL_LD_FREQ_INIT		1
+#define STB0899_CRL_FREQ_INIT			(0xffffff << 0)
+#define STB0899_OFFST_CRL_FREQ_INIT		0
+#define STB0899_WIDTH_CRL_FREQ_INIT		24
+
+#define STB0899_OFF0_CRL_LOOP_GAIN		0xf334
+#define STB0899_BASE_CRL_LOOP_GAIN		0x00000000
+#define STB0899_KCRL2_RSHFT			(0xf << 16)
+#define STB0899_OFFST_KCRL2_RSHFT		16
+#define STB0899_WIDTH_KCRL2_RSHFT		4
+#define STB0899_KCRL1				(0xf << 12)
+#define STB0899_OFFST_KCRL1			12
+#define STB0899_WIDTH_KCRL1			4
+#define STB0899_KCRL1_RSHFT			(0xf << 8)
+#define STB0899_OFFST_KCRL1_RSHFT		8
+#define STB0899_WIDTH_KCRL1_RSHFT		4
+#define STB0899_KCRL0				(0xf << 4)
+#define STB0899_OFFST_KCRL0			4
+#define STB0899_WIDTH_KCRL0			4
+#define STB0899_KCRL0_RSHFT			(0xf << 0)
+#define STB0899_OFFST_KCRL0_RSHFT		0
+#define STB0899_WIDTH_KCRL0_RSHFT		4
+
+#define STB0899_OFF0_CRL_NOM_FREQ		0xf338
+#define STB0899_BASE_CRL_NOM_FREQ		0x00000000
+#define STB0899_CRL_NOM_FREQ			(0x3fffffff << 0)
+#define STB0899_OFFST_CRL_NOM_FREQ		0
+#define STB0899_WIDTH_CRL_NOM_FREQ		30
+
+#define STB0899_OFF0_CRL_SWP_RATE		0xf33c
+#define STB0899_BASE_CRL_SWP_RATE		0x00000000
+#define STB0899_CRL_SWP_RATE			(0x3fffffff << 0)
+#define STB0899_OFFST_CRL_SWP_RATE		0
+#define STB0899_WIDTH_CRL_SWP_RATE		30
+
+#define STB0899_OFF0_CRL_MAX_SWP		0xf340
+#define STB0899_BASE_CRL_MAX_SWP		0x00000000
+#define STB0899_CRL_MAX_SWP			(0x3fffffff << 0)
+#define STB0899_OFFST_CRL_MAX_SWP		0
+#define STB0899_WIDTH_CRL_MAX_SWP		30
+
+#define STB0899_OFF0_CRL_LK_CNTRL		0xf344
+#define STB0899_BASE_CRL_LK_CNTRL		0x00000000
+
+#define STB0899_OFF0_DECIM_CNTRL		0xf348
+#define STB0899_BASE_DECIM_CNTRL		0x00000000
+#define STB0899_BAND_LIMIT_B			(0x01 << 5)
+#define STB0899_OFFST_BAND_LIMIT_B		5
+#define STB0899_WIDTH_BAND_LIMIT_B		1
+#define STB0899_WIN_SEL				(0x03 << 3)
+#define STB0899_OFFST_WIN_SEL			3
+#define STB0899_WIDTH_WIN_SEL			2
+#define STB0899_DECIM_RATE			(0x07 << 0)
+#define STB0899_OFFST_DECIM_RATE		0
+#define STB0899_WIDTH_DECIM_RATE		3
+
+#define STB0899_OFF0_BTR_CNTRL			0xf34c
+#define STB0899_BASE_BTR_CNTRL			0x00000000
+#define STB0899_BTR_FREQ_CORR			(0x7ff << 4)
+#define STB0899_OFFST_BTR_FREQ_CORR		4
+#define STB0899_WIDTH_BTR_FREQ_CORR		11
+#define STB0899_BTR_CLR_LOCK			(0x01 << 3)
+#define STB0899_OFFST_BTR_CLR_LOCK		3
+#define STB0899_WIDTH_BTR_CLR_LOCK		1
+#define STB0899_BTR_SENSE			(0x01 << 2)
+#define STB0899_OFFST_BTR_SENSE			2
+#define STB0899_WIDTH_BTR_SENSE			1
+#define STB0899_BTR_ERR_ENA			(0x01 << 1)
+#define STB0899_OFFST_BTR_ERR_ENA		1
+#define STB0899_WIDTH_BTR_ERR_ENA		1
+#define STB0899_INTRP_PHS_SENSE			(0x01 << 0)
+#define STB0899_OFFST_INTRP_PHS_SENSE		0
+#define STB0899_WIDTH_INTRP_PHS_SENSE		1
+
+#define STB0899_OFF0_BTR_LOOP_GAIN		0xf350
+#define STB0899_BASE_BTR_LOOP_GAIN		0x00000000
+#define STB0899_KBTR2_RSHFT			(0x0f << 16)
+#define STB0899_OFFST_KBTR2_RSHFT		16
+#define STB0899_WIDTH_KBTR2_RSHFT		4
+#define STB0899_KBTR1				(0x0f << 12)
+#define STB0899_OFFST_KBTR1			12
+#define STB0899_WIDTH_KBTR1			4
+#define STB0899_KBTR1_RSHFT			(0x0f << 8)
+#define STB0899_OFFST_KBTR1_RSHFT		8
+#define STB0899_WIDTH_KBTR1_RSHFT		4
+#define STB0899_KBTR0				(0x0f << 4)
+#define STB0899_OFFST_KBTR0			4
+#define STB0899_WIDTH_KBTR0			4
+#define STB0899_KBTR0_RSHFT			(0x0f << 0)
+#define STB0899_OFFST_KBTR0_RSHFT		0
+#define STB0899_WIDTH_KBTR0_RSHFT		4
+
+#define STB0899_OFF0_BTR_PHS_INIT		0xf354
+#define STB0899_BASE_BTR_PHS_INIT		0x00000000
+#define STB0899_BTR_LD_PHASE_INIT		(0x01 << 28)
+#define STB0899_OFFST_BTR_LD_PHASE_INIT		28
+#define STB0899_WIDTH_BTR_LD_PHASE_INIT		1
+#define STB0899_BTR_INIT_PHASE			(0xfffffff << 0)
+#define STB0899_OFFST_BTR_INIT_PHASE		0
+#define STB0899_WIDTH_BTR_INIT_PHASE		28
+
+#define STB0899_OFF0_BTR_FREQ_INIT		0xf358
+#define STB0899_BASE_BTR_FREQ_INIT		0x00000000
+#define STB0899_BTR_LD_FREQ_INIT		(1 << 28)
+#define STB0899_OFFST_BTR_LD_FREQ_INIT		28
+#define STB0899_WIDTH_BTR_LD_FREQ_INIT		1
+#define STB0899_BTR_FREQ_INIT			(0xfffffff << 0)
+#define STB0899_OFFST_BTR_FREQ_INIT		0
+#define STB0899_WIDTH_BTR_FREQ_INIT		28
+
+#define STB0899_OFF0_BTR_NOM_FREQ		0xf35c
+#define STB0899_BASE_BTR_NOM_FREQ		0x00000000
+#define STB0899_BTR_NOM_FREQ			(0xfffffff << 0)
+#define STB0899_OFFST_BTR_NOM_FREQ		0
+#define STB0899_WIDTH_BTR_NOM_FREQ		28
+
+#define STB0899_OFF0_BTR_LK_CNTRL		0xf360
+#define STB0899_BASE_BTR_LK_CNTRL		0x00000000
+#define STB0899_BTR_MIN_ENERGY			(0x0f << 24)
+#define STB0899_OFFST_BTR_MIN_ENERGY		24
+#define STB0899_WIDTH_BTR_MIN_ENERGY		4
+#define STB0899_BTR_LOCK_TH_LO			(0xff << 16)
+#define STB0899_OFFST_BTR_LOCK_TH_LO		16
+#define STB0899_WIDTH_BTR_LOCK_TH_LO		8
+#define STB0899_BTR_LOCK_TH_HI			(0xff << 8)
+#define STB0899_OFFST_BTR_LOCK_TH_HI		8
+#define STB0899_WIDTH_BTR_LOCK_TH_HI		8
+#define STB0899_BTR_LOCK_GAIN			(0x03 << 6)
+#define STB0899_OFFST_BTR_LOCK_GAIN		6
+#define STB0899_WIDTH_BTR_LOCK_GAIN		2
+#define STB0899_BTR_LOCK_LEAK			(0x3f << 0)
+#define STB0899_OFFST_BTR_LOCK_LEAK		0
+#define STB0899_WIDTH_BTR_LOCK_LEAK		6
+
+#define STB0899_OFF0_DECN_CNTRL			0xf364
+#define STB0899_BASE_DECN_CNTRL			0x00000000
+
+#define STB0899_OFF0_TP_CNTRL			0xf368
+#define STB0899_BASE_TP_CNTRL			0x00000000
+
+#define STB0899_OFF0_TP_BUF_STATUS		0xf36c
+#define STB0899_BASE_TP_BUF_STATUS		0x00000000
+#define STB0899_TP_BUFFER_FULL                  (1 << 0)
+
+#define STB0899_OFF0_DC_ESTIM			0xf37c
+#define STB0899_BASE_DC_ESTIM			0x0000
+#define STB0899_I_DC_ESTIMATE			(0xff << 8)
+#define STB0899_OFFST_I_DC_ESTIMATE		8
+#define STB0899_WIDTH_I_DC_ESTIMATE		8
+#define STB0899_Q_DC_ESTIMATE			(0xff << 0)
+#define STB0899_OFFST_Q_DC_ESTIMATE		0
+#define STB0899_WIDTH_Q_DC_ESTIMATE		8
+
+#define STB0899_OFF0_FLL_CNTRL			0xf310
+#define STB0899_BASE_FLL_CNTRL			0x00000020
+#define STB0899_CRL_FLL_ACC			(0x01 << 4)
+#define STB0899_OFFST_CRL_FLL_ACC		4
+#define STB0899_WIDTH_CRL_FLL_ACC		1
+#define STB0899_FLL_AVG_PERIOD			(0x0f << 0)
+#define STB0899_OFFST_FLL_AVG_PERIOD		0
+#define STB0899_WIDTH_FLL_AVG_PERIOD		4
+
+#define STB0899_OFF0_FLL_FREQ_WD		0xf314
+#define STB0899_BASE_FLL_FREQ_WD		0x00000020
+#define STB0899_FLL_FREQ_WD			(0xffffffff << 0)
+#define STB0899_OFFST_FLL_FREQ_WD		0
+#define STB0899_WIDTH_FLL_FREQ_WD		32
+
+#define STB0899_OFF0_ANTI_ALIAS_SEL		0xf358
+#define STB0899_BASE_ANTI_ALIAS_SEL		0x00000020
+#define STB0899_ANTI_ALIAS_SELB			(0x03 << 0)
+#define STB0899_OFFST_ANTI_ALIAS_SELB		0
+#define STB0899_WIDTH_ANTI_ALIAS_SELB		2
+
+#define STB0899_OFF0_RRC_ALPHA			0xf35c
+#define STB0899_BASE_RRC_ALPHA			0x00000020
+#define STB0899_RRC_ALPHA			(0x03 << 0)
+#define STB0899_OFFST_RRC_ALPHA			0
+#define STB0899_WIDTH_RRC_ALPHA			2
+
+#define STB0899_OFF0_DC_ADAPT_LSHFT		0xf360
+#define STB0899_BASE_DC_ADAPT_LSHFT		0x00000020
+#define STB0899_DC_ADAPT_LSHFT			(0x077 << 0)
+#define STB0899_OFFST_DC_ADAPT_LSHFT		0
+#define STB0899_WIDTH_DC_ADAPT_LSHFT		3
+
+#define STB0899_OFF0_IMB_OFFSET			0xf364
+#define STB0899_BASE_IMB_OFFSET			0x00000020
+#define STB0899_PHS_IMB_COMP			(0xff << 8)
+#define STB0899_OFFST_PHS_IMB_COMP		8
+#define STB0899_WIDTH_PHS_IMB_COMP		8
+#define STB0899_AMPL_IMB_COMP			(0xff << 0)
+#define STB0899_OFFST_AMPL_IMB_COMP		0
+#define STB0899_WIDTH_AMPL_IMB_COMP		8
+
+#define STB0899_OFF0_IMB_ESTIMATE		0xf368
+#define STB0899_BASE_IMB_ESTIMATE		0x00000020
+#define STB0899_PHS_IMB_ESTIMATE		(0xff << 8)
+#define STB0899_OFFST_PHS_IMB_ESTIMATE		8
+#define STB0899_WIDTH_PHS_IMB_ESTIMATE		8
+#define STB0899_AMPL_IMB_ESTIMATE		(0xff << 0)
+#define STB0899_OFFST_AMPL_IMB_ESTIMATE		0
+#define STB0899_WIDTH_AMPL_IMB_ESTIMATE		8
+
+#define STB0899_OFF0_IMB_CNTRL			0xf36c
+#define STB0899_BASE_IMB_CNTRL			0x00000020
+#define STB0899_PHS_ADAPT_LSHFT			(0x07 << 4)
+#define STB0899_OFFST_PHS_ADAPT_LSHFT		4
+#define STB0899_WIDTH_PHS_ADAPT_LSHFT		3
+#define STB0899_AMPL_ADAPT_LSHFT		(0x07 << 1)
+#define STB0899_OFFST_AMPL_ADAPT_LSHFT		1
+#define STB0899_WIDTH_AMPL_ADAPT_LSHFT		3
+#define STB0899_IMB_COMP			(0x01 << 0)
+#define STB0899_OFFST_IMB_COMP			0
+#define STB0899_WIDTH_IMB_COMP			1
+
+#define STB0899_OFF0_IF_AGC_CNTRL2		0xf374
+#define STB0899_BASE_IF_AGC_CNTRL2		0x00000020
+#define STB0899_IF_AGC_LOCK_TH			(0xff << 11)
+#define STB0899_OFFST_IF_AGC_LOCK_TH		11
+#define STB0899_WIDTH_IF_AGC_LOCK_TH		8
+#define STB0899_IF_AGC_SD_DIV			(0xff << 3)
+#define STB0899_OFFST_IF_AGC_SD_DIV		3
+#define STB0899_WIDTH_IF_AGC_SD_DIV		8
+#define STB0899_IF_AGC_DUMP_PER			(0x07 << 0)
+#define STB0899_OFFST_IF_AGC_DUMP_PER		0
+#define STB0899_WIDTH_IF_AGC_DUMP_PER		3
+
+#define STB0899_OFF0_DMD_CNTRL2			0xf378
+#define STB0899_BASE_DMD_CNTRL2			0x00000020
+#define STB0899_SPECTRUM_INVERT			(0x01 << 2)
+#define STB0899_OFFST_SPECTRUM_INVERT		2
+#define STB0899_WIDTH_SPECTRUM_INVERT		1
+#define STB0899_AGC_MODE			(0x01 << 1)
+#define STB0899_OFFST_AGC_MODE			1
+#define STB0899_WIDTH_AGC_MODE			1
+#define STB0899_CRL_FREQ_ADJ			(0x01 << 0)
+#define STB0899_OFFST_CRL_FREQ_ADJ		0
+#define STB0899_WIDTH_CRL_FREQ_ADJ		1
+
+#define STB0899_OFF0_TP_BUFFER			0xf300
+#define STB0899_BASE_TP_BUFFER			0x00000040
+#define STB0899_TP_BUFFER_IN			(0xffff << 0)
+#define STB0899_OFFST_TP_BUFFER_IN		0
+#define STB0899_WIDTH_TP_BUFFER_IN		16
+
+#define STB0899_OFF0_TP_BUFFER1			0xf304
+#define STB0899_BASE_TP_BUFFER1			0x00000040
+#define STB0899_OFF0_TP_BUFFER2			0xf308
+#define STB0899_BASE_TP_BUFFER2			0x00000040
+#define STB0899_OFF0_TP_BUFFER3			0xf30c
+#define STB0899_BASE_TP_BUFFER3			0x00000040
+#define STB0899_OFF0_TP_BUFFER4			0xf310
+#define STB0899_BASE_TP_BUFFER4			0x00000040
+#define STB0899_OFF0_TP_BUFFER5			0xf314
+#define STB0899_BASE_TP_BUFFER5			0x00000040
+#define STB0899_OFF0_TP_BUFFER6			0xf318
+#define STB0899_BASE_TP_BUFFER6			0x00000040
+#define STB0899_OFF0_TP_BUFFER7			0xf31c
+#define STB0899_BASE_TP_BUFFER7			0x00000040
+#define STB0899_OFF0_TP_BUFFER8			0xf320
+#define STB0899_BASE_TP_BUFFER8			0x00000040
+#define STB0899_OFF0_TP_BUFFER9			0xf324
+#define STB0899_BASE_TP_BUFFER9			0x00000040
+#define STB0899_OFF0_TP_BUFFER10		0xf328
+#define STB0899_BASE_TP_BUFFER10		0x00000040
+#define STB0899_OFF0_TP_BUFFER11		0xf32c
+#define STB0899_BASE_TP_BUFFER11		0x00000040
+#define STB0899_OFF0_TP_BUFFER12		0xf330
+#define STB0899_BASE_TP_BUFFER12		0x00000040
+#define STB0899_OFF0_TP_BUFFER13		0xf334
+#define STB0899_BASE_TP_BUFFER13		0x00000040
+#define STB0899_OFF0_TP_BUFFER14		0xf338
+#define STB0899_BASE_TP_BUFFER14		0x00000040
+#define STB0899_OFF0_TP_BUFFER15		0xf33c
+#define STB0899_BASE_TP_BUFFER15		0x00000040
+#define STB0899_OFF0_TP_BUFFER16		0xf340
+#define STB0899_BASE_TP_BUFFER16		0x00000040
+#define STB0899_OFF0_TP_BUFFER17		0xf344
+#define STB0899_BASE_TP_BUFFER17		0x00000040
+#define STB0899_OFF0_TP_BUFFER18		0xf348
+#define STB0899_BASE_TP_BUFFER18		0x00000040
+#define STB0899_OFF0_TP_BUFFER19		0xf34c
+#define STB0899_BASE_TP_BUFFER19		0x00000040
+#define STB0899_OFF0_TP_BUFFER20		0xf350
+#define STB0899_BASE_TP_BUFFER20		0x00000040
+#define STB0899_OFF0_TP_BUFFER21		0xf354
+#define STB0899_BASE_TP_BUFFER21		0x00000040
+#define STB0899_OFF0_TP_BUFFER22		0xf358
+#define STB0899_BASE_TP_BUFFER22		0x00000040
+#define STB0899_OFF0_TP_BUFFER23		0xf35c
+#define STB0899_BASE_TP_BUFFER23		0x00000040
+#define STB0899_OFF0_TP_BUFFER24		0xf360
+#define STB0899_BASE_TP_BUFFER24		0x00000040
+#define STB0899_OFF0_TP_BUFFER25		0xf364
+#define STB0899_BASE_TP_BUFFER25		0x00000040
+#define STB0899_OFF0_TP_BUFFER26		0xf368
+#define STB0899_BASE_TP_BUFFER26		0x00000040
+#define STB0899_OFF0_TP_BUFFER27		0xf36c
+#define STB0899_BASE_TP_BUFFER27		0x00000040
+#define STB0899_OFF0_TP_BUFFER28		0xf370
+#define STB0899_BASE_TP_BUFFER28		0x00000040
+#define STB0899_OFF0_TP_BUFFER29		0xf374
+#define STB0899_BASE_TP_BUFFER29		0x00000040
+#define STB0899_OFF0_TP_BUFFER30		0xf378
+#define STB0899_BASE_TP_BUFFER30		0x00000040
+#define STB0899_OFF0_TP_BUFFER31		0xf37c
+#define STB0899_BASE_TP_BUFFER31		0x00000040
+#define STB0899_OFF0_TP_BUFFER32		0xf300
+#define STB0899_BASE_TP_BUFFER32		0x00000060
+#define STB0899_OFF0_TP_BUFFER33		0xf304
+#define STB0899_BASE_TP_BUFFER33		0x00000060
+#define STB0899_OFF0_TP_BUFFER34		0xf308
+#define STB0899_BASE_TP_BUFFER34		0x00000060
+#define STB0899_OFF0_TP_BUFFER35		0xf30c
+#define STB0899_BASE_TP_BUFFER35		0x00000060
+#define STB0899_OFF0_TP_BUFFER36		0xf310
+#define STB0899_BASE_TP_BUFFER36		0x00000060
+#define STB0899_OFF0_TP_BUFFER37		0xf314
+#define STB0899_BASE_TP_BUFFER37		0x00000060
+#define STB0899_OFF0_TP_BUFFER38		0xf318
+#define STB0899_BASE_TP_BUFFER38		0x00000060
+#define STB0899_OFF0_TP_BUFFER39		0xf31c
+#define STB0899_BASE_TP_BUFFER39		0x00000060
+#define STB0899_OFF0_TP_BUFFER40		0xf320
+#define STB0899_BASE_TP_BUFFER40		0x00000060
+#define STB0899_OFF0_TP_BUFFER41		0xf324
+#define STB0899_BASE_TP_BUFFER41		0x00000060
+#define STB0899_OFF0_TP_BUFFER42		0xf328
+#define STB0899_BASE_TP_BUFFER42		0x00000060
+#define STB0899_OFF0_TP_BUFFER43		0xf32c
+#define STB0899_BASE_TP_BUFFER43		0x00000060
+#define STB0899_OFF0_TP_BUFFER44		0xf330
+#define STB0899_BASE_TP_BUFFER44		0x00000060
+#define STB0899_OFF0_TP_BUFFER45		0xf334
+#define STB0899_BASE_TP_BUFFER45		0x00000060
+#define STB0899_OFF0_TP_BUFFER46		0xf338
+#define STB0899_BASE_TP_BUFFER46		0x00000060
+#define STB0899_OFF0_TP_BUFFER47		0xf33c
+#define STB0899_BASE_TP_BUFFER47		0x00000060
+#define STB0899_OFF0_TP_BUFFER48		0xf340
+#define STB0899_BASE_TP_BUFFER48		0x00000060
+#define STB0899_OFF0_TP_BUFFER49		0xf344
+#define STB0899_BASE_TP_BUFFER49		0x00000060
+#define STB0899_OFF0_TP_BUFFER50		0xf348
+#define STB0899_BASE_TP_BUFFER50		0x00000060
+#define STB0899_OFF0_TP_BUFFER51		0xf34c
+#define STB0899_BASE_TP_BUFFER51		0x00000060
+#define STB0899_OFF0_TP_BUFFER52		0xf350
+#define STB0899_BASE_TP_BUFFER52		0x00000060
+#define STB0899_OFF0_TP_BUFFER53		0xf354
+#define STB0899_BASE_TP_BUFFER53		0x00000060
+#define STB0899_OFF0_TP_BUFFER54		0xf358
+#define STB0899_BASE_TP_BUFFER54		0x00000060
+#define STB0899_OFF0_TP_BUFFER55		0xf35c
+#define STB0899_BASE_TP_BUFFER55		0x00000060
+#define STB0899_OFF0_TP_BUFFER56		0xf360
+#define STB0899_BASE_TP_BUFFER56		0x00000060
+#define STB0899_OFF0_TP_BUFFER57		0xf364
+#define STB0899_BASE_TP_BUFFER57		0x00000060
+#define STB0899_OFF0_TP_BUFFER58		0xf368
+#define STB0899_BASE_TP_BUFFER58		0x00000060
+#define STB0899_OFF0_TP_BUFFER59		0xf36c
+#define STB0899_BASE_TP_BUFFER59		0x00000060
+#define STB0899_OFF0_TP_BUFFER60		0xf370
+#define STB0899_BASE_TP_BUFFER60		0x00000060
+#define STB0899_OFF0_TP_BUFFER61		0xf374
+#define STB0899_BASE_TP_BUFFER61		0x00000060
+#define STB0899_OFF0_TP_BUFFER62		0xf378
+#define STB0899_BASE_TP_BUFFER62		0x00000060
+#define STB0899_OFF0_TP_BUFFER63		0xf37c
+#define STB0899_BASE_TP_BUFFER63		0x00000060
+
+#define STB0899_OFF0_RESET_CNTRL		0xf300
+#define STB0899_BASE_RESET_CNTRL		0x00000400
+#define STB0899_DVBS2_RESET			(0x01 << 0)
+#define STB0899_OFFST_DVBS2_RESET		0
+#define STB0899_WIDTH_DVBS2_RESET		1
+
+#define STB0899_OFF0_ACM_ENABLE			0xf304
+#define STB0899_BASE_ACM_ENABLE			0x00000400
+#define STB0899_ACM_ENABLE			1
+
+#define STB0899_OFF0_DESCR_CNTRL		0xf30c
+#define STB0899_BASE_DESCR_CNTRL		0x00000400
+#define STB0899_OFFST_DESCR_CNTRL               0
+#define STB0899_WIDTH_DESCR_CNTRL               16
+
+#define STB0899_OFF0_UWP_CNTRL1			0xf320
+#define STB0899_BASE_UWP_CNTRL1			0x00000400
+#define STB0899_UWP_TH_SOF			(0x7fff << 11)
+#define STB0899_OFFST_UWP_TH_SOF		11
+#define STB0899_WIDTH_UWP_TH_SOF		15
+#define STB0899_UWP_ESN0_QUANT			(0xff << 3)
+#define STB0899_OFFST_UWP_ESN0_QUANT		3
+#define STB0899_WIDTH_UWP_ESN0_QUANT		8
+#define STB0899_UWP_ESN0_AVE			(0x03 << 1)
+#define STB0899_OFFST_UWP_ESN0_AVE		1
+#define STB0899_WIDTH_UWP_ESN0_AVE		2
+#define STB0899_UWP_START			(0x01 << 0)
+#define STB0899_OFFST_UWP_START			0
+#define STB0899_WIDTH_UWP_START			1
+
+#define STB0899_OFF0_UWP_CNTRL2			0xf324
+#define STB0899_BASE_UWP_CNTRL2			0x00000400
+#define STB0899_UWP_MISS_TH			(0xff << 16)
+#define STB0899_OFFST_UWP_MISS_TH		16
+#define STB0899_WIDTH_UWP_MISS_TH		8
+#define STB0899_FE_FINE_TRK			(0xff << 8)
+#define STB0899_OFFST_FE_FINE_TRK		8
+#define STB0899_WIDTH_FE_FINE_TRK		8
+#define STB0899_FE_COARSE_TRK			(0xff << 0)
+#define STB0899_OFFST_FE_COARSE_TRK		0
+#define STB0899_WIDTH_FE_COARSE_TRK		8
+
+#define STB0899_OFF0_UWP_STAT1			0xf328
+#define STB0899_BASE_UWP_STAT1			0x00000400
+#define STB0899_UWP_STATE			(0x03ff << 15)
+#define STB0899_OFFST_UWP_STATE			15
+#define STB0899_WIDTH_UWP_STATE			10
+#define STB0899_UW_MAX_PEAK			(0x7fff << 0)
+#define STB0899_OFFST_UW_MAX_PEAK		0
+#define STB0899_WIDTH_UW_MAX_PEAK		15
+
+#define STB0899_OFF0_UWP_STAT2			0xf32c
+#define STB0899_BASE_UWP_STAT2			0x00000400
+#define STB0899_ESNO_EST			(0x07ffff << 7)
+#define STB0899_OFFST_ESN0_EST			7
+#define STB0899_WIDTH_ESN0_EST			19
+#define STB0899_UWP_DECODE_MOD			(0x7f << 0)
+#define STB0899_OFFST_UWP_DECODE_MOD		0
+#define STB0899_WIDTH_UWP_DECODE_MOD		7
+
+#define STB0899_OFF0_DMD_CORE_ID		0xf334
+#define STB0899_BASE_DMD_CORE_ID		0x00000400
+#define STB0899_CORE_ID				(0xffffffff << 0)
+#define STB0899_OFFST_CORE_ID			0
+#define STB0899_WIDTH_CORE_ID			32
+
+#define STB0899_OFF0_DMD_VERSION_ID		0xf33c
+#define STB0899_BASE_DMD_VERSION_ID		0x00000400
+#define STB0899_VERSION_ID			(0xff << 0)
+#define STB0899_OFFST_VERSION_ID		0
+#define STB0899_WIDTH_VERSION_ID		8
+
+#define STB0899_OFF0_DMD_STAT2			0xf340
+#define STB0899_BASE_DMD_STAT2			0x00000400
+#define STB0899_CSM_LOCK			(0x01 << 1)
+#define STB0899_OFFST_CSM_LOCK			1
+#define STB0899_WIDTH_CSM_LOCK			1
+#define STB0899_UWP_LOCK			(0x01 << 0)
+#define STB0899_OFFST_UWP_LOCK			0
+#define STB0899_WIDTH_UWP_LOCK			1
+
+#define STB0899_OFF0_FREQ_ADJ_SCALE		0xf344
+#define STB0899_BASE_FREQ_ADJ_SCALE		0x00000400
+#define STB0899_FREQ_ADJ_SCALE			(0x0fff << 0)
+#define STB0899_OFFST_FREQ_ADJ_SCALE		0
+#define STB0899_WIDTH_FREQ_ADJ_SCALE		12
+
+#define STB0899_OFF0_UWP_CNTRL3			0xf34c
+#define STB0899_BASE_UWP_CNTRL3			0x00000400
+#define STB0899_UWP_TH_TRACK			(0x7fff << 15)
+#define STB0899_OFFST_UWP_TH_TRACK		15
+#define STB0899_WIDTH_UWP_TH_TRACK		15
+#define STB0899_UWP_TH_ACQ			(0x7fff << 0)
+#define STB0899_OFFST_UWP_TH_ACQ		0
+#define STB0899_WIDTH_UWP_TH_ACQ		15
+
+#define STB0899_OFF0_SYM_CLK_SEL		0xf350
+#define STB0899_BASE_SYM_CLK_SEL		0x00000400
+#define STB0899_SYM_CLK_SEL			(0x03 << 0)
+#define STB0899_OFFST_SYM_CLK_SEL		0
+#define STB0899_WIDTH_SYM_CLK_SEL		2
+
+#define STB0899_OFF0_SOF_SRCH_TO		0xf354
+#define STB0899_BASE_SOF_SRCH_TO		0x00000400
+#define STB0899_SOF_SEARCH_TIMEOUT		(0x3fffff << 0)
+#define STB0899_OFFST_SOF_SEARCH_TIMEOUT	0
+#define STB0899_WIDTH_SOF_SEARCH_TIMEOUT	22
+
+#define STB0899_OFF0_ACQ_CNTRL1			0xf358
+#define STB0899_BASE_ACQ_CNTRL1			0x00000400
+#define STB0899_FE_FINE_ACQ			(0xff << 8)
+#define STB0899_OFFST_FE_FINE_ACQ		8
+#define STB0899_WIDTH_FE_FINE_ACQ		8
+#define STB0899_FE_COARSE_ACQ			(0xff << 0)
+#define STB0899_OFFST_FE_COARSE_ACQ		0
+#define STB0899_WIDTH_FE_COARSE_ACQ		8
+
+#define STB0899_OFF0_ACQ_CNTRL2			0xf35c
+#define STB0899_BASE_ACQ_CNTRL2			0x00000400
+#define STB0899_ZIGZAG				(0x01 << 25)
+#define STB0899_OFFST_ZIGZAG			25
+#define STB0899_WIDTH_ZIGZAG			1
+#define STB0899_NUM_STEPS			(0xff << 17)
+#define STB0899_OFFST_NUM_STEPS			17
+#define STB0899_WIDTH_NUM_STEPS			8
+#define STB0899_FREQ_STEPSIZE			(0x1ffff << 0)
+#define STB0899_OFFST_FREQ_STEPSIZE		0
+#define STB0899_WIDTH_FREQ_STEPSIZE		17
+
+#define STB0899_OFF0_ACQ_CNTRL3			0xf360
+#define STB0899_BASE_ACQ_CNTRL3			0x00000400
+#define STB0899_THRESHOLD_SCL			(0x3f << 23)
+#define STB0899_OFFST_THRESHOLD_SCL		23
+#define STB0899_WIDTH_THRESHOLD_SCL		6
+#define STB0899_UWP_TH_SRCH			(0x7fff << 8)
+#define STB0899_OFFST_UWP_TH_SRCH		8
+#define STB0899_WIDTH_UWP_TH_SRCH		15
+#define STB0899_AUTO_REACQUIRE			(0x01 << 7)
+#define STB0899_OFFST_AUTO_REACQUIRE		7
+#define STB0899_WIDTH_AUTO_REACQUIRE		1
+#define STB0899_TRACK_LOCK_SEL			(0x01 << 6)
+#define STB0899_OFFST_TRACK_LOCK_SEL		6
+#define STB0899_WIDTH_TRACK_LOCK_SEL		1
+#define STB0899_ACQ_SEARCH_MODE			(0x03 << 4)
+#define STB0899_OFFST_ACQ_SEARCH_MODE		4
+#define STB0899_WIDTH_ACQ_SEARCH_MODE		2
+#define STB0899_CONFIRM_FRAMES			(0x0f << 0)
+#define STB0899_OFFST_CONFIRM_FRAMES		0
+#define STB0899_WIDTH_CONFIRM_FRAMES		4
+
+#define STB0899_OFF0_FE_SETTLE			0xf364
+#define STB0899_BASE_FE_SETTLE			0x00000400
+#define STB0899_SETTLING_TIME			(0x3fffff << 0)
+#define STB0899_OFFST_SETTLING_TIME		0
+#define STB0899_WIDTH_SETTLING_TIME		22
+
+#define STB0899_OFF0_AC_DWELL			0xf368
+#define STB0899_BASE_AC_DWELL			0x00000400
+#define STB0899_DWELL_TIME			(0x3fffff << 0)
+#define STB0899_OFFST_DWELL_TIME		0
+#define STB0899_WIDTH_DWELL_TIME		22
+
+#define STB0899_OFF0_ACQUIRE_TRIG		0xf36c
+#define STB0899_BASE_ACQUIRE_TRIG		0x00000400
+#define STB0899_ACQUIRE				(0x01 << 0)
+#define STB0899_OFFST_ACQUIRE			0
+#define STB0899_WIDTH_ACQUIRE			1
+
+#define STB0899_OFF0_LOCK_LOST			0xf370
+#define STB0899_BASE_LOCK_LOST			0x00000400
+#define STB0899_LOCK_LOST			(0x01 << 0)
+#define STB0899_OFFST_LOCK_LOST			0
+#define STB0899_WIDTH_LOCK_LOST			1
+
+#define STB0899_OFF0_ACQ_STAT1			0xf374
+#define STB0899_BASE_ACQ_STAT1			0x00000400
+#define STB0899_STEP_FREQ			(0x1fffff << 11)
+#define STB0899_OFFST_STEP_FREQ			11
+#define STB0899_WIDTH_STEP_FREQ			21
+#define STB0899_ACQ_STATE			(0x07 << 8)
+#define STB0899_OFFST_ACQ_STATE			8
+#define STB0899_WIDTH_ACQ_STATE			3
+#define STB0899_UW_DETECT_COUNT			(0xff << 0)
+#define STB0899_OFFST_UW_DETECT_COUNT		0
+#define STB0899_WIDTH_UW_DETECT_COUNT		8
+
+#define STB0899_OFF0_ACQ_TIMEOUT		0xf378
+#define STB0899_BASE_ACQ_TIMEOUT		0x00000400
+#define STB0899_ACQ_TIMEOUT			(0x3fffff << 0)
+#define STB0899_OFFST_ACQ_TIMEOUT		0
+#define STB0899_WIDTH_ACQ_TIMEOUT		22
+
+#define STB0899_OFF0_ACQ_TIME			0xf37c
+#define STB0899_BASE_ACQ_TIME			0x00000400
+#define STB0899_ACQ_TIME_SYM			(0xffffff << 0)
+#define STB0899_OFFST_ACQ_TIME_SYM		0
+#define STB0899_WIDTH_ACQ_TIME_SYM		24
+
+#define STB0899_OFF0_FINAL_AGC_CNTRL		0xf308
+#define STB0899_BASE_FINAL_AGC_CNTRL		0x00000440
+#define STB0899_FINAL_GAIN_INIT			(0x3fff << 12)
+#define STB0899_OFFST_FINAL_GAIN_INIT		12
+#define STB0899_WIDTH_FINAL_GAIN_INIT		14
+#define STB0899_FINAL_LOOP_GAIN			(0x0f << 8)
+#define STB0899_OFFST_FINAL_LOOP_GAIN		8
+#define STB0899_WIDTH_FINAL_LOOP_GAIN		4
+#define STB0899_FINAL_LD_GAIN_INIT		(0x01 << 7)
+#define STB0899_OFFST_FINAL_LD_GAIN_INIT	7
+#define STB0899_WIDTH_FINAL_LD_GAIN_INIT	1
+#define STB0899_FINAL_AGC_REF			(0x7f << 0)
+#define STB0899_OFFST_FINAL_AGC_REF		0
+#define STB0899_WIDTH_FINAL_AGC_REF		7
+
+#define STB0899_OFF0_FINAL_AGC_GAIN		0xf30c
+#define STB0899_BASE_FINAL_AGC_GAIN		0x00000440
+#define STB0899_FINAL_AGC_GAIN			(0x3fff << 0)
+#define STB0899_OFFST_FINAL_AGC_GAIN		0
+#define STB0899_WIDTH_FINAL_AGC_GAIN		14
+
+#define STB0899_OFF0_EQUALIZER_INIT		0xf310
+#define STB0899_BASE_EQUALIZER_INIT		0x00000440
+#define STB0899_EQ_SRST				(0x01 << 1)
+#define STB0899_OFFST_EQ_SRST			1
+#define STB0899_WIDTH_EQ_SRST			1
+#define STB0899_EQ_INIT				(0x01 << 0)
+#define STB0899_OFFST_EQ_INIT			0
+#define STB0899_WIDTH_EQ_INIT			1
+
+#define STB0899_OFF0_EQ_CNTRL			0xf314
+#define STB0899_BASE_EQ_CNTRL			0x00000440
+#define STB0899_EQ_ADAPT_MODE			(0x01 << 18)
+#define STB0899_OFFST_EQ_ADAPT_MODE		18
+#define STB0899_WIDTH_EQ_ADAPT_MODE		1
+#define STB0899_EQ_DELAY			(0x0f << 14)
+#define STB0899_OFFST_EQ_DELAY			14
+#define STB0899_WIDTH_EQ_DELAY			4
+#define STB0899_EQ_QUANT_LEVEL			(0xff << 6)
+#define STB0899_OFFST_EQ_QUANT_LEVEL		6
+#define STB0899_WIDTH_EQ_QUANT_LEVEL		8
+#define STB0899_EQ_DISABLE_UPDATE		(0x01 << 5)
+#define STB0899_OFFST_EQ_DISABLE_UPDATE		5
+#define STB0899_WIDTH_EQ_DISABLE_UPDATE		1
+#define STB0899_EQ_BYPASS			(0x01 << 4)
+#define STB0899_OFFST_EQ_BYPASS			4
+#define STB0899_WIDTH_EQ_BYPASS			1
+#define STB0899_EQ_SHIFT			(0x0f << 0)
+#define STB0899_OFFST_EQ_SHIFT			0
+#define STB0899_WIDTH_EQ_SHIFT			4
+
+#define STB0899_OFF0_EQ_I_INIT_COEFF_0		0xf320
+#define STB0899_OFF1_EQ_I_INIT_COEFF_1		0xf324
+#define STB0899_OFF2_EQ_I_INIT_COEFF_2		0xf328
+#define STB0899_OFF3_EQ_I_INIT_COEFF_3		0xf32c
+#define STB0899_OFF4_EQ_I_INIT_COEFF_4		0xf330
+#define STB0899_OFF5_EQ_I_INIT_COEFF_5		0xf334
+#define STB0899_OFF6_EQ_I_INIT_COEFF_6		0xf338
+#define STB0899_OFF7_EQ_I_INIT_COEFF_7		0xf33c
+#define STB0899_OFF8_EQ_I_INIT_COEFF_8		0xf340
+#define STB0899_OFF9_EQ_I_INIT_COEFF_9		0xf344
+#define STB0899_OFFa_EQ_I_INIT_COEFF_10		0xf348
+#define STB0899_BASE_EQ_I_INIT_COEFF_N		0x00000440
+#define STB0899_EQ_I_INIT_COEFF_N		(0x0fff << 0)
+#define STB0899_OFFST_EQ_I_INIT_COEFF_N		0
+#define STB0899_WIDTH_EQ_I_INIT_COEFF_N		12
+
+#define STB0899_OFF0_EQ_Q_INIT_COEFF_0		0xf350
+#define STB0899_OFF1_EQ_Q_INIT_COEFF_1		0xf354
+#define STB0899_OFF2_EQ_Q_INIT_COEFF_2		0xf358
+#define STB0899_OFF3_EQ_Q_INIT_COEFF_3		0xf35c
+#define STB0899_OFF4_EQ_Q_INIT_COEFF_4		0xf360
+#define STB0899_OFF5_EQ_Q_INIT_COEFF_5		0xf364
+#define STB0899_OFF6_EQ_Q_INIT_COEFF_6		0xf368
+#define STB0899_OFF7_EQ_Q_INIT_COEFF_7		0xf36c
+#define STB0899_OFF8_EQ_Q_INIT_COEFF_8		0xf370
+#define STB0899_OFF9_EQ_Q_INIT_COEFF_9		0xf374
+#define STB0899_OFFa_EQ_Q_INIT_COEFF_10		0xf378
+#define STB0899_BASE_EQ_Q_INIT_COEFF_N		0x00000440
+#define STB0899_EQ_Q_INIT_COEFF_N		(0x0fff << 0)
+#define STB0899_OFFST_EQ_Q_INIT_COEFF_N		0
+#define STB0899_WIDTH_EQ_Q_INIT_COEFF_N		12
+
+#define STB0899_OFF0_EQ_I_OUT_COEFF_0		0xf300
+#define STB0899_OFF1_EQ_I_OUT_COEFF_1		0xf304
+#define STB0899_OFF2_EQ_I_OUT_COEFF_2		0xf308
+#define STB0899_OFF3_EQ_I_OUT_COEFF_3		0xf30c
+#define STB0899_OFF4_EQ_I_OUT_COEFF_4		0xf310
+#define STB0899_OFF5_EQ_I_OUT_COEFF_5		0xf314
+#define STB0899_OFF6_EQ_I_OUT_COEFF_6		0xf318
+#define STB0899_OFF7_EQ_I_OUT_COEFF_7		0xf31c
+#define STB0899_OFF8_EQ_I_OUT_COEFF_8		0xf320
+#define STB0899_OFF9_EQ_I_OUT_COEFF_9		0xf324
+#define STB0899_OFFa_EQ_I_OUT_COEFF_10		0xf328
+#define STB0899_BASE_EQ_I_OUT_COEFF_N		0x00000460
+#define STB0899_EQ_I_OUT_COEFF_N		(0x0fff << 0)
+#define STB0899_OFFST_EQ_I_OUT_COEFF_N		0
+#define STB0899_WIDTH_EQ_I_OUT_COEFF_N		12
+
+#define STB0899_OFF0_EQ_Q_OUT_COEFF_0		0xf330
+#define STB0899_OFF1_EQ_Q_OUT_COEFF_1		0xf334
+#define STB0899_OFF2_EQ_Q_OUT_COEFF_2		0xf338
+#define STB0899_OFF3_EQ_Q_OUT_COEFF_3		0xf33c
+#define STB0899_OFF4_EQ_Q_OUT_COEFF_4		0xf340
+#define STB0899_OFF5_EQ_Q_OUT_COEFF_5		0xf344
+#define STB0899_OFF6_EQ_Q_OUT_COEFF_6		0xf348
+#define STB0899_OFF7_EQ_Q_OUT_COEFF_7		0xf34c
+#define STB0899_OFF8_EQ_Q_OUT_COEFF_8		0xf350
+#define STB0899_OFF9_EQ_Q_OUT_COEFF_9		0xf354
+#define STB0899_OFFa_EQ_Q_OUT_COEFF_10		0xf358
+#define STB0899_BASE_EQ_Q_OUT_COEFF_N		0x00000460
+#define STB0899_EQ_Q_OUT_COEFF_N		(0x0fff << 0)
+#define STB0899_OFFST_EQ_Q_OUT_COEFF_N		0
+#define STB0899_WIDTH_EQ_Q_OUT_COEFF_N		12
+
+/*	S2 FEC	*/
+#define STB0899_OFF0_BLOCK_LNGTH		0xfa04
+#define STB0899_BASE_BLOCK_LNGTH		0x00000000
+#define STB0899_BLOCK_LENGTH			(0xff << 0)
+#define STB0899_OFFST_BLOCK_LENGTH		0
+#define STB0899_WIDTH_BLOCK_LENGTH		8
+
+#define STB0899_OFF0_ROW_STR			0xfa08
+#define STB0899_BASE_ROW_STR			0x00000000
+#define STB0899_ROW_STRIDE			(0xff << 0)
+#define STB0899_OFFST_ROW_STRIDE		0
+#define STB0899_WIDTH_ROW_STRIDE		8
+
+#define STB0899_OFF0_MAX_ITER			0xfa0c
+#define STB0899_BASE_MAX_ITER			0x00000000
+#define STB0899_MAX_ITERATIONS			(0xff << 0)
+#define STB0899_OFFST_MAX_ITERATIONS		0
+#define STB0899_WIDTH_MAX_ITERATIONS		8
+
+#define STB0899_OFF0_BN_END_ADDR		0xfa10
+#define STB0899_BASE_BN_END_ADDR		0x00000000
+#define STB0899_BN_END_ADDR			(0x0fff << 0)
+#define STB0899_OFFST_BN_END_ADDR		0
+#define STB0899_WIDTH_BN_END_ADDR		12
+
+#define STB0899_OFF0_CN_END_ADDR		0xfa14
+#define STB0899_BASE_CN_END_ADDR		0x00000000
+#define STB0899_CN_END_ADDR			(0x0fff << 0)
+#define STB0899_OFFST_CN_END_ADDR		0
+#define STB0899_WIDTH_CN_END_ADDR		12
+
+#define STB0899_OFF0_INFO_LENGTH		0xfa1c
+#define STB0899_BASE_INFO_LENGTH		0x00000000
+#define STB0899_INFO_LENGTH			(0xff << 0)
+#define STB0899_OFFST_INFO_LENGTH		0
+#define STB0899_WIDTH_INFO_LENGTH		8
+
+#define STB0899_OFF0_BOT_ADDR			0xfa20
+#define STB0899_BASE_BOT_ADDR			0x00000000
+#define STB0899_BOTTOM_BASE_ADDR		(0x03ff << 0)
+#define STB0899_OFFST_BOTTOM_BASE_ADDR		0
+#define STB0899_WIDTH_BOTTOM_BASE_ADDR		10
+
+#define STB0899_OFF0_BCH_BLK_LN			0xfa24
+#define STB0899_BASE_BCH_BLK_LN			0x00000000
+#define STB0899_BCH_BLOCK_LENGTH		(0xffff << 0)
+#define STB0899_OFFST_BCH_BLOCK_LENGTH		0
+#define STB0899_WIDTH_BCH_BLOCK_LENGTH		16
+
+#define STB0899_OFF0_BCH_T			0xfa28
+#define STB0899_BASE_BCH_T			0x00000000
+#define STB0899_BCH_T				(0x0f << 0)
+#define STB0899_OFFST_BCH_T			0
+#define STB0899_WIDTH_BCH_T			4
+
+#define STB0899_OFF0_CNFG_MODE			0xfa00
+#define STB0899_BASE_CNFG_MODE			0x00000800
+#define STB0899_MODCOD				(0x1f << 2)
+#define STB0899_OFFST_MODCOD			2
+#define STB0899_WIDTH_MODCOD			5
+#define STB0899_MODCOD_SEL			(0x01 << 1)
+#define STB0899_OFFST_MODCOD_SEL		1
+#define STB0899_WIDTH_MODCOD_SEL		1
+#define STB0899_CONFIG_MODE			(0x01 << 0)
+#define STB0899_OFFST_CONFIG_MODE		0
+#define STB0899_WIDTH_CONFIG_MODE		1
+
+#define STB0899_OFF0_LDPC_STAT			0xfa04
+#define STB0899_BASE_LDPC_STAT			0x00000800
+#define STB0899_ITERATION			(0xff << 3)
+#define STB0899_OFFST_ITERATION			3
+#define STB0899_WIDTH_ITERATION			8
+#define STB0899_LDPC_DEC_STATE			(0x07 << 0)
+#define STB0899_OFFST_LDPC_DEC_STATE		0
+#define STB0899_WIDTH_LDPC_DEC_STATE		3
+
+#define STB0899_OFF0_ITER_SCALE			0xfa08
+#define STB0899_BASE_ITER_SCALE			0x00000800
+#define STB0899_ITERATION_SCALE			(0xff << 0)
+#define STB0899_OFFST_ITERATION_SCALE		0
+#define STB0899_WIDTH_ITERATION_SCALE		8
+
+#define STB0899_OFF0_INPUT_MODE			0xfa0c
+#define STB0899_BASE_INPUT_MODE			0x00000800
+#define STB0899_SD_BLOCK1_STREAM0		(0x01 << 0)
+#define STB0899_OFFST_SD_BLOCK1_STREAM0		0
+#define STB0899_WIDTH_SD_BLOCK1_STREAM0		1
+
+#define STB0899_OFF0_LDPCDECRST			0xfa10
+#define STB0899_BASE_LDPCDECRST			0x00000800
+#define STB0899_LDPC_DEC_RST			(0x01 << 0)
+#define STB0899_OFFST_LDPC_DEC_RST		0
+#define STB0899_WIDTH_LDPC_DEC_RST		1
+
+#define STB0899_OFF0_CLK_PER_BYTE_RW		0xfa14
+#define STB0899_BASE_CLK_PER_BYTE_RW		0x00000800
+#define STB0899_CLKS_PER_BYTE			(0x0f << 0)
+#define STB0899_OFFST_CLKS_PER_BYTE		0
+#define STB0899_WIDTH_CLKS_PER_BYTE		5
+
+#define STB0899_OFF0_BCH_ERRORS			0xfa18
+#define STB0899_BASE_BCH_ERRORS			0x00000800
+#define STB0899_BCH_ERRORS			(0x0f << 0)
+#define STB0899_OFFST_BCH_ERRORS		0
+#define STB0899_WIDTH_BCH_ERRORS		4
+
+#define STB0899_OFF0_LDPC_ERRORS		0xfa1c
+#define STB0899_BASE_LDPC_ERRORS		0x00000800
+#define STB0899_LDPC_ERRORS			(0xffff << 0)
+#define STB0899_OFFST_LDPC_ERRORS		0
+#define STB0899_WIDTH_LDPC_ERRORS		16
+
+#define STB0899_OFF0_BCH_MODE			0xfa20
+#define STB0899_BASE_BCH_MODE			0x00000800
+#define STB0899_BCH_CORRECT_N			(0x01 << 1)
+#define STB0899_OFFST_BCH_CORRECT_N		1
+#define STB0899_WIDTH_BCH_CORRECT_N		1
+#define STB0899_FULL_BYPASS			(0x01 << 0)
+#define STB0899_OFFST_FULL_BYPASS		0
+#define STB0899_WIDTH_FULL_BYPASS		1
+
+#define STB0899_OFF0_ERR_ACC_PER		0xfa24
+#define STB0899_BASE_ERR_ACC_PER		0x00000800
+#define STB0899_BCH_ERR_ACC_PERIOD		(0x0f << 0)
+#define STB0899_OFFST_BCH_ERR_ACC_PERIOD	0
+#define STB0899_WIDTH_BCH_ERR_ACC_PERIOD	4
+
+#define STB0899_OFF0_BCH_ERR_ACC		0xfa28
+#define STB0899_BASE_BCH_ERR_ACC		0x00000800
+#define STB0899_BCH_ERR_ACCUM			(0xff << 0)
+#define STB0899_OFFST_BCH_ERR_ACCUM		0
+#define STB0899_WIDTH_BCH_ERR_ACCUM		8
+
+#define STB0899_OFF0_FEC_CORE_ID_REG		0xfa2c
+#define STB0899_BASE_FEC_CORE_ID_REG		0x00000800
+#define STB0899_FEC_CORE_ID			(0xffffffff << 0)
+#define STB0899_OFFST_FEC_CORE_ID		0
+#define STB0899_WIDTH_FEC_CORE_ID		32
+
+#define STB0899_OFF0_FEC_VER_ID_REG		0xfa34
+#define STB0899_BASE_FEC_VER_ID_REG		0x00000800
+#define STB0899_FEC_VER_ID			(0xff << 0)
+#define STB0899_OFFST_FEC_VER_ID		0
+#define STB0899_WIDTH_FEC_VER_ID		8
+
+#define STB0899_OFF0_FEC_TP_SEL			0xfa38
+#define STB0899_BASE_FEC_TP_SEL			0x00000800
+
+#define STB0899_OFF0_CSM_CNTRL1			0xf310
+#define STB0899_BASE_CSM_CNTRL1			0x00000400
+#define STB0899_CSM_FORCE_FREQLOCK		(0x01 << 19)
+#define STB0899_OFFST_CSM_FORCE_FREQLOCK	19
+#define STB0899_WIDTH_CSM_FORCE_FREQLOCK	1
+#define STB0899_CSM_FREQ_LOCKSTATE		(0x01 << 18)
+#define STB0899_OFFST_CSM_FREQ_LOCKSTATE	18
+#define STB0899_WIDTH_CSM_FREQ_LOCKSTATE	1
+#define STB0899_CSM_AUTO_PARAM			(0x01 << 17)
+#define STB0899_OFFST_CSM_AUTO_PARAM		17
+#define STB0899_WIDTH_CSM_AUTO_PARAM		1
+#define STB0899_FE_LOOP_SHIFT			(0x07 << 14)
+#define STB0899_OFFST_FE_LOOP_SHIFT		14
+#define STB0899_WIDTH_FE_LOOP_SHIFT		3
+#define STB0899_CSM_AGC_SHIFT			(0x07 << 11)
+#define STB0899_OFFST_CSM_AGC_SHIFT		11
+#define STB0899_WIDTH_CSM_AGC_SHIFT		3
+#define STB0899_CSM_AGC_GAIN			(0x1ff << 2)
+#define STB0899_OFFST_CSM_AGC_GAIN		2
+#define STB0899_WIDTH_CSM_AGC_GAIN		9
+#define STB0899_CSM_TWO_PASS			(0x01 << 1)
+#define STB0899_OFFST_CSM_TWO_PASS		1
+#define STB0899_WIDTH_CSM_TWO_PASS		1
+#define STB0899_CSM_DVT_TABLE			(0x01 << 0)
+#define STB0899_OFFST_CSM_DVT_TABLE		0
+#define STB0899_WIDTH_CSM_DVT_TABLE		1
+
+#define STB0899_OFF0_CSM_CNTRL2			0xf314
+#define STB0899_BASE_CSM_CNTRL2			0x00000400
+#define STB0899_CSM_GAMMA_RHO_ACQ		(0x1ff << 9)
+#define STB0899_OFFST_CSM_GAMMA_RHOACQ		9
+#define STB0899_WIDTH_CSM_GAMMA_RHOACQ		9
+#define STB0899_CSM_GAMMA_ACQ			(0x1ff << 0)
+#define STB0899_OFFST_CSM_GAMMA_ACQ		0
+#define STB0899_WIDTH_CSM_GAMMA_ACQ		9
+
+#define STB0899_OFF0_CSM_CNTRL3			0xf318
+#define STB0899_BASE_CSM_CNTRL3			0x00000400
+#define STB0899_CSM_GAMMA_RHO_TRACK		(0x1ff << 9)
+#define STB0899_OFFST_CSM_GAMMA_RHOTRACK	9
+#define STB0899_WIDTH_CSM_GAMMA_RHOTRACK	9
+#define STB0899_CSM_GAMMA_TRACK			(0x1ff << 0)
+#define STB0899_OFFST_CSM_GAMMA_TRACK		0
+#define STB0899_WIDTH_CSM_GAMMA_TRACK		9
+
+#define STB0899_OFF0_CSM_CNTRL4			0xf31c
+#define STB0899_BASE_CSM_CNTRL4			0x00000400
+#define STB0899_CSM_PHASEDIFF_THRESH		(0x0f << 8)
+#define STB0899_OFFST_CSM_PHASEDIFF_THRESH	8
+#define STB0899_WIDTH_CSM_PHASEDIFF_THRESH	4
+#define STB0899_CSM_LOCKCOUNT_THRESH		(0xff << 0)
+#define STB0899_OFFST_CSM_LOCKCOUNT_THRESH	0
+#define STB0899_WIDTH_CSM_LOCKCOUNT_THRESH	8
+
+/*	Check on chapter 8 page 42	*/
+#define STB0899_ERRCTRL1			0xf574
+#define STB0899_ERRCTRL2			0xf575
+#define STB0899_ERRCTRL3			0xf576
+#define STB0899_ERR_SRC_S1			(0x1f << 3)
+#define STB0899_OFFST_ERR_SRC_S1		3
+#define STB0899_WIDTH_ERR_SRC_S1		5
+#define STB0899_ERR_SRC_S2			(0x0f << 0)
+#define STB0899_OFFST_ERR_SRC_S2		0
+#define STB0899_WIDTH_ERR_SRC_S2		4
+#define STB0899_NOE				(0x07 << 0)
+#define STB0899_OFFST_NOE			0
+#define STB0899_WIDTH_NOE			3
+
+#define STB0899_ECNT1M				0xf524
+#define STB0899_ECNT1L				0xf525
+#define STB0899_ECNT2M				0xf526
+#define STB0899_ECNT2L				0xf527
+#define STB0899_ECNT3M				0xf528
+#define STB0899_ECNT3L				0xf529
+
+#define STB0899_DMONMSK1			0xf57b
+#define STB0899_DMONMSK1_WAIT_1STEP		(1 << 7)
+#define STB0899_DMONMSK1_FREE_14		(1 << 6)
+#define STB0899_DMONMSK1_AVRGVIT_CALC		(1 << 5)
+#define STB0899_DMONMSK1_FREE_12		(1 << 4)
+#define STB0899_DMONMSK1_FREE_11		(1 << 3)
+#define STB0899_DMONMSK1_B0DIV_CALC		(1 << 2)
+#define STB0899_DMONMSK1_KDIVB1_CALC		(1 << 1)
+#define STB0899_DMONMSK1_KDIVB2_CALC		(1 << 0)
+
+#define STB0899_DMONMSK0			0xf57c
+#define STB0899_DMONMSK0_SMOTTH_CALC		(1 << 7)
+#define STB0899_DMONMSK0_FREE_6			(1 << 6)
+#define STB0899_DMONMSK0_SIGPOWER_CALC		(1 << 5)
+#define STB0899_DMONMSK0_QSEUIL_CALC		(1 << 4)
+#define STB0899_DMONMSK0_FREE_3			(1 << 3)
+#define STB0899_DMONMSK0_FREE_2			(1 << 2)
+#define STB0899_DMONMSK0_KVDIVB1_CALC		(1 << 1)
+#define STB0899_DMONMSK0_KVDIVB2_CALC		(1 << 0)
+
+#define STB0899_TSULC				0xf549
+#define STB0899_ULNOSYNCBYTES			(0x01 << 7)
+#define STB0899_OFFST_ULNOSYNCBYTES		7
+#define STB0899_WIDTH_ULNOSYNCBYTES		1
+#define STB0899_ULPARITY_ON			(0x01 << 6)
+#define STB0899_OFFST_ULPARITY_ON		6
+#define STB0899_WIDTH_ULPARITY_ON		1
+#define STB0899_ULSYNCOUTRS			(0x01 << 5)
+#define STB0899_OFFST_ULSYNCOUTRS		5
+#define STB0899_WIDTH_ULSYNCOUTRS		1
+#define STB0899_ULDSS_PACKETS			(0x01 << 0)
+#define STB0899_OFFST_ULDSS_PACKETS		0
+#define STB0899_WIDTH_ULDSS_PACKETS		1
+
+#define STB0899_TSLPL				0xf54b
+#define STB0899_LLDVBS2_MODE			(0x01 << 4)
+#define STB0899_OFFST_LLDVBS2_MODE		4
+#define STB0899_WIDTH_LLDVBS2_MODE		1
+#define STB0899_LLISSYI_ON			(0x01 << 3)
+#define STB0899_OFFST_LLISSYI_ON		3
+#define STB0899_WIDTH_LLISSYI_ON		1
+#define STB0899_LLNPD_ON			(0x01 << 2)
+#define STB0899_OFFST_LLNPD_ON			2
+#define STB0899_WIDTH_LLNPD_ON			1
+#define STB0899_LLCRC8_ON			(0x01 << 1)
+#define STB0899_OFFST_LLCRC8_ON			1
+#define STB0899_WIDTH_LLCRC8_ON			1
+
+#define STB0899_TSCFGH				0xf54c
+#define STB0899_OUTRS_PS			(0x01 << 6)
+#define STB0899_OFFST_OUTRS_PS			6
+#define STB0899_WIDTH_OUTRS_PS			1
+#define STB0899_SYNCBYTE			(0x01 << 5)
+#define STB0899_OFFST_SYNCBYTE			5
+#define STB0899_WIDTH_SYNCBYTE			1
+#define STB0899_PFBIT				(0x01 << 4)
+#define STB0899_OFFST_PFBIT			4
+#define STB0899_WIDTH_PFBIT			1
+#define STB0899_ERR_BIT				(0x01 << 3)
+#define STB0899_OFFST_ERR_BIT			3
+#define STB0899_WIDTH_ERR_BIT			1
+#define STB0899_MPEG				(0x01 << 2)
+#define STB0899_OFFST_MPEG			2
+#define STB0899_WIDTH_MPEG			1
+#define STB0899_CLK_POL				(0x01 << 1)
+#define STB0899_OFFST_CLK_POL			1
+#define STB0899_WIDTH_CLK_POL			1
+#define STB0899_FORCE0				(0x01 << 0)
+#define STB0899_OFFST_FORCE0			0
+#define STB0899_WIDTH_FORCE0			1
+
+#define STB0899_TSCFGM				0xf54d
+#define STB0899_LLPRIORITY			(0x01 << 3)
+#define STB0899_OFFST_LLPRIORIY			3
+#define STB0899_WIDTH_LLPRIORITY		1
+#define STB0899_EN188				(0x01 << 2)
+#define STB0899_OFFST_EN188			2
+#define STB0899_WIDTH_EN188			1
+
+#define STB0899_TSCFGL				0xf54e
+#define STB0899_DEL_ERRPCK			(0x01 << 7)
+#define STB0899_OFFST_DEL_ERRPCK		7
+#define STB0899_WIDTH_DEL_ERRPCK		1
+#define STB0899_ERRFLAGSTD			(0x01 << 5)
+#define STB0899_OFFST_ERRFLAGSTD		5
+#define STB0899_WIDTH_ERRFLAGSTD		1
+#define STB0899_MPEGERR				(0x01 << 4)
+#define STB0899_OFFST_MPEGERR			4
+#define STB0899_WIDTH_MPEGERR			1
+#define STB0899_BCH_CHK				(0x01 << 3)
+#define STB0899_OFFST_BCH_CHK			5
+#define STB0899_WIDTH_BCH_CHK			1
+#define STB0899_CRC8CHK				(0x01 << 2)
+#define STB0899_OFFST_CRC8CHK			2
+#define STB0899_WIDTH_CRC8CHK			1
+#define STB0899_SPEC_INFO			(0x01 << 1)
+#define STB0899_OFFST_SPEC_INFO			1
+#define STB0899_WIDTH_SPEC_INFO			1
+#define STB0899_LOW_PRIO_CLK			(0x01 << 0)
+#define STB0899_OFFST_LOW_PRIO_CLK		0
+#define STB0899_WIDTH_LOW_PRIO_CLK		1
+#define STB0899_ERROR_NORM			(0x00 << 0)
+#define STB0899_OFFST_ERROR_NORM		0
+#define STB0899_WIDTH_ERROR_NORM		0
+
+#define STB0899_TSOUT				0xf54f
+#define STB0899_RSSYNCDEL			0xf550
+#define STB0899_TSINHDELH			0xf551
+#define STB0899_TSINHDELM			0xf552
+#define STB0899_TSINHDELL			0xf553
+#define STB0899_TSLLSTKM			0xf55a
+#define STB0899_TSLLSTKL			0xf55b
+#define STB0899_TSULSTKM			0xf55c
+#define STB0899_TSULSTKL			0xf55d
+#define STB0899_TSSTATUS			0xf561
+
+#define STB0899_PDELCTRL			0xf600
+#define STB0899_INVERT_RES			(0x01 << 7)
+#define STB0899_OFFST_INVERT_RES		7
+#define STB0899_WIDTH_INVERT_RES		1
+#define STB0899_FORCE_ACCEPTED			(0x01 << 6)
+#define STB0899_OFFST_FORCE_ACCEPTED		6
+#define STB0899_WIDTH_FORCE_ACCEPTED		1
+#define STB0899_FILTER_EN			(0x01 << 5)
+#define STB0899_OFFST_FILTER_EN			5
+#define STB0899_WIDTH_FILTER_EN			1
+#define STB0899_LOCKFALL_THRESH			(0x01 << 4)
+#define STB0899_OFFST_LOCKFALL_THRESH		4
+#define STB0899_WIDTH_LOCKFALL_THRESH		1
+#define STB0899_HYST_EN				(0x01 << 3)
+#define STB0899_OFFST_HYST_EN			3
+#define STB0899_WIDTH_HYST_EN			1
+#define STB0899_HYST_SWRST			(0x01 << 2)
+#define STB0899_OFFST_HYST_SWRST		2
+#define STB0899_WIDTH_HYST_SWRST		1
+#define STB0899_ALGO_EN				(0x01 << 1)
+#define STB0899_OFFST_ALGO_EN			1
+#define STB0899_WIDTH_ALGO_EN			1
+#define STB0899_ALGO_SWRST			(0x01 << 0)
+#define STB0899_OFFST_ALGO_SWRST		0
+#define STB0899_WIDTH_ALGO_SWRST		1
+
+#define STB0899_PDELCTRL2			0xf601
+#define STB0899_BBHCTRL1			0xf602
+#define STB0899_BBHCTRL2			0xf603
+#define STB0899_HYSTTHRESH			0xf604
+
+#define STB0899_MATCSTM				0xf605
+#define STB0899_MATCSTL				0xf606
+#define STB0899_UPLCSTM				0xf607
+#define STB0899_UPLCSTL				0xf608
+#define STB0899_DFLCSTM				0xf609
+#define STB0899_DFLCSTL				0xf60a
+#define STB0899_SYNCCST				0xf60b
+#define STB0899_SYNCDCSTM			0xf60c
+#define STB0899_SYNCDCSTL			0xf60d
+#define STB0899_ISI_ENTRY			0xf60e
+#define STB0899_ISI_BIT_EN			0xf60f
+#define STB0899_MATSTRM				0xf610
+#define STB0899_MATSTRL				0xf611
+#define STB0899_UPLSTRM				0xf612
+#define STB0899_UPLSTRL				0xf613
+#define STB0899_DFLSTRM				0xf614
+#define STB0899_DFLSTRL				0xf615
+#define STB0899_SYNCSTR				0xf616
+#define STB0899_SYNCDSTRM			0xf617
+#define STB0899_SYNCDSTRL			0xf618
+
+#define STB0899_CFGPDELSTATUS1			0xf619
+#define STB0899_BADDFL				(0x01 << 6)
+#define STB0899_OFFST_BADDFL			6
+#define STB0899_WIDTH_BADDFL			1
+#define STB0899_CONTINUOUS_STREAM		(0x01 << 5)
+#define STB0899_OFFST_CONTINUOUS_STREAM		5
+#define STB0899_WIDTH_CONTINUOUS_STREAM		1
+#define STB0899_ACCEPTED_STREAM			(0x01 << 4)
+#define STB0899_OFFST_ACCEPTED_STREAM		4
+#define STB0899_WIDTH_ACCEPTED_STREAM		1
+#define STB0899_BCH_ERRFLAG			(0x01 << 3)
+#define STB0899_OFFST_BCH_ERRFLAG		3
+#define STB0899_WIDTH_BCH_ERRFLAG		1
+#define STB0899_CRCRES				(0x01 << 2)
+#define STB0899_OFFST_CRCRES			2
+#define STB0899_WIDTH_CRCRES			1
+#define STB0899_CFGPDELSTATUS_LOCK		(0x01 << 1)
+#define STB0899_OFFST_CFGPDELSTATUS_LOCK	1
+#define STB0899_WIDTH_CFGPDELSTATUS_LOCK	1
+#define STB0899_1STLOCK				(0x01 << 0)
+#define STB0899_OFFST_1STLOCK			0
+#define STB0899_WIDTH_1STLOCK			1
+
+#define STB0899_CFGPDELSTATUS2			0xf61a
+#define STB0899_BBFERRORM			0xf61b
+#define STB0899_BBFERRORL			0xf61c
+#define STB0899_UPKTERRORM			0xf61d
+#define STB0899_UPKTERRORL			0xf61e
+
+#define STB0899_TSTCK				0xff10
+
+#define STB0899_TSTRES				0xff11
+#define STB0899_FRESLDPC			(0x01 << 7)
+#define STB0899_OFFST_FRESLDPC			7
+#define STB0899_WIDTH_FRESLDPC			1
+#define STB0899_FRESRS				(0x01 << 6)
+#define STB0899_OFFST_FRESRS			6
+#define STB0899_WIDTH_FRESRS			1
+#define STB0899_FRESVIT				(0x01 << 5)
+#define STB0899_OFFST_FRESVIT			5
+#define STB0899_WIDTH_FRESVIT			1
+#define STB0899_FRESMAS1_2			(0x01 << 4)
+#define STB0899_OFFST_FRESMAS1_2		4
+#define STB0899_WIDTH_FRESMAS1_2		1
+#define STB0899_FRESACS				(0x01 << 3)
+#define STB0899_OFFST_FRESACS			3
+#define STB0899_WIDTH_FRESACS			1
+#define STB0899_FRESSYM				(0x01 << 2)
+#define STB0899_OFFST_FRESSYM			2
+#define STB0899_WIDTH_FRESSYM			1
+#define STB0899_FRESMAS				(0x01 << 1)
+#define STB0899_OFFST_FRESMAS			1
+#define STB0899_WIDTH_FRESMAS			1
+#define STB0899_FRESINT				(0x01 << 0)
+#define STB0899_OFFST_FRESINIT			0
+#define STB0899_WIDTH_FRESINIT			1
+
+#define STB0899_TSTOUT				0xff12
+#define STB0899_EN_SIGNATURE			(0x01 << 7)
+#define STB0899_OFFST_EN_SIGNATURE		7
+#define STB0899_WIDTH_EN_SIGNATURE		1
+#define STB0899_BCLK_CLK			(0x01 << 6)
+#define STB0899_OFFST_BCLK_CLK			6
+#define STB0899_WIDTH_BCLK_CLK			1
+#define STB0899_SGNL_OUT			(0x01 << 5)
+#define STB0899_OFFST_SGNL_OUT			5
+#define STB0899_WIDTH_SGNL_OUT			1
+#define STB0899_TS				(0x01 << 4)
+#define STB0899_OFFST_TS			4
+#define STB0899_WIDTH_TS			1
+#define STB0899_CTEST				(0x01 << 0)
+#define STB0899_OFFST_CTEST			0
+#define STB0899_WIDTH_CTEST			1
+
+#define STB0899_TSTIN				0xff13
+#define STB0899_TEST_IN				(0x01 << 7)
+#define STB0899_OFFST_TEST_IN			7
+#define STB0899_WIDTH_TEST_IN			1
+#define STB0899_EN_ADC				(0x01 << 6)
+#define STB0899_OFFST_EN_ADC			6
+#define STB0899_WIDTH_ENADC			1
+#define STB0899_SGN_ADC				(0x01 << 5)
+#define STB0899_OFFST_SGN_ADC			5
+#define STB0899_WIDTH_SGN_ADC			1
+#define STB0899_BCLK_IN				(0x01 << 4)
+#define STB0899_OFFST_BCLK_IN			4
+#define STB0899_WIDTH_BCLK_IN			1
+#define STB0899_JETONIN_MODE			(0x01 << 3)
+#define STB0899_OFFST_JETONIN_MODE		3
+#define STB0899_WIDTH_JETONIN_MODE		1
+#define STB0899_BCLK_VALUE			(0x01 << 2)
+#define STB0899_OFFST_BCLK_VALUE		2
+#define STB0899_WIDTH_BCLK_VALUE		1
+#define STB0899_SGNRST_T12			(0x01 << 1)
+#define STB0899_OFFST_SGNRST_T12		1
+#define STB0899_WIDTH_SGNRST_T12		1
+#define STB0899_LOWSP_ENAX			(0x01 << 0)
+#define STB0899_OFFST_LOWSP_ENAX		0
+#define STB0899_WIDTH_LOWSP_ENAX		1
+
+#define STB0899_TSTSYS				0xff14
+#define STB0899_TSTCHIP				0xff15
+#define STB0899_TSTFREE				0xff16
+#define STB0899_TSTI2C				0xff17
+#define STB0899_BITSPEEDM			0xff1c
+#define STB0899_BITSPEEDL			0xff1d
+#define STB0899_TBUSBIT				0xff1e
+#define STB0899_TSTDIS				0xff24
+#define STB0899_TSTDISRX			0xff25
+#define STB0899_TSTJETON			0xff28
+#define STB0899_TSTDCADJ			0xff40
+#define STB0899_TSTAGC1				0xff41
+#define STB0899_TSTAGC1N			0xff42
+#define STB0899_TSTPOLYPH			0xff48
+#define STB0899_TSTR				0xff49
+#define STB0899_TSTAGC2				0xff4a
+#define STB0899_TSTCTL1				0xff4b
+#define STB0899_TSTCTL2				0xff4c
+#define STB0899_TSTCTL3				0xff4d
+#define STB0899_TSTDEMAP			0xff50
+#define STB0899_TSTDEMAP2			0xff51
+#define STB0899_TSTDEMMON			0xff52
+#define STB0899_TSTRATE				0xff53
+#define STB0899_TSTSELOUT			0xff54
+#define STB0899_TSYNC				0xff55
+#define STB0899_TSTERR				0xff56
+#define STB0899_TSTRAM1				0xff58
+#define STB0899_TSTVSELOUT			0xff59
+#define STB0899_TSTFORCEIN			0xff5a
+#define STB0899_TSTRS1				0xff5c
+#define STB0899_TSTRS2				0xff5d
+#define STB0899_TSTRS3				0xff53
+
+#define STB0899_INTBUFSTATUS			0xf200
+#define STB0899_INTBUFCTRL			0xf201
+#define STB0899_PCKLENUL			0xf55e
+#define STB0899_PCKLENLL			0xf55f
+#define STB0899_RSPCKLEN			0xf560
+
+/*	2 registers	*/
+#define STB0899_SYNCDCST			0xf60c
+
+/*	DiSEqC	*/
+#define STB0899_DISCNTRL1			0xf0a0
+#define STB0899_TIMOFF				(0x01 << 7)
+#define STB0899_OFFST_TIMOFF			7
+#define STB0899_WIDTH_TIMOFF			1
+#define STB0899_DISEQCRESET			(0x01 << 6)
+#define STB0899_OFFST_DISEQCRESET		6
+#define STB0899_WIDTH_DISEQCRESET		1
+#define STB0899_TIMCMD				(0x03 << 4)
+#define STB0899_OFFST_TIMCMD			4
+#define STB0899_WIDTH_TIMCMD			2
+#define STB0899_DISPRECHARGE			(0x01 << 2)
+#define STB0899_OFFST_DISPRECHARGE		2
+#define STB0899_WIDTH_DISPRECHARGE		1
+#define STB0899_DISEQCMODE			(0x03 << 0)
+#define STB0899_OFFST_DISEQCMODE		0
+#define STB0899_WIDTH_DISEQCMODE		2
+
+#define STB0899_DISCNTRL2			0xf0a1
+#define STB0899_RECEIVER_ON			(0x01 << 7)
+#define STB0899_OFFST_RECEIVER_ON		7
+#define STB0899_WIDTH_RECEIVER_ON		1
+#define STB0899_IGNO_SHORT_22K			(0x01 << 6)
+#define STB0899_OFFST_IGNO_SHORT_22K		6
+#define STB0899_WIDTH_IGNO_SHORT_22K		1
+#define STB0899_ONECHIP_TRX			(0x01 << 5)
+#define STB0899_OFFST_ONECHIP_TRX		5
+#define STB0899_WIDTH_ONECHIP_TRX		1
+#define STB0899_EXT_ENVELOP			(0x01 << 4)
+#define STB0899_OFFST_EXT_ENVELOP		4
+#define STB0899_WIDTH_EXT_ENVELOP		1
+#define STB0899_PIN_SELECT			(0x03 << 2)
+#define STB0899_OFFST_PIN_SELCT			2
+#define STB0899_WIDTH_PIN_SELCT			2
+#define STB0899_IRQ_RXEND			(0x01 << 1)
+#define STB0899_OFFST_IRQ_RXEND			1
+#define STB0899_WIDTH_IRQ_RXEND			1
+#define STB0899_IRQ_4NBYTES			(0x01 << 0)
+#define STB0899_OFFST_IRQ_4NBYTES		0
+#define STB0899_WIDTH_IRQ_4NBYTES		1
+
+#define STB0899_DISRX_ST0			0xf0a4
+#define STB0899_RXEND				(0x01 << 7)
+#define STB0899_OFFST_RXEND			7
+#define STB0899_WIDTH_RXEND			1
+#define STB0899_RXACTIVE			(0x01 << 6)
+#define STB0899_OFFST_RXACTIVE			6
+#define STB0899_WIDTH_RXACTIVE			1
+#define STB0899_SHORT22K			(0x01 << 5)
+#define STB0899_OFFST_SHORT22K			5
+#define STB0899_WIDTH_SHORT22K			1
+#define STB0899_CONTTONE			(0x01 << 4)
+#define STB0899_OFFST_CONTTONE			4
+#define STB0899_WIDTH_CONTONE			1
+#define STB0899_4BFIFOREDY			(0x01 << 3)
+#define STB0899_OFFST_4BFIFOREDY		3
+#define STB0899_WIDTH_4BFIFOREDY		1
+#define STB0899_FIFOEMPTY			(0x01 << 2)
+#define STB0899_OFFST_FIFOEMPTY			2
+#define STB0899_WIDTH_FIFOEMPTY			1
+#define STB0899_ABORTTRX			(0x01 << 0)
+#define STB0899_OFFST_ABORTTRX			0
+#define STB0899_WIDTH_ABORTTRX			1
+
+#define STB0899_DISRX_ST1			0xf0a5
+#define STB0899_RXFAIL				(0x01 << 7)
+#define STB0899_OFFST_RXFAIL			7
+#define STB0899_WIDTH_RXFAIL			1
+#define STB0899_FIFOPFAIL			(0x01 << 6)
+#define STB0899_OFFST_FIFOPFAIL			6
+#define STB0899_WIDTH_FIFOPFAIL			1
+#define STB0899_RXNONBYTES			(0x01 << 5)
+#define STB0899_OFFST_RXNONBYTES		5
+#define STB0899_WIDTH_RXNONBYTES		1
+#define STB0899_FIFOOVF				(0x01 << 4)
+#define STB0899_OFFST_FIFOOVF			4
+#define STB0899_WIDTH_FIFOOVF			1
+#define STB0899_FIFOBYTENBR			(0x0f << 0)
+#define STB0899_OFFST_FIFOBYTENBR		0
+#define STB0899_WIDTH_FIFOBYTENBR		4
+
+#define STB0899_DISPARITY			0xf0a6
+
+#define STB0899_DISFIFO				0xf0a7
+
+#define STB0899_DISSTATUS			0xf0a8
+#define STB0899_FIFOFULL			(0x01 << 6)
+#define STB0899_OFFST_FIFOFULL			6
+#define STB0899_WIDTH_FIFOFULL			1
+#define STB0899_TXIDLE				(0x01 << 5)
+#define STB0899_OFFST_TXIDLE			5
+#define STB0899_WIDTH_TXIDLE			1
+#define STB0899_GAPBURST			(0x01 << 4)
+#define STB0899_OFFST_GAPBURST			4
+#define STB0899_WIDTH_GAPBURST			1
+#define STB0899_TXFIFOBYTES			(0x0f << 0)
+#define STB0899_OFFST_TXFIFOBYTES		0
+#define STB0899_WIDTH_TXFIFOBYTES		4
+#define STB0899_DISF22				0xf0a9
+
+#define STB0899_DISF22RX			0xf0aa
+
+/*	General Purpose	*/
+#define STB0899_SYSREG				0xf101
+#define STB0899_ACRPRESC			0xf110
+#define STB0899_OFFST_RSVD2			7
+#define STB0899_WIDTH_RSVD2			1
+#define STB0899_OFFST_ACRPRESC			4
+#define STB0899_WIDTH_ACRPRESC			3
+#define STB0899_OFFST_RSVD1			3
+#define STB0899_WIDTH_RSVD1			1
+#define STB0899_OFFST_ACRPRESC2			0
+#define STB0899_WIDTH_ACRPRESC2			3
+
+#define STB0899_ACRDIV1				0xf111
+#define STB0899_ACRDIV2				0xf112
+#define STB0899_DACR1				0xf113
+#define STB0899_DACR2				0xf114
+#define STB0899_OUTCFG				0xf11c
+#define STB0899_MODECFG				0xf11d
+#define STB0899_NCOARSE				0xf1b3
+
+#define STB0899_SYNTCTRL			0xf1b6
+#define STB0899_STANDBY				(0x01 << 7)
+#define STB0899_OFFST_STANDBY			7
+#define STB0899_WIDTH_STANDBY			1
+#define STB0899_BYPASSPLL			(0x01 << 6)
+#define STB0899_OFFST_BYPASSPLL			6
+#define STB0899_WIDTH_BYPASSPLL			1
+#define STB0899_SEL1XRATIO			(0x01 << 5)
+#define STB0899_OFFST_SEL1XRATIO		5
+#define STB0899_WIDTH_SEL1XRATIO		1
+#define STB0899_SELOSCI				(0x01 << 1)
+#define STB0899_OFFST_SELOSCI			1
+#define STB0899_WIDTH_SELOSCI			1
+
+#define STB0899_FILTCTRL			0xf1b7
+#define STB0899_SYSCTRL				0xf1b8
+
+#define STB0899_STOPCLK1			0xf1c2
+#define STB0899_STOP_CKINTBUF108		(0x01 << 7)
+#define STB0899_OFFST_STOP_CKINTBUF108		7
+#define STB0899_WIDTH_STOP_CKINTBUF108		1
+#define STB0899_STOP_CKINTBUF216		(0x01 << 6)
+#define STB0899_OFFST_STOP_CKINTBUF216		6
+#define STB0899_WIDTH_STOP_CKINTBUF216		1
+#define STB0899_STOP_CHK8PSK			(0x01 << 5)
+#define STB0899_OFFST_STOP_CHK8PSK		5
+#define STB0899_WIDTH_STOP_CHK8PSK		1
+#define STB0899_STOP_CKFEC108			(0x01 << 4)
+#define STB0899_OFFST_STOP_CKFEC108		4
+#define STB0899_WIDTH_STOP_CKFEC108		1
+#define STB0899_STOP_CKFEC216			(0x01 << 3)
+#define STB0899_OFFST_STOP_CKFEC216		3
+#define STB0899_WIDTH_STOP_CKFEC216		1
+#define STB0899_STOP_CKCORE216			(0x01 << 2)
+#define STB0899_OFFST_STOP_CKCORE216		2
+#define STB0899_WIDTH_STOP_CKCORE216		1
+#define STB0899_STOP_CKADCI108			(0x01 << 1)
+#define STB0899_OFFST_STOP_CKADCI108		1
+#define STB0899_WIDTH_STOP_CKADCI108		1
+#define STB0899_STOP_INVCKADCI108		(0x01 << 0)
+#define STB0899_OFFST_STOP_INVCKADCI108		0
+#define STB0899_WIDTH_STOP_INVCKADCI108		1
+
+#define STB0899_STOPCLK2			0xf1c3
+#define STB0899_STOP_CKS2DMD108			(0x01 << 2)
+#define STB0899_OFFST_STOP_CKS2DMD108		2
+#define STB0899_WIDTH_STOP_CKS2DMD108		1
+#define STB0899_STOP_CKPKDLIN108		(0x01 << 1)
+#define STB0899_OFFST_STOP_CKPKDLIN108		1
+#define STB0899_WIDTH_STOP_CKPKDLIN108		1
+#define STB0899_STOP_CKPKDLIN216		(0x01 << 0)
+#define STB0899_OFFST_STOP_CKPKDLIN216		0
+#define STB0899_WIDTH_STOP_CKPKDLIN216		1
+
+#define STB0899_TSTTNR1				0xf1e0
+#define STB0899_BYPASS_ADC			(0x01 << 7)
+#define STB0899_OFFST_BYPASS_ADC		7
+#define STB0899_WIDTH_BYPASS_ADC		1
+#define STB0899_INVADCICKOUT			(0x01 << 6)
+#define STB0899_OFFST_INVADCICKOUT		6
+#define STB0899_WIDTH_INVADCICKOUT		1
+#define STB0899_ADCTEST_VOLTAGE			(0x03 << 4)
+#define STB0899_OFFST_ADCTEST_VOLTAGE		4
+#define STB0899_WIDTH_ADCTEST_VOLTAGE		1
+#define STB0899_ADC_RESET			(0x01 << 3)
+#define STB0899_OFFST_ADC_RESET			3
+#define STB0899_WIDTH_ADC_RESET			1
+#define STB0899_TSTTNR1_2			(0x01 << 2)
+#define STB0899_OFFST_TSTTNR1_2			2
+#define STB0899_WIDTH_TSTTNR1_2			1
+#define STB0899_ADCPON				(0x01 << 1)
+#define STB0899_OFFST_ADCPON			1
+#define STB0899_WIDTH_ADCPON			1
+#define STB0899_ADCIN_MODE			(0x01 << 0)
+#define STB0899_OFFST_ADCIN_MODE		0
+#define STB0899_WIDTH_ADCIN_MODE		1
+
+#define STB0899_TSTTNR2				0xf1e1
+#define STB0899_TSTTNR2_7			(0x01 << 7)
+#define STB0899_OFFST_TSTTNR2_7			7
+#define STB0899_WIDTH_TSTTNR2_7			1
+#define STB0899_NOT_DISRX_WIRED			(0x01 << 6)
+#define STB0899_OFFST_NOT_DISRX_WIRED		6
+#define STB0899_WIDTH_NOT_DISRX_WIRED		1
+#define STB0899_DISEQC_DCURRENT			(0x01 << 5)
+#define STB0899_OFFST_DISEQC_DCURRENT		5
+#define STB0899_WIDTH_DISEQC_DCURRENT		1
+#define STB0899_DISEQC_ZCURRENT			(0x01 << 4)
+#define STB0899_OFFST_DISEQC_ZCURRENT		4
+#define STB0899_WIDTH_DISEQC_ZCURRENT		1
+#define STB0899_DISEQC_SINC_SOURCE		(0x03 << 2)
+#define STB0899_OFFST_DISEQC_SINC_SOURCE	2
+#define STB0899_WIDTH_DISEQC_SINC_SOURCE	2
+#define STB0899_SELIQSRC			(0x03 << 0)
+#define STB0899_OFFST_SELIQSRC			0
+#define STB0899_WIDTH_SELIQSRC			2
+
+#define STB0899_TSTTNR3				0xf1e2
+
+#define STB0899_I2CCFG				0xf129
+#define STB0899_I2CCFGRSVD			(0x0f << 4)
+#define STB0899_OFFST_I2CCFGRSVD		4
+#define STB0899_WIDTH_I2CCFGRSVD		4
+#define STB0899_I2CFASTMODE			(0x01 << 3)
+#define STB0899_OFFST_I2CFASTMODE		3
+#define STB0899_WIDTH_I2CFASTMODE		1
+#define STB0899_STATUSWR			(0x01 << 2)
+#define STB0899_OFFST_STATUSWR			2
+#define STB0899_WIDTH_STATUSWR			1
+#define STB0899_I2CADDRINC			(0x03 << 0)
+#define STB0899_OFFST_I2CADDRINC		0
+#define STB0899_WIDTH_I2CADDRINC		2
+
+#define STB0899_I2CRPT				0xf12a
+#define STB0899_I2CTON				(0x01 << 7)
+#define STB0899_OFFST_I2CTON			7
+#define STB0899_WIDTH_I2CTON			1
+#define STB0899_ENARPTLEVEL			(0x01 << 6)
+#define STB0899_OFFST_ENARPTLEVEL		6
+#define STB0899_WIDTH_ENARPTLEVEL		2
+#define STB0899_SCLTDELAY			(0x01 << 3)
+#define STB0899_OFFST_SCLTDELAY			3
+#define STB0899_WIDTH_SCLTDELAY			1
+#define STB0899_STOPENA				(0x01 << 2)
+#define STB0899_OFFST_STOPENA			2
+#define STB0899_WIDTH_STOPENA			1
+#define STB0899_STOPSDAT2SDA			(0x01 << 1)
+#define STB0899_OFFST_STOPSDAT2SDA		1
+#define STB0899_WIDTH_STOPSDAT2SDA		1
+
+#define STB0899_IOPVALUE8			0xf136
+#define STB0899_IOPVALUE7			0xf137
+#define STB0899_IOPVALUE6			0xf138
+#define STB0899_IOPVALUE5			0xf139
+#define STB0899_IOPVALUE4			0xf13a
+#define STB0899_IOPVALUE3			0xf13b
+#define STB0899_IOPVALUE2			0xf13c
+#define STB0899_IOPVALUE1			0xf13d
+#define STB0899_IOPVALUE0			0xf13e
+
+#define STB0899_GPIO00CFG			0xf140
+
+#define STB0899_GPIO01CFG			0xf141
+#define STB0899_GPIO02CFG			0xf142
+#define STB0899_GPIO03CFG			0xf143
+#define STB0899_GPIO04CFG			0xf144
+#define STB0899_GPIO05CFG			0xf145
+#define STB0899_GPIO06CFG			0xf146
+#define STB0899_GPIO07CFG			0xf147
+#define STB0899_GPIO08CFG			0xf148
+#define STB0899_GPIO09CFG			0xf149
+#define STB0899_GPIO10CFG			0xf14a
+#define STB0899_GPIO11CFG			0xf14b
+#define STB0899_GPIO12CFG			0xf14c
+#define STB0899_GPIO13CFG			0xf14d
+#define STB0899_GPIO14CFG			0xf14e
+#define STB0899_GPIO15CFG			0xf14f
+#define STB0899_GPIO16CFG			0xf150
+#define STB0899_GPIO17CFG			0xf151
+#define STB0899_GPIO18CFG			0xf152
+#define STB0899_GPIO19CFG			0xf153
+#define STB0899_GPIO20CFG			0xf154
+
+#define STB0899_SDATCFG				0xf155
+#define STB0899_SCLTCFG				0xf156
+#define STB0899_AGCRFCFG			0xf157
+#define STB0899_GPIO22				0xf158	/* AGCBB2CFG	*/
+#define STB0899_GPIO21				0xf159  /* AGCBB1CFG	*/
+#define STB0899_DIRCLKCFG			0xf15a
+#define STB0899_CLKOUT27CFG			0xf15b
+#define STB0899_STDBYCFG			0xf15c
+#define STB0899_CS0CFG				0xf15d
+#define STB0899_CS1CFG				0xf15e
+#define STB0899_DISEQCOCFG			0xf15f
+
+#define STB0899_GPIO32CFG			0xf160
+#define STB0899_GPIO33CFG			0xf161
+#define STB0899_GPIO34CFG			0xf162
+#define STB0899_GPIO35CFG			0xf163
+#define STB0899_GPIO36CFG			0xf164
+#define STB0899_GPIO37CFG			0xf165
+#define STB0899_GPIO38CFG			0xf166
+#define STB0899_GPIO39CFG			0xf167
+
+#define STB0899_IRQSTATUS_3			0xf120
+#define STB0899_IRQSTATUS_2			0xf121
+#define STB0899_IRQSTATUS_1			0xf122
+#define STB0899_IRQSTATUS_0			0xf123
+
+#define STB0899_IRQMSK_3			0xf124
+#define STB0899_IRQMSK_2			0xf125
+#define STB0899_IRQMSK_1			0xf126
+#define STB0899_IRQMSK_0			0xf127
+
+#define STB0899_IRQCFG				0xf128
+
+#define STB0899_GHOSTREG			0xf000
+
+#define STB0899_S2DEMOD				0xf3fc
+#define STB0899_S2FEC				0xfafc
+
+
+#endif
diff --git a/drivers/media/dvb-frontends/stb6000.c b/drivers/media/dvb-frontends/stb6000.c
new file mode 100644
index 0000000..a0c3c52
--- /dev/null
+++ b/drivers/media/dvb-frontends/stb6000.c
@@ -0,0 +1,256 @@
+  /*
+     Driver for ST STB6000 DVBS Silicon tuner
+
+     Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+     the Free Software Foundation; either version 2 of the License, or
+     (at your option) any later version.
+
+     This program is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+     GNU General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, write to the Free Software
+     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+  */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <asm/types.h>
+
+#include "stb6000.h"
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG "stb6000: " args); \
+	} while (0)
+
+struct stb6000_priv {
+	/* i2c details */
+	int i2c_address;
+	struct i2c_adapter *i2c;
+	u32 frequency;
+};
+
+static int stb6000_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int stb6000_sleep(struct dvb_frontend *fe)
+{
+	struct stb6000_priv *priv = fe->tuner_priv;
+	int ret;
+	u8 buf[] = { 10, 0 };
+	struct i2c_msg msg = {
+		.addr = priv->i2c_address,
+		.flags = 0,
+		.buf = buf,
+		.len = 2
+	};
+
+	dprintk("%s:\n", __func__);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	ret = i2c_transfer(priv->i2c, &msg, 1);
+	if (ret != 1)
+		dprintk("%s: i2c error\n", __func__);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return (ret == 1) ? 0 : ret;
+}
+
+static int stb6000_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct stb6000_priv *priv = fe->tuner_priv;
+	unsigned int n, m;
+	int ret;
+	u32 freq_mhz;
+	int bandwidth;
+	u8 buf[12];
+	struct i2c_msg msg = {
+		.addr = priv->i2c_address,
+		.flags = 0,
+		.buf = buf,
+		.len = 12
+	};
+
+	dprintk("%s:\n", __func__);
+
+	freq_mhz = p->frequency / 1000;
+	bandwidth = p->symbol_rate / 1000000;
+
+	if (bandwidth > 31)
+		bandwidth = 31;
+
+	if ((freq_mhz > 949) && (freq_mhz < 2151)) {
+		buf[0] = 0x01;
+		buf[1] = 0xac;
+		if (freq_mhz < 1950)
+			buf[1] = 0xaa;
+		if (freq_mhz < 1800)
+			buf[1] = 0xa8;
+		if (freq_mhz < 1650)
+			buf[1] = 0xa6;
+		if (freq_mhz < 1530)
+			buf[1] = 0xa5;
+		if (freq_mhz < 1470)
+			buf[1] = 0xa4;
+		if (freq_mhz < 1370)
+			buf[1] = 0xa2;
+		if (freq_mhz < 1300)
+			buf[1] = 0xa1;
+		if (freq_mhz < 1200)
+			buf[1] = 0xa0;
+		if (freq_mhz < 1075)
+			buf[1] = 0xbc;
+		if (freq_mhz < 1000)
+			buf[1] = 0xba;
+		if (freq_mhz < 1075) {
+			n = freq_mhz / 8; /* vco=lo*4 */
+			m = 2;
+		} else {
+			n = freq_mhz / 16; /* vco=lo*2 */
+			m = 1;
+		}
+		buf[2] = n >> 1;
+		buf[3] = (unsigned char)(((n & 1) << 7) |
+					(m * freq_mhz - n * 16) | 0x60);
+		buf[4] = 0x04;
+		buf[5] = 0x0e;
+
+		buf[6] = (unsigned char)(bandwidth);
+
+		buf[7] = 0xd8;
+		buf[8] = 0xd0;
+		buf[9] = 0x50;
+		buf[10] = 0xeb;
+		buf[11] = 0x4f;
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		ret = i2c_transfer(priv->i2c, &msg, 1);
+		if (ret != 1)
+			dprintk("%s: i2c error\n", __func__);
+
+		udelay(10);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+
+		buf[0] = 0x07;
+		buf[1] = 0xdf;
+		buf[2] = 0xd0;
+		buf[3] = 0x50;
+		buf[4] = 0xfb;
+		msg.len = 5;
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		ret = i2c_transfer(priv->i2c, &msg, 1);
+		if (ret != 1)
+			dprintk("%s: i2c error\n", __func__);
+
+		udelay(10);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+
+		priv->frequency = freq_mhz * 1000;
+
+		return (ret == 1) ? 0 : ret;
+	}
+	return -1;
+}
+
+static int stb6000_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct stb6000_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static struct dvb_tuner_ops stb6000_tuner_ops = {
+	.info = {
+		.name = "ST STB6000",
+		.frequency_min = 950000,
+		.frequency_max = 2150000
+	},
+	.release = stb6000_release,
+	.sleep = stb6000_sleep,
+	.set_params = stb6000_set_params,
+	.get_frequency = stb6000_get_frequency,
+};
+
+struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr,
+						struct i2c_adapter *i2c)
+{
+	struct stb6000_priv *priv = NULL;
+	u8 b0[] = { 0 };
+	u8 b1[] = { 0, 0 };
+	struct i2c_msg msg[2] = {
+		{
+			.addr = addr,
+			.flags = 0,
+			.buf = b0,
+			.len = 0
+		}, {
+			.addr = addr,
+			.flags = I2C_M_RD,
+			.buf = b1,
+			.len = 2
+		}
+	};
+	int ret;
+
+	dprintk("%s:\n", __func__);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	/* is some i2c device here ? */
+	ret = i2c_transfer(i2c, msg, 2);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	if (ret != 2)
+		return NULL;
+
+	priv = kzalloc(sizeof(struct stb6000_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->i2c_address = addr;
+	priv->i2c = i2c;
+
+	memcpy(&fe->ops.tuner_ops, &stb6000_tuner_ops,
+				sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+
+	return fe;
+}
+EXPORT_SYMBOL(stb6000_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("DVB STB6000 driver");
+MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/stb6000.h b/drivers/media/dvb-frontends/stb6000.h
new file mode 100644
index 0000000..7be479c
--- /dev/null
+++ b/drivers/media/dvb-frontends/stb6000.h
@@ -0,0 +1,51 @@
+  /*
+     Driver for ST stb6000 DVBS Silicon tuner
+
+     Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+     the Free Software Foundation; either version 2 of the License, or
+     (at your option) any later version.
+
+     This program is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+     GNU General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, write to the Free Software
+     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+  */
+
+#ifndef __DVB_STB6000_H__
+#define __DVB_STB6000_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/**
+ * Attach a stb6000 tuner to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param addr i2c address of the tuner.
+ * @param i2c i2c adapter to use.
+ * @return FE pointer on success, NULL on failure.
+ */
+#if defined(CONFIG_DVB_STB6000) || (defined(CONFIG_DVB_STB6000_MODULE) \
+							&& defined(MODULE))
+extern struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr,
+					   struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe,
+						  int addr,
+						  struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_STB6000 */
+
+#endif /* __DVB_STB6000_H__ */
diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c
new file mode 100644
index 0000000..2e93e65
--- /dev/null
+++ b/drivers/media/dvb-frontends/stb6100.c
@@ -0,0 +1,611 @@
+/*
+	STB6100 Silicon Tuner
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "dvb_frontend.h"
+#include "stb6100.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+
+
+#define FE_ERROR		0
+#define FE_NOTICE		1
+#define FE_INFO			2
+#define FE_DEBUG		3
+
+#define dprintk(x, y, z, format, arg...) do {						\
+	if (z) {									\
+		if	((x > FE_ERROR) && (x > y))					\
+			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);		\
+		else if	((x > FE_NOTICE) && (x > y))					\
+			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
+		else if ((x > FE_INFO) && (x > y))					\
+			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);		\
+		else if ((x > FE_DEBUG) && (x > y))					\
+			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
+	} else {									\
+		if (x > y)								\
+			printk(format, ##arg);						\
+	}										\
+} while (0)
+
+struct stb6100_lkup {
+	u32 val_low;
+	u32 val_high;
+	u8   reg;
+};
+
+static int stb6100_release(struct dvb_frontend *fe);
+
+static const struct stb6100_lkup lkup[] = {
+	{       0,  950000, 0x0a },
+	{  950000, 1000000, 0x0a },
+	{ 1000000, 1075000, 0x0c },
+	{ 1075000, 1200000, 0x00 },
+	{ 1200000, 1300000, 0x01 },
+	{ 1300000, 1370000, 0x02 },
+	{ 1370000, 1470000, 0x04 },
+	{ 1470000, 1530000, 0x05 },
+	{ 1530000, 1650000, 0x06 },
+	{ 1650000, 1800000, 0x08 },
+	{ 1800000, 1950000, 0x0a },
+	{ 1950000, 2150000, 0x0c },
+	{ 2150000, 9999999, 0x0c },
+	{       0,       0, 0x00 }
+};
+
+/* Register names for easy debugging.	*/
+static const char *stb6100_regnames[] = {
+	[STB6100_LD]		= "LD",
+	[STB6100_VCO]		= "VCO",
+	[STB6100_NI]		= "NI",
+	[STB6100_NF_LSB]	= "NF",
+	[STB6100_K]		= "K",
+	[STB6100_G]		= "G",
+	[STB6100_F]		= "F",
+	[STB6100_DLB]		= "DLB",
+	[STB6100_TEST1]		= "TEST1",
+	[STB6100_FCCK]		= "FCCK",
+	[STB6100_LPEN]		= "LPEN",
+	[STB6100_TEST3]		= "TEST3",
+};
+
+/* Template for normalisation, i.e. setting unused or undocumented
+ * bits as required according to the documentation.
+ */
+struct stb6100_regmask {
+	u8 mask;
+	u8 set;
+};
+
+static const struct stb6100_regmask stb6100_template[] = {
+	[STB6100_LD]		= { 0xff, 0x00 },
+	[STB6100_VCO]		= { 0xff, 0x00 },
+	[STB6100_NI]		= { 0xff, 0x00 },
+	[STB6100_NF_LSB]	= { 0xff, 0x00 },
+	[STB6100_K]		= { 0xc7, 0x38 },
+	[STB6100_G]		= { 0xef, 0x10 },
+	[STB6100_F]		= { 0x1f, 0xc0 },
+	[STB6100_DLB]		= { 0x38, 0xc4 },
+	[STB6100_TEST1]		= { 0x00, 0x8f },
+	[STB6100_FCCK]		= { 0x40, 0x0d },
+	[STB6100_LPEN]		= { 0xf0, 0x0b },
+	[STB6100_TEST3]		= { 0x00, 0xde },
+};
+
+/*
+ * Currently unused. Some boards might need it in the future
+ */
+static inline void stb6100_normalise_regs(u8 regs[])
+{
+	int i;
+
+	for (i = 0; i < STB6100_NUMREGS; i++)
+		regs[i] = (regs[i] & stb6100_template[i].mask) | stb6100_template[i].set;
+}
+
+static int stb6100_read_regs(struct stb6100_state *state, u8 regs[])
+{
+	int rc;
+	struct i2c_msg msg = {
+		.addr	= state->config->tuner_address,
+		.flags	= I2C_M_RD,
+		.buf	= regs,
+		.len	= STB6100_NUMREGS
+	};
+
+	rc = i2c_transfer(state->i2c, &msg, 1);
+	if (unlikely(rc != 1)) {
+		dprintk(verbose, FE_ERROR, 1, "Read (0x%x) err, rc=[%d]",
+			state->config->tuner_address, rc);
+
+		return -EREMOTEIO;
+	}
+	if (unlikely(verbose > FE_DEBUG)) {
+		int i;
+
+		dprintk(verbose, FE_DEBUG, 1, "    Read from 0x%02x", state->config->tuner_address);
+		for (i = 0; i < STB6100_NUMREGS; i++)
+			dprintk(verbose, FE_DEBUG, 1, "        %s: 0x%02x", stb6100_regnames[i], regs[i]);
+	}
+	return 0;
+}
+
+static int stb6100_read_reg(struct stb6100_state *state, u8 reg)
+{
+	u8 regs[STB6100_NUMREGS];
+
+	struct i2c_msg msg = {
+		.addr	= state->config->tuner_address + reg,
+		.flags	= I2C_M_RD,
+		.buf	= regs,
+		.len	= 1
+	};
+
+	i2c_transfer(state->i2c, &msg, 1);
+
+	if (unlikely(reg >= STB6100_NUMREGS)) {
+		dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
+		return -EINVAL;
+	}
+	if (unlikely(verbose > FE_DEBUG)) {
+		dprintk(verbose, FE_DEBUG, 1, "    Read from 0x%02x", state->config->tuner_address);
+		dprintk(verbose, FE_DEBUG, 1, "        %s: 0x%02x", stb6100_regnames[reg], regs[0]);
+	}
+
+	return (unsigned int)regs[0];
+}
+
+static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int start, int len)
+{
+	int rc;
+	u8 cmdbuf[len + 1];
+	struct i2c_msg msg = {
+		.addr	= state->config->tuner_address,
+		.flags	= 0,
+		.buf	= cmdbuf,
+		.len	= len + 1
+	};
+
+	if (unlikely(start < 1 || start + len > STB6100_NUMREGS)) {
+		dprintk(verbose, FE_ERROR, 1, "Invalid register range %d:%d",
+			start, len);
+		return -EINVAL;
+	}
+	memcpy(&cmdbuf[1], buf, len);
+	cmdbuf[0] = start;
+
+	if (unlikely(verbose > FE_DEBUG)) {
+		int i;
+
+		dprintk(verbose, FE_DEBUG, 1, "    Write @ 0x%02x: [%d:%d]", state->config->tuner_address, start, len);
+		for (i = 0; i < len; i++)
+			dprintk(verbose, FE_DEBUG, 1, "        %s: 0x%02x", stb6100_regnames[start + i], buf[i]);
+	}
+	rc = i2c_transfer(state->i2c, &msg, 1);
+	if (unlikely(rc != 1)) {
+		dprintk(verbose, FE_ERROR, 1, "(0x%x) write err [%d:%d], rc=[%d]",
+			(unsigned int)state->config->tuner_address, start, len,	rc);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data)
+{
+	if (unlikely(reg >= STB6100_NUMREGS)) {
+		dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
+		return -EREMOTEIO;
+	}
+	data = (data & stb6100_template[reg].mask) | stb6100_template[reg].set;
+	return stb6100_write_reg_range(state, &data, reg, 1);
+}
+
+
+static int stb6100_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	int rc;
+	struct stb6100_state *state = fe->tuner_priv;
+
+	rc = stb6100_read_reg(state, STB6100_LD);
+	if (rc < 0) {
+		dprintk(verbose, FE_ERROR, 1, "%s failed", __func__);
+		return rc;
+	}
+	return (rc & STB6100_LD_LOCK) ? TUNER_STATUS_LOCKED : 0;
+}
+
+static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	int rc;
+	u8 f;
+	struct stb6100_state *state = fe->tuner_priv;
+
+	rc = stb6100_read_reg(state, STB6100_F);
+	if (rc < 0)
+		return rc;
+	f = rc & STB6100_F_F;
+
+	state->status.bandwidth = (f + 5) * 2000;	/* x2 for ZIF	*/
+
+	*bandwidth = state->bandwidth = state->status.bandwidth * 1000;
+	dprintk(verbose, FE_DEBUG, 1, "bandwidth = %u Hz", state->bandwidth);
+	return 0;
+}
+
+static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
+{
+	u32 tmp;
+	int rc;
+	struct stb6100_state *state = fe->tuner_priv;
+
+	dprintk(verbose, FE_DEBUG, 1, "set bandwidth to %u Hz", bandwidth);
+
+	bandwidth /= 2; /* ZIF */
+
+	if (bandwidth >= 36000000)	/* F[4:0] BW/2 max =31+5=36 mhz for F=31	*/
+		tmp = 31;
+	else if (bandwidth <= 5000000)	/* bw/2 min = 5Mhz for F=0			*/
+		tmp = 0;
+	else				/* if 5 < bw/2 < 36				*/
+		tmp = (bandwidth + 500000) / 1000000 - 5;
+
+	/* Turn on LPF bandwidth setting clock control,
+	 * set bandwidth, wait 10ms, turn off.
+	 */
+	rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d | STB6100_FCCK_FCCK);
+	if (rc < 0)
+		return rc;
+	rc = stb6100_write_reg(state, STB6100_F, 0xc0 | tmp);
+	if (rc < 0)
+		return rc;
+
+	msleep(5);  /*  This is dangerous as another (related) thread may start */
+
+	rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d);
+	if (rc < 0)
+		return rc;
+
+	msleep(10);  /*  This is dangerous as another (related) thread may start */
+
+	return 0;
+}
+
+static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	int rc;
+	u32 nint, nfrac, fvco;
+	int psd2, odiv;
+	struct stb6100_state *state = fe->tuner_priv;
+	u8 regs[STB6100_NUMREGS];
+
+	rc = stb6100_read_regs(state, regs);
+	if (rc < 0)
+		return rc;
+
+	odiv = (regs[STB6100_VCO] & STB6100_VCO_ODIV) >> STB6100_VCO_ODIV_SHIFT;
+	psd2 = (regs[STB6100_K] & STB6100_K_PSD2) >> STB6100_K_PSD2_SHIFT;
+	nint = regs[STB6100_NI];
+	nfrac = ((regs[STB6100_K] & STB6100_K_NF_MSB) << 8) | regs[STB6100_NF_LSB];
+	fvco = (nfrac * state->reference >> (9 - psd2)) + (nint * state->reference << psd2);
+	*frequency = state->frequency = fvco >> (odiv + 1);
+
+	dprintk(verbose, FE_DEBUG, 1,
+		"frequency = %u kHz, odiv = %u, psd2 = %u, fxtal = %u kHz, fvco = %u kHz, N(I) = %u, N(F) = %u",
+		state->frequency, odiv, psd2, state->reference,	fvco, nint, nfrac);
+	return 0;
+}
+
+
+static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
+{
+	int rc;
+	const struct stb6100_lkup *ptr;
+	struct stb6100_state *state = fe->tuner_priv;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+	u32 srate = 0, fvco, nint, nfrac;
+	u8 regs[STB6100_NUMREGS];
+	u8 g, psd2, odiv;
+
+	dprintk(verbose, FE_DEBUG, 1, "Version 2010-8-14 13:51");
+
+	if (fe->ops.get_frontend) {
+		dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters");
+		fe->ops.get_frontend(fe);
+	}
+	srate = p->symbol_rate;
+
+	/* Set up tuner cleanly, LPF calibration on */
+	rc = stb6100_write_reg(state, STB6100_FCCK, 0x4d | STB6100_FCCK_FCCK);
+	if (rc < 0)
+		return rc;  /* allow LPF calibration */
+
+	/* PLL Loop disabled, bias on, VCO on, synth on */
+	regs[STB6100_LPEN] = 0xeb;
+	rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]);
+	if (rc < 0)
+		return rc;
+
+	/* Program the registers with their data values */
+
+	/* VCO divide ratio (LO divide ratio, VCO prescaler enable).	*/
+	if (frequency <= 1075000)
+		odiv = 1;
+	else
+		odiv = 0;
+
+	/* VCO enabled, search clock off as per LL3.7, 3.4.1 */
+	regs[STB6100_VCO] = 0xe0 | (odiv << STB6100_VCO_ODIV_SHIFT);
+
+	/* OSM	*/
+	for (ptr = lkup;
+	     (ptr->val_high != 0) && !CHKRANGE(frequency, ptr->val_low, ptr->val_high);
+	     ptr++);
+
+	if (ptr->val_high == 0) {
+		printk(KERN_ERR "%s: frequency out of range: %u kHz\n", __func__, frequency);
+		return -EINVAL;
+	}
+	regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_OSM) | ptr->reg;
+	rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]);
+	if (rc < 0)
+		return rc;
+
+	if ((frequency > 1075000) && (frequency <= 1325000))
+		psd2 = 0;
+	else
+		psd2 = 1;
+	/* F(VCO) = F(LO) * (ODIV == 0 ? 2 : 4)			*/
+	fvco = frequency << (1 + odiv);
+	/* N(I) = floor(f(VCO) / (f(XTAL) * (PSD2 ? 2 : 1)))	*/
+	nint = fvco / (state->reference << psd2);
+	/* N(F) = round(f(VCO) / f(XTAL) * (PSD2 ? 2 : 1) - N(I)) * 2 ^ 9	*/
+	nfrac = DIV_ROUND_CLOSEST((fvco - (nint * state->reference << psd2))
+					 << (9 - psd2), state->reference);
+
+	/* NI */
+	regs[STB6100_NI] = nint;
+	rc = stb6100_write_reg(state, STB6100_NI, regs[STB6100_NI]);
+	if (rc < 0)
+		return rc;
+
+	/* NF */
+	regs[STB6100_NF_LSB] = nfrac;
+	rc = stb6100_write_reg(state, STB6100_NF_LSB, regs[STB6100_NF_LSB]);
+	if (rc < 0)
+		return rc;
+
+	/* K */
+	regs[STB6100_K] = (0x38 & ~STB6100_K_PSD2) | (psd2 << STB6100_K_PSD2_SHIFT);
+	regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_NF_MSB) | ((nfrac >> 8) & STB6100_K_NF_MSB);
+	rc = stb6100_write_reg(state, STB6100_K, regs[STB6100_K]);
+	if (rc < 0)
+		return rc;
+
+	/* G Baseband gain. */
+	if (srate >= 15000000)
+		g = 9;  /*  +4 dB */
+	else if (srate >= 5000000)
+		g = 11; /*  +8 dB */
+	else
+		g = 14; /* +14 dB */
+
+	regs[STB6100_G] = (0x10 & ~STB6100_G_G) | g;
+	regs[STB6100_G] &= ~STB6100_G_GCT; /* mask GCT */
+	regs[STB6100_G] |= (1 << 5); /* 2Vp-p Mode */
+	rc = stb6100_write_reg(state, STB6100_G, regs[STB6100_G]);
+	if (rc < 0)
+		return rc;
+
+	/* F we don't write as it is set up in BW set */
+
+	/* DLB set DC servo loop BW to 160Hz (LLA 3.8 / 2.1) */
+	regs[STB6100_DLB] = 0xcc;
+	rc = stb6100_write_reg(state, STB6100_DLB, regs[STB6100_DLB]);
+	if (rc < 0)
+		return rc;
+
+	dprintk(verbose, FE_DEBUG, 1,
+		"frequency = %u, srate = %u, g = %u, odiv = %u, psd2 = %u, fxtal = %u, osm = %u, fvco = %u, N(I) = %u, N(F) = %u",
+		frequency, srate, (unsigned int)g, (unsigned int)odiv,
+		(unsigned int)psd2, state->reference,
+		ptr->reg, fvco, nint, nfrac);
+
+	/* Set up the test registers */
+	regs[STB6100_TEST1] = 0x8f;
+	rc = stb6100_write_reg(state, STB6100_TEST1, regs[STB6100_TEST1]);
+	if (rc < 0)
+		return rc;
+	regs[STB6100_TEST3] = 0xde;
+	rc = stb6100_write_reg(state, STB6100_TEST3, regs[STB6100_TEST3]);
+	if (rc < 0)
+		return rc;
+
+	/* Bring up tuner according to LLA 3.7 3.4.1, step 2 */
+	regs[STB6100_LPEN] = 0xfb; /* PLL Loop enabled, bias on, VCO on, synth on */
+	rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]);
+	if (rc < 0)
+		return rc;
+
+	msleep(2);
+
+	/* Bring up tuner according to LLA 3.7 3.4.1, step 3 */
+	regs[STB6100_VCO] &= ~STB6100_VCO_OCK;		/* VCO fast search		*/
+	rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]);
+	if (rc < 0)
+		return rc;
+
+	msleep(10);  /*  This is dangerous as another (related) thread may start */ /* wait for LO to lock */
+
+	regs[STB6100_VCO] &= ~STB6100_VCO_OSCH;		/* vco search disabled		*/
+	regs[STB6100_VCO] |= STB6100_VCO_OCK;		/* search clock off		*/
+	rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]);
+	if (rc < 0)
+		return rc;
+
+	rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d);
+	if (rc < 0)
+		return rc;  /* Stop LPF calibration */
+
+	msleep(10);  /*  This is dangerous as another (related) thread may start */
+		     /* wait for stabilisation, (should not be necessary)		*/
+	return 0;
+}
+
+static int stb6100_sleep(struct dvb_frontend *fe)
+{
+	/* TODO: power down	*/
+	return 0;
+}
+
+static int stb6100_init(struct dvb_frontend *fe)
+{
+	struct stb6100_state *state = fe->tuner_priv;
+	struct tuner_state *status = &state->status;
+
+	status->tunerstep	= 125000;
+	status->ifreq		= 0;
+	status->refclock	= 27000000;	/* Hz	*/
+	status->iqsense		= 1;
+	status->bandwidth	= 36000;	/* kHz	*/
+	state->bandwidth	= status->bandwidth * 1000;	/* Hz	*/
+	state->reference	= status->refclock / 1000;	/* kHz	*/
+
+	/* Set default bandwidth. Modified, PN 13-May-10	*/
+	return 0;
+}
+
+static int stb6100_get_state(struct dvb_frontend *fe,
+			     enum tuner_param param,
+			     struct tuner_state *state)
+{
+	switch (param) {
+	case DVBFE_TUNER_FREQUENCY:
+		stb6100_get_frequency(fe, &state->frequency);
+		break;
+	case DVBFE_TUNER_TUNERSTEP:
+		break;
+	case DVBFE_TUNER_IFFREQ:
+		break;
+	case DVBFE_TUNER_BANDWIDTH:
+		stb6100_get_bandwidth(fe, &state->bandwidth);
+		break;
+	case DVBFE_TUNER_REFCLOCK:
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int stb6100_set_state(struct dvb_frontend *fe,
+			     enum tuner_param param,
+			     struct tuner_state *state)
+{
+	struct stb6100_state *tstate = fe->tuner_priv;
+
+	switch (param) {
+	case DVBFE_TUNER_FREQUENCY:
+		stb6100_set_frequency(fe, state->frequency);
+		tstate->frequency = state->frequency;
+		break;
+	case DVBFE_TUNER_TUNERSTEP:
+		break;
+	case DVBFE_TUNER_IFFREQ:
+		break;
+	case DVBFE_TUNER_BANDWIDTH:
+		stb6100_set_bandwidth(fe, state->bandwidth);
+		tstate->bandwidth = state->bandwidth;
+		break;
+	case DVBFE_TUNER_REFCLOCK:
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static struct dvb_tuner_ops stb6100_ops = {
+	.info = {
+		.name			= "STB6100 Silicon Tuner",
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_step		= 0,
+	},
+
+	.init		= stb6100_init,
+	.sleep          = stb6100_sleep,
+	.get_status	= stb6100_get_status,
+	.get_state	= stb6100_get_state,
+	.set_state	= stb6100_set_state,
+	.release	= stb6100_release
+};
+
+struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
+				    const struct stb6100_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct stb6100_state *state = NULL;
+
+	state = kzalloc(sizeof (struct stb6100_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	state->config		= config;
+	state->i2c		= i2c;
+	state->frontend		= fe;
+	state->reference	= config->refclock / 1000; /* kHz */
+	fe->tuner_priv		= state;
+	fe->ops.tuner_ops	= stb6100_ops;
+
+	printk("%s: Attaching STB6100 \n", __func__);
+	return fe;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static int stb6100_release(struct dvb_frontend *fe)
+{
+	struct stb6100_state *state = fe->tuner_priv;
+
+	fe->tuner_priv = NULL;
+	kfree(state);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(stb6100_attach);
+MODULE_PARM_DESC(verbose, "Set Verbosity level");
+
+MODULE_AUTHOR("Manu Abraham");
+MODULE_DESCRIPTION("STB6100 Silicon tuner");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/stb6100.h b/drivers/media/dvb-frontends/stb6100.h
new file mode 100644
index 0000000..2ab0966
--- /dev/null
+++ b/drivers/media/dvb-frontends/stb6100.h
@@ -0,0 +1,115 @@
+/*
+	STB6100 Silicon Tuner
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __STB_6100_REG_H
+#define __STB_6100_REG_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+#define STB6100_LD			0x00
+#define STB6100_LD_LOCK			(1 << 0)
+
+#define STB6100_VCO			0x01
+#define STB6100_VCO_OSCH		(0x01 << 7)
+#define STB6100_VCO_OSCH_SHIFT		7
+#define STB6100_VCO_OCK			(0x03 << 5)
+#define STB6100_VCO_OCK_SHIFT		5
+#define STB6100_VCO_ODIV		(0x01 << 4)
+#define STB6100_VCO_ODIV_SHIFT		4
+#define STB6100_VCO_OSM			(0x0f << 0)
+
+#define STB6100_NI			0x02
+#define STB6100_NF_LSB			0x03
+
+#define STB6100_K			0x04
+#define STB6100_K_PSD2			(0x01 << 2)
+#define STB6100_K_PSD2_SHIFT            2
+#define STB6100_K_NF_MSB		(0x03 << 0)
+
+#define STB6100_G			0x05
+#define STB6100_G_G			(0x0f << 0)
+#define STB6100_G_GCT			(0x07 << 5)
+
+#define STB6100_F			0x06
+#define STB6100_F_F			(0x1f << 0)
+
+#define STB6100_DLB			0x07
+
+#define STB6100_TEST1			0x08
+
+#define STB6100_FCCK			0x09
+#define STB6100_FCCK_FCCK		(0x01 << 6)
+
+#define STB6100_LPEN			0x0a
+#define STB6100_LPEN_LPEN		(0x01 << 4)
+#define STB6100_LPEN_SYNP		(0x01 << 5)
+#define STB6100_LPEN_OSCP		(0x01 << 6)
+#define STB6100_LPEN_BEN		(0x01 << 7)
+
+#define STB6100_TEST3			0x0b
+
+#define STB6100_NUMREGS                 0x0c
+
+
+#define INRANGE(val, x, y)		(((x <= val) && (val <= y)) ||		\
+					 ((y <= val) && (val <= x)) ? 1 : 0)
+
+#define CHKRANGE(val, x, y)		(((val >= x) && (val < y)) ? 1 : 0)
+
+struct stb6100_config {
+	u8	tuner_address;
+	u32	refclock;
+};
+
+struct stb6100_state {
+	struct i2c_adapter *i2c;
+
+	const struct stb6100_config	*config;
+	struct dvb_tuner_ops		ops;
+	struct dvb_frontend		*frontend;
+	struct tuner_state		status;
+
+	u32 frequency;
+	u32 srate;
+	u32 bandwidth;
+	u32 reference;
+};
+
+#if defined(CONFIG_DVB_STB6100) || (defined(CONFIG_DVB_STB6100_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
+					   const struct stb6100_config *config,
+					   struct i2c_adapter *i2c);
+
+#else
+
+static inline struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
+						  const struct stb6100_config *config,
+						  struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+#endif //CONFIG_DVB_STB6100
+
+#endif
diff --git a/drivers/media/dvb-frontends/stb6100_cfg.h b/drivers/media/dvb-frontends/stb6100_cfg.h
new file mode 100644
index 0000000..6314d18
--- /dev/null
+++ b/drivers/media/dvb-frontends/stb6100_cfg.h
@@ -0,0 +1,104 @@
+/*
+	STB6100 Silicon Tuner
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct dvb_frontend_ops	*frontend_ops = NULL;
+	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct tuner_state	t_state;
+	int err = 0;
+
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+	if (tuner_ops->get_state) {
+		if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
+			printk("%s: Invalid parameter\n", __func__);
+			return err;
+		}
+		*frequency = t_state.frequency;
+	}
+	return 0;
+}
+
+static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
+{
+	struct dvb_frontend_ops	*frontend_ops = NULL;
+	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct tuner_state	t_state;
+	int err = 0;
+
+	t_state.frequency = frequency;
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+	if (tuner_ops->set_state) {
+		if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
+			printk("%s: Invalid parameter\n", __func__);
+			return err;
+		}
+	}
+	return 0;
+}
+
+static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct dvb_frontend_ops	*frontend_ops = &fe->ops;
+	struct dvb_tuner_ops	*tuner_ops = &frontend_ops->tuner_ops;
+	struct tuner_state	t_state;
+	int err = 0;
+
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+	if (tuner_ops->get_state) {
+		if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
+			printk("%s: Invalid parameter\n", __func__);
+			return err;
+		}
+		*bandwidth = t_state.bandwidth;
+	}
+	return 0;
+}
+
+static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
+{
+	struct dvb_frontend_ops	*frontend_ops = NULL;
+	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct tuner_state	t_state;
+	int err = 0;
+
+	t_state.bandwidth = bandwidth;
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+	if (tuner_ops->set_state) {
+		if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
+			printk("%s: Invalid parameter\n", __func__);
+			return err;
+		}
+	}
+	return 0;
+}
diff --git a/drivers/media/dvb-frontends/stb6100_proc.h b/drivers/media/dvb-frontends/stb6100_proc.h
new file mode 100644
index 0000000..112163a
--- /dev/null
+++ b/drivers/media/dvb-frontends/stb6100_proc.h
@@ -0,0 +1,138 @@
+/*
+	STB6100 Silicon Tuner wrapper
+	Copyright (C)2009 Igor M. Liplianin (liplianin@me.by)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+static int stb6100_get_freq(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct dvb_frontend_ops	*frontend_ops = NULL;
+	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct tuner_state	state;
+	int err = 0;
+
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+	if (tuner_ops->get_state) {
+		if (frontend_ops->i2c_gate_ctrl)
+			frontend_ops->i2c_gate_ctrl(fe, 1);
+
+		err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &state);
+		if (err < 0) {
+			printk(KERN_ERR "%s: Invalid parameter\n", __func__);
+			return err;
+		}
+
+		if (frontend_ops->i2c_gate_ctrl)
+			frontend_ops->i2c_gate_ctrl(fe, 0);
+
+		*frequency = state.frequency;
+	}
+
+	return 0;
+}
+
+static int stb6100_set_freq(struct dvb_frontend *fe, u32 frequency)
+{
+	struct dvb_frontend_ops	*frontend_ops = NULL;
+	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct tuner_state	state;
+	int err = 0;
+
+	state.frequency = frequency;
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+	if (tuner_ops->set_state) {
+		if (frontend_ops->i2c_gate_ctrl)
+			frontend_ops->i2c_gate_ctrl(fe, 1);
+
+		err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &state);
+		if (err < 0) {
+			printk(KERN_ERR "%s: Invalid parameter\n", __func__);
+			return err;
+		}
+
+		if (frontend_ops->i2c_gate_ctrl)
+			frontend_ops->i2c_gate_ctrl(fe, 0);
+
+	}
+
+	return 0;
+}
+
+static int stb6100_get_bandw(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct dvb_frontend_ops	*frontend_ops = NULL;
+	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct tuner_state	state;
+	int err = 0;
+
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+	if (tuner_ops->get_state) {
+		if (frontend_ops->i2c_gate_ctrl)
+			frontend_ops->i2c_gate_ctrl(fe, 1);
+
+		err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &state);
+		if (err < 0) {
+			printk(KERN_ERR "%s: Invalid parameter\n", __func__);
+			return err;
+		}
+
+		if (frontend_ops->i2c_gate_ctrl)
+			frontend_ops->i2c_gate_ctrl(fe, 0);
+
+		*bandwidth = state.bandwidth;
+	}
+
+	return 0;
+}
+
+static int stb6100_set_bandw(struct dvb_frontend *fe, u32 bandwidth)
+{
+	struct dvb_frontend_ops	*frontend_ops = NULL;
+	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct tuner_state	state;
+	int err = 0;
+
+	state.bandwidth = bandwidth;
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+	if (tuner_ops->set_state) {
+		if (frontend_ops->i2c_gate_ctrl)
+			frontend_ops->i2c_gate_ctrl(fe, 1);
+
+		err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &state);
+		if (err < 0) {
+			printk(KERN_ERR "%s: Invalid parameter\n", __func__);
+			return err;
+		}
+
+		if (frontend_ops->i2c_gate_ctrl)
+			frontend_ops->i2c_gate_ctrl(fe, 0);
+
+	}
+
+	return 0;
+}
diff --git a/drivers/media/dvb-frontends/stv0288.c b/drivers/media/dvb-frontends/stv0288.c
new file mode 100644
index 0000000..632b251
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv0288.c
@@ -0,0 +1,626 @@
+/*
+	Driver for ST STV0288 demodulator
+	Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de
+		for Reel Multimedia
+	Copyright (C) 2008 TurboSight.com, Bob Liu <bob@turbosight.com>
+	Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
+		Removed stb6000 specific tuner code and revised some
+		procedures.
+	2010-09-01 Josef Pavlik <josef@pavlik.it>
+		Fixed diseqc_msg, diseqc_burst and set_tone problems
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "stv0288.h"
+
+struct stv0288_state {
+	struct i2c_adapter *i2c;
+	const struct stv0288_config *config;
+	struct dvb_frontend frontend;
+
+	u8 initialised:1;
+	u32 tuner_frequency;
+	u32 symbol_rate;
+	fe_code_rate_t fec_inner;
+	int errmode;
+};
+
+#define STATUS_BER 0
+#define STATUS_UCBLOCKS 1
+
+static int debug;
+static int debug_legacy_dish_switch;
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG "stv0288: " args); \
+	} while (0)
+
+
+static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = {
+		.addr = state->config->demod_address,
+		.flags = 0,
+		.buf = buf,
+		.len = 2
+	};
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
+			"ret == %i)\n", __func__, reg, data, ret);
+
+	return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int stv0288_write(struct dvb_frontend *fe, const u8 buf[], int len)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	if (len != 2)
+		return -EINVAL;
+
+	return stv0288_writeregI(state, buf[0], buf[1]);
+}
+
+static u8 stv0288_readreg(struct stv0288_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{
+			.addr = state->config->demod_address,
+			.flags = 0,
+			.buf = b0,
+			.len = 1
+		}, {
+			.addr = state->config->demod_address,
+			.flags = I2C_M_RD,
+			.buf = b1,
+			.len = 1
+		}
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
+				__func__, reg, ret);
+
+	return b1[0];
+}
+
+static int stv0288_set_symbolrate(struct dvb_frontend *fe, u32 srate)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+	unsigned int temp;
+	unsigned char b[3];
+
+	if ((srate < 1000000) || (srate > 45000000))
+		return -EINVAL;
+
+	stv0288_writeregI(state, 0x22, 0);
+	stv0288_writeregI(state, 0x23, 0);
+	stv0288_writeregI(state, 0x2b, 0xff);
+	stv0288_writeregI(state, 0x2c, 0xf7);
+
+	temp = (unsigned int)srate / 1000;
+
+		temp = temp * 32768;
+		temp = temp / 25;
+		temp = temp / 125;
+		b[0] = (unsigned char)((temp >> 12) & 0xff);
+		b[1] = (unsigned char)((temp >> 4) & 0xff);
+		b[2] = (unsigned char)((temp << 4) & 0xf0);
+		stv0288_writeregI(state, 0x28, 0x80); /* SFRH */
+		stv0288_writeregI(state, 0x29, 0); /* SFRM */
+		stv0288_writeregI(state, 0x2a, 0); /* SFRL */
+
+		stv0288_writeregI(state, 0x28, b[0]);
+		stv0288_writeregI(state, 0x29, b[1]);
+		stv0288_writeregI(state, 0x2a, b[2]);
+		dprintk("stv0288: stv0288_set_symbolrate\n");
+
+	return 0;
+}
+
+static int stv0288_send_diseqc_msg(struct dvb_frontend *fe,
+				    struct dvb_diseqc_master_cmd *m)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	int i;
+
+	dprintk("%s\n", __func__);
+
+	stv0288_writeregI(state, 0x09, 0);
+	msleep(30);
+	stv0288_writeregI(state, 0x05, 0x12);/* modulated mode, single shot */
+
+	for (i = 0; i < m->msg_len; i++) {
+		if (stv0288_writeregI(state, 0x06, m->msg[i]))
+			return -EREMOTEIO;
+	}
+	msleep(m->msg_len*12);
+	return 0;
+}
+
+static int stv0288_send_diseqc_burst(struct dvb_frontend *fe,
+						fe_sec_mini_cmd_t burst)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	if (stv0288_writeregI(state, 0x05, 0x03))/* burst mode, single shot */
+		return -EREMOTEIO;
+
+	if (stv0288_writeregI(state, 0x06, burst == SEC_MINI_A ? 0x00 : 0xff))
+		return -EREMOTEIO;
+
+	msleep(15);
+	if (stv0288_writeregI(state, 0x05, 0x12))
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int stv0288_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		if (stv0288_writeregI(state, 0x05, 0x10))/* cont carrier */
+			return -EREMOTEIO;
+	break;
+
+	case SEC_TONE_OFF:
+		if (stv0288_writeregI(state, 0x05, 0x12))/* burst mode off*/
+			return -EREMOTEIO;
+	break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static u8 stv0288_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x20,
+	0x09, 0x0,
+	0x0a, 0x4,
+	0x0b, 0x0,
+	0x0c, 0x0,
+	0x0d, 0x0,
+	0x0e, 0xd4,
+	0x0f, 0x30,
+	0x11, 0x80,
+	0x12, 0x03,
+	0x13, 0x48,
+	0x14, 0x84,
+	0x15, 0x45,
+	0x16, 0xb7,
+	0x17, 0x9c,
+	0x18, 0x0,
+	0x19, 0xa6,
+	0x1a, 0x88,
+	0x1b, 0x8f,
+	0x1c, 0xf0,
+	0x20, 0x0b,
+	0x21, 0x54,
+	0x22, 0x0,
+	0x23, 0x0,
+	0x2b, 0xff,
+	0x2c, 0xf7,
+	0x30, 0x0,
+	0x31, 0x1e,
+	0x32, 0x14,
+	0x33, 0x0f,
+	0x34, 0x09,
+	0x35, 0x0c,
+	0x36, 0x05,
+	0x37, 0x2f,
+	0x38, 0x16,
+	0x39, 0xbe,
+	0x3a, 0x0,
+	0x3b, 0x13,
+	0x3c, 0x11,
+	0x3d, 0x30,
+	0x40, 0x63,
+	0x41, 0x04,
+	0x42, 0x20,
+	0x43, 0x00,
+	0x44, 0x00,
+	0x45, 0x00,
+	0x46, 0x00,
+	0x47, 0x00,
+	0x4a, 0x00,
+	0x50, 0x10,
+	0x51, 0x38,
+	0x52, 0x21,
+	0x58, 0x54,
+	0x59, 0x86,
+	0x5a, 0x0,
+	0x5b, 0x9b,
+	0x5c, 0x08,
+	0x5d, 0x7f,
+	0x5e, 0x0,
+	0x5f, 0xff,
+	0x70, 0x0,
+	0x71, 0x0,
+	0x72, 0x0,
+	0x74, 0x0,
+	0x75, 0x0,
+	0x76, 0x0,
+	0x81, 0x0,
+	0x82, 0x3f,
+	0x83, 0x3f,
+	0x84, 0x0,
+	0x85, 0x0,
+	0x88, 0x0,
+	0x89, 0x0,
+	0x8a, 0x0,
+	0x8b, 0x0,
+	0x8c, 0x0,
+	0x90, 0x0,
+	0x91, 0x0,
+	0x92, 0x0,
+	0x93, 0x0,
+	0x94, 0x1c,
+	0x97, 0x0,
+	0xa0, 0x48,
+	0xa1, 0x0,
+	0xb0, 0xb8,
+	0xb1, 0x3a,
+	0xb2, 0x10,
+	0xb3, 0x82,
+	0xb4, 0x80,
+	0xb5, 0x82,
+	0xb6, 0x82,
+	0xb7, 0x82,
+	0xb8, 0x20,
+	0xb9, 0x0,
+	0xf0, 0x0,
+	0xf1, 0x0,
+	0xf2, 0xc0,
+	0x51, 0x36,
+	0x52, 0x09,
+	0x53, 0x94,
+	0x54, 0x62,
+	0x55, 0x29,
+	0x56, 0x64,
+	0x57, 0x2b,
+	0xff, 0xff,
+};
+
+static int stv0288_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
+{
+	dprintk("%s: %s\n", __func__,
+		volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+		volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
+
+	return 0;
+}
+
+static int stv0288_init(struct dvb_frontend *fe)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+	int i;
+	u8 reg;
+	u8 val;
+
+	dprintk("stv0288: init chip\n");
+	stv0288_writeregI(state, 0x41, 0x04);
+	msleep(50);
+
+	/* we have default inittab */
+	if (state->config->inittab == NULL) {
+		for (i = 0; !(stv0288_inittab[i] == 0xff &&
+				stv0288_inittab[i + 1] == 0xff); i += 2)
+			stv0288_writeregI(state, stv0288_inittab[i],
+					stv0288_inittab[i + 1]);
+	} else {
+		for (i = 0; ; i += 2)  {
+			reg = state->config->inittab[i];
+			val = state->config->inittab[i+1];
+			if (reg == 0xff && val == 0xff)
+				break;
+			stv0288_writeregI(state, reg, val);
+		}
+	}
+	return 0;
+}
+
+static int stv0288_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	u8 sync = stv0288_readreg(state, 0x24);
+	if (sync == 255)
+		sync = 0;
+
+	dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync);
+
+	*status = 0;
+	if (sync & 0x80)
+		*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+	if (sync & 0x10)
+		*status |= FE_HAS_VITERBI;
+	if (sync & 0x08) {
+		*status |= FE_HAS_LOCK;
+		dprintk("stv0288 has locked\n");
+	}
+
+	return 0;
+}
+
+static int stv0288_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	if (state->errmode != STATUS_BER)
+		return 0;
+	*ber = (stv0288_readreg(state, 0x26) << 8) |
+					stv0288_readreg(state, 0x27);
+	dprintk("stv0288_read_ber %d\n", *ber);
+
+	return 0;
+}
+
+
+static int stv0288_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	s32 signal =  0xffff - ((stv0288_readreg(state, 0x10) << 8));
+
+
+	signal = signal * 5 / 4;
+	*strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal;
+	dprintk("stv0288_read_signal_strength %d\n", *strength);
+
+	return 0;
+}
+static int stv0288_sleep(struct dvb_frontend *fe)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	stv0288_writeregI(state, 0x41, 0x84);
+	state->initialised = 0;
+
+	return 0;
+}
+static int stv0288_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	s32 xsnr = 0xffff - ((stv0288_readreg(state, 0x2d) << 8)
+			   | stv0288_readreg(state, 0x2e));
+	xsnr = 3 * (xsnr - 0xa100);
+	*snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
+	dprintk("stv0288_read_snr %d\n", *snr);
+
+	return 0;
+}
+
+static int stv0288_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	if (state->errmode != STATUS_BER)
+		return 0;
+	*ucblocks = (stv0288_readreg(state, 0x26) << 8) |
+					stv0288_readreg(state, 0x27);
+	dprintk("stv0288_read_ber %d\n", *ucblocks);
+
+	return 0;
+}
+
+static int stv0288_set_property(struct dvb_frontend *fe, struct dtv_property *p)
+{
+	dprintk("%s(..)\n", __func__);
+	return 0;
+}
+
+static int stv0288_set_frontend(struct dvb_frontend *fe)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+	char tm;
+	unsigned char tda[3];
+	u8 reg, time_out = 0;
+
+	dprintk("%s : FE_SET_FRONTEND\n", __func__);
+
+	if (c->delivery_system != SYS_DVBS) {
+			dprintk("%s: unsupported delivery "
+				"system selected (%d)\n",
+				__func__, c->delivery_system);
+			return -EOPNOTSUPP;
+	}
+
+	if (state->config->set_ts_params)
+		state->config->set_ts_params(fe, 0);
+
+	/* only frequency & symbol_rate are used for tuner*/
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	udelay(10);
+	stv0288_set_symbolrate(fe, c->symbol_rate);
+	/* Carrier lock control register */
+	stv0288_writeregI(state, 0x15, 0xc5);
+
+	tda[2] = 0x0; /* CFRL */
+	for (tm = -9; tm < 7;) {
+		/* Viterbi status */
+		reg = stv0288_readreg(state, 0x24);
+		if (reg & 0x8)
+				break;
+		if (reg & 0x80) {
+			time_out++;
+			if (time_out > 10)
+				break;
+			tda[2] += 40;
+			if (tda[2] < 40)
+				tm++;
+		} else {
+			tm++;
+			tda[2] = 0;
+			time_out = 0;
+		}
+		tda[1] = (unsigned char)tm;
+		stv0288_writeregI(state, 0x2b, tda[1]);
+		stv0288_writeregI(state, 0x2c, tda[2]);
+		msleep(30);
+	}
+	state->tuner_frequency = c->frequency;
+	state->fec_inner = FEC_AUTO;
+	state->symbol_rate = c->symbol_rate;
+
+	return 0;
+}
+
+static int stv0288_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+
+	if (enable)
+		stv0288_writeregI(state, 0x01, 0xb5);
+	else
+		stv0288_writeregI(state, 0x01, 0x35);
+
+	udelay(1);
+
+	return 0;
+}
+
+static void stv0288_release(struct dvb_frontend *fe)
+{
+	struct stv0288_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops stv0288_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name			= "ST STV0288 DVB-S",
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 1000,	 /* kHz for QPSK frontends */
+		.frequency_tolerance	= 0,
+		.symbol_rate_min	= 1000000,
+		.symbol_rate_max	= 45000000,
+		.symbol_rate_tolerance	= 500,	/* ppm */
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+		      FE_CAN_QPSK |
+		      FE_CAN_FEC_AUTO
+	},
+
+	.release = stv0288_release,
+	.init = stv0288_init,
+	.sleep = stv0288_sleep,
+	.write = stv0288_write,
+	.i2c_gate_ctrl = stv0288_i2c_gate_ctrl,
+	.read_status = stv0288_read_status,
+	.read_ber = stv0288_read_ber,
+	.read_signal_strength = stv0288_read_signal_strength,
+	.read_snr = stv0288_read_snr,
+	.read_ucblocks = stv0288_read_ucblocks,
+	.diseqc_send_master_cmd = stv0288_send_diseqc_msg,
+	.diseqc_send_burst = stv0288_send_diseqc_burst,
+	.set_tone = stv0288_set_tone,
+	.set_voltage = stv0288_set_voltage,
+
+	.set_property = stv0288_set_property,
+	.set_frontend = stv0288_set_frontend,
+};
+
+struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct stv0288_state *state = NULL;
+	int id;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct stv0288_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->initialised = 0;
+	state->tuner_frequency = 0;
+	state->symbol_rate = 0;
+	state->fec_inner = 0;
+	state->errmode = STATUS_BER;
+
+	stv0288_writeregI(state, 0x41, 0x04);
+	msleep(200);
+	id = stv0288_readreg(state, 0x00);
+	dprintk("stv0288 id %x\n", id);
+
+	/* register 0x00 contains 0x11 for STV0288  */
+	if (id != 0x11)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &stv0288_ops,
+			sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+
+	return NULL;
+}
+EXPORT_SYMBOL(stv0288_attach);
+
+module_param(debug_legacy_dish_switch, int, 0444);
+MODULE_PARM_DESC(debug_legacy_dish_switch,
+		"Enable timing analysis for Dish Network legacy switches");
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("ST STV0288 DVB Demodulator driver");
+MODULE_AUTHOR("Georg Acher, Bob Liu, Igor liplianin");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/media/dvb-frontends/stv0288.h b/drivers/media/dvb-frontends/stv0288.h
new file mode 100644
index 0000000..f2b53db
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv0288.h
@@ -0,0 +1,67 @@
+/*
+	Driver for ST STV0288 demodulator
+
+	Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de
+		for Reel Multimedia
+	Copyright (C) 2008 TurboSight.com, <bob@turbosight.com>
+	Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
+		Removed stb6000 specific tuner code and revised some
+		procedures.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef STV0288_H
+#define STV0288_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct stv0288_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	u8* inittab;
+
+	/* minimum delay before retuning */
+	int min_delay_ms;
+
+	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
+};
+
+#if defined(CONFIG_DVB_STV0288) || (defined(CONFIG_DVB_STV0288_MODULE) && \
+							defined(MODULE))
+extern struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
+					   struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
+					   struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_STV0288 */
+
+static inline int stv0288_writereg(struct dvb_frontend *fe, u8 reg, u8 val)
+{
+	int r = 0;
+	u8 buf[] = { reg, val };
+	if (fe->ops.write)
+		r = fe->ops.write(fe, buf, 2);
+	return r;
+}
+
+#endif /* STV0288_H */
diff --git a/drivers/media/dvb-frontends/stv0297.c b/drivers/media/dvb-frontends/stv0297.c
new file mode 100644
index 0000000..d40f226
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv0297.c
@@ -0,0 +1,722 @@
+/*
+    Driver for STV0297 demodulator
+
+    Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.net>
+    Copyright (C) 2003-2004 Dennis Noermann <dennis.noermann@noernet.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "stv0297.h"
+
+struct stv0297_state {
+	struct i2c_adapter *i2c;
+	const struct stv0297_config *config;
+	struct dvb_frontend frontend;
+
+	unsigned long last_ber;
+	unsigned long base_freq;
+};
+
+#if 1
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+#define STV0297_CLOCK_KHZ   28900
+
+
+static int stv0297_writereg(struct stv0297_state *state, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 2 };
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
+			"ret == %i)\n", __func__, reg, data, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+
+static int stv0297_readreg(struct stv0297_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1},
+				 {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
+			       };
+
+	// this device needs a STOP between the register and data
+	if (state->config->stop_during_read) {
+		if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret);
+			return -1;
+		}
+		if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret);
+			return -1;
+		}
+	} else {
+		if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret);
+			return -1;
+		}
+	}
+
+	return b1[0];
+}
+
+static int stv0297_writereg_mask(struct stv0297_state *state, u8 reg, u8 mask, u8 data)
+{
+	int val;
+
+	val = stv0297_readreg(state, reg);
+	val &= ~mask;
+	val |= (data & mask);
+	stv0297_writereg(state, reg, val);
+
+	return 0;
+}
+
+static int stv0297_readregs(struct stv0297_state *state, u8 reg1, u8 * b, u8 len)
+{
+	int ret;
+	struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf =
+				  &reg1,.len = 1},
+	{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b,.len = len}
+	};
+
+	// this device needs a STOP between the register and data
+	if (state->config->stop_during_read) {
+		if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret);
+			return -1;
+		}
+		if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret);
+			return -1;
+		}
+	} else {
+		if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static u32 stv0297_get_symbolrate(struct stv0297_state *state)
+{
+	u64 tmp;
+
+	tmp = stv0297_readreg(state, 0x55);
+	tmp |= stv0297_readreg(state, 0x56) << 8;
+	tmp |= stv0297_readreg(state, 0x57) << 16;
+	tmp |= stv0297_readreg(state, 0x58) << 24;
+
+	tmp *= STV0297_CLOCK_KHZ;
+	tmp >>= 32;
+
+	return (u32) tmp;
+}
+
+static void stv0297_set_symbolrate(struct stv0297_state *state, u32 srate)
+{
+	long tmp;
+
+	tmp = 131072L * srate;	/* 131072 = 2^17  */
+	tmp = tmp / (STV0297_CLOCK_KHZ / 4);	/* 1/4 = 2^-2 */
+	tmp = tmp * 8192L;	/* 8192 = 2^13 */
+
+	stv0297_writereg(state, 0x55, (unsigned char) (tmp & 0xFF));
+	stv0297_writereg(state, 0x56, (unsigned char) (tmp >> 8));
+	stv0297_writereg(state, 0x57, (unsigned char) (tmp >> 16));
+	stv0297_writereg(state, 0x58, (unsigned char) (tmp >> 24));
+}
+
+static void stv0297_set_sweeprate(struct stv0297_state *state, short fshift, long symrate)
+{
+	long tmp;
+
+	tmp = (long) fshift *262144L;	/* 262144 = 2*18 */
+	tmp /= symrate;
+	tmp *= 1024;		/* 1024 = 2*10   */
+
+	// adjust
+	if (tmp >= 0) {
+		tmp += 500000;
+	} else {
+		tmp -= 500000;
+	}
+	tmp /= 1000000;
+
+	stv0297_writereg(state, 0x60, tmp & 0xFF);
+	stv0297_writereg_mask(state, 0x69, 0xF0, (tmp >> 4) & 0xf0);
+}
+
+static void stv0297_set_carrieroffset(struct stv0297_state *state, long offset)
+{
+	long tmp;
+
+	/* symrate is hardcoded to 10000 */
+	tmp = offset * 26844L;	/* (2**28)/10000 */
+	if (tmp < 0)
+		tmp += 0x10000000;
+	tmp &= 0x0FFFFFFF;
+
+	stv0297_writereg(state, 0x66, (unsigned char) (tmp & 0xFF));
+	stv0297_writereg(state, 0x67, (unsigned char) (tmp >> 8));
+	stv0297_writereg(state, 0x68, (unsigned char) (tmp >> 16));
+	stv0297_writereg_mask(state, 0x69, 0x0F, (tmp >> 24) & 0x0f);
+}
+
+/*
+static long stv0297_get_carrieroffset(struct stv0297_state *state)
+{
+	s64 tmp;
+
+	stv0297_writereg(state, 0x6B, 0x00);
+
+	tmp = stv0297_readreg(state, 0x66);
+	tmp |= (stv0297_readreg(state, 0x67) << 8);
+	tmp |= (stv0297_readreg(state, 0x68) << 16);
+	tmp |= (stv0297_readreg(state, 0x69) & 0x0F) << 24;
+
+	tmp *= stv0297_get_symbolrate(state);
+	tmp >>= 28;
+
+	return (s32) tmp;
+}
+*/
+
+static void stv0297_set_initialdemodfreq(struct stv0297_state *state, long freq)
+{
+	s32 tmp;
+
+	if (freq > 10000)
+		freq -= STV0297_CLOCK_KHZ;
+
+	tmp = (STV0297_CLOCK_KHZ * 1000) / (1 << 16);
+	tmp = (freq * 1000) / tmp;
+	if (tmp > 0xffff)
+		tmp = 0xffff;
+
+	stv0297_writereg_mask(state, 0x25, 0x80, 0x80);
+	stv0297_writereg(state, 0x21, tmp >> 8);
+	stv0297_writereg(state, 0x20, tmp);
+}
+
+static int stv0297_set_qam(struct stv0297_state *state, fe_modulation_t modulation)
+{
+	int val = 0;
+
+	switch (modulation) {
+	case QAM_16:
+		val = 0;
+		break;
+
+	case QAM_32:
+		val = 1;
+		break;
+
+	case QAM_64:
+		val = 4;
+		break;
+
+	case QAM_128:
+		val = 2;
+		break;
+
+	case QAM_256:
+		val = 3;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	stv0297_writereg_mask(state, 0x00, 0x70, val << 4);
+
+	return 0;
+}
+
+static int stv0297_set_inversion(struct stv0297_state *state, fe_spectral_inversion_t inversion)
+{
+	int val = 0;
+
+	switch (inversion) {
+	case INVERSION_OFF:
+		val = 0;
+		break;
+
+	case INVERSION_ON:
+		val = 1;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	stv0297_writereg_mask(state, 0x83, 0x08, val << 3);
+
+	return 0;
+}
+
+static int stv0297_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct stv0297_state *state = fe->demodulator_priv;
+
+	if (enable) {
+		stv0297_writereg(state, 0x87, 0x78);
+		stv0297_writereg(state, 0x86, 0xc8);
+	}
+
+	return 0;
+}
+
+static int stv0297_init(struct dvb_frontend *fe)
+{
+	struct stv0297_state *state = fe->demodulator_priv;
+	int i;
+
+	/* load init table */
+	for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2)
+		stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]);
+	msleep(200);
+
+	state->last_ber = 0;
+
+	return 0;
+}
+
+static int stv0297_sleep(struct dvb_frontend *fe)
+{
+	struct stv0297_state *state = fe->demodulator_priv;
+
+	stv0297_writereg_mask(state, 0x80, 1, 1);
+
+	return 0;
+}
+
+static int stv0297_read_status(struct dvb_frontend *fe, fe_status_t * status)
+{
+	struct stv0297_state *state = fe->demodulator_priv;
+
+	u8 sync = stv0297_readreg(state, 0xDF);
+
+	*status = 0;
+	if (sync & 0x80)
+		*status |=
+			FE_HAS_SYNC | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK;
+	return 0;
+}
+
+static int stv0297_read_ber(struct dvb_frontend *fe, u32 * ber)
+{
+	struct stv0297_state *state = fe->demodulator_priv;
+	u8 BER[3];
+
+	stv0297_readregs(state, 0xA0, BER, 3);
+	if (!(BER[0] & 0x80)) {
+		state->last_ber = BER[2] << 8 | BER[1];
+		stv0297_writereg_mask(state, 0xA0, 0x80, 0x80);
+	}
+
+	*ber = state->last_ber;
+
+	return 0;
+}
+
+
+static int stv0297_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+{
+	struct stv0297_state *state = fe->demodulator_priv;
+	u8 STRENGTH[3];
+	u16 tmp;
+
+	stv0297_readregs(state, 0x41, STRENGTH, 3);
+	tmp = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0];
+	if (STRENGTH[2] & 0x20) {
+		if (tmp < 0x200)
+			tmp = 0;
+		else
+			tmp = tmp - 0x200;
+	} else {
+		if (tmp > 0x1ff)
+			tmp = 0;
+		else
+			tmp = 0x1ff - tmp;
+	}
+	*strength = (tmp << 7) | (tmp >> 2);
+	return 0;
+}
+
+static int stv0297_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+	struct stv0297_state *state = fe->demodulator_priv;
+	u8 SNR[2];
+
+	stv0297_readregs(state, 0x07, SNR, 2);
+	*snr = SNR[1] << 8 | SNR[0];
+
+	return 0;
+}
+
+static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
+{
+	struct stv0297_state *state = fe->demodulator_priv;
+
+	stv0297_writereg_mask(state, 0xDF, 0x03, 0x03); /* freeze the counters */
+
+	*ucblocks = (stv0297_readreg(state, 0xD5) << 8)
+		| stv0297_readreg(state, 0xD4);
+
+	stv0297_writereg_mask(state, 0xDF, 0x03, 0x02); /* clear the counters */
+	stv0297_writereg_mask(state, 0xDF, 0x03, 0x01); /* re-enable the counters */
+
+	return 0;
+}
+
+static int stv0297_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct stv0297_state *state = fe->demodulator_priv;
+	int u_threshold;
+	int initial_u;
+	int blind_u;
+	int delay;
+	int sweeprate;
+	int carrieroffset;
+	unsigned long timeout;
+	fe_spectral_inversion_t inversion;
+
+	switch (p->modulation) {
+	case QAM_16:
+	case QAM_32:
+	case QAM_64:
+		delay = 100;
+		sweeprate = 1000;
+		break;
+
+	case QAM_128:
+	case QAM_256:
+		delay = 200;
+		sweeprate = 500;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	// determine inversion dependent parameters
+	inversion = p->inversion;
+	if (state->config->invert)
+		inversion = (inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON;
+	carrieroffset = -330;
+	switch (inversion) {
+	case INVERSION_OFF:
+		break;
+
+	case INVERSION_ON:
+		sweeprate = -sweeprate;
+		carrieroffset = -carrieroffset;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	stv0297_init(fe);
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	/* clear software interrupts */
+	stv0297_writereg(state, 0x82, 0x0);
+
+	/* set initial demodulation frequency */
+	stv0297_set_initialdemodfreq(state, 7250);
+
+	/* setup AGC */
+	stv0297_writereg_mask(state, 0x43, 0x10, 0x00);
+	stv0297_writereg(state, 0x41, 0x00);
+	stv0297_writereg_mask(state, 0x42, 0x03, 0x01);
+	stv0297_writereg_mask(state, 0x36, 0x60, 0x00);
+	stv0297_writereg_mask(state, 0x36, 0x18, 0x00);
+	stv0297_writereg_mask(state, 0x71, 0x80, 0x80);
+	stv0297_writereg(state, 0x72, 0x00);
+	stv0297_writereg(state, 0x73, 0x00);
+	stv0297_writereg_mask(state, 0x74, 0x0F, 0x00);
+	stv0297_writereg_mask(state, 0x43, 0x08, 0x00);
+	stv0297_writereg_mask(state, 0x71, 0x80, 0x00);
+
+	/* setup STL */
+	stv0297_writereg_mask(state, 0x5a, 0x20, 0x20);
+	stv0297_writereg_mask(state, 0x5b, 0x02, 0x02);
+	stv0297_writereg_mask(state, 0x5b, 0x02, 0x00);
+	stv0297_writereg_mask(state, 0x5b, 0x01, 0x00);
+	stv0297_writereg_mask(state, 0x5a, 0x40, 0x40);
+
+	/* disable frequency sweep */
+	stv0297_writereg_mask(state, 0x6a, 0x01, 0x00);
+
+	/* reset deinterleaver */
+	stv0297_writereg_mask(state, 0x81, 0x01, 0x01);
+	stv0297_writereg_mask(state, 0x81, 0x01, 0x00);
+
+	/* ??? */
+	stv0297_writereg_mask(state, 0x83, 0x20, 0x20);
+	stv0297_writereg_mask(state, 0x83, 0x20, 0x00);
+
+	/* reset equaliser */
+	u_threshold = stv0297_readreg(state, 0x00) & 0xf;
+	initial_u = stv0297_readreg(state, 0x01) >> 4;
+	blind_u = stv0297_readreg(state, 0x01) & 0xf;
+	stv0297_writereg_mask(state, 0x84, 0x01, 0x01);
+	stv0297_writereg_mask(state, 0x84, 0x01, 0x00);
+	stv0297_writereg_mask(state, 0x00, 0x0f, u_threshold);
+	stv0297_writereg_mask(state, 0x01, 0xf0, initial_u << 4);
+	stv0297_writereg_mask(state, 0x01, 0x0f, blind_u);
+
+	/* data comes from internal A/D */
+	stv0297_writereg_mask(state, 0x87, 0x80, 0x00);
+
+	/* clear phase registers */
+	stv0297_writereg(state, 0x63, 0x00);
+	stv0297_writereg(state, 0x64, 0x00);
+	stv0297_writereg(state, 0x65, 0x00);
+	stv0297_writereg(state, 0x66, 0x00);
+	stv0297_writereg(state, 0x67, 0x00);
+	stv0297_writereg(state, 0x68, 0x00);
+	stv0297_writereg_mask(state, 0x69, 0x0f, 0x00);
+
+	/* set parameters */
+	stv0297_set_qam(state, p->modulation);
+	stv0297_set_symbolrate(state, p->symbol_rate / 1000);
+	stv0297_set_sweeprate(state, sweeprate, p->symbol_rate / 1000);
+	stv0297_set_carrieroffset(state, carrieroffset);
+	stv0297_set_inversion(state, inversion);
+
+	/* kick off lock */
+	/* Disable corner detection for higher QAMs */
+	if (p->modulation == QAM_128 ||
+		p->modulation == QAM_256)
+		stv0297_writereg_mask(state, 0x88, 0x08, 0x00);
+	else
+		stv0297_writereg_mask(state, 0x88, 0x08, 0x08);
+
+	stv0297_writereg_mask(state, 0x5a, 0x20, 0x00);
+	stv0297_writereg_mask(state, 0x6a, 0x01, 0x01);
+	stv0297_writereg_mask(state, 0x43, 0x40, 0x40);
+	stv0297_writereg_mask(state, 0x5b, 0x30, 0x00);
+	stv0297_writereg_mask(state, 0x03, 0x0c, 0x0c);
+	stv0297_writereg_mask(state, 0x03, 0x03, 0x03);
+	stv0297_writereg_mask(state, 0x43, 0x10, 0x10);
+
+	/* wait for WGAGC lock */
+	timeout = jiffies + msecs_to_jiffies(2000);
+	while (time_before(jiffies, timeout)) {
+		msleep(10);
+		if (stv0297_readreg(state, 0x43) & 0x08)
+			break;
+	}
+	if (time_after(jiffies, timeout)) {
+		goto timeout;
+	}
+	msleep(20);
+
+	/* wait for equaliser partial convergence */
+	timeout = jiffies + msecs_to_jiffies(500);
+	while (time_before(jiffies, timeout)) {
+		msleep(10);
+
+		if (stv0297_readreg(state, 0x82) & 0x04) {
+			break;
+		}
+	}
+	if (time_after(jiffies, timeout)) {
+		goto timeout;
+	}
+
+	/* wait for equaliser full convergence */
+	timeout = jiffies + msecs_to_jiffies(delay);
+	while (time_before(jiffies, timeout)) {
+		msleep(10);
+
+		if (stv0297_readreg(state, 0x82) & 0x08) {
+			break;
+		}
+	}
+	if (time_after(jiffies, timeout)) {
+		goto timeout;
+	}
+
+	/* disable sweep */
+	stv0297_writereg_mask(state, 0x6a, 1, 0);
+	stv0297_writereg_mask(state, 0x88, 8, 0);
+
+	/* wait for main lock */
+	timeout = jiffies + msecs_to_jiffies(20);
+	while (time_before(jiffies, timeout)) {
+		msleep(10);
+
+		if (stv0297_readreg(state, 0xDF) & 0x80) {
+			break;
+		}
+	}
+	if (time_after(jiffies, timeout)) {
+		goto timeout;
+	}
+	msleep(100);
+
+	/* is it still locked after that delay? */
+	if (!(stv0297_readreg(state, 0xDF) & 0x80)) {
+		goto timeout;
+	}
+
+	/* success!! */
+	stv0297_writereg_mask(state, 0x5a, 0x40, 0x00);
+	state->base_freq = p->frequency;
+	return 0;
+
+timeout:
+	stv0297_writereg_mask(state, 0x6a, 0x01, 0x00);
+	return 0;
+}
+
+static int stv0297_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct stv0297_state *state = fe->demodulator_priv;
+	int reg_00, reg_83;
+
+	reg_00 = stv0297_readreg(state, 0x00);
+	reg_83 = stv0297_readreg(state, 0x83);
+
+	p->frequency = state->base_freq;
+	p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF;
+	if (state->config->invert)
+		p->inversion = (p->inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON;
+	p->symbol_rate = stv0297_get_symbolrate(state) * 1000;
+	p->fec_inner = FEC_NONE;
+
+	switch ((reg_00 >> 4) & 0x7) {
+	case 0:
+		p->modulation = QAM_16;
+		break;
+	case 1:
+		p->modulation = QAM_32;
+		break;
+	case 2:
+		p->modulation = QAM_128;
+		break;
+	case 3:
+		p->modulation = QAM_256;
+		break;
+	case 4:
+		p->modulation = QAM_64;
+		break;
+	}
+
+	return 0;
+}
+
+static void stv0297_release(struct dvb_frontend *fe)
+{
+	struct stv0297_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops stv0297_ops;
+
+struct dvb_frontend *stv0297_attach(const struct stv0297_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct stv0297_state *state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct stv0297_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->last_ber = 0;
+	state->base_freq = 0;
+
+	/* check if the demod is there */
+	if ((stv0297_readreg(state, 0x80) & 0x70) != 0x20)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops stv0297_ops = {
+	.delsys = { SYS_DVBC_ANNEX_A },
+	.info = {
+		 .name = "ST STV0297 DVB-C",
+		 .frequency_min = 47000000,
+		 .frequency_max = 862000000,
+		 .frequency_stepsize = 62500,
+		 .symbol_rate_min = 870000,
+		 .symbol_rate_max = 11700000,
+		 .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+		 FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO},
+
+	.release = stv0297_release,
+
+	.init = stv0297_init,
+	.sleep = stv0297_sleep,
+	.i2c_gate_ctrl = stv0297_i2c_gate_ctrl,
+
+	.set_frontend = stv0297_set_frontend,
+	.get_frontend = stv0297_get_frontend,
+
+	.read_status = stv0297_read_status,
+	.read_ber = stv0297_read_ber,
+	.read_signal_strength = stv0297_read_signal_strength,
+	.read_snr = stv0297_read_snr,
+	.read_ucblocks = stv0297_read_ucblocks,
+};
+
+MODULE_DESCRIPTION("ST STV0297 DVB-C Demodulator driver");
+MODULE_AUTHOR("Dennis Noermann and Andrew de Quincey");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(stv0297_attach);
diff --git a/drivers/media/dvb-frontends/stv0297.h b/drivers/media/dvb-frontends/stv0297.h
new file mode 100644
index 0000000..3f8f946
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv0297.h
@@ -0,0 +1,57 @@
+/*
+    Driver for STV0297 demodulator
+
+    Copyright (C) 2003-2004 Dennis Noermann <dennis.noermann@noernet.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef STV0297_H
+#define STV0297_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct stv0297_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* inittab - array of pairs of values.
+	* First of each pair is the register, second is the value.
+	* List should be terminated with an 0xff, 0xff pair.
+	*/
+	u8* inittab;
+
+	/* does the "inversion" need inverted? */
+	u8 invert:1;
+
+	/* set to 1 if the device requires an i2c STOP during reading */
+	u8 stop_during_read:1;
+};
+
+#if defined(CONFIG_DVB_STV0297) || (defined(CONFIG_DVB_STV0297_MODULE) && defined(MODULE))
+extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
+					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_STV0297
+
+#endif // STV0297_H
diff --git a/drivers/media/dvb-frontends/stv0299.c b/drivers/media/dvb-frontends/stv0299.c
new file mode 100644
index 0000000..057b5f8
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv0299.c
@@ -0,0 +1,762 @@
+/*
+    Driver for ST STV0299 demodulator
+
+    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
+	<ralph@convergence.de>,
+	<holger@convergence.de>,
+	<js@convergence.de>
+
+
+    Philips SU1278/SH
+
+    Copyright (C) 2002 by Peter Schildmann <peter.schildmann@web.de>
+
+
+    LG TDQF-S001F
+
+    Copyright (C) 2002 Felix Domke <tmbinc@elitedvb.net>
+		     & Andreas Oberritter <obi@linuxtv.org>
+
+
+    Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B
+
+    Copyright (C) 2003 Vadim Catana <skystar@moldova.cc>:
+
+    Support for Philips SU1278 on Technotrend hardware
+
+    Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.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.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "stv0299.h"
+
+struct stv0299_state {
+	struct i2c_adapter* i2c;
+	const struct stv0299_config* config;
+	struct dvb_frontend frontend;
+
+	u8 initialised:1;
+	u32 tuner_frequency;
+	u32 symbol_rate;
+	fe_code_rate_t fec_inner;
+	int errmode;
+	u32 ucblocks;
+	u8 mcr_reg;
+};
+
+#define STATUS_BER 0
+#define STATUS_UCBLOCKS 1
+
+static int debug;
+static int debug_legacy_dish_switch;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "stv0299: " args); \
+	} while (0)
+
+
+static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf [] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+
+	ret = i2c_transfer (state->i2c, &msg, 1);
+
+	if (ret != 1)
+		dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
+			"ret == %i)\n", __func__, reg, data, ret);
+
+	return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int stv0299_write(struct dvb_frontend* fe, const u8 buf[], int len)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+
+	if (len != 2)
+		return -EINVAL;
+
+	return stv0299_writeregI(state, buf[0], buf[1]);
+}
+
+static u8 stv0299_readreg (struct stv0299_state* state, u8 reg)
+{
+	int ret;
+	u8 b0 [] = { reg };
+	u8 b1 [] = { 0 };
+	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+
+	ret = i2c_transfer (state->i2c, msg, 2);
+
+	if (ret != 2)
+		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
+				__func__, reg, ret);
+
+	return b1[0];
+}
+
+static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len)
+{
+	int ret;
+	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = &reg1, .len = 1 },
+			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } };
+
+	ret = i2c_transfer (state->i2c, msg, 2);
+
+	if (ret != 2)
+		dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
+
+	return ret == 2 ? 0 : ret;
+}
+
+static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
+{
+	dprintk ("%s\n", __func__);
+
+	switch (fec) {
+	case FEC_AUTO:
+	{
+		return stv0299_writeregI (state, 0x31, 0x1f);
+	}
+	case FEC_1_2:
+	{
+		return stv0299_writeregI (state, 0x31, 0x01);
+	}
+	case FEC_2_3:
+	{
+		return stv0299_writeregI (state, 0x31, 0x02);
+	}
+	case FEC_3_4:
+	{
+		return stv0299_writeregI (state, 0x31, 0x04);
+	}
+	case FEC_5_6:
+	{
+		return stv0299_writeregI (state, 0x31, 0x08);
+	}
+	case FEC_7_8:
+	{
+		return stv0299_writeregI (state, 0x31, 0x10);
+	}
+	default:
+	{
+		return -EINVAL;
+	}
+    }
+}
+
+static fe_code_rate_t stv0299_get_fec (struct stv0299_state* state)
+{
+	static fe_code_rate_t fec_tab [] = { FEC_2_3, FEC_3_4, FEC_5_6,
+					     FEC_7_8, FEC_1_2 };
+	u8 index;
+
+	dprintk ("%s\n", __func__);
+
+	index = stv0299_readreg (state, 0x1b);
+	index &= 0x7;
+
+	if (index > 4)
+		return FEC_AUTO;
+
+	return fec_tab [index];
+}
+
+static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout)
+{
+	unsigned long start = jiffies;
+
+	dprintk ("%s\n", __func__);
+
+	while (stv0299_readreg(state, 0x0a) & 1) {
+		if (jiffies - start > timeout) {
+			dprintk ("%s: timeout!!\n", __func__);
+			return -ETIMEDOUT;
+		}
+		msleep(10);
+	};
+
+	return 0;
+}
+
+static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout)
+{
+	unsigned long start = jiffies;
+
+	dprintk ("%s\n", __func__);
+
+	while ((stv0299_readreg(state, 0x0a) & 3) != 2 ) {
+		if (jiffies - start > timeout) {
+			dprintk ("%s: timeout!!\n", __func__);
+			return -ETIMEDOUT;
+		}
+		msleep(10);
+	};
+
+	return 0;
+}
+
+static int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+	u64 big = srate;
+	u32 ratio;
+
+	// check rate is within limits
+	if ((srate < 1000000) || (srate > 45000000)) return -EINVAL;
+
+	// calculate value to program
+	big = big << 20;
+	big += (state->config->mclk-1); // round correctly
+	do_div(big, state->config->mclk);
+	ratio = big << 4;
+
+	return state->config->set_symbol_rate(fe, srate, ratio);
+}
+
+static int stv0299_get_symbolrate (struct stv0299_state* state)
+{
+	u32 Mclk = state->config->mclk / 4096L;
+	u32 srate;
+	s32 offset;
+	u8 sfr[3];
+	s8 rtf;
+
+	dprintk ("%s\n", __func__);
+
+	stv0299_readregs (state, 0x1f, sfr, 3);
+	stv0299_readregs (state, 0x1a, (u8 *)&rtf, 1);
+
+	srate = (sfr[0] << 8) | sfr[1];
+	srate *= Mclk;
+	srate /= 16;
+	srate += (sfr[2] >> 4) * Mclk / 256;
+	offset = (s32) rtf * (srate / 4096L);
+	offset /= 128;
+
+	dprintk ("%s : srate = %i\n", __func__, srate);
+	dprintk ("%s : ofset = %i\n", __func__, offset);
+
+	srate += offset;
+
+	srate += 1000;
+	srate /= 2000;
+	srate *= 2000;
+
+	return srate;
+}
+
+static int stv0299_send_diseqc_msg (struct dvb_frontend* fe,
+				    struct dvb_diseqc_master_cmd *m)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+	u8 val;
+	int i;
+
+	dprintk ("%s\n", __func__);
+
+	if (stv0299_wait_diseqc_idle (state, 100) < 0)
+		return -ETIMEDOUT;
+
+	val = stv0299_readreg (state, 0x08);
+
+	if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x6))  /* DiSEqC mode */
+		return -EREMOTEIO;
+
+	for (i=0; i<m->msg_len; i++) {
+		if (stv0299_wait_diseqc_fifo (state, 100) < 0)
+			return -ETIMEDOUT;
+
+		if (stv0299_writeregI (state, 0x09, m->msg[i]))
+			return -EREMOTEIO;
+	}
+
+	if (stv0299_wait_diseqc_idle (state, 100) < 0)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int stv0299_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+	u8 val;
+
+	dprintk ("%s\n", __func__);
+
+	if (stv0299_wait_diseqc_idle (state, 100) < 0)
+		return -ETIMEDOUT;
+
+	val = stv0299_readreg (state, 0x08);
+
+	if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x2))	/* burst mode */
+		return -EREMOTEIO;
+
+	if (stv0299_writeregI (state, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff))
+		return -EREMOTEIO;
+
+	if (stv0299_wait_diseqc_idle (state, 100) < 0)
+		return -ETIMEDOUT;
+
+	if (stv0299_writeregI (state, 0x08, val))
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int stv0299_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+	u8 val;
+
+	if (stv0299_wait_diseqc_idle (state, 100) < 0)
+		return -ETIMEDOUT;
+
+	val = stv0299_readreg (state, 0x08);
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		return stv0299_writeregI (state, 0x08, val | 0x3);
+
+	case SEC_TONE_OFF:
+		return stv0299_writeregI (state, 0x08, (val & ~0x3) | 0x02);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+	u8 reg0x08;
+	u8 reg0x0c;
+
+	dprintk("%s: %s\n", __func__,
+		voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+		voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
+
+	reg0x08 = stv0299_readreg (state, 0x08);
+	reg0x0c = stv0299_readreg (state, 0x0c);
+
+	/**
+	 *  H/V switching over OP0, OP1 and OP2 are LNB power enable bits
+	 */
+	reg0x0c &= 0x0f;
+	reg0x08 = (reg0x08 & 0x3f) | (state->config->lock_output << 6);
+
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0)
+			reg0x0c |= 0x10; /* OP1 off, OP0 on */
+		else
+			reg0x0c |= 0x40; /* OP1 on, OP0 off */
+		break;
+	case SEC_VOLTAGE_18:
+		reg0x0c |= 0x50; /* OP1 on, OP0 on */
+		break;
+	case SEC_VOLTAGE_OFF:
+		/* LNB power off! */
+		reg0x08 = 0x00;
+		reg0x0c = 0x00;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	if (state->config->op0_off)
+		reg0x0c &= ~0x10;
+
+	stv0299_writeregI(state, 0x08, reg0x08);
+	return stv0299_writeregI(state, 0x0c, reg0x0c);
+}
+
+static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long cmd)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+	u8 reg0x08;
+	u8 reg0x0c;
+	u8 lv_mask = 0x40;
+	u8 last = 1;
+	int i;
+	struct timeval nexttime;
+	struct timeval tv[10];
+
+	reg0x08 = stv0299_readreg (state, 0x08);
+	reg0x0c = stv0299_readreg (state, 0x0c);
+	reg0x0c &= 0x0f;
+	stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6));
+	if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0)
+		lv_mask = 0x10;
+
+	cmd = cmd << 1;
+	if (debug_legacy_dish_switch)
+		printk ("%s switch command: 0x%04lx\n",__func__, cmd);
+
+	do_gettimeofday (&nexttime);
+	if (debug_legacy_dish_switch)
+		memcpy (&tv[0], &nexttime, sizeof (struct timeval));
+	stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */
+
+	dvb_frontend_sleep_until(&nexttime, 32000);
+
+	for (i=0; i<9; i++) {
+		if (debug_legacy_dish_switch)
+			do_gettimeofday (&tv[i+1]);
+		if((cmd & 0x01) != last) {
+			/* set voltage to (last ? 13V : 18V) */
+			stv0299_writeregI (state, 0x0c, reg0x0c | (last ? lv_mask : 0x50));
+			last = (last) ? 0 : 1;
+		}
+
+		cmd = cmd >> 1;
+
+		if (i != 8)
+			dvb_frontend_sleep_until(&nexttime, 8000);
+	}
+	if (debug_legacy_dish_switch) {
+		printk ("%s(%d): switch delay (should be 32k followed by all 8k\n",
+			__func__, fe->dvb->num);
+		for (i = 1; i < 10; i++)
+			printk ("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
+	}
+
+	return 0;
+}
+
+static int stv0299_init (struct dvb_frontend* fe)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+	int i;
+	u8 reg;
+	u8 val;
+
+	dprintk("stv0299: init chip\n");
+
+	stv0299_writeregI(state, 0x02, 0x30 | state->mcr_reg);
+	msleep(50);
+
+	for (i = 0; ; i += 2)  {
+		reg = state->config->inittab[i];
+		val = state->config->inittab[i+1];
+		if (reg == 0xff && val == 0xff)
+			break;
+		if (reg == 0x0c && state->config->op0_off)
+			val &= ~0x10;
+		if (reg == 0x2)
+			state->mcr_reg = val & 0xf;
+		stv0299_writeregI(state, reg, val);
+	}
+
+	return 0;
+}
+
+static int stv0299_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+
+	u8 signal = 0xff - stv0299_readreg (state, 0x18);
+	u8 sync = stv0299_readreg (state, 0x1b);
+
+	dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync);
+	*status = 0;
+
+	if (signal > 10)
+		*status |= FE_HAS_SIGNAL;
+
+	if (sync & 0x80)
+		*status |= FE_HAS_CARRIER;
+
+	if (sync & 0x10)
+		*status |= FE_HAS_VITERBI;
+
+	if (sync & 0x08)
+		*status |= FE_HAS_SYNC;
+
+	if ((sync & 0x98) == 0x98)
+		*status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+
+	if (state->errmode != STATUS_BER)
+		return -ENOSYS;
+
+	*ber = stv0299_readreg(state, 0x1e) | (stv0299_readreg(state, 0x1d) << 8);
+
+	return 0;
+}
+
+static int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+
+	s32 signal =  0xffff - ((stv0299_readreg (state, 0x18) << 8)
+			       | stv0299_readreg (state, 0x19));
+
+	dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __func__,
+		 stv0299_readreg (state, 0x18),
+		 stv0299_readreg (state, 0x19), (int) signal);
+
+	signal = signal * 5 / 4;
+	*strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal;
+
+	return 0;
+}
+
+static int stv0299_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+
+	s32 xsnr = 0xffff - ((stv0299_readreg (state, 0x24) << 8)
+			   | stv0299_readreg (state, 0x25));
+	xsnr = 3 * (xsnr - 0xa100);
+	*snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
+
+	return 0;
+}
+
+static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+
+	if (state->errmode != STATUS_UCBLOCKS)
+		return -ENOSYS;
+
+	state->ucblocks += stv0299_readreg(state, 0x1e);
+	state->ucblocks += (stv0299_readreg(state, 0x1d) << 8);
+	*ucblocks = state->ucblocks;
+
+	return 0;
+}
+
+static int stv0299_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct stv0299_state* state = fe->demodulator_priv;
+	int invval = 0;
+
+	dprintk ("%s : FE_SET_FRONTEND\n", __func__);
+	if (state->config->set_ts_params)
+		state->config->set_ts_params(fe, 0);
+
+	// set the inversion
+	if (p->inversion == INVERSION_OFF) invval = 0;
+	else if (p->inversion == INVERSION_ON) invval = 1;
+	else {
+		printk("stv0299 does not support auto-inversion\n");
+		return -EINVAL;
+	}
+	if (state->config->invert) invval = (~invval) & 1;
+	stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	stv0299_set_FEC(state, p->fec_inner);
+	stv0299_set_symbolrate(fe, p->symbol_rate);
+	stv0299_writeregI(state, 0x22, 0x00);
+	stv0299_writeregI(state, 0x23, 0x00);
+
+	state->tuner_frequency = p->frequency;
+	state->fec_inner = p->fec_inner;
+	state->symbol_rate = p->symbol_rate;
+
+	return 0;
+}
+
+static int stv0299_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct stv0299_state* state = fe->demodulator_priv;
+	s32 derot_freq;
+	int invval;
+
+	derot_freq = (s32)(s16) ((stv0299_readreg (state, 0x22) << 8)
+				| stv0299_readreg (state, 0x23));
+
+	derot_freq *= (state->config->mclk >> 16);
+	derot_freq += 500;
+	derot_freq /= 1000;
+
+	p->frequency += derot_freq;
+
+	invval = stv0299_readreg (state, 0x0c) & 1;
+	if (state->config->invert) invval = (~invval) & 1;
+	p->inversion = invval ? INVERSION_ON : INVERSION_OFF;
+
+	p->fec_inner = stv0299_get_fec(state);
+	p->symbol_rate = stv0299_get_symbolrate(state);
+
+	return 0;
+}
+
+static int stv0299_sleep(struct dvb_frontend* fe)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+
+	stv0299_writeregI(state, 0x02, 0xb0 | state->mcr_reg);
+	state->initialised = 0;
+
+	return 0;
+}
+
+static int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		stv0299_writeregI(state, 0x05, 0xb5);
+	} else {
+		stv0299_writeregI(state, 0x05, 0x35);
+	}
+	udelay(1);
+	return 0;
+}
+
+static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+	fesettings->min_delay_ms = state->config->min_delay_ms;
+	if (p->symbol_rate < 10000000) {
+		fesettings->step_size = p->symbol_rate / 32000;
+		fesettings->max_drift = 5000;
+	} else {
+		fesettings->step_size = p->symbol_rate / 16000;
+		fesettings->max_drift = p->symbol_rate / 2000;
+	}
+	return 0;
+}
+
+static void stv0299_release(struct dvb_frontend* fe)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops stv0299_ops;
+
+struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
+				    struct i2c_adapter* i2c)
+{
+	struct stv0299_state* state = NULL;
+	int id;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct stv0299_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->initialised = 0;
+	state->tuner_frequency = 0;
+	state->symbol_rate = 0;
+	state->fec_inner = 0;
+	state->errmode = STATUS_BER;
+
+	/* check if the demod is there */
+	stv0299_writeregI(state, 0x02, 0x30); /* standby off */
+	msleep(200);
+	id = stv0299_readreg(state, 0x00);
+
+	/* register 0x00 contains 0xa1 for STV0299 and STV0299B */
+	/* register 0x00 might contain 0x80 when returning from standby */
+	if (id != 0xa1 && id != 0x80) goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops stv0299_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name			= "ST STV0299 DVB-S",
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 125,	 /* kHz for QPSK frontends */
+		.frequency_tolerance	= 0,
+		.symbol_rate_min	= 1000000,
+		.symbol_rate_max	= 45000000,
+		.symbol_rate_tolerance	= 500,	/* ppm */
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+		      FE_CAN_QPSK |
+		      FE_CAN_FEC_AUTO
+	},
+
+	.release = stv0299_release,
+
+	.init = stv0299_init,
+	.sleep = stv0299_sleep,
+	.write = stv0299_write,
+	.i2c_gate_ctrl = stv0299_i2c_gate_ctrl,
+
+	.set_frontend = stv0299_set_frontend,
+	.get_frontend = stv0299_get_frontend,
+	.get_tune_settings = stv0299_get_tune_settings,
+
+	.read_status = stv0299_read_status,
+	.read_ber = stv0299_read_ber,
+	.read_signal_strength = stv0299_read_signal_strength,
+	.read_snr = stv0299_read_snr,
+	.read_ucblocks = stv0299_read_ucblocks,
+
+	.diseqc_send_master_cmd = stv0299_send_diseqc_msg,
+	.diseqc_send_burst = stv0299_send_diseqc_burst,
+	.set_tone = stv0299_set_tone,
+	.set_voltage = stv0299_set_voltage,
+	.dishnetwork_send_legacy_command = stv0299_send_legacy_dish_cmd,
+};
+
+module_param(debug_legacy_dish_switch, int, 0444);
+MODULE_PARM_DESC(debug_legacy_dish_switch, "Enable timing analysis for Dish Network legacy switches");
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver");
+MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
+	      "Andreas Oberritter, Andrew de Quincey, Kenneth Aafly");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(stv0299_attach);
diff --git a/drivers/media/dvb-frontends/stv0299.h b/drivers/media/dvb-frontends/stv0299.h
new file mode 100644
index 0000000..ba219b7
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv0299.h
@@ -0,0 +1,118 @@
+/*
+    Driver for ST STV0299 demodulator
+
+    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
+	<ralph@convergence.de>,
+	<holger@convergence.de>,
+	<js@convergence.de>
+
+
+    Philips SU1278/SH
+
+    Copyright (C) 2002 by Peter Schildmann <peter.schildmann@web.de>
+
+
+    LG TDQF-S001F
+
+    Copyright (C) 2002 Felix Domke <tmbinc@elitedvb.net>
+		     & Andreas Oberritter <obi@linuxtv.org>
+
+
+    Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B
+
+    Copyright (C) 2003 Vadim Catana <skystar@moldova.cc>:
+
+    Support for Philips SU1278 on Technotrend hardware
+
+    Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.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.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef STV0299_H
+#define STV0299_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+#define STV0299_LOCKOUTPUT_0  0
+#define STV0299_LOCKOUTPUT_1  1
+#define STV0299_LOCKOUTPUT_CF 2
+#define STV0299_LOCKOUTPUT_LK 3
+
+#define STV0299_VOLT13_OP0 0
+#define STV0299_VOLT13_OP1 1
+
+struct stv0299_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* inittab - array of pairs of values.
+	 * First of each pair is the register, second is the value.
+	 * List should be terminated with an 0xff, 0xff pair.
+	 */
+	const u8* inittab;
+
+	/* master clock to use */
+	u32 mclk;
+
+	/* does the inversion require inversion? */
+	u8 invert:1;
+
+	/* Skip reinitialisation? */
+	u8 skip_reinit:1;
+
+	/* LOCK OUTPUT setting */
+	u8 lock_output:2;
+
+	/* Is 13v controlled by OP0 or OP1? */
+	u8 volt13_op0_op1:1;
+
+	/* Turn-off OP0? */
+	u8 op0_off:1;
+
+	/* minimum delay before retuning */
+	int min_delay_ms;
+
+	/* Set the symbol rate */
+	int (*set_symbol_rate)(struct dvb_frontend *fe, u32 srate, u32 ratio);
+
+	/* Set device param to start dma */
+	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
+};
+
+#if defined(CONFIG_DVB_STV0299) || (defined(CONFIG_DVB_STV0299_MODULE) && defined(MODULE))
+extern struct dvb_frontend *stv0299_attach(const struct stv0299_config *config,
+					   struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *stv0299_attach(const struct stv0299_config *config,
+					   struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_STV0299
+
+static inline int stv0299_writereg(struct dvb_frontend *fe, u8 reg, u8 val) {
+	int r = 0;
+	u8 buf[] = {reg, val};
+	if (fe->ops.write)
+		r = fe->ops.write(fe, buf, 2);
+	return r;
+}
+
+#endif // STV0299_H
diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c
new file mode 100644
index 0000000..2a8aaeb
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv0367.c
@@ -0,0 +1,3450 @@
+/*
+ * stv0367.c
+ *
+ * Driver for ST STV0367 DVB-T & DVB-C demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2010,2011 NetUP Inc.
+ * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+
+#include "stv0367.h"
+#include "stv0367_regs.h"
+#include "stv0367_priv.h"
+
+static int stvdebug;
+module_param_named(debug, stvdebug, int, 0644);
+
+static int i2cdebug;
+module_param_named(i2c_debug, i2cdebug, int, 0644);
+
+#define dprintk(args...) \
+	do { \
+		if (stvdebug) \
+			printk(KERN_DEBUG args); \
+	} while (0)
+	/* DVB-C */
+
+struct stv0367cab_state {
+	enum stv0367_cab_signal_type	state;
+	u32	mclk;
+	u32	adc_clk;
+	s32	search_range;
+	s32	derot_offset;
+	/* results */
+	int locked;			/* channel found		*/
+	u32 freq_khz;			/* found frequency (in kHz)	*/
+	u32 symbol_rate;		/* found symbol rate (in Bds)	*/
+	enum stv0367cab_mod modulation;	/* modulation			*/
+	fe_spectral_inversion_t	spect_inv; /* Spectrum Inversion	*/
+};
+
+struct stv0367ter_state {
+	/* DVB-T */
+	enum stv0367_ter_signal_type state;
+	enum stv0367_ter_if_iq_mode if_iq_mode;
+	enum stv0367_ter_mode mode;/* mode 2K or 8K */
+	fe_guard_interval_t guard;
+	enum stv0367_ter_hierarchy hierarchy;
+	u32 frequency;
+	fe_spectral_inversion_t  sense; /*  current search spectrum */
+	u8  force; /* force mode/guard */
+	u8  bw; /* channel width 6, 7 or 8 in MHz */
+	u8  pBW; /* channel width used during previous lock */
+	u32 pBER;
+	u32 pPER;
+	u32 ucblocks;
+	s8  echo_pos; /* echo position */
+	u8  first_lock;
+	u8  unlock_counter;
+	u32 agc_val;
+};
+
+struct stv0367_state {
+	struct dvb_frontend fe;
+	struct i2c_adapter *i2c;
+	/* config settings */
+	const struct stv0367_config *config;
+	u8 chip_id;
+	/* DVB-C */
+	struct stv0367cab_state *cab_state;
+	/* DVB-T */
+	struct stv0367ter_state *ter_state;
+};
+
+struct st_register {
+	u16	addr;
+	u8	value;
+};
+
+/* values for STV4100 XTAL=30M int clk=53.125M*/
+static struct st_register def0367ter[STV0367TER_NBREGS] = {
+	{R367TER_ID,		0x60},
+	{R367TER_I2CRPT,	0xa0},
+	/* {R367TER_I2CRPT,	0x22},*/
+	{R367TER_TOPCTRL,	0x00},/* for xc5000; was 0x02 */
+	{R367TER_IOCFG0,	0x40},
+	{R367TER_DAC0R,		0x00},
+	{R367TER_IOCFG1,	0x00},
+	{R367TER_DAC1R,		0x00},
+	{R367TER_IOCFG2,	0x62},
+	{R367TER_SDFR,		0x00},
+	{R367TER_STATUS,	0xf8},
+	{R367TER_AUX_CLK,	0x0a},
+	{R367TER_FREESYS1,	0x00},
+	{R367TER_FREESYS2,	0x00},
+	{R367TER_FREESYS3,	0x00},
+	{R367TER_GPIO_CFG,	0x55},
+	{R367TER_GPIO_CMD,	0x00},
+	{R367TER_AGC2MAX,	0xff},
+	{R367TER_AGC2MIN,	0x00},
+	{R367TER_AGC1MAX,	0xff},
+	{R367TER_AGC1MIN,	0x00},
+	{R367TER_AGCR,		0xbc},
+	{R367TER_AGC2TH,	0x00},
+	{R367TER_AGC12C,	0x00},
+	{R367TER_AGCCTRL1,	0x85},
+	{R367TER_AGCCTRL2,	0x1f},
+	{R367TER_AGC1VAL1,	0x00},
+	{R367TER_AGC1VAL2,	0x00},
+	{R367TER_AGC2VAL1,	0x6f},
+	{R367TER_AGC2VAL2,	0x05},
+	{R367TER_AGC2PGA,	0x00},
+	{R367TER_OVF_RATE1,	0x00},
+	{R367TER_OVF_RATE2,	0x00},
+	{R367TER_GAIN_SRC1,	0xaa},/* for xc5000; was 0x2b */
+	{R367TER_GAIN_SRC2,	0xd6},/* for xc5000; was 0x04 */
+	{R367TER_INC_DEROT1,	0x55},
+	{R367TER_INC_DEROT2,	0x55},
+	{R367TER_PPM_CPAMP_DIR,	0x2c},
+	{R367TER_PPM_CPAMP_INV,	0x00},
+	{R367TER_FREESTFE_1,	0x00},
+	{R367TER_FREESTFE_2,	0x1c},
+	{R367TER_DCOFFSET,	0x00},
+	{R367TER_EN_PROCESS,	0x05},
+	{R367TER_SDI_SMOOTHER,	0x80},
+	{R367TER_FE_LOOP_OPEN,	0x1c},
+	{R367TER_FREQOFF1,	0x00},
+	{R367TER_FREQOFF2,	0x00},
+	{R367TER_FREQOFF3,	0x00},
+	{R367TER_TIMOFF1,	0x00},
+	{R367TER_TIMOFF2,	0x00},
+	{R367TER_EPQ,		0x02},
+	{R367TER_EPQAUTO,	0x01},
+	{R367TER_SYR_UPDATE,	0xf5},
+	{R367TER_CHPFREE,	0x00},
+	{R367TER_PPM_STATE_MAC,	0x23},
+	{R367TER_INR_THRESHOLD,	0xff},
+	{R367TER_EPQ_TPS_ID_CELL, 0xf9},
+	{R367TER_EPQ_CFG,	0x00},
+	{R367TER_EPQ_STATUS,	0x01},
+	{R367TER_AUTORELOCK,	0x81},
+	{R367TER_BER_THR_VMSB,	0x00},
+	{R367TER_BER_THR_MSB,	0x00},
+	{R367TER_BER_THR_LSB,	0x00},
+	{R367TER_CCD,		0x83},
+	{R367TER_SPECTR_CFG,	0x00},
+	{R367TER_CHC_DUMMY,	0x18},
+	{R367TER_INC_CTL,	0x88},
+	{R367TER_INCTHRES_COR1,	0xb4},
+	{R367TER_INCTHRES_COR2,	0x96},
+	{R367TER_INCTHRES_DET1,	0x0e},
+	{R367TER_INCTHRES_DET2,	0x11},
+	{R367TER_IIR_CELLNB,	0x8d},
+	{R367TER_IIRCX_COEFF1_MSB, 0x00},
+	{R367TER_IIRCX_COEFF1_LSB, 0x00},
+	{R367TER_IIRCX_COEFF2_MSB, 0x09},
+	{R367TER_IIRCX_COEFF2_LSB, 0x18},
+	{R367TER_IIRCX_COEFF3_MSB, 0x14},
+	{R367TER_IIRCX_COEFF3_LSB, 0x9c},
+	{R367TER_IIRCX_COEFF4_MSB, 0x00},
+	{R367TER_IIRCX_COEFF4_LSB, 0x00},
+	{R367TER_IIRCX_COEFF5_MSB, 0x36},
+	{R367TER_IIRCX_COEFF5_LSB, 0x42},
+	{R367TER_FEPATH_CFG,	0x00},
+	{R367TER_PMC1_FUNC,	0x65},
+	{R367TER_PMC1_FOR,	0x00},
+	{R367TER_PMC2_FUNC,	0x00},
+	{R367TER_STATUS_ERR_DA,	0xe0},
+	{R367TER_DIG_AGC_R,	0xfe},
+	{R367TER_COMAGC_TARMSB,	0x0b},
+	{R367TER_COM_AGC_TAR_ENMODE, 0x41},
+	{R367TER_COM_AGC_CFG,	0x3e},
+	{R367TER_COM_AGC_GAIN1, 0x39},
+	{R367TER_AUT_AGC_TARGETMSB, 0x0b},
+	{R367TER_LOCK_DET_MSB,	0x01},
+	{R367TER_AGCTAR_LOCK_LSBS, 0x40},
+	{R367TER_AUT_GAIN_EN,	0xf4},
+	{R367TER_AUT_CFG,	0xf0},
+	{R367TER_LOCKN,		0x23},
+	{R367TER_INT_X_3,	0x00},
+	{R367TER_INT_X_2,	0x03},
+	{R367TER_INT_X_1,	0x8d},
+	{R367TER_INT_X_0,	0xa0},
+	{R367TER_MIN_ERRX_MSB,	0x00},
+	{R367TER_COR_CTL,	0x23},
+	{R367TER_COR_STAT,	0xf6},
+	{R367TER_COR_INTEN,	0x00},
+	{R367TER_COR_INTSTAT,	0x3f},
+	{R367TER_COR_MODEGUARD,	0x03},
+	{R367TER_AGC_CTL,	0x08},
+	{R367TER_AGC_MANUAL1,	0x00},
+	{R367TER_AGC_MANUAL2,	0x00},
+	{R367TER_AGC_TARG,	0x16},
+	{R367TER_AGC_GAIN1,	0x53},
+	{R367TER_AGC_GAIN2,	0x1d},
+	{R367TER_RESERVED_1,	0x00},
+	{R367TER_RESERVED_2,	0x00},
+	{R367TER_RESERVED_3,	0x00},
+	{R367TER_CAS_CTL,	0x44},
+	{R367TER_CAS_FREQ,	0xb3},
+	{R367TER_CAS_DAGCGAIN,	0x12},
+	{R367TER_SYR_CTL,	0x04},
+	{R367TER_SYR_STAT,	0x10},
+	{R367TER_SYR_NCO1,	0x00},
+	{R367TER_SYR_NCO2,	0x00},
+	{R367TER_SYR_OFFSET1,	0x00},
+	{R367TER_SYR_OFFSET2,	0x00},
+	{R367TER_FFT_CTL,	0x00},
+	{R367TER_SCR_CTL,	0x70},
+	{R367TER_PPM_CTL1,	0xf8},
+	{R367TER_TRL_CTL,	0x14},/* for xc5000; was 0xac */
+	{R367TER_TRL_NOMRATE1,	0xae},/* for xc5000; was 0x1e */
+	{R367TER_TRL_NOMRATE2,	0x56},/* for xc5000; was 0x58 */
+	{R367TER_TRL_TIME1,	0x1d},
+	{R367TER_TRL_TIME2,	0xfc},
+	{R367TER_CRL_CTL,	0x24},
+	{R367TER_CRL_FREQ1,	0xad},
+	{R367TER_CRL_FREQ2,	0x9d},
+	{R367TER_CRL_FREQ3,	0xff},
+	{R367TER_CHC_CTL,	0x01},
+	{R367TER_CHC_SNR,	0xf0},
+	{R367TER_BDI_CTL,	0x00},
+	{R367TER_DMP_CTL,	0x00},
+	{R367TER_TPS_RCVD1,	0x30},
+	{R367TER_TPS_RCVD2,	0x02},
+	{R367TER_TPS_RCVD3,	0x01},
+	{R367TER_TPS_RCVD4,	0x00},
+	{R367TER_TPS_ID_CELL1,	0x00},
+	{R367TER_TPS_ID_CELL2,	0x00},
+	{R367TER_TPS_RCVD5_SET1, 0x02},
+	{R367TER_TPS_SET2,	0x02},
+	{R367TER_TPS_SET3,	0x01},
+	{R367TER_TPS_CTL,	0x00},
+	{R367TER_CTL_FFTOSNUM,	0x34},
+	{R367TER_TESTSELECT,	0x09},
+	{R367TER_MSC_REV,	0x0a},
+	{R367TER_PIR_CTL,	0x00},
+	{R367TER_SNR_CARRIER1,	0xa1},
+	{R367TER_SNR_CARRIER2,	0x9a},
+	{R367TER_PPM_CPAMP,	0x2c},
+	{R367TER_TSM_AP0,	0x00},
+	{R367TER_TSM_AP1,	0x00},
+	{R367TER_TSM_AP2 ,	0x00},
+	{R367TER_TSM_AP3,	0x00},
+	{R367TER_TSM_AP4,	0x00},
+	{R367TER_TSM_AP5,	0x00},
+	{R367TER_TSM_AP6,	0x00},
+	{R367TER_TSM_AP7,	0x00},
+	{R367TER_TSTRES,	0x00},
+	{R367TER_ANACTRL,	0x0D},/* PLL stoped, restart at init!!! */
+	{R367TER_TSTBUS,	0x00},
+	{R367TER_TSTRATE,	0x00},
+	{R367TER_CONSTMODE,	0x01},
+	{R367TER_CONSTCARR1,	0x00},
+	{R367TER_CONSTCARR2,	0x00},
+	{R367TER_ICONSTEL,	0x0a},
+	{R367TER_QCONSTEL,	0x15},
+	{R367TER_TSTBISTRES0,	0x00},
+	{R367TER_TSTBISTRES1,	0x00},
+	{R367TER_TSTBISTRES2,	0x28},
+	{R367TER_TSTBISTRES3,	0x00},
+	{R367TER_RF_AGC1,	0xff},
+	{R367TER_RF_AGC2,	0x83},
+	{R367TER_ANADIGCTRL,	0x19},
+	{R367TER_PLLMDIV,	0x01},/* for xc5000; was 0x0c */
+	{R367TER_PLLNDIV,	0x06},/* for xc5000; was 0x55 */
+	{R367TER_PLLSETUP,	0x18},
+	{R367TER_DUAL_AD12,	0x0C},/* for xc5000 AGC voltage 1.6V */
+	{R367TER_TSTBIST,	0x00},
+	{R367TER_PAD_COMP_CTRL,	0x00},
+	{R367TER_PAD_COMP_WR,	0x00},
+	{R367TER_PAD_COMP_RD,	0xe0},
+	{R367TER_SYR_TARGET_FFTADJT_MSB, 0x00},
+	{R367TER_SYR_TARGET_FFTADJT_LSB, 0x00},
+	{R367TER_SYR_TARGET_CHCADJT_MSB, 0x00},
+	{R367TER_SYR_TARGET_CHCADJT_LSB, 0x00},
+	{R367TER_SYR_FLAG,	0x00},
+	{R367TER_CRL_TARGET1,	0x00},
+	{R367TER_CRL_TARGET2,	0x00},
+	{R367TER_CRL_TARGET3,	0x00},
+	{R367TER_CRL_TARGET4,	0x00},
+	{R367TER_CRL_FLAG,	0x00},
+	{R367TER_TRL_TARGET1,	0x00},
+	{R367TER_TRL_TARGET2,	0x00},
+	{R367TER_TRL_CHC,	0x00},
+	{R367TER_CHC_SNR_TARG,	0x00},
+	{R367TER_TOP_TRACK,	0x00},
+	{R367TER_TRACKER_FREE1,	0x00},
+	{R367TER_ERROR_CRL1,	0x00},
+	{R367TER_ERROR_CRL2,	0x00},
+	{R367TER_ERROR_CRL3,	0x00},
+	{R367TER_ERROR_CRL4,	0x00},
+	{R367TER_DEC_NCO1,	0x2c},
+	{R367TER_DEC_NCO2,	0x0f},
+	{R367TER_DEC_NCO3,	0x20},
+	{R367TER_SNR,		0xf1},
+	{R367TER_SYR_FFTADJ1,	0x00},
+	{R367TER_SYR_FFTADJ2,	0x00},
+	{R367TER_SYR_CHCADJ1,	0x00},
+	{R367TER_SYR_CHCADJ2,	0x00},
+	{R367TER_SYR_OFF,	0x00},
+	{R367TER_PPM_OFFSET1,	0x00},
+	{R367TER_PPM_OFFSET2,	0x03},
+	{R367TER_TRACKER_FREE2,	0x00},
+	{R367TER_DEBG_LT10,	0x00},
+	{R367TER_DEBG_LT11,	0x00},
+	{R367TER_DEBG_LT12,	0x00},
+	{R367TER_DEBG_LT13,	0x00},
+	{R367TER_DEBG_LT14,	0x00},
+	{R367TER_DEBG_LT15,	0x00},
+	{R367TER_DEBG_LT16,	0x00},
+	{R367TER_DEBG_LT17,	0x00},
+	{R367TER_DEBG_LT18,	0x00},
+	{R367TER_DEBG_LT19,	0x00},
+	{R367TER_DEBG_LT1A,	0x00},
+	{R367TER_DEBG_LT1B,	0x00},
+	{R367TER_DEBG_LT1C,	0x00},
+	{R367TER_DEBG_LT1D,	0x00},
+	{R367TER_DEBG_LT1E,	0x00},
+	{R367TER_DEBG_LT1F,	0x00},
+	{R367TER_RCCFGH,	0x00},
+	{R367TER_RCCFGM,	0x00},
+	{R367TER_RCCFGL,	0x00},
+	{R367TER_RCINSDELH,	0x00},
+	{R367TER_RCINSDELM,	0x00},
+	{R367TER_RCINSDELL,	0x00},
+	{R367TER_RCSTATUS,	0x00},
+	{R367TER_RCSPEED,	0x6f},
+	{R367TER_RCDEBUGM,	0xe7},
+	{R367TER_RCDEBUGL,	0x9b},
+	{R367TER_RCOBSCFG,	0x00},
+	{R367TER_RCOBSM,	0x00},
+	{R367TER_RCOBSL,	0x00},
+	{R367TER_RCFECSPY,	0x00},
+	{R367TER_RCFSPYCFG,	0x00},
+	{R367TER_RCFSPYDATA,	0x00},
+	{R367TER_RCFSPYOUT,	0x00},
+	{R367TER_RCFSTATUS,	0x00},
+	{R367TER_RCFGOODPACK,	0x00},
+	{R367TER_RCFPACKCNT,	0x00},
+	{R367TER_RCFSPYMISC,	0x00},
+	{R367TER_RCFBERCPT4,	0x00},
+	{R367TER_RCFBERCPT3,	0x00},
+	{R367TER_RCFBERCPT2,	0x00},
+	{R367TER_RCFBERCPT1,	0x00},
+	{R367TER_RCFBERCPT0,	0x00},
+	{R367TER_RCFBERERR2,	0x00},
+	{R367TER_RCFBERERR1,	0x00},
+	{R367TER_RCFBERERR0,	0x00},
+	{R367TER_RCFSTATESM,	0x00},
+	{R367TER_RCFSTATESL,	0x00},
+	{R367TER_RCFSPYBER,	0x00},
+	{R367TER_RCFSPYDISTM,	0x00},
+	{R367TER_RCFSPYDISTL,	0x00},
+	{R367TER_RCFSPYOBS7,	0x00},
+	{R367TER_RCFSPYOBS6,	0x00},
+	{R367TER_RCFSPYOBS5,	0x00},
+	{R367TER_RCFSPYOBS4,	0x00},
+	{R367TER_RCFSPYOBS3,	0x00},
+	{R367TER_RCFSPYOBS2,	0x00},
+	{R367TER_RCFSPYOBS1,	0x00},
+	{R367TER_RCFSPYOBS0,	0x00},
+	{R367TER_TSGENERAL,	0x00},
+	{R367TER_RC1SPEED,	0x6f},
+	{R367TER_TSGSTATUS,	0x18},
+	{R367TER_FECM,		0x01},
+	{R367TER_VTH12,		0xff},
+	{R367TER_VTH23,		0xa1},
+	{R367TER_VTH34,		0x64},
+	{R367TER_VTH56,		0x40},
+	{R367TER_VTH67,		0x00},
+	{R367TER_VTH78,		0x2c},
+	{R367TER_VITCURPUN,	0x12},
+	{R367TER_VERROR,	0x01},
+	{R367TER_PRVIT,		0x3f},
+	{R367TER_VAVSRVIT,	0x00},
+	{R367TER_VSTATUSVIT,	0xbd},
+	{R367TER_VTHINUSE,	0xa1},
+	{R367TER_KDIV12,	0x20},
+	{R367TER_KDIV23,	0x40},
+	{R367TER_KDIV34,	0x20},
+	{R367TER_KDIV56,	0x30},
+	{R367TER_KDIV67,	0x00},
+	{R367TER_KDIV78,	0x30},
+	{R367TER_SIGPOWER,	0x54},
+	{R367TER_DEMAPVIT,	0x40},
+	{R367TER_VITSCALE,	0x00},
+	{R367TER_FFEC1PRG,	0x00},
+	{R367TER_FVITCURPUN,	0x12},
+	{R367TER_FVERROR,	0x01},
+	{R367TER_FVSTATUSVIT,	0xbd},
+	{R367TER_DEBUG_LT1,	0x00},
+	{R367TER_DEBUG_LT2,	0x00},
+	{R367TER_DEBUG_LT3,	0x00},
+	{R367TER_TSTSFMET,	0x00},
+	{R367TER_SELOUT,	0x00},
+	{R367TER_TSYNC,		0x00},
+	{R367TER_TSTERR,	0x00},
+	{R367TER_TSFSYNC,	0x00},
+	{R367TER_TSTSFERR,	0x00},
+	{R367TER_TSTTSSF1,	0x01},
+	{R367TER_TSTTSSF2,	0x1f},
+	{R367TER_TSTTSSF3,	0x00},
+	{R367TER_TSTTS1,	0x00},
+	{R367TER_TSTTS2,	0x1f},
+	{R367TER_TSTTS3,	0x01},
+	{R367TER_TSTTS4,	0x00},
+	{R367TER_TSTTSRC,	0x00},
+	{R367TER_TSTTSRS,	0x00},
+	{R367TER_TSSTATEM,	0xb0},
+	{R367TER_TSSTATEL,	0x40},
+	{R367TER_TSCFGH,	0xC0},
+	{R367TER_TSCFGM,	0xc0},/* for xc5000; was 0x00 */
+	{R367TER_TSCFGL,	0x20},
+	{R367TER_TSSYNC,	0x00},
+	{R367TER_TSINSDELH,	0x00},
+	{R367TER_TSINSDELM,	0x00},
+	{R367TER_TSINSDELL,	0x00},
+	{R367TER_TSDIVN,	0x03},
+	{R367TER_TSDIVPM,	0x00},
+	{R367TER_TSDIVPL,	0x00},
+	{R367TER_TSDIVQM,	0x00},
+	{R367TER_TSDIVQL,	0x00},
+	{R367TER_TSDILSTKM,	0x00},
+	{R367TER_TSDILSTKL,	0x00},
+	{R367TER_TSSPEED,	0x40},/* for xc5000; was 0x6f */
+	{R367TER_TSSTATUS,	0x81},
+	{R367TER_TSSTATUS2,	0x6a},
+	{R367TER_TSBITRATEM,	0x0f},
+	{R367TER_TSBITRATEL,	0xc6},
+	{R367TER_TSPACKLENM,	0x00},
+	{R367TER_TSPACKLENL,	0xfc},
+	{R367TER_TSBLOCLENM,	0x0a},
+	{R367TER_TSBLOCLENL,	0x80},
+	{R367TER_TSDLYH,	0x90},
+	{R367TER_TSDLYM,	0x68},
+	{R367TER_TSDLYL,	0x01},
+	{R367TER_TSNPDAV,	0x00},
+	{R367TER_TSBUFSTATH,	0x00},
+	{R367TER_TSBUFSTATM,	0x00},
+	{R367TER_TSBUFSTATL,	0x00},
+	{R367TER_TSDEBUGM,	0xcf},
+	{R367TER_TSDEBUGL,	0x1e},
+	{R367TER_TSDLYSETH,	0x00},
+	{R367TER_TSDLYSETM,	0x68},
+	{R367TER_TSDLYSETL,	0x00},
+	{R367TER_TSOBSCFG,	0x00},
+	{R367TER_TSOBSM,	0x47},
+	{R367TER_TSOBSL,	0x1f},
+	{R367TER_ERRCTRL1,	0x95},
+	{R367TER_ERRCNT1H,	0x80},
+	{R367TER_ERRCNT1M,	0x00},
+	{R367TER_ERRCNT1L,	0x00},
+	{R367TER_ERRCTRL2,	0x95},
+	{R367TER_ERRCNT2H,	0x00},
+	{R367TER_ERRCNT2M,	0x00},
+	{R367TER_ERRCNT2L,	0x00},
+	{R367TER_FECSPY,	0x88},
+	{R367TER_FSPYCFG,	0x2c},
+	{R367TER_FSPYDATA,	0x3a},
+	{R367TER_FSPYOUT,	0x06},
+	{R367TER_FSTATUS,	0x61},
+	{R367TER_FGOODPACK,	0xff},
+	{R367TER_FPACKCNT,	0xff},
+	{R367TER_FSPYMISC,	0x66},
+	{R367TER_FBERCPT4,	0x00},
+	{R367TER_FBERCPT3,	0x00},
+	{R367TER_FBERCPT2,	0x36},
+	{R367TER_FBERCPT1,	0x36},
+	{R367TER_FBERCPT0,	0x14},
+	{R367TER_FBERERR2,	0x00},
+	{R367TER_FBERERR1,	0x03},
+	{R367TER_FBERERR0,	0x28},
+	{R367TER_FSTATESM,	0x00},
+	{R367TER_FSTATESL,	0x02},
+	{R367TER_FSPYBER,	0x00},
+	{R367TER_FSPYDISTM,	0x01},
+	{R367TER_FSPYDISTL,	0x9f},
+	{R367TER_FSPYOBS7,	0xc9},
+	{R367TER_FSPYOBS6,	0x99},
+	{R367TER_FSPYOBS5,	0x08},
+	{R367TER_FSPYOBS4,	0xec},
+	{R367TER_FSPYOBS3,	0x01},
+	{R367TER_FSPYOBS2,	0x0f},
+	{R367TER_FSPYOBS1,	0xf5},
+	{R367TER_FSPYOBS0,	0x08},
+	{R367TER_SFDEMAP,	0x40},
+	{R367TER_SFERROR,	0x00},
+	{R367TER_SFAVSR,	0x30},
+	{R367TER_SFECSTATUS,	0xcc},
+	{R367TER_SFKDIV12,	0x20},
+	{R367TER_SFKDIV23,	0x40},
+	{R367TER_SFKDIV34,	0x20},
+	{R367TER_SFKDIV56,	0x20},
+	{R367TER_SFKDIV67,	0x00},
+	{R367TER_SFKDIV78,	0x20},
+	{R367TER_SFDILSTKM,	0x00},
+	{R367TER_SFDILSTKL,	0x00},
+	{R367TER_SFSTATUS,	0xb5},
+	{R367TER_SFDLYH,	0x90},
+	{R367TER_SFDLYM,	0x60},
+	{R367TER_SFDLYL,	0x01},
+	{R367TER_SFDLYSETH,	0xc0},
+	{R367TER_SFDLYSETM,	0x60},
+	{R367TER_SFDLYSETL,	0x00},
+	{R367TER_SFOBSCFG,	0x00},
+	{R367TER_SFOBSM,	0x47},
+	{R367TER_SFOBSL,	0x05},
+	{R367TER_SFECINFO,	0x40},
+	{R367TER_SFERRCTRL,	0x74},
+	{R367TER_SFERRCNTH,	0x80},
+	{R367TER_SFERRCNTM ,	0x00},
+	{R367TER_SFERRCNTL,	0x00},
+	{R367TER_SYMBRATEM,	0x2f},
+	{R367TER_SYMBRATEL,	0x50},
+	{R367TER_SYMBSTATUS,	0x7f},
+	{R367TER_SYMBCFG,	0x00},
+	{R367TER_SYMBFIFOM,	0xf4},
+	{R367TER_SYMBFIFOL,	0x0d},
+	{R367TER_SYMBOFFSM,	0xf0},
+	{R367TER_SYMBOFFSL,	0x2d},
+	{R367TER_DEBUG_LT4,	0x00},
+	{R367TER_DEBUG_LT5,	0x00},
+	{R367TER_DEBUG_LT6,	0x00},
+	{R367TER_DEBUG_LT7,	0x00},
+	{R367TER_DEBUG_LT8,	0x00},
+	{R367TER_DEBUG_LT9,	0x00},
+};
+
+#define RF_LOOKUP_TABLE_SIZE  31
+#define RF_LOOKUP_TABLE2_SIZE 16
+/* RF Level (for RF AGC->AGC1) Lookup Table, depends on the board and tuner.*/
+s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = {
+	{/*AGC1*/
+		48, 50, 51, 53, 54, 56, 57, 58, 60, 61, 62, 63,
+		64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
+		76, 77, 78, 80, 83, 85, 88,
+	}, {/*RF(dbm)*/
+		22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+		34, 35, 36, 37, 38, 39, 41, 42, 43, 44, 46, 47,
+		49, 50, 52, 53, 54, 55, 56,
+	}
+};
+/* RF Level (for IF AGC->AGC2) Lookup Table, depends on the board and tuner.*/
+s32 stv0367cab_RF_LookUp2[RF_LOOKUP_TABLE2_SIZE][RF_LOOKUP_TABLE2_SIZE] = {
+	{/*AGC2*/
+		28, 29, 31, 32, 34, 35, 36, 37,
+		38, 39, 40, 41, 42, 43, 44, 45,
+	}, {/*RF(dbm)*/
+		57, 58, 59, 60, 61, 62, 63, 64,
+		65, 66, 67, 68, 69, 70, 71, 72,
+	}
+};
+
+static struct st_register def0367cab[STV0367CAB_NBREGS] = {
+	{R367CAB_ID,		0x60},
+	{R367CAB_I2CRPT,	0xa0},
+	/*{R367CAB_I2CRPT,	0x22},*/
+	{R367CAB_TOPCTRL,	0x10},
+	{R367CAB_IOCFG0,	0x80},
+	{R367CAB_DAC0R,		0x00},
+	{R367CAB_IOCFG1,	0x00},
+	{R367CAB_DAC1R,		0x00},
+	{R367CAB_IOCFG2,	0x00},
+	{R367CAB_SDFR,		0x00},
+	{R367CAB_AUX_CLK,	0x00},
+	{R367CAB_FREESYS1,	0x00},
+	{R367CAB_FREESYS2,	0x00},
+	{R367CAB_FREESYS3,	0x00},
+	{R367CAB_GPIO_CFG,	0x55},
+	{R367CAB_GPIO_CMD,	0x01},
+	{R367CAB_TSTRES,	0x00},
+	{R367CAB_ANACTRL,	0x0d},/* was 0x00 need to check - I.M.L.*/
+	{R367CAB_TSTBUS,	0x00},
+	{R367CAB_RF_AGC1,	0xea},
+	{R367CAB_RF_AGC2,	0x82},
+	{R367CAB_ANADIGCTRL,	0x0b},
+	{R367CAB_PLLMDIV,	0x01},
+	{R367CAB_PLLNDIV,	0x08},
+	{R367CAB_PLLSETUP,	0x18},
+	{R367CAB_DUAL_AD12,	0x0C}, /* for xc5000 AGC voltage 1.6V */
+	{R367CAB_TSTBIST,	0x00},
+	{R367CAB_CTRL_1,	0x00},
+	{R367CAB_CTRL_2,	0x03},
+	{R367CAB_IT_STATUS1,	0x2b},
+	{R367CAB_IT_STATUS2,	0x08},
+	{R367CAB_IT_EN1,	0x00},
+	{R367CAB_IT_EN2,	0x00},
+	{R367CAB_CTRL_STATUS,	0x04},
+	{R367CAB_TEST_CTL,	0x00},
+	{R367CAB_AGC_CTL,	0x73},
+	{R367CAB_AGC_IF_CFG,	0x50},
+	{R367CAB_AGC_RF_CFG,	0x00},
+	{R367CAB_AGC_PWM_CFG,	0x03},
+	{R367CAB_AGC_PWR_REF_L,	0x5a},
+	{R367CAB_AGC_PWR_REF_H,	0x00},
+	{R367CAB_AGC_RF_TH_L,	0xff},
+	{R367CAB_AGC_RF_TH_H,	0x07},
+	{R367CAB_AGC_IF_LTH_L,	0x00},
+	{R367CAB_AGC_IF_LTH_H,	0x08},
+	{R367CAB_AGC_IF_HTH_L,	0xff},
+	{R367CAB_AGC_IF_HTH_H,	0x07},
+	{R367CAB_AGC_PWR_RD_L,	0xa0},
+	{R367CAB_AGC_PWR_RD_M,	0xe9},
+	{R367CAB_AGC_PWR_RD_H,	0x03},
+	{R367CAB_AGC_PWM_IFCMD_L,	0xe4},
+	{R367CAB_AGC_PWM_IFCMD_H,	0x00},
+	{R367CAB_AGC_PWM_RFCMD_L,	0xff},
+	{R367CAB_AGC_PWM_RFCMD_H,	0x07},
+	{R367CAB_IQDEM_CFG,	0x01},
+	{R367CAB_MIX_NCO_LL,	0x22},
+	{R367CAB_MIX_NCO_HL,	0x96},
+	{R367CAB_MIX_NCO_HH,	0x55},
+	{R367CAB_SRC_NCO_LL,	0xff},
+	{R367CAB_SRC_NCO_LH,	0x0c},
+	{R367CAB_SRC_NCO_HL,	0xf5},
+	{R367CAB_SRC_NCO_HH,	0x20},
+	{R367CAB_IQDEM_GAIN_SRC_L,	0x06},
+	{R367CAB_IQDEM_GAIN_SRC_H,	0x01},
+	{R367CAB_IQDEM_DCRM_CFG_LL,	0xfe},
+	{R367CAB_IQDEM_DCRM_CFG_LH,	0xff},
+	{R367CAB_IQDEM_DCRM_CFG_HL,	0x0f},
+	{R367CAB_IQDEM_DCRM_CFG_HH,	0x00},
+	{R367CAB_IQDEM_ADJ_COEFF0,	0x34},
+	{R367CAB_IQDEM_ADJ_COEFF1,	0xae},
+	{R367CAB_IQDEM_ADJ_COEFF2,	0x46},
+	{R367CAB_IQDEM_ADJ_COEFF3,	0x77},
+	{R367CAB_IQDEM_ADJ_COEFF4,	0x96},
+	{R367CAB_IQDEM_ADJ_COEFF5,	0x69},
+	{R367CAB_IQDEM_ADJ_COEFF6,	0xc7},
+	{R367CAB_IQDEM_ADJ_COEFF7,	0x01},
+	{R367CAB_IQDEM_ADJ_EN,	0x04},
+	{R367CAB_IQDEM_ADJ_AGC_REF,	0x94},
+	{R367CAB_ALLPASSFILT1,	0xc9},
+	{R367CAB_ALLPASSFILT2,	0x2d},
+	{R367CAB_ALLPASSFILT3,	0xa3},
+	{R367CAB_ALLPASSFILT4,	0xfb},
+	{R367CAB_ALLPASSFILT5,	0xf6},
+	{R367CAB_ALLPASSFILT6,	0x45},
+	{R367CAB_ALLPASSFILT7,	0x6f},
+	{R367CAB_ALLPASSFILT8,	0x7e},
+	{R367CAB_ALLPASSFILT9,	0x05},
+	{R367CAB_ALLPASSFILT10,	0x0a},
+	{R367CAB_ALLPASSFILT11,	0x51},
+	{R367CAB_TRL_AGC_CFG,	0x20},
+	{R367CAB_TRL_LPF_CFG,	0x28},
+	{R367CAB_TRL_LPF_ACQ_GAIN,	0x44},
+	{R367CAB_TRL_LPF_TRK_GAIN,	0x22},
+	{R367CAB_TRL_LPF_OUT_GAIN,	0x03},
+	{R367CAB_TRL_LOCKDET_LTH,	0x04},
+	{R367CAB_TRL_LOCKDET_HTH,	0x11},
+	{R367CAB_TRL_LOCKDET_TRGVAL,	0x20},
+	{R367CAB_IQ_QAM,	0x01},
+	{R367CAB_FSM_STATE,	0xa0},
+	{R367CAB_FSM_CTL,	0x08},
+	{R367CAB_FSM_STS,	0x0c},
+	{R367CAB_FSM_SNR0_HTH,	0x00},
+	{R367CAB_FSM_SNR1_HTH,	0x00},
+	{R367CAB_FSM_SNR2_HTH,	0x23},/* 0x00 */
+	{R367CAB_FSM_SNR0_LTH,	0x00},
+	{R367CAB_FSM_SNR1_LTH,	0x00},
+	{R367CAB_FSM_EQA1_HTH,	0x00},
+	{R367CAB_FSM_TEMPO,	0x32},
+	{R367CAB_FSM_CONFIG,	0x03},
+	{R367CAB_EQU_I_TESTTAP_L,	0x11},
+	{R367CAB_EQU_I_TESTTAP_M,	0x00},
+	{R367CAB_EQU_I_TESTTAP_H,	0x00},
+	{R367CAB_EQU_TESTAP_CFG,	0x00},
+	{R367CAB_EQU_Q_TESTTAP_L,	0xff},
+	{R367CAB_EQU_Q_TESTTAP_M,	0x00},
+	{R367CAB_EQU_Q_TESTTAP_H,	0x00},
+	{R367CAB_EQU_TAP_CTRL,	0x00},
+	{R367CAB_EQU_CTR_CRL_CONTROL_L,	0x11},
+	{R367CAB_EQU_CTR_CRL_CONTROL_H,	0x05},
+	{R367CAB_EQU_CTR_HIPOW_L,	0x00},
+	{R367CAB_EQU_CTR_HIPOW_H,	0x00},
+	{R367CAB_EQU_I_EQU_LO,	0xef},
+	{R367CAB_EQU_I_EQU_HI,	0x00},
+	{R367CAB_EQU_Q_EQU_LO,	0xee},
+	{R367CAB_EQU_Q_EQU_HI,	0x00},
+	{R367CAB_EQU_MAPPER,	0xc5},
+	{R367CAB_EQU_SWEEP_RATE,	0x80},
+	{R367CAB_EQU_SNR_LO,	0x64},
+	{R367CAB_EQU_SNR_HI,	0x03},
+	{R367CAB_EQU_GAMMA_LO,	0x00},
+	{R367CAB_EQU_GAMMA_HI,	0x00},
+	{R367CAB_EQU_ERR_GAIN,	0x36},
+	{R367CAB_EQU_RADIUS,	0xaa},
+	{R367CAB_EQU_FFE_MAINTAP,	0x00},
+	{R367CAB_EQU_FFE_LEAKAGE,	0x63},
+	{R367CAB_EQU_FFE_MAINTAP_POS,	0xdf},
+	{R367CAB_EQU_GAIN_WIDE,	0x88},
+	{R367CAB_EQU_GAIN_NARROW,	0x41},
+	{R367CAB_EQU_CTR_LPF_GAIN,	0xd1},
+	{R367CAB_EQU_CRL_LPF_GAIN,	0xa7},
+	{R367CAB_EQU_GLOBAL_GAIN,	0x06},
+	{R367CAB_EQU_CRL_LD_SEN,	0x85},
+	{R367CAB_EQU_CRL_LD_VAL,	0xe2},
+	{R367CAB_EQU_CRL_TFR,	0x20},
+	{R367CAB_EQU_CRL_BISTH_LO,	0x00},
+	{R367CAB_EQU_CRL_BISTH_HI,	0x00},
+	{R367CAB_EQU_SWEEP_RANGE_LO,	0x00},
+	{R367CAB_EQU_SWEEP_RANGE_HI,	0x00},
+	{R367CAB_EQU_CRL_LIMITER,	0x40},
+	{R367CAB_EQU_MODULUS_MAP,	0x90},
+	{R367CAB_EQU_PNT_GAIN,	0xa7},
+	{R367CAB_FEC_AC_CTR_0,	0x16},
+	{R367CAB_FEC_AC_CTR_1,	0x0b},
+	{R367CAB_FEC_AC_CTR_2,	0x88},
+	{R367CAB_FEC_AC_CTR_3,	0x02},
+	{R367CAB_FEC_STATUS,	0x12},
+	{R367CAB_RS_COUNTER_0,	0x7d},
+	{R367CAB_RS_COUNTER_1,	0xd0},
+	{R367CAB_RS_COUNTER_2,	0x19},
+	{R367CAB_RS_COUNTER_3,	0x0b},
+	{R367CAB_RS_COUNTER_4,	0xa3},
+	{R367CAB_RS_COUNTER_5,	0x00},
+	{R367CAB_BERT_0,	0x01},
+	{R367CAB_BERT_1,	0x25},
+	{R367CAB_BERT_2,	0x41},
+	{R367CAB_BERT_3,	0x39},
+	{R367CAB_OUTFORMAT_0,	0xc2},
+	{R367CAB_OUTFORMAT_1,	0x22},
+	{R367CAB_SMOOTHER_2,	0x28},
+	{R367CAB_TSMF_CTRL_0,	0x01},
+	{R367CAB_TSMF_CTRL_1,	0xc6},
+	{R367CAB_TSMF_CTRL_3,	0x43},
+	{R367CAB_TS_ON_ID_0,	0x00},
+	{R367CAB_TS_ON_ID_1,	0x00},
+	{R367CAB_TS_ON_ID_2,	0x00},
+	{R367CAB_TS_ON_ID_3,	0x00},
+	{R367CAB_RE_STATUS_0,	0x00},
+	{R367CAB_RE_STATUS_1,	0x00},
+	{R367CAB_RE_STATUS_2,	0x00},
+	{R367CAB_RE_STATUS_3,	0x00},
+	{R367CAB_TS_STATUS_0,	0x00},
+	{R367CAB_TS_STATUS_1,	0x00},
+	{R367CAB_TS_STATUS_2,	0xa0},
+	{R367CAB_TS_STATUS_3,	0x00},
+	{R367CAB_T_O_ID_0,	0x00},
+	{R367CAB_T_O_ID_1,	0x00},
+	{R367CAB_T_O_ID_2,	0x00},
+	{R367CAB_T_O_ID_3,	0x00},
+};
+
+static
+int stv0367_writeregs(struct stv0367_state *state, u16 reg, u8 *data, int len)
+{
+	u8 buf[len + 2];
+	struct i2c_msg msg = {
+		.addr = state->config->demod_address,
+		.flags = 0,
+		.buf = buf,
+		.len = len + 2
+	};
+	int ret;
+
+	buf[0] = MSB(reg);
+	buf[1] = LSB(reg);
+	memcpy(buf + 2, data, len);
+
+	if (i2cdebug)
+		printk(KERN_DEBUG "%s: %02x: %02x\n", __func__, reg, buf[2]);
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+	if (ret != 1)
+		printk(KERN_ERR "%s: i2c write error!\n", __func__);
+
+	return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int stv0367_writereg(struct stv0367_state *state, u16 reg, u8 data)
+{
+	return stv0367_writeregs(state, reg, &data, 1);
+}
+
+static u8 stv0367_readreg(struct stv0367_state *state, u16 reg)
+{
+	u8 b0[] = { 0, 0 };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{
+			.addr = state->config->demod_address,
+			.flags = 0,
+			.buf = b0,
+			.len = 2
+		}, {
+			.addr = state->config->demod_address,
+			.flags = I2C_M_RD,
+			.buf = b1,
+			.len = 1
+		}
+	};
+	int ret;
+
+	b0[0] = MSB(reg);
+	b0[1] = LSB(reg);
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+	if (ret != 2)
+		printk(KERN_ERR "%s: i2c read error\n", __func__);
+
+	if (i2cdebug)
+		printk(KERN_DEBUG "%s: %02x: %02x\n", __func__, reg, b1[0]);
+
+	return b1[0];
+}
+
+static void extract_mask_pos(u32 label, u8 *mask, u8 *pos)
+{
+	u8 position = 0, i = 0;
+
+	(*mask) = label & 0xff;
+
+	while ((position == 0) && (i < 8)) {
+		position = ((*mask) >> i) & 0x01;
+		i++;
+	}
+
+	(*pos) = (i - 1);
+}
+
+static void stv0367_writebits(struct stv0367_state *state, u32 label, u8 val)
+{
+	u8 reg, mask, pos;
+
+	reg = stv0367_readreg(state, (label >> 16) & 0xffff);
+	extract_mask_pos(label, &mask, &pos);
+
+	val = mask & (val << pos);
+
+	reg = (reg & (~mask)) | val;
+	stv0367_writereg(state, (label >> 16) & 0xffff, reg);
+
+}
+
+static void stv0367_setbits(u8 *reg, u32 label, u8 val)
+{
+	u8 mask, pos;
+
+	extract_mask_pos(label, &mask, &pos);
+
+	val = mask & (val << pos);
+
+	(*reg) = ((*reg) & (~mask)) | val;
+}
+
+static u8 stv0367_readbits(struct stv0367_state *state, u32 label)
+{
+	u8 val = 0xff;
+	u8 mask, pos;
+
+	extract_mask_pos(label, &mask, &pos);
+
+	val = stv0367_readreg(state, label >> 16);
+	val = (val & mask) >> pos;
+
+	return val;
+}
+
+u8 stv0367_getbits(u8 reg, u32 label)
+{
+	u8 mask, pos;
+
+	extract_mask_pos(label, &mask, &pos);
+
+	return (reg & mask) >> pos;
+}
+
+static int stv0367ter_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct stv0367_state *state = fe->demodulator_priv;
+	u8 tmp = stv0367_readreg(state, R367TER_I2CRPT);
+
+	dprintk("%s:\n", __func__);
+
+	if (enable) {
+		stv0367_setbits(&tmp, F367TER_STOP_ENABLE, 0);
+		stv0367_setbits(&tmp, F367TER_I2CT_ON, 1);
+	} else {
+		stv0367_setbits(&tmp, F367TER_STOP_ENABLE, 1);
+		stv0367_setbits(&tmp, F367TER_I2CT_ON, 0);
+	}
+
+	stv0367_writereg(state, R367TER_I2CRPT, tmp);
+
+	return 0;
+}
+
+static u32 stv0367_get_tuner_freq(struct dvb_frontend *fe)
+{
+	struct dvb_frontend_ops	*frontend_ops = NULL;
+	struct dvb_tuner_ops	*tuner_ops = NULL;
+	u32 freq = 0;
+	int err = 0;
+
+	dprintk("%s:\n", __func__);
+
+
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+	if (tuner_ops->get_frequency) {
+		err = tuner_ops->get_frequency(fe, &freq);
+		if (err < 0) {
+			printk(KERN_ERR "%s: Invalid parameter\n", __func__);
+			return err;
+		}
+
+		dprintk("%s: frequency=%d\n", __func__, freq);
+
+	} else
+		return -1;
+
+	return freq;
+}
+
+static u16 CellsCoeffs_8MHz_367cofdm[3][6][5] = {
+	{
+		{0x10EF, 0xE205, 0x10EF, 0xCE49, 0x6DA7}, /* CELL 1 COEFFS 27M*/
+		{0x2151, 0xc557, 0x2151, 0xc705, 0x6f93}, /* CELL 2 COEFFS */
+		{0x2503, 0xc000, 0x2503, 0xc375, 0x7194}, /* CELL 3 COEFFS */
+		{0x20E9, 0xca94, 0x20e9, 0xc153, 0x7194}, /* CELL 4 COEFFS */
+		{0x06EF, 0xF852, 0x06EF, 0xC057, 0x7207}, /* CELL 5 COEFFS */
+		{0x0000, 0x0ECC, 0x0ECC, 0x0000, 0x3647} /* CELL 6 COEFFS */
+	}, {
+		{0x10A0, 0xE2AF, 0x10A1, 0xCE76, 0x6D6D}, /* CELL 1 COEFFS 25M*/
+		{0x20DC, 0xC676, 0x20D9, 0xC80A, 0x6F29},
+		{0x2532, 0xC000, 0x251D, 0xC391, 0x706F},
+		{0x1F7A, 0xCD2B, 0x2032, 0xC15E, 0x711F},
+		{0x0698, 0xFA5E, 0x0568, 0xC059, 0x7193},
+		{0x0000, 0x0918, 0x149C, 0x0000, 0x3642} /* CELL 6 COEFFS */
+	}, {
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000}
+	}
+};
+
+static u16 CellsCoeffs_7MHz_367cofdm[3][6][5] = {
+	{
+		{0x12CA, 0xDDAF, 0x12CA, 0xCCEB, 0x6FB1}, /* CELL 1 COEFFS 27M*/
+		{0x2329, 0xC000, 0x2329, 0xC6B0, 0x725F}, /* CELL 2 COEFFS */
+		{0x2394, 0xC000, 0x2394, 0xC2C7, 0x7410}, /* CELL 3 COEFFS */
+		{0x251C, 0xC000, 0x251C, 0xC103, 0x74D9}, /* CELL 4 COEFFS */
+		{0x0804, 0xF546, 0x0804, 0xC040, 0x7544}, /* CELL 5 COEFFS */
+		{0x0000, 0x0CD9, 0x0CD9, 0x0000, 0x370A} /* CELL 6 COEFFS */
+	}, {
+		{0x1285, 0xDE47, 0x1285, 0xCD17, 0x6F76}, /*25M*/
+		{0x234C, 0xC000, 0x2348, 0xC6DA, 0x7206},
+		{0x23B4, 0xC000, 0x23AC, 0xC2DB, 0x73B3},
+		{0x253D, 0xC000, 0x25B6, 0xC10B, 0x747F},
+		{0x0721, 0xF79C, 0x065F, 0xC041, 0x74EB},
+		{0x0000, 0x08FA, 0x1162, 0x0000, 0x36FF}
+	}, {
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000}
+	}
+};
+
+static u16 CellsCoeffs_6MHz_367cofdm[3][6][5] = {
+	{
+		{0x1699, 0xD5B8, 0x1699, 0xCBC3, 0x713B}, /* CELL 1 COEFFS 27M*/
+		{0x2245, 0xC000, 0x2245, 0xC568, 0x74D5}, /* CELL 2 COEFFS */
+		{0x227F, 0xC000, 0x227F, 0xC1FC, 0x76C6}, /* CELL 3 COEFFS */
+		{0x235E, 0xC000, 0x235E, 0xC0A7, 0x778A}, /* CELL 4 COEFFS */
+		{0x0ECB, 0xEA0B, 0x0ECB, 0xC027, 0x77DD}, /* CELL 5 COEFFS */
+		{0x0000, 0x0B68, 0x0B68, 0x0000, 0xC89A}, /* CELL 6 COEFFS */
+	}, {
+		{0x1655, 0xD64E, 0x1658, 0xCBEF, 0x70FE}, /*25M*/
+		{0x225E, 0xC000, 0x2256, 0xC589, 0x7489},
+		{0x2293, 0xC000, 0x2295, 0xC209, 0x767E},
+		{0x2377, 0xC000, 0x23AA, 0xC0AB, 0x7746},
+		{0x0DC7, 0xEBC8, 0x0D07, 0xC027, 0x7799},
+		{0x0000, 0x0888, 0x0E9C, 0x0000, 0x3757}
+
+	}, {
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000}
+	}
+};
+
+static u32 stv0367ter_get_mclk(struct stv0367_state *state, u32 ExtClk_Hz)
+{
+	u32 mclk_Hz = 0; /* master clock frequency (Hz) */
+	u32 m, n, p;
+
+	dprintk("%s:\n", __func__);
+
+	if (stv0367_readbits(state, F367TER_BYPASS_PLLXN) == 0) {
+		n = (u32)stv0367_readbits(state, F367TER_PLL_NDIV);
+		if (n == 0)
+			n = n + 1;
+
+		m = (u32)stv0367_readbits(state, F367TER_PLL_MDIV);
+		if (m == 0)
+			m = m + 1;
+
+		p = (u32)stv0367_readbits(state, F367TER_PLL_PDIV);
+		if (p > 5)
+			p = 5;
+
+		mclk_Hz = ((ExtClk_Hz / 2) * n) / (m * (1 << p));
+
+		dprintk("N=%d M=%d P=%d mclk_Hz=%d ExtClk_Hz=%d\n",
+				n, m, p, mclk_Hz, ExtClk_Hz);
+	} else
+		mclk_Hz = ExtClk_Hz;
+
+	dprintk("%s: mclk_Hz=%d\n", __func__, mclk_Hz);
+
+	return mclk_Hz;
+}
+
+static int stv0367ter_filt_coeff_init(struct stv0367_state *state,
+				u16 CellsCoeffs[3][6][5], u32 DemodXtal)
+{
+	int i, j, k, freq;
+
+	dprintk("%s:\n", __func__);
+
+	freq = stv0367ter_get_mclk(state, DemodXtal);
+
+	if (freq == 53125000)
+		k = 1; /* equivalent to Xtal 25M on 362*/
+	else if (freq == 54000000)
+		k = 0; /* equivalent to Xtal 27M on 362*/
+	else if (freq == 52500000)
+		k = 2; /* equivalent to Xtal 30M on 362*/
+	else
+		return 0;
+
+	for (i = 1; i <= 6; i++) {
+		stv0367_writebits(state, F367TER_IIR_CELL_NB, i - 1);
+
+		for (j = 1; j <= 5; j++) {
+			stv0367_writereg(state,
+				(R367TER_IIRCX_COEFF1_MSB + 2 * (j - 1)),
+				MSB(CellsCoeffs[k][i-1][j-1]));
+			stv0367_writereg(state,
+				(R367TER_IIRCX_COEFF1_LSB + 2 * (j - 1)),
+				LSB(CellsCoeffs[k][i-1][j-1]));
+		}
+	}
+
+	return 1;
+
+}
+
+static void stv0367ter_agc_iir_lock_detect_set(struct stv0367_state *state)
+{
+	dprintk("%s:\n", __func__);
+
+	stv0367_writebits(state, F367TER_LOCK_DETECT_LSB, 0x00);
+
+	/* Lock detect 1 */
+	stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x00);
+	stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x06);
+	stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x04);
+
+	/* Lock detect 2 */
+	stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x01);
+	stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x06);
+	stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x04);
+
+	/* Lock detect 3 */
+	stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x02);
+	stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x01);
+	stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x00);
+
+	/* Lock detect 4 */
+	stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x03);
+	stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x01);
+	stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x00);
+
+}
+
+static int stv0367_iir_filt_init(struct stv0367_state *state, u8 Bandwidth,
+							u32 DemodXtalValue)
+{
+	dprintk("%s:\n", __func__);
+
+	stv0367_writebits(state, F367TER_NRST_IIR, 0);
+
+	switch (Bandwidth) {
+	case 6:
+		if (!stv0367ter_filt_coeff_init(state,
+				CellsCoeffs_6MHz_367cofdm,
+				DemodXtalValue))
+			return 0;
+		break;
+	case 7:
+		if (!stv0367ter_filt_coeff_init(state,
+				CellsCoeffs_7MHz_367cofdm,
+				DemodXtalValue))
+			return 0;
+		break;
+	case 8:
+		if (!stv0367ter_filt_coeff_init(state,
+				CellsCoeffs_8MHz_367cofdm,
+				DemodXtalValue))
+			return 0;
+		break;
+	default:
+		return 0;
+	}
+
+	stv0367_writebits(state, F367TER_NRST_IIR, 1);
+
+	return 1;
+}
+
+static void stv0367ter_agc_iir_rst(struct stv0367_state *state)
+{
+
+	u8 com_n;
+
+	dprintk("%s:\n", __func__);
+
+	com_n = stv0367_readbits(state, F367TER_COM_N);
+
+	stv0367_writebits(state, F367TER_COM_N, 0x07);
+
+	stv0367_writebits(state, F367TER_COM_SOFT_RSTN, 0x00);
+	stv0367_writebits(state, F367TER_COM_AGC_ON, 0x00);
+
+	stv0367_writebits(state, F367TER_COM_SOFT_RSTN, 0x01);
+	stv0367_writebits(state, F367TER_COM_AGC_ON, 0x01);
+
+	stv0367_writebits(state, F367TER_COM_N, com_n);
+
+}
+
+static int stv0367ter_duration(s32 mode, int tempo1, int tempo2, int tempo3)
+{
+	int local_tempo = 0;
+	switch (mode) {
+	case 0:
+		local_tempo = tempo1;
+		break;
+	case 1:
+		local_tempo = tempo2;
+		break ;
+
+	case 2:
+		local_tempo = tempo3;
+		break;
+
+	default:
+		break;
+	}
+	/*	msleep(local_tempo);  */
+	return local_tempo;
+}
+
+static enum
+stv0367_ter_signal_type stv0367ter_check_syr(struct stv0367_state *state)
+{
+	int wd = 100;
+	unsigned short int SYR_var;
+	s32 SYRStatus;
+
+	dprintk("%s:\n", __func__);
+
+	SYR_var = stv0367_readbits(state, F367TER_SYR_LOCK);
+
+	while ((!SYR_var) && (wd > 0)) {
+		usleep_range(2000, 3000);
+		wd -= 2;
+		SYR_var = stv0367_readbits(state, F367TER_SYR_LOCK);
+	}
+
+	if (!SYR_var)
+		SYRStatus = FE_TER_NOSYMBOL;
+	else
+		SYRStatus =  FE_TER_SYMBOLOK;
+
+	dprintk("stv0367ter_check_syr SYRStatus %s\n",
+				SYR_var == 0 ? "No Symbol" : "OK");
+
+	return SYRStatus;
+}
+
+static enum
+stv0367_ter_signal_type stv0367ter_check_cpamp(struct stv0367_state *state,
+								s32 FFTmode)
+{
+
+	s32  CPAMPvalue = 0, CPAMPStatus, CPAMPMin;
+	int wd = 0;
+
+	dprintk("%s:\n", __func__);
+
+	switch (FFTmode) {
+	case 0: /*2k mode*/
+		CPAMPMin = 20;
+		wd = 10;
+		break;
+	case 1: /*8k mode*/
+		CPAMPMin = 80;
+		wd = 55;
+		break;
+	case 2: /*4k mode*/
+		CPAMPMin = 40;
+		wd = 30;
+		break;
+	default:
+		CPAMPMin = 0xffff;  /*drives to NOCPAMP	*/
+		break;
+	}
+
+	dprintk("%s: CPAMPMin=%d wd=%d\n", __func__, CPAMPMin, wd);
+
+	CPAMPvalue = stv0367_readbits(state, F367TER_PPM_CPAMP_DIRECT);
+	while ((CPAMPvalue < CPAMPMin) && (wd > 0)) {
+		usleep_range(1000, 2000);
+		wd -= 1;
+		CPAMPvalue = stv0367_readbits(state, F367TER_PPM_CPAMP_DIRECT);
+		/*dprintk("CPAMPvalue= %d at wd=%d\n",CPAMPvalue,wd); */
+	}
+	dprintk("******last CPAMPvalue= %d at wd=%d\n", CPAMPvalue, wd);
+	if (CPAMPvalue < CPAMPMin) {
+		CPAMPStatus = FE_TER_NOCPAMP;
+		printk(KERN_ERR "CPAMP failed\n");
+	} else {
+		printk(KERN_ERR "CPAMP OK !\n");
+		CPAMPStatus = FE_TER_CPAMPOK;
+	}
+
+	return CPAMPStatus;
+}
+
+enum
+stv0367_ter_signal_type stv0367ter_lock_algo(struct stv0367_state *state)
+{
+	enum stv0367_ter_signal_type ret_flag;
+	short int wd, tempo;
+	u8 try, u_var1 = 0, u_var2 = 0, u_var3 = 0, u_var4 = 0, mode, guard;
+	u8 tmp, tmp2;
+
+	dprintk("%s:\n", __func__);
+
+	if (state == NULL)
+		return FE_TER_SWNOK;
+
+	try = 0;
+	do {
+		ret_flag = FE_TER_LOCKOK;
+
+		stv0367_writebits(state, F367TER_CORE_ACTIVE, 0);
+
+		if (state->config->if_iq_mode != 0)
+			stv0367_writebits(state, F367TER_COM_N, 0x07);
+
+		stv0367_writebits(state, F367TER_GUARD, 3);/* suggest 2k 1/4 */
+		stv0367_writebits(state, F367TER_MODE, 0);
+		stv0367_writebits(state, F367TER_SYR_TR_DIS, 0);
+		usleep_range(5000, 10000);
+
+		stv0367_writebits(state, F367TER_CORE_ACTIVE, 1);
+
+
+		if (stv0367ter_check_syr(state) == FE_TER_NOSYMBOL)
+			return FE_TER_NOSYMBOL;
+		else { /*
+			if chip locked on wrong mode first try,
+			it must lock correctly second try */
+			mode = stv0367_readbits(state, F367TER_SYR_MODE);
+			if (stv0367ter_check_cpamp(state, mode) ==
+							FE_TER_NOCPAMP) {
+				if (try == 0)
+					ret_flag = FE_TER_NOCPAMP;
+
+			}
+		}
+
+		try++;
+	} while ((try < 10) && (ret_flag != FE_TER_LOCKOK));
+
+	tmp  = stv0367_readreg(state, R367TER_SYR_STAT);
+	tmp2 = stv0367_readreg(state, R367TER_STATUS);
+	dprintk("state=%p\n", state);
+	dprintk("LOCK OK! mode=%d SYR_STAT=0x%x R367TER_STATUS=0x%x\n",
+							mode, tmp, tmp2);
+
+	tmp  = stv0367_readreg(state, R367TER_PRVIT);
+	tmp2 = stv0367_readreg(state, R367TER_I2CRPT);
+	dprintk("PRVIT=0x%x I2CRPT=0x%x\n", tmp, tmp2);
+
+	tmp  = stv0367_readreg(state, R367TER_GAIN_SRC1);
+	dprintk("GAIN_SRC1=0x%x\n", tmp);
+
+	if ((mode != 0) && (mode != 1) && (mode != 2))
+		return FE_TER_SWNOK;
+
+	/*guard=stv0367_readbits(state,F367TER_SYR_GUARD); */
+
+	/*suppress EPQ auto for SYR_GARD 1/16 or 1/32
+	and set channel predictor in automatic */
+#if 0
+	switch (guard) {
+
+	case 0:
+	case 1:
+		stv0367_writebits(state, F367TER_AUTO_LE_EN, 0);
+		stv0367_writereg(state, R367TER_CHC_CTL, 0x01);
+		break;
+	case 2:
+	case 3:
+		stv0367_writebits(state, F367TER_AUTO_LE_EN, 1);
+		stv0367_writereg(state, R367TER_CHC_CTL, 0x11);
+		break;
+
+	default:
+		return FE_TER_SWNOK;
+	}
+#endif
+
+	/*reset fec an reedsolo FOR 367 only*/
+	stv0367_writebits(state, F367TER_RST_SFEC, 1);
+	stv0367_writebits(state, F367TER_RST_REEDSOLO, 1);
+	usleep_range(1000, 2000);
+	stv0367_writebits(state, F367TER_RST_SFEC, 0);
+	stv0367_writebits(state, F367TER_RST_REEDSOLO, 0);
+
+	u_var1 = stv0367_readbits(state, F367TER_LK);
+	u_var2 = stv0367_readbits(state, F367TER_PRF);
+	u_var3 = stv0367_readbits(state, F367TER_TPS_LOCK);
+	/*	u_var4=stv0367_readbits(state,F367TER_TSFIFO_LINEOK); */
+
+	wd = stv0367ter_duration(mode, 125, 500, 250);
+	tempo = stv0367ter_duration(mode, 4, 16, 8);
+
+	/*while ( ((!u_var1)||(!u_var2)||(!u_var3)||(!u_var4))  && (wd>=0)) */
+	while (((!u_var1) || (!u_var2) || (!u_var3)) && (wd >= 0)) {
+		usleep_range(1000 * tempo, 1000 * (tempo + 1));
+		wd -= tempo;
+		u_var1 = stv0367_readbits(state, F367TER_LK);
+		u_var2 = stv0367_readbits(state, F367TER_PRF);
+		u_var3 = stv0367_readbits(state, F367TER_TPS_LOCK);
+		/*u_var4=stv0367_readbits(state, F367TER_TSFIFO_LINEOK); */
+	}
+
+	if (!u_var1)
+		return FE_TER_NOLOCK;
+
+
+	if (!u_var2)
+		return FE_TER_NOPRFOUND;
+
+	if (!u_var3)
+		return FE_TER_NOTPS;
+
+	guard = stv0367_readbits(state, F367TER_SYR_GUARD);
+	stv0367_writereg(state, R367TER_CHC_CTL, 0x11);
+	switch (guard) {
+	case 0:
+	case 1:
+		stv0367_writebits(state, F367TER_AUTO_LE_EN, 0);
+		/*stv0367_writereg(state,R367TER_CHC_CTL, 0x1);*/
+		stv0367_writebits(state, F367TER_SYR_FILTER, 0);
+		break;
+	case 2:
+	case 3:
+		stv0367_writebits(state, F367TER_AUTO_LE_EN, 1);
+		/*stv0367_writereg(state,R367TER_CHC_CTL, 0x11);*/
+		stv0367_writebits(state, F367TER_SYR_FILTER, 1);
+		break;
+
+	default:
+		return FE_TER_SWNOK;
+	}
+
+	/* apply Sfec workaround if 8K 64QAM CR!=1/2*/
+	if ((stv0367_readbits(state, F367TER_TPS_CONST) == 2) &&
+			(mode == 1) &&
+			(stv0367_readbits(state, F367TER_TPS_HPCODE) != 0)) {
+		stv0367_writereg(state, R367TER_SFDLYSETH, 0xc0);
+		stv0367_writereg(state, R367TER_SFDLYSETM, 0x60);
+		stv0367_writereg(state, R367TER_SFDLYSETL, 0x0);
+	} else
+		stv0367_writereg(state, R367TER_SFDLYSETH, 0x0);
+
+	wd = stv0367ter_duration(mode, 125, 500, 250);
+	u_var4 = stv0367_readbits(state, F367TER_TSFIFO_LINEOK);
+
+	while ((!u_var4) && (wd >= 0)) {
+		usleep_range(1000 * tempo, 1000 * (tempo + 1));
+		wd -= tempo;
+		u_var4 = stv0367_readbits(state, F367TER_TSFIFO_LINEOK);
+	}
+
+	if (!u_var4)
+		return FE_TER_NOLOCK;
+
+	/* for 367 leave COM_N at 0x7 for IQ_mode*/
+	/*if(ter_state->if_iq_mode!=FE_TER_NORMAL_IF_TUNER) {
+		tempo=0;
+		while ((stv0367_readbits(state,F367TER_COM_USEGAINTRK)!=1) &&
+		(stv0367_readbits(state,F367TER_COM_AGCLOCK)!=1)&&(tempo<100)) {
+			ChipWaitOrAbort(state,1);
+			tempo+=1;
+		}
+
+		stv0367_writebits(state,F367TER_COM_N,0x17);
+	} */
+
+	stv0367_writebits(state, F367TER_SYR_TR_DIS, 1);
+
+	dprintk("FE_TER_LOCKOK !!!\n");
+
+	return	FE_TER_LOCKOK;
+
+}
+
+static void stv0367ter_set_ts_mode(struct stv0367_state *state,
+					enum stv0367_ts_mode PathTS)
+{
+
+	dprintk("%s:\n", __func__);
+
+	if (state == NULL)
+		return;
+
+	stv0367_writebits(state, F367TER_TS_DIS, 0);
+	switch (PathTS) {
+	default:
+		/*for removing warning :default we can assume in parallel mode*/
+	case STV0367_PARALLEL_PUNCT_CLOCK:
+		stv0367_writebits(state, F367TER_TSFIFO_SERIAL, 0);
+		stv0367_writebits(state, F367TER_TSFIFO_DVBCI, 0);
+		break;
+	case STV0367_SERIAL_PUNCT_CLOCK:
+		stv0367_writebits(state, F367TER_TSFIFO_SERIAL, 1);
+		stv0367_writebits(state, F367TER_TSFIFO_DVBCI, 1);
+		break;
+	}
+}
+
+static void stv0367ter_set_clk_pol(struct stv0367_state *state,
+					enum stv0367_clk_pol clock)
+{
+
+	dprintk("%s:\n", __func__);
+
+	if (state == NULL)
+		return;
+
+	switch (clock) {
+	case STV0367_RISINGEDGE_CLOCK:
+		stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 1);
+		break;
+	case STV0367_FALLINGEDGE_CLOCK:
+		stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 0);
+		break;
+		/*case FE_TER_CLOCK_POLARITY_DEFAULT:*/
+	default:
+		stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 0);
+		break;
+	}
+}
+
+#if 0
+static void stv0367ter_core_sw(struct stv0367_state *state)
+{
+
+	dprintk("%s:\n", __func__);
+
+	stv0367_writebits(state, F367TER_CORE_ACTIVE, 0);
+	stv0367_writebits(state, F367TER_CORE_ACTIVE, 1);
+	msleep(350);
+}
+#endif
+static int stv0367ter_standby(struct dvb_frontend *fe, u8 standby_on)
+{
+	struct stv0367_state *state = fe->demodulator_priv;
+
+	dprintk("%s:\n", __func__);
+
+	if (standby_on) {
+		stv0367_writebits(state, F367TER_STDBY, 1);
+		stv0367_writebits(state, F367TER_STDBY_FEC, 1);
+		stv0367_writebits(state, F367TER_STDBY_CORE, 1);
+	} else {
+		stv0367_writebits(state, F367TER_STDBY, 0);
+		stv0367_writebits(state, F367TER_STDBY_FEC, 0);
+		stv0367_writebits(state, F367TER_STDBY_CORE, 0);
+	}
+
+	return 0;
+}
+
+static int stv0367ter_sleep(struct dvb_frontend *fe)
+{
+	return stv0367ter_standby(fe, 1);
+}
+
+int stv0367ter_init(struct dvb_frontend *fe)
+{
+	struct stv0367_state *state = fe->demodulator_priv;
+	struct stv0367ter_state *ter_state = state->ter_state;
+	int i;
+
+	dprintk("%s:\n", __func__);
+
+	ter_state->pBER = 0;
+
+	for (i = 0; i < STV0367TER_NBREGS; i++)
+		stv0367_writereg(state, def0367ter[i].addr,
+					def0367ter[i].value);
+
+	switch (state->config->xtal) {
+		/*set internal freq to 53.125MHz */
+	case 25000000:
+		stv0367_writereg(state, R367TER_PLLMDIV, 0xa);
+		stv0367_writereg(state, R367TER_PLLNDIV, 0x55);
+		stv0367_writereg(state, R367TER_PLLSETUP, 0x18);
+		break;
+	default:
+	case 27000000:
+		dprintk("FE_STV0367TER_SetCLKgen for 27Mhz\n");
+		stv0367_writereg(state, R367TER_PLLMDIV, 0x1);
+		stv0367_writereg(state, R367TER_PLLNDIV, 0x8);
+		stv0367_writereg(state, R367TER_PLLSETUP, 0x18);
+		break;
+	case 30000000:
+		stv0367_writereg(state, R367TER_PLLMDIV, 0xc);
+		stv0367_writereg(state, R367TER_PLLNDIV, 0x55);
+		stv0367_writereg(state, R367TER_PLLSETUP, 0x18);
+		break;
+	}
+
+	stv0367_writereg(state, R367TER_I2CRPT, 0xa0);
+	stv0367_writereg(state, R367TER_ANACTRL, 0x00);
+
+	/*Set TS1 and TS2 to serial or parallel mode */
+	stv0367ter_set_ts_mode(state, state->config->ts_mode);
+	stv0367ter_set_clk_pol(state, state->config->clk_pol);
+
+	state->chip_id = stv0367_readreg(state, R367TER_ID);
+	ter_state->first_lock = 0;
+	ter_state->unlock_counter = 2;
+
+	return 0;
+}
+
+static int stv0367ter_algo(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct stv0367_state *state = fe->demodulator_priv;
+	struct stv0367ter_state *ter_state = state->ter_state;
+	int offset = 0, tempo = 0;
+	u8 u_var;
+	u8 /*constell,*/ counter;
+	s8 step;
+	s32 timing_offset = 0;
+	u32 trl_nomrate = 0, InternalFreq = 0, temp = 0;
+
+	dprintk("%s:\n", __func__);
+
+	ter_state->frequency = p->frequency;
+	ter_state->force = FE_TER_FORCENONE
+			+ stv0367_readbits(state, F367TER_FORCE) * 2;
+	ter_state->if_iq_mode = state->config->if_iq_mode;
+	switch (state->config->if_iq_mode) {
+	case FE_TER_NORMAL_IF_TUNER:  /* Normal IF mode */
+		dprintk("ALGO: FE_TER_NORMAL_IF_TUNER selected\n");
+		stv0367_writebits(state, F367TER_TUNER_BB, 0);
+		stv0367_writebits(state, F367TER_LONGPATH_IF, 0);
+		stv0367_writebits(state, F367TER_DEMUX_SWAP, 0);
+		break;
+	case FE_TER_LONGPATH_IF_TUNER:  /* Long IF mode */
+		dprintk("ALGO: FE_TER_LONGPATH_IF_TUNER selected\n");
+		stv0367_writebits(state, F367TER_TUNER_BB, 0);
+		stv0367_writebits(state, F367TER_LONGPATH_IF, 1);
+		stv0367_writebits(state, F367TER_DEMUX_SWAP, 1);
+		break;
+	case FE_TER_IQ_TUNER:  /* IQ mode */
+		dprintk("ALGO: FE_TER_IQ_TUNER selected\n");
+		stv0367_writebits(state, F367TER_TUNER_BB, 1);
+		stv0367_writebits(state, F367TER_PPM_INVSEL, 0);
+		break;
+	default:
+		printk(KERN_ERR "ALGO: wrong TUNER type selected\n");
+		return -EINVAL;
+	}
+
+	usleep_range(5000, 7000);
+
+	switch (p->inversion) {
+	case INVERSION_AUTO:
+	default:
+		dprintk("%s: inversion AUTO\n", __func__);
+		if (ter_state->if_iq_mode == FE_TER_IQ_TUNER)
+			stv0367_writebits(state, F367TER_IQ_INVERT,
+						ter_state->sense);
+		else
+			stv0367_writebits(state, F367TER_INV_SPECTR,
+						ter_state->sense);
+
+		break;
+	case INVERSION_ON:
+	case INVERSION_OFF:
+		if (ter_state->if_iq_mode == FE_TER_IQ_TUNER)
+			stv0367_writebits(state, F367TER_IQ_INVERT,
+						p->inversion);
+		else
+			stv0367_writebits(state, F367TER_INV_SPECTR,
+						p->inversion);
+
+		break;
+	}
+
+	if ((ter_state->if_iq_mode != FE_TER_NORMAL_IF_TUNER) &&
+				(ter_state->pBW != ter_state->bw)) {
+		stv0367ter_agc_iir_lock_detect_set(state);
+
+		/*set fine agc target to 180 for LPIF or IQ mode*/
+		/* set Q_AGCTarget */
+		stv0367_writebits(state, F367TER_SEL_IQNTAR, 1);
+		stv0367_writebits(state, F367TER_AUT_AGC_TARGET_MSB, 0xB);
+		/*stv0367_writebits(state,AUT_AGC_TARGET_LSB,0x04); */
+
+		/* set Q_AGCTarget */
+		stv0367_writebits(state, F367TER_SEL_IQNTAR, 0);
+		stv0367_writebits(state, F367TER_AUT_AGC_TARGET_MSB, 0xB);
+		/*stv0367_writebits(state,AUT_AGC_TARGET_LSB,0x04); */
+
+		if (!stv0367_iir_filt_init(state, ter_state->bw,
+						state->config->xtal))
+			return -EINVAL;
+		/*set IIR filter once for 6,7 or 8MHz BW*/
+		ter_state->pBW = ter_state->bw;
+
+		stv0367ter_agc_iir_rst(state);
+	}
+
+	if (ter_state->hierarchy == FE_TER_HIER_LOW_PRIO)
+		stv0367_writebits(state, F367TER_BDI_LPSEL, 0x01);
+	else
+		stv0367_writebits(state, F367TER_BDI_LPSEL, 0x00);
+
+	InternalFreq = stv0367ter_get_mclk(state, state->config->xtal) / 1000;
+	temp = (int)
+		((((ter_state->bw * 64 * (1 << 15) * 100)
+						/ (InternalFreq)) * 10) / 7);
+
+	stv0367_writebits(state, F367TER_TRL_NOMRATE_LSB, temp % 2);
+	temp = temp / 2;
+	stv0367_writebits(state, F367TER_TRL_NOMRATE_HI, temp / 256);
+	stv0367_writebits(state, F367TER_TRL_NOMRATE_LO, temp % 256);
+
+	temp = stv0367_readbits(state, F367TER_TRL_NOMRATE_HI) * 512 +
+			stv0367_readbits(state, F367TER_TRL_NOMRATE_LO) * 2 +
+			stv0367_readbits(state, F367TER_TRL_NOMRATE_LSB);
+	temp = (int)(((1 << 17) * ter_state->bw * 1000) / (7 * (InternalFreq)));
+	stv0367_writebits(state, F367TER_GAIN_SRC_HI, temp / 256);
+	stv0367_writebits(state, F367TER_GAIN_SRC_LO, temp % 256);
+	temp = stv0367_readbits(state, F367TER_GAIN_SRC_HI) * 256 +
+			stv0367_readbits(state, F367TER_GAIN_SRC_LO);
+
+	temp = (int)
+		((InternalFreq - state->config->if_khz) * (1 << 16)
+							/ (InternalFreq));
+
+	dprintk("DEROT temp=0x%x\n", temp);
+	stv0367_writebits(state, F367TER_INC_DEROT_HI, temp / 256);
+	stv0367_writebits(state, F367TER_INC_DEROT_LO, temp % 256);
+
+	ter_state->echo_pos = 0;
+	ter_state->ucblocks = 0; /* liplianin */
+	ter_state->pBER = 0; /* liplianin */
+	stv0367_writebits(state, F367TER_LONG_ECHO, ter_state->echo_pos);
+
+	if (stv0367ter_lock_algo(state) != FE_TER_LOCKOK)
+		return 0;
+
+	ter_state->state = FE_TER_LOCKOK;
+
+	ter_state->mode = stv0367_readbits(state, F367TER_SYR_MODE);
+	ter_state->guard = stv0367_readbits(state, F367TER_SYR_GUARD);
+
+	ter_state->first_lock = 1; /* we know sense now :) */
+
+	ter_state->agc_val =
+			(stv0367_readbits(state, F367TER_AGC1_VAL_LO) << 16) +
+			(stv0367_readbits(state, F367TER_AGC1_VAL_HI) << 24) +
+			stv0367_readbits(state, F367TER_AGC2_VAL_LO) +
+			(stv0367_readbits(state, F367TER_AGC2_VAL_HI) << 8);
+
+	/* Carrier offset calculation */
+	stv0367_writebits(state, F367TER_FREEZE, 1);
+	offset = (stv0367_readbits(state, F367TER_CRL_FOFFSET_VHI) << 16) ;
+	offset += (stv0367_readbits(state, F367TER_CRL_FOFFSET_HI) << 8);
+	offset += (stv0367_readbits(state, F367TER_CRL_FOFFSET_LO));
+	stv0367_writebits(state, F367TER_FREEZE, 0);
+	if (offset > 8388607)
+		offset -= 16777216;
+
+	offset = offset * 2 / 16384;
+
+	if (ter_state->mode == FE_TER_MODE_2K)
+		offset = (offset * 4464) / 1000;/*** 1 FFT BIN=4.464khz***/
+	else if (ter_state->mode == FE_TER_MODE_4K)
+		offset = (offset * 223) / 100;/*** 1 FFT BIN=2.23khz***/
+	else  if (ter_state->mode == FE_TER_MODE_8K)
+		offset = (offset * 111) / 100;/*** 1 FFT BIN=1.1khz***/
+
+	if (stv0367_readbits(state, F367TER_PPM_INVSEL) == 1) {
+		if ((stv0367_readbits(state, F367TER_INV_SPECTR) ==
+				(stv0367_readbits(state,
+					F367TER_STATUS_INV_SPECRUM) == 1)))
+			offset = offset * -1;
+	}
+
+	if (ter_state->bw == 6)
+		offset = (offset * 6) / 8;
+	else if (ter_state->bw == 7)
+		offset = (offset * 7) / 8;
+
+	ter_state->frequency += offset;
+
+	tempo = 10;  /* exit even if timing_offset stays null */
+	while ((timing_offset == 0) && (tempo > 0)) {
+		usleep_range(10000, 20000);	/*was 20ms  */
+		/* fine tuning of timing offset if required */
+		timing_offset = stv0367_readbits(state, F367TER_TRL_TOFFSET_LO)
+				+ 256 * stv0367_readbits(state,
+							F367TER_TRL_TOFFSET_HI);
+		if (timing_offset >= 32768)
+			timing_offset -= 65536;
+		trl_nomrate = (512 * stv0367_readbits(state,
+							F367TER_TRL_NOMRATE_HI)
+			+ stv0367_readbits(state, F367TER_TRL_NOMRATE_LO) * 2
+			+ stv0367_readbits(state, F367TER_TRL_NOMRATE_LSB));
+
+		timing_offset = ((signed)(1000000 / trl_nomrate) *
+							timing_offset) / 2048;
+		tempo--;
+	}
+
+	if (timing_offset <= 0) {
+		timing_offset = (timing_offset - 11) / 22;
+		step = -1;
+	} else {
+		timing_offset = (timing_offset + 11) / 22;
+		step = 1;
+	}
+
+	for (counter = 0; counter < abs(timing_offset); counter++) {
+		trl_nomrate += step;
+		stv0367_writebits(state, F367TER_TRL_NOMRATE_LSB,
+						trl_nomrate % 2);
+		stv0367_writebits(state, F367TER_TRL_NOMRATE_LO,
+						trl_nomrate / 2);
+		usleep_range(1000, 2000);
+	}
+
+	usleep_range(5000, 6000);
+	/* unlocks could happen in case of trl centring big step,
+	then a core off/on restarts demod */
+	u_var = stv0367_readbits(state, F367TER_LK);
+
+	if (!u_var) {
+		stv0367_writebits(state, F367TER_CORE_ACTIVE, 0);
+		msleep(20);
+		stv0367_writebits(state, F367TER_CORE_ACTIVE, 1);
+	}
+
+	return 0;
+}
+
+static int stv0367ter_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct stv0367_state *state = fe->demodulator_priv;
+	struct stv0367ter_state *ter_state = state->ter_state;
+
+	/*u8 trials[2]; */
+	s8 num_trials, index;
+	u8 SenseTrials[] = { INVERSION_ON, INVERSION_OFF };
+
+	stv0367ter_init(fe);
+
+	if (fe->ops.tuner_ops.set_params) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	switch (p->transmission_mode) {
+	default:
+	case TRANSMISSION_MODE_AUTO:
+	case TRANSMISSION_MODE_2K:
+		ter_state->mode = FE_TER_MODE_2K;
+		break;
+/*	case TRANSMISSION_MODE_4K:
+		pLook.mode = FE_TER_MODE_4K;
+		break;*/
+	case TRANSMISSION_MODE_8K:
+		ter_state->mode = FE_TER_MODE_8K;
+		break;
+	}
+
+	switch (p->guard_interval) {
+	default:
+	case GUARD_INTERVAL_1_32:
+	case GUARD_INTERVAL_1_16:
+	case GUARD_INTERVAL_1_8:
+	case GUARD_INTERVAL_1_4:
+		ter_state->guard = p->guard_interval;
+		break;
+	case GUARD_INTERVAL_AUTO:
+		ter_state->guard = GUARD_INTERVAL_1_32;
+		break;
+	}
+
+	switch (p->bandwidth_hz) {
+	case 6000000:
+		ter_state->bw = FE_TER_CHAN_BW_6M;
+		break;
+	case 7000000:
+		ter_state->bw = FE_TER_CHAN_BW_7M;
+		break;
+	case 8000000:
+	default:
+		ter_state->bw = FE_TER_CHAN_BW_8M;
+	}
+
+	ter_state->hierarchy = FE_TER_HIER_NONE;
+
+	switch (p->inversion) {
+	case INVERSION_OFF:
+	case INVERSION_ON:
+		num_trials = 1;
+		break;
+	default:
+		num_trials = 2;
+		if (ter_state->first_lock)
+			num_trials = 1;
+		break;
+	}
+
+	ter_state->state = FE_TER_NOLOCK;
+	index = 0;
+
+	while (((index) < num_trials) && (ter_state->state != FE_TER_LOCKOK)) {
+		if (!ter_state->first_lock) {
+			if (p->inversion == INVERSION_AUTO)
+				ter_state->sense = SenseTrials[index];
+
+		}
+		stv0367ter_algo(fe);
+
+		if ((ter_state->state == FE_TER_LOCKOK) &&
+				(p->inversion == INVERSION_AUTO) &&
+								(index == 1)) {
+			/* invert spectrum sense */
+			SenseTrials[index] = SenseTrials[0];
+			SenseTrials[(index + 1) % 2] = (SenseTrials[1] + 1) % 2;
+		}
+
+		index++;
+	}
+
+	return 0;
+}
+
+static int stv0367ter_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct stv0367_state *state = fe->demodulator_priv;
+	struct stv0367ter_state *ter_state = state->ter_state;
+	u32 errs = 0;
+
+	/*wait for counting completion*/
+	if (stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 0) {
+		errs =
+			((u32)stv0367_readbits(state, F367TER_ERR_CNT1)
+			* (1 << 16))
+			+ ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_HI)
+			* (1 << 8))
+			+ ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_LO));
+		ter_state->ucblocks = errs;
+	}
+
+	(*ucblocks) = ter_state->ucblocks;
+
+	return 0;
+}
+
+static int stv0367ter_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct stv0367_state *state = fe->demodulator_priv;
+	struct stv0367ter_state *ter_state = state->ter_state;
+
+	int error = 0;
+	enum stv0367_ter_mode mode;
+	int constell = 0,/* snr = 0,*/ Data = 0;
+
+	p->frequency = stv0367_get_tuner_freq(fe);
+	if ((int)p->frequency < 0)
+		p->frequency = -p->frequency;
+
+	constell = stv0367_readbits(state, F367TER_TPS_CONST);
+	if (constell == 0)
+		p->modulation = QPSK;
+	else if (constell == 1)
+		p->modulation = QAM_16;
+	else
+		p->modulation = QAM_64;
+
+	p->inversion = stv0367_readbits(state, F367TER_INV_SPECTR);
+
+	/* Get the Hierarchical mode */
+	Data = stv0367_readbits(state, F367TER_TPS_HIERMODE);
+
+	switch (Data) {
+	case 0:
+		p->hierarchy = HIERARCHY_NONE;
+		break;
+	case 1:
+		p->hierarchy = HIERARCHY_1;
+		break;
+	case 2:
+		p->hierarchy = HIERARCHY_2;
+		break;
+	case 3:
+		p->hierarchy = HIERARCHY_4;
+		break;
+	default:
+		p->hierarchy = HIERARCHY_AUTO;
+		break; /* error */
+	}
+
+	/* Get the FEC Rate */
+	if (ter_state->hierarchy == FE_TER_HIER_LOW_PRIO)
+		Data = stv0367_readbits(state, F367TER_TPS_LPCODE);
+	else
+		Data = stv0367_readbits(state, F367TER_TPS_HPCODE);
+
+	switch (Data) {
+	case 0:
+		p->code_rate_HP = FEC_1_2;
+		break;
+	case 1:
+		p->code_rate_HP = FEC_2_3;
+		break;
+	case 2:
+		p->code_rate_HP = FEC_3_4;
+		break;
+	case 3:
+		p->code_rate_HP = FEC_5_6;
+		break;
+	case 4:
+		p->code_rate_HP = FEC_7_8;
+		break;
+	default:
+		p->code_rate_HP = FEC_AUTO;
+		break; /* error */
+	}
+
+	mode = stv0367_readbits(state, F367TER_SYR_MODE);
+
+	switch (mode) {
+	case FE_TER_MODE_2K:
+		p->transmission_mode = TRANSMISSION_MODE_2K;
+		break;
+/*	case FE_TER_MODE_4K:
+		p->transmission_mode = TRANSMISSION_MODE_4K;
+		break;*/
+	case FE_TER_MODE_8K:
+		p->transmission_mode = TRANSMISSION_MODE_8K;
+		break;
+	default:
+		p->transmission_mode = TRANSMISSION_MODE_AUTO;
+	}
+
+	p->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD);
+
+	return error;
+}
+
+static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct stv0367_state *state = fe->demodulator_priv;
+	u32 snru32 = 0;
+	int cpt = 0;
+	u8 cut = stv0367_readbits(state, F367TER_IDENTIFICATIONREG);
+
+	while (cpt < 10) {
+		usleep_range(2000, 3000);
+		if (cut == 0x50) /*cut 1.0 cut 1.1*/
+			snru32 += stv0367_readbits(state, F367TER_CHCSNR) / 4;
+		else /*cu2.0*/
+			snru32 += 125 * stv0367_readbits(state, F367TER_CHCSNR);
+
+		cpt++;
+	}
+
+	snru32 /= 10;/*average on 10 values*/
+
+	*snr = snru32 / 1000;
+
+	return 0;
+}
+
+#if 0
+static int stv0367ter_status(struct dvb_frontend *fe)
+{
+
+	struct stv0367_state *state = fe->demodulator_priv;
+	struct stv0367ter_state *ter_state = state->ter_state;
+	int locked = FALSE;
+
+	locked = (stv0367_readbits(state, F367TER_LK));
+	if (!locked)
+		ter_state->unlock_counter += 1;
+	else
+		ter_state->unlock_counter = 0;
+
+	if (ter_state->unlock_counter > 2) {
+		if (!stv0367_readbits(state, F367TER_TPS_LOCK) ||
+				(!stv0367_readbits(state, F367TER_LK))) {
+			stv0367_writebits(state, F367TER_CORE_ACTIVE, 0);
+			usleep_range(2000, 3000);
+			stv0367_writebits(state, F367TER_CORE_ACTIVE, 1);
+			msleep(350);
+			locked = (stv0367_readbits(state, F367TER_TPS_LOCK)) &&
+					(stv0367_readbits(state, F367TER_LK));
+		}
+
+	}
+
+	return locked;
+}
+#endif
+static int stv0367ter_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct stv0367_state *state = fe->demodulator_priv;
+
+	dprintk("%s:\n", __func__);
+
+	*status = 0;
+
+	if (stv0367_readbits(state, F367TER_LK)) {
+		*status |= FE_HAS_LOCK;
+		dprintk("%s: stv0367 has locked\n", __func__);
+	}
+
+	return 0;
+}
+
+static int stv0367ter_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct stv0367_state *state = fe->demodulator_priv;
+	struct stv0367ter_state *ter_state = state->ter_state;
+	u32 Errors = 0, tber = 0, temporary = 0;
+	int abc = 0, def = 0;
+
+
+	/*wait for counting completion*/
+	if (stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 0)
+		Errors = ((u32)stv0367_readbits(state, F367TER_SFEC_ERR_CNT)
+			* (1 << 16))
+			+ ((u32)stv0367_readbits(state, F367TER_SFEC_ERR_CNT_HI)
+			* (1 << 8))
+			+ ((u32)stv0367_readbits(state,
+						F367TER_SFEC_ERR_CNT_LO));
+	/*measurement not completed, load previous value*/
+	else {
+		tber = ter_state->pBER;
+		return 0;
+	}
+
+	abc = stv0367_readbits(state, F367TER_SFEC_ERR_SOURCE);
+	def = stv0367_readbits(state, F367TER_SFEC_NUM_EVENT);
+
+	if (Errors == 0) {
+		tber = 0;
+	} else if (abc == 0x7) {
+		if (Errors <= 4) {
+			temporary = (Errors * 1000000000) / (8 * (1 << 14));
+			temporary =  temporary;
+		} else if (Errors <= 42) {
+			temporary = (Errors * 100000000) / (8 * (1 << 14));
+			temporary = temporary * 10;
+		} else if (Errors <= 429) {
+			temporary = (Errors * 10000000) / (8 * (1 << 14));
+			temporary = temporary * 100;
+		} else if (Errors <= 4294) {
+			temporary = (Errors * 1000000) / (8 * (1 << 14));
+			temporary = temporary * 1000;
+		} else if (Errors <= 42949) {
+			temporary = (Errors * 100000) / (8 * (1 << 14));
+			temporary = temporary * 10000;
+		} else if (Errors <= 429496) {
+			temporary = (Errors * 10000) / (8 * (1 << 14));
+			temporary = temporary * 100000;
+		} else { /*if (Errors<4294967) 2^22 max error*/
+			temporary = (Errors * 1000) / (8 * (1 << 14));
+			temporary = temporary * 100000;	/* still to *10 */
+		}
+
+		/* Byte error*/
+		if (def == 2)
+			/*tber=Errors/(8*(1 <<14));*/
+			tber = temporary;
+		else if (def == 3)
+			/*tber=Errors/(8*(1 <<16));*/
+			tber = temporary / 4;
+		else if (def == 4)
+			/*tber=Errors/(8*(1 <<18));*/
+			tber = temporary / 16;
+		else if (def == 5)
+			/*tber=Errors/(8*(1 <<20));*/
+			tber = temporary / 64;
+		else if (def == 6)
+			/*tber=Errors/(8*(1 <<22));*/
+			tber = temporary / 256;
+		else
+			/* should not pass here*/
+			tber = 0;
+
+		if ((Errors < 4294967) && (Errors > 429496))
+			tber *= 10;
+
+	}
+
+	/* save actual value */
+	ter_state->pBER = tber;
+
+	(*ber) = tber;
+
+	return 0;
+}
+#if 0
+static u32 stv0367ter_get_per(struct stv0367_state *state)
+{
+	struct stv0367ter_state *ter_state = state->ter_state;
+	u32 Errors = 0, Per = 0, temporary = 0;
+	int abc = 0, def = 0, cpt = 0;
+
+	while (((stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 1) &&
+			(cpt < 400)) || ((Errors == 0) && (cpt < 400))) {
+		usleep_range(1000, 2000);
+		Errors = ((u32)stv0367_readbits(state, F367TER_ERR_CNT1)
+			* (1 << 16))
+			+ ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_HI)
+			* (1 << 8))
+			+ ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_LO));
+		cpt++;
+	}
+	abc = stv0367_readbits(state, F367TER_ERR_SRC1);
+	def = stv0367_readbits(state, F367TER_NUM_EVT1);
+
+	if (Errors == 0)
+		Per = 0;
+	else if (abc == 0x9) {
+		if (Errors <= 4) {
+			temporary = (Errors * 1000000000) / (8 * (1 << 8));
+			temporary =  temporary;
+		} else if (Errors <= 42) {
+			temporary = (Errors * 100000000) / (8 * (1 << 8));
+			temporary = temporary * 10;
+		} else if (Errors <= 429) {
+			temporary = (Errors * 10000000) / (8 * (1 << 8));
+			temporary = temporary * 100;
+		} else if (Errors <= 4294) {
+			temporary = (Errors * 1000000) / (8 * (1 << 8));
+			temporary = temporary * 1000;
+		} else if (Errors <= 42949) {
+			temporary = (Errors * 100000) / (8 * (1 << 8));
+			temporary = temporary * 10000;
+		} else { /*if(Errors<=429496)  2^16 errors max*/
+			temporary = (Errors * 10000) / (8 * (1 << 8));
+			temporary = temporary * 100000;
+		}
+
+		/* pkt error*/
+		if (def == 2)
+			/*Per=Errors/(1 << 8);*/
+			Per = temporary;
+		else if (def == 3)
+			/*Per=Errors/(1 << 10);*/
+			Per = temporary / 4;
+		else if (def == 4)
+			/*Per=Errors/(1 << 12);*/
+			Per = temporary / 16;
+		else if (def == 5)
+			/*Per=Errors/(1 << 14);*/
+			Per = temporary / 64;
+		else if (def == 6)
+			/*Per=Errors/(1 << 16);*/
+			Per = temporary / 256;
+		else
+			Per = 0;
+
+	}
+	/* save actual value */
+	ter_state->pPER = Per;
+
+	return Per;
+}
+#endif
+static int stv0367_get_tune_settings(struct dvb_frontend *fe,
+					struct dvb_frontend_tune_settings
+					*fe_tune_settings)
+{
+	fe_tune_settings->min_delay_ms = 1000;
+	fe_tune_settings->step_size = 0;
+	fe_tune_settings->max_drift = 0;
+
+	return 0;
+}
+
+static void stv0367_release(struct dvb_frontend *fe)
+{
+	struct stv0367_state *state = fe->demodulator_priv;
+
+	kfree(state->ter_state);
+	kfree(state->cab_state);
+	kfree(state);
+}
+
+static struct dvb_frontend_ops stv0367ter_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name			= "ST STV0367 DVB-T",
+		.frequency_min		= 47000000,
+		.frequency_max		= 862000000,
+		.frequency_stepsize	= 15625,
+		.frequency_tolerance	= 0,
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+			FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+			FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER |
+			FE_CAN_INVERSION_AUTO |
+			FE_CAN_MUTE_TS
+	},
+	.release = stv0367_release,
+	.init = stv0367ter_init,
+	.sleep = stv0367ter_sleep,
+	.i2c_gate_ctrl = stv0367ter_gate_ctrl,
+	.set_frontend = stv0367ter_set_frontend,
+	.get_frontend = stv0367ter_get_frontend,
+	.get_tune_settings = stv0367_get_tune_settings,
+	.read_status = stv0367ter_read_status,
+	.read_ber = stv0367ter_read_ber,/* too slow */
+/*	.read_signal_strength = stv0367_read_signal_strength,*/
+	.read_snr = stv0367ter_read_snr,
+	.read_ucblocks = stv0367ter_read_ucblocks,
+};
+
+struct dvb_frontend *stv0367ter_attach(const struct stv0367_config *config,
+				   struct i2c_adapter *i2c)
+{
+	struct stv0367_state *state = NULL;
+	struct stv0367ter_state *ter_state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct stv0367_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+	ter_state = kzalloc(sizeof(struct stv0367ter_state), GFP_KERNEL);
+	if (ter_state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->i2c = i2c;
+	state->config = config;
+	state->ter_state = ter_state;
+	state->fe.ops = stv0367ter_ops;
+	state->fe.demodulator_priv = state;
+	state->chip_id = stv0367_readreg(state, 0xf000);
+
+	dprintk("%s: chip_id = 0x%x\n", __func__, state->chip_id);
+
+	/* check if the demod is there */
+	if ((state->chip_id != 0x50) && (state->chip_id != 0x60))
+		goto error;
+
+	return &state->fe;
+
+error:
+	kfree(ter_state);
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(stv0367ter_attach);
+
+static int stv0367cab_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct stv0367_state *state = fe->demodulator_priv;
+
+	dprintk("%s:\n", __func__);
+
+	stv0367_writebits(state, F367CAB_I2CT_ON, (enable > 0) ? 1 : 0);
+
+	return 0;
+}
+
+static u32 stv0367cab_get_mclk(struct dvb_frontend *fe, u32 ExtClk_Hz)
+{
+	struct stv0367_state *state = fe->demodulator_priv;
+	u32 mclk_Hz = 0;/* master clock frequency (Hz) */
+	u32 M, N, P;
+
+
+	if (stv0367_readbits(state, F367CAB_BYPASS_PLLXN) == 0) {
+		N = (u32)stv0367_readbits(state, F367CAB_PLL_NDIV);
+		if (N == 0)
+			N = N + 1;
+
+		M = (u32)stv0367_readbits(state, F367CAB_PLL_MDIV);
+		if (M == 0)
+			M = M + 1;
+
+		P = (u32)stv0367_readbits(state, F367CAB_PLL_PDIV);
+
+		if (P > 5)
+			P = 5;
+
+		mclk_Hz = ((ExtClk_Hz / 2) * N) / (M * (1 << P));
+		dprintk("stv0367cab_get_mclk BYPASS_PLLXN mclk_Hz=%d\n",
+								mclk_Hz);
+	} else
+		mclk_Hz = ExtClk_Hz;
+
+	dprintk("stv0367cab_get_mclk final mclk_Hz=%d\n", mclk_Hz);
+
+	return mclk_Hz;
+}
+
+static u32 stv0367cab_get_adc_freq(struct dvb_frontend *fe, u32 ExtClk_Hz)
+{
+	u32 ADCClk_Hz = ExtClk_Hz;
+
+	ADCClk_Hz = stv0367cab_get_mclk(fe, ExtClk_Hz);
+
+	return ADCClk_Hz;
+}
+
+enum stv0367cab_mod stv0367cab_SetQamSize(struct stv0367_state *state,
+					u32 SymbolRate,
+					enum stv0367cab_mod QAMSize)
+{
+	/* Set QAM size */
+	stv0367_writebits(state, F367CAB_QAM_MODE, QAMSize);
+
+	/* Set Registers settings specific to the QAM size */
+	switch (QAMSize) {
+	case FE_CAB_MOD_QAM4:
+		stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
+		break;
+	case FE_CAB_MOD_QAM16:
+		stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x64);
+		stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
+		stv0367_writereg(state, R367CAB_FSM_STATE, 0x90);
+		stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
+		stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7);
+		stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x95);
+		stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40);
+		stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0x8a);
+		break;
+	case FE_CAB_MOD_QAM32:
+		stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
+		stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x6e);
+		stv0367_writereg(state, R367CAB_FSM_STATE, 0xb0);
+		stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
+		stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xb7);
+		stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x9d);
+		stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x7f);
+		stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7);
+		break;
+	case FE_CAB_MOD_QAM64:
+		stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x82);
+		stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x5a);
+		if (SymbolRate > 45000000) {
+			stv0367_writereg(state, R367CAB_FSM_STATE, 0xb0);
+			stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
+			stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa5);
+		} else if (SymbolRate > 25000000) {
+			stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0);
+			stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
+			stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa6);
+		} else {
+			stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0);
+			stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xd1);
+			stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7);
+		}
+		stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x95);
+		stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40);
+		stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0x99);
+		break;
+	case FE_CAB_MOD_QAM128:
+		stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
+		stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x76);
+		stv0367_writereg(state, R367CAB_FSM_STATE, 0x90);
+		stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xb1);
+		if (SymbolRate > 45000000)
+			stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7);
+		else if (SymbolRate > 25000000)
+			stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa6);
+		else
+			stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0x97);
+
+		stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x8e);
+		stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x7f);
+		stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7);
+		break;
+	case FE_CAB_MOD_QAM256:
+		stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x94);
+		stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x5a);
+		stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0);
+		if (SymbolRate > 45000000)
+			stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
+		else if (SymbolRate > 25000000)
+			stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
+		else
+			stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xd1);
+
+		stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7);
+		stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x85);
+		stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40);
+		stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7);
+		break;
+	case FE_CAB_MOD_QAM512:
+		stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
+		break;
+	case FE_CAB_MOD_QAM1024:
+		stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
+		break;
+	default:
+		break;
+	}
+
+	return QAMSize;
+}
+
+static u32 stv0367cab_set_derot_freq(struct stv0367_state *state,
+					u32 adc_hz, s32 derot_hz)
+{
+	u32 sampled_if = 0;
+	u32 adc_khz;
+
+	adc_khz = adc_hz / 1000;
+
+	dprintk("%s: adc_hz=%d derot_hz=%d\n", __func__, adc_hz, derot_hz);
+
+	if (adc_khz != 0) {
+		if (derot_hz < 1000000)
+			derot_hz = adc_hz / 4; /* ZIF operation */
+		if (derot_hz > adc_hz)
+			derot_hz = derot_hz - adc_hz;
+		sampled_if = (u32)derot_hz / 1000;
+		sampled_if *= 32768;
+		sampled_if /= adc_khz;
+		sampled_if *= 256;
+	}
+
+	if (sampled_if > 8388607)
+		sampled_if = 8388607;
+
+	dprintk("%s: sampled_if=0x%x\n", __func__, sampled_if);
+
+	stv0367_writereg(state, R367CAB_MIX_NCO_LL, sampled_if);
+	stv0367_writereg(state, R367CAB_MIX_NCO_HL, (sampled_if >> 8));
+	stv0367_writebits(state, F367CAB_MIX_NCO_INC_HH, (sampled_if >> 16));
+
+	return derot_hz;
+}
+
+static u32 stv0367cab_get_derot_freq(struct stv0367_state *state, u32 adc_hz)
+{
+	u32 sampled_if;
+
+	sampled_if = stv0367_readbits(state, F367CAB_MIX_NCO_INC_LL) +
+			(stv0367_readbits(state, F367CAB_MIX_NCO_INC_HL) << 8) +
+			(stv0367_readbits(state, F367CAB_MIX_NCO_INC_HH) << 16);
+
+	sampled_if /= 256;
+	sampled_if *= (adc_hz / 1000);
+	sampled_if += 1;
+	sampled_if /= 32768;
+
+	return sampled_if;
+}
+
+static u32 stv0367cab_set_srate(struct stv0367_state *state, u32 adc_hz,
+			u32 mclk_hz, u32 SymbolRate,
+			enum stv0367cab_mod QAMSize)
+{
+	u32 QamSizeCorr = 0;
+	u32 u32_tmp = 0, u32_tmp1 = 0;
+	u32 adp_khz;
+
+	dprintk("%s:\n", __func__);
+
+	/* Set Correction factor of SRC gain */
+	switch (QAMSize) {
+	case FE_CAB_MOD_QAM4:
+		QamSizeCorr = 1110;
+		break;
+	case FE_CAB_MOD_QAM16:
+		QamSizeCorr = 1032;
+		break;
+	case FE_CAB_MOD_QAM32:
+		QamSizeCorr =  954;
+		break;
+	case FE_CAB_MOD_QAM64:
+		QamSizeCorr =  983;
+		break;
+	case FE_CAB_MOD_QAM128:
+		QamSizeCorr =  957;
+		break;
+	case FE_CAB_MOD_QAM256:
+		QamSizeCorr =  948;
+		break;
+	case FE_CAB_MOD_QAM512:
+		QamSizeCorr =    0;
+		break;
+	case FE_CAB_MOD_QAM1024:
+		QamSizeCorr =  944;
+		break;
+	default:
+		break;
+	}
+
+	/* Transfer ratio calculation */
+	if (adc_hz != 0) {
+		u32_tmp = 256 * SymbolRate;
+		u32_tmp = u32_tmp / adc_hz;
+	}
+	stv0367_writereg(state, R367CAB_EQU_CRL_TFR, (u8)u32_tmp);
+
+	/* Symbol rate and SRC gain calculation */
+	adp_khz = (mclk_hz >> 1) / 1000;/* TRL works at half the system clock */
+	if (adp_khz != 0) {
+		u32_tmp = SymbolRate;
+		u32_tmp1 = SymbolRate;
+
+		if (u32_tmp < 2097152) { /* 2097152 = 2^21 */
+			/* Symbol rate calculation */
+			u32_tmp *= 2048; /* 2048 = 2^11 */
+			u32_tmp = u32_tmp / adp_khz;
+			u32_tmp = u32_tmp * 16384; /* 16384 = 2^14 */
+			u32_tmp /= 125 ; /* 125 = 1000/2^3 */
+			u32_tmp = u32_tmp * 8; /* 8 = 2^3 */
+
+			/* SRC Gain Calculation */
+			u32_tmp1 *= 2048; /* *2*2^10 */
+			u32_tmp1 /= 439; /* *2/878 */
+			u32_tmp1 *= 256; /* *2^8 */
+			u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */
+			u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */
+			u32_tmp1 = u32_tmp1 / 10000000;
+
+		} else if (u32_tmp < 4194304) { /* 4194304 = 2**22 */
+			/* Symbol rate calculation */
+			u32_tmp *= 1024 ; /* 1024 = 2**10 */
+			u32_tmp = u32_tmp / adp_khz;
+			u32_tmp = u32_tmp * 16384; /* 16384 = 2**14 */
+			u32_tmp /= 125 ; /* 125 = 1000/2**3 */
+			u32_tmp = u32_tmp * 16; /* 16 = 2**4 */
+
+			/* SRC Gain Calculation */
+			u32_tmp1 *= 1024; /* *2*2^9 */
+			u32_tmp1 /= 439; /* *2/878 */
+			u32_tmp1 *= 256; /* *2^8 */
+			u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz)*/
+			u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */
+			u32_tmp1 = u32_tmp1 / 5000000;
+		} else if (u32_tmp < 8388607) { /* 8388607 = 2**23 */
+			/* Symbol rate calculation */
+			u32_tmp *= 512 ; /* 512 = 2**9 */
+			u32_tmp = u32_tmp / adp_khz;
+			u32_tmp = u32_tmp * 16384; /* 16384 = 2**14 */
+			u32_tmp /= 125 ; /* 125 = 1000/2**3 */
+			u32_tmp = u32_tmp * 32; /* 32 = 2**5 */
+
+			/* SRC Gain Calculation */
+			u32_tmp1 *= 512; /* *2*2^8 */
+			u32_tmp1 /= 439; /* *2/878 */
+			u32_tmp1 *= 256; /* *2^8 */
+			u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */
+			u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */
+			u32_tmp1 = u32_tmp1 / 2500000;
+		} else {
+			/* Symbol rate calculation */
+			u32_tmp *= 256 ; /* 256 = 2**8 */
+			u32_tmp = u32_tmp / adp_khz;
+			u32_tmp = u32_tmp * 16384; /* 16384 = 2**13 */
+			u32_tmp /= 125 ; /* 125 = 1000/2**3 */
+			u32_tmp = u32_tmp * 64; /* 64 = 2**6 */
+
+			/* SRC Gain Calculation */
+			u32_tmp1 *= 256; /* 2*2^7 */
+			u32_tmp1 /= 439; /* *2/878 */
+			u32_tmp1 *= 256; /* *2^8 */
+			u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */
+			u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */
+			u32_tmp1 = u32_tmp1 / 1250000;
+		}
+	}
+#if 0
+	/* Filters' coefficients are calculated and written
+	into registers only if the filters are enabled */
+	if (stv0367_readbits(state, F367CAB_ADJ_EN)) {
+		stv0367cab_SetIirAdjacentcoefficient(state, mclk_hz,
+								SymbolRate);
+		/* AllPass filter must be enabled
+		when the adjacents filter is used */
+		stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 1);
+		stv0367cab_SetAllPasscoefficient(state, mclk_hz, SymbolRate);
+	} else
+		/* AllPass filter must be disabled
+		when the adjacents filter is not used */
+#endif
+	stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 0);
+
+	stv0367_writereg(state, R367CAB_SRC_NCO_LL, u32_tmp);
+	stv0367_writereg(state, R367CAB_SRC_NCO_LH, (u32_tmp >> 8));
+	stv0367_writereg(state, R367CAB_SRC_NCO_HL, (u32_tmp >> 16));
+	stv0367_writereg(state, R367CAB_SRC_NCO_HH, (u32_tmp >> 24));
+
+	stv0367_writereg(state, R367CAB_IQDEM_GAIN_SRC_L, u32_tmp1 & 0x00ff);
+	stv0367_writebits(state, F367CAB_GAIN_SRC_HI, (u32_tmp1 >> 8) & 0x00ff);
+
+	return SymbolRate ;
+}
+
+static u32 stv0367cab_GetSymbolRate(struct stv0367_state *state, u32 mclk_hz)
+{
+	u32 regsym;
+	u32 adp_khz;
+
+	regsym = stv0367_readreg(state, R367CAB_SRC_NCO_LL) +
+		(stv0367_readreg(state, R367CAB_SRC_NCO_LH) << 8) +
+		(stv0367_readreg(state, R367CAB_SRC_NCO_HL) << 16) +
+		(stv0367_readreg(state, R367CAB_SRC_NCO_HH) << 24);
+
+	adp_khz = (mclk_hz >> 1) / 1000;/* TRL works at half the system clock */
+
+	if (regsym < 134217728) {		/* 134217728L = 2**27*/
+		regsym = regsym * 32;		/* 32 = 2**5 */
+		regsym = regsym / 32768;	/* 32768L = 2**15 */
+		regsym = adp_khz * regsym;	/* AdpClk in kHz */
+		regsym = regsym / 128;		/* 128 = 2**7 */
+		regsym *= 125 ;			/* 125 = 1000/2**3 */
+		regsym /= 2048 ;		/* 2048 = 2**11	*/
+	} else if (regsym < 268435456) {	/* 268435456L = 2**28 */
+		regsym = regsym * 16;		/* 16 = 2**4 */
+		regsym = regsym / 32768;	/* 32768L = 2**15 */
+		regsym = adp_khz * regsym;	/* AdpClk in kHz */
+		regsym = regsym / 128;		/* 128 = 2**7 */
+		regsym *= 125 ;			/* 125 = 1000/2**3*/
+		regsym /= 1024 ;		/* 256 = 2**10*/
+	} else if (regsym < 536870912) {	/* 536870912L = 2**29*/
+		regsym = regsym * 8;		/* 8 = 2**3 */
+		regsym = regsym / 32768;	/* 32768L = 2**15 */
+		regsym = adp_khz * regsym;	/* AdpClk in kHz */
+		regsym = regsym / 128;		/* 128 = 2**7 */
+		regsym *= 125 ;			/* 125 = 1000/2**3 */
+		regsym /= 512 ;			/* 128 = 2**9 */
+	} else {
+		regsym = regsym * 4;		/* 4 = 2**2 */
+		regsym = regsym / 32768;	/* 32768L = 2**15 */
+		regsym = adp_khz * regsym;	/* AdpClk in kHz */
+		regsym = regsym / 128;		/* 128 = 2**7 */
+		regsym *= 125 ;			/* 125 = 1000/2**3 */
+		regsym /= 256 ;			/* 64 = 2**8 */
+	}
+
+	return regsym;
+}
+
+static int stv0367cab_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct stv0367_state *state = fe->demodulator_priv;
+
+	dprintk("%s:\n", __func__);
+
+	*status = 0;
+
+	if (stv0367_readbits(state, F367CAB_QAMFEC_LOCK)) {
+		*status |= FE_HAS_LOCK;
+		dprintk("%s: stv0367 has locked\n", __func__);
+	}
+
+	return 0;
+}
+
+static int stv0367cab_standby(struct dvb_frontend *fe, u8 standby_on)
+{
+	struct stv0367_state *state = fe->demodulator_priv;
+
+	dprintk("%s:\n", __func__);
+
+	if (standby_on) {
+		stv0367_writebits(state, F367CAB_BYPASS_PLLXN, 0x03);
+		stv0367_writebits(state, F367CAB_STDBY_PLLXN, 0x01);
+		stv0367_writebits(state, F367CAB_STDBY, 1);
+		stv0367_writebits(state, F367CAB_STDBY_CORE, 1);
+		stv0367_writebits(state, F367CAB_EN_BUFFER_I, 0);
+		stv0367_writebits(state, F367CAB_EN_BUFFER_Q, 0);
+		stv0367_writebits(state, F367CAB_POFFQ, 1);
+		stv0367_writebits(state, F367CAB_POFFI, 1);
+	} else {
+		stv0367_writebits(state, F367CAB_STDBY_PLLXN, 0x00);
+		stv0367_writebits(state, F367CAB_BYPASS_PLLXN, 0x00);
+		stv0367_writebits(state, F367CAB_STDBY, 0);
+		stv0367_writebits(state, F367CAB_STDBY_CORE, 0);
+		stv0367_writebits(state, F367CAB_EN_BUFFER_I, 1);
+		stv0367_writebits(state, F367CAB_EN_BUFFER_Q, 1);
+		stv0367_writebits(state, F367CAB_POFFQ, 0);
+		stv0367_writebits(state, F367CAB_POFFI, 0);
+	}
+
+	return 0;
+}
+
+static int stv0367cab_sleep(struct dvb_frontend *fe)
+{
+	return stv0367cab_standby(fe, 1);
+}
+
+int stv0367cab_init(struct dvb_frontend *fe)
+{
+	struct stv0367_state *state = fe->demodulator_priv;
+	struct stv0367cab_state *cab_state = state->cab_state;
+	int i;
+
+	dprintk("%s:\n", __func__);
+
+	for (i = 0; i < STV0367CAB_NBREGS; i++)
+		stv0367_writereg(state, def0367cab[i].addr,
+						def0367cab[i].value);
+
+	switch (state->config->ts_mode) {
+	case STV0367_DVBCI_CLOCK:
+		dprintk("Setting TSMode = STV0367_DVBCI_CLOCK\n");
+		stv0367_writebits(state, F367CAB_OUTFORMAT, 0x03);
+		break;
+	case STV0367_SERIAL_PUNCT_CLOCK:
+	case STV0367_SERIAL_CONT_CLOCK:
+		stv0367_writebits(state, F367CAB_OUTFORMAT, 0x01);
+		break;
+	case STV0367_PARALLEL_PUNCT_CLOCK:
+	case STV0367_OUTPUTMODE_DEFAULT:
+		stv0367_writebits(state, F367CAB_OUTFORMAT, 0x00);
+		break;
+	}
+
+	switch (state->config->clk_pol) {
+	case STV0367_RISINGEDGE_CLOCK:
+		stv0367_writebits(state, F367CAB_CLK_POLARITY, 0x00);
+		break;
+	case STV0367_FALLINGEDGE_CLOCK:
+	case STV0367_CLOCKPOLARITY_DEFAULT:
+		stv0367_writebits(state, F367CAB_CLK_POLARITY, 0x01);
+		break;
+	}
+
+	stv0367_writebits(state, F367CAB_SYNC_STRIP, 0x00);
+
+	stv0367_writebits(state, F367CAB_CT_NBST, 0x01);
+
+	stv0367_writebits(state, F367CAB_TS_SWAP, 0x01);
+
+	stv0367_writebits(state, F367CAB_FIFO_BYPASS, 0x00);
+
+	stv0367_writereg(state, R367CAB_ANACTRL, 0x00);/*PLL enabled and used */
+
+	cab_state->mclk = stv0367cab_get_mclk(fe, state->config->xtal);
+	cab_state->adc_clk = stv0367cab_get_adc_freq(fe, state->config->xtal);
+
+	return 0;
+}
+static
+enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
+					     struct dtv_frontend_properties *p)
+{
+	struct stv0367cab_state *cab_state = state->cab_state;
+	enum stv0367_cab_signal_type signalType = FE_CAB_NOAGC;
+	u32	QAMFEC_Lock, QAM_Lock, u32_tmp,
+		LockTime, TRLTimeOut, AGCTimeOut, CRLSymbols,
+		CRLTimeOut, EQLTimeOut, DemodTimeOut, FECTimeOut;
+	u8	TrackAGCAccum;
+	s32	tmp;
+
+	dprintk("%s:\n", __func__);
+
+	/* Timeouts calculation */
+	/* A max lock time of 25 ms is allowed for delayed AGC */
+	AGCTimeOut = 25;
+	/* 100000 symbols needed by the TRL as a maximum value */
+	TRLTimeOut = 100000000 / p->symbol_rate;
+	/* CRLSymbols is the needed number of symbols to achieve a lock
+	   within [-4%, +4%] of the symbol rate.
+	   CRL timeout is calculated
+	   for a lock within [-search_range, +search_range].
+	   EQL timeout can be changed depending on
+	   the micro-reflections we want to handle.
+	   A characterization must be performed
+	   with these echoes to get new timeout values.
+	*/
+	switch (p->modulation) {
+	case QAM_16:
+		CRLSymbols = 150000;
+		EQLTimeOut = 100;
+		break;
+	case QAM_32:
+		CRLSymbols = 250000;
+		EQLTimeOut = 100;
+		break;
+	case QAM_64:
+		CRLSymbols = 200000;
+		EQLTimeOut = 100;
+		break;
+	case QAM_128:
+		CRLSymbols = 250000;
+		EQLTimeOut = 100;
+		break;
+	case QAM_256:
+		CRLSymbols = 250000;
+		EQLTimeOut = 100;
+		break;
+	default:
+		CRLSymbols = 200000;
+		EQLTimeOut = 100;
+		break;
+	}
+#if 0
+	if (pIntParams->search_range < 0) {
+		CRLTimeOut = (25 * CRLSymbols *
+				(-pIntParams->search_range / 1000)) /
+					(pIntParams->symbol_rate / 1000);
+	} else
+#endif
+	CRLTimeOut = (25 * CRLSymbols * (cab_state->search_range / 1000)) /
+					(p->symbol_rate / 1000);
+
+	CRLTimeOut = (1000 * CRLTimeOut) / p->symbol_rate;
+	/* Timeouts below 50ms are coerced */
+	if (CRLTimeOut < 50)
+		CRLTimeOut = 50;
+	/* A maximum of 100 TS packets is needed to get FEC lock even in case
+	the spectrum inversion needs to be changed.
+	   This is equal to 20 ms in case of the lowest symbol rate of 0.87Msps
+	*/
+	FECTimeOut = 20;
+	DemodTimeOut = AGCTimeOut + TRLTimeOut + CRLTimeOut + EQLTimeOut;
+
+	dprintk("%s: DemodTimeOut=%d\n", __func__, DemodTimeOut);
+
+	/* Reset the TRL to ensure nothing starts until the
+	   AGC is stable which ensures a better lock time
+	*/
+	stv0367_writereg(state, R367CAB_CTRL_1, 0x04);
+	/* Set AGC accumulation time to minimum and lock threshold to maximum
+	in order to speed up the AGC lock */
+	TrackAGCAccum = stv0367_readbits(state, F367CAB_AGC_ACCUMRSTSEL);
+	stv0367_writebits(state, F367CAB_AGC_ACCUMRSTSEL, 0x0);
+	/* Modulus Mapper is disabled */
+	stv0367_writebits(state, F367CAB_MODULUSMAP_EN, 0);
+	/* Disable the sweep function */
+	stv0367_writebits(state, F367CAB_SWEEP_EN, 0);
+	/* The sweep function is never used, Sweep rate must be set to 0 */
+	/* Set the derotator frequency in Hz */
+	stv0367cab_set_derot_freq(state, cab_state->adc_clk,
+		(1000 * (s32)state->config->if_khz + cab_state->derot_offset));
+	/* Disable the Allpass Filter when the symbol rate is out of range */
+	if ((p->symbol_rate > 10800000) | (p->symbol_rate < 1800000)) {
+		stv0367_writebits(state, F367CAB_ADJ_EN, 0);
+		stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 0);
+	}
+#if 0
+	/* Check if the tuner is locked */
+	tuner_lock = stv0367cab_tuner_get_status(fe);
+	if (tuner_lock == 0)
+		return FE_367CAB_NOTUNER;
+#endif
+	/* Relase the TRL to start demodulator acquisition */
+	/* Wait for QAM lock */
+	LockTime = 0;
+	stv0367_writereg(state, R367CAB_CTRL_1, 0x00);
+	do {
+		QAM_Lock = stv0367_readbits(state, F367CAB_FSM_STATUS);
+		if ((LockTime >= (DemodTimeOut - EQLTimeOut)) &&
+							(QAM_Lock == 0x04))
+			/*
+			 * We don't wait longer, the frequency/phase offset
+			 * must be too big
+			 */
+			LockTime = DemodTimeOut;
+		else if ((LockTime >= (AGCTimeOut + TRLTimeOut)) &&
+							(QAM_Lock == 0x02))
+			/*
+			 * We don't wait longer, either there is no signal or
+			 * it is not the right symbol rate or it is an analog
+			 * carrier
+			 */
+		{
+			LockTime = DemodTimeOut;
+			u32_tmp = stv0367_readbits(state,
+						F367CAB_AGC_PWR_WORD_LO) +
+					(stv0367_readbits(state,
+						F367CAB_AGC_PWR_WORD_ME) << 8) +
+					(stv0367_readbits(state,
+						F367CAB_AGC_PWR_WORD_HI) << 16);
+			if (u32_tmp >= 131072)
+				u32_tmp = 262144 - u32_tmp;
+			u32_tmp = u32_tmp / (1 << (11 - stv0367_readbits(state,
+							F367CAB_AGC_IF_BWSEL)));
+
+			if (u32_tmp < stv0367_readbits(state,
+						F367CAB_AGC_PWRREF_LO) +
+					256 * stv0367_readbits(state,
+						F367CAB_AGC_PWRREF_HI) - 10)
+				QAM_Lock = 0x0f;
+		} else {
+			usleep_range(10000, 20000);
+			LockTime += 10;
+		}
+		dprintk("QAM_Lock=0x%x LockTime=%d\n", QAM_Lock, LockTime);
+		tmp = stv0367_readreg(state, R367CAB_IT_STATUS1);
+
+		dprintk("R367CAB_IT_STATUS1=0x%x\n", tmp);
+
+	} while (((QAM_Lock != 0x0c) && (QAM_Lock != 0x0b)) &&
+						(LockTime < DemodTimeOut));
+
+	dprintk("QAM_Lock=0x%x\n", QAM_Lock);
+
+	tmp = stv0367_readreg(state, R367CAB_IT_STATUS1);
+	dprintk("R367CAB_IT_STATUS1=0x%x\n", tmp);
+	tmp = stv0367_readreg(state, R367CAB_IT_STATUS2);
+	dprintk("R367CAB_IT_STATUS2=0x%x\n", tmp);
+
+	tmp  = stv0367cab_get_derot_freq(state, cab_state->adc_clk);
+	dprintk("stv0367cab_get_derot_freq=0x%x\n", tmp);
+
+	if ((QAM_Lock == 0x0c) || (QAM_Lock == 0x0b)) {
+		/* Wait for FEC lock */
+		LockTime = 0;
+		do {
+			usleep_range(5000, 7000);
+			LockTime += 5;
+			QAMFEC_Lock = stv0367_readbits(state,
+							F367CAB_QAMFEC_LOCK);
+		} while (!QAMFEC_Lock && (LockTime < FECTimeOut));
+	} else
+		QAMFEC_Lock = 0;
+
+	if (QAMFEC_Lock) {
+		signalType = FE_CAB_DATAOK;
+		cab_state->modulation = p->modulation;
+		cab_state->spect_inv = stv0367_readbits(state,
+							F367CAB_QUAD_INV);
+#if 0
+/* not clear for me */
+		if (state->config->if_khz != 0) {
+			if (state->config->if_khz > cab_state->adc_clk / 1000) {
+				cab_state->freq_khz =
+					FE_Cab_TunerGetFrequency(pIntParams->hTuner)
+				- stv0367cab_get_derot_freq(state, cab_state->adc_clk)
+				- cab_state->adc_clk / 1000 + state->config->if_khz;
+			} else {
+				cab_state->freq_khz =
+						FE_Cab_TunerGetFrequency(pIntParams->hTuner)
+						- stv0367cab_get_derot_freq(state, cab_state->adc_clk)
+										+ state->config->if_khz;
+			}
+		} else {
+			cab_state->freq_khz =
+				FE_Cab_TunerGetFrequency(pIntParams->hTuner) +
+				stv0367cab_get_derot_freq(state,
+							cab_state->adc_clk) -
+				cab_state->adc_clk / 4000;
+		}
+#endif
+		cab_state->symbol_rate = stv0367cab_GetSymbolRate(state,
+							cab_state->mclk);
+		cab_state->locked = 1;
+
+		/* stv0367_setbits(state, F367CAB_AGC_ACCUMRSTSEL,7);*/
+	} else {
+		switch (QAM_Lock) {
+		case 1:
+			signalType = FE_CAB_NOAGC;
+			break;
+		case 2:
+			signalType = FE_CAB_NOTIMING;
+			break;
+		case 3:
+			signalType = FE_CAB_TIMINGOK;
+			break;
+		case 4:
+			signalType = FE_CAB_NOCARRIER;
+			break;
+		case 5:
+			signalType = FE_CAB_CARRIEROK;
+			break;
+		case 7:
+			signalType = FE_CAB_NOBLIND;
+			break;
+		case 8:
+			signalType = FE_CAB_BLINDOK;
+			break;
+		case 10:
+			signalType = FE_CAB_NODEMOD;
+			break;
+		case 11:
+			signalType = FE_CAB_DEMODOK;
+			break;
+		case 12:
+			signalType = FE_CAB_DEMODOK;
+			break;
+		case 13:
+			signalType = FE_CAB_NODEMOD;
+			break;
+		case 14:
+			signalType = FE_CAB_NOBLIND;
+			break;
+		case 15:
+			signalType = FE_CAB_NOSIGNAL;
+			break;
+		default:
+			break;
+		}
+
+	}
+
+	/* Set the AGC control values to tracking values */
+	stv0367_writebits(state, F367CAB_AGC_ACCUMRSTSEL, TrackAGCAccum);
+	return signalType;
+}
+
+static int stv0367cab_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct stv0367_state *state = fe->demodulator_priv;
+	struct stv0367cab_state *cab_state = state->cab_state;
+	enum stv0367cab_mod QAMSize = 0;
+
+	dprintk("%s: freq = %d, srate = %d\n", __func__,
+					p->frequency, p->symbol_rate);
+
+	cab_state->derot_offset = 0;
+
+	switch (p->modulation) {
+	case QAM_16:
+		QAMSize = FE_CAB_MOD_QAM16;
+		break;
+	case QAM_32:
+		QAMSize = FE_CAB_MOD_QAM32;
+		break;
+	case QAM_64:
+		QAMSize = FE_CAB_MOD_QAM64;
+		break;
+	case QAM_128:
+		QAMSize = FE_CAB_MOD_QAM128;
+		break;
+	case QAM_256:
+		QAMSize = FE_CAB_MOD_QAM256;
+		break;
+	default:
+		break;
+	}
+
+	stv0367cab_init(fe);
+
+	/* Tuner Frequency Setting */
+	if (fe->ops.tuner_ops.set_params) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	stv0367cab_SetQamSize(
+			state,
+			p->symbol_rate,
+			QAMSize);
+
+	stv0367cab_set_srate(state,
+			cab_state->adc_clk,
+			cab_state->mclk,
+			p->symbol_rate,
+			QAMSize);
+	/* Search algorithm launch, [-1.1*RangeOffset, +1.1*RangeOffset] scan */
+	cab_state->state = stv0367cab_algo(state, p);
+	return 0;
+}
+
+static int stv0367cab_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct stv0367_state *state = fe->demodulator_priv;
+	struct stv0367cab_state *cab_state = state->cab_state;
+
+	enum stv0367cab_mod QAMSize;
+
+	dprintk("%s:\n", __func__);
+
+	p->symbol_rate = stv0367cab_GetSymbolRate(state, cab_state->mclk);
+
+	QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE);
+	switch (QAMSize) {
+	case FE_CAB_MOD_QAM16:
+		p->modulation = QAM_16;
+		break;
+	case FE_CAB_MOD_QAM32:
+		p->modulation = QAM_32;
+		break;
+	case FE_CAB_MOD_QAM64:
+		p->modulation = QAM_64;
+		break;
+	case FE_CAB_MOD_QAM128:
+		p->modulation = QAM_128;
+		break;
+	case QAM_256:
+		p->modulation = QAM_256;
+		break;
+	default:
+		break;
+	}
+
+	p->frequency = stv0367_get_tuner_freq(fe);
+
+	dprintk("%s: tuner frequency = %d\n", __func__, p->frequency);
+
+	if (state->config->if_khz == 0) {
+		p->frequency +=
+			(stv0367cab_get_derot_freq(state, cab_state->adc_clk) -
+			cab_state->adc_clk / 4000);
+		return 0;
+	}
+
+	if (state->config->if_khz > cab_state->adc_clk / 1000)
+		p->frequency += (state->config->if_khz
+			- stv0367cab_get_derot_freq(state, cab_state->adc_clk)
+			- cab_state->adc_clk / 1000);
+	else
+		p->frequency += (state->config->if_khz
+			- stv0367cab_get_derot_freq(state, cab_state->adc_clk));
+
+	return 0;
+}
+
+#if 0
+void stv0367cab_GetErrorCount(state, enum stv0367cab_mod QAMSize,
+			u32 symbol_rate, FE_367qam_Monitor *Monitor_results)
+{
+	stv0367cab_OptimiseNByteAndGetBER(state, QAMSize, symbol_rate, Monitor_results);
+	stv0367cab_GetPacketsCount(state, Monitor_results);
+
+	return;
+}
+
+static int stv0367cab_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct stv0367_state *state = fe->demodulator_priv;
+
+	return 0;
+}
+#endif
+static s32 stv0367cab_get_rf_lvl(struct stv0367_state *state)
+{
+	s32 rfLevel = 0;
+	s32 RfAgcPwm = 0, IfAgcPwm = 0;
+	u8 i;
+
+	stv0367_writebits(state, F367CAB_STDBY_ADCGP, 0x0);
+
+	RfAgcPwm =
+		(stv0367_readbits(state, F367CAB_RF_AGC1_LEVEL_LO) & 0x03) +
+		(stv0367_readbits(state, F367CAB_RF_AGC1_LEVEL_HI) << 2);
+	RfAgcPwm = 100 * RfAgcPwm / 1023;
+
+	IfAgcPwm =
+		stv0367_readbits(state, F367CAB_AGC_IF_PWMCMD_LO) +
+		(stv0367_readbits(state, F367CAB_AGC_IF_PWMCMD_HI) << 8);
+	if (IfAgcPwm >= 2048)
+		IfAgcPwm -= 2048;
+	else
+		IfAgcPwm += 2048;
+
+	IfAgcPwm = 100 * IfAgcPwm / 4095;
+
+	/* For DTT75467 on NIM */
+	if (RfAgcPwm < 90  && IfAgcPwm < 28) {
+		for (i = 0; i < RF_LOOKUP_TABLE_SIZE; i++) {
+			if (RfAgcPwm <= stv0367cab_RF_LookUp1[0][i]) {
+				rfLevel = (-1) * stv0367cab_RF_LookUp1[1][i];
+				break;
+			}
+		}
+		if (i == RF_LOOKUP_TABLE_SIZE)
+			rfLevel = -56;
+	} else { /*if IF AGC>10*/
+		for (i = 0; i < RF_LOOKUP_TABLE2_SIZE; i++) {
+			if (IfAgcPwm <= stv0367cab_RF_LookUp2[0][i]) {
+				rfLevel = (-1) * stv0367cab_RF_LookUp2[1][i];
+				break;
+			}
+		}
+		if (i == RF_LOOKUP_TABLE2_SIZE)
+			rfLevel = -72;
+	}
+	return rfLevel;
+}
+
+static int stv0367cab_read_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct stv0367_state *state = fe->demodulator_priv;
+
+	s32 signal =  stv0367cab_get_rf_lvl(state);
+
+	dprintk("%s: signal=%d dBm\n", __func__, signal);
+
+	if (signal <= -72)
+		*strength = 65535;
+	else
+		*strength = (22 + signal) * (-1311);
+
+	dprintk("%s: strength=%d\n", __func__, (*strength));
+
+	return 0;
+}
+
+static int stv0367cab_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct stv0367_state *state = fe->demodulator_priv;
+	u32 noisepercentage;
+	enum stv0367cab_mod QAMSize;
+	u32 regval = 0, temp = 0;
+	int power, i;
+
+	QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE);
+	switch (QAMSize) {
+	case FE_CAB_MOD_QAM4:
+		power = 21904;
+		break;
+	case FE_CAB_MOD_QAM16:
+		power = 20480;
+		break;
+	case FE_CAB_MOD_QAM32:
+		power = 23040;
+		break;
+	case FE_CAB_MOD_QAM64:
+		power = 21504;
+		break;
+	case FE_CAB_MOD_QAM128:
+		power = 23616;
+		break;
+	case FE_CAB_MOD_QAM256:
+		power = 21760;
+		break;
+	case FE_CAB_MOD_QAM512:
+		power = 1;
+		break;
+	case FE_CAB_MOD_QAM1024:
+		power = 21280;
+		break;
+	default:
+		power = 1;
+		break;
+	}
+
+	for (i = 0; i < 10; i++) {
+		regval += (stv0367_readbits(state, F367CAB_SNR_LO)
+			+ 256 * stv0367_readbits(state, F367CAB_SNR_HI));
+	}
+
+	regval /= 10; /*for average over 10 times in for loop above*/
+	if (regval != 0) {
+		temp = power
+			* (1 << (3 + stv0367_readbits(state, F367CAB_SNR_PER)));
+		temp /= regval;
+	}
+
+	/* table values, not needed to calculate logarithms */
+	if (temp >= 5012)
+		noisepercentage = 100;
+	else if (temp >= 3981)
+		noisepercentage = 93;
+	else if (temp >= 3162)
+		noisepercentage = 86;
+	else if (temp >= 2512)
+		noisepercentage = 79;
+	else if (temp >= 1995)
+		noisepercentage = 72;
+	else if (temp >= 1585)
+		noisepercentage = 65;
+	else if (temp >= 1259)
+		noisepercentage = 58;
+	else if (temp >= 1000)
+		noisepercentage = 50;
+	else if (temp >= 794)
+		noisepercentage = 43;
+	else if (temp >= 501)
+		noisepercentage = 36;
+	else if (temp >= 316)
+		noisepercentage = 29;
+	else if (temp >= 200)
+		noisepercentage = 22;
+	else if (temp >= 158)
+		noisepercentage = 14;
+	else if (temp >= 126)
+		noisepercentage = 7;
+	else
+		noisepercentage = 0;
+
+	dprintk("%s: noisepercentage=%d\n", __func__, noisepercentage);
+
+	*snr = (noisepercentage * 65535) / 100;
+
+	return 0;
+}
+
+static int stv0367cab_read_ucblcks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct stv0367_state *state = fe->demodulator_priv;
+	int corrected, tscount;
+
+	*ucblocks = (stv0367_readreg(state, R367CAB_RS_COUNTER_5) << 8)
+			| stv0367_readreg(state, R367CAB_RS_COUNTER_4);
+	corrected = (stv0367_readreg(state, R367CAB_RS_COUNTER_3) << 8)
+			| stv0367_readreg(state, R367CAB_RS_COUNTER_2);
+	tscount = (stv0367_readreg(state, R367CAB_RS_COUNTER_2) << 8)
+			| stv0367_readreg(state, R367CAB_RS_COUNTER_1);
+
+	dprintk("%s: uncorrected blocks=%d corrected blocks=%d tscount=%d\n",
+				__func__, *ucblocks, corrected, tscount);
+
+	return 0;
+};
+
+static struct dvb_frontend_ops stv0367cab_ops = {
+	.delsys = { SYS_DVBC_ANNEX_A },
+	.info = {
+		.name = "ST STV0367 DVB-C",
+		.frequency_min = 47000000,
+		.frequency_max = 862000000,
+		.frequency_stepsize = 62500,
+		.symbol_rate_min = 870000,
+		.symbol_rate_max = 11700000,
+		.caps = 0x400 |/* FE_CAN_QAM_4 */
+			FE_CAN_QAM_16 | FE_CAN_QAM_32  |
+			FE_CAN_QAM_64 | FE_CAN_QAM_128 |
+			FE_CAN_QAM_256 | FE_CAN_FEC_AUTO
+	},
+	.release				= stv0367_release,
+	.init					= stv0367cab_init,
+	.sleep					= stv0367cab_sleep,
+	.i2c_gate_ctrl				= stv0367cab_gate_ctrl,
+	.set_frontend				= stv0367cab_set_frontend,
+	.get_frontend				= stv0367cab_get_frontend,
+	.read_status				= stv0367cab_read_status,
+/*	.read_ber				= stv0367cab_read_ber, */
+	.read_signal_strength			= stv0367cab_read_strength,
+	.read_snr				= stv0367cab_read_snr,
+	.read_ucblocks				= stv0367cab_read_ucblcks,
+	.get_tune_settings			= stv0367_get_tune_settings,
+};
+
+struct dvb_frontend *stv0367cab_attach(const struct stv0367_config *config,
+				   struct i2c_adapter *i2c)
+{
+	struct stv0367_state *state = NULL;
+	struct stv0367cab_state *cab_state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct stv0367_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+	cab_state = kzalloc(sizeof(struct stv0367cab_state), GFP_KERNEL);
+	if (cab_state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->i2c = i2c;
+	state->config = config;
+	cab_state->search_range = 280000;
+	state->cab_state = cab_state;
+	state->fe.ops = stv0367cab_ops;
+	state->fe.demodulator_priv = state;
+	state->chip_id = stv0367_readreg(state, 0xf000);
+
+	dprintk("%s: chip_id = 0x%x\n", __func__, state->chip_id);
+
+	/* check if the demod is there */
+	if ((state->chip_id != 0x50) && (state->chip_id != 0x60))
+		goto error;
+
+	return &state->fe;
+
+error:
+	kfree(cab_state);
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(stv0367cab_attach);
+
+MODULE_PARM_DESC(debug, "Set debug");
+MODULE_PARM_DESC(i2c_debug, "Set i2c debug");
+
+MODULE_AUTHOR("Igor M. Liplianin");
+MODULE_DESCRIPTION("ST STV0367 DVB-C/T demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/stv0367.h b/drivers/media/dvb-frontends/stv0367.h
new file mode 100644
index 0000000..93cc4a5
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv0367.h
@@ -0,0 +1,66 @@
+/*
+ * stv0367.h
+ *
+ * Driver for ST STV0367 DVB-T & DVB-C demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2010,2011 NetUP Inc.
+ * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef STV0367_H
+#define STV0367_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct stv0367_config {
+	u8 demod_address;
+	u32 xtal;
+	u32 if_khz;/*4500*/
+	int if_iq_mode;
+	int ts_mode;
+	int clk_pol;
+};
+
+#if defined(CONFIG_DVB_STV0367) || (defined(CONFIG_DVB_STV0367_MODULE) \
+							&& defined(MODULE))
+extern struct
+dvb_frontend *stv0367ter_attach(const struct stv0367_config *config,
+					struct i2c_adapter *i2c);
+extern struct
+dvb_frontend *stv0367cab_attach(const struct stv0367_config *config,
+					struct i2c_adapter *i2c);
+#else
+static inline struct
+dvb_frontend *stv0367ter_attach(const struct stv0367_config *config,
+					struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+static inline struct
+dvb_frontend *stv0367cab_attach(const struct stv0367_config *config,
+					struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb-frontends/stv0367_priv.h b/drivers/media/dvb-frontends/stv0367_priv.h
new file mode 100644
index 0000000..995db06
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv0367_priv.h
@@ -0,0 +1,212 @@
+/*
+ * stv0367_priv.h
+ *
+ * Driver for ST STV0367 DVB-T & DVB-C demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2010,2011 NetUP Inc.
+ * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* Common driver error constants */
+
+#ifndef STV0367_PRIV_H
+#define STV0367_PRIV_H
+
+#ifndef TRUE
+    #define TRUE (1 == 1)
+#endif
+#ifndef FALSE
+    #define FALSE (!TRUE)
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* MACRO definitions */
+#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X))
+#define MAX(X, Y) ((X) >= (Y) ? (X) : (Y))
+#define MIN(X, Y) ((X) <= (Y) ? (X) : (Y))
+#define INRANGE(X, Y, Z) \
+	((((X) <= (Y)) && ((Y) <= (Z))) || \
+	(((Z) <= (Y)) && ((Y) <= (X))) ? 1 : 0)
+
+#ifndef MAKEWORD
+#define MAKEWORD(X, Y) (((X) << 8) + (Y))
+#endif
+
+#define LSB(X) (((X) & 0xff))
+#define MSB(Y) (((Y) >> 8) & 0xff)
+#define MMSB(Y)(((Y) >> 16) & 0xff)
+
+enum stv0367_ter_signal_type {
+	FE_TER_NOAGC = 0,
+	FE_TER_AGCOK = 5,
+	FE_TER_NOTPS = 6,
+	FE_TER_TPSOK = 7,
+	FE_TER_NOSYMBOL = 8,
+	FE_TER_BAD_CPQ = 9,
+	FE_TER_PRFOUNDOK = 10,
+	FE_TER_NOPRFOUND = 11,
+	FE_TER_LOCKOK = 12,
+	FE_TER_NOLOCK = 13,
+	FE_TER_SYMBOLOK = 15,
+	FE_TER_CPAMPOK = 16,
+	FE_TER_NOCPAMP = 17,
+	FE_TER_SWNOK = 18
+};
+
+enum stv0367_ts_mode {
+	STV0367_OUTPUTMODE_DEFAULT,
+	STV0367_SERIAL_PUNCT_CLOCK,
+	STV0367_SERIAL_CONT_CLOCK,
+	STV0367_PARALLEL_PUNCT_CLOCK,
+	STV0367_DVBCI_CLOCK
+};
+
+enum stv0367_clk_pol {
+	STV0367_CLOCKPOLARITY_DEFAULT,
+	STV0367_RISINGEDGE_CLOCK,
+	STV0367_FALLINGEDGE_CLOCK
+};
+
+enum stv0367_ter_bw {
+	FE_TER_CHAN_BW_6M = 6,
+	FE_TER_CHAN_BW_7M = 7,
+	FE_TER_CHAN_BW_8M = 8
+};
+
+#if 0
+enum FE_TER_Rate_TPS {
+	FE_TER_TPS_1_2 = 0,
+	FE_TER_TPS_2_3 = 1,
+	FE_TER_TPS_3_4 = 2,
+	FE_TER_TPS_5_6 = 3,
+	FE_TER_TPS_7_8 = 4
+};
+#endif
+
+enum stv0367_ter_mode {
+	FE_TER_MODE_2K,
+	FE_TER_MODE_8K,
+	FE_TER_MODE_4K
+};
+#if 0
+enum FE_TER_Hierarchy_Alpha {
+	FE_TER_HIER_ALPHA_NONE,	/* Regular modulation */
+	FE_TER_HIER_ALPHA_1,	/* Hierarchical modulation a = 1*/
+	FE_TER_HIER_ALPHA_2,	/* Hierarchical modulation a = 2*/
+	FE_TER_HIER_ALPHA_4	/* Hierarchical modulation a = 4*/
+};
+#endif
+enum stv0367_ter_hierarchy {
+	FE_TER_HIER_NONE,	/*Hierarchy None*/
+	FE_TER_HIER_LOW_PRIO,	/*Hierarchy : Low Priority*/
+	FE_TER_HIER_HIGH_PRIO,	/*Hierarchy : High Priority*/
+	FE_TER_HIER_PRIO_ANY	/*Hierarchy  :Any*/
+};
+
+#if 0
+enum fe_stv0367_ter_spec {
+	FE_TER_INVERSION_NONE = 0,
+	FE_TER_INVERSION = 1,
+	FE_TER_INVERSION_AUTO = 2,
+	FE_TER_INVERSION_UNK  = 4
+};
+#endif
+
+enum stv0367_ter_if_iq_mode {
+	FE_TER_NORMAL_IF_TUNER = 0,
+	FE_TER_LONGPATH_IF_TUNER = 1,
+	FE_TER_IQ_TUNER = 2
+
+};
+
+#if 0
+enum FE_TER_FECRate {
+	FE_TER_FEC_NONE = 0x00,	/* no FEC rate specified */
+	FE_TER_FEC_ALL = 0xFF,	 /* Logical OR of all FECs */
+	FE_TER_FEC_1_2 = 1,
+	FE_TER_FEC_2_3 = (1 << 1),
+	FE_TER_FEC_3_4 = (1 << 2),
+	FE_TER_FEC_4_5 = (1 << 3),
+	FE_TER_FEC_5_6 = (1 << 4),
+	FE_TER_FEC_6_7 = (1 << 5),
+	FE_TER_FEC_7_8 = (1 << 6),
+	FE_TER_FEC_8_9 = (1 << 7)
+};
+
+enum FE_TER_Rate {
+	FE_TER_FE_1_2 = 0,
+	FE_TER_FE_2_3 = 1,
+	FE_TER_FE_3_4 = 2,
+	FE_TER_FE_5_6 = 3,
+	FE_TER_FE_6_7 = 4,
+	FE_TER_FE_7_8 = 5
+};
+#endif
+
+enum stv0367_ter_force {
+	FE_TER_FORCENONE = 0,
+	FE_TER_FORCE_M_G = 1
+};
+
+enum  stv0367cab_mod {
+	FE_CAB_MOD_QAM4,
+	FE_CAB_MOD_QAM16,
+	FE_CAB_MOD_QAM32,
+	FE_CAB_MOD_QAM64,
+	FE_CAB_MOD_QAM128,
+	FE_CAB_MOD_QAM256,
+	FE_CAB_MOD_QAM512,
+	FE_CAB_MOD_QAM1024
+};
+#if 0
+enum {
+	FE_CAB_FEC_A = 1,	/* J83 Annex A */
+	FE_CAB_FEC_B = (1 << 1),/* J83 Annex B */
+	FE_CAB_FEC_C = (1 << 2)	/* J83 Annex C */
+} FE_CAB_FECType_t;
+#endif
+struct stv0367_cab_signal_info {
+	int locked;
+	u32 frequency; /* kHz */
+	u32 symbol_rate; /* Mbds */
+	enum stv0367cab_mod modulation;
+	fe_spectral_inversion_t spect_inv;
+	s32 Power_dBmx10;	/* Power of the RF signal (dBm x 10) */
+	u32	CN_dBx10;	/* Carrier to noise ratio (dB x 10) */
+	u32	BER;		/* Bit error rate (x 10000000)	*/
+};
+
+enum stv0367_cab_signal_type {
+	FE_CAB_NOTUNER,
+	FE_CAB_NOAGC,
+	FE_CAB_NOSIGNAL,
+	FE_CAB_NOTIMING,
+	FE_CAB_TIMINGOK,
+	FE_CAB_NOCARRIER,
+	FE_CAB_CARRIEROK,
+	FE_CAB_NOBLIND,
+	FE_CAB_BLINDOK,
+	FE_CAB_NODEMOD,
+	FE_CAB_DEMODOK,
+	FE_CAB_DATAOK
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/stv0367_regs.h b/drivers/media/dvb-frontends/stv0367_regs.h
new file mode 100644
index 0000000..a96fbdc
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv0367_regs.h
@@ -0,0 +1,3614 @@
+/*
+ * stv0367_regs.h
+ *
+ * Driver for ST STV0367 DVB-T & DVB-C demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2010,2011 NetUP Inc.
+ * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef STV0367_REGS_H
+#define STV0367_REGS_H
+
+/* ID */
+#define	R367TER_ID	0xf000
+#define	F367TER_IDENTIFICATIONREG	0xf00000ff
+
+/* I2CRPT */
+#define	R367TER_I2CRPT	0xf001
+#define	F367TER_I2CT_ON	0xf0010080
+#define	F367TER_ENARPT_LEVEL	0xf0010070
+#define	F367TER_SCLT_DELAY	0xf0010008
+#define	F367TER_SCLT_NOD	0xf0010004
+#define	F367TER_STOP_ENABLE	0xf0010002
+#define	F367TER_SDAT_NOD	0xf0010001
+
+/* TOPCTRL */
+#define	R367TER_TOPCTRL	0xf002
+#define	F367TER_STDBY	0xf0020080
+#define	F367TER_STDBY_FEC	0xf0020040
+#define	F367TER_STDBY_CORE	0xf0020020
+#define	F367TER_QAM_COFDM	0xf0020010
+#define	F367TER_TS_DIS	0xf0020008
+#define	F367TER_DIR_CLK_216	0xf0020004
+#define	F367TER_TUNER_BB	0xf0020002
+#define	F367TER_DVBT_H	0xf0020001
+
+/* IOCFG0 */
+#define	R367TER_IOCFG0	0xf003
+#define	F367TER_OP0_SD	0xf0030080
+#define	F367TER_OP0_VAL	0xf0030040
+#define	F367TER_OP0_OD	0xf0030020
+#define	F367TER_OP0_INV	0xf0030010
+#define	F367TER_OP0_DACVALUE_HI	0xf003000f
+
+/* DAc0R */
+#define	R367TER_DAC0R	0xf004
+#define	F367TER_OP0_DACVALUE_LO	0xf00400ff
+
+/* IOCFG1 */
+#define	R367TER_IOCFG1	0xf005
+#define	F367TER_IP0	0xf0050040
+#define	F367TER_OP1_OD	0xf0050020
+#define	F367TER_OP1_INV	0xf0050010
+#define	F367TER_OP1_DACVALUE_HI	0xf005000f
+
+/* DAC1R */
+#define	R367TER_DAC1R	0xf006
+#define	F367TER_OP1_DACVALUE_LO	0xf00600ff
+
+/* IOCFG2 */
+#define	R367TER_IOCFG2	0xf007
+#define	F367TER_OP2_LOCK_CONF	0xf00700e0
+#define	F367TER_OP2_OD	0xf0070010
+#define	F367TER_OP2_VAL	0xf0070008
+#define	F367TER_OP1_LOCK_CONF	0xf0070007
+
+/* SDFR */
+#define	R367TER_SDFR	0xf008
+#define	F367TER_OP0_FREQ	0xf00800f0
+#define	F367TER_OP1_FREQ	0xf008000f
+
+/* STATUS */
+#define	R367TER_STATUS	0xf009
+#define	F367TER_TPS_LOCK	0xf0090080
+#define	F367TER_SYR_LOCK	0xf0090040
+#define	F367TER_AGC_LOCK	0xf0090020
+#define	F367TER_PRF	0xf0090010
+#define	F367TER_LK	0xf0090008
+#define	F367TER_PR	0xf0090007
+
+/* AUX_CLK */
+#define	R367TER_AUX_CLK	0xf00a
+#define	F367TER_AUXFEC_CTL	0xf00a00c0
+#define	F367TER_DIS_CKX4	0xf00a0020
+#define	F367TER_CKSEL	0xf00a0018
+#define	F367TER_CKDIV_PROG	0xf00a0006
+#define	F367TER_AUXCLK_ENA	0xf00a0001
+
+/* FREESYS1 */
+#define	R367TER_FREESYS1	0xf00b
+#define	F367TER_FREE_SYS1	0xf00b00ff
+
+/* FREESYS2 */
+#define	R367TER_FREESYS2	0xf00c
+#define	F367TER_FREE_SYS2	0xf00c00ff
+
+/* FREESYS3 */
+#define	R367TER_FREESYS3	0xf00d
+#define	F367TER_FREE_SYS3	0xf00d00ff
+
+/* GPIO_CFG */
+#define	R367TER_GPIO_CFG	0xf00e
+#define	F367TER_GPIO7_NOD	0xf00e0080
+#define	F367TER_GPIO7_CFG	0xf00e0040
+#define	F367TER_GPIO6_NOD	0xf00e0020
+#define	F367TER_GPIO6_CFG	0xf00e0010
+#define	F367TER_GPIO5_NOD	0xf00e0008
+#define	F367TER_GPIO5_CFG	0xf00e0004
+#define	F367TER_GPIO4_NOD	0xf00e0002
+#define	F367TER_GPIO4_CFG	0xf00e0001
+
+/* GPIO_CMD */
+#define	R367TER_GPIO_CMD	0xf00f
+#define	F367TER_GPIO7_VAL	0xf00f0008
+#define	F367TER_GPIO6_VAL	0xf00f0004
+#define	F367TER_GPIO5_VAL	0xf00f0002
+#define	F367TER_GPIO4_VAL	0xf00f0001
+
+/* AGC2MAX */
+#define	R367TER_AGC2MAX	0xf010
+#define	F367TER_AGC2_MAX	0xf01000ff
+
+/* AGC2MIN */
+#define	R367TER_AGC2MIN	0xf011
+#define	F367TER_AGC2_MIN	0xf01100ff
+
+/* AGC1MAX */
+#define	R367TER_AGC1MAX	0xf012
+#define	F367TER_AGC1_MAX	0xf01200ff
+
+/* AGC1MIN */
+#define	R367TER_AGC1MIN	0xf013
+#define	F367TER_AGC1_MIN	0xf01300ff
+
+/* AGCR */
+#define	R367TER_AGCR	0xf014
+#define	F367TER_RATIO_A	0xf01400e0
+#define	F367TER_RATIO_B	0xf0140018
+#define	F367TER_RATIO_C	0xf0140007
+
+/* AGC2TH */
+#define	R367TER_AGC2TH	0xf015
+#define	F367TER_AGC2_THRES	0xf01500ff
+
+/* AGC12c */
+#define	R367TER_AGC12C	0xf016
+#define	F367TER_AGC1_IV	0xf0160080
+#define	F367TER_AGC1_OD	0xf0160040
+#define	F367TER_AGC1_LOAD	0xf0160020
+#define	F367TER_AGC2_IV	0xf0160010
+#define	F367TER_AGC2_OD	0xf0160008
+#define	F367TER_AGC2_LOAD	0xf0160004
+#define	F367TER_AGC12_MODE	0xf0160003
+
+/* AGCCTRL1 */
+#define	R367TER_AGCCTRL1	0xf017
+#define	F367TER_DAGC_ON	0xf0170080
+#define	F367TER_INVERT_AGC12	0xf0170040
+#define	F367TER_AGC1_MODE	0xf0170008
+#define	F367TER_AGC2_MODE	0xf0170007
+
+/* AGCCTRL2 */
+#define	R367TER_AGCCTRL2	0xf018
+#define	F367TER_FRZ2_CTRL	0xf0180060
+#define	F367TER_FRZ1_CTRL	0xf0180018
+#define	F367TER_TIME_CST	0xf0180007
+
+/* AGC1VAL1 */
+#define	R367TER_AGC1VAL1	0xf019
+#define	F367TER_AGC1_VAL_LO	0xf01900ff
+
+/* AGC1VAL2 */
+#define	R367TER_AGC1VAL2	0xf01a
+#define	F367TER_AGC1_VAL_HI	0xf01a000f
+
+/* AGC2VAL1 */
+#define	R367TER_AGC2VAL1	0xf01b
+#define	F367TER_AGC2_VAL_LO	0xf01b00ff
+
+/* AGC2VAL2 */
+#define	R367TER_AGC2VAL2	0xf01c
+#define	F367TER_AGC2_VAL_HI	0xf01c000f
+
+/* AGC2PGA */
+#define	R367TER_AGC2PGA	0xf01d
+#define	F367TER_AGC2_PGA	0xf01d00ff
+
+/* OVF_RATE1 */
+#define	R367TER_OVF_RATE1	0xf01e
+#define	F367TER_OVF_RATE_HI	0xf01e000f
+
+/* OVF_RATE2 */
+#define	R367TER_OVF_RATE2	0xf01f
+#define	F367TER_OVF_RATE_LO	0xf01f00ff
+
+/* GAIN_SRC1 */
+#define	R367TER_GAIN_SRC1	0xf020
+#define	F367TER_INV_SPECTR	0xf0200080
+#define	F367TER_IQ_INVERT	0xf0200040
+#define	F367TER_INR_BYPASS	0xf0200020
+#define	F367TER_STATUS_INV_SPECRUM	0xf0200010
+#define	F367TER_GAIN_SRC_HI	0xf020000f
+
+/* GAIN_SRC2 */
+#define	R367TER_GAIN_SRC2	0xf021
+#define	F367TER_GAIN_SRC_LO	0xf02100ff
+
+/* INC_DEROT1 */
+#define	R367TER_INC_DEROT1	0xf022
+#define	F367TER_INC_DEROT_HI	0xf02200ff
+
+/* INC_DEROT2 */
+#define	R367TER_INC_DEROT2	0xf023
+#define	F367TER_INC_DEROT_LO	0xf02300ff
+
+/* PPM_CPAMP_DIR */
+#define	R367TER_PPM_CPAMP_DIR	0xf024
+#define	F367TER_PPM_CPAMP_DIRECT	0xf02400ff
+
+/* PPM_CPAMP_INV */
+#define	R367TER_PPM_CPAMP_INV	0xf025
+#define	F367TER_PPM_CPAMP_INVER	0xf02500ff
+
+/* FREESTFE_1 */
+#define	R367TER_FREESTFE_1	0xf026
+#define	F367TER_SYMBOL_NUMBER_INC	0xf02600c0
+#define	F367TER_SEL_LSB	0xf0260004
+#define	F367TER_AVERAGE_ON	0xf0260002
+#define	F367TER_DC_ADJ	0xf0260001
+
+/* FREESTFE_2 */
+#define	R367TER_FREESTFE_2	0xf027
+#define	F367TER_SEL_SRCOUT	0xf02700c0
+#define	F367TER_SEL_SYRTHR	0xf027001f
+
+/* DCOFFSET */
+#define	R367TER_DCOFFSET	0xf028
+#define	F367TER_SELECT_I_Q	0xf0280080
+#define	F367TER_DC_OFFSET	0xf028007f
+
+/* EN_PROCESS */
+#define	R367TER_EN_PROCESS	0xf029
+#define	F367TER_FREE	0xf02900f0
+#define	F367TER_ENAB_MANUAL	0xf0290001
+
+/* SDI_SMOOTHER */
+#define	R367TER_SDI_SMOOTHER	0xf02a
+#define	F367TER_DIS_SMOOTH	0xf02a0080
+#define	F367TER_SDI_INC_SMOOTHER	0xf02a007f
+
+/* FE_LOOP_OPEN */
+#define	R367TER_FE_LOOP_OPEN	0xf02b
+#define	F367TER_TRL_LOOP_OP	0xf02b0002
+#define	F367TER_CRL_LOOP_OP	0xf02b0001
+
+/* FREQOFF1 */
+#define	R367TER_FREQOFF1	0xf02c
+#define	F367TER_FREQ_OFFSET_LOOP_OPEN_VHI	0xf02c00ff
+
+/* FREQOFF2 */
+#define	R367TER_FREQOFF2	0xf02d
+#define	F367TER_FREQ_OFFSET_LOOP_OPEN_HI	0xf02d00ff
+
+/* FREQOFF3 */
+#define	R367TER_FREQOFF3	0xf02e
+#define	F367TER_FREQ_OFFSET_LOOP_OPEN_LO	0xf02e00ff
+
+/* TIMOFF1 */
+#define	R367TER_TIMOFF1	0xf02f
+#define	F367TER_TIM_OFFSET_LOOP_OPEN_HI	0xf02f00ff
+
+/* TIMOFF2 */
+#define	R367TER_TIMOFF2	0xf030
+#define	F367TER_TIM_OFFSET_LOOP_OPEN_LO	0xf03000ff
+
+/* EPQ */
+#define	R367TER_EPQ	0xf031
+#define	F367TER_EPQ1	0xf03100ff
+
+/* EPQAUTO */
+#define	R367TER_EPQAUTO	0xf032
+#define	F367TER_EPQ2	0xf03200ff
+
+/* SYR_UPDATE */
+#define	R367TER_SYR_UPDATE	0xf033
+#define	F367TER_SYR_PROTV	0xf0330080
+#define	F367TER_SYR_PROTV_GAIN	0xf0330060
+#define	F367TER_SYR_FILTER	0xf0330010
+#define	F367TER_SYR_TRACK_THRES	0xf033000c
+
+/* CHPFREE */
+#define	R367TER_CHPFREE	0xf034
+#define	F367TER_CHP_FREE	0xf03400ff
+
+/* PPM_STATE_MAC */
+#define	R367TER_PPM_STATE_MAC	0xf035
+#define	F367TER_PPM_STATE_MACHINE_DECODER	0xf035003f
+
+/* INR_THRESHOLD */
+#define	R367TER_INR_THRESHOLD	0xf036
+#define	F367TER_INR_THRESH	0xf03600ff
+
+/* EPQ_TPS_ID_CELL */
+#define	R367TER_EPQ_TPS_ID_CELL	0xf037
+#define	F367TER_ENABLE_LGTH_TO_CF	0xf0370080
+#define	F367TER_DIS_TPS_RSVD	0xf0370040
+#define	F367TER_DIS_BCH	0xf0370020
+#define	F367TER_DIS_ID_CEL	0xf0370010
+#define	F367TER_TPS_ADJUST_SYM	0xf037000f
+
+/* EPQ_CFG */
+#define	R367TER_EPQ_CFG	0xf038
+#define	F367TER_EPQ_RANGE	0xf0380002
+#define	F367TER_EPQ_SOFT	0xf0380001
+
+/* EPQ_STATUS */
+#define	R367TER_EPQ_STATUS	0xf039
+#define	F367TER_SLOPE_INC	0xf03900fc
+#define	F367TER_TPS_FIELD	0xf0390003
+
+/* AUTORELOCK */
+#define	R367TER_AUTORELOCK	0xf03a
+#define	F367TER_BYPASS_BER_TEMPO	0xf03a0080
+#define	F367TER_BER_TEMPO	0xf03a0070
+#define	F367TER_BYPASS_COFDM_TEMPO	0xf03a0008
+#define	F367TER_COFDM_TEMPO	0xf03a0007
+
+/* BER_THR_VMSB */
+#define	R367TER_BER_THR_VMSB	0xf03b
+#define	F367TER_BER_THRESHOLD_HI	0xf03b00ff
+
+/* BER_THR_MSB */
+#define	R367TER_BER_THR_MSB	0xf03c
+#define	F367TER_BER_THRESHOLD_MID	0xf03c00ff
+
+/* BER_THR_LSB */
+#define	R367TER_BER_THR_LSB	0xf03d
+#define	F367TER_BER_THRESHOLD_LO	0xf03d00ff
+
+/* CCD */
+#define	R367TER_CCD	0xf03e
+#define	F367TER_CCD_DETECTED	0xf03e0080
+#define	F367TER_CCD_RESET	0xf03e0040
+#define	F367TER_CCD_THRESHOLD	0xf03e000f
+
+/* SPECTR_CFG */
+#define	R367TER_SPECTR_CFG	0xf03f
+#define	F367TER_SPECT_CFG	0xf03f0003
+
+/* CONSTMU_MSB */
+#define	R367TER_CONSTMU_MSB	0xf040
+#define	F367TER_CONSTMU_FREEZE	0xf0400080
+#define	F367TER_CONSTNU_FORCE_EN	0xf0400040
+#define	F367TER_CONST_MU_MSB	0xf040003f
+
+/* CONSTMU_LSB */
+#define	R367TER_CONSTMU_LSB	0xf041
+#define	F367TER_CONST_MU_LSB	0xf04100ff
+
+/* CONSTMU_MAX_MSB */
+#define	R367TER_CONSTMU_MAX_MSB	0xf042
+#define	F367TER_CONST_MU_MAX_MSB	0xf042003f
+
+/* CONSTMU_MAX_LSB */
+#define	R367TER_CONSTMU_MAX_LSB	0xf043
+#define	F367TER_CONST_MU_MAX_LSB	0xf04300ff
+
+/* ALPHANOISE */
+#define	R367TER_ALPHANOISE	0xf044
+#define	F367TER_USE_ALLFILTER	0xf0440080
+#define	F367TER_INTER_ON	0xf0440040
+#define	F367TER_ALPHA_NOISE	0xf044001f
+
+/* MAXGP_MSB */
+#define	R367TER_MAXGP_MSB	0xf045
+#define	F367TER_MUFILTER_LENGTH	0xf04500f0
+#define	F367TER_MAX_GP_MSB	0xf045000f
+
+/* MAXGP_LSB */
+#define	R367TER_MAXGP_LSB	0xf046
+#define	F367TER_MAX_GP_LSB	0xf04600ff
+
+/* ALPHAMSB */
+#define	R367TER_ALPHAMSB	0xf047
+#define	F367TER_CHC_DATARATE	0xf04700c0
+#define	F367TER_ALPHA_MSB	0xf047003f
+
+/* ALPHALSB */
+#define	R367TER_ALPHALSB	0xf048
+#define	F367TER_ALPHA_LSB	0xf04800ff
+
+/* PILOT_ACCU */
+#define	R367TER_PILOT_ACCU	0xf049
+#define	F367TER_USE_SCAT4ADDAPT	0xf0490080
+#define	F367TER_PILOT_ACC	0xf049001f
+
+/* PILOTMU_ACCU */
+#define	R367TER_PILOTMU_ACCU	0xf04a
+#define	F367TER_DISCARD_BAD_SP	0xf04a0080
+#define	F367TER_DISCARD_BAD_CP	0xf04a0040
+#define	F367TER_PILOT_MU_ACCU	0xf04a001f
+
+/* FILT_CHANNEL_EST */
+#define	R367TER_FILT_CHANNEL_EST	0xf04b
+#define	F367TER_USE_FILT_PILOT	0xf04b0080
+#define	F367TER_FILT_CHANNEL	0xf04b007f
+
+/* ALPHA_NOPISE_FREQ */
+#define	R367TER_ALPHA_NOPISE_FREQ	0xf04c
+#define	F367TER_NOISE_FREQ_FILT	0xf04c0040
+#define	F367TER_ALPHA_NOISE_FREQ	0xf04c003f
+
+/* RATIO_PILOT */
+#define	R367TER_RATIO_PILOT	0xf04d
+#define	F367TER_RATIO_MEAN_SP	0xf04d00f0
+#define	F367TER_RATIO_MEAN_CP	0xf04d000f
+
+/* CHC_CTL */
+#define	R367TER_CHC_CTL	0xf04e
+#define	F367TER_TRACK_EN	0xf04e0080
+#define	F367TER_NOISE_NORM_EN	0xf04e0040
+#define	F367TER_FORCE_CHC_RESET	0xf04e0020
+#define	F367TER_SHORT_TIME	0xf04e0010
+#define	F367TER_FORCE_STATE_EN	0xf04e0008
+#define	F367TER_FORCE_STATE	0xf04e0007
+
+/* EPQ_ADJUST */
+#define	R367TER_EPQ_ADJUST	0xf04f
+#define	F367TER_ADJUST_SCAT_IND	0xf04f00c0
+#define	F367TER_ONE_SYMBOL	0xf04f0010
+#define	F367TER_EPQ_DECAY	0xf04f000e
+#define	F367TER_HOLD_SLOPE	0xf04f0001
+
+/* EPQ_THRES */
+#define	R367TER_EPQ_THRES	0xf050
+#define	F367TER_EPQ_THR	0xf05000ff
+
+/* OMEGA_CTL */
+#define	R367TER_OMEGA_CTL	0xf051
+#define	F367TER_OMEGA_RST	0xf0510080
+#define	F367TER_FREEZE_OMEGA	0xf0510040
+#define	F367TER_OMEGA_SEL	0xf051003f
+
+/* GP_CTL */
+#define	R367TER_GP_CTL	0xf052
+#define	F367TER_CHC_STATE	0xf05200e0
+#define	F367TER_FREEZE_GP	0xf0520010
+#define	F367TER_GP_SEL	0xf052000f
+
+/* MUMSB */
+#define	R367TER_MUMSB	0xf053
+#define	F367TER_MU_MSB	0xf053007f
+
+/* MULSB */
+#define	R367TER_MULSB	0xf054
+#define	F367TER_MU_LSB	0xf05400ff
+
+/* GPMSB */
+#define	R367TER_GPMSB	0xf055
+#define	F367TER_CSI_THRESHOLD	0xf05500e0
+#define	F367TER_GP_MSB	0xf055000f
+
+/* GPLSB */
+#define	R367TER_GPLSB	0xf056
+#define	F367TER_GP_LSB	0xf05600ff
+
+/* OMEGAMSB */
+#define	R367TER_OMEGAMSB	0xf057
+#define	F367TER_OMEGA_MSB	0xf057007f
+
+/* OMEGALSB */
+#define	R367TER_OMEGALSB	0xf058
+#define	F367TER_OMEGA_LSB	0xf05800ff
+
+/* SCAT_NB */
+#define	R367TER_SCAT_NB	0xf059
+#define	F367TER_CHC_TEST	0xf05900f8
+#define	F367TER_SCAT_NUMB	0xf0590003
+
+/* CHC_DUMMY */
+#define	R367TER_CHC_DUMMY	0xf05a
+#define	F367TER_CHC_DUM	0xf05a00ff
+
+/* INC_CTL */
+#define	R367TER_INC_CTL	0xf05b
+#define	F367TER_INC_BYPASS	0xf05b0080
+#define	F367TER_INC_NDEPTH	0xf05b000c
+#define	F367TER_INC_MADEPTH	0xf05b0003
+
+/* INCTHRES_COR1 */
+#define	R367TER_INCTHRES_COR1	0xf05c
+#define	F367TER_INC_THRES_COR1	0xf05c00ff
+
+/* INCTHRES_COR2 */
+#define	R367TER_INCTHRES_COR2	0xf05d
+#define	F367TER_INC_THRES_COR2	0xf05d00ff
+
+/* INCTHRES_DET1 */
+#define	R367TER_INCTHRES_DET1	0xf05e
+#define	F367TER_INC_THRES_DET1	0xf05e003f
+
+/* INCTHRES_DET2 */
+#define	R367TER_INCTHRES_DET2	0xf05f
+#define	F367TER_INC_THRES_DET2	0xf05f003f
+
+/* IIR_CELLNB */
+#define	R367TER_IIR_CELLNB	0xf060
+#define	F367TER_NRST_IIR	0xf0600080
+#define	F367TER_IIR_CELL_NB	0xf0600007
+
+/* IIRCX_COEFF1_MSB */
+#define	R367TER_IIRCX_COEFF1_MSB	0xf061
+#define	F367TER_IIR_CX_COEFF1_MSB	0xf06100ff
+
+/* IIRCX_COEFF1_LSB */
+#define	R367TER_IIRCX_COEFF1_LSB	0xf062
+#define	F367TER_IIR_CX_COEFF1_LSB	0xf06200ff
+
+/* IIRCX_COEFF2_MSB */
+#define	R367TER_IIRCX_COEFF2_MSB	0xf063
+#define	F367TER_IIR_CX_COEFF2_MSB	0xf06300ff
+
+/* IIRCX_COEFF2_LSB */
+#define	R367TER_IIRCX_COEFF2_LSB	0xf064
+#define	F367TER_IIR_CX_COEFF2_LSB	0xf06400ff
+
+/* IIRCX_COEFF3_MSB */
+#define	R367TER_IIRCX_COEFF3_MSB	0xf065
+#define	F367TER_IIR_CX_COEFF3_MSB	0xf06500ff
+
+/* IIRCX_COEFF3_LSB */
+#define	R367TER_IIRCX_COEFF3_LSB	0xf066
+#define	F367TER_IIR_CX_COEFF3_LSB	0xf06600ff
+
+/* IIRCX_COEFF4_MSB */
+#define	R367TER_IIRCX_COEFF4_MSB	0xf067
+#define	F367TER_IIR_CX_COEFF4_MSB	0xf06700ff
+
+/* IIRCX_COEFF4_LSB */
+#define	R367TER_IIRCX_COEFF4_LSB	0xf068
+#define	F367TER_IIR_CX_COEFF4_LSB	0xf06800ff
+
+/* IIRCX_COEFF5_MSB */
+#define	R367TER_IIRCX_COEFF5_MSB	0xf069
+#define	F367TER_IIR_CX_COEFF5_MSB	0xf06900ff
+
+/* IIRCX_COEFF5_LSB */
+#define	R367TER_IIRCX_COEFF5_LSB	0xf06a
+#define	F367TER_IIR_CX_COEFF5_LSB	0xf06a00ff
+
+/* FEPATH_CFG */
+#define	R367TER_FEPATH_CFG	0xf06b
+#define	F367TER_DEMUX_SWAP	0xf06b0004
+#define	F367TER_DIGAGC_SWAP	0xf06b0002
+#define	F367TER_LONGPATH_IF	0xf06b0001
+
+/* PMC1_FUNC */
+#define	R367TER_PMC1_FUNC	0xf06c
+#define	F367TER_SOFT_RSTN	0xf06c0080
+#define	F367TER_PMC1_AVERAGE_TIME	0xf06c0078
+#define	F367TER_PMC1_WAIT_TIME	0xf06c0006
+#define	F367TER_PMC1_2N_SEL	0xf06c0001
+
+/* PMC1_FOR */
+#define	R367TER_PMC1_FOR	0xf06d
+#define	F367TER_PMC1_FORCE	0xf06d0080
+#define	F367TER_PMC1_FORCE_VALUE	0xf06d007c
+
+/* PMC2_FUNC */
+#define	R367TER_PMC2_FUNC	0xf06e
+#define	F367TER_PMC2_SOFT_STN	0xf06e0080
+#define	F367TER_PMC2_ACCU_TIME	0xf06e0070
+#define	F367TER_PMC2_CMDP_MN	0xf06e0008
+#define	F367TER_PMC2_SWAP	0xf06e0004
+
+/* STATUS_ERR_DA */
+#define	R367TER_STATUS_ERR_DA	0xf06f
+#define	F367TER_COM_USEGAINTRK	0xf06f0080
+#define	F367TER_COM_AGCLOCK	0xf06f0040
+#define	F367TER_AUT_AGCLOCK	0xf06f0020
+#define	F367TER_MIN_ERR_X_LSB	0xf06f000f
+
+/* DIG_AGC_R */
+#define	R367TER_DIG_AGC_R	0xf070
+#define	F367TER_COM_SOFT_RSTN	0xf0700080
+#define	F367TER_COM_AGC_ON	0xf0700040
+#define	F367TER_COM_EARLY	0xf0700020
+#define	F367TER_AUT_SOFT_RESETN	0xf0700010
+#define	F367TER_AUT_AGC_ON	0xf0700008
+#define	F367TER_AUT_EARLY	0xf0700004
+#define	F367TER_AUT_ROT_EN	0xf0700002
+#define	F367TER_LOCK_SOFT_RESETN	0xf0700001
+
+/* COMAGC_TARMSB */
+#define	R367TER_COMAGC_TARMSB	0xf071
+#define	F367TER_COM_AGC_TARGET_MSB	0xf07100ff
+
+/* COM_AGC_TAR_ENMODE */
+#define	R367TER_COM_AGC_TAR_ENMODE	0xf072
+#define	F367TER_COM_AGC_TARGET_LSB	0xf07200f0
+#define	F367TER_COM_ENMODE	0xf072000f
+
+/* COM_AGC_CFG */
+#define	R367TER_COM_AGC_CFG	0xf073
+#define	F367TER_COM_N	0xf07300f8
+#define	F367TER_COM_STABMODE	0xf0730006
+#define	F367TER_ERR_SEL	0xf0730001
+
+/* COM_AGC_GAIN1 */
+#define	R367TER_COM_AGC_GAIN1	0xf074
+#define	F367TER_COM_GAIN1aCK	0xf07400f0
+#define	F367TER_COM_GAIN1TRK	0xf074000f
+
+/* AUT_AGC_TARGETMSB */
+#define	R367TER_AUT_AGC_TARGETMSB	0xf075
+#define	F367TER_AUT_AGC_TARGET_MSB	0xf07500ff
+
+/* LOCK_DET_MSB */
+#define	R367TER_LOCK_DET_MSB	0xf076
+#define	F367TER_LOCK_DETECT_MSB	0xf07600ff
+
+/* AGCTAR_LOCK_LSBS */
+#define	R367TER_AGCTAR_LOCK_LSBS	0xf077
+#define	F367TER_AUT_AGC_TARGET_LSB	0xf07700f0
+#define	F367TER_LOCK_DETECT_LSB	0xf077000f
+
+/* AUT_GAIN_EN */
+#define	R367TER_AUT_GAIN_EN	0xf078
+#define	F367TER_AUT_ENMODE	0xf07800f0
+#define	F367TER_AUT_GAIN2	0xf078000f
+
+/* AUT_CFG */
+#define	R367TER_AUT_CFG	0xf079
+#define	F367TER_AUT_N	0xf07900f8
+#define	F367TER_INT_CHOICE	0xf0790006
+#define	F367TER_INT_LOAD	0xf0790001
+
+/* LOCKN */
+#define	R367TER_LOCKN	0xf07a
+#define	F367TER_LOCK_N	0xf07a00f8
+#define	F367TER_SEL_IQNTAR	0xf07a0004
+#define	F367TER_LOCK_DETECT_CHOICE	0xf07a0003
+
+/* INT_X_3 */
+#define	R367TER_INT_X_3	0xf07b
+#define	F367TER_INT_X3	0xf07b00ff
+
+/* INT_X_2 */
+#define	R367TER_INT_X_2	0xf07c
+#define	F367TER_INT_X2	0xf07c00ff
+
+/* INT_X_1 */
+#define	R367TER_INT_X_1	0xf07d
+#define	F367TER_INT_X1	0xf07d00ff
+
+/* INT_X_0 */
+#define	R367TER_INT_X_0	0xf07e
+#define	F367TER_INT_X0	0xf07e00ff
+
+/* MIN_ERRX_MSB */
+#define	R367TER_MIN_ERRX_MSB	0xf07f
+#define	F367TER_MIN_ERR_X_MSB	0xf07f00ff
+
+/* COR_CTL */
+#define	R367TER_COR_CTL	0xf080
+#define	F367TER_CORE_ACTIVE	0xf0800020
+#define	F367TER_HOLD	0xf0800010
+#define	F367TER_CORE_STATE_CTL	0xf080000f
+
+/* COR_STAT */
+#define	R367TER_COR_STAT	0xf081
+#define	F367TER_SCATT_LOCKED	0xf0810080
+#define	F367TER_TPS_LOCKED	0xf0810040
+#define	F367TER_SYR_LOCKED_COR	0xf0810020
+#define	F367TER_AGC_LOCKED_STAT	0xf0810010
+#define	F367TER_CORE_STATE_STAT	0xf081000f
+
+/* COR_INTEN */
+#define	R367TER_COR_INTEN	0xf082
+#define	F367TER_INTEN	0xf0820080
+#define	F367TER_INTEN_SYR	0xf0820020
+#define	F367TER_INTEN_FFT	0xf0820010
+#define	F367TER_INTEN_AGC	0xf0820008
+#define	F367TER_INTEN_TPS1	0xf0820004
+#define	F367TER_INTEN_TPS2	0xf0820002
+#define	F367TER_INTEN_TPS3	0xf0820001
+
+/* COR_INTSTAT */
+#define	R367TER_COR_INTSTAT	0xf083
+#define	F367TER_INTSTAT_SYR	0xf0830020
+#define	F367TER_INTSTAT_FFT	0xf0830010
+#define	F367TER_INTSAT_AGC	0xf0830008
+#define	F367TER_INTSTAT_TPS1	0xf0830004
+#define	F367TER_INTSTAT_TPS2	0xf0830002
+#define	F367TER_INTSTAT_TPS3	0xf0830001
+
+/* COR_MODEGUARD */
+#define	R367TER_COR_MODEGUARD	0xf084
+#define	F367TER_FORCE	0xf0840010
+#define	F367TER_MODE	0xf084000c
+#define	F367TER_GUARD	0xf0840003
+
+/* AGC_CTL */
+#define	R367TER_AGC_CTL	0xf085
+#define	F367TER_AGC_TIMING_FACTOR	0xf08500e0
+#define	F367TER_AGC_LAST	0xf0850010
+#define	F367TER_AGC_GAIN	0xf085000c
+#define	F367TER_AGC_NEG	0xf0850002
+#define	F367TER_AGC_SET	0xf0850001
+
+/* AGC_MANUAL1 */
+#define	R367TER_AGC_MANUAL1	0xf086
+#define	F367TER_AGC_VAL_LO	0xf08600ff
+
+/* AGC_MANUAL2 */
+#define	R367TER_AGC_MANUAL2	0xf087
+#define	F367TER_AGC_VAL_HI	0xf087000f
+
+/* AGC_TARG */
+#define	R367TER_AGC_TARG	0xf088
+#define	F367TER_AGC_TARGET	0xf08800ff
+
+/* AGC_GAIN1 */
+#define	R367TER_AGC_GAIN1	0xf089
+#define	F367TER_AGC_GAIN_LO	0xf08900ff
+
+/* AGC_GAIN2 */
+#define	R367TER_AGC_GAIN2	0xf08a
+#define	F367TER_AGC_LOCKED_GAIN2	0xf08a0010
+#define	F367TER_AGC_GAIN_HI	0xf08a000f
+
+/* RESERVED_1 */
+#define	R367TER_RESERVED_1	0xf08b
+#define	F367TER_RESERVED1	0xf08b00ff
+
+/* RESERVED_2 */
+#define	R367TER_RESERVED_2	0xf08c
+#define	F367TER_RESERVED2	0xf08c00ff
+
+/* RESERVED_3 */
+#define	R367TER_RESERVED_3	0xf08d
+#define	F367TER_RESERVED3	0xf08d00ff
+
+/* CAS_CTL */
+#define	R367TER_CAS_CTL	0xf08e
+#define	F367TER_CCS_ENABLE	0xf08e0080
+#define	F367TER_ACS_DISABLE	0xf08e0040
+#define	F367TER_DAGC_DIS	0xf08e0020
+#define	F367TER_DAGC_GAIN	0xf08e0018
+#define	F367TER_CCSMU	0xf08e0007
+
+/* CAS_FREQ */
+#define	R367TER_CAS_FREQ	0xf08f
+#define	F367TER_CCS_FREQ	0xf08f00ff
+
+/* CAS_DAGCGAIN */
+#define	R367TER_CAS_DAGCGAIN	0xf090
+#define	F367TER_CAS_DAGC_GAIN	0xf09000ff
+
+/* SYR_CTL */
+#define	R367TER_SYR_CTL	0xf091
+#define	F367TER_SICTH_ENABLE	0xf0910080
+#define	F367TER_LONG_ECHO	0xf0910078
+#define	F367TER_AUTO_LE_EN	0xf0910004
+#define	F367TER_SYR_BYPASS	0xf0910002
+#define	F367TER_SYR_TR_DIS	0xf0910001
+
+/* SYR_STAT */
+#define	R367TER_SYR_STAT	0xf092
+#define	F367TER_SYR_LOCKED_STAT	0xf0920010
+#define	F367TER_SYR_MODE	0xf092000c
+#define	F367TER_SYR_GUARD	0xf0920003
+
+/* SYR_NCO1 */
+#define	R367TER_SYR_NCO1	0xf093
+#define	F367TER_SYR_NCO_LO	0xf09300ff
+
+/* SYR_NCO2 */
+#define	R367TER_SYR_NCO2	0xf094
+#define	F367TER_SYR_NCO_HI	0xf094003f
+
+/* SYR_OFFSET1 */
+#define	R367TER_SYR_OFFSET1	0xf095
+#define	F367TER_SYR_OFFSET_LO	0xf09500ff
+
+/* SYR_OFFSET2 */
+#define	R367TER_SYR_OFFSET2	0xf096
+#define	F367TER_SYR_OFFSET_HI	0xf096003f
+
+/* FFT_CTL */
+#define	R367TER_FFT_CTL	0xf097
+#define	F367TER_SHIFT_FFT_TRIG	0xf0970018
+#define	F367TER_FFT_TRIGGER	0xf0970004
+#define	F367TER_FFT_MANUAL	0xf0970002
+#define	F367TER_IFFT_MODE	0xf0970001
+
+/* SCR_CTL */
+#define	R367TER_SCR_CTL	0xf098
+#define	F367TER_SYRADJDECAY	0xf0980070
+#define	F367TER_SCR_CPEDIS	0xf0980002
+#define	F367TER_SCR_DIS	0xf0980001
+
+/* PPM_CTL1 */
+#define	R367TER_PPM_CTL1	0xf099
+#define	F367TER_PPM_MAXFREQ	0xf0990030
+#define	F367TER_PPM_MAXTIM	0xf0990008
+#define	F367TER_PPM_INVSEL	0xf0990004
+#define	F367TER_PPM_SCATDIS	0xf0990002
+#define	F367TER_PPM_BYP	0xf0990001
+
+/* TRL_CTL */
+#define	R367TER_TRL_CTL	0xf09a
+#define	F367TER_TRL_NOMRATE_LSB	0xf09a0080
+#define	F367TER_TRL_GAIN_FACTOR	0xf09a0078
+#define	F367TER_TRL_LOOPGAIN	0xf09a0007
+
+/* TRL_NOMRATE1 */
+#define	R367TER_TRL_NOMRATE1	0xf09b
+#define	F367TER_TRL_NOMRATE_LO	0xf09b00ff
+
+/* TRL_NOMRATE2 */
+#define	R367TER_TRL_NOMRATE2	0xf09c
+#define	F367TER_TRL_NOMRATE_HI	0xf09c00ff
+
+/* TRL_TIME1 */
+#define	R367TER_TRL_TIME1	0xf09d
+#define	F367TER_TRL_TOFFSET_LO	0xf09d00ff
+
+/* TRL_TIME2 */
+#define	R367TER_TRL_TIME2	0xf09e
+#define	F367TER_TRL_TOFFSET_HI	0xf09e00ff
+
+/* CRL_CTL */
+#define	R367TER_CRL_CTL	0xf09f
+#define	F367TER_CRL_DIS	0xf09f0080
+#define	F367TER_CRL_GAIN_FACTOR	0xf09f0078
+#define	F367TER_CRL_LOOPGAIN	0xf09f0007
+
+/* CRL_FREQ1 */
+#define	R367TER_CRL_FREQ1	0xf0a0
+#define	F367TER_CRL_FOFFSET_LO	0xf0a000ff
+
+/* CRL_FREQ2 */
+#define	R367TER_CRL_FREQ2	0xf0a1
+#define	F367TER_CRL_FOFFSET_HI	0xf0a100ff
+
+/* CRL_FREQ3 */
+#define	R367TER_CRL_FREQ3	0xf0a2
+#define	F367TER_CRL_FOFFSET_VHI	0xf0a200ff
+
+/* TPS_SFRAME_CTL */
+#define	R367TER_TPS_SFRAME_CTL	0xf0a3
+#define	F367TER_TPS_SFRAME_SYNC	0xf0a30001
+
+/* CHC_SNR */
+#define	R367TER_CHC_SNR	0xf0a4
+#define	F367TER_CHCSNR	0xf0a400ff
+
+/* BDI_CTL */
+#define	R367TER_BDI_CTL	0xf0a5
+#define	F367TER_BDI_LPSEL	0xf0a50002
+#define	F367TER_BDI_SERIAL	0xf0a50001
+
+/* DMP_CTL */
+#define	R367TER_DMP_CTL	0xf0a6
+#define	F367TER_DMP_SCALING_FACTOR	0xf0a6001e
+#define	F367TER_DMP_SDDIS	0xf0a60001
+
+/* TPS_RCVD1 */
+#define	R367TER_TPS_RCVD1	0xf0a7
+#define	F367TER_TPS_CHANGE	0xf0a70040
+#define	F367TER_BCH_OK	0xf0a70020
+#define	F367TER_TPS_SYNC	0xf0a70010
+#define	F367TER_TPS_FRAME	0xf0a70003
+
+/* TPS_RCVD2 */
+#define	R367TER_TPS_RCVD2	0xf0a8
+#define	F367TER_TPS_HIERMODE	0xf0a80070
+#define	F367TER_TPS_CONST	0xf0a80003
+
+/* TPS_RCVD3 */
+#define	R367TER_TPS_RCVD3	0xf0a9
+#define	F367TER_TPS_LPCODE	0xf0a90070
+#define	F367TER_TPS_HPCODE	0xf0a90007
+
+/* TPS_RCVD4 */
+#define	R367TER_TPS_RCVD4	0xf0aa
+#define	F367TER_TPS_GUARD	0xf0aa0030
+#define	F367TER_TPS_MODE	0xf0aa0003
+
+/* TPS_ID_CELL1 */
+#define	R367TER_TPS_ID_CELL1	0xf0ab
+#define	F367TER_TPS_ID_CELL_LO	0xf0ab00ff
+
+/* TPS_ID_CELL2 */
+#define	R367TER_TPS_ID_CELL2	0xf0ac
+#define	F367TER_TPS_ID_CELL_HI	0xf0ac00ff
+
+/* TPS_RCVD5_SET1 */
+#define	R367TER_TPS_RCVD5_SET1	0xf0ad
+#define	F367TER_TPS_NA	0xf0ad00fC
+#define	F367TER_TPS_SETFRAME	0xf0ad0003
+
+/* TPS_SET2 */
+#define	R367TER_TPS_SET2	0xf0ae
+#define	F367TER_TPS_SETHIERMODE	0xf0ae0070
+#define	F367TER_TPS_SETCONST	0xf0ae0003
+
+/* TPS_SET3 */
+#define	R367TER_TPS_SET3	0xf0af
+#define	F367TER_TPS_SETLPCODE	0xf0af0070
+#define	F367TER_TPS_SETHPCODE	0xf0af0007
+
+/* TPS_CTL */
+#define	R367TER_TPS_CTL	0xf0b0
+#define	F367TER_TPS_IMM	0xf0b00004
+#define	F367TER_TPS_BCHDIS	0xf0b00002
+#define	F367TER_TPS_UPDDIS	0xf0b00001
+
+/* CTL_FFTOSNUM */
+#define	R367TER_CTL_FFTOSNUM	0xf0b1
+#define	F367TER_SYMBOL_NUMBER	0xf0b1007f
+
+/* TESTSELECT */
+#define	R367TER_TESTSELECT	0xf0b2
+#define	F367TER_TEST_SELECT	0xf0b2001f
+
+/* MSC_REV */
+#define	R367TER_MSC_REV	0xf0b3
+#define	F367TER_REV_NUMBER	0xf0b300ff
+
+/* PIR_CTL */
+#define	R367TER_PIR_CTL	0xf0b4
+#define	F367TER_FREEZE	0xf0b40001
+
+/* SNR_CARRIER1 */
+#define	R367TER_SNR_CARRIER1	0xf0b5
+#define	F367TER_SNR_CARRIER_LO	0xf0b500ff
+
+/* SNR_CARRIER2 */
+#define	R367TER_SNR_CARRIER2	0xf0b6
+#define	F367TER_MEAN	0xf0b600c0
+#define	F367TER_SNR_CARRIER_HI	0xf0b6001f
+
+/* PPM_CPAMP */
+#define	R367TER_PPM_CPAMP	0xf0b7
+#define	F367TER_PPM_CPC	0xf0b700ff
+
+/* TSM_AP0 */
+#define	R367TER_TSM_AP0	0xf0b8
+#define	F367TER_ADDRESS_BYTE_0	0xf0b800ff
+
+/* TSM_AP1 */
+#define	R367TER_TSM_AP1	0xf0b9
+#define	F367TER_ADDRESS_BYTE_1	0xf0b900ff
+
+/* TSM_AP2 */
+#define	R367TER_TSM_AP2	0xf0bA
+#define	F367TER_DATA_BYTE_0	0xf0ba00ff
+
+/* TSM_AP3 */
+#define	R367TER_TSM_AP3	0xf0bB
+#define	F367TER_DATA_BYTE_1	0xf0bb00ff
+
+/* TSM_AP4 */
+#define	R367TER_TSM_AP4	0xf0bC
+#define	F367TER_DATA_BYTE_2	0xf0bc00ff
+
+/* TSM_AP5 */
+#define	R367TER_TSM_AP5	0xf0bD
+#define	F367TER_DATA_BYTE_3	0xf0bd00ff
+
+/* TSM_AP6 */
+#define	R367TER_TSM_AP6	0xf0bE
+#define	F367TER_TSM_AP_6	0xf0be00ff
+
+/* TSM_AP7 */
+#define	R367TER_TSM_AP7	0xf0bF
+#define	F367TER_MEM_SELECT_BYTE	0xf0bf00ff
+
+/* TSTRES */
+#define	R367TER_TSTRES	0xf0c0
+#define	F367TER_FRES_DISPLAY	0xf0c00080
+#define	F367TER_FRES_FIFO_AD	0xf0c00020
+#define	F367TER_FRESRS	0xf0c00010
+#define	F367TER_FRESACS	0xf0c00008
+#define	F367TER_FRESFEC	0xf0c00004
+#define	F367TER_FRES_PRIF	0xf0c00002
+#define	F367TER_FRESCORE	0xf0c00001
+
+/* ANACTRL */
+#define	R367TER_ANACTRL	0xf0c1
+#define	F367TER_BYPASS_XTAL	0xf0c10040
+#define	F367TER_BYPASS_PLLXN	0xf0c1000c
+#define	F367TER_DIS_PAD_OSC	0xf0c10002
+#define	F367TER_STDBY_PLLXN	0xf0c10001
+
+/* TSTBUS */
+#define	R367TER_TSTBUS	0xf0c2
+#define	F367TER_TS_BYTE_CLK_INV	0xf0c20080
+#define	F367TER_CFG_IP	0xf0c20070
+#define	F367TER_CFG_TST	0xf0c2000f
+
+/* TSTRATE */
+#define	R367TER_TSTRATE	0xf0c6
+#define	F367TER_FORCEPHA	0xf0c60080
+#define	F367TER_FNEWPHA	0xf0c60010
+#define	F367TER_FROT90	0xf0c60008
+#define	F367TER_FR	0xf0c60007
+
+/* CONSTMODE */
+#define	R367TER_CONSTMODE	0xf0cb
+#define	F367TER_TST_PRIF	0xf0cb00e0
+#define	F367TER_CAR_TYPE	0xf0cb0018
+#define	F367TER_CONST_MODE	0xf0cb0003
+
+/* CONSTCARR1 */
+#define	R367TER_CONSTCARR1	0xf0cc
+#define	F367TER_CONST_CARR_LO	0xf0cc00ff
+
+/* CONSTCARR2 */
+#define	R367TER_CONSTCARR2	0xf0cd
+#define	F367TER_CONST_CARR_HI	0xf0cd001f
+
+/* ICONSTEL */
+#define	R367TER_ICONSTEL	0xf0ce
+#define	F367TER_PICONSTEL	0xf0ce00ff
+
+/* QCONSTEL */
+#define	R367TER_QCONSTEL	0xf0cf
+#define	F367TER_PQCONSTEL	0xf0cf00ff
+
+/* TSTBISTRES0 */
+#define	R367TER_TSTBISTRES0	0xf0d0
+#define	F367TER_BEND_PPM	0xf0d00080
+#define	F367TER_BBAD_PPM	0xf0d00040
+#define	F367TER_BEND_FFTW	0xf0d00020
+#define	F367TER_BBAD_FFTW	0xf0d00010
+#define	F367TER_BEND_FFT_BUF	0xf0d00008
+#define	F367TER_BBAD_FFT_BUF	0xf0d00004
+#define	F367TER_BEND_SYR	0xf0d00002
+#define	F367TER_BBAD_SYR	0xf0d00001
+
+/* TSTBISTRES1 */
+#define	R367TER_TSTBISTRES1	0xf0d1
+#define	F367TER_BEND_CHC_CP	0xf0d10080
+#define	F367TER_BBAD_CHC_CP	0xf0d10040
+#define	F367TER_BEND_CHCI	0xf0d10020
+#define	F367TER_BBAD_CHCI	0xf0d10010
+#define	F367TER_BEND_BDI	0xf0d10008
+#define	F367TER_BBAD_BDI	0xf0d10004
+#define	F367TER_BEND_SDI	0xf0d10002
+#define	F367TER_BBAD_SDI	0xf0d10001
+
+/* TSTBISTRES2 */
+#define	R367TER_TSTBISTRES2	0xf0d2
+#define	F367TER_BEND_CHC_INC	0xf0d20080
+#define	F367TER_BBAD_CHC_INC	0xf0d20040
+#define	F367TER_BEND_CHC_SPP	0xf0d20020
+#define	F367TER_BBAD_CHC_SPP	0xf0d20010
+#define	F367TER_BEND_CHC_CPP	0xf0d20008
+#define	F367TER_BBAD_CHC_CPP	0xf0d20004
+#define	F367TER_BEND_CHC_SP	0xf0d20002
+#define	F367TER_BBAD_CHC_SP	0xf0d20001
+
+/* TSTBISTRES3 */
+#define	R367TER_TSTBISTRES3	0xf0d3
+#define	F367TER_BEND_QAM	0xf0d30080
+#define	F367TER_BBAD_QAM	0xf0d30040
+#define	F367TER_BEND_SFEC_VIT	0xf0d30020
+#define	F367TER_BBAD_SFEC_VIT	0xf0d30010
+#define	F367TER_BEND_SFEC_DLINE	0xf0d30008
+#define	F367TER_BBAD_SFEC_DLINE	0xf0d30004
+#define	F367TER_BEND_SFEC_HW	0xf0d30002
+#define	F367TER_BBAD_SFEC_HW	0xf0d30001
+
+/* RF_AGC1 */
+#define	R367TER_RF_AGC1	0xf0d4
+#define	F367TER_RF_AGC1_LEVEL_HI	0xf0d400ff
+
+/* RF_AGC2 */
+#define	R367TER_RF_AGC2	0xf0d5
+#define	F367TER_REF_ADGP	0xf0d50080
+#define	F367TER_STDBY_ADCGP	0xf0d50020
+#define	F367TER_CHANNEL_SEL	0xf0d5001c
+#define	F367TER_RF_AGC1_LEVEL_LO	0xf0d50003
+
+/* ANADIGCTRL */
+#define	R367TER_ANADIGCTRL	0xf0d7
+#define	F367TER_SEL_CLKDEM	0xf0d70020
+#define	F367TER_EN_BUFFER_Q	0xf0d70010
+#define	F367TER_EN_BUFFER_I	0xf0d70008
+#define	F367TER_ADC_RIS_EGDE	0xf0d70004
+#define	F367TER_SGN_ADC	0xf0d70002
+#define	F367TER_SEL_AD12_SYNC	0xf0d70001
+
+/* PLLMDIV */
+#define	R367TER_PLLMDIV	0xf0d8
+#define	F367TER_PLL_MDIV	0xf0d800ff
+
+/* PLLNDIV */
+#define	R367TER_PLLNDIV	0xf0d9
+#define	F367TER_PLL_NDIV	0xf0d900ff
+
+/* PLLSETUP */
+#define	R367TER_PLLSETUP	0xf0dA
+#define	F367TER_PLL_PDIV	0xf0da0070
+#define	F367TER_PLL_KDIV	0xf0da000f
+
+/* DUAL_AD12 */
+#define	R367TER_DUAL_AD12	0xf0dB
+#define	F367TER_FS20M	0xf0db0020
+#define	F367TER_FS50M	0xf0db0010
+#define	F367TER_INMODe0	0xf0db0008
+#define	F367TER_POFFQ	0xf0db0004
+#define	F367TER_POFFI	0xf0db0002
+#define	F367TER_INMODE1	0xf0db0001
+
+/* TSTBIST */
+#define	R367TER_TSTBIST	0xf0dC
+#define	F367TER_TST_BYP_CLK	0xf0dc0080
+#define	F367TER_TST_GCLKENA_STD	0xf0dc0040
+#define	F367TER_TST_GCLKENA	0xf0dc0020
+#define	F367TER_TST_MEMBIST	0xf0dc001f
+
+/* PAD_COMP_CTRL */
+#define	R367TER_PAD_COMP_CTRL	0xf0dD
+#define	F367TER_COMPTQ	0xf0dd0010
+#define	F367TER_COMPEN	0xf0dd0008
+#define	F367TER_FREEZE2	0xf0dd0004
+#define	F367TER_SLEEP_INHBT	0xf0dd0002
+#define	F367TER_CHIP_SLEEP	0xf0dd0001
+
+/* PAD_COMP_WR */
+#define	R367TER_PAD_COMP_WR	0xf0de
+#define	F367TER_WR_ASRC	0xf0de007f
+
+/* PAD_COMP_RD */
+#define	R367TER_PAD_COMP_RD	0xf0df
+#define	F367TER_COMPOK	0xf0df0080
+#define	F367TER_RD_ASRC	0xf0df007f
+
+/* SYR_TARGET_FFTADJT_MSB */
+#define	R367TER_SYR_TARGET_FFTADJT_MSB	0xf100
+#define	F367TER_SYR_START	0xf1000080
+#define	F367TER_SYR_TARGET_FFTADJ_HI	0xf100000f
+
+/* SYR_TARGET_FFTADJT_LSB */
+#define	R367TER_SYR_TARGET_FFTADJT_LSB	0xf101
+#define	F367TER_SYR_TARGET_FFTADJ_LO	0xf10100ff
+
+/* SYR_TARGET_CHCADJT_MSB */
+#define	R367TER_SYR_TARGET_CHCADJT_MSB	0xf102
+#define	F367TER_SYR_TARGET_CHCADJ_HI	0xf102000f
+
+/* SYR_TARGET_CHCADJT_LSB */
+#define	R367TER_SYR_TARGET_CHCADJT_LSB	0xf103
+#define	F367TER_SYR_TARGET_CHCADJ_LO	0xf10300ff
+
+/* SYR_FLAG */
+#define	R367TER_SYR_FLAG	0xf104
+#define	F367TER_TRIG_FLG1	0xf1040080
+#define	F367TER_TRIG_FLG0	0xf1040040
+#define	F367TER_FFT_FLG1	0xf1040008
+#define	F367TER_FFT_FLG0	0xf1040004
+#define	F367TER_CHC_FLG1	0xf1040002
+#define	F367TER_CHC_FLG0	0xf1040001
+
+/* CRL_TARGET1 */
+#define	R367TER_CRL_TARGET1	0xf105
+#define	F367TER_CRL_START	0xf1050080
+#define	F367TER_CRL_TARGET_VHI	0xf105000f
+
+/* CRL_TARGET2 */
+#define	R367TER_CRL_TARGET2	0xf106
+#define	F367TER_CRL_TARGET_HI	0xf10600ff
+
+/* CRL_TARGET3 */
+#define	R367TER_CRL_TARGET3	0xf107
+#define	F367TER_CRL_TARGET_LO	0xf10700ff
+
+/* CRL_TARGET4 */
+#define	R367TER_CRL_TARGET4	0xf108
+#define	F367TER_CRL_TARGET_VLO	0xf10800ff
+
+/* CRL_FLAG */
+#define	R367TER_CRL_FLAG	0xf109
+#define	F367TER_CRL_FLAG1	0xf1090002
+#define	F367TER_CRL_FLAG0	0xf1090001
+
+/* TRL_TARGET1 */
+#define	R367TER_TRL_TARGET1	0xf10a
+#define	F367TER_TRL_TARGET_HI	0xf10a00ff
+
+/* TRL_TARGET2 */
+#define	R367TER_TRL_TARGET2	0xf10b
+#define	F367TER_TRL_TARGET_LO	0xf10b00ff
+
+/* TRL_CHC */
+#define	R367TER_TRL_CHC	0xf10c
+#define	F367TER_TRL_START	0xf10c0080
+#define	F367TER_CHC_START	0xf10c0040
+#define	F367TER_TRL_FLAG1	0xf10c0002
+#define	F367TER_TRL_FLAG0	0xf10c0001
+
+/* CHC_SNR_TARG */
+#define	R367TER_CHC_SNR_TARG	0xf10d
+#define	F367TER_CHC_SNR_TARGET	0xf10d00ff
+
+/* TOP_TRACK */
+#define	R367TER_TOP_TRACK	0xf10e
+#define	F367TER_TOP_START	0xf10e0080
+#define	F367TER_FIRST_FLAG	0xf10e0070
+#define	F367TER_TOP_FLAG1	0xf10e0008
+#define	F367TER_TOP_FLAG0	0xf10e0004
+#define	F367TER_CHC_FLAG1	0xf10e0002
+#define	F367TER_CHC_FLAG0	0xf10e0001
+
+/* TRACKER_FREE1 */
+#define	R367TER_TRACKER_FREE1	0xf10f
+#define	F367TER_TRACKER_FREE_1	0xf10f00ff
+
+/* ERROR_CRL1 */
+#define	R367TER_ERROR_CRL1	0xf110
+#define	F367TER_ERROR_CRL_VHI	0xf11000ff
+
+/* ERROR_CRL2 */
+#define	R367TER_ERROR_CRL2	0xf111
+#define	F367TER_ERROR_CRL_HI	0xf11100ff
+
+/* ERROR_CRL3 */
+#define	R367TER_ERROR_CRL3	0xf112
+#define	F367TER_ERROR_CRL_LOI	0xf11200ff
+
+/* ERROR_CRL4 */
+#define	R367TER_ERROR_CRL4	0xf113
+#define	F367TER_ERROR_CRL_VLO	0xf11300ff
+
+/* DEC_NCO1 */
+#define	R367TER_DEC_NCO1	0xf114
+#define	F367TER_DEC_NCO_VHI	0xf11400ff
+
+/* DEC_NCO2 */
+#define	R367TER_DEC_NCO2	0xf115
+#define	F367TER_DEC_NCO_HI	0xf11500ff
+
+/* DEC_NCO3 */
+#define	R367TER_DEC_NCO3	0xf116
+#define	F367TER_DEC_NCO_LO	0xf11600ff
+
+/* SNR */
+#define	R367TER_SNR	0xf117
+#define	F367TER_SNRATIO	0xf11700ff
+
+/* SYR_FFTADJ1 */
+#define	R367TER_SYR_FFTADJ1	0xf118
+#define	F367TER_SYR_FFTADJ_HI	0xf11800ff
+
+/* SYR_FFTADJ2 */
+#define	R367TER_SYR_FFTADJ2	0xf119
+#define	F367TER_SYR_FFTADJ_LO	0xf11900ff
+
+/* SYR_CHCADJ1 */
+#define	R367TER_SYR_CHCADJ1	0xf11a
+#define	F367TER_SYR_CHCADJ_HI	0xf11a00ff
+
+/* SYR_CHCADJ2 */
+#define	R367TER_SYR_CHCADJ2	0xf11b
+#define	F367TER_SYR_CHCADJ_LO	0xf11b00ff
+
+/* SYR_OFF */
+#define	R367TER_SYR_OFF	0xf11c
+#define	F367TER_SYR_OFFSET	0xf11c00ff
+
+/* PPM_OFFSET1 */
+#define	R367TER_PPM_OFFSET1	0xf11d
+#define	F367TER_PPM_OFFSET_HI	0xf11d00ff
+
+/* PPM_OFFSET2 */
+#define	R367TER_PPM_OFFSET2	0xf11e
+#define	F367TER_PPM_OFFSET_LO	0xf11e00ff
+
+/* TRACKER_FREE2 */
+#define	R367TER_TRACKER_FREE2	0xf11f
+#define	F367TER_TRACKER_FREE_2	0xf11f00ff
+
+/* DEBG_LT10 */
+#define	R367TER_DEBG_LT10	0xf120
+#define	F367TER_DEBUG_LT10	0xf12000ff
+
+/* DEBG_LT11 */
+#define	R367TER_DEBG_LT11	0xf121
+#define	F367TER_DEBUG_LT11	0xf12100ff
+
+/* DEBG_LT12 */
+#define	R367TER_DEBG_LT12	0xf122
+#define	F367TER_DEBUG_LT12	0xf12200ff
+
+/* DEBG_LT13 */
+#define	R367TER_DEBG_LT13	0xf123
+#define	F367TER_DEBUG_LT13	0xf12300ff
+
+/* DEBG_LT14 */
+#define	R367TER_DEBG_LT14	0xf124
+#define	F367TER_DEBUG_LT14	0xf12400ff
+
+/* DEBG_LT15 */
+#define	R367TER_DEBG_LT15	0xf125
+#define	F367TER_DEBUG_LT15	0xf12500ff
+
+/* DEBG_LT16 */
+#define	R367TER_DEBG_LT16	0xf126
+#define	F367TER_DEBUG_LT16	0xf12600ff
+
+/* DEBG_LT17 */
+#define	R367TER_DEBG_LT17	0xf127
+#define	F367TER_DEBUG_LT17	0xf12700ff
+
+/* DEBG_LT18 */
+#define	R367TER_DEBG_LT18	0xf128
+#define	F367TER_DEBUG_LT18	0xf12800ff
+
+/* DEBG_LT19 */
+#define	R367TER_DEBG_LT19	0xf129
+#define	F367TER_DEBUG_LT19	0xf12900ff
+
+/* DEBG_LT1a */
+#define	R367TER_DEBG_LT1A	0xf12a
+#define	F367TER_DEBUG_LT1A	0xf12a00ff
+
+/* DEBG_LT1b */
+#define	R367TER_DEBG_LT1B	0xf12b
+#define	F367TER_DEBUG_LT1B	0xf12b00ff
+
+/* DEBG_LT1c */
+#define	R367TER_DEBG_LT1C	0xf12c
+#define	F367TER_DEBUG_LT1C	0xf12c00ff
+
+/* DEBG_LT1D */
+#define	R367TER_DEBG_LT1D	0xf12d
+#define	F367TER_DEBUG_LT1D	0xf12d00ff
+
+/* DEBG_LT1E */
+#define	R367TER_DEBG_LT1E	0xf12e
+#define	F367TER_DEBUG_LT1E	0xf12e00ff
+
+/* DEBG_LT1F */
+#define	R367TER_DEBG_LT1F	0xf12f
+#define	F367TER_DEBUG_LT1F	0xf12f00ff
+
+/* RCCFGH */
+#define	R367TER_RCCFGH	0xf200
+#define	F367TER_TSRCFIFO_DVBCI	0xf2000080
+#define	F367TER_TSRCFIFO_SERIAL	0xf2000040
+#define	F367TER_TSRCFIFO_DISABLE	0xf2000020
+#define	F367TER_TSFIFO_2TORC	0xf2000010
+#define	F367TER_TSRCFIFO_HSGNLOUT	0xf2000008
+#define	F367TER_TSRCFIFO_ERRMODE	0xf2000006
+#define	F367TER_RCCFGH_0	0xf2000001
+
+/* RCCFGM */
+#define	R367TER_RCCFGM	0xf201
+#define	F367TER_TSRCFIFO_MANSPEED	0xf20100c0
+#define	F367TER_TSRCFIFO_PERMDATA	0xf2010020
+#define	F367TER_TSRCFIFO_NONEWSGNL	0xf2010010
+#define	F367TER_RCBYTE_OVERSAMPLING	0xf201000e
+#define	F367TER_TSRCFIFO_INVDATA	0xf2010001
+
+/* RCCFGL */
+#define	R367TER_RCCFGL	0xf202
+#define	F367TER_TSRCFIFO_BCLKDEL1cK	0xf20200c0
+#define	F367TER_RCCFGL_5	0xf2020020
+#define	F367TER_TSRCFIFO_DUTY50	0xf2020010
+#define	F367TER_TSRCFIFO_NSGNL2dATA	0xf2020008
+#define	F367TER_TSRCFIFO_DISSERMUX	0xf2020004
+#define	F367TER_RCCFGL_1	0xf2020002
+#define	F367TER_TSRCFIFO_STOPCKDIS	0xf2020001
+
+/* RCINSDELH */
+#define	R367TER_RCINSDELH	0xf203
+#define	F367TER_TSRCDEL_SYNCBYTE	0xf2030080
+#define	F367TER_TSRCDEL_XXHEADER	0xf2030040
+#define	F367TER_TSRCDEL_BBHEADER	0xf2030020
+#define	F367TER_TSRCDEL_DATAFIELD	0xf2030010
+#define	F367TER_TSRCINSDEL_ISCR	0xf2030008
+#define	F367TER_TSRCINSDEL_NPD	0xf2030004
+#define	F367TER_TSRCINSDEL_RSPARITY	0xf2030002
+#define	F367TER_TSRCINSDEL_CRC8	0xf2030001
+
+/* RCINSDELM */
+#define	R367TER_RCINSDELM	0xf204
+#define	F367TER_TSRCINS_BBPADDING	0xf2040080
+#define	F367TER_TSRCINS_BCHFEC	0xf2040040
+#define	F367TER_TSRCINS_LDPCFEC	0xf2040020
+#define	F367TER_TSRCINS_EMODCOD	0xf2040010
+#define	F367TER_TSRCINS_TOKEN	0xf2040008
+#define	F367TER_TSRCINS_XXXERR	0xf2040004
+#define	F367TER_TSRCINS_MATYPE	0xf2040002
+#define	F367TER_TSRCINS_UPL	0xf2040001
+
+/* RCINSDELL */
+#define	R367TER_RCINSDELL	0xf205
+#define	F367TER_TSRCINS_DFL	0xf2050080
+#define	F367TER_TSRCINS_SYNCD	0xf2050040
+#define	F367TER_TSRCINS_BLOCLEN	0xf2050020
+#define	F367TER_TSRCINS_SIGPCOUNT	0xf2050010
+#define	F367TER_TSRCINS_FIFO	0xf2050008
+#define	F367TER_TSRCINS_REALPACK	0xf2050004
+#define	F367TER_TSRCINS_TSCONFIG	0xf2050002
+#define	F367TER_TSRCINS_LATENCY	0xf2050001
+
+/* RCSTATUS */
+#define	R367TER_RCSTATUS	0xf206
+#define	F367TER_TSRCFIFO_LINEOK	0xf2060080
+#define	F367TER_TSRCFIFO_ERROR	0xf2060040
+#define	F367TER_TSRCFIFO_DATA7	0xf2060020
+#define	F367TER_RCSTATUS_4	0xf2060010
+#define	F367TER_TSRCFIFO_DEMODSEL	0xf2060008
+#define	F367TER_TSRC1FIFOSPEED_STORE	0xf2060004
+#define	F367TER_RCSTATUS_1	0xf2060002
+#define	F367TER_TSRCSERIAL_IMPOSSIBLE	0xf2060001
+
+/* RCSPEED */
+#define	R367TER_RCSPEED	0xf207
+#define	F367TER_TSRCFIFO_OUTSPEED	0xf20700ff
+
+/* RCDEBUGM */
+#define	R367TER_RCDEBUGM	0xf208
+#define	F367TER_SD_UNSYNC	0xf2080080
+#define	F367TER_ULFLOCK_DETECTM	0xf2080040
+#define	F367TER_SUL_SELECTOS	0xf2080020
+#define	F367TER_DILUL_NOSCRBLE	0xf2080010
+#define	F367TER_NUL_SCRB	0xf2080008
+#define	F367TER_UL_SCRB	0xf2080004
+#define	F367TER_SCRAULBAD	0xf2080002
+#define	F367TER_SCRAUL_UNSYNC	0xf2080001
+
+/* RCDEBUGL */
+#define	R367TER_RCDEBUGL	0xf209
+#define	F367TER_RS_ERR	0xf2090080
+#define	F367TER_LLFLOCK_DETECTM	0xf2090040
+#define	F367TER_NOT_SUL_SELECTOS	0xf2090020
+#define	F367TER_DILLL_NOSCRBLE	0xf2090010
+#define	F367TER_NLL_SCRB	0xf2090008
+#define	F367TER_LL_SCRB	0xf2090004
+#define	F367TER_SCRALLBAD	0xf2090002
+#define	F367TER_SCRALL_UNSYNC	0xf2090001
+
+/* RCOBSCFG */
+#define	R367TER_RCOBSCFG	0xf20a
+#define	F367TER_TSRCFIFO_OBSCFG	0xf20a00ff
+
+/* RCOBSM */
+#define	R367TER_RCOBSM	0xf20b
+#define	F367TER_TSRCFIFO_OBSDATA_HI	0xf20b00ff
+
+/* RCOBSL */
+#define	R367TER_RCOBSL	0xf20c
+#define	F367TER_TSRCFIFO_OBSDATA_LO	0xf20c00ff
+
+/* RCFECSPY */
+#define	R367TER_RCFECSPY	0xf210
+#define	F367TER_SPYRC_ENABLE	0xf2100080
+#define	F367TER_RCNO_SYNCBYTE	0xf2100040
+#define	F367TER_RCSERIAL_MODE	0xf2100020
+#define	F367TER_RCUNUSUAL_PACKET	0xf2100010
+#define	F367TER_BERRCMETER_DATAMODE	0xf210000c
+#define	F367TER_BERRCMETER_LMODE	0xf2100002
+#define	F367TER_BERRCMETER_RESET	0xf2100001
+
+/* RCFSPYCFG */
+#define	R367TER_RCFSPYCFG	0xf211
+#define	F367TER_FECSPYRC_INPUT	0xf21100c0
+#define	F367TER_RCRST_ON_ERROR	0xf2110020
+#define	F367TER_RCONE_SHOT	0xf2110010
+#define	F367TER_RCI2C_MODE	0xf211000c
+#define	F367TER_SPYRC_HSTERESIS	0xf2110003
+
+/* RCFSPYDATA */
+#define	R367TER_RCFSPYDATA	0xf212
+#define	F367TER_SPYRC_STUFFING	0xf2120080
+#define	F367TER_RCNOERR_PKTJITTER	0xf2120040
+#define	F367TER_SPYRC_CNULLPKT	0xf2120020
+#define	F367TER_SPYRC_OUTDATA_MODE	0xf212001f
+
+/* RCFSPYOUT */
+#define	R367TER_RCFSPYOUT	0xf213
+#define	F367TER_FSPYRC_DIRECT	0xf2130080
+#define	F367TER_RCFSPYOUT_6	0xf2130040
+#define	F367TER_SPYRC_OUTDATA_BUS	0xf2130038
+#define	F367TER_RCSTUFF_MODE	0xf2130007
+
+/* RCFSTATUS */
+#define	R367TER_RCFSTATUS	0xf214
+#define	F367TER_SPYRC_ENDSIM	0xf2140080
+#define	F367TER_RCVALID_SIM	0xf2140040
+#define	F367TER_RCFOUND_SIGNAL	0xf2140020
+#define	F367TER_RCDSS_SYNCBYTE	0xf2140010
+#define	F367TER_RCRESULT_STATE	0xf214000f
+
+/* RCFGOODPACK */
+#define	R367TER_RCFGOODPACK	0xf215
+#define	F367TER_RCGOOD_PACKET	0xf21500ff
+
+/* RCFPACKCNT */
+#define	R367TER_RCFPACKCNT	0xf216
+#define	F367TER_RCPACKET_COUNTER	0xf21600ff
+
+/* RCFSPYMISC */
+#define	R367TER_RCFSPYMISC	0xf217
+#define	F367TER_RCLABEL_COUNTER	0xf21700ff
+
+/* RCFBERCPT4 */
+#define	R367TER_RCFBERCPT4	0xf218
+#define	F367TER_FBERRCMETER_CPT_MMMMSB	0xf21800ff
+
+/* RCFBERCPT3 */
+#define	R367TER_RCFBERCPT3	0xf219
+#define	F367TER_FBERRCMETER_CPT_MMMSB	0xf21900ff
+
+/* RCFBERCPT2 */
+#define	R367TER_RCFBERCPT2	0xf21a
+#define	F367TER_FBERRCMETER_CPT_MMSB	0xf21a00ff
+
+/* RCFBERCPT1 */
+#define	R367TER_RCFBERCPT1	0xf21b
+#define	F367TER_FBERRCMETER_CPT_MSB	0xf21b00ff
+
+/* RCFBERCPT0 */
+#define	R367TER_RCFBERCPT0	0xf21c
+#define	F367TER_FBERRCMETER_CPT_LSB	0xf21c00ff
+
+/* RCFBERERR2 */
+#define	R367TER_RCFBERERR2	0xf21d
+#define	F367TER_FBERRCMETER_ERR_HI	0xf21d00ff
+
+/* RCFBERERR1 */
+#define	R367TER_RCFBERERR1	0xf21e
+#define	F367TER_FBERRCMETER_ERR	0xf21e00ff
+
+/* RCFBERERR0 */
+#define	R367TER_RCFBERERR0	0xf21f
+#define	F367TER_FBERRCMETER_ERR_LO	0xf21f00ff
+
+/* RCFSTATESM */
+#define	R367TER_RCFSTATESM	0xf220
+#define	F367TER_RCRSTATE_F	0xf2200080
+#define	F367TER_RCRSTATE_E	0xf2200040
+#define	F367TER_RCRSTATE_D	0xf2200020
+#define	F367TER_RCRSTATE_C	0xf2200010
+#define	F367TER_RCRSTATE_B	0xf2200008
+#define	F367TER_RCRSTATE_A	0xf2200004
+#define	F367TER_RCRSTATE_9	0xf2200002
+#define	F367TER_RCRSTATE_8	0xf2200001
+
+/* RCFSTATESL */
+#define	R367TER_RCFSTATESL	0xf221
+#define	F367TER_RCRSTATE_7	0xf2210080
+#define	F367TER_RCRSTATE_6	0xf2210040
+#define	F367TER_RCRSTATE_5	0xf2210020
+#define	F367TER_RCRSTATE_4	0xf2210010
+#define	F367TER_RCRSTATE_3	0xf2210008
+#define	F367TER_RCRSTATE_2	0xf2210004
+#define	F367TER_RCRSTATE_1	0xf2210002
+#define	F367TER_RCRSTATE_0	0xf2210001
+
+/* RCFSPYBER */
+#define	R367TER_RCFSPYBER	0xf222
+#define	F367TER_RCFSPYBER_7	0xf2220080
+#define	F367TER_SPYRCOBS_XORREAD	0xf2220040
+#define	F367TER_FSPYRCBER_OBSMODE	0xf2220020
+#define	F367TER_FSPYRCBER_SYNCBYT	0xf2220010
+#define	F367TER_FSPYRCBER_UNSYNC	0xf2220008
+#define	F367TER_FSPYRCBER_CTIME	0xf2220007
+
+/* RCFSPYDISTM */
+#define	R367TER_RCFSPYDISTM	0xf223
+#define	F367TER_RCPKTTIME_DISTANCE_HI	0xf22300ff
+
+/* RCFSPYDISTL */
+#define	R367TER_RCFSPYDISTL	0xf224
+#define	F367TER_RCPKTTIME_DISTANCE_LO	0xf22400ff
+
+/* RCFSPYOBS7 */
+#define	R367TER_RCFSPYOBS7	0xf228
+#define	F367TER_RCSPYOBS_SPYFAIL	0xf2280080
+#define	F367TER_RCSPYOBS_SPYFAIL1	0xf2280040
+#define	F367TER_RCSPYOBS_ERROR	0xf2280020
+#define	F367TER_RCSPYOBS_STROUT	0xf2280010
+#define	F367TER_RCSPYOBS_RESULTSTATE1	0xf228000f
+
+/* RCFSPYOBS6 */
+#define	R367TER_RCFSPYOBS6	0xf229
+#define	F367TER_RCSPYOBS_RESULTSTATe0	0xf22900f0
+#define	F367TER_RCSPYOBS_RESULTSTATEM1	0xf229000f
+
+/* RCFSPYOBS5 */
+#define	R367TER_RCFSPYOBS5	0xf22a
+#define	F367TER_RCSPYOBS_BYTEOFPACKET1	0xf22a00ff
+
+/* RCFSPYOBS4 */
+#define	R367TER_RCFSPYOBS4	0xf22b
+#define	F367TER_RCSPYOBS_BYTEVALUE1	0xf22b00ff
+
+/* RCFSPYOBS3 */
+#define	R367TER_RCFSPYOBS3	0xf22c
+#define	F367TER_RCSPYOBS_DATA1	0xf22c00ff
+
+/* RCFSPYOBS2 */
+#define	R367TER_RCFSPYOBS2	0xf22d
+#define	F367TER_RCSPYOBS_DATa0	0xf22d00ff
+
+/* RCFSPYOBS1 */
+#define	R367TER_RCFSPYOBS1	0xf22e
+#define	F367TER_RCSPYOBS_DATAM1	0xf22e00ff
+
+/* RCFSPYOBS0 */
+#define	R367TER_RCFSPYOBS0	0xf22f
+#define	F367TER_RCSPYOBS_DATAM2	0xf22f00ff
+
+/* TSGENERAL */
+#define	R367TER_TSGENERAL	0xf230
+#define	F367TER_TSGENERAL_7	0xf2300080
+#define	F367TER_TSGENERAL_6	0xf2300040
+#define	F367TER_TSFIFO_BCLK1aLL	0xf2300020
+#define	F367TER_TSGENERAL_4	0xf2300010
+#define	F367TER_MUXSTREAM_OUTMODE	0xf2300008
+#define	F367TER_TSFIFO_PERMPARAL	0xf2300006
+#define	F367TER_RST_REEDSOLO	0xf2300001
+
+/* RC1SPEED */
+#define	R367TER_RC1SPEED	0xf231
+#define	F367TER_TSRCFIFO1_OUTSPEED	0xf23100ff
+
+/* TSGSTATUS */
+#define	R367TER_TSGSTATUS	0xf232
+#define	F367TER_TSGSTATUS_7	0xf2320080
+#define	F367TER_TSGSTATUS_6	0xf2320040
+#define	F367TER_RSMEM_FULL	0xf2320020
+#define	F367TER_RS_MULTCALC	0xf2320010
+#define	F367TER_RSIN_OVERTIME	0xf2320008
+#define	F367TER_TSFIFO3_DEMODSEL	0xf2320004
+#define	F367TER_TSFIFO2_DEMODSEL	0xf2320002
+#define	F367TER_TSFIFO1_DEMODSEL	0xf2320001
+
+
+/* FECM */
+#define	R367TER_FECM	0xf233
+#define	F367TER_DSS_DVB	0xf2330080
+#define	F367TER_DEMOD_BYPASS	0xf2330040
+#define	F367TER_CMP_SLOWMODE	0xf2330020
+#define	F367TER_DSS_SRCH	0xf2330010
+#define	F367TER_FECM_3	0xf2330008
+#define	F367TER_DIFF_MODEVIT	0xf2330004
+#define	F367TER_SYNCVIT	0xf2330002
+#define	F367TER_I2CSYM	0xf2330001
+
+/* VTH12 */
+#define	R367TER_VTH12	0xf234
+#define	F367TER_VTH_12	0xf23400ff
+
+/* VTH23 */
+#define	R367TER_VTH23	0xf235
+#define	F367TER_VTH_23	0xf23500ff
+
+/* VTH34 */
+#define	R367TER_VTH34	0xf236
+#define	F367TER_VTH_34	0xf23600ff
+
+/* VTH56 */
+#define	R367TER_VTH56	0xf237
+#define	F367TER_VTH_56	0xf23700ff
+
+/* VTH67 */
+#define	R367TER_VTH67	0xf238
+#define	F367TER_VTH_67	0xf23800ff
+
+/* VTH78 */
+#define	R367TER_VTH78	0xf239
+#define	F367TER_VTH_78	0xf23900ff
+
+/* VITCURPUN */
+#define	R367TER_VITCURPUN	0xf23a
+#define	F367TER_VIT_MAPPING	0xf23a00e0
+#define	F367TER_VIT_CURPUN	0xf23a001f
+
+/* VERROR */
+#define	R367TER_VERROR	0xf23b
+#define	F367TER_REGERR_VIT	0xf23b00ff
+
+/* PRVIT */
+#define	R367TER_PRVIT	0xf23c
+#define	F367TER_PRVIT_7	0xf23c0080
+#define	F367TER_DIS_VTHLOCK	0xf23c0040
+#define	F367TER_E7_8VIT	0xf23c0020
+#define	F367TER_E6_7VIT	0xf23c0010
+#define	F367TER_E5_6VIT	0xf23c0008
+#define	F367TER_E3_4VIT	0xf23c0004
+#define	F367TER_E2_3VIT	0xf23c0002
+#define	F367TER_E1_2VIT	0xf23c0001
+
+/* VAVSRVIT */
+#define	R367TER_VAVSRVIT	0xf23d
+#define	F367TER_AMVIT	0xf23d0080
+#define	F367TER_FROZENVIT	0xf23d0040
+#define	F367TER_SNVIT	0xf23d0030
+#define	F367TER_TOVVIT	0xf23d000c
+#define	F367TER_HYPVIT	0xf23d0003
+
+/* VSTATUSVIT */
+#define	R367TER_VSTATUSVIT	0xf23e
+#define	F367TER_VITERBI_ON	0xf23e0080
+#define	F367TER_END_LOOPVIT	0xf23e0040
+#define	F367TER_VITERBI_DEPRF	0xf23e0020
+#define	F367TER_PRFVIT	0xf23e0010
+#define	F367TER_LOCKEDVIT	0xf23e0008
+#define	F367TER_VITERBI_DELOCK	0xf23e0004
+#define	F367TER_VIT_DEMODSEL	0xf23e0002
+#define	F367TER_VITERBI_COMPOUT	0xf23e0001
+
+/* VTHINUSE */
+#define	R367TER_VTHINUSE	0xf23f
+#define	F367TER_VIT_INUSE	0xf23f00ff
+
+/* KDIV12 */
+#define	R367TER_KDIV12	0xf240
+#define	F367TER_KDIV12_MANUAL	0xf2400080
+#define	F367TER_K_DIVIDER_12	0xf240007f
+
+/* KDIV23 */
+#define	R367TER_KDIV23	0xf241
+#define	F367TER_KDIV23_MANUAL	0xf2410080
+#define	F367TER_K_DIVIDER_23	0xf241007f
+
+/* KDIV34 */
+#define	R367TER_KDIV34	0xf242
+#define	F367TER_KDIV34_MANUAL	0xf2420080
+#define	F367TER_K_DIVIDER_34	0xf242007f
+
+/* KDIV56 */
+#define	R367TER_KDIV56	0xf243
+#define	F367TER_KDIV56_MANUAL	0xf2430080
+#define	F367TER_K_DIVIDER_56	0xf243007f
+
+/* KDIV67 */
+#define	R367TER_KDIV67	0xf244
+#define	F367TER_KDIV67_MANUAL	0xf2440080
+#define	F367TER_K_DIVIDER_67	0xf244007f
+
+/* KDIV78 */
+#define	R367TER_KDIV78	0xf245
+#define	F367TER_KDIV78_MANUAL	0xf2450080
+#define	F367TER_K_DIVIDER_78	0xf245007f
+
+/* SIGPOWER */
+#define	R367TER_SIGPOWER	0xf246
+#define	F367TER_SIGPOWER_MANUAL	0xf2460080
+#define	F367TER_SIG_POWER	0xf246007f
+
+/* DEMAPVIT */
+#define	R367TER_DEMAPVIT	0xf247
+#define	F367TER_DEMAPVIT_7	0xf2470080
+#define	F367TER_K_DIVIDER_VIT	0xf247007f
+
+/* VITSCALE */
+#define	R367TER_VITSCALE	0xf248
+#define	F367TER_NVTH_NOSRANGE	0xf2480080
+#define	F367TER_VERROR_MAXMODE	0xf2480040
+#define	F367TER_KDIV_MODE	0xf2480030
+#define	F367TER_NSLOWSN_LOCKED	0xf2480008
+#define	F367TER_DELOCK_PRFLOSS	0xf2480004
+#define	F367TER_DIS_RSFLOCK	0xf2480002
+#define	F367TER_VITSCALE_0	0xf2480001
+
+/* FFEC1PRG */
+#define	R367TER_FFEC1PRG	0xf249
+#define	F367TER_FDSS_DVB	0xf2490080
+#define	F367TER_FDSS_SRCH	0xf2490040
+#define	F367TER_FFECPROG_5	0xf2490020
+#define	F367TER_FFECPROG_4	0xf2490010
+#define	F367TER_FFECPROG_3	0xf2490008
+#define	F367TER_FFECPROG_2	0xf2490004
+#define	F367TER_FTS1_DISABLE	0xf2490002
+#define	F367TER_FTS2_DISABLE	0xf2490001
+
+/* FVITCURPUN */
+#define	R367TER_FVITCURPUN	0xf24a
+#define	F367TER_FVIT_MAPPING	0xf24a00e0
+#define	F367TER_FVIT_CURPUN	0xf24a001f
+
+/* FVERROR */
+#define	R367TER_FVERROR	0xf24b
+#define	F367TER_FREGERR_VIT	0xf24b00ff
+
+/* FVSTATUSVIT */
+#define	R367TER_FVSTATUSVIT	0xf24c
+#define	F367TER_FVITERBI_ON	0xf24c0080
+#define	F367TER_F1END_LOOPVIT	0xf24c0040
+#define	F367TER_FVITERBI_DEPRF	0xf24c0020
+#define	F367TER_FPRFVIT	0xf24c0010
+#define	F367TER_FLOCKEDVIT	0xf24c0008
+#define	F367TER_FVITERBI_DELOCK	0xf24c0004
+#define	F367TER_FVIT_DEMODSEL	0xf24c0002
+#define	F367TER_FVITERBI_COMPOUT	0xf24c0001
+
+/* DEBUG_LT1 */
+#define	R367TER_DEBUG_LT1	0xf24d
+#define	F367TER_DBG_LT1	0xf24d00ff
+
+/* DEBUG_LT2 */
+#define	R367TER_DEBUG_LT2	0xf24e
+#define	F367TER_DBG_LT2	0xf24e00ff
+
+/* DEBUG_LT3 */
+#define	R367TER_DEBUG_LT3	0xf24f
+#define	F367TER_DBG_LT3	0xf24f00ff
+
+/*	TSTSFMET */
+#define	R367TER_TSTSFMET	0xf250
+#define F367TER_TSTSFEC_METRIQUES	0xf25000ff
+
+/*	SELOUT */
+#define	R367TER_SELOUT	0xf252
+#define	F367TER_EN_SYNC	0xf2520080
+#define	F367TER_EN_TBUSDEMAP	0xf2520040
+#define	F367TER_SELOUT_5	0xf2520020
+#define	F367TER_SELOUT_4	0xf2520010
+#define	F367TER_TSTSYNCHRO_MODE	0xf2520002
+
+/*	TSYNC */
+#define R367TER_TSYNC	0xf253
+#define F367TER_CURPUN_INCMODE	0xf2530080
+#define F367TER_CERR_TSTMODE	0xf2530040
+#define F367TER_SHIFTSOF_MODE	0xf2530030
+#define F367TER_SLOWPHA_MODE	0xf2530008
+#define F367TER_PXX_BYPALL	0xf2530004
+#define F367TER_FROTA45_FIRST	0xf2530002
+#define F367TER_TST_BCHERROR	0xf2530001
+
+/*	TSTERR */
+#define R367TER_TSTERR	0xf254
+#define F367TER_TST_LONGPKT	0xf2540080
+#define F367TER_TST_ISSYION	0xf2540040
+#define F367TER_TST_NPDON	0xf2540020
+#define F367TER_TSTERR_4	0xf2540010
+#define F367TER_TRACEBACK_MODE	0xf2540008
+#define F367TER_TST_RSPARITY	0xf2540004
+#define F367TER_METRIQUE_MODE	0xf2540003
+
+/*	TSFSYNC */
+#define R367TER_TSFSYNC	0xf255
+#define F367TER_EN_SFECSYNC	0xf2550080
+#define F367TER_EN_SFECDEMAP	0xf2550040
+#define F367TER_SFCERR_TSTMODE	0xf2550020
+#define F367TER_SFECPXX_BYPALL	0xf2550010
+#define F367TER_SFECTSTSYNCHRO_MODE 0xf255000f
+
+/*	TSTSFERR */
+#define R367TER_TSTSFERR	0xf256
+#define F367TER_TSTSTERR_7	0xf2560080
+#define F367TER_TSTSTERR_6	0xf2560040
+#define F367TER_TSTSTERR_5	0xf2560020
+#define F367TER_TSTSTERR_4	0xf2560010
+#define F367TER_SFECTRACEBACK_MODE	0xf2560008
+#define F367TER_SFEC_NCONVPROG	0xf2560004
+#define F367TER_SFECMETRIQUE_MODE	0xf2560003
+
+/*	TSTTSSF1 */
+#define R367TER_TSTTSSF1	0xf258
+#define F367TER_TSTERSSF	0xf2580080
+#define F367TER_TSTTSSFEN	0xf2580040
+#define F367TER_SFEC_OUTMODE	0xf2580030
+#define F367TER_XLSF_NOFTHRESHOLD  0xf2580008
+#define F367TER_TSTTSSF_STACKSEL	0xf2580007
+
+/*	TSTTSSF2 */
+#define R367TER_TSTTSSF2	0xf259
+#define F367TER_DILSF_DBBHEADER	0xf2590080
+#define F367TER_TSTTSSF_DISBUG	0xf2590040
+#define F367TER_TSTTSSF_NOBADSTART	0xf2590020
+#define F367TER_TSTTSSF_SELECT	0xf259001f
+
+/*	TSTTSSF3 */
+#define R367TER_TSTTSSF3	0xf25a
+#define F367TER_TSTTSSF3_7	0xf25a0080
+#define F367TER_TSTTSSF3_6	0xf25a0040
+#define F367TER_TSTTSSF3_5	0xf25a0020
+#define F367TER_TSTTSSF3_4	0xf25a0010
+#define F367TER_TSTTSSF3_3	0xf25a0008
+#define F367TER_TSTTSSF3_2	0xf25a0004
+#define F367TER_TSTTSSF3_1	0xf25a0002
+#define F367TER_DISSF_CLKENABLE	0xf25a0001
+
+/*	TSTTS1 */
+#define R367TER_TSTTS1	0xf25c
+#define F367TER_TSTERS	0xf25c0080
+#define F367TER_TSFIFO_DSSSYNCB	0xf25c0040
+#define F367TER_TSTTS_FSPYBEFRS	0xf25c0020
+#define F367TER_NFORCE_SYNCBYTE	0xf25c0010
+#define F367TER_XL_NOFTHRESHOLD	0xf25c0008
+#define F367TER_TSTTS_FRFORCEPKT	0xf25c0004
+#define F367TER_DESCR_NOTAUTO	0xf25c0002
+#define F367TER_TSTTSEN	0xf25c0001
+
+/*	TSTTS2 */
+#define R367TER_TSTTS2	0xf25d
+#define F367TER_DIL_DBBHEADER	0xf25d0080
+#define F367TER_TSTTS_NOBADXXX	0xf25d0040
+#define F367TER_TSFIFO_DELSPEEDUP	0xf25d0020
+#define F367TER_TSTTS_SELECT	0xf25d001f
+
+/*	TSTTS3 */
+#define R367TER_TSTTS3	0xf25e
+#define F367TER_TSTTS_NOPKTGAIN	0xf25e0080
+#define F367TER_TSTTS_NOPKTENE	0xf25e0040
+#define F367TER_TSTTS_ISOLATION	0xf25e0020
+#define F367TER_TSTTS_DISBUG	0xf25e0010
+#define F367TER_TSTTS_NOBADSTART	0xf25e0008
+#define F367TER_TSTTS_STACKSEL	0xf25e0007
+
+/*	TSTTS4 */
+#define R367TER_TSTTS4	0xf25f
+#define F367TER_TSTTS4_7	0xf25f0080
+#define F367TER_TSTTS4_6	0xf25f0040
+#define F367TER_TSTTS4_5	0xf25f0020
+#define F367TER_TSTTS_DISDSTATE	0xf25f0010
+#define F367TER_TSTTS_FASTNOSYNC	0xf25f0008
+#define F367TER_EXT_FECSPYIN	0xf25f0004
+#define F367TER_TSTTS_NODPZERO	0xf25f0002
+#define F367TER_TSTTS_NODIV3	0xf25f0001
+
+/*	TSTTSRC */
+#define R367TER_TSTTSRC	0xf26c
+#define F367TER_TSTTSRC_7	0xf26c0080
+#define F367TER_TSRCFIFO_DSSSYNCB	0xf26c0040
+#define F367TER_TSRCFIFO_DPUNACTIVE	0xf26c0020
+#define F367TER_TSRCFIFO_DELSPEEDUP	0xf26c0010
+#define F367TER_TSTTSRC_NODIV3	0xf26c0008
+#define F367TER_TSTTSRC_FRFORCEPKT	0xf26c0004
+#define F367TER_SAT25_SDDORIGINE	0xf26c0002
+#define F367TER_TSTTSRC_INACTIVE	0xf26c0001
+
+/*	TSTTSRS */
+#define R367TER_TSTTSRS	0xf26d
+#define F367TER_TSTTSRS_7	0xf26d0080
+#define F367TER_TSTTSRS_6	0xf26d0040
+#define F367TER_TSTTSRS_5	0xf26d0020
+#define F367TER_TSTTSRS_4	0xf26d0010
+#define F367TER_TSTTSRS_3	0xf26d0008
+#define F367TER_TSTTSRS_2	0xf26d0004
+#define F367TER_TSTRS_DISRS2	0xf26d0002
+#define F367TER_TSTRS_DISRS1	0xf26d0001
+
+/* TSSTATEM */
+#define	R367TER_TSSTATEM	0xf270
+#define	F367TER_TSDIL_ON	0xf2700080
+#define	F367TER_TSSKIPRS_ON	0xf2700040
+#define	F367TER_TSRS_ON	0xf2700020
+#define	F367TER_TSDESCRAMB_ON	0xf2700010
+#define	F367TER_TSFRAME_MODE	0xf2700008
+#define	F367TER_TS_DISABLE	0xf2700004
+#define	F367TER_TSACM_MODE	0xf2700002
+#define	F367TER_TSOUT_NOSYNC	0xf2700001
+
+/* TSSTATEL */
+#define	R367TER_TSSTATEL	0xf271
+#define	F367TER_TSNOSYNCBYTE	0xf2710080
+#define	F367TER_TSPARITY_ON	0xf2710040
+#define	F367TER_TSSYNCOUTRS_ON	0xf2710020
+#define	F367TER_TSDVBS2_MODE	0xf2710010
+#define	F367TER_TSISSYI_ON	0xf2710008
+#define	F367TER_TSNPD_ON	0xf2710004
+#define	F367TER_TSCRC8_ON	0xf2710002
+#define	F367TER_TSDSS_PACKET	0xf2710001
+
+/* TSCFGH */
+#define	R367TER_TSCFGH	0xf272
+#define	F367TER_TSFIFO_DVBCI	0xf2720080
+#define	F367TER_TSFIFO_SERIAL	0xf2720040
+#define	F367TER_TSFIFO_TEIUPDATE	0xf2720020
+#define	F367TER_TSFIFO_DUTY50	0xf2720010
+#define	F367TER_TSFIFO_HSGNLOUT	0xf2720008
+#define	F367TER_TSFIFO_ERRMODE	0xf2720006
+#define	F367TER_RST_HWARE	0xf2720001
+
+/* TSCFGM */
+#define	R367TER_TSCFGM	0xf273
+#define	F367TER_TSFIFO_MANSPEED	0xf27300c0
+#define	F367TER_TSFIFO_PERMDATA	0xf2730020
+#define	F367TER_TSFIFO_NONEWSGNL	0xf2730010
+#define	F367TER_TSFIFO_BITSPEED	0xf2730008
+#define	F367TER_NPD_SPECDVBS2	0xf2730004
+#define	F367TER_TSFIFO_STOPCKDIS	0xf2730002
+#define	F367TER_TSFIFO_INVDATA	0xf2730001
+
+/* TSCFGL */
+#define	R367TER_TSCFGL	0xf274
+#define	F367TER_TSFIFO_BCLKDEL1cK	0xf27400c0
+#define	F367TER_BCHERROR_MODE	0xf2740030
+#define	F367TER_TSFIFO_NSGNL2dATA	0xf2740008
+#define	F367TER_TSFIFO_EMBINDVB	0xf2740004
+#define	F367TER_TSFIFO_DPUNACT	0xf2740002
+#define	F367TER_TSFIFO_NPDOFF	0xf2740001
+
+/* TSSYNC */
+#define	R367TER_TSSYNC	0xf275
+#define	F367TER_TSFIFO_PERMUTE	0xf2750080
+#define	F367TER_TSFIFO_FISCR3B	0xf2750060
+#define	F367TER_TSFIFO_SYNCMODE	0xf2750018
+#define	F367TER_TSFIFO_SYNCSEL	0xf2750007
+
+/* TSINSDELH */
+#define	R367TER_TSINSDELH	0xf276
+#define	F367TER_TSDEL_SYNCBYTE	0xf2760080
+#define	F367TER_TSDEL_XXHEADER	0xf2760040
+#define	F367TER_TSDEL_BBHEADER	0xf2760020
+#define	F367TER_TSDEL_DATAFIELD	0xf2760010
+#define	F367TER_TSINSDEL_ISCR	0xf2760008
+#define	F367TER_TSINSDEL_NPD	0xf2760004
+#define	F367TER_TSINSDEL_RSPARITY	0xf2760002
+#define	F367TER_TSINSDEL_CRC8	0xf2760001
+
+/* TSINSDELM */
+#define	R367TER_TSINSDELM	0xf277
+#define	F367TER_TSINS_BBPADDING	0xf2770080
+#define	F367TER_TSINS_BCHFEC	0xf2770040
+#define	F367TER_TSINS_LDPCFEC	0xf2770020
+#define	F367TER_TSINS_EMODCOD	0xf2770010
+#define	F367TER_TSINS_TOKEN	0xf2770008
+#define	F367TER_TSINS_XXXERR	0xf2770004
+#define	F367TER_TSINS_MATYPE	0xf2770002
+#define	F367TER_TSINS_UPL	0xf2770001
+
+/* TSINSDELL */
+#define	R367TER_TSINSDELL	0xf278
+#define	F367TER_TSINS_DFL	0xf2780080
+#define	F367TER_TSINS_SYNCD	0xf2780040
+#define	F367TER_TSINS_BLOCLEN	0xf2780020
+#define	F367TER_TSINS_SIGPCOUNT	0xf2780010
+#define	F367TER_TSINS_FIFO	0xf2780008
+#define	F367TER_TSINS_REALPACK	0xf2780004
+#define	F367TER_TSINS_TSCONFIG	0xf2780002
+#define	F367TER_TSINS_LATENCY	0xf2780001
+
+/* TSDIVN */
+#define	R367TER_TSDIVN	0xf279
+#define	F367TER_TSFIFO_LOWSPEED	0xf2790080
+#define	F367TER_BYTE_OVERSAMPLING	0xf2790070
+#define	F367TER_TSMANUAL_PACKETNBR	0xf279000f
+
+/* TSDIVPM */
+#define	R367TER_TSDIVPM	0xf27a
+#define	F367TER_TSMANUAL_P_HI	0xf27a00ff
+
+/* TSDIVPL */
+#define	R367TER_TSDIVPL	0xf27b
+#define	F367TER_TSMANUAL_P_LO	0xf27b00ff
+
+/* TSDIVQM */
+#define	R367TER_TSDIVQM	0xf27c
+#define	F367TER_TSMANUAL_Q_HI	0xf27c00ff
+
+/* TSDIVQL */
+#define	R367TER_TSDIVQL	0xf27d
+#define	F367TER_TSMANUAL_Q_LO	0xf27d00ff
+
+/* TSDILSTKM */
+#define	R367TER_TSDILSTKM	0xf27e
+#define	F367TER_TSFIFO_DILSTK_HI	0xf27e00ff
+
+/* TSDILSTKL */
+#define	R367TER_TSDILSTKL	0xf27f
+#define	F367TER_TSFIFO_DILSTK_LO	0xf27f00ff
+
+/* TSSPEED */
+#define	R367TER_TSSPEED	0xf280
+#define	F367TER_TSFIFO_OUTSPEED	0xf28000ff
+
+/* TSSTATUS */
+#define	R367TER_TSSTATUS	0xf281
+#define	F367TER_TSFIFO_LINEOK	0xf2810080
+#define	F367TER_TSFIFO_ERROR	0xf2810040
+#define	F367TER_TSFIFO_DATA7	0xf2810020
+#define	F367TER_TSFIFO_NOSYNC	0xf2810010
+#define	F367TER_ISCR_INITIALIZED	0xf2810008
+#define	F367TER_ISCR_UPDATED	0xf2810004
+#define	F367TER_SOFFIFO_UNREGUL	0xf2810002
+#define	F367TER_DIL_READY	0xf2810001
+
+/* TSSTATUS2 */
+#define	R367TER_TSSTATUS2	0xf282
+#define	F367TER_TSFIFO_DEMODSEL	0xf2820080
+#define	F367TER_TSFIFOSPEED_STORE	0xf2820040
+#define	F367TER_DILXX_RESET	0xf2820020
+#define	F367TER_TSSERIAL_IMPOSSIBLE	0xf2820010
+#define	F367TER_TSFIFO_UNDERSPEED	0xf2820008
+#define	F367TER_BITSPEED_EVENT	0xf2820004
+#define	F367TER_UL_SCRAMBDETECT	0xf2820002
+#define	F367TER_ULDTV67_FALSELOCK	0xf2820001
+
+/* TSBITRATEM */
+#define	R367TER_TSBITRATEM	0xf283
+#define	F367TER_TSFIFO_BITRATE_HI	0xf28300ff
+
+/* TSBITRATEL */
+#define	R367TER_TSBITRATEL	0xf284
+#define	F367TER_TSFIFO_BITRATE_LO	0xf28400ff
+
+/* TSPACKLENM */
+#define	R367TER_TSPACKLENM	0xf285
+#define	F367TER_TSFIFO_PACKCPT	0xf28500e0
+#define	F367TER_DIL_RPLEN_HI	0xf285001f
+
+/* TSPACKLENL */
+#define	R367TER_TSPACKLENL	0xf286
+#define	F367TER_DIL_RPLEN_LO	0xf28600ff
+
+/* TSBLOCLENM */
+#define	R367TER_TSBLOCLENM	0xf287
+#define	F367TER_TSFIFO_PFLEN_HI	0xf28700ff
+
+/* TSBLOCLENL */
+#define	R367TER_TSBLOCLENL	0xf288
+#define	F367TER_TSFIFO_PFLEN_LO	0xf28800ff
+
+/* TSDLYH */
+#define	R367TER_TSDLYH	0xf289
+#define	F367TER_SOFFIFO_TSTIMEVALID	0xf2890080
+#define	F367TER_SOFFIFO_SPEEDUP	0xf2890040
+#define	F367TER_SOFFIFO_STOP	0xf2890020
+#define	F367TER_SOFFIFO_REGULATED	0xf2890010
+#define	F367TER_SOFFIFO_REALSBOFF_HI	0xf289000f
+
+/* TSDLYM */
+#define	R367TER_TSDLYM	0xf28a
+#define	F367TER_SOFFIFO_REALSBOFF_MED	0xf28a00ff
+
+/* TSDLYL */
+#define	R367TER_TSDLYL	0xf28b
+#define	F367TER_SOFFIFO_REALSBOFF_LO	0xf28b00ff
+
+/* TSNPDAV */
+#define	R367TER_TSNPDAV	0xf28c
+#define	F367TER_TSNPD_AVERAGE	0xf28c00ff
+
+/* TSBUFSTATH */
+#define	R367TER_TSBUFSTATH	0xf28d
+#define	F367TER_TSISCR_3BYTES	0xf28d0080
+#define	F367TER_TSISCR_NEWDATA	0xf28d0040
+#define	F367TER_TSISCR_BUFSTAT_HI	0xf28d003f
+
+/* TSBUFSTATM */
+#define	R367TER_TSBUFSTATM	0xf28e
+#define	F367TER_TSISCR_BUFSTAT_MED	0xf28e00ff
+
+/* TSBUFSTATL */
+#define	R367TER_TSBUFSTATL	0xf28f
+#define	F367TER_TSISCR_BUFSTAT_LO	0xf28f00ff
+
+/* TSDEBUGM */
+#define	R367TER_TSDEBUGM	0xf290
+#define	F367TER_TSFIFO_ILLPACKET	0xf2900080
+#define	F367TER_DIL_NOSYNC	0xf2900040
+#define	F367TER_DIL_ISCR	0xf2900020
+#define	F367TER_DILOUT_BSYNCB	0xf2900010
+#define	F367TER_TSFIFO_EMPTYPKT	0xf2900008
+#define	F367TER_TSFIFO_EMPTYRD	0xf2900004
+#define	F367TER_SOFFIFO_STOPM	0xf2900002
+#define	F367TER_SOFFIFO_SPEEDUPM	0xf2900001
+
+/* TSDEBUGL */
+#define	R367TER_TSDEBUGL	0xf291
+#define	F367TER_TSFIFO_PACKLENFAIL	0xf2910080
+#define	F367TER_TSFIFO_SYNCBFAIL	0xf2910040
+#define	F367TER_TSFIFO_VITLIBRE	0xf2910020
+#define	F367TER_TSFIFO_BOOSTSPEEDM	0xf2910010
+#define	F367TER_TSFIFO_UNDERSPEEDM	0xf2910008
+#define	F367TER_TSFIFO_ERROR_EVNT	0xf2910004
+#define	F367TER_TSFIFO_FULL	0xf2910002
+#define	F367TER_TSFIFO_OVERFLOWM	0xf2910001
+
+/* TSDLYSETH */
+#define	R367TER_TSDLYSETH	0xf292
+#define	F367TER_SOFFIFO_OFFSET	0xf29200e0
+#define	F367TER_SOFFIFO_SYMBOFFSET_HI	0xf292001f
+
+/* TSDLYSETM */
+#define	R367TER_TSDLYSETM	0xf293
+#define	F367TER_SOFFIFO_SYMBOFFSET_MED	0xf29300ff
+
+/* TSDLYSETL */
+#define	R367TER_TSDLYSETL	0xf294
+#define	F367TER_SOFFIFO_SYMBOFFSET_LO	0xf29400ff
+
+/* TSOBSCFG */
+#define	R367TER_TSOBSCFG	0xf295
+#define	F367TER_TSFIFO_OBSCFG	0xf29500ff
+
+/* TSOBSM */
+#define	R367TER_TSOBSM	0xf296
+#define	F367TER_TSFIFO_OBSDATA_HI	0xf29600ff
+
+/* TSOBSL */
+#define	R367TER_TSOBSL	0xf297
+#define	F367TER_TSFIFO_OBSDATA_LO	0xf29700ff
+
+/* ERRCTRL1 */
+#define	R367TER_ERRCTRL1	0xf298
+#define	F367TER_ERR_SRC1	0xf29800f0
+#define	F367TER_ERRCTRL1_3	0xf2980008
+#define	F367TER_NUM_EVT1	0xf2980007
+
+/* ERRCNT1H */
+#define	R367TER_ERRCNT1H	0xf299
+#define	F367TER_ERRCNT1_OLDVALUE	0xf2990080
+#define	F367TER_ERR_CNT1	0xf299007f
+
+/* ERRCNT1M */
+#define	R367TER_ERRCNT1M	0xf29a
+#define	F367TER_ERR_CNT1_HI	0xf29a00ff
+
+/* ERRCNT1L */
+#define	R367TER_ERRCNT1L	0xf29b
+#define	F367TER_ERR_CNT1_LO	0xf29b00ff
+
+/* ERRCTRL2 */
+#define	R367TER_ERRCTRL2	0xf29c
+#define	F367TER_ERR_SRC2	0xf29c00f0
+#define	F367TER_ERRCTRL2_3	0xf29c0008
+#define	F367TER_NUM_EVT2	0xf29c0007
+
+/* ERRCNT2H */
+#define	R367TER_ERRCNT2H	0xf29d
+#define	F367TER_ERRCNT2_OLDVALUE	0xf29d0080
+#define	F367TER_ERR_CNT2_HI	0xf29d007f
+
+/* ERRCNT2M */
+#define	R367TER_ERRCNT2M	0xf29e
+#define	F367TER_ERR_CNT2_MED	0xf29e00ff
+
+/* ERRCNT2L */
+#define	R367TER_ERRCNT2L	0xf29f
+#define	F367TER_ERR_CNT2_LO	0xf29f00ff
+
+/* FECSPY */
+#define	R367TER_FECSPY	0xf2a0
+#define	F367TER_SPY_ENABLE	0xf2a00080
+#define	F367TER_NO_SYNCBYTE	0xf2a00040
+#define	F367TER_SERIAL_MODE	0xf2a00020
+#define	F367TER_UNUSUAL_PACKET	0xf2a00010
+#define	F367TER_BERMETER_DATAMODE	0xf2a0000c
+#define	F367TER_BERMETER_LMODE	0xf2a00002
+#define	F367TER_BERMETER_RESET	0xf2a00001
+
+/* FSPYCFG */
+#define	R367TER_FSPYCFG	0xf2a1
+#define	F367TER_FECSPY_INPUT	0xf2a100c0
+#define	F367TER_RST_ON_ERROR	0xf2a10020
+#define	F367TER_ONE_SHOT	0xf2a10010
+#define	F367TER_I2C_MOD	0xf2a1000c
+#define	F367TER_SPY_HYSTERESIS	0xf2a10003
+
+/* FSPYDATA */
+#define	R367TER_FSPYDATA	0xf2a2
+#define	F367TER_SPY_STUFFING	0xf2a20080
+#define	F367TER_NOERROR_PKTJITTER	0xf2a20040
+#define	F367TER_SPY_CNULLPKT	0xf2a20020
+#define	F367TER_SPY_OUTDATA_MODE	0xf2a2001f
+
+/* FSPYOUT */
+#define	R367TER_FSPYOUT	0xf2a3
+#define	F367TER_FSPY_DIRECT	0xf2a30080
+#define	F367TER_FSPYOUT_6	0xf2a30040
+#define	F367TER_SPY_OUTDATA_BUS	0xf2a30038
+#define	F367TER_STUFF_MODE	0xf2a30007
+
+/* FSTATUS */
+#define	R367TER_FSTATUS	0xf2a4
+#define	F367TER_SPY_ENDSIM	0xf2a40080
+#define	F367TER_VALID_SIM	0xf2a40040
+#define	F367TER_FOUND_SIGNAL	0xf2a40020
+#define	F367TER_DSS_SYNCBYTE	0xf2a40010
+#define	F367TER_RESULT_STATE	0xf2a4000f
+
+/* FGOODPACK */
+#define	R367TER_FGOODPACK	0xf2a5
+#define	F367TER_FGOOD_PACKET	0xf2a500ff
+
+/* FPACKCNT */
+#define	R367TER_FPACKCNT	0xf2a6
+#define	F367TER_FPACKET_COUNTER	0xf2a600ff
+
+/* FSPYMISC */
+#define	R367TER_FSPYMISC	0xf2a7
+#define	F367TER_FLABEL_COUNTER	0xf2a700ff
+
+/* FBERCPT4 */
+#define	R367TER_FBERCPT4	0xf2a8
+#define	F367TER_FBERMETER_CPT5	0xf2a800ff
+
+/* FBERCPT3 */
+#define	R367TER_FBERCPT3	0xf2a9
+#define	F367TER_FBERMETER_CPT4	0xf2a900ff
+
+/* FBERCPT2 */
+#define	R367TER_FBERCPT2	0xf2aa
+#define	F367TER_FBERMETER_CPT3	0xf2aa00ff
+
+/* FBERCPT1 */
+#define	R367TER_FBERCPT1	0xf2ab
+#define	F367TER_FBERMETER_CPT2	0xf2ab00ff
+
+/* FBERCPT0 */
+#define	R367TER_FBERCPT0	0xf2ac
+#define	F367TER_FBERMETER_CPT1	0xf2ac00ff
+
+/* FBERERR2 */
+#define	R367TER_FBERERR2	0xf2ad
+#define	F367TER_FBERMETER_ERR_HI	0xf2ad00ff
+
+/* FBERERR1 */
+#define	R367TER_FBERERR1	0xf2ae
+#define	F367TER_FBERMETER_ERR_MED	0xf2ae00ff
+
+/* FBERERR0 */
+#define	R367TER_FBERERR0	0xf2af
+#define	F367TER_FBERMETER_ERR_LO	0xf2af00ff
+
+/* FSTATESM */
+#define	R367TER_FSTATESM	0xf2b0
+#define	F367TER_RSTATE_F	0xf2b00080
+#define	F367TER_RSTATE_E	0xf2b00040
+#define	F367TER_RSTATE_D	0xf2b00020
+#define	F367TER_RSTATE_C	0xf2b00010
+#define	F367TER_RSTATE_B	0xf2b00008
+#define	F367TER_RSTATE_A	0xf2b00004
+#define	F367TER_RSTATE_9	0xf2b00002
+#define	F367TER_RSTATE_8	0xf2b00001
+
+/* FSTATESL */
+#define	R367TER_FSTATESL	0xf2b1
+#define	F367TER_RSTATE_7	0xf2b10080
+#define	F367TER_RSTATE_6	0xf2b10040
+#define	F367TER_RSTATE_5	0xf2b10020
+#define	F367TER_RSTATE_4	0xf2b10010
+#define	F367TER_RSTATE_3	0xf2b10008
+#define	F367TER_RSTATE_2	0xf2b10004
+#define	F367TER_RSTATE_1	0xf2b10002
+#define	F367TER_RSTATE_0	0xf2b10001
+
+/* FSPYBER */
+#define	R367TER_FSPYBER	0xf2b2
+#define	F367TER_FSPYBER_7	0xf2b20080
+#define	F367TER_FSPYOBS_XORREAD	0xf2b20040
+#define	F367TER_FSPYBER_OBSMODE	0xf2b20020
+#define	F367TER_FSPYBER_SYNCBYTE	0xf2b20010
+#define	F367TER_FSPYBER_UNSYNC	0xf2b20008
+#define	F367TER_FSPYBER_CTIME	0xf2b20007
+
+/* FSPYDISTM */
+#define	R367TER_FSPYDISTM	0xf2b3
+#define	F367TER_PKTTIME_DISTANCE_HI	0xf2b300ff
+
+/* FSPYDISTL */
+#define	R367TER_FSPYDISTL	0xf2b4
+#define	F367TER_PKTTIME_DISTANCE_LO	0xf2b400ff
+
+/* FSPYOBS7 */
+#define	R367TER_FSPYOBS7	0xf2b8
+#define	F367TER_FSPYOBS_SPYFAIL	0xf2b80080
+#define	F367TER_FSPYOBS_SPYFAIL1	0xf2b80040
+#define	F367TER_FSPYOBS_ERROR	0xf2b80020
+#define	F367TER_FSPYOBS_STROUT	0xf2b80010
+#define	F367TER_FSPYOBS_RESULTSTATE1	0xf2b8000f
+
+/* FSPYOBS6 */
+#define	R367TER_FSPYOBS6	0xf2b9
+#define	F367TER_FSPYOBS_RESULTSTATe0	0xf2b900f0
+#define	F367TER_FSPYOBS_RESULTSTATEM1	0xf2b9000f
+
+/* FSPYOBS5 */
+#define	R367TER_FSPYOBS5	0xf2ba
+#define	F367TER_FSPYOBS_BYTEOFPACKET1	0xf2ba00ff
+
+/* FSPYOBS4 */
+#define	R367TER_FSPYOBS4	0xf2bb
+#define	F367TER_FSPYOBS_BYTEVALUE1	0xf2bb00ff
+
+/* FSPYOBS3 */
+#define	R367TER_FSPYOBS3	0xf2bc
+#define	F367TER_FSPYOBS_DATA1	0xf2bc00ff
+
+/* FSPYOBS2 */
+#define	R367TER_FSPYOBS2	0xf2bd
+#define	F367TER_FSPYOBS_DATa0	0xf2bd00ff
+
+/* FSPYOBS1 */
+#define	R367TER_FSPYOBS1	0xf2be
+#define	F367TER_FSPYOBS_DATAM1	0xf2be00ff
+
+/* FSPYOBS0 */
+#define	R367TER_FSPYOBS0	0xf2bf
+#define	F367TER_FSPYOBS_DATAM2	0xf2bf00ff
+
+/* SFDEMAP */
+#define	R367TER_SFDEMAP	0xf2c0
+#define	F367TER_SFDEMAP_7	0xf2c00080
+#define	F367TER_SFEC_K_DIVIDER_VIT	0xf2c0007f
+
+/* SFERROR */
+#define	R367TER_SFERROR	0xf2c1
+#define	F367TER_SFEC_REGERR_VIT	0xf2c100ff
+
+/* SFAVSR */
+#define	R367TER_SFAVSR	0xf2c2
+#define	F367TER_SFEC_SUMERRORS	0xf2c20080
+#define	F367TER_SERROR_MAXMODE	0xf2c20040
+#define	F367TER_SN_SFEC	0xf2c20030
+#define	F367TER_KDIV_MODE_SFEC	0xf2c2000c
+#define	F367TER_SFAVSR_1	0xf2c20002
+#define	F367TER_SFAVSR_0	0xf2c20001
+
+/* SFECSTATUS */
+#define	R367TER_SFECSTATUS	0xf2c3
+#define	F367TER_SFEC_ON	0xf2c30080
+#define	F367TER_SFSTATUS_6	0xf2c30040
+#define	F367TER_SFSTATUS_5	0xf2c30020
+#define	F367TER_SFSTATUS_4	0xf2c30010
+#define	F367TER_LOCKEDSFEC	0xf2c30008
+#define	F367TER_SFEC_DELOCK	0xf2c30004
+#define	F367TER_SFEC_DEMODSEL1	0xf2c30002
+#define	F367TER_SFEC_OVFON	0xf2c30001
+
+/* SFKDIV12 */
+#define	R367TER_SFKDIV12	0xf2c4
+#define	F367TER_SFECKDIV12_MAN	0xf2c40080
+#define	F367TER_SFEC_K_DIVIDER_12	0xf2c4007f
+
+/* SFKDIV23 */
+#define	R367TER_SFKDIV23	0xf2c5
+#define	F367TER_SFECKDIV23_MAN	0xf2c50080
+#define	F367TER_SFEC_K_DIVIDER_23	0xf2c5007f
+
+/* SFKDIV34 */
+#define	R367TER_SFKDIV34	0xf2c6
+#define	F367TER_SFECKDIV34_MAN	0xf2c60080
+#define	F367TER_SFEC_K_DIVIDER_34	0xf2c6007f
+
+/* SFKDIV56 */
+#define	R367TER_SFKDIV56	0xf2c7
+#define	F367TER_SFECKDIV56_MAN	0xf2c70080
+#define	F367TER_SFEC_K_DIVIDER_56	0xf2c7007f
+
+/* SFKDIV67 */
+#define	R367TER_SFKDIV67	0xf2c8
+#define	F367TER_SFECKDIV67_MAN	0xf2c80080
+#define	F367TER_SFEC_K_DIVIDER_67	0xf2c8007f
+
+/* SFKDIV78 */
+#define	R367TER_SFKDIV78	0xf2c9
+#define	F367TER_SFECKDIV78_MAN	0xf2c90080
+#define	F367TER_SFEC_K_DIVIDER_78	0xf2c9007f
+
+/* SFDILSTKM */
+#define	R367TER_SFDILSTKM	0xf2ca
+#define	F367TER_SFEC_PACKCPT	0xf2ca00e0
+#define	F367TER_SFEC_DILSTK_HI	0xf2ca001f
+
+/* SFDILSTKL */
+#define	R367TER_SFDILSTKL	0xf2cb
+#define	F367TER_SFEC_DILSTK_LO	0xf2cb00ff
+
+/* SFSTATUS */
+#define	R367TER_SFSTATUS	0xf2cc
+#define	F367TER_SFEC_LINEOK	0xf2cc0080
+#define	F367TER_SFEC_ERROR	0xf2cc0040
+#define	F367TER_SFEC_DATA7	0xf2cc0020
+#define	F367TER_SFEC_OVERFLOW	0xf2cc0010
+#define	F367TER_SFEC_DEMODSEL2	0xf2cc0008
+#define	F367TER_SFEC_NOSYNC	0xf2cc0004
+#define	F367TER_SFEC_UNREGULA	0xf2cc0002
+#define	F367TER_SFEC_READY	0xf2cc0001
+
+/* SFDLYH */
+#define	R367TER_SFDLYH	0xf2cd
+#define	F367TER_SFEC_TSTIMEVALID	0xf2cd0080
+#define	F367TER_SFEC_SPEEDUP	0xf2cd0040
+#define	F367TER_SFEC_STOP	0xf2cd0020
+#define	F367TER_SFEC_REGULATED	0xf2cd0010
+#define	F367TER_SFEC_REALSYMBOFFSET	0xf2cd000f
+
+/* SFDLYM */
+#define	R367TER_SFDLYM	0xf2ce
+#define	F367TER_SFEC_REALSYMBOFFSET_HI	0xf2ce00ff
+
+/* SFDLYL */
+#define	R367TER_SFDLYL	0xf2cf
+#define	F367TER_SFEC_REALSYMBOFFSET_LO	0xf2cf00ff
+
+/* SFDLYSETH */
+#define	R367TER_SFDLYSETH	0xf2d0
+#define	F367TER_SFEC_OFFSET	0xf2d000e0
+#define	F367TER_SFECDLYSETH_4	0xf2d00010
+#define	F367TER_RST_SFEC	0xf2d00008
+#define	F367TER_SFECDLYSETH_2	0xf2d00004
+#define	F367TER_SFEC_DISABLE	0xf2d00002
+#define	F367TER_SFEC_UNREGUL	0xf2d00001
+
+/* SFDLYSETM */
+#define	R367TER_SFDLYSETM	0xf2d1
+#define	F367TER_SFECDLYSETM_7	0xf2d10080
+#define	F367TER_SFEC_SYMBOFFSET_HI	0xf2d1007f
+
+/* SFDLYSETL */
+#define	R367TER_SFDLYSETL	0xf2d2
+#define	F367TER_SFEC_SYMBOFFSET_LO	0xf2d200ff
+
+/* SFOBSCFG */
+#define	R367TER_SFOBSCFG	0xf2d3
+#define	F367TER_SFEC_OBSCFG	0xf2d300ff
+
+/* SFOBSM */
+#define	R367TER_SFOBSM	0xf2d4
+#define	F367TER_SFEC_OBSDATA_HI	0xf2d400ff
+
+/* SFOBSL */
+#define	R367TER_SFOBSL	0xf2d5
+#define	F367TER_SFEC_OBSDATA_LO	0xf2d500ff
+
+/* SFECINFO */
+#define	R367TER_SFECINFO	0xf2d6
+#define	F367TER_SFECINFO_7	0xf2d60080
+#define	F367TER_SFEC_SYNCDLSB	0xf2d60070
+#define	F367TER_SFCE_S1cPHASE	0xf2d6000f
+
+/* SFERRCTRL */
+#define	R367TER_SFERRCTRL	0xf2d8
+#define	F367TER_SFEC_ERR_SOURCE	0xf2d800f0
+#define	F367TER_SFERRCTRL_3	0xf2d80008
+#define	F367TER_SFEC_NUM_EVENT	0xf2d80007
+
+/* SFERRCNTH */
+#define	R367TER_SFERRCNTH	0xf2d9
+#define	F367TER_SFERRC_OLDVALUE	0xf2d90080
+#define	F367TER_SFEC_ERR_CNT	0xf2d9007f
+
+/* SFERRCNTM */
+#define	R367TER_SFERRCNTM	0xf2da
+#define	F367TER_SFEC_ERR_CNT_HI	0xf2da00ff
+
+/* SFERRCNTL */
+#define	R367TER_SFERRCNTL	0xf2db
+#define	F367TER_SFEC_ERR_CNT_LO	0xf2db00ff
+
+/* SYMBRATEM */
+#define	R367TER_SYMBRATEM	0xf2e0
+#define	F367TER_DEFGEN_SYMBRATE_HI	0xf2e000ff
+
+/* SYMBRATEL */
+#define	R367TER_SYMBRATEL	0xf2e1
+#define	F367TER_DEFGEN_SYMBRATE_LO	0xf2e100ff
+
+/* SYMBSTATUS */
+#define	R367TER_SYMBSTATUS	0xf2e2
+#define	F367TER_SYMBDLINE2_OFF	0xf2e20080
+#define	F367TER_SDDL_REINIT1	0xf2e20040
+#define	F367TER_SDD_REINIT1	0xf2e20020
+#define	F367TER_TOKENID_ERROR	0xf2e20010
+#define	F367TER_SYMBRATE_OVERFLOW	0xf2e20008
+#define	F367TER_SYMBRATE_UNDERFLOW	0xf2e20004
+#define	F367TER_TOKENID_RSTEVENT	0xf2e20002
+#define	F367TER_TOKENID_RESET1	0xf2e20001
+
+/* SYMBCFG */
+#define	R367TER_SYMBCFG	0xf2e3
+#define	F367TER_SYMBCFG_7	0xf2e30080
+#define	F367TER_SYMBCFG_6	0xf2e30040
+#define	F367TER_SYMBCFG_5	0xf2e30020
+#define	F367TER_SYMBCFG_4	0xf2e30010
+#define	F367TER_SYMRATE_FSPEED	0xf2e3000c
+#define	F367TER_SYMRATE_SSPEED	0xf2e30003
+
+/* SYMBFIFOM */
+#define	R367TER_SYMBFIFOM	0xf2e4
+#define	F367TER_SYMBFIFOM_7	0xf2e40080
+#define	F367TER_SYMBFIFOM_6	0xf2e40040
+#define	F367TER_DEFGEN_SYMFIFO_HI	0xf2e4003f
+
+/* SYMBFIFOL */
+#define	R367TER_SYMBFIFOL	0xf2e5
+#define	F367TER_DEFGEN_SYMFIFO_LO	0xf2e500ff
+
+/* SYMBOFFSM */
+#define	R367TER_SYMBOFFSM	0xf2e6
+#define	F367TER_TOKENID_RESET2	0xf2e60080
+#define	F367TER_SDDL_REINIT2	0xf2e60040
+#define	F367TER_SDD_REINIT2	0xf2e60020
+#define	F367TER_SYMBOFFSM_4	0xf2e60010
+#define	F367TER_SYMBOFFSM_3	0xf2e60008
+#define	F367TER_DEFGEN_SYMBOFFSET_HI	0xf2e60007
+
+/* SYMBOFFSL */
+#define	R367TER_SYMBOFFSL	0xf2e7
+#define	F367TER_DEFGEN_SYMBOFFSET_LO	0xf2e700ff
+
+/* DEBUG_LT4 */
+#define	R367TER_DEBUG_LT4	0xf400
+#define	F367TER_F_DEBUG_LT4	0xf40000ff
+
+/* DEBUG_LT5 */
+#define	R367TER_DEBUG_LT5	0xf401
+#define	F367TER_F_DEBUG_LT5	0xf40100ff
+
+/* DEBUG_LT6 */
+#define	R367TER_DEBUG_LT6	0xf402
+#define	F367TER_F_DEBUG_LT6	0xf40200ff
+
+/* DEBUG_LT7 */
+#define	R367TER_DEBUG_LT7	0xf403
+#define	F367TER_F_DEBUG_LT7	0xf40300ff
+
+/* DEBUG_LT8 */
+#define	R367TER_DEBUG_LT8	0xf404
+#define	F367TER_F_DEBUG_LT8	0xf40400ff
+
+/* DEBUG_LT9 */
+#define	R367TER_DEBUG_LT9	0xf405
+#define	F367TER_F_DEBUG_LT9	0xf40500ff
+
+#define STV0367TER_NBREGS	445
+
+/* ID */
+#define	R367CAB_ID	0xf000
+#define	F367CAB_IDENTIFICATIONREGISTER	0xf00000ff
+
+/* I2CRPT */
+#define	R367CAB_I2CRPT	0xf001
+#define	F367CAB_I2CT_ON	0xf0010080
+#define	F367CAB_ENARPT_LEVEL	0xf0010070
+#define	F367CAB_SCLT_DELAY	0xf0010008
+#define	F367CAB_SCLT_NOD	0xf0010004
+#define	F367CAB_STOP_ENABLE	0xf0010002
+#define	F367CAB_SDAT_NOD	0xf0010001
+
+/* TOPCTRL */
+#define	R367CAB_TOPCTRL	0xf002
+#define	F367CAB_STDBY	0xf0020080
+#define	F367CAB_STDBY_CORE	0xf0020020
+#define	F367CAB_QAM_COFDM	0xf0020010
+#define	F367CAB_TS_DIS	0xf0020008
+#define	F367CAB_DIR_CLK_216	0xf0020004
+
+/* IOCFG0 */
+#define	R367CAB_IOCFG0	0xf003
+#define	F367CAB_OP0_SD	0xf0030080
+#define	F367CAB_OP0_VAL	0xf0030040
+#define	F367CAB_OP0_OD	0xf0030020
+#define	F367CAB_OP0_INV	0xf0030010
+#define	F367CAB_OP0_DACVALUE_HI	0xf003000f
+
+/* DAc0R */
+#define	R367CAB_DAC0R	0xf004
+#define	F367CAB_OP0_DACVALUE_LO	0xf00400ff
+
+/* IOCFG1 */
+#define	R367CAB_IOCFG1	0xf005
+#define	F367CAB_IP0	0xf0050040
+#define	F367CAB_OP1_OD	0xf0050020
+#define	F367CAB_OP1_INV	0xf0050010
+#define	F367CAB_OP1_DACVALUE_HI	0xf005000f
+
+/* DAC1R */
+#define	R367CAB_DAC1R	0xf006
+#define	F367CAB_OP1_DACVALUE_LO	0xf00600ff
+
+/* IOCFG2 */
+#define	R367CAB_IOCFG2	0xf007
+#define	F367CAB_OP2_LOCK_CONF	0xf00700e0
+#define	F367CAB_OP2_OD	0xf0070010
+#define	F367CAB_OP2_VAL	0xf0070008
+#define	F367CAB_OP1_LOCK_CONF	0xf0070007
+
+/* SDFR */
+#define	R367CAB_SDFR	0xf008
+#define	F367CAB_OP0_FREQ	0xf00800f0
+#define	F367CAB_OP1_FREQ	0xf008000f
+
+/* AUX_CLK */
+#define	R367CAB_AUX_CLK	0xf00a
+#define	F367CAB_AUXFEC_CTL	0xf00a00c0
+#define	F367CAB_DIS_CKX4	0xf00a0020
+#define	F367CAB_CKSEL	0xf00a0018
+#define	F367CAB_CKDIV_PROG	0xf00a0006
+#define	F367CAB_AUXCLK_ENA	0xf00a0001
+
+/* FREESYS1 */
+#define	R367CAB_FREESYS1	0xf00b
+#define	F367CAB_FREESYS_1	0xf00b00ff
+
+/* FREESYS2 */
+#define	R367CAB_FREESYS2	0xf00c
+#define	F367CAB_FREESYS_2	0xf00c00ff
+
+/* FREESYS3 */
+#define	R367CAB_FREESYS3	0xf00d
+#define	F367CAB_FREESYS_3	0xf00d00ff
+
+/* GPIO_CFG */
+#define	R367CAB_GPIO_CFG	0xf00e
+#define	F367CAB_GPIO7_OD	0xf00e0080
+#define	F367CAB_GPIO7_CFG	0xf00e0040
+#define	F367CAB_GPIO6_OD	0xf00e0020
+#define	F367CAB_GPIO6_CFG	0xf00e0010
+#define	F367CAB_GPIO5_OD	0xf00e0008
+#define	F367CAB_GPIO5_CFG	0xf00e0004
+#define	F367CAB_GPIO4_OD	0xf00e0002
+#define	F367CAB_GPIO4_CFG	0xf00e0001
+
+/* GPIO_CMD */
+#define	R367CAB_GPIO_CMD	0xf00f
+#define	F367CAB_GPIO7_VAL	0xf00f0008
+#define	F367CAB_GPIO6_VAL	0xf00f0004
+#define	F367CAB_GPIO5_VAL	0xf00f0002
+#define	F367CAB_GPIO4_VAL	0xf00f0001
+
+/* TSTRES */
+#define	R367CAB_TSTRES	0xf0c0
+#define	F367CAB_FRES_DISPLAY	0xf0c00080
+#define	F367CAB_FRES_FIFO_AD	0xf0c00020
+#define	F367CAB_FRESRS	0xf0c00010
+#define	F367CAB_FRESACS	0xf0c00008
+#define	F367CAB_FRESFEC	0xf0c00004
+#define	F367CAB_FRES_PRIF	0xf0c00002
+#define	F367CAB_FRESCORE	0xf0c00001
+
+/* ANACTRL */
+#define	R367CAB_ANACTRL	0xf0c1
+#define	F367CAB_BYPASS_XTAL	0xf0c10040
+#define	F367CAB_BYPASS_PLLXN	0xf0c1000c
+#define	F367CAB_DIS_PAD_OSC	0xf0c10002
+#define	F367CAB_STDBY_PLLXN	0xf0c10001
+
+/* TSTBUS */
+#define	R367CAB_TSTBUS	0xf0c2
+#define	F367CAB_TS_BYTE_CLK_INV	0xf0c20080
+#define	F367CAB_CFG_IP	0xf0c20070
+#define	F367CAB_CFG_TST	0xf0c2000f
+
+/* RF_AGC1 */
+#define	R367CAB_RF_AGC1	0xf0d4
+#define	F367CAB_RF_AGC1_LEVEL_HI	0xf0d400ff
+
+/* RF_AGC2 */
+#define	R367CAB_RF_AGC2	0xf0d5
+#define	F367CAB_REF_ADGP	0xf0d50080
+#define	F367CAB_STDBY_ADCGP	0xf0d50020
+#define	F367CAB_RF_AGC1_LEVEL_LO	0xf0d50003
+
+/* ANADIGCTRL */
+#define	R367CAB_ANADIGCTRL	0xf0d7
+#define	F367CAB_SEL_CLKDEM	0xf0d70020
+#define	F367CAB_EN_BUFFER_Q	0xf0d70010
+#define	F367CAB_EN_BUFFER_I	0xf0d70008
+#define	F367CAB_ADC_RIS_EGDE	0xf0d70004
+#define	F367CAB_SGN_ADC	0xf0d70002
+#define	F367CAB_SEL_AD12_SYNC	0xf0d70001
+
+/* PLLMDIV */
+#define	R367CAB_PLLMDIV	0xf0d8
+#define	F367CAB_PLL_MDIV	0xf0d800ff
+
+/* PLLNDIV */
+#define	R367CAB_PLLNDIV	0xf0d9
+#define	F367CAB_PLL_NDIV	0xf0d900ff
+
+/* PLLSETUP */
+#define	R367CAB_PLLSETUP	0xf0da
+#define	F367CAB_PLL_PDIV	0xf0da0070
+#define	F367CAB_PLL_KDIV	0xf0da000f
+
+/* DUAL_AD12 */
+#define	R367CAB_DUAL_AD12	0xf0db
+#define	F367CAB_FS20M	0xf0db0020
+#define	F367CAB_FS50M	0xf0db0010
+#define	F367CAB_INMODe0	0xf0db0008
+#define	F367CAB_POFFQ	0xf0db0004
+#define	F367CAB_POFFI	0xf0db0002
+#define	F367CAB_INMODE1	0xf0db0001
+
+/* TSTBIST */
+#define	R367CAB_TSTBIST	0xf0dc
+#define	F367CAB_TST_BYP_CLK	0xf0dc0080
+#define	F367CAB_TST_GCLKENA_STD	0xf0dc0040
+#define	F367CAB_TST_GCLKENA	0xf0dc0020
+#define	F367CAB_TST_MEMBIST	0xf0dc001f
+
+/* CTRL_1 */
+#define	R367CAB_CTRL_1	0xf402
+#define	F367CAB_SOFT_RST	0xf4020080
+#define	F367CAB_EQU_RST	0xf4020008
+#define	F367CAB_CRL_RST	0xf4020004
+#define	F367CAB_TRL_RST	0xf4020002
+#define	F367CAB_AGC_RST	0xf4020001
+
+/* CTRL_2 */
+#define	R367CAB_CTRL_2	0xf403
+#define	F367CAB_DEINT_RST	0xf4030008
+#define	F367CAB_RS_RST	0xf4030004
+
+/* IT_STATUS1 */
+#define	R367CAB_IT_STATUS1	0xf408
+#define	F367CAB_SWEEP_OUT	0xf4080080
+#define	F367CAB_FSM_CRL	0xf4080040
+#define	F367CAB_CRL_LOCK	0xf4080020
+#define	F367CAB_MFSM	0xf4080010
+#define	F367CAB_TRL_LOCK	0xf4080008
+#define	F367CAB_TRL_AGC_LIMIT	0xf4080004
+#define	F367CAB_ADJ_AGC_LOCK	0xf4080002
+#define	F367CAB_AGC_QAM_LOCK	0xf4080001
+
+/* IT_STATUS2 */
+#define	R367CAB_IT_STATUS2	0xf409
+#define	F367CAB_TSMF_CNT	0xf4090080
+#define	F367CAB_TSMF_EOF	0xf4090040
+#define	F367CAB_TSMF_RDY	0xf4090020
+#define	F367CAB_FEC_NOCORR	0xf4090010
+#define	F367CAB_SYNCSTATE	0xf4090008
+#define	F367CAB_DEINT_LOCK	0xf4090004
+#define	F367CAB_FADDING_FRZ	0xf4090002
+#define	F367CAB_TAPMON_ALARM	0xf4090001
+
+/* IT_EN1 */
+#define	R367CAB_IT_EN1	0xf40a
+#define	F367CAB_SWEEP_OUTE	0xf40a0080
+#define	F367CAB_FSM_CRLE	0xf40a0040
+#define	F367CAB_CRL_LOCKE	0xf40a0020
+#define	F367CAB_MFSME	0xf40a0010
+#define	F367CAB_TRL_LOCKE	0xf40a0008
+#define	F367CAB_TRL_AGC_LIMITE	0xf40a0004
+#define	F367CAB_ADJ_AGC_LOCKE	0xf40a0002
+#define	F367CAB_AGC_LOCKE	0xf40a0001
+
+/* IT_EN2 */
+#define	R367CAB_IT_EN2	0xf40b
+#define	F367CAB_TSMF_CNTE	0xf40b0080
+#define	F367CAB_TSMF_EOFE	0xf40b0040
+#define	F367CAB_TSMF_RDYE	0xf40b0020
+#define	F367CAB_FEC_NOCORRE	0xf40b0010
+#define	F367CAB_SYNCSTATEE	0xf40b0008
+#define	F367CAB_DEINT_LOCKE	0xf40b0004
+#define	F367CAB_FADDING_FRZE	0xf40b0002
+#define	F367CAB_TAPMON_ALARME	0xf40b0001
+
+/* CTRL_STATUS */
+#define	R367CAB_CTRL_STATUS	0xf40c
+#define	F367CAB_QAMFEC_LOCK	0xf40c0004
+#define	F367CAB_TSMF_LOCK	0xf40c0002
+#define	F367CAB_TSMF_ERROR	0xf40c0001
+
+/* TEST_CTL */
+#define	R367CAB_TEST_CTL	0xf40f
+#define	F367CAB_TST_BLK_SEL	0xf40f0060
+#define	F367CAB_TST_BUS_SEL	0xf40f001f
+
+/* AGC_CTL */
+#define	R367CAB_AGC_CTL	0xf410
+#define	F367CAB_AGC_LCK_TH	0xf41000f0
+#define	F367CAB_AGC_ACCUMRSTSEL	0xf4100007
+
+/* AGC_IF_CFG */
+#define	R367CAB_AGC_IF_CFG	0xf411
+#define	F367CAB_AGC_IF_BWSEL	0xf41100f0
+#define	F367CAB_AGC_IF_FREEZE	0xf4110002
+
+/* AGC_RF_CFG */
+#define	R367CAB_AGC_RF_CFG	0xf412
+#define	F367CAB_AGC_RF_BWSEL	0xf4120070
+#define	F367CAB_AGC_RF_FREEZE	0xf4120002
+
+/* AGC_PWM_CFG */
+#define	R367CAB_AGC_PWM_CFG	0xf413
+#define	F367CAB_AGC_RF_PWM_TST	0xf4130080
+#define	F367CAB_AGC_RF_PWM_INV	0xf4130040
+#define	F367CAB_AGC_IF_PWM_TST	0xf4130008
+#define	F367CAB_AGC_IF_PWM_INV	0xf4130004
+#define	F367CAB_AGC_PWM_CLKDIV	0xf4130003
+
+/* AGC_PWR_REF_L */
+#define	R367CAB_AGC_PWR_REF_L	0xf414
+#define	F367CAB_AGC_PWRREF_LO	0xf41400ff
+
+/* AGC_PWR_REF_H */
+#define	R367CAB_AGC_PWR_REF_H	0xf415
+#define	F367CAB_AGC_PWRREF_HI	0xf4150003
+
+/* AGC_RF_TH_L */
+#define	R367CAB_AGC_RF_TH_L	0xf416
+#define	F367CAB_AGC_RF_TH_LO	0xf41600ff
+
+/* AGC_RF_TH_H */
+#define	R367CAB_AGC_RF_TH_H	0xf417
+#define	F367CAB_AGC_RF_TH_HI	0xf417000f
+
+/* AGC_IF_LTH_L */
+#define	R367CAB_AGC_IF_LTH_L	0xf418
+#define	F367CAB_AGC_IF_THLO_LO	0xf41800ff
+
+/* AGC_IF_LTH_H */
+#define	R367CAB_AGC_IF_LTH_H	0xf419
+#define	F367CAB_AGC_IF_THLO_HI	0xf419000f
+
+/* AGC_IF_HTH_L */
+#define	R367CAB_AGC_IF_HTH_L	0xf41a
+#define	F367CAB_AGC_IF_THHI_LO	0xf41a00ff
+
+/* AGC_IF_HTH_H */
+#define	R367CAB_AGC_IF_HTH_H	0xf41b
+#define	F367CAB_AGC_IF_THHI_HI	0xf41b000f
+
+/* AGC_PWR_RD_L */
+#define	R367CAB_AGC_PWR_RD_L	0xf41c
+#define	F367CAB_AGC_PWR_WORD_LO	0xf41c00ff
+
+/* AGC_PWR_RD_M */
+#define	R367CAB_AGC_PWR_RD_M	0xf41d
+#define	F367CAB_AGC_PWR_WORD_ME	0xf41d00ff
+
+/* AGC_PWR_RD_H */
+#define	R367CAB_AGC_PWR_RD_H	0xf41e
+#define	F367CAB_AGC_PWR_WORD_HI	0xf41e0003
+
+/* AGC_PWM_IFCMD_L */
+#define	R367CAB_AGC_PWM_IFCMD_L	0xf420
+#define	F367CAB_AGC_IF_PWMCMD_LO	0xf42000ff
+
+/* AGC_PWM_IFCMD_H */
+#define	R367CAB_AGC_PWM_IFCMD_H	0xf421
+#define	F367CAB_AGC_IF_PWMCMD_HI	0xf421000f
+
+/* AGC_PWM_RFCMD_L */
+#define	R367CAB_AGC_PWM_RFCMD_L	0xf422
+#define	F367CAB_AGC_RF_PWMCMD_LO	0xf42200ff
+
+/* AGC_PWM_RFCMD_H */
+#define	R367CAB_AGC_PWM_RFCMD_H	0xf423
+#define	F367CAB_AGC_RF_PWMCMD_HI	0xf423000f
+
+/* IQDEM_CFG */
+#define	R367CAB_IQDEM_CFG	0xf424
+#define	F367CAB_IQDEM_CLK_SEL	0xf4240004
+#define	F367CAB_IQDEM_INVIQ	0xf4240002
+#define	F367CAB_IQDEM_A2dTYPE	0xf4240001
+
+/* MIX_NCO_LL */
+#define	R367CAB_MIX_NCO_LL	0xf425
+#define	F367CAB_MIX_NCO_INC_LL	0xf42500ff
+
+/* MIX_NCO_HL */
+#define	R367CAB_MIX_NCO_HL	0xf426
+#define	F367CAB_MIX_NCO_INC_HL	0xf42600ff
+
+/* MIX_NCO_HH */
+#define	R367CAB_MIX_NCO_HH	0xf427
+#define	F367CAB_MIX_NCO_INVCNST	0xf4270080
+#define	F367CAB_MIX_NCO_INC_HH	0xf427007f
+
+/* SRC_NCO_LL */
+#define	R367CAB_SRC_NCO_LL	0xf428
+#define	F367CAB_SRC_NCO_INC_LL	0xf42800ff
+
+/* SRC_NCO_LH */
+#define	R367CAB_SRC_NCO_LH	0xf429
+#define	F367CAB_SRC_NCO_INC_LH	0xf42900ff
+
+/* SRC_NCO_HL */
+#define	R367CAB_SRC_NCO_HL	0xf42a
+#define	F367CAB_SRC_NCO_INC_HL	0xf42a00ff
+
+/* SRC_NCO_HH */
+#define	R367CAB_SRC_NCO_HH	0xf42b
+#define	F367CAB_SRC_NCO_INC_HH	0xf42b007f
+
+/* IQDEM_GAIN_SRC_L */
+#define	R367CAB_IQDEM_GAIN_SRC_L	0xf42c
+#define	F367CAB_GAIN_SRC_LO	0xf42c00ff
+
+/* IQDEM_GAIN_SRC_H */
+#define	R367CAB_IQDEM_GAIN_SRC_H	0xf42d
+#define	F367CAB_GAIN_SRC_HI	0xf42d0003
+
+/* IQDEM_DCRM_CFG_LL */
+#define	R367CAB_IQDEM_DCRM_CFG_LL	0xf430
+#define	F367CAB_DCRM0_DCIN_L	0xf43000ff
+
+/* IQDEM_DCRM_CFG_LH */
+#define	R367CAB_IQDEM_DCRM_CFG_LH	0xf431
+#define	F367CAB_DCRM1_I_DCIN_L	0xf43100fc
+#define	F367CAB_DCRM0_DCIN_H	0xf4310003
+
+/* IQDEM_DCRM_CFG_HL */
+#define	R367CAB_IQDEM_DCRM_CFG_HL	0xf432
+#define	F367CAB_DCRM1_Q_DCIN_L	0xf43200f0
+#define	F367CAB_DCRM1_I_DCIN_H	0xf432000f
+
+/* IQDEM_DCRM_CFG_HH */
+#define	R367CAB_IQDEM_DCRM_CFG_HH	0xf433
+#define	F367CAB_DCRM1_FRZ	0xf4330080
+#define	F367CAB_DCRM0_FRZ	0xf4330040
+#define	F367CAB_DCRM1_Q_DCIN_H	0xf433003f
+
+/* IQDEM_ADJ_COEFf0 */
+#define	R367CAB_IQDEM_ADJ_COEFF0	0xf434
+#define	F367CAB_ADJIIR_COEFF10_L	0xf43400ff
+
+/* IQDEM_ADJ_COEFF1 */
+#define	R367CAB_IQDEM_ADJ_COEFF1	0xf435
+#define	F367CAB_ADJIIR_COEFF11_L	0xf43500fc
+#define	F367CAB_ADJIIR_COEFF10_H	0xf4350003
+
+/* IQDEM_ADJ_COEFF2 */
+#define	R367CAB_IQDEM_ADJ_COEFF2	0xf436
+#define	F367CAB_ADJIIR_COEFF12_L	0xf43600f0
+#define	F367CAB_ADJIIR_COEFF11_H	0xf436000f
+
+/* IQDEM_ADJ_COEFF3 */
+#define	R367CAB_IQDEM_ADJ_COEFF3	0xf437
+#define	F367CAB_ADJIIR_COEFF20_L	0xf43700c0
+#define	F367CAB_ADJIIR_COEFF12_H	0xf437003f
+
+/* IQDEM_ADJ_COEFF4 */
+#define	R367CAB_IQDEM_ADJ_COEFF4	0xf438
+#define	F367CAB_ADJIIR_COEFF20_H	0xf43800ff
+
+/* IQDEM_ADJ_COEFF5 */
+#define	R367CAB_IQDEM_ADJ_COEFF5	0xf439
+#define	F367CAB_ADJIIR_COEFF21_L	0xf43900ff
+
+/* IQDEM_ADJ_COEFF6 */
+#define	R367CAB_IQDEM_ADJ_COEFF6	0xf43a
+#define	F367CAB_ADJIIR_COEFF22_L	0xf43a00fc
+#define	F367CAB_ADJIIR_COEFF21_H	0xf43a0003
+
+/* IQDEM_ADJ_COEFF7 */
+#define	R367CAB_IQDEM_ADJ_COEFF7	0xf43b
+#define	F367CAB_ADJIIR_COEFF22_H	0xf43b000f
+
+/* IQDEM_ADJ_EN */
+#define	R367CAB_IQDEM_ADJ_EN	0xf43c
+#define	F367CAB_ALLPASSFILT_EN	0xf43c0008
+#define	F367CAB_ADJ_AGC_EN	0xf43c0004
+#define	F367CAB_ADJ_COEFF_FRZ	0xf43c0002
+#define	F367CAB_ADJ_EN	0xf43c0001
+
+/* IQDEM_ADJ_AGC_REF */
+#define	R367CAB_IQDEM_ADJ_AGC_REF	0xf43d
+#define	F367CAB_ADJ_AGC_REF	0xf43d00ff
+
+/* ALLPASSFILT1 */
+#define	R367CAB_ALLPASSFILT1	0xf440
+#define	F367CAB_ALLPASSFILT_COEFF1_LO	0xf44000ff
+
+/* ALLPASSFILT2 */
+#define	R367CAB_ALLPASSFILT2	0xf441
+#define	F367CAB_ALLPASSFILT_COEFF1_ME	0xf44100ff
+
+/* ALLPASSFILT3 */
+#define	R367CAB_ALLPASSFILT3	0xf442
+#define	F367CAB_ALLPASSFILT_COEFF2_LO	0xf44200c0
+#define	F367CAB_ALLPASSFILT_COEFF1_HI	0xf442003f
+
+/* ALLPASSFILT4 */
+#define	R367CAB_ALLPASSFILT4	0xf443
+#define	F367CAB_ALLPASSFILT_COEFF2_MEL	0xf44300ff
+
+/* ALLPASSFILT5 */
+#define	R367CAB_ALLPASSFILT5	0xf444
+#define	F367CAB_ALLPASSFILT_COEFF2_MEH	0xf44400ff
+
+/* ALLPASSFILT6 */
+#define	R367CAB_ALLPASSFILT6	0xf445
+#define	F367CAB_ALLPASSFILT_COEFF3_LO	0xf44500f0
+#define	F367CAB_ALLPASSFILT_COEFF2_HI	0xf445000f
+
+/* ALLPASSFILT7 */
+#define	R367CAB_ALLPASSFILT7	0xf446
+#define	F367CAB_ALLPASSFILT_COEFF3_MEL	0xf44600ff
+
+/* ALLPASSFILT8 */
+#define	R367CAB_ALLPASSFILT8	0xf447
+#define	F367CAB_ALLPASSFILT_COEFF3_MEH	0xf44700ff
+
+/* ALLPASSFILT9 */
+#define	R367CAB_ALLPASSFILT9	0xf448
+#define	F367CAB_ALLPASSFILT_COEFF4_LO	0xf44800fc
+#define	F367CAB_ALLPASSFILT_COEFF3_HI	0xf4480003
+
+/* ALLPASSFILT10 */
+#define	R367CAB_ALLPASSFILT10	0xf449
+#define	F367CAB_ALLPASSFILT_COEFF4_ME	0xf44900ff
+
+/* ALLPASSFILT11 */
+#define	R367CAB_ALLPASSFILT11	0xf44a
+#define	F367CAB_ALLPASSFILT_COEFF4_HI	0xf44a00ff
+
+/* TRL_AGC_CFG */
+#define	R367CAB_TRL_AGC_CFG	0xf450
+#define	F367CAB_TRL_AGC_FREEZE	0xf4500080
+#define	F367CAB_TRL_AGC_REF	0xf450007f
+
+/* TRL_LPF_CFG */
+#define	R367CAB_TRL_LPF_CFG	0xf454
+#define	F367CAB_NYQPOINT_INV	0xf4540040
+#define	F367CAB_TRL_SHIFT	0xf4540030
+#define	F367CAB_NYQ_COEFF_SEL	0xf454000c
+#define	F367CAB_TRL_LPF_FREEZE	0xf4540002
+#define	F367CAB_TRL_LPF_CRT	0xf4540001
+
+/* TRL_LPF_ACQ_GAIN */
+#define	R367CAB_TRL_LPF_ACQ_GAIN	0xf455
+#define	F367CAB_TRL_GDIR_ACQ	0xf4550070
+#define	F367CAB_TRL_GINT_ACQ	0xf4550007
+
+/* TRL_LPF_TRK_GAIN */
+#define	R367CAB_TRL_LPF_TRK_GAIN	0xf456
+#define	F367CAB_TRL_GDIR_TRK	0xf4560070
+#define	F367CAB_TRL_GINT_TRK	0xf4560007
+
+/* TRL_LPF_OUT_GAIN */
+#define	R367CAB_TRL_LPF_OUT_GAIN	0xf457
+#define	F367CAB_TRL_GAIN_OUT	0xf4570007
+
+/* TRL_LOCKDET_LTH */
+#define	R367CAB_TRL_LOCKDET_LTH	0xf458
+#define	F367CAB_TRL_LCK_THLO	0xf4580007
+
+/* TRL_LOCKDET_HTH */
+#define	R367CAB_TRL_LOCKDET_HTH	0xf459
+#define	F367CAB_TRL_LCK_THHI	0xf45900ff
+
+/* TRL_LOCKDET_TRGVAL */
+#define	R367CAB_TRL_LOCKDET_TRGVAL	0xf45a
+#define	F367CAB_TRL_LCK_TRG	0xf45a00ff
+
+/* IQ_QAM */
+#define	R367CAB_IQ_QAM	0xf45c
+#define	F367CAB_IQ_INPUT	0xf45c0008
+#define	F367CAB_DETECT_MODE	0xf45c0007
+
+/* FSM_STATE */
+#define	R367CAB_FSM_STATE	0xf460
+#define	F367CAB_CRL_DFE	0xf4600080
+#define	F367CAB_DFE_START	0xf4600040
+#define	F367CAB_CTRLG_START	0xf4600030
+#define	F367CAB_FSM_FORCESTATE	0xf460000f
+
+/* FSM_CTL */
+#define	R367CAB_FSM_CTL	0xf461
+#define	F367CAB_FEC2_EN	0xf4610040
+#define	F367CAB_SIT_EN	0xf4610020
+#define	F367CAB_TRL_AHEAD	0xf4610010
+#define	F367CAB_TRL2_EN	0xf4610008
+#define	F367CAB_FSM_EQA1_EN	0xf4610004
+#define	F367CAB_FSM_BKP_DIS	0xf4610002
+#define	F367CAB_FSM_FORCE_EN	0xf4610001
+
+/* FSM_STS */
+#define	R367CAB_FSM_STS	0xf462
+#define	F367CAB_FSM_STATUS	0xf462000f
+
+/* FSM_SNR0_HTH */
+#define	R367CAB_FSM_SNR0_HTH	0xf463
+#define	F367CAB_SNR0_HTH	0xf46300ff
+
+/* FSM_SNR1_HTH */
+#define	R367CAB_FSM_SNR1_HTH	0xf464
+#define	F367CAB_SNR1_HTH	0xf46400ff
+
+/* FSM_SNR2_HTH */
+#define	R367CAB_FSM_SNR2_HTH	0xf465
+#define	F367CAB_SNR2_HTH	0xf46500ff
+
+/* FSM_SNR0_LTH */
+#define	R367CAB_FSM_SNR0_LTH	0xf466
+#define	F367CAB_SNR0_LTH	0xf46600ff
+
+/* FSM_SNR1_LTH */
+#define	R367CAB_FSM_SNR1_LTH	0xf467
+#define	F367CAB_SNR1_LTH	0xf46700ff
+
+/* FSM_EQA1_HTH */
+#define	R367CAB_FSM_EQA1_HTH	0xf468
+#define	F367CAB_SNR3_HTH_LO	0xf46800f0
+#define	F367CAB_EQA1_HTH	0xf468000f
+
+/* FSM_TEMPO */
+#define	R367CAB_FSM_TEMPO	0xf469
+#define	F367CAB_SIT	0xf46900c0
+#define	F367CAB_WST	0xf4690038
+#define	F367CAB_ELT	0xf4690006
+#define	F367CAB_SNR3_HTH_HI	0xf4690001
+
+/* FSM_CONFIG */
+#define	R367CAB_FSM_CONFIG	0xf46a
+#define	F367CAB_FEC2_DFEOFF	0xf46a0004
+#define	F367CAB_PRIT_STATE	0xf46a0002
+#define	F367CAB_MODMAP_STATE	0xf46a0001
+
+/* EQU_I_TESTTAP_L */
+#define	R367CAB_EQU_I_TESTTAP_L	0xf474
+#define	F367CAB_I_TEST_TAP_L	0xf47400ff
+
+/* EQU_I_TESTTAP_M */
+#define	R367CAB_EQU_I_TESTTAP_M	0xf475
+#define	F367CAB_I_TEST_TAP_M	0xf47500ff
+
+/* EQU_I_TESTTAP_H */
+#define	R367CAB_EQU_I_TESTTAP_H	0xf476
+#define	F367CAB_I_TEST_TAP_H	0xf476001f
+
+/* EQU_TESTAP_CFG */
+#define	R367CAB_EQU_TESTAP_CFG	0xf477
+#define	F367CAB_TEST_FFE_DFE_SEL	0xf4770040
+#define	F367CAB_TEST_TAP_SELECT	0xf477003f
+
+/* EQU_Q_TESTTAP_L */
+#define	R367CAB_EQU_Q_TESTTAP_L	0xf478
+#define	F367CAB_Q_TEST_TAP_L	0xf47800ff
+
+/* EQU_Q_TESTTAP_M */
+#define	R367CAB_EQU_Q_TESTTAP_M	0xf479
+#define	F367CAB_Q_TEST_TAP_M	0xf47900ff
+
+/* EQU_Q_TESTTAP_H */
+#define	R367CAB_EQU_Q_TESTTAP_H	0xf47a
+#define	F367CAB_Q_TEST_TAP_H	0xf47a001f
+
+/* EQU_TAP_CTRL */
+#define	R367CAB_EQU_TAP_CTRL	0xf47b
+#define	F367CAB_MTAP_FRZ	0xf47b0010
+#define	F367CAB_PRE_FREEZE	0xf47b0008
+#define	F367CAB_DFE_TAPMON_EN	0xf47b0004
+#define	F367CAB_FFE_TAPMON_EN	0xf47b0002
+#define	F367CAB_MTAP_ONLY	0xf47b0001
+
+/* EQU_CTR_CRL_CONTROL_L */
+#define	R367CAB_EQU_CTR_CRL_CONTROL_L	0xf47c
+#define	F367CAB_EQU_CTR_CRL_CONTROL_LO	0xf47c00ff
+
+/* EQU_CTR_CRL_CONTROL_H */
+#define	R367CAB_EQU_CTR_CRL_CONTROL_H	0xf47d
+#define	F367CAB_EQU_CTR_CRL_CONTROL_HI	0xf47d00ff
+
+/* EQU_CTR_HIPOW_L */
+#define	R367CAB_EQU_CTR_HIPOW_L	0xf47e
+#define	F367CAB_CTR_HIPOW_L	0xf47e00ff
+
+/* EQU_CTR_HIPOW_H */
+#define	R367CAB_EQU_CTR_HIPOW_H	0xf47f
+#define	F367CAB_CTR_HIPOW_H	0xf47f00ff
+
+/* EQU_I_EQU_LO */
+#define	R367CAB_EQU_I_EQU_LO	0xf480
+#define	F367CAB_EQU_I_EQU_L	0xf48000ff
+
+/* EQU_I_EQU_HI */
+#define	R367CAB_EQU_I_EQU_HI	0xf481
+#define	F367CAB_EQU_I_EQU_H	0xf4810003
+
+/* EQU_Q_EQU_LO */
+#define	R367CAB_EQU_Q_EQU_LO	0xf482
+#define	F367CAB_EQU_Q_EQU_L	0xf48200ff
+
+/* EQU_Q_EQU_HI */
+#define	R367CAB_EQU_Q_EQU_HI	0xf483
+#define	F367CAB_EQU_Q_EQU_H	0xf4830003
+
+/* EQU_MAPPER */
+#define	R367CAB_EQU_MAPPER	0xf484
+#define	F367CAB_QUAD_AUTO	0xf4840080
+#define	F367CAB_QUAD_INV	0xf4840040
+#define	F367CAB_QAM_MODE	0xf4840007
+
+/* EQU_SWEEP_RATE */
+#define	R367CAB_EQU_SWEEP_RATE	0xf485
+#define	F367CAB_SNR_PER	0xf48500c0
+#define	F367CAB_SWEEP_RATE	0xf485003f
+
+/* EQU_SNR_LO */
+#define	R367CAB_EQU_SNR_LO	0xf486
+#define	F367CAB_SNR_LO	0xf48600ff
+
+/* EQU_SNR_HI */
+#define	R367CAB_EQU_SNR_HI	0xf487
+#define	F367CAB_SNR_HI	0xf48700ff
+
+/* EQU_GAMMA_LO */
+#define	R367CAB_EQU_GAMMA_LO	0xf488
+#define	F367CAB_GAMMA_LO	0xf48800ff
+
+/* EQU_GAMMA_HI */
+#define	R367CAB_EQU_GAMMA_HI	0xf489
+#define	F367CAB_GAMMA_ME	0xf48900ff
+
+/* EQU_ERR_GAIN */
+#define	R367CAB_EQU_ERR_GAIN	0xf48a
+#define	F367CAB_EQA1MU	0xf48a0070
+#define	F367CAB_CRL2MU	0xf48a000e
+#define	F367CAB_GAMMA_HI	0xf48a0001
+
+/* EQU_RADIUS */
+#define	R367CAB_EQU_RADIUS	0xf48b
+#define	F367CAB_RADIUS	0xf48b00ff
+
+/* EQU_FFE_MAINTAP */
+#define	R367CAB_EQU_FFE_MAINTAP	0xf48c
+#define	F367CAB_FFE_MAINTAP_INIT	0xf48c00ff
+
+/* EQU_FFE_LEAKAGE */
+#define	R367CAB_EQU_FFE_LEAKAGE	0xf48e
+#define	F367CAB_LEAK_PER	0xf48e00f0
+#define	F367CAB_EQU_OUTSEL	0xf48e0002
+#define	F367CAB_PNT2dFE	0xf48e0001
+
+/* EQU_FFE_MAINTAP_POS */
+#define	R367CAB_EQU_FFE_MAINTAP_POS	0xf48f
+#define	F367CAB_FFE_LEAK_EN	0xf48f0080
+#define	F367CAB_DFE_LEAK_EN	0xf48f0040
+#define	F367CAB_FFE_MAINTAP_POS	0xf48f003f
+
+/* EQU_GAIN_WIDE */
+#define	R367CAB_EQU_GAIN_WIDE	0xf490
+#define	F367CAB_DFE_GAIN_WIDE	0xf49000f0
+#define	F367CAB_FFE_GAIN_WIDE	0xf490000f
+
+/* EQU_GAIN_NARROW */
+#define	R367CAB_EQU_GAIN_NARROW	0xf491
+#define	F367CAB_DFE_GAIN_NARROW	0xf49100f0
+#define	F367CAB_FFE_GAIN_NARROW	0xf491000f
+
+/* EQU_CTR_LPF_GAIN */
+#define	R367CAB_EQU_CTR_LPF_GAIN	0xf492
+#define	F367CAB_CTR_GTO	0xf4920080
+#define	F367CAB_CTR_GDIR	0xf4920070
+#define	F367CAB_SWEEP_EN	0xf4920008
+#define	F367CAB_CTR_GINT	0xf4920007
+
+/* EQU_CRL_LPF_GAIN */
+#define	R367CAB_EQU_CRL_LPF_GAIN	0xf493
+#define	F367CAB_CRL_GTO	0xf4930080
+#define	F367CAB_CRL_GDIR	0xf4930070
+#define	F367CAB_SWEEP_DIR	0xf4930008
+#define	F367CAB_CRL_GINT	0xf4930007
+
+/* EQU_GLOBAL_GAIN */
+#define	R367CAB_EQU_GLOBAL_GAIN	0xf494
+#define	F367CAB_CRL_GAIN	0xf49400f8
+#define	F367CAB_CTR_INC_GAIN	0xf4940004
+#define	F367CAB_CTR_FRAC	0xf4940003
+
+/* EQU_CRL_LD_SEN */
+#define	R367CAB_EQU_CRL_LD_SEN	0xf495
+#define	F367CAB_CTR_BADPOINT_EN	0xf4950080
+#define	F367CAB_CTR_GAIN	0xf4950070
+#define	F367CAB_LIMANEN	0xf4950008
+#define	F367CAB_CRL_LD_SEN	0xf4950007
+
+/* EQU_CRL_LD_VAL */
+#define	R367CAB_EQU_CRL_LD_VAL	0xf496
+#define	F367CAB_CRL_BISTH_LIMIT	0xf4960080
+#define	F367CAB_CARE_EN	0xf4960040
+#define	F367CAB_CRL_LD_PER	0xf4960030
+#define	F367CAB_CRL_LD_WST	0xf496000c
+#define	F367CAB_CRL_LD_TFS	0xf4960003
+
+/* EQU_CRL_TFR */
+#define	R367CAB_EQU_CRL_TFR	0xf497
+#define	F367CAB_CRL_LD_TFR	0xf49700ff
+
+/* EQU_CRL_BISTH_LO */
+#define	R367CAB_EQU_CRL_BISTH_LO	0xf498
+#define	F367CAB_CRL_BISTH_LO	0xf49800ff
+
+/* EQU_CRL_BISTH_HI */
+#define	R367CAB_EQU_CRL_BISTH_HI	0xf499
+#define	F367CAB_CRL_BISTH_HI	0xf49900ff
+
+/* EQU_SWEEP_RANGE_LO */
+#define	R367CAB_EQU_SWEEP_RANGE_LO	0xf49a
+#define	F367CAB_SWEEP_RANGE_LO	0xf49a00ff
+
+/* EQU_SWEEP_RANGE_HI */
+#define	R367CAB_EQU_SWEEP_RANGE_HI	0xf49b
+#define	F367CAB_SWEEP_RANGE_HI	0xf49b00ff
+
+/* EQU_CRL_LIMITER */
+#define	R367CAB_EQU_CRL_LIMITER	0xf49c
+#define	F367CAB_BISECTOR_EN	0xf49c0080
+#define	F367CAB_PHEST128_EN	0xf49c0040
+#define	F367CAB_CRL_LIM	0xf49c003f
+
+/* EQU_MODULUS_MAP */
+#define	R367CAB_EQU_MODULUS_MAP	0xf49d
+#define	F367CAB_PNT_DEPTH	0xf49d00e0
+#define	F367CAB_MODULUS_CMP	0xf49d001f
+
+/* EQU_PNT_GAIN */
+#define	R367CAB_EQU_PNT_GAIN	0xf49e
+#define	F367CAB_PNT_EN	0xf49e0080
+#define	F367CAB_MODULUSMAP_EN	0xf49e0040
+#define	F367CAB_PNT_GAIN	0xf49e003f
+
+/* FEC_AC_CTR_0 */
+#define	R367CAB_FEC_AC_CTR_0	0xf4a8
+#define	F367CAB_BE_BYPASS	0xf4a80020
+#define	F367CAB_REFRESH47	0xf4a80010
+#define	F367CAB_CT_NBST	0xf4a80008
+#define	F367CAB_TEI_ENA	0xf4a80004
+#define	F367CAB_DS_ENA	0xf4a80002
+#define	F367CAB_TSMF_EN	0xf4a80001
+
+/* FEC_AC_CTR_1 */
+#define	R367CAB_FEC_AC_CTR_1	0xf4a9
+#define	F367CAB_DEINT_DEPTH	0xf4a900ff
+
+/* FEC_AC_CTR_2 */
+#define	R367CAB_FEC_AC_CTR_2	0xf4aa
+#define	F367CAB_DEINT_M	0xf4aa00f8
+#define	F367CAB_DIS_UNLOCK	0xf4aa0004
+#define	F367CAB_DESCR_MODE	0xf4aa0003
+
+/* FEC_AC_CTR_3 */
+#define	R367CAB_FEC_AC_CTR_3	0xf4ab
+#define	F367CAB_DI_UNLOCK	0xf4ab0080
+#define	F367CAB_DI_FREEZE	0xf4ab0040
+#define	F367CAB_MISMATCH	0xf4ab0030
+#define	F367CAB_ACQ_MODE	0xf4ab000c
+#define	F367CAB_TRK_MODE	0xf4ab0003
+
+/* FEC_STATUS */
+#define	R367CAB_FEC_STATUS	0xf4ac
+#define	F367CAB_DEINT_SMCNTR	0xf4ac00e0
+#define	F367CAB_DEINT_SYNCSTATE	0xf4ac0018
+#define	F367CAB_DEINT_SYNLOST	0xf4ac0004
+#define	F367CAB_DESCR_SYNCSTATE	0xf4ac0002
+
+/* RS_COUNTER_0 */
+#define	R367CAB_RS_COUNTER_0	0xf4ae
+#define	F367CAB_BK_CT_L	0xf4ae00ff
+
+/* RS_COUNTER_1 */
+#define	R367CAB_RS_COUNTER_1	0xf4af
+#define	F367CAB_BK_CT_H	0xf4af00ff
+
+/* RS_COUNTER_2 */
+#define	R367CAB_RS_COUNTER_2	0xf4b0
+#define	F367CAB_CORR_CT_L	0xf4b000ff
+
+/* RS_COUNTER_3 */
+#define	R367CAB_RS_COUNTER_3	0xf4b1
+#define	F367CAB_CORR_CT_H	0xf4b100ff
+
+/* RS_COUNTER_4 */
+#define	R367CAB_RS_COUNTER_4	0xf4b2
+#define	F367CAB_UNCORR_CT_L	0xf4b200ff
+
+/* RS_COUNTER_5 */
+#define	R367CAB_RS_COUNTER_5	0xf4b3
+#define	F367CAB_UNCORR_CT_H	0xf4b300ff
+
+/* BERT_0 */
+#define	R367CAB_BERT_0	0xf4b4
+#define	F367CAB_RS_NOCORR	0xf4b40004
+#define	F367CAB_CT_HOLD	0xf4b40002
+#define	F367CAB_CT_CLEAR	0xf4b40001
+
+/* BERT_1 */
+#define	R367CAB_BERT_1	0xf4b5
+#define	F367CAB_BERT_ON	0xf4b50020
+#define	F367CAB_BERT_ERR_SRC	0xf4b50010
+#define	F367CAB_BERT_ERR_MODE	0xf4b50008
+#define	F367CAB_BERT_NBYTE	0xf4b50007
+
+/* BERT_2 */
+#define	R367CAB_BERT_2	0xf4b6
+#define	F367CAB_BERT_ERRCOUNT_L	0xf4b600ff
+
+/* BERT_3 */
+#define	R367CAB_BERT_3	0xf4b7
+#define	F367CAB_BERT_ERRCOUNT_H	0xf4b700ff
+
+/* OUTFORMAT_0 */
+#define	R367CAB_OUTFORMAT_0	0xf4b8
+#define	F367CAB_CLK_POLARITY	0xf4b80080
+#define	F367CAB_FEC_TYPE	0xf4b80040
+#define	F367CAB_SYNC_STRIP	0xf4b80008
+#define	F367CAB_TS_SWAP	0xf4b80004
+#define	F367CAB_OUTFORMAT	0xf4b80003
+
+/* OUTFORMAT_1 */
+#define	R367CAB_OUTFORMAT_1	0xf4b9
+#define	F367CAB_CI_DIVRANGE	0xf4b900ff
+
+/* SMOOTHER_2 */
+#define	R367CAB_SMOOTHER_2	0xf4be
+#define	F367CAB_FIFO_BYPASS	0xf4be0020
+
+/* TSMF_CTRL_0 */
+#define	R367CAB_TSMF_CTRL_0	0xf4c0
+#define	F367CAB_TS_NUMBER	0xf4c0001e
+#define	F367CAB_SEL_MODE	0xf4c00001
+
+/* TSMF_CTRL_1 */
+#define	R367CAB_TSMF_CTRL_1	0xf4c1
+#define	F367CAB_CHECK_ERROR_BIT	0xf4c10080
+#define	F367CAB_CHCK_F_SYNC	0xf4c10040
+#define	F367CAB_H_MODE	0xf4c10008
+#define	F367CAB_D_V_MODE	0xf4c10004
+#define	F367CAB_MODE	0xf4c10003
+
+/* TSMF_CTRL_3 */
+#define	R367CAB_TSMF_CTRL_3	0xf4c3
+#define	F367CAB_SYNC_IN_COUNT	0xf4c300f0
+#define	F367CAB_SYNC_OUT_COUNT	0xf4c3000f
+
+/* TS_ON_ID_0 */
+#define	R367CAB_TS_ON_ID_0	0xf4c4
+#define	F367CAB_TS_ID_L	0xf4c400ff
+
+/* TS_ON_ID_1 */
+#define	R367CAB_TS_ON_ID_1	0xf4c5
+#define	F367CAB_TS_ID_H	0xf4c500ff
+
+/* TS_ON_ID_2 */
+#define	R367CAB_TS_ON_ID_2	0xf4c6
+#define	F367CAB_ON_ID_L	0xf4c600ff
+
+/* TS_ON_ID_3 */
+#define	R367CAB_TS_ON_ID_3	0xf4c7
+#define	F367CAB_ON_ID_H	0xf4c700ff
+
+/* RE_STATUS_0 */
+#define	R367CAB_RE_STATUS_0	0xf4c8
+#define	F367CAB_RECEIVE_STATUS_L	0xf4c800ff
+
+/* RE_STATUS_1 */
+#define	R367CAB_RE_STATUS_1	0xf4c9
+#define	F367CAB_RECEIVE_STATUS_LH	0xf4c900ff
+
+/* RE_STATUS_2 */
+#define	R367CAB_RE_STATUS_2	0xf4ca
+#define	F367CAB_RECEIVE_STATUS_HL	0xf4ca00ff
+
+/* RE_STATUS_3 */
+#define	R367CAB_RE_STATUS_3	0xf4cb
+#define	F367CAB_RECEIVE_STATUS_HH	0xf4cb003f
+
+/* TS_STATUS_0 */
+#define	R367CAB_TS_STATUS_0	0xf4cc
+#define	F367CAB_TS_STATUS_L	0xf4cc00ff
+
+/* TS_STATUS_1 */
+#define	R367CAB_TS_STATUS_1	0xf4cd
+#define	F367CAB_TS_STATUS_H	0xf4cd007f
+
+/* TS_STATUS_2 */
+#define	R367CAB_TS_STATUS_2	0xf4ce
+#define	F367CAB_ERROR	0xf4ce0080
+#define	F367CAB_EMERGENCY	0xf4ce0040
+#define	F367CAB_CRE_TS	0xf4ce0030
+#define	F367CAB_VER	0xf4ce000e
+#define	F367CAB_M_LOCK	0xf4ce0001
+
+/* TS_STATUS_3 */
+#define	R367CAB_TS_STATUS_3	0xf4cf
+#define	F367CAB_UPDATE_READY	0xf4cf0080
+#define	F367CAB_END_FRAME_HEADER	0xf4cf0040
+#define	F367CAB_CONTCNT	0xf4cf0020
+#define	F367CAB_TS_IDENTIFIER_SEL	0xf4cf000f
+
+/* T_O_ID_0 */
+#define	R367CAB_T_O_ID_0	0xf4d0
+#define	F367CAB_ON_ID_I_L	0xf4d000ff
+
+/* T_O_ID_1 */
+#define	R367CAB_T_O_ID_1	0xf4d1
+#define	F367CAB_ON_ID_I_H	0xf4d100ff
+
+/* T_O_ID_2 */
+#define	R367CAB_T_O_ID_2	0xf4d2
+#define	F367CAB_TS_ID_I_L	0xf4d200ff
+
+/* T_O_ID_3 */
+#define	R367CAB_T_O_ID_3	0xf4d3
+#define	F367CAB_TS_ID_I_H	0xf4d300ff
+
+#define STV0367CAB_NBREGS	187
+
+#endif
diff --git a/drivers/media/dvb-frontends/stv0900.h b/drivers/media/dvb-frontends/stv0900.h
new file mode 100644
index 0000000..91c7ee8
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv0900.h
@@ -0,0 +1,74 @@
+/*
+ * stv0900.h
+ *
+ * Driver for ST STV0900 satellite demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef STV0900_H
+#define STV0900_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct stv0900_reg {
+	u16 addr;
+	u8  val;
+};
+
+struct stv0900_config {
+	u8 demod_address;
+	u8 demod_mode;
+	u32 xtal;
+	u8 clkmode;/* 0 for CLKI,  2 for XTALI */
+
+	u8 diseqc_mode;
+
+	u8 path1_mode;
+	u8 path2_mode;
+	struct stv0900_reg *ts_config_regs;
+	u8 tun1_maddress;/* 0, 1, 2, 3 for 0xc0, 0xc2, 0xc4, 0xc6 */
+	u8 tun2_maddress;
+	u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */
+	u8 tun2_adc;
+	u8 tun1_type;/* for now 3 for stb6100 auto, else - software */
+	u8 tun2_type;
+	/* Set device param to start dma */
+	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
+	/* Hook for Lock LED */
+	void (*set_lock_led)(struct dvb_frontend *fe, int offon);
+};
+
+#if defined(CONFIG_DVB_STV0900) || (defined(CONFIG_DVB_STV0900_MODULE) \
+							&& defined(MODULE))
+extern struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
+					struct i2c_adapter *i2c, int demod);
+#else
+static inline struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
+					struct i2c_adapter *i2c, int demod)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
+
diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c
new file mode 100644
index 0000000..7f1bada
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv0900_core.c
@@ -0,0 +1,1959 @@
+/*
+ * stv0900_core.c
+ *
+ * Driver for ST STV0900 satellite demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+
+#include "stv0900.h"
+#include "stv0900_reg.h"
+#include "stv0900_priv.h"
+#include "stv0900_init.h"
+
+int stvdebug = 1;
+module_param_named(debug, stvdebug, int, 0644);
+
+/* internal params node */
+struct stv0900_inode {
+	/* pointer for internal params, one for each pair of demods */
+	struct stv0900_internal		*internal;
+	struct stv0900_inode		*next_inode;
+};
+
+/* first internal params */
+static struct stv0900_inode *stv0900_first_inode;
+
+/* find chip by i2c adapter and i2c address */
+static struct stv0900_inode *find_inode(struct i2c_adapter *i2c_adap,
+							u8 i2c_addr)
+{
+	struct stv0900_inode *temp_chip = stv0900_first_inode;
+
+	if (temp_chip != NULL) {
+		/*
+		 Search of the last stv0900 chip or
+		 find it by i2c adapter and i2c address */
+		while ((temp_chip != NULL) &&
+			((temp_chip->internal->i2c_adap != i2c_adap) ||
+			(temp_chip->internal->i2c_addr != i2c_addr)))
+
+			temp_chip = temp_chip->next_inode;
+
+	}
+
+	return temp_chip;
+}
+
+/* deallocating chip */
+static void remove_inode(struct stv0900_internal *internal)
+{
+	struct stv0900_inode *prev_node = stv0900_first_inode;
+	struct stv0900_inode *del_node = find_inode(internal->i2c_adap,
+						internal->i2c_addr);
+
+	if (del_node != NULL) {
+		if (del_node == stv0900_first_inode) {
+			stv0900_first_inode = del_node->next_inode;
+		} else {
+			while (prev_node->next_inode != del_node)
+				prev_node = prev_node->next_inode;
+
+			if (del_node->next_inode == NULL)
+				prev_node->next_inode = NULL;
+			else
+				prev_node->next_inode =
+					prev_node->next_inode->next_inode;
+		}
+
+		kfree(del_node);
+	}
+}
+
+/* allocating new chip */
+static struct stv0900_inode *append_internal(struct stv0900_internal *internal)
+{
+	struct stv0900_inode *new_node = stv0900_first_inode;
+
+	if (new_node == NULL) {
+		new_node = kmalloc(sizeof(struct stv0900_inode), GFP_KERNEL);
+		stv0900_first_inode = new_node;
+	} else {
+		while (new_node->next_inode != NULL)
+			new_node = new_node->next_inode;
+
+		new_node->next_inode = kmalloc(sizeof(struct stv0900_inode),
+								GFP_KERNEL);
+		if (new_node->next_inode != NULL)
+			new_node = new_node->next_inode;
+		else
+			new_node = NULL;
+	}
+
+	if (new_node != NULL) {
+		new_node->internal = internal;
+		new_node->next_inode = NULL;
+	}
+
+	return new_node;
+}
+
+s32 ge2comp(s32 a, s32 width)
+{
+	if (width == 32)
+		return a;
+	else
+		return (a >= (1 << (width - 1))) ? (a - (1 << width)) : a;
+}
+
+void stv0900_write_reg(struct stv0900_internal *intp, u16 reg_addr,
+								u8 reg_data)
+{
+	u8 data[3];
+	int ret;
+	struct i2c_msg i2cmsg = {
+		.addr  = intp->i2c_addr,
+		.flags = 0,
+		.len   = 3,
+		.buf   = data,
+	};
+
+	data[0] = MSB(reg_addr);
+	data[1] = LSB(reg_addr);
+	data[2] = reg_data;
+
+	ret = i2c_transfer(intp->i2c_adap, &i2cmsg, 1);
+	if (ret != 1)
+		dprintk("%s: i2c error %d\n", __func__, ret);
+}
+
+u8 stv0900_read_reg(struct stv0900_internal *intp, u16 reg)
+{
+	int ret;
+	u8 b0[] = { MSB(reg), LSB(reg) };
+	u8 buf = 0;
+	struct i2c_msg msg[] = {
+		{
+			.addr	= intp->i2c_addr,
+			.flags	= 0,
+			.buf = b0,
+			.len = 2,
+		}, {
+			.addr	= intp->i2c_addr,
+			.flags	= I2C_M_RD,
+			.buf = &buf,
+			.len = 1,
+		},
+	};
+
+	ret = i2c_transfer(intp->i2c_adap, msg, 2);
+	if (ret != 2)
+		dprintk("%s: i2c error %d, reg[0x%02x]\n",
+				__func__, ret, reg);
+
+	return buf;
+}
+
+static void extract_mask_pos(u32 label, u8 *mask, u8 *pos)
+{
+	u8 position = 0, i = 0;
+
+	(*mask) = label & 0xff;
+
+	while ((position == 0) && (i < 8)) {
+		position = ((*mask) >> i) & 0x01;
+		i++;
+	}
+
+	(*pos) = (i - 1);
+}
+
+void stv0900_write_bits(struct stv0900_internal *intp, u32 label, u8 val)
+{
+	u8 reg, mask, pos;
+
+	reg = stv0900_read_reg(intp, (label >> 16) & 0xffff);
+	extract_mask_pos(label, &mask, &pos);
+
+	val = mask & (val << pos);
+
+	reg = (reg & (~mask)) | val;
+	stv0900_write_reg(intp, (label >> 16) & 0xffff, reg);
+
+}
+
+u8 stv0900_get_bits(struct stv0900_internal *intp, u32 label)
+{
+	u8 val = 0xff;
+	u8 mask, pos;
+
+	extract_mask_pos(label, &mask, &pos);
+
+	val = stv0900_read_reg(intp, label >> 16);
+	val = (val & mask) >> pos;
+
+	return val;
+}
+
+static enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *intp)
+{
+	s32 i;
+
+	if (intp == NULL)
+		return STV0900_INVALID_HANDLE;
+
+	intp->chip_id = stv0900_read_reg(intp, R0900_MID);
+
+	if (intp->errs != STV0900_NO_ERROR)
+		return intp->errs;
+
+	/*Startup sequence*/
+	stv0900_write_reg(intp, R0900_P1_DMDISTATE, 0x5c);
+	stv0900_write_reg(intp, R0900_P2_DMDISTATE, 0x5c);
+	msleep(3);
+	stv0900_write_reg(intp, R0900_P1_TNRCFG, 0x6c);
+	stv0900_write_reg(intp, R0900_P2_TNRCFG, 0x6f);
+	stv0900_write_reg(intp, R0900_P1_I2CRPT, 0x20);
+	stv0900_write_reg(intp, R0900_P2_I2CRPT, 0x20);
+	stv0900_write_reg(intp, R0900_NCOARSE, 0x13);
+	msleep(3);
+	stv0900_write_reg(intp, R0900_I2CCFG, 0x08);
+
+	switch (intp->clkmode) {
+	case 0:
+	case 2:
+		stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20
+				| intp->clkmode);
+		break;
+	default:
+		/* preserve SELOSCI bit */
+		i = 0x02 & stv0900_read_reg(intp, R0900_SYNTCTRL);
+		stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20 | i);
+		break;
+	}
+
+	msleep(3);
+	for (i = 0; i < 181; i++)
+		stv0900_write_reg(intp, STV0900_InitVal[i][0],
+				STV0900_InitVal[i][1]);
+
+	if (stv0900_read_reg(intp, R0900_MID) >= 0x20) {
+		stv0900_write_reg(intp, R0900_TSGENERAL, 0x0c);
+		for (i = 0; i < 32; i++)
+			stv0900_write_reg(intp, STV0900_Cut20_AddOnVal[i][0],
+					STV0900_Cut20_AddOnVal[i][1]);
+	}
+
+	stv0900_write_reg(intp, R0900_P1_FSPYCFG, 0x6c);
+	stv0900_write_reg(intp, R0900_P2_FSPYCFG, 0x6c);
+
+	stv0900_write_reg(intp, R0900_P1_PDELCTRL2, 0x01);
+	stv0900_write_reg(intp, R0900_P2_PDELCTRL2, 0x21);
+
+	stv0900_write_reg(intp, R0900_P1_PDELCTRL3, 0x20);
+	stv0900_write_reg(intp, R0900_P2_PDELCTRL3, 0x20);
+
+	stv0900_write_reg(intp, R0900_TSTRES0, 0x80);
+	stv0900_write_reg(intp, R0900_TSTRES0, 0x00);
+
+	return STV0900_NO_ERROR;
+}
+
+static u32 stv0900_get_mclk_freq(struct stv0900_internal *intp, u32 ext_clk)
+{
+	u32 mclk = 90000000, div = 0, ad_div = 0;
+
+	div = stv0900_get_bits(intp, F0900_M_DIV);
+	ad_div = ((stv0900_get_bits(intp, F0900_SELX1RATIO) == 1) ? 4 : 6);
+
+	mclk = (div + 1) * ext_clk / ad_div;
+
+	dprintk("%s: Calculated Mclk = %d\n", __func__, mclk);
+
+	return mclk;
+}
+
+static enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *intp, u32 mclk)
+{
+	u32 m_div, clk_sel;
+
+	dprintk("%s: Mclk set to %d, Quartz = %d\n", __func__, mclk,
+			intp->quartz);
+
+	if (intp == NULL)
+		return STV0900_INVALID_HANDLE;
+
+	if (intp->errs)
+		return STV0900_I2C_ERROR;
+
+	clk_sel = ((stv0900_get_bits(intp, F0900_SELX1RATIO) == 1) ? 4 : 6);
+	m_div = ((clk_sel * mclk) / intp->quartz) - 1;
+	stv0900_write_bits(intp, F0900_M_DIV, m_div);
+	intp->mclk = stv0900_get_mclk_freq(intp,
+					intp->quartz);
+
+	/*Set the DiseqC frequency to 22KHz */
+	/*
+		Formula:
+		DiseqC_TX_Freq= MasterClock/(32*F22TX_Reg)
+		DiseqC_RX_Freq= MasterClock/(32*F22RX_Reg)
+	*/
+	m_div = intp->mclk / 704000;
+	stv0900_write_reg(intp, R0900_P1_F22TX, m_div);
+	stv0900_write_reg(intp, R0900_P1_F22RX, m_div);
+
+	stv0900_write_reg(intp, R0900_P2_F22TX, m_div);
+	stv0900_write_reg(intp, R0900_P2_F22RX, m_div);
+
+	if ((intp->errs))
+		return STV0900_I2C_ERROR;
+
+	return STV0900_NO_ERROR;
+}
+
+static u32 stv0900_get_err_count(struct stv0900_internal *intp, int cntr,
+					enum fe_stv0900_demod_num demod)
+{
+	u32 lsb, msb, hsb, err_val;
+
+	switch (cntr) {
+	case 0:
+	default:
+		hsb = stv0900_get_bits(intp, ERR_CNT12);
+		msb = stv0900_get_bits(intp, ERR_CNT11);
+		lsb = stv0900_get_bits(intp, ERR_CNT10);
+		break;
+	case 1:
+		hsb = stv0900_get_bits(intp, ERR_CNT22);
+		msb = stv0900_get_bits(intp, ERR_CNT21);
+		lsb = stv0900_get_bits(intp, ERR_CNT20);
+		break;
+	}
+
+	err_val = (hsb << 16) + (msb << 8) + (lsb);
+
+	return err_val;
+}
+
+static int stv0900_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+
+	stv0900_write_bits(intp, I2CT_ON, enable);
+
+	return 0;
+}
+
+static void stv0900_set_ts_parallel_serial(struct stv0900_internal *intp,
+					enum fe_stv0900_clock_type path1_ts,
+					enum fe_stv0900_clock_type path2_ts)
+{
+
+	dprintk("%s\n", __func__);
+
+	if (intp->chip_id >= 0x20) {
+		switch (path1_ts) {
+		case STV0900_PARALLEL_PUNCT_CLOCK:
+		case STV0900_DVBCI_CLOCK:
+			switch (path2_ts) {
+			case STV0900_SERIAL_PUNCT_CLOCK:
+			case STV0900_SERIAL_CONT_CLOCK:
+			default:
+				stv0900_write_reg(intp, R0900_TSGENERAL,
+							0x00);
+				break;
+			case STV0900_PARALLEL_PUNCT_CLOCK:
+			case STV0900_DVBCI_CLOCK:
+				stv0900_write_reg(intp, R0900_TSGENERAL,
+							0x06);
+				stv0900_write_bits(intp,
+						F0900_P1_TSFIFO_MANSPEED, 3);
+				stv0900_write_bits(intp,
+						F0900_P2_TSFIFO_MANSPEED, 0);
+				stv0900_write_reg(intp,
+						R0900_P1_TSSPEED, 0x14);
+				stv0900_write_reg(intp,
+						R0900_P2_TSSPEED, 0x28);
+				break;
+			}
+			break;
+		case STV0900_SERIAL_PUNCT_CLOCK:
+		case STV0900_SERIAL_CONT_CLOCK:
+		default:
+			switch (path2_ts) {
+			case STV0900_SERIAL_PUNCT_CLOCK:
+			case STV0900_SERIAL_CONT_CLOCK:
+			default:
+				stv0900_write_reg(intp,
+						R0900_TSGENERAL, 0x0C);
+				break;
+			case STV0900_PARALLEL_PUNCT_CLOCK:
+			case STV0900_DVBCI_CLOCK:
+				stv0900_write_reg(intp,
+						R0900_TSGENERAL, 0x0A);
+				dprintk("%s: 0x0a\n", __func__);
+				break;
+			}
+			break;
+		}
+	} else {
+		switch (path1_ts) {
+		case STV0900_PARALLEL_PUNCT_CLOCK:
+		case STV0900_DVBCI_CLOCK:
+			switch (path2_ts) {
+			case STV0900_SERIAL_PUNCT_CLOCK:
+			case STV0900_SERIAL_CONT_CLOCK:
+			default:
+				stv0900_write_reg(intp, R0900_TSGENERAL1X,
+							0x10);
+				break;
+			case STV0900_PARALLEL_PUNCT_CLOCK:
+			case STV0900_DVBCI_CLOCK:
+				stv0900_write_reg(intp, R0900_TSGENERAL1X,
+							0x16);
+				stv0900_write_bits(intp,
+						F0900_P1_TSFIFO_MANSPEED, 3);
+				stv0900_write_bits(intp,
+						F0900_P2_TSFIFO_MANSPEED, 0);
+				stv0900_write_reg(intp, R0900_P1_TSSPEED,
+							0x14);
+				stv0900_write_reg(intp, R0900_P2_TSSPEED,
+							0x28);
+				break;
+			}
+
+			break;
+		case STV0900_SERIAL_PUNCT_CLOCK:
+		case STV0900_SERIAL_CONT_CLOCK:
+		default:
+			switch (path2_ts) {
+			case STV0900_SERIAL_PUNCT_CLOCK:
+			case STV0900_SERIAL_CONT_CLOCK:
+			default:
+				stv0900_write_reg(intp, R0900_TSGENERAL1X,
+							0x14);
+				break;
+			case STV0900_PARALLEL_PUNCT_CLOCK:
+			case STV0900_DVBCI_CLOCK:
+				stv0900_write_reg(intp, R0900_TSGENERAL1X,
+							0x12);
+				dprintk("%s: 0x12\n", __func__);
+				break;
+			}
+
+			break;
+		}
+	}
+
+	switch (path1_ts) {
+	case STV0900_PARALLEL_PUNCT_CLOCK:
+		stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x00);
+		stv0900_write_bits(intp, F0900_P1_TSFIFO_DVBCI, 0x00);
+		break;
+	case STV0900_DVBCI_CLOCK:
+		stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x00);
+		stv0900_write_bits(intp, F0900_P1_TSFIFO_DVBCI, 0x01);
+		break;
+	case STV0900_SERIAL_PUNCT_CLOCK:
+		stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x01);
+		stv0900_write_bits(intp, F0900_P1_TSFIFO_DVBCI, 0x00);
+		break;
+	case STV0900_SERIAL_CONT_CLOCK:
+		stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x01);
+		stv0900_write_bits(intp, F0900_P1_TSFIFO_DVBCI, 0x01);
+		break;
+	default:
+		break;
+	}
+
+	switch (path2_ts) {
+	case STV0900_PARALLEL_PUNCT_CLOCK:
+		stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x00);
+		stv0900_write_bits(intp, F0900_P2_TSFIFO_DVBCI, 0x00);
+		break;
+	case STV0900_DVBCI_CLOCK:
+		stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x00);
+		stv0900_write_bits(intp, F0900_P2_TSFIFO_DVBCI, 0x01);
+		break;
+	case STV0900_SERIAL_PUNCT_CLOCK:
+		stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x01);
+		stv0900_write_bits(intp, F0900_P2_TSFIFO_DVBCI, 0x00);
+		break;
+	case STV0900_SERIAL_CONT_CLOCK:
+		stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x01);
+		stv0900_write_bits(intp, F0900_P2_TSFIFO_DVBCI, 0x01);
+		break;
+	default:
+		break;
+	}
+
+	stv0900_write_bits(intp, F0900_P2_RST_HWARE, 1);
+	stv0900_write_bits(intp, F0900_P2_RST_HWARE, 0);
+	stv0900_write_bits(intp, F0900_P1_RST_HWARE, 1);
+	stv0900_write_bits(intp, F0900_P1_RST_HWARE, 0);
+}
+
+void stv0900_set_tuner(struct dvb_frontend *fe, u32 frequency,
+							u32 bandwidth)
+{
+	struct dvb_frontend_ops *frontend_ops = NULL;
+	struct dvb_tuner_ops *tuner_ops = NULL;
+
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+
+	if (tuner_ops->set_frequency) {
+		if ((tuner_ops->set_frequency(fe, frequency)) < 0)
+			dprintk("%s: Invalid parameter\n", __func__);
+		else
+			dprintk("%s: Frequency=%d\n", __func__, frequency);
+
+	}
+
+	if (tuner_ops->set_bandwidth) {
+		if ((tuner_ops->set_bandwidth(fe, bandwidth)) < 0)
+			dprintk("%s: Invalid parameter\n", __func__);
+		else
+			dprintk("%s: Bandwidth=%d\n", __func__, bandwidth);
+
+	}
+}
+
+void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
+{
+	struct dvb_frontend_ops *frontend_ops = NULL;
+	struct dvb_tuner_ops *tuner_ops = NULL;
+
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+
+	if (tuner_ops->set_bandwidth) {
+		if ((tuner_ops->set_bandwidth(fe, bandwidth)) < 0)
+			dprintk("%s: Invalid parameter\n", __func__);
+		else
+			dprintk("%s: Bandwidth=%d\n", __func__, bandwidth);
+
+	}
+}
+
+u32 stv0900_get_freq_auto(struct stv0900_internal *intp, int demod)
+{
+	u32 freq, round;
+	/*	Formulat :
+	Tuner_Frequency(MHz)	= Regs / 64
+	Tuner_granularity(MHz)	= Regs / 2048
+	real_Tuner_Frequency	= Tuner_Frequency(MHz) - Tuner_granularity(MHz)
+	*/
+	freq = (stv0900_get_bits(intp, TUN_RFFREQ2) << 10) +
+		(stv0900_get_bits(intp, TUN_RFFREQ1) << 2) +
+		stv0900_get_bits(intp, TUN_RFFREQ0);
+
+	freq = (freq * 1000) / 64;
+
+	round = (stv0900_get_bits(intp, TUN_RFRESTE1) >> 2) +
+		stv0900_get_bits(intp, TUN_RFRESTE0);
+
+	round = (round * 1000) / 2048;
+
+	return freq + round;
+}
+
+void stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency,
+						u32 Bandwidth, int demod)
+{
+	u32 tunerFrequency;
+	/* Formulat:
+	Tuner_frequency_reg= Frequency(MHz)*64
+	*/
+	tunerFrequency = (Frequency * 64) / 1000;
+
+	stv0900_write_bits(intp, TUN_RFFREQ2, (tunerFrequency >> 10));
+	stv0900_write_bits(intp, TUN_RFFREQ1, (tunerFrequency >> 2) & 0xff);
+	stv0900_write_bits(intp, TUN_RFFREQ0, (tunerFrequency & 0x03));
+	/* Low Pass Filter = BW /2 (MHz)*/
+	stv0900_write_bits(intp, TUN_BW, Bandwidth / 2000000);
+	/* Tuner Write trig */
+	stv0900_write_reg(intp, TNRLD, 1);
+}
+
+static s32 stv0900_get_rf_level(struct stv0900_internal *intp,
+				const struct stv0900_table *lookup,
+				enum fe_stv0900_demod_num demod)
+{
+	s32 agc_gain = 0,
+		imin,
+		imax,
+		i,
+		rf_lvl = 0;
+
+	dprintk("%s\n", __func__);
+
+	if ((lookup == NULL) || (lookup->size <= 0))
+		return 0;
+
+	agc_gain = MAKEWORD(stv0900_get_bits(intp, AGCIQ_VALUE1),
+				stv0900_get_bits(intp, AGCIQ_VALUE0));
+
+	imin = 0;
+	imax = lookup->size - 1;
+	if (INRANGE(lookup->table[imin].regval, agc_gain,
+					lookup->table[imax].regval)) {
+		while ((imax - imin) > 1) {
+			i = (imax + imin) >> 1;
+
+			if (INRANGE(lookup->table[imin].regval,
+					agc_gain,
+					lookup->table[i].regval))
+				imax = i;
+			else
+				imin = i;
+		}
+
+		rf_lvl = (s32)agc_gain - lookup->table[imin].regval;
+		rf_lvl *= (lookup->table[imax].realval -
+				lookup->table[imin].realval);
+		rf_lvl /= (lookup->table[imax].regval -
+				lookup->table[imin].regval);
+		rf_lvl += lookup->table[imin].realval;
+	} else if (agc_gain > lookup->table[0].regval)
+		rf_lvl = 5;
+	else if (agc_gain < lookup->table[lookup->size-1].regval)
+		rf_lvl = -100;
+
+	dprintk("%s: RFLevel = %d\n", __func__, rf_lvl);
+
+	return rf_lvl;
+}
+
+static int stv0900_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *internal = state->internal;
+	s32 rflevel = stv0900_get_rf_level(internal, &stv0900_rf,
+								state->demod);
+
+	rflevel = (rflevel + 100) * (65535 / 70);
+	if (rflevel < 0)
+		rflevel = 0;
+
+	if (rflevel > 65535)
+		rflevel = 65535;
+
+	*strength = rflevel;
+
+	return 0;
+}
+
+static s32 stv0900_carr_get_quality(struct dvb_frontend *fe,
+					const struct stv0900_table *lookup)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+
+	s32	c_n = -100,
+		regval,
+		imin,
+		imax,
+		i,
+		noise_field1,
+		noise_field0;
+
+	dprintk("%s\n", __func__);
+
+	if (stv0900_get_standard(fe, demod) == STV0900_DVBS2_STANDARD) {
+		noise_field1 = NOSPLHT_NORMED1;
+		noise_field0 = NOSPLHT_NORMED0;
+	} else {
+		noise_field1 = NOSDATAT_NORMED1;
+		noise_field0 = NOSDATAT_NORMED0;
+	}
+
+	if (stv0900_get_bits(intp, LOCK_DEFINITIF)) {
+		if ((lookup != NULL) && lookup->size) {
+			regval = 0;
+			msleep(5);
+			for (i = 0; i < 16; i++) {
+				regval += MAKEWORD(stv0900_get_bits(intp,
+								noise_field1),
+						stv0900_get_bits(intp,
+								noise_field0));
+				msleep(1);
+			}
+
+			regval /= 16;
+			imin = 0;
+			imax = lookup->size - 1;
+			if (INRANGE(lookup->table[imin].regval,
+					regval,
+					lookup->table[imax].regval)) {
+				while ((imax - imin) > 1) {
+					i = (imax + imin) >> 1;
+					if (INRANGE(lookup->table[imin].regval,
+						    regval,
+						    lookup->table[i].regval))
+						imax = i;
+					else
+						imin = i;
+				}
+
+				c_n = ((regval - lookup->table[imin].regval)
+						* (lookup->table[imax].realval
+						- lookup->table[imin].realval)
+						/ (lookup->table[imax].regval
+						- lookup->table[imin].regval))
+						+ lookup->table[imin].realval;
+			} else if (regval < lookup->table[imin].regval)
+				c_n = 1000;
+		}
+	}
+
+	return c_n;
+}
+
+static int stv0900_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+	u8 err_val1, err_val0;
+	u32 header_err_val = 0;
+
+	*ucblocks = 0x0;
+	if (stv0900_get_standard(fe, demod) == STV0900_DVBS2_STANDARD) {
+		/* DVB-S2 delineator errors count */
+
+		/* retreiving number for errnous headers */
+		err_val1 = stv0900_read_reg(intp, BBFCRCKO1);
+		err_val0 = stv0900_read_reg(intp, BBFCRCKO0);
+		header_err_val = (err_val1 << 8) | err_val0;
+
+		/* retreiving number for errnous packets */
+		err_val1 = stv0900_read_reg(intp, UPCRCKO1);
+		err_val0 = stv0900_read_reg(intp, UPCRCKO0);
+		*ucblocks = (err_val1 << 8) | err_val0;
+		*ucblocks += header_err_val;
+	}
+
+	return 0;
+}
+
+static int stv0900_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	s32 snrlcl = stv0900_carr_get_quality(fe,
+			(const struct stv0900_table *)&stv0900_s2_cn);
+	snrlcl = (snrlcl + 30) * 384;
+	if (snrlcl < 0)
+		snrlcl = 0;
+
+	if (snrlcl > 65535)
+		snrlcl = 65535;
+
+	*snr = snrlcl;
+
+	return 0;
+}
+
+static u32 stv0900_get_ber(struct stv0900_internal *intp,
+				enum fe_stv0900_demod_num demod)
+{
+	u32 ber = 10000000, i;
+	s32 demod_state;
+
+	demod_state = stv0900_get_bits(intp, HEADER_MODE);
+
+	switch (demod_state) {
+	case STV0900_SEARCH:
+	case STV0900_PLH_DETECTED:
+	default:
+		ber = 10000000;
+		break;
+	case STV0900_DVBS_FOUND:
+		ber = 0;
+		for (i = 0; i < 5; i++) {
+			msleep(5);
+			ber += stv0900_get_err_count(intp, 0, demod);
+		}
+
+		ber /= 5;
+		if (stv0900_get_bits(intp, PRFVIT)) {
+			ber *= 9766;
+			ber = ber >> 13;
+		}
+
+		break;
+	case STV0900_DVBS2_FOUND:
+		ber = 0;
+		for (i = 0; i < 5; i++) {
+			msleep(5);
+			ber += stv0900_get_err_count(intp, 0, demod);
+		}
+
+		ber /= 5;
+		if (stv0900_get_bits(intp, PKTDELIN_LOCK)) {
+			ber *= 9766;
+			ber = ber >> 13;
+		}
+
+		break;
+	}
+
+	return ber;
+}
+
+static int stv0900_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *internal = state->internal;
+
+	*ber = stv0900_get_ber(internal, state->demod);
+
+	return 0;
+}
+
+int stv0900_get_demod_lock(struct stv0900_internal *intp,
+			enum fe_stv0900_demod_num demod, s32 time_out)
+{
+	s32 timer = 0,
+		lock = 0;
+
+	enum fe_stv0900_search_state	dmd_state;
+
+	while ((timer < time_out) && (lock == 0)) {
+		dmd_state = stv0900_get_bits(intp, HEADER_MODE);
+		dprintk("Demod State = %d\n", dmd_state);
+		switch (dmd_state) {
+		case STV0900_SEARCH:
+		case STV0900_PLH_DETECTED:
+		default:
+			lock = 0;
+			break;
+		case STV0900_DVBS2_FOUND:
+		case STV0900_DVBS_FOUND:
+			lock = stv0900_get_bits(intp, LOCK_DEFINITIF);
+			break;
+		}
+
+		if (lock == 0)
+			msleep(10);
+
+		timer += 10;
+	}
+
+	if (lock)
+		dprintk("DEMOD LOCK OK\n");
+	else
+		dprintk("DEMOD LOCK FAIL\n");
+
+	return lock;
+}
+
+void stv0900_stop_all_s2_modcod(struct stv0900_internal *intp,
+				enum fe_stv0900_demod_num demod)
+{
+	s32 regflist,
+	i;
+
+	dprintk("%s\n", __func__);
+
+	regflist = MODCODLST0;
+
+	for (i = 0; i < 16; i++)
+		stv0900_write_reg(intp, regflist + i, 0xff);
+}
+
+void stv0900_activate_s2_modcod(struct stv0900_internal *intp,
+				enum fe_stv0900_demod_num demod)
+{
+	u32 matype,
+		mod_code,
+		fmod,
+		reg_index,
+		field_index;
+
+	dprintk("%s\n", __func__);
+
+	if (intp->chip_id <= 0x11) {
+		msleep(5);
+
+		mod_code = stv0900_read_reg(intp, PLHMODCOD);
+		matype = mod_code & 0x3;
+		mod_code = (mod_code & 0x7f) >> 2;
+
+		reg_index = MODCODLSTF - mod_code / 2;
+		field_index = mod_code % 2;
+
+		switch (matype) {
+		case 0:
+		default:
+			fmod = 14;
+			break;
+		case 1:
+			fmod = 13;
+			break;
+		case 2:
+			fmod = 11;
+			break;
+		case 3:
+			fmod = 7;
+			break;
+		}
+
+		if ((INRANGE(STV0900_QPSK_12, mod_code, STV0900_8PSK_910))
+						&& (matype <= 1)) {
+			if (field_index == 0)
+				stv0900_write_reg(intp, reg_index,
+							0xf0 | fmod);
+			else
+				stv0900_write_reg(intp, reg_index,
+							(fmod << 4) | 0xf);
+		}
+
+	} else if (intp->chip_id >= 0x12) {
+		for (reg_index = 0; reg_index < 7; reg_index++)
+			stv0900_write_reg(intp, MODCODLST0 + reg_index, 0xff);
+
+		stv0900_write_reg(intp, MODCODLSTE, 0xff);
+		stv0900_write_reg(intp, MODCODLSTF, 0xcf);
+		for (reg_index = 0; reg_index < 8; reg_index++)
+			stv0900_write_reg(intp, MODCODLST7 + reg_index, 0xcc);
+
+
+	}
+}
+
+void stv0900_activate_s2_modcod_single(struct stv0900_internal *intp,
+					enum fe_stv0900_demod_num demod)
+{
+	u32 reg_index;
+
+	dprintk("%s\n", __func__);
+
+	stv0900_write_reg(intp, MODCODLST0, 0xff);
+	stv0900_write_reg(intp, MODCODLST1, 0xf0);
+	stv0900_write_reg(intp, MODCODLSTF, 0x0f);
+	for (reg_index = 0; reg_index < 13; reg_index++)
+		stv0900_write_reg(intp, MODCODLST2 + reg_index, 0);
+
+}
+
+static enum dvbfe_algo stv0900_frontend_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_CUSTOM;
+}
+
+void stv0900_start_search(struct stv0900_internal *intp,
+				enum fe_stv0900_demod_num demod)
+{
+	u32 freq;
+	s16 freq_s16 ;
+
+	stv0900_write_bits(intp, DEMOD_MODE, 0x1f);
+	if (intp->chip_id == 0x10)
+		stv0900_write_reg(intp, CORRELEXP, 0xaa);
+
+	if (intp->chip_id < 0x20)
+		stv0900_write_reg(intp, CARHDR, 0x55);
+
+	if (intp->chip_id <= 0x20) {
+		if (intp->symbol_rate[0] <= 5000000) {
+			stv0900_write_reg(intp, CARCFG, 0x44);
+			stv0900_write_reg(intp, CFRUP1, 0x0f);
+			stv0900_write_reg(intp, CFRUP0, 0xff);
+			stv0900_write_reg(intp, CFRLOW1, 0xf0);
+			stv0900_write_reg(intp, CFRLOW0, 0x00);
+			stv0900_write_reg(intp, RTCS2, 0x68);
+		} else {
+			stv0900_write_reg(intp, CARCFG, 0xc4);
+			stv0900_write_reg(intp, RTCS2, 0x44);
+		}
+
+	} else { /*cut 3.0 above*/
+		if (intp->symbol_rate[demod] <= 5000000)
+			stv0900_write_reg(intp, RTCS2, 0x68);
+		else
+			stv0900_write_reg(intp, RTCS2, 0x44);
+
+		stv0900_write_reg(intp, CARCFG, 0x46);
+		if (intp->srch_algo[demod] == STV0900_WARM_START) {
+			freq = 1000 << 16;
+			freq /= (intp->mclk / 1000);
+			freq_s16 = (s16)freq;
+		} else {
+			freq = (intp->srch_range[demod] / 2000);
+			if (intp->symbol_rate[demod] <= 5000000)
+				freq += 80;
+			else
+				freq += 600;
+
+			freq = freq << 16;
+			freq /= (intp->mclk / 1000);
+			freq_s16 = (s16)freq;
+		}
+
+		stv0900_write_bits(intp, CFR_UP1, MSB(freq_s16));
+		stv0900_write_bits(intp, CFR_UP0, LSB(freq_s16));
+		freq_s16 *= (-1);
+		stv0900_write_bits(intp, CFR_LOW1, MSB(freq_s16));
+		stv0900_write_bits(intp, CFR_LOW0, LSB(freq_s16));
+	}
+
+	stv0900_write_reg(intp, CFRINIT1, 0);
+	stv0900_write_reg(intp, CFRINIT0, 0);
+
+	if (intp->chip_id >= 0x20) {
+		stv0900_write_reg(intp, EQUALCFG, 0x41);
+		stv0900_write_reg(intp, FFECFG, 0x41);
+
+		if ((intp->srch_standard[demod] == STV0900_SEARCH_DVBS1) ||
+			(intp->srch_standard[demod] == STV0900_SEARCH_DSS) ||
+			(intp->srch_standard[demod] == STV0900_AUTO_SEARCH)) {
+			stv0900_write_reg(intp, VITSCALE,
+								0x82);
+			stv0900_write_reg(intp, VAVSRVIT, 0x0);
+		}
+	}
+
+	stv0900_write_reg(intp, SFRSTEP, 0x00);
+	stv0900_write_reg(intp, TMGTHRISE, 0xe0);
+	stv0900_write_reg(intp, TMGTHFALL, 0xc0);
+	stv0900_write_bits(intp, SCAN_ENABLE, 0);
+	stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
+	stv0900_write_bits(intp, S1S2_SEQUENTIAL, 0);
+	stv0900_write_reg(intp, RTC, 0x88);
+	if (intp->chip_id >= 0x20) {
+		if (intp->symbol_rate[demod] < 2000000) {
+			if (intp->chip_id <= 0x20)
+				stv0900_write_reg(intp, CARFREQ, 0x39);
+			else  /*cut 3.0*/
+				stv0900_write_reg(intp, CARFREQ, 0x89);
+
+			stv0900_write_reg(intp, CARHDR, 0x40);
+		} else if (intp->symbol_rate[demod] < 10000000) {
+			stv0900_write_reg(intp, CARFREQ, 0x4c);
+			stv0900_write_reg(intp, CARHDR, 0x20);
+		} else {
+			stv0900_write_reg(intp, CARFREQ, 0x4b);
+			stv0900_write_reg(intp, CARHDR, 0x20);
+		}
+
+	} else {
+		if (intp->symbol_rate[demod] < 10000000)
+			stv0900_write_reg(intp, CARFREQ, 0xef);
+		else
+			stv0900_write_reg(intp, CARFREQ, 0xed);
+	}
+
+	switch (intp->srch_algo[demod]) {
+	case STV0900_WARM_START:
+		stv0900_write_reg(intp, DMDISTATE, 0x1f);
+		stv0900_write_reg(intp, DMDISTATE, 0x18);
+		break;
+	case STV0900_COLD_START:
+		stv0900_write_reg(intp, DMDISTATE, 0x1f);
+		stv0900_write_reg(intp, DMDISTATE, 0x15);
+		break;
+	default:
+		break;
+	}
+}
+
+u8 stv0900_get_optim_carr_loop(s32 srate, enum fe_stv0900_modcode modcode,
+							s32 pilot, u8 chip_id)
+{
+	u8 aclc_value = 0x29;
+	s32 i;
+	const struct stv0900_car_loop_optim *cls2, *cllqs2, *cllas2;
+
+	dprintk("%s\n", __func__);
+
+	if (chip_id <= 0x12) {
+		cls2 = FE_STV0900_S2CarLoop;
+		cllqs2 = FE_STV0900_S2LowQPCarLoopCut30;
+		cllas2 = FE_STV0900_S2APSKCarLoopCut30;
+	} else if (chip_id == 0x20) {
+		cls2 = FE_STV0900_S2CarLoopCut20;
+		cllqs2 = FE_STV0900_S2LowQPCarLoopCut20;
+		cllas2 = FE_STV0900_S2APSKCarLoopCut20;
+	} else {
+		cls2 = FE_STV0900_S2CarLoopCut30;
+		cllqs2 = FE_STV0900_S2LowQPCarLoopCut30;
+		cllas2 = FE_STV0900_S2APSKCarLoopCut30;
+	}
+
+	if (modcode < STV0900_QPSK_12) {
+		i = 0;
+		while ((i < 3) && (modcode != cllqs2[i].modcode))
+			i++;
+
+		if (i >= 3)
+			i = 2;
+	} else {
+		i = 0;
+		while ((i < 14) && (modcode != cls2[i].modcode))
+			i++;
+
+		if (i >= 14) {
+			i = 0;
+			while ((i < 11) && (modcode != cllas2[i].modcode))
+				i++;
+
+			if (i >= 11)
+				i = 10;
+		}
+	}
+
+	if (modcode <= STV0900_QPSK_25) {
+		if (pilot) {
+			if (srate <= 3000000)
+				aclc_value = cllqs2[i].car_loop_pilots_on_2;
+			else if (srate <= 7000000)
+				aclc_value = cllqs2[i].car_loop_pilots_on_5;
+			else if (srate <= 15000000)
+				aclc_value = cllqs2[i].car_loop_pilots_on_10;
+			else if (srate <= 25000000)
+				aclc_value = cllqs2[i].car_loop_pilots_on_20;
+			else
+				aclc_value = cllqs2[i].car_loop_pilots_on_30;
+		} else {
+			if (srate <= 3000000)
+				aclc_value = cllqs2[i].car_loop_pilots_off_2;
+			else if (srate <= 7000000)
+				aclc_value = cllqs2[i].car_loop_pilots_off_5;
+			else if (srate <= 15000000)
+				aclc_value = cllqs2[i].car_loop_pilots_off_10;
+			else if (srate <= 25000000)
+				aclc_value = cllqs2[i].car_loop_pilots_off_20;
+			else
+				aclc_value = cllqs2[i].car_loop_pilots_off_30;
+		}
+
+	} else if (modcode <= STV0900_8PSK_910) {
+		if (pilot) {
+			if (srate <= 3000000)
+				aclc_value = cls2[i].car_loop_pilots_on_2;
+			else if (srate <= 7000000)
+				aclc_value = cls2[i].car_loop_pilots_on_5;
+			else if (srate <= 15000000)
+				aclc_value = cls2[i].car_loop_pilots_on_10;
+			else if (srate <= 25000000)
+				aclc_value = cls2[i].car_loop_pilots_on_20;
+			else
+				aclc_value = cls2[i].car_loop_pilots_on_30;
+		} else {
+			if (srate <= 3000000)
+				aclc_value = cls2[i].car_loop_pilots_off_2;
+			else if (srate <= 7000000)
+				aclc_value = cls2[i].car_loop_pilots_off_5;
+			else if (srate <= 15000000)
+				aclc_value = cls2[i].car_loop_pilots_off_10;
+			else if (srate <= 25000000)
+				aclc_value = cls2[i].car_loop_pilots_off_20;
+			else
+				aclc_value = cls2[i].car_loop_pilots_off_30;
+		}
+
+	} else {
+		if (srate <= 3000000)
+			aclc_value = cllas2[i].car_loop_pilots_on_2;
+		else if (srate <= 7000000)
+			aclc_value = cllas2[i].car_loop_pilots_on_5;
+		else if (srate <= 15000000)
+			aclc_value = cllas2[i].car_loop_pilots_on_10;
+		else if (srate <= 25000000)
+			aclc_value = cllas2[i].car_loop_pilots_on_20;
+		else
+			aclc_value = cllas2[i].car_loop_pilots_on_30;
+	}
+
+	return aclc_value;
+}
+
+u8 stv0900_get_optim_short_carr_loop(s32 srate,
+				enum fe_stv0900_modulation modulation,
+				u8 chip_id)
+{
+	const struct stv0900_short_frames_car_loop_optim *s2scl;
+	const struct stv0900_short_frames_car_loop_optim_vs_mod *s2sclc30;
+	s32 mod_index = 0;
+	u8 aclc_value = 0x0b;
+
+	dprintk("%s\n", __func__);
+
+	s2scl = FE_STV0900_S2ShortCarLoop;
+	s2sclc30 = FE_STV0900_S2ShortCarLoopCut30;
+
+	switch (modulation) {
+	case STV0900_QPSK:
+	default:
+		mod_index = 0;
+		break;
+	case STV0900_8PSK:
+		mod_index = 1;
+		break;
+	case STV0900_16APSK:
+		mod_index = 2;
+		break;
+	case STV0900_32APSK:
+		mod_index = 3;
+		break;
+	}
+
+	if (chip_id >= 0x30) {
+		if (srate <= 3000000)
+			aclc_value = s2sclc30[mod_index].car_loop_2;
+		else if (srate <= 7000000)
+			aclc_value = s2sclc30[mod_index].car_loop_5;
+		else if (srate <= 15000000)
+			aclc_value = s2sclc30[mod_index].car_loop_10;
+		else if (srate <= 25000000)
+			aclc_value = s2sclc30[mod_index].car_loop_20;
+		else
+			aclc_value = s2sclc30[mod_index].car_loop_30;
+
+	} else if (chip_id >= 0x20) {
+		if (srate <= 3000000)
+			aclc_value = s2scl[mod_index].car_loop_cut20_2;
+		else if (srate <= 7000000)
+			aclc_value = s2scl[mod_index].car_loop_cut20_5;
+		else if (srate <= 15000000)
+			aclc_value = s2scl[mod_index].car_loop_cut20_10;
+		else if (srate <= 25000000)
+			aclc_value = s2scl[mod_index].car_loop_cut20_20;
+		else
+			aclc_value = s2scl[mod_index].car_loop_cut20_30;
+
+	} else {
+		if (srate <= 3000000)
+			aclc_value = s2scl[mod_index].car_loop_cut12_2;
+		else if (srate <= 7000000)
+			aclc_value = s2scl[mod_index].car_loop_cut12_5;
+		else if (srate <= 15000000)
+			aclc_value = s2scl[mod_index].car_loop_cut12_10;
+		else if (srate <= 25000000)
+			aclc_value = s2scl[mod_index].car_loop_cut12_20;
+		else
+			aclc_value = s2scl[mod_index].car_loop_cut12_30;
+
+	}
+
+	return aclc_value;
+}
+
+static
+enum fe_stv0900_error stv0900_st_dvbs2_single(struct stv0900_internal *intp,
+					enum fe_stv0900_demod_mode LDPC_Mode,
+					enum fe_stv0900_demod_num demod)
+{
+	enum fe_stv0900_error error = STV0900_NO_ERROR;
+	s32 reg_ind;
+
+	dprintk("%s\n", __func__);
+
+	switch (LDPC_Mode) {
+	case STV0900_DUAL:
+	default:
+		if ((intp->demod_mode != STV0900_DUAL)
+			|| (stv0900_get_bits(intp, F0900_DDEMOD) != 1)) {
+			stv0900_write_reg(intp, R0900_GENCFG, 0x1d);
+
+			intp->demod_mode = STV0900_DUAL;
+
+			stv0900_write_bits(intp, F0900_FRESFEC, 1);
+			stv0900_write_bits(intp, F0900_FRESFEC, 0);
+
+			for (reg_ind = 0; reg_ind < 7; reg_ind++)
+				stv0900_write_reg(intp,
+						R0900_P1_MODCODLST0 + reg_ind,
+						0xff);
+			for (reg_ind = 0; reg_ind < 8; reg_ind++)
+				stv0900_write_reg(intp,
+						R0900_P1_MODCODLST7 + reg_ind,
+						0xcc);
+
+			stv0900_write_reg(intp, R0900_P1_MODCODLSTE, 0xff);
+			stv0900_write_reg(intp, R0900_P1_MODCODLSTF, 0xcf);
+
+			for (reg_ind = 0; reg_ind < 7; reg_ind++)
+				stv0900_write_reg(intp,
+						R0900_P2_MODCODLST0 + reg_ind,
+						0xff);
+			for (reg_ind = 0; reg_ind < 8; reg_ind++)
+				stv0900_write_reg(intp,
+						R0900_P2_MODCODLST7 + reg_ind,
+						0xcc);
+
+			stv0900_write_reg(intp, R0900_P2_MODCODLSTE, 0xff);
+			stv0900_write_reg(intp, R0900_P2_MODCODLSTF, 0xcf);
+		}
+
+		break;
+	case STV0900_SINGLE:
+		if (demod == STV0900_DEMOD_2) {
+			stv0900_stop_all_s2_modcod(intp, STV0900_DEMOD_1);
+			stv0900_activate_s2_modcod_single(intp,
+							STV0900_DEMOD_2);
+			stv0900_write_reg(intp, R0900_GENCFG, 0x06);
+		} else {
+			stv0900_stop_all_s2_modcod(intp, STV0900_DEMOD_2);
+			stv0900_activate_s2_modcod_single(intp,
+							STV0900_DEMOD_1);
+			stv0900_write_reg(intp, R0900_GENCFG, 0x04);
+		}
+
+		intp->demod_mode = STV0900_SINGLE;
+
+		stv0900_write_bits(intp, F0900_FRESFEC, 1);
+		stv0900_write_bits(intp, F0900_FRESFEC, 0);
+		stv0900_write_bits(intp, F0900_P1_ALGOSWRST, 1);
+		stv0900_write_bits(intp, F0900_P1_ALGOSWRST, 0);
+		stv0900_write_bits(intp, F0900_P2_ALGOSWRST, 1);
+		stv0900_write_bits(intp, F0900_P2_ALGOSWRST, 0);
+		break;
+	}
+
+	return error;
+}
+
+static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
+					struct stv0900_init_params *p_init)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	enum fe_stv0900_error error = STV0900_NO_ERROR;
+	enum fe_stv0900_error demodError = STV0900_NO_ERROR;
+	struct stv0900_internal *intp = NULL;
+	int selosci, i;
+
+	struct stv0900_inode *temp_int = find_inode(state->i2c_adap,
+						state->config->demod_address);
+
+	dprintk("%s\n", __func__);
+
+	if ((temp_int != NULL) && (p_init->demod_mode == STV0900_DUAL)) {
+		state->internal = temp_int->internal;
+		(state->internal->dmds_used)++;
+		dprintk("%s: Find Internal Structure!\n", __func__);
+		return STV0900_NO_ERROR;
+	} else {
+		state->internal = kmalloc(sizeof(struct stv0900_internal),
+								GFP_KERNEL);
+		if (state->internal == NULL)
+			return STV0900_INVALID_HANDLE;
+		temp_int = append_internal(state->internal);
+		if (temp_int == NULL) {
+			kfree(state->internal);
+			state->internal = NULL;
+			return STV0900_INVALID_HANDLE;
+		}
+		state->internal->dmds_used = 1;
+		state->internal->i2c_adap = state->i2c_adap;
+		state->internal->i2c_addr = state->config->demod_address;
+		state->internal->clkmode = state->config->clkmode;
+		state->internal->errs = STV0900_NO_ERROR;
+		dprintk("%s: Create New Internal Structure!\n", __func__);
+	}
+
+	if (state->internal == NULL) {
+		error = STV0900_INVALID_HANDLE;
+		return error;
+	}
+
+	demodError = stv0900_initialize(state->internal);
+	if (demodError == STV0900_NO_ERROR) {
+			error = STV0900_NO_ERROR;
+	} else {
+		if (demodError == STV0900_INVALID_HANDLE)
+			error = STV0900_INVALID_HANDLE;
+		else
+			error = STV0900_I2C_ERROR;
+
+		return error;
+	}
+
+	intp = state->internal;
+
+	intp->demod_mode = p_init->demod_mode;
+	stv0900_st_dvbs2_single(intp, intp->demod_mode,	STV0900_DEMOD_1);
+	intp->chip_id = stv0900_read_reg(intp, R0900_MID);
+	intp->rolloff = p_init->rolloff;
+	intp->quartz = p_init->dmd_ref_clk;
+
+	stv0900_write_bits(intp, F0900_P1_ROLLOFF_CONTROL, p_init->rolloff);
+	stv0900_write_bits(intp, F0900_P2_ROLLOFF_CONTROL, p_init->rolloff);
+
+	intp->ts_config = p_init->ts_config;
+	if (intp->ts_config == NULL)
+		stv0900_set_ts_parallel_serial(intp,
+				p_init->path1_ts_clock,
+				p_init->path2_ts_clock);
+	else {
+		for (i = 0; intp->ts_config[i].addr != 0xffff; i++)
+			stv0900_write_reg(intp,
+					intp->ts_config[i].addr,
+					intp->ts_config[i].val);
+
+		stv0900_write_bits(intp, F0900_P2_RST_HWARE, 1);
+		stv0900_write_bits(intp, F0900_P2_RST_HWARE, 0);
+		stv0900_write_bits(intp, F0900_P1_RST_HWARE, 1);
+		stv0900_write_bits(intp, F0900_P1_RST_HWARE, 0);
+	}
+
+	intp->tuner_type[0] = p_init->tuner1_type;
+	intp->tuner_type[1] = p_init->tuner2_type;
+	/* tuner init */
+	switch (p_init->tuner1_type) {
+	case 3: /*FE_AUTO_STB6100:*/
+		stv0900_write_reg(intp, R0900_P1_TNRCFG, 0x3c);
+		stv0900_write_reg(intp, R0900_P1_TNRCFG2, 0x86);
+		stv0900_write_reg(intp, R0900_P1_TNRCFG3, 0x18);
+		stv0900_write_reg(intp, R0900_P1_TNRXTAL, 27); /* 27MHz */
+		stv0900_write_reg(intp, R0900_P1_TNRSTEPS, 0x05);
+		stv0900_write_reg(intp, R0900_P1_TNRGAIN, 0x17);
+		stv0900_write_reg(intp, R0900_P1_TNRADJ, 0x1f);
+		stv0900_write_reg(intp, R0900_P1_TNRCTL2, 0x0);
+		stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 3);
+		break;
+	/* case FE_SW_TUNER: */
+	default:
+		stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 6);
+		break;
+	}
+
+	stv0900_write_bits(intp, F0900_P1_TUN_MADDRESS, p_init->tun1_maddress);
+	switch (p_init->tuner1_adc) {
+	case 1:
+		stv0900_write_reg(intp, R0900_TSTTNR1, 0x26);
+		break;
+	default:
+		break;
+	}
+
+	stv0900_write_reg(intp, R0900_P1_TNRLD, 1); /* hw tuner */
+
+	/* tuner init */
+	switch (p_init->tuner2_type) {
+	case 3: /*FE_AUTO_STB6100:*/
+		stv0900_write_reg(intp, R0900_P2_TNRCFG, 0x3c);
+		stv0900_write_reg(intp, R0900_P2_TNRCFG2, 0x86);
+		stv0900_write_reg(intp, R0900_P2_TNRCFG3, 0x18);
+		stv0900_write_reg(intp, R0900_P2_TNRXTAL, 27); /* 27MHz */
+		stv0900_write_reg(intp, R0900_P2_TNRSTEPS, 0x05);
+		stv0900_write_reg(intp, R0900_P2_TNRGAIN, 0x17);
+		stv0900_write_reg(intp, R0900_P2_TNRADJ, 0x1f);
+		stv0900_write_reg(intp, R0900_P2_TNRCTL2, 0x0);
+		stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 3);
+		break;
+	/* case FE_SW_TUNER: */
+	default:
+		stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 6);
+		break;
+	}
+
+	stv0900_write_bits(intp, F0900_P2_TUN_MADDRESS, p_init->tun2_maddress);
+	switch (p_init->tuner2_adc) {
+	case 1:
+		stv0900_write_reg(intp, R0900_TSTTNR3, 0x26);
+		break;
+	default:
+		break;
+	}
+
+	stv0900_write_reg(intp, R0900_P2_TNRLD, 1); /* hw tuner */
+
+	stv0900_write_bits(intp, F0900_P1_TUN_IQSWAP, p_init->tun1_iq_inv);
+	stv0900_write_bits(intp, F0900_P2_TUN_IQSWAP, p_init->tun2_iq_inv);
+	stv0900_set_mclk(intp, 135000000);
+	msleep(3);
+
+	switch (intp->clkmode) {
+	case 0:
+	case 2:
+		stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20 | intp->clkmode);
+		break;
+	default:
+		selosci = 0x02 & stv0900_read_reg(intp, R0900_SYNTCTRL);
+		stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20 | selosci);
+		break;
+	}
+	msleep(3);
+
+	intp->mclk = stv0900_get_mclk_freq(intp, intp->quartz);
+	if (intp->errs)
+		error = STV0900_I2C_ERROR;
+
+	return error;
+}
+
+static int stv0900_status(struct stv0900_internal *intp,
+					enum fe_stv0900_demod_num demod)
+{
+	enum fe_stv0900_search_state demod_state;
+	int locked = FALSE;
+	u8 tsbitrate0_val, tsbitrate1_val;
+	s32 bitrate;
+
+	demod_state = stv0900_get_bits(intp, HEADER_MODE);
+	switch (demod_state) {
+	case STV0900_SEARCH:
+	case STV0900_PLH_DETECTED:
+	default:
+		locked = FALSE;
+		break;
+	case STV0900_DVBS2_FOUND:
+		locked = stv0900_get_bits(intp, LOCK_DEFINITIF) &&
+				stv0900_get_bits(intp, PKTDELIN_LOCK) &&
+				stv0900_get_bits(intp, TSFIFO_LINEOK);
+		break;
+	case STV0900_DVBS_FOUND:
+		locked = stv0900_get_bits(intp, LOCK_DEFINITIF) &&
+				stv0900_get_bits(intp, LOCKEDVIT) &&
+				stv0900_get_bits(intp, TSFIFO_LINEOK);
+		break;
+	}
+
+	dprintk("%s: locked = %d\n", __func__, locked);
+
+	if (stvdebug) {
+		/* Print TS bitrate */
+		tsbitrate0_val = stv0900_read_reg(intp, TSBITRATE0);
+		tsbitrate1_val = stv0900_read_reg(intp, TSBITRATE1);
+		/* Formula Bit rate = Mclk * px_tsfifo_bitrate / 16384 */
+		bitrate = (stv0900_get_mclk_freq(intp, intp->quartz)/1000000)
+			* (tsbitrate1_val << 8 | tsbitrate0_val);
+		bitrate /= 16384;
+		dprintk("TS bitrate = %d Mbit/sec \n", bitrate);
+	};
+
+	return locked;
+}
+
+static enum dvbfe_search stv0900_search(struct dvb_frontend *fe)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+	struct stv0900_search_params p_search;
+	struct stv0900_signal_info p_result = intp->result[demod];
+
+	enum fe_stv0900_error error = STV0900_NO_ERROR;
+
+	dprintk("%s: ", __func__);
+
+	if (!(INRANGE(100000, c->symbol_rate, 70000000)))
+		return DVBFE_ALGO_SEARCH_FAILED;
+
+	if (state->config->set_ts_params)
+		state->config->set_ts_params(fe, 0);
+
+	p_result.locked = FALSE;
+	p_search.path = demod;
+	p_search.frequency = c->frequency;
+	p_search.symbol_rate = c->symbol_rate;
+	p_search.search_range = 10000000;
+	p_search.fec = STV0900_FEC_UNKNOWN;
+	p_search.standard = STV0900_AUTO_SEARCH;
+	p_search.iq_inversion = STV0900_IQ_AUTO;
+	p_search.search_algo = STV0900_BLIND_SEARCH;
+	/* Speeds up DVB-S searching */
+	if (c->delivery_system == SYS_DVBS)
+		p_search.standard = STV0900_SEARCH_DVBS1;
+
+	intp->srch_standard[demod] = p_search.standard;
+	intp->symbol_rate[demod] = p_search.symbol_rate;
+	intp->srch_range[demod] = p_search.search_range;
+	intp->freq[demod] = p_search.frequency;
+	intp->srch_algo[demod] = p_search.search_algo;
+	intp->srch_iq_inv[demod] = p_search.iq_inversion;
+	intp->fec[demod] = p_search.fec;
+	if ((stv0900_algo(fe) == STV0900_RANGEOK) &&
+				(intp->errs == STV0900_NO_ERROR)) {
+		p_result.locked = intp->result[demod].locked;
+		p_result.standard = intp->result[demod].standard;
+		p_result.frequency = intp->result[demod].frequency;
+		p_result.symbol_rate = intp->result[demod].symbol_rate;
+		p_result.fec = intp->result[demod].fec;
+		p_result.modcode = intp->result[demod].modcode;
+		p_result.pilot = intp->result[demod].pilot;
+		p_result.frame_len = intp->result[demod].frame_len;
+		p_result.spectrum = intp->result[demod].spectrum;
+		p_result.rolloff = intp->result[demod].rolloff;
+		p_result.modulation = intp->result[demod].modulation;
+	} else {
+		p_result.locked = FALSE;
+		switch (intp->err[demod]) {
+		case STV0900_I2C_ERROR:
+			error = STV0900_I2C_ERROR;
+			break;
+		case STV0900_NO_ERROR:
+		default:
+			error = STV0900_SEARCH_FAILED;
+			break;
+		}
+	}
+
+	if ((p_result.locked == TRUE) && (error == STV0900_NO_ERROR)) {
+		dprintk("Search Success\n");
+		return DVBFE_ALGO_SEARCH_SUCCESS;
+	} else {
+		dprintk("Search Fail\n");
+		return DVBFE_ALGO_SEARCH_FAILED;
+	}
+
+}
+
+static int stv0900_read_status(struct dvb_frontend *fe, enum fe_status *status)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+
+	dprintk("%s: ", __func__);
+
+	if ((stv0900_status(state->internal, state->demod)) == TRUE) {
+		dprintk("DEMOD LOCK OK\n");
+		*status = FE_HAS_CARRIER
+			| FE_HAS_VITERBI
+			| FE_HAS_SYNC
+			| FE_HAS_LOCK;
+		if (state->config->set_lock_led)
+			state->config->set_lock_led(fe, 1);
+	} else {
+		*status = 0;
+		if (state->config->set_lock_led)
+			state->config->set_lock_led(fe, 0);
+		dprintk("DEMOD LOCK FAIL\n");
+	}
+
+	return 0;
+}
+
+static int stv0900_stop_ts(struct dvb_frontend *fe, int stop_ts)
+{
+
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+
+	if (stop_ts == TRUE)
+		stv0900_write_bits(intp, RST_HWARE, 1);
+	else
+		stv0900_write_bits(intp, RST_HWARE, 0);
+
+	return 0;
+}
+
+static int stv0900_diseqc_init(struct dvb_frontend *fe)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+
+	stv0900_write_bits(intp, DISTX_MODE, state->config->diseqc_mode);
+	stv0900_write_bits(intp, DISEQC_RESET, 1);
+	stv0900_write_bits(intp, DISEQC_RESET, 0);
+
+	return 0;
+}
+
+static int stv0900_init(struct dvb_frontend *fe)
+{
+	dprintk("%s\n", __func__);
+
+	stv0900_stop_ts(fe, 1);
+	stv0900_diseqc_init(fe);
+
+	return 0;
+}
+
+static int stv0900_diseqc_send(struct stv0900_internal *intp , u8 *data,
+				u32 NbData, enum fe_stv0900_demod_num demod)
+{
+	s32 i = 0;
+
+	stv0900_write_bits(intp, DIS_PRECHARGE, 1);
+	while (i < NbData) {
+		while (stv0900_get_bits(intp, FIFO_FULL))
+			;/* checkpatch complains */
+		stv0900_write_reg(intp, DISTXDATA, data[i]);
+		i++;
+	}
+
+	stv0900_write_bits(intp, DIS_PRECHARGE, 0);
+	i = 0;
+	while ((stv0900_get_bits(intp, TX_IDLE) != 1) && (i < 10)) {
+		msleep(10);
+		i++;
+	}
+
+	return 0;
+}
+
+static int stv0900_send_master_cmd(struct dvb_frontend *fe,
+					struct dvb_diseqc_master_cmd *cmd)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+
+	return stv0900_diseqc_send(state->internal,
+				cmd->msg,
+				cmd->msg_len,
+				state->demod);
+}
+
+static int stv0900_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+	u8 data;
+
+
+	switch (burst) {
+	case SEC_MINI_A:
+		stv0900_write_bits(intp, DISTX_MODE, 3);/* Unmodulated */
+		data = 0x00;
+		stv0900_diseqc_send(intp, &data, 1, state->demod);
+		break;
+	case SEC_MINI_B:
+		stv0900_write_bits(intp, DISTX_MODE, 2);/* Modulated */
+		data = 0xff;
+		stv0900_diseqc_send(intp, &data, 1, state->demod);
+		break;
+	}
+
+	return 0;
+}
+
+static int stv0900_recv_slave_reply(struct dvb_frontend *fe,
+				struct dvb_diseqc_slave_reply *reply)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+	s32 i = 0;
+
+	reply->msg_len = 0;
+
+	while ((stv0900_get_bits(intp, RX_END) != 1) && (i < 10)) {
+		msleep(10);
+		i++;
+	}
+
+	if (stv0900_get_bits(intp, RX_END)) {
+		reply->msg_len = stv0900_get_bits(intp, FIFO_BYTENBR);
+
+		for (i = 0; i < reply->msg_len; i++)
+			reply->msg[i] = stv0900_read_reg(intp, DISRXDATA);
+	}
+
+	return 0;
+}
+
+static int stv0900_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t toneoff)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+
+	dprintk("%s: %s\n", __func__, ((toneoff == 0) ? "On" : "Off"));
+
+	switch (toneoff) {
+	case SEC_TONE_ON:
+		/*Set the DiseqC mode to 22Khz _continues_ tone*/
+		stv0900_write_bits(intp, DISTX_MODE, 0);
+		stv0900_write_bits(intp, DISEQC_RESET, 1);
+		/*release DiseqC reset to enable the 22KHz tone*/
+		stv0900_write_bits(intp, DISEQC_RESET, 0);
+		break;
+	case SEC_TONE_OFF:
+		/*return diseqc mode to config->diseqc_mode.
+		Usually it's without _continues_ tone */
+		stv0900_write_bits(intp, DISTX_MODE,
+				state->config->diseqc_mode);
+		/*maintain the DiseqC reset to disable the 22KHz tone*/
+		stv0900_write_bits(intp, DISEQC_RESET, 1);
+		stv0900_write_bits(intp, DISEQC_RESET, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void stv0900_release(struct dvb_frontend *fe)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	if (state->config->set_lock_led)
+		state->config->set_lock_led(fe, 0);
+
+	if ((--(state->internal->dmds_used)) <= 0) {
+
+		dprintk("%s: Actually removing\n", __func__);
+
+		remove_inode(state->internal);
+		kfree(state->internal);
+	}
+
+	kfree(state);
+}
+
+static int stv0900_sleep(struct dvb_frontend *fe)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	if (state->config->set_lock_led)
+		state->config->set_lock_led(fe, 0);
+
+	return 0;
+}
+
+static int stv0900_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+	struct stv0900_signal_info p_result = intp->result[demod];
+
+	p->frequency = p_result.locked ? p_result.frequency : 0;
+	p->symbol_rate = p_result.locked ? p_result.symbol_rate : 0;
+	return 0;
+}
+
+static struct dvb_frontend_ops stv0900_ops = {
+	.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
+	.info = {
+		.name			= "STV0900 frontend",
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 125,
+		.frequency_tolerance	= 0,
+		.symbol_rate_min	= 1000000,
+		.symbol_rate_max	= 45000000,
+		.symbol_rate_tolerance	= 500,
+		.caps			= FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+					  FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
+					  FE_CAN_FEC_7_8 | FE_CAN_QPSK    |
+					  FE_CAN_2G_MODULATION |
+					  FE_CAN_FEC_AUTO
+	},
+	.release			= stv0900_release,
+	.init				= stv0900_init,
+	.get_frontend                   = stv0900_get_frontend,
+	.sleep				= stv0900_sleep,
+	.get_frontend_algo		= stv0900_frontend_algo,
+	.i2c_gate_ctrl			= stv0900_i2c_gate_ctrl,
+	.diseqc_send_master_cmd		= stv0900_send_master_cmd,
+	.diseqc_send_burst		= stv0900_send_burst,
+	.diseqc_recv_slave_reply	= stv0900_recv_slave_reply,
+	.set_tone			= stv0900_set_tone,
+	.search				= stv0900_search,
+	.read_status			= stv0900_read_status,
+	.read_ber			= stv0900_read_ber,
+	.read_signal_strength		= stv0900_read_signal_strength,
+	.read_snr			= stv0900_read_snr,
+	.read_ucblocks                  = stv0900_read_ucblocks,
+};
+
+struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
+					struct i2c_adapter *i2c,
+					int demod)
+{
+	struct stv0900_state *state = NULL;
+	struct stv0900_init_params init_params;
+	enum fe_stv0900_error err_stv0900;
+
+	state = kzalloc(sizeof(struct stv0900_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	state->demod		= demod;
+	state->config		= config;
+	state->i2c_adap		= i2c;
+
+	memcpy(&state->frontend.ops, &stv0900_ops,
+			sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	switch (demod) {
+	case 0:
+	case 1:
+		init_params.dmd_ref_clk  	= config->xtal;
+		init_params.demod_mode		= config->demod_mode;
+		init_params.rolloff		= STV0900_35;
+		init_params.path1_ts_clock	= config->path1_mode;
+		init_params.tun1_maddress	= config->tun1_maddress;
+		init_params.tun1_iq_inv		= STV0900_IQ_NORMAL;
+		init_params.tuner1_adc		= config->tun1_adc;
+		init_params.tuner1_type		= config->tun1_type;
+		init_params.path2_ts_clock	= config->path2_mode;
+		init_params.ts_config		= config->ts_config_regs;
+		init_params.tun2_maddress	= config->tun2_maddress;
+		init_params.tuner2_adc		= config->tun2_adc;
+		init_params.tuner2_type		= config->tun2_type;
+		init_params.tun2_iq_inv		= STV0900_IQ_SWAPPED;
+
+		err_stv0900 = stv0900_init_internal(&state->frontend,
+							&init_params);
+
+		if (err_stv0900)
+			goto error;
+
+		break;
+	default:
+		goto error;
+		break;
+	}
+
+	dprintk("%s: Attaching STV0900 demodulator(%d) \n", __func__, demod);
+	return &state->frontend;
+
+error:
+	dprintk("%s: Failed to attach STV0900 demodulator(%d) \n",
+		__func__, demod);
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(stv0900_attach);
+
+MODULE_PARM_DESC(debug, "Set debug");
+
+MODULE_AUTHOR("Igor M. Liplianin");
+MODULE_DESCRIPTION("ST STV0900 frontend");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/stv0900_init.h b/drivers/media/dvb-frontends/stv0900_init.h
new file mode 100644
index 0000000..b684df9
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv0900_init.h
@@ -0,0 +1,584 @@
+/*
+ * stv0900_init.h
+ *
+ * Driver for ST STV0900 satellite demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef STV0900_INIT_H
+#define STV0900_INIT_H
+
+#include "stv0900_priv.h"
+
+/* DVBS2 C/N Look-Up table */
+static const struct stv0900_table stv0900_s2_cn = {
+	55,
+	{
+		{ -30,	13348 }, /*C/N=-3dB*/
+		{ -20,	12640 }, /*C/N=-2dB*/
+		{ -10,	11883 }, /*C/N=-1dB*/
+		{ 0,	11101 }, /*C/N=-0dB*/
+		{ 5,	10718 }, /*C/N=0.5dB*/
+		{ 10,	10339 }, /*C/N=1.0dB*/
+		{ 15,	9947 }, /*C/N=1.5dB*/
+		{ 20,	9552 }, /*C/N=2.0dB*/
+		{ 25,	9183 }, /*C/N=2.5dB*/
+		{ 30,	8799 }, /*C/N=3.0dB*/
+		{ 35,	8422 }, /*C/N=3.5dB*/
+		{ 40,	8062 }, /*C/N=4.0dB*/
+		{ 45,	7707 }, /*C/N=4.5dB*/
+		{ 50,	7353 }, /*C/N=5.0dB*/
+		{ 55,	7025 }, /*C/N=5.5dB*/
+		{ 60,	6684 }, /*C/N=6.0dB*/
+		{ 65,	6331 }, /*C/N=6.5dB*/
+		{ 70,	6036 }, /*C/N=7.0dB*/
+		{ 75,	5727 }, /*C/N=7.5dB*/
+		{ 80,	5437 }, /*C/N=8.0dB*/
+		{ 85,	5164 }, /*C/N=8.5dB*/
+		{ 90,	4902 }, /*C/N=9.0dB*/
+		{ 95,	4653 }, /*C/N=9.5dB*/
+		{ 100,	4408 }, /*C/N=10.0dB*/
+		{ 105,	4187 }, /*C/N=10.5dB*/
+		{ 110,	3961 }, /*C/N=11.0dB*/
+		{ 115,	3751 }, /*C/N=11.5dB*/
+		{ 120,	3558 }, /*C/N=12.0dB*/
+		{ 125,	3368 }, /*C/N=12.5dB*/
+		{ 130,	3191 }, /*C/N=13.0dB*/
+		{ 135,	3017 }, /*C/N=13.5dB*/
+		{ 140,	2862 }, /*C/N=14.0dB*/
+		{ 145,	2710 }, /*C/N=14.5dB*/
+		{ 150,	2565 }, /*C/N=15.0dB*/
+		{ 160,	2300 }, /*C/N=16.0dB*/
+		{ 170,	2058 }, /*C/N=17.0dB*/
+		{ 180,	1849 }, /*C/N=18.0dB*/
+		{ 190,	1663 }, /*C/N=19.0dB*/
+		{ 200,	1495 }, /*C/N=20.0dB*/
+		{ 210,	1349 }, /*C/N=21.0dB*/
+		{ 220,	1222 }, /*C/N=22.0dB*/
+		{ 230,	1110 }, /*C/N=23.0dB*/
+		{ 240,	1011 }, /*C/N=24.0dB*/
+		{ 250,	925 }, /*C/N=25.0dB*/
+		{ 260,	853 }, /*C/N=26.0dB*/
+		{ 270,	789 }, /*C/N=27.0dB*/
+		{ 280,	734 }, /*C/N=28.0dB*/
+		{ 290,	690 }, /*C/N=29.0dB*/
+		{ 300,	650 }, /*C/N=30.0dB*/
+		{ 310,	619 }, /*C/N=31.0dB*/
+		{ 320,	593 }, /*C/N=32.0dB*/
+		{ 330,	571 }, /*C/N=33.0dB*/
+		{ 400,	498 }, /*C/N=40.0dB*/
+		{ 450,	484 }, /*C/N=45.0dB*/
+		{ 500,	481 }  /*C/N=50.0dB*/
+	}
+};
+
+/* RF level C/N Look-Up table */
+static const struct stv0900_table stv0900_rf = {
+	14,
+	{
+		{ -5, 0xCAA1 }, /*-5dBm*/
+		{ -10, 0xC229 }, /*-10dBm*/
+		{ -15, 0xBB08 }, /*-15dBm*/
+		{ -20, 0xB4BC }, /*-20dBm*/
+		{ -25, 0xAD5A }, /*-25dBm*/
+		{ -30, 0xA298 }, /*-30dBm*/
+		{ -35, 0x98A8 }, /*-35dBm*/
+		{ -40, 0x8389 }, /*-40dBm*/
+		{ -45, 0x59BE }, /*-45dBm*/
+		{ -50, 0x3A14 }, /*-50dBm*/
+		{ -55, 0x2D11 }, /*-55dBm*/
+		{ -60, 0x210D }, /*-60dBm*/
+		{ -65, 0xA14F }, /*-65dBm*/
+		{ -70, 0x7AA }	/*-70dBm*/
+	}
+};
+
+struct stv0900_car_loop_optim {
+	enum fe_stv0900_modcode modcode;
+	u8 car_loop_pilots_on_2;
+	u8 car_loop_pilots_off_2;
+	u8 car_loop_pilots_on_5;
+	u8 car_loop_pilots_off_5;
+	u8 car_loop_pilots_on_10;
+	u8 car_loop_pilots_off_10;
+	u8 car_loop_pilots_on_20;
+	u8 car_loop_pilots_off_20;
+	u8 car_loop_pilots_on_30;
+	u8 car_loop_pilots_off_30;
+
+};
+
+struct stv0900_short_frames_car_loop_optim {
+	enum fe_stv0900_modulation modulation;
+	u8 car_loop_cut12_2;    /* Cut 1.2,   SR<=3msps     */
+	u8 car_loop_cut20_2;    /* Cut 2.0,   SR<3msps      */
+	u8 car_loop_cut12_5;    /* Cut 1.2,   3<SR<=7msps   */
+	u8 car_loop_cut20_5;    /* Cut 2.0,   3<SR<=7msps   */
+	u8 car_loop_cut12_10;   /* Cut 1.2,   7<SR<=15msps  */
+	u8 car_loop_cut20_10;   /* Cut 2.0,   7<SR<=15msps  */
+	u8 car_loop_cut12_20;   /* Cut 1.2,   10<SR<=25msps */
+	u8 car_loop_cut20_20;   /* Cut 2.0,   10<SR<=25msps */
+	u8 car_loop_cut12_30;   /* Cut 1.2,   25<SR<=45msps */
+	u8 car_loop_cut20_30;   /* Cut 2.0,   10<SR<=45msps */
+
+};
+
+struct stv0900_short_frames_car_loop_optim_vs_mod {
+	enum fe_stv0900_modulation modulation;
+	u8 car_loop_2;	  /* SR<3msps      */
+	u8 car_loop_5;	  /* 3<SR<=7msps   */
+	u8 car_loop_10;   /* 7<SR<=15msps  */
+	u8 car_loop_20;   /* 10<SR<=25msps */
+	u8 car_loop_30;   /* 10<SR<=45msps */
+};
+
+/* Cut 1.x Tracking carrier loop carrier QPSK 1/2 to 8PSK 9/10 long Frame */
+static const struct stv0900_car_loop_optim FE_STV0900_S2CarLoop[14] = {
+	/*Modcod		2MPon 	2MPoff	5MPon 	5MPoff	10MPon
+				10MPoff	20MPon 	20MPoff	30MPon 	30MPoff */
+	{ STV0900_QPSK_12,	0x1C,	0x0D,	0x1B,	0x2C,	0x3A,
+				0x1C,	0x2A,	0x3B,	0x2A,	0x1B },
+	{ STV0900_QPSK_35,	0x2C,	0x0D,	0x2B,	0x2C,	0x3A,
+				0x0C,	0x3A,	0x2B,	0x2A,	0x0B },
+	{ STV0900_QPSK_23,	0x2C,	0x0D,	0x2B,	0x2C,	0x0B,
+				0x0C,	0x3A,	0x1B,	0x2A,	0x3A },
+	{ STV0900_QPSK_34,	0x3C,	0x0D,	0x3B,	0x1C,	0x0B,
+				0x3B,	0x3A,	0x0B,	0x2A,	0x3A },
+	{ STV0900_QPSK_45,	0x3C,	0x0D,	0x3B,	0x1C,	0x0B,
+				0x3B,	0x3A,	0x0B,	0x2A,	0x3A },
+	{ STV0900_QPSK_56,	0x0D,	0x0D,	0x3B,	0x1C,	0x0B,
+				0x3B,	0x3A,	0x0B,	0x2A,	0x3A },
+	{ STV0900_QPSK_89,	0x0D,	0x0D,	0x3B,	0x1C,	0x1B,
+				0x3B,	0x3A,	0x0B,	0x2A,	0x3A },
+	{ STV0900_QPSK_910,	0x1D,	0x0D,	0x3B,	0x1C,	0x1B,
+				0x3B,	0x3A,	0x0B,	0x2A,	0x3A },
+	{ STV0900_8PSK_35,	0x29,	0x3B,	0x09,	0x2B,	0x38,
+				0x0B,	0x18,	0x1A,	0x08,	0x0A },
+	{ STV0900_8PSK_23,	0x0A,	0x3B,	0x29,	0x2B,	0x19,
+				0x0B,	0x38,	0x1A,	0x18,	0x0A },
+	{ STV0900_8PSK_34,	0x3A,	0x3B,	0x2A,	0x2B,	0x39,
+				0x0B,	0x19,	0x1A,	0x38,	0x0A },
+	{ STV0900_8PSK_56,	0x1B,	0x3B,	0x0B,	0x2B,	0x1A,
+				0x0B,	0x39,	0x1A,	0x19,	0x0A },
+	{ STV0900_8PSK_89,	0x3B,	0x3B,	0x0B,	0x2B,	0x2A,
+				0x0B,	0x39,	0x1A,	0x29,	0x39 },
+	{ STV0900_8PSK_910,	0x3B,	0x3B, 	0x0B,	0x2B, 	0x2A,
+				0x0B,	0x39,	0x1A,	0x29,	0x39 }
+};
+
+
+/* Cut 2.0 Tracking carrier loop carrier QPSK 1/2 to 8PSK 9/10 long Frame */
+static const struct stv0900_car_loop_optim FE_STV0900_S2CarLoopCut20[14] = {
+	/* Modcod		2MPon 	2MPoff	5MPon 	5MPoff	10MPon
+				10MPoff	20MPon 	20MPoff	30MPon 	30MPoff */
+	{ STV0900_QPSK_12,	0x1F,	0x3F,	0x1E,	0x3F,	0x3D,
+				0x1F,	0x3D,	0x3E,	0x3D,	0x1E },
+	{ STV0900_QPSK_35,	0x2F,	0x3F,	0x2E,	0x2F,	0x3D,
+				0x0F,	0x0E,	0x2E,	0x3D,	0x0E },
+	{ STV0900_QPSK_23,	0x2F,	0x3F,	0x2E,	0x2F,	0x0E,
+				0x0F,	0x0E,	0x1E,	0x3D,	0x3D },
+	{ STV0900_QPSK_34,	0x3F,	0x3F,	0x3E,	0x1F,	0x0E,
+				0x3E,	0x0E,	0x1E,	0x3D,	0x3D },
+	{ STV0900_QPSK_45,	0x3F,	0x3F,	0x3E,	0x1F,	0x0E,
+				0x3E,	0x0E,	0x1E,	0x3D,	0x3D },
+	{ STV0900_QPSK_56,	0x3F,	0x3F,	0x3E,	0x1F,	0x0E,
+				0x3E,	0x0E,	0x1E,	0x3D,	0x3D },
+	{ STV0900_QPSK_89,	0x3F,	0x3F,	0x3E,	0x1F,	0x1E,
+				0x3E,	0x0E,	0x1E,	0x3D,	0x3D },
+	{ STV0900_QPSK_910,	0x3F,	0x3F,	0x3E,	0x1F,	0x1E,
+				0x3E,	0x0E,	0x1E,	0x3D,	0x3D },
+	{ STV0900_8PSK_35,	0x3c,	0x0c,	0x1c,	0x3b,	0x0c,
+				0x3b,	0x2b,	0x2b,	0x1b,	0x2b },
+	{ STV0900_8PSK_23,	0x1d,	0x0c,	0x3c,	0x0c,	0x2c,
+				0x3b,	0x0c,	0x2b,	0x2b,	0x2b },
+	{ STV0900_8PSK_34,	0x0e,	0x1c,	0x3d,	0x0c,	0x0d,
+				0x3b,	0x2c,	0x3b,	0x0c,	0x2b },
+	{ STV0900_8PSK_56,	0x2e,	0x3e,	0x1e,	0x2e,	0x2d,
+				0x1e,	0x3c,	0x2d,	0x2c,	0x1d },
+	{ STV0900_8PSK_89,	0x3e,	0x3e,	0x1e,	0x2e,	0x3d,
+				0x1e,	0x0d,	0x2d,	0x3c,	0x1d },
+	{ STV0900_8PSK_910,	0x3e,	0x3e, 	0x1e,	0x2e, 	0x3d,
+				0x1e,	0x1d,	0x2d,	0x0d,	0x1d },
+};
+
+
+
+/* Cut 2.0 Tracking carrier loop carrier 16APSK 2/3 to 32APSK 9/10 long Frame */
+static const struct stv0900_car_loop_optim FE_STV0900_S2APSKCarLoopCut20[11] = {
+	/* Modcod		2MPon 	2MPoff	5MPon 	5MPoff	10MPon
+				10MPoff	20MPon 	20MPoff	30MPon 	30MPoff */
+	{ STV0900_16APSK_23,	0x0C,	0x0C,	0x0C,	0x0C,	0x1D,
+				0x0C,	0x3C,	0x0C,	0x2C,	0x0C },
+	{ STV0900_16APSK_34,	0x0C,	0x0C,	0x0C,	0x0C,	0x0E,
+				0x0C,	0x2D,	0x0C,	0x1D,	0x0C },
+	{ STV0900_16APSK_45,	0x0C,	0x0C,	0x0C,	0x0C,	0x1E,
+				0x0C,	0x3D,	0x0C,	0x2D,	0x0C },
+	{ STV0900_16APSK_56,	0x0C,	0x0C,	0x0C,	0x0C,	0x1E,
+				0x0C,	0x3D,	0x0C,	0x2D,	0x0C },
+	{ STV0900_16APSK_89,	0x0C,	0x0C,	0x0C,	0x0C,	0x2E,
+				0x0C,	0x0E,	0x0C,	0x3D,	0x0C },
+	{ STV0900_16APSK_910,	0x0C,	0x0C,	0x0C,	0x0C,	0x2E,
+				0x0C,	0x0E,	0x0C,	0x3D,	0x0C },
+	{ STV0900_32APSK_34,	0x0C,	0x0C,	0x0C,	0x0C,	0x0C,
+				0x0C,	0x0C,	0x0C,	0x0C,	0x0C },
+	{ STV0900_32APSK_45,	0x0C,	0x0C,	0x0C,	0x0C,	0x0C,
+				0x0C,	0x0C,	0x0C,	0x0C,	0x0C },
+	{ STV0900_32APSK_56,	0x0C,	0x0C,	0x0C,	0x0C,	0x0C,
+				0x0C,	0x0C,	0x0C,	0x0C,	0x0C },
+	{ STV0900_32APSK_89,	0x0C,	0x0C,	0x0C,	0x0C,	0x0C,
+				0x0C,	0x0C,	0x0C,	0x0C,	0x0C },
+	{ STV0900_32APSK_910,	0x0C,	0x0C,	0x0C,	0x0C,	0x0C,
+				0x0C,	0x0C,	0x0C,	0x0C,	0x0C },
+};
+
+
+/* Cut 2.0 Tracking carrier loop carrier QPSK 1/4 to QPSK 2/5 long Frame */
+static const struct stv0900_car_loop_optim FE_STV0900_S2LowQPCarLoopCut20[3] = {
+	/* Modcod		2MPon 	2MPoff	5MPon 	5MPoff	10MPon
+				10MPoff	20MPon 	20MPoff	30MPon 	30MPoff */
+	{ STV0900_QPSK_14,	0x0F,	0x3F,	0x0E,	0x3F,	0x2D,
+				0x2F,	0x2D,	0x1F,	0x3D,	0x3E },
+	{ STV0900_QPSK_13,	0x0F,	0x3F,	0x0E,	0x3F,	0x2D,
+				0x2F,	0x3D,	0x0F,	0x3D,	0x2E },
+	{ STV0900_QPSK_25,	0x1F,	0x3F,	0x1E,	0x3F,	0x3D,
+				0x1F,	0x3D,	0x3E,	0x3D,	0x2E }
+};
+
+
+/* Cut 2.0 Tracking carrier loop carrier  short Frame, cut 1.2 and 2.0 */
+static const
+struct stv0900_short_frames_car_loop_optim FE_STV0900_S2ShortCarLoop[4] = {
+	/*Mod		2Mcut1.2 2Mcut2.0 5Mcut1.2 5Mcut2.0 10Mcut1.2
+			10Mcut2.0 20Mcut1.2 20M_cut2.0 30Mcut1.2 30Mcut2.0*/
+	{ STV0900_QPSK,		0x3C,	0x2F,	0x2B,	0x2E,	0x0B,
+				0x0E,	0x3A,	0x0E,	0x2A,	0x3D },
+	{ STV0900_8PSK,		0x0B,	0x3E,	0x2A,	0x0E,	0x0A,
+				0x2D,	0x19,	0x0D,	0x09,	0x3C },
+	{ STV0900_16APSK,	0x1B,	0x1E,	0x1B,	0x1E,	0x1B,
+				0x1E,	0x3A,	0x3D,	0x2A,	0x2D },
+	{ STV0900_32APSK,	0x1B,	0x1E,	0x1B,	0x1E,	0x1B,
+				0x1E,	0x3A,	0x3D,	0x2A,	0x2D }
+};
+
+static	const struct stv0900_car_loop_optim FE_STV0900_S2CarLoopCut30[14] = {
+	/*Modcod		2MPon 	2MPoff	5MPon 	5MPoff	10MPon
+				10MPoff	20MPon 	20MPoff	30MPon 	30MPoff	*/
+	{ STV0900_QPSK_12,	0x3C,	0x2C,	0x0C,	0x2C,	0x1B,
+				0x2C,	0x1B,	0x1C,	0x0B, 	0x3B },
+	{ STV0900_QPSK_35,	0x0D,	0x0D,	0x0C,	0x0D,	0x1B,
+				0x3C,	0x1B,	0x1C,	0x0B,	0x3B },
+	{ STV0900_QPSK_23,	0x1D,	0x0D,	0x0C,	0x1D,	0x2B,
+				0x3C,	0x1B,	0x1C,	0x0B,	0x3B },
+	{ STV0900_QPSK_34,	0x1D,	0x1D,	0x0C,	0x1D,	0x2B,
+				0x3C,	0x1B,	0x1C,	0x0B,	0x3B },
+	{ STV0900_QPSK_45,	0x2D,	0x1D,	0x1C,	0x1D,	0x2B,
+				0x3C,	0x2B,	0x0C,	0x1B,	0x3B },
+	{ STV0900_QPSK_56,	0x2D,	0x1D,	0x1C,	0x1D,	0x2B,
+				0x3C,	0x2B,	0x0C,	0x1B,	0x3B },
+	{ STV0900_QPSK_89,	0x3D,	0x2D,	0x1C,	0x1D,	0x3B,
+				0x3C,	0x2B,	0x0C,	0x1B,	0x3B },
+	{ STV0900_QPSK_910,	0x3D,	0x2D,	0x1C,	0x1D,	0x3B,
+				0x3C,	0x2B,	0x0C,	0x1B,	0x3B },
+	{ STV0900_8PSK_35,	0x39,	0x19,	0x39,	0x19,	0x19,
+				0x19,	0x19,	0x19,	0x09,	0x19 },
+	{ STV0900_8PSK_23,	0x2A,	0x39,	0x1A,	0x0A,	0x39,
+				0x0A,	0x29,	0x39,	0x29,	0x0A },
+	{ STV0900_8PSK_34,	0x0B,	0x3A,	0x0B,	0x0B,	0x3A,
+				0x1B,	0x1A,	0x0B,	0x1A,	0x3A },
+	{ STV0900_8PSK_56,	0x0C,	0x1B,	0x3B,	0x2B,	0x1B,
+				0x3B,	0x3A,	0x3B,	0x3A,	0x1B },
+	{ STV0900_8PSK_89,	0x2C,	0x2C,	0x2C,	0x1C,	0x2B,
+				0x0C,	0x0B,	0x3B,	0x0B,	0x1B },
+	{ STV0900_8PSK_910,	0x2C,	0x3C,	0x2C,	0x1C,	0x3B,
+				0x1C,	0x0B,	0x3B,	0x0B,	0x1B }
+};
+
+static	const
+struct stv0900_car_loop_optim FE_STV0900_S2APSKCarLoopCut30[11] = {
+	/*Modcod		2MPon 	2MPoff	5MPon 	5MPoff	10MPon
+				10MPoff	20MPon 	20MPoff	30MPon 	30MPoff	*/
+	{ STV0900_16APSK_23,	0x0A,	0x0A,	0x0A,	0x0A,	0x1A,
+				0x0A,	0x3A,	0x0A,	0x2A,	0x0A },
+	{ STV0900_16APSK_34,	0x0A,	0x0A,	0x0A,	0x0A,	0x0B,
+				0x0A,	0x3B,	0x0A,	0x1B,	0x0A },
+	{ STV0900_16APSK_45,	0x0A,	0x0A,	0x0A,	0x0A,	0x1B,
+				0x0A,	0x3B,	0x0A,	0x2B,	0x0A },
+	{ STV0900_16APSK_56,	0x0A,	0x0A,	0x0A,	0x0A,	0x1B,
+				0x0A,	0x3B,	0x0A,	0x2B,	0x0A },
+	{ STV0900_16APSK_89,	0x0A,	0x0A,	0x0A,	0x0A,	0x2B,
+				0x0A,	0x0C,	0x0A,	0x3B,	0x0A },
+	{ STV0900_16APSK_910,	0x0A,	0x0A,	0x0A,	0x0A,	0x2B,
+				0x0A,	0x0C,	0x0A,	0x3B,	0x0A },
+	{ STV0900_32APSK_34,	0x0A,	0x0A,	0x0A,	0x0A,	0x0A,
+				0x0A,	0x0A,	0x0A,	0x0A,	0x0A },
+	{ STV0900_32APSK_45,	0x0A,	0x0A,	0x0A,	0x0A,	0x0A,
+				0x0A,	0x0A,	0x0A,	0x0A,	0x0A },
+	{ STV0900_32APSK_56,	0x0A,	0x0A,	0x0A,	0x0A,	0x0A,
+				0x0A,	0x0A,	0x0A,	0x0A,	0x0A },
+	{ STV0900_32APSK_89,	0x0A,	0x0A,	0x0A,	0x0A,	0x0A,
+				0x0A,	0x0A,	0x0A,	0x0A,	0x0A },
+	{ STV0900_32APSK_910,	0x0A,	0x0A,	0x0A,	0x0A,	0x0A,
+				0x0A,	0x0A,	0x0A,	0x0A,	0x0A }
+};
+
+static	const
+struct stv0900_car_loop_optim FE_STV0900_S2LowQPCarLoopCut30[3] = {
+	/*Modcod		2MPon 	2MPoff	5MPon 	5MPoff	10MPon
+				10MPoff	20MPon 	20MPoff	30MPon 	30MPoff*/
+	{ STV0900_QPSK_14,	0x0C,	0x3C,	0x0B,	0x3C,	0x2A,
+				0x2C,	0x2A,	0x1C,	0x3A,	0x3B },
+	{ STV0900_QPSK_13,	0x0C,	0x3C,	0x0B,	0x3C,	0x2A,
+				0x2C,	0x3A,	0x0C,	0x3A,	0x2B },
+	{ STV0900_QPSK_25,	0x1C,	0x3C,	0x1B,	0x3C,	0x3A,
+				0x1C,	0x3A,	0x3B,	0x3A,	0x2B }
+};
+
+static	const struct stv0900_short_frames_car_loop_optim_vs_mod
+FE_STV0900_S2ShortCarLoopCut30[4] = {
+	/*Mod		2Mcut3.0 5Mcut3.0 10Mcut3.0 20Mcut3.0 30Mcut3.0*/
+	{ STV0900_QPSK,		0x2C,	0x2B,	0x0B,	0x0B,	0x3A },
+	{ STV0900_8PSK,		0x3B,	0x0B,	0x2A,	0x0A,	0x39 },
+	{ STV0900_16APSK,	0x1B,	0x1B,	0x1B,	0x3A,	0x2A },
+	{ STV0900_32APSK,	0x1B,	0x1B,	0x1B,	0x3A,	0x2A },
+
+};
+
+static const u16 STV0900_InitVal[181][2] = {
+	{ R0900_OUTCFG		, 0x00	},
+	{ R0900_AGCRF1CFG	, 0x11	},
+	{ R0900_AGCRF2CFG	, 0x13	},
+	{ R0900_TSGENERAL1X	, 0x14	},
+	{ R0900_TSTTNR2		, 0x21	},
+	{ R0900_TSTTNR4		, 0x21	},
+	{ R0900_P2_DISTXCTL	, 0x22	},
+	{ R0900_P2_F22TX	, 0xc0	},
+	{ R0900_P2_F22RX	, 0xc0	},
+	{ R0900_P2_DISRXCTL	, 0x00	},
+	{ R0900_P2_TNRSTEPS	, 0x87	},
+	{ R0900_P2_TNRGAIN	, 0x09	},
+	{ R0900_P2_DMDCFGMD	, 0xF9	},
+	{ R0900_P2_DEMOD	, 0x08	},
+	{ R0900_P2_DMDCFG3	, 0xc4	},
+	{ R0900_P2_CARFREQ	, 0xed	},
+	{ R0900_P2_TNRCFG2	, 0x02	},
+	{ R0900_P2_TNRCFG3	, 0x02	},
+	{ R0900_P2_LDT		, 0xd0	},
+	{ R0900_P2_LDT2		, 0xb8	},
+	{ R0900_P2_TMGCFG	, 0xd2	},
+	{ R0900_P2_TMGTHRISE	, 0x20	},
+	{ R0900_P2_TMGTHFALL	, 0x00	},
+	{ R0900_P2_FECSPY	, 0x88	},
+	{ R0900_P2_FSPYDATA	, 0x3a	},
+	{ R0900_P2_FBERCPT4	, 0x00	},
+	{ R0900_P2_FSPYBER	, 0x10	},
+	{ R0900_P2_ERRCTRL1	, 0x35	},
+	{ R0900_P2_ERRCTRL2	, 0xc1	},
+	{ R0900_P2_CFRICFG	, 0xf8	},
+	{ R0900_P2_NOSCFG	, 0x1c	},
+	{ R0900_P2_DMDT0M	, 0x20	},
+	{ R0900_P2_CORRELMANT	, 0x70	},
+	{ R0900_P2_CORRELABS	, 0x88	},
+	{ R0900_P2_AGC2O	, 0x5b	},
+	{ R0900_P2_AGC2REF	, 0x38	},
+	{ R0900_P2_CARCFG	, 0xe4	},
+	{ R0900_P2_ACLC		, 0x1A	},
+	{ R0900_P2_BCLC		, 0x09	},
+	{ R0900_P2_CARHDR	, 0x08	},
+	{ R0900_P2_KREFTMG	, 0xc1	},
+	{ R0900_P2_SFRUPRATIO	, 0xf0	},
+	{ R0900_P2_SFRLOWRATIO	, 0x70	},
+	{ R0900_P2_SFRSTEP	, 0x58	},
+	{ R0900_P2_TMGCFG2	, 0x01	},
+	{ R0900_P2_CAR2CFG	, 0x26	},
+	{ R0900_P2_BCLC2S2Q	, 0x86	},
+	{ R0900_P2_BCLC2S28	, 0x86	},
+	{ R0900_P2_SMAPCOEF7	, 0x77	},
+	{ R0900_P2_SMAPCOEF6	, 0x85	},
+	{ R0900_P2_SMAPCOEF5	, 0x77	},
+	{ R0900_P2_TSCFGL	, 0x20	},
+	{ R0900_P2_DMDCFG2	, 0x3b	},
+	{ R0900_P2_MODCODLST0	, 0xff	},
+	{ R0900_P2_MODCODLST1	, 0xff	},
+	{ R0900_P2_MODCODLST2	, 0xff	},
+	{ R0900_P2_MODCODLST3	, 0xff	},
+	{ R0900_P2_MODCODLST4	, 0xff	},
+	{ R0900_P2_MODCODLST5	, 0xff	},
+	{ R0900_P2_MODCODLST6	, 0xff	},
+	{ R0900_P2_MODCODLST7	, 0xcc	},
+	{ R0900_P2_MODCODLST8	, 0xcc	},
+	{ R0900_P2_MODCODLST9	, 0xcc	},
+	{ R0900_P2_MODCODLSTA	, 0xcc	},
+	{ R0900_P2_MODCODLSTB	, 0xcc	},
+	{ R0900_P2_MODCODLSTC	, 0xcc	},
+	{ R0900_P2_MODCODLSTD	, 0xcc	},
+	{ R0900_P2_MODCODLSTE	, 0xcc	},
+	{ R0900_P2_MODCODLSTF	, 0xcf	},
+	{ R0900_P1_DISTXCTL	, 0x22	},
+	{ R0900_P1_F22TX	, 0xc0	},
+	{ R0900_P1_F22RX	, 0xc0	},
+	{ R0900_P1_DISRXCTL	, 0x00	},
+	{ R0900_P1_TNRSTEPS	, 0x87	},
+	{ R0900_P1_TNRGAIN	, 0x09	},
+	{ R0900_P1_DMDCFGMD	, 0xf9	},
+	{ R0900_P1_DEMOD	, 0x08	},
+	{ R0900_P1_DMDCFG3	, 0xc4	},
+	{ R0900_P1_DMDT0M	, 0x20	},
+	{ R0900_P1_CARFREQ	, 0xed	},
+	{ R0900_P1_TNRCFG2	, 0x82	},
+	{ R0900_P1_TNRCFG3	, 0x02	},
+	{ R0900_P1_LDT		, 0xd0	},
+	{ R0900_P1_LDT2		, 0xb8	},
+	{ R0900_P1_TMGCFG	, 0xd2	},
+	{ R0900_P1_TMGTHRISE	, 0x20	},
+	{ R0900_P1_TMGTHFALL	, 0x00	},
+	{ R0900_P1_SFRUPRATIO	, 0xf0	},
+	{ R0900_P1_SFRLOWRATIO	, 0x70	},
+	{ R0900_P1_TSCFGL	, 0x20	},
+	{ R0900_P1_FECSPY	, 0x88	},
+	{ R0900_P1_FSPYDATA	, 0x3a	},
+	{ R0900_P1_FBERCPT4	, 0x00	},
+	{ R0900_P1_FSPYBER	, 0x10	},
+	{ R0900_P1_ERRCTRL1	, 0x35	},
+	{ R0900_P1_ERRCTRL2	, 0xc1	},
+	{ R0900_P1_CFRICFG	, 0xf8	},
+	{ R0900_P1_NOSCFG	, 0x1c	},
+	{ R0900_P1_CORRELMANT	, 0x70	},
+	{ R0900_P1_CORRELABS	, 0x88	},
+	{ R0900_P1_AGC2O	, 0x5b	},
+	{ R0900_P1_AGC2REF	, 0x38	},
+	{ R0900_P1_CARCFG	, 0xe4	},
+	{ R0900_P1_ACLC		, 0x1A	},
+	{ R0900_P1_BCLC		, 0x09	},
+	{ R0900_P1_CARHDR	, 0x08	},
+	{ R0900_P1_KREFTMG	, 0xc1	},
+	{ R0900_P1_SFRSTEP	, 0x58	},
+	{ R0900_P1_TMGCFG2	, 0x01	},
+	{ R0900_P1_CAR2CFG	, 0x26	},
+	{ R0900_P1_BCLC2S2Q	, 0x86	},
+	{ R0900_P1_BCLC2S28	, 0x86	},
+	{ R0900_P1_SMAPCOEF7	, 0x77	},
+	{ R0900_P1_SMAPCOEF6	, 0x85	},
+	{ R0900_P1_SMAPCOEF5	, 0x77	},
+	{ R0900_P1_DMDCFG2	, 0x3b	},
+	{ R0900_P1_MODCODLST0	, 0xff	},
+	{ R0900_P1_MODCODLST1	, 0xff	},
+	{ R0900_P1_MODCODLST2	, 0xff	},
+	{ R0900_P1_MODCODLST3	, 0xff	},
+	{ R0900_P1_MODCODLST4	, 0xff	},
+	{ R0900_P1_MODCODLST5	, 0xff	},
+	{ R0900_P1_MODCODLST6	, 0xff	},
+	{ R0900_P1_MODCODLST7	, 0xcc	},
+	{ R0900_P1_MODCODLST8	, 0xcc	},
+	{ R0900_P1_MODCODLST9	, 0xcc	},
+	{ R0900_P1_MODCODLSTA	, 0xcc	},
+	{ R0900_P1_MODCODLSTB	, 0xcc	},
+	{ R0900_P1_MODCODLSTC	, 0xcc	},
+	{ R0900_P1_MODCODLSTD	, 0xcc	},
+	{ R0900_P1_MODCODLSTE	, 0xcc	},
+	{ R0900_P1_MODCODLSTF	, 0xcf	},
+	{ R0900_GENCFG		, 0x1d	},
+	{ R0900_NBITER_NF4	, 0x37	},
+	{ R0900_NBITER_NF5	, 0x29	},
+	{ R0900_NBITER_NF6	, 0x37	},
+	{ R0900_NBITER_NF7	, 0x33	},
+	{ R0900_NBITER_NF8	, 0x31	},
+	{ R0900_NBITER_NF9	, 0x2f	},
+	{ R0900_NBITER_NF10	, 0x39	},
+	{ R0900_NBITER_NF11	, 0x3a	},
+	{ R0900_NBITER_NF12	, 0x29	},
+	{ R0900_NBITER_NF13	, 0x37	},
+	{ R0900_NBITER_NF14	, 0x33	},
+	{ R0900_NBITER_NF15	, 0x2f	},
+	{ R0900_NBITER_NF16	, 0x39	},
+	{ R0900_NBITER_NF17	, 0x3a	},
+	{ R0900_NBITERNOERR	, 0x04	},
+	{ R0900_GAINLLR_NF4	, 0x0C	},
+	{ R0900_GAINLLR_NF5	, 0x0F	},
+	{ R0900_GAINLLR_NF6	, 0x11	},
+	{ R0900_GAINLLR_NF7	, 0x14	},
+	{ R0900_GAINLLR_NF8	, 0x17	},
+	{ R0900_GAINLLR_NF9	, 0x19	},
+	{ R0900_GAINLLR_NF10	, 0x20	},
+	{ R0900_GAINLLR_NF11	, 0x21	},
+	{ R0900_GAINLLR_NF12	, 0x0D	},
+	{ R0900_GAINLLR_NF13	, 0x0F	},
+	{ R0900_GAINLLR_NF14	, 0x13	},
+	{ R0900_GAINLLR_NF15	, 0x1A	},
+	{ R0900_GAINLLR_NF16	, 0x1F	},
+	{ R0900_GAINLLR_NF17	, 0x21	},
+	{ R0900_RCCFG2		, 0x20	},
+	{ R0900_P1_FECM		, 0x01	}, /*disable DSS modes*/
+	{ R0900_P2_FECM		, 0x01	}, /*disable DSS modes*/
+	{ R0900_P1_PRVIT	, 0x2F	}, /*disable puncture rate 6/7*/
+	{ R0900_P2_PRVIT	, 0x2F	}, /*disable puncture rate 6/7*/
+	{ R0900_STROUT1CFG	, 0x4c	},
+	{ R0900_STROUT2CFG	, 0x4c	},
+	{ R0900_CLKOUT1CFG	, 0x50	},
+	{ R0900_CLKOUT2CFG	, 0x50	},
+	{ R0900_DPN1CFG		, 0x4a	},
+	{ R0900_DPN2CFG		, 0x4a	},
+	{ R0900_DATA71CFG	, 0x52	},
+	{ R0900_DATA72CFG	, 0x52	},
+	{ R0900_P1_TSCFGM	, 0xc0	},
+	{ R0900_P2_TSCFGM	, 0xc0	},
+	{ R0900_P1_TSCFGH	, 0xe0	}, /* DVB-CI timings */
+	{ R0900_P2_TSCFGH	, 0xe0	}, /* DVB-CI timings */
+	{ R0900_P1_TSSPEED	, 0x40	},
+	{ R0900_P2_TSSPEED	, 0x40	},
+};
+
+static const u16 STV0900_Cut20_AddOnVal[32][2] = {
+	{ R0900_P2_DMDCFG3	, 0xe8	},
+	{ R0900_P2_DMDCFG4	, 0x10	},
+	{ R0900_P2_CARFREQ	, 0x38	},
+	{ R0900_P2_CARHDR	, 0x20	},
+	{ R0900_P2_KREFTMG	, 0x5a	},
+	{ R0900_P2_SMAPCOEF7	, 0x06	},
+	{ R0900_P2_SMAPCOEF6	, 0x00	},
+	{ R0900_P2_SMAPCOEF5	, 0x04	},
+	{ R0900_P2_NOSCFG	, 0x0c	},
+	{ R0900_P1_DMDCFG3	, 0xe8	},
+	{ R0900_P1_DMDCFG4	, 0x10	},
+	{ R0900_P1_CARFREQ	, 0x38	},
+	{ R0900_P1_CARHDR	, 0x20	},
+	{ R0900_P1_KREFTMG	, 0x5a	},
+	{ R0900_P1_SMAPCOEF7	, 0x06	},
+	{ R0900_P1_SMAPCOEF6	, 0x00	},
+	{ R0900_P1_SMAPCOEF5	, 0x04	},
+	{ R0900_P1_NOSCFG	, 0x0c	},
+	{ R0900_GAINLLR_NF4	, 0x21	},
+	{ R0900_GAINLLR_NF5	, 0x21	},
+	{ R0900_GAINLLR_NF6	, 0x20	},
+	{ R0900_GAINLLR_NF7	, 0x1F	},
+	{ R0900_GAINLLR_NF8	, 0x1E	},
+	{ R0900_GAINLLR_NF9	, 0x1E	},
+	{ R0900_GAINLLR_NF10	, 0x1D	},
+	{ R0900_GAINLLR_NF11	, 0x1B	},
+	{ R0900_GAINLLR_NF12	, 0x20	},
+	{ R0900_GAINLLR_NF13	, 0x20	},
+	{ R0900_GAINLLR_NF14	, 0x20	},
+	{ R0900_GAINLLR_NF15	, 0x20	},
+	{ R0900_GAINLLR_NF16	, 0x20	},
+	{ R0900_GAINLLR_NF17	, 0x21	}
+
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/stv0900_priv.h b/drivers/media/dvb-frontends/stv0900_priv.h
new file mode 100644
index 0000000..e0ea74c
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv0900_priv.h
@@ -0,0 +1,408 @@
+/*
+ * stv0900_priv.h
+ *
+ * Driver for ST STV0900 satellite demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef STV0900_PRIV_H
+#define STV0900_PRIV_H
+
+#include <linux/i2c.h>
+
+#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X))
+#define INRANGE(X, Y, Z) ((((X) <= (Y)) && ((Y) <= (Z))) \
+		|| (((Z) <= (Y)) && ((Y) <= (X))) ? 1 : 0)
+
+#ifndef MAKEWORD
+#define MAKEWORD(X, Y) (((X) << 8) + (Y))
+#endif
+
+#define LSB(X) (((X) & 0xFF))
+#define MSB(Y) (((Y) >> 8) & 0xFF)
+
+#ifndef TRUE
+#define TRUE (1 == 1)
+#endif
+#ifndef FALSE
+#define FALSE (!TRUE)
+#endif
+
+#define dprintk(args...) \
+	do { \
+		if (stvdebug) \
+			printk(KERN_DEBUG args); \
+	} while (0)
+
+#define STV0900_MAXLOOKUPSIZE 500
+#define STV0900_BLIND_SEARCH_AGC2_TH 700
+#define STV0900_BLIND_SEARCH_AGC2_TH_CUT30 1400
+#define IQPOWER_THRESHOLD  30
+
+/* One point of the lookup table */
+struct stv000_lookpoint {
+	s32 realval;/* real value */
+	s32 regval;/* binary value */
+};
+
+/* Lookup table definition */
+struct stv0900_table{
+	s32 size;/* Size of the lookup table */
+	struct stv000_lookpoint table[STV0900_MAXLOOKUPSIZE];/* Lookup table */
+};
+
+enum fe_stv0900_error {
+	STV0900_NO_ERROR = 0,
+	STV0900_INVALID_HANDLE,
+	STV0900_BAD_PARAMETER,
+	STV0900_I2C_ERROR,
+	STV0900_SEARCH_FAILED,
+};
+
+enum fe_stv0900_clock_type {
+	STV0900_USE_REGISTERS_DEFAULT,
+	STV0900_SERIAL_PUNCT_CLOCK,/*Serial punctured clock */
+	STV0900_SERIAL_CONT_CLOCK,/*Serial continues clock */
+	STV0900_PARALLEL_PUNCT_CLOCK,/*Parallel punctured clock */
+	STV0900_DVBCI_CLOCK/*Parallel continues clock : DVBCI */
+};
+
+enum fe_stv0900_search_state {
+	STV0900_SEARCH = 0,
+	STV0900_PLH_DETECTED,
+	STV0900_DVBS2_FOUND,
+	STV0900_DVBS_FOUND
+
+};
+
+enum fe_stv0900_ldpc_state {
+	STV0900_PATH1_OFF_PATH2_OFF = 0,
+	STV0900_PATH1_ON_PATH2_OFF = 1,
+	STV0900_PATH1_OFF_PATH2_ON = 2,
+	STV0900_PATH1_ON_PATH2_ON = 3
+};
+
+enum fe_stv0900_signal_type {
+	STV0900_NOAGC1 = 0,
+	STV0900_AGC1OK,
+	STV0900_NOTIMING,
+	STV0900_ANALOGCARRIER,
+	STV0900_TIMINGOK,
+	STV0900_NOAGC2,
+	STV0900_AGC2OK,
+	STV0900_NOCARRIER,
+	STV0900_CARRIEROK,
+	STV0900_NODATA,
+	STV0900_DATAOK,
+	STV0900_OUTOFRANGE,
+	STV0900_RANGEOK
+};
+
+enum fe_stv0900_demod_num {
+	STV0900_DEMOD_1,
+	STV0900_DEMOD_2
+};
+
+enum fe_stv0900_tracking_standard {
+	STV0900_DVBS1_STANDARD,/* Found Standard*/
+	STV0900_DVBS2_STANDARD,
+	STV0900_DSS_STANDARD,
+	STV0900_TURBOCODE_STANDARD,
+	STV0900_UNKNOWN_STANDARD
+};
+
+enum fe_stv0900_search_standard {
+	STV0900_AUTO_SEARCH,
+	STV0900_SEARCH_DVBS1,/* Search Standard*/
+	STV0900_SEARCH_DVBS2,
+	STV0900_SEARCH_DSS,
+	STV0900_SEARCH_TURBOCODE
+};
+
+enum fe_stv0900_search_algo {
+	STV0900_BLIND_SEARCH,/* offset freq and SR are Unknown */
+	STV0900_COLD_START,/* only the SR is known */
+	STV0900_WARM_START/* offset freq and SR are known */
+};
+
+enum fe_stv0900_modulation {
+	STV0900_QPSK,
+	STV0900_8PSK,
+	STV0900_16APSK,
+	STV0900_32APSK,
+	STV0900_UNKNOWN
+};
+
+enum fe_stv0900_modcode {
+	STV0900_DUMMY_PLF,
+	STV0900_QPSK_14,
+	STV0900_QPSK_13,
+	STV0900_QPSK_25,
+	STV0900_QPSK_12,
+	STV0900_QPSK_35,
+	STV0900_QPSK_23,
+	STV0900_QPSK_34,
+	STV0900_QPSK_45,
+	STV0900_QPSK_56,
+	STV0900_QPSK_89,
+	STV0900_QPSK_910,
+	STV0900_8PSK_35,
+	STV0900_8PSK_23,
+	STV0900_8PSK_34,
+	STV0900_8PSK_56,
+	STV0900_8PSK_89,
+	STV0900_8PSK_910,
+	STV0900_16APSK_23,
+	STV0900_16APSK_34,
+	STV0900_16APSK_45,
+	STV0900_16APSK_56,
+	STV0900_16APSK_89,
+	STV0900_16APSK_910,
+	STV0900_32APSK_34,
+	STV0900_32APSK_45,
+	STV0900_32APSK_56,
+	STV0900_32APSK_89,
+	STV0900_32APSK_910,
+	STV0900_MODCODE_UNKNOWN
+};
+
+enum fe_stv0900_fec {/*DVBS1, DSS and turbo code puncture rate*/
+	STV0900_FEC_1_2 = 0,
+	STV0900_FEC_2_3,
+	STV0900_FEC_3_4,
+	STV0900_FEC_4_5,/*for turbo code only*/
+	STV0900_FEC_5_6,
+	STV0900_FEC_6_7,/*for DSS only */
+	STV0900_FEC_7_8,
+	STV0900_FEC_8_9,/*for turbo code only*/
+	STV0900_FEC_UNKNOWN
+};
+
+enum fe_stv0900_frame_length {
+	STV0900_LONG_FRAME,
+	STV0900_SHORT_FRAME
+};
+
+enum fe_stv0900_pilot {
+	STV0900_PILOTS_OFF,
+	STV0900_PILOTS_ON
+};
+
+enum fe_stv0900_rolloff {
+	STV0900_35,
+	STV0900_25,
+	STV0900_20
+};
+
+enum fe_stv0900_search_iq {
+	STV0900_IQ_AUTO,
+	STV0900_IQ_AUTO_NORMAL_FIRST,
+	STV0900_IQ_FORCE_NORMAL,
+	STV0900_IQ_FORCE_SWAPPED
+};
+
+enum stv0900_iq_inversion {
+	STV0900_IQ_NORMAL,
+	STV0900_IQ_SWAPPED
+};
+
+enum fe_stv0900_diseqc_mode {
+	STV0900_22KHZ_Continues = 0,
+	STV0900_DISEQC_2_3_PWM = 2,
+	STV0900_DISEQC_3_3_PWM = 3,
+	STV0900_DISEQC_2_3_ENVELOP = 4,
+	STV0900_DISEQC_3_3_ENVELOP = 5
+};
+
+enum fe_stv0900_demod_mode {
+	STV0900_SINGLE = 0,
+	STV0900_DUAL
+};
+
+struct stv0900_init_params{
+	u32	dmd_ref_clk;/* Reference,Input clock for the demod in Hz */
+
+	/* Demodulator Type (single demod or dual demod) */
+	enum fe_stv0900_demod_mode	demod_mode;
+	enum fe_stv0900_rolloff		rolloff;
+	enum fe_stv0900_clock_type	path1_ts_clock;
+
+	u8	tun1_maddress;
+	int	tuner1_adc;
+	int 	tuner1_type;
+
+	/* IQ from the tuner1 to the demod */
+	enum stv0900_iq_inversion	tun1_iq_inv;
+	enum fe_stv0900_clock_type	path2_ts_clock;
+
+	u8	tun2_maddress;
+	int	tuner2_adc;
+	int	tuner2_type;
+
+	/* IQ from the tuner2 to the demod */
+	enum stv0900_iq_inversion	tun2_iq_inv;
+	struct stv0900_reg		*ts_config;
+};
+
+struct stv0900_search_params {
+	enum fe_stv0900_demod_num	path;/* Path Used demod1 or 2 */
+
+	u32	frequency;/* Transponder frequency (in KHz) */
+	u32	symbol_rate;/* Transponder symbol rate  (in bds)*/
+	u32	search_range;/* Range of the search (in Hz) */
+
+	enum fe_stv0900_search_standard	standard;
+	enum fe_stv0900_modulation	modulation;
+	enum fe_stv0900_fec		fec;
+	enum fe_stv0900_modcode		modcode;
+	enum fe_stv0900_search_iq	iq_inversion;
+	enum fe_stv0900_search_algo	search_algo;
+
+};
+
+struct stv0900_signal_info {
+	int	locked;/* Transponder locked */
+	u32	frequency;/* Transponder frequency (in KHz) */
+	u32	symbol_rate;/* Transponder symbol rate  (in Mbds) */
+
+	enum fe_stv0900_tracking_standard	standard;
+	enum fe_stv0900_fec			fec;
+	enum fe_stv0900_modcode			modcode;
+	enum fe_stv0900_modulation		modulation;
+	enum fe_stv0900_pilot			pilot;
+	enum fe_stv0900_frame_length		frame_len;
+	enum stv0900_iq_inversion		spectrum;
+	enum fe_stv0900_rolloff			rolloff;
+
+	s32 Power;/* Power of the RF signal (dBm) */
+	s32 C_N;/* Carrier to noise ratio (dB x10)*/
+	u32 BER;/* Bit error rate (x10^7) */
+
+};
+
+struct stv0900_internal{
+	s32	quartz;
+	s32	mclk;
+	/* manual RollOff for DVBS1/DSS only */
+	enum fe_stv0900_rolloff		rolloff;
+	/* Demodulator use for single demod or for dual demod) */
+	enum fe_stv0900_demod_mode	demod_mode;
+
+	/*Demods */
+	s32	freq[2];
+	s32	bw[2];
+	s32	symbol_rate[2];
+	s32	srch_range[2];
+	/* for software/auto tuner */
+	int	tuner_type[2];
+
+	/* algorithm for search Blind, Cold or Warm*/
+	enum fe_stv0900_search_algo	srch_algo[2];
+	/* search standard: Auto, DVBS1/DSS only or DVBS2 only*/
+	enum fe_stv0900_search_standard	srch_standard[2];
+	/* inversion search : auto, auto norma first, normal or inverted */
+	enum fe_stv0900_search_iq	srch_iq_inv[2];
+	enum fe_stv0900_modcode		modcode[2];
+	enum fe_stv0900_modulation	modulation[2];
+	enum fe_stv0900_fec		fec[2];
+
+	struct stv0900_signal_info	result[2];
+	enum fe_stv0900_error		err[2];
+
+
+	struct i2c_adapter	*i2c_adap;
+	u8			i2c_addr;
+	u8			clkmode;/* 0 for CLKI, 2 for XTALI */
+	u8			chip_id;
+	struct stv0900_reg	*ts_config;
+	enum fe_stv0900_error	errs;
+	int dmds_used;
+};
+
+/* state for each demod */
+struct stv0900_state {
+	/* pointer for internal params, one for each pair of demods */
+	struct stv0900_internal		*internal;
+	struct i2c_adapter		*i2c_adap;
+	const struct stv0900_config	*config;
+	struct dvb_frontend		frontend;
+	int demod;
+};
+
+extern int stvdebug;
+
+extern s32 ge2comp(s32 a, s32 width);
+
+extern void stv0900_write_reg(struct stv0900_internal *i_params,
+				u16 reg_addr, u8 reg_data);
+
+extern u8 stv0900_read_reg(struct stv0900_internal *i_params,
+				u16 reg_addr);
+
+extern void stv0900_write_bits(struct stv0900_internal *i_params,
+				u32 label, u8 val);
+
+extern u8 stv0900_get_bits(struct stv0900_internal *i_params,
+				u32 label);
+
+extern int stv0900_get_demod_lock(struct stv0900_internal *i_params,
+				enum fe_stv0900_demod_num demod, s32 time_out);
+extern int stv0900_check_signal_presence(struct stv0900_internal *i_params,
+				enum fe_stv0900_demod_num demod);
+
+extern enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe);
+
+extern void stv0900_set_tuner(struct dvb_frontend *fe, u32 frequency,
+				u32 bandwidth);
+extern void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth);
+
+extern void stv0900_start_search(struct stv0900_internal *i_params,
+				enum fe_stv0900_demod_num demod);
+
+extern u8 stv0900_get_optim_carr_loop(s32 srate,
+				enum fe_stv0900_modcode modcode,
+				s32 pilot, u8 chip_id);
+
+extern u8 stv0900_get_optim_short_carr_loop(s32 srate,
+				enum fe_stv0900_modulation modulation,
+				u8 chip_id);
+
+extern void stv0900_stop_all_s2_modcod(struct stv0900_internal *i_params,
+				enum fe_stv0900_demod_num demod);
+
+extern void stv0900_activate_s2_modcod(struct stv0900_internal *i_params,
+				enum fe_stv0900_demod_num demod);
+
+extern void stv0900_activate_s2_modcod_single(struct stv0900_internal *i_params,
+				enum fe_stv0900_demod_num demod);
+
+extern enum
+fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe,
+				enum fe_stv0900_demod_num demod);
+
+extern u32
+stv0900_get_freq_auto(struct stv0900_internal *intp, int demod);
+
+extern void
+stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency,
+						u32 Bandwidth, int demod);
+
+#endif
diff --git a/drivers/media/dvb-frontends/stv0900_reg.h b/drivers/media/dvb-frontends/stv0900_reg.h
new file mode 100644
index 0000000..731afe9
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv0900_reg.h
@@ -0,0 +1,3981 @@
+/*
+ * stv0900_reg.h
+ *
+ * Driver for ST STV0900 satellite demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef STV0900_REG_H
+#define STV0900_REG_H
+
+extern s32 shiftx(s32 x, int demod, s32 shift);
+
+#define REGx(x) shiftx(x, demod, 0x200)
+#define FLDx(x) shiftx(x, demod, 0x2000000)
+
+/*MID*/
+#define R0900_MID 0xf100
+#define F0900_MCHIP_IDENT 0xf10000f0
+#define F0900_MRELEASE 0xf100000f
+
+/*DACR1*/
+#define R0900_DACR1 0xf113
+#define F0900_DAC_MODE 0xf11300e0
+#define F0900_DAC_VALUE1 0xf113000f
+
+/*DACR2*/
+#define R0900_DACR2 0xf114
+#define F0900_DAC_VALUE0 0xf11400ff
+
+/*OUTCFG*/
+#define R0900_OUTCFG 0xf11c
+#define F0900_OUTSERRS1_HZ 0xf11c0040
+#define F0900_OUTSERRS2_HZ 0xf11c0020
+#define F0900_OUTSERRS3_HZ 0xf11c0010
+#define F0900_OUTPARRS3_HZ 0xf11c0008
+
+/*IRQSTATUS3*/
+#define R0900_IRQSTATUS3 0xf120
+#define F0900_SPLL_LOCK 0xf1200020
+#define F0900_SSTREAM_LCK_3 0xf1200010
+#define F0900_SSTREAM_LCK_2 0xf1200008
+#define F0900_SSTREAM_LCK_1 0xf1200004
+#define F0900_SDVBS1_PRF_2 0xf1200002
+#define F0900_SDVBS1_PRF_1 0xf1200001
+
+/*IRQSTATUS2*/
+#define R0900_IRQSTATUS2 0xf121
+#define F0900_SSPY_ENDSIM_3 0xf1210080
+#define F0900_SSPY_ENDSIM_2 0xf1210040
+#define F0900_SSPY_ENDSIM_1 0xf1210020
+#define F0900_SPKTDEL_ERROR_2 0xf1210010
+#define F0900_SPKTDEL_LOCKB_2 0xf1210008
+#define F0900_SPKTDEL_LOCK_2 0xf1210004
+#define F0900_SPKTDEL_ERROR_1 0xf1210002
+#define F0900_SPKTDEL_LOCKB_1 0xf1210001
+
+/*IRQSTATUS1*/
+#define R0900_IRQSTATUS1 0xf122
+#define F0900_SPKTDEL_LOCK_1 0xf1220080
+#define F0900_SDEMOD_LOCKB_2 0xf1220004
+#define F0900_SDEMOD_LOCK_2 0xf1220002
+#define F0900_SDEMOD_IRQ_2 0xf1220001
+
+/*IRQSTATUS0*/
+#define R0900_IRQSTATUS0 0xf123
+#define F0900_SDEMOD_LOCKB_1 0xf1230080
+#define F0900_SDEMOD_LOCK_1 0xf1230040
+#define F0900_SDEMOD_IRQ_1 0xf1230020
+#define F0900_SBCH_ERRFLAG 0xf1230010
+#define F0900_SDISEQC2RX_IRQ 0xf1230008
+#define F0900_SDISEQC2TX_IRQ 0xf1230004
+#define F0900_SDISEQC1RX_IRQ 0xf1230002
+#define F0900_SDISEQC1TX_IRQ 0xf1230001
+
+/*IRQMASK3*/
+#define R0900_IRQMASK3 0xf124
+#define F0900_MPLL_LOCK 0xf1240020
+#define F0900_MSTREAM_LCK_3 0xf1240010
+#define F0900_MSTREAM_LCK_2 0xf1240008
+#define F0900_MSTREAM_LCK_1 0xf1240004
+#define F0900_MDVBS1_PRF_2 0xf1240002
+#define F0900_MDVBS1_PRF_1 0xf1240001
+
+/*IRQMASK2*/
+#define R0900_IRQMASK2 0xf125
+#define F0900_MSPY_ENDSIM_3 0xf1250080
+#define F0900_MSPY_ENDSIM_2 0xf1250040
+#define F0900_MSPY_ENDSIM_1 0xf1250020
+#define F0900_MPKTDEL_ERROR_2 0xf1250010
+#define F0900_MPKTDEL_LOCKB_2 0xf1250008
+#define F0900_MPKTDEL_LOCK_2 0xf1250004
+#define F0900_MPKTDEL_ERROR_1 0xf1250002
+#define F0900_MPKTDEL_LOCKB_1 0xf1250001
+
+/*IRQMASK1*/
+#define R0900_IRQMASK1 0xf126
+#define F0900_MPKTDEL_LOCK_1 0xf1260080
+#define F0900_MEXTPINB2 0xf1260040
+#define F0900_MEXTPIN2 0xf1260020
+#define F0900_MEXTPINB1 0xf1260010
+#define F0900_MEXTPIN1 0xf1260008
+#define F0900_MDEMOD_LOCKB_2 0xf1260004
+#define F0900_MDEMOD_LOCK_2 0xf1260002
+#define F0900_MDEMOD_IRQ_2 0xf1260001
+
+/*IRQMASK0*/
+#define R0900_IRQMASK0 0xf127
+#define F0900_MDEMOD_LOCKB_1 0xf1270080
+#define F0900_MDEMOD_LOCK_1 0xf1270040
+#define F0900_MDEMOD_IRQ_1 0xf1270020
+#define F0900_MBCH_ERRFLAG 0xf1270010
+#define F0900_MDISEQC2RX_IRQ 0xf1270008
+#define F0900_MDISEQC2TX_IRQ 0xf1270004
+#define F0900_MDISEQC1RX_IRQ 0xf1270002
+#define F0900_MDISEQC1TX_IRQ 0xf1270001
+
+/*I2CCFG*/
+#define R0900_I2CCFG 0xf129
+#define F0900_I2C_FASTMODE 0xf1290008
+#define F0900_I2CADDR_INC 0xf1290003
+
+/*P1_I2CRPT*/
+#define R0900_P1_I2CRPT 0xf12a
+#define I2CRPT shiftx(R0900_P1_I2CRPT, demod, -1)
+#define F0900_P1_I2CT_ON 0xf12a0080
+#define I2CT_ON shiftx(F0900_P1_I2CT_ON, demod, -0x10000)
+#define F0900_P1_ENARPT_LEVEL 0xf12a0070
+#define F0900_P1_SCLT_DELAY 0xf12a0008
+#define F0900_P1_STOP_ENABLE 0xf12a0004
+#define F0900_P1_STOP_SDAT2SDA 0xf12a0002
+
+/*P2_I2CRPT*/
+#define R0900_P2_I2CRPT 0xf12b
+#define F0900_P2_I2CT_ON 0xf12b0080
+#define F0900_P2_ENARPT_LEVEL 0xf12b0070
+#define F0900_P2_SCLT_DELAY 0xf12b0008
+#define F0900_P2_STOP_ENABLE 0xf12b0004
+#define F0900_P2_STOP_SDAT2SDA 0xf12b0002
+
+/*IOPVALUE6*/
+#define R0900_IOPVALUE6 0xf138
+#define F0900_VSCL 0xf1380004
+#define F0900_VSDA 0xf1380002
+#define F0900_VDATA3_0 0xf1380001
+
+/*IOPVALUE5*/
+#define R0900_IOPVALUE5 0xf139
+#define F0900_VDATA3_1 0xf1390080
+#define F0900_VDATA3_2 0xf1390040
+#define F0900_VDATA3_3 0xf1390020
+#define F0900_VDATA3_4 0xf1390010
+#define F0900_VDATA3_5 0xf1390008
+#define F0900_VDATA3_6 0xf1390004
+#define F0900_VDATA3_7 0xf1390002
+#define F0900_VCLKOUT3 0xf1390001
+
+/*IOPVALUE4*/
+#define R0900_IOPVALUE4 0xf13a
+#define F0900_VSTROUT3 0xf13a0080
+#define F0900_VDPN3 0xf13a0040
+#define F0900_VERROR3 0xf13a0020
+#define F0900_VDATA2_7 0xf13a0010
+#define F0900_VCLKOUT2 0xf13a0008
+#define F0900_VSTROUT2 0xf13a0004
+#define F0900_VDPN2 0xf13a0002
+#define F0900_VERROR2 0xf13a0001
+
+/*IOPVALUE3*/
+#define R0900_IOPVALUE3 0xf13b
+#define F0900_VDATA1_7 0xf13b0080
+#define F0900_VCLKOUT1 0xf13b0040
+#define F0900_VSTROUT1 0xf13b0020
+#define F0900_VDPN1 0xf13b0010
+#define F0900_VERROR1 0xf13b0008
+#define F0900_VCLKOUT27 0xf13b0004
+#define F0900_VDISEQCOUT2 0xf13b0002
+#define F0900_VSCLT2 0xf13b0001
+
+/*IOPVALUE2*/
+#define R0900_IOPVALUE2 0xf13c
+#define F0900_VSDAT2 0xf13c0080
+#define F0900_VAGCRF2 0xf13c0040
+#define F0900_VDISEQCOUT1 0xf13c0020
+#define F0900_VSCLT1 0xf13c0010
+#define F0900_VSDAT1 0xf13c0008
+#define F0900_VAGCRF1 0xf13c0004
+#define F0900_VDIRCLK 0xf13c0002
+#define F0900_VSTDBY 0xf13c0001
+
+/*IOPVALUE1*/
+#define R0900_IOPVALUE1 0xf13d
+#define F0900_VCS1 0xf13d0080
+#define F0900_VCS0 0xf13d0040
+#define F0900_VGPIO13 0xf13d0020
+#define F0900_VGPIO12 0xf13d0010
+#define F0900_VGPIO11 0xf13d0008
+#define F0900_VGPIO10 0xf13d0004
+#define F0900_VGPIO9 0xf13d0002
+#define F0900_VGPIO8 0xf13d0001
+
+/*IOPVALUE0*/
+#define R0900_IOPVALUE0 0xf13e
+#define F0900_VGPIO7 0xf13e0080
+#define F0900_VGPIO6 0xf13e0040
+#define F0900_VGPIO5 0xf13e0020
+#define F0900_VGPIO4 0xf13e0010
+#define F0900_VGPIO3 0xf13e0008
+#define F0900_VGPIO2 0xf13e0004
+#define F0900_VGPIO1 0xf13e0002
+#define F0900_VCLKI2 0xf13e0001
+
+/*CLKI2CFG*/
+#define R0900_CLKI2CFG 0xf140
+#define F0900_CLKI2_OPD 0xf1400080
+#define F0900_CLKI2_CONFIG 0xf140007e
+#define F0900_CLKI2_XOR 0xf1400001
+
+/*GPIO1CFG*/
+#define R0900_GPIO1CFG 0xf141
+#define F0900_GPIO1_OPD 0xf1410080
+#define F0900_GPIO1_CONFIG 0xf141007e
+#define F0900_GPIO1_XOR 0xf1410001
+
+/*GPIO2CFG*/
+#define R0900_GPIO2CFG 0xf142
+#define F0900_GPIO2_OPD 0xf1420080
+#define F0900_GPIO2_CONFIG 0xf142007e
+#define F0900_GPIO2_XOR 0xf1420001
+
+/*GPIO3CFG*/
+#define R0900_GPIO3CFG 0xf143
+#define F0900_GPIO3_OPD 0xf1430080
+#define F0900_GPIO3_CONFIG 0xf143007e
+#define F0900_GPIO3_XOR 0xf1430001
+
+/*GPIO4CFG*/
+#define R0900_GPIO4CFG 0xf144
+#define F0900_GPIO4_OPD 0xf1440080
+#define F0900_GPIO4_CONFIG 0xf144007e
+#define F0900_GPIO4_XOR 0xf1440001
+
+/*GPIO5CFG*/
+#define R0900_GPIO5CFG 0xf145
+#define F0900_GPIO5_OPD 0xf1450080
+#define F0900_GPIO5_CONFIG 0xf145007e
+#define F0900_GPIO5_XOR 0xf1450001
+
+/*GPIO6CFG*/
+#define R0900_GPIO6CFG 0xf146
+#define F0900_GPIO6_OPD 0xf1460080
+#define F0900_GPIO6_CONFIG 0xf146007e
+#define F0900_GPIO6_XOR 0xf1460001
+
+/*GPIO7CFG*/
+#define R0900_GPIO7CFG 0xf147
+#define F0900_GPIO7_OPD 0xf1470080
+#define F0900_GPIO7_CONFIG 0xf147007e
+#define F0900_GPIO7_XOR 0xf1470001
+
+/*GPIO8CFG*/
+#define R0900_GPIO8CFG 0xf148
+#define F0900_GPIO8_OPD 0xf1480080
+#define F0900_GPIO8_CONFIG 0xf148007e
+#define F0900_GPIO8_XOR 0xf1480001
+
+/*GPIO9CFG*/
+#define R0900_GPIO9CFG 0xf149
+#define F0900_GPIO9_OPD 0xf1490080
+#define F0900_GPIO9_CONFIG 0xf149007e
+#define F0900_GPIO9_XOR 0xf1490001
+
+/*GPIO10CFG*/
+#define R0900_GPIO10CFG 0xf14a
+#define F0900_GPIO10_OPD 0xf14a0080
+#define F0900_GPIO10_CONFIG 0xf14a007e
+#define F0900_GPIO10_XOR 0xf14a0001
+
+/*GPIO11CFG*/
+#define R0900_GPIO11CFG 0xf14b
+#define F0900_GPIO11_OPD 0xf14b0080
+#define F0900_GPIO11_CONFIG 0xf14b007e
+#define F0900_GPIO11_XOR 0xf14b0001
+
+/*GPIO12CFG*/
+#define R0900_GPIO12CFG 0xf14c
+#define F0900_GPIO12_OPD 0xf14c0080
+#define F0900_GPIO12_CONFIG 0xf14c007e
+#define F0900_GPIO12_XOR 0xf14c0001
+
+/*GPIO13CFG*/
+#define R0900_GPIO13CFG 0xf14d
+#define F0900_GPIO13_OPD 0xf14d0080
+#define F0900_GPIO13_CONFIG 0xf14d007e
+#define F0900_GPIO13_XOR 0xf14d0001
+
+/*CS0CFG*/
+#define R0900_CS0CFG 0xf14e
+#define F0900_CS0_OPD 0xf14e0080
+#define F0900_CS0_CONFIG 0xf14e007e
+#define F0900_CS0_XOR 0xf14e0001
+
+/*CS1CFG*/
+#define R0900_CS1CFG 0xf14f
+#define F0900_CS1_OPD 0xf14f0080
+#define F0900_CS1_CONFIG 0xf14f007e
+#define F0900_CS1_XOR 0xf14f0001
+
+/*STDBYCFG*/
+#define R0900_STDBYCFG 0xf150
+#define F0900_STDBY_OPD 0xf1500080
+#define F0900_STDBY_CONFIG 0xf150007e
+#define F0900_STBDY_XOR 0xf1500001
+
+/*DIRCLKCFG*/
+#define R0900_DIRCLKCFG 0xf151
+#define F0900_DIRCLK_OPD 0xf1510080
+#define F0900_DIRCLK_CONFIG 0xf151007e
+#define F0900_DIRCLK_XOR 0xf1510001
+
+/*AGCRF1CFG*/
+#define R0900_AGCRF1CFG 0xf152
+#define F0900_AGCRF1_OPD 0xf1520080
+#define F0900_AGCRF1_CONFIG 0xf152007e
+#define F0900_AGCRF1_XOR 0xf1520001
+
+/*SDAT1CFG*/
+#define R0900_SDAT1CFG 0xf153
+#define F0900_SDAT1_OPD 0xf1530080
+#define F0900_SDAT1_CONFIG 0xf153007e
+#define F0900_SDAT1_XOR 0xf1530001
+
+/*SCLT1CFG*/
+#define R0900_SCLT1CFG 0xf154
+#define F0900_SCLT1_OPD 0xf1540080
+#define F0900_SCLT1_CONFIG 0xf154007e
+#define F0900_SCLT1_XOR 0xf1540001
+
+/*DISEQCO1CFG*/
+#define R0900_DISEQCO1CFG 0xf155
+#define F0900_DISEQCO1_OPD 0xf1550080
+#define F0900_DISEQCO1_CONFIG 0xf155007e
+#define F0900_DISEQC1_XOR 0xf1550001
+
+/*AGCRF2CFG*/
+#define R0900_AGCRF2CFG 0xf156
+#define F0900_AGCRF2_OPD 0xf1560080
+#define F0900_AGCRF2_CONFIG 0xf156007e
+#define F0900_AGCRF2_XOR 0xf1560001
+
+/*SDAT2CFG*/
+#define R0900_SDAT2CFG 0xf157
+#define F0900_SDAT2_OPD 0xf1570080
+#define F0900_SDAT2_CONFIG 0xf157007e
+#define F0900_SDAT2_XOR 0xf1570001
+
+/*SCLT2CFG*/
+#define R0900_SCLT2CFG 0xf158
+#define F0900_SCLT2_OPD 0xf1580080
+#define F0900_SCLT2_CONFIG 0xf158007e
+#define F0900_SCLT2_XOR 0xf1580001
+
+/*DISEQCO2CFG*/
+#define R0900_DISEQCO2CFG 0xf159
+#define F0900_DISEQCO2_OPD 0xf1590080
+#define F0900_DISEQCO2_CONFIG 0xf159007e
+#define F0900_DISEQC2_XOR 0xf1590001
+
+/*CLKOUT27CFG*/
+#define R0900_CLKOUT27CFG 0xf15a
+#define F0900_CLKOUT27_OPD 0xf15a0080
+#define F0900_CLKOUT27_CONFIG 0xf15a007e
+#define F0900_CLKOUT27_XOR 0xf15a0001
+
+/*ERROR1CFG*/
+#define R0900_ERROR1CFG 0xf15b
+#define F0900_ERROR1_OPD 0xf15b0080
+#define F0900_ERROR1_CONFIG 0xf15b007e
+#define F0900_ERROR1_XOR 0xf15b0001
+
+/*DPN1CFG*/
+#define R0900_DPN1CFG 0xf15c
+#define F0900_DPN1_OPD 0xf15c0080
+#define F0900_DPN1_CONFIG 0xf15c007e
+#define F0900_DPN1_XOR 0xf15c0001
+
+/*STROUT1CFG*/
+#define R0900_STROUT1CFG 0xf15d
+#define F0900_STROUT1_OPD 0xf15d0080
+#define F0900_STROUT1_CONFIG 0xf15d007e
+#define F0900_STROUT1_XOR 0xf15d0001
+
+/*CLKOUT1CFG*/
+#define R0900_CLKOUT1CFG 0xf15e
+#define F0900_CLKOUT1_OPD 0xf15e0080
+#define F0900_CLKOUT1_CONFIG 0xf15e007e
+#define F0900_CLKOUT1_XOR 0xf15e0001
+
+/*DATA71CFG*/
+#define R0900_DATA71CFG 0xf15f
+#define F0900_DATA71_OPD 0xf15f0080
+#define F0900_DATA71_CONFIG 0xf15f007e
+#define F0900_DATA71_XOR 0xf15f0001
+
+/*ERROR2CFG*/
+#define R0900_ERROR2CFG 0xf160
+#define F0900_ERROR2_OPD 0xf1600080
+#define F0900_ERROR2_CONFIG 0xf160007e
+#define F0900_ERROR2_XOR 0xf1600001
+
+/*DPN2CFG*/
+#define R0900_DPN2CFG 0xf161
+#define F0900_DPN2_OPD 0xf1610080
+#define F0900_DPN2_CONFIG 0xf161007e
+#define F0900_DPN2_XOR 0xf1610001
+
+/*STROUT2CFG*/
+#define R0900_STROUT2CFG 0xf162
+#define F0900_STROUT2_OPD 0xf1620080
+#define F0900_STROUT2_CONFIG 0xf162007e
+#define F0900_STROUT2_XOR 0xf1620001
+
+/*CLKOUT2CFG*/
+#define R0900_CLKOUT2CFG 0xf163
+#define F0900_CLKOUT2_OPD 0xf1630080
+#define F0900_CLKOUT2_CONFIG 0xf163007e
+#define F0900_CLKOUT2_XOR 0xf1630001
+
+/*DATA72CFG*/
+#define R0900_DATA72CFG 0xf164
+#define F0900_DATA72_OPD 0xf1640080
+#define F0900_DATA72_CONFIG 0xf164007e
+#define F0900_DATA72_XOR 0xf1640001
+
+/*ERROR3CFG*/
+#define R0900_ERROR3CFG 0xf165
+#define F0900_ERROR3_OPD 0xf1650080
+#define F0900_ERROR3_CONFIG 0xf165007e
+#define F0900_ERROR3_XOR 0xf1650001
+
+/*DPN3CFG*/
+#define R0900_DPN3CFG 0xf166
+#define F0900_DPN3_OPD 0xf1660080
+#define F0900_DPN3_CONFIG 0xf166007e
+#define F0900_DPN3_XOR 0xf1660001
+
+/*STROUT3CFG*/
+#define R0900_STROUT3CFG 0xf167
+#define F0900_STROUT3_OPD 0xf1670080
+#define F0900_STROUT3_CONFIG 0xf167007e
+#define F0900_STROUT3_XOR 0xf1670001
+
+/*CLKOUT3CFG*/
+#define R0900_CLKOUT3CFG 0xf168
+#define F0900_CLKOUT3_OPD 0xf1680080
+#define F0900_CLKOUT3_CONFIG 0xf168007e
+#define F0900_CLKOUT3_XOR 0xf1680001
+
+/*DATA73CFG*/
+#define R0900_DATA73CFG 0xf169
+#define F0900_DATA73_OPD 0xf1690080
+#define F0900_DATA73_CONFIG 0xf169007e
+#define F0900_DATA73_XOR 0xf1690001
+
+/*STRSTATUS1*/
+#define R0900_STRSTATUS1 0xf16a
+#define F0900_STRSTATUS_SEL2 0xf16a00f0
+#define F0900_STRSTATUS_SEL1 0xf16a000f
+
+/*STRSTATUS2*/
+#define R0900_STRSTATUS2 0xf16b
+#define F0900_STRSTATUS_SEL4 0xf16b00f0
+#define F0900_STRSTATUS_SEL3 0xf16b000f
+
+/*STRSTATUS3*/
+#define R0900_STRSTATUS3 0xf16c
+#define F0900_STRSTATUS_SEL6 0xf16c00f0
+#define F0900_STRSTATUS_SEL5 0xf16c000f
+
+/*FSKTFC2*/
+#define R0900_FSKTFC2 0xf170
+#define F0900_FSKT_KMOD 0xf17000fc
+#define F0900_FSKT_CAR2 0xf1700003
+
+/*FSKTFC1*/
+#define R0900_FSKTFC1 0xf171
+#define F0900_FSKT_CAR1 0xf17100ff
+
+/*FSKTFC0*/
+#define R0900_FSKTFC0 0xf172
+#define F0900_FSKT_CAR0 0xf17200ff
+
+/*FSKTDELTAF1*/
+#define R0900_FSKTDELTAF1 0xf173
+#define F0900_FSKT_DELTAF1 0xf173000f
+
+/*FSKTDELTAF0*/
+#define R0900_FSKTDELTAF0 0xf174
+#define F0900_FSKT_DELTAF0 0xf17400ff
+
+/*FSKTCTRL*/
+#define R0900_FSKTCTRL 0xf175
+#define F0900_FSKT_EN_SGN 0xf1750040
+#define F0900_FSKT_MOD_SGN 0xf1750020
+#define F0900_FSKT_MOD_EN 0xf175001c
+#define F0900_FSKT_DACMODE 0xf1750003
+
+/*FSKRFC2*/
+#define R0900_FSKRFC2 0xf176
+#define F0900_FSKR_DETSGN 0xf1760040
+#define F0900_FSKR_OUTSGN 0xf1760020
+#define F0900_FSKR_KAGC 0xf176001c
+#define F0900_FSKR_CAR2 0xf1760003
+
+/*FSKRFC1*/
+#define R0900_FSKRFC1 0xf177
+#define F0900_FSKR_CAR1 0xf17700ff
+
+/*FSKRFC0*/
+#define R0900_FSKRFC0 0xf178
+#define F0900_FSKR_CAR0 0xf17800ff
+
+/*FSKRK1*/
+#define R0900_FSKRK1 0xf179
+#define F0900_FSKR_K1_EXP 0xf17900e0
+#define F0900_FSKR_K1_MANT 0xf179001f
+
+/*FSKRK2*/
+#define R0900_FSKRK2 0xf17a
+#define F0900_FSKR_K2_EXP 0xf17a00e0
+#define F0900_FSKR_K2_MANT 0xf17a001f
+
+/*FSKRAGCR*/
+#define R0900_FSKRAGCR 0xf17b
+#define F0900_FSKR_OUTCTL 0xf17b00c0
+#define F0900_FSKR_AGC_REF 0xf17b003f
+
+/*FSKRAGC*/
+#define R0900_FSKRAGC 0xf17c
+#define F0900_FSKR_AGC_ACCU 0xf17c00ff
+
+/*FSKRALPHA*/
+#define R0900_FSKRALPHA 0xf17d
+#define F0900_FSKR_ALPHA_EXP 0xf17d001c
+#define F0900_FSKR_ALPHA_M 0xf17d0003
+
+/*FSKRPLTH1*/
+#define R0900_FSKRPLTH1 0xf17e
+#define F0900_FSKR_BETA 0xf17e00f0
+#define F0900_FSKR_PLL_TRESH1 0xf17e000f
+
+/*FSKRPLTH0*/
+#define R0900_FSKRPLTH0 0xf17f
+#define F0900_FSKR_PLL_TRESH0 0xf17f00ff
+
+/*FSKRDF1*/
+#define R0900_FSKRDF1 0xf180
+#define F0900_FSKR_OUT 0xf1800080
+#define F0900_FSKR_DELTAF1 0xf180001f
+
+/*FSKRDF0*/
+#define R0900_FSKRDF0 0xf181
+#define F0900_FSKR_DELTAF0 0xf18100ff
+
+/*FSKRSTEPP*/
+#define R0900_FSKRSTEPP 0xf182
+#define F0900_FSKR_STEP_PLUS 0xf18200ff
+
+/*FSKRSTEPM*/
+#define R0900_FSKRSTEPM 0xf183
+#define F0900_FSKR_STEP_MINUS 0xf18300ff
+
+/*FSKRDET1*/
+#define R0900_FSKRDET1 0xf184
+#define F0900_FSKR_DETECT 0xf1840080
+#define F0900_FSKR_CARDET_ACCU1 0xf184000f
+
+/*FSKRDET0*/
+#define R0900_FSKRDET0 0xf185
+#define F0900_FSKR_CARDET_ACCU0 0xf18500ff
+
+/*FSKRDTH1*/
+#define R0900_FSKRDTH1 0xf186
+#define F0900_FSKR_CARLOSS_THRESH1 0xf18600f0
+#define F0900_FSKR_CARDET_THRESH1 0xf186000f
+
+/*FSKRDTH0*/
+#define R0900_FSKRDTH0 0xf187
+#define F0900_FSKR_CARDET_THRESH0 0xf18700ff
+
+/*FSKRLOSS*/
+#define R0900_FSKRLOSS 0xf188
+#define F0900_FSKR_CARLOSS_THRESH0 0xf18800ff
+
+/*P2_DISTXCTL*/
+#define R0900_P2_DISTXCTL 0xf190
+#define F0900_P2_TIM_OFF 0xf1900080
+#define F0900_P2_DISEQC_RESET 0xf1900040
+#define F0900_P2_TIM_CMD 0xf1900030
+#define F0900_P2_DIS_PRECHARGE 0xf1900008
+#define F0900_P2_DISTX_MODE 0xf1900007
+
+/*P2_DISRXCTL*/
+#define R0900_P2_DISRXCTL 0xf191
+#define F0900_P2_RECEIVER_ON 0xf1910080
+#define F0900_P2_IGNO_SHORT22K 0xf1910040
+#define F0900_P2_ONECHIP_TRX 0xf1910020
+#define F0900_P2_EXT_ENVELOP 0xf1910010
+#define F0900_P2_PIN_SELECT0 0xf191000c
+#define F0900_P2_IRQ_RXEND 0xf1910002
+#define F0900_P2_IRQ_4NBYTES 0xf1910001
+
+/*P2_DISRX_ST0*/
+#define R0900_P2_DISRX_ST0 0xf194
+#define F0900_P2_RX_END 0xf1940080
+#define F0900_P2_RX_ACTIVE 0xf1940040
+#define F0900_P2_SHORT_22KHZ 0xf1940020
+#define F0900_P2_CONT_TONE 0xf1940010
+#define F0900_P2_FIFO_4BREADY 0xf1940008
+#define F0900_P2_FIFO_EMPTY 0xf1940004
+#define F0900_P2_ABORT_DISRX 0xf1940001
+
+/*P2_DISRX_ST1*/
+#define R0900_P2_DISRX_ST1 0xf195
+#define F0900_P2_RX_FAIL 0xf1950080
+#define F0900_P2_FIFO_PARITYFAIL 0xf1950040
+#define F0900_P2_RX_NONBYTE 0xf1950020
+#define F0900_P2_FIFO_OVERFLOW 0xf1950010
+#define F0900_P2_FIFO_BYTENBR 0xf195000f
+
+/*P2_DISRXDATA*/
+#define R0900_P2_DISRXDATA 0xf196
+#define F0900_P2_DISRX_DATA 0xf19600ff
+
+/*P2_DISTXDATA*/
+#define R0900_P2_DISTXDATA 0xf197
+#define F0900_P2_DISEQC_FIFO 0xf19700ff
+
+/*P2_DISTXSTATUS*/
+#define R0900_P2_DISTXSTATUS 0xf198
+#define F0900_P2_TX_FAIL 0xf1980080
+#define F0900_P2_FIFO_FULL 0xf1980040
+#define F0900_P2_TX_IDLE 0xf1980020
+#define F0900_P2_GAP_BURST 0xf1980010
+#define F0900_P2_TXFIFO_BYTES 0xf198000f
+
+/*P2_F22TX*/
+#define R0900_P2_F22TX 0xf199
+#define F0900_P2_F22_REG 0xf19900ff
+
+/*P2_F22RX*/
+#define R0900_P2_F22RX 0xf19a
+#define F0900_P2_F22RX_REG 0xf19a00ff
+
+/*P2_ACRPRESC*/
+#define R0900_P2_ACRPRESC 0xf19c
+#define F0900_P2_ACR_PRESC 0xf19c0007
+
+/*P2_ACRDIV*/
+#define R0900_P2_ACRDIV 0xf19d
+#define F0900_P2_ACR_DIV 0xf19d00ff
+
+/*P1_DISTXCTL*/
+#define R0900_P1_DISTXCTL 0xf1a0
+#define DISTXCTL shiftx(R0900_P1_DISTXCTL, demod, 0x10)
+#define F0900_P1_TIM_OFF 0xf1a00080
+#define F0900_P1_DISEQC_RESET 0xf1a00040
+#define DISEQC_RESET shiftx(F0900_P1_DISEQC_RESET, demod, 0x100000)
+#define F0900_P1_TIM_CMD 0xf1a00030
+#define F0900_P1_DIS_PRECHARGE 0xf1a00008
+#define DIS_PRECHARGE shiftx(F0900_P1_DIS_PRECHARGE, demod, 0x100000)
+#define F0900_P1_DISTX_MODE 0xf1a00007
+#define DISTX_MODE shiftx(F0900_P1_DISTX_MODE, demod, 0x100000)
+
+/*P1_DISRXCTL*/
+#define R0900_P1_DISRXCTL 0xf1a1
+#define DISRXCTL shiftx(R0900_P1_DISRXCTL, demod, 0x10)
+#define F0900_P1_RECEIVER_ON 0xf1a10080
+#define F0900_P1_IGNO_SHORT22K 0xf1a10040
+#define F0900_P1_ONECHIP_TRX 0xf1a10020
+#define F0900_P1_EXT_ENVELOP 0xf1a10010
+#define F0900_P1_PIN_SELECT0 0xf1a1000c
+#define F0900_P1_IRQ_RXEND 0xf1a10002
+#define F0900_P1_IRQ_4NBYTES 0xf1a10001
+
+/*P1_DISRX_ST0*/
+#define R0900_P1_DISRX_ST0 0xf1a4
+#define DISRX_ST0 shiftx(R0900_P1_DISRX_ST0, demod, 0x10)
+#define F0900_P1_RX_END 0xf1a40080
+#define RX_END shiftx(F0900_P1_RX_END, demod, 0x100000)
+#define F0900_P1_RX_ACTIVE 0xf1a40040
+#define F0900_P1_SHORT_22KHZ 0xf1a40020
+#define F0900_P1_CONT_TONE 0xf1a40010
+#define F0900_P1_FIFO_4BREADY 0xf1a40008
+#define F0900_P1_FIFO_EMPTY 0xf1a40004
+#define F0900_P1_ABORT_DISRX 0xf1a40001
+
+/*P1_DISRX_ST1*/
+#define R0900_P1_DISRX_ST1 0xf1a5
+#define DISRX_ST1 shiftx(R0900_P1_DISRX_ST1, demod, 0x10)
+#define F0900_P1_RX_FAIL 0xf1a50080
+#define F0900_P1_FIFO_PARITYFAIL 0xf1a50040
+#define F0900_P1_RX_NONBYTE 0xf1a50020
+#define F0900_P1_FIFO_OVERFLOW 0xf1a50010
+#define F0900_P1_FIFO_BYTENBR 0xf1a5000f
+#define FIFO_BYTENBR shiftx(F0900_P1_FIFO_BYTENBR, demod, 0x100000)
+
+/*P1_DISRXDATA*/
+#define R0900_P1_DISRXDATA 0xf1a6
+#define DISRXDATA shiftx(R0900_P1_DISRXDATA, demod, 0x10)
+#define F0900_P1_DISRX_DATA 0xf1a600ff
+
+/*P1_DISTXDATA*/
+#define R0900_P1_DISTXDATA 0xf1a7
+#define DISTXDATA shiftx(R0900_P1_DISTXDATA, demod, 0x10)
+#define F0900_P1_DISEQC_FIFO 0xf1a700ff
+
+/*P1_DISTXSTATUS*/
+#define R0900_P1_DISTXSTATUS 0xf1a8
+#define F0900_P1_TX_FAIL 0xf1a80080
+#define F0900_P1_FIFO_FULL 0xf1a80040
+#define FIFO_FULL shiftx(F0900_P1_FIFO_FULL, demod, 0x100000)
+#define F0900_P1_TX_IDLE 0xf1a80020
+#define TX_IDLE shiftx(F0900_P1_TX_IDLE, demod, 0x100000)
+#define F0900_P1_GAP_BURST 0xf1a80010
+#define F0900_P1_TXFIFO_BYTES 0xf1a8000f
+
+/*P1_F22TX*/
+#define R0900_P1_F22TX 0xf1a9
+#define F22TX shiftx(R0900_P1_F22TX, demod, 0x10)
+#define F0900_P1_F22_REG 0xf1a900ff
+
+/*P1_F22RX*/
+#define R0900_P1_F22RX 0xf1aa
+#define F22RX shiftx(R0900_P1_F22RX, demod, 0x10)
+#define F0900_P1_F22RX_REG 0xf1aa00ff
+
+/*P1_ACRPRESC*/
+#define R0900_P1_ACRPRESC 0xf1ac
+#define ACRPRESC shiftx(R0900_P1_ACRPRESC, demod, 0x10)
+#define F0900_P1_ACR_PRESC 0xf1ac0007
+
+/*P1_ACRDIV*/
+#define R0900_P1_ACRDIV 0xf1ad
+#define ACRDIV shiftx(R0900_P1_ACRDIV, demod, 0x10)
+#define F0900_P1_ACR_DIV 0xf1ad00ff
+
+/*NCOARSE*/
+#define R0900_NCOARSE 0xf1b3
+#define F0900_M_DIV 0xf1b300ff
+
+/*SYNTCTRL*/
+#define R0900_SYNTCTRL 0xf1b6
+#define F0900_STANDBY 0xf1b60080
+#define F0900_BYPASSPLLCORE 0xf1b60040
+#define F0900_SELX1RATIO 0xf1b60020
+#define F0900_STOP_PLL 0xf1b60008
+#define F0900_BYPASSPLLFSK 0xf1b60004
+#define F0900_SELOSCI 0xf1b60002
+#define F0900_BYPASSPLLADC 0xf1b60001
+
+/*FILTCTRL*/
+#define R0900_FILTCTRL 0xf1b7
+#define F0900_INV_CLK135 0xf1b70080
+#define F0900_SEL_FSKCKDIV 0xf1b70004
+#define F0900_INV_CLKFSK 0xf1b70002
+#define F0900_BYPASS_APPLI 0xf1b70001
+
+/*PLLSTAT*/
+#define R0900_PLLSTAT 0xf1b8
+#define F0900_PLLLOCK 0xf1b80001
+
+/*STOPCLK1*/
+#define R0900_STOPCLK1 0xf1c2
+#define F0900_STOP_CLKPKDT2 0xf1c20040
+#define F0900_STOP_CLKPKDT1 0xf1c20020
+#define F0900_STOP_CLKFEC 0xf1c20010
+#define F0900_STOP_CLKADCI2 0xf1c20008
+#define F0900_INV_CLKADCI2 0xf1c20004
+#define F0900_STOP_CLKADCI1 0xf1c20002
+#define F0900_INV_CLKADCI1 0xf1c20001
+
+/*STOPCLK2*/
+#define R0900_STOPCLK2 0xf1c3
+#define F0900_STOP_CLKSAMP2 0xf1c30010
+#define F0900_STOP_CLKSAMP1 0xf1c30008
+#define F0900_STOP_CLKVIT2 0xf1c30004
+#define F0900_STOP_CLKVIT1 0xf1c30002
+#define STOP_CLKVIT shiftx(F0900_STOP_CLKVIT1, demod, -2)
+#define F0900_STOP_CLKTS 0xf1c30001
+
+/*TSTTNR0*/
+#define R0900_TSTTNR0 0xf1df
+#define F0900_SEL_FSK 0xf1df0080
+#define F0900_FSK_PON 0xf1df0004
+
+/*TSTTNR1*/
+#define R0900_TSTTNR1 0xf1e0
+#define F0900_ADC1_PON 0xf1e00002
+#define F0900_ADC1_INMODE 0xf1e00001
+
+/*TSTTNR2*/
+#define R0900_TSTTNR2 0xf1e1
+#define F0900_DISEQC1_PON 0xf1e10020
+
+/*TSTTNR3*/
+#define R0900_TSTTNR3 0xf1e2
+#define F0900_ADC2_PON 0xf1e20002
+#define F0900_ADC2_INMODE 0xf1e20001
+
+/*TSTTNR4*/
+#define R0900_TSTTNR4 0xf1e3
+#define F0900_DISEQC2_PON 0xf1e30020
+
+/*P2_IQCONST*/
+#define R0900_P2_IQCONST 0xf200
+#define F0900_P2_CONSTEL_SELECT 0xf2000060
+#define F0900_P2_IQSYMB_SEL 0xf200001f
+
+/*P2_NOSCFG*/
+#define R0900_P2_NOSCFG 0xf201
+#define F0900_P2_DUMMYPL_NOSDATA 0xf2010020
+#define F0900_P2_NOSPLH_BETA 0xf2010018
+#define F0900_P2_NOSDATA_BETA 0xf2010007
+
+/*P2_ISYMB*/
+#define R0900_P2_ISYMB 0xf202
+#define F0900_P2_I_SYMBOL 0xf20201ff
+
+/*P2_QSYMB*/
+#define R0900_P2_QSYMB 0xf203
+#define F0900_P2_Q_SYMBOL 0xf20301ff
+
+/*P2_AGC1CFG*/
+#define R0900_P2_AGC1CFG 0xf204
+#define F0900_P2_DC_FROZEN 0xf2040080
+#define F0900_P2_DC_CORRECT 0xf2040040
+#define F0900_P2_AMM_FROZEN 0xf2040020
+#define F0900_P2_AMM_CORRECT 0xf2040010
+#define F0900_P2_QUAD_FROZEN 0xf2040008
+#define F0900_P2_QUAD_CORRECT 0xf2040004
+
+/*P2_AGC1CN*/
+#define R0900_P2_AGC1CN 0xf206
+#define F0900_P2_AGC1_LOCKED 0xf2060080
+#define F0900_P2_AGC1_MINPOWER 0xf2060010
+#define F0900_P2_AGCOUT_FAST 0xf2060008
+#define F0900_P2_AGCIQ_BETA 0xf2060007
+
+/*P2_AGC1REF*/
+#define R0900_P2_AGC1REF 0xf207
+#define F0900_P2_AGCIQ_REF 0xf20700ff
+
+/*P2_IDCCOMP*/
+#define R0900_P2_IDCCOMP 0xf208
+#define F0900_P2_IAVERAGE_ADJ 0xf20801ff
+
+/*P2_QDCCOMP*/
+#define R0900_P2_QDCCOMP 0xf209
+#define F0900_P2_QAVERAGE_ADJ 0xf20901ff
+
+/*P2_POWERI*/
+#define R0900_P2_POWERI 0xf20a
+#define F0900_P2_POWER_I 0xf20a00ff
+
+/*P2_POWERQ*/
+#define R0900_P2_POWERQ 0xf20b
+#define F0900_P2_POWER_Q 0xf20b00ff
+
+/*P2_AGC1AMM*/
+#define R0900_P2_AGC1AMM 0xf20c
+#define F0900_P2_AMM_VALUE 0xf20c00ff
+
+/*P2_AGC1QUAD*/
+#define R0900_P2_AGC1QUAD 0xf20d
+#define F0900_P2_QUAD_VALUE 0xf20d01ff
+
+/*P2_AGCIQIN1*/
+#define R0900_P2_AGCIQIN1 0xf20e
+#define F0900_P2_AGCIQ_VALUE1 0xf20e00ff
+
+/*P2_AGCIQIN0*/
+#define R0900_P2_AGCIQIN0 0xf20f
+#define F0900_P2_AGCIQ_VALUE0 0xf20f00ff
+
+/*P2_DEMOD*/
+#define R0900_P2_DEMOD 0xf210
+#define F0900_P2_MANUALS2_ROLLOFF 0xf2100080
+#define F0900_P2_SPECINV_CONTROL 0xf2100030
+#define F0900_P2_FORCE_ENASAMP 0xf2100008
+#define F0900_P2_MANUALSX_ROLLOFF 0xf2100004
+#define F0900_P2_ROLLOFF_CONTROL 0xf2100003
+
+/*P2_DMDMODCOD*/
+#define R0900_P2_DMDMODCOD 0xf211
+#define F0900_P2_MANUAL_MODCOD 0xf2110080
+#define F0900_P2_DEMOD_MODCOD 0xf211007c
+#define F0900_P2_DEMOD_TYPE 0xf2110003
+
+/*P2_DSTATUS*/
+#define R0900_P2_DSTATUS 0xf212
+#define F0900_P2_CAR_LOCK 0xf2120080
+#define F0900_P2_TMGLOCK_QUALITY 0xf2120060
+#define F0900_P2_LOCK_DEFINITIF 0xf2120008
+#define F0900_P2_OVADC_DETECT 0xf2120001
+
+/*P2_DSTATUS2*/
+#define R0900_P2_DSTATUS2 0xf213
+#define F0900_P2_DEMOD_DELOCK 0xf2130080
+#define F0900_P2_AGC1_NOSIGNALACK 0xf2130008
+#define F0900_P2_AGC2_OVERFLOW 0xf2130004
+#define F0900_P2_CFR_OVERFLOW 0xf2130002
+#define F0900_P2_GAMMA_OVERUNDER 0xf2130001
+
+/*P2_DMDCFGMD*/
+#define R0900_P2_DMDCFGMD 0xf214
+#define F0900_P2_DVBS2_ENABLE 0xf2140080
+#define F0900_P2_DVBS1_ENABLE 0xf2140040
+#define F0900_P2_SCAN_ENABLE 0xf2140010
+#define F0900_P2_CFR_AUTOSCAN 0xf2140008
+#define F0900_P2_TUN_RNG 0xf2140003
+
+/*P2_DMDCFG2*/
+#define R0900_P2_DMDCFG2 0xf215
+#define F0900_P2_S1S2_SEQUENTIAL 0xf2150040
+#define F0900_P2_INFINITE_RELOCK 0xf2150010
+
+/*P2_DMDISTATE*/
+#define R0900_P2_DMDISTATE 0xf216
+#define F0900_P2_I2C_DEMOD_MODE 0xf216001f
+
+/*P2_DMDT0M*/
+#define R0900_P2_DMDT0M 0xf217
+#define F0900_P2_DMDT0_MIN 0xf21700ff
+
+/*P2_DMDSTATE*/
+#define R0900_P2_DMDSTATE 0xf21b
+#define F0900_P2_HEADER_MODE 0xf21b0060
+
+/*P2_DMDFLYW*/
+#define R0900_P2_DMDFLYW 0xf21c
+#define F0900_P2_I2C_IRQVAL 0xf21c00f0
+#define F0900_P2_FLYWHEEL_CPT 0xf21c000f
+
+/*P2_DSTATUS3*/
+#define R0900_P2_DSTATUS3 0xf21d
+#define F0900_P2_DEMOD_CFGMODE 0xf21d0060
+
+/*P2_DMDCFG3*/
+#define R0900_P2_DMDCFG3 0xf21e
+#define F0900_P2_NOSTOP_FIFOFULL 0xf21e0008
+
+/*P2_DMDCFG4*/
+#define R0900_P2_DMDCFG4 0xf21f
+#define F0900_P2_TUNER_NRELAUNCH 0xf21f0008
+
+/*P2_CORRELMANT*/
+#define R0900_P2_CORRELMANT 0xf220
+#define F0900_P2_CORREL_MANT 0xf22000ff
+
+/*P2_CORRELABS*/
+#define R0900_P2_CORRELABS 0xf221
+#define F0900_P2_CORREL_ABS 0xf22100ff
+
+/*P2_CORRELEXP*/
+#define R0900_P2_CORRELEXP 0xf222
+#define F0900_P2_CORREL_ABSEXP 0xf22200f0
+#define F0900_P2_CORREL_EXP 0xf222000f
+
+/*P2_PLHMODCOD*/
+#define R0900_P2_PLHMODCOD 0xf224
+#define F0900_P2_SPECINV_DEMOD 0xf2240080
+#define F0900_P2_PLH_MODCOD 0xf224007c
+#define F0900_P2_PLH_TYPE 0xf2240003
+
+/*P2_DMDREG*/
+#define R0900_P2_DMDREG 0xf225
+#define F0900_P2_DECIM_PLFRAMES 0xf2250001
+
+/*P2_AGC2O*/
+#define R0900_P2_AGC2O 0xf22c
+#define F0900_P2_AGC2_COEF 0xf22c0007
+
+/*P2_AGC2REF*/
+#define R0900_P2_AGC2REF 0xf22d
+#define F0900_P2_AGC2_REF 0xf22d00ff
+
+/*P2_AGC1ADJ*/
+#define R0900_P2_AGC1ADJ 0xf22e
+#define F0900_P2_AGC1_ADJUSTED 0xf22e007f
+
+/*P2_AGC2I1*/
+#define R0900_P2_AGC2I1 0xf236
+#define F0900_P2_AGC2_INTEGRATOR1 0xf23600ff
+
+/*P2_AGC2I0*/
+#define R0900_P2_AGC2I0 0xf237
+#define F0900_P2_AGC2_INTEGRATOR0 0xf23700ff
+
+/*P2_CARCFG*/
+#define R0900_P2_CARCFG 0xf238
+#define F0900_P2_CFRUPLOW_AUTO 0xf2380080
+#define F0900_P2_CFRUPLOW_TEST 0xf2380040
+#define F0900_P2_ROTAON 0xf2380004
+#define F0900_P2_PH_DET_ALGO 0xf2380003
+
+/*P2_ACLC*/
+#define R0900_P2_ACLC 0xf239
+#define F0900_P2_CAR_ALPHA_MANT 0xf2390030
+#define F0900_P2_CAR_ALPHA_EXP 0xf239000f
+
+/*P2_BCLC*/
+#define R0900_P2_BCLC 0xf23a
+#define F0900_P2_CAR_BETA_MANT 0xf23a0030
+#define F0900_P2_CAR_BETA_EXP 0xf23a000f
+
+/*P2_CARFREQ*/
+#define R0900_P2_CARFREQ 0xf23d
+#define F0900_P2_KC_COARSE_EXP 0xf23d00f0
+#define F0900_P2_BETA_FREQ 0xf23d000f
+
+/*P2_CARHDR*/
+#define R0900_P2_CARHDR 0xf23e
+#define F0900_P2_K_FREQ_HDR 0xf23e00ff
+
+/*P2_LDT*/
+#define R0900_P2_LDT 0xf23f
+#define F0900_P2_CARLOCK_THRES 0xf23f01ff
+
+/*P2_LDT2*/
+#define R0900_P2_LDT2 0xf240
+#define F0900_P2_CARLOCK_THRES2 0xf24001ff
+
+/*P2_CFRICFG*/
+#define R0900_P2_CFRICFG 0xf241
+#define F0900_P2_NEG_CFRSTEP 0xf2410001
+
+/*P2_CFRUP1*/
+#define R0900_P2_CFRUP1 0xf242
+#define F0900_P2_CFR_UP1 0xf24201ff
+
+/*P2_CFRUP0*/
+#define R0900_P2_CFRUP0 0xf243
+#define F0900_P2_CFR_UP0 0xf24300ff
+
+/*P2_CFRLOW1*/
+#define R0900_P2_CFRLOW1 0xf246
+#define F0900_P2_CFR_LOW1 0xf24601ff
+
+/*P2_CFRLOW0*/
+#define R0900_P2_CFRLOW0 0xf247
+#define F0900_P2_CFR_LOW0 0xf24700ff
+
+/*P2_CFRINIT1*/
+#define R0900_P2_CFRINIT1 0xf248
+#define F0900_P2_CFR_INIT1 0xf24801ff
+
+/*P2_CFRINIT0*/
+#define R0900_P2_CFRINIT0 0xf249
+#define F0900_P2_CFR_INIT0 0xf24900ff
+
+/*P2_CFRINC1*/
+#define R0900_P2_CFRINC1 0xf24a
+#define F0900_P2_MANUAL_CFRINC 0xf24a0080
+#define F0900_P2_CFR_INC1 0xf24a003f
+
+/*P2_CFRINC0*/
+#define R0900_P2_CFRINC0 0xf24b
+#define F0900_P2_CFR_INC0 0xf24b00f8
+
+/*P2_CFR2*/
+#define R0900_P2_CFR2 0xf24c
+#define F0900_P2_CAR_FREQ2 0xf24c01ff
+
+/*P2_CFR1*/
+#define R0900_P2_CFR1 0xf24d
+#define F0900_P2_CAR_FREQ1 0xf24d00ff
+
+/*P2_CFR0*/
+#define R0900_P2_CFR0 0xf24e
+#define F0900_P2_CAR_FREQ0 0xf24e00ff
+
+/*P2_LDI*/
+#define R0900_P2_LDI 0xf24f
+#define F0900_P2_LOCK_DET_INTEGR 0xf24f01ff
+
+/*P2_TMGCFG*/
+#define R0900_P2_TMGCFG 0xf250
+#define F0900_P2_TMGLOCK_BETA 0xf25000c0
+#define F0900_P2_DO_TIMING_CORR 0xf2500010
+#define F0900_P2_TMG_MINFREQ 0xf2500003
+
+/*P2_RTC*/
+#define R0900_P2_RTC 0xf251
+#define F0900_P2_TMGALPHA_EXP 0xf25100f0
+#define F0900_P2_TMGBETA_EXP 0xf251000f
+
+/*P2_RTCS2*/
+#define R0900_P2_RTCS2 0xf252
+#define F0900_P2_TMGALPHAS2_EXP 0xf25200f0
+#define F0900_P2_TMGBETAS2_EXP 0xf252000f
+
+/*P2_TMGTHRISE*/
+#define R0900_P2_TMGTHRISE 0xf253
+#define F0900_P2_TMGLOCK_THRISE 0xf25300ff
+
+/*P2_TMGTHFALL*/
+#define R0900_P2_TMGTHFALL 0xf254
+#define F0900_P2_TMGLOCK_THFALL 0xf25400ff
+
+/*P2_SFRUPRATIO*/
+#define R0900_P2_SFRUPRATIO 0xf255
+#define F0900_P2_SFR_UPRATIO 0xf25500ff
+
+/*P2_SFRLOWRATIO*/
+#define R0900_P2_SFRLOWRATIO 0xf256
+#define F0900_P2_SFR_LOWRATIO 0xf25600ff
+
+/*P2_KREFTMG*/
+#define R0900_P2_KREFTMG 0xf258
+#define F0900_P2_KREF_TMG 0xf25800ff
+
+/*P2_SFRSTEP*/
+#define R0900_P2_SFRSTEP 0xf259
+#define F0900_P2_SFR_SCANSTEP 0xf25900f0
+#define F0900_P2_SFR_CENTERSTEP 0xf259000f
+
+/*P2_TMGCFG2*/
+#define R0900_P2_TMGCFG2 0xf25a
+#define F0900_P2_SFRRATIO_FINE 0xf25a0001
+
+/*P2_KREFTMG2*/
+#define R0900_P2_KREFTMG2 0xf25b
+#define F0900_P2_KREF_TMG2 0xf25b00ff
+
+/*P2_SFRINIT1*/
+#define R0900_P2_SFRINIT1 0xf25e
+#define F0900_P2_SFR_INIT1 0xf25e007f
+
+/*P2_SFRINIT0*/
+#define R0900_P2_SFRINIT0 0xf25f
+#define F0900_P2_SFR_INIT0 0xf25f00ff
+
+/*P2_SFRUP1*/
+#define R0900_P2_SFRUP1 0xf260
+#define F0900_P2_AUTO_GUP 0xf2600080
+#define F0900_P2_SYMB_FREQ_UP1 0xf260007f
+
+/*P2_SFRUP0*/
+#define R0900_P2_SFRUP0 0xf261
+#define F0900_P2_SYMB_FREQ_UP0 0xf26100ff
+
+/*P2_SFRLOW1*/
+#define R0900_P2_SFRLOW1 0xf262
+#define F0900_P2_AUTO_GLOW 0xf2620080
+#define F0900_P2_SYMB_FREQ_LOW1 0xf262007f
+
+/*P2_SFRLOW0*/
+#define R0900_P2_SFRLOW0 0xf263
+#define F0900_P2_SYMB_FREQ_LOW0 0xf26300ff
+
+/*P2_SFR3*/
+#define R0900_P2_SFR3 0xf264
+#define F0900_P2_SYMB_FREQ3 0xf26400ff
+
+/*P2_SFR2*/
+#define R0900_P2_SFR2 0xf265
+#define F0900_P2_SYMB_FREQ2 0xf26500ff
+
+/*P2_SFR1*/
+#define R0900_P2_SFR1 0xf266
+#define F0900_P2_SYMB_FREQ1 0xf26600ff
+
+/*P2_SFR0*/
+#define R0900_P2_SFR0 0xf267
+#define F0900_P2_SYMB_FREQ0 0xf26700ff
+
+/*P2_TMGREG2*/
+#define R0900_P2_TMGREG2 0xf268
+#define F0900_P2_TMGREG2 0xf26800ff
+
+/*P2_TMGREG1*/
+#define R0900_P2_TMGREG1 0xf269
+#define F0900_P2_TMGREG1 0xf26900ff
+
+/*P2_TMGREG0*/
+#define R0900_P2_TMGREG0 0xf26a
+#define F0900_P2_TMGREG0 0xf26a00ff
+
+/*P2_TMGLOCK1*/
+#define R0900_P2_TMGLOCK1 0xf26b
+#define F0900_P2_TMGLOCK_LEVEL1 0xf26b01ff
+
+/*P2_TMGLOCK0*/
+#define R0900_P2_TMGLOCK0 0xf26c
+#define F0900_P2_TMGLOCK_LEVEL0 0xf26c00ff
+
+/*P2_TMGOBS*/
+#define R0900_P2_TMGOBS 0xf26d
+#define F0900_P2_ROLLOFF_STATUS 0xf26d00c0
+
+/*P2_EQUALCFG*/
+#define R0900_P2_EQUALCFG 0xf26f
+#define F0900_P2_EQUAL_ON 0xf26f0040
+#define F0900_P2_MU_EQUALDFE 0xf26f0007
+
+/*P2_EQUAI1*/
+#define R0900_P2_EQUAI1 0xf270
+#define F0900_P2_EQUA_ACCI1 0xf27001ff
+
+/*P2_EQUAQ1*/
+#define R0900_P2_EQUAQ1 0xf271
+#define F0900_P2_EQUA_ACCQ1 0xf27101ff
+
+/*P2_EQUAI2*/
+#define R0900_P2_EQUAI2 0xf272
+#define F0900_P2_EQUA_ACCI2 0xf27201ff
+
+/*P2_EQUAQ2*/
+#define R0900_P2_EQUAQ2 0xf273
+#define F0900_P2_EQUA_ACCQ2 0xf27301ff
+
+/*P2_EQUAI3*/
+#define R0900_P2_EQUAI3 0xf274
+#define F0900_P2_EQUA_ACCI3 0xf27401ff
+
+/*P2_EQUAQ3*/
+#define R0900_P2_EQUAQ3 0xf275
+#define F0900_P2_EQUA_ACCQ3 0xf27501ff
+
+/*P2_EQUAI4*/
+#define R0900_P2_EQUAI4 0xf276
+#define F0900_P2_EQUA_ACCI4 0xf27601ff
+
+/*P2_EQUAQ4*/
+#define R0900_P2_EQUAQ4 0xf277
+#define F0900_P2_EQUA_ACCQ4 0xf27701ff
+
+/*P2_EQUAI5*/
+#define R0900_P2_EQUAI5 0xf278
+#define F0900_P2_EQUA_ACCI5 0xf27801ff
+
+/*P2_EQUAQ5*/
+#define R0900_P2_EQUAQ5 0xf279
+#define F0900_P2_EQUA_ACCQ5 0xf27901ff
+
+/*P2_EQUAI6*/
+#define R0900_P2_EQUAI6 0xf27a
+#define F0900_P2_EQUA_ACCI6 0xf27a01ff
+
+/*P2_EQUAQ6*/
+#define R0900_P2_EQUAQ6 0xf27b
+#define F0900_P2_EQUA_ACCQ6 0xf27b01ff
+
+/*P2_EQUAI7*/
+#define R0900_P2_EQUAI7 0xf27c
+#define F0900_P2_EQUA_ACCI7 0xf27c01ff
+
+/*P2_EQUAQ7*/
+#define R0900_P2_EQUAQ7 0xf27d
+#define F0900_P2_EQUA_ACCQ7 0xf27d01ff
+
+/*P2_EQUAI8*/
+#define R0900_P2_EQUAI8 0xf27e
+#define F0900_P2_EQUA_ACCI8 0xf27e01ff
+
+/*P2_EQUAQ8*/
+#define R0900_P2_EQUAQ8 0xf27f
+#define F0900_P2_EQUA_ACCQ8 0xf27f01ff
+
+/*P2_NNOSDATAT1*/
+#define R0900_P2_NNOSDATAT1 0xf280
+#define F0900_P2_NOSDATAT_NORMED1 0xf28000ff
+
+/*P2_NNOSDATAT0*/
+#define R0900_P2_NNOSDATAT0 0xf281
+#define F0900_P2_NOSDATAT_NORMED0 0xf28100ff
+
+/*P2_NNOSDATA1*/
+#define R0900_P2_NNOSDATA1 0xf282
+#define F0900_P2_NOSDATA_NORMED1 0xf28200ff
+
+/*P2_NNOSDATA0*/
+#define R0900_P2_NNOSDATA0 0xf283
+#define F0900_P2_NOSDATA_NORMED0 0xf28300ff
+
+/*P2_NNOSPLHT1*/
+#define R0900_P2_NNOSPLHT1 0xf284
+#define F0900_P2_NOSPLHT_NORMED1 0xf28400ff
+
+/*P2_NNOSPLHT0*/
+#define R0900_P2_NNOSPLHT0 0xf285
+#define F0900_P2_NOSPLHT_NORMED0 0xf28500ff
+
+/*P2_NNOSPLH1*/
+#define R0900_P2_NNOSPLH1 0xf286
+#define F0900_P2_NOSPLH_NORMED1 0xf28600ff
+
+/*P2_NNOSPLH0*/
+#define R0900_P2_NNOSPLH0 0xf287
+#define F0900_P2_NOSPLH_NORMED0 0xf28700ff
+
+/*P2_NOSDATAT1*/
+#define R0900_P2_NOSDATAT1 0xf288
+#define F0900_P2_NOSDATAT_UNNORMED1 0xf28800ff
+
+/*P2_NOSDATAT0*/
+#define R0900_P2_NOSDATAT0 0xf289
+#define F0900_P2_NOSDATAT_UNNORMED0 0xf28900ff
+
+/*P2_NOSDATA1*/
+#define R0900_P2_NOSDATA1 0xf28a
+#define F0900_P2_NOSDATA_UNNORMED1 0xf28a00ff
+
+/*P2_NOSDATA0*/
+#define R0900_P2_NOSDATA0 0xf28b
+#define F0900_P2_NOSDATA_UNNORMED0 0xf28b00ff
+
+/*P2_NOSPLHT1*/
+#define R0900_P2_NOSPLHT1 0xf28c
+#define F0900_P2_NOSPLHT_UNNORMED1 0xf28c00ff
+
+/*P2_NOSPLHT0*/
+#define R0900_P2_NOSPLHT0 0xf28d
+#define F0900_P2_NOSPLHT_UNNORMED0 0xf28d00ff
+
+/*P2_NOSPLH1*/
+#define R0900_P2_NOSPLH1 0xf28e
+#define F0900_P2_NOSPLH_UNNORMED1 0xf28e00ff
+
+/*P2_NOSPLH0*/
+#define R0900_P2_NOSPLH0 0xf28f
+#define F0900_P2_NOSPLH_UNNORMED0 0xf28f00ff
+
+/*P2_CAR2CFG*/
+#define R0900_P2_CAR2CFG 0xf290
+#define F0900_P2_CARRIER3_DISABLE 0xf2900040
+#define F0900_P2_ROTA2ON 0xf2900004
+#define F0900_P2_PH_DET_ALGO2 0xf2900003
+
+/*P2_CFR2CFR1*/
+#define R0900_P2_CFR2CFR1 0xf291
+#define F0900_P2_CFR2TOCFR1_DVBS1 0xf29100c0
+#define F0900_P2_EN_S2CAR2CENTER 0xf2910020
+#define F0900_P2_DIS_BCHERRCFR2 0xf2910010
+#define F0900_P2_CFR2TOCFR1_BETA 0xf2910007
+
+/*P2_CFR22*/
+#define R0900_P2_CFR22 0xf293
+#define F0900_P2_CAR2_FREQ2 0xf29301ff
+
+/*P2_CFR21*/
+#define R0900_P2_CFR21 0xf294
+#define F0900_P2_CAR2_FREQ1 0xf29400ff
+
+/*P2_CFR20*/
+#define R0900_P2_CFR20 0xf295
+#define F0900_P2_CAR2_FREQ0 0xf29500ff
+
+/*P2_ACLC2S2Q*/
+#define R0900_P2_ACLC2S2Q 0xf297
+#define F0900_P2_ENAB_SPSKSYMB 0xf2970080
+#define F0900_P2_CAR2S2_Q_ALPH_M 0xf2970030
+#define F0900_P2_CAR2S2_Q_ALPH_E 0xf297000f
+
+/*P2_ACLC2S28*/
+#define R0900_P2_ACLC2S28 0xf298
+#define F0900_P2_OLDI3Q_MODE 0xf2980080
+#define F0900_P2_CAR2S2_8_ALPH_M 0xf2980030
+#define F0900_P2_CAR2S2_8_ALPH_E 0xf298000f
+
+/*P2_ACLC2S216A*/
+#define R0900_P2_ACLC2S216A 0xf299
+#define F0900_P2_DIS_C3STOPA2 0xf2990080
+#define F0900_P2_CAR2S2_16ADERAT 0xf2990040
+#define F0900_P2_CAR2S2_16A_ALPH_M 0xf2990030
+#define F0900_P2_CAR2S2_16A_ALPH_E 0xf299000f
+
+/*P2_ACLC2S232A*/
+#define R0900_P2_ACLC2S232A 0xf29a
+#define F0900_P2_CAR2S2_32ADERAT 0xf29a0040
+#define F0900_P2_CAR2S2_32A_ALPH_M 0xf29a0030
+#define F0900_P2_CAR2S2_32A_ALPH_E 0xf29a000f
+
+/*P2_BCLC2S2Q*/
+#define R0900_P2_BCLC2S2Q 0xf29c
+#define F0900_P2_CAR2S2_Q_BETA_M 0xf29c0030
+#define F0900_P2_CAR2S2_Q_BETA_E 0xf29c000f
+
+/*P2_BCLC2S28*/
+#define R0900_P2_BCLC2S28 0xf29d
+#define F0900_P2_CAR2S2_8_BETA_M 0xf29d0030
+#define F0900_P2_CAR2S2_8_BETA_E 0xf29d000f
+
+/*P2_BCLC2S216A*/
+#define R0900_P2_BCLC2S216A 0xf29e
+
+/*P2_BCLC2S232A*/
+#define R0900_P2_BCLC2S232A 0xf29f
+
+/*P2_PLROOT2*/
+#define R0900_P2_PLROOT2 0xf2ac
+#define F0900_P2_PLSCRAMB_MODE 0xf2ac000c
+#define F0900_P2_PLSCRAMB_ROOT2 0xf2ac0003
+
+/*P2_PLROOT1*/
+#define R0900_P2_PLROOT1 0xf2ad
+#define F0900_P2_PLSCRAMB_ROOT1 0xf2ad00ff
+
+/*P2_PLROOT0*/
+#define R0900_P2_PLROOT0 0xf2ae
+#define F0900_P2_PLSCRAMB_ROOT0 0xf2ae00ff
+
+/*P2_MODCODLST0*/
+#define R0900_P2_MODCODLST0 0xf2b0
+
+/*P2_MODCODLST1*/
+#define R0900_P2_MODCODLST1 0xf2b1
+#define F0900_P2_DIS_MODCOD29 0xf2b100f0
+#define F0900_P2_DIS_32PSK_9_10 0xf2b1000f
+
+/*P2_MODCODLST2*/
+#define R0900_P2_MODCODLST2 0xf2b2
+#define F0900_P2_DIS_32PSK_8_9 0xf2b200f0
+#define F0900_P2_DIS_32PSK_5_6 0xf2b2000f
+
+/*P2_MODCODLST3*/
+#define R0900_P2_MODCODLST3 0xf2b3
+#define F0900_P2_DIS_32PSK_4_5 0xf2b300f0
+#define F0900_P2_DIS_32PSK_3_4 0xf2b3000f
+
+/*P2_MODCODLST4*/
+#define R0900_P2_MODCODLST4 0xf2b4
+#define F0900_P2_DIS_16PSK_9_10 0xf2b400f0
+#define F0900_P2_DIS_16PSK_8_9 0xf2b4000f
+
+/*P2_MODCODLST5*/
+#define R0900_P2_MODCODLST5 0xf2b5
+#define F0900_P2_DIS_16PSK_5_6 0xf2b500f0
+#define F0900_P2_DIS_16PSK_4_5 0xf2b5000f
+
+/*P2_MODCODLST6*/
+#define R0900_P2_MODCODLST6 0xf2b6
+#define F0900_P2_DIS_16PSK_3_4 0xf2b600f0
+#define F0900_P2_DIS_16PSK_2_3 0xf2b6000f
+
+/*P2_MODCODLST7*/
+#define R0900_P2_MODCODLST7 0xf2b7
+#define F0900_P2_DIS_8P_9_10 0xf2b700f0
+#define F0900_P2_DIS_8P_8_9 0xf2b7000f
+
+/*P2_MODCODLST8*/
+#define R0900_P2_MODCODLST8 0xf2b8
+#define F0900_P2_DIS_8P_5_6 0xf2b800f0
+#define F0900_P2_DIS_8P_3_4 0xf2b8000f
+
+/*P2_MODCODLST9*/
+#define R0900_P2_MODCODLST9 0xf2b9
+#define F0900_P2_DIS_8P_2_3 0xf2b900f0
+#define F0900_P2_DIS_8P_3_5 0xf2b9000f
+
+/*P2_MODCODLSTA*/
+#define R0900_P2_MODCODLSTA 0xf2ba
+#define F0900_P2_DIS_QP_9_10 0xf2ba00f0
+#define F0900_P2_DIS_QP_8_9 0xf2ba000f
+
+/*P2_MODCODLSTB*/
+#define R0900_P2_MODCODLSTB 0xf2bb
+#define F0900_P2_DIS_QP_5_6 0xf2bb00f0
+#define F0900_P2_DIS_QP_4_5 0xf2bb000f
+
+/*P2_MODCODLSTC*/
+#define R0900_P2_MODCODLSTC 0xf2bc
+#define F0900_P2_DIS_QP_3_4 0xf2bc00f0
+#define F0900_P2_DIS_QP_2_3 0xf2bc000f
+
+/*P2_MODCODLSTD*/
+#define R0900_P2_MODCODLSTD 0xf2bd
+#define F0900_P2_DIS_QP_3_5 0xf2bd00f0
+#define F0900_P2_DIS_QP_1_2 0xf2bd000f
+
+/*P2_MODCODLSTE*/
+#define R0900_P2_MODCODLSTE 0xf2be
+#define F0900_P2_DIS_QP_2_5 0xf2be00f0
+#define F0900_P2_DIS_QP_1_3 0xf2be000f
+
+/*P2_MODCODLSTF*/
+#define R0900_P2_MODCODLSTF 0xf2bf
+#define F0900_P2_DIS_QP_1_4 0xf2bf00f0
+
+/*P2_GAUSSR0*/
+#define R0900_P2_GAUSSR0 0xf2c0
+#define F0900_P2_EN_CCIMODE 0xf2c00080
+#define F0900_P2_R0_GAUSSIEN 0xf2c0007f
+
+/*P2_CCIR0*/
+#define R0900_P2_CCIR0 0xf2c1
+#define F0900_P2_CCIDETECT_PLHONLY 0xf2c10080
+#define F0900_P2_R0_CCI 0xf2c1007f
+
+/*P2_CCIQUANT*/
+#define R0900_P2_CCIQUANT 0xf2c2
+#define F0900_P2_CCI_BETA 0xf2c200e0
+#define F0900_P2_CCI_QUANT 0xf2c2001f
+
+/*P2_CCITHRES*/
+#define R0900_P2_CCITHRES 0xf2c3
+#define F0900_P2_CCI_THRESHOLD 0xf2c300ff
+
+/*P2_CCIACC*/
+#define R0900_P2_CCIACC 0xf2c4
+#define F0900_P2_CCI_VALUE 0xf2c400ff
+
+/*P2_DMDRESCFG*/
+#define R0900_P2_DMDRESCFG 0xf2c6
+#define F0900_P2_DMDRES_RESET 0xf2c60080
+#define F0900_P2_DMDRES_STRALL 0xf2c60008
+#define F0900_P2_DMDRES_NEWONLY 0xf2c60004
+#define F0900_P2_DMDRES_NOSTORE 0xf2c60002
+
+/*P2_DMDRESADR*/
+#define R0900_P2_DMDRESADR 0xf2c7
+#define F0900_P2_DMDRES_VALIDCFR 0xf2c70040
+#define F0900_P2_DMDRES_MEMFULL 0xf2c70030
+#define F0900_P2_DMDRES_RESNBR 0xf2c7000f
+
+/*P2_DMDRESDATA7*/
+#define R0900_P2_DMDRESDATA7 0xf2c8
+#define F0900_P2_DMDRES_DATA7 0xf2c800ff
+
+/*P2_DMDRESDATA6*/
+#define R0900_P2_DMDRESDATA6 0xf2c9
+#define F0900_P2_DMDRES_DATA6 0xf2c900ff
+
+/*P2_DMDRESDATA5*/
+#define R0900_P2_DMDRESDATA5 0xf2ca
+#define F0900_P2_DMDRES_DATA5 0xf2ca00ff
+
+/*P2_DMDRESDATA4*/
+#define R0900_P2_DMDRESDATA4 0xf2cb
+#define F0900_P2_DMDRES_DATA4 0xf2cb00ff
+
+/*P2_DMDRESDATA3*/
+#define R0900_P2_DMDRESDATA3 0xf2cc
+#define F0900_P2_DMDRES_DATA3 0xf2cc00ff
+
+/*P2_DMDRESDATA2*/
+#define R0900_P2_DMDRESDATA2 0xf2cd
+#define F0900_P2_DMDRES_DATA2 0xf2cd00ff
+
+/*P2_DMDRESDATA1*/
+#define R0900_P2_DMDRESDATA1 0xf2ce
+#define F0900_P2_DMDRES_DATA1 0xf2ce00ff
+
+/*P2_DMDRESDATA0*/
+#define R0900_P2_DMDRESDATA0 0xf2cf
+#define F0900_P2_DMDRES_DATA0 0xf2cf00ff
+
+/*P2_FFEI1*/
+#define R0900_P2_FFEI1 0xf2d0
+#define F0900_P2_FFE_ACCI1 0xf2d001ff
+
+/*P2_FFEQ1*/
+#define R0900_P2_FFEQ1 0xf2d1
+#define F0900_P2_FFE_ACCQ1 0xf2d101ff
+
+/*P2_FFEI2*/
+#define R0900_P2_FFEI2 0xf2d2
+#define F0900_P2_FFE_ACCI2 0xf2d201ff
+
+/*P2_FFEQ2*/
+#define R0900_P2_FFEQ2 0xf2d3
+#define F0900_P2_FFE_ACCQ2 0xf2d301ff
+
+/*P2_FFEI3*/
+#define R0900_P2_FFEI3 0xf2d4
+#define F0900_P2_FFE_ACCI3 0xf2d401ff
+
+/*P2_FFEQ3*/
+#define R0900_P2_FFEQ3 0xf2d5
+#define F0900_P2_FFE_ACCQ3 0xf2d501ff
+
+/*P2_FFEI4*/
+#define R0900_P2_FFEI4 0xf2d6
+#define F0900_P2_FFE_ACCI4 0xf2d601ff
+
+/*P2_FFEQ4*/
+#define R0900_P2_FFEQ4 0xf2d7
+#define F0900_P2_FFE_ACCQ4 0xf2d701ff
+
+/*P2_FFECFG*/
+#define R0900_P2_FFECFG 0xf2d8
+#define F0900_P2_EQUALFFE_ON 0xf2d80040
+#define F0900_P2_MU_EQUALFFE 0xf2d80007
+
+/*P2_TNRCFG*/
+#define R0900_P2_TNRCFG 0xf2e0
+#define F0900_P2_TUN_ACKFAIL 0xf2e00080
+#define F0900_P2_TUN_TYPE 0xf2e00070
+#define F0900_P2_TUN_SECSTOP 0xf2e00008
+#define F0900_P2_TUN_VCOSRCH 0xf2e00004
+#define F0900_P2_TUN_MADDRESS 0xf2e00003
+
+/*P2_TNRCFG2*/
+#define R0900_P2_TNRCFG2 0xf2e1
+#define F0900_P2_TUN_IQSWAP 0xf2e10080
+#define F0900_P2_DIS_BWCALC 0xf2e10004
+#define F0900_P2_SHORT_WAITSTATES 0xf2e10002
+
+/*P2_TNRXTAL*/
+#define R0900_P2_TNRXTAL 0xf2e4
+#define F0900_P2_TUN_XTALFREQ 0xf2e4001f
+
+/*P2_TNRSTEPS*/
+#define R0900_P2_TNRSTEPS 0xf2e7
+#define F0900_P2_TUNER_BW0P125 0xf2e70080
+#define F0900_P2_BWINC_OFFSET 0xf2e70170
+#define F0900_P2_SOFTSTEP_RNG 0xf2e70008
+#define F0900_P2_TUN_BWOFFSET 0xf2e70007
+
+/*P2_TNRGAIN*/
+#define R0900_P2_TNRGAIN 0xf2e8
+#define F0900_P2_TUN_KDIVEN 0xf2e800c0
+#define F0900_P2_STB6X00_OCK 0xf2e80030
+#define F0900_P2_TUN_GAIN 0xf2e8000f
+
+/*P2_TNRRF1*/
+#define R0900_P2_TNRRF1 0xf2e9
+#define F0900_P2_TUN_RFFREQ2 0xf2e900ff
+
+/*P2_TNRRF0*/
+#define R0900_P2_TNRRF0 0xf2ea
+#define F0900_P2_TUN_RFFREQ1 0xf2ea00ff
+
+/*P2_TNRBW*/
+#define R0900_P2_TNRBW 0xf2eb
+#define F0900_P2_TUN_RFFREQ0 0xf2eb00c0
+#define F0900_P2_TUN_BW 0xf2eb003f
+
+/*P2_TNRADJ*/
+#define R0900_P2_TNRADJ 0xf2ec
+#define F0900_P2_STB61X0_CALTIME 0xf2ec0040
+
+/*P2_TNRCTL2*/
+#define R0900_P2_TNRCTL2 0xf2ed
+#define F0900_P2_STB61X0_RCCKOFF 0xf2ed0080
+#define F0900_P2_STB61X0_ICP_SDOFF 0xf2ed0040
+#define F0900_P2_STB61X0_DCLOOPOFF 0xf2ed0020
+#define F0900_P2_STB61X0_REFOUTSEL 0xf2ed0010
+#define F0900_P2_STB61X0_CALOFF 0xf2ed0008
+#define F0900_P2_STB6XX0_LPT_BEN 0xf2ed0004
+#define F0900_P2_STB6XX0_RX_OSCP 0xf2ed0002
+#define F0900_P2_STB6XX0_SYN 0xf2ed0001
+
+/*P2_TNRCFG3*/
+#define R0900_P2_TNRCFG3 0xf2ee
+#define F0900_P2_TUN_PLLFREQ 0xf2ee001c
+#define F0900_P2_TUN_I2CFREQ_MODE 0xf2ee0003
+
+/*P2_TNRLAUNCH*/
+#define R0900_P2_TNRLAUNCH 0xf2f0
+
+/*P2_TNRLD*/
+#define R0900_P2_TNRLD 0xf2f0
+#define F0900_P2_TUNLD_VCOING 0xf2f00080
+#define F0900_P2_TUN_REG1FAIL 0xf2f00040
+#define F0900_P2_TUN_REG2FAIL 0xf2f00020
+#define F0900_P2_TUN_REG3FAIL 0xf2f00010
+#define F0900_P2_TUN_REG4FAIL 0xf2f00008
+#define F0900_P2_TUN_REG5FAIL 0xf2f00004
+#define F0900_P2_TUN_BWING 0xf2f00002
+#define F0900_P2_TUN_LOCKED 0xf2f00001
+
+/*P2_TNROBSL*/
+#define R0900_P2_TNROBSL 0xf2f6
+#define F0900_P2_TUN_I2CABORTED 0xf2f60080
+#define F0900_P2_TUN_LPEN 0xf2f60040
+#define F0900_P2_TUN_FCCK 0xf2f60020
+#define F0900_P2_TUN_I2CLOCKED 0xf2f60010
+#define F0900_P2_TUN_PROGDONE 0xf2f6000c
+#define F0900_P2_TUN_RFRESTE1 0xf2f60003
+
+/*P2_TNRRESTE*/
+#define R0900_P2_TNRRESTE 0xf2f7
+#define F0900_P2_TUN_RFRESTE0 0xf2f700ff
+
+/*P2_SMAPCOEF7*/
+#define R0900_P2_SMAPCOEF7 0xf300
+#define F0900_P2_DIS_QSCALE 0xf3000080
+#define F0900_P2_SMAPCOEF_Q_LLR12 0xf300017f
+
+/*P2_SMAPCOEF6*/
+#define R0900_P2_SMAPCOEF6 0xf301
+#define F0900_P2_ADJ_8PSKLLR1 0xf3010004
+#define F0900_P2_OLD_8PSKLLR1 0xf3010002
+#define F0900_P2_DIS_AB8PSK 0xf3010001
+
+/*P2_SMAPCOEF5*/
+#define R0900_P2_SMAPCOEF5 0xf302
+#define F0900_P2_DIS_8SCALE 0xf3020080
+#define F0900_P2_SMAPCOEF_8P_LLR23 0xf302017f
+
+/*P2_NCO2MAX1*/
+#define R0900_P2_NCO2MAX1 0xf314
+#define F0900_P2_TETA2_MAXVABS1 0xf31400ff
+
+/*P2_NCO2MAX0*/
+#define R0900_P2_NCO2MAX0 0xf315
+#define F0900_P2_TETA2_MAXVABS0 0xf31500ff
+
+/*P2_NCO2FR1*/
+#define R0900_P2_NCO2FR1 0xf316
+#define F0900_P2_NCO2FINAL_ANGLE1 0xf31600ff
+
+/*P2_NCO2FR0*/
+#define R0900_P2_NCO2FR0 0xf317
+#define F0900_P2_NCO2FINAL_ANGLE0 0xf31700ff
+
+/*P2_CFR2AVRGE1*/
+#define R0900_P2_CFR2AVRGE1 0xf318
+#define F0900_P2_I2C_CFR2AVERAGE1 0xf31800ff
+
+/*P2_CFR2AVRGE0*/
+#define R0900_P2_CFR2AVRGE0 0xf319
+#define F0900_P2_I2C_CFR2AVERAGE0 0xf31900ff
+
+/*P2_DMDPLHSTAT*/
+#define R0900_P2_DMDPLHSTAT 0xf320
+#define F0900_P2_PLH_STATISTIC 0xf32000ff
+
+/*P2_LOCKTIME3*/
+#define R0900_P2_LOCKTIME3 0xf322
+#define F0900_P2_DEMOD_LOCKTIME3 0xf32200ff
+
+/*P2_LOCKTIME2*/
+#define R0900_P2_LOCKTIME2 0xf323
+#define F0900_P2_DEMOD_LOCKTIME2 0xf32300ff
+
+/*P2_LOCKTIME1*/
+#define R0900_P2_LOCKTIME1 0xf324
+#define F0900_P2_DEMOD_LOCKTIME1 0xf32400ff
+
+/*P2_LOCKTIME0*/
+#define R0900_P2_LOCKTIME0 0xf325
+#define F0900_P2_DEMOD_LOCKTIME0 0xf32500ff
+
+/*P2_VITSCALE*/
+#define R0900_P2_VITSCALE 0xf332
+#define F0900_P2_NVTH_NOSRANGE 0xf3320080
+#define F0900_P2_VERROR_MAXMODE 0xf3320040
+#define F0900_P2_NSLOWSN_LOCKED 0xf3320008
+#define F0900_P2_DIS_RSFLOCK 0xf3320002
+
+/*P2_FECM*/
+#define R0900_P2_FECM 0xf333
+#define F0900_P2_DSS_DVB 0xf3330080
+#define F0900_P2_DSS_SRCH 0xf3330010
+#define F0900_P2_SYNCVIT 0xf3330002
+#define F0900_P2_IQINV 0xf3330001
+
+/*P2_VTH12*/
+#define R0900_P2_VTH12 0xf334
+#define F0900_P2_VTH12 0xf33400ff
+
+/*P2_VTH23*/
+#define R0900_P2_VTH23 0xf335
+#define F0900_P2_VTH23 0xf33500ff
+
+/*P2_VTH34*/
+#define R0900_P2_VTH34 0xf336
+#define F0900_P2_VTH34 0xf33600ff
+
+/*P2_VTH56*/
+#define R0900_P2_VTH56 0xf337
+#define F0900_P2_VTH56 0xf33700ff
+
+/*P2_VTH67*/
+#define R0900_P2_VTH67 0xf338
+#define F0900_P2_VTH67 0xf33800ff
+
+/*P2_VTH78*/
+#define R0900_P2_VTH78 0xf339
+#define F0900_P2_VTH78 0xf33900ff
+
+/*P2_VITCURPUN*/
+#define R0900_P2_VITCURPUN 0xf33a
+#define F0900_P2_VIT_CURPUN 0xf33a001f
+
+/*P2_VERROR*/
+#define R0900_P2_VERROR 0xf33b
+#define F0900_P2_REGERR_VIT 0xf33b00ff
+
+/*P2_PRVIT*/
+#define R0900_P2_PRVIT 0xf33c
+#define F0900_P2_DIS_VTHLOCK 0xf33c0040
+#define F0900_P2_E7_8VIT 0xf33c0020
+#define F0900_P2_E6_7VIT 0xf33c0010
+#define F0900_P2_E5_6VIT 0xf33c0008
+#define F0900_P2_E3_4VIT 0xf33c0004
+#define F0900_P2_E2_3VIT 0xf33c0002
+#define F0900_P2_E1_2VIT 0xf33c0001
+
+/*P2_VAVSRVIT*/
+#define R0900_P2_VAVSRVIT 0xf33d
+#define F0900_P2_AMVIT 0xf33d0080
+#define F0900_P2_FROZENVIT 0xf33d0040
+#define F0900_P2_SNVIT 0xf33d0030
+#define F0900_P2_TOVVIT 0xf33d000c
+#define F0900_P2_HYPVIT 0xf33d0003
+
+/*P2_VSTATUSVIT*/
+#define R0900_P2_VSTATUSVIT 0xf33e
+#define F0900_P2_PRFVIT 0xf33e0010
+#define F0900_P2_LOCKEDVIT 0xf33e0008
+
+/*P2_VTHINUSE*/
+#define R0900_P2_VTHINUSE 0xf33f
+#define F0900_P2_VIT_INUSE 0xf33f00ff
+
+/*P2_KDIV12*/
+#define R0900_P2_KDIV12 0xf340
+#define F0900_P2_K_DIVIDER_12 0xf340007f
+
+/*P2_KDIV23*/
+#define R0900_P2_KDIV23 0xf341
+#define F0900_P2_K_DIVIDER_23 0xf341007f
+
+/*P2_KDIV34*/
+#define R0900_P2_KDIV34 0xf342
+#define F0900_P2_K_DIVIDER_34 0xf342007f
+
+/*P2_KDIV56*/
+#define R0900_P2_KDIV56 0xf343
+#define F0900_P2_K_DIVIDER_56 0xf343007f
+
+/*P2_KDIV67*/
+#define R0900_P2_KDIV67 0xf344
+#define F0900_P2_K_DIVIDER_67 0xf344007f
+
+/*P2_KDIV78*/
+#define R0900_P2_KDIV78 0xf345
+#define F0900_P2_K_DIVIDER_78 0xf345007f
+
+/*P2_PDELCTRL1*/
+#define R0900_P2_PDELCTRL1 0xf350
+#define F0900_P2_INV_MISMASK 0xf3500080
+#define F0900_P2_FILTER_EN 0xf3500020
+#define F0900_P2_EN_MIS00 0xf3500002
+#define F0900_P2_ALGOSWRST 0xf3500001
+
+/*P2_PDELCTRL2*/
+#define R0900_P2_PDELCTRL2 0xf351
+#define F0900_P2_RESET_UPKO_COUNT 0xf3510040
+#define F0900_P2_FRAME_MODE 0xf3510002
+#define F0900_P2_NOBCHERRFLG_USE 0xf3510001
+
+/*P2_HYSTTHRESH*/
+#define R0900_P2_HYSTTHRESH 0xf354
+#define F0900_P2_UNLCK_THRESH 0xf35400f0
+#define F0900_P2_DELIN_LCK_THRESH 0xf354000f
+
+/*P2_ISIENTRY*/
+#define R0900_P2_ISIENTRY 0xf35e
+#define F0900_P2_ISI_ENTRY 0xf35e00ff
+
+/*P2_ISIBITENA*/
+#define R0900_P2_ISIBITENA 0xf35f
+#define F0900_P2_ISI_BIT_EN 0xf35f00ff
+
+/*P2_MATSTR1*/
+#define R0900_P2_MATSTR1 0xf360
+#define F0900_P2_MATYPE_CURRENT1 0xf36000ff
+
+/*P2_MATSTR0*/
+#define R0900_P2_MATSTR0 0xf361
+#define F0900_P2_MATYPE_CURRENT0 0xf36100ff
+
+/*P2_UPLSTR1*/
+#define R0900_P2_UPLSTR1 0xf362
+#define F0900_P2_UPL_CURRENT1 0xf36200ff
+
+/*P2_UPLSTR0*/
+#define R0900_P2_UPLSTR0 0xf363
+#define F0900_P2_UPL_CURRENT0 0xf36300ff
+
+/*P2_DFLSTR1*/
+#define R0900_P2_DFLSTR1 0xf364
+#define F0900_P2_DFL_CURRENT1 0xf36400ff
+
+/*P2_DFLSTR0*/
+#define R0900_P2_DFLSTR0 0xf365
+#define F0900_P2_DFL_CURRENT0 0xf36500ff
+
+/*P2_SYNCSTR*/
+#define R0900_P2_SYNCSTR 0xf366
+#define F0900_P2_SYNC_CURRENT 0xf36600ff
+
+/*P2_SYNCDSTR1*/
+#define R0900_P2_SYNCDSTR1 0xf367
+#define F0900_P2_SYNCD_CURRENT1 0xf36700ff
+
+/*P2_SYNCDSTR0*/
+#define R0900_P2_SYNCDSTR0 0xf368
+#define F0900_P2_SYNCD_CURRENT0 0xf36800ff
+
+/*P2_PDELSTATUS1*/
+#define R0900_P2_PDELSTATUS1 0xf369
+#define F0900_P2_PKTDELIN_DELOCK 0xf3690080
+#define F0900_P2_SYNCDUPDFL_BADDFL 0xf3690040
+#define F0900_P2_CONTINUOUS_STREAM 0xf3690020
+#define F0900_P2_UNACCEPTED_STREAM 0xf3690010
+#define F0900_P2_BCH_ERROR_FLAG 0xf3690008
+#define F0900_P2_PKTDELIN_LOCK 0xf3690002
+#define F0900_P2_FIRST_LOCK 0xf3690001
+
+/*P2_PDELSTATUS2*/
+#define R0900_P2_PDELSTATUS2 0xf36a
+#define F0900_P2_FRAME_MODCOD 0xf36a007c
+#define F0900_P2_FRAME_TYPE 0xf36a0003
+
+/*P2_BBFCRCKO1*/
+#define R0900_P2_BBFCRCKO1 0xf36b
+#define F0900_P2_BBHCRC_KOCNT1 0xf36b00ff
+
+/*P2_BBFCRCKO0*/
+#define R0900_P2_BBFCRCKO0 0xf36c
+#define F0900_P2_BBHCRC_KOCNT0 0xf36c00ff
+
+/*P2_UPCRCKO1*/
+#define R0900_P2_UPCRCKO1 0xf36d
+#define F0900_P2_PKTCRC_KOCNT1 0xf36d00ff
+
+/*P2_UPCRCKO0*/
+#define R0900_P2_UPCRCKO0 0xf36e
+#define F0900_P2_PKTCRC_KOCNT0 0xf36e00ff
+
+/*P2_PDELCTRL3*/
+#define R0900_P2_PDELCTRL3 0xf36f
+#define F0900_P2_PKTDEL_CONTFAIL 0xf36f0080
+#define F0900_P2_NOFIFO_BCHERR 0xf36f0020
+
+/*P2_TSSTATEM*/
+#define R0900_P2_TSSTATEM 0xf370
+#define F0900_P2_TSDIL_ON 0xf3700080
+#define F0900_P2_TSRS_ON 0xf3700020
+#define F0900_P2_TSDESCRAMB_ON 0xf3700010
+#define F0900_P2_TSFRAME_MODE 0xf3700008
+#define F0900_P2_TS_DISABLE 0xf3700004
+#define F0900_P2_TSOUT_NOSYNC 0xf3700001
+
+/*P2_TSCFGH*/
+#define R0900_P2_TSCFGH 0xf372
+#define F0900_P2_TSFIFO_DVBCI 0xf3720080
+#define F0900_P2_TSFIFO_SERIAL 0xf3720040
+#define F0900_P2_TSFIFO_TEIUPDATE 0xf3720020
+#define F0900_P2_TSFIFO_DUTY50 0xf3720010
+#define F0900_P2_TSFIFO_HSGNLOUT 0xf3720008
+#define F0900_P2_TSFIFO_ERRMODE 0xf3720006
+#define F0900_P2_RST_HWARE 0xf3720001
+
+/*P2_TSCFGM*/
+#define R0900_P2_TSCFGM 0xf373
+#define F0900_P2_TSFIFO_MANSPEED 0xf37300c0
+#define F0900_P2_TSFIFO_PERMDATA 0xf3730020
+#define F0900_P2_TSFIFO_DPUNACT 0xf3730002
+#define F0900_P2_TSFIFO_INVDATA 0xf3730001
+
+/*P2_TSCFGL*/
+#define R0900_P2_TSCFGL 0xf374
+#define F0900_P2_TSFIFO_BCLKDEL1CK 0xf37400c0
+#define F0900_P2_BCHERROR_MODE 0xf3740030
+#define F0900_P2_TSFIFO_NSGNL2DATA 0xf3740008
+#define F0900_P2_TSFIFO_EMBINDVB 0xf3740004
+#define F0900_P2_TSFIFO_BITSPEED 0xf3740003
+
+/*P2_TSINSDELH*/
+#define R0900_P2_TSINSDELH 0xf376
+#define F0900_P2_TSDEL_SYNCBYTE 0xf3760080
+#define F0900_P2_TSDEL_XXHEADER 0xf3760040
+#define F0900_P2_TSDEL_BBHEADER 0xf3760020
+#define F0900_P2_TSDEL_DATAFIELD 0xf3760010
+#define F0900_P2_TSINSDEL_ISCR 0xf3760008
+#define F0900_P2_TSINSDEL_NPD 0xf3760004
+#define F0900_P2_TSINSDEL_RSPARITY 0xf3760002
+#define F0900_P2_TSINSDEL_CRC8 0xf3760001
+
+/*P2_TSDIVN*/
+#define R0900_P2_TSDIVN 0xf379
+#define F0900_P2_TSFIFO_SPEEDMODE 0xf37900c0
+
+/*P2_TSCFG4*/
+#define R0900_P2_TSCFG4 0xf37a
+#define F0900_P2_TSFIFO_TSSPEEDMODE 0xf37a00c0
+
+/*P2_TSSPEED*/
+#define R0900_P2_TSSPEED 0xf380
+#define F0900_P2_TSFIFO_OUTSPEED 0xf38000ff
+
+/*P2_TSSTATUS*/
+#define R0900_P2_TSSTATUS 0xf381
+#define F0900_P2_TSFIFO_LINEOK 0xf3810080
+#define F0900_P2_TSFIFO_ERROR 0xf3810040
+#define F0900_P2_DIL_READY 0xf3810001
+
+/*P2_TSSTATUS2*/
+#define R0900_P2_TSSTATUS2 0xf382
+#define F0900_P2_TSFIFO_DEMODSEL 0xf3820080
+#define F0900_P2_TSFIFOSPEED_STORE 0xf3820040
+#define F0900_P2_DILXX_RESET 0xf3820020
+#define F0900_P2_TSSERIAL_IMPOS 0xf3820010
+#define F0900_P2_SCRAMBDETECT 0xf3820002
+
+/*P2_TSBITRATE1*/
+#define R0900_P2_TSBITRATE1 0xf383
+#define F0900_P2_TSFIFO_BITRATE1 0xf38300ff
+
+/*P2_TSBITRATE0*/
+#define R0900_P2_TSBITRATE0 0xf384
+#define F0900_P2_TSFIFO_BITRATE0 0xf38400ff
+
+/*P2_ERRCTRL1*/
+#define R0900_P2_ERRCTRL1 0xf398
+#define F0900_P2_ERR_SOURCE1 0xf39800f0
+#define F0900_P2_NUM_EVENT1 0xf3980007
+
+/*P2_ERRCNT12*/
+#define R0900_P2_ERRCNT12 0xf399
+#define F0900_P2_ERRCNT1_OLDVALUE 0xf3990080
+#define F0900_P2_ERR_CNT12 0xf399007f
+
+/*P2_ERRCNT11*/
+#define R0900_P2_ERRCNT11 0xf39a
+#define F0900_P2_ERR_CNT11 0xf39a00ff
+
+/*P2_ERRCNT10*/
+#define R0900_P2_ERRCNT10 0xf39b
+#define F0900_P2_ERR_CNT10 0xf39b00ff
+
+/*P2_ERRCTRL2*/
+#define R0900_P2_ERRCTRL2 0xf39c
+#define F0900_P2_ERR_SOURCE2 0xf39c00f0
+#define F0900_P2_NUM_EVENT2 0xf39c0007
+
+/*P2_ERRCNT22*/
+#define R0900_P2_ERRCNT22 0xf39d
+#define F0900_P2_ERRCNT2_OLDVALUE 0xf39d0080
+#define F0900_P2_ERR_CNT22 0xf39d007f
+
+/*P2_ERRCNT21*/
+#define R0900_P2_ERRCNT21 0xf39e
+#define F0900_P2_ERR_CNT21 0xf39e00ff
+
+/*P2_ERRCNT20*/
+#define R0900_P2_ERRCNT20 0xf39f
+#define F0900_P2_ERR_CNT20 0xf39f00ff
+
+/*P2_FECSPY*/
+#define R0900_P2_FECSPY 0xf3a0
+#define F0900_P2_SPY_ENABLE 0xf3a00080
+#define F0900_P2_NO_SYNCBYTE 0xf3a00040
+#define F0900_P2_SERIAL_MODE 0xf3a00020
+#define F0900_P2_UNUSUAL_PACKET 0xf3a00010
+#define F0900_P2_BERMETER_DATAMODE 0xf3a00008
+#define F0900_P2_BERMETER_LMODE 0xf3a00002
+#define F0900_P2_BERMETER_RESET 0xf3a00001
+
+/*P2_FSPYCFG*/
+#define R0900_P2_FSPYCFG 0xf3a1
+#define F0900_P2_FECSPY_INPUT 0xf3a100c0
+#define F0900_P2_RST_ON_ERROR 0xf3a10020
+#define F0900_P2_ONE_SHOT 0xf3a10010
+#define F0900_P2_I2C_MODE 0xf3a1000c
+#define F0900_P2_SPY_HYSTERESIS 0xf3a10003
+
+/*P2_FSPYDATA*/
+#define R0900_P2_FSPYDATA 0xf3a2
+#define F0900_P2_SPY_STUFFING 0xf3a20080
+#define F0900_P2_SPY_CNULLPKT 0xf3a20020
+#define F0900_P2_SPY_OUTDATA_MODE 0xf3a2001f
+
+/*P2_FSPYOUT*/
+#define R0900_P2_FSPYOUT 0xf3a3
+#define F0900_P2_FSPY_DIRECT 0xf3a30080
+#define F0900_P2_STUFF_MODE 0xf3a30007
+
+/*P2_FSTATUS*/
+#define R0900_P2_FSTATUS 0xf3a4
+#define F0900_P2_SPY_ENDSIM 0xf3a40080
+#define F0900_P2_VALID_SIM 0xf3a40040
+#define F0900_P2_FOUND_SIGNAL 0xf3a40020
+#define F0900_P2_DSS_SYNCBYTE 0xf3a40010
+#define F0900_P2_RESULT_STATE 0xf3a4000f
+
+/*P2_FBERCPT4*/
+#define R0900_P2_FBERCPT4 0xf3a8
+#define F0900_P2_FBERMETER_CPT4 0xf3a800ff
+
+/*P2_FBERCPT3*/
+#define R0900_P2_FBERCPT3 0xf3a9
+#define F0900_P2_FBERMETER_CPT3 0xf3a900ff
+
+/*P2_FBERCPT2*/
+#define R0900_P2_FBERCPT2 0xf3aa
+#define F0900_P2_FBERMETER_CPT2 0xf3aa00ff
+
+/*P2_FBERCPT1*/
+#define R0900_P2_FBERCPT1 0xf3ab
+#define F0900_P2_FBERMETER_CPT1 0xf3ab00ff
+
+/*P2_FBERCPT0*/
+#define R0900_P2_FBERCPT0 0xf3ac
+#define F0900_P2_FBERMETER_CPT0 0xf3ac00ff
+
+/*P2_FBERERR2*/
+#define R0900_P2_FBERERR2 0xf3ad
+#define F0900_P2_FBERMETER_ERR2 0xf3ad00ff
+
+/*P2_FBERERR1*/
+#define R0900_P2_FBERERR1 0xf3ae
+#define F0900_P2_FBERMETER_ERR1 0xf3ae00ff
+
+/*P2_FBERERR0*/
+#define R0900_P2_FBERERR0 0xf3af
+#define F0900_P2_FBERMETER_ERR0 0xf3af00ff
+
+/*P2_FSPYBER*/
+#define R0900_P2_FSPYBER 0xf3b2
+#define F0900_P2_FSPYBER_SYNCBYTE 0xf3b20010
+#define F0900_P2_FSPYBER_UNSYNC 0xf3b20008
+#define F0900_P2_FSPYBER_CTIME 0xf3b20007
+
+/*P1_IQCONST*/
+#define R0900_P1_IQCONST 0xf400
+#define IQCONST REGx(R0900_P1_IQCONST)
+#define F0900_P1_CONSTEL_SELECT 0xf4000060
+#define F0900_P1_IQSYMB_SEL 0xf400001f
+
+/*P1_NOSCFG*/
+#define R0900_P1_NOSCFG 0xf401
+#define NOSCFG REGx(R0900_P1_NOSCFG)
+#define F0900_P1_DUMMYPL_NOSDATA 0xf4010020
+#define F0900_P1_NOSPLH_BETA 0xf4010018
+#define F0900_P1_NOSDATA_BETA 0xf4010007
+
+/*P1_ISYMB*/
+#define R0900_P1_ISYMB 0xf402
+#define ISYMB REGx(R0900_P1_ISYMB)
+#define F0900_P1_I_SYMBOL 0xf40201ff
+
+/*P1_QSYMB*/
+#define R0900_P1_QSYMB 0xf403
+#define QSYMB REGx(R0900_P1_QSYMB)
+#define F0900_P1_Q_SYMBOL 0xf40301ff
+
+/*P1_AGC1CFG*/
+#define R0900_P1_AGC1CFG 0xf404
+#define AGC1CFG REGx(R0900_P1_AGC1CFG)
+#define F0900_P1_DC_FROZEN 0xf4040080
+#define F0900_P1_DC_CORRECT 0xf4040040
+#define F0900_P1_AMM_FROZEN 0xf4040020
+#define F0900_P1_AMM_CORRECT 0xf4040010
+#define F0900_P1_QUAD_FROZEN 0xf4040008
+#define F0900_P1_QUAD_CORRECT 0xf4040004
+
+/*P1_AGC1CN*/
+#define R0900_P1_AGC1CN 0xf406
+#define AGC1CN REGx(R0900_P1_AGC1CN)
+#define F0900_P1_AGC1_LOCKED 0xf4060080
+#define F0900_P1_AGC1_MINPOWER 0xf4060010
+#define F0900_P1_AGCOUT_FAST 0xf4060008
+#define F0900_P1_AGCIQ_BETA 0xf4060007
+
+/*P1_AGC1REF*/
+#define R0900_P1_AGC1REF 0xf407
+#define AGC1REF REGx(R0900_P1_AGC1REF)
+#define F0900_P1_AGCIQ_REF 0xf40700ff
+
+/*P1_IDCCOMP*/
+#define R0900_P1_IDCCOMP 0xf408
+#define IDCCOMP REGx(R0900_P1_IDCCOMP)
+#define F0900_P1_IAVERAGE_ADJ 0xf40801ff
+
+/*P1_QDCCOMP*/
+#define R0900_P1_QDCCOMP 0xf409
+#define QDCCOMP REGx(R0900_P1_QDCCOMP)
+#define F0900_P1_QAVERAGE_ADJ 0xf40901ff
+
+/*P1_POWERI*/
+#define R0900_P1_POWERI 0xf40a
+#define POWERI REGx(R0900_P1_POWERI)
+#define F0900_P1_POWER_I 0xf40a00ff
+#define POWER_I FLDx(F0900_P1_POWER_I)
+
+/*P1_POWERQ*/
+#define R0900_P1_POWERQ 0xf40b
+#define POWERQ REGx(R0900_P1_POWERQ)
+#define F0900_P1_POWER_Q 0xf40b00ff
+#define POWER_Q FLDx(F0900_P1_POWER_Q)
+
+/*P1_AGC1AMM*/
+#define R0900_P1_AGC1AMM 0xf40c
+#define AGC1AMM REGx(R0900_P1_AGC1AMM)
+#define F0900_P1_AMM_VALUE 0xf40c00ff
+
+/*P1_AGC1QUAD*/
+#define R0900_P1_AGC1QUAD 0xf40d
+#define AGC1QUAD REGx(R0900_P1_AGC1QUAD)
+#define F0900_P1_QUAD_VALUE 0xf40d01ff
+
+/*P1_AGCIQIN1*/
+#define R0900_P1_AGCIQIN1 0xf40e
+#define AGCIQIN1 REGx(R0900_P1_AGCIQIN1)
+#define F0900_P1_AGCIQ_VALUE1 0xf40e00ff
+#define AGCIQ_VALUE1 FLDx(F0900_P1_AGCIQ_VALUE1)
+
+/*P1_AGCIQIN0*/
+#define R0900_P1_AGCIQIN0 0xf40f
+#define AGCIQIN0 REGx(R0900_P1_AGCIQIN0)
+#define F0900_P1_AGCIQ_VALUE0 0xf40f00ff
+#define AGCIQ_VALUE0 FLDx(F0900_P1_AGCIQ_VALUE0)
+
+/*P1_DEMOD*/
+#define R0900_P1_DEMOD 0xf410
+#define DEMOD REGx(R0900_P1_DEMOD)
+#define F0900_P1_MANUALS2_ROLLOFF 0xf4100080
+#define MANUALS2_ROLLOFF FLDx(F0900_P1_MANUALS2_ROLLOFF)
+
+#define F0900_P1_SPECINV_CONTROL 0xf4100030
+#define SPECINV_CONTROL FLDx(F0900_P1_SPECINV_CONTROL)
+#define F0900_P1_FORCE_ENASAMP 0xf4100008
+#define F0900_P1_MANUALSX_ROLLOFF 0xf4100004
+#define MANUALSX_ROLLOFF FLDx(F0900_P1_MANUALSX_ROLLOFF)
+#define F0900_P1_ROLLOFF_CONTROL 0xf4100003
+#define ROLLOFF_CONTROL FLDx(F0900_P1_ROLLOFF_CONTROL)
+
+/*P1_DMDMODCOD*/
+#define R0900_P1_DMDMODCOD 0xf411
+#define DMDMODCOD REGx(R0900_P1_DMDMODCOD)
+#define F0900_P1_MANUAL_MODCOD 0xf4110080
+#define F0900_P1_DEMOD_MODCOD 0xf411007c
+#define DEMOD_MODCOD FLDx(F0900_P1_DEMOD_MODCOD)
+#define F0900_P1_DEMOD_TYPE 0xf4110003
+#define DEMOD_TYPE FLDx(F0900_P1_DEMOD_TYPE)
+
+/*P1_DSTATUS*/
+#define R0900_P1_DSTATUS 0xf412
+#define DSTATUS REGx(R0900_P1_DSTATUS)
+#define F0900_P1_CAR_LOCK 0xf4120080
+#define F0900_P1_TMGLOCK_QUALITY 0xf4120060
+#define TMGLOCK_QUALITY FLDx(F0900_P1_TMGLOCK_QUALITY)
+#define F0900_P1_LOCK_DEFINITIF 0xf4120008
+#define LOCK_DEFINITIF FLDx(F0900_P1_LOCK_DEFINITIF)
+#define F0900_P1_OVADC_DETECT 0xf4120001
+
+/*P1_DSTATUS2*/
+#define R0900_P1_DSTATUS2 0xf413
+#define DSTATUS2 REGx(R0900_P1_DSTATUS2)
+#define F0900_P1_DEMOD_DELOCK 0xf4130080
+#define F0900_P1_AGC1_NOSIGNALACK 0xf4130008
+#define F0900_P1_AGC2_OVERFLOW 0xf4130004
+#define F0900_P1_CFR_OVERFLOW 0xf4130002
+#define F0900_P1_GAMMA_OVERUNDER 0xf4130001
+
+/*P1_DMDCFGMD*/
+#define R0900_P1_DMDCFGMD 0xf414
+#define DMDCFGMD REGx(R0900_P1_DMDCFGMD)
+#define F0900_P1_DVBS2_ENABLE 0xf4140080
+#define DVBS2_ENABLE FLDx(F0900_P1_DVBS2_ENABLE)
+#define F0900_P1_DVBS1_ENABLE 0xf4140040
+#define DVBS1_ENABLE FLDx(F0900_P1_DVBS1_ENABLE)
+#define F0900_P1_SCAN_ENABLE 0xf4140010
+#define SCAN_ENABLE FLDx(F0900_P1_SCAN_ENABLE)
+#define F0900_P1_CFR_AUTOSCAN 0xf4140008
+#define CFR_AUTOSCAN FLDx(F0900_P1_CFR_AUTOSCAN)
+#define F0900_P1_TUN_RNG 0xf4140003
+
+/*P1_DMDCFG2*/
+#define R0900_P1_DMDCFG2 0xf415
+#define DMDCFG2 REGx(R0900_P1_DMDCFG2)
+#define F0900_P1_S1S2_SEQUENTIAL 0xf4150040
+#define S1S2_SEQUENTIAL FLDx(F0900_P1_S1S2_SEQUENTIAL)
+#define F0900_P1_INFINITE_RELOCK 0xf4150010
+
+/*P1_DMDISTATE*/
+#define R0900_P1_DMDISTATE 0xf416
+#define DMDISTATE REGx(R0900_P1_DMDISTATE)
+#define F0900_P1_I2C_DEMOD_MODE 0xf416001f
+#define DEMOD_MODE FLDx(F0900_P1_I2C_DEMOD_MODE)
+
+/*P1_DMDT0M*/
+#define R0900_P1_DMDT0M 0xf417
+#define DMDT0M REGx(R0900_P1_DMDT0M)
+#define F0900_P1_DMDT0_MIN 0xf41700ff
+
+/*P1_DMDSTATE*/
+#define R0900_P1_DMDSTATE 0xf41b
+#define DMDSTATE REGx(R0900_P1_DMDSTATE)
+#define F0900_P1_HEADER_MODE 0xf41b0060
+#define HEADER_MODE FLDx(F0900_P1_HEADER_MODE)
+
+/*P1_DMDFLYW*/
+#define R0900_P1_DMDFLYW 0xf41c
+#define DMDFLYW REGx(R0900_P1_DMDFLYW)
+#define F0900_P1_I2C_IRQVAL 0xf41c00f0
+#define F0900_P1_FLYWHEEL_CPT 0xf41c000f
+#define FLYWHEEL_CPT FLDx(F0900_P1_FLYWHEEL_CPT)
+
+/*P1_DSTATUS3*/
+#define R0900_P1_DSTATUS3 0xf41d
+#define DSTATUS3 REGx(R0900_P1_DSTATUS3)
+#define F0900_P1_DEMOD_CFGMODE 0xf41d0060
+
+/*P1_DMDCFG3*/
+#define R0900_P1_DMDCFG3 0xf41e
+#define DMDCFG3 REGx(R0900_P1_DMDCFG3)
+#define F0900_P1_NOSTOP_FIFOFULL 0xf41e0008
+
+/*P1_DMDCFG4*/
+#define R0900_P1_DMDCFG4 0xf41f
+#define DMDCFG4 REGx(R0900_P1_DMDCFG4)
+#define F0900_P1_TUNER_NRELAUNCH 0xf41f0008
+
+/*P1_CORRELMANT*/
+#define R0900_P1_CORRELMANT 0xf420
+#define CORRELMANT REGx(R0900_P1_CORRELMANT)
+#define F0900_P1_CORREL_MANT 0xf42000ff
+
+/*P1_CORRELABS*/
+#define R0900_P1_CORRELABS 0xf421
+#define CORRELABS REGx(R0900_P1_CORRELABS)
+#define F0900_P1_CORREL_ABS 0xf42100ff
+
+/*P1_CORRELEXP*/
+#define R0900_P1_CORRELEXP 0xf422
+#define CORRELEXP REGx(R0900_P1_CORRELEXP)
+#define F0900_P1_CORREL_ABSEXP 0xf42200f0
+#define F0900_P1_CORREL_EXP 0xf422000f
+
+/*P1_PLHMODCOD*/
+#define R0900_P1_PLHMODCOD 0xf424
+#define PLHMODCOD REGx(R0900_P1_PLHMODCOD)
+#define F0900_P1_SPECINV_DEMOD 0xf4240080
+#define SPECINV_DEMOD FLDx(F0900_P1_SPECINV_DEMOD)
+#define F0900_P1_PLH_MODCOD 0xf424007c
+#define F0900_P1_PLH_TYPE 0xf4240003
+
+/*P1_DMDREG*/
+#define R0900_P1_DMDREG 0xf425
+#define DMDREG REGx(R0900_P1_DMDREG)
+#define F0900_P1_DECIM_PLFRAMES 0xf4250001
+
+/*P1_AGC2O*/
+#define R0900_P1_AGC2O 0xf42c
+#define AGC2O REGx(R0900_P1_AGC2O)
+#define F0900_P1_AGC2_COEF 0xf42c0007
+
+/*P1_AGC2REF*/
+#define R0900_P1_AGC2REF 0xf42d
+#define AGC2REF REGx(R0900_P1_AGC2REF)
+#define F0900_P1_AGC2_REF 0xf42d00ff
+
+/*P1_AGC1ADJ*/
+#define R0900_P1_AGC1ADJ 0xf42e
+#define AGC1ADJ REGx(R0900_P1_AGC1ADJ)
+#define F0900_P1_AGC1_ADJUSTED 0xf42e007f
+
+/*P1_AGC2I1*/
+#define R0900_P1_AGC2I1 0xf436
+#define AGC2I1 REGx(R0900_P1_AGC2I1)
+#define F0900_P1_AGC2_INTEGRATOR1 0xf43600ff
+
+/*P1_AGC2I0*/
+#define R0900_P1_AGC2I0 0xf437
+#define AGC2I0 REGx(R0900_P1_AGC2I0)
+#define F0900_P1_AGC2_INTEGRATOR0 0xf43700ff
+
+/*P1_CARCFG*/
+#define R0900_P1_CARCFG 0xf438
+#define CARCFG REGx(R0900_P1_CARCFG)
+#define F0900_P1_CFRUPLOW_AUTO 0xf4380080
+#define F0900_P1_CFRUPLOW_TEST 0xf4380040
+#define F0900_P1_ROTAON 0xf4380004
+#define F0900_P1_PH_DET_ALGO 0xf4380003
+
+/*P1_ACLC*/
+#define R0900_P1_ACLC 0xf439
+#define ACLC REGx(R0900_P1_ACLC)
+#define F0900_P1_CAR_ALPHA_MANT 0xf4390030
+#define F0900_P1_CAR_ALPHA_EXP 0xf439000f
+
+/*P1_BCLC*/
+#define R0900_P1_BCLC 0xf43a
+#define BCLC REGx(R0900_P1_BCLC)
+#define F0900_P1_CAR_BETA_MANT 0xf43a0030
+#define F0900_P1_CAR_BETA_EXP 0xf43a000f
+
+/*P1_CARFREQ*/
+#define R0900_P1_CARFREQ 0xf43d
+#define CARFREQ REGx(R0900_P1_CARFREQ)
+#define F0900_P1_KC_COARSE_EXP 0xf43d00f0
+#define F0900_P1_BETA_FREQ 0xf43d000f
+
+/*P1_CARHDR*/
+#define R0900_P1_CARHDR 0xf43e
+#define CARHDR REGx(R0900_P1_CARHDR)
+#define F0900_P1_K_FREQ_HDR 0xf43e00ff
+
+/*P1_LDT*/
+#define R0900_P1_LDT 0xf43f
+#define LDT REGx(R0900_P1_LDT)
+#define F0900_P1_CARLOCK_THRES 0xf43f01ff
+
+/*P1_LDT2*/
+#define R0900_P1_LDT2 0xf440
+#define LDT2 REGx(R0900_P1_LDT2)
+#define F0900_P1_CARLOCK_THRES2 0xf44001ff
+
+/*P1_CFRICFG*/
+#define R0900_P1_CFRICFG 0xf441
+#define CFRICFG REGx(R0900_P1_CFRICFG)
+#define F0900_P1_NEG_CFRSTEP 0xf4410001
+
+/*P1_CFRUP1*/
+#define R0900_P1_CFRUP1 0xf442
+#define CFRUP1 REGx(R0900_P1_CFRUP1)
+#define F0900_P1_CFR_UP1 0xf44201ff
+#define CFR_UP1 FLDx(F0900_P1_CFR_UP1)
+
+/*P1_CFRUP0*/
+#define R0900_P1_CFRUP0 0xf443
+#define CFRUP0 REGx(R0900_P1_CFRUP0)
+#define F0900_P1_CFR_UP0 0xf44300ff
+#define CFR_UP0 FLDx(F0900_P1_CFR_UP0)
+
+/*P1_CFRLOW1*/
+#define R0900_P1_CFRLOW1 0xf446
+#define CFRLOW1 REGx(R0900_P1_CFRLOW1)
+#define F0900_P1_CFR_LOW1 0xf44601ff
+#define CFR_LOW1 FLDx(F0900_P1_CFR_LOW1)
+
+/*P1_CFRLOW0*/
+#define R0900_P1_CFRLOW0 0xf447
+#define CFRLOW0 REGx(R0900_P1_CFRLOW0)
+#define F0900_P1_CFR_LOW0 0xf44700ff
+#define CFR_LOW0 FLDx(F0900_P1_CFR_LOW0)
+
+/*P1_CFRINIT1*/
+#define R0900_P1_CFRINIT1 0xf448
+#define CFRINIT1 REGx(R0900_P1_CFRINIT1)
+#define F0900_P1_CFR_INIT1 0xf44801ff
+#define CFR_INIT1 FLDx(F0900_P1_CFR_INIT1)
+
+/*P1_CFRINIT0*/
+#define R0900_P1_CFRINIT0 0xf449
+#define CFRINIT0 REGx(R0900_P1_CFRINIT0)
+#define F0900_P1_CFR_INIT0 0xf44900ff
+#define CFR_INIT0 FLDx(F0900_P1_CFR_INIT0)
+
+/*P1_CFRINC1*/
+#define R0900_P1_CFRINC1 0xf44a
+#define CFRINC1 REGx(R0900_P1_CFRINC1)
+#define F0900_P1_MANUAL_CFRINC 0xf44a0080
+#define F0900_P1_CFR_INC1 0xf44a003f
+
+/*P1_CFRINC0*/
+#define R0900_P1_CFRINC0 0xf44b
+#define CFRINC0 REGx(R0900_P1_CFRINC0)
+#define F0900_P1_CFR_INC0 0xf44b00f8
+
+/*P1_CFR2*/
+#define R0900_P1_CFR2 0xf44c
+#define CFR2 REGx(R0900_P1_CFR2)
+#define F0900_P1_CAR_FREQ2 0xf44c01ff
+#define CAR_FREQ2 FLDx(F0900_P1_CAR_FREQ2)
+
+/*P1_CFR1*/
+#define R0900_P1_CFR1 0xf44d
+#define CFR1 REGx(R0900_P1_CFR1)
+#define F0900_P1_CAR_FREQ1 0xf44d00ff
+#define CAR_FREQ1 FLDx(F0900_P1_CAR_FREQ1)
+
+/*P1_CFR0*/
+#define R0900_P1_CFR0 0xf44e
+#define CFR0 REGx(R0900_P1_CFR0)
+#define F0900_P1_CAR_FREQ0 0xf44e00ff
+#define CAR_FREQ0 FLDx(F0900_P1_CAR_FREQ0)
+
+/*P1_LDI*/
+#define R0900_P1_LDI 0xf44f
+#define LDI REGx(R0900_P1_LDI)
+#define F0900_P1_LOCK_DET_INTEGR 0xf44f01ff
+
+/*P1_TMGCFG*/
+#define R0900_P1_TMGCFG 0xf450
+#define TMGCFG REGx(R0900_P1_TMGCFG)
+#define F0900_P1_TMGLOCK_BETA 0xf45000c0
+#define F0900_P1_DO_TIMING_CORR 0xf4500010
+#define F0900_P1_TMG_MINFREQ 0xf4500003
+
+/*P1_RTC*/
+#define R0900_P1_RTC 0xf451
+#define RTC REGx(R0900_P1_RTC)
+#define F0900_P1_TMGALPHA_EXP 0xf45100f0
+#define F0900_P1_TMGBETA_EXP 0xf451000f
+
+/*P1_RTCS2*/
+#define R0900_P1_RTCS2 0xf452
+#define RTCS2 REGx(R0900_P1_RTCS2)
+#define F0900_P1_TMGALPHAS2_EXP 0xf45200f0
+#define F0900_P1_TMGBETAS2_EXP 0xf452000f
+
+/*P1_TMGTHRISE*/
+#define R0900_P1_TMGTHRISE 0xf453
+#define TMGTHRISE REGx(R0900_P1_TMGTHRISE)
+#define F0900_P1_TMGLOCK_THRISE 0xf45300ff
+
+/*P1_TMGTHFALL*/
+#define R0900_P1_TMGTHFALL 0xf454
+#define TMGTHFALL REGx(R0900_P1_TMGTHFALL)
+#define F0900_P1_TMGLOCK_THFALL 0xf45400ff
+
+/*P1_SFRUPRATIO*/
+#define R0900_P1_SFRUPRATIO 0xf455
+#define SFRUPRATIO REGx(R0900_P1_SFRUPRATIO)
+#define F0900_P1_SFR_UPRATIO 0xf45500ff
+
+/*P1_SFRLOWRATIO*/
+#define R0900_P1_SFRLOWRATIO 0xf456
+#define F0900_P1_SFR_LOWRATIO 0xf45600ff
+
+/*P1_KREFTMG*/
+#define R0900_P1_KREFTMG 0xf458
+#define KREFTMG REGx(R0900_P1_KREFTMG)
+#define F0900_P1_KREF_TMG 0xf45800ff
+
+/*P1_SFRSTEP*/
+#define R0900_P1_SFRSTEP 0xf459
+#define SFRSTEP REGx(R0900_P1_SFRSTEP)
+#define F0900_P1_SFR_SCANSTEP 0xf45900f0
+#define F0900_P1_SFR_CENTERSTEP 0xf459000f
+
+/*P1_TMGCFG2*/
+#define R0900_P1_TMGCFG2 0xf45a
+#define TMGCFG2 REGx(R0900_P1_TMGCFG2)
+#define F0900_P1_SFRRATIO_FINE 0xf45a0001
+
+/*P1_KREFTMG2*/
+#define R0900_P1_KREFTMG2 0xf45b
+#define KREFTMG2 REGx(R0900_P1_KREFTMG2)
+#define F0900_P1_KREF_TMG2 0xf45b00ff
+
+/*P1_SFRINIT1*/
+#define R0900_P1_SFRINIT1 0xf45e
+#define SFRINIT1 REGx(R0900_P1_SFRINIT1)
+#define F0900_P1_SFR_INIT1 0xf45e007f
+
+/*P1_SFRINIT0*/
+#define R0900_P1_SFRINIT0 0xf45f
+#define SFRINIT0 REGx(R0900_P1_SFRINIT0)
+#define F0900_P1_SFR_INIT0 0xf45f00ff
+
+/*P1_SFRUP1*/
+#define R0900_P1_SFRUP1 0xf460
+#define SFRUP1 REGx(R0900_P1_SFRUP1)
+#define F0900_P1_AUTO_GUP 0xf4600080
+#define AUTO_GUP FLDx(F0900_P1_AUTO_GUP)
+#define F0900_P1_SYMB_FREQ_UP1 0xf460007f
+
+/*P1_SFRUP0*/
+#define R0900_P1_SFRUP0 0xf461
+#define SFRUP0 REGx(R0900_P1_SFRUP0)
+#define F0900_P1_SYMB_FREQ_UP0 0xf46100ff
+
+/*P1_SFRLOW1*/
+#define R0900_P1_SFRLOW1 0xf462
+#define SFRLOW1 REGx(R0900_P1_SFRLOW1)
+#define F0900_P1_AUTO_GLOW 0xf4620080
+#define AUTO_GLOW FLDx(F0900_P1_AUTO_GLOW)
+#define F0900_P1_SYMB_FREQ_LOW1 0xf462007f
+
+/*P1_SFRLOW0*/
+#define R0900_P1_SFRLOW0 0xf463
+#define SFRLOW0 REGx(R0900_P1_SFRLOW0)
+#define F0900_P1_SYMB_FREQ_LOW0 0xf46300ff
+
+/*P1_SFR3*/
+#define R0900_P1_SFR3 0xf464
+#define SFR3 REGx(R0900_P1_SFR3)
+#define F0900_P1_SYMB_FREQ3 0xf46400ff
+#define SYMB_FREQ3 FLDx(F0900_P1_SYMB_FREQ3)
+
+/*P1_SFR2*/
+#define R0900_P1_SFR2 0xf465
+#define SFR2 REGx(R0900_P1_SFR2)
+#define F0900_P1_SYMB_FREQ2 0xf46500ff
+#define SYMB_FREQ2 FLDx(F0900_P1_SYMB_FREQ2)
+
+/*P1_SFR1*/
+#define R0900_P1_SFR1 0xf466
+#define SFR1 REGx(R0900_P1_SFR1)
+#define F0900_P1_SYMB_FREQ1 0xf46600ff
+#define SYMB_FREQ1 FLDx(F0900_P1_SYMB_FREQ1)
+
+/*P1_SFR0*/
+#define R0900_P1_SFR0 0xf467
+#define SFR0 REGx(R0900_P1_SFR0)
+#define F0900_P1_SYMB_FREQ0 0xf46700ff
+#define SYMB_FREQ0 FLDx(F0900_P1_SYMB_FREQ0)
+
+/*P1_TMGREG2*/
+#define R0900_P1_TMGREG2 0xf468
+#define TMGREG2 REGx(R0900_P1_TMGREG2)
+#define F0900_P1_TMGREG2 0xf46800ff
+
+/*P1_TMGREG1*/
+#define R0900_P1_TMGREG1 0xf469
+#define TMGREG1 REGx(R0900_P1_TMGREG1)
+#define F0900_P1_TMGREG1 0xf46900ff
+
+/*P1_TMGREG0*/
+#define R0900_P1_TMGREG0 0xf46a
+#define TMGREG0 REGx(R0900_P1_TMGREG0)
+#define F0900_P1_TMGREG0 0xf46a00ff
+
+/*P1_TMGLOCK1*/
+#define R0900_P1_TMGLOCK1 0xf46b
+#define TMGLOCK1 REGx(R0900_P1_TMGLOCK1)
+#define F0900_P1_TMGLOCK_LEVEL1 0xf46b01ff
+
+/*P1_TMGLOCK0*/
+#define R0900_P1_TMGLOCK0 0xf46c
+#define TMGLOCK0 REGx(R0900_P1_TMGLOCK0)
+#define F0900_P1_TMGLOCK_LEVEL0 0xf46c00ff
+
+/*P1_TMGOBS*/
+#define R0900_P1_TMGOBS 0xf46d
+#define TMGOBS REGx(R0900_P1_TMGOBS)
+#define F0900_P1_ROLLOFF_STATUS 0xf46d00c0
+#define ROLLOFF_STATUS FLDx(F0900_P1_ROLLOFF_STATUS)
+
+/*P1_EQUALCFG*/
+#define R0900_P1_EQUALCFG 0xf46f
+#define EQUALCFG REGx(R0900_P1_EQUALCFG)
+#define F0900_P1_EQUAL_ON 0xf46f0040
+#define F0900_P1_MU_EQUALDFE 0xf46f0007
+
+/*P1_EQUAI1*/
+#define R0900_P1_EQUAI1 0xf470
+#define EQUAI1 REGx(R0900_P1_EQUAI1)
+#define F0900_P1_EQUA_ACCI1 0xf47001ff
+
+/*P1_EQUAQ1*/
+#define R0900_P1_EQUAQ1 0xf471
+#define EQUAQ1 REGx(R0900_P1_EQUAQ1)
+#define F0900_P1_EQUA_ACCQ1 0xf47101ff
+
+/*P1_EQUAI2*/
+#define R0900_P1_EQUAI2 0xf472
+#define EQUAI2 REGx(R0900_P1_EQUAI2)
+#define F0900_P1_EQUA_ACCI2 0xf47201ff
+
+/*P1_EQUAQ2*/
+#define R0900_P1_EQUAQ2 0xf473
+#define EQUAQ2 REGx(R0900_P1_EQUAQ2)
+#define F0900_P1_EQUA_ACCQ2 0xf47301ff
+
+/*P1_EQUAI3*/
+#define R0900_P1_EQUAI3 0xf474
+#define EQUAI3 REGx(R0900_P1_EQUAI3)
+#define F0900_P1_EQUA_ACCI3 0xf47401ff
+
+/*P1_EQUAQ3*/
+#define R0900_P1_EQUAQ3 0xf475
+#define EQUAQ3 REGx(R0900_P1_EQUAQ3)
+#define F0900_P1_EQUA_ACCQ3 0xf47501ff
+
+/*P1_EQUAI4*/
+#define R0900_P1_EQUAI4 0xf476
+#define EQUAI4 REGx(R0900_P1_EQUAI4)
+#define F0900_P1_EQUA_ACCI4 0xf47601ff
+
+/*P1_EQUAQ4*/
+#define R0900_P1_EQUAQ4 0xf477
+#define EQUAQ4 REGx(R0900_P1_EQUAQ4)
+#define F0900_P1_EQUA_ACCQ4 0xf47701ff
+
+/*P1_EQUAI5*/
+#define R0900_P1_EQUAI5 0xf478
+#define EQUAI5 REGx(R0900_P1_EQUAI5)
+#define F0900_P1_EQUA_ACCI5 0xf47801ff
+
+/*P1_EQUAQ5*/
+#define R0900_P1_EQUAQ5 0xf479
+#define EQUAQ5 REGx(R0900_P1_EQUAQ5)
+#define F0900_P1_EQUA_ACCQ5 0xf47901ff
+
+/*P1_EQUAI6*/
+#define R0900_P1_EQUAI6 0xf47a
+#define EQUAI6 REGx(R0900_P1_EQUAI6)
+#define F0900_P1_EQUA_ACCI6 0xf47a01ff
+
+/*P1_EQUAQ6*/
+#define R0900_P1_EQUAQ6 0xf47b
+#define EQUAQ6 REGx(R0900_P1_EQUAQ6)
+#define F0900_P1_EQUA_ACCQ6 0xf47b01ff
+
+/*P1_EQUAI7*/
+#define R0900_P1_EQUAI7 0xf47c
+#define EQUAI7 REGx(R0900_P1_EQUAI7)
+#define F0900_P1_EQUA_ACCI7 0xf47c01ff
+
+/*P1_EQUAQ7*/
+#define R0900_P1_EQUAQ7 0xf47d
+#define EQUAQ7 REGx(R0900_P1_EQUAQ7)
+#define F0900_P1_EQUA_ACCQ7 0xf47d01ff
+
+/*P1_EQUAI8*/
+#define R0900_P1_EQUAI8 0xf47e
+#define EQUAI8 REGx(R0900_P1_EQUAI8)
+#define F0900_P1_EQUA_ACCI8 0xf47e01ff
+
+/*P1_EQUAQ8*/
+#define R0900_P1_EQUAQ8 0xf47f
+#define EQUAQ8 REGx(R0900_P1_EQUAQ8)
+#define F0900_P1_EQUA_ACCQ8 0xf47f01ff
+
+/*P1_NNOSDATAT1*/
+#define R0900_P1_NNOSDATAT1 0xf480
+#define NNOSDATAT1 REGx(R0900_P1_NNOSDATAT1)
+#define F0900_P1_NOSDATAT_NORMED1 0xf48000ff
+#define NOSDATAT_NORMED1 FLDx(F0900_P1_NOSDATAT_NORMED1)
+
+/*P1_NNOSDATAT0*/
+#define R0900_P1_NNOSDATAT0 0xf481
+#define NNOSDATAT0 REGx(R0900_P1_NNOSDATAT0)
+#define F0900_P1_NOSDATAT_NORMED0 0xf48100ff
+#define NOSDATAT_NORMED0 FLDx(F0900_P1_NOSDATAT_NORMED0)
+
+/*P1_NNOSDATA1*/
+#define R0900_P1_NNOSDATA1 0xf482
+#define NNOSDATA1 REGx(R0900_P1_NNOSDATA1)
+#define F0900_P1_NOSDATA_NORMED1 0xf48200ff
+
+/*P1_NNOSDATA0*/
+#define R0900_P1_NNOSDATA0 0xf483
+#define NNOSDATA0 REGx(R0900_P1_NNOSDATA0)
+#define F0900_P1_NOSDATA_NORMED0 0xf48300ff
+
+/*P1_NNOSPLHT1*/
+#define R0900_P1_NNOSPLHT1 0xf484
+#define NNOSPLHT1 REGx(R0900_P1_NNOSPLHT1)
+#define F0900_P1_NOSPLHT_NORMED1 0xf48400ff
+#define NOSPLHT_NORMED1 FLDx(F0900_P1_NOSPLHT_NORMED1)
+
+/*P1_NNOSPLHT0*/
+#define R0900_P1_NNOSPLHT0 0xf485
+#define NNOSPLHT0 REGx(R0900_P1_NNOSPLHT0)
+#define F0900_P1_NOSPLHT_NORMED0 0xf48500ff
+#define NOSPLHT_NORMED0 FLDx(F0900_P1_NOSPLHT_NORMED0)
+
+/*P1_NNOSPLH1*/
+#define R0900_P1_NNOSPLH1 0xf486
+#define NNOSPLH1 REGx(R0900_P1_NNOSPLH1)
+#define F0900_P1_NOSPLH_NORMED1 0xf48600ff
+
+/*P1_NNOSPLH0*/
+#define R0900_P1_NNOSPLH0 0xf487
+#define NNOSPLH0 REGx(R0900_P1_NNOSPLH0)
+#define F0900_P1_NOSPLH_NORMED0 0xf48700ff
+
+/*P1_NOSDATAT1*/
+#define R0900_P1_NOSDATAT1 0xf488
+#define NOSDATAT1 REGx(R0900_P1_NOSDATAT1)
+#define F0900_P1_NOSDATAT_UNNORMED1 0xf48800ff
+
+/*P1_NOSDATAT0*/
+#define R0900_P1_NOSDATAT0 0xf489
+#define NOSDATAT0 REGx(R0900_P1_NOSDATAT0)
+#define F0900_P1_NOSDATAT_UNNORMED0 0xf48900ff
+
+/*P1_NOSDATA1*/
+#define R0900_P1_NOSDATA1 0xf48a
+#define NOSDATA1 REGx(R0900_P1_NOSDATA1)
+#define F0900_P1_NOSDATA_UNNORMED1 0xf48a00ff
+
+/*P1_NOSDATA0*/
+#define R0900_P1_NOSDATA0 0xf48b
+#define NOSDATA0 REGx(R0900_P1_NOSDATA0)
+#define F0900_P1_NOSDATA_UNNORMED0 0xf48b00ff
+
+/*P1_NOSPLHT1*/
+#define R0900_P1_NOSPLHT1 0xf48c
+#define NOSPLHT1 REGx(R0900_P1_NOSPLHT1)
+#define F0900_P1_NOSPLHT_UNNORMED1 0xf48c00ff
+
+/*P1_NOSPLHT0*/
+#define R0900_P1_NOSPLHT0 0xf48d
+#define NOSPLHT0 REGx(R0900_P1_NOSPLHT0)
+#define F0900_P1_NOSPLHT_UNNORMED0 0xf48d00ff
+
+/*P1_NOSPLH1*/
+#define R0900_P1_NOSPLH1 0xf48e
+#define NOSPLH1 REGx(R0900_P1_NOSPLH1)
+#define F0900_P1_NOSPLH_UNNORMED1 0xf48e00ff
+
+/*P1_NOSPLH0*/
+#define R0900_P1_NOSPLH0 0xf48f
+#define NOSPLH0 REGx(R0900_P1_NOSPLH0)
+#define F0900_P1_NOSPLH_UNNORMED0 0xf48f00ff
+
+/*P1_CAR2CFG*/
+#define R0900_P1_CAR2CFG 0xf490
+#define CAR2CFG REGx(R0900_P1_CAR2CFG)
+#define F0900_P1_CARRIER3_DISABLE 0xf4900040
+#define F0900_P1_ROTA2ON 0xf4900004
+#define F0900_P1_PH_DET_ALGO2 0xf4900003
+
+/*P1_CFR2CFR1*/
+#define R0900_P1_CFR2CFR1 0xf491
+#define CFR2CFR1 REGx(R0900_P1_CFR2CFR1)
+#define F0900_P1_CFR2TOCFR1_DVBS1 0xf49100c0
+#define F0900_P1_EN_S2CAR2CENTER 0xf4910020
+#define F0900_P1_DIS_BCHERRCFR2 0xf4910010
+#define F0900_P1_CFR2TOCFR1_BETA 0xf4910007
+
+/*P1_CFR22*/
+#define R0900_P1_CFR22 0xf493
+#define CFR22 REGx(R0900_P1_CFR22)
+#define F0900_P1_CAR2_FREQ2 0xf49301ff
+
+/*P1_CFR21*/
+#define R0900_P1_CFR21 0xf494
+#define CFR21 REGx(R0900_P1_CFR21)
+#define F0900_P1_CAR2_FREQ1 0xf49400ff
+
+/*P1_CFR20*/
+#define R0900_P1_CFR20 0xf495
+#define CFR20 REGx(R0900_P1_CFR20)
+#define F0900_P1_CAR2_FREQ0 0xf49500ff
+
+/*P1_ACLC2S2Q*/
+#define R0900_P1_ACLC2S2Q 0xf497
+#define ACLC2S2Q REGx(R0900_P1_ACLC2S2Q)
+#define F0900_P1_ENAB_SPSKSYMB 0xf4970080
+#define F0900_P1_CAR2S2_Q_ALPH_M 0xf4970030
+#define F0900_P1_CAR2S2_Q_ALPH_E 0xf497000f
+
+/*P1_ACLC2S28*/
+#define R0900_P1_ACLC2S28 0xf498
+#define ACLC2S28 REGx(R0900_P1_ACLC2S28)
+#define F0900_P1_OLDI3Q_MODE 0xf4980080
+#define F0900_P1_CAR2S2_8_ALPH_M 0xf4980030
+#define F0900_P1_CAR2S2_8_ALPH_E 0xf498000f
+
+/*P1_ACLC2S216A*/
+#define R0900_P1_ACLC2S216A 0xf499
+#define ACLC2S216A REGx(R0900_P1_ACLC2S216A)
+#define F0900_P1_DIS_C3STOPA2 0xf4990080
+#define F0900_P1_CAR2S2_16ADERAT 0xf4990040
+#define F0900_P1_CAR2S2_16A_ALPH_M 0xf4990030
+#define F0900_P1_CAR2S2_16A_ALPH_E 0xf499000f
+
+/*P1_ACLC2S232A*/
+#define R0900_P1_ACLC2S232A 0xf49a
+#define ACLC2S232A REGx(R0900_P1_ACLC2S232A)
+#define F0900_P1_CAR2S2_32ADERAT 0xf49a0040
+#define F0900_P1_CAR2S2_32A_ALPH_M 0xf49a0030
+#define F0900_P1_CAR2S2_32A_ALPH_E 0xf49a000f
+
+/*P1_BCLC2S2Q*/
+#define R0900_P1_BCLC2S2Q 0xf49c
+#define BCLC2S2Q REGx(R0900_P1_BCLC2S2Q)
+#define F0900_P1_CAR2S2_Q_BETA_M 0xf49c0030
+#define F0900_P1_CAR2S2_Q_BETA_E 0xf49c000f
+
+/*P1_BCLC2S28*/
+#define R0900_P1_BCLC2S28 0xf49d
+#define BCLC2S28 REGx(R0900_P1_BCLC2S28)
+#define F0900_P1_CAR2S2_8_BETA_M 0xf49d0030
+#define F0900_P1_CAR2S2_8_BETA_E 0xf49d000f
+
+/*P1_BCLC2S216A*/
+#define R0900_P1_BCLC2S216A 0xf49e
+#define BCLC2S216A REGx(R0900_P1_BCLC2S216A)
+
+/*P1_BCLC2S232A*/
+#define R0900_P1_BCLC2S232A 0xf49f
+#define BCLC2S232A REGx(R0900_P1_BCLC2S232A)
+
+/*P1_PLROOT2*/
+#define R0900_P1_PLROOT2 0xf4ac
+#define PLROOT2 REGx(R0900_P1_PLROOT2)
+#define F0900_P1_PLSCRAMB_MODE 0xf4ac000c
+#define F0900_P1_PLSCRAMB_ROOT2 0xf4ac0003
+
+/*P1_PLROOT1*/
+#define R0900_P1_PLROOT1 0xf4ad
+#define PLROOT1 REGx(R0900_P1_PLROOT1)
+#define F0900_P1_PLSCRAMB_ROOT1 0xf4ad00ff
+
+/*P1_PLROOT0*/
+#define R0900_P1_PLROOT0 0xf4ae
+#define PLROOT0 REGx(R0900_P1_PLROOT0)
+#define F0900_P1_PLSCRAMB_ROOT0 0xf4ae00ff
+
+/*P1_MODCODLST0*/
+#define R0900_P1_MODCODLST0 0xf4b0
+#define MODCODLST0 REGx(R0900_P1_MODCODLST0)
+
+/*P1_MODCODLST1*/
+#define R0900_P1_MODCODLST1 0xf4b1
+#define MODCODLST1 REGx(R0900_P1_MODCODLST1)
+#define F0900_P1_DIS_MODCOD29 0xf4b100f0
+#define F0900_P1_DIS_32PSK_9_10 0xf4b1000f
+
+/*P1_MODCODLST2*/
+#define R0900_P1_MODCODLST2 0xf4b2
+#define MODCODLST2 REGx(R0900_P1_MODCODLST2)
+#define F0900_P1_DIS_32PSK_8_9 0xf4b200f0
+#define F0900_P1_DIS_32PSK_5_6 0xf4b2000f
+
+/*P1_MODCODLST3*/
+#define R0900_P1_MODCODLST3 0xf4b3
+#define MODCODLST3 REGx(R0900_P1_MODCODLST3)
+#define F0900_P1_DIS_32PSK_4_5 0xf4b300f0
+#define F0900_P1_DIS_32PSK_3_4 0xf4b3000f
+
+/*P1_MODCODLST4*/
+#define R0900_P1_MODCODLST4 0xf4b4
+#define MODCODLST4 REGx(R0900_P1_MODCODLST4)
+#define F0900_P1_DIS_16PSK_9_10 0xf4b400f0
+#define F0900_P1_DIS_16PSK_8_9 0xf4b4000f
+
+/*P1_MODCODLST5*/
+#define R0900_P1_MODCODLST5 0xf4b5
+#define MODCODLST5 REGx(R0900_P1_MODCODLST5)
+#define F0900_P1_DIS_16PSK_5_6 0xf4b500f0
+#define F0900_P1_DIS_16PSK_4_5 0xf4b5000f
+
+/*P1_MODCODLST6*/
+#define R0900_P1_MODCODLST6 0xf4b6
+#define MODCODLST6 REGx(R0900_P1_MODCODLST6)
+#define F0900_P1_DIS_16PSK_3_4 0xf4b600f0
+#define F0900_P1_DIS_16PSK_2_3 0xf4b6000f
+
+/*P1_MODCODLST7*/
+#define R0900_P1_MODCODLST7 0xf4b7
+#define MODCODLST7 REGx(R0900_P1_MODCODLST7)
+#define F0900_P1_DIS_8P_9_10 0xf4b700f0
+#define F0900_P1_DIS_8P_8_9 0xf4b7000f
+
+/*P1_MODCODLST8*/
+#define R0900_P1_MODCODLST8 0xf4b8
+#define MODCODLST8 REGx(R0900_P1_MODCODLST8)
+#define F0900_P1_DIS_8P_5_6 0xf4b800f0
+#define F0900_P1_DIS_8P_3_4 0xf4b8000f
+
+/*P1_MODCODLST9*/
+#define R0900_P1_MODCODLST9 0xf4b9
+#define MODCODLST9 REGx(R0900_P1_MODCODLST9)
+#define F0900_P1_DIS_8P_2_3 0xf4b900f0
+#define F0900_P1_DIS_8P_3_5 0xf4b9000f
+
+/*P1_MODCODLSTA*/
+#define R0900_P1_MODCODLSTA 0xf4ba
+#define MODCODLSTA REGx(R0900_P1_MODCODLSTA)
+#define F0900_P1_DIS_QP_9_10 0xf4ba00f0
+#define F0900_P1_DIS_QP_8_9 0xf4ba000f
+
+/*P1_MODCODLSTB*/
+#define R0900_P1_MODCODLSTB 0xf4bb
+#define MODCODLSTB REGx(R0900_P1_MODCODLSTB)
+#define F0900_P1_DIS_QP_5_6 0xf4bb00f0
+#define F0900_P1_DIS_QP_4_5 0xf4bb000f
+
+/*P1_MODCODLSTC*/
+#define R0900_P1_MODCODLSTC 0xf4bc
+#define MODCODLSTC REGx(R0900_P1_MODCODLSTC)
+#define F0900_P1_DIS_QP_3_4 0xf4bc00f0
+#define F0900_P1_DIS_QP_2_3 0xf4bc000f
+
+/*P1_MODCODLSTD*/
+#define R0900_P1_MODCODLSTD 0xf4bd
+#define MODCODLSTD REGx(R0900_P1_MODCODLSTD)
+#define F0900_P1_DIS_QP_3_5 0xf4bd00f0
+#define F0900_P1_DIS_QP_1_2 0xf4bd000f
+
+/*P1_MODCODLSTE*/
+#define R0900_P1_MODCODLSTE 0xf4be
+#define MODCODLSTE REGx(R0900_P1_MODCODLSTE)
+#define F0900_P1_DIS_QP_2_5 0xf4be00f0
+#define F0900_P1_DIS_QP_1_3 0xf4be000f
+
+/*P1_MODCODLSTF*/
+#define R0900_P1_MODCODLSTF 0xf4bf
+#define MODCODLSTF REGx(R0900_P1_MODCODLSTF)
+#define F0900_P1_DIS_QP_1_4 0xf4bf00f0
+
+/*P1_GAUSSR0*/
+#define R0900_P1_GAUSSR0 0xf4c0
+#define GAUSSR0 REGx(R0900_P1_GAUSSR0)
+#define F0900_P1_EN_CCIMODE 0xf4c00080
+#define F0900_P1_R0_GAUSSIEN 0xf4c0007f
+
+/*P1_CCIR0*/
+#define R0900_P1_CCIR0 0xf4c1
+#define CCIR0 REGx(R0900_P1_CCIR0)
+#define F0900_P1_CCIDETECT_PLHONLY 0xf4c10080
+#define F0900_P1_R0_CCI 0xf4c1007f
+
+/*P1_CCIQUANT*/
+#define R0900_P1_CCIQUANT 0xf4c2
+#define CCIQUANT REGx(R0900_P1_CCIQUANT)
+#define F0900_P1_CCI_BETA 0xf4c200e0
+#define F0900_P1_CCI_QUANT 0xf4c2001f
+
+/*P1_CCITHRES*/
+#define R0900_P1_CCITHRES 0xf4c3
+#define CCITHRES REGx(R0900_P1_CCITHRES)
+#define F0900_P1_CCI_THRESHOLD 0xf4c300ff
+
+/*P1_CCIACC*/
+#define R0900_P1_CCIACC 0xf4c4
+#define CCIACC REGx(R0900_P1_CCIACC)
+#define F0900_P1_CCI_VALUE 0xf4c400ff
+
+/*P1_DMDRESCFG*/
+#define R0900_P1_DMDRESCFG 0xf4c6
+#define DMDRESCFG REGx(R0900_P1_DMDRESCFG)
+#define F0900_P1_DMDRES_RESET 0xf4c60080
+#define F0900_P1_DMDRES_STRALL 0xf4c60008
+#define F0900_P1_DMDRES_NEWONLY 0xf4c60004
+#define F0900_P1_DMDRES_NOSTORE 0xf4c60002
+
+/*P1_DMDRESADR*/
+#define R0900_P1_DMDRESADR 0xf4c7
+#define DMDRESADR REGx(R0900_P1_DMDRESADR)
+#define F0900_P1_DMDRES_VALIDCFR 0xf4c70040
+#define F0900_P1_DMDRES_MEMFULL 0xf4c70030
+#define F0900_P1_DMDRES_RESNBR 0xf4c7000f
+
+/*P1_DMDRESDATA7*/
+#define R0900_P1_DMDRESDATA7 0xf4c8
+#define F0900_P1_DMDRES_DATA7 0xf4c800ff
+
+/*P1_DMDRESDATA6*/
+#define R0900_P1_DMDRESDATA6 0xf4c9
+#define F0900_P1_DMDRES_DATA6 0xf4c900ff
+
+/*P1_DMDRESDATA5*/
+#define R0900_P1_DMDRESDATA5 0xf4ca
+#define F0900_P1_DMDRES_DATA5 0xf4ca00ff
+
+/*P1_DMDRESDATA4*/
+#define R0900_P1_DMDRESDATA4 0xf4cb
+#define F0900_P1_DMDRES_DATA4 0xf4cb00ff
+
+/*P1_DMDRESDATA3*/
+#define R0900_P1_DMDRESDATA3 0xf4cc
+#define F0900_P1_DMDRES_DATA3 0xf4cc00ff
+
+/*P1_DMDRESDATA2*/
+#define R0900_P1_DMDRESDATA2 0xf4cd
+#define F0900_P1_DMDRES_DATA2 0xf4cd00ff
+
+/*P1_DMDRESDATA1*/
+#define R0900_P1_DMDRESDATA1 0xf4ce
+#define F0900_P1_DMDRES_DATA1 0xf4ce00ff
+
+/*P1_DMDRESDATA0*/
+#define R0900_P1_DMDRESDATA0 0xf4cf
+#define F0900_P1_DMDRES_DATA0 0xf4cf00ff
+
+/*P1_FFEI1*/
+#define R0900_P1_FFEI1 0xf4d0
+#define FFEI1 REGx(R0900_P1_FFEI1)
+#define F0900_P1_FFE_ACCI1 0xf4d001ff
+
+/*P1_FFEQ1*/
+#define R0900_P1_FFEQ1 0xf4d1
+#define FFEQ1 REGx(R0900_P1_FFEQ1)
+#define F0900_P1_FFE_ACCQ1 0xf4d101ff
+
+/*P1_FFEI2*/
+#define R0900_P1_FFEI2 0xf4d2
+#define FFEI2 REGx(R0900_P1_FFEI2)
+#define F0900_P1_FFE_ACCI2 0xf4d201ff
+
+/*P1_FFEQ2*/
+#define R0900_P1_FFEQ2 0xf4d3
+#define FFEQ2 REGx(R0900_P1_FFEQ2)
+#define F0900_P1_FFE_ACCQ2 0xf4d301ff
+
+/*P1_FFEI3*/
+#define R0900_P1_FFEI3 0xf4d4
+#define FFEI3 REGx(R0900_P1_FFEI3)
+#define F0900_P1_FFE_ACCI3 0xf4d401ff
+
+/*P1_FFEQ3*/
+#define R0900_P1_FFEQ3 0xf4d5
+#define FFEQ3 REGx(R0900_P1_FFEQ3)
+#define F0900_P1_FFE_ACCQ3 0xf4d501ff
+
+/*P1_FFEI4*/
+#define R0900_P1_FFEI4 0xf4d6
+#define FFEI4 REGx(R0900_P1_FFEI4)
+#define F0900_P1_FFE_ACCI4 0xf4d601ff
+
+/*P1_FFEQ4*/
+#define R0900_P1_FFEQ4 0xf4d7
+#define FFEQ4 REGx(R0900_P1_FFEQ4)
+#define F0900_P1_FFE_ACCQ4 0xf4d701ff
+
+/*P1_FFECFG*/
+#define R0900_P1_FFECFG 0xf4d8
+#define FFECFG REGx(R0900_P1_FFECFG)
+#define F0900_P1_EQUALFFE_ON 0xf4d80040
+#define F0900_P1_MU_EQUALFFE 0xf4d80007
+
+/*P1_TNRCFG*/
+#define R0900_P1_TNRCFG 0xf4e0
+#define TNRCFG REGx(R0900_P1_TNRCFG)
+#define F0900_P1_TUN_ACKFAIL 0xf4e00080
+#define F0900_P1_TUN_TYPE 0xf4e00070
+#define F0900_P1_TUN_SECSTOP 0xf4e00008
+#define F0900_P1_TUN_VCOSRCH 0xf4e00004
+#define F0900_P1_TUN_MADDRESS 0xf4e00003
+
+/*P1_TNRCFG2*/
+#define R0900_P1_TNRCFG2 0xf4e1
+#define TNRCFG2 REGx(R0900_P1_TNRCFG2)
+#define F0900_P1_TUN_IQSWAP 0xf4e10080
+#define F0900_P1_DIS_BWCALC 0xf4e10004
+#define F0900_P1_SHORT_WAITSTATES 0xf4e10002
+
+/*P1_TNRXTAL*/
+#define R0900_P1_TNRXTAL 0xf4e4
+#define TNRXTAL REGx(R0900_P1_TNRXTAL)
+#define F0900_P1_TUN_XTALFREQ 0xf4e4001f
+
+/*P1_TNRSTEPS*/
+#define R0900_P1_TNRSTEPS 0xf4e7
+#define TNRSTEPS REGx(R0900_P1_TNRSTEPS)
+#define F0900_P1_TUNER_BW0P125 0xf4e70080
+#define F0900_P1_BWINC_OFFSET 0xf4e70170
+#define F0900_P1_SOFTSTEP_RNG 0xf4e70008
+#define F0900_P1_TUN_BWOFFSET 0xf4e70007
+
+/*P1_TNRGAIN*/
+#define R0900_P1_TNRGAIN 0xf4e8
+#define TNRGAIN REGx(R0900_P1_TNRGAIN)
+#define F0900_P1_TUN_KDIVEN 0xf4e800c0
+#define F0900_P1_STB6X00_OCK 0xf4e80030
+#define F0900_P1_TUN_GAIN 0xf4e8000f
+
+/*P1_TNRRF1*/
+#define R0900_P1_TNRRF1 0xf4e9
+#define TNRRF1 REGx(R0900_P1_TNRRF1)
+#define F0900_P1_TUN_RFFREQ2 0xf4e900ff
+#define TUN_RFFREQ2 FLDx(F0900_P1_TUN_RFFREQ2)
+
+/*P1_TNRRF0*/
+#define R0900_P1_TNRRF0 0xf4ea
+#define TNRRF0 REGx(R0900_P1_TNRRF0)
+#define F0900_P1_TUN_RFFREQ1 0xf4ea00ff
+#define TUN_RFFREQ1 FLDx(F0900_P1_TUN_RFFREQ1)
+
+/*P1_TNRBW*/
+#define R0900_P1_TNRBW 0xf4eb
+#define TNRBW REGx(R0900_P1_TNRBW)
+#define F0900_P1_TUN_RFFREQ0 0xf4eb00c0
+#define TUN_RFFREQ0 FLDx(F0900_P1_TUN_RFFREQ0)
+#define F0900_P1_TUN_BW 0xf4eb003f
+#define TUN_BW FLDx(F0900_P1_TUN_BW)
+
+/*P1_TNRADJ*/
+#define R0900_P1_TNRADJ 0xf4ec
+#define TNRADJ REGx(R0900_P1_TNRADJ)
+#define F0900_P1_STB61X0_CALTIME 0xf4ec0040
+
+/*P1_TNRCTL2*/
+#define R0900_P1_TNRCTL2 0xf4ed
+#define TNRCTL2 REGx(R0900_P1_TNRCTL2)
+#define F0900_P1_STB61X0_RCCKOFF 0xf4ed0080
+#define F0900_P1_STB61X0_ICP_SDOFF 0xf4ed0040
+#define F0900_P1_STB61X0_DCLOOPOFF 0xf4ed0020
+#define F0900_P1_STB61X0_REFOUTSEL 0xf4ed0010
+#define F0900_P1_STB61X0_CALOFF 0xf4ed0008
+#define F0900_P1_STB6XX0_LPT_BEN 0xf4ed0004
+#define F0900_P1_STB6XX0_RX_OSCP 0xf4ed0002
+#define F0900_P1_STB6XX0_SYN 0xf4ed0001
+
+/*P1_TNRCFG3*/
+#define R0900_P1_TNRCFG3 0xf4ee
+#define TNRCFG3 REGx(R0900_P1_TNRCFG3)
+#define F0900_P1_TUN_PLLFREQ 0xf4ee001c
+#define F0900_P1_TUN_I2CFREQ_MODE 0xf4ee0003
+
+/*P1_TNRLAUNCH*/
+#define R0900_P1_TNRLAUNCH 0xf4f0
+#define TNRLAUNCH REGx(R0900_P1_TNRLAUNCH)
+
+/*P1_TNRLD*/
+#define R0900_P1_TNRLD 0xf4f0
+#define TNRLD REGx(R0900_P1_TNRLD)
+#define F0900_P1_TUNLD_VCOING 0xf4f00080
+#define F0900_P1_TUN_REG1FAIL 0xf4f00040
+#define F0900_P1_TUN_REG2FAIL 0xf4f00020
+#define F0900_P1_TUN_REG3FAIL 0xf4f00010
+#define F0900_P1_TUN_REG4FAIL 0xf4f00008
+#define F0900_P1_TUN_REG5FAIL 0xf4f00004
+#define F0900_P1_TUN_BWING 0xf4f00002
+#define F0900_P1_TUN_LOCKED 0xf4f00001
+
+/*P1_TNROBSL*/
+#define R0900_P1_TNROBSL 0xf4f6
+#define TNROBSL REGx(R0900_P1_TNROBSL)
+#define F0900_P1_TUN_I2CABORTED 0xf4f60080
+#define F0900_P1_TUN_LPEN 0xf4f60040
+#define F0900_P1_TUN_FCCK 0xf4f60020
+#define F0900_P1_TUN_I2CLOCKED 0xf4f60010
+#define F0900_P1_TUN_PROGDONE 0xf4f6000c
+#define F0900_P1_TUN_RFRESTE1 0xf4f60003
+#define TUN_RFRESTE1 FLDx(F0900_P1_TUN_RFRESTE1)
+
+/*P1_TNRRESTE*/
+#define R0900_P1_TNRRESTE 0xf4f7
+#define TNRRESTE REGx(R0900_P1_TNRRESTE)
+#define F0900_P1_TUN_RFRESTE0 0xf4f700ff
+#define TUN_RFRESTE0 FLDx(F0900_P1_TUN_RFRESTE0)
+
+/*P1_SMAPCOEF7*/
+#define R0900_P1_SMAPCOEF7 0xf500
+#define SMAPCOEF7 REGx(R0900_P1_SMAPCOEF7)
+#define F0900_P1_DIS_QSCALE 0xf5000080
+#define F0900_P1_SMAPCOEF_Q_LLR12 0xf500017f
+
+/*P1_SMAPCOEF6*/
+#define R0900_P1_SMAPCOEF6 0xf501
+#define SMAPCOEF6 REGx(R0900_P1_SMAPCOEF6)
+#define F0900_P1_ADJ_8PSKLLR1 0xf5010004
+#define F0900_P1_OLD_8PSKLLR1 0xf5010002
+#define F0900_P1_DIS_AB8PSK 0xf5010001
+
+/*P1_SMAPCOEF5*/
+#define R0900_P1_SMAPCOEF5 0xf502
+#define SMAPCOEF5 REGx(R0900_P1_SMAPCOEF5)
+#define F0900_P1_DIS_8SCALE 0xf5020080
+#define F0900_P1_SMAPCOEF_8P_LLR23 0xf502017f
+
+/*P1_NCO2MAX1*/
+#define R0900_P1_NCO2MAX1 0xf514
+#define NCO2MAX1 REGx(R0900_P1_NCO2MAX1)
+#define F0900_P1_TETA2_MAXVABS1 0xf51400ff
+
+/*P1_NCO2MAX0*/
+#define R0900_P1_NCO2MAX0 0xf515
+#define NCO2MAX0 REGx(R0900_P1_NCO2MAX0)
+#define F0900_P1_TETA2_MAXVABS0 0xf51500ff
+
+/*P1_NCO2FR1*/
+#define R0900_P1_NCO2FR1 0xf516
+#define NCO2FR1 REGx(R0900_P1_NCO2FR1)
+#define F0900_P1_NCO2FINAL_ANGLE1 0xf51600ff
+
+/*P1_NCO2FR0*/
+#define R0900_P1_NCO2FR0 0xf517
+#define NCO2FR0 REGx(R0900_P1_NCO2FR0)
+#define F0900_P1_NCO2FINAL_ANGLE0 0xf51700ff
+
+/*P1_CFR2AVRGE1*/
+#define R0900_P1_CFR2AVRGE1 0xf518
+#define CFR2AVRGE1 REGx(R0900_P1_CFR2AVRGE1)
+#define F0900_P1_I2C_CFR2AVERAGE1 0xf51800ff
+
+/*P1_CFR2AVRGE0*/
+#define R0900_P1_CFR2AVRGE0 0xf519
+#define CFR2AVRGE0 REGx(R0900_P1_CFR2AVRGE0)
+#define F0900_P1_I2C_CFR2AVERAGE0 0xf51900ff
+
+/*P1_DMDPLHSTAT*/
+#define R0900_P1_DMDPLHSTAT 0xf520
+#define DMDPLHSTAT REGx(R0900_P1_DMDPLHSTAT)
+#define F0900_P1_PLH_STATISTIC 0xf52000ff
+
+/*P1_LOCKTIME3*/
+#define R0900_P1_LOCKTIME3 0xf522
+#define LOCKTIME3 REGx(R0900_P1_LOCKTIME3)
+#define F0900_P1_DEMOD_LOCKTIME3 0xf52200ff
+
+/*P1_LOCKTIME2*/
+#define R0900_P1_LOCKTIME2 0xf523
+#define LOCKTIME2 REGx(R0900_P1_LOCKTIME2)
+#define F0900_P1_DEMOD_LOCKTIME2 0xf52300ff
+
+/*P1_LOCKTIME1*/
+#define R0900_P1_LOCKTIME1 0xf524
+#define LOCKTIME1 REGx(R0900_P1_LOCKTIME1)
+#define F0900_P1_DEMOD_LOCKTIME1 0xf52400ff
+
+/*P1_LOCKTIME0*/
+#define R0900_P1_LOCKTIME0 0xf525
+#define LOCKTIME0 REGx(R0900_P1_LOCKTIME0)
+#define F0900_P1_DEMOD_LOCKTIME0 0xf52500ff
+
+/*P1_VITSCALE*/
+#define R0900_P1_VITSCALE 0xf532
+#define VITSCALE REGx(R0900_P1_VITSCALE)
+#define F0900_P1_NVTH_NOSRANGE 0xf5320080
+#define F0900_P1_VERROR_MAXMODE 0xf5320040
+#define F0900_P1_NSLOWSN_LOCKED 0xf5320008
+#define F0900_P1_DIS_RSFLOCK 0xf5320002
+
+/*P1_FECM*/
+#define R0900_P1_FECM 0xf533
+#define FECM REGx(R0900_P1_FECM)
+#define F0900_P1_DSS_DVB 0xf5330080
+#define DSS_DVB FLDx(F0900_P1_DSS_DVB)
+#define F0900_P1_DSS_SRCH 0xf5330010
+#define F0900_P1_SYNCVIT 0xf5330002
+#define F0900_P1_IQINV 0xf5330001
+#define IQINV FLDx(F0900_P1_IQINV)
+
+/*P1_VTH12*/
+#define R0900_P1_VTH12 0xf534
+#define VTH12 REGx(R0900_P1_VTH12)
+#define F0900_P1_VTH12 0xf53400ff
+
+/*P1_VTH23*/
+#define R0900_P1_VTH23 0xf535
+#define VTH23 REGx(R0900_P1_VTH23)
+#define F0900_P1_VTH23 0xf53500ff
+
+/*P1_VTH34*/
+#define R0900_P1_VTH34 0xf536
+#define VTH34 REGx(R0900_P1_VTH34)
+#define F0900_P1_VTH34 0xf53600ff
+
+/*P1_VTH56*/
+#define R0900_P1_VTH56 0xf537
+#define VTH56 REGx(R0900_P1_VTH56)
+#define F0900_P1_VTH56 0xf53700ff
+
+/*P1_VTH67*/
+#define R0900_P1_VTH67 0xf538
+#define VTH67 REGx(R0900_P1_VTH67)
+#define F0900_P1_VTH67 0xf53800ff
+
+/*P1_VTH78*/
+#define R0900_P1_VTH78 0xf539
+#define VTH78 REGx(R0900_P1_VTH78)
+#define F0900_P1_VTH78 0xf53900ff
+
+/*P1_VITCURPUN*/
+#define R0900_P1_VITCURPUN 0xf53a
+#define VITCURPUN REGx(R0900_P1_VITCURPUN)
+#define F0900_P1_VIT_CURPUN 0xf53a001f
+#define VIT_CURPUN FLDx(F0900_P1_VIT_CURPUN)
+
+/*P1_VERROR*/
+#define R0900_P1_VERROR 0xf53b
+#define VERROR REGx(R0900_P1_VERROR)
+#define F0900_P1_REGERR_VIT 0xf53b00ff
+
+/*P1_PRVIT*/
+#define R0900_P1_PRVIT 0xf53c
+#define PRVIT REGx(R0900_P1_PRVIT)
+#define F0900_P1_DIS_VTHLOCK 0xf53c0040
+#define F0900_P1_E7_8VIT 0xf53c0020
+#define F0900_P1_E6_7VIT 0xf53c0010
+#define F0900_P1_E5_6VIT 0xf53c0008
+#define F0900_P1_E3_4VIT 0xf53c0004
+#define F0900_P1_E2_3VIT 0xf53c0002
+#define F0900_P1_E1_2VIT 0xf53c0001
+
+/*P1_VAVSRVIT*/
+#define R0900_P1_VAVSRVIT 0xf53d
+#define VAVSRVIT REGx(R0900_P1_VAVSRVIT)
+#define F0900_P1_AMVIT 0xf53d0080
+#define F0900_P1_FROZENVIT 0xf53d0040
+#define F0900_P1_SNVIT 0xf53d0030
+#define F0900_P1_TOVVIT 0xf53d000c
+#define F0900_P1_HYPVIT 0xf53d0003
+
+/*P1_VSTATUSVIT*/
+#define R0900_P1_VSTATUSVIT 0xf53e
+#define VSTATUSVIT REGx(R0900_P1_VSTATUSVIT)
+#define F0900_P1_PRFVIT 0xf53e0010
+#define PRFVIT FLDx(F0900_P1_PRFVIT)
+#define F0900_P1_LOCKEDVIT 0xf53e0008
+#define LOCKEDVIT FLDx(F0900_P1_LOCKEDVIT)
+
+/*P1_VTHINUSE*/
+#define R0900_P1_VTHINUSE 0xf53f
+#define VTHINUSE REGx(R0900_P1_VTHINUSE)
+#define F0900_P1_VIT_INUSE 0xf53f00ff
+
+/*P1_KDIV12*/
+#define R0900_P1_KDIV12 0xf540
+#define KDIV12 REGx(R0900_P1_KDIV12)
+#define F0900_P1_K_DIVIDER_12 0xf540007f
+
+/*P1_KDIV23*/
+#define R0900_P1_KDIV23 0xf541
+#define KDIV23 REGx(R0900_P1_KDIV23)
+#define F0900_P1_K_DIVIDER_23 0xf541007f
+
+/*P1_KDIV34*/
+#define R0900_P1_KDIV34 0xf542
+#define KDIV34 REGx(R0900_P1_KDIV34)
+#define F0900_P1_K_DIVIDER_34 0xf542007f
+
+/*P1_KDIV56*/
+#define R0900_P1_KDIV56 0xf543
+#define KDIV56 REGx(R0900_P1_KDIV56)
+#define F0900_P1_K_DIVIDER_56 0xf543007f
+
+/*P1_KDIV67*/
+#define R0900_P1_KDIV67 0xf544
+#define KDIV67 REGx(R0900_P1_KDIV67)
+#define F0900_P1_K_DIVIDER_67 0xf544007f
+
+/*P1_KDIV78*/
+#define R0900_P1_KDIV78 0xf545
+#define KDIV78 REGx(R0900_P1_KDIV78)
+#define F0900_P1_K_DIVIDER_78 0xf545007f
+
+/*P1_PDELCTRL1*/
+#define R0900_P1_PDELCTRL1 0xf550
+#define PDELCTRL1 REGx(R0900_P1_PDELCTRL1)
+#define F0900_P1_INV_MISMASK 0xf5500080
+#define F0900_P1_FILTER_EN 0xf5500020
+#define F0900_P1_EN_MIS00 0xf5500002
+#define F0900_P1_ALGOSWRST 0xf5500001
+#define ALGOSWRST FLDx(F0900_P1_ALGOSWRST)
+
+/*P1_PDELCTRL2*/
+#define R0900_P1_PDELCTRL2 0xf551
+#define PDELCTRL2 REGx(R0900_P1_PDELCTRL2)
+#define F0900_P1_RESET_UPKO_COUNT 0xf5510040
+#define RESET_UPKO_COUNT FLDx(F0900_P1_RESET_UPKO_COUNT)
+#define F0900_P1_FRAME_MODE 0xf5510002
+#define F0900_P1_NOBCHERRFLG_USE 0xf5510001
+
+/*P1_HYSTTHRESH*/
+#define R0900_P1_HYSTTHRESH 0xf554
+#define HYSTTHRESH REGx(R0900_P1_HYSTTHRESH)
+#define F0900_P1_UNLCK_THRESH 0xf55400f0
+#define F0900_P1_DELIN_LCK_THRESH 0xf554000f
+
+/*P1_ISIENTRY*/
+#define R0900_P1_ISIENTRY 0xf55e
+#define ISIENTRY REGx(R0900_P1_ISIENTRY)
+#define F0900_P1_ISI_ENTRY 0xf55e00ff
+
+/*P1_ISIBITENA*/
+#define R0900_P1_ISIBITENA 0xf55f
+#define ISIBITENA REGx(R0900_P1_ISIBITENA)
+#define F0900_P1_ISI_BIT_EN 0xf55f00ff
+
+/*P1_MATSTR1*/
+#define R0900_P1_MATSTR1 0xf560
+#define MATSTR1 REGx(R0900_P1_MATSTR1)
+#define F0900_P1_MATYPE_CURRENT1 0xf56000ff
+
+/*P1_MATSTR0*/
+#define R0900_P1_MATSTR0 0xf561
+#define MATSTR0 REGx(R0900_P1_MATSTR0)
+#define F0900_P1_MATYPE_CURRENT0 0xf56100ff
+
+/*P1_UPLSTR1*/
+#define R0900_P1_UPLSTR1 0xf562
+#define UPLSTR1 REGx(R0900_P1_UPLSTR1)
+#define F0900_P1_UPL_CURRENT1 0xf56200ff
+
+/*P1_UPLSTR0*/
+#define R0900_P1_UPLSTR0 0xf563
+#define UPLSTR0 REGx(R0900_P1_UPLSTR0)
+#define F0900_P1_UPL_CURRENT0 0xf56300ff
+
+/*P1_DFLSTR1*/
+#define R0900_P1_DFLSTR1 0xf564
+#define DFLSTR1 REGx(R0900_P1_DFLSTR1)
+#define F0900_P1_DFL_CURRENT1 0xf56400ff
+
+/*P1_DFLSTR0*/
+#define R0900_P1_DFLSTR0 0xf565
+#define DFLSTR0 REGx(R0900_P1_DFLSTR0)
+#define F0900_P1_DFL_CURRENT0 0xf56500ff
+
+/*P1_SYNCSTR*/
+#define R0900_P1_SYNCSTR 0xf566
+#define SYNCSTR REGx(R0900_P1_SYNCSTR)
+#define F0900_P1_SYNC_CURRENT 0xf56600ff
+
+/*P1_SYNCDSTR1*/
+#define R0900_P1_SYNCDSTR1 0xf567
+#define SYNCDSTR1 REGx(R0900_P1_SYNCDSTR1)
+#define F0900_P1_SYNCD_CURRENT1 0xf56700ff
+
+/*P1_SYNCDSTR0*/
+#define R0900_P1_SYNCDSTR0 0xf568
+#define SYNCDSTR0 REGx(R0900_P1_SYNCDSTR0)
+#define F0900_P1_SYNCD_CURRENT0 0xf56800ff
+
+/*P1_PDELSTATUS1*/
+#define R0900_P1_PDELSTATUS1 0xf569
+#define F0900_P1_PKTDELIN_DELOCK 0xf5690080
+#define F0900_P1_SYNCDUPDFL_BADDFL 0xf5690040
+#define F0900_P1_CONTINUOUS_STREAM 0xf5690020
+#define F0900_P1_UNACCEPTED_STREAM 0xf5690010
+#define F0900_P1_BCH_ERROR_FLAG 0xf5690008
+#define F0900_P1_PKTDELIN_LOCK 0xf5690002
+#define PKTDELIN_LOCK FLDx(F0900_P1_PKTDELIN_LOCK)
+#define F0900_P1_FIRST_LOCK 0xf5690001
+
+/*P1_PDELSTATUS2*/
+#define R0900_P1_PDELSTATUS2 0xf56a
+#define F0900_P1_FRAME_MODCOD 0xf56a007c
+#define F0900_P1_FRAME_TYPE 0xf56a0003
+
+/*P1_BBFCRCKO1*/
+#define R0900_P1_BBFCRCKO1 0xf56b
+#define BBFCRCKO1 REGx(R0900_P1_BBFCRCKO1)
+#define F0900_P1_BBHCRC_KOCNT1 0xf56b00ff
+
+/*P1_BBFCRCKO0*/
+#define R0900_P1_BBFCRCKO0 0xf56c
+#define BBFCRCKO0 REGx(R0900_P1_BBFCRCKO0)
+#define F0900_P1_BBHCRC_KOCNT0 0xf56c00ff
+
+/*P1_UPCRCKO1*/
+#define R0900_P1_UPCRCKO1 0xf56d
+#define UPCRCKO1 REGx(R0900_P1_UPCRCKO1)
+#define F0900_P1_PKTCRC_KOCNT1 0xf56d00ff
+
+/*P1_UPCRCKO0*/
+#define R0900_P1_UPCRCKO0 0xf56e
+#define UPCRCKO0 REGx(R0900_P1_UPCRCKO0)
+#define F0900_P1_PKTCRC_KOCNT0 0xf56e00ff
+
+/*P1_PDELCTRL3*/
+#define R0900_P1_PDELCTRL3 0xf56f
+#define PDELCTRL3 REGx(R0900_P1_PDELCTRL3)
+#define F0900_P1_PKTDEL_CONTFAIL 0xf56f0080
+#define F0900_P1_NOFIFO_BCHERR 0xf56f0020
+
+/*P1_TSSTATEM*/
+#define R0900_P1_TSSTATEM 0xf570
+#define TSSTATEM REGx(R0900_P1_TSSTATEM)
+#define F0900_P1_TSDIL_ON 0xf5700080
+#define F0900_P1_TSRS_ON 0xf5700020
+#define F0900_P1_TSDESCRAMB_ON 0xf5700010
+#define F0900_P1_TSFRAME_MODE 0xf5700008
+#define F0900_P1_TS_DISABLE 0xf5700004
+#define F0900_P1_TSOUT_NOSYNC 0xf5700001
+
+/*P1_TSCFGH*/
+#define R0900_P1_TSCFGH 0xf572
+#define TSCFGH REGx(R0900_P1_TSCFGH)
+#define F0900_P1_TSFIFO_DVBCI 0xf5720080
+#define F0900_P1_TSFIFO_SERIAL 0xf5720040
+#define F0900_P1_TSFIFO_TEIUPDATE 0xf5720020
+#define F0900_P1_TSFIFO_DUTY50 0xf5720010
+#define F0900_P1_TSFIFO_HSGNLOUT 0xf5720008
+#define F0900_P1_TSFIFO_ERRMODE 0xf5720006
+#define F0900_P1_RST_HWARE 0xf5720001
+#define RST_HWARE FLDx(F0900_P1_RST_HWARE)
+
+/*P1_TSCFGM*/
+#define R0900_P1_TSCFGM 0xf573
+#define TSCFGM REGx(R0900_P1_TSCFGM)
+#define F0900_P1_TSFIFO_MANSPEED 0xf57300c0
+#define F0900_P1_TSFIFO_PERMDATA 0xf5730020
+#define F0900_P1_TSFIFO_DPUNACT 0xf5730002
+#define F0900_P1_TSFIFO_INVDATA 0xf5730001
+
+/*P1_TSCFGL*/
+#define R0900_P1_TSCFGL 0xf574
+#define TSCFGL REGx(R0900_P1_TSCFGL)
+#define F0900_P1_TSFIFO_BCLKDEL1CK 0xf57400c0
+#define F0900_P1_BCHERROR_MODE 0xf5740030
+#define F0900_P1_TSFIFO_NSGNL2DATA 0xf5740008
+#define F0900_P1_TSFIFO_EMBINDVB 0xf5740004
+#define F0900_P1_TSFIFO_BITSPEED 0xf5740003
+
+/*P1_TSINSDELH*/
+#define R0900_P1_TSINSDELH 0xf576
+#define TSINSDELH REGx(R0900_P1_TSINSDELH)
+#define F0900_P1_TSDEL_SYNCBYTE 0xf5760080
+#define F0900_P1_TSDEL_XXHEADER 0xf5760040
+#define F0900_P1_TSDEL_BBHEADER 0xf5760020
+#define F0900_P1_TSDEL_DATAFIELD 0xf5760010
+#define F0900_P1_TSINSDEL_ISCR 0xf5760008
+#define F0900_P1_TSINSDEL_NPD 0xf5760004
+#define F0900_P1_TSINSDEL_RSPARITY 0xf5760002
+#define F0900_P1_TSINSDEL_CRC8 0xf5760001
+
+/*P1_TSDIVN*/
+#define R0900_P1_TSDIVN 0xf579
+#define TSDIVN REGx(R0900_P1_TSDIVN)
+#define F0900_P1_TSFIFO_SPEEDMODE 0xf57900c0
+
+/*P1_TSCFG4*/
+#define R0900_P1_TSCFG4 0xf57a
+#define TSCFG4 REGx(R0900_P1_TSCFG4)
+#define F0900_P1_TSFIFO_TSSPEEDMODE 0xf57a00c0
+
+/*P1_TSSPEED*/
+#define R0900_P1_TSSPEED 0xf580
+#define TSSPEED REGx(R0900_P1_TSSPEED)
+#define F0900_P1_TSFIFO_OUTSPEED 0xf58000ff
+
+/*P1_TSSTATUS*/
+#define R0900_P1_TSSTATUS 0xf581
+#define TSSTATUS REGx(R0900_P1_TSSTATUS)
+#define F0900_P1_TSFIFO_LINEOK 0xf5810080
+#define TSFIFO_LINEOK FLDx(F0900_P1_TSFIFO_LINEOK)
+#define F0900_P1_TSFIFO_ERROR 0xf5810040
+#define F0900_P1_DIL_READY 0xf5810001
+
+/*P1_TSSTATUS2*/
+#define R0900_P1_TSSTATUS2 0xf582
+#define TSSTATUS2 REGx(R0900_P1_TSSTATUS2)
+#define F0900_P1_TSFIFO_DEMODSEL 0xf5820080
+#define F0900_P1_TSFIFOSPEED_STORE 0xf5820040
+#define F0900_P1_DILXX_RESET 0xf5820020
+#define F0900_P1_TSSERIAL_IMPOS 0xf5820010
+#define F0900_P1_SCRAMBDETECT 0xf5820002
+
+/*P1_TSBITRATE1*/
+#define R0900_P1_TSBITRATE1 0xf583
+#define TSBITRATE1 REGx(R0900_P1_TSBITRATE1)
+#define F0900_P1_TSFIFO_BITRATE1 0xf58300ff
+
+/*P1_TSBITRATE0*/
+#define R0900_P1_TSBITRATE0 0xf584
+#define TSBITRATE0 REGx(R0900_P1_TSBITRATE0)
+#define F0900_P1_TSFIFO_BITRATE0 0xf58400ff
+
+/*P1_ERRCTRL1*/
+#define R0900_P1_ERRCTRL1 0xf598
+#define ERRCTRL1 REGx(R0900_P1_ERRCTRL1)
+#define F0900_P1_ERR_SOURCE1 0xf59800f0
+#define F0900_P1_NUM_EVENT1 0xf5980007
+
+/*P1_ERRCNT12*/
+#define R0900_P1_ERRCNT12 0xf599
+#define ERRCNT12 REGx(R0900_P1_ERRCNT12)
+#define F0900_P1_ERRCNT1_OLDVALUE 0xf5990080
+#define F0900_P1_ERR_CNT12 0xf599007f
+#define ERR_CNT12 FLDx(F0900_P1_ERR_CNT12)
+
+/*P1_ERRCNT11*/
+#define R0900_P1_ERRCNT11 0xf59a
+#define ERRCNT11 REGx(R0900_P1_ERRCNT11)
+#define F0900_P1_ERR_CNT11 0xf59a00ff
+#define ERR_CNT11 FLDx(F0900_P1_ERR_CNT11)
+
+/*P1_ERRCNT10*/
+#define R0900_P1_ERRCNT10 0xf59b
+#define ERRCNT10 REGx(R0900_P1_ERRCNT10)
+#define F0900_P1_ERR_CNT10 0xf59b00ff
+#define ERR_CNT10 FLDx(F0900_P1_ERR_CNT10)
+
+/*P1_ERRCTRL2*/
+#define R0900_P1_ERRCTRL2 0xf59c
+#define ERRCTRL2 REGx(R0900_P1_ERRCTRL2)
+#define F0900_P1_ERR_SOURCE2 0xf59c00f0
+#define F0900_P1_NUM_EVENT2 0xf59c0007
+
+/*P1_ERRCNT22*/
+#define R0900_P1_ERRCNT22 0xf59d
+#define ERRCNT22 REGx(R0900_P1_ERRCNT22)
+#define F0900_P1_ERRCNT2_OLDVALUE 0xf59d0080
+#define F0900_P1_ERR_CNT22 0xf59d007f
+#define ERR_CNT22 FLDx(F0900_P1_ERR_CNT22)
+
+/*P1_ERRCNT21*/
+#define R0900_P1_ERRCNT21 0xf59e
+#define ERRCNT21 REGx(R0900_P1_ERRCNT21)
+#define F0900_P1_ERR_CNT21 0xf59e00ff
+#define ERR_CNT21 FLDx(F0900_P1_ERR_CNT21)
+
+/*P1_ERRCNT20*/
+#define R0900_P1_ERRCNT20 0xf59f
+#define ERRCNT20 REGx(R0900_P1_ERRCNT20)
+#define F0900_P1_ERR_CNT20 0xf59f00ff
+#define ERR_CNT20 FLDx(F0900_P1_ERR_CNT20)
+
+/*P1_FECSPY*/
+#define R0900_P1_FECSPY 0xf5a0
+#define FECSPY REGx(R0900_P1_FECSPY)
+#define F0900_P1_SPY_ENABLE 0xf5a00080
+#define F0900_P1_NO_SYNCBYTE 0xf5a00040
+#define F0900_P1_SERIAL_MODE 0xf5a00020
+#define F0900_P1_UNUSUAL_PACKET 0xf5a00010
+#define F0900_P1_BERMETER_DATAMODE 0xf5a00008
+#define F0900_P1_BERMETER_LMODE 0xf5a00002
+#define F0900_P1_BERMETER_RESET 0xf5a00001
+
+/*P1_FSPYCFG*/
+#define R0900_P1_FSPYCFG 0xf5a1
+#define FSPYCFG REGx(R0900_P1_FSPYCFG)
+#define F0900_P1_FECSPY_INPUT 0xf5a100c0
+#define F0900_P1_RST_ON_ERROR 0xf5a10020
+#define F0900_P1_ONE_SHOT 0xf5a10010
+#define F0900_P1_I2C_MODE 0xf5a1000c
+#define F0900_P1_SPY_HYSTERESIS 0xf5a10003
+
+/*P1_FSPYDATA*/
+#define R0900_P1_FSPYDATA 0xf5a2
+#define FSPYDATA REGx(R0900_P1_FSPYDATA)
+#define F0900_P1_SPY_STUFFING 0xf5a20080
+#define F0900_P1_SPY_CNULLPKT 0xf5a20020
+#define F0900_P1_SPY_OUTDATA_MODE 0xf5a2001f
+
+/*P1_FSPYOUT*/
+#define R0900_P1_FSPYOUT 0xf5a3
+#define FSPYOUT REGx(R0900_P1_FSPYOUT)
+#define F0900_P1_FSPY_DIRECT 0xf5a30080
+#define F0900_P1_STUFF_MODE 0xf5a30007
+
+/*P1_FSTATUS*/
+#define R0900_P1_FSTATUS 0xf5a4
+#define FSTATUS REGx(R0900_P1_FSTATUS)
+#define F0900_P1_SPY_ENDSIM 0xf5a40080
+#define F0900_P1_VALID_SIM 0xf5a40040
+#define F0900_P1_FOUND_SIGNAL 0xf5a40020
+#define F0900_P1_DSS_SYNCBYTE 0xf5a40010
+#define F0900_P1_RESULT_STATE 0xf5a4000f
+
+/*P1_FBERCPT4*/
+#define R0900_P1_FBERCPT4 0xf5a8
+#define FBERCPT4 REGx(R0900_P1_FBERCPT4)
+#define F0900_P1_FBERMETER_CPT4 0xf5a800ff
+
+/*P1_FBERCPT3*/
+#define R0900_P1_FBERCPT3 0xf5a9
+#define FBERCPT3 REGx(R0900_P1_FBERCPT3)
+#define F0900_P1_FBERMETER_CPT3 0xf5a900ff
+
+/*P1_FBERCPT2*/
+#define R0900_P1_FBERCPT2 0xf5aa
+#define FBERCPT2 REGx(R0900_P1_FBERCPT2)
+#define F0900_P1_FBERMETER_CPT2 0xf5aa00ff
+
+/*P1_FBERCPT1*/
+#define R0900_P1_FBERCPT1 0xf5ab
+#define FBERCPT1 REGx(R0900_P1_FBERCPT1)
+#define F0900_P1_FBERMETER_CPT1 0xf5ab00ff
+
+/*P1_FBERCPT0*/
+#define R0900_P1_FBERCPT0 0xf5ac
+#define FBERCPT0 REGx(R0900_P1_FBERCPT0)
+#define F0900_P1_FBERMETER_CPT0 0xf5ac00ff
+
+/*P1_FBERERR2*/
+#define R0900_P1_FBERERR2 0xf5ad
+#define FBERERR2 REGx(R0900_P1_FBERERR2)
+#define F0900_P1_FBERMETER_ERR2 0xf5ad00ff
+
+/*P1_FBERERR1*/
+#define R0900_P1_FBERERR1 0xf5ae
+#define FBERERR1 REGx(R0900_P1_FBERERR1)
+#define F0900_P1_FBERMETER_ERR1 0xf5ae00ff
+
+/*P1_FBERERR0*/
+#define R0900_P1_FBERERR0 0xf5af
+#define FBERERR0 REGx(R0900_P1_FBERERR0)
+#define F0900_P1_FBERMETER_ERR0 0xf5af00ff
+
+/*P1_FSPYBER*/
+#define R0900_P1_FSPYBER 0xf5b2
+#define FSPYBER REGx(R0900_P1_FSPYBER)
+#define F0900_P1_FSPYBER_SYNCBYTE 0xf5b20010
+#define F0900_P1_FSPYBER_UNSYNC 0xf5b20008
+#define F0900_P1_FSPYBER_CTIME 0xf5b20007
+
+/*RCCFG2*/
+#define R0900_RCCFG2 0xf600
+
+/*TSGENERAL*/
+#define R0900_TSGENERAL 0xf630
+#define F0900_TSFIFO_DISTS2PAR 0xf6300040
+#define F0900_MUXSTREAM_OUTMODE 0xf6300008
+#define F0900_TSFIFO_PERMPARAL 0xf6300006
+
+/*TSGENERAL1X*/
+#define R0900_TSGENERAL1X 0xf670
+
+/*NBITER_NF4*/
+#define R0900_NBITER_NF4 0xfa03
+#define F0900_NBITER_NF_QP_1_2 0xfa0300ff
+
+/*NBITER_NF5*/
+#define R0900_NBITER_NF5 0xfa04
+#define F0900_NBITER_NF_QP_3_5 0xfa0400ff
+
+/*NBITER_NF6*/
+#define R0900_NBITER_NF6 0xfa05
+#define F0900_NBITER_NF_QP_2_3 0xfa0500ff
+
+/*NBITER_NF7*/
+#define R0900_NBITER_NF7 0xfa06
+#define F0900_NBITER_NF_QP_3_4 0xfa0600ff
+
+/*NBITER_NF8*/
+#define R0900_NBITER_NF8 0xfa07
+#define F0900_NBITER_NF_QP_4_5 0xfa0700ff
+
+/*NBITER_NF9*/
+#define R0900_NBITER_NF9 0xfa08
+#define F0900_NBITER_NF_QP_5_6 0xfa0800ff
+
+/*NBITER_NF10*/
+#define R0900_NBITER_NF10 0xfa09
+#define F0900_NBITER_NF_QP_8_9 0xfa0900ff
+
+/*NBITER_NF11*/
+#define R0900_NBITER_NF11 0xfa0a
+#define F0900_NBITER_NF_QP_9_10 0xfa0a00ff
+
+/*NBITER_NF12*/
+#define R0900_NBITER_NF12 0xfa0b
+#define F0900_NBITER_NF_8P_3_5 0xfa0b00ff
+
+/*NBITER_NF13*/
+#define R0900_NBITER_NF13 0xfa0c
+#define F0900_NBITER_NF_8P_2_3 0xfa0c00ff
+
+/*NBITER_NF14*/
+#define R0900_NBITER_NF14 0xfa0d
+#define F0900_NBITER_NF_8P_3_4 0xfa0d00ff
+
+/*NBITER_NF15*/
+#define R0900_NBITER_NF15 0xfa0e
+#define F0900_NBITER_NF_8P_5_6 0xfa0e00ff
+
+/*NBITER_NF16*/
+#define R0900_NBITER_NF16 0xfa0f
+#define F0900_NBITER_NF_8P_8_9 0xfa0f00ff
+
+/*NBITER_NF17*/
+#define R0900_NBITER_NF17 0xfa10
+#define F0900_NBITER_NF_8P_9_10 0xfa1000ff
+
+/*NBITERNOERR*/
+#define R0900_NBITERNOERR 0xfa3f
+#define F0900_NBITER_STOP_CRIT 0xfa3f000f
+
+/*GAINLLR_NF4*/
+#define R0900_GAINLLR_NF4 0xfa43
+#define F0900_GAINLLR_NF_QP_1_2 0xfa43007f
+
+/*GAINLLR_NF5*/
+#define R0900_GAINLLR_NF5 0xfa44
+#define F0900_GAINLLR_NF_QP_3_5 0xfa44007f
+
+/*GAINLLR_NF6*/
+#define R0900_GAINLLR_NF6 0xfa45
+#define F0900_GAINLLR_NF_QP_2_3 0xfa45007f
+
+/*GAINLLR_NF7*/
+#define R0900_GAINLLR_NF7 0xfa46
+#define F0900_GAINLLR_NF_QP_3_4 0xfa46007f
+
+/*GAINLLR_NF8*/
+#define R0900_GAINLLR_NF8 0xfa47
+#define F0900_GAINLLR_NF_QP_4_5 0xfa47007f
+
+/*GAINLLR_NF9*/
+#define R0900_GAINLLR_NF9 0xfa48
+#define F0900_GAINLLR_NF_QP_5_6 0xfa48007f
+
+/*GAINLLR_NF10*/
+#define R0900_GAINLLR_NF10 0xfa49
+#define F0900_GAINLLR_NF_QP_8_9 0xfa49007f
+
+/*GAINLLR_NF11*/
+#define R0900_GAINLLR_NF11 0xfa4a
+#define F0900_GAINLLR_NF_QP_9_10 0xfa4a007f
+
+/*GAINLLR_NF12*/
+#define R0900_GAINLLR_NF12 0xfa4b
+#define F0900_GAINLLR_NF_8P_3_5 0xfa4b007f
+
+/*GAINLLR_NF13*/
+#define R0900_GAINLLR_NF13 0xfa4c
+#define F0900_GAINLLR_NF_8P_2_3 0xfa4c007f
+
+/*GAINLLR_NF14*/
+#define R0900_GAINLLR_NF14 0xfa4d
+#define F0900_GAINLLR_NF_8P_3_4 0xfa4d007f
+
+/*GAINLLR_NF15*/
+#define R0900_GAINLLR_NF15 0xfa4e
+#define F0900_GAINLLR_NF_8P_5_6 0xfa4e007f
+
+/*GAINLLR_NF16*/
+#define R0900_GAINLLR_NF16 0xfa4f
+#define F0900_GAINLLR_NF_8P_8_9 0xfa4f007f
+
+/*GAINLLR_NF17*/
+#define R0900_GAINLLR_NF17 0xfa50
+#define F0900_GAINLLR_NF_8P_9_10 0xfa50007f
+
+/*CFGEXT*/
+#define R0900_CFGEXT 0xfa80
+#define F0900_STAGMODE 0xfa800080
+#define F0900_BYPBCH 0xfa800040
+#define F0900_BYPLDPC 0xfa800020
+#define F0900_LDPCMODE 0xfa800010
+#define F0900_INVLLRSIGN 0xfa800008
+#define F0900_SHORTMULT 0xfa800004
+#define F0900_EXTERNTX 0xfa800001
+
+/*GENCFG*/
+#define R0900_GENCFG 0xfa86
+#define F0900_BROADCAST 0xfa860010
+#define F0900_PRIORITY 0xfa860002
+#define F0900_DDEMOD 0xfa860001
+
+/*LDPCERR1*/
+#define R0900_LDPCERR1 0xfa96
+#define F0900_LDPC_ERRORS_COUNTER1 0xfa9600ff
+
+/*LDPCERR0*/
+#define R0900_LDPCERR0 0xfa97
+#define F0900_LDPC_ERRORS_COUNTER0 0xfa9700ff
+
+/*BCHERR*/
+#define R0900_BCHERR 0xfa98
+#define F0900_ERRORFLAG 0xfa980010
+#define F0900_BCH_ERRORS_COUNTER 0xfa98000f
+
+/*TSTRES0*/
+#define R0900_TSTRES0 0xff11
+#define F0900_FRESFEC 0xff110080
+
+/*P2_TCTL4*/
+#define R0900_P2_TCTL4 0xff28
+#define F0900_P2_PN4_SELECT 0xff280020
+
+/*P1_TCTL4*/
+#define R0900_P1_TCTL4 0xff48
+#define TCTL4 shiftx(R0900_P1_TCTL4, demod, 0x20)
+#define F0900_P1_PN4_SELECT 0xff480020
+
+/*P2_TSTDISRX*/
+#define R0900_P2_TSTDISRX 0xff65
+#define F0900_P2_PIN_SELECT1 0xff650008
+
+/*P1_TSTDISRX*/
+#define R0900_P1_TSTDISRX 0xff67
+#define TSTDISRX shiftx(R0900_P1_TSTDISRX, demod, 2)
+#define F0900_P1_PIN_SELECT1 0xff670008
+#define PIN_SELECT1 shiftx(F0900_P1_PIN_SELECT1, demod, 0x20000)
+
+#define STV0900_NBREGS 723
+#define STV0900_NBFIELDS 1420
+
+#endif
+
diff --git a/drivers/media/dvb-frontends/stv0900_sw.c b/drivers/media/dvb-frontends/stv0900_sw.c
new file mode 100644
index 0000000..4af2078
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv0900_sw.c
@@ -0,0 +1,2032 @@
+/*
+ * stv0900_sw.c
+ *
+ * Driver for ST STV0900 satellite demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "stv0900.h"
+#include "stv0900_reg.h"
+#include "stv0900_priv.h"
+
+s32 shiftx(s32 x, int demod, s32 shift)
+{
+	if (demod == 1)
+		return x - shift;
+
+	return x;
+}
+
+int stv0900_check_signal_presence(struct stv0900_internal *intp,
+					enum fe_stv0900_demod_num demod)
+{
+	s32	carr_offset,
+		agc2_integr,
+		max_carrier;
+
+	int no_signal = FALSE;
+
+	carr_offset = (stv0900_read_reg(intp, CFR2) << 8)
+					| stv0900_read_reg(intp, CFR1);
+	carr_offset = ge2comp(carr_offset, 16);
+	agc2_integr = (stv0900_read_reg(intp, AGC2I1) << 8)
+					| stv0900_read_reg(intp, AGC2I0);
+	max_carrier = intp->srch_range[demod] / 1000;
+
+	max_carrier += (max_carrier / 10);
+	max_carrier = 65536 * (max_carrier / 2);
+	max_carrier /= intp->mclk / 1000;
+	if (max_carrier > 0x4000)
+		max_carrier = 0x4000;
+
+	if ((agc2_integr > 0x2000)
+			|| (carr_offset > (2 * max_carrier))
+			|| (carr_offset < (-2 * max_carrier)))
+		no_signal = TRUE;
+
+	return no_signal;
+}
+
+static void stv0900_get_sw_loop_params(struct stv0900_internal *intp,
+				s32 *frequency_inc, s32 *sw_timeout,
+				s32 *steps,
+				enum fe_stv0900_demod_num demod)
+{
+	s32 timeout, freq_inc, max_steps, srate, max_carrier;
+
+	enum fe_stv0900_search_standard	standard;
+
+	srate = intp->symbol_rate[demod];
+	max_carrier = intp->srch_range[demod] / 1000;
+	max_carrier += max_carrier / 10;
+	standard = intp->srch_standard[demod];
+
+	max_carrier = 65536 * (max_carrier / 2);
+	max_carrier /= intp->mclk / 1000;
+
+	if (max_carrier > 0x4000)
+		max_carrier = 0x4000;
+
+	freq_inc = srate;
+	freq_inc /= intp->mclk >> 10;
+	freq_inc = freq_inc << 6;
+
+	switch (standard) {
+	case STV0900_SEARCH_DVBS1:
+	case STV0900_SEARCH_DSS:
+		freq_inc *= 3;
+		timeout = 20;
+		break;
+	case STV0900_SEARCH_DVBS2:
+		freq_inc *= 4;
+		timeout = 25;
+		break;
+	case STV0900_AUTO_SEARCH:
+	default:
+		freq_inc *= 3;
+		timeout = 25;
+		break;
+	}
+
+	freq_inc /= 100;
+
+	if ((freq_inc > max_carrier) || (freq_inc < 0))
+		freq_inc = max_carrier / 2;
+
+	timeout *= 27500;
+
+	if (srate > 0)
+		timeout /= srate / 1000;
+
+	if ((timeout > 100) || (timeout < 0))
+		timeout = 100;
+
+	max_steps = (max_carrier / freq_inc) + 1;
+
+	if ((max_steps > 100) || (max_steps < 0)) {
+		max_steps =  100;
+		freq_inc = max_carrier / max_steps;
+	}
+
+	*frequency_inc = freq_inc;
+	*sw_timeout = timeout;
+	*steps = max_steps;
+
+}
+
+static int stv0900_search_carr_sw_loop(struct stv0900_internal *intp,
+				s32 FreqIncr, s32 Timeout, int zigzag,
+				s32 MaxStep, enum fe_stv0900_demod_num demod)
+{
+	int	no_signal,
+		lock = FALSE;
+	s32	stepCpt,
+		freqOffset,
+		max_carrier;
+
+	max_carrier = intp->srch_range[demod] / 1000;
+	max_carrier += (max_carrier / 10);
+
+	max_carrier = 65536 * (max_carrier / 2);
+	max_carrier /= intp->mclk / 1000;
+
+	if (max_carrier > 0x4000)
+		max_carrier = 0x4000;
+
+	if (zigzag == TRUE)
+		freqOffset = 0;
+	else
+		freqOffset = -max_carrier + FreqIncr;
+
+	stepCpt = 0;
+
+	do {
+		stv0900_write_reg(intp, DMDISTATE, 0x1c);
+		stv0900_write_reg(intp, CFRINIT1, (freqOffset / 256) & 0xff);
+		stv0900_write_reg(intp, CFRINIT0, freqOffset & 0xff);
+		stv0900_write_reg(intp, DMDISTATE, 0x18);
+		stv0900_write_bits(intp, ALGOSWRST, 1);
+
+		if (intp->chip_id == 0x12) {
+			stv0900_write_bits(intp, RST_HWARE, 1);
+			stv0900_write_bits(intp, RST_HWARE, 0);
+		}
+
+		if (zigzag == TRUE) {
+			if (freqOffset >= 0)
+				freqOffset = -freqOffset - 2 * FreqIncr;
+			else
+				freqOffset = -freqOffset;
+		} else
+			freqOffset += + 2 * FreqIncr;
+
+		stepCpt++;
+		lock = stv0900_get_demod_lock(intp, demod, Timeout);
+		no_signal = stv0900_check_signal_presence(intp, demod);
+
+	} while ((lock == FALSE)
+			&& (no_signal == FALSE)
+			&& ((freqOffset - FreqIncr) <  max_carrier)
+			&& ((freqOffset + FreqIncr) > -max_carrier)
+			&& (stepCpt < MaxStep));
+
+	stv0900_write_bits(intp, ALGOSWRST, 0);
+
+	return lock;
+}
+
+static int stv0900_sw_algo(struct stv0900_internal *intp,
+				enum fe_stv0900_demod_num demod)
+{
+	int	lock = FALSE,
+		no_signal,
+		zigzag;
+	s32	s2fw,
+		fqc_inc,
+		sft_stp_tout,
+		trial_cntr,
+		max_steps;
+
+	stv0900_get_sw_loop_params(intp, &fqc_inc, &sft_stp_tout,
+					&max_steps, demod);
+	switch (intp->srch_standard[demod]) {
+	case STV0900_SEARCH_DVBS1:
+	case STV0900_SEARCH_DSS:
+		if (intp->chip_id >= 0x20)
+			stv0900_write_reg(intp, CARFREQ, 0x3b);
+		else
+			stv0900_write_reg(intp, CARFREQ, 0xef);
+
+		stv0900_write_reg(intp, DMDCFGMD, 0x49);
+		zigzag = FALSE;
+		break;
+	case STV0900_SEARCH_DVBS2:
+		if (intp->chip_id >= 0x20)
+			stv0900_write_reg(intp, CORRELABS, 0x79);
+		else
+			stv0900_write_reg(intp, CORRELABS, 0x68);
+
+		stv0900_write_reg(intp, DMDCFGMD, 0x89);
+
+		zigzag = TRUE;
+		break;
+	case STV0900_AUTO_SEARCH:
+	default:
+		if (intp->chip_id >= 0x20) {
+			stv0900_write_reg(intp, CARFREQ, 0x3b);
+			stv0900_write_reg(intp, CORRELABS, 0x79);
+		} else {
+			stv0900_write_reg(intp, CARFREQ, 0xef);
+			stv0900_write_reg(intp, CORRELABS, 0x68);
+		}
+
+		stv0900_write_reg(intp, DMDCFGMD, 0xc9);
+		zigzag = FALSE;
+		break;
+	}
+
+	trial_cntr = 0;
+	do {
+		lock = stv0900_search_carr_sw_loop(intp,
+						fqc_inc,
+						sft_stp_tout,
+						zigzag,
+						max_steps,
+						demod);
+		no_signal = stv0900_check_signal_presence(intp, demod);
+		trial_cntr++;
+		if ((lock == TRUE)
+				|| (no_signal == TRUE)
+				|| (trial_cntr == 2)) {
+
+			if (intp->chip_id >= 0x20) {
+				stv0900_write_reg(intp, CARFREQ, 0x49);
+				stv0900_write_reg(intp, CORRELABS, 0x9e);
+			} else {
+				stv0900_write_reg(intp, CARFREQ, 0xed);
+				stv0900_write_reg(intp, CORRELABS, 0x88);
+			}
+
+			if ((stv0900_get_bits(intp, HEADER_MODE) ==
+						STV0900_DVBS2_FOUND) &&
+							(lock == TRUE)) {
+				msleep(sft_stp_tout);
+				s2fw = stv0900_get_bits(intp, FLYWHEEL_CPT);
+
+				if (s2fw < 0xd) {
+					msleep(sft_stp_tout);
+					s2fw = stv0900_get_bits(intp,
+								FLYWHEEL_CPT);
+				}
+
+				if (s2fw < 0xd) {
+					lock = FALSE;
+
+					if (trial_cntr < 2) {
+						if (intp->chip_id >= 0x20)
+							stv0900_write_reg(intp,
+								CORRELABS,
+								0x79);
+						else
+							stv0900_write_reg(intp,
+								CORRELABS,
+								0x68);
+
+						stv0900_write_reg(intp,
+								DMDCFGMD,
+								0x89);
+					}
+				}
+			}
+		}
+
+	} while ((lock == FALSE)
+		&& (trial_cntr < 2)
+		&& (no_signal == FALSE));
+
+	return lock;
+}
+
+static u32 stv0900_get_symbol_rate(struct stv0900_internal *intp,
+					u32 mclk,
+					enum fe_stv0900_demod_num demod)
+{
+	s32	rem1, rem2, intval1, intval2, srate;
+
+	srate = (stv0900_get_bits(intp, SYMB_FREQ3) << 24) +
+		(stv0900_get_bits(intp, SYMB_FREQ2) << 16) +
+		(stv0900_get_bits(intp, SYMB_FREQ1) << 8) +
+		(stv0900_get_bits(intp, SYMB_FREQ0));
+	dprintk("lock: srate=%d r0=0x%x r1=0x%x r2=0x%x r3=0x%x \n",
+		srate, stv0900_get_bits(intp, SYMB_FREQ0),
+		stv0900_get_bits(intp, SYMB_FREQ1),
+		stv0900_get_bits(intp, SYMB_FREQ2),
+		stv0900_get_bits(intp, SYMB_FREQ3));
+
+	intval1 = (mclk) >> 16;
+	intval2 = (srate) >> 16;
+
+	rem1 = (mclk) % 0x10000;
+	rem2 = (srate) % 0x10000;
+	srate =	(intval1 * intval2) +
+		((intval1 * rem2) >> 16) +
+		((intval2 * rem1) >> 16);
+
+	return srate;
+}
+
+static void stv0900_set_symbol_rate(struct stv0900_internal *intp,
+					u32 mclk, u32 srate,
+					enum fe_stv0900_demod_num demod)
+{
+	u32 symb;
+
+	dprintk("%s: Mclk %d, SR %d, Dmd %d\n", __func__, mclk,
+							srate, demod);
+
+	if (srate > 60000000) {
+		symb = srate << 4;
+		symb /= (mclk >> 12);
+	} else if (srate > 6000000) {
+		symb = srate << 6;
+		symb /= (mclk >> 10);
+	} else {
+		symb = srate << 9;
+		symb /= (mclk >> 7);
+	}
+
+	stv0900_write_reg(intp, SFRINIT1, (symb >> 8) & 0x7f);
+	stv0900_write_reg(intp, SFRINIT1 + 1, (symb & 0xff));
+}
+
+static void stv0900_set_max_symbol_rate(struct stv0900_internal *intp,
+					u32 mclk, u32 srate,
+					enum fe_stv0900_demod_num demod)
+{
+	u32 symb;
+
+	srate = 105 * (srate / 100);
+
+	if (srate > 60000000) {
+		symb = srate << 4;
+		symb /= (mclk >> 12);
+	} else if (srate > 6000000) {
+		symb = srate << 6;
+		symb /= (mclk >> 10);
+	} else {
+		symb = srate << 9;
+		symb /= (mclk >> 7);
+	}
+
+	if (symb < 0x7fff) {
+		stv0900_write_reg(intp, SFRUP1, (symb >> 8) & 0x7f);
+		stv0900_write_reg(intp, SFRUP1 + 1, (symb & 0xff));
+	} else {
+		stv0900_write_reg(intp, SFRUP1, 0x7f);
+		stv0900_write_reg(intp, SFRUP1 + 1, 0xff);
+	}
+}
+
+static void stv0900_set_min_symbol_rate(struct stv0900_internal *intp,
+					u32 mclk, u32 srate,
+					enum fe_stv0900_demod_num demod)
+{
+	u32	symb;
+
+	srate = 95 * (srate / 100);
+	if (srate > 60000000) {
+		symb = srate << 4;
+		symb /= (mclk >> 12);
+
+	} else if (srate > 6000000) {
+		symb = srate << 6;
+		symb /= (mclk >> 10);
+
+	} else {
+		symb = srate << 9;
+		symb /= (mclk >> 7);
+	}
+
+	stv0900_write_reg(intp, SFRLOW1, (symb >> 8) & 0xff);
+	stv0900_write_reg(intp, SFRLOW1 + 1, (symb & 0xff));
+}
+
+static s32 stv0900_get_timing_offst(struct stv0900_internal *intp,
+					u32 srate,
+					enum fe_stv0900_demod_num demod)
+{
+	s32 timingoffset;
+
+
+	timingoffset = (stv0900_read_reg(intp, TMGREG2) << 16) +
+		       (stv0900_read_reg(intp, TMGREG2 + 1) << 8) +
+		       (stv0900_read_reg(intp, TMGREG2 + 2));
+
+	timingoffset = ge2comp(timingoffset, 24);
+
+
+	if (timingoffset == 0)
+		timingoffset = 1;
+
+	timingoffset = ((s32)srate * 10) / ((s32)0x1000000 / timingoffset);
+	timingoffset /= 320;
+
+	return timingoffset;
+}
+
+static void stv0900_set_dvbs2_rolloff(struct stv0900_internal *intp,
+					enum fe_stv0900_demod_num demod)
+{
+	s32 rolloff;
+
+	if (intp->chip_id == 0x10) {
+		stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1);
+		rolloff = stv0900_read_reg(intp, MATSTR1) & 0x03;
+		stv0900_write_bits(intp, ROLLOFF_CONTROL, rolloff);
+	} else if (intp->chip_id <= 0x20)
+		stv0900_write_bits(intp, MANUALSX_ROLLOFF, 0);
+	else /* cut 3.0 */
+		stv0900_write_bits(intp, MANUALS2_ROLLOFF, 0);
+}
+
+static u32 stv0900_carrier_width(u32 srate, enum fe_stv0900_rolloff ro)
+{
+	u32 rolloff;
+
+	switch (ro) {
+	case STV0900_20:
+		rolloff = 20;
+		break;
+	case STV0900_25:
+		rolloff = 25;
+		break;
+	case STV0900_35:
+	default:
+		rolloff = 35;
+		break;
+	}
+
+	return srate  + (srate * rolloff) / 100;
+}
+
+static int stv0900_check_timing_lock(struct stv0900_internal *intp,
+				enum fe_stv0900_demod_num demod)
+{
+	int timingLock = FALSE;
+	s32	i,
+		timingcpt = 0;
+	u8	car_freq,
+		tmg_th_high,
+		tmg_th_low;
+
+	car_freq = stv0900_read_reg(intp, CARFREQ);
+	tmg_th_high = stv0900_read_reg(intp, TMGTHRISE);
+	tmg_th_low = stv0900_read_reg(intp, TMGTHFALL);
+	stv0900_write_reg(intp, TMGTHRISE, 0x20);
+	stv0900_write_reg(intp, TMGTHFALL, 0x0);
+	stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
+	stv0900_write_reg(intp, RTC, 0x80);
+	stv0900_write_reg(intp, RTCS2, 0x40);
+	stv0900_write_reg(intp, CARFREQ, 0x0);
+	stv0900_write_reg(intp, CFRINIT1, 0x0);
+	stv0900_write_reg(intp, CFRINIT0, 0x0);
+	stv0900_write_reg(intp, AGC2REF, 0x65);
+	stv0900_write_reg(intp, DMDISTATE, 0x18);
+	msleep(7);
+
+	for (i = 0; i < 10; i++) {
+		if (stv0900_get_bits(intp, TMGLOCK_QUALITY) >= 2)
+			timingcpt++;
+
+		msleep(1);
+	}
+
+	if (timingcpt >= 3)
+		timingLock = TRUE;
+
+	stv0900_write_reg(intp, AGC2REF, 0x38);
+	stv0900_write_reg(intp, RTC, 0x88);
+	stv0900_write_reg(intp, RTCS2, 0x68);
+	stv0900_write_reg(intp, CARFREQ, car_freq);
+	stv0900_write_reg(intp, TMGTHRISE, tmg_th_high);
+	stv0900_write_reg(intp, TMGTHFALL, tmg_th_low);
+
+	return	timingLock;
+}
+
+static int stv0900_get_demod_cold_lock(struct dvb_frontend *fe,
+					s32 demod_timeout)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+	int	lock = FALSE,
+		d = demod;
+	s32	srate,
+		search_range,
+		locktimeout,
+		currier_step,
+		nb_steps,
+		current_step,
+		direction,
+		tuner_freq,
+		timeout,
+		freq;
+
+	srate = intp->symbol_rate[d];
+	search_range = intp->srch_range[d];
+
+	if (srate >= 10000000)
+		locktimeout = demod_timeout / 3;
+	else
+		locktimeout = demod_timeout / 2;
+
+	lock = stv0900_get_demod_lock(intp, d, locktimeout);
+
+	if (lock != FALSE)
+		return lock;
+
+	if (srate >= 10000000) {
+		if (stv0900_check_timing_lock(intp, d) == TRUE) {
+			stv0900_write_reg(intp, DMDISTATE, 0x1f);
+			stv0900_write_reg(intp, DMDISTATE, 0x15);
+			lock = stv0900_get_demod_lock(intp, d, demod_timeout);
+		} else
+			lock = FALSE;
+
+		return lock;
+	}
+
+	if (intp->chip_id <= 0x20) {
+		if (srate <= 1000000)
+			currier_step = 500;
+		else if (srate <= 4000000)
+			currier_step = 1000;
+		else if (srate <= 7000000)
+			currier_step = 2000;
+		else if (srate <= 10000000)
+			currier_step = 3000;
+		else
+			currier_step = 5000;
+
+		if (srate >= 2000000) {
+			timeout = (demod_timeout / 3);
+			if (timeout > 1000)
+				timeout = 1000;
+		} else
+			timeout = (demod_timeout / 2);
+	} else {
+		/*cut 3.0 */
+		currier_step = srate / 4000;
+		timeout = (demod_timeout * 3) / 4;
+	}
+
+	nb_steps = ((search_range / 1000) / currier_step);
+
+	if ((nb_steps % 2) != 0)
+		nb_steps += 1;
+
+	if (nb_steps <= 0)
+		nb_steps = 2;
+	else if (nb_steps > 12)
+		nb_steps = 12;
+
+	current_step = 1;
+	direction = 1;
+
+	if (intp->chip_id <= 0x20) {
+		tuner_freq = intp->freq[d];
+		intp->bw[d] = stv0900_carrier_width(intp->symbol_rate[d],
+				intp->rolloff) + intp->symbol_rate[d];
+	} else
+		tuner_freq = 0;
+
+	while ((current_step <= nb_steps) && (lock == FALSE)) {
+		if (direction > 0)
+			tuner_freq += (current_step * currier_step);
+		else
+			tuner_freq -= (current_step * currier_step);
+
+		if (intp->chip_id <= 0x20) {
+			if (intp->tuner_type[d] == 3)
+				stv0900_set_tuner_auto(intp, tuner_freq,
+						intp->bw[d], demod);
+			else
+				stv0900_set_tuner(fe, tuner_freq, intp->bw[d]);
+
+			stv0900_write_reg(intp, DMDISTATE, 0x1c);
+			stv0900_write_reg(intp, CFRINIT1, 0);
+			stv0900_write_reg(intp, CFRINIT0, 0);
+			stv0900_write_reg(intp, DMDISTATE, 0x1f);
+			stv0900_write_reg(intp, DMDISTATE, 0x15);
+		} else {
+			stv0900_write_reg(intp, DMDISTATE, 0x1c);
+			freq = (tuner_freq * 65536) / (intp->mclk / 1000);
+			stv0900_write_bits(intp, CFR_INIT1, MSB(freq));
+			stv0900_write_bits(intp, CFR_INIT0, LSB(freq));
+			stv0900_write_reg(intp, DMDISTATE, 0x1f);
+			stv0900_write_reg(intp, DMDISTATE, 0x05);
+		}
+
+		lock = stv0900_get_demod_lock(intp, d, timeout);
+		direction *= -1;
+		current_step++;
+	}
+
+	return	lock;
+}
+
+static void stv0900_get_lock_timeout(s32 *demod_timeout, s32 *fec_timeout,
+					s32 srate,
+					enum fe_stv0900_search_algo algo)
+{
+	switch (algo) {
+	case STV0900_BLIND_SEARCH:
+		if (srate <= 1500000) {
+			(*demod_timeout) = 1500;
+			(*fec_timeout) = 400;
+		} else if (srate <= 5000000) {
+			(*demod_timeout) = 1000;
+			(*fec_timeout) = 300;
+		} else {
+			(*demod_timeout) = 700;
+			(*fec_timeout) = 100;
+		}
+
+		break;
+	case STV0900_COLD_START:
+	case STV0900_WARM_START:
+	default:
+		if (srate <= 1000000) {
+			(*demod_timeout) = 3000;
+			(*fec_timeout) = 1700;
+		} else if (srate <= 2000000) {
+			(*demod_timeout) = 2500;
+			(*fec_timeout) = 1100;
+		} else if (srate <= 5000000) {
+			(*demod_timeout) = 1000;
+			(*fec_timeout) = 550;
+		} else if (srate <= 10000000) {
+			(*demod_timeout) = 700;
+			(*fec_timeout) = 250;
+		} else if (srate <= 20000000) {
+			(*demod_timeout) = 400;
+			(*fec_timeout) = 130;
+		} else {
+			(*demod_timeout) = 300;
+			(*fec_timeout) = 100;
+		}
+
+		break;
+
+	}
+
+	if (algo == STV0900_WARM_START)
+		(*demod_timeout) /= 2;
+}
+
+static void stv0900_set_viterbi_tracq(struct stv0900_internal *intp,
+					enum fe_stv0900_demod_num demod)
+{
+
+	s32 vth_reg = VTH12;
+
+	dprintk("%s\n", __func__);
+
+	stv0900_write_reg(intp, vth_reg++, 0xd0);
+	stv0900_write_reg(intp, vth_reg++, 0x7d);
+	stv0900_write_reg(intp, vth_reg++, 0x53);
+	stv0900_write_reg(intp, vth_reg++, 0x2f);
+	stv0900_write_reg(intp, vth_reg++, 0x24);
+	stv0900_write_reg(intp, vth_reg++, 0x1f);
+}
+
+static void stv0900_set_viterbi_standard(struct stv0900_internal *intp,
+				   enum fe_stv0900_search_standard standard,
+				   enum fe_stv0900_fec fec,
+				   enum fe_stv0900_demod_num demod)
+{
+	dprintk("%s: ViterbiStandard = ", __func__);
+
+	switch (standard) {
+	case STV0900_AUTO_SEARCH:
+		dprintk("Auto\n");
+		stv0900_write_reg(intp, FECM, 0x10);
+		stv0900_write_reg(intp, PRVIT, 0x3f);
+		break;
+	case STV0900_SEARCH_DVBS1:
+		dprintk("DVBS1\n");
+		stv0900_write_reg(intp, FECM, 0x00);
+		switch (fec) {
+		case STV0900_FEC_UNKNOWN:
+		default:
+			stv0900_write_reg(intp, PRVIT, 0x2f);
+			break;
+		case STV0900_FEC_1_2:
+			stv0900_write_reg(intp, PRVIT, 0x01);
+			break;
+		case STV0900_FEC_2_3:
+			stv0900_write_reg(intp, PRVIT, 0x02);
+			break;
+		case STV0900_FEC_3_4:
+			stv0900_write_reg(intp, PRVIT, 0x04);
+			break;
+		case STV0900_FEC_5_6:
+			stv0900_write_reg(intp, PRVIT, 0x08);
+			break;
+		case STV0900_FEC_7_8:
+			stv0900_write_reg(intp, PRVIT, 0x20);
+			break;
+		}
+
+		break;
+	case STV0900_SEARCH_DSS:
+		dprintk("DSS\n");
+		stv0900_write_reg(intp, FECM, 0x80);
+		switch (fec) {
+		case STV0900_FEC_UNKNOWN:
+		default:
+			stv0900_write_reg(intp, PRVIT, 0x13);
+			break;
+		case STV0900_FEC_1_2:
+			stv0900_write_reg(intp, PRVIT, 0x01);
+			break;
+		case STV0900_FEC_2_3:
+			stv0900_write_reg(intp, PRVIT, 0x02);
+			break;
+		case STV0900_FEC_6_7:
+			stv0900_write_reg(intp, PRVIT, 0x10);
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static enum fe_stv0900_fec stv0900_get_vit_fec(struct stv0900_internal *intp,
+						enum fe_stv0900_demod_num demod)
+{
+	enum fe_stv0900_fec prate;
+	s32 rate_fld = stv0900_get_bits(intp, VIT_CURPUN);
+
+	switch (rate_fld) {
+	case 13:
+		prate = STV0900_FEC_1_2;
+		break;
+	case 18:
+		prate = STV0900_FEC_2_3;
+		break;
+	case 21:
+		prate = STV0900_FEC_3_4;
+		break;
+	case 24:
+		prate = STV0900_FEC_5_6;
+		break;
+	case 25:
+		prate = STV0900_FEC_6_7;
+		break;
+	case 26:
+		prate = STV0900_FEC_7_8;
+		break;
+	default:
+		prate = STV0900_FEC_UNKNOWN;
+		break;
+	}
+
+	return prate;
+}
+
+static void stv0900_set_dvbs1_track_car_loop(struct stv0900_internal *intp,
+					enum fe_stv0900_demod_num demod,
+					u32 srate)
+{
+	if (intp->chip_id >= 0x30) {
+		if (srate >= 15000000) {
+			stv0900_write_reg(intp, ACLC, 0x2b);
+			stv0900_write_reg(intp, BCLC, 0x1a);
+		} else if ((srate >= 7000000) && (15000000 > srate)) {
+			stv0900_write_reg(intp, ACLC, 0x0c);
+			stv0900_write_reg(intp, BCLC, 0x1b);
+		} else if (srate < 7000000) {
+			stv0900_write_reg(intp, ACLC, 0x2c);
+			stv0900_write_reg(intp, BCLC, 0x1c);
+		}
+
+	} else { /*cut 2.0 and 1.x*/
+		stv0900_write_reg(intp, ACLC, 0x1a);
+		stv0900_write_reg(intp, BCLC, 0x09);
+	}
+
+}
+
+static void stv0900_track_optimization(struct dvb_frontend *fe)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+
+	s32	srate,
+		pilots,
+		aclc,
+		freq1,
+		freq0,
+		i = 0,
+		timed,
+		timef,
+		blind_tun_sw = 0,
+		modulation;
+
+	enum fe_stv0900_modcode foundModcod;
+
+	dprintk("%s\n", __func__);
+
+	srate = stv0900_get_symbol_rate(intp, intp->mclk, demod);
+	srate += stv0900_get_timing_offst(intp, srate, demod);
+
+	switch (intp->result[demod].standard) {
+	case STV0900_DVBS1_STANDARD:
+	case STV0900_DSS_STANDARD:
+		dprintk("%s: found DVB-S or DSS\n", __func__);
+		if (intp->srch_standard[demod] == STV0900_AUTO_SEARCH) {
+			stv0900_write_bits(intp, DVBS1_ENABLE, 1);
+			stv0900_write_bits(intp, DVBS2_ENABLE, 0);
+		}
+
+		stv0900_write_bits(intp, ROLLOFF_CONTROL, intp->rolloff);
+		stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1);
+
+		if (intp->chip_id < 0x30) {
+			stv0900_write_reg(intp, ERRCTRL1, 0x75);
+			break;
+		}
+
+		if (stv0900_get_vit_fec(intp, demod) == STV0900_FEC_1_2) {
+			stv0900_write_reg(intp, GAUSSR0, 0x98);
+			stv0900_write_reg(intp, CCIR0, 0x18);
+		} else {
+			stv0900_write_reg(intp, GAUSSR0, 0x18);
+			stv0900_write_reg(intp, CCIR0, 0x18);
+		}
+
+		stv0900_write_reg(intp, ERRCTRL1, 0x75);
+		break;
+	case STV0900_DVBS2_STANDARD:
+		dprintk("%s: found DVB-S2\n", __func__);
+		stv0900_write_bits(intp, DVBS1_ENABLE, 0);
+		stv0900_write_bits(intp, DVBS2_ENABLE, 1);
+		stv0900_write_reg(intp, ACLC, 0);
+		stv0900_write_reg(intp, BCLC, 0);
+		if (intp->result[demod].frame_len == STV0900_LONG_FRAME) {
+			foundModcod = stv0900_get_bits(intp, DEMOD_MODCOD);
+			pilots = stv0900_get_bits(intp, DEMOD_TYPE) & 0x01;
+			aclc = stv0900_get_optim_carr_loop(srate,
+							foundModcod,
+							pilots,
+							intp->chip_id);
+			if (foundModcod <= STV0900_QPSK_910)
+				stv0900_write_reg(intp, ACLC2S2Q, aclc);
+			else if (foundModcod <= STV0900_8PSK_910) {
+				stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
+				stv0900_write_reg(intp, ACLC2S28, aclc);
+			}
+
+			if ((intp->demod_mode == STV0900_SINGLE) &&
+					(foundModcod > STV0900_8PSK_910)) {
+				if (foundModcod <= STV0900_16APSK_910) {
+					stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
+					stv0900_write_reg(intp, ACLC2S216A,
+									aclc);
+				} else if (foundModcod <= STV0900_32APSK_910) {
+					stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
+					stv0900_write_reg(intp,	ACLC2S232A,
+									aclc);
+				}
+			}
+
+		} else {
+			modulation = intp->result[demod].modulation;
+			aclc = stv0900_get_optim_short_carr_loop(srate,
+					modulation, intp->chip_id);
+			if (modulation == STV0900_QPSK)
+				stv0900_write_reg(intp, ACLC2S2Q, aclc);
+			else if (modulation == STV0900_8PSK) {
+				stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
+				stv0900_write_reg(intp, ACLC2S28, aclc);
+			} else if (modulation == STV0900_16APSK) {
+				stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
+				stv0900_write_reg(intp, ACLC2S216A, aclc);
+			} else if (modulation == STV0900_32APSK) {
+				stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
+				stv0900_write_reg(intp, ACLC2S232A, aclc);
+			}
+
+		}
+
+		if (intp->chip_id <= 0x11) {
+			if (intp->demod_mode != STV0900_SINGLE)
+				stv0900_activate_s2_modcod(intp, demod);
+
+		}
+
+		stv0900_write_reg(intp, ERRCTRL1, 0x67);
+		break;
+	case STV0900_UNKNOWN_STANDARD:
+	default:
+		dprintk("%s: found unknown standard\n", __func__);
+		stv0900_write_bits(intp, DVBS1_ENABLE, 1);
+		stv0900_write_bits(intp, DVBS2_ENABLE, 1);
+		break;
+	}
+
+	freq1 = stv0900_read_reg(intp, CFR2);
+	freq0 = stv0900_read_reg(intp, CFR1);
+	if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) {
+		stv0900_write_reg(intp, SFRSTEP, 0x00);
+		stv0900_write_bits(intp, SCAN_ENABLE, 0);
+		stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
+		stv0900_write_reg(intp, TMGCFG2, 0xc1);
+		stv0900_set_symbol_rate(intp, intp->mclk, srate, demod);
+		blind_tun_sw = 1;
+		if (intp->result[demod].standard != STV0900_DVBS2_STANDARD)
+			stv0900_set_dvbs1_track_car_loop(intp, demod, srate);
+
+	}
+
+	if (intp->chip_id >= 0x20) {
+		if ((intp->srch_standard[demod] == STV0900_SEARCH_DVBS1) ||
+				(intp->srch_standard[demod] ==
+							STV0900_SEARCH_DSS) ||
+				(intp->srch_standard[demod] ==
+							STV0900_AUTO_SEARCH)) {
+			stv0900_write_reg(intp, VAVSRVIT, 0x0a);
+			stv0900_write_reg(intp, VITSCALE, 0x0);
+		}
+	}
+
+	if (intp->chip_id < 0x20)
+		stv0900_write_reg(intp, CARHDR, 0x08);
+
+	if (intp->chip_id == 0x10)
+		stv0900_write_reg(intp, CORRELEXP, 0x0a);
+
+	stv0900_write_reg(intp, AGC2REF, 0x38);
+
+	if ((intp->chip_id >= 0x20) ||
+			(blind_tun_sw == 1) ||
+			(intp->symbol_rate[demod] < 10000000)) {
+		stv0900_write_reg(intp, CFRINIT1, freq1);
+		stv0900_write_reg(intp, CFRINIT0, freq0);
+		intp->bw[demod] = stv0900_carrier_width(srate,
+					intp->rolloff) + 10000000;
+
+		if ((intp->chip_id >= 0x20) || (blind_tun_sw == 1)) {
+			if (intp->srch_algo[demod] != STV0900_WARM_START) {
+				if (intp->tuner_type[demod] == 3)
+					stv0900_set_tuner_auto(intp,
+							intp->freq[demod],
+							intp->bw[demod],
+							demod);
+				else
+					stv0900_set_bandwidth(fe,
+							intp->bw[demod]);
+			}
+		}
+
+		if ((intp->srch_algo[demod] == STV0900_BLIND_SEARCH) ||
+				(intp->symbol_rate[demod] < 10000000))
+			msleep(50);
+		else
+			msleep(5);
+
+		stv0900_get_lock_timeout(&timed, &timef, srate,
+						STV0900_WARM_START);
+
+		if (stv0900_get_demod_lock(intp, demod, timed / 2) == FALSE) {
+			stv0900_write_reg(intp, DMDISTATE, 0x1f);
+			stv0900_write_reg(intp, CFRINIT1, freq1);
+			stv0900_write_reg(intp, CFRINIT0, freq0);
+			stv0900_write_reg(intp, DMDISTATE, 0x18);
+			i = 0;
+			while ((stv0900_get_demod_lock(intp,
+							demod,
+							timed / 2) == FALSE) &&
+						(i <= 2)) {
+				stv0900_write_reg(intp, DMDISTATE, 0x1f);
+				stv0900_write_reg(intp, CFRINIT1, freq1);
+				stv0900_write_reg(intp, CFRINIT0, freq0);
+				stv0900_write_reg(intp, DMDISTATE, 0x18);
+				i++;
+			}
+		}
+
+	}
+
+	if (intp->chip_id >= 0x20)
+		stv0900_write_reg(intp, CARFREQ, 0x49);
+
+	if ((intp->result[demod].standard == STV0900_DVBS1_STANDARD) ||
+			(intp->result[demod].standard == STV0900_DSS_STANDARD))
+		stv0900_set_viterbi_tracq(intp, demod);
+
+}
+
+static int stv0900_get_fec_lock(struct stv0900_internal *intp,
+				enum fe_stv0900_demod_num demod, s32 time_out)
+{
+	s32 timer = 0, lock = 0;
+
+	enum fe_stv0900_search_state dmd_state;
+
+	dprintk("%s\n", __func__);
+
+	dmd_state = stv0900_get_bits(intp, HEADER_MODE);
+
+	while ((timer < time_out) && (lock == 0)) {
+		switch (dmd_state) {
+		case STV0900_SEARCH:
+		case STV0900_PLH_DETECTED:
+		default:
+			lock = 0;
+			break;
+		case STV0900_DVBS2_FOUND:
+			lock = stv0900_get_bits(intp, PKTDELIN_LOCK);
+			break;
+		case STV0900_DVBS_FOUND:
+			lock = stv0900_get_bits(intp, LOCKEDVIT);
+			break;
+		}
+
+		if (lock == 0) {
+			msleep(10);
+			timer += 10;
+		}
+	}
+
+	if (lock)
+		dprintk("%s: DEMOD FEC LOCK OK\n", __func__);
+	else
+		dprintk("%s: DEMOD FEC LOCK FAIL\n", __func__);
+
+	return lock;
+}
+
+static int stv0900_wait_for_lock(struct stv0900_internal *intp,
+				enum fe_stv0900_demod_num demod,
+				s32 dmd_timeout, s32 fec_timeout)
+{
+
+	s32 timer = 0, lock = 0;
+
+	dprintk("%s\n", __func__);
+
+	lock = stv0900_get_demod_lock(intp, demod, dmd_timeout);
+
+	if (lock)
+		lock = lock && stv0900_get_fec_lock(intp, demod, fec_timeout);
+
+	if (lock) {
+		lock = 0;
+
+		dprintk("%s: Timer = %d, time_out = %d\n",
+				__func__, timer, fec_timeout);
+
+		while ((timer < fec_timeout) && (lock == 0)) {
+			lock = stv0900_get_bits(intp, TSFIFO_LINEOK);
+			msleep(1);
+			timer++;
+		}
+	}
+
+	if (lock)
+		dprintk("%s: DEMOD LOCK OK\n", __func__);
+	else
+		dprintk("%s: DEMOD LOCK FAIL\n", __func__);
+
+	if (lock)
+		return TRUE;
+	else
+		return FALSE;
+}
+
+enum fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe,
+						enum fe_stv0900_demod_num demod)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_tracking_standard fnd_standard;
+
+	int hdr_mode = stv0900_get_bits(intp, HEADER_MODE);
+
+	switch (hdr_mode) {
+	case 2:
+		fnd_standard = STV0900_DVBS2_STANDARD;
+		break;
+	case 3:
+		if (stv0900_get_bits(intp, DSS_DVB) == 1)
+			fnd_standard = STV0900_DSS_STANDARD;
+		else
+			fnd_standard = STV0900_DVBS1_STANDARD;
+
+		break;
+	default:
+		fnd_standard = STV0900_UNKNOWN_STANDARD;
+	}
+
+	dprintk("%s: standard %d\n", __func__, fnd_standard);
+
+	return fnd_standard;
+}
+
+static s32 stv0900_get_carr_freq(struct stv0900_internal *intp, u32 mclk,
+					enum fe_stv0900_demod_num demod)
+{
+	s32	derot,
+		rem1,
+		rem2,
+		intval1,
+		intval2;
+
+	derot = (stv0900_get_bits(intp, CAR_FREQ2) << 16) +
+		(stv0900_get_bits(intp, CAR_FREQ1) << 8) +
+		(stv0900_get_bits(intp, CAR_FREQ0));
+
+	derot = ge2comp(derot, 24);
+	intval1 = mclk >> 12;
+	intval2 = derot >> 12;
+	rem1 = mclk % 0x1000;
+	rem2 = derot % 0x1000;
+	derot = (intval1 * intval2) +
+		((intval1 * rem2) >> 12) +
+		((intval2 * rem1) >> 12);
+
+	return derot;
+}
+
+static u32 stv0900_get_tuner_freq(struct dvb_frontend *fe)
+{
+	struct dvb_frontend_ops	*frontend_ops = NULL;
+	struct dvb_tuner_ops *tuner_ops = NULL;
+	u32 freq = 0;
+
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+
+	if (tuner_ops->get_frequency) {
+		if ((tuner_ops->get_frequency(fe, &freq)) < 0)
+			dprintk("%s: Invalid parameter\n", __func__);
+		else
+			dprintk("%s: Frequency=%d\n", __func__, freq);
+
+	}
+
+	return freq;
+}
+
+static enum
+fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+	enum fe_stv0900_signal_type range = STV0900_OUTOFRANGE;
+	struct stv0900_signal_info *result = &intp->result[demod];
+	s32	offsetFreq,
+		srate_offset;
+	int	i = 0,
+		d = demod;
+
+	u8 timing;
+
+	msleep(5);
+	if (intp->srch_algo[d] == STV0900_BLIND_SEARCH) {
+		timing = stv0900_read_reg(intp, TMGREG2);
+		i = 0;
+		stv0900_write_reg(intp, SFRSTEP, 0x5c);
+
+		while ((i <= 50) && (timing != 0) && (timing != 0xff)) {
+			timing = stv0900_read_reg(intp, TMGREG2);
+			msleep(5);
+			i += 5;
+		}
+	}
+
+	result->standard = stv0900_get_standard(fe, d);
+	if (intp->tuner_type[demod] == 3)
+		result->frequency = stv0900_get_freq_auto(intp, d);
+	else
+		result->frequency = stv0900_get_tuner_freq(fe);
+
+	offsetFreq = stv0900_get_carr_freq(intp, intp->mclk, d) / 1000;
+	result->frequency += offsetFreq;
+	result->symbol_rate = stv0900_get_symbol_rate(intp, intp->mclk, d);
+	srate_offset = stv0900_get_timing_offst(intp, result->symbol_rate, d);
+	result->symbol_rate += srate_offset;
+	result->fec = stv0900_get_vit_fec(intp, d);
+	result->modcode = stv0900_get_bits(intp, DEMOD_MODCOD);
+	result->pilot = stv0900_get_bits(intp, DEMOD_TYPE) & 0x01;
+	result->frame_len = ((u32)stv0900_get_bits(intp, DEMOD_TYPE)) >> 1;
+	result->rolloff = stv0900_get_bits(intp, ROLLOFF_STATUS);
+
+	dprintk("%s: modcode=0x%x \n", __func__, result->modcode);
+
+	switch (result->standard) {
+	case STV0900_DVBS2_STANDARD:
+		result->spectrum = stv0900_get_bits(intp, SPECINV_DEMOD);
+		if (result->modcode <= STV0900_QPSK_910)
+			result->modulation = STV0900_QPSK;
+		else if (result->modcode <= STV0900_8PSK_910)
+			result->modulation = STV0900_8PSK;
+		else if (result->modcode <= STV0900_16APSK_910)
+			result->modulation = STV0900_16APSK;
+		else if (result->modcode <= STV0900_32APSK_910)
+			result->modulation = STV0900_32APSK;
+		else
+			result->modulation = STV0900_UNKNOWN;
+		break;
+	case STV0900_DVBS1_STANDARD:
+	case STV0900_DSS_STANDARD:
+		result->spectrum = stv0900_get_bits(intp, IQINV);
+		result->modulation = STV0900_QPSK;
+		break;
+	default:
+		break;
+	}
+
+	if ((intp->srch_algo[d] == STV0900_BLIND_SEARCH) ||
+				(intp->symbol_rate[d] < 10000000)) {
+		offsetFreq = result->frequency - intp->freq[d];
+		if (intp->tuner_type[demod] == 3)
+			intp->freq[d] = stv0900_get_freq_auto(intp, d);
+		else
+			intp->freq[d] = stv0900_get_tuner_freq(fe);
+
+		if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
+			range = STV0900_RANGEOK;
+		else if (ABS(offsetFreq) <=
+				(stv0900_carrier_width(result->symbol_rate,
+						result->rolloff) / 2000))
+			range = STV0900_RANGEOK;
+
+	} else if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
+		range = STV0900_RANGEOK;
+
+	dprintk("%s: range %d\n", __func__, range);
+
+	return range;
+}
+
+static enum
+fe_stv0900_signal_type stv0900_dvbs1_acq_workaround(struct dvb_frontend *fe)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+	enum fe_stv0900_signal_type signal_type = STV0900_NODATA;
+
+	s32	srate,
+		demod_timeout,
+		fec_timeout,
+		freq1,
+		freq0;
+
+	intp->result[demod].locked = FALSE;
+
+	if (stv0900_get_bits(intp, HEADER_MODE) == STV0900_DVBS_FOUND) {
+		srate = stv0900_get_symbol_rate(intp, intp->mclk, demod);
+		srate += stv0900_get_timing_offst(intp, srate, demod);
+		if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH)
+			stv0900_set_symbol_rate(intp, intp->mclk, srate, demod);
+
+		stv0900_get_lock_timeout(&demod_timeout, &fec_timeout,
+					srate, STV0900_WARM_START);
+		freq1 = stv0900_read_reg(intp, CFR2);
+		freq0 = stv0900_read_reg(intp, CFR1);
+		stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
+		stv0900_write_bits(intp, SPECINV_CONTROL,
+					STV0900_IQ_FORCE_SWAPPED);
+		stv0900_write_reg(intp, DMDISTATE, 0x1c);
+		stv0900_write_reg(intp, CFRINIT1, freq1);
+		stv0900_write_reg(intp, CFRINIT0, freq0);
+		stv0900_write_reg(intp, DMDISTATE, 0x18);
+		if (stv0900_wait_for_lock(intp, demod,
+				demod_timeout, fec_timeout) == TRUE) {
+			intp->result[demod].locked = TRUE;
+			signal_type = stv0900_get_signal_params(fe);
+			stv0900_track_optimization(fe);
+		} else {
+			stv0900_write_bits(intp, SPECINV_CONTROL,
+					STV0900_IQ_FORCE_NORMAL);
+			stv0900_write_reg(intp, DMDISTATE, 0x1c);
+			stv0900_write_reg(intp, CFRINIT1, freq1);
+			stv0900_write_reg(intp, CFRINIT0, freq0);
+			stv0900_write_reg(intp, DMDISTATE, 0x18);
+			if (stv0900_wait_for_lock(intp, demod,
+					demod_timeout, fec_timeout) == TRUE) {
+				intp->result[demod].locked = TRUE;
+				signal_type = stv0900_get_signal_params(fe);
+				stv0900_track_optimization(fe);
+			}
+
+		}
+
+	} else
+		intp->result[demod].locked = FALSE;
+
+	return signal_type;
+}
+
+static u16 stv0900_blind_check_agc2_min_level(struct stv0900_internal *intp,
+					enum fe_stv0900_demod_num demod)
+{
+	u32 minagc2level = 0xffff,
+		agc2level,
+		init_freq, freq_step;
+
+	s32 i, j, nb_steps, direction;
+
+	dprintk("%s\n", __func__);
+
+	stv0900_write_reg(intp, AGC2REF, 0x38);
+	stv0900_write_bits(intp, SCAN_ENABLE, 0);
+	stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
+
+	stv0900_write_bits(intp, AUTO_GUP, 1);
+	stv0900_write_bits(intp, AUTO_GLOW, 1);
+
+	stv0900_write_reg(intp, DMDT0M, 0x0);
+
+	stv0900_set_symbol_rate(intp, intp->mclk, 1000000, demod);
+	nb_steps = -1 + (intp->srch_range[demod] / 1000000);
+	nb_steps /= 2;
+	nb_steps = (2 * nb_steps) + 1;
+
+	if (nb_steps < 0)
+		nb_steps = 1;
+
+	direction = 1;
+
+	freq_step = (1000000 << 8) / (intp->mclk >> 8);
+
+	init_freq = 0;
+
+	for (i = 0; i < nb_steps; i++) {
+		if (direction > 0)
+			init_freq = init_freq + (freq_step * i);
+		else
+			init_freq = init_freq - (freq_step * i);
+
+		direction *= -1;
+		stv0900_write_reg(intp, DMDISTATE, 0x5C);
+		stv0900_write_reg(intp, CFRINIT1, (init_freq >> 8) & 0xff);
+		stv0900_write_reg(intp, CFRINIT0, init_freq  & 0xff);
+		stv0900_write_reg(intp, DMDISTATE, 0x58);
+		msleep(10);
+		agc2level = 0;
+
+		for (j = 0; j < 10; j++)
+			agc2level += (stv0900_read_reg(intp, AGC2I1) << 8)
+					| stv0900_read_reg(intp, AGC2I0);
+
+		agc2level /= 10;
+
+		if (agc2level < minagc2level)
+			minagc2level = agc2level;
+
+	}
+
+	return (u16)minagc2level;
+}
+
+static u32 stv0900_search_srate_coarse(struct dvb_frontend *fe)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+	int timing_lck = FALSE;
+	s32 i, timingcpt = 0,
+		direction = 1,
+		nb_steps,
+		current_step = 0,
+		tuner_freq;
+	u32 agc2_th,
+		coarse_srate = 0,
+		agc2_integr = 0,
+		currier_step = 1200;
+
+	if (intp->chip_id >= 0x30)
+		agc2_th = 0x2e00;
+	else
+		agc2_th = 0x1f00;
+
+	stv0900_write_bits(intp, DEMOD_MODE, 0x1f);
+	stv0900_write_reg(intp, TMGCFG, 0x12);
+	stv0900_write_reg(intp, TMGTHRISE, 0xf0);
+	stv0900_write_reg(intp, TMGTHFALL, 0xe0);
+	stv0900_write_bits(intp, SCAN_ENABLE, 1);
+	stv0900_write_bits(intp, CFR_AUTOSCAN, 1);
+	stv0900_write_reg(intp, SFRUP1, 0x83);
+	stv0900_write_reg(intp, SFRUP0, 0xc0);
+	stv0900_write_reg(intp, SFRLOW1, 0x82);
+	stv0900_write_reg(intp, SFRLOW0, 0xa0);
+	stv0900_write_reg(intp, DMDT0M, 0x0);
+	stv0900_write_reg(intp, AGC2REF, 0x50);
+
+	if (intp->chip_id >= 0x30) {
+		stv0900_write_reg(intp, CARFREQ, 0x99);
+		stv0900_write_reg(intp, SFRSTEP, 0x98);
+	} else if (intp->chip_id >= 0x20) {
+		stv0900_write_reg(intp, CARFREQ, 0x6a);
+		stv0900_write_reg(intp, SFRSTEP, 0x95);
+	} else {
+		stv0900_write_reg(intp, CARFREQ, 0xed);
+		stv0900_write_reg(intp, SFRSTEP, 0x73);
+	}
+
+	if (intp->symbol_rate[demod] <= 2000000)
+		currier_step = 1000;
+	else if (intp->symbol_rate[demod] <= 5000000)
+		currier_step = 2000;
+	else if (intp->symbol_rate[demod] <= 12000000)
+		currier_step = 3000;
+	else
+			currier_step = 5000;
+
+	nb_steps = -1 + ((intp->srch_range[demod] / 1000) / currier_step);
+	nb_steps /= 2;
+	nb_steps = (2 * nb_steps) + 1;
+
+	if (nb_steps < 0)
+		nb_steps = 1;
+	else if (nb_steps > 10) {
+		nb_steps = 11;
+		currier_step = (intp->srch_range[demod] / 1000) / 10;
+	}
+
+	current_step = 0;
+	direction = 1;
+
+	tuner_freq = intp->freq[demod];
+
+	while ((timing_lck == FALSE) && (current_step < nb_steps)) {
+		stv0900_write_reg(intp, DMDISTATE, 0x5f);
+		stv0900_write_bits(intp, DEMOD_MODE, 0);
+
+		msleep(50);
+
+		for (i = 0; i < 10; i++) {
+			if (stv0900_get_bits(intp, TMGLOCK_QUALITY) >= 2)
+				timingcpt++;
+
+			agc2_integr += (stv0900_read_reg(intp, AGC2I1) << 8) |
+					stv0900_read_reg(intp, AGC2I0);
+		}
+
+		agc2_integr /= 10;
+		coarse_srate = stv0900_get_symbol_rate(intp, intp->mclk, demod);
+		current_step++;
+		direction *= -1;
+
+		dprintk("lock: I2C_DEMOD_MODE_FIELD =0. Search started."
+			" tuner freq=%d agc2=0x%x srate_coarse=%d tmg_cpt=%d\n",
+			tuner_freq, agc2_integr, coarse_srate, timingcpt);
+
+		if ((timingcpt >= 5) &&
+				(agc2_integr < agc2_th) &&
+				(coarse_srate < 55000000) &&
+				(coarse_srate > 850000))
+			timing_lck = TRUE;
+		else if (current_step < nb_steps) {
+			if (direction > 0)
+				tuner_freq += (current_step * currier_step);
+			else
+				tuner_freq -= (current_step * currier_step);
+
+			if (intp->tuner_type[demod] == 3)
+				stv0900_set_tuner_auto(intp, tuner_freq,
+						intp->bw[demod], demod);
+			else
+				stv0900_set_tuner(fe, tuner_freq,
+						intp->bw[demod]);
+		}
+	}
+
+	if (timing_lck == FALSE)
+		coarse_srate = 0;
+	else
+		coarse_srate = stv0900_get_symbol_rate(intp, intp->mclk, demod);
+
+	return coarse_srate;
+}
+
+static u32 stv0900_search_srate_fine(struct dvb_frontend *fe)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+	u32	coarse_srate,
+		coarse_freq,
+		symb,
+		symbmax,
+		symbmin,
+		symbcomp;
+
+	coarse_srate = stv0900_get_symbol_rate(intp, intp->mclk, demod);
+
+	if (coarse_srate > 3000000) {
+		symbmax = 13 * (coarse_srate / 10);
+		symbmax = (symbmax / 1000) * 65536;
+		symbmax /= (intp->mclk / 1000);
+
+		symbmin = 10 * (coarse_srate / 13);
+		symbmin = (symbmin / 1000)*65536;
+		symbmin /= (intp->mclk / 1000);
+
+		symb = (coarse_srate / 1000) * 65536;
+		symb /= (intp->mclk / 1000);
+	} else {
+		symbmax = 13 * (coarse_srate / 10);
+		symbmax = (symbmax / 100) * 65536;
+		symbmax /= (intp->mclk / 100);
+
+		symbmin = 10 * (coarse_srate / 14);
+		symbmin = (symbmin / 100) * 65536;
+		symbmin /= (intp->mclk / 100);
+
+		symb = (coarse_srate / 100) * 65536;
+		symb /= (intp->mclk / 100);
+	}
+
+	symbcomp = 13 * (coarse_srate / 10);
+		coarse_freq = (stv0900_read_reg(intp, CFR2) << 8)
+					| stv0900_read_reg(intp, CFR1);
+
+	if (symbcomp < intp->symbol_rate[demod])
+		coarse_srate = 0;
+	else {
+		stv0900_write_reg(intp, DMDISTATE, 0x1f);
+		stv0900_write_reg(intp, TMGCFG2, 0xc1);
+		stv0900_write_reg(intp, TMGTHRISE, 0x20);
+		stv0900_write_reg(intp, TMGTHFALL, 0x00);
+		stv0900_write_reg(intp, TMGCFG, 0xd2);
+		stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
+		stv0900_write_reg(intp, AGC2REF, 0x38);
+
+		if (intp->chip_id >= 0x30)
+			stv0900_write_reg(intp, CARFREQ, 0x79);
+		else if (intp->chip_id >= 0x20)
+			stv0900_write_reg(intp, CARFREQ, 0x49);
+		else
+			stv0900_write_reg(intp, CARFREQ, 0xed);
+
+		stv0900_write_reg(intp, SFRUP1, (symbmax >> 8) & 0x7f);
+		stv0900_write_reg(intp, SFRUP0, (symbmax & 0xff));
+
+		stv0900_write_reg(intp, SFRLOW1, (symbmin >> 8) & 0x7f);
+		stv0900_write_reg(intp, SFRLOW0, (symbmin & 0xff));
+
+		stv0900_write_reg(intp, SFRINIT1, (symb >> 8) & 0xff);
+		stv0900_write_reg(intp, SFRINIT0, (symb & 0xff));
+
+		stv0900_write_reg(intp, DMDT0M, 0x20);
+		stv0900_write_reg(intp, CFRINIT1, (coarse_freq >> 8) & 0xff);
+		stv0900_write_reg(intp, CFRINIT0, coarse_freq  & 0xff);
+		stv0900_write_reg(intp, DMDISTATE, 0x15);
+	}
+
+	return coarse_srate;
+}
+
+static int stv0900_blind_search_algo(struct dvb_frontend *fe)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+	u8	k_ref_tmg,
+		k_ref_tmg_max,
+		k_ref_tmg_min;
+	u32	coarse_srate,
+		agc2_th;
+	int	lock = FALSE,
+		coarse_fail = FALSE;
+	s32	demod_timeout = 500,
+		fec_timeout = 50,
+		fail_cpt,
+		i,
+		agc2_overflow;
+	u16	agc2_int;
+	u8	dstatus2;
+
+	dprintk("%s\n", __func__);
+
+	if (intp->chip_id < 0x20) {
+		k_ref_tmg_max = 233;
+		k_ref_tmg_min = 143;
+	} else {
+		k_ref_tmg_max = 110;
+		k_ref_tmg_min = 10;
+	}
+
+	if (intp->chip_id <= 0x20)
+		agc2_th = STV0900_BLIND_SEARCH_AGC2_TH;
+	else
+		agc2_th = STV0900_BLIND_SEARCH_AGC2_TH_CUT30;
+
+	agc2_int = stv0900_blind_check_agc2_min_level(intp, demod);
+
+	dprintk("%s agc2_int=%d agc2_th=%d \n", __func__, agc2_int, agc2_th);
+	if (agc2_int > agc2_th)
+		return FALSE;
+
+	if (intp->chip_id == 0x10)
+		stv0900_write_reg(intp, CORRELEXP, 0xaa);
+
+	if (intp->chip_id < 0x20)
+		stv0900_write_reg(intp, CARHDR, 0x55);
+	else
+		stv0900_write_reg(intp, CARHDR, 0x20);
+
+	if (intp->chip_id <= 0x20)
+		stv0900_write_reg(intp, CARCFG, 0xc4);
+	else
+		stv0900_write_reg(intp, CARCFG, 0x6);
+
+	stv0900_write_reg(intp, RTCS2, 0x44);
+
+	if (intp->chip_id >= 0x20) {
+		stv0900_write_reg(intp, EQUALCFG, 0x41);
+		stv0900_write_reg(intp, FFECFG, 0x41);
+		stv0900_write_reg(intp, VITSCALE, 0x82);
+		stv0900_write_reg(intp, VAVSRVIT, 0x0);
+	}
+
+	k_ref_tmg = k_ref_tmg_max;
+
+	do {
+		stv0900_write_reg(intp, KREFTMG, k_ref_tmg);
+		if (stv0900_search_srate_coarse(fe) != 0) {
+			coarse_srate = stv0900_search_srate_fine(fe);
+
+			if (coarse_srate != 0) {
+				stv0900_get_lock_timeout(&demod_timeout,
+							&fec_timeout,
+							coarse_srate,
+							STV0900_BLIND_SEARCH);
+				lock = stv0900_get_demod_lock(intp,
+							demod,
+							demod_timeout);
+			} else
+				lock = FALSE;
+		} else {
+			fail_cpt = 0;
+			agc2_overflow = 0;
+
+			for (i = 0; i < 10; i++) {
+				agc2_int = (stv0900_read_reg(intp, AGC2I1) << 8)
+					| stv0900_read_reg(intp, AGC2I0);
+
+				if (agc2_int >= 0xff00)
+					agc2_overflow++;
+
+				dstatus2 = stv0900_read_reg(intp, DSTATUS2);
+
+				if (((dstatus2 & 0x1) == 0x1) &&
+						((dstatus2 >> 7) == 1))
+					fail_cpt++;
+			}
+
+			if ((fail_cpt > 7) || (agc2_overflow > 7))
+				coarse_fail = TRUE;
+
+			lock = FALSE;
+		}
+		k_ref_tmg -= 30;
+	} while ((k_ref_tmg >= k_ref_tmg_min) &&
+				(lock == FALSE) &&
+				(coarse_fail == FALSE));
+
+	return lock;
+}
+
+static void stv0900_set_viterbi_acq(struct stv0900_internal *intp,
+					enum fe_stv0900_demod_num demod)
+{
+	s32 vth_reg = VTH12;
+
+	dprintk("%s\n", __func__);
+
+	stv0900_write_reg(intp, vth_reg++, 0x96);
+	stv0900_write_reg(intp, vth_reg++, 0x64);
+	stv0900_write_reg(intp, vth_reg++, 0x36);
+	stv0900_write_reg(intp, vth_reg++, 0x23);
+	stv0900_write_reg(intp, vth_reg++, 0x1e);
+	stv0900_write_reg(intp, vth_reg++, 0x19);
+}
+
+static void stv0900_set_search_standard(struct stv0900_internal *intp,
+					enum fe_stv0900_demod_num demod)
+{
+
+	dprintk("%s\n", __func__);
+
+	switch (intp->srch_standard[demod]) {
+	case STV0900_SEARCH_DVBS1:
+		dprintk("Search Standard = DVBS1\n");
+		break;
+	case STV0900_SEARCH_DSS:
+		dprintk("Search Standard = DSS\n");
+	case STV0900_SEARCH_DVBS2:
+		break;
+		dprintk("Search Standard = DVBS2\n");
+	case STV0900_AUTO_SEARCH:
+	default:
+		dprintk("Search Standard = AUTO\n");
+		break;
+	}
+
+	switch (intp->srch_standard[demod]) {
+	case STV0900_SEARCH_DVBS1:
+	case STV0900_SEARCH_DSS:
+		stv0900_write_bits(intp, DVBS1_ENABLE, 1);
+		stv0900_write_bits(intp, DVBS2_ENABLE, 0);
+		stv0900_write_bits(intp, STOP_CLKVIT, 0);
+		stv0900_set_dvbs1_track_car_loop(intp,
+						demod,
+						intp->symbol_rate[demod]);
+		stv0900_write_reg(intp, CAR2CFG, 0x22);
+
+		stv0900_set_viterbi_acq(intp, demod);
+		stv0900_set_viterbi_standard(intp,
+					intp->srch_standard[demod],
+					intp->fec[demod], demod);
+
+		break;
+	case STV0900_SEARCH_DVBS2:
+		stv0900_write_bits(intp, DVBS1_ENABLE, 0);
+		stv0900_write_bits(intp, DVBS2_ENABLE, 1);
+		stv0900_write_bits(intp, STOP_CLKVIT, 1);
+		stv0900_write_reg(intp, ACLC, 0x1a);
+		stv0900_write_reg(intp, BCLC, 0x09);
+		if (intp->chip_id <= 0x20) /*cut 1.x and 2.0*/
+			stv0900_write_reg(intp, CAR2CFG, 0x26);
+		else
+			stv0900_write_reg(intp, CAR2CFG, 0x66);
+
+		if (intp->demod_mode != STV0900_SINGLE) {
+			if (intp->chip_id <= 0x11)
+				stv0900_stop_all_s2_modcod(intp, demod);
+			else
+				stv0900_activate_s2_modcod(intp, demod);
+
+		} else
+			stv0900_activate_s2_modcod_single(intp, demod);
+
+		stv0900_set_viterbi_tracq(intp, demod);
+
+		break;
+	case STV0900_AUTO_SEARCH:
+	default:
+		stv0900_write_bits(intp, DVBS1_ENABLE, 1);
+		stv0900_write_bits(intp, DVBS2_ENABLE, 1);
+		stv0900_write_bits(intp, STOP_CLKVIT, 0);
+		stv0900_write_reg(intp, ACLC, 0x1a);
+		stv0900_write_reg(intp, BCLC, 0x09);
+		stv0900_set_dvbs1_track_car_loop(intp,
+						demod,
+						intp->symbol_rate[demod]);
+		if (intp->chip_id <= 0x20) /*cut 1.x and 2.0*/
+			stv0900_write_reg(intp, CAR2CFG, 0x26);
+		else
+			stv0900_write_reg(intp, CAR2CFG, 0x66);
+
+		if (intp->demod_mode != STV0900_SINGLE) {
+			if (intp->chip_id <= 0x11)
+				stv0900_stop_all_s2_modcod(intp, demod);
+			else
+				stv0900_activate_s2_modcod(intp, demod);
+
+		} else
+			stv0900_activate_s2_modcod_single(intp, demod);
+
+		stv0900_set_viterbi_tracq(intp, demod);
+		stv0900_set_viterbi_standard(intp,
+						intp->srch_standard[demod],
+						intp->fec[demod], demod);
+
+		break;
+	}
+}
+
+enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
+
+	s32 demod_timeout = 500, fec_timeout = 50;
+	s32 aq_power, agc1_power, i;
+
+	int lock = FALSE, low_sr = FALSE;
+
+	enum fe_stv0900_signal_type signal_type = STV0900_NOCARRIER;
+	enum fe_stv0900_search_algo algo;
+	int no_signal = FALSE;
+
+	dprintk("%s\n", __func__);
+
+	algo = intp->srch_algo[demod];
+	stv0900_write_bits(intp, RST_HWARE, 1);
+	stv0900_write_reg(intp, DMDISTATE, 0x5c);
+	if (intp->chip_id >= 0x20) {
+		if (intp->symbol_rate[demod] > 5000000)
+			stv0900_write_reg(intp, CORRELABS, 0x9e);
+		else
+			stv0900_write_reg(intp, CORRELABS, 0x82);
+	} else
+		stv0900_write_reg(intp, CORRELABS, 0x88);
+
+	stv0900_get_lock_timeout(&demod_timeout, &fec_timeout,
+				intp->symbol_rate[demod],
+				intp->srch_algo[demod]);
+
+	if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) {
+		intp->bw[demod] = 2 * 36000000;
+
+		stv0900_write_reg(intp, TMGCFG2, 0xc0);
+		stv0900_write_reg(intp, CORRELMANT, 0x70);
+
+		stv0900_set_symbol_rate(intp, intp->mclk, 1000000, demod);
+	} else {
+		stv0900_write_reg(intp, DMDT0M, 0x20);
+		stv0900_write_reg(intp, TMGCFG, 0xd2);
+
+		if (intp->symbol_rate[demod] < 2000000)
+			stv0900_write_reg(intp, CORRELMANT, 0x63);
+		else
+			stv0900_write_reg(intp, CORRELMANT, 0x70);
+
+		stv0900_write_reg(intp, AGC2REF, 0x38);
+
+		intp->bw[demod] =
+				stv0900_carrier_width(intp->symbol_rate[demod],
+								intp->rolloff);
+		if (intp->chip_id >= 0x20) {
+			stv0900_write_reg(intp, KREFTMG, 0x5a);
+
+			if (intp->srch_algo[demod] == STV0900_COLD_START) {
+				intp->bw[demod] += 10000000;
+				intp->bw[demod] *= 15;
+				intp->bw[demod] /= 10;
+			} else if (intp->srch_algo[demod] == STV0900_WARM_START)
+				intp->bw[demod] += 10000000;
+
+		} else {
+			stv0900_write_reg(intp, KREFTMG, 0xc1);
+			intp->bw[demod] += 10000000;
+			intp->bw[demod] *= 15;
+			intp->bw[demod] /= 10;
+		}
+
+		stv0900_write_reg(intp, TMGCFG2, 0xc1);
+
+		stv0900_set_symbol_rate(intp, intp->mclk,
+					intp->symbol_rate[demod], demod);
+		stv0900_set_max_symbol_rate(intp, intp->mclk,
+					intp->symbol_rate[demod], demod);
+		stv0900_set_min_symbol_rate(intp, intp->mclk,
+					intp->symbol_rate[demod], demod);
+		if (intp->symbol_rate[demod] >= 10000000)
+			low_sr = FALSE;
+		else
+			low_sr = TRUE;
+
+	}
+
+	if (intp->tuner_type[demod] == 3)
+		stv0900_set_tuner_auto(intp, intp->freq[demod],
+				intp->bw[demod], demod);
+	else
+		stv0900_set_tuner(fe, intp->freq[demod], intp->bw[demod]);
+
+	agc1_power = MAKEWORD(stv0900_get_bits(intp, AGCIQ_VALUE1),
+				stv0900_get_bits(intp, AGCIQ_VALUE0));
+
+	aq_power = 0;
+
+	if (agc1_power == 0) {
+		for (i = 0; i < 5; i++)
+			aq_power += (stv0900_get_bits(intp, POWER_I) +
+					stv0900_get_bits(intp, POWER_Q)) / 2;
+
+		aq_power /= 5;
+	}
+
+	if ((agc1_power == 0) && (aq_power < IQPOWER_THRESHOLD)) {
+		intp->result[demod].locked = FALSE;
+		signal_type = STV0900_NOAGC1;
+		dprintk("%s: NO AGC1, POWERI, POWERQ\n", __func__);
+	} else {
+		stv0900_write_bits(intp, SPECINV_CONTROL,
+					intp->srch_iq_inv[demod]);
+		if (intp->chip_id <= 0x20) /*cut 2.0*/
+			stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1);
+		else /*cut 3.0*/
+			stv0900_write_bits(intp, MANUALS2_ROLLOFF, 1);
+
+		stv0900_set_search_standard(intp, demod);
+
+		if (intp->srch_algo[demod] != STV0900_BLIND_SEARCH)
+			stv0900_start_search(intp, demod);
+	}
+
+	if (signal_type == STV0900_NOAGC1)
+		return signal_type;
+
+	if (intp->chip_id == 0x12) {
+		stv0900_write_bits(intp, RST_HWARE, 0);
+		msleep(3);
+		stv0900_write_bits(intp, RST_HWARE, 1);
+		stv0900_write_bits(intp, RST_HWARE, 0);
+	}
+
+	if (algo == STV0900_BLIND_SEARCH)
+		lock = stv0900_blind_search_algo(fe);
+	else if (algo == STV0900_COLD_START)
+		lock = stv0900_get_demod_cold_lock(fe, demod_timeout);
+	else if (algo == STV0900_WARM_START)
+		lock = stv0900_get_demod_lock(intp, demod, demod_timeout);
+
+	if ((lock == FALSE) && (algo == STV0900_COLD_START)) {
+		if (low_sr == FALSE) {
+			if (stv0900_check_timing_lock(intp, demod) == TRUE)
+				lock = stv0900_sw_algo(intp, demod);
+		}
+	}
+
+	if (lock == TRUE)
+		signal_type = stv0900_get_signal_params(fe);
+
+	if ((lock == TRUE) && (signal_type == STV0900_RANGEOK)) {
+		stv0900_track_optimization(fe);
+		if (intp->chip_id <= 0x11) {
+			if ((stv0900_get_standard(fe, 0) ==
+						STV0900_DVBS1_STANDARD) &&
+			   (stv0900_get_standard(fe, 1) ==
+						STV0900_DVBS1_STANDARD)) {
+				msleep(20);
+				stv0900_write_bits(intp, RST_HWARE, 0);
+			} else {
+				stv0900_write_bits(intp, RST_HWARE, 0);
+				msleep(3);
+				stv0900_write_bits(intp, RST_HWARE, 1);
+				stv0900_write_bits(intp, RST_HWARE, 0);
+			}
+
+		} else if (intp->chip_id >= 0x20) {
+			stv0900_write_bits(intp, RST_HWARE, 0);
+			msleep(3);
+			stv0900_write_bits(intp, RST_HWARE, 1);
+			stv0900_write_bits(intp, RST_HWARE, 0);
+		}
+
+		if (stv0900_wait_for_lock(intp, demod,
+					fec_timeout, fec_timeout) == TRUE) {
+			lock = TRUE;
+			intp->result[demod].locked = TRUE;
+			if (intp->result[demod].standard ==
+						STV0900_DVBS2_STANDARD) {
+				stv0900_set_dvbs2_rolloff(intp, demod);
+				stv0900_write_bits(intp, RESET_UPKO_COUNT, 1);
+				stv0900_write_bits(intp, RESET_UPKO_COUNT, 0);
+				stv0900_write_reg(intp, ERRCTRL1, 0x67);
+			} else {
+				stv0900_write_reg(intp, ERRCTRL1, 0x75);
+			}
+
+			stv0900_write_reg(intp, FBERCPT4, 0);
+			stv0900_write_reg(intp, ERRCTRL2, 0xc1);
+		} else {
+			lock = FALSE;
+			signal_type = STV0900_NODATA;
+			no_signal = stv0900_check_signal_presence(intp, demod);
+
+				intp->result[demod].locked = FALSE;
+		}
+	}
+
+	if ((signal_type != STV0900_NODATA) || (no_signal != FALSE))
+		return signal_type;
+
+	if (intp->chip_id > 0x11) {
+		intp->result[demod].locked = FALSE;
+		return signal_type;
+	}
+
+	if ((stv0900_get_bits(intp, HEADER_MODE) == STV0900_DVBS_FOUND) &&
+	   (intp->srch_iq_inv[demod] <= STV0900_IQ_AUTO_NORMAL_FIRST))
+		signal_type = stv0900_dvbs1_acq_workaround(fe);
+
+	return signal_type;
+}
+
diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c
new file mode 100644
index 0000000..ea86a56
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv090x.c
@@ -0,0 +1,4823 @@
+/*
+	STV0900/0903 Multistandard Broadcast Frontend driver
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+#include "stv6110x.h" /* for demodulator internal modes */
+
+#include "stv090x_reg.h"
+#include "stv090x.h"
+#include "stv090x_priv.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+
+/* internal params node */
+struct stv090x_dev {
+	/* pointer for internal params, one for each pair of demods */
+	struct stv090x_internal		*internal;
+	struct stv090x_dev		*next_dev;
+};
+
+/* first internal params */
+static struct stv090x_dev *stv090x_first_dev;
+
+/* find chip by i2c adapter and i2c address */
+static struct stv090x_dev *find_dev(struct i2c_adapter *i2c_adap,
+					u8 i2c_addr)
+{
+	struct stv090x_dev *temp_dev = stv090x_first_dev;
+
+	/*
+	 Search of the last stv0900 chip or
+	 find it by i2c adapter and i2c address */
+	while ((temp_dev != NULL) &&
+		((temp_dev->internal->i2c_adap != i2c_adap) ||
+		(temp_dev->internal->i2c_addr != i2c_addr))) {
+
+		temp_dev = temp_dev->next_dev;
+	}
+
+	return temp_dev;
+}
+
+/* deallocating chip */
+static void remove_dev(struct stv090x_internal *internal)
+{
+	struct stv090x_dev *prev_dev = stv090x_first_dev;
+	struct stv090x_dev *del_dev = find_dev(internal->i2c_adap,
+						internal->i2c_addr);
+
+	if (del_dev != NULL) {
+		if (del_dev == stv090x_first_dev) {
+			stv090x_first_dev = del_dev->next_dev;
+		} else {
+			while (prev_dev->next_dev != del_dev)
+				prev_dev = prev_dev->next_dev;
+
+			prev_dev->next_dev = del_dev->next_dev;
+		}
+
+		kfree(del_dev);
+	}
+}
+
+/* allocating new chip */
+static struct stv090x_dev *append_internal(struct stv090x_internal *internal)
+{
+	struct stv090x_dev *new_dev;
+	struct stv090x_dev *temp_dev;
+
+	new_dev = kmalloc(sizeof(struct stv090x_dev), GFP_KERNEL);
+	if (new_dev != NULL) {
+		new_dev->internal = internal;
+		new_dev->next_dev = NULL;
+
+		/* append to list */
+		if (stv090x_first_dev == NULL) {
+			stv090x_first_dev = new_dev;
+		} else {
+			temp_dev = stv090x_first_dev;
+			while (temp_dev->next_dev != NULL)
+				temp_dev = temp_dev->next_dev;
+
+			temp_dev->next_dev = new_dev;
+		}
+	}
+
+	return new_dev;
+}
+
+
+/* DVBS1 and DSS C/N Lookup table */
+static const struct stv090x_tab stv090x_s1cn_tab[] = {
+	{   0, 8917 }, /*  0.0dB */
+	{   5, 8801 }, /*  0.5dB */
+	{  10, 8667 }, /*  1.0dB */
+	{  15, 8522 }, /*  1.5dB */
+	{  20, 8355 }, /*  2.0dB */
+	{  25, 8175 }, /*  2.5dB */
+	{  30, 7979 }, /*  3.0dB */
+	{  35, 7763 }, /*  3.5dB */
+	{  40, 7530 }, /*  4.0dB */
+	{  45, 7282 }, /*  4.5dB */
+	{  50, 7026 }, /*  5.0dB */
+	{  55, 6781 }, /*  5.5dB */
+	{  60, 6514 }, /*  6.0dB */
+	{  65, 6241 }, /*  6.5dB */
+	{  70, 5965 }, /*  7.0dB */
+	{  75, 5690 }, /*  7.5dB */
+	{  80, 5424 }, /*  8.0dB */
+	{  85, 5161 }, /*  8.5dB */
+	{  90, 4902 }, /*  9.0dB */
+	{  95, 4654 }, /*  9.5dB */
+	{ 100, 4417 }, /* 10.0dB */
+	{ 105, 4186 }, /* 10.5dB */
+	{ 110, 3968 }, /* 11.0dB */
+	{ 115, 3757 }, /* 11.5dB */
+	{ 120, 3558 }, /* 12.0dB */
+	{ 125, 3366 }, /* 12.5dB */
+	{ 130, 3185 }, /* 13.0dB */
+	{ 135, 3012 }, /* 13.5dB */
+	{ 140, 2850 }, /* 14.0dB */
+	{ 145, 2698 }, /* 14.5dB */
+	{ 150, 2550 }, /* 15.0dB */
+	{ 160, 2283 }, /* 16.0dB */
+	{ 170, 2042 }, /* 17.0dB */
+	{ 180, 1827 }, /* 18.0dB */
+	{ 190, 1636 }, /* 19.0dB */
+	{ 200, 1466 }, /* 20.0dB */
+	{ 210, 1315 }, /* 21.0dB */
+	{ 220, 1181 }, /* 22.0dB */
+	{ 230, 1064 }, /* 23.0dB */
+	{ 240,	960 }, /* 24.0dB */
+	{ 250,	869 }, /* 25.0dB */
+	{ 260,	792 }, /* 26.0dB */
+	{ 270,	724 }, /* 27.0dB */
+	{ 280,	665 }, /* 28.0dB */
+	{ 290,	616 }, /* 29.0dB */
+	{ 300,	573 }, /* 30.0dB */
+	{ 310,	537 }, /* 31.0dB */
+	{ 320,	507 }, /* 32.0dB */
+	{ 330,	483 }, /* 33.0dB */
+	{ 400,	398 }, /* 40.0dB */
+	{ 450,	381 }, /* 45.0dB */
+	{ 500,	377 }  /* 50.0dB */
+};
+
+/* DVBS2 C/N Lookup table */
+static const struct stv090x_tab stv090x_s2cn_tab[] = {
+	{ -30, 13348 }, /* -3.0dB */
+	{ -20, 12640 }, /* -2d.0B */
+	{ -10, 11883 }, /* -1.0dB */
+	{   0, 11101 }, /* -0.0dB */
+	{   5, 10718 }, /*  0.5dB */
+	{  10, 10339 }, /*  1.0dB */
+	{  15,  9947 }, /*  1.5dB */
+	{  20,  9552 }, /*  2.0dB */
+	{  25,  9183 }, /*  2.5dB */
+	{  30,  8799 }, /*  3.0dB */
+	{  35,  8422 }, /*  3.5dB */
+	{  40,  8062 }, /*  4.0dB */
+	{  45,  7707 }, /*  4.5dB */
+	{  50,  7353 }, /*  5.0dB */
+	{  55,  7025 }, /*  5.5dB */
+	{  60,  6684 }, /*  6.0dB */
+	{  65,  6331 }, /*  6.5dB */
+	{  70,  6036 }, /*  7.0dB */
+	{  75,  5727 }, /*  7.5dB */
+	{  80,  5437 }, /*  8.0dB */
+	{  85,  5164 }, /*  8.5dB */
+	{  90,  4902 }, /*  9.0dB */
+	{  95,  4653 }, /*  9.5dB */
+	{ 100,  4408 }, /* 10.0dB */
+	{ 105,  4187 }, /* 10.5dB */
+	{ 110,  3961 }, /* 11.0dB */
+	{ 115,  3751 }, /* 11.5dB */
+	{ 120,  3558 }, /* 12.0dB */
+	{ 125,  3368 }, /* 12.5dB */
+	{ 130,  3191 }, /* 13.0dB */
+	{ 135,  3017 }, /* 13.5dB */
+	{ 140,  2862 }, /* 14.0dB */
+	{ 145,  2710 }, /* 14.5dB */
+	{ 150,  2565 }, /* 15.0dB */
+	{ 160,  2300 }, /* 16.0dB */
+	{ 170,  2058 }, /* 17.0dB */
+	{ 180,  1849 }, /* 18.0dB */
+	{ 190,  1663 }, /* 19.0dB */
+	{ 200,  1495 }, /* 20.0dB */
+	{ 210,  1349 }, /* 21.0dB */
+	{ 220,  1222 }, /* 22.0dB */
+	{ 230,  1110 }, /* 23.0dB */
+	{ 240,  1011 }, /* 24.0dB */
+	{ 250,   925 }, /* 25.0dB */
+	{ 260,   853 }, /* 26.0dB */
+	{ 270,   789 }, /* 27.0dB */
+	{ 280,   734 }, /* 28.0dB */
+	{ 290,   690 }, /* 29.0dB */
+	{ 300,   650 }, /* 30.0dB */
+	{ 310,   619 }, /* 31.0dB */
+	{ 320,   593 }, /* 32.0dB */
+	{ 330,   571 }, /* 33.0dB */
+	{ 400,   498 }, /* 40.0dB */
+	{ 450,	 484 }, /* 45.0dB */
+	{ 500,	 481 }	/* 50.0dB */
+};
+
+/* RF level C/N lookup table */
+static const struct stv090x_tab stv090x_rf_tab[] = {
+	{  -5, 0xcaa1 }, /*  -5dBm */
+	{ -10, 0xc229 }, /* -10dBm */
+	{ -15, 0xbb08 }, /* -15dBm */
+	{ -20, 0xb4bc }, /* -20dBm */
+	{ -25, 0xad5a }, /* -25dBm */
+	{ -30, 0xa298 }, /* -30dBm */
+	{ -35, 0x98a8 }, /* -35dBm */
+	{ -40, 0x8389 }, /* -40dBm */
+	{ -45, 0x59be }, /* -45dBm */
+	{ -50, 0x3a14 }, /* -50dBm */
+	{ -55, 0x2d11 }, /* -55dBm */
+	{ -60, 0x210d }, /* -60dBm */
+	{ -65, 0xa14f }, /* -65dBm */
+	{ -70, 0x07aa }	 /* -70dBm */
+};
+
+
+static struct stv090x_reg stv0900_initval[] = {
+
+	{ STV090x_OUTCFG,		0x00 },
+	{ STV090x_MODECFG,		0xff },
+	{ STV090x_AGCRF1CFG,		0x11 },
+	{ STV090x_AGCRF2CFG,		0x13 },
+	{ STV090x_TSGENERAL1X,		0x14 },
+	{ STV090x_TSTTNR2,		0x21 },
+	{ STV090x_TSTTNR4,		0x21 },
+	{ STV090x_P2_DISTXCTL,		0x22 },
+	{ STV090x_P2_F22TX,		0xc0 },
+	{ STV090x_P2_F22RX,		0xc0 },
+	{ STV090x_P2_DISRXCTL,		0x00 },
+	{ STV090x_P2_DMDCFGMD,		0xF9 },
+	{ STV090x_P2_DEMOD,		0x08 },
+	{ STV090x_P2_DMDCFG3,		0xc4 },
+	{ STV090x_P2_CARFREQ,		0xed },
+	{ STV090x_P2_LDT,		0xd0 },
+	{ STV090x_P2_LDT2,		0xb8 },
+	{ STV090x_P2_TMGCFG,		0xd2 },
+	{ STV090x_P2_TMGTHRISE,		0x20 },
+	{ STV090x_P1_TMGCFG,		0xd2 },
+
+	{ STV090x_P2_TMGTHFALL,		0x00 },
+	{ STV090x_P2_FECSPY,		0x88 },
+	{ STV090x_P2_FSPYDATA,		0x3a },
+	{ STV090x_P2_FBERCPT4,		0x00 },
+	{ STV090x_P2_FSPYBER,		0x10 },
+	{ STV090x_P2_ERRCTRL1,		0x35 },
+	{ STV090x_P2_ERRCTRL2,		0xc1 },
+	{ STV090x_P2_CFRICFG,		0xf8 },
+	{ STV090x_P2_NOSCFG,		0x1c },
+	{ STV090x_P2_DMDTOM,		0x20 },
+	{ STV090x_P2_CORRELMANT,	0x70 },
+	{ STV090x_P2_CORRELABS,		0x88 },
+	{ STV090x_P2_AGC2O,		0x5b },
+	{ STV090x_P2_AGC2REF,		0x38 },
+	{ STV090x_P2_CARCFG,		0xe4 },
+	{ STV090x_P2_ACLC,		0x1A },
+	{ STV090x_P2_BCLC,		0x09 },
+	{ STV090x_P2_CARHDR,		0x08 },
+	{ STV090x_P2_KREFTMG,		0xc1 },
+	{ STV090x_P2_SFRUPRATIO,	0xf0 },
+	{ STV090x_P2_SFRLOWRATIO,	0x70 },
+	{ STV090x_P2_SFRSTEP,		0x58 },
+	{ STV090x_P2_TMGCFG2,		0x01 },
+	{ STV090x_P2_CAR2CFG,		0x26 },
+	{ STV090x_P2_BCLC2S2Q,		0x86 },
+	{ STV090x_P2_BCLC2S28,		0x86 },
+	{ STV090x_P2_SMAPCOEF7,		0x77 },
+	{ STV090x_P2_SMAPCOEF6,		0x85 },
+	{ STV090x_P2_SMAPCOEF5,		0x77 },
+	{ STV090x_P2_TSCFGL,		0x20 },
+	{ STV090x_P2_DMDCFG2,		0x3b },
+	{ STV090x_P2_MODCODLST0,	0xff },
+	{ STV090x_P2_MODCODLST1,	0xff },
+	{ STV090x_P2_MODCODLST2,	0xff },
+	{ STV090x_P2_MODCODLST3,	0xff },
+	{ STV090x_P2_MODCODLST4,	0xff },
+	{ STV090x_P2_MODCODLST5,	0xff },
+	{ STV090x_P2_MODCODLST6,	0xff },
+	{ STV090x_P2_MODCODLST7,	0xcc },
+	{ STV090x_P2_MODCODLST8,	0xcc },
+	{ STV090x_P2_MODCODLST9,	0xcc },
+	{ STV090x_P2_MODCODLSTA,	0xcc },
+	{ STV090x_P2_MODCODLSTB,	0xcc },
+	{ STV090x_P2_MODCODLSTC,	0xcc },
+	{ STV090x_P2_MODCODLSTD,	0xcc },
+	{ STV090x_P2_MODCODLSTE,	0xcc },
+	{ STV090x_P2_MODCODLSTF,	0xcf },
+	{ STV090x_P1_DISTXCTL,		0x22 },
+	{ STV090x_P1_F22TX,		0xc0 },
+	{ STV090x_P1_F22RX,		0xc0 },
+	{ STV090x_P1_DISRXCTL,		0x00 },
+	{ STV090x_P1_DMDCFGMD,		0xf9 },
+	{ STV090x_P1_DEMOD,		0x08 },
+	{ STV090x_P1_DMDCFG3,		0xc4 },
+	{ STV090x_P1_DMDTOM,		0x20 },
+	{ STV090x_P1_CARFREQ,		0xed },
+	{ STV090x_P1_LDT,		0xd0 },
+	{ STV090x_P1_LDT2,		0xb8 },
+	{ STV090x_P1_TMGCFG,		0xd2 },
+	{ STV090x_P1_TMGTHRISE,		0x20 },
+	{ STV090x_P1_TMGTHFALL,		0x00 },
+	{ STV090x_P1_SFRUPRATIO,	0xf0 },
+	{ STV090x_P1_SFRLOWRATIO,	0x70 },
+	{ STV090x_P1_TSCFGL,		0x20 },
+	{ STV090x_P1_FECSPY,		0x88 },
+	{ STV090x_P1_FSPYDATA,		0x3a },
+	{ STV090x_P1_FBERCPT4,		0x00 },
+	{ STV090x_P1_FSPYBER,		0x10 },
+	{ STV090x_P1_ERRCTRL1,		0x35 },
+	{ STV090x_P1_ERRCTRL2,		0xc1 },
+	{ STV090x_P1_CFRICFG,		0xf8 },
+	{ STV090x_P1_NOSCFG,		0x1c },
+	{ STV090x_P1_CORRELMANT,	0x70 },
+	{ STV090x_P1_CORRELABS,		0x88 },
+	{ STV090x_P1_AGC2O,		0x5b },
+	{ STV090x_P1_AGC2REF,		0x38 },
+	{ STV090x_P1_CARCFG,		0xe4 },
+	{ STV090x_P1_ACLC,		0x1A },
+	{ STV090x_P1_BCLC,		0x09 },
+	{ STV090x_P1_CARHDR,		0x08 },
+	{ STV090x_P1_KREFTMG,		0xc1 },
+	{ STV090x_P1_SFRSTEP,		0x58 },
+	{ STV090x_P1_TMGCFG2,		0x01 },
+	{ STV090x_P1_CAR2CFG,		0x26 },
+	{ STV090x_P1_BCLC2S2Q,		0x86 },
+	{ STV090x_P1_BCLC2S28,		0x86 },
+	{ STV090x_P1_SMAPCOEF7,		0x77 },
+	{ STV090x_P1_SMAPCOEF6,		0x85 },
+	{ STV090x_P1_SMAPCOEF5,		0x77 },
+	{ STV090x_P1_DMDCFG2,		0x3b },
+	{ STV090x_P1_MODCODLST0,	0xff },
+	{ STV090x_P1_MODCODLST1,	0xff },
+	{ STV090x_P1_MODCODLST2,	0xff },
+	{ STV090x_P1_MODCODLST3,	0xff },
+	{ STV090x_P1_MODCODLST4,	0xff },
+	{ STV090x_P1_MODCODLST5,	0xff },
+	{ STV090x_P1_MODCODLST6,	0xff },
+	{ STV090x_P1_MODCODLST7,	0xcc },
+	{ STV090x_P1_MODCODLST8,	0xcc },
+	{ STV090x_P1_MODCODLST9,	0xcc },
+	{ STV090x_P1_MODCODLSTA,	0xcc },
+	{ STV090x_P1_MODCODLSTB,	0xcc },
+	{ STV090x_P1_MODCODLSTC,	0xcc },
+	{ STV090x_P1_MODCODLSTD,	0xcc },
+	{ STV090x_P1_MODCODLSTE,	0xcc },
+	{ STV090x_P1_MODCODLSTF,	0xcf },
+	{ STV090x_GENCFG,		0x1d },
+	{ STV090x_NBITER_NF4,		0x37 },
+	{ STV090x_NBITER_NF5,		0x29 },
+	{ STV090x_NBITER_NF6,		0x37 },
+	{ STV090x_NBITER_NF7,		0x33 },
+	{ STV090x_NBITER_NF8,		0x31 },
+	{ STV090x_NBITER_NF9,		0x2f },
+	{ STV090x_NBITER_NF10,		0x39 },
+	{ STV090x_NBITER_NF11,		0x3a },
+	{ STV090x_NBITER_NF12,		0x29 },
+	{ STV090x_NBITER_NF13,		0x37 },
+	{ STV090x_NBITER_NF14,		0x33 },
+	{ STV090x_NBITER_NF15,		0x2f },
+	{ STV090x_NBITER_NF16,		0x39 },
+	{ STV090x_NBITER_NF17,		0x3a },
+	{ STV090x_NBITERNOERR,		0x04 },
+	{ STV090x_GAINLLR_NF4,		0x0C },
+	{ STV090x_GAINLLR_NF5,		0x0F },
+	{ STV090x_GAINLLR_NF6,		0x11 },
+	{ STV090x_GAINLLR_NF7,		0x14 },
+	{ STV090x_GAINLLR_NF8,		0x17 },
+	{ STV090x_GAINLLR_NF9,		0x19 },
+	{ STV090x_GAINLLR_NF10,		0x20 },
+	{ STV090x_GAINLLR_NF11,		0x21 },
+	{ STV090x_GAINLLR_NF12,		0x0D },
+	{ STV090x_GAINLLR_NF13,		0x0F },
+	{ STV090x_GAINLLR_NF14,		0x13 },
+	{ STV090x_GAINLLR_NF15,		0x1A },
+	{ STV090x_GAINLLR_NF16,		0x1F },
+	{ STV090x_GAINLLR_NF17,		0x21 },
+	{ STV090x_RCCFGH,		0x20 },
+	{ STV090x_P1_FECM,		0x01 }, /* disable DSS modes */
+	{ STV090x_P2_FECM,		0x01 }, /* disable DSS modes */
+	{ STV090x_P1_PRVIT,		0x2F }, /* disable PR 6/7 */
+	{ STV090x_P2_PRVIT,		0x2F }, /* disable PR 6/7 */
+};
+
+static struct stv090x_reg stv0903_initval[] = {
+	{ STV090x_OUTCFG,		0x00 },
+	{ STV090x_AGCRF1CFG,		0x11 },
+	{ STV090x_STOPCLK1,		0x48 },
+	{ STV090x_STOPCLK2,		0x14 },
+	{ STV090x_TSTTNR1,		0x27 },
+	{ STV090x_TSTTNR2,		0x21 },
+	{ STV090x_P1_DISTXCTL,		0x22 },
+	{ STV090x_P1_F22TX,		0xc0 },
+	{ STV090x_P1_F22RX,		0xc0 },
+	{ STV090x_P1_DISRXCTL,		0x00 },
+	{ STV090x_P1_DMDCFGMD,		0xF9 },
+	{ STV090x_P1_DEMOD,		0x08 },
+	{ STV090x_P1_DMDCFG3,		0xc4 },
+	{ STV090x_P1_CARFREQ,		0xed },
+	{ STV090x_P1_TNRCFG2,		0x82 },
+	{ STV090x_P1_LDT,		0xd0 },
+	{ STV090x_P1_LDT2,		0xb8 },
+	{ STV090x_P1_TMGCFG,		0xd2 },
+	{ STV090x_P1_TMGTHRISE,		0x20 },
+	{ STV090x_P1_TMGTHFALL,		0x00 },
+	{ STV090x_P1_SFRUPRATIO,	0xf0 },
+	{ STV090x_P1_SFRLOWRATIO,	0x70 },
+	{ STV090x_P1_TSCFGL,		0x20 },
+	{ STV090x_P1_FECSPY,		0x88 },
+	{ STV090x_P1_FSPYDATA,		0x3a },
+	{ STV090x_P1_FBERCPT4,		0x00 },
+	{ STV090x_P1_FSPYBER,		0x10 },
+	{ STV090x_P1_ERRCTRL1,		0x35 },
+	{ STV090x_P1_ERRCTRL2,		0xc1 },
+	{ STV090x_P1_CFRICFG,		0xf8 },
+	{ STV090x_P1_NOSCFG,		0x1c },
+	{ STV090x_P1_DMDTOM,		0x20 },
+	{ STV090x_P1_CORRELMANT,	0x70 },
+	{ STV090x_P1_CORRELABS,		0x88 },
+	{ STV090x_P1_AGC2O,		0x5b },
+	{ STV090x_P1_AGC2REF,		0x38 },
+	{ STV090x_P1_CARCFG,		0xe4 },
+	{ STV090x_P1_ACLC,		0x1A },
+	{ STV090x_P1_BCLC,		0x09 },
+	{ STV090x_P1_CARHDR,		0x08 },
+	{ STV090x_P1_KREFTMG,		0xc1 },
+	{ STV090x_P1_SFRSTEP,		0x58 },
+	{ STV090x_P1_TMGCFG2,		0x01 },
+	{ STV090x_P1_CAR2CFG,		0x26 },
+	{ STV090x_P1_BCLC2S2Q,		0x86 },
+	{ STV090x_P1_BCLC2S28,		0x86 },
+	{ STV090x_P1_SMAPCOEF7,		0x77 },
+	{ STV090x_P1_SMAPCOEF6,		0x85 },
+	{ STV090x_P1_SMAPCOEF5,		0x77 },
+	{ STV090x_P1_DMDCFG2,		0x3b },
+	{ STV090x_P1_MODCODLST0,	0xff },
+	{ STV090x_P1_MODCODLST1,	0xff },
+	{ STV090x_P1_MODCODLST2,	0xff },
+	{ STV090x_P1_MODCODLST3,	0xff },
+	{ STV090x_P1_MODCODLST4,	0xff },
+	{ STV090x_P1_MODCODLST5,	0xff },
+	{ STV090x_P1_MODCODLST6,	0xff },
+	{ STV090x_P1_MODCODLST7,	0xcc },
+	{ STV090x_P1_MODCODLST8,	0xcc },
+	{ STV090x_P1_MODCODLST9,	0xcc },
+	{ STV090x_P1_MODCODLSTA,	0xcc },
+	{ STV090x_P1_MODCODLSTB,	0xcc },
+	{ STV090x_P1_MODCODLSTC,	0xcc },
+	{ STV090x_P1_MODCODLSTD,	0xcc },
+	{ STV090x_P1_MODCODLSTE,	0xcc },
+	{ STV090x_P1_MODCODLSTF,	0xcf },
+	{ STV090x_GENCFG,		0x1c },
+	{ STV090x_NBITER_NF4,		0x37 },
+	{ STV090x_NBITER_NF5,		0x29 },
+	{ STV090x_NBITER_NF6,		0x37 },
+	{ STV090x_NBITER_NF7,		0x33 },
+	{ STV090x_NBITER_NF8,		0x31 },
+	{ STV090x_NBITER_NF9,		0x2f },
+	{ STV090x_NBITER_NF10,		0x39 },
+	{ STV090x_NBITER_NF11,		0x3a },
+	{ STV090x_NBITER_NF12,		0x29 },
+	{ STV090x_NBITER_NF13,		0x37 },
+	{ STV090x_NBITER_NF14,		0x33 },
+	{ STV090x_NBITER_NF15,		0x2f },
+	{ STV090x_NBITER_NF16,		0x39 },
+	{ STV090x_NBITER_NF17,		0x3a },
+	{ STV090x_NBITERNOERR,		0x04 },
+	{ STV090x_GAINLLR_NF4,		0x0C },
+	{ STV090x_GAINLLR_NF5,		0x0F },
+	{ STV090x_GAINLLR_NF6,		0x11 },
+	{ STV090x_GAINLLR_NF7,		0x14 },
+	{ STV090x_GAINLLR_NF8,		0x17 },
+	{ STV090x_GAINLLR_NF9,		0x19 },
+	{ STV090x_GAINLLR_NF10,		0x20 },
+	{ STV090x_GAINLLR_NF11,		0x21 },
+	{ STV090x_GAINLLR_NF12,		0x0D },
+	{ STV090x_GAINLLR_NF13,		0x0F },
+	{ STV090x_GAINLLR_NF14,		0x13 },
+	{ STV090x_GAINLLR_NF15,		0x1A },
+	{ STV090x_GAINLLR_NF16,		0x1F },
+	{ STV090x_GAINLLR_NF17,		0x21 },
+	{ STV090x_RCCFGH,		0x20 },
+	{ STV090x_P1_FECM,		0x01 }, /*disable the DSS mode */
+	{ STV090x_P1_PRVIT,		0x2f }  /*disable puncture rate 6/7*/
+};
+
+static struct stv090x_reg stv0900_cut20_val[] = {
+
+	{ STV090x_P2_DMDCFG3,		0xe8 },
+	{ STV090x_P2_DMDCFG4,		0x10 },
+	{ STV090x_P2_CARFREQ,		0x38 },
+	{ STV090x_P2_CARHDR,		0x20 },
+	{ STV090x_P2_KREFTMG,		0x5a },
+	{ STV090x_P2_SMAPCOEF7,		0x06 },
+	{ STV090x_P2_SMAPCOEF6,		0x00 },
+	{ STV090x_P2_SMAPCOEF5,		0x04 },
+	{ STV090x_P2_NOSCFG,		0x0c },
+	{ STV090x_P1_DMDCFG3,		0xe8 },
+	{ STV090x_P1_DMDCFG4,		0x10 },
+	{ STV090x_P1_CARFREQ,		0x38 },
+	{ STV090x_P1_CARHDR,		0x20 },
+	{ STV090x_P1_KREFTMG,		0x5a },
+	{ STV090x_P1_SMAPCOEF7,		0x06 },
+	{ STV090x_P1_SMAPCOEF6,		0x00 },
+	{ STV090x_P1_SMAPCOEF5,		0x04 },
+	{ STV090x_P1_NOSCFG,		0x0c },
+	{ STV090x_GAINLLR_NF4,		0x21 },
+	{ STV090x_GAINLLR_NF5,		0x21 },
+	{ STV090x_GAINLLR_NF6,		0x20 },
+	{ STV090x_GAINLLR_NF7,		0x1F },
+	{ STV090x_GAINLLR_NF8,		0x1E },
+	{ STV090x_GAINLLR_NF9,		0x1E },
+	{ STV090x_GAINLLR_NF10,		0x1D },
+	{ STV090x_GAINLLR_NF11,		0x1B },
+	{ STV090x_GAINLLR_NF12,		0x20 },
+	{ STV090x_GAINLLR_NF13,		0x20 },
+	{ STV090x_GAINLLR_NF14,		0x20 },
+	{ STV090x_GAINLLR_NF15,		0x20 },
+	{ STV090x_GAINLLR_NF16,		0x20 },
+	{ STV090x_GAINLLR_NF17,		0x21 },
+};
+
+static struct stv090x_reg stv0903_cut20_val[] = {
+	{ STV090x_P1_DMDCFG3,		0xe8 },
+	{ STV090x_P1_DMDCFG4,		0x10 },
+	{ STV090x_P1_CARFREQ,		0x38 },
+	{ STV090x_P1_CARHDR,		0x20 },
+	{ STV090x_P1_KREFTMG,		0x5a },
+	{ STV090x_P1_SMAPCOEF7,		0x06 },
+	{ STV090x_P1_SMAPCOEF6,		0x00 },
+	{ STV090x_P1_SMAPCOEF5,		0x04 },
+	{ STV090x_P1_NOSCFG,		0x0c },
+	{ STV090x_GAINLLR_NF4,		0x21 },
+	{ STV090x_GAINLLR_NF5,		0x21 },
+	{ STV090x_GAINLLR_NF6,		0x20 },
+	{ STV090x_GAINLLR_NF7,		0x1F },
+	{ STV090x_GAINLLR_NF8,		0x1E },
+	{ STV090x_GAINLLR_NF9,		0x1E },
+	{ STV090x_GAINLLR_NF10,		0x1D },
+	{ STV090x_GAINLLR_NF11,		0x1B },
+	{ STV090x_GAINLLR_NF12,		0x20 },
+	{ STV090x_GAINLLR_NF13,		0x20 },
+	{ STV090x_GAINLLR_NF14,		0x20 },
+	{ STV090x_GAINLLR_NF15,		0x20 },
+	{ STV090x_GAINLLR_NF16,		0x20 },
+	{ STV090x_GAINLLR_NF17,		0x21 }
+};
+
+/* Cut 2.0 Long Frame Tracking CR loop */
+static struct stv090x_long_frame_crloop stv090x_s2_crl_cut20[] = {
+	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+	{ STV090x_QPSK_12,  0x1f, 0x3f, 0x1e, 0x3f, 0x3d, 0x1f, 0x3d, 0x3e, 0x3d, 0x1e },
+	{ STV090x_QPSK_35,  0x2f, 0x3f, 0x2e, 0x2f, 0x3d, 0x0f, 0x0e, 0x2e, 0x3d, 0x0e },
+	{ STV090x_QPSK_23,  0x2f, 0x3f, 0x2e, 0x2f, 0x0e, 0x0f, 0x0e, 0x1e, 0x3d, 0x3d },
+	{ STV090x_QPSK_34,  0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+	{ STV090x_QPSK_45,  0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+	{ STV090x_QPSK_56,  0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+	{ STV090x_QPSK_89,  0x3f, 0x3f, 0x3e, 0x1f, 0x1e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+	{ STV090x_QPSK_910, 0x3f, 0x3f, 0x3e, 0x1f, 0x1e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+	{ STV090x_8PSK_35,  0x3c, 0x3e, 0x1c, 0x2e, 0x0c, 0x1e, 0x2b, 0x2d, 0x1b, 0x1d },
+	{ STV090x_8PSK_23,  0x1d, 0x3e, 0x3c, 0x2e, 0x2c, 0x1e, 0x0c, 0x2d, 0x2b, 0x1d },
+	{ STV090x_8PSK_34,  0x0e, 0x3e, 0x3d, 0x2e, 0x0d, 0x1e, 0x2c, 0x2d, 0x0c, 0x1d },
+	{ STV090x_8PSK_56,  0x2e, 0x3e, 0x1e, 0x2e, 0x2d, 0x1e, 0x3c, 0x2d, 0x2c, 0x1d },
+	{ STV090x_8PSK_89,  0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x0d, 0x2d, 0x3c, 0x1d },
+	{ STV090x_8PSK_910, 0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x1d, 0x2d, 0x0d, 0x1d }
+};
+
+/* Cut 3.0 Long Frame Tracking CR loop */
+static	struct stv090x_long_frame_crloop stv090x_s2_crl_cut30[] = {
+	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+	{ STV090x_QPSK_12,  0x3c, 0x2c, 0x0c, 0x2c, 0x1b, 0x2c, 0x1b, 0x1c, 0x0b, 0x3b },
+	{ STV090x_QPSK_35,  0x0d, 0x0d, 0x0c, 0x0d, 0x1b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b },
+	{ STV090x_QPSK_23,  0x1d, 0x0d, 0x0c, 0x1d, 0x2b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b },
+	{ STV090x_QPSK_34,  0x1d, 0x1d, 0x0c, 0x1d, 0x2b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b },
+	{ STV090x_QPSK_45,  0x2d, 0x1d, 0x1c, 0x1d, 0x2b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
+	{ STV090x_QPSK_56,  0x2d, 0x1d, 0x1c, 0x1d, 0x2b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
+	{ STV090x_QPSK_89,  0x3d, 0x2d, 0x1c, 0x1d, 0x3b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
+	{ STV090x_QPSK_910, 0x3d, 0x2d, 0x1c, 0x1d, 0x3b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
+	{ STV090x_8PSK_35,  0x39, 0x29, 0x39, 0x19, 0x19, 0x19, 0x19, 0x19, 0x09, 0x19 },
+	{ STV090x_8PSK_23,  0x2a, 0x39, 0x1a, 0x0a, 0x39, 0x0a, 0x29, 0x39, 0x29, 0x0a },
+	{ STV090x_8PSK_34,  0x2b, 0x3a, 0x1b, 0x1b, 0x3a, 0x1b, 0x1a, 0x0b, 0x1a, 0x3a },
+	{ STV090x_8PSK_56,  0x0c, 0x1b, 0x3b, 0x3b, 0x1b, 0x3b, 0x3a, 0x3b, 0x3a, 0x1b },
+	{ STV090x_8PSK_89,  0x0d, 0x3c, 0x2c, 0x2c, 0x2b, 0x0c, 0x0b, 0x3b, 0x0b, 0x1b },
+	{ STV090x_8PSK_910, 0x0d, 0x0d, 0x2c, 0x3c, 0x3b, 0x1c, 0x0b, 0x3b, 0x0b, 0x1b }
+};
+
+/* Cut 2.0 Long Frame Tracking CR Loop */
+static struct stv090x_long_frame_crloop stv090x_s2_apsk_crl_cut20[] = {
+	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+	{ STV090x_16APSK_23,  0x0c, 0x0c, 0x0c, 0x0c, 0x1d, 0x0c, 0x3c, 0x0c, 0x2c, 0x0c },
+	{ STV090x_16APSK_34,  0x0c, 0x0c, 0x0c, 0x0c, 0x0e, 0x0c, 0x2d, 0x0c, 0x1d, 0x0c },
+	{ STV090x_16APSK_45,  0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x0c, 0x3d, 0x0c, 0x2d, 0x0c },
+	{ STV090x_16APSK_56,  0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x0c, 0x3d, 0x0c, 0x2d, 0x0c },
+	{ STV090x_16APSK_89,  0x0c, 0x0c, 0x0c, 0x0c, 0x2e, 0x0c, 0x0e, 0x0c, 0x3d, 0x0c },
+	{ STV090x_16APSK_910, 0x0c, 0x0c, 0x0c, 0x0c, 0x2e, 0x0c, 0x0e, 0x0c, 0x3d, 0x0c },
+	{ STV090x_32APSK_34,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
+	{ STV090x_32APSK_45,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
+	{ STV090x_32APSK_56,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
+	{ STV090x_32APSK_89,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
+	{ STV090x_32APSK_910, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }
+};
+
+/* Cut 3.0 Long Frame Tracking CR Loop */
+static struct stv090x_long_frame_crloop	stv090x_s2_apsk_crl_cut30[] = {
+	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+	{ STV090x_16APSK_23,  0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x0a, 0x3a, 0x0a, 0x2a, 0x0a },
+	{ STV090x_16APSK_34,  0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0a, 0x3b, 0x0a, 0x1b, 0x0a },
+	{ STV090x_16APSK_45,  0x0a, 0x0a, 0x0a, 0x0a, 0x1b, 0x0a, 0x3b, 0x0a, 0x2b, 0x0a },
+	{ STV090x_16APSK_56,  0x0a, 0x0a, 0x0a, 0x0a, 0x1b, 0x0a, 0x3b, 0x0a, 0x2b, 0x0a },
+	{ STV090x_16APSK_89,  0x0a, 0x0a, 0x0a, 0x0a, 0x2b, 0x0a, 0x0c, 0x0a, 0x3b, 0x0a },
+	{ STV090x_16APSK_910, 0x0a, 0x0a, 0x0a, 0x0a, 0x2b, 0x0a, 0x0c, 0x0a, 0x3b, 0x0a },
+	{ STV090x_32APSK_34,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
+	{ STV090x_32APSK_45,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
+	{ STV090x_32APSK_56,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
+	{ STV090x_32APSK_89,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
+	{ STV090x_32APSK_910, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }
+};
+
+static struct stv090x_long_frame_crloop stv090x_s2_lowqpsk_crl_cut20[] = {
+	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+	{ STV090x_QPSK_14,  0x0f, 0x3f, 0x0e, 0x3f, 0x2d, 0x2f, 0x2d, 0x1f, 0x3d, 0x3e },
+	{ STV090x_QPSK_13,  0x0f, 0x3f, 0x0e, 0x3f, 0x2d, 0x2f, 0x3d, 0x0f, 0x3d, 0x2e },
+	{ STV090x_QPSK_25,  0x1f, 0x3f, 0x1e, 0x3f, 0x3d, 0x1f, 0x3d, 0x3e, 0x3d, 0x2e }
+};
+
+static struct stv090x_long_frame_crloop	stv090x_s2_lowqpsk_crl_cut30[] = {
+	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+	{ STV090x_QPSK_14,  0x0c, 0x3c, 0x0b, 0x3c, 0x2a, 0x2c, 0x2a, 0x1c, 0x3a, 0x3b },
+	{ STV090x_QPSK_13,  0x0c, 0x3c, 0x0b, 0x3c, 0x2a, 0x2c, 0x3a, 0x0c, 0x3a, 0x2b },
+	{ STV090x_QPSK_25,  0x1c, 0x3c, 0x1b, 0x3c, 0x3a, 0x1c, 0x3a, 0x3b, 0x3a, 0x2b }
+};
+
+/* Cut 2.0 Short Frame Tracking CR Loop */
+static struct stv090x_short_frame_crloop stv090x_s2_short_crl_cut20[] = {
+	/* MODCOD	  2M    5M    10M   20M   30M */
+	{ STV090x_QPSK,   0x2f, 0x2e, 0x0e, 0x0e, 0x3d },
+	{ STV090x_8PSK,   0x3e, 0x0e, 0x2d, 0x0d, 0x3c },
+	{ STV090x_16APSK, 0x1e, 0x1e, 0x1e, 0x3d, 0x2d },
+	{ STV090x_32APSK, 0x1e, 0x1e, 0x1e, 0x3d, 0x2d }
+};
+
+/* Cut 3.0 Short Frame Tracking CR Loop */
+static struct stv090x_short_frame_crloop stv090x_s2_short_crl_cut30[] = {
+	/* MODCOD  	  2M	5M    10M   20M	  30M */
+	{ STV090x_QPSK,   0x2C, 0x2B, 0x0B, 0x0B, 0x3A },
+	{ STV090x_8PSK,   0x3B, 0x0B, 0x2A, 0x0A, 0x39 },
+	{ STV090x_16APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A },
+	{ STV090x_32APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A }
+};
+
+static inline s32 comp2(s32 __x, s32 __width)
+{
+	if (__width == 32)
+		return __x;
+	else
+		return (__x >= (1 << (__width - 1))) ? (__x - (1 << __width)) : __x;
+}
+
+static int stv090x_read_reg(struct stv090x_state *state, unsigned int reg)
+{
+	const struct stv090x_config *config = state->config;
+	int ret;
+
+	u8 b0[] = { reg >> 8, reg & 0xff };
+	u8 buf;
+
+	struct i2c_msg msg[] = {
+		{ .addr	= config->address, .flags	= 0, 		.buf = b0,   .len = 2 },
+		{ .addr	= config->address, .flags	= I2C_M_RD,	.buf = &buf, .len = 1 }
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+	if (ret != 2) {
+		if (ret != -ERESTARTSYS)
+			dprintk(FE_ERROR, 1,
+				"Read error, Reg=[0x%02x], Status=%d",
+				reg, ret);
+
+		return ret < 0 ? ret : -EREMOTEIO;
+	}
+	if (unlikely(*state->verbose >= FE_DEBUGREG))
+		dprintk(FE_ERROR, 1, "Reg=[0x%02x], data=%02x",
+			reg, buf);
+
+	return (unsigned int) buf;
+}
+
+static int stv090x_write_regs(struct stv090x_state *state, unsigned int reg, u8 *data, u32 count)
+{
+	const struct stv090x_config *config = state->config;
+	int ret;
+	u8 buf[2 + count];
+	struct i2c_msg i2c_msg = { .addr = config->address, .flags = 0, .buf = buf, .len = 2 + count };
+
+	buf[0] = reg >> 8;
+	buf[1] = reg & 0xff;
+	memcpy(&buf[2], data, count);
+
+	if (unlikely(*state->verbose >= FE_DEBUGREG)) {
+		int i;
+
+		printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg);
+		for (i = 0; i < count; i++)
+			printk(" %02x", data[i]);
+		printk("\n");
+	}
+
+	ret = i2c_transfer(state->i2c, &i2c_msg, 1);
+	if (ret != 1) {
+		if (ret != -ERESTARTSYS)
+			dprintk(FE_ERROR, 1, "Reg=[0x%04x], Data=[0x%02x ...], Count=%u, Status=%d",
+				reg, data[0], count, ret);
+		return ret < 0 ? ret : -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int stv090x_write_reg(struct stv090x_state *state, unsigned int reg, u8 data)
+{
+	return stv090x_write_regs(state, reg, &data, 1);
+}
+
+static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable)
+{
+	u32 reg;
+
+	/*
+	 * NOTE! A lock is used as a FSM to control the state in which
+	 * access is serialized between two tuners on the same demod.
+	 * This has nothing to do with a lock to protect a critical section
+	 * which may in some other cases be confused with protecting I/O
+	 * access to the demodulator gate.
+	 * In case of any error, the lock is unlocked and exit within the
+	 * relevant operations themselves.
+	 */
+	if (enable) {
+		if (state->config->tuner_i2c_lock)
+			state->config->tuner_i2c_lock(&state->frontend, 1);
+		else
+			mutex_lock(&state->internal->tuner_lock);
+	}
+
+	reg = STV090x_READ_DEMOD(state, I2CRPT);
+	if (enable) {
+		dprintk(FE_DEBUG, 1, "Enable Gate");
+		STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 1);
+		if (STV090x_WRITE_DEMOD(state, I2CRPT, reg) < 0)
+			goto err;
+
+	} else {
+		dprintk(FE_DEBUG, 1, "Disable Gate");
+		STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 0);
+		if ((STV090x_WRITE_DEMOD(state, I2CRPT, reg)) < 0)
+			goto err;
+	}
+
+	if (!enable) {
+		if (state->config->tuner_i2c_lock)
+			state->config->tuner_i2c_lock(&state->frontend, 0);
+		else
+			mutex_unlock(&state->internal->tuner_lock);
+	}
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	if (state->config->tuner_i2c_lock)
+		state->config->tuner_i2c_lock(&state->frontend, 0);
+	else
+		mutex_unlock(&state->internal->tuner_lock);
+	return -1;
+}
+
+static void stv090x_get_lock_tmg(struct stv090x_state *state)
+{
+	switch (state->algo) {
+	case STV090x_BLIND_SEARCH:
+		dprintk(FE_DEBUG, 1, "Blind Search");
+		if (state->srate <= 1500000) {  /*10Msps< SR <=15Msps*/
+			state->DemodTimeout = 1500;
+			state->FecTimeout = 400;
+		} else if (state->srate <= 5000000) {  /*10Msps< SR <=15Msps*/
+			state->DemodTimeout = 1000;
+			state->FecTimeout = 300;
+		} else {  /*SR >20Msps*/
+			state->DemodTimeout = 700;
+			state->FecTimeout = 100;
+		}
+		break;
+
+	case STV090x_COLD_SEARCH:
+	case STV090x_WARM_SEARCH:
+	default:
+		dprintk(FE_DEBUG, 1, "Normal Search");
+		if (state->srate <= 1000000) {  /*SR <=1Msps*/
+			state->DemodTimeout = 4500;
+			state->FecTimeout = 1700;
+		} else if (state->srate <= 2000000) { /*1Msps < SR <= 2Msps */
+			state->DemodTimeout = 2500;
+			state->FecTimeout = 1100;
+		} else if (state->srate <= 5000000) { /*2Msps < SR <= 5Msps */
+			state->DemodTimeout = 1000;
+			state->FecTimeout = 550;
+		} else if (state->srate <= 10000000) { /*5Msps < SR <= 10Msps */
+			state->DemodTimeout = 700;
+			state->FecTimeout = 250;
+		} else if (state->srate <= 20000000) { /*10Msps < SR <= 20Msps */
+			state->DemodTimeout = 400;
+			state->FecTimeout = 130;
+		} else {   /*SR >20Msps*/
+			state->DemodTimeout = 300;
+			state->FecTimeout = 100;
+		}
+		break;
+	}
+
+	if (state->algo == STV090x_WARM_SEARCH)
+		state->DemodTimeout /= 2;
+}
+
+static int stv090x_set_srate(struct stv090x_state *state, u32 srate)
+{
+	u32 sym;
+
+	if (srate > 60000000) {
+		sym  = (srate << 4); /* SR * 2^16 / master_clk */
+		sym /= (state->internal->mclk >> 12);
+	} else if (srate > 6000000) {
+		sym  = (srate << 6);
+		sym /= (state->internal->mclk >> 10);
+	} else {
+		sym  = (srate << 9);
+		sym /= (state->internal->mclk >> 7);
+	}
+
+	if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0x7f) < 0) /* MSB */
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, SFRINIT0, (sym & 0xff)) < 0) /* LSB */
+		goto err;
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_set_max_srate(struct stv090x_state *state, u32 clk, u32 srate)
+{
+	u32 sym;
+
+	srate = 105 * (srate / 100);
+	if (srate > 60000000) {
+		sym  = (srate << 4); /* SR * 2^16 / master_clk */
+		sym /= (state->internal->mclk >> 12);
+	} else if (srate > 6000000) {
+		sym  = (srate << 6);
+		sym /= (state->internal->mclk >> 10);
+	} else {
+		sym  = (srate << 9);
+		sym /= (state->internal->mclk >> 7);
+	}
+
+	if (sym < 0x7fff) {
+		if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0) /* MSB */
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0) /* LSB */
+			goto err;
+	} else {
+		if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x7f) < 0) /* MSB */
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xff) < 0) /* LSB */
+			goto err;
+	}
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_set_min_srate(struct stv090x_state *state, u32 clk, u32 srate)
+{
+	u32 sym;
+
+	srate = 95 * (srate / 100);
+	if (srate > 60000000) {
+		sym  = (srate << 4); /* SR * 2^16 / master_clk */
+		sym /= (state->internal->mclk >> 12);
+	} else if (srate > 6000000) {
+		sym  = (srate << 6);
+		sym /= (state->internal->mclk >> 10);
+	} else {
+		sym  = (srate << 9);
+		sym /= (state->internal->mclk >> 7);
+	}
+
+	if (STV090x_WRITE_DEMOD(state, SFRLOW1, ((sym >> 8) & 0x7f)) < 0) /* MSB */
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, SFRLOW0, (sym & 0xff)) < 0) /* LSB */
+		goto err;
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static u32 stv090x_car_width(u32 srate, enum stv090x_rolloff rolloff)
+{
+	u32 ro;
+
+	switch (rolloff) {
+	case STV090x_RO_20:
+		ro = 20;
+		break;
+	case STV090x_RO_25:
+		ro = 25;
+		break;
+	case STV090x_RO_35:
+	default:
+		ro = 35;
+		break;
+	}
+
+	return srate + (srate * ro) / 100;
+}
+
+static int stv090x_set_vit_thacq(struct stv090x_state *state)
+{
+	if (STV090x_WRITE_DEMOD(state, VTH12, 0x96) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH23, 0x64) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH34, 0x36) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH56, 0x23) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH67, 0x1e) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH78, 0x19) < 0)
+		goto err;
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_set_vit_thtracq(struct stv090x_state *state)
+{
+	if (STV090x_WRITE_DEMOD(state, VTH12, 0xd0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH23, 0x7d) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH34, 0x53) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH56, 0x2f) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH67, 0x24) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH78, 0x1f) < 0)
+		goto err;
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_set_viterbi(struct stv090x_state *state)
+{
+	switch (state->search_mode) {
+	case STV090x_SEARCH_AUTO:
+		if (STV090x_WRITE_DEMOD(state, FECM, 0x10) < 0) /* DVB-S and DVB-S2 */
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, PRVIT, 0x3f) < 0) /* all puncture rate */
+			goto err;
+		break;
+	case STV090x_SEARCH_DVBS1:
+		if (STV090x_WRITE_DEMOD(state, FECM, 0x00) < 0) /* disable DSS */
+			goto err;
+		switch (state->fec) {
+		case STV090x_PR12:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x01) < 0)
+				goto err;
+			break;
+
+		case STV090x_PR23:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x02) < 0)
+				goto err;
+			break;
+
+		case STV090x_PR34:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x04) < 0)
+				goto err;
+			break;
+
+		case STV090x_PR56:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x08) < 0)
+				goto err;
+			break;
+
+		case STV090x_PR78:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x20) < 0)
+				goto err;
+			break;
+
+		default:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x2f) < 0) /* all */
+				goto err;
+			break;
+		}
+		break;
+	case STV090x_SEARCH_DSS:
+		if (STV090x_WRITE_DEMOD(state, FECM, 0x80) < 0)
+			goto err;
+		switch (state->fec) {
+		case STV090x_PR12:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x01) < 0)
+				goto err;
+			break;
+
+		case STV090x_PR23:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x02) < 0)
+				goto err;
+			break;
+
+		case STV090x_PR67:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x10) < 0)
+				goto err;
+			break;
+
+		default:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x13) < 0) /* 1/2, 2/3, 6/7 */
+				goto err;
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_stop_modcod(struct stv090x_state *state)
+{
+	if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xff) < 0)
+		goto err;
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_activate_modcod(struct stv090x_state *state)
+{
+	if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xfc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xcf) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_activate_modcod_single(struct stv090x_state *state)
+{
+
+	if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xf0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0x0f) < 0)
+		goto err;
+
+	return 0;
+
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_vitclk_ctl(struct stv090x_state *state, int enable)
+{
+	u32 reg;
+
+	switch (state->demod) {
+	case STV090x_DEMODULATOR_0:
+		mutex_lock(&state->internal->demod_lock);
+		reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+		STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, enable);
+		if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+			goto err;
+		mutex_unlock(&state->internal->demod_lock);
+		break;
+
+	case STV090x_DEMODULATOR_1:
+		mutex_lock(&state->internal->demod_lock);
+		reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+		STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, enable);
+		if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+			goto err;
+		mutex_unlock(&state->internal->demod_lock);
+		break;
+
+	default:
+		dprintk(FE_ERROR, 1, "Wrong demodulator!");
+		break;
+	}
+	return 0;
+err:
+	mutex_unlock(&state->internal->demod_lock);
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_dvbs_track_crl(struct stv090x_state *state)
+{
+	if (state->internal->dev_ver >= 0x30) {
+		/* Set ACLC BCLC optimised value vs SR */
+		if (state->srate >= 15000000) {
+			if (STV090x_WRITE_DEMOD(state, ACLC, 0x2b) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, BCLC, 0x1a) < 0)
+				goto err;
+		} else if ((state->srate >= 7000000) && (15000000 > state->srate)) {
+			if (STV090x_WRITE_DEMOD(state, ACLC, 0x0c) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, BCLC, 0x1b) < 0)
+				goto err;
+		} else if (state->srate < 7000000) {
+			if (STV090x_WRITE_DEMOD(state, ACLC, 0x2c) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, BCLC, 0x1c) < 0)
+				goto err;
+		}
+
+	} else {
+		/* Cut 2.0 */
+		if (STV090x_WRITE_DEMOD(state, ACLC, 0x1a) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0)
+			goto err;
+	}
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_delivery_search(struct stv090x_state *state)
+{
+	u32 reg;
+
+	switch (state->search_mode) {
+	case STV090x_SEARCH_DVBS1:
+	case STV090x_SEARCH_DSS:
+		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
+
+		/* Activate Viterbi decoder in legacy search,
+		 * do not use FRESVIT1, might impact VITERBI2
+		 */
+		if (stv090x_vitclk_ctl(state, 0) < 0)
+			goto err;
+
+		if (stv090x_dvbs_track_crl(state) < 0)
+			goto err;
+
+		if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x22) < 0) /* disable DVB-S2 */
+			goto err;
+
+		if (stv090x_set_vit_thacq(state) < 0)
+			goto err;
+		if (stv090x_set_viterbi(state) < 0)
+			goto err;
+		break;
+
+	case STV090x_SEARCH_DVBS2:
+		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
+		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
+		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
+
+		if (stv090x_vitclk_ctl(state, 1) < 0)
+			goto err;
+
+		if (STV090x_WRITE_DEMOD(state, ACLC, 0x1a) < 0) /* stop DVB-S CR loop */
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0)
+			goto err;
+
+		if (state->internal->dev_ver <= 0x20) {
+			/* enable S2 carrier loop */
+			if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0)
+				goto err;
+		} else {
+			/* > Cut 3: Stop carrier 3 */
+			if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x66) < 0)
+				goto err;
+		}
+
+		if (state->demod_mode != STV090x_SINGLE) {
+			/* Cut 2: enable link during search */
+			if (stv090x_activate_modcod(state) < 0)
+				goto err;
+		} else {
+			/* Single demodulator
+			 * Authorize SHORT and LONG frames,
+			 * QPSK, 8PSK, 16APSK and 32APSK
+			 */
+			if (stv090x_activate_modcod_single(state) < 0)
+				goto err;
+		}
+
+		if (stv090x_set_vit_thtracq(state) < 0)
+			goto err;
+		break;
+
+	case STV090x_SEARCH_AUTO:
+	default:
+		/* enable DVB-S2 and DVB-S2 in Auto MODE */
+		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
+		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
+		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
+
+		if (stv090x_vitclk_ctl(state, 0) < 0)
+			goto err;
+
+		if (stv090x_dvbs_track_crl(state) < 0)
+			goto err;
+
+		if (state->internal->dev_ver <= 0x20) {
+			/* enable S2 carrier loop */
+			if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0)
+				goto err;
+		} else {
+			/* > Cut 3: Stop carrier 3 */
+			if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x66) < 0)
+				goto err;
+		}
+
+		if (state->demod_mode != STV090x_SINGLE) {
+			/* Cut 2: enable link during search */
+			if (stv090x_activate_modcod(state) < 0)
+				goto err;
+		} else {
+			/* Single demodulator
+			 * Authorize SHORT and LONG frames,
+			 * QPSK, 8PSK, 16APSK and 32APSK
+			 */
+			if (stv090x_activate_modcod_single(state) < 0)
+				goto err;
+		}
+
+		if (stv090x_set_vit_thacq(state) < 0)
+			goto err;
+
+		if (stv090x_set_viterbi(state) < 0)
+			goto err;
+		break;
+	}
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_start_search(struct stv090x_state *state)
+{
+	u32 reg, freq_abs;
+	s16 freq;
+
+	/* Reset demodulator */
+	reg = STV090x_READ_DEMOD(state, DMDISTATE);
+	STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f);
+	if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0)
+		goto err;
+
+	if (state->internal->dev_ver <= 0x20) {
+		if (state->srate <= 5000000) {
+			if (STV090x_WRITE_DEMOD(state, CARCFG, 0x44) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, CFRUP1, 0x0f) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, CFRUP0, 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, CFRLOW1, 0xf0) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, CFRLOW0, 0x00) < 0)
+				goto err;
+
+			/*enlarge the timing bandwidth for Low SR*/
+			if (STV090x_WRITE_DEMOD(state, RTCS2, 0x68) < 0)
+				goto err;
+		} else {
+			/* If the symbol rate is >5 Msps
+			Set The carrier search up and low to auto mode */
+			if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0)
+				goto err;
+			/*reduce the timing bandwidth for high SR*/
+			if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0)
+				goto err;
+		}
+	} else {
+		/* >= Cut 3 */
+		if (state->srate <= 5000000) {
+			/* enlarge the timing bandwidth for Low SR */
+			STV090x_WRITE_DEMOD(state, RTCS2, 0x68);
+		} else {
+			/* reduce timing bandwidth for high SR */
+			STV090x_WRITE_DEMOD(state, RTCS2, 0x44);
+		}
+
+		/* Set CFR min and max to manual mode */
+		STV090x_WRITE_DEMOD(state, CARCFG, 0x46);
+
+		if (state->algo == STV090x_WARM_SEARCH) {
+			/* WARM Start
+			 * CFR min = -1MHz,
+			 * CFR max = +1MHz
+			 */
+			freq_abs  = 1000 << 16;
+			freq_abs /= (state->internal->mclk / 1000);
+			freq      = (s16) freq_abs;
+		} else {
+			/* COLD Start
+			 * CFR min =- (SearchRange / 2 + 600KHz)
+			 * CFR max = +(SearchRange / 2 + 600KHz)
+			 * (600KHz for the tuner step size)
+			 */
+			freq_abs  = (state->search_range / 2000) + 600;
+			freq_abs  = freq_abs << 16;
+			freq_abs /= (state->internal->mclk / 1000);
+			freq      = (s16) freq_abs;
+		}
+
+		if (STV090x_WRITE_DEMOD(state, CFRUP1, MSB(freq)) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRUP0, LSB(freq)) < 0)
+			goto err;
+
+		freq *= -1;
+
+		if (STV090x_WRITE_DEMOD(state, CFRLOW1, MSB(freq)) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRLOW0, LSB(freq)) < 0)
+			goto err;
+
+	}
+
+	if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0) < 0)
+		goto err;
+
+	if (state->internal->dev_ver >= 0x20) {
+		if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0)
+			goto err;
+
+		if ((state->search_mode == STV090x_SEARCH_DVBS1)	||
+			(state->search_mode == STV090x_SEARCH_DSS)	||
+			(state->search_mode == STV090x_SEARCH_AUTO)) {
+
+			if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x00) < 0)
+				goto err;
+		}
+	}
+
+	if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xe0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xc0) < 0)
+		goto err;
+
+	reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+	STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0);
+	STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0);
+	if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+		goto err;
+	reg = STV090x_READ_DEMOD(state, DMDCFG2);
+	STV090x_SETFIELD_Px(reg, S1S2_SEQUENTIAL_FIELD, 0x0);
+	if (STV090x_WRITE_DEMOD(state, DMDCFG2, reg) < 0)
+		goto err;
+
+	if (STV090x_WRITE_DEMOD(state, RTC, 0x88) < 0)
+		goto err;
+
+	if (state->internal->dev_ver >= 0x20) {
+		/*Frequency offset detector setting*/
+		if (state->srate < 2000000) {
+			if (state->internal->dev_ver <= 0x20) {
+				/* Cut 2 */
+				if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x39) < 0)
+					goto err;
+			} else {
+				/* Cut 3 */
+				if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x89) < 0)
+					goto err;
+			}
+			if (STV090x_WRITE_DEMOD(state, CARHDR, 0x40) < 0)
+				goto err;
+		} else if (state->srate < 10000000) {
+			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4c) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, CARHDR, 0x20) < 0)
+				goto err;
+		} else {
+			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4b) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, CARHDR, 0x20) < 0)
+				goto err;
+		}
+	} else {
+		if (state->srate < 10000000) {
+			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0xef) < 0)
+				goto err;
+		} else {
+			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0xed) < 0)
+				goto err;
+		}
+	}
+
+	switch (state->algo) {
+	case STV090x_WARM_SEARCH:
+		/* The symbol rate and the exact
+		 * carrier Frequency are known
+		 */
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
+			goto err;
+		break;
+
+	case STV090x_COLD_SEARCH:
+		/* The symbol rate is known */
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
+			goto err;
+		break;
+
+	default:
+		break;
+	}
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_get_agc2_min_level(struct stv090x_state *state)
+{
+	u32 agc2_min = 0xffff, agc2 = 0, freq_init, freq_step, reg;
+	s32 i, j, steps, dir;
+
+	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+		goto err;
+	reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+	STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0);
+	STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0);
+	if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+		goto err;
+
+	if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x83) < 0) /* SR = 65 Msps Max */
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xc0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x82) < 0) /* SR= 400 ksps Min */
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, SFRLOW0, 0xa0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0) /* stop acq @ coarse carrier state */
+		goto err;
+	if (stv090x_set_srate(state, 1000000) < 0)
+		goto err;
+
+	steps  = state->search_range / 1000000;
+	if (steps <= 0)
+		steps = 1;
+
+	dir = 1;
+	freq_step = (1000000 * 256) / (state->internal->mclk / 256);
+	freq_init = 0;
+
+	for (i = 0; i < steps; i++) {
+		if (dir > 0)
+			freq_init = freq_init + (freq_step * i);
+		else
+			freq_init = freq_init - (freq_step * i);
+
+		dir *= -1;
+
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod RESET */
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRINIT1, (freq_init >> 8) & 0xff) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRINIT0, freq_init & 0xff) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x58) < 0) /* Demod RESET */
+			goto err;
+		msleep(10);
+
+		agc2 = 0;
+		for (j = 0; j < 10; j++) {
+			agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) |
+				STV090x_READ_DEMOD(state, AGC2I0);
+		}
+		agc2 /= 10;
+		if (agc2 < agc2_min)
+			agc2_min = agc2;
+	}
+
+	return agc2_min;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static u32 stv090x_get_srate(struct stv090x_state *state, u32 clk)
+{
+	u8 r3, r2, r1, r0;
+	s32 srate, int_1, int_2, tmp_1, tmp_2;
+
+	r3 = STV090x_READ_DEMOD(state, SFR3);
+	r2 = STV090x_READ_DEMOD(state, SFR2);
+	r1 = STV090x_READ_DEMOD(state, SFR1);
+	r0 = STV090x_READ_DEMOD(state, SFR0);
+
+	srate = ((r3 << 24) | (r2 << 16) | (r1 <<  8) | r0);
+
+	int_1 = clk >> 16;
+	int_2 = srate >> 16;
+
+	tmp_1 = clk % 0x10000;
+	tmp_2 = srate % 0x10000;
+
+	srate = (int_1 * int_2) +
+		((int_1 * tmp_2) >> 16) +
+		((int_2 * tmp_1) >> 16);
+
+	return srate;
+}
+
+static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
+{
+	struct dvb_frontend *fe = &state->frontend;
+
+	int tmg_lock = 0, i;
+	s32 tmg_cpt = 0, dir = 1, steps, cur_step = 0, freq;
+	u32 srate_coarse = 0, agc2 = 0, car_step = 1200, reg;
+	u32 agc2th;
+
+	if (state->internal->dev_ver >= 0x30)
+		agc2th = 0x2e00;
+	else
+		agc2th = 0x1f00;
+
+	reg = STV090x_READ_DEMOD(state, DMDISTATE);
+	STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f); /* Demod RESET */
+	if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGCFG, 0x12) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xf0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xe0) < 0)
+		goto err;
+	reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+	STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 1);
+	STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0);
+	if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+		goto err;
+
+	if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x83) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xc0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x82) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, SFRLOW0, 0xa0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x50) < 0)
+		goto err;
+
+	if (state->internal->dev_ver >= 0x30) {
+		if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x99) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x98) < 0)
+			goto err;
+
+	} else if (state->internal->dev_ver >= 0x20) {
+		if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x6a) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x95) < 0)
+			goto err;
+	}
+
+	if (state->srate <= 2000000)
+		car_step = 1000;
+	else if (state->srate <= 5000000)
+		car_step = 2000;
+	else if (state->srate <= 12000000)
+		car_step = 3000;
+	else
+		car_step = 5000;
+
+	steps  = -1 + ((state->search_range / 1000) / car_step);
+	steps /= 2;
+	steps  = (2 * steps) + 1;
+	if (steps < 0)
+		steps = 1;
+	else if (steps > 10) {
+		steps = 11;
+		car_step = (state->search_range / 1000) / 10;
+	}
+	cur_step = 0;
+	dir = 1;
+	freq = state->frequency;
+
+	while ((!tmg_lock) && (cur_step < steps)) {
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5f) < 0) /* Demod RESET */
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, SFRINIT1, 0x00) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, SFRINIT0, 0x00) < 0)
+			goto err;
+		/* trigger acquisition */
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x40) < 0)
+			goto err;
+		msleep(50);
+		for (i = 0; i < 10; i++) {
+			reg = STV090x_READ_DEMOD(state, DSTATUS);
+			if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2)
+				tmg_cpt++;
+			agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) |
+				STV090x_READ_DEMOD(state, AGC2I0);
+		}
+		agc2 /= 10;
+		srate_coarse = stv090x_get_srate(state, state->internal->mclk);
+		cur_step++;
+		dir *= -1;
+		if ((tmg_cpt >= 5) && (agc2 < agc2th) &&
+		    (srate_coarse < 50000000) && (srate_coarse > 850000))
+			tmg_lock = 1;
+		else if (cur_step < steps) {
+			if (dir > 0)
+				freq += cur_step * car_step;
+			else
+				freq -= cur_step * car_step;
+
+			/* Setup tuner */
+			if (stv090x_i2c_gate_ctrl(state, 1) < 0)
+				goto err;
+
+			if (state->config->tuner_set_frequency) {
+				if (state->config->tuner_set_frequency(fe, freq) < 0)
+					goto err_gateoff;
+			}
+
+			if (state->config->tuner_set_bandwidth) {
+				if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
+					goto err_gateoff;
+			}
+
+			if (stv090x_i2c_gate_ctrl(state, 0) < 0)
+				goto err;
+
+			msleep(50);
+
+			if (stv090x_i2c_gate_ctrl(state, 1) < 0)
+				goto err;
+
+			if (state->config->tuner_get_status) {
+				if (state->config->tuner_get_status(fe, &reg) < 0)
+					goto err_gateoff;
+			}
+
+			if (reg)
+				dprintk(FE_DEBUG, 1, "Tuner phase locked");
+			else
+				dprintk(FE_DEBUG, 1, "Tuner unlocked");
+
+			if (stv090x_i2c_gate_ctrl(state, 0) < 0)
+				goto err;
+
+		}
+	}
+	if (!tmg_lock)
+		srate_coarse = 0;
+	else
+		srate_coarse = stv090x_get_srate(state, state->internal->mclk);
+
+	return srate_coarse;
+
+err_gateoff:
+	stv090x_i2c_gate_ctrl(state, 0);
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static u32 stv090x_srate_srch_fine(struct stv090x_state *state)
+{
+	u32 srate_coarse, freq_coarse, sym, reg;
+
+	srate_coarse = stv090x_get_srate(state, state->internal->mclk);
+	freq_coarse  = STV090x_READ_DEMOD(state, CFR2) << 8;
+	freq_coarse |= STV090x_READ_DEMOD(state, CFR1);
+	sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
+
+	if (sym < state->srate)
+		srate_coarse = 0;
+	else {
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) /* Demod RESET */
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0x00) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, TMGCFG, 0xd2) < 0)
+			goto err;
+		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+		STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
+
+		if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+			goto err;
+
+		if (state->internal->dev_ver >= 0x30) {
+			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x79) < 0)
+				goto err;
+		} else if (state->internal->dev_ver >= 0x20) {
+			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
+				goto err;
+		}
+
+		if (srate_coarse > 3000000) {
+			sym  = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
+			sym  = (sym / 1000) * 65536;
+			sym /= (state->internal->mclk / 1000);
+			if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0)
+				goto err;
+			sym  = 10 * (srate_coarse / 13); /* SFRLOW = SFR - 30% */
+			sym  = (sym / 1000) * 65536;
+			sym /= (state->internal->mclk / 1000);
+			if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0)
+				goto err;
+			sym  = (srate_coarse / 1000) * 65536;
+			sym /= (state->internal->mclk / 1000);
+			if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0)
+				goto err;
+		} else {
+			sym  = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
+			sym  = (sym / 100) * 65536;
+			sym /= (state->internal->mclk / 100);
+			if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0)
+				goto err;
+			sym  = 10 * (srate_coarse / 14); /* SFRLOW = SFR - 30% */
+			sym  = (sym / 100) * 65536;
+			sym /= (state->internal->mclk / 100);
+			if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0)
+				goto err;
+			sym  = (srate_coarse / 100) * 65536;
+			sym /= (state->internal->mclk / 100);
+			if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0)
+				goto err;
+		}
+		if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x20) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRINIT1, (freq_coarse >> 8) & 0xff) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRINIT0, freq_coarse & 0xff) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) /* trigger acquisition */
+			goto err;
+	}
+
+	return srate_coarse;
+
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_get_dmdlock(struct stv090x_state *state, s32 timeout)
+{
+	s32 timer = 0, lock = 0;
+	u32 reg;
+	u8 stat;
+
+	while ((timer < timeout) && (!lock)) {
+		reg = STV090x_READ_DEMOD(state, DMDSTATE);
+		stat = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD);
+
+		switch (stat) {
+		case 0: /* searching */
+		case 1: /* first PLH detected */
+		default:
+			dprintk(FE_DEBUG, 1, "Demodulator searching ..");
+			lock = 0;
+			break;
+		case 2: /* DVB-S2 mode */
+		case 3: /* DVB-S1/legacy mode */
+			reg = STV090x_READ_DEMOD(state, DSTATUS);
+			lock = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD);
+			break;
+		}
+
+		if (!lock)
+			msleep(10);
+		else
+			dprintk(FE_DEBUG, 1, "Demodulator acquired LOCK");
+
+		timer += 10;
+	}
+	return lock;
+}
+
+static int stv090x_blind_search(struct stv090x_state *state)
+{
+	u32 agc2, reg, srate_coarse;
+	s32 cpt_fail, agc2_ovflw, i;
+	u8 k_ref, k_max, k_min;
+	int coarse_fail = 0;
+	int lock;
+
+	k_max = 110;
+	k_min = 10;
+
+	agc2 = stv090x_get_agc2_min_level(state);
+
+	if (agc2 > STV090x_SEARCH_AGC2_TH(state->internal->dev_ver)) {
+		lock = 0;
+	} else {
+
+		if (state->internal->dev_ver <= 0x20) {
+			if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0)
+				goto err;
+		} else {
+			/* > Cut 3 */
+			if (STV090x_WRITE_DEMOD(state, CARCFG, 0x06) < 0)
+				goto err;
+		}
+
+		if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0)
+			goto err;
+
+		if (state->internal->dev_ver >= 0x20) {
+			if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x00) < 0) /* set viterbi hysteresis */
+				goto err;
+		}
+
+		k_ref = k_max;
+		do {
+			if (STV090x_WRITE_DEMOD(state, KREFTMG, k_ref) < 0)
+				goto err;
+			if (stv090x_srate_srch_coarse(state) != 0) {
+				srate_coarse = stv090x_srate_srch_fine(state);
+				if (srate_coarse != 0) {
+					stv090x_get_lock_tmg(state);
+					lock = stv090x_get_dmdlock(state,
+							state->DemodTimeout);
+				} else {
+					lock = 0;
+				}
+			} else {
+				cpt_fail = 0;
+				agc2_ovflw = 0;
+				for (i = 0; i < 10; i++) {
+					agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) |
+						STV090x_READ_DEMOD(state, AGC2I0);
+					if (agc2 >= 0xff00)
+						agc2_ovflw++;
+					reg = STV090x_READ_DEMOD(state, DSTATUS2);
+					if ((STV090x_GETFIELD_Px(reg, CFR_OVERFLOW_FIELD) == 0x01) &&
+					    (STV090x_GETFIELD_Px(reg, DEMOD_DELOCK_FIELD) == 0x01))
+
+						cpt_fail++;
+				}
+				if ((cpt_fail > 7) || (agc2_ovflw > 7))
+					coarse_fail = 1;
+
+				lock = 0;
+			}
+			k_ref -= 20;
+		} while ((k_ref >= k_min) && (!lock) && (!coarse_fail));
+	}
+
+	return lock;
+
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_chk_tmg(struct stv090x_state *state)
+{
+	u32 reg;
+	s32 tmg_cpt = 0, i;
+	u8 freq, tmg_thh, tmg_thl;
+	int tmg_lock = 0;
+
+	freq = STV090x_READ_DEMOD(state, CARFREQ);
+	tmg_thh = STV090x_READ_DEMOD(state, TMGTHRISE);
+	tmg_thl = STV090x_READ_DEMOD(state, TMGTHFALL);
+	if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0x00) < 0)
+		goto err;
+
+	reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+	STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00); /* stop carrier offset search */
+	if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, RTC, 0x80) < 0)
+		goto err;
+
+	if (STV090x_WRITE_DEMOD(state, RTCS2, 0x40) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x00) < 0)
+		goto err;
+
+	if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0) /* set car ofset to 0 */
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x65) < 0)
+		goto err;
+
+	if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) /* trigger acquisition */
+		goto err;
+	msleep(10);
+
+	for (i = 0; i < 10; i++) {
+		reg = STV090x_READ_DEMOD(state, DSTATUS);
+		if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2)
+			tmg_cpt++;
+		msleep(1);
+	}
+	if (tmg_cpt >= 3)
+		tmg_lock = 1;
+
+	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, RTC, 0x88) < 0) /* DVB-S1 timing */
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, RTCS2, 0x68) < 0) /* DVB-S2 timing */
+		goto err;
+
+	if (STV090x_WRITE_DEMOD(state, CARFREQ, freq) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGTHRISE, tmg_thh) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGTHFALL, tmg_thl) < 0)
+		goto err;
+
+	return	tmg_lock;
+
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd)
+{
+	struct dvb_frontend *fe = &state->frontend;
+
+	u32 reg;
+	s32 car_step, steps, cur_step, dir, freq, timeout_lock;
+	int lock = 0;
+
+	if (state->srate >= 10000000)
+		timeout_lock = timeout_dmd / 3;
+	else
+		timeout_lock = timeout_dmd / 2;
+
+	lock = stv090x_get_dmdlock(state, timeout_lock); /* cold start wait */
+	if (!lock) {
+		if (state->srate >= 10000000) {
+			if (stv090x_chk_tmg(state)) {
+				if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
+					goto err;
+				lock = stv090x_get_dmdlock(state, timeout_dmd);
+			} else {
+				lock = 0;
+			}
+		} else {
+			if (state->srate <= 4000000)
+				car_step = 1000;
+			else if (state->srate <= 7000000)
+				car_step = 2000;
+			else if (state->srate <= 10000000)
+				car_step = 3000;
+			else
+				car_step = 5000;
+
+			steps  = (state->search_range / 1000) / car_step;
+			steps /= 2;
+			steps  = 2 * (steps + 1);
+			if (steps < 0)
+				steps = 2;
+			else if (steps > 12)
+				steps = 12;
+
+			cur_step = 1;
+			dir = 1;
+
+			if (!lock) {
+				freq = state->frequency;
+				state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + state->srate;
+				while ((cur_step <= steps) && (!lock)) {
+					if (dir > 0)
+						freq += cur_step * car_step;
+					else
+						freq -= cur_step * car_step;
+
+					/* Setup tuner */
+					if (stv090x_i2c_gate_ctrl(state, 1) < 0)
+						goto err;
+
+					if (state->config->tuner_set_frequency) {
+						if (state->config->tuner_set_frequency(fe, freq) < 0)
+							goto err_gateoff;
+					}
+
+					if (state->config->tuner_set_bandwidth) {
+						if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
+							goto err_gateoff;
+					}
+
+					if (stv090x_i2c_gate_ctrl(state, 0) < 0)
+						goto err;
+
+					msleep(50);
+
+					if (stv090x_i2c_gate_ctrl(state, 1) < 0)
+						goto err;
+
+					if (state->config->tuner_get_status) {
+						if (state->config->tuner_get_status(fe, &reg) < 0)
+							goto err_gateoff;
+					}
+
+					if (reg)
+						dprintk(FE_DEBUG, 1, "Tuner phase locked");
+					else
+						dprintk(FE_DEBUG, 1, "Tuner unlocked");
+
+					if (stv090x_i2c_gate_ctrl(state, 0) < 0)
+						goto err;
+
+					STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c);
+					if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0)
+						goto err;
+					if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
+						goto err;
+					if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+						goto err;
+					if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
+						goto err;
+					lock = stv090x_get_dmdlock(state, (timeout_dmd / 3));
+
+					dir *= -1;
+					cur_step++;
+				}
+			}
+		}
+	}
+
+	return lock;
+
+err_gateoff:
+	stv090x_i2c_gate_ctrl(state, 0);
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_get_loop_params(struct stv090x_state *state, s32 *freq_inc, s32 *timeout_sw, s32 *steps)
+{
+	s32 timeout, inc, steps_max, srate, car_max;
+
+	srate = state->srate;
+	car_max = state->search_range / 1000;
+	car_max += car_max / 10;
+	car_max  = 65536 * (car_max / 2);
+	car_max /= (state->internal->mclk / 1000);
+
+	if (car_max > 0x4000)
+		car_max = 0x4000 ; /* maxcarrier should be<= +-1/4 Mclk */
+
+	inc  = srate;
+	inc /= state->internal->mclk / 1000;
+	inc *= 256;
+	inc *= 256;
+	inc /= 1000;
+
+	switch (state->search_mode) {
+	case STV090x_SEARCH_DVBS1:
+	case STV090x_SEARCH_DSS:
+		inc *= 3; /* freq step = 3% of srate */
+		timeout = 20;
+		break;
+
+	case STV090x_SEARCH_DVBS2:
+		inc *= 4;
+		timeout = 25;
+		break;
+
+	case STV090x_SEARCH_AUTO:
+	default:
+		inc *= 3;
+		timeout = 25;
+		break;
+	}
+	inc /= 100;
+	if ((inc > car_max) || (inc < 0))
+		inc = car_max / 2; /* increment <= 1/8 Mclk */
+
+	timeout *= 27500; /* 27.5 Msps reference */
+	if (srate > 0)
+		timeout /= (srate / 1000);
+
+	if ((timeout > 100) || (timeout < 0))
+		timeout = 100;
+
+	steps_max = (car_max / inc) + 1; /* min steps = 3 */
+	if ((steps_max > 100) || (steps_max < 0)) {
+		steps_max = 100; /* max steps <= 100 */
+		inc = car_max / steps_max;
+	}
+	*freq_inc = inc;
+	*timeout_sw = timeout;
+	*steps = steps_max;
+
+	return 0;
+}
+
+static int stv090x_chk_signal(struct stv090x_state *state)
+{
+	s32 offst_car, agc2, car_max;
+	int no_signal;
+
+	offst_car  = STV090x_READ_DEMOD(state, CFR2) << 8;
+	offst_car |= STV090x_READ_DEMOD(state, CFR1);
+	offst_car = comp2(offst_car, 16);
+
+	agc2  = STV090x_READ_DEMOD(state, AGC2I1) << 8;
+	agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
+	car_max = state->search_range / 1000;
+
+	car_max += (car_max / 10); /* 10% margin */
+	car_max  = (65536 * car_max / 2);
+	car_max /= state->internal->mclk / 1000;
+
+	if (car_max > 0x4000)
+		car_max = 0x4000;
+
+	if ((agc2 > 0x2000) || (offst_car > 2 * car_max) || (offst_car < -2 * car_max)) {
+		no_signal = 1;
+		dprintk(FE_DEBUG, 1, "No Signal");
+	} else {
+		no_signal = 0;
+		dprintk(FE_DEBUG, 1, "Found Signal");
+	}
+
+	return no_signal;
+}
+
+static int stv090x_search_car_loop(struct stv090x_state *state, s32 inc, s32 timeout, int zigzag, s32 steps_max)
+{
+	int no_signal, lock = 0;
+	s32 cpt_step = 0, offst_freq, car_max;
+	u32 reg;
+
+	car_max  = state->search_range / 1000;
+	car_max += (car_max / 10);
+	car_max  = (65536 * car_max / 2);
+	car_max /= (state->internal->mclk / 1000);
+	if (car_max > 0x4000)
+		car_max = 0x4000;
+
+	if (zigzag)
+		offst_freq = 0;
+	else
+		offst_freq = -car_max + inc;
+
+	do {
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRINIT1, ((offst_freq / 256) & 0xff)) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRINIT0, offst_freq & 0xff) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
+			goto err;
+
+		reg = STV090x_READ_DEMOD(state, PDELCTRL1);
+		STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x1); /* stop DVB-S2 packet delin */
+		if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
+			goto err;
+
+		if (zigzag) {
+			if (offst_freq >= 0)
+				offst_freq = -offst_freq - 2 * inc;
+			else
+				offst_freq = -offst_freq;
+		} else {
+			offst_freq += 2 * inc;
+		}
+
+		cpt_step++;
+
+		lock = stv090x_get_dmdlock(state, timeout);
+		no_signal = stv090x_chk_signal(state);
+
+	} while ((!lock) &&
+		 (!no_signal) &&
+		  ((offst_freq - inc) < car_max) &&
+		  ((offst_freq + inc) > -car_max) &&
+		  (cpt_step < steps_max));
+
+	reg = STV090x_READ_DEMOD(state, PDELCTRL1);
+	STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0);
+	if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
+			goto err;
+
+	return lock;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_sw_algo(struct stv090x_state *state)
+{
+	int no_signal, zigzag, lock = 0;
+	u32 reg;
+
+	s32 dvbs2_fly_wheel;
+	s32 inc, timeout_step, trials, steps_max;
+
+	/* get params */
+	stv090x_get_loop_params(state, &inc, &timeout_step, &steps_max);
+
+	switch (state->search_mode) {
+	case STV090x_SEARCH_DVBS1:
+	case STV090x_SEARCH_DSS:
+		/* accelerate the frequency detector */
+		if (state->internal->dev_ver >= 0x20) {
+			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3B) < 0)
+				goto err;
+		}
+
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x49) < 0)
+			goto err;
+		zigzag = 0;
+		break;
+
+	case STV090x_SEARCH_DVBS2:
+		if (state->internal->dev_ver >= 0x20) {
+			if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
+				goto err;
+		}
+
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x89) < 0)
+			goto err;
+		zigzag = 1;
+		break;
+
+	case STV090x_SEARCH_AUTO:
+	default:
+		/* accelerate the frequency detector */
+		if (state->internal->dev_ver >= 0x20) {
+			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3b) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
+				goto err;
+		}
+
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0xc9) < 0)
+			goto err;
+		zigzag = 0;
+		break;
+	}
+
+	trials = 0;
+	do {
+		lock = stv090x_search_car_loop(state, inc, timeout_step, zigzag, steps_max);
+		no_signal = stv090x_chk_signal(state);
+		trials++;
+
+		/*run the SW search 2 times maximum*/
+		if (lock || no_signal || (trials == 2)) {
+			/*Check if the demod is not losing lock in DVBS2*/
+			if (state->internal->dev_ver >= 0x20) {
+				if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0)
+					goto err;
+			}
+
+			reg = STV090x_READ_DEMOD(state, DMDSTATE);
+			if ((lock) && (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == STV090x_DVBS2)) {
+				/*Check if the demod is not losing lock in DVBS2*/
+				msleep(timeout_step);
+				reg = STV090x_READ_DEMOD(state, DMDFLYW);
+				dvbs2_fly_wheel = STV090x_GETFIELD_Px(reg, FLYWHEEL_CPT_FIELD);
+				if (dvbs2_fly_wheel < 0xd) {	 /*if correct frames is decrementing */
+					msleep(timeout_step);
+					reg = STV090x_READ_DEMOD(state, DMDFLYW);
+					dvbs2_fly_wheel = STV090x_GETFIELD_Px(reg, FLYWHEEL_CPT_FIELD);
+				}
+				if (dvbs2_fly_wheel < 0xd) {
+					/*FALSE lock, The demod is losing lock */
+					lock = 0;
+					if (trials < 2) {
+						if (state->internal->dev_ver >= 0x20) {
+							if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
+								goto err;
+						}
+
+						if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x89) < 0)
+							goto err;
+					}
+				}
+			}
+		}
+	} while ((!lock) && (trials < 2) && (!no_signal));
+
+	return lock;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static enum stv090x_delsys stv090x_get_std(struct stv090x_state *state)
+{
+	u32 reg;
+	enum stv090x_delsys delsys;
+
+	reg = STV090x_READ_DEMOD(state, DMDSTATE);
+	if (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == 2)
+		delsys = STV090x_DVBS2;
+	else if (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == 3) {
+		reg = STV090x_READ_DEMOD(state, FECM);
+		if (STV090x_GETFIELD_Px(reg, DSS_DVB_FIELD) == 1)
+			delsys = STV090x_DSS;
+		else
+			delsys = STV090x_DVBS1;
+	} else {
+		delsys = STV090x_ERROR;
+	}
+
+	return delsys;
+}
+
+/* in Hz */
+static s32 stv090x_get_car_freq(struct stv090x_state *state, u32 mclk)
+{
+	s32 derot, int_1, int_2, tmp_1, tmp_2;
+
+	derot  = STV090x_READ_DEMOD(state, CFR2) << 16;
+	derot |= STV090x_READ_DEMOD(state, CFR1) <<  8;
+	derot |= STV090x_READ_DEMOD(state, CFR0);
+
+	derot = comp2(derot, 24);
+	int_1 = mclk >> 12;
+	int_2 = derot >> 12;
+
+	/* carrier_frequency = MasterClock * Reg / 2^24 */
+	tmp_1 = mclk % 0x1000;
+	tmp_2 = derot % 0x1000;
+
+	derot = (int_1 * int_2) +
+		((int_1 * tmp_2) >> 12) +
+		((int_2 * tmp_1) >> 12);
+
+	return derot;
+}
+
+static int stv090x_get_viterbi(struct stv090x_state *state)
+{
+	u32 reg, rate;
+
+	reg = STV090x_READ_DEMOD(state, VITCURPUN);
+	rate = STV090x_GETFIELD_Px(reg, VIT_CURPUN_FIELD);
+
+	switch (rate) {
+	case 13:
+		state->fec = STV090x_PR12;
+		break;
+
+	case 18:
+		state->fec = STV090x_PR23;
+		break;
+
+	case 21:
+		state->fec = STV090x_PR34;
+		break;
+
+	case 24:
+		state->fec = STV090x_PR56;
+		break;
+
+	case 25:
+		state->fec = STV090x_PR67;
+		break;
+
+	case 26:
+		state->fec = STV090x_PR78;
+		break;
+
+	default:
+		state->fec = STV090x_PRERR;
+		break;
+	}
+
+	return 0;
+}
+
+static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *state)
+{
+	struct dvb_frontend *fe = &state->frontend;
+
+	u8 tmg;
+	u32 reg;
+	s32 i = 0, offst_freq;
+
+	msleep(5);
+
+	if (state->algo == STV090x_BLIND_SEARCH) {
+		tmg = STV090x_READ_DEMOD(state, TMGREG2);
+		STV090x_WRITE_DEMOD(state, SFRSTEP, 0x5c);
+		while ((i <= 50) && (tmg != 0) && (tmg != 0xff)) {
+			tmg = STV090x_READ_DEMOD(state, TMGREG2);
+			msleep(5);
+			i += 5;
+		}
+	}
+	state->delsys = stv090x_get_std(state);
+
+	if (stv090x_i2c_gate_ctrl(state, 1) < 0)
+		goto err;
+
+	if (state->config->tuner_get_frequency) {
+		if (state->config->tuner_get_frequency(fe, &state->frequency) < 0)
+			goto err_gateoff;
+	}
+
+	if (stv090x_i2c_gate_ctrl(state, 0) < 0)
+		goto err;
+
+	offst_freq = stv090x_get_car_freq(state, state->internal->mclk) / 1000;
+	state->frequency += offst_freq;
+
+	if (stv090x_get_viterbi(state) < 0)
+		goto err;
+
+	reg = STV090x_READ_DEMOD(state, DMDMODCOD);
+	state->modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD);
+	state->pilots = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) & 0x01;
+	state->frame_len = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) >> 1;
+	reg = STV090x_READ_DEMOD(state, TMGOBS);
+	state->rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD);
+	reg = STV090x_READ_DEMOD(state, FECM);
+	state->inversion = STV090x_GETFIELD_Px(reg, IQINV_FIELD);
+
+	if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000)) {
+
+		if (stv090x_i2c_gate_ctrl(state, 1) < 0)
+			goto err;
+
+		if (state->config->tuner_get_frequency) {
+			if (state->config->tuner_get_frequency(fe, &state->frequency) < 0)
+				goto err_gateoff;
+		}
+
+		if (stv090x_i2c_gate_ctrl(state, 0) < 0)
+			goto err;
+
+		if (abs(offst_freq) <= ((state->search_range / 2000) + 500))
+			return STV090x_RANGEOK;
+		else if (abs(offst_freq) <= (stv090x_car_width(state->srate, state->rolloff) / 2000))
+			return STV090x_RANGEOK;
+		else
+			return STV090x_OUTOFRANGE; /* Out of Range */
+	} else {
+		if (abs(offst_freq) <= ((state->search_range / 2000) + 500))
+			return STV090x_RANGEOK;
+		else
+			return STV090x_OUTOFRANGE;
+	}
+
+	return STV090x_OUTOFRANGE;
+
+err_gateoff:
+	stv090x_i2c_gate_ctrl(state, 0);
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static u32 stv090x_get_tmgoffst(struct stv090x_state *state, u32 srate)
+{
+	s32 offst_tmg;
+
+	offst_tmg  = STV090x_READ_DEMOD(state, TMGREG2) << 16;
+	offst_tmg |= STV090x_READ_DEMOD(state, TMGREG1) <<  8;
+	offst_tmg |= STV090x_READ_DEMOD(state, TMGREG0);
+
+	offst_tmg = comp2(offst_tmg, 24); /* 2's complement */
+	if (!offst_tmg)
+		offst_tmg = 1;
+
+	offst_tmg  = ((s32) srate * 10) / ((s32) 0x1000000 / offst_tmg);
+	offst_tmg /= 320;
+
+	return offst_tmg;
+}
+
+static u8 stv090x_optimize_carloop(struct stv090x_state *state, enum stv090x_modcod modcod, s32 pilots)
+{
+	u8 aclc = 0x29;
+	s32 i;
+	struct stv090x_long_frame_crloop *car_loop, *car_loop_qpsk_low, *car_loop_apsk_low;
+
+	if (state->internal->dev_ver == 0x20) {
+		car_loop		= stv090x_s2_crl_cut20;
+		car_loop_qpsk_low	= stv090x_s2_lowqpsk_crl_cut20;
+		car_loop_apsk_low	= stv090x_s2_apsk_crl_cut20;
+	} else {
+		/* >= Cut 3 */
+		car_loop		= stv090x_s2_crl_cut30;
+		car_loop_qpsk_low	= stv090x_s2_lowqpsk_crl_cut30;
+		car_loop_apsk_low	= stv090x_s2_apsk_crl_cut30;
+	}
+
+	if (modcod < STV090x_QPSK_12) {
+		i = 0;
+		while ((i < 3) && (modcod != car_loop_qpsk_low[i].modcod))
+			i++;
+
+		if (i >= 3)
+			i = 2;
+
+	} else {
+		i = 0;
+		while ((i < 14) && (modcod != car_loop[i].modcod))
+			i++;
+
+		if (i >= 14) {
+			i = 0;
+			while ((i < 11) && (modcod != car_loop_apsk_low[i].modcod))
+				i++;
+
+			if (i >= 11)
+				i = 10;
+		}
+	}
+
+	if (modcod <= STV090x_QPSK_25) {
+		if (pilots) {
+			if (state->srate <= 3000000)
+				aclc = car_loop_qpsk_low[i].crl_pilots_on_2;
+			else if (state->srate <= 7000000)
+				aclc = car_loop_qpsk_low[i].crl_pilots_on_5;
+			else if (state->srate <= 15000000)
+				aclc = car_loop_qpsk_low[i].crl_pilots_on_10;
+			else if (state->srate <= 25000000)
+				aclc = car_loop_qpsk_low[i].crl_pilots_on_20;
+			else
+				aclc = car_loop_qpsk_low[i].crl_pilots_on_30;
+		} else {
+			if (state->srate <= 3000000)
+				aclc = car_loop_qpsk_low[i].crl_pilots_off_2;
+			else if (state->srate <= 7000000)
+				aclc = car_loop_qpsk_low[i].crl_pilots_off_5;
+			else if (state->srate <= 15000000)
+				aclc = car_loop_qpsk_low[i].crl_pilots_off_10;
+			else if (state->srate <= 25000000)
+				aclc = car_loop_qpsk_low[i].crl_pilots_off_20;
+			else
+				aclc = car_loop_qpsk_low[i].crl_pilots_off_30;
+		}
+
+	} else if (modcod <= STV090x_8PSK_910) {
+		if (pilots) {
+			if (state->srate <= 3000000)
+				aclc = car_loop[i].crl_pilots_on_2;
+			else if (state->srate <= 7000000)
+				aclc = car_loop[i].crl_pilots_on_5;
+			else if (state->srate <= 15000000)
+				aclc = car_loop[i].crl_pilots_on_10;
+			else if (state->srate <= 25000000)
+				aclc = car_loop[i].crl_pilots_on_20;
+			else
+				aclc = car_loop[i].crl_pilots_on_30;
+		} else {
+			if (state->srate <= 3000000)
+				aclc = car_loop[i].crl_pilots_off_2;
+			else if (state->srate <= 7000000)
+				aclc = car_loop[i].crl_pilots_off_5;
+			else if (state->srate <= 15000000)
+				aclc = car_loop[i].crl_pilots_off_10;
+			else if (state->srate <= 25000000)
+				aclc = car_loop[i].crl_pilots_off_20;
+			else
+				aclc = car_loop[i].crl_pilots_off_30;
+		}
+	} else { /* 16APSK and 32APSK */
+		if (state->srate <= 3000000)
+			aclc = car_loop_apsk_low[i].crl_pilots_on_2;
+		else if (state->srate <= 7000000)
+			aclc = car_loop_apsk_low[i].crl_pilots_on_5;
+		else if (state->srate <= 15000000)
+			aclc = car_loop_apsk_low[i].crl_pilots_on_10;
+		else if (state->srate <= 25000000)
+			aclc = car_loop_apsk_low[i].crl_pilots_on_20;
+		else
+			aclc = car_loop_apsk_low[i].crl_pilots_on_30;
+	}
+
+	return aclc;
+}
+
+static u8 stv090x_optimize_carloop_short(struct stv090x_state *state)
+{
+	struct stv090x_short_frame_crloop *short_crl = NULL;
+	s32 index = 0;
+	u8 aclc = 0x0b;
+
+	switch (state->modulation) {
+	case STV090x_QPSK:
+	default:
+		index = 0;
+		break;
+	case STV090x_8PSK:
+		index = 1;
+		break;
+	case STV090x_16APSK:
+		index = 2;
+		break;
+	case STV090x_32APSK:
+		index = 3;
+		break;
+	}
+
+	if (state->internal->dev_ver >= 0x30) {
+		/* Cut 3.0 and up */
+		short_crl = stv090x_s2_short_crl_cut30;
+	} else {
+		/* Cut 2.0 and up: we don't support cuts older than 2.0 */
+		short_crl = stv090x_s2_short_crl_cut20;
+	}
+
+	if (state->srate <= 3000000)
+		aclc = short_crl[index].crl_2;
+	else if (state->srate <= 7000000)
+		aclc = short_crl[index].crl_5;
+	else if (state->srate <= 15000000)
+		aclc = short_crl[index].crl_10;
+	else if (state->srate <= 25000000)
+		aclc = short_crl[index].crl_20;
+	else
+		aclc = short_crl[index].crl_30;
+
+	return aclc;
+}
+
+static int stv090x_optimize_track(struct stv090x_state *state)
+{
+	struct dvb_frontend *fe = &state->frontend;
+
+	enum stv090x_modcod modcod;
+
+	s32 srate, pilots, aclc, f_1, f_0, i = 0, blind_tune = 0;
+	u32 reg;
+
+	srate  = stv090x_get_srate(state, state->internal->mclk);
+	srate += stv090x_get_tmgoffst(state, srate);
+
+	switch (state->delsys) {
+	case STV090x_DVBS1:
+	case STV090x_DSS:
+		if (state->search_mode == STV090x_SEARCH_AUTO) {
+			reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+			STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+			STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+			if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+				goto err;
+		}
+		reg = STV090x_READ_DEMOD(state, DEMOD);
+		STV090x_SETFIELD_Px(reg, ROLLOFF_CONTROL_FIELD, state->rolloff);
+		STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x01);
+		if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+			goto err;
+
+		if (state->internal->dev_ver >= 0x30) {
+			if (stv090x_get_viterbi(state) < 0)
+				goto err;
+
+			if (state->fec == STV090x_PR12) {
+				if (STV090x_WRITE_DEMOD(state, GAUSSR0, 0x98) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, CCIR0, 0x18) < 0)
+					goto err;
+			} else {
+				if (STV090x_WRITE_DEMOD(state, GAUSSR0, 0x18) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, CCIR0, 0x18) < 0)
+					goto err;
+			}
+		}
+
+		if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x75) < 0)
+			goto err;
+		break;
+
+	case STV090x_DVBS2:
+		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
+		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
+		if (state->internal->dev_ver >= 0x30) {
+			if (STV090x_WRITE_DEMOD(state, ACLC, 0) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, BCLC, 0) < 0)
+				goto err;
+		}
+		if (state->frame_len == STV090x_LONG_FRAME) {
+			reg = STV090x_READ_DEMOD(state, DMDMODCOD);
+			modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD);
+			pilots = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) & 0x01;
+			aclc = stv090x_optimize_carloop(state, modcod, pilots);
+			if (modcod <= STV090x_QPSK_910) {
+				STV090x_WRITE_DEMOD(state, ACLC2S2Q, aclc);
+			} else if (modcod <= STV090x_8PSK_910) {
+				if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, ACLC2S28, aclc) < 0)
+					goto err;
+			}
+			if ((state->demod_mode == STV090x_SINGLE) && (modcod > STV090x_8PSK_910)) {
+				if (modcod <= STV090x_16APSK_910) {
+					if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+						goto err;
+					if (STV090x_WRITE_DEMOD(state, ACLC2S216A, aclc) < 0)
+						goto err;
+				} else {
+					if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+						goto err;
+					if (STV090x_WRITE_DEMOD(state, ACLC2S232A, aclc) < 0)
+						goto err;
+				}
+			}
+		} else {
+			/*Carrier loop setting for short frame*/
+			aclc = stv090x_optimize_carloop_short(state);
+			if (state->modulation == STV090x_QPSK) {
+				if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, aclc) < 0)
+					goto err;
+			} else if (state->modulation == STV090x_8PSK) {
+				if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, ACLC2S28, aclc) < 0)
+					goto err;
+			} else if (state->modulation == STV090x_16APSK) {
+				if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, ACLC2S216A, aclc) < 0)
+					goto err;
+			} else if (state->modulation == STV090x_32APSK)  {
+				if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, ACLC2S232A, aclc) < 0)
+					goto err;
+			}
+		}
+
+		STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67); /* PER */
+		break;
+
+	case STV090x_ERROR:
+	default:
+		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
+		break;
+	}
+
+	f_1 = STV090x_READ_DEMOD(state, CFR2);
+	f_0 = STV090x_READ_DEMOD(state, CFR1);
+	reg = STV090x_READ_DEMOD(state, TMGOBS);
+
+	if (state->algo == STV090x_BLIND_SEARCH) {
+		STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00);
+		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+		STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0x00);
+		STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0)
+			goto err;
+
+		if (stv090x_set_srate(state, srate) < 0)
+			goto err;
+		blind_tune = 1;
+
+		if (stv090x_dvbs_track_crl(state) < 0)
+			goto err;
+	}
+
+	if (state->internal->dev_ver >= 0x20) {
+		if ((state->search_mode == STV090x_SEARCH_DVBS1)	||
+		    (state->search_mode == STV090x_SEARCH_DSS)		||
+		    (state->search_mode == STV090x_SEARCH_AUTO)) {
+
+			if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x0a) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x00) < 0)
+				goto err;
+		}
+	}
+
+	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+		goto err;
+
+	/* AUTO tracking MODE */
+	if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x80) < 0)
+		goto err;
+	/* AUTO tracking MODE */
+	if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x80) < 0)
+		goto err;
+
+	if ((state->internal->dev_ver >= 0x20) || (blind_tune == 1) ||
+	    (state->srate < 10000000)) {
+		/* update initial carrier freq with the found freq offset */
+		if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0)
+			goto err;
+		state->tuner_bw = stv090x_car_width(srate, state->rolloff) + 10000000;
+
+		if ((state->internal->dev_ver >= 0x20) || (blind_tune == 1)) {
+
+			if (state->algo != STV090x_WARM_SEARCH) {
+
+				if (stv090x_i2c_gate_ctrl(state, 1) < 0)
+					goto err;
+
+				if (state->config->tuner_set_bandwidth) {
+					if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
+						goto err_gateoff;
+				}
+
+				if (stv090x_i2c_gate_ctrl(state, 0) < 0)
+					goto err;
+
+			}
+		}
+		if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000))
+			msleep(50); /* blind search: wait 50ms for SR stabilization */
+		else
+			msleep(5);
+
+		stv090x_get_lock_tmg(state);
+
+		if (!(stv090x_get_dmdlock(state, (state->DemodTimeout / 2)))) {
+			if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
+				goto err;
+
+			i = 0;
+
+			while ((!(stv090x_get_dmdlock(state, (state->DemodTimeout / 2)))) && (i <= 2)) {
+
+				if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
+					goto err;
+				i++;
+			}
+		}
+
+	}
+
+	if (state->internal->dev_ver >= 0x20) {
+		if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
+			goto err;
+	}
+
+	if ((state->delsys == STV090x_DVBS1) || (state->delsys == STV090x_DSS))
+		stv090x_set_vit_thtracq(state);
+
+	return 0;
+
+err_gateoff:
+	stv090x_i2c_gate_ctrl(state, 0);
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_get_feclock(struct stv090x_state *state, s32 timeout)
+{
+	s32 timer = 0, lock = 0, stat;
+	u32 reg;
+
+	while ((timer < timeout) && (!lock)) {
+		reg = STV090x_READ_DEMOD(state, DMDSTATE);
+		stat = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD);
+
+		switch (stat) {
+		case 0: /* searching */
+		case 1: /* first PLH detected */
+		default:
+			lock = 0;
+			break;
+
+		case 2: /* DVB-S2 mode */
+			reg = STV090x_READ_DEMOD(state, PDELSTATUS1);
+			lock = STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD);
+			break;
+
+		case 3: /* DVB-S1/legacy mode */
+			reg = STV090x_READ_DEMOD(state, VSTATUSVIT);
+			lock = STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD);
+			break;
+		}
+		if (!lock) {
+			msleep(10);
+			timer += 10;
+		}
+	}
+	return lock;
+}
+
+static int stv090x_get_lock(struct stv090x_state *state, s32 timeout_dmd, s32 timeout_fec)
+{
+	u32 reg;
+	s32 timer = 0;
+	int lock;
+
+	lock = stv090x_get_dmdlock(state, timeout_dmd);
+	if (lock)
+		lock = stv090x_get_feclock(state, timeout_fec);
+
+	if (lock) {
+		lock = 0;
+
+		while ((timer < timeout_fec) && (!lock)) {
+			reg = STV090x_READ_DEMOD(state, TSSTATUS);
+			lock = STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD);
+			msleep(1);
+			timer++;
+		}
+	}
+
+	return lock;
+}
+
+static int stv090x_set_s2rolloff(struct stv090x_state *state)
+{
+	u32 reg;
+
+	if (state->internal->dev_ver <= 0x20) {
+		/* rolloff to auto mode if DVBS2 */
+		reg = STV090x_READ_DEMOD(state, DEMOD);
+		STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x00);
+		if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+			goto err;
+	} else {
+		/* DVB-S2 rolloff to auto mode if DVBS2 */
+		reg = STV090x_READ_DEMOD(state, DEMOD);
+		STV090x_SETFIELD_Px(reg, MANUAL_S2ROLLOFF_FIELD, 0x00);
+		if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+			goto err;
+	}
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+
+static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
+{
+	struct dvb_frontend *fe = &state->frontend;
+	enum stv090x_signal_state signal_state = STV090x_NOCARRIER;
+	u32 reg;
+	s32 agc1_power, power_iq = 0, i;
+	int lock = 0, low_sr = 0;
+
+	reg = STV090x_READ_DEMOD(state, TSCFGH);
+	STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* Stop path 1 stream merger */
+	if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
+		goto err;
+
+	if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod stop */
+		goto err;
+
+	if (state->internal->dev_ver >= 0x20) {
+		if (state->srate > 5000000) {
+			if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0)
+				goto err;
+		} else {
+			if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x82) < 0)
+				goto err;
+		}
+	}
+
+	stv090x_get_lock_tmg(state);
+
+	if (state->algo == STV090x_BLIND_SEARCH) {
+		state->tuner_bw = 2 * 36000000; /* wide bw for unknown srate */
+		if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc0) < 0) /* wider srate scan */
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x70) < 0)
+			goto err;
+		if (stv090x_set_srate(state, 1000000) < 0) /* initial srate = 1Msps */
+			goto err;
+	} else {
+		/* known srate */
+		if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x20) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, TMGCFG, 0xd2) < 0)
+			goto err;
+
+		if (state->srate < 2000000) {
+			/* SR < 2MSPS */
+			if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x63) < 0)
+				goto err;
+		} else {
+			/* SR >= 2Msps */
+			if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x70) < 0)
+				goto err;
+		}
+
+		if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+			goto err;
+
+		if (state->internal->dev_ver >= 0x20) {
+			if (STV090x_WRITE_DEMOD(state, KREFTMG, 0x5a) < 0)
+				goto err;
+			if (state->algo == STV090x_COLD_SEARCH)
+				state->tuner_bw = (15 * (stv090x_car_width(state->srate, state->rolloff) + 10000000)) / 10;
+			else if (state->algo == STV090x_WARM_SEARCH)
+				state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + 10000000;
+		}
+
+		/* if cold start or warm  (Symbolrate is known)
+		 * use a Narrow symbol rate scan range
+		 */
+		if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0) /* narrow srate scan */
+			goto err;
+
+		if (stv090x_set_srate(state, state->srate) < 0)
+			goto err;
+
+		if (stv090x_set_max_srate(state, state->internal->mclk,
+					  state->srate) < 0)
+			goto err;
+		if (stv090x_set_min_srate(state, state->internal->mclk,
+					  state->srate) < 0)
+			goto err;
+
+		if (state->srate >= 10000000)
+			low_sr = 0;
+		else
+			low_sr = 1;
+	}
+
+	/* Setup tuner */
+	if (stv090x_i2c_gate_ctrl(state, 1) < 0)
+		goto err;
+
+	if (state->config->tuner_set_bbgain) {
+		reg = state->config->tuner_bbgain;
+		if (reg == 0)
+			reg = 10; /* default: 10dB */
+		if (state->config->tuner_set_bbgain(fe, reg) < 0)
+			goto err_gateoff;
+	}
+
+	if (state->config->tuner_set_frequency) {
+		if (state->config->tuner_set_frequency(fe, state->frequency) < 0)
+			goto err_gateoff;
+	}
+
+	if (state->config->tuner_set_bandwidth) {
+		if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
+			goto err_gateoff;
+	}
+
+	if (stv090x_i2c_gate_ctrl(state, 0) < 0)
+		goto err;
+
+	msleep(50);
+
+	if (state->config->tuner_get_status) {
+		if (stv090x_i2c_gate_ctrl(state, 1) < 0)
+			goto err;
+		if (state->config->tuner_get_status(fe, &reg) < 0)
+			goto err_gateoff;
+		if (stv090x_i2c_gate_ctrl(state, 0) < 0)
+			goto err;
+
+		if (reg)
+			dprintk(FE_DEBUG, 1, "Tuner phase locked");
+		else {
+			dprintk(FE_DEBUG, 1, "Tuner unlocked");
+			return STV090x_NOCARRIER;
+		}
+	}
+
+	msleep(10);
+	agc1_power = MAKEWORD16(STV090x_READ_DEMOD(state, AGCIQIN1),
+				STV090x_READ_DEMOD(state, AGCIQIN0));
+
+	if (agc1_power == 0) {
+		/* If AGC1 integrator value is 0
+		 * then read POWERI, POWERQ
+		 */
+		for (i = 0; i < 5; i++) {
+			power_iq += (STV090x_READ_DEMOD(state, POWERI) +
+				     STV090x_READ_DEMOD(state, POWERQ)) >> 1;
+		}
+		power_iq /= 5;
+	}
+
+	if ((agc1_power == 0) && (power_iq < STV090x_IQPOWER_THRESHOLD)) {
+		dprintk(FE_ERROR, 1, "No Signal: POWER_IQ=0x%02x", power_iq);
+		lock = 0;
+		signal_state = STV090x_NOAGC1;
+	} else {
+		reg = STV090x_READ_DEMOD(state, DEMOD);
+		STV090x_SETFIELD_Px(reg, SPECINV_CONTROL_FIELD, state->inversion);
+
+		if (state->internal->dev_ver <= 0x20) {
+			/* rolloff to auto mode if DVBS2 */
+			STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 1);
+		} else {
+			/* DVB-S2 rolloff to auto mode if DVBS2 */
+			STV090x_SETFIELD_Px(reg, MANUAL_S2ROLLOFF_FIELD, 1);
+		}
+		if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+			goto err;
+
+		if (stv090x_delivery_search(state) < 0)
+			goto err;
+
+		if (state->algo != STV090x_BLIND_SEARCH) {
+			if (stv090x_start_search(state) < 0)
+				goto err;
+		}
+	}
+
+	if (signal_state == STV090x_NOAGC1)
+		return signal_state;
+
+	if (state->algo == STV090x_BLIND_SEARCH)
+		lock = stv090x_blind_search(state);
+
+	else if (state->algo == STV090x_COLD_SEARCH)
+		lock = stv090x_get_coldlock(state, state->DemodTimeout);
+
+	else if (state->algo == STV090x_WARM_SEARCH)
+		lock = stv090x_get_dmdlock(state, state->DemodTimeout);
+
+	if ((!lock) && (state->algo == STV090x_COLD_SEARCH)) {
+		if (!low_sr) {
+			if (stv090x_chk_tmg(state))
+				lock = stv090x_sw_algo(state);
+		}
+	}
+
+	if (lock)
+		signal_state = stv090x_get_sig_params(state);
+
+	if ((lock) && (signal_state == STV090x_RANGEOK)) { /* signal within Range */
+		stv090x_optimize_track(state);
+
+		if (state->internal->dev_ver >= 0x20) {
+			/* >= Cut 2.0 :release TS reset after
+			 * demod lock and optimized Tracking
+			 */
+			reg = STV090x_READ_DEMOD(state, TSCFGH);
+			STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0); /* release merger reset */
+			if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
+				goto err;
+
+			msleep(3);
+
+			STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* merger reset */
+			if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
+				goto err;
+
+			STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0); /* release merger reset */
+			if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
+				goto err;
+		}
+
+		lock = stv090x_get_lock(state, state->FecTimeout,
+				state->FecTimeout);
+		if (lock) {
+			if (state->delsys == STV090x_DVBS2) {
+				stv090x_set_s2rolloff(state);
+
+				reg = STV090x_READ_DEMOD(state, PDELCTRL2);
+				STV090x_SETFIELD_Px(reg, RESET_UPKO_COUNT, 1);
+				if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0)
+					goto err;
+				/* Reset DVBS2 packet delinator error counter */
+				reg = STV090x_READ_DEMOD(state, PDELCTRL2);
+				STV090x_SETFIELD_Px(reg, RESET_UPKO_COUNT, 0);
+				if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0)
+					goto err;
+
+				if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67) < 0) /* PER */
+					goto err;
+			} else {
+				if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x75) < 0)
+					goto err;
+			}
+			/* Reset the Total packet counter */
+			if (STV090x_WRITE_DEMOD(state, FBERCPT4, 0x00) < 0)
+				goto err;
+			/* Reset the packet Error counter2 */
+			if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0)
+				goto err;
+		} else {
+			signal_state = STV090x_NODATA;
+			stv090x_chk_signal(state);
+		}
+	}
+	return signal_state;
+
+err_gateoff:
+	stv090x_i2c_gate_ctrl(state, 0);
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static enum dvbfe_search stv090x_search(struct dvb_frontend *fe)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *props = &fe->dtv_property_cache;
+
+	if (props->frequency == 0)
+		return DVBFE_ALGO_SEARCH_INVALID;
+
+	state->delsys = props->delivery_system;
+	state->frequency = props->frequency;
+	state->srate = props->symbol_rate;
+	state->search_mode = STV090x_SEARCH_AUTO;
+	state->algo = STV090x_COLD_SEARCH;
+	state->fec = STV090x_PRERR;
+	if (state->srate > 10000000) {
+		dprintk(FE_DEBUG, 1, "Search range: 10 MHz");
+		state->search_range = 10000000;
+	} else {
+		dprintk(FE_DEBUG, 1, "Search range: 5 MHz");
+		state->search_range = 5000000;
+	}
+
+	if (stv090x_algo(state) == STV090x_RANGEOK) {
+		dprintk(FE_DEBUG, 1, "Search success!");
+		return DVBFE_ALGO_SEARCH_SUCCESS;
+	} else {
+		dprintk(FE_DEBUG, 1, "Search failed!");
+		return DVBFE_ALGO_SEARCH_FAILED;
+	}
+
+	return DVBFE_ALGO_SEARCH_ERROR;
+}
+
+static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg, dstatus;
+	u8 search_state;
+
+	*status = 0;
+
+	dstatus = STV090x_READ_DEMOD(state, DSTATUS);
+	if (STV090x_GETFIELD_Px(dstatus, CAR_LOCK_FIELD))
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+
+	reg = STV090x_READ_DEMOD(state, DMDSTATE);
+	search_state = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD);
+
+	switch (search_state) {
+	case 0: /* searching */
+	case 1: /* first PLH detected */
+	default:
+		dprintk(FE_DEBUG, 1, "Status: Unlocked (Searching ..)");
+		break;
+
+	case 2: /* DVB-S2 mode */
+		dprintk(FE_DEBUG, 1, "Delivery system: DVB-S2");
+		if (STV090x_GETFIELD_Px(dstatus, LOCK_DEFINITIF_FIELD)) {
+			reg = STV090x_READ_DEMOD(state, PDELSTATUS1);
+			if (STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD)) {
+				*status |= FE_HAS_VITERBI;
+				reg = STV090x_READ_DEMOD(state, TSSTATUS);
+				if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD))
+					*status |= FE_HAS_SYNC | FE_HAS_LOCK;
+			}
+		}
+		break;
+
+	case 3: /* DVB-S1/legacy mode */
+		dprintk(FE_DEBUG, 1, "Delivery system: DVB-S");
+		if (STV090x_GETFIELD_Px(dstatus, LOCK_DEFINITIF_FIELD)) {
+			reg = STV090x_READ_DEMOD(state, VSTATUSVIT);
+			if (STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD)) {
+				*status |= FE_HAS_VITERBI;
+				reg = STV090x_READ_DEMOD(state, TSSTATUS);
+				if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD))
+					*status |= FE_HAS_SYNC | FE_HAS_LOCK;
+			}
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static int stv090x_read_per(struct dvb_frontend *fe, u32 *per)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+
+	s32 count_4, count_3, count_2, count_1, count_0, count;
+	u32 reg, h, m, l;
+	enum fe_status status;
+
+	stv090x_read_status(fe, &status);
+	if (!(status & FE_HAS_LOCK)) {
+		*per = 1 << 23; /* Max PER */
+	} else {
+		/* Counter 2 */
+		reg = STV090x_READ_DEMOD(state, ERRCNT22);
+		h = STV090x_GETFIELD_Px(reg, ERR_CNT2_FIELD);
+
+		reg = STV090x_READ_DEMOD(state, ERRCNT21);
+		m = STV090x_GETFIELD_Px(reg, ERR_CNT21_FIELD);
+
+		reg = STV090x_READ_DEMOD(state, ERRCNT20);
+		l = STV090x_GETFIELD_Px(reg, ERR_CNT20_FIELD);
+
+		*per = ((h << 16) | (m << 8) | l);
+
+		count_4 = STV090x_READ_DEMOD(state, FBERCPT4);
+		count_3 = STV090x_READ_DEMOD(state, FBERCPT3);
+		count_2 = STV090x_READ_DEMOD(state, FBERCPT2);
+		count_1 = STV090x_READ_DEMOD(state, FBERCPT1);
+		count_0 = STV090x_READ_DEMOD(state, FBERCPT0);
+
+		if ((!count_4) && (!count_3)) {
+			count  = (count_2 & 0xff) << 16;
+			count |= (count_1 & 0xff) <<  8;
+			count |=  count_0 & 0xff;
+		} else {
+			count = 1 << 24;
+		}
+		if (count == 0)
+			*per = 1;
+	}
+	if (STV090x_WRITE_DEMOD(state, FBERCPT4, 0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_table_lookup(const struct stv090x_tab *tab, int max, int val)
+{
+	int res = 0;
+	int min = 0, med;
+
+	if ((val >= tab[min].read && val < tab[max].read) ||
+	    (val >= tab[max].read && val < tab[min].read)) {
+		while ((max - min) > 1) {
+			med = (max + min) / 2;
+			if ((val >= tab[min].read && val < tab[med].read) ||
+			    (val >= tab[med].read && val < tab[min].read))
+				max = med;
+			else
+				min = med;
+		}
+		res = ((val - tab[min].read) *
+		       (tab[max].real - tab[min].real) /
+		       (tab[max].read - tab[min].read)) +
+			tab[min].real;
+	} else {
+		if (tab[min].read < tab[max].read) {
+			if (val < tab[min].read)
+				res = tab[min].real;
+			else if (val >= tab[max].read)
+				res = tab[max].real;
+		} else {
+			if (val >= tab[min].read)
+				res = tab[min].real;
+			else if (val < tab[max].read)
+				res = tab[max].real;
+		}
+	}
+
+	return res;
+}
+
+static int stv090x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg;
+	s32 agc_0, agc_1, agc;
+	s32 str;
+
+	reg = STV090x_READ_DEMOD(state, AGCIQIN1);
+	agc_1 = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD);
+	reg = STV090x_READ_DEMOD(state, AGCIQIN0);
+	agc_0 = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD);
+	agc = MAKEWORD16(agc_1, agc_0);
+
+	str = stv090x_table_lookup(stv090x_rf_tab,
+		ARRAY_SIZE(stv090x_rf_tab) - 1, agc);
+	if (agc > stv090x_rf_tab[0].read)
+		str = 0;
+	else if (agc < stv090x_rf_tab[ARRAY_SIZE(stv090x_rf_tab) - 1].read)
+		str = -100;
+	*strength = (str + 100) * 0xFFFF / 100;
+
+	return 0;
+}
+
+static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg_0, reg_1, reg, i;
+	s32 val_0, val_1, val = 0;
+	u8 lock_f;
+	s32 div;
+	u32 last;
+
+	switch (state->delsys) {
+	case STV090x_DVBS2:
+		reg = STV090x_READ_DEMOD(state, DSTATUS);
+		lock_f = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD);
+		if (lock_f) {
+			msleep(5);
+			for (i = 0; i < 16; i++) {
+				reg_1 = STV090x_READ_DEMOD(state, NNOSPLHT1);
+				val_1 = STV090x_GETFIELD_Px(reg_1, NOSPLHT_NORMED_FIELD);
+				reg_0 = STV090x_READ_DEMOD(state, NNOSPLHT0);
+				val_0 = STV090x_GETFIELD_Px(reg_0, NOSPLHT_NORMED_FIELD);
+				val  += MAKEWORD16(val_1, val_0);
+				msleep(1);
+			}
+			val /= 16;
+			last = ARRAY_SIZE(stv090x_s2cn_tab) - 1;
+			div = stv090x_s2cn_tab[0].read -
+			      stv090x_s2cn_tab[last].read;
+			*cnr = 0xFFFF - ((val * 0xFFFF) / div);
+		}
+		break;
+
+	case STV090x_DVBS1:
+	case STV090x_DSS:
+		reg = STV090x_READ_DEMOD(state, DSTATUS);
+		lock_f = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD);
+		if (lock_f) {
+			msleep(5);
+			for (i = 0; i < 16; i++) {
+				reg_1 = STV090x_READ_DEMOD(state, NOSDATAT1);
+				val_1 = STV090x_GETFIELD_Px(reg_1, NOSDATAT_UNNORMED_FIELD);
+				reg_0 = STV090x_READ_DEMOD(state, NOSDATAT0);
+				val_0 = STV090x_GETFIELD_Px(reg_0, NOSDATAT_UNNORMED_FIELD);
+				val  += MAKEWORD16(val_1, val_0);
+				msleep(1);
+			}
+			val /= 16;
+			last = ARRAY_SIZE(stv090x_s1cn_tab) - 1;
+			div = stv090x_s1cn_tab[0].read -
+			      stv090x_s1cn_tab[last].read;
+			*cnr = 0xFFFF - ((val * 0xFFFF) / div);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int stv090x_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg;
+
+	reg = STV090x_READ_DEMOD(state, DISTXCTL);
+	switch (tone) {
+	case SEC_TONE_ON:
+		STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 0);
+		STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
+		if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+			goto err;
+		STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0);
+		if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+			goto err;
+		break;
+
+	case SEC_TONE_OFF:
+		STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 0);
+		STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
+		if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+			goto err;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+
+static enum dvbfe_algo stv090x_frontend_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_CUSTOM;
+}
+
+static int stv090x_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg, idle = 0, fifo_full = 1;
+	int i;
+
+	reg = STV090x_READ_DEMOD(state, DISTXCTL);
+
+	STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD,
+		(state->config->diseqc_envelope_mode) ? 4 : 2);
+	STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
+	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+		goto err;
+	STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0);
+	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+		goto err;
+
+	STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 1);
+	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+		goto err;
+
+	for (i = 0; i < cmd->msg_len; i++) {
+
+		while (fifo_full) {
+			reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
+			fifo_full = STV090x_GETFIELD_Px(reg, FIFO_FULL_FIELD);
+		}
+
+		if (STV090x_WRITE_DEMOD(state, DISTXDATA, cmd->msg[i]) < 0)
+			goto err;
+	}
+	reg = STV090x_READ_DEMOD(state, DISTXCTL);
+	STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 0);
+	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+		goto err;
+
+	i = 0;
+
+	while ((!idle) && (i < 10)) {
+		reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
+		idle = STV090x_GETFIELD_Px(reg, TX_IDLE_FIELD);
+		msleep(10);
+		i++;
+	}
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg, idle = 0, fifo_full = 1;
+	u8 mode, value;
+	int i;
+
+	reg = STV090x_READ_DEMOD(state, DISTXCTL);
+
+	if (burst == SEC_MINI_A) {
+		mode = (state->config->diseqc_envelope_mode) ? 5 : 3;
+		value = 0x00;
+	} else {
+		mode = (state->config->diseqc_envelope_mode) ? 4 : 2;
+		value = 0xFF;
+	}
+
+	STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, mode);
+	STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
+	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+		goto err;
+	STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0);
+	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+		goto err;
+
+	STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 1);
+	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+		goto err;
+
+	while (fifo_full) {
+		reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
+		fifo_full = STV090x_GETFIELD_Px(reg, FIFO_FULL_FIELD);
+	}
+
+	if (STV090x_WRITE_DEMOD(state, DISTXDATA, value) < 0)
+		goto err;
+
+	reg = STV090x_READ_DEMOD(state, DISTXCTL);
+	STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 0);
+	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+		goto err;
+
+	i = 0;
+
+	while ((!idle) && (i < 10)) {
+		reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
+		idle = STV090x_GETFIELD_Px(reg, TX_IDLE_FIELD);
+		msleep(10);
+		i++;
+	}
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_slave_reply *reply)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg = 0, i = 0, rx_end = 0;
+
+	while ((rx_end != 1) && (i < 10)) {
+		msleep(10);
+		i++;
+		reg = STV090x_READ_DEMOD(state, DISRX_ST0);
+		rx_end = STV090x_GETFIELD_Px(reg, RX_END_FIELD);
+	}
+
+	if (rx_end) {
+		reply->msg_len = STV090x_GETFIELD_Px(reg, FIFO_BYTENBR_FIELD);
+		for (i = 0; i < reply->msg_len; i++)
+			reply->msg[i] = STV090x_READ_DEMOD(state, DISRXDATA);
+	}
+
+	return 0;
+}
+
+static int stv090x_sleep(struct dvb_frontend *fe)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg;
+	u8 full_standby = 0;
+
+	if (stv090x_i2c_gate_ctrl(state, 1) < 0)
+		goto err;
+
+	if (state->config->tuner_sleep) {
+		if (state->config->tuner_sleep(fe) < 0)
+			goto err_gateoff;
+	}
+
+	if (stv090x_i2c_gate_ctrl(state, 0) < 0)
+		goto err;
+
+	dprintk(FE_DEBUG, 1, "Set %s(%d) to sleep",
+		state->device == STV0900 ? "STV0900" : "STV0903",
+		state->demod);
+
+	mutex_lock(&state->internal->demod_lock);
+
+	switch (state->demod) {
+	case STV090x_DEMODULATOR_0:
+		/* power off ADC 1 */
+		reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+		STV090x_SETFIELD(reg, ADC1_PON_FIELD, 0);
+		if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
+			goto err;
+		/* power off DiSEqC 1 */
+		reg = stv090x_read_reg(state, STV090x_TSTTNR2);
+		STV090x_SETFIELD(reg, DISEQC1_PON_FIELD, 0);
+		if (stv090x_write_reg(state, STV090x_TSTTNR2, reg) < 0)
+			goto err;
+
+		/* check whether path 2 is already sleeping, that is when
+		   ADC2 is off */
+		reg = stv090x_read_reg(state, STV090x_TSTTNR3);
+		if (STV090x_GETFIELD(reg, ADC2_PON_FIELD) == 0)
+			full_standby = 1;
+
+		/* stop clocks */
+		reg = stv090x_read_reg(state, STV090x_STOPCLK1);
+		/* packet delineator 1 clock */
+		STV090x_SETFIELD(reg, STOP_CLKPKDT1_FIELD, 1);
+		/* ADC 1 clock */
+		STV090x_SETFIELD(reg, STOP_CLKADCI1_FIELD, 1);
+		/* FEC clock is shared between the two paths, only stop it
+		   when full standby is possible */
+		if (full_standby)
+			STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1);
+		if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
+			goto err;
+		reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+		/* sampling 1 clock */
+		STV090x_SETFIELD(reg, STOP_CLKSAMP1_FIELD, 1);
+		/* viterbi 1 clock */
+		STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, 1);
+		/* TS clock is shared between the two paths, only stop it
+		   when full standby is possible */
+		if (full_standby)
+			STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1);
+		if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+			goto err;
+		break;
+
+	case STV090x_DEMODULATOR_1:
+		/* power off ADC 2 */
+		reg = stv090x_read_reg(state, STV090x_TSTTNR3);
+		STV090x_SETFIELD(reg, ADC2_PON_FIELD, 0);
+		if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0)
+			goto err;
+		/* power off DiSEqC 2 */
+		reg = stv090x_read_reg(state, STV090x_TSTTNR4);
+		STV090x_SETFIELD(reg, DISEQC2_PON_FIELD, 0);
+		if (stv090x_write_reg(state, STV090x_TSTTNR4, reg) < 0)
+			goto err;
+
+		/* check whether path 1 is already sleeping, that is when
+		   ADC1 is off */
+		reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+		if (STV090x_GETFIELD(reg, ADC1_PON_FIELD) == 0)
+			full_standby = 1;
+
+		/* stop clocks */
+		reg = stv090x_read_reg(state, STV090x_STOPCLK1);
+		/* packet delineator 2 clock */
+		STV090x_SETFIELD(reg, STOP_CLKPKDT2_FIELD, 1);
+		/* ADC 2 clock */
+		STV090x_SETFIELD(reg, STOP_CLKADCI2_FIELD, 1);
+		/* FEC clock is shared between the two paths, only stop it
+		   when full standby is possible */
+		if (full_standby)
+			STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1);
+		if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
+			goto err;
+		reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+		/* sampling 2 clock */
+		STV090x_SETFIELD(reg, STOP_CLKSAMP2_FIELD, 1);
+		/* viterbi 2 clock */
+		STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, 1);
+		/* TS clock is shared between the two paths, only stop it
+		   when full standby is possible */
+		if (full_standby)
+			STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1);
+		if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+			goto err;
+		break;
+
+	default:
+		dprintk(FE_ERROR, 1, "Wrong demodulator!");
+		break;
+	}
+
+	if (full_standby) {
+		/* general power off */
+		reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+		STV090x_SETFIELD(reg, STANDBY_FIELD, 0x01);
+		if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0)
+			goto err;
+	}
+
+	mutex_unlock(&state->internal->demod_lock);
+	return 0;
+
+err_gateoff:
+	stv090x_i2c_gate_ctrl(state, 0);
+err:
+	mutex_unlock(&state->internal->demod_lock);
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_wakeup(struct dvb_frontend *fe)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg;
+
+	dprintk(FE_DEBUG, 1, "Wake %s(%d) from standby",
+		state->device == STV0900 ? "STV0900" : "STV0903",
+		state->demod);
+
+	mutex_lock(&state->internal->demod_lock);
+
+	/* general power on */
+	reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+	STV090x_SETFIELD(reg, STANDBY_FIELD, 0x00);
+	if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0)
+		goto err;
+
+	switch (state->demod) {
+	case STV090x_DEMODULATOR_0:
+		/* power on ADC 1 */
+		reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+		STV090x_SETFIELD(reg, ADC1_PON_FIELD, 1);
+		if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
+			goto err;
+		/* power on DiSEqC 1 */
+		reg = stv090x_read_reg(state, STV090x_TSTTNR2);
+		STV090x_SETFIELD(reg, DISEQC1_PON_FIELD, 1);
+		if (stv090x_write_reg(state, STV090x_TSTTNR2, reg) < 0)
+			goto err;
+
+		/* activate clocks */
+		reg = stv090x_read_reg(state, STV090x_STOPCLK1);
+		/* packet delineator 1 clock */
+		STV090x_SETFIELD(reg, STOP_CLKPKDT1_FIELD, 0);
+		/* ADC 1 clock */
+		STV090x_SETFIELD(reg, STOP_CLKADCI1_FIELD, 0);
+		/* FEC clock */
+		STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 0);
+		if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
+			goto err;
+		reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+		/* sampling 1 clock */
+		STV090x_SETFIELD(reg, STOP_CLKSAMP1_FIELD, 0);
+		/* viterbi 1 clock */
+		STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, 0);
+		/* TS clock */
+		STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 0);
+		if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+			goto err;
+		break;
+
+	case STV090x_DEMODULATOR_1:
+		/* power on ADC 2 */
+		reg = stv090x_read_reg(state, STV090x_TSTTNR3);
+		STV090x_SETFIELD(reg, ADC2_PON_FIELD, 1);
+		if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0)
+			goto err;
+		/* power on DiSEqC 2 */
+		reg = stv090x_read_reg(state, STV090x_TSTTNR4);
+		STV090x_SETFIELD(reg, DISEQC2_PON_FIELD, 1);
+		if (stv090x_write_reg(state, STV090x_TSTTNR4, reg) < 0)
+			goto err;
+
+		/* activate clocks */
+		reg = stv090x_read_reg(state, STV090x_STOPCLK1);
+		/* packet delineator 2 clock */
+		STV090x_SETFIELD(reg, STOP_CLKPKDT2_FIELD, 0);
+		/* ADC 2 clock */
+		STV090x_SETFIELD(reg, STOP_CLKADCI2_FIELD, 0);
+		/* FEC clock */
+		STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 0);
+		if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
+			goto err;
+		reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+		/* sampling 2 clock */
+		STV090x_SETFIELD(reg, STOP_CLKSAMP2_FIELD, 0);
+		/* viterbi 2 clock */
+		STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, 0);
+		/* TS clock */
+		STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 0);
+		if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+			goto err;
+		break;
+
+	default:
+		dprintk(FE_ERROR, 1, "Wrong demodulator!");
+		break;
+	}
+
+	mutex_unlock(&state->internal->demod_lock);
+	return 0;
+err:
+	mutex_unlock(&state->internal->demod_lock);
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static void stv090x_release(struct dvb_frontend *fe)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+
+	state->internal->num_used--;
+	if (state->internal->num_used <= 0) {
+
+		dprintk(FE_ERROR, 1, "Actually removing");
+
+		remove_dev(state->internal);
+		kfree(state->internal);
+	}
+
+	kfree(state);
+}
+
+static int stv090x_ldpc_mode(struct stv090x_state *state, enum stv090x_mode ldpc_mode)
+{
+	u32 reg = 0;
+
+	reg = stv090x_read_reg(state, STV090x_GENCFG);
+
+	switch (ldpc_mode) {
+	case STV090x_DUAL:
+	default:
+		if ((state->demod_mode != STV090x_DUAL) || (STV090x_GETFIELD(reg, DDEMOD_FIELD) != 1)) {
+			/* set LDPC to dual mode */
+			if (stv090x_write_reg(state, STV090x_GENCFG, 0x1d) < 0)
+				goto err;
+
+			state->demod_mode = STV090x_DUAL;
+
+			reg = stv090x_read_reg(state, STV090x_TSTRES0);
+			STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x1);
+			if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
+				goto err;
+			STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x0);
+			if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
+				goto err;
+
+			if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xff) < 0)
+				goto err;
+
+			if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xcc) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xcc) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xcc) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xcc) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xcc) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xcc) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xcc) < 0)
+				goto err;
+
+			if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xcf) < 0)
+				goto err;
+		}
+		break;
+
+	case STV090x_SINGLE:
+		if (stv090x_stop_modcod(state) < 0)
+			goto err;
+		if (stv090x_activate_modcod_single(state) < 0)
+			goto err;
+
+		if (state->demod == STV090x_DEMODULATOR_1) {
+			if (stv090x_write_reg(state, STV090x_GENCFG, 0x06) < 0) /* path 2 */
+				goto err;
+		} else {
+			if (stv090x_write_reg(state, STV090x_GENCFG, 0x04) < 0) /* path 1 */
+				goto err;
+		}
+
+		reg = stv090x_read_reg(state, STV090x_TSTRES0);
+		STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x1);
+		if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
+			goto err;
+		STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x0);
+		if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
+			goto err;
+
+		reg = STV090x_READ_DEMOD(state, PDELCTRL1);
+		STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x01);
+		if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
+			goto err;
+		STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x00);
+		if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
+			goto err;
+		break;
+	}
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+/* return (Hz), clk in Hz*/
+static u32 stv090x_get_mclk(struct stv090x_state *state)
+{
+	const struct stv090x_config *config = state->config;
+	u32 div, reg;
+	u8 ratio;
+
+	div = stv090x_read_reg(state, STV090x_NCOARSE);
+	reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+	ratio = STV090x_GETFIELD(reg, SELX1RATIO_FIELD) ? 4 : 6;
+
+	return (div + 1) * config->xtal / ratio; /* kHz */
+}
+
+static int stv090x_set_mclk(struct stv090x_state *state, u32 mclk, u32 clk)
+{
+	const struct stv090x_config *config = state->config;
+	u32 reg, div, clk_sel;
+
+	reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+	clk_sel = ((STV090x_GETFIELD(reg, SELX1RATIO_FIELD) == 1) ? 4 : 6);
+
+	div = ((clk_sel * mclk) / config->xtal) - 1;
+
+	reg = stv090x_read_reg(state, STV090x_NCOARSE);
+	STV090x_SETFIELD(reg, M_DIV_FIELD, div);
+	if (stv090x_write_reg(state, STV090x_NCOARSE, reg) < 0)
+		goto err;
+
+	state->internal->mclk = stv090x_get_mclk(state);
+
+	/*Set the DiseqC frequency to 22KHz */
+	div = state->internal->mclk / 704000;
+	if (STV090x_WRITE_DEMOD(state, F22TX, div) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, F22RX, div) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_set_tspath(struct stv090x_state *state)
+{
+	u32 reg;
+
+	if (state->internal->dev_ver >= 0x20) {
+		switch (state->config->ts1_mode) {
+		case STV090x_TSMODE_PARALLEL_PUNCTURED:
+		case STV090x_TSMODE_DVBCI:
+			switch (state->config->ts2_mode) {
+			case STV090x_TSMODE_SERIAL_PUNCTURED:
+			case STV090x_TSMODE_SERIAL_CONTINUOUS:
+			default:
+				stv090x_write_reg(state, STV090x_TSGENERAL, 0x00);
+				break;
+
+			case STV090x_TSMODE_PARALLEL_PUNCTURED:
+			case STV090x_TSMODE_DVBCI:
+				if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x06) < 0) /* Mux'd stream mode */
+					goto err;
+				reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
+				STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+				if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
+					goto err;
+				reg = stv090x_read_reg(state, STV090x_P2_TSCFGM);
+				STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+				if (stv090x_write_reg(state, STV090x_P2_TSCFGM, reg) < 0)
+					goto err;
+				if (stv090x_write_reg(state, STV090x_P1_TSSPEED, 0x14) < 0)
+					goto err;
+				if (stv090x_write_reg(state, STV090x_P2_TSSPEED, 0x28) < 0)
+					goto err;
+				break;
+			}
+			break;
+
+		case STV090x_TSMODE_SERIAL_PUNCTURED:
+		case STV090x_TSMODE_SERIAL_CONTINUOUS:
+		default:
+			switch (state->config->ts2_mode) {
+			case STV090x_TSMODE_SERIAL_PUNCTURED:
+			case STV090x_TSMODE_SERIAL_CONTINUOUS:
+			default:
+				if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0)
+					goto err;
+				break;
+
+			case STV090x_TSMODE_PARALLEL_PUNCTURED:
+			case STV090x_TSMODE_DVBCI:
+				if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0a) < 0)
+					goto err;
+				break;
+			}
+			break;
+		}
+	} else {
+		switch (state->config->ts1_mode) {
+		case STV090x_TSMODE_PARALLEL_PUNCTURED:
+		case STV090x_TSMODE_DVBCI:
+			switch (state->config->ts2_mode) {
+			case STV090x_TSMODE_SERIAL_PUNCTURED:
+			case STV090x_TSMODE_SERIAL_CONTINUOUS:
+			default:
+				stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x10);
+				break;
+
+			case STV090x_TSMODE_PARALLEL_PUNCTURED:
+			case STV090x_TSMODE_DVBCI:
+				stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x16);
+				reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
+				STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+				if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
+					goto err;
+				reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
+				STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 0);
+				if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
+					goto err;
+				if (stv090x_write_reg(state, STV090x_P1_TSSPEED, 0x14) < 0)
+					goto err;
+				if (stv090x_write_reg(state, STV090x_P2_TSSPEED, 0x28) < 0)
+					goto err;
+				break;
+			}
+			break;
+
+		case STV090x_TSMODE_SERIAL_PUNCTURED:
+		case STV090x_TSMODE_SERIAL_CONTINUOUS:
+		default:
+			switch (state->config->ts2_mode) {
+			case STV090x_TSMODE_SERIAL_PUNCTURED:
+			case STV090x_TSMODE_SERIAL_CONTINUOUS:
+			default:
+				stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x14);
+				break;
+
+			case STV090x_TSMODE_PARALLEL_PUNCTURED:
+			case STV090x_TSMODE_DVBCI:
+				stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x12);
+				break;
+			}
+			break;
+		}
+	}
+
+	switch (state->config->ts1_mode) {
+	case STV090x_TSMODE_PARALLEL_PUNCTURED:
+		reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+		STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei);
+		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+		if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+			goto err;
+		break;
+
+	case STV090x_TSMODE_DVBCI:
+		reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+		STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei);
+		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+		if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+			goto err;
+		break;
+
+	case STV090x_TSMODE_SERIAL_PUNCTURED:
+		reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+		STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei);
+		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+		if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+			goto err;
+		break;
+
+	case STV090x_TSMODE_SERIAL_CONTINUOUS:
+		reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+		STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei);
+		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+		if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+			goto err;
+		break;
+
+	default:
+		break;
+	}
+
+	switch (state->config->ts2_mode) {
+	case STV090x_TSMODE_PARALLEL_PUNCTURED:
+		reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+		STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei);
+		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+		if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+			goto err;
+		break;
+
+	case STV090x_TSMODE_DVBCI:
+		reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+		STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei);
+		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+		if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+			goto err;
+		break;
+
+	case STV090x_TSMODE_SERIAL_PUNCTURED:
+		reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+		STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei);
+		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+		if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+			goto err;
+		break;
+
+	case STV090x_TSMODE_SERIAL_CONTINUOUS:
+		reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+		STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei);
+		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+		if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+			goto err;
+		break;
+
+	default:
+		break;
+	}
+
+	if (state->config->ts1_clk > 0) {
+		u32 speed;
+
+		switch (state->config->ts1_mode) {
+		case STV090x_TSMODE_PARALLEL_PUNCTURED:
+		case STV090x_TSMODE_DVBCI:
+		default:
+			speed = state->internal->mclk /
+				(state->config->ts1_clk / 4);
+			if (speed < 0x08)
+				speed = 0x08;
+			if (speed > 0xFF)
+				speed = 0xFF;
+			break;
+		case STV090x_TSMODE_SERIAL_PUNCTURED:
+		case STV090x_TSMODE_SERIAL_CONTINUOUS:
+			speed = state->internal->mclk /
+				(state->config->ts1_clk / 32);
+			if (speed < 0x20)
+				speed = 0x20;
+			if (speed > 0xFF)
+				speed = 0xFF;
+			break;
+		}
+		reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
+		STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+		if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
+			goto err;
+		if (stv090x_write_reg(state, STV090x_P1_TSSPEED, speed) < 0)
+			goto err;
+	}
+
+	if (state->config->ts2_clk > 0) {
+		u32 speed;
+
+		switch (state->config->ts2_mode) {
+		case STV090x_TSMODE_PARALLEL_PUNCTURED:
+		case STV090x_TSMODE_DVBCI:
+		default:
+			speed = state->internal->mclk /
+				(state->config->ts2_clk / 4);
+			if (speed < 0x08)
+				speed = 0x08;
+			if (speed > 0xFF)
+				speed = 0xFF;
+			break;
+		case STV090x_TSMODE_SERIAL_PUNCTURED:
+		case STV090x_TSMODE_SERIAL_CONTINUOUS:
+			speed = state->internal->mclk /
+				(state->config->ts2_clk / 32);
+			if (speed < 0x20)
+				speed = 0x20;
+			if (speed > 0xFF)
+				speed = 0xFF;
+			break;
+		}
+		reg = stv090x_read_reg(state, STV090x_P2_TSCFGM);
+		STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+		if (stv090x_write_reg(state, STV090x_P2_TSCFGM, reg) < 0)
+			goto err;
+		if (stv090x_write_reg(state, STV090x_P2_TSSPEED, speed) < 0)
+			goto err;
+	}
+
+	reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+	STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01);
+	if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+		goto err;
+	STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00);
+	if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+		goto err;
+
+	reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+	STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01);
+	if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+		goto err;
+	STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00);
+	if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_init(struct dvb_frontend *fe)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	const struct stv090x_config *config = state->config;
+	u32 reg;
+
+	if (state->internal->mclk == 0) {
+		/* call tuner init to configure the tuner's clock output
+		   divider directly before setting up the master clock of
+		   the stv090x. */
+		if (stv090x_i2c_gate_ctrl(state, 1) < 0)
+			goto err;
+
+		if (config->tuner_init) {
+			if (config->tuner_init(fe) < 0)
+				goto err_gateoff;
+		}
+
+		if (stv090x_i2c_gate_ctrl(state, 0) < 0)
+			goto err;
+
+		stv090x_set_mclk(state, 135000000, config->xtal); /* 135 Mhz */
+		msleep(5);
+		if (stv090x_write_reg(state, STV090x_SYNTCTRL,
+				      0x20 | config->clk_mode) < 0)
+			goto err;
+		stv090x_get_mclk(state);
+	}
+
+	if (stv090x_wakeup(fe) < 0) {
+		dprintk(FE_ERROR, 1, "Error waking device");
+		goto err;
+	}
+
+	if (stv090x_ldpc_mode(state, state->demod_mode) < 0)
+		goto err;
+
+	reg = STV090x_READ_DEMOD(state, TNRCFG2);
+	STV090x_SETFIELD_Px(reg, TUN_IQSWAP_FIELD, state->inversion);
+	if (STV090x_WRITE_DEMOD(state, TNRCFG2, reg) < 0)
+		goto err;
+	reg = STV090x_READ_DEMOD(state, DEMOD);
+	STV090x_SETFIELD_Px(reg, ROLLOFF_CONTROL_FIELD, state->rolloff);
+	if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+		goto err;
+
+	if (stv090x_i2c_gate_ctrl(state, 1) < 0)
+		goto err;
+
+	if (config->tuner_set_mode) {
+		if (config->tuner_set_mode(fe, TUNER_WAKE) < 0)
+			goto err_gateoff;
+	}
+
+	if (config->tuner_init) {
+		if (config->tuner_init(fe) < 0)
+			goto err_gateoff;
+	}
+
+	if (stv090x_i2c_gate_ctrl(state, 0) < 0)
+		goto err;
+
+	if (stv090x_set_tspath(state) < 0)
+		goto err;
+
+	return 0;
+
+err_gateoff:
+	stv090x_i2c_gate_ctrl(state, 0);
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_setup(struct dvb_frontend *fe)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	const struct stv090x_config *config = state->config;
+	const struct stv090x_reg *stv090x_initval = NULL;
+	const struct stv090x_reg *stv090x_cut20_val = NULL;
+	unsigned long t1_size = 0, t2_size = 0;
+	u32 reg = 0;
+
+	int i;
+
+	if (state->device == STV0900) {
+		dprintk(FE_DEBUG, 1, "Initializing STV0900");
+		stv090x_initval = stv0900_initval;
+		t1_size = ARRAY_SIZE(stv0900_initval);
+		stv090x_cut20_val = stv0900_cut20_val;
+		t2_size = ARRAY_SIZE(stv0900_cut20_val);
+	} else if (state->device == STV0903) {
+		dprintk(FE_DEBUG, 1, "Initializing STV0903");
+		stv090x_initval = stv0903_initval;
+		t1_size = ARRAY_SIZE(stv0903_initval);
+		stv090x_cut20_val = stv0903_cut20_val;
+		t2_size = ARRAY_SIZE(stv0903_cut20_val);
+	}
+
+	/* STV090x init */
+
+	/* Stop Demod */
+	if (stv090x_write_reg(state, STV090x_P1_DMDISTATE, 0x5c) < 0)
+		goto err;
+	if (stv090x_write_reg(state, STV090x_P2_DMDISTATE, 0x5c) < 0)
+		goto err;
+
+	msleep(5);
+
+	/* Set No Tuner Mode */
+	if (stv090x_write_reg(state, STV090x_P1_TNRCFG, 0x6c) < 0)
+		goto err;
+	if (stv090x_write_reg(state, STV090x_P2_TNRCFG, 0x6c) < 0)
+		goto err;
+
+	/* I2C repeater OFF */
+	STV090x_SETFIELD_Px(reg, ENARPT_LEVEL_FIELD, config->repeater_level);
+	if (stv090x_write_reg(state, STV090x_P1_I2CRPT, reg) < 0)
+		goto err;
+	if (stv090x_write_reg(state, STV090x_P2_I2CRPT, reg) < 0)
+		goto err;
+
+	if (stv090x_write_reg(state, STV090x_NCOARSE, 0x13) < 0) /* set PLL divider */
+		goto err;
+	msleep(5);
+	if (stv090x_write_reg(state, STV090x_I2CCFG, 0x08) < 0) /* 1/41 oversampling */
+		goto err;
+	if (stv090x_write_reg(state, STV090x_SYNTCTRL, 0x20 | config->clk_mode) < 0) /* enable PLL */
+		goto err;
+	msleep(5);
+
+	/* write initval */
+	dprintk(FE_DEBUG, 1, "Setting up initial values");
+	for (i = 0; i < t1_size; i++) {
+		if (stv090x_write_reg(state, stv090x_initval[i].addr, stv090x_initval[i].data) < 0)
+			goto err;
+	}
+
+	state->internal->dev_ver = stv090x_read_reg(state, STV090x_MID);
+	if (state->internal->dev_ver >= 0x20) {
+		if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0)
+			goto err;
+
+		/* write cut20_val*/
+		dprintk(FE_DEBUG, 1, "Setting up Cut 2.0 initial values");
+		for (i = 0; i < t2_size; i++) {
+			if (stv090x_write_reg(state, stv090x_cut20_val[i].addr, stv090x_cut20_val[i].data) < 0)
+				goto err;
+		}
+
+	} else if (state->internal->dev_ver < 0x20) {
+		dprintk(FE_ERROR, 1, "ERROR: Unsupported Cut: 0x%02x!",
+			state->internal->dev_ver);
+
+		goto err;
+	} else if (state->internal->dev_ver > 0x30) {
+		/* we shouldn't bail out from here */
+		dprintk(FE_ERROR, 1, "INFO: Cut: 0x%02x probably incomplete support!",
+			state->internal->dev_ver);
+	}
+
+	/* ADC1 range */
+	reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+	STV090x_SETFIELD(reg, ADC1_INMODE_FIELD,
+		(config->adc1_range == STV090x_ADC_1Vpp) ? 0 : 1);
+	if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
+		goto err;
+
+	/* ADC2 range */
+	reg = stv090x_read_reg(state, STV090x_TSTTNR3);
+	STV090x_SETFIELD(reg, ADC2_INMODE_FIELD,
+		(config->adc2_range == STV090x_ADC_1Vpp) ? 0 : 1);
+	if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0)
+		goto err;
+
+	if (stv090x_write_reg(state, STV090x_TSTRES0, 0x80) < 0)
+		goto err;
+	if (stv090x_write_reg(state, STV090x_TSTRES0, 0x00) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value,
+		u8 xor_value)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u8 reg = 0;
+
+	STV090x_SETFIELD(reg, GPIOx_OPD_FIELD, dir);
+	STV090x_SETFIELD(reg, GPIOx_CONFIG_FIELD, value);
+	STV090x_SETFIELD(reg, GPIOx_XOR_FIELD, xor_value);
+
+	return stv090x_write_reg(state, STV090x_GPIOxCFG(gpio), reg);
+}
+EXPORT_SYMBOL(stv090x_set_gpio);
+
+static struct dvb_frontend_ops stv090x_ops = {
+	.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
+	.info = {
+		.name			= "STV090x Multistandard",
+		.frequency_min		= 950000,
+		.frequency_max 		= 2150000,
+		.frequency_stepsize	= 0,
+		.frequency_tolerance	= 0,
+		.symbol_rate_min 	= 1000000,
+		.symbol_rate_max 	= 45000000,
+		.caps			= FE_CAN_INVERSION_AUTO |
+					  FE_CAN_FEC_AUTO       |
+					  FE_CAN_QPSK           |
+					  FE_CAN_2G_MODULATION
+	},
+
+	.release			= stv090x_release,
+	.init				= stv090x_init,
+
+	.sleep				= stv090x_sleep,
+	.get_frontend_algo		= stv090x_frontend_algo,
+
+	.diseqc_send_master_cmd		= stv090x_send_diseqc_msg,
+	.diseqc_send_burst		= stv090x_send_diseqc_burst,
+	.diseqc_recv_slave_reply	= stv090x_recv_slave_reply,
+	.set_tone			= stv090x_set_tone,
+
+	.search				= stv090x_search,
+	.read_status			= stv090x_read_status,
+	.read_ber			= stv090x_read_per,
+	.read_signal_strength		= stv090x_read_signal_strength,
+	.read_snr			= stv090x_read_cnr,
+};
+
+
+struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
+				    struct i2c_adapter *i2c,
+				    enum stv090x_demodulator demod)
+{
+	struct stv090x_state *state = NULL;
+	struct stv090x_dev *temp_int;
+
+	state = kzalloc(sizeof (struct stv090x_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	state->verbose				= &verbose;
+	state->config				= config;
+	state->i2c				= i2c;
+	state->frontend.ops			= stv090x_ops;
+	state->frontend.demodulator_priv	= state;
+	state->demod				= demod;
+	state->demod_mode 			= config->demod_mode; /* Single or Dual mode */
+	state->device				= config->device;
+	state->rolloff				= STV090x_RO_35; /* default */
+
+	temp_int = find_dev(state->i2c,
+				state->config->address);
+
+	if ((temp_int != NULL) && (state->demod_mode == STV090x_DUAL)) {
+		state->internal = temp_int->internal;
+		state->internal->num_used++;
+		dprintk(FE_INFO, 1, "Found Internal Structure!");
+	} else {
+		state->internal = kmalloc(sizeof(struct stv090x_internal),
+					  GFP_KERNEL);
+		if (!state->internal)
+			goto error;
+		temp_int = append_internal(state->internal);
+		if (!temp_int) {
+			kfree(state->internal);
+			goto error;
+		}
+		state->internal->num_used = 1;
+		state->internal->mclk = 0;
+		state->internal->dev_ver = 0;
+		state->internal->i2c_adap = state->i2c;
+		state->internal->i2c_addr = state->config->address;
+		dprintk(FE_INFO, 1, "Create New Internal Structure!");
+
+		mutex_init(&state->internal->demod_lock);
+		mutex_init(&state->internal->tuner_lock);
+
+		if (stv090x_setup(&state->frontend) < 0) {
+			dprintk(FE_ERROR, 1, "Error setting up device");
+			goto err_remove;
+		}
+	}
+
+	/* workaround for stuck DiSEqC output */
+	if (config->diseqc_envelope_mode)
+		stv090x_send_diseqc_burst(&state->frontend, SEC_MINI_A);
+
+	dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x",
+	       state->device == STV0900 ? "STV0900" : "STV0903",
+	       demod,
+	       state->internal->dev_ver);
+
+	return &state->frontend;
+
+err_remove:
+	remove_dev(state->internal);
+	kfree(state->internal);
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(stv090x_attach);
+MODULE_PARM_DESC(verbose, "Set Verbosity level");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_DESCRIPTION("STV090x Multi-Std Broadcast frontend");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/stv090x.h b/drivers/media/dvb-frontends/stv090x.h
new file mode 100644
index 0000000..29cdc2b
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv090x.h
@@ -0,0 +1,134 @@
+/*
+	STV0900/0903 Multistandard Broadcast Frontend driver
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __STV090x_H
+#define __STV090x_H
+
+enum stv090x_demodulator {
+	STV090x_DEMODULATOR_0 = 1,
+	STV090x_DEMODULATOR_1
+};
+
+enum stv090x_device {
+	STV0903	=  0,
+	STV0900,
+};
+
+enum stv090x_mode {
+	STV090x_DUAL = 0,
+	STV090x_SINGLE
+};
+
+enum stv090x_tsmode {
+	STV090x_TSMODE_SERIAL_PUNCTURED	= 1,
+	STV090x_TSMODE_SERIAL_CONTINUOUS,
+	STV090x_TSMODE_PARALLEL_PUNCTURED,
+	STV090x_TSMODE_DVBCI
+};
+
+enum stv090x_clkmode {
+	STV090x_CLK_INT = 0, /* Clk i/p = CLKI */
+	STV090x_CLK_EXT = 2 /* Clk i/p = XTALI */
+};
+
+enum stv090x_i2crpt {
+	STV090x_RPTLEVEL_256	= 0,
+	STV090x_RPTLEVEL_128	= 1,
+	STV090x_RPTLEVEL_64	= 2,
+	STV090x_RPTLEVEL_32	= 3,
+	STV090x_RPTLEVEL_16	= 4,
+	STV090x_RPTLEVEL_8	= 5,
+	STV090x_RPTLEVEL_4	= 6,
+	STV090x_RPTLEVEL_2	= 7,
+};
+
+enum stv090x_adc_range {
+	STV090x_ADC_2Vpp	= 0,
+	STV090x_ADC_1Vpp	= 1
+};
+
+struct stv090x_config {
+	enum stv090x_device	device;
+	enum stv090x_mode	demod_mode;
+	enum stv090x_clkmode	clk_mode;
+
+	u32 xtal; /* default: 8000000 */
+	u8 address; /* default: 0x68 */
+
+	u8 ts1_mode;
+	u8 ts2_mode;
+	u32 ts1_clk;
+	u32 ts2_clk;
+
+	u8 ts1_tei : 1;
+	u8 ts2_tei : 1;
+
+	enum stv090x_i2crpt	repeater_level;
+
+	u8			tuner_bbgain; /* default: 10db */
+	enum stv090x_adc_range	adc1_range; /* default: 2Vpp */
+	enum stv090x_adc_range	adc2_range; /* default: 2Vpp */
+
+	bool diseqc_envelope_mode;
+
+	int (*tuner_init) (struct dvb_frontend *fe);
+	int (*tuner_sleep) (struct dvb_frontend *fe);
+	int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode);
+	int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency);
+	int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency);
+	int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth);
+	int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth);
+	int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain);
+	int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain);
+	int (*tuner_set_refclk)  (struct dvb_frontend *fe, u32 refclk);
+	int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status);
+	void (*tuner_i2c_lock) (struct dvb_frontend *fe, int lock);
+};
+
+#if defined(CONFIG_DVB_STV090x) || (defined(CONFIG_DVB_STV090x_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
+					   struct i2c_adapter *i2c,
+					   enum stv090x_demodulator demod);
+
+/* dir = 0 -> output, dir = 1 -> input/open-drain */
+extern int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio,
+		u8 dir, u8 value, u8 xor_value);
+
+#else
+
+static inline struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
+						  struct i2c_adapter *i2c,
+						  enum stv090x_demodulator demod)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio,
+		u8 opd, u8 value, u8 xor_value)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+#endif /* CONFIG_DVB_STV090x */
+
+#endif /* __STV090x_H */
diff --git a/drivers/media/dvb-frontends/stv090x_priv.h b/drivers/media/dvb-frontends/stv090x_priv.h
new file mode 100644
index 0000000..5b780c8
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv090x_priv.h
@@ -0,0 +1,279 @@
+/*
+	STV0900/0903 Multistandard Broadcast Frontend driver
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __STV090x_PRIV_H
+#define __STV090x_PRIV_H
+
+#include "dvb_frontend.h"
+
+#define FE_ERROR				0
+#define FE_NOTICE				1
+#define FE_INFO					2
+#define FE_DEBUG				3
+#define FE_DEBUGREG				4
+
+#define dprintk(__y, __z, format, arg...) do {						\
+	if (__z) {									\
+		if	((verbose > FE_ERROR) && (verbose > __y))			\
+			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);		\
+		else if	((verbose > FE_NOTICE) && (verbose > __y))			\
+			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
+		else if ((verbose > FE_INFO) && (verbose > __y))			\
+			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);		\
+		else if ((verbose > FE_DEBUG) && (verbose > __y))			\
+			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
+	} else {									\
+		if (verbose > __y)							\
+			printk(format, ##arg);						\
+	}										\
+} while (0)
+
+#define STV090x_READ_DEMOD(__state, __reg) ((			\
+	(__state)->demod == STV090x_DEMODULATOR_1)	?	\
+	stv090x_read_reg(__state, STV090x_P2_##__reg) :		\
+	stv090x_read_reg(__state, STV090x_P1_##__reg))
+
+#define STV090x_WRITE_DEMOD(__state, __reg, __data) ((		\
+	(__state)->demod == STV090x_DEMODULATOR_1)	?	\
+	stv090x_write_reg(__state, STV090x_P2_##__reg, __data) :\
+	stv090x_write_reg(__state, STV090x_P1_##__reg, __data))
+
+#define STV090x_ADDR_OFFST(__state, __x) ((			\
+	(__state->demod) == STV090x_DEMODULATOR_1)	?	\
+		STV090x_P1_##__x :				\
+		STV090x_P2_##__x)
+
+
+#define STV090x_SETFIELD(mask, bitf, val)	(mask = (mask & (~(((1 << STV090x_WIDTH_##bitf) - 1) <<\
+							 STV090x_OFFST_##bitf))) | \
+							 (val << STV090x_OFFST_##bitf))
+
+#define STV090x_GETFIELD(val, bitf)		((val >> STV090x_OFFST_##bitf) & ((1 << STV090x_WIDTH_##bitf) - 1))
+
+
+#define STV090x_SETFIELD_Px(mask, bitf, val)	(mask = (mask & (~(((1 << STV090x_WIDTH_Px_##bitf) - 1) <<\
+							 STV090x_OFFST_Px_##bitf))) | \
+							 (val << STV090x_OFFST_Px_##bitf))
+
+#define STV090x_GETFIELD_Px(val, bitf)		((val >> STV090x_OFFST_Px_##bitf) & ((1 << STV090x_WIDTH_Px_##bitf) - 1))
+
+#define MAKEWORD16(__a, __b)			(((__a) << 8) | (__b))
+
+#define MSB(__x)				((__x >> 8) & 0xff)
+#define LSB(__x)				(__x & 0xff)
+
+
+#define STV090x_IQPOWER_THRESHOLD	  30
+#define STV090x_SEARCH_AGC2_TH_CUT20	 700
+#define STV090x_SEARCH_AGC2_TH_CUT30	1400
+
+#define STV090x_SEARCH_AGC2_TH(__ver)	\
+	((__ver <= 0x20) ?		\
+	STV090x_SEARCH_AGC2_TH_CUT20 :	\
+	STV090x_SEARCH_AGC2_TH_CUT30)
+
+enum stv090x_signal_state {
+	STV090x_NOAGC1,
+	STV090x_NOCARRIER,
+	STV090x_NODATA,
+	STV090x_DATAOK,
+	STV090x_RANGEOK,
+	STV090x_OUTOFRANGE
+};
+
+enum stv090x_fec {
+	STV090x_PR12 = 0,
+	STV090x_PR23,
+	STV090x_PR34,
+	STV090x_PR45,
+	STV090x_PR56,
+	STV090x_PR67,
+	STV090x_PR78,
+	STV090x_PR89,
+	STV090x_PR910,
+	STV090x_PRERR
+};
+
+enum stv090x_modulation {
+	STV090x_QPSK,
+	STV090x_8PSK,
+	STV090x_16APSK,
+	STV090x_32APSK,
+	STV090x_UNKNOWN
+};
+
+enum stv090x_frame {
+	STV090x_LONG_FRAME,
+	STV090x_SHORT_FRAME
+};
+
+enum stv090x_pilot {
+	STV090x_PILOTS_OFF,
+	STV090x_PILOTS_ON
+};
+
+enum stv090x_rolloff {
+	STV090x_RO_35,
+	STV090x_RO_25,
+	STV090x_RO_20
+};
+
+enum stv090x_inversion {
+	STV090x_IQ_AUTO,
+	STV090x_IQ_NORMAL,
+	STV090x_IQ_SWAP
+};
+
+enum stv090x_modcod {
+	STV090x_DUMMY_PLF = 0,
+	STV090x_QPSK_14,
+	STV090x_QPSK_13,
+	STV090x_QPSK_25,
+	STV090x_QPSK_12,
+	STV090x_QPSK_35,
+	STV090x_QPSK_23,
+	STV090x_QPSK_34,
+	STV090x_QPSK_45,
+	STV090x_QPSK_56,
+	STV090x_QPSK_89,
+	STV090x_QPSK_910,
+	STV090x_8PSK_35,
+	STV090x_8PSK_23,
+	STV090x_8PSK_34,
+	STV090x_8PSK_56,
+	STV090x_8PSK_89,
+	STV090x_8PSK_910,
+	STV090x_16APSK_23,
+	STV090x_16APSK_34,
+	STV090x_16APSK_45,
+	STV090x_16APSK_56,
+	STV090x_16APSK_89,
+	STV090x_16APSK_910,
+	STV090x_32APSK_34,
+	STV090x_32APSK_45,
+	STV090x_32APSK_56,
+	STV090x_32APSK_89,
+	STV090x_32APSK_910,
+	STV090x_MODCODE_UNKNOWN
+};
+
+enum stv090x_search {
+	STV090x_SEARCH_DSS = 0,
+	STV090x_SEARCH_DVBS1,
+	STV090x_SEARCH_DVBS2,
+	STV090x_SEARCH_AUTO
+};
+
+enum stv090x_algo {
+	STV090x_BLIND_SEARCH,
+	STV090x_COLD_SEARCH,
+	STV090x_WARM_SEARCH
+};
+
+enum stv090x_delsys {
+	STV090x_ERROR = 0,
+	STV090x_DVBS1 = 1,
+	STV090x_DVBS2,
+	STV090x_DSS
+};
+
+struct stv090x_long_frame_crloop {
+	enum stv090x_modcod	modcod;
+
+	u8 crl_pilots_on_2;
+	u8 crl_pilots_off_2;
+	u8 crl_pilots_on_5;
+	u8 crl_pilots_off_5;
+	u8 crl_pilots_on_10;
+	u8 crl_pilots_off_10;
+	u8 crl_pilots_on_20;
+	u8 crl_pilots_off_20;
+	u8 crl_pilots_on_30;
+	u8 crl_pilots_off_30;
+};
+
+struct stv090x_short_frame_crloop {
+	enum stv090x_modulation	modulation;
+
+	u8 crl_2;  /*      SR <   3M */
+	u8 crl_5;  /*  3 < SR <=  7M */
+	u8 crl_10; /*  7 < SR <= 15M */
+	u8 crl_20; /* 10 < SR <= 25M */
+	u8 crl_30; /* 10 < SR <= 45M */
+};
+
+struct stv090x_reg {
+	u16 addr;
+	u8  data;
+};
+
+struct stv090x_tab {
+	s32 real;
+	s32 read;
+};
+
+struct stv090x_internal {
+	struct i2c_adapter 	*i2c_adap;
+	u8			i2c_addr;
+
+	struct mutex		demod_lock; /* Lock access to shared register */
+	struct mutex		tuner_lock; /* Lock access to tuners */
+	s32			mclk; /* Masterclock Divider factor */
+	u32			dev_ver;
+
+	int			num_used;
+};
+
+struct stv090x_state {
+	enum stv090x_device		device;
+	enum stv090x_demodulator	demod;
+	enum stv090x_mode		demod_mode;
+	struct stv090x_internal		*internal;
+
+	struct i2c_adapter		*i2c;
+	const struct stv090x_config	*config;
+	struct dvb_frontend		frontend;
+
+	u32				*verbose; /* Cached module verbosity */
+
+	enum stv090x_delsys		delsys;
+	enum stv090x_fec		fec;
+	enum stv090x_modulation		modulation;
+	enum stv090x_modcod		modcod;
+	enum stv090x_search		search_mode;
+	enum stv090x_frame		frame_len;
+	enum stv090x_pilot		pilots;
+	enum stv090x_rolloff		rolloff;
+	enum stv090x_inversion		inversion;
+	enum stv090x_algo		algo;
+
+	u32				frequency;
+	u32				srate;
+
+	s32				tuner_bw;
+
+	s32				search_range;
+
+	s32				DemodTimeout;
+	s32				FecTimeout;
+};
+
+#endif /* __STV090x_PRIV_H */
diff --git a/drivers/media/dvb-frontends/stv090x_reg.h b/drivers/media/dvb-frontends/stv090x_reg.h
new file mode 100644
index 0000000..93741ee
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv090x_reg.h
@@ -0,0 +1,2371 @@
+/*
+	STV0900/0903 Multistandard Broadcast Frontend driver
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __STV090x_REG_H
+#define __STV090x_REG_H
+
+#define STV090x_MID				0xf100
+#define STV090x_OFFST_MCHIP_IDENT_FIELD		4
+#define STV090x_WIDTH_MCHIP_IDENT_FIELD		4
+#define STV090x_OFFST_MRELEASE_FIELD		0
+#define STV090x_WIDTH_MRELEASE_FIELD		4
+
+#define STV090x_DACR1				0xf113
+#define STV090x_OFFST_DACR1_MODE_FIELD		5
+#define STV090x_WIDTH_DACR1_MODE_FIELD		3
+#define STV090x_OFFST_DACR1_VALUE_FIELD		0
+#define STV090x_WIDTH_DACR1_VALUE_FIELD		4
+
+#define STV090x_DACR2				0xf114
+#define STV090x_OFFST_DACR2_VALUE_FIELD		0
+#define STV090x_WIDTH_DACR2_VALUE_FIELD		8
+
+#define STV090x_OUTCFG				0xf11c
+#define STV090x_OFFST_OUTSERRS1_HZ_FIELD	6
+#define STV090x_WIDTH_OUTSERRS1_HZ_FIELD	1
+#define STV090x_OFFST_OUTSERRS2_HZ_FIELD	5
+#define STV090x_WIDTH_OUTSERRS2_HZ_FIELD	1
+#define STV090x_OFFST_OUTSERRS3_HZ_FIELD	4
+#define STV090x_WIDTH_OUTSERRS3_HZ_FIELD	1
+#define STV090x_OFFST_OUTPARRS3_HZ_FIELD	3
+#define STV090x_WIDTH_OUTPARRS3_HZ_FIELD	1
+
+#define STV090x_MODECFG				0xf11d
+
+#define STV090x_IRQSTATUS3			0xf120
+#define STV090x_OFFST_SPLL_LOCK_FIELD		5
+#define STV090x_WIDTH_SPLL_LOCK_FIELD		1
+#define STV090x_OFFST_SSTREAM_LCK_3_FIELD	4
+#define STV090x_WIDTH_SSTREAM_LCK_3_FIELD	1
+#define STV090x_OFFST_SSTREAM_LCK_2_FIELD	3
+#define STV090x_WIDTH_SSTREAM_LCK_2_FIELD	1
+#define STV090x_OFFST_SSTREAM_LCK_1_FIELD	2
+#define STV090x_WIDTH_SSTREAM_LCK_1_FIELD	1
+#define STV090x_OFFST_SDVBS1_PRF_2_FIELD	1
+#define STV090x_WIDTH_SDVBS1_PRF_2_FIELD	1
+#define STV090x_OFFST_SDVBS1_PRF_1_FIELD	0
+#define STV090x_WIDTH_SDVBS1_PRF_1_FIELD	1
+
+#define STV090x_IRQSTATUS2			0xf121
+#define STV090x_OFFST_SSPY_ENDSIM_3_FIELD	7
+#define STV090x_WIDTH_SSPY_ENDSIM_3_FIELD	1
+#define STV090x_OFFST_SSPY_ENDSIM_2_FIELD	6
+#define STV090x_WIDTH_SSPY_ENDSIM_2_FIELD	1
+#define STV090x_OFFST_SSPY_ENDSIM_1_FIELD	5
+#define STV090x_WIDTH_SSPY_ENDSIM_1_FIELD	1
+#define STV090x_OFFST_SPKTDEL_ERROR_2_FIELD	4
+#define STV090x_WIDTH_SPKTDEL_ERROR_2_FIELD	1
+#define STV090x_OFFST_SPKTDEL_LOCKB_2_FIELD	3
+#define STV090x_WIDTH_SPKTDEL_LOCKB_2_FIELD	1
+#define STV090x_OFFST_SPKTDEL_LOCK_2_FIELD	2
+#define STV090x_WIDTH_SPKTDEL_LOCK_2_FIELD	1
+#define STV090x_OFFST_SPKTDEL_ERROR_1_FIELD	1
+#define STV090x_WIDTH_SPKTDEL_ERROR_1_FIELD	1
+#define STV090x_OFFST_SPKTDEL_LOCKB_1_FIELD	0
+#define STV090x_WIDTH_SPKTDEL_LOCKB_1_FIELD	1
+
+#define STV090x_IRQSTATUS1			0xf122
+#define STV090x_OFFST_SPKTDEL_LOCK_1_FIELD	7
+#define STV090x_WIDTH_SPKTDEL_LOCK_1_FIELD	1
+#define STV090x_OFFST_SDEMOD_LOCKB_2_FIELD	2
+#define STV090x_WIDTH_SDEMOD_LOCKB_2_FIELD	1
+#define STV090x_OFFST_SDEMOD_LOCK_2_FIELD	1
+#define STV090x_WIDTH_SDEMOD_LOCK_2_FIELD	1
+#define STV090x_OFFST_SDEMOD_IRQ_2_FIELD	0
+#define STV090x_WIDTH_SDEMOD_IRQ_2_FIELD	1
+
+#define STV090x_IRQSTATUS0			0xf123
+#define STV090x_OFFST_SDEMOD_LOCKB_1_FIELD	7
+#define STV090x_WIDTH_SDEMOD_LOCKB_1_FIELD	1
+#define STV090x_OFFST_SDEMOD_LOCK_1_FIELD	6
+#define STV090x_WIDTH_SDEMOD_LOCK_1_FIELD	1
+#define STV090x_OFFST_SDEMOD_IRQ_1_FIELD	5
+#define STV090x_WIDTH_SDEMOD_IRQ_1_FIELD	1
+#define STV090x_OFFST_SBCH_ERRFLAG_FIELD	4
+#define STV090x_WIDTH_SBCH_ERRFLAG_FIELD	1
+#define STV090x_OFFST_SDISEQC2RX_IRQ_FIELD	3
+#define STV090x_WIDTH_SDISEQC2RX_IRQ_FIELD	1
+#define STV090x_OFFST_SDISEQC2TX_IRQ_FIELD	2
+#define STV090x_WIDTH_SDISEQC2TX_IRQ_FIELD	1
+#define STV090x_OFFST_SDISEQC1RX_IRQ_FIELD	1
+#define STV090x_WIDTH_SDISEQC1RX_IRQ_FIELD	1
+#define STV090x_OFFST_SDISEQC1TX_IRQ_FIELD	0
+#define STV090x_WIDTH_SDISEQC1TX_IRQ_FIELD	1
+
+#define STV090x_IRQMASK3			0xf124
+#define STV090x_OFFST_MPLL_LOCK_FIELD		5
+#define STV090x_WIDTH_MPLL_LOCK_FIELD		1
+#define STV090x_OFFST_MSTREAM_LCK_3_FIELD	4
+#define STV090x_WIDTH_MSTREAM_LCK_3_FIELD	1
+#define STV090x_OFFST_MSTREAM_LCK_2_FIELD	3
+#define STV090x_WIDTH_MSTREAM_LCK_2_FIELD	1
+#define STV090x_OFFST_MSTREAM_LCK_1_FIELD	2
+#define STV090x_WIDTH_MSTREAM_LCK_1_FIELD	1
+#define STV090x_OFFST_MDVBS1_PRF_2_FIELD	1
+#define STV090x_WIDTH_MDVBS1_PRF_2_FIELD	1
+#define STV090x_OFFST_MDVBS1_PRF_1_FIELD	0
+#define STV090x_WIDTH_MDVBS1_PRF_1_FIELD	1
+
+#define STV090x_IRQMASK2			0xf125
+#define STV090x_OFFST_MSPY_ENDSIM_3_FIELD	7
+#define STV090x_WIDTH_MSPY_ENDSIM_3_FIELD	1
+#define STV090x_OFFST_MSPY_ENDSIM_2_FIELD	6
+#define STV090x_WIDTH_MSPY_ENDSIM_2_FIELD	1
+#define STV090x_OFFST_MSPY_ENDSIM_1_FIELD	5
+#define STV090x_WIDTH_MSPY_ENDSIM_1_FIELD	1
+#define STV090x_OFFST_MPKTDEL_ERROR_2_FIELD	4
+#define STV090x_WIDTH_MPKTDEL_ERROR_2_FIELD	1
+#define STV090x_OFFST_MPKTDEL_LOCKB_2_FIELD	3
+#define STV090x_WIDTH_MPKTDEL_LOCKB_2_FIELD	1
+#define STV090x_OFFST_MPKTDEL_LOCK_2_FIELD	2
+#define STV090x_WIDTH_MPKTDEL_LOCK_2_FIELD	1
+#define STV090x_OFFST_MPKTDEL_ERROR_1_FIELD	1
+#define STV090x_WIDTH_MPKTDEL_ERROR_1_FIELD	1
+#define STV090x_OFFST_MPKTDEL_LOCKB_1_FIELD	0
+#define STV090x_WIDTH_MPKTDEL_LOCKB_1_FIELD	1
+
+#define STV090x_IRQMASK1			0xf126
+#define STV090x_OFFST_MPKTDEL_LOCK_1_FIELD	7
+#define STV090x_WIDTH_MPKTDEL_LOCK_1_FIELD	1
+#define STV090x_OFFST_MEXTPINB2_FIELD		6
+#define STV090x_WIDTH_MEXTPINB2_FIELD		1
+#define STV090x_OFFST_MEXTPIN2_FIELD		5
+#define STV090x_WIDTH_MEXTPIN2_FIELD		1
+#define STV090x_OFFST_MEXTPINB1_FIELD		4
+#define STV090x_WIDTH_MEXTPINB1_FIELD		1
+#define STV090x_OFFST_MEXTPIN1_FIELD		3
+#define STV090x_WIDTH_MEXTPIN1_FIELD		1
+#define STV090x_OFFST_MDEMOD_LOCKB_2_FIELD	2
+#define STV090x_WIDTH_MDEMOD_LOCKB_2_FIELD	1
+#define STV090x_OFFST_MDEMOD_LOCK_2_FIELD	1
+#define STV090x_WIDTH_MDEMOD_LOCK_2_FIELD	1
+#define STV090x_OFFST_MDEMOD_IRQ_2_FIELD	0
+#define STV090x_WIDTH_MDEMOD_IRQ_2_FIELD	1
+
+#define STV090x_IRQMASK0			0xf127
+#define STV090x_OFFST_MDEMOD_LOCKB_1_FIELD	7
+#define STV090x_WIDTH_MDEMOD_LOCKB_1_FIELD	1
+#define STV090x_OFFST_MDEMOD_LOCK_1_FIELD	6
+#define STV090x_WIDTH_MDEMOD_LOCK_1_FIELD	1
+#define STV090x_OFFST_MDEMOD_IRQ_1_FIELD	5
+#define STV090x_WIDTH_MDEMOD_IRQ_1_FIELD	1
+#define STV090x_OFFST_MBCH_ERRFLAG_FIELD	4
+#define STV090x_WIDTH_MBCH_ERRFLAG_FIELD	1
+#define STV090x_OFFST_MDISEQC2RX_IRQ_FIELD	3
+#define STV090x_WIDTH_MDISEQC2RX_IRQ_FIELD	1
+#define STV090x_OFFST_MDISEQC2TX_IRQ_FIELD	2
+#define STV090x_WIDTH_MDISEQC2TX_IRQ_FIELD	1
+#define STV090x_OFFST_MDISEQC1RX_IRQ_FIELD	1
+#define STV090x_WIDTH_MDISEQC1RX_IRQ_FIELD	1
+#define STV090x_OFFST_MDISEQC1TX_IRQ_FIELD	0
+#define STV090x_WIDTH_MDISEQC1TX_IRQ_FIELD	1
+
+#define STV090x_I2CCFG				0xf129
+#define STV090x_OFFST_12C_FASTMODE_FIELD	3
+#define STV090x_WIDTH_12C_FASTMODE_FIELD	1
+#define STV090x_OFFST_12CADDR_INC_FIELD		0
+#define STV090x_WIDTH_12CADDR_INC_FIELD		2
+
+#define STV090x_Px_I2CRPT(__x)			(0xf12a + (__x - 1) * 0x1)
+#define STV090x_P1_I2CRPT			STV090x_Px_I2CRPT(1)
+#define STV090x_P2_I2CRPT			STV090x_Px_I2CRPT(2)
+#define STV090x_OFFST_Px_I2CT_ON_FIELD		7
+#define STV090x_WIDTH_Px_I2CT_ON_FIELD		1
+#define STV090x_OFFST_Px_ENARPT_LEVEL_FIELD	4
+#define STV090x_WIDTH_Px_ENARPT_LEVEL_FIELD	3
+#define STV090x_OFFST_Px_SCLT_DELAY_FIELD	3
+#define STV090x_WIDTH_Px_SCLT_DELAY_FIELD	1
+#define STV090x_OFFST_Px_STOP_ENABLE_FIELD	2
+#define STV090x_WIDTH_Px_STOP_ENABLE_FIELD	1
+#define STV090x_OFFST_Px_STOP_SDAT2SDA_FIELD	1
+#define STV090x_WIDTH_Px_STOP_SDAT2SDA_FIELD	1
+
+#define STV090x_CLKI2CFG			0xf140
+#define STV090x_OFFST_CLKI2_OPD_FIELD		7
+#define STV090x_WIDTH_CLKI2_OPD_FIELD		1
+#define STV090x_OFFST_CLKI2_CONFIG_FIELD	1
+#define STV090x_WIDTH_CLKI2_CONFIG_FIELD	6
+#define STV090x_OFFST_CLKI2_XOR_FIELD		0
+#define STV090x_WIDTH_CLKI2_XOR_FIELD		1
+
+#define STV090x_GPIOxCFG(__x)			(0xf141 + (__x - 1))
+#define STV090x_GPIO1CFG			STV090x_GPIOxCFG(1)
+#define STV090x_GPIO2CFG			STV090x_GPIOxCFG(2)
+#define STV090x_GPIO3CFG			STV090x_GPIOxCFG(3)
+#define STV090x_GPIO4CFG			STV090x_GPIOxCFG(4)
+#define STV090x_GPIO5CFG			STV090x_GPIOxCFG(5)
+#define STV090x_GPIO6CFG			STV090x_GPIOxCFG(6)
+#define STV090x_GPIO7CFG			STV090x_GPIOxCFG(7)
+#define STV090x_GPIO8CFG			STV090x_GPIOxCFG(8)
+#define STV090x_GPIO9CFG			STV090x_GPIOxCFG(9)
+#define STV090x_GPIO10CFG			STV090x_GPIOxCFG(10)
+#define STV090x_GPIO11CFG			STV090x_GPIOxCFG(11)
+#define STV090x_GPIO12CFG			STV090x_GPIOxCFG(12)
+#define STV090x_GPIO13CFG			STV090x_GPIOxCFG(13)
+#define STV090x_OFFST_GPIOx_OPD_FIELD		7
+#define STV090x_WIDTH_GPIOx_OPD_FIELD		1
+#define STV090x_OFFST_GPIOx_CONFIG_FIELD	1
+#define STV090x_WIDTH_GPIOx_CONFIG_FIELD	6
+#define STV090x_OFFST_GPIOx_XOR_FIELD		0
+#define STV090x_WIDTH_GPIOx_XOR_FIELD		1
+
+#define STV090x_CSxCFG(__x)			(0xf14e + __x * 0x1)
+#define STV090x_CS0CFG				STV090x_CSxCFG(0)
+#define STV090x_CS1CFG				STV090x_CSxCFG(1)
+#define STV090x_OFFST_CSX_OPD_FIELD		7
+#define STV090x_WIDTH_CSX_OPD_FIELD		1
+#define STV090x_OFFST_CSX_CONFIG_FIELD		1
+#define STV090x_WIDTH_CSX_CONFIG_FIELD		6
+#define STV090x_OFFST_CSX_XOR_FIELD		0
+#define STV090x_WIDTH_CSX_XOR_FIELD		1
+
+
+#define STV090x_STDBYCFG			0xf150
+#define STV090x_OFFST_STDBY_OPD_FIELD		7
+#define STV090x_WIDTH_STDBY_OPD_FIELD		1
+#define STV090x_OFFST_STDBY_CONFIG_FIELD	1
+#define STV090x_WIDTH_STDBY_CONFIG_FIELD	6
+#define STV090x_OFFST_STDBY_XOR_FIELD		0
+#define STV090x_WIDTH_STDBY_XOR_FIELD		1
+
+#define STV090x_DIRCLKCFG			0xf151
+#define STV090x_OFFST_DIRCLK_OPD_FIELD		7
+#define STV090x_WIDTH_DIRCLK_OPD_FIELD		1
+#define STV090x_OFFST_DIRCLK_CONFIG_FIELD	1
+#define STV090x_WIDTH_DIRCLK_CONFIG_FIELD	6
+#define STV090x_OFFST_DIRCLK_XOR_FIELD		0
+#define STV090x_WIDTH_DIRCLK_XOR_FIELD		1
+
+
+#define STV090x_AGCRFxCFG(__x)			(0xf152 + (__x - 1) * 0x4)
+#define STV090x_AGCRF1CFG			STV090x_AGCRFxCFG(1)
+#define STV090x_AGCRF2CFG			STV090x_AGCRFxCFG(2)
+#define STV090x_OFFST_AGCRFx_OPD_FIELD		7
+#define STV090x_WIDTH_AGCRFx_OPD_FIELD		1
+#define STV090x_OFFST_AGCRFx_CONFIG_FIELD	1
+#define STV090x_WIDTH_AGCRFx_CONFIG_FIELD	6
+#define STV090x_OFFST_AGCRFx_XOR_FIELD		0
+#define STV090x_WIDTH_AGCRFx_XOR_FIELD		1
+
+#define STV090x_SDATxCFG(__x)			(0xf153 + (__x - 1) * 0x4)
+#define STV090x_SDAT1CFG			STV090x_SDATxCFG(1)
+#define STV090x_SDAT2CFG			STV090x_SDATxCFG(2)
+#define STV090x_OFFST_SDATx_OPD_FIELD		7
+#define STV090x_WIDTH_SDATx_OPD_FIELD		1
+#define STV090x_OFFST_SDATx_CONFIG_FIELD	1
+#define STV090x_WIDTH_SDATx_CONFIG_FIELD	6
+#define STV090x_OFFST_SDATx_XOR_FIELD		0
+#define STV090x_WIDTH_SDATx_XOR_FIELD		1
+
+#define STV090x_SCLTxCFG(__x)			(0xf154 + (__x - 1) * 0x4)
+#define STV090x_SCLT1CFG			STV090x_SCLTxCFG(1)
+#define STV090x_SCLT2CFG			STV090x_SCLTxCFG(2)
+#define STV090x_OFFST_SCLTx_OPD_FIELD		7
+#define STV090x_WIDTH_SCLTx_OPD_FIELD		1
+#define STV090x_OFFST_SCLTx_CONFIG_FIELD	1
+#define STV090x_WIDTH_SCLTx_CONFIG_FIELD	6
+#define STV090x_OFFST_SCLTx_XOR_FIELD		0
+#define STV090x_WIDTH_SCLTx_XOR_FIELD		1
+
+#define STV090x_DISEQCOxCFG(__x)		(0xf155 + (__x - 1) * 0x4)
+#define STV090x_DISEQCO1CFG			STV090x_DISEQCOxCFG(1)
+#define STV090x_DISEQCO2CFG			STV090x_DISEQCOxCFG(2)
+#define STV090x_OFFST_DISEQCOx_OPD_FIELD	7
+#define STV090x_WIDTH_DISEQCOx_OPD_FIELD	1
+#define STV090x_OFFST_DISEQCOx_CONFIG_FIELD	1
+#define STV090x_WIDTH_DISEQCOx_CONFIG_FIELD	6
+#define STV090x_OFFST_DISEQCOx_XOR_FIELD	0
+#define STV090x_WIDTH_DISEQCOx_XOR_FIELD	1
+
+#define STV090x_CLKOUT27CFG			0xf15a
+#define STV090x_OFFST_CLKOUT27_OPD_FIELD	7
+#define STV090x_WIDTH_CLKOUT27_OPD_FIELD	1
+#define STV090x_OFFST_CLKOUT27_CONFIG_FIELD	1
+#define STV090x_WIDTH_CLKOUT27_CONFIG_FIELD	6
+#define STV090x_OFFST_CLKOUT27_XOR_FIELD	0
+#define STV090x_WIDTH_CLKOUT27_XOR_FIELD	1
+
+#define STV090x_ERRORxCFG(__x)			(0xf15b + (__x - 1) * 0x5)
+#define STV090x_ERROR1CFG			STV090x_ERRORxCFG(1)
+#define STV090x_ERROR2CFG			STV090x_ERRORxCFG(2)
+#define STV090x_ERROR3CFG			STV090x_ERRORxCFG(3)
+#define STV090x_OFFST_ERRORx_OPD_FIELD		7
+#define STV090x_WIDTH_ERRORx_OPD_FIELD		1
+#define STV090x_OFFST_ERRORx_CONFIG_FIELD	1
+#define STV090x_WIDTH_ERRORx_CONFIG_FIELD	6
+#define STV090x_OFFST_ERRORx_XOR_FIELD		0
+#define STV090x_WIDTH_ERRORx_XOR_FIELD		1
+
+#define STV090x_DPNxCFG(__x)			(0xf15c + (__x - 1) * 0x5)
+#define STV090x_DPN1CFG				STV090x_DPNxCFG(1)
+#define STV090x_DPN2CFG				STV090x_DPNxCFG(2)
+#define STV090x_DPN3CFG				STV090x_DPNxCFG(3)
+#define STV090x_OFFST_DPNx_OPD_FIELD		7
+#define STV090x_WIDTH_DPNx_OPD_FIELD		1
+#define STV090x_OFFST_DPNx_CONFIG_FIELD		1
+#define STV090x_WIDTH_DPNx_CONFIG_FIELD		6
+#define STV090x_OFFST_DPNx_XOR_FIELD		0
+#define STV090x_WIDTH_DPNx_XOR_FIELD		1
+
+#define STV090x_STROUTxCFG(__x)			(0xf15d + (__x - 1) * 0x5)
+#define STV090x_STROUT1CFG			STV090x_STROUTxCFG(1)
+#define STV090x_STROUT2CFG			STV090x_STROUTxCFG(2)
+#define STV090x_STROUT3CFG			STV090x_STROUTxCFG(3)
+#define STV090x_OFFST_STROUTx_OPD_FIELD		7
+#define STV090x_WIDTH_STROUTx_OPD_FIELD		1
+#define STV090x_OFFST_STROUTx_CONFIG_FIELD	1
+#define STV090x_WIDTH_STROUTx_CONFIG_FIELD	6
+#define STV090x_OFFST_STROUTx_XOR_FIELD		0
+#define STV090x_WIDTH_STROUTx_XOR_FIELD		1
+
+#define STV090x_CLKOUTxCFG(__x)			(0xf15e + (__x - 1) * 0x5)
+#define STV090x_CLKOUT1CFG			STV090x_CLKOUTxCFG(1)
+#define STV090x_CLKOUT2CFG			STV090x_CLKOUTxCFG(2)
+#define STV090x_CLKOUT3CFG			STV090x_CLKOUTxCFG(3)
+#define STV090x_OFFST_CLKOUTx_OPD_FIELD		7
+#define STV090x_WIDTH_CLKOUTx_OPD_FIELD		1
+#define STV090x_OFFST_CLKOUTx_CONFIG_FIELD	1
+#define STV090x_WIDTH_CLKOUTx_CONFIG_FIELD	6
+#define STV090x_OFFST_CLKOUTx_XOR_FIELD		0
+#define STV090x_WIDTH_CLKOUTx_XOR_FIELD		1
+
+#define STV090x_DATAxCFG(__x)			(0xf15f + (__x - 71) * 0x5)
+#define STV090x_DATA71CFG			STV090x_DATAxCFG(71)
+#define STV090x_DATA72CFG			STV090x_DATAxCFG(72)
+#define STV090x_DATA73CFG			STV090x_DATAxCFG(73)
+#define STV090x_OFFST_DATAx_OPD_FIELD		7
+#define STV090x_WIDTH_DATAx_OPD_FIELD		1
+#define STV090x_OFFST_DATAx_CONFIG_FIELD	1
+#define STV090x_WIDTH_DATAx_CONFIG_FIELD	6
+#define STV090x_OFFST_DATAx_XOR_FIELD		0
+#define STV090x_WIDTH_DATAx_XOR_FIELD		1
+
+#define STV090x_NCOARSE				0xf1b3
+#define STV090x_OFFST_M_DIV_FIELD		0
+#define STV090x_WIDTH_M_DIV_FIELD		8
+
+#define STV090x_SYNTCTRL			0xf1b6
+#define STV090x_OFFST_STANDBY_FIELD		7
+#define STV090x_WIDTH_STANDBY_FIELD		1
+#define STV090x_OFFST_BYPASSPLLCORE_FIELD	6
+#define STV090x_WIDTH_BYPASSPLLCORE_FIELD	1
+#define STV090x_OFFST_SELX1RATIO_FIELD		5
+#define STV090x_WIDTH_SELX1RATIO_FIELD		1
+#define STV090x_OFFST_STOP_PLL_FIELD		3
+#define STV090x_WIDTH_STOP_PLL_FIELD		1
+#define STV090x_OFFST_BYPASSPLLFSK_FIELD	2
+#define STV090x_WIDTH_BYPASSPLLFSK_FIELD	1
+#define STV090x_OFFST_SELOSCI_FIELD		1
+#define STV090x_WIDTH_SELOSCI_FIELD		1
+#define STV090x_OFFST_BYPASSPLLADC_FIELD	0
+#define STV090x_WIDTH_BYPASSPLLADC_FIELD	1
+
+#define STV090x_FILTCTRL			0xf1b7
+#define STV090x_OFFST_INV_CLK135_FIELD		7
+#define STV090x_WIDTH_INV_CLK135_FIELD		1
+#define STV090x_OFFST_SEL_FSKCKDIV_FIELD	2
+#define STV090x_WIDTH_SEL_FSKCKDIV_FIELD	1
+#define STV090x_OFFST_INV_CLKFSK_FIELD		1
+#define STV090x_WIDTH_INV_CLKFSK_FIELD		1
+#define STV090x_OFFST_BYPASS_APPLI_FIELD	0
+#define STV090x_WIDTH_BYPASS_APPLI_FIELD	1
+
+#define STV090x_PLLSTAT				0xf1b8
+#define STV090x_OFFST_PLLLOCK_FIELD		0
+#define STV090x_WIDTH_PLLLOCK_FIELD		1
+
+#define STV090x_STOPCLK1			0xf1c2
+#define STV090x_OFFST_STOP_CLKPKDT2_FIELD	6
+#define STV090x_WIDTH_STOP_CLKPKDT2_FIELD	1
+#define STV090x_OFFST_STOP_CLKPKDT1_FIELD	5
+#define STV090x_WIDTH_STOP_CLKPKDT1_FIELD	1
+#define STV090x_OFFST_STOP_CLKFEC_FIELD		4
+#define STV090x_WIDTH_STOP_CLKFEC_FIELD		1
+#define STV090x_OFFST_STOP_CLKADCI2_FIELD	3
+#define STV090x_WIDTH_STOP_CLKADCI2_FIELD	1
+#define STV090x_OFFST_INV_CLKADCI2_FIELD	2
+#define STV090x_WIDTH_INV_CLKADCI2_FIELD	1
+#define STV090x_OFFST_STOP_CLKADCI1_FIELD	1
+#define STV090x_WIDTH_STOP_CLKADCI1_FIELD	1
+#define STV090x_OFFST_INV_CLKADCI1_FIELD	0
+#define STV090x_WIDTH_INV_CLKADCI1_FIELD	1
+
+#define STV090x_STOPCLK2			0xf1c3
+#define STV090x_OFFST_STOP_CLKSAMP2_FIELD	4
+#define STV090x_WIDTH_STOP_CLKSAMP2_FIELD	1
+#define STV090x_OFFST_STOP_CLKSAMP1_FIELD	3
+#define STV090x_WIDTH_STOP_CLKSAMP1_FIELD	1
+#define STV090x_OFFST_STOP_CLKVIT2_FIELD	2
+#define STV090x_WIDTH_STOP_CLKVIT2_FIELD	1
+#define STV090x_OFFST_STOP_CLKVIT1_FIELD	1
+#define STV090x_WIDTH_STOP_CLKVIT1_FIELD	1
+#define STV090x_OFFST_STOP_CLKTS_FIELD		0
+#define STV090x_WIDTH_STOP_CLKTS_FIELD		1
+
+#define STV090x_TSTTNR0				0xf1df
+#define STV090x_OFFST_SEL_FSK_FIELD		7
+#define STV090x_WIDTH_SEL_FSK_FIELD		1
+#define STV090x_OFFST_FSK_PON_FIELD		2
+#define STV090x_WIDTH_FSK_PON_FIELD		1
+
+#define STV090x_TSTTNR1				0xf1e0
+#define STV090x_OFFST_ADC1_PON_FIELD		1
+#define STV090x_WIDTH_ADC1_PON_FIELD		1
+#define STV090x_OFFST_ADC1_INMODE_FIELD		0
+#define STV090x_WIDTH_ADC1_INMODE_FIELD		1
+
+#define STV090x_TSTTNR2				0xf1e1
+#define STV090x_OFFST_DISEQC1_PON_FIELD		5
+#define STV090x_WIDTH_DISEQC1_PON_FIELD		1
+
+#define STV090x_TSTTNR3				0xf1e2
+#define STV090x_OFFST_ADC2_PON_FIELD		1
+#define STV090x_WIDTH_ADC2_PON_FIELD		1
+#define STV090x_OFFST_ADC2_INMODE_FIELD		0
+#define STV090x_WIDTH_ADC2_INMODE_FIELD		1
+
+#define STV090x_TSTTNR4				0xf1e3
+#define STV090x_OFFST_DISEQC2_PON_FIELD		5
+#define STV090x_WIDTH_DISEQC2_PON_FIELD		1
+
+#define STV090x_FSKTFC2				0xf170
+#define STV090x_OFFST_FSKT_KMOD_FIELD		2
+#define STV090x_WIDTH_FSKT_KMOD_FIELD		6
+#define STV090x_OFFST_FSKT_CAR_FIELD		0
+#define STV090x_WIDTH_FSKT_CAR_FIELD		2
+
+#define STV090x_FSKTFC1				0xf171
+#define STV090x_OFFST_FSKTC1_CAR_FIELD		0
+#define STV090x_WIDTH_FSKTC1_CAR_FIELD		8
+
+#define STV090x_FSKTFC0				0xf172
+#define STV090x_OFFST_FSKTC0_CAR_FIELD		0
+#define STV090x_WIDTH_FSKTC0_CAR_FIELD		8
+
+#define STV090x_FSKTDELTAF1			0xf173
+#define STV090x_OFFST_FSKTF1_DELTAF_FIELD	0
+#define STV090x_WIDTH_FSKTF1_DELTAF_FIELD	4
+
+#define STV090x_FSKTDELTAF0			0xf174
+#define STV090x_OFFST_FSKTF0_DELTAF_FIELD	0
+#define STV090x_WIDTH_FSKTF0_DELTAF_FIELD	8
+
+#define STV090x_FSKTCTRL			0xf175
+#define STV090x_OFFST_FSKT_EN_SGN_FIELD		6
+#define STV090x_WIDTH_FSKT_EN_SGN_FIELD		1
+#define STV090x_OFFST_FSKT_MOD_SGN_FIELD	5
+#define STV090x_WIDTH_FSKT_MOD_SGN_FIELD	1
+#define STV090x_OFFST_FSKT_MOD_EN_FIELD		2
+#define STV090x_WIDTH_FSKT_MOD_EN_FIELD		3
+#define STV090x_OFFST_FSKT_DACMODE_FIELD	0
+#define STV090x_WIDTH_FSKT_DACMODE_FIELD	2
+
+#define STV090x_FSKRFC2				0xf176
+#define STV090x_OFFST_FSKRC2_DETSGN_FIELD	6
+#define STV090x_WIDTH_FSKRC2_DETSGN_FIELD	1
+#define STV090x_OFFST_FSKRC2_OUTSGN_FIELD	5
+#define STV090x_WIDTH_FSKRC2_OUTSGN_FIELD	1
+#define STV090x_OFFST_FSKRC2_KAGC_FIELD		2
+#define STV090x_WIDTH_FSKRC2_KAGC_FIELD		3
+#define STV090x_OFFST_FSKRC2_CAR_FIELD		0
+#define STV090x_WIDTH_FSKRC2_CAR_FIELD		2
+
+#define STV090x_FSKRFC1				0xf177
+#define STV090x_OFFST_FSKRC1_CAR_FIELD		0
+#define STV090x_WIDTH_FSKRC1_CAR_FIELD		8
+
+#define STV090x_FSKRFC0				0xf178
+#define STV090x_OFFST_FSKRC0_CAR_FIELD		0
+#define STV090x_WIDTH_FSKRC0_CAR_FIELD		8
+
+#define STV090x_FSKRK1				0xf179
+#define STV090x_OFFST_FSKR_K1_EXP_FIELD		5
+#define STV090x_WIDTH_FSKR_K1_EXP_FIELD		3
+#define STV090x_OFFST_FSKR_K1_MANT_FIELD	0
+#define STV090x_WIDTH_FSKR_K1_MANT_FIELD	5
+
+#define STV090x_FSKRK2				0xf17a
+#define STV090x_OFFST_FSKR_K2_EXP_FIELD		5
+#define STV090x_WIDTH_FSKR_K2_EXP_FIELD		3
+#define STV090x_OFFST_FSKR_K2_MANT_FIELD	0
+#define STV090x_WIDTH_FSKR_K2_MANT_FIELD	5
+
+#define STV090x_FSKRAGCR			0xf17b
+#define STV090x_OFFST_FSKR_OUTCTL_FIELD		6
+#define STV090x_WIDTH_FSKR_OUTCTL_FIELD		2
+#define STV090x_OFFST_FSKR_AGC_REF_FIELD	0
+#define STV090x_WIDTH_FSKR_AGC_REF_FIELD	6
+
+#define STV090x_FSKRAGC				0xf17c
+#define STV090x_OFFST_FSKR_AGC_ACCU_FIELD	0
+#define STV090x_WIDTH_FSKR_AGC_ACCU_FIELD	8
+
+#define STV090x_FSKRALPHA			0xf17d
+#define STV090x_OFFST_FSKR_ALPHA_EXP_FIELD	2
+#define STV090x_WIDTH_FSKR_ALPHA_EXP_FIELD	3
+#define STV090x_OFFST_FSKR_ALPHA_M_FIELD	0
+#define STV090x_WIDTH_FSKR_ALPHA_M_FIELD	2
+
+#define STV090x_FSKRPLTH1			0xf17e
+#define STV090x_OFFST_FSKR_BETA_FIELD		4
+#define STV090x_WIDTH_FSKR_BETA_FIELD		4
+#define STV090x_OFFST_FSKR_PLL_TRESH1_FIELD	0
+#define STV090x_WIDTH_FSKR_PLL_TRESH1_FIELD	4
+
+#define STV090x_FSKRPLTH0			0xf17f
+#define STV090x_OFFST_FSKR_PLL_TRESH0_FIELD	0
+#define STV090x_WIDTH_FSKR_PLL_TRESH0_FIELD	8
+
+#define STV090x_FSKRDF1				0xf180
+#define STV090x_OFFST_FSKR_DELTAF1_FIELD	0
+#define STV090x_WIDTH_FSKR_DELTAF1_FIELD	5
+
+#define STV090x_FSKRDF0				0xf181
+#define STV090x_OFFST_FSKR_DELTAF0_FIELD	0
+#define STV090x_WIDTH_FSKR_DELTAF0_FIELD	8
+
+#define STV090x_FSKRSTEPP			0xf182
+#define STV090x_OFFST_FSKR_STEP_PLUS_FIELD	0
+#define STV090x_WIDTH_FSKR_STEP_PLUS_FIELD	8
+
+#define STV090x_FSKRSTEPM			0xf183
+#define STV090x_OFFST_FSKR_STEP_MINUS_FIELD	0
+#define STV090x_WIDTH_FSKR_STEP_MINUS_FIELD	8
+
+#define STV090x_FSKRDET1			0xf184
+#define STV090x_OFFST_FSKR_CARDET1_ACCU_FIELD	0
+#define STV090x_WIDTH_FSKR_CARDET1_ACCU_FIELD	4
+
+#define STV090x_FSKRDET0			0xf185
+#define STV090x_OFFST_FSKR_CARDET0_ACCU_FIELD	0
+#define STV090x_WIDTH_FSKR_CARDET0_ACCU_FIELD	8
+
+#define STV090x_FSKRDTH1				0xf186
+#define STV090x_OFFST_FSKR_CARLOSS_THRESH1_FIELD	4
+#define STV090x_WIDTH_FSKR_CARLOSS_THRESH1_FIELD	4
+#define STV090x_OFFST_FSKR_CARDET_THRESH1_FIELD		0
+#define STV090x_WIDTH_FSKR_CARDET_THRESH1_FIELD		4
+
+#define STV090x_FSKRDTH0			0xf187
+#define STV090x_OFFST_FSKR_CARDET_THRESH0_FIELD	0
+#define STV090x_WIDTH_FSKR_CARDET_THRESH0_FIELD	8
+
+#define STV090x_FSKRLOSS			0xf188
+#define STV090x_OFFST_FSKR_CARLOSS_THRESH_FIELD	0
+#define STV090x_WIDTH_FSKR_CARLOSS_THRESH_FIELD	8
+
+#define STV090x_Px_DISTXCTL(__x)		(0xF1A0 - (__x - 1) * 0x10)
+#define STV090x_P1_DISTXCTL			STV090x_Px_DISTXCTL(1)
+#define STV090x_P2_DISTXCTL			STV090x_Px_DISTXCTL(2)
+#define STV090x_OFFST_Px_TIM_OFF_FIELD		7
+#define STV090x_WIDTH_Px_TIM_OFF_FIELD		1
+#define STV090x_OFFST_Px_DISEQC_RESET_FIELD	6
+#define STV090x_WIDTH_Px_DISEQC_RESET_FIELD	1
+#define STV090x_OFFST_Px_TIM_CMD_FIELD		4
+#define STV090x_WIDTH_Px_TIM_CMD_FIELD		2
+#define STV090x_OFFST_Px_DIS_PRECHARGE_FIELD	3
+#define STV090x_WIDTH_Px_DIS_PRECHARGE_FIELD	1
+#define STV090x_OFFST_Px_DISTX_MODE_FIELD	0
+#define STV090x_WIDTH_Px_DISTX_MODE_FIELD	3
+
+#define STV090x_Px_DISRXCTL(__x)		(0xf1a1 - (__x - 1) * 0x10)
+#define STV090x_P1_DISRXCTL			STV090x_Px_DISRXCTL(1)
+#define STV090x_P2_DISRXCTL			STV090x_Px_DISRXCTL(2)
+#define STV090x_OFFST_Px_RECEIVER_ON_FIELD	7
+#define STV090x_WIDTH_Px_RECEIVER_ON_FIELD	1
+#define STV090x_OFFST_Px_IGNO_SHORT22K_FIELD	6
+#define STV090x_WIDTH_Px_IGNO_SHORT22K_FIELD	1
+#define STV090x_OFFST_Px_ONECHIP_TRX_FIELD	5
+#define STV090x_WIDTH_Px_ONECHIP_TRX_FIELD	1
+#define STV090x_OFFST_Px_EXT_ENVELOP_FIELD	4
+#define STV090x_WIDTH_Px_EXT_ENVELOP_FIELD	1
+#define STV090x_OFFST_Px_PIN_SELECT_FIELD	2
+#define STV090x_WIDTH_Px_PIN_SELECT_FIELD	2
+#define STV090x_OFFST_Px_IRQ_RXEND_FIELD	1
+#define STV090x_WIDTH_Px_IRQ_RXEND_FIELD	1
+#define STV090x_OFFST_Px_IRQ_4NBYTES_FIELD	0
+#define STV090x_WIDTH_Px_IRQ_4NBYTES_FIELD	1
+
+#define STV090x_Px_DISRX_ST0(__x)		(0xf1a4 - (__x - 1) * 0x10)
+#define STV090x_P1_DISRX_ST0			STV090x_Px_DISRX_ST0(1)
+#define STV090x_P2_DISRX_ST0			STV090x_Px_DISRX_ST0(2)
+#define STV090x_OFFST_Px_RX_END_FIELD		7
+#define STV090x_WIDTH_Px_RX_END_FIELD		1
+#define STV090x_OFFST_Px_RX_ACTIVE_FIELD	6
+#define STV090x_WIDTH_Px_RX_ACTIVE_FIELD	1
+#define STV090x_OFFST_Px_SHORT_22KHZ_FIELD	5
+#define STV090x_WIDTH_Px_SHORT_22KHZ_FIELD	1
+#define STV090x_OFFST_Px_CONT_TONE_FIELD	4
+#define STV090x_WIDTH_Px_CONT_TONE_FIELD	1
+#define STV090x_OFFST_Px_FIFO_4BREADY_FIELD	3
+#define STV090x_WIDTH_Px_FIFO_4BREADY_FIELD	1
+#define STV090x_OFFST_Px_FIFO_EMPTY_FIELD	2
+#define STV090x_WIDTH_Px_FIFO_EMPTY_FIELD	1
+#define STV090x_OFFST_Px_ABORT_DISRX_FIELD	0
+#define STV090x_WIDTH_Px_ABORT_DISRX_FIELD	1
+
+#define STV090x_Px_DISRX_ST1(__x)		(0xf1a5 - (__x - 1) * 0x10)
+#define STV090x_P1_DISRX_ST1			STV090x_Px_DISRX_ST1(1)
+#define STV090x_P2_DISRX_ST1			STV090x_Px_DISRX_ST1(2)
+#define STV090x_OFFST_Px_RX_FAIL_FIELD		7
+#define STV090x_WIDTH_Px_RX_FAIL_FIELD		1
+#define STV090x_OFFST_Px_FIFO_PARITYFAIL_FIELD	6
+#define STV090x_WIDTH_Px_FIFO_PARITYFAIL_FIELD	1
+#define STV090x_OFFST_Px_RX_NONBYTE_FIELD	5
+#define STV090x_WIDTH_Px_RX_NONBYTE_FIELD	1
+#define STV090x_OFFST_Px_FIFO_OVERFLOW_FIELD	4
+#define STV090x_WIDTH_Px_FIFO_OVERFLOW_FIELD	1
+#define STV090x_OFFST_Px_FIFO_BYTENBR_FIELD	0
+#define STV090x_WIDTH_Px_FIFO_BYTENBR_FIELD	4
+
+#define STV090x_Px_DISRXDATA(__x)		(0xf1a6 - (__x - 1) * 0x10)
+#define STV090x_P1_DISRXDATA			STV090x_Px_DISRXDATA(1)
+#define STV090x_P2_DISRXDATA			STV090x_Px_DISRXDATA(2)
+#define STV090x_OFFST_Px_DISRX_DATA_FIELD	0
+#define STV090x_WIDTH_Px_DISRX_DATA_FIELD	8
+
+#define STV090x_Px_DISTXDATA(__x)		(0xf1a7 - (__x - 1) * 0x10)
+#define STV090x_P1_DISTXDATA			STV090x_Px_DISTXDATA(1)
+#define STV090x_P2_DISTXDATA			STV090x_Px_DISTXDATA(2)
+#define STV090x_OFFST_Px_DISEQC_FIFO_FIELD	0
+#define STV090x_WIDTH_Px_DISEQC_FIFO_FIELD	8
+
+#define STV090x_Px_DISTXSTATUS(__x)		(0xf1a8 - (__x - 1) * 0x10)
+#define STV090x_P1_DISTXSTATUS			STV090x_Px_DISTXSTATUS(1)
+#define STV090x_P2_DISTXSTATUS			STV090x_Px_DISTXSTATUS(2)
+#define STV090x_OFFST_Px_TX_FAIL_FIELD		7
+#define STV090x_WIDTH_Px_TX_FAIL_FIELD		1
+#define STV090x_OFFST_Px_FIFO_FULL_FIELD	6
+#define STV090x_WIDTH_Px_FIFO_FULL_FIELD	1
+#define STV090x_OFFST_Px_TX_IDLE_FIELD		5
+#define STV090x_WIDTH_Px_TX_IDLE_FIELD		1
+#define STV090x_OFFST_Px_GAP_BURST_FIELD	4
+#define STV090x_WIDTH_Px_GAP_BURST_FIELD	1
+#define STV090x_OFFST_Px_TXFIFO_BYTES_FIELD	0
+#define STV090x_WIDTH_Px_TXFIFO_BYTES_FIELD	4
+
+#define STV090x_Px_F22TX(__x)			(0xf1a9 - (__x - 1) * 0x10)
+#define STV090x_P1_F22TX			STV090x_Px_F22TX(1)
+#define STV090x_P2_F22TX			STV090x_Px_F22TX(2)
+#define STV090x_OFFST_Px_F22_REG_FIELD		0
+#define STV090x_WIDTH_Px_F22_REG_FIELD		8
+
+#define STV090x_Px_F22RX(__x)			(0xf1aa - (__x - 1) * 0x10)
+#define STV090x_P1_F22RX			STV090x_Px_F22RX(1)
+#define STV090x_P2_F22RX			STV090x_Px_F22RX(2)
+#define STV090x_OFFST_Px_F22RX_REG_FIELD	0
+#define STV090x_WIDTH_Px_F22RX_REG_FIELD	8
+
+#define STV090x_Px_ACRPRESC(__x)		(0xf1ac - (__x - 1) * 0x10)
+#define STV090x_P1_ACRPRESC			STV090x_Px_ACRPRESC(1)
+#define STV090x_P2_ACRPRESC			STV090x_Px_ACRPRESC(2)
+#define STV090x_OFFST_Px_ACR_PRESC_FIELD	0
+#define STV090x_WIDTH_Px_ACR_PRESC_FIELD	3
+
+#define STV090x_Px_ACRDIV(__x)			(0xf1ad - (__x - 1) * 0x10)
+#define STV090x_P1_ACRDIV			STV090x_Px_ACRDIV(1)
+#define STV090x_P2_ACRDIV			STV090x_Px_ACRDIV(2)
+#define STV090x_OFFST_Px_ACR_DIV_FIELD		0
+#define STV090x_WIDTH_Px_ACR_DIV_FIELD		8
+
+#define STV090x_Px_IQCONST(__x)			(0xF400 - (__x - 1) * 0x200)
+#define STV090x_P1_IQCONST			STV090x_Px_IQCONST(1)
+#define STV090x_P2_IQCONST			STV090x_Px_IQCONST(2)
+#define STV090x_OFFST_Px_CONSTEL_SELECT_FIELD	5
+#define STV090x_WIDTH_Px_CONSTEL_SELECT_FIELD	2
+
+#define STV090x_Px_NOSCFG(__x)			(0xF401 - (__x - 1) * 0x200)
+#define STV090x_P1_NOSCFG			STV090x_Px_NOSCFG(1)
+#define STV090x_P2_NOSCFG			STV090x_Px_NOSCFG(2)
+#define STV090x_OFFST_Px_NOSPLH_BETA_FIELD	3
+#define STV090x_WIDTH_Px_NOSPLH_BETA_FIELD	2
+#define STV090x_OFFST_Px_NOSDATA_BETA_FIELD	0
+#define STV090x_WIDTH_Px_NOSDATA_BETA_FIELD	3
+
+#define STV090x_Px_ISYMB(__x)			(0xF402 - (__x - 1) * 0x200)
+#define STV090x_P1_ISYMB			STV090x_Px_ISYMB(1)
+#define STV090x_P2_ISYMB			STV090x_Px_ISYMB(2)
+#define STV090x_OFFST_Px_I_SYMBOL_FIELD		0
+#define STV090x_WIDTH_Px_I_SYMBOL_FIELD		8
+
+#define STV090x_Px_QSYMB(__x)			(0xF403 - (__x - 1) * 0x200)
+#define STV090x_P1_QSYMB			STV090x_Px_QSYMB(1)
+#define STV090x_P2_QSYMB			STV090x_Px_QSYMB(2)
+#define STV090x_OFFST_Px_Q_SYMBOL_FIELD		0
+#define STV090x_WIDTH_Px_Q_SYMBOL_FIELD		8
+
+#define STV090x_Px_AGC1CFG(__x)			(0xF404 - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1CFG			STV090x_Px_AGC1CFG(1)
+#define STV090x_P2_AGC1CFG			STV090x_Px_AGC1CFG(2)
+#define STV090x_OFFST_Px_DC_FROZEN_FIELD	7
+#define STV090x_WIDTH_Px_DC_FROZEN_FIELD	1
+#define STV090x_OFFST_Px_DC_CORRECT_FIELD	6
+#define STV090x_WIDTH_Px_DC_CORRECT_FIELD	1
+#define STV090x_OFFST_Px_AMM_FROZEN_FIELD	5
+#define STV090x_WIDTH_Px_AMM_FROZEN_FIELD	1
+#define STV090x_OFFST_Px_AMM_CORRECT_FIELD	4
+#define STV090x_WIDTH_Px_AMM_CORRECT_FIELD	1
+#define STV090x_OFFST_Px_QUAD_FROZEN_FIELD	3
+#define STV090x_WIDTH_Px_QUAD_FROZEN_FIELD	1
+#define STV090x_OFFST_Px_QUAD_CORRECT_FIELD	2
+#define STV090x_WIDTH_Px_QUAD_CORRECT_FIELD	1
+
+#define STV090x_Px_AGC1CN(__x)			(0xF406 - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1CN			STV090x_Px_AGC1CN(1)
+#define STV090x_P2_AGC1CN			STV090x_Px_AGC1CN(2)
+#define STV090x_WIDTH_Px_AGC1_LOCKED_FIELD	7
+#define STV090x_OFFST_Px_AGC1_LOCKED_FIELD	1
+#define STV090x_OFFST_Px_AGC1_MINPOWER_FIELD	4
+#define STV090x_WIDTH_Px_AGC1_MINPOWER_FIELD	1
+#define STV090x_OFFST_Px_AGCOUT_FAST_FIELD	3
+#define STV090x_WIDTH_Px_AGCOUT_FAST_FIELD	1
+#define STV090x_OFFST_Px_AGCIQ_BETA_FIELD	0
+#define STV090x_WIDTH_Px_AGCIQ_BETA_FIELD	3
+
+#define STV090x_Px_AGC1REF(__x)			(0xF407 - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1REF			STV090x_Px_AGC1REF(1)
+#define STV090x_P2_AGC1REF			STV090x_Px_AGC1REF(2)
+#define STV090x_OFFST_Px_AGCIQ_REF_FIELD	0
+#define STV090x_WIDTH_Px_AGCIQ_REF_FIELD	8
+
+#define STV090x_Px_IDCCOMP(__x)			(0xF408 - (__x - 1) * 0x200)
+#define STV090x_P1_IDCCOMP			STV090x_Px_IDCCOMP(1)
+#define STV090x_P2_IDCCOMP			STV090x_Px_IDCCOMP(2)
+#define STV090x_OFFST_Px_IAVERAGE_ADJ_FIELD	0
+#define STV090x_WIDTH_Px_IAVERAGE_ADJ_FIELD	8
+
+#define STV090x_Px_QDCCOMP(__x)			(0xF409 - (__x - 1) * 0x200)
+#define STV090x_P1_QDCCOMP			STV090x_Px_QDCCOMP(1)
+#define STV090x_P2_QDCCOMP			STV090x_Px_QDCCOMP(2)
+#define STV090x_OFFST_Px_QAVERAGE_ADJ_FIELD	0
+#define STV090x_WIDTH_Px_QAVERAGE_ADJ_FIELD	8
+
+#define STV090x_Px_POWERI(__x)			(0xF40A - (__x - 1) * 0x200)
+#define STV090x_P1_POWERI			STV090x_Px_POWERI(1)
+#define STV090x_P2_POWERI			STV090x_Px_POWERI(2)
+#define STV090x_OFFST_Px_POWER_I_FIELD		0
+#define STV090x_WIDTH_Px_POWER_I_FIELD		8
+
+#define STV090x_Px_POWERQ(__x)			(0xF40B - (__x - 1) * 0x200)
+#define STV090x_P1_POWERQ			STV090x_Px_POWERQ(1)
+#define STV090x_P2_POWERQ			STV090x_Px_POWERQ(2)
+#define STV090x_OFFST_Px_POWER_Q_FIELD		0
+#define STV090x_WIDTH_Px_POWER_Q_FIELD		8
+
+#define STV090x_Px_AGC1AMM(__x)			(0xF40C - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1AMM			STV090x_Px_AGC1AMM(1)
+#define STV090x_P2_AGC1AMM			STV090x_Px_AGC1AMM(2)
+#define STV090x_OFFST_Px_AMM_VALUE_FIELD	0
+#define STV090x_WIDTH_Px_AMM_VALUE_FIELD	8
+
+#define STV090x_Px_AGC1QUAD(__x)		(0xF40D - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1QUAD			STV090x_Px_AGC1QUAD(1)
+#define STV090x_P2_AGC1QUAD			STV090x_Px_AGC1QUAD(2)
+#define STV090x_OFFST_Px_QUAD_VALUE_FIELD	0
+#define STV090x_WIDTH_Px_QUAD_VALUE_FIELD	8
+
+#define STV090x_Px_AGCIQINy(__x, __y)		(0xF40F - (__x-1) * 0x200 - __y * 0x1)
+#define STV090x_P1_AGCIQIN0			STV090x_Px_AGCIQINy(1, 0)
+#define STV090x_P1_AGCIQIN1			STV090x_Px_AGCIQINy(1, 1)
+#define STV090x_P2_AGCIQIN0			STV090x_Px_AGCIQINy(2, 0)
+#define STV090x_P2_AGCIQIN1			STV090x_Px_AGCIQINy(2, 1)
+#define STV090x_OFFST_Px_AGCIQ_VALUE_FIELD	0
+#define STV090x_WIDTH_Px_AGCIQ_VALUE_FIELD	8
+
+#define STV090x_Px_DEMOD(__x)			(0xF410 - (__x - 1) * 0x200)
+#define STV090x_P1_DEMOD			STV090x_Px_DEMOD(1)
+#define STV090x_P2_DEMOD			STV090x_Px_DEMOD(2)
+#define STV090x_OFFST_Px_MANUAL_S2ROLLOFF_FIELD	7
+#define STV090x_WIDTH_Px_MANUAL_S2ROLLOFF_FIELD	1
+#define STV090x_OFFST_Px_DEMOD_STOP_FIELD	6
+#define STV090x_WIDTH_Px_DEMOD_STOP_FIELD	1
+#define STV090x_OFFST_Px_SPECINV_CONTROL_FIELD	4
+#define STV090x_WIDTH_Px_SPECINV_CONTROL_FIELD	2
+#define STV090x_OFFST_Px_FORCE_ENASAMP_FIELD	3
+#define STV090x_WIDTH_Px_FORCE_ENASAMP_FIELD	1
+#define STV090x_OFFST_Px_MANUAL_SXROLLOFF_FIELD	2
+#define STV090x_WIDTH_Px_MANUAL_SXROLLOFF_FIELD	1
+#define STV090x_OFFST_Px_ROLLOFF_CONTROL_FIELD	0
+#define STV090x_WIDTH_Px_ROLLOFF_CONTROL_FIELD	2
+
+#define STV090x_Px_DMDMODCOD(__x)		(0xF411 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDMODCOD			STV090x_Px_DMDMODCOD(1)
+#define STV090x_P2_DMDMODCOD			STV090x_Px_DMDMODCOD(2)
+#define STV090x_OFFST_Px_MANUAL_MODCOD_FIELD	7
+#define STV090x_WIDTH_Px_MANUAL_MODCOD_FIELD	1
+#define STV090x_OFFST_Px_DEMOD_MODCOD_FIELD	2
+#define STV090x_WIDTH_Px_DEMOD_MODCOD_FIELD	5
+#define STV090x_OFFST_Px_DEMOD_TYPE_FIELD	0
+#define STV090x_WIDTH_Px_DEMOD_TYPE_FIELD	2
+
+#define STV090x_Px_DSTATUS(__x)			(0xF412 - (__x - 1) * 0x200)
+#define STV090x_P1_DSTATUS			STV090x_Px_DSTATUS(1)
+#define STV090x_P2_DSTATUS			STV090x_Px_DSTATUS(2)
+#define STV090x_OFFST_Px_CAR_LOCK_FIELD		7
+#define STV090x_WIDTH_Px_CAR_LOCK_FIELD		1
+#define STV090x_OFFST_Px_TMGLOCK_QUALITY_FIELD	5
+#define STV090x_WIDTH_Px_TMGLOCK_QUALITY_FIELD	2
+#define STV090x_OFFST_Px_LOCK_DEFINITIF_FIELD	3
+#define STV090x_WIDTH_Px_LOCK_DEFINITIF_FIELD	1
+
+#define STV090x_Px_DSTATUS2(__x)		(0xF413 - (__x - 1) * 0x200)
+#define STV090x_P1_DSTATUS2			STV090x_Px_DSTATUS2(1)
+#define STV090x_P2_DSTATUS2			STV090x_Px_DSTATUS2(2)
+#define STV090x_OFFST_Px_DEMOD_DELOCK_FIELD	7
+#define STV090x_WIDTH_Px_DEMOD_DELOCK_FIELD	1
+#define STV090x_OFFST_Px_AGC1_NOSIGNALACK_FIELD	3
+#define STV090x_WIDTH_Px_AGC1_NOSIGNALACK_FIELD	1
+#define STV090x_OFFST_Px_AGC2_OVERFLOW_FIELD	2
+#define STV090x_WIDTH_Px_AGC2_OVERFLOW_FIELD	1
+#define STV090x_OFFST_Px_CFR_OVERFLOW_FIELD	1
+#define STV090x_WIDTH_Px_CFR_OVERFLOW_FIELD	1
+#define STV090x_OFFST_Px_GAMMA_OVERUNDER_FIELD	0
+#define STV090x_WIDTH_Px_GAMMA_OVERUNDER_FIELD	1
+
+#define STV090x_Px_DMDCFGMD(__x)		(0xF414 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDCFGMD			STV090x_Px_DMDCFGMD(1)
+#define STV090x_P2_DMDCFGMD			STV090x_Px_DMDCFGMD(2)
+#define STV090x_OFFST_Px_DVBS2_ENABLE_FIELD	7
+#define STV090x_WIDTH_Px_DVBS2_ENABLE_FIELD	1
+#define STV090x_OFFST_Px_DVBS1_ENABLE_FIELD	6
+#define STV090x_WIDTH_Px_DVBS1_ENABLE_FIELD	1
+#define STV090x_OFFST_Px_SCAN_ENABLE_FIELD	4
+#define STV090x_WIDTH_Px_SCAN_ENABLE_FIELD	1
+#define STV090x_OFFST_Px_CFR_AUTOSCAN_FIELD	3
+#define STV090x_WIDTH_Px_CFR_AUTOSCAN_FIELD	1
+#define STV090x_OFFST_Px_NOFORCE_RELOCK_FIELD	2
+#define STV090x_WIDTH_Px_NOFORCE_RELOCK_FIELD	1
+#define STV090x_OFFST_Px_TUN_RNG_FIELD		0
+#define STV090x_WIDTH_Px_TUN_RNG_FIELD		2
+
+#define STV090x_Px_DMDCFG2(__x)			(0xF415 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDCFG2			STV090x_Px_DMDCFG2(1)
+#define STV090x_P2_DMDCFG2			STV090x_Px_DMDCFG2(2)
+#define STV090x_OFFST_Px_S1S2_SEQUENTIAL_FIELD	6
+#define STV090x_WIDTH_Px_S1S2_SEQUENTIAL_FIELD	1
+
+#define STV090x_Px_DMDISTATE(__x)		(0xF416 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDISTATE			STV090x_Px_DMDISTATE(1)
+#define STV090x_P2_DMDISTATE			STV090x_Px_DMDISTATE(2)
+#define STV090x_OFFST_Px_I2C_DEMOD_MODE_FIELD	0
+#define STV090x_WIDTH_Px_I2C_DEMOD_MODE_FIELD	5
+
+#define STV090x_Px_DMDTOM(__x)			(0xF417 - (__x - 1) * 0x200) /* check */
+#define STV090x_P1_DMDTOM			STV090x_Px_DMDTOM(1)
+#define STV090x_P2_DMDTOM			STV090x_Px_DMDTOM(2)
+
+#define STV090x_Px_DMDSTATE(__x)		(0xF41B - (__x - 1) * 0x200)
+#define STV090x_P1_DMDSTATE			STV090x_Px_DMDSTATE(1)
+#define STV090x_P2_DMDSTATE			STV090x_Px_DMDSTATE(2)
+#define STV090x_OFFST_Px_HEADER_MODE_FIELD	5
+#define STV090x_WIDTH_Px_HEADER_MODE_FIELD	2
+
+#define STV090x_Px_DMDFLYW(__x)			(0xF41C - (__x - 1) * 0x200)
+#define STV090x_P1_DMDFLYW			STV090x_Px_DMDFLYW(1)
+#define STV090x_P2_DMDFLYW			STV090x_Px_DMDFLYW(2)
+#define STV090x_OFFST_Px_I2C_IRQVAL_FIELD	4
+#define STV090x_WIDTH_Px_I2C_IRQVAL_FIELD	4
+#define STV090x_OFFST_Px_FLYWHEEL_CPT_FIELD	0
+#define STV090x_WIDTH_Px_FLYWHEEL_CPT_FIELD	4
+
+#define STV090x_Px_DSTATUS3(__x)		(0xF41D - (__x - 1) * 0x200)
+#define STV090x_P1_DSTATUS3			STV090x_Px_DSTATUS3(1)
+#define STV090x_P2_DSTATUS3			STV090x_Px_DSTATUS3(2)
+#define STV090x_OFFST_Px_DEMOD_CFGMODE_FIELD	5
+#define STV090x_WIDTH_Px_DEMOD_CFGMODE_FIELD	2
+
+#define STV090x_Px_DMDCFG3(__x)			(0xF41E - (__x - 1) * 0x200)
+#define STV090x_P1_DMDCFG3			STV090x_Px_DMDCFG3(1)
+#define STV090x_P2_DMDCFG3			STV090x_Px_DMDCFG3(2)
+#define STV090x_OFFST_Px_NOSTOP_FIFOFULL_FIELD	3
+#define STV090x_WIDTH_Px_NOSTOP_FIFOFULL_FIELD	1
+
+#define STV090x_Px_DMDCFG4(__x)			(0xf41f - (__x - 1) * 0x200)
+#define STV090x_P1_DMDCFG4			STV090x_Px_DMDCFG4(1)
+#define STV090x_P2_DMDCFG4			STV090x_Px_DMDCFG4(2)
+
+#define STV090x_Px_CORRELMANT(__x)		(0xF420 - (__x - 1) * 0x200)
+#define STV090x_P1_CORRELMANT			STV090x_Px_CORRELMANT(1)
+#define STV090x_P2_CORRELMANT			STV090x_Px_CORRELMANT(2)
+#define STV090x_OFFST_Px_CORREL_MANT_FIELD	0
+#define STV090x_WIDTH_Px_CORREL_MANT_FIELD	8
+
+#define STV090x_Px_CORRELABS(__x)		(0xF421 - (__x - 1) * 0x200)
+#define STV090x_P1_CORRELABS			STV090x_Px_CORRELABS(1)
+#define STV090x_P2_CORRELABS			STV090x_Px_CORRELABS(2)
+#define STV090x_OFFST_Px_CORREL_ABS_FIELD	0
+#define STV090x_WIDTH_Px_CORREL_ABS_FIELD	8
+
+#define STV090x_Px_CORRELEXP(__x)		(0xF422 - (__x - 1) * 0x200)
+#define STV090x_P1_CORRELEXP			STV090x_Px_CORRELEXP(1)
+#define STV090x_P2_CORRELEXP			STV090x_Px_CORRELEXP(2)
+#define STV090x_OFFST_Px_CORREL_ABSEXP_FIELD	4
+#define STV090x_WIDTH_Px_CORREL_ABSEXP_FIELD	4
+#define STV090x_OFFST_Px_CORREL_EXP_FIELD	0
+#define STV090x_WIDTH_Px_CORREL_EXP_FIELD	4
+
+#define STV090x_Px_PLHMODCOD(__x)		(0xF424 - (__x - 1) * 0x200)
+#define STV090x_P1_PLHMODCOD			STV090x_Px_PLHMODCOD(1)
+#define STV090x_P2_PLHMODCOD			STV090x_Px_PLHMODCOD(2)
+#define STV090x_OFFST_Px_SPECINV_DEMOD_FIELD	7
+#define STV090x_WIDTH_Px_SPECINV_DEMOD_FIELD	1
+#define STV090x_OFFST_Px_PLH_MODCOD_FIELD	2
+#define STV090x_WIDTH_Px_PLH_MODCOD_FIELD	5
+#define STV090x_OFFST_Px_PLH_TYPE_FIELD		0
+#define STV090x_WIDTH_Px_PLH_TYPE_FIELD		2
+
+#define STV090x_Px_AGCK32(__x)			(0xf42b - (__x - 1) * 0x200)
+#define STV090x_P1_AGCK32			STV090x_Px_AGCK32(1)
+#define STV090x_P2_AGCK32			STV090x_Px_AGCK32(2)
+
+#define STV090x_Px_AGC2O(__x)			(0xF42C - (__x - 1) * 0x200)
+#define STV090x_P1_AGC2O			STV090x_Px_AGC2O(1)
+#define STV090x_P2_AGC2O			STV090x_Px_AGC2O(2)
+
+#define STV090x_Px_AGC2REF(__x)			(0xF42D - (__x - 1) * 0x200)
+#define STV090x_P1_AGC2REF			STV090x_Px_AGC2REF(1)
+#define STV090x_P2_AGC2REF			STV090x_Px_AGC2REF(2)
+#define STV090x_OFFST_Px_AGC2_REF_FIELD		0
+#define STV090x_WIDTH_Px_AGC2_REF_FIELD		8
+
+#define STV090x_Px_AGC1ADJ(__x)			(0xF42E - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1ADJ			STV090x_Px_AGC1ADJ(1)
+#define STV090x_P2_AGC1ADJ			STV090x_Px_AGC1ADJ(2)
+#define STV090x_OFFST_Px_AGC1_ADJUSTED_FIELD	0
+#define STV090x_WIDTH_Px_AGC1_ADJUSTED_FIELD	7
+
+#define STV090x_Px_AGC2Iy(__x, __y)		(0xF437 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_AGC2I0			STV090x_Px_AGC2Iy(1, 0)
+#define STV090x_P1_AGC2I1			STV090x_Px_AGC2Iy(1, 1)
+#define STV090x_P2_AGC2I0			STV090x_Px_AGC2Iy(2, 0)
+#define STV090x_P2_AGC2I1			STV090x_Px_AGC2Iy(2, 1)
+#define STV090x_OFFST_Px_AGC2_INTEGRATOR_FIELD	0
+#define STV090x_WIDTH_Px_AGC2_INTEGRATOR_FIELD	8
+
+#define STV090x_Px_CARCFG(__x)			(0xF438 - (__x - 1) * 0x200)
+#define STV090x_P1_CARCFG			STV090x_Px_CARCFG(1)
+#define STV090x_P2_CARCFG			STV090x_Px_CARCFG(2)
+#define STV090x_OFFST_Px_EN_CAR2CENTER_FIELD	5
+#define STV090x_WIDTH_Px_EN_CAR2CENTER_FIELD	1
+#define STV090x_OFFST_Px_ROTATON_FIELD		2
+#define STV090x_WIDTH_Px_ROTATON_FIELD		1
+#define STV090x_OFFST_Px_PH_DET_ALGO_FIELD	0
+#define STV090x_WIDTH_Px_PH_DET_ALGO_FIELD	2
+
+#define STV090x_Px_ACLC(__x)			(0xF439 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC				STV090x_Px_ACLC(1)
+#define STV090x_P2_ACLC				STV090x_Px_ACLC(2)
+#define STV090x_OFFST_Px_CAR_ALPHA_MANT_FIELD	4
+#define STV090x_WIDTH_Px_CAR_ALPHA_MANT_FIELD	2
+#define STV090x_OFFST_Px_CAR_ALPHA_EXP_FIELD	0
+#define STV090x_WIDTH_Px_CAR_ALPHA_EXP_FIELD	4
+
+#define STV090x_Px_BCLC(__x)			(0xF43A - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC				STV090x_Px_BCLC(1)
+#define STV090x_P2_BCLC				STV090x_Px_BCLC(2)
+#define STV090x_OFFST_Px_CAR_BETA_MANT_FIELD	4
+#define STV090x_WIDTH_Px_CAR_BETA_MANT_FIELD	2
+#define STV090x_OFFST_Px_CAR_BETA_EXP_FIELD	0
+#define STV090x_WIDTH_Px_CAR_BETA_EXP_FIELD	4
+
+#define STV090x_Px_CARFREQ(__x)			(0xF43D - (__x - 1) * 0x200)
+#define STV090x_P1_CARFREQ			STV090x_Px_CARFREQ(1)
+#define STV090x_P2_CARFREQ			STV090x_Px_CARFREQ(2)
+#define STV090x_OFFST_Px_KC_COARSE_EXP_FIELD	4
+#define STV090x_WIDTH_Px_KC_COARSE_EXP_FIELD	4
+#define STV090x_OFFST_Px_BETA_FREQ_FIELD	0
+#define STV090x_WIDTH_Px_BETA_FREQ_FIELD	4
+
+#define STV090x_Px_CARHDR(__x)			(0xF43E - (__x - 1) * 0x200)
+#define STV090x_P1_CARHDR			STV090x_Px_CARHDR(1)
+#define STV090x_P2_CARHDR			STV090x_Px_CARHDR(2)
+#define STV090x_OFFST_Px_FREQ_HDR_FIELD		0
+#define STV090x_WIDTH_Px_FREQ_HDR_FIELD		8
+
+#define STV090x_Px_LDT(__x)			(0xF43F - (__x - 1) * 0x200)
+#define STV090x_P1_LDT				STV090x_Px_LDT(1)
+#define STV090x_P2_LDT				STV090x_Px_LDT(2)
+#define STV090x_OFFST_Px_CARLOCK_THRES_FIELD	0
+#define STV090x_WIDTH_Px_CARLOCK_THRES_FIELD	8
+
+#define STV090x_Px_LDT2(__x)			(0xF440 - (__x - 1) * 0x200)
+#define STV090x_P1_LDT2				STV090x_Px_LDT2(1)
+#define STV090x_P2_LDT2				STV090x_Px_LDT2(2)
+#define STV090x_OFFST_Px_CARLOCK_THRES2_FIELD	0
+#define STV090x_WIDTH_Px_CARLOCK_THRES2_FIELD	8
+
+#define STV090x_Px_CFRICFG(__x)			(0xF441 - (__x - 1) * 0x200)
+#define STV090x_P1_CFRICFG			STV090x_Px_CFRICFG(1)
+#define STV090x_P2_CFRICFG			STV090x_Px_CFRICFG(2)
+#define STV090x_OFFST_Px_NEG_CFRSTEP_FIELD	0
+#define STV090x_WIDTH_Px_NEG_CFRSTEP_FIELD	1
+
+#define STV090x_Pn_CFRUPy(__x, __y)		(0xF443 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_CFRUP0			STV090x_Pn_CFRUPy(1, 0)
+#define STV090x_P1_CFRUP1			STV090x_Pn_CFRUPy(1, 1)
+#define STV090x_P2_CFRUP0			STV090x_Pn_CFRUPy(2, 0)
+#define STV090x_P2_CFRUP1			STV090x_Pn_CFRUPy(2, 1)
+#define STV090x_OFFST_Px_CFR_UP_FIELD		0
+#define STV090x_WIDTH_Px_CFR_UP_FIELD		8
+
+#define STV090x_Pn_CFRLOWy(__x, __y)		(0xF447 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_CFRLOW0			STV090x_Pn_CFRLOWy(1, 0)
+#define STV090x_P1_CFRLOW1			STV090x_Pn_CFRLOWy(1, 1)
+#define STV090x_P2_CFRLOW0			STV090x_Pn_CFRLOWy(2, 0)
+#define STV090x_P2_CFRLOW1			STV090x_Pn_CFRLOWy(2, 1)
+#define STV090x_OFFST_Px_CFR_LOW_FIELD		0
+#define STV090x_WIDTH_Px_CFR_LOW_FIELD		8
+
+#define STV090x_Pn_CFRINITy(__x, __y)		(0xF449 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_CFRINIT0			STV090x_Pn_CFRINITy(1, 0)
+#define STV090x_P1_CFRINIT1			STV090x_Pn_CFRINITy(1, 1)
+#define STV090x_P2_CFRINIT0			STV090x_Pn_CFRINITy(2, 0)
+#define STV090x_P2_CFRINIT1			STV090x_Pn_CFRINITy(2, 1)
+#define STV090x_OFFST_Px_CFR_INIT_FIELD		0
+#define STV090x_WIDTH_Px_CFR_INIT_FIELD		8
+
+#define STV090x_Px_CFRINC1(__x)			(0xF44A - (__x - 1) * 0x200)
+#define STV090x_P1_CFRINC1			STV090x_Px_CFRINC1(1)
+#define STV090x_P2_CFRINC1			STV090x_Px_CFRINC1(2)
+#define STV090x_OFFST_Px_CFR_INC1_FIELD		0
+#define STV090x_WIDTH_Px_CFR_INC1_FIELD		7 /* check */
+
+#define STV090x_Px_CFRINC0(__x)			(0xF44B - (__x - 1) * 0x200)
+#define STV090x_P1_CFRINC0			STV090x_Px_CFRINC0(1)
+#define STV090x_P2_CFRINC0			STV090x_Px_CFRINC0(2)
+#define STV090x_OFFST_Px_CFR_INC0_FIELD		4 /* check */
+#define STV090x_WIDTH_Px_CFR_INC0_FIELD		4
+
+#define STV090x_Pn_CFRy(__x, __y)		(0xF44E - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_CFR0				STV090x_Pn_CFRy(1, 0)
+#define STV090x_P1_CFR1				STV090x_Pn_CFRy(1, 1)
+#define STV090x_P1_CFR2				STV090x_Pn_CFRy(1, 2)
+#define STV090x_P2_CFR0				STV090x_Pn_CFRy(2, 0)
+#define STV090x_P2_CFR1				STV090x_Pn_CFRy(2, 1)
+#define STV090x_P2_CFR2				STV090x_Pn_CFRy(2, 2)
+#define STV090x_OFFST_Px_CAR_FREQ_FIELD		0
+#define STV090x_WIDTH_Px_CAR_FREQ_FIELD		8
+
+#define STV090x_Px_LDI(__x)			(0xF44F - (__x - 1) * 0x200)
+#define STV090x_P1_LDI				STV090x_Px_LDI(1)
+#define STV090x_P2_LDI				STV090x_Px_LDI(2)
+#define STV090x_OFFST_Px_LOCK_DET_INTEGR_FIELD	0
+#define STV090x_WIDTH_Px_LOCK_DET_INTEGR_FIELD	8
+
+#define STV090x_Px_TMGCFG(__x)			(0xF450 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGCFG			STV090x_Px_TMGCFG(1)
+#define STV090x_P2_TMGCFG			STV090x_Px_TMGCFG(2)
+#define STV090x_OFFST_Px_TMGLOCK_BETA_FIELD	6
+#define STV090x_WIDTH_Px_TMGLOCK_BETA_FIELD	2
+#define STV090x_OFFST_Px_DO_TIMING_FIELD	4
+#define STV090x_WIDTH_Px_DO_TIMING_FIELD	1
+#define STV090x_OFFST_Px_TMG_MINFREQ_FIELD	0
+#define STV090x_WIDTH_Px_TMG_MINFREQ_FIELD	2
+
+#define STV090x_Px_RTC(__x)			(0xF451 - (__x - 1) * 0x200)
+#define STV090x_P1_RTC				STV090x_Px_RTC(1)
+#define STV090x_P2_RTC				STV090x_Px_RTC(2)
+#define STV090x_OFFST_Px_TMGALPHA_EXP_FIELD	4
+#define STV090x_WIDTH_Px_TMGALPHA_EXP_FIELD	4
+#define STV090x_OFFST_Px_TMGBETA_EXP_FIELD	0
+#define STV090x_WIDTH_Px_TMGBETA_EXP_FIELD	4
+
+#define STV090x_Px_RTCS2(__x)			(0xF452 - (__x - 1) * 0x200)
+#define STV090x_P1_RTCS2			STV090x_Px_RTCS2(1)
+#define STV090x_P2_RTCS2			STV090x_Px_RTCS2(2)
+#define STV090x_OFFST_Px_TMGALPHAS2_EXP_FIELD	4
+#define STV090x_WIDTH_Px_TMGALPHAS2_EXP_FIELD	4
+#define STV090x_OFFST_Px_TMGBETAS2_EXP_FIELD	0
+#define STV090x_WIDTH_Px_TMGBETAS2_EXP_FIELD	4
+
+#define STV090x_Px_TMGTHRISE(__x)		(0xF453 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGTHRISE			STV090x_Px_TMGTHRISE(1)
+#define STV090x_P2_TMGTHRISE			STV090x_Px_TMGTHRISE(2)
+#define STV090x_OFFST_Px_TMGLOCK_THRISE_FIELD	0
+#define STV090x_WIDTH_Px_TMGLOCK_THRISE_FIELD	8
+
+#define STV090x_Px_TMGTHFALL(__x)		(0xF454 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGTHFALL			STV090x_Px_TMGTHFALL(1)
+#define STV090x_P2_TMGTHFALL			STV090x_Px_TMGTHFALL(2)
+#define STV090x_OFFST_Px_TMGLOCK_THFALL_FIELD	0
+#define STV090x_WIDTH_Px_TMGLOCK_THFALL_FIELD	8
+
+#define STV090x_Px_SFRUPRATIO(__x)		(0xF455 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRUPRATIO			STV090x_Px_SFRUPRATIO(1)
+#define STV090x_P2_SFRUPRATIO			STV090x_Px_SFRUPRATIO(2)
+#define STV090x_OFFST_Px_SFR_UPRATIO_FIELD	0
+#define STV090x_WIDTH_Px_SFR_UPRATIO_FIELD	8
+
+#define STV090x_Px_SFRLOWRATIO(__x)		(0xF456 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRLOWRATIO			STV090x_Px_SFRLOWRATIO(1)
+#define STV090x_P2_SFRLOWRATIO			STV090x_Px_SFRLOWRATIO(2)
+#define STV090x_OFFST_Px_SFR_LOWRATIO_FIELD	0
+#define STV090x_WIDTH_Px_SFR_LOWRATIO_FIELD	8
+
+#define STV090x_Px_KREFTMG(__x)			(0xF458 - (__x - 1) * 0x200)
+#define STV090x_P1_KREFTMG			STV090x_Px_KREFTMG(1)
+#define STV090x_P2_KREFTMG			STV090x_Px_KREFTMG(2)
+#define STV090x_OFFST_Px_KREF_TMG_FIELD		0
+#define STV090x_WIDTH_Px_KREF_TMG_FIELD		8
+
+#define STV090x_Px_SFRSTEP(__x)			(0xF459 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRSTEP			STV090x_Px_SFRSTEP(1)
+#define STV090x_P2_SFRSTEP			STV090x_Px_SFRSTEP(2)
+#define STV090x_OFFST_Px_SFR_SCANSTEP_FIELD	4
+#define STV090x_WIDTH_Px_SFR_SCANSTEP_FIELD	4
+#define STV090x_OFFST_Px_SFR_CENTERSTEP_FIELD	0
+#define STV090x_WIDTH_Px_SFR_CENTERSTEP_FIELD	4
+
+#define STV090x_Px_TMGCFG2(__x)			(0xF45A - (__x - 1) * 0x200)
+#define STV090x_P1_TMGCFG2			STV090x_Px_TMGCFG2(1)
+#define STV090x_P2_TMGCFG2			STV090x_Px_TMGCFG2(2)
+#define STV090x_OFFST_Px_SFRRATIO_FINE_FIELD	0
+#define STV090x_WIDTH_Px_SFRRATIO_FINE_FIELD	1
+
+#define STV090x_Px_SFRINIT1(__x)		(0xF45E - (__x - 1) * 0x200)
+#define STV090x_P1_SFRINIT1			STV090x_Px_SFRINIT1(1)
+#define STV090x_P2_SFRINIT1			STV090x_Px_SFRINIT1(2)
+#define STV090x_OFFST_Px_SFR_INIT1_FIELD	0
+#define STV090x_WIDTH_Px_SFR_INIT1_FIELD	7
+
+#define STV090x_Px_SFRINIT0(__x)		(0xF45F - (__x - 1) * 0x200)
+#define STV090x_P1_SFRINIT0			STV090x_Px_SFRINIT0(1)
+#define STV090x_P2_SFRINIT0			STV090x_Px_SFRINIT0(2)
+#define STV090x_OFFST_Px_SFR_INIT0_FIELD	0
+#define STV090x_WIDTH_Px_SFR_INIT0_FIELD	8
+
+#define STV090x_Px_SFRUP1(__x)			(0xF460 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRUP1			STV090x_Px_SFRUP1(1)
+#define STV090x_P2_SFRUP1			STV090x_Px_SFRUP1(2)
+#define STV090x_OFFST_Px_SYMB_FREQ_UP1_FIELD	0
+#define STV090x_WIDTH_Px_SYMB_FREQ_UP1_FIELD	7
+
+#define STV090x_Px_SFRUP0(__x)			(0xF461 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRUP0			STV090x_Px_SFRUP0(1)
+#define STV090x_P2_SFRUP0			STV090x_Px_SFRUP0(2)
+#define STV090x_OFFST_Px_SYMB_FREQ_UP0_FIELD	0
+#define STV090x_WIDTH_Px_SYMB_FREQ_UP0_FIELD	8
+
+#define STV090x_Px_SFRLOW1(__x)			(0xF462 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRLOW1			STV090x_Px_SFRLOW1(1)
+#define STV090x_P2_SFRLOW1			STV090x_Px_SFRLOW1(2)
+#define STV090x_OFFST_Px_SYMB_FREQ_LOW1_FIELD	0
+#define STV090x_WIDTH_Px_SYMB_FREQ_LOW1_FIELD	7
+
+#define STV090x_Px_SFRLOW0(__x)			(0xF463 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRLOW0			STV090x_Px_SFRLOW0(1)
+#define STV090x_P2_SFRLOW0			STV090x_Px_SFRLOW0(2)
+#define STV090x_OFFST_Px_SYMB_FREQ_LOW0_FIELD	0
+#define STV090x_WIDTH_Px_SYMB_FREQ_LOW0_FIELD	8
+
+#define STV090x_Px_SFRy(__x, __y)		(0xF467 - (__x-1) * 0x200 - __y)
+#define STV090x_P1_SFR0				STV090x_Px_SFRy(1, 0)
+#define STV090x_P1_SFR1				STV090x_Px_SFRy(1, 1)
+#define STV090x_P1_SFR2				STV090x_Px_SFRy(1, 2)
+#define STV090x_P1_SFR3				STV090x_Px_SFRy(1, 3)
+#define STV090x_P2_SFR0				STV090x_Px_SFRy(2, 0)
+#define STV090x_P2_SFR1				STV090x_Px_SFRy(2, 1)
+#define STV090x_P2_SFR2				STV090x_Px_SFRy(2, 2)
+#define STV090x_P2_SFR3				STV090x_Px_SFRy(2, 3)
+#define STV090x_OFFST_Px_SYMB_FREQ_FIELD	0
+#define STV090x_WIDTH_Px_SYMB_FREQ_FIELD	8
+
+#define STV090x_Px_TMGREG2(__x)			(0xF468 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGREG2			STV090x_Px_TMGREG2(1)
+#define STV090x_P2_TMGREG2			STV090x_Px_TMGREG2(2)
+#define STV090x_OFFST_Px_TMGREG_FIELD		0
+#define STV090x_WIDTH_Px_TMGREG_FIELD		8
+
+#define STV090x_Px_TMGREG1(__x)			(0xF469 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGREG1			STV090x_Px_TMGREG1(1)
+#define STV090x_P2_TMGREG1			STV090x_Px_TMGREG1(2)
+#define STV090x_OFFST_Px_TMGREG_FIELD		0
+#define STV090x_WIDTH_Px_TMGREG_FIELD		8
+
+#define STV090x_Px_TMGREG0(__x)			(0xF46A - (__x - 1) * 0x200)
+#define STV090x_P1_TMGREG0			STV090x_Px_TMGREG0(1)
+#define STV090x_P2_TMGREG0			STV090x_Px_TMGREG0(2)
+#define STV090x_OFFST_Px_TMGREG_FIELD		0
+#define STV090x_WIDTH_Px_TMGREG_FIELD		8
+
+#define STV090x_Px_TMGLOCKy(__x, __y)		(0xF46C - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_TMGLOCK0			STV090x_Px_TMGLOCKy(1, 0)
+#define STV090x_P1_TMGLOCK1			STV090x_Px_TMGLOCKy(1, 1)
+#define STV090x_P2_TMGLOCK0			STV090x_Px_TMGLOCKy(2, 0)
+#define STV090x_P2_TMGLOCK1			STV090x_Px_TMGLOCKy(2, 1)
+#define STV090x_OFFST_Px_TMGLOCK_LEVEL_FIELD	0
+#define STV090x_WIDTH_Px_TMGLOCK_LEVEL_FIELD	8
+
+#define STV090x_Px_TMGOBS(__x)			(0xF46D - (__x - 1) * 0x200)
+#define STV090x_P1_TMGOBS			STV090x_Px_TMGOBS(1)
+#define STV090x_P2_TMGOBS			STV090x_Px_TMGOBS(2)
+#define STV090x_OFFST_Px_ROLLOFF_STATUS_FIELD	6
+#define STV090x_WIDTH_Px_ROLLOFF_STATUS_FIELD	2
+
+#define STV090x_Px_EQUALCFG(__x)		(0xF46F - (__x - 1) * 0x200)
+#define STV090x_P1_EQUALCFG			STV090x_Px_EQUALCFG(1)
+#define STV090x_P2_EQUALCFG			STV090x_Px_EQUALCFG(2)
+#define STV090x_OFFST_Px_EQUAL_ON_FIELD		6
+#define STV090x_WIDTH_Px_EQUAL_ON_FIELD		1
+#define STV090x_OFFST_Px_MU_EQUALDFE_FIELD	0
+#define STV090x_WIDTH_Px_MU_EQUALDFE_FIELD	3
+
+#define STV090x_Px_EQUAIy(__x, __y)	(0xf470 - (__x-1) * 0x200 + 2 * (__y-1))
+#define STV090x_P1_EQUAI1			STV090x_Px_EQUAIy(1, 1)
+#define STV090x_P1_EQUAI2			STV090x_Px_EQUAIy(1, 2)
+#define STV090x_P1_EQUAI3			STV090x_Px_EQUAIy(1, 3)
+#define STV090x_P1_EQUAI4			STV090x_Px_EQUAIy(1, 4)
+#define STV090x_P1_EQUAI5			STV090x_Px_EQUAIy(1, 5)
+#define STV090x_P1_EQUAI6			STV090x_Px_EQUAIy(1, 6)
+#define STV090x_P1_EQUAI7			STV090x_Px_EQUAIy(1, 7)
+#define STV090x_P1_EQUAI8			STV090x_Px_EQUAIy(1, 8)
+
+#define STV090x_P2_EQUAI1			STV090x_Px_EQUAIy(2, 1)
+#define STV090x_P2_EQUAI2			STV090x_Px_EQUAIy(2, 2)
+#define STV090x_P2_EQUAI3			STV090x_Px_EQUAIy(2, 3)
+#define STV090x_P2_EQUAI4			STV090x_Px_EQUAIy(2, 4)
+#define STV090x_P2_EQUAI5			STV090x_Px_EQUAIy(2, 5)
+#define STV090x_P2_EQUAI6			STV090x_Px_EQUAIy(2, 6)
+#define STV090x_P2_EQUAI7			STV090x_Px_EQUAIy(2, 7)
+#define STV090x_P2_EQUAI8			STV090x_Px_EQUAIy(2, 8)
+#define STV090x_OFFST_Px_EQUA_ACCIy_FIELD	0
+#define STV090x_WIDTH_Px_EQUA_ACCIy_FIELD	8
+
+#define STV090x_Px_EQUAQy(__x, __y)	(0xf471 - (__x-1) * 0x200 + 2 * (__y-1))
+#define STV090x_P1_EQUAQ1			STV090x_Px_EQUAQy(1, 1)
+#define STV090x_P1_EQUAQ2			STV090x_Px_EQUAQy(1, 2)
+#define STV090x_P1_EQUAQ3			STV090x_Px_EQUAQy(1, 3)
+#define STV090x_P1_EQUAQ4			STV090x_Px_EQUAQy(1, 4)
+#define STV090x_P1_EQUAQ5			STV090x_Px_EQUAQy(1, 5)
+#define STV090x_P1_EQUAQ6			STV090x_Px_EQUAQy(1, 6)
+#define STV090x_P1_EQUAQ7			STV090x_Px_EQUAQy(1, 7)
+#define STV090x_P1_EQUAQ8			STV090x_Px_EQUAQy(1, 8)
+
+#define STV090x_P2_EQUAQ1			STV090x_Px_EQUAQy(2, 1)
+#define STV090x_P2_EQUAQ2			STV090x_Px_EQUAQy(2, 2)
+#define STV090x_P2_EQUAQ3			STV090x_Px_EQUAQy(2, 3)
+#define STV090x_P2_EQUAQ4			STV090x_Px_EQUAQy(2, 4)
+#define STV090x_P2_EQUAQ5			STV090x_Px_EQUAQy(2, 5)
+#define STV090x_P2_EQUAQ6			STV090x_Px_EQUAQy(2, 6)
+#define STV090x_P2_EQUAQ7			STV090x_Px_EQUAQy(2, 7)
+#define STV090x_P2_EQUAQ8			STV090x_Px_EQUAQy(2, 8)
+#define STV090x_OFFST_Px_EQUA_ACCQy_FIELD	0
+#define STV090x_WIDTH_Px_EQUA_ACCQy_FIELD	8
+
+#define STV090x_Px_NNOSDATATy(__x, __y)		(0xf481 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NNOSDATAT0			STV090x_Px_NNOSDATATy(1, 0)
+#define STV090x_P1_NNOSDATAT1			STV090x_Px_NNOSDATATy(1, 1)
+#define STV090x_P2_NNOSDATAT0			STV090x_Px_NNOSDATATy(2, 0)
+#define STV090x_P2_NNOSDATAT1			STV090x_Px_NNOSDATATy(2, 1)
+#define STV090x_OFFST_Px_NOSDATAT_NORMED_FIELD	0
+#define STV090x_WIDTH_Px_NOSDATAT_NORMED_FIELD	8
+
+#define STV090x_Px_NNOSDATAy(__x, __y)		(0xf483 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NNOSDATA0			STV090x_Px_NNOSDATAy(1, 0)
+#define STV090x_P1_NNOSDATA1			STV090x_Px_NNOSDATAy(1, 1)
+#define STV090x_P2_NNOSDATA0			STV090x_Px_NNOSDATAy(2, 0)
+#define STV090x_P2_NNOSDATA1			STV090x_Px_NNOSDATAy(2, 1)
+#define STV090x_OFFST_Px_NOSDATA_NORMED_FIELD	0
+#define STV090x_WIDTH_Px_NOSDATA_NORMED_FIELD	8
+
+#define STV090x_Px_NNOSPLHTy(__x, __y)		(0xf485 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NNOSPLHT0			STV090x_Px_NNOSPLHTy(1, 0)
+#define STV090x_P1_NNOSPLHT1			STV090x_Px_NNOSPLHTy(1, 1)
+#define STV090x_P2_NNOSPLHT0			STV090x_Px_NNOSPLHTy(2, 0)
+#define STV090x_P2_NNOSPLHT1			STV090x_Px_NNOSPLHTy(2, 1)
+#define STV090x_OFFST_Px_NOSPLHT_NORMED_FIELD	0
+#define STV090x_WIDTH_Px_NOSPLHT_NORMED_FIELD	8
+
+#define STV090x_Px_NNOSPLHy(__x, __y)		(0xf487 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NNOSPLH0			STV090x_Px_NNOSPLHy(1, 0)
+#define STV090x_P1_NNOSPLH1			STV090x_Px_NNOSPLHy(1, 1)
+#define STV090x_P2_NNOSPLH0			STV090x_Px_NNOSPLHy(2, 0)
+#define STV090x_P2_NNOSPLH1			STV090x_Px_NNOSPLHy(2, 1)
+#define STV090x_OFFST_Px_NOSPLH_NORMED_FIELD	0
+#define STV090x_WIDTH_Px_NOSPLH_NORMED_FIELD	8
+
+#define STV090x_Px_NOSDATATy(__x, __y)			(0xf489 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NOSDATAT0				STV090x_Px_NOSDATATy(1, 0)
+#define STV090x_P1_NOSDATAT1				STV090x_Px_NOSDATATy(1, 1)
+#define STV090x_P2_NOSDATAT0				STV090x_Px_NOSDATATy(2, 0)
+#define STV090x_P2_NOSDATAT1				STV090x_Px_NOSDATATy(2, 1)
+#define STV090x_OFFST_Px_NOSDATAT_UNNORMED_FIELD	0
+#define STV090x_WIDTH_Px_NOSDATAT_UNNORMED_FIELD	8
+
+#define STV090x_Px_NOSDATAy(__x, __y)		(0xf48b - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NOSDATA0			STV090x_Px_NOSDATAy(1, 0)
+#define STV090x_P1_NOSDATA1			STV090x_Px_NOSDATAy(1, 1)
+#define STV090x_P2_NOSDATA0			STV090x_Px_NOSDATAy(2, 0)
+#define STV090x_P2_NOSDATA1			STV090x_Px_NOSDATAy(2, 1)
+#define STV090x_OFFST_Px_NOSDATA_UNNORMED_FIELD	0
+#define STV090x_WIDTH_Px_NOSDATA_UNNORMED_FIELD	8
+
+#define STV090x_Px_NOSPLHTy(__x, __y)		(0xf48d - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NOSPLHT0			STV090x_Px_NOSPLHTy(1, 0)
+#define STV090x_P1_NOSPLHT1			STV090x_Px_NOSPLHTy(1, 1)
+#define STV090x_P2_NOSPLHT0			STV090x_Px_NOSPLHTy(2, 0)
+#define STV090x_P2_NOSPLHT1			STV090x_Px_NOSPLHTy(2, 1)
+#define STV090x_OFFST_Px_NOSPLHT_UNNORMED_FIELD	0
+#define STV090x_WIDTH_Px_NOSPLHT_UNNORMED_FIELD	8
+
+#define STV090x_Px_NOSPLHy(__x, __y)		(0xf48f - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NOSPLH0			STV090x_Px_NOSPLHy(1, 0)
+#define STV090x_P1_NOSPLH1			STV090x_Px_NOSPLHy(1, 1)
+#define STV090x_P2_NOSPLH0			STV090x_Px_NOSPLHy(2, 0)
+#define STV090x_P2_NOSPLH1			STV090x_Px_NOSPLHy(2, 1)
+#define STV090x_OFFST_Px_NOSPLH_UNNORMED_FIELD	0
+#define STV090x_WIDTH_Px_NOSPLH_UNNORMED_FIELD	8
+
+#define STV090x_Px_CAR2CFG(__x)			(0xf490 - (__x - 1) * 0x200)
+#define STV090x_P1_CAR2CFG			STV090x_Px_CAR2CFG(1)
+#define STV090x_P2_CAR2CFG			STV090x_Px_CAR2CFG(2)
+#define STV090x_OFFST_Px_PN4_SELECT_FIELD	6
+#define STV090x_WIDTH_Px_PN4_SELECT_FIELD	1
+#define STV090x_OFFST_Px_CFR2_STOPDVBS1_FIELD	5
+#define STV090x_WIDTH_Px_CFR2_STOPDVBS1_FIELD	1
+#define STV090x_OFFST_Px_ROTA2ON_FIELD		2
+#define STV090x_WIDTH_Px_ROTA2ON_FIELD		1
+#define STV090x_OFFST_Px_PH_DET_ALGO2_FIELD	0
+#define STV090x_WIDTH_Px_PH_DET_ALGO2_FIELD	2
+
+#define STV090x_Px_ACLC2(__x)			(0xf491 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2			STV090x_Px_ACLC2(1)
+#define STV090x_P2_ACLC2			STV090x_Px_ACLC2(2)
+#define STV090x_OFFST_Px_CAR2_ALPHA_MANT_FIELD	4
+#define STV090x_WIDTH_Px_CAR2_ALPHA_MANT_FIELD	2
+#define STV090x_OFFST_Px_CAR2_ALPHA_EXP_FIELD	0
+#define STV090x_WIDTH_Px_CAR2_ALPHA_EXP_FIELD	4
+
+#define STV090x_Px_BCLC2(__x)			(0xf492 - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2			STV090x_Px_BCLC2(1)
+#define STV090x_P2_BCLC2			STV090x_Px_BCLC2(2)
+#define STV090x_OFFST_Px_CAR2_BETA_MANT_FIELD	4
+#define STV090x_WIDTH_Px_CAR2_BETA_MANT_FIELD	2
+#define STV090x_OFFST_Px_CAR2_BETA_EXP_FIELD	0
+#define STV090x_WIDTH_Px_CAR2_BETA_EXP_FIELD	4
+
+#define STV090x_Px_ACLC2S2Q(__x)		(0xf497 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2S2Q			STV090x_Px_ACLC2S2Q(1)
+#define STV090x_P2_ACLC2S2Q			STV090x_Px_ACLC2S2Q(2)
+#define STV090x_OFFST_Px_ENAB_SPSKSYMB_FIELD	7
+#define STV090x_WIDTH_Px_ENAB_SPSKSYMB_FIELD	1
+#define STV090x_OFFST_Px_CAR2S2_Q_ALPH_M_FIELD	4
+#define STV090x_WIDTH_Px_CAR2S2_Q_ALPH_M_FIELD	2
+#define STV090x_OFFST_Px_CAR2S2_Q_ALPH_E_FIELD	0
+#define STV090x_WIDTH_Px_CAR2S2_Q_ALPH_E_FIELD	4
+
+#define STV090x_Px_ACLC2S28(__x)		(0xf498 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2S28			STV090x_Px_ACLC2S28(1)
+#define STV090x_P2_ACLC2S28			STV090x_Px_ACLC2S28(2)
+#define STV090x_OFFST_Px_CAR2S2_8_ALPH_M_FIELD	4
+#define STV090x_WIDTH_Px_CAR2S2_8_ALPH_M_FIELD	2
+#define STV090x_OFFST_Px_CAR2S2_8_ALPH_E_FIELD	0
+#define STV090x_WIDTH_Px_CAR2S2_8_ALPH_E_FIELD	4
+
+#define STV090x_Px_ACLC2S216A(__x)		(0xf499 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2S216A			STV090x_Px_ACLC2S216A(1)
+#define STV090x_P2_ACLC2S216A			STV090x_Px_ACLC2S216A(2)
+#define STV090x_OFFST_Px_CAR2S2_16A_ALPH_M_FIELD	4
+#define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_M_FIELD	2
+#define STV090x_OFFST_Px_CAR2S2_16A_ALPH_E_FIELD	0
+#define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_E_FIELD	4
+
+#define STV090x_Px_ACLC2S232A(__x)		(0xf49A - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2S232A			STV090x_Px_ACLC2S232A(1)
+#define STV090x_P2_ACLC2S232A			STV090x_Px_ACLC2S232A(2)
+#define STV090x_OFFST_Px_CAR2S2_32A_ALPH_M_FIELD	4
+#define STV090x_WIDTH_Px_CAR2S2_32A_ALPH_M_FIELD	2
+#define STV090x_OFFST_Px_CAR2S2_32A_ALPH_E_FIELD	0
+#define STV090x_WIDTH_Px_CAR2S2_32A_ALPH_E_FIELD	4
+
+#define STV090x_Px_BCLC2S2Q(__x)		(0xf49c - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2S2Q			STV090x_Px_BCLC2S2Q(1)
+#define STV090x_P2_BCLC2S2Q			STV090x_Px_BCLC2S2Q(2)
+#define STV090x_OFFST_Px_CAR2S2_Q_BETA_M_FIELD	4
+#define STV090x_WIDTH_Px_CAR2S2_Q_BETA_M_FIELD	2
+#define STV090x_OFFST_Px_CAR2S2_Q_BETA_E_FIELD	0
+#define STV090x_WIDTH_Px_CAR2S2_Q_BETA_E_FIELD	4
+
+#define STV090x_Px_BCLC2S28(__x)		(0xf49d - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2S28			STV090x_Px_BCLC2S28(1)
+#define STV090x_P2_BCLC2S28			STV090x_Px_BCLC2S28(2)
+#define STV090x_OFFST_Px_CAR2S2_8_BETA_M_FIELD	4
+#define STV090x_WIDTH_Px_CAR2S2_8_BETA_M_FIELD	2
+#define STV090x_OFFST_Px_CAR2S2_8_BETA_E_FIELD	0
+#define STV090x_WIDTH_Px_CAR2S2_8_BETA_E_FIELD	4
+
+#define STV090x_Px_BCLC2S216A(__x)		(0xf49e - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2S216A			STV090x_Px_BCLC2S216A(1)
+#define STV090x_P2_BCLC2S216A			STV090x_Px_BCLC2S216A(2)
+#define STV090x_OFFST_Px_CAR2S2_16A_BETA_M_FIELD	4
+#define STV090x_WIDTH_Px_CAR2S2_16A_BETA_M_FIELD	2
+#define STV090x_OFFST_Px_CAR2S2_16A_BETA_E_FIELD	0
+#define STV090x_WIDTH_Px_CAR2S2_16A_BETA_E_FIELD	4
+
+#define STV090x_Px_BCLC2S232A(__x)		(0xf49f - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2S232A			STV090x_Px_BCLC2S232A(1)
+#define STV090x_P2_BCLC2S232A			STV090x_Px_BCLC2S232A(2)
+#define STV090x_OFFST_Px_CAR2S2_32A_BETA_M_FIELD	4
+#define STV090x_WIDTH_Px_CAR2S2_32A_BETA_M_FIELD	2
+#define STV090x_OFFST_Px_CAR2S2_32A_BETA_E_FIELD	0
+#define STV090x_WIDTH_Px_CAR2S2_32A_BETA_E_FIELD	4
+
+#define STV090x_Px_PLROOT2(__x)			(0xf4ac - (__x - 1) * 0x200)
+#define STV090x_P1_PLROOT2			STV090x_Px_PLROOT2(1)
+#define STV090x_P2_PLROOT2			STV090x_Px_PLROOT2(2)
+#define STV090x_OFFST_Px_PLSCRAMB_MODE_FIELD	2
+#define STV090x_WIDTH_Px_PLSCRAMB_MODE_FIELD	2
+#define STV090x_OFFST_Px_PLSCRAMB_ROOT_FIELD	0
+#define STV090x_WIDTH_Px_PLSCRAMB_ROOT_FIELD	2
+
+#define STV090x_Px_PLROOT1(__x)			(0xf4ad - (__x - 1) * 0x200)
+#define STV090x_P1_PLROOT1			STV090x_Px_PLROOT1(1)
+#define STV090x_P2_PLROOT1			STV090x_Px_PLROOT1(2)
+#define STV090x_OFFST_Px_PLSCRAMB_ROOT1_FIELD	0
+#define STV090x_WIDTH_Px_PLSCRAMB_ROOT1_FIELD	8
+
+#define STV090x_Px_PLROOT0(__x)			(0xf4ae - (__x - 1) * 0x200)
+#define STV090x_P1_PLROOT0			STV090x_Px_PLROOT0(1)
+#define STV090x_P2_PLROOT0			STV090x_Px_PLROOT0(2)
+#define STV090x_OFFST_Px_PLSCRAMB_ROOT0_FIELD	0
+#define STV090x_WIDTH_Px_PLSCRAMB_ROOT0_FIELD	8
+
+#define STV090x_Px_MODCODLST0(__x)		(0xf4b0 - (__x - 1) * 0x200) /* check */
+#define STV090x_P1_MODCODLST0			STV090x_Px_MODCODLST0(1)
+#define STV090x_P2_MODCODLST0			STV090x_Px_MODCODLST0(2)
+
+#define STV090x_Px_MODCODLST1(__x)		(0xf4b1 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST1			STV090x_Px_MODCODLST1(1)
+#define STV090x_P2_MODCODLST1			STV090x_Px_MODCODLST1(2)
+#define STV090x_OFFST_Px_DIS_MODCOD29_FIELD	4
+#define STV090x_WIDTH_Px_DIS_MODCOD29_FIELD	4
+#define STV090x_OFFST_Px_DIS_32PSK_9_10_FIELD	0
+#define STV090x_WIDTH_Px_DIS_32PSK_9_10_FIELD	4
+
+#define STV090x_Px_MODCODLST2(__x)		(0xf4b2 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST2			STV090x_Px_MODCODLST2(1)
+#define STV090x_P2_MODCODLST2			STV090x_Px_MODCODLST2(2)
+#define STV090x_OFFST_Px_DIS_32PSK_8_9_FIELD	4
+#define STV090x_WIDTH_Px_DIS_32PSK_8_9_FIELD	4
+#define STV090x_OFFST_Px_DIS_32PSK_5_6_FIELD	0
+#define STV090x_WIDTH_Px_DIS_32PSK_5_6_FIELD	4
+
+#define STV090x_Px_MODCODLST3(__x)		(0xf4b3 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST3			STV090x_Px_MODCODLST3(1)
+#define STV090x_P2_MODCODLST3			STV090x_Px_MODCODLST3(2)
+#define STV090x_OFFST_Px_DIS_32PSK_4_5_FIELD	4
+#define STV090x_WIDTH_Px_DIS_32PSK_4_5_FIELD	4
+#define STV090x_OFFST_Px_DIS_32PSK_3_4_FIELD	0
+#define STV090x_WIDTH_Px_DIS_32PSK_3_4_FIELD	4
+
+#define STV090x_Px_MODCODLST4(__x)		(0xf4b4 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST4			STV090x_Px_MODCODLST4(1)
+#define STV090x_P2_MODCODLST4			STV090x_Px_MODCODLST4(2)
+#define STV090x_OFFST_Px_DIS_16PSK_9_10_FIELD	4
+#define STV090x_WIDTH_Px_DIS_16PSK_9_10_FIELD	4
+#define STV090x_OFFST_Px_DIS_16PSK_8_9_FIELD	0
+#define STV090x_WIDTH_Px_DIS_16PSK_8_9_FIELD	4
+
+#define STV090x_Px_MODCODLST5(__x)		(0xf4b5 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST5			STV090x_Px_MODCODLST5(1)
+#define STV090x_P2_MODCODLST5			STV090x_Px_MODCODLST5(2)
+#define STV090x_OFFST_Px_DIS_16PSK_5_6_FIELD	4
+#define STV090x_WIDTH_Px_DIS_16PSK_5_6_FIELD	4
+#define STV090x_OFFST_Px_DIS_16PSK_4_5_FIELD	0
+#define STV090x_WIDTH_Px_DIS_16PSK_4_5_FIELD	4
+
+#define STV090x_Px_MODCODLST6(__x)		(0xf4b6 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST6			STV090x_Px_MODCODLST6(1)
+#define STV090x_P2_MODCODLST6			STV090x_Px_MODCODLST6(2)
+#define STV090x_OFFST_Px_DIS_16PSK_3_4_FIELD	4
+#define STV090x_WIDTH_Px_DIS_16PSK_3_4_FIELD	4
+#define STV090x_OFFST_Px_DIS_16PSK_2_3_FIELD	0
+#define STV090x_WIDTH_Px_DIS_16PSK_2_3_FIELD	4
+
+#define STV090x_Px_MODCODLST7(__x)		(0xf4b7 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST7			STV090x_Px_MODCODLST7(1)
+#define STV090x_P2_MODCODLST7			STV090x_Px_MODCODLST7(2)
+#define STV090x_OFFST_Px_DIS_8P_9_10_FIELD	4
+#define STV090x_WIDTH_Px_DIS_8P_9_10_FIELD	4
+#define STV090x_OFFST_Px_DIS_8P_8_9_FIELD	0
+#define STV090x_WIDTH_Px_DIS_8P_8_9_FIELD	4
+
+#define STV090x_Px_MODCODLST8(__x)		(0xf4b8 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST8			STV090x_Px_MODCODLST8(1)
+#define STV090x_P2_MODCODLST8			STV090x_Px_MODCODLST8(2)
+#define STV090x_OFFST_Px_DIS_8P_5_6_FIELD	4
+#define STV090x_WIDTH_Px_DIS_8P_5_6_FIELD	4
+#define STV090x_OFFST_Px_DIS_8P_3_4_FIELD	0
+#define STV090x_WIDTH_Px_DIS_8P_3_4_FIELD	4
+
+#define STV090x_Px_MODCODLST9(__x)		(0xf4b9 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST9			STV090x_Px_MODCODLST9(1)
+#define STV090x_P2_MODCODLST9			STV090x_Px_MODCODLST9(2)
+#define STV090x_OFFST_Px_DIS_8P_2_3_FIELD	4
+#define STV090x_WIDTH_Px_DIS_8P_2_3_FIELD	4
+#define STV090x_OFFST_Px_DIS_8P_3_5_FIELD	0
+#define STV090x_WIDTH_Px_DIS_8P_3_5_FIELD	4
+
+#define STV090x_Px_MODCODLSTA(__x)		(0xf4ba - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTA			STV090x_Px_MODCODLSTA(1)
+#define STV090x_P2_MODCODLSTA			STV090x_Px_MODCODLSTA(2)
+#define STV090x_OFFST_Px_DIS_QP_9_10_FIELD	4
+#define STV090x_WIDTH_Px_DIS_QP_9_10_FIELD	4
+#define STV090x_OFFST_Px_DIS_QP_8_9_FIELD	0
+#define STV090x_WIDTH_Px_DIS_QP_8_9_FIELD	4
+
+#define STV090x_Px_MODCODLSTB(__x)		(0xf4bb - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTB			STV090x_Px_MODCODLSTB(1)
+#define STV090x_P2_MODCODLSTB			STV090x_Px_MODCODLSTB(2)
+#define STV090x_OFFST_Px_DIS_QP_5_6_FIELD	4
+#define STV090x_WIDTH_Px_DIS_QP_5_6_FIELD	4
+#define STV090x_OFFST_Px_DIS_QP_4_5_FIELD	0
+#define STV090x_WIDTH_Px_DIS_QP_4_5_FIELD	4
+
+#define STV090x_Px_MODCODLSTC(__x)		(0xf4bc - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTC			STV090x_Px_MODCODLSTC(1)
+#define STV090x_P2_MODCODLSTC			STV090x_Px_MODCODLSTC(2)
+#define STV090x_OFFST_Px_DIS_QP_3_4_FIELD	4
+#define STV090x_WIDTH_Px_DIS_QP_3_4_FIELD	4
+#define STV090x_OFFST_Px_DIS_QP_2_3_FIELD	0
+#define STV090x_WIDTH_Px_DIS_QP_2_3_FIELD	4
+
+#define STV090x_Px_MODCODLSTD(__x)		(0xf4bd - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTD			STV090x_Px_MODCODLSTD(1)
+#define STV090x_P2_MODCODLSTD			STV090x_Px_MODCODLSTD(2)
+#define STV090x_OFFST_Px_DIS_QP_3_5_FIELD	4
+#define STV090x_WIDTH_Px_DIS_QP_3_5_FIELD	4
+#define STV090x_OFFST_Px_DIS_QP_1_2_FIELD	0
+#define STV090x_WIDTH_Px_DIS_QP_1_2_FIELD	4
+
+#define STV090x_Px_MODCODLSTE(__x)		(0xf4be - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTE			STV090x_Px_MODCODLSTE(1)
+#define STV090x_P2_MODCODLSTE			STV090x_Px_MODCODLSTE(2)
+#define STV090x_OFFST_Px_DIS_QP_2_5_FIELD	4
+#define STV090x_WIDTH_Px_DIS_QP_2_5_FIELD	4
+#define STV090x_OFFST_Px_DIS_QP_1_3_FIELD	0
+#define STV090x_WIDTH_Px_DIS_QP_1_3_FIELD	4
+
+#define STV090x_Px_MODCODLSTF(__x)		(0xf4bf - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTF			STV090x_Px_MODCODLSTF(1)
+#define STV090x_P2_MODCODLSTF			STV090x_Px_MODCODLSTF(2)
+#define STV090x_OFFST_Px_DIS_QP_1_4_FIELD	4
+#define STV090x_WIDTH_Px_DIS_QP_1_4_FIELD	4
+
+#define STV090x_Px_GAUSSR0(__x)			(0xf4c0 - (__x - 1) * 0x200)
+#define STV090x_P1_GAUSSR0			STV090x_Px_GAUSSR0(1)
+#define STV090x_P2_GAUSSR0			STV090x_Px_GAUSSR0(2)
+#define STV090x_OFFST_Px_EN_CCIMODE_FIELD	7
+#define STV090x_WIDTH_Px_EN_CCIMODE_FIELD	1
+#define STV090x_OFFST_Px_R0_GAUSSIEN_FIELD	0
+#define STV090x_WIDTH_Px_R0_GAUSSIEN_FIELD	7
+
+#define STV090x_Px_CCIR0(__x)			(0xf4c1 - (__x - 1) * 0x200)
+#define STV090x_P1_CCIR0			STV090x_Px_CCIR0(1)
+#define STV090x_P2_CCIR0			STV090x_Px_CCIR0(2)
+#define STV090x_OFFST_Px_CCIDETECT_PLH_FIELD	7
+#define STV090x_WIDTH_Px_CCIDETECT_PLH_FIELD	1
+#define STV090x_OFFST_Px_R0_CCI_FIELD		0
+#define STV090x_WIDTH_Px_R0_CCI_FIELD		7
+
+#define STV090x_Px_CCIQUANT(__x)		(0xf4c2 - (__x - 1) * 0x200)
+#define STV090x_P1_CCIQUANT			STV090x_Px_CCIQUANT(1)
+#define STV090x_P2_CCIQUANT			STV090x_Px_CCIQUANT(2)
+#define STV090x_OFFST_Px_CCI_BETA_FIELD		5
+#define STV090x_WIDTH_Px_CCI_BETA_FIELD		3
+#define STV090x_OFFST_Px_CCI_QUANT_FIELD	0
+#define STV090x_WIDTH_Px_CCI_QUANT_FIELD	5
+
+#define STV090x_Px_CCITHRESH(__x)		(0xf4c3 - (__x - 1) * 0x200)
+#define STV090x_P1_CCITHRESH			STV090x_Px_CCITHRESH(1)
+#define STV090x_P2_CCITHRESH			STV090x_Px_CCITHRESH(2)
+#define STV090x_OFFST_Px_CCI_THRESHOLD_FIELD	0
+#define STV090x_WIDTH_Px_CCI_THRESHOLD_FIELD	8
+
+#define STV090x_Px_CCIACC(__x)			(0xf4c4 - (__x - 1) * 0x200)
+#define STV090x_P1_CCIACC			STV090x_Px_CCIACC(1)
+#define STV090x_P2_CCIACC			STV090x_Px_CCIACC(2)
+#define STV090x_OFFST_Px_CCI_VALUE_FIELD	0
+#define STV090x_WIDTH_Px_CCI_VALUE_FIELD	8
+
+#define STV090x_Px_DMDRESCFG(__x)		(0xF4C6 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDRESCFG			STV090x_Px_DMDRESCFG(1)
+#define STV090x_P2_DMDRESCFG			STV090x_Px_DMDRESCFG(2)
+#define STV090x_OFFST_Px_DMDRES_RESET_FIELD	7
+#define STV090x_WIDTH_Px_DMDRES_RESET_FIELD	1
+
+#define STV090x_Px_DMDRESADR(__x)		(0xF4C7 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDRESADR			STV090x_Px_DMDRESADR(1)
+#define STV090x_P2_DMDRESADR			STV090x_Px_DMDRESADR(2)
+#define STV090x_OFFST_Px_DMDRES_RESNBR_FIELD	0
+#define STV090x_WIDTH_Px_DMDRES_RESNBR_FIELD	4
+
+#define STV090x_Px_DMDRESDATAy(__x, __y)	(0xF4C8 - (__x - 1) * 0x200 + (7 - __y))
+#define STV090x_P1_DMDRESDATA0			STV090x_Px_DMDRESDATAy(1, 0)
+#define STV090x_P1_DMDRESDATA1			STV090x_Px_DMDRESDATAy(1, 1)
+#define STV090x_P1_DMDRESDATA2			STV090x_Px_DMDRESDATAy(1, 2)
+#define STV090x_P1_DMDRESDATA3			STV090x_Px_DMDRESDATAy(1, 3)
+#define STV090x_P1_DMDRESDATA4			STV090x_Px_DMDRESDATAy(1, 4)
+#define STV090x_P1_DMDRESDATA5			STV090x_Px_DMDRESDATAy(1, 5)
+#define STV090x_P1_DMDRESDATA6			STV090x_Px_DMDRESDATAy(1, 6)
+#define STV090x_P1_DMDRESDATA7			STV090x_Px_DMDRESDATAy(1, 7)
+#define STV090x_P2_DMDRESDATA0			STV090x_Px_DMDRESDATAy(2, 0)
+#define STV090x_P2_DMDRESDATA1			STV090x_Px_DMDRESDATAy(2, 1)
+#define STV090x_P2_DMDRESDATA2			STV090x_Px_DMDRESDATAy(2, 2)
+#define STV090x_P2_DMDRESDATA3			STV090x_Px_DMDRESDATAy(2, 3)
+#define STV090x_P2_DMDRESDATA4			STV090x_Px_DMDRESDATAy(2, 4)
+#define STV090x_P2_DMDRESDATA5			STV090x_Px_DMDRESDATAy(2, 5)
+#define STV090x_P2_DMDRESDATA6			STV090x_Px_DMDRESDATAy(2, 6)
+#define STV090x_P2_DMDRESDATA7			STV090x_Px_DMDRESDATAy(2, 7)
+#define STV090x_OFFST_Px_DMDRES_DATA_FIELD	0
+#define STV090x_WIDTH_Px_DMDRES_DATA_FIELD	8
+
+#define STV090x_Px_FFEIy(__x, __y)		(0xf4d0 - (__x - 1) * 0x200 + 0x2 * (__y - 1))
+#define STV090x_P1_FFEI1			STV090x_Px_FFEIy(1, 1)
+#define STV090x_P1_FFEI2			STV090x_Px_FFEIy(1, 2)
+#define STV090x_P1_FFEI3			STV090x_Px_FFEIy(1, 3)
+#define STV090x_P1_FFEI4			STV090x_Px_FFEIy(1, 4)
+#define STV090x_P2_FFEI1			STV090x_Px_FFEIy(2, 1)
+#define STV090x_P2_FFEI2			STV090x_Px_FFEIy(2, 2)
+#define STV090x_P2_FFEI3			STV090x_Px_FFEIy(2, 3)
+#define STV090x_P2_FFEI4			STV090x_Px_FFEIy(2, 4)
+#define STV090x_OFFST_Px_FFE_ACCIy_FIELD	0
+#define STV090x_WIDTH_Px_FFE_ACCIy_FIELD	8
+
+#define STV090x_Px_FFEQy(__x, __y)		(0xf4d1 - (__x - 1) * 0x200 + 0x2 * (__y - 1))
+#define STV090x_P1_FFEQ1			STV090x_Px_FFEQy(1, 1)
+#define STV090x_P1_FFEQ2			STV090x_Px_FFEQy(1, 2)
+#define STV090x_P1_FFEQ3			STV090x_Px_FFEQy(1, 3)
+#define STV090x_P1_FFEQ4			STV090x_Px_FFEQy(1, 4)
+#define STV090x_P2_FFEQ1			STV090x_Px_FFEQy(2, 1)
+#define STV090x_P2_FFEQ2			STV090x_Px_FFEQy(2, 2)
+#define STV090x_P2_FFEQ3			STV090x_Px_FFEQy(2, 3)
+#define STV090x_P2_FFEQ4			STV090x_Px_FFEQy(2, 4)
+#define STV090x_OFFST_Px_FFE_ACCQy_FIELD	0
+#define STV090x_WIDTH_Px_FFE_ACCQy_FIELD	8
+
+#define STV090x_Px_FFECFG(__x)			(0xf4d8 - (__x - 1) * 0x200)
+#define STV090x_P1_FFECFG			STV090x_Px_FFECFG(1)
+#define STV090x_P2_FFECFG			STV090x_Px_FFECFG(2)
+#define STV090x_OFFST_Px_EQUALFFE_ON_FIELD	6
+#define STV090x_WIDTH_Px_EQUALFFE_ON_FIELD	1
+
+#define STV090x_Px_SMAPCOEF7(__x)		(0xf500 - (__x - 1) * 0x200)
+#define STV090x_P1_SMAPCOEF7			STV090x_Px_SMAPCOEF7(1)
+#define STV090x_P2_SMAPCOEF7			STV090x_Px_SMAPCOEF7(2)
+#define STV090x_OFFST_Px_DIS_QSCALE_FIELD	7
+#define STV090x_WIDTH_Px_DIS_QSCALE_FIELD	1
+#define STV090x_OFFST_Px_SMAPCOEF_Q_LLR12_FIELD	0
+#define STV090x_WIDTH_Px_SMAPCOEF_Q_LLR12_FIELD	7
+
+#define STV090x_Px_SMAPCOEF6(__x)		(0xf501 - (__x - 1) * 0x200)
+#define STV090x_P1_SMAPCOEF6			STV090x_Px_SMAPCOEF6(1)
+#define STV090x_P2_SMAPCOEF6			STV090x_Px_SMAPCOEF6(2)
+#define STV090x_OFFST_Px_ADJ_8PSKLLR1_FIELD	2
+#define STV090x_WIDTH_Px_ADJ_8PSKLLR1_FIELD	1
+#define STV090x_OFFST_Px_OLD_8PSKLLR1_FIELD	1
+#define STV090x_WIDTH_Px_OLD_8PSKLLR1_FIELD	1
+#define STV090x_OFFST_Px_DIS_AB8PSK_FIELD	0
+#define STV090x_WIDTH_Px_DIS_AB8PSK_FIELD	1
+
+#define STV090x_Px_SMAPCOEF5(__x)			(0xf502 - (__x - 1) * 0x200)
+#define STV090x_P1_SMAPCOEF5				STV090x_Px_SMAPCOEF5(1)
+#define STV090x_P2_SMAPCOEF5				STV090x_Px_SMAPCOEF5(2)
+#define STV090x_OFFST_Px_DIS_8SCALE_FIELD		7
+#define STV090x_WIDTH_Px_DIS_8SCALE_FIELD		1
+#define STV090x_OFFST_Px_SMAPCOEF_8P_LLR23_FIELD	0
+#define STV090x_WIDTH_Px_SMAPCOEF_8P_LLR23_FIELD	7
+
+#define STV090x_Px_DMDPLHSTAT(__x)		(0xF520 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDPLHSTAT			STV090x_Px_DMDPLHSTAT(1)
+#define STV090x_P2_DMDPLHSTAT			STV090x_Px_DMDPLHSTAT(2)
+#define STV090x_OFFST_Px_PLH_STATISTIC_FIELD	0
+#define STV090x_WIDTH_Px_PLH_STATISTIC_FIELD	8
+
+#define STV090x_Px_LOCKTIMEy(__x, __y)		(0xF525 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_LOCKTIME0			STV090x_Px_LOCKTIMEy(1, 0)
+#define STV090x_P1_LOCKTIME1			STV090x_Px_LOCKTIMEy(1, 1)
+#define STV090x_P1_LOCKTIME2			STV090x_Px_LOCKTIMEy(1, 2)
+#define STV090x_P1_LOCKTIME3			STV090x_Px_LOCKTIMEy(1, 3)
+#define STV090x_P2_LOCKTIME0			STV090x_Px_LOCKTIMEy(2, 0)
+#define STV090x_P2_LOCKTIME1			STV090x_Px_LOCKTIMEy(2, 1)
+#define STV090x_P2_LOCKTIME2			STV090x_Px_LOCKTIMEy(2, 2)
+#define STV090x_P2_LOCKTIME3			STV090x_Px_LOCKTIMEy(2, 3)
+#define STV090x_OFFST_Px_DEMOD_LOCKTIME_FIELD	0
+#define STV090x_WIDTH_Px_DEMOD_LOCKTIME_FIELD	8
+
+#define STV090x_Px_TNRCFG(__x)			(0xf4e0 - (__x - 1) * 0x200) /* check */
+#define STV090x_P1_TNRCFG			STV090x_Px_TNRCFG(1)
+#define STV090x_P2_TNRCFG			STV090x_Px_TNRCFG(2)
+
+#define STV090x_Px_TNRCFG2(__x)			(0xf4e1 - (__x - 1) * 0x200)
+#define STV090x_P1_TNRCFG2			STV090x_Px_TNRCFG2(1)
+#define STV090x_P2_TNRCFG2			STV090x_Px_TNRCFG2(2)
+#define STV090x_OFFST_Px_TUN_IQSWAP_FIELD	7
+#define STV090x_WIDTH_Px_TUN_IQSWAP_FIELD	1
+
+#define STV090x_Px_VITSCALE(__x)		(0xf532 - (__x - 1) * 0x200)
+#define STV090x_P1_VITSCALE			STV090x_Px_VITSCALE(1)
+#define STV090x_P2_VITSCALE			STV090x_Px_VITSCALE(2)
+#define STV090x_OFFST_Px_NVTH_NOSRANGE_FIELD	7
+#define STV090x_WIDTH_Px_NVTH_NOSRANGE_FIELD	1
+#define STV090x_OFFST_Px_VERROR_MAXMODE_FIELD	6
+#define STV090x_WIDTH_Px_VERROR_MAXMODE_FIELD	1
+#define STV090x_OFFST_Px_NSLOWSN_LOCKED_FIELD	3
+#define STV090x_WIDTH_Px_NSLOWSN_LOCKED_FIELD	1
+#define STV090x_OFFST_Px_DIS_RSFLOCK_FIELD	1
+#define STV090x_WIDTH_Px_DIS_RSFLOCK_FIELD	1
+
+#define STV090x_Px_FECM(__x)			(0xf533 - (__x - 1) * 0x200)
+#define STV090x_P1_FECM				STV090x_Px_FECM(1)
+#define STV090x_P2_FECM				STV090x_Px_FECM(2)
+#define STV090x_OFFST_Px_DSS_DVB_FIELD		7
+#define STV090x_WIDTH_Px_DSS_DVB_FIELD		1
+#define STV090x_OFFST_Px_DSS_SRCH_FIELD		4
+#define STV090x_WIDTH_Px_DSS_SRCH_FIELD		1
+#define STV090x_OFFST_Px_SYNCVIT_FIELD		1
+#define STV090x_WIDTH_Px_SYNCVIT_FIELD		1
+#define STV090x_OFFST_Px_IQINV_FIELD		0
+#define STV090x_WIDTH_Px_IQINV_FIELD		1
+
+#define STV090x_Px_VTH12(__x)			(0xf534 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH12			STV090x_Px_VTH12(1)
+#define STV090x_P2_VTH12			STV090x_Px_VTH12(2)
+#define STV090x_OFFST_Px_VTH12_FIELD		0
+#define STV090x_WIDTH_Px_VTH12_FIELD		8
+
+#define STV090x_Px_VTH23(__x)			(0xf535 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH23			STV090x_Px_VTH23(1)
+#define STV090x_P2_VTH23			STV090x_Px_VTH23(2)
+#define STV090x_OFFST_Px_VTH23_FIELD		0
+#define STV090x_WIDTH_Px_VTH23_FIELD		8
+
+#define STV090x_Px_VTH34(__x)			(0xf536 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH34			STV090x_Px_VTH34(1)
+#define STV090x_P2_VTH34			STV090x_Px_VTH34(2)
+#define STV090x_OFFST_Px_VTH34_FIELD		0
+#define STV090x_WIDTH_Px_VTH34_FIELD		8
+
+#define STV090x_Px_VTH56(__x)			(0xf537 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH56			STV090x_Px_VTH56(1)
+#define STV090x_P2_VTH56			STV090x_Px_VTH56(2)
+#define STV090x_OFFST_Px_VTH56_FIELD		0
+#define STV090x_WIDTH_Px_VTH56_FIELD		8
+
+#define STV090x_Px_VTH67(__x)			(0xf538 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH67			STV090x_Px_VTH67(1)
+#define STV090x_P2_VTH67			STV090x_Px_VTH67(2)
+#define STV090x_OFFST_Px_VTH67_FIELD		0
+#define STV090x_WIDTH_Px_VTH67_FIELD		8
+
+#define STV090x_Px_VTH78(__x)			(0xf539 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH78			STV090x_Px_VTH78(1)
+#define STV090x_P2_VTH78			STV090x_Px_VTH78(2)
+#define STV090x_OFFST_Px_VTH78_FIELD		0
+#define STV090x_WIDTH_Px_VTH78_FIELD		8
+
+#define STV090x_Px_VITCURPUN(__x)		(0xf53a - (__x - 1) * 0x200)
+#define STV090x_P1_VITCURPUN			STV090x_Px_VITCURPUN(1)
+#define STV090x_P2_VITCURPUN			STV090x_Px_VITCURPUN(2)
+#define STV090x_OFFST_Px_VIT_CURPUN_FIELD	0
+#define STV090x_WIDTH_Px_VIT_CURPUN_FIELD	5
+
+#define STV090x_Px_VERROR(__x)			(0xf53b - (__x - 1) * 0x200)
+#define STV090x_P1_VERROR			STV090x_Px_VERROR(1)
+#define STV090x_P2_VERROR			STV090x_Px_VERROR(2)
+#define STV090x_OFFST_Px_REGERR_VIT_FIELD	0
+#define STV090x_WIDTH_Px_REGERR_VIT_FIELD	8
+
+#define STV090x_Px_PRVIT(__x)			(0xf53c - (__x - 1) * 0x200)
+#define STV090x_P1_PRVIT			STV090x_Px_PRVIT(1)
+#define STV090x_P2_PRVIT			STV090x_Px_PRVIT(2)
+#define STV090x_OFFST_Px_DIS_VTHLOCK_FIELD	6
+#define STV090x_WIDTH_Px_DIS_VTHLOCK_FIELD	1
+#define STV090x_OFFST_Px_E7_8VIT_FIELD		5
+#define STV090x_WIDTH_Px_E7_8VIT_FIELD		1
+#define STV090x_OFFST_Px_E6_7VIT_FIELD		4
+#define STV090x_WIDTH_Px_E6_7VIT_FIELD		1
+#define STV090x_OFFST_Px_E5_6VIT_FIELD		3
+#define STV090x_WIDTH_Px_E5_6VIT_FIELD		1
+#define STV090x_OFFST_Px_E3_4VIT_FIELD		2
+#define STV090x_WIDTH_Px_E3_4VIT_FIELD		1
+#define STV090x_OFFST_Px_E2_3VIT_FIELD		1
+#define STV090x_WIDTH_Px_E2_3VIT_FIELD		1
+#define STV090x_OFFST_Px_E1_2VIT_FIELD		0
+#define STV090x_WIDTH_Px_E1_2VIT_FIELD		1
+
+#define STV090x_Px_VAVSRVIT(__x)		(0xf53d - (__x - 1) * 0x200)
+#define STV090x_P1_VAVSRVIT			STV090x_Px_VAVSRVIT(1)
+#define STV090x_P2_VAVSRVIT			STV090x_Px_VAVSRVIT(2)
+#define STV090x_OFFST_Px_SNVIT_FIELD		4
+#define STV090x_WIDTH_Px_SNVIT_FIELD		2
+#define STV090x_OFFST_Px_TOVVIT_FIELD		2
+#define STV090x_WIDTH_Px_TOVVIT_FIELD		2
+#define STV090x_OFFST_Px_HYPVIT_FIELD		0
+#define STV090x_WIDTH_Px_HYPVIT_FIELD		2
+
+#define STV090x_Px_VSTATUSVIT(__x)		(0xf53e - (__x - 1) * 0x200)
+#define STV090x_P1_VSTATUSVIT			STV090x_Px_VSTATUSVIT(1)
+#define STV090x_P2_VSTATUSVIT			STV090x_Px_VSTATUSVIT(2)
+#define STV090x_OFFST_Px_PRFVIT_FIELD		4
+#define STV090x_WIDTH_Px_PRFVIT_FIELD		1
+#define STV090x_OFFST_Px_LOCKEDVIT_FIELD	3
+#define STV090x_WIDTH_Px_LOCKEDVIT_FIELD	1
+
+#define STV090x_Px_VTHINUSE(__x)		(0xf53f - (__x - 1) * 0x200)
+#define STV090x_P1_VTHINUSE			STV090x_Px_VTHINUSE(1)
+#define STV090x_P2_VTHINUSE			STV090x_Px_VTHINUSE(2)
+#define STV090x_OFFST_Px_VIT_INUSE_FIELD	0
+#define STV090x_WIDTH_Px_VIT_INUSE_FIELD	8
+
+#define STV090x_Px_KDIV12(__x)			(0xf540 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV12			STV090x_Px_KDIV12(1)
+#define STV090x_P2_KDIV12			STV090x_Px_KDIV12(2)
+#define STV090x_OFFST_Px_K_DIVIDER_12_FIELD	0
+#define STV090x_WIDTH_Px_K_DIVIDER_12_FIELD	7
+
+#define STV090x_Px_KDIV23(__x)			(0xf541 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV23			STV090x_Px_KDIV23(1)
+#define STV090x_P2_KDIV23			STV090x_Px_KDIV23(2)
+#define STV090x_OFFST_Px_K_DIVIDER_23_FIELD	0
+#define STV090x_WIDTH_Px_K_DIVIDER_23_FIELD	7
+
+#define STV090x_Px_KDIV34(__x)			(0xf542 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV34			STV090x_Px_KDIV34(1)
+#define STV090x_P2_KDIV34			STV090x_Px_KDIV34(2)
+#define STV090x_OFFST_Px_K_DIVIDER_34_FIELD	0
+#define STV090x_WIDTH_Px_K_DIVIDER_34_FIELD	7
+
+#define STV090x_Px_KDIV56(__x)			(0xf543 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV56			STV090x_Px_KDIV56(1)
+#define STV090x_P2_KDIV56			STV090x_Px_KDIV56(2)
+#define STV090x_OFFST_Px_K_DIVIDER_56_FIELD	0
+#define STV090x_WIDTH_Px_K_DIVIDER_56_FIELD	7
+
+#define STV090x_Px_KDIV67(__x)			(0xf544 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV67			STV090x_Px_KDIV67(1)
+#define STV090x_P2_KDIV67			STV090x_Px_KDIV67(2)
+#define STV090x_OFFST_Px_K_DIVIDER_67_FIELD	0
+#define STV090x_WIDTH_Px_K_DIVIDER_67_FIELD	7
+
+#define STV090x_Px_KDIV78(__x)			(0xf545 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV78			STV090x_Px_KDIV78(1)
+#define STV090x_P2_KDIV78			STV090x_Px_KDIV78(2)
+#define STV090x_OFFST_Px_K_DIVIDER_78_FIELD	0
+#define STV090x_WIDTH_Px_K_DIVIDER_78_FIELD	7
+
+#define STV090x_Px_PDELCTRL1(__x)		(0xf550 - (__x - 1) * 0x200)
+#define STV090x_P1_PDELCTRL1			STV090x_Px_PDELCTRL1(1)
+#define STV090x_P2_PDELCTRL1			STV090x_Px_PDELCTRL1(2)
+#define STV090x_OFFST_Px_INV_MISMASK_FIELD	7
+#define STV090x_WIDTH_Px_INV_MISMASK_FIELD	1
+#define STV090x_OFFST_Px_FILTER_EN_FIELD	5
+#define STV090x_WIDTH_Px_FILTER_EN_FIELD	1
+#define STV090x_OFFST_Px_EN_MIS00_FIELD		1
+#define STV090x_WIDTH_Px_EN_MIS00_FIELD		1
+#define STV090x_OFFST_Px_ALGOSWRST_FIELD	0
+#define STV090x_WIDTH_Px_ALGOSWRST_FIELD	1
+
+#define STV090x_Px_PDELCTRL2(__x)		(0xf551 - (__x - 1) * 0x200)
+#define STV090x_P1_PDELCTRL2			STV090x_Px_PDELCTRL2(1)
+#define STV090x_P2_PDELCTRL2			STV090x_Px_PDELCTRL2(2)
+#define STV090x_OFFST_Px_FORCE_CONTINUOUS	7
+#define STV090x_WIDTH_Px_FORCE_CONTINUOUS	1
+#define STV090x_OFFST_Px_RESET_UPKO_COUNT	6
+#define STV090x_WIDTH_Px_RESET_UPKO_COUNT	1
+#define STV090x_OFFST_Px_USER_PKTDELIN_NB	5
+#define STV090x_WIDTH_Px_USER_PKTDELIN_NB	1
+#define STV090x_OFFST_Px_FORCE_LOCKED		4
+#define STV090x_WIDTH_Px_FORCE_LOCKED		1
+#define STV090x_OFFST_Px_DATA_UNBBSCRAM		3
+#define STV090x_WIDTH_Px_DATA_UNBBSCRAM		1
+#define STV090x_OFFST_Px_FORCE_LONGPACKET	2
+#define STV090x_WIDTH_Px_FORCE_LONGPACKET	1
+#define STV090x_OFFST_Px_FRAME_MODE_FIELD	1
+#define STV090x_WIDTH_Px_FRAME_MODE_FIELD	1
+
+#define STV090x_Px_HYSTTHRESH(__x)		(0xf554 - (__x - 1) * 0x200)
+#define STV090x_P1_HYSTTHRESH			STV090x_Px_HYSTTHRESH(1)
+#define STV090x_P2_HYSTTHRESH			STV090x_Px_HYSTTHRESH(2)
+#define STV090x_OFFST_Px_UNLCK_THRESH_FIELD	4
+#define STV090x_WIDTH_Px_UNLCK_THRESH_FIELD	4
+#define STV090x_OFFST_Px_DELIN_LCK_THRESH_FIELD	0
+#define STV090x_WIDTH_Px_DELIN_LCK_THRESH_FIELD	4
+
+#define STV090x_Px_ISIENTRY(__x)		(0xf55e - (__x - 1) * 0x200)
+#define STV090x_P1_ISIENTRY			STV090x_Px_ISIENTRY(1)
+#define STV090x_P2_ISIENTRY			STV090x_Px_ISIENTRY(2)
+#define STV090x_OFFST_Px_ISI_ENTRY_FIELD	0
+#define STV090x_WIDTH_Px_ISI_ENTRY_FIELD	8
+
+#define STV090x_Px_ISIBITENA(__x)		(0xf55f - (__x - 1) * 0x200)
+#define STV090x_P1_ISIBITENA			STV090x_Px_ISIBITENA(1)
+#define STV090x_P2_ISIBITENA			STV090x_Px_ISIBITENA(2)
+#define STV090x_OFFST_Px_ISI_BIT_EN_FIELD	0
+#define STV090x_WIDTH_Px_ISI_BIT_EN_FIELD	8
+
+#define STV090x_Px_MATSTRy(__x, __y)		(0xf561 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_MATSTR0			STV090x_Px_MATSTRy(1, 0)
+#define STV090x_P1_MATSTR1			STV090x_Px_MATSTRy(1, 1)
+#define STV090x_P2_MATSTR0			STV090x_Px_MATSTRy(2, 0)
+#define STV090x_P2_MATSTR1			STV090x_Px_MATSTRy(2, 1)
+#define STV090x_OFFST_Px_MATYPE_CURRENT_FIELD	0
+#define STV090x_WIDTH_Px_MATYPE_CURRENT_FIELD	8
+
+#define STV090x_Px_UPLSTRy(__x, __y)		(0xf563 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_UPLSTR0			STV090x_Px_UPLSTRy(1, 0)
+#define STV090x_P1_UPLSTR1			STV090x_Px_UPLSTRy(1, 1)
+#define STV090x_P2_UPLSTR0			STV090x_Px_UPLSTRy(2, 0)
+#define STV090x_P2_UPLSTR1			STV090x_Px_UPLSTRy(2, 1)
+#define STV090x_OFFST_Px_UPL_CURRENT_FIELD	0
+#define STV090x_WIDTH_Px_UPL_CURRENT_FIELD	8
+
+#define STV090x_Px_DFLSTRy(__x, __y)		(0xf565 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_DFLSTR0			STV090x_Px_DFLSTRy(1, 0)
+#define STV090x_P1_DFLSTR1			STV090x_Px_DFLSTRy(1, 1)
+#define STV090x_P2_DFLSTR0			STV090x_Px_DFLSTRy(2, 0)
+#define STV090x_P2_DFLSTR1			STV090x_Px_DFLSTRy(2, 1)
+#define STV090x_OFFST_Px_DFL_CURRENT_FIELD	0
+#define STV090x_WIDTH_Px_DFL_CURRENT_FIELD	8
+
+#define STV090x_Px_SYNCSTR(__x)			(0xf566 - (__x - 1) * 0x200)
+#define STV090x_P1_SYNCSTR			STV090x_Px_SYNCSTR(1)
+#define STV090x_P2_SYNCSTR			STV090x_Px_SYNCSTR(2)
+#define STV090x_OFFST_Px_SYNC_CURRENT_FIELD	0
+#define STV090x_WIDTH_Px_SYNC_CURRENT_FIELD	8
+
+#define STV090x_Px_SYNCDSTRy(__x, __y)		(0xf568 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_SYNCDSTR0			STV090x_Px_SYNCDSTRy(1, 0)
+#define STV090x_P1_SYNCDSTR1			STV090x_Px_SYNCDSTRy(1, 1)
+#define STV090x_P2_SYNCDSTR0			STV090x_Px_SYNCDSTRy(2, 0)
+#define STV090x_P2_SYNCDSTR1			STV090x_Px_SYNCDSTRy(2, 1)
+#define STV090x_OFFST_Px_SYNCD_CURRENT_FIELD	0
+#define STV090x_WIDTH_Px_SYNCD_CURRENT_FIELD	8
+
+#define STV090x_Px_PDELSTATUS1(__x)		(0xf569 - (__x - 1) * 0x200)
+#define STV090x_P1_PDELSTATUS1			STV090x_Px_PDELSTATUS1(1)
+#define STV090x_P2_PDELSTATUS1			STV090x_Px_PDELSTATUS1(2)
+#define STV090x_OFFST_Px_PKTDELIN_LOCK_FIELD	1
+#define STV090x_WIDTH_Px_PKTDELIN_LOCK_FIELD	1
+#define STV090x_OFFST_Px_FIRST_LOCK_FIELD	0
+#define STV090x_WIDTH_Px_FIRST_LOCK_FIELD	1
+
+#define STV090x_Px_PDELSTATUS2(__x)		(0xf56a - (__x - 1) * 0x200)
+#define STV090x_P1_PDELSTATUS2			STV090x_Px_PDELSTATUS2(1)
+#define STV090x_P2_PDELSTATUS2			STV090x_Px_PDELSTATUS2(2)
+#define STV090x_OFFST_Px_FRAME_MODCOD_FIELD	2
+#define STV090x_WIDTH_Px_FRAME_MODCOD_FIELD	5
+#define STV090x_OFFST_Px_FRAME_TYPE_FIELD	0
+#define STV090x_WIDTH_Px_FRAME_TYPE_FIELD	2
+
+#define STV090x_Px_BBFCRCKO1(__x)		(0xf56b - (__x - 1) * 0x200)
+#define STV090x_P1_BBFCRCKO1			STV090x_Px_BBFCRCKO1(1)
+#define STV090x_P2_BBFCRCKO1			STV090x_Px_BBFCRCKO1(2)
+#define STV090x_OFFST_Px_BBHCRC_KOCNT_FIELD	0
+#define STV090x_WIDTH_Px_BBHCRC_KOCNT_FIELD	8
+
+#define STV090x_Px_BBFCRCKO0(__x)		(0xf56c - (__x - 1) * 0x200)
+#define STV090x_P1_BBFCRCKO0			STV090x_Px_BBFCRCKO0(1)
+#define STV090x_P2_BBFCRCKO0			STV090x_Px_BBFCRCKO0(2)
+#define STV090x_OFFST_Px_BBHCRC_KOCNT_FIELD	0
+#define STV090x_WIDTH_Px_BBHCRC_KOCNT_FIELD	8
+
+#define STV090x_Px_UPCRCKO1(__x)		(0xf56d - (__x - 1) * 0x200)
+#define STV090x_P1_UPCRCKO1			STV090x_Px_UPCRCKO1(1)
+#define STV090x_P2_UPCRCKO1			STV090x_Px_UPCRCKO1(2)
+#define STV090x_OFFST_Px_PKTCRC_KOCNT_FIELD	0
+#define STV090x_WIDTH_Px_PKTCRC_KOCNT_FIELD	8
+
+#define STV090x_Px_UPCRCKO0(__x)		(0xf56e - (__x - 1) * 0x200)
+#define STV090x_P1_UPCRCKO0			STV090x_Px_UPCRCKO0(1)
+#define STV090x_P2_UPCRCKO0			STV090x_Px_UPCRCKO0(2)
+#define STV090x_OFFST_Px_PKTCRC_KOCNT_FIELD	0
+#define STV090x_WIDTH_Px_PKTCRC_KOCNT_FIELD	8
+
+#define STV090x_NBITER_NFx(__x)				(0xFA03 + (__x - 4) * 0x1)
+#define STV090x_NBITER_NF4				STV090x_NBITER_NFx(4)
+#define STV090x_NBITER_NF5				STV090x_NBITER_NFx(5)
+#define STV090x_NBITER_NF6				STV090x_NBITER_NFx(6)
+#define STV090x_NBITER_NF7				STV090x_NBITER_NFx(7)
+#define STV090x_NBITER_NF8				STV090x_NBITER_NFx(8)
+#define STV090x_NBITER_NF9				STV090x_NBITER_NFx(9)
+#define STV090x_NBITER_NF10				STV090x_NBITER_NFx(10)
+#define STV090x_NBITER_NF11				STV090x_NBITER_NFx(11)
+#define STV090x_NBITER_NF12				STV090x_NBITER_NFx(12)
+#define STV090x_NBITER_NF13				STV090x_NBITER_NFx(13)
+#define STV090x_NBITER_NF14				STV090x_NBITER_NFx(14)
+#define STV090x_NBITER_NF15				STV090x_NBITER_NFx(15)
+#define STV090x_NBITER_NF16				STV090x_NBITER_NFx(16)
+#define STV090x_NBITER_NF17				STV090x_NBITER_NFx(17)
+
+#define STV090x_NBITERNOERR				0xFA3F
+#define STV090x_OFFST_NBITER_STOP_CRIT_FIELD		0
+#define STV090x_WIDTH_NBITER_STOP_CRIT_FIELD		4
+
+#define STV090x_GAINLLR_NFx(__x)			(0xFA43 + (__x - 4) * 0x1)
+#define STV090x_GAINLLR_NF4				STV090x_GAINLLR_NFx(4)
+#define STV090x_OFFST_GAINLLR_NF_QP_1_2_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_QP_1_2_FIELD		7
+
+#define STV090x_GAINLLR_NF5				STV090x_GAINLLR_NFx(5)
+#define STV090x_OFFST_GAINLLR_NF_QP_3_5_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_QP_3_5_FIELD		7
+
+#define STV090x_GAINLLR_NF6				STV090x_GAINLLR_NFx(6)
+#define STV090x_OFFST_GAINLLR_NF_QP_2_3_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_QP_2_3_FIELD		7
+
+#define STV090x_GAINLLR_NF7				STV090x_GAINLLR_NFx(7)
+#define STV090x_OFFST_GAINLLR_NF_QP_3_4_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_QP_3_4_FIELD		7
+
+#define STV090x_GAINLLR_NF8				STV090x_GAINLLR_NFx(8)
+#define STV090x_OFFST_GAINLLR_NF_QP_4_5_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_QP_4_5_FIELD		7
+
+#define STV090x_GAINLLR_NF9				STV090x_GAINLLR_NFx(9)
+#define STV090x_OFFST_GAINLLR_NF_QP_5_6_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_QP_5_6_FIELD		7
+
+#define STV090x_GAINLLR_NF10				STV090x_GAINLLR_NFx(10)
+#define STV090x_OFFST_GAINLLR_NF_QP_8_9_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_QP_8_9_FIELD		7
+
+#define STV090x_GAINLLR_NF11				STV090x_GAINLLR_NFx(11)
+#define STV090x_OFFST_GAINLLR_NF_QP_9_10_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_QP_9_10_FIELD		7
+
+#define STV090x_GAINLLR_NF12				STV090x_GAINLLR_NFx(12)
+#define STV090x_OFFST_GAINLLR_NF_8P_3_5_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_8P_3_5_FIELD		7
+
+#define STV090x_GAINLLR_NF13				STV090x_GAINLLR_NFx(13)
+#define STV090x_OFFST_GAINLLR_NF_8P_2_3_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_8P_2_3_FIELD		7
+
+#define STV090x_GAINLLR_NF14				STV090x_GAINLLR_NFx(14)
+#define STV090x_OFFST_GAINLLR_NF_8P_3_4_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_8P_3_4_FIELD		7
+
+#define STV090x_GAINLLR_NF15				STV090x_GAINLLR_NFx(15)
+#define STV090x_OFFST_GAINLLR_NF_8P_5_6_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_8P_5_6_FIELD		7
+
+#define STV090x_GAINLLR_NF16				STV090x_GAINLLR_NFx(16)
+#define STV090x_OFFST_GAINLLR_NF_8P_8_9_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_8P_8_9_FIELD		7
+
+#define STV090x_GAINLLR_NF17				STV090x_GAINLLR_NFx(17)
+#define STV090x_OFFST_GAINLLR_NF_8P_9_10_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_8P_9_10_FIELD		7
+
+#define STV090x_GENCFG					0xFA86
+#define STV090x_OFFST_BROADCAST_FIELD			4
+#define STV090x_WIDTH_BROADCAST_FIELD			1
+#define STV090x_OFFST_PRIORITY_FIELD			1
+#define STV090x_WIDTH_PRIORITY_FIELD			1
+#define STV090x_OFFST_DDEMOD_FIELD			0
+#define STV090x_WIDTH_DDEMOD_FIELD			1
+
+#define STV090x_LDPCERRx(__x)				(0xFA97 - (__x  * 0x1))
+#define STV090x_LDPCERR0				STV090x_LDPCERRx(0)
+#define STV090x_LDPCERR1				STV090x_LDPCERRx(1)
+#define STV090x_OFFST_Px_LDPC_ERRORS_COUNTER_FIELD	0
+#define STV090x_WIDTH_Px_LDPC_ERRORS_COUNTER_FIELD	8
+
+#define STV090x_BCHERR					0xFA98
+#define STV090x_OFFST_Px_ERRORFLAG_FIELD		4
+#define STV090x_WIDTH_Px_ERRORFLAG_FIELD		1
+#define STV090x_OFFST_Px_BCH_ERRORS_COUNTER_FIELD	0
+#define STV090x_WIDTH_Px_BCH_ERRORS_COUNTER_FIELD	4
+
+#define STV090x_Px_TSSTATEM(__x)			(0xF570 - (__x - 1) * 0x200)
+#define STV090x_P1_TSSTATEM				STV090x_Px_TSSTATEM(1)
+#define STV090x_P2_TSSTATEM				STV090x_Px_TSSTATEM(2)
+#define STV090x_OFFST_Px_TSDIL_ON_FIELD			7
+#define STV090x_WIDTH_Px_TSDIL_ON_FIELD			1
+#define STV090x_OFFST_Px_TSRS_ON_FIELD			5
+#define STV090x_WIDTH_Px_TSRS_ON_FIELD			1
+
+#define STV090x_Px_TSCFGH(__x)				(0xF572 - (__x - 1) * 0x200)
+#define STV090x_P1_TSCFGH				STV090x_Px_TSCFGH(1)
+#define STV090x_P2_TSCFGH				STV090x_Px_TSCFGH(2)
+#define STV090x_OFFST_Px_TSFIFO_DVBCI_FIELD		7
+#define STV090x_WIDTH_Px_TSFIFO_DVBCI_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_SERIAL_FIELD		6
+#define STV090x_WIDTH_Px_TSFIFO_SERIAL_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_TEIUPDATE_FIELD		5
+#define STV090x_WIDTH_Px_TSFIFO_TEIUPDATE_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_DUTY50_FIELD		4
+#define STV090x_WIDTH_Px_TSFIFO_DUTY50_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_HSGNLOUT_FIELD		3
+#define STV090x_WIDTH_Px_TSFIFO_HSGNLOUT_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_ERRORMODE_FIELD		1
+#define STV090x_WIDTH_Px_TSFIFO_ERRORMODE_FIELD		2
+#define STV090x_OFFST_Px_RST_HWARE_FIELD		0
+#define STV090x_WIDTH_Px_RST_HWARE_FIELD		1
+
+#define STV090x_Px_TSCFGM(__x)				(0xF573 - (__x - 1) * 0x200)
+#define STV090x_P1_TSCFGM				STV090x_Px_TSCFGM(1)
+#define STV090x_P2_TSCFGM				STV090x_Px_TSCFGM(2)
+#define STV090x_OFFST_Px_TSFIFO_MANSPEED_FIELD		6
+#define STV090x_WIDTH_Px_TSFIFO_MANSPEED_FIELD		2
+#define STV090x_OFFST_Px_TSFIFO_PERMDATA_FIELD		5
+#define STV090x_WIDTH_Px_TSFIFO_PERMDATA_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_INVDATA_FIELD		0
+#define STV090x_WIDTH_Px_TSFIFO_INVDATA_FIELD		1
+
+#define STV090x_Px_TSCFGL(__x)				(0xF574 - (__x - 1) * 0x200)
+#define STV090x_P1_TSCFGL				STV090x_Px_TSCFGL(1)
+#define STV090x_P2_TSCFGL				STV090x_Px_TSCFGL(2)
+#define STV090x_OFFST_Px_TSFIFO_BCLKDEL1CK_FIELD	6
+#define STV090x_WIDTH_Px_TSFIFO_BCLKDEL1CK_FIELD	2
+#define STV090x_OFFST_Px_BCHERROR_MODE_FIELD		4
+#define STV090x_WIDTH_Px_BCHERROR_MODE_FIELD		2
+#define STV090x_OFFST_Px_TSFIFO_NSGNL2DATA_FIELD	3
+#define STV090x_WIDTH_Px_TSFIFO_NSGNL2DATA_FIELD	1
+#define STV090x_OFFST_Px_TSFIFO_EMBINDVB_FIELD		2
+#define STV090x_WIDTH_Px_TSFIFO_EMBINDVB_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_DPUNACT_FIELD		1
+#define STV090x_WIDTH_Px_TSFIFO_DPUNACT_FIELD		1
+
+#define STV090x_Px_TSINSDELH(__x)			(0xF576 - (__x - 1) * 0x200)
+#define STV090x_P1_TSINSDELH				STV090x_Px_TSINSDELH(1)
+#define STV090x_P2_TSINSDELH				STV090x_Px_TSINSDELH(2)
+#define STV090x_OFFST_Px_TSDEL_SYNCBYTE_FIELD		7
+#define STV090x_WIDTH_Px_TSDEL_SYNCBYTE_FIELD		1
+#define STV090x_OFFST_Px_TSDEL_XXHEADER_FIELD		6
+#define STV090x_WIDTH_Px_TSDEL_XXHEADER_FIELD		1
+
+#define STV090x_Px_TSSPEED(__x)				(0xF580 - (__x - 1) * 0x200)
+#define STV090x_P1_TSSPEED				STV090x_Px_TSSPEED(1)
+#define STV090x_P2_TSSPEED				STV090x_Px_TSSPEED(2)
+#define STV090x_OFFST_Px_TSFIFO_OUTSPEED_FIELD		0
+#define STV090x_WIDTH_Px_TSFIFO_OUTSPEED_FIELD		8
+
+#define STV090x_Px_TSSTATUS(__x)			(0xF581 - (__x - 1) * 0x200)
+#define STV090x_P1_TSSTATUS				STV090x_Px_TSSTATUS(1)
+#define STV090x_P2_TSSTATUS				STV090x_Px_TSSTATUS(2)
+#define STV090x_OFFST_Px_TSFIFO_LINEOK_FIELD		7
+#define STV090x_WIDTH_Px_TSFIFO_LINEOK_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_ERROR_FIELD		6
+#define STV090x_WIDTH_Px_TSFIFO_ERROR_FIELD		1
+
+#define STV090x_Px_TSSTATUS2(__x)			(0xF582 - (__x - 1) * 0x200)
+#define STV090x_P1_TSSTATUS2				STV090x_Px_TSSTATUS2(1)
+#define STV090x_P2_TSSTATUS2				STV090x_Px_TSSTATUS2(2)
+#define STV090x_OFFST_Px_TSFIFO_DEMODSEL_FIELD		7
+#define STV090x_WIDTH_Px_TSFIFO_DEMODSEL_FIELD		1
+#define STV090x_OFFST_Px_TSFIFOSPEED_STORE_FIELD	6
+#define STV090x_WIDTH_Px_TSFIFOSPEED_STORE_FIELD	1
+#define STV090x_OFFST_Px_DILXX_RESET_FIELD		5
+#define STV090x_WIDTH_Px_DILXX_RESET_FIELD		1
+#define STV090x_OFFST_Px_TSSERIAL_IMPOS_FIELD		4
+#define STV090x_WIDTH_Px_TSSERIAL_IMPOS_FIELD		1
+#define STV090x_OFFST_Px_SCRAMBDETECT_FIELD		1
+#define STV090x_WIDTH_Px_SCRAMBDETECT_FIELD		1
+
+#define STV090x_Px_TSBITRATEy(__x, __y)			(0xF584 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_TSBITRATE0				STV090x_Px_TSBITRATEy(1, 0)
+#define STV090x_P1_TSBITRATE1				STV090x_Px_TSBITRATEy(1, 1)
+#define STV090x_P2_TSBITRATE0				STV090x_Px_TSBITRATEy(2, 0)
+#define STV090x_P2_TSBITRATE1				STV090x_Px_TSBITRATEy(2, 1)
+#define STV090x_OFFST_Px_TSFIFO_BITRATE_FIELD		0
+#define STV090x_WIDTH_Px_TSFIFO_BITRATE_FIELD		8
+
+#define STV090x_Px_ERRCTRL1(__x)			(0xF598 - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCTRL1				STV090x_Px_ERRCTRL1(1)
+#define STV090x_P2_ERRCTRL1				STV090x_Px_ERRCTRL1(2)
+#define STV090x_OFFST_Px_ERR_SOURCE_FIELD		4
+#define STV090x_WIDTH_Px_ERR_SOURCE_FIELD		4
+#define STV090x_OFFST_Px_NUM_EVENT_FIELD		0
+#define STV090x_WIDTH_Px_NUM_EVENT_FIELD		3
+
+#define STV090x_Px_ERRCNT12(__x)			(0xF599 - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT12				STV090x_Px_ERRCNT12(1)
+#define STV090x_P2_ERRCNT12				STV090x_Px_ERRCNT12(2)
+#define STV090x_OFFST_Px_ERRCNT1_OLDVALUE_FIELD		7
+#define STV090x_WIDTH_Px_ERRCNT1_OLDVALUE_FIELD		1
+#define STV090x_OFFST_Px_ERR_CNT12_FIELD		0
+#define STV090x_WIDTH_Px_ERR_CNT12_FIELD		7
+
+#define STV090x_Px_ERRCNT11(__x)			(0xF59A - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT11				STV090x_Px_ERRCNT11(1)
+#define STV090x_P2_ERRCNT11				STV090x_Px_ERRCNT11(2)
+#define STV090x_OFFST_Px_ERR_CNT11_FIELD		0
+#define STV090x_WIDTH_Px_ERR_CNT11_FIELD		8
+
+#define STV090x_Px_ERRCNT10(__x)			(0xF59B - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT10				STV090x_Px_ERRCNT10(1)
+#define STV090x_P2_ERRCNT10				STV090x_Px_ERRCNT10(2)
+#define STV090x_OFFST_Px_ERR_CNT10_FIELD		0
+#define STV090x_WIDTH_Px_ERR_CNT10_FIELD		8
+
+#define STV090x_Px_ERRCTRL2(__x)			(0xF59C - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCTRL2				STV090x_Px_ERRCTRL2(1)
+#define STV090x_P2_ERRCTRL2				STV090x_Px_ERRCTRL2(2)
+#define STV090x_OFFST_Px_ERR_SOURCE2_FIELD		4
+#define STV090x_WIDTH_Px_ERR_SOURCE2_FIELD		4
+#define STV090x_OFFST_Px_NUM_EVENT2_FIELD		0
+#define STV090x_WIDTH_Px_NUM_EVENT2_FIELD		3
+
+#define STV090x_Px_ERRCNT22(__x)			(0xF59D - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT22				STV090x_Px_ERRCNT22(1)
+#define STV090x_P2_ERRCNT22				STV090x_Px_ERRCNT22(2)
+#define STV090x_OFFST_Px_ERRCNT2_OLDVALUE_FIELD		7
+#define STV090x_WIDTH_Px_ERRCNT2_OLDVALUE_FIELD		1
+#define STV090x_OFFST_Px_ERR_CNT2_FIELD			0
+#define STV090x_WIDTH_Px_ERR_CNT2_FIELD			7
+
+#define STV090x_Px_ERRCNT21(__x)			(0xF59E - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT21				STV090x_Px_ERRCNT21(1)
+#define STV090x_P2_ERRCNT21				STV090x_Px_ERRCNT21(2)
+#define STV090x_OFFST_Px_ERR_CNT21_FIELD		0
+#define STV090x_WIDTH_Px_ERR_CNT21_FIELD		8
+
+#define STV090x_Px_ERRCNT20(__x)			(0xF59F - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT20				STV090x_Px_ERRCNT20(1)
+#define STV090x_P2_ERRCNT20				STV090x_Px_ERRCNT20(2)
+#define STV090x_OFFST_Px_ERR_CNT20_FIELD		0
+#define STV090x_WIDTH_Px_ERR_CNT20_FIELD		8
+
+#define STV090x_Px_FECSPY(__x)				(0xF5A0 - (__x - 1) * 0x200)
+#define STV090x_P1_FECSPY				STV090x_Px_FECSPY(1)
+#define STV090x_P2_FECSPY				STV090x_Px_FECSPY(2)
+#define STV090x_OFFST_Px_SPY_ENABLE_FIELD		7
+#define STV090x_WIDTH_Px_SPY_ENABLE_FIELD		1
+#define STV090x_OFFST_Px_BERMETER_DATAMAODE_FIELD	2
+#define STV090x_WIDTH_Px_BERMETER_DATAMAODE_FIELD	2
+
+#define STV090x_Px_FSPYCFG(__x)				(0xF5A1 - (__x - 1) * 0x200)
+#define STV090x_P1_FSPYCFG				STV090x_Px_FSPYCFG(1)
+#define STV090x_P2_FSPYCFG				STV090x_Px_FSPYCFG(2)
+#define STV090x_OFFST_Px_RST_ON_ERROR_FIELD		5
+#define STV090x_WIDTH_Px_RST_ON_ERROR_FIELD		1
+#define STV090x_OFFST_Px_ONE_SHOT_FIELD			4
+#define STV090x_WIDTH_Px_ONE_SHOT_FIELD			1
+#define STV090x_OFFST_Px_I2C_MODE_FIELD			2
+#define STV090x_WIDTH_Px_I2C_MODE_FIELD			2
+
+#define STV090x_Px_FSPYDATA(__x)			(0xF5A2 - (__x - 1) * 0x200)
+#define STV090x_P1_FSPYDATA				STV090x_Px_FSPYDATA(1)
+#define STV090x_P2_FSPYDATA				STV090x_Px_FSPYDATA(2)
+#define STV090x_OFFST_Px_SPY_STUFFING_FIELD		7
+#define STV090x_WIDTH_Px_SPY_STUFFING_FIELD		1
+#define STV090x_OFFST_Px_SPY_CNULLPKT_FIELD		5
+#define STV090x_WIDTH_Px_SPY_CNULLPKT_FIELD		1
+#define STV090x_OFFST_Px_SPY_OUTDATA_MODE_FIELD		0
+#define STV090x_WIDTH_Px_SPY_OUTDATA_MODE_FIELD		5
+
+#define STV090x_Px_FSPYOUT(__x)				(0xF5A3 - (__x - 1) * 0x200)
+#define STV090x_P1_FSPYOUT				STV090x_Px_FSPYOUT(1)
+#define STV090x_P2_FSPYOUT				STV090x_Px_FSPYOUT(2)
+#define STV090x_OFFST_Px_FSPY_DIRECT_FIELD		7
+#define STV090x_WIDTH_Px_FSPY_DIRECT_FIELD		1
+#define STV090x_OFFST_Px_STUFF_MODE_FIELD		0
+#define STV090x_WIDTH_Px_STUFF_MODE_FIELD		3
+
+#define STV090x_Px_FSTATUS(__x)				(0xF5A4 - (__x - 1) * 0x200)
+#define STV090x_P1_FSTATUS				STV090x_Px_FSTATUS(1)
+#define STV090x_P2_FSTATUS				STV090x_Px_FSTATUS(2)
+#define STV090x_OFFST_Px_SPY_ENDSIM_FIELD		7
+#define STV090x_WIDTH_Px_SPY_ENDSIM_FIELD		1
+#define STV090x_OFFST_Px_VALID_SIM_FIELD		6
+#define STV090x_WIDTH_Px_VALID_SIM_FIELD		1
+#define STV090x_OFFST_Px_FOUND_SIGNAL_FIELD		5
+#define STV090x_WIDTH_Px_FOUND_SIGNAL_FIELD		1
+#define STV090x_OFFST_Px_DSS_SYNCBYTE_FIELD		4
+#define STV090x_WIDTH_Px_DSS_SYNCBYTE_FIELD		1
+#define STV090x_OFFST_Px_RESULT_STATE_FIELD		0
+#define STV090x_WIDTH_Px_RESULT_STATE_FIELD		4
+
+#define STV090x_Px_FBERCPT4(__x)			(0xF5A8 - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT4				STV090x_Px_FBERCPT4(1)
+#define STV090x_P2_FBERCPT4				STV090x_Px_FBERCPT4(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD		0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD		8
+
+#define STV090x_Px_FBERCPT3(__x)			(0xF5A9 - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT3				STV090x_Px_FBERCPT3(1)
+#define STV090x_P2_FBERCPT3				STV090x_Px_FBERCPT3(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD		0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD		8
+
+#define STV090x_Px_FBERCPT2(__x)			(0xF5AA - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT2				STV090x_Px_FBERCPT2(1)
+#define STV090x_P2_FBERCPT2				STV090x_Px_FBERCPT2(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD		0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD		8
+
+#define STV090x_Px_FBERCPT1(__x)			(0xF5AB - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT1				STV090x_Px_FBERCPT1(1)
+#define STV090x_P2_FBERCPT1				STV090x_Px_FBERCPT1(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD		0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD		8
+
+#define STV090x_Px_FBERCPT0(__x)			(0xF5AC - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT0				STV090x_Px_FBERCPT0(1)
+#define STV090x_P2_FBERCPT0				STV090x_Px_FBERCPT0(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD		0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD		8
+
+#define STV090x_Px_FBERERRy(__x, __y)			(0xF5AF - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_FBERERR0				STV090x_Px_FBERERRy(1, 0)
+#define STV090x_P1_FBERERR1				STV090x_Px_FBERERRy(1, 1)
+#define STV090x_P1_FBERERR2				STV090x_Px_FBERERRy(1, 2)
+#define STV090x_P2_FBERERR0				STV090x_Px_FBERERRy(2, 0)
+#define STV090x_P2_FBERERR1				STV090x_Px_FBERERRy(2, 1)
+#define STV090x_P2_FBERERR2				STV090x_Px_FBERERRy(2, 2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_ERR_FIELD	0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_ERR_FIELD	8
+
+#define STV090x_Px_FSPYBER(__x)				(0xF5B2 - (__x - 1) * 0x200)
+#define STV090x_P1_FSPYBER				STV090x_Px_FSPYBER(1)
+#define STV090x_P2_FSPYBER				STV090x_Px_FSPYBER(2)
+#define STV090x_OFFST_Px_FSPYBER_SYNCBYTE_FIELD		4
+#define STV090x_WIDTH_Px_FSPYBER_SYNCBYTE_FIELD		1
+#define STV090x_OFFST_Px_FSPYBER_UNSYNC_FIELD		3
+#define STV090x_WIDTH_Px_FSPYBER_UNSYNC_FIELD		1
+#define STV090x_OFFST_Px_FSPYBER_CTIME_FIELD		0
+#define STV090x_WIDTH_Px_FSPYBER_CTIME_FIELD		3
+
+#define STV090x_RCCFGH					0xf600
+
+#define STV090x_TSGENERAL				0xF630
+#define STV090x_OFFST_Px_MUXSTREAM_OUT_FIELD		3
+#define STV090x_WIDTH_Px_MUXSTREAM_OUT_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_PERMPARAL_FIELD		1
+#define STV090x_WIDTH_Px_TSFIFO_PERMPARAL_FIELD		2
+
+#define STV090x_TSGENERAL1X				0xf670
+#define STV090x_CFGEXT					0xfa80
+
+#define STV090x_TSTRES0					0xFF11
+#define STV090x_OFFST_FRESFEC_FIELD			7
+#define STV090x_WIDTH_FRESFEC_FIELD			1
+
+#define STV090x_Px_TSTDISRX(__x)			(0xFF67 - (__x - 1) * 0x2)
+#define STV090x_P1_TSTDISRX				STV090x_Px_TSTDISRX(1)
+#define STV090x_P2_TSTDISRX				STV090x_Px_TSTDISRX(2)
+#define STV090x_OFFST_Px_TSTDISRX_SELECT_FIELD		3
+#define STV090x_WIDTH_Px_TSTDISRX_SELECT_FIELD		1
+
+#endif /* __STV090x_REG_H */
diff --git a/drivers/media/dvb-frontends/stv6110.c b/drivers/media/dvb-frontends/stv6110.c
new file mode 100644
index 0000000..20b5fa9
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv6110.c
@@ -0,0 +1,451 @@
+/*
+ * stv6110.c
+ *
+ * Driver for ST STV6110 satellite tuner IC.
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+
+#include <linux/types.h>
+
+#include "stv6110.h"
+
+static int debug;
+
+struct stv6110_priv {
+	int i2c_address;
+	struct i2c_adapter *i2c;
+
+	u32 mclk;
+	u8 clk_div;
+	u8 gain;
+	u8 regs[8];
+};
+
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG args); \
+	} while (0)
+
+static s32 abssub(s32 a, s32 b)
+{
+	if (a > b)
+		return a - b;
+	else
+		return b - a;
+};
+
+static int stv6110_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int stv6110_write_regs(struct dvb_frontend *fe, u8 buf[],
+							int start, int len)
+{
+	struct stv6110_priv *priv = fe->tuner_priv;
+	int rc;
+	u8 cmdbuf[len + 1];
+	struct i2c_msg msg = {
+		.addr	= priv->i2c_address,
+		.flags	= 0,
+		.buf	= cmdbuf,
+		.len	= len + 1
+	};
+
+	dprintk("%s\n", __func__);
+
+	if (start + len > 8)
+		return -EINVAL;
+
+	memcpy(&cmdbuf[1], buf, len);
+	cmdbuf[0] = start;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	rc = i2c_transfer(priv->i2c, &msg, 1);
+	if (rc != 1)
+		dprintk("%s: i2c error\n", __func__);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return 0;
+}
+
+static int stv6110_read_regs(struct dvb_frontend *fe, u8 regs[],
+							int start, int len)
+{
+	struct stv6110_priv *priv = fe->tuner_priv;
+	int rc;
+	u8 reg[] = { start };
+	struct i2c_msg msg[] = {
+		{
+			.addr	= priv->i2c_address,
+			.flags	= 0,
+			.buf	= reg,
+			.len	= 1,
+		}, {
+			.addr	= priv->i2c_address,
+			.flags	= I2C_M_RD,
+			.buf	= regs,
+			.len	= len,
+		},
+	};
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	rc = i2c_transfer(priv->i2c, msg, 2);
+	if (rc != 2)
+		dprintk("%s: i2c error\n", __func__);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	memcpy(&priv->regs[start], regs, len);
+
+	return 0;
+}
+
+static int stv6110_read_reg(struct dvb_frontend *fe, int start)
+{
+	u8 buf[] = { 0 };
+	stv6110_read_regs(fe, buf, start, 1);
+
+	return buf[0];
+}
+
+static int stv6110_sleep(struct dvb_frontend *fe)
+{
+	u8 reg[] = { 0 };
+	stv6110_write_regs(fe, reg, 0, 1);
+
+	return 0;
+}
+
+static u32 carrier_width(u32 symbol_rate, fe_rolloff_t rolloff)
+{
+	u32 rlf;
+
+	switch (rolloff) {
+	case ROLLOFF_20:
+		rlf = 20;
+		break;
+	case ROLLOFF_25:
+		rlf = 25;
+		break;
+	default:
+		rlf = 35;
+		break;
+	}
+
+	return symbol_rate  + ((symbol_rate * rlf) / 100);
+}
+
+static int stv6110_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
+{
+	struct stv6110_priv *priv = fe->tuner_priv;
+	u8 r8, ret = 0x04;
+	int i;
+
+	if ((bandwidth / 2) > 36000000) /*BW/2 max=31+5=36 mhz for r8=31*/
+		r8 = 31;
+	else if ((bandwidth / 2) < 5000000) /* BW/2 min=5Mhz for F=0 */
+		r8 = 0;
+	else /*if 5 < BW/2 < 36*/
+		r8 = (bandwidth / 2) / 1000000 - 5;
+
+	/* ctrl3, RCCLKOFF = 0 Activate the calibration Clock */
+	/* ctrl3, CF = r8 Set the LPF value */
+	priv->regs[RSTV6110_CTRL3] &= ~((1 << 6) | 0x1f);
+	priv->regs[RSTV6110_CTRL3] |= (r8 & 0x1f);
+	stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL3], RSTV6110_CTRL3, 1);
+	/* stat1, CALRCSTRT = 1 Start LPF auto calibration*/
+	priv->regs[RSTV6110_STAT1] |= 0x02;
+	stv6110_write_regs(fe, &priv->regs[RSTV6110_STAT1], RSTV6110_STAT1, 1);
+
+	i = 0;
+	/* Wait for CALRCSTRT == 0 */
+	while ((i < 10) && (ret != 0)) {
+		ret = ((stv6110_read_reg(fe, RSTV6110_STAT1)) & 0x02);
+		mdelay(1);	/* wait for LPF auto calibration */
+		i++;
+	}
+
+	/* RCCLKOFF = 1 calibration done, desactivate the calibration Clock */
+	priv->regs[RSTV6110_CTRL3] |= (1 << 6);
+	stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL3], RSTV6110_CTRL3, 1);
+	return 0;
+}
+
+static int stv6110_init(struct dvb_frontend *fe)
+{
+	struct stv6110_priv *priv = fe->tuner_priv;
+	u8 buf0[] = { 0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e };
+
+	memcpy(priv->regs, buf0, 8);
+	/* K = (Reference / 1000000) - 16 */
+	priv->regs[RSTV6110_CTRL1] &= ~(0x1f << 3);
+	priv->regs[RSTV6110_CTRL1] |=
+				((((priv->mclk / 1000000) - 16) & 0x1f) << 3);
+
+	/* divisor value for the output clock */
+	priv->regs[RSTV6110_CTRL2] &= ~0xc0;
+	priv->regs[RSTV6110_CTRL2] |= (priv->clk_div << 6);
+
+	stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL1], RSTV6110_CTRL1, 8);
+	msleep(1);
+	stv6110_set_bandwidth(fe, 72000000);
+
+	return 0;
+}
+
+static int stv6110_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct stv6110_priv *priv = fe->tuner_priv;
+	u32 nbsteps, divider, psd2, freq;
+	u8 regs[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+	stv6110_read_regs(fe, regs, 0, 8);
+	/*N*/
+	divider = (priv->regs[RSTV6110_TUNING2] & 0x0f) << 8;
+	divider += priv->regs[RSTV6110_TUNING1];
+
+	/*R*/
+	nbsteps  = (priv->regs[RSTV6110_TUNING2] >> 6) & 3;
+	/*p*/
+	psd2  = (priv->regs[RSTV6110_TUNING2] >> 4) & 1;
+
+	freq = divider * (priv->mclk / 1000);
+	freq /= (1 << (nbsteps + psd2));
+	freq /= 4;
+
+	*frequency = freq;
+
+	return 0;
+}
+
+static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency)
+{
+	struct stv6110_priv *priv = fe->tuner_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u8 ret = 0x04;
+	u32 divider, ref, p, presc, i, result_freq, vco_freq;
+	s32 p_calc, p_calc_opt = 1000, r_div, r_div_opt = 0, p_val;
+	s32 srate;
+
+	dprintk("%s, freq=%d kHz, mclk=%d Hz\n", __func__,
+						frequency, priv->mclk);
+
+	/* K = (Reference / 1000000) - 16 */
+	priv->regs[RSTV6110_CTRL1] &= ~(0x1f << 3);
+	priv->regs[RSTV6110_CTRL1] |=
+				((((priv->mclk / 1000000) - 16) & 0x1f) << 3);
+
+	/* BB_GAIN = db/2 */
+	if (fe->ops.set_property && fe->ops.get_property) {
+		srate = c->symbol_rate;
+		dprintk("%s: Get Frontend parameters: srate=%d\n",
+							__func__, srate);
+	} else
+		srate = 15000000;
+
+	priv->regs[RSTV6110_CTRL2] &= ~0x0f;
+	priv->regs[RSTV6110_CTRL2] |= (priv->gain & 0x0f);
+
+	if (frequency <= 1023000) {
+		p = 1;
+		presc = 0;
+	} else if (frequency <= 1300000) {
+		p = 1;
+		presc = 1;
+	} else if (frequency <= 2046000) {
+		p = 0;
+		presc = 0;
+	} else {
+		p = 0;
+		presc = 1;
+	}
+	/* DIV4SEL = p*/
+	priv->regs[RSTV6110_TUNING2] &= ~(1 << 4);
+	priv->regs[RSTV6110_TUNING2] |= (p << 4);
+
+	/* PRESC32ON = presc */
+	priv->regs[RSTV6110_TUNING2] &= ~(1 << 5);
+	priv->regs[RSTV6110_TUNING2] |= (presc << 5);
+
+	p_val = (int)(1 << (p + 1)) * 10;/* P = 2 or P = 4 */
+	for (r_div = 0; r_div <= 3; r_div++) {
+		p_calc = (priv->mclk / 100000);
+		p_calc /= (1 << (r_div + 1));
+		if ((abssub(p_calc, p_val)) < (abssub(p_calc_opt, p_val)))
+			r_div_opt = r_div;
+
+		p_calc_opt = (priv->mclk / 100000);
+		p_calc_opt /= (1 << (r_div_opt + 1));
+	}
+
+	ref = priv->mclk / ((1 << (r_div_opt + 1))  * (1 << (p + 1)));
+	divider = (((frequency * 1000) + (ref >> 1)) / ref);
+
+	/* RDIV = r_div_opt */
+	priv->regs[RSTV6110_TUNING2] &= ~(3 << 6);
+	priv->regs[RSTV6110_TUNING2] |= (((r_div_opt) & 3) << 6);
+
+	/* NDIV_MSB = MSB(divider) */
+	priv->regs[RSTV6110_TUNING2] &= ~0x0f;
+	priv->regs[RSTV6110_TUNING2] |= (((divider) >> 8) & 0x0f);
+
+	/* NDIV_LSB, LSB(divider) */
+	priv->regs[RSTV6110_TUNING1] = (divider & 0xff);
+
+	/* CALVCOSTRT = 1 VCO Auto Calibration */
+	priv->regs[RSTV6110_STAT1] |= 0x04;
+	stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL1],
+						RSTV6110_CTRL1, 8);
+
+	i = 0;
+	/* Wait for CALVCOSTRT == 0 */
+	while ((i < 10) && (ret != 0)) {
+		ret = ((stv6110_read_reg(fe, RSTV6110_STAT1)) & 0x04);
+		msleep(1); /* wait for VCO auto calibration */
+		i++;
+	}
+
+	ret = stv6110_read_reg(fe, RSTV6110_STAT1);
+	stv6110_get_frequency(fe, &result_freq);
+
+	vco_freq = divider * ((priv->mclk / 1000) / ((1 << (r_div_opt + 1))));
+	dprintk("%s, stat1=%x, lo_freq=%d kHz, vco_frec=%d kHz\n", __func__,
+						ret, result_freq, vco_freq);
+
+	return 0;
+}
+
+static int stv6110_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 bandwidth = carrier_width(c->symbol_rate, c->rolloff);
+
+	stv6110_set_frequency(fe, c->frequency);
+	stv6110_set_bandwidth(fe, bandwidth);
+
+	return 0;
+}
+
+static int stv6110_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct stv6110_priv *priv = fe->tuner_priv;
+	u8 r8 = 0;
+	u8 regs[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+	stv6110_read_regs(fe, regs, 0, 8);
+
+	/* CF */
+	r8 = priv->regs[RSTV6110_CTRL3] & 0x1f;
+	*bandwidth = (r8 + 5) * 2000000;/* x2 for ZIF tuner BW/2 = F+5 Mhz */
+
+	return 0;
+}
+
+static struct dvb_tuner_ops stv6110_tuner_ops = {
+	.info = {
+		.name = "ST STV6110",
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		.frequency_step = 1000,
+	},
+	.init = stv6110_init,
+	.release = stv6110_release,
+	.sleep = stv6110_sleep,
+	.set_params = stv6110_set_params,
+	.get_frequency = stv6110_get_frequency,
+	.set_frequency = stv6110_set_frequency,
+	.get_bandwidth = stv6110_get_bandwidth,
+	.set_bandwidth = stv6110_set_bandwidth,
+
+};
+
+struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
+					const struct stv6110_config *config,
+					struct i2c_adapter *i2c)
+{
+	struct stv6110_priv *priv = NULL;
+	u8 reg0[] = { 0x00, 0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e };
+
+	struct i2c_msg msg[] = {
+		{
+			.addr = config->i2c_address,
+			.flags = 0,
+			.buf = reg0,
+			.len = 9
+		}
+	};
+	int ret;
+
+	/* divisor value for the output clock */
+	reg0[2] &= ~0xc0;
+	reg0[2] |= (config->clk_div << 6);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	ret = i2c_transfer(i2c, msg, 1);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	if (ret != 1)
+		return NULL;
+
+	priv = kzalloc(sizeof(struct stv6110_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->i2c_address = config->i2c_address;
+	priv->i2c = i2c;
+	priv->mclk = config->mclk;
+	priv->clk_div = config->clk_div;
+	priv->gain = config->gain;
+
+	memcpy(&priv->regs, &reg0[1], 8);
+
+	memcpy(&fe->ops.tuner_ops, &stv6110_tuner_ops,
+				sizeof(struct dvb_tuner_ops));
+	fe->tuner_priv = priv;
+	printk(KERN_INFO "STV6110 attached on addr=%x!\n", priv->i2c_address);
+
+	return fe;
+}
+EXPORT_SYMBOL(stv6110_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("ST STV6110 driver");
+MODULE_AUTHOR("Igor M. Liplianin");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/stv6110.h b/drivers/media/dvb-frontends/stv6110.h
new file mode 100644
index 0000000..fe71bba
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv6110.h
@@ -0,0 +1,63 @@
+/*
+ * stv6110.h
+ *
+ * Driver for ST STV6110 satellite tuner IC.
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __DVB_STV6110_H__
+#define __DVB_STV6110_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/* registers */
+#define RSTV6110_CTRL1		0
+#define RSTV6110_CTRL2		1
+#define RSTV6110_TUNING1	2
+#define RSTV6110_TUNING2	3
+#define RSTV6110_CTRL3		4
+#define RSTV6110_STAT1		5
+#define RSTV6110_STAT2		6
+#define RSTV6110_STAT3		7
+
+struct stv6110_config {
+	u8 i2c_address;
+	u32 mclk;
+	u8 gain;
+	u8 clk_div;	/* divisor value for the output clock */
+};
+
+#if defined(CONFIG_DVB_STV6110) || (defined(CONFIG_DVB_STV6110_MODULE) \
+							&& defined(MODULE))
+extern struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
+					const struct stv6110_config *config,
+					struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
+					const struct stv6110_config *config,
+					struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb-frontends/stv6110x.c b/drivers/media/dvb-frontends/stv6110x.c
new file mode 100644
index 0000000..f36cab1
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv6110x.c
@@ -0,0 +1,405 @@
+/*
+	STV6110(A) Silicon tuner driver
+
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "dvb_frontend.h"
+
+#include "stv6110x_reg.h"
+#include "stv6110x.h"
+#include "stv6110x_priv.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "Set Verbosity level");
+
+static int stv6110x_read_reg(struct stv6110x_state *stv6110x, u8 reg, u8 *data)
+{
+	int ret;
+	const struct stv6110x_config *config = stv6110x->config;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{ .addr = config->addr, .flags = 0, 	   .buf = b0, .len = 1 },
+		{ .addr = config->addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+	};
+
+	ret = i2c_transfer(stv6110x->i2c, msg, 2);
+	if (ret != 2) {
+		dprintk(FE_ERROR, 1, "I/O Error");
+		return -EREMOTEIO;
+	}
+	*data = b1[0];
+
+	return 0;
+}
+
+static int stv6110x_write_regs(struct stv6110x_state *stv6110x, int start, u8 data[], int len)
+{
+	int ret;
+	const struct stv6110x_config *config = stv6110x->config;
+	u8 buf[len + 1];
+	struct i2c_msg msg = {
+		.addr = config->addr,
+		.flags = 0,
+		.buf = buf,
+		.len = len + 1
+	};
+
+	if (start + len > 8)
+		return -EINVAL;
+
+	buf[0] = start;
+	memcpy(&buf[1], data, len);
+
+	ret = i2c_transfer(stv6110x->i2c, &msg, 1);
+	if (ret != 1) {
+		dprintk(FE_ERROR, 1, "I/O Error");
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
+{
+	return stv6110x_write_regs(stv6110x, reg, &data, 1);
+}
+
+static int stv6110x_init(struct dvb_frontend *fe)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+	int ret;
+
+	ret = stv6110x_write_regs(stv6110x, 0, stv6110x->regs,
+				  ARRAY_SIZE(stv6110x->regs));
+	if (ret < 0) {
+		dprintk(FE_ERROR, 1, "Initialization failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+	u32 rDiv, divider;
+	s32 pVal, pCalc, rDivOpt = 0, pCalcOpt = 1000;
+	u8 i;
+
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_K, (REFCLOCK_MHz - 16));
+
+	if (frequency <= 1023000) {
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
+		pVal = 40;
+	} else if (frequency <= 1300000) {
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
+		pVal = 40;
+	} else if (frequency <= 2046000) {
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
+		pVal = 20;
+	} else {
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
+		pVal = 20;
+	}
+
+	for (rDiv = 0; rDiv <= 3; rDiv++) {
+		pCalc = (REFCLOCK_kHz / 100) / R_DIV(rDiv);
+
+		if ((abs((s32)(pCalc - pVal))) < (abs((s32)(pCalcOpt - pVal))))
+			rDivOpt = rDiv;
+
+		pCalcOpt = (REFCLOCK_kHz / 100) / R_DIV(rDivOpt);
+	}
+
+	divider = (frequency * R_DIV(rDivOpt) * pVal) / REFCLOCK_kHz;
+	divider = (divider + 5) / 10;
+
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_R_DIV, rDivOpt);
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_N_DIV_11_8, MSB(divider));
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG0], TNG0_N_DIV_7_0, LSB(divider));
+
+	/* VCO Auto calibration */
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_STAT1], STAT1_CALVCO_STRT, 1);
+
+	stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x->regs[STV6110x_CTRL1]);
+	stv6110x_write_reg(stv6110x, STV6110x_TNG1, stv6110x->regs[STV6110x_TNG1]);
+	stv6110x_write_reg(stv6110x, STV6110x_TNG0, stv6110x->regs[STV6110x_TNG0]);
+	stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x->regs[STV6110x_STAT1]);
+
+	for (i = 0; i < TRIALS; i++) {
+		stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]);
+		if (!STV6110x_GETFIELD(STAT1_CALVCO_STRT, stv6110x->regs[STV6110x_STAT1]))
+				break;
+		msleep(1);
+	}
+
+	return 0;
+}
+
+static int stv6110x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+	stv6110x_read_reg(stv6110x, STV6110x_TNG1, &stv6110x->regs[STV6110x_TNG1]);
+	stv6110x_read_reg(stv6110x, STV6110x_TNG0, &stv6110x->regs[STV6110x_TNG0]);
+
+	*frequency = (MAKEWORD16(STV6110x_GETFIELD(TNG1_N_DIV_11_8, stv6110x->regs[STV6110x_TNG1]),
+				 STV6110x_GETFIELD(TNG0_N_DIV_7_0, stv6110x->regs[STV6110x_TNG0]))) * REFCLOCK_kHz;
+
+	*frequency /= (1 << (STV6110x_GETFIELD(TNG1_R_DIV, stv6110x->regs[STV6110x_TNG1]) +
+			     STV6110x_GETFIELD(TNG1_DIV4SEL, stv6110x->regs[STV6110x_TNG1])));
+
+	*frequency >>= 2;
+
+	return 0;
+}
+
+static int stv6110x_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+	u32 halfbw;
+	u8 i;
+
+	halfbw = bandwidth >> 1;
+
+	if (halfbw > 36000000)
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, 31); /* LPF */
+	else if (halfbw < 5000000)
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, 0); /* LPF */
+	else
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, ((halfbw / 1000000) - 5)); /* LPF */
+
+
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x0); /* cal. clk activated */
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_STAT1], STAT1_CALRC_STRT, 0x1); /* LPF auto cal */
+
+	stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x->regs[STV6110x_CTRL3]);
+	stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x->regs[STV6110x_STAT1]);
+
+	for (i = 0; i < TRIALS; i++) {
+		stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]);
+		if (!STV6110x_GETFIELD(STAT1_CALRC_STRT, stv6110x->regs[STV6110x_STAT1]))
+			break;
+		msleep(1);
+	}
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x1); /* cal. done */
+	stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x->regs[STV6110x_CTRL3]);
+
+	return 0;
+}
+
+static int stv6110x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+	stv6110x_read_reg(stv6110x, STV6110x_CTRL3, &stv6110x->regs[STV6110x_CTRL3]);
+	*bandwidth = (STV6110x_GETFIELD(CTRL3_CF, stv6110x->regs[STV6110x_CTRL3]) + 5) * 2000000;
+
+	return 0;
+}
+
+static int stv6110x_set_refclock(struct dvb_frontend *fe, u32 refclock)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+	/* setup divider */
+	switch (refclock) {
+	default:
+	case 1:
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
+		break;
+	case 2:
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
+		break;
+	case 4:
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
+		break;
+	case 8:
+	case 0:
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
+		break;
+	}
+	stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x->regs[STV6110x_CTRL2]);
+
+	return 0;
+}
+
+static int stv6110x_get_bbgain(struct dvb_frontend *fe, u32 *gain)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+	stv6110x_read_reg(stv6110x, STV6110x_CTRL2, &stv6110x->regs[STV6110x_CTRL2]);
+	*gain = 2 * STV6110x_GETFIELD(CTRL2_BBGAIN, stv6110x->regs[STV6110x_CTRL2]);
+
+	return 0;
+}
+
+static int stv6110x_set_bbgain(struct dvb_frontend *fe, u32 gain)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_BBGAIN, gain / 2);
+	stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x->regs[STV6110x_CTRL2]);
+
+	return 0;
+}
+
+static int stv6110x_set_mode(struct dvb_frontend *fe, enum tuner_mode mode)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+	int ret;
+
+	switch (mode) {
+	case TUNER_SLEEP:
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_SYN, 0);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_RX, 0);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_LPT, 0);
+		break;
+
+	case TUNER_WAKE:
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_SYN, 1);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_RX, 1);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_LPT, 1);
+		break;
+	}
+
+	ret = stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x->regs[STV6110x_CTRL1]);
+	if (ret < 0) {
+		dprintk(FE_ERROR, 1, "I/O Error");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int stv6110x_sleep(struct dvb_frontend *fe)
+{
+	if (fe->tuner_priv)
+		return stv6110x_set_mode(fe, TUNER_SLEEP);
+
+	return 0;
+}
+
+static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+	stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]);
+
+	if (STV6110x_GETFIELD(STAT1_LOCK, stv6110x->regs[STV6110x_STAT1]))
+		*status = TUNER_PHASELOCKED;
+	else
+		*status = 0;
+
+	return 0;
+}
+
+
+static int stv6110x_release(struct dvb_frontend *fe)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+	fe->tuner_priv = NULL;
+	kfree(stv6110x);
+
+	return 0;
+}
+
+static struct dvb_tuner_ops stv6110x_ops = {
+	.info = {
+		.name		= "STV6110(A) Silicon Tuner",
+		.frequency_min	=  950000,
+		.frequency_max	= 2150000,
+		.frequency_step	= 0,
+	},
+	.release		= stv6110x_release
+};
+
+static struct stv6110x_devctl stv6110x_ctl = {
+	.tuner_init		= stv6110x_init,
+	.tuner_sleep		= stv6110x_sleep,
+	.tuner_set_mode		= stv6110x_set_mode,
+	.tuner_set_frequency	= stv6110x_set_frequency,
+	.tuner_get_frequency	= stv6110x_get_frequency,
+	.tuner_set_bandwidth	= stv6110x_set_bandwidth,
+	.tuner_get_bandwidth	= stv6110x_get_bandwidth,
+	.tuner_set_bbgain	= stv6110x_set_bbgain,
+	.tuner_get_bbgain	= stv6110x_get_bbgain,
+	.tuner_set_refclk	= stv6110x_set_refclock,
+	.tuner_get_status	= stv6110x_get_status,
+};
+
+struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
+					const struct stv6110x_config *config,
+					struct i2c_adapter *i2c)
+{
+	struct stv6110x_state *stv6110x;
+	u8 default_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e};
+
+	stv6110x = kzalloc(sizeof (struct stv6110x_state), GFP_KERNEL);
+	if (!stv6110x)
+		return NULL;
+
+	stv6110x->i2c		= i2c;
+	stv6110x->config	= config;
+	stv6110x->devctl	= &stv6110x_ctl;
+	memcpy(stv6110x->regs, default_regs, 8);
+
+	/* setup divider */
+	switch (stv6110x->config->clk_div) {
+	default:
+	case 1:
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
+		break;
+	case 2:
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
+		break;
+	case 4:
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
+		break;
+	case 8:
+	case 0:
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
+		break;
+	}
+
+	fe->tuner_priv		= stv6110x;
+	fe->ops.tuner_ops	= stv6110x_ops;
+
+	printk(KERN_INFO "%s: Attaching STV6110x\n", __func__);
+	return stv6110x->devctl;
+}
+EXPORT_SYMBOL(stv6110x_attach);
+
+MODULE_AUTHOR("Manu Abraham");
+MODULE_DESCRIPTION("STV6110x Silicon tuner");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/stv6110x.h b/drivers/media/dvb-frontends/stv6110x.h
new file mode 100644
index 0000000..47516753
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv6110x.h
@@ -0,0 +1,73 @@
+/*
+	STV6110(A) Silicon tuner driver
+
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __STV6110x_H
+#define __STV6110x_H
+
+struct stv6110x_config {
+	u8	addr;
+	u32	refclk;
+	u8	clk_div; /* divisor value for the output clock */
+};
+
+enum tuner_mode {
+	TUNER_SLEEP = 1,
+	TUNER_WAKE,
+};
+
+enum tuner_status {
+	TUNER_PHASELOCKED = 1,
+};
+
+struct stv6110x_devctl {
+	int (*tuner_init) (struct dvb_frontend *fe);
+	int (*tuner_sleep) (struct dvb_frontend *fe);
+	int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode);
+	int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency);
+	int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency);
+	int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth);
+	int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth);
+	int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain);
+	int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain);
+	int (*tuner_set_refclk)  (struct dvb_frontend *fe, u32 refclk);
+	int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status);
+};
+
+
+#if defined(CONFIG_DVB_STV6110x) || (defined(CONFIG_DVB_STV6110x_MODULE) && defined(MODULE))
+
+extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
+					       const struct stv6110x_config *config,
+					       struct i2c_adapter *i2c);
+
+#else
+static inline struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
+						      const struct stv6110x_config *config,
+						      struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+#endif /* CONFIG_DVB_STV6110x */
+
+#endif /* __STV6110x_H */
diff --git a/drivers/media/dvb-frontends/stv6110x_priv.h b/drivers/media/dvb-frontends/stv6110x_priv.h
new file mode 100644
index 0000000..0ec936a
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv6110x_priv.h
@@ -0,0 +1,76 @@
+/*
+	STV6110(A) Silicon tuner driver
+
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __STV6110x_PRIV_H
+#define __STV6110x_PRIV_H
+
+#define FE_ERROR				0
+#define FE_NOTICE				1
+#define FE_INFO					2
+#define FE_DEBUG				3
+#define FE_DEBUGREG				4
+
+#define dprintk(__y, __z, format, arg...) do {						\
+	if (__z) {									\
+		if	((verbose > FE_ERROR) && (verbose > __y))			\
+			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);		\
+		else if	((verbose > FE_NOTICE) && (verbose > __y))			\
+			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
+		else if ((verbose > FE_INFO) && (verbose > __y))			\
+			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);		\
+		else if ((verbose > FE_DEBUG) && (verbose > __y))			\
+			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
+	} else {									\
+		if (verbose > __y)							\
+			printk(format, ##arg);						\
+	}										\
+} while (0)
+
+
+#define STV6110x_SETFIELD(mask, bitf, val)				\
+	(mask = (mask & (~(((1 << STV6110x_WIDTH_##bitf) - 1) <<	\
+				  STV6110x_OFFST_##bitf))) | 		\
+			  (val << STV6110x_OFFST_##bitf))
+
+#define STV6110x_GETFIELD(bitf, val)					\
+	((val >> STV6110x_OFFST_##bitf) & 				\
+	((1 << STV6110x_WIDTH_##bitf) - 1))
+
+#define MAKEWORD16(a, b)			(((a) << 8) | (b))
+
+#define LSB(x)					((x & 0xff))
+#define MSB(y)					((y >> 8) & 0xff)
+
+#define TRIALS					10
+#define R_DIV(__div)				(1 << (__div + 1))
+#define REFCLOCK_kHz				(stv6110x->config->refclk /    1000)
+#define REFCLOCK_MHz				(stv6110x->config->refclk / 1000000)
+
+struct stv6110x_state {
+	struct i2c_adapter		*i2c;
+	const struct stv6110x_config	*config;
+	u8 				regs[8];
+
+	struct stv6110x_devctl		*devctl;
+};
+
+#endif /* __STV6110x_PRIV_H */
diff --git a/drivers/media/dvb-frontends/stv6110x_reg.h b/drivers/media/dvb-frontends/stv6110x_reg.h
new file mode 100644
index 0000000..93e5c70
--- /dev/null
+++ b/drivers/media/dvb-frontends/stv6110x_reg.h
@@ -0,0 +1,82 @@
+/*
+	STV6110(A) Silicon tuner driver
+
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __STV6110x_REG_H
+#define __STV6110x_REG_H
+
+#define STV6110x_CTRL1				0x00
+#define STV6110x_OFFST_CTRL1_K			3
+#define STV6110x_WIDTH_CTRL1_K			5
+#define STV6110x_OFFST_CTRL1_LPT		2
+#define STV6110x_WIDTH_CTRL1_LPT		1
+#define STV6110x_OFFST_CTRL1_RX			1
+#define STV6110x_WIDTH_CTRL1_RX			1
+#define STV6110x_OFFST_CTRL1_SYN		0
+#define STV6110x_WIDTH_CTRL1_SYN		1
+
+#define STV6110x_CTRL2				0x01
+#define STV6110x_OFFST_CTRL2_CO_DIV		6
+#define STV6110x_WIDTH_CTRL2_CO_DIV		2
+#define STV6110x_OFFST_CTRL2_RSVD		5
+#define STV6110x_WIDTH_CTRL2_RSVD		1
+#define STV6110x_OFFST_CTRL2_REFOUT_SEL		4
+#define STV6110x_WIDTH_CTRL2_REFOUT_SEL		1
+#define STV6110x_OFFST_CTRL2_BBGAIN		0
+#define STV6110x_WIDTH_CTRL2_BBGAIN		4
+
+#define STV6110x_TNG0				0x02
+#define STV6110x_OFFST_TNG0_N_DIV_7_0		0
+#define STV6110x_WIDTH_TNG0_N_DIV_7_0		8
+
+#define STV6110x_TNG1				0x03
+#define STV6110x_OFFST_TNG1_R_DIV		6
+#define STV6110x_WIDTH_TNG1_R_DIV		2
+#define STV6110x_OFFST_TNG1_PRESC32_ON		5
+#define STV6110x_WIDTH_TNG1_PRESC32_ON		1
+#define STV6110x_OFFST_TNG1_DIV4SEL		4
+#define STV6110x_WIDTH_TNG1_DIV4SEL		1
+#define STV6110x_OFFST_TNG1_N_DIV_11_8		0
+#define STV6110x_WIDTH_TNG1_N_DIV_11_8		4
+
+
+#define STV6110x_CTRL3				0x04
+#define STV6110x_OFFST_CTRL3_DCLOOP_OFF		7
+#define STV6110x_WIDTH_CTRL3_DCLOOP_OFF		1
+#define STV6110x_OFFST_CTRL3_RCCLK_OFF		6
+#define STV6110x_WIDTH_CTRL3_RCCLK_OFF		1
+#define STV6110x_OFFST_CTRL3_ICP		5
+#define STV6110x_WIDTH_CTRL3_ICP		1
+#define STV6110x_OFFST_CTRL3_CF			0
+#define STV6110x_WIDTH_CTRL3_CF			5
+
+#define STV6110x_STAT1				0x05
+#define STV6110x_OFFST_STAT1_CALVCO_STRT	2
+#define STV6110x_WIDTH_STAT1_CALVCO_STRT	1
+#define STV6110x_OFFST_STAT1_CALRC_STRT		1
+#define STV6110x_WIDTH_STAT1_CALRC_STRT		1
+#define STV6110x_OFFST_STAT1_LOCK		0
+#define STV6110x_WIDTH_STAT1_LOCK		1
+
+#define STV6110x_STAT2				0x06
+#define STV6110x_STAT3				0x07
+
+#endif /* __STV6110x_REG_H */
diff --git a/drivers/media/dvb-frontends/tda10021.c b/drivers/media/dvb-frontends/tda10021.c
new file mode 100644
index 0000000..1bff7f4
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda10021.c
@@ -0,0 +1,528 @@
+/*
+    TDA10021  - Single Chip Cable Channel Receiver driver module
+	       used on the Siemens DVB-C cards
+
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+    Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
+		   Support for TDA10021
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "tda1002x.h"
+
+
+struct tda10021_state {
+	struct i2c_adapter* i2c;
+	/* configuration settings */
+	const struct tda1002x_config* config;
+	struct dvb_frontend frontend;
+
+	u8 pwm;
+	u8 reg0;
+};
+
+
+#if 0
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+static int verbose;
+
+#define XIN 57840000UL
+
+#define FIN (XIN >> 4)
+
+static int tda10021_inittab_size = 0x40;
+static u8 tda10021_inittab[0x40]=
+{
+	0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a,
+	0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40,
+	0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff,
+	0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00,
+	0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00,
+	0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58,
+	0x00, 0x00, 0x80, 0x00, 0x80, 0xff, 0x00, 0x00,
+	0x04, 0x2d, 0x2f, 0xff, 0x00, 0x00, 0x00, 0x00,
+};
+
+static int _tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+	int ret;
+
+	ret = i2c_transfer (state->i2c, &msg, 1);
+	if (ret != 1)
+		printk("DVB: TDA10021(%d): %s, writereg error "
+			"(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
+			state->frontend.dvb->num, __func__, reg, data, ret);
+
+	msleep(10);
+	return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
+{
+	u8 b0 [] = { reg };
+	u8 b1 [] = { 0 };
+	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+				  { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+	int ret;
+
+	ret = i2c_transfer (state->i2c, msg, 2);
+	// Don't print an error message if the id is read.
+	if (ret != 2 && reg != 0x1a)
+		printk("DVB: TDA10021: %s: readreg error (ret == %i)\n",
+				__func__, ret);
+	return b1[0];
+}
+
+//get access to tuner
+static int lock_tuner(struct tda10021_state* state)
+{
+	u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] | 0x80 };
+	struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
+
+	if(i2c_transfer(state->i2c, &msg, 1) != 1)
+	{
+		printk("tda10021: lock tuner fails\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+//release access from tuner
+static int unlock_tuner(struct tda10021_state* state)
+{
+	u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] & 0x7f };
+	struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
+
+	if(i2c_transfer(state->i2c, &msg_post, 1) != 1)
+	{
+		printk("tda10021: unlock tuner fails\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int tda10021_setup_reg0 (struct tda10021_state* state, u8 reg0,
+				fe_spectral_inversion_t inversion)
+{
+	reg0 |= state->reg0 & 0x63;
+
+	if ((INVERSION_ON == inversion) ^ (state->config->invert == 0))
+		reg0 &= ~0x20;
+	else
+		reg0 |= 0x20;
+
+	_tda10021_writereg (state, 0x00, reg0 & 0xfe);
+	_tda10021_writereg (state, 0x00, reg0 | 0x01);
+
+	state->reg0 = reg0;
+	return 0;
+}
+
+static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate)
+{
+	s32 BDR;
+	s32 BDRI;
+	s16 SFIL=0;
+	u16 NDEC = 0;
+	u32 tmp, ratio;
+
+	if (symbolrate > XIN/2)
+		symbolrate = XIN/2;
+	if (symbolrate < 500000)
+		symbolrate = 500000;
+
+	if (symbolrate < XIN/16) NDEC = 1;
+	if (symbolrate < XIN/32) NDEC = 2;
+	if (symbolrate < XIN/64) NDEC = 3;
+
+	if (symbolrate < (u32)(XIN/12.3)) SFIL = 1;
+	if (symbolrate < (u32)(XIN/16))	 SFIL = 0;
+	if (symbolrate < (u32)(XIN/24.6)) SFIL = 1;
+	if (symbolrate < (u32)(XIN/32))	 SFIL = 0;
+	if (symbolrate < (u32)(XIN/49.2)) SFIL = 1;
+	if (symbolrate < (u32)(XIN/64))	 SFIL = 0;
+	if (symbolrate < (u32)(XIN/98.4)) SFIL = 1;
+
+	symbolrate <<= NDEC;
+	ratio = (symbolrate << 4) / FIN;
+	tmp =  ((symbolrate << 4) % FIN) << 8;
+	ratio = (ratio << 8) + tmp / FIN;
+	tmp = (tmp % FIN) << 8;
+	ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, FIN);
+
+	BDR = ratio;
+	BDRI = (((XIN << 5) / symbolrate) + 1) / 2;
+
+	if (BDRI > 0xFF)
+		BDRI = 0xFF;
+
+	SFIL = (SFIL << 4) | tda10021_inittab[0x0E];
+
+	NDEC = (NDEC << 6) | tda10021_inittab[0x03];
+
+	_tda10021_writereg (state, 0x03, NDEC);
+	_tda10021_writereg (state, 0x0a, BDR&0xff);
+	_tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff);
+	_tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f);
+
+	_tda10021_writereg (state, 0x0d, BDRI);
+	_tda10021_writereg (state, 0x0e, SFIL);
+
+	return 0;
+}
+
+static int tda10021_init (struct dvb_frontend *fe)
+{
+	struct tda10021_state* state = fe->demodulator_priv;
+	int i;
+
+	dprintk("DVB: TDA10021(%d): init chip\n", fe->adapter->num);
+
+	//_tda10021_writereg (fe, 0, 0);
+
+	for (i=0; i<tda10021_inittab_size; i++)
+		_tda10021_writereg (state, i, tda10021_inittab[i]);
+
+	_tda10021_writereg (state, 0x34, state->pwm);
+
+	//Comment by markus
+	//0x2A[3-0] == PDIV -> P multiplaying factor (P=PDIV+1)(default 0)
+	//0x2A[4] == BYPPLL -> Power down mode (default 1)
+	//0x2A[5] == LCK -> PLL Lock Flag
+	//0x2A[6] == POLAXIN -> Polarity of the input reference clock (default 0)
+
+	//Activate PLL
+	_tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
+	return 0;
+}
+
+struct qam_params {
+	u8 conf, agcref, lthr, mseth, aref;
+};
+
+static int tda10021_set_parameters(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 delsys  = c->delivery_system;
+	unsigned qam = c->modulation;
+	bool is_annex_c;
+	u32 reg0x3d;
+	struct tda10021_state* state = fe->demodulator_priv;
+	static const struct qam_params qam_params[] = {
+		/* Modulation  Conf  AGCref  LTHR  MSETH  AREF */
+		[QPSK]	   = { 0x14, 0x78,   0x78, 0x8c,  0x96 },
+		[QAM_16]   = { 0x00, 0x8c,   0x87, 0xa2,  0x91 },
+		[QAM_32]   = { 0x04, 0x8c,   0x64, 0x74,  0x96 },
+		[QAM_64]   = { 0x08, 0x6a,   0x46, 0x43,  0x6a },
+		[QAM_128]  = { 0x0c, 0x78,   0x36, 0x34,  0x7e },
+		[QAM_256]  = { 0x10, 0x5c,   0x26, 0x23,  0x6b },
+	};
+
+	switch (delsys) {
+	case SYS_DVBC_ANNEX_A:
+		is_annex_c = false;
+		break;
+	case SYS_DVBC_ANNEX_C:
+		is_annex_c = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * gcc optimizes the code bellow the same way as it would code:
+	 *           "if (qam > 5) return -EINVAL;"
+	 * Yet, the code is clearer, as it shows what QAM standards are
+	 * supported by the driver, and avoids the usage of magic numbers on
+	 * it.
+	 */
+	switch (qam) {
+	case QPSK:
+	case QAM_16:
+	case QAM_32:
+	case QAM_64:
+	case QAM_128:
+	case QAM_256:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (c->inversion != INVERSION_ON && c->inversion != INVERSION_OFF)
+		return -EINVAL;
+
+	/*printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->symbol_rate);*/
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	tda10021_set_symbolrate(state, c->symbol_rate);
+	_tda10021_writereg(state, 0x34, state->pwm);
+
+	_tda10021_writereg(state, 0x01, qam_params[qam].agcref);
+	_tda10021_writereg(state, 0x05, qam_params[qam].lthr);
+	_tda10021_writereg(state, 0x08, qam_params[qam].mseth);
+	_tda10021_writereg(state, 0x09, qam_params[qam].aref);
+
+	/*
+	 * Bit 0 == 0 means roll-off = 0.15 (Annex A)
+	 *	 == 1 means roll-off = 0.13 (Annex C)
+	 */
+	reg0x3d = tda10021_readreg (state, 0x3d);
+	if (is_annex_c)
+		_tda10021_writereg (state, 0x3d, 0x01 | reg0x3d);
+	else
+		_tda10021_writereg (state, 0x3d, 0xfe & reg0x3d);
+	tda10021_setup_reg0(state, qam_params[qam].conf, c->inversion);
+
+	return 0;
+}
+
+static int tda10021_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct tda10021_state* state = fe->demodulator_priv;
+	int sync;
+
+	*status = 0;
+	//0x11[0] == EQALGO -> Equalizer algorithms state
+	//0x11[1] == CARLOCK -> Carrier locked
+	//0x11[2] == FSYNC -> Frame synchronisation
+	//0x11[3] == FEL -> Front End locked
+	//0x11[6] == NODVB -> DVB Mode Information
+	sync = tda10021_readreg (state, 0x11);
+
+	if (sync & 2)
+		*status |= FE_HAS_SIGNAL|FE_HAS_CARRIER;
+
+	if (sync & 4)
+		*status |= FE_HAS_SYNC|FE_HAS_VITERBI;
+
+	if (sync & 8)
+		*status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int tda10021_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct tda10021_state* state = fe->demodulator_priv;
+
+	u32 _ber = tda10021_readreg(state, 0x14) |
+		(tda10021_readreg(state, 0x15) << 8) |
+		((tda10021_readreg(state, 0x16) & 0x0f) << 16);
+	_tda10021_writereg(state, 0x10, (tda10021_readreg(state, 0x10) & ~0xc0)
+					| (tda10021_inittab[0x10] & 0xc0));
+	*ber = 10 * _ber;
+
+	return 0;
+}
+
+static int tda10021_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct tda10021_state* state = fe->demodulator_priv;
+
+	u8 config = tda10021_readreg(state, 0x02);
+	u8 gain = tda10021_readreg(state, 0x17);
+	if (config & 0x02)
+		/* the agc value is inverted */
+		gain = ~gain;
+	*strength = (gain << 8) | gain;
+
+	return 0;
+}
+
+static int tda10021_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct tda10021_state* state = fe->demodulator_priv;
+
+	u8 quality = ~tda10021_readreg(state, 0x18);
+	*snr = (quality << 8) | quality;
+
+	return 0;
+}
+
+static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct tda10021_state* state = fe->demodulator_priv;
+
+	*ucblocks = tda10021_readreg (state, 0x13) & 0x7f;
+	if (*ucblocks == 0x7f)
+		*ucblocks = 0xffffffff;
+
+	/* reset uncorrected block counter */
+	_tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf);
+	_tda10021_writereg (state, 0x10, tda10021_inittab[0x10]);
+
+	return 0;
+}
+
+static int tda10021_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct tda10021_state* state = fe->demodulator_priv;
+	int sync;
+	s8 afc = 0;
+
+	sync = tda10021_readreg(state, 0x11);
+	afc = tda10021_readreg(state, 0x19);
+	if (verbose) {
+		/* AFC only valid when carrier has been recovered */
+		printk(sync & 2 ? "DVB: TDA10021(%d): AFC (%d) %dHz\n" :
+				  "DVB: TDA10021(%d): [AFC (%d) %dHz]\n",
+			state->frontend.dvb->num, afc,
+		       -((s32)p->symbol_rate * afc) >> 10);
+	}
+
+	p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF;
+	p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
+
+	p->fec_inner = FEC_NONE;
+	p->frequency = ((p->frequency + 31250) / 62500) * 62500;
+
+	if (sync & 2)
+		p->frequency -= ((s32)p->symbol_rate * afc) >> 10;
+
+	return 0;
+}
+
+static int tda10021_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct tda10021_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		lock_tuner(state);
+	} else {
+		unlock_tuner(state);
+	}
+	return 0;
+}
+
+static int tda10021_sleep(struct dvb_frontend* fe)
+{
+	struct tda10021_state* state = fe->demodulator_priv;
+
+	_tda10021_writereg (state, 0x1b, 0x02);  /* pdown ADC */
+	_tda10021_writereg (state, 0x00, 0x80);  /* standby */
+
+	return 0;
+}
+
+static void tda10021_release(struct dvb_frontend* fe)
+{
+	struct tda10021_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops tda10021_ops;
+
+struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
+				     struct i2c_adapter* i2c,
+				     u8 pwm)
+{
+	struct tda10021_state* state = NULL;
+	u8 id;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct tda10021_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->pwm = pwm;
+	state->reg0 = tda10021_inittab[0];
+
+	/* check if the demod is there */
+	id = tda10021_readreg(state, 0x1a);
+	if ((id & 0xf0) != 0x70) goto error;
+
+	/* Don't claim TDA10023 */
+	if (id == 0x7d)
+		goto error;
+
+	printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n",
+	       state->config->demod_address, id);
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops tda10021_ops = {
+	.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C },
+	.info = {
+		.name = "Philips TDA10021 DVB-C",
+		.frequency_stepsize = 62500,
+		.frequency_min = 47000000,
+		.frequency_max = 862000000,
+		.symbol_rate_min = (XIN/2)/64,     /* SACLK/64 == (XIN/2)/64 */
+		.symbol_rate_max = (XIN/2)/4,      /* SACLK/4 */
+	#if 0
+		.frequency_tolerance = ???,
+		.symbol_rate_tolerance = ???,  /* ppm */  /* == 8% (spec p. 5) */
+	#endif
+		.caps = 0x400 | //FE_CAN_QAM_4
+			FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+			FE_CAN_QAM_128 | FE_CAN_QAM_256 |
+			FE_CAN_FEC_AUTO
+	},
+
+	.release = tda10021_release,
+
+	.init = tda10021_init,
+	.sleep = tda10021_sleep,
+	.i2c_gate_ctrl = tda10021_i2c_gate_ctrl,
+
+	.set_frontend = tda10021_set_parameters,
+	.get_frontend = tda10021_get_frontend,
+
+	.read_status = tda10021_read_status,
+	.read_ber = tda10021_read_ber,
+	.read_signal_strength = tda10021_read_signal_strength,
+	.read_snr = tda10021_read_snr,
+	.read_ucblocks = tda10021_read_ucblocks,
+};
+
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
+
+MODULE_DESCRIPTION("Philips TDA10021 DVB-C demodulator driver");
+MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Markus Schulz");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(tda10021_attach);
diff --git a/drivers/media/dvb-frontends/tda10023.c b/drivers/media/dvb-frontends/tda10023.c
new file mode 100644
index 0000000..ca1e0d5
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda10023.c
@@ -0,0 +1,610 @@
+/*
+    TDA10023  - DVB-C decoder
+    (as used in Philips CU1216-3 NIM and the Reelbox DVB-C tuner card)
+
+    Copyright (C) 2005 Georg Acher, BayCom GmbH (acher at baycom dot de)
+    Copyright (c) 2006 Hartmut Birr (e9hack at gmail dot com)
+
+    Remotely based on tda10021.c
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+    Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
+		   Support for TDA10021
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "tda1002x.h"
+
+#define REG0_INIT_VAL 0x23
+
+struct tda10023_state {
+	struct i2c_adapter* i2c;
+	/* configuration settings */
+	const struct tda10023_config *config;
+	struct dvb_frontend frontend;
+
+	u8 pwm;
+	u8 reg0;
+
+	/* clock settings */
+	u32 xtal;
+	u8 pll_m;
+	u8 pll_p;
+	u8 pll_n;
+	u32 sysclk;
+};
+
+#define dprintk(x...)
+
+static int verbose;
+
+static u8 tda10023_readreg (struct tda10023_state* state, u8 reg)
+{
+	u8 b0 [] = { reg };
+	u8 b1 [] = { 0 };
+	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+				  { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+	int ret;
+
+	ret = i2c_transfer (state->i2c, msg, 2);
+	if (ret != 2) {
+		int num = state->frontend.dvb ? state->frontend.dvb->num : -1;
+		printk(KERN_ERR "DVB: TDA10023(%d): %s: readreg error "
+			"(reg == 0x%02x, ret == %i)\n",
+			num, __func__, reg, ret);
+	}
+	return b1[0];
+}
+
+static int tda10023_writereg (struct tda10023_state* state, u8 reg, u8 data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+	int ret;
+
+	ret = i2c_transfer (state->i2c, &msg, 1);
+	if (ret != 1) {
+		int num = state->frontend.dvb ? state->frontend.dvb->num : -1;
+		printk(KERN_ERR "DVB: TDA10023(%d): %s, writereg error "
+			"(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
+			num, __func__, reg, data, ret);
+	}
+	return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+
+static int tda10023_writebit (struct tda10023_state* state, u8 reg, u8 mask,u8 data)
+{
+	if (mask==0xff)
+		return tda10023_writereg(state, reg, data);
+	else {
+		u8 val;
+		val=tda10023_readreg(state,reg);
+		val&=~mask;
+		val|=(data&mask);
+		return tda10023_writereg(state, reg, val);
+	}
+}
+
+static void tda10023_writetab(struct tda10023_state* state, u8* tab)
+{
+	u8 r,m,v;
+	while (1) {
+		r=*tab++;
+		m=*tab++;
+		v=*tab++;
+		if (r==0xff) {
+			if (m==0xff)
+				break;
+			else
+				msleep(m);
+		}
+		else
+			tda10023_writebit(state,r,m,v);
+	}
+}
+
+//get access to tuner
+static int lock_tuner(struct tda10023_state* state)
+{
+	u8 buf[2] = { 0x0f, 0xc0 };
+	struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
+
+	if(i2c_transfer(state->i2c, &msg, 1) != 1)
+	{
+		printk("tda10023: lock tuner fails\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+//release access from tuner
+static int unlock_tuner(struct tda10023_state* state)
+{
+	u8 buf[2] = { 0x0f, 0x40 };
+	struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
+
+	if(i2c_transfer(state->i2c, &msg_post, 1) != 1)
+	{
+		printk("tda10023: unlock tuner fails\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int tda10023_setup_reg0 (struct tda10023_state* state, u8 reg0)
+{
+	reg0 |= state->reg0 & 0x63;
+
+	tda10023_writereg (state, 0x00, reg0 & 0xfe);
+	tda10023_writereg (state, 0x00, reg0 | 0x01);
+
+	state->reg0 = reg0;
+	return 0;
+}
+
+static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
+{
+	s32 BDR;
+	s32 BDRI;
+	s16 SFIL=0;
+	u16 NDEC = 0;
+
+	/* avoid floating point operations multiplying syscloc and divider
+	   by 10 */
+	u32 sysclk_x_10 = state->sysclk * 10;
+
+	if (sr < (u32)(sysclk_x_10/984)) {
+		NDEC=3;
+		SFIL=1;
+	} else if (sr < (u32)(sysclk_x_10/640)) {
+		NDEC=3;
+		SFIL=0;
+	} else if (sr < (u32)(sysclk_x_10/492)) {
+		NDEC=2;
+		SFIL=1;
+	} else if (sr < (u32)(sysclk_x_10/320)) {
+		NDEC=2;
+		SFIL=0;
+	} else if (sr < (u32)(sysclk_x_10/246)) {
+		NDEC=1;
+		SFIL=1;
+	} else if (sr < (u32)(sysclk_x_10/160)) {
+		NDEC=1;
+		SFIL=0;
+	} else if (sr < (u32)(sysclk_x_10/123)) {
+		NDEC=0;
+		SFIL=1;
+	}
+
+	BDRI = (state->sysclk)*16;
+	BDRI>>=NDEC;
+	BDRI +=sr/2;
+	BDRI /=sr;
+
+	if (BDRI>255)
+		BDRI=255;
+
+	{
+		u64 BDRX;
+
+		BDRX=1<<(24+NDEC);
+		BDRX*=sr;
+		do_div(BDRX, state->sysclk); 	/* BDRX/=SYSCLK; */
+
+		BDR=(s32)BDRX;
+	}
+	dprintk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",
+		sr, BDR, BDRI, NDEC);
+	tda10023_writebit (state, 0x03, 0xc0, NDEC<<6);
+	tda10023_writereg (state, 0x0a, BDR&255);
+	tda10023_writereg (state, 0x0b, (BDR>>8)&255);
+	tda10023_writereg (state, 0x0c, (BDR>>16)&31);
+	tda10023_writereg (state, 0x0d, BDRI);
+	tda10023_writereg (state, 0x3d, (SFIL<<7));
+	return 0;
+}
+
+static int tda10023_init (struct dvb_frontend *fe)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	u8 tda10023_inittab[] = {
+/*        reg  mask val */
+/* 000 */ 0x2a, 0xff, 0x02,  /* PLL3, Bypass, Power Down */
+/* 003 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
+/* 006 */ 0x2a, 0xff, 0x03,  /* PLL3, Bypass, Power Down */
+/* 009 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
+			   /* PLL1 */
+/* 012 */ 0x28, 0xff, (state->pll_m-1),
+			   /* PLL2 */
+/* 015 */ 0x29, 0xff, ((state->pll_p-1)<<6)|(state->pll_n-1),
+			   /* GPR FSAMPLING=1 */
+/* 018 */ 0x00, 0xff, REG0_INIT_VAL,
+/* 021 */ 0x2a, 0xff, 0x08,  /* PLL3 PSACLK=1 */
+/* 024 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
+/* 027 */ 0x1f, 0xff, 0x00,  /* RESET */
+/* 030 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
+/* 033 */ 0xe6, 0x0c, 0x04,  /* RSCFG_IND */
+/* 036 */ 0x10, 0xc0, 0x80,  /* DECDVBCFG1 PBER=1 */
+
+/* 039 */ 0x0e, 0xff, 0x82,  /* GAIN1 */
+/* 042 */ 0x03, 0x08, 0x08,  /* CLKCONF DYN=1 */
+/* 045 */ 0x2e, 0xbf, 0x30,  /* AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1
+				       PPWMTUN=0 PPWMIF=0 */
+/* 048 */ 0x01, 0xff, 0x30,  /* AGCREF */
+/* 051 */ 0x1e, 0x84, 0x84,  /* CONTROL SACLK_ON=1 */
+/* 054 */ 0x1b, 0xff, 0xc8,  /* ADC TWOS=1 */
+/* 057 */ 0x3b, 0xff, 0xff,  /* IFMAX */
+/* 060 */ 0x3c, 0xff, 0x00,  /* IFMIN */
+/* 063 */ 0x34, 0xff, 0x00,  /* PWMREF */
+/* 066 */ 0x35, 0xff, 0xff,  /* TUNMAX */
+/* 069 */ 0x36, 0xff, 0x00,  /* TUNMIN */
+/* 072 */ 0x06, 0xff, 0x7f,  /* EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 */
+/* 075 */ 0x1c, 0x30, 0x30,  /* EQCONF2 STEPALGO=SGNALGO=1 */
+/* 078 */ 0x37, 0xff, 0xf6,  /* DELTAF_LSB */
+/* 081 */ 0x38, 0xff, 0xff,  /* DELTAF_MSB */
+/* 084 */ 0x02, 0xff, 0x93,  /* AGCCONF1  IFS=1 KAGCIF=2 KAGCTUN=3 */
+/* 087 */ 0x2d, 0xff, 0xf6,  /* SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2 */
+/* 090 */ 0x04, 0x10, 0x00,  /* SWRAMP=1 */
+/* 093 */ 0x12, 0xff, TDA10023_OUTPUT_MODE_PARALLEL_B, /*
+				INTP1 POCLKP=1 FEL=1 MFS=0 */
+/* 096 */ 0x2b, 0x01, 0xa1,  /* INTS1 */
+/* 099 */ 0x20, 0xff, 0x04,  /* INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=? */
+/* 102 */ 0x2c, 0xff, 0x0d,  /* INTP/S TRIP=0 TRIS=0 */
+/* 105 */ 0xc4, 0xff, 0x00,
+/* 108 */ 0xc3, 0x30, 0x00,
+/* 111 */ 0xb5, 0xff, 0x19,  /* ERAGC_THD */
+/* 114 */ 0x00, 0x03, 0x01,  /* GPR, CLBS soft reset */
+/* 117 */ 0x00, 0x03, 0x03,  /* GPR, CLBS soft reset */
+/* 120 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
+/* 123 */ 0xff, 0xff, 0xff
+};
+	dprintk("DVB: TDA10023(%d): init chip\n", fe->dvb->num);
+
+	/* override default values if set in config */
+	if (state->config->deltaf) {
+		tda10023_inittab[80] = (state->config->deltaf & 0xff);
+		tda10023_inittab[83] = (state->config->deltaf >> 8);
+	}
+
+	if (state->config->output_mode)
+		tda10023_inittab[95] = state->config->output_mode;
+
+	tda10023_writetab(state, tda10023_inittab);
+
+	return 0;
+}
+
+struct qam_params {
+	u8 qam, lockthr, mseth, aref, agcrefnyq, eragnyq_thd;
+};
+
+static int tda10023_set_parameters(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 delsys  = c->delivery_system;
+	unsigned qam = c->modulation;
+	bool is_annex_c;
+	struct tda10023_state* state = fe->demodulator_priv;
+	static const struct qam_params qam_params[] = {
+		/* Modulation  QAM    LOCKTHR   MSETH   AREF AGCREFNYQ ERAGCNYQ_THD */
+		[QPSK]    = { (5<<2),  0x78,    0x8c,   0x96,   0x78,   0x4c  },
+		[QAM_16]  = { (0<<2),  0x87,    0xa2,   0x91,   0x8c,   0x57  },
+		[QAM_32]  = { (1<<2),  0x64,    0x74,   0x96,   0x8c,   0x57  },
+		[QAM_64]  = { (2<<2),  0x46,    0x43,   0x6a,   0x6a,   0x44  },
+		[QAM_128] = { (3<<2),  0x36,    0x34,   0x7e,   0x78,   0x4c  },
+		[QAM_256] = { (4<<2),  0x26,    0x23,   0x6c,   0x5c,   0x3c  },
+	};
+
+	switch (delsys) {
+	case SYS_DVBC_ANNEX_A:
+		is_annex_c = false;
+		break;
+	case SYS_DVBC_ANNEX_C:
+		is_annex_c = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * gcc optimizes the code bellow the same way as it would code:
+	 *		 "if (qam > 5) return -EINVAL;"
+	 * Yet, the code is clearer, as it shows what QAM standards are
+	 * supported by the driver, and avoids the usage of magic numbers on
+	 * it.
+	 */
+	switch (qam) {
+	case QPSK:
+	case QAM_16:
+	case QAM_32:
+	case QAM_64:
+	case QAM_128:
+	case QAM_256:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	tda10023_set_symbolrate(state, c->symbol_rate);
+	tda10023_writereg(state, 0x05, qam_params[qam].lockthr);
+	tda10023_writereg(state, 0x08, qam_params[qam].mseth);
+	tda10023_writereg(state, 0x09, qam_params[qam].aref);
+	tda10023_writereg(state, 0xb4, qam_params[qam].agcrefnyq);
+	tda10023_writereg(state, 0xb6, qam_params[qam].eragnyq_thd);
+#if 0
+	tda10023_writereg(state, 0x04, (c->inversion ? 0x12 : 0x32));
+	tda10023_writebit(state, 0x04, 0x60, (c->inversion ? 0 : 0x20));
+#endif
+	tda10023_writebit(state, 0x04, 0x40, 0x40);
+
+	if (is_annex_c)
+		tda10023_writebit(state, 0x3d, 0xfc, 0x03);
+	else
+		tda10023_writebit(state, 0x3d, 0xfc, 0x02);
+
+	tda10023_setup_reg0(state, qam_params[qam].qam);
+
+	return 0;
+}
+
+static int tda10023_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	int sync;
+
+	*status = 0;
+
+	//0x11[1] == CARLOCK -> Carrier locked
+	//0x11[2] == FSYNC -> Frame synchronisation
+	//0x11[3] == FEL -> Front End locked
+	//0x11[6] == NODVB -> DVB Mode Information
+	sync = tda10023_readreg (state, 0x11);
+
+	if (sync & 2)
+		*status |= FE_HAS_SIGNAL|FE_HAS_CARRIER;
+
+	if (sync & 4)
+		*status |= FE_HAS_SYNC|FE_HAS_VITERBI;
+
+	if (sync & 8)
+		*status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int tda10023_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	u8 a,b,c;
+	a=tda10023_readreg(state, 0x14);
+	b=tda10023_readreg(state, 0x15);
+	c=tda10023_readreg(state, 0x16)&0xf;
+	tda10023_writebit (state, 0x10, 0xc0, 0x00);
+
+	*ber = a | (b<<8)| (c<<16);
+	return 0;
+}
+
+static int tda10023_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	u8 ifgain=tda10023_readreg(state, 0x2f);
+
+	u16 gain = ((255-tda10023_readreg(state, 0x17))) + (255-ifgain)/16;
+	// Max raw value is about 0xb0 -> Normalize to >0xf0 after 0x90
+	if (gain>0x90)
+		gain=gain+2*(gain-0x90);
+	if (gain>255)
+		gain=255;
+
+	*strength = (gain<<8)|gain;
+	return 0;
+}
+
+static int tda10023_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+
+	u8 quality = ~tda10023_readreg(state, 0x18);
+	*snr = (quality << 8) | quality;
+	return 0;
+}
+
+static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	u8 a,b,c,d;
+	a= tda10023_readreg (state, 0x74);
+	b= tda10023_readreg (state, 0x75);
+	c= tda10023_readreg (state, 0x76);
+	d= tda10023_readreg (state, 0x77);
+	*ucblocks = a | (b<<8)|(c<<16)|(d<<24);
+
+	tda10023_writebit (state, 0x10, 0x20,0x00);
+	tda10023_writebit (state, 0x10, 0x20,0x20);
+	tda10023_writebit (state, 0x13, 0x01, 0x00);
+
+	return 0;
+}
+
+static int tda10023_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct tda10023_state* state = fe->demodulator_priv;
+	int sync,inv;
+	s8 afc = 0;
+
+	sync = tda10023_readreg(state, 0x11);
+	afc = tda10023_readreg(state, 0x19);
+	inv = tda10023_readreg(state, 0x04);
+
+	if (verbose) {
+		/* AFC only valid when carrier has been recovered */
+		printk(sync & 2 ? "DVB: TDA10023(%d): AFC (%d) %dHz\n" :
+				  "DVB: TDA10023(%d): [AFC (%d) %dHz]\n",
+			state->frontend.dvb->num, afc,
+		       -((s32)p->symbol_rate * afc) >> 10);
+	}
+
+	p->inversion = (inv&0x20?0:1);
+	p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
+
+	p->fec_inner = FEC_NONE;
+	p->frequency = ((p->frequency + 31250) / 62500) * 62500;
+
+	if (sync & 2)
+		p->frequency -= ((s32)p->symbol_rate * afc) >> 10;
+
+	return 0;
+}
+
+static int tda10023_sleep(struct dvb_frontend* fe)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+
+	tda10023_writereg (state, 0x1b, 0x02);  /* pdown ADC */
+	tda10023_writereg (state, 0x00, 0x80);  /* standby */
+
+	return 0;
+}
+
+static int tda10023_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		lock_tuner(state);
+	} else {
+		unlock_tuner(state);
+	}
+	return 0;
+}
+
+static void tda10023_release(struct dvb_frontend* fe)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops tda10023_ops;
+
+struct dvb_frontend *tda10023_attach(const struct tda10023_config *config,
+				     struct i2c_adapter *i2c,
+				     u8 pwm)
+{
+	struct tda10023_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct tda10023_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+
+	/* wakeup if in standby */
+	tda10023_writereg (state, 0x00, 0x33);
+	/* check if the demod is there */
+	if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
+	state->pwm = pwm;
+	state->reg0 = REG0_INIT_VAL;
+	if (state->config->xtal) {
+		state->xtal  = state->config->xtal;
+		state->pll_m = state->config->pll_m;
+		state->pll_p = state->config->pll_p;
+		state->pll_n = state->config->pll_n;
+	} else {
+		/* set default values if not defined in config */
+		state->xtal  = 28920000;
+		state->pll_m = 8;
+		state->pll_p = 4;
+		state->pll_n = 1;
+	}
+
+	/* calc sysclk */
+	state->sysclk = (state->xtal * state->pll_m / \
+			(state->pll_n * state->pll_p));
+
+	state->frontend.ops.info.symbol_rate_min = (state->sysclk/2)/64;
+	state->frontend.ops.info.symbol_rate_max = (state->sysclk/2)/4;
+
+	dprintk("DVB: TDA10023 %s: xtal:%d pll_m:%d pll_p:%d pll_n:%d\n",
+		__func__, state->xtal, state->pll_m, state->pll_p,
+		state->pll_n);
+
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops tda10023_ops = {
+	.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C },
+	.info = {
+		.name = "Philips TDA10023 DVB-C",
+		.frequency_stepsize = 62500,
+		.frequency_min =  47000000,
+		.frequency_max = 862000000,
+		.symbol_rate_min = 0,  /* set in tda10023_attach */
+		.symbol_rate_max = 0,  /* set in tda10023_attach */
+		.caps = 0x400 | //FE_CAN_QAM_4
+			FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+			FE_CAN_QAM_128 | FE_CAN_QAM_256 |
+			FE_CAN_FEC_AUTO
+	},
+
+	.release = tda10023_release,
+
+	.init = tda10023_init,
+	.sleep = tda10023_sleep,
+	.i2c_gate_ctrl = tda10023_i2c_gate_ctrl,
+
+	.set_frontend = tda10023_set_parameters,
+	.get_frontend = tda10023_get_frontend,
+	.read_status = tda10023_read_status,
+	.read_ber = tda10023_read_ber,
+	.read_signal_strength = tda10023_read_signal_strength,
+	.read_snr = tda10023_read_snr,
+	.read_ucblocks = tda10023_read_ucblocks,
+};
+
+
+MODULE_DESCRIPTION("Philips TDA10023 DVB-C demodulator driver");
+MODULE_AUTHOR("Georg Acher, Hartmut Birr");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(tda10023_attach);
diff --git a/drivers/media/dvb-frontends/tda1002x.h b/drivers/media/dvb-frontends/tda1002x.h
new file mode 100644
index 0000000..04d1941
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda1002x.h
@@ -0,0 +1,87 @@
+/*
+    TDA10021/TDA10023  - Single Chip Cable Channel Receiver driver module
+			 used on the the Siemens DVB-C cards
+
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+    Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
+		   Support for TDA10021
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef TDA1002x_H
+#define TDA1002x_H
+
+#include <linux/dvb/frontend.h>
+
+struct tda1002x_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+	u8 invert;
+};
+
+enum tda10023_output_mode {
+	TDA10023_OUTPUT_MODE_PARALLEL_A = 0xe0,
+	TDA10023_OUTPUT_MODE_PARALLEL_B = 0xa1,
+	TDA10023_OUTPUT_MODE_PARALLEL_C = 0xa0,
+	TDA10023_OUTPUT_MODE_SERIAL, /* TODO: not implemented */
+};
+
+struct tda10023_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+	u8 invert;
+
+	/* clock settings */
+	u32 xtal; /* defaults: 28920000 */
+	u8 pll_m; /* defaults: 8 */
+	u8 pll_p; /* defaults: 4 */
+	u8 pll_n; /* defaults: 1 */
+
+	/* MPEG2 TS output mode */
+	u8 output_mode;
+
+	/* input freq offset + baseband conversion type */
+	u16 deltaf;
+};
+
+#if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE))
+extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
+					    struct i2c_adapter* i2c, u8 pwm);
+#else
+static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
+					    struct i2c_adapter* i2c, u8 pwm)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TDA10021
+
+#if defined(CONFIG_DVB_TDA10023) || \
+	(defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda10023_attach(
+	const struct tda10023_config *config,
+	struct i2c_adapter *i2c, u8 pwm);
+#else
+static inline struct dvb_frontend *tda10023_attach(
+	const struct tda10023_config *config,
+	struct i2c_adapter *i2c, u8 pwm)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TDA10023
+
+#endif // TDA1002x_H
diff --git a/drivers/media/dvb-frontends/tda10048.c b/drivers/media/dvb-frontends/tda10048.c
new file mode 100644
index 0000000..71fb632
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda10048.c
@@ -0,0 +1,1191 @@
+/*
+    NXP TDA10048HN DVB OFDM demodulator driver
+
+    Copyright (C) 2009 Steven Toth <stoth@kernellabs.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/math64.h>
+#include <asm/div64.h>
+#include "dvb_frontend.h"
+#include "dvb_math.h"
+#include "tda10048.h"
+
+#define TDA10048_DEFAULT_FIRMWARE "dvb-fe-tda10048-1.0.fw"
+#define TDA10048_DEFAULT_FIRMWARE_SIZE 24878
+
+/* Register name definitions */
+#define TDA10048_IDENTITY          0x00
+#define TDA10048_VERSION           0x01
+#define TDA10048_DSP_CODE_CPT      0x0C
+#define TDA10048_DSP_CODE_IN       0x0E
+#define TDA10048_IN_CONF1          0x10
+#define TDA10048_IN_CONF2          0x11
+#define TDA10048_IN_CONF3          0x12
+#define TDA10048_OUT_CONF1         0x14
+#define TDA10048_OUT_CONF2         0x15
+#define TDA10048_OUT_CONF3         0x16
+#define TDA10048_AUTO              0x18
+#define TDA10048_SYNC_STATUS       0x1A
+#define TDA10048_CONF_C4_1         0x1E
+#define TDA10048_CONF_C4_2         0x1F
+#define TDA10048_CODE_IN_RAM       0x20
+#define TDA10048_CHANNEL_INFO1_R   0x22
+#define TDA10048_CHANNEL_INFO2_R   0x23
+#define TDA10048_CHANNEL_INFO1     0x24
+#define TDA10048_CHANNEL_INFO2     0x25
+#define TDA10048_TIME_ERROR_R      0x26
+#define TDA10048_TIME_ERROR        0x27
+#define TDA10048_FREQ_ERROR_LSB_R  0x28
+#define TDA10048_FREQ_ERROR_MSB_R  0x29
+#define TDA10048_FREQ_ERROR_LSB    0x2A
+#define TDA10048_FREQ_ERROR_MSB    0x2B
+#define TDA10048_IT_SEL            0x30
+#define TDA10048_IT_STAT           0x32
+#define TDA10048_DSP_AD_LSB        0x3C
+#define TDA10048_DSP_AD_MSB        0x3D
+#define TDA10048_DSP_REG_LSB       0x3E
+#define TDA10048_DSP_REG_MSB       0x3F
+#define TDA10048_CONF_TRISTATE1    0x44
+#define TDA10048_CONF_TRISTATE2    0x45
+#define TDA10048_CONF_POLARITY     0x46
+#define TDA10048_GPIO_SP_DS0       0x48
+#define TDA10048_GPIO_SP_DS1       0x49
+#define TDA10048_GPIO_SP_DS2       0x4A
+#define TDA10048_GPIO_SP_DS3       0x4B
+#define TDA10048_GPIO_OUT_SEL      0x4C
+#define TDA10048_GPIO_SELECT       0x4D
+#define TDA10048_IC_MODE           0x4E
+#define TDA10048_CONF_XO           0x50
+#define TDA10048_CONF_PLL1         0x51
+#define TDA10048_CONF_PLL2         0x52
+#define TDA10048_CONF_PLL3         0x53
+#define TDA10048_CONF_ADC          0x54
+#define TDA10048_CONF_ADC_2        0x55
+#define TDA10048_CONF_C1_1         0x60
+#define TDA10048_CONF_C1_3         0x62
+#define TDA10048_AGC_CONF          0x70
+#define TDA10048_AGC_THRESHOLD_LSB 0x72
+#define TDA10048_AGC_THRESHOLD_MSB 0x73
+#define TDA10048_AGC_RENORM        0x74
+#define TDA10048_AGC_GAINS         0x76
+#define TDA10048_AGC_TUN_MIN       0x78
+#define TDA10048_AGC_TUN_MAX       0x79
+#define TDA10048_AGC_IF_MIN        0x7A
+#define TDA10048_AGC_IF_MAX        0x7B
+#define TDA10048_AGC_TUN_LEVEL     0x7E
+#define TDA10048_AGC_IF_LEVEL      0x7F
+#define TDA10048_DIG_AGC_LEVEL     0x81
+#define TDA10048_FREQ_PHY2_LSB     0x86
+#define TDA10048_FREQ_PHY2_MSB     0x87
+#define TDA10048_TIME_INVWREF_LSB  0x88
+#define TDA10048_TIME_INVWREF_MSB  0x89
+#define TDA10048_TIME_WREF_LSB     0x8A
+#define TDA10048_TIME_WREF_MID1    0x8B
+#define TDA10048_TIME_WREF_MID2    0x8C
+#define TDA10048_TIME_WREF_MSB     0x8D
+#define TDA10048_NP_OUT            0xA2
+#define TDA10048_CELL_ID_LSB       0xA4
+#define TDA10048_CELL_ID_MSB       0xA5
+#define TDA10048_EXTTPS_ODD        0xAA
+#define TDA10048_EXTTPS_EVEN       0xAB
+#define TDA10048_TPS_LENGTH        0xAC
+#define TDA10048_FREE_REG_1        0xB2
+#define TDA10048_FREE_REG_2        0xB3
+#define TDA10048_CONF_C3_1         0xC0
+#define TDA10048_CVBER_CTRL        0xC2
+#define TDA10048_CBER_NMAX_LSB     0xC4
+#define TDA10048_CBER_NMAX_MSB     0xC5
+#define TDA10048_CBER_LSB          0xC6
+#define TDA10048_CBER_MSB          0xC7
+#define TDA10048_VBER_LSB          0xC8
+#define TDA10048_VBER_MID          0xC9
+#define TDA10048_VBER_MSB          0xCA
+#define TDA10048_CVBER_LUT         0xCC
+#define TDA10048_UNCOR_CTRL        0xCD
+#define TDA10048_UNCOR_CPT_LSB     0xCE
+#define TDA10048_UNCOR_CPT_MSB     0xCF
+#define TDA10048_SOFT_IT_C3        0xD6
+#define TDA10048_CONF_TS2          0xE0
+#define TDA10048_CONF_TS1          0xE1
+
+static unsigned int debug;
+
+#define dprintk(level, fmt, arg...)\
+	do { if (debug >= level)\
+		printk(KERN_DEBUG "tda10048: " fmt, ## arg);\
+	} while (0)
+
+struct tda10048_state {
+
+	struct i2c_adapter *i2c;
+
+	/* We'll cache and update the attach config settings */
+	struct tda10048_config config;
+	struct dvb_frontend frontend;
+
+	int fwloaded;
+
+	u32 freq_if_hz;
+	u32 xtal_hz;
+	u32 pll_mfactor;
+	u32 pll_nfactor;
+	u32 pll_pfactor;
+	u32 sample_freq;
+
+	u32 bandwidth;
+};
+
+static struct init_tab {
+	u8	reg;
+	u16	data;
+} init_tab[] = {
+	{ TDA10048_CONF_PLL1, 0x08 },
+	{ TDA10048_CONF_ADC_2, 0x00 },
+	{ TDA10048_CONF_C4_1, 0x00 },
+	{ TDA10048_CONF_PLL1, 0x0f },
+	{ TDA10048_CONF_PLL2, 0x0a },
+	{ TDA10048_CONF_PLL3, 0x43 },
+	{ TDA10048_FREQ_PHY2_LSB, 0x02 },
+	{ TDA10048_FREQ_PHY2_MSB, 0x0a },
+	{ TDA10048_TIME_WREF_LSB, 0xbd },
+	{ TDA10048_TIME_WREF_MID1, 0xe4 },
+	{ TDA10048_TIME_WREF_MID2, 0xa8 },
+	{ TDA10048_TIME_WREF_MSB, 0x02 },
+	{ TDA10048_TIME_INVWREF_LSB, 0x04 },
+	{ TDA10048_TIME_INVWREF_MSB, 0x06 },
+	{ TDA10048_CONF_C4_1, 0x00 },
+	{ TDA10048_CONF_C1_1, 0xa8 },
+	{ TDA10048_AGC_CONF, 0x16 },
+	{ TDA10048_CONF_C1_3, 0x0b },
+	{ TDA10048_AGC_TUN_MIN, 0x00 },
+	{ TDA10048_AGC_TUN_MAX, 0xff },
+	{ TDA10048_AGC_IF_MIN, 0x00 },
+	{ TDA10048_AGC_IF_MAX, 0xff },
+	{ TDA10048_AGC_THRESHOLD_MSB, 0x00 },
+	{ TDA10048_AGC_THRESHOLD_LSB, 0x70 },
+	{ TDA10048_CVBER_CTRL, 0x38 },
+	{ TDA10048_AGC_GAINS, 0x12 },
+	{ TDA10048_CONF_XO, 0x00 },
+	{ TDA10048_CONF_TS1, 0x07 },
+	{ TDA10048_IC_MODE, 0x00 },
+	{ TDA10048_CONF_TS2, 0xc0 },
+	{ TDA10048_CONF_TRISTATE1, 0x21 },
+	{ TDA10048_CONF_TRISTATE2, 0x00 },
+	{ TDA10048_CONF_POLARITY, 0x00 },
+	{ TDA10048_CONF_C4_2, 0x04 },
+	{ TDA10048_CONF_ADC, 0x60 },
+	{ TDA10048_CONF_ADC_2, 0x10 },
+	{ TDA10048_CONF_ADC, 0x60 },
+	{ TDA10048_CONF_ADC_2, 0x00 },
+	{ TDA10048_CONF_C1_1, 0xa8 },
+	{ TDA10048_UNCOR_CTRL, 0x00 },
+	{ TDA10048_CONF_C4_2, 0x04 },
+};
+
+static struct pll_tab {
+	u32	clk_freq_khz;
+	u32	if_freq_khz;
+} pll_tab[] = {
+	{ TDA10048_CLK_4000,  TDA10048_IF_36130 },
+	{ TDA10048_CLK_16000, TDA10048_IF_3300 },
+	{ TDA10048_CLK_16000, TDA10048_IF_3500 },
+	{ TDA10048_CLK_16000, TDA10048_IF_3800 },
+	{ TDA10048_CLK_16000, TDA10048_IF_4000 },
+	{ TDA10048_CLK_16000, TDA10048_IF_4300 },
+	{ TDA10048_CLK_16000, TDA10048_IF_4500 },
+	{ TDA10048_CLK_16000, TDA10048_IF_5000 },
+	{ TDA10048_CLK_16000, TDA10048_IF_36130 },
+};
+
+static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
+{
+	struct tda10048_config *config = &state->config;
+	int ret;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = {
+		.addr = config->demod_address,
+		.flags = 0, .buf = buf, .len = 2 };
+
+	dprintk(2, "%s(reg = 0x%02x, data = 0x%02x)\n", __func__, reg, data);
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		printk("%s: writereg error (ret == %i)\n", __func__, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+
+static u8 tda10048_readreg(struct tda10048_state *state, u8 reg)
+{
+	struct tda10048_config *config = &state->config;
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{ .addr = config->demod_address,
+			.flags = 0, .buf = b0, .len = 1 },
+		{ .addr = config->demod_address,
+			.flags = I2C_M_RD, .buf = b1, .len = 1 } };
+
+	dprintk(2, "%s(reg = 0x%02x)\n", __func__, reg);
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+			__func__, ret);
+
+	return b1[0];
+}
+
+static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg,
+				 const u8 *data, u16 len)
+{
+	struct tda10048_config *config = &state->config;
+	int ret = -EREMOTEIO;
+	struct i2c_msg msg;
+	u8 *buf;
+
+	dprintk(2, "%s(%d, ?, len = %d)\n", __func__, reg, len);
+
+	buf = kmalloc(len + 1, GFP_KERNEL);
+	if (buf == NULL) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	*buf = reg;
+	memcpy(buf + 1, data, len);
+
+	msg.addr = config->demod_address;
+	msg.flags = 0;
+	msg.buf = buf;
+	msg.len = len + 1;
+
+	dprintk(2, "%s():  write len = %d\n",
+		__func__, msg.len);
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+	if (ret != 1) {
+		printk(KERN_ERR "%s(): writereg error err %i\n",
+			 __func__, ret);
+		ret = -EREMOTEIO;
+	}
+
+error:
+	kfree(buf);
+
+	return ret;
+}
+
+static int tda10048_set_phy2(struct dvb_frontend *fe, u32 sample_freq_hz,
+			     u32 if_hz)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	u64 t;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (sample_freq_hz == 0)
+		return -EINVAL;
+
+	if (if_hz < (sample_freq_hz / 2)) {
+		/* PHY2 = (if2/fs) * 2^15 */
+		t = if_hz;
+		t *= 10;
+		t *= 32768;
+		do_div(t, sample_freq_hz);
+		t += 5;
+		do_div(t, 10);
+	} else {
+		/* PHY2 = ((IF1-fs)/fs) * 2^15 */
+		t = sample_freq_hz - if_hz;
+		t *= 10;
+		t *= 32768;
+		do_div(t, sample_freq_hz);
+		t += 5;
+		do_div(t, 10);
+		t = ~t + 1;
+	}
+
+	tda10048_writereg(state, TDA10048_FREQ_PHY2_LSB, (u8)t);
+	tda10048_writereg(state, TDA10048_FREQ_PHY2_MSB, (u8)(t >> 8));
+
+	return 0;
+}
+
+static int tda10048_set_wref(struct dvb_frontend *fe, u32 sample_freq_hz,
+			     u32 bw)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	u64 t, z;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (sample_freq_hz == 0)
+		return -EINVAL;
+
+	/* WREF = (B / (7 * fs)) * 2^31 */
+	t = bw * 10;
+	/* avoid warning: this decimal constant is unsigned only in ISO C90 */
+	/* t *= 2147483648 on 32bit platforms */
+	t *= (2048 * 1024);
+	t *= 1024;
+	z = 7 * sample_freq_hz;
+	do_div(t, z);
+	t += 5;
+	do_div(t, 10);
+
+	tda10048_writereg(state, TDA10048_TIME_WREF_LSB, (u8)t);
+	tda10048_writereg(state, TDA10048_TIME_WREF_MID1, (u8)(t >> 8));
+	tda10048_writereg(state, TDA10048_TIME_WREF_MID2, (u8)(t >> 16));
+	tda10048_writereg(state, TDA10048_TIME_WREF_MSB, (u8)(t >> 24));
+
+	return 0;
+}
+
+static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz,
+				u32 bw)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	u64 t;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (sample_freq_hz == 0)
+		return -EINVAL;
+
+	/* INVWREF = ((7 * fs) / B) * 2^5 */
+	t = sample_freq_hz;
+	t *= 7;
+	t *= 32;
+	t *= 10;
+	do_div(t, bw);
+	t += 5;
+	do_div(t, 10);
+
+	tda10048_writereg(state, TDA10048_TIME_INVWREF_LSB, (u8)t);
+	tda10048_writereg(state, TDA10048_TIME_INVWREF_MSB, (u8)(t >> 8));
+
+	return 0;
+}
+
+static int tda10048_set_bandwidth(struct dvb_frontend *fe,
+	u32 bw)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	dprintk(1, "%s(bw=%d)\n", __func__, bw);
+
+	/* Bandwidth setting may need to be adjusted */
+	switch (bw) {
+	case 6000000:
+	case 7000000:
+	case 8000000:
+		tda10048_set_wref(fe, state->sample_freq, bw);
+		tda10048_set_invwref(fe, state->sample_freq, bw);
+		break;
+	default:
+		printk(KERN_ERR "%s() invalid bandwidth\n", __func__);
+		return -EINVAL;
+	}
+
+	state->bandwidth = bw;
+
+	return 0;
+}
+
+static int tda10048_set_if(struct dvb_frontend *fe, u32 bw)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	struct tda10048_config *config = &state->config;
+	int i;
+	u32 if_freq_khz;
+
+	dprintk(1, "%s(bw = %d)\n", __func__, bw);
+
+	/* based on target bandwidth and clk we calculate pll factors */
+	switch (bw) {
+	case 6000000:
+		if_freq_khz = config->dtv6_if_freq_khz;
+		break;
+	case 7000000:
+		if_freq_khz = config->dtv7_if_freq_khz;
+		break;
+	case 8000000:
+		if_freq_khz = config->dtv8_if_freq_khz;
+		break;
+	default:
+		printk(KERN_ERR "%s() no default\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pll_tab); i++) {
+		if ((pll_tab[i].clk_freq_khz == config->clk_freq_khz) &&
+			(pll_tab[i].if_freq_khz == if_freq_khz)) {
+
+			state->freq_if_hz = pll_tab[i].if_freq_khz * 1000;
+			state->xtal_hz = pll_tab[i].clk_freq_khz * 1000;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(pll_tab)) {
+		printk(KERN_ERR "%s() Incorrect attach settings\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	dprintk(1, "- freq_if_hz = %d\n", state->freq_if_hz);
+	dprintk(1, "- xtal_hz = %d\n", state->xtal_hz);
+	dprintk(1, "- pll_mfactor = %d\n", state->pll_mfactor);
+	dprintk(1, "- pll_nfactor = %d\n", state->pll_nfactor);
+	dprintk(1, "- pll_pfactor = %d\n", state->pll_pfactor);
+
+	/* Calculate the sample frequency */
+	state->sample_freq = state->xtal_hz * (state->pll_mfactor + 45);
+	state->sample_freq /= (state->pll_nfactor + 1);
+	state->sample_freq /= (state->pll_pfactor + 4);
+	dprintk(1, "- sample_freq = %d\n", state->sample_freq);
+
+	/* Update the I/F */
+	tda10048_set_phy2(fe, state->sample_freq, state->freq_if_hz);
+
+	return 0;
+}
+
+static int tda10048_firmware_upload(struct dvb_frontend *fe)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	struct tda10048_config *config = &state->config;
+	const struct firmware *fw;
+	int ret;
+	int pos = 0;
+	int cnt;
+	u8 wlen = config->fwbulkwritelen;
+
+	if ((wlen != TDA10048_BULKWRITE_200) && (wlen != TDA10048_BULKWRITE_50))
+		wlen = TDA10048_BULKWRITE_200;
+
+	/* request the firmware, this will block and timeout */
+	printk(KERN_INFO "%s: waiting for firmware upload (%s)...\n",
+		__func__,
+		TDA10048_DEFAULT_FIRMWARE);
+
+	ret = request_firmware(&fw, TDA10048_DEFAULT_FIRMWARE,
+		state->i2c->dev.parent);
+	if (ret) {
+		printk(KERN_ERR "%s: Upload failed. (file not found?)\n",
+			__func__);
+		return -EIO;
+	} else {
+		printk(KERN_INFO "%s: firmware read %Zu bytes.\n",
+			__func__,
+			fw->size);
+		ret = 0;
+	}
+
+	if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) {
+		printk(KERN_ERR "%s: firmware incorrect size\n", __func__);
+		ret = -EIO;
+	} else {
+		printk(KERN_INFO "%s: firmware uploading\n", __func__);
+
+		/* Soft reset */
+		tda10048_writereg(state, TDA10048_CONF_TRISTATE1,
+			tda10048_readreg(state, TDA10048_CONF_TRISTATE1)
+				& 0xfe);
+		tda10048_writereg(state, TDA10048_CONF_TRISTATE1,
+			tda10048_readreg(state, TDA10048_CONF_TRISTATE1)
+				| 0x01);
+
+		/* Put the demod into host download mode */
+		tda10048_writereg(state, TDA10048_CONF_C4_1,
+			tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xf9);
+
+		/* Boot the DSP */
+		tda10048_writereg(state, TDA10048_CONF_C4_1,
+			tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x08);
+
+		/* Prepare for download */
+		tda10048_writereg(state, TDA10048_DSP_CODE_CPT, 0);
+
+		/* Download the firmware payload */
+		while (pos < fw->size) {
+
+			if ((fw->size - pos) > wlen)
+				cnt = wlen;
+			else
+				cnt = fw->size - pos;
+
+			tda10048_writeregbulk(state, TDA10048_DSP_CODE_IN,
+				&fw->data[pos], cnt);
+
+			pos += cnt;
+		}
+
+		ret = -EIO;
+		/* Wait up to 250ms for the DSP to boot */
+		for (cnt = 0; cnt < 250 ; cnt += 10) {
+
+			msleep(10);
+
+			if (tda10048_readreg(state, TDA10048_SYNC_STATUS)
+				& 0x40) {
+				ret = 0;
+				break;
+			}
+		}
+	}
+
+	release_firmware(fw);
+
+	if (ret == 0) {
+		printk(KERN_INFO "%s: firmware uploaded\n", __func__);
+		state->fwloaded = 1;
+	} else
+		printk(KERN_ERR "%s: firmware upload failed\n", __func__);
+
+	return ret;
+}
+
+static int tda10048_set_inversion(struct dvb_frontend *fe, int inversion)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+
+	dprintk(1, "%s(%d)\n", __func__, inversion);
+
+	if (inversion == TDA10048_INVERSION_ON)
+		tda10048_writereg(state, TDA10048_CONF_C1_1,
+			tda10048_readreg(state, TDA10048_CONF_C1_1) | 0x20);
+	else
+		tda10048_writereg(state, TDA10048_CONF_C1_1,
+			tda10048_readreg(state, TDA10048_CONF_C1_1) & 0xdf);
+
+	return 0;
+}
+
+/* Retrieve the demod settings */
+static int tda10048_get_tps(struct tda10048_state *state,
+	struct dtv_frontend_properties *p)
+{
+	u8 val;
+
+	/* Make sure the TPS regs are valid */
+	if (!(tda10048_readreg(state, TDA10048_AUTO) & 0x01))
+		return -EAGAIN;
+
+	val = tda10048_readreg(state, TDA10048_OUT_CONF2);
+	switch ((val & 0x60) >> 5) {
+	case 0:
+		p->modulation = QPSK;
+		break;
+	case 1:
+		p->modulation = QAM_16;
+		break;
+	case 2:
+		p->modulation = QAM_64;
+		break;
+	}
+	switch ((val & 0x18) >> 3) {
+	case 0:
+		p->hierarchy = HIERARCHY_NONE;
+		break;
+	case 1:
+		p->hierarchy = HIERARCHY_1;
+		break;
+	case 2:
+		p->hierarchy = HIERARCHY_2;
+		break;
+	case 3:
+		p->hierarchy = HIERARCHY_4;
+		break;
+	}
+	switch (val & 0x07) {
+	case 0:
+		p->code_rate_HP = FEC_1_2;
+		break;
+	case 1:
+		p->code_rate_HP = FEC_2_3;
+		break;
+	case 2:
+		p->code_rate_HP = FEC_3_4;
+		break;
+	case 3:
+		p->code_rate_HP = FEC_5_6;
+		break;
+	case 4:
+		p->code_rate_HP = FEC_7_8;
+		break;
+	}
+
+	val = tda10048_readreg(state, TDA10048_OUT_CONF3);
+	switch (val & 0x07) {
+	case 0:
+		p->code_rate_LP = FEC_1_2;
+		break;
+	case 1:
+		p->code_rate_LP = FEC_2_3;
+		break;
+	case 2:
+		p->code_rate_LP = FEC_3_4;
+		break;
+	case 3:
+		p->code_rate_LP = FEC_5_6;
+		break;
+	case 4:
+		p->code_rate_LP = FEC_7_8;
+		break;
+	}
+
+	val = tda10048_readreg(state, TDA10048_OUT_CONF1);
+	switch ((val & 0x0c) >> 2) {
+	case 0:
+		p->guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		p->guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		p->guard_interval =  GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		p->guard_interval =  GUARD_INTERVAL_1_4;
+		break;
+	}
+	switch (val & 0x03) {
+	case 0:
+		p->transmission_mode = TRANSMISSION_MODE_2K;
+		break;
+	case 1:
+		p->transmission_mode = TRANSMISSION_MODE_8K;
+		break;
+	}
+
+	return 0;
+}
+
+static int tda10048_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	struct tda10048_config *config = &state->config;
+	dprintk(1, "%s(%d)\n", __func__, enable);
+
+	if (config->disable_gate_access)
+		return 0;
+
+	if (enable)
+		return tda10048_writereg(state, TDA10048_CONF_C4_1,
+			tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x02);
+	else
+		return tda10048_writereg(state, TDA10048_CONF_C4_1,
+			tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xfd);
+}
+
+static int tda10048_output_mode(struct dvb_frontend *fe, int serial)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	dprintk(1, "%s(%d)\n", __func__, serial);
+
+	/* Ensure pins are out of tri-state */
+	tda10048_writereg(state, TDA10048_CONF_TRISTATE1, 0x21);
+	tda10048_writereg(state, TDA10048_CONF_TRISTATE2, 0x00);
+
+	if (serial) {
+		tda10048_writereg(state, TDA10048_IC_MODE, 0x80 | 0x20);
+		tda10048_writereg(state, TDA10048_CONF_TS2, 0xc0);
+	} else {
+		tda10048_writereg(state, TDA10048_IC_MODE, 0x00);
+		tda10048_writereg(state, TDA10048_CONF_TS2, 0x01);
+	}
+
+	return 0;
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+/* TODO: Support manual tuning with specific params */
+static int tda10048_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct tda10048_state *state = fe->demodulator_priv;
+
+	dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency);
+
+	/* Update the I/F pll's if the bandwidth changes */
+	if (p->bandwidth_hz != state->bandwidth) {
+		tda10048_set_if(fe, p->bandwidth_hz);
+		tda10048_set_bandwidth(fe, p->bandwidth_hz);
+	}
+
+	if (fe->ops.tuner_ops.set_params) {
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		fe->ops.tuner_ops.set_params(fe);
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	/* Enable demod TPS auto detection and begin acquisition */
+	tda10048_writereg(state, TDA10048_AUTO, 0x57);
+	/* trigger cber and vber acquisition */
+	tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x3B);
+
+	return 0;
+}
+
+/* Establish sane defaults and load firmware. */
+static int tda10048_init(struct dvb_frontend *fe)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	struct tda10048_config *config = &state->config;
+	int ret = 0, i;
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* PLL */
+	init_tab[4].data = (u8)(state->pll_mfactor);
+	init_tab[5].data = (u8)(state->pll_nfactor) | 0x40;
+
+	/* Apply register defaults */
+	for (i = 0; i < ARRAY_SIZE(init_tab); i++)
+		tda10048_writereg(state, init_tab[i].reg, init_tab[i].data);
+
+	if (state->fwloaded == 0)
+		ret = tda10048_firmware_upload(fe);
+
+	/* Set either serial or parallel */
+	tda10048_output_mode(fe, config->output_mode);
+
+	/* Set inversion */
+	tda10048_set_inversion(fe, config->inversion);
+
+	/* Establish default RF values */
+	tda10048_set_if(fe, 8000000);
+	tda10048_set_bandwidth(fe, 8000000);
+
+	/* Ensure we leave the gate closed */
+	tda10048_i2c_gate_ctrl(fe, 0);
+
+	return ret;
+}
+
+static int tda10048_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	u8 reg;
+
+	*status = 0;
+
+	reg = tda10048_readreg(state, TDA10048_SYNC_STATUS);
+
+	dprintk(1, "%s() status =0x%02x\n", __func__, reg);
+
+	if (reg & 0x02)
+		*status |= FE_HAS_CARRIER;
+
+	if (reg & 0x04)
+		*status |= FE_HAS_SIGNAL;
+
+	if (reg & 0x08) {
+		*status |= FE_HAS_LOCK;
+		*status |= FE_HAS_VITERBI;
+		*status |= FE_HAS_SYNC;
+	}
+
+	return 0;
+}
+
+static int tda10048_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	static u32 cber_current;
+	u32 cber_nmax;
+	u64 cber_tmp;
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* update cber on interrupt */
+	if (tda10048_readreg(state, TDA10048_SOFT_IT_C3) & 0x01) {
+		cber_tmp = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 |
+			tda10048_readreg(state, TDA10048_CBER_LSB);
+		cber_nmax = tda10048_readreg(state, TDA10048_CBER_NMAX_MSB) << 8 |
+			tda10048_readreg(state, TDA10048_CBER_NMAX_LSB);
+		cber_tmp *= 100000000;
+		cber_tmp *= 2;
+		cber_tmp = div_u64(cber_tmp, (cber_nmax * 32) + 1);
+		cber_current = (u32)cber_tmp;
+		/* retrigger cber acquisition */
+		tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x39);
+	}
+	/* actual cber is (*ber)/1e8 */
+	*ber = cber_current;
+
+	return 0;
+}
+
+static int tda10048_read_signal_strength(struct dvb_frontend *fe,
+	u16 *signal_strength)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	u8 v;
+
+	dprintk(1, "%s()\n", __func__);
+
+	*signal_strength = 65535;
+
+	v = tda10048_readreg(state, TDA10048_NP_OUT);
+	if (v > 0)
+		*signal_strength -= (v << 8) | v;
+
+	return 0;
+}
+
+/* SNR lookup table */
+static struct snr_tab {
+	u8 val;
+	u8 data;
+} snr_tab[] = {
+	{   0,   0 },
+	{   1, 246 },
+	{   2, 215 },
+	{   3, 198 },
+	{   4, 185 },
+	{   5, 176 },
+	{   6, 168 },
+	{   7, 161 },
+	{   8, 155 },
+	{   9, 150 },
+	{  10, 146 },
+	{  11, 141 },
+	{  12, 138 },
+	{  13, 134 },
+	{  14, 131 },
+	{  15, 128 },
+	{  16, 125 },
+	{  17, 122 },
+	{  18, 120 },
+	{  19, 118 },
+	{  20, 115 },
+	{  21, 113 },
+	{  22, 111 },
+	{  23, 109 },
+	{  24, 107 },
+	{  25, 106 },
+	{  26, 104 },
+	{  27, 102 },
+	{  28, 101 },
+	{  29,  99 },
+	{  30,  98 },
+	{  31,  96 },
+	{  32,  95 },
+	{  33,  94 },
+	{  34,  92 },
+	{  35,  91 },
+	{  36,  90 },
+	{  37,  89 },
+	{  38,  88 },
+	{  39,  86 },
+	{  40,  85 },
+	{  41,  84 },
+	{  42,  83 },
+	{  43,  82 },
+	{  44,  81 },
+	{  45,  80 },
+	{  46,  79 },
+	{  47,  78 },
+	{  48,  77 },
+	{  49,  76 },
+	{  50,  76 },
+	{  51,  75 },
+	{  52,  74 },
+	{  53,  73 },
+	{  54,  72 },
+	{  56,  71 },
+	{  57,  70 },
+	{  58,  69 },
+	{  60,  68 },
+	{  61,  67 },
+	{  63,  66 },
+	{  64,  65 },
+	{  66,  64 },
+	{  67,  63 },
+	{  68,  62 },
+	{  69,  62 },
+	{  70,  61 },
+	{  72,  60 },
+	{  74,  59 },
+	{  75,  58 },
+	{  77,  57 },
+	{  79,  56 },
+	{  81,  55 },
+	{  83,  54 },
+	{  85,  53 },
+	{  87,  52 },
+	{  89,  51 },
+	{  91,  50 },
+	{  93,  49 },
+	{  95,  48 },
+	{  97,  47 },
+	{ 100,  46 },
+	{ 102,  45 },
+	{ 104,  44 },
+	{ 107,  43 },
+	{ 109,  42 },
+	{ 112,  41 },
+	{ 114,  40 },
+	{ 117,  39 },
+	{ 120,  38 },
+	{ 123,  37 },
+	{ 125,  36 },
+	{ 128,  35 },
+	{ 131,  34 },
+	{ 134,  33 },
+	{ 138,  32 },
+	{ 141,  31 },
+	{ 144,  30 },
+	{ 147,  29 },
+	{ 151,  28 },
+	{ 154,  27 },
+	{ 158,  26 },
+	{ 162,  25 },
+	{ 165,  24 },
+	{ 169,  23 },
+	{ 173,  22 },
+	{ 177,  21 },
+	{ 181,  20 },
+	{ 186,  19 },
+	{ 190,  18 },
+	{ 194,  17 },
+	{ 199,  16 },
+	{ 204,  15 },
+	{ 208,  14 },
+	{ 213,  13 },
+	{ 218,  12 },
+	{ 223,  11 },
+	{ 229,  10 },
+	{ 234,   9 },
+	{ 239,   8 },
+	{ 245,   7 },
+	{ 251,   6 },
+	{ 255,   5 },
+};
+
+static int tda10048_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	u8 v;
+	int i, ret = -EINVAL;
+
+	dprintk(1, "%s()\n", __func__);
+
+	v = tda10048_readreg(state, TDA10048_NP_OUT);
+	for (i = 0; i < ARRAY_SIZE(snr_tab); i++) {
+		if (v <= snr_tab[i].val) {
+			*snr = snr_tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+
+	dprintk(1, "%s()\n", __func__);
+
+	*ucblocks = tda10048_readreg(state, TDA10048_UNCOR_CPT_MSB) << 8 |
+		tda10048_readreg(state, TDA10048_UNCOR_CPT_LSB);
+	/* clear the uncorrected TS packets counter when saturated */
+	if (*ucblocks == 0xFFFF)
+		tda10048_writereg(state, TDA10048_UNCOR_CTRL, 0x80);
+
+	return 0;
+}
+
+static int tda10048_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct tda10048_state *state = fe->demodulator_priv;
+
+	dprintk(1, "%s()\n", __func__);
+
+	p->inversion = tda10048_readreg(state, TDA10048_CONF_C1_1)
+		& 0x20 ? INVERSION_ON : INVERSION_OFF;
+
+	return tda10048_get_tps(state, p);
+}
+
+static int tda10048_get_tune_settings(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	return 0;
+}
+
+static void tda10048_release(struct dvb_frontend *fe)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	dprintk(1, "%s()\n", __func__);
+	kfree(state);
+}
+
+static void tda10048_establish_defaults(struct dvb_frontend *fe)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	struct tda10048_config *config = &state->config;
+
+	/* Validate/default the config */
+	if (config->dtv6_if_freq_khz == 0) {
+		config->dtv6_if_freq_khz = TDA10048_IF_4300;
+		printk(KERN_WARNING "%s() tda10048_config.dtv6_if_freq_khz "
+			"is not set (defaulting to %d)\n",
+			__func__,
+			config->dtv6_if_freq_khz);
+	}
+
+	if (config->dtv7_if_freq_khz == 0) {
+		config->dtv7_if_freq_khz = TDA10048_IF_4300;
+		printk(KERN_WARNING "%s() tda10048_config.dtv7_if_freq_khz "
+			"is not set (defaulting to %d)\n",
+			__func__,
+			config->dtv7_if_freq_khz);
+	}
+
+	if (config->dtv8_if_freq_khz == 0) {
+		config->dtv8_if_freq_khz = TDA10048_IF_4300;
+		printk(KERN_WARNING "%s() tda10048_config.dtv8_if_freq_khz "
+			"is not set (defaulting to %d)\n",
+			__func__,
+			config->dtv8_if_freq_khz);
+	}
+
+	if (config->clk_freq_khz == 0) {
+		config->clk_freq_khz = TDA10048_CLK_16000;
+		printk(KERN_WARNING "%s() tda10048_config.clk_freq_khz "
+			"is not set (defaulting to %d)\n",
+			__func__,
+			config->clk_freq_khz);
+	}
+}
+
+static struct dvb_frontend_ops tda10048_ops;
+
+struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
+	struct i2c_adapter *i2c)
+{
+	struct tda10048_state *state = NULL;
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct tda10048_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state and clone the config */
+	memcpy(&state->config, config, sizeof(*config));
+	state->i2c = i2c;
+	state->fwloaded = config->no_firmware;
+	state->bandwidth = 8000000;
+
+	/* check if the demod is present */
+	if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &tda10048_ops,
+		sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	/* set pll */
+	if (config->set_pll) {
+		state->pll_mfactor = config->pll_m;
+		state->pll_nfactor = config->pll_n;
+		state->pll_pfactor = config->pll_p;
+	} else {
+		state->pll_mfactor = 10;
+		state->pll_nfactor = 3;
+		state->pll_pfactor = 0;
+	}
+
+	/* Establish any defaults the the user didn't pass */
+	tda10048_establish_defaults(&state->frontend);
+
+	/* Set the xtal and freq defaults */
+	if (tda10048_set_if(&state->frontend, 8000000) != 0)
+		goto error;
+
+	/* Default bandwidth */
+	if (tda10048_set_bandwidth(&state->frontend, 8000000) != 0)
+		goto error;
+
+	/* Leave the gate closed */
+	tda10048_i2c_gate_ctrl(&state->frontend, 0);
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(tda10048_attach);
+
+static struct dvb_frontend_ops tda10048_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name			= "NXP TDA10048HN DVB-T",
+		.frequency_min		= 177000000,
+		.frequency_max		= 858000000,
+		.frequency_stepsize	= 166666,
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+		FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+		FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+		FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
+	},
+
+	.release = tda10048_release,
+	.init = tda10048_init,
+	.i2c_gate_ctrl = tda10048_i2c_gate_ctrl,
+	.set_frontend = tda10048_set_frontend,
+	.get_frontend = tda10048_get_frontend,
+	.get_tune_settings = tda10048_get_tune_settings,
+	.read_status = tda10048_read_status,
+	.read_ber = tda10048_read_ber,
+	.read_signal_strength = tda10048_read_signal_strength,
+	.read_snr = tda10048_read_snr,
+	.read_ucblocks = tda10048_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("NXP TDA10048HN DVB-T Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/tda10048.h b/drivers/media/dvb-frontends/tda10048.h
new file mode 100644
index 0000000..fb2ef5a
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda10048.h
@@ -0,0 +1,90 @@
+/*
+    NXP TDA10048HN DVB OFDM demodulator driver
+
+    Copyright (C) 2009 Steven Toth <stoth@kernellabs.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef TDA10048_H
+#define TDA10048_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct tda10048_config {
+
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* serial/parallel output */
+#define TDA10048_PARALLEL_OUTPUT 0
+#define TDA10048_SERIAL_OUTPUT   1
+	u8 output_mode;
+
+#define TDA10048_BULKWRITE_200	200
+#define TDA10048_BULKWRITE_50	50
+	u8 fwbulkwritelen;
+
+	/* Spectral Inversion */
+#define TDA10048_INVERSION_OFF 0
+#define TDA10048_INVERSION_ON  1
+	u8 inversion;
+
+#define TDA10048_IF_3300  3300
+#define TDA10048_IF_3500  3500
+#define TDA10048_IF_3800  3800
+#define TDA10048_IF_4000  4000
+#define TDA10048_IF_4300  4300
+#define TDA10048_IF_4500  4500
+#define TDA10048_IF_4750  4750
+#define TDA10048_IF_5000  5000
+#define TDA10048_IF_36130 36130
+	u16 dtv6_if_freq_khz;
+	u16 dtv7_if_freq_khz;
+	u16 dtv8_if_freq_khz;
+
+#define TDA10048_CLK_4000  4000
+#define TDA10048_CLK_16000 16000
+	u16 clk_freq_khz;
+
+	/* Disable I2C gate access */
+	u8 disable_gate_access;
+
+	bool no_firmware;
+
+	bool set_pll;
+	u8 pll_m;
+	u8 pll_p;
+	u8 pll_n;
+};
+
+#if defined(CONFIG_DVB_TDA10048) || \
+	(defined(CONFIG_DVB_TDA10048_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda10048_attach(
+	const struct tda10048_config *config,
+	struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *tda10048_attach(
+	const struct tda10048_config *config,
+	struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_TDA10048 */
+
+#endif /* TDA10048_H */
diff --git a/drivers/media/dvb-frontends/tda1004x.c b/drivers/media/dvb-frontends/tda1004x.c
new file mode 100644
index 0000000..35d72b4
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda1004x.c
@@ -0,0 +1,1381 @@
+  /*
+     Driver for Philips tda1004xh OFDM Demodulator
+
+     (c) 2003, 2004 Andrew de Quincey & Robert Schlabbach
+
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+     the Free Software Foundation; either version 2 of the License, or
+     (at your option) any later version.
+
+     This program is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+     GNU General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, write to the Free Software
+     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   */
+/*
+ * This driver needs external firmware. Please use the commands
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
+ * download/extract them, and then copy them to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
+ */
+#define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw"
+#define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw"
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "tda1004x.h"
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "tda1004x: " args); \
+	} while (0)
+
+#define TDA1004X_CHIPID		 0x00
+#define TDA1004X_AUTO		 0x01
+#define TDA1004X_IN_CONF1	 0x02
+#define TDA1004X_IN_CONF2	 0x03
+#define TDA1004X_OUT_CONF1	 0x04
+#define TDA1004X_OUT_CONF2	 0x05
+#define TDA1004X_STATUS_CD	 0x06
+#define TDA1004X_CONFC4		 0x07
+#define TDA1004X_DSSPARE2	 0x0C
+#define TDA10045H_CODE_IN	 0x0D
+#define TDA10045H_FWPAGE	 0x0E
+#define TDA1004X_SCAN_CPT	 0x10
+#define TDA1004X_DSP_CMD	 0x11
+#define TDA1004X_DSP_ARG	 0x12
+#define TDA1004X_DSP_DATA1	 0x13
+#define TDA1004X_DSP_DATA2	 0x14
+#define TDA1004X_CONFADC1	 0x15
+#define TDA1004X_CONFC1		 0x16
+#define TDA10045H_S_AGC		 0x1a
+#define TDA10046H_AGC_TUN_LEVEL	 0x1a
+#define TDA1004X_SNR		 0x1c
+#define TDA1004X_CONF_TS1	 0x1e
+#define TDA1004X_CONF_TS2	 0x1f
+#define TDA1004X_CBER_RESET	 0x20
+#define TDA1004X_CBER_MSB	 0x21
+#define TDA1004X_CBER_LSB	 0x22
+#define TDA1004X_CVBER_LUT	 0x23
+#define TDA1004X_VBER_MSB	 0x24
+#define TDA1004X_VBER_MID	 0x25
+#define TDA1004X_VBER_LSB	 0x26
+#define TDA1004X_UNCOR		 0x27
+
+#define TDA10045H_CONFPLL_P	 0x2D
+#define TDA10045H_CONFPLL_M_MSB	 0x2E
+#define TDA10045H_CONFPLL_M_LSB	 0x2F
+#define TDA10045H_CONFPLL_N	 0x30
+
+#define TDA10046H_CONFPLL1	 0x2D
+#define TDA10046H_CONFPLL2	 0x2F
+#define TDA10046H_CONFPLL3	 0x30
+#define TDA10046H_TIME_WREF1	 0x31
+#define TDA10046H_TIME_WREF2	 0x32
+#define TDA10046H_TIME_WREF3	 0x33
+#define TDA10046H_TIME_WREF4	 0x34
+#define TDA10046H_TIME_WREF5	 0x35
+
+#define TDA10045H_UNSURW_MSB	 0x31
+#define TDA10045H_UNSURW_LSB	 0x32
+#define TDA10045H_WREF_MSB	 0x33
+#define TDA10045H_WREF_MID	 0x34
+#define TDA10045H_WREF_LSB	 0x35
+#define TDA10045H_MUXOUT	 0x36
+#define TDA1004X_CONFADC2	 0x37
+
+#define TDA10045H_IOFFSET	 0x38
+
+#define TDA10046H_CONF_TRISTATE1 0x3B
+#define TDA10046H_CONF_TRISTATE2 0x3C
+#define TDA10046H_CONF_POLARITY	 0x3D
+#define TDA10046H_FREQ_OFFSET	 0x3E
+#define TDA10046H_GPIO_OUT_SEL	 0x41
+#define TDA10046H_GPIO_SELECT	 0x42
+#define TDA10046H_AGC_CONF	 0x43
+#define TDA10046H_AGC_THR	 0x44
+#define TDA10046H_AGC_RENORM	 0x45
+#define TDA10046H_AGC_GAINS	 0x46
+#define TDA10046H_AGC_TUN_MIN	 0x47
+#define TDA10046H_AGC_TUN_MAX	 0x48
+#define TDA10046H_AGC_IF_MIN	 0x49
+#define TDA10046H_AGC_IF_MAX	 0x4A
+
+#define TDA10046H_FREQ_PHY2_MSB	 0x4D
+#define TDA10046H_FREQ_PHY2_LSB	 0x4E
+
+#define TDA10046H_CVBER_CTRL	 0x4F
+#define TDA10046H_AGC_IF_LEVEL	 0x52
+#define TDA10046H_CODE_CPT	 0x57
+#define TDA10046H_CODE_IN	 0x58
+
+
+static int tda1004x_write_byteI(struct tda1004x_state *state, int reg, int data)
+{
+	int ret;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
+
+	dprintk("%s: reg=0x%x, data=0x%x\n", __func__, reg, data);
+
+	msg.addr = state->config->demod_address;
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
+			__func__, reg, data, ret);
+
+	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__,
+		reg, data, ret);
+	return (ret != 1) ? -1 : 0;
+}
+
+static int tda1004x_read_byte(struct tda1004x_state *state, int reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 },
+				{ .flags = I2C_M_RD, .buf = b1, .len = 1 }};
+
+	dprintk("%s: reg=0x%x\n", __func__, reg);
+
+	msg[0].addr = state->config->demod_address;
+	msg[1].addr = state->config->demod_address;
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg,
+			ret);
+		return -EINVAL;
+	}
+
+	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__,
+		reg, b1[0], ret);
+	return b1[0];
+}
+
+static int tda1004x_write_mask(struct tda1004x_state *state, int reg, int mask, int data)
+{
+	int val;
+	dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __func__, reg,
+		mask, data);
+
+	// read a byte and check
+	val = tda1004x_read_byte(state, reg);
+	if (val < 0)
+		return val;
+
+	// mask if off
+	val = val & ~mask;
+	val |= data & 0xff;
+
+	// write it out again
+	return tda1004x_write_byteI(state, reg, val);
+}
+
+static int tda1004x_write_buf(struct tda1004x_state *state, int reg, unsigned char *buf, int len)
+{
+	int i;
+	int result;
+
+	dprintk("%s: reg=0x%x, len=0x%x\n", __func__, reg, len);
+
+	result = 0;
+	for (i = 0; i < len; i++) {
+		result = tda1004x_write_byteI(state, reg + i, buf[i]);
+		if (result != 0)
+			break;
+	}
+
+	return result;
+}
+
+static int tda1004x_enable_tuner_i2c(struct tda1004x_state *state)
+{
+	int result;
+	dprintk("%s\n", __func__);
+
+	result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2);
+	msleep(20);
+	return result;
+}
+
+static int tda1004x_disable_tuner_i2c(struct tda1004x_state *state)
+{
+	dprintk("%s\n", __func__);
+
+	return tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 0);
+}
+
+static int tda10045h_set_bandwidth(struct tda1004x_state *state,
+				   u32 bandwidth)
+{
+	static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f };
+	static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb };
+	static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 };
+
+	switch (bandwidth) {
+	case 6000000:
+		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz));
+		break;
+
+	case 7000000:
+		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz));
+		break;
+
+	case 8000000:
+		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz));
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	tda1004x_write_byteI(state, TDA10045H_IOFFSET, 0);
+
+	return 0;
+}
+
+static int tda10046h_set_bandwidth(struct tda1004x_state *state,
+				   u32 bandwidth)
+{
+	static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 };
+	static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f };
+	static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d };
+
+	static u8 bandwidth_6mhz_48M[] = { 0x70, 0x02, 0x49, 0x24, 0x92 };
+	static u8 bandwidth_7mhz_48M[] = { 0x60, 0x02, 0xaa, 0xaa, 0xab };
+	static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 };
+	int tda10046_clk53m;
+
+	if ((state->config->if_freq == TDA10046_FREQ_045) ||
+	    (state->config->if_freq == TDA10046_FREQ_052))
+		tda10046_clk53m = 0;
+	else
+		tda10046_clk53m = 1;
+	switch (bandwidth) {
+	case 6000000:
+		if (tda10046_clk53m)
+			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M,
+						  sizeof(bandwidth_6mhz_53M));
+		else
+			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_48M,
+						  sizeof(bandwidth_6mhz_48M));
+		if (state->config->if_freq == TDA10046_FREQ_045) {
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a);
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xab);
+		}
+		break;
+
+	case 7000000:
+		if (tda10046_clk53m)
+			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M,
+						  sizeof(bandwidth_7mhz_53M));
+		else
+			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_48M,
+						  sizeof(bandwidth_7mhz_48M));
+		if (state->config->if_freq == TDA10046_FREQ_045) {
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
+		}
+		break;
+
+	case 8000000:
+		if (tda10046_clk53m)
+			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M,
+						  sizeof(bandwidth_8mhz_53M));
+		else
+			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_48M,
+						  sizeof(bandwidth_8mhz_48M));
+		if (state->config->if_freq == TDA10046_FREQ_045) {
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x55);
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tda1004x_do_upload(struct tda1004x_state *state,
+			      const unsigned char *mem, unsigned int len,
+			      u8 dspCodeCounterReg, u8 dspCodeInReg)
+{
+	u8 buf[65];
+	struct i2c_msg fw_msg = { .flags = 0, .buf = buf, .len = 0 };
+	int tx_size;
+	int pos = 0;
+
+	/* clear code counter */
+	tda1004x_write_byteI(state, dspCodeCounterReg, 0);
+	fw_msg.addr = state->config->demod_address;
+
+	buf[0] = dspCodeInReg;
+	while (pos != len) {
+		// work out how much to send this time
+		tx_size = len - pos;
+		if (tx_size > 0x10)
+			tx_size = 0x10;
+
+		// send the chunk
+		memcpy(buf + 1, mem + pos, tx_size);
+		fw_msg.len = tx_size + 1;
+		if (i2c_transfer(state->i2c, &fw_msg, 1) != 1) {
+			printk(KERN_ERR "tda1004x: Error during firmware upload\n");
+			return -EIO;
+		}
+		pos += tx_size;
+
+		dprintk("%s: fw_pos=0x%x\n", __func__, pos);
+	}
+	// give the DSP a chance to settle 03/10/05 Hac
+	msleep(100);
+
+	return 0;
+}
+
+static int tda1004x_check_upload_ok(struct tda1004x_state *state)
+{
+	u8 data1, data2;
+	unsigned long timeout;
+
+	if (state->demod_type == TDA1004X_DEMOD_TDA10046) {
+		timeout = jiffies + 2 * HZ;
+		while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) {
+			if (time_after(jiffies, timeout)) {
+				printk(KERN_ERR "tda1004x: timeout waiting for DSP ready\n");
+				break;
+			}
+			msleep(1);
+		}
+	} else
+		msleep(100);
+
+	// check upload was OK
+	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP
+	tda1004x_write_byteI(state, TDA1004X_DSP_CMD, 0x67);
+
+	data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1);
+	data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2);
+	if (data1 != 0x67 || data2 < 0x20 || data2 > 0x2e) {
+		printk(KERN_INFO "tda1004x: found firmware revision %x -- invalid\n", data2);
+		return -EIO;
+	}
+	printk(KERN_INFO "tda1004x: found firmware revision %x -- ok\n", data2);
+	return 0;
+}
+
+static int tda10045_fwupload(struct dvb_frontend* fe)
+{
+	struct tda1004x_state* state = fe->demodulator_priv;
+	int ret;
+	const struct firmware *fw;
+
+	/* don't re-upload unless necessary */
+	if (tda1004x_check_upload_ok(state) == 0)
+		return 0;
+
+	/* request the firmware, this will block until someone uploads it */
+	printk(KERN_INFO "tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE);
+	ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
+	if (ret) {
+		printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
+		return ret;
+	}
+
+	/* reset chip */
+	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0);
+	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8);
+	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0);
+	msleep(10);
+
+	/* set parameters */
+	tda10045h_set_bandwidth(state, 8000000);
+
+	ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN);
+	release_firmware(fw);
+	if (ret)
+		return ret;
+	printk(KERN_INFO "tda1004x: firmware upload complete\n");
+
+	/* wait for DSP to initialise */
+	/* DSPREADY doesn't seem to work on the TDA10045H */
+	msleep(100);
+
+	return tda1004x_check_upload_ok(state);
+}
+
+static void tda10046_init_plls(struct dvb_frontend* fe)
+{
+	struct tda1004x_state* state = fe->demodulator_priv;
+	int tda10046_clk53m;
+
+	if ((state->config->if_freq == TDA10046_FREQ_045) ||
+	    (state->config->if_freq == TDA10046_FREQ_052))
+		tda10046_clk53m = 0;
+	else
+		tda10046_clk53m = 1;
+
+	tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
+	if(tda10046_clk53m) {
+		printk(KERN_INFO "tda1004x: setting up plls for 53MHz sampling clock\n");
+		tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x08); // PLL M = 8
+	} else {
+		printk(KERN_INFO "tda1004x: setting up plls for 48MHz sampling clock\n");
+		tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3
+	}
+	if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
+		dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __func__);
+		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
+	} else {
+		dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __func__);
+		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3
+	}
+	if(tda10046_clk53m)
+		tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x67);
+	else
+		tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x72);
+	/* Note clock frequency is handled implicitly */
+	switch (state->config->if_freq) {
+	case TDA10046_FREQ_045:
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
+		break;
+	case TDA10046_FREQ_052:
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xc7);
+		break;
+	case TDA10046_FREQ_3617:
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x59);
+		break;
+	case TDA10046_FREQ_3613:
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f);
+		break;
+	}
+	tda10046h_set_bandwidth(state, 8000000); /* default bandwidth 8 MHz */
+	/* let the PLLs settle */
+	msleep(120);
+}
+
+static int tda10046_fwupload(struct dvb_frontend* fe)
+{
+	struct tda1004x_state* state = fe->demodulator_priv;
+	int ret, confc4;
+	const struct firmware *fw;
+
+	/* reset + wake up chip */
+	if (state->config->xtal_freq == TDA10046_XTAL_4M) {
+		confc4 = 0;
+	} else {
+		dprintk("%s: 16MHz Xtal, reducing I2C speed\n", __func__);
+		confc4 = 0x80;
+	}
+	tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4);
+
+	tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
+	/* set GPIO 1 and 3 */
+	if (state->config->gpio_config != TDA10046_GPTRI) {
+		tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0x33);
+		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, state->config->gpio_config &0x0f);
+	}
+	/* let the clocks recover from sleep */
+	msleep(10);
+
+	/* The PLLs need to be reprogrammed after sleep */
+	tda10046_init_plls(fe);
+	tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0);
+
+	/* don't re-upload unless necessary */
+	if (tda1004x_check_upload_ok(state) == 0)
+		return 0;
+
+	/*
+	   For i2c normal work, we need to slow down the bus speed.
+	   However, the slow down breaks the eeprom firmware load.
+	   So, use normal speed for eeprom booting and then restore the
+	   i2c speed after that. Tested with MSI TV @nyware A/D board,
+	   that comes with firmware version 29 inside their eeprom.
+
+	   It should also be noticed that no other I2C transfer should
+	   be in course while booting from eeprom, otherwise, tda10046
+	   goes into an instable state. So, proper locking are needed
+	   at the i2c bus master.
+	 */
+	printk(KERN_INFO "tda1004x: trying to boot from eeprom\n");
+	tda1004x_write_byteI(state, TDA1004X_CONFC4, 4);
+	msleep(300);
+	tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4);
+
+	/* Checks if eeprom firmware went without troubles */
+	if (tda1004x_check_upload_ok(state) == 0)
+		return 0;
+
+	/* eeprom firmware didn't work. Load one manually. */
+
+	if (state->config->request_firmware != NULL) {
+		/* request the firmware, this will block until someone uploads it */
+		printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
+		ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
+		if (ret) {
+			/* remain compatible to old bug: try to load with tda10045 image name */
+			ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
+			if (ret) {
+				printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
+				return ret;
+			} else {
+				printk(KERN_INFO "tda1004x: please rename the firmware file to %s\n",
+						  TDA10046_DEFAULT_FIRMWARE);
+			}
+		}
+	} else {
+		printk(KERN_ERR "tda1004x: no request function defined, can't upload from file\n");
+		return -EIO;
+	}
+	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
+	ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
+	release_firmware(fw);
+	return tda1004x_check_upload_ok(state);
+}
+
+static int tda1004x_encode_fec(int fec)
+{
+	// convert known FEC values
+	switch (fec) {
+	case FEC_1_2:
+		return 0;
+	case FEC_2_3:
+		return 1;
+	case FEC_3_4:
+		return 2;
+	case FEC_5_6:
+		return 3;
+	case FEC_7_8:
+		return 4;
+	}
+
+	// unsupported
+	return -EINVAL;
+}
+
+static int tda1004x_decode_fec(int tdafec)
+{
+	// convert known FEC values
+	switch (tdafec) {
+	case 0:
+		return FEC_1_2;
+	case 1:
+		return FEC_2_3;
+	case 2:
+		return FEC_3_4;
+	case 3:
+		return FEC_5_6;
+	case 4:
+		return FEC_7_8;
+	}
+
+	// unsupported
+	return -1;
+}
+
+static int tda1004x_write(struct dvb_frontend* fe, const u8 buf[], int len)
+{
+	struct tda1004x_state* state = fe->demodulator_priv;
+
+	if (len != 2)
+		return -EINVAL;
+
+	return tda1004x_write_byteI(state, buf[0], buf[1]);
+}
+
+static int tda10045_init(struct dvb_frontend* fe)
+{
+	struct tda1004x_state* state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	if (tda10045_fwupload(fe)) {
+		printk("tda1004x: firmware upload failed\n");
+		return -EIO;
+	}
+
+	tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
+
+	// tda setup
+	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
+	tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
+	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0); // set polarity of VAGC signal
+	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0x80); // enable pulse killer
+	tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); // enable auto offset
+	tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0x0); // no frequency offset
+	tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 0); // setup MPEG2 TS interface
+	tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0); // setup MPEG2 TS interface
+	tda1004x_write_mask(state, TDA1004X_VBER_MSB, 0xe0, 0xa0); // 10^6 VBER measurement bits
+	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x10, 0); // VAGC polarity
+	tda1004x_write_byteI(state, TDA1004X_CONFADC1, 0x2e);
+
+	tda1004x_write_mask(state, 0x1f, 0x01, state->config->invert_oclk);
+
+	return 0;
+}
+
+static int tda10046_init(struct dvb_frontend* fe)
+{
+	struct tda1004x_state* state = fe->demodulator_priv;
+	dprintk("%s\n", __func__);
+
+	if (tda10046_fwupload(fe)) {
+		printk("tda1004x: firmware upload failed\n");
+			return -EIO;
+	}
+
+	// tda setup
+	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
+	tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87);    // 100 ppm crystal, select HP stream
+	tda1004x_write_byteI(state, TDA1004X_CONFC1, 0x88);      // enable pulse killer
+
+	switch (state->config->agc_config) {
+	case TDA10046_AGC_DEFAULT:
+		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup
+		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
+		break;
+	case TDA10046_AGC_IFO_AUTO_NEG:
+		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
+		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
+		break;
+	case TDA10046_AGC_IFO_AUTO_POS:
+		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
+		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x00);  // set AGC polarities
+		break;
+	case TDA10046_AGC_TDA827X:
+		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02);   // AGC setup
+		tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70);    // AGC Threshold
+		tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
+		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
+		break;
+	}
+	if (state->config->ts_mode == 0) {
+		tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x40);
+		tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
+	} else {
+		tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x80);
+		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x10,
+							state->config->invert_oclk << 4);
+	}
+	tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
+	tda1004x_write_mask (state, TDA10046H_CONF_TRISTATE1, 0x3e, 0x38); // Turn IF AGC output on
+	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0);	  // }
+	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
+	tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0);	  // }
+	tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff);  // }
+	tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 0x12); // IF gain 2, TUN gain 1
+	tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits
+	tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
+	tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
+	// tda1004x_write_mask(state, 0x50, 0x80, 0x80);         // handle out of guard echoes
+
+	return 0;
+}
+
+static int tda1004x_set_fe(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
+	struct tda1004x_state* state = fe->demodulator_priv;
+	int tmp;
+	int inversion;
+
+	dprintk("%s\n", __func__);
+
+	if (state->demod_type == TDA1004X_DEMOD_TDA10046) {
+		// setup auto offset
+		tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10);
+		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x80, 0);
+		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0);
+
+		// disable agc_conf[2]
+		tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 0);
+	}
+
+	// set frequency
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	// Hardcoded to use auto as much as possible on the TDA10045 as it
+	// is very unreliable if AUTO mode is _not_ used.
+	if (state->demod_type == TDA1004X_DEMOD_TDA10045) {
+		fe_params->code_rate_HP = FEC_AUTO;
+		fe_params->guard_interval = GUARD_INTERVAL_AUTO;
+		fe_params->transmission_mode = TRANSMISSION_MODE_AUTO;
+	}
+
+	// Set standard params.. or put them to auto
+	if ((fe_params->code_rate_HP == FEC_AUTO) ||
+		(fe_params->code_rate_LP == FEC_AUTO) ||
+		(fe_params->modulation == QAM_AUTO) ||
+		(fe_params->hierarchy == HIERARCHY_AUTO)) {
+		tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1);	// enable auto
+		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0);	/* turn off modulation bits */
+		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0);	// turn off hierarchy bits
+		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x3f, 0);	// turn off FEC bits
+	} else {
+		tda1004x_write_mask(state, TDA1004X_AUTO, 1, 0);	// disable auto
+
+		// set HP FEC
+		tmp = tda1004x_encode_fec(fe_params->code_rate_HP);
+		if (tmp < 0)
+			return tmp;
+		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp);
+
+		// set LP FEC
+		tmp = tda1004x_encode_fec(fe_params->code_rate_LP);
+		if (tmp < 0)
+			return tmp;
+		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3);
+
+		/* set modulation */
+		switch (fe_params->modulation) {
+		case QPSK:
+			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0);
+			break;
+
+		case QAM_16:
+			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 1);
+			break;
+
+		case QAM_64:
+			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 2);
+			break;
+
+		default:
+			return -EINVAL;
+		}
+
+		// set hierarchy
+		switch (fe_params->hierarchy) {
+		case HIERARCHY_NONE:
+			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5);
+			break;
+
+		case HIERARCHY_1:
+			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 1 << 5);
+			break;
+
+		case HIERARCHY_2:
+			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 2 << 5);
+			break;
+
+		case HIERARCHY_4:
+			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 3 << 5);
+			break;
+
+		default:
+			return -EINVAL;
+		}
+	}
+
+	// set bandwidth
+	switch (state->demod_type) {
+	case TDA1004X_DEMOD_TDA10045:
+		tda10045h_set_bandwidth(state, fe_params->bandwidth_hz);
+		break;
+
+	case TDA1004X_DEMOD_TDA10046:
+		tda10046h_set_bandwidth(state, fe_params->bandwidth_hz);
+		break;
+	}
+
+	// set inversion
+	inversion = fe_params->inversion;
+	if (state->config->invert)
+		inversion = inversion ? INVERSION_OFF : INVERSION_ON;
+	switch (inversion) {
+	case INVERSION_OFF:
+		tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0);
+		break;
+
+	case INVERSION_ON:
+		tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0x20);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	// set guard interval
+	switch (fe_params->guard_interval) {
+	case GUARD_INTERVAL_1_32:
+		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
+		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
+		break;
+
+	case GUARD_INTERVAL_1_16:
+		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
+		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 1 << 2);
+		break;
+
+	case GUARD_INTERVAL_1_8:
+		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
+		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 2 << 2);
+		break;
+
+	case GUARD_INTERVAL_1_4:
+		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
+		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 3 << 2);
+		break;
+
+	case GUARD_INTERVAL_AUTO:
+		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 2);
+		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	// set transmission mode
+	switch (fe_params->transmission_mode) {
+	case TRANSMISSION_MODE_2K:
+		tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0);
+		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0 << 4);
+		break;
+
+	case TRANSMISSION_MODE_8K:
+		tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0);
+		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 1 << 4);
+		break;
+
+	case TRANSMISSION_MODE_AUTO:
+		tda1004x_write_mask(state, TDA1004X_AUTO, 4, 4);
+		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	// start the lock
+	switch (state->demod_type) {
+	case TDA1004X_DEMOD_TDA10045:
+		tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8);
+		tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0);
+		break;
+
+	case TDA1004X_DEMOD_TDA10046:
+		tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40);
+		msleep(1);
+		tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 1);
+		break;
+	}
+
+	msleep(10);
+
+	return 0;
+}
+
+static int tda1004x_get_fe(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
+	struct tda1004x_state* state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	// inversion status
+	fe_params->inversion = INVERSION_OFF;
+	if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20)
+		fe_params->inversion = INVERSION_ON;
+	if (state->config->invert)
+		fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON;
+
+	// bandwidth
+	switch (state->demod_type) {
+	case TDA1004X_DEMOD_TDA10045:
+		switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) {
+		case 0x14:
+			fe_params->bandwidth_hz = 8000000;
+			break;
+		case 0xdb:
+			fe_params->bandwidth_hz = 7000000;
+			break;
+		case 0x4f:
+			fe_params->bandwidth_hz = 6000000;
+			break;
+		}
+		break;
+	case TDA1004X_DEMOD_TDA10046:
+		switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) {
+		case 0x5c:
+		case 0x54:
+			fe_params->bandwidth_hz = 8000000;
+			break;
+		case 0x6a:
+		case 0x60:
+			fe_params->bandwidth_hz = 7000000;
+			break;
+		case 0x7b:
+		case 0x70:
+			fe_params->bandwidth_hz = 6000000;
+			break;
+		}
+		break;
+	}
+
+	// FEC
+	fe_params->code_rate_HP =
+	    tda1004x_decode_fec(tda1004x_read_byte(state, TDA1004X_OUT_CONF2) & 7);
+	fe_params->code_rate_LP =
+	    tda1004x_decode_fec((tda1004x_read_byte(state, TDA1004X_OUT_CONF2) >> 3) & 7);
+
+	/* modulation */
+	switch (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 3) {
+	case 0:
+		fe_params->modulation = QPSK;
+		break;
+	case 1:
+		fe_params->modulation = QAM_16;
+		break;
+	case 2:
+		fe_params->modulation = QAM_64;
+		break;
+	}
+
+	// transmission mode
+	fe_params->transmission_mode = TRANSMISSION_MODE_2K;
+	if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10)
+		fe_params->transmission_mode = TRANSMISSION_MODE_8K;
+
+	// guard interval
+	switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) {
+	case 0:
+		fe_params->guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		fe_params->guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		fe_params->guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		fe_params->guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	}
+
+	// hierarchy
+	switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) {
+	case 0:
+		fe_params->hierarchy = HIERARCHY_NONE;
+		break;
+	case 1:
+		fe_params->hierarchy = HIERARCHY_1;
+		break;
+	case 2:
+		fe_params->hierarchy = HIERARCHY_2;
+		break;
+	case 3:
+		fe_params->hierarchy = HIERARCHY_4;
+		break;
+	}
+
+	return 0;
+}
+
+static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status)
+{
+	struct tda1004x_state* state = fe->demodulator_priv;
+	int status;
+	int cber;
+	int vber;
+
+	dprintk("%s\n", __func__);
+
+	// read status
+	status = tda1004x_read_byte(state, TDA1004X_STATUS_CD);
+	if (status == -1)
+		return -EIO;
+
+	// decode
+	*fe_status = 0;
+	if (status & 4)
+		*fe_status |= FE_HAS_SIGNAL;
+	if (status & 2)
+		*fe_status |= FE_HAS_CARRIER;
+	if (status & 8)
+		*fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+
+	// if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi
+	// is getting anything valid
+	if (!(*fe_status & FE_HAS_VITERBI)) {
+		// read the CBER
+		cber = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
+		if (cber == -1)
+			return -EIO;
+		status = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
+		if (status == -1)
+			return -EIO;
+		cber |= (status << 8);
+		// The address 0x20 should be read to cope with a TDA10046 bug
+		tda1004x_read_byte(state, TDA1004X_CBER_RESET);
+
+		if (cber != 65535)
+			*fe_status |= FE_HAS_VITERBI;
+	}
+
+	// if we DO have some valid VITERBI output, but don't already have SYNC
+	// bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid.
+	if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) {
+		// read the VBER
+		vber = tda1004x_read_byte(state, TDA1004X_VBER_LSB);
+		if (vber == -1)
+			return -EIO;
+		status = tda1004x_read_byte(state, TDA1004X_VBER_MID);
+		if (status == -1)
+			return -EIO;
+		vber |= (status << 8);
+		status = tda1004x_read_byte(state, TDA1004X_VBER_MSB);
+		if (status == -1)
+			return -EIO;
+		vber |= (status & 0x0f) << 16;
+		// The CVBER_LUT should be read to cope with TDA10046 hardware bug
+		tda1004x_read_byte(state, TDA1004X_CVBER_LUT);
+
+		// if RS has passed some valid TS packets, then we must be
+		// getting some SYNC bytes
+		if (vber < 16632)
+			*fe_status |= FE_HAS_SYNC;
+	}
+
+	// success
+	dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
+	return 0;
+}
+
+static int tda1004x_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
+{
+	struct tda1004x_state* state = fe->demodulator_priv;
+	int tmp;
+	int reg = 0;
+
+	dprintk("%s\n", __func__);
+
+	// determine the register to use
+	switch (state->demod_type) {
+	case TDA1004X_DEMOD_TDA10045:
+		reg = TDA10045H_S_AGC;
+		break;
+
+	case TDA1004X_DEMOD_TDA10046:
+		reg = TDA10046H_AGC_IF_LEVEL;
+		break;
+	}
+
+	// read it
+	tmp = tda1004x_read_byte(state, reg);
+	if (tmp < 0)
+		return -EIO;
+
+	*signal = (tmp << 8) | tmp;
+	dprintk("%s: signal=0x%x\n", __func__, *signal);
+	return 0;
+}
+
+static int tda1004x_read_snr(struct dvb_frontend* fe, u16 * snr)
+{
+	struct tda1004x_state* state = fe->demodulator_priv;
+	int tmp;
+
+	dprintk("%s\n", __func__);
+
+	// read it
+	tmp = tda1004x_read_byte(state, TDA1004X_SNR);
+	if (tmp < 0)
+		return -EIO;
+	tmp = 255 - tmp;
+
+	*snr = ((tmp << 8) | tmp);
+	dprintk("%s: snr=0x%x\n", __func__, *snr);
+	return 0;
+}
+
+static int tda1004x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct tda1004x_state* state = fe->demodulator_priv;
+	int tmp;
+	int tmp2;
+	int counter;
+
+	dprintk("%s\n", __func__);
+
+	// read the UCBLOCKS and reset
+	counter = 0;
+	tmp = tda1004x_read_byte(state, TDA1004X_UNCOR);
+	if (tmp < 0)
+		return -EIO;
+	tmp &= 0x7f;
+	while (counter++ < 5) {
+		tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
+		tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
+		tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
+
+		tmp2 = tda1004x_read_byte(state, TDA1004X_UNCOR);
+		if (tmp2 < 0)
+			return -EIO;
+		tmp2 &= 0x7f;
+		if ((tmp2 < tmp) || (tmp2 == 0))
+			break;
+	}
+
+	if (tmp != 0x7f)
+		*ucblocks = tmp;
+	else
+		*ucblocks = 0xffffffff;
+
+	dprintk("%s: ucblocks=0x%x\n", __func__, *ucblocks);
+	return 0;
+}
+
+static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct tda1004x_state* state = fe->demodulator_priv;
+	int tmp;
+
+	dprintk("%s\n", __func__);
+
+	// read it in
+	tmp = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
+	if (tmp < 0)
+		return -EIO;
+	*ber = tmp << 1;
+	tmp = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
+	if (tmp < 0)
+		return -EIO;
+	*ber |= (tmp << 9);
+	// The address 0x20 should be read to cope with a TDA10046 bug
+	tda1004x_read_byte(state, TDA1004X_CBER_RESET);
+
+	dprintk("%s: ber=0x%x\n", __func__, *ber);
+	return 0;
+}
+
+static int tda1004x_sleep(struct dvb_frontend* fe)
+{
+	struct tda1004x_state* state = fe->demodulator_priv;
+	int gpio_conf;
+
+	switch (state->demod_type) {
+	case TDA1004X_DEMOD_TDA10045:
+		tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0x10);
+		break;
+
+	case TDA1004X_DEMOD_TDA10046:
+		/* set outputs to tristate */
+		tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
+		/* invert GPIO 1 and 3 if desired*/
+		gpio_conf = state->config->gpio_config;
+		if (gpio_conf >= TDA10046_GP00_I)
+			tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f,
+							(gpio_conf & 0x0f) ^ 0x0a);
+
+		tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0xc0);
+		tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
+		break;
+	}
+
+	return 0;
+}
+
+static int tda1004x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct tda1004x_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		return tda1004x_enable_tuner_i2c(state);
+	} else {
+		return tda1004x_disable_tuner_i2c(state);
+	}
+}
+
+static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+	fesettings->min_delay_ms = 800;
+	/* Drift compensation makes no sense for DVB-T */
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+	return 0;
+}
+
+static void tda1004x_release(struct dvb_frontend* fe)
+{
+	struct tda1004x_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops tda10045_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "Philips TDA10045H DVB-T",
+		.frequency_min = 51000000,
+		.frequency_max = 858000000,
+		.frequency_stepsize = 166667,
+		.caps =
+		    FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		    FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+		    FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+		    FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
+	},
+
+	.release = tda1004x_release,
+
+	.init = tda10045_init,
+	.sleep = tda1004x_sleep,
+	.write = tda1004x_write,
+	.i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
+
+	.set_frontend = tda1004x_set_fe,
+	.get_frontend = tda1004x_get_fe,
+	.get_tune_settings = tda1004x_get_tune_settings,
+
+	.read_status = tda1004x_read_status,
+	.read_ber = tda1004x_read_ber,
+	.read_signal_strength = tda1004x_read_signal_strength,
+	.read_snr = tda1004x_read_snr,
+	.read_ucblocks = tda1004x_read_ucblocks,
+};
+
+struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
+				     struct i2c_adapter* i2c)
+{
+	struct tda1004x_state *state;
+	int id;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
+	if (!state) {
+		printk(KERN_ERR "Can't allocate memory for tda10045 state\n");
+		return NULL;
+	}
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->demod_type = TDA1004X_DEMOD_TDA10045;
+
+	/* check if the demod is there */
+	id = tda1004x_read_byte(state, TDA1004X_CHIPID);
+	if (id < 0) {
+		printk(KERN_ERR "tda10045: chip is not answering. Giving up.\n");
+		kfree(state);
+		return NULL;
+	}
+
+	if (id != 0x25) {
+		printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id);
+		kfree(state);
+		return NULL;
+	}
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+}
+
+static struct dvb_frontend_ops tda10046_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "Philips TDA10046H DVB-T",
+		.frequency_min = 51000000,
+		.frequency_max = 858000000,
+		.frequency_stepsize = 166667,
+		.caps =
+		    FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		    FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+		    FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+		    FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
+	},
+
+	.release = tda1004x_release,
+
+	.init = tda10046_init,
+	.sleep = tda1004x_sleep,
+	.write = tda1004x_write,
+	.i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
+
+	.set_frontend = tda1004x_set_fe,
+	.get_frontend = tda1004x_get_fe,
+	.get_tune_settings = tda1004x_get_tune_settings,
+
+	.read_status = tda1004x_read_status,
+	.read_ber = tda1004x_read_ber,
+	.read_signal_strength = tda1004x_read_signal_strength,
+	.read_snr = tda1004x_read_snr,
+	.read_ucblocks = tda1004x_read_ucblocks,
+};
+
+struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
+				     struct i2c_adapter* i2c)
+{
+	struct tda1004x_state *state;
+	int id;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
+	if (!state) {
+		printk(KERN_ERR "Can't allocate memory for tda10046 state\n");
+		return NULL;
+	}
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->demod_type = TDA1004X_DEMOD_TDA10046;
+
+	/* check if the demod is there */
+	id = tda1004x_read_byte(state, TDA1004X_CHIPID);
+	if (id < 0) {
+		printk(KERN_ERR "tda10046: chip is not answering. Giving up.\n");
+		kfree(state);
+		return NULL;
+	}
+	if (id != 0x46) {
+		printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id);
+		kfree(state);
+		return NULL;
+	}
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+}
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Philips TDA10045H & TDA10046H DVB-T Demodulator");
+MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(tda10045_attach);
+EXPORT_SYMBOL(tda10046_attach);
diff --git a/drivers/media/dvb-frontends/tda1004x.h b/drivers/media/dvb-frontends/tda1004x.h
new file mode 100644
index 0000000..4e27ffb
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda1004x.h
@@ -0,0 +1,149 @@
+  /*
+     Driver for Philips tda1004xh OFDM Frontend
+
+     (c) 2004 Andrew de Quincey
+
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+     the Free Software Foundation; either version 2 of the License, or
+     (at your option) any later version.
+
+     This program is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+     GNU General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, write to the Free Software
+     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   */
+
+#ifndef TDA1004X_H
+#define TDA1004X_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+enum tda10046_xtal {
+	TDA10046_XTAL_4M,
+	TDA10046_XTAL_16M,
+};
+
+enum tda10046_agc {
+	TDA10046_AGC_DEFAULT,		/* original configuration */
+	TDA10046_AGC_IFO_AUTO_NEG,	/* IF AGC only, automatic, negtive */
+	TDA10046_AGC_IFO_AUTO_POS,	/* IF AGC only, automatic, positive */
+	TDA10046_AGC_TDA827X,		/* IF AGC only, special setup for tda827x */
+};
+
+/* Many (hybrid) boards use GPIO 1 and 3
+	GPIO1	analog - dvb switch
+	GPIO3	firmware eeprom address switch
+*/
+enum tda10046_gpio {
+	TDA10046_GPTRI  = 0x00,		/* All GPIOs tristate */
+	TDA10046_GP00   = 0x40,		/* GPIO3=0, GPIO1=0 */
+	TDA10046_GP01   = 0x42,		/* GPIO3=0, GPIO1=1 */
+	TDA10046_GP10   = 0x48,		/* GPIO3=1, GPIO1=0 */
+	TDA10046_GP11   = 0x4a,		/* GPIO3=1, GPIO1=1 */
+	TDA10046_GP00_I = 0x80,		/* GPIO3=0, GPIO1=0, invert in sleep mode*/
+	TDA10046_GP01_I = 0x82,		/* GPIO3=0, GPIO1=1, invert in sleep mode */
+	TDA10046_GP10_I = 0x88,		/* GPIO3=1, GPIO1=0, invert in sleep mode */
+	TDA10046_GP11_I = 0x8a,		/* GPIO3=1, GPIO1=1, invert in sleep mode */
+};
+
+enum tda10046_if {
+	TDA10046_FREQ_3617,		/* original config, 36,166 MHZ */
+	TDA10046_FREQ_3613,		/* 36,13 MHZ */
+	TDA10046_FREQ_045,		/* low IF, 4.0, 4.5, or 5.0 MHZ */
+	TDA10046_FREQ_052,		/* low IF, 5.1667 MHZ for tda9889 */
+};
+
+enum tda10046_tsout {
+	TDA10046_TS_PARALLEL  = 0x00,	/* parallel transport stream, default */
+	TDA10046_TS_SERIAL    = 0x01,	/* serial transport stream */
+};
+
+struct tda1004x_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* does the "inversion" need inverted? */
+	u8 invert;
+
+	/* Does the OCLK signal need inverted? */
+	u8 invert_oclk;
+
+	/* parallel or serial transport stream */
+	enum tda10046_tsout ts_mode;
+
+	/* Xtal frequency, 4 or 16MHz*/
+	enum tda10046_xtal xtal_freq;
+
+	/* IF frequency */
+	enum tda10046_if if_freq;
+
+	/* AGC configuration */
+	enum tda10046_agc agc_config;
+
+	/* setting of GPIO1 and 3 */
+	enum tda10046_gpio gpio_config;
+
+	/* slave address and configuration of the tuner */
+	u8 tuner_address;
+	u8 antenna_switch;
+
+	/* if the board uses another I2c Bridge (tda8290), its address */
+	u8 i2c_gate;
+
+	/* request firmware for device */
+	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+};
+
+enum tda1004x_demod {
+	TDA1004X_DEMOD_TDA10045,
+	TDA1004X_DEMOD_TDA10046,
+};
+
+struct tda1004x_state {
+	struct i2c_adapter* i2c;
+	const struct tda1004x_config* config;
+	struct dvb_frontend frontend;
+
+	/* private demod data */
+	enum tda1004x_demod demod_type;
+};
+
+#if defined(CONFIG_DVB_TDA1004X) || (defined(CONFIG_DVB_TDA1004X_MODULE) && defined(MODULE))
+extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
+					    struct i2c_adapter* i2c);
+
+extern struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
+					    struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
+					    struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+static inline struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
+					    struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TDA1004X
+
+static inline int tda1004x_writereg(struct dvb_frontend *fe, u8 reg, u8 val) {
+	int r = 0;
+	u8 buf[] = {reg, val};
+	if (fe->ops.write)
+		r = fe->ops.write(fe, buf, 2);
+	return r;
+}
+
+#endif // TDA1004X_H
diff --git a/drivers/media/dvb-frontends/tda10071.c b/drivers/media/dvb-frontends/tda10071.c
new file mode 100644
index 0000000..703c3d0
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda10071.c
@@ -0,0 +1,1284 @@
+/*
+ * NXP TDA10071 + Conexant CX24118A DVB-S/S2 demodulator + tuner driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "tda10071_priv.h"
+
+static struct dvb_frontend_ops tda10071_ops;
+
+/* write multiple registers */
+static int tda10071_wr_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
+	int len)
+{
+	int ret;
+	u8 buf[len+1];
+	struct i2c_msg msg[1] = {
+		{
+			.addr = priv->cfg.i2c_address,
+			.flags = 0,
+			.len = sizeof(buf),
+			.buf = buf,
+		}
+	};
+
+	buf[0] = reg;
+	memcpy(&buf[1], val, len);
+
+	ret = i2c_transfer(priv->i2c, msg, 1);
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \
+				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+/* read multiple registers */
+static int tda10071_rd_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
+	int len)
+{
+	int ret;
+	u8 buf[len];
+	struct i2c_msg msg[2] = {
+		{
+			.addr = priv->cfg.i2c_address,
+			.flags = 0,
+			.len = 1,
+			.buf = &reg,
+		}, {
+			.addr = priv->cfg.i2c_address,
+			.flags = I2C_M_RD,
+			.len = sizeof(buf),
+			.buf = buf,
+		}
+	};
+
+	ret = i2c_transfer(priv->i2c, msg, 2);
+	if (ret == 2) {
+		memcpy(val, buf, len);
+		ret = 0;
+	} else {
+		dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \
+				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+/* write single register */
+static int tda10071_wr_reg(struct tda10071_priv *priv, u8 reg, u8 val)
+{
+	return tda10071_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+static int tda10071_rd_reg(struct tda10071_priv *priv, u8 reg, u8 *val)
+{
+	return tda10071_rd_regs(priv, reg, val, 1);
+}
+
+/* write single register with mask */
+int tda10071_wr_reg_mask(struct tda10071_priv *priv, u8 reg, u8 val, u8 mask)
+{
+	int ret;
+	u8 tmp;
+
+	/* no need for read if whole reg is written */
+	if (mask != 0xff) {
+		ret = tda10071_rd_regs(priv, reg, &tmp, 1);
+		if (ret)
+			return ret;
+
+		val &= mask;
+		tmp &= ~mask;
+		val |= tmp;
+	}
+
+	return tda10071_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register with mask */
+int tda10071_rd_reg_mask(struct tda10071_priv *priv, u8 reg, u8 *val, u8 mask)
+{
+	int ret, i;
+	u8 tmp;
+
+	ret = tda10071_rd_regs(priv, reg, &tmp, 1);
+	if (ret)
+		return ret;
+
+	tmp &= mask;
+
+	/* find position of the first bit */
+	for (i = 0; i < 8; i++) {
+		if ((mask >> i) & 0x01)
+			break;
+	}
+	*val = tmp >> i;
+
+	return 0;
+}
+
+/* execute firmware command */
+static int tda10071_cmd_execute(struct tda10071_priv *priv,
+	struct tda10071_cmd *cmd)
+{
+	int ret, i;
+	u8 tmp;
+
+	if (!priv->warm) {
+		ret = -EFAULT;
+		goto error;
+	}
+
+	/* write cmd and args for firmware */
+	ret = tda10071_wr_regs(priv, 0x00, cmd->args, cmd->len);
+	if (ret)
+		goto error;
+
+	/* start cmd execution */
+	ret = tda10071_wr_reg(priv, 0x1f, 1);
+	if (ret)
+		goto error;
+
+	/* wait cmd execution terminate */
+	for (i = 1000, tmp = 1; i && tmp; i--) {
+		ret = tda10071_rd_reg(priv, 0x1f, &tmp);
+		if (ret)
+			goto error;
+
+		usleep_range(200, 5000);
+	}
+
+	dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
+
+	if (i == 0) {
+		ret = -ETIMEDOUT;
+		goto error;
+	}
+
+	return ret;
+error:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int tda10071_set_tone(struct dvb_frontend *fe,
+	fe_sec_tone_mode_t fe_sec_tone_mode)
+{
+	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_cmd cmd;
+	int ret;
+	u8 tone;
+
+	if (!priv->warm) {
+		ret = -EFAULT;
+		goto error;
+	}
+
+	dev_dbg(&priv->i2c->dev, "%s: tone_mode=%d\n", __func__,
+			fe_sec_tone_mode);
+
+	switch (fe_sec_tone_mode) {
+	case SEC_TONE_ON:
+		tone = 1;
+		break;
+	case SEC_TONE_OFF:
+		tone = 0;
+		break;
+	default:
+		dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_tone_mode\n",
+				__func__);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	cmd.args[0] = CMD_LNB_PCB_CONFIG;
+	cmd.args[1] = 0;
+	cmd.args[2] = 0x00;
+	cmd.args[3] = 0x00;
+	cmd.args[4] = tone;
+	cmd.len = 5;
+	ret = tda10071_cmd_execute(priv, &cmd);
+	if (ret)
+		goto error;
+
+	return ret;
+error:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int tda10071_set_voltage(struct dvb_frontend *fe,
+	fe_sec_voltage_t fe_sec_voltage)
+{
+	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_cmd cmd;
+	int ret;
+	u8 voltage;
+
+	if (!priv->warm) {
+		ret = -EFAULT;
+		goto error;
+	}
+
+	dev_dbg(&priv->i2c->dev, "%s: voltage=%d\n", __func__, fe_sec_voltage);
+
+	switch (fe_sec_voltage) {
+	case SEC_VOLTAGE_13:
+		voltage = 0;
+		break;
+	case SEC_VOLTAGE_18:
+		voltage = 1;
+		break;
+	case SEC_VOLTAGE_OFF:
+		voltage = 0;
+		break;
+	default:
+		dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_voltage\n",
+				__func__);
+		ret = -EINVAL;
+		goto error;
+	};
+
+	cmd.args[0] = CMD_LNB_SET_DC_LEVEL;
+	cmd.args[1] = 0;
+	cmd.args[2] = voltage;
+	cmd.len = 3;
+	ret = tda10071_cmd_execute(priv, &cmd);
+	if (ret)
+		goto error;
+
+	return ret;
+error:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int tda10071_diseqc_send_master_cmd(struct dvb_frontend *fe,
+	struct dvb_diseqc_master_cmd *diseqc_cmd)
+{
+	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_cmd cmd;
+	int ret, i;
+	u8 tmp;
+
+	if (!priv->warm) {
+		ret = -EFAULT;
+		goto error;
+	}
+
+	dev_dbg(&priv->i2c->dev, "%s: msg_len=%d\n", __func__,
+			diseqc_cmd->msg_len);
+
+	if (diseqc_cmd->msg_len < 3 || diseqc_cmd->msg_len > 6) {
+		ret = -EINVAL;
+		goto error;
+	}
+
+	/* wait LNB TX */
+	for (i = 500, tmp = 0; i && !tmp; i--) {
+		ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x01);
+		if (ret)
+			goto error;
+
+		usleep_range(10000, 20000);
+	}
+
+	dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
+
+	if (i == 0) {
+		ret = -ETIMEDOUT;
+		goto error;
+	}
+
+	ret = tda10071_wr_reg_mask(priv, 0x47, 0x00, 0x01);
+	if (ret)
+		goto error;
+
+	cmd.args[0] = CMD_LNB_SEND_DISEQC;
+	cmd.args[1] = 0;
+	cmd.args[2] = 0;
+	cmd.args[3] = 0;
+	cmd.args[4] = 2;
+	cmd.args[5] = 0;
+	cmd.args[6] = diseqc_cmd->msg_len;
+	memcpy(&cmd.args[7], diseqc_cmd->msg, diseqc_cmd->msg_len);
+	cmd.len = 7 + diseqc_cmd->msg_len;
+	ret = tda10071_cmd_execute(priv, &cmd);
+	if (ret)
+		goto error;
+
+	return ret;
+error:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int tda10071_diseqc_recv_slave_reply(struct dvb_frontend *fe,
+	struct dvb_diseqc_slave_reply *reply)
+{
+	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_cmd cmd;
+	int ret, i;
+	u8 tmp;
+
+	if (!priv->warm) {
+		ret = -EFAULT;
+		goto error;
+	}
+
+	dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
+
+	/* wait LNB RX */
+	for (i = 500, tmp = 0; i && !tmp; i--) {
+		ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x02);
+		if (ret)
+			goto error;
+
+		usleep_range(10000, 20000);
+	}
+
+	dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
+
+	if (i == 0) {
+		ret = -ETIMEDOUT;
+		goto error;
+	}
+
+	/* reply len */
+	ret = tda10071_rd_reg(priv, 0x46, &tmp);
+	if (ret)
+		goto error;
+
+	reply->msg_len = tmp & 0x1f; /* [4:0] */;
+	if (reply->msg_len > sizeof(reply->msg))
+		reply->msg_len = sizeof(reply->msg); /* truncate API max */
+
+	/* read reply */
+	cmd.args[0] = CMD_LNB_UPDATE_REPLY;
+	cmd.args[1] = 0;
+	cmd.len = 2;
+	ret = tda10071_cmd_execute(priv, &cmd);
+	if (ret)
+		goto error;
+
+	ret = tda10071_rd_regs(priv, cmd.len, reply->msg, reply->msg_len);
+	if (ret)
+		goto error;
+
+	return ret;
+error:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int tda10071_diseqc_send_burst(struct dvb_frontend *fe,
+	fe_sec_mini_cmd_t fe_sec_mini_cmd)
+{
+	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_cmd cmd;
+	int ret, i;
+	u8 tmp, burst;
+
+	if (!priv->warm) {
+		ret = -EFAULT;
+		goto error;
+	}
+
+	dev_dbg(&priv->i2c->dev, "%s: fe_sec_mini_cmd=%d\n", __func__,
+			fe_sec_mini_cmd);
+
+	switch (fe_sec_mini_cmd) {
+	case SEC_MINI_A:
+		burst = 0;
+		break;
+	case SEC_MINI_B:
+		burst = 1;
+		break;
+	default:
+		dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_mini_cmd\n",
+				__func__);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	/* wait LNB TX */
+	for (i = 500, tmp = 0; i && !tmp; i--) {
+		ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x01);
+		if (ret)
+			goto error;
+
+		usleep_range(10000, 20000);
+	}
+
+	dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
+
+	if (i == 0) {
+		ret = -ETIMEDOUT;
+		goto error;
+	}
+
+	ret = tda10071_wr_reg_mask(priv, 0x47, 0x00, 0x01);
+	if (ret)
+		goto error;
+
+	cmd.args[0] = CMD_LNB_SEND_TONEBURST;
+	cmd.args[1] = 0;
+	cmd.args[2] = burst;
+	cmd.len = 3;
+	ret = tda10071_cmd_execute(priv, &cmd);
+	if (ret)
+		goto error;
+
+	return ret;
+error:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int tda10071_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct tda10071_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 tmp;
+
+	*status = 0;
+
+	if (!priv->warm) {
+		ret = 0;
+		goto error;
+	}
+
+	ret = tda10071_rd_reg(priv, 0x39, &tmp);
+	if (ret)
+		goto error;
+
+	if (tmp & 0x01) /* tuner PLL */
+		*status |= FE_HAS_SIGNAL;
+	if (tmp & 0x02) /* demod PLL */
+		*status |= FE_HAS_CARRIER;
+	if (tmp & 0x04) /* viterbi or LDPC*/
+		*status |= FE_HAS_VITERBI;
+	if (tmp & 0x08) /* RS or BCH */
+		*status |= FE_HAS_SYNC | FE_HAS_LOCK;
+
+	priv->fe_status = *status;
+
+	return ret;
+error:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int tda10071_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct tda10071_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 buf[2];
+
+	if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
+		*snr = 0;
+		ret = 0;
+		goto error;
+	}
+
+	ret = tda10071_rd_regs(priv, 0x3a, buf, 2);
+	if (ret)
+		goto error;
+
+	/* Es/No dBx10 */
+	*snr = buf[0] << 8 | buf[1];
+
+	return ret;
+error:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int tda10071_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_cmd cmd;
+	int ret;
+	u8 tmp;
+
+	if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
+		*strength = 0;
+		ret = 0;
+		goto error;
+	}
+
+	cmd.args[0] = CMD_GET_AGCACC;
+	cmd.args[1] = 0;
+	cmd.len = 2;
+	ret = tda10071_cmd_execute(priv, &cmd);
+	if (ret)
+		goto error;
+
+	/* input power estimate dBm */
+	ret = tda10071_rd_reg(priv, 0x50, &tmp);
+	if (ret)
+		goto error;
+
+	if (tmp < 181)
+		tmp = 181; /* -75 dBm */
+	else if (tmp > 236)
+		tmp = 236; /* -20 dBm */
+
+	/* scale value to 0x0000-0xffff */
+	*strength = (tmp-181) * 0xffff / (236-181);
+
+	return ret;
+error:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_cmd cmd;
+	int ret, i, len;
+	u8 tmp, reg, buf[8];
+
+	if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
+		*ber = priv->ber = 0;
+		ret = 0;
+		goto error;
+	}
+
+	switch (priv->delivery_system) {
+	case SYS_DVBS:
+		reg = 0x4c;
+		len = 8;
+		i = 1;
+		break;
+	case SYS_DVBS2:
+		reg = 0x4d;
+		len = 4;
+		i = 0;
+		break;
+	default:
+		*ber = priv->ber = 0;
+		return 0;
+	}
+
+	ret = tda10071_rd_reg(priv, reg, &tmp);
+	if (ret)
+		goto error;
+
+	if (priv->meas_count[i] == tmp) {
+		dev_dbg(&priv->i2c->dev, "%s: meas not ready=%02x\n", __func__,
+				tmp);
+		*ber = priv->ber;
+		return 0;
+	} else {
+		priv->meas_count[i] = tmp;
+	}
+
+	cmd.args[0] = CMD_BER_UPDATE_COUNTERS;
+	cmd.args[1] = 0;
+	cmd.args[2] = i;
+	cmd.len = 3;
+	ret = tda10071_cmd_execute(priv, &cmd);
+	if (ret)
+		goto error;
+
+	ret = tda10071_rd_regs(priv, cmd.len, buf, len);
+	if (ret)
+		goto error;
+
+	if (priv->delivery_system == SYS_DVBS) {
+		*ber = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+		priv->ucb += (buf[4] << 8) | buf[5];
+	} else {
+		*ber = (buf[0] << 8) | buf[1];
+	}
+	priv->ber = *ber;
+
+	return ret;
+error:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int tda10071_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct tda10071_priv *priv = fe->demodulator_priv;
+	int ret = 0;
+
+	if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
+		*ucblocks = 0;
+		goto error;
+	}
+
+	/* UCB is updated when BER is read. Assume BER is read anyway. */
+
+	*ucblocks = priv->ucb;
+
+	return ret;
+error:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int tda10071_set_frontend(struct dvb_frontend *fe)
+{
+	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_cmd cmd;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i;
+	u8 mode, rolloff, pilot, inversion, div;
+
+	dev_dbg(&priv->i2c->dev, "%s: delivery_system=%d modulation=%d " \
+		"frequency=%d symbol_rate=%d inversion=%d pilot=%d " \
+		"rolloff=%d\n", __func__, c->delivery_system, c->modulation,
+		c->frequency, c->symbol_rate, c->inversion, c->pilot,
+		c->rolloff);
+
+	priv->delivery_system = SYS_UNDEFINED;
+
+	if (!priv->warm) {
+		ret = -EFAULT;
+		goto error;
+	}
+
+	switch (c->inversion) {
+	case INVERSION_OFF:
+		inversion = 1;
+		break;
+	case INVERSION_ON:
+		inversion = 0;
+		break;
+	case INVERSION_AUTO:
+		/* 2 = auto; try first on then off
+		 * 3 = auto; try first off then on */
+		inversion = 3;
+		break;
+	default:
+		dev_dbg(&priv->i2c->dev, "%s: invalid inversion\n", __func__);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	switch (c->delivery_system) {
+	case SYS_DVBS:
+		rolloff = 0;
+		pilot = 2;
+		break;
+	case SYS_DVBS2:
+		switch (c->rolloff) {
+		case ROLLOFF_20:
+			rolloff = 2;
+			break;
+		case ROLLOFF_25:
+			rolloff = 1;
+			break;
+		case ROLLOFF_35:
+			rolloff = 0;
+			break;
+		case ROLLOFF_AUTO:
+		default:
+			dev_dbg(&priv->i2c->dev, "%s: invalid rolloff\n",
+					__func__);
+			ret = -EINVAL;
+			goto error;
+		}
+
+		switch (c->pilot) {
+		case PILOT_OFF:
+			pilot = 0;
+			break;
+		case PILOT_ON:
+			pilot = 1;
+			break;
+		case PILOT_AUTO:
+			pilot = 2;
+			break;
+		default:
+			dev_dbg(&priv->i2c->dev, "%s: invalid pilot\n",
+					__func__);
+			ret = -EINVAL;
+			goto error;
+		}
+		break;
+	default:
+		dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n",
+				__func__);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	for (i = 0, mode = 0xff; i < ARRAY_SIZE(TDA10071_MODCOD); i++) {
+		if (c->delivery_system == TDA10071_MODCOD[i].delivery_system &&
+			c->modulation == TDA10071_MODCOD[i].modulation &&
+			c->fec_inner == TDA10071_MODCOD[i].fec) {
+			mode = TDA10071_MODCOD[i].val;
+			dev_dbg(&priv->i2c->dev, "%s: mode found=%02x\n",
+					__func__, mode);
+			break;
+		}
+	}
+
+	if (mode == 0xff) {
+		dev_dbg(&priv->i2c->dev, "%s: invalid parameter combination\n",
+				__func__);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	if (c->symbol_rate <= 5000000)
+		div = 14;
+	else
+		div = 4;
+
+	ret = tda10071_wr_reg(priv, 0x81, div);
+	if (ret)
+		goto error;
+
+	ret = tda10071_wr_reg(priv, 0xe3, div);
+	if (ret)
+		goto error;
+
+	cmd.args[0] = CMD_CHANGE_CHANNEL;
+	cmd.args[1] = 0;
+	cmd.args[2] = mode;
+	cmd.args[3] = (c->frequency >> 16) & 0xff;
+	cmd.args[4] = (c->frequency >>  8) & 0xff;
+	cmd.args[5] = (c->frequency >>  0) & 0xff;
+	cmd.args[6] = ((c->symbol_rate / 1000) >> 8) & 0xff;
+	cmd.args[7] = ((c->symbol_rate / 1000) >> 0) & 0xff;
+	cmd.args[8] = (tda10071_ops.info.frequency_tolerance >> 8) & 0xff;
+	cmd.args[9] = (tda10071_ops.info.frequency_tolerance >> 0) & 0xff;
+	cmd.args[10] = rolloff;
+	cmd.args[11] = inversion;
+	cmd.args[12] = pilot;
+	cmd.args[13] = 0x00;
+	cmd.args[14] = 0x00;
+	cmd.len = 15;
+	ret = tda10071_cmd_execute(priv, &cmd);
+	if (ret)
+		goto error;
+
+	priv->delivery_system = c->delivery_system;
+
+	return ret;
+error:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int tda10071_get_frontend(struct dvb_frontend *fe)
+{
+	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i;
+	u8 buf[5], tmp;
+
+	if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
+		ret = -EFAULT;
+		goto error;
+	}
+
+	ret = tda10071_rd_regs(priv, 0x30, buf, 5);
+	if (ret)
+		goto error;
+
+	tmp = buf[0] & 0x3f;
+	for (i = 0; i < ARRAY_SIZE(TDA10071_MODCOD); i++) {
+		if (tmp == TDA10071_MODCOD[i].val) {
+			c->modulation = TDA10071_MODCOD[i].modulation;
+			c->fec_inner = TDA10071_MODCOD[i].fec;
+			c->delivery_system = TDA10071_MODCOD[i].delivery_system;
+		}
+	}
+
+	switch ((buf[1] >> 0) & 0x01) {
+	case 0:
+		c->inversion = INVERSION_OFF;
+		break;
+	case 1:
+		c->inversion = INVERSION_ON;
+		break;
+	}
+
+	switch ((buf[1] >> 7) & 0x01) {
+	case 0:
+		c->pilot = PILOT_OFF;
+		break;
+	case 1:
+		c->pilot = PILOT_ON;
+		break;
+	}
+
+	c->frequency = (buf[2] << 16) | (buf[3] << 8) | (buf[4] << 0);
+
+	ret = tda10071_rd_regs(priv, 0x52, buf, 3);
+	if (ret)
+		goto error;
+
+	c->symbol_rate = (buf[0] << 16) | (buf[1] << 8) | (buf[2] << 0);
+
+	return ret;
+error:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int tda10071_init(struct dvb_frontend *fe)
+{
+	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_cmd cmd;
+	int ret, i, len, remaining, fw_size;
+	const struct firmware *fw;
+	u8 *fw_file = TDA10071_DEFAULT_FIRMWARE;
+	u8 tmp, buf[4];
+	struct tda10071_reg_val_mask tab[] = {
+		{ 0xcd, 0x00, 0x07 },
+		{ 0x80, 0x00, 0x02 },
+		{ 0xcd, 0x00, 0xc0 },
+		{ 0xce, 0x00, 0x1b },
+		{ 0x9d, 0x00, 0x01 },
+		{ 0x9d, 0x00, 0x02 },
+		{ 0x9e, 0x00, 0x01 },
+		{ 0x87, 0x00, 0x80 },
+		{ 0xce, 0x00, 0x08 },
+		{ 0xce, 0x00, 0x10 },
+	};
+	struct tda10071_reg_val_mask tab2[] = {
+		{ 0xf1, 0x70, 0xff },
+		{ 0x88, priv->cfg.pll_multiplier, 0x3f },
+		{ 0x89, 0x00, 0x10 },
+		{ 0x89, 0x10, 0x10 },
+		{ 0xc0, 0x01, 0x01 },
+		{ 0xc0, 0x00, 0x01 },
+		{ 0xe0, 0xff, 0xff },
+		{ 0xe0, 0x00, 0xff },
+		{ 0x96, 0x1e, 0x7e },
+		{ 0x8b, 0x08, 0x08 },
+		{ 0x8b, 0x00, 0x08 },
+		{ 0x8f, 0x1a, 0x7e },
+		{ 0x8c, 0x68, 0xff },
+		{ 0x8d, 0x08, 0xff },
+		{ 0x8e, 0x4c, 0xff },
+		{ 0x8f, 0x01, 0x01 },
+		{ 0x8b, 0x04, 0x04 },
+		{ 0x8b, 0x00, 0x04 },
+		{ 0x87, 0x05, 0x07 },
+		{ 0x80, 0x00, 0x20 },
+		{ 0xc8, 0x01, 0xff },
+		{ 0xb4, 0x47, 0xff },
+		{ 0xb5, 0x9c, 0xff },
+		{ 0xb6, 0x7d, 0xff },
+		{ 0xba, 0x00, 0x03 },
+		{ 0xb7, 0x47, 0xff },
+		{ 0xb8, 0x9c, 0xff },
+		{ 0xb9, 0x7d, 0xff },
+		{ 0xba, 0x00, 0x0c },
+		{ 0xc8, 0x00, 0xff },
+		{ 0xcd, 0x00, 0x04 },
+		{ 0xcd, 0x00, 0x20 },
+		{ 0xe8, 0x02, 0xff },
+		{ 0xcf, 0x20, 0xff },
+		{ 0x9b, 0xd7, 0xff },
+		{ 0x9a, 0x01, 0x03 },
+		{ 0xa8, 0x05, 0x0f },
+		{ 0xa8, 0x65, 0xf0 },
+		{ 0xa6, 0xa0, 0xf0 },
+		{ 0x9d, 0x50, 0xfc },
+		{ 0x9e, 0x20, 0xe0 },
+		{ 0xa3, 0x1c, 0x7c },
+		{ 0xd5, 0x03, 0x03 },
+	};
+
+	/* firmware status */
+	ret = tda10071_rd_reg(priv, 0x51, &tmp);
+	if (ret)
+		goto error;
+
+	if (!tmp) {
+		/* warm state - wake up device from sleep */
+		priv->warm = 1;
+
+		for (i = 0; i < ARRAY_SIZE(tab); i++) {
+			ret = tda10071_wr_reg_mask(priv, tab[i].reg,
+				tab[i].val, tab[i].mask);
+			if (ret)
+				goto error;
+		}
+
+		cmd.args[0] = CMD_SET_SLEEP_MODE;
+		cmd.args[1] = 0;
+		cmd.args[2] = 0;
+		cmd.len = 3;
+		ret = tda10071_cmd_execute(priv, &cmd);
+		if (ret)
+			goto error;
+	} else {
+		/* cold state - try to download firmware */
+		priv->warm = 0;
+
+		/* request the firmware, this will block and timeout */
+		ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent);
+		if (ret) {
+			dev_err(&priv->i2c->dev, "%s: did not find the " \
+					"firmware file. (%s) Please see " \
+					"linux/Documentation/dvb/ for more " \
+					"details on firmware-problems. (%d)\n",
+					KBUILD_MODNAME, fw_file, ret);
+			goto error;
+		}
+
+		/* init */
+		for (i = 0; i < ARRAY_SIZE(tab2); i++) {
+			ret = tda10071_wr_reg_mask(priv, tab2[i].reg,
+				tab2[i].val, tab2[i].mask);
+			if (ret)
+				goto error_release_firmware;
+		}
+
+		/*  download firmware */
+		ret = tda10071_wr_reg(priv, 0xe0, 0x7f);
+		if (ret)
+			goto error_release_firmware;
+
+		ret = tda10071_wr_reg(priv, 0xf7, 0x81);
+		if (ret)
+			goto error_release_firmware;
+
+		ret = tda10071_wr_reg(priv, 0xf8, 0x00);
+		if (ret)
+			goto error_release_firmware;
+
+		ret = tda10071_wr_reg(priv, 0xf9, 0x00);
+		if (ret)
+			goto error_release_firmware;
+
+		dev_info(&priv->i2c->dev, "%s: found a '%s' in cold state, " \
+				"will try to load a firmware\n", KBUILD_MODNAME,
+				tda10071_ops.info.name);
+		dev_info(&priv->i2c->dev, "%s: downloading firmware from " \
+				"file '%s'\n", KBUILD_MODNAME, fw_file);
+
+		/* do not download last byte */
+		fw_size = fw->size - 1;
+
+		for (remaining = fw_size; remaining > 0;
+			remaining -= (priv->cfg.i2c_wr_max - 1)) {
+			len = remaining;
+			if (len > (priv->cfg.i2c_wr_max - 1))
+				len = (priv->cfg.i2c_wr_max - 1);
+
+			ret = tda10071_wr_regs(priv, 0xfa,
+				(u8 *) &fw->data[fw_size - remaining], len);
+			if (ret) {
+				dev_err(&priv->i2c->dev, "%s: firmware " \
+						"download failed=%d\n",
+						KBUILD_MODNAME, ret);
+				if (ret)
+					goto error_release_firmware;
+			}
+		}
+		release_firmware(fw);
+
+		ret = tda10071_wr_reg(priv, 0xf7, 0x0c);
+		if (ret)
+			goto error;
+
+		ret = tda10071_wr_reg(priv, 0xe0, 0x00);
+		if (ret)
+			goto error;
+
+		/* wait firmware start */
+		msleep(250);
+
+		/* firmware status */
+		ret = tda10071_rd_reg(priv, 0x51, &tmp);
+		if (ret)
+			goto error;
+
+		if (tmp) {
+			dev_info(&priv->i2c->dev, "%s: firmware did not run\n",
+					KBUILD_MODNAME);
+			ret = -EFAULT;
+			goto error;
+		} else {
+			priv->warm = 1;
+		}
+
+		cmd.args[0] = CMD_GET_FW_VERSION;
+		cmd.len = 1;
+		ret = tda10071_cmd_execute(priv, &cmd);
+		if (ret)
+			goto error;
+
+		ret = tda10071_rd_regs(priv, cmd.len, buf, 4);
+		if (ret)
+			goto error;
+
+		dev_info(&priv->i2c->dev, "%s: firmware version %d.%d.%d.%d\n",
+				KBUILD_MODNAME, buf[0], buf[1], buf[2], buf[3]);
+		dev_info(&priv->i2c->dev, "%s: found a '%s' in warm state\n",
+				KBUILD_MODNAME, tda10071_ops.info.name);
+
+		ret = tda10071_rd_regs(priv, 0x81, buf, 2);
+		if (ret)
+			goto error;
+
+		cmd.args[0] = CMD_DEMOD_INIT;
+		cmd.args[1] = ((priv->cfg.xtal / 1000) >> 8) & 0xff;
+		cmd.args[2] = ((priv->cfg.xtal / 1000) >> 0) & 0xff;
+		cmd.args[3] = buf[0];
+		cmd.args[4] = buf[1];
+		cmd.args[5] = priv->cfg.pll_multiplier;
+		cmd.args[6] = priv->cfg.spec_inv;
+		cmd.args[7] = 0x00;
+		cmd.len = 8;
+		ret = tda10071_cmd_execute(priv, &cmd);
+		if (ret)
+			goto error;
+
+		cmd.args[0] = CMD_TUNER_INIT;
+		cmd.args[1] = 0x00;
+		cmd.args[2] = 0x00;
+		cmd.args[3] = 0x00;
+		cmd.args[4] = 0x00;
+		cmd.args[5] = 0x14;
+		cmd.args[6] = 0x00;
+		cmd.args[7] = 0x03;
+		cmd.args[8] = 0x02;
+		cmd.args[9] = 0x02;
+		cmd.args[10] = 0x00;
+		cmd.args[11] = 0x00;
+		cmd.args[12] = 0x00;
+		cmd.args[13] = 0x00;
+		cmd.args[14] = 0x00;
+		cmd.len = 15;
+		ret = tda10071_cmd_execute(priv, &cmd);
+		if (ret)
+			goto error;
+
+		cmd.args[0] = CMD_MPEG_CONFIG;
+		cmd.args[1] = 0;
+		cmd.args[2] = priv->cfg.ts_mode;
+		cmd.args[3] = 0x00;
+		cmd.args[4] = 0x04;
+		cmd.args[5] = 0x00;
+		cmd.len = 6;
+		ret = tda10071_cmd_execute(priv, &cmd);
+		if (ret)
+			goto error;
+
+		ret = tda10071_wr_reg_mask(priv, 0xf0, 0x01, 0x01);
+		if (ret)
+			goto error;
+
+		cmd.args[0] = CMD_LNB_CONFIG;
+		cmd.args[1] = 0;
+		cmd.args[2] = 150;
+		cmd.args[3] = 3;
+		cmd.args[4] = 22;
+		cmd.args[5] = 1;
+		cmd.args[6] = 1;
+		cmd.args[7] = 30;
+		cmd.args[8] = 30;
+		cmd.args[9] = 30;
+		cmd.args[10] = 30;
+		cmd.len = 11;
+		ret = tda10071_cmd_execute(priv, &cmd);
+		if (ret)
+			goto error;
+
+		cmd.args[0] = CMD_BER_CONTROL;
+		cmd.args[1] = 0;
+		cmd.args[2] = 14;
+		cmd.args[3] = 14;
+		cmd.len = 4;
+		ret = tda10071_cmd_execute(priv, &cmd);
+		if (ret)
+			goto error;
+	}
+
+	return ret;
+error_release_firmware:
+	release_firmware(fw);
+error:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int tda10071_sleep(struct dvb_frontend *fe)
+{
+	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_cmd cmd;
+	int ret, i;
+	struct tda10071_reg_val_mask tab[] = {
+		{ 0xcd, 0x07, 0x07 },
+		{ 0x80, 0x02, 0x02 },
+		{ 0xcd, 0xc0, 0xc0 },
+		{ 0xce, 0x1b, 0x1b },
+		{ 0x9d, 0x01, 0x01 },
+		{ 0x9d, 0x02, 0x02 },
+		{ 0x9e, 0x01, 0x01 },
+		{ 0x87, 0x80, 0x80 },
+		{ 0xce, 0x08, 0x08 },
+		{ 0xce, 0x10, 0x10 },
+	};
+
+	if (!priv->warm) {
+		ret = -EFAULT;
+		goto error;
+	}
+
+	cmd.args[0] = CMD_SET_SLEEP_MODE;
+	cmd.args[1] = 0;
+	cmd.args[2] = 1;
+	cmd.len = 3;
+	ret = tda10071_cmd_execute(priv, &cmd);
+	if (ret)
+		goto error;
+
+	for (i = 0; i < ARRAY_SIZE(tab); i++) {
+		ret = tda10071_wr_reg_mask(priv, tab[i].reg, tab[i].val,
+			tab[i].mask);
+		if (ret)
+			goto error;
+	}
+
+	return ret;
+error:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int tda10071_get_tune_settings(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *s)
+{
+	s->min_delay_ms = 8000;
+	s->step_size = 0;
+	s->max_drift = 0;
+
+	return 0;
+}
+
+static void tda10071_release(struct dvb_frontend *fe)
+{
+	struct tda10071_priv *priv = fe->demodulator_priv;
+	kfree(priv);
+}
+
+struct dvb_frontend *tda10071_attach(const struct tda10071_config *config,
+	struct i2c_adapter *i2c)
+{
+	int ret;
+	struct tda10071_priv *priv = NULL;
+	u8 tmp;
+
+	/* allocate memory for the internal priv */
+	priv = kzalloc(sizeof(struct tda10071_priv), GFP_KERNEL);
+	if (priv == NULL) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	/* setup the priv */
+	priv->i2c = i2c;
+	memcpy(&priv->cfg, config, sizeof(struct tda10071_config));
+
+	/* chip ID */
+	ret = tda10071_rd_reg(priv, 0xff, &tmp);
+	if (ret || tmp != 0x0f)
+		goto error;
+
+	/* chip type */
+	ret = tda10071_rd_reg(priv, 0xdd, &tmp);
+	if (ret || tmp != 0x00)
+		goto error;
+
+	/* chip version */
+	ret = tda10071_rd_reg(priv, 0xfe, &tmp);
+	if (ret || tmp != 0x01)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&priv->fe.ops, &tda10071_ops, sizeof(struct dvb_frontend_ops));
+	priv->fe.demodulator_priv = priv;
+
+	return &priv->fe;
+error:
+	dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
+	kfree(priv);
+	return NULL;
+}
+EXPORT_SYMBOL(tda10071_attach);
+
+static struct dvb_frontend_ops tda10071_ops = {
+	.delsys = { SYS_DVBS, SYS_DVBS2 },
+	.info = {
+		.name = "NXP TDA10071",
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		.frequency_tolerance = 5000,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 |
+			FE_CAN_FEC_2_3 |
+			FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_4_5 |
+			FE_CAN_FEC_5_6 |
+			FE_CAN_FEC_6_7 |
+			FE_CAN_FEC_7_8 |
+			FE_CAN_FEC_8_9 |
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK |
+			FE_CAN_RECOVER |
+			FE_CAN_2G_MODULATION
+	},
+
+	.release = tda10071_release,
+
+	.get_tune_settings = tda10071_get_tune_settings,
+
+	.init = tda10071_init,
+	.sleep = tda10071_sleep,
+
+	.set_frontend = tda10071_set_frontend,
+	.get_frontend = tda10071_get_frontend,
+
+	.read_status = tda10071_read_status,
+	.read_snr = tda10071_read_snr,
+	.read_signal_strength = tda10071_read_signal_strength,
+	.read_ber = tda10071_read_ber,
+	.read_ucblocks = tda10071_read_ucblocks,
+
+	.diseqc_send_master_cmd = tda10071_diseqc_send_master_cmd,
+	.diseqc_recv_slave_reply = tda10071_diseqc_recv_slave_reply,
+	.diseqc_send_burst = tda10071_diseqc_send_burst,
+
+	.set_tone = tda10071_set_tone,
+	.set_voltage = tda10071_set_voltage,
+};
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("NXP TDA10071 DVB-S/S2 demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/tda10071.h b/drivers/media/dvb-frontends/tda10071.h
new file mode 100644
index 0000000..21163c4
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda10071.h
@@ -0,0 +1,81 @@
+/*
+ * NXP TDA10071 + Conexant CX24118A DVB-S/S2 demodulator + tuner driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef TDA10071_H
+#define TDA10071_H
+
+#include <linux/dvb/frontend.h>
+
+struct tda10071_config {
+	/* Demodulator I2C address.
+	 * Default: none, must set
+	 * Values: 0x55,
+	 */
+	u8 i2c_address;
+
+	/* Max bytes I2C provider can write at once.
+	 * Note: Buffer is taken from the stack currently!
+	 * Default: none, must set
+	 * Values:
+	 */
+	u16 i2c_wr_max;
+
+	/* TS output mode.
+	 * Default: TDA10071_TS_SERIAL
+	 * Values:
+	 */
+#define TDA10071_TS_SERIAL        0
+#define TDA10071_TS_PARALLEL      1
+	u8 ts_mode;
+
+	/* Input spectrum inversion.
+	 * Default: 0
+	 * Values: 0, 1
+	 */
+	bool spec_inv;
+
+	/* Xtal frequency Hz
+	 * Default: none, must set
+	 * Values:
+	 */
+	u32 xtal;
+
+	/* PLL multiplier.
+	 * Default: none, must set
+	 * Values:
+	 */
+	u8 pll_multiplier;
+};
+
+
+#if defined(CONFIG_DVB_TDA10071) || \
+	(defined(CONFIG_DVB_TDA10071_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda10071_attach(
+	const struct tda10071_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *tda10071_attach(
+	const struct tda10071_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* TDA10071_H */
diff --git a/drivers/media/dvb-frontends/tda10071_priv.h b/drivers/media/dvb-frontends/tda10071_priv.h
new file mode 100644
index 0000000..0fa85cf
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda10071_priv.h
@@ -0,0 +1,109 @@
+/*
+ * NXP TDA10071 + Conexant CX24118A DVB-S/S2 demodulator + tuner driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef TDA10071_PRIV
+#define TDA10071_PRIV
+
+#include "dvb_frontend.h"
+#include "tda10071.h"
+#include <linux/firmware.h>
+
+struct tda10071_priv {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend fe;
+	struct tda10071_config cfg;
+
+	u8 meas_count[2];
+	u32 ber;
+	u32 ucb;
+	fe_status_t fe_status;
+	fe_delivery_system_t delivery_system;
+	bool warm; /* FW running */
+};
+
+static struct tda10071_modcod {
+	fe_delivery_system_t delivery_system;
+	fe_modulation_t modulation;
+	fe_code_rate_t fec;
+	u8 val;
+} TDA10071_MODCOD[] = {
+	/* NBC-QPSK */
+	{ SYS_DVBS2, QPSK,  FEC_AUTO, 0x00 },
+	{ SYS_DVBS2, QPSK,  FEC_1_2,  0x04 },
+	{ SYS_DVBS2, QPSK,  FEC_3_5,  0x05 },
+	{ SYS_DVBS2, QPSK,  FEC_2_3,  0x06 },
+	{ SYS_DVBS2, QPSK,  FEC_3_4,  0x07 },
+	{ SYS_DVBS2, QPSK,  FEC_4_5,  0x08 },
+	{ SYS_DVBS2, QPSK,  FEC_5_6,  0x09 },
+	{ SYS_DVBS2, QPSK,  FEC_8_9,  0x0a },
+	{ SYS_DVBS2, QPSK,  FEC_9_10, 0x0b },
+	/* 8PSK */
+	{ SYS_DVBS2, PSK_8, FEC_3_5,  0x0c },
+	{ SYS_DVBS2, PSK_8, FEC_2_3,  0x0d },
+	{ SYS_DVBS2, PSK_8, FEC_3_4,  0x0e },
+	{ SYS_DVBS2, PSK_8, FEC_5_6,  0x0f },
+	{ SYS_DVBS2, PSK_8, FEC_8_9,  0x10 },
+	{ SYS_DVBS2, PSK_8, FEC_9_10, 0x11 },
+	/* QPSK */
+	{ SYS_DVBS,  QPSK,  FEC_AUTO, 0x2d },
+	{ SYS_DVBS,  QPSK,  FEC_1_2,  0x2e },
+	{ SYS_DVBS,  QPSK,  FEC_2_3,  0x2f },
+	{ SYS_DVBS,  QPSK,  FEC_3_4,  0x30 },
+	{ SYS_DVBS,  QPSK,  FEC_5_6,  0x31 },
+	{ SYS_DVBS,  QPSK,  FEC_7_8,  0x32 },
+};
+
+struct tda10071_reg_val_mask {
+	u8 reg;
+	u8 val;
+	u8 mask;
+};
+
+/* firmware filename */
+#define TDA10071_DEFAULT_FIRMWARE      "dvb-fe-tda10071.fw"
+
+/* firmware commands */
+#define CMD_DEMOD_INIT          0x10
+#define CMD_CHANGE_CHANNEL      0x11
+#define CMD_MPEG_CONFIG         0x13
+#define CMD_TUNER_INIT          0x15
+#define CMD_GET_AGCACC          0x1a
+
+#define CMD_LNB_CONFIG          0x20
+#define CMD_LNB_SEND_DISEQC     0x21
+#define CMD_LNB_SET_DC_LEVEL    0x22
+#define CMD_LNB_PCB_CONFIG      0x23
+#define CMD_LNB_SEND_TONEBURST  0x24
+#define CMD_LNB_UPDATE_REPLY    0x25
+
+#define CMD_GET_FW_VERSION      0x35
+#define CMD_SET_SLEEP_MODE      0x36
+#define CMD_BER_CONTROL         0x3e
+#define CMD_BER_UPDATE_COUNTERS 0x3f
+
+/* firmare command struct */
+#define TDA10071_ARGLEN      30
+struct tda10071_cmd {
+	u8 args[TDA10071_ARGLEN];
+	u8 len;
+};
+
+
+#endif /* TDA10071_PRIV */
diff --git a/drivers/media/dvb-frontends/tda10086.c b/drivers/media/dvb-frontends/tda10086.c
new file mode 100644
index 0000000..fcfe2e0
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda10086.c
@@ -0,0 +1,777 @@
+  /*
+     Driver for Philips tda10086 DVBS Demodulator
+
+     (c) 2006 Andrew de Quincey
+
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+     the Free Software Foundation; either version 2 of the License, or
+     (at your option) any later version.
+
+     This program is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+     GNU General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, write to the Free Software
+     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "tda10086.h"
+
+#define SACLK 96000000
+
+struct tda10086_state {
+	struct i2c_adapter* i2c;
+	const struct tda10086_config* config;
+	struct dvb_frontend frontend;
+
+	/* private demod data */
+	u32 frequency;
+	u32 symbol_rate;
+	bool has_lock;
+};
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "tda10086: " args); \
+	} while (0)
+
+static int tda10086_write_byte(struct tda10086_state *state, int reg, int data)
+{
+	int ret;
+	u8 b0[] = { reg, data };
+	struct i2c_msg msg = { .flags = 0, .buf = b0, .len = 2 };
+
+	msg.addr = state->config->demod_address;
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
+			__func__, reg, data, ret);
+
+	return (ret != 1) ? ret : 0;
+}
+
+static int tda10086_read_byte(struct tda10086_state *state, int reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 },
+				{ .flags = I2C_M_RD, .buf = b1, .len = 1 }};
+
+	msg[0].addr = state->config->demod_address;
+	msg[1].addr = state->config->demod_address;
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg,
+			ret);
+		return ret;
+	}
+
+	return b1[0];
+}
+
+static int tda10086_write_mask(struct tda10086_state *state, int reg, int mask, int data)
+{
+	int val;
+
+	/* read a byte and check */
+	val = tda10086_read_byte(state, reg);
+	if (val < 0)
+		return val;
+
+	/* mask if off */
+	val = val & ~mask;
+	val |= data & 0xff;
+
+	/* write it out again */
+	return tda10086_write_byte(state, reg, val);
+}
+
+static int tda10086_init(struct dvb_frontend* fe)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+	u8 t22k_off = 0x80;
+
+	dprintk ("%s\n", __func__);
+
+	if (state->config->diseqc_tone)
+		t22k_off = 0;
+	/* reset */
+	tda10086_write_byte(state, 0x00, 0x00);
+	msleep(10);
+
+	/* misc setup */
+	tda10086_write_byte(state, 0x01, 0x94);
+	tda10086_write_byte(state, 0x02, 0x35); /* NOTE: TT drivers appear to disable CSWP */
+	tda10086_write_byte(state, 0x03, 0xe4);
+	tda10086_write_byte(state, 0x04, 0x43);
+	tda10086_write_byte(state, 0x0c, 0x0c);
+	tda10086_write_byte(state, 0x1b, 0xb0); /* noise threshold */
+	tda10086_write_byte(state, 0x20, 0x89); /* misc */
+	tda10086_write_byte(state, 0x30, 0x04); /* acquisition period length */
+	tda10086_write_byte(state, 0x32, 0x00); /* irq off */
+	tda10086_write_byte(state, 0x31, 0x56); /* setup AFC */
+
+	/* setup PLL (this assumes SACLK = 96MHz) */
+	tda10086_write_byte(state, 0x55, 0x2c); /* misc PLL setup */
+	if (state->config->xtal_freq == TDA10086_XTAL_16M) {
+		tda10086_write_byte(state, 0x3a, 0x0b); /* M=12 */
+		tda10086_write_byte(state, 0x3b, 0x01); /* P=2 */
+	} else {
+		tda10086_write_byte(state, 0x3a, 0x17); /* M=24 */
+		tda10086_write_byte(state, 0x3b, 0x00); /* P=1 */
+	}
+	tda10086_write_mask(state, 0x55, 0x20, 0x00); /* powerup PLL */
+
+	/* setup TS interface */
+	tda10086_write_byte(state, 0x11, 0x81);
+	tda10086_write_byte(state, 0x12, 0x81);
+	tda10086_write_byte(state, 0x19, 0x40); /* parallel mode A + MSBFIRST */
+	tda10086_write_byte(state, 0x56, 0x80); /* powerdown WPLL - unused in the mode we use */
+	tda10086_write_byte(state, 0x57, 0x08); /* bypass WPLL - unused in the mode we use */
+	tda10086_write_byte(state, 0x10, 0x2a);
+
+	/* setup ADC */
+	tda10086_write_byte(state, 0x58, 0x61); /* ADC setup */
+	tda10086_write_mask(state, 0x58, 0x01, 0x00); /* powerup ADC */
+
+	/* setup AGC */
+	tda10086_write_byte(state, 0x05, 0x0B);
+	tda10086_write_byte(state, 0x37, 0x63);
+	tda10086_write_byte(state, 0x3f, 0x0a); /* NOTE: flydvb varies it */
+	tda10086_write_byte(state, 0x40, 0x64);
+	tda10086_write_byte(state, 0x41, 0x4f);
+	tda10086_write_byte(state, 0x42, 0x43);
+
+	/* setup viterbi */
+	tda10086_write_byte(state, 0x1a, 0x11); /* VBER 10^6, DVB, QPSK */
+
+	/* setup carrier recovery */
+	tda10086_write_byte(state, 0x3d, 0x80);
+
+	/* setup SEC */
+	tda10086_write_byte(state, 0x36, t22k_off); /* all SEC off, 22k tone */
+	tda10086_write_byte(state, 0x34, (((1<<19) * (22000/1000)) / (SACLK/1000)));
+	tda10086_write_byte(state, 0x35, (((1<<19) * (22000/1000)) / (SACLK/1000)) >> 8);
+
+	return 0;
+}
+
+static void tda10086_diseqc_wait(struct tda10086_state *state)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(200);
+	while (!(tda10086_read_byte(state, 0x50) & 0x01)) {
+		if(time_after(jiffies, timeout)) {
+			printk("%s: diseqc queue not ready, command may be lost.\n", __func__);
+			break;
+		}
+		msleep(10);
+	}
+}
+
+static int tda10086_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+	u8 t22k_off = 0x80;
+
+	dprintk ("%s\n", __func__);
+
+	if (state->config->diseqc_tone)
+		t22k_off = 0;
+
+	switch (tone) {
+	case SEC_TONE_OFF:
+		tda10086_write_byte(state, 0x36, t22k_off);
+		break;
+
+	case SEC_TONE_ON:
+		tda10086_write_byte(state, 0x36, 0x01 + t22k_off);
+		break;
+	}
+
+	return 0;
+}
+
+static int tda10086_send_master_cmd (struct dvb_frontend* fe,
+				    struct dvb_diseqc_master_cmd* cmd)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+	int i;
+	u8 oldval;
+	u8 t22k_off = 0x80;
+
+	dprintk ("%s\n", __func__);
+
+	if (state->config->diseqc_tone)
+		t22k_off = 0;
+
+	if (cmd->msg_len > 6)
+		return -EINVAL;
+	oldval = tda10086_read_byte(state, 0x36);
+
+	for(i=0; i< cmd->msg_len; i++) {
+		tda10086_write_byte(state, 0x48+i, cmd->msg[i]);
+	}
+	tda10086_write_byte(state, 0x36, (0x08 + t22k_off)
+					| ((cmd->msg_len - 1) << 4));
+
+	tda10086_diseqc_wait(state);
+
+	tda10086_write_byte(state, 0x36, oldval);
+
+	return 0;
+}
+
+static int tda10086_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+	u8 oldval = tda10086_read_byte(state, 0x36);
+	u8 t22k_off = 0x80;
+
+	dprintk ("%s\n", __func__);
+
+	if (state->config->diseqc_tone)
+		t22k_off = 0;
+
+	switch(minicmd) {
+	case SEC_MINI_A:
+		tda10086_write_byte(state, 0x36, 0x04 + t22k_off);
+		break;
+
+	case SEC_MINI_B:
+		tda10086_write_byte(state, 0x36, 0x06 + t22k_off);
+		break;
+	}
+
+	tda10086_diseqc_wait(state);
+
+	tda10086_write_byte(state, 0x36, oldval);
+
+	return 0;
+}
+
+static int tda10086_set_inversion(struct tda10086_state *state,
+				  struct dtv_frontend_properties *fe_params)
+{
+	u8 invval = 0x80;
+
+	dprintk ("%s %i %i\n", __func__, fe_params->inversion, state->config->invert);
+
+	switch(fe_params->inversion) {
+	case INVERSION_OFF:
+		if (state->config->invert)
+			invval = 0x40;
+		break;
+	case INVERSION_ON:
+		if (!state->config->invert)
+			invval = 0x40;
+		break;
+	case INVERSION_AUTO:
+		invval = 0x00;
+		break;
+	}
+	tda10086_write_mask(state, 0x0c, 0xc0, invval);
+
+	return 0;
+}
+
+static int tda10086_set_symbol_rate(struct tda10086_state *state,
+				    struct dtv_frontend_properties *fe_params)
+{
+	u8 dfn = 0;
+	u8 afs = 0;
+	u8 byp = 0;
+	u8 reg37 = 0x43;
+	u8 reg42 = 0x43;
+	u64 big;
+	u32 tmp;
+	u32 bdr;
+	u32 bdri;
+	u32 symbol_rate = fe_params->symbol_rate;
+
+	dprintk ("%s %i\n", __func__, symbol_rate);
+
+	/* setup the decimation and anti-aliasing filters.. */
+	if (symbol_rate < (u32) (SACLK * 0.0137)) {
+		dfn=4;
+		afs=1;
+	} else if (symbol_rate < (u32) (SACLK * 0.0208)) {
+		dfn=4;
+		afs=0;
+	} else if (symbol_rate < (u32) (SACLK * 0.0270)) {
+		dfn=3;
+		afs=1;
+	} else if (symbol_rate < (u32) (SACLK * 0.0416)) {
+		dfn=3;
+		afs=0;
+	} else if (symbol_rate < (u32) (SACLK * 0.0550)) {
+		dfn=2;
+		afs=1;
+	} else if (symbol_rate < (u32) (SACLK * 0.0833)) {
+		dfn=2;
+		afs=0;
+	} else if (symbol_rate < (u32) (SACLK * 0.1100)) {
+		dfn=1;
+		afs=1;
+	} else if (symbol_rate < (u32) (SACLK * 0.1666)) {
+		dfn=1;
+		afs=0;
+	} else if (symbol_rate < (u32) (SACLK * 0.2200)) {
+		dfn=0;
+		afs=1;
+	} else if (symbol_rate < (u32) (SACLK * 0.3333)) {
+		dfn=0;
+		afs=0;
+	} else {
+		reg37 = 0x63;
+		reg42 = 0x4f;
+		byp=1;
+	}
+
+	/* calculate BDR */
+	big = (1ULL<<21) * ((u64) symbol_rate/1000ULL) * (1ULL<<dfn);
+	big += ((SACLK/1000ULL)-1ULL);
+	do_div(big, (SACLK/1000ULL));
+	bdr = big & 0xfffff;
+
+	/* calculate BDRI */
+	tmp = (1<<dfn)*(symbol_rate/1000);
+	bdri = ((32 * (SACLK/1000)) + (tmp-1)) / tmp;
+
+	tda10086_write_byte(state, 0x21, (afs << 7) | dfn);
+	tda10086_write_mask(state, 0x20, 0x08, byp << 3);
+	tda10086_write_byte(state, 0x06, bdr);
+	tda10086_write_byte(state, 0x07, bdr >> 8);
+	tda10086_write_byte(state, 0x08, bdr >> 16);
+	tda10086_write_byte(state, 0x09, bdri);
+	tda10086_write_byte(state, 0x37, reg37);
+	tda10086_write_byte(state, 0x42, reg42);
+
+	return 0;
+}
+
+static int tda10086_set_fec(struct tda10086_state *state,
+			    struct dtv_frontend_properties *fe_params)
+{
+	u8 fecval;
+
+	dprintk("%s %i\n", __func__, fe_params->fec_inner);
+
+	switch (fe_params->fec_inner) {
+	case FEC_1_2:
+		fecval = 0x00;
+		break;
+	case FEC_2_3:
+		fecval = 0x01;
+		break;
+	case FEC_3_4:
+		fecval = 0x02;
+		break;
+	case FEC_4_5:
+		fecval = 0x03;
+		break;
+	case FEC_5_6:
+		fecval = 0x04;
+		break;
+	case FEC_6_7:
+		fecval = 0x05;
+		break;
+	case FEC_7_8:
+		fecval = 0x06;
+		break;
+	case FEC_8_9:
+		fecval = 0x07;
+		break;
+	case FEC_AUTO:
+		fecval = 0x08;
+		break;
+	default:
+		return -1;
+	}
+	tda10086_write_byte(state, 0x0d, fecval);
+
+	return 0;
+}
+
+static int tda10086_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
+	struct tda10086_state *state = fe->demodulator_priv;
+	int ret;
+	u32 freq = 0;
+	int freqoff;
+
+	dprintk ("%s\n", __func__);
+
+	/* modify parameters for tuning */
+	tda10086_write_byte(state, 0x02, 0x35);
+	state->has_lock = false;
+
+	/* set params */
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+
+		if (fe->ops.tuner_ops.get_frequency)
+			fe->ops.tuner_ops.get_frequency(fe, &freq);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	/* calcluate the frequency offset (in *Hz* not kHz) */
+	freqoff = fe_params->frequency - freq;
+	freqoff = ((1<<16) * freqoff) / (SACLK/1000);
+	tda10086_write_byte(state, 0x3d, 0x80 | ((freqoff >> 8) & 0x7f));
+	tda10086_write_byte(state, 0x3e, freqoff);
+
+	if ((ret = tda10086_set_inversion(state, fe_params)) < 0)
+		return ret;
+	if ((ret = tda10086_set_symbol_rate(state, fe_params)) < 0)
+		return ret;
+	if ((ret = tda10086_set_fec(state, fe_params)) < 0)
+		return ret;
+
+	/* soft reset + disable TS output until lock */
+	tda10086_write_mask(state, 0x10, 0x40, 0x40);
+	tda10086_write_mask(state, 0x00, 0x01, 0x00);
+
+	state->symbol_rate = fe_params->symbol_rate;
+	state->frequency = fe_params->frequency;
+	return 0;
+}
+
+static int tda10086_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
+	struct tda10086_state* state = fe->demodulator_priv;
+	u8 val;
+	int tmp;
+	u64 tmp64;
+
+	dprintk ("%s\n", __func__);
+
+	/* check for invalid symbol rate */
+	if (fe_params->symbol_rate < 500000)
+		return -EINVAL;
+
+	/* calculate the updated frequency (note: we convert from Hz->kHz) */
+	tmp64 = tda10086_read_byte(state, 0x52);
+	tmp64 |= (tda10086_read_byte(state, 0x51) << 8);
+	if (tmp64 & 0x8000)
+		tmp64 |= 0xffffffffffff0000ULL;
+	tmp64 = (tmp64 * (SACLK/1000ULL));
+	do_div(tmp64, (1ULL<<15) * (1ULL<<1));
+	fe_params->frequency = (int) state->frequency + (int) tmp64;
+
+	/* the inversion */
+	val = tda10086_read_byte(state, 0x0c);
+	if (val & 0x80) {
+		switch(val & 0x40) {
+		case 0x00:
+			fe_params->inversion = INVERSION_OFF;
+			if (state->config->invert)
+				fe_params->inversion = INVERSION_ON;
+			break;
+		default:
+			fe_params->inversion = INVERSION_ON;
+			if (state->config->invert)
+				fe_params->inversion = INVERSION_OFF;
+			break;
+		}
+	} else {
+		tda10086_read_byte(state, 0x0f);
+		switch(val & 0x02) {
+		case 0x00:
+			fe_params->inversion = INVERSION_OFF;
+			if (state->config->invert)
+				fe_params->inversion = INVERSION_ON;
+			break;
+		default:
+			fe_params->inversion = INVERSION_ON;
+			if (state->config->invert)
+				fe_params->inversion = INVERSION_OFF;
+			break;
+		}
+	}
+
+	/* calculate the updated symbol rate */
+	tmp = tda10086_read_byte(state, 0x1d);
+	if (tmp & 0x80)
+		tmp |= 0xffffff00;
+	tmp = (tmp * 480 * (1<<1)) / 128;
+	tmp = ((state->symbol_rate/1000) * tmp) / (1000000/1000);
+	fe_params->symbol_rate = state->symbol_rate + tmp;
+
+	/* the FEC */
+	val = (tda10086_read_byte(state, 0x0d) & 0x70) >> 4;
+	switch(val) {
+	case 0x00:
+		fe_params->fec_inner = FEC_1_2;
+		break;
+	case 0x01:
+		fe_params->fec_inner = FEC_2_3;
+		break;
+	case 0x02:
+		fe_params->fec_inner = FEC_3_4;
+		break;
+	case 0x03:
+		fe_params->fec_inner = FEC_4_5;
+		break;
+	case 0x04:
+		fe_params->fec_inner = FEC_5_6;
+		break;
+	case 0x05:
+		fe_params->fec_inner = FEC_6_7;
+		break;
+	case 0x06:
+		fe_params->fec_inner = FEC_7_8;
+		break;
+	case 0x07:
+		fe_params->fec_inner = FEC_8_9;
+		break;
+	}
+
+	return 0;
+}
+
+static int tda10086_read_status(struct dvb_frontend* fe, fe_status_t *fe_status)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+	u8 val;
+
+	dprintk ("%s\n", __func__);
+
+	val = tda10086_read_byte(state, 0x0e);
+	*fe_status = 0;
+	if (val & 0x01)
+		*fe_status |= FE_HAS_SIGNAL;
+	if (val & 0x02)
+		*fe_status |= FE_HAS_CARRIER;
+	if (val & 0x04)
+		*fe_status |= FE_HAS_VITERBI;
+	if (val & 0x08)
+		*fe_status |= FE_HAS_SYNC;
+	if (val & 0x10) {
+		*fe_status |= FE_HAS_LOCK;
+		if (!state->has_lock) {
+			state->has_lock = true;
+			/* modify parameters for stable reception */
+			tda10086_write_byte(state, 0x02, 0x00);
+		}
+	}
+
+	return 0;
+}
+
+static int tda10086_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+	u8 _str;
+
+	dprintk ("%s\n", __func__);
+
+	_str = 0xff - tda10086_read_byte(state, 0x43);
+	*signal = (_str << 8) | _str;
+
+	return 0;
+}
+
+static int tda10086_read_snr(struct dvb_frontend* fe, u16 * snr)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+	u8 _snr;
+
+	dprintk ("%s\n", __func__);
+
+	_snr = 0xff - tda10086_read_byte(state, 0x1c);
+	*snr = (_snr << 8) | _snr;
+
+	return 0;
+}
+
+static int tda10086_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+
+	dprintk ("%s\n", __func__);
+
+	/* read it */
+	*ucblocks = tda10086_read_byte(state, 0x18) & 0x7f;
+
+	/* reset counter */
+	tda10086_write_byte(state, 0x18, 0x00);
+	tda10086_write_byte(state, 0x18, 0x80);
+
+	return 0;
+}
+
+static int tda10086_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+
+	dprintk ("%s\n", __func__);
+
+	/* read it */
+	*ber = 0;
+	*ber |= tda10086_read_byte(state, 0x15);
+	*ber |= tda10086_read_byte(state, 0x16) << 8;
+	*ber |= (tda10086_read_byte(state, 0x17) & 0xf) << 16;
+
+	return 0;
+}
+
+static int tda10086_sleep(struct dvb_frontend* fe)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+
+	dprintk ("%s\n", __func__);
+
+	tda10086_write_mask(state, 0x00, 0x08, 0x08);
+
+	return 0;
+}
+
+static int tda10086_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+
+	dprintk ("%s\n", __func__);
+
+	if (enable) {
+		tda10086_write_mask(state, 0x00, 0x10, 0x10);
+	} else {
+		tda10086_write_mask(state, 0x00, 0x10, 0x00);
+	}
+
+	return 0;
+}
+
+static int tda10086_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+	if (p->symbol_rate > 20000000) {
+		fesettings->min_delay_ms = 50;
+		fesettings->step_size = 2000;
+		fesettings->max_drift = 8000;
+	} else if (p->symbol_rate > 12000000) {
+		fesettings->min_delay_ms = 100;
+		fesettings->step_size = 1500;
+		fesettings->max_drift = 9000;
+	} else if (p->symbol_rate > 8000000) {
+		fesettings->min_delay_ms = 100;
+		fesettings->step_size = 1000;
+		fesettings->max_drift = 8000;
+	} else if (p->symbol_rate > 4000000) {
+		fesettings->min_delay_ms = 100;
+		fesettings->step_size = 500;
+		fesettings->max_drift = 7000;
+	} else if (p->symbol_rate > 2000000) {
+		fesettings->min_delay_ms = 200;
+		fesettings->step_size = p->symbol_rate / 8000;
+		fesettings->max_drift = 14 * fesettings->step_size;
+	} else {
+		fesettings->min_delay_ms = 200;
+		fesettings->step_size =  p->symbol_rate / 8000;
+		fesettings->max_drift = 18 * fesettings->step_size;
+	}
+
+	return 0;
+}
+
+static void tda10086_release(struct dvb_frontend* fe)
+{
+	struct tda10086_state *state = fe->demodulator_priv;
+	tda10086_sleep(fe);
+	kfree(state);
+}
+
+static struct dvb_frontend_ops tda10086_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name     = "Philips TDA10086 DVB-S",
+		.frequency_min    = 950000,
+		.frequency_max    = 2150000,
+		.frequency_stepsize = 125,     /* kHz for QPSK frontends */
+		.symbol_rate_min  = 1000000,
+		.symbol_rate_max  = 45000000,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK
+	},
+
+	.release = tda10086_release,
+
+	.init = tda10086_init,
+	.sleep = tda10086_sleep,
+	.i2c_gate_ctrl = tda10086_i2c_gate_ctrl,
+
+	.set_frontend = tda10086_set_frontend,
+	.get_frontend = tda10086_get_frontend,
+	.get_tune_settings = tda10086_get_tune_settings,
+
+	.read_status = tda10086_read_status,
+	.read_ber = tda10086_read_ber,
+	.read_signal_strength = tda10086_read_signal_strength,
+	.read_snr = tda10086_read_snr,
+	.read_ucblocks = tda10086_read_ucblocks,
+
+	.diseqc_send_master_cmd = tda10086_send_master_cmd,
+	.diseqc_send_burst = tda10086_send_burst,
+	.set_tone = tda10086_set_tone,
+};
+
+struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
+				     struct i2c_adapter* i2c)
+{
+	struct tda10086_state *state;
+
+	dprintk ("%s\n", __func__);
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct tda10086_state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+
+	/* check if the demod is there */
+	if (tda10086_read_byte(state, 0x1e) != 0xe1) {
+		kfree(state);
+		return NULL;
+	}
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &tda10086_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+}
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Philips TDA10086 DVB-S Demodulator");
+MODULE_AUTHOR("Andrew de Quincey");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(tda10086_attach);
diff --git a/drivers/media/dvb-frontends/tda10086.h b/drivers/media/dvb-frontends/tda10086.h
new file mode 100644
index 0000000..61148c5
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda10086.h
@@ -0,0 +1,61 @@
+  /*
+     Driver for Philips tda10086 DVBS Frontend
+
+     (c) 2006 Andrew de Quincey
+
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+     the Free Software Foundation; either version 2 of the License, or
+     (at your option) any later version.
+
+     This program is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+     GNU General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, write to the Free Software
+     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   */
+
+#ifndef TDA10086_H
+#define TDA10086_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+enum tda10086_xtal {
+	TDA10086_XTAL_16M,
+	TDA10086_XTAL_4M
+};
+
+struct tda10086_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* does the "inversion" need inverted? */
+	u8 invert;
+
+	/* do we need the diseqc signal with carrier? */
+	u8 diseqc_tone;
+
+	/* frequency of the reference xtal */
+	enum tda10086_xtal xtal_freq;
+};
+
+#if defined(CONFIG_DVB_TDA10086) || (defined(CONFIG_DVB_TDA10086_MODULE) && defined(MODULE))
+extern struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
+					    struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
+						   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_TDA10086 */
+
+#endif /* TDA10086_H */
diff --git a/drivers/media/dvb-frontends/tda18271c2dd.c b/drivers/media/dvb-frontends/tda18271c2dd.c
new file mode 100644
index 0000000..ad7c72e
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda18271c2dd.c
@@ -0,0 +1,1246 @@
+/*
+ * tda18271c2dd: Driver for the TDA18271C2 tuner
+ *
+ * Copyright (C) 2010 Digital Devices GmbH
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+
+struct SStandardParam {
+	s32   m_IFFrequency;
+	u32   m_BandWidth;
+	u8    m_EP3_4_0;
+	u8    m_EB22;
+};
+
+struct SMap {
+	u32   m_Frequency;
+	u8    m_Param;
+};
+
+struct SMapI {
+	u32   m_Frequency;
+	s32    m_Param;
+};
+
+struct SMap2 {
+	u32   m_Frequency;
+	u8    m_Param1;
+	u8    m_Param2;
+};
+
+struct SRFBandMap {
+	u32   m_RF_max;
+	u32   m_RF1_Default;
+	u32   m_RF2_Default;
+	u32   m_RF3_Default;
+};
+
+enum ERegister {
+	ID = 0,
+	TM,
+	PL,
+	EP1, EP2, EP3, EP4, EP5,
+	CPD, CD1, CD2, CD3,
+	MPD, MD1, MD2, MD3,
+	EB1, EB2, EB3, EB4, EB5, EB6, EB7, EB8, EB9, EB10,
+	EB11, EB12, EB13, EB14, EB15, EB16, EB17, EB18, EB19, EB20,
+	EB21, EB22, EB23,
+	NUM_REGS
+};
+
+struct tda_state {
+	struct i2c_adapter *i2c;
+	u8 adr;
+
+	u32   m_Frequency;
+	u32   IF;
+
+	u8    m_IFLevelAnalog;
+	u8    m_IFLevelDigital;
+	u8    m_IFLevelDVBC;
+	u8    m_IFLevelDVBT;
+
+	u8    m_EP4;
+	u8    m_EP3_Standby;
+
+	bool  m_bMaster;
+
+	s32   m_SettlingTime;
+
+	u8    m_Regs[NUM_REGS];
+
+	/* Tracking filter settings for band 0..6 */
+	u32   m_RF1[7];
+	s32   m_RF_A1[7];
+	s32   m_RF_B1[7];
+	u32   m_RF2[7];
+	s32   m_RF_A2[7];
+	s32   m_RF_B2[7];
+	u32   m_RF3[7];
+
+	u8    m_TMValue_RFCal;    /* Calibration temperatur */
+
+	bool  m_bFMInput;         /* true to use Pin 8 for FM Radio */
+
+};
+
+static int PowerScan(struct tda_state *state,
+		     u8 RFBand, u32 RF_in,
+		     u32 *pRF_Out, bool *pbcal);
+
+static int i2c_readn(struct i2c_adapter *adapter, u8 adr, u8 *data, int len)
+{
+	struct i2c_msg msgs[1] = {{.addr = adr,  .flags = I2C_M_RD,
+				   .buf  = data, .len   = len} };
+	return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
+}
+
+static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
+{
+	struct i2c_msg msg = {.addr = adr, .flags = 0,
+			      .buf = data, .len = len};
+
+	if (i2c_transfer(adap, &msg, 1) != 1) {
+		printk(KERN_ERR "tda18271c2dd: i2c write error at addr %i\n", adr);
+		return -1;
+	}
+	return 0;
+}
+
+static int WriteRegs(struct tda_state *state,
+		     u8 SubAddr, u8 *Regs, u16 nRegs)
+{
+	u8 data[nRegs+1];
+
+	data[0] = SubAddr;
+	memcpy(data + 1, Regs, nRegs);
+	return i2c_write(state->i2c, state->adr, data, nRegs+1);
+}
+
+static int WriteReg(struct tda_state *state, u8 SubAddr, u8 Reg)
+{
+	u8 msg[2] = {SubAddr, Reg};
+
+	return i2c_write(state->i2c, state->adr, msg, 2);
+}
+
+static int Read(struct tda_state *state, u8 * Regs)
+{
+	return i2c_readn(state->i2c, state->adr, Regs, 16);
+}
+
+static int ReadExtented(struct tda_state *state, u8 * Regs)
+{
+	return i2c_readn(state->i2c, state->adr, Regs, NUM_REGS);
+}
+
+static int UpdateRegs(struct tda_state *state, u8 RegFrom, u8 RegTo)
+{
+	return WriteRegs(state, RegFrom,
+			 &state->m_Regs[RegFrom], RegTo-RegFrom+1);
+}
+static int UpdateReg(struct tda_state *state, u8 Reg)
+{
+	return WriteReg(state, Reg, state->m_Regs[Reg]);
+}
+
+#include "tda18271c2dd_maps.h"
+
+static void reset(struct tda_state *state)
+{
+	u32   ulIFLevelAnalog = 0;
+	u32   ulIFLevelDigital = 2;
+	u32   ulIFLevelDVBC = 7;
+	u32   ulIFLevelDVBT = 6;
+	u32   ulXTOut = 0;
+	u32   ulStandbyMode = 0x06;    /* Send in stdb, but leave osc on */
+	u32   ulSlave = 0;
+	u32   ulFMInput = 0;
+	u32   ulSettlingTime = 100;
+
+	state->m_Frequency         = 0;
+	state->m_SettlingTime = 100;
+	state->m_IFLevelAnalog = (ulIFLevelAnalog & 0x07) << 2;
+	state->m_IFLevelDigital = (ulIFLevelDigital & 0x07) << 2;
+	state->m_IFLevelDVBC = (ulIFLevelDVBC & 0x07) << 2;
+	state->m_IFLevelDVBT = (ulIFLevelDVBT & 0x07) << 2;
+
+	state->m_EP4 = 0x20;
+	if (ulXTOut != 0)
+		state->m_EP4 |= 0x40;
+
+	state->m_EP3_Standby = ((ulStandbyMode & 0x07) << 5) | 0x0F;
+	state->m_bMaster = (ulSlave == 0);
+
+	state->m_SettlingTime = ulSettlingTime;
+
+	state->m_bFMInput = (ulFMInput == 2);
+}
+
+static bool SearchMap1(struct SMap Map[],
+		       u32 Frequency, u8 *pParam)
+{
+	int i = 0;
+
+	while ((Map[i].m_Frequency != 0) && (Frequency > Map[i].m_Frequency))
+		i += 1;
+	if (Map[i].m_Frequency == 0)
+		return false;
+	*pParam = Map[i].m_Param;
+	return true;
+}
+
+static bool SearchMap2(struct SMapI Map[],
+		       u32 Frequency, s32 *pParam)
+{
+	int i = 0;
+
+	while ((Map[i].m_Frequency != 0) &&
+	       (Frequency > Map[i].m_Frequency))
+		i += 1;
+	if (Map[i].m_Frequency == 0)
+		return false;
+	*pParam = Map[i].m_Param;
+	return true;
+}
+
+static bool SearchMap3(struct SMap2 Map[], u32 Frequency,
+		       u8 *pParam1, u8 *pParam2)
+{
+	int i = 0;
+
+	while ((Map[i].m_Frequency != 0) &&
+	       (Frequency > Map[i].m_Frequency))
+		i += 1;
+	if (Map[i].m_Frequency == 0)
+		return false;
+	*pParam1 = Map[i].m_Param1;
+	*pParam2 = Map[i].m_Param2;
+	return true;
+}
+
+static bool SearchMap4(struct SRFBandMap Map[],
+		       u32 Frequency, u8 *pRFBand)
+{
+	int i = 0;
+
+	while (i < 7 && (Frequency > Map[i].m_RF_max))
+		i += 1;
+	if (i == 7)
+		return false;
+	*pRFBand = i;
+	return true;
+}
+
+static int ThermometerRead(struct tda_state *state, u8 *pTM_Value)
+{
+	int status = 0;
+
+	do {
+		u8 Regs[16];
+		state->m_Regs[TM] |= 0x10;
+		status = UpdateReg(state, TM);
+		if (status < 0)
+			break;
+		status = Read(state, Regs);
+		if (status < 0)
+			break;
+		if (((Regs[TM] & 0x0F) == 0 && (Regs[TM] & 0x20) == 0x20) ||
+		    ((Regs[TM] & 0x0F) == 8 && (Regs[TM] & 0x20) == 0x00)) {
+			state->m_Regs[TM] ^= 0x20;
+			status = UpdateReg(state, TM);
+			if (status < 0)
+				break;
+			msleep(10);
+			status = Read(state, Regs);
+			if (status < 0)
+				break;
+		}
+		*pTM_Value = (Regs[TM] & 0x20)
+				? m_Thermometer_Map_2[Regs[TM] & 0x0F]
+				: m_Thermometer_Map_1[Regs[TM] & 0x0F] ;
+		state->m_Regs[TM] &= ~0x10;        /* Thermometer off */
+		status = UpdateReg(state, TM);
+		if (status < 0)
+			break;
+		state->m_Regs[EP4] &= ~0x03;       /* CAL_mode = 0 ????????? */
+		status = UpdateReg(state, EP4);
+		if (status < 0)
+			break;
+	} while (0);
+
+	return status;
+}
+
+static int StandBy(struct tda_state *state)
+{
+	int status = 0;
+	do {
+		state->m_Regs[EB12] &= ~0x20;  /* PD_AGC1_Det = 0 */
+		status = UpdateReg(state, EB12);
+		if (status < 0)
+			break;
+		state->m_Regs[EB18] &= ~0x83;  /* AGC1_loop_off = 0, AGC1_Gain = 6 dB */
+		status = UpdateReg(state, EB18);
+		if (status < 0)
+			break;
+		state->m_Regs[EB21] |= 0x03; /* AGC2_Gain = -6 dB */
+		state->m_Regs[EP3] = state->m_EP3_Standby;
+		status = UpdateReg(state, EP3);
+		if (status < 0)
+			break;
+		state->m_Regs[EB23] &= ~0x06; /* ForceLP_Fc2_En = 0, LP_Fc[2] = 0 */
+		status = UpdateRegs(state, EB21, EB23);
+		if (status < 0)
+			break;
+	} while (0);
+	return status;
+}
+
+static int CalcMainPLL(struct tda_state *state, u32 freq)
+{
+
+	u8  PostDiv;
+	u8  Div;
+	u64 OscFreq;
+	u32 MainDiv;
+
+	if (!SearchMap3(m_Main_PLL_Map, freq, &PostDiv, &Div))
+		return -EINVAL;
+
+	OscFreq = (u64) freq * (u64) Div;
+	OscFreq *= (u64) 16384;
+	do_div(OscFreq, (u64)16000000);
+	MainDiv = OscFreq;
+
+	state->m_Regs[MPD] = PostDiv & 0x77;
+	state->m_Regs[MD1] = ((MainDiv >> 16) & 0x7F);
+	state->m_Regs[MD2] = ((MainDiv >>  8) & 0xFF);
+	state->m_Regs[MD3] = (MainDiv & 0xFF);
+
+	return UpdateRegs(state, MPD, MD3);
+}
+
+static int CalcCalPLL(struct tda_state *state, u32 freq)
+{
+	u8 PostDiv;
+	u8 Div;
+	u64 OscFreq;
+	u32 CalDiv;
+
+	if (!SearchMap3(m_Cal_PLL_Map, freq, &PostDiv, &Div))
+		return -EINVAL;
+
+	OscFreq = (u64)freq * (u64)Div;
+	/* CalDiv = u32( OscFreq * 16384 / 16000000 ); */
+	OscFreq *= (u64)16384;
+	do_div(OscFreq, (u64)16000000);
+	CalDiv = OscFreq;
+
+	state->m_Regs[CPD] = PostDiv;
+	state->m_Regs[CD1] = ((CalDiv >> 16) & 0xFF);
+	state->m_Regs[CD2] = ((CalDiv >>  8) & 0xFF);
+	state->m_Regs[CD3] = (CalDiv & 0xFF);
+
+	return UpdateRegs(state, CPD, CD3);
+}
+
+static int CalibrateRF(struct tda_state *state,
+		       u8 RFBand, u32 freq, s32 *pCprog)
+{
+	int status = 0;
+	u8 Regs[NUM_REGS];
+	do {
+		u8 BP_Filter = 0;
+		u8 GainTaper = 0;
+		u8 RFC_K = 0;
+		u8 RFC_M = 0;
+
+		state->m_Regs[EP4] &= ~0x03; /* CAL_mode = 0 */
+		status = UpdateReg(state, EP4);
+		if (status < 0)
+			break;
+		state->m_Regs[EB18] |= 0x03;  /* AGC1_Gain = 3 */
+		status = UpdateReg(state, EB18);
+		if (status < 0)
+			break;
+
+		/* Switching off LT (as datasheet says) causes calibration on C1 to fail */
+		/* (Readout of Cprog is allways 255) */
+		if (state->m_Regs[ID] != 0x83)    /* C1: ID == 83, C2: ID == 84 */
+			state->m_Regs[EP3] |= 0x40; /* SM_LT = 1 */
+
+		if (!(SearchMap1(m_BP_Filter_Map, freq, &BP_Filter) &&
+			SearchMap1(m_GainTaper_Map, freq, &GainTaper) &&
+			SearchMap3(m_KM_Map, freq, &RFC_K, &RFC_M)))
+			return -EINVAL;
+
+		state->m_Regs[EP1] = (state->m_Regs[EP1] & ~0x07) | BP_Filter;
+		state->m_Regs[EP2] = (RFBand << 5) | GainTaper;
+
+		state->m_Regs[EB13] = (state->m_Regs[EB13] & ~0x7C) | (RFC_K << 4) | (RFC_M << 2);
+
+		status = UpdateRegs(state, EP1, EP3);
+		if (status < 0)
+			break;
+		status = UpdateReg(state, EB13);
+		if (status < 0)
+			break;
+
+		state->m_Regs[EB4] |= 0x20;    /* LO_ForceSrce = 1 */
+		status = UpdateReg(state, EB4);
+		if (status < 0)
+			break;
+
+		state->m_Regs[EB7] |= 0x20;    /* CAL_ForceSrce = 1 */
+		status = UpdateReg(state, EB7);
+		if (status < 0)
+			break;
+
+		state->m_Regs[EB14] = 0; /* RFC_Cprog = 0 */
+		status = UpdateReg(state, EB14);
+		if (status < 0)
+			break;
+
+		state->m_Regs[EB20] &= ~0x20;  /* ForceLock = 0; */
+		status = UpdateReg(state, EB20);
+		if (status < 0)
+			break;
+
+		state->m_Regs[EP4] |= 0x03;  /* CAL_Mode = 3 */
+		status = UpdateRegs(state, EP4, EP5);
+		if (status < 0)
+			break;
+
+		status = CalcCalPLL(state, freq);
+		if (status < 0)
+			break;
+		status = CalcMainPLL(state, freq + 1000000);
+		if (status < 0)
+			break;
+
+		msleep(5);
+		status = UpdateReg(state, EP2);
+		if (status < 0)
+			break;
+		status = UpdateReg(state, EP1);
+		if (status < 0)
+			break;
+		status = UpdateReg(state, EP2);
+		if (status < 0)
+			break;
+		status = UpdateReg(state, EP1);
+		if (status < 0)
+			break;
+
+		state->m_Regs[EB4] &= ~0x20;    /* LO_ForceSrce = 0 */
+		status = UpdateReg(state, EB4);
+		if (status < 0)
+			break;
+
+		state->m_Regs[EB7] &= ~0x20;    /* CAL_ForceSrce = 0 */
+		status = UpdateReg(state, EB7);
+		if (status < 0)
+			break;
+		msleep(10);
+
+		state->m_Regs[EB20] |= 0x20;  /* ForceLock = 1; */
+		status = UpdateReg(state, EB20);
+		if (status < 0)
+			break;
+		msleep(60);
+
+		state->m_Regs[EP4] &= ~0x03;  /* CAL_Mode = 0 */
+		state->m_Regs[EP3] &= ~0x40; /* SM_LT = 0 */
+		state->m_Regs[EB18] &= ~0x03;  /* AGC1_Gain = 0 */
+		status = UpdateReg(state, EB18);
+		if (status < 0)
+			break;
+		status = UpdateRegs(state, EP3, EP4);
+		if (status < 0)
+			break;
+		status = UpdateReg(state, EP1);
+		if (status < 0)
+			break;
+
+		status = ReadExtented(state, Regs);
+		if (status < 0)
+			break;
+
+		*pCprog = Regs[EB14];
+
+	} while (0);
+	return status;
+}
+
+static int RFTrackingFiltersInit(struct tda_state *state,
+				 u8 RFBand)
+{
+	int status = 0;
+
+	u32   RF1 = m_RF_Band_Map[RFBand].m_RF1_Default;
+	u32   RF2 = m_RF_Band_Map[RFBand].m_RF2_Default;
+	u32   RF3 = m_RF_Band_Map[RFBand].m_RF3_Default;
+	bool    bcal = false;
+
+	s32    Cprog_cal1 = 0;
+	s32    Cprog_table1 = 0;
+	s32    Cprog_cal2 = 0;
+	s32    Cprog_table2 = 0;
+	s32    Cprog_cal3 = 0;
+	s32    Cprog_table3 = 0;
+
+	state->m_RF_A1[RFBand] = 0;
+	state->m_RF_B1[RFBand] = 0;
+	state->m_RF_A2[RFBand] = 0;
+	state->m_RF_B2[RFBand] = 0;
+
+	do {
+		status = PowerScan(state, RFBand, RF1, &RF1, &bcal);
+		if (status < 0)
+			break;
+		if (bcal) {
+			status = CalibrateRF(state, RFBand, RF1, &Cprog_cal1);
+			if (status < 0)
+				break;
+		}
+		SearchMap2(m_RF_Cal_Map, RF1, &Cprog_table1);
+		if (!bcal)
+			Cprog_cal1 = Cprog_table1;
+		state->m_RF_B1[RFBand] = Cprog_cal1 - Cprog_table1;
+		/* state->m_RF_A1[RF_Band] = ???? */
+
+		if (RF2 == 0)
+			break;
+
+		status = PowerScan(state, RFBand, RF2, &RF2, &bcal);
+		if (status < 0)
+			break;
+		if (bcal) {
+			status = CalibrateRF(state, RFBand, RF2, &Cprog_cal2);
+			if (status < 0)
+				break;
+		}
+		SearchMap2(m_RF_Cal_Map, RF2, &Cprog_table2);
+		if (!bcal)
+			Cprog_cal2 = Cprog_table2;
+
+		state->m_RF_A1[RFBand] =
+			(Cprog_cal2 - Cprog_table2 - Cprog_cal1 + Cprog_table1) /
+			((s32)(RF2) - (s32)(RF1));
+
+		if (RF3 == 0)
+			break;
+
+		status = PowerScan(state, RFBand, RF3, &RF3, &bcal);
+		if (status < 0)
+			break;
+		if (bcal) {
+			status = CalibrateRF(state, RFBand, RF3, &Cprog_cal3);
+			if (status < 0)
+				break;
+		}
+		SearchMap2(m_RF_Cal_Map, RF3, &Cprog_table3);
+		if (!bcal)
+			Cprog_cal3 = Cprog_table3;
+		state->m_RF_A2[RFBand] = (Cprog_cal3 - Cprog_table3 - Cprog_cal2 + Cprog_table2) / ((s32)(RF3) - (s32)(RF2));
+		state->m_RF_B2[RFBand] = Cprog_cal2 - Cprog_table2;
+
+	} while (0);
+
+	state->m_RF1[RFBand] = RF1;
+	state->m_RF2[RFBand] = RF2;
+	state->m_RF3[RFBand] = RF3;
+
+#if 0
+	printk(KERN_ERR "tda18271c2dd: %s %d RF1 = %d A1 = %d B1 = %d RF2 = %d A2 = %d B2 = %d RF3 = %d\n", __func__,
+	       RFBand, RF1, state->m_RF_A1[RFBand], state->m_RF_B1[RFBand], RF2,
+	       state->m_RF_A2[RFBand], state->m_RF_B2[RFBand], RF3);
+#endif
+
+	return status;
+}
+
+static int PowerScan(struct tda_state *state,
+		     u8 RFBand, u32 RF_in, u32 *pRF_Out, bool *pbcal)
+{
+	int status = 0;
+	do {
+		u8   Gain_Taper = 0;
+		s32  RFC_Cprog = 0;
+		u8   CID_Target = 0;
+		u8   CountLimit = 0;
+		u32  freq_MainPLL;
+		u8   Regs[NUM_REGS];
+		u8   CID_Gain;
+		s32  Count = 0;
+		int  sign  = 1;
+		bool wait = false;
+
+		if (!(SearchMap2(m_RF_Cal_Map, RF_in, &RFC_Cprog) &&
+		      SearchMap1(m_GainTaper_Map, RF_in, &Gain_Taper) &&
+		      SearchMap3(m_CID_Target_Map, RF_in, &CID_Target, &CountLimit))) {
+
+			printk(KERN_ERR "tda18271c2dd: %s Search map failed\n", __func__);
+			return -EINVAL;
+		}
+
+		state->m_Regs[EP2] = (RFBand << 5) | Gain_Taper;
+		state->m_Regs[EB14] = (RFC_Cprog);
+		status = UpdateReg(state, EP2);
+		if (status < 0)
+			break;
+		status = UpdateReg(state, EB14);
+		if (status < 0)
+			break;
+
+		freq_MainPLL = RF_in + 1000000;
+		status = CalcMainPLL(state, freq_MainPLL);
+		if (status < 0)
+			break;
+		msleep(5);
+		state->m_Regs[EP4] = (state->m_Regs[EP4] & ~0x03) | 1;    /* CAL_mode = 1 */
+		status = UpdateReg(state, EP4);
+		if (status < 0)
+			break;
+		status = UpdateReg(state, EP2);  /* Launch power measurement */
+		if (status < 0)
+			break;
+		status = ReadExtented(state, Regs);
+		if (status < 0)
+			break;
+		CID_Gain = Regs[EB10] & 0x3F;
+		state->m_Regs[ID] = Regs[ID];  /* Chip version, (needed for C1 workarround in CalibrateRF) */
+
+		*pRF_Out = RF_in;
+
+		while (CID_Gain < CID_Target) {
+			freq_MainPLL = RF_in + sign * Count + 1000000;
+			status = CalcMainPLL(state, freq_MainPLL);
+			if (status < 0)
+				break;
+			msleep(wait ? 5 : 1);
+			wait = false;
+			status = UpdateReg(state, EP2);  /* Launch power measurement */
+			if (status < 0)
+				break;
+			status = ReadExtented(state, Regs);
+			if (status < 0)
+				break;
+			CID_Gain = Regs[EB10] & 0x3F;
+			Count += 200000;
+
+			if (Count < CountLimit * 100000)
+				continue;
+			if (sign < 0)
+				break;
+
+			sign = -sign;
+			Count = 200000;
+			wait = true;
+		}
+		status = status;
+		if (status < 0)
+			break;
+		if (CID_Gain >= CID_Target) {
+			*pbcal = true;
+			*pRF_Out = freq_MainPLL - 1000000;
+		} else
+			*pbcal = false;
+	} while (0);
+
+	return status;
+}
+
+static int PowerScanInit(struct tda_state *state)
+{
+	int status = 0;
+	do {
+		state->m_Regs[EP3] = (state->m_Regs[EP3] & ~0x1F) | 0x12;
+		state->m_Regs[EP4] = (state->m_Regs[EP4] & ~0x1F); /* If level = 0, Cal mode = 0 */
+		status = UpdateRegs(state, EP3, EP4);
+		if (status < 0)
+			break;
+		state->m_Regs[EB18] = (state->m_Regs[EB18] & ~0x03); /* AGC 1 Gain = 0 */
+		status = UpdateReg(state, EB18);
+		if (status < 0)
+			break;
+		state->m_Regs[EB21] = (state->m_Regs[EB21] & ~0x03); /* AGC 2 Gain = 0 (Datasheet = 3) */
+		state->m_Regs[EB23] = (state->m_Regs[EB23] | 0x06); /* ForceLP_Fc2_En = 1, LPFc[2] = 1 */
+		status = UpdateRegs(state, EB21, EB23);
+		if (status < 0)
+			break;
+	} while (0);
+	return status;
+}
+
+static int CalcRFFilterCurve(struct tda_state *state)
+{
+	int status = 0;
+	do {
+		msleep(200);      /* Temperature stabilisation */
+		status = PowerScanInit(state);
+		if (status < 0)
+			break;
+		status = RFTrackingFiltersInit(state, 0);
+		if (status < 0)
+			break;
+		status = RFTrackingFiltersInit(state, 1);
+		if (status < 0)
+			break;
+		status = RFTrackingFiltersInit(state, 2);
+		if (status < 0)
+			break;
+		status = RFTrackingFiltersInit(state, 3);
+		if (status < 0)
+			break;
+		status = RFTrackingFiltersInit(state, 4);
+		if (status < 0)
+			break;
+		status = RFTrackingFiltersInit(state, 5);
+		if (status < 0)
+			break;
+		status = RFTrackingFiltersInit(state, 6);
+		if (status < 0)
+			break;
+		status = ThermometerRead(state, &state->m_TMValue_RFCal); /* also switches off Cal mode !!! */
+		if (status < 0)
+			break;
+	} while (0);
+
+	return status;
+}
+
+static int FixedContentsI2CUpdate(struct tda_state *state)
+{
+	static u8 InitRegs[] = {
+		0x08, 0x80, 0xC6,
+		0xDF, 0x16, 0x60, 0x80,
+		0x80, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00,
+		0xFC, 0x01, 0x84, 0x41,
+		0x01, 0x84, 0x40, 0x07,
+		0x00, 0x00, 0x96, 0x3F,
+		0xC1, 0x00, 0x8F, 0x00,
+		0x00, 0x8C, 0x00, 0x20,
+		0xB3, 0x48, 0xB0,
+	};
+	int status = 0;
+	memcpy(&state->m_Regs[TM], InitRegs, EB23 - TM + 1);
+	do {
+		status = UpdateRegs(state, TM, EB23);
+		if (status < 0)
+			break;
+
+		/* AGC1 gain setup */
+		state->m_Regs[EB17] = 0x00;
+		status = UpdateReg(state, EB17);
+		if (status < 0)
+			break;
+		state->m_Regs[EB17] = 0x03;
+		status = UpdateReg(state, EB17);
+		if (status < 0)
+			break;
+		state->m_Regs[EB17] = 0x43;
+		status = UpdateReg(state, EB17);
+		if (status < 0)
+			break;
+		state->m_Regs[EB17] = 0x4C;
+		status = UpdateReg(state, EB17);
+		if (status < 0)
+			break;
+
+		/* IRC Cal Low band */
+		state->m_Regs[EP3] = 0x1F;
+		state->m_Regs[EP4] = 0x66;
+		state->m_Regs[EP5] = 0x81;
+		state->m_Regs[CPD] = 0xCC;
+		state->m_Regs[CD1] = 0x6C;
+		state->m_Regs[CD2] = 0x00;
+		state->m_Regs[CD3] = 0x00;
+		state->m_Regs[MPD] = 0xC5;
+		state->m_Regs[MD1] = 0x77;
+		state->m_Regs[MD2] = 0x08;
+		state->m_Regs[MD3] = 0x00;
+		status = UpdateRegs(state, EP2, MD3); /* diff between sw and datasheet (ep3-md3) */
+		if (status < 0)
+			break;
+
+#if 0
+		state->m_Regs[EB4] = 0x61;          /* missing in sw */
+		status = UpdateReg(state, EB4);
+		if (status < 0)
+			break;
+		msleep(1);
+		state->m_Regs[EB4] = 0x41;
+		status = UpdateReg(state, EB4);
+		if (status < 0)
+			break;
+#endif
+
+		msleep(5);
+		status = UpdateReg(state, EP1);
+		if (status < 0)
+			break;
+		msleep(5);
+
+		state->m_Regs[EP5] = 0x85;
+		state->m_Regs[CPD] = 0xCB;
+		state->m_Regs[CD1] = 0x66;
+		state->m_Regs[CD2] = 0x70;
+		status = UpdateRegs(state, EP3, CD3);
+		if (status < 0)
+			break;
+		msleep(5);
+		status = UpdateReg(state, EP2);
+		if (status < 0)
+			break;
+		msleep(30);
+
+		/* IRC Cal mid band */
+		state->m_Regs[EP5] = 0x82;
+		state->m_Regs[CPD] = 0xA8;
+		state->m_Regs[CD2] = 0x00;
+		state->m_Regs[MPD] = 0xA1; /* Datasheet = 0xA9 */
+		state->m_Regs[MD1] = 0x73;
+		state->m_Regs[MD2] = 0x1A;
+		status = UpdateRegs(state, EP3, MD3);
+		if (status < 0)
+			break;
+
+		msleep(5);
+		status = UpdateReg(state, EP1);
+		if (status < 0)
+			break;
+		msleep(5);
+
+		state->m_Regs[EP5] = 0x86;
+		state->m_Regs[CPD] = 0xA8;
+		state->m_Regs[CD1] = 0x66;
+		state->m_Regs[CD2] = 0xA0;
+		status = UpdateRegs(state, EP3, CD3);
+		if (status < 0)
+			break;
+		msleep(5);
+		status = UpdateReg(state, EP2);
+		if (status < 0)
+			break;
+		msleep(30);
+
+		/* IRC Cal high band */
+		state->m_Regs[EP5] = 0x83;
+		state->m_Regs[CPD] = 0x98;
+		state->m_Regs[CD1] = 0x65;
+		state->m_Regs[CD2] = 0x00;
+		state->m_Regs[MPD] = 0x91;  /* Datasheet = 0x91 */
+		state->m_Regs[MD1] = 0x71;
+		state->m_Regs[MD2] = 0xCD;
+		status = UpdateRegs(state, EP3, MD3);
+		if (status < 0)
+			break;
+		msleep(5);
+		status = UpdateReg(state, EP1);
+		if (status < 0)
+			break;
+		msleep(5);
+		state->m_Regs[EP5] = 0x87;
+		state->m_Regs[CD1] = 0x65;
+		state->m_Regs[CD2] = 0x50;
+		status = UpdateRegs(state, EP3, CD3);
+		if (status < 0)
+			break;
+		msleep(5);
+		status = UpdateReg(state, EP2);
+		if (status < 0)
+			break;
+		msleep(30);
+
+		/* Back to normal */
+		state->m_Regs[EP4] = 0x64;
+		status = UpdateReg(state, EP4);
+		if (status < 0)
+			break;
+		status = UpdateReg(state, EP1);
+		if (status < 0)
+			break;
+
+	} while (0);
+	return status;
+}
+
+static int InitCal(struct tda_state *state)
+{
+	int status = 0;
+
+	do {
+		status = FixedContentsI2CUpdate(state);
+		if (status < 0)
+			break;
+		status = CalcRFFilterCurve(state);
+		if (status < 0)
+			break;
+		status = StandBy(state);
+		if (status < 0)
+			break;
+		/* m_bInitDone = true; */
+	} while (0);
+	return status;
+};
+
+static int RFTrackingFiltersCorrection(struct tda_state *state,
+				       u32 Frequency)
+{
+	int status = 0;
+	s32 Cprog_table;
+	u8 RFBand;
+	u8 dCoverdT;
+
+	if (!SearchMap2(m_RF_Cal_Map, Frequency, &Cprog_table) ||
+	    !SearchMap4(m_RF_Band_Map, Frequency, &RFBand) ||
+	    !SearchMap1(m_RF_Cal_DC_Over_DT_Map, Frequency, &dCoverdT))
+
+		return -EINVAL;
+
+	do {
+		u8 TMValue_Current;
+		u32   RF1 = state->m_RF1[RFBand];
+		u32   RF2 = state->m_RF1[RFBand];
+		u32   RF3 = state->m_RF1[RFBand];
+		s32    RF_A1 = state->m_RF_A1[RFBand];
+		s32    RF_B1 = state->m_RF_B1[RFBand];
+		s32    RF_A2 = state->m_RF_A2[RFBand];
+		s32    RF_B2 = state->m_RF_B2[RFBand];
+		s32 Capprox = 0;
+		int TComp;
+
+		state->m_Regs[EP3] &= ~0xE0;  /* Power up */
+		status = UpdateReg(state, EP3);
+		if (status < 0)
+			break;
+
+		status = ThermometerRead(state, &TMValue_Current);
+		if (status < 0)
+			break;
+
+		if (RF3 == 0 || Frequency < RF2)
+			Capprox = RF_A1 * ((s32)(Frequency) - (s32)(RF1)) + RF_B1 + Cprog_table;
+		else
+			Capprox = RF_A2 * ((s32)(Frequency) - (s32)(RF2)) + RF_B2 + Cprog_table;
+
+		TComp = (int)(dCoverdT) * ((int)(TMValue_Current) - (int)(state->m_TMValue_RFCal))/1000;
+
+		Capprox += TComp;
+
+		if (Capprox < 0)
+			Capprox = 0;
+		else if (Capprox > 255)
+			Capprox = 255;
+
+
+		/* TODO Temperature compensation. There is defenitely a scale factor */
+		/*      missing in the datasheet, so leave it out for now.           */
+		state->m_Regs[EB14] = Capprox;
+
+		status = UpdateReg(state, EB14);
+		if (status < 0)
+			break;
+
+	} while (0);
+	return status;
+}
+
+static int ChannelConfiguration(struct tda_state *state,
+				u32 Frequency, int Standard)
+{
+
+	s32 IntermediateFrequency = m_StandardTable[Standard].m_IFFrequency;
+	int status = 0;
+
+	u8 BP_Filter = 0;
+	u8 RF_Band = 0;
+	u8 GainTaper = 0;
+	u8 IR_Meas = 0;
+
+	state->IF = IntermediateFrequency;
+	/* printk("tda18271c2dd: %s Freq = %d Standard = %d IF = %d\n", __func__, Frequency, Standard, IntermediateFrequency); */
+	/* get values from tables */
+
+	if (!(SearchMap1(m_BP_Filter_Map, Frequency, &BP_Filter) &&
+	       SearchMap1(m_GainTaper_Map, Frequency, &GainTaper) &&
+	       SearchMap1(m_IR_Meas_Map, Frequency, &IR_Meas) &&
+	       SearchMap4(m_RF_Band_Map, Frequency, &RF_Band))) {
+
+		printk(KERN_ERR "tda18271c2dd: %s SearchMap failed\n", __func__);
+		return -EINVAL;
+	}
+
+	do {
+		state->m_Regs[EP3] = (state->m_Regs[EP3] & ~0x1F) | m_StandardTable[Standard].m_EP3_4_0;
+		state->m_Regs[EP3] &= ~0x04;   /* switch RFAGC to high speed mode */
+
+		/* m_EP4 default for XToutOn, CAL_Mode (0) */
+		state->m_Regs[EP4] = state->m_EP4 | ((Standard > HF_AnalogMax) ? state->m_IFLevelDigital : state->m_IFLevelAnalog);
+		/* state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDigital; */
+		if (Standard <= HF_AnalogMax)
+			state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelAnalog;
+		else if (Standard <= HF_ATSC)
+			state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDVBT;
+		else if (Standard <= HF_DVBC)
+			state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDVBC;
+		else
+			state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDigital;
+
+		if ((Standard == HF_FM_Radio) && state->m_bFMInput)
+			state->m_Regs[EP4] |= 80;
+
+		state->m_Regs[MPD] &= ~0x80;
+		if (Standard > HF_AnalogMax)
+			state->m_Regs[MPD] |= 0x80; /* Add IF_notch for digital */
+
+		state->m_Regs[EB22] = m_StandardTable[Standard].m_EB22;
+
+		/* Note: This is missing from flowchart in TDA18271 specification ( 1.5 MHz cutoff for FM ) */
+		if (Standard == HF_FM_Radio)
+			state->m_Regs[EB23] |=  0x06; /* ForceLP_Fc2_En = 1, LPFc[2] = 1 */
+		else
+			state->m_Regs[EB23] &= ~0x06; /* ForceLP_Fc2_En = 0, LPFc[2] = 0 */
+
+		status = UpdateRegs(state, EB22, EB23);
+		if (status < 0)
+			break;
+
+		state->m_Regs[EP1] = (state->m_Regs[EP1] & ~0x07) | 0x40 | BP_Filter;   /* Dis_Power_level = 1, Filter */
+		state->m_Regs[EP5] = (state->m_Regs[EP5] & ~0x07) | IR_Meas;
+		state->m_Regs[EP2] = (RF_Band << 5) | GainTaper;
+
+		state->m_Regs[EB1] = (state->m_Regs[EB1] & ~0x07) |
+			(state->m_bMaster ? 0x04 : 0x00); /* CALVCO_FortLOn = MS */
+		/* AGC1_always_master = 0 */
+		/* AGC_firstn = 0 */
+		status = UpdateReg(state, EB1);
+		if (status < 0)
+			break;
+
+		if (state->m_bMaster) {
+			status = CalcMainPLL(state, Frequency + IntermediateFrequency);
+			if (status < 0)
+				break;
+			status = UpdateRegs(state, TM, EP5);
+			if (status < 0)
+				break;
+			state->m_Regs[EB4] |= 0x20;    /* LO_forceSrce = 1 */
+			status = UpdateReg(state, EB4);
+			if (status < 0)
+				break;
+			msleep(1);
+			state->m_Regs[EB4] &= ~0x20;   /* LO_forceSrce = 0 */
+			status = UpdateReg(state, EB4);
+			if (status < 0)
+				break;
+		} else {
+			u8 PostDiv = 0;
+			u8 Div;
+			status = CalcCalPLL(state, Frequency + IntermediateFrequency);
+			if (status < 0)
+				break;
+
+			SearchMap3(m_Cal_PLL_Map, Frequency + IntermediateFrequency, &PostDiv, &Div);
+			state->m_Regs[MPD] = (state->m_Regs[MPD] & ~0x7F) | (PostDiv & 0x77);
+			status = UpdateReg(state, MPD);
+			if (status < 0)
+				break;
+			status = UpdateRegs(state, TM, EP5);
+			if (status < 0)
+				break;
+
+			state->m_Regs[EB7] |= 0x20;    /* CAL_forceSrce = 1 */
+			status = UpdateReg(state, EB7);
+			if (status < 0)
+				break;
+			msleep(1);
+			state->m_Regs[EB7] &= ~0x20;   /* CAL_forceSrce = 0 */
+			status = UpdateReg(state, EB7);
+			if (status < 0)
+				break;
+		}
+		msleep(20);
+		if (Standard != HF_FM_Radio)
+			state->m_Regs[EP3] |= 0x04;    /* RFAGC to normal mode */
+		status = UpdateReg(state, EP3);
+		if (status < 0)
+			break;
+
+	} while (0);
+	return status;
+}
+
+static int sleep(struct dvb_frontend *fe)
+{
+	struct tda_state *state = fe->tuner_priv;
+
+	StandBy(state);
+	return 0;
+}
+
+static int init(struct dvb_frontend *fe)
+{
+	return 0;
+}
+
+static int release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+
+static int set_params(struct dvb_frontend *fe)
+{
+	struct tda_state *state = fe->tuner_priv;
+	int status = 0;
+	int Standard;
+	u32 bw = fe->dtv_property_cache.bandwidth_hz;
+	u32 delsys  = fe->dtv_property_cache.delivery_system;
+
+	state->m_Frequency = fe->dtv_property_cache.frequency;
+
+	switch (delsys) {
+	case  SYS_DVBT:
+	case  SYS_DVBT2:
+		switch (bw) {
+		case 6000000:
+			Standard = HF_DVBT_6MHZ;
+			break;
+		case 7000000:
+			Standard = HF_DVBT_7MHZ;
+			break;
+		case 8000000:
+			Standard = HF_DVBT_8MHZ;
+			break;
+		default:
+			return -EINVAL;
+		}
+	case SYS_DVBC_ANNEX_A:
+	case SYS_DVBC_ANNEX_C:
+		if (bw <= 6000000)
+			Standard = HF_DVBC_6MHZ;
+		else if (bw <= 7000000)
+			Standard = HF_DVBC_7MHZ;
+		else
+			Standard = HF_DVBC_8MHZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+	do {
+		status = RFTrackingFiltersCorrection(state, state->m_Frequency);
+		if (status < 0)
+			break;
+		status = ChannelConfiguration(state, state->m_Frequency,
+					      Standard);
+		if (status < 0)
+			break;
+
+		msleep(state->m_SettlingTime);  /* Allow AGC's to settle down */
+	} while (0);
+	return status;
+}
+
+#if 0
+static int GetSignalStrength(s32 *pSignalStrength, u32 RFAgc, u32 IFAgc)
+{
+	if (IFAgc < 500) {
+		/* Scale this from 0 to 50000 */
+		*pSignalStrength = IFAgc * 100;
+	} else {
+		/* Scale range 500-1500 to 50000-80000 */
+		*pSignalStrength = 50000 + (IFAgc - 500) * 30;
+	}
+
+	return 0;
+}
+#endif
+
+static int get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tda_state *state = fe->tuner_priv;
+
+	*frequency = state->IF;
+	return 0;
+}
+
+static int get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	/* struct tda_state *state = fe->tuner_priv; */
+	/* *bandwidth = priv->bandwidth; */
+	return 0;
+}
+
+
+static struct dvb_tuner_ops tuner_ops = {
+	.info = {
+		.name = "NXP TDA18271C2D",
+		.frequency_min  =  47125000,
+		.frequency_max  = 865000000,
+		.frequency_step =     62500
+	},
+	.init              = init,
+	.sleep             = sleep,
+	.set_params        = set_params,
+	.release           = release,
+	.get_if_frequency  = get_if_frequency,
+	.get_bandwidth     = get_bandwidth,
+};
+
+struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe,
+					 struct i2c_adapter *i2c, u8 adr)
+{
+	struct tda_state *state;
+
+	state = kzalloc(sizeof(struct tda_state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	fe->tuner_priv = state;
+	state->adr = adr;
+	state->i2c = i2c;
+	memcpy(&fe->ops.tuner_ops, &tuner_ops, sizeof(struct dvb_tuner_ops));
+	reset(state);
+	InitCal(state);
+
+	return fe;
+}
+EXPORT_SYMBOL_GPL(tda18271c2dd_attach);
+
+MODULE_DESCRIPTION("TDA18271C2 driver");
+MODULE_AUTHOR("DD");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/tda18271c2dd.h b/drivers/media/dvb-frontends/tda18271c2dd.h
new file mode 100644
index 0000000..1389c74
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda18271c2dd.h
@@ -0,0 +1,16 @@
+#ifndef _TDA18271C2DD_H_
+#define _TDA18271C2DD_H_
+#if defined(CONFIG_DVB_TDA18271C2DD) || (defined(CONFIG_DVB_TDA18271C2DD_MODULE) \
+        && defined(MODULE))
+struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe,
+					 struct i2c_adapter *i2c, u8 adr);
+#else
+static inline struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe,
+					 struct i2c_adapter *i2c, u8 adr)
+{
+        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+        return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb-frontends/tda18271c2dd_maps.h b/drivers/media/dvb-frontends/tda18271c2dd_maps.h
new file mode 100644
index 0000000..b87661b
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda18271c2dd_maps.h
@@ -0,0 +1,814 @@
+enum HF_S {
+	HF_None = 0, HF_B, HF_DK, HF_G, HF_I, HF_L, HF_L1, HF_MN, HF_FM_Radio,
+	HF_AnalogMax, HF_DVBT_6MHZ, HF_DVBT_7MHZ, HF_DVBT_8MHZ,
+	HF_DVBT, HF_ATSC,  HF_DVBC_6MHZ,  HF_DVBC_7MHZ,
+	HF_DVBC_8MHZ, HF_DVBC
+};
+
+struct SStandardParam m_StandardTable[] = {
+	{       0,        0, 0x00, 0x00 },    /* HF_None */
+	{ 6000000,  7000000, 0x1D, 0x2C },    /* HF_B, */
+	{ 6900000,  8000000, 0x1E, 0x2C },    /* HF_DK, */
+	{ 7100000,  8000000, 0x1E, 0x2C },    /* HF_G, */
+	{ 7250000,  8000000, 0x1E, 0x2C },    /* HF_I, */
+	{ 6900000,  8000000, 0x1E, 0x2C },    /* HF_L, */
+	{ 1250000,  8000000, 0x1E, 0x2C },    /* HF_L1, */
+	{ 5400000,  6000000, 0x1C, 0x2C },    /* HF_MN, */
+	{ 1250000,   500000, 0x18, 0x2C },    /* HF_FM_Radio, */
+	{       0,        0, 0x00, 0x00 },    /* HF_AnalogMax (Unused) */
+	{ 3300000,  6000000, 0x1C, 0x58 },    /* HF_DVBT_6MHZ */
+	{ 3500000,  7000000, 0x1C, 0x37 },    /* HF_DVBT_7MHZ */
+	{ 4000000,  8000000, 0x1D, 0x37 },    /* HF_DVBT_8MHZ */
+	{       0,        0, 0x00, 0x00 },    /* HF_DVBT (Unused) */
+	{ 5000000,  6000000, 0x1C, 0x37 },    /* HF_ATSC  (center = 3.25 MHz) */
+	{ 4000000,  6000000, 0x1D, 0x58 },    /* HF_DVBC_6MHZ (Chicago) */
+	{ 4500000,  7000000, 0x1E, 0x37 },    /* HF_DVBC_7MHZ (not documented by NXP) */
+	{ 5000000,  8000000, 0x1F, 0x37 },    /* HF_DVBC_8MHZ */
+	{       0,        0, 0x00, 0x00 },    /* HF_DVBC (Unused) */
+};
+
+struct SMap  m_BP_Filter_Map[] = {
+	{   62000000,  0x00 },
+	{   84000000,  0x01 },
+	{  100000000,  0x02 },
+	{  140000000,  0x03 },
+	{  170000000,  0x04 },
+	{  180000000,  0x05 },
+	{  865000000,  0x06 },
+	{          0,  0x00 },    /* Table End */
+};
+
+static struct SMapI m_RF_Cal_Map[] = {
+	{   41000000,  0x0F },
+	{   43000000,  0x1C },
+	{   45000000,  0x2F },
+	{   46000000,  0x39 },
+	{   47000000,  0x40 },
+	{   47900000,  0x50 },
+	{   49100000,  0x16 },
+	{   50000000,  0x18 },
+	{   51000000,  0x20 },
+	{   53000000,  0x28 },
+	{   55000000,  0x2B },
+	{   56000000,  0x32 },
+	{   57000000,  0x35 },
+	{   58000000,  0x3E },
+	{   59000000,  0x43 },
+	{   60000000,  0x4E },
+	{   61100000,  0x55 },
+	{   63000000,  0x0F },
+	{   64000000,  0x11 },
+	{   65000000,  0x12 },
+	{   66000000,  0x15 },
+	{   67000000,  0x16 },
+	{   68000000,  0x17 },
+	{   70000000,  0x19 },
+	{   71000000,  0x1C },
+	{   72000000,  0x1D },
+	{   73000000,  0x1F },
+	{   74000000,  0x20 },
+	{   75000000,  0x21 },
+	{   76000000,  0x24 },
+	{   77000000,  0x25 },
+	{   78000000,  0x27 },
+	{   80000000,  0x28 },
+	{   81000000,  0x29 },
+	{   82000000,  0x2D },
+	{   83000000,  0x2E },
+	{   84000000,  0x2F },
+	{   85000000,  0x31 },
+	{   86000000,  0x33 },
+	{   87000000,  0x34 },
+	{   88000000,  0x35 },
+	{   89000000,  0x37 },
+	{   90000000,  0x38 },
+	{   91000000,  0x39 },
+	{   93000000,  0x3C },
+	{   94000000,  0x3E },
+	{   95000000,  0x3F },
+	{   96000000,  0x40 },
+	{   97000000,  0x42 },
+	{   99000000,  0x45 },
+	{  100000000,  0x46 },
+	{  102000000,  0x48 },
+	{  103000000,  0x4A },
+	{  105000000,  0x4D },
+	{  106000000,  0x4E },
+	{  107000000,  0x50 },
+	{  108000000,  0x51 },
+	{  110000000,  0x54 },
+	{  111000000,  0x56 },
+	{  112000000,  0x57 },
+	{  113000000,  0x58 },
+	{  114000000,  0x59 },
+	{  115000000,  0x5C },
+	{  116000000,  0x5D },
+	{  117000000,  0x5F },
+	{  119000000,  0x60 },
+	{  120000000,  0x64 },
+	{  121000000,  0x65 },
+	{  122000000,  0x66 },
+	{  123000000,  0x68 },
+	{  124000000,  0x69 },
+	{  125000000,  0x6C },
+	{  126000000,  0x6D },
+	{  127000000,  0x6E },
+	{  128000000,  0x70 },
+	{  129000000,  0x71 },
+	{  130000000,  0x75 },
+	{  131000000,  0x77 },
+	{  132000000,  0x78 },
+	{  133000000,  0x7B },
+	{  134000000,  0x7E },
+	{  135000000,  0x81 },
+	{  136000000,  0x82 },
+	{  137000000,  0x87 },
+	{  138000000,  0x88 },
+	{  139000000,  0x8D },
+	{  140000000,  0x8E },
+	{  141000000,  0x91 },
+	{  142000000,  0x95 },
+	{  143000000,  0x9A },
+	{  144000000,  0x9D },
+	{  145000000,  0xA1 },
+	{  146000000,  0xA2 },
+	{  147000000,  0xA4 },
+	{  148000000,  0xA9 },
+	{  149000000,  0xAE },
+	{  150000000,  0xB0 },
+	{  151000000,  0xB1 },
+	{  152000000,  0xB7 },
+	{  152600000,  0xBD },
+	{  154000000,  0x20 },
+	{  155000000,  0x22 },
+	{  156000000,  0x24 },
+	{  157000000,  0x25 },
+	{  158000000,  0x27 },
+	{  159000000,  0x29 },
+	{  160000000,  0x2C },
+	{  161000000,  0x2D },
+	{  163000000,  0x2E },
+	{  164000000,  0x2F },
+	{  164700000,  0x30 },
+	{  166000000,  0x11 },
+	{  167000000,  0x12 },
+	{  168000000,  0x13 },
+	{  169000000,  0x14 },
+	{  170000000,  0x15 },
+	{  172000000,  0x16 },
+	{  173000000,  0x17 },
+	{  174000000,  0x18 },
+	{  175000000,  0x1A },
+	{  176000000,  0x1B },
+	{  178000000,  0x1D },
+	{  179000000,  0x1E },
+	{  180000000,  0x1F },
+	{  181000000,  0x20 },
+	{  182000000,  0x21 },
+	{  183000000,  0x22 },
+	{  184000000,  0x24 },
+	{  185000000,  0x25 },
+	{  186000000,  0x26 },
+	{  187000000,  0x27 },
+	{  188000000,  0x29 },
+	{  189000000,  0x2A },
+	{  190000000,  0x2C },
+	{  191000000,  0x2D },
+	{  192000000,  0x2E },
+	{  193000000,  0x2F },
+	{  194000000,  0x30 },
+	{  195000000,  0x33 },
+	{  196000000,  0x35 },
+	{  198000000,  0x36 },
+	{  200000000,  0x38 },
+	{  201000000,  0x3C },
+	{  202000000,  0x3D },
+	{  203500000,  0x3E },
+	{  206000000,  0x0E },
+	{  208000000,  0x0F },
+	{  212000000,  0x10 },
+	{  216000000,  0x11 },
+	{  217000000,  0x12 },
+	{  218000000,  0x13 },
+	{  220000000,  0x14 },
+	{  222000000,  0x15 },
+	{  225000000,  0x16 },
+	{  228000000,  0x17 },
+	{  231000000,  0x18 },
+	{  234000000,  0x19 },
+	{  235000000,  0x1A },
+	{  236000000,  0x1B },
+	{  237000000,  0x1C },
+	{  240000000,  0x1D },
+	{  242000000,  0x1E },
+	{  244000000,  0x1F },
+	{  247000000,  0x20 },
+	{  249000000,  0x21 },
+	{  252000000,  0x22 },
+	{  253000000,  0x23 },
+	{  254000000,  0x24 },
+	{  256000000,  0x25 },
+	{  259000000,  0x26 },
+	{  262000000,  0x27 },
+	{  264000000,  0x28 },
+	{  267000000,  0x29 },
+	{  269000000,  0x2A },
+	{  271000000,  0x2B },
+	{  273000000,  0x2C },
+	{  275000000,  0x2D },
+	{  277000000,  0x2E },
+	{  279000000,  0x2F },
+	{  282000000,  0x30 },
+	{  284000000,  0x31 },
+	{  286000000,  0x32 },
+	{  287000000,  0x33 },
+	{  290000000,  0x34 },
+	{  293000000,  0x35 },
+	{  295000000,  0x36 },
+	{  297000000,  0x37 },
+	{  300000000,  0x38 },
+	{  303000000,  0x39 },
+	{  305000000,  0x3A },
+	{  306000000,  0x3B },
+	{  307000000,  0x3C },
+	{  310000000,  0x3D },
+	{  312000000,  0x3E },
+	{  315000000,  0x3F },
+	{  318000000,  0x40 },
+	{  320000000,  0x41 },
+	{  323000000,  0x42 },
+	{  324000000,  0x43 },
+	{  325000000,  0x44 },
+	{  327000000,  0x45 },
+	{  331000000,  0x46 },
+	{  334000000,  0x47 },
+	{  337000000,  0x48 },
+	{  339000000,  0x49 },
+	{  340000000,  0x4A },
+	{  341000000,  0x4B },
+	{  343000000,  0x4C },
+	{  345000000,  0x4D },
+	{  349000000,  0x4E },
+	{  352000000,  0x4F },
+	{  353000000,  0x50 },
+	{  355000000,  0x51 },
+	{  357000000,  0x52 },
+	{  359000000,  0x53 },
+	{  361000000,  0x54 },
+	{  362000000,  0x55 },
+	{  364000000,  0x56 },
+	{  368000000,  0x57 },
+	{  370000000,  0x58 },
+	{  372000000,  0x59 },
+	{  375000000,  0x5A },
+	{  376000000,  0x5B },
+	{  377000000,  0x5C },
+	{  379000000,  0x5D },
+	{  382000000,  0x5E },
+	{  384000000,  0x5F },
+	{  385000000,  0x60 },
+	{  386000000,  0x61 },
+	{  388000000,  0x62 },
+	{  390000000,  0x63 },
+	{  393000000,  0x64 },
+	{  394000000,  0x65 },
+	{  396000000,  0x66 },
+	{  397000000,  0x67 },
+	{  398000000,  0x68 },
+	{  400000000,  0x69 },
+	{  402000000,  0x6A },
+	{  403000000,  0x6B },
+	{  407000000,  0x6C },
+	{  408000000,  0x6D },
+	{  409000000,  0x6E },
+	{  410000000,  0x6F },
+	{  411000000,  0x70 },
+	{  412000000,  0x71 },
+	{  413000000,  0x72 },
+	{  414000000,  0x73 },
+	{  417000000,  0x74 },
+	{  418000000,  0x75 },
+	{  420000000,  0x76 },
+	{  422000000,  0x77 },
+	{  423000000,  0x78 },
+	{  424000000,  0x79 },
+	{  427000000,  0x7A },
+	{  428000000,  0x7B },
+	{  429000000,  0x7D },
+	{  432000000,  0x7F },
+	{  434000000,  0x80 },
+	{  435000000,  0x81 },
+	{  436000000,  0x83 },
+	{  437000000,  0x84 },
+	{  438000000,  0x85 },
+	{  439000000,  0x86 },
+	{  440000000,  0x87 },
+	{  441000000,  0x88 },
+	{  442000000,  0x89 },
+	{  445000000,  0x8A },
+	{  446000000,  0x8B },
+	{  447000000,  0x8C },
+	{  448000000,  0x8E },
+	{  449000000,  0x8F },
+	{  450000000,  0x90 },
+	{  452000000,  0x91 },
+	{  453000000,  0x93 },
+	{  454000000,  0x94 },
+	{  456000000,  0x96 },
+	{  457800000,  0x98 },
+	{  461000000,  0x11 },
+	{  468000000,  0x12 },
+	{  472000000,  0x13 },
+	{  473000000,  0x14 },
+	{  474000000,  0x15 },
+	{  481000000,  0x16 },
+	{  486000000,  0x17 },
+	{  491000000,  0x18 },
+	{  498000000,  0x19 },
+	{  499000000,  0x1A },
+	{  501000000,  0x1B },
+	{  506000000,  0x1C },
+	{  511000000,  0x1D },
+	{  516000000,  0x1E },
+	{  520000000,  0x1F },
+	{  521000000,  0x20 },
+	{  525000000,  0x21 },
+	{  529000000,  0x22 },
+	{  533000000,  0x23 },
+	{  539000000,  0x24 },
+	{  541000000,  0x25 },
+	{  547000000,  0x26 },
+	{  549000000,  0x27 },
+	{  551000000,  0x28 },
+	{  556000000,  0x29 },
+	{  561000000,  0x2A },
+	{  563000000,  0x2B },
+	{  565000000,  0x2C },
+	{  569000000,  0x2D },
+	{  571000000,  0x2E },
+	{  577000000,  0x2F },
+	{  580000000,  0x30 },
+	{  582000000,  0x31 },
+	{  584000000,  0x32 },
+	{  588000000,  0x33 },
+	{  591000000,  0x34 },
+	{  596000000,  0x35 },
+	{  598000000,  0x36 },
+	{  603000000,  0x37 },
+	{  604000000,  0x38 },
+	{  606000000,  0x39 },
+	{  612000000,  0x3A },
+	{  615000000,  0x3B },
+	{  617000000,  0x3C },
+	{  621000000,  0x3D },
+	{  622000000,  0x3E },
+	{  625000000,  0x3F },
+	{  632000000,  0x40 },
+	{  633000000,  0x41 },
+	{  634000000,  0x42 },
+	{  642000000,  0x43 },
+	{  643000000,  0x44 },
+	{  647000000,  0x45 },
+	{  650000000,  0x46 },
+	{  652000000,  0x47 },
+	{  657000000,  0x48 },
+	{  661000000,  0x49 },
+	{  662000000,  0x4A },
+	{  665000000,  0x4B },
+	{  667000000,  0x4C },
+	{  670000000,  0x4D },
+	{  673000000,  0x4E },
+	{  676000000,  0x4F },
+	{  677000000,  0x50 },
+	{  681000000,  0x51 },
+	{  683000000,  0x52 },
+	{  686000000,  0x53 },
+	{  688000000,  0x54 },
+	{  689000000,  0x55 },
+	{  691000000,  0x56 },
+	{  695000000,  0x57 },
+	{  698000000,  0x58 },
+	{  703000000,  0x59 },
+	{  704000000,  0x5A },
+	{  705000000,  0x5B },
+	{  707000000,  0x5C },
+	{  710000000,  0x5D },
+	{  712000000,  0x5E },
+	{  717000000,  0x5F },
+	{  718000000,  0x60 },
+	{  721000000,  0x61 },
+	{  722000000,  0x62 },
+	{  723000000,  0x63 },
+	{  725000000,  0x64 },
+	{  727000000,  0x65 },
+	{  730000000,  0x66 },
+	{  732000000,  0x67 },
+	{  735000000,  0x68 },
+	{  740000000,  0x69 },
+	{  741000000,  0x6A },
+	{  742000000,  0x6B },
+	{  743000000,  0x6C },
+	{  745000000,  0x6D },
+	{  747000000,  0x6E },
+	{  748000000,  0x6F },
+	{  750000000,  0x70 },
+	{  752000000,  0x71 },
+	{  754000000,  0x72 },
+	{  757000000,  0x73 },
+	{  758000000,  0x74 },
+	{  760000000,  0x75 },
+	{  763000000,  0x76 },
+	{  764000000,  0x77 },
+	{  766000000,  0x78 },
+	{  767000000,  0x79 },
+	{  768000000,  0x7A },
+	{  773000000,  0x7B },
+	{  774000000,  0x7C },
+	{  776000000,  0x7D },
+	{  777000000,  0x7E },
+	{  778000000,  0x7F },
+	{  779000000,  0x80 },
+	{  781000000,  0x81 },
+	{  783000000,  0x82 },
+	{  784000000,  0x83 },
+	{  785000000,  0x84 },
+	{  786000000,  0x85 },
+	{  793000000,  0x86 },
+	{  794000000,  0x87 },
+	{  795000000,  0x88 },
+	{  797000000,  0x89 },
+	{  799000000,  0x8A },
+	{  801000000,  0x8B },
+	{  802000000,  0x8C },
+	{  803000000,  0x8D },
+	{  804000000,  0x8E },
+	{  810000000,  0x90 },
+	{  811000000,  0x91 },
+	{  812000000,  0x92 },
+	{  814000000,  0x93 },
+	{  816000000,  0x94 },
+	{  817000000,  0x96 },
+	{  818000000,  0x97 },
+	{  820000000,  0x98 },
+	{  821000000,  0x99 },
+	{  822000000,  0x9A },
+	{  828000000,  0x9B },
+	{  829000000,  0x9D },
+	{  830000000,  0x9F },
+	{  831000000,  0xA0 },
+	{  833000000,  0xA1 },
+	{  835000000,  0xA2 },
+	{  836000000,  0xA3 },
+	{  837000000,  0xA4 },
+	{  838000000,  0xA6 },
+	{  840000000,  0xA8 },
+	{  842000000,  0xA9 },
+	{  845000000,  0xAA },
+	{  846000000,  0xAB },
+	{  847000000,  0xAD },
+	{  848000000,  0xAE },
+	{  852000000,  0xAF },
+	{  853000000,  0xB0 },
+	{  858000000,  0xB1 },
+	{  860000000,  0xB2 },
+	{  861000000,  0xB3 },
+	{  862000000,  0xB4 },
+	{  863000000,  0xB6 },
+	{  864000000,  0xB8 },
+	{  865000000,  0xB9 },
+	{          0,  0x00 },    /* Table End */
+};
+
+
+static struct SMap2  m_KM_Map[] = {
+	{   47900000,  3, 2 },
+	{   61100000,  3, 1 },
+	{  350000000,  3, 0 },
+	{  720000000,  2, 1 },
+	{  865000000,  3, 3 },
+	{          0,  0x00 },    /* Table End */
+};
+
+static struct SMap2 m_Main_PLL_Map[] = {
+	{  33125000, 0x57, 0xF0 },
+	{  35500000, 0x56, 0xE0 },
+	{  38188000, 0x55, 0xD0 },
+	{  41375000, 0x54, 0xC0 },
+	{  45125000, 0x53, 0xB0 },
+	{  49688000, 0x52, 0xA0 },
+	{  55188000, 0x51, 0x90 },
+	{  62125000, 0x50, 0x80 },
+	{  66250000, 0x47, 0x78 },
+	{  71000000, 0x46, 0x70 },
+	{  76375000, 0x45, 0x68 },
+	{  82750000, 0x44, 0x60 },
+	{  90250000, 0x43, 0x58 },
+	{  99375000, 0x42, 0x50 },
+	{ 110375000, 0x41, 0x48 },
+	{ 124250000, 0x40, 0x40 },
+	{ 132500000, 0x37, 0x3C },
+	{ 142000000, 0x36, 0x38 },
+	{ 152750000, 0x35, 0x34 },
+	{ 165500000, 0x34, 0x30 },
+	{ 180500000, 0x33, 0x2C },
+	{ 198750000, 0x32, 0x28 },
+	{ 220750000, 0x31, 0x24 },
+	{ 248500000, 0x30, 0x20 },
+	{ 265000000, 0x27, 0x1E },
+	{ 284000000, 0x26, 0x1C },
+	{ 305500000, 0x25, 0x1A },
+	{ 331000000, 0x24, 0x18 },
+	{ 361000000, 0x23, 0x16 },
+	{ 397500000, 0x22, 0x14 },
+	{ 441500000, 0x21, 0x12 },
+	{ 497000000, 0x20, 0x10 },
+	{ 530000000, 0x17, 0x0F },
+	{ 568000000, 0x16, 0x0E },
+	{ 611000000, 0x15, 0x0D },
+	{ 662000000, 0x14, 0x0C },
+	{ 722000000, 0x13, 0x0B },
+	{ 795000000, 0x12, 0x0A },
+	{ 883000000, 0x11, 0x09 },
+	{ 994000000, 0x10, 0x08 },
+	{         0, 0x00, 0x00 },    /* Table End */
+};
+
+static struct SMap2 m_Cal_PLL_Map[] = {
+	{  33813000, 0xDD, 0xD0 },
+	{  36625000, 0xDC, 0xC0 },
+	{  39938000, 0xDB, 0xB0 },
+	{  43938000, 0xDA, 0xA0 },
+	{  48813000, 0xD9, 0x90 },
+	{  54938000, 0xD8, 0x80 },
+	{  62813000, 0xD3, 0x70 },
+	{  67625000, 0xCD, 0x68 },
+	{  73250000, 0xCC, 0x60 },
+	{  79875000, 0xCB, 0x58 },
+	{  87875000, 0xCA, 0x50 },
+	{  97625000, 0xC9, 0x48 },
+	{ 109875000, 0xC8, 0x40 },
+	{ 125625000, 0xC3, 0x38 },
+	{ 135250000, 0xBD, 0x34 },
+	{ 146500000, 0xBC, 0x30 },
+	{ 159750000, 0xBB, 0x2C },
+	{ 175750000, 0xBA, 0x28 },
+	{ 195250000, 0xB9, 0x24 },
+	{ 219750000, 0xB8, 0x20 },
+	{ 251250000, 0xB3, 0x1C },
+	{ 270500000, 0xAD, 0x1A },
+	{ 293000000, 0xAC, 0x18 },
+	{ 319500000, 0xAB, 0x16 },
+	{ 351500000, 0xAA, 0x14 },
+	{ 390500000, 0xA9, 0x12 },
+	{ 439500000, 0xA8, 0x10 },
+	{ 502500000, 0xA3, 0x0E },
+	{ 541000000, 0x9D, 0x0D },
+	{ 586000000, 0x9C, 0x0C },
+	{ 639000000, 0x9B, 0x0B },
+	{ 703000000, 0x9A, 0x0A },
+	{ 781000000, 0x99, 0x09 },
+	{ 879000000, 0x98, 0x08 },
+	{         0, 0x00, 0x00 },    /* Table End */
+};
+
+static struct SMap  m_GainTaper_Map[] = {
+	{  45400000, 0x1F },
+	{  45800000, 0x1E },
+	{  46200000, 0x1D },
+	{  46700000, 0x1C },
+	{  47100000, 0x1B },
+	{  47500000, 0x1A },
+	{  47900000, 0x19 },
+	{  49600000, 0x17 },
+	{  51200000, 0x16 },
+	{  52900000, 0x15 },
+	{  54500000, 0x14 },
+	{  56200000, 0x13 },
+	{  57800000, 0x12 },
+	{  59500000, 0x11 },
+	{  61100000, 0x10 },
+	{  67600000, 0x0D },
+	{  74200000, 0x0C },
+	{  80700000, 0x0B },
+	{  87200000, 0x0A },
+	{  93800000, 0x09 },
+	{ 100300000, 0x08 },
+	{ 106900000, 0x07 },
+	{ 113400000, 0x06 },
+	{ 119900000, 0x05 },
+	{ 126500000, 0x04 },
+	{ 133000000, 0x03 },
+	{ 139500000, 0x02 },
+	{ 146100000, 0x01 },
+	{ 152600000, 0x00 },
+	{ 154300000, 0x1F },
+	{ 156100000, 0x1E },
+	{ 157800000, 0x1D },
+	{ 159500000, 0x1C },
+	{ 161200000, 0x1B },
+	{ 163000000, 0x1A },
+	{ 164700000, 0x19 },
+	{ 170200000, 0x17 },
+	{ 175800000, 0x16 },
+	{ 181300000, 0x15 },
+	{ 186900000, 0x14 },
+	{ 192400000, 0x13 },
+	{ 198000000, 0x12 },
+	{ 203500000, 0x11 },
+	{ 216200000, 0x14 },
+	{ 228900000, 0x13 },
+	{ 241600000, 0x12 },
+	{ 254400000, 0x11 },
+	{ 267100000, 0x10 },
+	{ 279800000, 0x0F },
+	{ 292500000, 0x0E },
+	{ 305200000, 0x0D },
+	{ 317900000, 0x0C },
+	{ 330700000, 0x0B },
+	{ 343400000, 0x0A },
+	{ 356100000, 0x09 },
+	{ 368800000, 0x08 },
+	{ 381500000, 0x07 },
+	{ 394200000, 0x06 },
+	{ 406900000, 0x05 },
+	{ 419700000, 0x04 },
+	{ 432400000, 0x03 },
+	{ 445100000, 0x02 },
+	{ 457800000, 0x01 },
+	{ 476300000, 0x19 },
+	{ 494800000, 0x18 },
+	{ 513300000, 0x17 },
+	{ 531800000, 0x16 },
+	{ 550300000, 0x15 },
+	{ 568900000, 0x14 },
+	{ 587400000, 0x13 },
+	{ 605900000, 0x12 },
+	{ 624400000, 0x11 },
+	{ 642900000, 0x10 },
+	{ 661400000, 0x0F },
+	{ 679900000, 0x0E },
+	{ 698400000, 0x0D },
+	{ 716900000, 0x0C },
+	{ 735400000, 0x0B },
+	{ 753900000, 0x0A },
+	{ 772500000, 0x09 },
+	{ 791000000, 0x08 },
+	{ 809500000, 0x07 },
+	{ 828000000, 0x06 },
+	{ 846500000, 0x05 },
+	{ 865000000, 0x04 },
+	{         0, 0x00 },    /* Table End */
+};
+
+static struct SMap m_RF_Cal_DC_Over_DT_Map[] = {
+	{  47900000, 0x00 },
+	{  55000000, 0x00 },
+	{  61100000, 0x0A },
+	{  64000000, 0x0A },
+	{  82000000, 0x14 },
+	{  84000000, 0x19 },
+	{ 119000000, 0x1C },
+	{ 124000000, 0x20 },
+	{ 129000000, 0x2A },
+	{ 134000000, 0x32 },
+	{ 139000000, 0x39 },
+	{ 144000000, 0x3E },
+	{ 149000000, 0x3F },
+	{ 152600000, 0x40 },
+	{ 154000000, 0x40 },
+	{ 164700000, 0x41 },
+	{ 203500000, 0x32 },
+	{ 353000000, 0x19 },
+	{ 356000000, 0x1A },
+	{ 359000000, 0x1B },
+	{ 363000000, 0x1C },
+	{ 366000000, 0x1D },
+	{ 369000000, 0x1E },
+	{ 373000000, 0x1F },
+	{ 376000000, 0x20 },
+	{ 379000000, 0x21 },
+	{ 383000000, 0x22 },
+	{ 386000000, 0x23 },
+	{ 389000000, 0x24 },
+	{ 393000000, 0x25 },
+	{ 396000000, 0x26 },
+	{ 399000000, 0x27 },
+	{ 402000000, 0x28 },
+	{ 404000000, 0x29 },
+	{ 407000000, 0x2A },
+	{ 409000000, 0x2B },
+	{ 412000000, 0x2C },
+	{ 414000000, 0x2D },
+	{ 417000000, 0x2E },
+	{ 419000000, 0x2F },
+	{ 422000000, 0x30 },
+	{ 424000000, 0x31 },
+	{ 427000000, 0x32 },
+	{ 429000000, 0x33 },
+	{ 432000000, 0x34 },
+	{ 434000000, 0x35 },
+	{ 437000000, 0x36 },
+	{ 439000000, 0x37 },
+	{ 442000000, 0x38 },
+	{ 444000000, 0x39 },
+	{ 447000000, 0x3A },
+	{ 449000000, 0x3B },
+	{ 457800000, 0x3C },
+	{ 465000000, 0x0F },
+	{ 477000000, 0x12 },
+	{ 483000000, 0x14 },
+	{ 502000000, 0x19 },
+	{ 508000000, 0x1B },
+	{ 519000000, 0x1C },
+	{ 522000000, 0x1D },
+	{ 524000000, 0x1E },
+	{ 534000000, 0x1F },
+	{ 549000000, 0x20 },
+	{ 554000000, 0x22 },
+	{ 584000000, 0x24 },
+	{ 589000000, 0x26 },
+	{ 658000000, 0x27 },
+	{ 664000000, 0x2C },
+	{ 669000000, 0x2D },
+	{ 699000000, 0x2E },
+	{ 704000000, 0x30 },
+	{ 709000000, 0x31 },
+	{ 714000000, 0x32 },
+	{ 724000000, 0x33 },
+	{ 729000000, 0x36 },
+	{ 739000000, 0x38 },
+	{ 744000000, 0x39 },
+	{ 749000000, 0x3B },
+	{ 754000000, 0x3C },
+	{ 759000000, 0x3D },
+	{ 764000000, 0x3E },
+	{ 769000000, 0x3F },
+	{ 774000000, 0x40 },
+	{ 779000000, 0x41 },
+	{ 784000000, 0x43 },
+	{ 789000000, 0x46 },
+	{ 794000000, 0x48 },
+	{ 799000000, 0x4B },
+	{ 804000000, 0x4F },
+	{ 809000000, 0x54 },
+	{ 814000000, 0x59 },
+	{ 819000000, 0x5D },
+	{ 824000000, 0x61 },
+	{ 829000000, 0x68 },
+	{ 834000000, 0x6E },
+	{ 839000000, 0x75 },
+	{ 844000000, 0x7E },
+	{ 849000000, 0x82 },
+	{ 854000000, 0x84 },
+	{ 859000000, 0x8F },
+	{ 865000000, 0x9A },
+	{         0, 0x00 },    /* Table End */
+};
+
+
+static struct SMap  m_IR_Meas_Map[] = {
+	{ 200000000, 0x05 },
+	{ 400000000, 0x06 },
+	{ 865000000, 0x07 },
+	{         0, 0x00 },    /* Table End */
+};
+
+static struct SMap2 m_CID_Target_Map[] = {
+	{  46000000, 0x04, 18 },
+	{  52200000, 0x0A, 15 },
+	{  70100000, 0x01, 40 },
+	{ 136800000, 0x18, 40 },
+	{ 156700000, 0x18, 40 },
+	{ 186250000, 0x0A, 40 },
+	{ 230000000, 0x0A, 40 },
+	{ 345000000, 0x18, 40 },
+	{ 426000000, 0x0E, 40 },
+	{ 489500000, 0x1E, 40 },
+	{ 697500000, 0x32, 40 },
+	{ 842000000, 0x3A, 40 },
+	{         0, 0x00,  0 },    /* Table End */
+};
+
+static struct SRFBandMap  m_RF_Band_Map[7] = {
+	{   47900000,   46000000,           0,          0},
+	{   61100000,   52200000,           0,          0},
+	{  152600000,   70100000,   136800000,          0},
+	{  164700000,  156700000,           0,          0},
+	{  203500000,  186250000,           0,          0},
+	{  457800000,  230000000,   345000000,  426000000},
+	{  865000000,  489500000,   697500000,  842000000},
+};
+
+u8 m_Thermometer_Map_1[16] = {
+	60, 62, 66, 64,
+	74, 72, 68, 70,
+	90, 88, 84, 86,
+	76, 78, 82, 80,
+};
+
+u8 m_Thermometer_Map_2[16] = {
+	92, 94, 98, 96,
+	106, 104, 100, 102,
+	122, 120, 116, 118,
+	108, 110, 114, 112,
+};
diff --git a/drivers/media/dvb-frontends/tda665x.c b/drivers/media/dvb-frontends/tda665x.c
new file mode 100644
index 0000000..2c1c759
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda665x.c
@@ -0,0 +1,258 @@
+/*
+	TDA665x tuner driver
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "tda665x.h"
+
+struct tda665x_state {
+	struct dvb_frontend		*fe;
+	struct i2c_adapter		*i2c;
+	const struct tda665x_config	*config;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+static int tda665x_read(struct tda665x_state *state, u8 *buf)
+{
+	const struct tda665x_config *config = state->config;
+	int err = 0;
+	struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD, .buf = buf, .len = 2 };
+
+	err = i2c_transfer(state->i2c, &msg, 1);
+	if (err != 1)
+		goto exit;
+
+	return err;
+exit:
+	printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
+	return err;
+}
+
+static int tda665x_write(struct tda665x_state *state, u8 *buf, u8 length)
+{
+	const struct tda665x_config *config = state->config;
+	int err = 0;
+	struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = length };
+
+	err = i2c_transfer(state->i2c, &msg, 1);
+	if (err != 1)
+		goto exit;
+
+	return err;
+exit:
+	printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
+	return err;
+}
+
+static int tda665x_get_state(struct dvb_frontend *fe,
+			     enum tuner_param param,
+			     struct tuner_state *tstate)
+{
+	struct tda665x_state *state = fe->tuner_priv;
+	int err = 0;
+
+	switch (param) {
+	case DVBFE_TUNER_FREQUENCY:
+		tstate->frequency = state->frequency;
+		break;
+	case DVBFE_TUNER_BANDWIDTH:
+		break;
+	default:
+		printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param);
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+static int tda665x_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct tda665x_state *state = fe->tuner_priv;
+	u8 result = 0;
+	int err = 0;
+
+	*status = 0;
+
+	err = tda665x_read(state, &result);
+	if (err < 0)
+		goto exit;
+
+	if ((result >> 6) & 0x01) {
+		printk(KERN_DEBUG "%s: Tuner Phase Locked\n", __func__);
+		*status = 1;
+	}
+
+	return err;
+exit:
+	printk(KERN_ERR "%s: I/O Error\n", __func__);
+	return err;
+}
+
+static int tda665x_set_state(struct dvb_frontend *fe,
+			     enum tuner_param param,
+			     struct tuner_state *tstate)
+{
+	struct tda665x_state *state = fe->tuner_priv;
+	const struct tda665x_config *config = state->config;
+	u32 frequency, status = 0;
+	u8 buf[4];
+	int err = 0;
+
+	if (param & DVBFE_TUNER_FREQUENCY) {
+
+		frequency = tstate->frequency;
+		if ((frequency < config->frequency_max) || (frequency > config->frequency_min)) {
+			printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n", __func__, frequency);
+			return -EINVAL;
+		}
+
+		frequency += config->frequency_offst;
+		frequency *= config->ref_multiplier;
+		frequency += config->ref_divider >> 1;
+		frequency /= config->ref_divider;
+
+		buf[0] = (u8) ((frequency & 0x7f00) >> 8);
+		buf[1] = (u8) (frequency & 0x00ff) >> 0;
+		buf[2] = 0x80 | 0x40 | 0x02;
+		buf[3] = 0x00;
+
+		/* restore frequency */
+		frequency = tstate->frequency;
+
+		if (frequency < 153000000) {
+			/* VHF-L */
+			buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */
+			if (frequency < 68000000)
+				buf[3] |= 0x40; /* 83uA */
+			if (frequency < 1040000000)
+				buf[3] |= 0x60; /* 122uA */
+			if (frequency < 1250000000)
+				buf[3] |= 0x80; /* 163uA */
+			else
+				buf[3] |= 0xa0; /* 254uA */
+		} else if (frequency < 438000000) {
+			/* VHF-H */
+			buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */
+			if (frequency < 230000000)
+				buf[3] |= 0x40;
+			if (frequency < 300000000)
+				buf[3] |= 0x60;
+			else
+				buf[3] |= 0x80;
+		} else {
+			/* UHF */
+			buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */
+			if (frequency < 470000000)
+				buf[3] |= 0x60;
+			if (frequency < 526000000)
+				buf[3] |= 0x80;
+			else
+				buf[3] |= 0xa0;
+		}
+
+		/* Set params */
+		err = tda665x_write(state, buf, 5);
+		if (err < 0)
+			goto exit;
+
+		/* sleep for some time */
+		printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__);
+		msleep(20);
+		/* check status */
+		err = tda665x_get_status(fe, &status);
+		if (err < 0)
+			goto exit;
+
+		if (status == 1) {
+			printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n", __func__, status);
+			state->frequency = frequency; /* cache successful state */
+		} else {
+			printk(KERN_ERR "%s: No Phase lock: status=%d\n", __func__, status);
+		}
+	} else {
+		printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param);
+		return -EINVAL;
+	}
+
+	return 0;
+exit:
+	printk(KERN_ERR "%s: I/O Error\n", __func__);
+	return err;
+}
+
+static int tda665x_release(struct dvb_frontend *fe)
+{
+	struct tda665x_state *state = fe->tuner_priv;
+
+	fe->tuner_priv = NULL;
+	kfree(state);
+	return 0;
+}
+
+static struct dvb_tuner_ops tda665x_ops = {
+
+	.set_state	= tda665x_set_state,
+	.get_state	= tda665x_get_state,
+	.get_status	= tda665x_get_status,
+	.release	= tda665x_release
+};
+
+struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
+				    const struct tda665x_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct tda665x_state *state = NULL;
+	struct dvb_tuner_info *info;
+
+	state = kzalloc(sizeof(struct tda665x_state), GFP_KERNEL);
+	if (state == NULL)
+		goto exit;
+
+	state->config		= config;
+	state->i2c		= i2c;
+	state->fe		= fe;
+	fe->tuner_priv		= state;
+	fe->ops.tuner_ops	= tda665x_ops;
+	info			 = &fe->ops.tuner_ops.info;
+
+	memcpy(info->name, config->name, sizeof(config->name));
+	info->frequency_min	= config->frequency_min;
+	info->frequency_max	= config->frequency_max;
+	info->frequency_step	= config->frequency_offst;
+
+	printk(KERN_DEBUG "%s: Attaching TDA665x (%s) tuner\n", __func__, info->name);
+
+	return fe;
+
+exit:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(tda665x_attach);
+
+MODULE_DESCRIPTION("TDA665x driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/tda665x.h b/drivers/media/dvb-frontends/tda665x.h
new file mode 100644
index 0000000..ec7927a
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda665x.h
@@ -0,0 +1,52 @@
+/*
+	TDA665x tuner driver
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TDA665x_H
+#define __TDA665x_H
+
+struct tda665x_config {
+	char name[128];
+
+	u8	addr;
+	u32	frequency_min;
+	u32	frequency_max;
+	u32	frequency_offst;
+	u32	ref_multiplier;
+	u32	ref_divider;
+};
+
+#if defined(CONFIG_DVB_TDA665x) || (defined(CONFIG_DVB_TDA665x_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
+					   const struct tda665x_config *config,
+					   struct i2c_adapter *i2c);
+
+#else
+
+static inline struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
+						  const struct tda665x_config *config,
+						  struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+#endif /* CONFIG_DVB_TDA665x */
+
+#endif /* __TDA665x_H */
diff --git a/drivers/media/dvb-frontends/tda8083.c b/drivers/media/dvb-frontends/tda8083.c
new file mode 100644
index 0000000..15912c9
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda8083.c
@@ -0,0 +1,487 @@
+/*
+    Driver for Philips TDA8083 based QPSK Demodulator
+
+    Copyright (C) 2001 Convergence Integrated Media GmbH
+
+    written by Ralph Metzler <ralph@convergence.de>
+
+    adoption to the new DVB frontend API and diagnostic ioctl's
+    by Holger Waechtler <holger@convergence.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include "dvb_frontend.h"
+#include "tda8083.h"
+
+
+struct tda8083_state {
+	struct i2c_adapter* i2c;
+	/* configuration settings */
+	const struct tda8083_config* config;
+	struct dvb_frontend frontend;
+};
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "tda8083: " args); \
+	} while (0)
+
+
+static u8 tda8083_init_tab [] = {
+	0x04, 0x00, 0x4a, 0x79, 0x04, 0x00, 0xff, 0xea,
+	0x48, 0x42, 0x79, 0x60, 0x70, 0x52, 0x9a, 0x10,
+	0x0e, 0x10, 0xf2, 0xa7, 0x93, 0x0b, 0x05, 0xc8,
+	0x9d, 0x00, 0x42, 0x80, 0x00, 0x60, 0x40, 0x00,
+	0x00, 0x75, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00
+};
+
+
+static int tda8083_writereg (struct tda8083_state* state, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf [] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		dprintk ("%s: writereg error (reg %02x, ret == %i)\n",
+			__func__, reg, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+
+static int tda8083_readregs (struct tda8083_state* state, u8 reg1, u8 *b, u8 len)
+{
+	int ret;
+	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = &reg1, .len = 1 },
+			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } };
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		dprintk ("%s: readreg error (reg %02x, ret == %i)\n",
+			__func__, reg1, ret);
+
+	return ret == 2 ? 0 : -1;
+}
+
+static inline u8 tda8083_readreg (struct tda8083_state* state, u8 reg)
+{
+	u8 val;
+
+	tda8083_readregs (state, reg, &val, 1);
+
+	return val;
+}
+
+static int tda8083_set_inversion (struct tda8083_state* state, fe_spectral_inversion_t inversion)
+{
+	/*  XXX FIXME: implement other modes than FEC_AUTO */
+	if (inversion == INVERSION_AUTO)
+		return 0;
+
+	return -EINVAL;
+}
+
+static int tda8083_set_fec (struct tda8083_state* state, fe_code_rate_t fec)
+{
+	if (fec == FEC_AUTO)
+		return tda8083_writereg (state, 0x07, 0xff);
+
+	if (fec >= FEC_1_2 && fec <= FEC_8_9)
+		return tda8083_writereg (state, 0x07, 1 << (FEC_8_9 - fec));
+
+	return -EINVAL;
+}
+
+static fe_code_rate_t tda8083_get_fec (struct tda8083_state* state)
+{
+	u8 index;
+	static fe_code_rate_t fec_tab [] = { FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4,
+				       FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8 };
+
+	index = tda8083_readreg(state, 0x0e) & 0x07;
+
+	return fec_tab [index];
+}
+
+static int tda8083_set_symbolrate (struct tda8083_state* state, u32 srate)
+{
+	u32 ratio;
+	u32 tmp;
+	u8 filter;
+
+	if (srate > 32000000)
+		srate = 32000000;
+	if (srate < 500000)
+		srate = 500000;
+
+	filter = 0;
+	if (srate < 24000000)
+		filter = 2;
+	if (srate < 16000000)
+		filter = 3;
+
+	tmp = 31250 << 16;
+	ratio = tmp / srate;
+
+	tmp = (tmp % srate) << 8;
+	ratio = (ratio << 8) + tmp / srate;
+
+	tmp = (tmp % srate) << 8;
+	ratio = (ratio << 8) + tmp / srate;
+
+	dprintk("tda8083: ratio == %08x\n", (unsigned int) ratio);
+
+	tda8083_writereg (state, 0x05, filter);
+	tda8083_writereg (state, 0x02, (ratio >> 16) & 0xff);
+	tda8083_writereg (state, 0x03, (ratio >>  8) & 0xff);
+	tda8083_writereg (state, 0x04, (ratio      ) & 0xff);
+
+	tda8083_writereg (state, 0x00, 0x3c);
+	tda8083_writereg (state, 0x00, 0x04);
+
+	return 1;
+}
+
+static void tda8083_wait_diseqc_fifo (struct tda8083_state* state, int timeout)
+{
+	unsigned long start = jiffies;
+
+	while (jiffies - start < timeout &&
+	       !(tda8083_readreg(state, 0x02) & 0x80))
+	{
+		msleep(50);
+	};
+}
+
+static int tda8083_set_tone (struct tda8083_state* state, fe_sec_tone_mode_t tone)
+{
+	tda8083_writereg (state, 0x26, 0xf1);
+
+	switch (tone) {
+	case SEC_TONE_OFF:
+		return tda8083_writereg (state, 0x29, 0x00);
+	case SEC_TONE_ON:
+		return tda8083_writereg (state, 0x29, 0x80);
+	default:
+		return -EINVAL;
+	};
+}
+
+static int tda8083_set_voltage (struct tda8083_state* state, fe_sec_voltage_t voltage)
+{
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		return tda8083_writereg (state, 0x20, 0x00);
+	case SEC_VOLTAGE_18:
+		return tda8083_writereg (state, 0x20, 0x11);
+	default:
+		return -EINVAL;
+	};
+}
+
+static int tda8083_send_diseqc_burst (struct tda8083_state* state, fe_sec_mini_cmd_t burst)
+{
+	switch (burst) {
+	case SEC_MINI_A:
+		tda8083_writereg (state, 0x29, (5 << 2));  /* send burst A */
+		break;
+	case SEC_MINI_B:
+		tda8083_writereg (state, 0x29, (7 << 2));  /* send B */
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	tda8083_wait_diseqc_fifo (state, 100);
+
+	return 0;
+}
+
+static int tda8083_send_diseqc_msg (struct dvb_frontend* fe,
+				    struct dvb_diseqc_master_cmd *m)
+{
+	struct tda8083_state* state = fe->demodulator_priv;
+	int i;
+
+	tda8083_writereg (state, 0x29, (m->msg_len - 3) | (1 << 2)); /* enable */
+
+	for (i=0; i<m->msg_len; i++)
+		tda8083_writereg (state, 0x23 + i, m->msg[i]);
+
+	tda8083_writereg (state, 0x29, (m->msg_len - 3) | (3 << 2)); /* send!! */
+
+	tda8083_wait_diseqc_fifo (state, 100);
+
+	return 0;
+}
+
+static int tda8083_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct tda8083_state* state = fe->demodulator_priv;
+
+	u8 signal = ~tda8083_readreg (state, 0x01);
+	u8 sync = tda8083_readreg (state, 0x02);
+
+	*status = 0;
+
+	if (signal > 10)
+		*status |= FE_HAS_SIGNAL;
+
+	if (sync & 0x01)
+		*status |= FE_HAS_CARRIER;
+
+	if (sync & 0x02)
+		*status |= FE_HAS_VITERBI;
+
+	if (sync & 0x10)
+		*status |= FE_HAS_SYNC;
+
+	if (sync & 0x20) /* frontend can not lock */
+		*status |= FE_TIMEDOUT;
+
+	if ((sync & 0x1f) == 0x1f)
+		*status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int tda8083_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct tda8083_state* state = fe->demodulator_priv;
+	int ret;
+	u8 buf[3];
+
+	if ((ret = tda8083_readregs(state, 0x0b, buf, sizeof(buf))))
+		return ret;
+
+	*ber = ((buf[0] & 0x1f) << 16) | (buf[1] << 8) | buf[2];
+
+	return 0;
+}
+
+static int tda8083_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct tda8083_state* state = fe->demodulator_priv;
+
+	u8 signal = ~tda8083_readreg (state, 0x01);
+	*strength = (signal << 8) | signal;
+
+	return 0;
+}
+
+static int tda8083_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct tda8083_state* state = fe->demodulator_priv;
+
+	u8 _snr = tda8083_readreg (state, 0x08);
+	*snr = (_snr << 8) | _snr;
+
+	return 0;
+}
+
+static int tda8083_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct tda8083_state* state = fe->demodulator_priv;
+
+	*ucblocks = tda8083_readreg(state, 0x0f);
+	if (*ucblocks == 0xff)
+		*ucblocks = 0xffffffff;
+
+	return 0;
+}
+
+static int tda8083_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct tda8083_state* state = fe->demodulator_priv;
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	tda8083_set_inversion (state, p->inversion);
+	tda8083_set_fec(state, p->fec_inner);
+	tda8083_set_symbolrate(state, p->symbol_rate);
+
+	tda8083_writereg (state, 0x00, 0x3c);
+	tda8083_writereg (state, 0x00, 0x04);
+
+	return 0;
+}
+
+static int tda8083_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct tda8083_state* state = fe->demodulator_priv;
+
+	/*  FIXME: get symbolrate & frequency offset...*/
+	/*p->frequency = ???;*/
+	p->inversion = (tda8083_readreg (state, 0x0e) & 0x80) ?
+			INVERSION_ON : INVERSION_OFF;
+	p->fec_inner = tda8083_get_fec(state);
+	/*p->symbol_rate = tda8083_get_symbolrate (state);*/
+
+	return 0;
+}
+
+static int tda8083_sleep(struct dvb_frontend* fe)
+{
+	struct tda8083_state* state = fe->demodulator_priv;
+
+	tda8083_writereg (state, 0x00, 0x02);
+	return 0;
+}
+
+static int tda8083_init(struct dvb_frontend* fe)
+{
+	struct tda8083_state* state = fe->demodulator_priv;
+	int i;
+
+	for (i=0; i<44; i++)
+		tda8083_writereg (state, i, tda8083_init_tab[i]);
+
+	tda8083_writereg (state, 0x00, 0x3c);
+	tda8083_writereg (state, 0x00, 0x04);
+
+	return 0;
+}
+
+static int tda8083_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
+{
+	struct tda8083_state* state = fe->demodulator_priv;
+
+	tda8083_send_diseqc_burst (state, burst);
+	tda8083_writereg (state, 0x00, 0x3c);
+	tda8083_writereg (state, 0x00, 0x04);
+
+	return 0;
+}
+
+static int tda8083_diseqc_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct tda8083_state* state = fe->demodulator_priv;
+
+	tda8083_set_tone (state, tone);
+	tda8083_writereg (state, 0x00, 0x3c);
+	tda8083_writereg (state, 0x00, 0x04);
+
+	return 0;
+}
+
+static int tda8083_diseqc_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	struct tda8083_state* state = fe->demodulator_priv;
+
+	tda8083_set_voltage (state, voltage);
+	tda8083_writereg (state, 0x00, 0x3c);
+	tda8083_writereg (state, 0x00, 0x04);
+
+	return 0;
+}
+
+static void tda8083_release(struct dvb_frontend* fe)
+{
+	struct tda8083_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops tda8083_ops;
+
+struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
+				    struct i2c_adapter* i2c)
+{
+	struct tda8083_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct tda8083_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+
+	/* check if the demod is there */
+	if ((tda8083_readreg(state, 0x00)) != 0x05) goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &tda8083_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops tda8083_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name			= "Philips TDA8083 DVB-S",
+		.frequency_min		= 920000,     /* TDA8060 */
+		.frequency_max		= 2200000,    /* TDA8060 */
+		.frequency_stepsize	= 125,   /* kHz for QPSK frontends */
+	/*      .frequency_tolerance	= ???,*/
+		.symbol_rate_min	= 12000000,
+		.symbol_rate_max	= 30000000,
+	/*      .symbol_rate_tolerance	= ???,*/
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+			FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_MUTE_TS
+	},
+
+	.release = tda8083_release,
+
+	.init = tda8083_init,
+	.sleep = tda8083_sleep,
+
+	.set_frontend = tda8083_set_frontend,
+	.get_frontend = tda8083_get_frontend,
+
+	.read_status = tda8083_read_status,
+	.read_signal_strength = tda8083_read_signal_strength,
+	.read_snr = tda8083_read_snr,
+	.read_ber = tda8083_read_ber,
+	.read_ucblocks = tda8083_read_ucblocks,
+
+	.diseqc_send_master_cmd = tda8083_send_diseqc_msg,
+	.diseqc_send_burst = tda8083_diseqc_send_burst,
+	.set_tone = tda8083_diseqc_set_tone,
+	.set_voltage = tda8083_diseqc_set_voltage,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Philips TDA8083 DVB-S Demodulator");
+MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(tda8083_attach);
diff --git a/drivers/media/dvb-frontends/tda8083.h b/drivers/media/dvb-frontends/tda8083.h
new file mode 100644
index 0000000..5a03c14
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda8083.h
@@ -0,0 +1,50 @@
+/*
+    Driver for Grundig 29504-491, a Philips TDA8083 based QPSK Frontend
+
+    Copyright (C) 2001 Convergence Integrated Media GmbH
+
+    written by Ralph Metzler <ralph@convergence.de>
+
+    adoption to the new DVB frontend API and diagnostic ioctl's
+    by Holger Waechtler <holger@convergence.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef TDA8083_H
+#define TDA8083_H
+
+#include <linux/dvb/frontend.h>
+
+struct tda8083_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+};
+
+#if defined(CONFIG_DVB_TDA8083) || (defined(CONFIG_DVB_TDA8083_MODULE) && defined(MODULE))
+extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
+					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TDA8083
+
+#endif // TDA8083_H
diff --git a/drivers/media/dvb-frontends/tda8261.c b/drivers/media/dvb-frontends/tda8261.c
new file mode 100644
index 0000000..53c7d8f
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda8261.c
@@ -0,0 +1,230 @@
+/*
+	TDA8261 8PSK/QPSK tuner driver
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "tda8261.h"
+
+struct tda8261_state {
+	struct dvb_frontend		*fe;
+	struct i2c_adapter		*i2c;
+	const struct tda8261_config	*config;
+
+	/* state cache */
+	u32 frequency;
+	u32 bandwidth;
+};
+
+static int tda8261_read(struct tda8261_state *state, u8 *buf)
+{
+	const struct tda8261_config *config = state->config;
+	int err = 0;
+	struct i2c_msg msg = { .addr	= config->addr, .flags = I2C_M_RD,.buf = buf,  .len = 1 };
+
+	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1)
+		printk("%s: read error, err=%d\n", __func__, err);
+
+	return err;
+}
+
+static int tda8261_write(struct tda8261_state *state, u8 *buf)
+{
+	const struct tda8261_config *config = state->config;
+	int err = 0;
+	struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = 4 };
+
+	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1)
+		printk("%s: write error, err=%d\n", __func__, err);
+
+	return err;
+}
+
+static int tda8261_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct tda8261_state *state = fe->tuner_priv;
+	u8 result = 0;
+	int err = 0;
+
+	*status = 0;
+
+	if ((err = tda8261_read(state, &result)) < 0) {
+		printk("%s: I/O Error\n", __func__);
+		return err;
+	}
+	if ((result >> 6) & 0x01) {
+		printk("%s: Tuner Phase Locked\n", __func__);
+		*status = 1;
+	}
+
+	return err;
+}
+
+static const u32 div_tab[] = { 2000, 1000,  500,  250,  125 }; /* kHz */
+static const u8  ref_div[] = { 0x00, 0x01, 0x02, 0x05, 0x07 };
+
+static int tda8261_get_state(struct dvb_frontend *fe,
+			     enum tuner_param param,
+			     struct tuner_state *tstate)
+{
+	struct tda8261_state *state = fe->tuner_priv;
+	int err = 0;
+
+	switch (param) {
+	case DVBFE_TUNER_FREQUENCY:
+		tstate->frequency = state->frequency;
+		break;
+	case DVBFE_TUNER_BANDWIDTH:
+		tstate->bandwidth = 40000000; /* FIXME! need to calculate Bandwidth */
+		break;
+	default:
+		printk("%s: Unknown parameter (param=%d)\n", __func__, param);
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+static int tda8261_set_state(struct dvb_frontend *fe,
+			     enum tuner_param param,
+			     struct tuner_state *tstate)
+{
+	struct tda8261_state *state = fe->tuner_priv;
+	const struct tda8261_config *config = state->config;
+	u32 frequency, N, status = 0;
+	u8 buf[4];
+	int err = 0;
+
+	if (param & DVBFE_TUNER_FREQUENCY) {
+		/**
+		 * N = Max VCO Frequency / Channel Spacing
+		 * Max VCO Frequency = VCO frequency + (channel spacing - 1)
+		 * (to account for half channel spacing on either side)
+		 */
+		frequency = tstate->frequency;
+		if ((frequency < 950000) || (frequency > 2150000)) {
+			printk("%s: Frequency beyond limits, frequency=%d\n", __func__, frequency);
+			return -EINVAL;
+		}
+		N = (frequency + (div_tab[config->step_size] - 1)) / div_tab[config->step_size];
+		printk("%s: Step size=%d, Divider=%d, PG=0x%02x (%d)\n",
+			__func__, config->step_size, div_tab[config->step_size], N, N);
+
+		buf[0] = (N >> 8) & 0xff;
+		buf[1] = N & 0xff;
+		buf[2] = (0x01 << 7) | ((ref_div[config->step_size] & 0x07) << 1);
+
+		if (frequency < 1450000)
+			buf[3] = 0x00;
+		else if (frequency < 2000000)
+			buf[3] = 0x40;
+		else if (frequency < 2150000)
+			buf[3] = 0x80;
+
+		/* Set params */
+		if ((err = tda8261_write(state, buf)) < 0) {
+			printk("%s: I/O Error\n", __func__);
+			return err;
+		}
+		/* sleep for some time */
+		printk("%s: Waiting to Phase LOCK\n", __func__);
+		msleep(20);
+		/* check status */
+		if ((err = tda8261_get_status(fe, &status)) < 0) {
+			printk("%s: I/O Error\n", __func__);
+			return err;
+		}
+		if (status == 1) {
+			printk("%s: Tuner Phase locked: status=%d\n", __func__, status);
+			state->frequency = frequency; /* cache successful state */
+		} else {
+			printk("%s: No Phase lock: status=%d\n", __func__, status);
+		}
+	} else {
+		printk("%s: Unknown parameter (param=%d)\n", __func__, param);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tda8261_release(struct dvb_frontend *fe)
+{
+	struct tda8261_state *state = fe->tuner_priv;
+
+	fe->tuner_priv = NULL;
+	kfree(state);
+	return 0;
+}
+
+static struct dvb_tuner_ops tda8261_ops = {
+
+	.info = {
+		.name		= "TDA8261",
+//		.tuner_name	= NULL,
+		.frequency_min	=  950000,
+		.frequency_max	= 2150000,
+		.frequency_step = 0
+	},
+
+	.set_state	= tda8261_set_state,
+	.get_state	= tda8261_get_state,
+	.get_status	= tda8261_get_status,
+	.release	= tda8261_release
+};
+
+struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
+				    const struct tda8261_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct tda8261_state *state = NULL;
+
+	if ((state = kzalloc(sizeof (struct tda8261_state), GFP_KERNEL)) == NULL)
+		goto exit;
+
+	state->config		= config;
+	state->i2c		= i2c;
+	state->fe		= fe;
+	fe->tuner_priv		= state;
+	fe->ops.tuner_ops	= tda8261_ops;
+
+	fe->ops.tuner_ops.info.frequency_step = div_tab[config->step_size];
+//	fe->ops.tuner_ops.tuner_name	 = &config->buf;
+
+//	printk("%s: Attaching %s TDA8261 8PSK/QPSK tuner\n",
+//		__func__, fe->ops.tuner_ops.tuner_name);
+	printk("%s: Attaching TDA8261 8PSK/QPSK tuner\n", __func__);
+
+	return fe;
+
+exit:
+	kfree(state);
+	return NULL;
+}
+
+EXPORT_SYMBOL(tda8261_attach);
+
+MODULE_AUTHOR("Manu Abraham");
+MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/tda8261.h b/drivers/media/dvb-frontends/tda8261.h
new file mode 100644
index 0000000..006e453
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda8261.h
@@ -0,0 +1,55 @@
+/*
+	TDA8261 8PSK/QPSK tuner driver
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TDA8261_H
+#define __TDA8261_H
+
+enum tda8261_step {
+	TDA8261_STEP_2000 = 0,	/* 2000 kHz */
+	TDA8261_STEP_1000,	/* 1000 kHz */
+	TDA8261_STEP_500,	/*  500 kHz */
+	TDA8261_STEP_250,	/*  250 kHz */
+	TDA8261_STEP_125	/*  125 kHz */
+};
+
+struct tda8261_config {
+//	u8			buf[16];
+	u8			addr;
+	enum tda8261_step	step_size;
+};
+
+#if defined(CONFIG_DVB_TDA8261) || (defined(CONFIG_DVB_TDA8261_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
+					   const struct tda8261_config *config,
+					   struct i2c_adapter *i2c);
+
+#else
+
+static inline struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
+						  const struct tda8261_config *config,
+						  struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+#endif //CONFIG_DVB_TDA8261
+
+#endif// __TDA8261_H
diff --git a/drivers/media/dvb-frontends/tda8261_cfg.h b/drivers/media/dvb-frontends/tda8261_cfg.h
new file mode 100644
index 0000000..1af1ee4
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda8261_cfg.h
@@ -0,0 +1,84 @@
+/*
+	TDA8261 8PSK/QPSK tuner driver
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct dvb_frontend_ops	*frontend_ops = NULL;
+	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct tuner_state	t_state;
+	int err = 0;
+
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+	if (tuner_ops->get_state) {
+		if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
+			printk("%s: Invalid parameter\n", __func__);
+			return err;
+		}
+		*frequency = t_state.frequency;
+		printk("%s: Frequency=%d\n", __func__, t_state.frequency);
+	}
+	return 0;
+}
+
+static int tda8261_set_frequency(struct dvb_frontend *fe, u32 frequency)
+{
+	struct dvb_frontend_ops	*frontend_ops = NULL;
+	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct tuner_state	t_state;
+	int err = 0;
+
+	t_state.frequency = frequency;
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+	if (tuner_ops->set_state) {
+		if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
+			printk("%s: Invalid parameter\n", __func__);
+			return err;
+		}
+	}
+	printk("%s: Frequency=%d\n", __func__, t_state.frequency);
+	return 0;
+}
+
+static int tda8261_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct dvb_frontend_ops	*frontend_ops = &fe->ops;
+	struct dvb_tuner_ops	*tuner_ops = &frontend_ops->tuner_ops;
+	struct tuner_state	t_state;
+	int err = 0;
+
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+	if (tuner_ops->get_state) {
+		if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
+			printk("%s: Invalid parameter\n", __func__);
+			return err;
+		}
+		*bandwidth = t_state.bandwidth;
+	}
+	printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
+	return 0;
+}
diff --git a/drivers/media/dvb-frontends/tda826x.c b/drivers/media/dvb-frontends/tda826x.c
new file mode 100644
index 0000000..04bbcc2
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda826x.c
@@ -0,0 +1,188 @@
+  /*
+     Driver for Philips tda8262/tda8263 DVBS Silicon tuners
+
+     (c) 2006 Andrew de Quincey
+
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+     the Free Software Foundation; either version 2 of the License, or
+     (at your option) any later version.
+
+     This program is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+     GNU General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, write to the Free Software
+     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+  */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <asm/types.h>
+
+#include "tda826x.h"
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "tda826x: " args); \
+	} while (0)
+
+struct tda826x_priv {
+	/* i2c details */
+	int i2c_address;
+	struct i2c_adapter *i2c;
+	u8 has_loopthrough:1;
+	u32 frequency;
+};
+
+static int tda826x_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int tda826x_sleep(struct dvb_frontend *fe)
+{
+	struct tda826x_priv *priv = fe->tuner_priv;
+	int ret;
+	u8 buf [] = { 0x00, 0x8d };
+	struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = buf, .len = 2 };
+
+	dprintk("%s:\n", __func__);
+
+	if (!priv->has_loopthrough)
+		buf[1] = 0xad;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
+		dprintk("%s: i2c error\n", __func__);
+	}
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return (ret == 1) ? 0 : ret;
+}
+
+static int tda826x_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct tda826x_priv *priv = fe->tuner_priv;
+	int ret;
+	u32 div;
+	u32 ksyms;
+	u32 bandwidth;
+	u8 buf [11];
+	struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = buf, .len = 11 };
+
+	dprintk("%s:\n", __func__);
+
+	div = (p->frequency + (1000-1)) / 1000;
+
+	/* BW = ((1 + RO) * SR/2 + 5) * 1.3      [SR in MSPS, BW in MHz] */
+	/* with R0 = 0.35 and some transformations: */
+	ksyms = p->symbol_rate / 1000;
+	bandwidth = (878 * ksyms + 6500000) / 1000000 + 1;
+	if (bandwidth < 5)
+		bandwidth = 5;
+	else if (bandwidth > 36)
+		bandwidth = 36;
+
+	buf[0] = 0x00; // subaddress
+	buf[1] = 0x09; // powerdown RSSI + the magic value 1
+	if (!priv->has_loopthrough)
+		buf[1] |= 0x20; // power down loopthrough if not needed
+	buf[2] = (1<<5) | 0x0b; // 1Mhz + 0.45 VCO
+	buf[3] = div >> 7;
+	buf[4] = div << 1;
+	buf[5] = ((bandwidth - 5) << 3) | 7; /* baseband cut-off */
+	buf[6] = 0xfe; // baseband gain 9 db + no RF attenuation
+	buf[7] = 0x83; // charge pumps at high, tests off
+	buf[8] = 0x80; // recommended value 4 for AMPVCO + disable ports.
+	buf[9] = 0x1a; // normal caltime + recommended values for SELTH + SELVTL
+	buf[10] = 0xd4; // recommended value 13 for BBIAS + unknown bit set on
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
+		dprintk("%s: i2c error\n", __func__);
+	}
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	priv->frequency = div * 1000;
+
+	return (ret == 1) ? 0 : ret;
+}
+
+static int tda826x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tda826x_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static struct dvb_tuner_ops tda826x_tuner_ops = {
+	.info = {
+		.name = "Philips TDA826X",
+		.frequency_min = 950000,
+		.frequency_max = 2175000
+	},
+	.release = tda826x_release,
+	.sleep = tda826x_sleep,
+	.set_params = tda826x_set_params,
+	.get_frequency = tda826x_get_frequency,
+};
+
+struct dvb_frontend *tda826x_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c, int has_loopthrough)
+{
+	struct tda826x_priv *priv = NULL;
+	u8 b1 [] = { 0, 0 };
+	struct i2c_msg msg[2] = {
+		{ .addr = addr, .flags = 0,        .buf = NULL, .len = 0 },
+		{ .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 }
+	};
+	int ret;
+
+	dprintk("%s:\n", __func__);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	ret = i2c_transfer (i2c, msg, 2);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	if (ret != 2)
+		return NULL;
+	if (!(b1[1] & 0x80))
+		return NULL;
+
+	priv = kzalloc(sizeof(struct tda826x_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->i2c_address = addr;
+	priv->i2c = i2c;
+	priv->has_loopthrough = has_loopthrough;
+
+	memcpy(&fe->ops.tuner_ops, &tda826x_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+
+	return fe;
+}
+EXPORT_SYMBOL(tda826x_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("DVB TDA826x driver");
+MODULE_AUTHOR("Andrew de Quincey");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/tda826x.h b/drivers/media/dvb-frontends/tda826x.h
new file mode 100644
index 0000000..89e9792
--- /dev/null
+++ b/drivers/media/dvb-frontends/tda826x.h
@@ -0,0 +1,53 @@
+  /*
+     Driver for Philips tda8262/tda8263 DVBS Silicon tuners
+
+     (c) 2006 Andrew de Quincey
+
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+     the Free Software Foundation; either version 2 of the License, or
+     (at your option) any later version.
+
+     This program is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+     GNU General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, write to the Free Software
+     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+  */
+
+#ifndef __DVB_TDA826X_H__
+#define __DVB_TDA826X_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/**
+ * Attach a tda826x tuner to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param addr i2c address of the tuner.
+ * @param i2c i2c adapter to use.
+ * @param has_loopthrough Set to 1 if the card has a loopthrough RF connector.
+ * @return FE pointer on success, NULL on failure.
+ */
+#if defined(CONFIG_DVB_TDA826X) || (defined(CONFIG_DVB_TDA826X_MODULE) && defined(MODULE))
+extern struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe, int addr,
+					   struct i2c_adapter *i2c,
+					   int has_loopthrough);
+#else
+static inline struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe,
+						  int addr,
+						  struct i2c_adapter *i2c,
+						  int has_loopthrough)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TDA826X
+
+#endif // __DVB_TDA826X_H__
diff --git a/drivers/media/dvb-frontends/tdhd1.h b/drivers/media/dvb-frontends/tdhd1.h
new file mode 100644
index 0000000..1775098
--- /dev/null
+++ b/drivers/media/dvb-frontends/tdhd1.h
@@ -0,0 +1,74 @@
+/*
+ * tdhd1.h - ALPS TDHD1-204A tuner support
+ *
+ * Copyright (C) 2008 Oliver Endriss <o.endriss@gmx.de>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * The project's page is at http://www.linuxtv.org
+ */
+
+#ifndef TDHD1_H
+#define TDHD1_H
+
+#include "tda1004x.h"
+
+static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name);
+
+static struct tda1004x_config alps_tdhd1_204a_config = {
+	.demod_address = 0x8,
+	.invert = 1,
+	.invert_oclk = 0,
+	.xtal_freq = TDA10046_XTAL_4M,
+	.agc_config = TDA10046_AGC_DEFAULT,
+	.if_freq = TDA10046_FREQ_3617,
+	.request_firmware = alps_tdhd1_204_request_firmware
+};
+
+static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct i2c_adapter *i2c = fe->tuner_priv;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+	u32 div;
+
+	div = (p->frequency + 36166666) / 166666;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x85;
+
+	if (p->frequency >= 174000000 && p->frequency <= 230000000)
+		data[3] = 0x02;
+	else if (p->frequency >= 470000000 && p->frequency <= 823000000)
+		data[3] = 0x0C;
+	else if (p->frequency > 823000000 && p->frequency <= 862000000)
+		data[3] = 0x8C;
+	else
+		return -EINVAL;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(i2c, &msg, 1) != 1)
+		return -EIO;
+
+	return 0;
+}
+
+#endif /* TDHD1_H */
diff --git a/drivers/media/dvb-frontends/tua6100.c b/drivers/media/dvb-frontends/tua6100.c
new file mode 100644
index 0000000..029384d
--- /dev/null
+++ b/drivers/media/dvb-frontends/tua6100.c
@@ -0,0 +1,206 @@
+/**
+ * Driver for Infineon tua6100 pll.
+ *
+ * (c) 2006 Andrew de Quincey
+ *
+ * Based on code found in budget-av.c, which has the following:
+ * Compiled from various sources by Michael Hunold <michael@mihu.de>
+ *
+ * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> &
+ *                               Andrew de Quincey <adq_dvb@lidskialf.net>
+ *
+ * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
+ *
+ * Copyright (C) 1999-2002 Ralph  Metzler
+ *                       & Marcus Metzler for convergence integrated media GmbH
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <asm/types.h>
+
+#include "tua6100.h"
+
+struct tua6100_priv {
+	/* i2c details */
+	int i2c_address;
+	struct i2c_adapter *i2c;
+	u32 frequency;
+};
+
+static int tua6100_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int tua6100_sleep(struct dvb_frontend *fe)
+{
+	struct tua6100_priv *priv = fe->tuner_priv;
+	int ret;
+	u8 reg0[] = { 0x00, 0x00 };
+	struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 };
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
+		printk("%s: i2c error\n", __func__);
+	}
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return (ret == 1) ? 0 : ret;
+}
+
+static int tua6100_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct tua6100_priv *priv = fe->tuner_priv;
+	u32 div;
+	u32 prediv;
+	u8 reg0[] = { 0x00, 0x00 };
+	u8 reg1[] = { 0x01, 0x00, 0x00, 0x00 };
+	u8 reg2[] = { 0x02, 0x00, 0x00 };
+	struct i2c_msg msg0 = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 };
+	struct i2c_msg msg1 = { .addr = priv->i2c_address, .flags = 0, .buf = reg1, .len = 4 };
+	struct i2c_msg msg2 = { .addr = priv->i2c_address, .flags = 0, .buf = reg2, .len = 3 };
+
+#define _R 4
+#define _P 32
+#define _ri 4000000
+
+	// setup register 0
+	if (c->frequency < 2000000)
+		reg0[1] = 0x03;
+	else
+		reg0[1] = 0x07;
+
+	// setup register 1
+	if (c->frequency < 1630000)
+		reg1[1] = 0x2c;
+	else
+		reg1[1] = 0x0c;
+
+	if (_P == 64)
+		reg1[1] |= 0x40;
+	if (c->frequency >= 1525000)
+		reg1[1] |= 0x80;
+
+	// register 2
+	reg2[1] = (_R >> 8) & 0x03;
+	reg2[2] = _R;
+	if (c->frequency < 1455000)
+		reg2[1] |= 0x1c;
+	else if (c->frequency < 1630000)
+		reg2[1] |= 0x0c;
+	else
+		reg2[1] |= 0x1c;
+
+	/*
+	 * The N divisor ratio (note: c->frequency is in kHz, but we
+	 * need it in Hz)
+	 */
+	prediv = (c->frequency * _R) / (_ri / 1000);
+	div = prediv / _P;
+	reg1[1] |= (div >> 9) & 0x03;
+	reg1[2] = div >> 1;
+	reg1[3] = (div << 7);
+	priv->frequency = ((div * _P) * (_ri / 1000)) / _R;
+
+	// Finally, calculate and store the value for A
+	reg1[3] |= (prediv - (div*_P)) & 0x7f;
+
+#undef _R
+#undef _P
+#undef _ri
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(priv->i2c, &msg0, 1) != 1)
+		return -EIO;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(priv->i2c, &msg2, 1) != 1)
+		return -EIO;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(priv->i2c, &msg1, 1) != 1)
+		return -EIO;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return 0;
+}
+
+static int tua6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tua6100_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static struct dvb_tuner_ops tua6100_tuner_ops = {
+	.info = {
+		.name = "Infineon TUA6100",
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		.frequency_step = 1000,
+	},
+	.release = tua6100_release,
+	.sleep = tua6100_sleep,
+	.set_params = tua6100_set_params,
+	.get_frequency = tua6100_get_frequency,
+};
+
+struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c)
+{
+	struct tua6100_priv *priv = NULL;
+	u8 b1 [] = { 0x80 };
+	u8 b2 [] = { 0x00 };
+	struct i2c_msg msg [] = { { .addr = addr, .flags = 0, .buf = b1, .len = 1 },
+				  { .addr = addr, .flags = I2C_M_RD, .buf = b2, .len = 1 } };
+	int ret;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	ret = i2c_transfer (i2c, msg, 2);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	if (ret != 2)
+		return NULL;
+
+	priv = kzalloc(sizeof(struct tua6100_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->i2c_address = addr;
+	priv->i2c = i2c;
+
+	memcpy(&fe->ops.tuner_ops, &tua6100_tuner_ops, sizeof(struct dvb_tuner_ops));
+	fe->tuner_priv = priv;
+	return fe;
+}
+EXPORT_SYMBOL(tua6100_attach);
+
+MODULE_DESCRIPTION("DVB tua6100 driver");
+MODULE_AUTHOR("Andrew de Quincey");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/tua6100.h b/drivers/media/dvb-frontends/tua6100.h
new file mode 100644
index 0000000..f83dbd5
--- /dev/null
+++ b/drivers/media/dvb-frontends/tua6100.h
@@ -0,0 +1,47 @@
+/**
+ * Driver for Infineon tua6100 PLL.
+ *
+ * (c) 2006 Andrew de Quincey
+ *
+ * Based on code found in budget-av.c, which has the following:
+ * Compiled from various sources by Michael Hunold <michael@mihu.de>
+ *
+ * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> &
+ *                               Andrew de Quincey <adq_dvb@lidskialf.net>
+ *
+ * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
+ *
+ * Copyright (C) 1999-2002 Ralph  Metzler
+ *                       & Marcus Metzler for convergence integrated media GmbH
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __DVB_TUA6100_H__
+#define __DVB_TUA6100_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_DVB_TUA6100) || (defined(CONFIG_DVB_TUA6100_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend* tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TUA6100
+
+#endif
diff --git a/drivers/media/dvb-frontends/ves1820.c b/drivers/media/dvb-frontends/ves1820.c
new file mode 100644
index 0000000..bb42b56
--- /dev/null
+++ b/drivers/media/dvb-frontends/ves1820.c
@@ -0,0 +1,447 @@
+/*
+    VES1820  - Single Chip Cable Channel Receiver driver module
+
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "ves1820.h"
+
+
+
+struct ves1820_state {
+	struct i2c_adapter* i2c;
+	/* configuration settings */
+	const struct ves1820_config* config;
+	struct dvb_frontend frontend;
+
+	/* private demodulator data */
+	u8 reg0;
+	u8 pwm;
+};
+
+
+static int verbose;
+
+static u8 ves1820_inittab[] = {
+	0x69, 0x6A, 0x93, 0x1A, 0x12, 0x46, 0x26, 0x1A,
+	0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x20,
+	0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+	0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x40
+};
+
+static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data)
+{
+	u8 buf[] = { 0x00, reg, data };
+	struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 3 };
+	int ret;
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		printk("ves1820: %s(): writereg error (reg == 0x%02x, "
+			"val == 0x%02x, ret == %i)\n", __func__, reg, data, ret);
+
+	return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static u8 ves1820_readreg(struct ves1820_state *state, u8 reg)
+{
+	u8 b0[] = { 0x00, reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 2},
+		{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
+	};
+	int ret;
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		printk("ves1820: %s(): readreg error (reg == 0x%02x, "
+		"ret == %i)\n", __func__, reg, ret);
+
+	return b1[0];
+}
+
+static int ves1820_setup_reg0(struct ves1820_state *state, u8 reg0, fe_spectral_inversion_t inversion)
+{
+	reg0 |= state->reg0 & 0x62;
+
+	if (INVERSION_ON == inversion) {
+		if (!state->config->invert) reg0 |= 0x20;
+		else reg0 &= ~0x20;
+	} else if (INVERSION_OFF == inversion) {
+		if (!state->config->invert) reg0 &= ~0x20;
+		else reg0 |= 0x20;
+	}
+
+	ves1820_writereg(state, 0x00, reg0 & 0xfe);
+	ves1820_writereg(state, 0x00, reg0 | 0x01);
+
+	state->reg0 = reg0;
+
+	return 0;
+}
+
+static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate)
+{
+	s32 BDR;
+	s32 BDRI;
+	s16 SFIL = 0;
+	u16 NDEC = 0;
+	u32 ratio;
+	u32 fin;
+	u32 tmp;
+	u64 fptmp;
+	u64 fpxin;
+
+	if (symbolrate > state->config->xin / 2)
+		symbolrate = state->config->xin / 2;
+
+	if (symbolrate < 500000)
+		symbolrate = 500000;
+
+	if (symbolrate < state->config->xin / 16)
+		NDEC = 1;
+	if (symbolrate < state->config->xin / 32)
+		NDEC = 2;
+	if (symbolrate < state->config->xin / 64)
+		NDEC = 3;
+
+	/* yeuch! */
+	fpxin = state->config->xin * 10;
+	fptmp = fpxin; do_div(fptmp, 123);
+	if (symbolrate < fptmp)
+		SFIL = 1;
+	fptmp = fpxin; do_div(fptmp, 160);
+	if (symbolrate < fptmp)
+		SFIL = 0;
+	fptmp = fpxin; do_div(fptmp, 246);
+	if (symbolrate < fptmp)
+		SFIL = 1;
+	fptmp = fpxin; do_div(fptmp, 320);
+	if (symbolrate < fptmp)
+		SFIL = 0;
+	fptmp = fpxin; do_div(fptmp, 492);
+	if (symbolrate < fptmp)
+		SFIL = 1;
+	fptmp = fpxin; do_div(fptmp, 640);
+	if (symbolrate < fptmp)
+		SFIL = 0;
+	fptmp = fpxin; do_div(fptmp, 984);
+	if (symbolrate < fptmp)
+		SFIL = 1;
+
+	fin = state->config->xin >> 4;
+	symbolrate <<= NDEC;
+	ratio = (symbolrate << 4) / fin;
+	tmp = ((symbolrate << 4) % fin) << 8;
+	ratio = (ratio << 8) + tmp / fin;
+	tmp = (tmp % fin) << 8;
+	ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, fin);
+
+	BDR = ratio;
+	BDRI = (((state->config->xin << 5) / symbolrate) + 1) / 2;
+
+	if (BDRI > 0xFF)
+		BDRI = 0xFF;
+
+	SFIL = (SFIL << 4) | ves1820_inittab[0x0E];
+
+	NDEC = (NDEC << 6) | ves1820_inittab[0x03];
+
+	ves1820_writereg(state, 0x03, NDEC);
+	ves1820_writereg(state, 0x0a, BDR & 0xff);
+	ves1820_writereg(state, 0x0b, (BDR >> 8) & 0xff);
+	ves1820_writereg(state, 0x0c, (BDR >> 16) & 0x3f);
+
+	ves1820_writereg(state, 0x0d, BDRI);
+	ves1820_writereg(state, 0x0e, SFIL);
+
+	return 0;
+}
+
+static int ves1820_init(struct dvb_frontend* fe)
+{
+	struct ves1820_state* state = fe->demodulator_priv;
+	int i;
+
+	ves1820_writereg(state, 0, 0);
+
+	for (i = 0; i < sizeof(ves1820_inittab); i++)
+		ves1820_writereg(state, i, ves1820_inittab[i]);
+	if (state->config->selagc)
+		ves1820_writereg(state, 2, ves1820_inittab[2] | 0x08);
+
+	ves1820_writereg(state, 0x34, state->pwm);
+
+	return 0;
+}
+
+static int ves1820_set_parameters(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct ves1820_state* state = fe->demodulator_priv;
+	static const u8 reg0x00[] = { 0x00, 0x04, 0x08, 0x0c, 0x10 };
+	static const u8 reg0x01[] = { 140, 140, 106, 100, 92 };
+	static const u8 reg0x05[] = { 135, 100, 70, 54, 38 };
+	static const u8 reg0x08[] = { 162, 116, 67, 52, 35 };
+	static const u8 reg0x09[] = { 145, 150, 106, 126, 107 };
+	int real_qam = p->modulation - QAM_16;
+
+	if (real_qam < 0 || real_qam > 4)
+		return -EINVAL;
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	ves1820_set_symbolrate(state, p->symbol_rate);
+	ves1820_writereg(state, 0x34, state->pwm);
+
+	ves1820_writereg(state, 0x01, reg0x01[real_qam]);
+	ves1820_writereg(state, 0x05, reg0x05[real_qam]);
+	ves1820_writereg(state, 0x08, reg0x08[real_qam]);
+	ves1820_writereg(state, 0x09, reg0x09[real_qam]);
+
+	ves1820_setup_reg0(state, reg0x00[real_qam], p->inversion);
+	ves1820_writereg(state, 2, ves1820_inittab[2] | (state->config->selagc ? 0x08 : 0));
+	return 0;
+}
+
+static int ves1820_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct ves1820_state* state = fe->demodulator_priv;
+	int sync;
+
+	*status = 0;
+	sync = ves1820_readreg(state, 0x11);
+
+	if (sync & 1)
+		*status |= FE_HAS_SIGNAL;
+
+	if (sync & 2)
+		*status |= FE_HAS_CARRIER;
+
+	if (sync & 2)	/* XXX FIXME! */
+		*status |= FE_HAS_VITERBI;
+
+	if (sync & 4)
+		*status |= FE_HAS_SYNC;
+
+	if (sync & 8)
+		*status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int ves1820_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct ves1820_state* state = fe->demodulator_priv;
+
+	u32 _ber = ves1820_readreg(state, 0x14) |
+			(ves1820_readreg(state, 0x15) << 8) |
+			((ves1820_readreg(state, 0x16) & 0x0f) << 16);
+	*ber = 10 * _ber;
+
+	return 0;
+}
+
+static int ves1820_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct ves1820_state* state = fe->demodulator_priv;
+
+	u8 gain = ves1820_readreg(state, 0x17);
+	*strength = (gain << 8) | gain;
+
+	return 0;
+}
+
+static int ves1820_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct ves1820_state* state = fe->demodulator_priv;
+
+	u8 quality = ~ves1820_readreg(state, 0x18);
+	*snr = (quality << 8) | quality;
+
+	return 0;
+}
+
+static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct ves1820_state* state = fe->demodulator_priv;
+
+	*ucblocks = ves1820_readreg(state, 0x13) & 0x7f;
+	if (*ucblocks == 0x7f)
+		*ucblocks = 0xffffffff;
+
+	/* reset uncorrected block counter */
+	ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf);
+	ves1820_writereg(state, 0x10, ves1820_inittab[0x10]);
+
+	return 0;
+}
+
+static int ves1820_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct ves1820_state* state = fe->demodulator_priv;
+	int sync;
+	s8 afc = 0;
+
+	sync = ves1820_readreg(state, 0x11);
+	afc = ves1820_readreg(state, 0x19);
+	if (verbose) {
+		/* AFC only valid when carrier has been recovered */
+		printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" :
+			"ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->symbol_rate * afc) >> 10);
+	}
+
+	if (!state->config->invert) {
+		p->inversion = (state->reg0 & 0x20) ? INVERSION_ON : INVERSION_OFF;
+	} else {
+		p->inversion = (!(state->reg0 & 0x20)) ? INVERSION_ON : INVERSION_OFF;
+	}
+
+	p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
+
+	p->fec_inner = FEC_NONE;
+
+	p->frequency = ((p->frequency + 31250) / 62500) * 62500;
+	if (sync & 2)
+		p->frequency -= ((s32) p->symbol_rate * afc) >> 10;
+
+	return 0;
+}
+
+static int ves1820_sleep(struct dvb_frontend* fe)
+{
+	struct ves1820_state* state = fe->demodulator_priv;
+
+	ves1820_writereg(state, 0x1b, 0x02);	/* pdown ADC */
+	ves1820_writereg(state, 0x00, 0x80);	/* standby */
+
+	return 0;
+}
+
+static int ves1820_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+
+	fesettings->min_delay_ms = 200;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+	return 0;
+}
+
+static void ves1820_release(struct dvb_frontend* fe)
+{
+	struct ves1820_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops ves1820_ops;
+
+struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
+				    struct i2c_adapter* i2c,
+				    u8 pwm)
+{
+	struct ves1820_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct ves1820_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->reg0 = ves1820_inittab[0];
+	state->config = config;
+	state->i2c = i2c;
+	state->pwm = pwm;
+
+	/* check if the demod is there */
+	if ((ves1820_readreg(state, 0x1a) & 0xf0) != 0x70)
+		goto error;
+
+	if (verbose)
+		printk("ves1820: pwm=0x%02x\n", state->pwm);
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.ops.info.symbol_rate_min = (state->config->xin / 2) / 64;      /* SACLK/64 == (XIN/2)/64 */
+	state->frontend.ops.info.symbol_rate_max = (state->config->xin / 2) / 4;       /* SACLK/4 */
+	state->frontend.demodulator_priv = state;
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops ves1820_ops = {
+	.delsys = { SYS_DVBC_ANNEX_A },
+	.info = {
+		.name = "VLSI VES1820 DVB-C",
+		.frequency_stepsize = 62500,
+		.frequency_min = 47000000,
+		.frequency_max = 862000000,
+		.caps = FE_CAN_QAM_16 |
+			FE_CAN_QAM_32 |
+			FE_CAN_QAM_64 |
+			FE_CAN_QAM_128 |
+			FE_CAN_QAM_256 |
+			FE_CAN_FEC_AUTO
+	},
+
+	.release = ves1820_release,
+
+	.init = ves1820_init,
+	.sleep = ves1820_sleep,
+
+	.set_frontend = ves1820_set_parameters,
+	.get_frontend = ves1820_get_frontend,
+	.get_tune_settings = ves1820_get_tune_settings,
+
+	.read_status = ves1820_read_status,
+	.read_ber = ves1820_read_ber,
+	.read_signal_strength = ves1820_read_signal_strength,
+	.read_snr = ves1820_read_snr,
+	.read_ucblocks = ves1820_read_ucblocks,
+};
+
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
+
+MODULE_DESCRIPTION("VLSI VES1820 DVB-C Demodulator driver");
+MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(ves1820_attach);
diff --git a/drivers/media/dvb-frontends/ves1820.h b/drivers/media/dvb-frontends/ves1820.h
new file mode 100644
index 0000000..e902ed6
--- /dev/null
+++ b/drivers/media/dvb-frontends/ves1820.h
@@ -0,0 +1,56 @@
+/*
+    VES1820  - Single Chip Cable Channel Receiver driver module
+
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef VES1820_H
+#define VES1820_H
+
+#include <linux/dvb/frontend.h>
+
+#define VES1820_SELAGC_PWM 0
+#define VES1820_SELAGC_SIGNAMPERR 1
+
+struct ves1820_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* value of XIN to use */
+	u32 xin;
+
+	/* does inversion need inverted? */
+	u8 invert:1;
+
+	/* SELAGC control */
+	u8 selagc:1;
+};
+
+#if defined(CONFIG_DVB_VES1820) || (defined(CONFIG_DVB_VES1820_MODULE) && defined(MODULE))
+extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
+					   struct i2c_adapter* i2c, u8 pwm);
+#else
+static inline struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
+					   struct i2c_adapter* i2c, u8 pwm)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_VES1820
+
+#endif // VES1820_H
diff --git a/drivers/media/dvb-frontends/ves1x93.c b/drivers/media/dvb-frontends/ves1x93.c
new file mode 100644
index 0000000..9c17eac
--- /dev/null
+++ b/drivers/media/dvb-frontends/ves1x93.c
@@ -0,0 +1,553 @@
+/*
+    Driver for VES1893 and VES1993 QPSK Demodulators
+
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+    Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de>
+    Copyright (C) 2002 Dennis Noermann <dennis.noermann@noernet.de>
+    Copyright (C) 2002-2003 Andreas Oberritter <obi@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include "dvb_frontend.h"
+#include "ves1x93.h"
+
+
+struct ves1x93_state {
+	struct i2c_adapter* i2c;
+	/* configuration settings */
+	const struct ves1x93_config* config;
+	struct dvb_frontend frontend;
+
+	/* previous uncorrected block counter */
+	fe_spectral_inversion_t inversion;
+	u8 *init_1x93_tab;
+	u8 *init_1x93_wtab;
+	u8 tab_size;
+	u8 demod_type;
+	u32 frequency;
+};
+
+static int debug;
+#define dprintk	if (debug) printk
+
+#define DEMOD_VES1893		0
+#define DEMOD_VES1993		1
+
+static u8 init_1893_tab [] = {
+	0x01, 0xa4, 0x35, 0x80, 0x2a, 0x0b, 0x55, 0xc4,
+	0x09, 0x69, 0x00, 0x86, 0x4c, 0x28, 0x7f, 0x00,
+	0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x80, 0x00, 0x21, 0xb0, 0x14, 0x00, 0xdc, 0x00,
+	0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x55, 0x00, 0x00, 0x7f, 0x00
+};
+
+static u8 init_1993_tab [] = {
+	0x00, 0x9c, 0x35, 0x80, 0x6a, 0x09, 0x72, 0x8c,
+	0x09, 0x6b, 0x00, 0x00, 0x4c, 0x08, 0x00, 0x00,
+	0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x80, 0x40, 0x21, 0xb0, 0x00, 0x00, 0x00, 0x10,
+	0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03,
+	0x00, 0x00, 0x0e, 0x80, 0x00
+};
+
+static u8 init_1893_wtab[] =
+{
+	1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
+	0,1,0,0,0,0,0,0, 1,0,1,1,0,0,0,1,
+	1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0,
+	1,1,1,0,1,1
+};
+
+static u8 init_1993_wtab[] =
+{
+	1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
+	0,1,0,0,0,0,0,0, 1,1,1,1,0,0,0,1,
+	1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0,
+	1,1,1,0,1,1,1,1, 1,1,1,1,1
+};
+
+static int ves1x93_writereg (struct ves1x93_state* state, u8 reg, u8 data)
+{
+	u8 buf [] = { 0x00, reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 };
+	int err;
+
+	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+		dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static u8 ves1x93_readreg (struct ves1x93_state* state, u8 reg)
+{
+	int ret;
+	u8 b0 [] = { 0x00, reg };
+	u8 b1 [] = { 0 };
+	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
+			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+
+	ret = i2c_transfer (state->i2c, msg, 2);
+
+	if (ret != 2) return ret;
+
+	return b1[0];
+}
+
+static int ves1x93_clr_bit (struct ves1x93_state* state)
+{
+	msleep(10);
+	ves1x93_writereg (state, 0, state->init_1x93_tab[0] & 0xfe);
+	ves1x93_writereg (state, 0, state->init_1x93_tab[0]);
+	msleep(50);
+	return 0;
+}
+
+static int ves1x93_set_inversion (struct ves1x93_state* state, fe_spectral_inversion_t inversion)
+{
+	u8 val;
+
+	/*
+	 * inversion on/off are interchanged because i and q seem to
+	 * be swapped on the hardware
+	 */
+
+	switch (inversion) {
+	case INVERSION_OFF:
+		val = 0xc0;
+		break;
+	case INVERSION_ON:
+		val = 0x80;
+		break;
+	case INVERSION_AUTO:
+		val = 0x00;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ves1x93_writereg (state, 0x0c, (state->init_1x93_tab[0x0c] & 0x3f) | val);
+}
+
+static int ves1x93_set_fec (struct ves1x93_state* state, fe_code_rate_t fec)
+{
+	if (fec == FEC_AUTO)
+		return ves1x93_writereg (state, 0x0d, 0x08);
+	else if (fec < FEC_1_2 || fec > FEC_8_9)
+		return -EINVAL;
+	else
+		return ves1x93_writereg (state, 0x0d, fec - FEC_1_2);
+}
+
+static fe_code_rate_t ves1x93_get_fec (struct ves1x93_state* state)
+{
+	return FEC_1_2 + ((ves1x93_readreg (state, 0x0d) >> 4) & 0x7);
+}
+
+static int ves1x93_set_symbolrate (struct ves1x93_state* state, u32 srate)
+{
+	u32 BDR;
+	u32 ratio;
+	u8  ADCONF, FCONF, FNR, AGCR;
+	u32 BDRI;
+	u32 tmp;
+	u32 FIN;
+
+	dprintk("%s: srate == %d\n", __func__, (unsigned int) srate);
+
+	if (srate > state->config->xin/2)
+		srate = state->config->xin/2;
+
+	if (srate < 500000)
+		srate = 500000;
+
+#define MUL (1UL<<26)
+
+	FIN = (state->config->xin + 6000) >> 4;
+
+	tmp = srate << 6;
+	ratio = tmp / FIN;
+
+	tmp = (tmp % FIN) << 8;
+	ratio = (ratio << 8) + tmp / FIN;
+
+	tmp = (tmp % FIN) << 8;
+	ratio = (ratio << 8) + tmp / FIN;
+
+	FNR = 0xff;
+
+	if (ratio < MUL/3)	     FNR = 0;
+	if (ratio < (MUL*11)/50)     FNR = 1;
+	if (ratio < MUL/6)	     FNR = 2;
+	if (ratio < MUL/9)	     FNR = 3;
+	if (ratio < MUL/12)	     FNR = 4;
+	if (ratio < (MUL*11)/200)    FNR = 5;
+	if (ratio < MUL/24)	     FNR = 6;
+	if (ratio < (MUL*27)/1000)   FNR = 7;
+	if (ratio < MUL/48)	     FNR = 8;
+	if (ratio < (MUL*137)/10000) FNR = 9;
+
+	if (FNR == 0xff) {
+		ADCONF = 0x89;
+		FCONF  = 0x80;
+		FNR	= 0;
+	} else {
+		ADCONF = 0x81;
+		FCONF  = 0x88 | (FNR >> 1) | ((FNR & 0x01) << 5);
+		/*FCONF	 = 0x80 | ((FNR & 0x01) << 5) | (((FNR > 1) & 0x03) << 3) | ((FNR >> 1) & 0x07);*/
+	}
+
+	BDR = (( (ratio << (FNR >> 1)) >> 4) + 1) >> 1;
+	BDRI = ( ((FIN << 8) / ((srate << (FNR >> 1)) >> 2)) + 1) >> 1;
+
+	dprintk("FNR= %d\n", FNR);
+	dprintk("ratio= %08x\n", (unsigned int) ratio);
+	dprintk("BDR= %08x\n", (unsigned int) BDR);
+	dprintk("BDRI= %02x\n", (unsigned int) BDRI);
+
+	if (BDRI > 0xff)
+		BDRI = 0xff;
+
+	ves1x93_writereg (state, 0x06, 0xff & BDR);
+	ves1x93_writereg (state, 0x07, 0xff & (BDR >> 8));
+	ves1x93_writereg (state, 0x08, 0x0f & (BDR >> 16));
+
+	ves1x93_writereg (state, 0x09, BDRI);
+	ves1x93_writereg (state, 0x20, ADCONF);
+	ves1x93_writereg (state, 0x21, FCONF);
+
+	AGCR = state->init_1x93_tab[0x05];
+	if (state->config->invert_pwm)
+		AGCR |= 0x20;
+
+	if (srate < 6000000)
+		AGCR |= 0x80;
+	else
+		AGCR &= ~0x80;
+
+	ves1x93_writereg (state, 0x05, AGCR);
+
+	/* ves1993 hates this, will lose lock */
+	if (state->demod_type != DEMOD_VES1993)
+		ves1x93_clr_bit (state);
+
+	return 0;
+}
+
+static int ves1x93_init (struct dvb_frontend* fe)
+{
+	struct ves1x93_state* state = fe->demodulator_priv;
+	int i;
+	int val;
+
+	dprintk("%s: init chip\n", __func__);
+
+	for (i = 0; i < state->tab_size; i++) {
+		if (state->init_1x93_wtab[i]) {
+			val = state->init_1x93_tab[i];
+
+			if (state->config->invert_pwm && (i == 0x05)) val |= 0x20; /* invert PWM */
+			ves1x93_writereg (state, i, val);
+		}
+	}
+
+	return 0;
+}
+
+static int ves1x93_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	struct ves1x93_state* state = fe->demodulator_priv;
+
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		return ves1x93_writereg (state, 0x1f, 0x20);
+	case SEC_VOLTAGE_18:
+		return ves1x93_writereg (state, 0x1f, 0x30);
+	case SEC_VOLTAGE_OFF:
+		return ves1x93_writereg (state, 0x1f, 0x00);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int ves1x93_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct ves1x93_state* state = fe->demodulator_priv;
+
+	u8 sync = ves1x93_readreg (state, 0x0e);
+
+	/*
+	 * The ves1893 sometimes returns sync values that make no sense,
+	 * because, e.g., the SIGNAL bit is 0, while some of the higher
+	 * bits are 1 (and how can there be a CARRIER w/o a SIGNAL?).
+	 * Tests showed that the VITERBI and SYNC bits are returned
+	 * reliably, while the SIGNAL and CARRIER bits ar sometimes wrong.
+	 * If such a case occurs, we read the value again, until we get a
+	 * valid value.
+	 */
+	int maxtry = 10; /* just for safety - let's not get stuck here */
+	while ((sync & 0x03) != 0x03 && (sync & 0x0c) && maxtry--) {
+		msleep(10);
+		sync = ves1x93_readreg (state, 0x0e);
+	}
+
+	*status = 0;
+
+	if (sync & 1)
+		*status |= FE_HAS_SIGNAL;
+
+	if (sync & 2)
+		*status |= FE_HAS_CARRIER;
+
+	if (sync & 4)
+		*status |= FE_HAS_VITERBI;
+
+	if (sync & 8)
+		*status |= FE_HAS_SYNC;
+
+	if ((sync & 0x1f) == 0x1f)
+		*status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int ves1x93_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct ves1x93_state* state = fe->demodulator_priv;
+
+	*ber = ves1x93_readreg (state, 0x15);
+	*ber |= (ves1x93_readreg (state, 0x16) << 8);
+	*ber |= ((ves1x93_readreg (state, 0x17) & 0x0F) << 16);
+	*ber *= 10;
+
+	return 0;
+}
+
+static int ves1x93_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct ves1x93_state* state = fe->demodulator_priv;
+
+	u8 signal = ~ves1x93_readreg (state, 0x0b);
+	*strength = (signal << 8) | signal;
+
+	return 0;
+}
+
+static int ves1x93_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct ves1x93_state* state = fe->demodulator_priv;
+
+	u8 _snr = ~ves1x93_readreg (state, 0x1c);
+	*snr = (_snr << 8) | _snr;
+
+	return 0;
+}
+
+static int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct ves1x93_state* state = fe->demodulator_priv;
+
+	*ucblocks = ves1x93_readreg (state, 0x18) & 0x7f;
+
+	if (*ucblocks == 0x7f)
+		*ucblocks = 0xffffffff;   /* counter overflow... */
+
+	ves1x93_writereg (state, 0x18, 0x00);  /* reset the counter */
+	ves1x93_writereg (state, 0x18, 0x80);  /* dto. */
+
+	return 0;
+}
+
+static int ves1x93_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct ves1x93_state* state = fe->demodulator_priv;
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+	ves1x93_set_inversion (state, p->inversion);
+	ves1x93_set_fec(state, p->fec_inner);
+	ves1x93_set_symbolrate(state, p->symbol_rate);
+	state->inversion = p->inversion;
+	state->frequency = p->frequency;
+
+	return 0;
+}
+
+static int ves1x93_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct ves1x93_state* state = fe->demodulator_priv;
+	int afc;
+
+	afc = ((int)((char)(ves1x93_readreg (state, 0x0a) << 1)))/2;
+	afc = (afc * (int)(p->symbol_rate/1000/8))/16;
+
+	p->frequency = state->frequency - afc;
+
+	/*
+	 * inversion indicator is only valid
+	 * if auto inversion was used
+	 */
+	if (state->inversion == INVERSION_AUTO)
+		p->inversion = (ves1x93_readreg (state, 0x0f) & 2) ?
+				INVERSION_OFF : INVERSION_ON;
+	p->fec_inner = ves1x93_get_fec(state);
+	/*  XXX FIXME: timing offset !! */
+
+	return 0;
+}
+
+static int ves1x93_sleep(struct dvb_frontend* fe)
+{
+	struct ves1x93_state* state = fe->demodulator_priv;
+
+	return ves1x93_writereg (state, 0x00, 0x08);
+}
+
+static void ves1x93_release(struct dvb_frontend* fe)
+{
+	struct ves1x93_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static int ves1x93_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct ves1x93_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		return ves1x93_writereg(state, 0x00, 0x11);
+	} else {
+		return ves1x93_writereg(state, 0x00, 0x01);
+	}
+}
+
+static struct dvb_frontend_ops ves1x93_ops;
+
+struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
+				    struct i2c_adapter* i2c)
+{
+	struct ves1x93_state* state = NULL;
+	u8 identity;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct ves1x93_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->inversion = INVERSION_OFF;
+
+	/* check if the demod is there + identify it */
+	identity = ves1x93_readreg(state, 0x1e);
+	switch (identity) {
+	case 0xdc: /* VES1893A rev1 */
+		printk("ves1x93: Detected ves1893a rev1\n");
+		state->demod_type = DEMOD_VES1893;
+		state->init_1x93_tab = init_1893_tab;
+		state->init_1x93_wtab = init_1893_wtab;
+		state->tab_size = sizeof(init_1893_tab);
+		break;
+
+	case 0xdd: /* VES1893A rev2 */
+		printk("ves1x93: Detected ves1893a rev2\n");
+		state->demod_type = DEMOD_VES1893;
+		state->init_1x93_tab = init_1893_tab;
+		state->init_1x93_wtab = init_1893_wtab;
+		state->tab_size = sizeof(init_1893_tab);
+		break;
+
+	case 0xde: /* VES1993 */
+		printk("ves1x93: Detected ves1993\n");
+		state->demod_type = DEMOD_VES1993;
+		state->init_1x93_tab = init_1993_tab;
+		state->init_1x93_wtab = init_1993_wtab;
+		state->tab_size = sizeof(init_1993_tab);
+		break;
+
+	default:
+		goto error;
+	}
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops ves1x93_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name			= "VLSI VES1x93 DVB-S",
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 125,		 /* kHz for QPSK frontends */
+		.frequency_tolerance	= 29500,
+		.symbol_rate_min	= 1000000,
+		.symbol_rate_max	= 45000000,
+	/*	.symbol_rate_tolerance	=	???,*/
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK
+	},
+
+	.release = ves1x93_release,
+
+	.init = ves1x93_init,
+	.sleep = ves1x93_sleep,
+	.i2c_gate_ctrl = ves1x93_i2c_gate_ctrl,
+
+	.set_frontend = ves1x93_set_frontend,
+	.get_frontend = ves1x93_get_frontend,
+
+	.read_status = ves1x93_read_status,
+	.read_ber = ves1x93_read_ber,
+	.read_signal_strength = ves1x93_read_signal_strength,
+	.read_snr = ves1x93_read_snr,
+	.read_ucblocks = ves1x93_read_ucblocks,
+
+	.set_voltage = ves1x93_set_voltage,
+};
+
+module_param(debug, int, 0644);
+
+MODULE_DESCRIPTION("VLSI VES1x93 DVB-S Demodulator driver");
+MODULE_AUTHOR("Ralph Metzler");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(ves1x93_attach);
diff --git a/drivers/media/dvb-frontends/ves1x93.h b/drivers/media/dvb-frontends/ves1x93.h
new file mode 100644
index 0000000..8a5a49e
--- /dev/null
+++ b/drivers/media/dvb-frontends/ves1x93.h
@@ -0,0 +1,55 @@
+/*
+    Driver for VES1893 and VES1993 QPSK Demodulators
+
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+    Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de>
+    Copyright (C) 2002 Dennis Noermann <dennis.noermann@noernet.de>
+    Copyright (C) 2002-2003 Andreas Oberritter <obi@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef VES1X93_H
+#define VES1X93_H
+
+#include <linux/dvb/frontend.h>
+
+struct ves1x93_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* value of XIN to use */
+	u32 xin;
+
+	/* should PWM be inverted? */
+	u8 invert_pwm:1;
+};
+
+#if defined(CONFIG_DVB_VES1X93) || (defined(CONFIG_DVB_VES1X93_MODULE) && defined(MODULE))
+extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
+					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_VES1X93
+
+#endif // VES1X93_H
diff --git a/drivers/media/dvb-frontends/z0194a.h b/drivers/media/dvb-frontends/z0194a.h
new file mode 100644
index 0000000..96d86d6
--- /dev/null
+++ b/drivers/media/dvb-frontends/z0194a.h
@@ -0,0 +1,85 @@
+/* z0194a.h Sharp z0194a tuner support
+*
+* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+*
+*	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, version 2.
+*
+* see Documentation/dvb/README.dvb-usb for more information
+*/
+
+#ifndef Z0194A
+#define Z0194A
+
+static int sharp_z0194a_set_symbol_rate(struct dvb_frontend *fe,
+					 u32 srate, u32 ratio)
+{
+	u8 aclk = 0;
+	u8 bclk = 0;
+
+	if (srate < 1500000) {
+		aclk = 0xb7; bclk = 0x47; }
+	else if (srate < 3000000) {
+		aclk = 0xb7; bclk = 0x4b; }
+	else if (srate < 7000000) {
+		aclk = 0xb7; bclk = 0x4f; }
+	else if (srate < 14000000) {
+		aclk = 0xb7; bclk = 0x53; }
+	else if (srate < 30000000) {
+		aclk = 0xb6; bclk = 0x53; }
+	else if (srate < 45000000) {
+		aclk = 0xb4; bclk = 0x51; }
+
+	stv0299_writereg(fe, 0x13, aclk);
+	stv0299_writereg(fe, 0x14, bclk);
+	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+	stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+	stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
+
+	return 0;
+}
+
+static u8 sharp_z0194a_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x30,
+	0x03, 0x00,
+	0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+	0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
+	0x06, 0x40,   /* DAC not used, set to high impendance mode */
+	0x07, 0x00,   /* DAC LSB */
+	0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
+	0x09, 0x00,   /* FIFO */
+	0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+	0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
+	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
+	0x10, 0x3f,   /* AGC2  0x3d */
+	0x11, 0x84,
+	0x12, 0xb9,
+	0x15, 0xc9,   /* lock detector threshold */
+	0x16, 0x00,
+	0x17, 0x00,
+	0x18, 0x00,
+	0x19, 0x00,
+	0x1a, 0x00,
+	0x1f, 0x50,
+	0x20, 0x00,
+	0x21, 0x00,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x28, 0x00,  /* out imp: normal  out type: parallel FEC mode:0 */
+	0x29, 0x1e,  /* 1/2 threshold */
+	0x2a, 0x14,  /* 2/3 threshold */
+	0x2b, 0x0f,  /* 3/4 threshold */
+	0x2c, 0x09,  /* 5/6 threshold */
+	0x2d, 0x05,  /* 7/8 threshold */
+	0x2e, 0x01,
+	0x31, 0x1f,  /* test all FECs */
+	0x32, 0x19,  /* viterbi and synchro search */
+	0x33, 0xfc,  /* rs control */
+	0x34, 0x93,  /* error control */
+	0x0f, 0x52,
+	0xff, 0xff
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/zl10036.c b/drivers/media/dvb-frontends/zl10036.c
new file mode 100644
index 0000000..0903d46
--- /dev/null
+++ b/drivers/media/dvb-frontends/zl10036.c
@@ -0,0 +1,520 @@
+/**
+ * Driver for Zarlink zl10036 DVB-S silicon tuner
+ *
+ * Copyright (C) 2006 Tino Reichardt
+ * Copyright (C) 2007-2009 Matthias Schwarzott <zzam@gentoo.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **
+ * The data sheet for this tuner can be found at:
+ *    http://www.mcmilk.de/projects/dvb-card/datasheets/ZL10036.pdf
+ *
+ * This one is working: (at my Avermedia DVB-S Pro)
+ * - zl10036 (40pin, FTA)
+ *
+ * A driver for zl10038 should be very similar.
+ */
+
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "zl10036.h"
+
+static int zl10036_debug;
+#define dprintk(level, args...) \
+	do { if (zl10036_debug & level) printk(KERN_DEBUG "zl10036: " args); \
+	} while (0)
+
+#define deb_info(args...)  dprintk(0x01, args)
+#define deb_i2c(args...)  dprintk(0x02, args)
+
+struct zl10036_state {
+	struct i2c_adapter *i2c;
+	const struct zl10036_config *config;
+	u32 frequency;
+	u8 br, bf;
+};
+
+
+/* This driver assumes the tuner is driven by a 10.111MHz Cristal */
+#define _XTAL 10111
+
+/* Some of the possible dividers:
+ *   64, (write 0x05 to reg), freq step size   158kHz
+ *   10, (write 0x0a to reg), freq step size 1.011kHz (used here)
+ *    5, (write 0x09 to reg), freq step size 2.022kHz
+ */
+
+#define _RDIV 10
+#define _RDIV_REG 0x0a
+#define _FR   (_XTAL/_RDIV)
+
+#define STATUS_POR 0x80 /* Power on Reset */
+#define STATUS_FL  0x40 /* Frequency & Phase Lock */
+
+/* read/write for zl10036 and zl10038 */
+
+static int zl10036_read_status_reg(struct zl10036_state *state)
+{
+	u8 status;
+	struct i2c_msg msg[1] = {
+		{ .addr = state->config->tuner_address, .flags = I2C_M_RD,
+		  .buf = &status, .len = sizeof(status) },
+	};
+
+	if (i2c_transfer(state->i2c, msg, 1) != 1) {
+		printk(KERN_ERR "%s: i2c read failed at addr=%02x\n",
+			__func__, state->config->tuner_address);
+		return -EIO;
+	}
+
+	deb_i2c("R(status): %02x  [FL=%d]\n", status,
+		(status & STATUS_FL) ? 1 : 0);
+	if (status & STATUS_POR)
+		deb_info("%s: Power-On-Reset bit enabled - "
+			"need to initialize the tuner\n", __func__);
+
+	return status;
+}
+
+static int zl10036_write(struct zl10036_state *state, u8 buf[], u8 count)
+{
+	struct i2c_msg msg[1] = {
+		{ .addr = state->config->tuner_address, .flags = 0,
+		  .buf = buf, .len = count },
+	};
+	u8 reg = 0;
+	int ret;
+
+	if (zl10036_debug & 0x02) {
+		/* every 8bit-value satisifes this!
+		 * so only check for debug log */
+		if ((buf[0] & 0x80) == 0x00)
+			reg = 2;
+		else if ((buf[0] & 0xc0) == 0x80)
+			reg = 4;
+		else if ((buf[0] & 0xf0) == 0xc0)
+			reg = 6;
+		else if ((buf[0] & 0xf0) == 0xd0)
+			reg = 8;
+		else if ((buf[0] & 0xf0) == 0xe0)
+			reg = 10;
+		else if ((buf[0] & 0xf0) == 0xf0)
+			reg = 12;
+
+		deb_i2c("W(%d):", reg);
+		{
+			int i;
+			for (i = 0; i < count; i++)
+				printk(KERN_CONT " %02x", buf[i]);
+			printk(KERN_CONT "\n");
+		}
+	}
+
+	ret = i2c_transfer(state->i2c, msg, 1);
+	if (ret != 1) {
+		printk(KERN_ERR "%s: i2c error, ret=%d\n", __func__, ret);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int zl10036_release(struct dvb_frontend *fe)
+{
+	struct zl10036_state *state = fe->tuner_priv;
+
+	fe->tuner_priv = NULL;
+	kfree(state);
+
+	return 0;
+}
+
+static int zl10036_sleep(struct dvb_frontend *fe)
+{
+	struct zl10036_state *state = fe->tuner_priv;
+	u8 buf[] = { 0xf0, 0x80 }; /* regs 12/13 */
+	int ret;
+
+	deb_info("%s\n", __func__);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	ret = zl10036_write(state, buf, sizeof(buf));
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	return ret;
+}
+
+/**
+ * register map of the ZL10036/ZL10038
+ *
+ * reg[default] content
+ *  2[0x00]:   0 | N14 | N13 | N12 | N11 | N10 |  N9 |  N8
+ *  3[0x00]:  N7 |  N6 |  N5 |  N4 |  N3 |  N2 |  N1 |  N0
+ *  4[0x80]:   1 |   0 | RFG | BA1 | BA0 | BG1 | BG0 | LEN
+ *  5[0x00]:  P0 |  C1 |  C0 |  R4 |  R3 |  R2 |  R1 |  R0
+ *  6[0xc0]:   1 |   1 |   0 |   0 | RSD |   0 |   0 |   0
+ *  7[0x20]:  P1 | BF6 | BF5 | BF4 | BF3 | BF2 | BF1 |   0
+ *  8[0xdb]:   1 |   1 |   0 |   1 |   0 |  CC |   1 |   1
+ *  9[0x30]: VSD |  V2 |  V1 |  V0 |  S3 |  S2 |  S1 |  S0
+ * 10[0xe1]:   1 |   1 |   1 |   0 |   0 | LS2 | LS1 | LS0
+ * 11[0xf5]:  WS | WH2 | WH1 | WH0 | WL2 | WL1 | WL0 | WRE
+ * 12[0xf0]:   1 |   1 |   1 |   1 |   0 |   0 |   0 |   0
+ * 13[0x28]:  PD | BR4 | BR3 | BR2 | BR1 | BR0 | CLR |  TL
+ */
+
+static int zl10036_set_frequency(struct zl10036_state *state, u32 frequency)
+{
+	u8 buf[2];
+	u32 div, foffset;
+
+	div = (frequency + _FR/2) / _FR;
+	state->frequency = div * _FR;
+
+	foffset = frequency - state->frequency;
+
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = (div >> 0) & 0xff;
+
+	deb_info("%s: ftodo=%u fpriv=%u ferr=%d div=%u\n", __func__,
+		frequency, state->frequency, foffset, div);
+
+	return zl10036_write(state, buf, sizeof(buf));
+}
+
+static int zl10036_set_bandwidth(struct zl10036_state *state, u32 fbw)
+{
+	/* fbw is measured in kHz */
+	u8 br, bf;
+	int ret;
+	u8 buf_bf[] = {
+		0xc0, 0x00, /*   6/7: rsd=0 bf=0 */
+	};
+	u8 buf_br[] = {
+		0xf0, 0x00, /* 12/13: br=0xa clr=0 tl=0*/
+	};
+	u8 zl10036_rsd_off[] = { 0xc8 }; /* set RSD=1 */
+
+	/* ensure correct values */
+	if (fbw > 35000)
+		fbw = 35000;
+	if (fbw <  8000)
+		fbw =  8000;
+
+#define _BR_MAXIMUM (_XTAL/575) /* _XTAL / 575kHz = 17 */
+
+	/* <= 28,82 MHz */
+	if (fbw <= 28820) {
+		br = _BR_MAXIMUM;
+	} else {
+		/**
+		 *  f(bw)=34,6MHz f(xtal)=10.111MHz
+		 *  br = (10111/34600) * 63 * 1/K = 14;
+		 */
+		br = ((_XTAL * 21 * 1000) / (fbw * 419));
+	}
+
+	/* ensure correct values */
+	if (br < 4)
+		br = 4;
+	if (br > _BR_MAXIMUM)
+		br = _BR_MAXIMUM;
+
+	/*
+	 * k = 1.257
+	 * bf = fbw/_XTAL * br * k - 1 */
+
+	bf = (fbw * br * 1257) / (_XTAL * 1000) - 1;
+
+	/* ensure correct values */
+	if (bf > 62)
+		bf = 62;
+
+	buf_bf[1] = (bf << 1) & 0x7e;
+	buf_br[1] = (br << 2) & 0x7c;
+	deb_info("%s: BW=%d br=%u bf=%u\n", __func__, fbw, br, bf);
+
+	if (br != state->br) {
+		ret = zl10036_write(state, buf_br, sizeof(buf_br));
+		if (ret < 0)
+			return ret;
+	}
+
+	if (bf != state->bf) {
+		ret = zl10036_write(state, buf_bf, sizeof(buf_bf));
+		if (ret < 0)
+			return ret;
+
+		/* time = br/(32* fxtal) */
+		/* minimal sleep time to be calculated
+		 * maximum br is 63 -> max time = 2 /10 MHz = 2e-7 */
+		msleep(1);
+
+		ret = zl10036_write(state, zl10036_rsd_off,
+			sizeof(zl10036_rsd_off));
+		if (ret < 0)
+			return ret;
+	}
+
+	state->br = br;
+	state->bf = bf;
+
+	return 0;
+}
+
+static int zl10036_set_gain_params(struct zl10036_state *state,
+	int c)
+{
+	u8 buf[2];
+	u8 rfg, ba, bg;
+
+	/* default values */
+	rfg = 0; /* enable when using an lna */
+	ba = 1;
+	bg = 1;
+
+	/* reg 4 */
+	buf[0] = 0x80 | ((rfg << 5) & 0x20)
+		| ((ba  << 3) & 0x18) | ((bg  << 1) & 0x06);
+
+	if (!state->config->rf_loop_enable)
+		buf[0] |= 0x01;
+
+	/* P0=0 */
+	buf[1] = _RDIV_REG | ((c << 5) & 0x60);
+
+	deb_info("%s: c=%u rfg=%u ba=%u bg=%u\n", __func__, c, rfg, ba, bg);
+	return zl10036_write(state, buf, sizeof(buf));
+}
+
+static int zl10036_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct zl10036_state *state = fe->tuner_priv;
+	int ret = 0;
+	u32 frequency = p->frequency;
+	u32 fbw;
+	int i;
+	u8 c;
+
+	/* ensure correct values
+	 * maybe redundant as core already checks this */
+	if ((frequency < fe->ops.info.frequency_min)
+	||  (frequency > fe->ops.info.frequency_max))
+		return -EINVAL;
+
+	/**
+	 * alpha = 1.35 for dvb-s
+	 * fBW = (alpha*symbolrate)/(2*0.8)
+	 * 1.35 / (2*0.8) = 27 / 32
+	 */
+	fbw = (27 * p->symbol_rate) / 32;
+
+	/* scale to kHz */
+	fbw /= 1000;
+
+	/* Add safe margin of 3MHz */
+	fbw += 3000;
+
+	/* setting the charge pump - guessed values */
+	if (frequency < 950000)
+		return -EINVAL;
+	else if (frequency < 1250000)
+		c = 0;
+	else if (frequency < 1750000)
+		c = 1;
+	else if (frequency < 2175000)
+		c = 2;
+	else
+		return -EINVAL;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	ret = zl10036_set_gain_params(state, c);
+	if (ret < 0)
+		goto error;
+
+	ret = zl10036_set_frequency(state, p->frequency);
+	if (ret < 0)
+		goto error;
+
+	ret = zl10036_set_bandwidth(state, fbw);
+	if (ret < 0)
+		goto error;
+
+	/* wait for tuner lock - no idea if this is really needed */
+	for (i = 0; i < 20; i++) {
+		ret = zl10036_read_status_reg(state);
+		if (ret < 0)
+			goto error;
+
+		/* check Frequency & Phase Lock Bit */
+		if (ret & STATUS_FL)
+			break;
+
+		msleep(10);
+	}
+
+error:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	return ret;
+}
+
+static int zl10036_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct zl10036_state *state = fe->tuner_priv;
+
+	*frequency = state->frequency;
+
+	return 0;
+}
+
+static int zl10036_init_regs(struct zl10036_state *state)
+{
+	int ret;
+	int i;
+
+	/* could also be one block from reg 2 to 13 and additional 10/11 */
+	u8 zl10036_init_tab[][2] = {
+		{ 0x04, 0x00 },		/*   2/3: div=0x400 - arbitrary value */
+		{ 0x8b, _RDIV_REG },	/*   4/5: rfg=0 ba=1 bg=1 len=? */
+					/*        p0=0 c=0 r=_RDIV_REG */
+		{ 0xc0, 0x20 },		/*   6/7: rsd=0 bf=0x10 */
+		{ 0xd3, 0x40 },		/*   8/9: from datasheet */
+		{ 0xe3, 0x5b },		/* 10/11: lock window level */
+		{ 0xf0, 0x28 },		/* 12/13: br=0xa clr=0 tl=0*/
+		{ 0xe3, 0xf9 },		/* 10/11: unlock window level */
+	};
+
+	/* invalid values to trigger writing */
+	state->br = 0xff;
+	state->bf = 0xff;
+
+	if (!state->config->rf_loop_enable)
+		zl10036_init_tab[1][0] |= 0x01;
+
+	deb_info("%s\n", __func__);
+
+	for (i = 0; i < ARRAY_SIZE(zl10036_init_tab); i++) {
+		ret = zl10036_write(state, zl10036_init_tab[i], 2);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int zl10036_init(struct dvb_frontend *fe)
+{
+	struct zl10036_state *state = fe->tuner_priv;
+	int ret = 0;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	ret = zl10036_read_status_reg(state);
+	if (ret < 0)
+		return ret;
+
+	/* Only init if Power-on-Reset bit is set? */
+	ret = zl10036_init_regs(state);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	return ret;
+}
+
+static struct dvb_tuner_ops zl10036_tuner_ops = {
+	.info = {
+		.name = "Zarlink ZL10036",
+		.frequency_min = 950000,
+		.frequency_max = 2175000
+	},
+	.init = zl10036_init,
+	.release = zl10036_release,
+	.sleep = zl10036_sleep,
+	.set_params = zl10036_set_params,
+	.get_frequency = zl10036_get_frequency,
+};
+
+struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe,
+				    const struct zl10036_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct zl10036_state *state;
+	int ret;
+
+	if (!config) {
+		printk(KERN_ERR "%s: no config specified", __func__);
+		return NULL;
+	}
+
+	state = kzalloc(sizeof(struct zl10036_state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	state->config = config;
+	state->i2c = i2c;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	ret = zl10036_read_status_reg(state);
+	if (ret < 0) {
+		printk(KERN_ERR "%s: No zl10036 found\n", __func__);
+		goto error;
+	}
+
+	ret = zl10036_init_regs(state);
+	if (ret < 0) {
+		printk(KERN_ERR "%s: tuner initialization failed\n",
+			__func__);
+		goto error;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	fe->tuner_priv = state;
+
+	memcpy(&fe->ops.tuner_ops, &zl10036_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+	printk(KERN_INFO "%s: tuner initialization (%s addr=0x%02x) ok\n",
+		__func__, fe->ops.tuner_ops.info.name, config->tuner_address);
+
+	return fe;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(zl10036_attach);
+
+module_param_named(debug, zl10036_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+MODULE_DESCRIPTION("DVB ZL10036 driver");
+MODULE_AUTHOR("Tino Reichardt");
+MODULE_AUTHOR("Matthias Schwarzott");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/zl10036.h b/drivers/media/dvb-frontends/zl10036.h
new file mode 100644
index 0000000..d84b8f8
--- /dev/null
+++ b/drivers/media/dvb-frontends/zl10036.h
@@ -0,0 +1,53 @@
+/**
+ * Driver for Zarlink ZL10036 DVB-S silicon tuner
+ *
+ * Copyright (C) 2006 Tino Reichardt
+ * Copyright (C) 2007-2009 Matthias Schwarzott <zzam@gentoo.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DVB_ZL10036_H
+#define DVB_ZL10036_H
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/**
+ * Attach a zl10036 tuner to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param config zl10036_config structure
+ * @return FE pointer on success, NULL on failure.
+ */
+
+struct zl10036_config {
+	u8 tuner_address;
+	int rf_loop_enable;
+};
+
+#if defined(CONFIG_DVB_ZL10036) || \
+	(defined(CONFIG_DVB_ZL10036_MODULE) && defined(MODULE))
+extern struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe,
+	const struct zl10036_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe,
+	const struct zl10036_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* DVB_ZL10036_H */
diff --git a/drivers/media/dvb-frontends/zl10039.c b/drivers/media/dvb-frontends/zl10039.c
new file mode 100644
index 0000000..eff9c5f
--- /dev/null
+++ b/drivers/media/dvb-frontends/zl10039.c
@@ -0,0 +1,307 @@
+/*
+ *  Driver for Zarlink ZL10039 DVB-S tuner
+ *
+ *  Copyright 2007 Jan D. Louw <jd.louw@mweb.co.za>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/dvb/frontend.h>
+
+#include "dvb_frontend.h"
+#include "zl10039.h"
+
+static int debug;
+
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG args); \
+	} while (0)
+
+enum zl10039_model_id {
+	ID_ZL10039 = 1
+};
+
+struct zl10039_state {
+	struct i2c_adapter *i2c;
+	u8 i2c_addr;
+	u8 id;
+};
+
+enum zl10039_reg_addr {
+	PLL0 = 0,
+	PLL1,
+	PLL2,
+	PLL3,
+	RFFE,
+	BASE0,
+	BASE1,
+	BASE2,
+	LO0,
+	LO1,
+	LO2,
+	LO3,
+	LO4,
+	LO5,
+	LO6,
+	GENERAL
+};
+
+static int zl10039_read(const struct zl10039_state *state,
+			const enum zl10039_reg_addr reg, u8 *buf,
+			const size_t count)
+{
+	u8 regbuf[] = { reg };
+	struct i2c_msg msg[] = {
+		{/* Write register address */
+			.addr = state->i2c_addr,
+			.flags = 0,
+			.buf = regbuf,
+			.len = 1,
+		}, {/* Read count bytes */
+			.addr = state->i2c_addr,
+			.flags = I2C_M_RD,
+			.buf = buf,
+			.len = count,
+		},
+	};
+
+	dprintk("%s\n", __func__);
+
+	if (i2c_transfer(state->i2c, msg, 2) != 2) {
+		dprintk("%s: i2c read error\n", __func__);
+		return -EREMOTEIO;
+	}
+
+	return 0; /* Success */
+}
+
+static int zl10039_write(struct zl10039_state *state,
+			const enum zl10039_reg_addr reg, const u8 *src,
+			const size_t count)
+{
+	u8 buf[count + 1];
+	struct i2c_msg msg = {
+		.addr = state->i2c_addr,
+		.flags = 0,
+		.buf = buf,
+		.len = count + 1,
+	};
+
+	dprintk("%s\n", __func__);
+	/* Write register address and data in one go */
+	buf[0] = reg;
+	memcpy(&buf[1], src, count);
+	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+		dprintk("%s: i2c write error\n", __func__);
+		return -EREMOTEIO;
+	}
+
+	return 0; /* Success */
+}
+
+static inline int zl10039_readreg(struct zl10039_state *state,
+				const enum zl10039_reg_addr reg, u8 *val)
+{
+	return zl10039_read(state, reg, val, 1);
+}
+
+static inline int zl10039_writereg(struct zl10039_state *state,
+				const enum zl10039_reg_addr reg,
+				const u8 val)
+{
+	return zl10039_write(state, reg, &val, 1);
+}
+
+static int zl10039_init(struct dvb_frontend *fe)
+{
+	struct zl10039_state *state = fe->tuner_priv;
+	int ret;
+
+	dprintk("%s\n", __func__);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	/* Reset logic */
+	ret = zl10039_writereg(state, GENERAL, 0x40);
+	if (ret < 0) {
+		dprintk("Note: i2c write error normal when resetting the "
+			"tuner\n");
+	}
+	/* Wake up */
+	ret = zl10039_writereg(state, GENERAL, 0x01);
+	if (ret < 0) {
+		dprintk("Tuner power up failed\n");
+		return ret;
+	}
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return 0;
+}
+
+static int zl10039_sleep(struct dvb_frontend *fe)
+{
+	struct zl10039_state *state = fe->tuner_priv;
+	int ret;
+
+	dprintk("%s\n", __func__);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	ret = zl10039_writereg(state, GENERAL, 0x80);
+	if (ret < 0) {
+		dprintk("Tuner sleep failed\n");
+		return ret;
+	}
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return 0;
+}
+
+static int zl10039_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct zl10039_state *state = fe->tuner_priv;
+	u8 buf[6];
+	u8 bf;
+	u32 fbw;
+	u32 div;
+	int ret;
+
+	dprintk("%s\n", __func__);
+	dprintk("Set frequency = %d, symbol rate = %d\n",
+			c->frequency, c->symbol_rate);
+
+	/* Assumed 10.111 MHz crystal oscillator */
+	/* Cancelled num/den 80 to prevent overflow */
+	div = (c->frequency * 1000) / 126387;
+	fbw = (c->symbol_rate * 27) / 32000;
+	/* Cancelled num/den 10 to prevent overflow */
+	bf = ((fbw * 5088) / 1011100) - 1;
+
+	/*PLL divider*/
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = (div >> 0) & 0xff;
+	/*Reference divider*/
+	/* Select reference ratio of 80 */
+	buf[2] = 0x1D;
+	/*PLL test modes*/
+	buf[3] = 0x40;
+	/*RF Control register*/
+	buf[4] = 0x6E; /* Bypass enable */
+	/*Baseband filter cutoff */
+	buf[5] = bf;
+
+	/* Open i2c gate */
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	/* BR = 10, Enable filter adjustment */
+	ret = zl10039_writereg(state, BASE1, 0x0A);
+	if (ret < 0)
+		goto error;
+	/* Write new config values */
+	ret = zl10039_write(state, PLL0, buf, sizeof(buf));
+	if (ret < 0)
+		goto error;
+	/* BR = 10, Disable filter adjustment */
+	ret = zl10039_writereg(state, BASE1, 0x6A);
+	if (ret < 0)
+		goto error;
+
+	/* Close i2c gate */
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+	return 0;
+error:
+	dprintk("Error setting tuner\n");
+	return ret;
+}
+
+static int zl10039_release(struct dvb_frontend *fe)
+{
+	struct zl10039_state *state = fe->tuner_priv;
+
+	dprintk("%s\n", __func__);
+	kfree(state);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static struct dvb_tuner_ops zl10039_ops = {
+	.release = zl10039_release,
+	.init = zl10039_init,
+	.sleep = zl10039_sleep,
+	.set_params = zl10039_set_params,
+};
+
+struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
+		u8 i2c_addr, struct i2c_adapter *i2c)
+{
+	struct zl10039_state *state = NULL;
+
+	dprintk("%s\n", __func__);
+	state = kmalloc(sizeof(struct zl10039_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	state->i2c = i2c;
+	state->i2c_addr = i2c_addr;
+
+	/* Open i2c gate */
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	/* check if this is a valid tuner */
+	if (zl10039_readreg(state, GENERAL, &state->id) < 0) {
+		/* Close i2c gate */
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+		goto error;
+	}
+	/* Close i2c gate */
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	state->id = state->id & 0x0f;
+	switch (state->id) {
+	case ID_ZL10039:
+		strcpy(fe->ops.tuner_ops.info.name,
+			"Zarlink ZL10039 DVB-S tuner");
+		break;
+	default:
+		dprintk("Chip ID=%x does not match a known type\n", state->id);
+		goto error;
+	}
+
+	memcpy(&fe->ops.tuner_ops, &zl10039_ops, sizeof(struct dvb_tuner_ops));
+	fe->tuner_priv = state;
+	dprintk("Tuner attached @ i2c address 0x%02x\n", i2c_addr);
+	return fe;
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(zl10039_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+MODULE_DESCRIPTION("Zarlink ZL10039 DVB-S tuner driver");
+MODULE_AUTHOR("Jan D. Louw <jd.louw@mweb.co.za>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/zl10039.h b/drivers/media/dvb-frontends/zl10039.h
new file mode 100644
index 0000000..5eee7ea
--- /dev/null
+++ b/drivers/media/dvb-frontends/zl10039.h
@@ -0,0 +1,40 @@
+/*
+    Driver for Zarlink ZL10039 DVB-S tuner
+
+    Copyright (C) 2007 Jan D. Louw <jd.louw@mweb.co.za>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef ZL10039_H
+#define ZL10039_H
+
+#if defined(CONFIG_DVB_ZL10039) || (defined(CONFIG_DVB_ZL10039_MODULE) \
+	    && defined(MODULE))
+struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
+					u8 i2c_addr,
+					struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
+					u8 i2c_addr,
+					struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_ZL10039 */
+
+#endif /* ZL10039_H */
diff --git a/drivers/media/dvb-frontends/zl10353.c b/drivers/media/dvb-frontends/zl10353.c
new file mode 100644
index 0000000..82946cd
--- /dev/null
+++ b/drivers/media/dvb-frontends/zl10353.c
@@ -0,0 +1,684 @@
+/*
+ * Driver for Zarlink DVB-T ZL10353 demodulator
+ *
+ * Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "zl10353_priv.h"
+#include "zl10353.h"
+
+struct zl10353_state {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend frontend;
+
+	struct zl10353_config config;
+
+	u32 bandwidth;
+	u32 ucblocks;
+	u32 frequency;
+};
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "zl10353: " args); \
+	} while (0)
+
+static int debug_regs;
+
+static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	u8 buf[2] = { reg, val };
+	struct i2c_msg msg = { .addr = state->config.demod_address, .flags = 0,
+			       .buf = buf, .len = 2 };
+	int err = i2c_transfer(state->i2c, &msg, 1);
+	if (err != 1) {
+		printk("zl10353: write to reg %x failed (err = %d)!\n", reg, err);
+		return err;
+	}
+	return 0;
+}
+
+static int zl10353_write(struct dvb_frontend *fe, const u8 ibuf[], int ilen)
+{
+	int err, i;
+	for (i = 0; i < ilen - 1; i++)
+		if ((err = zl10353_single_write(fe, ibuf[0] + i, ibuf[i + 1])))
+			return err;
+
+	return 0;
+}
+
+static int zl10353_read_register(struct zl10353_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[1] = { reg };
+	u8 b1[1] = { 0 };
+	struct i2c_msg msg[2] = { { .addr = state->config.demod_address,
+				    .flags = 0,
+				    .buf = b0, .len = 1 },
+				  { .addr = state->config.demod_address,
+				    .flags = I2C_M_RD,
+				    .buf = b1, .len = 1 } };
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		printk("%s: readreg error (reg=%d, ret==%i)\n",
+		       __func__, reg, ret);
+		return ret;
+	}
+
+	return b1[0];
+}
+
+static void zl10353_dump_regs(struct dvb_frontend *fe)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	int ret;
+	u8 reg;
+
+	/* Dump all registers. */
+	for (reg = 0; ; reg++) {
+		if (reg % 16 == 0) {
+			if (reg)
+				printk(KERN_CONT "\n");
+			printk(KERN_DEBUG "%02x:", reg);
+		}
+		ret = zl10353_read_register(state, reg);
+		if (ret >= 0)
+			printk(KERN_CONT " %02x", (u8)ret);
+		else
+			printk(KERN_CONT " --");
+		if (reg == 0xff)
+			break;
+	}
+	printk(KERN_CONT "\n");
+}
+
+static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
+				      u32 bandwidth,
+				      u16 *nominal_rate)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	u32 adc_clock = 450560; /* 45.056 MHz */
+	u64 value;
+	u8 bw = bandwidth / 1000000;
+
+	if (state->config.adc_clock)
+		adc_clock = state->config.adc_clock;
+
+	value = (u64)10 * (1 << 23) / 7 * 125;
+	value = (bw * value) + adc_clock / 2;
+	do_div(value, adc_clock);
+	*nominal_rate = value;
+
+	dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
+		__func__, bw, adc_clock, *nominal_rate);
+}
+
+static void zl10353_calc_input_freq(struct dvb_frontend *fe,
+				    u16 *input_freq)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	u32 adc_clock = 450560;	/* 45.056  MHz */
+	int if2 = 361667;	/* 36.1667 MHz */
+	int ife;
+	u64 value;
+
+	if (state->config.adc_clock)
+		adc_clock = state->config.adc_clock;
+	if (state->config.if2)
+		if2 = state->config.if2;
+
+	if (adc_clock >= if2 * 2)
+		ife = if2;
+	else {
+		ife = adc_clock - (if2 % adc_clock);
+		if (ife > adc_clock / 2)
+			ife = adc_clock - ife;
+	}
+	value = (u64)65536 * ife + adc_clock / 2;
+	do_div(value, adc_clock);
+	*input_freq = -value;
+
+	dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
+		__func__, if2, ife, adc_clock, -(int)value, *input_freq);
+}
+
+static int zl10353_sleep(struct dvb_frontend *fe)
+{
+	static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 };
+
+	zl10353_write(fe, zl10353_softdown, sizeof(zl10353_softdown));
+	return 0;
+}
+
+static int zl10353_set_parameters(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct zl10353_state *state = fe->demodulator_priv;
+	u16 nominal_rate, input_freq;
+	u8 pllbuf[6] = { 0x67 }, acq_ctl = 0;
+	u16 tps = 0;
+
+	state->frequency = c->frequency;
+
+	zl10353_single_write(fe, RESET, 0x80);
+	udelay(200);
+	zl10353_single_write(fe, 0xEA, 0x01);
+	udelay(200);
+	zl10353_single_write(fe, 0xEA, 0x00);
+
+	zl10353_single_write(fe, AGC_TARGET, 0x28);
+
+	if (c->transmission_mode != TRANSMISSION_MODE_AUTO)
+		acq_ctl |= (1 << 0);
+	if (c->guard_interval != GUARD_INTERVAL_AUTO)
+		acq_ctl |= (1 << 1);
+	zl10353_single_write(fe, ACQ_CTL, acq_ctl);
+
+	switch (c->bandwidth_hz) {
+	case 6000000:
+		/* These are extrapolated from the 7 and 8MHz values */
+		zl10353_single_write(fe, MCLK_RATIO, 0x97);
+		zl10353_single_write(fe, 0x64, 0x34);
+		zl10353_single_write(fe, 0xcc, 0xdd);
+		break;
+	case 7000000:
+		zl10353_single_write(fe, MCLK_RATIO, 0x86);
+		zl10353_single_write(fe, 0x64, 0x35);
+		zl10353_single_write(fe, 0xcc, 0x73);
+		break;
+	default:
+		c->bandwidth_hz = 8000000;
+		/* fall though */
+	case 8000000:
+		zl10353_single_write(fe, MCLK_RATIO, 0x75);
+		zl10353_single_write(fe, 0x64, 0x36);
+		zl10353_single_write(fe, 0xcc, 0x73);
+	}
+
+	zl10353_calc_nominal_rate(fe, c->bandwidth_hz, &nominal_rate);
+	zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate));
+	zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate));
+	state->bandwidth = c->bandwidth_hz;
+
+	zl10353_calc_input_freq(fe, &input_freq);
+	zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq));
+	zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq));
+
+	/* Hint at TPS settings */
+	switch (c->code_rate_HP) {
+	case FEC_2_3:
+		tps |= (1 << 7);
+		break;
+	case FEC_3_4:
+		tps |= (2 << 7);
+		break;
+	case FEC_5_6:
+		tps |= (3 << 7);
+		break;
+	case FEC_7_8:
+		tps |= (4 << 7);
+		break;
+	case FEC_1_2:
+	case FEC_AUTO:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (c->code_rate_LP) {
+	case FEC_2_3:
+		tps |= (1 << 4);
+		break;
+	case FEC_3_4:
+		tps |= (2 << 4);
+		break;
+	case FEC_5_6:
+		tps |= (3 << 4);
+		break;
+	case FEC_7_8:
+		tps |= (4 << 4);
+		break;
+	case FEC_1_2:
+	case FEC_AUTO:
+		break;
+	case FEC_NONE:
+		if (c->hierarchy == HIERARCHY_AUTO ||
+		    c->hierarchy == HIERARCHY_NONE)
+			break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (c->modulation) {
+	case QPSK:
+		break;
+	case QAM_AUTO:
+	case QAM_16:
+		tps |= (1 << 13);
+		break;
+	case QAM_64:
+		tps |= (2 << 13);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (c->transmission_mode) {
+	case TRANSMISSION_MODE_2K:
+	case TRANSMISSION_MODE_AUTO:
+		break;
+	case TRANSMISSION_MODE_8K:
+		tps |= (1 << 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (c->guard_interval) {
+	case GUARD_INTERVAL_1_32:
+	case GUARD_INTERVAL_AUTO:
+		break;
+	case GUARD_INTERVAL_1_16:
+		tps |= (1 << 2);
+		break;
+	case GUARD_INTERVAL_1_8:
+		tps |= (2 << 2);
+		break;
+	case GUARD_INTERVAL_1_4:
+		tps |= (3 << 2);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (c->hierarchy) {
+	case HIERARCHY_AUTO:
+	case HIERARCHY_NONE:
+		break;
+	case HIERARCHY_1:
+		tps |= (1 << 10);
+		break;
+	case HIERARCHY_2:
+		tps |= (2 << 10);
+		break;
+	case HIERARCHY_4:
+		tps |= (3 << 10);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	zl10353_single_write(fe, TPS_GIVEN_1, msb(tps));
+	zl10353_single_write(fe, TPS_GIVEN_0, lsb(tps));
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	/*
+	 * If there is no tuner attached to the secondary I2C bus, we call
+	 * set_params to program a potential tuner attached somewhere else.
+	 * Otherwise, we update the PLL registers via calc_regs.
+	 */
+	if (state->config.no_tuner) {
+		if (fe->ops.tuner_ops.set_params) {
+			fe->ops.tuner_ops.set_params(fe);
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+	} else if (fe->ops.tuner_ops.calc_regs) {
+		fe->ops.tuner_ops.calc_regs(fe, pllbuf + 1, 5);
+		pllbuf[1] <<= 1;
+		zl10353_write(fe, pllbuf, sizeof(pllbuf));
+	}
+
+	zl10353_single_write(fe, 0x5F, 0x13);
+
+	/* If no attached tuner or invalid PLL registers, just start the FSM. */
+	if (state->config.no_tuner || fe->ops.tuner_ops.calc_regs == NULL)
+		zl10353_single_write(fe, FSM_GO, 0x01);
+	else
+		zl10353_single_write(fe, TUNER_GO, 0x01);
+
+	return 0;
+}
+
+static int zl10353_get_parameters(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct zl10353_state *state = fe->demodulator_priv;
+	int s6, s9;
+	u16 tps;
+	static const u8 tps_fec_to_api[8] = {
+		FEC_1_2,
+		FEC_2_3,
+		FEC_3_4,
+		FEC_5_6,
+		FEC_7_8,
+		FEC_AUTO,
+		FEC_AUTO,
+		FEC_AUTO
+	};
+
+	s6 = zl10353_read_register(state, STATUS_6);
+	s9 = zl10353_read_register(state, STATUS_9);
+	if (s6 < 0 || s9 < 0)
+		return -EREMOTEIO;
+	if ((s6 & (1 << 5)) == 0 || (s9 & (1 << 4)) == 0)
+		return -EINVAL;	/* no FE or TPS lock */
+
+	tps = zl10353_read_register(state, TPS_RECEIVED_1) << 8 |
+	      zl10353_read_register(state, TPS_RECEIVED_0);
+
+	c->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7];
+	c->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7];
+
+	switch ((tps >> 13) & 3) {
+	case 0:
+		c->modulation = QPSK;
+		break;
+	case 1:
+		c->modulation = QAM_16;
+		break;
+	case 2:
+		c->modulation = QAM_64;
+		break;
+	default:
+		c->modulation = QAM_AUTO;
+		break;
+	}
+
+	c->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K :
+					       TRANSMISSION_MODE_2K;
+
+	switch ((tps >> 2) & 3) {
+	case 0:
+		c->guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		c->guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		c->guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		c->guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	default:
+		c->guard_interval = GUARD_INTERVAL_AUTO;
+		break;
+	}
+
+	switch ((tps >> 10) & 7) {
+	case 0:
+		c->hierarchy = HIERARCHY_NONE;
+		break;
+	case 1:
+		c->hierarchy = HIERARCHY_1;
+		break;
+	case 2:
+		c->hierarchy = HIERARCHY_2;
+		break;
+	case 3:
+		c->hierarchy = HIERARCHY_4;
+		break;
+	default:
+		c->hierarchy = HIERARCHY_AUTO;
+		break;
+	}
+
+	c->frequency = state->frequency;
+	c->bandwidth_hz = state->bandwidth;
+	c->inversion = INVERSION_AUTO;
+
+	return 0;
+}
+
+static int zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	int s6, s7, s8;
+
+	if ((s6 = zl10353_read_register(state, STATUS_6)) < 0)
+		return -EREMOTEIO;
+	if ((s7 = zl10353_read_register(state, STATUS_7)) < 0)
+		return -EREMOTEIO;
+	if ((s8 = zl10353_read_register(state, STATUS_8)) < 0)
+		return -EREMOTEIO;
+
+	*status = 0;
+	if (s6 & (1 << 2))
+		*status |= FE_HAS_CARRIER;
+	if (s6 & (1 << 1))
+		*status |= FE_HAS_VITERBI;
+	if (s6 & (1 << 5))
+		*status |= FE_HAS_LOCK;
+	if (s7 & (1 << 4))
+		*status |= FE_HAS_SYNC;
+	if (s8 & (1 << 6))
+		*status |= FE_HAS_SIGNAL;
+
+	if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
+	    (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
+		*status &= ~FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int zl10353_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+
+	*ber = zl10353_read_register(state, RS_ERR_CNT_2) << 16 |
+	       zl10353_read_register(state, RS_ERR_CNT_1) << 8 |
+	       zl10353_read_register(state, RS_ERR_CNT_0);
+
+	return 0;
+}
+
+static int zl10353_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+
+	u16 signal = zl10353_read_register(state, AGC_GAIN_1) << 10 |
+		     zl10353_read_register(state, AGC_GAIN_0) << 2 | 3;
+
+	*strength = ~signal;
+
+	return 0;
+}
+
+static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	u8 _snr;
+
+	if (debug_regs)
+		zl10353_dump_regs(fe);
+
+	_snr = zl10353_read_register(state, SNR);
+	*snr = 10 * _snr / 8;
+
+	return 0;
+}
+
+static int zl10353_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+       u32 ubl = 0;
+
+       ubl = zl10353_read_register(state, RS_UBC_1) << 8 |
+	     zl10353_read_register(state, RS_UBC_0);
+
+       state->ucblocks += ubl;
+       *ucblocks = state->ucblocks;
+
+	return 0;
+}
+
+static int zl10353_get_tune_settings(struct dvb_frontend *fe,
+				     struct dvb_frontend_tune_settings
+					 *fe_tune_settings)
+{
+	fe_tune_settings->min_delay_ms = 1000;
+	fe_tune_settings->step_size = 0;
+	fe_tune_settings->max_drift = 0;
+
+	return 0;
+}
+
+static int zl10353_init(struct dvb_frontend *fe)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	u8 zl10353_reset_attach[6] = { 0x50, 0x03, 0x64, 0x46, 0x15, 0x0F };
+
+	if (debug_regs)
+		zl10353_dump_regs(fe);
+	if (state->config.parallel_ts)
+		zl10353_reset_attach[2] &= ~0x20;
+	if (state->config.clock_ctl_1)
+		zl10353_reset_attach[3] = state->config.clock_ctl_1;
+	if (state->config.pll_0)
+		zl10353_reset_attach[4] = state->config.pll_0;
+
+	/* Do a "hard" reset if not already done */
+	if (zl10353_read_register(state, 0x50) != zl10353_reset_attach[1] ||
+	    zl10353_read_register(state, 0x51) != zl10353_reset_attach[2]) {
+		zl10353_write(fe, zl10353_reset_attach,
+				   sizeof(zl10353_reset_attach));
+		if (debug_regs)
+			zl10353_dump_regs(fe);
+	}
+
+	return 0;
+}
+
+static int zl10353_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	u8 val = 0x0a;
+
+	if (state->config.disable_i2c_gate_ctrl) {
+		/* No tuner attached to the internal I2C bus */
+		/* If set enable I2C bridge, the main I2C bus stopped hardly */
+		return 0;
+	}
+
+	if (enable)
+		val |= 0x10;
+
+	return zl10353_single_write(fe, 0x62, val);
+}
+
+static void zl10353_release(struct dvb_frontend *fe)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops zl10353_ops;
+
+struct dvb_frontend *zl10353_attach(const struct zl10353_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct zl10353_state *state = NULL;
+	int id;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct zl10353_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->i2c = i2c;
+	memcpy(&state->config, config, sizeof(struct zl10353_config));
+
+	/* check if the demod is there */
+	id = zl10353_read_register(state, CHIP_ID);
+	if ((id != ID_ZL10353) && (id != ID_CE6230) && (id != ID_CE6231))
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &zl10353_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	return &state->frontend;
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops zl10353_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name			= "Zarlink ZL10353 DVB-T",
+		.frequency_min		= 174000000,
+		.frequency_max		= 862000000,
+		.frequency_stepsize	= 166667,
+		.frequency_tolerance	= 0,
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+			FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER |
+			FE_CAN_MUTE_TS
+	},
+
+	.release = zl10353_release,
+
+	.init = zl10353_init,
+	.sleep = zl10353_sleep,
+	.i2c_gate_ctrl = zl10353_i2c_gate_ctrl,
+	.write = zl10353_write,
+
+	.set_frontend = zl10353_set_parameters,
+	.get_frontend = zl10353_get_parameters,
+	.get_tune_settings = zl10353_get_tune_settings,
+
+	.read_status = zl10353_read_status,
+	.read_ber = zl10353_read_ber,
+	.read_signal_strength = zl10353_read_signal_strength,
+	.read_snr = zl10353_read_snr,
+	.read_ucblocks = zl10353_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+module_param(debug_regs, int, 0644);
+MODULE_PARM_DESC(debug_regs, "Turn on/off frontend register dumps (default:off).");
+
+MODULE_DESCRIPTION("Zarlink ZL10353 DVB-T demodulator driver");
+MODULE_AUTHOR("Chris Pascoe");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(zl10353_attach);
diff --git a/drivers/media/dvb-frontends/zl10353.h b/drivers/media/dvb-frontends/zl10353.h
new file mode 100644
index 0000000..6e3ca9e
--- /dev/null
+++ b/drivers/media/dvb-frontends/zl10353.h
@@ -0,0 +1,62 @@
+/*
+ *  Driver for Zarlink DVB-T ZL10353 demodulator
+ *
+ *  Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef ZL10353_H
+#define ZL10353_H
+
+#include <linux/dvb/frontend.h>
+
+struct zl10353_config
+{
+	/* demodulator's I2C address */
+	u8 demod_address;
+
+	/* frequencies in units of 0.1kHz */
+	int adc_clock;	/* default: 450560 (45.056  MHz) */
+	int if2;	/* default: 361667 (36.1667 MHz) */
+
+	/* set if no pll is connected to the secondary i2c bus */
+	int no_tuner;
+
+	/* set if parallel ts output is required */
+	int parallel_ts;
+
+	/* set if i2c_gate_ctrl disable is required */
+	u8 disable_i2c_gate_ctrl:1;
+
+	/* clock control registers (0x51-0x54) */
+	u8 clock_ctl_1;  /* default: 0x46 */
+	u8 pll_0;        /* default: 0x15 */
+};
+
+#if defined(CONFIG_DVB_ZL10353) || (defined(CONFIG_DVB_ZL10353_MODULE) && defined(MODULE))
+extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
+					   struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
+					   struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_ZL10353 */
+
+#endif /* ZL10353_H */
diff --git a/drivers/media/dvb-frontends/zl10353_priv.h b/drivers/media/dvb-frontends/zl10353_priv.h
new file mode 100644
index 0000000..e0dd1d3
--- /dev/null
+++ b/drivers/media/dvb-frontends/zl10353_priv.h
@@ -0,0 +1,79 @@
+/*
+ *  Driver for Zarlink DVB-T ZL10353 demodulator
+ *
+ *  Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _ZL10353_PRIV_
+#define _ZL10353_PRIV_
+
+#define ID_ZL10353	0x14 /* Zarlink ZL10353 */
+#define ID_CE6230	0x18 /* Intel CE6230 */
+#define ID_CE6231	0x19 /* Intel CE6231 */
+
+#define msb(x) (((x) >> 8) & 0xff)
+#define lsb(x) ((x) & 0xff)
+
+enum zl10353_reg_addr {
+	INTERRUPT_0        = 0x00,
+	INTERRUPT_1        = 0x01,
+	INTERRUPT_2        = 0x02,
+	INTERRUPT_3        = 0x03,
+	INTERRUPT_4        = 0x04,
+	INTERRUPT_5        = 0x05,
+	STATUS_6           = 0x06,
+	STATUS_7           = 0x07,
+	STATUS_8           = 0x08,
+	STATUS_9           = 0x09,
+	AGC_GAIN_1         = 0x0A,
+	AGC_GAIN_0         = 0x0B,
+	SNR                = 0x10,
+	RS_ERR_CNT_2       = 0x11,
+	RS_ERR_CNT_1       = 0x12,
+	RS_ERR_CNT_0       = 0x13,
+	RS_UBC_1           = 0x14,
+	RS_UBC_0           = 0x15,
+	TPS_RECEIVED_1     = 0x1D,
+	TPS_RECEIVED_0     = 0x1E,
+	TPS_CURRENT_1      = 0x1F,
+	TPS_CURRENT_0      = 0x20,
+	CLOCK_CTL_0        = 0x51,
+	CLOCK_CTL_1        = 0x52,
+	PLL_0              = 0x53,
+	PLL_1              = 0x54,
+	RESET              = 0x55,
+	AGC_TARGET         = 0x56,
+	MCLK_RATIO         = 0x5C,
+	ACQ_CTL            = 0x5E,
+	TRL_NOMINAL_RATE_1 = 0x65,
+	TRL_NOMINAL_RATE_0 = 0x66,
+	INPUT_FREQ_1       = 0x6C,
+	INPUT_FREQ_0       = 0x6D,
+	TPS_GIVEN_1        = 0x6E,
+	TPS_GIVEN_0        = 0x6F,
+	TUNER_GO           = 0x70,
+	FSM_GO             = 0x71,
+	CHIP_ID            = 0x7F,
+	CHAN_STEP_1        = 0xE4,
+	CHAN_STEP_0        = 0xE5,
+	OFDM_LOCK_TIME     = 0xE7,
+	FEC_LOCK_TIME      = 0xE8,
+	ACQ_DELAY          = 0xE9,
+};
+
+#endif                          /* _ZL10353_PRIV_ */
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
deleted file mode 100644
index f6e40b3..0000000
--- a/drivers/media/dvb/Kconfig
+++ /dev/null
@@ -1,91 +0,0 @@
-#
-# DVB device configuration
-#
-
-config DVB_MAX_ADAPTERS
-	int "maximum number of DVB/ATSC adapters"
-	depends on DVB_CORE
-	default 8
-	range 1 255
-	help
-	  Maximum number of DVB/ATSC adapters. Increasing this number
-	  increases the memory consumption of the DVB subsystem even
-	  if a much lower number of DVB/ATSC adapters is present.
-	  Only values in the range 4-32 are tested.
-
-	  If you are unsure about this, use the default value 8
-
-config DVB_DYNAMIC_MINORS
-	bool "Dynamic DVB minor allocation"
-	depends on DVB_CORE
-	default n
-	help
-	  If you say Y here, the DVB subsystem will use dynamic minor
-	  allocation for any device that uses the DVB major number.
-	  This means that you can have more than 4 of a single type
-	  of device (like demuxes and frontends) per adapter, but udev
-	  will be required to manage the device nodes.
-
-	  If you are unsure about this, say N here.
-
-menuconfig DVB_CAPTURE_DRIVERS
-	bool "DVB/ATSC adapters"
-	depends on DVB_CORE
-	default y
-	---help---
-	  Say Y to select Digital TV adapters
-
-if DVB_CAPTURE_DRIVERS && DVB_CORE
-
-comment "Supported SAA7146 based PCI Adapters"
-	depends on DVB_CORE && PCI && I2C
-source "drivers/media/dvb/ttpci/Kconfig"
-
-comment "Supported USB Adapters"
-	depends on DVB_CORE && USB && I2C
-source "drivers/media/dvb/dvb-usb/Kconfig"
-source "drivers/media/dvb/ttusb-budget/Kconfig"
-source "drivers/media/dvb/ttusb-dec/Kconfig"
-source "drivers/media/dvb/siano/Kconfig"
-
-comment "Supported FlexCopII (B2C2) Adapters"
-	depends on DVB_CORE && (PCI || USB) && I2C
-source "drivers/media/dvb/b2c2/Kconfig"
-
-comment "Supported BT878 Adapters"
-	depends on DVB_CORE && PCI && I2C
-source "drivers/media/dvb/bt8xx/Kconfig"
-
-comment "Supported Pluto2 Adapters"
-	depends on DVB_CORE && PCI && I2C
-source "drivers/media/dvb/pluto2/Kconfig"
-
-comment "Supported SDMC DM1105 Adapters"
-	depends on DVB_CORE && PCI && I2C
-source "drivers/media/dvb/dm1105/Kconfig"
-
-comment "Supported FireWire (IEEE 1394) Adapters"
-	depends on DVB_CORE && FIREWIRE
-source "drivers/media/dvb/firewire/Kconfig"
-
-comment "Supported Earthsoft PT1 Adapters"
-	depends on DVB_CORE && PCI && I2C
-source "drivers/media/dvb/pt1/Kconfig"
-
-comment "Supported Mantis Adapters"
-	depends on DVB_CORE && PCI && I2C
-	source "drivers/media/dvb/mantis/Kconfig"
-
-comment "Supported nGene Adapters"
-	depends on DVB_CORE && PCI && I2C
-	source "drivers/media/dvb/ngene/Kconfig"
-
-comment "Supported ddbridge ('Octopus') Adapters"
-	depends on DVB_CORE && PCI && I2C
-	source "drivers/media/dvb/ddbridge/Kconfig"
-
-comment "Supported DVB Frontends"
-	depends on DVB_CORE
-source "drivers/media/dvb/frontends/Kconfig"
-
-endif # DVB_CAPTURE_DRIVERS
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile
deleted file mode 100644
index b2cefe6..0000000
--- a/drivers/media/dvb/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# Makefile for the kernel multimedia device drivers.
-#
-
-obj-y        := dvb-core/	\
-		frontends/	\
-		ttpci/		\
-		ttusb-dec/	\
-		ttusb-budget/	\
-		b2c2/		\
-		bt8xx/		\
-		dvb-usb/	\
-		pluto2/		\
-		siano/		\
-		dm1105/		\
-		pt1/		\
-		mantis/		\
-		ngene/		\
-		ddbridge/
-
-obj-$(CONFIG_DVB_FIREDTV)	+= firewire/
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
deleted file mode 100644
index 9e57814..0000000
--- a/drivers/media/dvb/b2c2/Kconfig
+++ /dev/null
@@ -1,45 +0,0 @@
-config DVB_B2C2_FLEXCOP
-	tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
-	depends on DVB_CORE && I2C
-	select DVB_PLL if !DVB_FE_CUSTOMISE
-	select DVB_STV0299 if !DVB_FE_CUSTOMISE
-	select DVB_MT352 if !DVB_FE_CUSTOMISE
-	select DVB_MT312 if !DVB_FE_CUSTOMISE
-	select DVB_NXT200X if !DVB_FE_CUSTOMISE
-	select DVB_STV0297 if !DVB_FE_CUSTOMISE
-	select DVB_BCM3510 if !DVB_FE_CUSTOMISE
-	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
-	select DVB_S5H1420 if !DVB_FE_CUSTOMISE
-	select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE
-	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
-	select DVB_CX24123 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
-	select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE
-	help
-	  Support for the digital TV receiver chip made by B2C2 Inc. included in
-	  Technisats PCI cards and USB boxes.
-
-	  Say Y if you own such a device and want to use it.
-
-config DVB_B2C2_FLEXCOP_PCI
-	tristate "Technisat/B2C2 Air/Sky/Cable2PC PCI"
-	depends on DVB_B2C2_FLEXCOP && PCI && I2C
-	help
-	  Support for the Air/Sky/CableStar2 PCI card (DVB/ATSC) by Technisat/B2C2.
-
-	  Say Y if you own such a device and want to use it.
-
-config DVB_B2C2_FLEXCOP_USB
-	tristate "Technisat/B2C2 Air/Sky/Cable2PC USB"
-	depends on DVB_B2C2_FLEXCOP && USB && I2C
-	help
-	  Support for the Air/Sky/Cable2PC USB1.1 box (DVB/ATSC) by Technisat/B2C2,
-
-	  Say Y if you own such a device and want to use it.
-
-config DVB_B2C2_FLEXCOP_DEBUG
-	bool "Enable debug for the B2C2 FlexCop drivers"
-	depends on DVB_B2C2_FLEXCOP
-	help
-	  Say Y if you want to enable the module option to control debug messages
-	  of all B2C2 FlexCop drivers.
diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile
deleted file mode 100644
index 3d04a8d..0000000
--- a/drivers/media/dvb/b2c2/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-b2c2-flexcop-objs = flexcop.o flexcop-fe-tuner.o flexcop-i2c.o \
-	flexcop-sram.o flexcop-eeprom.o flexcop-misc.o flexcop-hw-filter.o
-obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o
-
-ifneq ($(CONFIG_DVB_B2C2_FLEXCOP_PCI),)
-b2c2-flexcop-objs += flexcop-dma.o
-endif
-
-b2c2-flexcop-pci-objs = flexcop-pci.o
-obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o
-
-b2c2-flexcop-usb-objs = flexcop-usb.o
-obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
-ccflags-y += -Idrivers/media/common/tuners/
diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h
deleted file mode 100644
index 437912e..0000000
--- a/drivers/media/dvb/b2c2/flexcop-common.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- * flexcop-common.h - common header file for device-specific source files
- * see flexcop.c for copyright information
- */
-#ifndef __FLEXCOP_COMMON_H__
-#define __FLEXCOP_COMMON_H__
-
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/mutex.h>
-
-#include "flexcop-reg.h"
-
-#include "dmxdev.h"
-#include "dvb_demux.h"
-#include "dvb_filter.h"
-#include "dvb_net.h"
-#include "dvb_frontend.h"
-
-#define FC_MAX_FEED 256
-
-#ifndef FC_LOG_PREFIX
-#warning please define a log prefix for your file, using a default one
-#define FC_LOG_PREFIX "b2c2-undef"
-#endif
-
-/* Steal from usb.h */
-#undef err
-#define err(format, arg...) \
-	printk(KERN_ERR FC_LOG_PREFIX ": " format "\n" , ## arg)
-#undef info
-#define info(format, arg...) \
-	printk(KERN_INFO FC_LOG_PREFIX ": " format "\n" , ## arg)
-#undef warn
-#define warn(format, arg...) \
-	printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg)
-
-struct flexcop_dma {
-	struct pci_dev *pdev;
-
-	u8 *cpu_addr0;
-	dma_addr_t dma_addr0;
-	u8 *cpu_addr1;
-	dma_addr_t dma_addr1;
-	u32 size; /* size of each address in bytes */
-};
-
-struct flexcop_i2c_adapter {
-	struct flexcop_device *fc;
-	struct i2c_adapter i2c_adap;
-
-	u8 no_base_addr;
-	flexcop_i2c_port_t port;
-};
-
-/* Control structure for data definitions that are common to
- * the B2C2-based PCI and USB devices.
- */
-struct flexcop_device {
-	/* general */
-	struct device *dev; /* for firmware_class */
-
-#define FC_STATE_DVB_INIT 0x01
-#define FC_STATE_I2C_INIT 0x02
-#define FC_STATE_FE_INIT  0x04
-	int init_state;
-
-	/* device information */
-	int has_32_hw_pid_filter;
-	flexcop_revision_t rev;
-	flexcop_device_type_t dev_type;
-	flexcop_bus_t bus_type;
-
-	/* dvb stuff */
-	struct dvb_adapter dvb_adapter;
-	struct dvb_frontend *fe;
-	struct dvb_net dvbnet;
-	struct dvb_demux demux;
-	struct dmxdev dmxdev;
-	struct dmx_frontend hw_frontend;
-	struct dmx_frontend mem_frontend;
-	int (*fe_sleep) (struct dvb_frontend *);
-
-	struct flexcop_i2c_adapter fc_i2c_adap[3];
-	struct mutex i2c_mutex;
-	struct module *owner;
-
-	/* options and status */
-	int extra_feedcount;
-	int feedcount;
-	int pid_filtering;
-	int fullts_streaming_state;
-
-	/* bus specific callbacks */
-	flexcop_ibi_value(*read_ibi_reg) (struct flexcop_device *,
-			flexcop_ibi_register);
-	int (*write_ibi_reg) (struct flexcop_device *,
-			flexcop_ibi_register, flexcop_ibi_value);
-	int (*i2c_request) (struct flexcop_i2c_adapter *,
-		flexcop_access_op_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
-	int (*stream_control) (struct flexcop_device *, int);
-	int (*get_mac_addr) (struct flexcop_device *fc, int extended);
-	void *bus_specific;
-};
-
-/* exported prototypes */
-
-/* from flexcop.c */
-void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len);
-void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no);
-
-struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len);
-void flexcop_device_kfree(struct flexcop_device *);
-
-int flexcop_device_initialize(struct flexcop_device *);
-void flexcop_device_exit(struct flexcop_device *fc);
-void flexcop_reset_block_300(struct flexcop_device *fc);
-
-/* from flexcop-dma.c */
-int flexcop_dma_allocate(struct pci_dev *pdev,
-		struct flexcop_dma *dma, u32 size);
-void flexcop_dma_free(struct flexcop_dma *dma);
-
-int flexcop_dma_control_timer_irq(struct flexcop_device *fc,
-		flexcop_dma_index_t no, int onoff);
-int flexcop_dma_control_size_irq(struct flexcop_device *fc,
-		flexcop_dma_index_t no, int onoff);
-int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma,
-		flexcop_dma_index_t dma_idx);
-int flexcop_dma_xfer_control(struct flexcop_device *fc,
-		flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index,
-		int onoff);
-int flexcop_dma_config_timer(struct flexcop_device *fc,
-		flexcop_dma_index_t dma_idx, u8 cycles);
-
-/* from flexcop-eeprom.c */
-/* the PCI part uses this call to get the MAC address, the USB part has its own */
-int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended);
-
-/* from flexcop-i2c.c */
-/* the PCI part uses this a i2c_request callback, whereas the usb part has its own
- * one. We have it in flexcop-i2c.c, because it is going via the actual
- * I2C-channel of the flexcop.
- */
-int flexcop_i2c_request(struct flexcop_i2c_adapter*, flexcop_access_op_t,
-	u8 chipaddr, u8 addr, u8 *buf, u16 len);
-
-/* from flexcop-sram.c */
-int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest,
-	flexcop_sram_dest_target_t target);
-void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s);
-void flexcop_sram_ctrl(struct flexcop_device *fc,
-		int usb_wan, int sramdma, int maximumfill);
-
-/* global prototypes for the flexcop-chip */
-/* from flexcop-fe-tuner.c */
-int flexcop_frontend_init(struct flexcop_device *fc);
-void flexcop_frontend_exit(struct flexcop_device *fc);
-
-/* from flexcop-i2c.c */
-int flexcop_i2c_init(struct flexcop_device *fc);
-void flexcop_i2c_exit(struct flexcop_device *fc);
-
-/* from flexcop-sram.c */
-int flexcop_sram_init(struct flexcop_device *fc);
-
-/* from flexcop-misc.c */
-void flexcop_determine_revision(struct flexcop_device *fc);
-void flexcop_device_name(struct flexcop_device *fc,
-		const char *prefix, const char *suffix);
-void flexcop_dump_reg(struct flexcop_device *fc,
-		flexcop_ibi_register reg, int num);
-
-/* from flexcop-hw-filter.c */
-int flexcop_pid_feed_control(struct flexcop_device *fc,
-		struct dvb_demux_feed *dvbdmxfeed, int onoff);
-void flexcop_hw_filter_init(struct flexcop_device *fc);
-
-void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff);
-
-void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]);
-void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff);
-
-#endif
diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c
deleted file mode 100644
index 2881e0d..0000000
--- a/drivers/media/dvb/b2c2/flexcop-dma.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- * flexcop-dma.c - configuring and controlling the DMA of the FlexCop
- * see flexcop.c for copyright information
- */
-#include "flexcop.h"
-
-int flexcop_dma_allocate(struct pci_dev *pdev,
-		struct flexcop_dma *dma, u32 size)
-{
-	u8 *tcpu;
-	dma_addr_t tdma = 0;
-
-	if (size % 2) {
-		err("dma buffersize has to be even.");
-		return -EINVAL;
-	}
-
-	if ((tcpu = pci_alloc_consistent(pdev, size, &tdma)) != NULL) {
-		dma->pdev = pdev;
-		dma->cpu_addr0 = tcpu;
-		dma->dma_addr0 = tdma;
-		dma->cpu_addr1 = tcpu + size/2;
-		dma->dma_addr1 = tdma + size/2;
-		dma->size = size/2;
-		return 0;
-	}
-	return -ENOMEM;
-}
-EXPORT_SYMBOL(flexcop_dma_allocate);
-
-void flexcop_dma_free(struct flexcop_dma *dma)
-{
-	pci_free_consistent(dma->pdev, dma->size*2,
-			dma->cpu_addr0, dma->dma_addr0);
-	memset(dma,0,sizeof(struct flexcop_dma));
-}
-EXPORT_SYMBOL(flexcop_dma_free);
-
-int flexcop_dma_config(struct flexcop_device *fc,
-		struct flexcop_dma *dma,
-		flexcop_dma_index_t dma_idx)
-{
-	flexcop_ibi_value v0x0,v0x4,v0xc;
-	v0x0.raw = v0x4.raw = v0xc.raw = 0;
-
-	v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2;
-	v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2;
-	v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;
-
-	if ((dma_idx & FC_DMA_1) == dma_idx) {
-		fc->write_ibi_reg(fc,dma1_000,v0x0);
-		fc->write_ibi_reg(fc,dma1_004,v0x4);
-		fc->write_ibi_reg(fc,dma1_00c,v0xc);
-	} else if ((dma_idx & FC_DMA_2) == dma_idx) {
-		fc->write_ibi_reg(fc,dma2_010,v0x0);
-		fc->write_ibi_reg(fc,dma2_014,v0x4);
-		fc->write_ibi_reg(fc,dma2_01c,v0xc);
-	} else {
-		err("either DMA1 or DMA2 can be configured within one "
-			"flexcop_dma_config call.");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(flexcop_dma_config);
-
-/* start the DMA transfers, but not the DMA IRQs */
-int flexcop_dma_xfer_control(struct flexcop_device *fc,
-		flexcop_dma_index_t dma_idx,
-		flexcop_dma_addr_index_t index,
-		int onoff)
-{
-	flexcop_ibi_value v0x0,v0xc;
-	flexcop_ibi_register r0x0,r0xc;
-
-	if ((dma_idx & FC_DMA_1) == dma_idx) {
-		r0x0 = dma1_000;
-		r0xc = dma1_00c;
-	} else if ((dma_idx & FC_DMA_2) == dma_idx) {
-		r0x0 = dma2_010;
-		r0xc = dma2_01c;
-	} else {
-		err("either transfer DMA1 or DMA2 can be started within one "
-			"flexcop_dma_xfer_control call.");
-		return -EINVAL;
-	}
-
-	v0x0 = fc->read_ibi_reg(fc,r0x0);
-	v0xc = fc->read_ibi_reg(fc,r0xc);
-
-	deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
-	deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);
-
-	if (index & FC_DMA_SUBADDR_0)
-		v0x0.dma_0x0.dma_0start = onoff;
-
-	if (index & FC_DMA_SUBADDR_1)
-		v0xc.dma_0xc.dma_1start = onoff;
-
-	fc->write_ibi_reg(fc,r0x0,v0x0);
-	fc->write_ibi_reg(fc,r0xc,v0xc);
-
-	deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
-	deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);
-	return 0;
-}
-EXPORT_SYMBOL(flexcop_dma_xfer_control);
-
-static int flexcop_dma_remap(struct flexcop_device *fc,
-		flexcop_dma_index_t dma_idx,
-		int onoff)
-{
-	flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c;
-	flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
-	deb_info("%s\n",__func__);
-	v.dma_0xc.remap_enable = onoff;
-	fc->write_ibi_reg(fc,r,v);
-	return 0;
-}
-
-int flexcop_dma_control_size_irq(struct flexcop_device *fc,
-		flexcop_dma_index_t no,
-		int onoff)
-{
-	flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
-
-	if (no & FC_DMA_1)
-		v.ctrl_208.DMA1_IRQ_Enable_sig = onoff;
-
-	if (no & FC_DMA_2)
-		v.ctrl_208.DMA2_IRQ_Enable_sig = onoff;
-
-	fc->write_ibi_reg(fc,ctrl_208,v);
-	return 0;
-}
-EXPORT_SYMBOL(flexcop_dma_control_size_irq);
-
-int flexcop_dma_control_timer_irq(struct flexcop_device *fc,
-		flexcop_dma_index_t no,
-		int onoff)
-{
-	flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
-
-	if (no & FC_DMA_1)
-		v.ctrl_208.DMA1_Timer_Enable_sig = onoff;
-
-	if (no & FC_DMA_2)
-		v.ctrl_208.DMA2_Timer_Enable_sig = onoff;
-
-	fc->write_ibi_reg(fc,ctrl_208,v);
-	return 0;
-}
-EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
-
-/* 1 cycles = 1.97 msec */
-int flexcop_dma_config_timer(struct flexcop_device *fc,
-		flexcop_dma_index_t dma_idx, u8 cycles)
-{
-	flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
-	flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
-
-	flexcop_dma_remap(fc,dma_idx,0);
-
-	deb_info("%s\n",__func__);
-	v.dma_0x4_write.dmatimer = cycles;
-	fc->write_ibi_reg(fc,r,v);
-	return 0;
-}
-EXPORT_SYMBOL(flexcop_dma_config_timer);
-
diff --git a/drivers/media/dvb/b2c2/flexcop-eeprom.c b/drivers/media/dvb/b2c2/flexcop-eeprom.c
deleted file mode 100644
index a25373a..0000000
--- a/drivers/media/dvb/b2c2/flexcop-eeprom.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading)
- * see flexcop.c for copyright information
- */
-#include "flexcop.h"
-
-#if 0
-/*EEPROM (Skystar2 has one "24LC08B" chip on board) */
-static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len)
-{
-	return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len);
-}
-
-static int eeprom_lrc_write(struct adapter *adapter, u32 addr,
-		u32 len, u8 *wbuf, u8 *rbuf, int retries)
-{
-int i;
-
-for (i = 0; i < retries; i++) {
-	if (eeprom_write(adapter, addr, wbuf, len) == len) {
-		if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1)
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/* These functions could be used to unlock SkyStar2 cards. */
-
-static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len)
-{
-	u8 rbuf[20];
-	u8 wbuf[20];
-
-	if (len != 16)
-		return 0;
-
-	memcpy(wbuf, key, len);
-	wbuf[16] = 0;
-	wbuf[17] = 0;
-	wbuf[18] = 0;
-	wbuf[19] = calc_lrc(wbuf, 19);
-	return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4);
-}
-
-static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len)
-{
-	u8 buf[20];
-
-	if (len != 16)
-		return 0;
-
-	if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0)
-		return 0;
-
-	memcpy(key, buf, len);
-	return 1;
-}
-
-static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac)
-{
-	u8 tmp[8];
-
-	if (type != 0) {
-		tmp[0] = mac[0];
-		tmp[1] = mac[1];
-		tmp[2] = mac[2];
-		tmp[3] = mac[5];
-		tmp[4] = mac[6];
-		tmp[5] = mac[7];
-	} else {
-		tmp[0] = mac[0];
-		tmp[1] = mac[1];
-		tmp[2] = mac[2];
-		tmp[3] = mac[3];
-		tmp[4] = mac[4];
-		tmp[5] = mac[5];
-	}
-
-	tmp[6] = 0;
-	tmp[7] = calc_lrc(tmp, 7);
-
-	if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8)
-		return 1;
-	return 0;
-}
-
-static int flexcop_eeprom_read(struct flexcop_device *fc,
-		u16 addr, u8 *buf, u16 len)
-{
-	return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len);
-}
-
-#endif
-
-static u8 calc_lrc(u8 *buf, int len)
-{
-	int i;
-	u8 sum = 0;
-	for (i = 0; i < len; i++)
-		sum = sum ^ buf[i];
-	return sum;
-}
-
-static int flexcop_eeprom_request(struct flexcop_device *fc,
-	flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries)
-{
-	int i,ret = 0;
-	u8 chipaddr =  0x50 | ((addr >> 8) & 3);
-	for (i = 0; i < retries; i++) {
-		ret = fc->i2c_request(&fc->fc_i2c_adap[1], op, chipaddr,
-			addr & 0xff, buf, len);
-		if (ret == 0)
-			break;
-	}
-	return ret;
-}
-
-static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr,
-		u8 *buf, u16 len, int retries)
-{
-	int ret = flexcop_eeprom_request(fc, FC_READ, addr, buf, len, retries);
-	if (ret == 0)
-		if (calc_lrc(buf, len - 1) != buf[len - 1])
-			ret = -EINVAL;
-	return ret;
-}
-
-/* JJ's comment about extended == 1: it is not presently used anywhere but was
- * added to the low-level functions for possible support of EUI64 */
-int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended)
-{
-	u8 buf[8];
-	int ret = 0;
-
-	if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) {
-		if (extended != 0) {
-			err("TODO: extended (EUI64) MAC addresses aren't "
-				"completely supported yet");
-			ret = -EINVAL;
-		} else
-			memcpy(fc->dvb_adapter.proposed_mac,buf,6);
-	}
-	return ret;
-}
-EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr);
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
deleted file mode 100644
index 850a6c6..0000000
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ /dev/null
@@ -1,678 +0,0 @@
-/*
- * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- * flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling
- * see flexcop.c for copyright information
- */
-#include <media/tuner.h>
-#include "flexcop.h"
-#include "mt312.h"
-#include "stv0299.h"
-#include "s5h1420.h"
-#include "itd1000.h"
-#include "cx24113.h"
-#include "cx24123.h"
-#include "isl6421.h"
-#include "mt352.h"
-#include "bcm3510.h"
-#include "nxt200x.h"
-#include "dvb-pll.h"
-#include "lgdt330x.h"
-#include "tuner-simple.h"
-#include "stv0297.h"
-
-
-/* Can we use the specified front-end?  Remember that if we are compiled
- * into the kernel we can't call code that's in modules.  */
-#define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \
-	(defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE)))
-
-/* lnb control */
-#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)
-static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
-	struct flexcop_device *fc = fe->dvb->priv;
-	flexcop_ibi_value v;
-	deb_tuner("polarity/voltage = %u\n", voltage);
-
-	v = fc->read_ibi_reg(fc, misc_204);
-	switch (voltage) {
-	case SEC_VOLTAGE_OFF:
-		v.misc_204.ACPI1_sig = 1;
-		break;
-	case SEC_VOLTAGE_13:
-		v.misc_204.ACPI1_sig = 0;
-		v.misc_204.LNB_L_H_sig = 0;
-		break;
-	case SEC_VOLTAGE_18:
-		v.misc_204.ACPI1_sig = 0;
-		v.misc_204.LNB_L_H_sig = 1;
-		break;
-	default:
-		err("unknown SEC_VOLTAGE value");
-		return -EINVAL;
-	}
-	return fc->write_ibi_reg(fc, misc_204, v);
-}
-#endif
-
-#if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312)
-static int flexcop_sleep(struct dvb_frontend* fe)
-{
-	struct flexcop_device *fc = fe->dvb->priv;
-	if (fc->fe_sleep)
-		return fc->fe_sleep(fe);
-	return 0;
-}
-#endif
-
-/* SkyStar2 DVB-S rev 2.3 */
-#if FE_SUPPORTED(MT312) && FE_SUPPORTED(PLL)
-static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
-{
-/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
-	struct flexcop_device *fc = fe->dvb->priv;
-	flexcop_ibi_value v;
-	u16 ax;
-	v.raw = 0;
-	deb_tuner("tone = %u\n",tone);
-
-	switch (tone) {
-	case SEC_TONE_ON:
-		ax = 0x01ff;
-		break;
-	case SEC_TONE_OFF:
-		ax = 0;
-		break;
-	default:
-		err("unknown SEC_TONE value");
-		return -EINVAL;
-	}
-
-	v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
-	v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
-	v.lnb_switch_freq_200.LNB_CTLLowCount_sig  = ax == 0 ? 0x1ff : ax;
-	return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
-}
-
-static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
-{
-	flexcop_set_tone(fe, SEC_TONE_ON);
-	udelay(data ? 500 : 1000);
-	flexcop_set_tone(fe, SEC_TONE_OFF);
-	udelay(data ? 1000 : 500);
-}
-
-static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
-{
-	int i, par = 1, d;
-	for (i = 7; i >= 0; i--) {
-		d = (data >> i) & 1;
-		par ^= d;
-		flexcop_diseqc_send_bit(fe, d);
-	}
-	flexcop_diseqc_send_bit(fe, par);
-}
-
-static int flexcop_send_diseqc_msg(struct dvb_frontend *fe,
-	int len, u8 *msg, unsigned long burst)
-{
-	int i;
-
-	flexcop_set_tone(fe, SEC_TONE_OFF);
-	mdelay(16);
-
-	for (i = 0; i < len; i++)
-		flexcop_diseqc_send_byte(fe,msg[i]);
-	mdelay(16);
-
-	if (burst != -1) {
-		if (burst)
-			flexcop_diseqc_send_byte(fe, 0xff);
-		else {
-			flexcop_set_tone(fe, SEC_TONE_ON);
-			mdelay(12);
-			udelay(500);
-			flexcop_set_tone(fe, SEC_TONE_OFF);
-		}
-		msleep(20);
-	}
-	return 0;
-}
-
-static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe,
-	struct dvb_diseqc_master_cmd *cmd)
-{
-	return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
-}
-
-static int flexcop_diseqc_send_burst(struct dvb_frontend *fe,
-	fe_sec_mini_cmd_t minicmd)
-{
-	return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
-}
-
-static struct mt312_config skystar23_samsung_tbdu18132_config = {
-	.demod_address = 0x0e,
-};
-
-static int skystar2_rev23_attach(struct flexcop_device *fc,
-	struct i2c_adapter *i2c)
-{
-	struct dvb_frontend_ops *ops;
-
-	fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
-	if (!fc->fe)
-		return 0;
-
-	if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
-			DVB_PLL_SAMSUNG_TBDU18132))
-		return 0;
-
-	ops = &fc->fe->ops;
-	ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
-	ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
-	ops->set_tone               = flexcop_set_tone;
-	ops->set_voltage            = flexcop_set_voltage;
-	fc->fe_sleep                = ops->sleep;
-	ops->sleep                  = flexcop_sleep;
-	return 1;
-}
-#else
-#define skystar2_rev23_attach NULL
-#endif
-
-/* SkyStar2 DVB-S rev 2.6 */
-#if FE_SUPPORTED(STV0299) && FE_SUPPORTED(PLL)
-static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
-	u32 srate, u32 ratio)
-{
-	u8 aclk = 0;
-	u8 bclk = 0;
-
-	if (srate < 1500000) {
-		aclk = 0xb7; bclk = 0x47;
-	} else if (srate < 3000000) {
-		aclk = 0xb7; bclk = 0x4b;
-	} else if (srate < 7000000) {
-		aclk = 0xb7; bclk = 0x4f;
-	} else if (srate < 14000000) {
-		aclk = 0xb7; bclk = 0x53;
-	} else if (srate < 30000000) {
-		aclk = 0xb6; bclk = 0x53;
-	} else if (srate < 45000000) {
-		aclk = 0xb4; bclk = 0x51;
-	}
-
-	stv0299_writereg(fe, 0x13, aclk);
-	stv0299_writereg(fe, 0x14, bclk);
-	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
-	stv0299_writereg(fe, 0x20, (ratio >>  8) & 0xff);
-	stv0299_writereg(fe, 0x21,  ratio        & 0xf0);
-	return 0;
-}
-
-static u8 samsung_tbmu24112_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x30,
-	0x03, 0x00,
-	0x04, 0x7D,
-	0x05, 0x35,
-	0x06, 0x02,
-	0x07, 0x00,
-	0x08, 0xC3,
-	0x0C, 0x00,
-	0x0D, 0x81,
-	0x0E, 0x23,
-	0x0F, 0x12,
-	0x10, 0x7E,
-	0x11, 0x84,
-	0x12, 0xB9,
-	0x13, 0x88,
-	0x14, 0x89,
-	0x15, 0xC9,
-	0x16, 0x00,
-	0x17, 0x5C,
-	0x18, 0x00,
-	0x19, 0x00,
-	0x1A, 0x00,
-	0x1C, 0x00,
-	0x1D, 0x00,
-	0x1E, 0x00,
-	0x1F, 0x3A,
-	0x20, 0x2E,
-	0x21, 0x80,
-	0x22, 0xFF,
-	0x23, 0xC1,
-	0x28, 0x00,
-	0x29, 0x1E,
-	0x2A, 0x14,
-	0x2B, 0x0F,
-	0x2C, 0x09,
-	0x2D, 0x05,
-	0x31, 0x1F,
-	0x32, 0x19,
-	0x33, 0xFE,
-	0x34, 0x93,
-	0xff, 0xff,
-};
-
-static struct stv0299_config samsung_tbmu24112_config = {
-	.demod_address = 0x68,
-	.inittab = samsung_tbmu24112_inittab,
-	.mclk = 88000000UL,
-	.invert = 0,
-	.skip_reinit = 0,
-	.lock_output = STV0299_LOCKOUTPUT_LK,
-	.volt13_op0_op1 = STV0299_VOLT13_OP1,
-	.min_delay_ms = 100,
-	.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
-};
-
-static int skystar2_rev26_attach(struct flexcop_device *fc,
-	struct i2c_adapter *i2c)
-{
-	fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
-	if (!fc->fe)
-		return 0;
-
-	if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
-			DVB_PLL_SAMSUNG_TBMU24112))
-		return 0;
-
-	fc->fe->ops.set_voltage = flexcop_set_voltage;
-	fc->fe_sleep = fc->fe->ops.sleep;
-	fc->fe->ops.sleep = flexcop_sleep;
-	return 1;
-
-}
-#else
-#define skystar2_rev26_attach NULL
-#endif
-
-/* SkyStar2 DVB-S rev 2.7 */
-#if FE_SUPPORTED(S5H1420) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_ITD1000)
-static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
-	.demod_address = 0x53,
-	.invert = 1,
-	.repeated_start_workaround = 1,
-	.serial_mpeg = 1,
-};
-
-static struct itd1000_config skystar2_rev2_7_itd1000_config = {
-	.i2c_address = 0x61,
-};
-
-static int skystar2_rev27_attach(struct flexcop_device *fc,
-	struct i2c_adapter *i2c)
-{
-	flexcop_ibi_value r108;
-	struct i2c_adapter *i2c_tuner;
-
-	/* enable no_base_addr - no repeated start when reading */
-	fc->fc_i2c_adap[0].no_base_addr = 1;
-	fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config,
-			    i2c);
-	if (!fc->fe)
-		goto fail;
-
-	i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
-	if (!i2c_tuner)
-		goto fail;
-
-	fc->fe_sleep = fc->fe->ops.sleep;
-	fc->fe->ops.sleep = flexcop_sleep;
-
-	/* enable no_base_addr - no repeated start when reading */
-	fc->fc_i2c_adap[2].no_base_addr = 1;
-	if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
-			0x08, 1, 1)) {
-		err("ISL6421 could NOT be attached");
-		goto fail_isl;
-	}
-	info("ISL6421 successfully attached");
-
-	/* the ITD1000 requires a lower i2c clock - is it a problem ? */
-	r108.raw = 0x00000506;
-	fc->write_ibi_reg(fc, tw_sm_c_108, r108);
-	if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner,
-			&skystar2_rev2_7_itd1000_config)) {
-		err("ITD1000 could NOT be attached");
-		/* Should i2c clock be restored? */
-		goto fail_isl;
-	}
-	info("ITD1000 successfully attached");
-
-	return 1;
-
-fail_isl:
-	fc->fc_i2c_adap[2].no_base_addr = 0;
-fail:
-	/* for the next devices we need it again */
-	fc->fc_i2c_adap[0].no_base_addr = 0;
-	return 0;
-}
-#else
-#define skystar2_rev27_attach NULL
-#endif
-
-/* SkyStar2 rev 2.8 */
-#if FE_SUPPORTED(CX24123) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_CX24113)
-static struct cx24123_config skystar2_rev2_8_cx24123_config = {
-	.demod_address = 0x55,
-	.dont_use_pll = 1,
-	.agc_callback = cx24113_agc_callback,
-};
-
-static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
-	.i2c_addr = 0x54,
-	.xtal_khz = 10111,
-};
-
-static int skystar2_rev28_attach(struct flexcop_device *fc,
-	struct i2c_adapter *i2c)
-{
-	struct i2c_adapter *i2c_tuner;
-
-	fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config,
-			    i2c);
-	if (!fc->fe)
-		return 0;
-
-	i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);
-	if (!i2c_tuner)
-		return 0;
-
-	if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config,
-			i2c_tuner)) {
-		err("CX24113 could NOT be attached");
-		return 0;
-	}
-	info("CX24113 successfully attached");
-
-	fc->fc_i2c_adap[2].no_base_addr = 1;
-	if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
-			0x08, 0, 0)) {
-		err("ISL6421 could NOT be attached");
-		fc->fc_i2c_adap[2].no_base_addr = 0;
-		return 0;
-	}
-	info("ISL6421 successfully attached");
-	/* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
-	 * IR-receiver (PIC16F818) - but the card has no input for that ??? */
-	return 1;
-}
-#else
-#define skystar2_rev28_attach NULL
-#endif
-
-/* AirStar DVB-T */
-#if FE_SUPPORTED(MT352) && FE_SUPPORTED(PLL)
-static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
-{
-	static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d };
-	static u8 mt352_reset[] = { 0x50, 0x80 };
-	static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
-	static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 };
-	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
-
-	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
-	udelay(2000);
-	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
-	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
-	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
-	return 0;
-}
-
-static struct mt352_config samsung_tdtc9251dh0_config = {
-	.demod_address = 0x0f,
-	.demod_init    = samsung_tdtc9251dh0_demod_init,
-};
-
-static int airstar_dvbt_attach(struct flexcop_device *fc,
-	struct i2c_adapter *i2c)
-{
-	fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
-	if (!fc->fe)
-		return 0;
-
-	return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
-			    DVB_PLL_SAMSUNG_TDTC9251DH0);
-}
-#else
-#define airstar_dvbt_attach NULL
-#endif
-
-/* AirStar ATSC 1st generation */
-#if FE_SUPPORTED(BCM3510)
-static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
-	const struct firmware **fw, char* name)
-{
-	struct flexcop_device *fc = fe->dvb->priv;
-	return request_firmware(fw, name, fc->dev);
-}
-
-static struct bcm3510_config air2pc_atsc_first_gen_config = {
-	.demod_address    = 0x0f,
-	.request_firmware = flexcop_fe_request_firmware,
-};
-
-static int airstar_atsc1_attach(struct flexcop_device *fc,
-	struct i2c_adapter *i2c)
-{
-	fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
-	return fc->fe != NULL;
-}
-#else
-#define airstar_atsc1_attach NULL
-#endif
-
-/* AirStar ATSC 2nd generation */
-#if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL)
-static struct nxt200x_config samsung_tbmv_config = {
-	.demod_address = 0x0a,
-};
-
-static int airstar_atsc2_attach(struct flexcop_device *fc,
-	struct i2c_adapter *i2c)
-{
-	fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
-	if (!fc->fe)
-		return 0;
-
-	return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
-			    DVB_PLL_SAMSUNG_TBMV);
-}
-#else
-#define airstar_atsc2_attach NULL
-#endif
-
-/* AirStar ATSC 3rd generation */
-#if FE_SUPPORTED(LGDT330X)
-static struct lgdt330x_config air2pc_atsc_hd5000_config = {
-	.demod_address       = 0x59,
-	.demod_chip          = LGDT3303,
-	.serial_mpeg         = 0x04,
-	.clock_polarity_flip = 1,
-};
-
-static int airstar_atsc3_attach(struct flexcop_device *fc,
-	struct i2c_adapter *i2c)
-{
-	fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
-	if (!fc->fe)
-		return 0;
-
-	return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
-			    TUNER_LG_TDVS_H06XF);
-}
-#else
-#define airstar_atsc3_attach NULL
-#endif
-
-/* CableStar2 DVB-C */
-#if FE_SUPPORTED(STV0297) && FE_SUPPORTED(PLL)
-static u8 alps_tdee4_stv0297_inittab[] = {
-	0x80, 0x01,
-	0x80, 0x00,
-	0x81, 0x01,
-	0x81, 0x00,
-	0x00, 0x48,
-	0x01, 0x58,
-	0x03, 0x00,
-	0x04, 0x00,
-	0x07, 0x00,
-	0x08, 0x00,
-	0x30, 0xff,
-	0x31, 0x9d,
-	0x32, 0xff,
-	0x33, 0x00,
-	0x34, 0x29,
-	0x35, 0x55,
-	0x36, 0x80,
-	0x37, 0x6e,
-	0x38, 0x9c,
-	0x40, 0x1a,
-	0x41, 0xfe,
-	0x42, 0x33,
-	0x43, 0x00,
-	0x44, 0xff,
-	0x45, 0x00,
-	0x46, 0x00,
-	0x49, 0x04,
-	0x4a, 0x51,
-	0x4b, 0xf8,
-	0x52, 0x30,
-	0x53, 0x06,
-	0x59, 0x06,
-	0x5a, 0x5e,
-	0x5b, 0x04,
-	0x61, 0x49,
-	0x62, 0x0a,
-	0x70, 0xff,
-	0x71, 0x04,
-	0x72, 0x00,
-	0x73, 0x00,
-	0x74, 0x0c,
-	0x80, 0x20,
-	0x81, 0x00,
-	0x82, 0x30,
-	0x83, 0x00,
-	0x84, 0x04,
-	0x85, 0x22,
-	0x86, 0x08,
-	0x87, 0x1b,
-	0x88, 0x00,
-	0x89, 0x00,
-	0x90, 0x00,
-	0x91, 0x04,
-	0xa0, 0x86,
-	0xa1, 0x00,
-	0xa2, 0x00,
-	0xb0, 0x91,
-	0xb1, 0x0b,
-	0xc0, 0x5b,
-	0xc1, 0x10,
-	0xc2, 0x12,
-	0xd0, 0x02,
-	0xd1, 0x00,
-	0xd2, 0x00,
-	0xd3, 0x00,
-	0xd4, 0x02,
-	0xd5, 0x00,
-	0xde, 0x00,
-	0xdf, 0x01,
-	0xff, 0xff,
-};
-
-static struct stv0297_config alps_tdee4_stv0297_config = {
-	.demod_address = 0x1c,
-	.inittab = alps_tdee4_stv0297_inittab,
-};
-
-static int cablestar2_attach(struct flexcop_device *fc,
-	struct i2c_adapter *i2c)
-{
-	fc->fc_i2c_adap[0].no_base_addr = 1;
-	fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
-	if (!fc->fe)
-		goto fail;
-
-	/* This tuner doesn't use the stv0297's I2C gate, but instead the
-	 * tuner is connected to a different flexcop I2C adapter.  */
-	if (fc->fe->ops.i2c_gate_ctrl)
-		fc->fe->ops.i2c_gate_ctrl(fc->fe, 0);
-	fc->fe->ops.i2c_gate_ctrl = NULL;
-
-	if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61,
-			&fc->fc_i2c_adap[2].i2c_adap, DVB_PLL_TDEE4))
-		goto fail;
-
-	return 1;
-
-fail:
-	/* Reset for next frontend to try */
-	fc->fc_i2c_adap[0].no_base_addr = 0;
-	return 0;
-}
-#else
-#define cablestar2_attach NULL
-#endif
-
-static struct {
-	flexcop_device_type_t type;
-	int (*attach)(struct flexcop_device *, struct i2c_adapter *);
-} flexcop_frontends[] = {
-	{ FC_SKY_REV27, skystar2_rev27_attach },
-	{ FC_SKY_REV28, skystar2_rev28_attach },
-	{ FC_SKY_REV26, skystar2_rev26_attach },
-	{ FC_AIR_DVBT, airstar_dvbt_attach },
-	{ FC_AIR_ATSC2, airstar_atsc2_attach },
-	{ FC_AIR_ATSC3, airstar_atsc3_attach },
-	{ FC_AIR_ATSC1, airstar_atsc1_attach },
-	{ FC_CABLE, cablestar2_attach },
-	{ FC_SKY_REV23, skystar2_rev23_attach },
-};
-
-/* try to figure out the frontend */
-int flexcop_frontend_init(struct flexcop_device *fc)
-{
-	int i;
-	for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) {
-		if (!flexcop_frontends[i].attach)
-			continue;
-		/* type needs to be set before, because of some workarounds
-		 * done based on the probed card type */
-		fc->dev_type = flexcop_frontends[i].type;
-		if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap))
-			goto fe_found;
-		/* Clean up partially attached frontend */
-		if (fc->fe) {
-			dvb_frontend_detach(fc->fe);
-			fc->fe = NULL;
-		}
-	}
-	fc->dev_type = FC_UNK;
-	err("no frontend driver found for this B2C2/FlexCop adapter");
-	return -ENODEV;
-
-fe_found:
-	info("found '%s' .", fc->fe->ops.info.name);
-	if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
-		err("frontend registration failed!");
-		dvb_frontend_detach(fc->fe);
-		fc->fe = NULL;
-		return -EINVAL;
-	}
-	fc->init_state |= FC_STATE_FE_INIT;
-	return 0;
-}
-
-void flexcop_frontend_exit(struct flexcop_device *fc)
-{
-	if (fc->init_state & FC_STATE_FE_INIT) {
-		dvb_unregister_frontend(fc->fe);
-		dvb_frontend_detach(fc->fe);
-	}
-	fc->init_state &= ~FC_STATE_FE_INIT;
-}
diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c
deleted file mode 100644
index 77e4547..0000000
--- a/drivers/media/dvb/b2c2/flexcop-hw-filter.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- * flexcop-hw-filter.c - pid and mac address filtering and control functions
- * see flexcop.c for copyright information
- */
-#include "flexcop.h"
-
-static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff)
-{
-	flexcop_set_ibi_value(ctrl_208, Rcv_Data_sig, onoff);
-	deb_ts("rcv_data is now: '%s'\n", onoff ? "on" : "off");
-}
-
-void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff)
-{
-	flexcop_set_ibi_value(ctrl_208, SMC_Enable_sig, onoff);
-}
-
-static void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff)
-{
-	flexcop_set_ibi_value(ctrl_208, Null_filter_sig, onoff);
-}
-
-void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6])
-{
-	flexcop_ibi_value v418, v41c;
-	v41c = fc->read_ibi_reg(fc, mac_address_41c);
-
-	v418.mac_address_418.MAC1 = mac[0];
-	v418.mac_address_418.MAC2 = mac[1];
-	v418.mac_address_418.MAC3 = mac[2];
-	v418.mac_address_418.MAC6 = mac[3];
-	v41c.mac_address_41c.MAC7 = mac[4];
-	v41c.mac_address_41c.MAC8 = mac[5];
-
-	fc->write_ibi_reg(fc, mac_address_418, v418);
-	fc->write_ibi_reg(fc, mac_address_41c, v41c);
-}
-
-void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff)
-{
-	flexcop_set_ibi_value(ctrl_208, MAC_filter_Mode_sig, onoff);
-}
-
-static void flexcop_pid_group_filter(struct flexcop_device *fc,
-		u16 pid, u16 mask)
-{
-	/* index_reg_310.extra_index_reg need to 0 or 7 to work */
-	flexcop_ibi_value v30c;
-	v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid;
-	v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask;
-	fc->write_ibi_reg(fc, pid_filter_30c, v30c);
-}
-
-static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff)
-{
-	flexcop_set_ibi_value(ctrl_208, Mask_filter_sig, onoff);
-}
-
-/* this fancy define reduces the code size of the quite similar PID controlling of
- * the first 6 PIDs
- */
-
-#define pid_ctrl(vregname,field,enablefield,trans_field,transval) \
-	flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \
-v208 = fc->read_ibi_reg(fc, ctrl_208); \
-vpid.vregname.field = onoff ? pid : 0x1fff; \
-vpid.vregname.trans_field = transval; \
-v208.ctrl_208.enablefield = onoff; \
-fc->write_ibi_reg(fc, vregname, vpid); \
-fc->write_ibi_reg(fc, ctrl_208, v208);
-
-static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc,
-		u16 pid, int onoff)
-{
-	pid_ctrl(pid_filter_300, Stream1_PID, Stream1_filter_sig,
-			Stream1_trans, 0);
-}
-
-static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc,
-		u16 pid, int onoff)
-{
-	pid_ctrl(pid_filter_300, Stream2_PID, Stream2_filter_sig,
-			Stream2_trans, 0);
-}
-
-static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc,
-		u16 pid, int onoff)
-{
-	pid_ctrl(pid_filter_304, PCR_PID, PCR_filter_sig, PCR_trans, 0);
-}
-
-static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc,
-		u16 pid, int onoff)
-{
-	pid_ctrl(pid_filter_304, PMT_PID, PMT_filter_sig, PMT_trans, 0);
-}
-
-static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc,
-		u16 pid, int onoff)
-{
-	pid_ctrl(pid_filter_308, EMM_PID, EMM_filter_sig, EMM_trans, 0);
-}
-
-static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc,
-		u16 pid, int onoff)
-{
-	pid_ctrl(pid_filter_308, ECM_PID, ECM_filter_sig, ECM_trans, 0);
-}
-
-static void flexcop_pid_control(struct flexcop_device *fc,
-		int index, u16 pid, int onoff)
-{
-	if (pid == 0x2000)
-		return;
-
-	deb_ts("setting pid: %5d %04x at index %d '%s'\n",
-			pid, pid, index, onoff ? "on" : "off");
-
-	/* We could use bit magic here to reduce source code size.
-	 * I decided against it, but to use the real register names */
-	switch (index) {
-	case 0:
-		flexcop_pid_Stream1_PID_ctrl(fc, pid, onoff);
-		break;
-	case 1:
-		flexcop_pid_Stream2_PID_ctrl(fc, pid, onoff);
-		break;
-	case 2:
-		flexcop_pid_PCR_PID_ctrl(fc, pid, onoff);
-		break;
-	case 3:
-		flexcop_pid_PMT_PID_ctrl(fc, pid, onoff);
-		break;
-	case 4:
-		flexcop_pid_EMM_PID_ctrl(fc, pid, onoff);
-		break;
-	case 5:
-		flexcop_pid_ECM_PID_ctrl(fc, pid, onoff);
-		break;
-	default:
-		if (fc->has_32_hw_pid_filter && index < 38) {
-			flexcop_ibi_value vpid, vid;
-
-			/* set the index */
-			vid = fc->read_ibi_reg(fc, index_reg_310);
-			vid.index_reg_310.index_reg = index - 6;
-			fc->write_ibi_reg(fc, index_reg_310, vid);
-
-			vpid = fc->read_ibi_reg(fc, pid_n_reg_314);
-			vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff;
-			vpid.pid_n_reg_314.PID_enable_bit = onoff;
-			fc->write_ibi_reg(fc, pid_n_reg_314, vpid);
-		}
-		break;
-	}
-}
-
-static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc, int onoff)
-{
-	if (fc->fullts_streaming_state != onoff) {
-		deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling");
-		flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff));
-		flexcop_pid_group_filter_ctrl(fc, onoff);
-		fc->fullts_streaming_state = onoff;
-	}
-	return 0;
-}
-
-int flexcop_pid_feed_control(struct flexcop_device *fc,
-		struct dvb_demux_feed *dvbdmxfeed, int onoff)
-{
-	int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32;
-
-	fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */
-	if (dvbdmxfeed->index >= max_pid_filter)
-		fc->extra_feedcount += onoff ? 1 : -1;
-
-	/* toggle complete-TS-streaming when:
-	 * - pid_filtering is not enabled and it is the first or last feed requested
-	 * - pid_filtering is enabled,
-	 *   - but the number of requested feeds is exceeded
-	 *   - or the requested pid is 0x2000 */
-
-	if (!fc->pid_filtering && fc->feedcount == onoff)
-		flexcop_toggle_fullts_streaming(fc, onoff);
-
-	if (fc->pid_filtering) {
-		flexcop_pid_control \
-			(fc, dvbdmxfeed->index, dvbdmxfeed->pid, onoff);
-
-		if (fc->extra_feedcount > 0)
-			flexcop_toggle_fullts_streaming(fc, 1);
-		else if (dvbdmxfeed->pid == 0x2000)
-			flexcop_toggle_fullts_streaming(fc, onoff);
-		else
-			flexcop_toggle_fullts_streaming(fc, 0);
-	}
-
-	/* if it was the first or last feed request change the stream-status */
-	if (fc->feedcount == onoff) {
-		flexcop_rcv_data_ctrl(fc, onoff);
-		if (fc->stream_control) /* device specific stream control */
-			fc->stream_control(fc, onoff);
-
-		/* feeding stopped -> reset the flexcop filter*/
-		if (onoff == 0) {
-			flexcop_reset_block_300(fc);
-			flexcop_hw_filter_init(fc);
-		}
-	}
-	return 0;
-}
-EXPORT_SYMBOL(flexcop_pid_feed_control);
-
-void flexcop_hw_filter_init(struct flexcop_device *fc)
-{
-	int i;
-	flexcop_ibi_value v;
-	for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++)
-		flexcop_pid_control(fc, i, 0x1fff, 0);
-
-	flexcop_pid_group_filter(fc, 0, 0x1fe0);
-	flexcop_pid_group_filter_ctrl(fc, 0);
-
-	v = fc->read_ibi_reg(fc, pid_filter_308);
-	v.pid_filter_308.EMM_filter_4 = 1;
-	v.pid_filter_308.EMM_filter_6 = 0;
-	fc->write_ibi_reg(fc, pid_filter_308, v);
-
-	flexcop_null_filter_ctrl(fc, 1);
-}
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
deleted file mode 100644
index 965d5eb..0000000
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- * flexcop-i2c.c - flexcop internal 2Wire bus (I2C) and dvb i2c initialization
- * see flexcop.c for copyright information
- */
-#include "flexcop.h"
-
-#define FC_MAX_I2C_RETRIES 100000
-
-static int flexcop_i2c_operation(struct flexcop_device *fc,
-		flexcop_ibi_value *r100)
-{
-	int i;
-	flexcop_ibi_value r;
-
-	r100->tw_sm_c_100.working_start = 1;
-	deb_i2c("r100 before: %08x\n",r100->raw);
-
-	fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero);
-	fc->write_ibi_reg(fc, tw_sm_c_100, *r100); /* initiating i2c operation */
-
-	for (i = 0; i < FC_MAX_I2C_RETRIES; i++) {
-		r = fc->read_ibi_reg(fc, tw_sm_c_100);
-
-		if (!r.tw_sm_c_100.no_base_addr_ack_error) {
-			if (r.tw_sm_c_100.st_done) {
-				*r100 = r;
-				deb_i2c("i2c success\n");
-				return 0;
-			}
-		} else {
-			deb_i2c("suffering from an i2c ack_error\n");
-			return -EREMOTEIO;
-		}
-	}
-	deb_i2c("tried %d times i2c operation, "
-			"never finished or too many ack errors.\n", i);
-	return -EREMOTEIO;
-}
-
-static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c,
-		flexcop_ibi_value r100, u8 *buf)
-{
-	flexcop_ibi_value r104;
-	int len = r100.tw_sm_c_100.total_bytes,
-		/* remember total_bytes is buflen-1 */
-		ret;
-
-	/* work-around to have CableStar2 and SkyStar2 rev 2.7 work
-	 * correctly:
-	 *
-	 * the ITD1000 is behind an i2c-gate which closes automatically
-	 * after an i2c-transaction the STV0297 needs 2 consecutive reads
-	 * one with no_base_addr = 0 and one with 1
-	 *
-	 * those two work-arounds are conflictin: we check for the card
-	 * type, it is set when probing the ITD1000 */
-	if (i2c->fc->dev_type == FC_SKY_REV27)
-		r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
-
-	ret = flexcop_i2c_operation(i2c->fc, &r100);
-	if (ret != 0) {
-		deb_i2c("Retrying operation\n");
-		r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
-		ret = flexcop_i2c_operation(i2c->fc, &r100);
-	}
-	if (ret != 0) {
-		deb_i2c("read failed. %d\n", ret);
-		return ret;
-	}
-
-	buf[0] = r100.tw_sm_c_100.data1_reg;
-
-	if (len > 0) {
-		r104 = i2c->fc->read_ibi_reg(i2c->fc, tw_sm_c_104);
-		deb_i2c("read: r100: %08x, r104: %08x\n", r100.raw, r104.raw);
-
-		/* there is at least one more byte, otherwise we wouldn't be here */
-		buf[1] = r104.tw_sm_c_104.data2_reg;
-		if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg;
-		if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg;
-	}
-	return 0;
-}
-
-static int flexcop_i2c_write4(struct flexcop_device *fc,
-		flexcop_ibi_value r100, u8 *buf)
-{
-	flexcop_ibi_value r104;
-	int len = r100.tw_sm_c_100.total_bytes; /* remember total_bytes is buflen-1 */
-	r104.raw = 0;
-
-	/* there is at least one byte, otherwise we wouldn't be here */
-	r100.tw_sm_c_100.data1_reg = buf[0];
-	r104.tw_sm_c_104.data2_reg = len > 0 ? buf[1] : 0;
-	r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0;
-	r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0;
-
-	deb_i2c("write: r100: %08x, r104: %08x\n", r100.raw, r104.raw);
-
-	/* write the additional i2c data before doing the actual i2c operation */
-	fc->write_ibi_reg(fc, tw_sm_c_104, r104);
-	return flexcop_i2c_operation(fc, &r100);
-}
-
-int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c,
-		flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
-{
-	int ret;
-
-#ifdef DUMP_I2C_MESSAGES
-	int i;
-#endif
-
-	u16 bytes_to_transfer;
-	flexcop_ibi_value r100;
-
-	deb_i2c("op = %d\n",op);
-	r100.raw = 0;
-	r100.tw_sm_c_100.chipaddr = chipaddr;
-	r100.tw_sm_c_100.twoWS_rw = op;
-	r100.tw_sm_c_100.twoWS_port_reg = i2c->port;
-
-#ifdef DUMP_I2C_MESSAGES
-	printk(KERN_DEBUG "%d ", i2c->port);
-	if (op == FC_READ)
-		printk("rd(");
-	else
-		printk("wr(");
-	printk("%02x): %02x ", chipaddr, addr);
-#endif
-
-	/* in that case addr is the only value ->
-	 * we write it twice as baseaddr and val0
-	 * BBTI is doing it like that for ISL6421 at least */
-	if (i2c->no_base_addr && len == 0 && op == FC_WRITE) {
-		buf = &addr;
-		len = 1;
-	}
-
-	while (len != 0) {
-		bytes_to_transfer = len > 4 ? 4 : len;
-
-		r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1;
-		r100.tw_sm_c_100.baseaddr = addr;
-
-		if (op == FC_READ)
-			ret = flexcop_i2c_read4(i2c, r100, buf);
-		else
-			ret = flexcop_i2c_write4(i2c->fc, r100, buf);
-
-#ifdef DUMP_I2C_MESSAGES
-		for (i = 0; i < bytes_to_transfer; i++)
-			printk("%02x ", buf[i]);
-#endif
-
-		if (ret < 0)
-			return ret;
-
-		buf  += bytes_to_transfer;
-		addr += bytes_to_transfer;
-		len  -= bytes_to_transfer;
-	}
-
-#ifdef DUMP_I2C_MESSAGES
-	printk("\n");
-#endif
-
-	return 0;
-}
-/* exported for PCI i2c */
-EXPORT_SYMBOL(flexcop_i2c_request);
-
-/* master xfer callback for demodulator */
-static int flexcop_master_xfer(struct i2c_adapter *i2c_adap,
-		struct i2c_msg msgs[], int num)
-{
-	struct flexcop_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap);
-	int i, ret = 0;
-
-	/* Some drivers use 1 byte or 0 byte reads as probes, which this
-	 * driver doesn't support.  These probes will always fail, so this
-	 * hack makes them always succeed.  If one knew how, it would of
-	 * course be better to actually do the read.  */
-	if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1)
-		return 1;
-
-	if (mutex_lock_interruptible(&i2c->fc->i2c_mutex))
-		return -ERESTARTSYS;
-
-	for (i = 0; i < num; i++) {
-		/* reading */
-		if (i+1 < num && (msgs[i+1].flags == I2C_M_RD)) {
-			ret = i2c->fc->i2c_request(i2c, FC_READ, msgs[i].addr,
-					msgs[i].buf[0], msgs[i+1].buf,
-					msgs[i+1].len);
-			i++; /* skip the following message */
-		} else /* writing */
-			ret = i2c->fc->i2c_request(i2c, FC_WRITE, msgs[i].addr,
-					msgs[i].buf[0], &msgs[i].buf[1],
-					msgs[i].len - 1);
-		if (ret < 0) {
-			deb_i2c("i2c master_xfer failed");
-			break;
-		}
-	}
-
-	mutex_unlock(&i2c->fc->i2c_mutex);
-
-	if (ret == 0)
-		ret = num;
-	return ret;
-}
-
-static u32 flexcop_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm flexcop_algo = {
-	.master_xfer	= flexcop_master_xfer,
-	.functionality	= flexcop_i2c_func,
-};
-
-int flexcop_i2c_init(struct flexcop_device *fc)
-{
-	int ret;
-	mutex_init(&fc->i2c_mutex);
-
-	fc->fc_i2c_adap[0].fc = fc;
-	fc->fc_i2c_adap[1].fc = fc;
-	fc->fc_i2c_adap[2].fc = fc;
-	fc->fc_i2c_adap[0].port = FC_I2C_PORT_DEMOD;
-	fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM;
-	fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER;
-
-	strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod",
-			sizeof(fc->fc_i2c_adap[0].i2c_adap.name));
-	strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom",
-			sizeof(fc->fc_i2c_adap[1].i2c_adap.name));
-	strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner",
-			sizeof(fc->fc_i2c_adap[2].i2c_adap.name));
-
-	i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]);
-	i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
-	i2c_set_adapdata(&fc->fc_i2c_adap[2].i2c_adap, &fc->fc_i2c_adap[2]);
-
-	fc->fc_i2c_adap[0].i2c_adap.algo =
-		fc->fc_i2c_adap[1].i2c_adap.algo =
-		fc->fc_i2c_adap[2].i2c_adap.algo = &flexcop_algo;
-	fc->fc_i2c_adap[0].i2c_adap.algo_data =
-		fc->fc_i2c_adap[1].i2c_adap.algo_data =
-		fc->fc_i2c_adap[2].i2c_adap.algo_data = NULL;
-	fc->fc_i2c_adap[0].i2c_adap.dev.parent =
-		fc->fc_i2c_adap[1].i2c_adap.dev.parent =
-		fc->fc_i2c_adap[2].i2c_adap.dev.parent = fc->dev;
-
-	ret = i2c_add_adapter(&fc->fc_i2c_adap[0].i2c_adap);
-	if (ret < 0)
-		return ret;
-
-	ret = i2c_add_adapter(&fc->fc_i2c_adap[1].i2c_adap);
-	if (ret < 0)
-		goto adap_1_failed;
-
-	ret = i2c_add_adapter(&fc->fc_i2c_adap[2].i2c_adap);
-	if (ret < 0)
-		goto adap_2_failed;
-
-	fc->init_state |= FC_STATE_I2C_INIT;
-	return 0;
-
-adap_2_failed:
-	i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
-adap_1_failed:
-	i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
-	return ret;
-}
-
-void flexcop_i2c_exit(struct flexcop_device *fc)
-{
-	if (fc->init_state & FC_STATE_I2C_INIT) {
-		i2c_del_adapter(&fc->fc_i2c_adap[2].i2c_adap);
-		i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
-		i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
-	}
-	fc->init_state &= ~FC_STATE_I2C_INIT;
-}
diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c
deleted file mode 100644
index f06f3a9..0000000
--- a/drivers/media/dvb/b2c2/flexcop-misc.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- * flexcop-misc.c - miscellaneous functions
- * see flexcop.c for copyright information
- */
-#include "flexcop.h"
-
-void flexcop_determine_revision(struct flexcop_device *fc)
-{
-	flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204);
-
-	switch (v.misc_204.Rev_N_sig_revision_hi) {
-	case 0x2:
-		deb_info("found a FlexCopII.\n");
-		fc->rev = FLEXCOP_II;
-		break;
-	case 0x3:
-		deb_info("found a FlexCopIIb.\n");
-		fc->rev = FLEXCOP_IIB;
-		break;
-	case 0x0:
-		deb_info("found a FlexCopIII.\n");
-		fc->rev = FLEXCOP_III;
-		break;
-	default:
-		err("unknown FlexCop Revision: %x. Please report this to "
-				"linux-dvb@linuxtv.org.",
-				v.misc_204.Rev_N_sig_revision_hi);
-		break;
-	}
-
-	if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps))
-		deb_info("this FlexCop has "
-				"the additional 32 hardware pid filter.\n");
-	else
-		deb_info("this FlexCop has "
-				"the 6 basic main hardware pid filter.\n");
-	/* bus parts have to decide if hw pid filtering is used or not. */
-}
-
-static const char *flexcop_revision_names[] = {
-	"Unknown chip",
-	"FlexCopII",
-	"FlexCopIIb",
-	"FlexCopIII",
-};
-
-static const char *flexcop_device_names[] = {
-	[FC_UNK]	= "Unknown device",
-	[FC_CABLE]	= "Cable2PC/CableStar 2 DVB-C",
-	[FC_AIR_DVBT]	= "Air2PC/AirStar 2 DVB-T",
-	[FC_AIR_ATSC1]	= "Air2PC/AirStar 2 ATSC 1st generation",
-	[FC_AIR_ATSC2]	= "Air2PC/AirStar 2 ATSC 2nd generation",
-	[FC_AIR_ATSC3]	= "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
-	[FC_SKY_REV23]	= "Sky2PC/SkyStar 2 DVB-S rev 2.3 (old version)",
-	[FC_SKY_REV26]	= "Sky2PC/SkyStar 2 DVB-S rev 2.6",
-	[FC_SKY_REV27]	= "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
-	[FC_SKY_REV28]	= "Sky2PC/SkyStar 2 DVB-S rev 2.8",
-};
-
-static const char *flexcop_bus_names[] = {
-	"USB",
-	"PCI",
-};
-
-void flexcop_device_name(struct flexcop_device *fc,
-		const char *prefix, const char *suffix)
-{
-	info("%s '%s' at the '%s' bus controlled by a '%s' %s",
-			prefix,	flexcop_device_names[fc->dev_type],
-			flexcop_bus_names[fc->bus_type],
-			flexcop_revision_names[fc->rev], suffix);
-}
-
-void flexcop_dump_reg(struct flexcop_device *fc,
-		flexcop_ibi_register reg, int num)
-{
-	flexcop_ibi_value v;
-	int i;
-	for (i = 0; i < num; i++) {
-		v = fc->read_ibi_reg(fc, reg+4*i);
-		deb_rdump("0x%03x: %08x, ", reg+4*i, v.raw);
-	}
-	deb_rdump("\n");
-}
-EXPORT_SYMBOL(flexcop_dump_reg);
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c
deleted file mode 100644
index 44f8fb5..0000000
--- a/drivers/media/dvb/b2c2/flexcop-pci.c
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * Linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- * flexcop-pci.c - covers the PCI part including DMA transfers
- * see flexcop.c for copyright information
- */
-
-#define FC_LOG_PREFIX "flexcop-pci"
-#include "flexcop-common.h"
-
-static int enable_pid_filtering = 1;
-module_param(enable_pid_filtering, int, 0444);
-MODULE_PARM_DESC(enable_pid_filtering,
-	"enable hardware pid filtering: supported values: 0 (fullts), 1");
-
-static int irq_chk_intv = 100;
-module_param(irq_chk_intv, int, 0644);
-MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ streaming watchdog.");
-
-#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
-#define dprintk(level,args...) \
-	do { if ((debug & level)) printk(args); } while (0)
-#define DEBSTATUS ""
-#else
-#define dprintk(level,args...)
-#define DEBSTATUS " (debugging is not enabled)"
-#endif
-
-#define deb_info(args...) dprintk(0x01, args)
-#define deb_reg(args...) dprintk(0x02, args)
-#define deb_ts(args...) dprintk(0x04, args)
-#define deb_irq(args...) dprintk(0x08, args)
-#define deb_chk(args...) dprintk(0x10, args)
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug,
-	"set debug level (1=info,2=regs,4=TS,8=irqdma,16=check (|-able))."
-	DEBSTATUS);
-
-#define DRIVER_VERSION "0.1"
-#define DRIVER_NAME "flexcop-pci"
-#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
-
-struct flexcop_pci {
-	struct pci_dev *pdev;
-
-#define FC_PCI_INIT     0x01
-#define FC_PCI_DMA_INIT 0x02
-	int init_state;
-
-	void __iomem *io_mem;
-	u32 irq;
-	/* buffersize (at least for DMA1, need to be % 188 == 0,
-	 * this logic is required */
-#define FC_DEFAULT_DMA1_BUFSIZE (1280 * 188)
-#define FC_DEFAULT_DMA2_BUFSIZE (10 * 188)
-	struct flexcop_dma dma[2];
-
-	int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */
-	u32 last_dma1_cur_pos;
-	/* position of the pointer last time the timer/packet irq occurred */
-	int count;
-	int count_prev;
-	int stream_problem;
-
-	spinlock_t irq_lock;
-	unsigned long last_irq;
-
-	struct delayed_work irq_check_work;
-	struct flexcop_device *fc_dev;
-};
-
-static int lastwreg, lastwval, lastrreg, lastrval;
-
-static flexcop_ibi_value flexcop_pci_read_ibi_reg(struct flexcop_device *fc,
-		flexcop_ibi_register r)
-{
-	struct flexcop_pci *fc_pci = fc->bus_specific;
-	flexcop_ibi_value v;
-	v.raw = readl(fc_pci->io_mem + r);
-
-	if (lastrreg != r || lastrval != v.raw) {
-		lastrreg = r; lastrval = v.raw;
-		deb_reg("new rd: %3x: %08x\n", r, v.raw);
-	}
-
-	return v;
-}
-
-static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc,
-		flexcop_ibi_register r, flexcop_ibi_value v)
-{
-	struct flexcop_pci *fc_pci = fc->bus_specific;
-
-	if (lastwreg != r || lastwval != v.raw) {
-		lastwreg = r; lastwval = v.raw;
-		deb_reg("new wr: %3x: %08x\n", r, v.raw);
-	}
-
-	writel(v.raw, fc_pci->io_mem + r);
-	return 0;
-}
-
-static void flexcop_pci_irq_check_work(struct work_struct *work)
-{
-	struct flexcop_pci *fc_pci =
-		container_of(work, struct flexcop_pci, irq_check_work.work);
-	struct flexcop_device *fc = fc_pci->fc_dev;
-
-	if (fc->feedcount) {
-
-		if (fc_pci->count == fc_pci->count_prev) {
-			deb_chk("no IRQ since the last check\n");
-			if (fc_pci->stream_problem++ == 3) {
-				struct dvb_demux_feed *feed;
-				deb_info("flexcop-pci: stream problem, resetting pid filter\n");
-
-				spin_lock_irq(&fc->demux.lock);
-				list_for_each_entry(feed, &fc->demux.feed_list,
-						list_head) {
-					flexcop_pid_feed_control(fc, feed, 0);
-				}
-
-				list_for_each_entry(feed, &fc->demux.feed_list,
-						list_head) {
-					flexcop_pid_feed_control(fc, feed, 1);
-				}
-				spin_unlock_irq(&fc->demux.lock);
-
-				fc_pci->stream_problem = 0;
-			}
-		} else {
-			fc_pci->stream_problem = 0;
-			fc_pci->count_prev = fc_pci->count;
-		}
-	}
-
-	schedule_delayed_work(&fc_pci->irq_check_work,
-			msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
-}
-
-/* When PID filtering is turned on, we use the timer IRQ, because small amounts
- * of data need to be passed to the user space instantly as well. When PID
- * filtering is turned off, we use the page-change-IRQ */
-static irqreturn_t flexcop_pci_isr(int irq, void *dev_id)
-{
-	struct flexcop_pci *fc_pci = dev_id;
-	struct flexcop_device *fc = fc_pci->fc_dev;
-	unsigned long flags;
-	flexcop_ibi_value v;
-	irqreturn_t ret = IRQ_HANDLED;
-
-	spin_lock_irqsave(&fc_pci->irq_lock, flags);
-	v = fc->read_ibi_reg(fc, irq_20c);
-
-	/* errors */
-	if (v.irq_20c.Data_receiver_error)
-		deb_chk("data receiver error\n");
-	if (v.irq_20c.Continuity_error_flag)
-		deb_chk("Contunuity error flag is set\n");
-	if (v.irq_20c.LLC_SNAP_FLAG_set)
-		deb_chk("LLC_SNAP_FLAG_set is set\n");
-	if (v.irq_20c.Transport_Error)
-		deb_chk("Transport error\n");
-
-	if ((fc_pci->count % 1000) == 0)
-		deb_chk("%d valid irq took place so far\n", fc_pci->count);
-
-	if (v.irq_20c.DMA1_IRQ_Status == 1) {
-		if (fc_pci->active_dma1_addr == 0)
-			flexcop_pass_dmx_packets(fc_pci->fc_dev,
-					fc_pci->dma[0].cpu_addr0,
-					fc_pci->dma[0].size / 188);
-		else
-			flexcop_pass_dmx_packets(fc_pci->fc_dev,
-					fc_pci->dma[0].cpu_addr1,
-					fc_pci->dma[0].size / 188);
-
-		deb_irq("page change to page: %d\n",!fc_pci->active_dma1_addr);
-		fc_pci->active_dma1_addr = !fc_pci->active_dma1_addr;
-		/* for the timer IRQ we only can use buffer dmx feeding, because we don't have
-		 * complete TS packets when reading from the DMA memory */
-	} else if (v.irq_20c.DMA1_Timer_Status == 1) {
-		dma_addr_t cur_addr =
-			fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2;
-		u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0;
-
-		deb_irq("%u irq: %08x cur_addr: %llx: cur_pos: %08x, "
-			"last_cur_pos: %08x ",
-				jiffies_to_usecs(jiffies - fc_pci->last_irq),
-				v.raw, (unsigned long long)cur_addr, cur_pos,
-				fc_pci->last_dma1_cur_pos);
-		fc_pci->last_irq = jiffies;
-
-		/* buffer end was reached, restarted from the beginning
-		 * pass the data from last_cur_pos to the buffer end to the demux
-		 */
-		if (cur_pos < fc_pci->last_dma1_cur_pos) {
-			deb_irq(" end was reached: passing %d bytes ",
-				(fc_pci->dma[0].size*2 - 1) -
-				fc_pci->last_dma1_cur_pos);
-			flexcop_pass_dmx_data(fc_pci->fc_dev,
-				fc_pci->dma[0].cpu_addr0 +
-					fc_pci->last_dma1_cur_pos,
-				(fc_pci->dma[0].size*2) -
-					fc_pci->last_dma1_cur_pos);
-			fc_pci->last_dma1_cur_pos = 0;
-		}
-
-		if (cur_pos > fc_pci->last_dma1_cur_pos) {
-			deb_irq(" passing %d bytes ",
-				cur_pos - fc_pci->last_dma1_cur_pos);
-			flexcop_pass_dmx_data(fc_pci->fc_dev,
-				fc_pci->dma[0].cpu_addr0 +
-					fc_pci->last_dma1_cur_pos,
-				cur_pos - fc_pci->last_dma1_cur_pos);
-		}
-		deb_irq("\n");
-
-		fc_pci->last_dma1_cur_pos = cur_pos;
-		fc_pci->count++;
-	} else {
-		deb_irq("isr for flexcop called, "
-			"apparently without reason (%08x)\n", v.raw);
-		ret = IRQ_NONE;
-	}
-
-	spin_unlock_irqrestore(&fc_pci->irq_lock, flags);
-	return ret;
-}
-
-static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff)
-{
-	struct flexcop_pci *fc_pci = fc->bus_specific;
-	if (onoff) {
-		flexcop_dma_config(fc, &fc_pci->dma[0], FC_DMA_1);
-		flexcop_dma_config(fc, &fc_pci->dma[1], FC_DMA_2);
-		flexcop_dma_config_timer(fc, FC_DMA_1, 0);
-		flexcop_dma_xfer_control(fc, FC_DMA_1,
-				FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1, 1);
-		deb_irq("DMA xfer enabled\n");
-
-		fc_pci->last_dma1_cur_pos = 0;
-		flexcop_dma_control_timer_irq(fc, FC_DMA_1, 1);
-		deb_irq("IRQ enabled\n");
-		fc_pci->count_prev = fc_pci->count;
-	} else {
-		flexcop_dma_control_timer_irq(fc, FC_DMA_1, 0);
-		deb_irq("IRQ disabled\n");
-
-		flexcop_dma_xfer_control(fc, FC_DMA_1,
-			 FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1, 0);
-		deb_irq("DMA xfer disabled\n");
-	}
-	return 0;
-}
-
-static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci)
-{
-	int ret;
-	ret = flexcop_dma_allocate(fc_pci->pdev, &fc_pci->dma[0],
-			FC_DEFAULT_DMA1_BUFSIZE);
-	if (ret != 0)
-		return ret;
-
-	ret = flexcop_dma_allocate(fc_pci->pdev, &fc_pci->dma[1],
-			FC_DEFAULT_DMA2_BUFSIZE);
-	if (ret != 0) {
-		flexcop_dma_free(&fc_pci->dma[0]);
-		return ret;
-	}
-
-	flexcop_sram_set_dest(fc_pci->fc_dev, FC_SRAM_DEST_MEDIA |
-			FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1);
-	flexcop_sram_set_dest(fc_pci->fc_dev, FC_SRAM_DEST_CAO |
-			FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
-	fc_pci->init_state |= FC_PCI_DMA_INIT;
-	return ret;
-}
-
-static void flexcop_pci_dma_exit(struct flexcop_pci *fc_pci)
-{
-	if (fc_pci->init_state & FC_PCI_DMA_INIT) {
-		flexcop_dma_free(&fc_pci->dma[0]);
-		flexcop_dma_free(&fc_pci->dma[1]);
-	}
-	fc_pci->init_state &= ~FC_PCI_DMA_INIT;
-}
-
-static int flexcop_pci_init(struct flexcop_pci *fc_pci)
-{
-	int ret;
-
-	info("card revision %x", fc_pci->pdev->revision);
-
-	if ((ret = pci_enable_device(fc_pci->pdev)) != 0)
-		return ret;
-	pci_set_master(fc_pci->pdev);
-
-	if ((ret = pci_request_regions(fc_pci->pdev, DRIVER_NAME)) != 0)
-		goto err_pci_disable_device;
-
-	fc_pci->io_mem = pci_iomap(fc_pci->pdev, 0, 0x800);
-
-	if (!fc_pci->io_mem) {
-		err("cannot map io memory\n");
-		ret = -EIO;
-		goto err_pci_release_regions;
-	}
-
-	pci_set_drvdata(fc_pci->pdev, fc_pci);
-	spin_lock_init(&fc_pci->irq_lock);
-	if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr,
-					IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0)
-		goto err_pci_iounmap;
-
-	fc_pci->init_state |= FC_PCI_INIT;
-	return ret;
-
-err_pci_iounmap:
-	pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
-	pci_set_drvdata(fc_pci->pdev, NULL);
-err_pci_release_regions:
-	pci_release_regions(fc_pci->pdev);
-err_pci_disable_device:
-	pci_disable_device(fc_pci->pdev);
-	return ret;
-}
-
-static void flexcop_pci_exit(struct flexcop_pci *fc_pci)
-{
-	if (fc_pci->init_state & FC_PCI_INIT) {
-		free_irq(fc_pci->pdev->irq, fc_pci);
-		pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
-		pci_set_drvdata(fc_pci->pdev, NULL);
-		pci_release_regions(fc_pci->pdev);
-		pci_disable_device(fc_pci->pdev);
-	}
-	fc_pci->init_state &= ~FC_PCI_INIT;
-}
-
-static int flexcop_pci_probe(struct pci_dev *pdev,
-		const struct pci_device_id *ent)
-{
-	struct flexcop_device *fc;
-	struct flexcop_pci *fc_pci;
-	int ret = -ENOMEM;
-
-	if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_pci))) == NULL) {
-		err("out of memory\n");
-		return -ENOMEM;
-	}
-
-	/* general flexcop init */
-	fc_pci = fc->bus_specific;
-	fc_pci->fc_dev = fc;
-
-	fc->read_ibi_reg = flexcop_pci_read_ibi_reg;
-	fc->write_ibi_reg = flexcop_pci_write_ibi_reg;
-	fc->i2c_request = flexcop_i2c_request;
-	fc->get_mac_addr = flexcop_eeprom_check_mac_addr;
-	fc->stream_control = flexcop_pci_stream_control;
-
-	if (enable_pid_filtering)
-		info("will use the HW PID filter.");
-	else
-		info("will pass the complete TS to the demuxer.");
-
-	fc->pid_filtering = enable_pid_filtering;
-	fc->bus_type = FC_PCI;
-	fc->dev = &pdev->dev;
-	fc->owner = THIS_MODULE;
-
-	/* bus specific part */
-	fc_pci->pdev = pdev;
-	if ((ret = flexcop_pci_init(fc_pci)) != 0)
-		goto err_kfree;
-
-	/* init flexcop */
-	if ((ret = flexcop_device_initialize(fc)) != 0)
-		goto err_pci_exit;
-
-	/* init dma */
-	if ((ret = flexcop_pci_dma_init(fc_pci)) != 0)
-		goto err_fc_exit;
-
-	INIT_DELAYED_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work);
-
-	if (irq_chk_intv > 0)
-		schedule_delayed_work(&fc_pci->irq_check_work,
-				msecs_to_jiffies(irq_chk_intv < 100 ?
-					100 :
-					irq_chk_intv));
-	return ret;
-
-err_fc_exit:
-	flexcop_device_exit(fc);
-err_pci_exit:
-	flexcop_pci_exit(fc_pci);
-err_kfree:
-	flexcop_device_kfree(fc);
-	return ret;
-}
-
-/* in theory every _exit function should be called exactly two times,
- * here and in the bail-out-part of the _init-function
- */
-static void flexcop_pci_remove(struct pci_dev *pdev)
-{
-	struct flexcop_pci *fc_pci = pci_get_drvdata(pdev);
-
-	if (irq_chk_intv > 0)
-		cancel_delayed_work(&fc_pci->irq_check_work);
-
-	flexcop_pci_dma_exit(fc_pci);
-	flexcop_device_exit(fc_pci->fc_dev);
-	flexcop_pci_exit(fc_pci);
-	flexcop_device_kfree(fc_pci->fc_dev);
-}
-
-static struct pci_device_id flexcop_pci_tbl[] = {
-	{ PCI_DEVICE(0x13d0, 0x2103) },
-	{ },
-};
-
-MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl);
-
-static struct pci_driver flexcop_pci_driver = {
-	.name     = "b2c2_flexcop_pci",
-	.id_table = flexcop_pci_tbl,
-	.probe    = flexcop_pci_probe,
-	.remove   = flexcop_pci_remove,
-};
-
-static int __init flexcop_pci_module_init(void)
-{
-	return pci_register_driver(&flexcop_pci_driver);
-}
-
-static void __exit flexcop_pci_module_exit(void)
-{
-	pci_unregister_driver(&flexcop_pci_driver);
-}
-
-module_init(flexcop_pci_module_init);
-module_exit(flexcop_pci_module_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_NAME);
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h
deleted file mode 100644
index dc4528d..0000000
--- a/drivers/media/dvb/b2c2/flexcop-reg.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- * flexcop-reg.h - register abstraction for FlexCopII, FlexCopIIb and FlexCopIII
- * see flexcop.c for copyright information
- */
-#ifndef __FLEXCOP_REG_H__
-#define __FLEXCOP_REG_H__
-
-typedef enum {
-	FLEXCOP_UNK = 0,
-	FLEXCOP_II,
-	FLEXCOP_IIB,
-	FLEXCOP_III,
-} flexcop_revision_t;
-
-typedef enum {
-	FC_UNK = 0,
-	FC_CABLE,
-	FC_AIR_DVBT,
-	FC_AIR_ATSC1,
-	FC_AIR_ATSC2,
-	FC_AIR_ATSC3,
-	FC_SKY_REV23,
-	FC_SKY_REV26,
-	FC_SKY_REV27,
-	FC_SKY_REV28,
-} flexcop_device_type_t;
-
-typedef enum {
-	FC_USB = 0,
-	FC_PCI,
-} flexcop_bus_t;
-
-/* FlexCop IBI Registers */
-#if defined(__LITTLE_ENDIAN)
-#include "flexcop_ibi_value_le.h"
-#else
-#if defined(__BIG_ENDIAN)
-#include "flexcop_ibi_value_be.h"
-#else
-#error no endian defined
-#endif
-#endif
-
-#define fc_data_Tag_ID_DVB  0x3e
-#define fc_data_Tag_ID_ATSC 0x3f
-#define fc_data_Tag_ID_IDSB 0x8b
-
-#define fc_key_code_default 0x1
-#define fc_key_code_even    0x2
-#define fc_key_code_odd     0x3
-
-extern flexcop_ibi_value ibi_zero;
-
-typedef enum {
-	FC_I2C_PORT_DEMOD  = 1,
-	FC_I2C_PORT_EEPROM = 2,
-	FC_I2C_PORT_TUNER  = 3,
-} flexcop_i2c_port_t;
-
-typedef enum {
-	FC_WRITE = 0,
-	FC_READ  = 1,
-} flexcop_access_op_t;
-
-typedef enum {
-	FC_SRAM_DEST_NET   = 1,
-	FC_SRAM_DEST_CAI   = 2,
-	FC_SRAM_DEST_CAO   = 4,
-	FC_SRAM_DEST_MEDIA = 8
-} flexcop_sram_dest_t;
-
-typedef enum {
-	FC_SRAM_DEST_TARGET_WAN_USB = 0,
-	FC_SRAM_DEST_TARGET_DMA1    = 1,
-	FC_SRAM_DEST_TARGET_DMA2    = 2,
-	FC_SRAM_DEST_TARGET_FC3_CA  = 3
-} flexcop_sram_dest_target_t;
-
-typedef enum {
-	FC_SRAM_2_32KB  = 0, /*  64KB */
-	FC_SRAM_1_32KB  = 1, /*  32KB - default fow FCII */
-	FC_SRAM_1_128KB = 2, /* 128KB */
-	FC_SRAM_1_48KB  = 3, /*  48KB - default for FCIII */
-} flexcop_sram_type_t;
-
-typedef enum {
-	FC_WAN_SPEED_4MBITS  = 0,
-	FC_WAN_SPEED_8MBITS  = 1,
-	FC_WAN_SPEED_12MBITS = 2,
-	FC_WAN_SPEED_16MBITS = 3,
-} flexcop_wan_speed_t;
-
-typedef enum {
-	FC_DMA_1 = 1,
-	FC_DMA_2 = 2,
-} flexcop_dma_index_t;
-
-typedef enum {
-	FC_DMA_SUBADDR_0 = 1,
-	FC_DMA_SUBADDR_1 = 2,
-} flexcop_dma_addr_index_t;
-
-/* names of the particular registers */
-typedef enum {
-	dma1_000            = 0x000,
-	dma1_004            = 0x004,
-	dma1_008            = 0x008,
-	dma1_00c            = 0x00c,
-	dma2_010            = 0x010,
-	dma2_014            = 0x014,
-	dma2_018            = 0x018,
-	dma2_01c            = 0x01c,
-
-	tw_sm_c_100         = 0x100,
-	tw_sm_c_104         = 0x104,
-	tw_sm_c_108         = 0x108,
-	tw_sm_c_10c         = 0x10c,
-	tw_sm_c_110         = 0x110,
-
-	lnb_switch_freq_200 = 0x200,
-	misc_204            = 0x204,
-	ctrl_208            = 0x208,
-	irq_20c             = 0x20c,
-	sw_reset_210        = 0x210,
-	misc_214            = 0x214,
-	mbox_v8_to_host_218 = 0x218,
-	mbox_host_to_v8_21c = 0x21c,
-
-	pid_filter_300      = 0x300,
-	pid_filter_304      = 0x304,
-	pid_filter_308      = 0x308,
-	pid_filter_30c      = 0x30c,
-	index_reg_310       = 0x310,
-	pid_n_reg_314       = 0x314,
-	mac_low_reg_318     = 0x318,
-	mac_high_reg_31c    = 0x31c,
-
-	data_tag_400        = 0x400,
-	card_id_408         = 0x408,
-	card_id_40c         = 0x40c,
-	mac_address_418     = 0x418,
-	mac_address_41c     = 0x41c,
-
-	ci_600              = 0x600,
-	pi_604              = 0x604,
-	pi_608              = 0x608,
-	dvb_reg_60c         = 0x60c,
-
-	sram_ctrl_reg_700   = 0x700,
-	net_buf_reg_704     = 0x704,
-	cai_buf_reg_708     = 0x708,
-	cao_buf_reg_70c     = 0x70c,
-	media_buf_reg_710   = 0x710,
-	sram_dest_reg_714   = 0x714,
-	net_buf_reg_718     = 0x718,
-	wan_ctrl_reg_71c    = 0x71c,
-} flexcop_ibi_register;
-
-#define flexcop_set_ibi_value(reg,attr,val) { \
-	flexcop_ibi_value v = fc->read_ibi_reg(fc,reg); \
-	v.reg.attr = val; \
-	fc->write_ibi_reg(fc,reg,v); \
-}
-
-#endif
diff --git a/drivers/media/dvb/b2c2/flexcop-sram.c b/drivers/media/dvb/b2c2/flexcop-sram.c
deleted file mode 100644
index f2199e4..0000000
--- a/drivers/media/dvb/b2c2/flexcop-sram.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- * flexcop-sram.c - functions for controlling the SRAM
- * see flexcop.c for copyright information
- */
-#include "flexcop.h"
-
-static void flexcop_sram_set_chip(struct flexcop_device *fc,
-		flexcop_sram_type_t type)
-{
-	flexcop_set_ibi_value(wan_ctrl_reg_71c, sram_chip, type);
-}
-
-int flexcop_sram_init(struct flexcop_device *fc)
-{
-	switch (fc->rev) {
-	case FLEXCOP_II:
-	case FLEXCOP_IIB:
-		flexcop_sram_set_chip(fc, FC_SRAM_1_32KB);
-		break;
-	case FLEXCOP_III:
-		flexcop_sram_set_chip(fc, FC_SRAM_1_48KB);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest,
-		 flexcop_sram_dest_target_t target)
-{
-	flexcop_ibi_value v;
-	v = fc->read_ibi_reg(fc, sram_dest_reg_714);
-
-	if (fc->rev != FLEXCOP_III && target == FC_SRAM_DEST_TARGET_FC3_CA) {
-		err("SRAM destination target to available on FlexCopII(b)\n");
-		return -EINVAL;
-	}
-	deb_sram("sram dest: %x target: %x\n", dest, target);
-
-	if (dest & FC_SRAM_DEST_NET)
-		v.sram_dest_reg_714.NET_Dest = target;
-	if (dest & FC_SRAM_DEST_CAI)
-		v.sram_dest_reg_714.CAI_Dest = target;
-	if (dest & FC_SRAM_DEST_CAO)
-		v.sram_dest_reg_714.CAO_Dest = target;
-	if (dest & FC_SRAM_DEST_MEDIA)
-		v.sram_dest_reg_714.MEDIA_Dest = target;
-
-	fc->write_ibi_reg(fc,sram_dest_reg_714,v);
-	udelay(1000); /* TODO delay really necessary */
-
-	return 0;
-}
-EXPORT_SYMBOL(flexcop_sram_set_dest);
-
-void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s)
-{
-	flexcop_set_ibi_value(wan_ctrl_reg_71c,wan_speed_sig,s);
-}
-EXPORT_SYMBOL(flexcop_wan_set_speed);
-
-void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill)
-{
-	flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714);
-	v.sram_dest_reg_714.ctrl_usb_wan = usb_wan;
-	v.sram_dest_reg_714.ctrl_sramdma = sramdma;
-	v.sram_dest_reg_714.ctrl_maximumfill = maximumfill;
-	fc->write_ibi_reg(fc,sram_dest_reg_714,v);
-}
-EXPORT_SYMBOL(flexcop_sram_ctrl);
-
-#if 0
-static void flexcop_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
-{
-	int i, retries;
-	u32 command;
-
-	for (i = 0; i < len; i++) {
-		command = bank | addr | 0x04000000 | (*buf << 0x10);
-
-		retries = 2;
-
-		while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
-			mdelay(1);
-			retries--;
-		};
-
-		if (retries == 0)
-			printk("%s: SRAM timeout\n", __func__);
-
-		write_reg_dw(adapter, 0x700, command);
-
-		buf++;
-		addr++;
-	}
-}
-
-static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
-{
-	int i, retries;
-	u32 command, value;
-
-	for (i = 0; i < len; i++) {
-		command = bank | addr | 0x04008000;
-
-		retries = 10000;
-
-		while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
-			mdelay(1);
-			retries--;
-		};
-
-		if (retries == 0)
-			printk("%s: SRAM timeout\n", __func__);
-
-		write_reg_dw(adapter, 0x700, command);
-
-		retries = 10000;
-
-		while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
-			mdelay(1);
-			retries--;
-		};
-
-		if (retries == 0)
-			printk("%s: SRAM timeout\n", __func__);
-
-		value = read_reg_dw(adapter, 0x700) >> 0x10;
-
-		*buf = (value & 0xff);
-
-		addr++;
-		buf++;
-	}
-}
-
-static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
-{
-	u32 bank;
-
-	bank = 0;
-
-	if (adapter->dw_sram_type == 0x20000) {
-		bank = (addr & 0x18000) << 0x0d;
-	}
-
-	if (adapter->dw_sram_type == 0x00000) {
-		if ((addr >> 0x0f) == 0)
-			bank = 0x20000000;
-		else
-			bank = 0x10000000;
-	}
-	flex_sram_write(adapter, bank, addr & 0x7fff, buf, len);
-}
-
-static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
-{
-	u32 bank;
-	bank = 0;
-
-	if (adapter->dw_sram_type == 0x20000) {
-		bank = (addr & 0x18000) << 0x0d;
-	}
-
-	if (adapter->dw_sram_type == 0x00000) {
-		if ((addr >> 0x0f) == 0)
-			bank = 0x20000000;
-		else
-			bank = 0x10000000;
-	}
-	flex_sram_read(adapter, bank, addr & 0x7fff, buf, len);
-}
-
-static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
-{
-	u32 length;
-	while (len != 0) {
-		length = len;
-		/* check if the address range belongs to the same
-		 * 32K memory chip. If not, the data is read
-		 * from one chip at a time */
-		if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
-			length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
-		}
-
-		sram_read_chunk(adapter, addr, buf, length);
-		addr = addr + length;
-		buf = buf + length;
-		len = len - length;
-	}
-}
-
-static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
-{
-	u32 length;
-	while (len != 0) {
-		length = len;
-
-		/* check if the address range belongs to the same
-		 * 32K memory chip. If not, the data is
-		 * written to one chip at a time */
-		if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
-			length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
-		}
-
-		sram_write_chunk(adapter, addr, buf, length);
-		addr = addr + length;
-		buf = buf + length;
-		len = len - length;
-	}
-}
-
-static void sram_set_size(struct adapter *adapter, u32 mask)
-{
-	write_reg_dw(adapter, 0x71c,
-			(mask | (~0x30000 & read_reg_dw(adapter, 0x71c))));
-}
-
-static void sram_init(struct adapter *adapter)
-{
-	u32 tmp;
-	tmp = read_reg_dw(adapter, 0x71c);
-	write_reg_dw(adapter, 0x71c, 1);
-
-	if (read_reg_dw(adapter, 0x71c) != 0) {
-		write_reg_dw(adapter, 0x71c, tmp);
-		adapter->dw_sram_type = tmp & 0x30000;
-		ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type);
-	} else {
-		adapter->dw_sram_type = 0x10000;
-		ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type);
-	}
-}
-
-static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
-{
-	u8 tmp1, tmp2;
-	dprintk("%s: mask = %x, addr = %x\n", __func__, mask, addr);
-
-	sram_set_size(adapter, mask);
-	sram_init(adapter);
-
-	tmp2 = 0xa5;
-	tmp1 = 0x4f;
-
-	sram_write(adapter, addr, &tmp2, 1);
-	sram_write(adapter, addr + 4, &tmp1, 1);
-
-	tmp2 = 0;
-	mdelay(20);
-
-	sram_read(adapter, addr, &tmp2, 1);
-	sram_read(adapter, addr, &tmp2, 1);
-
-	dprintk("%s: wrote 0xa5, read 0x%2x\n", __func__, tmp2);
-
-	if (tmp2 != 0xa5)
-		return 0;
-
-	tmp2 = 0x5a;
-	tmp1 = 0xf4;
-
-	sram_write(adapter, addr, &tmp2, 1);
-	sram_write(adapter, addr + 4, &tmp1, 1);
-
-	tmp2 = 0;
-	mdelay(20);
-
-	sram_read(adapter, addr, &tmp2, 1);
-	sram_read(adapter, addr, &tmp2, 1);
-
-	dprintk("%s: wrote 0x5a, read 0x%2x\n", __func__, tmp2);
-
-	if (tmp2 != 0x5a)
-		return 0;
-	return 1;
-}
-
-static u32 sram_length(struct adapter *adapter)
-{
-	if (adapter->dw_sram_type == 0x10000)
-		return 32768; /* 32K */
-	if (adapter->dw_sram_type == 0x00000)
-		return 65536; /* 64K */
-	if (adapter->dw_sram_type == 0x20000)
-		return 131072; /* 128K */
-	return 32768; /* 32K */
-}
-
-/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory.
-   - for 128K there are 4x32K chips at bank 0,1,2,3.
-   - for  64K there are 2x32K chips at bank 1,2.
-   - for  32K there is one 32K chip at bank 0.
-
-   FlexCop works only with one bank at a time. The bank is selected
-   by bits 28-29 of the 0x700 register.
-
-   bank 0 covers addresses 0x00000-0x07fff
-   bank 1 covers addresses 0x08000-0x0ffff
-   bank 2 covers addresses 0x10000-0x17fff
-   bank 3 covers addresses 0x18000-0x1ffff */
-
-static int flexcop_sram_detect(struct flexcop_device *fc)
-{
-	flexcop_ibi_value r208, r71c_0, vr71c_1;
-	r208 = fc->read_ibi_reg(fc, ctrl_208);
-	fc->write_ibi_reg(fc, ctrl_208, ibi_zero);
-
-	r71c_0 = fc->read_ibi_reg(fc, wan_ctrl_reg_71c);
-	write_reg_dw(adapter, 0x71c, 1);
-	tmp3 = read_reg_dw(adapter, 0x71c);
-	dprintk("%s: tmp3 = %x\n", __func__, tmp3);
-	write_reg_dw(adapter, 0x71c, tmp2);
-
-	// check for internal SRAM ???
-	tmp3--;
-	if (tmp3 != 0) {
-		sram_set_size(adapter, 0x10000);
-		sram_init(adapter);
-		write_reg_dw(adapter, 0x208, tmp);
-		dprintk("%s: sram size = 32K\n", __func__);
-		return 32;
-	}
-
-	if (sram_test_location(adapter, 0x20000, 0x18000) != 0) {
-		sram_set_size(adapter, 0x20000);
-		sram_init(adapter);
-		write_reg_dw(adapter, 0x208, tmp);
-		dprintk("%s: sram size = 128K\n", __func__);
-		return 128;
-	}
-
-	if (sram_test_location(adapter, 0x00000, 0x10000) != 0) {
-		sram_set_size(adapter, 0x00000);
-		sram_init(adapter);
-		write_reg_dw(adapter, 0x208, tmp);
-		dprintk("%s: sram size = 64K\n", __func__);
-		return 64;
-	}
-
-	if (sram_test_location(adapter, 0x10000, 0x00000) != 0) {
-		sram_set_size(adapter, 0x10000);
-		sram_init(adapter);
-		write_reg_dw(adapter, 0x208, tmp);
-		dprintk("%s: sram size = 32K\n", __func__);
-		return 32;
-	}
-
-	sram_set_size(adapter, 0x10000);
-	sram_init(adapter);
-	write_reg_dw(adapter, 0x208, tmp);
-	dprintk("%s: SRAM detection failed. Set to 32K \n", __func__);
-	return 0;
-}
-
-static void sll_detect_sram_size(struct adapter *adapter)
-{
-	sram_detect_for_flex2(adapter);
-}
-
-#endif
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c
deleted file mode 100644
index 26c666d..0000000
--- a/drivers/media/dvb/b2c2/flexcop-usb.c
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- * flexcop-usb.c - covers the USB part
- * see flexcop.c for copyright information
- */
-#define FC_LOG_PREFIX "flexcop_usb"
-#include "flexcop-usb.h"
-#include "flexcop-common.h"
-
-/* Version information */
-#define DRIVER_VERSION "0.1"
-#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver"
-#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
-
-/* debug */
-#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
-#define dprintk(level,args...) \
-	do { if ((debug & level)) printk(args); } while (0)
-
-#define debug_dump(b, l, method) do {\
-	int i; \
-	for (i = 0; i < l; i++) \
-		method("%02x ", b[i]); \
-	method("\n"); \
-} while (0)
-
-#define DEBSTATUS ""
-#else
-#define dprintk(level, args...)
-#define debug_dump(b, l, method)
-#define DEBSTATUS " (debugging is not enabled)"
-#endif
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,"
-		"ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS);
-#undef DEBSTATUS
-
-#define deb_info(args...) dprintk(0x01, args)
-#define deb_ts(args...) dprintk(0x02, args)
-#define deb_ctrl(args...) dprintk(0x04, args)
-#define deb_i2c(args...) dprintk(0x08, args)
-#define deb_v8(args...) dprintk(0x10, args)
-
-/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits
- * in the IBI address, to make the V8 code simpler.
- * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (the six bits used)
- *                  in general: 0000 0HHH 000L LL00
- * IBI ADDRESS FORMAT:                    RHHH BLLL
- *
- * where R is the read(1)/write(0) bit, B is the busy bit
- * and HHH and LLL are the two sets of three bits from the PCI address.
- */
-#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) \
-	(((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
-#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) \
-	(((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
-
-/*
- * DKT 020228
- * - forget about this VENDOR_BUFFER_SIZE, read and write register
- *   deal with DWORD or 4 bytes, that should be should from now on
- * - from now on, we don't support anything older than firm 1.00
- *   I eliminated the write register as a 2 trip of writing hi word and lo word
- *   and force this to write only 4 bytes at a time.
- *   NOTE: this should work with all the firmware from 1.00 and newer
- */
-static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI, u32 *val, u8 read)
-{
-	struct flexcop_usb *fc_usb = fc->bus_specific;
-	u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG;
-	u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR;
-	u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) |
-		(read ? 0x80 : 0);
-
-	int len = usb_control_msg(fc_usb->udev,
-			read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT,
-			request,
-			request_type, /* 0xc0 read or 0x40 write */
-			wAddress,
-			0,
-			val,
-			sizeof(u32),
-			B2C2_WAIT_FOR_OPERATION_RDW * HZ);
-
-	if (len != sizeof(u32)) {
-		err("error while %s dword from %d (%d).", read ? "reading" :
-				"writing", wAddress, wRegOffsPCI);
-		return -EIO;
-	}
-	return 0;
-}
-/*
- * DKT 010817 - add support for V8 memory read/write and flash update
- */
-static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
-		flexcop_usb_request_t req, u8 page, u16 wAddress,
-		u8 *pbBuffer, u32 buflen)
-{
-	u8 request_type = USB_TYPE_VENDOR;
-	u16 wIndex;
-	int nWaitTime, pipe, len;
-	wIndex = page << 8;
-
-	switch (req) {
-	case B2C2_USB_READ_V8_MEM:
-		nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
-		request_type |= USB_DIR_IN;
-		pipe = B2C2_USB_CTRL_PIPE_IN;
-		break;
-	case B2C2_USB_WRITE_V8_MEM:
-		wIndex |= pbBuffer[0];
-		request_type |= USB_DIR_OUT;
-		nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE;
-		pipe = B2C2_USB_CTRL_PIPE_OUT;
-		break;
-	case B2C2_USB_FLASH_BLOCK:
-		request_type |= USB_DIR_OUT;
-		nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH;
-		pipe = B2C2_USB_CTRL_PIPE_OUT;
-		break;
-	default:
-		deb_info("unsupported request for v8_mem_req %x.\n", req);
-		return -EINVAL;
-	}
-	deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n", request_type, req,
-			wAddress, wIndex, buflen);
-
-	len = usb_control_msg(fc_usb->udev, pipe,
-			req,
-			request_type,
-			wAddress,
-			wIndex,
-			pbBuffer,
-			buflen,
-			nWaitTime * HZ);
-
-	debug_dump(pbBuffer, len, deb_v8);
-	return len == buflen ? 0 : -EIO;
-}
-
-#define bytes_left_to_read_on_page(paddr,buflen) \
-	((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \
-	 ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)))
-
-static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
-		flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start,
-		u32 addr, int extended, u8 *buf, u32 len)
-{
-	int i,ret = 0;
-	u16 wMax;
-	u32 pagechunk = 0;
-
-	switch(req) {
-	case B2C2_USB_READ_V8_MEM:
-		wMax = USB_MEM_READ_MAX;
-		break;
-	case B2C2_USB_WRITE_V8_MEM:
-		wMax = USB_MEM_WRITE_MAX;
-		break;
-	case B2C2_USB_FLASH_BLOCK:
-		wMax = USB_FLASH_MAX;
-		break;
-	default:
-		return -EINVAL;
-		break;
-	}
-	for (i = 0; i < len;) {
-		pagechunk =
-			wMax < bytes_left_to_read_on_page(addr, len) ?
-				wMax :
-				bytes_left_to_read_on_page(addr, len);
-		deb_info("%x\n",
-			(addr & V8_MEMORY_PAGE_MASK) |
-				(V8_MEMORY_EXTENDED*extended));
-
-		ret = flexcop_usb_v8_memory_req(fc_usb, req,
-			page_start + (addr / V8_MEMORY_PAGE_SIZE),
-			(addr & V8_MEMORY_PAGE_MASK) |
-				(V8_MEMORY_EXTENDED*extended),
-			&buf[i], pagechunk);
-
-		if (ret < 0)
-			return ret;
-		addr += pagechunk;
-		len -= pagechunk;
-	}
-	return 0;
-}
-
-static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended)
-{
-	return flexcop_usb_memory_req(fc->bus_specific, B2C2_USB_READ_V8_MEM,
-		V8_MEMORY_PAGE_FLASH, 0x1f010, 1,
-		fc->dvb_adapter.proposed_mac, 6);
-}
-
-#if 0
-static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set,
-		flexcop_usb_utility_function_t func, u8 extra, u16 wIndex,
-		u16 buflen, u8 *pvBuffer)
-{
-	u16 wValue;
-	u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR;
-	int nWaitTime = 2,
-	    pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, len;
-	wValue = (func << 8) | extra;
-
-	len = usb_control_msg(fc_usb->udev,pipe,
-			B2C2_USB_UTILITY,
-			request_type,
-			wValue,
-			wIndex,
-			pvBuffer,
-			buflen,
-			nWaitTime * HZ);
-	return len == buflen ? 0 : -EIO;
-}
-#endif
-
-/* usb i2c stuff */
-static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
-		flexcop_usb_request_t req, flexcop_usb_i2c_function_t func,
-		u8 chipaddr, u8 addr, u8 *buf, u8 buflen)
-{
-	struct flexcop_usb *fc_usb = i2c->fc->bus_specific;
-	u16 wValue, wIndex;
-	int nWaitTime,pipe,len;
-	u8 request_type = USB_TYPE_VENDOR;
-
-	switch (func) {
-	case USB_FUNC_I2C_WRITE:
-	case USB_FUNC_I2C_MULTIWRITE:
-	case USB_FUNC_I2C_REPEATWRITE:
-		/* DKT 020208 - add this to support special case of DiSEqC */
-	case USB_FUNC_I2C_CHECKWRITE:
-		pipe = B2C2_USB_CTRL_PIPE_OUT;
-		nWaitTime = 2;
-		request_type |= USB_DIR_OUT;
-		break;
-	case USB_FUNC_I2C_READ:
-	case USB_FUNC_I2C_REPEATREAD:
-		pipe = B2C2_USB_CTRL_PIPE_IN;
-		nWaitTime = 2;
-		request_type |= USB_DIR_IN;
-		break;
-	default:
-		deb_info("unsupported function for i2c_req %x\n", func);
-		return -EINVAL;
-	}
-	wValue = (func << 8) | (i2c->port << 4);
-	wIndex = (chipaddr << 8 ) | addr;
-
-	deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",
-			func, request_type, req,
-			wValue & 0xff, wValue >> 8,
-			wIndex & 0xff, wIndex >> 8);
-
-	len = usb_control_msg(fc_usb->udev,pipe,
-			req,
-			request_type,
-			wValue,
-			wIndex,
-			buf,
-			buflen,
-			nWaitTime * HZ);
-	return len == buflen ? 0 : -EREMOTEIO;
-}
-
-/* actual bus specific access functions,
-   make sure prototype are/will be equal to pci */
-static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc,
-	flexcop_ibi_register reg)
-{
-	flexcop_ibi_value val;
-	val.raw = 0;
-	flexcop_usb_readwrite_dw(fc, reg, &val.raw, 1);
-	return val;
-}
-
-static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc,
-		flexcop_ibi_register reg, flexcop_ibi_value val)
-{
-	return flexcop_usb_readwrite_dw(fc, reg, &val.raw, 0);
-}
-
-static int flexcop_usb_i2c_request(struct flexcop_i2c_adapter *i2c,
-		flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
-{
-	if (op == FC_READ)
-		return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
-				USB_FUNC_I2C_READ, chipaddr, addr, buf, len);
-	else
-		return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
-				USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len);
-}
-
-static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb,
-	u8 *buffer, int buffer_length)
-{
-	u8 *b;
-	int l;
-
-	deb_ts("tmp_buffer_length=%d, buffer_length=%d\n",
-		fc_usb->tmp_buffer_length, buffer_length);
-
-	if (fc_usb->tmp_buffer_length > 0) {
-		memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer,
-				buffer_length);
-		fc_usb->tmp_buffer_length += buffer_length;
-		b = fc_usb->tmp_buffer;
-		l = fc_usb->tmp_buffer_length;
-	} else {
-		b=buffer;
-		l=buffer_length;
-	}
-
-	while (l >= 190) {
-		if (*b == 0xff) {
-			switch (*(b+1) & 0x03) {
-			case 0x01: /* media packet */
-				if (*(b+2) == 0x47)
-					flexcop_pass_dmx_packets(
-							fc_usb->fc_dev, b+2, 1);
-				else
-					deb_ts(
-					"not ts packet %02x %02x %02x %02x \n",
-						*(b+2), *(b+3),
-						*(b+4), *(b+5));
-				b += 190;
-				l -= 190;
-				break;
-			default:
-				deb_ts("wrong packet type\n");
-				l = 0;
-				break;
-			}
-		} else {
-			deb_ts("wrong header\n");
-			l = 0;
-		}
-	}
-
-	if (l>0)
-		memcpy(fc_usb->tmp_buffer, b, l);
-	fc_usb->tmp_buffer_length = l;
-}
-
-static void flexcop_usb_urb_complete(struct urb *urb)
-{
-	struct flexcop_usb *fc_usb = urb->context;
-	int i;
-
-	if (urb->actual_length > 0)
-		deb_ts("urb completed, bufsize: %d actlen; %d\n",
-			urb->transfer_buffer_length, urb->actual_length);
-
-	for (i = 0; i < urb->number_of_packets; i++) {
-		if (urb->iso_frame_desc[i].status < 0) {
-			err("iso frame descriptor %d has an error: %d\n", i,
-				urb->iso_frame_desc[i].status);
-		} else
-			if (urb->iso_frame_desc[i].actual_length > 0) {
-				deb_ts("passed %d bytes to the demux\n",
-					urb->iso_frame_desc[i].actual_length);
-
-				flexcop_usb_process_frame(fc_usb,
-					urb->transfer_buffer +
-						urb->iso_frame_desc[i].offset,
-					urb->iso_frame_desc[i].actual_length);
-			}
-		urb->iso_frame_desc[i].status = 0;
-		urb->iso_frame_desc[i].actual_length = 0;
-	}
-	usb_submit_urb(urb,GFP_ATOMIC);
-}
-
-static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff)
-{
-	/* submit/kill iso packets */
-	return 0;
-}
-
-static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
-{
-	int i;
-	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
-		if (fc_usb->iso_urb[i] != NULL) {
-			deb_ts("unlinking/killing urb no. %d\n",i);
-			usb_kill_urb(fc_usb->iso_urb[i]);
-			usb_free_urb(fc_usb->iso_urb[i]);
-		}
-
-	if (fc_usb->iso_buffer != NULL)
-		pci_free_consistent(NULL,
-			fc_usb->buffer_size, fc_usb->iso_buffer,
-			fc_usb->dma_addr);
-}
-
-static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
-{
-	u16 frame_size = le16_to_cpu(
-		fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize);
-	int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO *
-		frame_size, i, j, ret;
-	int buffer_offset = 0;
-
-	deb_ts("creating %d iso-urbs with %d frames "
-			"each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB,
-			B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize);
-
-	fc_usb->iso_buffer = pci_alloc_consistent(NULL,
-			bufsize, &fc_usb->dma_addr);
-	if (fc_usb->iso_buffer == NULL)
-		return -ENOMEM;
-
-	memset(fc_usb->iso_buffer, 0, bufsize);
-	fc_usb->buffer_size = bufsize;
-
-	/* creating iso urbs */
-	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
-		fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,
-			GFP_ATOMIC);
-		if (fc_usb->iso_urb[i] == NULL) {
-			ret = -ENOMEM;
-			goto urb_error;
-		}
-	}
-
-	/* initialising and submitting iso urbs */
-	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
-		int frame_offset = 0;
-		struct urb *urb = fc_usb->iso_urb[i];
-		deb_ts("initializing and submitting urb no. %d "
-			"(buf_offset: %d).\n", i, buffer_offset);
-
-		urb->dev = fc_usb->udev;
-		urb->context = fc_usb;
-		urb->complete = flexcop_usb_urb_complete;
-		urb->pipe = B2C2_USB_DATA_PIPE;
-		urb->transfer_flags = URB_ISO_ASAP;
-		urb->interval = 1;
-		urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO;
-		urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO;
-		urb->transfer_buffer = fc_usb->iso_buffer + buffer_offset;
-
-		buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO;
-		for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) {
-			deb_ts("urb no: %d, frame: %d, frame_offset: %d\n",
-					i, j, frame_offset);
-			urb->iso_frame_desc[j].offset = frame_offset;
-			urb->iso_frame_desc[j].length = frame_size;
-			frame_offset += frame_size;
-		}
-
-		if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) {
-			err("submitting urb %d failed with %d.", i, ret);
-			goto urb_error;
-		}
-		deb_ts("submitted urb no. %d.\n",i);
-	}
-
-	/* SRAM */
-	flexcop_sram_set_dest(fc_usb->fc_dev, FC_SRAM_DEST_MEDIA |
-			FC_SRAM_DEST_NET | FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI,
-			FC_SRAM_DEST_TARGET_WAN_USB);
-	flexcop_wan_set_speed(fc_usb->fc_dev, FC_WAN_SPEED_8MBITS);
-	flexcop_sram_ctrl(fc_usb->fc_dev, 1, 1, 1);
-	return 0;
-
-urb_error:
-	flexcop_usb_transfer_exit(fc_usb);
-	return ret;
-}
-
-static int flexcop_usb_init(struct flexcop_usb *fc_usb)
-{
-	/* use the alternate setting with the larges buffer */
-	usb_set_interface(fc_usb->udev,0,1);
-	switch (fc_usb->udev->speed) {
-	case USB_SPEED_LOW:
-		err("cannot handle USB speed because it is too slow.");
-		return -ENODEV;
-		break;
-	case USB_SPEED_FULL:
-		info("running at FULL speed.");
-		break;
-	case USB_SPEED_HIGH:
-		info("running at HIGH speed.");
-		break;
-	case USB_SPEED_UNKNOWN: /* fall through */
-	default:
-		err("cannot handle USB speed because it is unknown.");
-		return -ENODEV;
-	}
-	usb_set_intfdata(fc_usb->uintf, fc_usb);
-	return 0;
-}
-
-static void flexcop_usb_exit(struct flexcop_usb *fc_usb)
-{
-	usb_set_intfdata(fc_usb->uintf, NULL);
-}
-
-static int flexcop_usb_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	struct usb_device *udev = interface_to_usbdev(intf);
-	struct flexcop_usb *fc_usb = NULL;
-	struct flexcop_device *fc = NULL;
-	int ret;
-
-	if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) {
-		err("out of memory\n");
-		return -ENOMEM;
-	}
-
-	/* general flexcop init */
-	fc_usb = fc->bus_specific;
-	fc_usb->fc_dev = fc;
-
-	fc->read_ibi_reg  = flexcop_usb_read_ibi_reg;
-	fc->write_ibi_reg = flexcop_usb_write_ibi_reg;
-	fc->i2c_request = flexcop_usb_i2c_request;
-	fc->get_mac_addr = flexcop_usb_get_mac_addr;
-
-	fc->stream_control = flexcop_usb_stream_control;
-
-	fc->pid_filtering = 1;
-	fc->bus_type = FC_USB;
-
-	fc->dev = &udev->dev;
-	fc->owner = THIS_MODULE;
-
-	/* bus specific part */
-	fc_usb->udev = udev;
-	fc_usb->uintf = intf;
-	if ((ret = flexcop_usb_init(fc_usb)) != 0)
-		goto err_kfree;
-
-	/* init flexcop */
-	if ((ret = flexcop_device_initialize(fc)) != 0)
-		goto err_usb_exit;
-
-	/* xfer init */
-	if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0)
-		goto err_fc_exit;
-
-	info("%s successfully initialized and connected.", DRIVER_NAME);
-	return 0;
-
-err_fc_exit:
-	flexcop_device_exit(fc);
-err_usb_exit:
-	flexcop_usb_exit(fc_usb);
-err_kfree:
-	flexcop_device_kfree(fc);
-	return ret;
-}
-
-static void flexcop_usb_disconnect(struct usb_interface *intf)
-{
-	struct flexcop_usb *fc_usb = usb_get_intfdata(intf);
-	flexcop_usb_transfer_exit(fc_usb);
-	flexcop_device_exit(fc_usb->fc_dev);
-	flexcop_usb_exit(fc_usb);
-	flexcop_device_kfree(fc_usb->fc_dev);
-	info("%s successfully deinitialized and disconnected.", DRIVER_NAME);
-}
-
-static struct usb_device_id flexcop_usb_table [] = {
-	{ USB_DEVICE(0x0af7, 0x0101) },
-	{ }
-};
-MODULE_DEVICE_TABLE (usb, flexcop_usb_table);
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver flexcop_usb_driver = {
-	.name		= "b2c2_flexcop_usb",
-	.probe		= flexcop_usb_probe,
-	.disconnect = flexcop_usb_disconnect,
-	.id_table	= flexcop_usb_table,
-};
-
-module_usb_driver(flexcop_usb_driver);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_NAME);
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.h b/drivers/media/dvb/b2c2/flexcop-usb.h
deleted file mode 100644
index 92529a9..0000000
--- a/drivers/media/dvb/b2c2/flexcop-usb.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- * flexcop-usb.h - header file for the USB part
- * see flexcop.c for copyright information
- */
-#ifndef __FLEXCOP_USB_H_INCLUDED__
-#define __FLEXCOP_USB_H_INCLUDED__
-
-#include <linux/usb.h>
-
-/* transfer parameters */
-#define B2C2_USB_FRAMES_PER_ISO 4
-#define B2C2_USB_NUM_ISO_URB 4
-
-#define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(fc_usb->udev, 0)
-#define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(fc_usb->udev, 0)
-#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(fc_usb->udev, 0x81)
-
-struct flexcop_usb {
-	struct usb_device *udev;
-	struct usb_interface *uintf;
-
-	u8 *iso_buffer;
-	int buffer_size;
-	dma_addr_t dma_addr;
-
-	struct urb *iso_urb[B2C2_USB_NUM_ISO_URB];
-	struct flexcop_device *fc_dev;
-
-	u8 tmp_buffer[1023+190];
-	int tmp_buffer_length;
-};
-
-#if 0
-/* request types TODO What is its use?*/
-typedef enum {
-
-} flexcop_usb_request_type_t;
-#endif
-
-/* request */
-typedef enum {
-	B2C2_USB_WRITE_V8_MEM = 0x04,
-	B2C2_USB_READ_V8_MEM  = 0x05,
-	B2C2_USB_READ_REG     = 0x08,
-	B2C2_USB_WRITE_REG    = 0x0A,
-	B2C2_USB_WRITEREGHI   = 0x0B,
-	B2C2_USB_FLASH_BLOCK  = 0x10,
-	B2C2_USB_I2C_REQUEST  = 0x11,
-	B2C2_USB_UTILITY      = 0x12,
-} flexcop_usb_request_t;
-
-/* function definition for I2C_REQUEST */
-typedef enum {
-	USB_FUNC_I2C_WRITE       = 0x01,
-	USB_FUNC_I2C_MULTIWRITE  = 0x02,
-	USB_FUNC_I2C_READ        = 0x03,
-	USB_FUNC_I2C_REPEATWRITE = 0x04,
-	USB_FUNC_GET_DESCRIPTOR  = 0x05,
-	USB_FUNC_I2C_REPEATREAD  = 0x06,
-	/* DKT 020208 - add this to support special case of DiSEqC */
-	USB_FUNC_I2C_CHECKWRITE  = 0x07,
-	USB_FUNC_I2C_CHECKRESULT = 0x08,
-} flexcop_usb_i2c_function_t;
-
-/* function definition for UTILITY request 0x12
- * DKT 020304 - new utility function */
-typedef enum {
-	UTILITY_SET_FILTER          = 0x01,
-	UTILITY_DATA_ENABLE         = 0x02,
-	UTILITY_FLEX_MULTIWRITE     = 0x03,
-	UTILITY_SET_BUFFER_SIZE     = 0x04,
-	UTILITY_FLEX_OPERATOR       = 0x05,
-	UTILITY_FLEX_RESET300_START = 0x06,
-	UTILITY_FLEX_RESET300_STOP  = 0x07,
-	UTILITY_FLEX_RESET300       = 0x08,
-	UTILITY_SET_ISO_SIZE        = 0x09,
-	UTILITY_DATA_RESET          = 0x0A,
-	UTILITY_GET_DATA_STATUS     = 0x10,
-	UTILITY_GET_V8_REG          = 0x11,
-	/* DKT 020326 - add function for v1.14 */
-	UTILITY_SRAM_WRITE          = 0x12,
-	UTILITY_SRAM_READ           = 0x13,
-	UTILITY_SRAM_TESTFILL       = 0x14,
-	UTILITY_SRAM_TESTSET        = 0x15,
-	UTILITY_SRAM_TESTVERIFY     = 0x16,
-} flexcop_usb_utility_function_t;
-
-#define B2C2_WAIT_FOR_OPERATION_RW (1*HZ)
-#define B2C2_WAIT_FOR_OPERATION_RDW (3*HZ)
-#define B2C2_WAIT_FOR_OPERATION_WDW (1*HZ)
-
-#define B2C2_WAIT_FOR_OPERATION_V8READ (3*HZ)
-#define B2C2_WAIT_FOR_OPERATION_V8WRITE (3*HZ)
-#define B2C2_WAIT_FOR_OPERATION_V8FLASH (3*HZ)
-
-typedef enum {
-	V8_MEMORY_PAGE_DVB_CI = 0x20,
-	V8_MEMORY_PAGE_DVB_DS = 0x40,
-	V8_MEMORY_PAGE_MULTI2 = 0x60,
-	V8_MEMORY_PAGE_FLASH  = 0x80
-} flexcop_usb_mem_page_t;
-
-#define V8_MEMORY_EXTENDED (1 << 15)
-#define USB_MEM_READ_MAX   32
-#define USB_MEM_WRITE_MAX   1
-#define USB_FLASH_MAX       8
-#define V8_MEMORY_PAGE_SIZE 0x8000 /* 32K */
-#define V8_MEMORY_PAGE_MASK 0x7FFF
-
-#endif
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
deleted file mode 100644
index b1e8c99..0000000
--- a/drivers/media/dvb/b2c2/flexcop.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- * flexcop.c - main module part
- * Copyright (C) 2004-9 Patrick Boettcher <patrick.boettcher@desy.de>
- * based on skystar2-driver Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
- *
- * Acknowledgements:
- *   John Jurrius from BBTI, Inc. for extensive support
- *                    with code examples and data books
- *   Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting)
- *
- * Contributions to the skystar2-driver have been done by
- *   Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes)
- *   Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code)
- *   Uwe Bugla, uwe.bugla at gmx.de (doing tests, restyling code, writing docu)
- *   Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac
- *               filtering)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#include "flexcop.h"
-
-#define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip"
-#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de"
-
-#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
-#define DEBSTATUS ""
-#else
-#define DEBSTATUS " (debugging is not enabled)"
-#endif
-
-int b2c2_flexcop_debug;
-module_param_named(debug, b2c2_flexcop_debug,  int, 0644);
-MODULE_PARM_DESC(debug,
-		"set debug level (1=info,2=tuner,4=i2c,8=ts,"
-		"16=sram,32=reg (|-able))."
-		DEBSTATUS);
-#undef DEBSTATUS
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-/* global zero for ibi values */
-flexcop_ibi_value ibi_zero;
-
-static int flexcop_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct flexcop_device *fc = dvbdmxfeed->demux->priv;
-	return flexcop_pid_feed_control(fc, dvbdmxfeed, 1);
-}
-
-static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct flexcop_device *fc = dvbdmxfeed->demux->priv;
-	return flexcop_pid_feed_control(fc, dvbdmxfeed, 0);
-}
-
-static int flexcop_dvb_init(struct flexcop_device *fc)
-{
-	int ret = dvb_register_adapter(&fc->dvb_adapter,
-			"FlexCop Digital TV device", fc->owner,
-			fc->dev, adapter_nr);
-	if (ret < 0) {
-		err("error registering DVB adapter");
-		return ret;
-	}
-	fc->dvb_adapter.priv = fc;
-
-	fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING
-			| DMX_MEMORY_BASED_FILTERING);
-	fc->demux.priv = fc;
-	fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED;
-	fc->demux.start_feed = flexcop_dvb_start_feed;
-	fc->demux.stop_feed = flexcop_dvb_stop_feed;
-	fc->demux.write_to_decoder = NULL;
-
-	ret = dvb_dmx_init(&fc->demux);
-	if (ret < 0) {
-		err("dvb_dmx failed: error %d", ret);
-		goto err_dmx;
-	}
-
-	fc->hw_frontend.source = DMX_FRONTEND_0;
-
-	fc->dmxdev.filternum = fc->demux.feednum;
-	fc->dmxdev.demux = &fc->demux.dmx;
-	fc->dmxdev.capabilities = 0;
-	ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter);
-	if (ret < 0) {
-		err("dvb_dmxdev_init failed: error %d", ret);
-		goto err_dmx_dev;
-	}
-
-	ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend);
-	if (ret < 0) {
-		err("adding hw_frontend to dmx failed: error %d", ret);
-		goto err_dmx_add_hw_frontend;
-	}
-
-	fc->mem_frontend.source = DMX_MEMORY_FE;
-	ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend);
-	if (ret < 0) {
-		err("adding mem_frontend to dmx failed: error %d", ret);
-		goto err_dmx_add_mem_frontend;
-	}
-
-	ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend);
-	if (ret < 0) {
-		err("connect frontend failed: error %d", ret);
-		goto err_connect_frontend;
-	}
-
-	ret = dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
-	if (ret < 0) {
-		err("dvb_net_init failed: error %d", ret);
-		goto err_net;
-	}
-
-	fc->init_state |= FC_STATE_DVB_INIT;
-	return 0;
-
-err_net:
-	fc->demux.dmx.disconnect_frontend(&fc->demux.dmx);
-err_connect_frontend:
-	fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->mem_frontend);
-err_dmx_add_mem_frontend:
-	fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->hw_frontend);
-err_dmx_add_hw_frontend:
-	dvb_dmxdev_release(&fc->dmxdev);
-err_dmx_dev:
-	dvb_dmx_release(&fc->demux);
-err_dmx:
-	dvb_unregister_adapter(&fc->dvb_adapter);
-	return ret;
-}
-
-static void flexcop_dvb_exit(struct flexcop_device *fc)
-{
-	if (fc->init_state & FC_STATE_DVB_INIT) {
-		dvb_net_release(&fc->dvbnet);
-
-		fc->demux.dmx.close(&fc->demux.dmx);
-		fc->demux.dmx.remove_frontend(&fc->demux.dmx,
-			&fc->mem_frontend);
-		fc->demux.dmx.remove_frontend(&fc->demux.dmx,
-			&fc->hw_frontend);
-		dvb_dmxdev_release(&fc->dmxdev);
-		dvb_dmx_release(&fc->demux);
-		dvb_unregister_adapter(&fc->dvb_adapter);
-		deb_info("deinitialized dvb stuff\n");
-	}
-	fc->init_state &= ~FC_STATE_DVB_INIT;
-}
-
-/* these methods are necessary to achieve the long-term-goal of hiding the
- * struct flexcop_device from the bus-parts */
-void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len)
-{
-	dvb_dmx_swfilter(&fc->demux, buf, len);
-}
-EXPORT_SYMBOL(flexcop_pass_dmx_data);
-
-void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no)
-{
-	dvb_dmx_swfilter_packets(&fc->demux, buf, no);
-}
-EXPORT_SYMBOL(flexcop_pass_dmx_packets);
-
-static void flexcop_reset(struct flexcop_device *fc)
-{
-	flexcop_ibi_value v210, v204;
-
-	/* reset the flexcop itself */
-	fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
-
-	v210.raw = 0;
-	v210.sw_reset_210.reset_block_000 = 1;
-	v210.sw_reset_210.reset_block_100 = 1;
-	v210.sw_reset_210.reset_block_200 = 1;
-	v210.sw_reset_210.reset_block_300 = 1;
-	v210.sw_reset_210.reset_block_400 = 1;
-	v210.sw_reset_210.reset_block_500 = 1;
-	v210.sw_reset_210.reset_block_600 = 1;
-	v210.sw_reset_210.reset_block_700 = 1;
-	v210.sw_reset_210.Block_reset_enable = 0xb2;
-	v210.sw_reset_210.Special_controls = 0xc259;
-	fc->write_ibi_reg(fc,sw_reset_210,v210);
-	msleep(1);
-
-	/* reset the periphical devices */
-
-	v204 = fc->read_ibi_reg(fc,misc_204);
-	v204.misc_204.Per_reset_sig = 0;
-	fc->write_ibi_reg(fc,misc_204,v204);
-	msleep(1);
-	v204.misc_204.Per_reset_sig = 1;
-	fc->write_ibi_reg(fc,misc_204,v204);
-}
-
-void flexcop_reset_block_300(struct flexcop_device *fc)
-{
-	flexcop_ibi_value v208_save = fc->read_ibi_reg(fc, ctrl_208),
-			  v210 = fc->read_ibi_reg(fc, sw_reset_210);
-
-	deb_rdump("208: %08x, 210: %08x\n", v208_save.raw, v210.raw);
-	fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
-
-	v210.sw_reset_210.reset_block_300 = 1;
-	v210.sw_reset_210.Block_reset_enable = 0xb2;
-
-	fc->write_ibi_reg(fc,sw_reset_210,v210);
-	fc->write_ibi_reg(fc,ctrl_208,v208_save);
-}
-
-struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
-{
-	void *bus;
-	struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device),
-				GFP_KERNEL);
-	if (!fc) {
-		err("no memory");
-		return NULL;
-	}
-
-	bus = kzalloc(bus_specific_len, GFP_KERNEL);
-	if (!bus) {
-		err("no memory");
-		kfree(fc);
-		return NULL;
-	}
-
-	fc->bus_specific = bus;
-
-	return fc;
-}
-EXPORT_SYMBOL(flexcop_device_kmalloc);
-
-void flexcop_device_kfree(struct flexcop_device *fc)
-{
-	kfree(fc->bus_specific);
-	kfree(fc);
-}
-EXPORT_SYMBOL(flexcop_device_kfree);
-
-int flexcop_device_initialize(struct flexcop_device *fc)
-{
-	int ret;
-	ibi_zero.raw = 0;
-
-	flexcop_reset(fc);
-	flexcop_determine_revision(fc);
-	flexcop_sram_init(fc);
-	flexcop_hw_filter_init(fc);
-	flexcop_smc_ctrl(fc, 0);
-
-	ret = flexcop_dvb_init(fc);
-	if (ret)
-		goto error;
-
-	/* i2c has to be done before doing EEProm stuff -
-	 * because the EEProm is accessed via i2c */
-	ret = flexcop_i2c_init(fc);
-	if (ret)
-		goto error;
-
-	/* do the MAC address reading after initializing the dvb_adapter */
-	if (fc->get_mac_addr(fc, 0) == 0) {
-		u8 *b = fc->dvb_adapter.proposed_mac;
-		info("MAC address = %pM", b);
-		flexcop_set_mac_filter(fc,b);
-		flexcop_mac_filter_ctrl(fc,1);
-	} else
-		warn("reading of MAC address failed.\n");
-
-	ret = flexcop_frontend_init(fc);
-	if (ret)
-		goto error;
-
-	flexcop_device_name(fc,"initialization of","complete");
-	return 0;
-
-error:
-	flexcop_device_exit(fc);
-	return ret;
-}
-EXPORT_SYMBOL(flexcop_device_initialize);
-
-void flexcop_device_exit(struct flexcop_device *fc)
-{
-	flexcop_frontend_exit(fc);
-	flexcop_i2c_exit(fc);
-	flexcop_dvb_exit(fc);
-}
-EXPORT_SYMBOL(flexcop_device_exit);
-
-static int flexcop_module_init(void)
-{
-	info(DRIVER_NAME " loaded successfully");
-	return 0;
-}
-
-static void flexcop_module_cleanup(void)
-{
-	info(DRIVER_NAME " unloaded successfully");
-}
-
-module_init(flexcop_module_init);
-module_exit(flexcop_module_cleanup);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_NAME);
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/b2c2/flexcop.h b/drivers/media/dvb/b2c2/flexcop.h
deleted file mode 100644
index 897b10c..0000000
--- a/drivers/media/dvb/b2c2/flexcop.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- * flexcop.h - private header file for all flexcop-chip-source files
- * see flexcop.c for copyright information
- */
-#ifndef __FLEXCOP_H__
-#define __FLEXCOP_H___
-
-#define FC_LOG_PREFIX "b2c2-flexcop"
-#include "flexcop-common.h"
-
-extern int b2c2_flexcop_debug;
-
-/* debug */
-#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
-#define dprintk(level,args...) \
-	do { if ((b2c2_flexcop_debug & level)) printk(args); } while (0)
-#else
-#define dprintk(level,args...)
-#endif
-
-#define deb_info(args...) dprintk(0x01, args)
-#define deb_tuner(args...) dprintk(0x02, args)
-#define deb_i2c(args...) dprintk(0x04, args)
-#define deb_ts(args...) dprintk(0x08, args)
-#define deb_sram(args...) dprintk(0x10, args)
-#define deb_rdump(args...) dprintk(0x20, args)
-
-#endif
diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h
deleted file mode 100644
index 8f64bdb..0000000
--- a/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h
+++ /dev/null
@@ -1,455 +0,0 @@
-/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- * register descriptions
- * see flexcop.c for copyright information
- */
-/* This file is automatically generated, do not edit things here. */
-#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
-#define __FLEXCOP_IBI_VALUE_INCLUDED__
-
-typedef union {
-	u32 raw;
-
-	struct {
-		u32 dma_address0                   :30;
-		u32 dma_0No_update                 : 1;
-		u32 dma_0start                     : 1;
-	} dma_0x0;
-
-	struct {
-		u32 dma_addr_size                  :24;
-		u32 DMA_maxpackets                 : 8;
-	} dma_0x4_remap;
-
-	struct {
-		u32 dma_addr_size                  :24;
-		u32 unused                         : 1;
-		u32 dma1timer                      : 7;
-	} dma_0x4_read;
-
-	struct {
-		u32 dma_addr_size                  :24;
-		u32 dmatimer                       : 7;
-		u32 unused                         : 1;
-	} dma_0x4_write;
-
-	struct {
-		u32 dma_cur_addr                   :30;
-		u32 unused                         : 2;
-	} dma_0x8;
-
-	struct {
-		u32 dma_address1                   :30;
-		u32 remap_enable                   : 1;
-		u32 dma_1start                     : 1;
-	} dma_0xc;
-
-	struct {
-		u32 st_done                        : 1;
-		u32 no_base_addr_ack_error         : 1;
-		u32 twoWS_port_reg                 : 2;
-		u32 total_bytes                    : 2;
-		u32 twoWS_rw                       : 1;
-		u32 working_start                  : 1;
-		u32 data1_reg                      : 8;
-		u32 baseaddr                       : 8;
-		u32 reserved1                      : 1;
-		u32 chipaddr                       : 7;
-	} tw_sm_c_100;
-
-	struct {
-		u32 unused                         : 6;
-		u32 force_stop                     : 1;
-		u32 exlicit_stops                  : 1;
-		u32 data4_reg                      : 8;
-		u32 data3_reg                      : 8;
-		u32 data2_reg                      : 8;
-	} tw_sm_c_104;
-
-	struct {
-		u32 reserved2                      :19;
-		u32 tlo1                           : 5;
-		u32 reserved1                      : 2;
-		u32 thi1                           : 6;
-	} tw_sm_c_108;
-
-	struct {
-		u32 reserved2                      :19;
-		u32 tlo1                           : 5;
-		u32 reserved1                      : 2;
-		u32 thi1                           : 6;
-	} tw_sm_c_10c;
-
-	struct {
-		u32 reserved2                      :19;
-		u32 tlo1                           : 5;
-		u32 reserved1                      : 2;
-		u32 thi1                           : 6;
-	} tw_sm_c_110;
-
-	struct {
-		u32 LNB_CTLPrescaler_sig           : 2;
-		u32 LNB_CTLLowCount_sig            :15;
-		u32 LNB_CTLHighCount_sig           :15;
-	} lnb_switch_freq_200;
-
-	struct {
-		u32 Rev_N_sig_reserved2            : 1;
-		u32 Rev_N_sig_caps                 : 1;
-		u32 Rev_N_sig_reserved1            : 2;
-		u32 Rev_N_sig_revision_hi          : 4;
-		u32 reserved                       :20;
-		u32 Per_reset_sig                  : 1;
-		u32 LNB_L_H_sig                    : 1;
-		u32 ACPI3_sig                      : 1;
-		u32 ACPI1_sig                      : 1;
-	} misc_204;
-
-	struct {
-		u32 unused                         : 9;
-		u32 Mailbox_from_V8_Enable_sig     : 1;
-		u32 DMA2_Size_IRQ_Enable_sig       : 1;
-		u32 DMA1_Size_IRQ_Enable_sig       : 1;
-		u32 DMA2_Timer_Enable_sig          : 1;
-		u32 DMA2_IRQ_Enable_sig            : 1;
-		u32 DMA1_Timer_Enable_sig          : 1;
-		u32 DMA1_IRQ_Enable_sig            : 1;
-		u32 Rcv_Data_sig                   : 1;
-		u32 MAC_filter_Mode_sig            : 1;
-		u32 Multi2_Enable_sig              : 1;
-		u32 Per_CA_Enable_sig              : 1;
-		u32 SMC_Enable_sig                 : 1;
-		u32 CA_Enable_sig                  : 1;
-		u32 WAN_CA_Enable_sig              : 1;
-		u32 WAN_Enable_sig                 : 1;
-		u32 Mask_filter_sig                : 1;
-		u32 Null_filter_sig                : 1;
-		u32 ECM_filter_sig                 : 1;
-		u32 EMM_filter_sig                 : 1;
-		u32 PMT_filter_sig                 : 1;
-		u32 PCR_filter_sig                 : 1;
-		u32 Stream2_filter_sig             : 1;
-		u32 Stream1_filter_sig             : 1;
-	} ctrl_208;
-
-	struct {
-		u32 reserved                       :21;
-		u32 Transport_Error                : 1;
-		u32 LLC_SNAP_FLAG_set              : 1;
-		u32 Continuity_error_flag          : 1;
-		u32 Data_receiver_error            : 1;
-		u32 Mailbox_from_V8_Status_sig     : 1;
-		u32 DMA2_Size_IRQ_Status           : 1;
-		u32 DMA1_Size_IRQ_Status           : 1;
-		u32 DMA2_Timer_Status              : 1;
-		u32 DMA2_IRQ_Status                : 1;
-		u32 DMA1_Timer_Status              : 1;
-		u32 DMA1_IRQ_Status                : 1;
-	} irq_20c;
-
-	struct {
-		u32 Special_controls               :16;
-		u32 Block_reset_enable             : 8;
-		u32 reset_block_700                : 1;
-		u32 reset_block_600                : 1;
-		u32 reset_block_500                : 1;
-		u32 reset_block_400                : 1;
-		u32 reset_block_300                : 1;
-		u32 reset_block_200                : 1;
-		u32 reset_block_100                : 1;
-		u32 reset_block_000                : 1;
-	} sw_reset_210;
-
-	struct {
-		u32 unused2                        :20;
-		u32 polarity_PS_ERR_sig            : 1;
-		u32 polarity_PS_SYNC_sig           : 1;
-		u32 polarity_PS_VALID_sig          : 1;
-		u32 polarity_PS_CLK_sig            : 1;
-		u32 unused1                        : 3;
-		u32 s2p_sel_sig                    : 1;
-		u32 section_pkg_enable_sig         : 1;
-		u32 halt_V8_sig                    : 1;
-		u32 v2WS_oe_sig                    : 1;
-		u32 vuart_oe_sig                   : 1;
-	} misc_214;
-
-	struct {
-		u32 Mailbox_from_V8                :32;
-	} mbox_v8_to_host_218;
-
-	struct {
-		u32 sysramaccess_busmuster         : 1;
-		u32 sysramaccess_write             : 1;
-		u32 unused                         : 7;
-		u32 sysramaccess_addr              :15;
-		u32 sysramaccess_data              : 8;
-	} mbox_host_to_v8_21c;
-
-	struct {
-		u32 debug_fifo_problem             : 1;
-		u32 debug_flag_write_status00      : 1;
-		u32 Stream2_trans                  : 1;
-		u32 Stream2_PID                    :13;
-		u32 debug_flag_pid_saved           : 1;
-		u32 MAC_Multicast_filter           : 1;
-		u32 Stream1_trans                  : 1;
-		u32 Stream1_PID                    :13;
-	} pid_filter_300;
-
-	struct {
-		u32 reserved                       : 2;
-		u32 PMT_trans                      : 1;
-		u32 PMT_PID                        :13;
-		u32 debug_overrun2                 : 1;
-		u32 debug_overrun3                 : 1;
-		u32 PCR_trans                      : 1;
-		u32 PCR_PID                        :13;
-	} pid_filter_304;
-
-	struct {
-		u32 reserved                       : 2;
-		u32 ECM_trans                      : 1;
-		u32 ECM_PID                        :13;
-		u32 EMM_filter_6                   : 1;
-		u32 EMM_filter_4                   : 1;
-		u32 EMM_trans                      : 1;
-		u32 EMM_PID                        :13;
-	} pid_filter_308;
-
-	struct {
-		u32 unused2                        : 3;
-		u32 Group_mask                     :13;
-		u32 unused1                        : 2;
-		u32 Group_trans                    : 1;
-		u32 Group_PID                      :13;
-	} pid_filter_30c_ext_ind_0_7;
-
-	struct {
-		u32 unused                         :15;
-		u32 net_master_read                :17;
-	} pid_filter_30c_ext_ind_1;
-
-	struct {
-		u32 unused                         :15;
-		u32 net_master_write               :17;
-	} pid_filter_30c_ext_ind_2;
-
-	struct {
-		u32 unused                         :15;
-		u32 next_net_master_write          :17;
-	} pid_filter_30c_ext_ind_3;
-
-	struct {
-		u32 reserved2                      : 5;
-		u32 stack_read                     :10;
-		u32 reserved1                      : 6;
-		u32 state_write                    :10;
-		u32 unused1                        : 1;
-	} pid_filter_30c_ext_ind_4;
-
-	struct {
-		u32 unused                         :22;
-		u32 stack_cnt                      :10;
-	} pid_filter_30c_ext_ind_5;
-
-	struct {
-		u32 unused                         : 4;
-		u32 data_size_reg                  :12;
-		u32 write_status4                  : 2;
-		u32 write_status1                  : 2;
-		u32 pid_fsm_save_reg300            : 2;
-		u32 pid_fsm_save_reg4              : 2;
-		u32 pid_fsm_save_reg3              : 2;
-		u32 pid_fsm_save_reg2              : 2;
-		u32 pid_fsm_save_reg1              : 2;
-		u32 pid_fsm_save_reg0              : 2;
-	} pid_filter_30c_ext_ind_6;
-
-	struct {
-		u32 unused                         :22;
-		u32 pass_alltables                 : 1;
-		u32 AB_select                      : 1;
-		u32 extra_index_reg                : 3;
-		u32 index_reg                      : 5;
-	} index_reg_310;
-
-	struct {
-		u32 reserved                       :17;
-		u32 PID_enable_bit                 : 1;
-		u32 PID_trans                      : 1;
-		u32 PID                            :13;
-	} pid_n_reg_314;
-
-	struct {
-		u32 reserved                       : 6;
-		u32 HighAB_bit                     : 1;
-		u32 Enable_bit                     : 1;
-		u32 A6_byte                        : 8;
-		u32 A5_byte                        : 8;
-		u32 A4_byte                        : 8;
-	} mac_low_reg_318;
-
-	struct {
-		u32 reserved                       : 8;
-		u32 A3_byte                        : 8;
-		u32 A2_byte                        : 8;
-		u32 A1_byte                        : 8;
-	} mac_high_reg_31c;
-
-	struct {
-		u32 data_Tag_ID                    :16;
-		u32 reserved                       :16;
-	} data_tag_400;
-
-	struct {
-		u32 Card_IDbyte3                   : 8;
-		u32 Card_IDbyte4                   : 8;
-		u32 Card_IDbyte5                   : 8;
-		u32 Card_IDbyte6                   : 8;
-	} card_id_408;
-
-	struct {
-		u32 Card_IDbyte1                   : 8;
-		u32 Card_IDbyte2                   : 8;
-	} card_id_40c;
-
-	struct {
-		u32 MAC6                           : 8;
-		u32 MAC3                           : 8;
-		u32 MAC2                           : 8;
-		u32 MAC1                           : 8;
-	} mac_address_418;
-
-	struct {
-		u32 reserved                       :16;
-		u32 MAC8                           : 8;
-		u32 MAC7                           : 8;
-	} mac_address_41c;
-
-	struct {
-		u32 reserved                       :21;
-		u32 txbuffempty                    : 1;
-		u32 ReceiveByteFrameError          : 1;
-		u32 ReceiveDataReady               : 1;
-		u32 transmitter_data_byte          : 8;
-	} ci_600;
-
-	struct {
-		u32 pi_component_reg               : 3;
-		u32 pi_rw                          : 1;
-		u32 pi_ha                          :20;
-		u32 pi_d                           : 8;
-	} pi_604;
-
-	struct {
-		u32 pi_busy_n                      : 1;
-		u32 pi_wait_n                      : 1;
-		u32 pi_timeout_status              : 1;
-		u32 pi_CiMax_IRQ_n                 : 1;
-		u32 config_cclk                    : 1;
-		u32 config_cs_n                    : 1;
-		u32 config_wr_n                    : 1;
-		u32 config_Prog_n                  : 1;
-		u32 config_Init_stat               : 1;
-		u32 config_Done_stat               : 1;
-		u32 pcmcia_b_mod_pwr_n             : 1;
-		u32 pcmcia_a_mod_pwr_n             : 1;
-		u32 reserved                       : 3;
-		u32 Timer_addr                     : 5;
-		u32 unused                         : 1;
-		u32 timer_data                     : 7;
-		u32 Timer_Load_req                 : 1;
-		u32 Timer_Read_req                 : 1;
-		u32 oncecycle_read                 : 1;
-		u32 serialReset                    : 1;
-	} pi_608;
-
-	struct {
-		u32 reserved                       : 6;
-		u32 rw_flag                        : 1;
-		u32 dvb_en                         : 1;
-		u32 key_array_row                  : 5;
-		u32 key_array_col                  : 3;
-		u32 key_code                       : 2;
-		u32 key_enable                     : 1;
-		u32 PID                            :13;
-	} dvb_reg_60c;
-
-	struct {
-		u32 start_sram_ibi                 : 1;
-		u32 reserved2                      : 1;
-		u32 ce_pin_reg                     : 1;
-		u32 oe_pin_reg                     : 1;
-		u32 reserved1                      : 3;
-		u32 sc_xfer_bit                    : 1;
-		u32 sram_data                      : 8;
-		u32 sram_rw                        : 1;
-		u32 sram_addr                      :15;
-	} sram_ctrl_reg_700;
-
-	struct {
-		u32 net_addr_write                 :16;
-		u32 net_addr_read                  :16;
-	} net_buf_reg_704;
-
-	struct {
-		u32 cai_cnt                        : 4;
-		u32 reserved2                      : 6;
-		u32 cai_write                      :11;
-		u32 reserved1                      : 5;
-		u32 cai_read                       :11;
-	} cai_buf_reg_708;
-
-	struct {
-		u32 cao_cnt                        : 4;
-		u32 reserved2                      : 6;
-		u32 cap_write                      :11;
-		u32 reserved1                      : 5;
-		u32 cao_read                       :11;
-	} cao_buf_reg_70c;
-
-	struct {
-		u32 media_cnt                      : 4;
-		u32 reserved2                      : 6;
-		u32 media_write                    :11;
-		u32 reserved1                      : 5;
-		u32 media_read                     :11;
-	} media_buf_reg_710;
-
-	struct {
-		u32 reserved                       :17;
-		u32 ctrl_maximumfill               : 1;
-		u32 ctrl_sramdma                   : 1;
-		u32 ctrl_usb_wan                   : 1;
-		u32 cao_ovflow_error               : 1;
-		u32 cai_ovflow_error               : 1;
-		u32 media_ovflow_error             : 1;
-		u32 net_ovflow_error               : 1;
-		u32 MEDIA_Dest                     : 2;
-		u32 CAO_Dest                       : 2;
-		u32 CAI_Dest                       : 2;
-		u32 NET_Dest                       : 2;
-	} sram_dest_reg_714;
-
-	struct {
-		u32 reserved3                      :11;
-		u32 net_addr_write                 : 1;
-		u32 reserved2                      : 3;
-		u32 net_addr_read                  : 1;
-		u32 reserved1                      : 4;
-		u32 net_cnt                        :12;
-	} net_buf_reg_718;
-
-	struct {
-		u32 reserved3                      : 4;
-		u32 wan_pkt_frame                  : 4;
-		u32 reserved2                      : 4;
-		u32 sram_memmap                    : 2;
-		u32 sram_chip                      : 2;
-		u32 wan_wait_state                 : 8;
-		u32 reserved1                      : 6;
-		u32 wan_speed_sig                  : 2;
-	} wan_ctrl_reg_71c;
-} flexcop_ibi_value;
-
-#endif
diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h
deleted file mode 100644
index c75830d..0000000
--- a/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h
+++ /dev/null
@@ -1,455 +0,0 @@
-/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- * register descriptions
- * see flexcop.c for copyright information
- */
-/* This file is automatically generated, do not edit things here. */
-#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
-#define __FLEXCOP_IBI_VALUE_INCLUDED__
-
-typedef union {
-	u32 raw;
-
-	struct {
-		u32 dma_0start                     : 1;
-		u32 dma_0No_update                 : 1;
-		u32 dma_address0                   :30;
-	} dma_0x0;
-
-	struct {
-		u32 DMA_maxpackets                 : 8;
-		u32 dma_addr_size                  :24;
-	} dma_0x4_remap;
-
-	struct {
-		u32 dma1timer                      : 7;
-		u32 unused                         : 1;
-		u32 dma_addr_size                  :24;
-	} dma_0x4_read;
-
-	struct {
-		u32 unused                         : 1;
-		u32 dmatimer                       : 7;
-		u32 dma_addr_size                  :24;
-	} dma_0x4_write;
-
-	struct {
-		u32 unused                         : 2;
-		u32 dma_cur_addr                   :30;
-	} dma_0x8;
-
-	struct {
-		u32 dma_1start                     : 1;
-		u32 remap_enable                   : 1;
-		u32 dma_address1                   :30;
-	} dma_0xc;
-
-	struct {
-		u32 chipaddr                       : 7;
-		u32 reserved1                      : 1;
-		u32 baseaddr                       : 8;
-		u32 data1_reg                      : 8;
-		u32 working_start                  : 1;
-		u32 twoWS_rw                       : 1;
-		u32 total_bytes                    : 2;
-		u32 twoWS_port_reg                 : 2;
-		u32 no_base_addr_ack_error         : 1;
-		u32 st_done                        : 1;
-	} tw_sm_c_100;
-
-	struct {
-		u32 data2_reg                      : 8;
-		u32 data3_reg                      : 8;
-		u32 data4_reg                      : 8;
-		u32 exlicit_stops                  : 1;
-		u32 force_stop                     : 1;
-		u32 unused                         : 6;
-	} tw_sm_c_104;
-
-	struct {
-		u32 thi1                           : 6;
-		u32 reserved1                      : 2;
-		u32 tlo1                           : 5;
-		u32 reserved2                      :19;
-	} tw_sm_c_108;
-
-	struct {
-		u32 thi1                           : 6;
-		u32 reserved1                      : 2;
-		u32 tlo1                           : 5;
-		u32 reserved2                      :19;
-	} tw_sm_c_10c;
-
-	struct {
-		u32 thi1                           : 6;
-		u32 reserved1                      : 2;
-		u32 tlo1                           : 5;
-		u32 reserved2                      :19;
-	} tw_sm_c_110;
-
-	struct {
-		u32 LNB_CTLHighCount_sig           :15;
-		u32 LNB_CTLLowCount_sig            :15;
-		u32 LNB_CTLPrescaler_sig           : 2;
-	} lnb_switch_freq_200;
-
-	struct {
-		u32 ACPI1_sig                      : 1;
-		u32 ACPI3_sig                      : 1;
-		u32 LNB_L_H_sig                    : 1;
-		u32 Per_reset_sig                  : 1;
-		u32 reserved                       :20;
-		u32 Rev_N_sig_revision_hi          : 4;
-		u32 Rev_N_sig_reserved1            : 2;
-		u32 Rev_N_sig_caps                 : 1;
-		u32 Rev_N_sig_reserved2            : 1;
-	} misc_204;
-
-	struct {
-		u32 Stream1_filter_sig             : 1;
-		u32 Stream2_filter_sig             : 1;
-		u32 PCR_filter_sig                 : 1;
-		u32 PMT_filter_sig                 : 1;
-		u32 EMM_filter_sig                 : 1;
-		u32 ECM_filter_sig                 : 1;
-		u32 Null_filter_sig                : 1;
-		u32 Mask_filter_sig                : 1;
-		u32 WAN_Enable_sig                 : 1;
-		u32 WAN_CA_Enable_sig              : 1;
-		u32 CA_Enable_sig                  : 1;
-		u32 SMC_Enable_sig                 : 1;
-		u32 Per_CA_Enable_sig              : 1;
-		u32 Multi2_Enable_sig              : 1;
-		u32 MAC_filter_Mode_sig            : 1;
-		u32 Rcv_Data_sig                   : 1;
-		u32 DMA1_IRQ_Enable_sig            : 1;
-		u32 DMA1_Timer_Enable_sig          : 1;
-		u32 DMA2_IRQ_Enable_sig            : 1;
-		u32 DMA2_Timer_Enable_sig          : 1;
-		u32 DMA1_Size_IRQ_Enable_sig       : 1;
-		u32 DMA2_Size_IRQ_Enable_sig       : 1;
-		u32 Mailbox_from_V8_Enable_sig     : 1;
-		u32 unused                         : 9;
-	} ctrl_208;
-
-	struct {
-		u32 DMA1_IRQ_Status                : 1;
-		u32 DMA1_Timer_Status              : 1;
-		u32 DMA2_IRQ_Status                : 1;
-		u32 DMA2_Timer_Status              : 1;
-		u32 DMA1_Size_IRQ_Status           : 1;
-		u32 DMA2_Size_IRQ_Status           : 1;
-		u32 Mailbox_from_V8_Status_sig     : 1;
-		u32 Data_receiver_error            : 1;
-		u32 Continuity_error_flag          : 1;
-		u32 LLC_SNAP_FLAG_set              : 1;
-		u32 Transport_Error                : 1;
-		u32 reserved                       :21;
-	} irq_20c;
-
-	struct {
-		u32 reset_block_000                : 1;
-		u32 reset_block_100                : 1;
-		u32 reset_block_200                : 1;
-		u32 reset_block_300                : 1;
-		u32 reset_block_400                : 1;
-		u32 reset_block_500                : 1;
-		u32 reset_block_600                : 1;
-		u32 reset_block_700                : 1;
-		u32 Block_reset_enable             : 8;
-		u32 Special_controls               :16;
-	} sw_reset_210;
-
-	struct {
-		u32 vuart_oe_sig                   : 1;
-		u32 v2WS_oe_sig                    : 1;
-		u32 halt_V8_sig                    : 1;
-		u32 section_pkg_enable_sig         : 1;
-		u32 s2p_sel_sig                    : 1;
-		u32 unused1                        : 3;
-		u32 polarity_PS_CLK_sig            : 1;
-		u32 polarity_PS_VALID_sig          : 1;
-		u32 polarity_PS_SYNC_sig           : 1;
-		u32 polarity_PS_ERR_sig            : 1;
-		u32 unused2                        :20;
-	} misc_214;
-
-	struct {
-		u32 Mailbox_from_V8                :32;
-	} mbox_v8_to_host_218;
-
-	struct {
-		u32 sysramaccess_data              : 8;
-		u32 sysramaccess_addr              :15;
-		u32 unused                         : 7;
-		u32 sysramaccess_write             : 1;
-		u32 sysramaccess_busmuster         : 1;
-	} mbox_host_to_v8_21c;
-
-	struct {
-		u32 Stream1_PID                    :13;
-		u32 Stream1_trans                  : 1;
-		u32 MAC_Multicast_filter           : 1;
-		u32 debug_flag_pid_saved           : 1;
-		u32 Stream2_PID                    :13;
-		u32 Stream2_trans                  : 1;
-		u32 debug_flag_write_status00      : 1;
-		u32 debug_fifo_problem             : 1;
-	} pid_filter_300;
-
-	struct {
-		u32 PCR_PID                        :13;
-		u32 PCR_trans                      : 1;
-		u32 debug_overrun3                 : 1;
-		u32 debug_overrun2                 : 1;
-		u32 PMT_PID                        :13;
-		u32 PMT_trans                      : 1;
-		u32 reserved                       : 2;
-	} pid_filter_304;
-
-	struct {
-		u32 EMM_PID                        :13;
-		u32 EMM_trans                      : 1;
-		u32 EMM_filter_4                   : 1;
-		u32 EMM_filter_6                   : 1;
-		u32 ECM_PID                        :13;
-		u32 ECM_trans                      : 1;
-		u32 reserved                       : 2;
-	} pid_filter_308;
-
-	struct {
-		u32 Group_PID                      :13;
-		u32 Group_trans                    : 1;
-		u32 unused1                        : 2;
-		u32 Group_mask                     :13;
-		u32 unused2                        : 3;
-	} pid_filter_30c_ext_ind_0_7;
-
-	struct {
-		u32 net_master_read                :17;
-		u32 unused                         :15;
-	} pid_filter_30c_ext_ind_1;
-
-	struct {
-		u32 net_master_write               :17;
-		u32 unused                         :15;
-	} pid_filter_30c_ext_ind_2;
-
-	struct {
-		u32 next_net_master_write          :17;
-		u32 unused                         :15;
-	} pid_filter_30c_ext_ind_3;
-
-	struct {
-		u32 unused1                        : 1;
-		u32 state_write                    :10;
-		u32 reserved1                      : 6;
-		u32 stack_read                     :10;
-		u32 reserved2                      : 5;
-	} pid_filter_30c_ext_ind_4;
-
-	struct {
-		u32 stack_cnt                      :10;
-		u32 unused                         :22;
-	} pid_filter_30c_ext_ind_5;
-
-	struct {
-		u32 pid_fsm_save_reg0              : 2;
-		u32 pid_fsm_save_reg1              : 2;
-		u32 pid_fsm_save_reg2              : 2;
-		u32 pid_fsm_save_reg3              : 2;
-		u32 pid_fsm_save_reg4              : 2;
-		u32 pid_fsm_save_reg300            : 2;
-		u32 write_status1                  : 2;
-		u32 write_status4                  : 2;
-		u32 data_size_reg                  :12;
-		u32 unused                         : 4;
-	} pid_filter_30c_ext_ind_6;
-
-	struct {
-		u32 index_reg                      : 5;
-		u32 extra_index_reg                : 3;
-		u32 AB_select                      : 1;
-		u32 pass_alltables                 : 1;
-		u32 unused                         :22;
-	} index_reg_310;
-
-	struct {
-		u32 PID                            :13;
-		u32 PID_trans                      : 1;
-		u32 PID_enable_bit                 : 1;
-		u32 reserved                       :17;
-	} pid_n_reg_314;
-
-	struct {
-		u32 A4_byte                        : 8;
-		u32 A5_byte                        : 8;
-		u32 A6_byte                        : 8;
-		u32 Enable_bit                     : 1;
-		u32 HighAB_bit                     : 1;
-		u32 reserved                       : 6;
-	} mac_low_reg_318;
-
-	struct {
-		u32 A1_byte                        : 8;
-		u32 A2_byte                        : 8;
-		u32 A3_byte                        : 8;
-		u32 reserved                       : 8;
-	} mac_high_reg_31c;
-
-	struct {
-		u32 reserved                       :16;
-		u32 data_Tag_ID                    :16;
-	} data_tag_400;
-
-	struct {
-		u32 Card_IDbyte6                   : 8;
-		u32 Card_IDbyte5                   : 8;
-		u32 Card_IDbyte4                   : 8;
-		u32 Card_IDbyte3                   : 8;
-	} card_id_408;
-
-	struct {
-		u32 Card_IDbyte2                   : 8;
-		u32 Card_IDbyte1                   : 8;
-	} card_id_40c;
-
-	struct {
-		u32 MAC1                           : 8;
-		u32 MAC2                           : 8;
-		u32 MAC3                           : 8;
-		u32 MAC6                           : 8;
-	} mac_address_418;
-
-	struct {
-		u32 MAC7                           : 8;
-		u32 MAC8                           : 8;
-		u32 reserved                       :16;
-	} mac_address_41c;
-
-	struct {
-		u32 transmitter_data_byte          : 8;
-		u32 ReceiveDataReady               : 1;
-		u32 ReceiveByteFrameError          : 1;
-		u32 txbuffempty                    : 1;
-		u32 reserved                       :21;
-	} ci_600;
-
-	struct {
-		u32 pi_d                           : 8;
-		u32 pi_ha                          :20;
-		u32 pi_rw                          : 1;
-		u32 pi_component_reg               : 3;
-	} pi_604;
-
-	struct {
-		u32 serialReset                    : 1;
-		u32 oncecycle_read                 : 1;
-		u32 Timer_Read_req                 : 1;
-		u32 Timer_Load_req                 : 1;
-		u32 timer_data                     : 7;
-		u32 unused                         : 1;
-		u32 Timer_addr                     : 5;
-		u32 reserved                       : 3;
-		u32 pcmcia_a_mod_pwr_n             : 1;
-		u32 pcmcia_b_mod_pwr_n             : 1;
-		u32 config_Done_stat               : 1;
-		u32 config_Init_stat               : 1;
-		u32 config_Prog_n                  : 1;
-		u32 config_wr_n                    : 1;
-		u32 config_cs_n                    : 1;
-		u32 config_cclk                    : 1;
-		u32 pi_CiMax_IRQ_n                 : 1;
-		u32 pi_timeout_status              : 1;
-		u32 pi_wait_n                      : 1;
-		u32 pi_busy_n                      : 1;
-	} pi_608;
-
-	struct {
-		u32 PID                            :13;
-		u32 key_enable                     : 1;
-		u32 key_code                       : 2;
-		u32 key_array_col                  : 3;
-		u32 key_array_row                  : 5;
-		u32 dvb_en                         : 1;
-		u32 rw_flag                        : 1;
-		u32 reserved                       : 6;
-	} dvb_reg_60c;
-
-	struct {
-		u32 sram_addr                      :15;
-		u32 sram_rw                        : 1;
-		u32 sram_data                      : 8;
-		u32 sc_xfer_bit                    : 1;
-		u32 reserved1                      : 3;
-		u32 oe_pin_reg                     : 1;
-		u32 ce_pin_reg                     : 1;
-		u32 reserved2                      : 1;
-		u32 start_sram_ibi                 : 1;
-	} sram_ctrl_reg_700;
-
-	struct {
-		u32 net_addr_read                  :16;
-		u32 net_addr_write                 :16;
-	} net_buf_reg_704;
-
-	struct {
-		u32 cai_read                       :11;
-		u32 reserved1                      : 5;
-		u32 cai_write                      :11;
-		u32 reserved2                      : 6;
-		u32 cai_cnt                        : 4;
-	} cai_buf_reg_708;
-
-	struct {
-		u32 cao_read                       :11;
-		u32 reserved1                      : 5;
-		u32 cap_write                      :11;
-		u32 reserved2                      : 6;
-		u32 cao_cnt                        : 4;
-	} cao_buf_reg_70c;
-
-	struct {
-		u32 media_read                     :11;
-		u32 reserved1                      : 5;
-		u32 media_write                    :11;
-		u32 reserved2                      : 6;
-		u32 media_cnt                      : 4;
-	} media_buf_reg_710;
-
-	struct {
-		u32 NET_Dest                       : 2;
-		u32 CAI_Dest                       : 2;
-		u32 CAO_Dest                       : 2;
-		u32 MEDIA_Dest                     : 2;
-		u32 net_ovflow_error               : 1;
-		u32 media_ovflow_error             : 1;
-		u32 cai_ovflow_error               : 1;
-		u32 cao_ovflow_error               : 1;
-		u32 ctrl_usb_wan                   : 1;
-		u32 ctrl_sramdma                   : 1;
-		u32 ctrl_maximumfill               : 1;
-		u32 reserved                       :17;
-	} sram_dest_reg_714;
-
-	struct {
-		u32 net_cnt                        :12;
-		u32 reserved1                      : 4;
-		u32 net_addr_read                  : 1;
-		u32 reserved2                      : 3;
-		u32 net_addr_write                 : 1;
-		u32 reserved3                      :11;
-	} net_buf_reg_718;
-
-	struct {
-		u32 wan_speed_sig                  : 2;
-		u32 reserved1                      : 6;
-		u32 wan_wait_state                 : 8;
-		u32 sram_chip                      : 2;
-		u32 sram_memmap                    : 2;
-		u32 reserved2                      : 4;
-		u32 wan_pkt_frame                  : 4;
-		u32 reserved3                      : 4;
-	} wan_ctrl_reg_71c;
-} flexcop_ibi_value;
-
-#endif
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
deleted file mode 100644
index 8668e63..0000000
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ /dev/null
@@ -1,22 +0,0 @@
-config DVB_BT8XX
-	tristate "BT8xx based PCI cards"
-	depends on DVB_CORE && PCI && I2C && VIDEO_BT848
-	select DVB_MT352 if !DVB_FE_CUSTOMISE
-	select DVB_SP887X if !DVB_FE_CUSTOMISE
-	select DVB_NXT6000 if !DVB_FE_CUSTOMISE
-	select DVB_CX24110 if !DVB_FE_CUSTOMISE
-	select DVB_OR51211 if !DVB_FE_CUSTOMISE
-	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
-	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
-	help
-	  Support for PCI cards based on the Bt8xx PCI bridge. Examples are
-	  the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
-	  the pcHDTV HD2000 cards, the DViCO FusionHDTV Lite cards, and
-	  some AVerMedia cards.
-
-	  Since these cards have no MPEG decoder onboard, they transmit
-	  only compressed MPEG data over the PCI bus, so you need
-	  an external software decoder to watch TV on your computer.
-
-	  Say Y if you own such a device and want to use it.
diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile
deleted file mode 100644
index 0713b3a..0000000
--- a/drivers/media/dvb/bt8xx/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
-ccflags-y += -Idrivers/media/video/bt8xx
-ccflags-y += -Idrivers/media/common/tuners
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
deleted file mode 100644
index b34fa95..0000000
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ /dev/null
@@ -1,609 +0,0 @@
-/*
- * bt878.c: part of the driver for the Pinnacle PCTV Sat DVB PCI card
- *
- * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de>
- *
- * large parts based on the bttv driver
- * Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@metzlerbros.de)
- *                        & Marcus Metzler (mocm@metzlerbros.de)
- * (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <linux/ioport.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/kmod.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "bt878.h"
-#include "dst_priv.h"
-
-
-/**************************************/
-/* Miscellaneous utility  definitions */
-/**************************************/
-
-static unsigned int bt878_verbose = 1;
-static unsigned int bt878_debug;
-
-module_param_named(verbose, bt878_verbose, int, 0444);
-MODULE_PARM_DESC(verbose,
-		 "verbose startup messages, default is 1 (yes)");
-module_param_named(debug, bt878_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off).");
-
-int bt878_num;
-struct bt878 bt878[BT878_MAX];
-
-EXPORT_SYMBOL(bt878_num);
-EXPORT_SYMBOL(bt878);
-
-#define btwrite(dat,adr)    bmtwrite((dat), (bt->bt878_mem+(adr)))
-#define btread(adr)         bmtread(bt->bt878_mem+(adr))
-
-#define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
-#define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
-#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
-
-#if defined(dprintk)
-#undef dprintk
-#endif
-#define dprintk(fmt, arg...) \
-	do { \
-		if (bt878_debug) \
-			printk(KERN_DEBUG fmt, ##arg); \
-	} while (0)
-
-static void bt878_mem_free(struct bt878 *bt)
-{
-	if (bt->buf_cpu) {
-		pci_free_consistent(bt->dev, bt->buf_size, bt->buf_cpu,
-				    bt->buf_dma);
-		bt->buf_cpu = NULL;
-	}
-
-	if (bt->risc_cpu) {
-		pci_free_consistent(bt->dev, bt->risc_size, bt->risc_cpu,
-				    bt->risc_dma);
-		bt->risc_cpu = NULL;
-	}
-}
-
-static int bt878_mem_alloc(struct bt878 *bt)
-{
-	if (!bt->buf_cpu) {
-		bt->buf_size = 128 * 1024;
-
-		bt->buf_cpu =
-		    pci_alloc_consistent(bt->dev, bt->buf_size,
-					 &bt->buf_dma);
-
-		if (!bt->buf_cpu)
-			return -ENOMEM;
-
-		memset(bt->buf_cpu, 0, bt->buf_size);
-	}
-
-	if (!bt->risc_cpu) {
-		bt->risc_size = PAGE_SIZE;
-		bt->risc_cpu =
-		    pci_alloc_consistent(bt->dev, bt->risc_size,
-					 &bt->risc_dma);
-
-		if (!bt->risc_cpu) {
-			bt878_mem_free(bt);
-			return -ENOMEM;
-		}
-
-		memset(bt->risc_cpu, 0, bt->risc_size);
-	}
-
-	return 0;
-}
-
-/* RISC instructions */
-#define RISC_WRITE		(0x01 << 28)
-#define RISC_JUMP		(0x07 << 28)
-#define RISC_SYNC		(0x08 << 28)
-
-/* RISC bits */
-#define RISC_WR_SOL		(1 << 27)
-#define RISC_WR_EOL		(1 << 26)
-#define RISC_IRQ		(1 << 24)
-#define RISC_STATUS(status)	((((~status) & 0x0F) << 20) | ((status & 0x0F) << 16))
-#define RISC_SYNC_RESYNC	(1 << 15)
-#define RISC_SYNC_FM1		0x06
-#define RISC_SYNC_VRO		0x0C
-
-#define RISC_FLUSH()		bt->risc_pos = 0
-#define RISC_INSTR(instr)	bt->risc_cpu[bt->risc_pos++] = cpu_to_le32(instr)
-
-static int bt878_make_risc(struct bt878 *bt)
-{
-	bt->block_bytes = bt->buf_size >> 4;
-	bt->block_count = 1 << 4;
-	bt->line_bytes = bt->block_bytes;
-	bt->line_count = bt->block_count;
-
-	while (bt->line_bytes > 4095) {
-		bt->line_bytes >>= 1;
-		bt->line_count <<= 1;
-	}
-
-	if (bt->line_count > 255) {
-		printk(KERN_ERR "bt878: buffer size error!\n");
-		return -EINVAL;
-	}
-	return 0;
-}
-
-
-static void bt878_risc_program(struct bt878 *bt, u32 op_sync_orin)
-{
-	u32 buf_pos = 0;
-	u32 line;
-
-	RISC_FLUSH();
-	RISC_INSTR(RISC_SYNC | RISC_SYNC_FM1 | op_sync_orin);
-	RISC_INSTR(0);
-
-	dprintk("bt878: risc len lines %u, bytes per line %u\n",
-			bt->line_count, bt->line_bytes);
-	for (line = 0; line < bt->line_count; line++) {
-		// At the beginning of every block we issue an IRQ with previous (finished) block number set
-		if (!(buf_pos % bt->block_bytes))
-			RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL |
-				   RISC_IRQ |
-				   RISC_STATUS(((buf_pos /
-						 bt->block_bytes) +
-						(bt->block_count -
-						 1)) %
-					       bt->block_count) | bt->
-				   line_bytes);
-		else
-			RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL |
-				   bt->line_bytes);
-		RISC_INSTR(bt->buf_dma + buf_pos);
-		buf_pos += bt->line_bytes;
-	}
-
-	RISC_INSTR(RISC_SYNC | op_sync_orin | RISC_SYNC_VRO);
-	RISC_INSTR(0);
-
-	RISC_INSTR(RISC_JUMP);
-	RISC_INSTR(bt->risc_dma);
-
-	btwrite((bt->line_count << 16) | bt->line_bytes, BT878_APACK_LEN);
-}
-
-/*****************************/
-/* Start/Stop grabbing funcs */
-/*****************************/
-
-void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin,
-		u32 irq_err_ignore)
-{
-	u32 int_mask;
-
-	dprintk("bt878 debug: bt878_start (ctl=%8.8x)\n", controlreg);
-	/* complete the writing of the risc dma program now we have
-	 * the card specifics
-	 */
-	bt878_risc_program(bt, op_sync_orin);
-	controlreg &= ~0x1f;
-	controlreg |= 0x1b;
-
-	btwrite(bt->risc_dma, BT878_ARISC_START);
-
-	/* original int mask had :
-	 *    6    2    8    4    0
-	 * 1111 1111 1000 0000 0000
-	 * SCERR|OCERR|PABORT|RIPERR|FDSR|FTRGT|FBUS|RISCI
-	 * Hacked for DST to:
-	 * SCERR | OCERR | FDSR | FTRGT | FBUS | RISCI
-	 */
-	int_mask = BT878_ASCERR | BT878_AOCERR | BT878_APABORT |
-		BT878_ARIPERR | BT878_APPERR | BT878_AFDSR | BT878_AFTRGT |
-		BT878_AFBUS | BT878_ARISCI;
-
-
-	/* ignore pesky bits */
-	int_mask &= ~irq_err_ignore;
-
-	btwrite(int_mask, BT878_AINT_MASK);
-	btwrite(controlreg, BT878_AGPIO_DMA_CTL);
-}
-
-void bt878_stop(struct bt878 *bt)
-{
-	u32 stat;
-	int i = 0;
-
-	dprintk("bt878 debug: bt878_stop\n");
-
-	btwrite(0, BT878_AINT_MASK);
-	btand(~0x13, BT878_AGPIO_DMA_CTL);
-
-	do {
-		stat = btread(BT878_AINT_STAT);
-		if (!(stat & BT878_ARISC_EN))
-			break;
-		i++;
-	} while (i < 500);
-
-	dprintk("bt878(%d) debug: bt878_stop, i=%d, stat=0x%8.8x\n",
-		bt->nr, i, stat);
-}
-
-EXPORT_SYMBOL(bt878_start);
-EXPORT_SYMBOL(bt878_stop);
-
-/*****************************/
-/* Interrupt service routine */
-/*****************************/
-
-static irqreturn_t bt878_irq(int irq, void *dev_id)
-{
-	u32 stat, astat, mask;
-	int count;
-	struct bt878 *bt;
-
-	bt = (struct bt878 *) dev_id;
-
-	count = 0;
-	while (1) {
-		stat = btread(BT878_AINT_STAT);
-		mask = btread(BT878_AINT_MASK);
-		if (!(astat = (stat & mask)))
-			return IRQ_NONE;	/* this interrupt is not for me */
-/*		dprintk("bt878(%d) debug: irq count %d, stat 0x%8.8x, mask 0x%8.8x\n",bt->nr,count,stat,mask); */
-		btwrite(astat, BT878_AINT_STAT);	/* try to clear interrupt condition */
-
-
-		if (astat & (BT878_ASCERR | BT878_AOCERR)) {
-			if (bt878_verbose) {
-				printk(KERN_INFO
-				       "bt878(%d): irq%s%s risc_pc=%08x\n",
-				       bt->nr,
-				       (astat & BT878_ASCERR) ? " SCERR" :
-				       "",
-				       (astat & BT878_AOCERR) ? " OCERR" :
-				       "", btread(BT878_ARISC_PC));
-			}
-		}
-		if (astat & (BT878_APABORT | BT878_ARIPERR | BT878_APPERR)) {
-			if (bt878_verbose) {
-				printk(KERN_INFO
-				     "bt878(%d): irq%s%s%s risc_pc=%08x\n",
-				     bt->nr,
-				     (astat & BT878_APABORT) ? " PABORT" :
-				     "",
-				     (astat & BT878_ARIPERR) ? " RIPERR" :
-				     "",
-				     (astat & BT878_APPERR) ? " PPERR" :
-				     "", btread(BT878_ARISC_PC));
-			}
-		}
-		if (astat & (BT878_AFDSR | BT878_AFTRGT | BT878_AFBUS)) {
-			if (bt878_verbose) {
-				printk(KERN_INFO
-				     "bt878(%d): irq%s%s%s risc_pc=%08x\n",
-				     bt->nr,
-				     (astat & BT878_AFDSR) ? " FDSR" : "",
-				     (astat & BT878_AFTRGT) ? " FTRGT" :
-				     "",
-				     (astat & BT878_AFBUS) ? " FBUS" : "",
-				     btread(BT878_ARISC_PC));
-			}
-		}
-		if (astat & BT878_ARISCI) {
-			bt->finished_block = (stat & BT878_ARISCS) >> 28;
-			tasklet_schedule(&bt->tasklet);
-			break;
-		}
-		count++;
-		if (count > 20) {
-			btwrite(0, BT878_AINT_MASK);
-			printk(KERN_ERR
-			       "bt878(%d): IRQ lockup, cleared int mask\n",
-			       bt->nr);
-			break;
-		}
-	}
-	return IRQ_HANDLED;
-}
-
-int
-bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp)
-{
-	int retval;
-
-	retval = 0;
-	if (mutex_lock_interruptible(&bt->gpio_lock))
-		return -ERESTARTSYS;
-	/* special gpio signal */
-	switch (cmd) {
-	    case DST_IG_ENABLE:
-		// dprintk("dvb_bt8xx: dst enable mask 0x%02x enb 0x%02x \n", mp->dstg.enb.mask, mp->dstg.enb.enable);
-		retval = bttv_gpio_enable(bt->bttv_nr,
-				mp->enb.mask,
-				mp->enb.enable);
-		break;
-	    case DST_IG_WRITE:
-		// dprintk("dvb_bt8xx: dst write gpio mask 0x%02x out 0x%02x\n", mp->dstg.outp.mask, mp->dstg.outp.highvals);
-		retval = bttv_write_gpio(bt->bttv_nr,
-				mp->outp.mask,
-				mp->outp.highvals);
-
-		break;
-	    case DST_IG_READ:
-		/* read */
-		retval =  bttv_read_gpio(bt->bttv_nr, &mp->rd.value);
-		// dprintk("dvb_bt8xx: dst read gpio 0x%02x\n", (unsigned)mp->dstg.rd.value);
-		break;
-	    case DST_IG_TS:
-		/* Set packet size */
-		bt->TS_Size = mp->psize;
-		break;
-
-	    default:
-		retval = -EINVAL;
-		break;
-	}
-	mutex_unlock(&bt->gpio_lock);
-	return retval;
-}
-
-EXPORT_SYMBOL(bt878_device_control);
-
-#define BROOKTREE_878_DEVICE(vend, dev, name) \
-	{ \
-		.vendor = PCI_VENDOR_ID_BROOKTREE, \
-		.device = PCI_DEVICE_ID_BROOKTREE_878, \
-		.subvendor = (vend), .subdevice = (dev), \
-		.driver_data = (unsigned long) name \
-	}
-
-static struct pci_device_id bt878_pci_tbl[] __devinitdata = {
-	BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"),
-	BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"),
-	BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"),
-	BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"),
-	BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"),
-	BROOKTREE_878_DEVICE(0x270f, 0xfc00,
-				"ChainTech digitop DST-1000 DVB-S"),
-	BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"),
-	BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"),
-	BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"),
-	BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"),
-	BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"),
-	BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"),
-	{ }
-};
-
-MODULE_DEVICE_TABLE(pci, bt878_pci_tbl);
-
-static const char * __devinit card_name(const struct pci_device_id *id)
-{
-	return id->driver_data ? (const char *)id->driver_data : "Unknown";
-}
-
-/***********************/
-/* PCI device handling */
-/***********************/
-
-static int __devinit bt878_probe(struct pci_dev *dev,
-				 const struct pci_device_id *pci_id)
-{
-	int result = 0;
-	unsigned char lat;
-	struct bt878 *bt;
-#if defined(__powerpc__)
-	unsigned int cmd;
-#endif
-	unsigned int cardid;
-
-	printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n",
-	       bt878_num);
-	if (bt878_num >= BT878_MAX) {
-		printk(KERN_ERR "bt878: Too many devices inserted\n");
-		result = -ENOMEM;
-		goto fail0;
-	}
-	if (pci_enable_device(dev))
-		return -EIO;
-
-	cardid = dev->subsystem_device << 16;
-	cardid |= dev->subsystem_vendor;
-
-	printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n",
-				__func__, cardid, card_name(pci_id));
-
-	bt = &bt878[bt878_num];
-	bt->dev = dev;
-	bt->nr = bt878_num;
-	bt->shutdown = 0;
-
-	bt->id = dev->device;
-	bt->irq = dev->irq;
-	bt->bt878_adr = pci_resource_start(dev, 0);
-	if (!request_mem_region(pci_resource_start(dev, 0),
-				pci_resource_len(dev, 0), "bt878")) {
-		result = -EBUSY;
-		goto fail0;
-	}
-
-	bt->revision = dev->revision;
-	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
-
-
-	printk(KERN_INFO "bt878(%d): Bt%x (rev %d) at %02x:%02x.%x, ",
-	       bt878_num, bt->id, bt->revision, dev->bus->number,
-	       PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
-	printk("irq: %d, latency: %d, memory: 0x%lx\n",
-	       bt->irq, lat, bt->bt878_adr);
-
-
-#if defined(__powerpc__)
-	/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
-	/* response on cards with no firmware is not enabled by OF */
-	pci_read_config_dword(dev, PCI_COMMAND, &cmd);
-	cmd = (cmd | PCI_COMMAND_MEMORY);
-	pci_write_config_dword(dev, PCI_COMMAND, cmd);
-#endif
-
-#ifdef __sparc__
-	bt->bt878_mem = (unsigned char *) bt->bt878_adr;
-#else
-	bt->bt878_mem = ioremap(bt->bt878_adr, 0x1000);
-#endif
-
-	/* clear interrupt mask */
-	btwrite(0, BT848_INT_MASK);
-
-	result = request_irq(bt->irq, bt878_irq,
-			     IRQF_SHARED | IRQF_DISABLED, "bt878",
-			     (void *) bt);
-	if (result == -EINVAL) {
-		printk(KERN_ERR "bt878(%d): Bad irq number or handler\n",
-		       bt878_num);
-		goto fail1;
-	}
-	if (result == -EBUSY) {
-		printk(KERN_ERR
-		       "bt878(%d): IRQ %d busy, change your PnP config in BIOS\n",
-		       bt878_num, bt->irq);
-		goto fail1;
-	}
-	if (result < 0)
-		goto fail1;
-
-	pci_set_master(dev);
-	pci_set_drvdata(dev, bt);
-
-	if ((result = bt878_mem_alloc(bt))) {
-		printk(KERN_ERR "bt878: failed to allocate memory!\n");
-		goto fail2;
-	}
-
-	bt878_make_risc(bt);
-	btwrite(0, BT878_AINT_MASK);
-	bt878_num++;
-
-	return 0;
-
-      fail2:
-	free_irq(bt->irq, bt);
-      fail1:
-	release_mem_region(pci_resource_start(bt->dev, 0),
-			   pci_resource_len(bt->dev, 0));
-      fail0:
-	pci_disable_device(dev);
-	return result;
-}
-
-static void __devexit bt878_remove(struct pci_dev *pci_dev)
-{
-	u8 command;
-	struct bt878 *bt = pci_get_drvdata(pci_dev);
-
-	if (bt878_verbose)
-		printk(KERN_INFO "bt878(%d): unloading\n", bt->nr);
-
-	/* turn off all capturing, DMA and IRQs */
-	btand(~0x13, BT878_AGPIO_DMA_CTL);
-
-	/* first disable interrupts before unmapping the memory! */
-	btwrite(0, BT878_AINT_MASK);
-	btwrite(~0U, BT878_AINT_STAT);
-
-	/* disable PCI bus-mastering */
-	pci_read_config_byte(bt->dev, PCI_COMMAND, &command);
-	/* Should this be &=~ ?? */
-	command &= ~PCI_COMMAND_MASTER;
-	pci_write_config_byte(bt->dev, PCI_COMMAND, command);
-
-	free_irq(bt->irq, bt);
-	printk(KERN_DEBUG "bt878_mem: 0x%p.\n", bt->bt878_mem);
-	if (bt->bt878_mem)
-		iounmap(bt->bt878_mem);
-
-	release_mem_region(pci_resource_start(bt->dev, 0),
-			   pci_resource_len(bt->dev, 0));
-	/* wake up any waiting processes
-	   because shutdown flag is set, no new processes (in this queue)
-	   are expected
-	 */
-	bt->shutdown = 1;
-	bt878_mem_free(bt);
-
-	pci_set_drvdata(pci_dev, NULL);
-	pci_disable_device(pci_dev);
-	return;
-}
-
-static struct pci_driver bt878_pci_driver = {
-      .name	= "bt878",
-      .id_table = bt878_pci_tbl,
-      .probe	= bt878_probe,
-      .remove	= __devexit_p(bt878_remove),
-};
-
-/*******************************/
-/* Module management functions */
-/*******************************/
-
-static int __init bt878_init_module(void)
-{
-	bt878_num = 0;
-
-	printk(KERN_INFO "bt878: AUDIO driver version %d.%d.%d loaded\n",
-	       (BT878_VERSION_CODE >> 16) & 0xff,
-	       (BT878_VERSION_CODE >> 8) & 0xff,
-	       BT878_VERSION_CODE & 0xff);
-
-	return pci_register_driver(&bt878_pci_driver);
-}
-
-static void __exit bt878_cleanup_module(void)
-{
-	pci_unregister_driver(&bt878_pci_driver);
-}
-
-module_init(bt878_init_module);
-module_exit(bt878_cleanup_module);
-
-MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h
deleted file mode 100644
index d19b592..0000000
--- a/drivers/media/dvb/bt8xx/bt878.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
-    bt878.h - Bt878 audio module (register offsets)
-
-    Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef _BT878_H_
-#define _BT878_H_
-
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-
-#include "bt848.h"
-#include "bttv.h"
-
-#define BT878_VERSION_CODE 0x000000
-
-#define BT878_AINT_STAT		0x100
-#define BT878_ARISCS		(0xf<<28)
-#define BT878_ARISC_EN		(1<<27)
-#define BT878_ASCERR		(1<<19)
-#define BT878_AOCERR		(1<<18)
-#define BT878_APABORT		(1<<17)
-#define BT878_ARIPERR		(1<<16)
-#define BT878_APPERR		(1<<15)
-#define BT878_AFDSR		(1<<14)
-#define BT878_AFTRGT		(1<<13)
-#define BT878_AFBUS		(1<<12)
-#define BT878_ARISCI		(1<<11)
-#define BT878_AOFLOW		(1<<3)
-
-#define BT878_AINT_MASK		0x104
-
-#define BT878_AGPIO_DMA_CTL	0x10c
-#define BT878_A_GAIN		(0xf<<28)
-#define BT878_A_G2X		(1<<27)
-#define BT878_A_PWRDN		(1<<26)
-#define BT878_A_SEL		(3<<24)
-#define BT878_DA_SCE		(1<<23)
-#define BT878_DA_LRI		(1<<22)
-#define BT878_DA_MLB		(1<<21)
-#define BT878_DA_LRD		(0x1f<<16)
-#define BT878_DA_DPM		(1<<15)
-#define BT878_DA_SBR		(1<<14)
-#define BT878_DA_ES2		(1<<13)
-#define BT878_DA_LMT		(1<<12)
-#define BT878_DA_SDR		(0xf<<8)
-#define BT878_DA_IOM		(3<<6)
-#define BT878_DA_APP		(1<<5)
-#define BT878_ACAP_EN		(1<<4)
-#define BT878_PKTP		(3<<2)
-#define BT878_RISC_EN		(1<<1)
-#define BT878_FIFO_EN		1
-
-#define BT878_APACK_LEN		0x110
-#define BT878_AFP_LEN		(0xff<<16)
-#define BT878_ALP_LEN		0xfff
-
-#define BT878_ARISC_START	0x114
-
-#define BT878_ARISC_PC		0x120
-
-/* BT878 FUNCTION 0 REGISTERS */
-#define BT878_GPIO_DMA_CTL	0x10c
-
-/* Interrupt register */
-#define BT878_INT_STAT		0x100
-#define BT878_INT_MASK		0x104
-#define BT878_I2CRACK		(1<<25)
-#define BT878_I2CDONE		(1<<8)
-
-#define BT878_MAX 4
-
-#define BT878_RISC_SYNC_MASK	(1 << 15)
-
-
-#define BTTV_BOARD_UNKNOWN                 0x00
-#define BTTV_BOARD_PINNACLESAT             0x5e
-#define BTTV_BOARD_NEBULA_DIGITV           0x68
-#define BTTV_BOARD_PC_HDTV                 0x70
-#define BTTV_BOARD_TWINHAN_DST             0x71
-#define BTTV_BOARD_AVDVBT_771              0x7b
-#define BTTV_BOARD_AVDVBT_761              0x7c
-#define BTTV_BOARD_DVICO_DVBT_LITE         0x80
-#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87
-
-extern int bt878_num;
-
-struct bt878 {
-	struct mutex gpio_lock;
-	unsigned int nr;
-	unsigned int bttv_nr;
-	struct i2c_adapter *adapter;
-	struct pci_dev *dev;
-	unsigned int id;
-	unsigned int TS_Size;
-	unsigned char revision;
-	unsigned int irq;
-	unsigned long bt878_adr;
-	volatile void __iomem *bt878_mem; /* function 1 */
-
-	volatile u32 finished_block;
-	volatile u32 last_block;
-	u32 block_count;
-	u32 block_bytes;
-	u32 line_bytes;
-	u32 line_count;
-
-	u32 buf_size;
-	u8 *buf_cpu;
-	dma_addr_t buf_dma;
-
-	u32 risc_size;
-	__le32 *risc_cpu;
-	dma_addr_t risc_dma;
-	u32 risc_pos;
-
-	struct tasklet_struct tasklet;
-	int shutdown;
-};
-
-extern struct bt878 bt878[BT878_MAX];
-
-void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin,
-		u32 irq_err_ignore);
-void bt878_stop(struct bt878 *bt);
-
-#if defined(__powerpc__)	/* big-endian */
-static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val)
-{
-	st_le32(addr, val);
-	eieio();
-}
-
-#define bmtwrite(dat,adr)  io_st_le32((adr),(dat))
-#define bmtread(adr)       ld_le32((adr))
-#else
-#define bmtwrite(dat,adr)  writel((dat), (adr))
-#define bmtread(adr)       readl(adr)
-#endif
-
-#endif
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
deleted file mode 100644
index 430b3eb..0000000
--- a/drivers/media/dvb/bt8xx/dst.c
+++ /dev/null
@@ -1,1873 +0,0 @@
-/*
-	Frontend/Card driver for TwinHan DST Frontend
-	Copyright (C) 2003 Jamie Honan
-	Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <asm/div64.h>
-#include "dvb_frontend.h"
-#include "dst_priv.h"
-#include "dst_common.h"
-
-static unsigned int verbose = 1;
-module_param(verbose, int, 0644);
-MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
-
-static unsigned int dst_addons;
-module_param(dst_addons, int, 0644);
-MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)");
-
-static unsigned int dst_algo;
-module_param(dst_algo, int, 0644);
-MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)");
-
-#define HAS_LOCK		1
-#define ATTEMPT_TUNE		2
-#define HAS_POWER		4
-
-#define DST_ERROR		0
-#define DST_NOTICE		1
-#define DST_INFO		2
-#define DST_DEBUG		3
-
-#define dprintk(x, y, z, format, arg...) do {				\
-	if (z) {							\
-		if	((x > DST_ERROR) && (x > y))			\
-			printk(KERN_ERR "dst(%d) %s: " format "\n",	\
-				state->bt->nr, __func__ , ##arg);	\
-		else if	((x > DST_NOTICE) && (x > y))			\
-			printk(KERN_NOTICE "dst(%d) %s: " format "\n",  \
-				state->bt->nr, __func__ , ##arg);	\
-		else if ((x > DST_INFO) && (x > y))			\
-			printk(KERN_INFO "dst(%d) %s: " format "\n",	\
-				state->bt->nr, __func__ , ##arg);	\
-		else if ((x > DST_DEBUG) && (x > y))			\
-			printk(KERN_DEBUG "dst(%d) %s: " format "\n",	\
-				state->bt->nr,  __func__ , ##arg);	\
-	} else {							\
-		if (x > y)						\
-			printk(format, ##arg);				\
-	}								\
-} while(0)
-
-static int dst_command(struct dst_state *state, u8 *data, u8 len);
-
-static void dst_packsize(struct dst_state *state, int psize)
-{
-	union dst_gpio_packet bits;
-
-	bits.psize = psize;
-	bt878_device_control(state->bt, DST_IG_TS, &bits);
-}
-
-static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb,
-			 u32 outhigh, int delay)
-{
-	union dst_gpio_packet enb;
-	union dst_gpio_packet bits;
-	int err;
-
-	enb.enb.mask = mask;
-	enb.enb.enable = enbb;
-
-	dprintk(verbose, DST_INFO, 1, "mask=[%04x], enbb=[%04x], outhigh=[%04x]", mask, enbb, outhigh);
-	if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) {
-		dprintk(verbose, DST_INFO, 1, "dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)", err, mask, enbb);
-		return -EREMOTEIO;
-	}
-	udelay(1000);
-	/* because complete disabling means no output, no need to do output packet */
-	if (enbb == 0)
-		return 0;
-	if (delay)
-		msleep(10);
-	bits.outp.mask = enbb;
-	bits.outp.highvals = outhigh;
-	if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) {
-		dprintk(verbose, DST_INFO, 1, "dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)", err, enbb, outhigh);
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static int dst_gpio_inb(struct dst_state *state, u8 *result)
-{
-	union dst_gpio_packet rd_packet;
-	int err;
-
-	*result = 0;
-	if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)", err);
-		return -EREMOTEIO;
-	}
-	*result = (u8) rd_packet.rd.value;
-
-	return 0;
-}
-
-int rdc_reset_state(struct dst_state *state)
-{
-	dprintk(verbose, DST_INFO, 1, "Resetting state machine");
-	if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, 0, NO_DELAY) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !");
-		return -1;
-	}
-	msleep(10);
-	if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, RDC_8820_INT, NO_DELAY) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !");
-		msleep(10);
-		return -1;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(rdc_reset_state);
-
-static int rdc_8820_reset(struct dst_state *state)
-{
-	dprintk(verbose, DST_DEBUG, 1, "Resetting DST");
-	if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !");
-		return -1;
-	}
-	udelay(1000);
-	if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, RDC_8820_RESET, DELAY) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int dst_pio_enable(struct dst_state *state)
-{
-	if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !");
-		return -1;
-	}
-	udelay(1000);
-
-	return 0;
-}
-
-int dst_pio_disable(struct dst_state *state)
-{
-	if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_DISABLE, RDC_8820_PIO_0_DISABLE, NO_DELAY) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !");
-		return -1;
-	}
-	if (state->type_flags & DST_TYPE_HAS_FW_1)
-		udelay(1000);
-
-	return 0;
-}
-EXPORT_SYMBOL(dst_pio_disable);
-
-int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode)
-{
-	u8 reply;
-	int i;
-
-	for (i = 0; i < 200; i++) {
-		if (dst_gpio_inb(state, &reply) < 0) {
-			dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb ERROR !");
-			return -1;
-		}
-		if ((reply & RDC_8820_PIO_0_ENABLE) == 0) {
-			dprintk(verbose, DST_INFO, 1, "dst wait ready after %d", i);
-			return 1;
-		}
-		msleep(10);
-	}
-	dprintk(verbose, DST_NOTICE, 1, "dst wait NOT ready after %d", i);
-
-	return 0;
-}
-EXPORT_SYMBOL(dst_wait_dst_ready);
-
-int dst_error_recovery(struct dst_state *state)
-{
-	dprintk(verbose, DST_NOTICE, 1, "Trying to return from previous errors.");
-	dst_pio_disable(state);
-	msleep(10);
-	dst_pio_enable(state);
-	msleep(10);
-
-	return 0;
-}
-EXPORT_SYMBOL(dst_error_recovery);
-
-int dst_error_bailout(struct dst_state *state)
-{
-	dprintk(verbose, DST_INFO, 1, "Trying to bailout from previous error.");
-	rdc_8820_reset(state);
-	dst_pio_disable(state);
-	msleep(10);
-
-	return 0;
-}
-EXPORT_SYMBOL(dst_error_bailout);
-
-int dst_comm_init(struct dst_state *state)
-{
-	dprintk(verbose, DST_INFO, 1, "Initializing DST.");
-	if ((dst_pio_enable(state)) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "PIO Enable Failed");
-		return -1;
-	}
-	if ((rdc_reset_state(state)) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "RDC 8820 State RESET Failed.");
-		return -1;
-	}
-	if (state->type_flags & DST_TYPE_HAS_FW_1)
-		msleep(100);
-	else
-		msleep(5);
-
-	return 0;
-}
-EXPORT_SYMBOL(dst_comm_init);
-
-int write_dst(struct dst_state *state, u8 *data, u8 len)
-{
-	struct i2c_msg msg = {
-		.addr = state->config->demod_address,
-		.flags = 0,
-		.buf = data,
-		.len = len
-	};
-
-	int err;
-	u8 cnt, i;
-
-	dprintk(verbose, DST_NOTICE, 0, "writing [ ");
-	for (i = 0; i < len; i++)
-		dprintk(verbose, DST_NOTICE, 0, "%02x ", data[i]);
-	dprintk(verbose, DST_NOTICE, 0, "]\n");
-
-	for (cnt = 0; cnt < 2; cnt++) {
-		if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) {
-			dprintk(verbose, DST_INFO, 1, "_write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, data[0]);
-			dst_error_recovery(state);
-			continue;
-		} else
-			break;
-	}
-	if (cnt >= 2) {
-		dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET");
-		dst_error_bailout(state);
-
-		return -1;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(write_dst);
-
-int read_dst(struct dst_state *state, u8 *ret, u8 len)
-{
-	struct i2c_msg msg = {
-		.addr = state->config->demod_address,
-		.flags = I2C_M_RD,
-		.buf = ret,
-		.len = len
-	};
-
-	int err;
-	int cnt;
-
-	for (cnt = 0; cnt < 2; cnt++) {
-		if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) {
-			dprintk(verbose, DST_INFO, 1, "read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, ret[0]);
-			dst_error_recovery(state);
-			continue;
-		} else
-			break;
-	}
-	if (cnt >= 2) {
-		dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET");
-		dst_error_bailout(state);
-
-		return -1;
-	}
-	dprintk(verbose, DST_DEBUG, 1, "reply is 0x%x", ret[0]);
-	for (err = 1; err < len; err++)
-		dprintk(verbose, DST_DEBUG, 0, " 0x%x", ret[err]);
-	if (err > 1)
-		dprintk(verbose, DST_DEBUG, 0, "\n");
-
-	return 0;
-}
-EXPORT_SYMBOL(read_dst);
-
-static int dst_set_polarization(struct dst_state *state)
-{
-	switch (state->voltage) {
-	case SEC_VOLTAGE_13:	/*	Vertical	*/
-		dprintk(verbose, DST_INFO, 1, "Polarization=[Vertical]");
-		state->tx_tuna[8] &= ~0x40;
-		break;
-	case SEC_VOLTAGE_18:	/*	Horizontal	*/
-		dprintk(verbose, DST_INFO, 1, "Polarization=[Horizontal]");
-		state->tx_tuna[8] |= 0x40;
-		break;
-	case SEC_VOLTAGE_OFF:
-		break;
-	}
-
-	return 0;
-}
-
-static int dst_set_freq(struct dst_state *state, u32 freq)
-{
-	state->frequency = freq;
-	dprintk(verbose, DST_INFO, 1, "set Frequency %u", freq);
-
-	if (state->dst_type == DST_TYPE_IS_SAT) {
-		freq = freq / 1000;
-		if (freq < 950 || freq > 2150)
-			return -EINVAL;
-		state->tx_tuna[2] = (freq >> 8);
-		state->tx_tuna[3] = (u8) freq;
-		state->tx_tuna[4] = 0x01;
-		state->tx_tuna[8] &= ~0x04;
-		if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
-			if (freq < 1531)
-				state->tx_tuna[8] |= 0x04;
-		}
-	} else if (state->dst_type == DST_TYPE_IS_TERR) {
-		freq = freq / 1000;
-		if (freq < 137000 || freq > 858000)
-			return -EINVAL;
-		state->tx_tuna[2] = (freq >> 16) & 0xff;
-		state->tx_tuna[3] = (freq >> 8) & 0xff;
-		state->tx_tuna[4] = (u8) freq;
-	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
-		freq = freq / 1000;
-		state->tx_tuna[2] = (freq >> 16) & 0xff;
-		state->tx_tuna[3] = (freq >> 8) & 0xff;
-		state->tx_tuna[4] = (u8) freq;
-	} else if (state->dst_type == DST_TYPE_IS_ATSC) {
-		freq = freq / 1000;
-		if (freq < 51000 || freq > 858000)
-			return -EINVAL;
-		state->tx_tuna[2] = (freq >> 16) & 0xff;
-		state->tx_tuna[3] = (freq >>  8) & 0xff;
-		state->tx_tuna[4] = (u8) freq;
-		state->tx_tuna[5] = 0x00;		/*	ATSC	*/
-		state->tx_tuna[6] = 0x00;
-		if (state->dst_hw_cap & DST_TYPE_HAS_ANALOG)
-			state->tx_tuna[7] = 0x00;	/*	Digital	*/
-	} else
-		return -EINVAL;
-
-	return 0;
-}
-
-static int dst_set_bandwidth(struct dst_state *state, u32 bandwidth)
-{
-	state->bandwidth = bandwidth;
-
-	if (state->dst_type != DST_TYPE_IS_TERR)
-		return -EOPNOTSUPP;
-
-	switch (bandwidth) {
-	case 6000000:
-		if (state->dst_hw_cap & DST_TYPE_HAS_CA)
-			state->tx_tuna[7] = 0x06;
-		else {
-			state->tx_tuna[6] = 0x06;
-			state->tx_tuna[7] = 0x00;
-		}
-		break;
-	case 7000000:
-		if (state->dst_hw_cap & DST_TYPE_HAS_CA)
-			state->tx_tuna[7] = 0x07;
-		else {
-			state->tx_tuna[6] = 0x07;
-			state->tx_tuna[7] = 0x00;
-		}
-		break;
-	case 8000000:
-		if (state->dst_hw_cap & DST_TYPE_HAS_CA)
-			state->tx_tuna[7] = 0x08;
-		else {
-			state->tx_tuna[6] = 0x08;
-			state->tx_tuna[7] = 0x00;
-		}
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int dst_set_inversion(struct dst_state *state, fe_spectral_inversion_t inversion)
-{
-	state->inversion = inversion;
-	switch (inversion) {
-	case INVERSION_OFF:	/*	Inversion = Normal	*/
-		state->tx_tuna[8] &= ~0x80;
-		break;
-	case INVERSION_ON:
-		state->tx_tuna[8] |= 0x80;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int dst_set_fec(struct dst_state *state, fe_code_rate_t fec)
-{
-	state->fec = fec;
-	return 0;
-}
-
-static fe_code_rate_t dst_get_fec(struct dst_state *state)
-{
-	return state->fec;
-}
-
-static int dst_set_symbolrate(struct dst_state *state, u32 srate)
-{
-	u32 symcalc;
-	u64 sval;
-
-	state->symbol_rate = srate;
-	if (state->dst_type == DST_TYPE_IS_TERR) {
-		return -EOPNOTSUPP;
-	}
-	dprintk(verbose, DST_INFO, 1, "set symrate %u", srate);
-	srate /= 1000;
-	if (state->dst_type == DST_TYPE_IS_SAT) {
-		if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
-			sval = srate;
-			sval <<= 20;
-			do_div(sval, 88000);
-			symcalc = (u32) sval;
-			dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc);
-			state->tx_tuna[5] = (u8) (symcalc >> 12);
-			state->tx_tuna[6] = (u8) (symcalc >> 4);
-			state->tx_tuna[7] = (u8) (symcalc << 4);
-		} else {
-			state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f;
-			state->tx_tuna[6] = (u8) (srate >> 8);
-			state->tx_tuna[7] = (u8) srate;
-		}
-		state->tx_tuna[8] &= ~0x20;
-		if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
-			if (srate > 8000)
-				state->tx_tuna[8] |= 0x20;
-		}
-	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
-		dprintk(verbose, DST_DEBUG, 1, "%s", state->fw_name);
-		if (!strncmp(state->fw_name, "DCTNEW", 6)) {
-			state->tx_tuna[5] = (u8) (srate >> 8);
-			state->tx_tuna[6] = (u8) srate;
-			state->tx_tuna[7] = 0x00;
-		} else if (!strncmp(state->fw_name, "DCT-CI", 6)) {
-			state->tx_tuna[5] = 0x00;
-			state->tx_tuna[6] = (u8) (srate >> 8);
-			state->tx_tuna[7] = (u8) srate;
-		}
-	}
-	return 0;
-}
-
-static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation)
-{
-	if (state->dst_type != DST_TYPE_IS_CABLE)
-		return -EOPNOTSUPP;
-
-	state->modulation = modulation;
-	switch (modulation) {
-	case QAM_16:
-		state->tx_tuna[8] = 0x10;
-		break;
-	case QAM_32:
-		state->tx_tuna[8] = 0x20;
-		break;
-	case QAM_64:
-		state->tx_tuna[8] = 0x40;
-		break;
-	case QAM_128:
-		state->tx_tuna[8] = 0x80;
-		break;
-	case QAM_256:
-		if (!strncmp(state->fw_name, "DCTNEW", 6))
-			state->tx_tuna[8] = 0xff;
-		else if (!strncmp(state->fw_name, "DCT-CI", 6))
-			state->tx_tuna[8] = 0x00;
-		break;
-	case QPSK:
-	case QAM_AUTO:
-	case VSB_8:
-	case VSB_16:
-	default:
-		return -EINVAL;
-
-	}
-
-	return 0;
-}
-
-static fe_modulation_t dst_get_modulation(struct dst_state *state)
-{
-	return state->modulation;
-}
-
-
-u8 dst_check_sum(u8 *buf, u32 len)
-{
-	u32 i;
-	u8 val = 0;
-	if (!len)
-		return 0;
-	for (i = 0; i < len; i++) {
-		val += buf[i];
-	}
-	return ((~val) + 1);
-}
-EXPORT_SYMBOL(dst_check_sum);
-
-static void dst_type_flags_print(struct dst_state *state)
-{
-	u32 type_flags = state->type_flags;
-
-	dprintk(verbose, DST_ERROR, 0, "DST type flags :");
-	if (type_flags & DST_TYPE_HAS_TS188)
-		dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_TS188);
-	if (type_flags & DST_TYPE_HAS_NEWTUNE_2)
-		dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner 2", DST_TYPE_HAS_NEWTUNE_2);
-	if (type_flags & DST_TYPE_HAS_TS204)
-		dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204);
-	if (type_flags & DST_TYPE_HAS_VLF)
-		dprintk(verbose, DST_ERROR, 0, " 0x%x VLF", DST_TYPE_HAS_VLF);
-	if (type_flags & DST_TYPE_HAS_SYMDIV)
-		dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV);
-	if (type_flags & DST_TYPE_HAS_FW_1)
-		dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 1", DST_TYPE_HAS_FW_1);
-	if (type_flags & DST_TYPE_HAS_FW_2)
-		dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 2", DST_TYPE_HAS_FW_2);
-	if (type_flags & DST_TYPE_HAS_FW_3)
-		dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 3", DST_TYPE_HAS_FW_3);
-	dprintk(verbose, DST_ERROR, 0, "\n");
-}
-
-
-static int dst_type_print(struct dst_state *state, u8 type)
-{
-	char *otype;
-	switch (type) {
-	case DST_TYPE_IS_SAT:
-		otype = "satellite";
-		break;
-
-	case DST_TYPE_IS_TERR:
-		otype = "terrestrial";
-		break;
-
-	case DST_TYPE_IS_CABLE:
-		otype = "cable";
-		break;
-
-	case DST_TYPE_IS_ATSC:
-		otype = "atsc";
-		break;
-
-	default:
-		dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type);
-		return -EINVAL;
-	}
-	dprintk(verbose, DST_INFO, 1, "DST type: %s", otype);
-
-	return 0;
-}
-
-static struct tuner_types tuner_list[] = {
-	{
-		.tuner_type = TUNER_TYPE_L64724,
-		.tuner_name = "L 64724",
-		.board_name = "UNKNOWN",
-		.fw_name    = "UNKNOWN"
-	},
-
-	{
-		.tuner_type = TUNER_TYPE_STV0299,
-		.tuner_name = "STV 0299",
-		.board_name = "VP1020",
-		.fw_name    = "DST-MOT"
-	},
-
-	{
-		.tuner_type = TUNER_TYPE_STV0299,
-		.tuner_name = "STV 0299",
-		.board_name = "VP1020",
-		.fw_name    = "DST-03T"
-	},
-
-	{
-		.tuner_type = TUNER_TYPE_MB86A15,
-		.tuner_name = "MB 86A15",
-		.board_name = "VP1022",
-		.fw_name    = "DST-03T"
-	},
-
-	{
-		.tuner_type = TUNER_TYPE_MB86A15,
-		.tuner_name = "MB 86A15",
-		.board_name = "VP1025",
-		.fw_name    = "DST-03T"
-	},
-
-	{
-		.tuner_type = TUNER_TYPE_STV0299,
-		.tuner_name = "STV 0299",
-		.board_name = "VP1030",
-		.fw_name    = "DST-CI"
-	},
-
-	{
-		.tuner_type = TUNER_TYPE_STV0299,
-		.tuner_name = "STV 0299",
-		.board_name = "VP1030",
-		.fw_name    = "DSTMCI"
-	},
-
-	{
-		.tuner_type = TUNER_TYPE_UNKNOWN,
-		.tuner_name = "UNKNOWN",
-		.board_name = "VP2021",
-		.fw_name    = "DCTNEW"
-	},
-
-	{
-		.tuner_type = TUNER_TYPE_UNKNOWN,
-		.tuner_name = "UNKNOWN",
-		.board_name = "VP2030",
-		.fw_name    = "DCT-CI"
-	},
-
-	{
-		.tuner_type = TUNER_TYPE_UNKNOWN,
-		.tuner_name = "UNKNOWN",
-		.board_name = "VP2031",
-		.fw_name    = "DCT-CI"
-	},
-
-	{
-		.tuner_type = TUNER_TYPE_UNKNOWN,
-		.tuner_name = "UNKNOWN",
-		.board_name = "VP2040",
-		.fw_name    = "DCT-CI"
-	},
-
-	{
-		.tuner_type = TUNER_TYPE_UNKNOWN,
-		.tuner_name = "UNKNOWN",
-		.board_name = "VP3020",
-		.fw_name    = "DTTFTA"
-	},
-
-	{
-		.tuner_type = TUNER_TYPE_UNKNOWN,
-		.tuner_name = "UNKNOWN",
-		.board_name = "VP3021",
-		.fw_name    = "DTTFTA"
-	},
-
-	{
-		.tuner_type = TUNER_TYPE_TDA10046,
-		.tuner_name = "TDA10046",
-		.board_name = "VP3040",
-		.fw_name    = "DTT-CI"
-	},
-
-	{
-		.tuner_type = TUNER_TYPE_UNKNOWN,
-		.tuner_name = "UNKNOWN",
-		.board_name = "VP3051",
-		.fw_name    = "DTTNXT"
-	},
-
-	{
-		.tuner_type = TUNER_TYPE_NXT200x,
-		.tuner_name = "NXT200x",
-		.board_name = "VP3220",
-		.fw_name    = "ATSCDI"
-	},
-
-	{
-		.tuner_type = TUNER_TYPE_NXT200x,
-		.tuner_name = "NXT200x",
-		.board_name = "VP3250",
-		.fw_name    = "ATSCAD"
-	},
-};
-
-/*
-	Known cards list
-	Satellite
-	-------------------
-		  200103A
-	VP-1020   DST-MOT	LG(old), TS=188
-
-	VP-1020   DST-03T	LG(new), TS=204
-	VP-1022   DST-03T	LG(new), TS=204
-	VP-1025   DST-03T	LG(new), TS=204
-
-	VP-1030   DSTMCI,	LG(new), TS=188
-	VP-1032   DSTMCI,	LG(new), TS=188
-
-	Cable
-	-------------------
-	VP-2030   DCT-CI,	Samsung, TS=204
-	VP-2021   DCT-CI,	Unknown, TS=204
-	VP-2031   DCT-CI,	Philips, TS=188
-	VP-2040   DCT-CI,	Philips, TS=188, with CA daughter board
-	VP-2040   DCT-CI,	Philips, TS=204, without CA daughter board
-
-	Terrestrial
-	-------------------
-	VP-3050  DTTNXT			 TS=188
-	VP-3040  DTT-CI,	Philips, TS=188
-	VP-3040  DTT-CI,	Philips, TS=204
-
-	ATSC
-	-------------------
-	VP-3220  ATSCDI,		 TS=188
-	VP-3250  ATSCAD,		 TS=188
-
-*/
-
-static struct dst_types dst_tlist[] = {
-	{
-		.device_id = "200103A",
-		.offset = 0,
-		.dst_type =  DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS,
-		.dst_feature = 0,
-		.tuner_type = 0
-	},	/*	obsolete	*/
-
-	{
-		.device_id = "DST-020",
-		.offset = 0,
-		.dst_type =  DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
-		.dst_feature = 0,
-		.tuner_type = 0
-	},	/*	obsolete	*/
-
-	{
-		.device_id = "DST-030",
-		.offset =  0,
-		.dst_type = DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
-		.dst_feature = 0,
-		.tuner_type = 0
-	},	/*	obsolete	*/
-
-	{
-		.device_id = "DST-03T",
-		.offset = 0,
-		.dst_type = DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2,
-		.dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5
-							 | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO,
-		.tuner_type = TUNER_TYPE_MULTI
-	 },
-
-	{
-		.device_id = "DST-MOT",
-		.offset =  0,
-		.dst_type = DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
-		.dst_feature = 0,
-		.tuner_type = 0
-	},	/*	obsolete	*/
-
-	{
-		.device_id = "DST-CI",
-		.offset = 1,
-		.dst_type = DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_1,
-		.dst_feature = DST_TYPE_HAS_CA,
-		.tuner_type = 0
-	},	/*	An OEM board	*/
-
-	{
-		.device_id = "DSTMCI",
-		.offset = 1,
-		.dst_type = DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT | DST_TYPE_HAS_VLF,
-		.dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4
-							| DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC,
-		.tuner_type = TUNER_TYPE_MULTI
-	},
-
-	{
-		.device_id = "DSTFCI",
-		.offset = 1,
-		.dst_type = DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
-		.dst_feature = 0,
-		.tuner_type = 0
-	},	/* unknown to vendor	*/
-
-	{
-		.device_id = "DCT-CI",
-		.offset = 1,
-		.dst_type = DST_TYPE_IS_CABLE,
-		.type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_1	| DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_VLF,
-		.dst_feature = DST_TYPE_HAS_CA,
-		.tuner_type = 0
-	},
-
-	{
-		.device_id = "DCTNEW",
-		.offset = 1,
-		.dst_type = DST_TYPE_IS_CABLE,
-		.type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_MULTI_FE,
-		.dst_feature = 0,
-		.tuner_type = 0
-	},
-
-	{
-		.device_id = "DTT-CI",
-		.offset = 1,
-		.dst_type = DST_TYPE_IS_TERR,
-		.type_flags = DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_VLF,
-		.dst_feature = DST_TYPE_HAS_CA,
-		.tuner_type = 0
-	},
-
-	{
-		.device_id = "DTTDIG",
-		.offset = 1,
-		.dst_type = DST_TYPE_IS_TERR,
-		.type_flags = DST_TYPE_HAS_FW_2,
-		.dst_feature = 0,
-		.tuner_type = 0
-	},
-
-	{
-		.device_id = "DTTNXT",
-		.offset = 1,
-		.dst_type = DST_TYPE_IS_TERR,
-		.type_flags = DST_TYPE_HAS_FW_2,
-		.dst_feature = DST_TYPE_HAS_ANALOG,
-		.tuner_type = 0
-	},
-
-	{
-		.device_id = "ATSCDI",
-		.offset = 1,
-		.dst_type = DST_TYPE_IS_ATSC,
-		.type_flags = DST_TYPE_HAS_FW_2,
-		.dst_feature = 0,
-		.tuner_type = 0
-	},
-
-	{
-		.device_id = "ATSCAD",
-		.offset = 1,
-		.dst_type = DST_TYPE_IS_ATSC,
-		.type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD,
-		.dst_feature = DST_TYPE_HAS_MAC | DST_TYPE_HAS_ANALOG,
-		.tuner_type = 0
-	},
-
-	{ }
-
-};
-
-static int dst_get_mac(struct dst_state *state)
-{
-	u8 get_mac[] = { 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-	get_mac[7] = dst_check_sum(get_mac, 7);
-	if (dst_command(state, get_mac, 8) < 0) {
-		dprintk(verbose, DST_INFO, 1, "Unsupported Command");
-		return -1;
-	}
-	memset(&state->mac_address, '\0', 8);
-	memcpy(&state->mac_address, &state->rxbuffer, 6);
-	dprintk(verbose, DST_ERROR, 1, "MAC Address=[%pM]", state->mac_address);
-
-	return 0;
-}
-
-static int dst_fw_ver(struct dst_state *state)
-{
-	u8 get_ver[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-	get_ver[7] = dst_check_sum(get_ver, 7);
-	if (dst_command(state, get_ver, 8) < 0) {
-		dprintk(verbose, DST_INFO, 1, "Unsupported Command");
-		return -1;
-	}
-	memcpy(&state->fw_version, &state->rxbuffer, 8);
-	dprintk(verbose, DST_ERROR, 1, "Firmware Ver = %x.%x Build = %02x, on %x:%x, %x-%x-20%02x",
-		state->fw_version[0] >> 4, state->fw_version[0] & 0x0f,
-		state->fw_version[1],
-		state->fw_version[5], state->fw_version[6],
-		state->fw_version[4], state->fw_version[3], state->fw_version[2]);
-
-	return 0;
-}
-
-static int dst_card_type(struct dst_state *state)
-{
-	int j;
-	struct tuner_types *p_tuner_list = NULL;
-
-	u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-	get_type[7] = dst_check_sum(get_type, 7);
-	if (dst_command(state, get_type, 8) < 0) {
-		dprintk(verbose, DST_INFO, 1, "Unsupported Command");
-		return -1;
-	}
-	memset(&state->card_info, '\0', 8);
-	memcpy(&state->card_info, &state->rxbuffer, 7);
-	dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]);
-
-	for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
-		if (!strcmp(&state->card_info[0], p_tuner_list->board_name)) {
-			state->tuner_type = p_tuner_list->tuner_type;
-			dprintk(verbose, DST_ERROR, 1, "DST has [%s] tuner, tuner type=[%d]",
-				p_tuner_list->tuner_name, p_tuner_list->tuner_type);
-		}
-	}
-
-	return 0;
-}
-
-static int dst_get_vendor(struct dst_state *state)
-{
-	u8 get_vendor[] = { 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-	get_vendor[7] = dst_check_sum(get_vendor, 7);
-	if (dst_command(state, get_vendor, 8) < 0) {
-		dprintk(verbose, DST_INFO, 1, "Unsupported Command");
-		return -1;
-	}
-	memset(&state->vendor, '\0', 8);
-	memcpy(&state->vendor, &state->rxbuffer, 7);
-	dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]);
-
-	return 0;
-}
-
-static void debug_dst_buffer(struct dst_state *state)
-{
-	int i;
-
-	if (verbose > 2) {
-		printk("%s: [", __func__);
-		for (i = 0; i < 8; i++)
-			printk(" %02x", state->rxbuffer[i]);
-		printk("]\n");
-	}
-}
-
-static int dst_check_stv0299(struct dst_state *state)
-{
-	u8 check_stv0299[] = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-	check_stv0299[7] = dst_check_sum(check_stv0299, 7);
-	if (dst_command(state, check_stv0299, 8) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "Cmd=[0x04] failed");
-		return -1;
-	}
-	debug_dst_buffer(state);
-
-	if (memcmp(&check_stv0299, &state->rxbuffer, 8)) {
-		dprintk(verbose, DST_ERROR, 1, "Found a STV0299 NIM");
-		state->tuner_type = TUNER_TYPE_STV0299;
-		return 0;
-	}
-
-	return -1;
-}
-
-static int dst_check_mb86a15(struct dst_state *state)
-{
-	u8 check_mb86a15[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-	check_mb86a15[7] = dst_check_sum(check_mb86a15, 7);
-	if (dst_command(state, check_mb86a15, 8) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "Cmd=[0x10], failed");
-		return -1;
-	}
-	debug_dst_buffer(state);
-
-	if (memcmp(&check_mb86a15, &state->rxbuffer, 8) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "Found a MB86A15 NIM");
-		state->tuner_type = TUNER_TYPE_MB86A15;
-		return 0;
-	}
-
-	return -1;
-}
-
-static int dst_get_tuner_info(struct dst_state *state)
-{
-	u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-	u8 get_tuner_2[] = { 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-	get_tuner_1[7] = dst_check_sum(get_tuner_1, 7);
-	get_tuner_2[7] = dst_check_sum(get_tuner_2, 7);
-	dprintk(verbose, DST_ERROR, 1, "DST TYpe = MULTI FE");
-	if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
-		if (dst_command(state, get_tuner_1, 8) < 0) {
-			dprintk(verbose, DST_INFO, 1, "Cmd=[0x13], Unsupported");
-			goto force;
-		}
-	} else {
-		if (dst_command(state, get_tuner_2, 8) < 0) {
-			dprintk(verbose, DST_INFO, 1, "Cmd=[0xb], Unsupported");
-			goto force;
-		}
-	}
-	memcpy(&state->board_info, &state->rxbuffer, 8);
-	if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
-		dprintk(verbose, DST_ERROR, 1, "DST type has TS=188");
-	}
-	if (state->board_info[0] == 0xbc) {
-		if (state->dst_type != DST_TYPE_IS_ATSC)
-			state->type_flags |= DST_TYPE_HAS_TS188;
-		else
-			state->type_flags |= DST_TYPE_HAS_NEWTUNE_2;
-
-		if (state->board_info[1] == 0x01) {
-			state->dst_hw_cap |= DST_TYPE_HAS_DBOARD;
-			dprintk(verbose, DST_ERROR, 1, "DST has Daughterboard");
-		}
-	}
-
-	return 0;
-force:
-	if (!strncmp(state->fw_name, "DCT-CI", 6)) {
-		state->type_flags |= DST_TYPE_HAS_TS204;
-		dprintk(verbose, DST_ERROR, 1, "Forcing [%s] to TS188", state->fw_name);
-	}
-
-	return -1;
-}
-
-static int dst_get_device_id(struct dst_state *state)
-{
-	u8 reply;
-
-	int i, j;
-	struct dst_types *p_dst_type = NULL;
-	struct tuner_types *p_tuner_list = NULL;
-
-	u8 use_dst_type = 0;
-	u32 use_type_flags = 0;
-
-	static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
-
-	state->tuner_type = 0;
-	device_type[7] = dst_check_sum(device_type, 7);
-
-	if (write_dst(state, device_type, FIXED_COMM))
-		return -1;		/*	Write failed		*/
-	if ((dst_pio_disable(state)) < 0)
-		return -1;
-	if (read_dst(state, &reply, GET_ACK))
-		return -1;		/*	Read failure		*/
-	if (reply != ACK) {
-		dprintk(verbose, DST_INFO, 1, "Write not Acknowledged! [Reply=0x%02x]", reply);
-		return -1;		/*	Unack'd write		*/
-	}
-	if (!dst_wait_dst_ready(state, DEVICE_INIT))
-		return -1;		/*	DST not ready yet	*/
-	if (read_dst(state, state->rxbuffer, FIXED_COMM))
-		return -1;
-
-	dst_pio_disable(state);
-	if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) {
-		dprintk(verbose, DST_INFO, 1, "Checksum failure!");
-		return -1;		/*	Checksum failure	*/
-	}
-	state->rxbuffer[7] = '\0';
-
-	for (i = 0, p_dst_type = dst_tlist; i < ARRAY_SIZE(dst_tlist); i++, p_dst_type++) {
-		if (!strncmp (&state->rxbuffer[p_dst_type->offset], p_dst_type->device_id, strlen (p_dst_type->device_id))) {
-			use_type_flags = p_dst_type->type_flags;
-			use_dst_type = p_dst_type->dst_type;
-
-			/*	Card capabilities	*/
-			state->dst_hw_cap = p_dst_type->dst_feature;
-			dprintk(verbose, DST_ERROR, 1, "Recognise [%s]", p_dst_type->device_id);
-			strncpy(&state->fw_name[0], p_dst_type->device_id, 6);
-			/*	Multiple tuners		*/
-			if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) {
-				switch (use_dst_type) {
-				case DST_TYPE_IS_SAT:
-					/*	STV0299 check	*/
-					if (dst_check_stv0299(state) < 0) {
-						dprintk(verbose, DST_ERROR, 1, "Unsupported");
-						state->tuner_type = TUNER_TYPE_MB86A15;
-					}
-					break;
-				default:
-					break;
-				}
-				if (dst_check_mb86a15(state) < 0)
-					dprintk(verbose, DST_ERROR, 1, "Unsupported");
-			/*	Single tuner		*/
-			} else {
-				state->tuner_type = p_dst_type->tuner_type;
-			}
-			for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
-				if (!(strncmp(p_dst_type->device_id, p_tuner_list->fw_name, 7)) &&
-					p_tuner_list->tuner_type == state->tuner_type) {
-					dprintk(verbose, DST_ERROR, 1, "[%s] has a [%s]",
-						p_dst_type->device_id, p_tuner_list->tuner_name);
-				}
-			}
-			break;
-		}
-	}
-
-	if (i >= ARRAY_SIZE(dst_tlist)) {
-		dprintk(verbose, DST_ERROR, 1, "Unable to recognize %s or %s", &state->rxbuffer[0], &state->rxbuffer[1]);
-		dprintk(verbose, DST_ERROR, 1, "please email linux-dvb@linuxtv.org with this type in");
-		use_dst_type = DST_TYPE_IS_SAT;
-		use_type_flags = DST_TYPE_HAS_SYMDIV;
-	}
-	dst_type_print(state, use_dst_type);
-	state->type_flags = use_type_flags;
-	state->dst_type = use_dst_type;
-	dst_type_flags_print(state);
-
-	return 0;
-}
-
-static int dst_probe(struct dst_state *state)
-{
-	mutex_init(&state->dst_mutex);
-	if (dst_addons & DST_TYPE_HAS_CA) {
-		if ((rdc_8820_reset(state)) < 0) {
-			dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
-			return -1;
-		}
-		msleep(4000);
-	} else {
-		msleep(100);
-	}
-	if ((dst_comm_init(state)) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed.");
-		return -1;
-	}
-	msleep(100);
-	if (dst_get_device_id(state) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "unknown device.");
-		return -1;
-	}
-	if (dst_get_mac(state) < 0) {
-		dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command");
-	}
-	if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) {
-		if (dst_get_tuner_info(state) < 0)
-			dprintk(verbose, DST_INFO, 1, "Tuner: Unsupported command");
-	}
-	if (state->type_flags & DST_TYPE_HAS_TS204) {
-		dst_packsize(state, 204);
-	}
-	if (state->type_flags & DST_TYPE_HAS_FW_BUILD) {
-		if (dst_fw_ver(state) < 0) {
-			dprintk(verbose, DST_INFO, 1, "FW: Unsupported command");
-			return 0;
-		}
-		if (dst_card_type(state) < 0) {
-			dprintk(verbose, DST_INFO, 1, "Card: Unsupported command");
-			return 0;
-		}
-		if (dst_get_vendor(state) < 0) {
-			dprintk(verbose, DST_INFO, 1, "Vendor: Unsupported command");
-			return 0;
-		}
-	}
-
-	return 0;
-}
-
-static int dst_command(struct dst_state *state, u8 *data, u8 len)
-{
-	u8 reply;
-
-	mutex_lock(&state->dst_mutex);
-	if ((dst_comm_init(state)) < 0) {
-		dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed.");
-		goto error;
-	}
-	if (write_dst(state, data, len)) {
-		dprintk(verbose, DST_INFO, 1, "Trying to recover.. ");
-		if ((dst_error_recovery(state)) < 0) {
-			dprintk(verbose, DST_ERROR, 1, "Recovery Failed.");
-			goto error;
-		}
-		goto error;
-	}
-	if ((dst_pio_disable(state)) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "PIO Disable Failed.");
-		goto error;
-	}
-	if (state->type_flags & DST_TYPE_HAS_FW_1)
-		mdelay(3);
-	if (read_dst(state, &reply, GET_ACK)) {
-		dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. ");
-		if ((dst_error_recovery(state)) < 0) {
-			dprintk(verbose, DST_INFO, 1, "Recovery Failed.");
-			goto error;
-		}
-		goto error;
-	}
-	if (reply != ACK) {
-		dprintk(verbose, DST_INFO, 1, "write not acknowledged 0x%02x ", reply);
-		goto error;
-	}
-	if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3))
-		goto error;
-	if (state->type_flags & DST_TYPE_HAS_FW_1)
-		mdelay(3);
-	else
-		udelay(2000);
-	if (!dst_wait_dst_ready(state, NO_DELAY))
-		goto error;
-	if (read_dst(state, state->rxbuffer, FIXED_COMM)) {
-		dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. ");
-		if ((dst_error_recovery(state)) < 0) {
-			dprintk(verbose, DST_INFO, 1, "Recovery failed.");
-			goto error;
-		}
-		goto error;
-	}
-	if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) {
-		dprintk(verbose, DST_INFO, 1, "checksum failure");
-		goto error;
-	}
-	mutex_unlock(&state->dst_mutex);
-	return 0;
-
-error:
-	mutex_unlock(&state->dst_mutex);
-	return -EIO;
-
-}
-
-static int dst_get_signal(struct dst_state *state)
-{
-	int retval;
-	u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb };
-	//dprintk("%s: Getting Signal strength and other parameters\n", __func__);
-	if ((state->diseq_flags & ATTEMPT_TUNE) == 0) {
-		state->decode_lock = state->decode_strength = state->decode_snr = 0;
-		return 0;
-	}
-	if (0 == (state->diseq_flags & HAS_LOCK)) {
-		state->decode_lock = state->decode_strength = state->decode_snr = 0;
-		return 0;
-	}
-	if (time_after_eq(jiffies, state->cur_jiff + (HZ / 5))) {
-		retval = dst_command(state, get_signal, 8);
-		if (retval < 0)
-			return retval;
-		if (state->dst_type == DST_TYPE_IS_SAT) {
-			state->decode_lock = ((state->rxbuffer[6] & 0x10) == 0) ? 1 : 0;
-			state->decode_strength = state->rxbuffer[5] << 8;
-			state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3];
-		} else if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) {
-			state->decode_lock = (state->rxbuffer[1]) ? 1 : 0;
-			state->decode_strength = state->rxbuffer[4] << 8;
-			state->decode_snr = state->rxbuffer[3] << 8;
-		} else if (state->dst_type == DST_TYPE_IS_ATSC) {
-			state->decode_lock = (state->rxbuffer[6] == 0x00) ? 1 : 0;
-			state->decode_strength = state->rxbuffer[4] << 8;
-			state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3];
-		}
-		state->cur_jiff = jiffies;
-	}
-	return 0;
-}
-
-static int dst_tone_power_cmd(struct dst_state *state)
-{
-	u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 };
-
-	if (state->dst_type != DST_TYPE_IS_SAT)
-		return -EOPNOTSUPP;
-	paket[4] = state->tx_tuna[4];
-	paket[2] = state->tx_tuna[2];
-	paket[3] = state->tx_tuna[3];
-	paket[7] = dst_check_sum (paket, 7);
-	return dst_command(state, paket, 8);
-}
-
-static int dst_get_tuna(struct dst_state *state)
-{
-	int retval;
-
-	if ((state->diseq_flags & ATTEMPT_TUNE) == 0)
-		return 0;
-	state->diseq_flags &= ~(HAS_LOCK);
-	if (!dst_wait_dst_ready(state, NO_DELAY))
-		return -EIO;
-	if ((state->type_flags & DST_TYPE_HAS_VLF) &&
-		!(state->dst_type == DST_TYPE_IS_ATSC))
-
-		retval = read_dst(state, state->rx_tuna, 10);
-	else
-		retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM);
-	if (retval < 0) {
-		dprintk(verbose, DST_DEBUG, 1, "read not successful");
-		return retval;
-	}
-	if ((state->type_flags & DST_TYPE_HAS_VLF) &&
-	   !(state->dst_type == DST_TYPE_IS_ATSC)) {
-
-		if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
-			dprintk(verbose, DST_INFO, 1, "checksum failure ? ");
-			return -EIO;
-		}
-	} else {
-		if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) {
-			dprintk(verbose, DST_INFO, 1, "checksum failure? ");
-			return -EIO;
-		}
-	}
-	if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0)
-		return 0;
-	if (state->dst_type == DST_TYPE_IS_SAT) {
-		state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3];
-	} else {
-		state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 16) + (state->rx_tuna[3] << 8) + state->rx_tuna[4];
-	}
-	state->decode_freq = state->decode_freq * 1000;
-	state->decode_lock = 1;
-	state->diseq_flags |= HAS_LOCK;
-
-	return 1;
-}
-
-static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
-
-static int dst_write_tuna(struct dvb_frontend *fe)
-{
-	struct dst_state *state = fe->demodulator_priv;
-	int retval;
-	u8 reply;
-
-	dprintk(verbose, DST_INFO, 1, "type_flags 0x%x ", state->type_flags);
-	state->decode_freq = 0;
-	state->decode_lock = state->decode_strength = state->decode_snr = 0;
-	if (state->dst_type == DST_TYPE_IS_SAT) {
-		if (!(state->diseq_flags & HAS_POWER))
-			dst_set_voltage(fe, SEC_VOLTAGE_13);
-	}
-	state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
-	mutex_lock(&state->dst_mutex);
-	if ((dst_comm_init(state)) < 0) {
-		dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed.");
-		goto error;
-	}
-//	if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
-	if ((state->type_flags & DST_TYPE_HAS_VLF) &&
-		(!(state->dst_type == DST_TYPE_IS_ATSC))) {
-
-		state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9);
-		retval = write_dst(state, &state->tx_tuna[0], 10);
-	} else {
-		state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7);
-		retval = write_dst(state, &state->tx_tuna[2], FIXED_COMM);
-	}
-	if (retval < 0) {
-		dst_pio_disable(state);
-		dprintk(verbose, DST_DEBUG, 1, "write not successful");
-		goto werr;
-	}
-	if ((dst_pio_disable(state)) < 0) {
-		dprintk(verbose, DST_DEBUG, 1, "DST PIO disable failed !");
-		goto error;
-	}
-	if ((read_dst(state, &reply, GET_ACK) < 0)) {
-		dprintk(verbose, DST_DEBUG, 1, "read verify not successful.");
-		goto error;
-	}
-	if (reply != ACK) {
-		dprintk(verbose, DST_DEBUG, 1, "write not acknowledged 0x%02x ", reply);
-		goto error;
-	}
-	state->diseq_flags |= ATTEMPT_TUNE;
-	retval = dst_get_tuna(state);
-werr:
-	mutex_unlock(&state->dst_mutex);
-	return retval;
-
-error:
-	mutex_unlock(&state->dst_mutex);
-	return -EIO;
-}
-
-/*
- * line22k0    0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00
- * line22k1    0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00
- * line22k2    0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00
- * tone        0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00
- * data        0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00
- * power_off   0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00
- * power_on    0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00
- * Diseqc 1    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec
- * Diseqc 2    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8
- * Diseqc 3    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4
- * Diseqc 4    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0
- */
-
-static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd)
-{
-	struct dst_state *state = fe->demodulator_priv;
-	u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec };
-
-	if (state->dst_type != DST_TYPE_IS_SAT)
-		return -EOPNOTSUPP;
-	if (cmd->msg_len > 0 && cmd->msg_len < 5)
-		memcpy(&paket[3], cmd->msg, cmd->msg_len);
-	else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5)
-		memcpy(&paket[2], cmd->msg, cmd->msg_len);
-	else
-		return -EINVAL;
-	paket[7] = dst_check_sum(&paket[0], 7);
-	return dst_command(state, paket, 8);
-}
-
-static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
-	int need_cmd, retval = 0;
-	struct dst_state *state = fe->demodulator_priv;
-
-	state->voltage = voltage;
-	if (state->dst_type != DST_TYPE_IS_SAT)
-		return -EOPNOTSUPP;
-
-	need_cmd = 0;
-
-	switch (voltage) {
-	case SEC_VOLTAGE_13:
-	case SEC_VOLTAGE_18:
-		if ((state->diseq_flags & HAS_POWER) == 0)
-			need_cmd = 1;
-		state->diseq_flags |= HAS_POWER;
-		state->tx_tuna[4] = 0x01;
-		break;
-	case SEC_VOLTAGE_OFF:
-		need_cmd = 1;
-		state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE);
-		state->tx_tuna[4] = 0x00;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (need_cmd)
-		retval = dst_tone_power_cmd(state);
-
-	return retval;
-}
-
-static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
-{
-	struct dst_state *state = fe->demodulator_priv;
-
-	state->tone = tone;
-	if (state->dst_type != DST_TYPE_IS_SAT)
-		return -EOPNOTSUPP;
-
-	switch (tone) {
-	case SEC_TONE_OFF:
-		if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
-		    state->tx_tuna[2] = 0x00;
-		else
-		    state->tx_tuna[2] = 0xff;
-		break;
-
-	case SEC_TONE_ON:
-		state->tx_tuna[2] = 0x02;
-		break;
-	default:
-		return -EINVAL;
-	}
-	return dst_tone_power_cmd(state);
-}
-
-static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd)
-{
-	struct dst_state *state = fe->demodulator_priv;
-
-	if (state->dst_type != DST_TYPE_IS_SAT)
-		return -EOPNOTSUPP;
-	state->minicmd = minicmd;
-	switch (minicmd) {
-	case SEC_MINI_A:
-		state->tx_tuna[3] = 0x02;
-		break;
-	case SEC_MINI_B:
-		state->tx_tuna[3] = 0xff;
-		break;
-	}
-	return dst_tone_power_cmd(state);
-}
-
-
-static int dst_init(struct dvb_frontend *fe)
-{
-	struct dst_state *state = fe->demodulator_priv;
-
-	static u8 sat_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x00, 0x73, 0x21, 0x00, 0x00 };
-	static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 };
-	static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
-	static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
-	static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
-	static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
-	static u8 atsc_tuner[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
-
-	state->inversion = INVERSION_OFF;
-	state->voltage = SEC_VOLTAGE_13;
-	state->tone = SEC_TONE_OFF;
-	state->diseq_flags = 0;
-	state->k22 = 0x02;
-	state->bandwidth = 7000000;
-	state->cur_jiff = jiffies;
-	if (state->dst_type == DST_TYPE_IS_SAT)
-		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204));
-	else if (state->dst_type == DST_TYPE_IS_TERR)
-		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204));
-	else if (state->dst_type == DST_TYPE_IS_CABLE)
-		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204));
-	else if (state->dst_type == DST_TYPE_IS_ATSC)
-		memcpy(state->tx_tuna, atsc_tuner, sizeof (atsc_tuner));
-
-	return 0;
-}
-
-static int dst_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct dst_state *state = fe->demodulator_priv;
-
-	*status = 0;
-	if (state->diseq_flags & HAS_LOCK) {
-//		dst_get_signal(state);	// don't require(?) to ask MCU
-		if (state->decode_lock)
-			*status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI;
-	}
-
-	return 0;
-}
-
-static int dst_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct dst_state *state = fe->demodulator_priv;
-
-	int retval = dst_get_signal(state);
-	*strength = state->decode_strength;
-
-	return retval;
-}
-
-static int dst_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct dst_state *state = fe->demodulator_priv;
-
-	int retval = dst_get_signal(state);
-	*snr = state->decode_snr;
-
-	return retval;
-}
-
-static int dst_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	int retval = -EINVAL;
-	struct dst_state *state = fe->demodulator_priv;
-
-	if (p != NULL) {
-		retval = dst_set_freq(state, p->frequency);
-		if(retval != 0)
-			return retval;
-		dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
-
-		if (state->dst_type == DST_TYPE_IS_SAT) {
-			if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
-				dst_set_inversion(state, p->inversion);
-			dst_set_fec(state, p->fec_inner);
-			dst_set_symbolrate(state, p->symbol_rate);
-			dst_set_polarization(state);
-			dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate);
-
-		} else if (state->dst_type == DST_TYPE_IS_TERR)
-			dst_set_bandwidth(state, p->bandwidth_hz);
-		else if (state->dst_type == DST_TYPE_IS_CABLE) {
-			dst_set_fec(state, p->fec_inner);
-			dst_set_symbolrate(state, p->symbol_rate);
-			dst_set_modulation(state, p->modulation);
-		}
-		retval = dst_write_tuna(fe);
-	}
-
-	return retval;
-}
-
-static int dst_tune_frontend(struct dvb_frontend* fe,
-			    bool re_tune,
-			    unsigned int mode_flags,
-			    unsigned int *delay,
-			    fe_status_t *status)
-{
-	struct dst_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-
-	if (re_tune) {
-		dst_set_freq(state, p->frequency);
-		dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
-
-		if (state->dst_type == DST_TYPE_IS_SAT) {
-			if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
-				dst_set_inversion(state, p->inversion);
-			dst_set_fec(state, p->fec_inner);
-			dst_set_symbolrate(state, p->symbol_rate);
-			dst_set_polarization(state);
-			dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate);
-
-		} else if (state->dst_type == DST_TYPE_IS_TERR)
-			dst_set_bandwidth(state, p->bandwidth_hz);
-		else if (state->dst_type == DST_TYPE_IS_CABLE) {
-			dst_set_fec(state, p->fec_inner);
-			dst_set_symbolrate(state, p->symbol_rate);
-			dst_set_modulation(state, p->modulation);
-		}
-		dst_write_tuna(fe);
-	}
-
-	if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
-		dst_read_status(fe, status);
-
-	*delay = HZ/10;
-	return 0;
-}
-
-static int dst_get_tuning_algo(struct dvb_frontend *fe)
-{
-	return dst_algo ? DVBFE_ALGO_HW : DVBFE_ALGO_SW;
-}
-
-static int dst_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct dst_state *state = fe->demodulator_priv;
-
-	p->frequency = state->decode_freq;
-	if (state->dst_type == DST_TYPE_IS_SAT) {
-		if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
-			p->inversion = state->inversion;
-		p->symbol_rate = state->symbol_rate;
-		p->fec_inner = dst_get_fec(state);
-	} else if (state->dst_type == DST_TYPE_IS_TERR) {
-		p->bandwidth_hz = state->bandwidth;
-	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
-		p->symbol_rate = state->symbol_rate;
-		p->fec_inner = dst_get_fec(state);
-		p->modulation = dst_get_modulation(state);
-	}
-
-	return 0;
-}
-
-static void dst_release(struct dvb_frontend *fe)
-{
-	struct dst_state *state = fe->demodulator_priv;
-	if (state->dst_ca) {
-		dvb_unregister_device(state->dst_ca);
-#ifdef CONFIG_MEDIA_ATTACH
-		symbol_put(dst_ca_attach);
-#endif
-	}
-	kfree(state);
-}
-
-static struct dvb_frontend_ops dst_dvbt_ops;
-static struct dvb_frontend_ops dst_dvbs_ops;
-static struct dvb_frontend_ops dst_dvbc_ops;
-static struct dvb_frontend_ops dst_atsc_ops;
-
-struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter)
-{
-	/* check if the ASIC is there */
-	if (dst_probe(state) < 0) {
-		kfree(state);
-		return NULL;
-	}
-	/* determine settings based on type */
-	/* create dvb_frontend */
-	switch (state->dst_type) {
-	case DST_TYPE_IS_TERR:
-		memcpy(&state->frontend.ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
-		break;
-	case DST_TYPE_IS_CABLE:
-		memcpy(&state->frontend.ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
-		break;
-	case DST_TYPE_IS_SAT:
-		memcpy(&state->frontend.ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
-		break;
-	case DST_TYPE_IS_ATSC:
-		memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops));
-		break;
-	default:
-		dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist.");
-		kfree(state);
-		return NULL;
-	}
-	state->frontend.demodulator_priv = state;
-
-	return state;				/*	Manu (DST is a card not a frontend)	*/
-}
-
-EXPORT_SYMBOL(dst_attach);
-
-static struct dvb_frontend_ops dst_dvbt_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name = "DST DVB-T",
-		.frequency_min = 137000000,
-		.frequency_max = 858000000,
-		.frequency_stepsize = 166667,
-		.caps = FE_CAN_FEC_AUTO			|
-			FE_CAN_QAM_AUTO			|
-			FE_CAN_QAM_16			|
-			FE_CAN_QAM_32			|
-			FE_CAN_QAM_64			|
-			FE_CAN_QAM_128			|
-			FE_CAN_QAM_256			|
-			FE_CAN_TRANSMISSION_MODE_AUTO	|
-			FE_CAN_GUARD_INTERVAL_AUTO
-	},
-
-	.release = dst_release,
-	.init = dst_init,
-	.tune = dst_tune_frontend,
-	.set_frontend = dst_set_frontend,
-	.get_frontend = dst_get_frontend,
-	.get_frontend_algo = dst_get_tuning_algo,
-	.read_status = dst_read_status,
-	.read_signal_strength = dst_read_signal_strength,
-	.read_snr = dst_read_snr,
-};
-
-static struct dvb_frontend_ops dst_dvbs_ops = {
-	.delsys = { SYS_DVBS },
-	.info = {
-		.name = "DST DVB-S",
-		.frequency_min = 950000,
-		.frequency_max = 2150000,
-		.frequency_stepsize = 1000,	/* kHz for QPSK frontends */
-		.frequency_tolerance = 29500,
-		.symbol_rate_min = 1000000,
-		.symbol_rate_max = 45000000,
-	/*     . symbol_rate_tolerance	=	???,*/
-		.caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK
-	},
-
-	.release = dst_release,
-	.init = dst_init,
-	.tune = dst_tune_frontend,
-	.set_frontend = dst_set_frontend,
-	.get_frontend = dst_get_frontend,
-	.get_frontend_algo = dst_get_tuning_algo,
-	.read_status = dst_read_status,
-	.read_signal_strength = dst_read_signal_strength,
-	.read_snr = dst_read_snr,
-	.diseqc_send_burst = dst_send_burst,
-	.diseqc_send_master_cmd = dst_set_diseqc,
-	.set_voltage = dst_set_voltage,
-	.set_tone = dst_set_tone,
-};
-
-static struct dvb_frontend_ops dst_dvbc_ops = {
-	.delsys = { SYS_DVBC_ANNEX_A },
-	.info = {
-		.name = "DST DVB-C",
-		.frequency_stepsize = 62500,
-		.frequency_min = 51000000,
-		.frequency_max = 858000000,
-		.symbol_rate_min = 1000000,
-		.symbol_rate_max = 45000000,
-		.caps = FE_CAN_FEC_AUTO |
-			FE_CAN_QAM_AUTO |
-			FE_CAN_QAM_16	|
-			FE_CAN_QAM_32	|
-			FE_CAN_QAM_64	|
-			FE_CAN_QAM_128	|
-			FE_CAN_QAM_256
-	},
-
-	.release = dst_release,
-	.init = dst_init,
-	.tune = dst_tune_frontend,
-	.set_frontend = dst_set_frontend,
-	.get_frontend = dst_get_frontend,
-	.get_frontend_algo = dst_get_tuning_algo,
-	.read_status = dst_read_status,
-	.read_signal_strength = dst_read_signal_strength,
-	.read_snr = dst_read_snr,
-};
-
-static struct dvb_frontend_ops dst_atsc_ops = {
-	.delsys = { SYS_ATSC },
-	.info = {
-		.name = "DST ATSC",
-		.frequency_stepsize = 62500,
-		.frequency_min = 510000000,
-		.frequency_max = 858000000,
-		.symbol_rate_min = 1000000,
-		.symbol_rate_max = 45000000,
-		.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
-	},
-
-	.release = dst_release,
-	.init = dst_init,
-	.tune = dst_tune_frontend,
-	.set_frontend = dst_set_frontend,
-	.get_frontend = dst_get_frontend,
-	.get_frontend_algo = dst_get_tuning_algo,
-	.read_status = dst_read_status,
-	.read_signal_strength = dst_read_signal_strength,
-	.read_snr = dst_read_snr,
-};
-
-MODULE_DESCRIPTION("DST DVB-S/T/C/ATSC Combo Frontend driver");
-MODULE_AUTHOR("Jamie Honan, Manu Abraham");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
deleted file mode 100644
index 66f52f1..0000000
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ /dev/null
@@ -1,725 +0,0 @@
-/*
-	CA-driver for TwinHan DST Frontend/Card
-
-	Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/string.h>
-#include <linux/dvb/ca.h>
-#include "dvbdev.h"
-#include "dvb_frontend.h"
-#include "dst_ca.h"
-#include "dst_common.h"
-
-#define DST_CA_ERROR		0
-#define DST_CA_NOTICE		1
-#define DST_CA_INFO		2
-#define DST_CA_DEBUG		3
-
-#define dprintk(x, y, z, format, arg...) do {						\
-	if (z) {									\
-		if	((x > DST_CA_ERROR) && (x > y))					\
-			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);	\
-		else if	((x > DST_CA_NOTICE) && (x > y))				\
-			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
-		else if ((x > DST_CA_INFO) && (x > y))					\
-			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);	\
-		else if ((x > DST_CA_DEBUG) && (x > y))					\
-			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
-	} else {									\
-		if (x > y)								\
-			printk(format, ## arg);						\
-	}										\
-} while(0)
-
-
-static DEFINE_MUTEX(dst_ca_mutex);
-static unsigned int verbose = 5;
-module_param(verbose, int, 0644);
-MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
-
-/*	Need some more work	*/
-static int ca_set_slot_descr(void)
-{
-	/*	We could make this more graceful ?	*/
-	return -EOPNOTSUPP;
-}
-
-/*	Need some more work	*/
-static int ca_set_pid(void)
-{
-	/*	We could make this more graceful ?	*/
-	return -EOPNOTSUPP;
-}
-
-static void put_command_and_length(u8 *data, int command, int length)
-{
-	data[0] = (command >> 16) & 0xff;
-	data[1] = (command >> 8) & 0xff;
-	data[2] = command & 0xff;
-	data[3] = length;
-}
-
-static void put_checksum(u8 *check_string, int length)
-{
-	dprintk(verbose, DST_CA_DEBUG, 1, " Computing string checksum.");
-	dprintk(verbose, DST_CA_DEBUG, 1, "  -> string length : 0x%02x", length);
-	check_string[length] = dst_check_sum (check_string, length);
-	dprintk(verbose, DST_CA_DEBUG, 1, "  -> checksum      : 0x%02x", check_string[length]);
-}
-
-static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read)
-{
-	u8 reply;
-
-	mutex_lock(&state->dst_mutex);
-	dst_comm_init(state);
-	msleep(65);
-
-	if (write_dst(state, data, len)) {
-		dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover");
-		dst_error_recovery(state);
-		goto error;
-	}
-	if ((dst_pio_disable(state)) < 0) {
-		dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed.");
-		goto error;
-	}
-	if (read_dst(state, &reply, GET_ACK) < 0) {
-		dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
-		dst_error_recovery(state);
-		goto error;
-	}
-	if (read) {
-		if (! dst_wait_dst_ready(state, LONG_DELAY)) {
-			dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready");
-			goto error;
-		}
-		if (read_dst(state, ca_string, 128) < 0) {	/*	Try to make this dynamic	*/
-			dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
-			dst_error_recovery(state);
-			goto error;
-		}
-	}
-	mutex_unlock(&state->dst_mutex);
-	return 0;
-
-error:
-	mutex_unlock(&state->dst_mutex);
-	return -EIO;
-}
-
-
-static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, int read)
-{
-	u8 dst_ca_comm_err = 0;
-
-	while (dst_ca_comm_err < RETRIES) {
-		dprintk(verbose, DST_CA_NOTICE, 1, " Put Command");
-		if (dst_ci_command(state, data, ca_string, len, read)) {	// If error
-			dst_error_recovery(state);
-			dst_ca_comm_err++; // work required here.
-		} else {
-			break;
-		}
-	}
-
-	if(dst_ca_comm_err == RETRIES)
-		return -1;
-
-	return 0;
-}
-
-
-
-static int ca_get_app_info(struct dst_state *state)
-{
-	int length, str_length;
-	static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff};
-
-	put_checksum(&command[0], command[0]);
-	if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) {
-		dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
-		return -1;
-	}
-	dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
-	dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================");
-	dprintk(verbose, DST_CA_INFO, 1, " Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]",
-		state->messages[7], (state->messages[8] << 8) | state->messages[9],
-		(state->messages[10] << 8) | state->messages[11], __func__, (char *)(&state->messages[12]));
-	dprintk(verbose, DST_CA_INFO, 1, " ==================================================================================================");
-
-	// Transform dst message to correct application_info message
-	length = state->messages[5];
-	str_length = length - 6;
-	if (str_length < 0) {
-		str_length = 0;
-		dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering.");
-	}
-
-	// First, the command and length fields
-	put_command_and_length(&state->messages[0], CA_APP_INFO, length);
-
-	// Copy application_type, application_manufacturer and manufacturer_code
-	memcpy(&state->messages[4], &state->messages[7], 5);
-
-	// Set string length and copy string
-	state->messages[9] = str_length;
-	memcpy(&state->messages[10], &state->messages[12], str_length);
-
-	return 0;
-}
-
-static int ca_get_ca_info(struct dst_state *state)
-{
-	int srcPtr, dstPtr, i, num_ids;
-	static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff};
-	const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7;
-
-	put_checksum(&slot_command[0], slot_command[0]);
-	if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) {
-		dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
-		return -1;
-	}
-	dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
-
-	// Print raw data
-	dprintk(verbose, DST_CA_INFO, 0, " DST data = [");
-	for (i = 0; i < state->messages[0] + 1; i++) {
-		dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]);
-	}
-	dprintk(verbose, DST_CA_INFO, 0, "]\n");
-
-	// Set the command and length of the output
-	num_ids = state->messages[in_num_ids_pos];
-	if (num_ids >= 100) {
-		num_ids = 100;
-		dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering.");
-	}
-	put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2);
-
-	dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = [");
-	srcPtr = in_system_id_pos;
-	dstPtr = out_system_id_pos;
-	for(i = 0; i < num_ids; i++) {
-		dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]);
-		// Append to output
-		state->messages[dstPtr + 0] = state->messages[srcPtr + 0];
-		state->messages[dstPtr + 1] = state->messages[srcPtr + 1];
-		srcPtr += 2;
-		dstPtr += 2;
-	}
-	dprintk(verbose, DST_CA_INFO, 0, "]\n");
-
-	return 0;
-}
-
-static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void __user *arg)
-{
-	int i;
-	u8 slot_cap[256];
-	static u8 slot_command[8] = {0x07, 0x40, 0x02, 0x00, 0x02, 0x00, 0x00, 0xff};
-
-	put_checksum(&slot_command[0], slot_command[0]);
-	if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) {
-		dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
-		return -1;
-	}
-	dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !");
-
-	/*	Will implement the rest soon		*/
-
-	dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]);
-	dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
-	for (i = 0; i < slot_cap[0] + 1; i++)
-		dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]);
-	dprintk(verbose, DST_CA_INFO, 0, "\n");
-
-	p_ca_caps->slot_num = 1;
-	p_ca_caps->slot_type = 1;
-	p_ca_caps->descr_num = slot_cap[7];
-	p_ca_caps->descr_type = 1;
-
-	if (copy_to_user(arg, p_ca_caps, sizeof (struct ca_caps)))
-		return -EFAULT;
-
-	return 0;
-}
-
-/*	Need some more work	*/
-static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
-{
-	return -EOPNOTSUPP;
-}
-
-
-static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void __user *arg)
-{
-	int i;
-	static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
-
-	u8 *slot_info = state->messages;
-
-	put_checksum(&slot_command[0], 7);
-	if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) {
-		dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
-		return -1;
-	}
-	dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
-
-	/*	Will implement the rest soon		*/
-
-	dprintk(verbose, DST_CA_INFO, 1, " Slot info = [%d]", slot_info[3]);
-	dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
-	for (i = 0; i < 8; i++)
-		dprintk(verbose, DST_CA_INFO, 0, " %d", slot_info[i]);
-	dprintk(verbose, DST_CA_INFO, 0, "\n");
-
-	if (slot_info[4] & 0x80) {
-		p_ca_slot_info->flags = CA_CI_MODULE_PRESENT;
-		p_ca_slot_info->num = 1;
-		p_ca_slot_info->type = CA_CI;
-	} else if (slot_info[4] & 0x40) {
-		p_ca_slot_info->flags = CA_CI_MODULE_READY;
-		p_ca_slot_info->num = 1;
-		p_ca_slot_info->type = CA_CI;
-	} else
-		p_ca_slot_info->flags = 0;
-
-	if (copy_to_user(arg, p_ca_slot_info, sizeof (struct ca_slot_info)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
-{
-	u8 i = 0;
-	u32 command = 0;
-
-	if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg)))
-		return -EFAULT;
-
-	if (p_ca_message->msg) {
-		dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%02x %02x %02x]", p_ca_message->msg[0], p_ca_message->msg[1], p_ca_message->msg[2]);
-
-		for (i = 0; i < 3; i++) {
-			command = command | p_ca_message->msg[i];
-			if (i < 2)
-				command = command << 8;
-		}
-		dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command);
-
-		switch (command) {
-		case CA_APP_INFO:
-			memcpy(p_ca_message->msg, state->messages, 128);
-			if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
-				return -EFAULT;
-			break;
-		case CA_INFO:
-			memcpy(p_ca_message->msg, state->messages, 128);
-			if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
-				return -EFAULT;
-			break;
-		}
-	}
-
-	return 0;
-}
-
-static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length)
-{
-	if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) {
-		hw_buffer->msg[2] = p_ca_message->msg[1];	/*	MSB	*/
-		hw_buffer->msg[3] = p_ca_message->msg[2];	/*	LSB	*/
-	} else {
-		if (length > 247) {
-			dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !");
-			return -1;
-		}
-		hw_buffer->msg[0] = (length & 0xff) + 7;
-		hw_buffer->msg[1] = 0x40;
-		hw_buffer->msg[2] = 0x03;
-		hw_buffer->msg[3] = 0x00;
-		hw_buffer->msg[4] = 0x03;
-		hw_buffer->msg[5] = length & 0xff;
-		hw_buffer->msg[6] = 0x00;
-
-		/*
-		 *	Need to compute length for EN50221 section 8.3.2, for the time being
-		 *	assuming 8.3.2 is not applicable
-		 */
-		memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length);
-	}
-
-	return 0;
-}
-
-static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply)
-{
-	if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) {
-		dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed.");
-		dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST.");
-		rdc_reset_state(state);
-		return -1;
-	}
-	dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success.");
-
-	return 0;
-}
-
-static u32 asn_1_decode(u8 *asn_1_array)
-{
-	u8 length_field = 0, word_count = 0, count = 0;
-	u32 length = 0;
-
-	length_field = asn_1_array[0];
-	dprintk(verbose, DST_CA_DEBUG, 1, " Length field=[%02x]", length_field);
-	if (length_field < 0x80) {
-		length = length_field & 0x7f;
-		dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%02x]\n", length);
-	} else {
-		word_count = length_field & 0x7f;
-		for (count = 0; count < word_count; count++) {
-			length = length  << 8;
-			length += asn_1_array[count + 1];
-			dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length);
-		}
-	}
-	return length;
-}
-
-static int debug_string(u8 *msg, u32 length, u32 offset)
-{
-	u32 i;
-
-	dprintk(verbose, DST_CA_DEBUG, 0, " String=[ ");
-	for (i = offset; i < length; i++)
-		dprintk(verbose, DST_CA_DEBUG, 0, "%02x ", msg[i]);
-	dprintk(verbose, DST_CA_DEBUG, 0, "]\n");
-
-	return 0;
-}
-
-
-static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
-{
-	u32 length = 0;
-	u8 tag_length = 8;
-
-	length = asn_1_decode(&p_ca_message->msg[3]);
-	dprintk(verbose, DST_CA_DEBUG, 1, " CA Message length=[%d]", length);
-	debug_string(&p_ca_message->msg[4], length, 0); /*	length is excluding tag & length	*/
-
-	memset(hw_buffer->msg, '\0', length);
-	handle_dst_tag(state, p_ca_message, hw_buffer, length);
-	put_checksum(hw_buffer->msg, hw_buffer->msg[0]);
-
-	debug_string(hw_buffer->msg, (length + tag_length), 0); /*	tags too	*/
-	write_to_8820(state, hw_buffer, (length + tag_length), reply);
-
-	return 0;
-}
-
-
-/*	Board supports CA PMT reply ?		*/
-static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
-{
-	int ca_pmt_reply_test = 0;
-
-	/*	Do test board			*/
-	/*	Not there yet but soon		*/
-
-	/*	CA PMT Reply capable		*/
-	if (ca_pmt_reply_test) {
-		if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) {
-			dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
-			return -1;
-		}
-
-	/*	Process CA PMT Reply		*/
-	/*	will implement soon		*/
-		dprintk(verbose, DST_CA_ERROR, 1, " Not there yet");
-	}
-	/*	CA PMT Reply not capable	*/
-	if (!ca_pmt_reply_test) {
-		if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) {
-			dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
-			return -1;
-		}
-		dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !");
-	/*	put a dummy message		*/
-
-	}
-	return 0;
-}
-
-static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
-{
-	int i = 0;
-
-	u32 command = 0;
-	struct ca_msg *hw_buffer;
-	int result = 0;
-
-	if ((hw_buffer = kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
-		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
-		return -ENOMEM;
-	}
-	dprintk(verbose, DST_CA_DEBUG, 1, " ");
-
-	if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) {
-		result = -EFAULT;
-		goto free_mem_and_exit;
-	}
-
-
-	if (p_ca_message->msg) {
-		/*	EN50221 tag	*/
-		command = 0;
-
-		for (i = 0; i < 3; i++) {
-			command = command | p_ca_message->msg[i];
-			if (i < 2)
-				command = command << 8;
-		}
-		dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command);
-
-		switch (command) {
-		case CA_PMT:
-			dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT");
-			if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) {	// code simplification started
-				dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !");
-				result = -1;
-				goto free_mem_and_exit;
-			}
-			dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !");
-			break;
-		case CA_PMT_REPLY:
-			dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY");
-			/*      Have to handle the 2 basic types of cards here  */
-			if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) {
-				dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !");
-				result = -1;
-				goto free_mem_and_exit;
-			}
-			dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !");
-			break;
-		case CA_APP_INFO_ENQUIRY:		// only for debugging
-			dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information");
-
-			if ((ca_get_app_info(state)) < 0) {
-				dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !");
-				result = -1;
-				goto free_mem_and_exit;
-			}
-			dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
-			break;
-		case CA_INFO_ENQUIRY:
-			dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information");
-
-			if ((ca_get_ca_info(state)) < 0) {
-				dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !");
-				result = -1;
-				goto free_mem_and_exit;
-			}
-			dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !");
-			break;
-		}
-	}
-free_mem_and_exit:
-	kfree (hw_buffer);
-
-	return result;
-}
-
-static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioctl_arg)
-{
-	struct dvb_device *dvbdev;
-	struct dst_state *state;
-	struct ca_slot_info *p_ca_slot_info;
-	struct ca_caps *p_ca_caps;
-	struct ca_msg *p_ca_message;
-	void __user *arg = (void __user *)ioctl_arg;
-	int result = 0;
-
-	mutex_lock(&dst_ca_mutex);
-	dvbdev = file->private_data;
-	state = (struct dst_state *)dvbdev->priv;
-	p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
-	p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
-	p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL);
-	if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) {
-		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
-		result = -ENOMEM;
-		goto free_mem_and_exit;
-	}
-
-	/*	We have now only the standard ioctl's, the driver is upposed to handle internals.	*/
-	switch (cmd) {
-	case CA_SEND_MSG:
-		dprintk(verbose, DST_CA_INFO, 1, " Sending message");
-		if ((ca_send_message(state, p_ca_message, arg)) < 0) {
-			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !");
-			result = -1;
-			goto free_mem_and_exit;
-		}
-		break;
-	case CA_GET_MSG:
-		dprintk(verbose, DST_CA_INFO, 1, " Getting message");
-		if ((ca_get_message(state, p_ca_message, arg)) < 0) {
-			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !");
-			result = -1;
-			goto free_mem_and_exit;
-		}
-		dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !");
-		break;
-	case CA_RESET:
-		dprintk(verbose, DST_CA_ERROR, 1, " Resetting DST");
-		dst_error_bailout(state);
-		msleep(4000);
-		break;
-	case CA_GET_SLOT_INFO:
-		dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info");
-		if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) {
-			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !");
-			result = -1;
-			goto free_mem_and_exit;
-		}
-		dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !");
-		break;
-	case CA_GET_CAP:
-		dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities");
-		if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) {
-			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !");
-			result = -1;
-			goto free_mem_and_exit;
-		}
-		dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !");
-		break;
-	case CA_GET_DESCR_INFO:
-		dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description");
-		if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) {
-			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !");
-			result = -1;
-			goto free_mem_and_exit;
-		}
-		dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !");
-		break;
-	case CA_SET_DESCR:
-		dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler");
-		if ((ca_set_slot_descr()) < 0) {
-			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !");
-			result = -1;
-			goto free_mem_and_exit;
-		}
-		dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !");
-		break;
-	case CA_SET_PID:
-		dprintk(verbose, DST_CA_INFO, 1, " Setting PID");
-		if ((ca_set_pid()) < 0) {
-			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !");
-			result = -1;
-			goto free_mem_and_exit;
-		}
-		dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !");
-	default:
-		result = -EOPNOTSUPP;
-	};
- free_mem_and_exit:
-	kfree (p_ca_message);
-	kfree (p_ca_slot_info);
-	kfree (p_ca_caps);
-
-	mutex_unlock(&dst_ca_mutex);
-	return result;
-}
-
-static int dst_ca_open(struct inode *inode, struct file *file)
-{
-	dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file);
-	try_module_get(THIS_MODULE);
-
-	return 0;
-}
-
-static int dst_ca_release(struct inode *inode, struct file *file)
-{
-	dprintk(verbose, DST_CA_DEBUG, 1, " Device closed.");
-	module_put(THIS_MODULE);
-
-	return 0;
-}
-
-static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
-{
-	ssize_t bytes_read = 0;
-
-	dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
-
-	return bytes_read;
-}
-
-static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
-{
-	dprintk(verbose, DST_CA_DEBUG, 1, " Device write.");
-
-	return 0;
-}
-
-static const struct file_operations dst_ca_fops = {
-	.owner = THIS_MODULE,
-	.unlocked_ioctl = dst_ca_ioctl,
-	.open = dst_ca_open,
-	.release = dst_ca_release,
-	.read = dst_ca_read,
-	.write = dst_ca_write,
-	.llseek = noop_llseek,
-};
-
-static struct dvb_device dvbdev_ca = {
-	.priv = NULL,
-	.users = 1,
-	.readers = 1,
-	.writers = 1,
-	.fops = &dst_ca_fops
-};
-
-struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter)
-{
-	struct dvb_device *dvbdev;
-
-	dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device");
-	if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) {
-		dst->dst_ca = dvbdev;
-		return dst->dst_ca;
-	}
-
-	return NULL;
-}
-
-EXPORT_SYMBOL(dst_ca_attach);
-
-MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver");
-MODULE_AUTHOR("Manu Abraham");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/bt8xx/dst_ca.h b/drivers/media/dvb/bt8xx/dst_ca.h
deleted file mode 100644
index 59cd0dd..0000000
--- a/drivers/media/dvb/bt8xx/dst_ca.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-	CA-driver for TwinHan DST Frontend/Card
-
-	Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef _DST_CA_H_
-#define _DST_CA_H_
-
-#define RETRIES			5
-
-
-#define	CA_APP_INFO_ENQUIRY	0x9f8020
-#define	CA_APP_INFO		0x9f8021
-#define	CA_ENTER_MENU		0x9f8022
-#define CA_INFO_ENQUIRY		0x9f8030
-#define	CA_INFO			0x9f8031
-#define CA_PMT			0x9f8032
-#define CA_PMT_REPLY		0x9f8033
-
-#define CA_CLOSE_MMI		0x9f8800
-#define CA_DISPLAY_CONTROL	0x9f8801
-#define CA_DISPLAY_REPLY	0x9f8802
-#define CA_TEXT_LAST		0x9f8803
-#define CA_TEXT_MORE		0x9f8804
-#define CA_KEYPAD_CONTROL	0x9f8805
-#define CA_KEYPRESS		0x9f8806
-
-#define CA_ENQUIRY		0x9f8807
-#define CA_ANSWER		0x9f8808
-#define CA_MENU_LAST		0x9f8809
-#define CA_MENU_MORE		0x9f880a
-#define CA_MENU_ANSWER		0x9f880b
-#define CA_LIST_LAST		0x9f880c
-#define CA_LIST_MORE		0x9f880d
-
-
-struct dst_ca_private {
-	struct dst_state *dst;
-	struct dvb_device *dvbdev;
-};
-
-
-#endif
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
deleted file mode 100644
index d70d98f..0000000
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
-	Frontend-driver for TwinHan DST Frontend
-
-	Copyright (C) 2003 Jamie Honan
-	Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef DST_COMMON_H
-#define DST_COMMON_H
-
-#include <linux/dvb/frontend.h>
-#include <linux/device.h>
-#include <linux/mutex.h>
-#include "bt878.h"
-
-#include "dst_ca.h"
-
-
-#define NO_DELAY		0
-#define LONG_DELAY		1
-#define DEVICE_INIT		2
-
-#define DELAY			1
-
-#define DST_TYPE_IS_SAT		0
-#define DST_TYPE_IS_TERR	1
-#define DST_TYPE_IS_CABLE	2
-#define DST_TYPE_IS_ATSC	3
-
-#define DST_TYPE_HAS_TS188	1
-#define DST_TYPE_HAS_TS204	2
-#define DST_TYPE_HAS_SYMDIV	4
-#define DST_TYPE_HAS_FW_1	8
-#define DST_TYPE_HAS_FW_2	16
-#define DST_TYPE_HAS_FW_3	32
-#define DST_TYPE_HAS_FW_BUILD	64
-#define DST_TYPE_HAS_OBS_REGS	128
-#define DST_TYPE_HAS_INC_COUNT	256
-#define DST_TYPE_HAS_MULTI_FE	512
-#define DST_TYPE_HAS_NEWTUNE_2	1024
-#define DST_TYPE_HAS_DBOARD	2048
-#define DST_TYPE_HAS_VLF	4096
-
-/*	Card capability list	*/
-
-#define DST_TYPE_HAS_MAC	1
-#define DST_TYPE_HAS_DISEQC3	2
-#define DST_TYPE_HAS_DISEQC4	4
-#define DST_TYPE_HAS_DISEQC5	8
-#define DST_TYPE_HAS_MOTO	16
-#define DST_TYPE_HAS_CA		32
-#define	DST_TYPE_HAS_ANALOG	64	/*	Analog inputs	*/
-#define DST_TYPE_HAS_SESSION	128
-
-#define TUNER_TYPE_MULTI	1
-#define TUNER_TYPE_UNKNOWN	2
-/*	DVB-S		*/
-#define TUNER_TYPE_L64724	4
-#define TUNER_TYPE_STV0299	8
-#define TUNER_TYPE_MB86A15	16
-
-/*	DVB-T		*/
-#define TUNER_TYPE_TDA10046	32
-
-/*	ATSC		*/
-#define TUNER_TYPE_NXT200x	64
-
-
-#define RDC_8820_PIO_0_DISABLE	0
-#define RDC_8820_PIO_0_ENABLE	1
-#define RDC_8820_INT		2
-#define RDC_8820_RESET		4
-
-/*	DST Communication	*/
-#define GET_REPLY		1
-#define NO_REPLY		0
-
-#define GET_ACK			1
-#define FIXED_COMM		8
-
-#define ACK			0xff
-
-struct dst_state {
-
-	struct i2c_adapter* i2c;
-
-	struct bt878* bt;
-
-	/* configuration settings */
-	const struct dst_config* config;
-
-	struct dvb_frontend frontend;
-
-	/* private ASIC data */
-	u8 tx_tuna[10];
-	u8 rx_tuna[10];
-	u8 rxbuffer[10];
-	u8 diseq_flags;
-	u8 dst_type;
-	u32 type_flags;
-	u32 frequency;		/* intermediate frequency in kHz for QPSK */
-	fe_spectral_inversion_t inversion;
-	u32 symbol_rate;	/* symbol rate in Symbols per second */
-	fe_code_rate_t fec;
-	fe_sec_voltage_t voltage;
-	fe_sec_tone_mode_t tone;
-	u32 decode_freq;
-	u8 decode_lock;
-	u16 decode_strength;
-	u16 decode_snr;
-	unsigned long cur_jiff;
-	u8 k22;
-	u32 bandwidth;
-	u32 dst_hw_cap;
-	u8 dst_fw_version;
-	fe_sec_mini_cmd_t minicmd;
-	fe_modulation_t modulation;
-	u8 messages[256];
-	u8 mac_address[8];
-	u8 fw_version[8];
-	u8 card_info[8];
-	u8 vendor[8];
-	u8 board_info[8];
-	u32 tuner_type;
-	char *tuner_name;
-	struct mutex dst_mutex;
-	u8 fw_name[8];
-	struct dvb_device *dst_ca;
-};
-
-struct tuner_types {
-	u32 tuner_type;
-	char *tuner_name;
-	char *board_name;
-	char *fw_name;
-};
-
-struct dst_types {
-	char *device_id;
-	int offset;
-	u8 dst_type;
-	u32 type_flags;
-	u32 dst_feature;
-	u32 tuner_type;
-};
-
-struct dst_config
-{
-	/* the ASIC i2c address */
-	u8 demod_address;
-};
-
-int rdc_reset_state(struct dst_state *state);
-
-int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode);
-int dst_pio_disable(struct dst_state *state);
-int dst_error_recovery(struct dst_state* state);
-int dst_error_bailout(struct dst_state *state);
-int dst_comm_init(struct dst_state* state);
-
-int write_dst(struct dst_state *state, u8 * data, u8 len);
-int read_dst(struct dst_state *state, u8 * ret, u8 len);
-u8 dst_check_sum(u8 * buf, u32 len);
-struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter);
-struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter);
-
-
-#endif // DST_COMMON_H
diff --git a/drivers/media/dvb/bt8xx/dst_priv.h b/drivers/media/dvb/bt8xx/dst_priv.h
deleted file mode 100644
index 3974a4c..0000000
--- a/drivers/media/dvb/bt8xx/dst_priv.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * dst-bt878.h: part of the DST driver for the TwinHan DST Frontend
- *
- * Copyright (C) 2003 Jamie Honan
- */
-
-struct dst_gpio_enable {
-	u32	mask;
-	u32	enable;
-};
-
-struct dst_gpio_output {
-	u32	mask;
-	u32	highvals;
-};
-
-struct dst_gpio_read {
-	unsigned long value;
-};
-
-union dst_gpio_packet {
-	struct dst_gpio_enable enb;
-	struct dst_gpio_output outp;
-	struct dst_gpio_read rd;
-	int    psize;
-};
-
-#define DST_IG_ENABLE	0
-#define DST_IG_WRITE	1
-#define DST_IG_READ	2
-#define DST_IG_TS       3
-
-struct bt878;
-
-int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp);
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
deleted file mode 100644
index 81fab9a..0000000
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ /dev/null
@@ -1,975 +0,0 @@
-/*
- * Bt8xx based DVB adapter driver
- *
- * Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#define pr_fmt(fmt) "dvb_bt8xx: " fmt
-
-#include <linux/bitops.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb-bt8xx.h"
-#include "bt878.h"
-
-static int debug;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define dprintk( args... ) \
-	do { \
-		if (debug) printk(KERN_DEBUG args); \
-	} while (0)
-
-#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
-
-static void dvb_bt8xx_task(unsigned long data)
-{
-	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *)data;
-
-	//printk("%d ", card->bt->finished_block);
-
-	while (card->bt->last_block != card->bt->finished_block) {
-		(card->bt->TS_Size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter)
-			(&card->demux,
-			 &card->bt->buf_cpu[card->bt->last_block *
-					    card->bt->block_bytes],
-			 card->bt->block_bytes);
-		card->bt->last_block = (card->bt->last_block + 1) %
-					card->bt->block_count;
-	}
-}
-
-static int dvb_bt8xx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux*dvbdmx = dvbdmxfeed->demux;
-	struct dvb_bt8xx_card *card = dvbdmx->priv;
-	int rc;
-
-	dprintk("dvb_bt8xx: start_feed\n");
-
-	if (!dvbdmx->dmx.frontend)
-		return -EINVAL;
-
-	mutex_lock(&card->lock);
-	card->nfeeds++;
-	rc = card->nfeeds;
-	if (card->nfeeds == 1)
-		bt878_start(card->bt, card->gpio_mode,
-			    card->op_sync_orin, card->irq_err_ignore);
-	mutex_unlock(&card->lock);
-	return rc;
-}
-
-static int dvb_bt8xx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-	struct dvb_bt8xx_card *card = dvbdmx->priv;
-
-	dprintk("dvb_bt8xx: stop_feed\n");
-
-	if (!dvbdmx->dmx.frontend)
-		return -EINVAL;
-
-	mutex_lock(&card->lock);
-	card->nfeeds--;
-	if (card->nfeeds == 0)
-		bt878_stop(card->bt);
-	mutex_unlock(&card->lock);
-
-	return 0;
-}
-
-static int is_pci_slot_eq(struct pci_dev* adev, struct pci_dev* bdev)
-{
-	if ((adev->subsystem_vendor == bdev->subsystem_vendor) &&
-		(adev->subsystem_device == bdev->subsystem_device) &&
-		(adev->bus->number == bdev->bus->number) &&
-		(PCI_SLOT(adev->devfn) == PCI_SLOT(bdev->devfn)))
-		return 1;
-	return 0;
-}
-
-static struct bt878 __devinit *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci_dev* bttv_pci_dev)
-{
-	unsigned int card_nr;
-
-	/* Hmm, n squared. Hope n is small */
-	for (card_nr = 0; card_nr < bt878_num; card_nr++)
-		if (is_pci_slot_eq(bt878[card_nr].dev, bttv_pci_dev))
-			return &bt878[card_nr];
-	return NULL;
-}
-
-static int thomson_dtt7579_demod_init(struct dvb_frontend* fe)
-{
-	static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 };
-	static u8 mt352_reset [] = { 0x50, 0x80 };
-	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
-	static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 };
-	static u8 mt352_gpp_ctl_cfg [] = { 0x8C, 0x33 };
-	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
-
-	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
-	udelay(2000);
-	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
-	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-
-	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
-	mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg));
-	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
-
-	return 0;
-}
-
-static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend *fe, u8* pllbuf, int buf_len)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 div;
-	unsigned char bs = 0;
-	unsigned char cp = 0;
-
-	if (buf_len < 5)
-		return -EINVAL;
-
-	div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
-
-	if (c->frequency < 542000000)
-		cp = 0xb4;
-	else if (c->frequency < 771000000)
-		cp = 0xbc;
-	else
-		cp = 0xf4;
-
-	if (c->frequency == 0)
-		bs = 0x03;
-	else if (c->frequency < 443250000)
-		bs = 0x02;
-	else
-		bs = 0x08;
-
-	pllbuf[0] = 0x60;
-	pllbuf[1] = div >> 8;
-	pllbuf[2] = div & 0xff;
-	pllbuf[3] = cp;
-	pllbuf[4] = bs;
-
-	return 5;
-}
-
-static struct mt352_config thomson_dtt7579_config = {
-	.demod_address = 0x0f,
-	.demod_init = thomson_dtt7579_demod_init,
-};
-
-static struct zl10353_config thomson_dtt7579_zl10353_config = {
-	.demod_address = 0x0f,
-};
-
-static int cx24108_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 freq = c->frequency;
-	int i, a, n, pump;
-	u32 band, pll;
-	u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000,
-		1576000,1718000,1856000,2036000,2150000};
-	u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000,
-		0x00102000,0x00104000,0x00108000,0x00110000,
-		0x00120000,0x00140000};
-
-	#define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */
-	dprintk("cx24108 debug: entering SetTunerFreq, freq=%d\n", freq);
-
-	/* This is really the bit driving the tuner chip cx24108 */
-
-	if (freq<950000)
-		freq = 950000; /* kHz */
-	else if (freq>2150000)
-		freq = 2150000; /* satellite IF is 950..2150MHz */
-
-	/* decide which VCO to use for the input frequency */
-	for(i = 1; (i < ARRAY_SIZE(osci) - 1) && (osci[i] < freq); i++);
-	dprintk("cx24108 debug: select vco #%d (f=%d)\n", i, freq);
-	band=bandsel[i];
-	/* the gain values must be set by SetSymbolrate */
-	/* compute the pll divider needed, from Conexant data sheet,
-	   resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4,
-	   depending on the divider bit. It is set to /4 on the 2 lowest
-	   bands  */
-	n=((i<=2?2:1)*freq*10L)/(XTAL/100);
-	a=n%32; n/=32; if(a==0) n--;
-	pump=(freq<(osci[i-1]+osci[i])/2);
-	pll=0xf8000000|
-	    ((pump?1:2)<<(14+11))|
-	    ((n&0x1ff)<<(5+11))|
-	    ((a&0x1f)<<11);
-	/* everything is shifted left 11 bits to left-align the bits in the
-	   32bit word. Output to the tuner goes MSB-aligned, after all */
-	dprintk("cx24108 debug: pump=%d, n=%d, a=%d\n", pump, n, a);
-	cx24110_pll_write(fe,band);
-	/* set vga and vca to their widest-band settings, as a precaution.
-	   SetSymbolrate might not be called to set this up */
-	cx24110_pll_write(fe,0x500c0000);
-	cx24110_pll_write(fe,0x83f1f800);
-	cx24110_pll_write(fe,pll);
-	//writereg(client,0x56,0x7f);
-
-	return 0;
-}
-
-static int pinnsat_tuner_init(struct dvb_frontend* fe)
-{
-	struct dvb_bt8xx_card *card = fe->dvb->priv;
-
-	bttv_gpio_enable(card->bttv_nr, 1, 1);  /* output */
-	bttv_write_gpio(card->bttv_nr, 1, 1);   /* relay on */
-
-	return 0;
-}
-
-static int pinnsat_tuner_sleep(struct dvb_frontend* fe)
-{
-	struct dvb_bt8xx_card *card = fe->dvb->priv;
-
-	bttv_write_gpio(card->bttv_nr, 1, 0);   /* relay off */
-
-	return 0;
-}
-
-static struct cx24110_config pctvsat_config = {
-	.demod_address = 0x55,
-};
-
-static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
-	u8 cfg, cpump, band_select;
-	u8 data[4];
-	u32 div;
-	struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	div = (36000000 + c->frequency + 83333) / 166666;
-	cfg = 0x88;
-
-	if (c->frequency < 175000000)
-		cpump = 2;
-	else if (c->frequency < 390000000)
-		cpump = 1;
-	else if (c->frequency < 470000000)
-		cpump = 2;
-	else if (c->frequency < 750000000)
-		cpump = 2;
-	else
-		cpump = 3;
-
-	if (c->frequency < 175000000)
-		band_select = 0x0e;
-	else if (c->frequency < 470000000)
-		band_select = 0x05;
-	else
-		band_select = 0x03;
-
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = ((div >> 10) & 0x60) | cfg;
-	data[3] = (cpump << 6) | band_select;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	i2c_transfer(card->i2c_adapter, &msg, 1);
-	return (div * 166666 - 36000000);
-}
-
-static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
-{
-	struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv;
-
-	return request_firmware(fw, name, &bt->bt->dev->dev);
-}
-
-static struct sp887x_config microtune_mt7202dtf_config = {
-	.demod_address = 0x70,
-	.request_firmware = microtune_mt7202dtf_request_firmware,
-};
-
-static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
-{
-	static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d };
-	static u8 mt352_reset [] = { 0x50, 0x80 };
-	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
-	static u8 mt352_agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
-				       0x00, 0xFF, 0x00, 0x40, 0x40 };
-	static u8 mt352_av771_extra[] = { 0xB5, 0x7A };
-	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
-
-	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
-	udelay(2000);
-	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
-	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-
-	mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg));
-	udelay(2000);
-	mt352_write(fe, mt352_av771_extra,sizeof(mt352_av771_extra));
-	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
-
-	return 0;
-}
-
-static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 div;
-	unsigned char bs = 0;
-	unsigned char cp = 0;
-
-	if (buf_len < 5) return -EINVAL;
-
-	div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
-
-	if (c->frequency < 150000000)
-		cp = 0xB4;
-	else if (c->frequency < 173000000)
-		cp = 0xBC;
-	else if (c->frequency < 250000000)
-		cp = 0xB4;
-	else if (c->frequency < 400000000)
-		cp = 0xBC;
-	else if (c->frequency < 420000000)
-		cp = 0xF4;
-	else if (c->frequency < 470000000)
-		cp = 0xFC;
-	else if (c->frequency < 600000000)
-		cp = 0xBC;
-	else if (c->frequency < 730000000)
-		cp = 0xF4;
-	else
-		cp = 0xFC;
-
-	if (c->frequency < 150000000)
-		bs = 0x01;
-	else if (c->frequency < 173000000)
-		bs = 0x01;
-	else if (c->frequency < 250000000)
-		bs = 0x02;
-	else if (c->frequency < 400000000)
-		bs = 0x02;
-	else if (c->frequency < 420000000)
-		bs = 0x02;
-	else if (c->frequency < 470000000)
-		bs = 0x02;
-	else if (c->frequency < 600000000)
-		bs = 0x08;
-	else if (c->frequency < 730000000)
-		bs = 0x08;
-	else
-		bs = 0x08;
-
-	pllbuf[0] = 0x61;
-	pllbuf[1] = div >> 8;
-	pllbuf[2] = div & 0xff;
-	pllbuf[3] = cp;
-	pllbuf[4] = bs;
-
-	return 5;
-}
-
-static struct mt352_config advbt771_samsung_tdtc9251dh0_config = {
-	.demod_address = 0x0f,
-	.demod_init = advbt771_samsung_tdtc9251dh0_demod_init,
-};
-
-static struct dst_config dst_config = {
-	.demod_address = 0x55,
-};
-
-static int or51211_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
-{
-	struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv;
-
-	return request_firmware(fw, name, &bt->bt->dev->dev);
-}
-
-static void or51211_setmode(struct dvb_frontend * fe, int mode)
-{
-	struct dvb_bt8xx_card *bt = fe->dvb->priv;
-	bttv_write_gpio(bt->bttv_nr, 0x0002, mode);   /* Reset */
-	msleep(20);
-}
-
-static void or51211_reset(struct dvb_frontend * fe)
-{
-	struct dvb_bt8xx_card *bt = fe->dvb->priv;
-
-	/* RESET DEVICE
-	 * reset is controlled by GPIO-0
-	 * when set to 0 causes reset and when to 1 for normal op
-	 * must remain reset for 128 clock cycles on a 50Mhz clock
-	 * also PRM1 PRM2 & PRM4 are controlled by GPIO-1,GPIO-2 & GPIO-4
-	 * We assume that the reset has be held low long enough or we
-	 * have been reset by a power on.  When the driver is unloaded
-	 * reset set to 0 so if reloaded we have been reset.
-	 */
-	/* reset & PRM1,2&4 are outputs */
-	int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F);
-	if (ret != 0)
-		printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR (%i)\n", ret);
-	bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000);   /* Reset */
-	msleep(20);
-	/* Now set for normal operation */
-	bttv_write_gpio(bt->bttv_nr, 0x0001F, 0x0001);
-	/* wait for operation to begin */
-	msleep(500);
-}
-
-static void or51211_sleep(struct dvb_frontend * fe)
-{
-	struct dvb_bt8xx_card *bt = fe->dvb->priv;
-	bttv_write_gpio(bt->bttv_nr, 0x0001, 0x0000);
-}
-
-static struct or51211_config or51211_config = {
-	.demod_address = 0x15,
-	.request_firmware = or51211_request_firmware,
-	.setmode = or51211_setmode,
-	.reset = or51211_reset,
-	.sleep = or51211_sleep,
-};
-
-static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
-	u8 buf[4];
-	u32 div;
-	struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) };
-
-	div = (c->frequency + 36166667) / 166667;
-
-	buf[0] = (div >> 8) & 0x7F;
-	buf[1] = div & 0xFF;
-	buf[2] = 0x85;
-	if ((c->frequency >= 47000000) && (c->frequency < 153000000))
-		buf[3] = 0x01;
-	else if ((c->frequency >= 153000000) && (c->frequency < 430000000))
-		buf[3] = 0x02;
-	else if ((c->frequency >= 430000000) && (c->frequency < 824000000))
-		buf[3] = 0x0C;
-	else if ((c->frequency >= 824000000) && (c->frequency < 863000000))
-		buf[3] = 0x8C;
-	else
-		return -EINVAL;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	i2c_transfer(card->i2c_adapter, &msg, 1);
-	return 0;
-}
-
-static struct nxt6000_config vp3021_alps_tded4_config = {
-	.demod_address = 0x0a,
-	.clock_inversion = 1,
-};
-
-static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
-{
-	static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d };
-	static u8 mt352_reset [] = { 0x50, 0x80 };
-	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
-	static u8 mt352_agc_cfg [] = { 0x67, 0x20, 0xa0 };
-	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
-
-	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
-	udelay(2000);
-	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
-	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-	mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg));
-	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
-
-	return 0;
-}
-
-static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend *fe,  u8 *pllbuf, int buf_len)
-{
-	u32 div;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-
-	if (buf_len < 5)
-		return -EINVAL;
-
-	div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
-
-	pllbuf[0] = 0x61;
-	pllbuf[1] = (div >> 8) & 0x7F;
-	pllbuf[2] = div & 0xFF;
-	pllbuf[3] = 0x85;
-
-	dprintk("frequency %u, div %u\n", c->frequency, div);
-
-	if (c->frequency < 470000000)
-		pllbuf[4] = 0x02;
-	else if (c->frequency > 823000000)
-		pllbuf[4] = 0x88;
-	else
-		pllbuf[4] = 0x08;
-
-	if (c->bandwidth_hz == 8000000)
-		pllbuf[4] |= 0x04;
-
-	return 5;
-}
-
-static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
-{
-	/*
-	 * Reset the frontend, must be called before trying
-	 * to initialise the MT352 or mt352_attach
-	 * will fail. Same goes for the nxt6000 frontend.
-	 *
-	 */
-
-	int ret = bttv_gpio_enable(bt->bttv_nr, 0x08, 0x08);
-	if (ret != 0)
-		printk(KERN_WARNING "digitv_alps_tded4: Init Error - Can't Reset DVR (%i)\n", ret);
-
-	/* Pulse the reset line */
-	bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */
-	bttv_write_gpio(bt->bttv_nr, 0x08, 0x00); /* Low  */
-	msleep(100);
-
-	bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */
-}
-
-static struct mt352_config digitv_alps_tded4_config = {
-	.demod_address = 0x0a,
-	.demod_init = digitv_alps_tded4_demod_init,
-};
-
-static struct lgdt330x_config tdvs_tua6034_config = {
-	.demod_address    = 0x0e,
-	.demod_chip       = LGDT3303,
-	.serial_mpeg      = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
-};
-
-static void lgdt330x_reset(struct dvb_bt8xx_card *bt)
-{
-	/* Set pin 27 of the lgdt3303 chip high to reset the frontend */
-
-	/* Pulse the reset line */
-	bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
-	bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000000); /* Low  */
-	msleep(100);
-
-	bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
-	msleep(100);
-}
-
-static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
-{
-	struct dst_state* state = NULL;
-
-	switch(type) {
-	case BTTV_BOARD_DVICO_DVBT_LITE:
-		card->fe = dvb_attach(mt352_attach, &thomson_dtt7579_config, card->i2c_adapter);
-
-		if (card->fe == NULL)
-			card->fe = dvb_attach(zl10353_attach, &thomson_dtt7579_zl10353_config,
-						  card->i2c_adapter);
-
-		if (card->fe != NULL) {
-			card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs;
-			card->fe->ops.info.frequency_min = 174000000;
-			card->fe->ops.info.frequency_max = 862000000;
-		}
-		break;
-
-	case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
-		lgdt330x_reset(card);
-		card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
-		if (card->fe != NULL) {
-			dvb_attach(simple_tuner_attach, card->fe,
-				   card->i2c_adapter, 0x61,
-				   TUNER_LG_TDVS_H06XF);
-			dprintk ("dvb_bt8xx: lgdt330x detected\n");
-		}
-		break;
-
-	case BTTV_BOARD_NEBULA_DIGITV:
-		/*
-		 * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK);
-		 * this would be a cleaner solution than trying each frontend in turn.
-		 */
-
-		/* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */
-		digitv_alps_tded4_reset(card);
-		card->fe = dvb_attach(nxt6000_attach, &vp3021_alps_tded4_config, card->i2c_adapter);
-		if (card->fe != NULL) {
-			card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params;
-			dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
-			break;
-		}
-
-		/* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */
-		digitv_alps_tded4_reset(card);
-		card->fe = dvb_attach(mt352_attach, &digitv_alps_tded4_config, card->i2c_adapter);
-
-		if (card->fe != NULL) {
-			card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs;
-			dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n");
-		}
-		break;
-
-	case BTTV_BOARD_AVDVBT_761:
-		card->fe = dvb_attach(sp887x_attach, &microtune_mt7202dtf_config, card->i2c_adapter);
-		if (card->fe) {
-			card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params;
-		}
-		break;
-
-	case BTTV_BOARD_AVDVBT_771:
-		card->fe = dvb_attach(mt352_attach, &advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
-		if (card->fe != NULL) {
-			card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs;
-			card->fe->ops.info.frequency_min = 174000000;
-			card->fe->ops.info.frequency_max = 862000000;
-		}
-		break;
-
-	case BTTV_BOARD_TWINHAN_DST:
-		/*	DST is not a frontend driver !!!		*/
-		state = kmalloc(sizeof (struct dst_state), GFP_KERNEL);
-		if (!state) {
-			pr_err("No memory\n");
-			break;
-		}
-		/*	Setup the Card					*/
-		state->config = &dst_config;
-		state->i2c = card->i2c_adapter;
-		state->bt = card->bt;
-		state->dst_ca = NULL;
-		/*	DST is not a frontend, attaching the ASIC	*/
-		if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) {
-			pr_err("%s: Could not find a Twinhan DST\n", __func__);
-			break;
-		}
-		/*	Attach other DST peripherals if any		*/
-		/*	Conditional Access device			*/
-		card->fe = &state->frontend;
-		if (state->dst_hw_cap & DST_TYPE_HAS_CA)
-			dvb_attach(dst_ca_attach, state, &card->dvb_adapter);
-		break;
-
-	case BTTV_BOARD_PINNACLESAT:
-		card->fe = dvb_attach(cx24110_attach, &pctvsat_config, card->i2c_adapter);
-		if (card->fe) {
-			card->fe->ops.tuner_ops.init = pinnsat_tuner_init;
-			card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep;
-			card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params;
-		}
-		break;
-
-	case BTTV_BOARD_PC_HDTV:
-		card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter);
-		if (card->fe != NULL)
-			dvb_attach(simple_tuner_attach, card->fe,
-				   card->i2c_adapter, 0x61,
-				   TUNER_PHILIPS_FCV1236D);
-		break;
-	}
-
-	if (card->fe == NULL)
-		pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
-		       card->bt->dev->vendor,
-		       card->bt->dev->device,
-		       card->bt->dev->subsystem_vendor,
-		       card->bt->dev->subsystem_device);
-	else
-		if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
-			pr_err("Frontend registration failed!\n");
-			dvb_frontend_detach(card->fe);
-			card->fe = NULL;
-		}
-}
-
-static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
-{
-	int result;
-
-	result = dvb_register_adapter(&card->dvb_adapter, card->card_name,
-				      THIS_MODULE, &card->bt->dev->dev,
-				      adapter_nr);
-	if (result < 0) {
-		pr_err("dvb_register_adapter failed (errno = %d)\n", result);
-		return result;
-	}
-	card->dvb_adapter.priv = card;
-
-	card->bt->adapter = card->i2c_adapter;
-
-	memset(&card->demux, 0, sizeof(struct dvb_demux));
-
-	card->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING;
-
-	card->demux.priv = card;
-	card->demux.filternum = 256;
-	card->demux.feednum = 256;
-	card->demux.start_feed = dvb_bt8xx_start_feed;
-	card->demux.stop_feed = dvb_bt8xx_stop_feed;
-	card->demux.write_to_decoder = NULL;
-
-	result = dvb_dmx_init(&card->demux);
-	if (result < 0) {
-		pr_err("dvb_dmx_init failed (errno = %d)\n", result);
-		goto err_unregister_adaptor;
-	}
-
-	card->dmxdev.filternum = 256;
-	card->dmxdev.demux = &card->demux.dmx;
-	card->dmxdev.capabilities = 0;
-
-	result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter);
-	if (result < 0) {
-		pr_err("dvb_dmxdev_init failed (errno = %d)\n", result);
-		goto err_dmx_release;
-	}
-
-	card->fe_hw.source = DMX_FRONTEND_0;
-
-	result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw);
-	if (result < 0) {
-		pr_err("dvb_dmx_init failed (errno = %d)\n", result);
-		goto err_dmxdev_release;
-	}
-
-	card->fe_mem.source = DMX_MEMORY_FE;
-
-	result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem);
-	if (result < 0) {
-		pr_err("dvb_dmx_init failed (errno = %d)\n", result);
-		goto err_remove_hw_frontend;
-	}
-
-	result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw);
-	if (result < 0) {
-		pr_err("dvb_dmx_init failed (errno = %d)\n", result);
-		goto err_remove_mem_frontend;
-	}
-
-	result = dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx);
-	if (result < 0) {
-		pr_err("dvb_net_init failed (errno = %d)\n", result);
-		goto err_disconnect_frontend;
-	}
-
-	tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card);
-
-	frontend_init(card, type);
-
-	return 0;
-
-err_disconnect_frontend:
-	card->demux.dmx.disconnect_frontend(&card->demux.dmx);
-err_remove_mem_frontend:
-	card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
-err_remove_hw_frontend:
-	card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
-err_dmxdev_release:
-	dvb_dmxdev_release(&card->dmxdev);
-err_dmx_release:
-	dvb_dmx_release(&card->demux);
-err_unregister_adaptor:
-	dvb_unregister_adapter(&card->dvb_adapter);
-	return result;
-}
-
-static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
-{
-	struct dvb_bt8xx_card *card;
-	struct pci_dev* bttv_pci_dev;
-	int ret;
-
-	if (!(card = kzalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL)))
-		return -ENOMEM;
-
-	mutex_init(&card->lock);
-	card->bttv_nr = sub->core->nr;
-	strlcpy(card->card_name, sub->core->v4l2_dev.name, sizeof(card->card_name));
-	card->i2c_adapter = &sub->core->i2c_adap;
-
-	switch(sub->core->type) {
-	case BTTV_BOARD_PINNACLESAT:
-		card->gpio_mode = 0x0400c060;
-		/* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR,
-			      BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */
-		card->op_sync_orin = BT878_RISC_SYNC_MASK;
-		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
-		break;
-
-	case BTTV_BOARD_DVICO_DVBT_LITE:
-		card->gpio_mode = 0x0400C060;
-		card->op_sync_orin = BT878_RISC_SYNC_MASK;
-		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
-		/* 26, 15, 14, 6, 5
-		 * A_PWRDN  DA_DPM DA_SBR DA_IOM_DA
-		 * DA_APP(parallel) */
-		break;
-
-	case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
-		card->gpio_mode = 0x0400c060;
-		card->op_sync_orin = BT878_RISC_SYNC_MASK;
-		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
-		break;
-
-	case BTTV_BOARD_NEBULA_DIGITV:
-	case BTTV_BOARD_AVDVBT_761:
-		card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
-		card->op_sync_orin = BT878_RISC_SYNC_MASK;
-		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
-		/* A_PWRDN DA_SBR DA_APP (high speed serial) */
-		break;
-
-	case BTTV_BOARD_AVDVBT_771: //case 0x07711461:
-		card->gpio_mode = 0x0400402B;
-		card->op_sync_orin = BT878_RISC_SYNC_MASK;
-		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
-		/* A_PWRDN DA_SBR  DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/
-		break;
-
-	case BTTV_BOARD_TWINHAN_DST:
-		card->gpio_mode = 0x2204f2c;
-		card->op_sync_orin = BT878_RISC_SYNC_MASK;
-		card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR |
-				       BT878_APPERR | BT878_AFBUS;
-		/* 25,21,14,11,10,9,8,3,2 then
-		 * 0x33 = 5,4,1,0
-		 * A_SEL=SML, DA_MLB, DA_SBR,
-		 * DA_SDR=f, fifo trigger = 32 DWORDS
-		 * IOM = 0 == audio A/D
-		 * DPM = 0 == digital audio mode
-		 * == async data parallel port
-		 * then 0x33 (13 is set by start_capture)
-		 * DA_APP = async data parallel port,
-		 * ACAP_EN = 1,
-		 * RISC+FIFO ENABLE */
-		break;
-
-	case BTTV_BOARD_PC_HDTV:
-		card->gpio_mode = 0x0100EC7B;
-		card->op_sync_orin = BT878_RISC_SYNC_MASK;
-		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
-		break;
-
-	default:
-		pr_err("Unknown bttv card type: %d\n", sub->core->type);
-		kfree(card);
-		return -ENODEV;
-	}
-
-	dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name);
-
-	if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) {
-		pr_err("no pci device for card %d\n", card->bttv_nr);
-		kfree(card);
-		return -ENODEV;
-	}
-
-	if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) {
-		pr_err("unable to determine DMA core of card %d,\n", card->bttv_nr);
-		pr_err("if you have the ALSA bt87x audio driver installed, try removing it.\n");
-
-		kfree(card);
-		return -ENODEV;
-	}
-
-	mutex_init(&card->bt->gpio_lock);
-	card->bt->bttv_nr = sub->core->nr;
-
-	if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) {
-		kfree(card);
-		return ret;
-	}
-
-	dev_set_drvdata(&sub->dev, card);
-	return 0;
-}
-
-static void dvb_bt8xx_remove(struct bttv_sub_device *sub)
-{
-	struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev);
-
-	dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr);
-
-	bt878_stop(card->bt);
-	tasklet_kill(&card->bt->tasklet);
-	dvb_net_release(&card->dvbnet);
-	card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
-	card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
-	dvb_dmxdev_release(&card->dmxdev);
-	dvb_dmx_release(&card->demux);
-	if (card->fe) {
-		dvb_unregister_frontend(card->fe);
-		dvb_frontend_detach(card->fe);
-	}
-	dvb_unregister_adapter(&card->dvb_adapter);
-
-	kfree(card);
-}
-
-static struct bttv_sub_driver driver = {
-	.drv = {
-		.name		= "dvb-bt8xx",
-	},
-	.probe		= dvb_bt8xx_probe,
-	.remove		= dvb_bt8xx_remove,
-	/* FIXME:
-	 * .shutdown	= dvb_bt8xx_shutdown,
-	 * .suspend	= dvb_bt8xx_suspend,
-	 * .resume	= dvb_bt8xx_resume,
-	 */
-};
-
-static int __init dvb_bt8xx_init(void)
-{
-	return bttv_sub_register(&driver, "dvb");
-}
-
-static void __exit dvb_bt8xx_exit(void)
-{
-	bttv_sub_unregister(&driver);
-}
-
-module_init(dvb_bt8xx_init);
-module_exit(dvb_bt8xx_exit);
-
-MODULE_DESCRIPTION("Bt8xx based DVB adapter driver");
-MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
deleted file mode 100644
index 4499ed2..0000000
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Bt8xx based DVB adapter driver
- *
- * Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org>
- * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de>
- * Copyright (C) 1999-2001 Ralph  Metzler & Marcus Metzler for convergence integrated media GmbH
- * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef DVB_BT8XX_H
-#define DVB_BT8XX_H
-
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include "dvbdev.h"
-#include "dvb_net.h"
-#include "bttv.h"
-#include "mt352.h"
-#include "sp887x.h"
-#include "dst_common.h"
-#include "nxt6000.h"
-#include "cx24110.h"
-#include "or51211.h"
-#include "lgdt330x.h"
-#include "zl10353.h"
-#include "tuner-simple.h"
-
-struct dvb_bt8xx_card {
-	struct mutex lock;
-	int nfeeds;
-	char card_name[32];
-	struct dvb_adapter dvb_adapter;
-	struct bt878 *bt;
-	unsigned int bttv_nr;
-	struct dvb_demux demux;
-	struct dmxdev dmxdev;
-	struct dmx_frontend fe_hw;
-	struct dmx_frontend fe_mem;
-	u32 gpio_mode;
-	u32 op_sync_orin;
-	u32 irq_err_ignore;
-	struct i2c_adapter *i2c_adapter;
-	struct dvb_net dvbnet;
-
-	struct dvb_frontend* fe;
-};
-
-#endif /* DVB_BT8XX_H */
diff --git a/drivers/media/dvb/ddbridge/Kconfig b/drivers/media/dvb/ddbridge/Kconfig
deleted file mode 100644
index d099e1a..0000000
--- a/drivers/media/dvb/ddbridge/Kconfig
+++ /dev/null
@@ -1,18 +0,0 @@
-config DVB_DDBRIDGE
-	tristate "Digital Devices bridge support"
-	depends on DVB_CORE && PCI && I2C
-	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
-	select DVB_STV6110x if !DVB_FE_CUSTOMISE
-	select DVB_STV090x if !DVB_FE_CUSTOMISE
-	select DVB_DRXK if !DVB_FE_CUSTOMISE
-	select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE
-	---help---
-	  Support for cards with the Digital Devices PCI express bridge:
-	  - Octopus PCIe Bridge
-	  - Octopus mini PCIe Bridge
-	  - Octopus LE
-	  - DuoFlex S2 Octopus
-	  - DuoFlex CT Octopus
-	  - cineS2(v6)
-
-	  Say Y if you own such a card and want to use it.
diff --git a/drivers/media/dvb/ddbridge/Makefile b/drivers/media/dvb/ddbridge/Makefile
deleted file mode 100644
index 38019ba..0000000
--- a/drivers/media/dvb/ddbridge/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Makefile for the ddbridge device driver
-#
-
-ddbridge-objs := ddbridge-core.o
-
-obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/
-ccflags-y += -Idrivers/media/dvb/frontends/
-ccflags-y += -Idrivers/media/common/tuners/
-
-# For the staging CI driver cxd2099
-ccflags-y += -Idrivers/staging/media/cxd2099/
diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/dvb/ddbridge/ddbridge-core.c
deleted file mode 100644
index ebf3f05..0000000
--- a/drivers/media/dvb/ddbridge/ddbridge-core.c
+++ /dev/null
@@ -1,1723 +0,0 @@
-/*
- * ddbridge.c: Digital Devices PCIe bridge driver
- *
- * Copyright (C) 2010-2011 Digital Devices GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/io.h>
-#include <linux/pci.h>
-#include <linux/pci_ids.h>
-#include <linux/timer.h>
-#include <linux/i2c.h>
-#include <linux/swab.h>
-#include <linux/vmalloc.h>
-#include "ddbridge.h"
-
-#include "ddbridge-regs.h"
-
-#include "tda18271c2dd.h"
-#include "stv6110x.h"
-#include "stv090x.h"
-#include "lnbh24.h"
-#include "drxk.h"
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-/* MSI had problems with lost interrupts, fixed but needs testing */
-#undef CONFIG_PCI_MSI
-
-/******************************************************************************/
-
-static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
-{
-	struct i2c_msg msgs[1] = {{.addr = adr,  .flags = I2C_M_RD,
-				   .buf  = val,  .len   = 1 } };
-	return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
-}
-
-static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val)
-{
-	struct i2c_msg msgs[2] = {{.addr = adr,  .flags = 0,
-				   .buf  = &reg, .len   = 1 },
-				  {.addr = adr,  .flags = I2C_M_RD,
-				   .buf  = val,  .len   = 1 } };
-	return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
-}
-
-static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
-			  u16 reg, u8 *val)
-{
-	u8 msg[2] = {reg>>8, reg&0xff};
-	struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
-				   .buf  = msg, .len   = 2},
-				  {.addr = adr, .flags = I2C_M_RD,
-				   .buf  = val, .len   = 1} };
-	return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
-}
-
-static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
-{
-	struct ddb *dev = i2c->dev;
-	int stat;
-	u32 val;
-
-	i2c->done = 0;
-	ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND);
-	stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ);
-	if (stat <= 0) {
-		printk(KERN_ERR "I2C timeout\n");
-		{ /* MSI debugging*/
-			u32 istat = ddbreadl(INTERRUPT_STATUS);
-			printk(KERN_ERR "IRS %08x\n", istat);
-			ddbwritel(istat, INTERRUPT_ACK);
-		}
-		return -EIO;
-	}
-	val = ddbreadl(i2c->regs+I2C_COMMAND);
-	if (val & 0x70000)
-		return -EIO;
-	return 0;
-}
-
-static int ddb_i2c_master_xfer(struct i2c_adapter *adapter,
-			       struct i2c_msg msg[], int num)
-{
-	struct ddb_i2c *i2c = (struct ddb_i2c *)i2c_get_adapdata(adapter);
-	struct ddb *dev = i2c->dev;
-	u8 addr = 0;
-
-	if (num)
-		addr = msg[0].addr;
-
-	if (num == 2 && msg[1].flags & I2C_M_RD &&
-	    !(msg[0].flags & I2C_M_RD)) {
-		memcpy_toio(dev->regs + I2C_TASKMEM_BASE + i2c->wbuf,
-			    msg[0].buf, msg[0].len);
-		ddbwritel(msg[0].len|(msg[1].len << 16),
-			  i2c->regs+I2C_TASKLENGTH);
-		if (!ddb_i2c_cmd(i2c, addr, 1)) {
-			memcpy_fromio(msg[1].buf,
-				      dev->regs + I2C_TASKMEM_BASE + i2c->rbuf,
-				      msg[1].len);
-			return num;
-		}
-	}
-
-	if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
-		ddbcpyto(I2C_TASKMEM_BASE + i2c->wbuf, msg[0].buf, msg[0].len);
-		ddbwritel(msg[0].len, i2c->regs + I2C_TASKLENGTH);
-		if (!ddb_i2c_cmd(i2c, addr, 2))
-			return num;
-	}
-	if (num == 1 && (msg[0].flags & I2C_M_RD)) {
-		ddbwritel(msg[0].len << 16, i2c->regs + I2C_TASKLENGTH);
-		if (!ddb_i2c_cmd(i2c, addr, 3)) {
-			ddbcpyfrom(msg[0].buf,
-				   I2C_TASKMEM_BASE + i2c->rbuf, msg[0].len);
-			return num;
-		}
-	}
-	return -EIO;
-}
-
-
-static u32 ddb_i2c_functionality(struct i2c_adapter *adap)
-{
-	return I2C_FUNC_SMBUS_EMUL;
-}
-
-struct i2c_algorithm ddb_i2c_algo = {
-	.master_xfer   = ddb_i2c_master_xfer,
-	.functionality = ddb_i2c_functionality,
-};
-
-static void ddb_i2c_release(struct ddb *dev)
-{
-	int i;
-	struct ddb_i2c *i2c;
-	struct i2c_adapter *adap;
-
-	for (i = 0; i < dev->info->port_num; i++) {
-		i2c = &dev->i2c[i];
-		adap = &i2c->adap;
-		i2c_del_adapter(adap);
-	}
-}
-
-static int ddb_i2c_init(struct ddb *dev)
-{
-	int i, j, stat = 0;
-	struct ddb_i2c *i2c;
-	struct i2c_adapter *adap;
-
-	for (i = 0; i < dev->info->port_num; i++) {
-		i2c = &dev->i2c[i];
-		i2c->dev = dev;
-		i2c->nr = i;
-		i2c->wbuf = i * (I2C_TASKMEM_SIZE / 4);
-		i2c->rbuf = i2c->wbuf + (I2C_TASKMEM_SIZE / 8);
-		i2c->regs = 0x80 + i * 0x20;
-		ddbwritel(I2C_SPEED_100, i2c->regs + I2C_TIMING);
-		ddbwritel((i2c->rbuf << 16) | i2c->wbuf,
-			  i2c->regs + I2C_TASKADDRESS);
-		init_waitqueue_head(&i2c->wq);
-
-		adap = &i2c->adap;
-		i2c_set_adapdata(adap, i2c);
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
-		adap->class = I2C_ADAP_CLASS_TV_DIGITAL|I2C_CLASS_TV_ANALOG;
-#else
-#ifdef I2C_CLASS_TV_ANALOG
-		adap->class = I2C_CLASS_TV_ANALOG;
-#endif
-#endif
-		strcpy(adap->name, "ddbridge");
-		adap->algo = &ddb_i2c_algo;
-		adap->algo_data = (void *)i2c;
-		adap->dev.parent = &dev->pdev->dev;
-		stat = i2c_add_adapter(adap);
-		if (stat)
-			break;
-	}
-	if (stat)
-		for (j = 0; j < i; j++) {
-			i2c = &dev->i2c[j];
-			adap = &i2c->adap;
-			i2c_del_adapter(adap);
-		}
-	return stat;
-}
-
-
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
-
-#if 0
-static void set_table(struct ddb *dev, u32 off,
-		      dma_addr_t *pbuf, u32 num)
-{
-	u32 i, base;
-	u64 mem;
-
-	base = DMA_BASE_ADDRESS_TABLE + off;
-	for (i = 0; i < num; i++) {
-		mem = pbuf[i];
-		ddbwritel(mem & 0xffffffff, base + i * 8);
-		ddbwritel(mem >> 32, base + i * 8 + 4);
-	}
-}
-#endif
-
-static void ddb_address_table(struct ddb *dev)
-{
-	u32 i, j, base;
-	u64 mem;
-	dma_addr_t *pbuf;
-
-	for (i = 0; i < dev->info->port_num * 2; i++) {
-		base = DMA_BASE_ADDRESS_TABLE + i * 0x100;
-		pbuf = dev->input[i].pbuf;
-		for (j = 0; j < dev->input[i].dma_buf_num; j++) {
-			mem = pbuf[j];
-			ddbwritel(mem & 0xffffffff, base + j * 8);
-			ddbwritel(mem >> 32, base + j * 8 + 4);
-		}
-	}
-	for (i = 0; i < dev->info->port_num; i++) {
-		base = DMA_BASE_ADDRESS_TABLE + 0x800 + i * 0x100;
-		pbuf = dev->output[i].pbuf;
-		for (j = 0; j < dev->output[i].dma_buf_num; j++) {
-			mem = pbuf[j];
-			ddbwritel(mem & 0xffffffff, base + j * 8);
-			ddbwritel(mem >> 32, base + j * 8 + 4);
-		}
-	}
-}
-
-static void io_free(struct pci_dev *pdev, u8 **vbuf,
-		    dma_addr_t *pbuf, u32 size, int num)
-{
-	int i;
-
-	for (i = 0; i < num; i++) {
-		if (vbuf[i]) {
-			pci_free_consistent(pdev, size, vbuf[i], pbuf[i]);
-			vbuf[i] = 0;
-		}
-	}
-}
-
-static int io_alloc(struct pci_dev *pdev, u8 **vbuf,
-		    dma_addr_t *pbuf, u32 size, int num)
-{
-	int i;
-
-	for (i = 0; i < num; i++) {
-		vbuf[i] = pci_alloc_consistent(pdev, size, &pbuf[i]);
-		if (!vbuf[i])
-			return -ENOMEM;
-	}
-	return 0;
-}
-
-static int ddb_buffers_alloc(struct ddb *dev)
-{
-	int i;
-	struct ddb_port *port;
-
-	for (i = 0; i < dev->info->port_num; i++) {
-		port = &dev->port[i];
-		switch (port->class) {
-		case DDB_PORT_TUNER:
-			if (io_alloc(dev->pdev, port->input[0]->vbuf,
-				     port->input[0]->pbuf,
-				     port->input[0]->dma_buf_size,
-				     port->input[0]->dma_buf_num) < 0)
-				return -1;
-			if (io_alloc(dev->pdev, port->input[1]->vbuf,
-				     port->input[1]->pbuf,
-				     port->input[1]->dma_buf_size,
-				     port->input[1]->dma_buf_num) < 0)
-				return -1;
-			break;
-		case DDB_PORT_CI:
-			if (io_alloc(dev->pdev, port->input[0]->vbuf,
-				     port->input[0]->pbuf,
-				     port->input[0]->dma_buf_size,
-				     port->input[0]->dma_buf_num) < 0)
-				return -1;
-			if (io_alloc(dev->pdev, port->output->vbuf,
-				     port->output->pbuf,
-				     port->output->dma_buf_size,
-				     port->output->dma_buf_num) < 0)
-				return -1;
-			break;
-		default:
-			break;
-		}
-	}
-	ddb_address_table(dev);
-	return 0;
-}
-
-static void ddb_buffers_free(struct ddb *dev)
-{
-	int i;
-	struct ddb_port *port;
-
-	for (i = 0; i < dev->info->port_num; i++) {
-		port = &dev->port[i];
-		io_free(dev->pdev, port->input[0]->vbuf,
-			port->input[0]->pbuf,
-			port->input[0]->dma_buf_size,
-			port->input[0]->dma_buf_num);
-		io_free(dev->pdev, port->input[1]->vbuf,
-			port->input[1]->pbuf,
-			port->input[1]->dma_buf_size,
-			port->input[1]->dma_buf_num);
-		io_free(dev->pdev, port->output->vbuf,
-			port->output->pbuf,
-			port->output->dma_buf_size,
-			port->output->dma_buf_num);
-	}
-}
-
-static void ddb_input_start(struct ddb_input *input)
-{
-	struct ddb *dev = input->port->dev;
-
-	spin_lock_irq(&input->lock);
-	input->cbuf = 0;
-	input->coff = 0;
-
-	/* reset */
-	ddbwritel(0, TS_INPUT_CONTROL(input->nr));
-	ddbwritel(2, TS_INPUT_CONTROL(input->nr));
-	ddbwritel(0, TS_INPUT_CONTROL(input->nr));
-
-	ddbwritel((1 << 16) |
-		  (input->dma_buf_num << 11) |
-		  (input->dma_buf_size >> 7),
-		  DMA_BUFFER_SIZE(input->nr));
-	ddbwritel(0, DMA_BUFFER_ACK(input->nr));
-
-	ddbwritel(1, DMA_BASE_WRITE);
-	ddbwritel(3, DMA_BUFFER_CONTROL(input->nr));
-	ddbwritel(9, TS_INPUT_CONTROL(input->nr));
-	input->running = 1;
-	spin_unlock_irq(&input->lock);
-}
-
-static void ddb_input_stop(struct ddb_input *input)
-{
-	struct ddb *dev = input->port->dev;
-
-	spin_lock_irq(&input->lock);
-	ddbwritel(0, TS_INPUT_CONTROL(input->nr));
-	ddbwritel(0, DMA_BUFFER_CONTROL(input->nr));
-	input->running = 0;
-	spin_unlock_irq(&input->lock);
-}
-
-static void ddb_output_start(struct ddb_output *output)
-{
-	struct ddb *dev = output->port->dev;
-
-	spin_lock_irq(&output->lock);
-	output->cbuf = 0;
-	output->coff = 0;
-	ddbwritel(0, TS_OUTPUT_CONTROL(output->nr));
-	ddbwritel(2, TS_OUTPUT_CONTROL(output->nr));
-	ddbwritel(0, TS_OUTPUT_CONTROL(output->nr));
-	ddbwritel(0x3c, TS_OUTPUT_CONTROL(output->nr));
-	ddbwritel((1 << 16) |
-		  (output->dma_buf_num << 11) |
-		  (output->dma_buf_size >> 7),
-		  DMA_BUFFER_SIZE(output->nr + 8));
-	ddbwritel(0, DMA_BUFFER_ACK(output->nr + 8));
-
-	ddbwritel(1, DMA_BASE_READ);
-	ddbwritel(3, DMA_BUFFER_CONTROL(output->nr + 8));
-	/* ddbwritel(0xbd, TS_OUTPUT_CONTROL(output->nr)); */
-	ddbwritel(0x1d, TS_OUTPUT_CONTROL(output->nr));
-	output->running = 1;
-	spin_unlock_irq(&output->lock);
-}
-
-static void ddb_output_stop(struct ddb_output *output)
-{
-	struct ddb *dev = output->port->dev;
-
-	spin_lock_irq(&output->lock);
-	ddbwritel(0, TS_OUTPUT_CONTROL(output->nr));
-	ddbwritel(0, DMA_BUFFER_CONTROL(output->nr + 8));
-	output->running = 0;
-	spin_unlock_irq(&output->lock);
-}
-
-static u32 ddb_output_free(struct ddb_output *output)
-{
-	u32 idx, off, stat = output->stat;
-	s32 diff;
-
-	idx = (stat >> 11) & 0x1f;
-	off = (stat & 0x7ff) << 7;
-
-	if (output->cbuf != idx) {
-		if ((((output->cbuf + 1) % output->dma_buf_num) == idx) &&
-		    (output->dma_buf_size - output->coff <= 188))
-			return 0;
-		return 188;
-	}
-	diff = off - output->coff;
-	if (diff <= 0 || diff > 188)
-		return 188;
-	return 0;
-}
-
-static ssize_t ddb_output_write(struct ddb_output *output,
-				const u8 *buf, size_t count)
-{
-	struct ddb *dev = output->port->dev;
-	u32 idx, off, stat = output->stat;
-	u32 left = count, len;
-
-	idx = (stat >> 11) & 0x1f;
-	off = (stat & 0x7ff) << 7;
-
-	while (left) {
-		len = output->dma_buf_size - output->coff;
-		if ((((output->cbuf + 1) % output->dma_buf_num) == idx) &&
-		    (off == 0)) {
-			if (len <= 188)
-				break;
-			len -= 188;
-		}
-		if (output->cbuf == idx) {
-			if (off > output->coff) {
-#if 1
-				len = off - output->coff;
-				len -= (len % 188);
-				if (len <= 188)
-
-#endif
-					break;
-				len -= 188;
-			}
-		}
-		if (len > left)
-			len = left;
-		if (copy_from_user(output->vbuf[output->cbuf] + output->coff,
-				   buf, len))
-			return -EIO;
-		left -= len;
-		buf += len;
-		output->coff += len;
-		if (output->coff == output->dma_buf_size) {
-			output->coff = 0;
-			output->cbuf = ((output->cbuf + 1) % output->dma_buf_num);
-		}
-		ddbwritel((output->cbuf << 11) | (output->coff >> 7),
-			  DMA_BUFFER_ACK(output->nr + 8));
-	}
-	return count - left;
-}
-
-static u32 ddb_input_avail(struct ddb_input *input)
-{
-	struct ddb *dev = input->port->dev;
-	u32 idx, off, stat = input->stat;
-	u32 ctrl = ddbreadl(DMA_BUFFER_CONTROL(input->nr));
-
-	idx = (stat >> 11) & 0x1f;
-	off = (stat & 0x7ff) << 7;
-
-	if (ctrl & 4) {
-		printk(KERN_ERR "IA %d %d %08x\n", idx, off, ctrl);
-		ddbwritel(input->stat, DMA_BUFFER_ACK(input->nr));
-		return 0;
-	}
-	if (input->cbuf != idx)
-		return 188;
-	return 0;
-}
-
-static ssize_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count)
-{
-	struct ddb *dev = input->port->dev;
-	u32 left = count;
-	u32 idx, free, stat = input->stat;
-	int ret;
-
-	idx = (stat >> 11) & 0x1f;
-
-	while (left) {
-		if (input->cbuf == idx)
-			return count - left;
-		free = input->dma_buf_size - input->coff;
-		if (free > left)
-			free = left;
-		ret = copy_to_user(buf, input->vbuf[input->cbuf] +
-				   input->coff, free);
-		if (ret)
-			return -EFAULT;
-		input->coff += free;
-		if (input->coff == input->dma_buf_size) {
-			input->coff = 0;
-			input->cbuf = (input->cbuf+1) % input->dma_buf_num;
-		}
-		left -= free;
-		ddbwritel((input->cbuf << 11) | (input->coff >> 7),
-			  DMA_BUFFER_ACK(input->nr));
-	}
-	return count;
-}
-
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
-
-#if 0
-static struct ddb_input *fe2input(struct ddb *dev, struct dvb_frontend *fe)
-{
-	int i;
-
-	for (i = 0; i < dev->info->port_num * 2; i++) {
-		if (dev->input[i].fe == fe)
-			return &dev->input[i];
-	}
-	return NULL;
-}
-#endif
-
-static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct ddb_input *input = fe->sec_priv;
-	struct ddb_port *port = input->port;
-	int status;
-
-	if (enable) {
-		mutex_lock(&port->i2c_gate_lock);
-		status = input->gate_ctrl(fe, 1);
-	} else {
-		status = input->gate_ctrl(fe, 0);
-		mutex_unlock(&port->i2c_gate_lock);
-	}
-	return status;
-}
-
-static int demod_attach_drxk(struct ddb_input *input)
-{
-	struct i2c_adapter *i2c = &input->port->i2c->adap;
-	struct dvb_frontend *fe;
-	struct drxk_config config;
-
-	memset(&config, 0, sizeof(config));
-	config.microcode_name = "drxk_a3.mc";
-	config.qam_demod_parameter_count = 4;
-	config.adr = 0x29 + (input->nr & 1);
-
-	fe = input->fe = dvb_attach(drxk_attach, &config, i2c);
-	if (!input->fe) {
-		printk(KERN_ERR "No DRXK found!\n");
-		return -ENODEV;
-	}
-	fe->sec_priv = input;
-	input->gate_ctrl = fe->ops.i2c_gate_ctrl;
-	fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
-	return 0;
-}
-
-static int tuner_attach_tda18271(struct ddb_input *input)
-{
-	struct i2c_adapter *i2c = &input->port->i2c->adap;
-	struct dvb_frontend *fe;
-
-	if (input->fe->ops.i2c_gate_ctrl)
-		input->fe->ops.i2c_gate_ctrl(input->fe, 1);
-	fe = dvb_attach(tda18271c2dd_attach, input->fe, i2c, 0x60);
-	if (!fe) {
-		printk(KERN_ERR "No TDA18271 found!\n");
-		return -ENODEV;
-	}
-	if (input->fe->ops.i2c_gate_ctrl)
-		input->fe->ops.i2c_gate_ctrl(input->fe, 0);
-	return 0;
-}
-
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
-
-static struct stv090x_config stv0900 = {
-	.device         = STV0900,
-	.demod_mode     = STV090x_DUAL,
-	.clk_mode       = STV090x_CLK_EXT,
-
-	.xtal           = 27000000,
-	.address        = 0x69,
-
-	.ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
-	.ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
-
-	.repeater_level = STV090x_RPTLEVEL_16,
-
-	.adc1_range	= STV090x_ADC_1Vpp,
-	.adc2_range	= STV090x_ADC_1Vpp,
-
-	.diseqc_envelope_mode = true,
-};
-
-static struct stv090x_config stv0900_aa = {
-	.device         = STV0900,
-	.demod_mode     = STV090x_DUAL,
-	.clk_mode       = STV090x_CLK_EXT,
-
-	.xtal           = 27000000,
-	.address        = 0x68,
-
-	.ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
-	.ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
-
-	.repeater_level = STV090x_RPTLEVEL_16,
-
-	.adc1_range	= STV090x_ADC_1Vpp,
-	.adc2_range	= STV090x_ADC_1Vpp,
-
-	.diseqc_envelope_mode = true,
-};
-
-static struct stv6110x_config stv6110a = {
-	.addr    = 0x60,
-	.refclk	 = 27000000,
-	.clk_div = 1,
-};
-
-static struct stv6110x_config stv6110b = {
-	.addr    = 0x63,
-	.refclk	 = 27000000,
-	.clk_div = 1,
-};
-
-static int demod_attach_stv0900(struct ddb_input *input, int type)
-{
-	struct i2c_adapter *i2c = &input->port->i2c->adap;
-	struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900;
-
-	input->fe = dvb_attach(stv090x_attach, feconf, i2c,
-			       (input->nr & 1) ? STV090x_DEMODULATOR_1
-			       : STV090x_DEMODULATOR_0);
-	if (!input->fe) {
-		printk(KERN_ERR "No STV0900 found!\n");
-		return -ENODEV;
-	}
-	if (!dvb_attach(lnbh24_attach, input->fe, i2c, 0,
-			0, (input->nr & 1) ?
-			(0x09 - type) : (0x0b - type))) {
-		printk(KERN_ERR "No LNBH24 found!\n");
-		return -ENODEV;
-	}
-	return 0;
-}
-
-static int tuner_attach_stv6110(struct ddb_input *input, int type)
-{
-	struct i2c_adapter *i2c = &input->port->i2c->adap;
-	struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900;
-	struct stv6110x_config *tunerconf = (input->nr & 1) ?
-		&stv6110b : &stv6110a;
-	struct stv6110x_devctl *ctl;
-
-	ctl = dvb_attach(stv6110x_attach, input->fe, tunerconf, i2c);
-	if (!ctl) {
-		printk(KERN_ERR "No STV6110X found!\n");
-		return -ENODEV;
-	}
-	printk(KERN_INFO "attach tuner input %d adr %02x\n",
-			 input->nr, tunerconf->addr);
-
-	feconf->tuner_init          = ctl->tuner_init;
-	feconf->tuner_sleep         = ctl->tuner_sleep;
-	feconf->tuner_set_mode      = ctl->tuner_set_mode;
-	feconf->tuner_set_frequency = ctl->tuner_set_frequency;
-	feconf->tuner_get_frequency = ctl->tuner_get_frequency;
-	feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth;
-	feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth;
-	feconf->tuner_set_bbgain    = ctl->tuner_set_bbgain;
-	feconf->tuner_get_bbgain    = ctl->tuner_get_bbgain;
-	feconf->tuner_set_refclk    = ctl->tuner_set_refclk;
-	feconf->tuner_get_status    = ctl->tuner_get_status;
-
-	return 0;
-}
-
-static int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
-			    int (*start_feed)(struct dvb_demux_feed *),
-			    int (*stop_feed)(struct dvb_demux_feed *),
-			    void *priv)
-{
-	dvbdemux->priv = priv;
-
-	dvbdemux->filternum = 256;
-	dvbdemux->feednum = 256;
-	dvbdemux->start_feed = start_feed;
-	dvbdemux->stop_feed = stop_feed;
-	dvbdemux->write_to_decoder = NULL;
-	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
-				      DMX_SECTION_FILTERING |
-				      DMX_MEMORY_BASED_FILTERING);
-	return dvb_dmx_init(dvbdemux);
-}
-
-static int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
-			       struct dvb_demux *dvbdemux,
-			       struct dmx_frontend *hw_frontend,
-			       struct dmx_frontend *mem_frontend,
-			       struct dvb_adapter *dvb_adapter)
-{
-	int ret;
-
-	dmxdev->filternum = 256;
-	dmxdev->demux = &dvbdemux->dmx;
-	dmxdev->capabilities = 0;
-	ret = dvb_dmxdev_init(dmxdev, dvb_adapter);
-	if (ret < 0)
-		return ret;
-
-	hw_frontend->source = DMX_FRONTEND_0;
-	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend);
-	mem_frontend->source = DMX_MEMORY_FE;
-	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend);
-	return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend);
-}
-
-static int start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-	struct ddb_input *input = dvbdmx->priv;
-
-	if (!input->users)
-		ddb_input_start(input);
-
-	return ++input->users;
-}
-
-static int stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-	struct ddb_input *input = dvbdmx->priv;
-
-	if (--input->users)
-		return input->users;
-
-	ddb_input_stop(input);
-	return 0;
-}
-
-
-static void dvb_input_detach(struct ddb_input *input)
-{
-	struct dvb_adapter *adap = &input->adap;
-	struct dvb_demux *dvbdemux = &input->demux;
-
-	switch (input->attached) {
-	case 5:
-		if (input->fe2)
-			dvb_unregister_frontend(input->fe2);
-		if (input->fe) {
-			dvb_unregister_frontend(input->fe);
-			dvb_frontend_detach(input->fe);
-			input->fe = NULL;
-		}
-	case 4:
-		dvb_net_release(&input->dvbnet);
-
-	case 3:
-		dvbdemux->dmx.close(&dvbdemux->dmx);
-		dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
-					      &input->hw_frontend);
-		dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
-					      &input->mem_frontend);
-		dvb_dmxdev_release(&input->dmxdev);
-
-	case 2:
-		dvb_dmx_release(&input->demux);
-
-	case 1:
-		dvb_unregister_adapter(adap);
-	}
-	input->attached = 0;
-}
-
-static int dvb_input_attach(struct ddb_input *input)
-{
-	int ret;
-	struct ddb_port *port = input->port;
-	struct dvb_adapter *adap = &input->adap;
-	struct dvb_demux *dvbdemux = &input->demux;
-
-	ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE,
-				   &input->port->dev->pdev->dev,
-				   adapter_nr);
-	if (ret < 0) {
-		printk(KERN_ERR "ddbridge: Could not register adapter."
-		       "Check if you enabled enough adapters in dvb-core!\n");
-		return ret;
-	}
-	input->attached = 1;
-
-	ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux",
-				      start_feed,
-				      stop_feed, input);
-	if (ret < 0)
-		return ret;
-	input->attached = 2;
-
-	ret = my_dvb_dmxdev_ts_card_init(&input->dmxdev, &input->demux,
-					 &input->hw_frontend,
-					 &input->mem_frontend, adap);
-	if (ret < 0)
-		return ret;
-	input->attached = 3;
-
-	ret = dvb_net_init(adap, &input->dvbnet, input->dmxdev.demux);
-	if (ret < 0)
-		return ret;
-	input->attached = 4;
-
-	input->fe = 0;
-	switch (port->type) {
-	case DDB_TUNER_DVBS_ST:
-		if (demod_attach_stv0900(input, 0) < 0)
-			return -ENODEV;
-		if (tuner_attach_stv6110(input, 0) < 0)
-			return -ENODEV;
-		if (input->fe) {
-			if (dvb_register_frontend(adap, input->fe) < 0)
-				return -ENODEV;
-		}
-		break;
-	case DDB_TUNER_DVBS_ST_AA:
-		if (demod_attach_stv0900(input, 1) < 0)
-			return -ENODEV;
-		if (tuner_attach_stv6110(input, 1) < 0)
-			return -ENODEV;
-		if (input->fe) {
-			if (dvb_register_frontend(adap, input->fe) < 0)
-				return -ENODEV;
-		}
-		break;
-	case DDB_TUNER_DVBCT_TR:
-		if (demod_attach_drxk(input) < 0)
-			return -ENODEV;
-		if (tuner_attach_tda18271(input) < 0)
-			return -ENODEV;
-		if (input->fe) {
-			if (dvb_register_frontend(adap, input->fe) < 0)
-				return -ENODEV;
-		}
-		if (input->fe2) {
-			if (dvb_register_frontend(adap, input->fe2) < 0)
-				return -ENODEV;
-			input->fe2->tuner_priv = input->fe->tuner_priv;
-			memcpy(&input->fe2->ops.tuner_ops,
-			       &input->fe->ops.tuner_ops,
-			       sizeof(struct dvb_tuner_ops));
-		}
-		break;
-	}
-	input->attached = 5;
-	return 0;
-}
-
-/****************************************************************************/
-/****************************************************************************/
-
-static ssize_t ts_write(struct file *file, const char *buf,
-			size_t count, loff_t *ppos)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct ddb_output *output = dvbdev->priv;
-	size_t left = count;
-	int stat;
-
-	while (left) {
-		if (ddb_output_free(output) < 188) {
-			if (file->f_flags & O_NONBLOCK)
-				break;
-			if (wait_event_interruptible(
-				    output->wq, ddb_output_free(output) >= 188) < 0)
-				break;
-		}
-		stat = ddb_output_write(output, buf, left);
-		if (stat < 0)
-			break;
-		buf += stat;
-		left -= stat;
-	}
-	return (left == count) ? -EAGAIN : (count - left);
-}
-
-static ssize_t ts_read(struct file *file, char *buf,
-		       size_t count, loff_t *ppos)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct ddb_output *output = dvbdev->priv;
-	struct ddb_input *input = output->port->input[0];
-	int left, read;
-
-	count -= count % 188;
-	left = count;
-	while (left) {
-		if (ddb_input_avail(input) < 188) {
-			if (file->f_flags & O_NONBLOCK)
-				break;
-			if (wait_event_interruptible(
-				    input->wq, ddb_input_avail(input) >= 188) < 0)
-				break;
-		}
-		read = ddb_input_read(input, buf, left);
-		if (read < 0)
-			return read;
-		left -= read;
-		buf += read;
-	}
-	return (left == count) ? -EAGAIN : (count - left);
-}
-
-static unsigned int ts_poll(struct file *file, poll_table *wait)
-{
-	/*
-	struct dvb_device *dvbdev = file->private_data;
-	struct ddb_output *output = dvbdev->priv;
-	struct ddb_input *input = output->port->input[0];
-	*/
-	unsigned int mask = 0;
-
-#if 0
-	if (data_avail_to_read)
-		mask |= POLLIN | POLLRDNORM;
-	if (data_avail_to_write)
-		mask |= POLLOUT | POLLWRNORM;
-
-	poll_wait(file, &read_queue, wait);
-	poll_wait(file, &write_queue, wait);
-#endif
-	return mask;
-}
-
-static const struct file_operations ci_fops = {
-	.owner   = THIS_MODULE,
-	.read    = ts_read,
-	.write   = ts_write,
-	.open    = dvb_generic_open,
-	.release = dvb_generic_release,
-	.poll    = ts_poll,
-	.mmap    = 0,
-};
-
-static struct dvb_device dvbdev_ci = {
-	.priv    = 0,
-	.readers = -1,
-	.writers = -1,
-	.users   = -1,
-	.fops    = &ci_fops,
-};
-
-/****************************************************************************/
-/****************************************************************************/
-/****************************************************************************/
-
-static void input_tasklet(unsigned long data)
-{
-	struct ddb_input *input = (struct ddb_input *) data;
-	struct ddb *dev = input->port->dev;
-
-	spin_lock(&input->lock);
-	if (!input->running) {
-		spin_unlock(&input->lock);
-		return;
-	}
-	input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr));
-
-	if (input->port->class == DDB_PORT_TUNER) {
-		if (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr)))
-			printk(KERN_ERR "Overflow input %d\n", input->nr);
-		while (input->cbuf != ((input->stat >> 11) & 0x1f)
-		       || (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr)))) {
-			dvb_dmx_swfilter_packets(&input->demux,
-						 input->vbuf[input->cbuf],
-						 input->dma_buf_size / 188);
-
-			input->cbuf = (input->cbuf + 1) % input->dma_buf_num;
-			ddbwritel((input->cbuf << 11),
-				  DMA_BUFFER_ACK(input->nr));
-			input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr));
-		       }
-	}
-	if (input->port->class == DDB_PORT_CI)
-		wake_up(&input->wq);
-	spin_unlock(&input->lock);
-}
-
-static void output_tasklet(unsigned long data)
-{
-	struct ddb_output *output = (struct ddb_output *) data;
-	struct ddb *dev = output->port->dev;
-
-	spin_lock(&output->lock);
-	if (!output->running) {
-		spin_unlock(&output->lock);
-		return;
-	}
-	output->stat = ddbreadl(DMA_BUFFER_CURRENT(output->nr + 8));
-	wake_up(&output->wq);
-	spin_unlock(&output->lock);
-}
-
-
-struct cxd2099_cfg cxd_cfg = {
-	.bitrate =  62000,
-	.adr     =  0x40,
-	.polarity = 1,
-	.clock_mode = 1,
-};
-
-static int ddb_ci_attach(struct ddb_port *port)
-{
-	int ret;
-
-	ret = dvb_register_adapter(&port->output->adap,
-				   "DDBridge",
-				   THIS_MODULE,
-				   &port->dev->pdev->dev,
-				   adapter_nr);
-	if (ret < 0)
-		return ret;
-	port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap);
-	if (!port->en) {
-		dvb_unregister_adapter(&port->output->adap);
-		return -ENODEV;
-	}
-	ddb_input_start(port->input[0]);
-	ddb_output_start(port->output);
-	dvb_ca_en50221_init(&port->output->adap,
-			    port->en, 0, 1);
-	ret = dvb_register_device(&port->output->adap, &port->output->dev,
-				  &dvbdev_ci, (void *) port->output,
-				  DVB_DEVICE_SEC);
-	return ret;
-}
-
-static int ddb_port_attach(struct ddb_port *port)
-{
-	int ret = 0;
-
-	switch (port->class) {
-	case DDB_PORT_TUNER:
-		ret = dvb_input_attach(port->input[0]);
-		if (ret < 0)
-			break;
-		ret = dvb_input_attach(port->input[1]);
-		break;
-	case DDB_PORT_CI:
-		ret = ddb_ci_attach(port);
-		break;
-	default:
-		break;
-	}
-	if (ret < 0)
-		printk(KERN_ERR "port_attach on port %d failed\n", port->nr);
-	return ret;
-}
-
-static int ddb_ports_attach(struct ddb *dev)
-{
-	int i, ret = 0;
-	struct ddb_port *port;
-
-	for (i = 0; i < dev->info->port_num; i++) {
-		port = &dev->port[i];
-		ret = ddb_port_attach(port);
-		if (ret < 0)
-			break;
-	}
-	return ret;
-}
-
-static void ddb_ports_detach(struct ddb *dev)
-{
-	int i;
-	struct ddb_port *port;
-
-	for (i = 0; i < dev->info->port_num; i++) {
-		port = &dev->port[i];
-		switch (port->class) {
-		case DDB_PORT_TUNER:
-			dvb_input_detach(port->input[0]);
-			dvb_input_detach(port->input[1]);
-			break;
-		case DDB_PORT_CI:
-			if (port->output->dev)
-				dvb_unregister_device(port->output->dev);
-			if (port->en) {
-				ddb_input_stop(port->input[0]);
-				ddb_output_stop(port->output);
-				dvb_ca_en50221_release(port->en);
-				kfree(port->en);
-				port->en = 0;
-				dvb_unregister_adapter(&port->output->adap);
-			}
-			break;
-		}
-	}
-}
-
-/****************************************************************************/
-/****************************************************************************/
-
-static int port_has_ci(struct ddb_port *port)
-{
-	u8 val;
-	return i2c_read_reg(&port->i2c->adap, 0x40, 0, &val) ? 0 : 1;
-}
-
-static int port_has_stv0900(struct ddb_port *port)
-{
-	u8 val;
-	if (i2c_read_reg16(&port->i2c->adap, 0x69, 0xf100, &val) < 0)
-		return 0;
-	return 1;
-}
-
-static int port_has_stv0900_aa(struct ddb_port *port)
-{
-	u8 val;
-	if (i2c_read_reg16(&port->i2c->adap, 0x68, 0xf100, &val) < 0)
-		return 0;
-	return 1;
-}
-
-static int port_has_drxks(struct ddb_port *port)
-{
-	u8 val;
-	if (i2c_read(&port->i2c->adap, 0x29, &val) < 0)
-		return 0;
-	if (i2c_read(&port->i2c->adap, 0x2a, &val) < 0)
-		return 0;
-	return 1;
-}
-
-static void ddb_port_probe(struct ddb_port *port)
-{
-	struct ddb *dev = port->dev;
-	char *modname = "NO MODULE";
-
-	port->class = DDB_PORT_NONE;
-
-	if (port_has_ci(port)) {
-		modname = "CI";
-		port->class = DDB_PORT_CI;
-		ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
-	} else if (port_has_stv0900(port)) {
-		modname = "DUAL DVB-S2";
-		port->class = DDB_PORT_TUNER;
-		port->type = DDB_TUNER_DVBS_ST;
-		ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING);
-	} else if (port_has_stv0900_aa(port)) {
-		modname = "DUAL DVB-S2";
-		port->class = DDB_PORT_TUNER;
-		port->type = DDB_TUNER_DVBS_ST_AA;
-		ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING);
-	} else if (port_has_drxks(port)) {
-		modname = "DUAL DVB-C/T";
-		port->class = DDB_PORT_TUNER;
-		port->type = DDB_TUNER_DVBCT_TR;
-		ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
-	}
-	printk(KERN_INFO "Port %d (TAB %d): %s\n",
-			 port->nr, port->nr+1, modname);
-}
-
-static void ddb_input_init(struct ddb_port *port, int nr)
-{
-	struct ddb *dev = port->dev;
-	struct ddb_input *input = &dev->input[nr];
-
-	input->nr = nr;
-	input->port = port;
-	input->dma_buf_num = INPUT_DMA_BUFS;
-	input->dma_buf_size = INPUT_DMA_SIZE;
-	ddbwritel(0, TS_INPUT_CONTROL(nr));
-	ddbwritel(2, TS_INPUT_CONTROL(nr));
-	ddbwritel(0, TS_INPUT_CONTROL(nr));
-	ddbwritel(0, DMA_BUFFER_ACK(nr));
-	tasklet_init(&input->tasklet, input_tasklet, (unsigned long) input);
-	spin_lock_init(&input->lock);
-	init_waitqueue_head(&input->wq);
-}
-
-static void ddb_output_init(struct ddb_port *port, int nr)
-{
-	struct ddb *dev = port->dev;
-	struct ddb_output *output = &dev->output[nr];
-	output->nr = nr;
-	output->port = port;
-	output->dma_buf_num = OUTPUT_DMA_BUFS;
-	output->dma_buf_size = OUTPUT_DMA_SIZE;
-
-	ddbwritel(0, TS_OUTPUT_CONTROL(nr));
-	ddbwritel(2, TS_OUTPUT_CONTROL(nr));
-	ddbwritel(0, TS_OUTPUT_CONTROL(nr));
-	tasklet_init(&output->tasklet, output_tasklet, (unsigned long) output);
-	init_waitqueue_head(&output->wq);
-}
-
-static void ddb_ports_init(struct ddb *dev)
-{
-	int i;
-	struct ddb_port *port;
-
-	for (i = 0; i < dev->info->port_num; i++) {
-		port = &dev->port[i];
-		port->dev = dev;
-		port->nr = i;
-		port->i2c = &dev->i2c[i];
-		port->input[0] = &dev->input[2 * i];
-		port->input[1] = &dev->input[2 * i + 1];
-		port->output = &dev->output[i];
-
-		mutex_init(&port->i2c_gate_lock);
-		ddb_port_probe(port);
-		ddb_input_init(port, 2 * i);
-		ddb_input_init(port, 2 * i + 1);
-		ddb_output_init(port, i);
-	}
-}
-
-static void ddb_ports_release(struct ddb *dev)
-{
-	int i;
-	struct ddb_port *port;
-
-	for (i = 0; i < dev->info->port_num; i++) {
-		port = &dev->port[i];
-		port->dev = dev;
-		tasklet_kill(&port->input[0]->tasklet);
-		tasklet_kill(&port->input[1]->tasklet);
-		tasklet_kill(&port->output->tasklet);
-	}
-}
-
-/****************************************************************************/
-/****************************************************************************/
-/****************************************************************************/
-
-static void irq_handle_i2c(struct ddb *dev, int n)
-{
-	struct ddb_i2c *i2c = &dev->i2c[n];
-
-	i2c->done = 1;
-	wake_up(&i2c->wq);
-}
-
-static irqreturn_t irq_handler(int irq, void *dev_id)
-{
-	struct ddb *dev = (struct ddb *) dev_id;
-	u32 s = ddbreadl(INTERRUPT_STATUS);
-
-	if (!s)
-		return IRQ_NONE;
-
-	do {
-		ddbwritel(s, INTERRUPT_ACK);
-
-		if (s & 0x00000001)
-			irq_handle_i2c(dev, 0);
-		if (s & 0x00000002)
-			irq_handle_i2c(dev, 1);
-		if (s & 0x00000004)
-			irq_handle_i2c(dev, 2);
-		if (s & 0x00000008)
-			irq_handle_i2c(dev, 3);
-
-		if (s & 0x00000100)
-			tasklet_schedule(&dev->input[0].tasklet);
-		if (s & 0x00000200)
-			tasklet_schedule(&dev->input[1].tasklet);
-		if (s & 0x00000400)
-			tasklet_schedule(&dev->input[2].tasklet);
-		if (s & 0x00000800)
-			tasklet_schedule(&dev->input[3].tasklet);
-		if (s & 0x00001000)
-			tasklet_schedule(&dev->input[4].tasklet);
-		if (s & 0x00002000)
-			tasklet_schedule(&dev->input[5].tasklet);
-		if (s & 0x00004000)
-			tasklet_schedule(&dev->input[6].tasklet);
-		if (s & 0x00008000)
-			tasklet_schedule(&dev->input[7].tasklet);
-
-		if (s & 0x00010000)
-			tasklet_schedule(&dev->output[0].tasklet);
-		if (s & 0x00020000)
-			tasklet_schedule(&dev->output[1].tasklet);
-		if (s & 0x00040000)
-			tasklet_schedule(&dev->output[2].tasklet);
-		if (s & 0x00080000)
-			tasklet_schedule(&dev->output[3].tasklet);
-
-		/* if (s & 0x000f0000)	printk(KERN_DEBUG "%08x\n", istat); */
-	} while ((s = ddbreadl(INTERRUPT_STATUS)));
-
-	return IRQ_HANDLED;
-}
-
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
-
-static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen)
-{
-	u32 data, shift;
-
-	if (wlen > 4)
-		ddbwritel(1, SPI_CONTROL);
-	while (wlen > 4) {
-		/* FIXME: check for big-endian */
-		data = swab32(*(u32 *)wbuf);
-		wbuf += 4;
-		wlen -= 4;
-		ddbwritel(data, SPI_DATA);
-		while (ddbreadl(SPI_CONTROL) & 0x0004)
-			;
-	}
-
-	if (rlen)
-		ddbwritel(0x0001 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL);
-	else
-		ddbwritel(0x0003 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL);
-
-	data = 0;
-	shift = ((4 - wlen) * 8);
-	while (wlen) {
-		data <<= 8;
-		data |= *wbuf;
-		wlen--;
-		wbuf++;
-	}
-	if (shift)
-		data <<= shift;
-	ddbwritel(data, SPI_DATA);
-	while (ddbreadl(SPI_CONTROL) & 0x0004)
-		;
-
-	if (!rlen) {
-		ddbwritel(0, SPI_CONTROL);
-		return 0;
-	}
-	if (rlen > 4)
-		ddbwritel(1, SPI_CONTROL);
-
-	while (rlen > 4) {
-		ddbwritel(0xffffffff, SPI_DATA);
-		while (ddbreadl(SPI_CONTROL) & 0x0004)
-			;
-		data = ddbreadl(SPI_DATA);
-		*(u32 *) rbuf = swab32(data);
-		rbuf += 4;
-		rlen -= 4;
-	}
-	ddbwritel(0x0003 | ((rlen << (8 + 3)) & 0x1F00), SPI_CONTROL);
-	ddbwritel(0xffffffff, SPI_DATA);
-	while (ddbreadl(SPI_CONTROL) & 0x0004)
-		;
-
-	data = ddbreadl(SPI_DATA);
-	ddbwritel(0, SPI_CONTROL);
-
-	if (rlen < 4)
-		data <<= ((4 - rlen) * 8);
-
-	while (rlen > 0) {
-		*rbuf = ((data >> 24) & 0xff);
-		data <<= 8;
-		rbuf++;
-		rlen--;
-	}
-	return 0;
-}
-
-#define DDB_MAGIC 'd'
-
-struct ddb_flashio {
-	__u8 *write_buf;
-	__u32 write_len;
-	__u8 *read_buf;
-	__u32 read_len;
-};
-
-#define IOCTL_DDB_FLASHIO  _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio)
-
-#define DDB_NAME "ddbridge"
-
-static u32 ddb_num;
-static struct ddb *ddbs[32];
-static struct class *ddb_class;
-static int ddb_major;
-
-static int ddb_open(struct inode *inode, struct file *file)
-{
-	struct ddb *dev = ddbs[iminor(inode)];
-
-	file->private_data = dev;
-	return 0;
-}
-
-static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct ddb *dev = file->private_data;
-	void *parg = (void *)arg;
-	int res;
-
-	switch (cmd) {
-	case IOCTL_DDB_FLASHIO:
-	{
-		struct ddb_flashio fio;
-		u8 *rbuf, *wbuf;
-
-		if (copy_from_user(&fio, parg, sizeof(fio)))
-			return -EFAULT;
-
-		if (fio.write_len > 1028 || fio.read_len > 1028)
-			return -EINVAL;
-		if (fio.write_len + fio.read_len > 1028)
-			return -EINVAL;
-
-		wbuf = &dev->iobuf[0];
-		rbuf = wbuf + fio.write_len;
-
-		if (copy_from_user(wbuf, fio.write_buf, fio.write_len))
-			return -EFAULT;
-		res = flashio(dev, wbuf, fio.write_len, rbuf, fio.read_len);
-		if (res)
-			return res;
-		if (copy_to_user(fio.read_buf, rbuf, fio.read_len))
-			return -EFAULT;
-		break;
-	}
-	default:
-		return -ENOTTY;
-	}
-	return 0;
-}
-
-static const struct file_operations ddb_fops = {
-	.unlocked_ioctl = ddb_ioctl,
-	.open           = ddb_open,
-};
-
-static char *ddb_devnode(struct device *device, umode_t *mode)
-{
-	struct ddb *dev = dev_get_drvdata(device);
-
-	return kasprintf(GFP_KERNEL, "ddbridge/card%d", dev->nr);
-}
-
-static int ddb_class_create(void)
-{
-	ddb_major = register_chrdev(0, DDB_NAME, &ddb_fops);
-	if (ddb_major < 0)
-		return ddb_major;
-
-	ddb_class = class_create(THIS_MODULE, DDB_NAME);
-	if (IS_ERR(ddb_class)) {
-		unregister_chrdev(ddb_major, DDB_NAME);
-		return -1;
-	}
-	ddb_class->devnode = ddb_devnode;
-	return 0;
-}
-
-static void ddb_class_destroy(void)
-{
-	class_destroy(ddb_class);
-	unregister_chrdev(ddb_major, DDB_NAME);
-}
-
-static int ddb_device_create(struct ddb *dev)
-{
-	dev->nr = ddb_num++;
-	dev->ddb_dev = device_create(ddb_class, NULL,
-				     MKDEV(ddb_major, dev->nr),
-				     dev, "ddbridge%d", dev->nr);
-	ddbs[dev->nr] = dev;
-	if (IS_ERR(dev->ddb_dev))
-		return -1;
-	return 0;
-}
-
-static void ddb_device_destroy(struct ddb *dev)
-{
-	ddb_num--;
-	if (IS_ERR(dev->ddb_dev))
-		return;
-	device_destroy(ddb_class, MKDEV(ddb_major, 0));
-}
-
-
-/****************************************************************************/
-/****************************************************************************/
-/****************************************************************************/
-
-static void ddb_unmap(struct ddb *dev)
-{
-	if (dev->regs)
-		iounmap(dev->regs);
-	vfree(dev);
-}
-
-
-static void __devexit ddb_remove(struct pci_dev *pdev)
-{
-	struct ddb *dev = (struct ddb *) pci_get_drvdata(pdev);
-
-	ddb_ports_detach(dev);
-	ddb_i2c_release(dev);
-
-	ddbwritel(0, INTERRUPT_ENABLE);
-	free_irq(dev->pdev->irq, dev);
-#ifdef CONFIG_PCI_MSI
-	if (dev->msi)
-		pci_disable_msi(dev->pdev);
-#endif
-	ddb_ports_release(dev);
-	ddb_buffers_free(dev);
-	ddb_device_destroy(dev);
-
-	ddb_unmap(dev);
-	pci_set_drvdata(pdev, 0);
-	pci_disable_device(pdev);
-}
-
-
-static int __devinit ddb_probe(struct pci_dev *pdev,
-			       const struct pci_device_id *id)
-{
-	struct ddb *dev;
-	int stat = 0;
-	int irq_flag = IRQF_SHARED;
-
-	if (pci_enable_device(pdev) < 0)
-		return -ENODEV;
-
-	dev = vmalloc(sizeof(struct ddb));
-	if (dev == NULL)
-		return -ENOMEM;
-	memset(dev, 0, sizeof(struct ddb));
-
-	dev->pdev = pdev;
-	pci_set_drvdata(pdev, dev);
-	dev->info = (struct ddb_info *) id->driver_data;
-	printk(KERN_INFO "DDBridge driver detected: %s\n", dev->info->name);
-
-	dev->regs = ioremap(pci_resource_start(dev->pdev, 0),
-			    pci_resource_len(dev->pdev, 0));
-	if (!dev->regs) {
-		stat = -ENOMEM;
-		goto fail;
-	}
-	printk(KERN_INFO "HW %08x FW %08x\n", ddbreadl(0), ddbreadl(4));
-
-#ifdef CONFIG_PCI_MSI
-	if (pci_msi_enabled())
-		stat = pci_enable_msi(dev->pdev);
-	if (stat) {
-		printk(KERN_INFO ": MSI not available.\n");
-	} else {
-		irq_flag = 0;
-		dev->msi = 1;
-	}
-#endif
-	stat = request_irq(dev->pdev->irq, irq_handler,
-			   irq_flag, "DDBridge", (void *) dev);
-	if (stat < 0)
-		goto fail1;
-	ddbwritel(0, DMA_BASE_WRITE);
-	ddbwritel(0, DMA_BASE_READ);
-	ddbwritel(0xffffffff, INTERRUPT_ACK);
-	ddbwritel(0xfff0f, INTERRUPT_ENABLE);
-	ddbwritel(0, MSI1_ENABLE);
-
-	if (ddb_i2c_init(dev) < 0)
-		goto fail1;
-	ddb_ports_init(dev);
-	if (ddb_buffers_alloc(dev) < 0) {
-		printk(KERN_INFO ": Could not allocate buffer memory\n");
-		goto fail2;
-	}
-	if (ddb_ports_attach(dev) < 0)
-		goto fail3;
-	ddb_device_create(dev);
-	return 0;
-
-fail3:
-	ddb_ports_detach(dev);
-	printk(KERN_ERR "fail3\n");
-	ddb_ports_release(dev);
-fail2:
-	printk(KERN_ERR "fail2\n");
-	ddb_buffers_free(dev);
-fail1:
-	printk(KERN_ERR "fail1\n");
-	if (dev->msi)
-		pci_disable_msi(dev->pdev);
-	free_irq(dev->pdev->irq, dev);
-fail:
-	printk(KERN_ERR "fail\n");
-	ddb_unmap(dev);
-	pci_set_drvdata(pdev, 0);
-	pci_disable_device(pdev);
-	return -1;
-}
-
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
-
-static struct ddb_info ddb_none = {
-	.type     = DDB_NONE,
-	.name     = "Digital Devices PCIe bridge",
-};
-
-static struct ddb_info ddb_octopus = {
-	.type     = DDB_OCTOPUS,
-	.name     = "Digital Devices Octopus DVB adapter",
-	.port_num = 4,
-};
-
-static struct ddb_info ddb_octopus_le = {
-	.type     = DDB_OCTOPUS,
-	.name     = "Digital Devices Octopus LE DVB adapter",
-	.port_num = 2,
-};
-
-static struct ddb_info ddb_v6 = {
-	.type     = DDB_OCTOPUS,
-	.name     = "Digital Devices Cine S2 V6 DVB adapter",
-	.port_num = 3,
-};
-
-#define DDVID 0xdd01 /* Digital Devices Vendor ID */
-
-#define DDB_ID(_vend, _dev, _subvend, _subdev, _driverdata) {	\
-	.vendor      = _vend,    .device    = _dev, \
-	.subvendor   = _subvend, .subdevice = _subdev, \
-	.driver_data = (unsigned long)&_driverdata }
-
-static const struct pci_device_id ddb_id_tbl[] __devinitdata = {
-	DDB_ID(DDVID, 0x0002, DDVID, 0x0001, ddb_octopus),
-	DDB_ID(DDVID, 0x0003, DDVID, 0x0001, ddb_octopus),
-	DDB_ID(DDVID, 0x0003, DDVID, 0x0002, ddb_octopus_le),
-	DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus),
-	DDB_ID(DDVID, 0x0003, DDVID, 0x0020, ddb_v6),
-	/* in case sub-ids got deleted in flash */
-	DDB_ID(DDVID, 0x0003, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
-	{0}
-};
-MODULE_DEVICE_TABLE(pci, ddb_id_tbl);
-
-
-static struct pci_driver ddb_pci_driver = {
-	.name        = "DDBridge",
-	.id_table    = ddb_id_tbl,
-	.probe       = ddb_probe,
-	.remove      = __devexit_p(ddb_remove),
-};
-
-static __init int module_init_ddbridge(void)
-{
-	printk(KERN_INFO "Digital Devices PCIE bridge driver, "
-	       "Copyright (C) 2010-11 Digital Devices GmbH\n");
-	if (ddb_class_create())
-		return -1;
-	return pci_register_driver(&ddb_pci_driver);
-}
-
-static __exit void module_exit_ddbridge(void)
-{
-	pci_unregister_driver(&ddb_pci_driver);
-	ddb_class_destroy();
-}
-
-module_init(module_init_ddbridge);
-module_exit(module_exit_ddbridge);
-
-MODULE_DESCRIPTION("Digital Devices PCIe Bridge");
-MODULE_AUTHOR("Ralph Metzler");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.5");
diff --git a/drivers/media/dvb/ddbridge/ddbridge-regs.h b/drivers/media/dvb/ddbridge/ddbridge-regs.h
deleted file mode 100644
index a3ccb31..0000000
--- a/drivers/media/dvb/ddbridge/ddbridge-regs.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * ddbridge-regs.h: Digital Devices PCIe bridge driver
- *
- * Copyright (C) 2010-2011 Digital Devices GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-/* DD-DVBBridgeV1.h 273 2010-09-17 05:03:16Z manfred */
-
-/* Register Definitions */
-
-#define CUR_REGISTERMAP_VERSION 0x10000
-
-#define HARDWARE_VERSION       0x00
-#define REGISTERMAP_VERSION    0x04
-
-/* ------------------------------------------------------------------------- */
-/* SPI Controller */
-
-#define SPI_CONTROL     0x10
-#define SPI_DATA        0x14
-
-/* ------------------------------------------------------------------------- */
-
-/* Interrupt controller                                     */
-/* How many MSI's are available depends on HW (Min 2 max 8) */
-/* How many are usable also depends on Host platform        */
-
-#define INTERRUPT_BASE   (0x40)
-
-#define INTERRUPT_ENABLE (INTERRUPT_BASE + 0x00)
-#define MSI0_ENABLE      (INTERRUPT_BASE + 0x00)
-#define MSI1_ENABLE      (INTERRUPT_BASE + 0x04)
-#define MSI2_ENABLE      (INTERRUPT_BASE + 0x08)
-#define MSI3_ENABLE      (INTERRUPT_BASE + 0x0C)
-#define MSI4_ENABLE      (INTERRUPT_BASE + 0x10)
-#define MSI5_ENABLE      (INTERRUPT_BASE + 0x14)
-#define MSI6_ENABLE      (INTERRUPT_BASE + 0x18)
-#define MSI7_ENABLE      (INTERRUPT_BASE + 0x1C)
-
-#define INTERRUPT_STATUS (INTERRUPT_BASE + 0x20)
-#define INTERRUPT_ACK    (INTERRUPT_BASE + 0x20)
-
-#define INTMASK_I2C1        (0x00000001)
-#define INTMASK_I2C2        (0x00000002)
-#define INTMASK_I2C3        (0x00000004)
-#define INTMASK_I2C4        (0x00000008)
-
-#define INTMASK_CIRQ1       (0x00000010)
-#define INTMASK_CIRQ2       (0x00000020)
-#define INTMASK_CIRQ3       (0x00000040)
-#define INTMASK_CIRQ4       (0x00000080)
-
-#define INTMASK_TSINPUT1    (0x00000100)
-#define INTMASK_TSINPUT2    (0x00000200)
-#define INTMASK_TSINPUT3    (0x00000400)
-#define INTMASK_TSINPUT4    (0x00000800)
-#define INTMASK_TSINPUT5    (0x00001000)
-#define INTMASK_TSINPUT6    (0x00002000)
-#define INTMASK_TSINPUT7    (0x00004000)
-#define INTMASK_TSINPUT8    (0x00008000)
-
-#define INTMASK_TSOUTPUT1   (0x00010000)
-#define INTMASK_TSOUTPUT2   (0x00020000)
-#define INTMASK_TSOUTPUT3   (0x00040000)
-#define INTMASK_TSOUTPUT4   (0x00080000)
-
-/* ------------------------------------------------------------------------- */
-/* I2C Master Controller */
-
-#define I2C_BASE        (0x80)  /* Byte offset */
-
-#define I2C_COMMAND     (0x00)
-#define I2C_TIMING      (0x04)
-#define I2C_TASKLENGTH  (0x08)     /* High read, low write */
-#define I2C_TASKADDRESS (0x0C)     /* High read, low write */
-
-#define I2C_MONITOR     (0x1C)
-
-#define I2C_BASE_1      (I2C_BASE + 0x00)
-#define I2C_BASE_2      (I2C_BASE + 0x20)
-#define I2C_BASE_3      (I2C_BASE + 0x40)
-#define I2C_BASE_4      (I2C_BASE + 0x60)
-
-#define I2C_BASE_N(i)   (I2C_BASE + (i) * 0x20)
-
-#define I2C_TASKMEM_BASE    (0x1000)    /* Byte offset */
-#define I2C_TASKMEM_SIZE    (0x1000)
-
-#define I2C_SPEED_400   (0x04030404)
-#define I2C_SPEED_200   (0x09080909)
-#define I2C_SPEED_154   (0x0C0B0C0C)
-#define I2C_SPEED_100   (0x13121313)
-#define I2C_SPEED_77    (0x19181919)
-#define I2C_SPEED_50    (0x27262727)
-
-
-/* ------------------------------------------------------------------------- */
-/* DMA  Controller */
-
-#define DMA_BASE_WRITE        (0x100)
-#define DMA_BASE_READ         (0x140)
-
-#define DMA_CONTROL     (0x00)                  /* 64 */
-#define DMA_ERROR       (0x04)                  /* 65 ( only read instance ) */
-
-#define DMA_DIAG_CONTROL                (0x1C)  /* 71 */
-#define DMA_DIAG_PACKETCOUNTER_LOW      (0x20)  /* 72 */
-#define DMA_DIAG_PACKETCOUNTER_HIGH     (0x24)  /* 73 */
-#define DMA_DIAG_TIMECOUNTER_LOW        (0x28)  /* 74 */
-#define DMA_DIAG_TIMECOUNTER_HIGH       (0x2C)  /* 75 */
-#define DMA_DIAG_RECHECKCOUNTER         (0x30)  /* 76  ( Split completions on read ) */
-#define DMA_DIAG_WAITTIMEOUTINIT        (0x34)  /* 77 */
-#define DMA_DIAG_WAITOVERFLOWCOUNTER    (0x38)  /* 78 */
-#define DMA_DIAG_WAITCOUNTER            (0x3C)  /* 79 */
-
-/* ------------------------------------------------------------------------- */
-/* DMA  Buffer */
-
-#define TS_INPUT_BASE       (0x200)
-#define TS_INPUT_CONTROL(i)         (TS_INPUT_BASE + (i) * 16 + 0x00)
-
-#define TS_OUTPUT_BASE       (0x280)
-#define TS_OUTPUT_CONTROL(i)         (TS_OUTPUT_BASE + (i) * 16 + 0x00)
-
-#define DMA_BUFFER_BASE     (0x300)
-
-#define DMA_BUFFER_CONTROL(i)       (DMA_BUFFER_BASE + (i) * 16 + 0x00)
-#define DMA_BUFFER_ACK(i)           (DMA_BUFFER_BASE + (i) * 16 + 0x04)
-#define DMA_BUFFER_CURRENT(i)       (DMA_BUFFER_BASE + (i) * 16 + 0x08)
-#define DMA_BUFFER_SIZE(i)          (DMA_BUFFER_BASE + (i) * 16 + 0x0c)
-
-#define DMA_BASE_ADDRESS_TABLE  (0x2000)
-#define DMA_BASE_ADDRESS_TABLE_ENTRIES (512)
-
diff --git a/drivers/media/dvb/ddbridge/ddbridge.h b/drivers/media/dvb/ddbridge/ddbridge.h
deleted file mode 100644
index 8b1b41d..0000000
--- a/drivers/media/dvb/ddbridge/ddbridge.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * ddbridge.h: Digital Devices PCIe bridge driver
- *
- * Copyright (C) 2010-2011 Digital Devices GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#ifndef _DDBRIDGE_H_
-#define _DDBRIDGE_H_
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <asm/dma.h>
-#include <linux/dvb/frontend.h>
-#include <linux/dvb/ca.h>
-#include <linux/socket.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_ringbuffer.h"
-#include "dvb_ca_en50221.h"
-#include "dvb_net.h"
-#include "cxd2099.h"
-
-#define DDB_MAX_I2C     4
-#define DDB_MAX_PORT    4
-#define DDB_MAX_INPUT   8
-#define DDB_MAX_OUTPUT  4
-
-struct ddb_info {
-	int   type;
-#define DDB_NONE         0
-#define DDB_OCTOPUS      1
-	char *name;
-	int   port_num;
-	u32   port_type[DDB_MAX_PORT];
-};
-
-/* DMA_SIZE MUST be divisible by 188 and 128 !!! */
-
-#define INPUT_DMA_MAX_BUFS 32      /* hardware table limit */
-#define INPUT_DMA_BUFS 8
-#define INPUT_DMA_SIZE (128*47*21)
-
-#define OUTPUT_DMA_MAX_BUFS 32
-#define OUTPUT_DMA_BUFS 8
-#define OUTPUT_DMA_SIZE (128*47*21)
-
-struct ddb;
-struct ddb_port;
-
-struct ddb_input {
-	struct ddb_port       *port;
-	u32                    nr;
-	int                    attached;
-
-	dma_addr_t             pbuf[INPUT_DMA_MAX_BUFS];
-	u8                    *vbuf[INPUT_DMA_MAX_BUFS];
-	u32                    dma_buf_num;
-	u32                    dma_buf_size;
-
-	struct tasklet_struct  tasklet;
-	spinlock_t             lock;
-	wait_queue_head_t      wq;
-	int                    running;
-	u32                    stat;
-	u32                    cbuf;
-	u32                    coff;
-
-	struct dvb_adapter     adap;
-	struct dvb_device     *dev;
-	struct dvb_frontend   *fe;
-	struct dvb_frontend   *fe2;
-	struct dmxdev          dmxdev;
-	struct dvb_demux       demux;
-	struct dvb_net         dvbnet;
-	struct dmx_frontend    hw_frontend;
-	struct dmx_frontend    mem_frontend;
-	int                    users;
-	int (*gate_ctrl)(struct dvb_frontend *, int);
-};
-
-struct ddb_output {
-	struct ddb_port       *port;
-	u32                    nr;
-	dma_addr_t             pbuf[OUTPUT_DMA_MAX_BUFS];
-	u8                    *vbuf[OUTPUT_DMA_MAX_BUFS];
-	u32                    dma_buf_num;
-	u32                    dma_buf_size;
-	struct tasklet_struct  tasklet;
-	spinlock_t             lock;
-	wait_queue_head_t      wq;
-	int                    running;
-	u32                    stat;
-	u32                    cbuf;
-	u32                    coff;
-
-	struct dvb_adapter     adap;
-	struct dvb_device     *dev;
-};
-
-struct ddb_i2c {
-	struct ddb            *dev;
-	u32                    nr;
-	struct i2c_adapter     adap;
-	struct i2c_adapter     adap2;
-	u32                    regs;
-	u32                    rbuf;
-	u32                    wbuf;
-	int                    done;
-	wait_queue_head_t      wq;
-};
-
-struct ddb_port {
-	struct ddb            *dev;
-	u32                    nr;
-	struct ddb_i2c        *i2c;
-	struct mutex           i2c_gate_lock;
-	u32                    class;
-#define DDB_PORT_NONE           0
-#define DDB_PORT_CI             1
-#define DDB_PORT_TUNER          2
-	u32                    type;
-#define DDB_TUNER_NONE          0
-#define DDB_TUNER_DVBS_ST       1
-#define DDB_TUNER_DVBS_ST_AA    2
-#define DDB_TUNER_DVBCT_TR     16
-#define DDB_TUNER_DVBCT_ST     17
-	u32                    adr;
-
-	struct ddb_input      *input[2];
-	struct ddb_output     *output;
-	struct dvb_ca_en50221 *en;
-};
-
-struct ddb {
-	struct pci_dev        *pdev;
-	unsigned char         *regs;
-	struct ddb_port        port[DDB_MAX_PORT];
-	struct ddb_i2c         i2c[DDB_MAX_I2C];
-	struct ddb_input       input[DDB_MAX_INPUT];
-	struct ddb_output      output[DDB_MAX_OUTPUT];
-
-	struct device         *ddb_dev;
-	int                    nr;
-	u8                     iobuf[1028];
-
-	struct ddb_info       *info;
-	int                    msi;
-};
-
-/****************************************************************************/
-
-#define ddbwritel(_val, _adr)        writel((_val), \
-				     (char *) (dev->regs+(_adr)))
-#define ddbreadl(_adr)               readl((char *) (dev->regs+(_adr)))
-#define ddbcpyto(_adr, _src, _count) memcpy_toio((char *)	\
-				     (dev->regs+(_adr)), (_src), (_count))
-#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), (char *) \
-				       (dev->regs+(_adr)), (_count))
-
-/****************************************************************************/
-
-#endif
diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig
deleted file mode 100644
index f3de0a4..0000000
--- a/drivers/media/dvb/dm1105/Kconfig
+++ /dev/null
@@ -1,20 +0,0 @@
-config DVB_DM1105
-	tristate "SDMC DM1105 based PCI cards"
-	depends on DVB_CORE && PCI && I2C
-	select DVB_PLL if !DVB_FE_CUSTOMISE
-	select DVB_STV0299 if !DVB_FE_CUSTOMISE
-	select DVB_STV0288 if !DVB_FE_CUSTOMISE
-	select DVB_STB6000 if !DVB_FE_CUSTOMISE
-	select DVB_CX24116 if !DVB_FE_CUSTOMISE
-	select DVB_SI21XX if !DVB_FE_CUSTOMISE
-	select DVB_DS3000 if !DVB_FE_CUSTOMISE
-	depends on RC_CORE
-	help
-	  Support for cards based on the SDMC DM1105 PCI chip like
-	  DvbWorld 2002
-
-	  Since these cards have no MPEG decoder onboard, they transmit
-	  only compressed MPEG data over the PCI bus, so you need
-	  an external software decoder to watch TV on your computer.
-
-	  Say Y or M if you own such a device and want to use it.
diff --git a/drivers/media/dvb/dm1105/Makefile b/drivers/media/dvb/dm1105/Makefile
deleted file mode 100644
index 95a008b..0000000
--- a/drivers/media/dvb/dm1105/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_DVB_DM1105) += dm1105.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
deleted file mode 100644
index a609b3a..0000000
--- a/drivers/media/dvb/dm1105/dm1105.c
+++ /dev/null
@@ -1,1248 +0,0 @@
-/*
- * dm1105.c - driver for DVB cards based on SDMC DM1105 PCI chip
- *
- * Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <media/rc-core.h>
-
-#include "demux.h"
-#include "dmxdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-#include "dvbdev.h"
-#include "dvb-pll.h"
-
-#include "stv0299.h"
-#include "stv0288.h"
-#include "stb6000.h"
-#include "si21xx.h"
-#include "cx24116.h"
-#include "z0194a.h"
-#include "ds3000.h"
-
-#define MODULE_NAME "dm1105"
-
-#define UNSET (-1U)
-
-#define DM1105_BOARD_NOAUTO			UNSET
-#define DM1105_BOARD_UNKNOWN			0
-#define DM1105_BOARD_DVBWORLD_2002		1
-#define DM1105_BOARD_DVBWORLD_2004		2
-#define DM1105_BOARD_AXESS_DM05			3
-#define DM1105_BOARD_UNBRANDED_I2C_ON_GPIO	4
-
-/* ----------------------------------------------- */
-/*
- * PCI ID's
- */
-#ifndef PCI_VENDOR_ID_TRIGEM
-#define PCI_VENDOR_ID_TRIGEM	0x109f
-#endif
-#ifndef PCI_VENDOR_ID_AXESS
-#define PCI_VENDOR_ID_AXESS	0x195d
-#endif
-#ifndef PCI_DEVICE_ID_DM1105
-#define PCI_DEVICE_ID_DM1105	0x036f
-#endif
-#ifndef PCI_DEVICE_ID_DW2002
-#define PCI_DEVICE_ID_DW2002	0x2002
-#endif
-#ifndef PCI_DEVICE_ID_DW2004
-#define PCI_DEVICE_ID_DW2004	0x2004
-#endif
-#ifndef PCI_DEVICE_ID_DM05
-#define PCI_DEVICE_ID_DM05	0x1105
-#endif
-/* ----------------------------------------------- */
-/* sdmc dm1105 registers */
-
-/* TS Control */
-#define DM1105_TSCTR				0x00
-#define DM1105_DTALENTH				0x04
-
-/* GPIO Interface */
-#define DM1105_GPIOVAL				0x08
-#define DM1105_GPIOCTR				0x0c
-
-/* PID serial number */
-#define DM1105_PIDN				0x10
-
-/* Odd-even secret key select */
-#define DM1105_CWSEL				0x14
-
-/* Host Command Interface */
-#define DM1105_HOST_CTR				0x18
-#define DM1105_HOST_AD				0x1c
-
-/* PCI Interface */
-#define DM1105_CR				0x30
-#define DM1105_RST				0x34
-#define DM1105_STADR				0x38
-#define DM1105_RLEN				0x3c
-#define DM1105_WRP				0x40
-#define DM1105_INTCNT				0x44
-#define DM1105_INTMAK				0x48
-#define DM1105_INTSTS				0x4c
-
-/* CW Value */
-#define DM1105_ODD				0x50
-#define DM1105_EVEN				0x58
-
-/* PID Value */
-#define DM1105_PID				0x60
-
-/* IR Control */
-#define DM1105_IRCTR				0x64
-#define DM1105_IRMODE				0x68
-#define DM1105_SYSTEMCODE			0x6c
-#define DM1105_IRCODE				0x70
-
-/* Unknown Values */
-#define DM1105_ENCRYPT				0x74
-#define DM1105_VER				0x7c
-
-/* I2C Interface */
-#define DM1105_I2CCTR				0x80
-#define DM1105_I2CSTS				0x81
-#define DM1105_I2CDAT				0x82
-#define DM1105_I2C_RA				0x83
-/* ----------------------------------------------- */
-/* Interrupt Mask Bits */
-
-#define INTMAK_TSIRQM				0x01
-#define INTMAK_HIRQM				0x04
-#define INTMAK_IRM				0x08
-#define INTMAK_ALLMASK				(INTMAK_TSIRQM | \
-						INTMAK_HIRQM | \
-						INTMAK_IRM)
-#define INTMAK_NONEMASK				0x00
-
-/* Interrupt Status Bits */
-#define INTSTS_TSIRQ				0x01
-#define INTSTS_HIRQ				0x04
-#define INTSTS_IR				0x08
-
-/* IR Control Bits */
-#define DM1105_IR_EN				0x01
-#define DM1105_SYS_CHK				0x02
-#define DM1105_REP_FLG				0x08
-
-/* EEPROM addr */
-#define IIC_24C01_addr				0xa0
-/* Max board count */
-#define DM1105_MAX				0x04
-
-#define DRIVER_NAME				"dm1105"
-#define DM1105_I2C_GPIO_NAME			"dm1105-gpio"
-
-#define DM1105_DMA_PACKETS			47
-#define DM1105_DMA_PACKET_LENGTH		(128*4)
-#define DM1105_DMA_BYTES			(128 * 4 * DM1105_DMA_PACKETS)
-
-/*  */
-#define GPIO08					(1 << 8)
-#define GPIO13					(1 << 13)
-#define GPIO14					(1 << 14)
-#define GPIO15					(1 << 15)
-#define GPIO16					(1 << 16)
-#define GPIO17					(1 << 17)
-#define GPIO_ALL				0x03ffff
-
-/* GPIO's for LNB power control */
-#define DM1105_LNB_MASK				(GPIO_ALL & ~(GPIO14 | GPIO13))
-#define DM1105_LNB_OFF				GPIO17
-#define DM1105_LNB_13V				(GPIO16 | GPIO08)
-#define DM1105_LNB_18V				GPIO08
-
-/* GPIO's for LNB power control for Axess DM05 */
-#define DM05_LNB_MASK				(GPIO_ALL & ~(GPIO14 | GPIO13))
-#define DM05_LNB_OFF				GPIO17/* actually 13v */
-#define DM05_LNB_13V				GPIO17
-#define DM05_LNB_18V				(GPIO17 | GPIO16)
-
-/* GPIO's for LNB power control for unbranded with I2C on GPIO */
-#define UNBR_LNB_MASK				(GPIO17 | GPIO16)
-#define UNBR_LNB_OFF				0
-#define UNBR_LNB_13V				GPIO17
-#define UNBR_LNB_18V				(GPIO17 | GPIO16)
-
-static unsigned int card[]  = {[0 ... 3] = UNSET };
-module_param_array(card,  int, NULL, 0444);
-MODULE_PARM_DESC(card, "card type");
-
-static int ir_debug;
-module_param(ir_debug, int, 0644);
-MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
-
-static unsigned int dm1105_devcount;
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-struct dm1105_board {
-	char	*name;
-	struct	{
-		u32	mask, off, v13, v18;
-	} lnb;
-	u32	gpio_scl, gpio_sda;
-};
-
-struct dm1105_subid {
-	u16     subvendor;
-	u16     subdevice;
-	u32     card;
-};
-
-static const struct dm1105_board dm1105_boards[] = {
-	[DM1105_BOARD_UNKNOWN] = {
-		.name		= "UNKNOWN/GENERIC",
-		.lnb = {
-			.mask = DM1105_LNB_MASK,
-			.off = DM1105_LNB_OFF,
-			.v13 = DM1105_LNB_13V,
-			.v18 = DM1105_LNB_18V,
-		},
-	},
-	[DM1105_BOARD_DVBWORLD_2002] = {
-		.name		= "DVBWorld PCI 2002",
-		.lnb = {
-			.mask = DM1105_LNB_MASK,
-			.off = DM1105_LNB_OFF,
-			.v13 = DM1105_LNB_13V,
-			.v18 = DM1105_LNB_18V,
-		},
-	},
-	[DM1105_BOARD_DVBWORLD_2004] = {
-		.name		= "DVBWorld PCI 2004",
-		.lnb = {
-			.mask = DM1105_LNB_MASK,
-			.off = DM1105_LNB_OFF,
-			.v13 = DM1105_LNB_13V,
-			.v18 = DM1105_LNB_18V,
-		},
-	},
-	[DM1105_BOARD_AXESS_DM05] = {
-		.name		= "Axess/EasyTv DM05",
-		.lnb = {
-			.mask = DM05_LNB_MASK,
-			.off = DM05_LNB_OFF,
-			.v13 = DM05_LNB_13V,
-			.v18 = DM05_LNB_18V,
-		},
-	},
-	[DM1105_BOARD_UNBRANDED_I2C_ON_GPIO] = {
-		.name		= "Unbranded DM1105 with i2c on GPIOs",
-		.lnb = {
-			.mask = UNBR_LNB_MASK,
-			.off = UNBR_LNB_OFF,
-			.v13 = UNBR_LNB_13V,
-			.v18 = UNBR_LNB_18V,
-		},
-		.gpio_scl	= GPIO14,
-		.gpio_sda	= GPIO13,
-	},
-};
-
-static const struct dm1105_subid dm1105_subids[] = {
-	{
-		.subvendor = 0x0000,
-		.subdevice = 0x2002,
-		.card      = DM1105_BOARD_DVBWORLD_2002,
-	}, {
-		.subvendor = 0x0001,
-		.subdevice = 0x2002,
-		.card      = DM1105_BOARD_DVBWORLD_2002,
-	}, {
-		.subvendor = 0x0000,
-		.subdevice = 0x2004,
-		.card      = DM1105_BOARD_DVBWORLD_2004,
-	}, {
-		.subvendor = 0x0001,
-		.subdevice = 0x2004,
-		.card      = DM1105_BOARD_DVBWORLD_2004,
-	}, {
-		.subvendor = 0x195d,
-		.subdevice = 0x1105,
-		.card      = DM1105_BOARD_AXESS_DM05,
-	},
-};
-
-static void dm1105_card_list(struct pci_dev *pci)
-{
-	int i;
-
-	if (0 == pci->subsystem_vendor &&
-			0 == pci->subsystem_device) {
-		printk(KERN_ERR
-			"dm1105: Your board has no valid PCI Subsystem ID\n"
-			"dm1105: and thus can't be autodetected\n"
-			"dm1105: Please pass card=<n> insmod option to\n"
-			"dm1105: workaround that.  Redirect complaints to\n"
-			"dm1105: the vendor of the TV card.  Best regards,\n"
-			"dm1105: -- tux\n");
-	} else {
-		printk(KERN_ERR
-			"dm1105: Your board isn't known (yet) to the driver.\n"
-			"dm1105: You can try to pick one of the existing\n"
-			"dm1105: card configs via card=<n> insmod option.\n"
-			"dm1105: Updating to the latest version might help\n"
-			"dm1105: as well.\n");
-	}
-	printk(KERN_ERR "Here is a list of valid choices for the card=<n> "
-		   "insmod option:\n");
-	for (i = 0; i < ARRAY_SIZE(dm1105_boards); i++)
-		printk(KERN_ERR "dm1105:    card=%d -> %s\n",
-				i, dm1105_boards[i].name);
-}
-
-/* infrared remote control */
-struct infrared {
-	struct rc_dev		*dev;
-	char			input_phys[32];
-	struct work_struct	work;
-	u32			ir_command;
-};
-
-struct dm1105_dev {
-	/* pci */
-	struct pci_dev *pdev;
-	u8 __iomem *io_mem;
-
-	/* ir */
-	struct infrared ir;
-
-	/* dvb */
-	struct dmx_frontend hw_frontend;
-	struct dmx_frontend mem_frontend;
-	struct dmxdev dmxdev;
-	struct dvb_adapter dvb_adapter;
-	struct dvb_demux demux;
-	struct dvb_frontend *fe;
-	struct dvb_net dvbnet;
-	unsigned int full_ts_users;
-	unsigned int boardnr;
-	int nr;
-
-	/* i2c */
-	struct i2c_adapter i2c_adap;
-	struct i2c_adapter i2c_bb_adap;
-	struct i2c_algo_bit_data i2c_bit;
-
-	/* irq */
-	struct work_struct work;
-	struct workqueue_struct *wq;
-	char wqn[16];
-
-	/* dma */
-	dma_addr_t dma_addr;
-	unsigned char *ts_buf;
-	u32 wrp;
-	u32 nextwrp;
-	u32 buffer_size;
-	unsigned int	PacketErrorCount;
-	unsigned int dmarst;
-	spinlock_t lock;
-};
-
-#define dm_io_mem(reg)	((unsigned long)(&dev->io_mem[reg]))
-
-#define dm_readb(reg)		inb(dm_io_mem(reg))
-#define dm_writeb(reg, value)	outb((value), (dm_io_mem(reg)))
-
-#define dm_readw(reg)		inw(dm_io_mem(reg))
-#define dm_writew(reg, value)	outw((value), (dm_io_mem(reg)))
-
-#define dm_readl(reg)		inl(dm_io_mem(reg))
-#define dm_writel(reg, value)	outl((value), (dm_io_mem(reg)))
-
-#define dm_andorl(reg, mask, value) \
-	outl((inl(dm_io_mem(reg)) & ~(mask)) |\
-		((value) & (mask)), (dm_io_mem(reg)))
-
-#define dm_setl(reg, bit)	dm_andorl((reg), (bit), (bit))
-#define dm_clearl(reg, bit)	dm_andorl((reg), (bit), 0)
-
-/* The chip has 18 GPIOs. In HOST mode GPIO's used as 15 bit address lines,
- so we can use only 3 GPIO's from GPIO15 to GPIO17.
- Here I don't check whether HOST is enebled as it is not implemented yet.
- */
-static void dm1105_gpio_set(struct dm1105_dev *dev, u32 mask)
-{
-	if (mask & 0xfffc0000)
-		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
-
-	if (mask & 0x0003ffff)
-		dm_setl(DM1105_GPIOVAL, mask & 0x0003ffff);
-
-}
-
-static void dm1105_gpio_clear(struct dm1105_dev *dev, u32 mask)
-{
-	if (mask & 0xfffc0000)
-		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
-
-	if (mask & 0x0003ffff)
-		dm_clearl(DM1105_GPIOVAL, mask & 0x0003ffff);
-
-}
-
-static void dm1105_gpio_andor(struct dm1105_dev *dev, u32 mask, u32 val)
-{
-	if (mask & 0xfffc0000)
-		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
-
-	if (mask & 0x0003ffff)
-		dm_andorl(DM1105_GPIOVAL, mask & 0x0003ffff, val);
-
-}
-
-static u32 dm1105_gpio_get(struct dm1105_dev *dev, u32 mask)
-{
-	if (mask & 0xfffc0000)
-		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
-
-	if (mask & 0x0003ffff)
-		return dm_readl(DM1105_GPIOVAL) & mask & 0x0003ffff;
-
-	return 0;
-}
-
-static void dm1105_gpio_enable(struct dm1105_dev *dev, u32 mask, int asoutput)
-{
-	if (mask & 0xfffc0000)
-		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
-
-	if ((mask & 0x0003ffff) && asoutput)
-		dm_clearl(DM1105_GPIOCTR, mask & 0x0003ffff);
-	else if ((mask & 0x0003ffff) && !asoutput)
-		dm_setl(DM1105_GPIOCTR, mask & 0x0003ffff);
-
-}
-
-static void dm1105_setline(struct dm1105_dev *dev, u32 line, int state)
-{
-	if (state)
-		dm1105_gpio_enable(dev, line, 0);
-	else {
-		dm1105_gpio_enable(dev, line, 1);
-		dm1105_gpio_clear(dev, line);
-	}
-}
-
-static void dm1105_setsda(void *data, int state)
-{
-	struct dm1105_dev *dev = data;
-
-	dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_sda, state);
-}
-
-static void dm1105_setscl(void *data, int state)
-{
-	struct dm1105_dev *dev = data;
-
-	dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_scl, state);
-}
-
-static int dm1105_getsda(void *data)
-{
-	struct dm1105_dev *dev = data;
-
-	return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_sda)
-									? 1 : 0;
-}
-
-static int dm1105_getscl(void *data)
-{
-	struct dm1105_dev *dev = data;
-
-	return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_scl)
-									? 1 : 0;
-}
-
-static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
-			    struct i2c_msg *msgs, int num)
-{
-	struct dm1105_dev *dev ;
-
-	int addr, rc, i, j, k, len, byte, data;
-	u8 status;
-
-	dev = i2c_adap->algo_data;
-	for (i = 0; i < num; i++) {
-		dm_writeb(DM1105_I2CCTR, 0x00);
-		if (msgs[i].flags & I2C_M_RD) {
-			/* read bytes */
-			addr  = msgs[i].addr << 1;
-			addr |= 1;
-			dm_writeb(DM1105_I2CDAT, addr);
-			for (byte = 0; byte < msgs[i].len; byte++)
-				dm_writeb(DM1105_I2CDAT + byte + 1, 0);
-
-			dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len);
-			for (j = 0; j < 55; j++) {
-				mdelay(10);
-				status = dm_readb(DM1105_I2CSTS);
-				if ((status & 0xc0) == 0x40)
-					break;
-			}
-			if (j >= 55)
-				return -1;
-
-			for (byte = 0; byte < msgs[i].len; byte++) {
-				rc = dm_readb(DM1105_I2CDAT + byte + 1);
-				if (rc < 0)
-					goto err;
-				msgs[i].buf[byte] = rc;
-			}
-		} else if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) {
-			/* prepaired for cx24116 firmware */
-			/* Write in small blocks */
-			len = msgs[i].len - 1;
-			k = 1;
-			do {
-				dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1);
-				dm_writeb(DM1105_I2CDAT + 1, 0xf7);
-				for (byte = 0; byte < (len > 48 ? 48 : len); byte++) {
-					data = msgs[i].buf[k + byte];
-					dm_writeb(DM1105_I2CDAT + byte + 2, data);
-				}
-				dm_writeb(DM1105_I2CCTR, 0x82 + (len > 48 ? 48 : len));
-				for (j = 0; j < 25; j++) {
-					mdelay(10);
-					status = dm_readb(DM1105_I2CSTS);
-					if ((status & 0xc0) == 0x40)
-						break;
-				}
-
-				if (j >= 25)
-					return -1;
-
-				k += 48;
-				len -= 48;
-			} while (len > 0);
-		} else {
-			/* write bytes */
-			dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1);
-			for (byte = 0; byte < msgs[i].len; byte++) {
-				data = msgs[i].buf[byte];
-				dm_writeb(DM1105_I2CDAT + byte + 1, data);
-			}
-			dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len);
-			for (j = 0; j < 25; j++) {
-				mdelay(10);
-				status = dm_readb(DM1105_I2CSTS);
-				if ((status & 0xc0) == 0x40)
-					break;
-			}
-
-			if (j >= 25)
-				return -1;
-		}
-	}
-	return num;
- err:
-	return rc;
-}
-
-static u32 functionality(struct i2c_adapter *adap)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm dm1105_algo = {
-	.master_xfer   = dm1105_i2c_xfer,
-	.functionality = functionality,
-};
-
-static inline struct dm1105_dev *feed_to_dm1105_dev(struct dvb_demux_feed *feed)
-{
-	return container_of(feed->demux, struct dm1105_dev, demux);
-}
-
-static inline struct dm1105_dev *frontend_to_dm1105_dev(struct dvb_frontend *fe)
-{
-	return container_of(fe->dvb, struct dm1105_dev, dvb_adapter);
-}
-
-static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
-	struct dm1105_dev *dev = frontend_to_dm1105_dev(fe);
-
-	dm1105_gpio_enable(dev, dm1105_boards[dev->boardnr].lnb.mask, 1);
-	if (voltage == SEC_VOLTAGE_18)
-		dm1105_gpio_andor(dev,
-				dm1105_boards[dev->boardnr].lnb.mask,
-				dm1105_boards[dev->boardnr].lnb.v18);
-	else if (voltage == SEC_VOLTAGE_13)
-		dm1105_gpio_andor(dev,
-				dm1105_boards[dev->boardnr].lnb.mask,
-				dm1105_boards[dev->boardnr].lnb.v13);
-	else
-		dm1105_gpio_andor(dev,
-				dm1105_boards[dev->boardnr].lnb.mask,
-				dm1105_boards[dev->boardnr].lnb.off);
-
-	return 0;
-}
-
-static void dm1105_set_dma_addr(struct dm1105_dev *dev)
-{
-	dm_writel(DM1105_STADR, cpu_to_le32(dev->dma_addr));
-}
-
-static int __devinit dm1105_dma_map(struct dm1105_dev *dev)
-{
-	dev->ts_buf = pci_alloc_consistent(dev->pdev,
-					6 * DM1105_DMA_BYTES,
-					&dev->dma_addr);
-
-	return !dev->ts_buf;
-}
-
-static void dm1105_dma_unmap(struct dm1105_dev *dev)
-{
-	pci_free_consistent(dev->pdev,
-			6 * DM1105_DMA_BYTES,
-			dev->ts_buf,
-			dev->dma_addr);
-}
-
-static void dm1105_enable_irqs(struct dm1105_dev *dev)
-{
-	dm_writeb(DM1105_INTMAK, INTMAK_ALLMASK);
-	dm_writeb(DM1105_CR, 1);
-}
-
-static void dm1105_disable_irqs(struct dm1105_dev *dev)
-{
-	dm_writeb(DM1105_INTMAK, INTMAK_IRM);
-	dm_writeb(DM1105_CR, 0);
-}
-
-static int dm1105_start_feed(struct dvb_demux_feed *f)
-{
-	struct dm1105_dev *dev = feed_to_dm1105_dev(f);
-
-	if (dev->full_ts_users++ == 0)
-		dm1105_enable_irqs(dev);
-
-	return 0;
-}
-
-static int dm1105_stop_feed(struct dvb_demux_feed *f)
-{
-	struct dm1105_dev *dev = feed_to_dm1105_dev(f);
-
-	if (--dev->full_ts_users == 0)
-		dm1105_disable_irqs(dev);
-
-	return 0;
-}
-
-/* ir work handler */
-static void dm1105_emit_key(struct work_struct *work)
-{
-	struct infrared *ir = container_of(work, struct infrared, work);
-	u32 ircom = ir->ir_command;
-	u8 data;
-
-	if (ir_debug)
-		printk(KERN_INFO "%s: received byte 0x%04x\n", __func__, ircom);
-
-	data = (ircom >> 8) & 0x7f;
-
-	rc_keydown(ir->dev, data, 0);
-}
-
-/* work handler */
-static void dm1105_dmx_buffer(struct work_struct *work)
-{
-	struct dm1105_dev *dev = container_of(work, struct dm1105_dev, work);
-	unsigned int nbpackets;
-	u32 oldwrp = dev->wrp;
-	u32 nextwrp = dev->nextwrp;
-
-	if (!((dev->ts_buf[oldwrp] == 0x47) &&
-			(dev->ts_buf[oldwrp + 188] == 0x47) &&
-			(dev->ts_buf[oldwrp + 188 * 2] == 0x47))) {
-		dev->PacketErrorCount++;
-		/* bad packet found */
-		if ((dev->PacketErrorCount >= 2) &&
-				(dev->dmarst == 0)) {
-			dm_writeb(DM1105_RST, 1);
-			dev->wrp = 0;
-			dev->PacketErrorCount = 0;
-			dev->dmarst = 0;
-			return;
-		}
-	}
-
-	if (nextwrp < oldwrp) {
-		memcpy(dev->ts_buf + dev->buffer_size, dev->ts_buf, nextwrp);
-		nbpackets = ((dev->buffer_size - oldwrp) + nextwrp) / 188;
-	} else
-		nbpackets = (nextwrp - oldwrp) / 188;
-
-	dev->wrp = nextwrp;
-	dvb_dmx_swfilter_packets(&dev->demux, &dev->ts_buf[oldwrp], nbpackets);
-}
-
-static irqreturn_t dm1105_irq(int irq, void *dev_id)
-{
-	struct dm1105_dev *dev = dev_id;
-
-	/* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */
-	unsigned int intsts = dm_readb(DM1105_INTSTS);
-	dm_writeb(DM1105_INTSTS, intsts);
-
-	switch (intsts) {
-	case INTSTS_TSIRQ:
-	case (INTSTS_TSIRQ | INTSTS_IR):
-		dev->nextwrp = dm_readl(DM1105_WRP) - dm_readl(DM1105_STADR);
-		queue_work(dev->wq, &dev->work);
-		break;
-	case INTSTS_IR:
-		dev->ir.ir_command = dm_readl(DM1105_IRCODE);
-		schedule_work(&dev->ir.work);
-		break;
-	}
-
-	return IRQ_HANDLED;
-}
-
-int __devinit dm1105_ir_init(struct dm1105_dev *dm1105)
-{
-	struct rc_dev *dev;
-	int err = -ENOMEM;
-
-	dev = rc_allocate_device();
-	if (!dev)
-		return -ENOMEM;
-
-	snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys),
-		"pci-%s/ir0", pci_name(dm1105->pdev));
-
-	dev->driver_name = MODULE_NAME;
-	dev->map_name = RC_MAP_DM1105_NEC;
-	dev->driver_type = RC_DRIVER_SCANCODE;
-	dev->input_name = "DVB on-card IR receiver";
-	dev->input_phys = dm1105->ir.input_phys;
-	dev->input_id.bustype = BUS_PCI;
-	dev->input_id.version = 1;
-	if (dm1105->pdev->subsystem_vendor) {
-		dev->input_id.vendor = dm1105->pdev->subsystem_vendor;
-		dev->input_id.product = dm1105->pdev->subsystem_device;
-	} else {
-		dev->input_id.vendor = dm1105->pdev->vendor;
-		dev->input_id.product = dm1105->pdev->device;
-	}
-	dev->dev.parent = &dm1105->pdev->dev;
-
-	INIT_WORK(&dm1105->ir.work, dm1105_emit_key);
-
-	err = rc_register_device(dev);
-	if (err < 0) {
-		rc_free_device(dev);
-		return err;
-	}
-
-	dm1105->ir.dev = dev;
-	return 0;
-}
-
-void __devexit dm1105_ir_exit(struct dm1105_dev *dm1105)
-{
-	rc_unregister_device(dm1105->ir.dev);
-}
-
-static int __devinit dm1105_hw_init(struct dm1105_dev *dev)
-{
-	dm1105_disable_irqs(dev);
-
-	dm_writeb(DM1105_HOST_CTR, 0);
-
-	/*DATALEN 188,*/
-	dm_writeb(DM1105_DTALENTH, 188);
-	/*TS_STRT TS_VALP MSBFIRST TS_MODE ALPAS TSPES*/
-	dm_writew(DM1105_TSCTR, 0xc10a);
-
-	/* map DMA and set address */
-	dm1105_dma_map(dev);
-	dm1105_set_dma_addr(dev);
-	/* big buffer */
-	dm_writel(DM1105_RLEN, 5 * DM1105_DMA_BYTES);
-	dm_writeb(DM1105_INTCNT, 47);
-
-	/* IR NEC mode enable */
-	dm_writeb(DM1105_IRCTR, (DM1105_IR_EN | DM1105_SYS_CHK));
-	dm_writeb(DM1105_IRMODE, 0);
-	dm_writew(DM1105_SYSTEMCODE, 0);
-
-	return 0;
-}
-
-static void dm1105_hw_exit(struct dm1105_dev *dev)
-{
-	dm1105_disable_irqs(dev);
-
-	/* IR disable */
-	dm_writeb(DM1105_IRCTR, 0);
-	dm_writeb(DM1105_INTMAK, INTMAK_NONEMASK);
-
-	dm1105_dma_unmap(dev);
-}
-
-static struct stv0299_config sharp_z0194a_config = {
-	.demod_address = 0x68,
-	.inittab = sharp_z0194a_inittab,
-	.mclk = 88000000UL,
-	.invert = 1,
-	.skip_reinit = 0,
-	.lock_output = STV0299_LOCKOUTPUT_1,
-	.volt13_op0_op1 = STV0299_VOLT13_OP1,
-	.min_delay_ms = 100,
-	.set_symbol_rate = sharp_z0194a_set_symbol_rate,
-};
-
-static struct stv0288_config earda_config = {
-	.demod_address = 0x68,
-	.min_delay_ms = 100,
-};
-
-static struct si21xx_config serit_config = {
-	.demod_address = 0x68,
-	.min_delay_ms = 100,
-
-};
-
-static struct cx24116_config serit_sp2633_config = {
-	.demod_address = 0x55,
-};
-
-static struct ds3000_config dvbworld_ds3000_config = {
-	.demod_address = 0x68,
-};
-
-static int __devinit frontend_init(struct dm1105_dev *dev)
-{
-	int ret;
-
-	switch (dev->boardnr) {
-	case DM1105_BOARD_UNBRANDED_I2C_ON_GPIO:
-		dm1105_gpio_enable(dev, GPIO15, 1);
-		dm1105_gpio_clear(dev, GPIO15);
-		msleep(100);
-		dm1105_gpio_set(dev, GPIO15);
-		msleep(200);
-		dev->fe = dvb_attach(
-			stv0299_attach, &sharp_z0194a_config,
-			&dev->i2c_bb_adap);
-		if (dev->fe) {
-			dev->fe->ops.set_voltage = dm1105_set_voltage;
-			dvb_attach(dvb_pll_attach, dev->fe, 0x60,
-					&dev->i2c_bb_adap, DVB_PLL_OPERA1);
-			break;
-		}
-
-		dev->fe = dvb_attach(
-			stv0288_attach, &earda_config,
-			&dev->i2c_bb_adap);
-		if (dev->fe) {
-			dev->fe->ops.set_voltage = dm1105_set_voltage;
-			dvb_attach(stb6000_attach, dev->fe, 0x61,
-					&dev->i2c_bb_adap);
-			break;
-		}
-
-		dev->fe = dvb_attach(
-			si21xx_attach, &serit_config,
-			&dev->i2c_bb_adap);
-		if (dev->fe)
-			dev->fe->ops.set_voltage = dm1105_set_voltage;
-		break;
-	case DM1105_BOARD_DVBWORLD_2004:
-		dev->fe = dvb_attach(
-			cx24116_attach, &serit_sp2633_config,
-			&dev->i2c_adap);
-		if (dev->fe) {
-			dev->fe->ops.set_voltage = dm1105_set_voltage;
-			break;
-		}
-
-		dev->fe = dvb_attach(
-			ds3000_attach, &dvbworld_ds3000_config,
-			&dev->i2c_adap);
-		if (dev->fe)
-			dev->fe->ops.set_voltage = dm1105_set_voltage;
-
-		break;
-	case DM1105_BOARD_DVBWORLD_2002:
-	case DM1105_BOARD_AXESS_DM05:
-	default:
-		dev->fe = dvb_attach(
-			stv0299_attach, &sharp_z0194a_config,
-			&dev->i2c_adap);
-		if (dev->fe) {
-			dev->fe->ops.set_voltage = dm1105_set_voltage;
-			dvb_attach(dvb_pll_attach, dev->fe, 0x60,
-					&dev->i2c_adap, DVB_PLL_OPERA1);
-			break;
-		}
-
-		dev->fe = dvb_attach(
-			stv0288_attach, &earda_config,
-			&dev->i2c_adap);
-		if (dev->fe) {
-			dev->fe->ops.set_voltage = dm1105_set_voltage;
-			dvb_attach(stb6000_attach, dev->fe, 0x61,
-					&dev->i2c_adap);
-			break;
-		}
-
-		dev->fe = dvb_attach(
-			si21xx_attach, &serit_config,
-			&dev->i2c_adap);
-		if (dev->fe)
-			dev->fe->ops.set_voltage = dm1105_set_voltage;
-
-	}
-
-	if (!dev->fe) {
-		dev_err(&dev->pdev->dev, "could not attach frontend\n");
-		return -ENODEV;
-	}
-
-	ret = dvb_register_frontend(&dev->dvb_adapter, dev->fe);
-	if (ret < 0) {
-		if (dev->fe->ops.release)
-			dev->fe->ops.release(dev->fe);
-		dev->fe = NULL;
-		return ret;
-	}
-
-	return 0;
-}
-
-static void __devinit dm1105_read_mac(struct dm1105_dev *dev, u8 *mac)
-{
-	static u8 command[1] = { 0x28 };
-
-	struct i2c_msg msg[] = {
-		{
-			.addr = IIC_24C01_addr >> 1,
-			.flags = 0,
-			.buf = command,
-			.len = 1
-		}, {
-			.addr = IIC_24C01_addr >> 1,
-			.flags = I2C_M_RD,
-			.buf = mac,
-			.len = 6
-		},
-	};
-
-	dm1105_i2c_xfer(&dev->i2c_adap, msg , 2);
-	dev_info(&dev->pdev->dev, "MAC %pM\n", mac);
-}
-
-static int __devinit dm1105_probe(struct pci_dev *pdev,
-				  const struct pci_device_id *ent)
-{
-	struct dm1105_dev *dev;
-	struct dvb_adapter *dvb_adapter;
-	struct dvb_demux *dvbdemux;
-	struct dmx_demux *dmx;
-	int ret = -ENOMEM;
-	int i;
-
-	dev = kzalloc(sizeof(struct dm1105_dev), GFP_KERNEL);
-	if (!dev)
-		return -ENOMEM;
-
-	/* board config */
-	dev->nr = dm1105_devcount;
-	dev->boardnr = UNSET;
-	if (card[dev->nr] < ARRAY_SIZE(dm1105_boards))
-		dev->boardnr = card[dev->nr];
-	for (i = 0; UNSET == dev->boardnr &&
-				i < ARRAY_SIZE(dm1105_subids); i++)
-		if (pdev->subsystem_vendor ==
-			dm1105_subids[i].subvendor &&
-				pdev->subsystem_device ==
-					dm1105_subids[i].subdevice)
-			dev->boardnr = dm1105_subids[i].card;
-
-	if (UNSET == dev->boardnr) {
-		dev->boardnr = DM1105_BOARD_UNKNOWN;
-		dm1105_card_list(pdev);
-	}
-
-	dm1105_devcount++;
-	dev->pdev = pdev;
-	dev->buffer_size = 5 * DM1105_DMA_BYTES;
-	dev->PacketErrorCount = 0;
-	dev->dmarst = 0;
-
-	ret = pci_enable_device(pdev);
-	if (ret < 0)
-		goto err_kfree;
-
-	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-	if (ret < 0)
-		goto err_pci_disable_device;
-
-	pci_set_master(pdev);
-
-	ret = pci_request_regions(pdev, DRIVER_NAME);
-	if (ret < 0)
-		goto err_pci_disable_device;
-
-	dev->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
-	if (!dev->io_mem) {
-		ret = -EIO;
-		goto err_pci_release_regions;
-	}
-
-	spin_lock_init(&dev->lock);
-	pci_set_drvdata(pdev, dev);
-
-	ret = dm1105_hw_init(dev);
-	if (ret < 0)
-		goto err_pci_iounmap;
-
-	/* i2c */
-	i2c_set_adapdata(&dev->i2c_adap, dev);
-	strcpy(dev->i2c_adap.name, DRIVER_NAME);
-	dev->i2c_adap.owner = THIS_MODULE;
-	dev->i2c_adap.dev.parent = &pdev->dev;
-	dev->i2c_adap.algo = &dm1105_algo;
-	dev->i2c_adap.algo_data = dev;
-	ret = i2c_add_adapter(&dev->i2c_adap);
-
-	if (ret < 0)
-		goto err_dm1105_hw_exit;
-
-	i2c_set_adapdata(&dev->i2c_bb_adap, dev);
-	strcpy(dev->i2c_bb_adap.name, DM1105_I2C_GPIO_NAME);
-	dev->i2c_bb_adap.owner = THIS_MODULE;
-	dev->i2c_bb_adap.dev.parent = &pdev->dev;
-	dev->i2c_bb_adap.algo_data = &dev->i2c_bit;
-	dev->i2c_bit.data = dev;
-	dev->i2c_bit.setsda = dm1105_setsda;
-	dev->i2c_bit.setscl = dm1105_setscl;
-	dev->i2c_bit.getsda = dm1105_getsda;
-	dev->i2c_bit.getscl = dm1105_getscl;
-	dev->i2c_bit.udelay = 10;
-	dev->i2c_bit.timeout = 10;
-
-	/* Raise SCL and SDA */
-	dm1105_setsda(dev, 1);
-	dm1105_setscl(dev, 1);
-
-	ret = i2c_bit_add_bus(&dev->i2c_bb_adap);
-	if (ret < 0)
-		goto err_i2c_del_adapter;
-
-	/* dvb */
-	ret = dvb_register_adapter(&dev->dvb_adapter, DRIVER_NAME,
-					THIS_MODULE, &pdev->dev, adapter_nr);
-	if (ret < 0)
-		goto err_i2c_del_adapters;
-
-	dvb_adapter = &dev->dvb_adapter;
-
-	dm1105_read_mac(dev, dvb_adapter->proposed_mac);
-
-	dvbdemux = &dev->demux;
-	dvbdemux->filternum = 256;
-	dvbdemux->feednum = 256;
-	dvbdemux->start_feed = dm1105_start_feed;
-	dvbdemux->stop_feed = dm1105_stop_feed;
-	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
-			DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
-	ret = dvb_dmx_init(dvbdemux);
-	if (ret < 0)
-		goto err_dvb_unregister_adapter;
-
-	dmx = &dvbdemux->dmx;
-	dev->dmxdev.filternum = 256;
-	dev->dmxdev.demux = dmx;
-	dev->dmxdev.capabilities = 0;
-
-	ret = dvb_dmxdev_init(&dev->dmxdev, dvb_adapter);
-	if (ret < 0)
-		goto err_dvb_dmx_release;
-
-	dev->hw_frontend.source = DMX_FRONTEND_0;
-
-	ret = dmx->add_frontend(dmx, &dev->hw_frontend);
-	if (ret < 0)
-		goto err_dvb_dmxdev_release;
-
-	dev->mem_frontend.source = DMX_MEMORY_FE;
-
-	ret = dmx->add_frontend(dmx, &dev->mem_frontend);
-	if (ret < 0)
-		goto err_remove_hw_frontend;
-
-	ret = dmx->connect_frontend(dmx, &dev->hw_frontend);
-	if (ret < 0)
-		goto err_remove_mem_frontend;
-
-	ret = dvb_net_init(dvb_adapter, &dev->dvbnet, dmx);
-	if (ret < 0)
-		goto err_disconnect_frontend;
-
-	ret = frontend_init(dev);
-	if (ret < 0)
-		goto err_dvb_net;
-
-	dm1105_ir_init(dev);
-
-	INIT_WORK(&dev->work, dm1105_dmx_buffer);
-	sprintf(dev->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num);
-	dev->wq = create_singlethread_workqueue(dev->wqn);
-	if (!dev->wq)
-		goto err_dvb_net;
-
-	ret = request_irq(pdev->irq, dm1105_irq, IRQF_SHARED,
-						DRIVER_NAME, dev);
-	if (ret < 0)
-		goto err_workqueue;
-
-	return 0;
-
-err_workqueue:
-	destroy_workqueue(dev->wq);
-err_dvb_net:
-	dvb_net_release(&dev->dvbnet);
-err_disconnect_frontend:
-	dmx->disconnect_frontend(dmx);
-err_remove_mem_frontend:
-	dmx->remove_frontend(dmx, &dev->mem_frontend);
-err_remove_hw_frontend:
-	dmx->remove_frontend(dmx, &dev->hw_frontend);
-err_dvb_dmxdev_release:
-	dvb_dmxdev_release(&dev->dmxdev);
-err_dvb_dmx_release:
-	dvb_dmx_release(dvbdemux);
-err_dvb_unregister_adapter:
-	dvb_unregister_adapter(dvb_adapter);
-err_i2c_del_adapters:
-	i2c_del_adapter(&dev->i2c_bb_adap);
-err_i2c_del_adapter:
-	i2c_del_adapter(&dev->i2c_adap);
-err_dm1105_hw_exit:
-	dm1105_hw_exit(dev);
-err_pci_iounmap:
-	pci_iounmap(pdev, dev->io_mem);
-err_pci_release_regions:
-	pci_release_regions(pdev);
-err_pci_disable_device:
-	pci_disable_device(pdev);
-err_kfree:
-	pci_set_drvdata(pdev, NULL);
-	kfree(dev);
-	return ret;
-}
-
-static void __devexit dm1105_remove(struct pci_dev *pdev)
-{
-	struct dm1105_dev *dev = pci_get_drvdata(pdev);
-	struct dvb_adapter *dvb_adapter = &dev->dvb_adapter;
-	struct dvb_demux *dvbdemux = &dev->demux;
-	struct dmx_demux *dmx = &dvbdemux->dmx;
-
-	dm1105_ir_exit(dev);
-	dmx->close(dmx);
-	dvb_net_release(&dev->dvbnet);
-	if (dev->fe)
-		dvb_unregister_frontend(dev->fe);
-
-	dmx->disconnect_frontend(dmx);
-	dmx->remove_frontend(dmx, &dev->mem_frontend);
-	dmx->remove_frontend(dmx, &dev->hw_frontend);
-	dvb_dmxdev_release(&dev->dmxdev);
-	dvb_dmx_release(dvbdemux);
-	dvb_unregister_adapter(dvb_adapter);
-	if (&dev->i2c_adap)
-		i2c_del_adapter(&dev->i2c_adap);
-
-	dm1105_hw_exit(dev);
-	synchronize_irq(pdev->irq);
-	free_irq(pdev->irq, dev);
-	pci_iounmap(pdev, dev->io_mem);
-	pci_release_regions(pdev);
-	pci_disable_device(pdev);
-	pci_set_drvdata(pdev, NULL);
-	dm1105_devcount--;
-	kfree(dev);
-}
-
-static struct pci_device_id dm1105_id_table[] __devinitdata = {
-	{
-		.vendor = PCI_VENDOR_ID_TRIGEM,
-		.device = PCI_DEVICE_ID_DM1105,
-		.subvendor = PCI_ANY_ID,
-		.subdevice = PCI_ANY_ID,
-	}, {
-		.vendor = PCI_VENDOR_ID_AXESS,
-		.device = PCI_DEVICE_ID_DM05,
-		.subvendor = PCI_ANY_ID,
-		.subdevice = PCI_ANY_ID,
-	}, {
-		/* empty */
-	},
-};
-
-MODULE_DEVICE_TABLE(pci, dm1105_id_table);
-
-static struct pci_driver dm1105_driver = {
-	.name = DRIVER_NAME,
-	.id_table = dm1105_id_table,
-	.probe = dm1105_probe,
-	.remove = __devexit_p(dm1105_remove),
-};
-
-static int __init dm1105_init(void)
-{
-	return pci_register_driver(&dm1105_driver);
-}
-
-static void __exit dm1105_exit(void)
-{
-	pci_unregister_driver(&dm1105_driver);
-}
-
-module_init(dm1105_init);
-module_exit(dm1105_exit);
-
-MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>");
-MODULE_DESCRIPTION("SDMC DM1105 DVB driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile
deleted file mode 100644
index 8f22bcd..0000000
--- a/drivers/media/dvb/dvb-core/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Makefile for the kernel DVB device drivers.
-#
-
-dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
-
-dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o 	\
-		 dvb_ca_en50221.o dvb_frontend.o 		\
-		 $(dvb-net-y) dvb_ringbuffer.o dvb_math.o
-
-obj-$(CONFIG_DVB_CORE) += dvb-core.o
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
deleted file mode 100644
index eb91fd8..0000000
--- a/drivers/media/dvb/dvb-core/demux.h
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * demux.h
- *
- * Copyright (c) 2002 Convergence GmbH
- *
- * based on code:
- * Copyright (c) 2000 Nokia Research Center
- *                    Tampere, FINLAND
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- */
-
-#ifndef __DEMUX_H
-#define __DEMUX_H
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/list.h>
-#include <linux/time.h>
-#include <linux/dvb/dmx.h>
-
-/*--------------------------------------------------------------------------*/
-/* Common definitions */
-/*--------------------------------------------------------------------------*/
-
-/*
- * DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter.
- */
-
-#ifndef DMX_MAX_FILTER_SIZE
-#define DMX_MAX_FILTER_SIZE 18
-#endif
-
-/*
- * DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter.
- */
-
-#ifndef DMX_MAX_SECTION_SIZE
-#define DMX_MAX_SECTION_SIZE 4096
-#endif
-#ifndef DMX_MAX_SECFEED_SIZE
-#define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188)
-#endif
-
-
-/*
- * enum dmx_success: Success codes for the Demux Callback API.
- */
-
-enum dmx_success {
-  DMX_OK = 0, /* Received Ok */
-  DMX_LENGTH_ERROR, /* Incorrect length */
-  DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */
-  DMX_CRC_ERROR, /* Incorrect CRC */
-  DMX_FRAME_ERROR, /* Frame alignment error */
-  DMX_FIFO_ERROR, /* Receiver FIFO overrun */
-  DMX_MISSED_ERROR /* Receiver missed packet */
-} ;
-
-/*--------------------------------------------------------------------------*/
-/* TS packet reception */
-/*--------------------------------------------------------------------------*/
-
-/* TS filter type for set() */
-
-#define TS_PACKET       1   /* send TS packets (188 bytes) to callback (default) */
-#define	TS_PAYLOAD_ONLY 2   /* in case TS_PACKET is set, only send the TS
-			       payload (<=184 bytes per packet) to callback */
-#define TS_DECODER      4   /* send stream to built-in decoder (if present) */
-#define TS_DEMUX        8   /* in case TS_PACKET is set, send the TS to
-			       the demux device, not to the dvr device */
-
-/* PES type for filters which write to built-in decoder */
-/* these should be kept identical to the types in dmx.h */
-
-enum dmx_ts_pes
-{  /* also send packets to decoder (if it exists) */
-	DMX_TS_PES_AUDIO0,
-	DMX_TS_PES_VIDEO0,
-	DMX_TS_PES_TELETEXT0,
-	DMX_TS_PES_SUBTITLE0,
-	DMX_TS_PES_PCR0,
-
-	DMX_TS_PES_AUDIO1,
-	DMX_TS_PES_VIDEO1,
-	DMX_TS_PES_TELETEXT1,
-	DMX_TS_PES_SUBTITLE1,
-	DMX_TS_PES_PCR1,
-
-	DMX_TS_PES_AUDIO2,
-	DMX_TS_PES_VIDEO2,
-	DMX_TS_PES_TELETEXT2,
-	DMX_TS_PES_SUBTITLE2,
-	DMX_TS_PES_PCR2,
-
-	DMX_TS_PES_AUDIO3,
-	DMX_TS_PES_VIDEO3,
-	DMX_TS_PES_TELETEXT3,
-	DMX_TS_PES_SUBTITLE3,
-	DMX_TS_PES_PCR3,
-
-	DMX_TS_PES_OTHER
-};
-
-#define DMX_TS_PES_AUDIO    DMX_TS_PES_AUDIO0
-#define DMX_TS_PES_VIDEO    DMX_TS_PES_VIDEO0
-#define DMX_TS_PES_TELETEXT DMX_TS_PES_TELETEXT0
-#define DMX_TS_PES_SUBTITLE DMX_TS_PES_SUBTITLE0
-#define DMX_TS_PES_PCR      DMX_TS_PES_PCR0
-
-
-struct dmx_ts_feed {
-	int is_filtering; /* Set to non-zero when filtering in progress */
-	struct dmx_demux *parent; /* Back-pointer */
-	void *priv; /* Pointer to private data of the API client */
-	int (*set) (struct dmx_ts_feed *feed,
-		    u16 pid,
-		    int type,
-		    enum dmx_ts_pes pes_type,
-		    size_t circular_buffer_size,
-		    struct timespec timeout);
-	int (*start_filtering) (struct dmx_ts_feed* feed);
-	int (*stop_filtering) (struct dmx_ts_feed* feed);
-};
-
-/*--------------------------------------------------------------------------*/
-/* Section reception */
-/*--------------------------------------------------------------------------*/
-
-struct dmx_section_filter {
-	u8 filter_value [DMX_MAX_FILTER_SIZE];
-	u8 filter_mask [DMX_MAX_FILTER_SIZE];
-	u8 filter_mode [DMX_MAX_FILTER_SIZE];
-	struct dmx_section_feed* parent; /* Back-pointer */
-	void* priv; /* Pointer to private data of the API client */
-};
-
-struct dmx_section_feed {
-	int is_filtering; /* Set to non-zero when filtering in progress */
-	struct dmx_demux* parent; /* Back-pointer */
-	void* priv; /* Pointer to private data of the API client */
-
-	int check_crc;
-	u32 crc_val;
-
-	u8 *secbuf;
-	u8 secbuf_base[DMX_MAX_SECFEED_SIZE];
-	u16 secbufp, seclen, tsfeedp;
-
-	int (*set) (struct dmx_section_feed* feed,
-		    u16 pid,
-		    size_t circular_buffer_size,
-		    int check_crc);
-	int (*allocate_filter) (struct dmx_section_feed* feed,
-				struct dmx_section_filter** filter);
-	int (*release_filter) (struct dmx_section_feed* feed,
-			       struct dmx_section_filter* filter);
-	int (*start_filtering) (struct dmx_section_feed* feed);
-	int (*stop_filtering) (struct dmx_section_feed* feed);
-};
-
-/*--------------------------------------------------------------------------*/
-/* Callback functions */
-/*--------------------------------------------------------------------------*/
-
-typedef int (*dmx_ts_cb) ( const u8 * buffer1,
-			   size_t buffer1_length,
-			   const u8 * buffer2,
-			   size_t buffer2_length,
-			   struct dmx_ts_feed* source,
-			   enum dmx_success success);
-
-typedef int (*dmx_section_cb) (	const u8 * buffer1,
-				size_t buffer1_len,
-				const u8 * buffer2,
-				size_t buffer2_len,
-				struct dmx_section_filter * source,
-				enum dmx_success success);
-
-/*--------------------------------------------------------------------------*/
-/* DVB Front-End */
-/*--------------------------------------------------------------------------*/
-
-enum dmx_frontend_source {
-	DMX_MEMORY_FE,
-	DMX_FRONTEND_0,
-	DMX_FRONTEND_1,
-	DMX_FRONTEND_2,
-	DMX_FRONTEND_3,
-	DMX_STREAM_0,    /* external stream input, e.g. LVDS */
-	DMX_STREAM_1,
-	DMX_STREAM_2,
-	DMX_STREAM_3
-};
-
-struct dmx_frontend {
-	struct list_head connectivity_list; /* List of front-ends that can
-					       be connected to a particular
-					       demux */
-	enum dmx_frontend_source source;
-};
-
-/*--------------------------------------------------------------------------*/
-/* MPEG-2 TS Demux */
-/*--------------------------------------------------------------------------*/
-
-/*
- * Flags OR'ed in the capabilities field of struct dmx_demux.
- */
-
-#define DMX_TS_FILTERING                        1
-#define DMX_PES_FILTERING                       2
-#define DMX_SECTION_FILTERING                   4
-#define DMX_MEMORY_BASED_FILTERING              8    /* write() available */
-#define DMX_CRC_CHECKING                        16
-#define DMX_TS_DESCRAMBLING                     32
-
-/*
- * Demux resource type identifier.
-*/
-
-/*
- * DMX_FE_ENTRY(): Casts elements in the list of registered
- * front-ends from the generic type struct list_head
- * to the type * struct dmx_frontend
- *.
-*/
-
-#define DMX_FE_ENTRY(list) list_entry(list, struct dmx_frontend, connectivity_list)
-
-struct dmx_demux {
-	u32 capabilities;            /* Bitfield of capability flags */
-	struct dmx_frontend* frontend;    /* Front-end connected to the demux */
-	void* priv;                  /* Pointer to private data of the API client */
-	int (*open) (struct dmx_demux* demux);
-	int (*close) (struct dmx_demux* demux);
-	int (*write) (struct dmx_demux* demux, const char __user *buf, size_t count);
-	int (*allocate_ts_feed) (struct dmx_demux* demux,
-				 struct dmx_ts_feed** feed,
-				 dmx_ts_cb callback);
-	int (*release_ts_feed) (struct dmx_demux* demux,
-				struct dmx_ts_feed* feed);
-	int (*allocate_section_feed) (struct dmx_demux* demux,
-				      struct dmx_section_feed** feed,
-				      dmx_section_cb callback);
-	int (*release_section_feed) (struct dmx_demux* demux,
-				     struct dmx_section_feed* feed);
-	int (*add_frontend) (struct dmx_demux* demux,
-			     struct dmx_frontend* frontend);
-	int (*remove_frontend) (struct dmx_demux* demux,
-				struct dmx_frontend* frontend);
-	struct list_head* (*get_frontends) (struct dmx_demux* demux);
-	int (*connect_frontend) (struct dmx_demux* demux,
-				 struct dmx_frontend* frontend);
-	int (*disconnect_frontend) (struct dmx_demux* demux);
-
-	int (*get_pes_pids) (struct dmx_demux* demux, u16 *pids);
-
-	int (*get_caps) (struct dmx_demux* demux, struct dmx_caps *caps);
-
-	int (*set_source) (struct dmx_demux* demux, const dmx_source_t *src);
-
-	int (*get_stc) (struct dmx_demux* demux, unsigned int num,
-			u64 *stc, unsigned int *base);
-};
-
-#endif /* #ifndef __DEMUX_H */
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
deleted file mode 100644
index 73970cd..0000000
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ /dev/null
@@ -1,1277 +0,0 @@
-/*
- * dmxdev.c - DVB demultiplexer device
- *
- * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
- *		      for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- */
-
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/ioctl.h>
-#include <linux/wait.h>
-#include <asm/uaccess.h>
-#include "dmxdev.h"
-
-static int debug;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-#define dprintk	if (debug) printk
-
-static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
-				   const u8 *src, size_t len)
-{
-	ssize_t free;
-
-	if (!len)
-		return 0;
-	if (!buf->data)
-		return 0;
-
-	free = dvb_ringbuffer_free(buf);
-	if (len > free) {
-		dprintk("dmxdev: buffer overflow\n");
-		return -EOVERFLOW;
-	}
-
-	return dvb_ringbuffer_write(buf, src, len);
-}
-
-static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
-				      int non_blocking, char __user *buf,
-				      size_t count, loff_t *ppos)
-{
-	size_t todo;
-	ssize_t avail;
-	ssize_t ret = 0;
-
-	if (!src->data)
-		return 0;
-
-	if (src->error) {
-		ret = src->error;
-		dvb_ringbuffer_flush(src);
-		return ret;
-	}
-
-	for (todo = count; todo > 0; todo -= ret) {
-		if (non_blocking && dvb_ringbuffer_empty(src)) {
-			ret = -EWOULDBLOCK;
-			break;
-		}
-
-		ret = wait_event_interruptible(src->queue,
-					       !dvb_ringbuffer_empty(src) ||
-					       (src->error != 0));
-		if (ret < 0)
-			break;
-
-		if (src->error) {
-			ret = src->error;
-			dvb_ringbuffer_flush(src);
-			break;
-		}
-
-		avail = dvb_ringbuffer_avail(src);
-		if (avail > todo)
-			avail = todo;
-
-		ret = dvb_ringbuffer_read_user(src, buf, avail);
-		if (ret < 0)
-			break;
-
-		buf += ret;
-	}
-
-	return (count - todo) ? (count - todo) : ret;
-}
-
-static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type)
-{
-	struct list_head *head, *pos;
-
-	head = demux->get_frontends(demux);
-	if (!head)
-		return NULL;
-	list_for_each(pos, head)
-		if (DMX_FE_ENTRY(pos)->source == type)
-			return DMX_FE_ENTRY(pos);
-
-	return NULL;
-}
-
-static int dvb_dvr_open(struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dmxdev *dmxdev = dvbdev->priv;
-	struct dmx_frontend *front;
-
-	dprintk("function : %s\n", __func__);
-
-	if (mutex_lock_interruptible(&dmxdev->mutex))
-		return -ERESTARTSYS;
-
-	if (dmxdev->exit) {
-		mutex_unlock(&dmxdev->mutex);
-		return -ENODEV;
-	}
-
-	if ((file->f_flags & O_ACCMODE) == O_RDWR) {
-		if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
-			mutex_unlock(&dmxdev->mutex);
-			return -EOPNOTSUPP;
-		}
-	}
-
-	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
-		void *mem;
-		if (!dvbdev->readers) {
-			mutex_unlock(&dmxdev->mutex);
-			return -EBUSY;
-		}
-		mem = vmalloc(DVR_BUFFER_SIZE);
-		if (!mem) {
-			mutex_unlock(&dmxdev->mutex);
-			return -ENOMEM;
-		}
-		dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
-		dvbdev->readers--;
-	}
-
-	if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
-		dmxdev->dvr_orig_fe = dmxdev->demux->frontend;
-
-		if (!dmxdev->demux->write) {
-			mutex_unlock(&dmxdev->mutex);
-			return -EOPNOTSUPP;
-		}
-
-		front = get_fe(dmxdev->demux, DMX_MEMORY_FE);
-
-		if (!front) {
-			mutex_unlock(&dmxdev->mutex);
-			return -EINVAL;
-		}
-		dmxdev->demux->disconnect_frontend(dmxdev->demux);
-		dmxdev->demux->connect_frontend(dmxdev->demux, front);
-	}
-	dvbdev->users++;
-	mutex_unlock(&dmxdev->mutex);
-	return 0;
-}
-
-static int dvb_dvr_release(struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dmxdev *dmxdev = dvbdev->priv;
-
-	mutex_lock(&dmxdev->mutex);
-
-	if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
-		dmxdev->demux->disconnect_frontend(dmxdev->demux);
-		dmxdev->demux->connect_frontend(dmxdev->demux,
-						dmxdev->dvr_orig_fe);
-	}
-	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
-		dvbdev->readers++;
-		if (dmxdev->dvr_buffer.data) {
-			void *mem = dmxdev->dvr_buffer.data;
-			mb();
-			spin_lock_irq(&dmxdev->lock);
-			dmxdev->dvr_buffer.data = NULL;
-			spin_unlock_irq(&dmxdev->lock);
-			vfree(mem);
-		}
-	}
-	/* TODO */
-	dvbdev->users--;
-	if (dvbdev->users == 1 && dmxdev->exit == 1) {
-		fops_put(file->f_op);
-		file->f_op = NULL;
-		mutex_unlock(&dmxdev->mutex);
-		wake_up(&dvbdev->wait_queue);
-	} else
-		mutex_unlock(&dmxdev->mutex);
-
-	return 0;
-}
-
-static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
-			     size_t count, loff_t *ppos)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dmxdev *dmxdev = dvbdev->priv;
-	int ret;
-
-	if (!dmxdev->demux->write)
-		return -EOPNOTSUPP;
-	if ((file->f_flags & O_ACCMODE) != O_WRONLY)
-		return -EINVAL;
-	if (mutex_lock_interruptible(&dmxdev->mutex))
-		return -ERESTARTSYS;
-
-	if (dmxdev->exit) {
-		mutex_unlock(&dmxdev->mutex);
-		return -ENODEV;
-	}
-	ret = dmxdev->demux->write(dmxdev->demux, buf, count);
-	mutex_unlock(&dmxdev->mutex);
-	return ret;
-}
-
-static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
-			    loff_t *ppos)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dmxdev *dmxdev = dvbdev->priv;
-
-	if (dmxdev->exit)
-		return -ENODEV;
-
-	return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
-				      file->f_flags & O_NONBLOCK,
-				      buf, count, ppos);
-}
-
-static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
-				      unsigned long size)
-{
-	struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer;
-	void *newmem;
-	void *oldmem;
-
-	dprintk("function : %s\n", __func__);
-
-	if (buf->size == size)
-		return 0;
-	if (!size)
-		return -EINVAL;
-
-	newmem = vmalloc(size);
-	if (!newmem)
-		return -ENOMEM;
-
-	oldmem = buf->data;
-
-	spin_lock_irq(&dmxdev->lock);
-	buf->data = newmem;
-	buf->size = size;
-
-	/* reset and not flush in case the buffer shrinks */
-	dvb_ringbuffer_reset(buf);
-	spin_unlock_irq(&dmxdev->lock);
-
-	vfree(oldmem);
-
-	return 0;
-}
-
-static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter
-					       *dmxdevfilter, int state)
-{
-	spin_lock_irq(&dmxdevfilter->dev->lock);
-	dmxdevfilter->state = state;
-	spin_unlock_irq(&dmxdevfilter->dev->lock);
-}
-
-static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,
-				      unsigned long size)
-{
-	struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
-	void *newmem;
-	void *oldmem;
-
-	if (buf->size == size)
-		return 0;
-	if (!size)
-		return -EINVAL;
-	if (dmxdevfilter->state >= DMXDEV_STATE_GO)
-		return -EBUSY;
-
-	newmem = vmalloc(size);
-	if (!newmem)
-		return -ENOMEM;
-
-	oldmem = buf->data;
-
-	spin_lock_irq(&dmxdevfilter->dev->lock);
-	buf->data = newmem;
-	buf->size = size;
-
-	/* reset and not flush in case the buffer shrinks */
-	dvb_ringbuffer_reset(buf);
-	spin_unlock_irq(&dmxdevfilter->dev->lock);
-
-	vfree(oldmem);
-
-	return 0;
-}
-
-static void dvb_dmxdev_filter_timeout(unsigned long data)
-{
-	struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
-
-	dmxdevfilter->buffer.error = -ETIMEDOUT;
-	spin_lock_irq(&dmxdevfilter->dev->lock);
-	dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
-	spin_unlock_irq(&dmxdevfilter->dev->lock);
-	wake_up(&dmxdevfilter->buffer.queue);
-}
-
-static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
-{
-	struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec;
-
-	del_timer(&dmxdevfilter->timer);
-	if (para->timeout) {
-		dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout;
-		dmxdevfilter->timer.data = (unsigned long)dmxdevfilter;
-		dmxdevfilter->timer.expires =
-		    jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000;
-		add_timer(&dmxdevfilter->timer);
-	}
-}
-
-static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
-				       const u8 *buffer2, size_t buffer2_len,
-				       struct dmx_section_filter *filter,
-				       enum dmx_success success)
-{
-	struct dmxdev_filter *dmxdevfilter = filter->priv;
-	int ret;
-
-	if (dmxdevfilter->buffer.error) {
-		wake_up(&dmxdevfilter->buffer.queue);
-		return 0;
-	}
-	spin_lock(&dmxdevfilter->dev->lock);
-	if (dmxdevfilter->state != DMXDEV_STATE_GO) {
-		spin_unlock(&dmxdevfilter->dev->lock);
-		return 0;
-	}
-	del_timer(&dmxdevfilter->timer);
-	dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n",
-		buffer1[0], buffer1[1],
-		buffer1[2], buffer1[3], buffer1[4], buffer1[5]);
-	ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
-				      buffer1_len);
-	if (ret == buffer1_len) {
-		ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
-					      buffer2_len);
-	}
-	if (ret < 0) {
-		dvb_ringbuffer_flush(&dmxdevfilter->buffer);
-		dmxdevfilter->buffer.error = ret;
-	}
-	if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
-		dmxdevfilter->state = DMXDEV_STATE_DONE;
-	spin_unlock(&dmxdevfilter->dev->lock);
-	wake_up(&dmxdevfilter->buffer.queue);
-	return 0;
-}
-
-static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
-				  const u8 *buffer2, size_t buffer2_len,
-				  struct dmx_ts_feed *feed,
-				  enum dmx_success success)
-{
-	struct dmxdev_filter *dmxdevfilter = feed->priv;
-	struct dvb_ringbuffer *buffer;
-	int ret;
-
-	spin_lock(&dmxdevfilter->dev->lock);
-	if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
-		spin_unlock(&dmxdevfilter->dev->lock);
-		return 0;
-	}
-
-	if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
-	    || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
-		buffer = &dmxdevfilter->buffer;
-	else
-		buffer = &dmxdevfilter->dev->dvr_buffer;
-	if (buffer->error) {
-		spin_unlock(&dmxdevfilter->dev->lock);
-		wake_up(&buffer->queue);
-		return 0;
-	}
-	ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
-	if (ret == buffer1_len)
-		ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
-	if (ret < 0) {
-		dvb_ringbuffer_flush(buffer);
-		buffer->error = ret;
-	}
-	spin_unlock(&dmxdevfilter->dev->lock);
-	wake_up(&buffer->queue);
-	return 0;
-}
-
-/* stop feed but only mark the specified filter as stopped (state set) */
-static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
-{
-	struct dmxdev_feed *feed;
-
-	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
-
-	switch (dmxdevfilter->type) {
-	case DMXDEV_TYPE_SEC:
-		del_timer(&dmxdevfilter->timer);
-		dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);
-		break;
-	case DMXDEV_TYPE_PES:
-		list_for_each_entry(feed, &dmxdevfilter->feed.ts, next)
-			feed->ts->stop_filtering(feed->ts);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-/* start feed associated with the specified filter */
-static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
-{
-	struct dmxdev_feed *feed;
-	int ret;
-
-	dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
-
-	switch (filter->type) {
-	case DMXDEV_TYPE_SEC:
-		return filter->feed.sec->start_filtering(filter->feed.sec);
-	case DMXDEV_TYPE_PES:
-		list_for_each_entry(feed, &filter->feed.ts, next) {
-			ret = feed->ts->start_filtering(feed->ts);
-			if (ret < 0) {
-				dvb_dmxdev_feed_stop(filter);
-				return ret;
-			}
-		}
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-/* restart section feed if it has filters left associated with it,
-   otherwise release the feed */
-static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter)
-{
-	int i;
-	struct dmxdev *dmxdev = filter->dev;
-	u16 pid = filter->params.sec.pid;
-
-	for (i = 0; i < dmxdev->filternum; i++)
-		if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
-		    dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
-		    dmxdev->filter[i].params.sec.pid == pid) {
-			dvb_dmxdev_feed_start(&dmxdev->filter[i]);
-			return 0;
-		}
-
-	filter->dev->demux->release_section_feed(dmxdev->demux,
-						 filter->feed.sec);
-
-	return 0;
-}
-
-static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
-{
-	struct dmxdev_feed *feed;
-	struct dmx_demux *demux;
-
-	if (dmxdevfilter->state < DMXDEV_STATE_GO)
-		return 0;
-
-	switch (dmxdevfilter->type) {
-	case DMXDEV_TYPE_SEC:
-		if (!dmxdevfilter->feed.sec)
-			break;
-		dvb_dmxdev_feed_stop(dmxdevfilter);
-		if (dmxdevfilter->filter.sec)
-			dmxdevfilter->feed.sec->
-			    release_filter(dmxdevfilter->feed.sec,
-					   dmxdevfilter->filter.sec);
-		dvb_dmxdev_feed_restart(dmxdevfilter);
-		dmxdevfilter->feed.sec = NULL;
-		break;
-	case DMXDEV_TYPE_PES:
-		dvb_dmxdev_feed_stop(dmxdevfilter);
-		demux = dmxdevfilter->dev->demux;
-		list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
-			demux->release_ts_feed(demux, feed->ts);
-			feed->ts = NULL;
-		}
-		break;
-	default:
-		if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)
-			return 0;
-		return -EINVAL;
-	}
-
-	dvb_ringbuffer_flush(&dmxdevfilter->buffer);
-	return 0;
-}
-
-static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter)
-{
-	struct dmxdev_feed *feed, *tmp;
-
-	/* delete all PIDs */
-	list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) {
-		list_del(&feed->next);
-		kfree(feed);
-	}
-
-	BUG_ON(!list_empty(&dmxdevfilter->feed.ts));
-}
-
-static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)
-{
-	if (dmxdevfilter->state < DMXDEV_STATE_SET)
-		return 0;
-
-	if (dmxdevfilter->type == DMXDEV_TYPE_PES)
-		dvb_dmxdev_delete_pids(dmxdevfilter);
-
-	dmxdevfilter->type = DMXDEV_TYPE_NONE;
-	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
-	return 0;
-}
-
-static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
-				 struct dmxdev_filter *filter,
-				 struct dmxdev_feed *feed)
-{
-	struct timespec timeout = { 0 };
-	struct dmx_pes_filter_params *para = &filter->params.pes;
-	dmx_output_t otype;
-	int ret;
-	int ts_type;
-	dmx_pes_type_t ts_pes;
-	struct dmx_ts_feed *tsfeed;
-
-	feed->ts = NULL;
-	otype = para->output;
-
-	ts_pes = para->pes_type;
-
-	if (ts_pes < DMX_PES_OTHER)
-		ts_type = TS_DECODER;
-	else
-		ts_type = 0;
-
-	if (otype == DMX_OUT_TS_TAP)
-		ts_type |= TS_PACKET;
-	else if (otype == DMX_OUT_TSDEMUX_TAP)
-		ts_type |= TS_PACKET | TS_DEMUX;
-	else if (otype == DMX_OUT_TAP)
-		ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
-
-	ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts,
-					      dvb_dmxdev_ts_callback);
-	if (ret < 0)
-		return ret;
-
-	tsfeed = feed->ts;
-	tsfeed->priv = filter;
-
-	ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);
-	if (ret < 0) {
-		dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
-		return ret;
-	}
-
-	ret = tsfeed->start_filtering(tsfeed);
-	if (ret < 0) {
-		dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
-		return ret;
-	}
-
-	return 0;
-}
-
-static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
-{
-	struct dmxdev *dmxdev = filter->dev;
-	struct dmxdev_feed *feed;
-	void *mem;
-	int ret, i;
-
-	if (filter->state < DMXDEV_STATE_SET)
-		return -EINVAL;
-
-	if (filter->state >= DMXDEV_STATE_GO)
-		dvb_dmxdev_filter_stop(filter);
-
-	if (!filter->buffer.data) {
-		mem = vmalloc(filter->buffer.size);
-		if (!mem)
-			return -ENOMEM;
-		spin_lock_irq(&filter->dev->lock);
-		filter->buffer.data = mem;
-		spin_unlock_irq(&filter->dev->lock);
-	}
-
-	dvb_ringbuffer_flush(&filter->buffer);
-
-	switch (filter->type) {
-	case DMXDEV_TYPE_SEC:
-	{
-		struct dmx_sct_filter_params *para = &filter->params.sec;
-		struct dmx_section_filter **secfilter = &filter->filter.sec;
-		struct dmx_section_feed **secfeed = &filter->feed.sec;
-
-		*secfilter = NULL;
-		*secfeed = NULL;
-
-
-		/* find active filter/feed with same PID */
-		for (i = 0; i < dmxdev->filternum; i++) {
-			if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
-			    dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
-			    dmxdev->filter[i].params.sec.pid == para->pid) {
-				*secfeed = dmxdev->filter[i].feed.sec;
-				break;
-			}
-		}
-
-		/* if no feed found, try to allocate new one */
-		if (!*secfeed) {
-			ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,
-								   secfeed,
-								   dvb_dmxdev_section_callback);
-			if (ret < 0) {
-				printk("DVB (%s): could not alloc feed\n",
-				       __func__);
-				return ret;
-			}
-
-			ret = (*secfeed)->set(*secfeed, para->pid, 32768,
-					      (para->flags & DMX_CHECK_CRC) ? 1 : 0);
-			if (ret < 0) {
-				printk("DVB (%s): could not set feed\n",
-				       __func__);
-				dvb_dmxdev_feed_restart(filter);
-				return ret;
-			}
-		} else {
-			dvb_dmxdev_feed_stop(filter);
-		}
-
-		ret = (*secfeed)->allocate_filter(*secfeed, secfilter);
-		if (ret < 0) {
-			dvb_dmxdev_feed_restart(filter);
-			filter->feed.sec->start_filtering(*secfeed);
-			dprintk("could not get filter\n");
-			return ret;
-		}
-
-		(*secfilter)->priv = filter;
-
-		memcpy(&((*secfilter)->filter_value[3]),
-		       &(para->filter.filter[1]), DMX_FILTER_SIZE - 1);
-		memcpy(&(*secfilter)->filter_mask[3],
-		       &para->filter.mask[1], DMX_FILTER_SIZE - 1);
-		memcpy(&(*secfilter)->filter_mode[3],
-		       &para->filter.mode[1], DMX_FILTER_SIZE - 1);
-
-		(*secfilter)->filter_value[0] = para->filter.filter[0];
-		(*secfilter)->filter_mask[0] = para->filter.mask[0];
-		(*secfilter)->filter_mode[0] = para->filter.mode[0];
-		(*secfilter)->filter_mask[1] = 0;
-		(*secfilter)->filter_mask[2] = 0;
-
-		filter->todo = 0;
-
-		ret = filter->feed.sec->start_filtering(filter->feed.sec);
-		if (ret < 0)
-			return ret;
-
-		dvb_dmxdev_filter_timer(filter);
-		break;
-	}
-	case DMXDEV_TYPE_PES:
-		list_for_each_entry(feed, &filter->feed.ts, next) {
-			ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
-			if (ret < 0) {
-				dvb_dmxdev_filter_stop(filter);
-				return ret;
-			}
-		}
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
-	return 0;
-}
-
-static int dvb_demux_open(struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dmxdev *dmxdev = dvbdev->priv;
-	int i;
-	struct dmxdev_filter *dmxdevfilter;
-
-	if (!dmxdev->filter)
-		return -EINVAL;
-
-	if (mutex_lock_interruptible(&dmxdev->mutex))
-		return -ERESTARTSYS;
-
-	for (i = 0; i < dmxdev->filternum; i++)
-		if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
-			break;
-
-	if (i == dmxdev->filternum) {
-		mutex_unlock(&dmxdev->mutex);
-		return -EMFILE;
-	}
-
-	dmxdevfilter = &dmxdev->filter[i];
-	mutex_init(&dmxdevfilter->mutex);
-	file->private_data = dmxdevfilter;
-
-	dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
-	dmxdevfilter->type = DMXDEV_TYPE_NONE;
-	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
-	init_timer(&dmxdevfilter->timer);
-
-	dvbdev->users++;
-
-	mutex_unlock(&dmxdev->mutex);
-	return 0;
-}
-
-static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
-				  struct dmxdev_filter *dmxdevfilter)
-{
-	mutex_lock(&dmxdev->mutex);
-	mutex_lock(&dmxdevfilter->mutex);
-
-	dvb_dmxdev_filter_stop(dmxdevfilter);
-	dvb_dmxdev_filter_reset(dmxdevfilter);
-
-	if (dmxdevfilter->buffer.data) {
-		void *mem = dmxdevfilter->buffer.data;
-
-		spin_lock_irq(&dmxdev->lock);
-		dmxdevfilter->buffer.data = NULL;
-		spin_unlock_irq(&dmxdev->lock);
-		vfree(mem);
-	}
-
-	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
-	wake_up(&dmxdevfilter->buffer.queue);
-	mutex_unlock(&dmxdevfilter->mutex);
-	mutex_unlock(&dmxdev->mutex);
-	return 0;
-}
-
-static inline void invert_mode(dmx_filter_t *filter)
-{
-	int i;
-
-	for (i = 0; i < DMX_FILTER_SIZE; i++)
-		filter->mode[i] ^= 0xff;
-}
-
-static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev,
-			      struct dmxdev_filter *filter, u16 pid)
-{
-	struct dmxdev_feed *feed;
-
-	if ((filter->type != DMXDEV_TYPE_PES) ||
-	    (filter->state < DMXDEV_STATE_SET))
-		return -EINVAL;
-
-	/* only TS packet filters may have multiple PIDs */
-	if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) &&
-	    (!list_empty(&filter->feed.ts)))
-		return -EINVAL;
-
-	feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL);
-	if (feed == NULL)
-		return -ENOMEM;
-
-	feed->pid = pid;
-	list_add(&feed->next, &filter->feed.ts);
-
-	if (filter->state >= DMXDEV_STATE_GO)
-		return dvb_dmxdev_start_feed(dmxdev, filter, feed);
-
-	return 0;
-}
-
-static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,
-				  struct dmxdev_filter *filter, u16 pid)
-{
-	struct dmxdev_feed *feed, *tmp;
-
-	if ((filter->type != DMXDEV_TYPE_PES) ||
-	    (filter->state < DMXDEV_STATE_SET))
-		return -EINVAL;
-
-	list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {
-		if ((feed->pid == pid) && (feed->ts != NULL)) {
-			feed->ts->stop_filtering(feed->ts);
-			filter->dev->demux->release_ts_feed(filter->dev->demux,
-							    feed->ts);
-			list_del(&feed->next);
-			kfree(feed);
-		}
-	}
-
-	return 0;
-}
-
-static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
-				 struct dmxdev_filter *dmxdevfilter,
-				 struct dmx_sct_filter_params *params)
-{
-	dprintk("function : %s\n", __func__);
-
-	dvb_dmxdev_filter_stop(dmxdevfilter);
-
-	dmxdevfilter->type = DMXDEV_TYPE_SEC;
-	memcpy(&dmxdevfilter->params.sec,
-	       params, sizeof(struct dmx_sct_filter_params));
-	invert_mode(&dmxdevfilter->params.sec.filter);
-	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
-
-	if (params->flags & DMX_IMMEDIATE_START)
-		return dvb_dmxdev_filter_start(dmxdevfilter);
-
-	return 0;
-}
-
-static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
-				     struct dmxdev_filter *dmxdevfilter,
-				     struct dmx_pes_filter_params *params)
-{
-	int ret;
-
-	dvb_dmxdev_filter_stop(dmxdevfilter);
-	dvb_dmxdev_filter_reset(dmxdevfilter);
-
-	if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
-		return -EINVAL;
-
-	dmxdevfilter->type = DMXDEV_TYPE_PES;
-	memcpy(&dmxdevfilter->params, params,
-	       sizeof(struct dmx_pes_filter_params));
-	INIT_LIST_HEAD(&dmxdevfilter->feed.ts);
-
-	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
-
-	ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter,
-				 dmxdevfilter->params.pes.pid);
-	if (ret < 0)
-		return ret;
-
-	if (params->flags & DMX_IMMEDIATE_START)
-		return dvb_dmxdev_filter_start(dmxdevfilter);
-
-	return 0;
-}
-
-static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
-				   struct file *file, char __user *buf,
-				   size_t count, loff_t *ppos)
-{
-	int result, hcount;
-	int done = 0;
-
-	if (dfil->todo <= 0) {
-		hcount = 3 + dfil->todo;
-		if (hcount > count)
-			hcount = count;
-		result = dvb_dmxdev_buffer_read(&dfil->buffer,
-						file->f_flags & O_NONBLOCK,
-						buf, hcount, ppos);
-		if (result < 0) {
-			dfil->todo = 0;
-			return result;
-		}
-		if (copy_from_user(dfil->secheader - dfil->todo, buf, result))
-			return -EFAULT;
-		buf += result;
-		done = result;
-		count -= result;
-		dfil->todo -= result;
-		if (dfil->todo > -3)
-			return done;
-		dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff;
-		if (!count)
-			return done;
-	}
-	if (count > dfil->todo)
-		count = dfil->todo;
-	result = dvb_dmxdev_buffer_read(&dfil->buffer,
-					file->f_flags & O_NONBLOCK,
-					buf, count, ppos);
-	if (result < 0)
-		return result;
-	dfil->todo -= result;
-	return (result + done);
-}
-
-static ssize_t
-dvb_demux_read(struct file *file, char __user *buf, size_t count,
-	       loff_t *ppos)
-{
-	struct dmxdev_filter *dmxdevfilter = file->private_data;
-	int ret;
-
-	if (mutex_lock_interruptible(&dmxdevfilter->mutex))
-		return -ERESTARTSYS;
-
-	if (dmxdevfilter->type == DMXDEV_TYPE_SEC)
-		ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
-	else
-		ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
-					     file->f_flags & O_NONBLOCK,
-					     buf, count, ppos);
-
-	mutex_unlock(&dmxdevfilter->mutex);
-	return ret;
-}
-
-static int dvb_demux_do_ioctl(struct file *file,
-			      unsigned int cmd, void *parg)
-{
-	struct dmxdev_filter *dmxdevfilter = file->private_data;
-	struct dmxdev *dmxdev = dmxdevfilter->dev;
-	unsigned long arg = (unsigned long)parg;
-	int ret = 0;
-
-	if (mutex_lock_interruptible(&dmxdev->mutex))
-		return -ERESTARTSYS;
-
-	switch (cmd) {
-	case DMX_START:
-		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
-			mutex_unlock(&dmxdev->mutex);
-			return -ERESTARTSYS;
-		}
-		if (dmxdevfilter->state < DMXDEV_STATE_SET)
-			ret = -EINVAL;
-		else
-			ret = dvb_dmxdev_filter_start(dmxdevfilter);
-		mutex_unlock(&dmxdevfilter->mutex);
-		break;
-
-	case DMX_STOP:
-		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
-			mutex_unlock(&dmxdev->mutex);
-			return -ERESTARTSYS;
-		}
-		ret = dvb_dmxdev_filter_stop(dmxdevfilter);
-		mutex_unlock(&dmxdevfilter->mutex);
-		break;
-
-	case DMX_SET_FILTER:
-		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
-			mutex_unlock(&dmxdev->mutex);
-			return -ERESTARTSYS;
-		}
-		ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg);
-		mutex_unlock(&dmxdevfilter->mutex);
-		break;
-
-	case DMX_SET_PES_FILTER:
-		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
-			mutex_unlock(&dmxdev->mutex);
-			return -ERESTARTSYS;
-		}
-		ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg);
-		mutex_unlock(&dmxdevfilter->mutex);
-		break;
-
-	case DMX_SET_BUFFER_SIZE:
-		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
-			mutex_unlock(&dmxdev->mutex);
-			return -ERESTARTSYS;
-		}
-		ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);
-		mutex_unlock(&dmxdevfilter->mutex);
-		break;
-
-	case DMX_GET_PES_PIDS:
-		if (!dmxdev->demux->get_pes_pids) {
-			ret = -EINVAL;
-			break;
-		}
-		dmxdev->demux->get_pes_pids(dmxdev->demux, parg);
-		break;
-
-	case DMX_GET_CAPS:
-		if (!dmxdev->demux->get_caps) {
-			ret = -EINVAL;
-			break;
-		}
-		ret = dmxdev->demux->get_caps(dmxdev->demux, parg);
-		break;
-
-	case DMX_SET_SOURCE:
-		if (!dmxdev->demux->set_source) {
-			ret = -EINVAL;
-			break;
-		}
-		ret = dmxdev->demux->set_source(dmxdev->demux, parg);
-		break;
-
-	case DMX_GET_STC:
-		if (!dmxdev->demux->get_stc) {
-			ret = -EINVAL;
-			break;
-		}
-		ret = dmxdev->demux->get_stc(dmxdev->demux,
-					     ((struct dmx_stc *)parg)->num,
-					     &((struct dmx_stc *)parg)->stc,
-					     &((struct dmx_stc *)parg)->base);
-		break;
-
-	case DMX_ADD_PID:
-		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
-			ret = -ERESTARTSYS;
-			break;
-		}
-		ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
-		mutex_unlock(&dmxdevfilter->mutex);
-		break;
-
-	case DMX_REMOVE_PID:
-		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
-			ret = -ERESTARTSYS;
-			break;
-		}
-		ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
-		mutex_unlock(&dmxdevfilter->mutex);
-		break;
-
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	mutex_unlock(&dmxdev->mutex);
-	return ret;
-}
-
-static long dvb_demux_ioctl(struct file *file, unsigned int cmd,
-			    unsigned long arg)
-{
-	return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl);
-}
-
-static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
-{
-	struct dmxdev_filter *dmxdevfilter = file->private_data;
-	unsigned int mask = 0;
-
-	if (!dmxdevfilter)
-		return -EINVAL;
-
-	poll_wait(file, &dmxdevfilter->buffer.queue, wait);
-
-	if (dmxdevfilter->state != DMXDEV_STATE_GO &&
-	    dmxdevfilter->state != DMXDEV_STATE_DONE &&
-	    dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT)
-		return 0;
-
-	if (dmxdevfilter->buffer.error)
-		mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
-
-	if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
-		mask |= (POLLIN | POLLRDNORM | POLLPRI);
-
-	return mask;
-}
-
-static int dvb_demux_release(struct inode *inode, struct file *file)
-{
-	struct dmxdev_filter *dmxdevfilter = file->private_data;
-	struct dmxdev *dmxdev = dmxdevfilter->dev;
-
-	int ret;
-
-	ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
-
-	mutex_lock(&dmxdev->mutex);
-	dmxdev->dvbdev->users--;
-	if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) {
-		fops_put(file->f_op);
-		file->f_op = NULL;
-		mutex_unlock(&dmxdev->mutex);
-		wake_up(&dmxdev->dvbdev->wait_queue);
-	} else
-		mutex_unlock(&dmxdev->mutex);
-
-	return ret;
-}
-
-static const struct file_operations dvb_demux_fops = {
-	.owner = THIS_MODULE,
-	.read = dvb_demux_read,
-	.unlocked_ioctl = dvb_demux_ioctl,
-	.open = dvb_demux_open,
-	.release = dvb_demux_release,
-	.poll = dvb_demux_poll,
-	.llseek = default_llseek,
-};
-
-static struct dvb_device dvbdev_demux = {
-	.priv = NULL,
-	.users = 1,
-	.writers = 1,
-	.fops = &dvb_demux_fops
-};
-
-static int dvb_dvr_do_ioctl(struct file *file,
-			    unsigned int cmd, void *parg)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dmxdev *dmxdev = dvbdev->priv;
-	unsigned long arg = (unsigned long)parg;
-	int ret;
-
-	if (mutex_lock_interruptible(&dmxdev->mutex))
-		return -ERESTARTSYS;
-
-	switch (cmd) {
-	case DMX_SET_BUFFER_SIZE:
-		ret = dvb_dvr_set_buffer_size(dmxdev, arg);
-		break;
-
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	mutex_unlock(&dmxdev->mutex);
-	return ret;
-}
-
-static long dvb_dvr_ioctl(struct file *file,
-			 unsigned int cmd, unsigned long arg)
-{
-	return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl);
-}
-
-static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dmxdev *dmxdev = dvbdev->priv;
-	unsigned int mask = 0;
-
-	dprintk("function : %s\n", __func__);
-
-	poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
-
-	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
-		if (dmxdev->dvr_buffer.error)
-			mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
-
-		if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
-			mask |= (POLLIN | POLLRDNORM | POLLPRI);
-	} else
-		mask |= (POLLOUT | POLLWRNORM | POLLPRI);
-
-	return mask;
-}
-
-static const struct file_operations dvb_dvr_fops = {
-	.owner = THIS_MODULE,
-	.read = dvb_dvr_read,
-	.write = dvb_dvr_write,
-	.unlocked_ioctl = dvb_dvr_ioctl,
-	.open = dvb_dvr_open,
-	.release = dvb_dvr_release,
-	.poll = dvb_dvr_poll,
-	.llseek = default_llseek,
-};
-
-static struct dvb_device dvbdev_dvr = {
-	.priv = NULL,
-	.readers = 1,
-	.users = 1,
-	.fops = &dvb_dvr_fops
-};
-
-int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
-{
-	int i;
-
-	if (dmxdev->demux->open(dmxdev->demux) < 0)
-		return -EUSERS;
-
-	dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter));
-	if (!dmxdev->filter)
-		return -ENOMEM;
-
-	mutex_init(&dmxdev->mutex);
-	spin_lock_init(&dmxdev->lock);
-	for (i = 0; i < dmxdev->filternum; i++) {
-		dmxdev->filter[i].dev = dmxdev;
-		dmxdev->filter[i].buffer.data = NULL;
-		dvb_dmxdev_filter_state_set(&dmxdev->filter[i],
-					    DMXDEV_STATE_FREE);
-	}
-
-	dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
-			    DVB_DEVICE_DEMUX);
-	dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
-			    dmxdev, DVB_DEVICE_DVR);
-
-	dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
-
-	return 0;
-}
-
-EXPORT_SYMBOL(dvb_dmxdev_init);
-
-void dvb_dmxdev_release(struct dmxdev *dmxdev)
-{
-	dmxdev->exit=1;
-	if (dmxdev->dvbdev->users > 1) {
-		wait_event(dmxdev->dvbdev->wait_queue,
-				dmxdev->dvbdev->users==1);
-	}
-	if (dmxdev->dvr_dvbdev->users > 1) {
-		wait_event(dmxdev->dvr_dvbdev->wait_queue,
-				dmxdev->dvr_dvbdev->users==1);
-	}
-
-	dvb_unregister_device(dmxdev->dvbdev);
-	dvb_unregister_device(dmxdev->dvr_dvbdev);
-
-	vfree(dmxdev->filter);
-	dmxdev->filter = NULL;
-	dmxdev->demux->close(dmxdev->demux);
-}
-
-EXPORT_SYMBOL(dvb_dmxdev_release);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
deleted file mode 100644
index 02ebe28..0000000
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * dmxdev.h
- *
- * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
- *                    for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- */
-
-#ifndef _DMXDEV_H_
-#define _DMXDEV_H_
-
-#include <linux/types.h>
-#include <linux/spinlock.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-
-#include <linux/dvb/dmx.h>
-
-#include "dvbdev.h"
-#include "demux.h"
-#include "dvb_ringbuffer.h"
-
-enum dmxdev_type {
-	DMXDEV_TYPE_NONE,
-	DMXDEV_TYPE_SEC,
-	DMXDEV_TYPE_PES,
-};
-
-enum dmxdev_state {
-	DMXDEV_STATE_FREE,
-	DMXDEV_STATE_ALLOCATED,
-	DMXDEV_STATE_SET,
-	DMXDEV_STATE_GO,
-	DMXDEV_STATE_DONE,
-	DMXDEV_STATE_TIMEDOUT
-};
-
-struct dmxdev_feed {
-	u16 pid;
-	struct dmx_ts_feed *ts;
-	struct list_head next;
-};
-
-struct dmxdev_filter {
-	union {
-		struct dmx_section_filter *sec;
-	} filter;
-
-	union {
-		/* list of TS and PES feeds (struct dmxdev_feed) */
-		struct list_head ts;
-		struct dmx_section_feed *sec;
-	} feed;
-
-	union {
-		struct dmx_sct_filter_params sec;
-		struct dmx_pes_filter_params pes;
-	} params;
-
-	enum dmxdev_type type;
-	enum dmxdev_state state;
-	struct dmxdev *dev;
-	struct dvb_ringbuffer buffer;
-
-	struct mutex mutex;
-
-	/* only for sections */
-	struct timer_list timer;
-	int todo;
-	u8 secheader[3];
-};
-
-
-struct dmxdev {
-	struct dvb_device *dvbdev;
-	struct dvb_device *dvr_dvbdev;
-
-	struct dmxdev_filter *filter;
-	struct dmx_demux *demux;
-
-	int filternum;
-	int capabilities;
-
-	unsigned int exit:1;
-#define DMXDEV_CAP_DUPLEX 1
-	struct dmx_frontend *dvr_orig_fe;
-
-	struct dvb_ringbuffer dvr_buffer;
-#define DVR_BUFFER_SIZE (10*188*1024)
-
-	struct mutex mutex;
-	spinlock_t lock;
-};
-
-
-int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *);
-void dvb_dmxdev_release(struct dmxdev *dmxdev);
-
-#endif /* _DMXDEV_H_ */
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
deleted file mode 100644
index 9be65a3..0000000
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ /dev/null
@@ -1,1753 +0,0 @@
-/*
- * dvb_ca.c: generic DVB functions for EN50221 CAM interfaces
- *
- * Copyright (C) 2004 Andrew de Quincey
- *
- * Parts of this file were based on sources as follows:
- *
- * Copyright (C) 2003 Ralph Metzler <rjkm@metzlerbros.de>
- *
- * based on code:
- *
- * Copyright (C) 1999-2002 Ralph  Metzler
- *                       & Marcus Metzler for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/kthread.h>
-
-#include "dvb_ca_en50221.h"
-#include "dvb_ringbuffer.h"
-
-static int dvb_ca_en50221_debug;
-
-module_param_named(cam_debug, dvb_ca_en50221_debug, int, 0644);
-MODULE_PARM_DESC(cam_debug, "enable verbose debug messages");
-
-#define dprintk if (dvb_ca_en50221_debug) printk
-
-#define INIT_TIMEOUT_SECS 10
-
-#define HOST_LINK_BUF_SIZE 0x200
-
-#define RX_BUFFER_SIZE 65535
-
-#define MAX_RX_PACKETS_PER_ITERATION 10
-
-#define CTRLIF_DATA      0
-#define CTRLIF_COMMAND   1
-#define CTRLIF_STATUS    1
-#define CTRLIF_SIZE_LOW  2
-#define CTRLIF_SIZE_HIGH 3
-
-#define CMDREG_HC        1	/* Host control */
-#define CMDREG_SW        2	/* Size write */
-#define CMDREG_SR        4	/* Size read */
-#define CMDREG_RS        8	/* Reset interface */
-#define CMDREG_FRIE   0x40	/* Enable FR interrupt */
-#define CMDREG_DAIE   0x80	/* Enable DA interrupt */
-#define IRQEN (CMDREG_DAIE)
-
-#define STATUSREG_RE     1	/* read error */
-#define STATUSREG_WE     2	/* write error */
-#define STATUSREG_FR  0x40	/* module free */
-#define STATUSREG_DA  0x80	/* data available */
-#define STATUSREG_TXERR (STATUSREG_RE|STATUSREG_WE)	/* general transfer error */
-
-
-#define DVB_CA_SLOTSTATE_NONE           0
-#define DVB_CA_SLOTSTATE_UNINITIALISED  1
-#define DVB_CA_SLOTSTATE_RUNNING        2
-#define DVB_CA_SLOTSTATE_INVALID        3
-#define DVB_CA_SLOTSTATE_WAITREADY      4
-#define DVB_CA_SLOTSTATE_VALIDATE       5
-#define DVB_CA_SLOTSTATE_WAITFR         6
-#define DVB_CA_SLOTSTATE_LINKINIT       7
-
-
-/* Information on a CA slot */
-struct dvb_ca_slot {
-
-	/* current state of the CAM */
-	int slot_state;
-
-	/* mutex used for serializing access to one CI slot */
-	struct mutex slot_lock;
-
-	/* Number of CAMCHANGES that have occurred since last processing */
-	atomic_t camchange_count;
-
-	/* Type of last CAMCHANGE */
-	int camchange_type;
-
-	/* base address of CAM config */
-	u32 config_base;
-
-	/* value to write into Config Control register */
-	u8 config_option;
-
-	/* if 1, the CAM supports DA IRQs */
-	u8 da_irq_supported:1;
-
-	/* size of the buffer to use when talking to the CAM */
-	int link_buf_size;
-
-	/* buffer for incoming packets */
-	struct dvb_ringbuffer rx_buffer;
-
-	/* timer used during various states of the slot */
-	unsigned long timeout;
-};
-
-/* Private CA-interface information */
-struct dvb_ca_private {
-
-	/* pointer back to the public data structure */
-	struct dvb_ca_en50221 *pub;
-
-	/* the DVB device */
-	struct dvb_device *dvbdev;
-
-	/* Flags describing the interface (DVB_CA_FLAG_*) */
-	u32 flags;
-
-	/* number of slots supported by this CA interface */
-	unsigned int slot_count;
-
-	/* information on each slot */
-	struct dvb_ca_slot *slot_info;
-
-	/* wait queues for read() and write() operations */
-	wait_queue_head_t wait_queue;
-
-	/* PID of the monitoring thread */
-	struct task_struct *thread;
-
-	/* Flag indicating if the CA device is open */
-	unsigned int open:1;
-
-	/* Flag indicating the thread should wake up now */
-	unsigned int wakeup:1;
-
-	/* Delay the main thread should use */
-	unsigned long delay;
-
-	/* Slot to start looking for data to read from in the next user-space read operation */
-	int next_read_slot;
-};
-
-static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca);
-static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount);
-static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount);
-
-
-/**
- * Safely find needle in haystack.
- *
- * @param haystack Buffer to look in.
- * @param hlen Number of bytes in haystack.
- * @param needle Buffer to find.
- * @param nlen Number of bytes in needle.
- * @return Pointer into haystack needle was found at, or NULL if not found.
- */
-static char *findstr(char * haystack, int hlen, char * needle, int nlen)
-{
-	int i;
-
-	if (hlen < nlen)
-		return NULL;
-
-	for (i = 0; i <= hlen - nlen; i++) {
-		if (!strncmp(haystack + i, needle, nlen))
-			return haystack + i;
-	}
-
-	return NULL;
-}
-
-
-
-/* ******************************************************************************** */
-/* EN50221 physical interface functions */
-
-
-/**
- * Check CAM status.
- */
-static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot)
-{
-	int slot_status;
-	int cam_present_now;
-	int cam_changed;
-
-	/* IRQ mode */
-	if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) {
-		return (atomic_read(&ca->slot_info[slot].camchange_count) != 0);
-	}
-
-	/* poll mode */
-	slot_status = ca->pub->poll_slot_status(ca->pub, slot, ca->open);
-
-	cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1 : 0;
-	cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1 : 0;
-	if (!cam_changed) {
-		int cam_present_old = (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE);
-		cam_changed = (cam_present_now != cam_present_old);
-	}
-
-	if (cam_changed) {
-		if (!cam_present_now) {
-			ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
-		} else {
-			ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_INSERTED;
-		}
-		atomic_set(&ca->slot_info[slot].camchange_count, 1);
-	} else {
-		if ((ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) &&
-		    (slot_status & DVB_CA_EN50221_POLL_CAM_READY)) {
-			// move to validate state if reset is completed
-			ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;
-		}
-	}
-
-	return cam_changed;
-}
-
-
-/**
- * Wait for flags to become set on the STATUS register on a CAM interface,
- * checking for errors and timeout.
- *
- * @param ca CA instance.
- * @param slot Slot on interface.
- * @param waitfor Flags to wait for.
- * @param timeout_ms Timeout in milliseconds.
- *
- * @return 0 on success, nonzero on error.
- */
-static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot,
-					 u8 waitfor, int timeout_hz)
-{
-	unsigned long timeout;
-	unsigned long start;
-
-	dprintk("%s\n", __func__);
-
-	/* loop until timeout elapsed */
-	start = jiffies;
-	timeout = jiffies + timeout_hz;
-	while (1) {
-		/* read the status and check for error */
-		int res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
-		if (res < 0)
-			return -EIO;
-
-		/* if we got the flags, it was successful! */
-		if (res & waitfor) {
-			dprintk("%s succeeded timeout:%lu\n", __func__, jiffies - start);
-			return 0;
-		}
-
-		/* check for timeout */
-		if (time_after(jiffies, timeout)) {
-			break;
-		}
-
-		/* wait for a bit */
-		msleep(1);
-	}
-
-	dprintk("%s failed timeout:%lu\n", __func__, jiffies - start);
-
-	/* if we get here, we've timed out */
-	return -ETIMEDOUT;
-}
-
-
-/**
- * Initialise the link layer connection to a CAM.
- *
- * @param ca CA instance.
- * @param slot Slot id.
- *
- * @return 0 on success, nonzero on failure.
- */
-static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
-{
-	int ret;
-	int buf_size;
-	u8 buf[2];
-
-	dprintk("%s\n", __func__);
-
-	/* we'll be determining these during this function */
-	ca->slot_info[slot].da_irq_supported = 0;
-
-	/* set the host link buffer size temporarily. it will be overwritten with the
-	 * real negotiated size later. */
-	ca->slot_info[slot].link_buf_size = 2;
-
-	/* read the buffer size from the CAM */
-	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0)
-		return ret;
-	if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ / 10)) != 0)
-		return ret;
-	if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2)
-		return -EIO;
-	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0)
-		return ret;
-
-	/* store it, and choose the minimum of our buffer and the CAM's buffer size */
-	buf_size = (buf[0] << 8) | buf[1];
-	if (buf_size > HOST_LINK_BUF_SIZE)
-		buf_size = HOST_LINK_BUF_SIZE;
-	ca->slot_info[slot].link_buf_size = buf_size;
-	buf[0] = buf_size >> 8;
-	buf[1] = buf_size & 0xff;
-	dprintk("Chosen link buffer size of %i\n", buf_size);
-
-	/* write the buffer size to the CAM */
-	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SW)) != 0)
-		return ret;
-	if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10)) != 0)
-		return ret;
-	if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2)
-		return -EIO;
-	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0)
-		return ret;
-
-	/* success */
-	return 0;
-}
-
-/**
- * Read a tuple from attribute memory.
- *
- * @param ca CA instance.
- * @param slot Slot id.
- * @param address Address to read from. Updated.
- * @param tupleType Tuple id byte. Updated.
- * @param tupleLength Tuple length. Updated.
- * @param tuple Dest buffer for tuple (must be 256 bytes). Updated.
- *
- * @return 0 on success, nonzero on error.
- */
-static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot,
-				     int *address, int *tupleType, int *tupleLength, u8 * tuple)
-{
-	int i;
-	int _tupleType;
-	int _tupleLength;
-	int _address = *address;
-
-	/* grab the next tuple length and type */
-	if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0)
-		return _tupleType;
-	if (_tupleType == 0xff) {
-		dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType);
-		*address += 2;
-		*tupleType = _tupleType;
-		*tupleLength = 0;
-		return 0;
-	}
-	if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address + 2)) < 0)
-		return _tupleLength;
-	_address += 4;
-
-	dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength);
-
-	/* read in the whole tuple */
-	for (i = 0; i < _tupleLength; i++) {
-		tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, _address + (i * 2));
-		dprintk("  0x%02x: 0x%02x %c\n",
-			i, tuple[i] & 0xff,
-			((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.');
-	}
-	_address += (_tupleLength * 2);
-
-	// success
-	*tupleType = _tupleType;
-	*tupleLength = _tupleLength;
-	*address = _address;
-	return 0;
-}
-
-
-/**
- * Parse attribute memory of a CAM module, extracting Config register, and checking
- * it is a DVB CAM module.
- *
- * @param ca CA instance.
- * @param slot Slot id.
- *
- * @return 0 on success, <0 on failure.
- */
-static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
-{
-	int address = 0;
-	int tupleLength;
-	int tupleType;
-	u8 tuple[257];
-	char *dvb_str;
-	int rasz;
-	int status;
-	int got_cftableentry = 0;
-	int end_chain = 0;
-	int i;
-	u16 manfid = 0;
-	u16 devid = 0;
-
-
-	// CISTPL_DEVICE_0A
-	if ((status =
-	     dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
-		return status;
-	if (tupleType != 0x1D)
-		return -EINVAL;
-
-
-
-	// CISTPL_DEVICE_0C
-	if ((status =
-	     dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
-		return status;
-	if (tupleType != 0x1C)
-		return -EINVAL;
-
-
-
-	// CISTPL_VERS_1
-	if ((status =
-	     dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
-		return status;
-	if (tupleType != 0x15)
-		return -EINVAL;
-
-
-
-	// CISTPL_MANFID
-	if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
-						&tupleLength, tuple)) < 0)
-		return status;
-	if (tupleType != 0x20)
-		return -EINVAL;
-	if (tupleLength != 4)
-		return -EINVAL;
-	manfid = (tuple[1] << 8) | tuple[0];
-	devid = (tuple[3] << 8) | tuple[2];
-
-
-
-	// CISTPL_CONFIG
-	if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
-						&tupleLength, tuple)) < 0)
-		return status;
-	if (tupleType != 0x1A)
-		return -EINVAL;
-	if (tupleLength < 3)
-		return -EINVAL;
-
-	/* extract the configbase */
-	rasz = tuple[0] & 3;
-	if (tupleLength < (3 + rasz + 14))
-		return -EINVAL;
-	ca->slot_info[slot].config_base = 0;
-	for (i = 0; i < rasz + 1; i++) {
-		ca->slot_info[slot].config_base |= (tuple[2 + i] << (8 * i));
-	}
-
-	/* check it contains the correct DVB string */
-	dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8);
-	if (dvb_str == NULL)
-		return -EINVAL;
-	if (tupleLength < ((dvb_str - (char *) tuple) + 12))
-		return -EINVAL;
-
-	/* is it a version we support? */
-	if (strncmp(dvb_str + 8, "1.00", 4)) {
-		printk("dvb_ca adapter %d: Unsupported DVB CAM module version %c%c%c%c\n",
-		       ca->dvbdev->adapter->num, dvb_str[8], dvb_str[9], dvb_str[10], dvb_str[11]);
-		return -EINVAL;
-	}
-
-	/* process the CFTABLE_ENTRY tuples, and any after those */
-	while ((!end_chain) && (address < 0x1000)) {
-		if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
-							&tupleLength, tuple)) < 0)
-			return status;
-		switch (tupleType) {
-		case 0x1B:	// CISTPL_CFTABLE_ENTRY
-			if (tupleLength < (2 + 11 + 17))
-				break;
-
-			/* if we've already parsed one, just use it */
-			if (got_cftableentry)
-				break;
-
-			/* get the config option */
-			ca->slot_info[slot].config_option = tuple[0] & 0x3f;
-
-			/* OK, check it contains the correct strings */
-			if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
-			    (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
-				break;
-
-			got_cftableentry = 1;
-			break;
-
-		case 0x14:	// CISTPL_NO_LINK
-			break;
-
-		case 0xFF:	// CISTPL_END
-			end_chain = 1;
-			break;
-
-		default:	/* Unknown tuple type - just skip this tuple and move to the next one */
-			dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", tupleType,
-				tupleLength);
-			break;
-		}
-	}
-
-	if ((address > 0x1000) || (!got_cftableentry))
-		return -EINVAL;
-
-	dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n",
-		manfid, devid, ca->slot_info[slot].config_base, ca->slot_info[slot].config_option);
-
-	// success!
-	return 0;
-}
-
-
-/**
- * Set CAM's configoption correctly.
- *
- * @param ca CA instance.
- * @param slot Slot containing the CAM.
- */
-static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot)
-{
-	int configoption;
-
-	dprintk("%s\n", __func__);
-
-	/* set the config option */
-	ca->pub->write_attribute_mem(ca->pub, slot,
-				     ca->slot_info[slot].config_base,
-				     ca->slot_info[slot].config_option);
-
-	/* check it */
-	configoption = ca->pub->read_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base);
-	dprintk("Set configoption 0x%x, read configoption 0x%x\n",
-		ca->slot_info[slot].config_option, configoption & 0x3f);
-
-	/* fine! */
-	return 0;
-
-}
-
-
-/**
- * This function talks to an EN50221 CAM control interface. It reads a buffer of
- * data from the CAM. The data can either be stored in a supplied buffer, or
- * automatically be added to the slot's rx_buffer.
- *
- * @param ca CA instance.
- * @param slot Slot to read from.
- * @param ebuf If non-NULL, the data will be written to this buffer. If NULL,
- * the data will be added into the buffering system as a normal fragment.
- * @param ecount Size of ebuf. Ignored if ebuf is NULL.
- *
- * @return Number of bytes read, or < 0 on error
- */
-static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount)
-{
-	int bytes_read;
-	int status;
-	u8 buf[HOST_LINK_BUF_SIZE];
-	int i;
-
-	dprintk("%s\n", __func__);
-
-	/* check if we have space for a link buf in the rx_buffer */
-	if (ebuf == NULL) {
-		int buf_free;
-
-		if (ca->slot_info[slot].rx_buffer.data == NULL) {
-			status = -EIO;
-			goto exit;
-		}
-		buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer);
-
-		if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) {
-			status = -EAGAIN;
-			goto exit;
-		}
-	}
-
-	/* check if there is data available */
-	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
-		goto exit;
-	if (!(status & STATUSREG_DA)) {
-		/* no data */
-		status = 0;
-		goto exit;
-	}
-
-	/* read the amount of data */
-	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0)
-		goto exit;
-	bytes_read = status << 8;
-	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0)
-		goto exit;
-	bytes_read |= status;
-
-	/* check it will fit */
-	if (ebuf == NULL) {
-		if (bytes_read > ca->slot_info[slot].link_buf_size) {
-			printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n",
-			       ca->dvbdev->adapter->num, bytes_read, ca->slot_info[slot].link_buf_size);
-			ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-			status = -EIO;
-			goto exit;
-		}
-		if (bytes_read < 2) {
-			printk("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n",
-			       ca->dvbdev->adapter->num);
-			ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-			status = -EIO;
-			goto exit;
-		}
-	} else {
-		if (bytes_read > ecount) {
-			printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n",
-			       ca->dvbdev->adapter->num);
-			status = -EIO;
-			goto exit;
-		}
-	}
-
-	/* fill the buffer */
-	for (i = 0; i < bytes_read; i++) {
-		/* read byte and check */
-		if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0)
-			goto exit;
-
-		/* OK, store it in the buffer */
-		buf[i] = status;
-	}
-
-	/* check for read error (RE should now be 0) */
-	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
-		goto exit;
-	if (status & STATUSREG_RE) {
-		ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-		status = -EIO;
-		goto exit;
-	}
-
-	/* OK, add it to the receive buffer, or copy into external buffer if supplied */
-	if (ebuf == NULL) {
-		if (ca->slot_info[slot].rx_buffer.data == NULL) {
-			status = -EIO;
-			goto exit;
-		}
-		dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read);
-	} else {
-		memcpy(ebuf, buf, bytes_read);
-	}
-
-	dprintk("Received CA packet for slot %i connection id 0x%x last_frag:%i size:0x%x\n", slot,
-		buf[0], (buf[1] & 0x80) == 0, bytes_read);
-
-	/* wake up readers when a last_fragment is received */
-	if ((buf[1] & 0x80) == 0x00) {
-		wake_up_interruptible(&ca->wait_queue);
-	}
-	status = bytes_read;
-
-exit:
-	return status;
-}
-
-
-/**
- * This function talks to an EN50221 CAM control interface. It writes a buffer of data
- * to a CAM.
- *
- * @param ca CA instance.
- * @param slot Slot to write to.
- * @param ebuf The data in this buffer is treated as a complete link-level packet to
- * be written.
- * @param count Size of ebuf.
- *
- * @return Number of bytes written, or < 0 on error.
- */
-static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * buf, int bytes_write)
-{
-	int status;
-	int i;
-
-	dprintk("%s\n", __func__);
-
-
-	/* sanity check */
-	if (bytes_write > ca->slot_info[slot].link_buf_size)
-		return -EINVAL;
-
-	/* it is possible we are dealing with a single buffer implementation,
-	   thus if there is data available for read or if there is even a read
-	   already in progress, we do nothing but awake the kernel thread to
-	   process the data if necessary. */
-	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
-		goto exitnowrite;
-	if (status & (STATUSREG_DA | STATUSREG_RE)) {
-		if (status & STATUSREG_DA)
-			dvb_ca_en50221_thread_wakeup(ca);
-
-		status = -EAGAIN;
-		goto exitnowrite;
-	}
-
-	/* OK, set HC bit */
-	if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
-						 IRQEN | CMDREG_HC)) != 0)
-		goto exit;
-
-	/* check if interface is still free */
-	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
-		goto exit;
-	if (!(status & STATUSREG_FR)) {
-		/* it wasn't free => try again later */
-		status = -EAGAIN;
-		goto exit;
-	}
-
-	/* send the amount of data */
-	if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0)
-		goto exit;
-	if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW,
-						 bytes_write & 0xff)) != 0)
-		goto exit;
-
-	/* send the buffer */
-	for (i = 0; i < bytes_write; i++) {
-		if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, buf[i])) != 0)
-			goto exit;
-	}
-
-	/* check for write error (WE should now be 0) */
-	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
-		goto exit;
-	if (status & STATUSREG_WE) {
-		ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-		status = -EIO;
-		goto exit;
-	}
-	status = bytes_write;
-
-	dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i size:0x%x\n", slot,
-		buf[0], (buf[1] & 0x80) == 0, bytes_write);
-
-exit:
-	ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
-
-exitnowrite:
-	return status;
-}
-EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq);
-
-
-
-/* ******************************************************************************** */
-/* EN50221 higher level functions */
-
-
-/**
- * A CAM has been removed => shut it down.
- *
- * @param ca CA instance.
- * @param slot Slot to shut down.
- */
-static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot)
-{
-	dprintk("%s\n", __func__);
-
-	ca->pub->slot_shutdown(ca->pub, slot);
-	ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
-
-	/* need to wake up all processes to check if they're now
-	   trying to write to a defunct CAM */
-	wake_up_interruptible(&ca->wait_queue);
-
-	dprintk("Slot %i shutdown\n", slot);
-
-	/* success */
-	return 0;
-}
-EXPORT_SYMBOL(dvb_ca_en50221_camready_irq);
-
-
-/**
- * A CAMCHANGE IRQ has occurred.
- *
- * @param ca CA instance.
- * @param slot Slot concerned.
- * @param change_type One of the DVB_CA_CAMCHANGE_* values.
- */
-void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot, int change_type)
-{
-	struct dvb_ca_private *ca = pubca->private;
-
-	dprintk("CAMCHANGE IRQ slot:%i change_type:%i\n", slot, change_type);
-
-	switch (change_type) {
-	case DVB_CA_EN50221_CAMCHANGE_REMOVED:
-	case DVB_CA_EN50221_CAMCHANGE_INSERTED:
-		break;
-
-	default:
-		return;
-	}
-
-	ca->slot_info[slot].camchange_type = change_type;
-	atomic_inc(&ca->slot_info[slot].camchange_count);
-	dvb_ca_en50221_thread_wakeup(ca);
-}
-EXPORT_SYMBOL(dvb_ca_en50221_frda_irq);
-
-
-/**
- * A CAMREADY IRQ has occurred.
- *
- * @param ca CA instance.
- * @param slot Slot concerned.
- */
-void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot)
-{
-	struct dvb_ca_private *ca = pubca->private;
-
-	dprintk("CAMREADY IRQ slot:%i\n", slot);
-
-	if (ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) {
-		ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;
-		dvb_ca_en50221_thread_wakeup(ca);
-	}
-}
-
-
-/**
- * An FR or DA IRQ has occurred.
- *
- * @param ca CA instance.
- * @param slot Slot concerned.
- */
-void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot)
-{
-	struct dvb_ca_private *ca = pubca->private;
-	int flags;
-
-	dprintk("FR/DA IRQ slot:%i\n", slot);
-
-	switch (ca->slot_info[slot].slot_state) {
-	case DVB_CA_SLOTSTATE_LINKINIT:
-		flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS);
-		if (flags & STATUSREG_DA) {
-			dprintk("CAM supports DA IRQ\n");
-			ca->slot_info[slot].da_irq_supported = 1;
-		}
-		break;
-
-	case DVB_CA_SLOTSTATE_RUNNING:
-		if (ca->open)
-			dvb_ca_en50221_thread_wakeup(ca);
-		break;
-	}
-}
-
-
-
-/* ******************************************************************************** */
-/* EN50221 thread functions */
-
-/**
- * Wake up the DVB CA thread
- *
- * @param ca CA instance.
- */
-static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca)
-{
-
-	dprintk("%s\n", __func__);
-
-	ca->wakeup = 1;
-	mb();
-	wake_up_process(ca->thread);
-}
-
-/**
- * Update the delay used by the thread.
- *
- * @param ca CA instance.
- */
-static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
-{
-	int delay;
-	int curdelay = 100000000;
-	int slot;
-
-	/* Beware of too high polling frequency, because one polling
-	 * call might take several hundred milliseconds until timeout!
-	 */
-	for (slot = 0; slot < ca->slot_count; slot++) {
-		switch (ca->slot_info[slot].slot_state) {
-		default:
-		case DVB_CA_SLOTSTATE_NONE:
-			delay = HZ * 60;  /* 60s */
-			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
-				delay = HZ * 5;  /* 5s */
-			break;
-		case DVB_CA_SLOTSTATE_INVALID:
-			delay = HZ * 60;  /* 60s */
-			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
-				delay = HZ / 10;  /* 100ms */
-			break;
-
-		case DVB_CA_SLOTSTATE_UNINITIALISED:
-		case DVB_CA_SLOTSTATE_WAITREADY:
-		case DVB_CA_SLOTSTATE_VALIDATE:
-		case DVB_CA_SLOTSTATE_WAITFR:
-		case DVB_CA_SLOTSTATE_LINKINIT:
-			delay = HZ / 10;  /* 100ms */
-			break;
-
-		case DVB_CA_SLOTSTATE_RUNNING:
-			delay = HZ * 60;  /* 60s */
-			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
-				delay = HZ / 10;  /* 100ms */
-			if (ca->open) {
-				if ((!ca->slot_info[slot].da_irq_supported) ||
-				    (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA)))
-					delay = HZ / 10;  /* 100ms */
-			}
-			break;
-		}
-
-		if (delay < curdelay)
-			curdelay = delay;
-	}
-
-	ca->delay = curdelay;
-}
-
-
-
-/**
- * Kernel thread which monitors CA slots for CAM changes, and performs data transfers.
- */
-static int dvb_ca_en50221_thread(void *data)
-{
-	struct dvb_ca_private *ca = data;
-	int slot;
-	int flags;
-	int status;
-	int pktcount;
-	void *rxbuf;
-
-	dprintk("%s\n", __func__);
-
-	/* choose the correct initial delay */
-	dvb_ca_en50221_thread_update_delay(ca);
-
-	/* main loop */
-	while (!kthread_should_stop()) {
-		/* sleep for a bit */
-		if (!ca->wakeup) {
-			set_current_state(TASK_INTERRUPTIBLE);
-			schedule_timeout(ca->delay);
-			if (kthread_should_stop())
-				return 0;
-		}
-		ca->wakeup = 0;
-
-		/* go through all the slots processing them */
-		for (slot = 0; slot < ca->slot_count; slot++) {
-
-			mutex_lock(&ca->slot_info[slot].slot_lock);
-
-			// check the cam status + deal with CAMCHANGEs
-			while (dvb_ca_en50221_check_camstatus(ca, slot)) {
-				/* clear down an old CI slot if necessary */
-				if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE)
-					dvb_ca_en50221_slot_shutdown(ca, slot);
-
-				/* if a CAM is NOW present, initialise it */
-				if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) {
-					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_UNINITIALISED;
-				}
-
-				/* we've handled one CAMCHANGE */
-				dvb_ca_en50221_thread_update_delay(ca);
-				atomic_dec(&ca->slot_info[slot].camchange_count);
-			}
-
-			// CAM state machine
-			switch (ca->slot_info[slot].slot_state) {
-			case DVB_CA_SLOTSTATE_NONE:
-			case DVB_CA_SLOTSTATE_INVALID:
-				// no action needed
-				break;
-
-			case DVB_CA_SLOTSTATE_UNINITIALISED:
-				ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITREADY;
-				ca->pub->slot_reset(ca->pub, slot);
-				ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
-				break;
-
-			case DVB_CA_SLOTSTATE_WAITREADY:
-				if (time_after(jiffies, ca->slot_info[slot].timeout)) {
-					printk("dvb_ca adaptor %d: PC card did not respond :(\n",
-					       ca->dvbdev->adapter->num);
-					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-					dvb_ca_en50221_thread_update_delay(ca);
-					break;
-				}
-				// no other action needed; will automatically change state when ready
-				break;
-
-			case DVB_CA_SLOTSTATE_VALIDATE:
-				if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
-					/* we need this extra check for annoying interfaces like the budget-av */
-					if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
-					    (ca->pub->poll_slot_status)) {
-						status = ca->pub->poll_slot_status(ca->pub, slot, 0);
-						if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
-							ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
-							dvb_ca_en50221_thread_update_delay(ca);
-							break;
-						}
-					}
-
-					printk("dvb_ca adapter %d: Invalid PC card inserted :(\n",
-					       ca->dvbdev->adapter->num);
-					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-					dvb_ca_en50221_thread_update_delay(ca);
-					break;
-				}
-				if (dvb_ca_en50221_set_configoption(ca, slot) != 0) {
-					printk("dvb_ca adapter %d: Unable to initialise CAM :(\n",
-					       ca->dvbdev->adapter->num);
-					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-					dvb_ca_en50221_thread_update_delay(ca);
-					break;
-				}
-				if (ca->pub->write_cam_control(ca->pub, slot,
-							       CTRLIF_COMMAND, CMDREG_RS) != 0) {
-					printk("dvb_ca adapter %d: Unable to reset CAM IF\n",
-					       ca->dvbdev->adapter->num);
-					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-					dvb_ca_en50221_thread_update_delay(ca);
-					break;
-				}
-				dprintk("DVB CAM validated successfully\n");
-
-				ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
-				ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITFR;
-				ca->wakeup = 1;
-				break;
-
-			case DVB_CA_SLOTSTATE_WAITFR:
-				if (time_after(jiffies, ca->slot_info[slot].timeout)) {
-					printk("dvb_ca adapter %d: DVB CAM did not respond :(\n",
-					       ca->dvbdev->adapter->num);
-					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-					dvb_ca_en50221_thread_update_delay(ca);
-					break;
-				}
-
-				flags = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
-				if (flags & STATUSREG_FR) {
-					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-					ca->wakeup = 1;
-				}
-				break;
-
-			case DVB_CA_SLOTSTATE_LINKINIT:
-				if (dvb_ca_en50221_link_init(ca, slot) != 0) {
-					/* we need this extra check for annoying interfaces like the budget-av */
-					if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
-					    (ca->pub->poll_slot_status)) {
-						status = ca->pub->poll_slot_status(ca->pub, slot, 0);
-						if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
-							ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
-							dvb_ca_en50221_thread_update_delay(ca);
-							break;
-						}
-					}
-
-					printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num);
-					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-					dvb_ca_en50221_thread_update_delay(ca);
-					break;
-				}
-
-				if (ca->slot_info[slot].rx_buffer.data == NULL) {
-					rxbuf = vmalloc(RX_BUFFER_SIZE);
-					if (rxbuf == NULL) {
-						printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num);
-						ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-						dvb_ca_en50221_thread_update_delay(ca);
-						break;
-					}
-					dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE);
-				}
-
-				ca->pub->slot_ts_enable(ca->pub, slot);
-				ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING;
-				dvb_ca_en50221_thread_update_delay(ca);
-				printk("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", ca->dvbdev->adapter->num);
-				break;
-
-			case DVB_CA_SLOTSTATE_RUNNING:
-				if (!ca->open)
-					break;
-
-				// poll slots for data
-				pktcount = 0;
-				while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) {
-					if (!ca->open)
-						break;
-
-					/* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */
-					if (dvb_ca_en50221_check_camstatus(ca, slot)) {
-						// we dont want to sleep on the next iteration so we can handle the cam change
-						ca->wakeup = 1;
-						break;
-					}
-
-					/* check if we've hit our limit this time */
-					if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) {
-						// dont sleep; there is likely to be more data to read
-						ca->wakeup = 1;
-						break;
-					}
-				}
-				break;
-			}
-
-			mutex_unlock(&ca->slot_info[slot].slot_lock);
-		}
-	}
-
-	return 0;
-}
-
-
-
-/* ******************************************************************************** */
-/* EN50221 IO interface functions */
-
-/**
- * Real ioctl implementation.
- * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them.
- *
- * @param inode Inode concerned.
- * @param file File concerned.
- * @param cmd IOCTL command.
- * @param arg Associated argument.
- *
- * @return 0 on success, <0 on error.
- */
-static int dvb_ca_en50221_io_do_ioctl(struct file *file,
-				      unsigned int cmd, void *parg)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dvb_ca_private *ca = dvbdev->priv;
-	int err = 0;
-	int slot;
-
-	dprintk("%s\n", __func__);
-
-	switch (cmd) {
-	case CA_RESET:
-		for (slot = 0; slot < ca->slot_count; slot++) {
-			mutex_lock(&ca->slot_info[slot].slot_lock);
-			if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) {
-				dvb_ca_en50221_slot_shutdown(ca, slot);
-				if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)
-					dvb_ca_en50221_camchange_irq(ca->pub,
-								     slot,
-								     DVB_CA_EN50221_CAMCHANGE_INSERTED);
-			}
-			mutex_unlock(&ca->slot_info[slot].slot_lock);
-		}
-		ca->next_read_slot = 0;
-		dvb_ca_en50221_thread_wakeup(ca);
-		break;
-
-	case CA_GET_CAP: {
-		struct ca_caps *caps = parg;
-
-		caps->slot_num = ca->slot_count;
-		caps->slot_type = CA_CI_LINK;
-		caps->descr_num = 0;
-		caps->descr_type = 0;
-		break;
-	}
-
-	case CA_GET_SLOT_INFO: {
-		struct ca_slot_info *info = parg;
-
-		if ((info->num > ca->slot_count) || (info->num < 0))
-			return -EINVAL;
-
-		info->type = CA_CI_LINK;
-		info->flags = 0;
-		if ((ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_NONE)
-			&& (ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_INVALID)) {
-			info->flags = CA_CI_MODULE_PRESENT;
-		}
-		if (ca->slot_info[info->num].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
-			info->flags |= CA_CI_MODULE_READY;
-		}
-		break;
-	}
-
-	default:
-		err = -EINVAL;
-		break;
-	}
-
-	return err;
-}
-
-
-/**
- * Wrapper for ioctl implementation.
- *
- * @param inode Inode concerned.
- * @param file File concerned.
- * @param cmd IOCTL command.
- * @param arg Associated argument.
- *
- * @return 0 on success, <0 on error.
- */
-static long dvb_ca_en50221_io_ioctl(struct file *file,
-				    unsigned int cmd, unsigned long arg)
-{
-	return dvb_usercopy(file, cmd, arg, dvb_ca_en50221_io_do_ioctl);
-}
-
-
-/**
- * Implementation of write() syscall.
- *
- * @param file File structure.
- * @param buf Source buffer.
- * @param count Size of source buffer.
- * @param ppos Position in file (ignored).
- *
- * @return Number of bytes read, or <0 on error.
- */
-static ssize_t dvb_ca_en50221_io_write(struct file *file,
-				       const char __user * buf, size_t count, loff_t * ppos)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dvb_ca_private *ca = dvbdev->priv;
-	u8 slot, connection_id;
-	int status;
-	u8 fragbuf[HOST_LINK_BUF_SIZE];
-	int fragpos = 0;
-	int fraglen;
-	unsigned long timeout;
-	int written;
-
-	dprintk("%s\n", __func__);
-
-	/* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
-	if (count < 2)
-		return -EINVAL;
-
-	/* extract slot & connection id */
-	if (copy_from_user(&slot, buf, 1))
-		return -EFAULT;
-	if (copy_from_user(&connection_id, buf + 1, 1))
-		return -EFAULT;
-	buf += 2;
-	count -= 2;
-
-	/* check if the slot is actually running */
-	if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
-		return -EINVAL;
-
-	/* fragment the packets & store in the buffer */
-	while (fragpos < count) {
-		fraglen = ca->slot_info[slot].link_buf_size - 2;
-		if (fraglen < 0)
-			break;
-		if (fraglen > HOST_LINK_BUF_SIZE - 2)
-			fraglen = HOST_LINK_BUF_SIZE - 2;
-		if ((count - fragpos) < fraglen)
-			fraglen = count - fragpos;
-
-		fragbuf[0] = connection_id;
-		fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00;
-		status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen);
-		if (status) {
-			status = -EFAULT;
-			goto exit;
-		}
-
-		timeout = jiffies + HZ / 2;
-		written = 0;
-		while (!time_after(jiffies, timeout)) {
-			/* check the CAM hasn't been removed/reset in the meantime */
-			if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) {
-				status = -EIO;
-				goto exit;
-			}
-
-			mutex_lock(&ca->slot_info[slot].slot_lock);
-			status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen + 2);
-			mutex_unlock(&ca->slot_info[slot].slot_lock);
-			if (status == (fraglen + 2)) {
-				written = 1;
-				break;
-			}
-			if (status != -EAGAIN)
-				goto exit;
-
-			msleep(1);
-		}
-		if (!written) {
-			status = -EIO;
-			goto exit;
-		}
-
-		fragpos += fraglen;
-	}
-	status = count + 2;
-
-exit:
-	return status;
-}
-
-
-/**
- * Condition for waking up in dvb_ca_en50221_io_read_condition
- */
-static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca,
-					    int *result, int *_slot)
-{
-	int slot;
-	int slot_count = 0;
-	int idx;
-	size_t fraglen;
-	int connection_id = -1;
-	int found = 0;
-	u8 hdr[2];
-
-	slot = ca->next_read_slot;
-	while ((slot_count < ca->slot_count) && (!found)) {
-		if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
-			goto nextslot;
-
-		if (ca->slot_info[slot].rx_buffer.data == NULL) {
-			return 0;
-		}
-
-		idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
-		while (idx != -1) {
-			dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
-			if (connection_id == -1)
-				connection_id = hdr[0];
-			if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) {
-				*_slot = slot;
-				found = 1;
-				break;
-			}
-
-			idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
-		}
-
-nextslot:
-		slot = (slot + 1) % ca->slot_count;
-		slot_count++;
-	}
-
-	ca->next_read_slot = slot;
-	return found;
-}
-
-
-/**
- * Implementation of read() syscall.
- *
- * @param file File structure.
- * @param buf Destination buffer.
- * @param count Size of destination buffer.
- * @param ppos Position in file (ignored).
- *
- * @return Number of bytes read, or <0 on error.
- */
-static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
-				      size_t count, loff_t * ppos)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dvb_ca_private *ca = dvbdev->priv;
-	int status;
-	int result = 0;
-	u8 hdr[2];
-	int slot;
-	int connection_id = -1;
-	size_t idx, idx2;
-	int last_fragment = 0;
-	size_t fraglen;
-	int pktlen;
-	int dispose = 0;
-
-	dprintk("%s\n", __func__);
-
-	/* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
-	if (count < 2)
-		return -EINVAL;
-
-	/* wait for some data */
-	if ((status = dvb_ca_en50221_io_read_condition(ca, &result, &slot)) == 0) {
-
-		/* if we're in nonblocking mode, exit immediately */
-		if (file->f_flags & O_NONBLOCK)
-			return -EWOULDBLOCK;
-
-		/* wait for some data */
-		status = wait_event_interruptible(ca->wait_queue,
-						  dvb_ca_en50221_io_read_condition
-						  (ca, &result, &slot));
-	}
-	if ((status < 0) || (result < 0)) {
-		if (result)
-			return result;
-		return status;
-	}
-
-	idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
-	pktlen = 2;
-	do {
-		if (idx == -1) {
-			printk("dvb_ca adapter %d: BUG: read packet ended before last_fragment encountered\n", ca->dvbdev->adapter->num);
-			status = -EIO;
-			goto exit;
-		}
-
-		dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
-		if (connection_id == -1)
-			connection_id = hdr[0];
-		if (hdr[0] == connection_id) {
-			if (pktlen < count) {
-				if ((pktlen + fraglen - 2) > count) {
-					fraglen = count - pktlen;
-				} else {
-					fraglen -= 2;
-				}
-
-				if ((status = dvb_ringbuffer_pkt_read_user(&ca->slot_info[slot].rx_buffer, idx, 2,
-								      buf + pktlen, fraglen)) < 0) {
-					goto exit;
-				}
-				pktlen += fraglen;
-			}
-
-			if ((hdr[1] & 0x80) == 0)
-				last_fragment = 1;
-			dispose = 1;
-		}
-
-		idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
-		if (dispose)
-			dvb_ringbuffer_pkt_dispose(&ca->slot_info[slot].rx_buffer, idx);
-		idx = idx2;
-		dispose = 0;
-	} while (!last_fragment);
-
-	hdr[0] = slot;
-	hdr[1] = connection_id;
-	status = copy_to_user(buf, hdr, 2);
-	if (status) {
-		status = -EFAULT;
-		goto exit;
-	}
-	status = pktlen;
-
-exit:
-	return status;
-}
-
-
-/**
- * Implementation of file open syscall.
- *
- * @param inode Inode concerned.
- * @param file File concerned.
- *
- * @return 0 on success, <0 on failure.
- */
-static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dvb_ca_private *ca = dvbdev->priv;
-	int err;
-	int i;
-
-	dprintk("%s\n", __func__);
-
-	if (!try_module_get(ca->pub->owner))
-		return -EIO;
-
-	err = dvb_generic_open(inode, file);
-	if (err < 0) {
-		module_put(ca->pub->owner);
-		return err;
-	}
-
-	for (i = 0; i < ca->slot_count; i++) {
-
-		if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
-			if (ca->slot_info[i].rx_buffer.data != NULL) {
-				/* it is safe to call this here without locks because
-				 * ca->open == 0. Data is not read in this case */
-				dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer);
-			}
-		}
-	}
-
-	ca->open = 1;
-	dvb_ca_en50221_thread_update_delay(ca);
-	dvb_ca_en50221_thread_wakeup(ca);
-
-	return 0;
-}
-
-
-/**
- * Implementation of file close syscall.
- *
- * @param inode Inode concerned.
- * @param file File concerned.
- *
- * @return 0 on success, <0 on failure.
- */
-static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dvb_ca_private *ca = dvbdev->priv;
-	int err;
-
-	dprintk("%s\n", __func__);
-
-	/* mark the CA device as closed */
-	ca->open = 0;
-	dvb_ca_en50221_thread_update_delay(ca);
-
-	err = dvb_generic_release(inode, file);
-
-	module_put(ca->pub->owner);
-
-	return err;
-}
-
-
-/**
- * Implementation of poll() syscall.
- *
- * @param file File concerned.
- * @param wait poll wait table.
- *
- * @return Standard poll mask.
- */
-static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dvb_ca_private *ca = dvbdev->priv;
-	unsigned int mask = 0;
-	int slot;
-	int result = 0;
-
-	dprintk("%s\n", __func__);
-
-	if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
-		mask |= POLLIN;
-	}
-
-	/* if there is something, return now */
-	if (mask)
-		return mask;
-
-	/* wait for something to happen */
-	poll_wait(file, &ca->wait_queue, wait);
-
-	if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
-		mask |= POLLIN;
-	}
-
-	return mask;
-}
-EXPORT_SYMBOL(dvb_ca_en50221_init);
-
-
-static const struct file_operations dvb_ca_fops = {
-	.owner = THIS_MODULE,
-	.read = dvb_ca_en50221_io_read,
-	.write = dvb_ca_en50221_io_write,
-	.unlocked_ioctl = dvb_ca_en50221_io_ioctl,
-	.open = dvb_ca_en50221_io_open,
-	.release = dvb_ca_en50221_io_release,
-	.poll = dvb_ca_en50221_io_poll,
-	.llseek = noop_llseek,
-};
-
-static struct dvb_device dvbdev_ca = {
-	.priv = NULL,
-	.users = 1,
-	.readers = 1,
-	.writers = 1,
-	.fops = &dvb_ca_fops,
-};
-
-
-/* ******************************************************************************** */
-/* Initialisation/shutdown functions */
-
-
-/**
- * Initialise a new DVB CA EN50221 interface device.
- *
- * @param dvb_adapter DVB adapter to attach the new CA device to.
- * @param ca The dvb_ca instance.
- * @param flags Flags describing the CA device (DVB_CA_FLAG_*).
- * @param slot_count Number of slots supported.
- *
- * @return 0 on success, nonzero on failure
- */
-int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
-			struct dvb_ca_en50221 *pubca, int flags, int slot_count)
-{
-	int ret;
-	struct dvb_ca_private *ca = NULL;
-	int i;
-
-	dprintk("%s\n", __func__);
-
-	if (slot_count < 1)
-		return -EINVAL;
-
-	/* initialise the system data */
-	if ((ca = kzalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) {
-		ret = -ENOMEM;
-		goto error;
-	}
-	ca->pub = pubca;
-	ca->flags = flags;
-	ca->slot_count = slot_count;
-	if ((ca->slot_info = kcalloc(slot_count, sizeof(struct dvb_ca_slot), GFP_KERNEL)) == NULL) {
-		ret = -ENOMEM;
-		goto error;
-	}
-	init_waitqueue_head(&ca->wait_queue);
-	ca->open = 0;
-	ca->wakeup = 0;
-	ca->next_read_slot = 0;
-	pubca->private = ca;
-
-	/* register the DVB device */
-	ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA);
-	if (ret)
-		goto error;
-
-	/* now initialise each slot */
-	for (i = 0; i < slot_count; i++) {
-		memset(&ca->slot_info[i], 0, sizeof(struct dvb_ca_slot));
-		ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE;
-		atomic_set(&ca->slot_info[i].camchange_count, 0);
-		ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
-		mutex_init(&ca->slot_info[i].slot_lock);
-	}
-
-	if (signal_pending(current)) {
-		ret = -EINTR;
-		goto error;
-	}
-	mb();
-
-	/* create a kthread for monitoring this CA device */
-	ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i",
-				 ca->dvbdev->adapter->num, ca->dvbdev->id);
-	if (IS_ERR(ca->thread)) {
-		ret = PTR_ERR(ca->thread);
-		printk("dvb_ca_init: failed to start kernel_thread (%d)\n",
-			ret);
-		goto error;
-	}
-	return 0;
-
-error:
-	if (ca != NULL) {
-		if (ca->dvbdev != NULL)
-			dvb_unregister_device(ca->dvbdev);
-		kfree(ca->slot_info);
-		kfree(ca);
-	}
-	pubca->private = NULL;
-	return ret;
-}
-EXPORT_SYMBOL(dvb_ca_en50221_release);
-
-
-
-/**
- * Release a DVB CA EN50221 interface device.
- *
- * @param ca_dev The dvb_device_t instance for the CA device.
- * @param ca The associated dvb_ca instance.
- */
-void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
-{
-	struct dvb_ca_private *ca = pubca->private;
-	int i;
-
-	dprintk("%s\n", __func__);
-
-	/* shutdown the thread if there was one */
-	kthread_stop(ca->thread);
-
-	for (i = 0; i < ca->slot_count; i++) {
-		dvb_ca_en50221_slot_shutdown(ca, i);
-		vfree(ca->slot_info[i].rx_buffer.data);
-	}
-	kfree(ca->slot_info);
-	dvb_unregister_device(ca->dvbdev);
-	kfree(ca);
-	pubca->private = NULL;
-}
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.h b/drivers/media/dvb/dvb-core/dvb_ca_en50221.h
deleted file mode 100644
index 7df2e14..0000000
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * dvb_ca.h: generic DVB functions for EN50221 CA interfaces
- *
- * Copyright (C) 2004 Andrew de Quincey
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#ifndef _DVB_CA_EN50221_H_
-#define _DVB_CA_EN50221_H_
-
-#include <linux/list.h>
-#include <linux/dvb/ca.h>
-
-#include "dvbdev.h"
-
-#define DVB_CA_EN50221_POLL_CAM_PRESENT	1
-#define DVB_CA_EN50221_POLL_CAM_CHANGED	2
-#define DVB_CA_EN50221_POLL_CAM_READY		4
-
-#define DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE	1
-#define DVB_CA_EN50221_FLAG_IRQ_FR		2
-#define DVB_CA_EN50221_FLAG_IRQ_DA		4
-
-#define DVB_CA_EN50221_CAMCHANGE_REMOVED		0
-#define DVB_CA_EN50221_CAMCHANGE_INSERTED		1
-
-
-
-/* Structure describing a CA interface */
-struct dvb_ca_en50221 {
-
-	/* the module owning this structure */
-	struct module* owner;
-
-	/* NOTE: the read_*, write_* and poll_slot_status functions will be
-	 * called for different slots concurrently and need to use locks where
-	 * and if appropriate. There will be no concurrent access to one slot.
-	 */
-
-	/* functions for accessing attribute memory on the CAM */
-	int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address);
-	int (*write_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address, u8 value);
-
-	/* functions for accessing the control interface on the CAM */
-	int (*read_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address);
-	int (*write_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value);
-
-	/* Functions for controlling slots */
-	int (*slot_reset)(struct dvb_ca_en50221* ca, int slot);
-	int (*slot_shutdown)(struct dvb_ca_en50221* ca, int slot);
-	int (*slot_ts_enable)(struct dvb_ca_en50221* ca, int slot);
-
-	/*
-	* Poll slot status.
-	* Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set
-	*/
-	int (*poll_slot_status)(struct dvb_ca_en50221* ca, int slot, int open);
-
-	/* private data, used by caller */
-	void* data;
-
-	/* Opaque data used by the dvb_ca core. Do not modify! */
-	void* private;
-};
-
-
-
-
-/* ******************************************************************************** */
-/* Functions for reporting IRQ events */
-
-/**
- * A CAMCHANGE IRQ has occurred.
- *
- * @param ca CA instance.
- * @param slot Slot concerned.
- * @param change_type One of the DVB_CA_CAMCHANGE_* values
- */
-void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int change_type);
-
-/**
- * A CAMREADY IRQ has occurred.
- *
- * @param ca CA instance.
- * @param slot Slot concerned.
- */
-void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221* pubca, int slot);
-
-/**
- * An FR or a DA IRQ has occurred.
- *
- * @param ca CA instance.
- * @param slot Slot concerned.
- */
-void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* ca, int slot);
-
-
-
-/* ******************************************************************************** */
-/* Initialisation/shutdown functions */
-
-/**
- * Initialise a new DVB CA device.
- *
- * @param dvb_adapter DVB adapter to attach the new CA device to.
- * @param ca The dvb_ca instance.
- * @param flags Flags describing the CA device (DVB_CA_EN50221_FLAG_*).
- * @param slot_count Number of slots supported.
- *
- * @return 0 on success, nonzero on failure
- */
-extern int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* ca, int flags, int slot_count);
-
-/**
- * Release a DVB CA device.
- *
- * @param ca The associated dvb_ca instance.
- */
-extern void dvb_ca_en50221_release(struct dvb_ca_en50221* ca);
-
-
-
-#endif
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
deleted file mode 100644
index d82469f..0000000
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ /dev/null
@@ -1,1309 +0,0 @@
-/*
- * dvb_demux.c - DVB kernel demux API
- *
- * Copyright (C) 2000-2001 Ralph  Metzler <ralph@convergence.de>
- *		       & Marcus Metzler <marcus@convergence.de>
- *			 for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- */
-
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/string.h>
-#include <linux/crc32.h>
-#include <asm/uaccess.h>
-#include <asm/div64.h>
-
-#include "dvb_demux.h"
-
-#define NOBUFS
-/*
-** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog
-*/
-// #define DVB_DEMUX_SECTION_LOSS_LOG
-
-static int dvb_demux_tscheck;
-module_param(dvb_demux_tscheck, int, 0644);
-MODULE_PARM_DESC(dvb_demux_tscheck,
-		"enable transport stream continuity and TEI check");
-
-static int dvb_demux_speedcheck;
-module_param(dvb_demux_speedcheck, int, 0644);
-MODULE_PARM_DESC(dvb_demux_speedcheck,
-		"enable transport stream speed check");
-
-#define dprintk_tscheck(x...) do {                              \
-		if (dvb_demux_tscheck && printk_ratelimit())    \
-			printk(x);                              \
-	} while (0)
-
-/******************************************************************************
- * static inlined helper functions
- ******************************************************************************/
-
-static inline u16 section_length(const u8 *buf)
-{
-	return 3 + ((buf[1] & 0x0f) << 8) + buf[2];
-}
-
-static inline u16 ts_pid(const u8 *buf)
-{
-	return ((buf[1] & 0x1f) << 8) + buf[2];
-}
-
-static inline u8 payload(const u8 *tsp)
-{
-	if (!(tsp[3] & 0x10))	// no payload?
-		return 0;
-
-	if (tsp[3] & 0x20) {	// adaptation field?
-		if (tsp[4] > 183)	// corrupted data?
-			return 0;
-		else
-			return 184 - 1 - tsp[4];
-	}
-
-	return 184;
-}
-
-static u32 dvb_dmx_crc32(struct dvb_demux_feed *f, const u8 *src, size_t len)
-{
-	return (f->feed.sec.crc_val = crc32_be(f->feed.sec.crc_val, src, len));
-}
-
-static void dvb_dmx_memcopy(struct dvb_demux_feed *f, u8 *d, const u8 *s,
-			    size_t len)
-{
-	memcpy(d, s, len);
-}
-
-/******************************************************************************
- * Software filter functions
- ******************************************************************************/
-
-static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
-					   const u8 *buf)
-{
-	int count = payload(buf);
-	int p;
-	//int ccok;
-	//u8 cc;
-
-	if (count == 0)
-		return -1;
-
-	p = 188 - count;
-
-	/*
-	cc = buf[3] & 0x0f;
-	ccok = ((feed->cc + 1) & 0x0f) == cc;
-	feed->cc = cc;
-	if (!ccok)
-		printk("missed packet!\n");
-	*/
-
-	if (buf[1] & 0x40)	// PUSI ?
-		feed->peslen = 0xfffa;
-
-	feed->peslen += count;
-
-	return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK);
-}
-
-static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
-					  struct dvb_demux_filter *f)
-{
-	u8 neq = 0;
-	int i;
-
-	for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
-		u8 xor = f->filter.filter_value[i] ^ feed->feed.sec.secbuf[i];
-
-		if (f->maskandmode[i] & xor)
-			return 0;
-
-		neq |= f->maskandnotmode[i] & xor;
-	}
-
-	if (f->doneq && !neq)
-		return 0;
-
-	return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen,
-			    NULL, 0, &f->filter, DMX_OK);
-}
-
-static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
-{
-	struct dvb_demux *demux = feed->demux;
-	struct dvb_demux_filter *f = feed->filter;
-	struct dmx_section_feed *sec = &feed->feed.sec;
-	int section_syntax_indicator;
-
-	if (!sec->is_filtering)
-		return 0;
-
-	if (!f)
-		return 0;
-
-	if (sec->check_crc) {
-		section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
-		if (section_syntax_indicator &&
-		    demux->check_crc32(feed, sec->secbuf, sec->seclen))
-			return -1;
-	}
-
-	do {
-		if (dvb_dmx_swfilter_sectionfilter(feed, f) < 0)
-			return -1;
-	} while ((f = f->next) && sec->is_filtering);
-
-	sec->seclen = 0;
-
-	return 0;
-}
-
-static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
-{
-	struct dmx_section_feed *sec = &feed->feed.sec;
-
-#ifdef DVB_DEMUX_SECTION_LOSS_LOG
-	if (sec->secbufp < sec->tsfeedp) {
-		int i, n = sec->tsfeedp - sec->secbufp;
-
-		/*
-		 * Section padding is done with 0xff bytes entirely.
-		 * Due to speed reasons, we won't check all of them
-		 * but just first and last.
-		 */
-		if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) {
-			printk("dvb_demux.c section ts padding loss: %d/%d\n",
-			       n, sec->tsfeedp);
-			printk("dvb_demux.c pad data:");
-			for (i = 0; i < n; i++)
-				printk(" %02x", sec->secbuf[i]);
-			printk("\n");
-		}
-	}
-#endif
-
-	sec->tsfeedp = sec->secbufp = sec->seclen = 0;
-	sec->secbuf = sec->secbuf_base;
-}
-
-/*
- * Losless Section Demux 1.4.1 by Emard
- * Valsecchi Patrick:
- *  - middle of section A  (no PUSI)
- *  - end of section A and start of section B
- *    (with PUSI pointing to the start of the second section)
- *
- *  In this case, without feed->pusi_seen you'll receive a garbage section
- *  consisting of the end of section A. Basically because tsfeedp
- *  is incemented and the use=0 condition is not raised
- *  when the second packet arrives.
- *
- * Fix:
- * when demux is started, let feed->pusi_seen = 0 to
- * prevent initial feeding of garbage from the end of
- * previous section. When you for the first time see PUSI=1
- * then set feed->pusi_seen = 1
- */
-static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
-					      const u8 *buf, u8 len)
-{
-	struct dvb_demux *demux = feed->demux;
-	struct dmx_section_feed *sec = &feed->feed.sec;
-	u16 limit, seclen, n;
-
-	if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE)
-		return 0;
-
-	if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) {
-#ifdef DVB_DEMUX_SECTION_LOSS_LOG
-		printk("dvb_demux.c section buffer full loss: %d/%d\n",
-		       sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
-		       DMX_MAX_SECFEED_SIZE);
-#endif
-		len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp;
-	}
-
-	if (len <= 0)
-		return 0;
-
-	demux->memcopy(feed, sec->secbuf_base + sec->tsfeedp, buf, len);
-	sec->tsfeedp += len;
-
-	/*
-	 * Dump all the sections we can find in the data (Emard)
-	 */
-	limit = sec->tsfeedp;
-	if (limit > DMX_MAX_SECFEED_SIZE)
-		return -1;	/* internal error should never happen */
-
-	/* to be sure always set secbuf */
-	sec->secbuf = sec->secbuf_base + sec->secbufp;
-
-	for (n = 0; sec->secbufp + 2 < limit; n++) {
-		seclen = section_length(sec->secbuf);
-		if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE
-		    || seclen + sec->secbufp > limit)
-			return 0;
-		sec->seclen = seclen;
-		sec->crc_val = ~0;
-		/* dump [secbuf .. secbuf+seclen) */
-		if (feed->pusi_seen)
-			dvb_dmx_swfilter_section_feed(feed);
-#ifdef DVB_DEMUX_SECTION_LOSS_LOG
-		else
-			printk("dvb_demux.c pusi not seen, discarding section data\n");
-#endif
-		sec->secbufp += seclen;	/* secbufp and secbuf moving together is */
-		sec->secbuf += seclen;	/* redundant but saves pointer arithmetic */
-	}
-
-	return 0;
-}
-
-static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
-					   const u8 *buf)
-{
-	u8 p, count;
-	int ccok, dc_i = 0;
-	u8 cc;
-
-	count = payload(buf);
-
-	if (count == 0)		/* count == 0 if no payload or out of range */
-		return -1;
-
-	p = 188 - count;	/* payload start */
-
-	cc = buf[3] & 0x0f;
-	ccok = ((feed->cc + 1) & 0x0f) == cc;
-	feed->cc = cc;
-
-	if (buf[3] & 0x20) {
-		/* adaption field present, check for discontinuity_indicator */
-		if ((buf[4] > 0) && (buf[5] & 0x80))
-			dc_i = 1;
-	}
-
-	if (!ccok || dc_i) {
-#ifdef DVB_DEMUX_SECTION_LOSS_LOG
-		printk("dvb_demux.c discontinuity detected %d bytes lost\n",
-		       count);
-		/*
-		 * those bytes under sume circumstances will again be reported
-		 * in the following dvb_dmx_swfilter_section_new
-		 */
-#endif
-		/*
-		 * Discontinuity detected. Reset pusi_seen = 0 to
-		 * stop feeding of suspicious data until next PUSI=1 arrives
-		 */
-		feed->pusi_seen = 0;
-		dvb_dmx_swfilter_section_new(feed);
-	}
-
-	if (buf[1] & 0x40) {
-		/* PUSI=1 (is set), section boundary is here */
-		if (count > 1 && buf[p] < count) {
-			const u8 *before = &buf[p + 1];
-			u8 before_len = buf[p];
-			const u8 *after = &before[before_len];
-			u8 after_len = count - 1 - before_len;
-
-			dvb_dmx_swfilter_section_copy_dump(feed, before,
-							   before_len);
-			/* before start of new section, set pusi_seen = 1 */
-			feed->pusi_seen = 1;
-			dvb_dmx_swfilter_section_new(feed);
-			dvb_dmx_swfilter_section_copy_dump(feed, after,
-							   after_len);
-		}
-#ifdef DVB_DEMUX_SECTION_LOSS_LOG
-		else if (count > 0)
-			printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count);
-#endif
-	} else {
-		/* PUSI=0 (is not set), no section boundary */
-		dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count);
-	}
-
-	return 0;
-}
-
-static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
-						const u8 *buf)
-{
-	switch (feed->type) {
-	case DMX_TYPE_TS:
-		if (!feed->feed.ts.is_filtering)
-			break;
-		if (feed->ts_type & TS_PACKET) {
-			if (feed->ts_type & TS_PAYLOAD_ONLY)
-				dvb_dmx_swfilter_payload(feed, buf);
-			else
-				feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
-					    DMX_OK);
-		}
-		if (feed->ts_type & TS_DECODER)
-			if (feed->demux->write_to_decoder)
-				feed->demux->write_to_decoder(feed, buf, 188);
-		break;
-
-	case DMX_TYPE_SEC:
-		if (!feed->feed.sec.is_filtering)
-			break;
-		if (dvb_dmx_swfilter_section_packet(feed, buf) < 0)
-			feed->feed.sec.seclen = feed->feed.sec.secbufp = 0;
-		break;
-
-	default:
-		break;
-	}
-}
-
-#define DVR_FEED(f)							\
-	(((f)->type == DMX_TYPE_TS) &&					\
-	((f)->feed.ts.is_filtering) &&					\
-	(((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET))
-
-static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
-{
-	struct dvb_demux_feed *feed;
-	u16 pid = ts_pid(buf);
-	int dvr_done = 0;
-
-	if (dvb_demux_speedcheck) {
-		struct timespec cur_time, delta_time;
-		u64 speed_bytes, speed_timedelta;
-
-		demux->speed_pkts_cnt++;
-
-		/* show speed every SPEED_PKTS_INTERVAL packets */
-		if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) {
-			cur_time = current_kernel_time();
-
-			if (demux->speed_last_time.tv_sec != 0 &&
-					demux->speed_last_time.tv_nsec != 0) {
-				delta_time = timespec_sub(cur_time,
-						demux->speed_last_time);
-				speed_bytes = (u64)demux->speed_pkts_cnt
-					* 188 * 8;
-				/* convert to 1024 basis */
-				speed_bytes = 1000 * div64_u64(speed_bytes,
-						1024);
-				speed_timedelta =
-					(u64)timespec_to_ns(&delta_time);
-				speed_timedelta = div64_u64(speed_timedelta,
-						1000000); /* nsec -> usec */
-				printk(KERN_INFO "TS speed %llu Kbits/sec \n",
-						div64_u64(speed_bytes,
-							speed_timedelta));
-			};
-
-			demux->speed_last_time = cur_time;
-			demux->speed_pkts_cnt = 0;
-		};
-	};
-
-	if (demux->cnt_storage && dvb_demux_tscheck) {
-		/* check pkt counter */
-		if (pid < MAX_PID) {
-			if (buf[1] & 0x80)
-				dprintk_tscheck("TEI detected. "
-						"PID=0x%x data1=0x%x\n",
-						pid, buf[1]);
-
-			if ((buf[3] & 0xf) != demux->cnt_storage[pid])
-				dprintk_tscheck("TS packet counter mismatch. "
-						"PID=0x%x expected 0x%x "
-						"got 0x%x\n",
-						pid, demux->cnt_storage[pid],
-						buf[3] & 0xf);
-
-			demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf;
-		};
-		/* end check */
-	};
-
-	list_for_each_entry(feed, &demux->feed_list, list_head) {
-		if ((feed->pid != pid) && (feed->pid != 0x2000))
-			continue;
-
-		/* copy each packet only once to the dvr device, even
-		 * if a PID is in multiple filters (e.g. video + PCR) */
-		if ((DVR_FEED(feed)) && (dvr_done++))
-			continue;
-
-		if (feed->pid == pid)
-			dvb_dmx_swfilter_packet_type(feed, buf);
-		else if (feed->pid == 0x2000)
-			feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
-	}
-}
-
-void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
-			      size_t count)
-{
-	spin_lock(&demux->lock);
-
-	while (count--) {
-		if (buf[0] == 0x47)
-			dvb_dmx_swfilter_packet(demux, buf);
-		buf += 188;
-	}
-
-	spin_unlock(&demux->lock);
-}
-
-EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
-
-static inline int find_next_packet(const u8 *buf, int pos, size_t count,
-				   const int pktsize)
-{
-	int start = pos, lost;
-
-	while (pos < count) {
-		if (buf[pos] == 0x47 ||
-		    (pktsize == 204 && buf[pos] == 0xB8))
-			break;
-		pos++;
-	}
-
-	lost = pos - start;
-	if (lost) {
-		/* This garbage is part of a valid packet? */
-		int backtrack = pos - pktsize;
-		if (backtrack >= 0 && (buf[backtrack] == 0x47 ||
-		    (pktsize == 204 && buf[backtrack] == 0xB8)))
-			return backtrack;
-	}
-
-	return pos;
-}
-
-/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */
-static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
-		size_t count, const int pktsize)
-{
-	int p = 0, i, j;
-	const u8 *q;
-
-	spin_lock(&demux->lock);
-
-	if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
-		i = demux->tsbufp;
-		j = pktsize - i;
-		if (count < j) {
-			memcpy(&demux->tsbuf[i], buf, count);
-			demux->tsbufp += count;
-			goto bailout;
-		}
-		memcpy(&demux->tsbuf[i], buf, j);
-		if (demux->tsbuf[0] == 0x47) /* double check */
-			dvb_dmx_swfilter_packet(demux, demux->tsbuf);
-		demux->tsbufp = 0;
-		p += j;
-	}
-
-	while (1) {
-		p = find_next_packet(buf, p, count, pktsize);
-		if (p >= count)
-			break;
-		if (count - p < pktsize)
-			break;
-
-		q = &buf[p];
-
-		if (pktsize == 204 && (*q == 0xB8)) {
-			memcpy(demux->tsbuf, q, 188);
-			demux->tsbuf[0] = 0x47;
-			q = demux->tsbuf;
-		}
-		dvb_dmx_swfilter_packet(demux, q);
-		p += pktsize;
-	}
-
-	i = count - p;
-	if (i) {
-		memcpy(demux->tsbuf, &buf[p], i);
-		demux->tsbufp = i;
-		if (pktsize == 204 && demux->tsbuf[0] == 0xB8)
-			demux->tsbuf[0] = 0x47;
-	}
-
-bailout:
-	spin_unlock(&demux->lock);
-}
-
-void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
-{
-	_dvb_dmx_swfilter(demux, buf, count, 188);
-}
-EXPORT_SYMBOL(dvb_dmx_swfilter);
-
-void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
-{
-	_dvb_dmx_swfilter(demux, buf, count, 204);
-}
-EXPORT_SYMBOL(dvb_dmx_swfilter_204);
-
-void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
-{
-	spin_lock(&demux->lock);
-
-	demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, DMX_OK);
-
-	spin_unlock(&demux->lock);
-}
-EXPORT_SYMBOL(dvb_dmx_swfilter_raw);
-
-static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
-{
-	int i;
-
-	for (i = 0; i < demux->filternum; i++)
-		if (demux->filter[i].state == DMX_STATE_FREE)
-			break;
-
-	if (i == demux->filternum)
-		return NULL;
-
-	demux->filter[i].state = DMX_STATE_ALLOCATED;
-
-	return &demux->filter[i];
-}
-
-static struct dvb_demux_feed *dvb_dmx_feed_alloc(struct dvb_demux *demux)
-{
-	int i;
-
-	for (i = 0; i < demux->feednum; i++)
-		if (demux->feed[i].state == DMX_STATE_FREE)
-			break;
-
-	if (i == demux->feednum)
-		return NULL;
-
-	demux->feed[i].state = DMX_STATE_ALLOCATED;
-
-	return &demux->feed[i];
-}
-
-static int dvb_demux_feed_find(struct dvb_demux_feed *feed)
-{
-	struct dvb_demux_feed *entry;
-
-	list_for_each_entry(entry, &feed->demux->feed_list, list_head)
-		if (entry == feed)
-			return 1;
-
-	return 0;
-}
-
-static void dvb_demux_feed_add(struct dvb_demux_feed *feed)
-{
-	spin_lock_irq(&feed->demux->lock);
-	if (dvb_demux_feed_find(feed)) {
-		printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n",
-		       __func__, feed->type, feed->state, feed->pid);
-		goto out;
-	}
-
-	list_add(&feed->list_head, &feed->demux->feed_list);
-out:
-	spin_unlock_irq(&feed->demux->lock);
-}
-
-static void dvb_demux_feed_del(struct dvb_demux_feed *feed)
-{
-	spin_lock_irq(&feed->demux->lock);
-	if (!(dvb_demux_feed_find(feed))) {
-		printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n",
-		       __func__, feed->type, feed->state, feed->pid);
-		goto out;
-	}
-
-	list_del(&feed->list_head);
-out:
-	spin_unlock_irq(&feed->demux->lock);
-}
-
-static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
-			   enum dmx_ts_pes pes_type,
-			   size_t circular_buffer_size, struct timespec timeout)
-{
-	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
-	struct dvb_demux *demux = feed->demux;
-
-	if (pid > DMX_MAX_PID)
-		return -EINVAL;
-
-	if (mutex_lock_interruptible(&demux->mutex))
-		return -ERESTARTSYS;
-
-	if (ts_type & TS_DECODER) {
-		if (pes_type >= DMX_TS_PES_OTHER) {
-			mutex_unlock(&demux->mutex);
-			return -EINVAL;
-		}
-
-		if (demux->pesfilter[pes_type] &&
-		    demux->pesfilter[pes_type] != feed) {
-			mutex_unlock(&demux->mutex);
-			return -EINVAL;
-		}
-
-		demux->pesfilter[pes_type] = feed;
-		demux->pids[pes_type] = pid;
-	}
-
-	dvb_demux_feed_add(feed);
-
-	feed->pid = pid;
-	feed->buffer_size = circular_buffer_size;
-	feed->timeout = timeout;
-	feed->ts_type = ts_type;
-	feed->pes_type = pes_type;
-
-	if (feed->buffer_size) {
-#ifdef NOBUFS
-		feed->buffer = NULL;
-#else
-		feed->buffer = vmalloc(feed->buffer_size);
-		if (!feed->buffer) {
-			mutex_unlock(&demux->mutex);
-			return -ENOMEM;
-		}
-#endif
-	}
-
-	feed->state = DMX_STATE_READY;
-	mutex_unlock(&demux->mutex);
-
-	return 0;
-}
-
-static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed)
-{
-	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
-	struct dvb_demux *demux = feed->demux;
-	int ret;
-
-	if (mutex_lock_interruptible(&demux->mutex))
-		return -ERESTARTSYS;
-
-	if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) {
-		mutex_unlock(&demux->mutex);
-		return -EINVAL;
-	}
-
-	if (!demux->start_feed) {
-		mutex_unlock(&demux->mutex);
-		return -ENODEV;
-	}
-
-	if ((ret = demux->start_feed(feed)) < 0) {
-		mutex_unlock(&demux->mutex);
-		return ret;
-	}
-
-	spin_lock_irq(&demux->lock);
-	ts_feed->is_filtering = 1;
-	feed->state = DMX_STATE_GO;
-	spin_unlock_irq(&demux->lock);
-	mutex_unlock(&demux->mutex);
-
-	return 0;
-}
-
-static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed)
-{
-	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
-	struct dvb_demux *demux = feed->demux;
-	int ret;
-
-	mutex_lock(&demux->mutex);
-
-	if (feed->state < DMX_STATE_GO) {
-		mutex_unlock(&demux->mutex);
-		return -EINVAL;
-	}
-
-	if (!demux->stop_feed) {
-		mutex_unlock(&demux->mutex);
-		return -ENODEV;
-	}
-
-	ret = demux->stop_feed(feed);
-
-	spin_lock_irq(&demux->lock);
-	ts_feed->is_filtering = 0;
-	feed->state = DMX_STATE_ALLOCATED;
-	spin_unlock_irq(&demux->lock);
-	mutex_unlock(&demux->mutex);
-
-	return ret;
-}
-
-static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
-				   struct dmx_ts_feed **ts_feed,
-				   dmx_ts_cb callback)
-{
-	struct dvb_demux *demux = (struct dvb_demux *)dmx;
-	struct dvb_demux_feed *feed;
-
-	if (mutex_lock_interruptible(&demux->mutex))
-		return -ERESTARTSYS;
-
-	if (!(feed = dvb_dmx_feed_alloc(demux))) {
-		mutex_unlock(&demux->mutex);
-		return -EBUSY;
-	}
-
-	feed->type = DMX_TYPE_TS;
-	feed->cb.ts = callback;
-	feed->demux = demux;
-	feed->pid = 0xffff;
-	feed->peslen = 0xfffa;
-	feed->buffer = NULL;
-
-	(*ts_feed) = &feed->feed.ts;
-	(*ts_feed)->parent = dmx;
-	(*ts_feed)->priv = NULL;
-	(*ts_feed)->is_filtering = 0;
-	(*ts_feed)->start_filtering = dmx_ts_feed_start_filtering;
-	(*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering;
-	(*ts_feed)->set = dmx_ts_feed_set;
-
-	if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
-		feed->state = DMX_STATE_FREE;
-		mutex_unlock(&demux->mutex);
-		return -EBUSY;
-	}
-
-	feed->filter->type = DMX_TYPE_TS;
-	feed->filter->feed = feed;
-	feed->filter->state = DMX_STATE_READY;
-
-	mutex_unlock(&demux->mutex);
-
-	return 0;
-}
-
-static int dvbdmx_release_ts_feed(struct dmx_demux *dmx,
-				  struct dmx_ts_feed *ts_feed)
-{
-	struct dvb_demux *demux = (struct dvb_demux *)dmx;
-	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
-
-	mutex_lock(&demux->mutex);
-
-	if (feed->state == DMX_STATE_FREE) {
-		mutex_unlock(&demux->mutex);
-		return -EINVAL;
-	}
-#ifndef NOBUFS
-	vfree(feed->buffer);
-	feed->buffer = NULL;
-#endif
-
-	feed->state = DMX_STATE_FREE;
-	feed->filter->state = DMX_STATE_FREE;
-
-	dvb_demux_feed_del(feed);
-
-	feed->pid = 0xffff;
-
-	if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER)
-		demux->pesfilter[feed->pes_type] = NULL;
-
-	mutex_unlock(&demux->mutex);
-	return 0;
-}
-
-/******************************************************************************
- * dmx_section_feed API calls
- ******************************************************************************/
-
-static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed,
-					    struct dmx_section_filter **filter)
-{
-	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
-	struct dvb_demux *dvbdemux = dvbdmxfeed->demux;
-	struct dvb_demux_filter *dvbdmxfilter;
-
-	if (mutex_lock_interruptible(&dvbdemux->mutex))
-		return -ERESTARTSYS;
-
-	dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux);
-	if (!dvbdmxfilter) {
-		mutex_unlock(&dvbdemux->mutex);
-		return -EBUSY;
-	}
-
-	spin_lock_irq(&dvbdemux->lock);
-	*filter = &dvbdmxfilter->filter;
-	(*filter)->parent = feed;
-	(*filter)->priv = NULL;
-	dvbdmxfilter->feed = dvbdmxfeed;
-	dvbdmxfilter->type = DMX_TYPE_SEC;
-	dvbdmxfilter->state = DMX_STATE_READY;
-	dvbdmxfilter->next = dvbdmxfeed->filter;
-	dvbdmxfeed->filter = dvbdmxfilter;
-	spin_unlock_irq(&dvbdemux->lock);
-
-	mutex_unlock(&dvbdemux->mutex);
-	return 0;
-}
-
-static int dmx_section_feed_set(struct dmx_section_feed *feed,
-				u16 pid, size_t circular_buffer_size,
-				int check_crc)
-{
-	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-
-	if (pid > 0x1fff)
-		return -EINVAL;
-
-	if (mutex_lock_interruptible(&dvbdmx->mutex))
-		return -ERESTARTSYS;
-
-	dvb_demux_feed_add(dvbdmxfeed);
-
-	dvbdmxfeed->pid = pid;
-	dvbdmxfeed->buffer_size = circular_buffer_size;
-	dvbdmxfeed->feed.sec.check_crc = check_crc;
-
-#ifdef NOBUFS
-	dvbdmxfeed->buffer = NULL;
-#else
-	dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size);
-	if (!dvbdmxfeed->buffer) {
-		mutex_unlock(&dvbdmx->mutex);
-		return -ENOMEM;
-	}
-#endif
-
-	dvbdmxfeed->state = DMX_STATE_READY;
-	mutex_unlock(&dvbdmx->mutex);
-	return 0;
-}
-
-static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed)
-{
-	int i;
-	struct dvb_demux_filter *f;
-	struct dmx_section_filter *sf;
-	u8 mask, mode, doneq;
-
-	if (!(f = dvbdmxfeed->filter))
-		return;
-	do {
-		sf = &f->filter;
-		doneq = 0;
-		for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
-			mode = sf->filter_mode[i];
-			mask = sf->filter_mask[i];
-			f->maskandmode[i] = mask & mode;
-			doneq |= f->maskandnotmode[i] = mask & ~mode;
-		}
-		f->doneq = doneq ? 1 : 0;
-	} while ((f = f->next));
-}
-
-static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
-{
-	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-	int ret;
-
-	if (mutex_lock_interruptible(&dvbdmx->mutex))
-		return -ERESTARTSYS;
-
-	if (feed->is_filtering) {
-		mutex_unlock(&dvbdmx->mutex);
-		return -EBUSY;
-	}
-
-	if (!dvbdmxfeed->filter) {
-		mutex_unlock(&dvbdmx->mutex);
-		return -EINVAL;
-	}
-
-	dvbdmxfeed->feed.sec.tsfeedp = 0;
-	dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
-	dvbdmxfeed->feed.sec.secbufp = 0;
-	dvbdmxfeed->feed.sec.seclen = 0;
-
-	if (!dvbdmx->start_feed) {
-		mutex_unlock(&dvbdmx->mutex);
-		return -ENODEV;
-	}
-
-	prepare_secfilters(dvbdmxfeed);
-
-	if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) {
-		mutex_unlock(&dvbdmx->mutex);
-		return ret;
-	}
-
-	spin_lock_irq(&dvbdmx->lock);
-	feed->is_filtering = 1;
-	dvbdmxfeed->state = DMX_STATE_GO;
-	spin_unlock_irq(&dvbdmx->lock);
-
-	mutex_unlock(&dvbdmx->mutex);
-	return 0;
-}
-
-static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed)
-{
-	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-	int ret;
-
-	mutex_lock(&dvbdmx->mutex);
-
-	if (!dvbdmx->stop_feed) {
-		mutex_unlock(&dvbdmx->mutex);
-		return -ENODEV;
-	}
-
-	ret = dvbdmx->stop_feed(dvbdmxfeed);
-
-	spin_lock_irq(&dvbdmx->lock);
-	dvbdmxfeed->state = DMX_STATE_READY;
-	feed->is_filtering = 0;
-	spin_unlock_irq(&dvbdmx->lock);
-
-	mutex_unlock(&dvbdmx->mutex);
-	return ret;
-}
-
-static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
-					   struct dmx_section_filter *filter)
-{
-	struct dvb_demux_filter *dvbdmxfilter = (struct dvb_demux_filter *)filter, *f;
-	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-
-	mutex_lock(&dvbdmx->mutex);
-
-	if (dvbdmxfilter->feed != dvbdmxfeed) {
-		mutex_unlock(&dvbdmx->mutex);
-		return -EINVAL;
-	}
-
-	if (feed->is_filtering)
-		feed->stop_filtering(feed);
-
-	spin_lock_irq(&dvbdmx->lock);
-	f = dvbdmxfeed->filter;
-
-	if (f == dvbdmxfilter) {
-		dvbdmxfeed->filter = dvbdmxfilter->next;
-	} else {
-		while (f->next != dvbdmxfilter)
-			f = f->next;
-		f->next = f->next->next;
-	}
-
-	dvbdmxfilter->state = DMX_STATE_FREE;
-	spin_unlock_irq(&dvbdmx->lock);
-	mutex_unlock(&dvbdmx->mutex);
-	return 0;
-}
-
-static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
-					struct dmx_section_feed **feed,
-					dmx_section_cb callback)
-{
-	struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
-	struct dvb_demux_feed *dvbdmxfeed;
-
-	if (mutex_lock_interruptible(&dvbdmx->mutex))
-		return -ERESTARTSYS;
-
-	if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) {
-		mutex_unlock(&dvbdmx->mutex);
-		return -EBUSY;
-	}
-
-	dvbdmxfeed->type = DMX_TYPE_SEC;
-	dvbdmxfeed->cb.sec = callback;
-	dvbdmxfeed->demux = dvbdmx;
-	dvbdmxfeed->pid = 0xffff;
-	dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
-	dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
-	dvbdmxfeed->feed.sec.tsfeedp = 0;
-	dvbdmxfeed->filter = NULL;
-	dvbdmxfeed->buffer = NULL;
-
-	(*feed) = &dvbdmxfeed->feed.sec;
-	(*feed)->is_filtering = 0;
-	(*feed)->parent = demux;
-	(*feed)->priv = NULL;
-
-	(*feed)->set = dmx_section_feed_set;
-	(*feed)->allocate_filter = dmx_section_feed_allocate_filter;
-	(*feed)->start_filtering = dmx_section_feed_start_filtering;
-	(*feed)->stop_filtering = dmx_section_feed_stop_filtering;
-	(*feed)->release_filter = dmx_section_feed_release_filter;
-
-	mutex_unlock(&dvbdmx->mutex);
-	return 0;
-}
-
-static int dvbdmx_release_section_feed(struct dmx_demux *demux,
-				       struct dmx_section_feed *feed)
-{
-	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
-	struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
-
-	mutex_lock(&dvbdmx->mutex);
-
-	if (dvbdmxfeed->state == DMX_STATE_FREE) {
-		mutex_unlock(&dvbdmx->mutex);
-		return -EINVAL;
-	}
-#ifndef NOBUFS
-	vfree(dvbdmxfeed->buffer);
-	dvbdmxfeed->buffer = NULL;
-#endif
-	dvbdmxfeed->state = DMX_STATE_FREE;
-
-	dvb_demux_feed_del(dvbdmxfeed);
-
-	dvbdmxfeed->pid = 0xffff;
-
-	mutex_unlock(&dvbdmx->mutex);
-	return 0;
-}
-
-/******************************************************************************
- * dvb_demux kernel data API calls
- ******************************************************************************/
-
-static int dvbdmx_open(struct dmx_demux *demux)
-{
-	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
-	if (dvbdemux->users >= MAX_DVB_DEMUX_USERS)
-		return -EUSERS;
-
-	dvbdemux->users++;
-	return 0;
-}
-
-static int dvbdmx_close(struct dmx_demux *demux)
-{
-	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
-	if (dvbdemux->users == 0)
-		return -ENODEV;
-
-	dvbdemux->users--;
-	//FIXME: release any unneeded resources if users==0
-	return 0;
-}
-
-static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count)
-{
-	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-	void *p;
-
-	if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
-		return -EINVAL;
-
-	p = memdup_user(buf, count);
-	if (IS_ERR(p))
-		return PTR_ERR(p);
-	if (mutex_lock_interruptible(&dvbdemux->mutex)) {
-		kfree(p);
-		return -ERESTARTSYS;
-	}
-	dvb_dmx_swfilter(dvbdemux, p, count);
-	kfree(p);
-	mutex_unlock(&dvbdemux->mutex);
-
-	if (signal_pending(current))
-		return -EINTR;
-	return count;
-}
-
-static int dvbdmx_add_frontend(struct dmx_demux *demux,
-			       struct dmx_frontend *frontend)
-{
-	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-	struct list_head *head = &dvbdemux->frontend_list;
-
-	list_add(&(frontend->connectivity_list), head);
-
-	return 0;
-}
-
-static int dvbdmx_remove_frontend(struct dmx_demux *demux,
-				  struct dmx_frontend *frontend)
-{
-	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-	struct list_head *pos, *n, *head = &dvbdemux->frontend_list;
-
-	list_for_each_safe(pos, n, head) {
-		if (DMX_FE_ENTRY(pos) == frontend) {
-			list_del(pos);
-			return 0;
-		}
-	}
-
-	return -ENODEV;
-}
-
-static struct list_head *dvbdmx_get_frontends(struct dmx_demux *demux)
-{
-	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
-	if (list_empty(&dvbdemux->frontend_list))
-		return NULL;
-
-	return &dvbdemux->frontend_list;
-}
-
-static int dvbdmx_connect_frontend(struct dmx_demux *demux,
-				   struct dmx_frontend *frontend)
-{
-	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
-	if (demux->frontend)
-		return -EINVAL;
-
-	mutex_lock(&dvbdemux->mutex);
-
-	demux->frontend = frontend;
-	mutex_unlock(&dvbdemux->mutex);
-	return 0;
-}
-
-static int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
-{
-	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
-	mutex_lock(&dvbdemux->mutex);
-
-	demux->frontend = NULL;
-	mutex_unlock(&dvbdemux->mutex);
-	return 0;
-}
-
-static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids)
-{
-	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
-	memcpy(pids, dvbdemux->pids, 5 * sizeof(u16));
-	return 0;
-}
-
-int dvb_dmx_init(struct dvb_demux *dvbdemux)
-{
-	int i;
-	struct dmx_demux *dmx = &dvbdemux->dmx;
-
-	dvbdemux->cnt_storage = NULL;
-	dvbdemux->users = 0;
-	dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter));
-
-	if (!dvbdemux->filter)
-		return -ENOMEM;
-
-	dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed));
-	if (!dvbdemux->feed) {
-		vfree(dvbdemux->filter);
-		dvbdemux->filter = NULL;
-		return -ENOMEM;
-	}
-	for (i = 0; i < dvbdemux->filternum; i++) {
-		dvbdemux->filter[i].state = DMX_STATE_FREE;
-		dvbdemux->filter[i].index = i;
-	}
-	for (i = 0; i < dvbdemux->feednum; i++) {
-		dvbdemux->feed[i].state = DMX_STATE_FREE;
-		dvbdemux->feed[i].index = i;
-	}
-
-	dvbdemux->cnt_storage = vmalloc(MAX_PID + 1);
-	if (!dvbdemux->cnt_storage)
-		printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
-
-	INIT_LIST_HEAD(&dvbdemux->frontend_list);
-
-	for (i = 0; i < DMX_TS_PES_OTHER; i++) {
-		dvbdemux->pesfilter[i] = NULL;
-		dvbdemux->pids[i] = 0xffff;
-	}
-
-	INIT_LIST_HEAD(&dvbdemux->feed_list);
-
-	dvbdemux->playing = 0;
-	dvbdemux->recording = 0;
-	dvbdemux->tsbufp = 0;
-
-	if (!dvbdemux->check_crc32)
-		dvbdemux->check_crc32 = dvb_dmx_crc32;
-
-	if (!dvbdemux->memcopy)
-		dvbdemux->memcopy = dvb_dmx_memcopy;
-
-	dmx->frontend = NULL;
-	dmx->priv = dvbdemux;
-	dmx->open = dvbdmx_open;
-	dmx->close = dvbdmx_close;
-	dmx->write = dvbdmx_write;
-	dmx->allocate_ts_feed = dvbdmx_allocate_ts_feed;
-	dmx->release_ts_feed = dvbdmx_release_ts_feed;
-	dmx->allocate_section_feed = dvbdmx_allocate_section_feed;
-	dmx->release_section_feed = dvbdmx_release_section_feed;
-
-	dmx->add_frontend = dvbdmx_add_frontend;
-	dmx->remove_frontend = dvbdmx_remove_frontend;
-	dmx->get_frontends = dvbdmx_get_frontends;
-	dmx->connect_frontend = dvbdmx_connect_frontend;
-	dmx->disconnect_frontend = dvbdmx_disconnect_frontend;
-	dmx->get_pes_pids = dvbdmx_get_pes_pids;
-
-	mutex_init(&dvbdemux->mutex);
-	spin_lock_init(&dvbdemux->lock);
-
-	return 0;
-}
-
-EXPORT_SYMBOL(dvb_dmx_init);
-
-void dvb_dmx_release(struct dvb_demux *dvbdemux)
-{
-	vfree(dvbdemux->cnt_storage);
-	vfree(dvbdemux->filter);
-	vfree(dvbdemux->feed);
-}
-
-EXPORT_SYMBOL(dvb_dmx_release);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
deleted file mode 100644
index fa7188a..0000000
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * dvb_demux.h: DVB kernel demux API
- *
- * Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler
- *                         for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- */
-
-#ifndef _DVB_DEMUX_H_
-#define _DVB_DEMUX_H_
-
-#include <linux/time.h>
-#include <linux/timer.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-
-#include "demux.h"
-
-#define DMX_TYPE_TS  0
-#define DMX_TYPE_SEC 1
-#define DMX_TYPE_PES 2
-
-#define DMX_STATE_FREE      0
-#define DMX_STATE_ALLOCATED 1
-#define DMX_STATE_SET       2
-#define DMX_STATE_READY     3
-#define DMX_STATE_GO        4
-
-#define DVB_DEMUX_MASK_MAX 18
-
-#define MAX_PID 0x1fff
-
-#define SPEED_PKTS_INTERVAL 50000
-
-struct dvb_demux_filter {
-	struct dmx_section_filter filter;
-	u8 maskandmode[DMX_MAX_FILTER_SIZE];
-	u8 maskandnotmode[DMX_MAX_FILTER_SIZE];
-	int doneq;
-
-	struct dvb_demux_filter *next;
-	struct dvb_demux_feed *feed;
-	int index;
-	int state;
-	int type;
-
-	u16 hw_handle;
-	struct timer_list timer;
-};
-
-#define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head)
-
-struct dvb_demux_feed {
-	union {
-		struct dmx_ts_feed ts;
-		struct dmx_section_feed sec;
-	} feed;
-
-	union {
-		dmx_ts_cb ts;
-		dmx_section_cb sec;
-	} cb;
-
-	struct dvb_demux *demux;
-	void *priv;
-	int type;
-	int state;
-	u16 pid;
-	u8 *buffer;
-	int buffer_size;
-
-	struct timespec timeout;
-	struct dvb_demux_filter *filter;
-
-	int ts_type;
-	enum dmx_ts_pes pes_type;
-
-	int cc;
-	int pusi_seen;		/* prevents feeding of garbage from previous section */
-
-	u16 peslen;
-
-	struct list_head list_head;
-	unsigned int index;	/* a unique index for each feed (can be used as hardware pid filter index) */
-};
-
-struct dvb_demux {
-	struct dmx_demux dmx;
-	void *priv;
-	int filternum;
-	int feednum;
-	int (*start_feed)(struct dvb_demux_feed *feed);
-	int (*stop_feed)(struct dvb_demux_feed *feed);
-	int (*write_to_decoder)(struct dvb_demux_feed *feed,
-				 const u8 *buf, size_t len);
-	u32 (*check_crc32)(struct dvb_demux_feed *feed,
-			    const u8 *buf, size_t len);
-	void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst,
-			 const u8 *src, size_t len);
-
-	int users;
-#define MAX_DVB_DEMUX_USERS 10
-	struct dvb_demux_filter *filter;
-	struct dvb_demux_feed *feed;
-
-	struct list_head frontend_list;
-
-	struct dvb_demux_feed *pesfilter[DMX_TS_PES_OTHER];
-	u16 pids[DMX_TS_PES_OTHER];
-	int playing;
-	int recording;
-
-#define DMX_MAX_PID 0x2000
-	struct list_head feed_list;
-	u8 tsbuf[204];
-	int tsbufp;
-
-	struct mutex mutex;
-	spinlock_t lock;
-
-	uint8_t *cnt_storage; /* for TS continuity check */
-
-	struct timespec speed_last_time; /* for TS speed check */
-	uint32_t speed_pkts_cnt; /* for TS speed check */
-};
-
-int dvb_dmx_init(struct dvb_demux *dvbdemux);
-void dvb_dmx_release(struct dvb_demux *dvbdemux);
-void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf,
-			      size_t count);
-void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
-void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf,
-			  size_t count);
-void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf,
-			  size_t count);
-
-#endif /* _DVB_DEMUX_H_ */
diff --git a/drivers/media/dvb/dvb-core/dvb_filter.c b/drivers/media/dvb/dvb-core/dvb_filter.c
deleted file mode 100644
index 772003f..0000000
--- a/drivers/media/dvb/dvb-core/dvb_filter.c
+++ /dev/null
@@ -1,603 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include "dvb_filter.h"
-
-#if 0
-static unsigned int bitrates[3][16] =
-{{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},
- {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0},
- {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}};
-#endif
-
-static u32 freq[4] = {480, 441, 320, 0};
-
-static unsigned int ac3_bitrates[32] =
-    {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640,
-     0,0,0,0,0,0,0,0,0,0,0,0,0};
-
-static u32 ac3_frames[3][32] =
-    {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024,
-      1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0},
-     {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114,
-      1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0},
-     {96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344,
-      1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}};
-
-
-
-#if 0
-static void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv,
-		  void (*pes_write)(u8 *buf, int count, void *data),
-		  void *priv)
-{
-	dvb_filter_ipack_init(pa, IPACKS, pes_write);
-	dvb_filter_ipack_init(pv, IPACKS, pes_write);
-	pa->pid = pida;
-	pv->pid = pidv;
-	pa->data = priv;
-	pv->data = priv;
-}
-#endif
-
-#if 0
-static void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188)
-{
-	u8 off = 0;
-
-	if (!buf || !p ){
-		printk("NULL POINTER IDIOT\n");
-		return;
-	}
-	if (buf[1]&PAY_START) {
-		if (p->plength == MMAX_PLENGTH-6 && p->found>6){
-			p->plength = p->found-6;
-			p->found = 0;
-			send_ipack(p);
-			dvb_filter_ipack_reset(p);
-		}
-	}
-	if (buf[3] & ADAPT_FIELD) {  // adaptation field?
-		off = buf[4] + 1;
-		if (off+4 > 187) return;
-	}
-	dvb_filter_instant_repack(buf+4+off, TS_SIZE-4-off, p);
-}
-#endif
-
-#if 0
-/* needs 5 byte input, returns picture coding type*/
-static int read_picture_header(u8 *headr, struct mpg_picture *pic, int field, int pr)
-{
-	u8 pct;
-
-	if (pr) printk( "Pic header: ");
-	pic->temporal_reference[field] = (( headr[0] << 2 ) |
-					  (headr[1] & 0x03) )& 0x03ff;
-	if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]);
-
-	pct = ( headr[1] >> 2 ) & 0x07;
-	pic->picture_coding_type[field] = pct;
-	if (pr) {
-		switch(pct){
-			case I_FRAME:
-				printk( "  I-FRAME");
-				break;
-			case B_FRAME:
-				printk( "  B-FRAME");
-				break;
-			case P_FRAME:
-				printk( "  P-FRAME");
-				break;
-		}
-	}
-
-
-	pic->vinfo.vbv_delay  = (( headr[1] >> 5 ) | ( headr[2] << 3) |
-				 ( (headr[3] & 0x1F) << 11) ) & 0xffff;
-
-	if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay);
-
-	pic->picture_header_parameter = ( headr[3] & 0xe0 ) |
-		((headr[4] & 0x80) >> 3);
-
-	if ( pct == B_FRAME ){
-		pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f;
-	}
-	if (pr) printk( " pic head param: 0x%x",
-			pic->picture_header_parameter);
-
-	return pct;
-}
-#endif
-
-#if 0
-/* needs 4 byte input */
-static int read_gop_header(u8 *headr, struct mpg_picture *pic, int pr)
-{
-	if (pr) printk("GOP header: ");
-
-	pic->time_code  = (( headr[0] << 17 ) | ( headr[1] << 9) |
-			   ( headr[2] << 1 ) | (headr[3] &0x01)) & 0x1ffffff;
-
-	if (pr) printk(" time: %d:%d.%d ", (headr[0]>>2)& 0x1F,
-		       ((headr[0]<<4)& 0x30)| ((headr[1]>>4)& 0x0F),
-		       ((headr[1]<<3)& 0x38)| ((headr[2]>>5)& 0x0F));
-
-	if ( ( headr[3] & 0x40 ) != 0 ){
-		pic->closed_gop = 1;
-	} else {
-		pic->closed_gop = 0;
-	}
-	if (pr) printk("closed: %d", pic->closed_gop);
-
-	if ( ( headr[3] & 0x20 ) != 0 ){
-		pic->broken_link = 1;
-	} else {
-		pic->broken_link = 0;
-	}
-	if (pr) printk(" broken: %d\n", pic->broken_link);
-
-	return 0;
-}
-#endif
-
-#if 0
-/* needs 8 byte input */
-static int read_sequence_header(u8 *headr, struct dvb_video_info *vi, int pr)
-{
-	int sw;
-	int form = -1;
-
-	if (pr) printk("Reading sequence header\n");
-
-	vi->horizontal_size	= ((headr[1] &0xF0) >> 4) | (headr[0] << 4);
-	vi->vertical_size	= ((headr[1] &0x0F) << 8) | (headr[2]);
-
-	sw = (int)((headr[3]&0xF0) >> 4) ;
-
-	switch( sw ){
-	case 1:
-		if (pr)
-			printk("Videostream: ASPECT: 1:1");
-		vi->aspect_ratio = 100;
-		break;
-	case 2:
-		if (pr)
-			printk("Videostream: ASPECT: 4:3");
-		vi->aspect_ratio = 133;
-		break;
-	case 3:
-		if (pr)
-			printk("Videostream: ASPECT: 16:9");
-		vi->aspect_ratio = 177;
-		break;
-	case 4:
-		if (pr)
-			printk("Videostream: ASPECT: 2.21:1");
-		vi->aspect_ratio = 221;
-		break;
-
-	case 5 ... 15:
-		if (pr)
-			printk("Videostream: ASPECT: reserved");
-		vi->aspect_ratio = 0;
-		break;
-
-	default:
-		vi->aspect_ratio = 0;
-		return -1;
-	}
-
-	if (pr)
-		printk("  Size = %dx%d",vi->horizontal_size,vi->vertical_size);
-
-	sw = (int)(headr[3]&0x0F);
-
-	switch ( sw ) {
-	case 1:
-		if (pr)
-			printk("  FRate: 23.976 fps");
-		vi->framerate = 23976;
-		form = -1;
-		break;
-	case 2:
-		if (pr)
-			printk("  FRate: 24 fps");
-		vi->framerate = 24000;
-		form = -1;
-		break;
-	case 3:
-		if (pr)
-			printk("  FRate: 25 fps");
-		vi->framerate = 25000;
-		form = VIDEO_MODE_PAL;
-		break;
-	case 4:
-		if (pr)
-			printk("  FRate: 29.97 fps");
-		vi->framerate = 29970;
-		form = VIDEO_MODE_NTSC;
-		break;
-	case 5:
-		if (pr)
-			printk("  FRate: 30 fps");
-		vi->framerate = 30000;
-		form = VIDEO_MODE_NTSC;
-		break;
-	case 6:
-		if (pr)
-			printk("  FRate: 50 fps");
-		vi->framerate = 50000;
-		form = VIDEO_MODE_PAL;
-		break;
-	case 7:
-		if (pr)
-			printk("  FRate: 60 fps");
-		vi->framerate = 60000;
-		form = VIDEO_MODE_NTSC;
-		break;
-	}
-
-	vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03);
-
-	vi->vbv_buffer_size
-		= (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5);
-
-	if (pr){
-		printk("  BRate: %d Mbit/s",4*(vi->bit_rate)/10000);
-		printk("  vbvbuffer %d",16*1024*(vi->vbv_buffer_size));
-		printk("\n");
-	}
-
-	vi->video_format = form;
-
-	return 0;
-}
-#endif
-
-
-#if 0
-static int get_vinfo(u8 *mbuf, int count, struct dvb_video_info *vi, int pr)
-{
-	u8 *headr;
-	int found = 0;
-	int c = 0;
-
-	while (found < 4 && c+4 < count){
-		u8 *b;
-
-		b = mbuf+c;
-		if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01
-		     && b[3] == 0xb3) found = 4;
-		else {
-			c++;
-		}
-	}
-
-	if (! found) return -1;
-	c += 4;
-	if (c+12 >= count) return -1;
-	headr = mbuf+c;
-	if (read_sequence_header(headr, vi, pr) < 0) return -1;
-	vi->off = c-4;
-	return 0;
-}
-#endif
-
-
-#if 0
-static int get_ainfo(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr)
-{
-	u8 *headr;
-	int found = 0;
-	int c = 0;
-	int fr = 0;
-
-	while (found < 2 && c < count){
-		u8 b[2];
-		memcpy( b, mbuf+c, 2);
-
-		if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8)
-			found = 2;
-		else {
-			c++;
-		}
-	}
-
-	if (!found) return -1;
-
-	if (c+3 >= count) return -1;
-	headr = mbuf+c;
-
-	ai->layer = (headr[1] & 0x06) >> 1;
-
-	if (pr)
-		printk("Audiostream: Layer: %d", 4-ai->layer);
-
-
-	ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000;
-
-	if (pr){
-		if (ai->bit_rate == 0)
-			printk("  Bit rate: free");
-		else if (ai->bit_rate == 0xf)
-			printk("  BRate: reserved");
-		else
-			printk("  BRate: %d kb/s", ai->bit_rate/1000);
-	}
-
-	fr = (headr[2] & 0x0c ) >> 2;
-	ai->frequency = freq[fr]*100;
-	if (pr){
-		if (ai->frequency == 3)
-			printk("  Freq: reserved\n");
-		else
-			printk("  Freq: %d kHz\n",ai->frequency);
-
-	}
-	ai->off = c;
-	return 0;
-}
-#endif
-
-
-int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr)
-{
-	u8 *headr;
-	int found = 0;
-	int c = 0;
-	u8 frame = 0;
-	int fr = 0;
-
-	while ( !found  && c < count){
-		u8 *b = mbuf+c;
-
-		if ( b[0] == 0x0b &&  b[1] == 0x77 )
-			found = 1;
-		else {
-			c++;
-		}
-	}
-
-	if (!found) return -1;
-	if (pr)
-		printk("Audiostream: AC3");
-
-	ai->off = c;
-	if (c+5 >= count) return -1;
-
-	ai->layer = 0;  // 0 for AC3
-	headr = mbuf+c+2;
-
-	frame = (headr[2]&0x3f);
-	ai->bit_rate = ac3_bitrates[frame >> 1]*1000;
-
-	if (pr)
-		printk("  BRate: %d kb/s", (int) ai->bit_rate/1000);
-
-	ai->frequency = (headr[2] & 0xc0 ) >> 6;
-	fr = (headr[2] & 0xc0 ) >> 6;
-	ai->frequency = freq[fr]*100;
-	if (pr) printk ("  Freq: %d Hz\n", (int) ai->frequency);
-
-
-	ai->framesize = ac3_frames[fr][frame >> 1];
-	if ((frame & 1) &&  (fr == 1)) ai->framesize++;
-	ai->framesize = ai->framesize << 1;
-	if (pr) printk ("  Framesize %d\n",(int) ai->framesize);
-
-
-	return 0;
-}
-EXPORT_SYMBOL(dvb_filter_get_ac3info);
-
-
-#if 0
-static u8 *skip_pes_header(u8 **bufp)
-{
-	u8 *inbuf = *bufp;
-	u8 *buf = inbuf;
-	u8 *pts = NULL;
-	int skip = 0;
-
-	static const int mpeg1_skip_table[16] = {
-		1, 0xffff,      5,     10, 0xffff, 0xffff, 0xffff, 0xffff,
-		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
-	};
-
-
-	if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */
-		if (buf[7] & PTS_ONLY)
-			pts = buf+9;
-		else pts = NULL;
-		buf = inbuf + 9 + inbuf[8];
-	} else {        /* mpeg1 */
-		for (buf = inbuf + 6; *buf == 0xff; buf++)
-			if (buf == inbuf + 6 + 16) {
-				break;
-			}
-		if ((*buf & 0xc0) == 0x40)
-			buf += 2;
-		skip = mpeg1_skip_table [*buf >> 4];
-		if (skip == 5 || skip == 10) pts = buf;
-		else pts = NULL;
-
-		buf += mpeg1_skip_table [*buf >> 4];
-	}
-
-	*bufp = buf;
-	return pts;
-}
-#endif
-
-#if 0
-static void initialize_quant_matrix( u32 *matrix )
-{
-	int i;
-
-	matrix[0]  = 0x08101013;
-	matrix[1]  = 0x10131616;
-	matrix[2]  = 0x16161616;
-	matrix[3]  = 0x1a181a1b;
-	matrix[4]  = 0x1b1b1a1a;
-	matrix[5]  = 0x1a1a1b1b;
-	matrix[6]  = 0x1b1d1d1d;
-	matrix[7]  = 0x2222221d;
-	matrix[8]  = 0x1d1d1b1b;
-	matrix[9]  = 0x1d1d2020;
-	matrix[10] = 0x22222526;
-	matrix[11] = 0x25232322;
-	matrix[12] = 0x23262628;
-	matrix[13] = 0x28283030;
-	matrix[14] = 0x2e2e3838;
-	matrix[15] = 0x3a454553;
-
-	for ( i = 16 ; i < 32 ; i++ )
-		matrix[i] = 0x10101010;
-}
-#endif
-
-#if 0
-static void initialize_mpg_picture(struct mpg_picture *pic)
-{
-	int i;
-
-	/* set MPEG1 */
-	pic->mpeg1_flag = 1;
-	pic->profile_and_level = 0x4A ;        /* MP@LL */
-	pic->progressive_sequence = 1;
-	pic->low_delay = 0;
-
-	pic->sequence_display_extension_flag = 0;
-	for ( i = 0 ; i < 4 ; i++ ){
-		pic->frame_centre_horizontal_offset[i] = 0;
-		pic->frame_centre_vertical_offset[i] = 0;
-	}
-	pic->last_frame_centre_horizontal_offset = 0;
-	pic->last_frame_centre_vertical_offset = 0;
-
-	pic->picture_display_extension_flag[0] = 0;
-	pic->picture_display_extension_flag[1] = 0;
-	pic->sequence_header_flag = 0;
-	pic->gop_flag = 0;
-	pic->sequence_end_flag = 0;
-}
-#endif
-
-#if 0
-static void mpg_set_picture_parameter( int32_t field_type, struct mpg_picture *pic )
-{
-	int16_t last_h_offset;
-	int16_t last_v_offset;
-
-	int16_t *p_h_offset;
-	int16_t *p_v_offset;
-
-	if ( pic->mpeg1_flag ){
-		pic->picture_structure[field_type] = VIDEO_FRAME_PICTURE;
-		pic->top_field_first = 0;
-		pic->repeat_first_field = 0;
-		pic->progressive_frame = 1;
-		pic->picture_coding_parameter = 0x000010;
-	}
-
-	/* Reset flag */
-	pic->picture_display_extension_flag[field_type] = 0;
-
-	last_h_offset = pic->last_frame_centre_horizontal_offset;
-	last_v_offset = pic->last_frame_centre_vertical_offset;
-	if ( field_type == FIRST_FIELD ){
-		p_h_offset = pic->frame_centre_horizontal_offset;
-		p_v_offset = pic->frame_centre_vertical_offset;
-		*p_h_offset = last_h_offset;
-		*(p_h_offset + 1) = last_h_offset;
-		*(p_h_offset + 2) = last_h_offset;
-		*p_v_offset = last_v_offset;
-		*(p_v_offset + 1) = last_v_offset;
-		*(p_v_offset + 2) = last_v_offset;
-	} else {
-		pic->frame_centre_horizontal_offset[3] = last_h_offset;
-		pic->frame_centre_vertical_offset[3] = last_v_offset;
-	}
-}
-#endif
-
-#if 0
-static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_type)
-{
-	pic->picture_header = 0;
-	pic->sequence_header_data
-		= ( INIT_HORIZONTAL_SIZE << 20 )
-			| ( INIT_VERTICAL_SIZE << 8 )
-			| ( INIT_ASPECT_RATIO << 4 )
-			| ( INIT_FRAME_RATE );
-	pic->mpeg1_flag = 0;
-	pic->vinfo.horizontal_size
-		= INIT_DISP_HORIZONTAL_SIZE;
-	pic->vinfo.vertical_size
-		= INIT_DISP_VERTICAL_SIZE;
-	pic->picture_display_extension_flag[field_type]
-		= 0;
-	pic->pts_flag[field_type] = 0;
-
-	pic->sequence_gop_header = 0;
-	pic->picture_header = 0;
-	pic->sequence_header_flag = 0;
-	pic->gop_flag = 0;
-	pic->sequence_end_flag = 0;
-	pic->sequence_display_extension_flag = 0;
-	pic->last_frame_centre_horizontal_offset = 0;
-	pic->last_frame_centre_vertical_offset = 0;
-	pic->channel = chan;
-}
-#endif
-
-void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
-			    dvb_filter_pes2ts_cb_t *cb, void *priv)
-{
-	unsigned char *buf=p2ts->buf;
-
-	buf[0]=0x47;
-	buf[1]=(pid>>8);
-	buf[2]=pid&0xff;
-	p2ts->cc=0;
-	p2ts->cb=cb;
-	p2ts->priv=priv;
-}
-EXPORT_SYMBOL(dvb_filter_pes2ts_init);
-
-int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
-		      int len, int payload_start)
-{
-	unsigned char *buf=p2ts->buf;
-	int ret=0, rest;
-
-	//len=6+((pes[4]<<8)|pes[5]);
-
-	if (payload_start)
-		buf[1]|=0x40;
-	else
-		buf[1]&=~0x40;
-	while (len>=184) {
-		buf[3]=0x10|((p2ts->cc++)&0x0f);
-		memcpy(buf+4, pes, 184);
-		if ((ret=p2ts->cb(p2ts->priv, buf)))
-			return ret;
-		len-=184; pes+=184;
-		buf[1]&=~0x40;
-	}
-	if (!len)
-		return 0;
-	buf[3]=0x30|((p2ts->cc++)&0x0f);
-	rest=183-len;
-	if (rest) {
-		buf[5]=0x00;
-		if (rest-1)
-			memset(buf+6, 0xff, rest-1);
-	}
-	buf[4]=rest;
-	memcpy(buf+5+rest, pes, len);
-	return p2ts->cb(p2ts->priv, buf);
-}
-EXPORT_SYMBOL(dvb_filter_pes2ts);
diff --git a/drivers/media/dvb/dvb-core/dvb_filter.h b/drivers/media/dvb/dvb-core/dvb_filter.h
deleted file mode 100644
index 375e3be..0000000
--- a/drivers/media/dvb/dvb-core/dvb_filter.h
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * dvb_filter.h
- *
- * Copyright (C) 2003 Convergence GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#ifndef _DVB_FILTER_H_
-#define _DVB_FILTER_H_
-
-#include <linux/slab.h>
-
-#include "demux.h"
-
-typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *);
-
-struct dvb_filter_pes2ts {
-	unsigned char buf[188];
-	unsigned char cc;
-	dvb_filter_pes2ts_cb_t *cb;
-	void *priv;
-};
-
-void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
-			    dvb_filter_pes2ts_cb_t *cb, void *priv);
-
-int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
-		      int len, int payload_start);
-
-
-#define PROG_STREAM_MAP  0xBC
-#define PRIVATE_STREAM1  0xBD
-#define PADDING_STREAM   0xBE
-#define PRIVATE_STREAM2  0xBF
-#define AUDIO_STREAM_S   0xC0
-#define AUDIO_STREAM_E   0xDF
-#define VIDEO_STREAM_S   0xE0
-#define VIDEO_STREAM_E   0xEF
-#define ECM_STREAM       0xF0
-#define EMM_STREAM       0xF1
-#define DSM_CC_STREAM    0xF2
-#define ISO13522_STREAM  0xF3
-#define PROG_STREAM_DIR  0xFF
-
-#define DVB_PICTURE_START    0x00
-#define DVB_USER_START       0xb2
-#define DVB_SEQUENCE_HEADER  0xb3
-#define DVB_SEQUENCE_ERROR   0xb4
-#define DVB_EXTENSION_START  0xb5
-#define DVB_SEQUENCE_END     0xb7
-#define DVB_GOP_START        0xb8
-#define DVB_EXCEPT_SLICE     0xb0
-
-#define SEQUENCE_EXTENSION           0x01
-#define SEQUENCE_DISPLAY_EXTENSION   0x02
-#define PICTURE_CODING_EXTENSION     0x08
-#define QUANT_MATRIX_EXTENSION       0x03
-#define PICTURE_DISPLAY_EXTENSION    0x07
-
-#define I_FRAME 0x01
-#define B_FRAME 0x02
-#define P_FRAME 0x03
-
-/* Initialize sequence_data */
-#define INIT_HORIZONTAL_SIZE        720
-#define INIT_VERTICAL_SIZE          576
-#define INIT_ASPECT_RATIO          0x02
-#define INIT_FRAME_RATE            0x03
-#define INIT_DISP_HORIZONTAL_SIZE   540
-#define INIT_DISP_VERTICAL_SIZE     576
-
-
-//flags2
-#define PTS_DTS_FLAGS    0xC0
-#define ESCR_FLAG        0x20
-#define ES_RATE_FLAG     0x10
-#define DSM_TRICK_FLAG   0x08
-#define ADD_CPY_FLAG     0x04
-#define PES_CRC_FLAG     0x02
-#define PES_EXT_FLAG     0x01
-
-//pts_dts flags
-#define PTS_ONLY         0x80
-#define PTS_DTS          0xC0
-
-#define TS_SIZE        188
-#define TRANS_ERROR    0x80
-#define PAY_START      0x40
-#define TRANS_PRIO     0x20
-#define PID_MASK_HI    0x1F
-//flags
-#define TRANS_SCRMBL1  0x80
-#define TRANS_SCRMBL2  0x40
-#define ADAPT_FIELD    0x20
-#define PAYLOAD        0x10
-#define COUNT_MASK     0x0F
-
-// adaptation flags
-#define DISCON_IND     0x80
-#define RAND_ACC_IND   0x40
-#define ES_PRI_IND     0x20
-#define PCR_FLAG       0x10
-#define OPCR_FLAG      0x08
-#define SPLICE_FLAG    0x04
-#define TRANS_PRIV     0x02
-#define ADAP_EXT_FLAG  0x01
-
-// adaptation extension flags
-#define LTW_FLAG       0x80
-#define PIECE_RATE     0x40
-#define SEAM_SPLICE    0x20
-
-
-#define MAX_PLENGTH 0xFFFF
-#define MMAX_PLENGTH (256*MAX_PLENGTH)
-
-#ifndef IPACKS
-#define IPACKS 2048
-#endif
-
-struct ipack {
-	int size;
-	int found;
-	u8 *buf;
-	u8 cid;
-	u32 plength;
-	u8 plen[2];
-	u8 flag1;
-	u8 flag2;
-	u8 hlength;
-	u8 pts[5];
-	u16 *pid;
-	int mpeg;
-	u8 check;
-	int which;
-	int done;
-	void *data;
-	void (*func)(u8 *buf,  int size, void *priv);
-	int count;
-	int repack_subids;
-};
-
-struct dvb_video_info {
-	u32 horizontal_size;
-	u32 vertical_size;
-	u32 aspect_ratio;
-	u32 framerate;
-	u32 video_format;
-	u32 bit_rate;
-	u32 comp_bit_rate;
-	u32 vbv_buffer_size;
-	s16 vbv_delay;
-	u32 CSPF;
-	u32 off;
-};
-
-#define OFF_SIZE 4
-#define FIRST_FIELD 0
-#define SECOND_FIELD 1
-#define VIDEO_FRAME_PICTURE 0x03
-
-struct mpg_picture {
-	int       channel;
-	struct dvb_video_info vinfo;
-	u32      *sequence_gop_header;
-	u32      *picture_header;
-	s32       time_code;
-	int       low_delay;
-	int       closed_gop;
-	int       broken_link;
-	int       sequence_header_flag;
-	int       gop_flag;
-	int       sequence_end_flag;
-
-	u8        profile_and_level;
-	s32       picture_coding_parameter;
-	u32       matrix[32];
-	s8        matrix_change_flag;
-
-	u8        picture_header_parameter;
-  /* bit 0 - 2: bwd f code
-     bit 3    : fpb vector
-     bit 4 - 6: fwd f code
-     bit 7    : fpf vector */
-
-	int       mpeg1_flag;
-	int       progressive_sequence;
-	int       sequence_display_extension_flag;
-	u32       sequence_header_data;
-	s16       last_frame_centre_horizontal_offset;
-	s16       last_frame_centre_vertical_offset;
-
-	u32       pts[2]; /* [0] 1st field, [1] 2nd field */
-	int       top_field_first;
-	int       repeat_first_field;
-	int       progressive_frame;
-	int       bank;
-	int       forward_bank;
-	int       backward_bank;
-	int       compress;
-	s16       frame_centre_horizontal_offset[OFF_SIZE];
-		  /* [0-2] 1st field, [3] 2nd field */
-	s16       frame_centre_vertical_offset[OFF_SIZE];
-		  /* [0-2] 1st field, [3] 2nd field */
-	s16       temporal_reference[2];
-		  /* [0] 1st field, [1] 2nd field */
-
-	s8        picture_coding_type[2];
-		  /* [0] 1st field, [1] 2nd field */
-	s8        picture_structure[2];
-		  /* [0] 1st field, [1] 2nd field */
-	s8        picture_display_extension_flag[2];
-		  /* [0] 1st field, [1] 2nd field */
-		  /* picture_display_extenion() 0:no 1:exit*/
-	s8        pts_flag[2];
-		  /* [0] 1st field, [1] 2nd field */
-};
-
-struct dvb_audio_info {
-	int layer;
-	u32 bit_rate;
-	u32 frequency;
-	u32 mode;
-	u32 mode_extension ;
-	u32 emphasis;
-	u32 framesize;
-	u32 off;
-};
-
-int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr);
-
-
-#endif
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
deleted file mode 100644
index aebcdf2..0000000
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ /dev/null
@@ -1,2563 +0,0 @@
-/*
- * dvb_frontend.c: DVB frontend tuning interface/thread
- *
- *
- * Copyright (C) 1999-2001 Ralph  Metzler
- *			   Marcus Metzler
- *			   Holger Waechtler
- *				      for convergence integrated media GmbH
- *
- * Copyright (C) 2004 Andrew de Quincey (tuning thread cleanup)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-/* Enables DVBv3 compatibility bits at the headers */
-#define __DVB_CORE__
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/semaphore.h>
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/freezer.h>
-#include <linux/jiffies.h>
-#include <linux/kthread.h>
-#include <asm/processor.h>
-
-#include "dvb_frontend.h"
-#include "dvbdev.h"
-#include <linux/dvb/version.h>
-
-static int dvb_frontend_debug;
-static int dvb_shutdown_timeout;
-static int dvb_force_auto_inversion;
-static int dvb_override_tune_delay;
-static int dvb_powerdown_on_sleep = 1;
-static int dvb_mfe_wait_time = 5;
-
-module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
-MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off).");
-module_param(dvb_shutdown_timeout, int, 0644);
-MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");
-module_param(dvb_force_auto_inversion, int, 0644);
-MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always");
-module_param(dvb_override_tune_delay, int, 0644);
-MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
-module_param(dvb_powerdown_on_sleep, int, 0644);
-MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");
-module_param(dvb_mfe_wait_time, int, 0644);
-MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)");
-
-#define dprintk if (dvb_frontend_debug) printk
-
-#define FESTATE_IDLE 1
-#define FESTATE_RETUNE 2
-#define FESTATE_TUNING_FAST 4
-#define FESTATE_TUNING_SLOW 8
-#define FESTATE_TUNED 16
-#define FESTATE_ZIGZAG_FAST 32
-#define FESTATE_ZIGZAG_SLOW 64
-#define FESTATE_DISEQC 128
-#define FESTATE_ERROR 256
-#define FESTATE_WAITFORLOCK (FESTATE_TUNING_FAST | FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW | FESTATE_DISEQC)
-#define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST)
-#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
-#define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
-
-#define FE_ALGO_HW		1
-/*
- * FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
- * FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.
- * FESTATE_TUNING_FAST. Tuning parameters have been supplied and fast zigzag scan is in progress.
- * FESTATE_TUNING_SLOW. Tuning parameters have been supplied. Fast zigzag failed, so we're trying again, but slower.
- * FESTATE_TUNED. The frontend has successfully locked on.
- * FESTATE_ZIGZAG_FAST. The lock has been lost, and a fast zigzag has been initiated to try and regain it.
- * FESTATE_ZIGZAG_SLOW. The lock has been lost. Fast zigzag has been failed, so we're trying again, but slower.
- * FESTATE_DISEQC. A DISEQC command has just been issued.
- * FESTATE_WAITFORLOCK. When we're waiting for a lock.
- * FESTATE_SEARCHING_FAST. When we're searching for a signal using a fast zigzag scan.
- * FESTATE_SEARCHING_SLOW. When we're searching for a signal using a slow zigzag scan.
- * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
- */
-
-#define DVB_FE_NO_EXIT	0
-#define DVB_FE_NORMAL_EXIT	1
-#define DVB_FE_DEVICE_REMOVED	2
-
-static DEFINE_MUTEX(frontend_mutex);
-
-struct dvb_frontend_private {
-
-	/* thread/frontend values */
-	struct dvb_device *dvbdev;
-	struct dvb_frontend_parameters parameters_out;
-	struct dvb_fe_events events;
-	struct semaphore sem;
-	struct list_head list_head;
-	wait_queue_head_t wait_queue;
-	struct task_struct *thread;
-	unsigned long release_jiffies;
-	unsigned int exit;
-	unsigned int wakeup;
-	fe_status_t status;
-	unsigned long tune_mode_flags;
-	unsigned int delay;
-	unsigned int reinitialise;
-	int tone;
-	int voltage;
-
-	/* swzigzag values */
-	unsigned int state;
-	unsigned int bending;
-	int lnb_drift;
-	unsigned int inversion;
-	unsigned int auto_step;
-	unsigned int auto_sub_step;
-	unsigned int started_auto_step;
-	unsigned int min_delay;
-	unsigned int max_drift;
-	unsigned int step_size;
-	int quality;
-	unsigned int check_wrapped;
-	enum dvbfe_search algo_status;
-};
-
-static void dvb_frontend_wakeup(struct dvb_frontend *fe);
-static int dtv_get_frontend(struct dvb_frontend *fe,
-			    struct dvb_frontend_parameters *p_out);
-static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
-					   struct dvb_frontend_parameters *p);
-
-static bool has_get_frontend(struct dvb_frontend *fe)
-{
-	return fe->ops.get_frontend != NULL;
-}
-
-/*
- * Due to DVBv3 API calls, a delivery system should be mapped into one of
- * the 4 DVBv3 delivery systems (FE_QPSK, FE_QAM, FE_OFDM or FE_ATSC),
- * otherwise, a DVBv3 call will fail.
- */
-enum dvbv3_emulation_type {
-	DVBV3_UNKNOWN,
-	DVBV3_QPSK,
-	DVBV3_QAM,
-	DVBV3_OFDM,
-	DVBV3_ATSC,
-};
-
-static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system)
-{
-	switch (delivery_system) {
-	case SYS_DVBC_ANNEX_A:
-	case SYS_DVBC_ANNEX_C:
-		return DVBV3_QAM;
-	case SYS_DVBS:
-	case SYS_DVBS2:
-	case SYS_TURBO:
-	case SYS_ISDBS:
-	case SYS_DSS:
-		return DVBV3_QPSK;
-	case SYS_DVBT:
-	case SYS_DVBT2:
-	case SYS_ISDBT:
-	case SYS_DMBTH:
-		return DVBV3_OFDM;
-	case SYS_ATSC:
-	case SYS_ATSCMH:
-	case SYS_DVBC_ANNEX_B:
-		return DVBV3_ATSC;
-	case SYS_UNDEFINED:
-	case SYS_ISDBC:
-	case SYS_DVBH:
-	case SYS_DAB:
-	default:
-		/*
-		 * Doesn't know how to emulate those types and/or
-		 * there's no frontend driver from this type yet
-		 * with some emulation code, so, we're not sure yet how
-		 * to handle them, or they're not compatible with a DVBv3 call.
-		 */
-		return DVBV3_UNKNOWN;
-	}
-}
-
-static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
-{
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-	struct dvb_fe_events *events = &fepriv->events;
-	struct dvb_frontend_event *e;
-	int wp;
-
-	dprintk ("%s\n", __func__);
-
-	if ((status & FE_HAS_LOCK) && has_get_frontend(fe))
-		dtv_get_frontend(fe, &fepriv->parameters_out);
-
-	mutex_lock(&events->mtx);
-
-	wp = (events->eventw + 1) % MAX_EVENT;
-	if (wp == events->eventr) {
-		events->overflow = 1;
-		events->eventr = (events->eventr + 1) % MAX_EVENT;
-	}
-
-	e = &events->events[events->eventw];
-	e->status = status;
-	e->parameters = fepriv->parameters_out;
-
-	events->eventw = wp;
-
-	mutex_unlock(&events->mtx);
-
-	wake_up_interruptible (&events->wait_queue);
-}
-
-static int dvb_frontend_get_event(struct dvb_frontend *fe,
-			    struct dvb_frontend_event *event, int flags)
-{
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-	struct dvb_fe_events *events = &fepriv->events;
-
-	dprintk ("%s\n", __func__);
-
-	if (events->overflow) {
-		events->overflow = 0;
-		return -EOVERFLOW;
-	}
-
-	if (events->eventw == events->eventr) {
-		int ret;
-
-		if (flags & O_NONBLOCK)
-			return -EWOULDBLOCK;
-
-		up(&fepriv->sem);
-
-		ret = wait_event_interruptible (events->wait_queue,
-						events->eventw != events->eventr);
-
-		if (down_interruptible (&fepriv->sem))
-			return -ERESTARTSYS;
-
-		if (ret < 0)
-			return ret;
-	}
-
-	mutex_lock(&events->mtx);
-	*event = events->events[events->eventr];
-	events->eventr = (events->eventr + 1) % MAX_EVENT;
-	mutex_unlock(&events->mtx);
-
-	return 0;
-}
-
-static void dvb_frontend_clear_events(struct dvb_frontend *fe)
-{
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-	struct dvb_fe_events *events = &fepriv->events;
-
-	mutex_lock(&events->mtx);
-	events->eventr = events->eventw;
-	mutex_unlock(&events->mtx);
-}
-
-static void dvb_frontend_init(struct dvb_frontend *fe)
-{
-	dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n",
-		 fe->dvb->num,
-		 fe->id,
-		 fe->ops.info.name);
-
-	if (fe->ops.init)
-		fe->ops.init(fe);
-	if (fe->ops.tuner_ops.init) {
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-		fe->ops.tuner_ops.init(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-}
-
-void dvb_frontend_reinitialise(struct dvb_frontend *fe)
-{
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
-	fepriv->reinitialise = 1;
-	dvb_frontend_wakeup(fe);
-}
-EXPORT_SYMBOL(dvb_frontend_reinitialise);
-
-static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked)
-{
-	int q2;
-
-	dprintk ("%s\n", __func__);
-
-	if (locked)
-		(fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256;
-	else
-		(fepriv->quality) = (fepriv->quality * 220 + 0) / 256;
-
-	q2 = fepriv->quality - 128;
-	q2 *= q2;
-
-	fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128);
-}
-
-/**
- * Performs automatic twiddling of frontend parameters.
- *
- * @param fe The frontend concerned.
- * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT
- * @returns Number of complete iterations that have been performed.
- */
-static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped)
-{
-	int autoinversion;
-	int ready = 0;
-	int fe_set_err = 0;
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp;
-	int original_inversion = c->inversion;
-	u32 original_frequency = c->frequency;
-
-	/* are we using autoinversion? */
-	autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
-			 (c->inversion == INVERSION_AUTO));
-
-	/* setup parameters correctly */
-	while(!ready) {
-		/* calculate the lnb_drift */
-		fepriv->lnb_drift = fepriv->auto_step * fepriv->step_size;
-
-		/* wrap the auto_step if we've exceeded the maximum drift */
-		if (fepriv->lnb_drift > fepriv->max_drift) {
-			fepriv->auto_step = 0;
-			fepriv->auto_sub_step = 0;
-			fepriv->lnb_drift = 0;
-		}
-
-		/* perform inversion and +/- zigzag */
-		switch(fepriv->auto_sub_step) {
-		case 0:
-			/* try with the current inversion and current drift setting */
-			ready = 1;
-			break;
-
-		case 1:
-			if (!autoinversion) break;
-
-			fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
-			ready = 1;
-			break;
-
-		case 2:
-			if (fepriv->lnb_drift == 0) break;
-
-			fepriv->lnb_drift = -fepriv->lnb_drift;
-			ready = 1;
-			break;
-
-		case 3:
-			if (fepriv->lnb_drift == 0) break;
-			if (!autoinversion) break;
-
-			fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
-			fepriv->lnb_drift = -fepriv->lnb_drift;
-			ready = 1;
-			break;
-
-		default:
-			fepriv->auto_step++;
-			fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */
-			break;
-		}
-
-		if (!ready) fepriv->auto_sub_step++;
-	}
-
-	/* if this attempt would hit where we started, indicate a complete
-	 * iteration has occurred */
-	if ((fepriv->auto_step == fepriv->started_auto_step) &&
-	    (fepriv->auto_sub_step == 0) && check_wrapped) {
-		return 1;
-	}
-
-	dprintk("%s: drift:%i inversion:%i auto_step:%i "
-		"auto_sub_step:%i started_auto_step:%i\n",
-		__func__, fepriv->lnb_drift, fepriv->inversion,
-		fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
-
-	/* set the frontend itself */
-	c->frequency += fepriv->lnb_drift;
-	if (autoinversion)
-		c->inversion = fepriv->inversion;
-	tmp = *c;
-	if (fe->ops.set_frontend)
-		fe_set_err = fe->ops.set_frontend(fe);
-	*c = tmp;
-	if (fe_set_err < 0) {
-		fepriv->state = FESTATE_ERROR;
-		return fe_set_err;
-	}
-
-	c->frequency = original_frequency;
-	c->inversion = original_inversion;
-
-	fepriv->auto_sub_step++;
-	return 0;
-}
-
-static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
-{
-	fe_status_t s = 0;
-	int retval = 0;
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp;
-
-	/* if we've got no parameters, just keep idling */
-	if (fepriv->state & FESTATE_IDLE) {
-		fepriv->delay = 3*HZ;
-		fepriv->quality = 0;
-		return;
-	}
-
-	/* in SCAN mode, we just set the frontend when asked and leave it alone */
-	if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
-		if (fepriv->state & FESTATE_RETUNE) {
-			tmp = *c;
-			if (fe->ops.set_frontend)
-				retval = fe->ops.set_frontend(fe);
-			*c = tmp;
-			if (retval < 0)
-				fepriv->state = FESTATE_ERROR;
-			else
-				fepriv->state = FESTATE_TUNED;
-		}
-		fepriv->delay = 3*HZ;
-		fepriv->quality = 0;
-		return;
-	}
-
-	/* get the frontend status */
-	if (fepriv->state & FESTATE_RETUNE) {
-		s = 0;
-	} else {
-		if (fe->ops.read_status)
-			fe->ops.read_status(fe, &s);
-		if (s != fepriv->status) {
-			dvb_frontend_add_event(fe, s);
-			fepriv->status = s;
-		}
-	}
-
-	/* if we're not tuned, and we have a lock, move to the TUNED state */
-	if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
-		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
-		fepriv->state = FESTATE_TUNED;
-
-		/* if we're tuned, then we have determined the correct inversion */
-		if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
-		    (c->inversion == INVERSION_AUTO)) {
-			c->inversion = fepriv->inversion;
-		}
-		return;
-	}
-
-	/* if we are tuned already, check we're still locked */
-	if (fepriv->state & FESTATE_TUNED) {
-		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
-
-		/* we're tuned, and the lock is still good... */
-		if (s & FE_HAS_LOCK) {
-			return;
-		} else { /* if we _WERE_ tuned, but now don't have a lock */
-			fepriv->state = FESTATE_ZIGZAG_FAST;
-			fepriv->started_auto_step = fepriv->auto_step;
-			fepriv->check_wrapped = 0;
-		}
-	}
-
-	/* don't actually do anything if we're in the LOSTLOCK state,
-	 * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
-	if ((fepriv->state & FESTATE_LOSTLOCK) &&
-	    (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
-		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
-		return;
-	}
-
-	/* don't do anything if we're in the DISEQC state, since this
-	 * might be someone with a motorized dish controlled by DISEQC.
-	 * If its actually a re-tune, there will be a SET_FRONTEND soon enough.	*/
-	if (fepriv->state & FESTATE_DISEQC) {
-		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
-		return;
-	}
-
-	/* if we're in the RETUNE state, set everything up for a brand
-	 * new scan, keeping the current inversion setting, as the next
-	 * tune is _very_ likely to require the same */
-	if (fepriv->state & FESTATE_RETUNE) {
-		fepriv->lnb_drift = 0;
-		fepriv->auto_step = 0;
-		fepriv->auto_sub_step = 0;
-		fepriv->started_auto_step = 0;
-		fepriv->check_wrapped = 0;
-	}
-
-	/* fast zigzag. */
-	if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
-		fepriv->delay = fepriv->min_delay;
-
-		/* perform a tune */
-		retval = dvb_frontend_swzigzag_autotune(fe,
-							fepriv->check_wrapped);
-		if (retval < 0) {
-			return;
-		} else if (retval) {
-			/* OK, if we've run out of trials at the fast speed.
-			 * Drop back to slow for the _next_ attempt */
-			fepriv->state = FESTATE_SEARCHING_SLOW;
-			fepriv->started_auto_step = fepriv->auto_step;
-			return;
-		}
-		fepriv->check_wrapped = 1;
-
-		/* if we've just retuned, enter the ZIGZAG_FAST state.
-		 * This ensures we cannot return from an
-		 * FE_SET_FRONTEND ioctl before the first frontend tune
-		 * occurs */
-		if (fepriv->state & FESTATE_RETUNE) {
-			fepriv->state = FESTATE_TUNING_FAST;
-		}
-	}
-
-	/* slow zigzag */
-	if (fepriv->state & FESTATE_SEARCHING_SLOW) {
-		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
-
-		/* Note: don't bother checking for wrapping; we stay in this
-		 * state until we get a lock */
-		dvb_frontend_swzigzag_autotune(fe, 0);
-	}
-}
-
-static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
-{
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
-	if (fepriv->exit != DVB_FE_NO_EXIT)
-		return 1;
-
-	if (fepriv->dvbdev->writers == 1)
-		if (time_after_eq(jiffies, fepriv->release_jiffies +
-				  dvb_shutdown_timeout * HZ))
-			return 1;
-
-	return 0;
-}
-
-static int dvb_frontend_should_wakeup(struct dvb_frontend *fe)
-{
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
-	if (fepriv->wakeup) {
-		fepriv->wakeup = 0;
-		return 1;
-	}
-	return dvb_frontend_is_exiting(fe);
-}
-
-static void dvb_frontend_wakeup(struct dvb_frontend *fe)
-{
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
-	fepriv->wakeup = 1;
-	wake_up_interruptible(&fepriv->wait_queue);
-}
-
-static int dvb_frontend_thread(void *data)
-{
-	struct dvb_frontend *fe = data;
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-	fe_status_t s;
-	enum dvbfe_algo algo;
-
-	bool re_tune = false;
-
-	dprintk("%s\n", __func__);
-
-	fepriv->check_wrapped = 0;
-	fepriv->quality = 0;
-	fepriv->delay = 3*HZ;
-	fepriv->status = 0;
-	fepriv->wakeup = 0;
-	fepriv->reinitialise = 0;
-
-	dvb_frontend_init(fe);
-
-	set_freezable();
-	while (1) {
-		up(&fepriv->sem);	    /* is locked when we enter the thread... */
-restart:
-		wait_event_interruptible_timeout(fepriv->wait_queue,
-			dvb_frontend_should_wakeup(fe) || kthread_should_stop()
-				|| freezing(current),
-			fepriv->delay);
-
-		if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
-			/* got signal or quitting */
-			fepriv->exit = DVB_FE_NORMAL_EXIT;
-			break;
-		}
-
-		if (try_to_freeze())
-			goto restart;
-
-		if (down_interruptible(&fepriv->sem))
-			break;
-
-		if (fepriv->reinitialise) {
-			dvb_frontend_init(fe);
-			if (fe->ops.set_tone && fepriv->tone != -1)
-				fe->ops.set_tone(fe, fepriv->tone);
-			if (fe->ops.set_voltage && fepriv->voltage != -1)
-				fe->ops.set_voltage(fe, fepriv->voltage);
-			fepriv->reinitialise = 0;
-		}
-
-		/* do an iteration of the tuning loop */
-		if (fe->ops.get_frontend_algo) {
-			algo = fe->ops.get_frontend_algo(fe);
-			switch (algo) {
-			case DVBFE_ALGO_HW:
-				dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__);
-
-				if (fepriv->state & FESTATE_RETUNE) {
-					dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
-					re_tune = true;
-					fepriv->state = FESTATE_TUNED;
-				} else {
-					re_tune = false;
-				}
-
-				if (fe->ops.tune)
-					fe->ops.tune(fe, re_tune, fepriv->tune_mode_flags, &fepriv->delay, &s);
-
-				if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
-					dprintk("%s: state changed, adding current state\n", __func__);
-					dvb_frontend_add_event(fe, s);
-					fepriv->status = s;
-				}
-				break;
-			case DVBFE_ALGO_SW:
-				dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__);
-				dvb_frontend_swzigzag(fe);
-				break;
-			case DVBFE_ALGO_CUSTOM:
-				dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);
-				if (fepriv->state & FESTATE_RETUNE) {
-					dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);
-					fepriv->state = FESTATE_TUNED;
-				}
-				/* Case where we are going to search for a carrier
-				 * User asked us to retune again for some reason, possibly
-				 * requesting a search with a new set of parameters
-				 */
-				if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
-					if (fe->ops.search) {
-						fepriv->algo_status = fe->ops.search(fe);
-						/* We did do a search as was requested, the flags are
-						 * now unset as well and has the flags wrt to search.
-						 */
-					} else {
-						fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN;
-					}
-				}
-				/* Track the carrier if the search was successful */
-				if (fepriv->algo_status != DVBFE_ALGO_SEARCH_SUCCESS) {
-					fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
-					fepriv->delay = HZ / 2;
-				}
-				dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
-				fe->ops.read_status(fe, &s);
-				if (s != fepriv->status) {
-					dvb_frontend_add_event(fe, s); /* update event list */
-					fepriv->status = s;
-					if (!(s & FE_HAS_LOCK)) {
-						fepriv->delay = HZ / 10;
-						fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
-					} else {
-						fepriv->delay = 60 * HZ;
-					}
-				}
-				break;
-			default:
-				dprintk("%s: UNDEFINED ALGO !\n", __func__);
-				break;
-			}
-		} else {
-			dvb_frontend_swzigzag(fe);
-		}
-	}
-
-	if (dvb_powerdown_on_sleep) {
-		if (fe->ops.set_voltage)
-			fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
-		if (fe->ops.tuner_ops.sleep) {
-			if (fe->ops.i2c_gate_ctrl)
-				fe->ops.i2c_gate_ctrl(fe, 1);
-			fe->ops.tuner_ops.sleep(fe);
-			if (fe->ops.i2c_gate_ctrl)
-				fe->ops.i2c_gate_ctrl(fe, 0);
-		}
-		if (fe->ops.sleep)
-			fe->ops.sleep(fe);
-	}
-
-	fepriv->thread = NULL;
-	if (kthread_should_stop())
-		fepriv->exit = DVB_FE_DEVICE_REMOVED;
-	else
-		fepriv->exit = DVB_FE_NO_EXIT;
-	mb();
-
-	dvb_frontend_wakeup(fe);
-	return 0;
-}
-
-static void dvb_frontend_stop(struct dvb_frontend *fe)
-{
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
-	dprintk ("%s\n", __func__);
-
-	fepriv->exit = DVB_FE_NORMAL_EXIT;
-	mb();
-
-	if (!fepriv->thread)
-		return;
-
-	kthread_stop(fepriv->thread);
-
-	sema_init(&fepriv->sem, 1);
-	fepriv->state = FESTATE_IDLE;
-
-	/* paranoia check in case a signal arrived */
-	if (fepriv->thread)
-		printk("dvb_frontend_stop: warning: thread %p won't exit\n",
-				fepriv->thread);
-}
-
-s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)
-{
-	return ((curtime.tv_usec < lasttime.tv_usec) ?
-		1000000 - lasttime.tv_usec + curtime.tv_usec :
-		curtime.tv_usec - lasttime.tv_usec);
-}
-EXPORT_SYMBOL(timeval_usec_diff);
-
-static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec)
-{
-	curtime->tv_usec += add_usec;
-	if (curtime->tv_usec >= 1000000) {
-		curtime->tv_usec -= 1000000;
-		curtime->tv_sec++;
-	}
-}
-
-/*
- * Sleep until gettimeofday() > waketime + add_usec
- * This needs to be as precise as possible, but as the delay is
- * usually between 2ms and 32ms, it is done using a scheduled msleep
- * followed by usleep (normally a busy-wait loop) for the remainder
- */
-void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec)
-{
-	struct timeval lasttime;
-	s32 delta, newdelta;
-
-	timeval_usec_add(waketime, add_usec);
-
-	do_gettimeofday(&lasttime);
-	delta = timeval_usec_diff(lasttime, *waketime);
-	if (delta > 2500) {
-		msleep((delta - 1500) / 1000);
-		do_gettimeofday(&lasttime);
-		newdelta = timeval_usec_diff(lasttime, *waketime);
-		delta = (newdelta > delta) ? 0 : newdelta;
-	}
-	if (delta > 0)
-		udelay(delta);
-}
-EXPORT_SYMBOL(dvb_frontend_sleep_until);
-
-static int dvb_frontend_start(struct dvb_frontend *fe)
-{
-	int ret;
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-	struct task_struct *fe_thread;
-
-	dprintk ("%s\n", __func__);
-
-	if (fepriv->thread) {
-		if (fepriv->exit == DVB_FE_NO_EXIT)
-			return 0;
-		else
-			dvb_frontend_stop (fe);
-	}
-
-	if (signal_pending(current))
-		return -EINTR;
-	if (down_interruptible (&fepriv->sem))
-		return -EINTR;
-
-	fepriv->state = FESTATE_IDLE;
-	fepriv->exit = DVB_FE_NO_EXIT;
-	fepriv->thread = NULL;
-	mb();
-
-	fe_thread = kthread_run(dvb_frontend_thread, fe,
-		"kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id);
-	if (IS_ERR(fe_thread)) {
-		ret = PTR_ERR(fe_thread);
-		printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);
-		up(&fepriv->sem);
-		return ret;
-	}
-	fepriv->thread = fe_thread;
-	return 0;
-}
-
-static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,
-					u32 *freq_min, u32 *freq_max)
-{
-	*freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min);
-
-	if (fe->ops.info.frequency_max == 0)
-		*freq_max = fe->ops.tuner_ops.info.frequency_max;
-	else if (fe->ops.tuner_ops.info.frequency_max == 0)
-		*freq_max = fe->ops.info.frequency_max;
-	else
-		*freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);
-
-	if (*freq_min == 0 || *freq_max == 0)
-		printk(KERN_WARNING "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n",
-		       fe->dvb->num,fe->id);
-}
-
-static int dvb_frontend_check_parameters(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 freq_min;
-	u32 freq_max;
-
-	/* range check: frequency */
-	dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max);
-	if ((freq_min && c->frequency < freq_min) ||
-	    (freq_max && c->frequency > freq_max)) {
-		printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n",
-		       fe->dvb->num, fe->id, c->frequency, freq_min, freq_max);
-		return -EINVAL;
-	}
-
-	/* range check: symbol rate */
-	switch (c->delivery_system) {
-	case SYS_DVBS:
-	case SYS_DVBS2:
-	case SYS_TURBO:
-	case SYS_DVBC_ANNEX_A:
-	case SYS_DVBC_ANNEX_C:
-		if ((fe->ops.info.symbol_rate_min &&
-		     c->symbol_rate < fe->ops.info.symbol_rate_min) ||
-		    (fe->ops.info.symbol_rate_max &&
-		     c->symbol_rate > fe->ops.info.symbol_rate_max)) {
-			printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
-			       fe->dvb->num, fe->id, c->symbol_rate,
-			       fe->ops.info.symbol_rate_min,
-			       fe->ops.info.symbol_rate_max);
-			return -EINVAL;
-		}
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int i;
-	u32 delsys;
-
-	delsys = c->delivery_system;
-	memset(c, 0, sizeof(struct dtv_frontend_properties));
-	c->delivery_system = delsys;
-
-	c->state = DTV_CLEAR;
-
-	dprintk("%s() Clearing cache for delivery system %d\n", __func__,
-		c->delivery_system);
-
-	c->transmission_mode = TRANSMISSION_MODE_AUTO;
-	c->bandwidth_hz = 0;	/* AUTO */
-	c->guard_interval = GUARD_INTERVAL_AUTO;
-	c->hierarchy = HIERARCHY_AUTO;
-	c->symbol_rate = 0;
-	c->code_rate_HP = FEC_AUTO;
-	c->code_rate_LP = FEC_AUTO;
-	c->fec_inner = FEC_AUTO;
-	c->rolloff = ROLLOFF_AUTO;
-	c->voltage = SEC_VOLTAGE_OFF;
-	c->sectone = SEC_TONE_OFF;
-	c->pilot = PILOT_AUTO;
-
-	c->isdbt_partial_reception = 0;
-	c->isdbt_sb_mode = 0;
-	c->isdbt_sb_subchannel = 0;
-	c->isdbt_sb_segment_idx = 0;
-	c->isdbt_sb_segment_count = 0;
-	c->isdbt_layer_enabled = 0;
-	for (i = 0; i < 3; i++) {
-		c->layer[i].fec = FEC_AUTO;
-		c->layer[i].modulation = QAM_AUTO;
-		c->layer[i].interleaving = 0;
-		c->layer[i].segment_count = 0;
-	}
-
-	c->isdbs_ts_id = 0;
-	c->dvbt2_plp_id = 0;
-
-	switch (c->delivery_system) {
-	case SYS_DVBS:
-	case SYS_DVBS2:
-	case SYS_TURBO:
-		c->modulation = QPSK;   /* implied for DVB-S in legacy API */
-		c->rolloff = ROLLOFF_35;/* implied for DVB-S */
-		break;
-	case SYS_ATSC:
-		c->modulation = VSB_8;
-		break;
-	default:
-		c->modulation = QAM_AUTO;
-		break;
-	}
-
-	return 0;
-}
-
-#define _DTV_CMD(n, s, b) \
-[n] = { \
-	.name = #n, \
-	.cmd  = n, \
-	.set  = s,\
-	.buffer = b \
-}
-
-static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
-	_DTV_CMD(DTV_TUNE, 1, 0),
-	_DTV_CMD(DTV_CLEAR, 1, 0),
-
-	/* Set */
-	_DTV_CMD(DTV_FREQUENCY, 1, 0),
-	_DTV_CMD(DTV_BANDWIDTH_HZ, 1, 0),
-	_DTV_CMD(DTV_MODULATION, 1, 0),
-	_DTV_CMD(DTV_INVERSION, 1, 0),
-	_DTV_CMD(DTV_DISEQC_MASTER, 1, 1),
-	_DTV_CMD(DTV_SYMBOL_RATE, 1, 0),
-	_DTV_CMD(DTV_INNER_FEC, 1, 0),
-	_DTV_CMD(DTV_VOLTAGE, 1, 0),
-	_DTV_CMD(DTV_TONE, 1, 0),
-	_DTV_CMD(DTV_PILOT, 1, 0),
-	_DTV_CMD(DTV_ROLLOFF, 1, 0),
-	_DTV_CMD(DTV_DELIVERY_SYSTEM, 1, 0),
-	_DTV_CMD(DTV_HIERARCHY, 1, 0),
-	_DTV_CMD(DTV_CODE_RATE_HP, 1, 0),
-	_DTV_CMD(DTV_CODE_RATE_LP, 1, 0),
-	_DTV_CMD(DTV_GUARD_INTERVAL, 1, 0),
-	_DTV_CMD(DTV_TRANSMISSION_MODE, 1, 0),
-
-	_DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0),
-	_DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0),
-	_DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 1, 0),
-	_DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 1, 0),
-	_DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 1, 0),
-	_DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 1, 0),
-	_DTV_CMD(DTV_ISDBT_LAYERA_FEC, 1, 0),
-	_DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 1, 0),
-	_DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 1, 0),
-	_DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 1, 0),
-	_DTV_CMD(DTV_ISDBT_LAYERB_FEC, 1, 0),
-	_DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 1, 0),
-	_DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 1, 0),
-	_DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 1, 0),
-	_DTV_CMD(DTV_ISDBT_LAYERC_FEC, 1, 0),
-	_DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 1, 0),
-	_DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0),
-	_DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0),
-
-	_DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),
-	_DTV_CMD(DTV_DVBT2_PLP_ID, 1, 0),
-
-	/* Get */
-	_DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
-	_DTV_CMD(DTV_API_VERSION, 0, 0),
-	_DTV_CMD(DTV_CODE_RATE_HP, 0, 0),
-	_DTV_CMD(DTV_CODE_RATE_LP, 0, 0),
-	_DTV_CMD(DTV_GUARD_INTERVAL, 0, 0),
-	_DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0),
-	_DTV_CMD(DTV_HIERARCHY, 0, 0),
-
-	_DTV_CMD(DTV_ENUM_DELSYS, 0, 0),
-
-	_DTV_CMD(DTV_ATSCMH_PARADE_ID, 1, 0),
-	_DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 1, 0),
-
-	_DTV_CMD(DTV_ATSCMH_FIC_VER, 0, 0),
-	_DTV_CMD(DTV_ATSCMH_PARADE_ID, 0, 0),
-	_DTV_CMD(DTV_ATSCMH_NOG, 0, 0),
-	_DTV_CMD(DTV_ATSCMH_TNOG, 0, 0),
-	_DTV_CMD(DTV_ATSCMH_SGN, 0, 0),
-	_DTV_CMD(DTV_ATSCMH_PRC, 0, 0),
-	_DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE, 0, 0),
-	_DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 0, 0),
-	_DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI, 0, 0),
-	_DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC, 0, 0),
-	_DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE, 0, 0),
-	_DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_A, 0, 0),
-	_DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0),
-	_DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0),
-	_DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0),
-};
-
-static void dtv_property_dump(struct dtv_property *tvp)
-{
-	int i;
-
-	if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
-		printk(KERN_WARNING "%s: tvp.cmd = 0x%08x undefined\n",
-			__func__, tvp->cmd);
-		return;
-	}
-
-	dprintk("%s() tvp.cmd    = 0x%08x (%s)\n"
-		,__func__
-		,tvp->cmd
-		,dtv_cmds[ tvp->cmd ].name);
-
-	if(dtv_cmds[ tvp->cmd ].buffer) {
-
-		dprintk("%s() tvp.u.buffer.len = 0x%02x\n"
-			,__func__
-			,tvp->u.buffer.len);
-
-		for(i = 0; i < tvp->u.buffer.len; i++)
-			dprintk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
-				,__func__
-				,i
-				,tvp->u.buffer.data[i]);
-
-	} else
-		dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data);
-}
-
-/* Synchronise the legacy tuning parameters into the cache, so that demodulator
- * drivers can use a single set_frontend tuning function, regardless of whether
- * it's being used for the legacy or new API, reducing code and complexity.
- */
-static int dtv_property_cache_sync(struct dvb_frontend *fe,
-				   struct dtv_frontend_properties *c,
-				   const struct dvb_frontend_parameters *p)
-{
-	c->frequency = p->frequency;
-	c->inversion = p->inversion;
-
-	switch (dvbv3_type(c->delivery_system)) {
-	case DVBV3_QPSK:
-		dprintk("%s() Preparing QPSK req\n", __func__);
-		c->symbol_rate = p->u.qpsk.symbol_rate;
-		c->fec_inner = p->u.qpsk.fec_inner;
-		break;
-	case DVBV3_QAM:
-		dprintk("%s() Preparing QAM req\n", __func__);
-		c->symbol_rate = p->u.qam.symbol_rate;
-		c->fec_inner = p->u.qam.fec_inner;
-		c->modulation = p->u.qam.modulation;
-		break;
-	case DVBV3_OFDM:
-		dprintk("%s() Preparing OFDM req\n", __func__);
-		switch (p->u.ofdm.bandwidth) {
-		case BANDWIDTH_10_MHZ:
-			c->bandwidth_hz = 10000000;
-			break;
-		case BANDWIDTH_8_MHZ:
-			c->bandwidth_hz = 8000000;
-			break;
-		case BANDWIDTH_7_MHZ:
-			c->bandwidth_hz = 7000000;
-			break;
-		case BANDWIDTH_6_MHZ:
-			c->bandwidth_hz = 6000000;
-			break;
-		case BANDWIDTH_5_MHZ:
-			c->bandwidth_hz = 5000000;
-			break;
-		case BANDWIDTH_1_712_MHZ:
-			c->bandwidth_hz = 1712000;
-			break;
-		case BANDWIDTH_AUTO:
-			c->bandwidth_hz = 0;
-		}
-
-		c->code_rate_HP = p->u.ofdm.code_rate_HP;
-		c->code_rate_LP = p->u.ofdm.code_rate_LP;
-		c->modulation = p->u.ofdm.constellation;
-		c->transmission_mode = p->u.ofdm.transmission_mode;
-		c->guard_interval = p->u.ofdm.guard_interval;
-		c->hierarchy = p->u.ofdm.hierarchy_information;
-		break;
-	case DVBV3_ATSC:
-		dprintk("%s() Preparing ATSC req\n", __func__);
-		c->modulation = p->u.vsb.modulation;
-		if (c->delivery_system == SYS_ATSCMH)
-			break;
-		if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
-			c->delivery_system = SYS_ATSC;
-		else
-			c->delivery_system = SYS_DVBC_ANNEX_B;
-		break;
-	case DVBV3_UNKNOWN:
-		printk(KERN_ERR
-		       "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
-		       __func__, c->delivery_system);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-/* Ensure the cached values are set correctly in the frontend
- * legacy tuning structures, for the advanced tuning API.
- */
-static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
-					    struct dvb_frontend_parameters *p)
-{
-	const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-
-	p->frequency = c->frequency;
-	p->inversion = c->inversion;
-
-	switch (dvbv3_type(c->delivery_system)) {
-	case DVBV3_UNKNOWN:
-		printk(KERN_ERR
-		       "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
-		       __func__, c->delivery_system);
-		return -EINVAL;
-	case DVBV3_QPSK:
-		dprintk("%s() Preparing QPSK req\n", __func__);
-		p->u.qpsk.symbol_rate = c->symbol_rate;
-		p->u.qpsk.fec_inner = c->fec_inner;
-		break;
-	case DVBV3_QAM:
-		dprintk("%s() Preparing QAM req\n", __func__);
-		p->u.qam.symbol_rate = c->symbol_rate;
-		p->u.qam.fec_inner = c->fec_inner;
-		p->u.qam.modulation = c->modulation;
-		break;
-	case DVBV3_OFDM:
-		dprintk("%s() Preparing OFDM req\n", __func__);
-
-		switch (c->bandwidth_hz) {
-		case 10000000:
-			p->u.ofdm.bandwidth = BANDWIDTH_10_MHZ;
-			break;
-		case 8000000:
-			p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
-			break;
-		case 7000000:
-			p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
-			break;
-		case 6000000:
-			p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
-			break;
-		case 5000000:
-			p->u.ofdm.bandwidth = BANDWIDTH_5_MHZ;
-			break;
-		case 1712000:
-			p->u.ofdm.bandwidth = BANDWIDTH_1_712_MHZ;
-			break;
-		case 0:
-		default:
-			p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
-		}
-		p->u.ofdm.code_rate_HP = c->code_rate_HP;
-		p->u.ofdm.code_rate_LP = c->code_rate_LP;
-		p->u.ofdm.constellation = c->modulation;
-		p->u.ofdm.transmission_mode = c->transmission_mode;
-		p->u.ofdm.guard_interval = c->guard_interval;
-		p->u.ofdm.hierarchy_information = c->hierarchy;
-		break;
-	case DVBV3_ATSC:
-		dprintk("%s() Preparing VSB req\n", __func__);
-		p->u.vsb.modulation = c->modulation;
-		break;
-	}
-	return 0;
-}
-
-/**
- * dtv_get_frontend - calls a callback for retrieving DTV parameters
- * @fe:		struct dvb_frontend pointer
- * @c:		struct dtv_frontend_properties pointer (DVBv5 cache)
- * @p_out	struct dvb_frontend_parameters pointer (DVBv3 FE struct)
- *
- * This routine calls either the DVBv3 or DVBv5 get_frontend call.
- * If c is not null, it will update the DVBv5 cache struct pointed by it.
- * If p_out is not null, it will update the DVBv3 params pointed by it.
- */
-static int dtv_get_frontend(struct dvb_frontend *fe,
-			    struct dvb_frontend_parameters *p_out)
-{
-	int r;
-
-	if (fe->ops.get_frontend) {
-		r = fe->ops.get_frontend(fe);
-		if (unlikely(r < 0))
-			return r;
-		if (p_out)
-			dtv_property_legacy_params_sync(fe, p_out);
-		return 0;
-	}
-
-	/* As everything is in cache, get_frontend fops are always supported */
-	return 0;
-}
-
-static int dvb_frontend_ioctl_legacy(struct file *file,
-			unsigned int cmd, void *parg);
-static int dvb_frontend_ioctl_properties(struct file *file,
-			unsigned int cmd, void *parg);
-
-static int dtv_property_process_get(struct dvb_frontend *fe,
-				    const struct dtv_frontend_properties *c,
-				    struct dtv_property *tvp,
-				    struct file *file)
-{
-	int r, ncaps;
-
-	switch(tvp->cmd) {
-	case DTV_ENUM_DELSYS:
-		ncaps = 0;
-		while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
-			tvp->u.buffer.data[ncaps] = fe->ops.delsys[ncaps];
-			ncaps++;
-		}
-		tvp->u.buffer.len = ncaps;
-		break;
-	case DTV_FREQUENCY:
-		tvp->u.data = c->frequency;
-		break;
-	case DTV_MODULATION:
-		tvp->u.data = c->modulation;
-		break;
-	case DTV_BANDWIDTH_HZ:
-		tvp->u.data = c->bandwidth_hz;
-		break;
-	case DTV_INVERSION:
-		tvp->u.data = c->inversion;
-		break;
-	case DTV_SYMBOL_RATE:
-		tvp->u.data = c->symbol_rate;
-		break;
-	case DTV_INNER_FEC:
-		tvp->u.data = c->fec_inner;
-		break;
-	case DTV_PILOT:
-		tvp->u.data = c->pilot;
-		break;
-	case DTV_ROLLOFF:
-		tvp->u.data = c->rolloff;
-		break;
-	case DTV_DELIVERY_SYSTEM:
-		tvp->u.data = c->delivery_system;
-		break;
-	case DTV_VOLTAGE:
-		tvp->u.data = c->voltage;
-		break;
-	case DTV_TONE:
-		tvp->u.data = c->sectone;
-		break;
-	case DTV_API_VERSION:
-		tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
-		break;
-	case DTV_CODE_RATE_HP:
-		tvp->u.data = c->code_rate_HP;
-		break;
-	case DTV_CODE_RATE_LP:
-		tvp->u.data = c->code_rate_LP;
-		break;
-	case DTV_GUARD_INTERVAL:
-		tvp->u.data = c->guard_interval;
-		break;
-	case DTV_TRANSMISSION_MODE:
-		tvp->u.data = c->transmission_mode;
-		break;
-	case DTV_HIERARCHY:
-		tvp->u.data = c->hierarchy;
-		break;
-
-	/* ISDB-T Support here */
-	case DTV_ISDBT_PARTIAL_RECEPTION:
-		tvp->u.data = c->isdbt_partial_reception;
-		break;
-	case DTV_ISDBT_SOUND_BROADCASTING:
-		tvp->u.data = c->isdbt_sb_mode;
-		break;
-	case DTV_ISDBT_SB_SUBCHANNEL_ID:
-		tvp->u.data = c->isdbt_sb_subchannel;
-		break;
-	case DTV_ISDBT_SB_SEGMENT_IDX:
-		tvp->u.data = c->isdbt_sb_segment_idx;
-		break;
-	case DTV_ISDBT_SB_SEGMENT_COUNT:
-		tvp->u.data = c->isdbt_sb_segment_count;
-		break;
-	case DTV_ISDBT_LAYER_ENABLED:
-		tvp->u.data = c->isdbt_layer_enabled;
-		break;
-	case DTV_ISDBT_LAYERA_FEC:
-		tvp->u.data = c->layer[0].fec;
-		break;
-	case DTV_ISDBT_LAYERA_MODULATION:
-		tvp->u.data = c->layer[0].modulation;
-		break;
-	case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
-		tvp->u.data = c->layer[0].segment_count;
-		break;
-	case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
-		tvp->u.data = c->layer[0].interleaving;
-		break;
-	case DTV_ISDBT_LAYERB_FEC:
-		tvp->u.data = c->layer[1].fec;
-		break;
-	case DTV_ISDBT_LAYERB_MODULATION:
-		tvp->u.data = c->layer[1].modulation;
-		break;
-	case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
-		tvp->u.data = c->layer[1].segment_count;
-		break;
-	case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
-		tvp->u.data = c->layer[1].interleaving;
-		break;
-	case DTV_ISDBT_LAYERC_FEC:
-		tvp->u.data = c->layer[2].fec;
-		break;
-	case DTV_ISDBT_LAYERC_MODULATION:
-		tvp->u.data = c->layer[2].modulation;
-		break;
-	case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
-		tvp->u.data = c->layer[2].segment_count;
-		break;
-	case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
-		tvp->u.data = c->layer[2].interleaving;
-		break;
-	case DTV_ISDBS_TS_ID:
-		tvp->u.data = c->isdbs_ts_id;
-		break;
-	case DTV_DVBT2_PLP_ID:
-		tvp->u.data = c->dvbt2_plp_id;
-		break;
-
-	/* ATSC-MH */
-	case DTV_ATSCMH_FIC_VER:
-		tvp->u.data = fe->dtv_property_cache.atscmh_fic_ver;
-		break;
-	case DTV_ATSCMH_PARADE_ID:
-		tvp->u.data = fe->dtv_property_cache.atscmh_parade_id;
-		break;
-	case DTV_ATSCMH_NOG:
-		tvp->u.data = fe->dtv_property_cache.atscmh_nog;
-		break;
-	case DTV_ATSCMH_TNOG:
-		tvp->u.data = fe->dtv_property_cache.atscmh_tnog;
-		break;
-	case DTV_ATSCMH_SGN:
-		tvp->u.data = fe->dtv_property_cache.atscmh_sgn;
-		break;
-	case DTV_ATSCMH_PRC:
-		tvp->u.data = fe->dtv_property_cache.atscmh_prc;
-		break;
-	case DTV_ATSCMH_RS_FRAME_MODE:
-		tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_mode;
-		break;
-	case DTV_ATSCMH_RS_FRAME_ENSEMBLE:
-		tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_ensemble;
-		break;
-	case DTV_ATSCMH_RS_CODE_MODE_PRI:
-		tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_pri;
-		break;
-	case DTV_ATSCMH_RS_CODE_MODE_SEC:
-		tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_sec;
-		break;
-	case DTV_ATSCMH_SCCC_BLOCK_MODE:
-		tvp->u.data = fe->dtv_property_cache.atscmh_sccc_block_mode;
-		break;
-	case DTV_ATSCMH_SCCC_CODE_MODE_A:
-		tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_a;
-		break;
-	case DTV_ATSCMH_SCCC_CODE_MODE_B:
-		tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_b;
-		break;
-	case DTV_ATSCMH_SCCC_CODE_MODE_C:
-		tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_c;
-		break;
-	case DTV_ATSCMH_SCCC_CODE_MODE_D:
-		tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_d;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	/* Allow the frontend to override outgoing properties */
-	if (fe->ops.get_property) {
-		r = fe->ops.get_property(fe, tvp);
-		if (r < 0)
-			return r;
-	}
-
-	dtv_property_dump(tvp);
-
-	return 0;
-}
-
-static int dtv_set_frontend(struct dvb_frontend *fe);
-
-static bool is_dvbv3_delsys(u32 delsys)
-{
-	bool status;
-
-	status = (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) ||
-		 (delsys == SYS_DVBS) || (delsys == SYS_ATSC);
-
-	return status;
-}
-
-static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system)
-{
-	int ncaps, i;
-	u32 delsys = SYS_UNDEFINED;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	enum dvbv3_emulation_type type;
-
-	/*
-	 * It was reported that some old DVBv5 applications were
-	 * filling delivery_system with SYS_UNDEFINED. If this happens,
-	 * assume that the application wants to use the first supported
-	 * delivery system.
-	 */
-	if (c->delivery_system == SYS_UNDEFINED)
-	        c->delivery_system = fe->ops.delsys[0];
-
-	if (desired_system == SYS_UNDEFINED) {
-		/*
-		 * A DVBv3 call doesn't know what's the desired system.
-		 * Also, DVBv3 applications don't know that ops.info->type
-		 * could be changed, and they simply dies when it doesn't
-		 * match.
-		 * So, don't change the current delivery system, as it
-		 * may be trying to do the wrong thing, like setting an
-		 * ISDB-T frontend as DVB-T. Instead, find the closest
-		 * DVBv3 system that matches the delivery system.
-		 */
-		if (is_dvbv3_delsys(c->delivery_system)) {
-			dprintk("%s() Using delivery system to %d\n",
-				__func__, c->delivery_system);
-			return 0;
-		}
-		type = dvbv3_type(c->delivery_system);
-		switch (type) {
-		case DVBV3_QPSK:
-			desired_system = SYS_DVBS;
-			break;
-		case DVBV3_QAM:
-			desired_system = SYS_DVBC_ANNEX_A;
-			break;
-		case DVBV3_ATSC:
-			desired_system = SYS_ATSC;
-			break;
-		case DVBV3_OFDM:
-			desired_system = SYS_DVBT;
-			break;
-		default:
-			dprintk("%s(): This frontend doesn't support DVBv3 calls\n",
-				__func__);
-			return -EINVAL;
-		}
-		/*
-		 * Get a delivery system that is compatible with DVBv3
-		 * NOTE: in order for this to work with softwares like Kaffeine that
-		 *	uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to
-		 *	DVB-S, drivers that support both should put the SYS_DVBS entry
-		 *	before the SYS_DVBS2, otherwise it won't switch back to DVB-S.
-		 *	The real fix is that userspace applications should not use DVBv3
-		 *	and not trust on calling FE_SET_FRONTEND to switch the delivery
-		 *	system.
-		 */
-		ncaps = 0;
-		while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
-			if (fe->ops.delsys[ncaps] == desired_system) {
-				delsys = desired_system;
-				break;
-			}
-			ncaps++;
-		}
-		if (delsys == SYS_UNDEFINED) {
-			dprintk("%s() Couldn't find a delivery system that matches %d\n",
-				__func__, desired_system);
-		}
-	} else {
-		/*
-		 * This is a DVBv5 call. So, it likely knows the supported
-		 * delivery systems.
-		 */
-
-		/* Check if the desired delivery system is supported */
-		ncaps = 0;
-		while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
-			if (fe->ops.delsys[ncaps] == desired_system) {
-				c->delivery_system = desired_system;
-				dprintk("%s() Changing delivery system to %d\n",
-					__func__, desired_system);
-				return 0;
-			}
-			ncaps++;
-		}
-		type = dvbv3_type(desired_system);
-
-		/*
-		 * The delivery system is not supported. See if it can be
-		 * emulated.
-		 * The emulation only works if the desired system is one of the
-		 * DVBv3 delivery systems
-		 */
-		if (!is_dvbv3_delsys(desired_system)) {
-			dprintk("%s() can't use a DVBv3 FE_SET_FRONTEND call on this frontend\n",
-				__func__);
-			return -EINVAL;
-		}
-
-		/*
-		 * Get the last non-DVBv3 delivery system that has the same type
-		 * of the desired system
-		 */
-		ncaps = 0;
-		while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
-			if ((dvbv3_type(fe->ops.delsys[ncaps]) == type) &&
-			    !is_dvbv3_delsys(fe->ops.delsys[ncaps]))
-				delsys = fe->ops.delsys[ncaps];
-			ncaps++;
-		}
-		/* There's nothing compatible with the desired delivery system */
-		if (delsys == SYS_UNDEFINED) {
-			dprintk("%s() Incompatible DVBv3 FE_SET_FRONTEND call for this frontend\n",
-				__func__);
-			return -EINVAL;
-		}
-	}
-
-	c->delivery_system = delsys;
-
-	/*
-	 * The DVBv3 or DVBv5 call is requesting a different system. So,
-	 * emulation is needed.
-	 *
-	 * Emulate newer delivery systems like ISDBT, DVBT and DMBTH
-	 * for older DVBv5 applications. The emulation will try to use
-	 * the auto mode for most things, and will assume that the desired
-	 * delivery system is the last one at the ops.delsys[] array
-	 */
-	dprintk("%s() Using delivery system %d emulated as if it were a %d\n",
-		__func__, delsys, desired_system);
-
-	/*
-	 * For now, handles ISDB-T calls. More code may be needed here for the
-	 * other emulated stuff
-	 */
-	if (type == DVBV3_OFDM) {
-		if (c->delivery_system == SYS_ISDBT) {
-			dprintk("%s() Using defaults for SYS_ISDBT\n",
-				__func__);
-			if (!c->bandwidth_hz)
-				c->bandwidth_hz = 6000000;
-
-			c->isdbt_partial_reception = 0;
-			c->isdbt_sb_mode = 0;
-			c->isdbt_sb_subchannel = 0;
-			c->isdbt_sb_segment_idx = 0;
-			c->isdbt_sb_segment_count = 0;
-			c->isdbt_layer_enabled = 0;
-			for (i = 0; i < 3; i++) {
-				c->layer[i].fec = FEC_AUTO;
-				c->layer[i].modulation = QAM_AUTO;
-				c->layer[i].interleaving = 0;
-				c->layer[i].segment_count = 0;
-			}
-		}
-	}
-	dprintk("change delivery system on cache to %d\n", c->delivery_system);
-
-	return 0;
-}
-
-static int dtv_property_process_set(struct dvb_frontend *fe,
-				    struct dtv_property *tvp,
-				    struct file *file)
-{
-	int r = 0;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-
-	/* Allow the frontend to validate incoming properties */
-	if (fe->ops.set_property) {
-		r = fe->ops.set_property(fe, tvp);
-		if (r < 0)
-			return r;
-	}
-
-	switch(tvp->cmd) {
-	case DTV_CLEAR:
-		/*
-		 * Reset a cache of data specific to the frontend here. This does
-		 * not effect hardware.
-		 */
-		dvb_frontend_clear_cache(fe);
-		break;
-	case DTV_TUNE:
-		/* interpret the cache of data, build either a traditional frontend
-		 * tunerequest so we can pass validation in the FE_SET_FRONTEND
-		 * ioctl.
-		 */
-		c->state = tvp->cmd;
-		dprintk("%s() Finalised property cache\n", __func__);
-
-		r = dtv_set_frontend(fe);
-		break;
-	case DTV_FREQUENCY:
-		c->frequency = tvp->u.data;
-		break;
-	case DTV_MODULATION:
-		c->modulation = tvp->u.data;
-		break;
-	case DTV_BANDWIDTH_HZ:
-		c->bandwidth_hz = tvp->u.data;
-		break;
-	case DTV_INVERSION:
-		c->inversion = tvp->u.data;
-		break;
-	case DTV_SYMBOL_RATE:
-		c->symbol_rate = tvp->u.data;
-		break;
-	case DTV_INNER_FEC:
-		c->fec_inner = tvp->u.data;
-		break;
-	case DTV_PILOT:
-		c->pilot = tvp->u.data;
-		break;
-	case DTV_ROLLOFF:
-		c->rolloff = tvp->u.data;
-		break;
-	case DTV_DELIVERY_SYSTEM:
-		r = set_delivery_system(fe, tvp->u.data);
-		break;
-	case DTV_VOLTAGE:
-		c->voltage = tvp->u.data;
-		r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE,
-			(void *)c->voltage);
-		break;
-	case DTV_TONE:
-		c->sectone = tvp->u.data;
-		r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE,
-			(void *)c->sectone);
-		break;
-	case DTV_CODE_RATE_HP:
-		c->code_rate_HP = tvp->u.data;
-		break;
-	case DTV_CODE_RATE_LP:
-		c->code_rate_LP = tvp->u.data;
-		break;
-	case DTV_GUARD_INTERVAL:
-		c->guard_interval = tvp->u.data;
-		break;
-	case DTV_TRANSMISSION_MODE:
-		c->transmission_mode = tvp->u.data;
-		break;
-	case DTV_HIERARCHY:
-		c->hierarchy = tvp->u.data;
-		break;
-
-	/* ISDB-T Support here */
-	case DTV_ISDBT_PARTIAL_RECEPTION:
-		c->isdbt_partial_reception = tvp->u.data;
-		break;
-	case DTV_ISDBT_SOUND_BROADCASTING:
-		c->isdbt_sb_mode = tvp->u.data;
-		break;
-	case DTV_ISDBT_SB_SUBCHANNEL_ID:
-		c->isdbt_sb_subchannel = tvp->u.data;
-		break;
-	case DTV_ISDBT_SB_SEGMENT_IDX:
-		c->isdbt_sb_segment_idx = tvp->u.data;
-		break;
-	case DTV_ISDBT_SB_SEGMENT_COUNT:
-		c->isdbt_sb_segment_count = tvp->u.data;
-		break;
-	case DTV_ISDBT_LAYER_ENABLED:
-		c->isdbt_layer_enabled = tvp->u.data;
-		break;
-	case DTV_ISDBT_LAYERA_FEC:
-		c->layer[0].fec = tvp->u.data;
-		break;
-	case DTV_ISDBT_LAYERA_MODULATION:
-		c->layer[0].modulation = tvp->u.data;
-		break;
-	case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
-		c->layer[0].segment_count = tvp->u.data;
-		break;
-	case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
-		c->layer[0].interleaving = tvp->u.data;
-		break;
-	case DTV_ISDBT_LAYERB_FEC:
-		c->layer[1].fec = tvp->u.data;
-		break;
-	case DTV_ISDBT_LAYERB_MODULATION:
-		c->layer[1].modulation = tvp->u.data;
-		break;
-	case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
-		c->layer[1].segment_count = tvp->u.data;
-		break;
-	case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
-		c->layer[1].interleaving = tvp->u.data;
-		break;
-	case DTV_ISDBT_LAYERC_FEC:
-		c->layer[2].fec = tvp->u.data;
-		break;
-	case DTV_ISDBT_LAYERC_MODULATION:
-		c->layer[2].modulation = tvp->u.data;
-		break;
-	case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
-		c->layer[2].segment_count = tvp->u.data;
-		break;
-	case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
-		c->layer[2].interleaving = tvp->u.data;
-		break;
-	case DTV_ISDBS_TS_ID:
-		c->isdbs_ts_id = tvp->u.data;
-		break;
-	case DTV_DVBT2_PLP_ID:
-		c->dvbt2_plp_id = tvp->u.data;
-		break;
-
-	/* ATSC-MH */
-	case DTV_ATSCMH_PARADE_ID:
-		fe->dtv_property_cache.atscmh_parade_id = tvp->u.data;
-		break;
-	case DTV_ATSCMH_RS_FRAME_ENSEMBLE:
-		fe->dtv_property_cache.atscmh_rs_frame_ensemble = tvp->u.data;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	return r;
-}
-
-static int dvb_frontend_ioctl(struct file *file,
-			unsigned int cmd, void *parg)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dvb_frontend *fe = dvbdev->priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-	int err = -EOPNOTSUPP;
-
-	dprintk("%s (%d)\n", __func__, _IOC_NR(cmd));
-
-	if (fepriv->exit != DVB_FE_NO_EXIT)
-		return -ENODEV;
-
-	if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
-	    (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT ||
-	     cmd == FE_DISEQC_RECV_SLAVE_REPLY))
-		return -EPERM;
-
-	if (down_interruptible (&fepriv->sem))
-		return -ERESTARTSYS;
-
-	if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
-		err = dvb_frontend_ioctl_properties(file, cmd, parg);
-	else {
-		c->state = DTV_UNDEFINED;
-		err = dvb_frontend_ioctl_legacy(file, cmd, parg);
-	}
-
-	up(&fepriv->sem);
-	return err;
-}
-
-static int dvb_frontend_ioctl_properties(struct file *file,
-			unsigned int cmd, void *parg)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dvb_frontend *fe = dvbdev->priv;
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int err = 0;
-
-	struct dtv_properties *tvps = NULL;
-	struct dtv_property *tvp = NULL;
-	int i;
-
-	dprintk("%s\n", __func__);
-
-	if(cmd == FE_SET_PROPERTY) {
-		tvps = (struct dtv_properties __user *)parg;
-
-		dprintk("%s() properties.num = %d\n", __func__, tvps->num);
-		dprintk("%s() properties.props = %p\n", __func__, tvps->props);
-
-		/* Put an arbitrary limit on the number of messages that can
-		 * be sent at once */
-		if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
-			return -EINVAL;
-
-		tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
-		if (!tvp) {
-			err = -ENOMEM;
-			goto out;
-		}
-
-		if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
-			err = -EFAULT;
-			goto out;
-		}
-
-		for (i = 0; i < tvps->num; i++) {
-			err = dtv_property_process_set(fe, tvp + i, file);
-			if (err < 0)
-				goto out;
-			(tvp + i)->result = err;
-		}
-
-		if (c->state == DTV_TUNE)
-			dprintk("%s() Property cache is full, tuning\n", __func__);
-
-	} else
-	if(cmd == FE_GET_PROPERTY) {
-		tvps = (struct dtv_properties __user *)parg;
-
-		dprintk("%s() properties.num = %d\n", __func__, tvps->num);
-		dprintk("%s() properties.props = %p\n", __func__, tvps->props);
-
-		/* Put an arbitrary limit on the number of messages that can
-		 * be sent at once */
-		if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
-			return -EINVAL;
-
-		tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
-		if (!tvp) {
-			err = -ENOMEM;
-			goto out;
-		}
-
-		if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
-			err = -EFAULT;
-			goto out;
-		}
-
-		/*
-		 * Fills the cache out struct with the cache contents, plus
-		 * the data retrieved from get_frontend, if the frontend
-		 * is not idle. Otherwise, returns the cached content
-		 */
-		if (fepriv->state != FESTATE_IDLE) {
-			err = dtv_get_frontend(fe, NULL);
-			if (err < 0)
-				goto out;
-		}
-		for (i = 0; i < tvps->num; i++) {
-			err = dtv_property_process_get(fe, c, tvp + i, file);
-			if (err < 0)
-				goto out;
-			(tvp + i)->result = err;
-		}
-
-		if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
-			err = -EFAULT;
-			goto out;
-		}
-
-	} else
-		err = -EOPNOTSUPP;
-
-out:
-	kfree(tvp);
-	return err;
-}
-
-static int dtv_set_frontend(struct dvb_frontend *fe)
-{
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct dvb_frontend_tune_settings fetunesettings;
-	u32 rolloff = 0;
-
-	if (dvb_frontend_check_parameters(fe) < 0)
-		return -EINVAL;
-
-	/*
-	 * Initialize output parameters to match the values given by
-	 * the user. FE_SET_FRONTEND triggers an initial frontend event
-	 * with status = 0, which copies output parameters to userspace.
-	 */
-	dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
-
-	/*
-	 * Be sure that the bandwidth will be filled for all
-	 * non-satellite systems, as tuners need to know what
-	 * low pass/Nyquist half filter should be applied, in
-	 * order to avoid inter-channel noise.
-	 *
-	 * ISDB-T and DVB-T/T2 already sets bandwidth.
-	 * ATSC and DVB-C don't set, so, the core should fill it.
-	 *
-	 * On DVB-C Annex A and C, the bandwidth is a function of
-	 * the roll-off and symbol rate. Annex B defines different
-	 * roll-off factors depending on the modulation. Fortunately,
-	 * Annex B is only used with 6MHz, so there's no need to
-	 * calculate it.
-	 *
-	 * While not officially supported, a side effect of handling it at
-	 * the cache level is that a program could retrieve the bandwidth
-	 * via DTV_BANDWIDTH_HZ, which may be useful for test programs.
-	 */
-	switch (c->delivery_system) {
-	case SYS_ATSC:
-	case SYS_DVBC_ANNEX_B:
-		c->bandwidth_hz = 6000000;
-		break;
-	case SYS_DVBC_ANNEX_A:
-		rolloff = 115;
-		break;
-	case SYS_DVBC_ANNEX_C:
-		rolloff = 113;
-		break;
-	default:
-		break;
-	}
-	if (rolloff)
-		c->bandwidth_hz = (c->symbol_rate * rolloff) / 100;
-
-	/* force auto frequency inversion if requested */
-	if (dvb_force_auto_inversion)
-		c->inversion = INVERSION_AUTO;
-
-	/*
-	 * without hierarchical coding code_rate_LP is irrelevant,
-	 * so we tolerate the otherwise invalid FEC_NONE setting
-	 */
-	if (c->hierarchy == HIERARCHY_NONE && c->code_rate_LP == FEC_NONE)
-		c->code_rate_LP = FEC_AUTO;
-
-	/* get frontend-specific tuning settings */
-	memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
-	if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
-		fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
-		fepriv->max_drift = fetunesettings.max_drift;
-		fepriv->step_size = fetunesettings.step_size;
-	} else {
-		/* default values */
-		switch (c->delivery_system) {
-		case SYS_DVBS:
-		case SYS_DVBS2:
-		case SYS_ISDBS:
-		case SYS_TURBO:
-		case SYS_DVBC_ANNEX_A:
-		case SYS_DVBC_ANNEX_C:
-			fepriv->min_delay = HZ / 20;
-			fepriv->step_size = c->symbol_rate / 16000;
-			fepriv->max_drift = c->symbol_rate / 2000;
-			break;
-		case SYS_DVBT:
-		case SYS_DVBT2:
-		case SYS_ISDBT:
-		case SYS_DMBTH:
-			fepriv->min_delay = HZ / 20;
-			fepriv->step_size = fe->ops.info.frequency_stepsize * 2;
-			fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
-			break;
-		default:
-			/*
-			 * FIXME: This sounds wrong! if freqency_stepsize is
-			 * defined by the frontend, why not use it???
-			 */
-			fepriv->min_delay = HZ / 20;
-			fepriv->step_size = 0; /* no zigzag */
-			fepriv->max_drift = 0;
-			break;
-		}
-	}
-	if (dvb_override_tune_delay > 0)
-		fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000;
-
-	fepriv->state = FESTATE_RETUNE;
-
-	/* Request the search algorithm to search */
-	fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
-
-	dvb_frontend_clear_events(fe);
-	dvb_frontend_add_event(fe, 0);
-	dvb_frontend_wakeup(fe);
-	fepriv->status = 0;
-
-	return 0;
-}
-
-
-static int dvb_frontend_ioctl_legacy(struct file *file,
-			unsigned int cmd, void *parg)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dvb_frontend *fe = dvbdev->priv;
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int cb_err, err = -EOPNOTSUPP;
-
-	if (fe->dvb->fe_ioctl_override) {
-		cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg,
-						    DVB_FE_IOCTL_PRE);
-		if (cb_err < 0)
-			return cb_err;
-		if (cb_err > 0)
-			return 0;
-		/* fe_ioctl_override returning 0 allows
-		 * dvb-core to continue handling the ioctl */
-	}
-
-	switch (cmd) {
-	case FE_GET_INFO: {
-		struct dvb_frontend_info* info = parg;
-
-		memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
-		dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max);
-
-		/*
-		 * Associate the 4 delivery systems supported by DVBv3
-		 * API with their DVBv5 counterpart. For the other standards,
-		 * use the closest type, assuming that it would hopefully
-		 * work with a DVBv3 application.
-		 * It should be noticed that, on multi-frontend devices with
-		 * different types (terrestrial and cable, for example),
-		 * a pure DVBv3 application won't be able to use all delivery
-		 * systems. Yet, changing the DVBv5 cache to the other delivery
-		 * system should be enough for making it work.
-		 */
-		switch (dvbv3_type(c->delivery_system)) {
-		case DVBV3_QPSK:
-			info->type = FE_QPSK;
-			break;
-		case DVBV3_ATSC:
-			info->type = FE_ATSC;
-			break;
-		case DVBV3_QAM:
-			info->type = FE_QAM;
-			break;
-		case DVBV3_OFDM:
-			info->type = FE_OFDM;
-			break;
-		default:
-			printk(KERN_ERR
-			       "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
-			       __func__, c->delivery_system);
-			fe->ops.info.type = FE_OFDM;
-		}
-		dprintk("current delivery system on cache: %d, V3 type: %d\n",
-			c->delivery_system, fe->ops.info.type);
-
-		/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
-		 * do it, it is done for it. */
-		info->caps |= FE_CAN_INVERSION_AUTO;
-		err = 0;
-		break;
-	}
-
-	case FE_READ_STATUS: {
-		fe_status_t* status = parg;
-
-		/* if retune was requested but hasn't occurred yet, prevent
-		 * that user get signal state from previous tuning */
-		if (fepriv->state == FESTATE_RETUNE ||
-		    fepriv->state == FESTATE_ERROR) {
-			err=0;
-			*status = 0;
-			break;
-		}
-
-		if (fe->ops.read_status)
-			err = fe->ops.read_status(fe, status);
-		break;
-	}
-	case FE_READ_BER:
-		if (fe->ops.read_ber)
-			err = fe->ops.read_ber(fe, (__u32*) parg);
-		break;
-
-	case FE_READ_SIGNAL_STRENGTH:
-		if (fe->ops.read_signal_strength)
-			err = fe->ops.read_signal_strength(fe, (__u16*) parg);
-		break;
-
-	case FE_READ_SNR:
-		if (fe->ops.read_snr)
-			err = fe->ops.read_snr(fe, (__u16*) parg);
-		break;
-
-	case FE_READ_UNCORRECTED_BLOCKS:
-		if (fe->ops.read_ucblocks)
-			err = fe->ops.read_ucblocks(fe, (__u32*) parg);
-		break;
-
-
-	case FE_DISEQC_RESET_OVERLOAD:
-		if (fe->ops.diseqc_reset_overload) {
-			err = fe->ops.diseqc_reset_overload(fe);
-			fepriv->state = FESTATE_DISEQC;
-			fepriv->status = 0;
-		}
-		break;
-
-	case FE_DISEQC_SEND_MASTER_CMD:
-		if (fe->ops.diseqc_send_master_cmd) {
-			err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
-			fepriv->state = FESTATE_DISEQC;
-			fepriv->status = 0;
-		}
-		break;
-
-	case FE_DISEQC_SEND_BURST:
-		if (fe->ops.diseqc_send_burst) {
-			err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
-			fepriv->state = FESTATE_DISEQC;
-			fepriv->status = 0;
-		}
-		break;
-
-	case FE_SET_TONE:
-		if (fe->ops.set_tone) {
-			err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
-			fepriv->tone = (fe_sec_tone_mode_t) parg;
-			fepriv->state = FESTATE_DISEQC;
-			fepriv->status = 0;
-		}
-		break;
-
-	case FE_SET_VOLTAGE:
-		if (fe->ops.set_voltage) {
-			err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
-			fepriv->voltage = (fe_sec_voltage_t) parg;
-			fepriv->state = FESTATE_DISEQC;
-			fepriv->status = 0;
-		}
-		break;
-
-	case FE_DISHNETWORK_SEND_LEGACY_CMD:
-		if (fe->ops.dishnetwork_send_legacy_command) {
-			err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);
-			fepriv->state = FESTATE_DISEQC;
-			fepriv->status = 0;
-		} else if (fe->ops.set_voltage) {
-			/*
-			 * NOTE: This is a fallback condition.  Some frontends
-			 * (stv0299 for instance) take longer than 8msec to
-			 * respond to a set_voltage command.  Those switches
-			 * need custom routines to switch properly.  For all
-			 * other frontends, the following should work ok.
-			 * Dish network legacy switches (as used by Dish500)
-			 * are controlled by sending 9-bit command words
-			 * spaced 8msec apart.
-			 * the actual command word is switch/port dependent
-			 * so it is up to the userspace application to send
-			 * the right command.
-			 * The command must always start with a '0' after
-			 * initialization, so parg is 8 bits and does not
-			 * include the initialization or start bit
-			 */
-			unsigned long swcmd = ((unsigned long) parg) << 1;
-			struct timeval nexttime;
-			struct timeval tv[10];
-			int i;
-			u8 last = 1;
-			if (dvb_frontend_debug)
-				printk("%s switch command: 0x%04lx\n", __func__, swcmd);
-			do_gettimeofday(&nexttime);
-			if (dvb_frontend_debug)
-				memcpy(&tv[0], &nexttime, sizeof(struct timeval));
-			/* before sending a command, initialize by sending
-			 * a 32ms 18V to the switch
-			 */
-			fe->ops.set_voltage(fe, SEC_VOLTAGE_18);
-			dvb_frontend_sleep_until(&nexttime, 32000);
-
-			for (i = 0; i < 9; i++) {
-				if (dvb_frontend_debug)
-					do_gettimeofday(&tv[i + 1]);
-				if ((swcmd & 0x01) != last) {
-					/* set voltage to (last ? 13V : 18V) */
-					fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
-					last = (last) ? 0 : 1;
-				}
-				swcmd = swcmd >> 1;
-				if (i != 8)
-					dvb_frontend_sleep_until(&nexttime, 8000);
-			}
-			if (dvb_frontend_debug) {
-				printk("%s(%d): switch delay (should be 32k followed by all 8k\n",
-					__func__, fe->dvb->num);
-				for (i = 1; i < 10; i++)
-					printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
-			}
-			err = 0;
-			fepriv->state = FESTATE_DISEQC;
-			fepriv->status = 0;
-		}
-		break;
-
-	case FE_DISEQC_RECV_SLAVE_REPLY:
-		if (fe->ops.diseqc_recv_slave_reply)
-			err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
-		break;
-
-	case FE_ENABLE_HIGH_LNB_VOLTAGE:
-		if (fe->ops.enable_high_lnb_voltage)
-			err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
-		break;
-
-	case FE_SET_FRONTEND:
-		err = set_delivery_system(fe, SYS_UNDEFINED);
-		if (err)
-			break;
-
-		err = dtv_property_cache_sync(fe, c, parg);
-		if (err)
-			break;
-		err = dtv_set_frontend(fe);
-		break;
-	case FE_GET_EVENT:
-		err = dvb_frontend_get_event (fe, parg, file->f_flags);
-		break;
-
-	case FE_GET_FRONTEND:
-		err = dtv_get_frontend(fe, parg);
-		break;
-
-	case FE_SET_FRONTEND_TUNE_MODE:
-		fepriv->tune_mode_flags = (unsigned long) parg;
-		err = 0;
-		break;
-	};
-
-	if (fe->dvb->fe_ioctl_override) {
-		cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg,
-						    DVB_FE_IOCTL_POST);
-		if (cb_err < 0)
-			return cb_err;
-	}
-
-	return err;
-}
-
-
-static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dvb_frontend *fe = dvbdev->priv;
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
-	dprintk ("%s\n", __func__);
-
-	poll_wait (file, &fepriv->events.wait_queue, wait);
-
-	if (fepriv->events.eventw != fepriv->events.eventr)
-		return (POLLIN | POLLRDNORM | POLLPRI);
-
-	return 0;
-}
-
-static int dvb_frontend_open(struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dvb_frontend *fe = dvbdev->priv;
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-	struct dvb_adapter *adapter = fe->dvb;
-	int ret;
-
-	dprintk ("%s\n", __func__);
-	if (fepriv->exit == DVB_FE_DEVICE_REMOVED)
-		return -ENODEV;
-
-	if (adapter->mfe_shared) {
-		mutex_lock (&adapter->mfe_lock);
-
-		if (adapter->mfe_dvbdev == NULL)
-			adapter->mfe_dvbdev = dvbdev;
-
-		else if (adapter->mfe_dvbdev != dvbdev) {
-			struct dvb_device
-				*mfedev = adapter->mfe_dvbdev;
-			struct dvb_frontend
-				*mfe = mfedev->priv;
-			struct dvb_frontend_private
-				*mfepriv = mfe->frontend_priv;
-			int mferetry = (dvb_mfe_wait_time << 1);
-
-			mutex_unlock (&adapter->mfe_lock);
-			while (mferetry-- && (mfedev->users != -1 ||
-					mfepriv->thread != NULL)) {
-				if(msleep_interruptible(500)) {
-					if(signal_pending(current))
-						return -EINTR;
-				}
-			}
-
-			mutex_lock (&adapter->mfe_lock);
-			if(adapter->mfe_dvbdev != dvbdev) {
-				mfedev = adapter->mfe_dvbdev;
-				mfe = mfedev->priv;
-				mfepriv = mfe->frontend_priv;
-				if (mfedev->users != -1 ||
-						mfepriv->thread != NULL) {
-					mutex_unlock (&adapter->mfe_lock);
-					return -EBUSY;
-				}
-				adapter->mfe_dvbdev = dvbdev;
-			}
-		}
-	}
-
-	if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
-		if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
-			goto err0;
-
-		/* If we took control of the bus, we need to force
-		   reinitialization.  This is because many ts_bus_ctrl()
-		   functions strobe the RESET pin on the demod, and if the
-		   frontend thread already exists then the dvb_init() routine
-		   won't get called (which is what usually does initial
-		   register configuration). */
-		fepriv->reinitialise = 1;
-	}
-
-	if ((ret = dvb_generic_open (inode, file)) < 0)
-		goto err1;
-
-	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
-		/* normal tune mode when opened R/W */
-		fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
-		fepriv->tone = -1;
-		fepriv->voltage = -1;
-
-		ret = dvb_frontend_start (fe);
-		if (ret)
-			goto err2;
-
-		/*  empty event queue */
-		fepriv->events.eventr = fepriv->events.eventw = 0;
-	}
-
-	if (adapter->mfe_shared)
-		mutex_unlock (&adapter->mfe_lock);
-	return ret;
-
-err2:
-	dvb_generic_release(inode, file);
-err1:
-	if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
-		fe->ops.ts_bus_ctrl(fe, 0);
-err0:
-	if (adapter->mfe_shared)
-		mutex_unlock (&adapter->mfe_lock);
-	return ret;
-}
-
-static int dvb_frontend_release(struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dvb_frontend *fe = dvbdev->priv;
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-	int ret;
-
-	dprintk ("%s\n", __func__);
-
-	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
-		fepriv->release_jiffies = jiffies;
-		mb();
-	}
-
-	ret = dvb_generic_release (inode, file);
-
-	if (dvbdev->users == -1) {
-		wake_up(&fepriv->wait_queue);
-		if (fepriv->exit != DVB_FE_NO_EXIT) {
-			fops_put(file->f_op);
-			file->f_op = NULL;
-			wake_up(&dvbdev->wait_queue);
-		}
-		if (fe->ops.ts_bus_ctrl)
-			fe->ops.ts_bus_ctrl(fe, 0);
-	}
-
-	return ret;
-}
-
-static const struct file_operations dvb_frontend_fops = {
-	.owner		= THIS_MODULE,
-	.unlocked_ioctl	= dvb_generic_ioctl,
-	.poll		= dvb_frontend_poll,
-	.open		= dvb_frontend_open,
-	.release	= dvb_frontend_release,
-	.llseek		= noop_llseek,
-};
-
-int dvb_register_frontend(struct dvb_adapter* dvb,
-			  struct dvb_frontend* fe)
-{
-	struct dvb_frontend_private *fepriv;
-	static const struct dvb_device dvbdev_template = {
-		.users = ~0,
-		.writers = 1,
-		.readers = (~0)-1,
-		.fops = &dvb_frontend_fops,
-		.kernel_ioctl = dvb_frontend_ioctl
-	};
-
-	dprintk ("%s\n", __func__);
-
-	if (mutex_lock_interruptible(&frontend_mutex))
-		return -ERESTARTSYS;
-
-	fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL);
-	if (fe->frontend_priv == NULL) {
-		mutex_unlock(&frontend_mutex);
-		return -ENOMEM;
-	}
-	fepriv = fe->frontend_priv;
-
-	sema_init(&fepriv->sem, 1);
-	init_waitqueue_head (&fepriv->wait_queue);
-	init_waitqueue_head (&fepriv->events.wait_queue);
-	mutex_init(&fepriv->events.mtx);
-	fe->dvb = dvb;
-	fepriv->inversion = INVERSION_OFF;
-
-	printk ("DVB: registering adapter %i frontend %i (%s)...\n",
-		fe->dvb->num,
-		fe->id,
-		fe->ops.info.name);
-
-	dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
-			     fe, DVB_DEVICE_FRONTEND);
-
-	/*
-	 * Initialize the cache to the proper values according with the
-	 * first supported delivery system (ops->delsys[0])
-	 */
-
-        fe->dtv_property_cache.delivery_system = fe->ops.delsys[0];
-	dvb_frontend_clear_cache(fe);
-
-	mutex_unlock(&frontend_mutex);
-	return 0;
-}
-EXPORT_SYMBOL(dvb_register_frontend);
-
-int dvb_unregister_frontend(struct dvb_frontend* fe)
-{
-	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-	dprintk ("%s\n", __func__);
-
-	mutex_lock(&frontend_mutex);
-	dvb_frontend_stop (fe);
-	mutex_unlock(&frontend_mutex);
-
-	if (fepriv->dvbdev->users < -1)
-		wait_event(fepriv->dvbdev->wait_queue,
-				fepriv->dvbdev->users==-1);
-
-	mutex_lock(&frontend_mutex);
-	dvb_unregister_device (fepriv->dvbdev);
-
-	/* fe is invalid now */
-	kfree(fepriv);
-	mutex_unlock(&frontend_mutex);
-	return 0;
-}
-EXPORT_SYMBOL(dvb_unregister_frontend);
-
-#ifdef CONFIG_MEDIA_ATTACH
-void dvb_frontend_detach(struct dvb_frontend* fe)
-{
-	void *ptr;
-
-	if (fe->ops.release_sec) {
-		fe->ops.release_sec(fe);
-		symbol_put_addr(fe->ops.release_sec);
-	}
-	if (fe->ops.tuner_ops.release) {
-		fe->ops.tuner_ops.release(fe);
-		symbol_put_addr(fe->ops.tuner_ops.release);
-	}
-	if (fe->ops.analog_ops.release) {
-		fe->ops.analog_ops.release(fe);
-		symbol_put_addr(fe->ops.analog_ops.release);
-	}
-	ptr = (void*)fe->ops.release;
-	if (ptr) {
-		fe->ops.release(fe);
-		symbol_put_addr(ptr);
-	}
-}
-#else
-void dvb_frontend_detach(struct dvb_frontend* fe)
-{
-	if (fe->ops.release_sec)
-		fe->ops.release_sec(fe);
-	if (fe->ops.tuner_ops.release)
-		fe->ops.tuner_ops.release(fe);
-	if (fe->ops.analog_ops.release)
-		fe->ops.analog_ops.release(fe);
-	if (fe->ops.release)
-		fe->ops.release(fe);
-}
-#endif
-EXPORT_SYMBOL(dvb_frontend_detach);
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
deleted file mode 100644
index 7c64c09..0000000
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * dvb_frontend.h
- *
- * Copyright (C) 2001 convergence integrated media GmbH
- * Copyright (C) 2004 convergence GmbH
- *
- * Written by Ralph Metzler
- * Overhauled by Holger Waechtler
- * Kernel I2C stuff by Michael Hunold <hunold@convergence.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
-
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- */
-
-#ifndef _DVB_FRONTEND_H_
-#define _DVB_FRONTEND_H_
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/ioctl.h>
-#include <linux/i2c.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-
-#include <linux/dvb/frontend.h>
-
-#include "dvbdev.h"
-
-/*
- * Maximum number of Delivery systems per frontend. It
- * should be smaller or equal to 32
- */
-#define MAX_DELSYS	8
-
-struct dvb_frontend_tune_settings {
-	int min_delay_ms;
-	int step_size;
-	int max_drift;
-};
-
-struct dvb_frontend;
-
-struct dvb_tuner_info {
-	char name[128];
-
-	u32 frequency_min;
-	u32 frequency_max;
-	u32 frequency_step;
-
-	u32 bandwidth_min;
-	u32 bandwidth_max;
-	u32 bandwidth_step;
-};
-
-struct analog_parameters {
-	unsigned int frequency;
-	unsigned int mode;
-	unsigned int audmode;
-	u64 std;
-};
-
-enum dvbfe_modcod {
-	DVBFE_MODCOD_DUMMY_PLFRAME	= 0,
-	DVBFE_MODCOD_QPSK_1_4,
-	DVBFE_MODCOD_QPSK_1_3,
-	DVBFE_MODCOD_QPSK_2_5,
-	DVBFE_MODCOD_QPSK_1_2,
-	DVBFE_MODCOD_QPSK_3_5,
-	DVBFE_MODCOD_QPSK_2_3,
-	DVBFE_MODCOD_QPSK_3_4,
-	DVBFE_MODCOD_QPSK_4_5,
-	DVBFE_MODCOD_QPSK_5_6,
-	DVBFE_MODCOD_QPSK_8_9,
-	DVBFE_MODCOD_QPSK_9_10,
-	DVBFE_MODCOD_8PSK_3_5,
-	DVBFE_MODCOD_8PSK_2_3,
-	DVBFE_MODCOD_8PSK_3_4,
-	DVBFE_MODCOD_8PSK_5_6,
-	DVBFE_MODCOD_8PSK_8_9,
-	DVBFE_MODCOD_8PSK_9_10,
-	DVBFE_MODCOD_16APSK_2_3,
-	DVBFE_MODCOD_16APSK_3_4,
-	DVBFE_MODCOD_16APSK_4_5,
-	DVBFE_MODCOD_16APSK_5_6,
-	DVBFE_MODCOD_16APSK_8_9,
-	DVBFE_MODCOD_16APSK_9_10,
-	DVBFE_MODCOD_32APSK_3_4,
-	DVBFE_MODCOD_32APSK_4_5,
-	DVBFE_MODCOD_32APSK_5_6,
-	DVBFE_MODCOD_32APSK_8_9,
-	DVBFE_MODCOD_32APSK_9_10,
-	DVBFE_MODCOD_RESERVED_1,
-	DVBFE_MODCOD_BPSK_1_3,
-	DVBFE_MODCOD_BPSK_1_4,
-	DVBFE_MODCOD_RESERVED_2
-};
-
-enum tuner_param {
-	DVBFE_TUNER_FREQUENCY		= (1 <<  0),
-	DVBFE_TUNER_TUNERSTEP		= (1 <<  1),
-	DVBFE_TUNER_IFFREQ		= (1 <<  2),
-	DVBFE_TUNER_BANDWIDTH		= (1 <<  3),
-	DVBFE_TUNER_REFCLOCK		= (1 <<  4),
-	DVBFE_TUNER_IQSENSE		= (1 <<  5),
-	DVBFE_TUNER_DUMMY		= (1 << 31)
-};
-
-/*
- * ALGO_HW: (Hardware Algorithm)
- * ----------------------------------------------------------------
- * Devices that support this algorithm do everything in hardware
- * and no software support is needed to handle them.
- * Requesting these devices to LOCK is the only thing required,
- * device is supposed to do everything in the hardware.
- *
- * ALGO_SW: (Software Algorithm)
- * ----------------------------------------------------------------
- * These are dumb devices, that require software to do everything
- *
- * ALGO_CUSTOM: (Customizable Agorithm)
- * ----------------------------------------------------------------
- * Devices having this algorithm can be customized to have specific
- * algorithms in the frontend driver, rather than simply doing a
- * software zig-zag. In this case the zigzag maybe hardware assisted
- * or it maybe completely done in hardware. In all cases, usage of
- * this algorithm, in conjunction with the search and track
- * callbacks, utilizes the driver specific algorithm.
- *
- * ALGO_RECOVERY: (Recovery Algorithm)
- * ----------------------------------------------------------------
- * These devices have AUTO recovery capabilities from LOCK failure
- */
-enum dvbfe_algo {
-	DVBFE_ALGO_HW			= (1 <<  0),
-	DVBFE_ALGO_SW			= (1 <<  1),
-	DVBFE_ALGO_CUSTOM		= (1 <<  2),
-	DVBFE_ALGO_RECOVERY		= (1 << 31)
-};
-
-struct tuner_state {
-	u32 frequency;
-	u32 tunerstep;
-	u32 ifreq;
-	u32 bandwidth;
-	u32 iqsense;
-	u32 refclock;
-};
-
-/*
- * search callback possible return status
- *
- * DVBFE_ALGO_SEARCH_SUCCESS
- * The frontend search algorithm completed and returned successfully
- *
- * DVBFE_ALGO_SEARCH_ASLEEP
- * The frontend search algorithm is sleeping
- *
- * DVBFE_ALGO_SEARCH_FAILED
- * The frontend search for a signal failed
- *
- * DVBFE_ALGO_SEARCH_INVALID
- * The frontend search algorith was probably supplied with invalid
- * parameters and the search is an invalid one
- *
- * DVBFE_ALGO_SEARCH_ERROR
- * The frontend search algorithm failed due to some error
- *
- * DVBFE_ALGO_SEARCH_AGAIN
- * The frontend search algorithm was requested to search again
- */
-enum dvbfe_search {
-	DVBFE_ALGO_SEARCH_SUCCESS	= (1 <<  0),
-	DVBFE_ALGO_SEARCH_ASLEEP	= (1 <<  1),
-	DVBFE_ALGO_SEARCH_FAILED	= (1 <<  2),
-	DVBFE_ALGO_SEARCH_INVALID	= (1 <<  3),
-	DVBFE_ALGO_SEARCH_AGAIN		= (1 <<  4),
-	DVBFE_ALGO_SEARCH_ERROR		= (1 << 31),
-};
-
-
-struct dvb_tuner_ops {
-
-	struct dvb_tuner_info info;
-
-	int (*release)(struct dvb_frontend *fe);
-	int (*init)(struct dvb_frontend *fe);
-	int (*sleep)(struct dvb_frontend *fe);
-
-	/** This is for simple PLLs - set all parameters in one go. */
-	int (*set_params)(struct dvb_frontend *fe);
-	int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p);
-
-	/** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
-	int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len);
-
-	/** This is to allow setting tuner-specific configs */
-	int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
-
-	int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
-	int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
-	int (*get_if_frequency)(struct dvb_frontend *fe, u32 *frequency);
-
-#define TUNER_STATUS_LOCKED 1
-#define TUNER_STATUS_STEREO 2
-	int (*get_status)(struct dvb_frontend *fe, u32 *status);
-	int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
-	int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
-
-	/** These are provided separately from set_params in order to facilitate silicon
-	 * tuners which require sophisticated tuning loops, controlling each parameter separately. */
-	int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
-	int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
-
-	/*
-	 * These are provided separately from set_params in order to facilitate silicon
-	 * tuners which require sophisticated tuning loops, controlling each parameter separately.
-	 */
-	int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
-	int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
-};
-
-struct analog_demod_info {
-	char *name;
-};
-
-struct analog_demod_ops {
-
-	struct analog_demod_info info;
-
-	void (*set_params)(struct dvb_frontend *fe,
-			   struct analog_parameters *params);
-	int  (*has_signal)(struct dvb_frontend *fe);
-	int  (*get_afc)(struct dvb_frontend *fe);
-	void (*tuner_status)(struct dvb_frontend *fe);
-	void (*standby)(struct dvb_frontend *fe);
-	void (*release)(struct dvb_frontend *fe);
-	int  (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable);
-
-	/** This is to allow setting tuner-specific configuration */
-	int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
-};
-
-struct dtv_frontend_properties;
-
-struct dvb_frontend_ops {
-
-	struct dvb_frontend_info info;
-
-	u8 delsys[MAX_DELSYS];
-
-	void (*release)(struct dvb_frontend* fe);
-	void (*release_sec)(struct dvb_frontend* fe);
-
-	int (*init)(struct dvb_frontend* fe);
-	int (*sleep)(struct dvb_frontend* fe);
-
-	int (*write)(struct dvb_frontend* fe, const u8 buf[], int len);
-
-	/* if this is set, it overrides the default swzigzag */
-	int (*tune)(struct dvb_frontend* fe,
-		    bool re_tune,
-		    unsigned int mode_flags,
-		    unsigned int *delay,
-		    fe_status_t *status);
-	/* get frontend tuning algorithm from the module */
-	enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe);
-
-	/* these two are only used for the swzigzag code */
-	int (*set_frontend)(struct dvb_frontend *fe);
-	int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
-
-	int (*get_frontend)(struct dvb_frontend *fe);
-
-	int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
-	int (*read_ber)(struct dvb_frontend* fe, u32* ber);
-	int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
-	int (*read_snr)(struct dvb_frontend* fe, u16* snr);
-	int (*read_ucblocks)(struct dvb_frontend* fe, u32* ucblocks);
-
-	int (*diseqc_reset_overload)(struct dvb_frontend* fe);
-	int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
-	int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply);
-	int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
-	int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
-	int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
-	int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
-	int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
-	int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
-	int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
-
-	/* These callbacks are for devices that implement their own
-	 * tuning algorithms, rather than a simple swzigzag
-	 */
-	enum dvbfe_search (*search)(struct dvb_frontend *fe);
-
-	struct dvb_tuner_ops tuner_ops;
-	struct analog_demod_ops analog_ops;
-
-	int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
-	int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
-};
-
-#ifdef __DVB_CORE__
-#define MAX_EVENT 8
-
-struct dvb_fe_events {
-	struct dvb_frontend_event events[MAX_EVENT];
-	int			  eventw;
-	int			  eventr;
-	int			  overflow;
-	wait_queue_head_t	  wait_queue;
-	struct mutex		  mtx;
-};
-#endif
-
-struct dtv_frontend_properties {
-
-	/* Cache State */
-	u32			state;
-
-	u32			frequency;
-	fe_modulation_t		modulation;
-
-	fe_sec_voltage_t	voltage;
-	fe_sec_tone_mode_t	sectone;
-	fe_spectral_inversion_t	inversion;
-	fe_code_rate_t		fec_inner;
-	fe_transmit_mode_t	transmission_mode;
-	u32			bandwidth_hz;	/* 0 = AUTO */
-	fe_guard_interval_t	guard_interval;
-	fe_hierarchy_t		hierarchy;
-	u32			symbol_rate;
-	fe_code_rate_t		code_rate_HP;
-	fe_code_rate_t		code_rate_LP;
-
-	fe_pilot_t		pilot;
-	fe_rolloff_t		rolloff;
-
-	fe_delivery_system_t	delivery_system;
-
-	/* ISDB-T specifics */
-	u8			isdbt_partial_reception;
-	u8			isdbt_sb_mode;
-	u8			isdbt_sb_subchannel;
-	u32			isdbt_sb_segment_idx;
-	u32			isdbt_sb_segment_count;
-	u8			isdbt_layer_enabled;
-	struct {
-	    u8			segment_count;
-	    fe_code_rate_t	fec;
-	    fe_modulation_t	modulation;
-	    u8			interleaving;
-	} layer[3];
-
-	/* ISDB-T specifics */
-	u32			isdbs_ts_id;
-
-	/* DVB-T2 specifics */
-	u32                     dvbt2_plp_id;
-
-	/* ATSC-MH specifics */
-	u8			atscmh_fic_ver;
-	u8			atscmh_parade_id;
-	u8			atscmh_nog;
-	u8			atscmh_tnog;
-	u8			atscmh_sgn;
-	u8			atscmh_prc;
-
-	u8			atscmh_rs_frame_mode;
-	u8			atscmh_rs_frame_ensemble;
-	u8			atscmh_rs_code_mode_pri;
-	u8			atscmh_rs_code_mode_sec;
-	u8			atscmh_sccc_block_mode;
-	u8			atscmh_sccc_code_mode_a;
-	u8			atscmh_sccc_code_mode_b;
-	u8			atscmh_sccc_code_mode_c;
-	u8			atscmh_sccc_code_mode_d;
-};
-
-struct dvb_frontend {
-	struct dvb_frontend_ops ops;
-	struct dvb_adapter *dvb;
-	void *demodulator_priv;
-	void *tuner_priv;
-	void *frontend_priv;
-	void *sec_priv;
-	void *analog_demod_priv;
-	struct dtv_frontend_properties dtv_property_cache;
-#define DVB_FRONTEND_COMPONENT_TUNER 0
-#define DVB_FRONTEND_COMPONENT_DEMOD 1
-	int (*callback)(void *adapter_priv, int component, int cmd, int arg);
-	int id;
-};
-
-extern int dvb_register_frontend(struct dvb_adapter *dvb,
-				 struct dvb_frontend *fe);
-
-extern int dvb_unregister_frontend(struct dvb_frontend *fe);
-
-extern void dvb_frontend_detach(struct dvb_frontend *fe);
-
-extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
-
-extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec);
-extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime);
-
-#endif
diff --git a/drivers/media/dvb/dvb-core/dvb_math.c b/drivers/media/dvb/dvb-core/dvb_math.c
deleted file mode 100644
index beb7c93..0000000
--- a/drivers/media/dvb/dvb-core/dvb_math.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * dvb-math provides some complex fixed-point math
- * operations shared between the dvb related stuff
- *
- * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/bitops.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/bug.h>
-#include "dvb_math.h"
-
-static const unsigned short logtable[256] = {
-	0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
-	0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
-	0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
-	0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
-	0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
-	0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
-	0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
-	0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
-	0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
-	0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
-	0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
-	0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
-	0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
-	0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
-	0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
-	0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
-	0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
-	0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
-	0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
-	0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
-	0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
-	0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
-	0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
-	0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
-	0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
-	0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
-	0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
-	0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
-	0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
-	0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
-	0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
-	0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
-};
-
-unsigned int intlog2(u32 value)
-{
-	/**
-	 *	returns: log2(value) * 2^24
-	 *	wrong result if value = 0 (log2(0) is undefined)
-	 */
-	unsigned int msb;
-	unsigned int logentry;
-	unsigned int significand;
-	unsigned int interpolation;
-
-	if (unlikely(value == 0)) {
-		WARN_ON(1);
-		return 0;
-	}
-
-	/* first detect the msb (count begins at 0) */
-	msb = fls(value) - 1;
-
-	/**
-	 *	now we use a logtable after the following method:
-	 *
-	 *	log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
-	 *	where x = msb and therefore 1 <= y < 2
-	 *	first y is determined by shifting the value left
-	 *	so that msb is bit 31
-	 *		0x00231f56 -> 0x8C7D5800
-	 *	the result is y * 2^31 -> "significand"
-	 *	then the highest 9 bits are used for a table lookup
-	 *	the highest bit is discarded because it's always set
-	 *	the highest nine bits in our example are 100011000
-	 *	so we would use the entry 0x18
-	 */
-	significand = value << (31 - msb);
-	logentry = (significand >> 23) & 0xff;
-
-	/**
-	 *	last step we do is interpolation because of the
-	 *	limitations of the log table the error is that part of
-	 *	the significand which isn't used for lookup then we
-	 *	compute the ratio between the error and the next table entry
-	 *	and interpolate it between the log table entry used and the
-	 *	next one the biggest error possible is 0x7fffff
-	 *	(in our example it's 0x7D5800)
-	 *	needed value for next table entry is 0x800000
-	 *	so the interpolation is
-	 *	(error / 0x800000) * (logtable_next - logtable_current)
-	 *	in the implementation the division is moved to the end for
-	 *	better accuracy there is also an overflow correction if
-	 *	logtable_next is 256
-	 */
-	interpolation = ((significand & 0x7fffff) *
-			((logtable[(logentry + 1) & 0xff] -
-			  logtable[logentry]) & 0xffff)) >> 15;
-
-	/* now we return the result */
-	return ((msb << 24) + (logtable[logentry] << 8) + interpolation);
-}
-EXPORT_SYMBOL(intlog2);
-
-unsigned int intlog10(u32 value)
-{
-	/**
-	 *	returns: log10(value) * 2^24
-	 *	wrong result if value = 0 (log10(0) is undefined)
-	 */
-	u64 log;
-
-	if (unlikely(value == 0)) {
-		WARN_ON(1);
-		return 0;
-	}
-
-	log = intlog2(value);
-
-	/**
-	 *	we use the following method:
-	 *	log10(x) = log2(x) * log10(2)
-	 */
-
-	return (log * 646456993) >> 31;
-}
-EXPORT_SYMBOL(intlog10);
diff --git a/drivers/media/dvb/dvb-core/dvb_math.h b/drivers/media/dvb/dvb-core/dvb_math.h
deleted file mode 100644
index aecc867..0000000
--- a/drivers/media/dvb/dvb-core/dvb_math.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * dvb-math provides some complex fixed-point math
- * operations shared between the dvb related stuff
- *
- * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef __DVB_MATH_H
-#define __DVB_MATH_H
-
-#include <linux/types.h>
-
-/**
- * computes log2 of a value; the result is shifted left by 24 bits
- *
- * to use rational values you can use the following method:
- *   intlog2(value) = intlog2(value * 2^x) - x * 2^24
- *
- * example: intlog2(8) will give 3 << 24 = 3 * 2^24
- * example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
- * example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
- *
- * @param value The value (must be != 0)
- * @return log2(value) * 2^24
- */
-extern unsigned int intlog2(u32 value);
-
-/**
- * computes log10 of a value; the result is shifted left by 24 bits
- *
- * to use rational values you can use the following method:
- *   intlog10(value) = intlog10(value * 10^x) - x * 2^24
- *
- * example: intlog10(1000) will give 3 << 24 = 3 * 2^24
- *   due to the implementation intlog10(1000) might be not exactly 3 * 2^24
- *
- * look at intlog2 for similar examples
- *
- * @param value The value (must be != 0)
- * @return log10(value) * 2^24
- */
-extern unsigned int intlog10(u32 value);
-
-#endif
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
deleted file mode 100644
index 8766ce8..0000000
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ /dev/null
@@ -1,1516 +0,0 @@
-/*
- * dvb_net.c
- *
- * Copyright (C) 2001 Convergence integrated media GmbH
- *                    Ralph Metzler <ralph@convergence.de>
- * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
- *
- * ULE Decapsulation code:
- * Copyright (C) 2003, 2004 gcs - Global Communication & Services GmbH.
- *                      and Department of Scientific Computing
- *                          Paris Lodron University of Salzburg.
- *                          Hilmar Linder <hlinder@cosy.sbg.ac.at>
- *                      and Wolfram Stering <wstering@cosy.sbg.ac.at>
- *
- * ULE Decaps according to RFC 4326.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-/*
- * ULE ChangeLog:
- * Feb 2004: hl/ws v1: Implementing draft-fair-ipdvb-ule-01.txt
- *
- * Dec 2004: hl/ws v2: Implementing draft-ietf-ipdvb-ule-03.txt:
- *                       ULE Extension header handling.
- *                     Bugreports by Moritz Vieth and Hanno Tersteegen,
- *                       Fraunhofer Institute for Open Communication Systems
- *                       Competence Center for Advanced Satellite Communications.
- *                     Bugfixes and robustness improvements.
- *                     Filtering on dest MAC addresses, if present (D-Bit = 0)
- *                     ULE_DEBUG compile-time option.
- * Apr 2006: cp v3:    Bugfixes and compliency with RFC 4326 (ULE) by
- *                       Christian Praehauser <cpraehaus@cosy.sbg.ac.at>,
- *                       Paris Lodron University of Salzburg.
- */
-
-/*
- * FIXME / TODO (dvb_net.c):
- *
- * Unloading does not work for 2.6.9 kernels: a refcount doesn't go to zero.
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/dvb/net.h>
-#include <linux/uio.h>
-#include <asm/uaccess.h>
-#include <linux/crc32.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-
-#include "dvb_demux.h"
-#include "dvb_net.h"
-
-static int dvb_net_debug;
-module_param(dvb_net_debug, int, 0444);
-MODULE_PARM_DESC(dvb_net_debug, "enable debug messages");
-
-#define dprintk(x...) do { if (dvb_net_debug) printk(x); } while (0)
-
-
-static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
-{
-	unsigned int j;
-	for (j = 0; j < cnt; j++)
-		c = crc32_be( c, iov[j].iov_base, iov[j].iov_len );
-	return c;
-}
-
-
-#define DVB_NET_MULTICAST_MAX 10
-
-#undef ULE_DEBUG
-
-#ifdef ULE_DEBUG
-
-#define MAC_ADDR_PRINTFMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"
-#define MAX_ADDR_PRINTFMT_ARGS(macap) (macap)[0],(macap)[1],(macap)[2],(macap)[3],(macap)[4],(macap)[5]
-
-#define isprint(c)	((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
-
-static void hexdump( const unsigned char *buf, unsigned short len )
-{
-	char str[80], octet[10];
-	int ofs, i, l;
-
-	for (ofs = 0; ofs < len; ofs += 16) {
-		sprintf( str, "%03d: ", ofs );
-
-		for (i = 0; i < 16; i++) {
-			if ((i + ofs) < len)
-				sprintf( octet, "%02x ", buf[ofs + i] );
-			else
-				strcpy( octet, "   " );
-
-			strcat( str, octet );
-		}
-		strcat( str, "  " );
-		l = strlen( str );
-
-		for (i = 0; (i < 16) && ((i + ofs) < len); i++)
-			str[l++] = isprint( buf[ofs + i] ) ? buf[ofs + i] : '.';
-
-		str[l] = '\0';
-		printk( KERN_WARNING "%s\n", str );
-	}
-}
-
-#endif
-
-struct dvb_net_priv {
-	int in_use;
-	u16 pid;
-	struct net_device *net;
-	struct dvb_net *host;
-	struct dmx_demux *demux;
-	struct dmx_section_feed *secfeed;
-	struct dmx_section_filter *secfilter;
-	struct dmx_ts_feed *tsfeed;
-	int multi_num;
-	struct dmx_section_filter *multi_secfilter[DVB_NET_MULTICAST_MAX];
-	unsigned char multi_macs[DVB_NET_MULTICAST_MAX][6];
-	int rx_mode;
-#define RX_MODE_UNI 0
-#define RX_MODE_MULTI 1
-#define RX_MODE_ALL_MULTI 2
-#define RX_MODE_PROMISC 3
-	struct work_struct set_multicast_list_wq;
-	struct work_struct restart_net_feed_wq;
-	unsigned char feedtype;			/* Either FEED_TYPE_ or FEED_TYPE_ULE */
-	int need_pusi;				/* Set to 1, if synchronization on PUSI required. */
-	unsigned char tscc;			/* TS continuity counter after sync on PUSI. */
-	struct sk_buff *ule_skb;		/* ULE SNDU decodes into this buffer. */
-	unsigned char *ule_next_hdr;		/* Pointer into skb to next ULE extension header. */
-	unsigned short ule_sndu_len;		/* ULE SNDU length in bytes, w/o D-Bit. */
-	unsigned short ule_sndu_type;		/* ULE SNDU type field, complete. */
-	unsigned char ule_sndu_type_1;		/* ULE SNDU type field, if split across 2 TS cells. */
-	unsigned char ule_dbit;			/* Whether the DestMAC address present
-						 * or not (bit is set). */
-	unsigned char ule_bridged;		/* Whether the ULE_BRIDGED extension header was found. */
-	int ule_sndu_remain;			/* Nr. of bytes still required for current ULE SNDU. */
-	unsigned long ts_count;			/* Current ts cell counter. */
-	struct mutex mutex;
-};
-
-
-/**
- *	Determine the packet's protocol ID. The rule here is that we
- *	assume 802.3 if the type field is short enough to be a length.
- *	This is normal practice and works for any 'now in use' protocol.
- *
- *  stolen from eth.c out of the linux kernel, hacked for dvb-device
- *  by Michael Holzt <kju@debian.org>
- */
-static __be16 dvb_net_eth_type_trans(struct sk_buff *skb,
-				      struct net_device *dev)
-{
-	struct ethhdr *eth;
-	unsigned char *rawp;
-
-	skb_reset_mac_header(skb);
-	skb_pull(skb,dev->hard_header_len);
-	eth = eth_hdr(skb);
-
-	if (*eth->h_dest & 1) {
-		if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
-			skb->pkt_type=PACKET_BROADCAST;
-		else
-			skb->pkt_type=PACKET_MULTICAST;
-	}
-
-	if (ntohs(eth->h_proto) >= 1536)
-		return eth->h_proto;
-
-	rawp = skb->data;
-
-	/**
-	 *	This is a magic hack to spot IPX packets. Older Novell breaks
-	 *	the protocol design and runs IPX over 802.3 without an 802.2 LLC
-	 *	layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
-	 *	won't work for fault tolerant netware but does for the rest.
-	 */
-	if (*(unsigned short *)rawp == 0xFFFF)
-		return htons(ETH_P_802_3);
-
-	/**
-	 *	Real 802.2 LLC
-	 */
-	return htons(ETH_P_802_2);
-}
-
-#define TS_SZ	188
-#define TS_SYNC	0x47
-#define TS_TEI	0x80
-#define TS_SC	0xC0
-#define TS_PUSI	0x40
-#define TS_AF_A	0x20
-#define TS_AF_D	0x10
-
-/* ULE Extension Header handlers. */
-
-#define ULE_TEST	0
-#define ULE_BRIDGED	1
-
-#define ULE_OPTEXTHDR_PADDING 0
-
-static int ule_test_sndu( struct dvb_net_priv *p )
-{
-	return -1;
-}
-
-static int ule_bridged_sndu( struct dvb_net_priv *p )
-{
-	struct ethhdr *hdr = (struct ethhdr*) p->ule_next_hdr;
-	if(ntohs(hdr->h_proto) < 1536) {
-		int framelen = p->ule_sndu_len - ((p->ule_next_hdr+sizeof(struct ethhdr)) - p->ule_skb->data);
-		/* A frame Type < 1536 for a bridged frame, introduces a LLC Length field. */
-		if(framelen != ntohs(hdr->h_proto)) {
-			return -1;
-		}
-	}
-	/* Note:
-	 * From RFC4326:
-	 *  "A bridged SNDU is a Mandatory Extension Header of Type 1.
-	 *   It must be the final (or only) extension header specified in the header chain of a SNDU."
-	 * The 'ule_bridged' flag will cause the extension header processing loop to terminate.
-	 */
-	p->ule_bridged = 1;
-	return 0;
-}
-
-static int ule_exthdr_padding(struct dvb_net_priv *p)
-{
-	return 0;
-}
-
-/** Handle ULE extension headers.
- *  Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding.
- *  Returns: >= 0: nr. of bytes consumed by next extension header
- *	     -1:   Mandatory extension header that is not recognized or TEST SNDU; discard.
- */
-static int handle_one_ule_extension( struct dvb_net_priv *p )
-{
-	/* Table of mandatory extension header handlers.  The header type is the index. */
-	static int (*ule_mandatory_ext_handlers[255])( struct dvb_net_priv *p ) =
-		{ [0] = ule_test_sndu, [1] = ule_bridged_sndu, [2] = NULL,  };
-
-	/* Table of optional extension header handlers.  The header type is the index. */
-	static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) =
-		{ [0] = ule_exthdr_padding, [1] = NULL, };
-
-	int ext_len = 0;
-	unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8;
-	unsigned char htype = p->ule_sndu_type & 0x00FF;
-
-	/* Discriminate mandatory and optional extension headers. */
-	if (hlen == 0) {
-		/* Mandatory extension header */
-		if (ule_mandatory_ext_handlers[htype]) {
-			ext_len = ule_mandatory_ext_handlers[htype]( p );
-			if(ext_len >= 0) {
-				p->ule_next_hdr += ext_len;
-				if (!p->ule_bridged) {
-					p->ule_sndu_type = ntohs(*(__be16 *)p->ule_next_hdr);
-					p->ule_next_hdr += 2;
-				} else {
-					p->ule_sndu_type = ntohs(*(__be16 *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)));
-					/* This assures the extension handling loop will terminate. */
-				}
-			}
-			// else: extension handler failed or SNDU should be discarded
-		} else
-			ext_len = -1;	/* SNDU has to be discarded. */
-	} else {
-		/* Optional extension header.  Calculate the length. */
-		ext_len = hlen << 1;
-		/* Process the optional extension header according to its type. */
-		if (ule_optional_ext_handlers[htype])
-			(void)ule_optional_ext_handlers[htype]( p );
-		p->ule_next_hdr += ext_len;
-		p->ule_sndu_type = ntohs( *(__be16 *)(p->ule_next_hdr-2) );
-		/*
-		 * note: the length of the next header type is included in the
-		 * length of THIS optional extension header
-		 */
-	}
-
-	return ext_len;
-}
-
-static int handle_ule_extensions( struct dvb_net_priv *p )
-{
-	int total_ext_len = 0, l;
-
-	p->ule_next_hdr = p->ule_skb->data;
-	do {
-		l = handle_one_ule_extension( p );
-		if (l < 0)
-			return l;	/* Stop extension header processing and discard SNDU. */
-		total_ext_len += l;
-#ifdef ULE_DEBUG
-		dprintk("handle_ule_extensions: ule_next_hdr=%p, ule_sndu_type=%i, "
-			"l=%i, total_ext_len=%i\n", p->ule_next_hdr,
-			(int) p->ule_sndu_type, l, total_ext_len);
-#endif
-
-	} while (p->ule_sndu_type < 1536);
-
-	return total_ext_len;
-}
-
-
-/** Prepare for a new ULE SNDU: reset the decoder state. */
-static inline void reset_ule( struct dvb_net_priv *p )
-{
-	p->ule_skb = NULL;
-	p->ule_next_hdr = NULL;
-	p->ule_sndu_len = 0;
-	p->ule_sndu_type = 0;
-	p->ule_sndu_type_1 = 0;
-	p->ule_sndu_remain = 0;
-	p->ule_dbit = 0xFF;
-	p->ule_bridged = 0;
-}
-
-/**
- * Decode ULE SNDUs according to draft-ietf-ipdvb-ule-03.txt from a sequence of
- * TS cells of a single PID.
- */
-static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
-{
-	struct dvb_net_priv *priv = netdev_priv(dev);
-	unsigned long skipped = 0L;
-	const u8 *ts, *ts_end, *from_where = NULL;
-	u8 ts_remain = 0, how_much = 0, new_ts = 1;
-	struct ethhdr *ethh = NULL;
-	bool error = false;
-
-#ifdef ULE_DEBUG
-	/* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */
-	static unsigned char ule_hist[100*TS_SZ];
-	static unsigned char *ule_where = ule_hist, ule_dump;
-#endif
-
-	/* For all TS cells in current buffer.
-	 * Appearently, we are called for every single TS cell.
-	 */
-	for (ts = buf, ts_end = buf + buf_len; ts < ts_end; /* no default incr. */ ) {
-
-		if (new_ts) {
-			/* We are about to process a new TS cell. */
-
-#ifdef ULE_DEBUG
-			if (ule_where >= &ule_hist[100*TS_SZ]) ule_where = ule_hist;
-			memcpy( ule_where, ts, TS_SZ );
-			if (ule_dump) {
-				hexdump( ule_where, TS_SZ );
-				ule_dump = 0;
-			}
-			ule_where += TS_SZ;
-#endif
-
-			/* Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control . */
-			if ((ts[0] != TS_SYNC) || (ts[1] & TS_TEI) || ((ts[3] & TS_SC) != 0)) {
-				printk(KERN_WARNING "%lu: Invalid TS cell: SYNC %#x, TEI %u, SC %#x.\n",
-				       priv->ts_count, ts[0], ts[1] & TS_TEI >> 7, ts[3] & 0xC0 >> 6);
-
-				/* Drop partly decoded SNDU, reset state, resync on PUSI. */
-				if (priv->ule_skb) {
-					dev_kfree_skb( priv->ule_skb );
-					/* Prepare for next SNDU. */
-					dev->stats.rx_errors++;
-					dev->stats.rx_frame_errors++;
-				}
-				reset_ule(priv);
-				priv->need_pusi = 1;
-
-				/* Continue with next TS cell. */
-				ts += TS_SZ;
-				priv->ts_count++;
-				continue;
-			}
-
-			ts_remain = 184;
-			from_where = ts + 4;
-		}
-		/* Synchronize on PUSI, if required. */
-		if (priv->need_pusi) {
-			if (ts[1] & TS_PUSI) {
-				/* Find beginning of first ULE SNDU in current TS cell. */
-				/* Synchronize continuity counter. */
-				priv->tscc = ts[3] & 0x0F;
-				/* There is a pointer field here. */
-				if (ts[4] > ts_remain) {
-					printk(KERN_ERR "%lu: Invalid ULE packet "
-					       "(pointer field %d)\n", priv->ts_count, ts[4]);
-					ts += TS_SZ;
-					priv->ts_count++;
-					continue;
-				}
-				/* Skip to destination of pointer field. */
-				from_where = &ts[5] + ts[4];
-				ts_remain -= 1 + ts[4];
-				skipped = 0;
-			} else {
-				skipped++;
-				ts += TS_SZ;
-				priv->ts_count++;
-				continue;
-			}
-		}
-
-		if (new_ts) {
-			/* Check continuity counter. */
-			if ((ts[3] & 0x0F) == priv->tscc)
-				priv->tscc = (priv->tscc + 1) & 0x0F;
-			else {
-				/* TS discontinuity handling: */
-				printk(KERN_WARNING "%lu: TS discontinuity: got %#x, "
-				       "expected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);
-				/* Drop partly decoded SNDU, reset state, resync on PUSI. */
-				if (priv->ule_skb) {
-					dev_kfree_skb( priv->ule_skb );
-					/* Prepare for next SNDU. */
-					// reset_ule(priv);  moved to below.
-					dev->stats.rx_errors++;
-					dev->stats.rx_frame_errors++;
-				}
-				reset_ule(priv);
-				/* skip to next PUSI. */
-				priv->need_pusi = 1;
-				continue;
-			}
-			/* If we still have an incomplete payload, but PUSI is
-			 * set; some TS cells are missing.
-			 * This is only possible here, if we missed exactly 16 TS
-			 * cells (continuity counter wrap). */
-			if (ts[1] & TS_PUSI) {
-				if (! priv->need_pusi) {
-					if (!(*from_where < (ts_remain-1)) || *from_where != priv->ule_sndu_remain) {
-						/* Pointer field is invalid.  Drop this TS cell and any started ULE SNDU. */
-						printk(KERN_WARNING "%lu: Invalid pointer "
-						       "field: %u.\n", priv->ts_count, *from_where);
-
-						/* Drop partly decoded SNDU, reset state, resync on PUSI. */
-						if (priv->ule_skb) {
-							error = true;
-							dev_kfree_skb(priv->ule_skb);
-						}
-
-						if (error || priv->ule_sndu_remain) {
-							dev->stats.rx_errors++;
-							dev->stats.rx_frame_errors++;
-							error = false;
-						}
-
-						reset_ule(priv);
-						priv->need_pusi = 1;
-						continue;
-					}
-					/* Skip pointer field (we're processing a
-					 * packed payload). */
-					from_where += 1;
-					ts_remain -= 1;
-				} else
-					priv->need_pusi = 0;
-
-				if (priv->ule_sndu_remain > 183) {
-					/* Current SNDU lacks more data than there could be available in the
-					 * current TS cell. */
-					dev->stats.rx_errors++;
-					dev->stats.rx_length_errors++;
-					printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but "
-					       "got PUSI (pf %d, ts_remain %d).  Flushing incomplete payload.\n",
-					       priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain);
-					dev_kfree_skb(priv->ule_skb);
-					/* Prepare for next SNDU. */
-					reset_ule(priv);
-					/* Resync: go to where pointer field points to: start of next ULE SNDU. */
-					from_where += ts[4];
-					ts_remain -= ts[4];
-				}
-			}
-		}
-
-		/* Check if new payload needs to be started. */
-		if (priv->ule_skb == NULL) {
-			/* Start a new payload with skb.
-			 * Find ULE header.  It is only guaranteed that the
-			 * length field (2 bytes) is contained in the current
-			 * TS.
-			 * Check ts_remain has to be >= 2 here. */
-			if (ts_remain < 2) {
-				printk(KERN_WARNING "Invalid payload packing: only %d "
-				       "bytes left in TS.  Resyncing.\n", ts_remain);
-				priv->ule_sndu_len = 0;
-				priv->need_pusi = 1;
-				ts += TS_SZ;
-				continue;
-			}
-
-			if (! priv->ule_sndu_len) {
-				/* Got at least two bytes, thus extrace the SNDU length. */
-				priv->ule_sndu_len = from_where[0] << 8 | from_where[1];
-				if (priv->ule_sndu_len & 0x8000) {
-					/* D-Bit is set: no dest mac present. */
-					priv->ule_sndu_len &= 0x7FFF;
-					priv->ule_dbit = 1;
-				} else
-					priv->ule_dbit = 0;
-
-				if (priv->ule_sndu_len < 5) {
-					printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. "
-					       "Resyncing.\n", priv->ts_count, priv->ule_sndu_len);
-					dev->stats.rx_errors++;
-					dev->stats.rx_length_errors++;
-					priv->ule_sndu_len = 0;
-					priv->need_pusi = 1;
-					new_ts = 1;
-					ts += TS_SZ;
-					priv->ts_count++;
-					continue;
-				}
-				ts_remain -= 2;	/* consume the 2 bytes SNDU length. */
-				from_where += 2;
-			}
-
-			priv->ule_sndu_remain = priv->ule_sndu_len + 2;
-			/*
-			 * State of current TS:
-			 *   ts_remain (remaining bytes in the current TS cell)
-			 *   0	ule_type is not available now, we need the next TS cell
-			 *   1	the first byte of the ule_type is present
-			 * >=2	full ULE header present, maybe some payload data as well.
-			 */
-			switch (ts_remain) {
-				case 1:
-					priv->ule_sndu_remain--;
-					priv->ule_sndu_type = from_where[0] << 8;
-					priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */
-					ts_remain -= 1; from_where += 1;
-					/* Continue w/ next TS. */
-				case 0:
-					new_ts = 1;
-					ts += TS_SZ;
-					priv->ts_count++;
-					continue;
-
-				default: /* complete ULE header is present in current TS. */
-					/* Extract ULE type field. */
-					if (priv->ule_sndu_type_1) {
-						priv->ule_sndu_type_1 = 0;
-						priv->ule_sndu_type |= from_where[0];
-						from_where += 1; /* points to payload start. */
-						ts_remain -= 1;
-					} else {
-						/* Complete type is present in new TS. */
-						priv->ule_sndu_type = from_where[0] << 8 | from_where[1];
-						from_where += 2; /* points to payload start. */
-						ts_remain -= 2;
-					}
-					break;
-			}
-
-			/* Allocate the skb (decoder target buffer) with the correct size, as follows:
-			 * prepare for the largest case: bridged SNDU with MAC address (dbit = 0). */
-			priv->ule_skb = dev_alloc_skb( priv->ule_sndu_len + ETH_HLEN + ETH_ALEN );
-			if (priv->ule_skb == NULL) {
-				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
-				       dev->name);
-				dev->stats.rx_dropped++;
-				return;
-			}
-
-			/* This includes the CRC32 _and_ dest mac, if !dbit. */
-			priv->ule_sndu_remain = priv->ule_sndu_len;
-			priv->ule_skb->dev = dev;
-			/* Leave space for Ethernet or bridged SNDU header (eth hdr plus one MAC addr). */
-			skb_reserve( priv->ule_skb, ETH_HLEN + ETH_ALEN );
-		}
-
-		/* Copy data into our current skb. */
-		how_much = min(priv->ule_sndu_remain, (int)ts_remain);
-		memcpy(skb_put(priv->ule_skb, how_much), from_where, how_much);
-		priv->ule_sndu_remain -= how_much;
-		ts_remain -= how_much;
-		from_where += how_much;
-
-		/* Check for complete payload. */
-		if (priv->ule_sndu_remain <= 0) {
-			/* Check CRC32, we've got it in our skb already. */
-			__be16 ulen = htons(priv->ule_sndu_len);
-			__be16 utype = htons(priv->ule_sndu_type);
-			const u8 *tail;
-			struct kvec iov[3] = {
-				{ &ulen, sizeof ulen },
-				{ &utype, sizeof utype },
-				{ priv->ule_skb->data, priv->ule_skb->len - 4 }
-			};
-			u32 ule_crc = ~0L, expected_crc;
-			if (priv->ule_dbit) {
-				/* Set D-bit for CRC32 verification,
-				 * if it was set originally. */
-				ulen |= htons(0x8000);
-			}
-
-			ule_crc = iov_crc32(ule_crc, iov, 3);
-			tail = skb_tail_pointer(priv->ule_skb);
-			expected_crc = *(tail - 4) << 24 |
-				       *(tail - 3) << 16 |
-				       *(tail - 2) << 8 |
-				       *(tail - 1);
-			if (ule_crc != expected_crc) {
-				printk(KERN_WARNING "%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n",
-				       priv->ts_count, ule_crc, expected_crc, priv->ule_sndu_len, priv->ule_sndu_type, ts_remain, ts_remain > 2 ? *(unsigned short *)from_where : 0);
-
-#ifdef ULE_DEBUG
-				hexdump( iov[0].iov_base, iov[0].iov_len );
-				hexdump( iov[1].iov_base, iov[1].iov_len );
-				hexdump( iov[2].iov_base, iov[2].iov_len );
-
-				if (ule_where == ule_hist) {
-					hexdump( &ule_hist[98*TS_SZ], TS_SZ );
-					hexdump( &ule_hist[99*TS_SZ], TS_SZ );
-				} else if (ule_where == &ule_hist[TS_SZ]) {
-					hexdump( &ule_hist[99*TS_SZ], TS_SZ );
-					hexdump( ule_hist, TS_SZ );
-				} else {
-					hexdump( ule_where - TS_SZ - TS_SZ, TS_SZ );
-					hexdump( ule_where - TS_SZ, TS_SZ );
-				}
-				ule_dump = 1;
-#endif
-
-				dev->stats.rx_errors++;
-				dev->stats.rx_crc_errors++;
-				dev_kfree_skb(priv->ule_skb);
-			} else {
-				/* CRC32 verified OK. */
-				u8 dest_addr[ETH_ALEN];
-				static const u8 bc_addr[ETH_ALEN] =
-					{ [ 0 ... ETH_ALEN-1] = 0xff };
-
-				/* CRC32 was OK. Remove it from skb. */
-				priv->ule_skb->tail -= 4;
-				priv->ule_skb->len -= 4;
-
-				if (!priv->ule_dbit) {
-					/*
-					 * The destination MAC address is the
-					 * next data in the skb.  It comes
-					 * before any extension headers.
-					 *
-					 * Check if the payload of this SNDU
-					 * should be passed up the stack.
-					 */
-					register int drop = 0;
-					if (priv->rx_mode != RX_MODE_PROMISC) {
-						if (priv->ule_skb->data[0] & 0x01) {
-							/* multicast or broadcast */
-							if (memcmp(priv->ule_skb->data, bc_addr, ETH_ALEN)) {
-								/* multicast */
-								if (priv->rx_mode == RX_MODE_MULTI) {
-									int i;
-									for(i = 0; i < priv->multi_num && memcmp(priv->ule_skb->data, priv->multi_macs[i], ETH_ALEN); i++)
-										;
-									if (i == priv->multi_num)
-										drop = 1;
-								} else if (priv->rx_mode != RX_MODE_ALL_MULTI)
-									drop = 1; /* no broadcast; */
-								/* else: all multicast mode: accept all multicast packets */
-							}
-							/* else: broadcast */
-						}
-						else if (memcmp(priv->ule_skb->data, dev->dev_addr, ETH_ALEN))
-							drop = 1;
-						/* else: destination address matches the MAC address of our receiver device */
-					}
-					/* else: promiscuous mode; pass everything up the stack */
-
-					if (drop) {
-#ifdef ULE_DEBUG
-						dprintk("Dropping SNDU: MAC destination address does not match: dest addr: "MAC_ADDR_PRINTFMT", dev addr: "MAC_ADDR_PRINTFMT"\n",
-							MAX_ADDR_PRINTFMT_ARGS(priv->ule_skb->data), MAX_ADDR_PRINTFMT_ARGS(dev->dev_addr));
-#endif
-						dev_kfree_skb(priv->ule_skb);
-						goto sndu_done;
-					}
-					else
-					{
-						skb_copy_from_linear_data(priv->ule_skb,
-							      dest_addr,
-							      ETH_ALEN);
-						skb_pull(priv->ule_skb, ETH_ALEN);
-					}
-				}
-
-				/* Handle ULE Extension Headers. */
-				if (priv->ule_sndu_type < 1536) {
-					/* There is an extension header.  Handle it accordingly. */
-					int l = handle_ule_extensions(priv);
-					if (l < 0) {
-						/* Mandatory extension header unknown or TEST SNDU.  Drop it. */
-						// printk( KERN_WARNING "Dropping SNDU, extension headers.\n" );
-						dev_kfree_skb(priv->ule_skb);
-						goto sndu_done;
-					}
-					skb_pull(priv->ule_skb, l);
-				}
-
-				/*
-				 * Construct/assure correct ethernet header.
-				 * Note: in bridged mode (priv->ule_bridged !=
-				 * 0) we already have the (original) ethernet
-				 * header at the start of the payload (after
-				 * optional dest. address and any extension
-				 * headers).
-				 */
-
-				if (!priv->ule_bridged) {
-					skb_push(priv->ule_skb, ETH_HLEN);
-					ethh = (struct ethhdr *)priv->ule_skb->data;
-					if (!priv->ule_dbit) {
-						 /* dest_addr buffer is only valid if priv->ule_dbit == 0 */
-						memcpy(ethh->h_dest, dest_addr, ETH_ALEN);
-						memset(ethh->h_source, 0, ETH_ALEN);
-					}
-					else /* zeroize source and dest */
-						memset( ethh, 0, ETH_ALEN*2 );
-
-					ethh->h_proto = htons(priv->ule_sndu_type);
-				}
-				/* else:  skb is in correct state; nothing to do. */
-				priv->ule_bridged = 0;
-
-				/* Stuff into kernel's protocol stack. */
-				priv->ule_skb->protocol = dvb_net_eth_type_trans(priv->ule_skb, dev);
-				/* If D-bit is set (i.e. destination MAC address not present),
-				 * receive the packet anyhow. */
-				/* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST)
-					priv->ule_skb->pkt_type = PACKET_HOST; */
-				dev->stats.rx_packets++;
-				dev->stats.rx_bytes += priv->ule_skb->len;
-				netif_rx(priv->ule_skb);
-			}
-			sndu_done:
-			/* Prepare for next SNDU. */
-			reset_ule(priv);
-		}
-
-		/* More data in current TS (look at the bytes following the CRC32)? */
-		if (ts_remain >= 2 && *((unsigned short *)from_where) != 0xFFFF) {
-			/* Next ULE SNDU starts right there. */
-			new_ts = 0;
-			priv->ule_skb = NULL;
-			priv->ule_sndu_type_1 = 0;
-			priv->ule_sndu_len = 0;
-			// printk(KERN_WARNING "More data in current TS: [%#x %#x %#x %#x]\n",
-			//	*(from_where + 0), *(from_where + 1),
-			//	*(from_where + 2), *(from_where + 3));
-			// printk(KERN_WARNING "ts @ %p, stopped @ %p:\n", ts, from_where + 0);
-			// hexdump(ts, 188);
-		} else {
-			new_ts = 1;
-			ts += TS_SZ;
-			priv->ts_count++;
-			if (priv->ule_skb == NULL) {
-				priv->need_pusi = 1;
-				priv->ule_sndu_type_1 = 0;
-				priv->ule_sndu_len = 0;
-			}
-		}
-	}	/* for all available TS cells */
-}
-
-static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len,
-			       const u8 *buffer2, size_t buffer2_len,
-			       struct dmx_ts_feed *feed, enum dmx_success success)
-{
-	struct net_device *dev = feed->priv;
-
-	if (buffer2)
-		printk(KERN_WARNING "buffer2 not NULL: %p.\n", buffer2);
-	if (buffer1_len > 32768)
-		printk(KERN_WARNING "length > 32k: %zu.\n", buffer1_len);
-	/* printk("TS callback: %u bytes, %u TS cells @ %p.\n",
-		  buffer1_len, buffer1_len / TS_SZ, buffer1); */
-	dvb_net_ule(dev, buffer1, buffer1_len);
-	return 0;
-}
-
-
-static void dvb_net_sec(struct net_device *dev,
-			const u8 *pkt, int pkt_len)
-{
-	u8 *eth;
-	struct sk_buff *skb;
-	struct net_device_stats *stats = &dev->stats;
-	int snap = 0;
-
-	/* note: pkt_len includes a 32bit checksum */
-	if (pkt_len < 16) {
-		printk("%s: IP/MPE packet length = %d too small.\n",
-			dev->name, pkt_len);
-		stats->rx_errors++;
-		stats->rx_length_errors++;
-		return;
-	}
-/* it seems some ISPs manage to screw up here, so we have to
- * relax the error checks... */
-#if 0
-	if ((pkt[5] & 0xfd) != 0xc1) {
-		/* drop scrambled or broken packets */
-#else
-	if ((pkt[5] & 0x3c) != 0x00) {
-		/* drop scrambled */
-#endif
-		stats->rx_errors++;
-		stats->rx_crc_errors++;
-		return;
-	}
-	if (pkt[5] & 0x02) {
-		/* handle LLC/SNAP, see rfc-1042 */
-		if (pkt_len < 24 || memcmp(&pkt[12], "\xaa\xaa\x03\0\0\0", 6)) {
-			stats->rx_dropped++;
-			return;
-		}
-		snap = 8;
-	}
-	if (pkt[7]) {
-		/* FIXME: assemble datagram from multiple sections */
-		stats->rx_errors++;
-		stats->rx_frame_errors++;
-		return;
-	}
-
-	/* we have 14 byte ethernet header (ip header follows);
-	 * 12 byte MPE header; 4 byte checksum; + 2 byte alignment, 8 byte LLC/SNAP
-	 */
-	if (!(skb = dev_alloc_skb(pkt_len - 4 - 12 + 14 + 2 - snap))) {
-		//printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
-		stats->rx_dropped++;
-		return;
-	}
-	skb_reserve(skb, 2);    /* longword align L3 header */
-	skb->dev = dev;
-
-	/* copy L3 payload */
-	eth = (u8 *) skb_put(skb, pkt_len - 12 - 4 + 14 - snap);
-	memcpy(eth + 14, pkt + 12 + snap, pkt_len - 12 - 4 - snap);
-
-	/* create ethernet header: */
-	eth[0]=pkt[0x0b];
-	eth[1]=pkt[0x0a];
-	eth[2]=pkt[0x09];
-	eth[3]=pkt[0x08];
-	eth[4]=pkt[0x04];
-	eth[5]=pkt[0x03];
-
-	eth[6]=eth[7]=eth[8]=eth[9]=eth[10]=eth[11]=0;
-
-	if (snap) {
-		eth[12] = pkt[18];
-		eth[13] = pkt[19];
-	} else {
-		/* protocol numbers are from rfc-1700 or
-		 * http://www.iana.org/assignments/ethernet-numbers
-		 */
-		if (pkt[12] >> 4 == 6) { /* version field from IP header */
-			eth[12] = 0x86;	/* IPv6 */
-			eth[13] = 0xdd;
-		} else {
-			eth[12] = 0x08;	/* IPv4 */
-			eth[13] = 0x00;
-		}
-	}
-
-	skb->protocol = dvb_net_eth_type_trans(skb, dev);
-
-	stats->rx_packets++;
-	stats->rx_bytes+=skb->len;
-	netif_rx(skb);
-}
-
-static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
-		 const u8 *buffer2, size_t buffer2_len,
-		 struct dmx_section_filter *filter,
-		 enum dmx_success success)
-{
-	struct net_device *dev = filter->priv;
-
-	/**
-	 * we rely on the DVB API definition where exactly one complete
-	 * section is delivered in buffer1
-	 */
-	dvb_net_sec (dev, buffer1, buffer1_len);
-	return 0;
-}
-
-static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev)
-{
-	dev_kfree_skb(skb);
-	return NETDEV_TX_OK;
-}
-
-static u8 mask_normal[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-static u8 mask_allmulti[6]={0xff, 0xff, 0xff, 0x00, 0x00, 0x00};
-static u8 mac_allmulti[6]={0x01, 0x00, 0x5e, 0x00, 0x00, 0x00};
-static u8 mask_promisc[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
-static int dvb_net_filter_sec_set(struct net_device *dev,
-		   struct dmx_section_filter **secfilter,
-		   u8 *mac, u8 *mac_mask)
-{
-	struct dvb_net_priv *priv = netdev_priv(dev);
-	int ret;
-
-	*secfilter=NULL;
-	ret = priv->secfeed->allocate_filter(priv->secfeed, secfilter);
-	if (ret<0) {
-		printk("%s: could not get filter\n", dev->name);
-		return ret;
-	}
-
-	(*secfilter)->priv=(void *) dev;
-
-	memset((*secfilter)->filter_value, 0x00, DMX_MAX_FILTER_SIZE);
-	memset((*secfilter)->filter_mask,  0x00, DMX_MAX_FILTER_SIZE);
-	memset((*secfilter)->filter_mode,  0xff, DMX_MAX_FILTER_SIZE);
-
-	(*secfilter)->filter_value[0]=0x3e;
-	(*secfilter)->filter_value[3]=mac[5];
-	(*secfilter)->filter_value[4]=mac[4];
-	(*secfilter)->filter_value[8]=mac[3];
-	(*secfilter)->filter_value[9]=mac[2];
-	(*secfilter)->filter_value[10]=mac[1];
-	(*secfilter)->filter_value[11]=mac[0];
-
-	(*secfilter)->filter_mask[0] = 0xff;
-	(*secfilter)->filter_mask[3] = mac_mask[5];
-	(*secfilter)->filter_mask[4] = mac_mask[4];
-	(*secfilter)->filter_mask[8] = mac_mask[3];
-	(*secfilter)->filter_mask[9] = mac_mask[2];
-	(*secfilter)->filter_mask[10] = mac_mask[1];
-	(*secfilter)->filter_mask[11]=mac_mask[0];
-
-	dprintk("%s: filter mac=%pM\n", dev->name, mac);
-	dprintk("%s: filter mask=%pM\n", dev->name, mac_mask);
-
-	return 0;
-}
-
-static int dvb_net_feed_start(struct net_device *dev)
-{
-	int ret = 0, i;
-	struct dvb_net_priv *priv = netdev_priv(dev);
-	struct dmx_demux *demux = priv->demux;
-	unsigned char *mac = (unsigned char *) dev->dev_addr;
-
-	dprintk("%s: rx_mode %i\n", __func__, priv->rx_mode);
-	mutex_lock(&priv->mutex);
-	if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0])
-		printk("%s: BUG %d\n", __func__, __LINE__);
-
-	priv->secfeed=NULL;
-	priv->secfilter=NULL;
-	priv->tsfeed = NULL;
-
-	if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
-		dprintk("%s: alloc secfeed\n", __func__);
-		ret=demux->allocate_section_feed(demux, &priv->secfeed,
-					 dvb_net_sec_callback);
-		if (ret<0) {
-			printk("%s: could not allocate section feed\n", dev->name);
-			goto error;
-		}
-
-		ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1);
-
-		if (ret<0) {
-			printk("%s: could not set section feed\n", dev->name);
-			priv->demux->release_section_feed(priv->demux, priv->secfeed);
-			priv->secfeed=NULL;
-			goto error;
-		}
-
-		if (priv->rx_mode != RX_MODE_PROMISC) {
-			dprintk("%s: set secfilter\n", __func__);
-			dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_normal);
-		}
-
-		switch (priv->rx_mode) {
-		case RX_MODE_MULTI:
-			for (i = 0; i < priv->multi_num; i++) {
-				dprintk("%s: set multi_secfilter[%d]\n", __func__, i);
-				dvb_net_filter_sec_set(dev, &priv->multi_secfilter[i],
-						       priv->multi_macs[i], mask_normal);
-			}
-			break;
-		case RX_MODE_ALL_MULTI:
-			priv->multi_num=1;
-			dprintk("%s: set multi_secfilter[0]\n", __func__);
-			dvb_net_filter_sec_set(dev, &priv->multi_secfilter[0],
-					       mac_allmulti, mask_allmulti);
-			break;
-		case RX_MODE_PROMISC:
-			priv->multi_num=0;
-			dprintk("%s: set secfilter\n", __func__);
-			dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_promisc);
-			break;
-		}
-
-		dprintk("%s: start filtering\n", __func__);
-		priv->secfeed->start_filtering(priv->secfeed);
-	} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
-		struct timespec timeout = { 0, 10000000 }; // 10 msec
-
-		/* we have payloads encapsulated in TS */
-		dprintk("%s: alloc tsfeed\n", __func__);
-		ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback);
-		if (ret < 0) {
-			printk("%s: could not allocate ts feed\n", dev->name);
-			goto error;
-		}
-
-		/* Set netdevice pointer for ts decaps callback. */
-		priv->tsfeed->priv = (void *)dev;
-		ret = priv->tsfeed->set(priv->tsfeed,
-					priv->pid, /* pid */
-					TS_PACKET, /* type */
-					DMX_TS_PES_OTHER, /* pes type */
-					32768,     /* circular buffer size */
-					timeout    /* timeout */
-					);
-
-		if (ret < 0) {
-			printk("%s: could not set ts feed\n", dev->name);
-			priv->demux->release_ts_feed(priv->demux, priv->tsfeed);
-			priv->tsfeed = NULL;
-			goto error;
-		}
-
-		dprintk("%s: start filtering\n", __func__);
-		priv->tsfeed->start_filtering(priv->tsfeed);
-	} else
-		ret = -EINVAL;
-
-error:
-	mutex_unlock(&priv->mutex);
-	return ret;
-}
-
-static int dvb_net_feed_stop(struct net_device *dev)
-{
-	struct dvb_net_priv *priv = netdev_priv(dev);
-	int i, ret = 0;
-
-	dprintk("%s\n", __func__);
-	mutex_lock(&priv->mutex);
-	if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
-		if (priv->secfeed) {
-			if (priv->secfeed->is_filtering) {
-				dprintk("%s: stop secfeed\n", __func__);
-				priv->secfeed->stop_filtering(priv->secfeed);
-			}
-
-			if (priv->secfilter) {
-				dprintk("%s: release secfilter\n", __func__);
-				priv->secfeed->release_filter(priv->secfeed,
-							      priv->secfilter);
-				priv->secfilter=NULL;
-			}
-
-			for (i=0; i<priv->multi_num; i++) {
-				if (priv->multi_secfilter[i]) {
-					dprintk("%s: release multi_filter[%d]\n",
-						__func__, i);
-					priv->secfeed->release_filter(priv->secfeed,
-								      priv->multi_secfilter[i]);
-					priv->multi_secfilter[i] = NULL;
-				}
-			}
-
-			priv->demux->release_section_feed(priv->demux, priv->secfeed);
-			priv->secfeed = NULL;
-		} else
-			printk("%s: no feed to stop\n", dev->name);
-	} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
-		if (priv->tsfeed) {
-			if (priv->tsfeed->is_filtering) {
-				dprintk("%s: stop tsfeed\n", __func__);
-				priv->tsfeed->stop_filtering(priv->tsfeed);
-			}
-			priv->demux->release_ts_feed(priv->demux, priv->tsfeed);
-			priv->tsfeed = NULL;
-		}
-		else
-			printk("%s: no ts feed to stop\n", dev->name);
-	} else
-		ret = -EINVAL;
-	mutex_unlock(&priv->mutex);
-	return ret;
-}
-
-
-static int dvb_set_mc_filter(struct net_device *dev, unsigned char *addr)
-{
-	struct dvb_net_priv *priv = netdev_priv(dev);
-
-	if (priv->multi_num == DVB_NET_MULTICAST_MAX)
-		return -ENOMEM;
-
-	memcpy(priv->multi_macs[priv->multi_num], addr, ETH_ALEN);
-
-	priv->multi_num++;
-	return 0;
-}
-
-
-static void wq_set_multicast_list (struct work_struct *work)
-{
-	struct dvb_net_priv *priv =
-		container_of(work, struct dvb_net_priv, set_multicast_list_wq);
-	struct net_device *dev = priv->net;
-
-	dvb_net_feed_stop(dev);
-	priv->rx_mode = RX_MODE_UNI;
-	netif_addr_lock_bh(dev);
-
-	if (dev->flags & IFF_PROMISC) {
-		dprintk("%s: promiscuous mode\n", dev->name);
-		priv->rx_mode = RX_MODE_PROMISC;
-	} else if ((dev->flags & IFF_ALLMULTI)) {
-		dprintk("%s: allmulti mode\n", dev->name);
-		priv->rx_mode = RX_MODE_ALL_MULTI;
-	} else if (!netdev_mc_empty(dev)) {
-		struct netdev_hw_addr *ha;
-
-		dprintk("%s: set_mc_list, %d entries\n",
-			dev->name, netdev_mc_count(dev));
-
-		priv->rx_mode = RX_MODE_MULTI;
-		priv->multi_num = 0;
-
-		netdev_for_each_mc_addr(ha, dev)
-			dvb_set_mc_filter(dev, ha->addr);
-	}
-
-	netif_addr_unlock_bh(dev);
-	dvb_net_feed_start(dev);
-}
-
-
-static void dvb_net_set_multicast_list (struct net_device *dev)
-{
-	struct dvb_net_priv *priv = netdev_priv(dev);
-	schedule_work(&priv->set_multicast_list_wq);
-}
-
-
-static void wq_restart_net_feed (struct work_struct *work)
-{
-	struct dvb_net_priv *priv =
-		container_of(work, struct dvb_net_priv, restart_net_feed_wq);
-	struct net_device *dev = priv->net;
-
-	if (netif_running(dev)) {
-		dvb_net_feed_stop(dev);
-		dvb_net_feed_start(dev);
-	}
-}
-
-
-static int dvb_net_set_mac (struct net_device *dev, void *p)
-{
-	struct dvb_net_priv *priv = netdev_priv(dev);
-	struct sockaddr *addr=p;
-
-	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-
-	if (netif_running(dev))
-		schedule_work(&priv->restart_net_feed_wq);
-
-	return 0;
-}
-
-
-static int dvb_net_open(struct net_device *dev)
-{
-	struct dvb_net_priv *priv = netdev_priv(dev);
-
-	priv->in_use++;
-	dvb_net_feed_start(dev);
-	return 0;
-}
-
-
-static int dvb_net_stop(struct net_device *dev)
-{
-	struct dvb_net_priv *priv = netdev_priv(dev);
-
-	priv->in_use--;
-	return dvb_net_feed_stop(dev);
-}
-
-static const struct header_ops dvb_header_ops = {
-	.create		= eth_header,
-	.parse		= eth_header_parse,
-	.rebuild	= eth_rebuild_header,
-};
-
-
-static const struct net_device_ops dvb_netdev_ops = {
-	.ndo_open		= dvb_net_open,
-	.ndo_stop		= dvb_net_stop,
-	.ndo_start_xmit		= dvb_net_tx,
-	.ndo_set_rx_mode	= dvb_net_set_multicast_list,
-	.ndo_set_mac_address    = dvb_net_set_mac,
-	.ndo_change_mtu		= eth_change_mtu,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static void dvb_net_setup(struct net_device *dev)
-{
-	ether_setup(dev);
-
-	dev->header_ops		= &dvb_header_ops;
-	dev->netdev_ops		= &dvb_netdev_ops;
-	dev->mtu		= 4096;
-
-	dev->flags |= IFF_NOARP;
-}
-
-static int get_if(struct dvb_net *dvbnet)
-{
-	int i;
-
-	for (i=0; i<DVB_NET_DEVICES_MAX; i++)
-		if (!dvbnet->state[i])
-			break;
-
-	if (i == DVB_NET_DEVICES_MAX)
-		return -1;
-
-	dvbnet->state[i]=1;
-	return i;
-}
-
-static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
-{
-	struct net_device *net;
-	struct dvb_net_priv *priv;
-	int result;
-	int if_num;
-
-	if (feedtype != DVB_NET_FEEDTYPE_MPE && feedtype != DVB_NET_FEEDTYPE_ULE)
-		return -EINVAL;
-	if ((if_num = get_if(dvbnet)) < 0)
-		return -EINVAL;
-
-	net = alloc_netdev(sizeof(struct dvb_net_priv), "dvb", dvb_net_setup);
-	if (!net)
-		return -ENOMEM;
-
-	if (dvbnet->dvbdev->id)
-		snprintf(net->name, IFNAMSIZ, "dvb%d%u%d",
-			 dvbnet->dvbdev->adapter->num, dvbnet->dvbdev->id, if_num);
-	else
-		/* compatibility fix to keep dvb0_0 format */
-		snprintf(net->name, IFNAMSIZ, "dvb%d_%d",
-			 dvbnet->dvbdev->adapter->num, if_num);
-
-	net->addr_len = 6;
-	memcpy(net->dev_addr, dvbnet->dvbdev->adapter->proposed_mac, 6);
-
-	dvbnet->device[if_num] = net;
-
-	priv = netdev_priv(net);
-	priv->net = net;
-	priv->demux = dvbnet->demux;
-	priv->pid = pid;
-	priv->rx_mode = RX_MODE_UNI;
-	priv->need_pusi = 1;
-	priv->tscc = 0;
-	priv->feedtype = feedtype;
-	reset_ule(priv);
-
-	INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list);
-	INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed);
-	mutex_init(&priv->mutex);
-
-	net->base_addr = pid;
-
-	if ((result = register_netdev(net)) < 0) {
-		dvbnet->device[if_num] = NULL;
-		free_netdev(net);
-		return result;
-	}
-	printk("dvb_net: created network interface %s\n", net->name);
-
-	return if_num;
-}
-
-static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)
-{
-	struct net_device *net = dvbnet->device[num];
-	struct dvb_net_priv *priv;
-
-	if (!dvbnet->state[num])
-		return -EINVAL;
-	priv = netdev_priv(net);
-	if (priv->in_use)
-		return -EBUSY;
-
-	dvb_net_stop(net);
-	flush_work_sync(&priv->set_multicast_list_wq);
-	flush_work_sync(&priv->restart_net_feed_wq);
-	printk("dvb_net: removed network interface %s\n", net->name);
-	unregister_netdev(net);
-	dvbnet->state[num]=0;
-	dvbnet->device[num] = NULL;
-	free_netdev(net);
-
-	return 0;
-}
-
-static int dvb_net_do_ioctl(struct file *file,
-		  unsigned int cmd, void *parg)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dvb_net *dvbnet = dvbdev->priv;
-
-	if (((file->f_flags&O_ACCMODE)==O_RDONLY))
-		return -EPERM;
-
-	switch (cmd) {
-	case NET_ADD_IF:
-	{
-		struct dvb_net_if *dvbnetif = parg;
-		int result;
-
-		if (!capable(CAP_SYS_ADMIN))
-			return -EPERM;
-
-		if (!try_module_get(dvbdev->adapter->module))
-			return -EPERM;
-
-		result=dvb_net_add_if(dvbnet, dvbnetif->pid, dvbnetif->feedtype);
-		if (result<0) {
-			module_put(dvbdev->adapter->module);
-			return result;
-		}
-		dvbnetif->if_num=result;
-		break;
-	}
-	case NET_GET_IF:
-	{
-		struct net_device *netdev;
-		struct dvb_net_priv *priv_data;
-		struct dvb_net_if *dvbnetif = parg;
-
-		if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
-		    !dvbnet->state[dvbnetif->if_num])
-			return -EINVAL;
-
-		netdev = dvbnet->device[dvbnetif->if_num];
-
-		priv_data = netdev_priv(netdev);
-		dvbnetif->pid=priv_data->pid;
-		dvbnetif->feedtype=priv_data->feedtype;
-		break;
-	}
-	case NET_REMOVE_IF:
-	{
-		int ret;
-
-		if (!capable(CAP_SYS_ADMIN))
-			return -EPERM;
-		if ((unsigned long) parg >= DVB_NET_DEVICES_MAX)
-			return -EINVAL;
-		ret = dvb_net_remove_if(dvbnet, (unsigned long) parg);
-		if (!ret)
-			module_put(dvbdev->adapter->module);
-		return ret;
-	}
-
-	/* binary compatibility cruft */
-	case __NET_ADD_IF_OLD:
-	{
-		struct __dvb_net_if_old *dvbnetif = parg;
-		int result;
-
-		if (!capable(CAP_SYS_ADMIN))
-			return -EPERM;
-
-		if (!try_module_get(dvbdev->adapter->module))
-			return -EPERM;
-
-		result=dvb_net_add_if(dvbnet, dvbnetif->pid, DVB_NET_FEEDTYPE_MPE);
-		if (result<0) {
-			module_put(dvbdev->adapter->module);
-			return result;
-		}
-		dvbnetif->if_num=result;
-		break;
-	}
-	case __NET_GET_IF_OLD:
-	{
-		struct net_device *netdev;
-		struct dvb_net_priv *priv_data;
-		struct __dvb_net_if_old *dvbnetif = parg;
-
-		if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
-		    !dvbnet->state[dvbnetif->if_num])
-			return -EINVAL;
-
-		netdev = dvbnet->device[dvbnetif->if_num];
-
-		priv_data = netdev_priv(netdev);
-		dvbnetif->pid=priv_data->pid;
-		break;
-	}
-	default:
-		return -ENOTTY;
-	}
-	return 0;
-}
-
-static long dvb_net_ioctl(struct file *file,
-	      unsigned int cmd, unsigned long arg)
-{
-	return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl);
-}
-
-static int dvb_net_close(struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct dvb_net *dvbnet = dvbdev->priv;
-
-	dvb_generic_release(inode, file);
-
-	if(dvbdev->users == 1 && dvbnet->exit == 1) {
-		fops_put(file->f_op);
-		file->f_op = NULL;
-		wake_up(&dvbdev->wait_queue);
-	}
-	return 0;
-}
-
-
-static const struct file_operations dvb_net_fops = {
-	.owner = THIS_MODULE,
-	.unlocked_ioctl = dvb_net_ioctl,
-	.open =	dvb_generic_open,
-	.release = dvb_net_close,
-	.llseek = noop_llseek,
-};
-
-static struct dvb_device dvbdev_net = {
-	.priv = NULL,
-	.users = 1,
-	.writers = 1,
-	.fops = &dvb_net_fops,
-};
-
-
-void dvb_net_release (struct dvb_net *dvbnet)
-{
-	int i;
-
-	dvbnet->exit = 1;
-	if (dvbnet->dvbdev->users < 1)
-		wait_event(dvbnet->dvbdev->wait_queue,
-				dvbnet->dvbdev->users==1);
-
-	dvb_unregister_device(dvbnet->dvbdev);
-
-	for (i=0; i<DVB_NET_DEVICES_MAX; i++) {
-		if (!dvbnet->state[i])
-			continue;
-		dvb_net_remove_if(dvbnet, i);
-	}
-}
-EXPORT_SYMBOL(dvb_net_release);
-
-
-int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
-		  struct dmx_demux *dmx)
-{
-	int i;
-
-	dvbnet->demux = dmx;
-
-	for (i=0; i<DVB_NET_DEVICES_MAX; i++)
-		dvbnet->state[i] = 0;
-
-	return dvb_register_device(adap, &dvbnet->dvbdev, &dvbdev_net,
-			     dvbnet, DVB_DEVICE_NET);
-}
-EXPORT_SYMBOL(dvb_net_init);
diff --git a/drivers/media/dvb/dvb-core/dvb_net.h b/drivers/media/dvb/dvb-core/dvb_net.h
deleted file mode 100644
index 1e53acd..0000000
--- a/drivers/media/dvb/dvb-core/dvb_net.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * dvb_net.h
- *
- * Copyright (C) 2001 Ralph Metzler for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- */
-
-#ifndef _DVB_NET_H_
-#define _DVB_NET_H_
-
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include "dvbdev.h"
-
-#define DVB_NET_DEVICES_MAX 10
-
-#ifdef CONFIG_DVB_NET
-
-struct dvb_net {
-	struct dvb_device *dvbdev;
-	struct net_device *device[DVB_NET_DEVICES_MAX];
-	int state[DVB_NET_DEVICES_MAX];
-	unsigned int exit:1;
-	struct dmx_demux *demux;
-};
-
-void dvb_net_release(struct dvb_net *);
-int  dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *);
-
-#else
-
-struct dvb_net {
-	struct dvb_device *dvbdev;
-};
-
-static inline void dvb_net_release(struct dvb_net *dvbnet)
-{
-}
-
-static inline int dvb_net_init(struct dvb_adapter *adap,
-			       struct dvb_net *dvbnet, struct dmx_demux *dmx)
-{
-	return 0;
-}
-
-#endif /* ifdef CONFIG_DVB_NET */
-
-#endif
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
deleted file mode 100644
index a5712cd..0000000
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- *
- * dvb_ringbuffer.c: ring buffer implementation for the dvb driver
- *
- * Copyright (C) 2003 Oliver Endriss
- * Copyright (C) 2004 Andrew de Quincey
- *
- * based on code originally found in av7110.c & dvb_ci.c:
- * Copyright (C) 1999-2003 Ralph  Metzler
- *                       & Marcus Metzler for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <asm/uaccess.h>
-
-#include "dvb_ringbuffer.h"
-
-#define PKT_READY 0
-#define PKT_DISPOSED 1
-
-
-void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
-{
-	rbuf->pread=rbuf->pwrite=0;
-	rbuf->data=data;
-	rbuf->size=len;
-	rbuf->error=0;
-
-	init_waitqueue_head(&rbuf->queue);
-
-	spin_lock_init(&(rbuf->lock));
-}
-
-
-
-int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
-{
-	return (rbuf->pread==rbuf->pwrite);
-}
-
-
-
-ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf)
-{
-	ssize_t free;
-
-	free = rbuf->pread - rbuf->pwrite;
-	if (free <= 0)
-		free += rbuf->size;
-	return free-1;
-}
-
-
-
-ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
-{
-	ssize_t avail;
-
-	avail = rbuf->pwrite - rbuf->pread;
-	if (avail < 0)
-		avail += rbuf->size;
-	return avail;
-}
-
-
-
-void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
-{
-	rbuf->pread = rbuf->pwrite;
-	rbuf->error = 0;
-}
-EXPORT_SYMBOL(dvb_ringbuffer_flush);
-
-void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf)
-{
-	rbuf->pread = rbuf->pwrite = 0;
-	rbuf->error = 0;
-}
-
-void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&rbuf->lock, flags);
-	dvb_ringbuffer_flush(rbuf);
-	spin_unlock_irqrestore(&rbuf->lock, flags);
-
-	wake_up(&rbuf->queue);
-}
-
-ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, size_t len)
-{
-	size_t todo = len;
-	size_t split;
-
-	split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
-	if (split > 0) {
-		if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
-			return -EFAULT;
-		buf += split;
-		todo -= split;
-		rbuf->pread = 0;
-	}
-	if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
-		return -EFAULT;
-
-	rbuf->pread = (rbuf->pread + todo) % rbuf->size;
-
-	return len;
-}
-
-void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
-{
-	size_t todo = len;
-	size_t split;
-
-	split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
-	if (split > 0) {
-		memcpy(buf, rbuf->data+rbuf->pread, split);
-		buf += split;
-		todo -= split;
-		rbuf->pread = 0;
-	}
-	memcpy(buf, rbuf->data+rbuf->pread, todo);
-
-	rbuf->pread = (rbuf->pread + todo) % rbuf->size;
-}
-
-
-ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len)
-{
-	size_t todo = len;
-	size_t split;
-
-	split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
-
-	if (split > 0) {
-		memcpy(rbuf->data+rbuf->pwrite, buf, split);
-		buf += split;
-		todo -= split;
-		rbuf->pwrite = 0;
-	}
-	memcpy(rbuf->data+rbuf->pwrite, buf, todo);
-	rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
-
-	return len;
-}
-
-ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len)
-{
-	int status;
-	ssize_t oldpwrite = rbuf->pwrite;
-
-	DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8);
-	DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff);
-	DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY);
-	status = dvb_ringbuffer_write(rbuf, buf, len);
-
-	if (status < 0) rbuf->pwrite = oldpwrite;
-	return status;
-}
-
-ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
-				int offset, u8 __user *buf, size_t len)
-{
-	size_t todo;
-	size_t split;
-	size_t pktlen;
-
-	pktlen = rbuf->data[idx] << 8;
-	pktlen |= rbuf->data[(idx + 1) % rbuf->size];
-	if (offset > pktlen) return -EINVAL;
-	if ((offset + len) > pktlen) len = pktlen - offset;
-
-	idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
-	todo = len;
-	split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
-	if (split > 0) {
-		if (copy_to_user(buf, rbuf->data+idx, split))
-			return -EFAULT;
-		buf += split;
-		todo -= split;
-		idx = 0;
-	}
-	if (copy_to_user(buf, rbuf->data+idx, todo))
-		return -EFAULT;
-
-	return len;
-}
-
-ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
-				int offset, u8* buf, size_t len)
-{
-	size_t todo;
-	size_t split;
-	size_t pktlen;
-
-	pktlen = rbuf->data[idx] << 8;
-	pktlen |= rbuf->data[(idx + 1) % rbuf->size];
-	if (offset > pktlen) return -EINVAL;
-	if ((offset + len) > pktlen) len = pktlen - offset;
-
-	idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
-	todo = len;
-	split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
-	if (split > 0) {
-		memcpy(buf, rbuf->data+idx, split);
-		buf += split;
-		todo -= split;
-		idx = 0;
-	}
-	memcpy(buf, rbuf->data+idx, todo);
-	return len;
-}
-
-void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
-{
-	size_t pktlen;
-
-	rbuf->data[(idx + 2) % rbuf->size] = PKT_DISPOSED;
-
-	// clean up disposed packets
-	while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) {
-		if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) {
-			pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8;
-			pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1);
-			DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE);
-		} else {
-			// first packet is not disposed, so we stop cleaning now
-			break;
-		}
-	}
-}
-
-ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen)
-{
-	int consumed;
-	int curpktlen;
-	int curpktstatus;
-
-	if (idx == -1) {
-	       idx = rbuf->pread;
-	} else {
-		curpktlen = rbuf->data[idx] << 8;
-		curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
-		idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
-	}
-
-	consumed = (idx - rbuf->pread) % rbuf->size;
-
-	while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) {
-
-		curpktlen = rbuf->data[idx] << 8;
-		curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
-		curpktstatus = rbuf->data[(idx + 2) % rbuf->size];
-
-		if (curpktstatus == PKT_READY) {
-			*pktlen = curpktlen;
-			return idx;
-		}
-
-		consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE;
-		idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
-	}
-
-	// no packets available
-	return -1;
-}
-
-
-
-EXPORT_SYMBOL(dvb_ringbuffer_init);
-EXPORT_SYMBOL(dvb_ringbuffer_empty);
-EXPORT_SYMBOL(dvb_ringbuffer_free);
-EXPORT_SYMBOL(dvb_ringbuffer_avail);
-EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
-EXPORT_SYMBOL(dvb_ringbuffer_read_user);
-EXPORT_SYMBOL(dvb_ringbuffer_read);
-EXPORT_SYMBOL(dvb_ringbuffer_write);
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
deleted file mode 100644
index 41f04da..0000000
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- *
- * dvb_ringbuffer.h: ring buffer implementation for the dvb driver
- *
- * Copyright (C) 2003 Oliver Endriss
- * Copyright (C) 2004 Andrew de Quincey
- *
- * based on code originally found in av7110.c & dvb_ci.c:
- * Copyright (C) 1999-2003 Ralph Metzler & Marcus Metzler
- *                         for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _DVB_RINGBUFFER_H_
-#define _DVB_RINGBUFFER_H_
-
-#include <linux/spinlock.h>
-#include <linux/wait.h>
-
-struct dvb_ringbuffer {
-	u8               *data;
-	ssize_t           size;
-	ssize_t           pread;
-	ssize_t           pwrite;
-	int               error;
-
-	wait_queue_head_t queue;
-	spinlock_t        lock;
-};
-
-#define DVB_RINGBUFFER_PKTHDRSIZE 3
-
-
-/*
-** Notes:
-** ------
-** (1) For performance reasons read and write routines don't check buffer sizes
-**     and/or number of bytes free/available. This has to be done before these
-**     routines are called. For example:
-**
-**     *** write <buflen> bytes ***
-**     free = dvb_ringbuffer_free(rbuf);
-**     if (free >= buflen)
-**         count = dvb_ringbuffer_write(rbuf, buffer, buflen);
-**     else
-**         ...
-**
-**     *** read min. 1000, max. <bufsize> bytes ***
-**     avail = dvb_ringbuffer_avail(rbuf);
-**     if (avail >= 1000)
-**         count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize));
-**     else
-**         ...
-**
-** (2) If there is exactly one reader and one writer, there is no need
-**     to lock read or write operations.
-**     Two or more readers must be locked against each other.
-**     Flushing the buffer counts as a read operation.
-**     Resetting the buffer counts as a read and write operation.
-**     Two or more writers must be locked against each other.
-*/
-
-/* initialize ring buffer, lock and queue */
-extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len);
-
-/* test whether buffer is empty */
-extern int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf);
-
-/* return the number of free bytes in the buffer */
-extern ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf);
-
-/* return the number of bytes waiting in the buffer */
-extern ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf);
-
-
-/*
-** Reset the read and write pointers to zero and flush the buffer
-** This counts as a read and write operation
-*/
-extern void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf);
-
-
-/* read routines & macros */
-/* ---------------------- */
-/* flush buffer */
-extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf);
-
-/* flush buffer protected by spinlock and wake-up waiting task(s) */
-extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
-
-/* peek at byte <offs> in the buffer */
-#define DVB_RINGBUFFER_PEEK(rbuf,offs)	\
-			(rbuf)->data[((rbuf)->pread+(offs))%(rbuf)->size]
-
-/* advance read ptr by <num> bytes */
-#define DVB_RINGBUFFER_SKIP(rbuf,num)	\
-			(rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size
-
-/*
-** read <len> bytes from ring buffer into <buf>
-** <usermem> specifies whether <buf> resides in user space
-** returns number of bytes transferred or -EFAULT
-*/
-extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf,
-				   u8 __user *buf, size_t len);
-extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf,
-				   u8 *buf, size_t len);
-
-
-/* write routines & macros */
-/* ----------------------- */
-/* write single byte to ring buffer */
-#define DVB_RINGBUFFER_WRITE_BYTE(rbuf,byte)	\
-			{ (rbuf)->data[(rbuf)->pwrite]=(byte); \
-			(rbuf)->pwrite=((rbuf)->pwrite+1)%(rbuf)->size; }
-/*
-** write <len> bytes to ring buffer
-** <usermem> specifies whether <buf> resides in user space
-** returns number of bytes transferred or -EFAULT
-*/
-extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
-				    size_t len);
-
-
-/**
- * Write a packet into the ringbuffer.
- *
- * <rbuf> Ringbuffer to write to.
- * <buf> Buffer to write.
- * <len> Length of buffer (currently limited to 65535 bytes max).
- * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
- */
-extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
-					size_t len);
-
-/**
- * Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this
- * does NOT update the read pointer in the ringbuffer. You must use
- * dvb_ringbuffer_pkt_dispose() to mark a packet as no longer required.
- *
- * <rbuf> Ringbuffer concerned.
- * <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
- * <offset> Offset into packet to read from.
- * <buf> Destination buffer for data.
- * <len> Size of destination buffer.
- * <usermem> Set to 1 if <buf> is in userspace.
- * returns Number of bytes read, or -EFAULT.
- */
-extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
-				       int offset, u8 __user *buf, size_t len);
-extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
-				       int offset, u8 *buf, size_t len);
-
-/**
- * Dispose of a packet in the ring buffer.
- *
- * <rbuf> Ring buffer concerned.
- * <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
- */
-extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx);
-
-/**
- * Get the index of the next packet in a ringbuffer.
- *
- * <rbuf> Ringbuffer concerned.
- * <idx> Previous packet index, or -1 to return the first packet index.
- * <pktlen> On success, will be updated to contain the length of the packet in bytes.
- * returns Packet index (if >=0), or -1 if no packets available.
- */
-extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen);
-
-
-#endif /* _DVB_RINGBUFFER_H_ */
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
deleted file mode 100644
index 39eab73..0000000
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * dvbdev.c
- *
- * Copyright (C) 2000 Ralph  Metzler <ralph@convergence.de>
- *                  & Marcus Metzler <marcus@convergence.de>
- *                    for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/mutex.h>
-#include "dvbdev.h"
-
-static DEFINE_MUTEX(dvbdev_mutex);
-static int dvbdev_debug;
-
-module_param(dvbdev_debug, int, 0644);
-MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off).");
-
-#define dprintk if (dvbdev_debug) printk
-
-static LIST_HEAD(dvb_adapter_list);
-static DEFINE_MUTEX(dvbdev_register_lock);
-
-static const char * const dnames[] = {
-	"video", "audio", "sec", "frontend", "demux", "dvr", "ca",
-	"net", "osd"
-};
-
-#ifdef CONFIG_DVB_DYNAMIC_MINORS
-#define MAX_DVB_MINORS		256
-#define DVB_MAX_IDS		MAX_DVB_MINORS
-#else
-#define DVB_MAX_IDS		4
-#define nums2minor(num,type,id)	((num << 6) | (id << 4) | type)
-#define MAX_DVB_MINORS		(DVB_MAX_ADAPTERS*64)
-#endif
-
-static struct class *dvb_class;
-
-static struct dvb_device *dvb_minors[MAX_DVB_MINORS];
-static DECLARE_RWSEM(minor_rwsem);
-
-static int dvb_device_open(struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev;
-
-	mutex_lock(&dvbdev_mutex);
-	down_read(&minor_rwsem);
-	dvbdev = dvb_minors[iminor(inode)];
-
-	if (dvbdev && dvbdev->fops) {
-		int err = 0;
-		const struct file_operations *old_fops;
-
-		file->private_data = dvbdev;
-		old_fops = file->f_op;
-		file->f_op = fops_get(dvbdev->fops);
-		if (file->f_op == NULL) {
-			file->f_op = old_fops;
-			goto fail;
-		}
-		if(file->f_op->open)
-			err = file->f_op->open(inode,file);
-		if (err) {
-			fops_put(file->f_op);
-			file->f_op = fops_get(old_fops);
-		}
-		fops_put(old_fops);
-		up_read(&minor_rwsem);
-		mutex_unlock(&dvbdev_mutex);
-		return err;
-	}
-fail:
-	up_read(&minor_rwsem);
-	mutex_unlock(&dvbdev_mutex);
-	return -ENODEV;
-}
-
-
-static const struct file_operations dvb_device_fops =
-{
-	.owner =	THIS_MODULE,
-	.open =		dvb_device_open,
-	.llseek =	noop_llseek,
-};
-
-static struct cdev dvb_device_cdev;
-
-int dvb_generic_open(struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev = file->private_data;
-
-	if (!dvbdev)
-		return -ENODEV;
-
-	if (!dvbdev->users)
-		return -EBUSY;
-
-	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
-		if (!dvbdev->readers)
-			return -EBUSY;
-		dvbdev->readers--;
-	} else {
-		if (!dvbdev->writers)
-			return -EBUSY;
-		dvbdev->writers--;
-	}
-
-	dvbdev->users--;
-	return 0;
-}
-EXPORT_SYMBOL(dvb_generic_open);
-
-
-int dvb_generic_release(struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev = file->private_data;
-
-	if (!dvbdev)
-		return -ENODEV;
-
-	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
-		dvbdev->readers++;
-	} else {
-		dvbdev->writers++;
-	}
-
-	dvbdev->users++;
-	return 0;
-}
-EXPORT_SYMBOL(dvb_generic_release);
-
-
-long dvb_generic_ioctl(struct file *file,
-		       unsigned int cmd, unsigned long arg)
-{
-	struct dvb_device *dvbdev = file->private_data;
-
-	if (!dvbdev)
-		return -ENODEV;
-
-	if (!dvbdev->kernel_ioctl)
-		return -EINVAL;
-
-	return dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl);
-}
-EXPORT_SYMBOL(dvb_generic_ioctl);
-
-
-static int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
-{
-	u32 id = 0;
-
-	while (id < DVB_MAX_IDS) {
-		struct dvb_device *dev;
-		list_for_each_entry(dev, &adap->device_list, list_head)
-			if (dev->type == type && dev->id == id)
-				goto skip;
-		return id;
-skip:
-		id++;
-	}
-	return -ENFILE;
-}
-
-
-int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
-			const struct dvb_device *template, void *priv, int type)
-{
-	struct dvb_device *dvbdev;
-	struct file_operations *dvbdevfops;
-	struct device *clsdev;
-	int minor;
-	int id;
-
-	mutex_lock(&dvbdev_register_lock);
-
-	if ((id = dvbdev_get_free_id (adap, type)) < 0){
-		mutex_unlock(&dvbdev_register_lock);
-		*pdvbdev = NULL;
-		printk(KERN_ERR "%s: couldn't find free device id\n", __func__);
-		return -ENFILE;
-	}
-
-	*pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);
-
-	if (!dvbdev){
-		mutex_unlock(&dvbdev_register_lock);
-		return -ENOMEM;
-	}
-
-	dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
-
-	if (!dvbdevfops){
-		kfree (dvbdev);
-		mutex_unlock(&dvbdev_register_lock);
-		return -ENOMEM;
-	}
-
-	memcpy(dvbdev, template, sizeof(struct dvb_device));
-	dvbdev->type = type;
-	dvbdev->id = id;
-	dvbdev->adapter = adap;
-	dvbdev->priv = priv;
-	dvbdev->fops = dvbdevfops;
-	init_waitqueue_head (&dvbdev->wait_queue);
-
-	memcpy(dvbdevfops, template->fops, sizeof(struct file_operations));
-	dvbdevfops->owner = adap->module;
-
-	list_add_tail (&dvbdev->list_head, &adap->device_list);
-
-	down_write(&minor_rwsem);
-#ifdef CONFIG_DVB_DYNAMIC_MINORS
-	for (minor = 0; minor < MAX_DVB_MINORS; minor++)
-		if (dvb_minors[minor] == NULL)
-			break;
-
-	if (minor == MAX_DVB_MINORS) {
-		kfree(dvbdevfops);
-		kfree(dvbdev);
-		up_write(&minor_rwsem);
-		mutex_unlock(&dvbdev_register_lock);
-		return -EINVAL;
-	}
-#else
-	minor = nums2minor(adap->num, type, id);
-#endif
-
-	dvbdev->minor = minor;
-	dvb_minors[minor] = dvbdev;
-	up_write(&minor_rwsem);
-
-	mutex_unlock(&dvbdev_register_lock);
-
-	clsdev = device_create(dvb_class, adap->device,
-			       MKDEV(DVB_MAJOR, minor),
-			       dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
-	if (IS_ERR(clsdev)) {
-		printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
-		       __func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
-		return PTR_ERR(clsdev);
-	}
-
-	dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
-		adap->num, dnames[type], id, minor, minor);
-
-	return 0;
-}
-EXPORT_SYMBOL(dvb_register_device);
-
-
-void dvb_unregister_device(struct dvb_device *dvbdev)
-{
-	if (!dvbdev)
-		return;
-
-	down_write(&minor_rwsem);
-	dvb_minors[dvbdev->minor] = NULL;
-	up_write(&minor_rwsem);
-
-	device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
-
-	list_del (&dvbdev->list_head);
-	kfree (dvbdev->fops);
-	kfree (dvbdev);
-}
-EXPORT_SYMBOL(dvb_unregister_device);
-
-static int dvbdev_check_free_adapter_num(int num)
-{
-	struct list_head *entry;
-	list_for_each(entry, &dvb_adapter_list) {
-		struct dvb_adapter *adap;
-		adap = list_entry(entry, struct dvb_adapter, list_head);
-		if (adap->num == num)
-			return 0;
-	}
-	return 1;
-}
-
-static int dvbdev_get_free_adapter_num (void)
-{
-	int num = 0;
-
-	while (num < DVB_MAX_ADAPTERS) {
-		if (dvbdev_check_free_adapter_num(num))
-			return num;
-		num++;
-	}
-
-	return -ENFILE;
-}
-
-
-int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
-			 struct module *module, struct device *device,
-			 short *adapter_nums)
-{
-	int i, num;
-
-	mutex_lock(&dvbdev_register_lock);
-
-	for (i = 0; i < DVB_MAX_ADAPTERS; ++i) {
-		num = adapter_nums[i];
-		if (num >= 0  &&  num < DVB_MAX_ADAPTERS) {
-		/* use the one the driver asked for */
-			if (dvbdev_check_free_adapter_num(num))
-				break;
-		} else {
-			num = dvbdev_get_free_adapter_num();
-			break;
-		}
-		num = -1;
-	}
-
-	if (num < 0) {
-		mutex_unlock(&dvbdev_register_lock);
-		return -ENFILE;
-	}
-
-	memset (adap, 0, sizeof(struct dvb_adapter));
-	INIT_LIST_HEAD (&adap->device_list);
-
-	printk(KERN_INFO "DVB: registering new adapter (%s)\n", name);
-
-	adap->num = num;
-	adap->name = name;
-	adap->module = module;
-	adap->device = device;
-	adap->mfe_shared = 0;
-	adap->mfe_dvbdev = NULL;
-	mutex_init (&adap->mfe_lock);
-
-	list_add_tail (&adap->list_head, &dvb_adapter_list);
-
-	mutex_unlock(&dvbdev_register_lock);
-
-	return num;
-}
-EXPORT_SYMBOL(dvb_register_adapter);
-
-
-int dvb_unregister_adapter(struct dvb_adapter *adap)
-{
-	mutex_lock(&dvbdev_register_lock);
-	list_del (&adap->list_head);
-	mutex_unlock(&dvbdev_register_lock);
-	return 0;
-}
-EXPORT_SYMBOL(dvb_unregister_adapter);
-
-/* if the miracle happens and "generic_usercopy()" is included into
-   the kernel, then this can vanish. please don't make the mistake and
-   define this as video_usercopy(). this will introduce a dependecy
-   to the v4l "videodev.o" module, which is unnecessary for some
-   cards (ie. the budget dvb-cards don't need the v4l module...) */
-int dvb_usercopy(struct file *file,
-		     unsigned int cmd, unsigned long arg,
-		     int (*func)(struct file *file,
-		     unsigned int cmd, void *arg))
-{
-	char    sbuf[128];
-	void    *mbuf = NULL;
-	void    *parg = NULL;
-	int     err  = -EINVAL;
-
-	/*  Copy arguments into temp kernel buffer  */
-	switch (_IOC_DIR(cmd)) {
-	case _IOC_NONE:
-		/*
-		 * For this command, the pointer is actually an integer
-		 * argument.
-		 */
-		parg = (void *) arg;
-		break;
-	case _IOC_READ: /* some v4l ioctls are marked wrong ... */
-	case _IOC_WRITE:
-	case (_IOC_WRITE | _IOC_READ):
-		if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
-			parg = sbuf;
-		} else {
-			/* too big to allocate from stack */
-			mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
-			if (NULL == mbuf)
-				return -ENOMEM;
-			parg = mbuf;
-		}
-
-		err = -EFAULT;
-		if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
-			goto out;
-		break;
-	}
-
-	/* call driver */
-	mutex_lock(&dvbdev_mutex);
-	if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
-		err = -EINVAL;
-	mutex_unlock(&dvbdev_mutex);
-
-	if (err < 0)
-		goto out;
-
-	/*  Copy results into user buffer  */
-	switch (_IOC_DIR(cmd))
-	{
-	case _IOC_READ:
-	case (_IOC_WRITE | _IOC_READ):
-		if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
-			err = -EFAULT;
-		break;
-	}
-
-out:
-	kfree(mbuf);
-	return err;
-}
-
-static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
-	struct dvb_device *dvbdev = dev_get_drvdata(dev);
-
-	add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num);
-	add_uevent_var(env, "DVB_DEVICE_TYPE=%s", dnames[dvbdev->type]);
-	add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id);
-	return 0;
-}
-
-static char *dvb_devnode(struct device *dev, umode_t *mode)
-{
-	struct dvb_device *dvbdev = dev_get_drvdata(dev);
-
-	return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d",
-		dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id);
-}
-
-
-static int __init init_dvbdev(void)
-{
-	int retval;
-	dev_t dev = MKDEV(DVB_MAJOR, 0);
-
-	if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
-		printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR);
-		return retval;
-	}
-
-	cdev_init(&dvb_device_cdev, &dvb_device_fops);
-	if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
-		printk(KERN_ERR "dvb-core: unable register character device\n");
-		goto error;
-	}
-
-	dvb_class = class_create(THIS_MODULE, "dvb");
-	if (IS_ERR(dvb_class)) {
-		retval = PTR_ERR(dvb_class);
-		goto error;
-	}
-	dvb_class->dev_uevent = dvb_uevent;
-	dvb_class->devnode = dvb_devnode;
-	return 0;
-
-error:
-	cdev_del(&dvb_device_cdev);
-	unregister_chrdev_region(dev, MAX_DVB_MINORS);
-	return retval;
-}
-
-
-static void __exit exit_dvbdev(void)
-{
-	class_destroy(dvb_class);
-	cdev_del(&dvb_device_cdev);
-	unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
-}
-
-subsys_initcall(init_dvbdev);
-module_exit(exit_dvbdev);
-
-MODULE_DESCRIPTION("DVB Core Driver");
-MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
deleted file mode 100644
index fcc6ae9..0000000
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * dvbdev.h
- *
- * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
- *                    for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Lesser Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- */
-
-#ifndef _DVBDEV_H_
-#define _DVBDEV_H_
-
-#include <linux/types.h>
-#include <linux/poll.h>
-#include <linux/fs.h>
-#include <linux/list.h>
-
-#define DVB_MAJOR 212
-
-#if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0
-  #define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS
-#else
-  #define DVB_MAX_ADAPTERS 8
-#endif
-
-#define DVB_UNSET (-1)
-
-#define DVB_DEVICE_VIDEO      0
-#define DVB_DEVICE_AUDIO      1
-#define DVB_DEVICE_SEC        2
-#define DVB_DEVICE_FRONTEND   3
-#define DVB_DEVICE_DEMUX      4
-#define DVB_DEVICE_DVR        5
-#define DVB_DEVICE_CA         6
-#define DVB_DEVICE_NET        7
-#define DVB_DEVICE_OSD        8
-
-#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \
-	static short adapter_nr[] = \
-		{[0 ... (DVB_MAX_ADAPTERS - 1)] = DVB_UNSET }; \
-	module_param_array(adapter_nr, short, NULL, 0444); \
-	MODULE_PARM_DESC(adapter_nr, "DVB adapter numbers")
-
-struct dvb_frontend;
-
-struct dvb_adapter {
-	int num;
-	struct list_head list_head;
-	struct list_head device_list;
-	const char *name;
-	u8 proposed_mac [6];
-	void* priv;
-
-	struct device *device;
-
-	struct module *module;
-
-	int mfe_shared;			/* indicates mutually exclusive frontends */
-	struct dvb_device *mfe_dvbdev;	/* frontend device in use */
-	struct mutex mfe_lock;		/* access lock for thread creation */
-
-	/* Allow the adapter/bridge driver to perform an action before and/or
-	 * after the core handles an ioctl:
-	 *
-	 * DVB_FE_IOCTL_PRE indicates that the ioctl has not yet been handled.
-	 * DVB_FE_IOCTL_POST indicates that the ioctl has been handled.
-	 *
-	 * When DVB_FE_IOCTL_PRE is passed to the callback as the stage arg:
-	 *
-	 * return 0 to allow dvb-core to handle the ioctl.
-	 * return a positive int to prevent dvb-core from handling the ioctl,
-	 * 	and exit without error.
-	 * return a negative int to prevent dvb-core from handling the ioctl,
-	 * 	and return that value as an error.
-	 *
-	 * When DVB_FE_IOCTL_POST is passed to the callback as the stage arg:
-	 *
-	 * return 0 to allow the dvb_frontend ioctl handler to exit normally.
-	 * return a negative int to cause the dvb_frontend ioctl handler to
-	 * 	return that value as an error.
-	 */
-#define DVB_FE_IOCTL_PRE 0
-#define DVB_FE_IOCTL_POST 1
-	int (*fe_ioctl_override)(struct dvb_frontend *fe,
-				 unsigned int cmd, void *parg,
-				 unsigned int stage);
-};
-
-
-struct dvb_device {
-	struct list_head list_head;
-	const struct file_operations *fops;
-	struct dvb_adapter *adapter;
-	int type;
-	int minor;
-	u32 id;
-
-	/* in theory, 'users' can vanish now,
-	   but I don't want to change too much now... */
-	int readers;
-	int writers;
-	int users;
-
-	wait_queue_head_t	  wait_queue;
-	/* don't really need those !? -- FIXME: use video_usercopy  */
-	int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg);
-
-	void *priv;
-};
-
-
-extern int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
-				struct module *module, struct device *device,
-				short *adapter_nums);
-extern int dvb_unregister_adapter (struct dvb_adapter *adap);
-
-extern int dvb_register_device (struct dvb_adapter *adap,
-				struct dvb_device **pdvbdev,
-				const struct dvb_device *template,
-				void *priv,
-				int type);
-
-extern void dvb_unregister_device (struct dvb_device *dvbdev);
-
-extern int dvb_generic_open (struct inode *inode, struct file *file);
-extern int dvb_generic_release (struct inode *inode, struct file *file);
-extern long dvb_generic_ioctl (struct file *file,
-			      unsigned int cmd, unsigned long arg);
-
-/* we don't mess with video_usercopy() any more,
-we simply define out own dvb_usercopy(), which will hopefully become
-generic_usercopy()  someday... */
-
-extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
-			    int (*func)(struct file *file, unsigned int cmd, void *arg));
-
-/** generic DVB attach function. */
-#ifdef CONFIG_MEDIA_ATTACH
-#define dvb_attach(FUNCTION, ARGS...) ({ \
-	void *__r = NULL; \
-	typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
-	if (__a) { \
-		__r = (void *) __a(ARGS); \
-		if (__r == NULL) \
-			symbol_put(FUNCTION); \
-	} else { \
-		printk(KERN_ERR "DVB: Unable to find symbol "#FUNCTION"()\n"); \
-	} \
-	__r; \
-})
-
-#else
-#define dvb_attach(FUNCTION, ARGS...) ({ \
-	FUNCTION(ARGS); \
-})
-
-#endif
-
-#endif /* #ifndef _DVBDEV_H_ */
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
deleted file mode 100644
index c216156..0000000
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ /dev/null
@@ -1,440 +0,0 @@
-config DVB_USB
-	tristate "Support for various USB DVB devices"
-	depends on DVB_CORE && USB && I2C && RC_CORE
-	help
-	  By enabling this you will be able to choose the various supported
-	  USB1.1 and USB2.0 DVB devices.
-
-	  Almost every USB device needs a firmware, please look into
-	  <file:Documentation/dvb/README.dvb-usb>.
-
-	  For a complete list of supported USB devices see the LinuxTV DVB Wiki:
-	  <http://www.linuxtv.org/wiki/index.php/DVB_USB>
-
-	  Say Y if you own a USB DVB device.
-
-config DVB_USB_DEBUG
-	bool "Enable extended debug support for all DVB-USB devices"
-	depends on DVB_USB
-	help
-	  Say Y if you want to enable debugging. See modinfo dvb-usb (and the
-	  appropriate drivers) for debug levels.
-
-config DVB_USB_A800
-	tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)"
-	depends on DVB_USB
-	select DVB_DIB3000MC
-	select DVB_PLL if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
-
-config DVB_USB_DIBUSB_MB
-	tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
-	depends on DVB_USB
-	select DVB_PLL if !DVB_FE_CUSTOMISE
-	select DVB_DIB3000MB
-	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
-	help
-	  Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
-	  DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
-
-	  For an up-to-date list of devices supported by this driver, have a look
-	  on the Linux-DVB Wiki at www.linuxtv.org.
-
-	  Say Y if you own such a device and want to use it. You should build it as
-	  a module.
-
-config DVB_USB_DIBUSB_MB_FAULTY
-	bool "Support faulty USB IDs"
-	depends on DVB_USB_DIBUSB_MB
-	help
-	  Support for faulty USB IDs due to an invalid EEPROM on some Artec devices.
-
-config DVB_USB_DIBUSB_MC
-	tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
-	depends on DVB_USB
-	select DVB_DIB3000MC
-	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
-	help
-	  Support for USB2.0 DVB-T receivers based on reference designs made by
-	  DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
-
-	  For an up-to-date list of devices supported by this driver, have a look
-	  on the Linux-DVB Wiki at www.linuxtv.org.
-
-	  Say Y if you own such a device and want to use it. You should build it as
-	  a module.
-
-config DVB_USB_DIB0700
-	tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)"
-	depends on DVB_USB
-	select DVB_DIB7000P if !DVB_FE_CUSTOMISE
-	select DVB_DIB7000M if !DVB_FE_CUSTOMISE
-	select DVB_DIB8000 if !DVB_FE_CUSTOMISE
-	select DVB_DIB3000MC if !DVB_FE_CUSTOMISE
-	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
-	select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
-	select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
-	select DVB_TUNER_DIB0090 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
-	help
-	  Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
-	  USB bridge is also present in devices having the DiB7700 DVB-T-USB
-	  silicon. This chip can be found in devices offered by Hauppauge,
-	  Avermedia and other big and small companies.
-
-	  For an up-to-date list of devices supported by this driver, have a look
-	  on the LinuxTV Wiki at www.linuxtv.org.
-
-	  Say Y if you own such a device and want to use it. You should build it as
-	  a module.
-
-config DVB_USB_UMT_010
-	tristate "HanfTek UMT-010 DVB-T USB2.0 support"
-	depends on DVB_USB
-	select DVB_PLL if !DVB_FE_CUSTOMISE
-	select DVB_DIB3000MC
-	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
-	select DVB_MT352 if !DVB_FE_CUSTOMISE
-	help
-	  Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
-
-config DVB_USB_CXUSB
-	tristate "Conexant USB2.0 hybrid reference design support"
-	depends on DVB_USB
-	select DVB_PLL if !DVB_FE_CUSTOMISE
-	select DVB_CX22702 if !DVB_FE_CUSTOMISE
-	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
-	select DVB_MT352 if !DVB_FE_CUSTOMISE
-	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-	select DVB_DIB7000P if !DVB_FE_CUSTOMISE
-	select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
-	select DVB_ATBM8830 if !DVB_FE_CUSTOMISE
-	select DVB_LGS8GXX if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_MAX2165 if !MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to support the Conexant USB2.0 hybrid reference design.
-	  Currently, only DVB and ATSC modes are supported, analog mode
-	  shall be added in the future. Devices that require this module:
-
-	  Medion MD95700 hybrid USB2.0 device.
-	  DViCO FusionHDTV (Bluebird) USB2.0 devices
-
-config DVB_USB_M920X
-	tristate "Uli m920x DVB-T USB2.0 support"
-	depends on DVB_USB
-	select DVB_MT352 if !DVB_FE_CUSTOMISE
-	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
-	  Currently, only devices with a product id of
-	  "DTV USB MINI" (in cold state) are supported.
-	  Firmware required.
-
-config DVB_USB_GL861
-	tristate "Genesys Logic GL861 USB2.0 support"
-	depends on DVB_USB
-	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
-	  receiver with USB ID 0db0:5581.
-
-config DVB_USB_AU6610
-	tristate "Alcor Micro AU6610 USB2.0 support"
-	depends on DVB_USB
-	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
-
-config DVB_USB_DIGITV
-	tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
-	depends on DVB_USB
-	select DVB_PLL if !DVB_FE_CUSTOMISE
-	select DVB_NXT6000 if !DVB_FE_CUSTOMISE
-	select DVB_MT352 if !DVB_FE_CUSTOMISE
-	help
-	  Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver.
-
-config DVB_USB_VP7045
-	tristate "TwinhanDTV Alpha/MagicBoxII, DNTV tinyUSB2, Beetle USB2.0 support"
-	depends on DVB_USB
-	help
-	  Say Y here to support the
-
-	    TwinhanDTV Alpha (stick) (VP-7045),
-		TwinhanDTV MagicBox II (VP-7046),
-		DigitalNow TinyUSB 2 DVB-t,
-		DigitalRise USB 2.0 Ter (Beetle) and
-		TYPHOON DVB-T USB DRIVE
-
-	  DVB-T USB2.0 receivers.
-
-config DVB_USB_VP702X
-	tristate "TwinhanDTV StarBox and clones DVB-S USB2.0 support"
-	depends on DVB_USB
-	help
-	  Say Y here to support the
-
-	    TwinhanDTV StarBox,
-		DigitalRise USB Starbox and
-		TYPHOON DVB-S USB 2.0 BOX
-
-	  DVB-S USB2.0 receivers.
-
-config DVB_USB_GP8PSK
-	tristate "GENPIX 8PSK->USB module support"
-	depends on DVB_USB
-	help
-	  Say Y here to support the
-	    GENPIX 8psk module
-
-	  DVB-S USB2.0 receivers.
-
-config DVB_USB_NOVA_T_USB2
-	tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
-	depends on DVB_USB
-	select DVB_DIB3000MC
-	select DVB_PLL if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
-
-config DVB_USB_TTUSB2
-	tristate "Pinnacle 400e DVB-S USB2.0 support"
-	depends on DVB_USB
-	select DVB_TDA10086 if !DVB_FE_CUSTOMISE
-	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
-	select DVB_TDA826X if !DVB_FE_CUSTOMISE
-	help
-	  Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The
-	  firmware protocol used by this module is similar to the one used by the
-	  old ttusb-driver - that's why the module is called dvb-usb-ttusb2.
-
-config DVB_USB_DTT200U
-	tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)"
-	depends on DVB_USB
-	help
-	  Say Y here to support the WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver.
-
-	  The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan).
-
-	  The WT-220U and its clones are pen-sized.
-
-config DVB_USB_OPERA1
-	tristate "Opera1 DVB-S USB2.0 receiver"
-	depends on DVB_USB
-	select DVB_STV0299 if !DVB_FE_CUSTOMISE
-	select DVB_PLL if !DVB_FE_CUSTOMISE
-	help
-	  Say Y here to support the Opera DVB-S USB2.0 receiver.
-
-config DVB_USB_AF9005
-	tristate "Afatech AF9005 DVB-T USB1.1 support"
-	depends on DVB_USB && EXPERIMENTAL
-	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
-	  and the TerraTec Cinergy T USB XE (Rev.1)
-
-config DVB_USB_AF9005_REMOTE
-	tristate "Afatech AF9005 default remote control support"
-	depends on DVB_USB_AF9005
-	help
-	  Say Y here to support the default remote control decoding for the
-	  Afatech AF9005 based receiver.
-
-config DVB_USB_PCTV452E
-	tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600"
-	depends on DVB_USB
-	select TTPCI_EEPROM
-	select DVB_LNBP22 if !DVB_FE_CUSTOMISE
-	select DVB_STB0899 if !DVB_FE_CUSTOMISE
-	select DVB_STB6100 if !DVB_FE_CUSTOMISE
-	help
-	  Support for external USB adapter designed by Pinnacle,
-	  shipped under the brand name 'PCTV HDTV Pro USB'.
-	  Also supports TT Connect S2-3600/3650 cards.
-	  Say Y if you own such a device and want to use it.
-
-config DVB_USB_DW2102
-	tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support"
-	depends on DVB_USB
-	select DVB_PLL if !DVB_FE_CUSTOMISE
-	select DVB_STV0299 if !DVB_FE_CUSTOMISE
-	select DVB_STV0288 if !DVB_FE_CUSTOMISE
-	select DVB_STB6000 if !DVB_FE_CUSTOMISE
-	select DVB_CX24116 if !DVB_FE_CUSTOMISE
-	select DVB_SI21XX if !DVB_FE_CUSTOMISE
-	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
-	select DVB_MT312 if !DVB_FE_CUSTOMISE
-	select DVB_ZL10039 if !DVB_FE_CUSTOMISE
-	select DVB_DS3000 if !DVB_FE_CUSTOMISE
-	select DVB_STB6100 if !DVB_FE_CUSTOMISE
-	select DVB_STV6110 if !DVB_FE_CUSTOMISE
-	select DVB_STV0900 if !DVB_FE_CUSTOMISE
-	help
-	  Say Y here to support the DvbWorld, TeVii, Prof DVB-S/S2 USB2.0
-	  receivers.
-
-config DVB_USB_CINERGY_T2
-	tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver"
-	depends on DVB_USB
-	help
-	  Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
-
-	  Say Y if you own such a device and want to use it.
-
-config DVB_USB_ANYSEE
-	tristate "Anysee DVB-T/C USB2.0 support"
-	depends on DVB_USB
-	select DVB_PLL if !DVB_FE_CUSTOMISE
-	select DVB_MT352 if !DVB_FE_CUSTOMISE
-	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_TDA18212 if !MEDIA_TUNER_CUSTOMISE
-	select DVB_CX24116 if !DVB_FE_CUSTOMISE
-	select DVB_STV0900 if !DVB_FE_CUSTOMISE
-	select DVB_STV6110 if !DVB_FE_CUSTOMISE
-	select DVB_ISL6423 if !DVB_FE_CUSTOMISE
-	select DVB_CXD2820R if !DVB_FE_CUSTOMISE
-	help
-	  Say Y here to support the Anysee E30, Anysee E30 Plus or
-	  Anysee E30 C Plus DVB USB2.0 receiver.
-
-config DVB_USB_DTV5100
-	tristate "AME DTV-5100 USB2.0 DVB-T support"
-	depends on DVB_USB
-	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver.
-
-config DVB_USB_AF9015
-	tristate "Afatech AF9015 DVB-T USB2.0 support"
-	depends on DVB_USB
-	select DVB_AF9013
-	select DVB_PLL              if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_MT2060   if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_QT1010   if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
-
-config DVB_USB_CE6230
-	tristate "Intel CE6230 DVB-T USB2.0 support"
-	depends on DVB_USB
-	select DVB_ZL10353
-	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver
-
-config DVB_USB_FRIIO
-	tristate "Friio ISDB-T USB2.0 Receiver support"
-	depends on DVB_USB
-	help
-	  Say Y here to support the Japanese DTV receiver Friio.
-
-config DVB_USB_EC168
-	tristate "E3C EC168 DVB-T USB2.0 support"
-	depends on DVB_USB
-	select DVB_EC100
-	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to support the E3C EC168 DVB-T USB2.0 receiver.
-
-config DVB_USB_AZ6007
-	tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support"
-	depends on DVB_USB
-	select DVB_DRXK if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_MT2063 if !DVB_FE_CUSTOMISE
-	help
-	  Say Y here to support theAfatech AF9005 based DVB-T/DVB-C receivers.
-
-config DVB_USB_AZ6027
-	tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support"
-	depends on DVB_USB
-	select DVB_STB0899 if !DVB_FE_CUSTOMISE
-	select DVB_STB6100 if !DVB_FE_CUSTOMISE
-	help
-	  Say Y here to support the AZ6027 device
-
-config DVB_USB_LME2510
-	tristate "LME DM04/QQBOX DVB-S USB2.0 support"
-	depends on DVB_USB
-	select DVB_TDA10086 if !DVB_FE_CUSTOMISE
-	select DVB_TDA826X if !DVB_FE_CUSTOMISE
-	select DVB_STV0288 if !DVB_FE_CUSTOMISE
-	select DVB_IX2505V if !DVB_FE_CUSTOMISE
-	select DVB_STV0299 if !DVB_FE_CUSTOMISE
-	select DVB_PLL if !DVB_FE_CUSTOMISE
-	select DVB_M88RS2000 if !DVB_FE_CUSTOMISE
-	help
-	  Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 .
-
-config DVB_USB_TECHNISAT_USB2
-	tristate "Technisat DVB-S/S2 USB2.0 support"
-	depends on DVB_USB
-	select DVB_STV090x if !DVB_FE_CUSTOMISE
-	select DVB_STV6110x if !DVB_FE_CUSTOMISE
-	help
-	  Say Y here to support the Technisat USB2 DVB-S/S2 device
-
-config DVB_USB_IT913X
-	tristate "it913x driver"
-	depends on DVB_USB
-	select DVB_IT913X_FE
-	help
-	  Say Y here to support the it913x device
-
-config DVB_USB_MXL111SF
-	tristate "MxL111SF DTV USB2.0 support"
-	depends on DVB_USB
-	select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
-	select DVB_LG2160 if !DVB_FE_CUSTOMISE
-	select VIDEO_TVEEPROM
-	help
-	  Say Y here to support the MxL111SF USB2.0 DTV receiver.
-
-config DVB_USB_RTL28XXU
-	tristate "Realtek RTL28xxU DVB USB support"
-	depends on DVB_USB && EXPERIMENTAL
-	select DVB_RTL2830
-	select DVB_RTL2832
-	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_FC0012 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_FC0013 if !MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to support the Realtek RTL28xxU DVB USB receiver.
-
-config DVB_USB_AF9035
-	tristate "Afatech AF9035 DVB-T USB2.0 support"
-	depends on DVB_USB
-	select DVB_AF9033
-	select MEDIA_TUNER_TUA9001 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_FC0011 if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
-	select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE
-	help
-	  Say Y here to support the Afatech AF9035 based DVB USB receiver.
-
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
deleted file mode 100644
index b667ac3..0000000
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ /dev/null
@@ -1,121 +0,0 @@
-dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o
-obj-$(CONFIG_DVB_USB) += dvb-usb.o
-
-dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o
-obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o
-
-dvb-usb-vp702x-objs = vp702x.o vp702x-fe.o
-obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o
-
-dvb-usb-gp8psk-objs = gp8psk.o gp8psk-fe.o
-obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o
-
-dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o
-obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o
-
-dvb-usb-dibusb-common-objs = dibusb-common.o
-
-dvb-usb-a800-objs = a800.o
-obj-$(CONFIG_DVB_USB_A800) += dvb-usb-dibusb-common.o dvb-usb-a800.o
-
-dvb-usb-dibusb-mb-objs = dibusb-mb.o
-obj-$(CONFIG_DVB_USB_DIBUSB_MB) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mb.o
-
-dvb-usb-dibusb-mc-objs = dibusb-mc.o
-obj-$(CONFIG_DVB_USB_DIBUSB_MC) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mc.o
-
-dvb-usb-nova-t-usb2-objs = nova-t-usb2.o
-obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2.o
-
-dvb-usb-umt-010-objs = umt-010.o
-obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o
-
-dvb-usb-m920x-objs = m920x.o
-obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o
-
-dvb-usb-gl861-objs = gl861.o
-obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o
-
-dvb-usb-au6610-objs = au6610.o
-obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o
-
-dvb-usb-digitv-objs = digitv.o
-obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
-
-dvb-usb-cxusb-objs = cxusb.o
-obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o
-
-dvb-usb-ttusb2-objs = ttusb2.o
-obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-ttusb2.o
-
-dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o
-obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o
-
-dvb-usb-opera-objs = opera1.o
-obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o
-
-dvb-usb-af9005-objs = af9005.o af9005-fe.o
-obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o
-
-dvb-usb-af9005-remote-objs = af9005-remote.o
-obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
-
-dvb-usb-anysee-objs = anysee.o
-obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
-
-dvb-usb-pctv452e-objs = pctv452e.o
-obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o
-
-dvb-usb-dw2102-objs = dw2102.o
-obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o
-
-dvb-usb-dtv5100-objs = dtv5100.o
-obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o
-
-dvb-usb-af9015-objs = af9015.o
-obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
-
-dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o
-obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
-
-dvb-usb-ce6230-objs = ce6230.o
-obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o
-
-dvb-usb-friio-objs = friio.o friio-fe.o
-obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o
-
-dvb-usb-ec168-objs = ec168.o
-obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
-
-dvb-usb-az6007-objs = az6007.o
-obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o
-
-dvb-usb-az6027-objs = az6027.o
-obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
-
-dvb-usb-lmedm04-objs = lmedm04.o
-obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o
-
-dvb-usb-technisat-usb2-objs = technisat-usb2.o
-obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o
-
-dvb-usb-it913x-objs := it913x.o
-obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o
-
-dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o
-obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o
-obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o
-obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o
-
-dvb-usb-rtl28xxu-objs = rtl28xxu.o
-obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
-
-dvb-usb-af9035-objs = af9035.o
-obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o
-
-ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
-ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/
-# due to tuner-xc3028
-ccflags-y += -I$(srctree)/drivers/media/common/tuners
-ccflags-y += -I$(srctree)/drivers/media/dvb/ttpci
-
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c
deleted file mode 100644
index 8d7fef8..0000000
--- a/drivers/media/dvb/dvb-usb/a800.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/* DVB USB framework compliant Linux driver for the AVerMedia AverTV DVB-T
- * USB2.0 (A800) DVB-T receiver.
- *
- * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * Thanks to
- *   - AVerMedia who kindly provided information and
- *   - Glen Harris who suffered from my mistakes during development.
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "dibusb.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (rc=1 (or-able))." DVB_USB_DEBUG_STATUS);
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define deb_rc(args...)   dprintk(debug,0x01,args)
-
-static int a800_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	/* do nothing for the AVerMedia */
-	return 0;
-}
-
-/* assure to put cold to 0 for iManufacturer == 1 */
-static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
-	struct dvb_usb_device_description **desc, int *cold)
-{
-	*cold = udev->descriptor.iManufacturer != 1;
-	return 0;
-}
-
-static struct rc_map_table rc_map_a800_table[] = {
-	{ 0x0201, KEY_MODE },      /* SOURCE */
-	{ 0x0200, KEY_POWER2 },      /* POWER */
-	{ 0x0205, KEY_1 },           /* 1 */
-	{ 0x0206, KEY_2 },           /* 2 */
-	{ 0x0207, KEY_3 },           /* 3 */
-	{ 0x0209, KEY_4 },           /* 4 */
-	{ 0x020a, KEY_5 },           /* 5 */
-	{ 0x020b, KEY_6 },           /* 6 */
-	{ 0x020d, KEY_7 },           /* 7 */
-	{ 0x020e, KEY_8 },           /* 8 */
-	{ 0x020f, KEY_9 },           /* 9 */
-	{ 0x0212, KEY_LEFT },        /* L / DISPLAY */
-	{ 0x0211, KEY_0 },           /* 0 */
-	{ 0x0213, KEY_RIGHT },       /* R / CH RTN */
-	{ 0x0217, KEY_CAMERA },      /* SNAP SHOT */
-	{ 0x0210, KEY_LAST },        /* 16-CH PREV */
-	{ 0x021e, KEY_VOLUMEDOWN },  /* VOL DOWN */
-	{ 0x020c, KEY_ZOOM },        /* FULL SCREEN */
-	{ 0x021f, KEY_VOLUMEUP },    /* VOL UP */
-	{ 0x0214, KEY_MUTE },        /* MUTE */
-	{ 0x0208, KEY_AUDIO },       /* AUDIO */
-	{ 0x0219, KEY_RECORD },      /* RECORD */
-	{ 0x0218, KEY_PLAY },        /* PLAY */
-	{ 0x021b, KEY_STOP },        /* STOP */
-	{ 0x021a, KEY_PLAYPAUSE },   /* TIMESHIFT / PAUSE */
-	{ 0x021d, KEY_BACK },        /* << / RED */
-	{ 0x021c, KEY_FORWARD },     /* >> / YELLOW */
-	{ 0x0203, KEY_TEXT },        /* TELETEXT */
-	{ 0x0204, KEY_EPG },         /* EPG */
-	{ 0x0215, KEY_MENU },        /* MENU */
-
-	{ 0x0303, KEY_CHANNELUP },   /* CH UP */
-	{ 0x0302, KEY_CHANNELDOWN }, /* CH DOWN */
-	{ 0x0301, KEY_FIRST },       /* |<< / GREEN */
-	{ 0x0300, KEY_LAST },        /* >>| / BLUE */
-
-};
-
-static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
-{
-	int ret;
-	u8 *key = kmalloc(5, GFP_KERNEL);
-	if (!key)
-		return -ENOMEM;
-
-	if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0),
-				0x04, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, key, 5,
-				2000) != 5) {
-		ret = -ENODEV;
-		goto out;
-	}
-
-	/* call the universal NEC remote processor, to find out the key's state and event */
-	dvb_usb_nec_rc_key_to_event(d,key,event,state);
-	if (key[0] != 0)
-		deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
-	ret = 0;
-out:
-	kfree(key);
-	return ret;
-}
-
-/* USB Driver stuff */
-static struct dvb_usb_device_properties a800_properties;
-
-static int a800_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	return dvb_usb_device_init(intf, &a800_properties,
-				   THIS_MODULE, NULL, adapter_nr);
-}
-
-/* do not change the order of the ID table */
-static struct usb_device_id a800_table [] = {
-/* 00 */	{ USB_DEVICE(USB_VID_AVERMEDIA,     USB_PID_AVERMEDIA_DVBT_USB2_COLD) },
-/* 01 */	{ USB_DEVICE(USB_VID_AVERMEDIA,     USB_PID_AVERMEDIA_DVBT_USB2_WARM) },
-			{ }		/* Terminating entry */
-};
-MODULE_DEVICE_TABLE (usb, a800_table);
-
-static struct dvb_usb_device_properties a800_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware = "dvb-usb-avertv-a800-02.fw",
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-			.pid_filter_count = 32,
-			.streaming_ctrl   = dibusb2_0_streaming_ctrl,
-			.pid_filter       = dibusb_pid_filter,
-			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
-
-			.frontend_attach  = dibusb_dib3000mc_frontend_attach,
-			.tuner_attach     = dibusb_dib3000mc_tuner_attach,
-
-			/* parameter for the MPEG2-data transfer */
-					.stream = {
-						.type = USB_BULK,
-				.count = 7,
-				.endpoint = 0x06,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-			.size_of_priv     = sizeof(struct dibusb_state),
-		},
-	},
-
-	.power_ctrl       = a800_power_ctrl,
-	.identify_state   = a800_identify_state,
-
-	.rc.legacy = {
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_map_table     = rc_map_a800_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_a800_table),
-		.rc_query         = a800_rc_query,
-	},
-
-	.i2c_algo         = &dibusb_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-	.num_device_descs = 1,
-	.devices = {
-		{   "AVerMedia AverTV DVB-T USB 2.0 (A800)",
-			{ &a800_table[0], NULL },
-			{ &a800_table[1], NULL },
-		},
-	}
-};
-
-static struct usb_driver a800_driver = {
-	.name		= "dvb_usb_a800",
-	.probe		= a800_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table	= a800_table,
-};
-
-module_usb_driver(a800_driver);
-
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("AVerMedia AverTV DVB-T USB 2.0 (A800)");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9005-fe.c b/drivers/media/dvb/dvb-usb/af9005-fe.c
deleted file mode 100644
index 740f3f4..0000000
--- a/drivers/media/dvb/dvb-usb/af9005-fe.c
+++ /dev/null
@@ -1,1487 +0,0 @@
-/* Frontend part of the Linux driver for the Afatech 9005
- * USB1.1 DVB-T receiver.
- *
- * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
- *
- * Thanks to Afatech who kindly provided information.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "af9005.h"
-#include "af9005-script.h"
-#include "mt2060.h"
-#include "qt1010.h"
-#include <asm/div64.h>
-
-struct af9005_fe_state {
-	struct dvb_usb_device *d;
-	fe_status_t stat;
-
-	/* retraining parameters */
-	u32 original_fcw;
-	u16 original_rf_top;
-	u16 original_if_top;
-	u16 original_if_min;
-	u16 original_aci0_if_top;
-	u16 original_aci1_if_top;
-	u16 original_aci0_if_min;
-	u8 original_if_unplug_th;
-	u8 original_rf_unplug_th;
-	u8 original_dtop_if_unplug_th;
-	u8 original_dtop_rf_unplug_th;
-
-	/* statistics */
-	u32 pre_vit_error_count;
-	u32 pre_vit_bit_count;
-	u32 ber;
-	u32 post_vit_error_count;
-	u32 post_vit_bit_count;
-	u32 unc;
-	u16 abort_count;
-
-	int opened;
-	int strong;
-	unsigned long next_status_check;
-	struct dvb_frontend frontend;
-};
-
-static int af9005_write_word_agc(struct dvb_usb_device *d, u16 reghi,
-				 u16 reglo, u8 pos, u8 len, u16 value)
-{
-	int ret;
-
-	if ((ret = af9005_write_ofdm_register(d, reglo, (u8) (value & 0xff))))
-		return ret;
-	return af9005_write_register_bits(d, reghi, pos, len,
-					  (u8) ((value & 0x300) >> 8));
-}
-
-static int af9005_read_word_agc(struct dvb_usb_device *d, u16 reghi,
-				u16 reglo, u8 pos, u8 len, u16 * value)
-{
-	int ret;
-	u8 temp0, temp1;
-
-	if ((ret = af9005_read_ofdm_register(d, reglo, &temp0)))
-		return ret;
-	if ((ret = af9005_read_ofdm_register(d, reghi, &temp1)))
-		return ret;
-	switch (pos) {
-	case 0:
-		*value = ((u16) (temp1 & 0x03) << 8) + (u16) temp0;
-		break;
-	case 2:
-		*value = ((u16) (temp1 & 0x0C) << 6) + (u16) temp0;
-		break;
-	case 4:
-		*value = ((u16) (temp1 & 0x30) << 4) + (u16) temp0;
-		break;
-	case 6:
-		*value = ((u16) (temp1 & 0xC0) << 2) + (u16) temp0;
-		break;
-	default:
-		err("invalid pos in read word agc");
-		return -EINVAL;
-	}
-	return 0;
-
-}
-
-static int af9005_is_fecmon_available(struct dvb_frontend *fe, int *available)
-{
-	struct af9005_fe_state *state = fe->demodulator_priv;
-	int ret;
-	u8 temp;
-
-	*available = false;
-
-	ret = af9005_read_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en,
-					fec_vtb_rsd_mon_en_pos,
-					fec_vtb_rsd_mon_en_len, &temp);
-	if (ret)
-		return ret;
-	if (temp & 1) {
-		ret =
-		    af9005_read_register_bits(state->d,
-					      xd_p_reg_ofsm_read_rbc_en,
-					      reg_ofsm_read_rbc_en_pos,
-					      reg_ofsm_read_rbc_en_len, &temp);
-		if (ret)
-			return ret;
-		if ((temp & 1) == 0)
-			*available = true;
-
-	}
-	return 0;
-}
-
-static int af9005_get_post_vit_err_cw_count(struct dvb_frontend *fe,
-					    u32 * post_err_count,
-					    u32 * post_cw_count,
-					    u16 * abort_count)
-{
-	struct af9005_fe_state *state = fe->demodulator_priv;
-	int ret;
-	u32 err_count;
-	u32 cw_count;
-	u8 temp, temp0, temp1, temp2;
-	u16 loc_abort_count;
-
-	*post_err_count = 0;
-	*post_cw_count = 0;
-
-	/* check if error bit count is ready */
-	ret =
-	    af9005_read_register_bits(state->d, xd_r_fec_rsd_ber_rdy,
-				      fec_rsd_ber_rdy_pos, fec_rsd_ber_rdy_len,
-				      &temp);
-	if (ret)
-		return ret;
-	if (!temp) {
-		deb_info("rsd counter not ready\n");
-		return 100;
-	}
-	/* get abort count */
-	ret =
-	    af9005_read_ofdm_register(state->d,
-				      xd_r_fec_rsd_abort_packet_cnt_7_0,
-				      &temp0);
-	if (ret)
-		return ret;
-	ret =
-	    af9005_read_ofdm_register(state->d,
-				      xd_r_fec_rsd_abort_packet_cnt_15_8,
-				      &temp1);
-	if (ret)
-		return ret;
-	loc_abort_count = ((u16) temp1 << 8) + temp0;
-
-	/* get error count */
-	ret =
-	    af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_7_0,
-				      &temp0);
-	if (ret)
-		return ret;
-	ret =
-	    af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_15_8,
-				      &temp1);
-	if (ret)
-		return ret;
-	ret =
-	    af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_23_16,
-				      &temp2);
-	if (ret)
-		return ret;
-	err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0;
-	*post_err_count = err_count - (u32) loc_abort_count *8 * 8;
-
-	/* get RSD packet number */
-	ret =
-	    af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0,
-				      &temp0);
-	if (ret)
-		return ret;
-	ret =
-	    af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8,
-				      &temp1);
-	if (ret)
-		return ret;
-	cw_count = ((u32) temp1 << 8) + temp0;
-	if (cw_count == 0) {
-		err("wrong RSD packet count");
-		return -EIO;
-	}
-	deb_info("POST abort count %d err count %d rsd packets %d\n",
-		 loc_abort_count, err_count, cw_count);
-	*post_cw_count = cw_count - (u32) loc_abort_count;
-	*abort_count = loc_abort_count;
-	return 0;
-
-}
-
-static int af9005_get_post_vit_ber(struct dvb_frontend *fe,
-				   u32 * post_err_count, u32 * post_cw_count,
-				   u16 * abort_count)
-{
-	u32 loc_cw_count = 0, loc_err_count;
-	u16 loc_abort_count = 0;
-	int ret;
-
-	ret =
-	    af9005_get_post_vit_err_cw_count(fe, &loc_err_count, &loc_cw_count,
-					     &loc_abort_count);
-	if (ret)
-		return ret;
-	*post_err_count = loc_err_count;
-	*post_cw_count = loc_cw_count * 204 * 8;
-	*abort_count = loc_abort_count;
-
-	return 0;
-}
-
-static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe,
-					    u32 * pre_err_count,
-					    u32 * pre_bit_count)
-{
-	struct af9005_fe_state *state = fe->demodulator_priv;
-	u8 temp, temp0, temp1, temp2;
-	u32 super_frame_count, x, bits;
-	int ret;
-
-	ret =
-	    af9005_read_register_bits(state->d, xd_r_fec_vtb_ber_rdy,
-				      fec_vtb_ber_rdy_pos, fec_vtb_ber_rdy_len,
-				      &temp);
-	if (ret)
-		return ret;
-	if (!temp) {
-		deb_info("viterbi counter not ready\n");
-		return 101;	/* ERR_APO_VTB_COUNTER_NOT_READY; */
-	}
-	ret =
-	    af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_7_0,
-				      &temp0);
-	if (ret)
-		return ret;
-	ret =
-	    af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_15_8,
-				      &temp1);
-	if (ret)
-		return ret;
-	ret =
-	    af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_23_16,
-				      &temp2);
-	if (ret)
-		return ret;
-	*pre_err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0;
-
-	ret =
-	    af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0,
-				      &temp0);
-	if (ret)
-		return ret;
-	ret =
-	    af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8,
-				      &temp1);
-	if (ret)
-		return ret;
-	super_frame_count = ((u32) temp1 << 8) + temp0;
-	if (super_frame_count == 0) {
-		deb_info("super frame count 0\n");
-		return 102;
-	}
-
-	/* read fft mode */
-	ret =
-	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod,
-				      reg_tpsd_txmod_pos, reg_tpsd_txmod_len,
-				      &temp);
-	if (ret)
-		return ret;
-	if (temp == 0) {
-		/* 2K */
-		x = 1512;
-	} else if (temp == 1) {
-		/* 8k */
-		x = 6048;
-	} else {
-		err("Invalid fft mode");
-		return -EINVAL;
-	}
-
-	/* read modulation mode */
-	ret =
-	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
-				      reg_tpsd_const_pos, reg_tpsd_const_len,
-				      &temp);
-	if (ret)
-		return ret;
-	switch (temp) {
-	case 0:		/* QPSK */
-		bits = 2;
-		break;
-	case 1:		/* QAM_16 */
-		bits = 4;
-		break;
-	case 2:		/* QAM_64 */
-		bits = 6;
-		break;
-	default:
-		err("invalid modulation mode");
-		return -EINVAL;
-	}
-	*pre_bit_count = super_frame_count * 68 * 4 * x * bits;
-	deb_info("PRE err count %d frame count %d bit count %d\n",
-		 *pre_err_count, super_frame_count, *pre_bit_count);
-	return 0;
-}
-
-static int af9005_reset_pre_viterbi(struct dvb_frontend *fe)
-{
-	struct af9005_fe_state *state = fe->demodulator_priv;
-	int ret;
-
-	/* set super frame count to 1 */
-	ret =
-	    af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0,
-				       1 & 0xff);
-	if (ret)
-		return ret;
-	ret = af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8,
-					 1 >> 8);
-	if (ret)
-		return ret;
-	/* reset pre viterbi error count */
-	ret =
-	    af9005_write_register_bits(state->d, xd_p_fec_vtb_ber_rst,
-				       fec_vtb_ber_rst_pos, fec_vtb_ber_rst_len,
-				       1);
-
-	return ret;
-}
-
-static int af9005_reset_post_viterbi(struct dvb_frontend *fe)
-{
-	struct af9005_fe_state *state = fe->demodulator_priv;
-	int ret;
-
-	/* set packet unit */
-	ret =
-	    af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0,
-				       10000 & 0xff);
-	if (ret)
-		return ret;
-	ret =
-	    af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8,
-				       10000 >> 8);
-	if (ret)
-		return ret;
-	/* reset post viterbi error count */
-	ret =
-	    af9005_write_register_bits(state->d, xd_p_fec_rsd_ber_rst,
-				       fec_rsd_ber_rst_pos, fec_rsd_ber_rst_len,
-				       1);
-
-	return ret;
-}
-
-static int af9005_get_statistic(struct dvb_frontend *fe)
-{
-	struct af9005_fe_state *state = fe->demodulator_priv;
-	int ret, fecavailable;
-	u64 numerator, denominator;
-
-	deb_info("GET STATISTIC\n");
-	ret = af9005_is_fecmon_available(fe, &fecavailable);
-	if (ret)
-		return ret;
-	if (!fecavailable) {
-		deb_info("fecmon not available\n");
-		return 0;
-	}
-
-	ret = af9005_get_pre_vit_err_bit_count(fe, &state->pre_vit_error_count,
-					       &state->pre_vit_bit_count);
-	if (ret == 0) {
-		af9005_reset_pre_viterbi(fe);
-		if (state->pre_vit_bit_count > 0) {
-			/* according to v 0.0.4 of the dvb api ber should be a multiple
-			   of 10E-9 so we have to multiply the error count by
-			   10E9=1000000000 */
-			numerator =
-			    (u64) state->pre_vit_error_count * (u64) 1000000000;
-			denominator = (u64) state->pre_vit_bit_count;
-			state->ber = do_div(numerator, denominator);
-		} else {
-			state->ber = 0xffffffff;
-		}
-	}
-
-	ret = af9005_get_post_vit_ber(fe, &state->post_vit_error_count,
-				      &state->post_vit_bit_count,
-				      &state->abort_count);
-	if (ret == 0) {
-		ret = af9005_reset_post_viterbi(fe);
-		state->unc += state->abort_count;
-		if (ret)
-			return ret;
-	}
-	return 0;
-}
-
-static int af9005_fe_refresh_state(struct dvb_frontend *fe)
-{
-	struct af9005_fe_state *state = fe->demodulator_priv;
-	if (time_after(jiffies, state->next_status_check)) {
-		deb_info("REFRESH STATE\n");
-
-		/* statistics */
-		if (af9005_get_statistic(fe))
-			err("get_statistic_failed");
-		state->next_status_check = jiffies + 250 * HZ / 1000;
-	}
-	return 0;
-}
-
-static int af9005_fe_read_status(struct dvb_frontend *fe, fe_status_t * stat)
-{
-	struct af9005_fe_state *state = fe->demodulator_priv;
-	u8 temp;
-	int ret;
-
-	if (fe->ops.tuner_ops.release == NULL)
-		return -ENODEV;
-
-	*stat = 0;
-	ret = af9005_read_register_bits(state->d, xd_p_agc_lock,
-					agc_lock_pos, agc_lock_len, &temp);
-	if (ret)
-		return ret;
-	if (temp)
-		*stat |= FE_HAS_SIGNAL;
-
-	ret = af9005_read_register_bits(state->d, xd_p_fd_tpsd_lock,
-					fd_tpsd_lock_pos, fd_tpsd_lock_len,
-					&temp);
-	if (ret)
-		return ret;
-	if (temp)
-		*stat |= FE_HAS_CARRIER;
-
-	ret = af9005_read_register_bits(state->d,
-					xd_r_mp2if_sync_byte_locked,
-					mp2if_sync_byte_locked_pos,
-					mp2if_sync_byte_locked_pos, &temp);
-	if (ret)
-		return ret;
-	if (temp)
-		*stat |= FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_LOCK;
-	if (state->opened)
-		af9005_led_control(state->d, *stat & FE_HAS_LOCK);
-
-	ret =
-	    af9005_read_register_bits(state->d, xd_p_reg_strong_sginal_detected,
-				      reg_strong_sginal_detected_pos,
-				      reg_strong_sginal_detected_len, &temp);
-	if (ret)
-		return ret;
-	if (temp != state->strong) {
-		deb_info("adjust for strong signal %d\n", temp);
-			state->strong = temp;
-	}
-	return 0;
-}
-
-static int af9005_fe_read_ber(struct dvb_frontend *fe, u32 * ber)
-{
-	struct af9005_fe_state *state = fe->demodulator_priv;
-	if (fe->ops.tuner_ops.release  == NULL)
-		return -ENODEV;
-	af9005_fe_refresh_state(fe);
-	*ber = state->ber;
-	return 0;
-}
-
-static int af9005_fe_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
-{
-	struct af9005_fe_state *state = fe->demodulator_priv;
-	if (fe->ops.tuner_ops.release == NULL)
-		return -ENODEV;
-	af9005_fe_refresh_state(fe);
-	*unc = state->unc;
-	return 0;
-}
-
-static int af9005_fe_read_signal_strength(struct dvb_frontend *fe,
-					  u16 * strength)
-{
-	struct af9005_fe_state *state = fe->demodulator_priv;
-	int ret;
-	u8 if_gain, rf_gain;
-
-	if (fe->ops.tuner_ops.release == NULL)
-		return -ENODEV;
-	ret =
-	    af9005_read_ofdm_register(state->d, xd_r_reg_aagc_rf_gain,
-				      &rf_gain);
-	if (ret)
-		return ret;
-	ret =
-	    af9005_read_ofdm_register(state->d, xd_r_reg_aagc_if_gain,
-				      &if_gain);
-	if (ret)
-		return ret;
-	/* this value has no real meaning, but i don't have the tables that relate
-	   the rf and if gain with the dbm, so I just scale the value */
-	*strength = (512 - rf_gain - if_gain) << 7;
-	return 0;
-}
-
-static int af9005_fe_read_snr(struct dvb_frontend *fe, u16 * snr)
-{
-	/* the snr can be derived from the ber and the modulation
-	   but I don't think this kind of complex calculations belong
-	   in the driver. I may be wrong.... */
-	return -ENOSYS;
-}
-
-static int af9005_fe_program_cfoe(struct dvb_usb_device *d, u32 bw)
-{
-	u8 temp0, temp1, temp2, temp3, buf[4];
-	int ret;
-	u32 NS_coeff1_2048Nu;
-	u32 NS_coeff1_8191Nu;
-	u32 NS_coeff1_8192Nu;
-	u32 NS_coeff1_8193Nu;
-	u32 NS_coeff2_2k;
-	u32 NS_coeff2_8k;
-
-	switch (bw) {
-	case 6000000:
-		NS_coeff1_2048Nu = 0x2ADB6DC;
-		NS_coeff1_8191Nu = 0xAB7313;
-		NS_coeff1_8192Nu = 0xAB6DB7;
-		NS_coeff1_8193Nu = 0xAB685C;
-		NS_coeff2_2k = 0x156DB6E;
-		NS_coeff2_8k = 0x55B6DC;
-		break;
-
-	case 7000000:
-		NS_coeff1_2048Nu = 0x3200001;
-		NS_coeff1_8191Nu = 0xC80640;
-		NS_coeff1_8192Nu = 0xC80000;
-		NS_coeff1_8193Nu = 0xC7F9C0;
-		NS_coeff2_2k = 0x1900000;
-		NS_coeff2_8k = 0x640000;
-		break;
-
-	case 8000000:
-		NS_coeff1_2048Nu = 0x3924926;
-		NS_coeff1_8191Nu = 0xE4996E;
-		NS_coeff1_8192Nu = 0xE49249;
-		NS_coeff1_8193Nu = 0xE48B25;
-		NS_coeff2_2k = 0x1C92493;
-		NS_coeff2_8k = 0x724925;
-		break;
-	default:
-		err("Invalid bandwidth %d.", bw);
-		return -EINVAL;
-	}
-
-	/*
-	 *  write NS_coeff1_2048Nu
-	 */
-
-	temp0 = (u8) (NS_coeff1_2048Nu & 0x000000FF);
-	temp1 = (u8) ((NS_coeff1_2048Nu & 0x0000FF00) >> 8);
-	temp2 = (u8) ((NS_coeff1_2048Nu & 0x00FF0000) >> 16);
-	temp3 = (u8) ((NS_coeff1_2048Nu & 0x03000000) >> 24);
-
-	/*  big endian to make 8051 happy */
-	buf[0] = temp3;
-	buf[1] = temp2;
-	buf[2] = temp1;
-	buf[3] = temp0;
-
-	/*  cfoe_NS_2k_coeff1_25_24 */
-	ret = af9005_write_ofdm_register(d, 0xAE00, buf[0]);
-	if (ret)
-		return ret;
-
-	/*  cfoe_NS_2k_coeff1_23_16 */
-	ret = af9005_write_ofdm_register(d, 0xAE01, buf[1]);
-	if (ret)
-		return ret;
-
-	/*  cfoe_NS_2k_coeff1_15_8 */
-	ret = af9005_write_ofdm_register(d, 0xAE02, buf[2]);
-	if (ret)
-		return ret;
-
-	/*  cfoe_NS_2k_coeff1_7_0 */
-	ret = af9005_write_ofdm_register(d, 0xAE03, buf[3]);
-	if (ret)
-		return ret;
-
-	/*
-	 *  write NS_coeff2_2k
-	 */
-
-	temp0 = (u8) ((NS_coeff2_2k & 0x0000003F));
-	temp1 = (u8) ((NS_coeff2_2k & 0x00003FC0) >> 6);
-	temp2 = (u8) ((NS_coeff2_2k & 0x003FC000) >> 14);
-	temp3 = (u8) ((NS_coeff2_2k & 0x01C00000) >> 22);
-
-	/*  big endian to make 8051 happy */
-	buf[0] = temp3;
-	buf[1] = temp2;
-	buf[2] = temp1;
-	buf[3] = temp0;
-
-	ret = af9005_write_ofdm_register(d, 0xAE04, buf[0]);
-	if (ret)
-		return ret;
-
-	ret = af9005_write_ofdm_register(d, 0xAE05, buf[1]);
-	if (ret)
-		return ret;
-
-	ret = af9005_write_ofdm_register(d, 0xAE06, buf[2]);
-	if (ret)
-		return ret;
-
-	ret = af9005_write_ofdm_register(d, 0xAE07, buf[3]);
-	if (ret)
-		return ret;
-
-	/*
-	 *  write NS_coeff1_8191Nu
-	 */
-
-	temp0 = (u8) ((NS_coeff1_8191Nu & 0x000000FF));
-	temp1 = (u8) ((NS_coeff1_8191Nu & 0x0000FF00) >> 8);
-	temp2 = (u8) ((NS_coeff1_8191Nu & 0x00FFC000) >> 16);
-	temp3 = (u8) ((NS_coeff1_8191Nu & 0x03000000) >> 24);
-
-	/*  big endian to make 8051 happy */
-	buf[0] = temp3;
-	buf[1] = temp2;
-	buf[2] = temp1;
-	buf[3] = temp0;
-
-	ret = af9005_write_ofdm_register(d, 0xAE08, buf[0]);
-	if (ret)
-		return ret;
-
-	ret = af9005_write_ofdm_register(d, 0xAE09, buf[1]);
-	if (ret)
-		return ret;
-
-	ret = af9005_write_ofdm_register(d, 0xAE0A, buf[2]);
-	if (ret)
-		return ret;
-
-	ret = af9005_write_ofdm_register(d, 0xAE0B, buf[3]);
-	if (ret)
-		return ret;
-
-	/*
-	 *  write NS_coeff1_8192Nu
-	 */
-
-	temp0 = (u8) (NS_coeff1_8192Nu & 0x000000FF);
-	temp1 = (u8) ((NS_coeff1_8192Nu & 0x0000FF00) >> 8);
-	temp2 = (u8) ((NS_coeff1_8192Nu & 0x00FFC000) >> 16);
-	temp3 = (u8) ((NS_coeff1_8192Nu & 0x03000000) >> 24);
-
-	/*  big endian to make 8051 happy */
-	buf[0] = temp3;
-	buf[1] = temp2;
-	buf[2] = temp1;
-	buf[3] = temp0;
-
-	ret = af9005_write_ofdm_register(d, 0xAE0C, buf[0]);
-	if (ret)
-		return ret;
-
-	ret = af9005_write_ofdm_register(d, 0xAE0D, buf[1]);
-	if (ret)
-		return ret;
-
-	ret = af9005_write_ofdm_register(d, 0xAE0E, buf[2]);
-	if (ret)
-		return ret;
-
-	ret = af9005_write_ofdm_register(d, 0xAE0F, buf[3]);
-	if (ret)
-		return ret;
-
-	/*
-	 *  write NS_coeff1_8193Nu
-	 */
-
-	temp0 = (u8) ((NS_coeff1_8193Nu & 0x000000FF));
-	temp1 = (u8) ((NS_coeff1_8193Nu & 0x0000FF00) >> 8);
-	temp2 = (u8) ((NS_coeff1_8193Nu & 0x00FFC000) >> 16);
-	temp3 = (u8) ((NS_coeff1_8193Nu & 0x03000000) >> 24);
-
-	/*  big endian to make 8051 happy */
-	buf[0] = temp3;
-	buf[1] = temp2;
-	buf[2] = temp1;
-	buf[3] = temp0;
-
-	ret = af9005_write_ofdm_register(d, 0xAE10, buf[0]);
-	if (ret)
-		return ret;
-
-	ret = af9005_write_ofdm_register(d, 0xAE11, buf[1]);
-	if (ret)
-		return ret;
-
-	ret = af9005_write_ofdm_register(d, 0xAE12, buf[2]);
-	if (ret)
-		return ret;
-
-	ret = af9005_write_ofdm_register(d, 0xAE13, buf[3]);
-	if (ret)
-		return ret;
-
-	/*
-	 *  write NS_coeff2_8k
-	 */
-
-	temp0 = (u8) ((NS_coeff2_8k & 0x0000003F));
-	temp1 = (u8) ((NS_coeff2_8k & 0x00003FC0) >> 6);
-	temp2 = (u8) ((NS_coeff2_8k & 0x003FC000) >> 14);
-	temp3 = (u8) ((NS_coeff2_8k & 0x01C00000) >> 22);
-
-	/*  big endian to make 8051 happy */
-	buf[0] = temp3;
-	buf[1] = temp2;
-	buf[2] = temp1;
-	buf[3] = temp0;
-
-	ret = af9005_write_ofdm_register(d, 0xAE14, buf[0]);
-	if (ret)
-		return ret;
-
-	ret = af9005_write_ofdm_register(d, 0xAE15, buf[1]);
-	if (ret)
-		return ret;
-
-	ret = af9005_write_ofdm_register(d, 0xAE16, buf[2]);
-	if (ret)
-		return ret;
-
-	ret = af9005_write_ofdm_register(d, 0xAE17, buf[3]);
-	return ret;
-
-}
-
-static int af9005_fe_select_bw(struct dvb_usb_device *d, u32 bw)
-{
-	u8 temp;
-	switch (bw) {
-	case 6000000:
-		temp = 0;
-		break;
-	case 7000000:
-		temp = 1;
-		break;
-	case 8000000:
-		temp = 2;
-		break;
-	default:
-		err("Invalid bandwidth %d.", bw);
-		return -EINVAL;
-	}
-	return af9005_write_register_bits(d, xd_g_reg_bw, reg_bw_pos,
-					  reg_bw_len, temp);
-}
-
-static int af9005_fe_power(struct dvb_frontend *fe, int on)
-{
-	struct af9005_fe_state *state = fe->demodulator_priv;
-	u8 temp = on;
-	int ret;
-	deb_info("power %s tuner\n", on ? "on" : "off");
-	ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0);
-	return ret;
-}
-
-static struct mt2060_config af9005_mt2060_config = {
-	0xC0
-};
-
-static struct qt1010_config af9005_qt1010_config = {
-	0xC4
-};
-
-static int af9005_fe_init(struct dvb_frontend *fe)
-{
-	struct af9005_fe_state *state = fe->demodulator_priv;
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	int ret, i, scriptlen;
-	u8 temp, temp0 = 0, temp1 = 0, temp2 = 0;
-	u8 buf[2];
-	u16 if1;
-
-	deb_info("in af9005_fe_init\n");
-
-	/* reset */
-	deb_info("reset\n");
-	if ((ret =
-	     af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst_en,
-					4, 1, 0x01)))
-		return ret;
-	if ((ret = af9005_write_ofdm_register(state->d, APO_REG_RESET, 0)))
-		return ret;
-	/* clear ofdm reset */
-	deb_info("clear ofdm reset\n");
-	for (i = 0; i < 150; i++) {
-		if ((ret =
-		     af9005_read_ofdm_register(state->d,
-					       xd_I2C_reg_ofdm_rst, &temp)))
-			return ret;
-		if (temp & (regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos))
-			break;
-		msleep(10);
-	}
-	if (i == 150)
-		return -ETIMEDOUT;
-
-	/*FIXME in the dump
-	   write B200 A9
-	   write xd_g_reg_ofsm_clk 7
-	   read eepr c6 (2)
-	   read eepr c7 (2)
-	   misc ctrl 3 -> 1
-	   read eepr ca (6)
-	   write xd_g_reg_ofsm_clk 0
-	   write B200 a1
-	 */
-	ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa9);
-	if (ret)
-		return ret;
-	ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x07);
-	if (ret)
-		return ret;
-	temp = 0x01;
-	ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0);
-	if (ret)
-		return ret;
-	ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x00);
-	if (ret)
-		return ret;
-	ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa1);
-	if (ret)
-		return ret;
-
-	temp = regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos;
-	if ((ret =
-	     af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst,
-					reg_ofdm_rst_pos, reg_ofdm_rst_len, 1)))
-		return ret;
-	ret = af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst,
-					 reg_ofdm_rst_pos, reg_ofdm_rst_len, 0);
-
-	if (ret)
-		return ret;
-	/* don't know what register aefc is, but this is what the windows driver does */
-	ret = af9005_write_ofdm_register(state->d, 0xaefc, 0);
-	if (ret)
-		return ret;
-
-	/* set stand alone chip */
-	deb_info("set stand alone chip\n");
-	if ((ret =
-	     af9005_write_register_bits(state->d, xd_p_reg_dca_stand_alone,
-					reg_dca_stand_alone_pos,
-					reg_dca_stand_alone_len, 1)))
-		return ret;
-
-	/* set dca upper & lower chip */
-	deb_info("set dca upper & lower chip\n");
-	if ((ret =
-	     af9005_write_register_bits(state->d, xd_p_reg_dca_upper_chip,
-					reg_dca_upper_chip_pos,
-					reg_dca_upper_chip_len, 0)))
-		return ret;
-	if ((ret =
-	     af9005_write_register_bits(state->d, xd_p_reg_dca_lower_chip,
-					reg_dca_lower_chip_pos,
-					reg_dca_lower_chip_len, 0)))
-		return ret;
-
-	/* set 2wire master clock to 0x14 (for 60KHz) */
-	deb_info("set 2wire master clock to 0x14 (for 60KHz)\n");
-	if ((ret =
-	     af9005_write_ofdm_register(state->d, xd_I2C_i2c_m_period, 0x14)))
-		return ret;
-
-	/* clear dca enable chip */
-	deb_info("clear dca enable chip\n");
-	if ((ret =
-	     af9005_write_register_bits(state->d, xd_p_reg_dca_en,
-					reg_dca_en_pos, reg_dca_en_len, 0)))
-		return ret;
-	/* FIXME these are register bits, but I don't know which ones */
-	ret = af9005_write_ofdm_register(state->d, 0xa16c, 1);
-	if (ret)
-		return ret;
-	ret = af9005_write_ofdm_register(state->d, 0xa3c1, 0);
-	if (ret)
-		return ret;
-
-	/* init other parameters: program cfoe and select bandwidth */
-	deb_info("program cfoe\n");
-	ret = af9005_fe_program_cfoe(state->d, 6000000);
-	if (ret)
-		return ret;
-	/* set read-update bit for modulation */
-	deb_info("set read-update bit for modulation\n");
-	if ((ret =
-	     af9005_write_register_bits(state->d, xd_p_reg_feq_read_update,
-					reg_feq_read_update_pos,
-					reg_feq_read_update_len, 1)))
-		return ret;
-
-	/* sample code has a set MPEG TS code here
-	   but sniffing reveals that it doesn't do it */
-
-	/* set read-update bit to 1 for DCA modulation */
-	deb_info("set read-update bit 1 for DCA modulation\n");
-	if ((ret =
-	     af9005_write_register_bits(state->d, xd_p_reg_dca_read_update,
-					reg_dca_read_update_pos,
-					reg_dca_read_update_len, 1)))
-		return ret;
-
-	/* enable fec monitor */
-	deb_info("enable fec monitor\n");
-	if ((ret =
-	     af9005_write_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en,
-					fec_vtb_rsd_mon_en_pos,
-					fec_vtb_rsd_mon_en_len, 1)))
-		return ret;
-
-	/* FIXME should be register bits, I don't know which ones */
-	ret = af9005_write_ofdm_register(state->d, 0xa601, 0);
-
-	/* set api_retrain_never_freeze */
-	deb_info("set api_retrain_never_freeze\n");
-	if ((ret = af9005_write_ofdm_register(state->d, 0xaefb, 0x01)))
-		return ret;
-
-	/* load init script */
-	deb_info("load init script\n");
-	scriptlen = sizeof(script) / sizeof(RegDesc);
-	for (i = 0; i < scriptlen; i++) {
-		if ((ret =
-		     af9005_write_register_bits(state->d, script[i].reg,
-						script[i].pos,
-						script[i].len, script[i].val)))
-			return ret;
-		/* save 3 bytes of original fcw */
-		if (script[i].reg == 0xae18)
-			temp2 = script[i].val;
-		if (script[i].reg == 0xae19)
-			temp1 = script[i].val;
-		if (script[i].reg == 0xae1a)
-			temp0 = script[i].val;
-
-		/* save original unplug threshold */
-		if (script[i].reg == xd_p_reg_unplug_th)
-			state->original_if_unplug_th = script[i].val;
-		if (script[i].reg == xd_p_reg_unplug_rf_gain_th)
-			state->original_rf_unplug_th = script[i].val;
-		if (script[i].reg == xd_p_reg_unplug_dtop_if_gain_th)
-			state->original_dtop_if_unplug_th = script[i].val;
-		if (script[i].reg == xd_p_reg_unplug_dtop_rf_gain_th)
-			state->original_dtop_rf_unplug_th = script[i].val;
-
-	}
-	state->original_fcw =
-	    ((u32) temp2 << 16) + ((u32) temp1 << 8) + (u32) temp0;
-
-
-	/* save original TOPs */
-	deb_info("save original TOPs\n");
-
-	/*  RF TOP */
-	ret =
-	    af9005_read_word_agc(state->d,
-				 xd_p_reg_aagc_rf_top_numerator_9_8,
-				 xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2,
-				 &state->original_rf_top);
-	if (ret)
-		return ret;
-
-	/*  IF TOP */
-	ret =
-	    af9005_read_word_agc(state->d,
-				 xd_p_reg_aagc_if_top_numerator_9_8,
-				 xd_p_reg_aagc_if_top_numerator_7_0, 0, 2,
-				 &state->original_if_top);
-	if (ret)
-		return ret;
-
-	/*  ACI 0 IF TOP */
-	ret =
-	    af9005_read_word_agc(state->d, 0xA60E, 0xA60A, 4, 2,
-				 &state->original_aci0_if_top);
-	if (ret)
-		return ret;
-
-	/*  ACI 1 IF TOP */
-	ret =
-	    af9005_read_word_agc(state->d, 0xA60E, 0xA60B, 6, 2,
-				 &state->original_aci1_if_top);
-	if (ret)
-		return ret;
-
-	/* attach tuner and init */
-	if (fe->ops.tuner_ops.release == NULL) {
-		/* read tuner and board id from eeprom */
-		ret = af9005_read_eeprom(adap->dev, 0xc6, buf, 2);
-		if (ret) {
-			err("Impossible to read EEPROM\n");
-			return ret;
-		}
-		deb_info("Tuner id %d, board id %d\n", buf[0], buf[1]);
-		switch (buf[0]) {
-		case 2:	/* MT2060 */
-			/* read if1 from eeprom */
-			ret = af9005_read_eeprom(adap->dev, 0xc8, buf, 2);
-			if (ret) {
-				err("Impossible to read EEPROM\n");
-				return ret;
-			}
-			if1 = (u16) (buf[0] << 8) + buf[1];
-			if (dvb_attach(mt2060_attach, fe, &adap->dev->i2c_adap,
-					 &af9005_mt2060_config, if1) == NULL) {
-				deb_info("MT2060 attach failed\n");
-				return -ENODEV;
-			}
-			break;
-		case 3:	/* QT1010 */
-		case 9:	/* QT1010B */
-			if (dvb_attach(qt1010_attach, fe, &adap->dev->i2c_adap,
-					&af9005_qt1010_config) ==NULL) {
-				deb_info("QT1010 attach failed\n");
-				return -ENODEV;
-			}
-			break;
-		default:
-			err("Unsupported tuner type %d", buf[0]);
-			return -ENODEV;
-		}
-		ret = fe->ops.tuner_ops.init(fe);
-		if (ret)
-			return ret;
-	}
-
-	deb_info("profit!\n");
-	return 0;
-}
-
-static int af9005_fe_sleep(struct dvb_frontend *fe)
-{
-	return af9005_fe_power(fe, 0);
-}
-
-static int af9005_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
-{
-	struct af9005_fe_state *state = fe->demodulator_priv;
-
-	if (acquire) {
-		state->opened++;
-	} else {
-
-		state->opened--;
-		if (!state->opened)
-			af9005_led_control(state->d, 0);
-	}
-	return 0;
-}
-
-static int af9005_fe_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
-	struct af9005_fe_state *state = fe->demodulator_priv;
-	int ret;
-	u8 temp, temp0, temp1, temp2;
-
-	deb_info("af9005_fe_set_frontend freq %d bw %d\n", fep->frequency,
-		 fep->bandwidth_hz);
-	if (fe->ops.tuner_ops.release == NULL) {
-		err("Tuner not attached");
-		return -ENODEV;
-	}
-
-	deb_info("turn off led\n");
-	/* not in the log */
-	ret = af9005_led_control(state->d, 0);
-	if (ret)
-		return ret;
-	/* not sure about the bits */
-	ret = af9005_write_register_bits(state->d, XD_MP2IF_MISC, 2, 1, 0);
-	if (ret)
-		return ret;
-
-	/* set FCW to default value */
-	deb_info("set FCW to default value\n");
-	temp0 = (u8) (state->original_fcw & 0x000000ff);
-	temp1 = (u8) ((state->original_fcw & 0x0000ff00) >> 8);
-	temp2 = (u8) ((state->original_fcw & 0x00ff0000) >> 16);
-	ret = af9005_write_ofdm_register(state->d, 0xae1a, temp0);
-	if (ret)
-		return ret;
-	ret = af9005_write_ofdm_register(state->d, 0xae19, temp1);
-	if (ret)
-		return ret;
-	ret = af9005_write_ofdm_register(state->d, 0xae18, temp2);
-	if (ret)
-		return ret;
-
-	/* restore original TOPs */
-	deb_info("restore original TOPs\n");
-	ret =
-	    af9005_write_word_agc(state->d,
-				  xd_p_reg_aagc_rf_top_numerator_9_8,
-				  xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2,
-				  state->original_rf_top);
-	if (ret)
-		return ret;
-	ret =
-	    af9005_write_word_agc(state->d,
-				  xd_p_reg_aagc_if_top_numerator_9_8,
-				  xd_p_reg_aagc_if_top_numerator_7_0, 0, 2,
-				  state->original_if_top);
-	if (ret)
-		return ret;
-	ret =
-	    af9005_write_word_agc(state->d, 0xA60E, 0xA60A, 4, 2,
-				  state->original_aci0_if_top);
-	if (ret)
-		return ret;
-	ret =
-	    af9005_write_word_agc(state->d, 0xA60E, 0xA60B, 6, 2,
-				  state->original_aci1_if_top);
-	if (ret)
-		return ret;
-
-	/* select bandwidth */
-	deb_info("select bandwidth");
-	ret = af9005_fe_select_bw(state->d, fep->bandwidth_hz);
-	if (ret)
-		return ret;
-	ret = af9005_fe_program_cfoe(state->d, fep->bandwidth_hz);
-	if (ret)
-		return ret;
-
-	/* clear easy mode flag */
-	deb_info("clear easy mode flag\n");
-	ret = af9005_write_ofdm_register(state->d, 0xaefd, 0);
-	if (ret)
-		return ret;
-
-	/* set unplug threshold to original value */
-	deb_info("set unplug threshold to original value\n");
-	ret =
-	    af9005_write_ofdm_register(state->d, xd_p_reg_unplug_th,
-				       state->original_if_unplug_th);
-	if (ret)
-		return ret;
-	/* set tuner */
-	deb_info("set tuner\n");
-	ret = fe->ops.tuner_ops.set_params(fe);
-	if (ret)
-		return ret;
-
-	/* trigger ofsm */
-	deb_info("trigger ofsm\n");
-	temp = 0;
-	ret = af9005_write_tuner_registers(state->d, 0xffff, &temp, 1);
-	if (ret)
-		return ret;
-
-	/* clear retrain and freeze flag */
-	deb_info("clear retrain and freeze flag\n");
-	ret =
-	    af9005_write_register_bits(state->d,
-				       xd_p_reg_api_retrain_request,
-				       reg_api_retrain_request_pos, 2, 0);
-	if (ret)
-		return ret;
-
-	/* reset pre viterbi and post viterbi registers and statistics */
-	af9005_reset_pre_viterbi(fe);
-	af9005_reset_post_viterbi(fe);
-	state->pre_vit_error_count = 0;
-	state->pre_vit_bit_count = 0;
-	state->ber = 0;
-	state->post_vit_error_count = 0;
-	/* state->unc = 0; commented out since it should be ever increasing */
-	state->abort_count = 0;
-
-	state->next_status_check = jiffies;
-	state->strong = -1;
-
-	return 0;
-}
-
-static int af9005_fe_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
-	struct af9005_fe_state *state = fe->demodulator_priv;
-	int ret;
-	u8 temp;
-
-	/* mode */
-	ret =
-	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
-				      reg_tpsd_const_pos, reg_tpsd_const_len,
-				      &temp);
-	if (ret)
-		return ret;
-	deb_info("===== fe_get_frontend_legacy = =============\n");
-	deb_info("CONSTELLATION ");
-	switch (temp) {
-	case 0:
-		fep->modulation = QPSK;
-		deb_info("QPSK\n");
-		break;
-	case 1:
-		fep->modulation = QAM_16;
-		deb_info("QAM_16\n");
-		break;
-	case 2:
-		fep->modulation = QAM_64;
-		deb_info("QAM_64\n");
-		break;
-	}
-
-	/* tps hierarchy and alpha value */
-	ret =
-	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_hier,
-				      reg_tpsd_hier_pos, reg_tpsd_hier_len,
-				      &temp);
-	if (ret)
-		return ret;
-	deb_info("HIERARCHY ");
-	switch (temp) {
-	case 0:
-		fep->hierarchy = HIERARCHY_NONE;
-		deb_info("NONE\n");
-		break;
-	case 1:
-		fep->hierarchy = HIERARCHY_1;
-		deb_info("1\n");
-		break;
-	case 2:
-		fep->hierarchy = HIERARCHY_2;
-		deb_info("2\n");
-		break;
-	case 3:
-		fep->hierarchy = HIERARCHY_4;
-		deb_info("4\n");
-		break;
-	}
-
-	/*  high/low priority     */
-	ret =
-	    af9005_read_register_bits(state->d, xd_g_reg_dec_pri,
-				      reg_dec_pri_pos, reg_dec_pri_len, &temp);
-	if (ret)
-		return ret;
-	/* if temp is set = high priority */
-	deb_info("PRIORITY %s\n", temp ? "high" : "low");
-
-	/* high coderate */
-	ret =
-	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_hpcr,
-				      reg_tpsd_hpcr_pos, reg_tpsd_hpcr_len,
-				      &temp);
-	if (ret)
-		return ret;
-	deb_info("CODERATE HP ");
-	switch (temp) {
-	case 0:
-		fep->code_rate_HP = FEC_1_2;
-		deb_info("FEC_1_2\n");
-		break;
-	case 1:
-		fep->code_rate_HP = FEC_2_3;
-		deb_info("FEC_2_3\n");
-		break;
-	case 2:
-		fep->code_rate_HP = FEC_3_4;
-		deb_info("FEC_3_4\n");
-		break;
-	case 3:
-		fep->code_rate_HP = FEC_5_6;
-		deb_info("FEC_5_6\n");
-		break;
-	case 4:
-		fep->code_rate_HP = FEC_7_8;
-		deb_info("FEC_7_8\n");
-		break;
-	}
-
-	/* low coderate */
-	ret =
-	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_lpcr,
-				      reg_tpsd_lpcr_pos, reg_tpsd_lpcr_len,
-				      &temp);
-	if (ret)
-		return ret;
-	deb_info("CODERATE LP ");
-	switch (temp) {
-	case 0:
-		fep->code_rate_LP = FEC_1_2;
-		deb_info("FEC_1_2\n");
-		break;
-	case 1:
-		fep->code_rate_LP = FEC_2_3;
-		deb_info("FEC_2_3\n");
-		break;
-	case 2:
-		fep->code_rate_LP = FEC_3_4;
-		deb_info("FEC_3_4\n");
-		break;
-	case 3:
-		fep->code_rate_LP = FEC_5_6;
-		deb_info("FEC_5_6\n");
-		break;
-	case 4:
-		fep->code_rate_LP = FEC_7_8;
-		deb_info("FEC_7_8\n");
-		break;
-	}
-
-	/* guard interval */
-	ret =
-	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_gi,
-				      reg_tpsd_gi_pos, reg_tpsd_gi_len, &temp);
-	if (ret)
-		return ret;
-	deb_info("GUARD INTERVAL ");
-	switch (temp) {
-	case 0:
-		fep->guard_interval = GUARD_INTERVAL_1_32;
-		deb_info("1_32\n");
-		break;
-	case 1:
-		fep->guard_interval = GUARD_INTERVAL_1_16;
-		deb_info("1_16\n");
-		break;
-	case 2:
-		fep->guard_interval = GUARD_INTERVAL_1_8;
-		deb_info("1_8\n");
-		break;
-	case 3:
-		fep->guard_interval = GUARD_INTERVAL_1_4;
-		deb_info("1_4\n");
-		break;
-	}
-
-	/* fft */
-	ret =
-	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod,
-				      reg_tpsd_txmod_pos, reg_tpsd_txmod_len,
-				      &temp);
-	if (ret)
-		return ret;
-	deb_info("TRANSMISSION MODE ");
-	switch (temp) {
-	case 0:
-		fep->transmission_mode = TRANSMISSION_MODE_2K;
-		deb_info("2K\n");
-		break;
-	case 1:
-		fep->transmission_mode = TRANSMISSION_MODE_8K;
-		deb_info("8K\n");
-		break;
-	}
-
-	/* bandwidth      */
-	ret =
-	    af9005_read_register_bits(state->d, xd_g_reg_bw, reg_bw_pos,
-				      reg_bw_len, &temp);
-	deb_info("BANDWIDTH ");
-	switch (temp) {
-	case 0:
-		fep->bandwidth_hz = 6000000;
-		deb_info("6\n");
-		break;
-	case 1:
-		fep->bandwidth_hz = 7000000;
-		deb_info("7\n");
-		break;
-	case 2:
-		fep->bandwidth_hz = 8000000;
-		deb_info("8\n");
-		break;
-	}
-	return 0;
-}
-
-static void af9005_fe_release(struct dvb_frontend *fe)
-{
-	struct af9005_fe_state *state =
-	    (struct af9005_fe_state *)fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops af9005_fe_ops;
-
-struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d)
-{
-	struct af9005_fe_state *state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct af9005_fe_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	deb_info("attaching frontend af9005\n");
-
-	state->d = d;
-	state->opened = 0;
-
-	memcpy(&state->frontend.ops, &af9005_fe_ops,
-	       sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-
-	return &state->frontend;
-      error:
-	return NULL;
-}
-
-static struct dvb_frontend_ops af9005_fe_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		 .name = "AF9005 USB DVB-T",
-		 .frequency_min = 44250000,
-		 .frequency_max = 867250000,
-		 .frequency_stepsize = 250000,
-		 .caps = FE_CAN_INVERSION_AUTO |
-		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
-		 FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
-		 FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER |
-		 FE_CAN_HIERARCHY_AUTO,
-		 },
-
-	.release = af9005_fe_release,
-
-	.init = af9005_fe_init,
-	.sleep = af9005_fe_sleep,
-	.ts_bus_ctrl = af9005_ts_bus_ctrl,
-
-	.set_frontend = af9005_fe_set_frontend,
-	.get_frontend = af9005_fe_get_frontend,
-
-	.read_status = af9005_fe_read_status,
-	.read_ber = af9005_fe_read_ber,
-	.read_signal_strength = af9005_fe_read_signal_strength,
-	.read_snr = af9005_fe_read_snr,
-	.read_ucblocks = af9005_fe_read_unc_blocks,
-};
diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c
deleted file mode 100644
index 7e3961d..0000000
--- a/drivers/media/dvb/dvb-usb/af9005-remote.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/* DVB USB compliant Linux driver for the Afatech 9005
- * USB1.1 DVB-T receiver.
- *
- * Standard remote decode function
- *
- * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
- *
- * Thanks to Afatech who kindly provided information.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "af9005.h"
-/* debug */
-static int dvb_usb_af9005_remote_debug;
-module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644);
-MODULE_PARM_DESC(debug,
-		 "enable (1) or disable (0) debug messages."
-		 DVB_USB_DEBUG_STATUS);
-
-#define deb_decode(args...)   dprintk(dvb_usb_af9005_remote_debug,0x01,args)
-
-struct rc_map_table rc_map_af9005_table[] = {
-
-	{0x01b7, KEY_POWER},
-	{0x01a7, KEY_VOLUMEUP},
-	{0x0187, KEY_CHANNELUP},
-	{0x017f, KEY_MUTE},
-	{0x01bf, KEY_VOLUMEDOWN},
-	{0x013f, KEY_CHANNELDOWN},
-	{0x01df, KEY_1},
-	{0x015f, KEY_2},
-	{0x019f, KEY_3},
-	{0x011f, KEY_4},
-	{0x01ef, KEY_5},
-	{0x016f, KEY_6},
-	{0x01af, KEY_7},
-	{0x0127, KEY_8},
-	{0x0107, KEY_9},
-	{0x01cf, KEY_ZOOM},
-	{0x014f, KEY_0},
-	{0x018f, KEY_GOTO},	/* marked jump on the remote */
-
-	{0x00bd, KEY_POWER},
-	{0x007d, KEY_VOLUMEUP},
-	{0x00fd, KEY_CHANNELUP},
-	{0x009d, KEY_MUTE},
-	{0x005d, KEY_VOLUMEDOWN},
-	{0x00dd, KEY_CHANNELDOWN},
-	{0x00ad, KEY_1},
-	{0x006d, KEY_2},
-	{0x00ed, KEY_3},
-	{0x008d, KEY_4},
-	{0x004d, KEY_5},
-	{0x00cd, KEY_6},
-	{0x00b5, KEY_7},
-	{0x0075, KEY_8},
-	{0x00f5, KEY_9},
-	{0x0095, KEY_ZOOM},
-	{0x0055, KEY_0},
-	{0x00d5, KEY_GOTO},	/* marked jump on the remote */
-};
-
-int rc_map_af9005_table_size = ARRAY_SIZE(rc_map_af9005_table);
-
-static int repeatable_keys[] = {
-	KEY_VOLUMEUP,
-	KEY_VOLUMEDOWN,
-	KEY_CHANNELUP,
-	KEY_CHANNELDOWN
-};
-
-int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
-		     int *state)
-{
-	u16 mark, space;
-	u32 result;
-	u8 cust, dat, invdat;
-	int i;
-
-	if (len >= 6) {
-		mark = (u16) (data[0] << 8) + data[1];
-		space = (u16) (data[2] << 8) + data[3];
-		if (space * 3 < mark) {
-			for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) {
-				if (d->last_event == repeatable_keys[i]) {
-					*state = REMOTE_KEY_REPEAT;
-					*event = d->last_event;
-					deb_decode("repeat key, event %x\n",
-						   *event);
-					return 0;
-				}
-			}
-			deb_decode("repeated key ignored (non repeatable)\n");
-			return 0;
-		} else if (len >= 33 * 4) {	/*32 bits + start code */
-			result = 0;
-			for (i = 4; i < 4 + 32 * 4; i += 4) {
-				result <<= 1;
-				mark = (u16) (data[i] << 8) + data[i + 1];
-				mark >>= 1;
-				space = (u16) (data[i + 2] << 8) + data[i + 3];
-				space >>= 1;
-				if (mark * 2 > space)
-					result += 1;
-			}
-			deb_decode("key pressed, raw value %x\n", result);
-			if ((result & 0xff000000) != 0xfe000000) {
-				deb_decode
-				    ("doesn't start with 0xfe, ignored\n");
-				return 0;
-			}
-			cust = (result >> 16) & 0xff;
-			dat = (result >> 8) & 0xff;
-			invdat = (~result) & 0xff;
-			if (dat != invdat) {
-				deb_decode("code != inverted code\n");
-				return 0;
-			}
-			for (i = 0; i < rc_map_af9005_table_size; i++) {
-				if (rc5_custom(&rc_map_af9005_table[i]) == cust
-				    && rc5_data(&rc_map_af9005_table[i]) == dat) {
-					*event = rc_map_af9005_table[i].keycode;
-					*state = REMOTE_KEY_PRESSED;
-					deb_decode
-					    ("key pressed, event %x\n", *event);
-					return 0;
-				}
-			}
-			deb_decode("not found in table\n");
-		}
-	}
-	return 0;
-}
-
-EXPORT_SYMBOL(rc_map_af9005_table);
-EXPORT_SYMBOL(rc_map_af9005_table_size);
-EXPORT_SYMBOL(af9005_rc_decode);
-
-MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
-MODULE_DESCRIPTION
-    ("Standard remote control decoder for Afatech 9005 DVB-T USB1.1 stick");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9005-script.h b/drivers/media/dvb/dvb-usb/af9005-script.h
deleted file mode 100644
index 4d69045..0000000
--- a/drivers/media/dvb/dvb-usb/af9005-script.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
-File automatically generated by createinit.py using data
-extracted from AF05BDA.sys (windows driver):
-
-dd if=AF05BDA.sys of=initsequence bs=1 skip=88316 count=1110
-python createinit.py > af9005-script.h
-
-*/
-
-typedef struct {
-	u16 reg;
-	u8 pos;
-	u8 len;
-	u8 val;
-} RegDesc;
-
-static RegDesc script[] = {
-	{0xa180, 0x0, 0x8, 0xa},
-	{0xa181, 0x0, 0x8, 0xd7},
-	{0xa182, 0x0, 0x8, 0xa3},
-	{0xa0a0, 0x0, 0x8, 0x0},
-	{0xa0a1, 0x0, 0x5, 0x0},
-	{0xa0a1, 0x5, 0x1, 0x1},
-	{0xa0c0, 0x0, 0x4, 0x1},
-	{0xa20e, 0x4, 0x4, 0xa},
-	{0xa20f, 0x0, 0x8, 0x40},
-	{0xa210, 0x0, 0x8, 0x8},
-	{0xa32a, 0x0, 0x4, 0xa},
-	{0xa32c, 0x0, 0x8, 0x20},
-	{0xa32b, 0x0, 0x8, 0x15},
-	{0xa1a0, 0x1, 0x1, 0x1},
-	{0xa000, 0x0, 0x1, 0x1},
-	{0xa000, 0x1, 0x1, 0x0},
-	{0xa001, 0x1, 0x1, 0x1},
-	{0xa001, 0x0, 0x1, 0x0},
-	{0xa001, 0x5, 0x1, 0x0},
-	{0xa00e, 0x0, 0x5, 0x10},
-	{0xa00f, 0x0, 0x3, 0x4},
-	{0xa00f, 0x3, 0x3, 0x5},
-	{0xa010, 0x0, 0x3, 0x4},
-	{0xa010, 0x3, 0x3, 0x5},
-	{0xa016, 0x4, 0x4, 0x3},
-	{0xa01f, 0x0, 0x6, 0xa},
-	{0xa020, 0x0, 0x6, 0xa},
-	{0xa2bc, 0x0, 0x1, 0x1},
-	{0xa2bc, 0x5, 0x1, 0x1},
-	{0xa015, 0x0, 0x8, 0x50},
-	{0xa016, 0x0, 0x1, 0x0},
-	{0xa02a, 0x0, 0x8, 0x50},
-	{0xa029, 0x0, 0x8, 0x4b},
-	{0xa614, 0x0, 0x8, 0x46},
-	{0xa002, 0x0, 0x5, 0x19},
-	{0xa003, 0x0, 0x5, 0x1a},
-	{0xa004, 0x0, 0x5, 0x19},
-	{0xa005, 0x0, 0x5, 0x1a},
-	{0xa008, 0x0, 0x8, 0x69},
-	{0xa009, 0x0, 0x2, 0x2},
-	{0xae1b, 0x0, 0x8, 0x69},
-	{0xae1c, 0x0, 0x8, 0x2},
-	{0xae1d, 0x0, 0x8, 0x2a},
-	{0xa022, 0x0, 0x8, 0xaa},
-	{0xa006, 0x0, 0x8, 0xc8},
-	{0xa007, 0x0, 0x2, 0x0},
-	{0xa00c, 0x0, 0x8, 0xba},
-	{0xa00d, 0x0, 0x2, 0x2},
-	{0xa608, 0x0, 0x8, 0xba},
-	{0xa60e, 0x0, 0x2, 0x2},
-	{0xa609, 0x0, 0x8, 0x80},
-	{0xa60e, 0x2, 0x2, 0x3},
-	{0xa00a, 0x0, 0x8, 0xb6},
-	{0xa00b, 0x0, 0x2, 0x0},
-	{0xa011, 0x0, 0x8, 0xb9},
-	{0xa012, 0x0, 0x2, 0x0},
-	{0xa013, 0x0, 0x8, 0xbd},
-	{0xa014, 0x0, 0x2, 0x2},
-	{0xa366, 0x0, 0x1, 0x1},
-	{0xa2bc, 0x3, 0x1, 0x0},
-	{0xa2bd, 0x0, 0x8, 0xa},
-	{0xa2be, 0x0, 0x8, 0x14},
-	{0xa2bf, 0x0, 0x8, 0x8},
-	{0xa60a, 0x0, 0x8, 0xbd},
-	{0xa60e, 0x4, 0x2, 0x2},
-	{0xa60b, 0x0, 0x8, 0x86},
-	{0xa60e, 0x6, 0x2, 0x3},
-	{0xa001, 0x2, 0x2, 0x1},
-	{0xa1c7, 0x0, 0x8, 0xf5},
-	{0xa03d, 0x0, 0x8, 0xb1},
-	{0xa616, 0x0, 0x8, 0xff},
-	{0xa617, 0x0, 0x8, 0xad},
-	{0xa618, 0x0, 0x8, 0xad},
-	{0xa61e, 0x3, 0x1, 0x1},
-	{0xae1a, 0x0, 0x8, 0x0},
-	{0xae19, 0x0, 0x8, 0xc8},
-	{0xae18, 0x0, 0x8, 0x61},
-	{0xa140, 0x0, 0x8, 0x0},
-	{0xa141, 0x0, 0x8, 0xc8},
-	{0xa142, 0x0, 0x7, 0x61},
-	{0xa023, 0x0, 0x8, 0xff},
-	{0xa021, 0x0, 0x8, 0xad},
-	{0xa026, 0x0, 0x1, 0x0},
-	{0xa024, 0x0, 0x8, 0xff},
-	{0xa025, 0x0, 0x8, 0xff},
-	{0xa1c8, 0x0, 0x8, 0xf},
-	{0xa2bc, 0x1, 0x1, 0x0},
-	{0xa60c, 0x0, 0x4, 0x5},
-	{0xa60c, 0x4, 0x4, 0x6},
-	{0xa60d, 0x0, 0x8, 0xa},
-	{0xa371, 0x0, 0x1, 0x1},
-	{0xa366, 0x1, 0x3, 0x7},
-	{0xa338, 0x0, 0x8, 0x10},
-	{0xa339, 0x0, 0x6, 0x7},
-	{0xa33a, 0x0, 0x6, 0x1f},
-	{0xa33b, 0x0, 0x8, 0xf6},
-	{0xa33c, 0x3, 0x5, 0x4},
-	{0xa33d, 0x4, 0x4, 0x0},
-	{0xa33d, 0x1, 0x1, 0x1},
-	{0xa33d, 0x2, 0x1, 0x1},
-	{0xa33d, 0x3, 0x1, 0x1},
-	{0xa16d, 0x0, 0x4, 0xf},
-	{0xa161, 0x0, 0x5, 0x5},
-	{0xa162, 0x0, 0x4, 0x5},
-	{0xa165, 0x0, 0x8, 0xff},
-	{0xa166, 0x0, 0x8, 0x9c},
-	{0xa2c3, 0x0, 0x4, 0x5},
-	{0xa61a, 0x0, 0x6, 0xf},
-	{0xb200, 0x0, 0x8, 0xa1},
-	{0xb201, 0x0, 0x8, 0x7},
-	{0xa093, 0x0, 0x1, 0x0},
-	{0xa093, 0x1, 0x5, 0xf},
-	{0xa094, 0x0, 0x8, 0xff},
-	{0xa095, 0x0, 0x8, 0xf},
-	{0xa080, 0x2, 0x5, 0x3},
-	{0xa081, 0x0, 0x4, 0x0},
-	{0xa081, 0x4, 0x4, 0x9},
-	{0xa082, 0x0, 0x5, 0x1f},
-	{0xa08d, 0x0, 0x8, 0x1},
-	{0xa083, 0x0, 0x8, 0x32},
-	{0xa084, 0x0, 0x1, 0x0},
-	{0xa08e, 0x0, 0x8, 0x3},
-	{0xa085, 0x0, 0x8, 0x32},
-	{0xa086, 0x0, 0x3, 0x0},
-	{0xa087, 0x0, 0x8, 0x6e},
-	{0xa088, 0x0, 0x5, 0x15},
-	{0xa089, 0x0, 0x8, 0x0},
-	{0xa08a, 0x0, 0x5, 0x19},
-	{0xa08b, 0x0, 0x8, 0x92},
-	{0xa08c, 0x0, 0x5, 0x1c},
-	{0xa120, 0x0, 0x8, 0x0},
-	{0xa121, 0x0, 0x5, 0x10},
-	{0xa122, 0x0, 0x8, 0x0},
-	{0xa123, 0x0, 0x7, 0x40},
-	{0xa123, 0x7, 0x1, 0x0},
-	{0xa124, 0x0, 0x8, 0x13},
-	{0xa125, 0x0, 0x7, 0x10},
-	{0xa1c0, 0x0, 0x8, 0x0},
-	{0xa1c1, 0x0, 0x5, 0x4},
-	{0xa1c2, 0x0, 0x8, 0x0},
-	{0xa1c3, 0x0, 0x5, 0x10},
-	{0xa1c3, 0x5, 0x3, 0x0},
-	{0xa1c4, 0x0, 0x6, 0x0},
-	{0xa1c5, 0x0, 0x7, 0x10},
-	{0xa100, 0x0, 0x8, 0x0},
-	{0xa101, 0x0, 0x5, 0x10},
-	{0xa102, 0x0, 0x8, 0x0},
-	{0xa103, 0x0, 0x7, 0x40},
-	{0xa103, 0x7, 0x1, 0x0},
-	{0xa104, 0x0, 0x8, 0x18},
-	{0xa105, 0x0, 0x7, 0xa},
-	{0xa106, 0x0, 0x8, 0x20},
-	{0xa107, 0x0, 0x8, 0x40},
-	{0xa108, 0x0, 0x4, 0x0},
-	{0xa38c, 0x0, 0x8, 0xfc},
-	{0xa38d, 0x0, 0x8, 0x0},
-	{0xa38e, 0x0, 0x8, 0x7e},
-	{0xa38f, 0x0, 0x8, 0x0},
-	{0xa390, 0x0, 0x8, 0x2f},
-	{0xa60f, 0x5, 0x1, 0x1},
-	{0xa170, 0x0, 0x8, 0xdc},
-	{0xa171, 0x0, 0x2, 0x0},
-	{0xa2ae, 0x0, 0x1, 0x1},
-	{0xa2ae, 0x1, 0x1, 0x1},
-	{0xa392, 0x0, 0x1, 0x1},
-	{0xa391, 0x2, 0x1, 0x0},
-	{0xabc1, 0x0, 0x8, 0xff},
-	{0xabc2, 0x0, 0x8, 0x0},
-	{0xabc8, 0x0, 0x8, 0x8},
-	{0xabca, 0x0, 0x8, 0x10},
-	{0xabcb, 0x0, 0x1, 0x0},
-	{0xabc3, 0x5, 0x3, 0x7},
-	{0xabc0, 0x6, 0x1, 0x0},
-	{0xabc0, 0x4, 0x2, 0x0},
-	{0xa344, 0x4, 0x4, 0x1},
-	{0xabc0, 0x7, 0x1, 0x1},
-	{0xabc0, 0x2, 0x1, 0x1},
-	{0xa345, 0x0, 0x8, 0x66},
-	{0xa346, 0x0, 0x8, 0x66},
-	{0xa347, 0x0, 0x4, 0x0},
-	{0xa343, 0x0, 0x4, 0xa},
-	{0xa347, 0x4, 0x4, 0x2},
-	{0xa348, 0x0, 0x4, 0xc},
-	{0xa348, 0x4, 0x4, 0x7},
-	{0xa349, 0x0, 0x6, 0x2},
-};
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
deleted file mode 100644
index af176b6..0000000
--- a/drivers/media/dvb/dvb-usb/af9005.c
+++ /dev/null
@@ -1,1117 +0,0 @@
-/* DVB USB compliant Linux driver for the Afatech 9005
- * USB1.1 DVB-T receiver.
- *
- * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
- *
- * Thanks to Afatech who kindly provided information.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "af9005.h"
-
-/* debug */
-int dvb_usb_af9005_debug;
-module_param_named(debug, dvb_usb_af9005_debug, int, 0644);
-MODULE_PARM_DESC(debug,
-		 "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))."
-		 DVB_USB_DEBUG_STATUS);
-/* enable obnoxious led */
-bool dvb_usb_af9005_led = 1;
-module_param_named(led, dvb_usb_af9005_led, bool, 0644);
-MODULE_PARM_DESC(led, "enable led (default: 1).");
-
-/* eeprom dump */
-static int dvb_usb_af9005_dump_eeprom;
-module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0);
-MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom.");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-/* remote control decoder */
-static int (*rc_decode) (struct dvb_usb_device *d, u8 *data, int len,
-		u32 *event, int *state);
-static void *rc_keys;
-static int *rc_keys_size;
-
-u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
-
-struct af9005_device_state {
-	u8 sequence;
-	int led_state;
-};
-
-static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
-			      int readwrite, int type, u8 * values, int len)
-{
-	struct af9005_device_state *st = d->priv;
-	u8 obuf[16] = { 0 };
-	u8 ibuf[17] = { 0 };
-	u8 command;
-	int i;
-	int ret;
-
-	if (len < 1) {
-		err("generic read/write, less than 1 byte. Makes no sense.");
-		return -EINVAL;
-	}
-	if (len > 8) {
-		err("generic read/write, more than 8 bytes. Not supported.");
-		return -EINVAL;
-	}
-
-	obuf[0] = 14;		/* rest of buffer length low */
-	obuf[1] = 0;		/* rest of buffer length high */
-
-	obuf[2] = AF9005_REGISTER_RW;	/* register operation */
-	obuf[3] = 12;		/* rest of buffer length */
-
-	obuf[4] = st->sequence++;	/* sequence number */
-
-	obuf[5] = (u8) (reg >> 8);	/* register address */
-	obuf[6] = (u8) (reg & 0xff);
-
-	if (type == AF9005_OFDM_REG) {
-		command = AF9005_CMD_OFDM_REG;
-	} else {
-		command = AF9005_CMD_TUNER;
-	}
-
-	if (len > 1)
-		command |=
-		    AF9005_CMD_BURST | AF9005_CMD_AUTOINC | (len - 1) << 3;
-	command |= readwrite;
-	if (readwrite == AF9005_CMD_WRITE)
-		for (i = 0; i < len; i++)
-			obuf[8 + i] = values[i];
-	else if (type == AF9005_TUNER_REG)
-		/* read command for tuner, the first byte contains the i2c address */
-		obuf[8] = values[0];
-	obuf[7] = command;
-
-	ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
-	if (ret)
-		return ret;
-
-	/* sanity check */
-	if (ibuf[2] != AF9005_REGISTER_RW_ACK) {
-		err("generic read/write, wrong reply code.");
-		return -EIO;
-	}
-	if (ibuf[3] != 0x0d) {
-		err("generic read/write, wrong length in reply.");
-		return -EIO;
-	}
-	if (ibuf[4] != obuf[4]) {
-		err("generic read/write, wrong sequence in reply.");
-		return -EIO;
-	}
-	/*
-	   Windows driver doesn't check these fields, in fact sometimes
-	   the register in the reply is different that what has been sent
-
-	   if (ibuf[5] != obuf[5] || ibuf[6] != obuf[6]) {
-	   err("generic read/write, wrong register in reply.");
-	   return -EIO;
-	   }
-	   if (ibuf[7] != command) {
-	   err("generic read/write wrong command in reply.");
-	   return -EIO;
-	   }
-	 */
-	if (ibuf[16] != 0x01) {
-		err("generic read/write wrong status code in reply.");
-		return -EIO;
-	}
-	if (readwrite == AF9005_CMD_READ)
-		for (i = 0; i < len; i++)
-			values[i] = ibuf[8 + i];
-
-	return 0;
-
-}
-
-int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 * value)
-{
-	int ret;
-	deb_reg("read register %x ", reg);
-	ret = af9005_generic_read_write(d, reg,
-					AF9005_CMD_READ, AF9005_OFDM_REG,
-					value, 1);
-	if (ret)
-		deb_reg("failed\n");
-	else
-		deb_reg("value %x\n", *value);
-	return ret;
-}
-
-int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,
-			       u8 * values, int len)
-{
-	int ret;
-	deb_reg("read %d registers %x ", len, reg);
-	ret = af9005_generic_read_write(d, reg,
-					AF9005_CMD_READ, AF9005_OFDM_REG,
-					values, len);
-	if (ret)
-		deb_reg("failed\n");
-	else
-		debug_dump(values, len, deb_reg);
-	return ret;
-}
-
-int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 value)
-{
-	int ret;
-	u8 temp = value;
-	deb_reg("write register %x value %x ", reg, value);
-	ret = af9005_generic_read_write(d, reg,
-					AF9005_CMD_WRITE, AF9005_OFDM_REG,
-					&temp, 1);
-	if (ret)
-		deb_reg("failed\n");
-	else
-		deb_reg("ok\n");
-	return ret;
-}
-
-int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,
-				u8 * values, int len)
-{
-	int ret;
-	deb_reg("write %d registers %x values ", len, reg);
-	debug_dump(values, len, deb_reg);
-
-	ret = af9005_generic_read_write(d, reg,
-					AF9005_CMD_WRITE, AF9005_OFDM_REG,
-					values, len);
-	if (ret)
-		deb_reg("failed\n");
-	else
-		deb_reg("ok\n");
-	return ret;
-}
-
-int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
-			      u8 len, u8 * value)
-{
-	u8 temp;
-	int ret;
-	deb_reg("read bits %x %x %x", reg, pos, len);
-	ret = af9005_read_ofdm_register(d, reg, &temp);
-	if (ret) {
-		deb_reg(" failed\n");
-		return ret;
-	}
-	*value = (temp >> pos) & regmask[len - 1];
-	deb_reg(" value %x\n", *value);
-	return 0;
-
-}
-
-int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
-			       u8 len, u8 value)
-{
-	u8 temp, mask;
-	int ret;
-	deb_reg("write bits %x %x %x value %x\n", reg, pos, len, value);
-	if (pos == 0 && len == 8)
-		return af9005_write_ofdm_register(d, reg, value);
-	ret = af9005_read_ofdm_register(d, reg, &temp);
-	if (ret)
-		return ret;
-	mask = regmask[len - 1] << pos;
-	temp = (temp & ~mask) | ((value << pos) & mask);
-	return af9005_write_ofdm_register(d, reg, temp);
-
-}
-
-static int af9005_usb_read_tuner_registers(struct dvb_usb_device *d,
-					   u16 reg, u8 * values, int len)
-{
-	return af9005_generic_read_write(d, reg,
-					 AF9005_CMD_READ, AF9005_TUNER_REG,
-					 values, len);
-}
-
-static int af9005_usb_write_tuner_registers(struct dvb_usb_device *d,
-					    u16 reg, u8 * values, int len)
-{
-	return af9005_generic_read_write(d, reg,
-					 AF9005_CMD_WRITE,
-					 AF9005_TUNER_REG, values, len);
-}
-
-int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,
-				 u8 * values, int len)
-{
-	/* don't let the name of this function mislead you: it's just used
-	   as an interface from the firmware to the i2c bus. The actual
-	   i2c addresses are contained in the data */
-	int ret, i, done = 0, fail = 0;
-	u8 temp;
-	ret = af9005_usb_write_tuner_registers(d, reg, values, len);
-	if (ret)
-		return ret;
-	if (reg != 0xffff) {
-		/* check if write done (0xa40d bit 1) or fail (0xa40d bit 2) */
-		for (i = 0; i < 200; i++) {
-			ret =
-			    af9005_read_ofdm_register(d,
-						      xd_I2C_i2c_m_status_wdat_done,
-						      &temp);
-			if (ret)
-				return ret;
-			done = temp & (regmask[i2c_m_status_wdat_done_len - 1]
-				       << i2c_m_status_wdat_done_pos);
-			if (done)
-				break;
-			fail = temp & (regmask[i2c_m_status_wdat_fail_len - 1]
-				       << i2c_m_status_wdat_fail_pos);
-			if (fail)
-				break;
-			msleep(50);
-		}
-		if (i == 200)
-			return -ETIMEDOUT;
-		if (fail) {
-			/* clear write fail bit */
-			af9005_write_register_bits(d,
-						   xd_I2C_i2c_m_status_wdat_fail,
-						   i2c_m_status_wdat_fail_pos,
-						   i2c_m_status_wdat_fail_len,
-						   1);
-			return -EIO;
-		}
-		/* clear write done bit */
-		ret =
-		    af9005_write_register_bits(d,
-					       xd_I2C_i2c_m_status_wdat_fail,
-					       i2c_m_status_wdat_done_pos,
-					       i2c_m_status_wdat_done_len, 1);
-		if (ret)
-			return ret;
-	}
-	return 0;
-}
-
-int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, u8 addr,
-				u8 * values, int len)
-{
-	/* don't let the name of this function mislead you: it's just used
-	   as an interface from the firmware to the i2c bus. The actual
-	   i2c addresses are contained in the data */
-	int ret, i;
-	u8 temp, buf[2];
-
-	buf[0] = addr;		/* tuner i2c address */
-	buf[1] = values[0];	/* tuner register */
-
-	values[0] = addr + 0x01;	/* i2c read address */
-
-	if (reg == APO_REG_I2C_RW_SILICON_TUNER) {
-		/* write tuner i2c address to tuner, 0c00c0 undocumented, found by sniffing */
-		ret = af9005_write_tuner_registers(d, 0x00c0, buf, 2);
-		if (ret)
-			return ret;
-	}
-
-	/* send read command to ofsm */
-	ret = af9005_usb_read_tuner_registers(d, reg, values, 1);
-	if (ret)
-		return ret;
-
-	/* check if read done */
-	for (i = 0; i < 200; i++) {
-		ret = af9005_read_ofdm_register(d, 0xa408, &temp);
-		if (ret)
-			return ret;
-		if (temp & 0x01)
-			break;
-		msleep(50);
-	}
-	if (i == 200)
-		return -ETIMEDOUT;
-
-	/* clear read done bit (by writing 1) */
-	ret = af9005_write_ofdm_register(d, xd_I2C_i2c_m_data8, 1);
-	if (ret)
-		return ret;
-
-	/* get read data (available from 0xa400) */
-	for (i = 0; i < len; i++) {
-		ret = af9005_read_ofdm_register(d, 0xa400 + i, &temp);
-		if (ret)
-			return ret;
-		values[i] = temp;
-	}
-	return 0;
-}
-
-static int af9005_i2c_write(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
-			    u8 * data, int len)
-{
-	int ret, i;
-	u8 buf[3];
-	deb_i2c("i2c_write i2caddr %x, reg %x, len %d data ", i2caddr,
-		reg, len);
-	debug_dump(data, len, deb_i2c);
-
-	for (i = 0; i < len; i++) {
-		buf[0] = i2caddr;
-		buf[1] = reg + (u8) i;
-		buf[2] = data[i];
-		ret =
-		    af9005_write_tuner_registers(d,
-						 APO_REG_I2C_RW_SILICON_TUNER,
-						 buf, 3);
-		if (ret) {
-			deb_i2c("i2c_write failed\n");
-			return ret;
-		}
-	}
-	deb_i2c("i2c_write ok\n");
-	return 0;
-}
-
-static int af9005_i2c_read(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
-			   u8 * data, int len)
-{
-	int ret, i;
-	u8 temp;
-	deb_i2c("i2c_read i2caddr %x, reg %x, len %d\n ", i2caddr, reg, len);
-	for (i = 0; i < len; i++) {
-		temp = reg + i;
-		ret =
-		    af9005_read_tuner_registers(d,
-						APO_REG_I2C_RW_SILICON_TUNER,
-						i2caddr, &temp, 1);
-		if (ret) {
-			deb_i2c("i2c_read failed\n");
-			return ret;
-		}
-		data[i] = temp;
-	}
-	deb_i2c("i2c data read: ");
-	debug_dump(data, len, deb_i2c);
-	return 0;
-}
-
-static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-			   int num)
-{
-	/* only implements what the mt2060 module does, don't know how
-	   to make it really generic */
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int ret;
-	u8 reg, addr;
-	u8 *value;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	if (num > 2)
-		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
-
-	if (num == 2) {
-		/* reads a single register */
-		reg = *msg[0].buf;
-		addr = msg[0].addr;
-		value = msg[1].buf;
-		ret = af9005_i2c_read(d, addr, reg, value, 1);
-		if (ret == 0)
-			ret = 2;
-	} else {
-		/* write one or more registers */
-		reg = msg[0].buf[0];
-		addr = msg[0].addr;
-		value = &msg[0].buf[1];
-		ret = af9005_i2c_write(d, addr, reg, value, msg[0].len - 1);
-		if (ret == 0)
-			ret = 1;
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return ret;
-}
-
-static u32 af9005_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm af9005_i2c_algo = {
-	.master_xfer = af9005_i2c_xfer,
-	.functionality = af9005_i2c_func,
-};
-
-int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,
-			int wlen, u8 * rbuf, int rlen)
-{
-	struct af9005_device_state *st = d->priv;
-
-	int ret, i, packet_len;
-	u8 buf[64];
-	u8 ibuf[64];
-
-	if (wlen < 0) {
-		err("send command, wlen less than 0 bytes. Makes no sense.");
-		return -EINVAL;
-	}
-	if (wlen > 54) {
-		err("send command, wlen more than 54 bytes. Not supported.");
-		return -EINVAL;
-	}
-	if (rlen > 54) {
-		err("send command, rlen more than 54 bytes. Not supported.");
-		return -EINVAL;
-	}
-	packet_len = wlen + 5;
-	buf[0] = (u8) (packet_len & 0xff);
-	buf[1] = (u8) ((packet_len & 0xff00) >> 8);
-
-	buf[2] = 0x26;		/* packet type */
-	buf[3] = wlen + 3;
-	buf[4] = st->sequence++;
-	buf[5] = command;
-	buf[6] = wlen;
-	for (i = 0; i < wlen; i++)
-		buf[7 + i] = wbuf[i];
-	ret = dvb_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);
-	if (ret)
-		return ret;
-	if (ibuf[2] != 0x27) {
-		err("send command, wrong reply code.");
-		return -EIO;
-	}
-	if (ibuf[4] != buf[4]) {
-		err("send command, wrong sequence in reply.");
-		return -EIO;
-	}
-	if (ibuf[5] != 0x01) {
-		err("send command, wrong status code in reply.");
-		return -EIO;
-	}
-	if (ibuf[6] != rlen) {
-		err("send command, invalid data length in reply.");
-		return -EIO;
-	}
-	for (i = 0; i < rlen; i++)
-		rbuf[i] = ibuf[i + 7];
-	return 0;
-}
-
-int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values,
-		       int len)
-{
-	struct af9005_device_state *st = d->priv;
-	u8 obuf[16], ibuf[14];
-	int ret, i;
-
-	memset(obuf, 0, sizeof(obuf));
-	memset(ibuf, 0, sizeof(ibuf));
-
-	obuf[0] = 14;		/* length of rest of packet low */
-	obuf[1] = 0;		/* length of rest of packer high */
-
-	obuf[2] = 0x2a;		/* read/write eeprom */
-
-	obuf[3] = 12;		/* size */
-
-	obuf[4] = st->sequence++;
-
-	obuf[5] = 0;		/* read */
-
-	obuf[6] = len;
-	obuf[7] = address;
-	ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
-	if (ret)
-		return ret;
-	if (ibuf[2] != 0x2b) {
-		err("Read eeprom, invalid reply code");
-		return -EIO;
-	}
-	if (ibuf[3] != 10) {
-		err("Read eeprom, invalid reply length");
-		return -EIO;
-	}
-	if (ibuf[4] != obuf[4]) {
-		err("Read eeprom, wrong sequence in reply ");
-		return -EIO;
-	}
-	if (ibuf[5] != 1) {
-		err("Read eeprom, wrong status in reply ");
-		return -EIO;
-	}
-	for (i = 0; i < len; i++) {
-		values[i] = ibuf[6 + i];
-	}
-	return 0;
-}
-
-static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply)
-{
-	u8 buf[FW_BULKOUT_SIZE + 2];
-	u16 checksum;
-	int act_len, i, ret;
-	memset(buf, 0, sizeof(buf));
-	buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
-	buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
-	switch (type) {
-	case FW_CONFIG:
-		buf[2] = 0x11;
-		buf[3] = 0x04;
-		buf[4] = 0x00;	/* sequence number, original driver doesn't increment it here */
-		buf[5] = 0x03;
-		checksum = buf[4] + buf[5];
-		buf[6] = (u8) ((checksum >> 8) & 0xff);
-		buf[7] = (u8) (checksum & 0xff);
-		break;
-	case FW_CONFIRM:
-		buf[2] = 0x11;
-		buf[3] = 0x04;
-		buf[4] = 0x00;	/* sequence number, original driver doesn't increment it here */
-		buf[5] = 0x01;
-		checksum = buf[4] + buf[5];
-		buf[6] = (u8) ((checksum >> 8) & 0xff);
-		buf[7] = (u8) (checksum & 0xff);
-		break;
-	case FW_BOOT:
-		buf[2] = 0x10;
-		buf[3] = 0x08;
-		buf[4] = 0x00;	/* sequence number, original driver doesn't increment it here */
-		buf[5] = 0x97;
-		buf[6] = 0xaa;
-		buf[7] = 0x55;
-		buf[8] = 0xa5;
-		buf[9] = 0x5a;
-		checksum = 0;
-		for (i = 4; i <= 9; i++)
-			checksum += buf[i];
-		buf[10] = (u8) ((checksum >> 8) & 0xff);
-		buf[11] = (u8) (checksum & 0xff);
-		break;
-	default:
-		err("boot packet invalid boot packet type");
-		return -EINVAL;
-	}
-	deb_fw(">>> ");
-	debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
-
-	ret = usb_bulk_msg(udev,
-			   usb_sndbulkpipe(udev, 0x02),
-			   buf, FW_BULKOUT_SIZE + 2, &act_len, 2000);
-	if (ret)
-		err("boot packet bulk message failed: %d (%d/%d)", ret,
-		    FW_BULKOUT_SIZE + 2, act_len);
-	else
-		ret = act_len != FW_BULKOUT_SIZE + 2 ? -1 : 0;
-	if (ret)
-		return ret;
-	memset(buf, 0, 9);
-	ret = usb_bulk_msg(udev,
-			   usb_rcvbulkpipe(udev, 0x01), buf, 9, &act_len, 2000);
-	if (ret) {
-		err("boot packet recv bulk message failed: %d", ret);
-		return ret;
-	}
-	deb_fw("<<< ");
-	debug_dump(buf, act_len, deb_fw);
-	checksum = 0;
-	switch (type) {
-	case FW_CONFIG:
-		if (buf[2] != 0x11) {
-			err("boot bad config header.");
-			return -EIO;
-		}
-		if (buf[3] != 0x05) {
-			err("boot bad config size.");
-			return -EIO;
-		}
-		if (buf[4] != 0x00) {
-			err("boot bad config sequence.");
-			return -EIO;
-		}
-		if (buf[5] != 0x04) {
-			err("boot bad config subtype.");
-			return -EIO;
-		}
-		for (i = 4; i <= 6; i++)
-			checksum += buf[i];
-		if (buf[7] * 256 + buf[8] != checksum) {
-			err("boot bad config checksum.");
-			return -EIO;
-		}
-		*reply = buf[6];
-		break;
-	case FW_CONFIRM:
-		if (buf[2] != 0x11) {
-			err("boot bad confirm header.");
-			return -EIO;
-		}
-		if (buf[3] != 0x05) {
-			err("boot bad confirm size.");
-			return -EIO;
-		}
-		if (buf[4] != 0x00) {
-			err("boot bad confirm sequence.");
-			return -EIO;
-		}
-		if (buf[5] != 0x02) {
-			err("boot bad confirm subtype.");
-			return -EIO;
-		}
-		for (i = 4; i <= 6; i++)
-			checksum += buf[i];
-		if (buf[7] * 256 + buf[8] != checksum) {
-			err("boot bad confirm checksum.");
-			return -EIO;
-		}
-		*reply = buf[6];
-		break;
-	case FW_BOOT:
-		if (buf[2] != 0x10) {
-			err("boot bad boot header.");
-			return -EIO;
-		}
-		if (buf[3] != 0x05) {
-			err("boot bad boot size.");
-			return -EIO;
-		}
-		if (buf[4] != 0x00) {
-			err("boot bad boot sequence.");
-			return -EIO;
-		}
-		if (buf[5] != 0x01) {
-			err("boot bad boot pattern 01.");
-			return -EIO;
-		}
-		if (buf[6] != 0x10) {
-			err("boot bad boot pattern 10.");
-			return -EIO;
-		}
-		for (i = 4; i <= 6; i++)
-			checksum += buf[i];
-		if (buf[7] * 256 + buf[8] != checksum) {
-			err("boot bad boot checksum.");
-			return -EIO;
-		}
-		break;
-
-	}
-
-	return 0;
-}
-
-static int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw)
-{
-	int i, packets, ret, act_len;
-
-	u8 buf[FW_BULKOUT_SIZE + 2];
-	u8 reply;
-
-	ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
-	if (ret)
-		return ret;
-	if (reply != 0x01) {
-		err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply);
-		return -EIO;
-	}
-	packets = fw->size / FW_BULKOUT_SIZE;
-	buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
-	buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
-	for (i = 0; i < packets; i++) {
-		memcpy(&buf[2], fw->data + i * FW_BULKOUT_SIZE,
-		       FW_BULKOUT_SIZE);
-		deb_fw(">>> ");
-		debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
-		ret = usb_bulk_msg(udev,
-				   usb_sndbulkpipe(udev, 0x02),
-				   buf, FW_BULKOUT_SIZE + 2, &act_len, 1000);
-		if (ret) {
-			err("firmware download failed at packet %d with code %d", i, ret);
-			return ret;
-		}
-	}
-	ret = af9005_boot_packet(udev, FW_CONFIRM, &reply);
-	if (ret)
-		return ret;
-	if (reply != (u8) (packets & 0xff)) {
-		err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply);
-		return -EIO;
-	}
-	ret = af9005_boot_packet(udev, FW_BOOT, &reply);
-	if (ret)
-		return ret;
-	ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
-	if (ret)
-		return ret;
-	if (reply != 0x02) {
-		err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply);
-		return -EIO;
-	}
-
-	return 0;
-
-}
-
-int af9005_led_control(struct dvb_usb_device *d, int onoff)
-{
-	struct af9005_device_state *st = d->priv;
-	int temp, ret;
-
-	if (onoff && dvb_usb_af9005_led)
-		temp = 1;
-	else
-		temp = 0;
-	if (st->led_state != temp) {
-		ret =
-		    af9005_write_register_bits(d, xd_p_reg_top_locken1,
-					       reg_top_locken1_pos,
-					       reg_top_locken1_len, temp);
-		if (ret)
-			return ret;
-		ret =
-		    af9005_write_register_bits(d, xd_p_reg_top_lock1,
-					       reg_top_lock1_pos,
-					       reg_top_lock1_len, temp);
-		if (ret)
-			return ret;
-		st->led_state = temp;
-	}
-	return 0;
-}
-
-static int af9005_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	u8 buf[8];
-	int i;
-
-	/* without these calls the first commands after downloading
-	   the firmware fail. I put these calls here to simulate
-	   what it is done in dvb-usb-init.c.
-	 */
-	struct usb_device *udev = adap->dev->udev;
-	usb_clear_halt(udev, usb_sndbulkpipe(udev, 2));
-	usb_clear_halt(udev, usb_rcvbulkpipe(udev, 1));
-	if (dvb_usb_af9005_dump_eeprom) {
-		printk("EEPROM DUMP\n");
-		for (i = 0; i < 255; i += 8) {
-			af9005_read_eeprom(adap->dev, i, buf, 8);
-			printk("ADDR %x ", i);
-			debug_dump(buf, 8, printk);
-		}
-	}
-	adap->fe_adap[0].fe = af9005_fe_attach(adap->dev);
-	return 0;
-}
-
-static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state)
-{
-	struct af9005_device_state *st = d->priv;
-	int ret, len;
-
-	u8 obuf[5];
-	u8 ibuf[256];
-
-	*state = REMOTE_NO_KEY_PRESSED;
-	if (rc_decode == NULL) {
-		/* it shouldn't never come here */
-		return 0;
-	}
-	/* deb_info("rc_query\n"); */
-	obuf[0] = 3;		/* rest of packet length low */
-	obuf[1] = 0;		/* rest of packet lentgh high */
-	obuf[2] = 0x40;		/* read remote */
-	obuf[3] = 1;		/* rest of packet length */
-	obuf[4] = st->sequence++;	/* sequence number */
-	ret = dvb_usb_generic_rw(d, obuf, 5, ibuf, 256, 0);
-	if (ret) {
-		err("rc query failed");
-		return ret;
-	}
-	if (ibuf[2] != 0x41) {
-		err("rc query bad header.");
-		return -EIO;
-	}
-	if (ibuf[4] != obuf[4]) {
-		err("rc query bad sequence.");
-		return -EIO;
-	}
-	len = ibuf[5];
-	if (len > 246) {
-		err("rc query invalid length");
-		return -EIO;
-	}
-	if (len > 0) {
-		deb_rc("rc data (%d) ", len);
-		debug_dump((ibuf + 6), len, deb_rc);
-		ret = rc_decode(d, &ibuf[6], len, event, state);
-		if (ret) {
-			err("rc_decode failed");
-			return ret;
-		} else {
-			deb_rc("rc_decode state %x event %x\n", *state, *event);
-			if (*state == REMOTE_KEY_REPEAT)
-				*event = d->last_event;
-		}
-	}
-	return 0;
-}
-
-static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-
-	return 0;
-}
-
-static int af9005_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
-{
-	int ret;
-	deb_info("pid filter control  onoff %d\n", onoff);
-	if (onoff) {
-		ret =
-		    af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
-		if (ret)
-			return ret;
-		ret =
-		    af9005_write_register_bits(adap->dev,
-					       XD_MP2IF_DMX_CTRL, 1, 1, 1);
-		if (ret)
-			return ret;
-		ret =
-		    af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
-	} else
-		ret =
-		    af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 0);
-	if (ret)
-		return ret;
-	deb_info("pid filter control ok\n");
-	return 0;
-}
-
-static int af9005_pid_filter(struct dvb_usb_adapter *adap, int index,
-			     u16 pid, int onoff)
-{
-	u8 cmd = index & 0x1f;
-	int ret;
-	deb_info("set pid filter, index %d, pid %x, onoff %d\n", index,
-		 pid, onoff);
-	if (onoff) {
-		/* cannot use it as pid_filter_ctrl since it has to be done
-		   before setting the first pid */
-		if (adap->feedcount == 1) {
-			deb_info("first pid set, enable pid table\n");
-			ret = af9005_pid_filter_control(adap, onoff);
-			if (ret)
-				return ret;
-		}
-		ret =
-		    af9005_write_ofdm_register(adap->dev,
-					       XD_MP2IF_PID_DATA_L,
-					       (u8) (pid & 0xff));
-		if (ret)
-			return ret;
-		ret =
-		    af9005_write_ofdm_register(adap->dev,
-					       XD_MP2IF_PID_DATA_H,
-					       (u8) (pid >> 8));
-		if (ret)
-			return ret;
-		cmd |= 0x20 | 0x40;
-	} else {
-		if (adap->feedcount == 0) {
-			deb_info("last pid unset, disable pid table\n");
-			ret = af9005_pid_filter_control(adap, onoff);
-			if (ret)
-				return ret;
-		}
-	}
-	ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_IDX, cmd);
-	if (ret)
-		return ret;
-	deb_info("set pid ok\n");
-	return 0;
-}
-
-static int af9005_identify_state(struct usb_device *udev,
-				 struct dvb_usb_device_properties *props,
-				 struct dvb_usb_device_description **desc,
-				 int *cold)
-{
-	int ret;
-	u8 reply;
-	ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
-	if (ret)
-		return ret;
-	deb_info("result of FW_CONFIG in identify state %d\n", reply);
-	if (reply == 0x01)
-		*cold = 1;
-	else if (reply == 0x02)
-		*cold = 0;
-	else
-		return -EIO;
-	deb_info("Identify state cold = %d\n", *cold);
-	return 0;
-}
-
-static struct dvb_usb_device_properties af9005_properties;
-
-static int af9005_usb_probe(struct usb_interface *intf,
-			    const struct usb_device_id *id)
-{
-	return dvb_usb_device_init(intf, &af9005_properties,
-				   THIS_MODULE, NULL, adapter_nr);
-}
-
-enum af9005_usb_table_entry {
-	AFATECH_AF9005,
-	TERRATEC_AF9005,
-	ANSONIC_AF9005,
-};
-
-static struct usb_device_id af9005_usb_table[] = {
-	[AFATECH_AF9005] = {USB_DEVICE(USB_VID_AFATECH,
-				USB_PID_AFATECH_AF9005)},
-	[TERRATEC_AF9005] = {USB_DEVICE(USB_VID_TERRATEC,
-				USB_PID_TERRATEC_CINERGY_T_USB_XE)},
-	[ANSONIC_AF9005] = {USB_DEVICE(USB_VID_ANSONIC,
-				USB_PID_ANSONIC_DVBT_USB)},
-	{ }
-};
-
-MODULE_DEVICE_TABLE(usb, af9005_usb_table);
-
-static struct dvb_usb_device_properties af9005_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = DEVICE_SPECIFIC,
-	.firmware = "af9005.fw",
-	.download_firmware = af9005_download_firmware,
-	.no_reconnect = 1,
-
-	.size_of_priv = sizeof(struct af9005_device_state),
-
-	.num_adapters = 1,
-	.adapter = {
-		    {
-		    .num_frontends = 1,
-		    .fe = {{
-		     .caps =
-		     DVB_USB_ADAP_HAS_PID_FILTER |
-		     DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-		     .pid_filter_count = 32,
-		     .pid_filter = af9005_pid_filter,
-		     /* .pid_filter_ctrl = af9005_pid_filter_control, */
-		     .frontend_attach = af9005_frontend_attach,
-		     /* .tuner_attach     = af9005_tuner_attach, */
-		     /* parameter for the MPEG2-data transfer */
-		     .stream = {
-				.type = USB_BULK,
-				.count = 10,
-				.endpoint = 0x04,
-				.u = {
-				      .bulk = {
-					       .buffersize = 4096,	/* actual size seen is 3948 */
-					       }
-				      }
-				},
-		     }},
-		     }
-		    },
-	.power_ctrl = af9005_power_ctrl,
-	.identify_state = af9005_identify_state,
-
-	.i2c_algo = &af9005_i2c_algo,
-
-	.rc.legacy = {
-		.rc_interval = 200,
-		.rc_map_table = NULL,
-		.rc_map_size = 0,
-		.rc_query = af9005_rc_query,
-	},
-
-	.generic_bulk_ctrl_endpoint          = 2,
-	.generic_bulk_ctrl_endpoint_response = 1,
-
-	.num_device_descs = 3,
-	.devices = {
-		    {.name = "Afatech DVB-T USB1.1 stick",
-		     .cold_ids = {&af9005_usb_table[AFATECH_AF9005], NULL},
-		     .warm_ids = {NULL},
-		     },
-		    {.name = "TerraTec Cinergy T USB XE",
-		     .cold_ids = {&af9005_usb_table[TERRATEC_AF9005], NULL},
-		     .warm_ids = {NULL},
-		     },
-		    {.name = "Ansonic DVB-T USB1.1 stick",
-		     .cold_ids = {&af9005_usb_table[ANSONIC_AF9005], NULL},
-		     .warm_ids = {NULL},
-		     },
-		    {NULL},
-		    }
-};
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver af9005_usb_driver = {
-	.name = "dvb_usb_af9005",
-	.probe = af9005_usb_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table = af9005_usb_table,
-};
-
-/* module stuff */
-static int __init af9005_usb_module_init(void)
-{
-	int result;
-	if ((result = usb_register(&af9005_usb_driver))) {
-		err("usb_register failed. (%d)", result);
-		return result;
-	}
-	rc_decode = symbol_request(af9005_rc_decode);
-	rc_keys = symbol_request(rc_map_af9005_table);
-	rc_keys_size = symbol_request(rc_map_af9005_table_size);
-	if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) {
-		err("af9005_rc_decode function not found, disabling remote");
-		af9005_properties.rc.legacy.rc_query = NULL;
-	} else {
-		af9005_properties.rc.legacy.rc_map_table = rc_keys;
-		af9005_properties.rc.legacy.rc_map_size = *rc_keys_size;
-	}
-
-	return 0;
-}
-
-static void __exit af9005_usb_module_exit(void)
-{
-	/* release rc decode symbols */
-	if (rc_decode != NULL)
-		symbol_put(af9005_rc_decode);
-	if (rc_keys != NULL)
-		symbol_put(rc_map_af9005_table);
-	if (rc_keys_size != NULL)
-		symbol_put(rc_map_af9005_table_size);
-	/* deregister this driver from the USB subsystem */
-	usb_deregister(&af9005_usb_driver);
-}
-
-module_init(af9005_usb_module_init);
-module_exit(af9005_usb_module_exit);
-
-MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
-MODULE_DESCRIPTION("Driver for Afatech 9005 DVB-T USB1.1 stick");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/dvb/dvb-usb/af9005.h
deleted file mode 100644
index 6a2bf3d..0000000
--- a/drivers/media/dvb/dvb-usb/af9005.h
+++ /dev/null
@@ -1,3496 +0,0 @@
-/* Common header-file of the Linux driver for the Afatech 9005
- * USB1.1 DVB-T receiver.
- *
- * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
- *
- * Thanks to Afatech who kindly provided information.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#ifndef _DVB_USB_AF9005_H_
-#define _DVB_USB_AF9005_H_
-
-#define DVB_USB_LOG_PREFIX "af9005"
-#include "dvb-usb.h"
-
-extern int dvb_usb_af9005_debug;
-#define deb_info(args...) dprintk(dvb_usb_af9005_debug,0x01,args)
-#define deb_xfer(args...) dprintk(dvb_usb_af9005_debug,0x02,args)
-#define deb_rc(args...)   dprintk(dvb_usb_af9005_debug,0x04,args)
-#define deb_reg(args...)  dprintk(dvb_usb_af9005_debug,0x08,args)
-#define deb_i2c(args...)  dprintk(dvb_usb_af9005_debug,0x10,args)
-#define deb_fw(args...)   dprintk(dvb_usb_af9005_debug,0x20,args)
-
-extern bool dvb_usb_af9005_led;
-
-/* firmware */
-#define FW_BULKOUT_SIZE 250
-enum {
-	FW_CONFIG,
-	FW_CONFIRM,
-	FW_BOOT
-};
-
-/* af9005 commands */
-#define AF9005_OFDM_REG  0
-#define AF9005_TUNER_REG 1
-
-#define AF9005_REGISTER_RW     0x20
-#define AF9005_REGISTER_RW_ACK 0x21
-
-#define AF9005_CMD_OFDM_REG 0x00
-#define AF9005_CMD_TUNER    0x80
-#define AF9005_CMD_BURST    0x02
-#define AF9005_CMD_AUTOINC  0x04
-#define AF9005_CMD_READ     0x00
-#define AF9005_CMD_WRITE    0x01
-
-/* af9005 registers */
-#define APO_REG_RESET					0xAEFF
-
-#define APO_REG_I2C_RW_CAN_TUNER            0xF000
-#define APO_REG_I2C_RW_SILICON_TUNER        0xF001
-#define APO_REG_GPIO_RW_SILICON_TUNER       0xFFFE	/*  also for OFSM */
-#define APO_REG_TRIGGER_OFSM                0xFFFF	/*  also for OFSM */
-
-/***********************************************************************
- *  Apollo Registers from VLSI					       *
- ***********************************************************************/
-#define xd_p_reg_aagc_inverted_agc	0xA000
-#define	reg_aagc_inverted_agc_pos 0
-#define	reg_aagc_inverted_agc_len 1
-#define	reg_aagc_inverted_agc_lsb 0
-#define xd_p_reg_aagc_sign_only	0xA000
-#define	reg_aagc_sign_only_pos 1
-#define	reg_aagc_sign_only_len 1
-#define	reg_aagc_sign_only_lsb 0
-#define xd_p_reg_aagc_slow_adc_en	0xA000
-#define	reg_aagc_slow_adc_en_pos 2
-#define	reg_aagc_slow_adc_en_len 1
-#define	reg_aagc_slow_adc_en_lsb 0
-#define xd_p_reg_aagc_slow_adc_scale	0xA000
-#define	reg_aagc_slow_adc_scale_pos 3
-#define	reg_aagc_slow_adc_scale_len 5
-#define	reg_aagc_slow_adc_scale_lsb 0
-#define xd_p_reg_aagc_check_slow_adc_lock	0xA001
-#define	reg_aagc_check_slow_adc_lock_pos 0
-#define	reg_aagc_check_slow_adc_lock_len 1
-#define	reg_aagc_check_slow_adc_lock_lsb 0
-#define xd_p_reg_aagc_init_control	0xA001
-#define	reg_aagc_init_control_pos 1
-#define	reg_aagc_init_control_len 1
-#define	reg_aagc_init_control_lsb 0
-#define xd_p_reg_aagc_total_gain_sel	0xA001
-#define	reg_aagc_total_gain_sel_pos 2
-#define	reg_aagc_total_gain_sel_len 2
-#define	reg_aagc_total_gain_sel_lsb 0
-#define xd_p_reg_aagc_out_inv	0xA001
-#define	reg_aagc_out_inv_pos 5
-#define	reg_aagc_out_inv_len 1
-#define	reg_aagc_out_inv_lsb 0
-#define xd_p_reg_aagc_int_en	0xA001
-#define	reg_aagc_int_en_pos 6
-#define	reg_aagc_int_en_len 1
-#define	reg_aagc_int_en_lsb 0
-#define xd_p_reg_aagc_lock_change_flag	0xA001
-#define	reg_aagc_lock_change_flag_pos 7
-#define	reg_aagc_lock_change_flag_len 1
-#define	reg_aagc_lock_change_flag_lsb 0
-#define xd_p_reg_aagc_rf_loop_bw_scale_acquire	0xA002
-#define	reg_aagc_rf_loop_bw_scale_acquire_pos 0
-#define	reg_aagc_rf_loop_bw_scale_acquire_len 5
-#define	reg_aagc_rf_loop_bw_scale_acquire_lsb 0
-#define xd_p_reg_aagc_rf_loop_bw_scale_track	0xA003
-#define	reg_aagc_rf_loop_bw_scale_track_pos 0
-#define	reg_aagc_rf_loop_bw_scale_track_len 5
-#define	reg_aagc_rf_loop_bw_scale_track_lsb 0
-#define xd_p_reg_aagc_if_loop_bw_scale_acquire	0xA004
-#define	reg_aagc_if_loop_bw_scale_acquire_pos 0
-#define	reg_aagc_if_loop_bw_scale_acquire_len 5
-#define	reg_aagc_if_loop_bw_scale_acquire_lsb 0
-#define xd_p_reg_aagc_if_loop_bw_scale_track	0xA005
-#define	reg_aagc_if_loop_bw_scale_track_pos 0
-#define	reg_aagc_if_loop_bw_scale_track_len 5
-#define	reg_aagc_if_loop_bw_scale_track_lsb 0
-#define xd_p_reg_aagc_max_rf_agc_7_0	0xA006
-#define	reg_aagc_max_rf_agc_7_0_pos 0
-#define	reg_aagc_max_rf_agc_7_0_len 8
-#define	reg_aagc_max_rf_agc_7_0_lsb 0
-#define xd_p_reg_aagc_max_rf_agc_9_8	0xA007
-#define	reg_aagc_max_rf_agc_9_8_pos 0
-#define	reg_aagc_max_rf_agc_9_8_len 2
-#define	reg_aagc_max_rf_agc_9_8_lsb 8
-#define xd_p_reg_aagc_min_rf_agc_7_0	0xA008
-#define	reg_aagc_min_rf_agc_7_0_pos 0
-#define	reg_aagc_min_rf_agc_7_0_len 8
-#define	reg_aagc_min_rf_agc_7_0_lsb 0
-#define xd_p_reg_aagc_min_rf_agc_9_8	0xA009
-#define	reg_aagc_min_rf_agc_9_8_pos 0
-#define	reg_aagc_min_rf_agc_9_8_len 2
-#define	reg_aagc_min_rf_agc_9_8_lsb 8
-#define xd_p_reg_aagc_max_if_agc_7_0	0xA00A
-#define	reg_aagc_max_if_agc_7_0_pos 0
-#define	reg_aagc_max_if_agc_7_0_len 8
-#define	reg_aagc_max_if_agc_7_0_lsb 0
-#define xd_p_reg_aagc_max_if_agc_9_8	0xA00B
-#define	reg_aagc_max_if_agc_9_8_pos 0
-#define	reg_aagc_max_if_agc_9_8_len 2
-#define	reg_aagc_max_if_agc_9_8_lsb 8
-#define xd_p_reg_aagc_min_if_agc_7_0	0xA00C
-#define	reg_aagc_min_if_agc_7_0_pos 0
-#define	reg_aagc_min_if_agc_7_0_len 8
-#define	reg_aagc_min_if_agc_7_0_lsb 0
-#define xd_p_reg_aagc_min_if_agc_9_8	0xA00D
-#define	reg_aagc_min_if_agc_9_8_pos 0
-#define	reg_aagc_min_if_agc_9_8_len 2
-#define	reg_aagc_min_if_agc_9_8_lsb 8
-#define xd_p_reg_aagc_lock_sample_scale	0xA00E
-#define	reg_aagc_lock_sample_scale_pos 0
-#define	reg_aagc_lock_sample_scale_len 5
-#define	reg_aagc_lock_sample_scale_lsb 0
-#define xd_p_reg_aagc_rf_agc_lock_scale_acquire	0xA00F
-#define	reg_aagc_rf_agc_lock_scale_acquire_pos 0
-#define	reg_aagc_rf_agc_lock_scale_acquire_len 3
-#define	reg_aagc_rf_agc_lock_scale_acquire_lsb 0
-#define xd_p_reg_aagc_rf_agc_lock_scale_track	0xA00F
-#define	reg_aagc_rf_agc_lock_scale_track_pos 3
-#define	reg_aagc_rf_agc_lock_scale_track_len 3
-#define	reg_aagc_rf_agc_lock_scale_track_lsb 0
-#define xd_p_reg_aagc_if_agc_lock_scale_acquire	0xA010
-#define	reg_aagc_if_agc_lock_scale_acquire_pos 0
-#define	reg_aagc_if_agc_lock_scale_acquire_len 3
-#define	reg_aagc_if_agc_lock_scale_acquire_lsb 0
-#define xd_p_reg_aagc_if_agc_lock_scale_track	0xA010
-#define	reg_aagc_if_agc_lock_scale_track_pos 3
-#define	reg_aagc_if_agc_lock_scale_track_len 3
-#define	reg_aagc_if_agc_lock_scale_track_lsb 0
-#define xd_p_reg_aagc_rf_top_numerator_7_0	0xA011
-#define	reg_aagc_rf_top_numerator_7_0_pos 0
-#define	reg_aagc_rf_top_numerator_7_0_len 8
-#define	reg_aagc_rf_top_numerator_7_0_lsb 0
-#define xd_p_reg_aagc_rf_top_numerator_9_8	0xA012
-#define	reg_aagc_rf_top_numerator_9_8_pos 0
-#define	reg_aagc_rf_top_numerator_9_8_len 2
-#define	reg_aagc_rf_top_numerator_9_8_lsb 8
-#define xd_p_reg_aagc_if_top_numerator_7_0	0xA013
-#define	reg_aagc_if_top_numerator_7_0_pos 0
-#define	reg_aagc_if_top_numerator_7_0_len 8
-#define	reg_aagc_if_top_numerator_7_0_lsb 0
-#define xd_p_reg_aagc_if_top_numerator_9_8	0xA014
-#define	reg_aagc_if_top_numerator_9_8_pos 0
-#define	reg_aagc_if_top_numerator_9_8_len 2
-#define	reg_aagc_if_top_numerator_9_8_lsb 8
-#define xd_p_reg_aagc_adc_out_desired_7_0	0xA015
-#define	reg_aagc_adc_out_desired_7_0_pos 0
-#define	reg_aagc_adc_out_desired_7_0_len 8
-#define	reg_aagc_adc_out_desired_7_0_lsb 0
-#define xd_p_reg_aagc_adc_out_desired_8	0xA016
-#define	reg_aagc_adc_out_desired_8_pos 0
-#define	reg_aagc_adc_out_desired_8_len 1
-#define	reg_aagc_adc_out_desired_8_lsb 0
-#define xd_p_reg_aagc_fixed_gain	0xA016
-#define	reg_aagc_fixed_gain_pos 3
-#define	reg_aagc_fixed_gain_len 1
-#define	reg_aagc_fixed_gain_lsb 0
-#define xd_p_reg_aagc_lock_count_th	0xA016
-#define	reg_aagc_lock_count_th_pos 4
-#define	reg_aagc_lock_count_th_len 4
-#define	reg_aagc_lock_count_th_lsb 0
-#define xd_p_reg_aagc_fixed_rf_agc_control_7_0	0xA017
-#define	reg_aagc_fixed_rf_agc_control_7_0_pos 0
-#define	reg_aagc_fixed_rf_agc_control_7_0_len 8
-#define	reg_aagc_fixed_rf_agc_control_7_0_lsb 0
-#define xd_p_reg_aagc_fixed_rf_agc_control_15_8	0xA018
-#define	reg_aagc_fixed_rf_agc_control_15_8_pos 0
-#define	reg_aagc_fixed_rf_agc_control_15_8_len 8
-#define	reg_aagc_fixed_rf_agc_control_15_8_lsb 8
-#define xd_p_reg_aagc_fixed_rf_agc_control_23_16	0xA019
-#define	reg_aagc_fixed_rf_agc_control_23_16_pos 0
-#define	reg_aagc_fixed_rf_agc_control_23_16_len 8
-#define	reg_aagc_fixed_rf_agc_control_23_16_lsb 16
-#define xd_p_reg_aagc_fixed_rf_agc_control_30_24	0xA01A
-#define	reg_aagc_fixed_rf_agc_control_30_24_pos 0
-#define	reg_aagc_fixed_rf_agc_control_30_24_len 7
-#define	reg_aagc_fixed_rf_agc_control_30_24_lsb 24
-#define xd_p_reg_aagc_fixed_if_agc_control_7_0	0xA01B
-#define	reg_aagc_fixed_if_agc_control_7_0_pos 0
-#define	reg_aagc_fixed_if_agc_control_7_0_len 8
-#define	reg_aagc_fixed_if_agc_control_7_0_lsb 0
-#define xd_p_reg_aagc_fixed_if_agc_control_15_8	0xA01C
-#define	reg_aagc_fixed_if_agc_control_15_8_pos 0
-#define	reg_aagc_fixed_if_agc_control_15_8_len 8
-#define	reg_aagc_fixed_if_agc_control_15_8_lsb 8
-#define xd_p_reg_aagc_fixed_if_agc_control_23_16	0xA01D
-#define	reg_aagc_fixed_if_agc_control_23_16_pos 0
-#define	reg_aagc_fixed_if_agc_control_23_16_len 8
-#define	reg_aagc_fixed_if_agc_control_23_16_lsb 16
-#define xd_p_reg_aagc_fixed_if_agc_control_30_24	0xA01E
-#define	reg_aagc_fixed_if_agc_control_30_24_pos 0
-#define	reg_aagc_fixed_if_agc_control_30_24_len 7
-#define	reg_aagc_fixed_if_agc_control_30_24_lsb 24
-#define xd_p_reg_aagc_rf_agc_unlock_numerator	0xA01F
-#define	reg_aagc_rf_agc_unlock_numerator_pos 0
-#define	reg_aagc_rf_agc_unlock_numerator_len 6
-#define	reg_aagc_rf_agc_unlock_numerator_lsb 0
-#define xd_p_reg_aagc_if_agc_unlock_numerator	0xA020
-#define	reg_aagc_if_agc_unlock_numerator_pos 0
-#define	reg_aagc_if_agc_unlock_numerator_len 6
-#define	reg_aagc_if_agc_unlock_numerator_lsb 0
-#define xd_p_reg_unplug_th	0xA021
-#define	reg_unplug_th_pos 0
-#define	reg_unplug_th_len 8
-#define	reg_aagc_rf_x0_lsb 0
-#define xd_p_reg_weak_signal_rfagc_thr 0xA022
-#define	reg_weak_signal_rfagc_thr_pos 0
-#define	reg_weak_signal_rfagc_thr_len 8
-#define	reg_weak_signal_rfagc_thr_lsb 0
-#define xd_p_reg_unplug_rf_gain_th 0xA023
-#define	reg_unplug_rf_gain_th_pos 0
-#define	reg_unplug_rf_gain_th_len 8
-#define	reg_unplug_rf_gain_th_lsb 0
-#define xd_p_reg_unplug_dtop_rf_gain_th 0xA024
-#define	reg_unplug_dtop_rf_gain_th_pos 0
-#define	reg_unplug_dtop_rf_gain_th_len 8
-#define	reg_unplug_dtop_rf_gain_th_lsb 0
-#define xd_p_reg_unplug_dtop_if_gain_th 0xA025
-#define	reg_unplug_dtop_if_gain_th_pos 0
-#define	reg_unplug_dtop_if_gain_th_len 8
-#define	reg_unplug_dtop_if_gain_th_lsb 0
-#define xd_p_reg_top_recover_at_unplug_en 0xA026
-#define	reg_top_recover_at_unplug_en_pos 0
-#define	reg_top_recover_at_unplug_en_len 1
-#define	reg_top_recover_at_unplug_en_lsb 0
-#define xd_p_reg_aagc_rf_x6	0xA027
-#define	reg_aagc_rf_x6_pos 0
-#define	reg_aagc_rf_x6_len 8
-#define	reg_aagc_rf_x6_lsb 0
-#define xd_p_reg_aagc_rf_x7	0xA028
-#define	reg_aagc_rf_x7_pos 0
-#define	reg_aagc_rf_x7_len 8
-#define	reg_aagc_rf_x7_lsb 0
-#define xd_p_reg_aagc_rf_x8	0xA029
-#define	reg_aagc_rf_x8_pos 0
-#define	reg_aagc_rf_x8_len 8
-#define	reg_aagc_rf_x8_lsb 0
-#define xd_p_reg_aagc_rf_x9	0xA02A
-#define	reg_aagc_rf_x9_pos 0
-#define	reg_aagc_rf_x9_len 8
-#define	reg_aagc_rf_x9_lsb 0
-#define xd_p_reg_aagc_rf_x10	0xA02B
-#define	reg_aagc_rf_x10_pos 0
-#define	reg_aagc_rf_x10_len 8
-#define	reg_aagc_rf_x10_lsb 0
-#define xd_p_reg_aagc_rf_x11	0xA02C
-#define	reg_aagc_rf_x11_pos 0
-#define	reg_aagc_rf_x11_len 8
-#define	reg_aagc_rf_x11_lsb 0
-#define xd_p_reg_aagc_rf_x12	0xA02D
-#define	reg_aagc_rf_x12_pos 0
-#define	reg_aagc_rf_x12_len 8
-#define	reg_aagc_rf_x12_lsb 0
-#define xd_p_reg_aagc_rf_x13	0xA02E
-#define	reg_aagc_rf_x13_pos 0
-#define	reg_aagc_rf_x13_len 8
-#define	reg_aagc_rf_x13_lsb 0
-#define xd_p_reg_aagc_if_x0	0xA02F
-#define	reg_aagc_if_x0_pos 0
-#define	reg_aagc_if_x0_len 8
-#define	reg_aagc_if_x0_lsb 0
-#define xd_p_reg_aagc_if_x1	0xA030
-#define	reg_aagc_if_x1_pos 0
-#define	reg_aagc_if_x1_len 8
-#define	reg_aagc_if_x1_lsb 0
-#define xd_p_reg_aagc_if_x2	0xA031
-#define	reg_aagc_if_x2_pos 0
-#define	reg_aagc_if_x2_len 8
-#define	reg_aagc_if_x2_lsb 0
-#define xd_p_reg_aagc_if_x3	0xA032
-#define	reg_aagc_if_x3_pos 0
-#define	reg_aagc_if_x3_len 8
-#define	reg_aagc_if_x3_lsb 0
-#define xd_p_reg_aagc_if_x4	0xA033
-#define	reg_aagc_if_x4_pos 0
-#define	reg_aagc_if_x4_len 8
-#define	reg_aagc_if_x4_lsb 0
-#define xd_p_reg_aagc_if_x5	0xA034
-#define	reg_aagc_if_x5_pos 0
-#define	reg_aagc_if_x5_len 8
-#define	reg_aagc_if_x5_lsb 0
-#define xd_p_reg_aagc_if_x6	0xA035
-#define	reg_aagc_if_x6_pos 0
-#define	reg_aagc_if_x6_len 8
-#define	reg_aagc_if_x6_lsb 0
-#define xd_p_reg_aagc_if_x7	0xA036
-#define	reg_aagc_if_x7_pos 0
-#define	reg_aagc_if_x7_len 8
-#define	reg_aagc_if_x7_lsb 0
-#define xd_p_reg_aagc_if_x8	0xA037
-#define	reg_aagc_if_x8_pos 0
-#define	reg_aagc_if_x8_len 8
-#define	reg_aagc_if_x8_lsb 0
-#define xd_p_reg_aagc_if_x9	0xA038
-#define	reg_aagc_if_x9_pos 0
-#define	reg_aagc_if_x9_len 8
-#define	reg_aagc_if_x9_lsb 0
-#define xd_p_reg_aagc_if_x10	0xA039
-#define	reg_aagc_if_x10_pos 0
-#define	reg_aagc_if_x10_len 8
-#define	reg_aagc_if_x10_lsb 0
-#define xd_p_reg_aagc_if_x11	0xA03A
-#define	reg_aagc_if_x11_pos 0
-#define	reg_aagc_if_x11_len 8
-#define	reg_aagc_if_x11_lsb 0
-#define xd_p_reg_aagc_if_x12	0xA03B
-#define	reg_aagc_if_x12_pos 0
-#define	reg_aagc_if_x12_len 8
-#define	reg_aagc_if_x12_lsb 0
-#define xd_p_reg_aagc_if_x13	0xA03C
-#define	reg_aagc_if_x13_pos 0
-#define	reg_aagc_if_x13_len 8
-#define	reg_aagc_if_x13_lsb 0
-#define xd_p_reg_aagc_min_rf_ctl_8bit_for_dca	0xA03D
-#define	reg_aagc_min_rf_ctl_8bit_for_dca_pos 0
-#define	reg_aagc_min_rf_ctl_8bit_for_dca_len 8
-#define	reg_aagc_min_rf_ctl_8bit_for_dca_lsb 0
-#define xd_p_reg_aagc_min_if_ctl_8bit_for_dca	0xA03E
-#define	reg_aagc_min_if_ctl_8bit_for_dca_pos 0
-#define	reg_aagc_min_if_ctl_8bit_for_dca_len 8
-#define	reg_aagc_min_if_ctl_8bit_for_dca_lsb 0
-#define xd_r_reg_aagc_total_gain_7_0	0xA070
-#define	reg_aagc_total_gain_7_0_pos 0
-#define	reg_aagc_total_gain_7_0_len 8
-#define	reg_aagc_total_gain_7_0_lsb 0
-#define xd_r_reg_aagc_total_gain_15_8	0xA071
-#define	reg_aagc_total_gain_15_8_pos 0
-#define	reg_aagc_total_gain_15_8_len 8
-#define	reg_aagc_total_gain_15_8_lsb 8
-#define xd_p_reg_aagc_in_sat_cnt_7_0	0xA074
-#define	reg_aagc_in_sat_cnt_7_0_pos 0
-#define	reg_aagc_in_sat_cnt_7_0_len 8
-#define	reg_aagc_in_sat_cnt_7_0_lsb 0
-#define xd_p_reg_aagc_in_sat_cnt_15_8	0xA075
-#define	reg_aagc_in_sat_cnt_15_8_pos 0
-#define	reg_aagc_in_sat_cnt_15_8_len 8
-#define	reg_aagc_in_sat_cnt_15_8_lsb 8
-#define xd_p_reg_aagc_in_sat_cnt_23_16	0xA076
-#define	reg_aagc_in_sat_cnt_23_16_pos 0
-#define	reg_aagc_in_sat_cnt_23_16_len 8
-#define	reg_aagc_in_sat_cnt_23_16_lsb 16
-#define xd_p_reg_aagc_in_sat_cnt_31_24	0xA077
-#define	reg_aagc_in_sat_cnt_31_24_pos 0
-#define	reg_aagc_in_sat_cnt_31_24_len 8
-#define	reg_aagc_in_sat_cnt_31_24_lsb 24
-#define xd_r_reg_aagc_digital_rf_volt_7_0	0xA078
-#define	reg_aagc_digital_rf_volt_7_0_pos 0
-#define	reg_aagc_digital_rf_volt_7_0_len 8
-#define	reg_aagc_digital_rf_volt_7_0_lsb 0
-#define xd_r_reg_aagc_digital_rf_volt_9_8	0xA079
-#define	reg_aagc_digital_rf_volt_9_8_pos 0
-#define	reg_aagc_digital_rf_volt_9_8_len 2
-#define	reg_aagc_digital_rf_volt_9_8_lsb 8
-#define xd_r_reg_aagc_digital_if_volt_7_0	0xA07A
-#define	reg_aagc_digital_if_volt_7_0_pos 0
-#define	reg_aagc_digital_if_volt_7_0_len 8
-#define	reg_aagc_digital_if_volt_7_0_lsb 0
-#define xd_r_reg_aagc_digital_if_volt_9_8	0xA07B
-#define	reg_aagc_digital_if_volt_9_8_pos 0
-#define	reg_aagc_digital_if_volt_9_8_len 2
-#define	reg_aagc_digital_if_volt_9_8_lsb 8
-#define xd_r_reg_aagc_rf_gain	0xA07C
-#define	reg_aagc_rf_gain_pos 0
-#define	reg_aagc_rf_gain_len 8
-#define	reg_aagc_rf_gain_lsb 0
-#define xd_r_reg_aagc_if_gain	0xA07D
-#define	reg_aagc_if_gain_pos 0
-#define	reg_aagc_if_gain_len 8
-#define	reg_aagc_if_gain_lsb 0
-#define xd_p_tinr_imp_indicator	0xA080
-#define	tinr_imp_indicator_pos 0
-#define	tinr_imp_indicator_len 2
-#define	tinr_imp_indicator_lsb 0
-#define xd_p_reg_tinr_fifo_size	0xA080
-#define	reg_tinr_fifo_size_pos 2
-#define	reg_tinr_fifo_size_len 5
-#define	reg_tinr_fifo_size_lsb 0
-#define xd_p_reg_tinr_saturation_cnt_th	0xA081
-#define	reg_tinr_saturation_cnt_th_pos 0
-#define	reg_tinr_saturation_cnt_th_len 4
-#define	reg_tinr_saturation_cnt_th_lsb 0
-#define xd_p_reg_tinr_saturation_th_3_0	0xA081
-#define	reg_tinr_saturation_th_3_0_pos 4
-#define	reg_tinr_saturation_th_3_0_len 4
-#define	reg_tinr_saturation_th_3_0_lsb 0
-#define xd_p_reg_tinr_saturation_th_8_4	0xA082
-#define	reg_tinr_saturation_th_8_4_pos 0
-#define	reg_tinr_saturation_th_8_4_len 5
-#define	reg_tinr_saturation_th_8_4_lsb 4
-#define xd_p_reg_tinr_imp_duration_th_2k_7_0	0xA083
-#define	reg_tinr_imp_duration_th_2k_7_0_pos 0
-#define	reg_tinr_imp_duration_th_2k_7_0_len 8
-#define	reg_tinr_imp_duration_th_2k_7_0_lsb 0
-#define xd_p_reg_tinr_imp_duration_th_2k_8	0xA084
-#define	reg_tinr_imp_duration_th_2k_8_pos 0
-#define	reg_tinr_imp_duration_th_2k_8_len 1
-#define	reg_tinr_imp_duration_th_2k_8_lsb 0
-#define xd_p_reg_tinr_imp_duration_th_8k_7_0	0xA085
-#define	reg_tinr_imp_duration_th_8k_7_0_pos 0
-#define	reg_tinr_imp_duration_th_8k_7_0_len 8
-#define	reg_tinr_imp_duration_th_8k_7_0_lsb 0
-#define xd_p_reg_tinr_imp_duration_th_8k_10_8	0xA086
-#define	reg_tinr_imp_duration_th_8k_10_8_pos 0
-#define	reg_tinr_imp_duration_th_8k_10_8_len 3
-#define	reg_tinr_imp_duration_th_8k_10_8_lsb 8
-#define xd_p_reg_tinr_freq_ratio_6m_7_0	0xA087
-#define	reg_tinr_freq_ratio_6m_7_0_pos 0
-#define	reg_tinr_freq_ratio_6m_7_0_len 8
-#define	reg_tinr_freq_ratio_6m_7_0_lsb 0
-#define xd_p_reg_tinr_freq_ratio_6m_12_8	0xA088
-#define	reg_tinr_freq_ratio_6m_12_8_pos 0
-#define	reg_tinr_freq_ratio_6m_12_8_len 5
-#define	reg_tinr_freq_ratio_6m_12_8_lsb 8
-#define xd_p_reg_tinr_freq_ratio_7m_7_0	0xA089
-#define	reg_tinr_freq_ratio_7m_7_0_pos 0
-#define	reg_tinr_freq_ratio_7m_7_0_len 8
-#define	reg_tinr_freq_ratio_7m_7_0_lsb 0
-#define xd_p_reg_tinr_freq_ratio_7m_12_8	0xA08A
-#define	reg_tinr_freq_ratio_7m_12_8_pos 0
-#define	reg_tinr_freq_ratio_7m_12_8_len 5
-#define	reg_tinr_freq_ratio_7m_12_8_lsb 8
-#define xd_p_reg_tinr_freq_ratio_8m_7_0	0xA08B
-#define	reg_tinr_freq_ratio_8m_7_0_pos 0
-#define	reg_tinr_freq_ratio_8m_7_0_len 8
-#define	reg_tinr_freq_ratio_8m_7_0_lsb 0
-#define xd_p_reg_tinr_freq_ratio_8m_12_8	0xA08C
-#define	reg_tinr_freq_ratio_8m_12_8_pos 0
-#define	reg_tinr_freq_ratio_8m_12_8_len 5
-#define	reg_tinr_freq_ratio_8m_12_8_lsb 8
-#define xd_p_reg_tinr_imp_duration_th_low_2k	0xA08D
-#define	reg_tinr_imp_duration_th_low_2k_pos 0
-#define	reg_tinr_imp_duration_th_low_2k_len 8
-#define	reg_tinr_imp_duration_th_low_2k_lsb 0
-#define xd_p_reg_tinr_imp_duration_th_low_8k	0xA08E
-#define	reg_tinr_imp_duration_th_low_8k_pos 0
-#define	reg_tinr_imp_duration_th_low_8k_len 8
-#define	reg_tinr_imp_duration_th_low_8k_lsb 0
-#define xd_r_reg_tinr_counter_7_0	0xA090
-#define	reg_tinr_counter_7_0_pos 0
-#define	reg_tinr_counter_7_0_len 8
-#define	reg_tinr_counter_7_0_lsb 0
-#define xd_r_reg_tinr_counter_15_8	0xA091
-#define	reg_tinr_counter_15_8_pos 0
-#define	reg_tinr_counter_15_8_len 8
-#define	reg_tinr_counter_15_8_lsb 8
-#define xd_p_reg_tinr_adative_tinr_en	0xA093
-#define	reg_tinr_adative_tinr_en_pos 0
-#define	reg_tinr_adative_tinr_en_len 1
-#define	reg_tinr_adative_tinr_en_lsb 0
-#define xd_p_reg_tinr_peak_fifo_size	0xA093
-#define	reg_tinr_peak_fifo_size_pos 1
-#define	reg_tinr_peak_fifo_size_len 5
-#define	reg_tinr_peak_fifo_size_lsb 0
-#define xd_p_reg_tinr_counter_rst	0xA093
-#define	reg_tinr_counter_rst_pos 6
-#define	reg_tinr_counter_rst_len 1
-#define	reg_tinr_counter_rst_lsb 0
-#define xd_p_reg_tinr_search_period_7_0	0xA094
-#define	reg_tinr_search_period_7_0_pos 0
-#define	reg_tinr_search_period_7_0_len 8
-#define	reg_tinr_search_period_7_0_lsb 0
-#define xd_p_reg_tinr_search_period_15_8	0xA095
-#define	reg_tinr_search_period_15_8_pos 0
-#define	reg_tinr_search_period_15_8_len 8
-#define	reg_tinr_search_period_15_8_lsb 8
-#define xd_p_reg_ccifs_fcw_7_0	0xA0A0
-#define	reg_ccifs_fcw_7_0_pos 0
-#define	reg_ccifs_fcw_7_0_len 8
-#define	reg_ccifs_fcw_7_0_lsb 0
-#define xd_p_reg_ccifs_fcw_12_8	0xA0A1
-#define	reg_ccifs_fcw_12_8_pos 0
-#define	reg_ccifs_fcw_12_8_len 5
-#define	reg_ccifs_fcw_12_8_lsb 8
-#define xd_p_reg_ccifs_spec_inv	0xA0A1
-#define	reg_ccifs_spec_inv_pos 5
-#define	reg_ccifs_spec_inv_len 1
-#define	reg_ccifs_spec_inv_lsb 0
-#define xd_p_reg_gp_trigger	0xA0A2
-#define	reg_gp_trigger_pos 0
-#define	reg_gp_trigger_len 1
-#define	reg_gp_trigger_lsb 0
-#define xd_p_reg_trigger_sel	0xA0A2
-#define	reg_trigger_sel_pos 1
-#define	reg_trigger_sel_len 2
-#define	reg_trigger_sel_lsb 0
-#define xd_p_reg_debug_ofdm	0xA0A2
-#define	reg_debug_ofdm_pos 3
-#define	reg_debug_ofdm_len 2
-#define	reg_debug_ofdm_lsb 0
-#define xd_p_reg_trigger_module_sel	0xA0A3
-#define	reg_trigger_module_sel_pos 0
-#define	reg_trigger_module_sel_len 6
-#define	reg_trigger_module_sel_lsb 0
-#define xd_p_reg_trigger_set_sel	0xA0A4
-#define	reg_trigger_set_sel_pos 0
-#define	reg_trigger_set_sel_len 6
-#define	reg_trigger_set_sel_lsb 0
-#define xd_p_reg_fw_int_mask_n	0xA0A4
-#define	reg_fw_int_mask_n_pos 6
-#define	reg_fw_int_mask_n_len 1
-#define	reg_fw_int_mask_n_lsb 0
-#define xd_p_reg_debug_group	0xA0A5
-#define	reg_debug_group_pos 0
-#define	reg_debug_group_len 4
-#define	reg_debug_group_lsb 0
-#define xd_p_reg_odbg_clk_sel	0xA0A5
-#define	reg_odbg_clk_sel_pos 4
-#define	reg_odbg_clk_sel_len 2
-#define	reg_odbg_clk_sel_lsb 0
-#define xd_p_reg_ccif_sc	0xA0C0
-#define	reg_ccif_sc_pos 0
-#define	reg_ccif_sc_len 4
-#define	reg_ccif_sc_lsb 0
-#define xd_r_reg_ccif_saturate	0xA0C1
-#define	reg_ccif_saturate_pos 0
-#define	reg_ccif_saturate_len 2
-#define	reg_ccif_saturate_lsb 0
-#define xd_r_reg_antif_saturate	0xA0C1
-#define	reg_antif_saturate_pos 2
-#define	reg_antif_saturate_len 4
-#define	reg_antif_saturate_lsb 0
-#define xd_r_reg_acif_saturate	0xA0C2
-#define	reg_acif_saturate_pos 0
-#define	reg_acif_saturate_len 8
-#define	reg_acif_saturate_lsb 0
-#define xd_p_reg_tmr_timer0_threshold_7_0	0xA0C8
-#define	reg_tmr_timer0_threshold_7_0_pos 0
-#define	reg_tmr_timer0_threshold_7_0_len 8
-#define	reg_tmr_timer0_threshold_7_0_lsb 0
-#define xd_p_reg_tmr_timer0_threshold_15_8	0xA0C9
-#define	reg_tmr_timer0_threshold_15_8_pos 0
-#define	reg_tmr_timer0_threshold_15_8_len 8
-#define	reg_tmr_timer0_threshold_15_8_lsb 8
-#define xd_p_reg_tmr_timer0_enable	0xA0CA
-#define	reg_tmr_timer0_enable_pos 0
-#define	reg_tmr_timer0_enable_len 1
-#define	reg_tmr_timer0_enable_lsb 0
-#define xd_p_reg_tmr_timer0_clk_sel	0xA0CA
-#define	reg_tmr_timer0_clk_sel_pos 1
-#define	reg_tmr_timer0_clk_sel_len 1
-#define	reg_tmr_timer0_clk_sel_lsb 0
-#define xd_p_reg_tmr_timer0_int	0xA0CA
-#define	reg_tmr_timer0_int_pos 2
-#define	reg_tmr_timer0_int_len 1
-#define	reg_tmr_timer0_int_lsb 0
-#define xd_p_reg_tmr_timer0_rst	0xA0CA
-#define	reg_tmr_timer0_rst_pos 3
-#define	reg_tmr_timer0_rst_len 1
-#define	reg_tmr_timer0_rst_lsb 0
-#define xd_r_reg_tmr_timer0_count_7_0	0xA0CB
-#define	reg_tmr_timer0_count_7_0_pos 0
-#define	reg_tmr_timer0_count_7_0_len 8
-#define	reg_tmr_timer0_count_7_0_lsb 0
-#define xd_r_reg_tmr_timer0_count_15_8	0xA0CC
-#define	reg_tmr_timer0_count_15_8_pos 0
-#define	reg_tmr_timer0_count_15_8_len 8
-#define	reg_tmr_timer0_count_15_8_lsb 8
-#define xd_p_reg_suspend	0xA0CD
-#define	reg_suspend_pos 0
-#define	reg_suspend_len 1
-#define	reg_suspend_lsb 0
-#define xd_p_reg_suspend_rdy	0xA0CD
-#define	reg_suspend_rdy_pos 1
-#define	reg_suspend_rdy_len 1
-#define	reg_suspend_rdy_lsb 0
-#define xd_p_reg_resume	0xA0CD
-#define	reg_resume_pos 2
-#define	reg_resume_len 1
-#define	reg_resume_lsb 0
-#define xd_p_reg_resume_rdy	0xA0CD
-#define	reg_resume_rdy_pos 3
-#define	reg_resume_rdy_len 1
-#define	reg_resume_rdy_lsb 0
-#define xd_p_reg_fmf	0xA0CE
-#define	reg_fmf_pos 0
-#define	reg_fmf_len 8
-#define	reg_fmf_lsb 0
-#define xd_p_ccid_accumulate_num_2k_7_0	0xA100
-#define	ccid_accumulate_num_2k_7_0_pos 0
-#define	ccid_accumulate_num_2k_7_0_len 8
-#define	ccid_accumulate_num_2k_7_0_lsb 0
-#define xd_p_ccid_accumulate_num_2k_12_8	0xA101
-#define	ccid_accumulate_num_2k_12_8_pos 0
-#define	ccid_accumulate_num_2k_12_8_len 5
-#define	ccid_accumulate_num_2k_12_8_lsb 8
-#define xd_p_ccid_accumulate_num_8k_7_0	0xA102
-#define	ccid_accumulate_num_8k_7_0_pos 0
-#define	ccid_accumulate_num_8k_7_0_len 8
-#define	ccid_accumulate_num_8k_7_0_lsb 0
-#define xd_p_ccid_accumulate_num_8k_14_8	0xA103
-#define	ccid_accumulate_num_8k_14_8_pos 0
-#define	ccid_accumulate_num_8k_14_8_len 7
-#define	ccid_accumulate_num_8k_14_8_lsb 8
-#define xd_p_ccid_desired_level_0	0xA103
-#define	ccid_desired_level_0_pos 7
-#define	ccid_desired_level_0_len 1
-#define	ccid_desired_level_0_lsb 0
-#define xd_p_ccid_desired_level_8_1	0xA104
-#define	ccid_desired_level_8_1_pos 0
-#define	ccid_desired_level_8_1_len 8
-#define	ccid_desired_level_8_1_lsb 1
-#define xd_p_ccid_apply_delay	0xA105
-#define	ccid_apply_delay_pos 0
-#define	ccid_apply_delay_len 7
-#define	ccid_apply_delay_lsb 0
-#define xd_p_ccid_CCID_Threshold1	0xA106
-#define	ccid_CCID_Threshold1_pos 0
-#define	ccid_CCID_Threshold1_len 8
-#define	ccid_CCID_Threshold1_lsb 0
-#define xd_p_ccid_CCID_Threshold2	0xA107
-#define	ccid_CCID_Threshold2_pos 0
-#define	ccid_CCID_Threshold2_len 8
-#define	ccid_CCID_Threshold2_lsb 0
-#define xd_p_reg_ccid_gain_scale	0xA108
-#define	reg_ccid_gain_scale_pos 0
-#define	reg_ccid_gain_scale_len 4
-#define	reg_ccid_gain_scale_lsb 0
-#define xd_p_reg_ccid2_passband_gain_set	0xA108
-#define	reg_ccid2_passband_gain_set_pos 4
-#define	reg_ccid2_passband_gain_set_len 4
-#define	reg_ccid2_passband_gain_set_lsb 0
-#define xd_r_ccid_multiplier_7_0	0xA109
-#define	ccid_multiplier_7_0_pos 0
-#define	ccid_multiplier_7_0_len 8
-#define	ccid_multiplier_7_0_lsb 0
-#define xd_r_ccid_multiplier_15_8	0xA10A
-#define	ccid_multiplier_15_8_pos 0
-#define	ccid_multiplier_15_8_len 8
-#define	ccid_multiplier_15_8_lsb 8
-#define xd_r_ccid_right_shift_bits	0xA10B
-#define	ccid_right_shift_bits_pos 0
-#define	ccid_right_shift_bits_len 4
-#define	ccid_right_shift_bits_lsb 0
-#define xd_r_reg_ccid_sx_7_0	0xA10C
-#define	reg_ccid_sx_7_0_pos 0
-#define	reg_ccid_sx_7_0_len 8
-#define	reg_ccid_sx_7_0_lsb 0
-#define xd_r_reg_ccid_sx_15_8	0xA10D
-#define	reg_ccid_sx_15_8_pos 0
-#define	reg_ccid_sx_15_8_len 8
-#define	reg_ccid_sx_15_8_lsb 8
-#define xd_r_reg_ccid_sx_21_16	0xA10E
-#define	reg_ccid_sx_21_16_pos 0
-#define	reg_ccid_sx_21_16_len 6
-#define	reg_ccid_sx_21_16_lsb 16
-#define xd_r_reg_ccid_sy_7_0	0xA110
-#define	reg_ccid_sy_7_0_pos 0
-#define	reg_ccid_sy_7_0_len 8
-#define	reg_ccid_sy_7_0_lsb 0
-#define xd_r_reg_ccid_sy_15_8	0xA111
-#define	reg_ccid_sy_15_8_pos 0
-#define	reg_ccid_sy_15_8_len 8
-#define	reg_ccid_sy_15_8_lsb 8
-#define xd_r_reg_ccid_sy_23_16	0xA112
-#define	reg_ccid_sy_23_16_pos 0
-#define	reg_ccid_sy_23_16_len 8
-#define	reg_ccid_sy_23_16_lsb 16
-#define xd_r_reg_ccid2_sz_7_0	0xA114
-#define	reg_ccid2_sz_7_0_pos 0
-#define	reg_ccid2_sz_7_0_len 8
-#define	reg_ccid2_sz_7_0_lsb 0
-#define xd_r_reg_ccid2_sz_15_8	0xA115
-#define	reg_ccid2_sz_15_8_pos 0
-#define	reg_ccid2_sz_15_8_len 8
-#define	reg_ccid2_sz_15_8_lsb 8
-#define xd_r_reg_ccid2_sz_23_16	0xA116
-#define	reg_ccid2_sz_23_16_pos 0
-#define	reg_ccid2_sz_23_16_len 8
-#define	reg_ccid2_sz_23_16_lsb 16
-#define xd_r_reg_ccid2_sz_25_24	0xA117
-#define	reg_ccid2_sz_25_24_pos 0
-#define	reg_ccid2_sz_25_24_len 2
-#define	reg_ccid2_sz_25_24_lsb 24
-#define xd_r_reg_ccid2_sy_7_0	0xA118
-#define	reg_ccid2_sy_7_0_pos 0
-#define	reg_ccid2_sy_7_0_len 8
-#define	reg_ccid2_sy_7_0_lsb 0
-#define xd_r_reg_ccid2_sy_15_8	0xA119
-#define	reg_ccid2_sy_15_8_pos 0
-#define	reg_ccid2_sy_15_8_len 8
-#define	reg_ccid2_sy_15_8_lsb 8
-#define xd_r_reg_ccid2_sy_23_16	0xA11A
-#define	reg_ccid2_sy_23_16_pos 0
-#define	reg_ccid2_sy_23_16_len 8
-#define	reg_ccid2_sy_23_16_lsb 16
-#define xd_r_reg_ccid2_sy_25_24	0xA11B
-#define	reg_ccid2_sy_25_24_pos 0
-#define	reg_ccid2_sy_25_24_len 2
-#define	reg_ccid2_sy_25_24_lsb 24
-#define xd_p_dagc1_accumulate_num_2k_7_0	0xA120
-#define	dagc1_accumulate_num_2k_7_0_pos 0
-#define	dagc1_accumulate_num_2k_7_0_len 8
-#define	dagc1_accumulate_num_2k_7_0_lsb 0
-#define xd_p_dagc1_accumulate_num_2k_12_8	0xA121
-#define	dagc1_accumulate_num_2k_12_8_pos 0
-#define	dagc1_accumulate_num_2k_12_8_len 5
-#define	dagc1_accumulate_num_2k_12_8_lsb 8
-#define xd_p_dagc1_accumulate_num_8k_7_0	0xA122
-#define	dagc1_accumulate_num_8k_7_0_pos 0
-#define	dagc1_accumulate_num_8k_7_0_len 8
-#define	dagc1_accumulate_num_8k_7_0_lsb 0
-#define xd_p_dagc1_accumulate_num_8k_14_8	0xA123
-#define	dagc1_accumulate_num_8k_14_8_pos 0
-#define	dagc1_accumulate_num_8k_14_8_len 7
-#define	dagc1_accumulate_num_8k_14_8_lsb 8
-#define xd_p_dagc1_desired_level_0	0xA123
-#define	dagc1_desired_level_0_pos 7
-#define	dagc1_desired_level_0_len 1
-#define	dagc1_desired_level_0_lsb 0
-#define xd_p_dagc1_desired_level_8_1	0xA124
-#define	dagc1_desired_level_8_1_pos 0
-#define	dagc1_desired_level_8_1_len 8
-#define	dagc1_desired_level_8_1_lsb 1
-#define xd_p_dagc1_apply_delay	0xA125
-#define	dagc1_apply_delay_pos 0
-#define	dagc1_apply_delay_len 7
-#define	dagc1_apply_delay_lsb 0
-#define xd_p_dagc1_bypass_scale_ctl	0xA126
-#define	dagc1_bypass_scale_ctl_pos 0
-#define	dagc1_bypass_scale_ctl_len 2
-#define	dagc1_bypass_scale_ctl_lsb 0
-#define xd_p_reg_dagc1_in_sat_cnt_7_0	0xA127
-#define	reg_dagc1_in_sat_cnt_7_0_pos 0
-#define	reg_dagc1_in_sat_cnt_7_0_len 8
-#define	reg_dagc1_in_sat_cnt_7_0_lsb 0
-#define xd_p_reg_dagc1_in_sat_cnt_15_8	0xA128
-#define	reg_dagc1_in_sat_cnt_15_8_pos 0
-#define	reg_dagc1_in_sat_cnt_15_8_len 8
-#define	reg_dagc1_in_sat_cnt_15_8_lsb 8
-#define xd_p_reg_dagc1_in_sat_cnt_23_16	0xA129
-#define	reg_dagc1_in_sat_cnt_23_16_pos 0
-#define	reg_dagc1_in_sat_cnt_23_16_len 8
-#define	reg_dagc1_in_sat_cnt_23_16_lsb 16
-#define xd_p_reg_dagc1_in_sat_cnt_31_24	0xA12A
-#define	reg_dagc1_in_sat_cnt_31_24_pos 0
-#define	reg_dagc1_in_sat_cnt_31_24_len 8
-#define	reg_dagc1_in_sat_cnt_31_24_lsb 24
-#define xd_p_reg_dagc1_out_sat_cnt_7_0	0xA12B
-#define	reg_dagc1_out_sat_cnt_7_0_pos 0
-#define	reg_dagc1_out_sat_cnt_7_0_len 8
-#define	reg_dagc1_out_sat_cnt_7_0_lsb 0
-#define xd_p_reg_dagc1_out_sat_cnt_15_8	0xA12C
-#define	reg_dagc1_out_sat_cnt_15_8_pos 0
-#define	reg_dagc1_out_sat_cnt_15_8_len 8
-#define	reg_dagc1_out_sat_cnt_15_8_lsb 8
-#define xd_p_reg_dagc1_out_sat_cnt_23_16	0xA12D
-#define	reg_dagc1_out_sat_cnt_23_16_pos 0
-#define	reg_dagc1_out_sat_cnt_23_16_len 8
-#define	reg_dagc1_out_sat_cnt_23_16_lsb 16
-#define xd_p_reg_dagc1_out_sat_cnt_31_24	0xA12E
-#define	reg_dagc1_out_sat_cnt_31_24_pos 0
-#define	reg_dagc1_out_sat_cnt_31_24_len 8
-#define	reg_dagc1_out_sat_cnt_31_24_lsb 24
-#define xd_r_dagc1_multiplier_7_0	0xA136
-#define	dagc1_multiplier_7_0_pos 0
-#define	dagc1_multiplier_7_0_len 8
-#define	dagc1_multiplier_7_0_lsb 0
-#define xd_r_dagc1_multiplier_15_8	0xA137
-#define	dagc1_multiplier_15_8_pos 0
-#define	dagc1_multiplier_15_8_len 8
-#define	dagc1_multiplier_15_8_lsb 8
-#define xd_r_dagc1_right_shift_bits	0xA138
-#define	dagc1_right_shift_bits_pos 0
-#define	dagc1_right_shift_bits_len 4
-#define	dagc1_right_shift_bits_lsb 0
-#define xd_p_reg_bfs_fcw_7_0	0xA140
-#define	reg_bfs_fcw_7_0_pos 0
-#define	reg_bfs_fcw_7_0_len 8
-#define	reg_bfs_fcw_7_0_lsb 0
-#define xd_p_reg_bfs_fcw_15_8	0xA141
-#define	reg_bfs_fcw_15_8_pos 0
-#define	reg_bfs_fcw_15_8_len 8
-#define	reg_bfs_fcw_15_8_lsb 8
-#define xd_p_reg_bfs_fcw_22_16	0xA142
-#define	reg_bfs_fcw_22_16_pos 0
-#define	reg_bfs_fcw_22_16_len 7
-#define	reg_bfs_fcw_22_16_lsb 16
-#define xd_p_reg_antif_sf_7_0	0xA144
-#define	reg_antif_sf_7_0_pos 0
-#define	reg_antif_sf_7_0_len 8
-#define	reg_antif_sf_7_0_lsb 0
-#define xd_p_reg_antif_sf_11_8	0xA145
-#define	reg_antif_sf_11_8_pos 0
-#define	reg_antif_sf_11_8_len 4
-#define	reg_antif_sf_11_8_lsb 8
-#define xd_r_bfs_fcw_q_7_0	0xA150
-#define	bfs_fcw_q_7_0_pos 0
-#define	bfs_fcw_q_7_0_len 8
-#define	bfs_fcw_q_7_0_lsb 0
-#define xd_r_bfs_fcw_q_15_8	0xA151
-#define	bfs_fcw_q_15_8_pos 0
-#define	bfs_fcw_q_15_8_len 8
-#define	bfs_fcw_q_15_8_lsb 8
-#define xd_r_bfs_fcw_q_22_16	0xA152
-#define	bfs_fcw_q_22_16_pos 0
-#define	bfs_fcw_q_22_16_len 7
-#define	bfs_fcw_q_22_16_lsb 16
-#define xd_p_reg_dca_enu	0xA160
-#define	reg_dca_enu_pos 0
-#define	reg_dca_enu_len 1
-#define	reg_dca_enu_lsb 0
-#define xd_p_reg_dca_enl	0xA160
-#define	reg_dca_enl_pos 1
-#define	reg_dca_enl_len 1
-#define	reg_dca_enl_lsb 0
-#define xd_p_reg_dca_lower_chip	0xA160
-#define	reg_dca_lower_chip_pos 2
-#define	reg_dca_lower_chip_len 1
-#define	reg_dca_lower_chip_lsb 0
-#define xd_p_reg_dca_upper_chip	0xA160
-#define	reg_dca_upper_chip_pos 3
-#define	reg_dca_upper_chip_len 1
-#define	reg_dca_upper_chip_lsb 0
-#define xd_p_reg_dca_platch	0xA160
-#define	reg_dca_platch_pos 4
-#define	reg_dca_platch_len 1
-#define	reg_dca_platch_lsb 0
-#define xd_p_reg_dca_th	0xA161
-#define	reg_dca_th_pos 0
-#define	reg_dca_th_len 5
-#define	reg_dca_th_lsb 0
-#define xd_p_reg_dca_scale	0xA162
-#define	reg_dca_scale_pos 0
-#define	reg_dca_scale_len 4
-#define	reg_dca_scale_lsb 0
-#define xd_p_reg_dca_tone_7_0	0xA163
-#define	reg_dca_tone_7_0_pos 0
-#define	reg_dca_tone_7_0_len 8
-#define	reg_dca_tone_7_0_lsb 0
-#define xd_p_reg_dca_tone_12_8	0xA164
-#define	reg_dca_tone_12_8_pos 0
-#define	reg_dca_tone_12_8_len 5
-#define	reg_dca_tone_12_8_lsb 8
-#define xd_p_reg_dca_time_7_0	0xA165
-#define	reg_dca_time_7_0_pos 0
-#define	reg_dca_time_7_0_len 8
-#define	reg_dca_time_7_0_lsb 0
-#define xd_p_reg_dca_time_15_8	0xA166
-#define	reg_dca_time_15_8_pos 0
-#define	reg_dca_time_15_8_len 8
-#define	reg_dca_time_15_8_lsb 8
-#define xd_r_dcasm	0xA167
-#define	dcasm_pos 0
-#define	dcasm_len 3
-#define	dcasm_lsb 0
-#define xd_p_reg_qnt_valuew_7_0	0xA168
-#define	reg_qnt_valuew_7_0_pos 0
-#define	reg_qnt_valuew_7_0_len 8
-#define	reg_qnt_valuew_7_0_lsb 0
-#define xd_p_reg_qnt_valuew_10_8	0xA169
-#define	reg_qnt_valuew_10_8_pos 0
-#define	reg_qnt_valuew_10_8_len 3
-#define	reg_qnt_valuew_10_8_lsb 8
-#define xd_p_dca_sbx_gain_diff_7_0	0xA16A
-#define	dca_sbx_gain_diff_7_0_pos 0
-#define	dca_sbx_gain_diff_7_0_len 8
-#define	dca_sbx_gain_diff_7_0_lsb 0
-#define xd_p_dca_sbx_gain_diff_9_8	0xA16B
-#define	dca_sbx_gain_diff_9_8_pos 0
-#define	dca_sbx_gain_diff_9_8_len 2
-#define	dca_sbx_gain_diff_9_8_lsb 8
-#define xd_p_reg_dca_stand_alone	0xA16C
-#define	reg_dca_stand_alone_pos 0
-#define	reg_dca_stand_alone_len 1
-#define	reg_dca_stand_alone_lsb 0
-#define xd_p_reg_dca_upper_out_en	0xA16C
-#define	reg_dca_upper_out_en_pos 1
-#define	reg_dca_upper_out_en_len 1
-#define	reg_dca_upper_out_en_lsb 0
-#define xd_p_reg_dca_rc_en	0xA16C
-#define	reg_dca_rc_en_pos 2
-#define	reg_dca_rc_en_len 1
-#define	reg_dca_rc_en_lsb 0
-#define xd_p_reg_dca_retrain_send	0xA16C
-#define	reg_dca_retrain_send_pos 3
-#define	reg_dca_retrain_send_len 1
-#define	reg_dca_retrain_send_lsb 0
-#define xd_p_reg_dca_retrain_rec	0xA16C
-#define	reg_dca_retrain_rec_pos 4
-#define	reg_dca_retrain_rec_len 1
-#define	reg_dca_retrain_rec_lsb 0
-#define xd_p_reg_dca_api_tpsrdy	0xA16C
-#define	reg_dca_api_tpsrdy_pos 5
-#define	reg_dca_api_tpsrdy_len 1
-#define	reg_dca_api_tpsrdy_lsb 0
-#define xd_p_reg_dca_symbol_gap	0xA16D
-#define	reg_dca_symbol_gap_pos 0
-#define	reg_dca_symbol_gap_len 4
-#define	reg_dca_symbol_gap_lsb 0
-#define xd_p_reg_qnt_nfvaluew_7_0	0xA16E
-#define	reg_qnt_nfvaluew_7_0_pos 0
-#define	reg_qnt_nfvaluew_7_0_len 8
-#define	reg_qnt_nfvaluew_7_0_lsb 0
-#define xd_p_reg_qnt_nfvaluew_10_8	0xA16F
-#define	reg_qnt_nfvaluew_10_8_pos 0
-#define	reg_qnt_nfvaluew_10_8_len 3
-#define	reg_qnt_nfvaluew_10_8_lsb 8
-#define xd_p_reg_qnt_flatness_thr_7_0	0xA170
-#define	reg_qnt_flatness_thr_7_0_pos 0
-#define	reg_qnt_flatness_thr_7_0_len 8
-#define	reg_qnt_flatness_thr_7_0_lsb 0
-#define xd_p_reg_qnt_flatness_thr_9_8	0xA171
-#define	reg_qnt_flatness_thr_9_8_pos 0
-#define	reg_qnt_flatness_thr_9_8_len 2
-#define	reg_qnt_flatness_thr_9_8_lsb 8
-#define xd_p_reg_dca_tone_idx_5_0	0xA171
-#define	reg_dca_tone_idx_5_0_pos 2
-#define	reg_dca_tone_idx_5_0_len 6
-#define	reg_dca_tone_idx_5_0_lsb 0
-#define xd_p_reg_dca_tone_idx_12_6	0xA172
-#define	reg_dca_tone_idx_12_6_pos 0
-#define	reg_dca_tone_idx_12_6_len 7
-#define	reg_dca_tone_idx_12_6_lsb 6
-#define xd_p_reg_dca_data_vld	0xA173
-#define	reg_dca_data_vld_pos 0
-#define	reg_dca_data_vld_len 1
-#define	reg_dca_data_vld_lsb 0
-#define xd_p_reg_dca_read_update	0xA173
-#define	reg_dca_read_update_pos 1
-#define	reg_dca_read_update_len 1
-#define	reg_dca_read_update_lsb 0
-#define xd_r_reg_dca_data_re_5_0	0xA173
-#define	reg_dca_data_re_5_0_pos 2
-#define	reg_dca_data_re_5_0_len 6
-#define	reg_dca_data_re_5_0_lsb 0
-#define xd_r_reg_dca_data_re_10_6	0xA174
-#define	reg_dca_data_re_10_6_pos 0
-#define	reg_dca_data_re_10_6_len 5
-#define	reg_dca_data_re_10_6_lsb 6
-#define xd_r_reg_dca_data_im_7_0	0xA175
-#define	reg_dca_data_im_7_0_pos 0
-#define	reg_dca_data_im_7_0_len 8
-#define	reg_dca_data_im_7_0_lsb 0
-#define xd_r_reg_dca_data_im_10_8	0xA176
-#define	reg_dca_data_im_10_8_pos 0
-#define	reg_dca_data_im_10_8_len 3
-#define	reg_dca_data_im_10_8_lsb 8
-#define xd_r_reg_dca_data_h2_7_0	0xA178
-#define	reg_dca_data_h2_7_0_pos 0
-#define	reg_dca_data_h2_7_0_len 8
-#define	reg_dca_data_h2_7_0_lsb 0
-#define xd_r_reg_dca_data_h2_9_8	0xA179
-#define	reg_dca_data_h2_9_8_pos 0
-#define	reg_dca_data_h2_9_8_len 2
-#define	reg_dca_data_h2_9_8_lsb 8
-#define xd_p_reg_f_adc_7_0	0xA180
-#define	reg_f_adc_7_0_pos 0
-#define	reg_f_adc_7_0_len 8
-#define	reg_f_adc_7_0_lsb 0
-#define xd_p_reg_f_adc_15_8	0xA181
-#define	reg_f_adc_15_8_pos 0
-#define	reg_f_adc_15_8_len 8
-#define	reg_f_adc_15_8_lsb 8
-#define xd_p_reg_f_adc_23_16	0xA182
-#define	reg_f_adc_23_16_pos 0
-#define	reg_f_adc_23_16_len 8
-#define	reg_f_adc_23_16_lsb 16
-#define xd_r_intp_mu_7_0	0xA190
-#define	intp_mu_7_0_pos 0
-#define	intp_mu_7_0_len 8
-#define	intp_mu_7_0_lsb 0
-#define xd_r_intp_mu_15_8	0xA191
-#define	intp_mu_15_8_pos 0
-#define	intp_mu_15_8_len 8
-#define	intp_mu_15_8_lsb 8
-#define xd_r_intp_mu_19_16	0xA192
-#define	intp_mu_19_16_pos 0
-#define	intp_mu_19_16_len 4
-#define	intp_mu_19_16_lsb 16
-#define xd_p_reg_agc_rst	0xA1A0
-#define	reg_agc_rst_pos 0
-#define	reg_agc_rst_len 1
-#define	reg_agc_rst_lsb 0
-#define xd_p_rf_agc_en	0xA1A0
-#define	rf_agc_en_pos 1
-#define	rf_agc_en_len 1
-#define	rf_agc_en_lsb 0
-#define xd_p_rf_agc_dis	0xA1A0
-#define	rf_agc_dis_pos 2
-#define	rf_agc_dis_len 1
-#define	rf_agc_dis_lsb 0
-#define xd_p_if_agc_rst	0xA1A0
-#define	if_agc_rst_pos 3
-#define	if_agc_rst_len 1
-#define	if_agc_rst_lsb 0
-#define xd_p_if_agc_en	0xA1A0
-#define	if_agc_en_pos 4
-#define	if_agc_en_len 1
-#define	if_agc_en_lsb 0
-#define xd_p_if_agc_dis	0xA1A0
-#define	if_agc_dis_pos 5
-#define	if_agc_dis_len 1
-#define	if_agc_dis_lsb 0
-#define xd_p_agc_lock	0xA1A0
-#define	agc_lock_pos 6
-#define	agc_lock_len 1
-#define	agc_lock_lsb 0
-#define xd_p_reg_tinr_rst	0xA1A1
-#define	reg_tinr_rst_pos 0
-#define	reg_tinr_rst_len 1
-#define	reg_tinr_rst_lsb 0
-#define xd_p_reg_tinr_en	0xA1A1
-#define	reg_tinr_en_pos 1
-#define	reg_tinr_en_len 1
-#define	reg_tinr_en_lsb 0
-#define xd_p_reg_ccifs_en	0xA1A2
-#define	reg_ccifs_en_pos 0
-#define	reg_ccifs_en_len 1
-#define	reg_ccifs_en_lsb 0
-#define xd_p_reg_ccifs_dis	0xA1A2
-#define	reg_ccifs_dis_pos 1
-#define	reg_ccifs_dis_len 1
-#define	reg_ccifs_dis_lsb 0
-#define xd_p_reg_ccifs_rst	0xA1A2
-#define	reg_ccifs_rst_pos 2
-#define	reg_ccifs_rst_len 1
-#define	reg_ccifs_rst_lsb 0
-#define xd_p_reg_ccifs_byp	0xA1A2
-#define	reg_ccifs_byp_pos 3
-#define	reg_ccifs_byp_len 1
-#define	reg_ccifs_byp_lsb 0
-#define xd_p_reg_ccif_en	0xA1A3
-#define	reg_ccif_en_pos 0
-#define	reg_ccif_en_len 1
-#define	reg_ccif_en_lsb 0
-#define xd_p_reg_ccif_dis	0xA1A3
-#define	reg_ccif_dis_pos 1
-#define	reg_ccif_dis_len 1
-#define	reg_ccif_dis_lsb 0
-#define xd_p_reg_ccif_rst	0xA1A3
-#define	reg_ccif_rst_pos 2
-#define	reg_ccif_rst_len 1
-#define	reg_ccif_rst_lsb 0
-#define xd_p_reg_ccif_byp	0xA1A3
-#define	reg_ccif_byp_pos 3
-#define	reg_ccif_byp_len 1
-#define	reg_ccif_byp_lsb 0
-#define xd_p_dagc1_rst	0xA1A4
-#define	dagc1_rst_pos 0
-#define	dagc1_rst_len 1
-#define	dagc1_rst_lsb 0
-#define xd_p_dagc1_en	0xA1A4
-#define	dagc1_en_pos 1
-#define	dagc1_en_len 1
-#define	dagc1_en_lsb 0
-#define xd_p_dagc1_mode	0xA1A4
-#define	dagc1_mode_pos 2
-#define	dagc1_mode_len 2
-#define	dagc1_mode_lsb 0
-#define xd_p_dagc1_done	0xA1A4
-#define	dagc1_done_pos 4
-#define	dagc1_done_len 1
-#define	dagc1_done_lsb 0
-#define xd_p_ccid_rst	0xA1A5
-#define	ccid_rst_pos 0
-#define	ccid_rst_len 1
-#define	ccid_rst_lsb 0
-#define xd_p_ccid_en	0xA1A5
-#define	ccid_en_pos 1
-#define	ccid_en_len 1
-#define	ccid_en_lsb 0
-#define xd_p_ccid_mode	0xA1A5
-#define	ccid_mode_pos 2
-#define	ccid_mode_len 2
-#define	ccid_mode_lsb 0
-#define xd_p_ccid_done	0xA1A5
-#define	ccid_done_pos 4
-#define	ccid_done_len 1
-#define	ccid_done_lsb 0
-#define xd_r_ccid_deted	0xA1A5
-#define	ccid_deted_pos 5
-#define	ccid_deted_len 1
-#define	ccid_deted_lsb 0
-#define xd_p_ccid2_en	0xA1A5
-#define	ccid2_en_pos 6
-#define	ccid2_en_len 1
-#define	ccid2_en_lsb 0
-#define xd_p_ccid2_done	0xA1A5
-#define	ccid2_done_pos 7
-#define	ccid2_done_len 1
-#define	ccid2_done_lsb 0
-#define xd_p_reg_bfs_en	0xA1A6
-#define	reg_bfs_en_pos 0
-#define	reg_bfs_en_len 1
-#define	reg_bfs_en_lsb 0
-#define xd_p_reg_bfs_dis	0xA1A6
-#define	reg_bfs_dis_pos 1
-#define	reg_bfs_dis_len 1
-#define	reg_bfs_dis_lsb 0
-#define xd_p_reg_bfs_rst	0xA1A6
-#define	reg_bfs_rst_pos 2
-#define	reg_bfs_rst_len 1
-#define	reg_bfs_rst_lsb 0
-#define xd_p_reg_bfs_byp	0xA1A6
-#define	reg_bfs_byp_pos 3
-#define	reg_bfs_byp_len 1
-#define	reg_bfs_byp_lsb 0
-#define xd_p_reg_antif_en	0xA1A7
-#define	reg_antif_en_pos 0
-#define	reg_antif_en_len 1
-#define	reg_antif_en_lsb 0
-#define xd_p_reg_antif_dis	0xA1A7
-#define	reg_antif_dis_pos 1
-#define	reg_antif_dis_len 1
-#define	reg_antif_dis_lsb 0
-#define xd_p_reg_antif_rst	0xA1A7
-#define	reg_antif_rst_pos 2
-#define	reg_antif_rst_len 1
-#define	reg_antif_rst_lsb 0
-#define xd_p_reg_antif_byp	0xA1A7
-#define	reg_antif_byp_pos 3
-#define	reg_antif_byp_len 1
-#define	reg_antif_byp_lsb 0
-#define xd_p_intp_en	0xA1A8
-#define	intp_en_pos 0
-#define	intp_en_len 1
-#define	intp_en_lsb 0
-#define xd_p_intp_dis	0xA1A8
-#define	intp_dis_pos 1
-#define	intp_dis_len 1
-#define	intp_dis_lsb 0
-#define xd_p_intp_rst	0xA1A8
-#define	intp_rst_pos 2
-#define	intp_rst_len 1
-#define	intp_rst_lsb 0
-#define xd_p_intp_byp	0xA1A8
-#define	intp_byp_pos 3
-#define	intp_byp_len 1
-#define	intp_byp_lsb 0
-#define xd_p_reg_acif_en	0xA1A9
-#define	reg_acif_en_pos 0
-#define	reg_acif_en_len 1
-#define	reg_acif_en_lsb 0
-#define xd_p_reg_acif_dis	0xA1A9
-#define	reg_acif_dis_pos 1
-#define	reg_acif_dis_len 1
-#define	reg_acif_dis_lsb 0
-#define xd_p_reg_acif_rst	0xA1A9
-#define	reg_acif_rst_pos 2
-#define	reg_acif_rst_len 1
-#define	reg_acif_rst_lsb 0
-#define xd_p_reg_acif_byp	0xA1A9
-#define	reg_acif_byp_pos 3
-#define	reg_acif_byp_len 1
-#define	reg_acif_byp_lsb 0
-#define xd_p_reg_acif_sync_mode	0xA1A9
-#define	reg_acif_sync_mode_pos 4
-#define	reg_acif_sync_mode_len 1
-#define	reg_acif_sync_mode_lsb 0
-#define xd_p_dagc2_rst	0xA1AA
-#define	dagc2_rst_pos 0
-#define	dagc2_rst_len 1
-#define	dagc2_rst_lsb 0
-#define xd_p_dagc2_en	0xA1AA
-#define	dagc2_en_pos 1
-#define	dagc2_en_len 1
-#define	dagc2_en_lsb 0
-#define xd_p_dagc2_mode	0xA1AA
-#define	dagc2_mode_pos 2
-#define	dagc2_mode_len 2
-#define	dagc2_mode_lsb 0
-#define xd_p_dagc2_done	0xA1AA
-#define	dagc2_done_pos 4
-#define	dagc2_done_len 1
-#define	dagc2_done_lsb 0
-#define xd_p_reg_dca_en	0xA1AB
-#define	reg_dca_en_pos 0
-#define	reg_dca_en_len 1
-#define	reg_dca_en_lsb 0
-#define xd_p_dagc2_accumulate_num_2k_7_0	0xA1C0
-#define	dagc2_accumulate_num_2k_7_0_pos 0
-#define	dagc2_accumulate_num_2k_7_0_len 8
-#define	dagc2_accumulate_num_2k_7_0_lsb 0
-#define xd_p_dagc2_accumulate_num_2k_12_8	0xA1C1
-#define	dagc2_accumulate_num_2k_12_8_pos 0
-#define	dagc2_accumulate_num_2k_12_8_len 5
-#define	dagc2_accumulate_num_2k_12_8_lsb 8
-#define xd_p_dagc2_accumulate_num_8k_7_0	0xA1C2
-#define	dagc2_accumulate_num_8k_7_0_pos 0
-#define	dagc2_accumulate_num_8k_7_0_len 8
-#define	dagc2_accumulate_num_8k_7_0_lsb 0
-#define xd_p_dagc2_accumulate_num_8k_12_8	0xA1C3
-#define	dagc2_accumulate_num_8k_12_8_pos 0
-#define	dagc2_accumulate_num_8k_12_8_len 5
-#define	dagc2_accumulate_num_8k_12_8_lsb 8
-#define xd_p_dagc2_desired_level_2_0	0xA1C3
-#define	dagc2_desired_level_2_0_pos 5
-#define	dagc2_desired_level_2_0_len 3
-#define	dagc2_desired_level_2_0_lsb 0
-#define xd_p_dagc2_desired_level_8_3	0xA1C4
-#define	dagc2_desired_level_8_3_pos 0
-#define	dagc2_desired_level_8_3_len 6
-#define	dagc2_desired_level_8_3_lsb 3
-#define xd_p_dagc2_apply_delay	0xA1C5
-#define	dagc2_apply_delay_pos 0
-#define	dagc2_apply_delay_len 7
-#define	dagc2_apply_delay_lsb 0
-#define xd_p_dagc2_bypass_scale_ctl	0xA1C6
-#define	dagc2_bypass_scale_ctl_pos 0
-#define	dagc2_bypass_scale_ctl_len 3
-#define	dagc2_bypass_scale_ctl_lsb 0
-#define xd_p_dagc2_programmable_shift1	0xA1C7
-#define	dagc2_programmable_shift1_pos 0
-#define	dagc2_programmable_shift1_len 8
-#define	dagc2_programmable_shift1_lsb 0
-#define xd_p_dagc2_programmable_shift2	0xA1C8
-#define	dagc2_programmable_shift2_pos 0
-#define	dagc2_programmable_shift2_len 8
-#define	dagc2_programmable_shift2_lsb 0
-#define xd_p_reg_dagc2_in_sat_cnt_7_0	0xA1C9
-#define	reg_dagc2_in_sat_cnt_7_0_pos 0
-#define	reg_dagc2_in_sat_cnt_7_0_len 8
-#define	reg_dagc2_in_sat_cnt_7_0_lsb 0
-#define xd_p_reg_dagc2_in_sat_cnt_15_8	0xA1CA
-#define	reg_dagc2_in_sat_cnt_15_8_pos 0
-#define	reg_dagc2_in_sat_cnt_15_8_len 8
-#define	reg_dagc2_in_sat_cnt_15_8_lsb 8
-#define xd_p_reg_dagc2_in_sat_cnt_23_16	0xA1CB
-#define	reg_dagc2_in_sat_cnt_23_16_pos 0
-#define	reg_dagc2_in_sat_cnt_23_16_len 8
-#define	reg_dagc2_in_sat_cnt_23_16_lsb 16
-#define xd_p_reg_dagc2_in_sat_cnt_31_24	0xA1CC
-#define	reg_dagc2_in_sat_cnt_31_24_pos 0
-#define	reg_dagc2_in_sat_cnt_31_24_len 8
-#define	reg_dagc2_in_sat_cnt_31_24_lsb 24
-#define xd_p_reg_dagc2_out_sat_cnt_7_0	0xA1CD
-#define	reg_dagc2_out_sat_cnt_7_0_pos 0
-#define	reg_dagc2_out_sat_cnt_7_0_len 8
-#define	reg_dagc2_out_sat_cnt_7_0_lsb 0
-#define xd_p_reg_dagc2_out_sat_cnt_15_8	0xA1CE
-#define	reg_dagc2_out_sat_cnt_15_8_pos 0
-#define	reg_dagc2_out_sat_cnt_15_8_len 8
-#define	reg_dagc2_out_sat_cnt_15_8_lsb 8
-#define xd_p_reg_dagc2_out_sat_cnt_23_16	0xA1CF
-#define	reg_dagc2_out_sat_cnt_23_16_pos 0
-#define	reg_dagc2_out_sat_cnt_23_16_len 8
-#define	reg_dagc2_out_sat_cnt_23_16_lsb 16
-#define xd_p_reg_dagc2_out_sat_cnt_31_24	0xA1D0
-#define	reg_dagc2_out_sat_cnt_31_24_pos 0
-#define	reg_dagc2_out_sat_cnt_31_24_len 8
-#define	reg_dagc2_out_sat_cnt_31_24_lsb 24
-#define xd_r_dagc2_multiplier_7_0	0xA1D6
-#define	dagc2_multiplier_7_0_pos 0
-#define	dagc2_multiplier_7_0_len 8
-#define	dagc2_multiplier_7_0_lsb 0
-#define xd_r_dagc2_multiplier_15_8	0xA1D7
-#define	dagc2_multiplier_15_8_pos 0
-#define	dagc2_multiplier_15_8_len 8
-#define	dagc2_multiplier_15_8_lsb 8
-#define xd_r_dagc2_right_shift_bits	0xA1D8
-#define	dagc2_right_shift_bits_pos 0
-#define	dagc2_right_shift_bits_len 4
-#define	dagc2_right_shift_bits_lsb 0
-#define xd_p_cfoe_NS_coeff1_7_0	0xA200
-#define	cfoe_NS_coeff1_7_0_pos 0
-#define	cfoe_NS_coeff1_7_0_len 8
-#define	cfoe_NS_coeff1_7_0_lsb 0
-#define xd_p_cfoe_NS_coeff1_15_8	0xA201
-#define	cfoe_NS_coeff1_15_8_pos 0
-#define	cfoe_NS_coeff1_15_8_len 8
-#define	cfoe_NS_coeff1_15_8_lsb 8
-#define xd_p_cfoe_NS_coeff1_23_16	0xA202
-#define	cfoe_NS_coeff1_23_16_pos 0
-#define	cfoe_NS_coeff1_23_16_len 8
-#define	cfoe_NS_coeff1_23_16_lsb 16
-#define xd_p_cfoe_NS_coeff1_25_24	0xA203
-#define	cfoe_NS_coeff1_25_24_pos 0
-#define	cfoe_NS_coeff1_25_24_len 2
-#define	cfoe_NS_coeff1_25_24_lsb 24
-#define xd_p_cfoe_NS_coeff2_5_0	0xA203
-#define	cfoe_NS_coeff2_5_0_pos 2
-#define	cfoe_NS_coeff2_5_0_len 6
-#define	cfoe_NS_coeff2_5_0_lsb 0
-#define xd_p_cfoe_NS_coeff2_13_6	0xA204
-#define	cfoe_NS_coeff2_13_6_pos 0
-#define	cfoe_NS_coeff2_13_6_len 8
-#define	cfoe_NS_coeff2_13_6_lsb 6
-#define xd_p_cfoe_NS_coeff2_21_14	0xA205
-#define	cfoe_NS_coeff2_21_14_pos 0
-#define	cfoe_NS_coeff2_21_14_len 8
-#define	cfoe_NS_coeff2_21_14_lsb 14
-#define xd_p_cfoe_NS_coeff2_24_22	0xA206
-#define	cfoe_NS_coeff2_24_22_pos 0
-#define	cfoe_NS_coeff2_24_22_len 3
-#define	cfoe_NS_coeff2_24_22_lsb 22
-#define xd_p_cfoe_lf_c1_4_0	0xA206
-#define	cfoe_lf_c1_4_0_pos 3
-#define	cfoe_lf_c1_4_0_len 5
-#define	cfoe_lf_c1_4_0_lsb 0
-#define xd_p_cfoe_lf_c1_12_5	0xA207
-#define	cfoe_lf_c1_12_5_pos 0
-#define	cfoe_lf_c1_12_5_len 8
-#define	cfoe_lf_c1_12_5_lsb 5
-#define xd_p_cfoe_lf_c1_20_13	0xA208
-#define	cfoe_lf_c1_20_13_pos 0
-#define	cfoe_lf_c1_20_13_len 8
-#define	cfoe_lf_c1_20_13_lsb 13
-#define xd_p_cfoe_lf_c1_25_21	0xA209
-#define	cfoe_lf_c1_25_21_pos 0
-#define	cfoe_lf_c1_25_21_len 5
-#define	cfoe_lf_c1_25_21_lsb 21
-#define xd_p_cfoe_lf_c2_2_0	0xA209
-#define	cfoe_lf_c2_2_0_pos 5
-#define	cfoe_lf_c2_2_0_len 3
-#define	cfoe_lf_c2_2_0_lsb 0
-#define xd_p_cfoe_lf_c2_10_3	0xA20A
-#define	cfoe_lf_c2_10_3_pos 0
-#define	cfoe_lf_c2_10_3_len 8
-#define	cfoe_lf_c2_10_3_lsb 3
-#define xd_p_cfoe_lf_c2_18_11	0xA20B
-#define	cfoe_lf_c2_18_11_pos 0
-#define	cfoe_lf_c2_18_11_len 8
-#define	cfoe_lf_c2_18_11_lsb 11
-#define xd_p_cfoe_lf_c2_25_19	0xA20C
-#define	cfoe_lf_c2_25_19_pos 0
-#define	cfoe_lf_c2_25_19_len 7
-#define	cfoe_lf_c2_25_19_lsb 19
-#define xd_p_cfoe_ifod_7_0	0xA20D
-#define	cfoe_ifod_7_0_pos 0
-#define	cfoe_ifod_7_0_len 8
-#define	cfoe_ifod_7_0_lsb 0
-#define xd_p_cfoe_ifod_10_8	0xA20E
-#define	cfoe_ifod_10_8_pos 0
-#define	cfoe_ifod_10_8_len 3
-#define	cfoe_ifod_10_8_lsb 8
-#define xd_p_cfoe_Divg_ctr_th	0xA20E
-#define	cfoe_Divg_ctr_th_pos 4
-#define	cfoe_Divg_ctr_th_len 4
-#define	cfoe_Divg_ctr_th_lsb 0
-#define xd_p_cfoe_FOT_divg_th	0xA20F
-#define	cfoe_FOT_divg_th_pos 0
-#define	cfoe_FOT_divg_th_len 8
-#define	cfoe_FOT_divg_th_lsb 0
-#define xd_p_cfoe_FOT_cnvg_th	0xA210
-#define	cfoe_FOT_cnvg_th_pos 0
-#define	cfoe_FOT_cnvg_th_len 8
-#define	cfoe_FOT_cnvg_th_lsb 0
-#define xd_p_reg_cfoe_offset_7_0	0xA211
-#define	reg_cfoe_offset_7_0_pos 0
-#define	reg_cfoe_offset_7_0_len 8
-#define	reg_cfoe_offset_7_0_lsb 0
-#define xd_p_reg_cfoe_offset_9_8	0xA212
-#define	reg_cfoe_offset_9_8_pos 0
-#define	reg_cfoe_offset_9_8_len 2
-#define	reg_cfoe_offset_9_8_lsb 8
-#define xd_p_reg_cfoe_ifoe_sign_corr	0xA212
-#define	reg_cfoe_ifoe_sign_corr_pos 2
-#define	reg_cfoe_ifoe_sign_corr_len 1
-#define	reg_cfoe_ifoe_sign_corr_lsb 0
-#define xd_r_cfoe_fot_LF_output_7_0	0xA218
-#define	cfoe_fot_LF_output_7_0_pos 0
-#define	cfoe_fot_LF_output_7_0_len 8
-#define	cfoe_fot_LF_output_7_0_lsb 0
-#define xd_r_cfoe_fot_LF_output_15_8	0xA219
-#define	cfoe_fot_LF_output_15_8_pos 0
-#define	cfoe_fot_LF_output_15_8_len 8
-#define	cfoe_fot_LF_output_15_8_lsb 8
-#define xd_r_cfoe_ifo_metric_7_0	0xA21A
-#define	cfoe_ifo_metric_7_0_pos 0
-#define	cfoe_ifo_metric_7_0_len 8
-#define	cfoe_ifo_metric_7_0_lsb 0
-#define xd_r_cfoe_ifo_metric_15_8	0xA21B
-#define	cfoe_ifo_metric_15_8_pos 0
-#define	cfoe_ifo_metric_15_8_len 8
-#define	cfoe_ifo_metric_15_8_lsb 8
-#define xd_r_cfoe_ifo_metric_23_16	0xA21C
-#define	cfoe_ifo_metric_23_16_pos 0
-#define	cfoe_ifo_metric_23_16_len 8
-#define	cfoe_ifo_metric_23_16_lsb 16
-#define xd_p_ste_Nu	0xA220
-#define	ste_Nu_pos 0
-#define	ste_Nu_len 2
-#define	ste_Nu_lsb 0
-#define xd_p_ste_GI	0xA220
-#define	ste_GI_pos 2
-#define	ste_GI_len 3
-#define	ste_GI_lsb 0
-#define xd_p_ste_symbol_num	0xA221
-#define	ste_symbol_num_pos 0
-#define	ste_symbol_num_len 2
-#define	ste_symbol_num_lsb 0
-#define xd_p_ste_sample_num	0xA221
-#define	ste_sample_num_pos 2
-#define	ste_sample_num_len 2
-#define	ste_sample_num_lsb 0
-#define xd_p_reg_ste_buf_en	0xA221
-#define	reg_ste_buf_en_pos 7
-#define	reg_ste_buf_en_len 1
-#define	reg_ste_buf_en_lsb 0
-#define xd_p_ste_FFT_offset_7_0	0xA222
-#define	ste_FFT_offset_7_0_pos 0
-#define	ste_FFT_offset_7_0_len 8
-#define	ste_FFT_offset_7_0_lsb 0
-#define xd_p_ste_FFT_offset_11_8	0xA223
-#define	ste_FFT_offset_11_8_pos 0
-#define	ste_FFT_offset_11_8_len 4
-#define	ste_FFT_offset_11_8_lsb 8
-#define xd_p_reg_ste_tstmod	0xA223
-#define	reg_ste_tstmod_pos 5
-#define	reg_ste_tstmod_len 1
-#define	reg_ste_tstmod_lsb 0
-#define xd_p_ste_adv_start_7_0	0xA224
-#define	ste_adv_start_7_0_pos 0
-#define	ste_adv_start_7_0_len 8
-#define	ste_adv_start_7_0_lsb 0
-#define xd_p_ste_adv_start_10_8	0xA225
-#define	ste_adv_start_10_8_pos 0
-#define	ste_adv_start_10_8_len 3
-#define	ste_adv_start_10_8_lsb 8
-#define xd_p_ste_adv_stop	0xA226
-#define	ste_adv_stop_pos 0
-#define	ste_adv_stop_len 8
-#define	ste_adv_stop_lsb 0
-#define xd_r_ste_P_value_7_0	0xA228
-#define	ste_P_value_7_0_pos 0
-#define	ste_P_value_7_0_len 8
-#define	ste_P_value_7_0_lsb 0
-#define xd_r_ste_P_value_10_8	0xA229
-#define	ste_P_value_10_8_pos 0
-#define	ste_P_value_10_8_len 3
-#define	ste_P_value_10_8_lsb 8
-#define xd_r_ste_M_value_7_0	0xA22A
-#define	ste_M_value_7_0_pos 0
-#define	ste_M_value_7_0_len 8
-#define	ste_M_value_7_0_lsb 0
-#define xd_r_ste_M_value_10_8	0xA22B
-#define	ste_M_value_10_8_pos 0
-#define	ste_M_value_10_8_len 3
-#define	ste_M_value_10_8_lsb 8
-#define xd_r_ste_H1	0xA22C
-#define	ste_H1_pos 0
-#define	ste_H1_len 7
-#define	ste_H1_lsb 0
-#define xd_r_ste_H2	0xA22D
-#define	ste_H2_pos 0
-#define	ste_H2_len 7
-#define	ste_H2_lsb 0
-#define xd_r_ste_H3	0xA22E
-#define	ste_H3_pos 0
-#define	ste_H3_len 7
-#define	ste_H3_lsb 0
-#define xd_r_ste_H4	0xA22F
-#define	ste_H4_pos 0
-#define	ste_H4_len 7
-#define	ste_H4_lsb 0
-#define xd_r_ste_Corr_value_I_7_0	0xA230
-#define	ste_Corr_value_I_7_0_pos 0
-#define	ste_Corr_value_I_7_0_len 8
-#define	ste_Corr_value_I_7_0_lsb 0
-#define xd_r_ste_Corr_value_I_15_8	0xA231
-#define	ste_Corr_value_I_15_8_pos 0
-#define	ste_Corr_value_I_15_8_len 8
-#define	ste_Corr_value_I_15_8_lsb 8
-#define xd_r_ste_Corr_value_I_23_16	0xA232
-#define	ste_Corr_value_I_23_16_pos 0
-#define	ste_Corr_value_I_23_16_len 8
-#define	ste_Corr_value_I_23_16_lsb 16
-#define xd_r_ste_Corr_value_I_27_24	0xA233
-#define	ste_Corr_value_I_27_24_pos 0
-#define	ste_Corr_value_I_27_24_len 4
-#define	ste_Corr_value_I_27_24_lsb 24
-#define xd_r_ste_Corr_value_Q_7_0	0xA234
-#define	ste_Corr_value_Q_7_0_pos 0
-#define	ste_Corr_value_Q_7_0_len 8
-#define	ste_Corr_value_Q_7_0_lsb 0
-#define xd_r_ste_Corr_value_Q_15_8	0xA235
-#define	ste_Corr_value_Q_15_8_pos 0
-#define	ste_Corr_value_Q_15_8_len 8
-#define	ste_Corr_value_Q_15_8_lsb 8
-#define xd_r_ste_Corr_value_Q_23_16	0xA236
-#define	ste_Corr_value_Q_23_16_pos 0
-#define	ste_Corr_value_Q_23_16_len 8
-#define	ste_Corr_value_Q_23_16_lsb 16
-#define xd_r_ste_Corr_value_Q_27_24	0xA237
-#define	ste_Corr_value_Q_27_24_pos 0
-#define	ste_Corr_value_Q_27_24_len 4
-#define	ste_Corr_value_Q_27_24_lsb 24
-#define xd_r_ste_J_num_7_0	0xA238
-#define	ste_J_num_7_0_pos 0
-#define	ste_J_num_7_0_len 8
-#define	ste_J_num_7_0_lsb 0
-#define xd_r_ste_J_num_15_8	0xA239
-#define	ste_J_num_15_8_pos 0
-#define	ste_J_num_15_8_len 8
-#define	ste_J_num_15_8_lsb 8
-#define xd_r_ste_J_num_23_16	0xA23A
-#define	ste_J_num_23_16_pos 0
-#define	ste_J_num_23_16_len 8
-#define	ste_J_num_23_16_lsb 16
-#define xd_r_ste_J_num_31_24	0xA23B
-#define	ste_J_num_31_24_pos 0
-#define	ste_J_num_31_24_len 8
-#define	ste_J_num_31_24_lsb 24
-#define xd_r_ste_J_den_7_0	0xA23C
-#define	ste_J_den_7_0_pos 0
-#define	ste_J_den_7_0_len 8
-#define	ste_J_den_7_0_lsb 0
-#define xd_r_ste_J_den_15_8	0xA23D
-#define	ste_J_den_15_8_pos 0
-#define	ste_J_den_15_8_len 8
-#define	ste_J_den_15_8_lsb 8
-#define xd_r_ste_J_den_18_16	0xA23E
-#define	ste_J_den_18_16_pos 0
-#define	ste_J_den_18_16_len 3
-#define	ste_J_den_18_16_lsb 16
-#define xd_r_ste_Beacon_Indicator	0xA23E
-#define	ste_Beacon_Indicator_pos 4
-#define	ste_Beacon_Indicator_len 1
-#define	ste_Beacon_Indicator_lsb 0
-#define xd_r_tpsd_Frame_Num	0xA250
-#define	tpsd_Frame_Num_pos 0
-#define	tpsd_Frame_Num_len 2
-#define	tpsd_Frame_Num_lsb 0
-#define xd_r_tpsd_Constel	0xA250
-#define	tpsd_Constel_pos 2
-#define	tpsd_Constel_len 2
-#define	tpsd_Constel_lsb 0
-#define xd_r_tpsd_GI	0xA250
-#define	tpsd_GI_pos 4
-#define	tpsd_GI_len 2
-#define	tpsd_GI_lsb 0
-#define xd_r_tpsd_Mode	0xA250
-#define	tpsd_Mode_pos 6
-#define	tpsd_Mode_len 2
-#define	tpsd_Mode_lsb 0
-#define xd_r_tpsd_CR_HP	0xA251
-#define	tpsd_CR_HP_pos 0
-#define	tpsd_CR_HP_len 3
-#define	tpsd_CR_HP_lsb 0
-#define xd_r_tpsd_CR_LP	0xA251
-#define	tpsd_CR_LP_pos 3
-#define	tpsd_CR_LP_len 3
-#define	tpsd_CR_LP_lsb 0
-#define xd_r_tpsd_Hie	0xA252
-#define	tpsd_Hie_pos 0
-#define	tpsd_Hie_len 3
-#define	tpsd_Hie_lsb 0
-#define xd_r_tpsd_Res_Bits	0xA252
-#define	tpsd_Res_Bits_pos 3
-#define	tpsd_Res_Bits_len 5
-#define	tpsd_Res_Bits_lsb 0
-#define xd_r_tpsd_Res_Bits_0	0xA253
-#define	tpsd_Res_Bits_0_pos 0
-#define	tpsd_Res_Bits_0_len 1
-#define	tpsd_Res_Bits_0_lsb 0
-#define xd_r_tpsd_LengthInd	0xA253
-#define	tpsd_LengthInd_pos 1
-#define	tpsd_LengthInd_len 6
-#define	tpsd_LengthInd_lsb 0
-#define xd_r_tpsd_Cell_Id_7_0	0xA254
-#define	tpsd_Cell_Id_7_0_pos 0
-#define	tpsd_Cell_Id_7_0_len 8
-#define	tpsd_Cell_Id_7_0_lsb 0
-#define xd_r_tpsd_Cell_Id_15_8	0xA255
-#define	tpsd_Cell_Id_15_8_pos 0
-#define	tpsd_Cell_Id_15_8_len 8
-#define	tpsd_Cell_Id_15_8_lsb 0
-#define xd_p_reg_fft_mask_tone0_7_0	0xA260
-#define	reg_fft_mask_tone0_7_0_pos 0
-#define	reg_fft_mask_tone0_7_0_len 8
-#define	reg_fft_mask_tone0_7_0_lsb 0
-#define xd_p_reg_fft_mask_tone0_12_8	0xA261
-#define	reg_fft_mask_tone0_12_8_pos 0
-#define	reg_fft_mask_tone0_12_8_len 5
-#define	reg_fft_mask_tone0_12_8_lsb 8
-#define xd_p_reg_fft_mask_tone1_7_0	0xA262
-#define	reg_fft_mask_tone1_7_0_pos 0
-#define	reg_fft_mask_tone1_7_0_len 8
-#define	reg_fft_mask_tone1_7_0_lsb 0
-#define xd_p_reg_fft_mask_tone1_12_8	0xA263
-#define	reg_fft_mask_tone1_12_8_pos 0
-#define	reg_fft_mask_tone1_12_8_len 5
-#define	reg_fft_mask_tone1_12_8_lsb 8
-#define xd_p_reg_fft_mask_tone2_7_0	0xA264
-#define	reg_fft_mask_tone2_7_0_pos 0
-#define	reg_fft_mask_tone2_7_0_len 8
-#define	reg_fft_mask_tone2_7_0_lsb 0
-#define xd_p_reg_fft_mask_tone2_12_8	0xA265
-#define	reg_fft_mask_tone2_12_8_pos 0
-#define	reg_fft_mask_tone2_12_8_len 5
-#define	reg_fft_mask_tone2_12_8_lsb 8
-#define xd_p_reg_fft_mask_tone3_7_0	0xA266
-#define	reg_fft_mask_tone3_7_0_pos 0
-#define	reg_fft_mask_tone3_7_0_len 8
-#define	reg_fft_mask_tone3_7_0_lsb 0
-#define xd_p_reg_fft_mask_tone3_12_8	0xA267
-#define	reg_fft_mask_tone3_12_8_pos 0
-#define	reg_fft_mask_tone3_12_8_len 5
-#define	reg_fft_mask_tone3_12_8_lsb 8
-#define xd_p_reg_fft_mask_from0_7_0	0xA268
-#define	reg_fft_mask_from0_7_0_pos 0
-#define	reg_fft_mask_from0_7_0_len 8
-#define	reg_fft_mask_from0_7_0_lsb 0
-#define xd_p_reg_fft_mask_from0_12_8	0xA269
-#define	reg_fft_mask_from0_12_8_pos 0
-#define	reg_fft_mask_from0_12_8_len 5
-#define	reg_fft_mask_from0_12_8_lsb 8
-#define xd_p_reg_fft_mask_to0_7_0	0xA26A
-#define	reg_fft_mask_to0_7_0_pos 0
-#define	reg_fft_mask_to0_7_0_len 8
-#define	reg_fft_mask_to0_7_0_lsb 0
-#define xd_p_reg_fft_mask_to0_12_8	0xA26B
-#define	reg_fft_mask_to0_12_8_pos 0
-#define	reg_fft_mask_to0_12_8_len 5
-#define	reg_fft_mask_to0_12_8_lsb 8
-#define xd_p_reg_fft_mask_from1_7_0	0xA26C
-#define	reg_fft_mask_from1_7_0_pos 0
-#define	reg_fft_mask_from1_7_0_len 8
-#define	reg_fft_mask_from1_7_0_lsb 0
-#define xd_p_reg_fft_mask_from1_12_8	0xA26D
-#define	reg_fft_mask_from1_12_8_pos 0
-#define	reg_fft_mask_from1_12_8_len 5
-#define	reg_fft_mask_from1_12_8_lsb 8
-#define xd_p_reg_fft_mask_to1_7_0	0xA26E
-#define	reg_fft_mask_to1_7_0_pos 0
-#define	reg_fft_mask_to1_7_0_len 8
-#define	reg_fft_mask_to1_7_0_lsb 0
-#define xd_p_reg_fft_mask_to1_12_8	0xA26F
-#define	reg_fft_mask_to1_12_8_pos 0
-#define	reg_fft_mask_to1_12_8_len 5
-#define	reg_fft_mask_to1_12_8_lsb 8
-#define xd_p_reg_cge_idx0_7_0	0xA280
-#define	reg_cge_idx0_7_0_pos 0
-#define	reg_cge_idx0_7_0_len 8
-#define	reg_cge_idx0_7_0_lsb 0
-#define xd_p_reg_cge_idx0_12_8	0xA281
-#define	reg_cge_idx0_12_8_pos 0
-#define	reg_cge_idx0_12_8_len 5
-#define	reg_cge_idx0_12_8_lsb 8
-#define xd_p_reg_cge_idx1_7_0	0xA282
-#define	reg_cge_idx1_7_0_pos 0
-#define	reg_cge_idx1_7_0_len 8
-#define	reg_cge_idx1_7_0_lsb 0
-#define xd_p_reg_cge_idx1_12_8	0xA283
-#define	reg_cge_idx1_12_8_pos 0
-#define	reg_cge_idx1_12_8_len 5
-#define	reg_cge_idx1_12_8_lsb 8
-#define xd_p_reg_cge_idx2_7_0	0xA284
-#define	reg_cge_idx2_7_0_pos 0
-#define	reg_cge_idx2_7_0_len 8
-#define	reg_cge_idx2_7_0_lsb 0
-#define xd_p_reg_cge_idx2_12_8	0xA285
-#define	reg_cge_idx2_12_8_pos 0
-#define	reg_cge_idx2_12_8_len 5
-#define	reg_cge_idx2_12_8_lsb 8
-#define xd_p_reg_cge_idx3_7_0	0xA286
-#define	reg_cge_idx3_7_0_pos 0
-#define	reg_cge_idx3_7_0_len 8
-#define	reg_cge_idx3_7_0_lsb 0
-#define xd_p_reg_cge_idx3_12_8	0xA287
-#define	reg_cge_idx3_12_8_pos 0
-#define	reg_cge_idx3_12_8_len 5
-#define	reg_cge_idx3_12_8_lsb 8
-#define xd_p_reg_cge_idx4_7_0	0xA288
-#define	reg_cge_idx4_7_0_pos 0
-#define	reg_cge_idx4_7_0_len 8
-#define	reg_cge_idx4_7_0_lsb 0
-#define xd_p_reg_cge_idx4_12_8	0xA289
-#define	reg_cge_idx4_12_8_pos 0
-#define	reg_cge_idx4_12_8_len 5
-#define	reg_cge_idx4_12_8_lsb 8
-#define xd_p_reg_cge_idx5_7_0	0xA28A
-#define	reg_cge_idx5_7_0_pos 0
-#define	reg_cge_idx5_7_0_len 8
-#define	reg_cge_idx5_7_0_lsb 0
-#define xd_p_reg_cge_idx5_12_8	0xA28B
-#define	reg_cge_idx5_12_8_pos 0
-#define	reg_cge_idx5_12_8_len 5
-#define	reg_cge_idx5_12_8_lsb 8
-#define xd_p_reg_cge_idx6_7_0	0xA28C
-#define	reg_cge_idx6_7_0_pos 0
-#define	reg_cge_idx6_7_0_len 8
-#define	reg_cge_idx6_7_0_lsb 0
-#define xd_p_reg_cge_idx6_12_8	0xA28D
-#define	reg_cge_idx6_12_8_pos 0
-#define	reg_cge_idx6_12_8_len 5
-#define	reg_cge_idx6_12_8_lsb 8
-#define xd_p_reg_cge_idx7_7_0	0xA28E
-#define	reg_cge_idx7_7_0_pos 0
-#define	reg_cge_idx7_7_0_len 8
-#define	reg_cge_idx7_7_0_lsb 0
-#define xd_p_reg_cge_idx7_12_8	0xA28F
-#define	reg_cge_idx7_12_8_pos 0
-#define	reg_cge_idx7_12_8_len 5
-#define	reg_cge_idx7_12_8_lsb 8
-#define xd_p_reg_cge_idx8_7_0	0xA290
-#define	reg_cge_idx8_7_0_pos 0
-#define	reg_cge_idx8_7_0_len 8
-#define	reg_cge_idx8_7_0_lsb 0
-#define xd_p_reg_cge_idx8_12_8	0xA291
-#define	reg_cge_idx8_12_8_pos 0
-#define	reg_cge_idx8_12_8_len 5
-#define	reg_cge_idx8_12_8_lsb 8
-#define xd_p_reg_cge_idx9_7_0	0xA292
-#define	reg_cge_idx9_7_0_pos 0
-#define	reg_cge_idx9_7_0_len 8
-#define	reg_cge_idx9_7_0_lsb 0
-#define xd_p_reg_cge_idx9_12_8	0xA293
-#define	reg_cge_idx9_12_8_pos 0
-#define	reg_cge_idx9_12_8_len 5
-#define	reg_cge_idx9_12_8_lsb 8
-#define xd_p_reg_cge_idx10_7_0	0xA294
-#define	reg_cge_idx10_7_0_pos 0
-#define	reg_cge_idx10_7_0_len 8
-#define	reg_cge_idx10_7_0_lsb 0
-#define xd_p_reg_cge_idx10_12_8	0xA295
-#define	reg_cge_idx10_12_8_pos 0
-#define	reg_cge_idx10_12_8_len 5
-#define	reg_cge_idx10_12_8_lsb 8
-#define xd_p_reg_cge_idx11_7_0	0xA296
-#define	reg_cge_idx11_7_0_pos 0
-#define	reg_cge_idx11_7_0_len 8
-#define	reg_cge_idx11_7_0_lsb 0
-#define xd_p_reg_cge_idx11_12_8	0xA297
-#define	reg_cge_idx11_12_8_pos 0
-#define	reg_cge_idx11_12_8_len 5
-#define	reg_cge_idx11_12_8_lsb 8
-#define xd_p_reg_cge_idx12_7_0	0xA298
-#define	reg_cge_idx12_7_0_pos 0
-#define	reg_cge_idx12_7_0_len 8
-#define	reg_cge_idx12_7_0_lsb 0
-#define xd_p_reg_cge_idx12_12_8	0xA299
-#define	reg_cge_idx12_12_8_pos 0
-#define	reg_cge_idx12_12_8_len 5
-#define	reg_cge_idx12_12_8_lsb 8
-#define xd_p_reg_cge_idx13_7_0	0xA29A
-#define	reg_cge_idx13_7_0_pos 0
-#define	reg_cge_idx13_7_0_len 8
-#define	reg_cge_idx13_7_0_lsb 0
-#define xd_p_reg_cge_idx13_12_8	0xA29B
-#define	reg_cge_idx13_12_8_pos 0
-#define	reg_cge_idx13_12_8_len 5
-#define	reg_cge_idx13_12_8_lsb 8
-#define xd_p_reg_cge_idx14_7_0	0xA29C
-#define	reg_cge_idx14_7_0_pos 0
-#define	reg_cge_idx14_7_0_len 8
-#define	reg_cge_idx14_7_0_lsb 0
-#define xd_p_reg_cge_idx14_12_8	0xA29D
-#define	reg_cge_idx14_12_8_pos 0
-#define	reg_cge_idx14_12_8_len 5
-#define	reg_cge_idx14_12_8_lsb 8
-#define xd_p_reg_cge_idx15_7_0	0xA29E
-#define	reg_cge_idx15_7_0_pos 0
-#define	reg_cge_idx15_7_0_len 8
-#define	reg_cge_idx15_7_0_lsb 0
-#define xd_p_reg_cge_idx15_12_8	0xA29F
-#define	reg_cge_idx15_12_8_pos 0
-#define	reg_cge_idx15_12_8_len 5
-#define	reg_cge_idx15_12_8_lsb 8
-#define xd_r_reg_fft_crc	0xA2A8
-#define	reg_fft_crc_pos 0
-#define	reg_fft_crc_len 8
-#define	reg_fft_crc_lsb 0
-#define xd_p_fd_fft_shift_max	0xA2A9
-#define	fd_fft_shift_max_pos 0
-#define	fd_fft_shift_max_len 4
-#define	fd_fft_shift_max_lsb 0
-#define xd_r_fd_fft_shift	0xA2A9
-#define	fd_fft_shift_pos 4
-#define	fd_fft_shift_len 4
-#define	fd_fft_shift_lsb 0
-#define xd_r_fd_fft_frame_num	0xA2AA
-#define	fd_fft_frame_num_pos 0
-#define	fd_fft_frame_num_len 2
-#define	fd_fft_frame_num_lsb 0
-#define xd_r_fd_fft_symbol_count	0xA2AB
-#define	fd_fft_symbol_count_pos 0
-#define	fd_fft_symbol_count_len 7
-#define	fd_fft_symbol_count_lsb 0
-#define xd_r_reg_fft_idx_max_7_0	0xA2AC
-#define	reg_fft_idx_max_7_0_pos 0
-#define	reg_fft_idx_max_7_0_len 8
-#define	reg_fft_idx_max_7_0_lsb 0
-#define xd_r_reg_fft_idx_max_12_8	0xA2AD
-#define	reg_fft_idx_max_12_8_pos 0
-#define	reg_fft_idx_max_12_8_len 5
-#define	reg_fft_idx_max_12_8_lsb 8
-#define xd_p_reg_cge_program	0xA2AE
-#define	reg_cge_program_pos 0
-#define	reg_cge_program_len 1
-#define	reg_cge_program_lsb 0
-#define xd_p_reg_cge_fixed	0xA2AE
-#define	reg_cge_fixed_pos 1
-#define	reg_cge_fixed_len 1
-#define	reg_cge_fixed_lsb 0
-#define xd_p_reg_fft_rotate_en	0xA2AE
-#define	reg_fft_rotate_en_pos 2
-#define	reg_fft_rotate_en_len 1
-#define	reg_fft_rotate_en_lsb 0
-#define xd_p_reg_fft_rotate_base_4_0	0xA2AE
-#define	reg_fft_rotate_base_4_0_pos 3
-#define	reg_fft_rotate_base_4_0_len 5
-#define	reg_fft_rotate_base_4_0_lsb 0
-#define xd_p_reg_fft_rotate_base_12_5	0xA2AF
-#define	reg_fft_rotate_base_12_5_pos 0
-#define	reg_fft_rotate_base_12_5_len 8
-#define	reg_fft_rotate_base_12_5_lsb 5
-#define xd_p_reg_gp_trigger_fd	0xA2B8
-#define	reg_gp_trigger_fd_pos 0
-#define	reg_gp_trigger_fd_len 1
-#define	reg_gp_trigger_fd_lsb 0
-#define xd_p_reg_trigger_sel_fd	0xA2B8
-#define	reg_trigger_sel_fd_pos 1
-#define	reg_trigger_sel_fd_len 2
-#define	reg_trigger_sel_fd_lsb 0
-#define xd_p_reg_trigger_module_sel_fd	0xA2B9
-#define	reg_trigger_module_sel_fd_pos 0
-#define	reg_trigger_module_sel_fd_len 6
-#define	reg_trigger_module_sel_fd_lsb 0
-#define xd_p_reg_trigger_set_sel_fd	0xA2BA
-#define	reg_trigger_set_sel_fd_pos 0
-#define	reg_trigger_set_sel_fd_len 6
-#define	reg_trigger_set_sel_fd_lsb 0
-#define xd_p_reg_fd_noname_7_0	0xA2BC
-#define	reg_fd_noname_7_0_pos 0
-#define	reg_fd_noname_7_0_len 8
-#define	reg_fd_noname_7_0_lsb 0
-#define xd_p_reg_fd_noname_15_8	0xA2BD
-#define	reg_fd_noname_15_8_pos 0
-#define	reg_fd_noname_15_8_len 8
-#define	reg_fd_noname_15_8_lsb 8
-#define xd_p_reg_fd_noname_23_16	0xA2BE
-#define	reg_fd_noname_23_16_pos 0
-#define	reg_fd_noname_23_16_len 8
-#define	reg_fd_noname_23_16_lsb 16
-#define xd_p_reg_fd_noname_31_24	0xA2BF
-#define	reg_fd_noname_31_24_pos 0
-#define	reg_fd_noname_31_24_len 8
-#define	reg_fd_noname_31_24_lsb 24
-#define xd_r_fd_fpcc_cp_corr_signn	0xA2C0
-#define	fd_fpcc_cp_corr_signn_pos 0
-#define	fd_fpcc_cp_corr_signn_len 8
-#define	fd_fpcc_cp_corr_signn_lsb 0
-#define xd_p_reg_feq_s1	0xA2C1
-#define	reg_feq_s1_pos 0
-#define	reg_feq_s1_len 5
-#define	reg_feq_s1_lsb 0
-#define xd_p_fd_fpcc_cp_corr_tone_th	0xA2C2
-#define	fd_fpcc_cp_corr_tone_th_pos 0
-#define	fd_fpcc_cp_corr_tone_th_len 6
-#define	fd_fpcc_cp_corr_tone_th_lsb 0
-#define xd_p_fd_fpcc_cp_corr_symbol_log_th	0xA2C3
-#define	fd_fpcc_cp_corr_symbol_log_th_pos 0
-#define	fd_fpcc_cp_corr_symbol_log_th_len 4
-#define	fd_fpcc_cp_corr_symbol_log_th_lsb 0
-#define xd_p_fd_fpcc_cp_corr_int	0xA2C4
-#define	fd_fpcc_cp_corr_int_pos 0
-#define	fd_fpcc_cp_corr_int_len 1
-#define	fd_fpcc_cp_corr_int_lsb 0
-#define xd_p_reg_sfoe_ns_7_0	0xA320
-#define	reg_sfoe_ns_7_0_pos 0
-#define	reg_sfoe_ns_7_0_len 8
-#define	reg_sfoe_ns_7_0_lsb 0
-#define xd_p_reg_sfoe_ns_14_8	0xA321
-#define	reg_sfoe_ns_14_8_pos 0
-#define	reg_sfoe_ns_14_8_len 7
-#define	reg_sfoe_ns_14_8_lsb 8
-#define xd_p_reg_sfoe_c1_7_0	0xA322
-#define	reg_sfoe_c1_7_0_pos 0
-#define	reg_sfoe_c1_7_0_len 8
-#define	reg_sfoe_c1_7_0_lsb 0
-#define xd_p_reg_sfoe_c1_15_8	0xA323
-#define	reg_sfoe_c1_15_8_pos 0
-#define	reg_sfoe_c1_15_8_len 8
-#define	reg_sfoe_c1_15_8_lsb 8
-#define xd_p_reg_sfoe_c1_17_16	0xA324
-#define	reg_sfoe_c1_17_16_pos 0
-#define	reg_sfoe_c1_17_16_len 2
-#define	reg_sfoe_c1_17_16_lsb 16
-#define xd_p_reg_sfoe_c2_7_0	0xA325
-#define	reg_sfoe_c2_7_0_pos 0
-#define	reg_sfoe_c2_7_0_len 8
-#define	reg_sfoe_c2_7_0_lsb 0
-#define xd_p_reg_sfoe_c2_15_8	0xA326
-#define	reg_sfoe_c2_15_8_pos 0
-#define	reg_sfoe_c2_15_8_len 8
-#define	reg_sfoe_c2_15_8_lsb 8
-#define xd_p_reg_sfoe_c2_17_16	0xA327
-#define	reg_sfoe_c2_17_16_pos 0
-#define	reg_sfoe_c2_17_16_len 2
-#define	reg_sfoe_c2_17_16_lsb 16
-#define xd_r_reg_sfoe_out_9_2	0xA328
-#define	reg_sfoe_out_9_2_pos 0
-#define	reg_sfoe_out_9_2_len 8
-#define	reg_sfoe_out_9_2_lsb 0
-#define xd_r_reg_sfoe_out_1_0	0xA329
-#define	reg_sfoe_out_1_0_pos 0
-#define	reg_sfoe_out_1_0_len 2
-#define	reg_sfoe_out_1_0_lsb 0
-#define xd_p_reg_sfoe_lm_counter_th	0xA32A
-#define	reg_sfoe_lm_counter_th_pos 0
-#define	reg_sfoe_lm_counter_th_len 4
-#define	reg_sfoe_lm_counter_th_lsb 0
-#define xd_p_reg_sfoe_convg_th	0xA32B
-#define	reg_sfoe_convg_th_pos 0
-#define	reg_sfoe_convg_th_len 8
-#define	reg_sfoe_convg_th_lsb 0
-#define xd_p_reg_sfoe_divg_th	0xA32C
-#define	reg_sfoe_divg_th_pos 0
-#define	reg_sfoe_divg_th_len 8
-#define	reg_sfoe_divg_th_lsb 0
-#define xd_p_fd_tpsd_en	0xA330
-#define	fd_tpsd_en_pos 0
-#define	fd_tpsd_en_len 1
-#define	fd_tpsd_en_lsb 0
-#define xd_p_fd_tpsd_dis	0xA330
-#define	fd_tpsd_dis_pos 1
-#define	fd_tpsd_dis_len 1
-#define	fd_tpsd_dis_lsb 0
-#define xd_p_fd_tpsd_rst	0xA330
-#define	fd_tpsd_rst_pos 2
-#define	fd_tpsd_rst_len 1
-#define	fd_tpsd_rst_lsb 0
-#define xd_p_fd_tpsd_lock	0xA330
-#define	fd_tpsd_lock_pos 3
-#define	fd_tpsd_lock_len 1
-#define	fd_tpsd_lock_lsb 0
-#define xd_r_fd_tpsd_s19	0xA330
-#define	fd_tpsd_s19_pos 4
-#define	fd_tpsd_s19_len 1
-#define	fd_tpsd_s19_lsb 0
-#define xd_r_fd_tpsd_s17	0xA330
-#define	fd_tpsd_s17_pos 5
-#define	fd_tpsd_s17_len 1
-#define	fd_tpsd_s17_lsb 0
-#define xd_p_fd_sfr_ste_en	0xA331
-#define	fd_sfr_ste_en_pos 0
-#define	fd_sfr_ste_en_len 1
-#define	fd_sfr_ste_en_lsb 0
-#define xd_p_fd_sfr_ste_dis	0xA331
-#define	fd_sfr_ste_dis_pos 1
-#define	fd_sfr_ste_dis_len 1
-#define	fd_sfr_ste_dis_lsb 0
-#define xd_p_fd_sfr_ste_rst	0xA331
-#define	fd_sfr_ste_rst_pos 2
-#define	fd_sfr_ste_rst_len 1
-#define	fd_sfr_ste_rst_lsb 0
-#define xd_p_fd_sfr_ste_mode	0xA331
-#define	fd_sfr_ste_mode_pos 3
-#define	fd_sfr_ste_mode_len 1
-#define	fd_sfr_ste_mode_lsb 0
-#define xd_p_fd_sfr_ste_done	0xA331
-#define	fd_sfr_ste_done_pos 4
-#define	fd_sfr_ste_done_len 1
-#define	fd_sfr_ste_done_lsb 0
-#define xd_p_reg_cfoe_ffoe_en	0xA332
-#define	reg_cfoe_ffoe_en_pos 0
-#define	reg_cfoe_ffoe_en_len 1
-#define	reg_cfoe_ffoe_en_lsb 0
-#define xd_p_reg_cfoe_ffoe_dis	0xA332
-#define	reg_cfoe_ffoe_dis_pos 1
-#define	reg_cfoe_ffoe_dis_len 1
-#define	reg_cfoe_ffoe_dis_lsb 0
-#define xd_p_reg_cfoe_ffoe_rst	0xA332
-#define	reg_cfoe_ffoe_rst_pos 2
-#define	reg_cfoe_ffoe_rst_len 1
-#define	reg_cfoe_ffoe_rst_lsb 0
-#define xd_p_reg_cfoe_ifoe_en	0xA332
-#define	reg_cfoe_ifoe_en_pos 3
-#define	reg_cfoe_ifoe_en_len 1
-#define	reg_cfoe_ifoe_en_lsb 0
-#define xd_p_reg_cfoe_ifoe_dis	0xA332
-#define	reg_cfoe_ifoe_dis_pos 4
-#define	reg_cfoe_ifoe_dis_len 1
-#define	reg_cfoe_ifoe_dis_lsb 0
-#define xd_p_reg_cfoe_ifoe_rst	0xA332
-#define	reg_cfoe_ifoe_rst_pos 5
-#define	reg_cfoe_ifoe_rst_len 1
-#define	reg_cfoe_ifoe_rst_lsb 0
-#define xd_p_reg_cfoe_fot_en	0xA332
-#define	reg_cfoe_fot_en_pos 6
-#define	reg_cfoe_fot_en_len 1
-#define	reg_cfoe_fot_en_lsb 0
-#define xd_p_reg_cfoe_fot_lm_en	0xA332
-#define	reg_cfoe_fot_lm_en_pos 7
-#define	reg_cfoe_fot_lm_en_len 1
-#define	reg_cfoe_fot_lm_en_lsb 0
-#define xd_p_reg_cfoe_fot_rst	0xA333
-#define	reg_cfoe_fot_rst_pos 0
-#define	reg_cfoe_fot_rst_len 1
-#define	reg_cfoe_fot_rst_lsb 0
-#define xd_r_fd_cfoe_ffoe_done	0xA333
-#define	fd_cfoe_ffoe_done_pos 1
-#define	fd_cfoe_ffoe_done_len 1
-#define	fd_cfoe_ffoe_done_lsb 0
-#define xd_p_fd_cfoe_metric_vld	0xA333
-#define	fd_cfoe_metric_vld_pos 2
-#define	fd_cfoe_metric_vld_len 1
-#define	fd_cfoe_metric_vld_lsb 0
-#define xd_p_reg_cfoe_ifod_vld	0xA333
-#define	reg_cfoe_ifod_vld_pos 3
-#define	reg_cfoe_ifod_vld_len 1
-#define	reg_cfoe_ifod_vld_lsb 0
-#define xd_r_fd_cfoe_ifoe_done	0xA333
-#define	fd_cfoe_ifoe_done_pos 4
-#define	fd_cfoe_ifoe_done_len 1
-#define	fd_cfoe_ifoe_done_lsb 0
-#define xd_r_fd_cfoe_fot_valid	0xA333
-#define	fd_cfoe_fot_valid_pos 5
-#define	fd_cfoe_fot_valid_len 1
-#define	fd_cfoe_fot_valid_lsb 0
-#define xd_p_reg_cfoe_divg_int	0xA333
-#define	reg_cfoe_divg_int_pos 6
-#define	reg_cfoe_divg_int_len 1
-#define	reg_cfoe_divg_int_lsb 0
-#define xd_r_reg_cfoe_divg_flag	0xA333
-#define	reg_cfoe_divg_flag_pos 7
-#define	reg_cfoe_divg_flag_len 1
-#define	reg_cfoe_divg_flag_lsb 0
-#define xd_p_reg_sfoe_en	0xA334
-#define	reg_sfoe_en_pos 0
-#define	reg_sfoe_en_len 1
-#define	reg_sfoe_en_lsb 0
-#define xd_p_reg_sfoe_dis	0xA334
-#define	reg_sfoe_dis_pos 1
-#define	reg_sfoe_dis_len 1
-#define	reg_sfoe_dis_lsb 0
-#define xd_p_reg_sfoe_rst	0xA334
-#define	reg_sfoe_rst_pos 2
-#define	reg_sfoe_rst_len 1
-#define	reg_sfoe_rst_lsb 0
-#define xd_p_reg_sfoe_vld_int	0xA334
-#define	reg_sfoe_vld_int_pos 3
-#define	reg_sfoe_vld_int_len 1
-#define	reg_sfoe_vld_int_lsb 0
-#define xd_p_reg_sfoe_lm_en	0xA334
-#define	reg_sfoe_lm_en_pos 4
-#define	reg_sfoe_lm_en_len 1
-#define	reg_sfoe_lm_en_lsb 0
-#define xd_p_reg_sfoe_divg_int	0xA334
-#define	reg_sfoe_divg_int_pos 5
-#define	reg_sfoe_divg_int_len 1
-#define	reg_sfoe_divg_int_lsb 0
-#define xd_r_reg_sfoe_divg_flag	0xA334
-#define	reg_sfoe_divg_flag_pos 6
-#define	reg_sfoe_divg_flag_len 1
-#define	reg_sfoe_divg_flag_lsb 0
-#define xd_p_reg_fft_rst	0xA335
-#define	reg_fft_rst_pos 0
-#define	reg_fft_rst_len 1
-#define	reg_fft_rst_lsb 0
-#define xd_p_reg_fft_fast_beacon	0xA335
-#define	reg_fft_fast_beacon_pos 1
-#define	reg_fft_fast_beacon_len 1
-#define	reg_fft_fast_beacon_lsb 0
-#define xd_p_reg_fft_fast_valid	0xA335
-#define	reg_fft_fast_valid_pos 2
-#define	reg_fft_fast_valid_len 1
-#define	reg_fft_fast_valid_lsb 0
-#define xd_p_reg_fft_mask_en	0xA335
-#define	reg_fft_mask_en_pos 3
-#define	reg_fft_mask_en_len 1
-#define	reg_fft_mask_en_lsb 0
-#define xd_p_reg_fft_crc_en	0xA335
-#define	reg_fft_crc_en_pos 4
-#define	reg_fft_crc_en_len 1
-#define	reg_fft_crc_en_lsb 0
-#define xd_p_reg_finr_en	0xA336
-#define	reg_finr_en_pos 0
-#define	reg_finr_en_len 1
-#define	reg_finr_en_lsb 0
-#define xd_p_fd_fste_en	0xA337
-#define	fd_fste_en_pos 1
-#define	fd_fste_en_len 1
-#define	fd_fste_en_lsb 0
-#define xd_p_fd_sqi_tps_level_shift	0xA338
-#define	fd_sqi_tps_level_shift_pos 0
-#define	fd_sqi_tps_level_shift_len 8
-#define	fd_sqi_tps_level_shift_lsb 0
-#define xd_p_fd_pilot_ma_len	0xA339
-#define	fd_pilot_ma_len_pos 0
-#define	fd_pilot_ma_len_len 6
-#define	fd_pilot_ma_len_lsb 0
-#define xd_p_fd_tps_ma_len	0xA33A
-#define	fd_tps_ma_len_pos 0
-#define	fd_tps_ma_len_len 6
-#define	fd_tps_ma_len_lsb 0
-#define xd_p_fd_sqi_s3	0xA33B
-#define	fd_sqi_s3_pos 0
-#define	fd_sqi_s3_len 8
-#define	fd_sqi_s3_lsb 0
-#define xd_p_fd_sqi_dummy_reg_0	0xA33C
-#define	fd_sqi_dummy_reg_0_pos 0
-#define	fd_sqi_dummy_reg_0_len 1
-#define	fd_sqi_dummy_reg_0_lsb 0
-#define xd_p_fd_sqi_debug_sel	0xA33C
-#define	fd_sqi_debug_sel_pos 1
-#define	fd_sqi_debug_sel_len 2
-#define	fd_sqi_debug_sel_lsb 0
-#define xd_p_fd_sqi_s2	0xA33C
-#define	fd_sqi_s2_pos 3
-#define	fd_sqi_s2_len 5
-#define	fd_sqi_s2_lsb 0
-#define xd_p_fd_sqi_dummy_reg_1	0xA33D
-#define	fd_sqi_dummy_reg_1_pos 0
-#define	fd_sqi_dummy_reg_1_len 1
-#define	fd_sqi_dummy_reg_1_lsb 0
-#define xd_p_fd_inr_ignore	0xA33D
-#define	fd_inr_ignore_pos 1
-#define	fd_inr_ignore_len 1
-#define	fd_inr_ignore_lsb 0
-#define xd_p_fd_pilot_ignore	0xA33D
-#define	fd_pilot_ignore_pos 2
-#define	fd_pilot_ignore_len 1
-#define	fd_pilot_ignore_lsb 0
-#define xd_p_fd_etps_ignore	0xA33D
-#define	fd_etps_ignore_pos 3
-#define	fd_etps_ignore_len 1
-#define	fd_etps_ignore_lsb 0
-#define xd_p_fd_sqi_s1	0xA33D
-#define	fd_sqi_s1_pos 4
-#define	fd_sqi_s1_len 4
-#define	fd_sqi_s1_lsb 0
-#define xd_p_reg_fste_ehw_7_0	0xA33E
-#define	reg_fste_ehw_7_0_pos 0
-#define	reg_fste_ehw_7_0_len 8
-#define	reg_fste_ehw_7_0_lsb 0
-#define xd_p_reg_fste_ehw_9_8	0xA33F
-#define	reg_fste_ehw_9_8_pos 0
-#define	reg_fste_ehw_9_8_len 2
-#define	reg_fste_ehw_9_8_lsb 8
-#define xd_p_reg_fste_i_adj_vld	0xA33F
-#define	reg_fste_i_adj_vld_pos 2
-#define	reg_fste_i_adj_vld_len 1
-#define	reg_fste_i_adj_vld_lsb 0
-#define xd_p_reg_fste_phase_ini_7_0	0xA340
-#define	reg_fste_phase_ini_7_0_pos 0
-#define	reg_fste_phase_ini_7_0_len 8
-#define	reg_fste_phase_ini_7_0_lsb 0
-#define xd_p_reg_fste_phase_ini_11_8	0xA341
-#define	reg_fste_phase_ini_11_8_pos 0
-#define	reg_fste_phase_ini_11_8_len 4
-#define	reg_fste_phase_ini_11_8_lsb 8
-#define xd_p_reg_fste_phase_inc_3_0	0xA341
-#define	reg_fste_phase_inc_3_0_pos 4
-#define	reg_fste_phase_inc_3_0_len 4
-#define	reg_fste_phase_inc_3_0_lsb 0
-#define xd_p_reg_fste_phase_inc_11_4	0xA342
-#define	reg_fste_phase_inc_11_4_pos 0
-#define	reg_fste_phase_inc_11_4_len 8
-#define	reg_fste_phase_inc_11_4_lsb 4
-#define xd_p_reg_fste_acum_cost_cnt_max	0xA343
-#define	reg_fste_acum_cost_cnt_max_pos 0
-#define	reg_fste_acum_cost_cnt_max_len 4
-#define	reg_fste_acum_cost_cnt_max_lsb 0
-#define xd_p_reg_fste_step_size_std	0xA343
-#define	reg_fste_step_size_std_pos 4
-#define	reg_fste_step_size_std_len 4
-#define	reg_fste_step_size_std_lsb 0
-#define xd_p_reg_fste_step_size_max	0xA344
-#define	reg_fste_step_size_max_pos 0
-#define	reg_fste_step_size_max_len 4
-#define	reg_fste_step_size_max_lsb 0
-#define xd_p_reg_fste_step_size_min	0xA344
-#define	reg_fste_step_size_min_pos 4
-#define	reg_fste_step_size_min_len 4
-#define	reg_fste_step_size_min_lsb 0
-#define xd_p_reg_fste_frac_step_size_7_0	0xA345
-#define	reg_fste_frac_step_size_7_0_pos 0
-#define	reg_fste_frac_step_size_7_0_len 8
-#define	reg_fste_frac_step_size_7_0_lsb 0
-#define xd_p_reg_fste_frac_step_size_15_8	0xA346
-#define	reg_fste_frac_step_size_15_8_pos 0
-#define	reg_fste_frac_step_size_15_8_len 8
-#define	reg_fste_frac_step_size_15_8_lsb 8
-#define xd_p_reg_fste_frac_step_size_19_16	0xA347
-#define	reg_fste_frac_step_size_19_16_pos 0
-#define	reg_fste_frac_step_size_19_16_len 4
-#define	reg_fste_frac_step_size_19_16_lsb 16
-#define xd_p_reg_fste_rpd_dir_cnt_max	0xA347
-#define	reg_fste_rpd_dir_cnt_max_pos 4
-#define	reg_fste_rpd_dir_cnt_max_len 4
-#define	reg_fste_rpd_dir_cnt_max_lsb 0
-#define xd_p_reg_fste_ehs	0xA348
-#define	reg_fste_ehs_pos 0
-#define	reg_fste_ehs_len 4
-#define	reg_fste_ehs_lsb 0
-#define xd_p_reg_fste_frac_cost_cnt_max_3_0	0xA348
-#define	reg_fste_frac_cost_cnt_max_3_0_pos 4
-#define	reg_fste_frac_cost_cnt_max_3_0_len 4
-#define	reg_fste_frac_cost_cnt_max_3_0_lsb 0
-#define xd_p_reg_fste_frac_cost_cnt_max_9_4	0xA349
-#define	reg_fste_frac_cost_cnt_max_9_4_pos 0
-#define	reg_fste_frac_cost_cnt_max_9_4_len 6
-#define	reg_fste_frac_cost_cnt_max_9_4_lsb 4
-#define xd_p_reg_fste_w0_7_0	0xA34A
-#define	reg_fste_w0_7_0_pos 0
-#define	reg_fste_w0_7_0_len 8
-#define	reg_fste_w0_7_0_lsb 0
-#define xd_p_reg_fste_w0_11_8	0xA34B
-#define	reg_fste_w0_11_8_pos 0
-#define	reg_fste_w0_11_8_len 4
-#define	reg_fste_w0_11_8_lsb 8
-#define xd_p_reg_fste_w1_3_0	0xA34B
-#define	reg_fste_w1_3_0_pos 4
-#define	reg_fste_w1_3_0_len 4
-#define	reg_fste_w1_3_0_lsb 0
-#define xd_p_reg_fste_w1_11_4	0xA34C
-#define	reg_fste_w1_11_4_pos 0
-#define	reg_fste_w1_11_4_len 8
-#define	reg_fste_w1_11_4_lsb 4
-#define xd_p_reg_fste_w2_7_0	0xA34D
-#define	reg_fste_w2_7_0_pos 0
-#define	reg_fste_w2_7_0_len 8
-#define	reg_fste_w2_7_0_lsb 0
-#define xd_p_reg_fste_w2_11_8	0xA34E
-#define	reg_fste_w2_11_8_pos 0
-#define	reg_fste_w2_11_8_len 4
-#define	reg_fste_w2_11_8_lsb 8
-#define xd_p_reg_fste_w3_3_0	0xA34E
-#define	reg_fste_w3_3_0_pos 4
-#define	reg_fste_w3_3_0_len 4
-#define	reg_fste_w3_3_0_lsb 0
-#define xd_p_reg_fste_w3_11_4	0xA34F
-#define	reg_fste_w3_11_4_pos 0
-#define	reg_fste_w3_11_4_len 8
-#define	reg_fste_w3_11_4_lsb 4
-#define xd_p_reg_fste_w4_7_0	0xA350
-#define	reg_fste_w4_7_0_pos 0
-#define	reg_fste_w4_7_0_len 8
-#define	reg_fste_w4_7_0_lsb 0
-#define xd_p_reg_fste_w4_11_8	0xA351
-#define	reg_fste_w4_11_8_pos 0
-#define	reg_fste_w4_11_8_len 4
-#define	reg_fste_w4_11_8_lsb 8
-#define xd_p_reg_fste_w5_3_0	0xA351
-#define	reg_fste_w5_3_0_pos 4
-#define	reg_fste_w5_3_0_len 4
-#define	reg_fste_w5_3_0_lsb 0
-#define xd_p_reg_fste_w5_11_4	0xA352
-#define	reg_fste_w5_11_4_pos 0
-#define	reg_fste_w5_11_4_len 8
-#define	reg_fste_w5_11_4_lsb 4
-#define xd_p_reg_fste_w6_7_0	0xA353
-#define	reg_fste_w6_7_0_pos 0
-#define	reg_fste_w6_7_0_len 8
-#define	reg_fste_w6_7_0_lsb 0
-#define xd_p_reg_fste_w6_11_8	0xA354
-#define	reg_fste_w6_11_8_pos 0
-#define	reg_fste_w6_11_8_len 4
-#define	reg_fste_w6_11_8_lsb 8
-#define xd_p_reg_fste_w7_3_0	0xA354
-#define	reg_fste_w7_3_0_pos 4
-#define	reg_fste_w7_3_0_len 4
-#define	reg_fste_w7_3_0_lsb 0
-#define xd_p_reg_fste_w7_11_4	0xA355
-#define	reg_fste_w7_11_4_pos 0
-#define	reg_fste_w7_11_4_len 8
-#define	reg_fste_w7_11_4_lsb 4
-#define xd_p_reg_fste_w8_7_0	0xA356
-#define	reg_fste_w8_7_0_pos 0
-#define	reg_fste_w8_7_0_len 8
-#define	reg_fste_w8_7_0_lsb 0
-#define xd_p_reg_fste_w8_11_8	0xA357
-#define	reg_fste_w8_11_8_pos 0
-#define	reg_fste_w8_11_8_len 4
-#define	reg_fste_w8_11_8_lsb 8
-#define xd_p_reg_fste_w9_3_0	0xA357
-#define	reg_fste_w9_3_0_pos 4
-#define	reg_fste_w9_3_0_len 4
-#define	reg_fste_w9_3_0_lsb 0
-#define xd_p_reg_fste_w9_11_4	0xA358
-#define	reg_fste_w9_11_4_pos 0
-#define	reg_fste_w9_11_4_len 8
-#define	reg_fste_w9_11_4_lsb 4
-#define xd_p_reg_fste_wa_7_0	0xA359
-#define	reg_fste_wa_7_0_pos 0
-#define	reg_fste_wa_7_0_len 8
-#define	reg_fste_wa_7_0_lsb 0
-#define xd_p_reg_fste_wa_11_8	0xA35A
-#define	reg_fste_wa_11_8_pos 0
-#define	reg_fste_wa_11_8_len 4
-#define	reg_fste_wa_11_8_lsb 8
-#define xd_p_reg_fste_wb_3_0	0xA35A
-#define	reg_fste_wb_3_0_pos 4
-#define	reg_fste_wb_3_0_len 4
-#define	reg_fste_wb_3_0_lsb 0
-#define xd_p_reg_fste_wb_11_4	0xA35B
-#define	reg_fste_wb_11_4_pos 0
-#define	reg_fste_wb_11_4_len 8
-#define	reg_fste_wb_11_4_lsb 4
-#define xd_r_fd_fste_i_adj	0xA35C
-#define	fd_fste_i_adj_pos 0
-#define	fd_fste_i_adj_len 5
-#define	fd_fste_i_adj_lsb 0
-#define xd_r_fd_fste_f_adj_7_0	0xA35D
-#define	fd_fste_f_adj_7_0_pos 0
-#define	fd_fste_f_adj_7_0_len 8
-#define	fd_fste_f_adj_7_0_lsb 0
-#define xd_r_fd_fste_f_adj_15_8	0xA35E
-#define	fd_fste_f_adj_15_8_pos 0
-#define	fd_fste_f_adj_15_8_len 8
-#define	fd_fste_f_adj_15_8_lsb 8
-#define xd_r_fd_fste_f_adj_19_16	0xA35F
-#define	fd_fste_f_adj_19_16_pos 0
-#define	fd_fste_f_adj_19_16_len 4
-#define	fd_fste_f_adj_19_16_lsb 16
-#define xd_p_reg_feq_Leak_Bypass	0xA366
-#define	reg_feq_Leak_Bypass_pos 0
-#define	reg_feq_Leak_Bypass_len 1
-#define	reg_feq_Leak_Bypass_lsb 0
-#define xd_p_reg_feq_Leak_Mneg1	0xA366
-#define	reg_feq_Leak_Mneg1_pos 1
-#define	reg_feq_Leak_Mneg1_len 3
-#define	reg_feq_Leak_Mneg1_lsb 0
-#define xd_p_reg_feq_Leak_B_ShiftQ	0xA366
-#define	reg_feq_Leak_B_ShiftQ_pos 4
-#define	reg_feq_Leak_B_ShiftQ_len 4
-#define	reg_feq_Leak_B_ShiftQ_lsb 0
-#define xd_p_reg_feq_Leak_B_Float0	0xA367
-#define	reg_feq_Leak_B_Float0_pos 0
-#define	reg_feq_Leak_B_Float0_len 8
-#define	reg_feq_Leak_B_Float0_lsb 0
-#define xd_p_reg_feq_Leak_B_Float1	0xA368
-#define	reg_feq_Leak_B_Float1_pos 0
-#define	reg_feq_Leak_B_Float1_len 8
-#define	reg_feq_Leak_B_Float1_lsb 0
-#define xd_p_reg_feq_Leak_B_Float2	0xA369
-#define	reg_feq_Leak_B_Float2_pos 0
-#define	reg_feq_Leak_B_Float2_len 8
-#define	reg_feq_Leak_B_Float2_lsb 0
-#define xd_p_reg_feq_Leak_B_Float3	0xA36A
-#define	reg_feq_Leak_B_Float3_pos 0
-#define	reg_feq_Leak_B_Float3_len 8
-#define	reg_feq_Leak_B_Float3_lsb 0
-#define xd_p_reg_feq_Leak_B_Float4	0xA36B
-#define	reg_feq_Leak_B_Float4_pos 0
-#define	reg_feq_Leak_B_Float4_len 8
-#define	reg_feq_Leak_B_Float4_lsb 0
-#define xd_p_reg_feq_Leak_B_Float5	0xA36C
-#define	reg_feq_Leak_B_Float5_pos 0
-#define	reg_feq_Leak_B_Float5_len 8
-#define	reg_feq_Leak_B_Float5_lsb 0
-#define xd_p_reg_feq_Leak_B_Float6	0xA36D
-#define	reg_feq_Leak_B_Float6_pos 0
-#define	reg_feq_Leak_B_Float6_len 8
-#define	reg_feq_Leak_B_Float6_lsb 0
-#define xd_p_reg_feq_Leak_B_Float7	0xA36E
-#define	reg_feq_Leak_B_Float7_pos 0
-#define	reg_feq_Leak_B_Float7_len 8
-#define	reg_feq_Leak_B_Float7_lsb 0
-#define xd_r_reg_feq_data_h2_7_0	0xA36F
-#define	reg_feq_data_h2_7_0_pos 0
-#define	reg_feq_data_h2_7_0_len 8
-#define	reg_feq_data_h2_7_0_lsb 0
-#define xd_r_reg_feq_data_h2_9_8	0xA370
-#define	reg_feq_data_h2_9_8_pos 0
-#define	reg_feq_data_h2_9_8_len 2
-#define	reg_feq_data_h2_9_8_lsb 8
-#define xd_p_reg_feq_leak_use_slice_tps	0xA371
-#define	reg_feq_leak_use_slice_tps_pos 0
-#define	reg_feq_leak_use_slice_tps_len 1
-#define	reg_feq_leak_use_slice_tps_lsb 0
-#define xd_p_reg_feq_read_update	0xA371
-#define	reg_feq_read_update_pos 1
-#define	reg_feq_read_update_len 1
-#define	reg_feq_read_update_lsb 0
-#define xd_p_reg_feq_data_vld	0xA371
-#define	reg_feq_data_vld_pos 2
-#define	reg_feq_data_vld_len 1
-#define	reg_feq_data_vld_lsb 0
-#define xd_p_reg_feq_tone_idx_4_0	0xA371
-#define	reg_feq_tone_idx_4_0_pos 3
-#define	reg_feq_tone_idx_4_0_len 5
-#define	reg_feq_tone_idx_4_0_lsb 0
-#define xd_p_reg_feq_tone_idx_12_5	0xA372
-#define	reg_feq_tone_idx_12_5_pos 0
-#define	reg_feq_tone_idx_12_5_len 8
-#define	reg_feq_tone_idx_12_5_lsb 5
-#define xd_r_reg_feq_data_re_7_0	0xA373
-#define	reg_feq_data_re_7_0_pos 0
-#define	reg_feq_data_re_7_0_len 8
-#define	reg_feq_data_re_7_0_lsb 0
-#define xd_r_reg_feq_data_re_10_8	0xA374
-#define	reg_feq_data_re_10_8_pos 0
-#define	reg_feq_data_re_10_8_len 3
-#define	reg_feq_data_re_10_8_lsb 8
-#define xd_r_reg_feq_data_im_7_0	0xA375
-#define	reg_feq_data_im_7_0_pos 0
-#define	reg_feq_data_im_7_0_len 8
-#define	reg_feq_data_im_7_0_lsb 0
-#define xd_r_reg_feq_data_im_10_8	0xA376
-#define	reg_feq_data_im_10_8_pos 0
-#define	reg_feq_data_im_10_8_len 3
-#define	reg_feq_data_im_10_8_lsb 8
-#define xd_r_reg_feq_y_re	0xA377
-#define	reg_feq_y_re_pos 0
-#define	reg_feq_y_re_len 8
-#define	reg_feq_y_re_lsb 0
-#define xd_r_reg_feq_y_im	0xA378
-#define	reg_feq_y_im_pos 0
-#define	reg_feq_y_im_len 8
-#define	reg_feq_y_im_lsb 0
-#define xd_r_reg_feq_h_re_7_0	0xA379
-#define	reg_feq_h_re_7_0_pos 0
-#define	reg_feq_h_re_7_0_len 8
-#define	reg_feq_h_re_7_0_lsb 0
-#define xd_r_reg_feq_h_re_8	0xA37A
-#define	reg_feq_h_re_8_pos 0
-#define	reg_feq_h_re_8_len 1
-#define	reg_feq_h_re_8_lsb 0
-#define xd_r_reg_feq_h_im_7_0	0xA37B
-#define	reg_feq_h_im_7_0_pos 0
-#define	reg_feq_h_im_7_0_len 8
-#define	reg_feq_h_im_7_0_lsb 0
-#define xd_r_reg_feq_h_im_8	0xA37C
-#define	reg_feq_h_im_8_pos 0
-#define	reg_feq_h_im_8_len 1
-#define	reg_feq_h_im_8_lsb 0
-#define xd_p_fec_super_frm_unit_7_0	0xA380
-#define	fec_super_frm_unit_7_0_pos 0
-#define	fec_super_frm_unit_7_0_len 8
-#define	fec_super_frm_unit_7_0_lsb 0
-#define xd_p_fec_super_frm_unit_15_8	0xA381
-#define	fec_super_frm_unit_15_8_pos 0
-#define	fec_super_frm_unit_15_8_len 8
-#define	fec_super_frm_unit_15_8_lsb 8
-#define xd_r_fec_vtb_err_bit_cnt_7_0	0xA382
-#define	fec_vtb_err_bit_cnt_7_0_pos 0
-#define	fec_vtb_err_bit_cnt_7_0_len 8
-#define	fec_vtb_err_bit_cnt_7_0_lsb 0
-#define xd_r_fec_vtb_err_bit_cnt_15_8	0xA383
-#define	fec_vtb_err_bit_cnt_15_8_pos 0
-#define	fec_vtb_err_bit_cnt_15_8_len 8
-#define	fec_vtb_err_bit_cnt_15_8_lsb 8
-#define xd_r_fec_vtb_err_bit_cnt_23_16	0xA384
-#define	fec_vtb_err_bit_cnt_23_16_pos 0
-#define	fec_vtb_err_bit_cnt_23_16_len 8
-#define	fec_vtb_err_bit_cnt_23_16_lsb 16
-#define xd_p_fec_rsd_packet_unit_7_0	0xA385
-#define	fec_rsd_packet_unit_7_0_pos 0
-#define	fec_rsd_packet_unit_7_0_len 8
-#define	fec_rsd_packet_unit_7_0_lsb 0
-#define xd_p_fec_rsd_packet_unit_15_8	0xA386
-#define	fec_rsd_packet_unit_15_8_pos 0
-#define	fec_rsd_packet_unit_15_8_len 8
-#define	fec_rsd_packet_unit_15_8_lsb 8
-#define xd_r_fec_rsd_bit_err_cnt_7_0	0xA387
-#define	fec_rsd_bit_err_cnt_7_0_pos 0
-#define	fec_rsd_bit_err_cnt_7_0_len 8
-#define	fec_rsd_bit_err_cnt_7_0_lsb 0
-#define xd_r_fec_rsd_bit_err_cnt_15_8	0xA388
-#define	fec_rsd_bit_err_cnt_15_8_pos 0
-#define	fec_rsd_bit_err_cnt_15_8_len 8
-#define	fec_rsd_bit_err_cnt_15_8_lsb 8
-#define xd_r_fec_rsd_bit_err_cnt_23_16	0xA389
-#define	fec_rsd_bit_err_cnt_23_16_pos 0
-#define	fec_rsd_bit_err_cnt_23_16_len 8
-#define	fec_rsd_bit_err_cnt_23_16_lsb 16
-#define xd_r_fec_rsd_abort_packet_cnt_7_0	0xA38A
-#define	fec_rsd_abort_packet_cnt_7_0_pos 0
-#define	fec_rsd_abort_packet_cnt_7_0_len 8
-#define	fec_rsd_abort_packet_cnt_7_0_lsb 0
-#define xd_r_fec_rsd_abort_packet_cnt_15_8	0xA38B
-#define	fec_rsd_abort_packet_cnt_15_8_pos 0
-#define	fec_rsd_abort_packet_cnt_15_8_len 8
-#define	fec_rsd_abort_packet_cnt_15_8_lsb 8
-#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_7_0	0xA38C
-#define	fec_RSD_PKT_NUM_PER_UNIT_7_0_pos 0
-#define	fec_RSD_PKT_NUM_PER_UNIT_7_0_len 8
-#define	fec_RSD_PKT_NUM_PER_UNIT_7_0_lsb 0
-#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_15_8	0xA38D
-#define	fec_RSD_PKT_NUM_PER_UNIT_15_8_pos 0
-#define	fec_RSD_PKT_NUM_PER_UNIT_15_8_len 8
-#define	fec_RSD_PKT_NUM_PER_UNIT_15_8_lsb 8
-#define xd_p_fec_RS_TH_1_7_0	0xA38E
-#define	fec_RS_TH_1_7_0_pos 0
-#define	fec_RS_TH_1_7_0_len 8
-#define	fec_RS_TH_1_7_0_lsb 0
-#define xd_p_fec_RS_TH_1_15_8	0xA38F
-#define	fec_RS_TH_1_15_8_pos 0
-#define	fec_RS_TH_1_15_8_len 8
-#define	fec_RS_TH_1_15_8_lsb 8
-#define xd_p_fec_RS_TH_2	0xA390
-#define	fec_RS_TH_2_pos 0
-#define	fec_RS_TH_2_len 8
-#define	fec_RS_TH_2_lsb 0
-#define xd_p_fec_mon_en	0xA391
-#define	fec_mon_en_pos 0
-#define	fec_mon_en_len 1
-#define	fec_mon_en_lsb 0
-#define xd_p_reg_b8to47	0xA391
-#define	reg_b8to47_pos 1
-#define	reg_b8to47_len 1
-#define	reg_b8to47_lsb 0
-#define xd_p_reg_rsd_sync_rep	0xA391
-#define	reg_rsd_sync_rep_pos 2
-#define	reg_rsd_sync_rep_len 1
-#define	reg_rsd_sync_rep_lsb 0
-#define xd_p_fec_rsd_retrain_rst	0xA391
-#define	fec_rsd_retrain_rst_pos 3
-#define	fec_rsd_retrain_rst_len 1
-#define	fec_rsd_retrain_rst_lsb 0
-#define xd_r_fec_rsd_ber_rdy	0xA391
-#define	fec_rsd_ber_rdy_pos 4
-#define	fec_rsd_ber_rdy_len 1
-#define	fec_rsd_ber_rdy_lsb 0
-#define xd_p_fec_rsd_ber_rst	0xA391
-#define	fec_rsd_ber_rst_pos 5
-#define	fec_rsd_ber_rst_len 1
-#define	fec_rsd_ber_rst_lsb 0
-#define xd_r_fec_vtb_ber_rdy	0xA391
-#define	fec_vtb_ber_rdy_pos 6
-#define	fec_vtb_ber_rdy_len 1
-#define	fec_vtb_ber_rdy_lsb 0
-#define xd_p_fec_vtb_ber_rst	0xA391
-#define	fec_vtb_ber_rst_pos 7
-#define	fec_vtb_ber_rst_len 1
-#define	fec_vtb_ber_rst_lsb 0
-#define xd_p_reg_vtb_clk40en	0xA392
-#define	reg_vtb_clk40en_pos 0
-#define	reg_vtb_clk40en_len 1
-#define	reg_vtb_clk40en_lsb 0
-#define xd_p_fec_vtb_rsd_mon_en	0xA392
-#define	fec_vtb_rsd_mon_en_pos 1
-#define	fec_vtb_rsd_mon_en_len 1
-#define	fec_vtb_rsd_mon_en_lsb 0
-#define xd_p_reg_fec_data_en	0xA392
-#define	reg_fec_data_en_pos 2
-#define	reg_fec_data_en_len 1
-#define	reg_fec_data_en_lsb 0
-#define xd_p_fec_dummy_reg_2	0xA392
-#define	fec_dummy_reg_2_pos 3
-#define	fec_dummy_reg_2_len 3
-#define	fec_dummy_reg_2_lsb 0
-#define xd_p_reg_sync_chk	0xA392
-#define	reg_sync_chk_pos 6
-#define	reg_sync_chk_len 1
-#define	reg_sync_chk_lsb 0
-#define xd_p_fec_rsd_bypass	0xA392
-#define	fec_rsd_bypass_pos 7
-#define	fec_rsd_bypass_len 1
-#define	fec_rsd_bypass_lsb 0
-#define xd_p_fec_sw_rst	0xA393
-#define	fec_sw_rst_pos 0
-#define	fec_sw_rst_len 1
-#define	fec_sw_rst_lsb 0
-#define xd_r_fec_vtb_pm_crc	0xA394
-#define	fec_vtb_pm_crc_pos 0
-#define	fec_vtb_pm_crc_len 8
-#define	fec_vtb_pm_crc_lsb 0
-#define xd_r_fec_vtb_tb_7_crc	0xA395
-#define	fec_vtb_tb_7_crc_pos 0
-#define	fec_vtb_tb_7_crc_len 8
-#define	fec_vtb_tb_7_crc_lsb 0
-#define xd_r_fec_vtb_tb_6_crc	0xA396
-#define	fec_vtb_tb_6_crc_pos 0
-#define	fec_vtb_tb_6_crc_len 8
-#define	fec_vtb_tb_6_crc_lsb 0
-#define xd_r_fec_vtb_tb_5_crc	0xA397
-#define	fec_vtb_tb_5_crc_pos 0
-#define	fec_vtb_tb_5_crc_len 8
-#define	fec_vtb_tb_5_crc_lsb 0
-#define xd_r_fec_vtb_tb_4_crc	0xA398
-#define	fec_vtb_tb_4_crc_pos 0
-#define	fec_vtb_tb_4_crc_len 8
-#define	fec_vtb_tb_4_crc_lsb 0
-#define xd_r_fec_vtb_tb_3_crc	0xA399
-#define	fec_vtb_tb_3_crc_pos 0
-#define	fec_vtb_tb_3_crc_len 8
-#define	fec_vtb_tb_3_crc_lsb 0
-#define xd_r_fec_vtb_tb_2_crc	0xA39A
-#define	fec_vtb_tb_2_crc_pos 0
-#define	fec_vtb_tb_2_crc_len 8
-#define	fec_vtb_tb_2_crc_lsb 0
-#define xd_r_fec_vtb_tb_1_crc	0xA39B
-#define	fec_vtb_tb_1_crc_pos 0
-#define	fec_vtb_tb_1_crc_len 8
-#define	fec_vtb_tb_1_crc_lsb 0
-#define xd_r_fec_vtb_tb_0_crc	0xA39C
-#define	fec_vtb_tb_0_crc_pos 0
-#define	fec_vtb_tb_0_crc_len 8
-#define	fec_vtb_tb_0_crc_lsb 0
-#define xd_r_fec_rsd_bank0_crc	0xA39D
-#define	fec_rsd_bank0_crc_pos 0
-#define	fec_rsd_bank0_crc_len 8
-#define	fec_rsd_bank0_crc_lsb 0
-#define xd_r_fec_rsd_bank1_crc	0xA39E
-#define	fec_rsd_bank1_crc_pos 0
-#define	fec_rsd_bank1_crc_len 8
-#define	fec_rsd_bank1_crc_lsb 0
-#define xd_r_fec_idi_vtb_crc	0xA39F
-#define	fec_idi_vtb_crc_pos 0
-#define	fec_idi_vtb_crc_len 8
-#define	fec_idi_vtb_crc_lsb 0
-#define xd_g_reg_tpsd_txmod	0xA3C0
-#define	reg_tpsd_txmod_pos 0
-#define	reg_tpsd_txmod_len 2
-#define	reg_tpsd_txmod_lsb 0
-#define xd_g_reg_tpsd_gi	0xA3C0
-#define	reg_tpsd_gi_pos 2
-#define	reg_tpsd_gi_len 2
-#define	reg_tpsd_gi_lsb 0
-#define xd_g_reg_tpsd_hier	0xA3C0
-#define	reg_tpsd_hier_pos 4
-#define	reg_tpsd_hier_len 3
-#define	reg_tpsd_hier_lsb 0
-#define xd_g_reg_bw	0xA3C1
-#define	reg_bw_pos 2
-#define	reg_bw_len 2
-#define	reg_bw_lsb 0
-#define xd_g_reg_dec_pri	0xA3C1
-#define	reg_dec_pri_pos 4
-#define	reg_dec_pri_len 1
-#define	reg_dec_pri_lsb 0
-#define xd_g_reg_tpsd_const	0xA3C1
-#define	reg_tpsd_const_pos 6
-#define	reg_tpsd_const_len 2
-#define	reg_tpsd_const_lsb 0
-#define xd_g_reg_tpsd_hpcr	0xA3C2
-#define	reg_tpsd_hpcr_pos 0
-#define	reg_tpsd_hpcr_len 3
-#define	reg_tpsd_hpcr_lsb 0
-#define xd_g_reg_tpsd_lpcr	0xA3C2
-#define	reg_tpsd_lpcr_pos 3
-#define	reg_tpsd_lpcr_len 3
-#define	reg_tpsd_lpcr_lsb 0
-#define xd_g_reg_ofsm_clk	0xA3D0
-#define	reg_ofsm_clk_pos 0
-#define	reg_ofsm_clk_len 3
-#define	reg_ofsm_clk_lsb 0
-#define xd_g_reg_fclk_cfg	0xA3D1
-#define	reg_fclk_cfg_pos 0
-#define	reg_fclk_cfg_len 1
-#define	reg_fclk_cfg_lsb 0
-#define xd_g_reg_fclk_idi	0xA3D1
-#define	reg_fclk_idi_pos 1
-#define	reg_fclk_idi_len 1
-#define	reg_fclk_idi_lsb 0
-#define xd_g_reg_fclk_odi	0xA3D1
-#define	reg_fclk_odi_pos 2
-#define	reg_fclk_odi_len 1
-#define	reg_fclk_odi_lsb 0
-#define xd_g_reg_fclk_rsd	0xA3D1
-#define	reg_fclk_rsd_pos 3
-#define	reg_fclk_rsd_len 1
-#define	reg_fclk_rsd_lsb 0
-#define xd_g_reg_fclk_vtb	0xA3D1
-#define	reg_fclk_vtb_pos 4
-#define	reg_fclk_vtb_len 1
-#define	reg_fclk_vtb_lsb 0
-#define xd_g_reg_fclk_cste	0xA3D1
-#define	reg_fclk_cste_pos 5
-#define	reg_fclk_cste_len 1
-#define	reg_fclk_cste_lsb 0
-#define xd_g_reg_fclk_mp2if	0xA3D1
-#define	reg_fclk_mp2if_pos 6
-#define	reg_fclk_mp2if_len 1
-#define	reg_fclk_mp2if_lsb 0
-#define xd_I2C_i2c_m_slave_addr	0xA400
-#define	i2c_m_slave_addr_pos 0
-#define	i2c_m_slave_addr_len 8
-#define	i2c_m_slave_addr_lsb 0
-#define xd_I2C_i2c_m_data1	0xA401
-#define	i2c_m_data1_pos 0
-#define	i2c_m_data1_len 8
-#define	i2c_m_data1_lsb 0
-#define xd_I2C_i2c_m_data2	0xA402
-#define	i2c_m_data2_pos 0
-#define	i2c_m_data2_len 8
-#define	i2c_m_data2_lsb 0
-#define xd_I2C_i2c_m_data3	0xA403
-#define	i2c_m_data3_pos 0
-#define	i2c_m_data3_len 8
-#define	i2c_m_data3_lsb 0
-#define xd_I2C_i2c_m_data4	0xA404
-#define	i2c_m_data4_pos 0
-#define	i2c_m_data4_len 8
-#define	i2c_m_data4_lsb 0
-#define xd_I2C_i2c_m_data5	0xA405
-#define	i2c_m_data5_pos 0
-#define	i2c_m_data5_len 8
-#define	i2c_m_data5_lsb 0
-#define xd_I2C_i2c_m_data6	0xA406
-#define	i2c_m_data6_pos 0
-#define	i2c_m_data6_len 8
-#define	i2c_m_data6_lsb 0
-#define xd_I2C_i2c_m_data7	0xA407
-#define	i2c_m_data7_pos 0
-#define	i2c_m_data7_len 8
-#define	i2c_m_data7_lsb 0
-#define xd_I2C_i2c_m_data8	0xA408
-#define	i2c_m_data8_pos 0
-#define	i2c_m_data8_len 8
-#define	i2c_m_data8_lsb 0
-#define xd_I2C_i2c_m_data9	0xA409
-#define	i2c_m_data9_pos 0
-#define	i2c_m_data9_len 8
-#define	i2c_m_data9_lsb 0
-#define xd_I2C_i2c_m_data10	0xA40A
-#define	i2c_m_data10_pos 0
-#define	i2c_m_data10_len 8
-#define	i2c_m_data10_lsb 0
-#define xd_I2C_i2c_m_data11	0xA40B
-#define	i2c_m_data11_pos 0
-#define	i2c_m_data11_len 8
-#define	i2c_m_data11_lsb 0
-#define xd_I2C_i2c_m_cmd_rw	0xA40C
-#define	i2c_m_cmd_rw_pos 0
-#define	i2c_m_cmd_rw_len 1
-#define	i2c_m_cmd_rw_lsb 0
-#define xd_I2C_i2c_m_cmd_rwlen	0xA40C
-#define	i2c_m_cmd_rwlen_pos 3
-#define	i2c_m_cmd_rwlen_len 4
-#define	i2c_m_cmd_rwlen_lsb 0
-#define xd_I2C_i2c_m_status_cmd_exe	0xA40D
-#define	i2c_m_status_cmd_exe_pos 0
-#define	i2c_m_status_cmd_exe_len 1
-#define	i2c_m_status_cmd_exe_lsb 0
-#define xd_I2C_i2c_m_status_wdat_done	0xA40D
-#define	i2c_m_status_wdat_done_pos 1
-#define	i2c_m_status_wdat_done_len 1
-#define	i2c_m_status_wdat_done_lsb 0
-#define xd_I2C_i2c_m_status_wdat_fail	0xA40D
-#define	i2c_m_status_wdat_fail_pos 2
-#define	i2c_m_status_wdat_fail_len 1
-#define	i2c_m_status_wdat_fail_lsb 0
-#define xd_I2C_i2c_m_period	0xA40E
-#define	i2c_m_period_pos 0
-#define	i2c_m_period_len 8
-#define	i2c_m_period_lsb 0
-#define xd_I2C_i2c_m_reg_msb_lsb	0xA40F
-#define	i2c_m_reg_msb_lsb_pos 0
-#define	i2c_m_reg_msb_lsb_len 1
-#define	i2c_m_reg_msb_lsb_lsb 0
-#define xd_I2C_reg_ofdm_rst	0xA40F
-#define	reg_ofdm_rst_pos 1
-#define	reg_ofdm_rst_len 1
-#define	reg_ofdm_rst_lsb 0
-#define xd_I2C_reg_sample_period_on_tuner	0xA40F
-#define	reg_sample_period_on_tuner_pos 2
-#define	reg_sample_period_on_tuner_len 1
-#define	reg_sample_period_on_tuner_lsb 0
-#define xd_I2C_reg_rst_i2c	0xA40F
-#define	reg_rst_i2c_pos 3
-#define	reg_rst_i2c_len 1
-#define	reg_rst_i2c_lsb 0
-#define xd_I2C_reg_ofdm_rst_en	0xA40F
-#define	reg_ofdm_rst_en_pos 4
-#define	reg_ofdm_rst_en_len 1
-#define	reg_ofdm_rst_en_lsb 0
-#define xd_I2C_reg_tuner_sda_sync_on	0xA40F
-#define	reg_tuner_sda_sync_on_pos 5
-#define	reg_tuner_sda_sync_on_len 1
-#define	reg_tuner_sda_sync_on_lsb 0
-#define xd_p_mp2if_data_access_disable_ofsm	0xA500
-#define	mp2if_data_access_disable_ofsm_pos 0
-#define	mp2if_data_access_disable_ofsm_len 1
-#define	mp2if_data_access_disable_ofsm_lsb 0
-#define xd_p_reg_mp2_sw_rst_ofsm	0xA500
-#define	reg_mp2_sw_rst_ofsm_pos 1
-#define	reg_mp2_sw_rst_ofsm_len 1
-#define	reg_mp2_sw_rst_ofsm_lsb 0
-#define xd_p_reg_mp2if_clk_en_ofsm	0xA500
-#define	reg_mp2if_clk_en_ofsm_pos 2
-#define	reg_mp2if_clk_en_ofsm_len 1
-#define	reg_mp2if_clk_en_ofsm_lsb 0
-#define xd_r_mp2if_sync_byte_locked	0xA500
-#define	mp2if_sync_byte_locked_pos 3
-#define	mp2if_sync_byte_locked_len 1
-#define	mp2if_sync_byte_locked_lsb 0
-#define xd_r_mp2if_ts_not_188	0xA500
-#define	mp2if_ts_not_188_pos 4
-#define	mp2if_ts_not_188_len 1
-#define	mp2if_ts_not_188_lsb 0
-#define xd_r_mp2if_psb_empty	0xA500
-#define	mp2if_psb_empty_pos 5
-#define	mp2if_psb_empty_len 1
-#define	mp2if_psb_empty_lsb 0
-#define xd_r_mp2if_psb_overflow	0xA500
-#define	mp2if_psb_overflow_pos 6
-#define	mp2if_psb_overflow_len 1
-#define	mp2if_psb_overflow_lsb 0
-#define xd_p_mp2if_keep_sf_sync_byte_ofsm	0xA500
-#define	mp2if_keep_sf_sync_byte_ofsm_pos 7
-#define	mp2if_keep_sf_sync_byte_ofsm_len 1
-#define	mp2if_keep_sf_sync_byte_ofsm_lsb 0
-#define xd_r_mp2if_psb_mp2if_num_pkt	0xA501
-#define	mp2if_psb_mp2if_num_pkt_pos 0
-#define	mp2if_psb_mp2if_num_pkt_len 6
-#define	mp2if_psb_mp2if_num_pkt_lsb 0
-#define xd_p_reg_mpeg_full_speed_ofsm	0xA501
-#define	reg_mpeg_full_speed_ofsm_pos 6
-#define	reg_mpeg_full_speed_ofsm_len 1
-#define	reg_mpeg_full_speed_ofsm_lsb 0
-#define xd_p_mp2if_mpeg_ser_mode_ofsm	0xA501
-#define	mp2if_mpeg_ser_mode_ofsm_pos 7
-#define	mp2if_mpeg_ser_mode_ofsm_len 1
-#define	mp2if_mpeg_ser_mode_ofsm_lsb 0
-#define xd_p_reg_sw_mon51	0xA600
-#define	reg_sw_mon51_pos 0
-#define	reg_sw_mon51_len 8
-#define	reg_sw_mon51_lsb 0
-#define xd_p_reg_top_pcsel	0xA601
-#define	reg_top_pcsel_pos 0
-#define	reg_top_pcsel_len 1
-#define	reg_top_pcsel_lsb 0
-#define xd_p_reg_top_rs232	0xA601
-#define	reg_top_rs232_pos 1
-#define	reg_top_rs232_len 1
-#define	reg_top_rs232_lsb 0
-#define xd_p_reg_top_pcout	0xA601
-#define	reg_top_pcout_pos 2
-#define	reg_top_pcout_len 1
-#define	reg_top_pcout_lsb 0
-#define xd_p_reg_top_debug	0xA601
-#define	reg_top_debug_pos 3
-#define	reg_top_debug_len 1
-#define	reg_top_debug_lsb 0
-#define xd_p_reg_top_adcdly	0xA601
-#define	reg_top_adcdly_pos 4
-#define	reg_top_adcdly_len 2
-#define	reg_top_adcdly_lsb 0
-#define xd_p_reg_top_pwrdw	0xA601
-#define	reg_top_pwrdw_pos 6
-#define	reg_top_pwrdw_len 1
-#define	reg_top_pwrdw_lsb 0
-#define xd_p_reg_top_pwrdw_inv	0xA601
-#define	reg_top_pwrdw_inv_pos 7
-#define	reg_top_pwrdw_inv_len 1
-#define	reg_top_pwrdw_inv_lsb 0
-#define xd_p_reg_top_int_inv	0xA602
-#define	reg_top_int_inv_pos 0
-#define	reg_top_int_inv_len 1
-#define	reg_top_int_inv_lsb 0
-#define xd_p_reg_top_dio_sel	0xA602
-#define	reg_top_dio_sel_pos 1
-#define	reg_top_dio_sel_len 1
-#define	reg_top_dio_sel_lsb 0
-#define xd_p_reg_top_gpioon0	0xA603
-#define	reg_top_gpioon0_pos 0
-#define	reg_top_gpioon0_len 1
-#define	reg_top_gpioon0_lsb 0
-#define xd_p_reg_top_gpioon1	0xA603
-#define	reg_top_gpioon1_pos 1
-#define	reg_top_gpioon1_len 1
-#define	reg_top_gpioon1_lsb 0
-#define xd_p_reg_top_gpioon2	0xA603
-#define	reg_top_gpioon2_pos 2
-#define	reg_top_gpioon2_len 1
-#define	reg_top_gpioon2_lsb 0
-#define xd_p_reg_top_gpioon3	0xA603
-#define	reg_top_gpioon3_pos 3
-#define	reg_top_gpioon3_len 1
-#define	reg_top_gpioon3_lsb 0
-#define xd_p_reg_top_lockon1	0xA603
-#define	reg_top_lockon1_pos 4
-#define	reg_top_lockon1_len 1
-#define	reg_top_lockon1_lsb 0
-#define xd_p_reg_top_lockon2	0xA603
-#define	reg_top_lockon2_pos 5
-#define	reg_top_lockon2_len 1
-#define	reg_top_lockon2_lsb 0
-#define xd_p_reg_top_gpioo0	0xA604
-#define	reg_top_gpioo0_pos 0
-#define	reg_top_gpioo0_len 1
-#define	reg_top_gpioo0_lsb 0
-#define xd_p_reg_top_gpioo1	0xA604
-#define	reg_top_gpioo1_pos 1
-#define	reg_top_gpioo1_len 1
-#define	reg_top_gpioo1_lsb 0
-#define xd_p_reg_top_gpioo2	0xA604
-#define	reg_top_gpioo2_pos 2
-#define	reg_top_gpioo2_len 1
-#define	reg_top_gpioo2_lsb 0
-#define xd_p_reg_top_gpioo3	0xA604
-#define	reg_top_gpioo3_pos 3
-#define	reg_top_gpioo3_len 1
-#define	reg_top_gpioo3_lsb 0
-#define xd_p_reg_top_lock1	0xA604
-#define	reg_top_lock1_pos 4
-#define	reg_top_lock1_len 1
-#define	reg_top_lock1_lsb 0
-#define xd_p_reg_top_lock2	0xA604
-#define	reg_top_lock2_pos 5
-#define	reg_top_lock2_len 1
-#define	reg_top_lock2_lsb 0
-#define xd_p_reg_top_gpioen0	0xA605
-#define	reg_top_gpioen0_pos 0
-#define	reg_top_gpioen0_len 1
-#define	reg_top_gpioen0_lsb 0
-#define xd_p_reg_top_gpioen1	0xA605
-#define	reg_top_gpioen1_pos 1
-#define	reg_top_gpioen1_len 1
-#define	reg_top_gpioen1_lsb 0
-#define xd_p_reg_top_gpioen2	0xA605
-#define	reg_top_gpioen2_pos 2
-#define	reg_top_gpioen2_len 1
-#define	reg_top_gpioen2_lsb 0
-#define xd_p_reg_top_gpioen3	0xA605
-#define	reg_top_gpioen3_pos 3
-#define	reg_top_gpioen3_len 1
-#define	reg_top_gpioen3_lsb 0
-#define xd_p_reg_top_locken1	0xA605
-#define	reg_top_locken1_pos 4
-#define	reg_top_locken1_len 1
-#define	reg_top_locken1_lsb 0
-#define xd_p_reg_top_locken2	0xA605
-#define	reg_top_locken2_pos 5
-#define	reg_top_locken2_len 1
-#define	reg_top_locken2_lsb 0
-#define xd_r_reg_top_gpioi0	0xA606
-#define	reg_top_gpioi0_pos 0
-#define	reg_top_gpioi0_len 1
-#define	reg_top_gpioi0_lsb 0
-#define xd_r_reg_top_gpioi1	0xA606
-#define	reg_top_gpioi1_pos 1
-#define	reg_top_gpioi1_len 1
-#define	reg_top_gpioi1_lsb 0
-#define xd_r_reg_top_gpioi2	0xA606
-#define	reg_top_gpioi2_pos 2
-#define	reg_top_gpioi2_len 1
-#define	reg_top_gpioi2_lsb 0
-#define xd_r_reg_top_gpioi3	0xA606
-#define	reg_top_gpioi3_pos 3
-#define	reg_top_gpioi3_len 1
-#define	reg_top_gpioi3_lsb 0
-#define xd_r_reg_top_locki1	0xA606
-#define	reg_top_locki1_pos 4
-#define	reg_top_locki1_len 1
-#define	reg_top_locki1_lsb 0
-#define xd_r_reg_top_locki2	0xA606
-#define	reg_top_locki2_pos 5
-#define	reg_top_locki2_len 1
-#define	reg_top_locki2_lsb 0
-#define xd_p_reg_dummy_7_0	0xA608
-#define	reg_dummy_7_0_pos 0
-#define	reg_dummy_7_0_len 8
-#define	reg_dummy_7_0_lsb 0
-#define xd_p_reg_dummy_15_8	0xA609
-#define	reg_dummy_15_8_pos 0
-#define	reg_dummy_15_8_len 8
-#define	reg_dummy_15_8_lsb 8
-#define xd_p_reg_dummy_23_16	0xA60A
-#define	reg_dummy_23_16_pos 0
-#define	reg_dummy_23_16_len 8
-#define	reg_dummy_23_16_lsb 16
-#define xd_p_reg_dummy_31_24	0xA60B
-#define	reg_dummy_31_24_pos 0
-#define	reg_dummy_31_24_len 8
-#define	reg_dummy_31_24_lsb 24
-#define xd_p_reg_dummy_39_32	0xA60C
-#define	reg_dummy_39_32_pos 0
-#define	reg_dummy_39_32_len 8
-#define	reg_dummy_39_32_lsb 32
-#define xd_p_reg_dummy_47_40	0xA60D
-#define	reg_dummy_47_40_pos 0
-#define	reg_dummy_47_40_len 8
-#define	reg_dummy_47_40_lsb 40
-#define xd_p_reg_dummy_55_48	0xA60E
-#define	reg_dummy_55_48_pos 0
-#define	reg_dummy_55_48_len 8
-#define	reg_dummy_55_48_lsb 48
-#define xd_p_reg_dummy_63_56	0xA60F
-#define	reg_dummy_63_56_pos 0
-#define	reg_dummy_63_56_len 8
-#define	reg_dummy_63_56_lsb 56
-#define xd_p_reg_dummy_71_64	0xA610
-#define	reg_dummy_71_64_pos 0
-#define	reg_dummy_71_64_len 8
-#define	reg_dummy_71_64_lsb 64
-#define xd_p_reg_dummy_79_72	0xA611
-#define	reg_dummy_79_72_pos 0
-#define	reg_dummy_79_72_len 8
-#define	reg_dummy_79_72_lsb 72
-#define xd_p_reg_dummy_87_80	0xA612
-#define	reg_dummy_87_80_pos 0
-#define	reg_dummy_87_80_len 8
-#define	reg_dummy_87_80_lsb 80
-#define xd_p_reg_dummy_95_88	0xA613
-#define	reg_dummy_95_88_pos 0
-#define	reg_dummy_95_88_len 8
-#define	reg_dummy_95_88_lsb 88
-#define xd_p_reg_dummy_103_96	0xA614
-#define	reg_dummy_103_96_pos 0
-#define	reg_dummy_103_96_len 8
-#define	reg_dummy_103_96_lsb 96
-
-#define xd_p_reg_unplug_flag	0xA615
-#define	reg_unplug_flag_pos 0
-#define	reg_unplug_flag_len 1
-#define	reg_unplug_flag_lsb 104
-
-#define xd_p_reg_api_dca_stes_request   0xA615
-#define reg_api_dca_stes_request_pos 1
-#define reg_api_dca_stes_request_len 1
-#define reg_api_dca_stes_request_lsb 0
-
-#define xd_p_reg_back_to_dca_flag	0xA615
-#define	reg_back_to_dca_flag_pos 2
-#define	reg_back_to_dca_flag_len 1
-#define	reg_back_to_dca_flag_lsb 106
-
-#define xd_p_reg_api_retrain_request    0xA615
-#define reg_api_retrain_request_pos 3
-#define reg_api_retrain_request_len 1
-#define reg_api_retrain_request_lsb 0
-
-#define xd_p_reg_Dyn_Top_Try_flag	0xA615
-#define	reg_Dyn_Top_Try_flag_pos 3
-#define	reg_Dyn_Top_Try_flag_len 1
-#define	reg_Dyn_Top_Try_flag_lsb 107
-
-#define xd_p_reg_API_retrain_freeze_flag	0xA615
-#define	reg_API_retrain_freeze_flag_pos 4
-#define	reg_API_retrain_freeze_flag_len 1
-#define	reg_API_retrain_freeze_flag_lsb 108
-
-#define xd_p_reg_dummy_111_104	0xA615
-#define	reg_dummy_111_104_pos 0
-#define	reg_dummy_111_104_len 8
-#define	reg_dummy_111_104_lsb 104
-#define xd_p_reg_dummy_119_112	0xA616
-#define	reg_dummy_119_112_pos 0
-#define	reg_dummy_119_112_len 8
-#define	reg_dummy_119_112_lsb 112
-#define xd_p_reg_dummy_127_120	0xA617
-#define	reg_dummy_127_120_pos 0
-#define	reg_dummy_127_120_len 8
-#define	reg_dummy_127_120_lsb 120
-#define xd_p_reg_dummy_135_128	0xA618
-#define	reg_dummy_135_128_pos 0
-#define	reg_dummy_135_128_len 8
-#define	reg_dummy_135_128_lsb 128
-
-#define xd_p_reg_dummy_143_136	0xA619
-#define	reg_dummy_143_136_pos 0
-#define	reg_dummy_143_136_len 8
-#define	reg_dummy_143_136_lsb 136
-
-#define xd_p_reg_CCIR_dis	0xA619
-#define	reg_CCIR_dis_pos 0
-#define	reg_CCIR_dis_len 1
-#define	reg_CCIR_dis_lsb 0
-
-#define xd_p_reg_dummy_151_144	0xA61A
-#define	reg_dummy_151_144_pos 0
-#define	reg_dummy_151_144_len 8
-#define	reg_dummy_151_144_lsb 144
-
-#define xd_p_reg_dummy_159_152	0xA61B
-#define	reg_dummy_159_152_pos 0
-#define	reg_dummy_159_152_len 8
-#define	reg_dummy_159_152_lsb 152
-
-#define xd_p_reg_dummy_167_160	0xA61C
-#define	reg_dummy_167_160_pos 0
-#define	reg_dummy_167_160_len 8
-#define	reg_dummy_167_160_lsb 160
-
-#define xd_p_reg_dummy_175_168	0xA61D
-#define	reg_dummy_175_168_pos 0
-#define	reg_dummy_175_168_len 8
-#define	reg_dummy_175_168_lsb 168
-
-#define xd_p_reg_dummy_183_176	0xA61E
-#define	reg_dummy_183_176_pos 0
-#define	reg_dummy_183_176_len 8
-#define	reg_dummy_183_176_lsb 176
-
-#define xd_p_reg_ofsm_read_rbc_en  0xA61E
-#define reg_ofsm_read_rbc_en_pos 2
-#define reg_ofsm_read_rbc_en_len 1
-#define reg_ofsm_read_rbc_en_lsb 0
-
-#define xd_p_reg_ce_filter_selection_dis  0xA61E
-#define reg_ce_filter_selection_dis_pos 1
-#define reg_ce_filter_selection_dis_len 1
-#define reg_ce_filter_selection_dis_lsb 0
-
-#define xd_p_reg_OFSM_version_control_7_0  0xA611
-#define reg_OFSM_version_control_7_0_pos 0
-#define reg_OFSM_version_control_7_0_len 8
-#define reg_OFSM_version_control_7_0_lsb 0
-
-#define xd_p_reg_OFSM_version_control_15_8  0xA61F
-#define reg_OFSM_version_control_15_8_pos 0
-#define reg_OFSM_version_control_15_8_len 8
-#define reg_OFSM_version_control_15_8_lsb 0
-
-#define xd_p_reg_OFSM_version_control_23_16  0xA620
-#define reg_OFSM_version_control_23_16_pos 0
-#define reg_OFSM_version_control_23_16_len 8
-#define reg_OFSM_version_control_23_16_lsb 0
-
-#define xd_p_reg_dummy_191_184	0xA61F
-#define	reg_dummy_191_184_pos 0
-#define	reg_dummy_191_184_len 8
-#define	reg_dummy_191_184_lsb 184
-
-#define xd_p_reg_dummy_199_192	0xA620
-#define	reg_dummy_199_192_pos 0
-#define	reg_dummy_199_192_len 8
-#define	reg_dummy_199_192_lsb 192
-
-#define xd_p_reg_ce_en	0xABC0
-#define	reg_ce_en_pos 0
-#define	reg_ce_en_len 1
-#define	reg_ce_en_lsb 0
-#define xd_p_reg_ce_fctrl_en	0xABC0
-#define	reg_ce_fctrl_en_pos 1
-#define	reg_ce_fctrl_en_len 1
-#define	reg_ce_fctrl_en_lsb 0
-#define xd_p_reg_ce_fste_tdi	0xABC0
-#define	reg_ce_fste_tdi_pos 2
-#define	reg_ce_fste_tdi_len 1
-#define	reg_ce_fste_tdi_lsb 0
-#define xd_p_reg_ce_dynamic	0xABC0
-#define	reg_ce_dynamic_pos 3
-#define	reg_ce_dynamic_len 1
-#define	reg_ce_dynamic_lsb 0
-#define xd_p_reg_ce_conf	0xABC0
-#define	reg_ce_conf_pos 4
-#define	reg_ce_conf_len 2
-#define	reg_ce_conf_lsb 0
-#define xd_p_reg_ce_dyn12	0xABC0
-#define	reg_ce_dyn12_pos 6
-#define	reg_ce_dyn12_len 1
-#define	reg_ce_dyn12_lsb 0
-#define xd_p_reg_ce_derot_en	0xABC0
-#define	reg_ce_derot_en_pos 7
-#define	reg_ce_derot_en_len 1
-#define	reg_ce_derot_en_lsb 0
-#define xd_p_reg_ce_dynamic_th_7_0	0xABC1
-#define	reg_ce_dynamic_th_7_0_pos 0
-#define	reg_ce_dynamic_th_7_0_len 8
-#define	reg_ce_dynamic_th_7_0_lsb 0
-#define xd_p_reg_ce_dynamic_th_15_8	0xABC2
-#define	reg_ce_dynamic_th_15_8_pos 0
-#define	reg_ce_dynamic_th_15_8_len 8
-#define	reg_ce_dynamic_th_15_8_lsb 8
-#define xd_p_reg_ce_s1	0xABC3
-#define	reg_ce_s1_pos 0
-#define	reg_ce_s1_len 5
-#define	reg_ce_s1_lsb 0
-#define xd_p_reg_ce_var_forced_value	0xABC3
-#define	reg_ce_var_forced_value_pos 5
-#define	reg_ce_var_forced_value_len 3
-#define	reg_ce_var_forced_value_lsb 0
-#define xd_p_reg_ce_data_im_7_0	0xABC4
-#define	reg_ce_data_im_7_0_pos 0
-#define	reg_ce_data_im_7_0_len 8
-#define	reg_ce_data_im_7_0_lsb 0
-#define xd_p_reg_ce_data_im_8	0xABC5
-#define	reg_ce_data_im_8_pos 0
-#define	reg_ce_data_im_8_len 1
-#define	reg_ce_data_im_8_lsb 0
-#define xd_p_reg_ce_data_re_6_0	0xABC5
-#define	reg_ce_data_re_6_0_pos 1
-#define	reg_ce_data_re_6_0_len 7
-#define	reg_ce_data_re_6_0_lsb 0
-#define xd_p_reg_ce_data_re_8_7	0xABC6
-#define	reg_ce_data_re_8_7_pos 0
-#define	reg_ce_data_re_8_7_len 2
-#define	reg_ce_data_re_8_7_lsb 7
-#define xd_p_reg_ce_tone_5_0	0xABC6
-#define	reg_ce_tone_5_0_pos 2
-#define	reg_ce_tone_5_0_len 6
-#define	reg_ce_tone_5_0_lsb 0
-#define xd_p_reg_ce_tone_12_6	0xABC7
-#define	reg_ce_tone_12_6_pos 0
-#define	reg_ce_tone_12_6_len 7
-#define	reg_ce_tone_12_6_lsb 6
-#define xd_p_reg_ce_centroid_drift_th	0xABC8
-#define	reg_ce_centroid_drift_th_pos 0
-#define	reg_ce_centroid_drift_th_len 8
-#define	reg_ce_centroid_drift_th_lsb 0
-#define xd_p_reg_ce_centroid_count_max	0xABC9
-#define	reg_ce_centroid_count_max_pos 0
-#define	reg_ce_centroid_count_max_len 4
-#define	reg_ce_centroid_count_max_lsb 0
-#define xd_p_reg_ce_centroid_bias_inc_7_0	0xABCA
-#define	reg_ce_centroid_bias_inc_7_0_pos 0
-#define	reg_ce_centroid_bias_inc_7_0_len 8
-#define	reg_ce_centroid_bias_inc_7_0_lsb 0
-#define xd_p_reg_ce_centroid_bias_inc_8	0xABCB
-#define	reg_ce_centroid_bias_inc_8_pos 0
-#define	reg_ce_centroid_bias_inc_8_len 1
-#define	reg_ce_centroid_bias_inc_8_lsb 0
-#define xd_p_reg_ce_var_th0_7_0	0xABCC
-#define	reg_ce_var_th0_7_0_pos 0
-#define	reg_ce_var_th0_7_0_len 8
-#define	reg_ce_var_th0_7_0_lsb 0
-#define xd_p_reg_ce_var_th0_15_8	0xABCD
-#define	reg_ce_var_th0_15_8_pos 0
-#define	reg_ce_var_th0_15_8_len 8
-#define	reg_ce_var_th0_15_8_lsb 8
-#define xd_p_reg_ce_var_th1_7_0	0xABCE
-#define	reg_ce_var_th1_7_0_pos 0
-#define	reg_ce_var_th1_7_0_len 8
-#define	reg_ce_var_th1_7_0_lsb 0
-#define xd_p_reg_ce_var_th1_15_8	0xABCF
-#define	reg_ce_var_th1_15_8_pos 0
-#define	reg_ce_var_th1_15_8_len 8
-#define	reg_ce_var_th1_15_8_lsb 8
-#define xd_p_reg_ce_var_th2_7_0	0xABD0
-#define	reg_ce_var_th2_7_0_pos 0
-#define	reg_ce_var_th2_7_0_len 8
-#define	reg_ce_var_th2_7_0_lsb 0
-#define xd_p_reg_ce_var_th2_15_8	0xABD1
-#define	reg_ce_var_th2_15_8_pos 0
-#define	reg_ce_var_th2_15_8_len 8
-#define	reg_ce_var_th2_15_8_lsb 8
-#define xd_p_reg_ce_var_th3_7_0	0xABD2
-#define	reg_ce_var_th3_7_0_pos 0
-#define	reg_ce_var_th3_7_0_len 8
-#define	reg_ce_var_th3_7_0_lsb 0
-#define xd_p_reg_ce_var_th3_15_8	0xABD3
-#define	reg_ce_var_th3_15_8_pos 0
-#define	reg_ce_var_th3_15_8_len 8
-#define	reg_ce_var_th3_15_8_lsb 8
-#define xd_p_reg_ce_var_th4_7_0	0xABD4
-#define	reg_ce_var_th4_7_0_pos 0
-#define	reg_ce_var_th4_7_0_len 8
-#define	reg_ce_var_th4_7_0_lsb 0
-#define xd_p_reg_ce_var_th4_15_8	0xABD5
-#define	reg_ce_var_th4_15_8_pos 0
-#define	reg_ce_var_th4_15_8_len 8
-#define	reg_ce_var_th4_15_8_lsb 8
-#define xd_p_reg_ce_var_th5_7_0	0xABD6
-#define	reg_ce_var_th5_7_0_pos 0
-#define	reg_ce_var_th5_7_0_len 8
-#define	reg_ce_var_th5_7_0_lsb 0
-#define xd_p_reg_ce_var_th5_15_8	0xABD7
-#define	reg_ce_var_th5_15_8_pos 0
-#define	reg_ce_var_th5_15_8_len 8
-#define	reg_ce_var_th5_15_8_lsb 8
-#define xd_p_reg_ce_var_th6_7_0	0xABD8
-#define	reg_ce_var_th6_7_0_pos 0
-#define	reg_ce_var_th6_7_0_len 8
-#define	reg_ce_var_th6_7_0_lsb 0
-#define xd_p_reg_ce_var_th6_15_8	0xABD9
-#define	reg_ce_var_th6_15_8_pos 0
-#define	reg_ce_var_th6_15_8_len 8
-#define	reg_ce_var_th6_15_8_lsb 8
-#define xd_p_reg_ce_fctrl_reset	0xABDA
-#define	reg_ce_fctrl_reset_pos 0
-#define	reg_ce_fctrl_reset_len 1
-#define	reg_ce_fctrl_reset_lsb 0
-#define xd_p_reg_ce_cent_auto_clr_en	0xABDA
-#define	reg_ce_cent_auto_clr_en_pos 1
-#define	reg_ce_cent_auto_clr_en_len 1
-#define	reg_ce_cent_auto_clr_en_lsb 0
-#define xd_p_reg_ce_fctrl_auto_reset_en	0xABDA
-#define	reg_ce_fctrl_auto_reset_en_pos 2
-#define	reg_ce_fctrl_auto_reset_en_len 1
-#define	reg_ce_fctrl_auto_reset_en_lsb 0
-#define xd_p_reg_ce_var_forced_en	0xABDA
-#define	reg_ce_var_forced_en_pos 3
-#define	reg_ce_var_forced_en_len 1
-#define	reg_ce_var_forced_en_lsb 0
-#define xd_p_reg_ce_cent_forced_en	0xABDA
-#define	reg_ce_cent_forced_en_pos 4
-#define	reg_ce_cent_forced_en_len 1
-#define	reg_ce_cent_forced_en_lsb 0
-#define xd_p_reg_ce_var_max	0xABDA
-#define	reg_ce_var_max_pos 5
-#define	reg_ce_var_max_len 3
-#define	reg_ce_var_max_lsb 0
-#define xd_p_reg_ce_cent_forced_value_7_0	0xABDB
-#define	reg_ce_cent_forced_value_7_0_pos 0
-#define	reg_ce_cent_forced_value_7_0_len 8
-#define	reg_ce_cent_forced_value_7_0_lsb 0
-#define xd_p_reg_ce_cent_forced_value_11_8	0xABDC
-#define	reg_ce_cent_forced_value_11_8_pos 0
-#define	reg_ce_cent_forced_value_11_8_len 4
-#define	reg_ce_cent_forced_value_11_8_lsb 8
-#define xd_p_reg_ce_fctrl_rd	0xABDD
-#define	reg_ce_fctrl_rd_pos 0
-#define	reg_ce_fctrl_rd_len 1
-#define	reg_ce_fctrl_rd_lsb 0
-#define xd_p_reg_ce_centroid_max_6_0	0xABDD
-#define	reg_ce_centroid_max_6_0_pos 1
-#define	reg_ce_centroid_max_6_0_len 7
-#define	reg_ce_centroid_max_6_0_lsb 0
-#define xd_p_reg_ce_centroid_max_11_7	0xABDE
-#define	reg_ce_centroid_max_11_7_pos 0
-#define	reg_ce_centroid_max_11_7_len 5
-#define	reg_ce_centroid_max_11_7_lsb 7
-#define xd_p_reg_ce_var	0xABDF
-#define	reg_ce_var_pos 0
-#define	reg_ce_var_len 3
-#define	reg_ce_var_lsb 0
-#define xd_p_reg_ce_fctrl_rdy	0xABDF
-#define	reg_ce_fctrl_rdy_pos 3
-#define	reg_ce_fctrl_rdy_len 1
-#define	reg_ce_fctrl_rdy_lsb 0
-#define xd_p_reg_ce_centroid_out_3_0	0xABDF
-#define	reg_ce_centroid_out_3_0_pos 4
-#define	reg_ce_centroid_out_3_0_len 4
-#define	reg_ce_centroid_out_3_0_lsb 0
-#define xd_p_reg_ce_centroid_out_11_4	0xABE0
-#define	reg_ce_centroid_out_11_4_pos 0
-#define	reg_ce_centroid_out_11_4_len 8
-#define	reg_ce_centroid_out_11_4_lsb 4
-#define xd_p_reg_ce_bias_7_0	0xABE1
-#define	reg_ce_bias_7_0_pos 0
-#define	reg_ce_bias_7_0_len 8
-#define	reg_ce_bias_7_0_lsb 0
-#define xd_p_reg_ce_bias_11_8	0xABE2
-#define	reg_ce_bias_11_8_pos 0
-#define	reg_ce_bias_11_8_len 4
-#define	reg_ce_bias_11_8_lsb 8
-#define xd_p_reg_ce_m1_3_0	0xABE2
-#define	reg_ce_m1_3_0_pos 4
-#define	reg_ce_m1_3_0_len 4
-#define	reg_ce_m1_3_0_lsb 0
-#define xd_p_reg_ce_m1_11_4	0xABE3
-#define	reg_ce_m1_11_4_pos 0
-#define	reg_ce_m1_11_4_len 8
-#define	reg_ce_m1_11_4_lsb 4
-#define xd_p_reg_ce_rh0_7_0	0xABE4
-#define	reg_ce_rh0_7_0_pos 0
-#define	reg_ce_rh0_7_0_len 8
-#define	reg_ce_rh0_7_0_lsb 0
-#define xd_p_reg_ce_rh0_15_8	0xABE5
-#define	reg_ce_rh0_15_8_pos 0
-#define	reg_ce_rh0_15_8_len 8
-#define	reg_ce_rh0_15_8_lsb 8
-#define xd_p_reg_ce_rh0_23_16	0xABE6
-#define	reg_ce_rh0_23_16_pos 0
-#define	reg_ce_rh0_23_16_len 8
-#define	reg_ce_rh0_23_16_lsb 16
-#define xd_p_reg_ce_rh0_31_24	0xABE7
-#define	reg_ce_rh0_31_24_pos 0
-#define	reg_ce_rh0_31_24_len 8
-#define	reg_ce_rh0_31_24_lsb 24
-#define xd_p_reg_ce_rh3_real_7_0	0xABE8
-#define	reg_ce_rh3_real_7_0_pos 0
-#define	reg_ce_rh3_real_7_0_len 8
-#define	reg_ce_rh3_real_7_0_lsb 0
-#define xd_p_reg_ce_rh3_real_15_8	0xABE9
-#define	reg_ce_rh3_real_15_8_pos 0
-#define	reg_ce_rh3_real_15_8_len 8
-#define	reg_ce_rh3_real_15_8_lsb 8
-#define xd_p_reg_ce_rh3_real_23_16	0xABEA
-#define	reg_ce_rh3_real_23_16_pos 0
-#define	reg_ce_rh3_real_23_16_len 8
-#define	reg_ce_rh3_real_23_16_lsb 16
-#define xd_p_reg_ce_rh3_real_31_24	0xABEB
-#define	reg_ce_rh3_real_31_24_pos 0
-#define	reg_ce_rh3_real_31_24_len 8
-#define	reg_ce_rh3_real_31_24_lsb 24
-#define xd_p_reg_ce_rh3_imag_7_0	0xABEC
-#define	reg_ce_rh3_imag_7_0_pos 0
-#define	reg_ce_rh3_imag_7_0_len 8
-#define	reg_ce_rh3_imag_7_0_lsb 0
-#define xd_p_reg_ce_rh3_imag_15_8	0xABED
-#define	reg_ce_rh3_imag_15_8_pos 0
-#define	reg_ce_rh3_imag_15_8_len 8
-#define	reg_ce_rh3_imag_15_8_lsb 8
-#define xd_p_reg_ce_rh3_imag_23_16	0xABEE
-#define	reg_ce_rh3_imag_23_16_pos 0
-#define	reg_ce_rh3_imag_23_16_len 8
-#define	reg_ce_rh3_imag_23_16_lsb 16
-#define xd_p_reg_ce_rh3_imag_31_24	0xABEF
-#define	reg_ce_rh3_imag_31_24_pos 0
-#define	reg_ce_rh3_imag_31_24_len 8
-#define	reg_ce_rh3_imag_31_24_lsb 24
-#define xd_p_reg_feq_fix_eh2_7_0	0xABF0
-#define	reg_feq_fix_eh2_7_0_pos 0
-#define	reg_feq_fix_eh2_7_0_len 8
-#define	reg_feq_fix_eh2_7_0_lsb 0
-#define xd_p_reg_feq_fix_eh2_15_8	0xABF1
-#define	reg_feq_fix_eh2_15_8_pos 0
-#define	reg_feq_fix_eh2_15_8_len 8
-#define	reg_feq_fix_eh2_15_8_lsb 8
-#define xd_p_reg_feq_fix_eh2_23_16	0xABF2
-#define	reg_feq_fix_eh2_23_16_pos 0
-#define	reg_feq_fix_eh2_23_16_len 8
-#define	reg_feq_fix_eh2_23_16_lsb 16
-#define xd_p_reg_feq_fix_eh2_31_24	0xABF3
-#define	reg_feq_fix_eh2_31_24_pos 0
-#define	reg_feq_fix_eh2_31_24_len 8
-#define	reg_feq_fix_eh2_31_24_lsb 24
-#define xd_p_reg_ce_m2_central_7_0	0xABF4
-#define	reg_ce_m2_central_7_0_pos 0
-#define	reg_ce_m2_central_7_0_len 8
-#define	reg_ce_m2_central_7_0_lsb 0
-#define xd_p_reg_ce_m2_central_15_8	0xABF5
-#define	reg_ce_m2_central_15_8_pos 0
-#define	reg_ce_m2_central_15_8_len 8
-#define	reg_ce_m2_central_15_8_lsb 8
-#define xd_p_reg_ce_fftshift	0xABF6
-#define	reg_ce_fftshift_pos 0
-#define	reg_ce_fftshift_len 4
-#define	reg_ce_fftshift_lsb 0
-#define xd_p_reg_ce_fftshift1	0xABF6
-#define	reg_ce_fftshift1_pos 4
-#define	reg_ce_fftshift1_len 4
-#define	reg_ce_fftshift1_lsb 0
-#define xd_p_reg_ce_fftshift2	0xABF7
-#define	reg_ce_fftshift2_pos 0
-#define	reg_ce_fftshift2_len 4
-#define	reg_ce_fftshift2_lsb 0
-#define xd_p_reg_ce_top_mobile	0xABF7
-#define	reg_ce_top_mobile_pos 4
-#define	reg_ce_top_mobile_len 1
-#define	reg_ce_top_mobile_lsb 0
-#define xd_p_reg_strong_sginal_detected 0xA2BC
-#define reg_strong_sginal_detected_pos 2
-#define reg_strong_sginal_detected_len 1
-#define reg_strong_sginal_detected_lsb 0
-
-#define XD_MP2IF_BASE                           0xB000
-#define XD_MP2IF_CSR                        (0x00 + XD_MP2IF_BASE)
-#define XD_MP2IF_DMX_CTRL                       (0x03 + XD_MP2IF_BASE)
-#define XD_MP2IF_PID_IDX                        (0x04 + XD_MP2IF_BASE)
-#define XD_MP2IF_PID_DATA_L                     (0x05 + XD_MP2IF_BASE)
-#define XD_MP2IF_PID_DATA_H                     (0x06 + XD_MP2IF_BASE)
-#define XD_MP2IF_MISC                       (0x07 + XD_MP2IF_BASE)
-
-extern struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d);
-extern int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg,
-				     u8 * value);
-extern int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,
-				      u8 * values, int len);
-extern int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg,
-				      u8 value);
-extern int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,
-				       u8 * values, int len);
-extern int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg,
-				       u8 addr, u8 * values, int len);
-extern int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,
-					u8 * values, int len);
-extern int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg,
-				     u8 pos, u8 len, u8 * value);
-extern int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg,
-				      u8 pos, u8 len, u8 value);
-extern int af9005_send_command(struct dvb_usb_device *d, u8 command,
-			       u8 * wbuf, int wlen, u8 * rbuf, int rlen);
-extern int af9005_read_eeprom(struct dvb_usb_device *d, u8 address,
-			      u8 * values, int len);
-extern int af9005_tuner_attach(struct dvb_usb_adapter *adap);
-extern int af9005_led_control(struct dvb_usb_device *d, int onoff);
-
-extern u8 regmask[8];
-
-/* remote control decoder */
-extern int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len,
-			    u32 * event, int *state);
-extern struct rc_map_table rc_map_af9005_table[];
-extern int rc_map_af9005_table_size;
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
deleted file mode 100644
index 677fed7..0000000
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ /dev/null
@@ -1,1952 +0,0 @@
-/*
- * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
- *
- * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
- *
- * Thanks to Afatech who kindly provided information.
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/hash.h>
-#include <linux/slab.h>
-
-#include "af9015.h"
-#include "af9013.h"
-#include "mt2060.h"
-#include "qt1010.h"
-#include "tda18271.h"
-#include "mxl5005s.h"
-#include "mc44s803.h"
-#include "tda18218.h"
-#include "mxl5007t.h"
-
-static int dvb_usb_af9015_debug;
-module_param_named(debug, dvb_usb_af9015_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
-static int dvb_usb_af9015_remote;
-module_param_named(remote, dvb_usb_af9015_remote, int, 0644);
-MODULE_PARM_DESC(remote, "select remote");
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static DEFINE_MUTEX(af9015_usb_mutex);
-
-static struct af9015_config af9015_config;
-static struct dvb_usb_device_properties af9015_properties[3];
-static int af9015_properties_count = ARRAY_SIZE(af9015_properties);
-
-static struct af9013_config af9015_af9013_config[] = {
-	{
-		.i2c_addr = AF9015_I2C_DEMOD,
-		.ts_mode = AF9013_TS_USB,
-		.api_version = { 0, 1, 9, 0 },
-		.gpio[0] = AF9013_GPIO_HI,
-		.gpio[3] = AF9013_GPIO_TUNER_ON,
-
-	}, {
-		.ts_mode = AF9013_TS_SERIAL,
-		.api_version = { 0, 1, 9, 0 },
-		.gpio[0] = AF9013_GPIO_TUNER_ON,
-		.gpio[1] = AF9013_GPIO_LO,
-	}
-};
-
-static int af9015_rw_udev(struct usb_device *udev, struct req_t *req)
-{
-#define BUF_LEN 63
-#define REQ_HDR_LEN 8 /* send header size */
-#define ACK_HDR_LEN 2 /* rece header size */
-	int act_len, ret;
-	u8 buf[BUF_LEN];
-	u8 write = 1;
-	u8 msg_len = REQ_HDR_LEN;
-	static u8 seq; /* packet sequence number */
-
-	if (mutex_lock_interruptible(&af9015_usb_mutex) < 0)
-		return -EAGAIN;
-
-	buf[0] = req->cmd;
-	buf[1] = seq++;
-	buf[2] = req->i2c_addr;
-	buf[3] = req->addr >> 8;
-	buf[4] = req->addr & 0xff;
-	buf[5] = req->mbox;
-	buf[6] = req->addr_len;
-	buf[7] = req->data_len;
-
-	switch (req->cmd) {
-	case GET_CONFIG:
-	case READ_MEMORY:
-	case RECONNECT_USB:
-		write = 0;
-		break;
-	case READ_I2C:
-		write = 0;
-		buf[2] |= 0x01; /* set I2C direction */
-	case WRITE_I2C:
-		buf[0] = READ_WRITE_I2C;
-		break;
-	case WRITE_MEMORY:
-		if (((req->addr & 0xff00) == 0xff00) ||
-		    ((req->addr & 0xff00) == 0xae00))
-			buf[0] = WRITE_VIRTUAL_MEMORY;
-	case WRITE_VIRTUAL_MEMORY:
-	case COPY_FIRMWARE:
-	case DOWNLOAD_FIRMWARE:
-	case BOOT:
-		break;
-	default:
-		err("unknown command:%d", req->cmd);
-		ret = -1;
-		goto error_unlock;
-	}
-
-	/* buffer overflow check */
-	if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) ||
-		(!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) {
-		err("too much data; cmd:%d len:%d", req->cmd, req->data_len);
-		ret = -EINVAL;
-		goto error_unlock;
-	}
-
-	/* write requested */
-	if (write) {
-		memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len);
-		msg_len += req->data_len;
-	}
-
-	deb_xfer(">>> ");
-	debug_dump(buf, msg_len, deb_xfer);
-
-	/* send req */
-	ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len,
-		&act_len, AF9015_USB_TIMEOUT);
-	if (ret)
-		err("bulk message failed:%d (%d/%d)", ret, msg_len, act_len);
-	else
-		if (act_len != msg_len)
-			ret = -1; /* all data is not send */
-	if (ret)
-		goto error_unlock;
-
-	/* no ack for those packets */
-	if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB)
-		goto exit_unlock;
-
-	/* write receives seq + status = 2 bytes
-	   read receives seq + status + data = 2 + N bytes */
-	msg_len = ACK_HDR_LEN;
-	if (!write)
-		msg_len += req->data_len;
-
-	ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len,
-		&act_len, AF9015_USB_TIMEOUT);
-	if (ret) {
-		err("recv bulk message failed:%d", ret);
-		ret = -1;
-		goto error_unlock;
-	}
-
-	deb_xfer("<<< ");
-	debug_dump(buf, act_len, deb_xfer);
-
-	/* check status */
-	if (buf[1]) {
-		err("command failed:%d", buf[1]);
-		ret = -1;
-		goto error_unlock;
-	}
-
-	/* read request, copy returned data to return buf */
-	if (!write)
-		memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len);
-
-error_unlock:
-exit_unlock:
-	mutex_unlock(&af9015_usb_mutex);
-
-	return ret;
-}
-
-static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
-{
-	return af9015_rw_udev(d->udev, req);
-}
-
-static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val,
-	u8 len)
-{
-	struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
-		val};
-	return af9015_ctrl_msg(d, &req);
-}
-
-static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val)
-{
-	return af9015_write_regs(d, addr, &val, 1);
-}
-
-static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len)
-{
-	struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
-		val};
-	return af9015_ctrl_msg(d, &req);
-}
-
-static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val)
-{
-	return af9015_read_regs(d, addr, val, 1);
-}
-
-static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
-	u8 val)
-{
-	struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val};
-
-	if (addr == af9015_af9013_config[0].i2c_addr ||
-	    addr == af9015_af9013_config[1].i2c_addr)
-		req.addr_len = 3;
-
-	return af9015_ctrl_msg(d, &req);
-}
-
-static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
-	u8 *val)
-{
-	struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val};
-
-	if (addr == af9015_af9013_config[0].i2c_addr ||
-	    addr == af9015_af9013_config[1].i2c_addr)
-		req.addr_len = 3;
-
-	return af9015_ctrl_msg(d, &req);
-}
-
-static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-	int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int ret = 0, i = 0;
-	u16 addr;
-	u8 uninitialized_var(mbox), addr_len;
-	struct req_t req;
-
-/*
-The bus lock is needed because there is two tuners both using same I2C-address.
-Due to that the only way to select correct tuner is use demodulator I2C-gate.
-
-................................................
-. AF9015 includes integrated AF9013 demodulator.
-. ____________                   ____________  .                ____________
-.|     uC     |                 |   demod    | .               |    tuner   |
-.|------------|                 |------------| .               |------------|
-.|   AF9015   |                 |  AF9013/5  | .               |   MXL5003  |
-.|            |--+----I2C-------|-----/ -----|-.-----I2C-------|            |
-.|            |  |              | addr 0x38  | .               |  addr 0xc6 |
-.|____________|  |              |____________| .               |____________|
-.................|..............................
-		 |               ____________                   ____________
-		 |              |   demod    |                 |    tuner   |
-		 |              |------------|                 |------------|
-		 |              |   AF9013   |                 |   MXL5003  |
-		 +----I2C-------|-----/ -----|-------I2C-------|            |
-				| addr 0x3a  |                 |  addr 0xc6 |
-				|____________|                 |____________|
-*/
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	while (i < num) {
-		if (msg[i].addr == af9015_af9013_config[0].i2c_addr ||
-		    msg[i].addr == af9015_af9013_config[1].i2c_addr) {
-			addr = msg[i].buf[0] << 8;
-			addr += msg[i].buf[1];
-			mbox = msg[i].buf[2];
-			addr_len = 3;
-		} else {
-			addr = msg[i].buf[0];
-			addr_len = 1;
-			/* mbox is don't care in that case */
-		}
-
-		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
-			if (msg[i].len > 3 || msg[i+1].len > 61) {
-				ret = -EOPNOTSUPP;
-				goto error;
-			}
-			if (msg[i].addr == af9015_af9013_config[0].i2c_addr)
-				req.cmd = READ_MEMORY;
-			else
-				req.cmd = READ_I2C;
-			req.i2c_addr = msg[i].addr;
-			req.addr = addr;
-			req.mbox = mbox;
-			req.addr_len = addr_len;
-			req.data_len = msg[i+1].len;
-			req.data = &msg[i+1].buf[0];
-			ret = af9015_ctrl_msg(d, &req);
-			i += 2;
-		} else if (msg[i].flags & I2C_M_RD) {
-			if (msg[i].len > 61) {
-				ret = -EOPNOTSUPP;
-				goto error;
-			}
-			if (msg[i].addr ==
-				af9015_af9013_config[0].i2c_addr) {
-				ret = -EINVAL;
-				goto error;
-			}
-			req.cmd = READ_I2C;
-			req.i2c_addr = msg[i].addr;
-			req.addr = addr;
-			req.mbox = mbox;
-			req.addr_len = addr_len;
-			req.data_len = msg[i].len;
-			req.data = &msg[i].buf[0];
-			ret = af9015_ctrl_msg(d, &req);
-			i += 1;
-		} else {
-			if (msg[i].len > 21) {
-				ret = -EOPNOTSUPP;
-				goto error;
-			}
-			if (msg[i].addr == af9015_af9013_config[0].i2c_addr)
-				req.cmd = WRITE_MEMORY;
-			else
-				req.cmd = WRITE_I2C;
-			req.i2c_addr = msg[i].addr;
-			req.addr = addr;
-			req.mbox = mbox;
-			req.addr_len = addr_len;
-			req.data_len = msg[i].len-addr_len;
-			req.data = &msg[i].buf[addr_len];
-			ret = af9015_ctrl_msg(d, &req);
-			i += 1;
-		}
-		if (ret)
-			goto error;
-
-	}
-	ret = i;
-
-error:
-	mutex_unlock(&d->i2c_mutex);
-
-	return ret;
-}
-
-static u32 af9015_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm af9015_i2c_algo = {
-	.master_xfer = af9015_i2c_xfer,
-	.functionality = af9015_i2c_func,
-};
-
-static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op)
-{
-	int ret;
-	u8 val, mask = 0x01;
-
-	ret = af9015_read_reg(d, addr, &val);
-	if (ret)
-		return ret;
-
-	mask <<= bit;
-	if (op) {
-		/* set bit */
-		val |= mask;
-	} else {
-		/* clear bit */
-		mask ^= 0xff;
-		val &= mask;
-	}
-
-	return af9015_write_reg(d, addr, val);
-}
-
-static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
-{
-	return af9015_do_reg_bit(d, addr, bit, 1);
-}
-
-static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
-{
-	return af9015_do_reg_bit(d, addr, bit, 0);
-}
-
-static int af9015_init_endpoint(struct dvb_usb_device *d)
-{
-	int ret;
-	u16 frame_size;
-	u8  packet_size;
-	deb_info("%s: USB speed:%d\n", __func__, d->udev->speed);
-
-	/* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0.
-	   We use smaller - about 1/4 from the original, 5 and 87. */
-#define TS_PACKET_SIZE            188
-
-#define TS_USB20_PACKET_COUNT      87
-#define TS_USB20_FRAME_SIZE       (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT)
-
-#define TS_USB11_PACKET_COUNT       5
-#define TS_USB11_FRAME_SIZE       (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT)
-
-#define TS_USB20_MAX_PACKET_SIZE  512
-#define TS_USB11_MAX_PACKET_SIZE   64
-
-	if (d->udev->speed == USB_SPEED_FULL) {
-		frame_size = TS_USB11_FRAME_SIZE/4;
-		packet_size = TS_USB11_MAX_PACKET_SIZE/4;
-	} else {
-		frame_size = TS_USB20_FRAME_SIZE/4;
-		packet_size = TS_USB20_MAX_PACKET_SIZE/4;
-	}
-
-	ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */
-	if (ret)
-		goto error;
-	ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */
-	if (ret)
-		goto error;
-	ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */
-	if (ret)
-		goto error;
-	ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */
-	if (ret)
-		goto error;
-	ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */
-	if (ret)
-		goto error;
-	if (af9015_config.dual_mode) {
-		ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */
-		if (ret)
-			goto error;
-	}
-	ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */
-	if (ret)
-		goto error;
-	if (af9015_config.dual_mode) {
-		ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */
-		if (ret)
-			goto error;
-	}
-	/* EP4 xfer length */
-	ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff);
-	if (ret)
-		goto error;
-	ret = af9015_write_reg(d, 0xdd89, frame_size >> 8);
-	if (ret)
-		goto error;
-	/* EP5 xfer length */
-	ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff);
-	if (ret)
-		goto error;
-	ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8);
-	if (ret)
-		goto error;
-	ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */
-	if (ret)
-		goto error;
-	ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */
-	if (ret)
-		goto error;
-	ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */
-	if (ret)
-		goto error;
-	if (af9015_config.dual_mode) {
-		ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */
-		if (ret)
-			goto error;
-	}
-
-	/* enable / disable mp2if2 */
-	if (af9015_config.dual_mode)
-		ret = af9015_set_reg_bit(d, 0xd50b, 0);
-	else
-		ret = af9015_clear_reg_bit(d, 0xd50b, 0);
-
-error:
-	if (ret)
-		err("endpoint init failed:%d", ret);
-	return ret;
-}
-
-static int af9015_copy_firmware(struct dvb_usb_device *d)
-{
-	int ret;
-	u8 fw_params[4];
-	u8 val, i;
-	struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params),
-		fw_params };
-	deb_info("%s:\n", __func__);
-
-	fw_params[0] = af9015_config.firmware_size >> 8;
-	fw_params[1] = af9015_config.firmware_size & 0xff;
-	fw_params[2] = af9015_config.firmware_checksum >> 8;
-	fw_params[3] = af9015_config.firmware_checksum & 0xff;
-
-	/* wait 2nd demodulator ready */
-	msleep(100);
-
-	ret = af9015_read_reg_i2c(d,
-		af9015_af9013_config[1].i2c_addr, 0x98be, &val);
-	if (ret)
-		goto error;
-	else
-		deb_info("%s: firmware status:%02x\n", __func__, val);
-
-	if (val == 0x0c) /* fw is running, no need for download */
-		goto exit;
-
-	/* set I2C master clock to fast (to speed up firmware copy) */
-	ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */
-	if (ret)
-		goto error;
-
-	msleep(50);
-
-	/* copy firmware */
-	ret = af9015_ctrl_msg(d, &req);
-	if (ret)
-		err("firmware copy cmd failed:%d", ret);
-	deb_info("%s: firmware copy done\n", __func__);
-
-	/* set I2C master clock back to normal */
-	ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */
-	if (ret)
-		goto error;
-
-	/* request boot firmware */
-	ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].i2c_addr,
-		0xe205, 1);
-	deb_info("%s: firmware boot cmd status:%d\n", __func__, ret);
-	if (ret)
-		goto error;
-
-	for (i = 0; i < 15; i++) {
-		msleep(100);
-
-		/* check firmware status */
-		ret = af9015_read_reg_i2c(d,
-			af9015_af9013_config[1].i2c_addr, 0x98be, &val);
-		deb_info("%s: firmware status cmd status:%d fw status:%02x\n",
-			__func__, ret, val);
-		if (ret)
-			goto error;
-
-		if (val == 0x0c || val == 0x04) /* success or fail */
-			break;
-	}
-
-	if (val == 0x04) {
-		err("firmware did not run");
-		ret = -1;
-	} else if (val != 0x0c) {
-		err("firmware boot timeout");
-		ret = -1;
-	}
-
-error:
-exit:
-	return ret;
-}
-
-/* hash (and dump) eeprom */
-static int af9015_eeprom_hash(struct usb_device *udev)
-{
-	static const unsigned int eeprom_size = 256;
-	unsigned int reg;
-	int ret;
-	u8 val, *eeprom;
-	struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
-
-	eeprom = kmalloc(eeprom_size, GFP_KERNEL);
-	if (eeprom == NULL)
-		return -ENOMEM;
-
-	for (reg = 0; reg < eeprom_size; reg++) {
-		req.addr = reg;
-		ret = af9015_rw_udev(udev, &req);
-		if (ret)
-			goto free;
-		eeprom[reg] = val;
-	}
-
-	if (dvb_usb_af9015_debug & 0x01)
-		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, eeprom,
-				eeprom_size);
-
-	BUG_ON(eeprom_size % 4);
-
-	af9015_config.eeprom_sum = 0;
-	for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) {
-		af9015_config.eeprom_sum *= GOLDEN_RATIO_PRIME_32;
-		af9015_config.eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]);
-	}
-
-	deb_info("%s: eeprom sum=%.8x\n", __func__, af9015_config.eeprom_sum);
-
-	ret = 0;
-free:
-	kfree(eeprom);
-	return ret;
-}
-
-static int af9015_init(struct dvb_usb_device *d)
-{
-	int ret;
-	deb_info("%s:\n", __func__);
-
-	/* init RC canary */
-	ret = af9015_write_reg(d, 0x98e9, 0xff);
-	if (ret)
-		goto error;
-
-	ret = af9015_init_endpoint(d);
-	if (ret)
-		goto error;
-
-error:
-	return ret;
-}
-
-static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	int ret;
-	deb_info("%s: onoff:%d\n", __func__, onoff);
-
-	if (onoff)
-		ret = af9015_set_reg_bit(adap->dev, 0xd503, 0);
-	else
-		ret = af9015_clear_reg_bit(adap->dev, 0xd503, 0);
-
-	return ret;
-}
-
-static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
-	int onoff)
-{
-	int ret;
-	u8 idx;
-
-	deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n",
-		__func__, index, pid, onoff);
-
-	ret = af9015_write_reg(adap->dev, 0xd505, (pid & 0xff));
-	if (ret)
-		goto error;
-
-	ret = af9015_write_reg(adap->dev, 0xd506, (pid >> 8));
-	if (ret)
-		goto error;
-
-	idx = ((index & 0x1f) | (1 << 5));
-	ret = af9015_write_reg(adap->dev, 0xd504, idx);
-
-error:
-	return ret;
-}
-
-static int af9015_download_firmware(struct usb_device *udev,
-	const struct firmware *fw)
-{
-	int i, len, remaining, ret;
-	struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL};
-	u16 checksum = 0;
-
-	deb_info("%s:\n", __func__);
-
-	/* calc checksum */
-	for (i = 0; i < fw->size; i++)
-		checksum += fw->data[i];
-
-	af9015_config.firmware_size = fw->size;
-	af9015_config.firmware_checksum = checksum;
-
-	#define FW_ADDR 0x5100 /* firmware start address */
-	#define LEN_MAX 55 /* max packet size */
-	for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) {
-		len = remaining;
-		if (len > LEN_MAX)
-			len = LEN_MAX;
-
-		req.data_len = len;
-		req.data = (u8 *) &fw->data[fw->size - remaining];
-		req.addr = FW_ADDR + fw->size - remaining;
-
-		ret = af9015_rw_udev(udev, &req);
-		if (ret) {
-			err("firmware download failed:%d", ret);
-			goto error;
-		}
-	}
-
-	/* firmware loaded, request boot */
-	req.cmd = BOOT;
-	ret = af9015_rw_udev(udev, &req);
-	if (ret) {
-		err("firmware boot failed:%d", ret);
-		goto error;
-	}
-
-error:
-	return ret;
-}
-
-struct af9015_rc_setup {
-	unsigned int id;
-	char *rc_codes;
-};
-
-static char *af9015_rc_setup_match(unsigned int id,
-	const struct af9015_rc_setup *table)
-{
-	for (; table->rc_codes; table++)
-		if (table->id == id)
-			return table->rc_codes;
-	return NULL;
-}
-
-static const struct af9015_rc_setup af9015_rc_setup_modparam[] = {
-	{ AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M },
-	{ AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II },
-	{ AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND },
-	{ AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE },
-	{ AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS },
-	{ }
-};
-
-static const struct af9015_rc_setup af9015_rc_setup_hashes[] = {
-	{ 0xb8feb708, RC_MAP_MSI_DIGIVOX_II },
-	{ 0xa3703d00, RC_MAP_ALINK_DTU_M },
-	{ 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */
-	{ 0x5d49e3db, RC_MAP_DIGITTRADE }, /* LC-Power LC-USB-DVBT */
-	{ }
-};
-
-static const struct af9015_rc_setup af9015_rc_setup_usbids[] = {
-	{ (USB_VID_TERRATEC << 16) | USB_PID_TERRATEC_CINERGY_T_STICK_RC,
-		RC_MAP_TERRATEC_SLIM_2 },
-	{ (USB_VID_TERRATEC << 16) | USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC,
-		RC_MAP_TERRATEC_SLIM },
-	{ (USB_VID_VISIONPLUS << 16) | USB_PID_AZUREWAVE_AD_TU700,
-		RC_MAP_AZUREWAVE_AD_TU700 },
-	{ (USB_VID_VISIONPLUS << 16) | USB_PID_TINYTWIN,
-		RC_MAP_AZUREWAVE_AD_TU700 },
-	{ (USB_VID_MSI_2 << 16) | USB_PID_MSI_DIGI_VOX_MINI_III,
-		RC_MAP_MSI_DIGIVOX_III },
-	{ (USB_VID_MSI_2 << 16) | USB_PID_MSI_DIGIVOX_DUO,
-		RC_MAP_MSI_DIGIVOX_III },
-	{ (USB_VID_LEADTEK << 16) | USB_PID_WINFAST_DTV_DONGLE_GOLD,
-		RC_MAP_LEADTEK_Y04G0051 },
-	{ (USB_VID_LEADTEK << 16) | USB_PID_WINFAST_DTV2000DS,
-		RC_MAP_LEADTEK_Y04G0051 },
-	{ (USB_VID_AVERMEDIA << 16) | USB_PID_AVERMEDIA_VOLAR_X,
-		RC_MAP_AVERMEDIA_M135A },
-	{ (USB_VID_AFATECH << 16) | USB_PID_TREKSTOR_DVBT,
-		RC_MAP_TREKSTOR },
-	{ (USB_VID_KWORLD_2 << 16) | USB_PID_TINYTWIN_2,
-		RC_MAP_DIGITALNOW_TINYTWIN },
-	{ (USB_VID_GTEK << 16) | USB_PID_TINYTWIN_3,
-		RC_MAP_DIGITALNOW_TINYTWIN },
-	{ (USB_VID_KWORLD_2 << 16) | USB_PID_SVEON_STV22,
-		RC_MAP_MSI_DIGIVOX_III },
-	{ }
-};
-
-static void af9015_set_remote_config(struct usb_device *udev,
-		struct dvb_usb_device_properties *props)
-{
-	u16 vid = le16_to_cpu(udev->descriptor.idVendor);
-	u16 pid = le16_to_cpu(udev->descriptor.idProduct);
-
-	/* try to load remote based module param */
-	props->rc.core.rc_codes = af9015_rc_setup_match(
-		dvb_usb_af9015_remote, af9015_rc_setup_modparam);
-
-	/* try to load remote based eeprom hash */
-	if (!props->rc.core.rc_codes)
-		props->rc.core.rc_codes = af9015_rc_setup_match(
-			af9015_config.eeprom_sum, af9015_rc_setup_hashes);
-
-	/* try to load remote based USB ID */
-	if (!props->rc.core.rc_codes)
-		props->rc.core.rc_codes = af9015_rc_setup_match(
-			(vid << 16) | pid, af9015_rc_setup_usbids);
-
-	/* try to load remote based USB iManufacturer string */
-	if (!props->rc.core.rc_codes && vid == USB_VID_AFATECH) {
-		/* Check USB manufacturer and product strings and try
-		   to determine correct remote in case of chip vendor
-		   reference IDs are used.
-		   DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */
-		char manufacturer[10];
-		memset(manufacturer, 0, sizeof(manufacturer));
-		usb_string(udev, udev->descriptor.iManufacturer,
-			manufacturer, sizeof(manufacturer));
-		if (!strcmp("MSI", manufacturer)) {
-			/* iManufacturer 1 MSI
-			   iProduct      2 MSI K-VOX */
-			props->rc.core.rc_codes = af9015_rc_setup_match(
-				AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
-				af9015_rc_setup_modparam);
-		}
-	}
-
-	/* finally load "empty" just for leaving IR receiver enabled */
-	if (!props->rc.core.rc_codes)
-		props->rc.core.rc_codes = RC_MAP_EMPTY;
-
-	return;
-}
-
-static int af9015_read_config(struct usb_device *udev)
-{
-	int ret;
-	u8 val, i, offset = 0;
-	struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
-
-	/* IR remote controller */
-	req.addr = AF9015_EEPROM_IR_MODE;
-	/* first message will timeout often due to possible hw bug */
-	for (i = 0; i < 4; i++) {
-		ret = af9015_rw_udev(udev, &req);
-		if (!ret)
-			break;
-	}
-	if (ret)
-		goto error;
-
-	ret = af9015_eeprom_hash(udev);
-	if (ret)
-		goto error;
-
-	deb_info("%s: IR mode=%d\n", __func__, val);
-	for (i = 0; i < af9015_properties_count; i++) {
-		if (val == AF9015_IR_MODE_DISABLED)
-			af9015_properties[i].rc.core.rc_codes = NULL;
-		else
-			af9015_set_remote_config(udev, &af9015_properties[i]);
-	}
-
-	/* TS mode - one or two receivers */
-	req.addr = AF9015_EEPROM_TS_MODE;
-	ret = af9015_rw_udev(udev, &req);
-	if (ret)
-		goto error;
-	af9015_config.dual_mode = val;
-	deb_info("%s: TS mode=%d\n", __func__, af9015_config.dual_mode);
-
-	/* Set adapter0 buffer size according to USB port speed, adapter1 buffer
-	   size can be static because it is enabled only USB2.0 */
-	for (i = 0; i < af9015_properties_count; i++) {
-		/* USB1.1 set smaller buffersize and disable 2nd adapter */
-		if (udev->speed == USB_SPEED_FULL) {
-			af9015_properties[i].adapter[0].fe[0].stream.u.bulk.buffersize
-				= TS_USB11_FRAME_SIZE;
-			/* disable 2nd adapter because we don't have
-			   PID-filters */
-			af9015_config.dual_mode = 0;
-		} else {
-			af9015_properties[i].adapter[0].fe[0].stream.u.bulk.buffersize
-				= TS_USB20_FRAME_SIZE;
-		}
-	}
-
-	if (af9015_config.dual_mode) {
-		/* read 2nd demodulator I2C address */
-		req.addr = AF9015_EEPROM_DEMOD2_I2C;
-		ret = af9015_rw_udev(udev, &req);
-		if (ret)
-			goto error;
-		af9015_af9013_config[1].i2c_addr = val;
-
-		/* enable 2nd adapter */
-		for (i = 0; i < af9015_properties_count; i++)
-			af9015_properties[i].num_adapters = 2;
-
-	} else {
-		 /* disable 2nd adapter */
-		for (i = 0; i < af9015_properties_count; i++)
-			af9015_properties[i].num_adapters = 1;
-	}
-
-	for (i = 0; i < af9015_properties[0].num_adapters; i++) {
-		if (i == 1)
-			offset = AF9015_EEPROM_OFFSET;
-		/* xtal */
-		req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset;
-		ret = af9015_rw_udev(udev, &req);
-		if (ret)
-			goto error;
-		switch (val) {
-		case 0:
-			af9015_af9013_config[i].clock = 28800000;
-			break;
-		case 1:
-			af9015_af9013_config[i].clock = 20480000;
-			break;
-		case 2:
-			af9015_af9013_config[i].clock = 28000000;
-			break;
-		case 3:
-			af9015_af9013_config[i].clock = 25000000;
-			break;
-		};
-		deb_info("%s: [%d] xtal=%d set clock=%d\n", __func__, i,
-			val, af9015_af9013_config[i].clock);
-
-		/* IF frequency */
-		req.addr = AF9015_EEPROM_IF1H + offset;
-		ret = af9015_rw_udev(udev, &req);
-		if (ret)
-			goto error;
-
-		af9015_af9013_config[i].if_frequency = val << 8;
-
-		req.addr = AF9015_EEPROM_IF1L + offset;
-		ret = af9015_rw_udev(udev, &req);
-		if (ret)
-			goto error;
-
-		af9015_af9013_config[i].if_frequency += val;
-		af9015_af9013_config[i].if_frequency *= 1000;
-		deb_info("%s: [%d] IF frequency=%d\n", __func__, i,
-			af9015_af9013_config[0].if_frequency);
-
-		/* MT2060 IF1 */
-		req.addr = AF9015_EEPROM_MT2060_IF1H  + offset;
-		ret = af9015_rw_udev(udev, &req);
-		if (ret)
-			goto error;
-		af9015_config.mt2060_if1[i] = val << 8;
-		req.addr = AF9015_EEPROM_MT2060_IF1L + offset;
-		ret = af9015_rw_udev(udev, &req);
-		if (ret)
-			goto error;
-		af9015_config.mt2060_if1[i] += val;
-		deb_info("%s: [%d] MT2060 IF1=%d\n", __func__, i,
-			af9015_config.mt2060_if1[i]);
-
-		/* tuner */
-		req.addr =  AF9015_EEPROM_TUNER_ID1 + offset;
-		ret = af9015_rw_udev(udev, &req);
-		if (ret)
-			goto error;
-		switch (val) {
-		case AF9013_TUNER_ENV77H11D5:
-		case AF9013_TUNER_MT2060:
-		case AF9013_TUNER_QT1010:
-		case AF9013_TUNER_UNKNOWN:
-		case AF9013_TUNER_MT2060_2:
-		case AF9013_TUNER_TDA18271:
-		case AF9013_TUNER_QT1010A:
-		case AF9013_TUNER_TDA18218:
-			af9015_af9013_config[i].spec_inv = 1;
-			break;
-		case AF9013_TUNER_MXL5003D:
-		case AF9013_TUNER_MXL5005D:
-		case AF9013_TUNER_MXL5005R:
-		case AF9013_TUNER_MXL5007T:
-			af9015_af9013_config[i].spec_inv = 0;
-			break;
-		case AF9013_TUNER_MC44S803:
-			af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO;
-			af9015_af9013_config[i].spec_inv = 1;
-			break;
-		default:
-			warn("tuner id=%d not supported, please report!", val);
-			return -ENODEV;
-		};
-
-		af9015_af9013_config[i].tuner = val;
-		deb_info("%s: [%d] tuner id=%d\n", __func__, i, val);
-	}
-
-error:
-	if (ret)
-		err("eeprom read failed=%d", ret);
-
-	/* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM
-	   content :-( Override some wrong values here. Ditto for the
-	   AVerTV Red HD+ (A850T) device. */
-	if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_AVERMEDIA &&
-		((le16_to_cpu(udev->descriptor.idProduct) ==
-			USB_PID_AVERMEDIA_A850) ||
-		(le16_to_cpu(udev->descriptor.idProduct) ==
-			USB_PID_AVERMEDIA_A850T))) {
-		deb_info("%s: AverMedia A850: overriding config\n", __func__);
-		/* disable dual mode */
-		af9015_config.dual_mode = 0;
-		 /* disable 2nd adapter */
-		for (i = 0; i < af9015_properties_count; i++)
-			af9015_properties[i].num_adapters = 1;
-
-		/* set correct IF */
-		af9015_af9013_config[0].if_frequency = 4570000;
-	}
-
-	return ret;
-}
-
-static int af9015_identify_state(struct usb_device *udev,
-				 struct dvb_usb_device_properties *props,
-				 struct dvb_usb_device_description **desc,
-				 int *cold)
-{
-	int ret;
-	u8 reply;
-	struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply};
-
-	ret = af9015_rw_udev(udev, &req);
-	if (ret)
-		return ret;
-
-	deb_info("%s: reply:%02x\n", __func__, reply);
-	if (reply == 0x02)
-		*cold = 0;
-	else
-		*cold = 1;
-
-	return ret;
-}
-
-static int af9015_rc_query(struct dvb_usb_device *d)
-{
-	struct af9015_state *priv = d->priv;
-	int ret;
-	u8 buf[17];
-
-	/* read registers needed to detect remote controller code */
-	ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf));
-	if (ret)
-		goto error;
-
-	/* If any of these are non-zero, assume invalid data */
-	if (buf[1] || buf[2] || buf[3])
-		return ret;
-
-	/* Check for repeat of previous code */
-	if ((priv->rc_repeat != buf[6] || buf[0]) &&
-					!memcmp(&buf[12], priv->rc_last, 4)) {
-		deb_rc("%s: key repeated\n", __func__);
-		rc_keydown(d->rc_dev, priv->rc_keycode, 0);
-		priv->rc_repeat = buf[6];
-		return ret;
-	}
-
-	/* Only process key if canary killed */
-	if (buf[16] != 0xff && buf[0] != 0x01) {
-		deb_rc("%s: key pressed %02x %02x %02x %02x\n", __func__,
-			buf[12], buf[13], buf[14], buf[15]);
-
-		/* Reset the canary */
-		ret = af9015_write_reg(d, 0x98e9, 0xff);
-		if (ret)
-			goto error;
-
-		/* Remember this key */
-		memcpy(priv->rc_last, &buf[12], 4);
-		if (buf[14] == (u8) ~buf[15]) {
-			if (buf[12] == (u8) ~buf[13]) {
-				/* NEC */
-				priv->rc_keycode = buf[12] << 8 | buf[14];
-			} else {
-				/* NEC extended*/
-				priv->rc_keycode = buf[12] << 16 |
-					buf[13] << 8 | buf[14];
-			}
-		} else {
-			/* 32 bit NEC */
-			priv->rc_keycode = buf[12] << 24 | buf[13] << 16 |
-					buf[14] << 8 | buf[15];
-		}
-		rc_keydown(d->rc_dev, priv->rc_keycode, 0);
-	} else {
-		deb_rc("%s: no key press\n", __func__);
-		/* Invalidate last keypress */
-		/* Not really needed, but helps with debug */
-		priv->rc_last[2] = priv->rc_last[3];
-	}
-
-	priv->rc_repeat = buf[6];
-
-error:
-	if (ret)
-		err("%s: failed:%d", __func__, ret);
-
-	return ret;
-}
-
-/* override demod callbacks for resource locking */
-static int af9015_af9013_set_frontend(struct dvb_frontend *fe)
-{
-	int ret;
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct af9015_state *priv = adap->dev->priv;
-
-	if (mutex_lock_interruptible(&adap->dev->usb_mutex))
-		return -EAGAIN;
-
-	ret = priv->set_frontend[adap->id](fe);
-
-	mutex_unlock(&adap->dev->usb_mutex);
-
-	return ret;
-}
-
-/* override demod callbacks for resource locking */
-static int af9015_af9013_read_status(struct dvb_frontend *fe,
-	fe_status_t *status)
-{
-	int ret;
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct af9015_state *priv = adap->dev->priv;
-
-	if (mutex_lock_interruptible(&adap->dev->usb_mutex))
-		return -EAGAIN;
-
-	ret = priv->read_status[adap->id](fe, status);
-
-	mutex_unlock(&adap->dev->usb_mutex);
-
-	return ret;
-}
-
-/* override demod callbacks for resource locking */
-static int af9015_af9013_init(struct dvb_frontend *fe)
-{
-	int ret;
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct af9015_state *priv = adap->dev->priv;
-
-	if (mutex_lock_interruptible(&adap->dev->usb_mutex))
-		return -EAGAIN;
-
-	ret = priv->init[adap->id](fe);
-
-	mutex_unlock(&adap->dev->usb_mutex);
-
-	return ret;
-}
-
-/* override demod callbacks for resource locking */
-static int af9015_af9013_sleep(struct dvb_frontend *fe)
-{
-	int ret;
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct af9015_state *priv = adap->dev->priv;
-
-	if (mutex_lock_interruptible(&adap->dev->usb_mutex))
-		return -EAGAIN;
-
-	ret = priv->sleep[adap->id](fe);
-
-	mutex_unlock(&adap->dev->usb_mutex);
-
-	return ret;
-}
-
-/* override tuner callbacks for resource locking */
-static int af9015_tuner_init(struct dvb_frontend *fe)
-{
-	int ret;
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct af9015_state *priv = adap->dev->priv;
-
-	if (mutex_lock_interruptible(&adap->dev->usb_mutex))
-		return -EAGAIN;
-
-	ret = priv->tuner_init[adap->id](fe);
-
-	mutex_unlock(&adap->dev->usb_mutex);
-
-	return ret;
-}
-
-/* override tuner callbacks for resource locking */
-static int af9015_tuner_sleep(struct dvb_frontend *fe)
-{
-	int ret;
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct af9015_state *priv = adap->dev->priv;
-
-	if (mutex_lock_interruptible(&adap->dev->usb_mutex))
-		return -EAGAIN;
-
-	ret = priv->tuner_sleep[adap->id](fe);
-
-	mutex_unlock(&adap->dev->usb_mutex);
-
-	return ret;
-}
-
-
-static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	int ret;
-	struct af9015_state *state = adap->dev->priv;
-
-	if (adap->id == 1) {
-		/* copy firmware to 2nd demodulator */
-		if (af9015_config.dual_mode) {
-			ret = af9015_copy_firmware(adap->dev);
-			if (ret) {
-				err("firmware copy to 2nd frontend " \
-					"failed, will disable it");
-				af9015_config.dual_mode = 0;
-				return -ENODEV;
-			}
-		} else {
-			return -ENODEV;
-		}
-	}
-
-	/* attach demodulator */
-	adap->fe_adap[0].fe = dvb_attach(af9013_attach,
-		&af9015_af9013_config[adap->id], &adap->dev->i2c_adap);
-
-	/*
-	 * AF9015 firmware does not like if it gets interrupted by I2C adapter
-	 * request on some critical phases. During normal operation I2C adapter
-	 * is used only 2nd demodulator and tuner on dual tuner devices.
-	 * Override demodulator callbacks and use mutex for limit access to
-	 * those "critical" paths to keep AF9015 happy.
-	 * Note: we abuse unused usb_mutex here.
-	 */
-	if (adap->fe_adap[0].fe) {
-		state->set_frontend[adap->id] =
-			adap->fe_adap[0].fe->ops.set_frontend;
-		adap->fe_adap[0].fe->ops.set_frontend =
-			af9015_af9013_set_frontend;
-
-		state->read_status[adap->id] =
-			adap->fe_adap[0].fe->ops.read_status;
-		adap->fe_adap[0].fe->ops.read_status =
-			af9015_af9013_read_status;
-
-		state->init[adap->id] = adap->fe_adap[0].fe->ops.init;
-		adap->fe_adap[0].fe->ops.init = af9015_af9013_init;
-
-		state->sleep[adap->id] = adap->fe_adap[0].fe->ops.sleep;
-		adap->fe_adap[0].fe->ops.sleep = af9015_af9013_sleep;
-	}
-
-	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-static struct mt2060_config af9015_mt2060_config = {
-	.i2c_address = 0xc0,
-	.clock_out = 0,
-};
-
-static struct qt1010_config af9015_qt1010_config = {
-	.i2c_address = 0xc4,
-};
-
-static struct tda18271_config af9015_tda18271_config = {
-	.gate = TDA18271_GATE_DIGITAL,
-	.small_i2c = TDA18271_16_BYTE_CHUNK_INIT,
-};
-
-static struct mxl5005s_config af9015_mxl5003_config = {
-	.i2c_address     = 0xc6,
-	.if_freq         = IF_FREQ_4570000HZ,
-	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
-	.agc_mode        = MXL_SINGLE_AGC,
-	.tracking_filter = MXL_TF_DEFAULT,
-	.rssi_enable     = MXL_RSSI_ENABLE,
-	.cap_select      = MXL_CAP_SEL_ENABLE,
-	.div_out         = MXL_DIV_OUT_4,
-	.clock_out       = MXL_CLOCK_OUT_DISABLE,
-	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
-	.top		 = MXL5005S_TOP_25P2,
-	.mod_mode        = MXL_DIGITAL_MODE,
-	.if_mode         = MXL_ZERO_IF,
-	.AgcMasterByte   = 0x00,
-};
-
-static struct mxl5005s_config af9015_mxl5005_config = {
-	.i2c_address     = 0xc6,
-	.if_freq         = IF_FREQ_4570000HZ,
-	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
-	.agc_mode        = MXL_SINGLE_AGC,
-	.tracking_filter = MXL_TF_OFF,
-	.rssi_enable     = MXL_RSSI_ENABLE,
-	.cap_select      = MXL_CAP_SEL_ENABLE,
-	.div_out         = MXL_DIV_OUT_4,
-	.clock_out       = MXL_CLOCK_OUT_DISABLE,
-	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
-	.top		 = MXL5005S_TOP_25P2,
-	.mod_mode        = MXL_DIGITAL_MODE,
-	.if_mode         = MXL_ZERO_IF,
-	.AgcMasterByte   = 0x00,
-};
-
-static struct mc44s803_config af9015_mc44s803_config = {
-	.i2c_address = 0xc0,
-	.dig_out = 1,
-};
-
-static struct tda18218_config af9015_tda18218_config = {
-	.i2c_address = 0xc0,
-	.i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */
-};
-
-static struct mxl5007t_config af9015_mxl5007t_config = {
-	.xtal_freq_hz = MxL_XTAL_24_MHZ,
-	.if_freq_hz = MxL_IF_4_57_MHZ,
-};
-
-static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	int ret;
-	struct af9015_state *state = adap->dev->priv;
-	deb_info("%s:\n", __func__);
-
-	switch (af9015_af9013_config[adap->id].tuner) {
-	case AF9013_TUNER_MT2060:
-	case AF9013_TUNER_MT2060_2:
-		ret = dvb_attach(mt2060_attach, adap->fe_adap[0].fe,
-			&adap->dev->i2c_adap, &af9015_mt2060_config,
-			af9015_config.mt2060_if1[adap->id])
-			== NULL ? -ENODEV : 0;
-		break;
-	case AF9013_TUNER_QT1010:
-	case AF9013_TUNER_QT1010A:
-		ret = dvb_attach(qt1010_attach, adap->fe_adap[0].fe,
-			&adap->dev->i2c_adap,
-			&af9015_qt1010_config) == NULL ? -ENODEV : 0;
-		break;
-	case AF9013_TUNER_TDA18271:
-		ret = dvb_attach(tda18271_attach, adap->fe_adap[0].fe, 0xc0,
-			&adap->dev->i2c_adap,
-			&af9015_tda18271_config) == NULL ? -ENODEV : 0;
-		break;
-	case AF9013_TUNER_TDA18218:
-		ret = dvb_attach(tda18218_attach, adap->fe_adap[0].fe,
-			&adap->dev->i2c_adap,
-			&af9015_tda18218_config) == NULL ? -ENODEV : 0;
-		break;
-	case AF9013_TUNER_MXL5003D:
-		ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
-			&adap->dev->i2c_adap,
-			&af9015_mxl5003_config) == NULL ? -ENODEV : 0;
-		break;
-	case AF9013_TUNER_MXL5005D:
-	case AF9013_TUNER_MXL5005R:
-		ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
-			&adap->dev->i2c_adap,
-			&af9015_mxl5005_config) == NULL ? -ENODEV : 0;
-		break;
-	case AF9013_TUNER_ENV77H11D5:
-		ret = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0xc0,
-			&adap->dev->i2c_adap,
-			DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
-		break;
-	case AF9013_TUNER_MC44S803:
-		ret = dvb_attach(mc44s803_attach, adap->fe_adap[0].fe,
-			&adap->dev->i2c_adap,
-			&af9015_mc44s803_config) == NULL ? -ENODEV : 0;
-		break;
-	case AF9013_TUNER_MXL5007T:
-		ret = dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe,
-			&adap->dev->i2c_adap,
-			0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0;
-		break;
-	case AF9013_TUNER_UNKNOWN:
-	default:
-		ret = -ENODEV;
-		err("Unknown tuner id:%d",
-			af9015_af9013_config[adap->id].tuner);
-	}
-
-	if (adap->fe_adap[0].fe->ops.tuner_ops.init) {
-		state->tuner_init[adap->id] =
-			adap->fe_adap[0].fe->ops.tuner_ops.init;
-		adap->fe_adap[0].fe->ops.tuner_ops.init = af9015_tuner_init;
-	}
-
-	if (adap->fe_adap[0].fe->ops.tuner_ops.sleep) {
-		state->tuner_sleep[adap->id] =
-			adap->fe_adap[0].fe->ops.tuner_ops.sleep;
-		adap->fe_adap[0].fe->ops.tuner_ops.sleep = af9015_tuner_sleep;
-	}
-
-	return ret;
-}
-
-enum af9015_usb_table_entry {
-	AFATECH_9015,
-	AFATECH_9016,
-	WINFAST_DTV_GOLD,
-	PINNACLE_PCTV_71E,
-	KWORLD_PLUSTV_399U,
-	TINYTWIN,
-	AZUREWAVE_TU700,
-	TERRATEC_AF9015,
-	KWORLD_PLUSTV_PC160,
-	AVERTV_VOLAR_X,
-	XTENSIONS_380U,
-	MSI_DIGIVOX_DUO,
-	AVERTV_VOLAR_X_REV2,
-	TELESTAR_STARSTICK_2,
-	AVERMEDIA_A309_USB,
-	MSI_DIGIVOX_MINI_III,
-	KWORLD_E396,
-	KWORLD_E39B,
-	KWORLD_E395,
-	TREKSTOR_DVBT,
-	AVERTV_A850,
-	AVERTV_A805,
-	CONCEPTRONIC_CTVDIGRCU,
-	KWORLD_MC810,
-	GENIUS_TVGO_DVB_T03,
-	KWORLD_399U_2,
-	KWORLD_PC160_T,
-	SVEON_STV20,
-	TINYTWIN_2,
-	WINFAST_DTV2000DS,
-	KWORLD_UB383_T,
-	KWORLD_E39A,
-	AVERMEDIA_A815M,
-	CINERGY_T_STICK_RC,
-	CINERGY_T_DUAL_RC,
-	AVERTV_A850T,
-	TINYTWIN_3,
-	SVEON_STV22,
-};
-
-static struct usb_device_id af9015_usb_table[] = {
-	[AFATECH_9015] = {
-		USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)},
-	[AFATECH_9016] = {
-		USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)},
-	[WINFAST_DTV_GOLD] = {
-		USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)},
-	[PINNACLE_PCTV_71E] = {
-		USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)},
-	[KWORLD_PLUSTV_399U] = {
-		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)},
-	[TINYTWIN] = {
-		USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN)},
-	[AZUREWAVE_TU700] = {
-		USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700)},
-	[TERRATEC_AF9015] = {
-		USB_DEVICE(USB_VID_TERRATEC,
-				USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)},
-	[KWORLD_PLUSTV_PC160] = {
-		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)},
-	[AVERTV_VOLAR_X] = {
-		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)},
-	[XTENSIONS_380U] = {
-		USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)},
-	[MSI_DIGIVOX_DUO] = {
-		USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)},
-	[AVERTV_VOLAR_X_REV2] = {
-		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)},
-	[TELESTAR_STARSTICK_2] = {
-		USB_DEVICE(USB_VID_TELESTAR,  USB_PID_TELESTAR_STARSTICK_2)},
-	[AVERMEDIA_A309_USB] = {
-		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)},
-	[MSI_DIGIVOX_MINI_III] = {
-		USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)},
-	[KWORLD_E396] = {
-		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)},
-	[KWORLD_E39B] = {
-		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)},
-	[KWORLD_E395] = {
-		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)},
-	[TREKSTOR_DVBT] = {
-		USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)},
-	[AVERTV_A850] = {
-		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
-	[AVERTV_A805] = {
-		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)},
-	[CONCEPTRONIC_CTVDIGRCU] = {
-		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)},
-	[KWORLD_MC810] = {
-		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)},
-	[GENIUS_TVGO_DVB_T03] = {
-		USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)},
-	[KWORLD_399U_2] = {
-		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)},
-	[KWORLD_PC160_T] = {
-		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)},
-	[SVEON_STV20] = {
-		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)},
-	[TINYTWIN_2] = {
-		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)},
-	[WINFAST_DTV2000DS] = {
-		USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)},
-	[KWORLD_UB383_T] = {
-		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)},
-	[KWORLD_E39A] = {
-		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)},
-	[AVERMEDIA_A815M] = {
-		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)},
-	[CINERGY_T_STICK_RC] = {
-		USB_DEVICE(USB_VID_TERRATEC,
-				USB_PID_TERRATEC_CINERGY_T_STICK_RC)},
-	[CINERGY_T_DUAL_RC] = {
-		USB_DEVICE(USB_VID_TERRATEC,
-				USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)},
-	[AVERTV_A850T] = {
-		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)},
-	[TINYTWIN_3] = {
-		USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)},
-	[SVEON_STV22] = {
-		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22)},
-	{ }
-};
-MODULE_DEVICE_TABLE(usb, af9015_usb_table);
-
-#define AF9015_RC_INTERVAL 500
-static struct dvb_usb_device_properties af9015_properties[] = {
-	{
-		.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-		.usb_ctrl = DEVICE_SPECIFIC,
-		.download_firmware = af9015_download_firmware,
-		.firmware = "dvb-usb-af9015.fw",
-		.no_reconnect = 1,
-
-		.size_of_priv = sizeof(struct af9015_state),
-
-		.num_adapters = 2,
-		.adapter = {
-			{
-				.num_frontends = 1,
-				.fe = {
-					{
-						.caps = DVB_USB_ADAP_HAS_PID_FILTER |
-							DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-
-						.pid_filter_count = 32,
-						.pid_filter       = af9015_pid_filter,
-						.pid_filter_ctrl  = af9015_pid_filter_ctrl,
-
-						.frontend_attach = af9015_af9013_frontend_attach,
-						.tuner_attach    = af9015_tuner_attach,
-						.stream = {
-							.type = USB_BULK,
-							.count = 6,
-							.endpoint = 0x84,
-						},
-					}
-				},
-			},
-			{
-				.num_frontends = 1,
-				.fe = {
-					{
-						.frontend_attach = af9015_af9013_frontend_attach,
-						.tuner_attach    = af9015_tuner_attach,
-						.stream = {
-							.type = USB_BULK,
-							.count = 6,
-							.endpoint = 0x85,
-							.u = {
-								.bulk = {
-									.buffersize = TS_USB20_FRAME_SIZE,
-								}
-							}
-						},
-					}
-				},
-			}
-		},
-
-		.identify_state = af9015_identify_state,
-
-		.rc.core = {
-			.protocol         = RC_TYPE_NEC,
-			.module_name      = "af9015",
-			.rc_query         = af9015_rc_query,
-			.rc_interval      = AF9015_RC_INTERVAL,
-			.allowed_protos   = RC_TYPE_NEC,
-		},
-
-		.i2c_algo = &af9015_i2c_algo,
-
-		.num_device_descs = 12, /* check max from dvb-usb.h */
-		.devices = {
-			{
-				.name = "Afatech AF9015 DVB-T USB2.0 stick",
-				.cold_ids = {
-					&af9015_usb_table[AFATECH_9015],
-					&af9015_usb_table[AFATECH_9016],
-				},
-			}, {
-				.name = "Leadtek WinFast DTV Dongle Gold",
-				.cold_ids = {
-					&af9015_usb_table[WINFAST_DTV_GOLD],
-				},
-			}, {
-				.name = "Pinnacle PCTV 71e",
-				.cold_ids = {
-					&af9015_usb_table[PINNACLE_PCTV_71E],
-				},
-			}, {
-				.name = "KWorld PlusTV Dual DVB-T Stick " \
-					"(DVB-T 399U)",
-				.cold_ids = {
-					&af9015_usb_table[KWORLD_PLUSTV_399U],
-					&af9015_usb_table[KWORLD_399U_2],
-				},
-			}, {
-				.name = "DigitalNow TinyTwin DVB-T Receiver",
-				.cold_ids = {
-					&af9015_usb_table[TINYTWIN],
-					&af9015_usb_table[TINYTWIN_2],
-					&af9015_usb_table[TINYTWIN_3],
-				},
-			}, {
-				.name = "TwinHan AzureWave AD-TU700(704J)",
-				.cold_ids = {
-					&af9015_usb_table[AZUREWAVE_TU700],
-				},
-			}, {
-				.name = "TerraTec Cinergy T USB XE",
-				.cold_ids = {
-					&af9015_usb_table[TERRATEC_AF9015],
-				},
-			}, {
-				.name = "KWorld PlusTV Dual DVB-T PCI " \
-					"(DVB-T PC160-2T)",
-				.cold_ids = {
-					&af9015_usb_table[KWORLD_PLUSTV_PC160],
-				},
-			}, {
-				.name = "AVerMedia AVerTV DVB-T Volar X",
-				.cold_ids = {
-					&af9015_usb_table[AVERTV_VOLAR_X],
-				},
-			}, {
-				.name = "TerraTec Cinergy T Stick RC",
-				.cold_ids = {
-					&af9015_usb_table[CINERGY_T_STICK_RC],
-				},
-			}, {
-				.name = "TerraTec Cinergy T Stick Dual RC",
-				.cold_ids = {
-					&af9015_usb_table[CINERGY_T_DUAL_RC],
-				},
-			}, {
-				.name = "AverMedia AVerTV Red HD+ (A850T)",
-				.cold_ids = {
-					&af9015_usb_table[AVERTV_A850T],
-				},
-			},
-		}
-	}, {
-		.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-		.usb_ctrl = DEVICE_SPECIFIC,
-		.download_firmware = af9015_download_firmware,
-		.firmware = "dvb-usb-af9015.fw",
-		.no_reconnect = 1,
-
-		.size_of_priv = sizeof(struct af9015_state),
-
-		.num_adapters = 2,
-		.adapter = {
-			{
-				.num_frontends = 1,
-				.fe = {
-					{
-						.caps = DVB_USB_ADAP_HAS_PID_FILTER |
-							DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-
-						.pid_filter_count = 32,
-						.pid_filter       = af9015_pid_filter,
-						.pid_filter_ctrl  = af9015_pid_filter_ctrl,
-
-						.frontend_attach = af9015_af9013_frontend_attach,
-						.tuner_attach    = af9015_tuner_attach,
-						.stream = {
-							.type = USB_BULK,
-							.count = 6,
-							.endpoint = 0x84,
-						},
-					}
-				},
-			},
-			{
-				.num_frontends = 1,
-				.fe = {
-					{
-						.frontend_attach = af9015_af9013_frontend_attach,
-						.tuner_attach    = af9015_tuner_attach,
-						.stream = {
-							.type = USB_BULK,
-							.count = 6,
-							.endpoint = 0x85,
-							.u = {
-								.bulk = {
-									.buffersize = TS_USB20_FRAME_SIZE,
-								}
-							}
-						},
-					}
-				},
-			}
-		},
-
-		.identify_state = af9015_identify_state,
-
-		.rc.core = {
-			.protocol         = RC_TYPE_NEC,
-			.module_name      = "af9015",
-			.rc_query         = af9015_rc_query,
-			.rc_interval      = AF9015_RC_INTERVAL,
-			.allowed_protos   = RC_TYPE_NEC,
-		},
-
-		.i2c_algo = &af9015_i2c_algo,
-
-		.num_device_descs = 10, /* check max from dvb-usb.h */
-		.devices = {
-			{
-				.name = "Xtensions XD-380",
-				.cold_ids = {
-					&af9015_usb_table[XTENSIONS_380U],
-				},
-			}, {
-				.name = "MSI DIGIVOX Duo",
-				.cold_ids = {
-					&af9015_usb_table[MSI_DIGIVOX_DUO],
-				},
-			}, {
-				.name = "Fujitsu-Siemens Slim Mobile USB DVB-T",
-				.cold_ids = {
-					&af9015_usb_table[AVERTV_VOLAR_X_REV2],
-				},
-			}, {
-				.name = "Telestar Starstick 2",
-				.cold_ids = {
-					&af9015_usb_table[TELESTAR_STARSTICK_2],
-				},
-			}, {
-				.name = "AVerMedia A309",
-				.cold_ids = {
-					&af9015_usb_table[AVERMEDIA_A309_USB],
-				},
-			}, {
-				.name = "MSI Digi VOX mini III",
-				.cold_ids = {
-					&af9015_usb_table[MSI_DIGIVOX_MINI_III],
-				},
-			}, {
-				.name = "KWorld USB DVB-T TV Stick II " \
-					"(VS-DVB-T 395U)",
-				.cold_ids = {
-					&af9015_usb_table[KWORLD_E396],
-					&af9015_usb_table[KWORLD_E39B],
-					&af9015_usb_table[KWORLD_E395],
-					&af9015_usb_table[KWORLD_E39A],
-				},
-			}, {
-				.name = "TrekStor DVB-T USB Stick",
-				.cold_ids = {
-					&af9015_usb_table[TREKSTOR_DVBT],
-				},
-			}, {
-				.name = "AverMedia AVerTV Volar Black HD " \
-					"(A850)",
-				.cold_ids = {
-					&af9015_usb_table[AVERTV_A850],
-				},
-			}, {
-				.name = "Sveon STV22 Dual USB DVB-T Tuner HDTV",
-				.cold_ids = {
-					&af9015_usb_table[SVEON_STV22],
-				},
-			},
-		}
-	}, {
-		.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-		.usb_ctrl = DEVICE_SPECIFIC,
-		.download_firmware = af9015_download_firmware,
-		.firmware = "dvb-usb-af9015.fw",
-		.no_reconnect = 1,
-
-		.size_of_priv = sizeof(struct af9015_state),
-
-		.num_adapters = 2,
-		.adapter = {
-			{
-				.num_frontends = 1,
-				.fe = {
-					{
-						.caps = DVB_USB_ADAP_HAS_PID_FILTER |
-							DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-
-						.pid_filter_count = 32,
-						.pid_filter       = af9015_pid_filter,
-						.pid_filter_ctrl  = af9015_pid_filter_ctrl,
-
-						.frontend_attach = af9015_af9013_frontend_attach,
-						.tuner_attach    = af9015_tuner_attach,
-						.stream = {
-							.type = USB_BULK,
-							.count = 6,
-							.endpoint = 0x84,
-						},
-					}
-				},
-			},
-			{
-				.num_frontends = 1,
-				.fe = {
-					{
-						.frontend_attach = af9015_af9013_frontend_attach,
-						.tuner_attach    = af9015_tuner_attach,
-						.stream = {
-							.type = USB_BULK,
-							.count = 6,
-							.endpoint = 0x85,
-							.u = {
-								.bulk = {
-									.buffersize = TS_USB20_FRAME_SIZE,
-								}
-							}
-						},
-					}
-				},
-			}
-		},
-
-		.identify_state = af9015_identify_state,
-
-		.rc.core = {
-			.protocol         = RC_TYPE_NEC,
-			.module_name      = "af9015",
-			.rc_query         = af9015_rc_query,
-			.rc_interval      = AF9015_RC_INTERVAL,
-			.allowed_protos   = RC_TYPE_NEC,
-		},
-
-		.i2c_algo = &af9015_i2c_algo,
-
-		.num_device_descs = 9, /* check max from dvb-usb.h */
-		.devices = {
-			{
-				.name = "AverMedia AVerTV Volar GPS 805 (A805)",
-				.cold_ids = {
-					&af9015_usb_table[AVERTV_A805],
-				},
-			}, {
-				.name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \
-					"V3.0",
-				.cold_ids = {
-					&af9015_usb_table[CONCEPTRONIC_CTVDIGRCU],
-				},
-			}, {
-				.name = "KWorld Digial MC-810",
-				.cold_ids = {
-					&af9015_usb_table[KWORLD_MC810],
-				},
-			}, {
-				.name = "Genius TVGo DVB-T03",
-				.cold_ids = {
-					&af9015_usb_table[GENIUS_TVGO_DVB_T03],
-				},
-			}, {
-				.name = "KWorld PlusTV DVB-T PCI Pro Card " \
-					"(DVB-T PC160-T)",
-				.cold_ids = {
-					&af9015_usb_table[KWORLD_PC160_T],
-				},
-			}, {
-				.name = "Sveon STV20 Tuner USB DVB-T HDTV",
-				.cold_ids = {
-					&af9015_usb_table[SVEON_STV20],
-				},
-			}, {
-				.name = "Leadtek WinFast DTV2000DS",
-				.cold_ids = {
-					&af9015_usb_table[WINFAST_DTV2000DS],
-				},
-			}, {
-				.name = "KWorld USB DVB-T Stick Mobile " \
-					"(UB383-T)",
-				.cold_ids = {
-					&af9015_usb_table[KWORLD_UB383_T],
-				},
-			}, {
-				.name = "AverMedia AVerTV Volar M (A815Mac)",
-				.cold_ids = {
-					&af9015_usb_table[AVERMEDIA_A815M],
-				},
-			},
-		}
-	},
-};
-
-static int af9015_usb_probe(struct usb_interface *intf,
-			    const struct usb_device_id *id)
-{
-	int ret = 0;
-	struct dvb_usb_device *d = NULL;
-	struct usb_device *udev = interface_to_usbdev(intf);
-	u8 i;
-
-	deb_info("%s: interface:%d\n", __func__,
-		intf->cur_altsetting->desc.bInterfaceNumber);
-
-	/* interface 0 is used by DVB-T receiver and
-	   interface 1 is for remote controller (HID) */
-	if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
-		ret = af9015_read_config(udev);
-		if (ret)
-			return ret;
-
-		for (i = 0; i < af9015_properties_count; i++) {
-			ret = dvb_usb_device_init(intf, &af9015_properties[i],
-				THIS_MODULE, &d, adapter_nr);
-			if (!ret)
-				break;
-			if (ret != -ENODEV)
-				return ret;
-		}
-		if (ret)
-			return ret;
-
-		if (d)
-			ret = af9015_init(d);
-	}
-
-	return ret;
-}
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver af9015_usb_driver = {
-	.name = "dvb_usb_af9015",
-	.probe = af9015_usb_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table = af9015_usb_table,
-};
-
-module_usb_driver(af9015_usb_driver);
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Afatech AF9015 driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h
deleted file mode 100644
index 2f68419..0000000
--- a/drivers/media/dvb/dvb-usb/af9015.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
- *
- * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
- *
- * Thanks to Afatech who kindly provided information.
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef _DVB_USB_AF9015_H_
-#define _DVB_USB_AF9015_H_
-
-#define DVB_USB_LOG_PREFIX "af9015"
-#include "dvb-usb.h"
-
-#define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args)
-#define deb_rc(args...)   dprintk(dvb_usb_af9015_debug, 0x02, args)
-#define deb_xfer(args...) dprintk(dvb_usb_af9015_debug, 0x04, args)
-#define deb_reg(args...)  dprintk(dvb_usb_af9015_debug, 0x08, args)
-#define deb_i2c(args...)  dprintk(dvb_usb_af9015_debug, 0x10, args)
-#define deb_fw(args...)   dprintk(dvb_usb_af9015_debug, 0x20, args)
-
-#define AF9015_I2C_EEPROM  0xa0
-#define AF9015_I2C_DEMOD   0x38
-#define AF9015_USB_TIMEOUT 2000
-
-/* EEPROM locations */
-#define AF9015_EEPROM_IR_MODE        0x18
-#define AF9015_EEPROM_IR_REMOTE_TYPE 0x34
-#define AF9015_EEPROM_TS_MODE        0x31
-#define AF9015_EEPROM_DEMOD2_I2C     0x32
-
-#define AF9015_EEPROM_SAW_BW1        0x35
-#define AF9015_EEPROM_XTAL_TYPE1     0x36
-#define AF9015_EEPROM_SPEC_INV1      0x37
-#define AF9015_EEPROM_IF1L           0x38
-#define AF9015_EEPROM_IF1H           0x39
-#define AF9015_EEPROM_MT2060_IF1L    0x3a
-#define AF9015_EEPROM_MT2060_IF1H    0x3b
-#define AF9015_EEPROM_TUNER_ID1      0x3c
-
-#define AF9015_EEPROM_SAW_BW2        0x45
-#define AF9015_EEPROM_XTAL_TYPE2     0x46
-#define AF9015_EEPROM_SPEC_INV2      0x47
-#define AF9015_EEPROM_IF2L           0x48
-#define AF9015_EEPROM_IF2H           0x49
-#define AF9015_EEPROM_MT2060_IF2L    0x4a
-#define AF9015_EEPROM_MT2060_IF2H    0x4b
-#define AF9015_EEPROM_TUNER_ID2      0x4c
-
-#define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1)
-
-struct req_t {
-	u8  cmd;       /* [0] */
-	/*  seq */     /* [1] */
-	u8  i2c_addr;  /* [2] */
-	u16 addr;      /* [3|4] */
-	u8  mbox;      /* [5] */
-	u8  addr_len;  /* [6] */
-	u8  data_len;  /* [7] */
-	u8  *data;
-};
-
-enum af9015_cmd {
-	GET_CONFIG           = 0x10,
-	DOWNLOAD_FIRMWARE    = 0x11,
-	BOOT                 = 0x13,
-	READ_MEMORY          = 0x20,
-	WRITE_MEMORY         = 0x21,
-	READ_WRITE_I2C       = 0x22,
-	COPY_FIRMWARE        = 0x23,
-	RECONNECT_USB        = 0x5a,
-	WRITE_VIRTUAL_MEMORY = 0x26,
-	GET_IR_CODE          = 0x27,
-	READ_I2C,
-	WRITE_I2C,
-};
-
-enum af9015_ir_mode {
-	AF9015_IR_MODE_DISABLED = 0,
-	AF9015_IR_MODE_HID,
-	AF9015_IR_MODE_RLC,
-	AF9015_IR_MODE_RC6,
-	AF9015_IR_MODE_POLLING, /* just guess */
-};
-
-struct af9015_state {
-	u8 rc_repeat;
-	u32 rc_keycode;
-	u8 rc_last[4];
-
-	/* for demod callback override */
-	int (*set_frontend[2]) (struct dvb_frontend *fe);
-	int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status);
-	int (*init[2]) (struct dvb_frontend *fe);
-	int (*sleep[2]) (struct dvb_frontend *fe);
-	int (*tuner_init[2]) (struct dvb_frontend *fe);
-	int (*tuner_sleep[2]) (struct dvb_frontend *fe);
-};
-
-struct af9015_config {
-	u8  dual_mode:1;
-	u16 mt2060_if1[2];
-	u16 firmware_size;
-	u16 firmware_checksum;
-	u32 eeprom_sum;
-};
-
-enum af9015_remote {
-	AF9015_REMOTE_NONE                    = 0,
-/* 1 */	AF9015_REMOTE_A_LINK_DTU_M,
-	AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
-	AF9015_REMOTE_MYGICTV_U718,
-	AF9015_REMOTE_DIGITTRADE_DVB_T,
-/* 5 */	AF9015_REMOTE_AVERMEDIA_KS,
-};
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/af9035.c b/drivers/media/dvb/dvb-usb/af9035.c
deleted file mode 100644
index e83b39d..0000000
--- a/drivers/media/dvb/dvb-usb/af9035.c
+++ /dev/null
@@ -1,1242 +0,0 @@
-/*
- * Afatech AF9035 DVB USB driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "af9035.h"
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-static DEFINE_MUTEX(af9035_usb_mutex);
-static struct dvb_usb_device_properties af9035_properties[2];
-static int af9035_properties_count = ARRAY_SIZE(af9035_properties);
-
-static u16 af9035_checksum(const u8 *buf, size_t len)
-{
-	size_t i;
-	u16 checksum = 0;
-
-	for (i = 1; i < len; i++) {
-		if (i % 2)
-			checksum += buf[i] << 8;
-		else
-			checksum += buf[i];
-	}
-	checksum = ~checksum;
-
-	return checksum;
-}
-
-static int af9035_ctrl_msg(struct usb_device *udev, struct usb_req *req)
-{
-#define BUF_LEN 64
-#define REQ_HDR_LEN 4 /* send header size */
-#define ACK_HDR_LEN 3 /* rece header size */
-#define CHECKSUM_LEN 2
-#define USB_TIMEOUT 2000
-
-	int ret, msg_len, act_len;
-	u8 buf[BUF_LEN];
-	static u8 seq; /* packet sequence number */
-	u16 checksum, tmp_checksum;
-
-	/* buffer overflow check */
-	if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) ||
-		req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) {
-		pr_debug("%s: too much data wlen=%d rlen=%d\n", __func__,
-				req->wlen, req->rlen);
-		return -EINVAL;
-	}
-
-	if (mutex_lock_interruptible(&af9035_usb_mutex) < 0)
-		return -EAGAIN;
-
-	buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1;
-	buf[1] = req->mbox;
-	buf[2] = req->cmd;
-	buf[3] = seq++;
-	if (req->wlen)
-		memcpy(&buf[4], req->wbuf, req->wlen);
-
-	/* calc and add checksum */
-	checksum = af9035_checksum(buf, buf[0] - 1);
-	buf[buf[0] - 1] = (checksum >> 8);
-	buf[buf[0] - 0] = (checksum & 0xff);
-
-	msg_len = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN ;
-
-	/* send req */
-	ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len,
-			&act_len, USB_TIMEOUT);
-	if (ret < 0)
-		err("bulk message failed=%d (%d/%d)", ret, msg_len, act_len);
-	else
-		if (act_len != msg_len)
-			ret = -EIO; /* all data is not send */
-	if (ret < 0)
-		goto err_mutex_unlock;
-
-	/* no ack for those packets */
-	if (req->cmd == CMD_FW_DL)
-		goto exit_mutex_unlock;
-
-	/* receive ack and data if read req */
-	msg_len = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN;
-	ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len,
-			&act_len, USB_TIMEOUT);
-	if (ret < 0) {
-		err("recv bulk message failed=%d", ret);
-		ret = -EIO;
-		goto err_mutex_unlock;
-	}
-
-	if (act_len != msg_len) {
-		err("recv bulk message truncated (%d != %d)", act_len, msg_len);
-		ret = -EIO;
-		goto err_mutex_unlock;
-	}
-
-	/* verify checksum */
-	checksum = af9035_checksum(buf, act_len - 2);
-	tmp_checksum = (buf[act_len - 2] << 8) | buf[act_len - 1];
-	if (tmp_checksum != checksum) {
-		err("%s: command=%02x checksum mismatch (%04x != %04x)",
-		    __func__, req->cmd, tmp_checksum, checksum);
-		ret = -EIO;
-		goto err_mutex_unlock;
-	}
-
-	/* check status */
-	if (buf[2]) {
-		pr_debug("%s: command=%02x failed fw error=%d\n", __func__,
-				req->cmd, buf[2]);
-		ret = -EIO;
-		goto err_mutex_unlock;
-	}
-
-	/* read request, copy returned data to return buf */
-	if (req->rlen)
-		memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen);
-
-err_mutex_unlock:
-exit_mutex_unlock:
-	mutex_unlock(&af9035_usb_mutex);
-
-	return ret;
-}
-
-/* write multiple registers */
-static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len)
-{
-	u8 wbuf[6 + len];
-	u8 mbox = (reg >> 16) & 0xff;
-	struct usb_req req = { CMD_MEM_WR, mbox, sizeof(wbuf), wbuf, 0, NULL };
-
-	wbuf[0] = len;
-	wbuf[1] = 2;
-	wbuf[2] = 0;
-	wbuf[3] = 0;
-	wbuf[4] = (reg >> 8) & 0xff;
-	wbuf[5] = (reg >> 0) & 0xff;
-	memcpy(&wbuf[6], val, len);
-
-	return af9035_ctrl_msg(d->udev, &req);
-}
-
-/* read multiple registers */
-static int af9035_rd_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len)
-{
-	u8 wbuf[] = { len, 2, 0, 0, (reg >> 8) & 0xff, reg & 0xff };
-	u8 mbox = (reg >> 16) & 0xff;
-	struct usb_req req = { CMD_MEM_RD, mbox, sizeof(wbuf), wbuf, len, val };
-
-	return af9035_ctrl_msg(d->udev, &req);
-}
-
-/* write single register */
-static int af9035_wr_reg(struct dvb_usb_device *d, u32 reg, u8 val)
-{
-	return af9035_wr_regs(d, reg, &val, 1);
-}
-
-/* read single register */
-static int af9035_rd_reg(struct dvb_usb_device *d, u32 reg, u8 *val)
-{
-	return af9035_rd_regs(d, reg, val, 1);
-}
-
-/* write single register with mask */
-static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val,
-		u8 mask)
-{
-	int ret;
-	u8 tmp;
-
-	/* no need for read if whole reg is written */
-	if (mask != 0xff) {
-		ret = af9035_rd_regs(d, reg, &tmp, 1);
-		if (ret)
-			return ret;
-
-		val &= mask;
-		tmp &= ~mask;
-		val |= tmp;
-	}
-
-	return af9035_wr_regs(d, reg, &val, 1);
-}
-
-static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
-		struct i2c_msg msg[], int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	struct state *state = d->priv;
-	int ret;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	/*
-	 * I2C sub header is 5 bytes long. Meaning of those bytes are:
-	 * 0: data len
-	 * 1: I2C addr << 1
-	 * 2: reg addr len
-	 *    byte 3 and 4 can be used as reg addr
-	 * 3: reg addr MSB
-	 *    used when reg addr len is set to 2
-	 * 4: reg addr LSB
-	 *    used when reg addr len is set to 1 or 2
-	 *
-	 * For the simplify we do not use register addr at all.
-	 * NOTE: As a firmware knows tuner type there is very small possibility
-	 * there could be some tuner I2C hacks done by firmware and this may
-	 * lead problems if firmware expects those bytes are used.
-	 */
-	if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
-			(msg[1].flags & I2C_M_RD)) {
-		if (msg[0].len > 40 || msg[1].len > 40) {
-			/* TODO: correct limits > 40 */
-			ret = -EOPNOTSUPP;
-		} else if (msg[0].addr == state->af9033_config[0].i2c_addr) {
-			/* integrated demod */
-			u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
-					msg[0].buf[2];
-			ret = af9035_rd_regs(d, reg, &msg[1].buf[0],
-					msg[1].len);
-		} else {
-			/* I2C */
-			u8 buf[5 + msg[0].len];
-			struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf),
-					buf, msg[1].len, msg[1].buf };
-			buf[0] = msg[1].len;
-			buf[1] = msg[0].addr << 1;
-			buf[2] = 0x00; /* reg addr len */
-			buf[3] = 0x00; /* reg addr MSB */
-			buf[4] = 0x00; /* reg addr LSB */
-			memcpy(&buf[5], msg[0].buf, msg[0].len);
-			ret = af9035_ctrl_msg(d->udev, &req);
-		}
-	} else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
-		if (msg[0].len > 40) {
-			/* TODO: correct limits > 40 */
-			ret = -EOPNOTSUPP;
-		} else if (msg[0].addr == state->af9033_config[0].i2c_addr) {
-			/* integrated demod */
-			u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
-					msg[0].buf[2];
-			ret = af9035_wr_regs(d, reg, &msg[0].buf[3],
-					msg[0].len - 3);
-		} else {
-			/* I2C */
-			u8 buf[5 + msg[0].len];
-			struct usb_req req = { CMD_I2C_WR, 0, sizeof(buf), buf,
-					0, NULL };
-			buf[0] = msg[0].len;
-			buf[1] = msg[0].addr << 1;
-			buf[2] = 0x00; /* reg addr len */
-			buf[3] = 0x00; /* reg addr MSB */
-			buf[4] = 0x00; /* reg addr LSB */
-			memcpy(&buf[5], msg[0].buf, msg[0].len);
-			ret = af9035_ctrl_msg(d->udev, &req);
-		}
-	} else {
-		/*
-		 * We support only two kind of I2C transactions:
-		 * 1) 1 x read + 1 x write
-		 * 2) 1 x write
-		 */
-		ret = -EOPNOTSUPP;
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-
-	if (ret < 0)
-		return ret;
-	else
-		return num;
-}
-
-static u32 af9035_i2c_functionality(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm af9035_i2c_algo = {
-	.master_xfer = af9035_i2c_master_xfer,
-	.functionality = af9035_i2c_functionality,
-};
-
-#define AF9035_POLL 250
-static int af9035_rc_query(struct dvb_usb_device *d)
-{
-	unsigned int key;
-	unsigned char b[4];
-	int ret;
-	struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b };
-
-	ret = af9035_ctrl_msg(d->udev, &req);
-	if (ret < 0)
-		goto err;
-
-	if ((b[2] + b[3]) == 0xff) {
-		if ((b[0] + b[1]) == 0xff) {
-			/* NEC */
-			key = b[0] << 8 | b[2];
-		} else {
-			/* ext. NEC */
-			key = b[0] << 16 | b[1] << 8 | b[2];
-		}
-	} else {
-		key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
-	}
-
-	rc_keydown(d->rc_dev, key, 0);
-
-err:
-	/* ignore errors */
-	return 0;
-}
-
-static int af9035_init(struct dvb_usb_device *d)
-{
-	struct state *state = d->priv;
-	int ret, i;
-	u16 frame_size = 87 * 188 / 4;
-	u8  packet_size = 512 / 4;
-	struct reg_val_mask tab[] = {
-		{ 0x80f99d, 0x01, 0x01 },
-		{ 0x80f9a4, 0x01, 0x01 },
-		{ 0x00dd11, 0x00, 0x20 },
-		{ 0x00dd11, 0x00, 0x40 },
-		{ 0x00dd13, 0x00, 0x20 },
-		{ 0x00dd13, 0x00, 0x40 },
-		{ 0x00dd11, 0x20, 0x20 },
-		{ 0x00dd88, (frame_size >> 0) & 0xff, 0xff},
-		{ 0x00dd89, (frame_size >> 8) & 0xff, 0xff},
-		{ 0x00dd0c, packet_size, 0xff},
-		{ 0x00dd11, state->dual_mode << 6, 0x40 },
-		{ 0x00dd8a, (frame_size >> 0) & 0xff, 0xff},
-		{ 0x00dd8b, (frame_size >> 8) & 0xff, 0xff},
-		{ 0x00dd0d, packet_size, 0xff },
-		{ 0x80f9a3, 0x00, 0x01 },
-		{ 0x80f9cd, 0x00, 0x01 },
-		{ 0x80f99d, 0x00, 0x01 },
-		{ 0x80f9a4, 0x00, 0x01 },
-	};
-
-	pr_debug("%s: USB speed=%d frame_size=%04x packet_size=%02x\n",
-		__func__, d->udev->speed, frame_size, packet_size);
-
-	/* init endpoints */
-	for (i = 0; i < ARRAY_SIZE(tab); i++) {
-		ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val,
-				tab[i].mask);
-		if (ret < 0)
-			goto err;
-	}
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static int af9035_identify_state(struct usb_device *udev,
-		struct dvb_usb_device_properties *props,
-		struct dvb_usb_device_description **desc,
-		int *cold)
-{
-	int ret;
-	u8 wbuf[1] = { 1 };
-	u8 rbuf[4];
-	struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf,
-			sizeof(rbuf), rbuf };
-
-	ret = af9035_ctrl_msg(udev, &req);
-	if (ret < 0)
-		goto err;
-
-	pr_debug("%s: reply=%02x %02x %02x %02x\n", __func__,
-		rbuf[0], rbuf[1], rbuf[2], rbuf[3]);
-	if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])
-		*cold = 0;
-	else
-		*cold = 1;
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static int af9035_download_firmware(struct usb_device *udev,
-		const struct firmware *fw)
-{
-	int ret, i, j, len;
-	u8 wbuf[1];
-	u8 rbuf[4];
-	struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
-	struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL };
-	struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
-	u8 hdr_core;
-	u16 hdr_addr, hdr_data_len, hdr_checksum;
-	#define MAX_DATA 58
-	#define HDR_SIZE 7
-
-	/*
-	 * Thanks to Daniel Glöckner <daniel-gl@gmx.net> about that info!
-	 *
-	 * byte 0: MCS 51 core
-	 *  There are two inside the AF9035 (1=Link and 2=OFDM) with separate
-	 *  address spaces
-	 * byte 1-2: Big endian destination address
-	 * byte 3-4: Big endian number of data bytes following the header
-	 * byte 5-6: Big endian header checksum, apparently ignored by the chip
-	 *  Calculated as ~(h[0]*256+h[1]+h[2]*256+h[3]+h[4]*256)
-	 */
-
-	for (i = fw->size; i > HDR_SIZE;) {
-		hdr_core = fw->data[fw->size - i + 0];
-		hdr_addr = fw->data[fw->size - i + 1] << 8;
-		hdr_addr |= fw->data[fw->size - i + 2] << 0;
-		hdr_data_len = fw->data[fw->size - i + 3] << 8;
-		hdr_data_len |= fw->data[fw->size - i + 4] << 0;
-		hdr_checksum = fw->data[fw->size - i + 5] << 8;
-		hdr_checksum |= fw->data[fw->size - i + 6] << 0;
-
-		pr_debug("%s: core=%d addr=%04x data_len=%d checksum=%04x\n",
-				__func__, hdr_core, hdr_addr, hdr_data_len,
-				hdr_checksum);
-
-		if (((hdr_core != 1) && (hdr_core != 2)) ||
-				(hdr_data_len > i)) {
-			pr_debug("%s: bad firmware\n", __func__);
-			break;
-		}
-
-		/* download begin packet */
-		req.cmd = CMD_FW_DL_BEGIN;
-		ret = af9035_ctrl_msg(udev, &req);
-		if (ret < 0)
-			goto err;
-
-		/* download firmware packet(s) */
-		for (j = HDR_SIZE + hdr_data_len; j > 0; j -= MAX_DATA) {
-			len = j;
-			if (len > MAX_DATA)
-				len = MAX_DATA;
-			req_fw_dl.wlen = len;
-			req_fw_dl.wbuf = (u8 *) &fw->data[fw->size - i +
-					HDR_SIZE + hdr_data_len - j];
-			ret = af9035_ctrl_msg(udev, &req_fw_dl);
-			if (ret < 0)
-				goto err;
-		}
-
-		/* download end packet */
-		req.cmd = CMD_FW_DL_END;
-		ret = af9035_ctrl_msg(udev, &req);
-		if (ret < 0)
-			goto err;
-
-		i -= hdr_data_len + HDR_SIZE;
-
-		pr_debug("%s: data uploaded=%zu\n", __func__, fw->size - i);
-	}
-
-	/* firmware loaded, request boot */
-	req.cmd = CMD_FW_BOOT;
-	ret = af9035_ctrl_msg(udev, &req);
-	if (ret < 0)
-		goto err;
-
-	/* ensure firmware starts */
-	wbuf[0] = 1;
-	ret = af9035_ctrl_msg(udev, &req_fw_ver);
-	if (ret < 0)
-		goto err;
-
-	if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
-		info("firmware did not run");
-		ret = -ENODEV;
-		goto err;
-	}
-
-	info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2],
-			rbuf[3]);
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static int af9035_download_firmware_it9135(struct usb_device *udev,
-		const struct firmware *fw)
-{
-	int ret, i, i_prev;
-	u8 wbuf[1];
-	u8 rbuf[4];
-	struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
-	struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL };
-	struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
-	#define HDR_SIZE 7
-
-	/*
-	 * There seems to be following firmware header. Meaning of bytes 0-3
-	 * is unknown.
-	 *
-	 * 0: 3
-	 * 1: 0, 1
-	 * 2: 0
-	 * 3: 1, 2, 3
-	 * 4: addr MSB
-	 * 5: addr LSB
-	 * 6: count of data bytes ?
-	 */
-
-	for (i = HDR_SIZE, i_prev = 0; i <= fw->size; i++) {
-		if (i == fw->size ||
-				(fw->data[i + 0] == 0x03 &&
-				(fw->data[i + 1] == 0x00 ||
-				fw->data[i + 1] == 0x01) &&
-				fw->data[i + 2] == 0x00)) {
-			req_fw_dl.wlen = i - i_prev;
-			req_fw_dl.wbuf = (u8 *) &fw->data[i_prev];
-			i_prev = i;
-			ret = af9035_ctrl_msg(udev, &req_fw_dl);
-			if (ret < 0)
-				goto err;
-
-			pr_debug("%s: data uploaded=%d\n", __func__, i);
-		}
-	}
-
-	/* firmware loaded, request boot */
-	req.cmd = CMD_FW_BOOT;
-	ret = af9035_ctrl_msg(udev, &req);
-	if (ret < 0)
-		goto err;
-
-	/* ensure firmware starts */
-	wbuf[0] = 1;
-	ret = af9035_ctrl_msg(udev, &req_fw_ver);
-	if (ret < 0)
-		goto err;
-
-	if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
-		info("firmware did not run");
-		ret = -ENODEV;
-		goto err;
-	}
-
-	info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2],
-			rbuf[3]);
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-/* abuse that callback as there is no better one for reading eeprom */
-static int af9035_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
-{
-	struct state *state = d->priv;
-	int ret, i, eeprom_shift = 0;
-	u8 tmp;
-	u16 tmp16;
-
-	/* check if there is dual tuners */
-	ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp);
-	if (ret < 0)
-		goto err;
-
-	state->dual_mode = tmp;
-	pr_debug("%s: dual mode=%d\n", __func__, state->dual_mode);
-
-	for (i = 0; i < af9035_properties[0].num_adapters; i++) {
-		/* tuner */
-		ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp);
-		if (ret < 0)
-			goto err;
-
-		state->af9033_config[i].tuner = tmp;
-		pr_debug("%s: [%d]tuner=%02x\n", __func__, i, tmp);
-
-		switch (tmp) {
-		case AF9033_TUNER_TUA9001:
-		case AF9033_TUNER_FC0011:
-		case AF9033_TUNER_MXL5007T:
-		case AF9033_TUNER_TDA18218:
-			state->af9033_config[i].spec_inv = 1;
-			break;
-		default:
-			warn("tuner ID=%02x not supported, please report!",
-				tmp);
-		};
-
-		/* tuner IF frequency */
-		ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp);
-		if (ret < 0)
-			goto err;
-
-		tmp16 = tmp;
-
-		ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_H + eeprom_shift, &tmp);
-		if (ret < 0)
-			goto err;
-
-		tmp16 |= tmp << 8;
-
-		pr_debug("%s: [%d]IF=%d\n", __func__, i, tmp16);
-
-		eeprom_shift = 0x10; /* shift for the 2nd tuner params */
-	}
-
-	/* get demod clock */
-	ret = af9035_rd_reg(d, 0x00d800, &tmp);
-	if (ret < 0)
-		goto err;
-
-	tmp = (tmp >> 0) & 0x0f;
-
-	for (i = 0; i < af9035_properties[0].num_adapters; i++)
-		state->af9033_config[i].clock = clock_lut[tmp];
-
-	ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp);
-	if (ret < 0)
-		goto err;
-	pr_debug("%s: ir_mode=%02x\n", __func__, tmp);
-
-	/* don't activate rc if in HID mode or if not available */
-	if (tmp == 5) {
-		ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp);
-		if (ret < 0)
-			goto err;
-		pr_debug("%s: ir_type=%02x\n", __func__, tmp);
-
-		switch (tmp) {
-		case 0: /* NEC */
-		default:
-			d->props.rc.core.protocol = RC_TYPE_NEC;
-			d->props.rc.core.allowed_protos = RC_TYPE_NEC;
-			break;
-		case 1: /* RC6 */
-			d->props.rc.core.protocol = RC_TYPE_RC6;
-			d->props.rc.core.allowed_protos = RC_TYPE_RC6;
-			break;
-		}
-		d->props.rc.core.rc_query = af9035_rc_query;
-	}
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-/* abuse that callback as there is no better one for reading eeprom */
-static int af9035_read_mac_address_it9135(struct dvb_usb_device *d, u8 mac[6])
-{
-	struct state *state = d->priv;
-	int ret, i;
-	u8 tmp;
-
-	state->dual_mode = false;
-
-	/* get demod clock */
-	ret = af9035_rd_reg(d, 0x00d800, &tmp);
-	if (ret < 0)
-		goto err;
-
-	tmp = (tmp >> 0) & 0x0f;
-
-	for (i = 0; i < af9035_properties[0].num_adapters; i++)
-		state->af9033_config[i].clock = clock_lut_it9135[tmp];
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static int af9035_fc0011_tuner_callback(struct dvb_usb_device *d,
-		int cmd, int arg)
-{
-	int ret;
-
-	switch (cmd) {
-	case FC0011_FE_CALLBACK_POWER:
-		/* Tuner enable */
-		ret = af9035_wr_reg_mask(d, 0xd8eb, 1, 1);
-		if (ret < 0)
-			goto err;
-
-		ret = af9035_wr_reg_mask(d, 0xd8ec, 1, 1);
-		if (ret < 0)
-			goto err;
-
-		ret = af9035_wr_reg_mask(d, 0xd8ed, 1, 1);
-		if (ret < 0)
-			goto err;
-
-		/* LED */
-		ret = af9035_wr_reg_mask(d, 0xd8d0, 1, 1);
-		if (ret < 0)
-			goto err;
-
-		ret = af9035_wr_reg_mask(d, 0xd8d1, 1, 1);
-		if (ret < 0)
-			goto err;
-
-		usleep_range(10000, 50000);
-		break;
-	case FC0011_FE_CALLBACK_RESET:
-		ret = af9035_wr_reg(d, 0xd8e9, 1);
-		if (ret < 0)
-			goto err;
-
-		ret = af9035_wr_reg(d, 0xd8e8, 1);
-		if (ret < 0)
-			goto err;
-
-		ret = af9035_wr_reg(d, 0xd8e7, 1);
-		if (ret < 0)
-			goto err;
-
-		usleep_range(10000, 20000);
-
-		ret = af9035_wr_reg(d, 0xd8e7, 0);
-		if (ret < 0)
-			goto err;
-
-		usleep_range(10000, 20000);
-		break;
-	default:
-		ret = -EINVAL;
-		goto err;
-	}
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static int af9035_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
-{
-	struct state *state = d->priv;
-
-	switch (state->af9033_config[0].tuner) {
-	case AF9033_TUNER_FC0011:
-		return af9035_fc0011_tuner_callback(d, cmd, arg);
-	default:
-		break;
-	}
-
-	return -ENODEV;
-}
-
-static int af9035_frontend_callback(void *adapter_priv, int component,
-				    int cmd, int arg)
-{
-	struct i2c_adapter *adap = adapter_priv;
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-
-	switch (component) {
-	case DVB_FRONTEND_COMPONENT_TUNER:
-		return af9035_tuner_callback(d, cmd, arg);
-	default:
-		break;
-	}
-
-	return -EINVAL;
-}
-
-static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct state *state = adap->dev->priv;
-	int ret;
-
-	if (!state->af9033_config[adap->id].tuner) {
-		/* unsupported tuner */
-		ret = -ENODEV;
-		goto err;
-	}
-
-	if (adap->id == 0) {
-		state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
-		state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL;
-
-		ret = af9035_wr_reg(adap->dev, 0x00417f,
-				state->af9033_config[1].i2c_addr);
-		if (ret < 0)
-			goto err;
-
-		ret = af9035_wr_reg(adap->dev, 0x00d81a,
-				state->dual_mode);
-		if (ret < 0)
-			goto err;
-	}
-
-	/* attach demodulator */
-	adap->fe_adap[0].fe = dvb_attach(af9033_attach,
-			&state->af9033_config[adap->id], &adap->dev->i2c_adap);
-	if (adap->fe_adap[0].fe == NULL) {
-		ret = -ENODEV;
-		goto err;
-	}
-
-	/* disable I2C-gate */
-	adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL;
-	adap->fe_adap[0].fe->callback = af9035_frontend_callback;
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static struct tua9001_config af9035_tua9001_config = {
-	.i2c_addr = 0x60,
-};
-
-static const struct fc0011_config af9035_fc0011_config = {
-	.i2c_address = 0x60,
-};
-
-static struct mxl5007t_config af9035_mxl5007t_config = {
-	.xtal_freq_hz = MxL_XTAL_24_MHZ,
-	.if_freq_hz = MxL_IF_4_57_MHZ,
-	.invert_if = 0,
-	.loop_thru_enable = 0,
-	.clk_out_enable = 0,
-	.clk_out_amp = MxL_CLKOUT_AMP_0_94V,
-};
-
-static struct tda18218_config af9035_tda18218_config = {
-	.i2c_address = 0x60,
-	.i2c_wr_max = 21,
-};
-
-static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct state *state = adap->dev->priv;
-	int ret;
-	struct dvb_frontend *fe;
-
-	switch (state->af9033_config[adap->id].tuner) {
-	case AF9033_TUNER_TUA9001:
-		/* AF9035 gpiot3 = TUA9001 RESETN
-		   AF9035 gpiot2 = TUA9001 RXEN */
-
-		/* configure gpiot2 and gpiot2 as output */
-		ret = af9035_wr_reg_mask(adap->dev, 0x00d8ec, 0x01, 0x01);
-		if (ret < 0)
-			goto err;
-
-		ret = af9035_wr_reg_mask(adap->dev, 0x00d8ed, 0x01, 0x01);
-		if (ret < 0)
-			goto err;
-
-		ret = af9035_wr_reg_mask(adap->dev, 0x00d8e8, 0x01, 0x01);
-		if (ret < 0)
-			goto err;
-
-		ret = af9035_wr_reg_mask(adap->dev, 0x00d8e9, 0x01, 0x01);
-		if (ret < 0)
-			goto err;
-
-		/* reset tuner */
-		ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x00, 0x01);
-		if (ret < 0)
-			goto err;
-
-		usleep_range(2000, 20000);
-
-		ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x01, 0x01);
-		if (ret < 0)
-			goto err;
-
-		/* activate tuner RX */
-		/* TODO: use callback for TUA9001 RXEN */
-		ret = af9035_wr_reg_mask(adap->dev, 0x00d8eb, 0x01, 0x01);
-		if (ret < 0)
-			goto err;
-
-		/* attach tuner */
-		fe = dvb_attach(tua9001_attach, adap->fe_adap[0].fe,
-				&adap->dev->i2c_adap, &af9035_tua9001_config);
-		break;
-	case AF9033_TUNER_FC0011:
-		fe = dvb_attach(fc0011_attach, adap->fe_adap[0].fe,
-				&adap->dev->i2c_adap, &af9035_fc0011_config);
-		break;
-	case AF9033_TUNER_MXL5007T:
-		ret = af9035_wr_reg(adap->dev, 0x00d8e0, 1);
-		if (ret < 0)
-			goto err;
-		ret = af9035_wr_reg(adap->dev, 0x00d8e1, 1);
-		if (ret < 0)
-			goto err;
-		ret = af9035_wr_reg(adap->dev, 0x00d8df, 0);
-		if (ret < 0)
-			goto err;
-
-		msleep(30);
-
-		ret = af9035_wr_reg(adap->dev, 0x00d8df, 1);
-		if (ret < 0)
-			goto err;
-
-		msleep(300);
-
-		ret = af9035_wr_reg(adap->dev, 0x00d8c0, 1);
-		if (ret < 0)
-			goto err;
-		ret = af9035_wr_reg(adap->dev, 0x00d8c1, 1);
-		if (ret < 0)
-			goto err;
-		ret = af9035_wr_reg(adap->dev, 0x00d8bf, 0);
-		if (ret < 0)
-			goto err;
-		ret = af9035_wr_reg(adap->dev, 0x00d8b4, 1);
-		if (ret < 0)
-			goto err;
-		ret = af9035_wr_reg(adap->dev, 0x00d8b5, 1);
-		if (ret < 0)
-			goto err;
-		ret = af9035_wr_reg(adap->dev, 0x00d8b3, 1);
-		if (ret < 0)
-			goto err;
-
-		/* attach tuner */
-		fe = dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe,
-				&adap->dev->i2c_adap, 0x60, &af9035_mxl5007t_config);
-		break;
-	case AF9033_TUNER_TDA18218:
-		/* attach tuner */
-		fe = dvb_attach(tda18218_attach, adap->fe_adap[0].fe,
-				&adap->dev->i2c_adap, &af9035_tda18218_config);
-		break;
-	default:
-		fe = NULL;
-	}
-
-	if (fe == NULL) {
-		ret = -ENODEV;
-		goto err;
-	}
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-enum af9035_id_entry {
-	AF9035_15A4_9035,
-	AF9035_15A4_1000,
-	AF9035_15A4_1001,
-	AF9035_15A4_1002,
-	AF9035_15A4_1003,
-	AF9035_0CCD_0093,
-	AF9035_07CA_A835,
-	AF9035_07CA_B835,
-	AF9035_07CA_1867,
-	AF9035_07CA_A867,
-	AF9035_07CA_0825,
-};
-
-static struct usb_device_id af9035_id[] = {
-	[AF9035_15A4_9035] = {
-		USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035)},
-	[AF9035_15A4_1000] = {
-		USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000)},
-	[AF9035_15A4_1001] = {
-		USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1001)},
-	[AF9035_15A4_1002] = {
-		USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1002)},
-	[AF9035_15A4_1003] = {
-		USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1003)},
-	[AF9035_0CCD_0093] = {
-		USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK)},
-	[AF9035_07CA_A835] = {
-		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835)},
-	[AF9035_07CA_B835] = {
-		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835)},
-	[AF9035_07CA_1867] = {
-		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867)},
-	[AF9035_07CA_A867] = {
-		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867)},
-	[AF9035_07CA_0825] = {
-		USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR)},
-	{},
-};
-
-MODULE_DEVICE_TABLE(usb, af9035_id);
-
-static struct dvb_usb_device_properties af9035_properties[] = {
-	{
-		.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-		.usb_ctrl = DEVICE_SPECIFIC,
-		.download_firmware = af9035_download_firmware,
-		.firmware = "dvb-usb-af9035-02.fw",
-		.no_reconnect = 1,
-
-		.size_of_priv = sizeof(struct state),
-
-		.num_adapters = 1,
-		.adapter = {
-			{
-				.num_frontends = 1,
-				.fe = {
-					{
-						.frontend_attach = af9035_frontend_attach,
-						.tuner_attach = af9035_tuner_attach,
-						.stream = {
-							.type = USB_BULK,
-							.count = 6,
-							.endpoint = 0x84,
-							.u = {
-								.bulk = {
-									.buffersize = (87 * 188),
-								}
-							}
-						}
-					}
-				}
-			}
-		},
-
-		.identify_state = af9035_identify_state,
-		.read_mac_address = af9035_read_mac_address,
-
-		.i2c_algo = &af9035_i2c_algo,
-
-		.rc.core = {
-			.protocol       = RC_TYPE_UNKNOWN,
-			.module_name    = "af9035",
-			.rc_query       = NULL,
-			.rc_interval    = AF9035_POLL,
-			.allowed_protos = RC_TYPE_UNKNOWN,
-			.rc_codes       = RC_MAP_EMPTY,
-		},
-		.num_device_descs = 5,
-		.devices = {
-			{
-				.name = "Afatech AF9035 reference design",
-				.cold_ids = {
-					&af9035_id[AF9035_15A4_9035],
-					&af9035_id[AF9035_15A4_1000],
-					&af9035_id[AF9035_15A4_1001],
-					&af9035_id[AF9035_15A4_1002],
-					&af9035_id[AF9035_15A4_1003],
-				},
-			}, {
-				.name = "TerraTec Cinergy T Stick",
-				.cold_ids = {
-					&af9035_id[AF9035_0CCD_0093],
-				},
-			}, {
-				.name = "AVerMedia AVerTV Volar HD/PRO (A835)",
-				.cold_ids = {
-					&af9035_id[AF9035_07CA_A835],
-					&af9035_id[AF9035_07CA_B835],
-				},
-			}, {
-				.name = "AVerMedia HD Volar (A867)",
-				.cold_ids = {
-					&af9035_id[AF9035_07CA_1867],
-					&af9035_id[AF9035_07CA_A867],
-				},
-			}, {
-				.name = "AVerMedia Twinstar (A825)",
-				.cold_ids = {
-					&af9035_id[AF9035_07CA_0825],
-				},
-			},
-		}
-	},
-	{
-		.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-		.usb_ctrl = DEVICE_SPECIFIC,
-		.download_firmware = af9035_download_firmware_it9135,
-		.firmware = "dvb-usb-it9135-01.fw",
-		.no_reconnect = 1,
-
-		.size_of_priv = sizeof(struct state),
-
-		.num_adapters = 1,
-		.adapter = {
-			{
-				.num_frontends = 1,
-				.fe = {
-					{
-						.frontend_attach = af9035_frontend_attach,
-						.tuner_attach = af9035_tuner_attach,
-						.stream = {
-							.type = USB_BULK,
-							.count = 6,
-							.endpoint = 0x84,
-							.u = {
-								.bulk = {
-									.buffersize = (87 * 188),
-								}
-							}
-						}
-					}
-				}
-			}
-		},
-
-		.identify_state = af9035_identify_state,
-		.read_mac_address = af9035_read_mac_address_it9135,
-
-		.i2c_algo = &af9035_i2c_algo,
-
-		.num_device_descs = 0, /* disabled as no support for IT9135 */
-		.devices = {
-			{
-				.name = "ITE Tech. IT9135 reference design",
-			},
-		}
-	},
-};
-
-static int af9035_usb_probe(struct usb_interface *intf,
-			    const struct usb_device_id *id)
-{
-	int ret, i;
-	struct dvb_usb_device *d = NULL;
-	struct usb_device *udev;
-	bool found;
-
-	pr_debug("%s: interface=%d\n", __func__,
-			intf->cur_altsetting->desc.bInterfaceNumber);
-
-	/* interface 0 is used by DVB-T receiver and
-	   interface 1 is for remote controller (HID) */
-	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
-		return 0;
-
-	/* Dynamic USB ID support. Replaces first device ID with current one. */
-	udev = interface_to_usbdev(intf);
-
-	for (i = 0, found = false; i < ARRAY_SIZE(af9035_id) - 1; i++) {
-		if (af9035_id[i].idVendor ==
-				le16_to_cpu(udev->descriptor.idVendor) &&
-				af9035_id[i].idProduct ==
-				le16_to_cpu(udev->descriptor.idProduct)) {
-			found = true;
-			break;
-		}
-	}
-
-	if (!found) {
-		pr_debug("%s: using dynamic ID %04x:%04x\n", __func__,
-				le16_to_cpu(udev->descriptor.idVendor),
-				le16_to_cpu(udev->descriptor.idProduct));
-		af9035_properties[0].devices[0].cold_ids[0]->idVendor =
-				le16_to_cpu(udev->descriptor.idVendor);
-		af9035_properties[0].devices[0].cold_ids[0]->idProduct =
-				le16_to_cpu(udev->descriptor.idProduct);
-	}
-
-
-	for (i = 0; i < af9035_properties_count; i++) {
-		ret = dvb_usb_device_init(intf, &af9035_properties[i],
-				THIS_MODULE, &d, adapter_nr);
-
-		if (ret == -ENODEV)
-			continue;
-		else
-			break;
-	}
-
-	if (ret < 0)
-		goto err;
-
-	if (d) {
-		ret = af9035_init(d);
-		if (ret < 0)
-			goto err;
-	}
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver af9035_usb_driver = {
-	.name = "dvb_usb_af9035",
-	.probe = af9035_usb_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table = af9035_id,
-};
-
-module_usb_driver(af9035_usb_driver);
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Afatech AF9035 driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9035.h b/drivers/media/dvb/dvb-usb/af9035.h
deleted file mode 100644
index 481a1a4..0000000
--- a/drivers/media/dvb/dvb-usb/af9035.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Afatech AF9035 DVB USB driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef AF9035_H
-#define AF9035_H
-
-/* prefix for dvb-usb log writings */
-#define DVB_USB_LOG_PREFIX "af9035"
-
-#include "dvb-usb.h"
-#include "af9033.h"
-#include "tua9001.h"
-#include "fc0011.h"
-#include "mxl5007t.h"
-#include "tda18218.h"
-
-struct reg_val {
-	u32 reg;
-	u8  val;
-};
-
-struct reg_val_mask {
-	u32 reg;
-	u8  val;
-	u8  mask;
-};
-
-struct usb_req {
-	u8  cmd;
-	u8  mbox;
-	u8  wlen;
-	u8  *wbuf;
-	u8  rlen;
-	u8  *rbuf;
-};
-
-struct state {
-	bool dual_mode;
-
-	struct af9033_config af9033_config[2];
-};
-
-u32 clock_lut[] = {
-	20480000, /*      FPGA */
-	16384000, /* 16.38 MHz */
-	20480000, /* 20.48 MHz */
-	36000000, /* 36.00 MHz */
-	30000000, /* 30.00 MHz */
-	26000000, /* 26.00 MHz */
-	28000000, /* 28.00 MHz */
-	32000000, /* 32.00 MHz */
-	34000000, /* 34.00 MHz */
-	24000000, /* 24.00 MHz */
-	22000000, /* 22.00 MHz */
-	12000000, /* 12.00 MHz */
-};
-
-u32 clock_lut_it9135[] = {
-	12000000, /* 12.00 MHz */
-	20480000, /* 20.48 MHz */
-	36000000, /* 36.00 MHz */
-	30000000, /* 30.00 MHz */
-	26000000, /* 26.00 MHz */
-	28000000, /* 28.00 MHz */
-	32000000, /* 32.00 MHz */
-	34000000, /* 34.00 MHz */
-	24000000, /* 24.00 MHz */
-	22000000, /* 22.00 MHz */
-};
-
-/* EEPROM locations */
-#define EEPROM_IR_MODE            0x430d
-#define EEPROM_DUAL_MODE          0x4326
-#define EEPROM_IR_TYPE            0x4329
-#define EEPROM_1_IFFREQ_L         0x432d
-#define EEPROM_1_IFFREQ_H         0x432e
-#define EEPROM_1_TUNER_ID         0x4331
-#define EEPROM_2_IFFREQ_L         0x433d
-#define EEPROM_2_IFFREQ_H         0x433e
-#define EEPROM_2_TUNER_ID         0x4341
-
-/* USB commands */
-#define CMD_MEM_RD                  0x00
-#define CMD_MEM_WR                  0x01
-#define CMD_I2C_RD                  0x02
-#define CMD_I2C_WR                  0x03
-#define CMD_IR_GET                  0x18
-#define CMD_FW_DL                   0x21
-#define CMD_FW_QUERYINFO            0x22
-#define CMD_FW_BOOT                 0x23
-#define CMD_FW_DL_BEGIN             0x24
-#define CMD_FW_DL_END               0x25
-#define CMD_FW_SCATTER_WR           0x29
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
deleted file mode 100644
index 03c2865..0000000
--- a/drivers/media/dvb/dvb-usb/anysee.c
+++ /dev/null
@@ -1,1406 +0,0 @@
-/*
- * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
- *
- * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * TODO:
- * - add smart card reader support for Conditional Access (CA)
- *
- * Card reader in Anysee is nothing more than ISO 7816 card reader.
- * There is no hardware CAM in any Anysee device sold.
- * In my understanding it should be implemented by making own module
- * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
- * module registers serial interface that can be used to communicate
- * with any ISO 7816 smart card.
- *
- * Any help according to implement serial smart card reader support
- * is highly welcome!
- */
-
-#include "anysee.h"
-#include "tda1002x.h"
-#include "mt352.h"
-#include "mt352_priv.h"
-#include "zl10353.h"
-#include "tda18212.h"
-#include "cx24116.h"
-#include "stv0900.h"
-#include "stv6110.h"
-#include "isl6423.h"
-#include "cxd2820r.h"
-
-/* debug */
-static int dvb_usb_anysee_debug;
-module_param_named(debug, dvb_usb_anysee_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
-static int dvb_usb_anysee_delsys;
-module_param_named(delsys, dvb_usb_anysee_delsys, int, 0644);
-MODULE_PARM_DESC(delsys, "select delivery mode (0=DVB-C, 1=DVB-T)");
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static DEFINE_MUTEX(anysee_usb_mutex);
-
-static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
-	u8 *rbuf, u8 rlen)
-{
-	struct anysee_state *state = d->priv;
-	int act_len, ret, i;
-	u8 buf[64];
-
-	memcpy(&buf[0], sbuf, slen);
-	buf[60] = state->seq++;
-
-	if (mutex_lock_interruptible(&anysee_usb_mutex) < 0)
-		return -EAGAIN;
-
-	deb_xfer(">>> ");
-	debug_dump(buf, slen, deb_xfer);
-
-	/* We need receive one message more after dvb_usb_generic_rw due
-	   to weird transaction flow, which is 1 x send + 2 x receive. */
-	ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0);
-	if (ret)
-		goto error_unlock;
-
-	/* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32
-	 * (EPIPE, Broken pipe). Function supports currently msleep() as a
-	 * parameter but I would not like to use it, since according to
-	 * Documentation/timers/timers-howto.txt it should not be used such
-	 * short, under < 20ms, sleeps. Repeating failed message would be
-	 * better choice as not to add unwanted delays...
-	 * Fixing that correctly is one of those or both;
-	 * 1) use repeat if possible
-	 * 2) add suitable delay
-	 */
-
-	/* get answer, retry few times if error returned */
-	for (i = 0; i < 3; i++) {
-		/* receive 2nd answer */
-		ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
-			d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf),
-			&act_len, 2000);
-
-		if (ret) {
-			deb_info("%s: recv bulk message failed: %d",
-					__func__, ret);
-		} else {
-			deb_xfer("<<< ");
-			debug_dump(buf, rlen, deb_xfer);
-
-			if (buf[63] != 0x4f)
-				deb_info("%s: cmd failed\n", __func__);
-
-			break;
-		}
-	}
-
-	if (ret) {
-		/* all retries failed, it is fatal */
-		err("%s: recv bulk message failed: %d", __func__, ret);
-		goto error_unlock;
-	}
-
-	/* read request, copy returned data to return buf */
-	if (rbuf && rlen)
-		memcpy(rbuf, buf, rlen);
-
-error_unlock:
-	mutex_unlock(&anysee_usb_mutex);
-
-	return ret;
-}
-
-static int anysee_read_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
-{
-	u8 buf[] = {CMD_REG_READ, reg >> 8, reg & 0xff, 0x01};
-	int ret;
-	ret = anysee_ctrl_msg(d, buf, sizeof(buf), val, 1);
-	deb_info("%s: reg:%04x val:%02x\n", __func__, reg, *val);
-	return ret;
-}
-
-static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val)
-{
-	u8 buf[] = {CMD_REG_WRITE, reg >> 8, reg & 0xff, 0x01, val};
-	deb_info("%s: reg:%04x val:%02x\n", __func__, reg, val);
-	return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
-}
-
-/* write single register with mask */
-static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val,
-	u8 mask)
-{
-	int ret;
-	u8 tmp;
-
-	/* no need for read if whole reg is written */
-	if (mask != 0xff) {
-		ret = anysee_read_reg(d, reg, &tmp);
-		if (ret)
-			return ret;
-
-		val &= mask;
-		tmp &= ~mask;
-		val |= tmp;
-	}
-
-	return anysee_write_reg(d, reg, val);
-}
-
-/* read single register with mask */
-static int anysee_rd_reg_mask(struct dvb_usb_device *d, u16 reg, u8 *val,
-	u8 mask)
-{
-	int ret, i;
-	u8 tmp;
-
-	ret = anysee_read_reg(d, reg, &tmp);
-	if (ret)
-		return ret;
-
-	tmp &= mask;
-
-	/* find position of the first bit */
-	for (i = 0; i < 8; i++) {
-		if ((mask >> i) & 0x01)
-			break;
-	}
-	*val = tmp >> i;
-
-	return 0;
-}
-
-static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id)
-{
-	u8 buf[] = {CMD_GET_HW_INFO};
-	return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3);
-}
-
-static int anysee_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00};
-	deb_info("%s: onoff:%02x\n", __func__, onoff);
-	return anysee_ctrl_msg(adap->dev, buf, sizeof(buf), NULL, 0);
-}
-
-static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval)
-{
-	u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x01, mode, interval};
-	deb_info("%s: state:%02x interval:%02x\n", __func__, mode, interval);
-	return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
-}
-
-static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff)
-{
-	u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x02, onoff};
-	deb_info("%s: onoff:%02x\n", __func__, onoff);
-	return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
-}
-
-/* I2C */
-static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
-	int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int ret = 0, inc, i = 0;
-	u8 buf[52]; /* 4 + 48 (I2C WR USB command header + I2C WR max) */
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	while (i < num) {
-		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
-			if (msg[i].len > 2 || msg[i+1].len > 60) {
-				ret = -EOPNOTSUPP;
-				break;
-			}
-			buf[0] = CMD_I2C_READ;
-			buf[1] = (msg[i].addr << 1) | 0x01;
-			buf[2] = msg[i].buf[0];
-			buf[3] = msg[i].buf[1];
-			buf[4] = msg[i].len-1;
-			buf[5] = msg[i+1].len;
-			ret = anysee_ctrl_msg(d, buf, 6, msg[i+1].buf,
-				msg[i+1].len);
-			inc = 2;
-		} else {
-			if (msg[i].len > 48) {
-				ret = -EOPNOTSUPP;
-				break;
-			}
-			buf[0] = CMD_I2C_WRITE;
-			buf[1] = (msg[i].addr << 1);
-			buf[2] = msg[i].len;
-			buf[3] = 0x01;
-			memcpy(&buf[4], msg[i].buf, msg[i].len);
-			ret = anysee_ctrl_msg(d, buf, 4 + msg[i].len, NULL, 0);
-			inc = 1;
-		}
-		if (ret)
-			break;
-
-		i += inc;
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-
-	return ret ? ret : i;
-}
-
-static u32 anysee_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm anysee_i2c_algo = {
-	.master_xfer   = anysee_master_xfer,
-	.functionality = anysee_i2c_func,
-};
-
-static int anysee_mt352_demod_init(struct dvb_frontend *fe)
-{
-	static u8 clock_config[]   = { CLOCK_CTL,  0x38, 0x28 };
-	static u8 reset[]          = { RESET,      0x80 };
-	static u8 adc_ctl_1_cfg[]  = { ADC_CTL_1,  0x40 };
-	static u8 agc_cfg[]        = { AGC_TARGET, 0x28, 0x20 };
-	static u8 gpp_ctl_cfg[]    = { GPP_CTL,    0x33 };
-	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
-
-	mt352_write(fe, clock_config,   sizeof(clock_config));
-	udelay(200);
-	mt352_write(fe, reset,          sizeof(reset));
-	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
-
-	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
-	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
-	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
-
-	return 0;
-}
-
-/* Callbacks for DVB USB */
-static struct tda10023_config anysee_tda10023_config = {
-	.demod_address = (0x1a >> 1),
-	.invert = 0,
-	.xtal   = 16000000,
-	.pll_m  = 11,
-	.pll_p  = 3,
-	.pll_n  = 1,
-	.output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C,
-	.deltaf = 0xfeeb,
-};
-
-static struct mt352_config anysee_mt352_config = {
-	.demod_address = (0x1e >> 1),
-	.demod_init    = anysee_mt352_demod_init,
-};
-
-static struct zl10353_config anysee_zl10353_config = {
-	.demod_address = (0x1e >> 1),
-	.parallel_ts = 1,
-};
-
-static struct zl10353_config anysee_zl10353_tda18212_config2 = {
-	.demod_address = (0x1e >> 1),
-	.parallel_ts = 1,
-	.disable_i2c_gate_ctrl = 1,
-	.no_tuner = 1,
-	.if2 = 41500,
-};
-
-static struct zl10353_config anysee_zl10353_tda18212_config = {
-	.demod_address = (0x18 >> 1),
-	.parallel_ts = 1,
-	.disable_i2c_gate_ctrl = 1,
-	.no_tuner = 1,
-	.if2 = 41500,
-};
-
-static struct tda10023_config anysee_tda10023_tda18212_config = {
-	.demod_address = (0x1a >> 1),
-	.xtal   = 16000000,
-	.pll_m  = 12,
-	.pll_p  = 3,
-	.pll_n  = 1,
-	.output_mode = TDA10023_OUTPUT_MODE_PARALLEL_B,
-	.deltaf = 0xba02,
-};
-
-static struct tda18212_config anysee_tda18212_config = {
-	.i2c_address = (0xc0 >> 1),
-	.if_dvbt_6 = 4150,
-	.if_dvbt_7 = 4150,
-	.if_dvbt_8 = 4150,
-	.if_dvbc = 5000,
-};
-
-static struct tda18212_config anysee_tda18212_config2 = {
-	.i2c_address = 0x60 /* (0xc0 >> 1) */,
-	.if_dvbt_6 = 3550,
-	.if_dvbt_7 = 3700,
-	.if_dvbt_8 = 4150,
-	.if_dvbt2_6 = 3250,
-	.if_dvbt2_7 = 4000,
-	.if_dvbt2_8 = 4000,
-	.if_dvbc = 5000,
-};
-
-static struct cx24116_config anysee_cx24116_config = {
-	.demod_address = (0xaa >> 1),
-	.mpg_clk_pos_pol = 0x00,
-	.i2c_wr_max = 48,
-};
-
-static struct stv0900_config anysee_stv0900_config = {
-	.demod_address = (0xd0 >> 1),
-	.demod_mode = 0,
-	.xtal = 8000000,
-	.clkmode = 3,
-	.diseqc_mode = 2,
-	.tun1_maddress = 0,
-	.tun1_adc = 1, /* 1 Vpp */
-	.path1_mode = 3,
-};
-
-static struct stv6110_config anysee_stv6110_config = {
-	.i2c_address = (0xc0 >> 1),
-	.mclk = 16000000,
-	.clk_div = 1,
-};
-
-static struct isl6423_config anysee_isl6423_config = {
-	.current_max = SEC_CURRENT_800m,
-	.curlim  = SEC_CURRENT_LIM_OFF,
-	.mod_extern = 1,
-	.addr = (0x10 >> 1),
-};
-
-static struct cxd2820r_config anysee_cxd2820r_config = {
-	.i2c_address = 0x6d, /* (0xda >> 1) */
-	.ts_mode = 0x38,
-};
-
-/*
- * New USB device strings: Mfr=1, Product=2, SerialNumber=0
- * Manufacturer: AMT.CO.KR
- *
- * E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=????????
- * PCB: ?
- * parts: DNOS404ZH102A(MT352, DTT7579(?))
- *
- * E30 VID=04b4 PID=861f HW=2 FW=2.1 "anysee-T(LP)"
- * PCB: PCB 507T (rev1.61)
- * parts: DNOS404ZH103A(ZL10353, DTT7579(?))
- * OEA=0a OEB=00 OEC=00 OED=ff OEE=00
- * IOA=45 IOB=ff IOC=00 IOD=ff IOE=00
- *
- * E30 Plus VID=04b4 PID=861f HW=6 FW=1.0 "anysee"
- * PCB: 507CD (rev1.1)
- * parts: DNOS404ZH103A(ZL10353, DTT7579(?)), CST56I01
- * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe
- * IOA=4f IOB=ff IOC=00 IOD=06 IOE=01
- * IOD[0] ZL10353 1=enabled
- * IOA[7] TS 0=enabled
- * tuner is not behind ZL10353 I2C-gate (no care if gate disabled or not)
- *
- * E30 C Plus VID=04b4 PID=861f HW=10 FW=1.0 "anysee-DC(LP)"
- * PCB: 507DC (rev0.2)
- * parts: TDA10023, DTOS403IH102B TM, CST56I01
- * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe
- * IOA=4f IOB=ff IOC=00 IOD=26 IOE=01
- * IOD[0] TDA10023 1=enabled
- *
- * E30 S2 Plus VID=04b4 PID=861f HW=11 FW=0.1 "anysee-S2(LP)"
- * PCB: 507SI (rev2.1)
- * parts: BS2N10WCC01(CX24116, CX24118), ISL6423, TDA8024
- * OEA=80 OEB=00 OEC=ff OED=ff OEE=fe
- * IOA=4d IOB=ff IOC=00 IOD=26 IOE=01
- * IOD[0] CX24116 1=enabled
- *
- * E30 C Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
- * PCB: 507FA (rev0.4)
- * parts: TDA10023, DTOS403IH102B TM, TDA8024
- * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff
- * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0
- * IOD[5] TDA10023 1=enabled
- * IOE[0] tuner 1=enabled
- *
- * E30 Combo Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
- * PCB: 507FA (rev1.1)
- * parts: ZL10353, TDA10023, DTOS403IH102B TM, TDA8024
- * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff
- * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0
- * DVB-C:
- * IOD[5] TDA10023 1=enabled
- * IOE[0] tuner 1=enabled
- * DVB-T:
- * IOD[0] ZL10353 1=enabled
- * IOE[0] tuner 0=enabled
- * tuner is behind ZL10353 I2C-gate
- *
- * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)"
- * PCB: 508TC (rev0.6)
- * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212)
- * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
- * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4
- * IOA[7] TS 1=enabled
- * IOE[4] TDA18212 1=enabled
- * DVB-C:
- * IOD[6] ZL10353 0=disabled
- * IOD[5] TDA10023 1=enabled
- * IOE[0] IF 1=enabled
- * DVB-T:
- * IOD[5] TDA10023 0=disabled
- * IOD[6] ZL10353 1=enabled
- * IOE[0] IF 0=enabled
- *
- * E7 S2 VID=1c73 PID=861f HW=19 FW=0.4 AMTCI=0.5 "anysee-E7S2(LP)"
- * PCB: 508S2 (rev0.7)
- * parts: DNBU10512IST(STV0903, STV6110), ISL6423
- * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
- * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4
- * IOA[7] TS 1=enabled
- * IOE[5] STV0903 1=enabled
- *
- * E7 T2C VID=1c73 PID=861f HW=20 FW=0.1 AMTCI=0.5 "anysee-E7T2C(LP)"
- * PCB: 508T2C (rev0.3)
- * parts: DNOQ44QCH106A(CXD2820R, TDA18212), TDA8024
- * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
- * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4
- * IOA[7] TS 1=enabled
- * IOE[5] CXD2820R 1=enabled
- *
- * E7 PTC VID=1c73 PID=861f HW=21 FW=0.1 AMTCI=?? "anysee-E7PTC(LP)"
- * PCB: 508PTC (rev0.5)
- * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212)
- * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
- * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4
- * IOA[7] TS 1=enabled
- * IOE[4] TDA18212 1=enabled
- * DVB-C:
- * IOD[6] ZL10353 0=disabled
- * IOD[5] TDA10023 1=enabled
- * IOE[0] IF 1=enabled
- * DVB-T:
- * IOD[5] TDA10023 0=disabled
- * IOD[6] ZL10353 1=enabled
- * IOE[0] IF 0=enabled
- *
- * E7 PS2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)"
- * PCB: 508PS2 (rev0.4)
- * parts: DNBU10512IST(STV0903, STV6110), ISL6423
- * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
- * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4
- * IOA[7] TS 1=enabled
- * IOE[5] STV0903 1=enabled
- */
-
-
-/* external I2C gate used for DNOD44CDH086A(TDA18212) tuner module */
-static int anysee_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-
-	/* enable / disable tuner access on IOE[4] */
-	return anysee_wr_reg_mask(adap->dev, REG_IOE, (enable << 4), 0x10);
-}
-
-static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct anysee_state *state = adap->dev->priv;
-	int ret;
-
-	deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
-
-	/* no frontend sleep control */
-	if (onoff == 0)
-		return 0;
-
-	switch (state->hw) {
-	case ANYSEE_HW_507FA: /* 15 */
-		/* E30 Combo Plus */
-		/* E30 C Plus */
-
-		if ((fe->id ^ dvb_usb_anysee_delsys) == 0)  {
-			/* disable DVB-T demod on IOD[0] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0),
-				0x01);
-			if (ret)
-				goto error;
-
-			/* enable DVB-C demod on IOD[5] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
-				0x20);
-			if (ret)
-				goto error;
-
-			/* enable DVB-C tuner on IOE[0] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
-				0x01);
-			if (ret)
-				goto error;
-		} else {
-			/* disable DVB-C demod on IOD[5] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
-				0x20);
-			if (ret)
-				goto error;
-
-			/* enable DVB-T demod on IOD[0] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0),
-				0x01);
-			if (ret)
-				goto error;
-
-			/* enable DVB-T tuner on IOE[0] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
-				0x01);
-			if (ret)
-				goto error;
-		}
-
-		break;
-	case ANYSEE_HW_508TC: /* 18 */
-	case ANYSEE_HW_508PTC: /* 21 */
-		/* E7 TC */
-		/* E7 PTC */
-
-		if ((fe->id ^ dvb_usb_anysee_delsys) == 0)  {
-			/* disable DVB-T demod on IOD[6] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6),
-				0x40);
-			if (ret)
-				goto error;
-
-			/* enable DVB-C demod on IOD[5] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
-				0x20);
-			if (ret)
-				goto error;
-
-			/* enable IF route on IOE[0] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
-				0x01);
-			if (ret)
-				goto error;
-		} else {
-			/* disable DVB-C demod on IOD[5] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
-				0x20);
-			if (ret)
-				goto error;
-
-			/* enable DVB-T demod on IOD[6] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6),
-				0x40);
-			if (ret)
-				goto error;
-
-			/* enable IF route on IOE[0] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
-				0x01);
-			if (ret)
-				goto error;
-		}
-
-		break;
-	default:
-		ret = 0;
-	}
-
-error:
-	return ret;
-}
-
-static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	int ret;
-	struct anysee_state *state = adap->dev->priv;
-	u8 hw_info[3];
-	u8 tmp;
-	struct i2c_msg msg[2] = {
-		{
-			.addr = anysee_tda18212_config.i2c_address,
-			.flags = 0,
-			.len = 1,
-			.buf = "\x00",
-		}, {
-			.addr = anysee_tda18212_config.i2c_address,
-			.flags = I2C_M_RD,
-			.len = 1,
-			.buf = &tmp,
-		}
-	};
-
-	/* detect hardware only once */
-	if (adap->fe_adap[0].fe == NULL) {
-		/* Check which hardware we have.
-		 * We must do this call two times to get reliable values
-		 * (hw/fw bug).
-		 */
-		ret = anysee_get_hw_info(adap->dev, hw_info);
-		if (ret)
-			goto error;
-
-		ret = anysee_get_hw_info(adap->dev, hw_info);
-		if (ret)
-			goto error;
-
-		/* Meaning of these info bytes are guessed. */
-		info("firmware version:%d.%d hardware id:%d",
-			hw_info[1], hw_info[2], hw_info[0]);
-
-		state->hw = hw_info[0];
-	}
-
-	/* set current frondend ID for devices having two frondends */
-	if (adap->fe_adap[0].fe)
-		state->fe_id++;
-
-	switch (state->hw) {
-	case ANYSEE_HW_507T: /* 2 */
-		/* E30 */
-
-		if (state->fe_id)
-			break;
-
-		/* attach demod */
-		adap->fe_adap[0].fe = dvb_attach(mt352_attach,
-			&anysee_mt352_config, &adap->dev->i2c_adap);
-		if (adap->fe_adap[0].fe)
-			break;
-
-		/* attach demod */
-		adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
-			&anysee_zl10353_config, &adap->dev->i2c_adap);
-
-		break;
-	case ANYSEE_HW_507CD: /* 6 */
-		/* E30 Plus */
-
-		if (state->fe_id)
-			break;
-
-		/* enable DVB-T demod on IOD[0] */
-		ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
-		if (ret)
-			goto error;
-
-		/* enable transport stream on IOA[7] */
-		ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (0 << 7), 0x80);
-		if (ret)
-			goto error;
-
-		/* attach demod */
-		adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
-			&anysee_zl10353_config, &adap->dev->i2c_adap);
-
-		break;
-	case ANYSEE_HW_507DC: /* 10 */
-		/* E30 C Plus */
-
-		if (state->fe_id)
-			break;
-
-		/* enable DVB-C demod on IOD[0] */
-		ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
-		if (ret)
-			goto error;
-
-		/* attach demod */
-		adap->fe_adap[0].fe = dvb_attach(tda10023_attach,
-			&anysee_tda10023_config, &adap->dev->i2c_adap, 0x48);
-
-		break;
-	case ANYSEE_HW_507SI: /* 11 */
-		/* E30 S2 Plus */
-
-		if (state->fe_id)
-			break;
-
-		/* enable DVB-S/S2 demod on IOD[0] */
-		ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
-		if (ret)
-			goto error;
-
-		/* attach demod */
-		adap->fe_adap[0].fe = dvb_attach(cx24116_attach,
-			&anysee_cx24116_config, &adap->dev->i2c_adap);
-
-		break;
-	case ANYSEE_HW_507FA: /* 15 */
-		/* E30 Combo Plus */
-		/* E30 C Plus */
-
-		/* enable tuner on IOE[4] */
-		ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
-		if (ret)
-			goto error;
-
-		/* probe TDA18212 */
-		tmp = 0;
-		ret = i2c_transfer(&adap->dev->i2c_adap, msg, 2);
-		if (ret == 2 && tmp == 0xc7)
-			deb_info("%s: TDA18212 found\n", __func__);
-		else
-			tmp = 0;
-
-		/* disable tuner on IOE[4] */
-		ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 4), 0x10);
-		if (ret)
-			goto error;
-
-		if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0)  {
-			/* disable DVB-T demod on IOD[0] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0),
-				0x01);
-			if (ret)
-				goto error;
-
-			/* enable DVB-C demod on IOD[5] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
-				0x20);
-			if (ret)
-				goto error;
-
-			/* attach demod */
-			if (tmp == 0xc7) {
-				/* TDA18212 config */
-				adap->fe_adap[state->fe_id].fe = dvb_attach(
-					tda10023_attach,
-					&anysee_tda10023_tda18212_config,
-					&adap->dev->i2c_adap, 0x48);
-			} else {
-				/* PLL config */
-				adap->fe_adap[state->fe_id].fe = dvb_attach(
-					tda10023_attach,
-					&anysee_tda10023_config,
-					&adap->dev->i2c_adap, 0x48);
-			}
-		} else {
-			/* disable DVB-C demod on IOD[5] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
-				0x20);
-			if (ret)
-				goto error;
-
-			/* enable DVB-T demod on IOD[0] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0),
-				0x01);
-			if (ret)
-				goto error;
-
-			/* attach demod */
-			if (tmp == 0xc7) {
-				/* TDA18212 config */
-				adap->fe_adap[state->fe_id].fe = dvb_attach(
-					zl10353_attach,
-					&anysee_zl10353_tda18212_config2,
-					&adap->dev->i2c_adap);
-			} else {
-				/* PLL config */
-				adap->fe_adap[state->fe_id].fe = dvb_attach(
-					zl10353_attach,
-					&anysee_zl10353_config,
-					&adap->dev->i2c_adap);
-			}
-		}
-
-		/* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
-		if (tmp == 0xc7) {
-			if (adap->fe_adap[state->fe_id].fe)
-				adap->fe_adap[state->fe_id].fe->ops.i2c_gate_ctrl =
-					anysee_i2c_gate_ctrl;
-		}
-
-		break;
-	case ANYSEE_HW_508TC: /* 18 */
-	case ANYSEE_HW_508PTC: /* 21 */
-		/* E7 TC */
-		/* E7 PTC */
-
-		if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0)  {
-			/* disable DVB-T demod on IOD[6] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6),
-				0x40);
-			if (ret)
-				goto error;
-
-			/* enable DVB-C demod on IOD[5] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
-				0x20);
-			if (ret)
-				goto error;
-
-			/* attach demod */
-			adap->fe_adap[state->fe_id].fe =
-				dvb_attach(tda10023_attach,
-				&anysee_tda10023_tda18212_config,
-				&adap->dev->i2c_adap, 0x48);
-		} else {
-			/* disable DVB-C demod on IOD[5] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
-				0x20);
-			if (ret)
-				goto error;
-
-			/* enable DVB-T demod on IOD[6] */
-			ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6),
-				0x40);
-			if (ret)
-				goto error;
-
-			/* attach demod */
-			adap->fe_adap[state->fe_id].fe =
-				dvb_attach(zl10353_attach,
-				&anysee_zl10353_tda18212_config,
-				&adap->dev->i2c_adap);
-		}
-
-		/* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
-		if (adap->fe_adap[state->fe_id].fe)
-			adap->fe_adap[state->fe_id].fe->ops.i2c_gate_ctrl =
-				anysee_i2c_gate_ctrl;
-
-		state->has_ci = true;
-
-		break;
-	case ANYSEE_HW_508S2: /* 19 */
-	case ANYSEE_HW_508PS2: /* 22 */
-		/* E7 S2 */
-		/* E7 PS2 */
-
-		if (state->fe_id)
-			break;
-
-		/* enable DVB-S/S2 demod on IOE[5] */
-		ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20);
-		if (ret)
-			goto error;
-
-		/* attach demod */
-		adap->fe_adap[0].fe = dvb_attach(stv0900_attach,
-			&anysee_stv0900_config, &adap->dev->i2c_adap, 0);
-
-		state->has_ci = true;
-
-		break;
-	case ANYSEE_HW_508T2C: /* 20 */
-		/* E7 T2C */
-
-		if (state->fe_id)
-			break;
-
-		/* enable DVB-T/T2/C demod on IOE[5] */
-		ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20);
-		if (ret)
-			goto error;
-
-		/* attach demod */
-		adap->fe_adap[state->fe_id].fe = dvb_attach(cxd2820r_attach,
-				&anysee_cxd2820r_config, &adap->dev->i2c_adap);
-
-		state->has_ci = true;
-
-		break;
-	}
-
-	if (!adap->fe_adap[0].fe) {
-		/* we have no frontend :-( */
-		ret = -ENODEV;
-		err("Unsupported Anysee version. " \
-			"Please report the <linux-media@vger.kernel.org>.");
-	}
-error:
-	return ret;
-}
-
-static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct anysee_state *state = adap->dev->priv;
-	struct dvb_frontend *fe;
-	int ret;
-	deb_info("%s: fe=%d\n", __func__, state->fe_id);
-
-	switch (state->hw) {
-	case ANYSEE_HW_507T: /* 2 */
-		/* E30 */
-
-		/* attach tuner */
-		fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe,
-			(0xc2 >> 1), NULL, DVB_PLL_THOMSON_DTT7579);
-
-		break;
-	case ANYSEE_HW_507CD: /* 6 */
-		/* E30 Plus */
-
-		/* attach tuner */
-		fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe,
-			(0xc2 >> 1), &adap->dev->i2c_adap,
-			DVB_PLL_THOMSON_DTT7579);
-
-		break;
-	case ANYSEE_HW_507DC: /* 10 */
-		/* E30 C Plus */
-
-		/* attach tuner */
-		fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe,
-			(0xc0 >> 1), &adap->dev->i2c_adap,
-			DVB_PLL_SAMSUNG_DTOS403IH102A);
-
-		break;
-	case ANYSEE_HW_507SI: /* 11 */
-		/* E30 S2 Plus */
-
-		/* attach LNB controller */
-		fe = dvb_attach(isl6423_attach, adap->fe_adap[0].fe,
-			&adap->dev->i2c_adap, &anysee_isl6423_config);
-
-		break;
-	case ANYSEE_HW_507FA: /* 15 */
-		/* E30 Combo Plus */
-		/* E30 C Plus */
-
-		/* Try first attach TDA18212 silicon tuner on IOE[4], if that
-		 * fails attach old simple PLL. */
-
-		/* attach tuner */
-		fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
-			&adap->dev->i2c_adap, &anysee_tda18212_config);
-		if (fe)
-			break;
-
-		/* attach tuner */
-		fe = dvb_attach(dvb_pll_attach, adap->fe_adap[state->fe_id].fe,
-			(0xc0 >> 1), &adap->dev->i2c_adap,
-			DVB_PLL_SAMSUNG_DTOS403IH102A);
-
-		break;
-	case ANYSEE_HW_508TC: /* 18 */
-	case ANYSEE_HW_508PTC: /* 21 */
-		/* E7 TC */
-		/* E7 PTC */
-
-		/* attach tuner */
-		fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
-			&adap->dev->i2c_adap, &anysee_tda18212_config);
-
-		break;
-	case ANYSEE_HW_508S2: /* 19 */
-	case ANYSEE_HW_508PS2: /* 22 */
-		/* E7 S2 */
-		/* E7 PS2 */
-
-		/* attach tuner */
-		fe = dvb_attach(stv6110_attach, adap->fe_adap[0].fe,
-			&anysee_stv6110_config, &adap->dev->i2c_adap);
-
-		if (fe) {
-			/* attach LNB controller */
-			fe = dvb_attach(isl6423_attach, adap->fe_adap[0].fe,
-				&adap->dev->i2c_adap, &anysee_isl6423_config);
-		}
-
-		break;
-
-	case ANYSEE_HW_508T2C: /* 20 */
-		/* E7 T2C */
-
-		/* attach tuner */
-		fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
-			&adap->dev->i2c_adap, &anysee_tda18212_config2);
-
-		break;
-	default:
-		fe = NULL;
-	}
-
-	if (fe)
-		ret = 0;
-	else
-		ret = -ENODEV;
-
-	return ret;
-}
-
-static int anysee_rc_query(struct dvb_usb_device *d)
-{
-	u8 buf[] = {CMD_GET_IR_CODE};
-	u8 ircode[2];
-	int ret;
-
-	/* Remote controller is basic NEC using address byte 0x08.
-	   Anysee device RC query returns only two bytes, status and code,
-	   address byte is dropped. Also it does not return any value for
-	   NEC RCs having address byte other than 0x08. Due to that, we
-	   cannot use that device as standard NEC receiver.
-	   It could be possible make hack which reads whole code directly
-	   from device memory... */
-
-	ret = anysee_ctrl_msg(d, buf, sizeof(buf), ircode, sizeof(ircode));
-	if (ret)
-		return ret;
-
-	if (ircode[0]) {
-		deb_rc("%s: key pressed %02x\n", __func__, ircode[1]);
-		rc_keydown(d->rc_dev, 0x08 << 8 | ircode[1], 0);
-	}
-
-	return 0;
-}
-
-static int anysee_ci_read_attribute_mem(struct dvb_ca_en50221 *ci, int slot,
-	int addr)
-{
-	struct dvb_usb_device *d = ci->data;
-	int ret;
-	u8 buf[] = {CMD_CI, 0x02, 0x40 | addr >> 8, addr & 0xff, 0x00, 1};
-	u8 val;
-
-	ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1);
-	if (ret)
-		return ret;
-
-	return val;
-}
-
-static int anysee_ci_write_attribute_mem(struct dvb_ca_en50221 *ci, int slot,
-	int addr, u8 val)
-{
-	struct dvb_usb_device *d = ci->data;
-	int ret;
-	u8 buf[] = {CMD_CI, 0x03, 0x40 | addr >> 8, addr & 0xff, 0x00, 1, val};
-
-	ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static int anysee_ci_read_cam_control(struct dvb_ca_en50221 *ci, int slot,
-	u8 addr)
-{
-	struct dvb_usb_device *d = ci->data;
-	int ret;
-	u8 buf[] = {CMD_CI, 0x04, 0x40, addr, 0x00, 1};
-	u8 val;
-
-	ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1);
-	if (ret)
-		return ret;
-
-	return val;
-}
-
-static int anysee_ci_write_cam_control(struct dvb_ca_en50221 *ci, int slot,
-	u8 addr, u8 val)
-{
-	struct dvb_usb_device *d = ci->data;
-	int ret;
-	u8 buf[] = {CMD_CI, 0x05, 0x40, addr, 0x00, 1, val};
-
-	ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static int anysee_ci_slot_reset(struct dvb_ca_en50221 *ci, int slot)
-{
-	struct dvb_usb_device *d = ci->data;
-	int ret;
-	struct anysee_state *state = d->priv;
-
-	state->ci_cam_ready = jiffies + msecs_to_jiffies(1000);
-
-	ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80);
-	if (ret)
-		return ret;
-
-	msleep(300);
-
-	ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static int anysee_ci_slot_shutdown(struct dvb_ca_en50221 *ci, int slot)
-{
-	struct dvb_usb_device *d = ci->data;
-	int ret;
-
-	ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80);
-	if (ret)
-		return ret;
-
-	msleep(30);
-
-	ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static int anysee_ci_slot_ts_enable(struct dvb_ca_en50221 *ci, int slot)
-{
-	struct dvb_usb_device *d = ci->data;
-	int ret;
-
-	ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 1), 0x02);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static int anysee_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot,
-	int open)
-{
-	struct dvb_usb_device *d = ci->data;
-	struct anysee_state *state = d->priv;
-	int ret;
-	u8 tmp;
-
-	ret = anysee_rd_reg_mask(d, REG_IOC, &tmp, 0x40);
-	if (ret)
-		return ret;
-
-	if (tmp == 0) {
-		ret = DVB_CA_EN50221_POLL_CAM_PRESENT;
-		if (time_after(jiffies, state->ci_cam_ready))
-			ret |= DVB_CA_EN50221_POLL_CAM_READY;
-	}
-
-	return ret;
-}
-
-static int anysee_ci_init(struct dvb_usb_device *d)
-{
-	struct anysee_state *state = d->priv;
-	int ret;
-
-	state->ci.owner               = THIS_MODULE;
-	state->ci.read_attribute_mem  = anysee_ci_read_attribute_mem;
-	state->ci.write_attribute_mem = anysee_ci_write_attribute_mem;
-	state->ci.read_cam_control    = anysee_ci_read_cam_control;
-	state->ci.write_cam_control   = anysee_ci_write_cam_control;
-	state->ci.slot_reset          = anysee_ci_slot_reset;
-	state->ci.slot_shutdown       = anysee_ci_slot_shutdown;
-	state->ci.slot_ts_enable      = anysee_ci_slot_ts_enable;
-	state->ci.poll_slot_status    = anysee_ci_poll_slot_status;
-	state->ci.data                = d;
-
-	ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80);
-	if (ret)
-		return ret;
-
-	ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 2)|(0 << 1)|(0 << 0), 0x07);
-	if (ret)
-		return ret;
-
-	ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 2)|(1 << 1)|(1 << 0), 0x07);
-	if (ret)
-		return ret;
-
-	ret = dvb_ca_en50221_init(&d->adapter[0].dvb_adap, &state->ci, 0, 1);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static void anysee_ci_release(struct dvb_usb_device *d)
-{
-	struct anysee_state *state = d->priv;
-
-	/* detach CI */
-	if (state->has_ci)
-		dvb_ca_en50221_release(&state->ci);
-
-	return;
-}
-
-static int anysee_init(struct dvb_usb_device *d)
-{
-	struct anysee_state *state = d->priv;
-	int ret;
-
-	/* LED light */
-	ret = anysee_led_ctrl(d, 0x01, 0x03);
-	if (ret)
-		return ret;
-
-	/* enable IR */
-	ret = anysee_ir_ctrl(d, 1);
-	if (ret)
-		return ret;
-
-	/* attach CI */
-	if (state->has_ci) {
-		ret = anysee_ci_init(d);
-		if (ret) {
-			state->has_ci = false;
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties anysee_properties;
-
-static int anysee_probe(struct usb_interface *intf,
-			const struct usb_device_id *id)
-{
-	struct dvb_usb_device *d;
-	struct usb_host_interface *alt;
-	int ret;
-
-	/* There is one interface with two alternate settings.
-	   Alternate setting 0 is for bulk transfer.
-	   Alternate setting 1 is for isochronous transfer.
-	   We use bulk transfer (alternate setting 0). */
-	if (intf->num_altsetting < 1)
-		return -ENODEV;
-
-	/*
-	 * Anysee is always warm (its USB-bridge, Cypress FX2, uploads
-	 * firmware from eeprom).  If dvb_usb_device_init() succeeds that
-	 * means d is a valid pointer.
-	 */
-	ret = dvb_usb_device_init(intf, &anysee_properties, THIS_MODULE, &d,
-		adapter_nr);
-	if (ret)
-		return ret;
-
-	alt = usb_altnum_to_altsetting(intf, 0);
-	if (alt == NULL) {
-		deb_info("%s: no alt found!\n", __func__);
-		return -ENODEV;
-	}
-
-	ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
-		alt->desc.bAlternateSetting);
-	if (ret)
-		return ret;
-
-	return anysee_init(d);
-}
-
-static void anysee_disconnect(struct usb_interface *intf)
-{
-	struct dvb_usb_device *d = usb_get_intfdata(intf);
-
-	anysee_ci_release(d);
-	dvb_usb_device_exit(intf);
-
-	return;
-}
-
-static struct usb_device_id anysee_table[] = {
-	{ USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) },
-	{ USB_DEVICE(USB_VID_AMT,     USB_PID_ANYSEE) },
-	{ }		/* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, anysee_table);
-
-static struct dvb_usb_device_properties anysee_properties = {
-	.caps             = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl         = DEVICE_SPECIFIC,
-
-	.size_of_priv     = sizeof(struct anysee_state),
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends    = 2,
-		.frontend_ctrl    = anysee_frontend_ctrl,
-		.fe = { {
-			.streaming_ctrl   = anysee_streaming_ctrl,
-			.frontend_attach  = anysee_frontend_attach,
-			.tuner_attach     = anysee_tuner_attach,
-			.stream = {
-				.type = USB_BULK,
-				.count = 8,
-				.endpoint = 0x82,
-				.u = {
-					.bulk = {
-						.buffersize = (16*512),
-					}
-				}
-			},
-		}, {
-			.streaming_ctrl   = anysee_streaming_ctrl,
-			.frontend_attach  = anysee_frontend_attach,
-			.tuner_attach     = anysee_tuner_attach,
-			.stream = {
-				.type = USB_BULK,
-				.count = 8,
-				.endpoint = 0x82,
-				.u = {
-					.bulk = {
-						.buffersize = (16*512),
-					}
-				}
-			},
-		} },
-		}
-	},
-
-	.rc.core = {
-		.rc_codes         = RC_MAP_ANYSEE,
-		.protocol         = RC_TYPE_OTHER,
-		.module_name      = "anysee",
-		.rc_query         = anysee_rc_query,
-		.rc_interval      = 250,  /* windows driver uses 500ms */
-	},
-
-	.i2c_algo         = &anysee_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 1,
-
-	.num_device_descs = 1,
-	.devices = {
-		{
-			.name = "Anysee DVB USB2.0",
-			.cold_ids = {NULL},
-			.warm_ids = {&anysee_table[0],
-				     &anysee_table[1], NULL},
-		},
-	}
-};
-
-static struct usb_driver anysee_driver = {
-	.name       = "dvb_usb_anysee",
-	.probe      = anysee_probe,
-	.disconnect = anysee_disconnect,
-	.id_table   = anysee_table,
-};
-
-module_usb_driver(anysee_driver);
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/anysee.h b/drivers/media/dvb/dvb-usb/anysee.h
deleted file mode 100644
index 8ac8794..0000000
--- a/drivers/media/dvb/dvb-usb/anysee.h
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
- *
- * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * TODO:
- * - add smart card reader support for Conditional Access (CA)
- *
- * Card reader in Anysee is nothing more than ISO 7816 card reader.
- * There is no hardware CAM in any Anysee device sold.
- * In my understanding it should be implemented by making own module
- * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
- * module registers serial interface that can be used to communicate
- * with any ISO 7816 smart card.
- *
- * Any help according to implement serial smart card reader support
- * is highly welcome!
- */
-
-#ifndef _DVB_USB_ANYSEE_H_
-#define _DVB_USB_ANYSEE_H_
-
-#define DVB_USB_LOG_PREFIX "anysee"
-#include "dvb-usb.h"
-#include "dvb_ca_en50221.h"
-
-#define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args)
-#define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args)
-#define deb_rc(args...)   dprintk(dvb_usb_anysee_debug, 0x04, args)
-#define deb_reg(args...)  dprintk(dvb_usb_anysee_debug, 0x08, args)
-#define deb_i2c(args...)  dprintk(dvb_usb_anysee_debug, 0x10, args)
-#define deb_fw(args...)   dprintk(dvb_usb_anysee_debug, 0x20, args)
-
-enum cmd {
-	CMD_I2C_READ            = 0x33,
-	CMD_I2C_WRITE           = 0x31,
-	CMD_REG_READ            = 0xb0,
-	CMD_REG_WRITE           = 0xb1,
-	CMD_STREAMING_CTRL      = 0x12,
-	CMD_LED_AND_IR_CTRL     = 0x16,
-	CMD_GET_IR_CODE         = 0x41,
-	CMD_GET_HW_INFO         = 0x19,
-	CMD_SMARTCARD           = 0x34,
-	CMD_CI                  = 0x37,
-};
-
-struct anysee_state {
-	u8 hw; /* PCB ID */
-	u8 seq;
-	u8 fe_id:1; /* frondend ID */
-	u8 has_ci:1;
-	struct dvb_ca_en50221 ci;
-	unsigned long ci_cam_ready; /* jiffies */
-};
-
-#define ANYSEE_HW_507T    2 /* E30 */
-#define ANYSEE_HW_507CD   6 /* E30 Plus */
-#define ANYSEE_HW_507DC  10 /* E30 C Plus */
-#define ANYSEE_HW_507SI  11 /* E30 S2 Plus */
-#define ANYSEE_HW_507FA  15 /* E30 Combo Plus / E30 C Plus */
-#define ANYSEE_HW_508TC  18 /* E7 TC */
-#define ANYSEE_HW_508S2  19 /* E7 S2 */
-#define ANYSEE_HW_508T2C 20 /* E7 T2C */
-#define ANYSEE_HW_508PTC 21 /* E7 PTC Plus */
-#define ANYSEE_HW_508PS2 22 /* E7 PS2 Plus */
-
-#define REG_IOA       0x80 /* Port A (bit addressable) */
-#define REG_IOB       0x90 /* Port B (bit addressable) */
-#define REG_IOC       0xa0 /* Port C (bit addressable) */
-#define REG_IOD       0xb0 /* Port D (bit addressable) */
-#define REG_IOE       0xb1 /* Port E (NOT bit addressable) */
-#define REG_OEA       0xb2 /* Port A Output Enable */
-#define REG_OEB       0xb3 /* Port B Output Enable */
-#define REG_OEC       0xb4 /* Port C Output Enable */
-#define REG_OED       0xb5 /* Port D Output Enable */
-#define REG_OEE       0xb6 /* Port E Output Enable */
-
-#endif
-
-/***************************************************************************
- * USB API description (reverse engineered)
- ***************************************************************************
-
-Transaction flow:
-=================
-BULK[00001] >>> REQUEST PACKET 64 bytes
-BULK[00081] <<< REPLY PACKET #1 64 bytes (PREVIOUS TRANSACTION REPLY)
-BULK[00081] <<< REPLY PACKET #2 64 bytes (CURRENT TRANSACTION REPLY)
-
-General reply packet(s) are always used if not own reply defined.
-
-============================================================================
-| 00-63 | GENERAL REPLY PACKET #1 (PREVIOUS REPLY)
-============================================================================
-|    00 | reply data (if any) from previous transaction
-|       | Just same reply packet as returned during previous transaction.
-|       | Needed only if reply is missed in previous transaction.
-|       | Just skip normally.
-----------------------------------------------------------------------------
-| 01-59 | don't care
-----------------------------------------------------------------------------
-|    60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | GENERAL REPLY PACKET #2 (CURRENT REPLY)
-============================================================================
-|    00 | reply data (if any)
-----------------------------------------------------------------------------
-| 01-59 | don't care
-----------------------------------------------------------------------------
-|    60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | I2C WRITE REQUEST PACKET
-============================================================================
-|    00 | 0x31 I2C write command
-----------------------------------------------------------------------------
-|    01 | i2c address
-----------------------------------------------------------------------------
-|    02 | data length
-|       | 0x02 (for typical I2C reg / val pair)
-----------------------------------------------------------------------------
-|    03 | 0x01
-----------------------------------------------------------------------------
-| 04-   | data
-----------------------------------------------------------------------------
-|   -59 | don't care
-----------------------------------------------------------------------------
-|    60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | I2C READ REQUEST PACKET
-============================================================================
-|    00 | 0x33 I2C read command
-----------------------------------------------------------------------------
-|    01 | i2c address + 1
-----------------------------------------------------------------------------
-|    02 | register
-----------------------------------------------------------------------------
-|    03 | 0x00
-----------------------------------------------------------------------------
-|    04 | 0x00
-----------------------------------------------------------------------------
-|    05 | data length
-----------------------------------------------------------------------------
-| 06-59 | don't care
-----------------------------------------------------------------------------
-|    60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | USB CONTROLLER REGISTER WRITE REQUEST PACKET
-============================================================================
-|    00 | 0xb1 register write command
-----------------------------------------------------------------------------
-| 01-02 | register
-----------------------------------------------------------------------------
-|    03 | 0x01
-----------------------------------------------------------------------------
-|    04 | value
-----------------------------------------------------------------------------
-| 05-59 | don't care
-----------------------------------------------------------------------------
-|    60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | USB CONTROLLER REGISTER READ REQUEST PACKET
-============================================================================
-|    00 | 0xb0 register read command
-----------------------------------------------------------------------------
-| 01-02 | register
-----------------------------------------------------------------------------
-|    03 | 0x01
-----------------------------------------------------------------------------
-| 04-59 | don't care
-----------------------------------------------------------------------------
-|    60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | LED CONTROL REQUEST PACKET
-============================================================================
-|    00 | 0x16 LED and IR control command
-----------------------------------------------------------------------------
-|    01 | 0x01 (LED)
-----------------------------------------------------------------------------
-|    03 | 0x00 blink
-|       | 0x01 lights continuously
-----------------------------------------------------------------------------
-|    04 | blink interval
-|       | 0x00 fastest (looks like LED lights continuously)
-|       | 0xff slowest
-----------------------------------------------------------------------------
-| 05-59 | don't care
-----------------------------------------------------------------------------
-|    60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | IR CONTROL REQUEST PACKET
-============================================================================
-|    00 | 0x16 LED and IR control command
-----------------------------------------------------------------------------
-|    01 | 0x02 (IR)
-----------------------------------------------------------------------------
-|    03 | 0x00 IR disabled
-|       | 0x01 IR enabled
-----------------------------------------------------------------------------
-| 04-59 | don't care
-----------------------------------------------------------------------------
-|    60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | STREAMING CONTROL REQUEST PACKET
-============================================================================
-|    00 | 0x12 streaming control command
-----------------------------------------------------------------------------
-|    01 | 0x00 streaming disabled
-|       | 0x01 streaming enabled
-----------------------------------------------------------------------------
-|    02 | 0x00
-----------------------------------------------------------------------------
-| 03-59 | don't care
-----------------------------------------------------------------------------
-|    60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | REMOTE CONTROL REQUEST PACKET
-============================================================================
-|    00 | 0x41 remote control command
-----------------------------------------------------------------------------
-| 01-59 | don't care
-----------------------------------------------------------------------------
-|    60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | REMOTE CONTROL REPLY PACKET
-============================================================================
-|    00 | 0x00 code not received
-|       | 0x01 code received
-----------------------------------------------------------------------------
-|    01 | remote control code
-----------------------------------------------------------------------------
-| 02-59 | don't care
-----------------------------------------------------------------------------
-|    60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | GET HARDWARE INFO REQUEST PACKET
-============================================================================
-|    00 | 0x19 get hardware info command
-----------------------------------------------------------------------------
-| 01-59 | don't care
-----------------------------------------------------------------------------
-|    60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | GET HARDWARE INFO REPLY PACKET
-============================================================================
-|    00 | hardware id
-----------------------------------------------------------------------------
-| 01-02 | firmware version
-----------------------------------------------------------------------------
-| 03-59 | don't care
-----------------------------------------------------------------------------
-|    60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | SMART CARD READER PACKET
-============================================================================
-|    00 | 0x34 smart card reader command
-----------------------------------------------------------------------------
-|    xx |
-----------------------------------------------------------------------------
-| xx-59 | don't care
-----------------------------------------------------------------------------
-|    60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-*/
diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c
deleted file mode 100644
index 16210c0..0000000
--- a/drivers/media/dvb/dvb-usb/au6610.c
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
- *
- * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "au6610.h"
-#include "zl10353.h"
-#include "qt1010.h"
-
-/* debug */
-static int dvb_usb_au6610_debug;
-module_param_named(debug, dvb_usb_au6610_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
-			  u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
-{
-	int ret;
-	u16 index;
-	u8 *usb_buf;
-
-	/*
-	 * allocate enough for all known requests,
-	 * read returns 5 and write 6 bytes
-	 */
-	usb_buf = kmalloc(6, GFP_KERNEL);
-	if (!usb_buf)
-		return -ENOMEM;
-
-	switch (wlen) {
-	case 1:
-		index = wbuf[0] << 8;
-		break;
-	case 2:
-		index = wbuf[0] << 8;
-		index += wbuf[1];
-		break;
-	default:
-		warn("wlen = %x, aborting.", wlen);
-		ret = -EINVAL;
-		goto error;
-	}
-
-	ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
-			      USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index,
-			      usb_buf, 6, AU6610_USB_TIMEOUT);
-	if (ret < 0)
-		goto error;
-
-	switch (operation) {
-	case AU6610_REQ_I2C_READ:
-	case AU6610_REQ_USB_READ:
-		/* requested value is always 5th byte in buffer */
-		rbuf[0] = usb_buf[4];
-	}
-error:
-	kfree(usb_buf);
-	return ret;
-}
-
-static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr,
-			  u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
-{
-	u8 request;
-	u8 wo = (rbuf == NULL || rlen == 0); /* write-only */
-
-	if (wo) {
-		request = AU6610_REQ_I2C_WRITE;
-	} else { /* rw */
-		request = AU6610_REQ_I2C_READ;
-	}
-
-	return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen);
-}
-
-
-/* I2C */
-static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-			   int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int i;
-
-	if (num > 2)
-		return -EINVAL;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	for (i = 0; i < num; i++) {
-		/* write/read request */
-		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
-			if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
-					   msg[i].len, msg[i+1].buf,
-					   msg[i+1].len) < 0)
-				break;
-			i++;
-		} else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
-					       msg[i].len, NULL, 0) < 0)
-				break;
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return i;
-}
-
-
-static u32 au6610_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm au6610_i2c_algo = {
-	.master_xfer   = au6610_i2c_xfer,
-	.functionality = au6610_i2c_func,
-};
-
-/* Callbacks for DVB USB */
-static struct zl10353_config au6610_zl10353_config = {
-	.demod_address = 0x0f,
-	.no_tuner = 1,
-	.parallel_ts = 1,
-};
-
-static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
-		&adap->dev->i2c_adap);
-	if (adap->fe_adap[0].fe == NULL)
-		return -ENODEV;
-
-	return 0;
-}
-
-static struct qt1010_config au6610_qt1010_config = {
-	.i2c_address = 0x62
-};
-
-static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	return dvb_attach(qt1010_attach,
-			  adap->fe_adap[0].fe, &adap->dev->i2c_adap,
-			  &au6610_qt1010_config) == NULL ? -ENODEV : 0;
-}
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties au6610_properties;
-
-static int au6610_probe(struct usb_interface *intf,
-			const struct usb_device_id *id)
-{
-	struct dvb_usb_device *d;
-	struct usb_host_interface *alt;
-	int ret;
-
-	if (intf->num_altsetting < AU6610_ALTSETTING_COUNT)
-		return -ENODEV;
-
-	ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d,
-				  adapter_nr);
-	if (ret == 0) {
-		alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);
-
-		if (alt == NULL) {
-			deb_info("%s: no alt found!\n", __func__);
-			return -ENODEV;
-		}
-		ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
-					alt->desc.bAlternateSetting);
-	}
-
-	return ret;
-}
-
-static struct usb_device_id au6610_table [] = {
-	{ USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) },
-	{ }		/* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, au6610_table);
-
-static struct dvb_usb_device_properties au6610_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = DEVICE_SPECIFIC,
-
-	.size_of_priv = 0,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.frontend_attach  = au6610_zl10353_frontend_attach,
-			.tuner_attach     = au6610_qt1010_tuner_attach,
-
-			.stream = {
-				.type = USB_ISOC,
-				.count = 5,
-				.endpoint = 0x82,
-				.u = {
-					.isoc = {
-						.framesperurb = 40,
-						.framesize = 942,
-						.interval = 1,
-					}
-				}
-			},
-		}},
-		}
-	},
-
-	.i2c_algo = &au6610_i2c_algo,
-
-	.num_device_descs = 1,
-	.devices = {
-		{
-			.name = "Sigmatek DVB-110 DVB-T USB2.0",
-			.cold_ids = {NULL},
-			.warm_ids = {&au6610_table[0], NULL},
-		},
-	}
-};
-
-static struct usb_driver au6610_driver = {
-	.name       = "dvb_usb_au6610",
-	.probe      = au6610_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table   = au6610_table,
-};
-
-module_usb_driver(au6610_driver);
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0");
-MODULE_VERSION("0.1");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/au6610.h b/drivers/media/dvb/dvb-usb/au6610.h
deleted file mode 100644
index 7849abe..0000000
--- a/drivers/media/dvb/dvb-usb/au6610.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
- *
- * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _DVB_USB_AU6610_H_
-#define _DVB_USB_AU6610_H_
-
-#define DVB_USB_LOG_PREFIX "au6610"
-#include "dvb-usb.h"
-
-#define deb_info(args...)   dprintk(dvb_usb_au6610_debug, 0x01, args)
-
-#define AU6610_REQ_I2C_WRITE	0x14
-#define AU6610_REQ_I2C_READ	0x13
-#define AU6610_REQ_USB_WRITE	0x16
-#define AU6610_REQ_USB_READ	0x15
-
-#define AU6610_USB_TIMEOUT 1000
-
-#define AU6610_ALTSETTING_COUNT 6
-#define AU6610_ALTSETTING       5
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/az6007.c b/drivers/media/dvb/dvb-usb/az6007.c
deleted file mode 100644
index 86861e6..0000000
--- a/drivers/media/dvb/dvb-usb/az6007.c
+++ /dev/null
@@ -1,955 +0,0 @@
-/*
- * Driver for AzureWave 6007 DVB-C/T USB2.0 and clones
- *
- * Copyright (c) Henry Wang <Henry.wang@AzureWave.com>
- *
- * This driver was made publicly available by Terratec, at:
- *	http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
- * The original driver's license is GPL, as declared with MODULE_LICENSE()
- *
- * Copyright (c) 2010-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
- *	Driver modified by in order to work with upstream drxk driver, and
- *	tons of bugs got fixed.
- *
- * 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 under version 2 of the License.
- *
- * 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 "drxk.h"
-#include "mt2063.h"
-#include "dvb_ca_en50221.h"
-
-#define DVB_USB_LOG_PREFIX "az6007"
-#include "dvb-usb.h"
-
-/* debug */
-int dvb_usb_az6007_debug;
-module_param_named(debug, dvb_usb_az6007_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))."
-		 DVB_USB_DEBUG_STATUS);
-
-#define deb_info(args...) dprintk(dvb_usb_az6007_debug, 0x01, args)
-#define deb_xfer(args...) dprintk(dvb_usb_az6007_debug, 0x02, args)
-#define deb_rc(args...)   dprintk(dvb_usb_az6007_debug, 0x04, args)
-#define deb_fe(args...)   dprintk(dvb_usb_az6007_debug, 0x08, args)
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-/* Known requests (Cypress FX2 firmware + az6007 "private" ones*/
-
-#define FX2_OED			0xb5
-#define AZ6007_READ_DATA	0xb7
-#define AZ6007_I2C_RD		0xb9
-#define AZ6007_POWER		0xbc
-#define AZ6007_I2C_WR		0xbd
-#define FX2_SCON1		0xc0
-#define AZ6007_TS_THROUGH	0xc7
-#define AZ6007_READ_IR		0xb4
-
-struct az6007_device_state {
-	struct mutex		mutex;
-	struct mutex		ca_mutex;
-	struct dvb_ca_en50221	ca;
-	unsigned		warm:1;
-	int			(*gate_ctrl) (struct dvb_frontend *, int);
-	unsigned char		data[4096];
-};
-
-static struct drxk_config terratec_h7_drxk = {
-	.adr = 0x29,
-	.parallel_ts = true,
-	.dynamic_clk = true,
-	.single_master = true,
-	.enable_merr_cfg = true,
-	.no_i2c_bridge = false,
-	.chunk_size = 64,
-	.mpeg_out_clk_strength = 0x02,
-	.microcode_name = "dvb-usb-terratec-h7-drxk.fw",
-};
-
-static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct dvb_usb_adapter *adap = fe->sec_priv;
-	struct az6007_device_state *st;
-	int status = 0;
-
-	deb_info("%s: %s\n", __func__, enable ? "enable" : "disable");
-
-	if (!adap)
-		return -EINVAL;
-
-	st = adap->dev->priv;
-
-	if (!st)
-		return -EINVAL;
-
-	if (enable)
-		status = st->gate_ctrl(fe, 1);
-	else
-		status = st->gate_ctrl(fe, 0);
-
-	return status;
-}
-
-static struct mt2063_config az6007_mt2063_config = {
-	.tuner_address = 0x60,
-	.refclock = 36125000,
-};
-
-static int __az6007_read(struct usb_device *udev, u8 req, u16 value,
-			    u16 index, u8 *b, int blen)
-{
-	int ret;
-
-	ret = usb_control_msg(udev,
-			      usb_rcvctrlpipe(udev, 0),
-			      req,
-			      USB_TYPE_VENDOR | USB_DIR_IN,
-			      value, index, b, blen, 5000);
-	if (ret < 0) {
-		warn("usb read operation failed. (%d)", ret);
-		return -EIO;
-	}
-
-	deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value,
-		 index);
-	debug_dump(b, blen, deb_xfer);
-
-	return ret;
-}
-
-static int az6007_read(struct dvb_usb_device *d, u8 req, u16 value,
-			    u16 index, u8 *b, int blen)
-{
-	struct az6007_device_state *st = d->priv;
-	int ret;
-
-	if (mutex_lock_interruptible(&st->mutex) < 0)
-		return -EAGAIN;
-
-	ret = __az6007_read(d->udev, req, value, index, b, blen);
-
-	mutex_unlock(&st->mutex);
-
-	return ret;
-}
-
-static int __az6007_write(struct usb_device *udev, u8 req, u16 value,
-			     u16 index, u8 *b, int blen)
-{
-	int ret;
-
-	deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value,
-		 index);
-	debug_dump(b, blen, deb_xfer);
-
-	if (blen > 64) {
-		err("az6007: tried to write %d bytes, but I2C max size is 64 bytes\n",
-		    blen);
-		return -EOPNOTSUPP;
-	}
-
-	ret = usb_control_msg(udev,
-			      usb_sndctrlpipe(udev, 0),
-			      req,
-			      USB_TYPE_VENDOR | USB_DIR_OUT,
-			      value, index, b, blen, 5000);
-	if (ret != blen) {
-		err("usb write operation failed. (%d)", ret);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int az6007_write(struct dvb_usb_device *d, u8 req, u16 value,
-			    u16 index, u8 *b, int blen)
-{
-	struct az6007_device_state *st = d->priv;
-	int ret;
-
-	if (mutex_lock_interruptible(&st->mutex) < 0)
-		return -EAGAIN;
-
-	ret = __az6007_write(d->udev, req, value, index, b, blen);
-
-	mutex_unlock(&st->mutex);
-
-	return ret;
-}
-
-static int az6007_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	struct dvb_usb_device *d = adap->dev;
-
-	deb_info("%s: %s", __func__, onoff ? "enable" : "disable");
-
-	return az6007_write(d, 0xbc, onoff, 0, NULL, 0);
-}
-
-/* remote control stuff (does not work with my box) */
-static int az6007_rc_query(struct dvb_usb_device *d)
-{
-	struct az6007_device_state *st = d->priv;
-	unsigned code = 0;
-
-	az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10);
-
-	if (st->data[1] == 0x44)
-		return 0;
-
-	if ((st->data[1] ^ st->data[2]) == 0xff)
-		code = st->data[1];
-	else
-		code = st->data[1] << 8 | st->data[2];
-
-	if ((st->data[3] ^ st->data[4]) == 0xff)
-		code = code << 8 | st->data[3];
-	else
-		code = code << 16 | st->data[3] << 8 | st->data[4];
-
-	rc_keydown(d->rc_dev, code, st->data[5]);
-
-	return 0;
-}
-
-static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
-					int slot,
-					int address)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-	struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
-
-	int ret;
-	u8 req;
-	u16 value;
-	u16 index;
-	int blen;
-	u8 *b;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	b = kmalloc(12, GFP_KERNEL);
-	if (!b)
-		return -ENOMEM;
-
-	mutex_lock(&state->ca_mutex);
-
-	req = 0xC1;
-	value = address;
-	index = 0;
-	blen = 1;
-
-	ret = az6007_read(d, req, value, index, b, blen);
-	if (ret < 0) {
-		warn("usb in operation failed. (%d)", ret);
-		ret = -EINVAL;
-	} else {
-		ret = b[0];
-	}
-
-	mutex_unlock(&state->ca_mutex);
-	kfree(b);
-	return ret;
-}
-
-static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
-					 int slot,
-					 int address,
-					 u8 value)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-	struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
-
-	int ret;
-	u8 req;
-	u16 value1;
-	u16 index;
-	int blen;
-
-	deb_info("%s %d", __func__, slot);
-	if (slot != 0)
-		return -EINVAL;
-
-	mutex_lock(&state->ca_mutex);
-	req = 0xC2;
-	value1 = address;
-	index = value;
-	blen = 0;
-
-	ret = az6007_write(d, req, value1, index, NULL, blen);
-	if (ret != 0)
-		warn("usb out operation failed. (%d)", ret);
-
-	mutex_unlock(&state->ca_mutex);
-	return ret;
-}
-
-static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca,
-				      int slot,
-				      u8 address)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-	struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
-
-	int ret;
-	u8 req;
-	u16 value;
-	u16 index;
-	int blen;
-	u8 *b;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	b = kmalloc(12, GFP_KERNEL);
-	if (!b)
-		return -ENOMEM;
-
-	mutex_lock(&state->ca_mutex);
-
-	req = 0xC3;
-	value = address;
-	index = 0;
-	blen = 2;
-
-	ret = az6007_read(d, req, value, index, b, blen);
-	if (ret < 0) {
-		warn("usb in operation failed. (%d)", ret);
-		ret = -EINVAL;
-	} else {
-		if (b[0] == 0)
-			warn("Read CI IO error");
-
-		ret = b[1];
-		deb_info("read cam data = %x from 0x%x", b[1], value);
-	}
-
-	mutex_unlock(&state->ca_mutex);
-	kfree(b);
-	return ret;
-}
-
-static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca,
-				       int slot,
-				       u8 address,
-				       u8 value)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-	struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
-
-	int ret;
-	u8 req;
-	u16 value1;
-	u16 index;
-	int blen;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	mutex_lock(&state->ca_mutex);
-	req = 0xC4;
-	value1 = address;
-	index = value;
-	blen = 0;
-
-	ret = az6007_write(d, req, value1, index, NULL, blen);
-	if (ret != 0) {
-		warn("usb out operation failed. (%d)", ret);
-		goto failed;
-	}
-
-failed:
-	mutex_unlock(&state->ca_mutex);
-	return ret;
-}
-
-static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-
-	int ret;
-	u8 req;
-	u16 value;
-	u16 index;
-	int blen;
-	u8 *b;
-
-	b = kmalloc(12, GFP_KERNEL);
-	if (!b)
-		return -ENOMEM;
-
-	req = 0xC8;
-	value = 0;
-	index = 0;
-	blen = 1;
-
-	ret = az6007_read(d, req, value, index, b, blen);
-	if (ret < 0) {
-		warn("usb in operation failed. (%d)", ret);
-		ret = -EIO;
-	} else{
-		ret = b[0];
-	}
-	kfree(b);
-	return ret;
-}
-
-static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-	struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
-
-	int ret, i;
-	u8 req;
-	u16 value;
-	u16 index;
-	int blen;
-
-	mutex_lock(&state->ca_mutex);
-
-	req = 0xC6;
-	value = 1;
-	index = 0;
-	blen = 0;
-
-	ret = az6007_write(d, req, value, index, NULL, blen);
-	if (ret != 0) {
-		warn("usb out operation failed. (%d)", ret);
-		goto failed;
-	}
-
-	msleep(500);
-	req = 0xC6;
-	value = 0;
-	index = 0;
-	blen = 0;
-
-	ret = az6007_write(d, req, value, index, NULL, blen);
-	if (ret != 0) {
-		warn("usb out operation failed. (%d)", ret);
-		goto failed;
-	}
-
-	for (i = 0; i < 15; i++) {
-		msleep(100);
-
-		if (CI_CamReady(ca, slot)) {
-			deb_info("CAM Ready");
-			break;
-		}
-	}
-	msleep(5000);
-
-failed:
-	mutex_unlock(&state->ca_mutex);
-	return ret;
-}
-
-static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
-{
-	return 0;
-}
-
-static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-	struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
-
-	int ret;
-	u8 req;
-	u16 value;
-	u16 index;
-	int blen;
-
-	deb_info("%s", __func__);
-	mutex_lock(&state->ca_mutex);
-	req = 0xC7;
-	value = 1;
-	index = 0;
-	blen = 0;
-
-	ret = az6007_write(d, req, value, index, NULL, blen);
-	if (ret != 0) {
-		warn("usb out operation failed. (%d)", ret);
-		goto failed;
-	}
-
-failed:
-	mutex_unlock(&state->ca_mutex);
-	return ret;
-}
-
-static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-	struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
-	int ret;
-	u8 req;
-	u16 value;
-	u16 index;
-	int blen;
-	u8 *b;
-
-	b = kmalloc(12, GFP_KERNEL);
-	if (!b)
-		return -ENOMEM;
-	mutex_lock(&state->ca_mutex);
-
-	req = 0xC5;
-	value = 0;
-	index = 0;
-	blen = 1;
-
-	ret = az6007_read(d, req, value, index, b, blen);
-	if (ret < 0) {
-		warn("usb in operation failed. (%d)", ret);
-		ret = -EIO;
-	} else
-		ret = 0;
-
-	if (!ret && b[0] == 1) {
-		ret = DVB_CA_EN50221_POLL_CAM_PRESENT |
-		      DVB_CA_EN50221_POLL_CAM_READY;
-	}
-
-	mutex_unlock(&state->ca_mutex);
-	kfree(b);
-	return ret;
-}
-
-
-static void az6007_ci_uninit(struct dvb_usb_device *d)
-{
-	struct az6007_device_state *state;
-
-	deb_info("%s", __func__);
-
-	if (NULL == d)
-		return;
-
-	state = (struct az6007_device_state *)d->priv;
-	if (NULL == state)
-		return;
-
-	if (NULL == state->ca.data)
-		return;
-
-	dvb_ca_en50221_release(&state->ca);
-
-	memset(&state->ca, 0, sizeof(state->ca));
-}
-
-
-static int az6007_ci_init(struct dvb_usb_adapter *a)
-{
-	struct dvb_usb_device *d = a->dev;
-	struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
-	int ret;
-
-	deb_info("%s", __func__);
-
-	mutex_init(&state->ca_mutex);
-
-	state->ca.owner			= THIS_MODULE;
-	state->ca.read_attribute_mem	= az6007_ci_read_attribute_mem;
-	state->ca.write_attribute_mem	= az6007_ci_write_attribute_mem;
-	state->ca.read_cam_control	= az6007_ci_read_cam_control;
-	state->ca.write_cam_control	= az6007_ci_write_cam_control;
-	state->ca.slot_reset		= az6007_ci_slot_reset;
-	state->ca.slot_shutdown		= az6007_ci_slot_shutdown;
-	state->ca.slot_ts_enable	= az6007_ci_slot_ts_enable;
-	state->ca.poll_slot_status	= az6007_ci_poll_slot_status;
-	state->ca.data			= d;
-
-	ret = dvb_ca_en50221_init(&a->dvb_adap,
-				  &state->ca,
-				  0, /* flags */
-				  1);/* n_slots */
-	if (ret != 0) {
-		err("Cannot initialize CI: Error %d.", ret);
-		memset(&state->ca, 0, sizeof(state->ca));
-		return ret;
-	}
-
-	deb_info("CI initialized.");
-
-	return 0;
-}
-
-static int az6007_read_mac_addr(struct dvb_usb_device *d, u8 mac[6])
-{
-	struct az6007_device_state *st = d->priv;
-	int ret;
-
-	ret = az6007_read(d, AZ6007_READ_DATA, 6, 0, st->data, 6);
-	memcpy(mac, st->data, 6);
-
-	if (ret > 0)
-		deb_info("%s: mac is %pM\n", __func__, mac);
-
-	return ret;
-}
-
-static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct az6007_device_state *st = adap->dev->priv;
-
-	deb_info("attaching demod drxk");
-
-	adap->fe_adap[0].fe = dvb_attach(drxk_attach, &terratec_h7_drxk,
-					 &adap->dev->i2c_adap);
-	if (!adap->fe_adap[0].fe)
-		return -EINVAL;
-
-	adap->fe_adap[0].fe->sec_priv = adap;
-	st->gate_ctrl = adap->fe_adap[0].fe->ops.i2c_gate_ctrl;
-	adap->fe_adap[0].fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
-
-	az6007_ci_init(adap);
-
-	return 0;
-}
-
-static int az6007_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	deb_info("attaching tuner mt2063");
-
-	/* Attach mt2063 to DVB-C frontend */
-	if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
-		adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1);
-	if (!dvb_attach(mt2063_attach, adap->fe_adap[0].fe,
-			&az6007_mt2063_config,
-			&adap->dev->i2c_adap))
-		return -EINVAL;
-
-	if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
-		adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0);
-
-	return 0;
-}
-
-int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	struct az6007_device_state *st = d->priv;
-	int ret;
-
-	deb_info("%s()\n", __func__);
-
-	if (!st->warm) {
-		mutex_init(&st->mutex);
-
-		ret = az6007_write(d, AZ6007_POWER, 0, 2, NULL, 0);
-		if (ret < 0)
-			return ret;
-		msleep(60);
-		ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0);
-		if (ret < 0)
-			return ret;
-		msleep(100);
-		ret = az6007_write(d, AZ6007_POWER, 1, 3, NULL, 0);
-		if (ret < 0)
-			return ret;
-		msleep(20);
-		ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0);
-		if (ret < 0)
-			return ret;
-
-		msleep(400);
-		ret = az6007_write(d, FX2_SCON1, 0, 3, NULL, 0);
-		if (ret < 0)
-			return ret;
-		msleep(150);
-		ret = az6007_write(d, FX2_SCON1, 1, 3, NULL, 0);
-		if (ret < 0)
-			return ret;
-		msleep(430);
-		ret = az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0);
-		if (ret < 0)
-			return ret;
-
-		st->warm = true;
-
-		return 0;
-	}
-
-	if (!onoff)
-		return 0;
-
-	az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0);
-	az6007_write(d, AZ6007_TS_THROUGH, 0, 0, NULL, 0);
-
-	return 0;
-}
-
-/* I2C */
-static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
-			   int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	struct az6007_device_state *st = d->priv;
-	int i, j, len;
-	int ret = 0;
-	u16 index;
-	u16 value;
-	int length;
-	u8 req, addr;
-
-	if (mutex_lock_interruptible(&st->mutex) < 0)
-		return -EAGAIN;
-
-	for (i = 0; i < num; i++) {
-		addr = msgs[i].addr << 1;
-		if (((i + 1) < num)
-		    && (msgs[i].len == 1)
-		    && (!msgs[i].flags & I2C_M_RD)
-		    && (msgs[i + 1].flags & I2C_M_RD)
-		    && (msgs[i].addr == msgs[i + 1].addr)) {
-			/*
-			 * A write + read xfer for the same address, where
-			 * the first xfer has just 1 byte length.
-			 * Need to join both into one operation
-			 */
-			if (dvb_usb_az6007_debug & 2)
-				printk(KERN_DEBUG
-				       "az6007 I2C xfer write+read addr=0x%x len=%d/%d: ",
-				       addr, msgs[i].len, msgs[i + 1].len);
-			req = AZ6007_I2C_RD;
-			index = msgs[i].buf[0];
-			value = addr | (1 << 8);
-			length = 6 + msgs[i + 1].len;
-			len = msgs[i + 1].len;
-			ret = __az6007_read(d->udev, req, value, index,
-					    st->data, length);
-			if (ret >= len) {
-				for (j = 0; j < len; j++) {
-					msgs[i + 1].buf[j] = st->data[j + 5];
-					if (dvb_usb_az6007_debug & 2)
-						printk(KERN_CONT
-						       "0x%02x ",
-						       msgs[i + 1].buf[j]);
-				}
-			} else
-				ret = -EIO;
-			i++;
-		} else if (!(msgs[i].flags & I2C_M_RD)) {
-			/* write bytes */
-			if (dvb_usb_az6007_debug & 2)
-				printk(KERN_DEBUG
-				       "az6007 I2C xfer write addr=0x%x len=%d: ",
-				       addr, msgs[i].len);
-			req = AZ6007_I2C_WR;
-			index = msgs[i].buf[0];
-			value = addr | (1 << 8);
-			length = msgs[i].len - 1;
-			len = msgs[i].len - 1;
-			if (dvb_usb_az6007_debug & 2)
-				printk(KERN_CONT "(0x%02x) ", msgs[i].buf[0]);
-			for (j = 0; j < len; j++) {
-				st->data[j] = msgs[i].buf[j + 1];
-				if (dvb_usb_az6007_debug & 2)
-					printk(KERN_CONT "0x%02x ",
-					       st->data[j]);
-			}
-			ret =  __az6007_write(d->udev, req, value, index,
-					      st->data, length);
-		} else {
-			/* read bytes */
-			if (dvb_usb_az6007_debug & 2)
-				printk(KERN_DEBUG
-				       "az6007 I2C xfer read addr=0x%x len=%d: ",
-				       addr, msgs[i].len);
-			req = AZ6007_I2C_RD;
-			index = msgs[i].buf[0];
-			value = addr;
-			length = msgs[i].len + 6;
-			len = msgs[i].len;
-			ret = __az6007_read(d->udev, req, value, index,
-					    st->data, length);
-			for (j = 0; j < len; j++) {
-				msgs[i].buf[j] = st->data[j + 5];
-				if (dvb_usb_az6007_debug & 2)
-					printk(KERN_CONT
-					       "0x%02x ", st->data[j + 5]);
-			}
-		}
-		if (dvb_usb_az6007_debug & 2)
-			printk(KERN_CONT "\n");
-		if (ret < 0)
-			goto err;
-	}
-err:
-	mutex_unlock(&st->mutex);
-
-	if (ret < 0) {
-		info("%s ERROR: %i", __func__, ret);
-		return ret;
-	}
-	return num;
-}
-
-static u32 az6007_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm az6007_i2c_algo = {
-	.master_xfer = az6007_i2c_xfer,
-	.functionality = az6007_i2c_func,
-};
-
-int az6007_identify_state(struct usb_device *udev,
-			  struct dvb_usb_device_properties *props,
-			  struct dvb_usb_device_description **desc, int *cold)
-{
-	int ret;
-	u8 *mac;
-
-	mac = kmalloc(6, GFP_ATOMIC);
-	if (!mac)
-		return -ENOMEM;
-
-	/* Try to read the mac address */
-	ret = __az6007_read(udev, AZ6007_READ_DATA, 6, 0, mac, 6);
-	if (ret == 6)
-		*cold = 0;
-	else
-		*cold = 1;
-
-	kfree(mac);
-
-	if (*cold) {
-		__az6007_write(udev, 0x09, 1, 0, NULL, 0);
-		__az6007_write(udev, 0x00, 0, 0, NULL, 0);
-		__az6007_write(udev, 0x00, 0, 0, NULL, 0);
-	}
-
-	deb_info("Device is on %s state\n", *cold ? "warm" : "cold");
-	return 0;
-}
-
-static struct dvb_usb_device_properties az6007_properties;
-
-static void az6007_usb_disconnect(struct usb_interface *intf)
-{
-	struct dvb_usb_device *d = usb_get_intfdata(intf);
-	az6007_ci_uninit(d);
-	dvb_usb_device_exit(intf);
-}
-
-static int az6007_usb_probe(struct usb_interface *intf,
-			    const struct usb_device_id *id)
-{
-	return dvb_usb_device_init(intf, &az6007_properties,
-				   THIS_MODULE, NULL, adapter_nr);
-}
-
-static struct usb_device_id az6007_usb_table[] = {
-	{USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007)},
-	{USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7)},
-	{USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2)},
-	{0},
-};
-
-MODULE_DEVICE_TABLE(usb, az6007_usb_table);
-
-static struct dvb_usb_device_properties az6007_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware            = "dvb-usb-terratec-h7-az6007.fw",
-	.no_reconnect        = 1,
-	.size_of_priv        = sizeof(struct az6007_device_state),
-	.identify_state	     = az6007_identify_state,
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = az6007_streaming_ctrl,
-			.tuner_attach     = az6007_tuner_attach,
-			.frontend_attach  = az6007_frontend_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 10,
-				.endpoint = 0x02,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		} }
-	} },
-	.power_ctrl       = az6007_power_ctrl,
-	.read_mac_address = az6007_read_mac_addr,
-
-	.rc.core = {
-		.rc_interval      = 400,
-		.rc_codes         = RC_MAP_NEC_TERRATEC_CINERGY_XS,
-		.module_name	  = "az6007",
-		.rc_query         = az6007_rc_query,
-		.allowed_protos   = RC_TYPE_NEC,
-	},
-	.i2c_algo         = &az6007_i2c_algo,
-
-	.num_device_descs = 2,
-	.devices = {
-		{ .name = "AzureWave DTV StarBox DVB-T/C USB2.0 (az6007)",
-		  .cold_ids = { &az6007_usb_table[0], NULL },
-		  .warm_ids = { NULL },
-		},
-		{ .name = "TerraTec DTV StarBox DVB-T/C USB2.0 (az6007)",
-		  .cold_ids = { &az6007_usb_table[1], &az6007_usb_table[2], NULL },
-		  .warm_ids = { NULL },
-		},
-		{ NULL },
-	}
-};
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver az6007_usb_driver = {
-	.name		= "dvb_usb_az6007",
-	.probe		= az6007_usb_probe,
-	.disconnect	= az6007_usb_disconnect,
-	.id_table	= az6007_usb_table,
-};
-
-/* module stuff */
-static int __init az6007_usb_module_init(void)
-{
-	int result;
-	deb_info("az6007 usb module init\n");
-
-	result = usb_register(&az6007_usb_driver);
-	if (result) {
-		err("usb_register failed. (%d)", result);
-		return result;
-	}
-
-	return 0;
-}
-
-static void __exit az6007_usb_module_exit(void)
-{
-	/* deregister this driver from the USB subsystem */
-	deb_info("az6007 usb module exit\n");
-	usb_deregister(&az6007_usb_driver);
-}
-
-module_init(az6007_usb_module_init);
-module_exit(az6007_usb_module_exit);
-
-MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones");
-MODULE_VERSION("1.1");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/az6027.c b/drivers/media/dvb/dvb-usb/az6027.c
deleted file mode 100644
index 5e45ae6..0000000
--- a/drivers/media/dvb/dvb-usb/az6027.c
+++ /dev/null
@@ -1,1182 +0,0 @@
-/* DVB USB compliant Linux driver for the AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)
- * receiver.
- *
- * Copyright (C) 2009 Adams.Xu <adams.xu@azwave.com.cn>
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "az6027.h"
-
-#include "stb0899_drv.h"
-#include "stb0899_reg.h"
-#include "stb0899_cfg.h"
-
-#include "stb6100.h"
-#include "stb6100_cfg.h"
-#include "dvb_ca_en50221.h"
-
-int dvb_usb_az6027_debug;
-module_param_named(debug, dvb_usb_az6027_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-struct az6027_device_state {
-	struct dvb_ca_en50221 ca;
-	struct mutex ca_mutex;
-	u8 power_state;
-};
-
-static const struct stb0899_s1_reg az6027_stb0899_s1_init_1[] = {
-
-	/* 0x0000000b, SYSREG */
-	{ STB0899_DEV_ID		, 0x30 },
-	{ STB0899_DISCNTRL1		, 0x32 },
-	{ STB0899_DISCNTRL2     	, 0x80 },
-	{ STB0899_DISRX_ST0     	, 0x04 },
-	{ STB0899_DISRX_ST1     	, 0x00 },
-	{ STB0899_DISPARITY     	, 0x00 },
-	{ STB0899_DISSTATUS		, 0x20 },
-	{ STB0899_DISF22        	, 0x99 },
-	{ STB0899_DISF22RX      	, 0xa8 },
-	/* SYSREG ? */
-	{ STB0899_ACRPRESC      	, 0x11 },
-	{ STB0899_ACRDIV1       	, 0x0a },
-	{ STB0899_ACRDIV2       	, 0x05 },
-	{ STB0899_DACR1         	, 0x00 },
-	{ STB0899_DACR2         	, 0x00 },
-	{ STB0899_OUTCFG        	, 0x00 },
-	{ STB0899_MODECFG       	, 0x00 },
-	{ STB0899_IRQSTATUS_3		, 0xfe },
-	{ STB0899_IRQSTATUS_2		, 0x03 },
-	{ STB0899_IRQSTATUS_1		, 0x7c },
-	{ STB0899_IRQSTATUS_0		, 0xf4 },
-	{ STB0899_IRQMSK_3      	, 0xf3 },
-	{ STB0899_IRQMSK_2      	, 0xfc },
-	{ STB0899_IRQMSK_1      	, 0xff },
-	{ STB0899_IRQMSK_0		, 0xff },
-	{ STB0899_IRQCFG		, 0x00 },
-	{ STB0899_I2CCFG        	, 0x88 },
-	{ STB0899_I2CRPT        	, 0x58 },
-	{ STB0899_IOPVALUE5		, 0x00 },
-	{ STB0899_IOPVALUE4		, 0x33 },
-	{ STB0899_IOPVALUE3		, 0x6d },
-	{ STB0899_IOPVALUE2		, 0x90 },
-	{ STB0899_IOPVALUE1		, 0x60 },
-	{ STB0899_IOPVALUE0		, 0x00 },
-	{ STB0899_GPIO00CFG     	, 0x82 },
-	{ STB0899_GPIO01CFG     	, 0x82 },
-	{ STB0899_GPIO02CFG     	, 0x82 },
-	{ STB0899_GPIO03CFG     	, 0x82 },
-	{ STB0899_GPIO04CFG     	, 0x82 },
-	{ STB0899_GPIO05CFG     	, 0x82 },
-	{ STB0899_GPIO06CFG     	, 0x82 },
-	{ STB0899_GPIO07CFG     	, 0x82 },
-	{ STB0899_GPIO08CFG     	, 0x82 },
-	{ STB0899_GPIO09CFG     	, 0x82 },
-	{ STB0899_GPIO10CFG     	, 0x82 },
-	{ STB0899_GPIO11CFG     	, 0x82 },
-	{ STB0899_GPIO12CFG     	, 0x82 },
-	{ STB0899_GPIO13CFG     	, 0x82 },
-	{ STB0899_GPIO14CFG     	, 0x82 },
-	{ STB0899_GPIO15CFG     	, 0x82 },
-	{ STB0899_GPIO16CFG     	, 0x82 },
-	{ STB0899_GPIO17CFG     	, 0x82 },
-	{ STB0899_GPIO18CFG     	, 0x82 },
-	{ STB0899_GPIO19CFG     	, 0x82 },
-	{ STB0899_GPIO20CFG     	, 0x82 },
-	{ STB0899_SDATCFG       	, 0xb8 },
-	{ STB0899_SCLTCFG       	, 0xba },
-	{ STB0899_AGCRFCFG      	, 0x1c }, /* 0x11 */
-	{ STB0899_GPIO22        	, 0x82 }, /* AGCBB2CFG */
-	{ STB0899_GPIO21        	, 0x91 }, /* AGCBB1CFG */
-	{ STB0899_DIRCLKCFG     	, 0x82 },
-	{ STB0899_CLKOUT27CFG   	, 0x7e },
-	{ STB0899_STDBYCFG      	, 0x82 },
-	{ STB0899_CS0CFG        	, 0x82 },
-	{ STB0899_CS1CFG        	, 0x82 },
-	{ STB0899_DISEQCOCFG    	, 0x20 },
-	{ STB0899_GPIO32CFG		, 0x82 },
-	{ STB0899_GPIO33CFG		, 0x82 },
-	{ STB0899_GPIO34CFG		, 0x82 },
-	{ STB0899_GPIO35CFG		, 0x82 },
-	{ STB0899_GPIO36CFG		, 0x82 },
-	{ STB0899_GPIO37CFG		, 0x82 },
-	{ STB0899_GPIO38CFG		, 0x82 },
-	{ STB0899_GPIO39CFG		, 0x82 },
-	{ STB0899_NCOARSE       	, 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
-	{ STB0899_SYNTCTRL      	, 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
-	{ STB0899_FILTCTRL      	, 0x00 },
-	{ STB0899_SYSCTRL       	, 0x01 },
-	{ STB0899_STOPCLK1      	, 0x20 },
-	{ STB0899_STOPCLK2      	, 0x00 },
-	{ STB0899_INTBUFSTATUS		, 0x00 },
-	{ STB0899_INTBUFCTRL    	, 0x0a },
-	{ 0xffff			, 0xff },
-};
-
-static const struct stb0899_s1_reg az6027_stb0899_s1_init_3[] = {
-	{ STB0899_DEMOD         	, 0x00 },
-	{ STB0899_RCOMPC        	, 0xc9 },
-	{ STB0899_AGC1CN        	, 0x01 },
-	{ STB0899_AGC1REF       	, 0x10 },
-	{ STB0899_RTC			, 0x23 },
-	{ STB0899_TMGCFG        	, 0x4e },
-	{ STB0899_AGC2REF       	, 0x34 },
-	{ STB0899_TLSR          	, 0x84 },
-	{ STB0899_CFD           	, 0xf7 },
-	{ STB0899_ACLC			, 0x87 },
-	{ STB0899_BCLC          	, 0x94 },
-	{ STB0899_EQON          	, 0x41 },
-	{ STB0899_LDT           	, 0xf1 },
-	{ STB0899_LDT2          	, 0xe3 },
-	{ STB0899_EQUALREF      	, 0xb4 },
-	{ STB0899_TMGRAMP       	, 0x10 },
-	{ STB0899_TMGTHD        	, 0x30 },
-	{ STB0899_IDCCOMP		, 0xfd },
-	{ STB0899_QDCCOMP		, 0xff },
-	{ STB0899_POWERI		, 0x0c },
-	{ STB0899_POWERQ		, 0x0f },
-	{ STB0899_RCOMP			, 0x6c },
-	{ STB0899_AGCIQIN		, 0x80 },
-	{ STB0899_AGC2I1		, 0x06 },
-	{ STB0899_AGC2I2		, 0x00 },
-	{ STB0899_TLIR			, 0x30 },
-	{ STB0899_RTF			, 0x7f },
-	{ STB0899_DSTATUS		, 0x00 },
-	{ STB0899_LDI			, 0xbc },
-	{ STB0899_CFRM			, 0xea },
-	{ STB0899_CFRL			, 0x31 },
-	{ STB0899_NIRM			, 0x2b },
-	{ STB0899_NIRL			, 0x80 },
-	{ STB0899_ISYMB			, 0x1d },
-	{ STB0899_QSYMB			, 0xa6 },
-	{ STB0899_SFRH          	, 0x2f },
-	{ STB0899_SFRM          	, 0x68 },
-	{ STB0899_SFRL          	, 0x40 },
-	{ STB0899_SFRUPH        	, 0x2f },
-	{ STB0899_SFRUPM        	, 0x68 },
-	{ STB0899_SFRUPL        	, 0x40 },
-	{ STB0899_EQUAI1		, 0x02 },
-	{ STB0899_EQUAQ1		, 0xff },
-	{ STB0899_EQUAI2		, 0x04 },
-	{ STB0899_EQUAQ2		, 0x05 },
-	{ STB0899_EQUAI3		, 0x02 },
-	{ STB0899_EQUAQ3		, 0xfd },
-	{ STB0899_EQUAI4		, 0x03 },
-	{ STB0899_EQUAQ4		, 0x07 },
-	{ STB0899_EQUAI5		, 0x08 },
-	{ STB0899_EQUAQ5		, 0xf5 },
-	{ STB0899_DSTATUS2		, 0x00 },
-	{ STB0899_VSTATUS       	, 0x00 },
-	{ STB0899_VERROR		, 0x86 },
-	{ STB0899_IQSWAP		, 0x2a },
-	{ STB0899_ECNT1M		, 0x00 },
-	{ STB0899_ECNT1L		, 0x00 },
-	{ STB0899_ECNT2M		, 0x00 },
-	{ STB0899_ECNT2L		, 0x00 },
-	{ STB0899_ECNT3M		, 0x0a },
-	{ STB0899_ECNT3L		, 0xad },
-	{ STB0899_FECAUTO1      	, 0x06 },
-	{ STB0899_FECM			, 0x01 },
-	{ STB0899_VTH12         	, 0xb0 },
-	{ STB0899_VTH23         	, 0x7a },
-	{ STB0899_VTH34			, 0x58 },
-	{ STB0899_VTH56         	, 0x38 },
-	{ STB0899_VTH67         	, 0x34 },
-	{ STB0899_VTH78         	, 0x24 },
-	{ STB0899_PRVIT         	, 0xff },
-	{ STB0899_VITSYNC       	, 0x19 },
-	{ STB0899_RSULC         	, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
-	{ STB0899_TSULC         	, 0x42 },
-	{ STB0899_RSLLC         	, 0x41 },
-	{ STB0899_TSLPL			, 0x12 },
-	{ STB0899_TSCFGH        	, 0x0c },
-	{ STB0899_TSCFGM        	, 0x00 },
-	{ STB0899_TSCFGL        	, 0x00 },
-	{ STB0899_TSOUT			, 0x69 }, /* 0x0d for CAM */
-	{ STB0899_RSSYNCDEL     	, 0x00 },
-	{ STB0899_TSINHDELH     	, 0x02 },
-	{ STB0899_TSINHDELM		, 0x00 },
-	{ STB0899_TSINHDELL		, 0x00 },
-	{ STB0899_TSLLSTKM		, 0x1b },
-	{ STB0899_TSLLSTKL		, 0xb3 },
-	{ STB0899_TSULSTKM		, 0x00 },
-	{ STB0899_TSULSTKL		, 0x00 },
-	{ STB0899_PCKLENUL		, 0xbc },
-	{ STB0899_PCKLENLL		, 0xcc },
-	{ STB0899_RSPCKLEN		, 0xbd },
-	{ STB0899_TSSTATUS		, 0x90 },
-	{ STB0899_ERRCTRL1      	, 0xb6 },
-	{ STB0899_ERRCTRL2      	, 0x95 },
-	{ STB0899_ERRCTRL3      	, 0x8d },
-	{ STB0899_DMONMSK1		, 0x27 },
-	{ STB0899_DMONMSK0		, 0x03 },
-	{ STB0899_DEMAPVIT      	, 0x5c },
-	{ STB0899_PLPARM		, 0x19 },
-	{ STB0899_PDELCTRL      	, 0x48 },
-	{ STB0899_PDELCTRL2     	, 0x00 },
-	{ STB0899_BBHCTRL1      	, 0x00 },
-	{ STB0899_BBHCTRL2      	, 0x00 },
-	{ STB0899_HYSTTHRESH    	, 0x77 },
-	{ STB0899_MATCSTM		, 0x00 },
-	{ STB0899_MATCSTL		, 0x00 },
-	{ STB0899_UPLCSTM		, 0x00 },
-	{ STB0899_UPLCSTL		, 0x00 },
-	{ STB0899_DFLCSTM		, 0x00 },
-	{ STB0899_DFLCSTL		, 0x00 },
-	{ STB0899_SYNCCST		, 0x00 },
-	{ STB0899_SYNCDCSTM		, 0x00 },
-	{ STB0899_SYNCDCSTL		, 0x00 },
-	{ STB0899_ISI_ENTRY		, 0x00 },
-	{ STB0899_ISI_BIT_EN		, 0x00 },
-	{ STB0899_MATSTRM		, 0xf0 },
-	{ STB0899_MATSTRL		, 0x02 },
-	{ STB0899_UPLSTRM		, 0x45 },
-	{ STB0899_UPLSTRL		, 0x60 },
-	{ STB0899_DFLSTRM		, 0xe3 },
-	{ STB0899_DFLSTRL		, 0x00 },
-	{ STB0899_SYNCSTR		, 0x47 },
-	{ STB0899_SYNCDSTRM		, 0x05 },
-	{ STB0899_SYNCDSTRL		, 0x18 },
-	{ STB0899_CFGPDELSTATUS1	, 0x19 },
-	{ STB0899_CFGPDELSTATUS2	, 0x2b },
-	{ STB0899_BBFERRORM		, 0x00 },
-	{ STB0899_BBFERRORL		, 0x01 },
-	{ STB0899_UPKTERRORM		, 0x00 },
-	{ STB0899_UPKTERRORL		, 0x00 },
-	{ 0xffff			, 0xff },
-};
-
-
-
-struct stb0899_config az6027_stb0899_config = {
-	.init_dev		= az6027_stb0899_s1_init_1,
-	.init_s2_demod		= stb0899_s2_init_2,
-	.init_s1_demod		= az6027_stb0899_s1_init_3,
-	.init_s2_fec		= stb0899_s2_init_4,
-	.init_tst		= stb0899_s1_init_5,
-
-	.demod_address 		= 0xd0, /* 0x68, 0xd0 >> 1 */
-
-	.xtal_freq		= 27000000,
-	.inversion		= IQ_SWAP_ON, /* 1 */
-
-	.lo_clk			= 76500000,
-	.hi_clk			= 99000000,
-
-	.esno_ave		= STB0899_DVBS2_ESNO_AVE,
-	.esno_quant		= STB0899_DVBS2_ESNO_QUANT,
-	.avframes_coarse	= STB0899_DVBS2_AVFRAMES_COARSE,
-	.avframes_fine		= STB0899_DVBS2_AVFRAMES_FINE,
-	.miss_threshold		= STB0899_DVBS2_MISS_THRESHOLD,
-	.uwp_threshold_acq	= STB0899_DVBS2_UWP_THRESHOLD_ACQ,
-	.uwp_threshold_track	= STB0899_DVBS2_UWP_THRESHOLD_TRACK,
-	.uwp_threshold_sof	= STB0899_DVBS2_UWP_THRESHOLD_SOF,
-	.sof_search_timeout	= STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
-
-	.btr_nco_bits		= STB0899_DVBS2_BTR_NCO_BITS,
-	.btr_gain_shift_offset	= STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
-	.crl_nco_bits		= STB0899_DVBS2_CRL_NCO_BITS,
-	.ldpc_max_iter		= STB0899_DVBS2_LDPC_MAX_ITER,
-
-	.tuner_get_frequency	= stb6100_get_frequency,
-	.tuner_set_frequency	= stb6100_set_frequency,
-	.tuner_set_bandwidth	= stb6100_set_bandwidth,
-	.tuner_get_bandwidth	= stb6100_get_bandwidth,
-	.tuner_set_rfsiggain	= NULL,
-};
-
-struct stb6100_config az6027_stb6100_config = {
-	.tuner_address	= 0xc0,
-	.refclock	= 27000000,
-};
-
-
-/* check for mutex FIXME */
-int az6027_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
-{
-	int ret = -1;
-	if (mutex_lock_interruptible(&d->usb_mutex))
-		return -EAGAIN;
-
-	ret = usb_control_msg(d->udev,
-			      usb_rcvctrlpipe(d->udev, 0),
-			      req,
-			      USB_TYPE_VENDOR | USB_DIR_IN,
-			      value,
-			      index,
-			      b,
-			      blen,
-			      2000);
-
-	if (ret < 0) {
-		warn("usb in operation failed. (%d)", ret);
-		ret = -EIO;
-	} else
-		ret = 0;
-
-	deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index);
-	debug_dump(b, blen, deb_xfer);
-
-	mutex_unlock(&d->usb_mutex);
-	return ret;
-}
-
-static int az6027_usb_out_op(struct dvb_usb_device *d,
-			     u8 req,
-			     u16 value,
-			     u16 index,
-			     u8 *b,
-			     int blen)
-{
-	int ret;
-
-	deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index);
-	debug_dump(b, blen, deb_xfer);
-
-	if (mutex_lock_interruptible(&d->usb_mutex))
-		return -EAGAIN;
-
-	ret = usb_control_msg(d->udev,
-			      usb_sndctrlpipe(d->udev, 0),
-			      req,
-			      USB_TYPE_VENDOR | USB_DIR_OUT,
-			      value,
-			      index,
-			      b,
-			      blen,
-			      2000);
-
-	if (ret != blen) {
-		warn("usb out operation failed. (%d)", ret);
-		mutex_unlock(&d->usb_mutex);
-		return -EIO;
-	} else{
-		mutex_unlock(&d->usb_mutex);
-		return 0;
-	}
-}
-
-static int az6027_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	int ret;
-	u8 req;
-	u16 value;
-	u16 index;
-	int blen;
-
-	deb_info("%s %d", __func__, onoff);
-
-	req = 0xBC;
-	value = onoff;
-	index = 0;
-	blen = 0;
-
-	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
-	if (ret != 0)
-		warn("usb out operation failed. (%d)", ret);
-
-	return ret;
-}
-
-/* keys for the enclosed remote control */
-static struct rc_map_table rc_map_az6027_table[] = {
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-};
-
-/* remote control stuff (does not work with my box) */
-static int az6027_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
-{
-	return 0;
-}
-
-/*
-int az6027_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	u8 v = onoff;
-	return az6027_usb_out_op(d,0xBC,v,3,NULL,1);
-}
-*/
-
-static int az6027_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
-					int slot,
-					int address)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
-
-	int ret;
-	u8 req;
-	u16 value;
-	u16 index;
-	int blen;
-	u8 *b;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	b = kmalloc(12, GFP_KERNEL);
-	if (!b)
-		return -ENOMEM;
-
-	mutex_lock(&state->ca_mutex);
-
-	req = 0xC1;
-	value = address;
-	index = 0;
-	blen = 1;
-
-	ret = az6027_usb_in_op(d, req, value, index, b, blen);
-	if (ret < 0) {
-		warn("usb in operation failed. (%d)", ret);
-		ret = -EINVAL;
-	} else {
-		ret = b[0];
-	}
-
-	mutex_unlock(&state->ca_mutex);
-	kfree(b);
-	return ret;
-}
-
-static int az6027_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
-					 int slot,
-					 int address,
-					 u8 value)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
-
-	int ret;
-	u8 req;
-	u16 value1;
-	u16 index;
-	int blen;
-
-	deb_info("%s %d", __func__, slot);
-	if (slot != 0)
-		return -EINVAL;
-
-	mutex_lock(&state->ca_mutex);
-	req = 0xC2;
-	value1 = address;
-	index = value;
-	blen = 0;
-
-	ret = az6027_usb_out_op(d, req, value1, index, NULL, blen);
-	if (ret != 0)
-		warn("usb out operation failed. (%d)", ret);
-
-	mutex_unlock(&state->ca_mutex);
-	return ret;
-}
-
-static int az6027_ci_read_cam_control(struct dvb_ca_en50221 *ca,
-				      int slot,
-				      u8 address)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
-
-	int ret;
-	u8 req;
-	u16 value;
-	u16 index;
-	int blen;
-	u8 *b;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	b = kmalloc(12, GFP_KERNEL);
-	if (!b)
-		return -ENOMEM;
-
-	mutex_lock(&state->ca_mutex);
-
-	req = 0xC3;
-	value = address;
-	index = 0;
-	blen = 2;
-
-	ret = az6027_usb_in_op(d, req, value, index, b, blen);
-	if (ret < 0) {
-		warn("usb in operation failed. (%d)", ret);
-		ret = -EINVAL;
-	} else {
-		if (b[0] == 0)
-			warn("Read CI IO error");
-
-		ret = b[1];
-		deb_info("read cam data = %x from 0x%x", b[1], value);
-	}
-
-	mutex_unlock(&state->ca_mutex);
-	kfree(b);
-	return ret;
-}
-
-static int az6027_ci_write_cam_control(struct dvb_ca_en50221 *ca,
-				       int slot,
-				       u8 address,
-				       u8 value)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
-
-	int ret;
-	u8 req;
-	u16 value1;
-	u16 index;
-	int blen;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	mutex_lock(&state->ca_mutex);
-	req = 0xC4;
-	value1 = address;
-	index = value;
-	blen = 0;
-
-	ret = az6027_usb_out_op(d, req, value1, index, NULL, blen);
-	if (ret != 0) {
-		warn("usb out operation failed. (%d)", ret);
-		goto failed;
-	}
-
-failed:
-	mutex_unlock(&state->ca_mutex);
-	return ret;
-}
-
-static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-
-	int ret;
-	u8 req;
-	u16 value;
-	u16 index;
-	int blen;
-	u8 *b;
-
-	b = kmalloc(12, GFP_KERNEL);
-	if (!b)
-		return -ENOMEM;
-
-	req = 0xC8;
-	value = 0;
-	index = 0;
-	blen = 1;
-
-	ret = az6027_usb_in_op(d, req, value, index, b, blen);
-	if (ret < 0) {
-		warn("usb in operation failed. (%d)", ret);
-		ret = -EIO;
-	} else{
-		ret = b[0];
-	}
-	kfree(b);
-	return ret;
-}
-
-static int az6027_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
-
-	int ret, i;
-	u8 req;
-	u16 value;
-	u16 index;
-	int blen;
-
-	mutex_lock(&state->ca_mutex);
-
-	req = 0xC6;
-	value = 1;
-	index = 0;
-	blen = 0;
-
-	ret = az6027_usb_out_op(d, req, value, index, NULL, blen);
-	if (ret != 0) {
-		warn("usb out operation failed. (%d)", ret);
-		goto failed;
-	}
-
-	msleep(500);
-	req = 0xC6;
-	value = 0;
-	index = 0;
-	blen = 0;
-
-	ret = az6027_usb_out_op(d, req, value, index, NULL, blen);
-	if (ret != 0) {
-		warn("usb out operation failed. (%d)", ret);
-		goto failed;
-	}
-
-	for (i = 0; i < 15; i++) {
-		msleep(100);
-
-		if (CI_CamReady(ca, slot)) {
-			deb_info("CAM Ready");
-			break;
-		}
-	}
-	msleep(5000);
-
-failed:
-	mutex_unlock(&state->ca_mutex);
-	return ret;
-}
-
-static int az6027_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
-{
-	return 0;
-}
-
-static int az6027_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
-
-	int ret;
-	u8 req;
-	u16 value;
-	u16 index;
-	int blen;
-
-	deb_info("%s", __func__);
-	mutex_lock(&state->ca_mutex);
-	req = 0xC7;
-	value = 1;
-	index = 0;
-	blen = 0;
-
-	ret = az6027_usb_out_op(d, req, value, index, NULL, blen);
-	if (ret != 0) {
-		warn("usb out operation failed. (%d)", ret);
-		goto failed;
-	}
-
-failed:
-	mutex_unlock(&state->ca_mutex);
-	return ret;
-}
-
-static int az6027_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
-	int ret;
-	u8 req;
-	u16 value;
-	u16 index;
-	int blen;
-	u8 *b;
-
-	b = kmalloc(12, GFP_KERNEL);
-	if (!b)
-		return -ENOMEM;
-	mutex_lock(&state->ca_mutex);
-
-	req = 0xC5;
-	value = 0;
-	index = 0;
-	blen = 1;
-
-	ret = az6027_usb_in_op(d, req, value, index, b, blen);
-	if (ret < 0) {
-		warn("usb in operation failed. (%d)", ret);
-		ret = -EIO;
-	} else
-		ret = 0;
-
-	if (!ret && b[0] == 1) {
-		ret = DVB_CA_EN50221_POLL_CAM_PRESENT |
-		      DVB_CA_EN50221_POLL_CAM_READY;
-	}
-
-	mutex_unlock(&state->ca_mutex);
-	kfree(b);
-	return ret;
-}
-
-
-static void az6027_ci_uninit(struct dvb_usb_device *d)
-{
-	struct az6027_device_state *state;
-
-	deb_info("%s", __func__);
-
-	if (NULL == d)
-		return;
-
-	state = (struct az6027_device_state *)d->priv;
-	if (NULL == state)
-		return;
-
-	if (NULL == state->ca.data)
-		return;
-
-	dvb_ca_en50221_release(&state->ca);
-
-	memset(&state->ca, 0, sizeof(state->ca));
-}
-
-
-static int az6027_ci_init(struct dvb_usb_adapter *a)
-{
-	struct dvb_usb_device *d = a->dev;
-	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
-	int ret;
-
-	deb_info("%s", __func__);
-
-	mutex_init(&state->ca_mutex);
-
-	state->ca.owner			= THIS_MODULE;
-	state->ca.read_attribute_mem	= az6027_ci_read_attribute_mem;
-	state->ca.write_attribute_mem	= az6027_ci_write_attribute_mem;
-	state->ca.read_cam_control	= az6027_ci_read_cam_control;
-	state->ca.write_cam_control	= az6027_ci_write_cam_control;
-	state->ca.slot_reset		= az6027_ci_slot_reset;
-	state->ca.slot_shutdown		= az6027_ci_slot_shutdown;
-	state->ca.slot_ts_enable	= az6027_ci_slot_ts_enable;
-	state->ca.poll_slot_status	= az6027_ci_poll_slot_status;
-	state->ca.data			= d;
-
-	ret = dvb_ca_en50221_init(&a->dvb_adap,
-				  &state->ca,
-				  0, /* flags */
-				  1);/* n_slots */
-	if (ret != 0) {
-		err("Cannot initialize CI: Error %d.", ret);
-		memset(&state->ca, 0, sizeof(state->ca));
-		return ret;
-	}
-
-	deb_info("CI initialized.");
-
-	return 0;
-}
-
-/*
-static int az6027_read_mac_addr(struct dvb_usb_device *d, u8 mac[6])
-{
-	az6027_usb_in_op(d, 0xb7, 6, 0, &mac[0], 6);
-	return 0;
-}
-*/
-
-static int az6027_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
-
-	u8 buf;
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-
-	struct i2c_msg i2c_msg = {
-		.addr	= 0x99,
-		.flags	= 0,
-		.buf	= &buf,
-		.len	= 1
-	};
-
-	/*
-	 * 2   --18v
-	 * 1   --13v
-	 * 0   --off
-	 */
-	switch (voltage) {
-	case SEC_VOLTAGE_13:
-		buf = 1;
-		i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
-		break;
-
-	case SEC_VOLTAGE_18:
-		buf = 2;
-		i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
-		break;
-
-	case SEC_VOLTAGE_OFF:
-		buf = 0;
-		i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
-		break;
-
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-
-static int az6027_frontend_poweron(struct dvb_usb_adapter *adap)
-{
-	int ret;
-	u8 req;
-	u16 value;
-	u16 index;
-	int blen;
-
-	req = 0xBC;
-	value = 1; /* power on */
-	index = 3;
-	blen = 0;
-
-	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
-	if (ret != 0)
-		return -EIO;
-
-	return 0;
-}
-static int az6027_frontend_reset(struct dvb_usb_adapter *adap)
-{
-	int ret;
-	u8 req;
-	u16 value;
-	u16 index;
-	int blen;
-
-	/* reset demodulator */
-	req = 0xC0;
-	value = 1; /* high */
-	index = 3;
-	blen = 0;
-
-	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
-	if (ret != 0)
-		return -EIO;
-
-	req = 0xC0;
-	value = 0; /* low */
-	index = 3;
-	blen = 0;
-	msleep_interruptible(200);
-
-	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
-	if (ret != 0)
-		return -EIO;
-
-	msleep_interruptible(200);
-
-	req = 0xC0;
-	value = 1; /*high */
-	index = 3;
-	blen = 0;
-
-	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
-	if (ret != 0)
-		return -EIO;
-
-	msleep_interruptible(200);
-	return 0;
-}
-
-static int az6027_frontend_tsbypass(struct dvb_usb_adapter *adap, int onoff)
-{
-	int ret;
-	u8 req;
-	u16 value;
-	u16 index;
-	int blen;
-
-	/* TS passthrough */
-	req = 0xC7;
-	value = onoff;
-	index = 0;
-	blen = 0;
-
-	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
-	if (ret != 0)
-		return -EIO;
-
-	return 0;
-}
-
-static int az6027_frontend_attach(struct dvb_usb_adapter *adap)
-{
-
-	az6027_frontend_poweron(adap);
-	az6027_frontend_reset(adap);
-
-	deb_info("adap = %p, dev = %p\n", adap, adap->dev);
-	adap->fe_adap[0].fe = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap);
-
-	if (adap->fe_adap[0].fe) {
-		deb_info("found STB0899 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb0899_config.demod_address);
-		if (stb6100_attach(adap->fe_adap[0].fe, &az6027_stb6100_config, &adap->dev->i2c_adap)) {
-			deb_info("found STB6100 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb6100_config.tuner_address);
-			adap->fe_adap[0].fe->ops.set_voltage = az6027_set_voltage;
-			az6027_ci_init(adap);
-		} else {
-			adap->fe_adap[0].fe = NULL;
-		}
-	} else
-		warn("no front-end attached\n");
-
-	az6027_frontend_tsbypass(adap, 0);
-
-	return 0;
-}
-
-static struct dvb_usb_device_properties az6027_properties;
-
-static void az6027_usb_disconnect(struct usb_interface *intf)
-{
-	struct dvb_usb_device *d = usb_get_intfdata(intf);
-	az6027_ci_uninit(d);
-	dvb_usb_device_exit(intf);
-}
-
-
-static int az6027_usb_probe(struct usb_interface *intf,
-			    const struct usb_device_id *id)
-{
-	return dvb_usb_device_init(intf,
-				   &az6027_properties,
-				   THIS_MODULE,
-				   NULL,
-				   adapter_nr);
-}
-
-/* I2C */
-static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int i = 0, j = 0, len = 0;
-	u16 index;
-	u16 value;
-	int length;
-	u8 req;
-	u8 *data;
-
-	data = kmalloc(256, GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0) {
-		kfree(data);
-		return -EAGAIN;
-	}
-
-	if (num > 2)
-		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
-
-	for (i = 0; i < num; i++) {
-
-		if (msg[i].addr == 0x99) {
-			req = 0xBE;
-			index = 0;
-			value = msg[i].buf[0] & 0x00ff;
-			length = 1;
-			az6027_usb_out_op(d, req, value, index, data, length);
-		}
-
-		if (msg[i].addr == 0xd0) {
-			/* write/read request */
-			if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) {
-				req = 0xB9;
-				index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
-				value = msg[i].addr + (msg[i].len << 8);
-				length = msg[i + 1].len + 6;
-				az6027_usb_in_op(d, req, value, index, data, length);
-				len = msg[i + 1].len;
-				for (j = 0; j < len; j++)
-					msg[i + 1].buf[j] = data[j + 5];
-
-				i++;
-			} else {
-
-				/* demod 16bit addr */
-				req = 0xBD;
-				index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
-				value = msg[i].addr + (2 << 8);
-				length = msg[i].len - 2;
-				len = msg[i].len - 2;
-				for (j = 0; j < len; j++)
-					data[j] = msg[i].buf[j + 2];
-				az6027_usb_out_op(d, req, value, index, data, length);
-			}
-		}
-
-		if (msg[i].addr == 0xc0) {
-			if (msg[i].flags & I2C_M_RD) {
-
-				req = 0xB9;
-				index = 0x0;
-				value = msg[i].addr;
-				length = msg[i].len + 6;
-				az6027_usb_in_op(d, req, value, index, data, length);
-				len = msg[i].len;
-				for (j = 0; j < len; j++)
-					msg[i].buf[j] = data[j + 5];
-
-			} else {
-
-				req = 0xBD;
-				index = msg[i].buf[0] & 0x00FF;
-				value = msg[i].addr + (1 << 8);
-				length = msg[i].len - 1;
-				len = msg[i].len - 1;
-
-				for (j = 0; j < len; j++)
-					data[j] = msg[i].buf[j + 1];
-
-				az6027_usb_out_op(d, req, value, index, data, length);
-			}
-		}
-	}
-	mutex_unlock(&d->i2c_mutex);
-	kfree(data);
-
-	return i;
-}
-
-
-static u32 az6027_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm az6027_i2c_algo = {
-	.master_xfer   = az6027_i2c_xfer,
-	.functionality = az6027_i2c_func,
-};
-
-int az6027_identify_state(struct usb_device *udev,
-			  struct dvb_usb_device_properties *props,
-			  struct dvb_usb_device_description **desc,
-			  int *cold)
-{
-	u8 *b;
-	s16 ret;
-
-	b = kmalloc(16, GFP_KERNEL);
-	if (!b)
-		return -ENOMEM;
-
-	ret = usb_control_msg(udev,
-				  usb_rcvctrlpipe(udev, 0),
-				  0xb7,
-				  USB_TYPE_VENDOR | USB_DIR_IN,
-				  6,
-				  0,
-				  b,
-				  6,
-				  USB_CTRL_GET_TIMEOUT);
-
-	*cold = ret <= 0;
-	kfree(b);
-	deb_info("cold: %d\n", *cold);
-	return 0;
-}
-
-
-static struct usb_device_id az6027_usb_table[] = {
-	{ USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_AZ6027) },
-	{ USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_DVBS2CI_V1) },
-	{ USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_DVBS2CI_V2) },
-	{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V1) },
-	{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) },
-	{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) },
-	{ },
-};
-
-MODULE_DEVICE_TABLE(usb, az6027_usb_table);
-
-static struct dvb_usb_device_properties az6027_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware            = "dvb-usb-az6027-03.fw",
-	.no_reconnect        = 1,
-
-	.size_of_priv     = sizeof(struct az6027_device_state),
-	.identify_state		= az6027_identify_state,
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = az6027_streaming_ctrl,
-			.frontend_attach  = az6027_frontend_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 10,
-				.endpoint = 0x02,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-		}
-	},
-/*
-	.power_ctrl       = az6027_power_ctrl,
-	.read_mac_address = az6027_read_mac_addr,
- */
-	.rc.legacy = {
-		.rc_map_table     = rc_map_az6027_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_az6027_table),
-		.rc_interval      = 400,
-		.rc_query         = az6027_rc_query,
-	},
-
-	.i2c_algo         = &az6027_i2c_algo,
-
-	.num_device_descs = 6,
-	.devices = {
-		{
-			.name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)",
-			.cold_ids = { &az6027_usb_table[0], NULL },
-			.warm_ids = { NULL },
-		}, {
-			.name = "TERRATEC S7",
-			.cold_ids = { &az6027_usb_table[1], NULL },
-			.warm_ids = { NULL },
-		}, {
-			.name = "TERRATEC S7 MKII",
-			.cold_ids = { &az6027_usb_table[2], NULL },
-			.warm_ids = { NULL },
-		}, {
-			.name = "Technisat SkyStar USB 2 HD CI",
-			.cold_ids = { &az6027_usb_table[3], NULL },
-			.warm_ids = { NULL },
-		}, {
-			.name = "Technisat SkyStar USB 2 HD CI",
-			.cold_ids = { &az6027_usb_table[4], NULL },
-			.warm_ids = { NULL },
-		}, {
-			.name = "Elgato EyeTV Sat",
-			.cold_ids = { &az6027_usb_table[5], NULL },
-			.warm_ids = { NULL },
-		},
-		{ NULL },
-	}
-};
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver az6027_usb_driver = {
-	.name		= "dvb_usb_az6027",
-	.probe 		= az6027_usb_probe,
-	.disconnect 	= az6027_usb_disconnect,
-	.id_table 	= az6027_usb_table,
-};
-
-module_usb_driver(az6027_usb_driver);
-
-MODULE_AUTHOR("Adams Xu <Adams.xu@azwave.com.cn>");
-MODULE_DESCRIPTION("Driver for AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/az6027.h b/drivers/media/dvb/dvb-usb/az6027.h
deleted file mode 100644
index f3afe17..0000000
--- a/drivers/media/dvb/dvb-usb/az6027.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _DVB_USB_VP6027_H_
-#define _DVB_USB_VP6027_H_
-
-#define DVB_USB_LOG_PREFIX "az6027"
-#include "dvb-usb.h"
-
-
-extern int dvb_usb_az6027_debug;
-#define deb_info(args...) dprintk(dvb_usb_az6027_debug, 0x01, args)
-#define deb_xfer(args...) dprintk(dvb_usb_az6027_debug, 0x02, args)
-#define deb_rc(args...)   dprintk(dvb_usb_az6027_debug, 0x04, args)
-#define deb_fe(args...)   dprintk(dvb_usb_az6027_debug, 0x08, args)
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/ce6230.c b/drivers/media/dvb/dvb-usb/ce6230.c
deleted file mode 100644
index fa63725..0000000
--- a/drivers/media/dvb/dvb-usb/ce6230.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include "ce6230.h"
-#include "zl10353.h"
-#include "mxl5005s.h"
-
-/* debug */
-static int dvb_usb_ce6230_debug;
-module_param_named(debug, dvb_usb_ce6230_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static struct zl10353_config ce6230_zl10353_config;
-
-static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
-{
-	int ret;
-	unsigned int pipe;
-	u8 request;
-	u8 requesttype;
-	u16 value;
-	u16 index;
-	u8 *buf;
-
-	request = req->cmd;
-	value = req->value;
-	index = req->index;
-
-	switch (req->cmd) {
-	case I2C_READ:
-	case DEMOD_READ:
-	case REG_READ:
-		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
-		break;
-	case I2C_WRITE:
-	case DEMOD_WRITE:
-	case REG_WRITE:
-		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
-		break;
-	default:
-		err("unknown command:%02x", req->cmd);
-		ret = -EPERM;
-		goto error;
-	}
-
-	buf = kmalloc(req->data_len, GFP_KERNEL);
-	if (!buf) {
-		ret = -ENOMEM;
-		goto error;
-	}
-
-	if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
-		/* write */
-		memcpy(buf, req->data, req->data_len);
-		pipe = usb_sndctrlpipe(udev, 0);
-	} else {
-		/* read */
-		pipe = usb_rcvctrlpipe(udev, 0);
-	}
-
-	msleep(1); /* avoid I2C errors */
-
-	ret = usb_control_msg(udev, pipe, request, requesttype, value, index,
-				buf, req->data_len, CE6230_USB_TIMEOUT);
-
-	ce6230_debug_dump(request, requesttype, value, index, buf,
-		req->data_len, deb_xfer);
-
-	if (ret < 0)
-		deb_info("%s: usb_control_msg failed:%d\n", __func__, ret);
-	else
-		ret = 0;
-
-	/* read request, copy returned data to return buf */
-	if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
-		memcpy(req->data, buf, req->data_len);
-
-	kfree(buf);
-error:
-	return ret;
-}
-
-static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
-{
-	return ce6230_rw_udev(d->udev, req);
-}
-
-/* I2C */
-static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-			   int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int i = 0;
-	struct req_t req;
-	int ret = 0;
-	memset(&req, 0, sizeof(req));
-
-	if (num > 2)
-		return -EINVAL;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	while (i < num) {
-		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
-			if (msg[i].addr ==
-				ce6230_zl10353_config.demod_address) {
-				req.cmd = DEMOD_READ;
-				req.value = msg[i].addr >> 1;
-				req.index = msg[i].buf[0];
-				req.data_len = msg[i+1].len;
-				req.data = &msg[i+1].buf[0];
-				ret = ce6230_ctrl_msg(d, &req);
-			} else {
-				err("i2c read not implemented");
-				ret = -EPERM;
-			}
-			i += 2;
-		} else {
-			if (msg[i].addr ==
-				ce6230_zl10353_config.demod_address) {
-				req.cmd = DEMOD_WRITE;
-				req.value = msg[i].addr >> 1;
-				req.index = msg[i].buf[0];
-				req.data_len = msg[i].len-1;
-				req.data = &msg[i].buf[1];
-				ret = ce6230_ctrl_msg(d, &req);
-			} else {
-				req.cmd = I2C_WRITE;
-				req.value = 0x2000 + (msg[i].addr >> 1);
-				req.index = 0x0000;
-				req.data_len = msg[i].len;
-				req.data = &msg[i].buf[0];
-				ret = ce6230_ctrl_msg(d, &req);
-			}
-			i += 1;
-		}
-		if (ret)
-			break;
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return ret ? ret : i;
-}
-
-static u32 ce6230_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm ce6230_i2c_algo = {
-	.master_xfer   = ce6230_i2c_xfer,
-	.functionality = ce6230_i2c_func,
-};
-
-/* Callbacks for DVB USB */
-static struct zl10353_config ce6230_zl10353_config = {
-	.demod_address = 0x1e,
-	.adc_clock = 450000,
-	.if2 = 45700,
-	.no_tuner = 1,
-	.parallel_ts = 1,
-	.clock_ctl_1 = 0x34,
-	.pll_0 = 0x0e,
-};
-
-static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	deb_info("%s:\n", __func__);
-	adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
-		&adap->dev->i2c_adap);
-	if (adap->fe_adap[0].fe == NULL)
-		return -ENODEV;
-	return 0;
-}
-
-static struct mxl5005s_config ce6230_mxl5003s_config = {
-	.i2c_address     = 0xc6,
-	.if_freq         = IF_FREQ_4570000HZ,
-	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
-	.agc_mode        = MXL_SINGLE_AGC,
-	.tracking_filter = MXL_TF_DEFAULT,
-	.rssi_enable     = MXL_RSSI_ENABLE,
-	.cap_select      = MXL_CAP_SEL_ENABLE,
-	.div_out         = MXL_DIV_OUT_4,
-	.clock_out       = MXL_CLOCK_OUT_DISABLE,
-	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
-	.top		 = MXL5005S_TOP_25P2,
-	.mod_mode        = MXL_DIGITAL_MODE,
-	.if_mode         = MXL_ZERO_IF,
-	.AgcMasterByte   = 0x00,
-};
-
-static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	int ret;
-	deb_info("%s:\n", __func__);
-	ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
-			&ce6230_mxl5003s_config) == NULL ? -ENODEV : 0;
-	return ret;
-}
-
-static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	int ret;
-	deb_info("%s: onoff:%d\n", __func__, onoff);
-
-	/* InterfaceNumber 1 / AlternateSetting 0     idle
-	   InterfaceNumber 1 / AlternateSetting 1     streaming */
-	ret = usb_set_interface(d->udev, 1, onoff);
-	if (ret)
-		err("usb_set_interface failed with error:%d", ret);
-
-	return ret;
-}
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties ce6230_properties;
-
-static int ce6230_probe(struct usb_interface *intf,
-			const struct usb_device_id *id)
-{
-	int ret = 0;
-	struct dvb_usb_device *d = NULL;
-
-	deb_info("%s: interface:%d\n", __func__,
-		intf->cur_altsetting->desc.bInterfaceNumber);
-
-	if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
-		ret = dvb_usb_device_init(intf, &ce6230_properties, THIS_MODULE,
-			&d, adapter_nr);
-		if (ret)
-			err("init failed with error:%d\n", ret);
-	}
-
-	return ret;
-}
-
-static struct usb_device_id ce6230_table[] = {
-	{ USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500) },
-	{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310) },
-	{ } /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, ce6230_table);
-
-static struct dvb_usb_device_properties ce6230_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = DEVICE_SPECIFIC,
-	.no_reconnect = 1,
-
-	.size_of_priv = 0,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.frontend_attach  = ce6230_zl10353_frontend_attach,
-			.tuner_attach     = ce6230_mxl5003s_tuner_attach,
-			.stream = {
-				.type = USB_BULK,
-				.count = 6,
-				.endpoint = 0x82,
-				.u = {
-					.bulk = {
-						.buffersize = (16*512),
-					}
-				}
-			},
-		}},
-		}
-	},
-
-	.power_ctrl = ce6230_power_ctrl,
-
-	.i2c_algo = &ce6230_i2c_algo,
-
-	.num_device_descs = 2,
-	.devices = {
-		{
-			.name = "Intel CE9500 reference design",
-			.cold_ids = {NULL},
-			.warm_ids = {&ce6230_table[0], NULL},
-		},
-		{
-			.name = "AVerMedia A310 USB 2.0 DVB-T tuner",
-			.cold_ids = {NULL},
-			.warm_ids = {&ce6230_table[1], NULL},
-		},
-	}
-};
-
-static struct usb_driver ce6230_driver = {
-	.name       = "dvb_usb_ce6230",
-	.probe      = ce6230_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table   = ce6230_table,
-};
-
-module_usb_driver(ce6230_driver);
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Driver for Intel CE6230 DVB-T USB2.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/ce6230.h b/drivers/media/dvb/dvb-usb/ce6230.h
deleted file mode 100644
index 97c4248..0000000
--- a/drivers/media/dvb/dvb-usb/ce6230.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef _DVB_USB_CE6230_H_
-#define _DVB_USB_CE6230_H_
-
-#define DVB_USB_LOG_PREFIX "ce6230"
-#include "dvb-usb.h"
-
-#define deb_info(args...) dprintk(dvb_usb_ce6230_debug, 0x01, args)
-#define deb_rc(args...)   dprintk(dvb_usb_ce6230_debug, 0x02, args)
-#define deb_xfer(args...) dprintk(dvb_usb_ce6230_debug, 0x04, args)
-#define deb_reg(args...)  dprintk(dvb_usb_ce6230_debug, 0x08, args)
-#define deb_i2c(args...)  dprintk(dvb_usb_ce6230_debug, 0x10, args)
-#define deb_fw(args...)   dprintk(dvb_usb_ce6230_debug, 0x20, args)
-
-#define ce6230_debug_dump(r, t, v, i, b, l, func) { \
-	int loop_; \
-	func("%02x %02x %02x %02x %02x %02x %02x %02x", \
-		t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \
-	if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
-		func(" >>> "); \
-	else \
-		func(" <<< "); \
-	for (loop_ = 0; loop_ < l; loop_++) \
-		func("%02x ", b[loop_]); \
-	func("\n");\
-}
-
-#define CE6230_USB_TIMEOUT 1000
-
-struct req_t {
-	u8  cmd;       /* [1] */
-	u16 value;     /* [2|3] */
-	u16 index;     /* [4|5] */
-	u16 data_len;  /* [6|7] */
-	u8  *data;
-};
-
-enum ce6230_cmd {
-	CONFIG_READ          = 0xd0, /* rd 0 (unclear) */
-	UNKNOWN_WRITE        = 0xc7, /* wr 7 (unclear) */
-	I2C_READ             = 0xd9, /* rd 9 (unclear) */
-	I2C_WRITE            = 0xca, /* wr a */
-	DEMOD_READ           = 0xdb, /* rd b */
-	DEMOD_WRITE          = 0xcc, /* wr c */
-	REG_READ             = 0xde, /* rd e */
-	REG_WRITE            = 0xcf, /* wr f */
-};
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/drivers/media/dvb/dvb-usb/cinergyT2-core.c
deleted file mode 100644
index 0a98548..0000000
--- a/drivers/media/dvb/dvb-usb/cinergyT2-core.c
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
- *
- * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
- *
- * Based on the dvb-usb-framework code and the
- * original Terratec Cinergy T2 driver by:
- *
- * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
- *		    Holger Waechtler <holger@qanu.de>
- *
- *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include "cinergyT2.h"
-
-
-/* debug */
-int dvb_usb_cinergyt2_debug;
-
-module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 "
-		"(or-able)).");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-struct cinergyt2_state {
-	u8 rc_counter;
-};
-
-/* We are missing a release hook with usb_device data */
-static struct dvb_usb_device *cinergyt2_usb_device;
-
-static struct dvb_usb_device_properties cinergyt2_properties;
-
-static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable)
-{
-	char buf[] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 };
-	char result[64];
-	return dvb_usb_generic_rw(adap->dev, buf, sizeof(buf), result,
-				sizeof(result), 0);
-}
-
-static int cinergyt2_power_ctrl(struct dvb_usb_device *d, int enable)
-{
-	char buf[] = { CINERGYT2_EP1_SLEEP_MODE, enable ? 0 : 1 };
-	char state[3];
-	return dvb_usb_generic_rw(d, buf, sizeof(buf), state, sizeof(state), 0);
-}
-
-static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	char query[] = { CINERGYT2_EP1_GET_FIRMWARE_VERSION };
-	char state[3];
-	int ret;
-
-	adap->fe_adap[0].fe = cinergyt2_fe_attach(adap->dev);
-
-	ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state,
-				sizeof(state), 0);
-	if (ret < 0) {
-		deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep "
-			"state info\n");
-	}
-
-	/* Copy this pointer as we are gonna need it in the release phase */
-	cinergyt2_usb_device = adap->dev;
-
-	return 0;
-}
-
-static struct rc_map_table rc_map_cinergyt2_table[] = {
-	{ 0x0401, KEY_POWER },
-	{ 0x0402, KEY_1 },
-	{ 0x0403, KEY_2 },
-	{ 0x0404, KEY_3 },
-	{ 0x0405, KEY_4 },
-	{ 0x0406, KEY_5 },
-	{ 0x0407, KEY_6 },
-	{ 0x0408, KEY_7 },
-	{ 0x0409, KEY_8 },
-	{ 0x040a, KEY_9 },
-	{ 0x040c, KEY_0 },
-	{ 0x040b, KEY_VIDEO },
-	{ 0x040d, KEY_REFRESH },
-	{ 0x040e, KEY_SELECT },
-	{ 0x040f, KEY_EPG },
-	{ 0x0410, KEY_UP },
-	{ 0x0414, KEY_DOWN },
-	{ 0x0411, KEY_LEFT },
-	{ 0x0413, KEY_RIGHT },
-	{ 0x0412, KEY_OK },
-	{ 0x0415, KEY_TEXT },
-	{ 0x0416, KEY_INFO },
-	{ 0x0417, KEY_RED },
-	{ 0x0418, KEY_GREEN },
-	{ 0x0419, KEY_YELLOW },
-	{ 0x041a, KEY_BLUE },
-	{ 0x041c, KEY_VOLUMEUP },
-	{ 0x041e, KEY_VOLUMEDOWN },
-	{ 0x041d, KEY_MUTE },
-	{ 0x041b, KEY_CHANNELUP },
-	{ 0x041f, KEY_CHANNELDOWN },
-	{ 0x0440, KEY_PAUSE },
-	{ 0x044c, KEY_PLAY },
-	{ 0x0458, KEY_RECORD },
-	{ 0x0454, KEY_PREVIOUS },
-	{ 0x0448, KEY_STOP },
-	{ 0x045c, KEY_NEXT }
-};
-
-/* Number of keypresses to ignore before detect repeating */
-#define RC_REPEAT_DELAY 3
-
-static int repeatable_keys[] = {
-	KEY_UP,
-	KEY_DOWN,
-	KEY_LEFT,
-	KEY_RIGHT,
-	KEY_VOLUMEUP,
-	KEY_VOLUMEDOWN,
-	KEY_CHANNELUP,
-	KEY_CHANNELDOWN
-};
-
-static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
-{
-	struct cinergyt2_state *st = d->priv;
-	u8 key[5] = {0, 0, 0, 0, 0}, cmd = CINERGYT2_EP1_GET_RC_EVENTS;
-	int i;
-
-	*state = REMOTE_NO_KEY_PRESSED;
-
-	dvb_usb_generic_rw(d, &cmd, 1, key, sizeof(key), 0);
-	if (key[4] == 0xff) {
-		/* key repeat */
-		st->rc_counter++;
-		if (st->rc_counter > RC_REPEAT_DELAY) {
-			for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) {
-				if (d->last_event == repeatable_keys[i]) {
-					*state = REMOTE_KEY_REPEAT;
-					*event = d->last_event;
-					deb_rc("repeat key, event %x\n",
-						   *event);
-					return 0;
-				}
-			}
-			deb_rc("repeated key (non repeatable)\n");
-		}
-		return 0;
-	}
-
-	/* hack to pass checksum on the custom field */
-	key[2] = ~key[1];
-	dvb_usb_nec_rc_key_to_event(d, key, event, state);
-	if (key[0] != 0) {
-		if (*event != d->last_event)
-			st->rc_counter = 0;
-
-		deb_rc("key: %x %x %x %x %x\n",
-		       key[0], key[1], key[2], key[3], key[4]);
-	}
-	return 0;
-}
-
-static int cinergyt2_usb_probe(struct usb_interface *intf,
-				const struct usb_device_id *id)
-{
-	return dvb_usb_device_init(intf, &cinergyt2_properties,
-					THIS_MODULE, NULL, adapter_nr);
-}
-
-
-static struct usb_device_id cinergyt2_usb_table[] = {
-	{ USB_DEVICE(USB_VID_TERRATEC, 0x0038) },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table);
-
-static struct dvb_usb_device_properties cinergyt2_properties = {
-	.size_of_priv = sizeof(struct cinergyt2_state),
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = cinergyt2_streaming_ctrl,
-			.frontend_attach  = cinergyt2_frontend_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 5,
-				.endpoint = 0x02,
-				.u = {
-					.bulk = {
-						.buffersize = 512,
-					}
-				}
-			},
-		}},
-		}
-	},
-
-	.power_ctrl       = cinergyt2_power_ctrl,
-
-	.rc.legacy = {
-		.rc_interval      = 50,
-		.rc_map_table     = rc_map_cinergyt2_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_cinergyt2_table),
-		.rc_query         = cinergyt2_rc_query,
-	},
-
-	.generic_bulk_ctrl_endpoint = 1,
-
-	.num_device_descs = 1,
-	.devices = {
-		{ .name = "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver",
-		  .cold_ids = {NULL},
-		  .warm_ids = { &cinergyt2_usb_table[0], NULL },
-		},
-		{ NULL },
-	}
-};
-
-
-static struct usb_driver cinergyt2_driver = {
-	.name		= "cinergyT2",
-	.probe		= cinergyt2_usb_probe,
-	.disconnect	= dvb_usb_device_exit,
-	.id_table	= cinergyt2_usb_table
-};
-
-module_usb_driver(cinergyt2_driver);
-
-MODULE_DESCRIPTION("Terratec Cinergy T2 DVB-T driver");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Tomi Orava");
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-fe.c b/drivers/media/dvb/dvb-usb/cinergyT2-fe.c
deleted file mode 100644
index 1efc028..0000000
--- a/drivers/media/dvb/dvb-usb/cinergyT2-fe.c
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
- *
- * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
- *
- * Based on the dvb-usb-framework code and the
- * original Terratec Cinergy T2 driver by:
- *
- * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
- *                  Holger Waechtler <holger@qanu.de>
- *
- *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include "cinergyT2.h"
-
-
-/**
- *  convert linux-dvb frontend parameter set into TPS.
- *  See ETSI ETS-300744, section 4.6.2, table 9 for details.
- *
- *  This function is probably reusable and may better get placed in a support
- *  library.
- *
- *  We replace errornous fields by default TPS fields (the ones with value 0).
- */
-
-static uint16_t compute_tps(struct dtv_frontend_properties *op)
-{
-	uint16_t tps = 0;
-
-	switch (op->code_rate_HP) {
-	case FEC_2_3:
-		tps |= (1 << 7);
-		break;
-	case FEC_3_4:
-		tps |= (2 << 7);
-		break;
-	case FEC_5_6:
-		tps |= (3 << 7);
-		break;
-	case FEC_7_8:
-		tps |= (4 << 7);
-		break;
-	case FEC_1_2:
-	case FEC_AUTO:
-	default:
-		/* tps |= (0 << 7) */;
-	}
-
-	switch (op->code_rate_LP) {
-	case FEC_2_3:
-		tps |= (1 << 4);
-		break;
-	case FEC_3_4:
-		tps |= (2 << 4);
-		break;
-	case FEC_5_6:
-		tps |= (3 << 4);
-		break;
-	case FEC_7_8:
-		tps |= (4 << 4);
-		break;
-	case FEC_1_2:
-	case FEC_AUTO:
-	default:
-		/* tps |= (0 << 4) */;
-	}
-
-	switch (op->modulation) {
-	case QAM_16:
-		tps |= (1 << 13);
-		break;
-	case QAM_64:
-		tps |= (2 << 13);
-		break;
-	case QPSK:
-	default:
-		/* tps |= (0 << 13) */;
-	}
-
-	switch (op->transmission_mode) {
-	case TRANSMISSION_MODE_8K:
-		tps |= (1 << 0);
-		break;
-	case TRANSMISSION_MODE_2K:
-	default:
-		/* tps |= (0 << 0) */;
-	}
-
-	switch (op->guard_interval) {
-	case GUARD_INTERVAL_1_16:
-		tps |= (1 << 2);
-		break;
-	case GUARD_INTERVAL_1_8:
-		tps |= (2 << 2);
-		break;
-	case GUARD_INTERVAL_1_4:
-		tps |= (3 << 2);
-		break;
-	case GUARD_INTERVAL_1_32:
-	default:
-		/* tps |= (0 << 2) */;
-	}
-
-	switch (op->hierarchy) {
-	case HIERARCHY_1:
-		tps |= (1 << 10);
-		break;
-	case HIERARCHY_2:
-		tps |= (2 << 10);
-		break;
-	case HIERARCHY_4:
-		tps |= (3 << 10);
-		break;
-	case HIERARCHY_NONE:
-	default:
-		/* tps |= (0 << 10) */;
-	}
-
-	return tps;
-}
-
-struct cinergyt2_fe_state {
-	struct dvb_frontend fe;
-	struct dvb_usb_device *d;
-};
-
-static int cinergyt2_fe_read_status(struct dvb_frontend *fe,
-					fe_status_t *status)
-{
-	struct cinergyt2_fe_state *state = fe->demodulator_priv;
-	struct dvbt_get_status_msg result;
-	u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
-	int ret;
-
-	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result,
-			sizeof(result), 0);
-	if (ret < 0)
-		return ret;
-
-	*status = 0;
-
-	if (0xffff - le16_to_cpu(result.gain) > 30)
-		*status |= FE_HAS_SIGNAL;
-	if (result.lock_bits & (1 << 6))
-		*status |= FE_HAS_LOCK;
-	if (result.lock_bits & (1 << 5))
-		*status |= FE_HAS_SYNC;
-	if (result.lock_bits & (1 << 4))
-		*status |= FE_HAS_CARRIER;
-	if (result.lock_bits & (1 << 1))
-		*status |= FE_HAS_VITERBI;
-
-	if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
-			(FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
-		*status &= ~FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct cinergyt2_fe_state *state = fe->demodulator_priv;
-	struct dvbt_get_status_msg status;
-	char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
-	int ret;
-
-	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
-				sizeof(status), 0);
-	if (ret < 0)
-		return ret;
-
-	*ber = le32_to_cpu(status.viterbi_error_rate);
-	return 0;
-}
-
-static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
-{
-	struct cinergyt2_fe_state *state = fe->demodulator_priv;
-	struct dvbt_get_status_msg status;
-	u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
-	int ret;
-
-	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&status,
-				sizeof(status), 0);
-	if (ret < 0) {
-		err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n",
-			ret);
-		return ret;
-	}
-	*unc = le32_to_cpu(status.uncorrected_block_count);
-	return 0;
-}
-
-static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe,
-						u16 *strength)
-{
-	struct cinergyt2_fe_state *state = fe->demodulator_priv;
-	struct dvbt_get_status_msg status;
-	char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
-	int ret;
-
-	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
-				sizeof(status), 0);
-	if (ret < 0) {
-		err("cinergyt2_fe_read_signal_strength() Failed!"
-			" (Error=%d)\n", ret);
-		return ret;
-	}
-	*strength = (0xffff - le16_to_cpu(status.gain));
-	return 0;
-}
-
-static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct cinergyt2_fe_state *state = fe->demodulator_priv;
-	struct dvbt_get_status_msg status;
-	char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
-	int ret;
-
-	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
-				sizeof(status), 0);
-	if (ret < 0) {
-		err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret);
-		return ret;
-	}
-	*snr = (status.snr << 8) | status.snr;
-	return 0;
-}
-
-static int cinergyt2_fe_init(struct dvb_frontend *fe)
-{
-	return 0;
-}
-
-static int cinergyt2_fe_sleep(struct dvb_frontend *fe)
-{
-	deb_info("cinergyt2_fe_sleep() Called\n");
-	return 0;
-}
-
-static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe,
-				struct dvb_frontend_tune_settings *tune)
-{
-	tune->min_delay_ms = 800;
-	return 0;
-}
-
-static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
-	struct cinergyt2_fe_state *state = fe->demodulator_priv;
-	struct dvbt_set_parameters_msg param;
-	char result[2];
-	int err;
-
-	param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
-	param.tps = cpu_to_le16(compute_tps(fep));
-	param.freq = cpu_to_le32(fep->frequency / 1000);
-	param.flags = 0;
-
-	switch (fep->bandwidth_hz) {
-	default:
-	case 8000000:
-		param.bandwidth = 8;
-		break;
-	case 7000000:
-		param.bandwidth = 7;
-		break;
-	case 6000000:
-		param.bandwidth = 6;
-		break;
-	}
-
-	err = dvb_usb_generic_rw(state->d,
-			(char *)&param, sizeof(param),
-			result, sizeof(result), 0);
-	if (err < 0)
-		err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err);
-
-	return (err < 0) ? err : 0;
-}
-
-static void cinergyt2_fe_release(struct dvb_frontend *fe)
-{
-	struct cinergyt2_fe_state *state = fe->demodulator_priv;
-	if (state != NULL)
-		kfree(state);
-}
-
-static struct dvb_frontend_ops cinergyt2_fe_ops;
-
-struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d)
-{
-	struct cinergyt2_fe_state *s = kzalloc(sizeof(
-					struct cinergyt2_fe_state), GFP_KERNEL);
-	if (s == NULL)
-		return NULL;
-
-	s->d = d;
-	memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops));
-	s->fe.demodulator_priv = s;
-	return &s->fe;
-}
-
-
-static struct dvb_frontend_ops cinergyt2_fe_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name			= DRIVER_NAME,
-		.frequency_min		= 174000000,
-		.frequency_max		= 862000000,
-		.frequency_stepsize	= 166667,
-		.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2
-			| FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4
-			| FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8
-			| FE_CAN_FEC_AUTO | FE_CAN_QPSK
-			| FE_CAN_QAM_16 | FE_CAN_QAM_64
-			| FE_CAN_QAM_AUTO
-			| FE_CAN_TRANSMISSION_MODE_AUTO
-			| FE_CAN_GUARD_INTERVAL_AUTO
-			| FE_CAN_HIERARCHY_AUTO
-			| FE_CAN_RECOVER
-			| FE_CAN_MUTE_TS
-	},
-
-	.release		= cinergyt2_fe_release,
-
-	.init			= cinergyt2_fe_init,
-	.sleep			= cinergyt2_fe_sleep,
-
-	.set_frontend		= cinergyt2_fe_set_frontend,
-	.get_tune_settings	= cinergyt2_fe_get_tune_settings,
-
-	.read_status		= cinergyt2_fe_read_status,
-	.read_ber		= cinergyt2_fe_read_ber,
-	.read_signal_strength	= cinergyt2_fe_read_signal_strength,
-	.read_snr		= cinergyt2_fe_read_snr,
-	.read_ucblocks		= cinergyt2_fe_read_unc_blocks,
-};
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2.h b/drivers/media/dvb/dvb-usb/cinergyT2.h
deleted file mode 100644
index 84efe03..0000000
--- a/drivers/media/dvb/dvb-usb/cinergyT2.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
- *
- * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
- *
- * Based on the dvb-usb-framework code and the
- * original Terratec Cinergy T2 driver by:
- *
- * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
- *                  Holger Waechtler <holger@qanu.de>
- *
- *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License,  or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not,  write to the Free Software
- * Foundation,  Inc.,  675 Mass Ave,  Cambridge,  MA 02139,  USA.
- *
- */
-
-#ifndef _DVB_USB_CINERGYT2_H_
-#define _DVB_USB_CINERGYT2_H_
-
-#include <linux/usb/input.h>
-
-#define DVB_USB_LOG_PREFIX "cinergyT2"
-#include "dvb-usb.h"
-
-#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver"
-
-extern int dvb_usb_cinergyt2_debug;
-
-#define deb_info(args...)  dprintk(dvb_usb_cinergyt2_debug,  0x001, args)
-#define deb_xfer(args...)  dprintk(dvb_usb_cinergyt2_debug,  0x002, args)
-#define deb_pll(args...)   dprintk(dvb_usb_cinergyt2_debug,  0x004, args)
-#define deb_ts(args...)    dprintk(dvb_usb_cinergyt2_debug,  0x008, args)
-#define deb_err(args...)   dprintk(dvb_usb_cinergyt2_debug,  0x010, args)
-#define deb_rc(args...)    dprintk(dvb_usb_cinergyt2_debug,  0x020, args)
-#define deb_fw(args...)    dprintk(dvb_usb_cinergyt2_debug,  0x040, args)
-#define deb_mem(args...)   dprintk(dvb_usb_cinergyt2_debug,  0x080, args)
-#define deb_uxfer(args...) dprintk(dvb_usb_cinergyt2_debug,  0x100, args)
-
-
-
-enum cinergyt2_ep1_cmd {
-	CINERGYT2_EP1_PID_TABLE_RESET		= 0x01,
-	CINERGYT2_EP1_PID_SETUP			= 0x02,
-	CINERGYT2_EP1_CONTROL_STREAM_TRANSFER	= 0x03,
-	CINERGYT2_EP1_SET_TUNER_PARAMETERS	= 0x04,
-	CINERGYT2_EP1_GET_TUNER_STATUS		= 0x05,
-	CINERGYT2_EP1_START_SCAN		= 0x06,
-	CINERGYT2_EP1_CONTINUE_SCAN		= 0x07,
-	CINERGYT2_EP1_GET_RC_EVENTS		= 0x08,
-	CINERGYT2_EP1_SLEEP_MODE		= 0x09,
-	CINERGYT2_EP1_GET_FIRMWARE_VERSION	= 0x0A
-};
-
-
-struct dvbt_get_status_msg {
-	uint32_t freq;
-	uint8_t bandwidth;
-	uint16_t tps;
-	uint8_t flags;
-	__le16 gain;
-	uint8_t snr;
-	__le32 viterbi_error_rate;
-	uint32_t rs_error_rate;
-	__le32 uncorrected_block_count;
-	uint8_t lock_bits;
-	uint8_t prev_lock_bits;
-} __attribute__((packed));
-
-
-struct dvbt_set_parameters_msg {
-	uint8_t cmd;
-	__le32 freq;
-	uint8_t bandwidth;
-	__le16 tps;
-	uint8_t flags;
-} __attribute__((packed));
-
-
-extern struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d);
-
-#endif /* _DVB_USB_CINERGYT2_H_ */
-
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
deleted file mode 100644
index 3940bb0..0000000
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ /dev/null
@@ -1,2043 +0,0 @@
-/* DVB USB compliant linux driver for Conexant USB reference design.
- *
- * The Conexant reference design I saw on their website was only for analogue
- * capturing (using the cx25842). The box I took to write this driver (reverse
- * engineered) is the one labeled Medion MD95700. In addition to the cx25842
- * for analogue capturing it also has a cx22702 DVB-T demodulator on the main
- * board. Besides it has a atiremote (X10) and a USB2.0 hub onboard.
- *
- * Maybe it is a little bit premature to call this driver cxusb, but I assume
- * the USB protocol is identical or at least inherited from the reference
- * design, so it can be reused for the "analogue-only" device (if it will
- * appear at all).
- *
- * TODO: Use the cx25840-driver for the analogue part
- *
- * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
- * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org)
- * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au)
- *
- *   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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include <media/tuner.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-
-#include "cxusb.h"
-
-#include "cx22702.h"
-#include "lgdt330x.h"
-#include "mt352.h"
-#include "mt352_priv.h"
-#include "zl10353.h"
-#include "tuner-xc2028.h"
-#include "tuner-simple.h"
-#include "mxl5005s.h"
-#include "max2165.h"
-#include "dib7000p.h"
-#include "dib0070.h"
-#include "lgs8gxx.h"
-#include "atbm8830.h"
-
-/* debug */
-static int dvb_usb_cxusb_debug;
-module_param_named(debug, dvb_usb_cxusb_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define deb_info(args...)   dprintk(dvb_usb_cxusb_debug, 0x03, args)
-#define deb_i2c(args...)    dprintk(dvb_usb_cxusb_debug, 0x02, args)
-
-static int cxusb_ctrl_msg(struct dvb_usb_device *d,
-			  u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
-{
-	int wo = (rbuf == NULL || rlen == 0); /* write-only */
-	u8 sndbuf[1+wlen];
-	memset(sndbuf, 0, 1+wlen);
-
-	sndbuf[0] = cmd;
-	memcpy(&sndbuf[1], wbuf, wlen);
-	if (wo)
-		return dvb_usb_generic_write(d, sndbuf, 1+wlen);
-	else
-		return dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
-}
-
-/* GPIO */
-static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff)
-{
-	struct cxusb_state *st = d->priv;
-	u8 o[2], i;
-
-	if (st->gpio_write_state[GPIO_TUNER] == onoff)
-		return;
-
-	o[0] = GPIO_TUNER;
-	o[1] = onoff;
-	cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
-
-	if (i != 0x01)
-		deb_info("gpio_write failed.\n");
-
-	st->gpio_write_state[GPIO_TUNER] = onoff;
-}
-
-static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask,
-				 u8 newval)
-{
-	u8 o[2], gpio_state;
-	int rc;
-
-	o[0] = 0xff & ~changemask;	/* mask of bits to keep */
-	o[1] = newval & changemask;	/* new values for bits  */
-
-	rc = cxusb_ctrl_msg(d, CMD_BLUEBIRD_GPIO_RW, o, 2, &gpio_state, 1);
-	if (rc < 0 || (gpio_state & changemask) != (newval & changemask))
-		deb_info("bluebird_gpio_write failed.\n");
-
-	return rc < 0 ? rc : gpio_state;
-}
-
-static void cxusb_bluebird_gpio_pulse(struct dvb_usb_device *d, u8 pin, int low)
-{
-	cxusb_bluebird_gpio_rw(d, pin, low ? 0 : pin);
-	msleep(5);
-	cxusb_bluebird_gpio_rw(d, pin, low ? pin : 0);
-}
-
-static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff)
-{
-	cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40);
-}
-
-static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d,
-		u8 addr, int onoff)
-{
-	u8  o[2] = {addr, onoff};
-	u8  i;
-	int rc;
-
-	rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
-
-	if (rc < 0)
-		return rc;
-	if (i == 0x01)
-		return 0;
-	else {
-		deb_info("gpio_write failed.\n");
-		return -EIO;
-	}
-}
-
-/* I2C */
-static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-			  int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int i;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	for (i = 0; i < num; i++) {
-
-		if (d->udev->descriptor.idVendor == USB_VID_MEDION)
-			switch (msg[i].addr) {
-			case 0x63:
-				cxusb_gpio_tuner(d, 0);
-				break;
-			default:
-				cxusb_gpio_tuner(d, 1);
-				break;
-			}
-
-		if (msg[i].flags & I2C_M_RD) {
-			/* read only */
-			u8 obuf[3], ibuf[1+msg[i].len];
-			obuf[0] = 0;
-			obuf[1] = msg[i].len;
-			obuf[2] = msg[i].addr;
-			if (cxusb_ctrl_msg(d, CMD_I2C_READ,
-					   obuf, 3,
-					   ibuf, 1+msg[i].len) < 0) {
-				warn("i2c read failed");
-				break;
-			}
-			memcpy(msg[i].buf, &ibuf[1], msg[i].len);
-		} else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) &&
-			   msg[i].addr == msg[i+1].addr) {
-			/* write to then read from same address */
-			u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len];
-			obuf[0] = msg[i].len;
-			obuf[1] = msg[i+1].len;
-			obuf[2] = msg[i].addr;
-			memcpy(&obuf[3], msg[i].buf, msg[i].len);
-
-			if (cxusb_ctrl_msg(d, CMD_I2C_READ,
-					   obuf, 3+msg[i].len,
-					   ibuf, 1+msg[i+1].len) < 0)
-				break;
-
-			if (ibuf[0] != 0x08)
-				deb_i2c("i2c read may have failed\n");
-
-			memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
-
-			i++;
-		} else {
-			/* write only */
-			u8 obuf[2+msg[i].len], ibuf;
-			obuf[0] = msg[i].addr;
-			obuf[1] = msg[i].len;
-			memcpy(&obuf[2], msg[i].buf, msg[i].len);
-
-			if (cxusb_ctrl_msg(d, CMD_I2C_WRITE, obuf,
-					   2+msg[i].len, &ibuf,1) < 0)
-				break;
-			if (ibuf != 0x08)
-				deb_i2c("i2c write may have failed\n");
-		}
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return i == num ? num : -EREMOTEIO;
-}
-
-static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm cxusb_i2c_algo = {
-	.master_xfer   = cxusb_i2c_xfer,
-	.functionality = cxusb_i2c_func,
-};
-
-static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	u8 b = 0;
-	if (onoff)
-		return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0);
-	else
-		return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0);
-}
-
-static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	int ret;
-	if (!onoff)
-		return cxusb_ctrl_msg(d, CMD_POWER_OFF, NULL, 0, NULL, 0);
-	if (d->state == DVB_USB_STATE_INIT &&
-	    usb_set_interface(d->udev, 0, 0) < 0)
-		err("set interface failed");
-	do {} while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) &&
-		   !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) &&
-		   !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0);
-	if (!ret) {
-		/* FIXME: We don't know why, but we need to configure the
-		 * lgdt3303 with the register settings below on resume */
-		int i;
-		u8 buf, bufs[] = {
-			0x0e, 0x2, 0x00, 0x7f,
-			0x0e, 0x2, 0x02, 0xfe,
-			0x0e, 0x2, 0x02, 0x01,
-			0x0e, 0x2, 0x00, 0x03,
-			0x0e, 0x2, 0x0d, 0x40,
-			0x0e, 0x2, 0x0e, 0x87,
-			0x0e, 0x2, 0x0f, 0x8e,
-			0x0e, 0x2, 0x10, 0x01,
-			0x0e, 0x2, 0x14, 0xd7,
-			0x0e, 0x2, 0x47, 0x88,
-		};
-		msleep(20);
-		for (i = 0; i < sizeof(bufs)/sizeof(u8); i += 4/sizeof(u8)) {
-			ret = cxusb_ctrl_msg(d, CMD_I2C_WRITE,
-					     bufs+i, 4, &buf, 1);
-			if (ret)
-				break;
-			if (buf != 0x8)
-				return -EREMOTEIO;
-		}
-	}
-	return ret;
-}
-
-static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	u8 b = 0;
-	if (onoff)
-		return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0);
-	else
-		return 0;
-}
-
-static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	int rc = 0;
-
-	rc = cxusb_power_ctrl(d, onoff);
-	if (!onoff)
-		cxusb_nano2_led(d, 0);
-
-	return rc;
-}
-
-static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	int ret;
-	u8  b;
-	ret = cxusb_power_ctrl(d, onoff);
-	if (!onoff)
-		return ret;
-
-	msleep(128);
-	cxusb_ctrl_msg(d, CMD_DIGITAL, NULL, 0, &b, 1);
-	msleep(100);
-	return ret;
-}
-
-static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	u8 buf[2] = { 0x03, 0x00 };
-	if (onoff)
-		cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, buf, 2, NULL, 0);
-	else
-		cxusb_ctrl_msg(adap->dev, CMD_STREAMING_OFF, NULL, 0, NULL, 0);
-
-	return 0;
-}
-
-static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	if (onoff)
-		cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_ON, NULL, 0, NULL, 0);
-	else
-		cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_OFF,
-			       NULL, 0, NULL, 0);
-	return 0;
-}
-
-static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d)
-{
-	int       ep = d->props.generic_bulk_ctrl_endpoint;
-	const int timeout = 100;
-	const int junk_len = 32;
-	u8        *junk;
-	int       rd_count;
-
-	/* Discard remaining data in video pipe */
-	junk = kmalloc(junk_len, GFP_KERNEL);
-	if (!junk)
-		return;
-	while (1) {
-		if (usb_bulk_msg(d->udev,
-			usb_rcvbulkpipe(d->udev, ep),
-			junk, junk_len, &rd_count, timeout) < 0)
-			break;
-		if (!rd_count)
-			break;
-	}
-	kfree(junk);
-}
-
-static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d)
-{
-	struct usb_data_stream_properties *p = &d->props.adapter[0].fe[0].stream;
-	const int timeout = 100;
-	const int junk_len = p->u.bulk.buffersize;
-	u8        *junk;
-	int       rd_count;
-
-	/* Discard remaining data in video pipe */
-	junk = kmalloc(junk_len, GFP_KERNEL);
-	if (!junk)
-		return;
-	while (1) {
-		if (usb_bulk_msg(d->udev,
-			usb_rcvbulkpipe(d->udev, p->endpoint),
-			junk, junk_len, &rd_count, timeout) < 0)
-			break;
-		if (!rd_count)
-			break;
-	}
-	kfree(junk);
-}
-
-static int cxusb_d680_dmb_streaming_ctrl(
-		struct dvb_usb_adapter *adap, int onoff)
-{
-	if (onoff) {
-		u8 buf[2] = { 0x03, 0x00 };
-		cxusb_d680_dmb_drain_video(adap->dev);
-		return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON,
-			buf, sizeof(buf), NULL, 0);
-	} else {
-		int ret = cxusb_ctrl_msg(adap->dev,
-			CMD_STREAMING_OFF, NULL, 0, NULL, 0);
-		return ret;
-	}
-}
-
-static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
-{
-	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
-	u8 ircode[4];
-	int i;
-
-	cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4);
-
-	*event = 0;
-	*state = REMOTE_NO_KEY_PRESSED;
-
-	for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
-		if (rc5_custom(&keymap[i]) == ircode[2] &&
-		    rc5_data(&keymap[i]) == ircode[3]) {
-			*event = keymap[i].keycode;
-			*state = REMOTE_KEY_PRESSED;
-
-			return 0;
-		}
-	}
-
-	return 0;
-}
-
-static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
-				    int *state)
-{
-	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
-	u8 ircode[4];
-	int i;
-	struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
-			       .buf = ircode, .len = 4 };
-
-	*event = 0;
-	*state = REMOTE_NO_KEY_PRESSED;
-
-	if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1)
-		return 0;
-
-	for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
-		if (rc5_custom(&keymap[i]) == ircode[1] &&
-		    rc5_data(&keymap[i]) == ircode[2]) {
-			*event = keymap[i].keycode;
-			*state = REMOTE_KEY_PRESSED;
-
-			return 0;
-		}
-	}
-
-	return 0;
-}
-
-static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
-		int *state)
-{
-	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
-	u8 ircode[2];
-	int i;
-
-	*event = 0;
-	*state = REMOTE_NO_KEY_PRESSED;
-
-	if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0)
-		return 0;
-
-	for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
-		if (rc5_custom(&keymap[i]) == ircode[0] &&
-		    rc5_data(&keymap[i]) == ircode[1]) {
-			*event = keymap[i].keycode;
-			*state = REMOTE_KEY_PRESSED;
-
-			return 0;
-		}
-	}
-
-	return 0;
-}
-
-static struct rc_map_table rc_map_dvico_mce_table[] = {
-	{ 0xfe02, KEY_TV },
-	{ 0xfe0e, KEY_MP3 },
-	{ 0xfe1a, KEY_DVD },
-	{ 0xfe1e, KEY_FAVORITES },
-	{ 0xfe16, KEY_SETUP },
-	{ 0xfe46, KEY_POWER2 },
-	{ 0xfe0a, KEY_EPG },
-	{ 0xfe49, KEY_BACK },
-	{ 0xfe4d, KEY_MENU },
-	{ 0xfe51, KEY_UP },
-	{ 0xfe5b, KEY_LEFT },
-	{ 0xfe5f, KEY_RIGHT },
-	{ 0xfe53, KEY_DOWN },
-	{ 0xfe5e, KEY_OK },
-	{ 0xfe59, KEY_INFO },
-	{ 0xfe55, KEY_TAB },
-	{ 0xfe0f, KEY_PREVIOUSSONG },/* Replay */
-	{ 0xfe12, KEY_NEXTSONG },	/* Skip */
-	{ 0xfe42, KEY_ENTER	 },	/* Windows/Start */
-	{ 0xfe15, KEY_VOLUMEUP },
-	{ 0xfe05, KEY_VOLUMEDOWN },
-	{ 0xfe11, KEY_CHANNELUP },
-	{ 0xfe09, KEY_CHANNELDOWN },
-	{ 0xfe52, KEY_CAMERA },
-	{ 0xfe5a, KEY_TUNER },	/* Live */
-	{ 0xfe19, KEY_OPEN },
-	{ 0xfe0b, KEY_1 },
-	{ 0xfe17, KEY_2 },
-	{ 0xfe1b, KEY_3 },
-	{ 0xfe07, KEY_4 },
-	{ 0xfe50, KEY_5 },
-	{ 0xfe54, KEY_6 },
-	{ 0xfe48, KEY_7 },
-	{ 0xfe4c, KEY_8 },
-	{ 0xfe58, KEY_9 },
-	{ 0xfe13, KEY_ANGLE },	/* Aspect */
-	{ 0xfe03, KEY_0 },
-	{ 0xfe1f, KEY_ZOOM },
-	{ 0xfe43, KEY_REWIND },
-	{ 0xfe47, KEY_PLAYPAUSE },
-	{ 0xfe4f, KEY_FASTFORWARD },
-	{ 0xfe57, KEY_MUTE },
-	{ 0xfe0d, KEY_STOP },
-	{ 0xfe01, KEY_RECORD },
-	{ 0xfe4e, KEY_POWER },
-};
-
-static struct rc_map_table rc_map_dvico_portable_table[] = {
-	{ 0xfc02, KEY_SETUP },       /* Profile */
-	{ 0xfc43, KEY_POWER2 },
-	{ 0xfc06, KEY_EPG },
-	{ 0xfc5a, KEY_BACK },
-	{ 0xfc05, KEY_MENU },
-	{ 0xfc47, KEY_INFO },
-	{ 0xfc01, KEY_TAB },
-	{ 0xfc42, KEY_PREVIOUSSONG },/* Replay */
-	{ 0xfc49, KEY_VOLUMEUP },
-	{ 0xfc09, KEY_VOLUMEDOWN },
-	{ 0xfc54, KEY_CHANNELUP },
-	{ 0xfc0b, KEY_CHANNELDOWN },
-	{ 0xfc16, KEY_CAMERA },
-	{ 0xfc40, KEY_TUNER },	/* ATV/DTV */
-	{ 0xfc45, KEY_OPEN },
-	{ 0xfc19, KEY_1 },
-	{ 0xfc18, KEY_2 },
-	{ 0xfc1b, KEY_3 },
-	{ 0xfc1a, KEY_4 },
-	{ 0xfc58, KEY_5 },
-	{ 0xfc59, KEY_6 },
-	{ 0xfc15, KEY_7 },
-	{ 0xfc14, KEY_8 },
-	{ 0xfc17, KEY_9 },
-	{ 0xfc44, KEY_ANGLE },	/* Aspect */
-	{ 0xfc55, KEY_0 },
-	{ 0xfc07, KEY_ZOOM },
-	{ 0xfc0a, KEY_REWIND },
-	{ 0xfc08, KEY_PLAYPAUSE },
-	{ 0xfc4b, KEY_FASTFORWARD },
-	{ 0xfc5b, KEY_MUTE },
-	{ 0xfc04, KEY_STOP },
-	{ 0xfc56, KEY_RECORD },
-	{ 0xfc57, KEY_POWER },
-	{ 0xfc41, KEY_UNKNOWN },    /* INPUT */
-	{ 0xfc00, KEY_UNKNOWN },    /* HD */
-};
-
-static struct rc_map_table rc_map_d680_dmb_table[] = {
-	{ 0x0038, KEY_UNKNOWN },	/* TV/AV */
-	{ 0x080c, KEY_ZOOM },
-	{ 0x0800, KEY_0 },
-	{ 0x0001, KEY_1 },
-	{ 0x0802, KEY_2 },
-	{ 0x0003, KEY_3 },
-	{ 0x0804, KEY_4 },
-	{ 0x0005, KEY_5 },
-	{ 0x0806, KEY_6 },
-	{ 0x0007, KEY_7 },
-	{ 0x0808, KEY_8 },
-	{ 0x0009, KEY_9 },
-	{ 0x000a, KEY_MUTE },
-	{ 0x0829, KEY_BACK },
-	{ 0x0012, KEY_CHANNELUP },
-	{ 0x0813, KEY_CHANNELDOWN },
-	{ 0x002b, KEY_VOLUMEUP },
-	{ 0x082c, KEY_VOLUMEDOWN },
-	{ 0x0020, KEY_UP },
-	{ 0x0821, KEY_DOWN },
-	{ 0x0011, KEY_LEFT },
-	{ 0x0810, KEY_RIGHT },
-	{ 0x000d, KEY_OK },
-	{ 0x081f, KEY_RECORD },
-	{ 0x0017, KEY_PLAYPAUSE },
-	{ 0x0816, KEY_PLAYPAUSE },
-	{ 0x000b, KEY_STOP },
-	{ 0x0827, KEY_FASTFORWARD },
-	{ 0x0026, KEY_REWIND },
-	{ 0x081e, KEY_UNKNOWN },    /* Time Shift */
-	{ 0x000e, KEY_UNKNOWN },    /* Snapshot */
-	{ 0x082d, KEY_UNKNOWN },    /* Mouse Cursor */
-	{ 0x000f, KEY_UNKNOWN },    /* Minimize/Maximize */
-	{ 0x0814, KEY_UNKNOWN },    /* Shuffle */
-	{ 0x0025, KEY_POWER },
-};
-
-static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
-{
-	static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x28 };
-	static u8 reset []         = { RESET,      0x80 };
-	static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
-	static u8 agc_cfg []       = { AGC_TARGET, 0x28, 0x20 };
-	static u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
-	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
-
-	mt352_write(fe, clock_config,   sizeof(clock_config));
-	udelay(200);
-	mt352_write(fe, reset,          sizeof(reset));
-	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
-
-	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
-	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
-	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
-
-	return 0;
-}
-
-static int cxusb_mt352_demod_init(struct dvb_frontend* fe)
-{	/* used in both lgz201 and th7579 */
-	static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x29 };
-	static u8 reset []         = { RESET,      0x80 };
-	static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
-	static u8 agc_cfg []       = { AGC_TARGET, 0x24, 0x20 };
-	static u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
-	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
-
-	mt352_write(fe, clock_config,   sizeof(clock_config));
-	udelay(200);
-	mt352_write(fe, reset,          sizeof(reset));
-	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
-
-	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
-	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
-	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
-	return 0;
-}
-
-static struct cx22702_config cxusb_cx22702_config = {
-	.demod_address = 0x63,
-	.output_mode = CX22702_PARALLEL_OUTPUT,
-};
-
-static struct lgdt330x_config cxusb_lgdt3303_config = {
-	.demod_address = 0x0e,
-	.demod_chip    = LGDT3303,
-};
-
-static struct lgdt330x_config cxusb_aver_lgdt3303_config = {
-	.demod_address       = 0x0e,
-	.demod_chip          = LGDT3303,
-	.clock_polarity_flip = 2,
-};
-
-static struct mt352_config cxusb_dee1601_config = {
-	.demod_address = 0x0f,
-	.demod_init    = cxusb_dee1601_demod_init,
-};
-
-static struct zl10353_config cxusb_zl10353_dee1601_config = {
-	.demod_address = 0x0f,
-	.parallel_ts = 1,
-};
-
-static struct mt352_config cxusb_mt352_config = {
-	/* used in both lgz201 and th7579 */
-	.demod_address = 0x0f,
-	.demod_init    = cxusb_mt352_demod_init,
-};
-
-static struct zl10353_config cxusb_zl10353_xc3028_config = {
-	.demod_address = 0x0f,
-	.if2 = 45600,
-	.no_tuner = 1,
-	.parallel_ts = 1,
-};
-
-static struct zl10353_config cxusb_zl10353_xc3028_config_no_i2c_gate = {
-	.demod_address = 0x0f,
-	.if2 = 45600,
-	.no_tuner = 1,
-	.parallel_ts = 1,
-	.disable_i2c_gate_ctrl = 1,
-};
-
-static struct mt352_config cxusb_mt352_xc3028_config = {
-	.demod_address = 0x0f,
-	.if2 = 4560,
-	.no_tuner = 1,
-	.demod_init = cxusb_mt352_demod_init,
-};
-
-/* FIXME: needs tweaking */
-static struct mxl5005s_config aver_a868r_tuner = {
-	.i2c_address     = 0x63,
-	.if_freq         = 6000000UL,
-	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
-	.agc_mode        = MXL_SINGLE_AGC,
-	.tracking_filter = MXL_TF_C,
-	.rssi_enable     = MXL_RSSI_ENABLE,
-	.cap_select      = MXL_CAP_SEL_ENABLE,
-	.div_out         = MXL_DIV_OUT_4,
-	.clock_out       = MXL_CLOCK_OUT_DISABLE,
-	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
-	.top		 = MXL5005S_TOP_25P2,
-	.mod_mode        = MXL_DIGITAL_MODE,
-	.if_mode         = MXL_ZERO_IF,
-	.AgcMasterByte   = 0x00,
-};
-
-/* FIXME: needs tweaking */
-static struct mxl5005s_config d680_dmb_tuner = {
-	.i2c_address     = 0x63,
-	.if_freq         = 36125000UL,
-	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
-	.agc_mode        = MXL_SINGLE_AGC,
-	.tracking_filter = MXL_TF_C,
-	.rssi_enable     = MXL_RSSI_ENABLE,
-	.cap_select      = MXL_CAP_SEL_ENABLE,
-	.div_out         = MXL_DIV_OUT_4,
-	.clock_out       = MXL_CLOCK_OUT_DISABLE,
-	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
-	.top		 = MXL5005S_TOP_25P2,
-	.mod_mode        = MXL_DIGITAL_MODE,
-	.if_mode         = MXL_ZERO_IF,
-	.AgcMasterByte   = 0x00,
-};
-
-static struct max2165_config mygica_d689_max2165_cfg = {
-	.i2c_address = 0x60,
-	.osc_clk = 20
-};
-
-/* Callbacks for DVB USB */
-static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe,
-		   &adap->dev->i2c_adap, 0x61,
-		   TUNER_PHILIPS_FMD1216ME_MK3);
-	return 0;
-}
-
-static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61,
-		   NULL, DVB_PLL_THOMSON_DTT7579);
-	return 0;
-}
-
-static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_LG_Z201);
-	return 0;
-}
-
-static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
-		   NULL, DVB_PLL_THOMSON_DTT7579);
-	return 0;
-}
-
-static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe,
-		   &adap->dev->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF);
-	return 0;
-}
-
-static int dvico_bluebird_xc2028_callback(void *ptr, int component,
-					  int command, int arg)
-{
-	struct dvb_usb_adapter *adap = ptr;
-	struct dvb_usb_device *d = adap->dev;
-
-	switch (command) {
-	case XC2028_TUNER_RESET:
-		deb_info("%s: XC2028_TUNER_RESET %d\n", __func__, arg);
-		cxusb_bluebird_gpio_pulse(d, 0x01, 1);
-		break;
-	case XC2028_RESET_CLK:
-		deb_info("%s: XC2028_RESET_CLK %d\n", __func__, arg);
-		break;
-	default:
-		deb_info("%s: unknown command %d, arg %d\n", __func__,
-			 command, arg);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct dvb_frontend	 *fe;
-	struct xc2028_config	  cfg = {
-		.i2c_adap  = &adap->dev->i2c_adap,
-		.i2c_addr  = 0x61,
-	};
-	static struct xc2028_ctrl ctl = {
-		.fname       = XC2028_DEFAULT_FIRMWARE,
-		.max_len     = 64,
-		.demod       = XC3028_FE_ZARLINK456,
-	};
-
-	/* FIXME: generalize & move to common area */
-	adap->fe_adap[0].fe->callback = dvico_bluebird_xc2028_callback;
-
-	fe = dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &cfg);
-	if (fe == NULL || fe->ops.tuner_ops.set_config == NULL)
-		return -EIO;
-
-	fe->ops.tuner_ops.set_config(fe, &ctl);
-
-	return 0;
-}
-
-static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
-		   &adap->dev->i2c_adap, &aver_a868r_tuner);
-	return 0;
-}
-
-static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct dvb_frontend *fe;
-	fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
-			&adap->dev->i2c_adap, &d680_dmb_tuner);
-	return (fe == NULL) ? -EIO : 0;
-}
-
-static int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct dvb_frontend *fe;
-	fe = dvb_attach(max2165_attach, adap->fe_adap[0].fe,
-			&adap->dev->i2c_adap, &mygica_d689_max2165_cfg);
-	return (fe == NULL) ? -EIO : 0;
-}
-
-static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	u8 b;
-	if (usb_set_interface(adap->dev->udev, 0, 6) < 0)
-		err("set interface failed");
-
-	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1);
-
-	adap->fe_adap[0].fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config,
-					 &adap->dev->i2c_adap);
-	if ((adap->fe_adap[0].fe) != NULL)
-		return 0;
-
-	return -EIO;
-}
-
-static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	if (usb_set_interface(adap->dev->udev, 0, 7) < 0)
-		err("set interface failed");
-
-	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
-
-	adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach,
-					 &cxusb_lgdt3303_config,
-					 &adap->dev->i2c_adap);
-	if ((adap->fe_adap[0].fe) != NULL)
-		return 0;
-
-	return -EIO;
-}
-
-static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config,
-			      &adap->dev->i2c_adap);
-	if (adap->fe_adap[0].fe != NULL)
-		return 0;
-
-	return -EIO;
-}
-
-static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	/* used in both lgz201 and th7579 */
-	if (usb_set_interface(adap->dev->udev, 0, 0) < 0)
-		err("set interface failed");
-
-	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
-
-	adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_mt352_config,
-					 &adap->dev->i2c_adap);
-	if ((adap->fe_adap[0].fe) != NULL)
-		return 0;
-
-	return -EIO;
-}
-
-static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	if (usb_set_interface(adap->dev->udev, 0, 0) < 0)
-		err("set interface failed");
-
-	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
-
-	adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_dee1601_config,
-					 &adap->dev->i2c_adap);
-	if ((adap->fe_adap[0].fe) != NULL)
-		return 0;
-
-	adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
-					 &cxusb_zl10353_dee1601_config,
-					 &adap->dev->i2c_adap);
-	if ((adap->fe_adap[0].fe) != NULL)
-		return 0;
-
-	return -EIO;
-}
-
-static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	u8 ircode[4];
-	int i;
-	struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
-			       .buf = ircode, .len = 4 };
-
-	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
-		err("set interface failed");
-
-	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
-
-	/* reset the tuner and demodulator */
-	cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0);
-	cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
-	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
-
-	adap->fe_adap[0].fe =
-		dvb_attach(zl10353_attach,
-			   &cxusb_zl10353_xc3028_config_no_i2c_gate,
-			   &adap->dev->i2c_adap);
-	if ((adap->fe_adap[0].fe) == NULL)
-		return -EIO;
-
-	/* try to determine if there is no IR decoder on the I2C bus */
-	for (i = 0; adap->dev->props.rc.legacy.rc_map_table != NULL && i < 5; i++) {
-		msleep(20);
-		if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1)
-			goto no_IR;
-		if (ircode[0] == 0 && ircode[1] == 0)
-			continue;
-		if (ircode[2] + ircode[3] != 0xff) {
-no_IR:
-			adap->dev->props.rc.legacy.rc_map_table = NULL;
-			info("No IR receiver detected on this device.");
-			break;
-		}
-	}
-
-	return 0;
-}
-
-static struct dibx000_agc_config dib7070_agc_config = {
-	.band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
-
-	/*
-	 * P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5,
-	 * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
-	 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0
-	 */
-	.setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) |
-		 (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
-	.inv_gain = 600,
-	.time_stabiliz = 10,
-	.alpha_level = 0,
-	.thlock = 118,
-	.wbd_inv = 0,
-	.wbd_ref = 3530,
-	.wbd_sel = 1,
-	.wbd_alpha = 5,
-	.agc1_max = 65535,
-	.agc1_min = 0,
-	.agc2_max = 65535,
-	.agc2_min = 0,
-	.agc1_pt1 = 0,
-	.agc1_pt2 = 40,
-	.agc1_pt3 = 183,
-	.agc1_slope1 = 206,
-	.agc1_slope2 = 255,
-	.agc2_pt1 = 72,
-	.agc2_pt2 = 152,
-	.agc2_slope1 = 88,
-	.agc2_slope2 = 90,
-	.alpha_mant = 17,
-	.alpha_exp = 27,
-	.beta_mant = 23,
-	.beta_exp = 51,
-	.perform_agc_softsplit = 0,
-};
-
-static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
-	.internal = 60000,
-	.sampling = 15000,
-	.pll_prediv = 1,
-	.pll_ratio = 20,
-	.pll_range = 3,
-	.pll_reset = 1,
-	.pll_bypass = 0,
-	.enable_refdiv = 0,
-	.bypclk_div = 0,
-	.IO_CLK_en_core = 1,
-	.ADClkSrc = 1,
-	.modulo = 2,
-	/* refsel, sel, freq_15k */
-	.sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
-	.ifreq = (0 << 25) | 0,
-	.timf = 20452225,
-	.xtal_hz = 12000000,
-};
-
-static struct dib7000p_config cxusb_dualdig4_rev2_config = {
-	.output_mode = OUTMODE_MPEG2_PAR_GATED_CLK,
-	.output_mpeg2_in_188_bytes = 1,
-
-	.agc_config_count = 1,
-	.agc = &dib7070_agc_config,
-	.bw  = &dib7070_bw_config_12_mhz,
-	.tuner_is_baseband = 1,
-	.spur_protect = 1,
-
-	.gpio_dir = 0xfcef,
-	.gpio_val = 0x0110,
-
-	.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
-
-	.hostbus_diversity = 1,
-};
-
-static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
-		err("set interface failed");
-
-	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
-
-	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
-
-	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
-				     &cxusb_dualdig4_rev2_config) < 0) {
-		printk(KERN_WARNING "Unable to enumerate dib7000p\n");
-		return -ENODEV;
-	}
-
-	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
-			      &cxusb_dualdig4_rev2_config);
-	if (adap->fe_adap[0].fe == NULL)
-		return -EIO;
-
-	return 0;
-}
-
-static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
-{
-	return dib7000p_set_gpio(fe, 8, 0, !onoff);
-}
-
-static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
-{
-	return 0;
-}
-
-static struct dib0070_config dib7070p_dib0070_config = {
-	.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
-	.reset = dib7070_tuner_reset,
-	.sleep = dib7070_tuner_sleep,
-	.clock_khz = 12000,
-};
-
-struct dib0700_adapter_state {
-	int (*set_param_save) (struct dvb_frontend *);
-};
-
-static int dib7070_set_param_override(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct dib0700_adapter_state *state = adap->priv;
-
-	u16 offset;
-	u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
-	switch (band) {
-	case BAND_VHF: offset = 950; break;
-	default:
-	case BAND_UHF: offset = 550; break;
-	}
-
-	dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
-
-	return state->set_param_save(fe);
-}
-
-static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_adapter_state *st = adap->priv;
-	struct i2c_adapter *tun_i2c =
-		dib7000p_get_i2c_master(adap->fe_adap[0].fe,
-					DIBX000_I2C_INTERFACE_TUNER, 1);
-
-	if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
-	    &dib7070p_dib0070_config) == NULL)
-		return -ENODEV;
-
-	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
-	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7070_set_param_override;
-	return 0;
-}
-
-static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
-		err("set interface failed");
-
-	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
-
-	/* reset the tuner and demodulator */
-	cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0);
-	cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
-	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
-
-	adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
-					 &cxusb_zl10353_xc3028_config,
-					 &adap->dev->i2c_adap);
-	if ((adap->fe_adap[0].fe) != NULL)
-		return 0;
-
-	adap->fe_adap[0].fe = dvb_attach(mt352_attach,
-					 &cxusb_mt352_xc3028_config,
-					 &adap->dev->i2c_adap);
-	if ((adap->fe_adap[0].fe) != NULL)
-		return 0;
-
-	return -EIO;
-}
-
-static struct lgs8gxx_config d680_lgs8gl5_cfg = {
-	.prod = LGS8GXX_PROD_LGS8GL5,
-	.demod_address = 0x19,
-	.serial_ts = 0,
-	.ts_clk_pol = 0,
-	.ts_clk_gated = 1,
-	.if_clk_freq = 30400, /* 30.4 MHz */
-	.if_freq = 5725, /* 5.725 MHz */
-	.if_neg_center = 0,
-	.ext_adc = 0,
-	.adc_signed = 0,
-	.if_neg_edge = 0,
-};
-
-static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct dvb_usb_device *d = adap->dev;
-	int n;
-
-	/* Select required USB configuration */
-	if (usb_set_interface(d->udev, 0, 0) < 0)
-		err("set interface failed");
-
-	/* Unblock all USB pipes */
-	usb_clear_halt(d->udev,
-		usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
-	usb_clear_halt(d->udev,
-		usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
-	usb_clear_halt(d->udev,
-		usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint));
-
-	/* Drain USB pipes to avoid hang after reboot */
-	for (n = 0;  n < 5;  n++) {
-		cxusb_d680_dmb_drain_message(d);
-		cxusb_d680_dmb_drain_video(d);
-		msleep(200);
-	}
-
-	/* Reset the tuner */
-	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) {
-		err("clear tuner gpio failed");
-		return -EIO;
-	}
-	msleep(100);
-	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) {
-		err("set tuner gpio failed");
-		return -EIO;
-	}
-	msleep(100);
-
-	/* Attach frontend */
-	adap->fe_adap[0].fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap);
-	if (adap->fe_adap[0].fe == NULL)
-		return -EIO;
-
-	return 0;
-}
-
-static struct atbm8830_config mygica_d689_atbm8830_cfg = {
-	.prod = ATBM8830_PROD_8830,
-	.demod_address = 0x40,
-	.serial_ts = 0,
-	.ts_sampling_edge = 1,
-	.ts_clk_gated = 0,
-	.osc_clk_freq = 30400, /* in kHz */
-	.if_freq = 0, /* zero IF */
-	.zif_swap_iq = 1,
-	.agc_min = 0x2E,
-	.agc_max = 0x90,
-	.agc_hold_loop = 0,
-};
-
-static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct dvb_usb_device *d = adap->dev;
-
-	/* Select required USB configuration */
-	if (usb_set_interface(d->udev, 0, 0) < 0)
-		err("set interface failed");
-
-	/* Unblock all USB pipes */
-	usb_clear_halt(d->udev,
-		usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
-	usb_clear_halt(d->udev,
-		usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
-	usb_clear_halt(d->udev,
-		usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint));
-
-
-	/* Reset the tuner */
-	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) {
-		err("clear tuner gpio failed");
-		return -EIO;
-	}
-	msleep(100);
-	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) {
-		err("set tuner gpio failed");
-		return -EIO;
-	}
-	msleep(100);
-
-	/* Attach frontend */
-	adap->fe_adap[0].fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg,
-		&d->i2c_adap);
-	if (adap->fe_adap[0].fe == NULL)
-		return -EIO;
-
-	return 0;
-}
-
-/*
- * DViCO has shipped two devices with the same USB ID, but only one of them
- * needs a firmware download.  Check the device class details to see if they
- * have non-default values to decide whether the device is actually cold or
- * not, and forget a match if it turns out we selected the wrong device.
- */
-static int bluebird_fx2_identify_state(struct usb_device *udev,
-				       struct dvb_usb_device_properties *props,
-				       struct dvb_usb_device_description **desc,
-				       int *cold)
-{
-	int wascold = *cold;
-
-	*cold = udev->descriptor.bDeviceClass == 0xff &&
-		udev->descriptor.bDeviceSubClass == 0xff &&
-		udev->descriptor.bDeviceProtocol == 0xff;
-
-	if (*cold && !wascold)
-		*desc = NULL;
-
-	return 0;
-}
-
-/*
- * DViCO bluebird firmware needs the "warm" product ID to be patched into the
- * firmware file before download.
- */
-
-static const int dvico_firmware_id_offsets[] = { 6638, 3204 };
-static int bluebird_patch_dvico_firmware_download(struct usb_device *udev,
-						  const struct firmware *fw)
-{
-	int pos;
-
-	for (pos = 0; pos < ARRAY_SIZE(dvico_firmware_id_offsets); pos++) {
-		int idoff = dvico_firmware_id_offsets[pos];
-
-		if (fw->size < idoff + 4)
-			continue;
-
-		if (fw->data[idoff] == (USB_VID_DVICO & 0xff) &&
-		    fw->data[idoff + 1] == USB_VID_DVICO >> 8) {
-			struct firmware new_fw;
-			u8 *new_fw_data = vmalloc(fw->size);
-			int ret;
-
-			if (!new_fw_data)
-				return -ENOMEM;
-
-			memcpy(new_fw_data, fw->data, fw->size);
-			new_fw.size = fw->size;
-			new_fw.data = new_fw_data;
-
-			new_fw_data[idoff + 2] =
-				le16_to_cpu(udev->descriptor.idProduct) + 1;
-			new_fw_data[idoff + 3] =
-				le16_to_cpu(udev->descriptor.idProduct) >> 8;
-
-			ret = usb_cypress_load_firmware(udev, &new_fw,
-							CYPRESS_FX2);
-			vfree(new_fw_data);
-			return ret;
-		}
-	}
-
-	return -EINVAL;
-}
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties cxusb_medion_properties;
-static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties;
-static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties;
-static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties;
-static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties;
-static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties;
-static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties;
-static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
-static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
-static struct dvb_usb_device_properties cxusb_aver_a868r_properties;
-static struct dvb_usb_device_properties cxusb_d680_dmb_properties;
-static struct dvb_usb_device_properties cxusb_mygica_d689_properties;
-
-static int cxusb_probe(struct usb_interface *intf,
-		       const struct usb_device_id *id)
-{
-	if (0 == dvb_usb_device_init(intf, &cxusb_medion_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgh064f_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_dee1601_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgz201_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_dtt7579_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_dualdig4_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_nano2_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf,
-				&cxusb_bluebird_nano2_needsfirmware_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf,
-				     &cxusb_bluebird_dualdig4_rev2_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &cxusb_mygica_d689_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0)
-		return 0;
-
-	return -EINVAL;
-}
-
-static struct usb_device_id cxusb_table [] = {
-	{ USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
-	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) },
-	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) },
-	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD) },
-	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM) },
-	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) },
-	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) },
-	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) },
-	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) },
-	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) },
-	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) },
-	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) },
-	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) },
-	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) },
-	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) },
-	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) },
-	{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) },
-	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) },
-	{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) },
-	{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) },
-	{}		/* Terminating entry */
-};
-MODULE_DEVICE_TABLE (usb, cxusb_table);
-
-static struct dvb_usb_device_properties cxusb_medion_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = CYPRESS_FX2,
-
-	.size_of_priv     = sizeof(struct cxusb_state),
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = cxusb_streaming_ctrl,
-			.frontend_attach  = cxusb_cx22702_frontend_attach,
-			.tuner_attach     = cxusb_fmd1216me_tuner_attach,
-			/* parameter for the MPEG2-data transfer */
-					.stream = {
-						.type = USB_BULK,
-				.count = 5,
-				.endpoint = 0x02,
-				.u = {
-					.bulk = {
-						.buffersize = 8192,
-					}
-				}
-			},
-		}},
-		},
-	},
-	.power_ctrl       = cxusb_power_ctrl,
-
-	.i2c_algo         = &cxusb_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 1,
-	.devices = {
-		{   "Medion MD95700 (MDUSBTV-HYBRID)",
-			{ NULL },
-			{ &cxusb_table[0], NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl          = DEVICE_SPECIFIC,
-	.firmware          = "dvb-usb-bluebird-01.fw",
-	.download_firmware = bluebird_patch_dvico_firmware_download,
-	/* use usb alt setting 0 for EP4 transfer (dvb-t),
-	   use usb alt setting 7 for EP2 transfer (atsc) */
-
-	.size_of_priv     = sizeof(struct cxusb_state),
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = cxusb_streaming_ctrl,
-			.frontend_attach  = cxusb_lgdt3303_frontend_attach,
-			.tuner_attach     = cxusb_lgh064f_tuner_attach,
-
-			/* parameter for the MPEG2-data transfer */
-					.stream = {
-						.type = USB_BULK,
-				.count = 5,
-				.endpoint = 0x02,
-				.u = {
-					.bulk = {
-						.buffersize = 8192,
-					}
-				}
-			},
-		}},
-		},
-	},
-
-	.power_ctrl       = cxusb_bluebird_power_ctrl,
-
-	.i2c_algo         = &cxusb_i2c_algo,
-
-	.rc.legacy = {
-		.rc_interval      = 100,
-		.rc_map_table     = rc_map_dvico_portable_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_dvico_portable_table),
-		.rc_query         = cxusb_rc_query,
-	},
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 1,
-	.devices = {
-		{   "DViCO FusionHDTV5 USB Gold",
-			{ &cxusb_table[1], NULL },
-			{ &cxusb_table[2], NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl          = DEVICE_SPECIFIC,
-	.firmware          = "dvb-usb-bluebird-01.fw",
-	.download_firmware = bluebird_patch_dvico_firmware_download,
-	/* use usb alt setting 0 for EP4 transfer (dvb-t),
-	   use usb alt setting 7 for EP2 transfer (atsc) */
-
-	.size_of_priv     = sizeof(struct cxusb_state),
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = cxusb_streaming_ctrl,
-			.frontend_attach  = cxusb_dee1601_frontend_attach,
-			.tuner_attach     = cxusb_dee1601_tuner_attach,
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 5,
-				.endpoint = 0x04,
-				.u = {
-					.bulk = {
-						.buffersize = 8192,
-					}
-				}
-			},
-		}},
-		},
-	},
-
-	.power_ctrl       = cxusb_bluebird_power_ctrl,
-
-	.i2c_algo         = &cxusb_i2c_algo,
-
-	.rc.legacy = {
-		.rc_interval      = 150,
-		.rc_map_table     = rc_map_dvico_mce_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_dvico_mce_table),
-		.rc_query         = cxusb_rc_query,
-	},
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 3,
-	.devices = {
-		{   "DViCO FusionHDTV DVB-T Dual USB",
-			{ &cxusb_table[3], NULL },
-			{ &cxusb_table[4], NULL },
-		},
-		{   "DigitalNow DVB-T Dual USB",
-			{ &cxusb_table[9],  NULL },
-			{ &cxusb_table[10], NULL },
-		},
-		{   "DViCO FusionHDTV DVB-T Dual Digital 2",
-			{ &cxusb_table[11], NULL },
-			{ &cxusb_table[12], NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl          = DEVICE_SPECIFIC,
-	.firmware          = "dvb-usb-bluebird-01.fw",
-	.download_firmware = bluebird_patch_dvico_firmware_download,
-	/* use usb alt setting 0 for EP4 transfer (dvb-t),
-	   use usb alt setting 7 for EP2 transfer (atsc) */
-
-	.size_of_priv     = sizeof(struct cxusb_state),
-
-	.num_adapters = 2,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = cxusb_streaming_ctrl,
-			.frontend_attach  = cxusb_mt352_frontend_attach,
-			.tuner_attach     = cxusb_lgz201_tuner_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 5,
-				.endpoint = 0x04,
-				.u = {
-					.bulk = {
-						.buffersize = 8192,
-					}
-				}
-			},
-		}},
-		},
-	},
-	.power_ctrl       = cxusb_bluebird_power_ctrl,
-
-	.i2c_algo         = &cxusb_i2c_algo,
-
-	.rc.legacy = {
-		.rc_interval      = 100,
-		.rc_map_table     = rc_map_dvico_portable_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_dvico_portable_table),
-		.rc_query         = cxusb_rc_query,
-	},
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-	.num_device_descs = 1,
-	.devices = {
-		{   "DViCO FusionHDTV DVB-T USB (LGZ201)",
-			{ &cxusb_table[5], NULL },
-			{ &cxusb_table[6], NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl          = DEVICE_SPECIFIC,
-	.firmware          = "dvb-usb-bluebird-01.fw",
-	.download_firmware = bluebird_patch_dvico_firmware_download,
-	/* use usb alt setting 0 for EP4 transfer (dvb-t),
-	   use usb alt setting 7 for EP2 transfer (atsc) */
-
-	.size_of_priv     = sizeof(struct cxusb_state),
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = cxusb_streaming_ctrl,
-			.frontend_attach  = cxusb_mt352_frontend_attach,
-			.tuner_attach     = cxusb_dtt7579_tuner_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 5,
-				.endpoint = 0x04,
-				.u = {
-					.bulk = {
-						.buffersize = 8192,
-					}
-				}
-			},
-		}},
-		},
-	},
-	.power_ctrl       = cxusb_bluebird_power_ctrl,
-
-	.i2c_algo         = &cxusb_i2c_algo,
-
-	.rc.legacy = {
-		.rc_interval      = 100,
-		.rc_map_table     = rc_map_dvico_portable_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_dvico_portable_table),
-		.rc_query         = cxusb_rc_query,
-	},
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 1,
-	.devices = {
-		{   "DViCO FusionHDTV DVB-T USB (TH7579)",
-			{ &cxusb_table[7], NULL },
-			{ &cxusb_table[8], NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl         = CYPRESS_FX2,
-
-	.size_of_priv     = sizeof(struct cxusb_state),
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = cxusb_streaming_ctrl,
-			.frontend_attach  = cxusb_dualdig4_frontend_attach,
-			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 5,
-				.endpoint = 0x02,
-				.u = {
-					.bulk = {
-						.buffersize = 8192,
-					}
-				}
-			},
-		}},
-		},
-	},
-
-	.power_ctrl       = cxusb_power_ctrl,
-
-	.i2c_algo         = &cxusb_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.rc.legacy = {
-		.rc_interval      = 100,
-		.rc_map_table     = rc_map_dvico_mce_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_dvico_mce_table),
-		.rc_query         = cxusb_bluebird2_rc_query,
-	},
-
-	.num_device_descs = 1,
-	.devices = {
-		{   "DViCO FusionHDTV DVB-T Dual Digital 4",
-			{ NULL },
-			{ &cxusb_table[13], NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl         = CYPRESS_FX2,
-	.identify_state   = bluebird_fx2_identify_state,
-
-	.size_of_priv     = sizeof(struct cxusb_state),
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = cxusb_streaming_ctrl,
-			.frontend_attach  = cxusb_nano2_frontend_attach,
-			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 5,
-				.endpoint = 0x02,
-				.u = {
-					.bulk = {
-						.buffersize = 8192,
-					}
-				}
-			},
-		}},
-		},
-	},
-
-	.power_ctrl       = cxusb_nano2_power_ctrl,
-
-	.i2c_algo         = &cxusb_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.rc.legacy = {
-		.rc_interval      = 100,
-		.rc_map_table     = rc_map_dvico_portable_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_dvico_portable_table),
-		.rc_query         = cxusb_bluebird2_rc_query,
-	},
-
-	.num_device_descs = 1,
-	.devices = {
-		{   "DViCO FusionHDTV DVB-T NANO2",
-			{ NULL },
-			{ &cxusb_table[14], NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl          = DEVICE_SPECIFIC,
-	.firmware          = "dvb-usb-bluebird-02.fw",
-	.download_firmware = bluebird_patch_dvico_firmware_download,
-	.identify_state    = bluebird_fx2_identify_state,
-
-	.size_of_priv      = sizeof(struct cxusb_state),
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = cxusb_streaming_ctrl,
-			.frontend_attach  = cxusb_nano2_frontend_attach,
-			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 5,
-				.endpoint = 0x02,
-				.u = {
-					.bulk = {
-						.buffersize = 8192,
-					}
-				}
-			},
-		}},
-		},
-	},
-
-	.power_ctrl       = cxusb_nano2_power_ctrl,
-
-	.i2c_algo         = &cxusb_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.rc.legacy = {
-		.rc_interval      = 100,
-		.rc_map_table     = rc_map_dvico_portable_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_dvico_portable_table),
-		.rc_query         = cxusb_rc_query,
-	},
-
-	.num_device_descs = 1,
-	.devices = {
-		{   "DViCO FusionHDTV DVB-T NANO2 w/o firmware",
-			{ &cxusb_table[14], NULL },
-			{ &cxusb_table[15], NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties cxusb_aver_a868r_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl         = CYPRESS_FX2,
-
-	.size_of_priv     = sizeof(struct cxusb_state),
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = cxusb_aver_streaming_ctrl,
-			.frontend_attach  = cxusb_aver_lgdt3303_frontend_attach,
-			.tuner_attach     = cxusb_mxl5003s_tuner_attach,
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 5,
-				.endpoint = 0x04,
-				.u = {
-					.bulk = {
-						.buffersize = 8192,
-					}
-				}
-			},
-		}},
-		},
-	},
-	.power_ctrl       = cxusb_aver_power_ctrl,
-
-	.i2c_algo         = &cxusb_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 1,
-	.devices = {
-		{   "AVerMedia AVerTVHD Volar (A868R)",
-			{ NULL },
-			{ &cxusb_table[16], NULL },
-		},
-	}
-};
-
-static
-struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl         = CYPRESS_FX2,
-
-	.size_of_priv     = sizeof(struct cxusb_state),
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.size_of_priv    = sizeof(struct dib0700_adapter_state),
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl  = cxusb_streaming_ctrl,
-			.frontend_attach = cxusb_dualdig4_rev2_frontend_attach,
-			.tuner_attach    = cxusb_dualdig4_rev2_tuner_attach,
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 7,
-				.endpoint = 0x02,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-		},
-	},
-
-	.power_ctrl       = cxusb_bluebird_power_ctrl,
-
-	.i2c_algo         = &cxusb_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.rc.legacy = {
-		.rc_interval      = 100,
-		.rc_map_table     = rc_map_dvico_mce_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_dvico_mce_table),
-		.rc_query         = cxusb_rc_query,
-	},
-
-	.num_device_descs = 1,
-	.devices = {
-		{   "DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2)",
-			{ NULL },
-			{ &cxusb_table[17], NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl         = CYPRESS_FX2,
-
-	.size_of_priv     = sizeof(struct cxusb_state),
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = cxusb_d680_dmb_streaming_ctrl,
-			.frontend_attach  = cxusb_d680_dmb_frontend_attach,
-			.tuner_attach     = cxusb_d680_dmb_tuner_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 5,
-				.endpoint = 0x02,
-				.u = {
-					.bulk = {
-						.buffersize = 8192,
-					}
-				}
-			},
-		}},
-		},
-	},
-
-	.power_ctrl       = cxusb_d680_dmb_power_ctrl,
-
-	.i2c_algo         = &cxusb_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.rc.legacy = {
-		.rc_interval      = 100,
-		.rc_map_table     = rc_map_d680_dmb_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_d680_dmb_table),
-		.rc_query         = cxusb_d680_dmb_rc_query,
-	},
-
-	.num_device_descs = 1,
-	.devices = {
-		{
-			"Conexant DMB-TH Stick",
-			{ NULL },
-			{ &cxusb_table[18], NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl         = CYPRESS_FX2,
-
-	.size_of_priv     = sizeof(struct cxusb_state),
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = cxusb_d680_dmb_streaming_ctrl,
-			.frontend_attach  = cxusb_mygica_d689_frontend_attach,
-			.tuner_attach     = cxusb_mygica_d689_tuner_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 5,
-				.endpoint = 0x02,
-				.u = {
-					.bulk = {
-						.buffersize = 8192,
-					}
-				}
-			},
-		}},
-		},
-	},
-
-	.power_ctrl       = cxusb_d680_dmb_power_ctrl,
-
-	.i2c_algo         = &cxusb_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.rc.legacy = {
-		.rc_interval      = 100,
-		.rc_map_table     = rc_map_d680_dmb_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_d680_dmb_table),
-		.rc_query         = cxusb_d680_dmb_rc_query,
-	},
-
-	.num_device_descs = 1,
-	.devices = {
-		{
-			"Mygica D689 DMB-TH",
-			{ NULL },
-			{ &cxusb_table[19], NULL },
-		},
-	}
-};
-
-static struct usb_driver cxusb_driver = {
-	.name		= "dvb_usb_cxusb",
-	.probe		= cxusb_probe,
-	.disconnect     = dvb_usb_device_exit,
-	.id_table	= cxusb_table,
-};
-
-module_usb_driver(cxusb_driver);
-
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
-MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
-MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design");
-MODULE_VERSION("1.0-alpha");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h
deleted file mode 100644
index 1a51eaf..0000000
--- a/drivers/media/dvb/dvb-usb/cxusb.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef _DVB_USB_CXUSB_H_
-#define _DVB_USB_CXUSB_H_
-
-#define DVB_USB_LOG_PREFIX "cxusb"
-#include "dvb-usb.h"
-
-/* usb commands - some of it are guesses, don't have a reference yet */
-#define CMD_BLUEBIRD_GPIO_RW 0x05
-
-#define CMD_I2C_WRITE     0x08
-#define CMD_I2C_READ      0x09
-
-#define CMD_GPIO_READ     0x0d
-#define CMD_GPIO_WRITE    0x0e
-#define     GPIO_TUNER         0x02
-
-#define CMD_POWER_OFF     0xdc
-#define CMD_POWER_ON      0xde
-
-#define CMD_STREAMING_ON  0x36
-#define CMD_STREAMING_OFF 0x37
-
-#define CMD_AVER_STREAM_ON  0x18
-#define CMD_AVER_STREAM_OFF 0x19
-
-#define CMD_GET_IR_CODE   0x47
-
-#define CMD_ANALOG        0x50
-#define CMD_DIGITAL       0x51
-
-struct cxusb_state {
-	u8 gpio_write_state[3];
-};
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
deleted file mode 100644
index 7de125c..0000000
--- a/drivers/media/dvb/dvb-usb/dib0700.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
- *
- *	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, version 2.
- *
- *  Copyright (C) 2005-6 DiBcom, SA
- */
-#ifndef _DIB0700_H_
-#define _DIB0700_H_
-
-#define DVB_USB_LOG_PREFIX "dib0700"
-#include "dvb-usb.h"
-
-#include "dib07x0.h"
-
-extern int dvb_usb_dib0700_debug;
-#define deb_info(args...)   dprintk(dvb_usb_dib0700_debug,0x01,args)
-#define deb_fw(args...)     dprintk(dvb_usb_dib0700_debug,0x02,args)
-#define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args)
-#define deb_data(args...)   dprintk(dvb_usb_dib0700_debug,0x08,args)
-
-#define REQUEST_SET_USB_XFER_LEN    0x0 /* valid only for firmware version */
-					/* higher than 1.21 */
-#define REQUEST_I2C_READ            0x2
-#define REQUEST_I2C_WRITE           0x3
-#define REQUEST_POLL_RC             0x4 /* deprecated in firmware v1.20 */
-#define REQUEST_JUMPRAM             0x8
-#define REQUEST_SET_CLOCK           0xB
-#define REQUEST_SET_GPIO            0xC
-#define REQUEST_ENABLE_VIDEO        0xF
-	// 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog)
-	// 2 Byte: MPEG2 mode:  4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1)
-	// 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines)    4LSB(     "                "           )
-#define REQUEST_SET_I2C_PARAM       0x10
-#define REQUEST_SET_RC              0x11
-#define REQUEST_NEW_I2C_READ        0x12
-#define REQUEST_NEW_I2C_WRITE       0x13
-#define REQUEST_GET_VERSION         0x15
-
-struct dib0700_state {
-	u8 channel_state;
-	u16 mt2060_if1[2];
-	u8 rc_toggle;
-	u8 rc_counter;
-	u8 is_dib7000pc;
-	u8 fw_use_new_i2c_api;
-	u8 disable_streaming_master_mode;
-	u32 fw_version;
-	u32 nb_packet_buffer_size;
-	int (*read_status)(struct dvb_frontend *, fe_status_t *);
-	int (*sleep)(struct dvb_frontend* fe);
-	u8 buf[255];
-};
-
-extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
-			       u32 *romversion, u32 *ramversion, u32 *fwtype);
-extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val);
-extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3);
-extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen);
-extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw);
-extern int dib0700_rc_setup(struct dvb_usb_device *d);
-extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
-extern struct i2c_algorithm dib0700_i2c_algo;
-extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
-			struct dvb_usb_device_description **desc, int *cold);
-extern int dib0700_change_protocol(struct rc_dev *dev, u64 rc_type);
-extern int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz);
-
-extern int dib0700_device_count;
-extern int dvb_usb_dib0700_ir_proto;
-extern struct dvb_usb_device_properties dib0700_devices[];
-extern struct usb_device_id dib0700_usb_id_table[];
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
deleted file mode 100644
index 7e9e00f..0000000
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ /dev/null
@@ -1,845 +0,0 @@
-/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
- *
- *	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, version 2.
- *
- *  Copyright (C) 2005-6 DiBcom, SA
- */
-#include "dib0700.h"
-
-/* debug */
-int dvb_usb_dib0700_debug;
-module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
-
-static int nb_packet_buffer_size = 21;
-module_param(nb_packet_buffer_size, int, 0644);
-MODULE_PARM_DESC(nb_packet_buffer_size,
-	"Set the dib0700 driver data buffer size. This parameter "
-	"corresponds to the number of TS packets. The actual size of "
-	"the data buffer corresponds to this parameter "
-	"multiplied by 188 (default: 21)");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-
-int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
-			u32 *romversion, u32 *ramversion, u32 *fwtype)
-{
-	struct dib0700_state *st = d->priv;
-	int ret;
-
-	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
-		err("could not acquire lock");
-		return -EINTR;
-	}
-
-	ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
-				  REQUEST_GET_VERSION,
-				  USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
-				  st->buf, 16, USB_CTRL_GET_TIMEOUT);
-	if (hwversion != NULL)
-		*hwversion  = (st->buf[0] << 24)  | (st->buf[1] << 16)  |
-			(st->buf[2] << 8)  | st->buf[3];
-	if (romversion != NULL)
-		*romversion = (st->buf[4] << 24)  | (st->buf[5] << 16)  |
-			(st->buf[6] << 8)  | st->buf[7];
-	if (ramversion != NULL)
-		*ramversion = (st->buf[8] << 24)  | (st->buf[9] << 16)  |
-			(st->buf[10] << 8) | st->buf[11];
-	if (fwtype != NULL)
-		*fwtype     = (st->buf[12] << 24) | (st->buf[13] << 16) |
-			(st->buf[14] << 8) | st->buf[15];
-	mutex_unlock(&d->usb_mutex);
-	return ret;
-}
-
-/* expecting rx buffer: request data[0] data[1] ... data[2] */
-static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
-{
-	int status;
-
-	deb_data(">>> ");
-	debug_dump(tx, txlen, deb_data);
-
-	status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0),
-		tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen,
-		USB_CTRL_GET_TIMEOUT);
-
-	if (status != txlen)
-		deb_data("ep 0 write error (status = %d, len: %d)\n",status,txlen);
-
-	return status < 0 ? status : 0;
-}
-
-/* expecting tx buffer: request data[0] ... data[n] (n <= 4) */
-int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
-{
-	u16 index, value;
-	int status;
-
-	if (txlen < 2) {
-		err("tx buffer length is smaller than 2. Makes no sense.");
-		return -EINVAL;
-	}
-	if (txlen > 4) {
-		err("tx buffer length is larger than 4. Not supported.");
-		return -EINVAL;
-	}
-
-	deb_data(">>> ");
-	debug_dump(tx,txlen,deb_data);
-
-	value = ((txlen - 2) << 8) | tx[1];
-	index = 0;
-	if (txlen > 2)
-		index |= (tx[2] << 8);
-	if (txlen > 3)
-		index |= tx[3];
-
-	status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0],
-			USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen,
-			USB_CTRL_GET_TIMEOUT);
-
-	if (status < 0)
-		deb_info("ep 0 read error (status = %d)\n",status);
-
-	deb_data("<<< ");
-	debug_dump(rx, rxlen, deb_data);
-
-	return status; /* length in case of success */
-}
-
-int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
-{
-	struct dib0700_state *st = d->priv;
-	int ret;
-
-	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
-		err("could not acquire lock");
-		return -EINTR;
-	}
-
-	st->buf[0] = REQUEST_SET_GPIO;
-	st->buf[1] = gpio;
-	st->buf[2] = ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6);
-
-	ret = dib0700_ctrl_wr(d, st->buf, 3);
-
-	mutex_unlock(&d->usb_mutex);
-	return ret;
-}
-
-static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
-{
-	struct dib0700_state *st = d->priv;
-	int ret;
-
-	if (st->fw_version >= 0x10201) {
-		if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
-			err("could not acquire lock");
-			return -EINTR;
-		}
-
-		st->buf[0] = REQUEST_SET_USB_XFER_LEN;
-		st->buf[1] = (nb_ts_packets >> 8) & 0xff;
-		st->buf[2] = nb_ts_packets & 0xff;
-
-		deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
-
-		ret = dib0700_ctrl_wr(d, st->buf, 3);
-		mutex_unlock(&d->usb_mutex);
-	} else {
-		deb_info("this firmware does not allow to change the USB xfer len\n");
-		ret = -EIO;
-	}
-
-	return ret;
-}
-
-/*
- * I2C master xfer function (supported in 1.20 firmware)
- */
-static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
-				int num)
-{
-	/* The new i2c firmware messages are more reliable and in particular
-	   properly support i2c read calls not preceded by a write */
-
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	struct dib0700_state *st = d->priv;
-	uint8_t bus_mode = 1;  /* 0=eeprom bus, 1=frontend bus */
-	uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */
-	uint8_t en_start = 0;
-	uint8_t en_stop = 0;
-	int result, i;
-
-	/* Ensure nobody else hits the i2c bus while we're sending our
-	   sequence of messages, (such as the remote control thread) */
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EINTR;
-
-	for (i = 0; i < num; i++) {
-		if (i == 0) {
-			/* First message in the transaction */
-			en_start = 1;
-		} else if (!(msg[i].flags & I2C_M_NOSTART)) {
-			/* Device supports repeated-start */
-			en_start = 1;
-		} else {
-			/* Not the first packet and device doesn't support
-			   repeated start */
-			en_start = 0;
-		}
-		if (i == (num - 1)) {
-			/* Last message in the transaction */
-			en_stop = 1;
-		}
-
-		if (msg[i].flags & I2C_M_RD) {
-			/* Read request */
-			u16 index, value;
-			uint8_t i2c_dest;
-
-			i2c_dest = (msg[i].addr << 1);
-			value = ((en_start << 7) | (en_stop << 6) |
-				 (msg[i].len & 0x3F)) << 8 | i2c_dest;
-			/* I2C ctrl + FE bus; */
-			index = ((gen_mode << 6) & 0xC0) |
-				((bus_mode << 4) & 0x30);
-
-			result = usb_control_msg(d->udev,
-						 usb_rcvctrlpipe(d->udev, 0),
-						 REQUEST_NEW_I2C_READ,
-						 USB_TYPE_VENDOR | USB_DIR_IN,
-						 value, index, msg[i].buf,
-						 msg[i].len,
-						 USB_CTRL_GET_TIMEOUT);
-			if (result < 0) {
-				deb_info("i2c read error (status = %d)\n", result);
-				break;
-			}
-
-			deb_data("<<< ");
-			debug_dump(msg[i].buf, msg[i].len, deb_data);
-
-		} else {
-			/* Write request */
-			if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
-				err("could not acquire lock");
-				mutex_unlock(&d->i2c_mutex);
-				return -EINTR;
-			}
-			st->buf[0] = REQUEST_NEW_I2C_WRITE;
-			st->buf[1] = msg[i].addr << 1;
-			st->buf[2] = (en_start << 7) | (en_stop << 6) |
-				(msg[i].len & 0x3F);
-			/* I2C ctrl + FE bus; */
-			st->buf[3] = ((gen_mode << 6) & 0xC0) |
-				 ((bus_mode << 4) & 0x30);
-			/* The Actual i2c payload */
-			memcpy(&st->buf[4], msg[i].buf, msg[i].len);
-
-			deb_data(">>> ");
-			debug_dump(st->buf, msg[i].len + 4, deb_data);
-
-			result = usb_control_msg(d->udev,
-						 usb_sndctrlpipe(d->udev, 0),
-						 REQUEST_NEW_I2C_WRITE,
-						 USB_TYPE_VENDOR | USB_DIR_OUT,
-						 0, 0, st->buf, msg[i].len + 4,
-						 USB_CTRL_GET_TIMEOUT);
-			mutex_unlock(&d->usb_mutex);
-			if (result < 0) {
-				deb_info("i2c write error (status = %d)\n", result);
-				break;
-			}
-		}
-	}
-	mutex_unlock(&d->i2c_mutex);
-	return i;
-}
-
-/*
- * I2C master xfer function (pre-1.20 firmware)
- */
-static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
-				   struct i2c_msg *msg, int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	struct dib0700_state *st = d->priv;
-	int i,len;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EINTR;
-	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
-		err("could not acquire lock");
-		mutex_unlock(&d->i2c_mutex);
-		return -EINTR;
-	}
-
-	for (i = 0; i < num; i++) {
-		/* fill in the address */
-		st->buf[1] = msg[i].addr << 1;
-		/* fill the buffer */
-		memcpy(&st->buf[2], msg[i].buf, msg[i].len);
-
-		/* write/read request */
-		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
-			st->buf[0] = REQUEST_I2C_READ;
-			st->buf[1] |= 1;
-
-			/* special thing in the current firmware: when length is zero the read-failed */
-			len = dib0700_ctrl_rd(d, st->buf, msg[i].len + 2,
-					msg[i+1].buf, msg[i+1].len);
-			if (len <= 0) {
-				deb_info("I2C read failed on address 0x%02x\n",
-						msg[i].addr);
-				break;
-			}
-
-			msg[i+1].len = len;
-
-			i++;
-		} else {
-			st->buf[0] = REQUEST_I2C_WRITE;
-			if (dib0700_ctrl_wr(d, st->buf, msg[i].len + 2) < 0)
-				break;
-		}
-	}
-	mutex_unlock(&d->usb_mutex);
-	mutex_unlock(&d->i2c_mutex);
-
-	return i;
-}
-
-static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
-			    int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	struct dib0700_state *st = d->priv;
-
-	if (st->fw_use_new_i2c_api == 1) {
-		/* User running at least fw 1.20 */
-		return dib0700_i2c_xfer_new(adap, msg, num);
-	} else {
-		/* Use legacy calls */
-		return dib0700_i2c_xfer_legacy(adap, msg, num);
-	}
-}
-
-static u32 dib0700_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-struct i2c_algorithm dib0700_i2c_algo = {
-	.master_xfer   = dib0700_i2c_xfer,
-	.functionality = dib0700_i2c_func,
-};
-
-int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
-			struct dvb_usb_device_description **desc, int *cold)
-{
-	s16 ret;
-	u8 *b;
-
-	b = kmalloc(16, GFP_KERNEL);
-	if (!b)
-		return	-ENOMEM;
-
-
-	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-		REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, 16, USB_CTRL_GET_TIMEOUT);
-
-	deb_info("FW GET_VERSION length: %d\n",ret);
-
-	*cold = ret <= 0;
-	deb_info("cold: %d\n", *cold);
-
-	kfree(b);
-	return 0;
-}
-
-static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
-	u8 pll_src, u8 pll_range, u8 clock_gpio3, u16 pll_prediv,
-	u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
-{
-	struct dib0700_state *st = d->priv;
-	int ret;
-
-	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
-		err("could not acquire lock");
-		return -EINTR;
-	}
-
-	st->buf[0] = REQUEST_SET_CLOCK;
-	st->buf[1] = (en_pll << 7) | (pll_src << 6) |
-		(pll_range << 5) | (clock_gpio3 << 4);
-	st->buf[2] = (pll_prediv >> 8)  & 0xff; /* MSB */
-	st->buf[3] =  pll_prediv        & 0xff; /* LSB */
-	st->buf[4] = (pll_loopdiv >> 8) & 0xff; /* MSB */
-	st->buf[5] =  pll_loopdiv       & 0xff; /* LSB */
-	st->buf[6] = (free_div >> 8)    & 0xff; /* MSB */
-	st->buf[7] =  free_div          & 0xff; /* LSB */
-	st->buf[8] = (dsuScaler >> 8)   & 0xff; /* MSB */
-	st->buf[9] =  dsuScaler         & 0xff; /* LSB */
-
-	ret = dib0700_ctrl_wr(d, st->buf, 10);
-	mutex_unlock(&d->usb_mutex);
-
-	return ret;
-}
-
-int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz)
-{
-	struct dib0700_state *st = d->priv;
-	u16 divider;
-	int ret;
-
-	if (scl_kHz == 0)
-		return -EINVAL;
-
-	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
-		err("could not acquire lock");
-		return -EINTR;
-	}
-
-	st->buf[0] = REQUEST_SET_I2C_PARAM;
-	divider = (u16) (30000 / scl_kHz);
-	st->buf[1] = 0;
-	st->buf[2] = (u8) (divider >> 8);
-	st->buf[3] = (u8) (divider & 0xff);
-	divider = (u16) (72000 / scl_kHz);
-	st->buf[4] = (u8) (divider >> 8);
-	st->buf[5] = (u8) (divider & 0xff);
-	divider = (u16) (72000 / scl_kHz); /* clock: 72MHz */
-	st->buf[6] = (u8) (divider >> 8);
-	st->buf[7] = (u8) (divider & 0xff);
-
-	deb_info("setting I2C speed: %04x %04x %04x (%d kHz).",
-		(st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) |
-		st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz);
-
-	ret = dib0700_ctrl_wr(d, st->buf, 8);
-	mutex_unlock(&d->usb_mutex);
-
-	return ret;
-}
-
-
-int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3)
-{
-	switch (clk_MHz) {
-		case 72: dib0700_set_clock(d, 1, 0, 1, clock_out_gp3, 2, 24, 0, 0x4c); break;
-		default: return -EINVAL;
-	}
-	return 0;
-}
-
-static int dib0700_jumpram(struct usb_device *udev, u32 address)
-{
-	int ret = 0, actlen;
-	u8 *buf;
-
-	buf = kmalloc(8, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-	buf[0] = REQUEST_JUMPRAM;
-	buf[1] = 0;
-	buf[2] = 0;
-	buf[3] = 0;
-	buf[4] = (address >> 24) & 0xff;
-	buf[5] = (address >> 16) & 0xff;
-	buf[6] = (address >> 8)  & 0xff;
-	buf[7] =  address        & 0xff;
-
-	if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) {
-		deb_fw("jumpram to 0x%x failed\n",address);
-		goto out;
-	}
-	if (actlen != 8) {
-		deb_fw("jumpram to 0x%x failed\n",address);
-		ret = -EIO;
-		goto out;
-	}
-out:
-	kfree(buf);
-	return ret;
-}
-
-int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw)
-{
-	struct hexline hx;
-	int pos = 0, ret, act_len, i, adap_num;
-	u8 *buf;
-	u32 fw_version;
-
-	buf = kmalloc(260, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) {
-		deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",
-				hx.addr, hx.len, hx.chk);
-
-		buf[0] = hx.len;
-		buf[1] = (hx.addr >> 8) & 0xff;
-		buf[2] =  hx.addr       & 0xff;
-		buf[3] = hx.type;
-		memcpy(&buf[4],hx.data,hx.len);
-		buf[4+hx.len] = hx.chk;
-
-		ret = usb_bulk_msg(udev,
-			usb_sndbulkpipe(udev, 0x01),
-			buf,
-			hx.len + 5,
-			&act_len,
-			1000);
-
-		if (ret < 0) {
-			err("firmware download failed at %d with %d",pos,ret);
-			goto out;
-		}
-	}
-
-	if (ret == 0) {
-		/* start the firmware */
-		if ((ret = dib0700_jumpram(udev, 0x70000000)) == 0) {
-			info("firmware started successfully.");
-			msleep(500);
-		}
-	} else
-		ret = -EIO;
-
-	/* the number of ts packet has to be at least 1 */
-	if (nb_packet_buffer_size < 1)
-		nb_packet_buffer_size = 1;
-
-	/* get the fimware version */
-	usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-				  REQUEST_GET_VERSION,
-				  USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
-				  buf, 16, USB_CTRL_GET_TIMEOUT);
-	fw_version = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11];
-
-	/* set the buffer size - DVB-USB is allocating URB buffers
-	 * only after the firwmare download was successful */
-	for (i = 0; i < dib0700_device_count; i++) {
-		for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters;
-				adap_num++) {
-			if (fw_version >= 0x10201) {
-				dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 188*nb_packet_buffer_size;
-			} else {
-				/* for fw version older than 1.20.1,
-				 * the buffersize has to be n times 512 */
-				dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512;
-				if (dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize < 512)
-					dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 512;
-			}
-		}
-	}
-out:
-	kfree(buf);
-	return ret;
-}
-
-int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	struct dib0700_state *st = adap->dev->priv;
-	int ret;
-
-	if ((onoff != 0) && (st->fw_version >= 0x10201)) {
-		/* for firmware later than 1.20.1,
-		 * the USB xfer length can be set  */
-		ret = dib0700_set_usb_xfer_len(adap->dev,
-			st->nb_packet_buffer_size);
-		if (ret < 0) {
-			deb_info("can not set the USB xfer len\n");
-			return ret;
-		}
-	}
-
-	if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) {
-		err("could not acquire lock");
-		return -EINTR;
-	}
-
-	st->buf[0] = REQUEST_ENABLE_VIDEO;
-	/* this bit gives a kind of command,
-	 * rather than enabling something or not */
-	st->buf[1] = (onoff << 4) | 0x00;
-
-	if (st->disable_streaming_master_mode == 1)
-		st->buf[2] = 0x00;
-	else
-		st->buf[2] = 0x01 << 4; /* Master mode */
-
-	st->buf[3] = 0x00;
-
-	deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);
-
-	st->channel_state &= ~0x3;
-	if ((adap->fe_adap[0].stream.props.endpoint != 2)
-			&& (adap->fe_adap[0].stream.props.endpoint != 3)) {
-		deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->fe_adap[0].stream.props.endpoint);
-		if (onoff)
-			st->channel_state |=	1 << (adap->id);
-		else
-			st->channel_state |=	1 << ~(adap->id);
-	} else {
-		if (onoff)
-			st->channel_state |=	1 << (adap->fe_adap[0].stream.props.endpoint-2);
-		else
-			st->channel_state |=	1 << (3-adap->fe_adap[0].stream.props.endpoint);
-	}
-
-	st->buf[2] |= st->channel_state;
-
-	deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]);
-
-	ret = dib0700_ctrl_wr(adap->dev, st->buf, 4);
-	mutex_unlock(&adap->dev->usb_mutex);
-
-	return ret;
-}
-
-int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
-{
-	struct dvb_usb_device *d = rc->priv;
-	struct dib0700_state *st = d->priv;
-	int new_proto, ret;
-
-	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
-		err("could not acquire lock");
-		return -EINTR;
-	}
-
-	st->buf[0] = REQUEST_SET_RC;
-	st->buf[1] = 0;
-	st->buf[2] = 0;
-
-	/* Set the IR mode */
-	if (rc_type == RC_TYPE_RC5)
-		new_proto = 1;
-	else if (rc_type == RC_TYPE_NEC)
-		new_proto = 0;
-	else if (rc_type == RC_TYPE_RC6) {
-		if (st->fw_version < 0x10200) {
-			ret = -EINVAL;
-			goto out;
-		}
-
-		new_proto = 2;
-	} else {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	st->buf[1] = new_proto;
-
-	ret = dib0700_ctrl_wr(d, st->buf, 3);
-	if (ret < 0) {
-		err("ir protocol setup failed");
-		goto out;
-	}
-
-	d->props.rc.core.protocol = rc_type;
-
-out:
-	mutex_unlock(&d->usb_mutex);
-	return ret;
-}
-
-/* Number of keypresses to ignore before start repeating */
-#define RC_REPEAT_DELAY_V1_20 10
-
-/* This is the structure of the RC response packet starting in firmware 1.20 */
-struct dib0700_rc_response {
-	u8 report_id;
-	u8 data_state;
-	union {
-		u16 system16;
-		struct {
-			u8 not_system;
-			u8 system;
-		};
-	};
-	u8 data;
-	u8 not_data;
-};
-#define RC_MSG_SIZE_V1_20 6
-
-static void dib0700_rc_urb_completion(struct urb *purb)
-{
-	struct dvb_usb_device *d = purb->context;
-	struct dib0700_rc_response *poll_reply;
-	u32 uninitialized_var(keycode);
-	u8 toggle;
-
-	deb_info("%s()\n", __func__);
-	if (d->rc_dev == NULL) {
-		/* This will occur if disable_rc_polling=1 */
-		kfree(purb->transfer_buffer);
-		usb_free_urb(purb);
-		return;
-	}
-
-	poll_reply = purb->transfer_buffer;
-
-	if (purb->status < 0) {
-		deb_info("discontinuing polling\n");
-		kfree(purb->transfer_buffer);
-		usb_free_urb(purb);
-		return;
-	}
-
-	if (purb->actual_length != RC_MSG_SIZE_V1_20) {
-		deb_info("malformed rc msg size=%d\n", purb->actual_length);
-		goto resubmit;
-	}
-
-	deb_data("IR ID = %02X state = %02X System = %02X %02X Cmd = %02X %02X (len %d)\n",
-		 poll_reply->report_id, poll_reply->data_state,
-		 poll_reply->system, poll_reply->not_system,
-		 poll_reply->data, poll_reply->not_data,
-		 purb->actual_length);
-
-	switch (d->props.rc.core.protocol) {
-	case RC_TYPE_NEC:
-		toggle = 0;
-
-		/* NEC protocol sends repeat code as 0 0 0 FF */
-		if ((poll_reply->system == 0x00) && (poll_reply->data == 0x00)
-		    && (poll_reply->not_data == 0xff)) {
-			poll_reply->data_state = 2;
-			break;
-		}
-
-		if ((poll_reply->system ^ poll_reply->not_system) != 0xff) {
-			deb_data("NEC extended protocol\n");
-			/* NEC extended code - 24 bits */
-			keycode = be16_to_cpu(poll_reply->system16) << 8 | poll_reply->data;
-		} else {
-			deb_data("NEC normal protocol\n");
-			/* normal NEC code - 16 bits */
-			keycode = poll_reply->system << 8 | poll_reply->data;
-		}
-
-		break;
-	default:
-		deb_data("RC5 protocol\n");
-		/* RC5 Protocol */
-		toggle = poll_reply->report_id;
-		keycode = poll_reply->system << 8 | poll_reply->data;
-
-		break;
-	}
-
-	if ((poll_reply->data + poll_reply->not_data) != 0xff) {
-		/* Key failed integrity check */
-		err("key failed integrity check: %04x %02x %02x",
-		    poll_reply->system,
-		    poll_reply->data, poll_reply->not_data);
-		goto resubmit;
-	}
-
-	rc_keydown(d->rc_dev, keycode, toggle);
-
-resubmit:
-	/* Clean the buffer before we requeue */
-	memset(purb->transfer_buffer, 0, RC_MSG_SIZE_V1_20);
-
-	/* Requeue URB */
-	usb_submit_urb(purb, GFP_ATOMIC);
-}
-
-int dib0700_rc_setup(struct dvb_usb_device *d)
-{
-	struct dib0700_state *st = d->priv;
-	struct urb *purb;
-	int ret;
-
-	/* Poll-based. Don't initialize bulk mode */
-	if (st->fw_version < 0x10200)
-		return 0;
-
-	/* Starting in firmware 1.20, the RC info is provided on a bulk pipe */
-	purb = usb_alloc_urb(0, GFP_KERNEL);
-	if (purb == NULL) {
-		err("rc usb alloc urb failed\n");
-		return -ENOMEM;
-	}
-
-	purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL);
-	if (purb->transfer_buffer == NULL) {
-		err("rc kzalloc failed\n");
-		usb_free_urb(purb);
-		return -ENOMEM;
-	}
-
-	purb->status = -EINPROGRESS;
-	usb_fill_bulk_urb(purb, d->udev, usb_rcvbulkpipe(d->udev, 1),
-			  purb->transfer_buffer, RC_MSG_SIZE_V1_20,
-			  dib0700_rc_urb_completion, d);
-
-	ret = usb_submit_urb(purb, GFP_ATOMIC);
-	if (ret) {
-		err("rc submit urb failed\n");
-		kfree(purb->transfer_buffer);
-		usb_free_urb(purb);
-	}
-
-	return ret;
-}
-
-static int dib0700_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	int i;
-	struct dvb_usb_device *dev;
-
-	for (i = 0; i < dib0700_device_count; i++)
-		if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE,
-		    &dev, adapter_nr) == 0) {
-			struct dib0700_state *st = dev->priv;
-			u32 hwversion, romversion, fw_version, fwtype;
-
-			dib0700_get_version(dev, &hwversion, &romversion,
-				&fw_version, &fwtype);
-
-			deb_info("Firmware version: %x, %d, 0x%x, %d\n",
-				hwversion, romversion, fw_version, fwtype);
-
-			st->fw_version = fw_version;
-			st->nb_packet_buffer_size = (u32)nb_packet_buffer_size;
-
-			/* Disable polling mode on newer firmwares */
-			if (st->fw_version >= 0x10200)
-				dev->props.rc.core.bulk_mode = true;
-			else
-				dev->props.rc.core.bulk_mode = false;
-
-			dib0700_rc_setup(dev);
-
-			return 0;
-		}
-
-	return -ENODEV;
-}
-
-static struct usb_driver dib0700_driver = {
-	.name       = "dvb_usb_dib0700",
-	.probe      = dib0700_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table   = dib0700_usb_id_table,
-};
-
-module_usb_driver(dib0700_driver);
-
-MODULE_FIRMWARE("dvb-usb-dib0700-1.20.fw");
-MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
-MODULE_DESCRIPTION("Driver for devices based on DiBcom DiB0700 - USB bridge");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
deleted file mode 100644
index 510001d..0000000
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ /dev/null
@@ -1,4813 +0,0 @@
-/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
- *
- *	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, version 2.
- *
- *  Copyright (C) 2005-9 DiBcom, SA et al
- */
-#include "dib0700.h"
-
-#include "dib3000mc.h"
-#include "dib7000m.h"
-#include "dib7000p.h"
-#include "dib8000.h"
-#include "dib9000.h"
-#include "mt2060.h"
-#include "mt2266.h"
-#include "tuner-xc2028.h"
-#include "xc5000.h"
-#include "xc4000.h"
-#include "s5h1411.h"
-#include "dib0070.h"
-#include "dib0090.h"
-#include "lgdt3305.h"
-#include "mxl5007t.h"
-
-static int force_lna_activation;
-module_param(force_lna_activation, int, 0644);
-MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), "
-		"if applicable for the device (default: 0=automatic/off).");
-
-struct dib0700_adapter_state {
-	int (*set_param_save) (struct dvb_frontend *);
-	const struct firmware *frontend_firmware;
-};
-
-/* Hauppauge Nova-T 500 (aka Bristol)
- *  has a LNA on GPIO0 which is enabled by setting 1 */
-static struct mt2060_config bristol_mt2060_config[2] = {
-	{
-		.i2c_address = 0x60,
-		.clock_out   = 3,
-	}, {
-		.i2c_address = 0x61,
-	}
-};
-
-
-static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = {
-	.band_caps = BAND_VHF | BAND_UHF,
-	.setup     = (1 << 8) | (5 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (2 << 0),
-
-	.agc1_max = 42598,
-	.agc1_min = 17694,
-	.agc2_max = 45875,
-	.agc2_min = 0,
-
-	.agc1_pt1 = 0,
-	.agc1_pt2 = 59,
-
-	.agc1_slope1 = 0,
-	.agc1_slope2 = 69,
-
-	.agc2_pt1 = 0,
-	.agc2_pt2 = 59,
-
-	.agc2_slope1 = 111,
-	.agc2_slope2 = 28,
-};
-
-static struct dib3000mc_config bristol_dib3000mc_config[2] = {
-	{	.agc          = &bristol_dib3000p_mt2060_agc_config,
-		.max_time     = 0x196,
-		.ln_adc_level = 0x1cc7,
-		.output_mpeg2_in_188_bytes = 1,
-	},
-	{	.agc          = &bristol_dib3000p_mt2060_agc_config,
-		.max_time     = 0x196,
-		.ln_adc_level = 0x1cc7,
-		.output_mpeg2_in_188_bytes = 1,
-	}
-};
-
-static int bristol_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_state *st = adap->dev->priv;
-	if (adap->id == 0) {
-		dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 0); msleep(10);
-		dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 1); msleep(10);
-		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10);
-		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10);
-
-		if (force_lna_activation)
-			dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-		else
-			dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0);
-
-		if (dib3000mc_i2c_enumeration(&adap->dev->i2c_adap, 2, DEFAULT_DIB3000P_I2C_ADDRESS, bristol_dib3000mc_config) != 0) {
-			dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10);
-			return -ENODEV;
-		}
-	}
-	st->mt2060_if1[adap->id] = 1220;
-	return (adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap,
-		(10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0;
-}
-
-static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval)
-{
-	struct i2c_msg msg[2] = {
-		{ .addr = 0x50, .flags = 0,        .buf = &adrs, .len = 1 },
-		{ .addr = 0x50, .flags = I2C_M_RD, .buf = pval,  .len = 1 },
-	};
-	if (i2c_transfer(adap, msg, 2) != 2) return -EREMOTEIO;
-	return 0;
-}
-
-static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
-	struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe_adap[0].fe, 1);
-	s8 a;
-	int if1=1220;
-	if (adap->dev->udev->descriptor.idVendor  == cpu_to_le16(USB_VID_HAUPPAUGE) &&
-		adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_500_2)) {
-		if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a;
-	}
-	return dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c,
-			  &bristol_mt2060_config[adap->id], if1) == NULL ?
-			  -ENODEV : 0;
-}
-
-/* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */
-
-/* MT226x */
-static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = {
-	{
-		BAND_UHF,
-
-		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
-		* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
-		(0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8)
-	    | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
-
-		1130,
-		21,
-
-		0,
-		118,
-
-		0,
-		3530,
-		1,
-		0,
-
-		65535,
-		33770,
-		65535,
-		23592,
-
-		0,
-		62,
-		255,
-		64,
-		64,
-		132,
-		192,
-		80,
-		80,
-
-		17,
-		27,
-		23,
-		51,
-
-		1,
-	}, {
-		BAND_VHF | BAND_LBAND,
-
-		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
-		* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
-		(0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8)
-	    | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
-
-		2372,
-		21,
-
-		0,
-		118,
-
-		0,
-		3530,
-		1,
-		0,
-
-		65535,
-		0,
-		65535,
-		23592,
-
-		0,
-		128,
-		128,
-		128,
-		0,
-		128,
-		253,
-		81,
-		0,
-
-		17,
-		27,
-		23,
-		51,
-
-		1,
-	}
-};
-
-static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = {
-	60000, 30000,
-	1, 8, 3, 1, 0,
-	0, 0, 1, 1, 2,
-	(3 << 14) | (1 << 12) | (524 << 0),
-	0,
-	20452225,
-};
-
-static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = {
-	{	.output_mpeg2_in_188_bytes = 1,
-		.hostbus_diversity = 1,
-		.tuner_is_baseband = 1,
-
-		.agc_config_count = 2,
-		.agc = stk7700d_7000p_mt2266_agc_config,
-		.bw  = &stk7700d_mt2266_pll_config,
-
-		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
-		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
-		.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
-	},
-	{	.output_mpeg2_in_188_bytes = 1,
-		.hostbus_diversity = 1,
-		.tuner_is_baseband = 1,
-
-		.agc_config_count = 2,
-		.agc = stk7700d_7000p_mt2266_agc_config,
-		.bw  = &stk7700d_mt2266_pll_config,
-
-		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
-		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
-		.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
-	}
-};
-
-static struct mt2266_config stk7700d_mt2266_config[2] = {
-	{	.i2c_address = 0x60
-	},
-	{	.i2c_address = 0x60
-	}
-};
-
-static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	if (adap->id == 0) {
-		dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-		msleep(10);
-		dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-		dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-		dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-		msleep(10);
-		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-		msleep(10);
-		if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
-					     stk7700d_dib7000p_mt2266_config)
-		    != 0) {
-			err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
-			return -ENODEV;
-		}
-	}
-
-	adap->fe_adap[0].fe =
-		dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
-			   0x80 + (adap->id << 1),
-			   &stk7700d_dib7000p_mt2266_config[adap->id]);
-
-	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	if (adap->id == 0) {
-		dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-		msleep(10);
-		dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-		dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-		dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-		msleep(10);
-		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-		msleep(10);
-		dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-		if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18,
-					     stk7700d_dib7000p_mt2266_config)
-		    != 0) {
-			err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
-			return -ENODEV;
-		}
-	}
-
-	adap->fe_adap[0].fe =
-		dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
-			   0x80 + (adap->id << 1),
-			   &stk7700d_dib7000p_mt2266_config[adap->id]);
-
-	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct i2c_adapter *tun_i2c;
-	tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
-	return dvb_attach(mt2266_attach, adap->fe_adap[0].fe, tun_i2c,
-		&stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;
-}
-
-/* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */
-static struct dibx000_agc_config xc3028_agc_config = {
-	BAND_VHF | BAND_UHF,       /* band_caps */
-
-	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0,
-	 * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
-	 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
-	(0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) |
-	(3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */
-
-	712,	/* inv_gain */
-	21,	/* time_stabiliz */
-
-	0,	/* alpha_level */
-	118,	/* thlock */
-
-	0,	/* wbd_inv */
-	2867,	/* wbd_ref */
-	0,	/* wbd_sel */
-	2,	/* wbd_alpha */
-
-	0,	/* agc1_max */
-	0,	/* agc1_min */
-	39718,	/* agc2_max */
-	9930,	/* agc2_min */
-	0,	/* agc1_pt1 */
-	0,	/* agc1_pt2 */
-	0,	/* agc1_pt3 */
-	0,	/* agc1_slope1 */
-	0,	/* agc1_slope2 */
-	0,	/* agc2_pt1 */
-	128,	/* agc2_pt2 */
-	29,	/* agc2_slope1 */
-	29,	/* agc2_slope2 */
-
-	17,	/* alpha_mant */
-	27,	/* alpha_exp */
-	23,	/* beta_mant */
-	51,	/* beta_exp */
-
-	1,	/* perform_agc_softsplit */
-};
-
-/* PLL Configuration for COFDM BW_MHz = 8.00 with external clock = 30.00 */
-static struct dibx000_bandwidth_config xc3028_bw_config = {
-	60000, 30000, /* internal, sampling */
-	1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */
-	0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc,
-			  modulo */
-	(3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */
-	(1 << 25) | 5816102, /* ifreq = 5.200000 MHz */
-	20452225, /* timf */
-	30000000, /* xtal_hz */
-};
-
-static struct dib7000p_config stk7700ph_dib7700_xc3028_config = {
-	.output_mpeg2_in_188_bytes = 1,
-	.tuner_is_baseband = 1,
-
-	.agc_config_count = 1,
-	.agc = &xc3028_agc_config,
-	.bw  = &xc3028_bw_config,
-
-	.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
-	.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
-	.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
-};
-
-static int stk7700ph_xc3028_callback(void *ptr, int component,
-				     int command, int arg)
-{
-	struct dvb_usb_adapter *adap = ptr;
-
-	switch (command) {
-	case XC2028_TUNER_RESET:
-		/* Send the tuner in then out of reset */
-		dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 0); msleep(10);
-		dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
-		break;
-	case XC2028_RESET_CLK:
-		break;
-	default:
-		err("%s: unknown command %d, arg %d\n", __func__,
-			command, arg);
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static struct xc2028_ctrl stk7700ph_xc3028_ctrl = {
-	.fname = XC2028_DEFAULT_FIRMWARE,
-	.max_len = 64,
-	.demod = XC3028_FE_DIBCOM52,
-};
-
-static struct xc2028_config stk7700ph_xc3028_config = {
-	.i2c_addr = 0x61,
-	.ctrl = &stk7700ph_xc3028_ctrl,
-};
-
-static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct usb_device_descriptor *desc = &adap->dev->udev->descriptor;
-
-	if (desc->idVendor  == cpu_to_le16(USB_VID_PINNACLE) &&
-	    desc->idProduct == cpu_to_le16(USB_PID_PINNACLE_EXPRESSCARD_320CX))
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
-	else
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-	msleep(10);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-	msleep(10);
-
-	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
-				     &stk7700ph_dib7700_xc3028_config) != 0) {
-		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
-		    __func__);
-		return -ENODEV;
-	}
-
-	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
-		&stk7700ph_dib7700_xc3028_config);
-
-	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct i2c_adapter *tun_i2c;
-
-	tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe,
-		DIBX000_I2C_INTERFACE_TUNER, 1);
-
-	stk7700ph_xc3028_config.i2c_adap = tun_i2c;
-
-	/* FIXME: generalize & move to common area */
-	adap->fe_adap[0].fe->callback = stk7700ph_xc3028_callback;
-
-	return dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &stk7700ph_xc3028_config)
-		== NULL ? -ENODEV : 0;
-}
-
-#define DEFAULT_RC_INTERVAL 50
-
-static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
-
-/* Number of keypresses to ignore before start repeating */
-#define RC_REPEAT_DELAY 6
-
-/*
- * This function is used only when firmware is < 1.20 version. Newer
- * firmwares use bulk mode, with functions implemented at dib0700_core,
- * at dib0700_rc_urb_completion()
- */
-static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
-{
-	u8 key[4];
-	u32 keycode;
-	u8 toggle;
-	int i;
-	struct dib0700_state *st = d->priv;
-
-	if (st->fw_version >= 0x10200) {
-		/* For 1.20 firmware , We need to keep the RC polling
-		   callback so we can reuse the input device setup in
-		   dvb-usb-remote.c.  However, the actual work is being done
-		   in the bulk URB completion handler. */
-		return 0;
-	}
-
-	i = dib0700_ctrl_rd(d, rc_request, 2, key, 4);
-	if (i <= 0) {
-		err("RC Query Failed");
-		return -1;
-	}
-
-	/* losing half of KEY_0 events from Philipps rc5 remotes.. */
-	if (key[0] == 0 && key[1] == 0 && key[2] == 0 && key[3] == 0)
-		return 0;
-
-	/* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]);  */
-
-	dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */
-
-	d->last_event = 0;
-	switch (d->props.rc.core.protocol) {
-	case RC_TYPE_NEC:
-		/* NEC protocol sends repeat code as 0 0 0 FF */
-		if ((key[3-2] == 0x00) && (key[3-3] == 0x00) &&
-		    (key[3] == 0xff))
-			keycode = d->last_event;
-		else {
-			keycode = key[3-2] << 8 | key[3-3];
-			d->last_event = keycode;
-		}
-
-		rc_keydown(d->rc_dev, keycode, 0);
-		break;
-	default:
-		/* RC-5 protocol changes toggle bit on new keypress */
-		keycode = key[3-2] << 8 | key[3-3];
-		toggle = key[3-1];
-		rc_keydown(d->rc_dev, keycode, toggle);
-
-		break;
-	}
-	return 0;
-}
-
-/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
-static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
-	BAND_UHF | BAND_VHF,
-
-	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
-	 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
-	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
-	| (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
-
-	712,
-	41,
-
-	0,
-	118,
-
-	0,
-	4095,
-	0,
-	0,
-
-	42598,
-	17694,
-	45875,
-	2621,
-	0,
-	76,
-	139,
-	52,
-	59,
-	107,
-	172,
-	57,
-	70,
-
-	21,
-	25,
-	28,
-	48,
-
-	1,
-	{  0,
-	   107,
-	   51800,
-	   24700
-	},
-};
-
-static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = {
-	BAND_UHF | BAND_VHF,
-
-	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
-	 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
-	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
-	| (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
-
-	712,
-	41,
-
-	0,
-	118,
-
-	0,
-	4095,
-	0,
-	0,
-
-	42598,
-	16384,
-	42598,
-	    0,
-
-	  0,
-	137,
-	255,
-
-	  0,
-	255,
-
-	0,
-	0,
-
-	 0,
-	41,
-
-	15,
-	25,
-
-	28,
-	48,
-
-	0,
-};
-
-static struct dibx000_bandwidth_config stk7700p_pll_config = {
-	60000, 30000,
-	1, 8, 3, 1, 0,
-	0, 0, 1, 1, 0,
-	(3 << 14) | (1 << 12) | (524 << 0),
-	60258167,
-	20452225,
-	30000000,
-};
-
-static struct dib7000m_config stk7700p_dib7000m_config = {
-	.dvbt_mode = 1,
-	.output_mpeg2_in_188_bytes = 1,
-	.quartz_direct = 1,
-
-	.agc_config_count = 1,
-	.agc = &stk7700p_7000m_mt2060_agc_config,
-	.bw  = &stk7700p_pll_config,
-
-	.gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
-	.gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
-	.gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
-};
-
-static struct dib7000p_config stk7700p_dib7000p_config = {
-	.output_mpeg2_in_188_bytes = 1,
-
-	.agc_config_count = 1,
-	.agc = &stk7700p_7000p_mt2060_agc_config,
-	.bw  = &stk7700p_pll_config,
-
-	.gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
-	.gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
-	.gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
-};
-
-static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_state *st = adap->dev->priv;
-	/* unless there is no real power management in DVB - we leave the device on GPIO6 */
-
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-	dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 0); msleep(50);
-
-	dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 1); msleep(10);
-	dib0700_set_gpio(adap->dev, GPIO9,  GPIO_OUT, 1);
-
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10);
-	dib0700_ctrl_clock(adap->dev, 72, 1);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(100);
-
-	dib0700_set_gpio(adap->dev,  GPIO0, GPIO_OUT, 1);
-
-	st->mt2060_if1[0] = 1220;
-
-	if (dib7000pc_detection(&adap->dev->i2c_adap)) {
-		adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config);
-		st->is_dib7000pc = 1;
-	} else
-		adap->fe_adap[0].fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config);
-
-	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-static struct mt2060_config stk7700p_mt2060_config = {
-	0x60
-};
-
-static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
-	struct dib0700_state *st = adap->dev->priv;
-	struct i2c_adapter *tun_i2c;
-	s8 a;
-	int if1=1220;
-	if (adap->dev->udev->descriptor.idVendor  == cpu_to_le16(USB_VID_HAUPPAUGE) &&
-		adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_STICK)) {
-		if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a;
-	}
-	if (st->is_dib7000pc)
-		tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
-	else
-		tun_i2c = dib7000m_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
-
-	return dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, &stk7700p_mt2060_config,
-		if1) == NULL ? -ENODEV : 0;
-}
-
-/* DIB7070 generic */
-static struct dibx000_agc_config dib7070_agc_config = {
-	BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
-	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
-	 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
-	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
-	| (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
-
-	600,
-	10,
-
-	0,
-	118,
-
-	0,
-	3530,
-	1,
-	5,
-
-	65535,
-		0,
-
-	65535,
-	0,
-
-	0,
-	40,
-	183,
-	206,
-	255,
-	72,
-	152,
-	88,
-	90,
-
-	17,
-	27,
-	23,
-	51,
-
-	0,
-};
-
-static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
-{
-	deb_info("reset: %d", onoff);
-	return dib7000p_set_gpio(fe, 8, 0, !onoff);
-}
-
-static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
-{
-	deb_info("sleep: %d", onoff);
-	return dib7000p_set_gpio(fe, 9, 0, onoff);
-}
-
-static struct dib0070_config dib7070p_dib0070_config[2] = {
-	{
-		.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
-		.reset = dib7070_tuner_reset,
-		.sleep = dib7070_tuner_sleep,
-		.clock_khz = 12000,
-		.clock_pad_drive = 4,
-		.charge_pump = 2,
-	}, {
-		.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
-		.reset = dib7070_tuner_reset,
-		.sleep = dib7070_tuner_sleep,
-		.clock_khz = 12000,
-		.charge_pump = 2,
-	}
-};
-
-static struct dib0070_config dib7770p_dib0070_config = {
-	 .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
-	 .reset = dib7070_tuner_reset,
-	 .sleep = dib7070_tuner_sleep,
-	 .clock_khz = 12000,
-	 .clock_pad_drive = 0,
-	 .flip_chip = 1,
-	 .charge_pump = 2,
-};
-
-static int dib7070_set_param_override(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct dib0700_adapter_state *state = adap->priv;
-
-	u16 offset;
-	u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
-	switch (band) {
-		case BAND_VHF: offset = 950; break;
-		case BAND_UHF:
-		default: offset = 550; break;
-	}
-	deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
-	dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
-	return state->set_param_save(fe);
-}
-
-static int dib7770_set_param_override(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct dib0700_adapter_state *state = adap->priv;
-
-	 u16 offset;
-	 u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
-	 switch (band) {
-	 case BAND_VHF:
-		  dib7000p_set_gpio(fe, 0, 0, 1);
-		  offset = 850;
-		  break;
-	 case BAND_UHF:
-	 default:
-		  dib7000p_set_gpio(fe, 0, 0, 0);
-		  offset = 250;
-		  break;
-	 }
-	 deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
-	 dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
-	 return state->set_param_save(fe);
-}
-
-static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	 struct dib0700_adapter_state *st = adap->priv;
-	 struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe,
-			 DIBX000_I2C_INTERFACE_TUNER, 1);
-
-	 if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
-			&dib7770p_dib0070_config) == NULL)
-		 return -ENODEV;
-
-	 st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
-	 adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7770_set_param_override;
-	 return 0;
-}
-
-static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_adapter_state *st = adap->priv;
-	struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
-
-	if (adap->id == 0) {
-		if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL)
-			return -ENODEV;
-	} else {
-		if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL)
-			return -ENODEV;
-	}
-
-	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
-	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7070_set_param_override;
-	return 0;
-}
-
-static int stk7700p_pid_filter(struct dvb_usb_adapter *adapter, int index,
-		u16 pid, int onoff)
-{
-	struct dib0700_state *st = adapter->dev->priv;
-	if (st->is_dib7000pc)
-		return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
-	return dib7000m_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
-}
-
-static int stk7700p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
-{
-	struct dib0700_state *st = adapter->dev->priv;
-	if (st->is_dib7000pc)
-		return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
-	return dib7000m_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
-}
-
-static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
-{
-	return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
-}
-
-static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
-{
-	return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
-}
-
-static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
-	60000, 15000,
-	1, 20, 3, 1, 0,
-	0, 0, 1, 1, 2,
-	(3 << 14) | (1 << 12) | (524 << 0),
-	(0 << 25) | 0,
-	20452225,
-	12000000,
-};
-
-static struct dib7000p_config dib7070p_dib7000p_config = {
-	.output_mpeg2_in_188_bytes = 1,
-
-	.agc_config_count = 1,
-	.agc = &dib7070_agc_config,
-	.bw  = &dib7070_bw_config_12_mhz,
-	.tuner_is_baseband = 1,
-	.spur_protect = 1,
-
-	.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
-	.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
-	.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
-
-	.hostbus_diversity = 1,
-};
-
-/* STK7070P */
-static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct usb_device_descriptor *p = &adap->dev->udev->descriptor;
-	if (p->idVendor  == cpu_to_le16(USB_VID_PINNACLE) &&
-	    p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E))
-		dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
-	else
-		dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-	msleep(10);
-	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-
-	dib0700_ctrl_clock(adap->dev, 72, 1);
-
-	msleep(10);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-	msleep(10);
-	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-
-	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
-				     &dib7070p_dib7000p_config) != 0) {
-		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
-		    __func__);
-		return -ENODEV;
-	}
-
-	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
-		&dib7070p_dib7000p_config);
-	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-/* STK7770P */
-static struct dib7000p_config dib7770p_dib7000p_config = {
-	.output_mpeg2_in_188_bytes = 1,
-
-	.agc_config_count = 1,
-	.agc = &dib7070_agc_config,
-	.bw  = &dib7070_bw_config_12_mhz,
-	.tuner_is_baseband = 1,
-	.spur_protect = 1,
-
-	.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
-	.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
-	.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
-
-	.hostbus_diversity = 1,
-	.enable_current_mirror = 1,
-	.disable_sample_and_hold = 0,
-};
-
-static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct usb_device_descriptor *p = &adap->dev->udev->descriptor;
-	if (p->idVendor  == cpu_to_le16(USB_VID_PINNACLE) &&
-	    p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E))
-		dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
-	else
-		dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-	msleep(10);
-	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-
-	dib0700_ctrl_clock(adap->dev, 72, 1);
-
-	msleep(10);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-	msleep(10);
-	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-
-	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
-				     &dib7770p_dib7000p_config) != 0) {
-		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
-		    __func__);
-		return -ENODEV;
-	}
-
-	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
-		&dib7770p_dib7000p_config);
-	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-/* DIB807x generic */
-static struct dibx000_agc_config dib807x_agc_config[2] = {
-	{
-		BAND_VHF,
-		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
-		 * P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
-		 * P_agc_inv_pwm2=0,P_agc_inh_dc_rv_est=0,
-		 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
-		 * P_agc_write=0 */
-		(0 << 15) | (0 << 14) | (7 << 11) | (0 << 10) | (0 << 9) |
-			(0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) |
-			(0 << 0), /* setup*/
-
-		600, /* inv_gain*/
-		10,  /* time_stabiliz*/
-
-		0,  /* alpha_level*/
-		118,  /* thlock*/
-
-		0,     /* wbd_inv*/
-		3530,  /* wbd_ref*/
-		1,     /* wbd_sel*/
-		5,     /* wbd_alpha*/
-
-		65535,  /* agc1_max*/
-		0,  /* agc1_min*/
-
-		65535,  /* agc2_max*/
-		0,      /* agc2_min*/
-
-		0,      /* agc1_pt1*/
-		40,     /* agc1_pt2*/
-		183,    /* agc1_pt3*/
-		206,    /* agc1_slope1*/
-		255,    /* agc1_slope2*/
-		72,     /* agc2_pt1*/
-		152,    /* agc2_pt2*/
-		88,     /* agc2_slope1*/
-		90,     /* agc2_slope2*/
-
-		17,  /* alpha_mant*/
-		27,  /* alpha_exp*/
-		23,  /* beta_mant*/
-		51,  /* beta_exp*/
-
-		0,  /* perform_agc_softsplit*/
-	}, {
-		BAND_UHF,
-		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
-		 * P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
-		 * P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
-		 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
-		 * P_agc_write=0 */
-		(0 << 15) | (0 << 14) | (1 << 11) | (0 << 10) | (0 << 9) |
-			(0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) |
-			(0 << 0), /* setup */
-
-		600, /* inv_gain*/
-		10,  /* time_stabiliz*/
-
-		0,  /* alpha_level*/
-		118,  /* thlock*/
-
-		0,     /* wbd_inv*/
-		3530,  /* wbd_ref*/
-		1,     /* wbd_sel*/
-		5,     /* wbd_alpha*/
-
-		65535,  /* agc1_max*/
-		0,  /* agc1_min*/
-
-		65535,  /* agc2_max*/
-		0,      /* agc2_min*/
-
-		0,      /* agc1_pt1*/
-		40,     /* agc1_pt2*/
-		183,    /* agc1_pt3*/
-		206,    /* agc1_slope1*/
-		255,    /* agc1_slope2*/
-		72,     /* agc2_pt1*/
-		152,    /* agc2_pt2*/
-		88,     /* agc2_slope1*/
-		90,     /* agc2_slope2*/
-
-		17,  /* alpha_mant*/
-		27,  /* alpha_exp*/
-		23,  /* beta_mant*/
-		51,  /* beta_exp*/
-
-		0,  /* perform_agc_softsplit*/
-	}
-};
-
-static struct dibx000_bandwidth_config dib807x_bw_config_12_mhz = {
-	60000, 15000, /* internal, sampling*/
-	1, 20, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass*/
-	0, 0, 1, 1, 2, /* misc: refdiv, bypclk_div, IO_CLK_en_core,
-			  ADClkSrc, modulo */
-	(3 << 14) | (1 << 12) | (599 << 0), /* sad_cfg: refsel, sel, freq_15k*/
-	(0 << 25) | 0, /* ifreq = 0.000000 MHz*/
-	18179755, /* timf*/
-	12000000, /* xtal_hz*/
-};
-
-static struct dib8000_config dib807x_dib8000_config[2] = {
-	{
-		.output_mpeg2_in_188_bytes = 1,
-
-		.agc_config_count = 2,
-		.agc = dib807x_agc_config,
-		.pll = &dib807x_bw_config_12_mhz,
-		.tuner_is_baseband = 1,
-
-		.gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
-		.gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
-		.gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
-
-		.hostbus_diversity = 1,
-		.div_cfg = 1,
-		.agc_control = &dib0070_ctrl_agc_filter,
-		.output_mode = OUTMODE_MPEG2_FIFO,
-		.drives = 0x2d98,
-	}, {
-		.output_mpeg2_in_188_bytes = 1,
-
-		.agc_config_count = 2,
-		.agc = dib807x_agc_config,
-		.pll = &dib807x_bw_config_12_mhz,
-		.tuner_is_baseband = 1,
-
-		.gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
-		.gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
-		.gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
-
-		.hostbus_diversity = 1,
-		.agc_control = &dib0070_ctrl_agc_filter,
-		.output_mode = OUTMODE_MPEG2_FIFO,
-		.drives = 0x2d98,
-	}
-};
-
-static int dib80xx_tuner_reset(struct dvb_frontend *fe, int onoff)
-{
-	return dib8000_set_gpio(fe, 5, 0, !onoff);
-}
-
-static int dib80xx_tuner_sleep(struct dvb_frontend *fe, int onoff)
-{
-	return dib8000_set_gpio(fe, 0, 0, onoff);
-}
-
-static const struct dib0070_wbd_gain_cfg dib8070_wbd_gain_cfg[] = {
-    { 240,      7},
-    { 0xffff,   6},
-};
-
-static struct dib0070_config dib807x_dib0070_config[2] = {
-	{
-		.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
-		.reset = dib80xx_tuner_reset,
-		.sleep = dib80xx_tuner_sleep,
-		.clock_khz = 12000,
-		.clock_pad_drive = 4,
-		.vga_filter = 1,
-		.force_crystal_mode = 1,
-		.enable_third_order_filter = 1,
-		.charge_pump = 0,
-		.wbd_gain = dib8070_wbd_gain_cfg,
-		.osc_buffer_state = 0,
-		.freq_offset_khz_uhf = -100,
-		.freq_offset_khz_vhf = -100,
-	}, {
-		.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
-		.reset = dib80xx_tuner_reset,
-		.sleep = dib80xx_tuner_sleep,
-		.clock_khz = 12000,
-		.clock_pad_drive = 2,
-		.vga_filter = 1,
-		.force_crystal_mode = 1,
-		.enable_third_order_filter = 1,
-		.charge_pump = 0,
-		.wbd_gain = dib8070_wbd_gain_cfg,
-		.osc_buffer_state = 0,
-		.freq_offset_khz_uhf = -25,
-		.freq_offset_khz_vhf = -25,
-	}
-};
-
-static int dib807x_set_param_override(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct dib0700_adapter_state *state = adap->priv;
-
-	u16 offset = dib0070_wbd_offset(fe);
-	u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
-	switch (band) {
-	case BAND_VHF:
-		offset += 750;
-		break;
-	case BAND_UHF:  /* fall-thru wanted */
-	default:
-		offset += 250; break;
-	}
-	deb_info("WBD for DiB8000: %d\n", offset);
-	dib8000_set_wbd_ref(fe, offset);
-
-	return state->set_param_save(fe);
-}
-
-static int dib807x_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_adapter_state *st = adap->priv;
-	struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe,
-			DIBX000_I2C_INTERFACE_TUNER, 1);
-
-	if (adap->id == 0) {
-		if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
-				&dib807x_dib0070_config[0]) == NULL)
-			return -ENODEV;
-	} else {
-		if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
-				&dib807x_dib0070_config[1]) == NULL)
-			return -ENODEV;
-	}
-
-	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
-	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib807x_set_param_override;
-	return 0;
-}
-
-static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index,
-	u16 pid, int onoff)
-{
-	return dib8000_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
-}
-
-static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter,
-		int onoff)
-{
-	return dib8000_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
-}
-
-/* STK807x */
-static int stk807x_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-	msleep(10);
-	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-
-	dib0700_ctrl_clock(adap->dev, 72, 1);
-
-	msleep(10);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-	msleep(10);
-	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-
-	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
-				0x80, 0);
-
-	adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80,
-			      &dib807x_dib8000_config[0]);
-
-	return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
-}
-
-/* STK807xPVR */
-static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap)
-{
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
-	msleep(30);
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-	msleep(500);
-	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-
-	dib0700_ctrl_clock(adap->dev, 72, 1);
-
-	msleep(10);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-	msleep(10);
-	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-
-	/* initialize IC 0 */
-	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80, 0);
-
-	adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80,
-			      &dib807x_dib8000_config[0]);
-
-	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap)
-{
-	/* initialize IC 1 */
-	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82, 0);
-
-	adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82,
-			      &dib807x_dib8000_config[1]);
-
-	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-/* STK8096GP */
-static struct dibx000_agc_config dib8090_agc_config[2] = {
-	{
-	BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
-	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1,
-	 * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
-	 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
-	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
-	| (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
-
-	787,
-	10,
-
-	0,
-	118,
-
-	0,
-	3530,
-	1,
-	5,
-
-	65535,
-	0,
-
-	65535,
-	0,
-
-	0,
-	32,
-	114,
-	143,
-	144,
-	114,
-	227,
-	116,
-	117,
-
-	28,
-	26,
-	31,
-	51,
-
-	0,
-	},
-	{
-	BAND_CBAND,
-	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1,
-	 * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
-	 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
-	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
-	| (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
-
-	787,
-	10,
-
-	0,
-	118,
-
-	0,
-	3530,
-	1,
-	5,
-
-	0,
-	0,
-
-	65535,
-	0,
-
-	0,
-	32,
-	114,
-	143,
-	144,
-	114,
-	227,
-	116,
-	117,
-
-	28,
-	26,
-	31,
-	51,
-
-	0,
-	}
-};
-
-static struct dibx000_bandwidth_config dib8090_pll_config_12mhz = {
-	54000, 13500,
-	1, 18, 3, 1, 0,
-	0, 0, 1, 1, 2,
-	(3 << 14) | (1 << 12) | (599 << 0),
-	(0 << 25) | 0,
-	20199727,
-	12000000,
-};
-
-static int dib8090_get_adc_power(struct dvb_frontend *fe)
-{
-	return dib8000_get_adc_power(fe, 1);
-}
-
-static struct dib8000_config dib809x_dib8000_config[2] = {
-	{
-	.output_mpeg2_in_188_bytes = 1,
-
-	.agc_config_count = 2,
-	.agc = dib8090_agc_config,
-	.agc_control = dib0090_dcc_freq,
-	.pll = &dib8090_pll_config_12mhz,
-	.tuner_is_baseband = 1,
-
-	.gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
-	.gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
-	.gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
-
-	.hostbus_diversity = 1,
-	.div_cfg = 0x31,
-	.output_mode = OUTMODE_MPEG2_FIFO,
-	.drives = 0x2d98,
-	.diversity_delay = 48,
-	.refclksel = 3,
-	}, {
-	.output_mpeg2_in_188_bytes = 1,
-
-	.agc_config_count = 2,
-	.agc = dib8090_agc_config,
-	.agc_control = dib0090_dcc_freq,
-	.pll = &dib8090_pll_config_12mhz,
-	.tuner_is_baseband = 1,
-
-	.gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
-	.gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
-	.gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
-
-	.hostbus_diversity = 1,
-	.div_cfg = 0x31,
-	.output_mode = OUTMODE_DIVERSITY,
-	.drives = 0x2d08,
-	.diversity_delay = 1,
-	.refclksel = 3,
-	}
-};
-
-static struct dib0090_wbd_slope dib8090_wbd_table[] = {
-	/* max freq ; cold slope ; cold offset ; warm slope ; warm offset ; wbd gain */
-	{ 120,     0, 500,  0,   500, 4 }, /* CBAND */
-	{ 170,     0, 450,  0,   450, 4 }, /* CBAND */
-	{ 380,    48, 373, 28,   259, 6 }, /* VHF */
-	{ 860,    34, 700, 36,   616, 6 }, /* high UHF */
-	{ 0xFFFF, 34, 700, 36,   616, 6 }, /* default */
-};
-
-static struct dib0090_config dib809x_dib0090_config = {
-	.io.pll_bypass = 1,
-	.io.pll_range = 1,
-	.io.pll_prediv = 1,
-	.io.pll_loopdiv = 20,
-	.io.adc_clock_ratio = 8,
-	.io.pll_int_loop_filt = 0,
-	.io.clock_khz = 12000,
-	.reset = dib80xx_tuner_reset,
-	.sleep = dib80xx_tuner_sleep,
-	.clkouttobamse = 1,
-	.analog_output = 1,
-	.i2c_address = DEFAULT_DIB0090_I2C_ADDRESS,
-	.use_pwm_agc = 1,
-	.clkoutdrive = 1,
-	.get_adc_power = dib8090_get_adc_power,
-	.freq_offset_khz_uhf = -63,
-	.freq_offset_khz_vhf = -143,
-	.wbd = dib8090_wbd_table,
-	.fref_clock_ratio = 6,
-};
-
-static int dib8096_set_param_override(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct dib0700_adapter_state *state = adap->priv;
-	u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
-	u16 target;
-	int ret = 0;
-	enum frontend_tune_state tune_state = CT_SHUTDOWN;
-	u16 ltgain, rf_gain_limit;
-
-	ret = state->set_param_save(fe);
-	if (ret < 0)
-		return ret;
-
-	target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2;
-	dib8000_set_wbd_ref(fe, target);
-
-
-	if (band == BAND_CBAND) {
-		deb_info("tuning in CBAND - soft-AGC startup\n");
-		dib0090_set_tune_state(fe, CT_AGC_START);
-		do {
-			ret = dib0090_gain_control(fe);
-			msleep(ret);
-			tune_state = dib0090_get_tune_state(fe);
-			if (tune_state == CT_AGC_STEP_0)
-				dib8000_set_gpio(fe, 6, 0, 1);
-			else if (tune_state == CT_AGC_STEP_1) {
-				dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, &ltgain);
-				if (rf_gain_limit == 0)
-					dib8000_set_gpio(fe, 6, 0, 0);
-			}
-		} while (tune_state < CT_AGC_STOP);
-		dib0090_pwm_gain_reset(fe);
-		dib8000_pwm_agc_reset(fe);
-		dib8000_set_tune_state(fe, CT_DEMOD_START);
-	} else {
-		deb_info("not tuning in CBAND - standard AGC startup\n");
-		dib0090_pwm_gain_reset(fe);
-	}
-
-	return 0;
-}
-
-static int dib809x_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_adapter_state *st = adap->priv;
-	struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
-
-	if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL)
-		return -ENODEV;
-
-	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
-	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096_set_param_override;
-	return 0;
-}
-
-static int stk809x_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-	msleep(10);
-	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-
-	dib0700_ctrl_clock(adap->dev, 72, 1);
-
-	msleep(10);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-	msleep(10);
-	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-
-	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80, 0);
-
-	adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
-
-	return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
-}
-
-static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_adapter_state *st = adap->priv;
-	struct i2c_adapter *tun_i2c;
-	struct dvb_frontend *fe_slave  = dib8000_get_slave_frontend(adap->fe_adap[0].fe, 1);
-
-	if (fe_slave) {
-		tun_i2c = dib8000_get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1);
-		if (dvb_attach(dib0090_register, fe_slave, tun_i2c, &dib809x_dib0090_config) == NULL)
-			return -ENODEV;
-		fe_slave->dvb = adap->fe_adap[0].fe->dvb;
-		fe_slave->ops.tuner_ops.set_params = dib8096_set_param_override;
-	}
-	tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
-	if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL)
-		return -ENODEV;
-
-	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
-	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096_set_param_override;
-
-	return 0;
-}
-
-static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct dvb_frontend *fe_slave;
-
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-	msleep(1000);
-	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-
-	dib0700_ctrl_clock(adap->dev, 72, 1);
-
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-
-	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80, 0);
-
-	adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
-	if (adap->fe_adap[0].fe == NULL)
-		return -ENODEV;
-
-	fe_slave = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]);
-	dib8000_set_slave_frontend(adap->fe_adap[0].fe, fe_slave);
-
-	return fe_slave == NULL ?  -ENODEV : 0;
-}
-
-/* TFE8096P */
-static struct dibx000_agc_config dib8096p_agc_config[2] = {
-	{
-		.band_caps		= BAND_UHF,
-		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
-		   P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
-		   P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
-		   P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
-		   P_agc_write=0 */
-		.setup			= (0 << 15) | (0 << 14) | (5 << 11)
-			| (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5)
-			| (0 << 4) | (5 << 1) | (0 << 0),
-
-		.inv_gain		= 684,
-		.time_stabiliz	= 10,
-
-		.alpha_level	= 0,
-		.thlock			= 118,
-
-		.wbd_inv		= 0,
-		.wbd_ref		= 1200,
-		.wbd_sel		= 3,
-		.wbd_alpha		= 5,
-
-		.agc1_max		= 65535,
-		.agc1_min		= 0,
-
-		.agc2_max		= 32767,
-		.agc2_min		= 0,
-
-		.agc1_pt1		= 0,
-		.agc1_pt2		= 0,
-		.agc1_pt3		= 105,
-		.agc1_slope1	= 0,
-		.agc1_slope2	= 156,
-		.agc2_pt1		= 105,
-		.agc2_pt2		= 255,
-		.agc2_slope1	= 54,
-		.agc2_slope2	= 0,
-
-		.alpha_mant		= 28,
-		.alpha_exp		= 26,
-		.beta_mant		= 31,
-		.beta_exp		= 51,
-
-		.perform_agc_softsplit = 0,
-	} , {
-		.band_caps		= BAND_FM | BAND_VHF | BAND_CBAND,
-		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
-		   P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
-		   P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
-		   P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
-		   P_agc_write=0 */
-		.setup			= (0 << 15) | (0 << 14) | (5 << 11)
-			| (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5)
-			| (0 << 4) | (5 << 1) | (0 << 0),
-
-		.inv_gain		= 732,
-		.time_stabiliz  = 10,
-
-		.alpha_level	= 0,
-		.thlock			= 118,
-
-		.wbd_inv		= 0,
-		.wbd_ref		= 1200,
-		.wbd_sel		= 3,
-		.wbd_alpha		= 5,
-
-		.agc1_max		= 65535,
-		.agc1_min		= 0,
-
-		.agc2_max		= 32767,
-		.agc2_min		= 0,
-
-		.agc1_pt1		= 0,
-		.agc1_pt2		= 0,
-		.agc1_pt3		= 98,
-		.agc1_slope1	= 0,
-		.agc1_slope2	= 167,
-		.agc2_pt1		= 98,
-		.agc2_pt2		= 255,
-		.agc2_slope1	= 52,
-		.agc2_slope2	= 0,
-
-		.alpha_mant		= 28,
-		.alpha_exp		= 26,
-		.beta_mant		= 31,
-		.beta_exp		= 51,
-
-		.perform_agc_softsplit = 0,
-	}
-};
-
-static struct dibx000_bandwidth_config dib8096p_clock_config_12_mhz = {
-	108000, 13500,
-	1, 9, 1, 0, 0,
-	0, 0, 0, 0, 2,
-	(3 << 14) | (1 << 12) | (524 << 0),
-	(0 << 25) | 0,
-	20199729,
-	12000000,
-};
-
-static struct dib8000_config tfe8096p_dib8000_config = {
-	.output_mpeg2_in_188_bytes	= 1,
-	.hostbus_diversity			= 1,
-	.update_lna					= NULL,
-
-	.agc_config_count			= 2,
-	.agc						= dib8096p_agc_config,
-	.pll						= &dib8096p_clock_config_12_mhz,
-
-	.gpio_dir					= DIB8000_GPIO_DEFAULT_DIRECTIONS,
-	.gpio_val					= DIB8000_GPIO_DEFAULT_VALUES,
-	.gpio_pwm_pos				= DIB8000_GPIO_DEFAULT_PWM_POS,
-
-	.agc_control				= NULL,
-	.diversity_delay			= 48,
-	.output_mode				= OUTMODE_MPEG2_FIFO,
-	.enMpegOutput				= 1,
-};
-
-static struct dib0090_wbd_slope dib8096p_wbd_table[] = {
-	{ 380, 81, 850, 64, 540, 4},
-	{ 860, 51, 866, 21, 375, 4},
-	{1700, 0, 250, 0, 100, 6},
-	{2600, 0, 250, 0, 100, 6},
-	{ 0xFFFF, 0, 0, 0, 0, 0},
-};
-
-static const struct dib0090_config tfe8096p_dib0090_config = {
-	.io.clock_khz			= 12000,
-	.io.pll_bypass			= 0,
-	.io.pll_range			= 0,
-	.io.pll_prediv			= 3,
-	.io.pll_loopdiv			= 6,
-	.io.adc_clock_ratio		= 0,
-	.io.pll_int_loop_filt	= 0,
-	.reset					= dib8096p_tuner_sleep,
-	.sleep					= dib8096p_tuner_sleep,
-
-	.freq_offset_khz_uhf	= -143,
-	.freq_offset_khz_vhf	= -143,
-
-	.get_adc_power			= dib8090_get_adc_power,
-
-	.clkouttobamse			= 1,
-	.analog_output			= 0,
-
-	.wbd_vhf_offset			= 0,
-	.wbd_cband_offset		= 0,
-	.use_pwm_agc			= 1,
-	.clkoutdrive			= 0,
-
-	.fref_clock_ratio		= 1,
-
-	.wbd					= dib8096p_wbd_table,
-
-	.ls_cfg_pad_drv			= 0,
-	.data_tx_drv			= 0,
-	.low_if					= NULL,
-	.in_soc					= 1,
-	.force_cband_input		= 0,
-};
-
-struct dibx090p_adc {
-	u32 freq;			/* RF freq MHz */
-	u32 timf;			/* New Timf */
-	u32 pll_loopdiv;	/* New prediv */
-	u32 pll_prediv;		/* New loopdiv */
-};
-
-struct dibx090p_adc dib8090p_adc_tab[] = {
-	{ 50000, 17043521, 16, 3}, /* 64 MHz */
-	{878000, 20199729, 9, 1}, /* 60 MHz */
-	{0xffffffff, 0, 0, 0}, /* 60 MHz */
-};
-
-static int dib8096p_agc_startup(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct dib0700_adapter_state *state = adap->priv;
-	struct dibx000_bandwidth_config pll;
-	u16 target;
-	int better_sampling_freq = 0, ret;
-	struct dibx090p_adc *adc_table = &dib8090p_adc_tab[0];
-
-	ret = state->set_param_save(fe);
-	if (ret < 0)
-		return ret;
-	memset(&pll, 0, sizeof(struct dibx000_bandwidth_config));
-
-	dib0090_pwm_gain_reset(fe);
-	/* dib0090_get_wbd_target is returning any possible
-	   temperature compensated wbd-target */
-	target = (dib0090_get_wbd_target(fe) * 8  + 1) / 2;
-	dib8000_set_wbd_ref(fe, target);
-
-
-	while (p->frequency / 1000 > adc_table->freq) {
-		better_sampling_freq = 1;
-		adc_table++;
-	}
-
-	if ((adc_table->freq != 0xffffffff) && better_sampling_freq) {
-		pll.pll_ratio  = adc_table->pll_loopdiv;
-		pll.pll_prediv = adc_table->pll_prediv;
-		dib8000_update_pll(fe, &pll);
-		dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc_table->timf);
-	}
-	return 0;
-}
-
-static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-
-	dib0700_ctrl_clock(adap->dev, 72, 1);
-
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-
-	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80, 1);
-
-	adap->fe_adap[0].fe = dvb_attach(dib8000_attach,
-			&adap->dev->i2c_adap, 0x80, &tfe8096p_dib8000_config);
-
-	return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
-}
-
-static int tfe8096p_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_adapter_state *st = adap->priv;
-	struct i2c_adapter *tun_i2c = dib8096p_get_i2c_tuner(adap->fe_adap[0].fe);
-
-	if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
-				&tfe8096p_dib0090_config) == NULL)
-		return -ENODEV;
-
-	dib8000_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
-
-	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
-	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096p_agc_startup;
-	return 0;
-}
-
-/* STK9090M */
-static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
-{
-	return dib9000_fw_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
-}
-
-static int dib90x0_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
-{
-	return dib9000_fw_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
-}
-
-static int dib90x0_tuner_reset(struct dvb_frontend *fe, int onoff)
-{
-	return dib9000_set_gpio(fe, 5, 0, !onoff);
-}
-
-static int dib90x0_tuner_sleep(struct dvb_frontend *fe, int onoff)
-{
-	return dib9000_set_gpio(fe, 0, 0, onoff);
-}
-
-static int dib01x0_pmu_update(struct i2c_adapter *i2c, u16 *data, u8 len)
-{
-	u8 wb[4] = { 0xc >> 8, 0xc & 0xff, 0, 0 };
-	u8 rb[2];
-	struct i2c_msg msg[2] = {
-		{.addr = 0x1e >> 1, .flags = 0, .buf = wb, .len = 2},
-		{.addr = 0x1e >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2},
-	};
-	u8 index_data;
-
-	dibx000_i2c_set_speed(i2c, 250);
-
-	if (i2c_transfer(i2c, msg, 2) != 2)
-		return -EIO;
-
-	switch (rb[0] << 8 | rb[1]) {
-	case 0:
-			deb_info("Found DiB0170 rev1: This version of DiB0170 is not supported any longer.\n");
-			return -EIO;
-	case 1:
-			deb_info("Found DiB0170 rev2");
-			break;
-	case 2:
-			deb_info("Found DiB0190 rev2");
-			break;
-	default:
-			deb_info("DiB01x0 not found");
-			return -EIO;
-	}
-
-	for (index_data = 0; index_data < len; index_data += 2) {
-		wb[2] = (data[index_data + 1] >> 8) & 0xff;
-		wb[3] = (data[index_data + 1]) & 0xff;
-
-		if (data[index_data] == 0) {
-			wb[0] = (data[index_data] >> 8) & 0xff;
-			wb[1] = (data[index_data]) & 0xff;
-			msg[0].len = 2;
-			if (i2c_transfer(i2c, msg, 2) != 2)
-				return -EIO;
-			wb[2] |= rb[0];
-			wb[3] |= rb[1] & ~(3 << 4);
-		}
-
-		wb[0] = (data[index_data] >> 8)&0xff;
-		wb[1] = (data[index_data])&0xff;
-		msg[0].len = 4;
-		if (i2c_transfer(i2c, &msg[0], 1) != 1)
-			return -EIO;
-	}
-	return 0;
-}
-
-static struct dib9000_config stk9090m_config = {
-	.output_mpeg2_in_188_bytes = 1,
-	.output_mode = OUTMODE_MPEG2_FIFO,
-	.vcxo_timer = 279620,
-	.timing_frequency = 20452225,
-	.demod_clock_khz = 60000,
-	.xtal_clock_khz = 30000,
-	.if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0),
-	.subband = {
-		2,
-		{
-			{ 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0008 } }, /* GPIO 3 to 1 for VHF */
-			{ 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0000 } }, /* GPIO 3 to 0 for UHF */
-			{ 0 },
-		},
-	},
-	.gpio_function = {
-		{ .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 },
-		{ .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 },
-	},
-};
-
-static struct dib9000_config nim9090md_config[2] = {
-	{
-		.output_mpeg2_in_188_bytes = 1,
-		.output_mode = OUTMODE_MPEG2_FIFO,
-		.vcxo_timer = 279620,
-		.timing_frequency = 20452225,
-		.demod_clock_khz = 60000,
-		.xtal_clock_khz = 30000,
-		.if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0),
-	}, {
-		.output_mpeg2_in_188_bytes = 1,
-		.output_mode = OUTMODE_DIVERSITY,
-		.vcxo_timer = 279620,
-		.timing_frequency = 20452225,
-		.demod_clock_khz = 60000,
-		.xtal_clock_khz = 30000,
-		.if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0),
-		.subband = {
-			2,
-			{
-				{ 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0006 } }, /* GPIO 1 and 2 to 1 for VHF */
-				{ 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0000 } }, /* GPIO 1 and 2 to 0 for UHF */
-				{ 0 },
-			},
-		},
-		.gpio_function = {
-			{ .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 },
-			{ .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 },
-		},
-	}
-};
-
-static struct dib0090_config dib9090_dib0090_config = {
-	.io.pll_bypass = 0,
-	.io.pll_range = 1,
-	.io.pll_prediv = 1,
-	.io.pll_loopdiv = 8,
-	.io.adc_clock_ratio = 8,
-	.io.pll_int_loop_filt = 0,
-	.io.clock_khz = 30000,
-	.reset = dib90x0_tuner_reset,
-	.sleep = dib90x0_tuner_sleep,
-	.clkouttobamse = 0,
-	.analog_output = 0,
-	.use_pwm_agc = 0,
-	.clkoutdrive = 0,
-	.freq_offset_khz_uhf = 0,
-	.freq_offset_khz_vhf = 0,
-};
-
-static struct dib0090_config nim9090md_dib0090_config[2] = {
-	{
-		.io.pll_bypass = 0,
-		.io.pll_range = 1,
-		.io.pll_prediv = 1,
-		.io.pll_loopdiv = 8,
-		.io.adc_clock_ratio = 8,
-		.io.pll_int_loop_filt = 0,
-		.io.clock_khz = 30000,
-		.reset = dib90x0_tuner_reset,
-		.sleep = dib90x0_tuner_sleep,
-		.clkouttobamse = 1,
-		.analog_output = 0,
-		.use_pwm_agc = 0,
-		.clkoutdrive = 0,
-		.freq_offset_khz_uhf = 0,
-		.freq_offset_khz_vhf = 0,
-	}, {
-		.io.pll_bypass = 0,
-		.io.pll_range = 1,
-		.io.pll_prediv = 1,
-		.io.pll_loopdiv = 8,
-		.io.adc_clock_ratio = 8,
-		.io.pll_int_loop_filt = 0,
-		.io.clock_khz = 30000,
-		.reset = dib90x0_tuner_reset,
-		.sleep = dib90x0_tuner_sleep,
-		.clkouttobamse = 0,
-		.analog_output = 0,
-		.use_pwm_agc = 0,
-		.clkoutdrive = 0,
-		.freq_offset_khz_uhf = 0,
-		.freq_offset_khz_vhf = 0,
-	}
-};
-
-
-static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_adapter_state *state = adap->priv;
-	struct dib0700_state *st = adap->dev->priv;
-	u32 fw_version;
-
-	/* Make use of the new i2c functions from FW 1.20 */
-	dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL);
-	if (fw_version >= 0x10200)
-		st->fw_use_new_i2c_api = 1;
-	dib0700_set_i2c_speed(adap->dev, 340);
-
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-
-	dib0700_ctrl_clock(adap->dev, 72, 1);
-
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-
-	dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80);
-
-	if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) {
-		deb_info("%s: Upload failed. (file not found?)\n", __func__);
-		return -ENODEV;
-	} else {
-		deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size);
-	}
-	stk9090m_config.microcode_B_fe_size = state->frontend_firmware->size;
-	stk9090m_config.microcode_B_fe_buffer = state->frontend_firmware->data;
-
-	adap->fe_adap[0].fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config);
-
-	return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
-}
-
-static int dib9090_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_adapter_state *state = adap->priv;
-	struct i2c_adapter *i2c = dib9000_get_tuner_interface(adap->fe_adap[0].fe);
-	u16 data_dib190[10] = {
-		1, 0x1374,
-		2, 0x01a2,
-		7, 0x0020,
-		0, 0x00ef,
-		8, 0x0486,
-	};
-
-	if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &dib9090_dib0090_config) == NULL)
-		return -ENODEV;
-	i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
-	if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0)
-		return -ENODEV;
-	dib0700_set_i2c_speed(adap->dev, 1500);
-	if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0)
-		return -ENODEV;
-	release_firmware(state->frontend_firmware);
-	return 0;
-}
-
-static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_adapter_state *state = adap->priv;
-	struct dib0700_state *st = adap->dev->priv;
-	struct i2c_adapter *i2c;
-	struct dvb_frontend *fe_slave;
-	u32 fw_version;
-
-	/* Make use of the new i2c functions from FW 1.20 */
-	dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL);
-	if (fw_version >= 0x10200)
-		st->fw_use_new_i2c_api = 1;
-	dib0700_set_i2c_speed(adap->dev, 340);
-
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-
-	dib0700_ctrl_clock(adap->dev, 72, 1);
-
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-
-	if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) {
-		deb_info("%s: Upload failed. (file not found?)\n", __func__);
-		return -EIO;
-	} else {
-		deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size);
-	}
-	nim9090md_config[0].microcode_B_fe_size = state->frontend_firmware->size;
-	nim9090md_config[0].microcode_B_fe_buffer = state->frontend_firmware->data;
-	nim9090md_config[1].microcode_B_fe_size = state->frontend_firmware->size;
-	nim9090md_config[1].microcode_B_fe_buffer = state->frontend_firmware->data;
-
-	dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, 0x80);
-	adap->fe_adap[0].fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]);
-
-	if (adap->fe_adap[0].fe == NULL)
-		return -ENODEV;
-
-	i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_3_4, 0);
-	dib9000_i2c_enumeration(i2c, 1, 0x12, 0x82);
-
-	fe_slave = dvb_attach(dib9000_attach, i2c, 0x82, &nim9090md_config[1]);
-	dib9000_set_slave_frontend(adap->fe_adap[0].fe, fe_slave);
-
-	return fe_slave == NULL ?  -ENODEV : 0;
-}
-
-static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_adapter_state *state = adap->priv;
-	struct i2c_adapter *i2c;
-	struct dvb_frontend *fe_slave;
-	u16 data_dib190[10] = {
-		1, 0x5374,
-		2, 0x01ae,
-		7, 0x0020,
-		0, 0x00ef,
-		8, 0x0406,
-	};
-	i2c = dib9000_get_tuner_interface(adap->fe_adap[0].fe);
-	if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &nim9090md_dib0090_config[0]) == NULL)
-		return -ENODEV;
-	i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
-	if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0)
-		return -ENODEV;
-
-	dib0700_set_i2c_speed(adap->dev, 1500);
-	if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0)
-		return -ENODEV;
-
-	fe_slave = dib9000_get_slave_frontend(adap->fe_adap[0].fe, 1);
-	if (fe_slave != NULL) {
-		i2c = dib9000_get_component_bus_interface(adap->fe_adap[0].fe);
-		dib9000_set_i2c_adapter(fe_slave, i2c);
-
-		i2c = dib9000_get_tuner_interface(fe_slave);
-		if (dvb_attach(dib0090_fw_register, fe_slave, i2c, &nim9090md_dib0090_config[1]) == NULL)
-			return -ENODEV;
-		fe_slave->dvb = adap->fe_adap[0].fe->dvb;
-		dib9000_fw_set_component_bus_speed(adap->fe_adap[0].fe, 1500);
-		if (dib9000_firmware_post_pll_init(fe_slave) < 0)
-			return -ENODEV;
-	}
-	release_firmware(state->frontend_firmware);
-
-	return 0;
-}
-
-/* NIM7090 */
-struct dib7090p_best_adc {
-	u32 timf;
-	u32 pll_loopdiv;
-	u32 pll_prediv;
-};
-
-static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_best_adc *adc)
-{
-	u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1;
-
-	u16 xtal = 12000;
-	u32 fcp_min = 1900;  /* PLL Minimum Frequency comparator KHz */
-	u32 fcp_max = 20000; /* PLL Maximum Frequency comparator KHz */
-	u32 fdem_max = 76000;
-	u32 fdem_min = 69500;
-	u32 fcp = 0, fs = 0, fdem = 0;
-	u32 harmonic_id = 0;
-
-	adc->pll_loopdiv = loopdiv;
-	adc->pll_prediv = prediv;
-	adc->timf = 0;
-
-	deb_info("bandwidth = %d fdem_min =%d", fe->dtv_property_cache.bandwidth_hz, fdem_min);
-
-	/* Find Min and Max prediv */
-	while ((xtal/max_prediv) >= fcp_min)
-		max_prediv++;
-
-	max_prediv--;
-	min_prediv = max_prediv;
-	while ((xtal/min_prediv) <= fcp_max) {
-		min_prediv--;
-		if (min_prediv == 1)
-			break;
-	}
-	deb_info("MIN prediv = %d : MAX prediv = %d", min_prediv, max_prediv);
-
-	min_prediv = 2;
-
-	for (prediv = min_prediv ; prediv < max_prediv; prediv++) {
-		fcp = xtal / prediv;
-		if (fcp > fcp_min && fcp < fcp_max) {
-			for (loopdiv = 1 ; loopdiv < 64 ; loopdiv++) {
-				fdem = ((xtal/prediv) * loopdiv);
-				fs   = fdem / 4;
-				/* test min/max system restrictions */
-
-				if ((fdem >= fdem_min) && (fdem <= fdem_max) && (fs >= fe->dtv_property_cache.bandwidth_hz/1000)) {
-					spur = 0;
-					/* test fs harmonics positions */
-					for (harmonic_id = (fe->dtv_property_cache.frequency / (1000*fs)) ;  harmonic_id <= ((fe->dtv_property_cache.frequency / (1000*fs))+1) ; harmonic_id++) {
-						if (((fs*harmonic_id) >= ((fe->dtv_property_cache.frequency/1000) - (fe->dtv_property_cache.bandwidth_hz/2000))) &&  ((fs*harmonic_id) <= ((fe->dtv_property_cache.frequency/1000) + (fe->dtv_property_cache.bandwidth_hz/2000)))) {
-							spur = 1;
-							break;
-						}
-					}
-
-					if (!spur) {
-						adc->pll_loopdiv = loopdiv;
-						adc->pll_prediv = prediv;
-						adc->timf = 2396745143UL/fdem*(1 << 9);
-						adc->timf += ((2396745143UL%fdem) << 9)/fdem;
-						deb_info("loopdiv=%i prediv=%i timf=%i", loopdiv, prediv, adc->timf);
-						break;
-					}
-				}
-			}
-		}
-		if (!spur)
-			break;
-	}
-
-
-	if (adc->pll_loopdiv == 0 && adc->pll_prediv == 0)
-		return -EINVAL;
-	else
-		return 0;
-}
-
-static int dib7090_agc_startup(struct dvb_frontend *fe)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct dib0700_adapter_state *state = adap->priv;
-	struct dibx000_bandwidth_config pll;
-	u16 target;
-	struct dib7090p_best_adc adc;
-	int ret;
-
-	ret = state->set_param_save(fe);
-	if (ret < 0)
-		return ret;
-
-	memset(&pll, 0, sizeof(struct dibx000_bandwidth_config));
-	dib0090_pwm_gain_reset(fe);
-	target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2;
-	dib7000p_set_wbd_ref(fe, target);
-
-	if (dib7090p_get_best_sampling(fe, &adc) == 0) {
-		pll.pll_ratio  = adc.pll_loopdiv;
-		pll.pll_prediv = adc.pll_prediv;
-
-		dib7000p_update_pll(fe, &pll);
-		dib7000p_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf);
-	}
-	return 0;
-}
-
-static int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
-{
-	deb_info("AGC restart callback: %d", restart);
-	if (restart == 0) /* before AGC startup */
-		dib0090_set_dc_servo(fe, 1);
-	return 0;
-}
-
-static int dib7090e_update_lna(struct dvb_frontend *fe, u16 agc_global)
-{
-	u16 agc1 = 0, agc2, wbd = 0, wbd_target, wbd_offset, threshold_agc1;
-	s16 wbd_delta;
-
-	if ((fe->dtv_property_cache.frequency) < 400000000)
-		threshold_agc1 = 25000;
-	else
-		threshold_agc1 = 30000;
-
-	wbd_target = (dib0090_get_wbd_target(fe)*8+1)/2;
-	wbd_offset = dib0090_get_wbd_offset(fe);
-	dib7000p_get_agc_values(fe, NULL, &agc1, &agc2, &wbd);
-	wbd_delta = (s16)wbd - (((s16)wbd_offset+10)*4) ;
-
-	deb_info("update lna, agc_global=%d agc1=%d agc2=%d",
-			agc_global, agc1, agc2);
-	deb_info("update lna, wbd=%d wbd target=%d wbd offset=%d wbd delta=%d",
-			wbd, wbd_target, wbd_offset, wbd_delta);
-
-	if ((agc1 < threshold_agc1) && (wbd_delta > 0)) {
-		dib0090_set_switch(fe, 1, 1, 1);
-		dib0090_set_vga(fe, 0);
-		dib0090_update_rframp_7090(fe, 0);
-		dib0090_update_tuning_table_7090(fe, 0);
-	} else {
-		dib0090_set_vga(fe, 1);
-		dib0090_update_rframp_7090(fe, 1);
-		dib0090_update_tuning_table_7090(fe, 1);
-		dib0090_set_switch(fe, 0, 0, 0);
-	}
-
-	return 0;
-}
-
-static struct dib0090_wbd_slope dib7090_wbd_table[] = {
-	{ 380,   81, 850, 64, 540,  4},
-	{ 860,   51, 866, 21,  375, 4},
-	{1700,    0, 250, 0,   100, 6},
-	{2600,    0, 250, 0,   100, 6},
-	{ 0xFFFF, 0,   0, 0,   0,   0},
-};
-
-static struct dib0090_wbd_slope dib7090e_wbd_table[] = {
-	{ 380,   81, 850, 64, 540,	4},
-	{ 700,   51, 866, 21,  320,	4},
-	{ 860,   48, 666, 18,  330,	6},
-	{1700,    0, 250, 0,   100, 6},
-	{2600,    0, 250, 0,   100, 6},
-	{ 0xFFFF, 0,   0, 0,   0,	0},
-};
-
-static struct dibx000_agc_config dib7090_agc_config[2] = {
-	{
-		.band_caps      = BAND_UHF,
-		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
-		* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
-		.setup          = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
-
-		.inv_gain       = 687,
-		.time_stabiliz  = 10,
-
-		.alpha_level    = 0,
-		.thlock         = 118,
-
-		.wbd_inv        = 0,
-		.wbd_ref        = 1200,
-		.wbd_sel        = 3,
-		.wbd_alpha      = 5,
-
-		.agc1_max       = 65535,
-		.agc1_min       = 0,
-
-		.agc2_max       = 65535,
-		.agc2_min       = 0,
-
-		.agc1_pt1       = 0,
-		.agc1_pt2       = 32,
-		.agc1_pt3       = 114,
-		.agc1_slope1    = 143,
-		.agc1_slope2    = 144,
-		.agc2_pt1       = 114,
-		.agc2_pt2       = 227,
-		.agc2_slope1    = 116,
-		.agc2_slope2    = 117,
-
-		.alpha_mant     = 18,
-		.alpha_exp      = 0,
-		.beta_mant      = 20,
-		.beta_exp       = 59,
-
-		.perform_agc_softsplit = 0,
-	} , {
-		.band_caps      = BAND_FM | BAND_VHF | BAND_CBAND,
-		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
-		* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
-		.setup          = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
-
-		.inv_gain       = 732,
-		.time_stabiliz  = 10,
-
-		.alpha_level    = 0,
-		.thlock         = 118,
-
-		.wbd_inv        = 0,
-		.wbd_ref        = 1200,
-		.wbd_sel        = 3,
-		.wbd_alpha      = 5,
-
-		.agc1_max       = 65535,
-		.agc1_min       = 0,
-
-		.agc2_max       = 65535,
-		.agc2_min       = 0,
-
-		.agc1_pt1       = 0,
-		.agc1_pt2       = 0,
-		.agc1_pt3       = 98,
-		.agc1_slope1    = 0,
-		.agc1_slope2    = 167,
-		.agc2_pt1       = 98,
-		.agc2_pt2       = 255,
-		.agc2_slope1    = 104,
-		.agc2_slope2    = 0,
-
-		.alpha_mant     = 18,
-		.alpha_exp      = 0,
-		.beta_mant      = 20,
-		.beta_exp       = 59,
-
-		.perform_agc_softsplit = 0,
-	}
-};
-
-static struct dibx000_bandwidth_config dib7090_clock_config_12_mhz = {
-	60000, 15000,
-	1, 5, 0, 0, 0,
-	0, 0, 1, 1, 2,
-	(3 << 14) | (1 << 12) | (524 << 0),
-	(0 << 25) | 0,
-	20452225,
-	15000000,
-};
-
-static struct dib7000p_config nim7090_dib7000p_config = {
-	.output_mpeg2_in_188_bytes  = 1,
-	.hostbus_diversity			= 1,
-	.tuner_is_baseband			= 1,
-	.update_lna					= NULL,
-
-	.agc_config_count			= 2,
-	.agc						= dib7090_agc_config,
-
-	.bw							= &dib7090_clock_config_12_mhz,
-
-	.gpio_dir					= DIB7000P_GPIO_DEFAULT_DIRECTIONS,
-	.gpio_val					= DIB7000P_GPIO_DEFAULT_VALUES,
-	.gpio_pwm_pos				= DIB7000P_GPIO_DEFAULT_PWM_POS,
-
-	.pwm_freq_div				= 0,
-
-	.agc_control				= dib7090_agc_restart,
-
-	.spur_protect				= 0,
-	.disable_sample_and_hold	= 0,
-	.enable_current_mirror		= 0,
-	.diversity_delay			= 0,
-
-	.output_mode				= OUTMODE_MPEG2_FIFO,
-	.enMpegOutput				= 1,
-};
-
-static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = {
-	{
-		.output_mpeg2_in_188_bytes  = 1,
-		.hostbus_diversity			= 1,
-		.tuner_is_baseband			= 1,
-		.update_lna					= NULL,
-
-		.agc_config_count			= 2,
-		.agc						= dib7090_agc_config,
-
-		.bw							= &dib7090_clock_config_12_mhz,
-
-		.gpio_dir					= DIB7000P_GPIO_DEFAULT_DIRECTIONS,
-		.gpio_val					= DIB7000P_GPIO_DEFAULT_VALUES,
-		.gpio_pwm_pos				= DIB7000P_GPIO_DEFAULT_PWM_POS,
-
-		.pwm_freq_div				= 0,
-
-		.agc_control				= dib7090_agc_restart,
-
-		.spur_protect				= 0,
-		.disable_sample_and_hold	= 0,
-		.enable_current_mirror		= 0,
-		.diversity_delay			= 0,
-
-		.output_mode				= OUTMODE_MPEG2_PAR_GATED_CLK,
-		.default_i2c_addr			= 0x90,
-		.enMpegOutput				= 1,
-	}, {
-		.output_mpeg2_in_188_bytes  = 1,
-		.hostbus_diversity			= 1,
-		.tuner_is_baseband			= 1,
-		.update_lna					= NULL,
-
-		.agc_config_count			= 2,
-		.agc						= dib7090_agc_config,
-
-		.bw							= &dib7090_clock_config_12_mhz,
-
-		.gpio_dir					= DIB7000P_GPIO_DEFAULT_DIRECTIONS,
-		.gpio_val					= DIB7000P_GPIO_DEFAULT_VALUES,
-		.gpio_pwm_pos				= DIB7000P_GPIO_DEFAULT_PWM_POS,
-
-		.pwm_freq_div				= 0,
-
-		.agc_control				= dib7090_agc_restart,
-
-		.spur_protect				= 0,
-		.disable_sample_and_hold	= 0,
-		.enable_current_mirror		= 0,
-		.diversity_delay			= 0,
-
-		.output_mode				= OUTMODE_MPEG2_PAR_GATED_CLK,
-		.default_i2c_addr			= 0x92,
-		.enMpegOutput				= 0,
-	}
-};
-
-static struct dib7000p_config tfe7090e_dib7000p_config = {
-	.output_mpeg2_in_188_bytes  = 1,
-	.hostbus_diversity			= 1,
-	.tuner_is_baseband			= 1,
-	.update_lna					= dib7090e_update_lna,
-
-	.agc_config_count			= 2,
-	.agc						= dib7090_agc_config,
-
-	.bw							= &dib7090_clock_config_12_mhz,
-
-	.gpio_dir					= DIB7000P_GPIO_DEFAULT_DIRECTIONS,
-	.gpio_val					= DIB7000P_GPIO_DEFAULT_VALUES,
-	.gpio_pwm_pos				= DIB7000P_GPIO_DEFAULT_PWM_POS,
-
-	.pwm_freq_div				= 0,
-
-	.agc_control				= dib7090_agc_restart,
-
-	.spur_protect				= 0,
-	.disable_sample_and_hold	= 0,
-	.enable_current_mirror		= 0,
-	.diversity_delay			= 0,
-
-	.output_mode				= OUTMODE_MPEG2_FIFO,
-	.enMpegOutput				= 1,
-};
-
-static const struct dib0090_config nim7090_dib0090_config = {
-	.io.clock_khz = 12000,
-	.io.pll_bypass = 0,
-	.io.pll_range = 0,
-	.io.pll_prediv = 3,
-	.io.pll_loopdiv = 6,
-	.io.adc_clock_ratio = 0,
-	.io.pll_int_loop_filt = 0,
-	.reset = dib7090_tuner_sleep,
-	.sleep = dib7090_tuner_sleep,
-
-	.freq_offset_khz_uhf = 0,
-	.freq_offset_khz_vhf = 0,
-
-	.get_adc_power = dib7090_get_adc_power,
-
-	.clkouttobamse = 1,
-	.analog_output = 0,
-
-	.wbd_vhf_offset = 0,
-	.wbd_cband_offset = 0,
-	.use_pwm_agc = 1,
-	.clkoutdrive = 0,
-
-	.fref_clock_ratio = 0,
-
-	.wbd = dib7090_wbd_table,
-
-	.ls_cfg_pad_drv = 0,
-	.data_tx_drv = 0,
-	.low_if = NULL,
-	.in_soc = 1,
-};
-
-static const struct dib0090_config tfe7090e_dib0090_config = {
-	.io.clock_khz = 12000,
-	.io.pll_bypass = 0,
-	.io.pll_range = 0,
-	.io.pll_prediv = 3,
-	.io.pll_loopdiv = 6,
-	.io.adc_clock_ratio = 0,
-	.io.pll_int_loop_filt = 0,
-	.reset = dib7090_tuner_sleep,
-	.sleep = dib7090_tuner_sleep,
-
-	.freq_offset_khz_uhf = 0,
-	.freq_offset_khz_vhf = 0,
-
-	.get_adc_power = dib7090_get_adc_power,
-
-	.clkouttobamse = 1,
-	.analog_output = 0,
-
-	.wbd_vhf_offset = 0,
-	.wbd_cband_offset = 0,
-	.use_pwm_agc = 1,
-	.clkoutdrive = 0,
-
-	.fref_clock_ratio = 0,
-
-	.wbd = dib7090e_wbd_table,
-
-	.ls_cfg_pad_drv = 0,
-	.data_tx_drv = 0,
-	.low_if = NULL,
-	.in_soc = 1,
-	.force_cband_input = 1,
-	.is_dib7090e = 1,
-};
-
-static struct dib7000p_config tfe7790e_dib7000p_config = {
-	.output_mpeg2_in_188_bytes  = 1,
-	.hostbus_diversity			= 1,
-	.tuner_is_baseband			= 1,
-	.update_lna					= dib7090e_update_lna,
-
-	.agc_config_count			= 2,
-	.agc						= dib7090_agc_config,
-
-	.bw							= &dib7090_clock_config_12_mhz,
-
-	.gpio_dir					= DIB7000P_GPIO_DEFAULT_DIRECTIONS,
-	.gpio_val					= DIB7000P_GPIO_DEFAULT_VALUES,
-	.gpio_pwm_pos				= DIB7000P_GPIO_DEFAULT_PWM_POS,
-
-	.pwm_freq_div				= 0,
-
-	.agc_control				= dib7090_agc_restart,
-
-	.spur_protect				= 0,
-	.disable_sample_and_hold	= 0,
-	.enable_current_mirror		= 0,
-	.diversity_delay			= 0,
-
-	.output_mode				= OUTMODE_MPEG2_PAR_GATED_CLK,
-	.enMpegOutput				= 1,
-};
-
-static const struct dib0090_config tfe7790e_dib0090_config = {
-	.io.clock_khz = 12000,
-	.io.pll_bypass = 0,
-	.io.pll_range = 0,
-	.io.pll_prediv = 3,
-	.io.pll_loopdiv = 6,
-	.io.adc_clock_ratio = 0,
-	.io.pll_int_loop_filt = 0,
-	.reset = dib7090_tuner_sleep,
-	.sleep = dib7090_tuner_sleep,
-
-	.freq_offset_khz_uhf = 0,
-	.freq_offset_khz_vhf = 0,
-
-	.get_adc_power = dib7090_get_adc_power,
-
-	.clkouttobamse = 1,
-	.analog_output = 0,
-
-	.wbd_vhf_offset = 0,
-	.wbd_cband_offset = 0,
-	.use_pwm_agc = 1,
-	.clkoutdrive = 0,
-
-	.fref_clock_ratio = 0,
-
-	.wbd = dib7090e_wbd_table,
-
-	.ls_cfg_pad_drv = 0,
-	.data_tx_drv = 0,
-	.low_if = NULL,
-	.in_soc = 1,
-	.force_cband_input = 1,
-	.is_dib7090e = 1,
-	.force_crystal_mode = 1,
-};
-
-static const struct dib0090_config tfe7090pvr_dib0090_config[2] = {
-	{
-		.io.clock_khz = 12000,
-		.io.pll_bypass = 0,
-		.io.pll_range = 0,
-		.io.pll_prediv = 3,
-		.io.pll_loopdiv = 6,
-		.io.adc_clock_ratio = 0,
-		.io.pll_int_loop_filt = 0,
-		.reset = dib7090_tuner_sleep,
-		.sleep = dib7090_tuner_sleep,
-
-		.freq_offset_khz_uhf = 50,
-		.freq_offset_khz_vhf = 70,
-
-		.get_adc_power = dib7090_get_adc_power,
-
-		.clkouttobamse = 1,
-		.analog_output = 0,
-
-		.wbd_vhf_offset = 0,
-		.wbd_cband_offset = 0,
-		.use_pwm_agc = 1,
-		.clkoutdrive = 0,
-
-		.fref_clock_ratio = 0,
-
-		.wbd = dib7090_wbd_table,
-
-		.ls_cfg_pad_drv = 0,
-		.data_tx_drv = 0,
-		.low_if = NULL,
-		.in_soc = 1,
-	}, {
-		.io.clock_khz = 12000,
-		.io.pll_bypass = 0,
-		.io.pll_range = 0,
-		.io.pll_prediv = 3,
-		.io.pll_loopdiv = 6,
-		.io.adc_clock_ratio = 0,
-		.io.pll_int_loop_filt = 0,
-		.reset = dib7090_tuner_sleep,
-		.sleep = dib7090_tuner_sleep,
-
-		.freq_offset_khz_uhf = -50,
-		.freq_offset_khz_vhf = -70,
-
-		.get_adc_power = dib7090_get_adc_power,
-
-		.clkouttobamse = 1,
-		.analog_output = 0,
-
-		.wbd_vhf_offset = 0,
-		.wbd_cband_offset = 0,
-		.use_pwm_agc = 1,
-		.clkoutdrive = 0,
-
-		.fref_clock_ratio = 0,
-
-		.wbd = dib7090_wbd_table,
-
-		.ls_cfg_pad_drv = 0,
-		.data_tx_drv = 0,
-		.low_if = NULL,
-		.in_soc = 1,
-	}
-};
-
-static int nim7090_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-
-	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) {
-		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
-		return -ENODEV;
-	}
-	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config);
-
-	return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
-}
-
-static int nim7090_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_adapter_state *st = adap->priv;
-	struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
-
-	if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &nim7090_dib0090_config) == NULL)
-		return -ENODEV;
-
-	dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
-
-	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
-	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
-	return 0;
-}
-
-static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_state *st = adap->dev->priv;
-
-	/* The TFE7090 requires the dib0700 to not be in master mode */
-	st->disable_streaming_master_mode = 1;
-
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-
-	/* initialize IC 0 */
-	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) {
-		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
-		return -ENODEV;
-	}
-
-	dib0700_set_i2c_speed(adap->dev, 340);
-	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]);
-	if (adap->fe_adap[0].fe == NULL)
-		return -ENODEV;
-
-	dib7090_slave_reset(adap->fe_adap[0].fe);
-
-	return 0;
-}
-
-static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap)
-{
-	struct i2c_adapter *i2c;
-
-	if (adap->dev->adapter[0].fe_adap[0].fe == NULL) {
-		err("the master dib7090 has to be initialized first");
-		return -ENODEV; /* the master device has not been initialized */
-	}
-
-	i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1);
-	if (dib7000p_i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) {
-		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
-		return -ENODEV;
-	}
-
-	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]);
-	dib0700_set_i2c_speed(adap->dev, 200);
-
-	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-static int tfe7090pvr_tuner0_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_adapter_state *st = adap->priv;
-	struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
-
-	if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL)
-		return -ENODEV;
-
-	dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
-
-	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
-	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
-	return 0;
-}
-
-static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_adapter_state *st = adap->priv;
-	struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
-
-	if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL)
-		return -ENODEV;
-
-	dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
-
-	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
-	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
-	return 0;
-}
-
-static int tfe7090e_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-
-	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap,
-				1, 0x10, &tfe7090e_dib7000p_config) != 0) {
-		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
-				__func__);
-		return -ENODEV;
-	}
-	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
-			0x80, &tfe7090e_dib7000p_config);
-
-	return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
-}
-
-static int tfe7790e_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_state *st = adap->dev->priv;
-
-	/* The TFE7790E requires the dib0700 to not be in master mode */
-	st->disable_streaming_master_mode = 1;
-
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-	msleep(20);
-	dib0700_ctrl_clock(adap->dev, 72, 1);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-	msleep(20);
-	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-
-	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap,
-				1, 0x10, &tfe7790e_dib7000p_config) != 0) {
-		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
-				__func__);
-		return -ENODEV;
-	}
-	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
-			0x80, &tfe7790e_dib7000p_config);
-
-	return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
-}
-
-static int tfe7790e_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_adapter_state *st = adap->priv;
-	struct i2c_adapter *tun_i2c =
-		dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
-
-	if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
-				&tfe7790e_dib0090_config) == NULL)
-		return -ENODEV;
-
-	dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
-
-	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
-	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
-	return 0;
-}
-
-static int tfe7090e_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_adapter_state *st = adap->priv;
-	struct i2c_adapter *tun_i2c =
-		dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
-
-	if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
-				&tfe7090e_dib0090_config) == NULL)
-		return -ENODEV;
-
-	dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
-
-	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
-	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
-	return 0;
-}
-
-/* STK7070PD */
-static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
-	{
-		.output_mpeg2_in_188_bytes = 1,
-
-		.agc_config_count = 1,
-		.agc = &dib7070_agc_config,
-		.bw  = &dib7070_bw_config_12_mhz,
-		.tuner_is_baseband = 1,
-		.spur_protect = 1,
-
-		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
-		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
-		.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
-
-		.hostbus_diversity = 1,
-	}, {
-		.output_mpeg2_in_188_bytes = 1,
-
-		.agc_config_count = 1,
-		.agc = &dib7070_agc_config,
-		.bw  = &dib7070_bw_config_12_mhz,
-		.tuner_is_baseband = 1,
-		.spur_protect = 1,
-
-		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
-		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
-		.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
-
-		.hostbus_diversity = 1,
-	}
-};
-
-static void stk7070pd_init(struct dvb_usb_device *dev)
-{
-	dib0700_set_gpio(dev, GPIO6, GPIO_OUT, 1);
-	msleep(10);
-	dib0700_set_gpio(dev, GPIO9, GPIO_OUT, 1);
-	dib0700_set_gpio(dev, GPIO4, GPIO_OUT, 1);
-	dib0700_set_gpio(dev, GPIO7, GPIO_OUT, 1);
-	dib0700_set_gpio(dev, GPIO10, GPIO_OUT, 0);
-
-	dib0700_ctrl_clock(dev, 72, 1);
-
-	msleep(10);
-	dib0700_set_gpio(dev, GPIO10, GPIO_OUT, 1);
-}
-
-static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap)
-{
-	stk7070pd_init(adap->dev);
-
-	msleep(10);
-	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-
-	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18,
-				     stk7070pd_dib7000p_config) != 0) {
-		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
-		    __func__);
-		return -ENODEV;
-	}
-
-	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]);
-	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap)
-{
-	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]);
-	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-static int novatd_read_status_override(struct dvb_frontend *fe,
-		fe_status_t *stat)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct dvb_usb_device *dev = adap->dev;
-	struct dib0700_state *state = dev->priv;
-	int ret;
-
-	ret = state->read_status(fe, stat);
-
-	if (!ret)
-		dib0700_set_gpio(dev, adap->id == 0 ? GPIO1 : GPIO0, GPIO_OUT,
-				!!(*stat & FE_HAS_LOCK));
-
-	return ret;
-}
-
-static int novatd_sleep_override(struct dvb_frontend* fe)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct dvb_usb_device *dev = adap->dev;
-	struct dib0700_state *state = dev->priv;
-
-	/* turn off LED */
-	dib0700_set_gpio(dev, adap->id == 0 ? GPIO1 : GPIO0, GPIO_OUT, 0);
-
-	return state->sleep(fe);
-}
-
-/**
- * novatd_frontend_attach - Nova-TD specific attach
- *
- * Nova-TD has GPIO0, 1 and 2 for LEDs. So do not fiddle with them except for
- * information purposes.
- */
-static int novatd_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct dvb_usb_device *dev = adap->dev;
-	struct dib0700_state *st = dev->priv;
-
-	if (adap->id == 0) {
-		stk7070pd_init(dev);
-
-		/* turn the power LED on, the other two off (just in case) */
-		dib0700_set_gpio(dev, GPIO0, GPIO_OUT, 0);
-		dib0700_set_gpio(dev, GPIO1, GPIO_OUT, 0);
-		dib0700_set_gpio(dev, GPIO2, GPIO_OUT, 1);
-
-		if (dib7000p_i2c_enumeration(&dev->i2c_adap, 2, 18,
-					     stk7070pd_dib7000p_config) != 0) {
-			err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
-			    __func__);
-			return -ENODEV;
-		}
-	}
-
-	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &dev->i2c_adap,
-			adap->id == 0 ? 0x80 : 0x82,
-			&stk7070pd_dib7000p_config[adap->id]);
-
-	if (adap->fe_adap[0].fe == NULL)
-		return -ENODEV;
-
-	st->read_status = adap->fe_adap[0].fe->ops.read_status;
-	adap->fe_adap[0].fe->ops.read_status = novatd_read_status_override;
-	st->sleep = adap->fe_adap[0].fe->ops.sleep;
-	adap->fe_adap[0].fe->ops.sleep = novatd_sleep_override;
-
-	return 0;
-}
-
-/* S5H1411 */
-static struct s5h1411_config pinnacle_801e_config = {
-	.output_mode   = S5H1411_PARALLEL_OUTPUT,
-	.gpio          = S5H1411_GPIO_OFF,
-	.mpeg_timing   = S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK,
-	.qam_if        = S5H1411_IF_44000,
-	.vsb_if        = S5H1411_IF_44000,
-	.inversion     = S5H1411_INVERSION_OFF,
-	.status_mode   = S5H1411_DEMODLOCKING
-};
-
-/* Pinnacle PCTV HD Pro 801e GPIOs map:
-   GPIO0  - currently unknown
-   GPIO1  - xc5000 tuner reset
-   GPIO2  - CX25843 sleep
-   GPIO3  - currently unknown
-   GPIO4  - currently unknown
-   GPIO6  - currently unknown
-   GPIO7  - currently unknown
-   GPIO9  - currently unknown
-   GPIO10 - CX25843 reset
- */
-static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_state *st = adap->dev->priv;
-
-	/* Make use of the new i2c functions from FW 1.20 */
-	st->fw_use_new_i2c_api = 1;
-
-	/* The s5h1411 requires the dib0700 to not be in master mode */
-	st->disable_streaming_master_mode = 1;
-
-	/* All msleep values taken from Windows USB trace */
-	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0);
-	dib0700_set_gpio(adap->dev, GPIO3, GPIO_OUT, 0);
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-	msleep(400);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-	msleep(60);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-	msleep(30);
-	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-	dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 0);
-	msleep(30);
-
-	/* Put the CX25843 to sleep for now since we're in digital mode */
-	dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1);
-
-	/* GPIOs are initialized, do the attach */
-	adap->fe_adap[0].fe = dvb_attach(s5h1411_attach, &pinnacle_801e_config,
-			      &adap->dev->i2c_adap);
-	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-static int dib0700_xc5000_tuner_callback(void *priv, int component,
-					 int command, int arg)
-{
-	struct dvb_usb_adapter *adap = priv;
-
-	if (command == XC5000_TUNER_RESET) {
-		/* Reset the tuner */
-		dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0);
-		msleep(10);
-		dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1);
-		msleep(10);
-	} else {
-		err("xc5000: unknown tuner callback command: %d\n", command);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static struct xc5000_config s5h1411_xc5000_tunerconfig = {
-	.i2c_address      = 0x64,
-	.if_khz           = 5380,
-};
-
-static int xc5000_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	/* FIXME: generalize & move to common area */
-	adap->fe_adap[0].fe->callback = dib0700_xc5000_tuner_callback;
-
-	return dvb_attach(xc5000_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
-			  &s5h1411_xc5000_tunerconfig)
-		== NULL ? -ENODEV : 0;
-}
-
-static int dib0700_xc4000_tuner_callback(void *priv, int component,
-					 int command, int arg)
-{
-	struct dvb_usb_adapter *adap = priv;
-
-	if (command == XC4000_TUNER_RESET) {
-		/* Reset the tuner */
-		dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 0);
-		msleep(10);
-		dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
-	} else {
-		err("xc4000: unknown tuner callback command: %d\n", command);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static struct dibx000_agc_config stk7700p_7000p_xc4000_agc_config = {
-	.band_caps = BAND_UHF | BAND_VHF,
-	.setup = 0x64,
-	.inv_gain = 0x02c8,
-	.time_stabiliz = 0x15,
-	.alpha_level = 0x00,
-	.thlock = 0x76,
-	.wbd_inv = 0x01,
-	.wbd_ref = 0x0b33,
-	.wbd_sel = 0x00,
-	.wbd_alpha = 0x02,
-	.agc1_max = 0x00,
-	.agc1_min = 0x00,
-	.agc2_max = 0x9b26,
-	.agc2_min = 0x26ca,
-	.agc1_pt1 = 0x00,
-	.agc1_pt2 = 0x00,
-	.agc1_pt3 = 0x00,
-	.agc1_slope1 = 0x00,
-	.agc1_slope2 = 0x00,
-	.agc2_pt1 = 0x00,
-	.agc2_pt2 = 0x80,
-	.agc2_slope1 = 0x1d,
-	.agc2_slope2 = 0x1d,
-	.alpha_mant = 0x11,
-	.alpha_exp = 0x1b,
-	.beta_mant = 0x17,
-	.beta_exp = 0x33,
-	.perform_agc_softsplit = 0x00,
-};
-
-static struct dibx000_bandwidth_config stk7700p_xc4000_pll_config = {
-	60000, 30000,	/* internal, sampling */
-	1, 8, 3, 1, 0,	/* pll_cfg: prediv, ratio, range, reset, bypass */
-	0, 0, 1, 1, 0,	/* misc: refdiv, bypclk_div, IO_CLK_en_core, */
-			/* ADClkSrc, modulo */
-	(3 << 14) | (1 << 12) | 524,	/* sad_cfg: refsel, sel, freq_15k */
-	39370534,	/* ifreq */
-	20452225,	/* timf */
-	30000000	/* xtal */
-};
-
-/* FIXME: none of these inputs are validated yet */
-static struct dib7000p_config pctv_340e_config = {
-	.output_mpeg2_in_188_bytes = 1,
-
-	.agc_config_count = 1,
-	.agc = &stk7700p_7000p_xc4000_agc_config,
-	.bw  = &stk7700p_xc4000_pll_config,
-
-	.gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
-	.gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
-	.gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
-};
-
-/* PCTV 340e GPIOs map:
-   dib0700:
-   GPIO2  - CX25843 sleep
-   GPIO3  - CS5340 reset
-   GPIO5  - IRD
-   GPIO6  - Power Supply
-   GPIO8  - LNA (1=off 0=on)
-   GPIO10 - CX25843 reset
-   dib7000:
-   GPIO8  - xc4000 reset
- */
-static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_state *st = adap->dev->priv;
-
-	/* Power Supply on */
-	dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 0);
-	msleep(50);
-	dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 1);
-	msleep(100); /* Allow power supply to settle before probing */
-
-	/* cx25843 reset */
-	dib0700_set_gpio(adap->dev, GPIO10,  GPIO_OUT, 0);
-	msleep(1); /* cx25843 datasheet say 350us required */
-	dib0700_set_gpio(adap->dev, GPIO10,  GPIO_OUT, 1);
-
-	/* LNA off for now */
-	dib0700_set_gpio(adap->dev, GPIO8,  GPIO_OUT, 1);
-
-	/* Put the CX25843 to sleep for now since we're in digital mode */
-	dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1);
-
-	/* FIXME: not verified yet */
-	dib0700_ctrl_clock(adap->dev, 72, 1);
-
-	msleep(500);
-
-	if (dib7000pc_detection(&adap->dev->i2c_adap) == 0) {
-		/* Demodulator not found for some reason? */
-		return -ENODEV;
-	}
-
-	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12,
-			      &pctv_340e_config);
-	st->is_dib7000pc = 1;
-
-	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-static struct xc4000_config dib7000p_xc4000_tunerconfig = {
-	.i2c_address	  = 0x61,
-	.default_pm	  = 1,
-	.dvb_amplitude	  = 0,
-	.set_smoothedcvbs = 0,
-	.if_khz		  = 5400
-};
-
-static int xc4000_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct i2c_adapter *tun_i2c;
-
-	/* The xc4000 is not on the main i2c bus */
-	tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe,
-					  DIBX000_I2C_INTERFACE_TUNER, 1);
-	if (tun_i2c == NULL) {
-		printk(KERN_ERR "Could not reach tuner i2c bus\n");
-		return 0;
-	}
-
-	/* Setup the reset callback */
-	adap->fe_adap[0].fe->callback = dib0700_xc4000_tuner_callback;
-
-	return dvb_attach(xc4000_attach, adap->fe_adap[0].fe, tun_i2c,
-			  &dib7000p_xc4000_tunerconfig)
-		== NULL ? -ENODEV : 0;
-}
-
-static struct lgdt3305_config hcw_lgdt3305_config = {
-	.i2c_addr           = 0x0e,
-	.mpeg_mode          = LGDT3305_MPEG_PARALLEL,
-	.tpclk_edge         = LGDT3305_TPCLK_FALLING_EDGE,
-	.tpvalid_polarity   = LGDT3305_TP_VALID_LOW,
-	.deny_i2c_rptr      = 0,
-	.spectral_inversion = 1,
-	.qam_if_khz         = 6000,
-	.vsb_if_khz         = 6000,
-	.usref_8vsb         = 0x0500,
-};
-
-static struct mxl5007t_config hcw_mxl5007t_config = {
-	.xtal_freq_hz = MxL_XTAL_25_MHZ,
-	.if_freq_hz = MxL_IF_6_MHZ,
-	.invert_if = 1,
-};
-
-/* TIGER-ATSC map:
-   GPIO0  - LNA_CTR  (H: LNA power enabled, L: LNA power disabled)
-   GPIO1  - ANT_SEL  (H: VPA, L: MCX)
-   GPIO4  - SCL2
-   GPIO6  - EN_TUNER
-   GPIO7  - SDA2
-   GPIO10 - DEM_RST
-
-   MXL is behind LG's i2c repeater.  LG is on SCL2/SDA2 gpios on the DIB
- */
-static int lgdt3305_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib0700_state *st = adap->dev->priv;
-
-	/* Make use of the new i2c functions from FW 1.20 */
-	st->fw_use_new_i2c_api = 1;
-
-	st->disable_streaming_master_mode = 1;
-
-	/* fe power enable */
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
-	msleep(30);
-	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-	msleep(30);
-
-	/* demod reset */
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-	msleep(30);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-	msleep(30);
-	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-	msleep(30);
-
-	adap->fe_adap[0].fe = dvb_attach(lgdt3305_attach,
-			      &hcw_lgdt3305_config,
-			      &adap->dev->i2c_adap);
-
-	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-static int mxl5007t_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	return dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe,
-			  &adap->dev->i2c_adap, 0x60,
-			  &hcw_mxl5007t_config) == NULL ? -ENODEV : 0;
-}
-
-
-/* DVB-USB and USB stuff follows */
-struct usb_device_id dib0700_usb_id_table[] = {
-/* 0 */	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P) },
-	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P_PC) },
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) },
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) },
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) },
-/* 5 */	{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
-	{ USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500) },
-	{ USB_DEVICE(USB_VID_UNIWILL,   USB_PID_UNIWILL_STK7700P) },
-	{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P) },
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) },
-/* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
-	{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV2000E) },
-	{ USB_DEVICE(USB_VID_TERRATEC,
-			USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) },
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) },
-	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700D) },
-/* 15 */{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7070P) },
-	{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV_DVB_T_FLASH) },
-	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7070PD) },
-	{ USB_DEVICE(USB_VID_PINNACLE,
-			USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) },
-	{ USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500_PC) },
-/* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) },
-	{ USB_DEVICE(USB_VID_GIGABYTE,  USB_PID_GIGABYTE_U7000) },
-	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) },
-	{ USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3000) },
-	{ USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3100) },
-/* 25 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) },
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) },
-	{ USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_CINERGY_HT_USB_XE) },
-	{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_EXPRESSCARD_320CX) },
-	{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV72E) },
-/* 30 */{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV73E) },
-	{ USB_DEVICE(USB_VID_YUAN,	USB_PID_YUAN_EC372S) },
-	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_HT_EXPRESS) },
-	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_T_XXS) },
-	{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) },
-/* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) },
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) },
-	{ USB_DEVICE(USB_VID_GIGABYTE,  USB_PID_GIGABYTE_U8000) },
-	{ USB_DEVICE(USB_VID_YUAN,      USB_PID_YUAN_STK7700PH) },
-	{ USB_DEVICE(USB_VID_ASUS,	USB_PID_ASUS_U3000H) },
-/* 40 */{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV801E) },
-	{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV801E_SE) },
-	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_T_EXPRESS) },
-	{ USB_DEVICE(USB_VID_TERRATEC,
-			USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2) },
-	{ USB_DEVICE(USB_VID_SONY,	USB_PID_SONY_PLAYTV) },
-/* 45 */{ USB_DEVICE(USB_VID_YUAN,      USB_PID_YUAN_PD378S) },
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC) },
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC_B210) },
-	{ USB_DEVICE(USB_VID_YUAN,	USB_PID_YUAN_MC770) },
-	{ USB_DEVICE(USB_VID_ELGATO,	USB_PID_ELGATO_EYETV_DTT) },
-/* 50 */{ USB_DEVICE(USB_VID_ELGATO,	USB_PID_ELGATO_EYETV_DTT_Dlx) },
-	{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_H) },
-	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_T3) },
-	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_T5) },
-	{ USB_DEVICE(USB_VID_YUAN,      USB_PID_YUAN_STK7700D) },
-/* 55 */{ USB_DEVICE(USB_VID_YUAN,	USB_PID_YUAN_STK7700D_2) },
-	{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV73A) },
-	{ USB_DEVICE(USB_VID_PCTV,	USB_PID_PINNACLE_PCTV73ESE) },
-	{ USB_DEVICE(USB_VID_PCTV,	USB_PID_PINNACLE_PCTV282E) },
-	{ USB_DEVICE(USB_VID_DIBCOM,	USB_PID_DIBCOM_STK7770P) },
-/* 60 */{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_T_XXS_2) },
-	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK807XPVR) },
-	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK807XP) },
-	{ USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x000, 0x3f00) },
-	{ USB_DEVICE(USB_VID_EVOLUTEPC, USB_PID_TVWAY_PLUS) },
-/* 65 */{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV73ESE) },
-	{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV282E) },
-	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK8096GP) },
-	{ USB_DEVICE(USB_VID_ELGATO,    USB_PID_ELGATO_EYETV_DIVERSITY) },
-	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_NIM9090M) },
-/* 70 */{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_NIM8096MD) },
-	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_NIM9090MD) },
-	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_NIM7090) },
-	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE7090PVR) },
-	{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2) },
-/* 75 */{ USB_DEVICE(USB_VID_MEDION,    USB_PID_CREATIX_CTX1921) },
-	{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV340E) },
-	{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV340E_SE) },
-	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE7090E) },
-	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE7790E) },
-/* 80 */{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE8096P) },
-	{ USB_DEVICE(USB_VID_ELGATO,	USB_PID_ELGATO_EYETV_DTT_2) },
-	{ 0 }		/* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
-
-#define DIB0700_DEFAULT_DEVICE_PROPERTIES \
-	.caps              = DVB_USB_IS_AN_I2C_ADAPTER, \
-	.usb_ctrl          = DEVICE_SPECIFIC, \
-	.firmware          = "dvb-usb-dib0700-1.20.fw", \
-	.download_firmware = dib0700_download_firmware, \
-	.no_reconnect      = 1, \
-	.size_of_priv      = sizeof(struct dib0700_state), \
-	.i2c_algo          = &dib0700_i2c_algo, \
-	.identify_state    = dib0700_identify_state
-
-#define DIB0700_DEFAULT_STREAMING_CONFIG(ep) \
-	.streaming_ctrl   = dib0700_streaming_ctrl, \
-	.stream = { \
-		.type = USB_BULK, \
-		.count = 4, \
-		.endpoint = ep, \
-		.u = { \
-			.bulk = { \
-				.buffersize = 39480, \
-			} \
-		} \
-	}
-
-struct dvb_usb_device_properties dib0700_devices[] = {
-	{
-		DIB0700_DEFAULT_DEVICE_PROPERTIES,
-
-		.num_adapters = 1,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter       = stk7700p_pid_filter,
-				.pid_filter_ctrl  = stk7700p_pid_filter_ctrl,
-				.frontend_attach  = stk7700p_frontend_attach,
-				.tuner_attach     = stk7700p_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-			},
-		},
-
-		.num_device_descs = 8,
-		.devices = {
-			{   "DiBcom STK7700P reference design",
-				{ &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] },
-				{ NULL },
-			},
-			{   "Hauppauge Nova-T Stick",
-				{ &dib0700_usb_id_table[4], &dib0700_usb_id_table[9], NULL },
-				{ NULL },
-			},
-			{   "AVerMedia AVerTV DVB-T Volar",
-				{ &dib0700_usb_id_table[5], &dib0700_usb_id_table[10] },
-				{ NULL },
-			},
-			{   "Compro Videomate U500",
-				{ &dib0700_usb_id_table[6], &dib0700_usb_id_table[19] },
-				{ NULL },
-			},
-			{   "Uniwill STK7700P based (Hama and others)",
-				{ &dib0700_usb_id_table[7], NULL },
-				{ NULL },
-			},
-			{   "Leadtek Winfast DTV Dongle (STK7700P based)",
-				{ &dib0700_usb_id_table[8], &dib0700_usb_id_table[34] },
-				{ NULL },
-			},
-			{   "AVerMedia AVerTV DVB-T Express",
-				{ &dib0700_usb_id_table[20] },
-				{ NULL },
-			},
-			{   "Gigabyte U7000",
-				{ &dib0700_usb_id_table[21], NULL },
-				{ NULL },
-			}
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-
-		.num_adapters = 2,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.frontend_attach  = bristol_frontend_attach,
-				.tuner_attach     = bristol_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-			}, {
-			.num_frontends = 1,
-			.fe = {{
-				.frontend_attach  = bristol_frontend_attach,
-				.tuner_attach     = bristol_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
-			}},
-			}
-		},
-
-		.num_device_descs = 1,
-		.devices = {
-			{   "Hauppauge Nova-T 500 Dual DVB-T",
-				{ &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-
-		.num_adapters = 2,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter       = stk70x0p_pid_filter,
-				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
-				.frontend_attach  = stk7700d_frontend_attach,
-				.tuner_attach     = stk7700d_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-			}, {
-			.num_frontends = 1,
-			.fe = {{
-				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter       = stk70x0p_pid_filter,
-				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
-				.frontend_attach  = stk7700d_frontend_attach,
-				.tuner_attach     = stk7700d_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
-			}},
-			}
-		},
-
-		.num_device_descs = 5,
-		.devices = {
-			{   "Pinnacle PCTV 2000e",
-				{ &dib0700_usb_id_table[11], NULL },
-				{ NULL },
-			},
-			{   "Terratec Cinergy DT XS Diversity",
-				{ &dib0700_usb_id_table[12], NULL },
-				{ NULL },
-			},
-			{   "Hauppauge Nova-TD Stick/Elgato Eye-TV Diversity",
-				{ &dib0700_usb_id_table[13], NULL },
-				{ NULL },
-			},
-			{   "DiBcom STK7700D reference design",
-				{ &dib0700_usb_id_table[14], NULL },
-				{ NULL },
-			},
-			{   "YUAN High-Tech DiBcom STK7700D",
-				{ &dib0700_usb_id_table[55], NULL },
-				{ NULL },
-			},
-
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-
-		.num_adapters = 1,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter       = stk70x0p_pid_filter,
-				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
-				.frontend_attach  = stk7700P2_frontend_attach,
-				.tuner_attach     = stk7700d_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-			},
-		},
-
-		.num_device_descs = 3,
-		.devices = {
-			{   "ASUS My Cinema U3000 Mini DVBT Tuner",
-				{ &dib0700_usb_id_table[23], NULL },
-				{ NULL },
-			},
-			{   "Yuan EC372S",
-				{ &dib0700_usb_id_table[31], NULL },
-				{ NULL },
-			},
-			{   "Terratec Cinergy T Express",
-				{ &dib0700_usb_id_table[42], NULL },
-				{ NULL },
-			}
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-
-		.num_adapters = 1,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter       = stk70x0p_pid_filter,
-				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
-				.frontend_attach  = stk7070p_frontend_attach,
-				.tuner_attach     = dib7070p_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv     = sizeof(struct dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 12,
-		.devices = {
-			{   "DiBcom STK7070P reference design",
-				{ &dib0700_usb_id_table[15], NULL },
-				{ NULL },
-			},
-			{   "Pinnacle PCTV DVB-T Flash Stick",
-				{ &dib0700_usb_id_table[16], NULL },
-				{ NULL },
-			},
-			{   "Artec T14BR DVB-T",
-				{ &dib0700_usb_id_table[22], NULL },
-				{ NULL },
-			},
-			{   "ASUS My Cinema U3100 Mini DVBT Tuner",
-				{ &dib0700_usb_id_table[24], NULL },
-				{ NULL },
-			},
-			{   "Hauppauge Nova-T Stick",
-				{ &dib0700_usb_id_table[25], NULL },
-				{ NULL },
-			},
-			{   "Hauppauge Nova-T MyTV.t",
-				{ &dib0700_usb_id_table[26], NULL },
-				{ NULL },
-			},
-			{   "Pinnacle PCTV 72e",
-				{ &dib0700_usb_id_table[29], NULL },
-				{ NULL },
-			},
-			{   "Pinnacle PCTV 73e",
-				{ &dib0700_usb_id_table[30], NULL },
-				{ NULL },
-			},
-			{   "Elgato EyeTV DTT",
-				{ &dib0700_usb_id_table[49], NULL },
-				{ NULL },
-			},
-			{   "Yuan PD378S",
-				{ &dib0700_usb_id_table[45], NULL },
-				{ NULL },
-			},
-			{   "Elgato EyeTV Dtt Dlx PD378S",
-				{ &dib0700_usb_id_table[50], NULL },
-				{ NULL },
-			},
-			{   "Elgato EyeTV DTT rev. 2",
-				{ &dib0700_usb_id_table[81], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-
-		.num_adapters = 1,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter       = stk70x0p_pid_filter,
-				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
-				.frontend_attach  = stk7070p_frontend_attach,
-				.tuner_attach     = dib7070p_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv     = sizeof(struct dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 3,
-		.devices = {
-			{   "Pinnacle PCTV 73A",
-				{ &dib0700_usb_id_table[56], NULL },
-				{ NULL },
-			},
-			{   "Pinnacle PCTV 73e SE",
-				{ &dib0700_usb_id_table[57], &dib0700_usb_id_table[65], NULL },
-				{ NULL },
-			},
-			{   "Pinnacle PCTV 282e",
-				{ &dib0700_usb_id_table[58], &dib0700_usb_id_table[66], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-
-		.num_adapters = 2,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter       = stk70x0p_pid_filter,
-				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
-				.frontend_attach  = novatd_frontend_attach,
-				.tuner_attach     = dib7070p_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv     = sizeof(struct dib0700_adapter_state),
-			}, {
-			.num_frontends = 1,
-			.fe = {{
-				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter       = stk70x0p_pid_filter,
-				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
-				.frontend_attach  = novatd_frontend_attach,
-				.tuner_attach     = dib7070p_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
-			}},
-				.size_of_priv     = sizeof(struct dib0700_adapter_state),
-			}
-		},
-
-		.num_device_descs = 1,
-		.devices = {
-			{   "Hauppauge Nova-TD Stick (52009)",
-				{ &dib0700_usb_id_table[35], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-
-		.num_adapters = 2,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter       = stk70x0p_pid_filter,
-				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
-				.frontend_attach  = stk7070pd_frontend_attach0,
-				.tuner_attach     = dib7070p_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv     = sizeof(struct dib0700_adapter_state),
-			}, {
-			.num_frontends = 1,
-			.fe = {{
-				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter       = stk70x0p_pid_filter,
-				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
-				.frontend_attach  = stk7070pd_frontend_attach1,
-				.tuner_attach     = dib7070p_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
-			}},
-				.size_of_priv     = sizeof(struct dib0700_adapter_state),
-			}
-		},
-
-		.num_device_descs = 5,
-		.devices = {
-			{   "DiBcom STK7070PD reference design",
-				{ &dib0700_usb_id_table[17], NULL },
-				{ NULL },
-			},
-			{   "Pinnacle PCTV Dual DVB-T Diversity Stick",
-				{ &dib0700_usb_id_table[18], NULL },
-				{ NULL },
-			},
-			{   "Hauppauge Nova-TD-500 (84xxx)",
-				{ &dib0700_usb_id_table[36], NULL },
-				{ NULL },
-			},
-			{  "Terratec Cinergy DT USB XS Diversity/ T5",
-				{ &dib0700_usb_id_table[43],
-					&dib0700_usb_id_table[53], NULL},
-				{ NULL },
-			},
-			{  "Sony PlayTV",
-				{ &dib0700_usb_id_table[44], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-
-		.num_adapters = 2,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter       = stk70x0p_pid_filter,
-				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
-				.frontend_attach  = stk7070pd_frontend_attach0,
-				.tuner_attach     = dib7070p_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv     = sizeof(struct dib0700_adapter_state),
-			}, {
-			.num_frontends = 1,
-			.fe = {{
-				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter       = stk70x0p_pid_filter,
-				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
-				.frontend_attach  = stk7070pd_frontend_attach1,
-				.tuner_attach     = dib7070p_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
-			}},
-				.size_of_priv     = sizeof(struct dib0700_adapter_state),
-			}
-		},
-
-		.num_device_descs = 1,
-		.devices = {
-			{   "Elgato EyeTV Diversity",
-				{ &dib0700_usb_id_table[68], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_NEC_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-
-		.num_adapters = 1,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter       = stk70x0p_pid_filter,
-				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
-				.frontend_attach  = stk7700ph_frontend_attach,
-				.tuner_attach     = stk7700ph_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv = sizeof(struct
-						dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 9,
-		.devices = {
-			{   "Terratec Cinergy HT USB XE",
-				{ &dib0700_usb_id_table[27], NULL },
-				{ NULL },
-			},
-			{   "Pinnacle Expresscard 320cx",
-				{ &dib0700_usb_id_table[28], NULL },
-				{ NULL },
-			},
-			{   "Terratec Cinergy HT Express",
-				{ &dib0700_usb_id_table[32], NULL },
-				{ NULL },
-			},
-			{   "Gigabyte U8000-RH",
-				{ &dib0700_usb_id_table[37], NULL },
-				{ NULL },
-			},
-			{   "YUAN High-Tech STK7700PH",
-				{ &dib0700_usb_id_table[38], NULL },
-				{ NULL },
-			},
-			{   "Asus My Cinema-U3000Hybrid",
-				{ &dib0700_usb_id_table[39], NULL },
-				{ NULL },
-			},
-			{   "YUAN High-Tech MC770",
-				{ &dib0700_usb_id_table[48], NULL },
-				{ NULL },
-			},
-			{   "Leadtek WinFast DTV Dongle H",
-				{ &dib0700_usb_id_table[51], NULL },
-				{ NULL },
-			},
-			{   "YUAN High-Tech STK7700D",
-				{ &dib0700_usb_id_table[54], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-		.num_adapters = 1,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.frontend_attach  = s5h1411_frontend_attach,
-				.tuner_attach     = xc5000_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv = sizeof(struct
-						dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 2,
-		.devices = {
-			{   "Pinnacle PCTV HD Pro USB Stick",
-				{ &dib0700_usb_id_table[40], NULL },
-				{ NULL },
-			},
-			{   "Pinnacle PCTV HD USB Stick",
-				{ &dib0700_usb_id_table[41], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-		.num_adapters = 1,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.frontend_attach  = lgdt3305_frontend_attach,
-				.tuner_attach     = mxl5007t_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv = sizeof(struct
-						dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 2,
-		.devices = {
-			{   "Hauppauge ATSC MiniCard (B200)",
-				{ &dib0700_usb_id_table[46], NULL },
-				{ NULL },
-			},
-			{   "Hauppauge ATSC MiniCard (B210)",
-				{ &dib0700_usb_id_table[47], NULL },
-				{ NULL },
-			},
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-
-		.num_adapters = 1,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter       = stk70x0p_pid_filter,
-				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
-				.frontend_attach  = stk7770p_frontend_attach,
-				.tuner_attach     = dib7770p_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv =
-					sizeof(struct dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 4,
-		.devices = {
-			{   "DiBcom STK7770P reference design",
-				{ &dib0700_usb_id_table[59], NULL },
-				{ NULL },
-			},
-			{   "Terratec Cinergy T USB XXS (HD)/ T3",
-				{ &dib0700_usb_id_table[33],
-					&dib0700_usb_id_table[52],
-					&dib0700_usb_id_table[60], NULL},
-				{ NULL },
-			},
-			{   "TechniSat AirStar TeleStick 2",
-				{ &dib0700_usb_id_table[74], NULL },
-				{ NULL },
-			},
-			{   "Medion CTX1921 DVB-T USB",
-				{ &dib0700_usb_id_table[75], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-		.num_adapters = 1,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps  = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter = stk80xx_pid_filter,
-				.pid_filter_ctrl = stk80xx_pid_filter_ctrl,
-				.frontend_attach  = stk807x_frontend_attach,
-				.tuner_attach     = dib807x_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv =
-					sizeof(struct dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 3,
-		.devices = {
-			{   "DiBcom STK807xP reference design",
-				{ &dib0700_usb_id_table[62], NULL },
-				{ NULL },
-			},
-			{   "Prolink Pixelview SBTVD",
-				{ &dib0700_usb_id_table[63], NULL },
-				{ NULL },
-			},
-			{   "EvolutePC TVWay+",
-				{ &dib0700_usb_id_table[64], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_NEC_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-		.num_adapters = 2,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps  = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter = stk80xx_pid_filter,
-				.pid_filter_ctrl = stk80xx_pid_filter_ctrl,
-				.frontend_attach  = stk807xpvr_frontend_attach0,
-				.tuner_attach     = dib807x_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv =
-					sizeof(struct dib0700_adapter_state),
-			},
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps  = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter = stk80xx_pid_filter,
-				.pid_filter_ctrl = stk80xx_pid_filter_ctrl,
-				.frontend_attach  = stk807xpvr_frontend_attach1,
-				.tuner_attach     = dib807x_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
-			}},
-				.size_of_priv =
-					sizeof(struct dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 1,
-		.devices = {
-			{   "DiBcom STK807xPVR reference design",
-				{ &dib0700_usb_id_table[61], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-		.num_adapters = 1,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
-					DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter = stk80xx_pid_filter,
-				.pid_filter_ctrl = stk80xx_pid_filter_ctrl,
-				.frontend_attach  = stk809x_frontend_attach,
-				.tuner_attach     = dib809x_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv =
-					sizeof(struct dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 1,
-		.devices = {
-			{   "DiBcom STK8096GP reference design",
-				{ &dib0700_usb_id_table[67], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-		.num_adapters = 1,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
-					DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter = dib90x0_pid_filter,
-				.pid_filter_ctrl = dib90x0_pid_filter_ctrl,
-				.frontend_attach  = stk9090m_frontend_attach,
-				.tuner_attach     = dib9090_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv =
-					sizeof(struct dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 1,
-		.devices = {
-			{   "DiBcom STK9090M reference design",
-				{ &dib0700_usb_id_table[69], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-		.num_adapters = 1,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
-					DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter = stk80xx_pid_filter,
-				.pid_filter_ctrl = stk80xx_pid_filter_ctrl,
-				.frontend_attach  = nim8096md_frontend_attach,
-				.tuner_attach     = nim8096md_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv =
-					sizeof(struct dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 1,
-		.devices = {
-			{   "DiBcom NIM8096MD reference design",
-				{ &dib0700_usb_id_table[70], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-		.num_adapters = 1,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
-					DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter = dib90x0_pid_filter,
-				.pid_filter_ctrl = dib90x0_pid_filter_ctrl,
-				.frontend_attach  = nim9090md_frontend_attach,
-				.tuner_attach     = nim9090md_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv =
-					sizeof(struct dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 1,
-		.devices = {
-			{   "DiBcom NIM9090MD reference design",
-				{ &dib0700_usb_id_table[71], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-		.num_adapters = 1,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
-					DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter = stk70x0p_pid_filter,
-				.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
-				.frontend_attach  = nim7090_frontend_attach,
-				.tuner_attach     = nim7090_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv =
-					sizeof(struct dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 1,
-		.devices = {
-			{   "DiBcom NIM7090 reference design",
-				{ &dib0700_usb_id_table[72], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-		.num_adapters = 2,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
-					DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter = stk70x0p_pid_filter,
-				.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
-				.frontend_attach  = tfe7090pvr_frontend0_attach,
-				.tuner_attach     = tfe7090pvr_tuner0_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
-			}},
-				.size_of_priv =
-					sizeof(struct dib0700_adapter_state),
-			},
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
-					DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-				.pid_filter_count = 32,
-				.pid_filter = stk70x0p_pid_filter,
-				.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
-				.frontend_attach  = tfe7090pvr_frontend1_attach,
-				.tuner_attach     = tfe7090pvr_tuner1_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv =
-					sizeof(struct dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 1,
-		.devices = {
-			{   "DiBcom TFE7090PVR reference design",
-				{ &dib0700_usb_id_table[73], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-		.num_adapters = 1,
-		.adapter = {
-			{
-			.num_frontends = 1,
-			.fe = {{
-				.frontend_attach  = pctv340e_frontend_attach,
-				.tuner_attach     = xc4000_tuner_attach,
-
-				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-			}},
-				.size_of_priv = sizeof(struct
-						dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 2,
-		.devices = {
-			{   "Pinnacle PCTV 340e HD Pro USB Stick",
-				{ &dib0700_usb_id_table[76], NULL },
-				{ NULL },
-			},
-			{   "Pinnacle PCTV Hybrid Stick Solo",
-				{ &dib0700_usb_id_table[77], NULL },
-				{ NULL },
-			},
-		},
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-		.num_adapters = 1,
-		.adapter = {
-			{
-				.num_frontends = 1,
-				.fe = {{
-					.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
-						DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-					.pid_filter_count = 32,
-					.pid_filter = stk70x0p_pid_filter,
-					.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
-					.frontend_attach  = tfe7090e_frontend_attach,
-					.tuner_attach     = tfe7090e_tuner_attach,
-
-					DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-				} },
-
-				.size_of_priv =
-					sizeof(struct dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 1,
-		.devices = {
-			{   "DiBcom TFE7090E reference design",
-				{ &dib0700_usb_id_table[78], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-		.num_adapters = 1,
-		.adapter = {
-			{
-				.num_frontends = 1,
-				.fe = {{
-					.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
-						DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-					.pid_filter_count = 32,
-					.pid_filter = stk70x0p_pid_filter,
-					.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
-					.frontend_attach  = tfe7790e_frontend_attach,
-					.tuner_attach     = tfe7790e_tuner_attach,
-
-					DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
-				} },
-
-				.size_of_priv =
-					sizeof(struct dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 1,
-		.devices = {
-			{   "DiBcom TFE7790E reference design",
-				{ &dib0700_usb_id_table[79], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
-		.num_adapters = 1,
-		.adapter = {
-			{
-				.num_frontends = 1,
-				.fe = {{
-					.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
-						DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-					.pid_filter_count = 32,
-					.pid_filter = stk80xx_pid_filter,
-					.pid_filter_ctrl = stk80xx_pid_filter_ctrl,
-					.frontend_attach  = tfe8096p_frontend_attach,
-					.tuner_attach     = tfe8096p_tuner_attach,
-
-					DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-
-				} },
-
-				.size_of_priv =
-					sizeof(struct dib0700_adapter_state),
-			},
-		},
-
-		.num_device_descs = 1,
-		.devices = {
-			{   "DiBcom TFE8096P reference design",
-				{ &dib0700_usb_id_table[80], NULL },
-				{ NULL },
-			},
-		},
-
-		.rc.core = {
-			.rc_interval      = DEFAULT_RC_INTERVAL,
-			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
-			.module_name	  = "dib0700",
-			.rc_query         = dib0700_rc_query_old_firmware,
-			.allowed_protos   = RC_TYPE_RC5 |
-					    RC_TYPE_RC6 |
-					    RC_TYPE_NEC,
-			.change_protocol  = dib0700_change_protocol,
-		},
-	},
-};
-
-int dib0700_device_count = ARRAY_SIZE(dib0700_devices);
diff --git a/drivers/media/dvb/dvb-usb/dib07x0.h b/drivers/media/dvb/dvb-usb/dib07x0.h
deleted file mode 100644
index 7e62c10..0000000
--- a/drivers/media/dvb/dvb-usb/dib07x0.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef _DIB07X0_H_
-#define _DIB07X0_H_
-
-enum dib07x0_gpios {
-	GPIO0  =  0,
-	GPIO1  =  2,
-	GPIO2  =  3,
-	GPIO3  =  4,
-	GPIO4  =  5,
-	GPIO5  =  6,
-	GPIO6  =  8,
-	GPIO7  = 10,
-	GPIO8  = 11,
-	GPIO9  = 14,
-	GPIO10 = 15,
-};
-
-#define GPIO_IN  0
-#define GPIO_OUT 1
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
deleted file mode 100644
index a76bbb2..0000000
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ /dev/null
@@ -1,479 +0,0 @@
-/* Common methods for dibusb-based-receivers.
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License as published by the Free
- *	Software Foundation, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "dibusb.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS);
-MODULE_LICENSE("GPL");
-
-#define deb_info(args...) dprintk(debug,0x01,args)
-
-/* common stuff used by the different dibusb modules */
-int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	if (adap->priv != NULL) {
-		struct dibusb_state *st = adap->priv;
-		if (st->ops.fifo_ctrl != NULL)
-			if (st->ops.fifo_ctrl(adap->fe_adap[0].fe, onoff)) {
-				err("error while controlling the fifo of the demod.");
-				return -ENODEV;
-			}
-	}
-	return 0;
-}
-EXPORT_SYMBOL(dibusb_streaming_ctrl);
-
-int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
-{
-	if (adap->priv != NULL) {
-		struct dibusb_state *st = adap->priv;
-		if (st->ops.pid_ctrl != NULL)
-			st->ops.pid_ctrl(adap->fe_adap[0].fe,
-					 index, pid, onoff);
-	}
-	return 0;
-}
-EXPORT_SYMBOL(dibusb_pid_filter);
-
-int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	if (adap->priv != NULL) {
-		struct dibusb_state *st = adap->priv;
-		if (st->ops.pid_parse != NULL)
-			if (st->ops.pid_parse(adap->fe_adap[0].fe, onoff) < 0)
-				err("could not handle pid_parser");
-	}
-	return 0;
-}
-EXPORT_SYMBOL(dibusb_pid_filter_ctrl);
-
-int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	u8 b[3];
-	int ret;
-	b[0] = DIBUSB_REQ_SET_IOCTL;
-	b[1] = DIBUSB_IOCTL_CMD_POWER_MODE;
-	b[2] = onoff ? DIBUSB_IOCTL_POWER_WAKEUP : DIBUSB_IOCTL_POWER_SLEEP;
-	ret = dvb_usb_generic_write(d,b,3);
-	msleep(10);
-	return ret;
-}
-EXPORT_SYMBOL(dibusb_power_ctrl);
-
-int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	u8 b[3] = { 0 };
-	int ret;
-
-	if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0)
-		return ret;
-
-	if (onoff) {
-		b[0] = DIBUSB_REQ_SET_STREAMING_MODE;
-		b[1] = 0x00;
-		if ((ret = dvb_usb_generic_write(adap->dev,b,2)) < 0)
-			return ret;
-	}
-
-	b[0] = DIBUSB_REQ_SET_IOCTL;
-	b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM;
-	return dvb_usb_generic_write(adap->dev,b,3);
-}
-EXPORT_SYMBOL(dibusb2_0_streaming_ctrl);
-
-int dibusb2_0_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	if (onoff) {
-		u8 b[3] = { DIBUSB_REQ_SET_IOCTL, DIBUSB_IOCTL_CMD_POWER_MODE, DIBUSB_IOCTL_POWER_WAKEUP };
-		return dvb_usb_generic_write(d,b,3);
-	} else
-		return 0;
-}
-EXPORT_SYMBOL(dibusb2_0_power_ctrl);
-
-static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr,
-			  u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
-{
-	u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */
-	/* write only ? */
-	int wo = (rbuf == NULL || rlen == 0),
-		len = 2 + wlen + (wo ? 0 : 2);
-
-	sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ;
-	sndbuf[1] = (addr << 1) | (wo ? 0 : 1);
-
-	memcpy(&sndbuf[2],wbuf,wlen);
-
-	if (!wo) {
-		sndbuf[wlen+2] = (rlen >> 8) & 0xff;
-		sndbuf[wlen+3] = rlen & 0xff;
-	}
-
-	return dvb_usb_generic_rw(d,sndbuf,len,rbuf,rlen,0);
-}
-
-/*
- * I2C master xfer function
- */
-static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int i;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	for (i = 0; i < num; i++) {
-		/* write/read request */
-		if (i+1 < num && (msg[i].flags & I2C_M_RD) == 0
-					  && (msg[i+1].flags & I2C_M_RD)) {
-			if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,
-						msg[i+1].buf,msg[i+1].len) < 0)
-				break;
-			i++;
-		} else if ((msg[i].flags & I2C_M_RD) == 0) {
-			if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
-				break;
-		} else if (msg[i].addr != 0x50) {
-			/* 0x50 is the address of the eeprom - we need to protect it
-			 * from dibusb's bad i2c implementation: reads without
-			 * writing the offset before are forbidden */
-			if (dibusb_i2c_msg(d, msg[i].addr, NULL, 0, msg[i].buf, msg[i].len) < 0)
-				break;
-		}
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return i;
-}
-
-static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-struct i2c_algorithm dibusb_i2c_algo = {
-	.master_xfer   = dibusb_i2c_xfer,
-	.functionality = dibusb_i2c_func,
-};
-EXPORT_SYMBOL(dibusb_i2c_algo);
-
-int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val)
-{
-	u8 wbuf[1] = { offs };
-	return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1);
-}
-EXPORT_SYMBOL(dibusb_read_eeprom_byte);
-
-/* 3000MC/P stuff */
-// Config Adjacent channels  Perf -cal22
-static struct dibx000_agc_config dib3000p_mt2060_agc_config = {
-	.band_caps = BAND_VHF | BAND_UHF,
-	.setup     = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0),
-
-	.agc1_max = 48497,
-	.agc1_min = 23593,
-	.agc2_max = 46531,
-	.agc2_min = 24904,
-
-	.agc1_pt1 = 0x65,
-	.agc1_pt2 = 0x69,
-
-	.agc1_slope1 = 0x51,
-	.agc1_slope2 = 0x27,
-
-	.agc2_pt1 = 0,
-	.agc2_pt2 = 0x33,
-
-	.agc2_slope1 = 0x35,
-	.agc2_slope2 = 0x37,
-};
-
-static struct dib3000mc_config stk3000p_dib3000p_config = {
-	&dib3000p_mt2060_agc_config,
-
-	.max_time     = 0x196,
-	.ln_adc_level = 0x1cc7,
-
-	.output_mpeg2_in_188_bytes = 1,
-
-	.agc_command1 = 1,
-	.agc_command2 = 1,
-};
-
-static struct dibx000_agc_config dib3000p_panasonic_agc_config = {
-	.band_caps = BAND_VHF | BAND_UHF,
-	.setup     = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0),
-
-	.agc1_max = 56361,
-	.agc1_min = 22282,
-	.agc2_max = 47841,
-	.agc2_min = 36045,
-
-	.agc1_pt1 = 0x3b,
-	.agc1_pt2 = 0x6b,
-
-	.agc1_slope1 = 0x55,
-	.agc1_slope2 = 0x1d,
-
-	.agc2_pt1 = 0,
-	.agc2_pt2 = 0x0a,
-
-	.agc2_slope1 = 0x95,
-	.agc2_slope2 = 0x1e,
-};
-
-#if defined(CONFIG_DVB_DIB3000MC) || 					\
-	(defined(CONFIG_DVB_DIB3000MC_MODULE) && defined(MODULE))
-
-static struct dib3000mc_config mod3000p_dib3000p_config = {
-	&dib3000p_panasonic_agc_config,
-
-	.max_time     = 0x51,
-	.ln_adc_level = 0x1cc7,
-
-	.output_mpeg2_in_188_bytes = 1,
-
-	.agc_command1 = 1,
-	.agc_command2 = 1,
-};
-
-int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	if (adap->dev->udev->descriptor.idVendor  == USB_VID_LITEON &&
-			adap->dev->udev->descriptor.idProduct ==
-			USB_PID_LITEON_DVB_T_WARM) {
-		msleep(1000);
-	}
-
-	adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach,
-					 &adap->dev->i2c_adap,
-					 DEFAULT_DIB3000P_I2C_ADDRESS,
-					 &mod3000p_dib3000p_config);
-	if ((adap->fe_adap[0].fe) == NULL)
-		adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach,
-						 &adap->dev->i2c_adap,
-						 DEFAULT_DIB3000MC_I2C_ADDRESS,
-						 &mod3000p_dib3000p_config);
-	if ((adap->fe_adap[0].fe) != NULL) {
-		if (adap->priv != NULL) {
-			struct dibusb_state *st = adap->priv;
-			st->ops.pid_parse = dib3000mc_pid_parse;
-			st->ops.pid_ctrl  = dib3000mc_pid_control;
-		}
-		return 0;
-	}
-	return -ENODEV;
-}
-EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach);
-
-static struct mt2060_config stk3000p_mt2060_config = {
-	0x60
-};
-
-int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct dibusb_state *st = adap->priv;
-	u8 a,b;
-	u16 if1 = 1220;
-	struct i2c_adapter *tun_i2c;
-
-	// First IF calibration for Liteon Sticks
-	if (adap->dev->udev->descriptor.idVendor  == USB_VID_LITEON &&
-		adap->dev->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) {
-
-		dibusb_read_eeprom_byte(adap->dev,0x7E,&a);
-		dibusb_read_eeprom_byte(adap->dev,0x7F,&b);
-
-		if (a == 0x00)
-			if1 += b;
-		else if (a == 0x80)
-			if1 -= b;
-		else
-			warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b);
-
-	} else if (adap->dev->udev->descriptor.idVendor  == USB_VID_DIBCOM &&
-		   adap->dev->udev->descriptor.idProduct == USB_PID_DIBCOM_MOD3001_WARM) {
-		u8 desc;
-		dibusb_read_eeprom_byte(adap->dev, 7, &desc);
-		if (desc == 2) {
-			a = 127;
-			do {
-				dibusb_read_eeprom_byte(adap->dev, a, &desc);
-				a--;
-			} while (a > 7 && (desc == 0xff || desc == 0x00));
-			if (desc & 0x80)
-				if1 -= (0xff - desc);
-			else
-				if1 += desc;
-		}
-	}
-
-	tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe_adap[0].fe, 1);
-	if (dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) {
-		/* not found - use panasonic pll parameters */
-		if (dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL)
-			return -ENOMEM;
-	} else {
-		st->mt2060_present = 1;
-		/* set the correct parameters for the dib3000p */
-		dib3000mc_set_config(adap->fe_adap[0].fe, &stk3000p_dib3000p_config);
-	}
-	return 0;
-}
-EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
-#endif
-
-/*
- * common remote control stuff
- */
-struct rc_map_table rc_map_dibusb_table[] = {
-	/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
-	{ 0x0016, KEY_POWER },
-	{ 0x0010, KEY_MUTE },
-	{ 0x0003, KEY_1 },
-	{ 0x0001, KEY_2 },
-	{ 0x0006, KEY_3 },
-	{ 0x0009, KEY_4 },
-	{ 0x001d, KEY_5 },
-	{ 0x001f, KEY_6 },
-	{ 0x000d, KEY_7 },
-	{ 0x0019, KEY_8 },
-	{ 0x001b, KEY_9 },
-	{ 0x0015, KEY_0 },
-	{ 0x0005, KEY_CHANNELUP },
-	{ 0x0002, KEY_CHANNELDOWN },
-	{ 0x001e, KEY_VOLUMEUP },
-	{ 0x000a, KEY_VOLUMEDOWN },
-	{ 0x0011, KEY_RECORD },
-	{ 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */
-	{ 0x0014, KEY_PLAY },
-	{ 0x001a, KEY_STOP },
-	{ 0x0040, KEY_REWIND },
-	{ 0x0012, KEY_FASTFORWARD },
-	{ 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */
-	{ 0x004c, KEY_PAUSE },
-	{ 0x004d, KEY_SCREEN }, /* Full screen mode. */
-	{ 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
-	/* additional keys TwinHan VisionPlus, the Artec seemingly not have */
-	{ 0x000c, KEY_CANCEL }, /* Cancel */
-	{ 0x001c, KEY_EPG }, /* EPG */
-	{ 0x0000, KEY_TAB }, /* Tab */
-	{ 0x0048, KEY_INFO }, /* Preview */
-	{ 0x0004, KEY_LIST }, /* RecordList */
-	{ 0x000f, KEY_TEXT }, /* Teletext */
-	/* Key codes for the KWorld/ADSTech/JetWay remote. */
-	{ 0x8612, KEY_POWER },
-	{ 0x860f, KEY_SELECT }, /* source */
-	{ 0x860c, KEY_UNKNOWN }, /* scan */
-	{ 0x860b, KEY_EPG },
-	{ 0x8610, KEY_MUTE },
-	{ 0x8601, KEY_1 },
-	{ 0x8602, KEY_2 },
-	{ 0x8603, KEY_3 },
-	{ 0x8604, KEY_4 },
-	{ 0x8605, KEY_5 },
-	{ 0x8606, KEY_6 },
-	{ 0x8607, KEY_7 },
-	{ 0x8608, KEY_8 },
-	{ 0x8609, KEY_9 },
-	{ 0x860a, KEY_0 },
-	{ 0x8618, KEY_ZOOM },
-	{ 0x861c, KEY_UNKNOWN }, /* preview */
-	{ 0x8613, KEY_UNKNOWN }, /* snap */
-	{ 0x8600, KEY_UNDO },
-	{ 0x861d, KEY_RECORD },
-	{ 0x860d, KEY_STOP },
-	{ 0x860e, KEY_PAUSE },
-	{ 0x8616, KEY_PLAY },
-	{ 0x8611, KEY_BACK },
-	{ 0x8619, KEY_FORWARD },
-	{ 0x8614, KEY_UNKNOWN }, /* pip */
-	{ 0x8615, KEY_ESC },
-	{ 0x861a, KEY_UP },
-	{ 0x861e, KEY_DOWN },
-	{ 0x861f, KEY_LEFT },
-	{ 0x861b, KEY_RIGHT },
-
-	/* Key codes for the DiBcom MOD3000 remote. */
-	{ 0x8000, KEY_MUTE },
-	{ 0x8001, KEY_TEXT },
-	{ 0x8002, KEY_HOME },
-	{ 0x8003, KEY_POWER },
-
-	{ 0x8004, KEY_RED },
-	{ 0x8005, KEY_GREEN },
-	{ 0x8006, KEY_YELLOW },
-	{ 0x8007, KEY_BLUE },
-
-	{ 0x8008, KEY_DVD },
-	{ 0x8009, KEY_AUDIO },
-	{ 0x800a, KEY_IMAGES },      /* Pictures */
-	{ 0x800b, KEY_VIDEO },
-
-	{ 0x800c, KEY_BACK },
-	{ 0x800d, KEY_UP },
-	{ 0x800e, KEY_RADIO },
-	{ 0x800f, KEY_EPG },
-
-	{ 0x8010, KEY_LEFT },
-	{ 0x8011, KEY_OK },
-	{ 0x8012, KEY_RIGHT },
-	{ 0x8013, KEY_UNKNOWN },    /* SAP */
-
-	{ 0x8014, KEY_TV },
-	{ 0x8015, KEY_DOWN },
-	{ 0x8016, KEY_MENU },       /* DVD Menu */
-	{ 0x8017, KEY_LAST },
-
-	{ 0x8018, KEY_RECORD },
-	{ 0x8019, KEY_STOP },
-	{ 0x801a, KEY_PAUSE },
-	{ 0x801b, KEY_PLAY },
-
-	{ 0x801c, KEY_PREVIOUS },
-	{ 0x801d, KEY_REWIND },
-	{ 0x801e, KEY_FASTFORWARD },
-	{ 0x801f, KEY_NEXT},
-
-	{ 0x8040, KEY_1 },
-	{ 0x8041, KEY_2 },
-	{ 0x8042, KEY_3 },
-	{ 0x8043, KEY_CHANNELUP },
-
-	{ 0x8044, KEY_4 },
-	{ 0x8045, KEY_5 },
-	{ 0x8046, KEY_6 },
-	{ 0x8047, KEY_CHANNELDOWN },
-
-	{ 0x8048, KEY_7 },
-	{ 0x8049, KEY_8 },
-	{ 0x804a, KEY_9 },
-	{ 0x804b, KEY_VOLUMEUP },
-
-	{ 0x804c, KEY_CLEAR },
-	{ 0x804d, KEY_0 },
-	{ 0x804e, KEY_ENTER },
-	{ 0x804f, KEY_VOLUMEDOWN },
-};
-EXPORT_SYMBOL(rc_map_dibusb_table);
-
-int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
-{
-	u8 key[5],cmd = DIBUSB_REQ_POLL_REMOTE;
-	dvb_usb_generic_rw(d,&cmd,1,key,5,0);
-	dvb_usb_nec_rc_key_to_event(d,key,event,state);
-	if (key[0] != 0)
-		deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
-	return 0;
-}
-EXPORT_SYMBOL(dibusb_rc_query);
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
deleted file mode 100644
index a4ac37e..0000000
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ /dev/null
@@ -1,471 +0,0 @@
-/* DVB USB compliant linux driver for mobile DVB-T USB devices based on
- * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-B)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * based on GPL code from DiBcom, which has
- * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "dibusb.h"
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static int dib3000mb_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct dibusb_state *st = adap->priv;
-
-	return st->ops.tuner_pass_ctrl(fe, enable, st->tuner_addr);
-}
-
-static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct dib3000_config demod_cfg;
-	struct dibusb_state *st = adap->priv;
-
-	demod_cfg.demod_address = 0x8;
-
-	adap->fe_adap[0].fe = dvb_attach(dib3000mb_attach, &demod_cfg,
-					 &adap->dev->i2c_adap, &st->ops);
-	if ((adap->fe_adap[0].fe) == NULL)
-		return -ENODEV;
-
-	adap->fe_adap[0].fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl;
-
-	return 0;
-}
-
-static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct dibusb_state *st = adap->priv;
-
-	st->tuner_addr = 0x61;
-
-	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap,
-		   DVB_PLL_TUA6010XS);
-	return 0;
-}
-
-static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct dibusb_state *st = adap->priv;
-
-	st->tuner_addr = 0x60;
-
-	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap,
-		   DVB_PLL_TDA665X);
-	return 0;
-}
-
-/* Some of the Artec 1.1 device aren't equipped with the default tuner
- * (Thomson Cable), but with a Panasonic ENV77H11D5.  This function figures
- * this out. */
-static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap)
-{
-	u8 b[2] = { 0,0 }, b2[1];
-	int ret = 0;
-	struct i2c_msg msg[2] = {
-		{ .flags = 0,        .buf = b,  .len = 2 },
-		{ .flags = I2C_M_RD, .buf = b2, .len = 1 },
-	};
-	struct dibusb_state *st = adap->priv;
-
-	/* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */
-	msg[0].addr = msg[1].addr = st->tuner_addr = 0x60;
-
-	if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
-		adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1);
-
-	if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) {
-		err("tuner i2c write failed.");
-		ret = -EREMOTEIO;
-	}
-
-	if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
-		adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0);
-
-	if (b2[0] == 0xfe) {
-		info("This device has the Thomson Cable onboard. Which is default.");
-		ret = dibusb_thomson_tuner_attach(adap);
-	} else {
-		info("This device has the Panasonic ENV77H11D5 onboard.");
-		ret = dibusb_panasonic_tuner_attach(adap);
-	}
-
-	return ret;
-}
-
-/* USB Driver stuff */
-static struct dvb_usb_device_properties dibusb1_1_properties;
-static struct dvb_usb_device_properties dibusb1_1_an2235_properties;
-static struct dvb_usb_device_properties dibusb2_0b_properties;
-static struct dvb_usb_device_properties artec_t1_usb2_properties;
-
-static int dibusb_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	if (0 == dvb_usb_device_init(intf, &dibusb1_1_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &dibusb1_1_an2235_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &dibusb2_0b_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &artec_t1_usb2_properties,
-				     THIS_MODULE, NULL, adapter_nr))
-		return 0;
-
-	return -EINVAL;
-}
-
-/* do not change the order of the ID table */
-static struct usb_device_id dibusb_dib3000mb_table [] = {
-/* 00 */	{ USB_DEVICE(USB_VID_WIDEVIEW,		USB_PID_AVERMEDIA_DVBT_USB_COLD) },
-/* 01 */	{ USB_DEVICE(USB_VID_WIDEVIEW,		USB_PID_AVERMEDIA_DVBT_USB_WARM) },
-/* 02 */	{ USB_DEVICE(USB_VID_COMPRO,		USB_PID_COMPRO_DVBU2000_COLD) },
-/* 03 */	{ USB_DEVICE(USB_VID_COMPRO,		USB_PID_COMPRO_DVBU2000_WARM) },
-/* 04 */	{ USB_DEVICE(USB_VID_COMPRO_UNK,	USB_PID_COMPRO_DVBU2000_UNK_COLD) },
-/* 05 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3000_COLD) },
-/* 06 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3000_WARM) },
-/* 07 */	{ USB_DEVICE(USB_VID_EMPIA,		USB_PID_KWORLD_VSTREAM_COLD) },
-/* 08 */	{ USB_DEVICE(USB_VID_EMPIA,		USB_PID_KWORLD_VSTREAM_WARM) },
-/* 09 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_GRANDTEC_DVBT_USB_COLD) },
-/* 10 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_GRANDTEC_DVBT_USB_WARM) },
-/* 11 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_DIBCOM_MOD3000_COLD) },
-/* 12 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_DIBCOM_MOD3000_WARM) },
-/* 13 */	{ USB_DEVICE(USB_VID_HYPER_PALTEK,	USB_PID_UNK_HYPER_PALTEK_COLD) },
-/* 14 */	{ USB_DEVICE(USB_VID_HYPER_PALTEK,	USB_PID_UNK_HYPER_PALTEK_WARM) },
-/* 15 */	{ USB_DEVICE(USB_VID_VISIONPLUS,	USB_PID_TWINHAN_VP7041_COLD) },
-/* 16 */	{ USB_DEVICE(USB_VID_VISIONPLUS,	USB_PID_TWINHAN_VP7041_WARM) },
-/* 17 */	{ USB_DEVICE(USB_VID_TWINHAN,		USB_PID_TWINHAN_VP7041_COLD) },
-/* 18 */	{ USB_DEVICE(USB_VID_TWINHAN,		USB_PID_TWINHAN_VP7041_WARM) },
-/* 19 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_COLD) },
-/* 20 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_WARM) },
-/* 21 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
-/* 22 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
-/* 23 */	{ USB_DEVICE(USB_VID_ADSTECH,		USB_PID_ADSTECH_USB2_COLD) },
-
-/* device ID with default DIBUSB2_0-firmware and with the hacked firmware */
-/* 24 */	{ USB_DEVICE(USB_VID_ADSTECH,		USB_PID_ADSTECH_USB2_WARM) },
-/* 25 */	{ USB_DEVICE(USB_VID_KYE,		USB_PID_KYE_DVB_T_COLD) },
-/* 26 */	{ USB_DEVICE(USB_VID_KYE,		USB_PID_KYE_DVB_T_WARM) },
-
-/* 27 */	{ USB_DEVICE(USB_VID_KWORLD,		USB_PID_KWORLD_VSTREAM_COLD) },
-
-/* 28 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_USB2_COLD) },
-/* 29 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_USB2_WARM) },
-
-/*
- * XXX: As Artec just 'forgot' to program the EEPROM on some Artec T1 devices
- *      we don't catch these faulty IDs (namely 'Cypress FX1 USB controller') that
- *      have been left on the device. If you don't have such a device but an Artec
- *      device that's supposed to work with this driver but is not detected by it,
- *      free to enable CONFIG_DVB_USB_DIBUSB_MB_FAULTY via your kernel config.
- */
-
-#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
-/* 30 */	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
-#endif
-
-			{ }		/* Terminating entry */
-};
-MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table);
-
-static struct dvb_usb_device_properties dibusb1_1_properties = {
-	.caps =  DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = CYPRESS_AN2135,
-
-	.firmware = "dvb-usb-dibusb-5.0.0.11.fw",
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-			.pid_filter_count = 16,
-
-			.streaming_ctrl   = dibusb_streaming_ctrl,
-			.pid_filter       = dibusb_pid_filter,
-			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
-			.frontend_attach  = dibusb_dib3000mb_frontend_attach,
-			.tuner_attach     = dibusb_tuner_probe_and_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 7,
-				.endpoint = 0x02,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-			.size_of_priv     = sizeof(struct dibusb_state),
-		}
-	},
-
-	.power_ctrl       = dibusb_power_ctrl,
-
-	.rc.legacy = {
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_map_table     = rc_map_dibusb_table,
-		.rc_map_size      = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
-		.rc_query         = dibusb_rc_query,
-	},
-
-	.i2c_algo         = &dibusb_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 9,
-	.devices = {
-		{	"AVerMedia AverTV DVBT USB1.1",
-			{ &dibusb_dib3000mb_table[0],  NULL },
-			{ &dibusb_dib3000mb_table[1],  NULL },
-		},
-		{	"Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)",
-			{ &dibusb_dib3000mb_table[2], &dibusb_dib3000mb_table[4], NULL},
-			{ &dibusb_dib3000mb_table[3], NULL },
-		},
-		{	"DiBcom USB1.1 DVB-T reference design (MOD3000)",
-			{ &dibusb_dib3000mb_table[5],  NULL },
-			{ &dibusb_dib3000mb_table[6],  NULL },
-		},
-		{	"KWorld V-Stream XPERT DTV - DVB-T USB1.1",
-			{ &dibusb_dib3000mb_table[7], NULL },
-			{ &dibusb_dib3000mb_table[8], NULL },
-		},
-		{	"Grandtec USB1.1 DVB-T",
-			{ &dibusb_dib3000mb_table[9],  &dibusb_dib3000mb_table[11], NULL },
-			{ &dibusb_dib3000mb_table[10], &dibusb_dib3000mb_table[12], NULL },
-		},
-		{	"Unknown USB1.1 DVB-T device ???? please report the name to the author",
-			{ &dibusb_dib3000mb_table[13], NULL },
-			{ &dibusb_dib3000mb_table[14], NULL },
-		},
-		{	"TwinhanDTV USB-Ter USB1.1 / Magic Box I / HAMA USB1.1 DVB-T device",
-			{ &dibusb_dib3000mb_table[15], &dibusb_dib3000mb_table[17], NULL},
-			{ &dibusb_dib3000mb_table[16], &dibusb_dib3000mb_table[18], NULL},
-		},
-		{	"Artec T1 USB1.1 TVBOX with AN2135",
-			{ &dibusb_dib3000mb_table[19], NULL },
-			{ &dibusb_dib3000mb_table[20], NULL },
-		},
-		{	"VideoWalker DVB-T USB",
-			{ &dibusb_dib3000mb_table[25], NULL },
-			{ &dibusb_dib3000mb_table[26], NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties dibusb1_1_an2235_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-	.usb_ctrl = CYPRESS_AN2235,
-
-	.firmware = "dvb-usb-dibusb-an2235-01.fw",
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.caps = DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_ADAP_HAS_PID_FILTER,
-			.pid_filter_count = 16,
-
-			.streaming_ctrl   = dibusb_streaming_ctrl,
-			.pid_filter       = dibusb_pid_filter,
-			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
-			.frontend_attach  = dibusb_dib3000mb_frontend_attach,
-			.tuner_attach     = dibusb_tuner_probe_and_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 7,
-				.endpoint = 0x02,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-			.size_of_priv     = sizeof(struct dibusb_state),
-		},
-	},
-	.power_ctrl       = dibusb_power_ctrl,
-
-	.rc.legacy = {
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_map_table     = rc_map_dibusb_table,
-		.rc_map_size      = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
-		.rc_query         = dibusb_rc_query,
-	},
-
-	.i2c_algo         = &dibusb_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
-	.num_device_descs = 2,
-#else
-	.num_device_descs = 1,
-#endif
-	.devices = {
-		{	"Artec T1 USB1.1 TVBOX with AN2235",
-			{ &dibusb_dib3000mb_table[21], NULL },
-			{ &dibusb_dib3000mb_table[22], NULL },
-		},
-#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
-		{	"Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
-			{ &dibusb_dib3000mb_table[30], NULL },
-			{ NULL },
-		},
-		{ NULL },
-#endif
-	}
-};
-
-static struct dvb_usb_device_properties dibusb2_0b_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = CYPRESS_FX2,
-
-	.firmware = "dvb-usb-adstech-usb2-02.fw",
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-			.pid_filter_count = 16,
-
-			.streaming_ctrl   = dibusb2_0_streaming_ctrl,
-			.pid_filter       = dibusb_pid_filter,
-			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
-			.frontend_attach  = dibusb_dib3000mb_frontend_attach,
-			.tuner_attach     = dibusb_thomson_tuner_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 7,
-				.endpoint = 0x06,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-			.size_of_priv     = sizeof(struct dibusb_state),
-		}
-	},
-	.power_ctrl       = dibusb2_0_power_ctrl,
-
-	.rc.legacy = {
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_map_table     = rc_map_dibusb_table,
-		.rc_map_size      = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
-		.rc_query         = dibusb_rc_query,
-	},
-
-	.i2c_algo         = &dibusb_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 2,
-	.devices = {
-		{	"KWorld/ADSTech Instant DVB-T USB2.0",
-			{ &dibusb_dib3000mb_table[23], NULL },
-			{ &dibusb_dib3000mb_table[24], NULL },
-		},
-		{	"KWorld Xpert DVB-T USB2.0",
-			{ &dibusb_dib3000mb_table[27], NULL },
-			{ NULL }
-		},
-		{ NULL },
-	}
-};
-
-static struct dvb_usb_device_properties artec_t1_usb2_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = CYPRESS_FX2,
-
-	.firmware = "dvb-usb-dibusb-6.0.0.8.fw",
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-			.pid_filter_count = 16,
-
-			.streaming_ctrl   = dibusb2_0_streaming_ctrl,
-			.pid_filter       = dibusb_pid_filter,
-			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
-			.frontend_attach  = dibusb_dib3000mb_frontend_attach,
-			.tuner_attach     = dibusb_tuner_probe_and_attach,
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 7,
-				.endpoint = 0x06,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-			.size_of_priv     = sizeof(struct dibusb_state),
-		}
-	},
-	.power_ctrl       = dibusb2_0_power_ctrl,
-
-	.rc.legacy = {
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_map_table     = rc_map_dibusb_table,
-		.rc_map_size      = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
-		.rc_query         = dibusb_rc_query,
-	},
-
-	.i2c_algo         = &dibusb_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 1,
-	.devices = {
-		{	"Artec T1 USB2.0",
-			{ &dibusb_dib3000mb_table[28], NULL },
-			{ &dibusb_dib3000mb_table[29], NULL },
-		},
-		{ NULL },
-	}
-};
-
-static struct usb_driver dibusb_driver = {
-	.name		= "dvb_usb_dibusb_mb",
-	.probe		= dibusb_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table	= dibusb_dib3000mb_table,
-};
-
-module_usb_driver(dibusb_driver);
-
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("Driver for DiBcom USB DVB-T devices (DiB3000M-B based)");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c
deleted file mode 100644
index 9d1a59d0..0000000
--- a/drivers/media/dvb/dvb-usb/dibusb-mc.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/* DVB USB compliant linux driver for mobile DVB-T USB devices based on
- * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-C/P)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * based on GPL code from DiBcom, which has
- * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "dibusb.h"
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-/* USB Driver stuff */
-static struct dvb_usb_device_properties dibusb_mc_properties;
-
-static int dibusb_mc_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	return dvb_usb_device_init(intf, &dibusb_mc_properties, THIS_MODULE,
-				   NULL, adapter_nr);
-}
-
-/* do not change the order of the ID table */
-static struct usb_device_id dibusb_dib3000mc_table [] = {
-/* 00 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3001_COLD) },
-/* 01 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3001_WARM) },
-/* 02 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_USB2_COLD) },
-/* 03 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_USB2_WARM) }, // ( ? )
-/* 04 */	{ USB_DEVICE(USB_VID_LITEON,		USB_PID_LITEON_DVB_T_COLD) },
-/* 05 */	{ USB_DEVICE(USB_VID_LITEON,		USB_PID_LITEON_DVB_T_WARM) },
-/* 06 */	{ USB_DEVICE(USB_VID_EMPIA,		USB_PID_DIGIVOX_MINI_SL_COLD) },
-/* 07 */	{ USB_DEVICE(USB_VID_EMPIA,		USB_PID_DIGIVOX_MINI_SL_WARM) },
-/* 08 */	{ USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_GRANDTEC_DVBT_USB2_COLD) },
-/* 09 */	{ USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_GRANDTEC_DVBT_USB2_WARM) },
-/* 10 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ARTEC_T14_COLD) },
-/* 11 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ARTEC_T14_WARM) },
-/* 12 */	{ USB_DEVICE(USB_VID_LEADTEK,		USB_PID_WINFAST_DTV_DONGLE_COLD) },
-/* 13 */	{ USB_DEVICE(USB_VID_LEADTEK,		USB_PID_WINFAST_DTV_DONGLE_WARM) },
-/* 14 */	{ USB_DEVICE(USB_VID_HUMAX_COEX,	USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD) },
-/* 15 */	{ USB_DEVICE(USB_VID_HUMAX_COEX,	USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM) },
-			{ }		/* Terminating entry */
-};
-MODULE_DEVICE_TABLE (usb, dibusb_dib3000mc_table);
-
-static struct dvb_usb_device_properties dibusb_mc_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware = "dvb-usb-dibusb-6.0.0.8.fw",
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-			.pid_filter_count = 32,
-			.streaming_ctrl   = dibusb2_0_streaming_ctrl,
-			.pid_filter       = dibusb_pid_filter,
-			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
-			.frontend_attach  = dibusb_dib3000mc_frontend_attach,
-			.tuner_attach     = dibusb_dib3000mc_tuner_attach,
-
-	/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 8,
-				.endpoint = 0x06,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-			.size_of_priv     = sizeof(struct dibusb_state),
-		}
-	},
-	.power_ctrl       = dibusb2_0_power_ctrl,
-
-	.rc.legacy = {
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_map_table     = rc_map_dibusb_table,
-		.rc_map_size      = 111, /* FIXME */
-		.rc_query         = dibusb_rc_query,
-	},
-
-	.i2c_algo         = &dibusb_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 8,
-	.devices = {
-		{   "DiBcom USB2.0 DVB-T reference design (MOD3000P)",
-			{ &dibusb_dib3000mc_table[0], NULL },
-			{ &dibusb_dib3000mc_table[1], NULL },
-		},
-		{   "Artec T1 USB2.0 TVBOX (please check the warm ID)",
-			{ &dibusb_dib3000mc_table[2], NULL },
-			{ &dibusb_dib3000mc_table[3], NULL },
-		},
-		{   "LITE-ON USB2.0 DVB-T Tuner",
-		    /* Also rebranded as Intuix S800, Toshiba */
-			{ &dibusb_dib3000mc_table[4], NULL },
-			{ &dibusb_dib3000mc_table[5], NULL },
-		},
-		{   "MSI Digivox Mini SL",
-			{ &dibusb_dib3000mc_table[6], NULL },
-			{ &dibusb_dib3000mc_table[7], NULL },
-		},
-		{   "GRAND - USB2.0 DVB-T adapter",
-			{ &dibusb_dib3000mc_table[8], NULL },
-			{ &dibusb_dib3000mc_table[9], NULL },
-		},
-		{   "Artec T14 - USB2.0 DVB-T",
-			{ &dibusb_dib3000mc_table[10], NULL },
-			{ &dibusb_dib3000mc_table[11], NULL },
-		},
-		{   "Leadtek - USB2.0 Winfast DTV dongle",
-			{ &dibusb_dib3000mc_table[12], NULL },
-			{ &dibusb_dib3000mc_table[13], NULL },
-		},
-		{   "Humax/Coex DVB-T USB Stick 2.0 High Speed",
-			{ &dibusb_dib3000mc_table[14], NULL },
-			{ &dibusb_dib3000mc_table[15], NULL },
-		},
-		{ NULL },
-	}
-};
-
-static struct usb_driver dibusb_mc_driver = {
-	.name		= "dvb_usb_dibusb_mc",
-	.probe		= dibusb_mc_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table	= dibusb_dib3000mc_table,
-};
-
-module_usb_driver(dibusb_mc_driver);
-
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("Driver for DiBcom USB2.0 DVB-T (DiB3000M-C/P based) devices");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h
deleted file mode 100644
index e47c321..0000000
--- a/drivers/media/dvb/dvb-usb/dibusb.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/* Header file for all dibusb-based-receivers.
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License as published by the Free
- *	Software Foundation, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#ifndef _DVB_USB_DIBUSB_H_
-#define _DVB_USB_DIBUSB_H_
-
-#ifndef DVB_USB_LOG_PREFIX
- #define DVB_USB_LOG_PREFIX "dibusb"
-#endif
-#include "dvb-usb.h"
-
-#include "dib3000.h"
-#include "dib3000mc.h"
-#include "mt2060.h"
-
-/*
- * protocol of all dibusb related devices
- */
-
-/*
- * bulk msg to/from endpoint 0x01
- *
- * general structure:
- * request_byte parameter_bytes
- */
-
-#define DIBUSB_REQ_START_READ			0x00
-#define DIBUSB_REQ_START_DEMOD			0x01
-
-/*
- * i2c read
- * bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word
- * bulk read:  byte_buffer (length_word bytes)
- */
-#define DIBUSB_REQ_I2C_READ			0x02
-
-/*
- * i2c write
- * bulk write: 0x03 (7bit i2c_addr << 1) register_bytes value_bytes
- */
-#define DIBUSB_REQ_I2C_WRITE			0x03
-
-/*
- * polling the value of the remote control
- * bulk write: 0x04
- * bulk read:  byte_buffer (5 bytes)
- */
-#define DIBUSB_REQ_POLL_REMOTE       0x04
-
-/* additional status values for Hauppauge Remote Control Protocol */
-#define DIBUSB_RC_HAUPPAUGE_KEY_PRESSED	0x01
-#define DIBUSB_RC_HAUPPAUGE_KEY_EMPTY	0x03
-
-/* streaming mode:
- * bulk write: 0x05 mode_byte
- *
- * mode_byte is mostly 0x00
- */
-#define DIBUSB_REQ_SET_STREAMING_MODE	0x05
-
-/* interrupt the internal read loop, when blocking */
-#define DIBUSB_REQ_INTR_READ			0x06
-
-/* io control
- * 0x07 cmd_byte param_bytes
- *
- * param_bytes can be up to 32 bytes
- *
- * cmd_byte function    parameter name
- * 0x00     power mode
- *                      0x00      sleep
- *                      0x01      wakeup
- *
- * 0x01     enable streaming
- * 0x02     disable streaming
- *
- *
- */
-#define DIBUSB_REQ_SET_IOCTL			0x07
-
-/* IOCTL commands */
-
-/* change the power mode in firmware */
-#define DIBUSB_IOCTL_CMD_POWER_MODE		0x00
-#define DIBUSB_IOCTL_POWER_SLEEP			0x00
-#define DIBUSB_IOCTL_POWER_WAKEUP			0x01
-
-/* modify streaming of the FX2 */
-#define DIBUSB_IOCTL_CMD_ENABLE_STREAM	0x01
-#define DIBUSB_IOCTL_CMD_DISABLE_STREAM	0x02
-
-struct dibusb_state {
-	struct dib_fe_xfer_ops ops;
-	int mt2060_present;
-	u8 tuner_addr;
-};
-
-struct dibusb_device_state {
-	/* for RC5 remote control */
-	int old_toggle;
-	int last_repeat_count;
-};
-
-extern struct i2c_algorithm dibusb_i2c_algo;
-
-extern int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *);
-extern int dibusb_dib3000mc_tuner_attach (struct dvb_usb_adapter *);
-
-extern int dibusb_streaming_ctrl(struct dvb_usb_adapter *, int);
-extern int dibusb_pid_filter(struct dvb_usb_adapter *, int, u16, int);
-extern int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *, int);
-extern int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *, int);
-
-extern int dibusb_power_ctrl(struct dvb_usb_device *, int);
-extern int dibusb2_0_power_ctrl(struct dvb_usb_device *, int);
-
-#define DEFAULT_RC_INTERVAL 150
-//#define DEFAULT_RC_INTERVAL 100000
-
-extern struct rc_map_table rc_map_dibusb_table[];
-extern int dibusb_rc_query(struct dvb_usb_device *, u32 *, int *);
-extern int dibusb_read_eeprom_byte(struct dvb_usb_device *, u8, u8 *);
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
deleted file mode 100644
index ff34419..0000000
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0
- * receiver
- *
- * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * partly based on the SDK published by Nebula Electronics
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "digitv.h"
-
-#include "mt352.h"
-#include "nxt6000.h"
-
-/* debug */
-static int dvb_usb_digitv_debug;
-module_param_named(debug,dvb_usb_digitv_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define deb_rc(args...)   dprintk(dvb_usb_digitv_debug,0x01,args)
-
-static int digitv_ctrl_msg(struct dvb_usb_device *d,
-		u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
-{
-	int wo = (rbuf == NULL || rlen == 0); /* write-only */
-	u8 sndbuf[7],rcvbuf[7];
-	memset(sndbuf,0,7); memset(rcvbuf,0,7);
-
-	sndbuf[0] = cmd;
-	sndbuf[1] = vv;
-	sndbuf[2] = wo ? wlen : rlen;
-
-	if (wo) {
-		memcpy(&sndbuf[3],wbuf,wlen);
-		dvb_usb_generic_write(d,sndbuf,7);
-	} else {
-		dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7,10);
-		memcpy(rbuf,&rcvbuf[3],rlen);
-	}
-	return 0;
-}
-
-/* I2C */
-static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int i;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	if (num > 2)
-		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
-
-	for (i = 0; i < num; i++) {
-		/* write/read request */
-		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
-			if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0,
-						msg[i+1].buf,msg[i+1].len) < 0)
-				break;
-			i++;
-		} else
-			if (digitv_ctrl_msg(d,USB_WRITE_COFDM, msg[i].buf[0],
-						&msg[i].buf[1],msg[i].len-1,NULL,0) < 0)
-				break;
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return i;
-}
-
-static u32 digitv_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm digitv_i2c_algo = {
-	.master_xfer   = digitv_i2c_xfer,
-	.functionality = digitv_i2c_func,
-};
-
-/* Callbacks for DVB USB */
-static int digitv_identify_state (struct usb_device *udev, struct
-		dvb_usb_device_properties *props, struct dvb_usb_device_description **desc,
-		int *cold)
-{
-	*cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
-	return 0;
-}
-
-static int digitv_mt352_demod_init(struct dvb_frontend *fe)
-{
-	static u8 reset_buf[] = { 0x89, 0x38,  0x8a, 0x2d, 0x50, 0x80 };
-	static u8 init_buf[] = { 0x68, 0xa0,  0x8e, 0x40,  0x53, 0x50,
-			0x67, 0x20,  0x7d, 0x01,  0x7c, 0x00,  0x7a, 0x00,
-			0x79, 0x20,  0x57, 0x05,  0x56, 0x31,  0x88, 0x0f,
-			0x75, 0x32 };
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(reset_buf); i += 2)
-		mt352_write(fe, &reset_buf[i], 2);
-
-	msleep(1);
-
-	for (i = 0; i < ARRAY_SIZE(init_buf); i += 2)
-		mt352_write(fe, &init_buf[i], 2);
-
-	return 0;
-}
-
-static struct mt352_config digitv_mt352_config = {
-	.demod_init = digitv_mt352_demod_init,
-};
-
-static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	u8 b[5];
-
-	fe->ops.tuner_ops.calc_regs(fe, b, sizeof(b));
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0);
-}
-
-static struct nxt6000_config digitv_nxt6000_config = {
-	.clock_inversion = 1,
-};
-
-static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct digitv_state *st = adap->dev->priv;
-
-	adap->fe_adap[0].fe = dvb_attach(mt352_attach, &digitv_mt352_config,
-					 &adap->dev->i2c_adap);
-	if ((adap->fe_adap[0].fe) != NULL) {
-		st->is_nxt6000 = 0;
-		return 0;
-	}
-	adap->fe_adap[0].fe = dvb_attach(nxt6000_attach,
-					 &digitv_nxt6000_config,
-					 &adap->dev->i2c_adap);
-	if ((adap->fe_adap[0].fe) != NULL) {
-		st->is_nxt6000 = 1;
-		return 0;
-	}
-	return -EIO;
-}
-
-static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	struct digitv_state *st = adap->dev->priv;
-
-	if (!dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, NULL, DVB_PLL_TDED4))
-		return -ENODEV;
-
-	if (st->is_nxt6000)
-		adap->fe_adap[0].fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
-
-	return 0;
-}
-
-static struct rc_map_table rc_map_digitv_table[] = {
-	{ 0x5f55, KEY_0 },
-	{ 0x6f55, KEY_1 },
-	{ 0x9f55, KEY_2 },
-	{ 0xaf55, KEY_3 },
-	{ 0x5f56, KEY_4 },
-	{ 0x6f56, KEY_5 },
-	{ 0x9f56, KEY_6 },
-	{ 0xaf56, KEY_7 },
-	{ 0x5f59, KEY_8 },
-	{ 0x6f59, KEY_9 },
-	{ 0x9f59, KEY_TV },
-	{ 0xaf59, KEY_AUX },
-	{ 0x5f5a, KEY_DVD },
-	{ 0x6f5a, KEY_POWER },
-	{ 0x9f5a, KEY_CAMERA },     /* labelled 'Picture' */
-	{ 0xaf5a, KEY_AUDIO },
-	{ 0x5f65, KEY_INFO },
-	{ 0x6f65, KEY_F13 },     /* 16:9 */
-	{ 0x9f65, KEY_F14 },     /* 14:9 */
-	{ 0xaf65, KEY_EPG },
-	{ 0x5f66, KEY_EXIT },
-	{ 0x6f66, KEY_MENU },
-	{ 0x9f66, KEY_UP },
-	{ 0xaf66, KEY_DOWN },
-	{ 0x5f69, KEY_LEFT },
-	{ 0x6f69, KEY_RIGHT },
-	{ 0x9f69, KEY_ENTER },
-	{ 0xaf69, KEY_CHANNELUP },
-	{ 0x5f6a, KEY_CHANNELDOWN },
-	{ 0x6f6a, KEY_VOLUMEUP },
-	{ 0x9f6a, KEY_VOLUMEDOWN },
-	{ 0xaf6a, KEY_RED },
-	{ 0x5f95, KEY_GREEN },
-	{ 0x6f95, KEY_YELLOW },
-	{ 0x9f95, KEY_BLUE },
-	{ 0xaf95, KEY_SUBTITLE },
-	{ 0x5f96, KEY_F15 },     /* AD */
-	{ 0x6f96, KEY_TEXT },
-	{ 0x9f96, KEY_MUTE },
-	{ 0xaf96, KEY_REWIND },
-	{ 0x5f99, KEY_STOP },
-	{ 0x6f99, KEY_PLAY },
-	{ 0x9f99, KEY_FASTFORWARD },
-	{ 0xaf99, KEY_F16 },     /* chapter */
-	{ 0x5f9a, KEY_PAUSE },
-	{ 0x6f9a, KEY_PLAY },
-	{ 0x9f9a, KEY_RECORD },
-	{ 0xaf9a, KEY_F17 },     /* picture in picture */
-	{ 0x5fa5, KEY_KPPLUS },  /* zoom in */
-	{ 0x6fa5, KEY_KPMINUS }, /* zoom out */
-	{ 0x9fa5, KEY_F18 },     /* capture */
-	{ 0xafa5, KEY_F19 },     /* web */
-	{ 0x5fa6, KEY_EMAIL },
-	{ 0x6fa6, KEY_PHONE },
-	{ 0x9fa6, KEY_PC },
-};
-
-static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
-{
-	int i;
-	u8 key[5];
-	u8 b[4] = { 0 };
-
-	*event = 0;
-	*state = REMOTE_NO_KEY_PRESSED;
-
-	digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4);
-
-	/* Tell the device we've read the remote. Not sure how necessary
-	   this is, but the Nebula SDK does it. */
-	digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0);
-
-	/* if something is inside the buffer, simulate key press */
-	if (key[1] != 0)
-	{
-		  for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
-			if (rc5_custom(&d->props.rc.legacy.rc_map_table[i]) == key[1] &&
-			    rc5_data(&d->props.rc.legacy.rc_map_table[i]) == key[2]) {
-				*event = d->props.rc.legacy.rc_map_table[i].keycode;
-				*state = REMOTE_KEY_PRESSED;
-				return 0;
-			}
-		}
-	}
-
-	if (key[0] != 0)
-		deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
-	return 0;
-}
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties digitv_properties;
-
-static int digitv_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	struct dvb_usb_device *d;
-	int ret = dvb_usb_device_init(intf, &digitv_properties, THIS_MODULE, &d,
-				      adapter_nr);
-	if (ret == 0) {
-		u8 b[4] = { 0 };
-
-		if (d != NULL) { /* do that only when the firmware is loaded */
-			b[0] = 1;
-			digitv_ctrl_msg(d,USB_WRITE_REMOTE_TYPE,0,b,4,NULL,0);
-
-			b[0] = 0;
-			digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0);
-		}
-	}
-	return ret;
-}
-
-static struct usb_device_id digitv_table [] = {
-		{ USB_DEVICE(USB_VID_ANCHOR, USB_PID_NEBULA_DIGITV) },
-		{ }		/* Terminating entry */
-};
-MODULE_DEVICE_TABLE (usb, digitv_table);
-
-static struct dvb_usb_device_properties digitv_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware = "dvb-usb-digitv-02.fw",
-
-	.size_of_priv = sizeof(struct digitv_state),
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.frontend_attach  = digitv_frontend_attach,
-			.tuner_attach     = digitv_tuner_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 7,
-				.endpoint = 0x02,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-		}
-	},
-	.identify_state   = digitv_identify_state,
-
-	.rc.legacy = {
-		.rc_interval      = 1000,
-		.rc_map_table     = rc_map_digitv_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_digitv_table),
-		.rc_query         = digitv_rc_query,
-	},
-
-	.i2c_algo         = &digitv_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 1,
-	.devices = {
-		{   "Nebula Electronics uDigiTV DVB-T USB2.0)",
-			{ &digitv_table[0], NULL },
-			{ NULL },
-		},
-		{ NULL },
-	}
-};
-
-static struct usb_driver digitv_driver = {
-	.name		= "dvb_usb_digitv",
-	.probe		= digitv_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table	= digitv_table,
-};
-
-module_usb_driver(digitv_driver);
-
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("Driver for Nebula Electronics uDigiTV DVB-T USB2.0");
-MODULE_VERSION("1.0-alpha");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/digitv.h b/drivers/media/dvb/dvb-usb/digitv.h
deleted file mode 100644
index 908c09f..0000000
--- a/drivers/media/dvb/dvb-usb/digitv.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef _DVB_USB_DIGITV_H_
-#define _DVB_USB_DIGITV_H_
-
-#define DVB_USB_LOG_PREFIX "digitv"
-#include "dvb-usb.h"
-
-struct digitv_state {
-    int is_nxt6000;
-};
-
-/* protocol (from usblogging and the SDK:
- *
- * Always 7 bytes bulk message(s) for controlling
- *
- * First byte describes the command. Reads are 2 consecutive transfer (as always).
- *
- * General structure:
- *
- * write or first message of a read:
- * <cmdbyte> VV <len> B0 B1 B2 B3
- *
- * second message of a read
- * <cmdbyte> VV <len> R0 R1 R2 R3
- *
- * whereas 0 < len <= 4
- *
- * I2C address is stored somewhere inside the device.
- *
- * 0x01 read from EEPROM
- *  VV = offset; B* = 0; R* = value(s)
- *
- * 0x02 read register of the COFDM
- *  VV = register; B* = 0; R* = value(s)
- *
- * 0x05 write register of the COFDM
- *  VV = register; B* = value(s);
- *
- * 0x06 write to the tuner (only for NXT6000)
- *  VV = 0; B* = PLL data; len = 4;
- *
- * 0x03 read remote control
- *  VV = 0; B* = 0; len = 4; R* = key
- *
- * 0x07 write to the remote (don't know why one should this, resetting ?)
- *  VV = 0; B* = key; len = 4;
- *
- * 0x08 write remote type
- *  VV = 0; B[0] = 0x01, len = 4
- *
- * 0x09 write device init
- *  TODO
- */
-#define USB_READ_EEPROM         1
-
-#define USB_READ_COFDM          2
-#define USB_WRITE_COFDM         5
-
-#define USB_WRITE_TUNER         6
-
-#define USB_READ_REMOTE         3
-#define USB_WRITE_REMOTE        7
-#define USB_WRITE_REMOTE_TYPE   8
-
-#define USB_DEV_INIT            9
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c
deleted file mode 100644
index 3d81daa..0000000
--- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/* Frontend part of the Linux driver for the WideView/ Yakumo/ Hama/
- * Typhoon/ Yuan DVB-T USB2.0 receiver.
- *
- * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
- *
- *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License as published by the Free
- *	Software Foundation, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "dtt200u.h"
-
-struct dtt200u_fe_state {
-	struct dvb_usb_device *d;
-
-	fe_status_t stat;
-
-	struct dtv_frontend_properties fep;
-	struct dvb_frontend frontend;
-};
-
-static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
-{
-	struct dtt200u_fe_state *state = fe->demodulator_priv;
-	u8 st = GET_TUNE_STATUS, b[3];
-
-	dvb_usb_generic_rw(state->d,&st,1,b,3,0);
-
-	switch (b[0]) {
-		case 0x01:
-			*stat = FE_HAS_SIGNAL | FE_HAS_CARRIER |
-				FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
-			break;
-		case 0x00: /* pending */
-			*stat = FE_TIMEDOUT; /* during set_frontend */
-			break;
-		default:
-		case 0x02: /* failed */
-			*stat = 0;
-			break;
-	}
-	return 0;
-}
-
-static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
-{
-	struct dtt200u_fe_state *state = fe->demodulator_priv;
-	u8 bw = GET_VIT_ERR_CNT,b[3];
-	dvb_usb_generic_rw(state->d,&bw,1,b,3,0);
-	*ber = (b[0] << 16) | (b[1] << 8) | b[2];
-	return 0;
-}
-
-static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
-{
-	struct dtt200u_fe_state *state = fe->demodulator_priv;
-	u8 bw = GET_RS_UNCOR_BLK_CNT,b[2];
-
-	dvb_usb_generic_rw(state->d,&bw,1,b,2,0);
-	*unc = (b[0] << 8) | b[1];
-	return 0;
-}
-
-static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
-{
-	struct dtt200u_fe_state *state = fe->demodulator_priv;
-	u8 bw = GET_AGC, b;
-	dvb_usb_generic_rw(state->d,&bw,1,&b,1,0);
-	*strength = (b << 8) | b;
-	return 0;
-}
-
-static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
-{
-	struct dtt200u_fe_state *state = fe->demodulator_priv;
-	u8 bw = GET_SNR,br;
-	dvb_usb_generic_rw(state->d,&bw,1,&br,1,0);
-	*snr = ~((br << 8) | br);
-	return 0;
-}
-
-static int dtt200u_fe_init(struct dvb_frontend* fe)
-{
-	struct dtt200u_fe_state *state = fe->demodulator_priv;
-	u8 b = SET_INIT;
-	return dvb_usb_generic_write(state->d,&b,1);
-}
-
-static int dtt200u_fe_sleep(struct dvb_frontend* fe)
-{
-	return dtt200u_fe_init(fe);
-}
-
-static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
-{
-	tune->min_delay_ms = 1500;
-	tune->step_size = 0;
-	tune->max_drift = 0;
-	return 0;
-}
-
-static int dtt200u_fe_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
-	struct dtt200u_fe_state *state = fe->demodulator_priv;
-	int i;
-	fe_status_t st;
-	u16 freq = fep->frequency / 250000;
-	u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 };
-
-	switch (fep->bandwidth_hz) {
-	case 8000000:
-		bwbuf[1] = 8;
-		break;
-	case 7000000:
-		bwbuf[1] = 7;
-		break;
-	case 6000000:
-		bwbuf[1] = 6;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	dvb_usb_generic_write(state->d,bwbuf,2);
-
-	freqbuf[1] = freq & 0xff;
-	freqbuf[2] = (freq >> 8) & 0xff;
-	dvb_usb_generic_write(state->d,freqbuf,3);
-
-	for (i = 0; i < 30; i++) {
-		msleep(20);
-		dtt200u_fe_read_status(fe, &st);
-		if (st & FE_TIMEDOUT)
-			continue;
-	}
-
-	return 0;
-}
-
-static int dtt200u_fe_get_frontend(struct dvb_frontend* fe)
-{
-	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
-	struct dtt200u_fe_state *state = fe->demodulator_priv;
-	memcpy(fep, &state->fep, sizeof(struct dtv_frontend_properties));
-	return 0;
-}
-
-static void dtt200u_fe_release(struct dvb_frontend* fe)
-{
-	struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops dtt200u_fe_ops;
-
-struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d)
-{
-	struct dtt200u_fe_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct dtt200u_fe_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	deb_info("attaching frontend dtt200u\n");
-
-	state->d = d;
-
-	memcpy(&state->frontend.ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-
-	return &state->frontend;
-error:
-	return NULL;
-}
-
-static struct dvb_frontend_ops dtt200u_fe_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name			= "WideView USB DVB-T",
-		.frequency_min		= 44250000,
-		.frequency_max		= 867250000,
-		.frequency_stepsize	= 250000,
-		.caps = FE_CAN_INVERSION_AUTO |
-				FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-				FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-				FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-				FE_CAN_TRANSMISSION_MODE_AUTO |
-				FE_CAN_GUARD_INTERVAL_AUTO |
-				FE_CAN_RECOVER |
-				FE_CAN_HIERARCHY_AUTO,
-	},
-
-	.release = dtt200u_fe_release,
-
-	.init = dtt200u_fe_init,
-	.sleep = dtt200u_fe_sleep,
-
-	.set_frontend = dtt200u_fe_set_frontend,
-	.get_frontend = dtt200u_fe_get_frontend,
-	.get_tune_settings = dtt200u_fe_get_tune_settings,
-
-	.read_status = dtt200u_fe_read_status,
-	.read_ber = dtt200u_fe_read_ber,
-	.read_signal_strength = dtt200u_fe_read_signal_strength,
-	.read_snr = dtt200u_fe_read_snr,
-	.read_ucblocks = dtt200u_fe_read_unc_blocks,
-};
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
deleted file mode 100644
index 66f205c..0000000
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/
- * Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver.
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * Thanks to Steve Chang from WideView for providing support for the WT-220U.
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "dtt200u.h"
-
-/* debug */
-int dvb_usb_dtt200u_debug;
-module_param_named(debug,dvb_usb_dtt200u_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB_DEBUG_STATUS);
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	u8 b = SET_INIT;
-
-	if (onoff)
-		dvb_usb_generic_write(d,&b,2);
-
-	return 0;
-}
-
-static int dtt200u_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	u8 b_streaming[2] = { SET_STREAMING, onoff };
-	u8 b_rst_pid = RESET_PID_FILTER;
-
-	dvb_usb_generic_write(adap->dev, b_streaming, 2);
-
-	if (onoff == 0)
-		dvb_usb_generic_write(adap->dev, &b_rst_pid, 1);
-	return 0;
-}
-
-static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
-{
-	u8 b_pid[4];
-	pid = onoff ? pid : 0;
-
-	b_pid[0] = SET_PID_FILTER;
-	b_pid[1] = index;
-	b_pid[2] = pid & 0xff;
-	b_pid[3] = (pid >> 8) & 0x1f;
-
-	return dvb_usb_generic_write(adap->dev, b_pid, 4);
-}
-
-/* remote control */
-/* key list for the tiny remote control (Yakumo, don't know about the others) */
-static struct rc_map_table rc_map_dtt200u_table[] = {
-	{ 0x8001, KEY_MUTE },
-	{ 0x8002, KEY_CHANNELDOWN },
-	{ 0x8003, KEY_VOLUMEDOWN },
-	{ 0x8004, KEY_1 },
-	{ 0x8005, KEY_2 },
-	{ 0x8006, KEY_3 },
-	{ 0x8007, KEY_4 },
-	{ 0x8008, KEY_5 },
-	{ 0x8009, KEY_6 },
-	{ 0x800a, KEY_7 },
-	{ 0x800c, KEY_ZOOM },
-	{ 0x800d, KEY_0 },
-	{ 0x800e, KEY_SELECT },
-	{ 0x8012, KEY_POWER },
-	{ 0x801a, KEY_CHANNELUP },
-	{ 0x801b, KEY_8 },
-	{ 0x801e, KEY_VOLUMEUP },
-	{ 0x801f, KEY_9 },
-};
-
-static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
-{
-	u8 key[5],cmd = GET_RC_CODE;
-	dvb_usb_generic_rw(d,&cmd,1,key,5,0);
-	dvb_usb_nec_rc_key_to_event(d,key,event,state);
-	if (key[0] != 0)
-		deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
-	return 0;
-}
-
-static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	adap->fe_adap[0].fe = dtt200u_fe_attach(adap->dev);
-	return 0;
-}
-
-static struct dvb_usb_device_properties dtt200u_properties;
-static struct dvb_usb_device_properties wt220u_fc_properties;
-static struct dvb_usb_device_properties wt220u_properties;
-static struct dvb_usb_device_properties wt220u_zl0353_properties;
-static struct dvb_usb_device_properties wt220u_miglia_properties;
-
-static int dtt200u_usb_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	if (0 == dvb_usb_device_init(intf, &dtt200u_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &wt220u_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &wt220u_fc_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &wt220u_zl0353_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &wt220u_miglia_properties,
-				     THIS_MODULE, NULL, adapter_nr))
-		return 0;
-
-	return -ENODEV;
-}
-
-static struct usb_device_id dtt200u_usb_table [] = {
-	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) },
-	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) },
-	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD)  },
-	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM)  },
-	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD)  },
-	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM)  },
-	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD)  },
-	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM)  },
-	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD)  },
-	{ USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD)  },
-	{ 0 },
-};
-MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
-
-static struct dvb_usb_device_properties dtt200u_properties = {
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware = "dvb-usb-dtt200u-01.fw",
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
-			.pid_filter_count = 15,
-
-	.streaming_ctrl  = dtt200u_streaming_ctrl,
-	.pid_filter      = dtt200u_pid_filter,
-	.frontend_attach = dtt200u_frontend_attach,
-	/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-		.count = 7,
-		.endpoint = 0x02,
-		.u = {
-			.bulk = {
-				.buffersize = 4096,
-			}
-		}
-	},
-		}},
-		}
-	},
-	.power_ctrl      = dtt200u_power_ctrl,
-
-	.rc.legacy = {
-		.rc_interval     = 300,
-		.rc_map_table    = rc_map_dtt200u_table,
-		.rc_map_size     = ARRAY_SIZE(rc_map_dtt200u_table),
-		.rc_query        = dtt200u_rc_query,
-	},
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 1,
-	.devices = {
-		{ .name = "WideView/Yuan/Yakumo/Hama/Typhoon DVB-T USB2.0 (WT-200U)",
-		  .cold_ids = { &dtt200u_usb_table[0], NULL },
-		  .warm_ids = { &dtt200u_usb_table[1], NULL },
-		},
-		{ NULL },
-	}
-};
-
-static struct dvb_usb_device_properties wt220u_properties = {
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware = "dvb-usb-wt220u-02.fw",
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
-			.pid_filter_count = 15,
-
-	.streaming_ctrl  = dtt200u_streaming_ctrl,
-	.pid_filter      = dtt200u_pid_filter,
-	.frontend_attach = dtt200u_frontend_attach,
-	/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-		.count = 7,
-		.endpoint = 0x02,
-		.u = {
-			.bulk = {
-				.buffersize = 4096,
-			}
-		}
-	},
-		}},
-		}
-	},
-	.power_ctrl      = dtt200u_power_ctrl,
-
-	.rc.legacy = {
-		.rc_interval     = 300,
-		.rc_map_table      = rc_map_dtt200u_table,
-		.rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table),
-		.rc_query        = dtt200u_rc_query,
-	},
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 1,
-	.devices = {
-		{ .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
-		  .cold_ids = { &dtt200u_usb_table[2], &dtt200u_usb_table[8], NULL },
-		  .warm_ids = { &dtt200u_usb_table[3], NULL },
-		},
-		{ NULL },
-	}
-};
-
-static struct dvb_usb_device_properties wt220u_fc_properties = {
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware = "dvb-usb-wt220u-fc03.fw",
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
-			.pid_filter_count = 15,
-
-	.streaming_ctrl  = dtt200u_streaming_ctrl,
-	.pid_filter      = dtt200u_pid_filter,
-	.frontend_attach = dtt200u_frontend_attach,
-	/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-		.count = 7,
-				.endpoint = 0x06,
-		.u = {
-			.bulk = {
-				.buffersize = 4096,
-			}
-		}
-	},
-		}},
-		}
-	},
-	.power_ctrl      = dtt200u_power_ctrl,
-
-	.rc.legacy = {
-		.rc_interval     = 300,
-		.rc_map_table    = rc_map_dtt200u_table,
-		.rc_map_size     = ARRAY_SIZE(rc_map_dtt200u_table),
-		.rc_query        = dtt200u_rc_query,
-	},
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 1,
-	.devices = {
-		{ .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
-		  .cold_ids = { &dtt200u_usb_table[6], NULL },
-		  .warm_ids = { &dtt200u_usb_table[7], NULL },
-		},
-		{ NULL },
-	}
-};
-
-static struct dvb_usb_device_properties wt220u_zl0353_properties = {
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware = "dvb-usb-wt220u-zl0353-01.fw",
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
-			.pid_filter_count = 15,
-
-			.streaming_ctrl  = dtt200u_streaming_ctrl,
-			.pid_filter      = dtt200u_pid_filter,
-			.frontend_attach = dtt200u_frontend_attach,
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 7,
-				.endpoint = 0x02,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-		}
-	},
-	.power_ctrl      = dtt200u_power_ctrl,
-
-	.rc.legacy = {
-		.rc_interval     = 300,
-		.rc_map_table    = rc_map_dtt200u_table,
-		.rc_map_size     = ARRAY_SIZE(rc_map_dtt200u_table),
-		.rc_query        = dtt200u_rc_query,
-	},
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 1,
-	.devices = {
-		{ .name = "WideView WT-220U PenType Receiver (based on ZL353)",
-		  .cold_ids = { &dtt200u_usb_table[4], NULL },
-		  .warm_ids = { &dtt200u_usb_table[5], NULL },
-		},
-		{ NULL },
-	}
-};
-
-static struct dvb_usb_device_properties wt220u_miglia_properties = {
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware = "dvb-usb-wt220u-miglia-01.fw",
-
-	.num_adapters = 1,
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 1,
-	.devices = {
-		{ .name = "WideView WT-220U PenType Receiver (Miglia)",
-		  .cold_ids = { &dtt200u_usb_table[9], NULL },
-		  /* This device turns into WT220U_ZL0353_WARM when fw
-		     has been uploaded */
-		  .warm_ids = { NULL },
-		},
-		{ NULL },
-	}
-};
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver dtt200u_usb_driver = {
-	.name		= "dvb_usb_dtt200u",
-	.probe		= dtt200u_usb_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table	= dtt200u_usb_table,
-};
-
-module_usb_driver(dtt200u_usb_driver);
-
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.h b/drivers/media/dvb/dvb-usb/dtt200u.h
deleted file mode 100644
index 005b0a7..0000000
--- a/drivers/media/dvb/dvb-usb/dtt200u.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* Common header file of Linux driver for the WideView/ Yakumo/ Hama/
- * Typhoon/ Yuan DVB-T USB2.0 receiver.
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License as published by the Free
- *	Software Foundation, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#ifndef _DVB_USB_DTT200U_H_
-#define _DVB_USB_DTT200U_H_
-
-#define DVB_USB_LOG_PREFIX "dtt200u"
-
-#include "dvb-usb.h"
-
-extern int dvb_usb_dtt200u_debug;
-#define deb_info(args...) dprintk(dvb_usb_dtt200u_debug,0x01,args)
-#define deb_xfer(args...) dprintk(dvb_usb_dtt200u_debug,0x02,args)
-
-/* guessed protocol description (reverse engineered):
- * read
- *  00 - USB type 0x02 for usb2.0, 0x01 for usb1.1
- *  88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
- */
-
-#define GET_SPEED		0x00
-#define GET_TUNE_STATUS		0x81
-#define GET_RC_CODE		0x84
-#define GET_CONFIGURATION	0x88
-#define GET_AGC			0x89
-#define GET_SNR			0x8a
-#define GET_VIT_ERR_CNT		0x8c
-#define GET_RS_ERR_CNT		0x8d
-#define GET_RS_UNCOR_BLK_CNT	0x8e
-
-/* write
- *  01 - init
- *  02 - frequency (divided by 250000)
- *  03 - bandwidth
- *  04 - pid table (index pid(7:0) pid(12:8))
- *  05 - reset the pid table
- *  08 - transfer switch
- */
-
-#define SET_INIT		0x01
-#define SET_RF_FREQ		0x02
-#define SET_BANDWIDTH		0x03
-#define SET_PID_FILTER		0x04
-#define RESET_PID_FILTER	0x05
-#define SET_STREAMING		0x08
-
-extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d);
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/dtv5100.c b/drivers/media/dvb/dvb-usb/dtv5100.c
deleted file mode 100644
index 3d11df4..0000000
--- a/drivers/media/dvb/dvb-usb/dtv5100.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T
- *
- * Copyright (C) 2008  Antoine Jacquet <royale@zerezo.com>
- * http://royale.zerezo.com/dtv5100/
- *
- * Inspired by gl861.c and au6610.c drivers
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include "dtv5100.h"
-#include "zl10353.h"
-#include "qt1010.h"
-
-/* debug */
-static int dvb_usb_dtv5100_debug;
-module_param_named(debug, dvb_usb_dtv5100_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr,
-			   u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
-{
-	u8 request;
-	u8 type;
-	u16 value;
-	u16 index;
-
-	switch (wlen) {
-	case 1:
-		/* write { reg }, read { value } */
-		request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ :
-							DTV5100_TUNER_READ);
-		type = USB_TYPE_VENDOR | USB_DIR_IN;
-		value = 0;
-		break;
-	case 2:
-		/* write { reg, value } */
-		request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE :
-							DTV5100_TUNER_WRITE);
-		type = USB_TYPE_VENDOR | USB_DIR_OUT;
-		value = wbuf[1];
-		break;
-	default:
-		warn("wlen = %x, aborting.", wlen);
-		return -EINVAL;
-	}
-	index = (addr << 8) + wbuf[0];
-
-	msleep(1); /* avoid I2C errors */
-	return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), request,
-			       type, value, index, rbuf, rlen,
-			       DTV5100_USB_TIMEOUT);
-}
-
-/* I2C */
-static int dtv5100_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-			    int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int i;
-
-	if (num > 2)
-		return -EINVAL;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	for (i = 0; i < num; i++) {
-		/* write/read request */
-		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
-			if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf,
-					    msg[i].len, msg[i+1].buf,
-					    msg[i+1].len) < 0)
-				break;
-			i++;
-		} else if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf,
-					   msg[i].len, NULL, 0) < 0)
-				break;
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return i;
-}
-
-static u32 dtv5100_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm dtv5100_i2c_algo = {
-	.master_xfer   = dtv5100_i2c_xfer,
-	.functionality = dtv5100_i2c_func,
-};
-
-/* Callbacks for DVB USB */
-static struct zl10353_config dtv5100_zl10353_config = {
-	.demod_address = DTV5100_DEMOD_ADDR,
-	.no_tuner = 1,
-	.parallel_ts = 1,
-};
-
-static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config,
-			      &adap->dev->i2c_adap);
-	if (adap->fe_adap[0].fe == NULL)
-		return -EIO;
-
-	/* disable i2c gate, or it won't work... is this safe? */
-	adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL;
-
-	return 0;
-}
-
-static struct qt1010_config dtv5100_qt1010_config = {
-	.i2c_address = DTV5100_TUNER_ADDR
-};
-
-static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	return dvb_attach(qt1010_attach,
-			  adap->fe_adap[0].fe, &adap->dev->i2c_adap,
-			  &dtv5100_qt1010_config) == NULL ? -ENODEV : 0;
-}
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties dtv5100_properties;
-
-static int dtv5100_probe(struct usb_interface *intf,
-			 const struct usb_device_id *id)
-{
-	int i, ret;
-	struct usb_device *udev = interface_to_usbdev(intf);
-
-	/* initialize non qt1010/zl10353 part? */
-	for (i = 0; dtv5100_init[i].request; i++) {
-		ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-				      dtv5100_init[i].request,
-				      USB_TYPE_VENDOR | USB_DIR_OUT,
-				      dtv5100_init[i].value,
-				      dtv5100_init[i].index, NULL, 0,
-				      DTV5100_USB_TIMEOUT);
-		if (ret)
-			return ret;
-	}
-
-	ret = dvb_usb_device_init(intf, &dtv5100_properties,
-				  THIS_MODULE, NULL, adapter_nr);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static struct usb_device_id dtv5100_table[] = {
-	{ USB_DEVICE(0x06be, 0xa232) },
-	{ }		/* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, dtv5100_table);
-
-static struct dvb_usb_device_properties dtv5100_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-	.usb_ctrl = DEVICE_SPECIFIC,
-
-	.size_of_priv = 0,
-
-	.num_adapters = 1,
-	.adapter = {{
-		.num_frontends = 1,
-		.fe = {{
-		.frontend_attach = dtv5100_frontend_attach,
-		.tuner_attach    = dtv5100_tuner_attach,
-
-		.stream = {
-			.type = USB_BULK,
-			.count = 8,
-			.endpoint = 0x82,
-			.u = {
-				.bulk = {
-					.buffersize = 4096,
-				}
-			}
-		},
-		}},
-	} },
-
-	.i2c_algo = &dtv5100_i2c_algo,
-
-	.num_device_descs = 1,
-	.devices = {
-		{
-			.name = "AME DTV-5100 USB2.0 DVB-T",
-			.cold_ids = { NULL },
-			.warm_ids = { &dtv5100_table[0], NULL },
-		},
-	}
-};
-
-static struct usb_driver dtv5100_driver = {
-	.name		= "dvb_usb_dtv5100",
-	.probe		= dtv5100_probe,
-	.disconnect	= dvb_usb_device_exit,
-	.id_table	= dtv5100_table,
-};
-
-module_usb_driver(dtv5100_driver);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dtv5100.h b/drivers/media/dvb/dvb-usb/dtv5100.h
deleted file mode 100644
index 93e96e0..0000000
--- a/drivers/media/dvb/dvb-usb/dtv5100.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T
- *
- * Copyright (C) 2008  Antoine Jacquet <royale@zerezo.com>
- * http://royale.zerezo.com/dtv5100/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#ifndef _DVB_USB_DTV5100_H_
-#define _DVB_USB_DTV5100_H_
-
-#define DVB_USB_LOG_PREFIX "dtv5100"
-#include "dvb-usb.h"
-
-#define DTV5100_USB_TIMEOUT 500
-
-#define DTV5100_DEMOD_ADDR	0x00
-#define DTV5100_DEMOD_WRITE	0xc0
-#define DTV5100_DEMOD_READ	0xc1
-
-#define DTV5100_TUNER_ADDR	0xc4
-#define DTV5100_TUNER_WRITE	0xc7
-#define DTV5100_TUNER_READ	0xc8
-
-#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
-#define DRIVER_DESC "AME DTV-5100 USB2.0 DVB-T"
-
-static struct {
-	u8 request;
-	u8 value;
-	u16 index;
-} dtv5100_init[] = {
-	{ 0x000000c5, 0x00000000, 0x00000001 },
-	{ 0x000000c5, 0x00000001, 0x00000001 },
-	{ }		/* Terminating entry */
-};
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h
deleted file mode 100644
index 6b7b2a8..0000000
--- a/drivers/media/dvb/dvb-usb/dvb-usb-common.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* dvb-usb-common.h is part of the DVB USB library.
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- * see dvb-usb-init.c for copyright information.
- *
- * a header file containing prototypes and types for internal use of the dvb-usb-lib
- */
-#ifndef _DVB_USB_COMMON_H_
-#define _DVB_USB_COMMON_H_
-
-#define DVB_USB_LOG_PREFIX "dvb-usb"
-#include "dvb-usb.h"
-
-extern int dvb_usb_debug;
-extern int dvb_usb_disable_rc_polling;
-
-#define deb_info(args...)  dprintk(dvb_usb_debug,0x001,args)
-#define deb_xfer(args...)  dprintk(dvb_usb_debug,0x002,args)
-#define deb_pll(args...)   dprintk(dvb_usb_debug,0x004,args)
-#define deb_ts(args...)    dprintk(dvb_usb_debug,0x008,args)
-#define deb_err(args...)   dprintk(dvb_usb_debug,0x010,args)
-#define deb_rc(args...)    dprintk(dvb_usb_debug,0x020,args)
-#define deb_fw(args...)    dprintk(dvb_usb_debug,0x040,args)
-#define deb_mem(args...)   dprintk(dvb_usb_debug,0x080,args)
-#define deb_uxfer(args...) dprintk(dvb_usb_debug,0x100,args)
-
-/* commonly used  methods */
-extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_device_properties *);
-
-extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff);
-
-extern int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props);
-extern int usb_urb_exit(struct usb_data_stream *stream);
-extern int usb_urb_submit(struct usb_data_stream *stream);
-extern int usb_urb_kill(struct usb_data_stream *stream);
-
-extern int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap);
-extern int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap);
-
-extern int dvb_usb_i2c_init(struct dvb_usb_device *);
-extern int dvb_usb_i2c_exit(struct dvb_usb_device *);
-
-extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap,
-				    short *adapter_nums);
-extern int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap);
-extern int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap);
-extern int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap);
-
-extern int dvb_usb_remote_init(struct dvb_usb_device *);
-extern int dvb_usb_remote_exit(struct dvb_usb_device *);
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
deleted file mode 100644
index ddf282f..0000000
--- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
+++ /dev/null
@@ -1,289 +0,0 @@
-/* dvb-usb-dvb.c is part of the DVB USB library.
- *
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
- * see dvb-usb-init.c for copyright information.
- *
- * This file contains functions for initializing and handling the
- * linux-dvb API.
- */
-#include "dvb-usb-common.h"
-
-/* does the complete input transfer handling */
-static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
-{
-	struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
-	int newfeedcount, ret;
-
-	if (adap == NULL)
-		return -ENODEV;
-
-	if ((adap->active_fe < 0) ||
-	    (adap->active_fe >= adap->num_frontends_initialized)) {
-		return -EINVAL;
-	}
-
-	newfeedcount = adap->feedcount + (onoff ? 1 : -1);
-
-	/* stop feed before setting a new pid if there will be no pid anymore */
-	if (newfeedcount == 0) {
-		deb_ts("stop feeding\n");
-		usb_urb_kill(&adap->fe_adap[adap->active_fe].stream);
-
-		if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) {
-			ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 0);
-			if (ret < 0) {
-				err("error while stopping stream.");
-				return ret;
-			}
-		}
-	}
-
-	adap->feedcount = newfeedcount;
-
-	/* activate the pid on the device specific pid_filter */
-	deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",
-		adap->fe_adap[adap->active_fe].pid_filtering ?
-		"yes" : "no", dvbdmxfeed->pid, dvbdmxfeed->pid,
-		dvbdmxfeed->index, onoff ? "on" : "off");
-	if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER &&
-		adap->fe_adap[adap->active_fe].pid_filtering &&
-		adap->props.fe[adap->active_fe].pid_filter != NULL)
-		adap->props.fe[adap->active_fe].pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, onoff);
-
-	/* start the feed if this was the first feed and there is still a feed
-	 * for reception.
-	 */
-	if (adap->feedcount == onoff && adap->feedcount > 0) {
-		deb_ts("submitting all URBs\n");
-		usb_urb_submit(&adap->fe_adap[adap->active_fe].stream);
-
-		deb_ts("controlling pid parser\n");
-		if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER &&
-			adap->props.fe[adap->active_fe].caps &
-			DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
-			adap->props.fe[adap->active_fe].pid_filter_ctrl != NULL) {
-			ret = adap->props.fe[adap->active_fe].pid_filter_ctrl(adap,
-				adap->fe_adap[adap->active_fe].pid_filtering);
-			if (ret < 0) {
-				err("could not handle pid_parser");
-				return ret;
-			}
-		}
-		deb_ts("start feeding\n");
-		if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) {
-			ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 1);
-			if (ret < 0) {
-				err("error while enabling fifo.");
-				return ret;
-			}
-		}
-
-	}
-	return 0;
-}
-
-static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
-	return dvb_usb_ctrl_feed(dvbdmxfeed,1);
-}
-
-static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type);
-	return dvb_usb_ctrl_feed(dvbdmxfeed,0);
-}
-
-int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
-{
-	int i;
-	int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name,
-				       adap->dev->owner, &adap->dev->udev->dev,
-				       adapter_nums);
-
-	if (ret < 0) {
-		deb_info("dvb_register_adapter failed: error %d", ret);
-		goto err;
-	}
-	adap->dvb_adap.priv = adap;
-	adap->dvb_adap.fe_ioctl_override = adap->props.fe_ioctl_override;
-
-	if (adap->dev->props.read_mac_address) {
-		if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0)
-			info("MAC address: %pM",adap->dvb_adap.proposed_mac);
-		else
-			err("MAC address reading failed.");
-	}
-
-
-	adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
-	adap->demux.priv             = adap;
-
-	adap->demux.filternum        = 0;
-	for (i = 0; i < adap->props.num_frontends; i++) {
-		if (adap->demux.filternum < adap->fe_adap[i].max_feed_count)
-			adap->demux.filternum = adap->fe_adap[i].max_feed_count;
-	}
-	adap->demux.feednum          = adap->demux.filternum;
-	adap->demux.start_feed       = dvb_usb_start_feed;
-	adap->demux.stop_feed        = dvb_usb_stop_feed;
-	adap->demux.write_to_decoder = NULL;
-	if ((ret = dvb_dmx_init(&adap->demux)) < 0) {
-		err("dvb_dmx_init failed: error %d",ret);
-		goto err_dmx;
-	}
-
-	adap->dmxdev.filternum       = adap->demux.filternum;
-	adap->dmxdev.demux           = &adap->demux.dmx;
-	adap->dmxdev.capabilities    = 0;
-	if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap)) < 0) {
-		err("dvb_dmxdev_init failed: error %d",ret);
-		goto err_dmx_dev;
-	}
-
-	if ((ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net,
-						&adap->demux.dmx)) < 0) {
-		err("dvb_net_init failed: error %d",ret);
-		goto err_net_init;
-	}
-
-	adap->state |= DVB_USB_ADAP_STATE_DVB;
-	return 0;
-
-err_net_init:
-	dvb_dmxdev_release(&adap->dmxdev);
-err_dmx_dev:
-	dvb_dmx_release(&adap->demux);
-err_dmx:
-	dvb_unregister_adapter(&adap->dvb_adap);
-err:
-	return ret;
-}
-
-int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap)
-{
-	if (adap->state & DVB_USB_ADAP_STATE_DVB) {
-		deb_info("unregistering DVB part\n");
-		dvb_net_release(&adap->dvb_net);
-		adap->demux.dmx.close(&adap->demux.dmx);
-		dvb_dmxdev_release(&adap->dmxdev);
-		dvb_dmx_release(&adap->demux);
-		dvb_unregister_adapter(&adap->dvb_adap);
-		adap->state &= ~DVB_USB_ADAP_STATE_DVB;
-	}
-	return 0;
-}
-
-static int dvb_usb_set_active_fe(struct dvb_frontend *fe, int onoff)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-
-	int ret = (adap->props.frontend_ctrl) ?
-		adap->props.frontend_ctrl(fe, onoff) : 0;
-
-	if (ret < 0) {
-		err("frontend_ctrl request failed");
-		return ret;
-	}
-	if (onoff)
-		adap->active_fe = fe->id;
-
-	return 0;
-}
-
-static int dvb_usb_fe_wakeup(struct dvb_frontend *fe)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-
-	dvb_usb_device_power_ctrl(adap->dev, 1);
-
-	dvb_usb_set_active_fe(fe, 1);
-
-	if (adap->fe_adap[fe->id].fe_init)
-		adap->fe_adap[fe->id].fe_init(fe);
-
-	return 0;
-}
-
-static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-
-	if (adap->fe_adap[fe->id].fe_sleep)
-		adap->fe_adap[fe->id].fe_sleep(fe);
-
-	dvb_usb_set_active_fe(fe, 0);
-
-	return dvb_usb_device_power_ctrl(adap->dev, 0);
-}
-
-int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap)
-{
-	int ret, i;
-
-	/* register all given adapter frontends */
-	for (i = 0; i < adap->props.num_frontends; i++) {
-
-		if (adap->props.fe[i].frontend_attach == NULL) {
-			err("strange: '%s' #%d,%d "
-			    "doesn't want to attach a frontend.",
-			    adap->dev->desc->name, adap->id, i);
-
-			return 0;
-		}
-
-		ret = adap->props.fe[i].frontend_attach(adap);
-		if (ret || adap->fe_adap[i].fe == NULL) {
-			/* only print error when there is no FE at all */
-			if (i == 0)
-				err("no frontend was attached by '%s'",
-					adap->dev->desc->name);
-
-			return 0;
-		}
-
-		adap->fe_adap[i].fe->id = i;
-
-		/* re-assign sleep and wakeup functions */
-		adap->fe_adap[i].fe_init = adap->fe_adap[i].fe->ops.init;
-		adap->fe_adap[i].fe->ops.init  = dvb_usb_fe_wakeup;
-		adap->fe_adap[i].fe_sleep = adap->fe_adap[i].fe->ops.sleep;
-		adap->fe_adap[i].fe->ops.sleep = dvb_usb_fe_sleep;
-
-		if (dvb_register_frontend(&adap->dvb_adap, adap->fe_adap[i].fe)) {
-			err("Frontend %d registration failed.", i);
-			dvb_frontend_detach(adap->fe_adap[i].fe);
-			adap->fe_adap[i].fe = NULL;
-			/* In error case, do not try register more FEs,
-			 * still leaving already registered FEs alive. */
-			if (i == 0)
-				return -ENODEV;
-			else
-				return 0;
-		}
-
-		/* only attach the tuner if the demod is there */
-		if (adap->props.fe[i].tuner_attach != NULL)
-			adap->props.fe[i].tuner_attach(adap);
-
-		adap->num_frontends_initialized++;
-	}
-
-	return 0;
-}
-
-int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap)
-{
-	int i = adap->num_frontends_initialized - 1;
-
-	/* unregister all given adapter frontends */
-	for (; i >= 0; i--) {
-		if (adap->fe_adap[i].fe != NULL) {
-			dvb_unregister_frontend(adap->fe_adap[i].fe);
-			dvb_frontend_detach(adap->fe_adap[i].fe);
-		}
-	}
-	adap->num_frontends_initialized = 0;
-
-	return 0;
-}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
deleted file mode 100644
index 733a7ff..0000000
--- a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/* dvb-usb-firmware.c is part of the DVB USB library.
- *
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
- * see dvb-usb-init.c for copyright information.
- *
- * This file contains functions for downloading the firmware to Cypress FX 1 and 2 based devices.
- *
- * FIXME: This part does actually not belong to dvb-usb, but to the usb-subsystem.
- */
-#include "dvb-usb-common.h"
-
-#include <linux/usb.h>
-
-struct usb_cypress_controller {
-	int id;
-	const char *name;       /* name of the usb controller */
-	u16 cpu_cs_register;    /* needs to be restarted, when the firmware has been downloaded. */
-};
-
-static struct usb_cypress_controller cypress[] = {
-	{ .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 },
-	{ .id = CYPRESS_AN2135,  .name = "Cypress AN2135",  .cpu_cs_register = 0x7f92 },
-	{ .id = CYPRESS_AN2235,  .name = "Cypress AN2235",  .cpu_cs_register = 0x7f92 },
-	{ .id = CYPRESS_FX2,     .name = "Cypress FX2",     .cpu_cs_register = 0xe600 },
-};
-
-/*
- * load a firmware packet to the device
- */
-static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
-{
-	return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
-			0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
-}
-
-int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
-{
-	struct hexline hx;
-	u8 reset;
-	int ret,pos=0;
-
-	/* stop the CPU */
-	reset = 1;
-	if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
-		err("could not stop the USB controller CPU.");
-
-	while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) {
-		deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk);
-		ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len);
-
-		if (ret != hx.len) {
-			err("error while transferring firmware "
-				"(transferred size: %d, block size: %d)",
-				ret,hx.len);
-			ret = -EINVAL;
-			break;
-		}
-	}
-	if (ret < 0) {
-		err("firmware download failed at %d with %d",pos,ret);
-		return ret;
-	}
-
-	if (ret == 0) {
-		/* restart the CPU */
-		reset = 0;
-		if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
-			err("could not restart the USB controller CPU.");
-			ret = -EINVAL;
-		}
-	} else
-		ret = -EIO;
-
-	return ret;
-}
-EXPORT_SYMBOL(usb_cypress_load_firmware);
-
-int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_device_properties *props)
-{
-	int ret;
-	const struct firmware *fw = NULL;
-
-	if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) {
-		err("did not find the firmware file. (%s) "
-			"Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
-			props->firmware,ret);
-		return ret;
-	}
-
-	info("downloading firmware from file '%s'",props->firmware);
-
-	switch (props->usb_ctrl) {
-		case CYPRESS_AN2135:
-		case CYPRESS_AN2235:
-		case CYPRESS_FX2:
-			ret = usb_cypress_load_firmware(udev, fw, props->usb_ctrl);
-			break;
-		case DEVICE_SPECIFIC:
-			if (props->download_firmware)
-				ret = props->download_firmware(udev,fw);
-			else {
-				err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one.");
-				ret = -EINVAL;
-			}
-			break;
-		default:
-			ret = -EINVAL;
-			break;
-	}
-
-	release_firmware(fw);
-	return ret;
-}
-
-int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx,
-			       int *pos)
-{
-	u8 *b = (u8 *) &fw->data[*pos];
-	int data_offs = 4;
-	if (*pos >= fw->size)
-		return 0;
-
-	memset(hx,0,sizeof(struct hexline));
-
-	hx->len  = b[0];
-
-	if ((*pos + hx->len + 4) >= fw->size)
-		return -EINVAL;
-
-	hx->addr = b[1] | (b[2] << 8);
-	hx->type = b[3];
-
-	if (hx->type == 0x04) {
-		/* b[4] and b[5] are the Extended linear address record data field */
-		hx->addr |= (b[4] << 24) | (b[5] << 16);
-/*		hx->len -= 2;
-		data_offs += 2; */
-	}
-	memcpy(hx->data,&b[data_offs],hx->len);
-	hx->chk = b[hx->len + data_offs];
-
-	*pos += hx->len + 5;
-
-	return *pos;
-}
-EXPORT_SYMBOL(dvb_usb_get_hexline);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
deleted file mode 100644
index 88e4a62..0000000
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/* dvb-usb-i2c.c is part of the DVB USB library.
- *
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
- * see dvb-usb-init.c for copyright information.
- *
- * This file contains functions for (de-)initializing an I2C adapter.
- */
-#include "dvb-usb-common.h"
-
-int dvb_usb_i2c_init(struct dvb_usb_device *d)
-{
-	int ret = 0;
-
-	if (!(d->props.caps & DVB_USB_IS_AN_I2C_ADAPTER))
-		return 0;
-
-	if (d->props.i2c_algo == NULL) {
-		err("no i2c algorithm specified");
-		return -EINVAL;
-	}
-
-	strlcpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
-	d->i2c_adap.algo      = d->props.i2c_algo;
-	d->i2c_adap.algo_data = NULL;
-	d->i2c_adap.dev.parent = &d->udev->dev;
-
-	i2c_set_adapdata(&d->i2c_adap, d);
-
-	if ((ret = i2c_add_adapter(&d->i2c_adap)) < 0)
-		err("could not add i2c adapter");
-
-	d->state |= DVB_USB_STATE_I2C;
-
-	return ret;
-}
-
-int dvb_usb_i2c_exit(struct dvb_usb_device *d)
-{
-	if (d->state & DVB_USB_STATE_I2C)
-		i2c_del_adapter(&d->i2c_adap);
-	d->state &= ~DVB_USB_STATE_I2C;
-	return 0;
-}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
deleted file mode 100644
index 26c4481..0000000
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ /dev/null
@@ -1,361 +0,0 @@
-/* dvb-usb-ids.h is part of the DVB USB library.
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) see
- * dvb-usb-init.c for copyright information.
- *
- * a header file containing define's for the USB device supported by the
- * various drivers.
- */
-#ifndef _DVB_USB_IDS_H_
-#define _DVB_USB_IDS_H_
-
-/* Vendor IDs */
-#define USB_VID_ADSTECH				0x06e1
-#define USB_VID_AFATECH				0x15a4
-#define USB_VID_ALCOR_MICRO			0x058f
-#define USB_VID_ALINK				0x05e3
-#define USB_VID_AMT				0x1c73
-#define USB_VID_ANCHOR				0x0547
-#define USB_VID_ANSONIC				0x10b9
-#define USB_VID_ANUBIS_ELECTRONIC		0x10fd
-#define USB_VID_ASUS				0x0b05
-#define USB_VID_AVERMEDIA			0x07ca
-#define USB_VID_COMPRO				0x185b
-#define USB_VID_COMPRO_UNK			0x145f
-#define USB_VID_CONEXANT			0x0572
-#define USB_VID_CYPRESS				0x04b4
-#define USB_VID_DIBCOM				0x10b8
-#define USB_VID_DPOSH				0x1498
-#define USB_VID_DVICO				0x0fe9
-#define USB_VID_E3C				0x18b4
-#define USB_VID_ELGATO				0x0fd9
-#define USB_VID_EMPIA				0xeb1a
-#define USB_VID_GENPIX				0x09c0
-#define USB_VID_GRANDTEC			0x5032
-#define USB_VID_GTEK				0x1f4d
-#define USB_VID_HANFTEK				0x15f4
-#define USB_VID_HAUPPAUGE			0x2040
-#define USB_VID_HYPER_PALTEK			0x1025
-#define USB_VID_INTEL				0x8086
-#define USB_VID_ITETECH				0x048d
-#define USB_VID_KWORLD				0xeb2a
-#define USB_VID_KWORLD_2			0x1b80
-#define USB_VID_KYE				0x0458
-#define USB_VID_LEADTEK				0x0413
-#define USB_VID_LITEON				0x04ca
-#define USB_VID_MEDION				0x1660
-#define USB_VID_MIGLIA				0x18f3
-#define USB_VID_MSI				0x0db0
-#define USB_VID_MSI_2				0x1462
-#define USB_VID_OPERA1				0x695c
-#define USB_VID_PINNACLE			0x2304
-#define USB_VID_PCTV				0x2013
-#define USB_VID_PIXELVIEW			0x1554
-#define USB_VID_REALTEK				0x0bda
-#define USB_VID_TECHNOTREND			0x0b48
-#define USB_VID_TERRATEC			0x0ccd
-#define USB_VID_TELESTAR			0x10b9
-#define USB_VID_VISIONPLUS			0x13d3
-#define USB_VID_SONY				0x1415
-#define USB_VID_TWINHAN				0x1822
-#define USB_VID_ULTIMA_ELECTRONIC		0x05d8
-#define USB_VID_UNIWILL				0x1584
-#define USB_VID_WIDEVIEW			0x14aa
-#define USB_VID_GIGABYTE			0x1044
-#define USB_VID_YUAN				0x1164
-#define USB_VID_XTENSIONS			0x1ae7
-#define USB_VID_HUMAX_COEX			0x10b9
-#define USB_VID_774				0x7a69
-#define USB_VID_EVOLUTEPC			0x1e59
-#define USB_VID_AZUREWAVE			0x13d3
-#define USB_VID_TECHNISAT			0x14f7
-
-/* Product IDs */
-#define USB_PID_ADSTECH_USB2_COLD			0xa333
-#define USB_PID_ADSTECH_USB2_WARM			0xa334
-#define USB_PID_AFATECH_AF9005				0x9020
-#define USB_PID_AFATECH_AF9015_9015			0x9015
-#define USB_PID_AFATECH_AF9015_9016			0x9016
-#define USB_PID_AFATECH_AF9035_1000			0x1000
-#define USB_PID_AFATECH_AF9035_1001			0x1001
-#define USB_PID_AFATECH_AF9035_1002			0x1002
-#define USB_PID_AFATECH_AF9035_1003			0x1003
-#define USB_PID_AFATECH_AF9035_9035			0x9035
-#define USB_PID_TREKSTOR_DVBT				0x901b
-#define USB_VID_ALINK_DTU				0xf170
-#define USB_PID_ANSONIC_DVBT_USB			0x6000
-#define USB_PID_ANYSEE					0x861f
-#define USB_PID_AZUREWAVE_AD_TU700			0x3237
-#define USB_PID_AZUREWAVE_6007				0x0ccd
-#define USB_PID_AVERMEDIA_DVBT_USB_COLD			0x0001
-#define USB_PID_AVERMEDIA_DVBT_USB_WARM			0x0002
-#define USB_PID_AVERMEDIA_DVBT_USB2_COLD		0xa800
-#define USB_PID_AVERMEDIA_DVBT_USB2_WARM		0xa801
-#define USB_PID_COMPRO_DVBU2000_COLD			0xd000
-#define USB_PID_COMPRO_DVBU2000_WARM			0xd001
-#define USB_PID_COMPRO_DVBU2000_UNK_COLD		0x010c
-#define USB_PID_COMPRO_DVBU2000_UNK_WARM		0x010d
-#define USB_PID_COMPRO_VIDEOMATE_U500			0x1e78
-#define USB_PID_COMPRO_VIDEOMATE_U500_PC		0x1e80
-#define USB_PID_CONCEPTRONIC_CTVDIGRCU			0xe397
-#define USB_PID_CONEXANT_D680_DMB			0x86d6
-#define USB_PID_CREATIX_CTX1921				0x1921
-#define USB_PID_DELOCK_USB2_DVBT			0xb803
-#define USB_PID_DIBCOM_HOOK_DEFAULT			0x0064
-#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM		0x0065
-#define USB_PID_DIBCOM_MOD3000_COLD			0x0bb8
-#define USB_PID_DIBCOM_MOD3000_WARM			0x0bb9
-#define USB_PID_DIBCOM_MOD3001_COLD			0x0bc6
-#define USB_PID_DIBCOM_MOD3001_WARM			0x0bc7
-#define USB_PID_DIBCOM_STK7700P				0x1e14
-#define USB_PID_DIBCOM_STK7700P_PC			0x1e78
-#define USB_PID_DIBCOM_STK7700D				0x1ef0
-#define USB_PID_DIBCOM_STK7700_U7000			0x7001
-#define USB_PID_DIBCOM_STK7070P				0x1ebc
-#define USB_PID_DIBCOM_STK7070PD			0x1ebe
-#define USB_PID_DIBCOM_STK807XP				0x1f90
-#define USB_PID_DIBCOM_STK807XPVR			0x1f98
-#define USB_PID_DIBCOM_STK8096GP                        0x1fa0
-#define USB_PID_DIBCOM_NIM8096MD                        0x1fa8
-#define USB_PID_DIBCOM_TFE8096P				0x1f9C
-#define USB_PID_DIBCOM_ANCHOR_2135_COLD			0x2131
-#define USB_PID_DIBCOM_STK7770P				0x1e80
-#define USB_PID_DIBCOM_NIM7090				0x1bb2
-#define USB_PID_DIBCOM_TFE7090PVR			0x1bb4
-#define USB_PID_DIBCOM_TFE7090E				0x1bb7
-#define USB_PID_DIBCOM_TFE7790E				0x1e6e
-#define USB_PID_DIBCOM_NIM9090M				0x2383
-#define USB_PID_DIBCOM_NIM9090MD			0x2384
-#define USB_PID_DPOSH_M9206_COLD			0x9206
-#define USB_PID_DPOSH_M9206_WARM			0xa090
-#define USB_PID_E3C_EC168				0x1689
-#define USB_PID_E3C_EC168_2				0xfffa
-#define USB_PID_E3C_EC168_3				0xfffb
-#define USB_PID_E3C_EC168_4				0x1001
-#define USB_PID_E3C_EC168_5				0x1002
-#define USB_PID_FREECOM_DVBT				0x0160
-#define USB_PID_FREECOM_DVBT_2				0x0161
-#define USB_PID_UNIWILL_STK7700P			0x6003
-#define USB_PID_GENIUS_TVGO_DVB_T03			0x4012
-#define USB_PID_GRANDTEC_DVBT_USB_COLD			0x0fa0
-#define USB_PID_GRANDTEC_DVBT_USB_WARM			0x0fa1
-#define USB_PID_INTEL_CE9500				0x9500
-#define USB_PID_ITETECH_IT9135				0x9135
-#define USB_PID_ITETECH_IT9135_9005			0x9005
-#define USB_PID_ITETECH_IT9135_9006			0x9006
-#define USB_PID_KWORLD_399U				0xe399
-#define USB_PID_KWORLD_399U_2				0xe400
-#define USB_PID_KWORLD_395U				0xe396
-#define USB_PID_KWORLD_395U_2				0xe39b
-#define USB_PID_KWORLD_395U_3				0xe395
-#define USB_PID_KWORLD_395U_4				0xe39a
-#define USB_PID_KWORLD_MC810				0xc810
-#define USB_PID_KWORLD_PC160_2T				0xc160
-#define USB_PID_KWORLD_PC160_T				0xc161
-#define USB_PID_KWORLD_UB383_T				0xe383
-#define USB_PID_KWORLD_UB499_2T_T09			0xe409
-#define USB_PID_KWORLD_VSTREAM_COLD			0x17de
-#define USB_PID_KWORLD_VSTREAM_WARM			0x17df
-#define USB_PID_TERRATEC_CINERGY_T_USB_XE		0x0055
-#define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2		0x0069
-#define USB_PID_TERRATEC_CINERGY_T_STICK		0x0093
-#define USB_PID_TERRATEC_CINERGY_T_STICK_RC		0x0097
-#define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC	0x0099
-#define USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1	0x00a9
-#define USB_PID_TWINHAN_VP7041_COLD			0x3201
-#define USB_PID_TWINHAN_VP7041_WARM			0x3202
-#define USB_PID_TWINHAN_VP7020_COLD			0x3203
-#define USB_PID_TWINHAN_VP7020_WARM			0x3204
-#define USB_PID_TWINHAN_VP7045_COLD			0x3205
-#define USB_PID_TWINHAN_VP7045_WARM			0x3206
-#define USB_PID_TWINHAN_VP7021_COLD			0x3207
-#define USB_PID_TWINHAN_VP7021_WARM			0x3208
-#define USB_PID_TINYTWIN				0x3226
-#define USB_PID_TINYTWIN_2				0xe402
-#define USB_PID_TINYTWIN_3				0x9016
-#define USB_PID_DNTV_TINYUSB2_COLD			0x3223
-#define USB_PID_DNTV_TINYUSB2_WARM			0x3224
-#define USB_PID_ULTIMA_TVBOX_COLD			0x8105
-#define USB_PID_ULTIMA_TVBOX_WARM			0x8106
-#define USB_PID_ULTIMA_TVBOX_AN2235_COLD		0x8107
-#define USB_PID_ULTIMA_TVBOX_AN2235_WARM		0x8108
-#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD		0x2235
-#define USB_PID_ULTIMA_TVBOX_USB2_COLD			0x8109
-#define USB_PID_ULTIMA_TVBOX_USB2_WARM			0x810a
-#define USB_PID_ARTEC_T14_COLD				0x810b
-#define USB_PID_ARTEC_T14_WARM				0x810c
-#define USB_PID_ARTEC_T14BR				0x810f
-#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD		0x8613
-#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM		0x1002
-#define USB_PID_UNK_HYPER_PALTEK_COLD			0x005e
-#define USB_PID_UNK_HYPER_PALTEK_WARM			0x005f
-#define USB_PID_HANFTEK_UMT_010_COLD			0x0001
-#define USB_PID_HANFTEK_UMT_010_WARM			0x0015
-#define USB_PID_DTT200U_COLD				0x0201
-#define USB_PID_DTT200U_WARM				0x0301
-#define USB_PID_WT220U_ZAP250_COLD			0x0220
-#define USB_PID_WT220U_COLD				0x0222
-#define USB_PID_WT220U_WARM				0x0221
-#define USB_PID_WT220U_FC_COLD				0x0225
-#define USB_PID_WT220U_FC_WARM				0x0226
-#define USB_PID_WT220U_ZL0353_COLD			0x022a
-#define USB_PID_WT220U_ZL0353_WARM			0x022b
-#define USB_PID_WINTV_NOVA_T_USB2_COLD			0x9300
-#define USB_PID_WINTV_NOVA_T_USB2_WARM			0x9301
-#define USB_PID_HAUPPAUGE_NOVA_T_500			0x9941
-#define USB_PID_HAUPPAUGE_NOVA_T_500_2			0x9950
-#define USB_PID_HAUPPAUGE_NOVA_T_500_3			0x8400
-#define USB_PID_HAUPPAUGE_NOVA_T_STICK			0x7050
-#define USB_PID_HAUPPAUGE_NOVA_T_STICK_2		0x7060
-#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3		0x7070
-#define USB_PID_HAUPPAUGE_MYTV_T			0x7080
-#define USB_PID_HAUPPAUGE_NOVA_TD_STICK			0x9580
-#define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009		0x5200
-#define USB_PID_HAUPPAUGE_TIGER_ATSC			0xb200
-#define USB_PID_HAUPPAUGE_TIGER_ATSC_B210		0xb210
-#define USB_PID_AVERMEDIA_EXPRESS			0xb568
-#define USB_PID_AVERMEDIA_VOLAR				0xa807
-#define USB_PID_AVERMEDIA_VOLAR_2			0xb808
-#define USB_PID_AVERMEDIA_VOLAR_A868R			0xa868
-#define USB_PID_AVERMEDIA_MCE_USB_M038			0x1228
-#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R	0x0039
-#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC	0x1039
-#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT	0x2039
-#define USB_PID_AVERMEDIA_VOLAR_X			0xa815
-#define USB_PID_AVERMEDIA_VOLAR_X_2			0x8150
-#define USB_PID_AVERMEDIA_A309				0xa309
-#define USB_PID_AVERMEDIA_A310				0xa310
-#define USB_PID_AVERMEDIA_A850				0x850a
-#define USB_PID_AVERMEDIA_A850T				0x850b
-#define USB_PID_AVERMEDIA_A805				0xa805
-#define USB_PID_AVERMEDIA_A815M				0x815a
-#define USB_PID_AVERMEDIA_A835				0xa835
-#define USB_PID_AVERMEDIA_B835				0xb835
-#define USB_PID_AVERMEDIA_1867				0x1867
-#define USB_PID_AVERMEDIA_A867				0xa867
-#define USB_PID_AVERMEDIA_TWINSTAR			0x0825
-#define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
-#define USB_PID_TECHNOTREND_CONNECT_CT3650		0x300d
-#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY	0x005a
-#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2	0x0081
-#define USB_PID_TERRATEC_CINERGY_HT_USB_XE		0x0058
-#define USB_PID_TERRATEC_CINERGY_HT_EXPRESS		0x0060
-#define USB_PID_TERRATEC_CINERGY_T_EXPRESS		0x0062
-#define USB_PID_TERRATEC_CINERGY_T_XXS			0x0078
-#define USB_PID_TERRATEC_CINERGY_T_XXS_2		0x00ab
-#define USB_PID_TERRATEC_H7				0x10b4
-#define USB_PID_TERRATEC_H7_2				0x10a3
-#define USB_PID_TERRATEC_T3				0x10a0
-#define USB_PID_TERRATEC_T5				0x10a1
-#define USB_PID_NOXON_DAB_STICK				0x00b3
-#define USB_PID_PINNACLE_EXPRESSCARD_320CX		0x022e
-#define USB_PID_PINNACLE_PCTV2000E			0x022c
-#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH		0x0228
-#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T	0x0229
-#define USB_PID_PINNACLE_PCTV71E			0x022b
-#define USB_PID_PINNACLE_PCTV72E			0x0236
-#define USB_PID_PINNACLE_PCTV73E			0x0237
-#define USB_PID_PINNACLE_PCTV310E			0x3211
-#define USB_PID_PINNACLE_PCTV801E			0x023a
-#define USB_PID_PINNACLE_PCTV801E_SE			0x023b
-#define USB_PID_PINNACLE_PCTV340E			0x023d
-#define USB_PID_PINNACLE_PCTV340E_SE			0x023e
-#define USB_PID_PINNACLE_PCTV73A			0x0243
-#define USB_PID_PINNACLE_PCTV73ESE			0x0245
-#define USB_PID_PINNACLE_PCTV74E			0x0246
-#define USB_PID_PINNACLE_PCTV282E			0x0248
-#define USB_PID_PIXELVIEW_SBTVD				0x5010
-#define USB_PID_PCTV_200E				0x020e
-#define USB_PID_PCTV_400E				0x020f
-#define USB_PID_PCTV_450E				0x0222
-#define USB_PID_PCTV_452E				0x021f
-#define USB_PID_REALTEK_RTL2831U			0x2831
-#define USB_PID_REALTEK_RTL2832U			0x2832
-#define USB_PID_TECHNOTREND_CONNECT_S2_3600		0x3007
-#define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI		0x300a
-#define USB_PID_NEBULA_DIGITV				0x0201
-#define USB_PID_DVICO_BLUEBIRD_LGDT			0xd820
-#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD		0xd500
-#define USB_PID_DVICO_BLUEBIRD_LG064F_WARM		0xd501
-#define USB_PID_DVICO_BLUEBIRD_LGZ201_COLD		0xdb00
-#define USB_PID_DVICO_BLUEBIRD_LGZ201_WARM		0xdb01
-#define USB_PID_DVICO_BLUEBIRD_TH7579_COLD		0xdb10
-#define USB_PID_DVICO_BLUEBIRD_TH7579_WARM		0xdb11
-#define USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD		0xdb50
-#define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM		0xdb51
-#define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD		0xdb58
-#define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM		0xdb59
-#define USB_PID_DVICO_BLUEBIRD_DUAL_4			0xdb78
-#define USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2		0xdb98
-#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2		0xdb70
-#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM	0xdb71
-#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD		0xdb54
-#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM		0xdb55
-#define USB_PID_MEDION_MD95700				0x0932
-#define USB_PID_MSI_MEGASKY580				0x5580
-#define USB_PID_MSI_MEGASKY580_55801			0x5581
-#define USB_PID_KYE_DVB_T_COLD				0x701e
-#define USB_PID_KYE_DVB_T_WARM				0x701f
-#define USB_PID_LITEON_DVB_T_COLD			0xf000
-#define USB_PID_LITEON_DVB_T_WARM			0xf001
-#define USB_PID_DIGIVOX_MINI_SL_COLD			0xe360
-#define USB_PID_DIGIVOX_MINI_SL_WARM			0xe361
-#define USB_PID_GRANDTEC_DVBT_USB2_COLD			0x0bc6
-#define USB_PID_GRANDTEC_DVBT_USB2_WARM			0x0bc7
-#define USB_PID_WINFAST_DTV2000DS			0x6a04
-#define USB_PID_WINFAST_DTV_DONGLE_COLD			0x6025
-#define USB_PID_WINFAST_DTV_DONGLE_WARM			0x6026
-#define USB_PID_WINFAST_DTV_DONGLE_STK7700P		0x6f00
-#define USB_PID_WINFAST_DTV_DONGLE_H			0x60f6
-#define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2		0x6f01
-#define USB_PID_WINFAST_DTV_DONGLE_GOLD			0x6029
-#define USB_PID_GENPIX_8PSK_REV_1_COLD			0x0200
-#define USB_PID_GENPIX_8PSK_REV_1_WARM			0x0201
-#define USB_PID_GENPIX_8PSK_REV_2			0x0202
-#define USB_PID_GENPIX_SKYWALKER_1			0x0203
-#define USB_PID_GENPIX_SKYWALKER_CW3K			0x0204
-#define USB_PID_GENPIX_SKYWALKER_2			0x0206
-#define USB_PID_SIGMATEK_DVB_110			0x6610
-#define USB_PID_MSI_DIGI_VOX_MINI_II			0x1513
-#define USB_PID_MSI_DIGIVOX_DUO				0x8801
-#define USB_PID_OPERA1_COLD				0x2830
-#define USB_PID_OPERA1_WARM				0x3829
-#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD		0x0514
-#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM		0x0513
-#define USB_PID_GIGABYTE_U7000				0x7001
-#define USB_PID_GIGABYTE_U8000				0x7002
-#define USB_PID_ASUS_U3000				0x171f
-#define USB_PID_ASUS_U3000H				0x1736
-#define USB_PID_ASUS_U3100				0x173f
-#define USB_PID_YUAN_EC372S				0x1edc
-#define USB_PID_YUAN_STK7700PH				0x1f08
-#define USB_PID_YUAN_PD378S				0x2edc
-#define USB_PID_YUAN_MC770				0x0871
-#define USB_PID_YUAN_STK7700D				0x1efc
-#define USB_PID_YUAN_STK7700D_2				0x1e8c
-#define USB_PID_DW2102					0x2102
-#define USB_PID_XTENSIONS_XD_380			0x0381
-#define USB_PID_TELESTAR_STARSTICK_2			0x8000
-#define USB_PID_MSI_DIGI_VOX_MINI_III                   0x8807
-#define USB_PID_SONY_PLAYTV				0x0003
-#define USB_PID_MYGICA_D689				0xd811
-#define USB_PID_ELGATO_EYETV_DIVERSITY			0x0011
-#define USB_PID_ELGATO_EYETV_DTT			0x0021
-#define USB_PID_ELGATO_EYETV_DTT_2			0x003f
-#define USB_PID_ELGATO_EYETV_DTT_Dlx			0x0020
-#define USB_PID_ELGATO_EYETV_SAT			0x002a
-#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD		0x5000
-#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM		0x5001
-#define USB_PID_FRIIO_WHITE				0x0001
-#define USB_PID_TVWAY_PLUS				0x0002
-#define USB_PID_SVEON_STV20				0xe39d
-#define USB_PID_SVEON_STV22				0xe401
-#define USB_PID_SVEON_STV22_IT9137			0xe411
-#define USB_PID_AZUREWAVE_AZ6027			0x3275
-#define USB_PID_TERRATEC_DVBS2CI_V1			0x10a4
-#define USB_PID_TERRATEC_DVBS2CI_V2			0x10ac
-#define USB_PID_TECHNISAT_USB2_HDCI_V1			0x0001
-#define USB_PID_TECHNISAT_USB2_HDCI_V2			0x0002
-#define USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2		0x0004
-#define USB_PID_TECHNISAT_USB2_DVB_S2			0x0500
-#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
deleted file mode 100644
index 169196e..0000000
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * DVB USB library - provides a generic interface for a DVB USB device driver.
- *
- * dvb-usb-init.c
- *
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License as published by the Free
- *	Software Foundation, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "dvb-usb-common.h"
-
-/* debug */
-int dvb_usb_debug;
-module_param_named(debug, dvb_usb_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256  (or-able))." DVB_USB_DEBUG_STATUS);
-
-int dvb_usb_disable_rc_polling;
-module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644);
-MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0).");
-
-static int dvb_usb_force_pid_filter_usage;
-module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444);
-MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
-
-static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
-{
-	struct dvb_usb_adapter *adap;
-	int ret, n, o;
-
-	for (n = 0; n < d->props.num_adapters; n++) {
-		adap = &d->adapter[n];
-		adap->dev = d;
-		adap->id  = n;
-
-		memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties));
-
-	for (o = 0; o < adap->props.num_frontends; o++) {
-		struct dvb_usb_adapter_fe_properties *props = &adap->props.fe[o];
-		/* speed - when running at FULL speed we need a HW PID filter */
-		if (d->udev->speed == USB_SPEED_FULL && !(props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
-			err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
-			return -ENODEV;
-		}
-
-		if ((d->udev->speed == USB_SPEED_FULL && props->caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
-			(props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
-			info("will use the device's hardware PID filter (table count: %d).", props->pid_filter_count);
-			adap->fe_adap[o].pid_filtering  = 1;
-			adap->fe_adap[o].max_feed_count = props->pid_filter_count;
-		} else {
-			info("will pass the complete MPEG2 transport stream to the software demuxer.");
-			adap->fe_adap[o].pid_filtering  = 0;
-			adap->fe_adap[o].max_feed_count = 255;
-		}
-
-		if (!adap->fe_adap[o].pid_filtering &&
-			dvb_usb_force_pid_filter_usage &&
-			props->caps & DVB_USB_ADAP_HAS_PID_FILTER) {
-			info("pid filter enabled by module option.");
-			adap->fe_adap[o].pid_filtering  = 1;
-			adap->fe_adap[o].max_feed_count = props->pid_filter_count;
-		}
-
-		if (props->size_of_priv > 0) {
-			adap->fe_adap[o].priv = kzalloc(props->size_of_priv, GFP_KERNEL);
-			if (adap->fe_adap[o].priv == NULL) {
-				err("no memory for priv for adapter %d fe %d.", n, o);
-				return -ENOMEM;
-			}
-		}
-	}
-
-		if (adap->props.size_of_priv > 0) {
-			adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL);
-			if (adap->priv == NULL) {
-				err("no memory for priv for adapter %d.", n);
-				return -ENOMEM;
-			}
-		}
-
-		if ((ret = dvb_usb_adapter_stream_init(adap)) ||
-			(ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs)) ||
-			(ret = dvb_usb_adapter_frontend_init(adap))) {
-			return ret;
-		}
-
-		/* use exclusive FE lock if there is multiple shared FEs */
-		if (adap->fe_adap[1].fe)
-			adap->dvb_adap.mfe_shared = 1;
-
-		d->num_adapters_initialized++;
-		d->state |= DVB_USB_STATE_DVB;
-	}
-
-	/*
-	 * when reloading the driver w/o replugging the device
-	 * sometimes a timeout occures, this helps
-	 */
-	if (d->props.generic_bulk_ctrl_endpoint != 0) {
-		usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
-		usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
-	}
-
-	return 0;
-}
-
-static int dvb_usb_adapter_exit(struct dvb_usb_device *d)
-{
-	int n;
-
-	for (n = 0; n < d->num_adapters_initialized; n++) {
-		dvb_usb_adapter_frontend_exit(&d->adapter[n]);
-		dvb_usb_adapter_dvb_exit(&d->adapter[n]);
-		dvb_usb_adapter_stream_exit(&d->adapter[n]);
-		kfree(d->adapter[n].priv);
-	}
-	d->num_adapters_initialized = 0;
-	d->state &= ~DVB_USB_STATE_DVB;
-	return 0;
-}
-
-
-/* general initialization functions */
-static int dvb_usb_exit(struct dvb_usb_device *d)
-{
-	deb_info("state before exiting everything: %x\n", d->state);
-	dvb_usb_remote_exit(d);
-	dvb_usb_adapter_exit(d);
-	dvb_usb_i2c_exit(d);
-	deb_info("state should be zero now: %x\n", d->state);
-	d->state = DVB_USB_STATE_INIT;
-	kfree(d->priv);
-	kfree(d);
-	return 0;
-}
-
-static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums)
-{
-	int ret = 0;
-
-	mutex_init(&d->usb_mutex);
-	mutex_init(&d->i2c_mutex);
-
-	d->state = DVB_USB_STATE_INIT;
-
-	if (d->props.size_of_priv > 0) {
-		d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL);
-		if (d->priv == NULL) {
-			err("no memory for priv in 'struct dvb_usb_device'");
-			return -ENOMEM;
-		}
-	}
-
-	/* check the capabilities and set appropriate variables */
-	dvb_usb_device_power_ctrl(d, 1);
-
-	if ((ret = dvb_usb_i2c_init(d)) ||
-		(ret = dvb_usb_adapter_init(d, adapter_nums))) {
-		dvb_usb_exit(d);
-		return ret;
-	}
-
-	if ((ret = dvb_usb_remote_init(d)))
-		err("could not initialize remote control.");
-
-	dvb_usb_device_power_ctrl(d, 0);
-
-	return 0;
-}
-
-/* determine the name and the state of the just found USB device */
-static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *udev, struct dvb_usb_device_properties *props, int *cold)
-{
-	int i, j;
-	struct dvb_usb_device_description *desc = NULL;
-
-	*cold = -1;
-
-	for (i = 0; i < props->num_device_descs; i++) {
-
-		for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) {
-			deb_info("check for cold %x %x\n", props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct);
-			if (props->devices[i].cold_ids[j]->idVendor  == le16_to_cpu(udev->descriptor.idVendor) &&
-				props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
-				*cold = 1;
-				desc = &props->devices[i];
-				break;
-			}
-		}
-
-		if (desc != NULL)
-			break;
-
-		for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) {
-			deb_info("check for warm %x %x\n", props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct);
-			if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
-				props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
-				*cold = 0;
-				desc = &props->devices[i];
-				break;
-			}
-		}
-	}
-
-	if (desc != NULL && props->identify_state != NULL)
-		props->identify_state(udev, props, &desc, cold);
-
-	return desc;
-}
-
-int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	if (onoff)
-		d->powered++;
-	else
-		d->powered--;
-
-	if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */
-		deb_info("power control: %d\n", onoff);
-		if (d->props.power_ctrl)
-			return d->props.power_ctrl(d, onoff);
-	}
-	return 0;
-}
-
-/*
- * USB
- */
-int dvb_usb_device_init(struct usb_interface *intf,
-			struct dvb_usb_device_properties *props,
-			struct module *owner, struct dvb_usb_device **du,
-			short *adapter_nums)
-{
-	struct usb_device *udev = interface_to_usbdev(intf);
-	struct dvb_usb_device *d = NULL;
-	struct dvb_usb_device_description *desc = NULL;
-
-	int ret = -ENOMEM, cold = 0;
-
-	if (du != NULL)
-		*du = NULL;
-
-	if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) {
-		deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
-		return -ENODEV;
-	}
-
-	if (cold) {
-		info("found a '%s' in cold state, will try to load a firmware", desc->name);
-		ret = dvb_usb_download_firmware(udev, props);
-		if (!props->no_reconnect || ret != 0)
-			return ret;
-	}
-
-	info("found a '%s' in warm state.", desc->name);
-	d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL);
-	if (d == NULL) {
-		err("no memory for 'struct dvb_usb_device'");
-		return -ENOMEM;
-	}
-
-	d->udev = udev;
-	memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties));
-	d->desc = desc;
-	d->owner = owner;
-
-	usb_set_intfdata(intf, d);
-
-	if (du != NULL)
-		*du = d;
-
-	ret = dvb_usb_init(d, adapter_nums);
-
-	if (ret == 0)
-		info("%s successfully initialized and connected.", desc->name);
-	else
-		info("%s error while loading driver (%d)", desc->name, ret);
-	return ret;
-}
-EXPORT_SYMBOL(dvb_usb_device_init);
-
-void dvb_usb_device_exit(struct usb_interface *intf)
-{
-	struct dvb_usb_device *d = usb_get_intfdata(intf);
-	const char *name = "generic DVB-USB module";
-
-	usb_set_intfdata(intf, NULL);
-	if (d != NULL && d->desc != NULL) {
-		name = d->desc->name;
-		dvb_usb_exit(d);
-	}
-	info("%s successfully deinitialized and disconnected.", name);
-
-}
-EXPORT_SYMBOL(dvb_usb_device_exit);
-
-MODULE_VERSION("1.0");
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
deleted file mode 100644
index 41bacff..0000000
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ /dev/null
@@ -1,391 +0,0 @@
-/* dvb-usb-remote.c is part of the DVB USB library.
- *
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
- * see dvb-usb-init.c for copyright information.
- *
- * This file contains functions for initializing the input-device and for handling remote-control-queries.
- */
-#include "dvb-usb-common.h"
-#include <linux/usb/input.h>
-
-static unsigned int
-legacy_dvb_usb_get_keymap_index(const struct input_keymap_entry *ke,
-				struct rc_map_table *keymap,
-				unsigned int keymap_size)
-{
-	unsigned int index;
-	unsigned int scancode;
-
-	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
-		index = ke->index;
-	} else {
-		if (input_scancode_to_scalar(ke, &scancode))
-			return keymap_size;
-
-		/* See if we can match the raw key code. */
-		for (index = 0; index < keymap_size; index++)
-			if (keymap[index].scancode == scancode)
-				break;
-
-		/* See if there is an unused hole in the map */
-		if (index >= keymap_size) {
-			for (index = 0; index < keymap_size; index++) {
-				if (keymap[index].keycode == KEY_RESERVED ||
-				    keymap[index].keycode == KEY_UNKNOWN) {
-					break;
-				}
-			}
-		}
-	}
-
-	return index;
-}
-
-static int legacy_dvb_usb_getkeycode(struct input_dev *dev,
-				     struct input_keymap_entry *ke)
-{
-	struct dvb_usb_device *d = input_get_drvdata(dev);
-	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
-	unsigned int keymap_size = d->props.rc.legacy.rc_map_size;
-	unsigned int index;
-
-	index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);
-	if (index >= keymap_size)
-		return -EINVAL;
-
-	ke->keycode = keymap[index].keycode;
-	if (ke->keycode == KEY_UNKNOWN)
-		ke->keycode = KEY_RESERVED;
-	ke->len = sizeof(keymap[index].scancode);
-	memcpy(&ke->scancode, &keymap[index].scancode, ke->len);
-	ke->index = index;
-
-	return 0;
-}
-
-static int legacy_dvb_usb_setkeycode(struct input_dev *dev,
-				     const struct input_keymap_entry *ke,
-				     unsigned int *old_keycode)
-{
-	struct dvb_usb_device *d = input_get_drvdata(dev);
-	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
-	unsigned int keymap_size = d->props.rc.legacy.rc_map_size;
-	unsigned int index;
-
-	index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);
-	/*
-	 * FIXME: Currently, it is not possible to increase the size of
-	 * scancode table. For it to happen, one possibility
-	 * would be to allocate a table with key_map_size + 1,
-	 * copying data, appending the new key on it, and freeing
-	 * the old one - or maybe just allocating some spare space
-	 */
-	if (index >= keymap_size)
-		return -EINVAL;
-
-	*old_keycode = keymap[index].keycode;
-	keymap->keycode = ke->keycode;
-	__set_bit(ke->keycode, dev->keybit);
-
-	if (*old_keycode != KEY_RESERVED) {
-		__clear_bit(*old_keycode, dev->keybit);
-		for (index = 0; index < keymap_size; index++) {
-			if (keymap[index].keycode == *old_keycode) {
-				__set_bit(*old_keycode, dev->keybit);
-				break;
-			}
-		}
-	}
-
-	return 0;
-}
-
-/* Remote-control poll function - called every dib->rc_query_interval ms to see
- * whether the remote control has received anything.
- *
- * TODO: Fix the repeat rate of the input device.
- */
-static void legacy_dvb_usb_read_remote_control(struct work_struct *work)
-{
-	struct dvb_usb_device *d =
-		container_of(work, struct dvb_usb_device, rc_query_work.work);
-	u32 event;
-	int state;
-
-	/* TODO: need a lock here.  We can simply skip checking for the remote control
-	   if we're busy. */
-
-	/* when the parameter has been set to 1 via sysfs while the driver was running */
-	if (dvb_usb_disable_rc_polling)
-		return;
-
-	if (d->props.rc.legacy.rc_query(d,&event,&state)) {
-		err("error while querying for an remote control event.");
-		goto schedule;
-	}
-
-
-	switch (state) {
-		case REMOTE_NO_KEY_PRESSED:
-			break;
-		case REMOTE_KEY_PRESSED:
-			deb_rc("key pressed\n");
-			d->last_event = event;
-		case REMOTE_KEY_REPEAT:
-			deb_rc("key repeated\n");
-			input_event(d->input_dev, EV_KEY, event, 1);
-			input_sync(d->input_dev);
-			input_event(d->input_dev, EV_KEY, d->last_event, 0);
-			input_sync(d->input_dev);
-			break;
-		default:
-			break;
-	}
-
-/* improved repeat handling ???
-	switch (state) {
-		case REMOTE_NO_KEY_PRESSED:
-			deb_rc("NO KEY PRESSED\n");
-			if (d->last_state != REMOTE_NO_KEY_PRESSED) {
-				deb_rc("releasing event %d\n",d->last_event);
-				input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
-				input_sync(d->rc_input_dev);
-			}
-			d->last_state = REMOTE_NO_KEY_PRESSED;
-			d->last_event = 0;
-			break;
-		case REMOTE_KEY_PRESSED:
-			deb_rc("KEY PRESSED\n");
-			deb_rc("pressing event %d\n",event);
-
-			input_event(d->rc_input_dev, EV_KEY, event, 1);
-			input_sync(d->rc_input_dev);
-
-			d->last_event = event;
-			d->last_state = REMOTE_KEY_PRESSED;
-			break;
-		case REMOTE_KEY_REPEAT:
-			deb_rc("KEY_REPEAT\n");
-			if (d->last_state != REMOTE_NO_KEY_PRESSED) {
-				deb_rc("repeating event %d\n",d->last_event);
-				input_event(d->rc_input_dev, EV_KEY, d->last_event, 2);
-				input_sync(d->rc_input_dev);
-				d->last_state = REMOTE_KEY_REPEAT;
-			}
-		default:
-			break;
-	}
-*/
-
-schedule:
-	schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval));
-}
-
-static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d)
-{
-	int i, err, rc_interval;
-	struct input_dev *input_dev;
-
-	input_dev = input_allocate_device();
-	if (!input_dev)
-		return -ENOMEM;
-
-	input_dev->evbit[0] = BIT_MASK(EV_KEY);
-	input_dev->name = "IR-receiver inside an USB DVB receiver";
-	input_dev->phys = d->rc_phys;
-	usb_to_input_id(d->udev, &input_dev->id);
-	input_dev->dev.parent = &d->udev->dev;
-	d->input_dev = input_dev;
-	d->rc_dev = NULL;
-
-	input_dev->getkeycode = legacy_dvb_usb_getkeycode;
-	input_dev->setkeycode = legacy_dvb_usb_setkeycode;
-
-	/* set the bits for the keys */
-	deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size);
-	for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
-		deb_rc("setting bit for event %d item %d\n",
-			d->props.rc.legacy.rc_map_table[i].keycode, i);
-		set_bit(d->props.rc.legacy.rc_map_table[i].keycode, input_dev->keybit);
-	}
-
-	/* setting these two values to non-zero, we have to manage key repeats */
-	input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval;
-	input_dev->rep[REP_DELAY]  = d->props.rc.legacy.rc_interval + 150;
-
-	input_set_drvdata(input_dev, d);
-
-	err = input_register_device(input_dev);
-	if (err)
-		input_free_device(input_dev);
-
-	rc_interval = d->props.rc.legacy.rc_interval;
-
-	INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control);
-
-	info("schedule remote query interval to %d msecs.", rc_interval);
-	schedule_delayed_work(&d->rc_query_work,
-			      msecs_to_jiffies(rc_interval));
-
-	d->state |= DVB_USB_STATE_REMOTE;
-
-	return err;
-}
-
-/* Remote-control poll function - called every dib->rc_query_interval ms to see
- * whether the remote control has received anything.
- *
- * TODO: Fix the repeat rate of the input device.
- */
-static void dvb_usb_read_remote_control(struct work_struct *work)
-{
-	struct dvb_usb_device *d =
-		container_of(work, struct dvb_usb_device, rc_query_work.work);
-	int err;
-
-	/* TODO: need a lock here.  We can simply skip checking for the remote control
-	   if we're busy. */
-
-	/* when the parameter has been set to 1 via sysfs while the
-	 * driver was running, or when bulk mode is enabled after IR init
-	 */
-	if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode)
-		return;
-
-	err = d->props.rc.core.rc_query(d);
-	if (err)
-		err("error %d while querying for an remote control event.", err);
-
-	schedule_delayed_work(&d->rc_query_work,
-			      msecs_to_jiffies(d->props.rc.core.rc_interval));
-}
-
-static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
-{
-	int err, rc_interval;
-	struct rc_dev *dev;
-
-	dev = rc_allocate_device();
-	if (!dev)
-		return -ENOMEM;
-
-	dev->driver_name = d->props.rc.core.module_name;
-	dev->map_name = d->props.rc.core.rc_codes;
-	dev->change_protocol = d->props.rc.core.change_protocol;
-	dev->allowed_protos = d->props.rc.core.allowed_protos;
-	dev->driver_type = d->props.rc.core.driver_type;
-	usb_to_input_id(d->udev, &dev->input_id);
-	dev->input_name = "IR-receiver inside an USB DVB receiver";
-	dev->input_phys = d->rc_phys;
-	dev->dev.parent = &d->udev->dev;
-	dev->priv = d;
-
-	err = rc_register_device(dev);
-	if (err < 0) {
-		rc_free_device(dev);
-		return err;
-	}
-
-	d->input_dev = NULL;
-	d->rc_dev = dev;
-
-	if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode)
-		return 0;
-
-	/* Polling mode - initialize a work queue for handling it */
-	INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);
-
-	rc_interval = d->props.rc.core.rc_interval;
-
-	info("schedule remote query interval to %d msecs.", rc_interval);
-	schedule_delayed_work(&d->rc_query_work,
-			      msecs_to_jiffies(rc_interval));
-
-	return 0;
-}
-
-int dvb_usb_remote_init(struct dvb_usb_device *d)
-{
-	int err;
-
-	if (dvb_usb_disable_rc_polling)
-		return 0;
-
-	if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query)
-		d->props.rc.mode = DVB_RC_LEGACY;
-	else if (d->props.rc.core.rc_codes)
-		d->props.rc.mode = DVB_RC_CORE;
-	else
-		return 0;
-
-	usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
-	strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
-
-	/* Start the remote-control polling. */
-	if (d->props.rc.legacy.rc_interval < 40)
-		d->props.rc.legacy.rc_interval = 100; /* default */
-
-	if (d->props.rc.mode == DVB_RC_LEGACY)
-		err = legacy_dvb_usb_remote_init(d);
-	else
-		err = rc_core_dvb_usb_remote_init(d);
-	if (err)
-		return err;
-
-	d->state |= DVB_USB_STATE_REMOTE;
-
-	return 0;
-}
-
-int dvb_usb_remote_exit(struct dvb_usb_device *d)
-{
-	if (d->state & DVB_USB_STATE_REMOTE) {
-		cancel_delayed_work_sync(&d->rc_query_work);
-		if (d->props.rc.mode == DVB_RC_LEGACY)
-			input_unregister_device(d->input_dev);
-		else
-			rc_unregister_device(d->rc_dev);
-	}
-	d->state &= ~DVB_USB_STATE_REMOTE;
-	return 0;
-}
-
-#define DVB_USB_RC_NEC_EMPTY           0x00
-#define DVB_USB_RC_NEC_KEY_PRESSED     0x01
-#define DVB_USB_RC_NEC_KEY_REPEATED    0x02
-int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
-		u8 keybuf[5], u32 *event, int *state)
-{
-	int i;
-	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
-	*event = 0;
-	*state = REMOTE_NO_KEY_PRESSED;
-	switch (keybuf[0]) {
-		case DVB_USB_RC_NEC_EMPTY:
-			break;
-		case DVB_USB_RC_NEC_KEY_PRESSED:
-			if ((u8) ~keybuf[1] != keybuf[2] ||
-				(u8) ~keybuf[3] != keybuf[4]) {
-				deb_err("remote control checksum failed.\n");
-				break;
-			}
-			/* See if we can match the raw key code. */
-			for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
-				if (rc5_custom(&keymap[i]) == keybuf[1] &&
-					rc5_data(&keymap[i]) == keybuf[3]) {
-					*event = keymap[i].keycode;
-					*state = REMOTE_KEY_PRESSED;
-					return 0;
-				}
-			deb_err("key mapping failed - no appropriate key found in keymapping\n");
-			break;
-		case DVB_USB_RC_NEC_KEY_REPEATED:
-			*state = REMOTE_KEY_REPEAT;
-			break;
-		default:
-			deb_err("unknown type of remote status: %d\n",keybuf[0]);
-			break;
-	}
-	return 0;
-}
-EXPORT_SYMBOL(dvb_usb_nec_rc_key_to_event);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
deleted file mode 100644
index 5c8f651..0000000
--- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/* dvb-usb-urb.c is part of the DVB USB library.
- *
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
- * see dvb-usb-init.c for copyright information.
- *
- * This file keeps functions for initializing and handling the
- * USB and URB stuff.
- */
-#include "dvb-usb-common.h"
-
-int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
-	u16 rlen, int delay_ms)
-{
-	int actlen,ret = -ENOMEM;
-
-	if (!d || wbuf == NULL || wlen == 0)
-		return -EINVAL;
-
-	if (d->props.generic_bulk_ctrl_endpoint == 0) {
-		err("endpoint for generic control not specified.");
-		return -EINVAL;
-	}
-
-	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
-		return ret;
-
-	deb_xfer(">>> ");
-	debug_dump(wbuf,wlen,deb_xfer);
-
-	ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev,
-			d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen,
-			2000);
-
-	if (ret)
-		err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
-	else
-		ret = actlen != wlen ? -1 : 0;
-
-	/* an answer is expected, and no error before */
-	if (!ret && rbuf && rlen) {
-		if (delay_ms)
-			msleep(delay_ms);
-
-		ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev,
-				d->props.generic_bulk_ctrl_endpoint_response ?
-				d->props.generic_bulk_ctrl_endpoint_response :
-				d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen,
-				2000);
-
-		if (ret)
-			err("recv bulk message failed: %d",ret);
-		else {
-			deb_xfer("<<< ");
-			debug_dump(rbuf,actlen,deb_xfer);
-		}
-	}
-
-	mutex_unlock(&d->usb_mutex);
-	return ret;
-}
-EXPORT_SYMBOL(dvb_usb_generic_rw);
-
-int dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len)
-{
-	return dvb_usb_generic_rw(d,buf,len,NULL,0,0);
-}
-EXPORT_SYMBOL(dvb_usb_generic_write);
-
-static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, size_t length)
-{
-	struct dvb_usb_adapter *adap = stream->user_priv;
-	if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
-		dvb_dmx_swfilter(&adap->demux, buffer, length);
-}
-
-static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer, size_t length)
-{
-	struct dvb_usb_adapter *adap = stream->user_priv;
-	if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
-		dvb_dmx_swfilter_204(&adap->demux, buffer, length);
-}
-
-static void dvb_usb_data_complete_raw(struct usb_data_stream *stream,
-				      u8 *buffer, size_t length)
-{
-	struct dvb_usb_adapter *adap = stream->user_priv;
-	if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
-		dvb_dmx_swfilter_raw(&adap->demux, buffer, length);
-}
-
-int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap)
-{
-	int i, ret = 0;
-	for (i = 0; i < adap->props.num_frontends; i++) {
-
-		adap->fe_adap[i].stream.udev      = adap->dev->udev;
-		if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS)
-			adap->fe_adap[i].stream.complete =
-				dvb_usb_data_complete_204;
-		else
-		if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD)
-			adap->fe_adap[i].stream.complete =
-				dvb_usb_data_complete_raw;
-		else
-		adap->fe_adap[i].stream.complete  = dvb_usb_data_complete;
-		adap->fe_adap[i].stream.user_priv = adap;
-		ret = usb_urb_init(&adap->fe_adap[i].stream,
-				   &adap->props.fe[i].stream);
-		if (ret < 0)
-			break;
-	}
-	return ret;
-}
-
-int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap)
-{
-	int i;
-	for (i = 0; i < adap->props.num_frontends; i++)
-		usb_urb_exit(&adap->fe_adap[i].stream);
-	return 0;
-}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
deleted file mode 100644
index 99f9440..0000000
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ /dev/null
@@ -1,485 +0,0 @@
-/* dvb-usb.h is part of the DVB USB library.
- *
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
- * see dvb-usb-init.c for copyright information.
- *
- * the headerfile, all dvb-usb-drivers have to include.
- *
- * TODO: clean-up the structures for unused fields and update the comments
- */
-#ifndef __DVB_USB_H__
-#define __DVB_USB_H__
-
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/firmware.h>
-#include <linux/mutex.h>
-#include <media/rc-core.h>
-
-#include "dvb_frontend.h"
-#include "dvb_demux.h"
-#include "dvb_net.h"
-#include "dmxdev.h"
-
-#include "dvb-pll.h"
-
-#include "dvb-usb-ids.h"
-
-/* debug */
-#ifdef CONFIG_DVB_USB_DEBUG
-#define dprintk(var,level,args...) \
-	    do { if ((var & level)) { printk(args); } } while (0)
-
-#define debug_dump(b,l,func) {\
-	int loop_; \
-	for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \
-	func("\n");\
-}
-#define DVB_USB_DEBUG_STATUS
-#else
-#define dprintk(args...)
-#define debug_dump(b,l,func)
-
-#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)"
-
-#endif
-
-/* generic log methods - taken from usb.h */
-#ifndef DVB_USB_LOG_PREFIX
- #define DVB_USB_LOG_PREFIX "dvb-usb (please define a log prefix)"
-#endif
-
-#undef err
-#define err(format, arg...)  printk(KERN_ERR     DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
-#undef info
-#define info(format, arg...) printk(KERN_INFO    DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
-#undef warn
-#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
-
-/**
- * struct dvb_usb_device_description - name and its according USB IDs
- * @name: real name of the box, regardless which DVB USB device class is in use
- * @cold_ids: array of struct usb_device_id which describe the device in
- *  pre-firmware state
- * @warm_ids: array of struct usb_device_id which describe the device in
- *  post-firmware state
- *
- * Each DVB USB device class can have one or more actual devices, this struct
- * assigns a name to it.
- */
-struct dvb_usb_device_description {
-	const char *name;
-
-#define DVB_USB_ID_MAX_NUM 15
-	struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM];
-	struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM];
-};
-
-static inline u8 rc5_custom(struct rc_map_table *key)
-{
-	return (key->scancode >> 8) & 0xff;
-}
-
-static inline u8 rc5_data(struct rc_map_table *key)
-{
-	return key->scancode & 0xff;
-}
-
-static inline u16 rc5_scan(struct rc_map_table *key)
-{
-	return key->scancode & 0xffff;
-}
-
-struct dvb_usb_device;
-struct dvb_usb_adapter;
-struct usb_data_stream;
-
-/**
- * Properties of USB streaming - TODO this structure should be somewhere else
- * describes the kind of USB transfer used for data-streaming.
- *  (BULK or ISOC)
- */
-struct usb_data_stream_properties {
-#define USB_BULK  1
-#define USB_ISOC  2
-	int type;
-	int count;
-	int endpoint;
-
-	union {
-		struct {
-			int buffersize; /* per URB */
-		} bulk;
-		struct {
-			int framesperurb;
-			int framesize;
-			int interval;
-		} isoc;
-	} u;
-};
-
-/**
- * struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter.
- *    A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device.
- * @caps: capabilities of the DVB USB device.
- * @pid_filter_count: number of PID filter position in the optional hardware
- *  PID-filter.
- * @num_frontends: number of frontends of the DVB USB adapter.
- * @frontend_ctrl: called to power on/off active frontend.
- * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the
- *  device (not URB submitting/killing).
- * @pid_filter_ctrl: called to en/disable the PID filter, if any.
- * @pid_filter: called to set/unset a PID for filtering.
- * @frontend_attach: called to attach the possible frontends (fill fe-field
- *  of struct dvb_usb_device).
- * @tuner_attach: called to attach the correct tuner and to fill pll_addr,
- *  pll_desc and pll_init_buf of struct dvb_usb_device).
- * @stream: configuration of the USB streaming
- */
-struct dvb_usb_adapter_fe_properties {
-#define DVB_USB_ADAP_HAS_PID_FILTER               0x01
-#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02
-#define DVB_USB_ADAP_NEED_PID_FILTERING           0x04
-#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS         0x08
-#define DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD         0x10
-	int caps;
-	int pid_filter_count;
-
-	int (*streaming_ctrl)  (struct dvb_usb_adapter *, int);
-	int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int);
-	int (*pid_filter)      (struct dvb_usb_adapter *, int, u16, int);
-
-	int (*frontend_attach) (struct dvb_usb_adapter *);
-	int (*tuner_attach)    (struct dvb_usb_adapter *);
-
-	struct usb_data_stream_properties stream;
-
-	int size_of_priv;
-};
-
-#define MAX_NO_OF_FE_PER_ADAP 3
-struct dvb_usb_adapter_properties {
-	int size_of_priv;
-
-	int (*frontend_ctrl)   (struct dvb_frontend *, int);
-	int (*fe_ioctl_override) (struct dvb_frontend *,
-				  unsigned int, void *, unsigned int);
-
-	int num_frontends;
-	struct dvb_usb_adapter_fe_properties fe[MAX_NO_OF_FE_PER_ADAP];
-};
-
-/**
- * struct dvb_rc_legacy - old properties of remote controller
- * @rc_map_table: a hard-wired array of struct rc_map_table (NULL to disable
- *  remote control handling).
- * @rc_map_size: number of items in @rc_map_table.
- * @rc_query: called to query an event event.
- * @rc_interval: time in ms between two queries.
- */
-struct dvb_rc_legacy {
-/* remote control properties */
-#define REMOTE_NO_KEY_PRESSED      0x00
-#define REMOTE_KEY_PRESSED         0x01
-#define REMOTE_KEY_REPEAT          0x02
-	struct rc_map_table  *rc_map_table;
-	int rc_map_size;
-	int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
-	int rc_interval;
-};
-
-/**
- * struct dvb_rc properties of remote controller, using rc-core
- * @rc_codes: name of rc codes table
- * @protocol: type of protocol(s) currently used by the driver
- * @allowed_protos: protocol(s) supported by the driver
- * @driver_type: Used to point if a device supports raw mode
- * @change_protocol: callback to change protocol
- * @rc_query: called to query an event event.
- * @rc_interval: time in ms between two queries.
- * @bulk_mode: device supports bulk mode for RC (disable polling mode)
- */
-struct dvb_rc {
-	char *rc_codes;
-	u64 protocol;
-	u64 allowed_protos;
-	enum rc_driver_type driver_type;
-	int (*change_protocol)(struct rc_dev *dev, u64 rc_type);
-	char *module_name;
-	int (*rc_query) (struct dvb_usb_device *d);
-	int rc_interval;
-	bool bulk_mode;				/* uses bulk mode */
-};
-
-/**
- * enum dvb_usb_mode - Specifies if it is using a legacy driver or a new one
- *		       based on rc-core
- * This is initialized/used only inside dvb-usb-remote.c.
- * It shouldn't be set by the drivers.
- */
-enum dvb_usb_mode {
-	DVB_RC_LEGACY,
-	DVB_RC_CORE,
-};
-
-/**
- * struct dvb_usb_device_properties - properties of a dvb-usb-device
- * @usb_ctrl: which USB device-side controller is in use. Needed for firmware
- *  download.
- * @firmware: name of the firmware file.
- * @download_firmware: called to download the firmware when the usb_ctrl is
- *  DEVICE_SPECIFIC.
- * @no_reconnect: device doesn't do a reconnect after downloading the firmware,
- *  so do the warm initialization right after it
- *
- * @size_of_priv: how many bytes shall be allocated for the private field
- *  of struct dvb_usb_device.
- *
- * @power_ctrl: called to enable/disable power of the device.
- * @read_mac_address: called to read the MAC address of the device.
- * @identify_state: called to determine the state (cold or warm), when it
- *  is not distinguishable by the USB IDs.
- *
- * @rc: remote controller properties
- *
- * @i2c_algo: i2c_algorithm if the device has I2CoverUSB.
- *
- * @generic_bulk_ctrl_endpoint: most of the DVB USB devices have a generic
- *  endpoint which received control messages with bulk transfers. When this
- *  is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write-
- *  helper functions.
- *
- * @generic_bulk_ctrl_endpoint_response: some DVB USB devices use a separate
- *  endpoint for responses to control messages sent with bulk transfers via
- *  the generic_bulk_ctrl_endpoint. When this is non-zero, this will be used
- *  instead of the generic_bulk_ctrl_endpoint when reading usb responses in
- *  the dvb_usb_generic_rw helper function.
- *
- * @num_device_descs: number of struct dvb_usb_device_description in @devices
- * @devices: array of struct dvb_usb_device_description compatibles with these
- *  properties.
- */
-#define MAX_NO_OF_ADAPTER_PER_DEVICE 2
-struct dvb_usb_device_properties {
-
-#define DVB_USB_IS_AN_I2C_ADAPTER            0x01
-	int caps;
-
-#define DEVICE_SPECIFIC 0
-#define CYPRESS_AN2135  1
-#define CYPRESS_AN2235  2
-#define CYPRESS_FX2     3
-	int        usb_ctrl;
-	int        (*download_firmware) (struct usb_device *, const struct firmware *);
-	const char *firmware;
-	int        no_reconnect;
-
-	int size_of_priv;
-
-	int num_adapters;
-	struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
-
-	int (*power_ctrl)       (struct dvb_usb_device *, int);
-	int (*read_mac_address) (struct dvb_usb_device *, u8 []);
-	int (*identify_state)   (struct usb_device *, struct dvb_usb_device_properties *,
-			struct dvb_usb_device_description **, int *);
-
-	struct {
-		enum dvb_usb_mode mode;	/* Drivers shouldn't touch on it */
-		struct dvb_rc_legacy legacy;
-		struct dvb_rc core;
-	} rc;
-
-	struct i2c_algorithm *i2c_algo;
-
-	int generic_bulk_ctrl_endpoint;
-	int generic_bulk_ctrl_endpoint_response;
-
-	int num_device_descs;
-	struct dvb_usb_device_description devices[12];
-};
-
-/**
- * struct usb_data_stream - generic object of an USB stream
- * @buf_num: number of buffer allocated.
- * @buf_size: size of each buffer in buf_list.
- * @buf_list: array containing all allocate buffers for streaming.
- * @dma_addr: list of dma_addr_t for each buffer in buf_list.
- *
- * @urbs_initialized: number of URBs initialized.
- * @urbs_submitted: number of URBs submitted.
- */
-#define MAX_NO_URBS_FOR_DATA_STREAM 10
-struct usb_data_stream {
-	struct usb_device                 *udev;
-	struct usb_data_stream_properties  props;
-
-#define USB_STATE_INIT    0x00
-#define USB_STATE_URB_BUF 0x01
-	int state;
-
-	void (*complete) (struct usb_data_stream *, u8 *, size_t);
-
-	struct urb    *urb_list[MAX_NO_URBS_FOR_DATA_STREAM];
-	int            buf_num;
-	unsigned long  buf_size;
-	u8            *buf_list[MAX_NO_URBS_FOR_DATA_STREAM];
-	dma_addr_t     dma_addr[MAX_NO_URBS_FOR_DATA_STREAM];
-
-	int urbs_initialized;
-	int urbs_submitted;
-
-	void *user_priv;
-};
-
-/**
- * struct dvb_usb_adapter - a DVB adapter on a USB device
- * @id: index of this adapter (starting with 0).
- *
- * @feedcount: number of reqested feeds (used for streaming-activation)
- * @pid_filtering: is hardware pid_filtering used or not.
- *
- * @pll_addr: I2C address of the tuner for programming
- * @pll_init: array containing the initialization buffer
- * @pll_desc: pointer to the appropriate struct dvb_pll_desc
- * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board
- *
- * @dvb_adap: device's dvb_adapter.
- * @dmxdev: device's dmxdev.
- * @demux: device's software demuxer.
- * @dvb_net: device's dvb_net interfaces.
- * @dvb_frontend: device's frontend.
- * @max_feed_count: how many feeds can be handled simultaneously by this
- *  device
- *
- * @fe_init:  rerouted frontend-init (wakeup) function.
- * @fe_sleep: rerouted frontend-sleep function.
- *
- * @stream: the usb data stream.
- */
-struct dvb_usb_fe_adapter {
-	struct dvb_frontend *fe;
-
-	int (*fe_init)  (struct dvb_frontend *);
-	int (*fe_sleep) (struct dvb_frontend *);
-
-	struct usb_data_stream stream;
-
-	int pid_filtering;
-	int max_feed_count;
-
-	void *priv;
-};
-
-struct dvb_usb_adapter {
-	struct dvb_usb_device *dev;
-	struct dvb_usb_adapter_properties props;
-
-#define DVB_USB_ADAP_STATE_INIT 0x000
-#define DVB_USB_ADAP_STATE_DVB  0x001
-	int state;
-
-	u8  id;
-
-	int feedcount;
-
-	/* dvb */
-	struct dvb_adapter   dvb_adap;
-	struct dmxdev        dmxdev;
-	struct dvb_demux     demux;
-	struct dvb_net       dvb_net;
-
-	struct dvb_usb_fe_adapter fe_adap[MAX_NO_OF_FE_PER_ADAP];
-	int active_fe;
-	int num_frontends_initialized;
-
-	void *priv;
-};
-
-/**
- * struct dvb_usb_device - object of a DVB USB device
- * @props: copy of the struct dvb_usb_properties this device belongs to.
- * @desc: pointer to the device's struct dvb_usb_device_description.
- * @state: initialization and runtime state of the device.
- *
- * @powered: indicated whether the device is power or not.
- *  Powered is in/decremented for each call to modify the state.
- * @udev: pointer to the device's struct usb_device.
- *
- * @usb_mutex: semaphore of USB control messages (reading needs two messages)
- * @i2c_mutex: semaphore for i2c-transfers
- *
- * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
- *
- * @rc_dev: rc device for the remote control (rc-core mode)
- * @input_dev: input device for the remote control (legacy mode)
- * @rc_query_work: struct work_struct frequent rc queries
- * @last_event: last triggered event
- * @last_state: last state (no, pressed, repeat)
- * @owner: owner of the dvb_adapter
- * @priv: private data of the actual driver (allocate by dvb-usb, size defined
- *  in size_of_priv of dvb_usb_properties).
- */
-struct dvb_usb_device {
-	struct dvb_usb_device_properties props;
-	struct dvb_usb_device_description *desc;
-
-	struct usb_device *udev;
-
-#define DVB_USB_STATE_INIT        0x000
-#define DVB_USB_STATE_I2C         0x001
-#define DVB_USB_STATE_DVB         0x002
-#define DVB_USB_STATE_REMOTE      0x004
-	int state;
-
-	int powered;
-
-	/* locking */
-	struct mutex usb_mutex;
-
-	/* i2c */
-	struct mutex i2c_mutex;
-	struct i2c_adapter i2c_adap;
-
-	int                    num_adapters_initialized;
-	struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
-
-	/* remote control */
-	struct rc_dev *rc_dev;
-	struct input_dev *input_dev;
-	char rc_phys[64];
-	struct delayed_work rc_query_work;
-	u32 last_event;
-	int last_state;
-
-	struct module *owner;
-
-	void *priv;
-};
-
-extern int dvb_usb_device_init(struct usb_interface *,
-			       struct dvb_usb_device_properties *,
-			       struct module *, struct dvb_usb_device **,
-			       short *adapter_nums);
-extern void dvb_usb_device_exit(struct usb_interface *);
-
-/* the generic read/write method for device control */
-extern int dvb_usb_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16,int);
-extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16);
-
-/* commonly used remote control parsing */
-extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
-
-/* commonly used firmware download types and function */
-struct hexline {
-	u8 len;
-	u32 addr;
-	u8 type;
-	u8 data[255];
-	u8 chk;
-};
-extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type);
-extern int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos);
-
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
deleted file mode 100644
index 9382895..0000000
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ /dev/null
@@ -1,1951 +0,0 @@
-/* DVB USB framework compliant Linux driver for the
- *	DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
- *	TeVii S600, S630, S650, S660, S480,
- *	Prof 1100, 7500,
- *	Geniatech SU3000 Cards
- * Copyright (C) 2008-2011 Igor M. Liplianin (liplianin@me.by)
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "dw2102.h"
-#include "si21xx.h"
-#include "stv0299.h"
-#include "z0194a.h"
-#include "stv0288.h"
-#include "stb6000.h"
-#include "eds1547.h"
-#include "cx24116.h"
-#include "tda1002x.h"
-#include "mt312.h"
-#include "zl10039.h"
-#include "ds3000.h"
-#include "stv0900.h"
-#include "stv6110.h"
-#include "stb6100.h"
-#include "stb6100_proc.h"
-
-#ifndef USB_PID_DW2102
-#define USB_PID_DW2102 0x2102
-#endif
-
-#ifndef USB_PID_DW2104
-#define USB_PID_DW2104 0x2104
-#endif
-
-#ifndef USB_PID_DW3101
-#define USB_PID_DW3101 0x3101
-#endif
-
-#ifndef USB_PID_CINERGY_S
-#define USB_PID_CINERGY_S 0x0064
-#endif
-
-#ifndef USB_PID_TEVII_S630
-#define USB_PID_TEVII_S630 0xd630
-#endif
-
-#ifndef USB_PID_TEVII_S650
-#define USB_PID_TEVII_S650 0xd650
-#endif
-
-#ifndef USB_PID_TEVII_S660
-#define USB_PID_TEVII_S660 0xd660
-#endif
-
-#ifndef USB_PID_TEVII_S480_1
-#define USB_PID_TEVII_S480_1 0xd481
-#endif
-
-#ifndef USB_PID_TEVII_S480_2
-#define USB_PID_TEVII_S480_2 0xd482
-#endif
-
-#ifndef USB_PID_PROF_1100
-#define USB_PID_PROF_1100 0xb012
-#endif
-
-#define DW210X_READ_MSG 0
-#define DW210X_WRITE_MSG 1
-
-#define REG_1F_SYMBOLRATE_BYTE0 0x1f
-#define REG_20_SYMBOLRATE_BYTE1 0x20
-#define REG_21_SYMBOLRATE_BYTE2 0x21
-/* on my own*/
-#define DW2102_VOLTAGE_CTRL (0x1800)
-#define SU3000_STREAM_CTRL (0x1900)
-#define DW2102_RC_QUERY (0x1a00)
-#define DW2102_LED_CTRL (0x1b00)
-
-#define	err_str "did not find the firmware file. (%s) " \
-		"Please see linux/Documentation/dvb/ for more details " \
-		"on firmware-problems."
-
-struct rc_map_dvb_usb_table_table {
-	struct rc_map_table *rc_keys;
-	int rc_keys_size;
-};
-
-struct su3000_state {
-	u8 initialized;
-};
-
-struct s6x0_state {
-	int (*old_set_voltage)(struct dvb_frontend *f, fe_sec_voltage_t v);
-};
-
-/* debug */
-static int dvb_usb_dw2102_debug;
-module_param_named(debug, dvb_usb_dw2102_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))."
-						DVB_USB_DEBUG_STATUS);
-
-/* keymaps */
-static int ir_keymap;
-module_param_named(keymap, ir_keymap, int, 0644);
-MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs  ..."
-			" 256=none");
-
-/* demod probe */
-static int demod_probe = 1;
-module_param_named(demod, demod_probe, int, 0644);
-MODULE_PARM_DESC(demod, "demod to probe (1=cx24116 2=stv0903+stv6110 "
-			"4=stv0903+stb6100(or-able)).");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
-			u16 index, u8 * data, u16 len, int flags)
-{
-	int ret;
-	u8 *u8buf;
-	unsigned int pipe = (flags == DW210X_READ_MSG) ?
-				usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
-	u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
-
-	u8buf = kmalloc(len, GFP_KERNEL);
-	if (!u8buf)
-		return -ENOMEM;
-
-
-	if (flags == DW210X_WRITE_MSG)
-		memcpy(u8buf, data, len);
-	ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
-				value, index , u8buf, len, 2000);
-
-	if (flags == DW210X_READ_MSG)
-		memcpy(data, u8buf, len);
-
-	kfree(u8buf);
-	return ret;
-}
-
-/* I2C */
-static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-		int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int i = 0;
-	u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0};
-	u16 value;
-
-	if (!d)
-		return -ENODEV;
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	switch (num) {
-	case 2:
-		/* read stv0299 register */
-		value = msg[0].buf[0];/* register */
-		for (i = 0; i < msg[1].len; i++) {
-			dw210x_op_rw(d->udev, 0xb5, value + i, 0,
-					buf6, 2, DW210X_READ_MSG);
-			msg[1].buf[i] = buf6[0];
-		}
-		break;
-	case 1:
-		switch (msg[0].addr) {
-		case 0x68:
-			/* write to stv0299 register */
-			buf6[0] = 0x2a;
-			buf6[1] = msg[0].buf[0];
-			buf6[2] = msg[0].buf[1];
-			dw210x_op_rw(d->udev, 0xb2, 0, 0,
-					buf6, 3, DW210X_WRITE_MSG);
-			break;
-		case 0x60:
-			if (msg[0].flags == 0) {
-			/* write to tuner pll */
-				buf6[0] = 0x2c;
-				buf6[1] = 5;
-				buf6[2] = 0xc0;
-				buf6[3] = msg[0].buf[0];
-				buf6[4] = msg[0].buf[1];
-				buf6[5] = msg[0].buf[2];
-				buf6[6] = msg[0].buf[3];
-				dw210x_op_rw(d->udev, 0xb2, 0, 0,
-						buf6, 7, DW210X_WRITE_MSG);
-			} else {
-			/* read from tuner */
-				dw210x_op_rw(d->udev, 0xb5, 0, 0,
-						buf6, 1, DW210X_READ_MSG);
-				msg[0].buf[0] = buf6[0];
-			}
-			break;
-		case (DW2102_RC_QUERY):
-			dw210x_op_rw(d->udev, 0xb8, 0, 0,
-					buf6, 2, DW210X_READ_MSG);
-			msg[0].buf[0] = buf6[0];
-			msg[0].buf[1] = buf6[1];
-			break;
-		case (DW2102_VOLTAGE_CTRL):
-			buf6[0] = 0x30;
-			buf6[1] = msg[0].buf[0];
-			dw210x_op_rw(d->udev, 0xb2, 0, 0,
-					buf6, 2, DW210X_WRITE_MSG);
-			break;
-		}
-
-		break;
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return num;
-}
-
-static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
-						struct i2c_msg msg[], int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	u8 buf6[] = {0, 0, 0, 0, 0, 0, 0};
-
-	if (!d)
-		return -ENODEV;
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	switch (num) {
-	case 2:
-		/* read si2109 register by number */
-		buf6[0] = msg[0].addr << 1;
-		buf6[1] = msg[0].len;
-		buf6[2] = msg[0].buf[0];
-		dw210x_op_rw(d->udev, 0xc2, 0, 0,
-				buf6, msg[0].len + 2, DW210X_WRITE_MSG);
-		/* read si2109 register */
-		dw210x_op_rw(d->udev, 0xc3, 0xd0, 0,
-				buf6, msg[1].len + 2, DW210X_READ_MSG);
-		memcpy(msg[1].buf, buf6 + 2, msg[1].len);
-
-		break;
-	case 1:
-		switch (msg[0].addr) {
-		case 0x68:
-			/* write to si2109 register */
-			buf6[0] = msg[0].addr << 1;
-			buf6[1] = msg[0].len;
-			memcpy(buf6 + 2, msg[0].buf, msg[0].len);
-			dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6,
-					msg[0].len + 2, DW210X_WRITE_MSG);
-			break;
-		case(DW2102_RC_QUERY):
-			dw210x_op_rw(d->udev, 0xb8, 0, 0,
-					buf6, 2, DW210X_READ_MSG);
-			msg[0].buf[0] = buf6[0];
-			msg[0].buf[1] = buf6[1];
-			break;
-		case(DW2102_VOLTAGE_CTRL):
-			buf6[0] = 0x30;
-			buf6[1] = msg[0].buf[0];
-			dw210x_op_rw(d->udev, 0xb2, 0, 0,
-					buf6, 2, DW210X_WRITE_MSG);
-			break;
-		}
-		break;
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return num;
-}
-
-static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-
-	if (!d)
-		return -ENODEV;
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	switch (num) {
-	case 2: {
-		/* read */
-		/* first write first register number */
-		u8 ibuf[msg[1].len + 2], obuf[3];
-		obuf[0] = msg[0].addr << 1;
-		obuf[1] = msg[0].len;
-		obuf[2] = msg[0].buf[0];
-		dw210x_op_rw(d->udev, 0xc2, 0, 0,
-				obuf, msg[0].len + 2, DW210X_WRITE_MSG);
-		/* second read registers */
-		dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0,
-				ibuf, msg[1].len + 2, DW210X_READ_MSG);
-		memcpy(msg[1].buf, ibuf + 2, msg[1].len);
-
-		break;
-	}
-	case 1:
-		switch (msg[0].addr) {
-		case 0x68: {
-			/* write to register */
-			u8 obuf[msg[0].len + 2];
-			obuf[0] = msg[0].addr << 1;
-			obuf[1] = msg[0].len;
-			memcpy(obuf + 2, msg[0].buf, msg[0].len);
-			dw210x_op_rw(d->udev, 0xc2, 0, 0,
-					obuf, msg[0].len + 2, DW210X_WRITE_MSG);
-			break;
-		}
-		case 0x61: {
-			/* write to tuner */
-			u8 obuf[msg[0].len + 2];
-			obuf[0] = msg[0].addr << 1;
-			obuf[1] = msg[0].len;
-			memcpy(obuf + 2, msg[0].buf, msg[0].len);
-			dw210x_op_rw(d->udev, 0xc2, 0, 0,
-					obuf, msg[0].len + 2, DW210X_WRITE_MSG);
-			break;
-		}
-		case(DW2102_RC_QUERY): {
-			u8 ibuf[2];
-			dw210x_op_rw(d->udev, 0xb8, 0, 0,
-					ibuf, 2, DW210X_READ_MSG);
-			memcpy(msg[0].buf, ibuf , 2);
-			break;
-		}
-		case(DW2102_VOLTAGE_CTRL): {
-			u8 obuf[2];
-			obuf[0] = 0x30;
-			obuf[1] = msg[0].buf[0];
-			dw210x_op_rw(d->udev, 0xb2, 0, 0,
-					obuf, 2, DW210X_WRITE_MSG);
-			break;
-		}
-		}
-
-		break;
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return num;
-}
-
-static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int len, i, j;
-
-	if (!d)
-		return -ENODEV;
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	for (j = 0; j < num; j++) {
-		switch (msg[j].addr) {
-		case(DW2102_RC_QUERY): {
-			u8 ibuf[2];
-			dw210x_op_rw(d->udev, 0xb8, 0, 0,
-					ibuf, 2, DW210X_READ_MSG);
-			memcpy(msg[j].buf, ibuf , 2);
-			break;
-		}
-		case(DW2102_VOLTAGE_CTRL): {
-			u8 obuf[2];
-			obuf[0] = 0x30;
-			obuf[1] = msg[j].buf[0];
-			dw210x_op_rw(d->udev, 0xb2, 0, 0,
-					obuf, 2, DW210X_WRITE_MSG);
-			break;
-		}
-		/*case 0x55: cx24116
-		case 0x6a: stv0903
-		case 0x68: ds3000, stv0903
-		case 0x60: ts2020, stv6110, stb6100 */
-		default: {
-			if (msg[j].flags == I2C_M_RD) {
-				/* read registers */
-				u8  ibuf[msg[j].len + 2];
-				dw210x_op_rw(d->udev, 0xc3,
-						(msg[j].addr << 1) + 1, 0,
-						ibuf, msg[j].len + 2,
-						DW210X_READ_MSG);
-				memcpy(msg[j].buf, ibuf + 2, msg[j].len);
-			mdelay(10);
-			} else if (((msg[j].buf[0] == 0xb0) &&
-						(msg[j].addr == 0x68)) ||
-						((msg[j].buf[0] == 0xf7) &&
-						(msg[j].addr == 0x55))) {
-				/* write firmware */
-				u8 obuf[19];
-				obuf[0] = msg[j].addr << 1;
-				obuf[1] = (msg[j].len > 15 ? 17 : msg[j].len);
-				obuf[2] = msg[j].buf[0];
-				len = msg[j].len - 1;
-				i = 1;
-				do {
-					memcpy(obuf + 3, msg[j].buf + i,
-							(len > 16 ? 16 : len));
-					dw210x_op_rw(d->udev, 0xc2, 0, 0,
-						obuf, (len > 16 ? 16 : len) + 3,
-						DW210X_WRITE_MSG);
-					i += 16;
-					len -= 16;
-				} while (len > 0);
-			} else {
-				/* write registers */
-				u8 obuf[msg[j].len + 2];
-				obuf[0] = msg[j].addr << 1;
-				obuf[1] = msg[j].len;
-				memcpy(obuf + 2, msg[j].buf, msg[j].len);
-				dw210x_op_rw(d->udev, 0xc2, 0, 0,
-						obuf, msg[j].len + 2,
-						DW210X_WRITE_MSG);
-			}
-			break;
-		}
-		}
-
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return num;
-}
-
-static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-								int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int i;
-
-	if (!d)
-		return -ENODEV;
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	switch (num) {
-	case 2: {
-		/* read */
-		/* first write first register number */
-		u8 ibuf[msg[1].len + 2], obuf[3];
-		obuf[0] = msg[0].addr << 1;
-		obuf[1] = msg[0].len;
-		obuf[2] = msg[0].buf[0];
-		dw210x_op_rw(d->udev, 0xc2, 0, 0,
-				obuf, msg[0].len + 2, DW210X_WRITE_MSG);
-		/* second read registers */
-		dw210x_op_rw(d->udev, 0xc3, 0x19 , 0,
-				ibuf, msg[1].len + 2, DW210X_READ_MSG);
-		memcpy(msg[1].buf, ibuf + 2, msg[1].len);
-
-		break;
-	}
-	case 1:
-		switch (msg[0].addr) {
-		case 0x60:
-		case 0x0c: {
-			/* write to register */
-			u8 obuf[msg[0].len + 2];
-			obuf[0] = msg[0].addr << 1;
-			obuf[1] = msg[0].len;
-			memcpy(obuf + 2, msg[0].buf, msg[0].len);
-			dw210x_op_rw(d->udev, 0xc2, 0, 0,
-					obuf, msg[0].len + 2, DW210X_WRITE_MSG);
-			break;
-		}
-		case(DW2102_RC_QUERY): {
-			u8 ibuf[2];
-			dw210x_op_rw(d->udev, 0xb8, 0, 0,
-					ibuf, 2, DW210X_READ_MSG);
-			memcpy(msg[0].buf, ibuf , 2);
-			break;
-		}
-		}
-
-		break;
-	}
-
-	for (i = 0; i < num; i++) {
-		deb_xfer("%02x:%02x: %s ", i, msg[i].addr,
-				msg[i].flags == 0 ? ">>>" : "<<<");
-		debug_dump(msg[i].buf, msg[i].len, deb_xfer);
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return num;
-}
-
-static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-								int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	struct usb_device *udev;
-	int len, i, j;
-
-	if (!d)
-		return -ENODEV;
-	udev = d->udev;
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	for (j = 0; j < num; j++) {
-		switch (msg[j].addr) {
-		case (DW2102_RC_QUERY): {
-			u8 ibuf[5];
-			dw210x_op_rw(d->udev, 0xb8, 0, 0,
-					ibuf, 5, DW210X_READ_MSG);
-			memcpy(msg[j].buf, ibuf + 3, 2);
-			break;
-		}
-		case (DW2102_VOLTAGE_CTRL): {
-			u8 obuf[2];
-
-			obuf[0] = 1;
-			obuf[1] = msg[j].buf[1];/* off-on */
-			dw210x_op_rw(d->udev, 0x8a, 0, 0,
-					obuf, 2, DW210X_WRITE_MSG);
-			obuf[0] = 3;
-			obuf[1] = msg[j].buf[0];/* 13v-18v */
-			dw210x_op_rw(d->udev, 0x8a, 0, 0,
-					obuf, 2, DW210X_WRITE_MSG);
-			break;
-		}
-		case (DW2102_LED_CTRL): {
-			u8 obuf[2];
-
-			obuf[0] = 5;
-			obuf[1] = msg[j].buf[0];
-			dw210x_op_rw(d->udev, 0x8a, 0, 0,
-					obuf, 2, DW210X_WRITE_MSG);
-			break;
-		}
-		/*case 0x55: cx24116
-		case 0x6a: stv0903
-		case 0x68: ds3000, stv0903
-		case 0x60: ts2020, stv6110, stb6100
-		case 0xa0: eeprom */
-		default: {
-			if (msg[j].flags == I2C_M_RD) {
-				/* read registers */
-				u8 ibuf[msg[j].len];
-				dw210x_op_rw(d->udev, 0x91, 0, 0,
-						ibuf, msg[j].len,
-						DW210X_READ_MSG);
-				memcpy(msg[j].buf, ibuf, msg[j].len);
-				break;
-			} else if ((msg[j].buf[0] == 0xb0) &&
-						(msg[j].addr == 0x68)) {
-				/* write firmware */
-				u8 obuf[19];
-				obuf[0] = (msg[j].len > 16 ?
-						18 : msg[j].len + 1);
-				obuf[1] = msg[j].addr << 1;
-				obuf[2] = msg[j].buf[0];
-				len = msg[j].len - 1;
-				i = 1;
-				do {
-					memcpy(obuf + 3, msg[j].buf + i,
-							(len > 16 ? 16 : len));
-					dw210x_op_rw(d->udev, 0x80, 0, 0,
-						obuf, (len > 16 ? 16 : len) + 3,
-						DW210X_WRITE_MSG);
-					i += 16;
-					len -= 16;
-				} while (len > 0);
-			} else if (j < (num - 1)) {
-				/* write register addr before read */
-				u8 obuf[msg[j].len + 2];
-				obuf[0] = msg[j + 1].len;
-				obuf[1] = (msg[j].addr << 1);
-				memcpy(obuf + 2, msg[j].buf, msg[j].len);
-				dw210x_op_rw(d->udev,
-						udev->descriptor.idProduct ==
-						0x7500 ? 0x92 : 0x90, 0, 0,
-						obuf, msg[j].len + 2,
-						DW210X_WRITE_MSG);
-				break;
-			} else {
-				/* write registers */
-				u8 obuf[msg[j].len + 2];
-				obuf[0] = msg[j].len + 1;
-				obuf[1] = (msg[j].addr << 1);
-				memcpy(obuf + 2, msg[j].buf, msg[j].len);
-				dw210x_op_rw(d->udev, 0x80, 0, 0,
-						obuf, msg[j].len + 2,
-						DW210X_WRITE_MSG);
-				break;
-			}
-			break;
-		}
-		}
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return num;
-}
-
-static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-								int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	u8 obuf[0x40], ibuf[0x40];
-
-	if (!d)
-		return -ENODEV;
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	switch (num) {
-	case 1:
-		switch (msg[0].addr) {
-		case SU3000_STREAM_CTRL:
-			obuf[0] = msg[0].buf[0] + 0x36;
-			obuf[1] = 3;
-			obuf[2] = 0;
-			if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 0, 0) < 0)
-				err("i2c transfer failed.");
-			break;
-		case DW2102_RC_QUERY:
-			obuf[0] = 0x10;
-			if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 2, 0) < 0)
-				err("i2c transfer failed.");
-			msg[0].buf[1] = ibuf[0];
-			msg[0].buf[0] = ibuf[1];
-			break;
-		default:
-			/* always i2c write*/
-			obuf[0] = 0x08;
-			obuf[1] = msg[0].addr;
-			obuf[2] = msg[0].len;
-
-			memcpy(&obuf[3], msg[0].buf, msg[0].len);
-
-			if (dvb_usb_generic_rw(d, obuf, msg[0].len + 3,
-						ibuf, 1, 0) < 0)
-				err("i2c transfer failed.");
-
-		}
-		break;
-	case 2:
-		/* always i2c read */
-		obuf[0] = 0x09;
-		obuf[1] = msg[0].len;
-		obuf[2] = msg[1].len;
-		obuf[3] = msg[0].addr;
-		memcpy(&obuf[4], msg[0].buf, msg[0].len);
-
-		if (dvb_usb_generic_rw(d, obuf, msg[0].len + 4,
-					ibuf, msg[1].len + 1, 0) < 0)
-			err("i2c transfer failed.");
-
-		memcpy(msg[1].buf, &ibuf[1], msg[1].len);
-		break;
-	default:
-		warn("more than 2 i2c messages at a time is not handled yet.");
-		break;
-	}
-	mutex_unlock(&d->i2c_mutex);
-	return num;
-}
-
-static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm dw2102_i2c_algo = {
-	.master_xfer = dw2102_i2c_transfer,
-	.functionality = dw210x_i2c_func,
-};
-
-static struct i2c_algorithm dw2102_serit_i2c_algo = {
-	.master_xfer = dw2102_serit_i2c_transfer,
-	.functionality = dw210x_i2c_func,
-};
-
-static struct i2c_algorithm dw2102_earda_i2c_algo = {
-	.master_xfer = dw2102_earda_i2c_transfer,
-	.functionality = dw210x_i2c_func,
-};
-
-static struct i2c_algorithm dw2104_i2c_algo = {
-	.master_xfer = dw2104_i2c_transfer,
-	.functionality = dw210x_i2c_func,
-};
-
-static struct i2c_algorithm dw3101_i2c_algo = {
-	.master_xfer = dw3101_i2c_transfer,
-	.functionality = dw210x_i2c_func,
-};
-
-static struct i2c_algorithm s6x0_i2c_algo = {
-	.master_xfer = s6x0_i2c_transfer,
-	.functionality = dw210x_i2c_func,
-};
-
-static struct i2c_algorithm su3000_i2c_algo = {
-	.master_xfer = su3000_i2c_transfer,
-	.functionality = dw210x_i2c_func,
-};
-
-static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
-{
-	int i;
-	u8 ibuf[] = {0, 0};
-	u8 eeprom[256], eepromline[16];
-
-	for (i = 0; i < 256; i++) {
-		if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) {
-			err("read eeprom failed.");
-			return -1;
-		} else {
-			eepromline[i%16] = ibuf[0];
-			eeprom[i] = ibuf[0];
-		}
-		if ((i % 16) == 15) {
-			deb_xfer("%02x: ", i - 15);
-			debug_dump(eepromline, 16, deb_xfer);
-		}
-	}
-
-	memcpy(mac, eeprom + 8, 6);
-	return 0;
-};
-
-static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
-{
-	int i, ret;
-	u8 ibuf[] = { 0 }, obuf[] = { 0 };
-	u8 eeprom[256], eepromline[16];
-	struct i2c_msg msg[] = {
-		{
-			.addr = 0xa0 >> 1,
-			.flags = 0,
-			.buf = obuf,
-			.len = 1,
-		}, {
-			.addr = 0xa0 >> 1,
-			.flags = I2C_M_RD,
-			.buf = ibuf,
-			.len = 1,
-		}
-	};
-
-	for (i = 0; i < 256; i++) {
-		obuf[0] = i;
-		ret = s6x0_i2c_transfer(&d->i2c_adap, msg, 2);
-		if (ret != 2) {
-			err("read eeprom failed.");
-			return -1;
-		} else {
-			eepromline[i % 16] = ibuf[0];
-			eeprom[i] = ibuf[0];
-		}
-
-		if ((i % 16) == 15) {
-			deb_xfer("%02x: ", i - 15);
-			debug_dump(eepromline, 16, deb_xfer);
-		}
-	}
-
-	memcpy(mac, eeprom + 16, 6);
-	return 0;
-};
-
-static int su3000_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	static u8 command_start[] = {0x00};
-	static u8 command_stop[] = {0x01};
-	struct i2c_msg msg = {
-		.addr = SU3000_STREAM_CTRL,
-		.flags = 0,
-		.buf = onoff ? command_start : command_stop,
-		.len = 1
-	};
-
-	i2c_transfer(&adap->dev->i2c_adap, &msg, 1);
-
-	return 0;
-}
-
-static int su3000_power_ctrl(struct dvb_usb_device *d, int i)
-{
-	struct su3000_state *state = (struct su3000_state *)d->priv;
-	u8 obuf[] = {0xde, 0};
-
-	info("%s: %d, initialized %d\n", __func__, i, state->initialized);
-
-	if (i && !state->initialized) {
-		state->initialized = 1;
-		/* reset board */
-		dvb_usb_generic_rw(d, obuf, 2, NULL, 0, 0);
-	}
-
-	return 0;
-}
-
-static int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
-{
-	int i;
-	u8 obuf[] = { 0x1f, 0xf0 };
-	u8 ibuf[] = { 0 };
-	struct i2c_msg msg[] = {
-		{
-			.addr = 0x51,
-			.flags = 0,
-			.buf = obuf,
-			.len = 2,
-		}, {
-			.addr = 0x51,
-			.flags = I2C_M_RD,
-			.buf = ibuf,
-			.len = 1,
-
-		}
-	};
-
-	for (i = 0; i < 6; i++) {
-		obuf[1] = 0xf0 + i;
-		if (i2c_transfer(&d->i2c_adap, msg, 2) != 2)
-			break;
-		else
-			mac[i] = ibuf[0];
-
-		debug_dump(mac, 6, printk);
-	}
-
-	return 0;
-}
-
-static int su3000_identify_state(struct usb_device *udev,
-				 struct dvb_usb_device_properties *props,
-				 struct dvb_usb_device_description **desc,
-				 int *cold)
-{
-	info("%s\n", __func__);
-
-	*cold = 0;
-	return 0;
-}
-
-static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
-	static u8 command_13v[] = {0x00, 0x01};
-	static u8 command_18v[] = {0x01, 0x01};
-	static u8 command_off[] = {0x00, 0x00};
-	struct i2c_msg msg = {
-		.addr = DW2102_VOLTAGE_CTRL,
-		.flags = 0,
-		.buf = command_off,
-		.len = 2,
-	};
-
-	struct dvb_usb_adapter *udev_adap =
-		(struct dvb_usb_adapter *)(fe->dvb->priv);
-	if (voltage == SEC_VOLTAGE_18)
-		msg.buf = command_18v;
-	else if (voltage == SEC_VOLTAGE_13)
-		msg.buf = command_13v;
-
-	i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1);
-
-	return 0;
-}
-
-static int s660_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
-	struct dvb_usb_adapter *d =
-		(struct dvb_usb_adapter *)(fe->dvb->priv);
-	struct s6x0_state *st = (struct s6x0_state *)d->dev->priv;
-
-	dw210x_set_voltage(fe, voltage);
-	if (st->old_set_voltage)
-		st->old_set_voltage(fe, voltage);
-
-	return 0;
-}
-
-static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon)
-{
-	static u8 led_off[] = { 0 };
-	static u8 led_on[] = { 1 };
-	struct i2c_msg msg = {
-		.addr = DW2102_LED_CTRL,
-		.flags = 0,
-		.buf = led_off,
-		.len = 1
-	};
-	struct dvb_usb_adapter *udev_adap =
-		(struct dvb_usb_adapter *)(fe->dvb->priv);
-
-	if (offon)
-		msg.buf = led_on;
-	i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1);
-}
-
-static struct stv0299_config sharp_z0194a_config = {
-	.demod_address = 0x68,
-	.inittab = sharp_z0194a_inittab,
-	.mclk = 88000000UL,
-	.invert = 1,
-	.skip_reinit = 0,
-	.lock_output = STV0299_LOCKOUTPUT_1,
-	.volt13_op0_op1 = STV0299_VOLT13_OP1,
-	.min_delay_ms = 100,
-	.set_symbol_rate = sharp_z0194a_set_symbol_rate,
-};
-
-static struct cx24116_config dw2104_config = {
-	.demod_address = 0x55,
-	.mpg_clk_pos_pol = 0x01,
-};
-
-static struct si21xx_config serit_sp1511lhb_config = {
-	.demod_address = 0x68,
-	.min_delay_ms = 100,
-
-};
-
-static struct tda10023_config dw3101_tda10023_config = {
-	.demod_address = 0x0c,
-	.invert = 1,
-};
-
-static struct mt312_config zl313_config = {
-	.demod_address = 0x0e,
-};
-
-static struct ds3000_config dw2104_ds3000_config = {
-	.demod_address = 0x68,
-};
-
-static struct stv0900_config dw2104a_stv0900_config = {
-	.demod_address = 0x6a,
-	.demod_mode = 0,
-	.xtal = 27000000,
-	.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
-	.diseqc_mode = 2,/* 2/3 PWM */
-	.tun1_maddress = 0,/* 0x60 */
-	.tun1_adc = 0,/* 2 Vpp */
-	.path1_mode = 3,
-};
-
-static struct stb6100_config dw2104a_stb6100_config = {
-	.tuner_address = 0x60,
-	.refclock = 27000000,
-};
-
-static struct stv0900_config dw2104_stv0900_config = {
-	.demod_address = 0x68,
-	.demod_mode = 0,
-	.xtal = 8000000,
-	.clkmode = 3,
-	.diseqc_mode = 2,
-	.tun1_maddress = 0,
-	.tun1_adc = 1,/* 1 Vpp */
-	.path1_mode = 3,
-};
-
-static struct stv6110_config dw2104_stv6110_config = {
-	.i2c_address = 0x60,
-	.mclk = 16000000,
-	.clk_div = 1,
-};
-
-static struct stv0900_config prof_7500_stv0900_config = {
-	.demod_address = 0x6a,
-	.demod_mode = 0,
-	.xtal = 27000000,
-	.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
-	.diseqc_mode = 2,/* 2/3 PWM */
-	.tun1_maddress = 0,/* 0x60 */
-	.tun1_adc = 0,/* 2 Vpp */
-	.path1_mode = 3,
-	.tun1_type = 3,
-	.set_lock_led = dw210x_led_ctrl,
-};
-
-static struct ds3000_config su3000_ds3000_config = {
-	.demod_address = 0x68,
-	.ci_mode = 1,
-};
-
-static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
-{
-	struct dvb_tuner_ops *tuner_ops = NULL;
-
-	if (demod_probe & 4) {
-		d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config,
-				&d->dev->i2c_adap, 0);
-		if (d->fe_adap[0].fe != NULL) {
-			if (dvb_attach(stb6100_attach, d->fe_adap[0].fe,
-					&dw2104a_stb6100_config,
-					&d->dev->i2c_adap)) {
-				tuner_ops = &d->fe_adap[0].fe->ops.tuner_ops;
-				tuner_ops->set_frequency = stb6100_set_freq;
-				tuner_ops->get_frequency = stb6100_get_freq;
-				tuner_ops->set_bandwidth = stb6100_set_bandw;
-				tuner_ops->get_bandwidth = stb6100_get_bandw;
-				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
-				info("Attached STV0900+STB6100!\n");
-				return 0;
-			}
-		}
-	}
-
-	if (demod_probe & 2) {
-		d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config,
-				&d->dev->i2c_adap, 0);
-		if (d->fe_adap[0].fe != NULL) {
-			if (dvb_attach(stv6110_attach, d->fe_adap[0].fe,
-					&dw2104_stv6110_config,
-					&d->dev->i2c_adap)) {
-				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
-				info("Attached STV0900+STV6110A!\n");
-				return 0;
-			}
-		}
-	}
-
-	if (demod_probe & 1) {
-		d->fe_adap[0].fe = dvb_attach(cx24116_attach, &dw2104_config,
-				&d->dev->i2c_adap);
-		if (d->fe_adap[0].fe != NULL) {
-			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
-			info("Attached cx24116!\n");
-			return 0;
-		}
-	}
-
-	d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
-			&d->dev->i2c_adap);
-	if (d->fe_adap[0].fe != NULL) {
-		d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
-		info("Attached DS3000!\n");
-		return 0;
-	}
-
-	return -EIO;
-}
-
-static struct dvb_usb_device_properties dw2102_properties;
-static struct dvb_usb_device_properties dw2104_properties;
-static struct dvb_usb_device_properties s6x0_properties;
-
-static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
-{
-	if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) {
-		/*dw2102_properties.adapter->tuner_attach = NULL;*/
-		d->fe_adap[0].fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config,
-					&d->dev->i2c_adap);
-		if (d->fe_adap[0].fe != NULL) {
-			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
-			info("Attached si21xx!\n");
-			return 0;
-		}
-	}
-
-	if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) {
-		d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config,
-					&d->dev->i2c_adap);
-		if (d->fe_adap[0].fe != NULL) {
-			if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61,
-					&d->dev->i2c_adap)) {
-				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
-				info("Attached stv0288!\n");
-				return 0;
-			}
-		}
-	}
-
-	if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) {
-		/*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
-		d->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
-					&d->dev->i2c_adap);
-		if (d->fe_adap[0].fe != NULL) {
-			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
-			info("Attached stv0299!\n");
-			return 0;
-		}
-	}
-	return -EIO;
-}
-
-static int dw3101_frontend_attach(struct dvb_usb_adapter *d)
-{
-	d->fe_adap[0].fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config,
-				&d->dev->i2c_adap, 0x48);
-	if (d->fe_adap[0].fe != NULL) {
-		info("Attached tda10023!\n");
-		return 0;
-	}
-	return -EIO;
-}
-
-static int zl100313_frontend_attach(struct dvb_usb_adapter *d)
-{
-	d->fe_adap[0].fe = dvb_attach(mt312_attach, &zl313_config,
-			&d->dev->i2c_adap);
-	if (d->fe_adap[0].fe != NULL) {
-		if (dvb_attach(zl10039_attach, d->fe_adap[0].fe, 0x60,
-				&d->dev->i2c_adap)) {
-			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
-			info("Attached zl100313+zl10039!\n");
-			return 0;
-		}
-	}
-
-	return -EIO;
-}
-
-static int stv0288_frontend_attach(struct dvb_usb_adapter *d)
-{
-	u8 obuf[] = {7, 1};
-
-	d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config,
-			&d->dev->i2c_adap);
-
-	if (d->fe_adap[0].fe == NULL)
-		return -EIO;
-
-	if (NULL == dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, &d->dev->i2c_adap))
-		return -EIO;
-
-	d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
-
-	dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
-
-	info("Attached stv0288+stb6000!\n");
-
-	return 0;
-
-}
-
-static int ds3000_frontend_attach(struct dvb_usb_adapter *d)
-{
-	struct s6x0_state *st = (struct s6x0_state *)d->dev->priv;
-	u8 obuf[] = {7, 1};
-
-	d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
-			&d->dev->i2c_adap);
-
-	if (d->fe_adap[0].fe == NULL)
-		return -EIO;
-
-	st->old_set_voltage = d->fe_adap[0].fe->ops.set_voltage;
-	d->fe_adap[0].fe->ops.set_voltage = s660_set_voltage;
-
-	dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
-
-	info("Attached ds3000+ds2020!\n");
-
-	return 0;
-}
-
-static int prof_7500_frontend_attach(struct dvb_usb_adapter *d)
-{
-	u8 obuf[] = {7, 1};
-
-	d->fe_adap[0].fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config,
-					&d->dev->i2c_adap, 0);
-	if (d->fe_adap[0].fe == NULL)
-		return -EIO;
-
-	d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
-
-	dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
-
-	info("Attached STV0900+STB6100A!\n");
-
-	return 0;
-}
-
-static int su3000_frontend_attach(struct dvb_usb_adapter *d)
-{
-	u8 obuf[3] = { 0xe, 0x80, 0 };
-	u8 ibuf[] = { 0 };
-
-	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
-		err("command 0x0e transfer failed.");
-
-	obuf[0] = 0xe;
-	obuf[1] = 0x83;
-	obuf[2] = 0;
-
-	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
-		err("command 0x0e transfer failed.");
-
-	obuf[0] = 0xe;
-	obuf[1] = 0x83;
-	obuf[2] = 1;
-
-	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
-		err("command 0x0e transfer failed.");
-
-	obuf[0] = 0x51;
-
-	if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
-		err("command 0x51 transfer failed.");
-
-	d->fe_adap[0].fe = dvb_attach(ds3000_attach, &su3000_ds3000_config,
-					&d->dev->i2c_adap);
-	if (d->fe_adap[0].fe == NULL)
-		return -EIO;
-
-	info("Attached DS3000!\n");
-
-	return 0;
-}
-
-static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
-		&adap->dev->i2c_adap, DVB_PLL_OPERA1);
-	return 0;
-}
-
-static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
-		&adap->dev->i2c_adap, DVB_PLL_TUA6034);
-
-	return 0;
-}
-
-static struct rc_map_table rc_map_dw210x_table[] = {
-	{ 0xf80a, KEY_POWER2 },		/*power*/
-	{ 0xf80c, KEY_MUTE },		/*mute*/
-	{ 0xf811, KEY_1 },
-	{ 0xf812, KEY_2 },
-	{ 0xf813, KEY_3 },
-	{ 0xf814, KEY_4 },
-	{ 0xf815, KEY_5 },
-	{ 0xf816, KEY_6 },
-	{ 0xf817, KEY_7 },
-	{ 0xf818, KEY_8 },
-	{ 0xf819, KEY_9 },
-	{ 0xf810, KEY_0 },
-	{ 0xf81c, KEY_CHANNELUP },	/*ch+*/
-	{ 0xf80f, KEY_CHANNELDOWN },	/*ch-*/
-	{ 0xf81a, KEY_VOLUMEUP },	/*vol+*/
-	{ 0xf80e, KEY_VOLUMEDOWN },	/*vol-*/
-	{ 0xf804, KEY_RECORD },		/*rec*/
-	{ 0xf809, KEY_FAVORITES },	/*fav*/
-	{ 0xf808, KEY_REWIND },		/*rewind*/
-	{ 0xf807, KEY_FASTFORWARD },	/*fast*/
-	{ 0xf80b, KEY_PAUSE },		/*pause*/
-	{ 0xf802, KEY_ESC },		/*cancel*/
-	{ 0xf803, KEY_TAB },		/*tab*/
-	{ 0xf800, KEY_UP },		/*up*/
-	{ 0xf81f, KEY_OK },		/*ok*/
-	{ 0xf801, KEY_DOWN },		/*down*/
-	{ 0xf805, KEY_CAMERA },		/*cap*/
-	{ 0xf806, KEY_STOP },		/*stop*/
-	{ 0xf840, KEY_ZOOM },		/*full*/
-	{ 0xf81e, KEY_TV },		/*tvmode*/
-	{ 0xf81b, KEY_LAST },		/*recall*/
-};
-
-static struct rc_map_table rc_map_tevii_table[] = {
-	{ 0xf80a, KEY_POWER },
-	{ 0xf80c, KEY_MUTE },
-	{ 0xf811, KEY_1 },
-	{ 0xf812, KEY_2 },
-	{ 0xf813, KEY_3 },
-	{ 0xf814, KEY_4 },
-	{ 0xf815, KEY_5 },
-	{ 0xf816, KEY_6 },
-	{ 0xf817, KEY_7 },
-	{ 0xf818, KEY_8 },
-	{ 0xf819, KEY_9 },
-	{ 0xf810, KEY_0 },
-	{ 0xf81c, KEY_MENU },
-	{ 0xf80f, KEY_VOLUMEDOWN },
-	{ 0xf81a, KEY_LAST },
-	{ 0xf80e, KEY_OPEN },
-	{ 0xf804, KEY_RECORD },
-	{ 0xf809, KEY_VOLUMEUP },
-	{ 0xf808, KEY_CHANNELUP },
-	{ 0xf807, KEY_PVR },
-	{ 0xf80b, KEY_TIME },
-	{ 0xf802, KEY_RIGHT },
-	{ 0xf803, KEY_LEFT },
-	{ 0xf800, KEY_UP },
-	{ 0xf81f, KEY_OK },
-	{ 0xf801, KEY_DOWN },
-	{ 0xf805, KEY_TUNER },
-	{ 0xf806, KEY_CHANNELDOWN },
-	{ 0xf840, KEY_PLAYPAUSE },
-	{ 0xf81e, KEY_REWIND },
-	{ 0xf81b, KEY_FAVORITES },
-	{ 0xf81d, KEY_BACK },
-	{ 0xf84d, KEY_FASTFORWARD },
-	{ 0xf844, KEY_EPG },
-	{ 0xf84c, KEY_INFO },
-	{ 0xf841, KEY_AB },
-	{ 0xf843, KEY_AUDIO },
-	{ 0xf845, KEY_SUBTITLE },
-	{ 0xf84a, KEY_LIST },
-	{ 0xf846, KEY_F1 },
-	{ 0xf847, KEY_F2 },
-	{ 0xf85e, KEY_F3 },
-	{ 0xf85c, KEY_F4 },
-	{ 0xf852, KEY_F5 },
-	{ 0xf85a, KEY_F6 },
-	{ 0xf856, KEY_MODE },
-	{ 0xf858, KEY_SWITCHVIDEOMODE },
-};
-
-static struct rc_map_table rc_map_tbs_table[] = {
-	{ 0xf884, KEY_POWER },
-	{ 0xf894, KEY_MUTE },
-	{ 0xf887, KEY_1 },
-	{ 0xf886, KEY_2 },
-	{ 0xf885, KEY_3 },
-	{ 0xf88b, KEY_4 },
-	{ 0xf88a, KEY_5 },
-	{ 0xf889, KEY_6 },
-	{ 0xf88f, KEY_7 },
-	{ 0xf88e, KEY_8 },
-	{ 0xf88d, KEY_9 },
-	{ 0xf892, KEY_0 },
-	{ 0xf896, KEY_CHANNELUP },
-	{ 0xf891, KEY_CHANNELDOWN },
-	{ 0xf893, KEY_VOLUMEUP },
-	{ 0xf88c, KEY_VOLUMEDOWN },
-	{ 0xf883, KEY_RECORD },
-	{ 0xf898, KEY_PAUSE  },
-	{ 0xf899, KEY_OK },
-	{ 0xf89a, KEY_SHUFFLE },
-	{ 0xf881, KEY_UP },
-	{ 0xf890, KEY_LEFT },
-	{ 0xf882, KEY_RIGHT },
-	{ 0xf888, KEY_DOWN },
-	{ 0xf895, KEY_FAVORITES },
-	{ 0xf897, KEY_SUBTITLE },
-	{ 0xf89d, KEY_ZOOM },
-	{ 0xf89f, KEY_EXIT },
-	{ 0xf89e, KEY_MENU },
-	{ 0xf89c, KEY_EPG },
-	{ 0xf880, KEY_PREVIOUS },
-	{ 0xf89b, KEY_MODE }
-};
-
-static struct rc_map_table rc_map_su3000_table[] = {
-	{ 0x25, KEY_POWER },	/* right-bottom Red */
-	{ 0x0a, KEY_MUTE },	/* -/-- */
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-	{ 0x00, KEY_0 },
-	{ 0x20, KEY_UP },	/* CH+ */
-	{ 0x21, KEY_DOWN },	/* CH+ */
-	{ 0x12, KEY_VOLUMEUP },	/* Brightness Up */
-	{ 0x13, KEY_VOLUMEDOWN },/* Brightness Down */
-	{ 0x1f, KEY_RECORD },
-	{ 0x17, KEY_PLAY },
-	{ 0x16, KEY_PAUSE },
-	{ 0x0b, KEY_STOP },
-	{ 0x27, KEY_FASTFORWARD },/* >> */
-	{ 0x26, KEY_REWIND },	/* << */
-	{ 0x0d, KEY_OK },	/* Mute */
-	{ 0x11, KEY_LEFT },	/* VOL- */
-	{ 0x10, KEY_RIGHT },	/* VOL+ */
-	{ 0x29, KEY_BACK },	/* button under 9 */
-	{ 0x2c, KEY_MENU },	/* TTX */
-	{ 0x2b, KEY_EPG },	/* EPG */
-	{ 0x1e, KEY_RED },	/* OSD */
-	{ 0x0e, KEY_GREEN },	/* Window */
-	{ 0x2d, KEY_YELLOW },	/* button under << */
-	{ 0x0f, KEY_BLUE },	/* bottom yellow button */
-	{ 0x14, KEY_AUDIO },	/* Snapshot */
-	{ 0x38, KEY_TV },	/* TV/Radio */
-	{ 0x0c, KEY_ESC }	/* upper Red button */
-};
-
-static struct rc_map_dvb_usb_table_table keys_tables[] = {
-	{ rc_map_dw210x_table, ARRAY_SIZE(rc_map_dw210x_table) },
-	{ rc_map_tevii_table, ARRAY_SIZE(rc_map_tevii_table) },
-	{ rc_map_tbs_table, ARRAY_SIZE(rc_map_tbs_table) },
-	{ rc_map_su3000_table, ARRAY_SIZE(rc_map_su3000_table) },
-};
-
-static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
-{
-	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
-	int keymap_size = d->props.rc.legacy.rc_map_size;
-	u8 key[2];
-	struct i2c_msg msg = {
-		.addr = DW2102_RC_QUERY,
-		.flags = I2C_M_RD,
-		.buf = key,
-		.len = 2
-	};
-	int i;
-	/* override keymap */
-	if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) {
-		keymap = keys_tables[ir_keymap - 1].rc_keys ;
-		keymap_size = keys_tables[ir_keymap - 1].rc_keys_size;
-	} else if (ir_keymap > ARRAY_SIZE(keys_tables))
-		return 0; /* none */
-
-	*state = REMOTE_NO_KEY_PRESSED;
-	if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) {
-		for (i = 0; i < keymap_size ; i++) {
-			if (rc5_data(&keymap[i]) == msg.buf[0]) {
-				*state = REMOTE_KEY_PRESSED;
-				*event = keymap[i].keycode;
-				break;
-			}
-
-		}
-
-		if ((*state) == REMOTE_KEY_PRESSED)
-			deb_rc("%s: found rc key: %x, %x, event: %x\n",
-					__func__, key[0], key[1], (*event));
-		else if (key[0] != 0xff)
-			deb_rc("%s: unknown rc key: %x, %x\n",
-					__func__, key[0], key[1]);
-
-	}
-
-	return 0;
-}
-
-enum dw2102_table_entry {
-	CYPRESS_DW2102,
-	CYPRESS_DW2101,
-	CYPRESS_DW2104,
-	TEVII_S650,
-	TERRATEC_CINERGY_S,
-	CYPRESS_DW3101,
-	TEVII_S630,
-	PROF_1100,
-	TEVII_S660,
-	PROF_7500,
-	GENIATECH_SU3000,
-	TERRATEC_CINERGY_S2,
-	TEVII_S480_1,
-	TEVII_S480_2,
-	X3M_SPC1400HD,
-};
-
-static struct usb_device_id dw2102_table[] = {
-	[CYPRESS_DW2102] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
-	[CYPRESS_DW2101] = {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
-	[CYPRESS_DW2104] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)},
-	[TEVII_S650] = {USB_DEVICE(0x9022, USB_PID_TEVII_S650)},
-	[TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
-	[CYPRESS_DW3101] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)},
-	[TEVII_S630] = {USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
-	[PROF_1100] = {USB_DEVICE(0x3011, USB_PID_PROF_1100)},
-	[TEVII_S660] = {USB_DEVICE(0x9022, USB_PID_TEVII_S660)},
-	[PROF_7500] = {USB_DEVICE(0x3034, 0x7500)},
-	[GENIATECH_SU3000] = {USB_DEVICE(0x1f4d, 0x3000)},
-	[TERRATEC_CINERGY_S2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)},
-	[TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)},
-	[TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
-	[X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)},
-	{ }
-};
-
-MODULE_DEVICE_TABLE(usb, dw2102_table);
-
-static int dw2102_load_firmware(struct usb_device *dev,
-			const struct firmware *frmwr)
-{
-	u8 *b, *p;
-	int ret = 0, i;
-	u8 reset;
-	u8 reset16[] = {0, 0, 0, 0, 0, 0, 0};
-	const struct firmware *fw;
-	const char *fw_2101 = "dvb-usb-dw2101.fw";
-
-	switch (dev->descriptor.idProduct) {
-	case 0x2101:
-		ret = request_firmware(&fw, fw_2101, &dev->dev);
-		if (ret != 0) {
-			err(err_str, fw_2101);
-			return ret;
-		}
-		break;
-	default:
-		fw = frmwr;
-		break;
-	}
-	info("start downloading DW210X firmware");
-	p = kmalloc(fw->size, GFP_KERNEL);
-	reset = 1;
-	/*stop the CPU*/
-	dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW210X_WRITE_MSG);
-	dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW210X_WRITE_MSG);
-
-	if (p != NULL) {
-		memcpy(p, fw->data, fw->size);
-		for (i = 0; i < fw->size; i += 0x40) {
-			b = (u8 *) p + i;
-			if (dw210x_op_rw(dev, 0xa0, i, 0, b , 0x40,
-					DW210X_WRITE_MSG) != 0x40) {
-				err("error while transferring firmware");
-				ret = -EINVAL;
-				break;
-			}
-		}
-		/* restart the CPU */
-		reset = 0;
-		if (ret || dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1,
-					DW210X_WRITE_MSG) != 1) {
-			err("could not restart the USB controller CPU.");
-			ret = -EINVAL;
-		}
-		if (ret || dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1,
-					DW210X_WRITE_MSG) != 1) {
-			err("could not restart the USB controller CPU.");
-			ret = -EINVAL;
-		}
-		/* init registers */
-		switch (dev->descriptor.idProduct) {
-		case USB_PID_TEVII_S650:
-			dw2104_properties.rc.legacy.rc_map_table = rc_map_tevii_table;
-			dw2104_properties.rc.legacy.rc_map_size =
-					ARRAY_SIZE(rc_map_tevii_table);
-		case USB_PID_DW2104:
-			reset = 1;
-			dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
-					DW210X_WRITE_MSG);
-			/* break omitted intentionally */
-		case USB_PID_DW3101:
-			reset = 0;
-			dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
-					DW210X_WRITE_MSG);
-			break;
-		case USB_PID_CINERGY_S:
-		case USB_PID_DW2102:
-			dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
-					DW210X_WRITE_MSG);
-			dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2,
-					DW210X_READ_MSG);
-			/* check STV0299 frontend  */
-			dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2,
-					DW210X_READ_MSG);
-			if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) {
-				dw2102_properties.i2c_algo = &dw2102_i2c_algo;
-				dw2102_properties.adapter->fe[0].tuner_attach = &dw2102_tuner_attach;
-				break;
-			} else {
-				/* check STV0288 frontend  */
-				reset16[0] = 0xd0;
-				reset16[1] = 1;
-				reset16[2] = 0;
-				dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3,
-						DW210X_WRITE_MSG);
-				dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3,
-						DW210X_READ_MSG);
-				if (reset16[2] == 0x11) {
-					dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo;
-					break;
-				}
-			}
-		case 0x2101:
-			dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2,
-					DW210X_READ_MSG);
-			dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7,
-					DW210X_READ_MSG);
-			dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7,
-					DW210X_READ_MSG);
-			dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2,
-					DW210X_READ_MSG);
-			break;
-		}
-
-		msleep(100);
-		kfree(p);
-	}
-	return ret;
-}
-
-static struct dvb_usb_device_properties dw2102_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-	.usb_ctrl = DEVICE_SPECIFIC,
-	.firmware = "dvb-usb-dw2102.fw",
-	.no_reconnect = 1,
-
-	.i2c_algo = &dw2102_serit_i2c_algo,
-
-	.rc.legacy = {
-		.rc_map_table = rc_map_dw210x_table,
-		.rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
-		.rc_interval = 150,
-		.rc_query = dw2102_rc_query,
-	},
-
-	.generic_bulk_ctrl_endpoint = 0x81,
-	/* parameter for the MPEG2-data transfer */
-	.num_adapters = 1,
-	.download_firmware = dw2102_load_firmware,
-	.read_mac_address = dw210x_read_mac_address,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.frontend_attach = dw2102_frontend_attach,
-			.stream = {
-				.type = USB_BULK,
-				.count = 8,
-				.endpoint = 0x82,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-		}
-	},
-	.num_device_descs = 3,
-	.devices = {
-		{"DVBWorld DVB-S 2102 USB2.0",
-			{&dw2102_table[CYPRESS_DW2102], NULL},
-			{NULL},
-		},
-		{"DVBWorld DVB-S 2101 USB2.0",
-			{&dw2102_table[CYPRESS_DW2101], NULL},
-			{NULL},
-		},
-		{"TerraTec Cinergy S USB",
-			{&dw2102_table[TERRATEC_CINERGY_S], NULL},
-			{NULL},
-		},
-	}
-};
-
-static struct dvb_usb_device_properties dw2104_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-	.usb_ctrl = DEVICE_SPECIFIC,
-	.firmware = "dvb-usb-dw2104.fw",
-	.no_reconnect = 1,
-
-	.i2c_algo = &dw2104_i2c_algo,
-	.rc.legacy = {
-		.rc_map_table = rc_map_dw210x_table,
-		.rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
-		.rc_interval = 150,
-		.rc_query = dw2102_rc_query,
-	},
-
-	.generic_bulk_ctrl_endpoint = 0x81,
-	/* parameter for the MPEG2-data transfer */
-	.num_adapters = 1,
-	.download_firmware = dw2102_load_firmware,
-	.read_mac_address = dw210x_read_mac_address,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.frontend_attach = dw2104_frontend_attach,
-			.stream = {
-				.type = USB_BULK,
-				.count = 8,
-				.endpoint = 0x82,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-		}
-	},
-	.num_device_descs = 2,
-	.devices = {
-		{ "DVBWorld DW2104 USB2.0",
-			{&dw2102_table[CYPRESS_DW2104], NULL},
-			{NULL},
-		},
-		{ "TeVii S650 USB2.0",
-			{&dw2102_table[TEVII_S650], NULL},
-			{NULL},
-		},
-	}
-};
-
-static struct dvb_usb_device_properties dw3101_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-	.usb_ctrl = DEVICE_SPECIFIC,
-	.firmware = "dvb-usb-dw3101.fw",
-	.no_reconnect = 1,
-
-	.i2c_algo = &dw3101_i2c_algo,
-	.rc.legacy = {
-		.rc_map_table = rc_map_dw210x_table,
-		.rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
-		.rc_interval = 150,
-		.rc_query = dw2102_rc_query,
-	},
-
-	.generic_bulk_ctrl_endpoint = 0x81,
-	/* parameter for the MPEG2-data transfer */
-	.num_adapters = 1,
-	.download_firmware = dw2102_load_firmware,
-	.read_mac_address = dw210x_read_mac_address,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.frontend_attach = dw3101_frontend_attach,
-			.tuner_attach = dw3101_tuner_attach,
-			.stream = {
-				.type = USB_BULK,
-				.count = 8,
-				.endpoint = 0x82,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-		}
-	},
-	.num_device_descs = 1,
-	.devices = {
-		{ "DVBWorld DVB-C 3101 USB2.0",
-			{&dw2102_table[CYPRESS_DW3101], NULL},
-			{NULL},
-		},
-	}
-};
-
-static struct dvb_usb_device_properties s6x0_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-	.usb_ctrl = DEVICE_SPECIFIC,
-	.size_of_priv = sizeof(struct s6x0_state),
-	.firmware = "dvb-usb-s630.fw",
-	.no_reconnect = 1,
-
-	.i2c_algo = &s6x0_i2c_algo,
-	.rc.legacy = {
-		.rc_map_table = rc_map_tevii_table,
-		.rc_map_size = ARRAY_SIZE(rc_map_tevii_table),
-		.rc_interval = 150,
-		.rc_query = dw2102_rc_query,
-	},
-
-	.generic_bulk_ctrl_endpoint = 0x81,
-	.num_adapters = 1,
-	.download_firmware = dw2102_load_firmware,
-	.read_mac_address = s6x0_read_mac_address,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.frontend_attach = zl100313_frontend_attach,
-			.stream = {
-				.type = USB_BULK,
-				.count = 8,
-				.endpoint = 0x82,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-		}
-	},
-	.num_device_descs = 1,
-	.devices = {
-		{"TeVii S630 USB",
-			{&dw2102_table[TEVII_S630], NULL},
-			{NULL},
-		},
-	}
-};
-
-struct dvb_usb_device_properties *p1100;
-static struct dvb_usb_device_description d1100 = {
-	"Prof 1100 USB ",
-	{&dw2102_table[PROF_1100], NULL},
-	{NULL},
-};
-
-struct dvb_usb_device_properties *s660;
-static struct dvb_usb_device_description d660 = {
-	"TeVii S660 USB",
-	{&dw2102_table[TEVII_S660], NULL},
-	{NULL},
-};
-
-static struct dvb_usb_device_description d480_1 = {
-	"TeVii S480.1 USB",
-	{&dw2102_table[TEVII_S480_1], NULL},
-	{NULL},
-};
-
-static struct dvb_usb_device_description d480_2 = {
-	"TeVii S480.2 USB",
-	{&dw2102_table[TEVII_S480_2], NULL},
-	{NULL},
-};
-
-struct dvb_usb_device_properties *p7500;
-static struct dvb_usb_device_description d7500 = {
-	"Prof 7500 USB DVB-S2",
-	{&dw2102_table[PROF_7500], NULL},
-	{NULL},
-};
-
-static struct dvb_usb_device_properties su3000_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-	.usb_ctrl = DEVICE_SPECIFIC,
-	.size_of_priv = sizeof(struct su3000_state),
-	.power_ctrl = su3000_power_ctrl,
-	.num_adapters = 1,
-	.identify_state	= su3000_identify_state,
-	.i2c_algo = &su3000_i2c_algo,
-
-	.rc.legacy = {
-		.rc_map_table = rc_map_su3000_table,
-		.rc_map_size = ARRAY_SIZE(rc_map_su3000_table),
-		.rc_interval = 150,
-		.rc_query = dw2102_rc_query,
-	},
-
-	.read_mac_address = su3000_read_mac_address,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = su3000_streaming_ctrl,
-			.frontend_attach  = su3000_frontend_attach,
-			.stream = {
-				.type = USB_BULK,
-				.count = 8,
-				.endpoint = 0x82,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			}
-		}},
-		}
-	},
-	.num_device_descs = 3,
-	.devices = {
-		{ "SU3000HD DVB-S USB2.0",
-			{ &dw2102_table[GENIATECH_SU3000], NULL },
-			{ NULL },
-		},
-		{ "Terratec Cinergy S2 USB HD",
-			{ &dw2102_table[TERRATEC_CINERGY_S2], NULL },
-			{ NULL },
-		},
-		{ "X3M TV SPC1400HD PCI",
-			{ &dw2102_table[X3M_SPC1400HD], NULL },
-			{ NULL },
-		},
-	}
-};
-
-static int dw2102_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	p1100 = kmemdup(&s6x0_properties,
-			sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
-	if (!p1100)
-		return -ENOMEM;
-	/* copy default structure */
-	/* fill only different fields */
-	p1100->firmware = "dvb-usb-p1100.fw";
-	p1100->devices[0] = d1100;
-	p1100->rc.legacy.rc_map_table = rc_map_tbs_table;
-	p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
-	p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach;
-
-	s660 = kmemdup(&s6x0_properties,
-		       sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
-	if (!s660) {
-		kfree(p1100);
-		return -ENOMEM;
-	}
-	s660->firmware = "dvb-usb-s660.fw";
-	s660->num_device_descs = 3;
-	s660->devices[0] = d660;
-	s660->devices[1] = d480_1;
-	s660->devices[2] = d480_2;
-	s660->adapter->fe[0].frontend_attach = ds3000_frontend_attach;
-
-	p7500 = kmemdup(&s6x0_properties,
-			sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
-	if (!p7500) {
-		kfree(p1100);
-		kfree(s660);
-		return -ENOMEM;
-	}
-	p7500->firmware = "dvb-usb-p7500.fw";
-	p7500->devices[0] = d7500;
-	p7500->rc.legacy.rc_map_table = rc_map_tbs_table;
-	p7500->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
-	p7500->adapter->fe[0].frontend_attach = prof_7500_frontend_attach;
-
-	if (0 == dvb_usb_device_init(intf, &dw2102_properties,
-			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &dw2104_properties,
-			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &dw3101_properties,
-			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &s6x0_properties,
-			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, p1100,
-			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, s660,
-			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, p7500,
-			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &su3000_properties,
-				     THIS_MODULE, NULL, adapter_nr))
-		return 0;
-
-	return -ENODEV;
-}
-
-static struct usb_driver dw2102_driver = {
-	.name = "dw2102",
-	.probe = dw2102_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table = dw2102_table,
-};
-
-module_usb_driver(dw2102_driver);
-
-MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
-MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
-				" DVB-C 3101 USB2.0,"
-				" TeVii S600, S630, S650, S660, S480,"
-				" Prof 1100, 7500 USB2.0,"
-				" Geniatech SU3000 devices");
-MODULE_VERSION("0.1");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dw2102.h b/drivers/media/dvb/dvb-usb/dw2102.h
deleted file mode 100644
index 5cd0b0e..0000000
--- a/drivers/media/dvb/dvb-usb/dw2102.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _DW2102_H_
-#define _DW2102_H_
-
-#define DVB_USB_LOG_PREFIX "dw2102"
-#include "dvb-usb.h"
-
-#define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args)
-#define deb_rc(args...)   dprintk(dvb_usb_dw2102_debug, 0x04, args)
-#endif
diff --git a/drivers/media/dvb/dvb-usb/ec168.c b/drivers/media/dvb/dvb-usb/ec168.c
deleted file mode 100644
index b4989ba..0000000
--- a/drivers/media/dvb/dvb-usb/ec168.c
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * E3C EC168 DVB USB driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include "ec168.h"
-#include "ec100.h"
-#include "mxl5005s.h"
-
-/* debug */
-static int dvb_usb_ec168_debug;
-module_param_named(debug, dvb_usb_ec168_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static struct ec100_config ec168_ec100_config;
-
-static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
-{
-	int ret;
-	unsigned int pipe;
-	u8 request, requesttype;
-	u8 *buf;
-
-
-
-	switch (req->cmd) {
-	case DOWNLOAD_FIRMWARE:
-	case GPIO:
-	case WRITE_I2C:
-	case STREAMING_CTRL:
-		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
-		request = req->cmd;
-		break;
-	case READ_I2C:
-		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
-		request = req->cmd;
-		break;
-	case GET_CONFIG:
-		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
-		request = CONFIG;
-		break;
-	case SET_CONFIG:
-		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
-		request = CONFIG;
-		break;
-	case WRITE_DEMOD:
-		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
-		request = DEMOD_RW;
-		break;
-	case READ_DEMOD:
-		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
-		request = DEMOD_RW;
-		break;
-	default:
-		err("unknown command:%02x", req->cmd);
-		ret = -EPERM;
-		goto error;
-	}
-
-	buf = kmalloc(req->size, GFP_KERNEL);
-	if (!buf) {
-		ret = -ENOMEM;
-		goto error;
-	}
-
-	if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
-		/* write */
-		memcpy(buf, req->data, req->size);
-		pipe = usb_sndctrlpipe(udev, 0);
-	} else {
-		/* read */
-		pipe = usb_rcvctrlpipe(udev, 0);
-	}
-
-	msleep(1); /* avoid I2C errors */
-
-	ret = usb_control_msg(udev, pipe, request, requesttype, req->value,
-		req->index, buf, req->size, EC168_USB_TIMEOUT);
-
-	ec168_debug_dump(request, requesttype, req->value, req->index, buf,
-		req->size, deb_xfer);
-
-	if (ret < 0)
-		goto err_dealloc;
-	else
-		ret = 0;
-
-	/* read request, copy returned data to return buf */
-	if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
-		memcpy(req->data, buf, req->size);
-
-	kfree(buf);
-	return ret;
-
-err_dealloc:
-	kfree(buf);
-error:
-	deb_info("%s: failed:%d\n", __func__, ret);
-	return ret;
-}
-
-static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req)
-{
-	return ec168_rw_udev(d->udev, req);
-}
-
-/* I2C */
-static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-	int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	struct ec168_req req;
-	int i = 0;
-	int ret;
-
-	if (num > 2)
-		return -EINVAL;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	while (i < num) {
-		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
-			if (msg[i].addr == ec168_ec100_config.demod_address) {
-				req.cmd = READ_DEMOD;
-				req.value = 0;
-				req.index = 0xff00 + msg[i].buf[0]; /* reg */
-				req.size = msg[i+1].len; /* bytes to read */
-				req.data = &msg[i+1].buf[0];
-				ret = ec168_ctrl_msg(d, &req);
-				i += 2;
-			} else {
-				err("I2C read not implemented");
-				ret = -ENOSYS;
-				i += 2;
-			}
-		} else {
-			if (msg[i].addr == ec168_ec100_config.demod_address) {
-				req.cmd = WRITE_DEMOD;
-				req.value = msg[i].buf[1]; /* val */
-				req.index = 0xff00 + msg[i].buf[0]; /* reg */
-				req.size = 0;
-				req.data = NULL;
-				ret = ec168_ctrl_msg(d, &req);
-				i += 1;
-			} else {
-				req.cmd = WRITE_I2C;
-				req.value = msg[i].buf[0]; /* val */
-				req.index = 0x0100 + msg[i].addr; /* I2C addr */
-				req.size = msg[i].len-1;
-				req.data = &msg[i].buf[1];
-				ret = ec168_ctrl_msg(d, &req);
-				i += 1;
-			}
-		}
-		if (ret)
-			goto error;
-
-	}
-	ret = i;
-
-error:
-	mutex_unlock(&d->i2c_mutex);
-	return i;
-}
-
-
-static u32 ec168_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm ec168_i2c_algo = {
-	.master_xfer   = ec168_i2c_xfer,
-	.functionality = ec168_i2c_func,
-};
-
-/* Callbacks for DVB USB */
-static struct ec100_config ec168_ec100_config = {
-	.demod_address = 0xff, /* not real address, demod is integrated */
-};
-
-static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	deb_info("%s:\n", __func__);
-	adap->fe_adap[0].fe = dvb_attach(ec100_attach, &ec168_ec100_config,
-		&adap->dev->i2c_adap);
-	if (adap->fe_adap[0].fe == NULL)
-		return -ENODEV;
-
-	return 0;
-}
-
-static struct mxl5005s_config ec168_mxl5003s_config = {
-	.i2c_address     = 0xc6,
-	.if_freq         = IF_FREQ_4570000HZ,
-	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
-	.agc_mode        = MXL_SINGLE_AGC,
-	.tracking_filter = MXL_TF_OFF,
-	.rssi_enable     = MXL_RSSI_ENABLE,
-	.cap_select      = MXL_CAP_SEL_ENABLE,
-	.div_out         = MXL_DIV_OUT_4,
-	.clock_out       = MXL_CLOCK_OUT_DISABLE,
-	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
-	.top		 = MXL5005S_TOP_25P2,
-	.mod_mode        = MXL_DIGITAL_MODE,
-	.if_mode         = MXL_ZERO_IF,
-	.AgcMasterByte   = 0x00,
-};
-
-static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	deb_info("%s:\n", __func__);
-	return dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
-		&ec168_mxl5003s_config) == NULL ? -ENODEV : 0;
-}
-
-static int ec168_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL};
-	deb_info("%s: onoff:%d\n", __func__, onoff);
-	if (onoff)
-		req.index = 0x0102;
-	return ec168_ctrl_msg(adap->dev, &req);
-}
-
-static int ec168_download_firmware(struct usb_device *udev,
-	const struct firmware *fw)
-{
-	int i, len, packets, remainder, ret;
-	u16 addr = 0x0000; /* firmware start address */
-	struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL};
-	deb_info("%s:\n", __func__);
-
-	#define FW_PACKET_MAX_DATA  2048
-	packets = fw->size / FW_PACKET_MAX_DATA;
-	remainder = fw->size % FW_PACKET_MAX_DATA;
-	len = FW_PACKET_MAX_DATA;
-	for (i = 0; i <= packets; i++) {
-		if (i == packets)  /* set size of the last packet */
-			len = remainder;
-
-		req.size = len;
-		req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA);
-		req.index = addr;
-		addr += FW_PACKET_MAX_DATA;
-
-		ret = ec168_rw_udev(udev, &req);
-		if (ret) {
-			err("firmware download failed:%d packet:%d", ret, i);
-			goto error;
-		}
-	}
-	req.size = 0;
-
-	/* set "warm"? */
-	req.cmd = SET_CONFIG;
-	req.value = 0;
-	req.index = 0x0001;
-	ret = ec168_rw_udev(udev, &req);
-	if (ret)
-		goto error;
-
-	/* really needed - no idea what does */
-	req.cmd = GPIO;
-	req.value = 0;
-	req.index = 0x0206;
-	ret = ec168_rw_udev(udev, &req);
-	if (ret)
-		goto error;
-
-	/* activate tuner I2C? */
-	req.cmd = WRITE_I2C;
-	req.value = 0;
-	req.index = 0x00c6;
-	ret = ec168_rw_udev(udev, &req);
-	if (ret)
-		goto error;
-
-	return ret;
-error:
-	deb_info("%s: failed:%d\n", __func__, ret);
-	return ret;
-}
-
-static int ec168_identify_state(struct usb_device *udev,
-	struct dvb_usb_device_properties *props,
-	struct dvb_usb_device_description **desc, int *cold)
-{
-	int ret;
-	u8 reply;
-	struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply};
-	deb_info("%s:\n", __func__);
-
-	ret = ec168_rw_udev(udev, &req);
-	if (ret)
-		goto error;
-
-	deb_info("%s: reply:%02x\n", __func__, reply);
-
-	if (reply == 0x01)
-		*cold = 0;
-	else
-		*cold = 1;
-
-	return ret;
-error:
-	deb_info("%s: failed:%d\n", __func__, ret);
-	return ret;
-}
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties ec168_properties;
-
-static int ec168_probe(struct usb_interface *intf,
-	const struct usb_device_id *id)
-{
-	int ret;
-	deb_info("%s: interface:%d\n", __func__,
-		intf->cur_altsetting->desc.bInterfaceNumber);
-
-	ret = dvb_usb_device_init(intf, &ec168_properties, THIS_MODULE, NULL,
-		adapter_nr);
-	if (ret)
-		goto error;
-
-	return ret;
-error:
-	deb_info("%s: failed:%d\n", __func__, ret);
-	return ret;
-}
-
-#define E3C_EC168_1689                          0
-#define E3C_EC168_FFFA                          1
-#define E3C_EC168_FFFB                          2
-#define E3C_EC168_1001                          3
-#define E3C_EC168_1002                          4
-
-static struct usb_device_id ec168_id[] = {
-	[E3C_EC168_1689] =
-		{USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168)},
-	[E3C_EC168_FFFA] =
-		{USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2)},
-	[E3C_EC168_FFFB] =
-		{USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3)},
-	[E3C_EC168_1001] =
-		{USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4)},
-	[E3C_EC168_1002] =
-		{USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5)},
-	{} /* terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, ec168_id);
-
-static struct dvb_usb_device_properties ec168_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = DEVICE_SPECIFIC,
-	.download_firmware = ec168_download_firmware,
-	.firmware = "dvb-usb-ec168.fw",
-	.no_reconnect = 1,
-
-	.size_of_priv = 0,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = ec168_streaming_ctrl,
-			.frontend_attach  = ec168_ec100_frontend_attach,
-			.tuner_attach     = ec168_mxl5003s_tuner_attach,
-			.stream = {
-				.type = USB_BULK,
-				.count = 6,
-				.endpoint = 0x82,
-				.u = {
-					.bulk = {
-						.buffersize = (32*512),
-					}
-				}
-			},
-		}},
-		}
-	},
-
-	.identify_state = ec168_identify_state,
-
-	.i2c_algo = &ec168_i2c_algo,
-
-	.num_device_descs = 1,
-	.devices = {
-		{
-			.name = "E3C EC168 DVB-T USB2.0 reference design",
-			.cold_ids = {
-				&ec168_id[E3C_EC168_1689],
-				&ec168_id[E3C_EC168_FFFA],
-				&ec168_id[E3C_EC168_FFFB],
-				&ec168_id[E3C_EC168_1001],
-				&ec168_id[E3C_EC168_1002],
-				NULL},
-			.warm_ids = {NULL},
-		},
-	}
-};
-
-static struct usb_driver ec168_driver = {
-	.name       = "dvb_usb_ec168",
-	.probe      = ec168_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table   = ec168_id,
-};
-
-module_usb_driver(ec168_driver);
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("E3C EC168 DVB-T USB2.0 driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/ec168.h b/drivers/media/dvb/dvb-usb/ec168.h
deleted file mode 100644
index e7e0b83..0000000
--- a/drivers/media/dvb/dvb-usb/ec168.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * E3C EC168 DVB USB driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef EC168_H
-#define EC168_H
-
-#define DVB_USB_LOG_PREFIX "ec168"
-#include "dvb-usb.h"
-
-#define deb_info(args...) dprintk(dvb_usb_ec168_debug, 0x01, args)
-#define deb_rc(args...)   dprintk(dvb_usb_ec168_debug, 0x02, args)
-#define deb_xfer(args...) dprintk(dvb_usb_ec168_debug, 0x04, args)
-#define deb_reg(args...)  dprintk(dvb_usb_ec168_debug, 0x08, args)
-#define deb_i2c(args...)  dprintk(dvb_usb_ec168_debug, 0x10, args)
-#define deb_fw(args...)   dprintk(dvb_usb_ec168_debug, 0x20, args)
-
-#define ec168_debug_dump(r, t, v, i, b, l, func) { \
-	int loop_; \
-	func("%02x %02x %02x %02x %02x %02x %02x %02x", \
-		t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \
-	if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
-		func(" >>> "); \
-	else \
-		func(" <<< "); \
-	for (loop_ = 0; loop_ < l; loop_++) \
-		func("%02x ", b[loop_]); \
-	func("\n");\
-}
-
-#define EC168_USB_TIMEOUT 1000
-
-struct ec168_req {
-	u8  cmd;       /* [1] */
-	u16 value;     /* [2|3] */
-	u16 index;     /* [4|5] */
-	u16 size;      /* [6|7] */
-	u8  *data;
-};
-
-enum ec168_cmd {
-	DOWNLOAD_FIRMWARE    = 0x00,
-	CONFIG               = 0x01,
-	DEMOD_RW             = 0x03,
-	GPIO                 = 0x04,
-	STREAMING_CTRL       = 0x10,
-	READ_I2C             = 0x20,
-	WRITE_I2C            = 0x21,
-	HID_DOWNLOAD         = 0x30,
-	GET_CONFIG,
-	SET_CONFIG,
-	READ_DEMOD,
-	WRITE_DEMOD,
-};
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/friio-fe.c b/drivers/media/dvb/dvb-usb/friio-fe.c
deleted file mode 100644
index 90a70c6..0000000
--- a/drivers/media/dvb/dvb-usb/friio-fe.c
+++ /dev/null
@@ -1,473 +0,0 @@
-/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
- *
- * Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
- *
- * This module is based off the the gl861 and vp702x modules.
- *
- * 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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "friio.h"
-
-struct jdvbt90502_state {
-	struct i2c_adapter *i2c;
-	struct dvb_frontend frontend;
-	struct jdvbt90502_config config;
-};
-
-/* NOTE: TC90502 has 16bit register-address? */
-/* register 0x0100 is used for reading PLL status, so reg is u16 here */
-static int jdvbt90502_reg_read(struct jdvbt90502_state *state,
-			       const u16 reg, u8 *buf, const size_t count)
-{
-	int ret;
-	u8 wbuf[3];
-	struct i2c_msg msg[2];
-
-	wbuf[0] = reg & 0xFF;
-	wbuf[1] = 0;
-	wbuf[2] = reg >> 8;
-
-	msg[0].addr = state->config.demod_address;
-	msg[0].flags = 0;
-	msg[0].buf = wbuf;
-	msg[0].len = sizeof(wbuf);
-
-	msg[1].addr = msg[0].addr;
-	msg[1].flags = I2C_M_RD;
-	msg[1].buf = buf;
-	msg[1].len = count;
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-	if (ret != 2) {
-		deb_fe(" reg read failed.\n");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-/* currently 16bit register-address is not used, so reg is u8 here */
-static int jdvbt90502_single_reg_write(struct jdvbt90502_state *state,
-				       const u8 reg, const u8 val)
-{
-	struct i2c_msg msg;
-	u8 wbuf[2];
-
-	wbuf[0] = reg;
-	wbuf[1] = val;
-
-	msg.addr = state->config.demod_address;
-	msg.flags = 0;
-	msg.buf = wbuf;
-	msg.len = sizeof(wbuf);
-
-	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
-		deb_fe(" reg write failed.");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int _jdvbt90502_write(struct dvb_frontend *fe, const u8 buf[], int len)
-{
-	struct jdvbt90502_state *state = fe->demodulator_priv;
-	int err, i;
-	for (i = 0; i < len - 1; i++) {
-		err = jdvbt90502_single_reg_write(state,
-						  buf[0] + i, buf[i + 1]);
-		if (err)
-			return err;
-	}
-
-	return 0;
-}
-
-/* read pll status byte via the demodulator's I2C register */
-/* note: Win box reads it by 8B block at the I2C addr 0x30 from reg:0x80 */
-static int jdvbt90502_pll_read(struct jdvbt90502_state *state, u8 *result)
-{
-	int ret;
-
-	/* +1 for reading */
-	u8 pll_addr_byte = (state->config.pll_address << 1) + 1;
-
-	*result = 0;
-
-	ret = jdvbt90502_single_reg_write(state, JDVBT90502_2ND_I2C_REG,
-					  pll_addr_byte);
-	if (ret)
-		goto error;
-
-	ret = jdvbt90502_reg_read(state, 0x0100, result, 1);
-	if (ret)
-		goto error;
-
-	deb_fe("PLL read val:%02x\n", *result);
-	return 0;
-
-error:
-	deb_fe("%s:ret == %d\n", __func__, ret);
-	return -EREMOTEIO;
-}
-
-
-/* set pll frequency via the demodulator's I2C register */
-static int jdvbt90502_pll_set_freq(struct jdvbt90502_state *state, u32 freq)
-{
-	int ret;
-	int retry;
-	u8 res1;
-	u8 res2[9];
-
-	u8 pll_freq_cmd[PLL_CMD_LEN];
-	u8 pll_agc_cmd[PLL_CMD_LEN];
-	struct i2c_msg msg[2];
-	u32 f;
-
-	deb_fe("%s: freq=%d, step=%d\n", __func__, freq,
-	       state->frontend.ops.info.frequency_stepsize);
-	/* freq -> oscilator frequency conversion. */
-	/* freq: 473,000,000 + n*6,000,000 [+ 142857 (center freq. shift)] */
-	f = freq / state->frontend.ops.info.frequency_stepsize;
-	/* add 399[1/7 MHZ] = 57MHz for the IF  */
-	f += 399;
-	/* add center frequency shift if necessary */
-	if (f % 7 == 0)
-		f++;
-	pll_freq_cmd[DEMOD_REDIRECT_REG] = JDVBT90502_2ND_I2C_REG; /* 0xFE */
-	pll_freq_cmd[ADDRESS_BYTE] = state->config.pll_address << 1;
-	pll_freq_cmd[DIVIDER_BYTE1] = (f >> 8) & 0x7F;
-	pll_freq_cmd[DIVIDER_BYTE2] = f & 0xFF;
-	pll_freq_cmd[CONTROL_BYTE] = 0xB2; /* ref.divider:28, 4MHz/28=1/7MHz */
-	pll_freq_cmd[BANDSWITCH_BYTE] = 0x08;	/* UHF band */
-
-	msg[0].addr = state->config.demod_address;
-	msg[0].flags = 0;
-	msg[0].buf = pll_freq_cmd;
-	msg[0].len = sizeof(pll_freq_cmd);
-
-	ret = i2c_transfer(state->i2c, &msg[0], 1);
-	if (ret != 1)
-		goto error;
-
-	udelay(50);
-
-	pll_agc_cmd[DEMOD_REDIRECT_REG] = pll_freq_cmd[DEMOD_REDIRECT_REG];
-	pll_agc_cmd[ADDRESS_BYTE] = pll_freq_cmd[ADDRESS_BYTE];
-	pll_agc_cmd[DIVIDER_BYTE1] = pll_freq_cmd[DIVIDER_BYTE1];
-	pll_agc_cmd[DIVIDER_BYTE2] = pll_freq_cmd[DIVIDER_BYTE2];
-	pll_agc_cmd[CONTROL_BYTE] = 0x9A; /*  AGC_CTRL instead of BANDSWITCH */
-	pll_agc_cmd[AGC_CTRL_BYTE] = 0x50;
-	/* AGC Time Constant 2s, AGC take-over point:103dBuV(lowest) */
-
-	msg[1].addr = msg[0].addr;
-	msg[1].flags = 0;
-	msg[1].buf = pll_agc_cmd;
-	msg[1].len = sizeof(pll_agc_cmd);
-
-	ret = i2c_transfer(state->i2c, &msg[1], 1);
-	if (ret != 1)
-		goto error;
-
-	/* I don't know what these cmds are for,  */
-	/* but the USB log on a windows box contains them */
-	ret = jdvbt90502_single_reg_write(state, 0x01, 0x40);
-	ret |= jdvbt90502_single_reg_write(state, 0x01, 0x00);
-	if (ret)
-		goto error;
-	udelay(100);
-
-	/* wait for the demod to be ready? */
-#define RETRY_COUNT 5
-	for (retry = 0; retry < RETRY_COUNT; retry++) {
-		ret = jdvbt90502_reg_read(state, 0x0096, &res1, 1);
-		if (ret)
-			goto error;
-		/* if (res1 != 0x00) goto error; */
-		ret = jdvbt90502_reg_read(state, 0x00B0, res2, sizeof(res2));
-		if (ret)
-			goto error;
-		if (res2[0] >= 0xA7)
-			break;
-		msleep(100);
-	}
-	if (retry >= RETRY_COUNT) {
-		deb_fe("%s: FE does not get ready after freq setting.\n",
-		       __func__);
-		return -EREMOTEIO;
-	}
-
-	return 0;
-error:
-	deb_fe("%s:ret == %d\n", __func__, ret);
-	return -EREMOTEIO;
-}
-
-static int jdvbt90502_read_status(struct dvb_frontend *fe, fe_status_t *state)
-{
-	u8 result;
-	int ret;
-
-	*state = FE_HAS_SIGNAL;
-
-	ret = jdvbt90502_pll_read(fe->demodulator_priv, &result);
-	if (ret) {
-		deb_fe("%s:ret == %d\n", __func__, ret);
-		return -EREMOTEIO;
-	}
-
-	*state = FE_HAS_SIGNAL
-		| FE_HAS_CARRIER
-		| FE_HAS_VITERBI
-		| FE_HAS_SYNC;
-
-	if (result & PLL_STATUS_LOCKED)
-		*state |= FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int jdvbt90502_read_signal_strength(struct dvb_frontend *fe,
-					   u16 *strength)
-{
-	int ret;
-	u8 rbuf[37];
-
-	*strength = 0;
-
-	/* status register (incl. signal strength) : 0x89  */
-	/* TODO: read just the necessary registers [0x8B..0x8D]? */
-	ret = jdvbt90502_reg_read(fe->demodulator_priv, 0x0089,
-				  rbuf, sizeof(rbuf));
-
-	if (ret) {
-		deb_fe("%s:ret == %d\n", __func__, ret);
-		return -EREMOTEIO;
-	}
-
-	/* signal_strength: rbuf[2-4] (24bit BE), use lower 16bit for now. */
-	*strength = (rbuf[3] << 8) + rbuf[4];
-	if (rbuf[2])
-		*strength = 0xffff;
-
-	return 0;
-}
-
-
-/* filter out un-supported properties to notify users */
-static int jdvbt90502_set_property(struct dvb_frontend *fe,
-				   struct dtv_property *tvp)
-{
-	int r = 0;
-
-	switch (tvp->cmd) {
-	case DTV_DELIVERY_SYSTEM:
-		if (tvp->u.data != SYS_ISDBT)
-			r = -EINVAL;
-		break;
-	case DTV_CLEAR:
-	case DTV_TUNE:
-	case DTV_FREQUENCY:
-		break;
-	default:
-		r = -EINVAL;
-	}
-	return r;
-}
-
-static int jdvbt90502_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	p->inversion = INVERSION_AUTO;
-	p->bandwidth_hz = 6000000;
-	p->code_rate_HP = FEC_AUTO;
-	p->code_rate_LP = FEC_AUTO;
-	p->modulation = QAM_64;
-	p->transmission_mode = TRANSMISSION_MODE_AUTO;
-	p->guard_interval = GUARD_INTERVAL_AUTO;
-	p->hierarchy = HIERARCHY_AUTO;
-	return 0;
-}
-
-static int jdvbt90502_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-
-	/**
-	 * NOTE: ignore all the parameters except frequency.
-	 *       others should be fixed to the proper value for ISDB-T,
-	 *       but don't check here.
-	 */
-
-	struct jdvbt90502_state *state = fe->demodulator_priv;
-	int ret;
-
-	deb_fe("%s: Freq:%d\n", __func__, p->frequency);
-
-	/* for recovery from DTV_CLEAN */
-	fe->dtv_property_cache.delivery_system = SYS_ISDBT;
-
-	ret = jdvbt90502_pll_set_freq(state, p->frequency);
-	if (ret) {
-		deb_fe("%s:ret == %d\n", __func__, ret);
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-
-/**
- * (reg, val) commad list to initialize this module.
- *  captured on a Windows box.
- */
-static u8 init_code[][2] = {
-	{0x01, 0x40},
-	{0x04, 0x38},
-	{0x05, 0x40},
-	{0x07, 0x40},
-	{0x0F, 0x4F},
-	{0x11, 0x21},
-	{0x12, 0x0B},
-	{0x13, 0x2F},
-	{0x14, 0x31},
-	{0x16, 0x02},
-	{0x21, 0xC4},
-	{0x22, 0x20},
-	{0x2C, 0x79},
-	{0x2D, 0x34},
-	{0x2F, 0x00},
-	{0x30, 0x28},
-	{0x31, 0x31},
-	{0x32, 0xDF},
-	{0x38, 0x01},
-	{0x39, 0x78},
-	{0x3B, 0x33},
-	{0x3C, 0x33},
-	{0x48, 0x90},
-	{0x51, 0x68},
-	{0x5E, 0x38},
-	{0x71, 0x00},
-	{0x72, 0x08},
-	{0x77, 0x00},
-	{0xC0, 0x21},
-	{0xC1, 0x10},
-	{0xE4, 0x1A},
-	{0xEA, 0x1F},
-	{0x77, 0x00},
-	{0x71, 0x00},
-	{0x71, 0x00},
-	{0x76, 0x0C},
-};
-
-static const int init_code_len = sizeof(init_code) / sizeof(u8[2]);
-
-static int jdvbt90502_init(struct dvb_frontend *fe)
-{
-	int i = -1;
-	int ret;
-	struct i2c_msg msg;
-
-	struct jdvbt90502_state *state = fe->demodulator_priv;
-
-	deb_fe("%s called.\n", __func__);
-
-	msg.addr = state->config.demod_address;
-	msg.flags = 0;
-	msg.len = 2;
-	for (i = 0; i < init_code_len; i++) {
-		msg.buf = init_code[i];
-		ret = i2c_transfer(state->i2c, &msg, 1);
-		if (ret != 1)
-			goto error;
-	}
-	fe->dtv_property_cache.delivery_system = SYS_ISDBT;
-	msleep(100);
-
-	return 0;
-
-error:
-	deb_fe("%s: init_code[%d] failed. ret==%d\n", __func__, i, ret);
-	return -EREMOTEIO;
-}
-
-
-static void jdvbt90502_release(struct dvb_frontend *fe)
-{
-	struct jdvbt90502_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-
-static struct dvb_frontend_ops jdvbt90502_ops;
-
-struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d)
-{
-	struct jdvbt90502_state *state = NULL;
-
-	deb_info("%s called.\n", __func__);
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct jdvbt90502_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->i2c = &d->i2c_adap;
-	memcpy(&state->config, &friio_fe_config, sizeof(friio_fe_config));
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &jdvbt90502_ops,
-	       sizeof(jdvbt90502_ops));
-	state->frontend.demodulator_priv = state;
-
-	if (jdvbt90502_init(&state->frontend) < 0)
-		goto error;
-
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops jdvbt90502_ops = {
-	.delsys = { SYS_ISDBT },
-	.info = {
-		.name			= "Comtech JDVBT90502 ISDB-T",
-		.frequency_min		= 473000000, /* UHF 13ch, center */
-		.frequency_max		= 767142857, /* UHF 62ch, center */
-		.frequency_stepsize	= JDVBT90502_PLL_CLK / JDVBT90502_PLL_DIVIDER,
-		.frequency_tolerance	= 0,
-
-		/* NOTE: this driver ignores all parameters but frequency. */
-		.caps = FE_CAN_INVERSION_AUTO |
-			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
-			FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
-			FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_HIERARCHY_AUTO,
-	},
-
-	.release = jdvbt90502_release,
-
-	.init = jdvbt90502_init,
-	.write = _jdvbt90502_write,
-
-	.set_property = jdvbt90502_set_property,
-
-	.set_frontend = jdvbt90502_set_frontend,
-	.get_frontend = jdvbt90502_get_frontend,
-
-	.read_status = jdvbt90502_read_status,
-	.read_signal_strength = jdvbt90502_read_signal_strength,
-};
diff --git a/drivers/media/dvb/dvb-usb/friio.c b/drivers/media/dvb/dvb-usb/friio.c
deleted file mode 100644
index 474a17e..0000000
--- a/drivers/media/dvb/dvb-usb/friio.c
+++ /dev/null
@@ -1,522 +0,0 @@
-/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
- *
- * Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
- *
- * This module is based off the the gl861 and vp702x modules.
- *
- * 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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "friio.h"
-
-/* debug */
-int dvb_usb_friio_debug;
-module_param_named(debug, dvb_usb_friio_debug, int, 0644);
-MODULE_PARM_DESC(debug,
-		 "set debugging level (1=info,2=xfer,4=rc,8=fe (or-able))."
-		 DVB_USB_DEBUG_STATUS);
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-/**
- * Indirect I2C access to the PLL via FE.
- * whole I2C protocol data to the PLL is sent via the FE's I2C register.
- * This is done by a control msg to the FE with the I2C data accompanied, and
- * a specific USB request number is assigned for that purpose.
- *
- * this func sends wbuf[1..] to the I2C register wbuf[0] at addr (= at FE).
- * TODO: refoctored, smarter i2c functions.
- */
-static int gl861_i2c_ctrlmsg_data(struct dvb_usb_device *d, u8 addr,
-				  u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
-{
-	u16 index = wbuf[0];	/* must be JDVBT90502_2ND_I2C_REG(=0xFE) */
-	u16 value = addr << (8 + 1);
-	int wo = (rbuf == NULL || rlen == 0);	/* write only */
-	u8 req, type;
-
-	deb_xfer("write to PLL:0x%02x via FE reg:0x%02x, len:%d\n",
-		 wbuf[1], wbuf[0], wlen - 1);
-
-	if (wo && wlen >= 2) {
-		req = GL861_REQ_I2C_DATA_CTRL_WRITE;
-		type = GL861_WRITE;
-		udelay(20);
-		return usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
-				       req, type, value, index,
-				       &wbuf[1], wlen - 1, 2000);
-	}
-
-	deb_xfer("not supported ctrl-msg, aborting.");
-	return -EINVAL;
-}
-
-/* normal I2C access (without extra data arguments).
- * write to the register wbuf[0] at I2C address addr with the value wbuf[1],
- *  or read from the register wbuf[0].
- * register address can be 16bit (wbuf[2]<<8 | wbuf[0]) if wlen==3
- */
-static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
-			 u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
-{
-	u16 index;
-	u16 value = addr << (8 + 1);
-	int wo = (rbuf == NULL || rlen == 0);	/* write-only */
-	u8 req, type;
-	unsigned int pipe;
-
-	/* special case for the indirect I2C access to the PLL via FE, */
-	if (addr == friio_fe_config.demod_address &&
-	    wbuf[0] == JDVBT90502_2ND_I2C_REG)
-		return gl861_i2c_ctrlmsg_data(d, addr, wbuf, wlen, rbuf, rlen);
-
-	if (wo) {
-		req = GL861_REQ_I2C_WRITE;
-		type = GL861_WRITE;
-		pipe = usb_sndctrlpipe(d->udev, 0);
-	} else {		/* rw */
-		req = GL861_REQ_I2C_READ;
-		type = GL861_READ;
-		pipe = usb_rcvctrlpipe(d->udev, 0);
-	}
-
-	switch (wlen) {
-	case 1:
-		index = wbuf[0];
-		break;
-	case 2:
-		index = wbuf[0];
-		value = value + wbuf[1];
-		break;
-	case 3:
-		/* special case for 16bit register-address */
-		index = (wbuf[2] << 8) | wbuf[0];
-		value = value + wbuf[1];
-		break;
-	default:
-		deb_xfer("wlen = %x, aborting.", wlen);
-		return -EINVAL;
-	}
-	msleep(1);
-	return usb_control_msg(d->udev, pipe, req, type,
-			       value, index, rbuf, rlen, 2000);
-}
-
-/* I2C */
-static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-			  int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int i;
-
-
-	if (num > 2)
-		return -EINVAL;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	for (i = 0; i < num; i++) {
-		/* write/read request */
-		if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) {
-			if (gl861_i2c_msg(d, msg[i].addr,
-					  msg[i].buf, msg[i].len,
-					  msg[i + 1].buf, msg[i + 1].len) < 0)
-				break;
-			i++;
-		} else
-			if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
-					  msg[i].len, NULL, 0) < 0)
-				break;
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return i;
-}
-
-static u32 gl861_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static int friio_ext_ctl(struct dvb_usb_adapter *adap,
-			 u32 sat_color, int lnb_on)
-{
-	int i;
-	int ret;
-	struct i2c_msg msg;
-	u8 *buf;
-	u32 mask;
-	u8 lnb = (lnb_on) ? FRIIO_CTL_LNB : 0;
-
-	buf = kmalloc(2, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	msg.addr = 0x00;
-	msg.flags = 0;
-	msg.len = 2;
-	msg.buf = buf;
-
-	buf[0] = 0x00;
-
-	/* send 2bit header (&B10) */
-	buf[1] = lnb | FRIIO_CTL_LED | FRIIO_CTL_STROBE;
-	ret = gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
-	buf[1] |= FRIIO_CTL_CLK;
-	ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
-
-	buf[1] = lnb | FRIIO_CTL_STROBE;
-	ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
-	buf[1] |= FRIIO_CTL_CLK;
-	ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
-
-	/* send 32bit(satur, R, G, B) data in serial */
-	mask = 1 << 31;
-	for (i = 0; i < 32; i++) {
-		buf[1] = lnb | FRIIO_CTL_STROBE;
-		if (sat_color & mask)
-			buf[1] |= FRIIO_CTL_LED;
-		ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
-		buf[1] |= FRIIO_CTL_CLK;
-		ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
-		mask >>= 1;
-	}
-
-	/* set the strobe off */
-	buf[1] = lnb;
-	ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
-	buf[1] |= FRIIO_CTL_CLK;
-	ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
-
-	kfree(buf);
-	return (ret == 70);
-}
-
-
-static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
-
-/* TODO: move these init cmds to the FE's init routine? */
-static u8 streaming_init_cmds[][2] = {
-	{0x33, 0x08},
-	{0x37, 0x40},
-	{0x3A, 0x1F},
-	{0x3B, 0xFF},
-	{0x3C, 0x1F},
-	{0x3D, 0xFF},
-	{0x38, 0x00},
-	{0x35, 0x00},
-	{0x39, 0x00},
-	{0x36, 0x00},
-};
-static int cmdlen = sizeof(streaming_init_cmds) / 2;
-
-/*
- * Command sequence in this init function is a replay
- *  of the captured USB commands from the Windows proprietary driver.
- */
-static int friio_initialize(struct dvb_usb_device *d)
-{
-	int ret;
-	int i;
-	int retry = 0;
-	u8 *rbuf, *wbuf;
-
-	deb_info("%s called.\n", __func__);
-
-	wbuf = kmalloc(3, GFP_KERNEL);
-	if (!wbuf)
-		return -ENOMEM;
-
-	rbuf = kmalloc(2, GFP_KERNEL);
-	if (!rbuf) {
-		kfree(wbuf);
-		return -ENOMEM;
-	}
-
-	/* use gl861_i2c_msg instead of gl861_i2c_xfer(), */
-	/* because the i2c device is not set up yet. */
-	wbuf[0] = 0x11;
-	wbuf[1] = 0x02;
-	ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
-	if (ret < 0)
-		goto error;
-	msleep(2);
-
-	wbuf[0] = 0x11;
-	wbuf[1] = 0x00;
-	ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
-	if (ret < 0)
-		goto error;
-	msleep(1);
-
-	/* following msgs should be in the FE's init code? */
-	/* cmd sequence to identify the device type? (friio black/white) */
-	wbuf[0] = 0x03;
-	wbuf[1] = 0x80;
-	/* can't use gl861_i2c_cmd, as the register-addr is 16bit(0x0100) */
-	ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
-			      GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE,
-			      0x1200, 0x0100, wbuf, 2, 2000);
-	if (ret < 0)
-		goto error;
-
-	msleep(2);
-	wbuf[0] = 0x00;
-	wbuf[2] = 0x01;		/* reg.0x0100 */
-	wbuf[1] = 0x00;
-	ret = gl861_i2c_msg(d, 0x12 >> 1, wbuf, 3, rbuf, 2);
-	/* my Friio White returns 0xffff. */
-	if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff)
-		goto error;
-
-	msleep(2);
-	wbuf[0] = 0x03;
-	wbuf[1] = 0x80;
-	ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
-			      GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE,
-			      0x9000, 0x0100, wbuf, 2, 2000);
-	if (ret < 0)
-		goto error;
-
-	msleep(2);
-	wbuf[0] = 0x00;
-	wbuf[2] = 0x01;		/* reg.0x0100 */
-	wbuf[1] = 0x00;
-	ret = gl861_i2c_msg(d, 0x90 >> 1, wbuf, 3, rbuf, 2);
-	/* my Friio White returns 0xffff again. */
-	if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff)
-		goto error;
-
-	msleep(1);
-
-restart:
-	/* ============ start DEMOD init cmds ================== */
-	/* read PLL status to clear the POR bit */
-	wbuf[0] = JDVBT90502_2ND_I2C_REG;
-	wbuf[1] = (FRIIO_PLL_ADDR << 1) + 1;	/* +1 for reading */
-	ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, NULL, 0);
-	if (ret < 0)
-		goto error;
-
-	msleep(5);
-	/* note: DEMODULATOR has 16bit register-address. */
-	wbuf[0] = 0x00;
-	wbuf[2] = 0x01;		/* reg addr: 0x0100 */
-	wbuf[1] = 0x00;		/* val: not used */
-	ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 3, rbuf, 1);
-	if (ret < 0)
-		goto error;
-/*
-	msleep(1);
-	wbuf[0] = 0x80;
-	wbuf[1] = 0x00;
-	ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, rbuf, 1);
-	if (ret < 0)
-		goto error;
- */
-	if (rbuf[0] & 0x80) {	/* still in PowerOnReset state? */
-		if (++retry > 3) {
-			deb_info("failed to get the correct"
-				 " FE demod status:0x%02x\n", rbuf[0]);
-			goto error;
-		}
-		msleep(100);
-		goto restart;
-	}
-
-	/* TODO: check return value in rbuf */
-	/* =========== end DEMOD init cmds ===================== */
-	msleep(1);
-
-	wbuf[0] = 0x30;
-	wbuf[1] = 0x04;
-	ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
-	if (ret < 0)
-		goto error;
-
-	msleep(2);
-	/* following 2 cmds unnecessary? */
-	wbuf[0] = 0x00;
-	wbuf[1] = 0x01;
-	ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
-	if (ret < 0)
-		goto error;
-
-	wbuf[0] = 0x06;
-	wbuf[1] = 0x0F;
-	ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
-	if (ret < 0)
-		goto error;
-
-	/* some streaming ctl cmds (maybe) */
-	msleep(10);
-	for (i = 0; i < cmdlen; i++) {
-		ret = gl861_i2c_msg(d, 0x00, streaming_init_cmds[i], 2,
-				    NULL, 0);
-		if (ret < 0)
-			goto error;
-		msleep(1);
-	}
-	msleep(20);
-
-	/* change the LED color etc. */
-	ret = friio_streaming_ctrl(&d->adapter[0], 0);
-	if (ret < 0)
-		goto error;
-
-	return 0;
-
-error:
-	kfree(wbuf);
-	kfree(rbuf);
-	deb_info("%s:ret == %d\n", __func__, ret);
-	return -EIO;
-}
-
-/* Callbacks for DVB USB */
-
-static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	int ret;
-
-	deb_info("%s called.(%d)\n", __func__, onoff);
-
-	/* set the LED color and saturation (and LNB on) */
-	if (onoff)
-		ret = friio_ext_ctl(adap, 0x6400ff64, 1);
-	else
-		ret = friio_ext_ctl(adap, 0x96ff00ff, 1);
-
-	if (ret != 1) {
-		deb_info("%s failed to send cmdx. ret==%d\n", __func__, ret);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int friio_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	if (friio_initialize(adap->dev) < 0)
-		return -EIO;
-
-	adap->fe_adap[0].fe = jdvbt90502_attach(adap->dev);
-	if (adap->fe_adap[0].fe == NULL)
-		return -EIO;
-
-	return 0;
-}
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties friio_properties;
-
-static int friio_probe(struct usb_interface *intf,
-		       const struct usb_device_id *id)
-{
-	struct dvb_usb_device *d;
-	struct usb_host_interface *alt;
-	int ret;
-
-	if (intf->num_altsetting < GL861_ALTSETTING_COUNT)
-		return -ENODEV;
-
-	alt = usb_altnum_to_altsetting(intf, FRIIO_BULK_ALTSETTING);
-	if (alt == NULL) {
-		deb_rc("not alt found!\n");
-		return -ENODEV;
-	}
-	ret = usb_set_interface(interface_to_usbdev(intf),
-				alt->desc.bInterfaceNumber,
-				alt->desc.bAlternateSetting);
-	if (ret != 0) {
-		deb_rc("failed to set alt-setting!\n");
-		return ret;
-	}
-
-	ret = dvb_usb_device_init(intf, &friio_properties,
-				  THIS_MODULE, &d, adapter_nr);
-	if (ret == 0)
-		friio_streaming_ctrl(&d->adapter[0], 1);
-
-	return ret;
-}
-
-
-struct jdvbt90502_config friio_fe_config = {
-	.demod_address = FRIIO_DEMOD_ADDR,
-	.pll_address = FRIIO_PLL_ADDR,
-};
-
-static struct i2c_algorithm gl861_i2c_algo = {
-	.master_xfer   = gl861_i2c_xfer,
-	.functionality = gl861_i2c_func,
-};
-
-static struct usb_device_id friio_table[] = {
-	{ USB_DEVICE(USB_VID_774, USB_PID_FRIIO_WHITE) },
-	{ }		/* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, friio_table);
-
-
-static struct dvb_usb_device_properties friio_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-	.usb_ctrl = DEVICE_SPECIFIC,
-
-	.size_of_priv = 0,
-
-	.num_adapters = 1,
-	.adapter = {
-		/* caps:0 =>  no pid filter, 188B TS packet */
-		/* GL861 has a HW pid filter, but no info available. */
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.caps  = 0,
-
-			.frontend_attach  = friio_frontend_attach,
-			.streaming_ctrl = friio_streaming_ctrl,
-
-			.stream = {
-				.type = USB_BULK,
-				/* count <= MAX_NO_URBS_FOR_DATA_STREAM(10) */
-				.count = 8,
-				.endpoint = 0x01,
-				.u = {
-					/* GL861 has 6KB buf inside */
-					.bulk = {
-						.buffersize = 16384,
-					}
-				}
-			},
-		}},
-		}
-	},
-	.i2c_algo = &gl861_i2c_algo,
-
-	.num_device_descs = 1,
-	.devices = {
-		{
-			.name = "774 Friio ISDB-T USB2.0",
-			.cold_ids = { NULL },
-			.warm_ids = { &friio_table[0], NULL },
-		},
-	}
-};
-
-static struct usb_driver friio_driver = {
-	.name		= "dvb_usb_friio",
-	.probe		= friio_probe,
-	.disconnect	= dvb_usb_device_exit,
-	.id_table	= friio_table,
-};
-
-module_usb_driver(friio_driver);
-
-MODULE_AUTHOR("Akihiro Tsukada <tskd2@yahoo.co.jp>");
-MODULE_DESCRIPTION("Driver for Friio ISDB-T USB2.0 Receiver");
-MODULE_VERSION("0.2");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/friio.h b/drivers/media/dvb/dvb-usb/friio.h
deleted file mode 100644
index 0f461ca..0000000
--- a/drivers/media/dvb/dvb-usb/friio.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
- *
- * Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
- *
- * This module is based off the the gl861 and vp702x modules.
- *
- * 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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#ifndef _DVB_USB_FRIIO_H_
-#define _DVB_USB_FRIIO_H_
-
-/**
- *      Friio Components
- *       USB hub:                                AU4254
- *         USB controller(+ TS dmx & streaming): GL861
- *         Frontend:                             comtech JDVBT-90502
- *             (tuner PLL:                       tua6034, I2C addr:(0xC0 >> 1))
- *             (OFDM demodulator:                TC90502, I2C addr:(0x30 >> 1))
- *         LED x3 (+LNB) control:                PIC 16F676
- *         EEPROM:                               24C08
- *
- *        (USB smart card reader:                AU9522)
- *
- */
-
-#define DVB_USB_LOG_PREFIX "friio"
-#include "dvb-usb.h"
-
-extern int dvb_usb_friio_debug;
-#define deb_info(args...) dprintk(dvb_usb_friio_debug, 0x01, args)
-#define deb_xfer(args...) dprintk(dvb_usb_friio_debug, 0x02, args)
-#define deb_rc(args...)   dprintk(dvb_usb_friio_debug, 0x04, args)
-#define deb_fe(args...)   dprintk(dvb_usb_friio_debug, 0x08, args)
-
-/* Vendor requests */
-#define GL861_WRITE		0x40
-#define GL861_READ		0xc0
-
-/* command bytes */
-#define GL861_REQ_I2C_WRITE	0x01
-#define GL861_REQ_I2C_READ	0x02
-/* For control msg with data argument */
-/* Used for accessing the PLL on the secondary I2C bus of FE via GL861 */
-#define GL861_REQ_I2C_DATA_CTRL_WRITE	0x03
-
-#define GL861_ALTSETTING_COUNT	2
-#define FRIIO_BULK_ALTSETTING	0
-#define FRIIO_ISOC_ALTSETTING	1
-
-/* LED & LNB control via PIC. */
-/* basically, it's serial control with clock and strobe. */
-/* write the below 4bit control data to the reg 0x00 at the I2C addr 0x00 */
-/* when controlling the LEDs, 32bit(saturation, R, G, B) is sent on the bit3*/
-#define FRIIO_CTL_LNB (1 << 0)
-#define FRIIO_CTL_STROBE (1 << 1)
-#define FRIIO_CTL_CLK (1 << 2)
-#define FRIIO_CTL_LED (1 << 3)
-
-/* Front End related */
-
-#define FRIIO_DEMOD_ADDR  (0x30 >> 1)
-#define FRIIO_PLL_ADDR  (0xC0 >> 1)
-
-#define JDVBT90502_PLL_CLK	4000000
-#define JDVBT90502_PLL_DIVIDER	28
-
-#define JDVBT90502_2ND_I2C_REG 0xFE
-
-/* byte index for pll i2c command data structure*/
-/* see datasheet for tua6034 */
-#define DEMOD_REDIRECT_REG 0
-#define ADDRESS_BYTE       1
-#define DIVIDER_BYTE1      2
-#define DIVIDER_BYTE2      3
-#define CONTROL_BYTE       4
-#define BANDSWITCH_BYTE    5
-#define AGC_CTRL_BYTE      5
-#define PLL_CMD_LEN        6
-
-/* bit masks for PLL STATUS response */
-#define PLL_STATUS_POR_MODE   0x80 /* 1: Power on Reset (test) Mode */
-#define PLL_STATUS_LOCKED     0x40 /* 1: locked */
-#define PLL_STATUS_AGC_ACTIVE 0x08 /* 1:active */
-#define PLL_STATUS_TESTMODE   0x07 /* digital output level (5 level) */
-  /* 0.15Vcc step   0x00: < 0.15Vcc, ..., 0x04: >= 0.6Vcc (<= 1Vcc) */
-
-
-struct jdvbt90502_config {
-	u8 demod_address; /* i2c addr for demodulator IC */
-	u8 pll_address;   /* PLL addr on the secondary i2c*/
-};
-extern struct jdvbt90502_config friio_fe_config;
-
-extern struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d);
-#endif
diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
deleted file mode 100644
index c1f5582..0000000
--- a/drivers/media/dvb/dvb-usb/gl861.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/* DVB USB compliant linux driver for GL861 USB2.0 devices.
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "gl861.h"
-
-#include "zl10353.h"
-#include "qt1010.h"
-
-/* debug */
-static int dvb_usb_gl861_debug;
-module_param_named(debug, dvb_usb_gl861_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))."
-	DVB_USB_DEBUG_STATUS);
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
-			 u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
-{
-	u16 index;
-	u16 value = addr << (8 + 1);
-	int wo = (rbuf == NULL || rlen == 0); /* write-only */
-	u8 req, type;
-
-	if (wo) {
-		req = GL861_REQ_I2C_WRITE;
-		type = GL861_WRITE;
-	} else { /* rw */
-		req = GL861_REQ_I2C_READ;
-		type = GL861_READ;
-	}
-
-	switch (wlen) {
-	case 1:
-		index = wbuf[0];
-		break;
-	case 2:
-		index = wbuf[0];
-		value = value + wbuf[1];
-		break;
-	default:
-		warn("wlen = %x, aborting.", wlen);
-		return -EINVAL;
-	}
-
-	msleep(1); /* avoid I2C errors */
-
-	return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type,
-			       value, index, rbuf, rlen, 2000);
-}
-
-/* I2C */
-static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-			  int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int i;
-
-	if (num > 2)
-		return -EINVAL;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	for (i = 0; i < num; i++) {
-		/* write/read request */
-		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
-			if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
-				msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
-				break;
-			i++;
-		} else
-			if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
-					  msg[i].len, NULL, 0) < 0)
-				break;
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return i;
-}
-
-static u32 gl861_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm gl861_i2c_algo = {
-	.master_xfer   = gl861_i2c_xfer,
-	.functionality = gl861_i2c_func,
-};
-
-/* Callbacks for DVB USB */
-static struct zl10353_config gl861_zl10353_config = {
-	.demod_address = 0x0f,
-	.no_tuner = 1,
-	.parallel_ts = 1,
-};
-
-static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
-{
-
-	adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
-		&adap->dev->i2c_adap);
-	if (adap->fe_adap[0].fe == NULL)
-		return -EIO;
-
-	return 0;
-}
-
-static struct qt1010_config gl861_qt1010_config = {
-	.i2c_address = 0x62
-};
-
-static int gl861_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	return dvb_attach(qt1010_attach,
-			  adap->fe_adap[0].fe, &adap->dev->i2c_adap,
-			  &gl861_qt1010_config) == NULL ? -ENODEV : 0;
-}
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties gl861_properties;
-
-static int gl861_probe(struct usb_interface *intf,
-		       const struct usb_device_id *id)
-{
-	struct dvb_usb_device *d;
-	struct usb_host_interface *alt;
-	int ret;
-
-	if (intf->num_altsetting < 2)
-		return -ENODEV;
-
-	ret = dvb_usb_device_init(intf, &gl861_properties, THIS_MODULE, &d,
-				  adapter_nr);
-	if (ret == 0) {
-		alt = usb_altnum_to_altsetting(intf, 0);
-
-		if (alt == NULL) {
-			deb_rc("not alt found!\n");
-			return -ENODEV;
-		}
-
-		ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
-					alt->desc.bAlternateSetting);
-	}
-
-	return ret;
-}
-
-static struct usb_device_id gl861_table [] = {
-		{ USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) },
-		{ USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) },
-		{ }		/* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, gl861_table);
-
-static struct dvb_usb_device_properties gl861_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-	.usb_ctrl = DEVICE_SPECIFIC,
-
-	.size_of_priv     = 0,
-
-	.num_adapters = 1,
-	.adapter = {{
-		.num_frontends = 1,
-		.fe = {{
-
-		.frontend_attach  = gl861_frontend_attach,
-		.tuner_attach     = gl861_tuner_attach,
-
-		.stream = {
-			.type = USB_BULK,
-			.count = 7,
-			.endpoint = 0x81,
-			.u = {
-				.bulk = {
-					.buffersize = 512,
-				}
-			}
-		},
-		}},
-	} },
-	.i2c_algo         = &gl861_i2c_algo,
-
-	.num_device_descs = 2,
-	.devices = {
-		{
-			.name = "MSI Mega Sky 55801 DVB-T USB2.0",
-			.cold_ids = { NULL },
-			.warm_ids = { &gl861_table[0], NULL },
-		},
-		{
-			.name = "A-LINK DTU DVB-T USB2.0",
-			.cold_ids = { NULL },
-			.warm_ids = { &gl861_table[1], NULL },
-		},
-	}
-};
-
-static struct usb_driver gl861_driver = {
-	.name		= "dvb_usb_gl861",
-	.probe		= gl861_probe,
-	.disconnect	= dvb_usb_device_exit,
-	.id_table	= gl861_table,
-};
-
-module_usb_driver(gl861_driver);
-
-MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>");
-MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861");
-MODULE_VERSION("0.1");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/gl861.h b/drivers/media/dvb/dvb-usb/gl861.h
deleted file mode 100644
index c54855e..0000000
--- a/drivers/media/dvb/dvb-usb/gl861.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef _DVB_USB_GL861_H_
-#define _DVB_USB_GL861_H_
-
-#define DVB_USB_LOG_PREFIX "gl861"
-#include "dvb-usb.h"
-
-#define deb_rc(args...)   dprintk(dvb_usb_gl861_debug, 0x01, args)
-
-#define GL861_WRITE		0x40
-#define GL861_READ		0xc0
-
-#define GL861_REQ_I2C_WRITE	0x01
-#define GL861_REQ_I2C_READ	0x02
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
deleted file mode 100644
index 67957dd..0000000
--- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c
+++ /dev/null
@@ -1,369 +0,0 @@
-/* DVB USB compliant Linux driver for the
- *  - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
- *
- * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
- * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com)
- *
- * Thanks to GENPIX for the sample code used to implement this module.
- *
- * This module is based off the vp7045 and vp702x modules
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "gp8psk.h"
-
-struct gp8psk_fe_state {
-	struct dvb_frontend fe;
-	struct dvb_usb_device *d;
-	u8 lock;
-	u16 snr;
-	unsigned long next_status_check;
-	unsigned long status_check_interval;
-};
-
-static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe)
-{
-	struct gp8psk_fe_state *st = fe->demodulator_priv;
-	u8 status;
-	gp8psk_usb_in_op(st->d, GET_8PSK_CONFIG, 0, 0, &status, 1);
-	return status & bmDCtuned;
-}
-
-static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode)
-{
-	struct gp8psk_fe_state *state = fe->demodulator_priv;
-	return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0);
-}
-
-static int gp8psk_fe_update_status(struct gp8psk_fe_state *st)
-{
-	u8 buf[6];
-	if (time_after(jiffies,st->next_status_check)) {
-		gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1);
-		gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6);
-		st->snr = (buf[1]) << 8 | buf[0];
-		st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
-	}
-	return 0;
-}
-
-static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
-{
-	struct gp8psk_fe_state *st = fe->demodulator_priv;
-	gp8psk_fe_update_status(st);
-
-	if (st->lock)
-		*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
-	else
-		*status = 0;
-
-	if (*status & FE_HAS_LOCK)
-		st->status_check_interval = 1000;
-	else
-		st->status_check_interval = 100;
-	return 0;
-}
-
-/* not supported by this Frontend */
-static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
-{
-	(void) fe;
-	*ber = 0;
-	return 0;
-}
-
-/* not supported by this Frontend */
-static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
-{
-	(void) fe;
-	*unc = 0;
-	return 0;
-}
-
-static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
-{
-	struct gp8psk_fe_state *st = fe->demodulator_priv;
-	gp8psk_fe_update_status(st);
-	/* snr is reported in dBu*256 */
-	*snr = st->snr;
-	return 0;
-}
-
-static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
-{
-	struct gp8psk_fe_state *st = fe->demodulator_priv;
-	gp8psk_fe_update_status(st);
-	/* snr is reported in dBu*256 */
-	/* snr / 38.4 ~= 100% strength */
-	/* snr * 17 returns 100% strength as 65535 */
-	if (st->snr > 0xf00)
-		*strength = 0xffff;
-	else
-		*strength = (st->snr << 4) + st->snr; /* snr*17 */
-	return 0;
-}
-
-static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
-{
-	tune->min_delay_ms = 800;
-	return 0;
-}
-
-static int gp8psk_fe_set_frontend(struct dvb_frontend *fe)
-{
-	struct gp8psk_fe_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u8 cmd[10];
-	u32 freq = c->frequency * 1000;
-	int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct);
-
-	deb_fe("%s()\n", __func__);
-
-	cmd[4] = freq         & 0xff;
-	cmd[5] = (freq >> 8)  & 0xff;
-	cmd[6] = (freq >> 16) & 0xff;
-	cmd[7] = (freq >> 24) & 0xff;
-
-	/* backwards compatibility: DVB-S + 8-PSK were used for Turbo-FEC */
-	if (c->delivery_system == SYS_DVBS && c->modulation == PSK_8)
-		c->delivery_system = SYS_TURBO;
-
-	switch (c->delivery_system) {
-	case SYS_DVBS:
-		if (c->modulation != QPSK) {
-			deb_fe("%s: unsupported modulation selected (%d)\n",
-				__func__, c->modulation);
-			return -EOPNOTSUPP;
-		}
-		c->fec_inner = FEC_AUTO;
-		break;
-	case SYS_DVBS2: /* kept for backwards compatibility */
-		deb_fe("%s: DVB-S2 delivery system selected\n", __func__);
-		break;
-	case SYS_TURBO:
-		deb_fe("%s: Turbo-FEC delivery system selected\n", __func__);
-		break;
-
-	default:
-		deb_fe("%s: unsupported delivery system selected (%d)\n",
-			__func__, c->delivery_system);
-		return -EOPNOTSUPP;
-	}
-
-	cmd[0] =  c->symbol_rate        & 0xff;
-	cmd[1] = (c->symbol_rate >>  8) & 0xff;
-	cmd[2] = (c->symbol_rate >> 16) & 0xff;
-	cmd[3] = (c->symbol_rate >> 24) & 0xff;
-	switch (c->modulation) {
-	case QPSK:
-		if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
-			if (gp8psk_tuned_to_DCII(fe))
-				gp8psk_bcm4500_reload(state->d);
-		switch (c->fec_inner) {
-		case FEC_1_2:
-			cmd[9] = 0; break;
-		case FEC_2_3:
-			cmd[9] = 1; break;
-		case FEC_3_4:
-			cmd[9] = 2; break;
-		case FEC_5_6:
-			cmd[9] = 3; break;
-		case FEC_7_8:
-			cmd[9] = 4; break;
-		case FEC_AUTO:
-			cmd[9] = 5; break;
-		default:
-			cmd[9] = 5; break;
-		}
-		if (c->delivery_system == SYS_TURBO)
-			cmd[8] = ADV_MOD_TURBO_QPSK;
-		else
-			cmd[8] = ADV_MOD_DVB_QPSK;
-		break;
-	case PSK_8: /* PSK_8 is for compatibility with DN */
-		cmd[8] = ADV_MOD_TURBO_8PSK;
-		switch (c->fec_inner) {
-		case FEC_2_3:
-			cmd[9] = 0; break;
-		case FEC_3_4:
-			cmd[9] = 1; break;
-		case FEC_3_5:
-			cmd[9] = 2; break;
-		case FEC_5_6:
-			cmd[9] = 3; break;
-		case FEC_8_9:
-			cmd[9] = 4; break;
-		default:
-			cmd[9] = 0; break;
-		}
-		break;
-	case QAM_16: /* QAM_16 is for compatibility with DN */
-		cmd[8] = ADV_MOD_TURBO_16QAM;
-		cmd[9] = 0;
-		break;
-	default: /* Unknown modulation */
-		deb_fe("%s: unsupported modulation selected (%d)\n",
-			__func__, c->modulation);
-		return -EOPNOTSUPP;
-	}
-
-	if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
-		gp8psk_set_tuner_mode(fe, 0);
-	gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10);
-
-	state->lock = 0;
-	state->next_status_check = jiffies;
-	state->status_check_interval = 200;
-
-	return 0;
-}
-
-static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
-				    struct dvb_diseqc_master_cmd *m)
-{
-	struct gp8psk_fe_state *st = fe->demodulator_priv;
-
-	deb_fe("%s\n",__func__);
-
-	if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0,
-			m->msg, m->msg_len)) {
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe,
-				    fe_sec_mini_cmd_t burst)
-{
-	struct gp8psk_fe_state *st = fe->demodulator_priv;
-	u8 cmd;
-
-	deb_fe("%s\n",__func__);
-
-	/* These commands are certainly wrong */
-	cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01;
-
-	if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0,
-			&cmd, 0)) {
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
-	struct gp8psk_fe_state* state = fe->demodulator_priv;
-
-	if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE,
-		 (tone == SEC_TONE_ON), 0, NULL, 0)) {
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
-	struct gp8psk_fe_state* state = fe->demodulator_priv;
-
-	if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE,
-			 voltage == SEC_VOLTAGE_18, 0, NULL, 0)) {
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff)
-{
-	struct gp8psk_fe_state* state = fe->demodulator_priv;
-	return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0);
-}
-
-static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd)
-{
-	struct gp8psk_fe_state* state = fe->demodulator_priv;
-	u8 cmd = sw_cmd & 0x7f;
-
-	if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0,
-			NULL, 0)) {
-		return -EINVAL;
-	}
-	if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80),
-			0, NULL, 0)) {
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static void gp8psk_fe_release(struct dvb_frontend* fe)
-{
-	struct gp8psk_fe_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops gp8psk_fe_ops;
-
-struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d)
-{
-	struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL);
-	if (s == NULL)
-		goto error;
-
-	s->d = d;
-	memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops));
-	s->fe.demodulator_priv = s;
-
-	goto success;
-error:
-	return NULL;
-success:
-	return &s->fe;
-}
-
-
-static struct dvb_frontend_ops gp8psk_fe_ops = {
-	.delsys = { SYS_DVBS },
-	.info = {
-		.name			= "Genpix DVB-S",
-		.frequency_min		= 800000,
-		.frequency_max		= 2250000,
-		.frequency_stepsize	= 100,
-		.symbol_rate_min        = 1000000,
-		.symbol_rate_max        = 45000000,
-		.symbol_rate_tolerance  = 500,  /* ppm */
-		.caps = FE_CAN_INVERSION_AUTO |
-			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			/*
-			 * FE_CAN_QAM_16 is for compatibility
-			 * (Myth incorrectly detects Turbo-QPSK as plain QAM-16)
-			 */
-			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_TURBO_FEC
-	},
-
-	.release = gp8psk_fe_release,
-
-	.init = NULL,
-	.sleep = NULL,
-
-	.set_frontend = gp8psk_fe_set_frontend,
-
-	.get_tune_settings = gp8psk_fe_get_tune_settings,
-
-	.read_status = gp8psk_fe_read_status,
-	.read_ber = gp8psk_fe_read_ber,
-	.read_signal_strength = gp8psk_fe_read_signal_strength,
-	.read_snr = gp8psk_fe_read_snr,
-	.read_ucblocks = gp8psk_fe_read_unc_blocks,
-
-	.diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg,
-	.diseqc_send_burst = gp8psk_fe_send_diseqc_burst,
-	.set_tone = gp8psk_fe_set_tone,
-	.set_voltage = gp8psk_fe_set_voltage,
-	.dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd,
-	.enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage
-};
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
deleted file mode 100644
index 5d0384d..0000000
--- a/drivers/media/dvb/dvb-usb/gp8psk.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/* DVB USB compliant Linux driver for the
- *  - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
- *
- * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
- * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com)
- *
- * Thanks to GENPIX for the sample code used to implement this module.
- *
- * This module is based off the vp7045 and vp702x modules
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "gp8psk.h"
-
-/* debug */
-static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw";
-int dvb_usb_gp8psk_debug;
-module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers)
-{
-	return (gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6));
-}
-
-static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers)
-{
-	return (gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1));
-}
-
-static void gp8psk_info(struct dvb_usb_device *d)
-{
-	u8 fpga_vers, fw_vers[6];
-
-	if (!gp8psk_get_fw_version(d, fw_vers))
-		info("FW Version = %i.%02i.%i (0x%x)  Build %4i/%02i/%02i",
-		fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers),
-		2000 + fw_vers[5], fw_vers[4], fw_vers[3]);
-	else
-		info("failed to get FW version");
-
-	if (!gp8psk_get_fpga_version(d, &fpga_vers))
-		info("FPGA Version = %i", fpga_vers);
-	else
-		info("failed to get FPGA version");
-}
-
-int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
-{
-	int ret = 0,try = 0;
-
-	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
-		return ret;
-
-	while (ret >= 0 && ret != blen && try < 3) {
-		ret = usb_control_msg(d->udev,
-			usb_rcvctrlpipe(d->udev,0),
-			req,
-			USB_TYPE_VENDOR | USB_DIR_IN,
-			value,index,b,blen,
-			2000);
-		deb_info("reading number %d (ret: %d)\n",try,ret);
-		try++;
-	}
-
-	if (ret < 0 || ret != blen) {
-		warn("usb in %d operation failed.", req);
-		ret = -EIO;
-	} else
-		ret = 0;
-
-	deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
-	debug_dump(b,blen,deb_xfer);
-
-	mutex_unlock(&d->usb_mutex);
-
-	return ret;
-}
-
-int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
-			     u16 index, u8 *b, int blen)
-{
-	int ret;
-
-	deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
-	debug_dump(b,blen,deb_xfer);
-
-	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
-		return ret;
-
-	if (usb_control_msg(d->udev,
-			usb_sndctrlpipe(d->udev,0),
-			req,
-			USB_TYPE_VENDOR | USB_DIR_OUT,
-			value,index,b,blen,
-			2000) != blen) {
-		warn("usb out operation failed.");
-		ret = -EIO;
-	} else
-		ret = 0;
-	mutex_unlock(&d->usb_mutex);
-
-	return ret;
-}
-
-static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
-{
-	int ret;
-	const struct firmware *fw = NULL;
-	const u8 *ptr;
-	u8 *buf;
-	if ((ret = request_firmware(&fw, bcm4500_firmware,
-					&d->udev->dev)) != 0) {
-		err("did not find the bcm4500 firmware file. (%s) "
-			"Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
-			bcm4500_firmware,ret);
-		return ret;
-	}
-
-	ret = -EINVAL;
-
-	if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0))
-		goto out_rel_fw;
-
-	info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware);
-
-	ptr = fw->data;
-	buf = kmalloc(64, GFP_KERNEL | GFP_DMA);
-	if (!buf) {
-		ret = -ENOMEM;
-		goto out_rel_fw;
-	}
-
-	while (ptr[0] != 0xff) {
-		u16 buflen = ptr[0] + 4;
-		if (ptr + buflen >= fw->data + fw->size) {
-			err("failed to load bcm4500 firmware.");
-			goto out_free;
-		}
-		memcpy(buf, ptr, buflen);
-		if (dvb_usb_generic_write(d, buf, buflen)) {
-			err("failed to load bcm4500 firmware.");
-			goto out_free;
-		}
-		ptr += buflen;
-	}
-
-	ret = 0;
-
-out_free:
-	kfree(buf);
-out_rel_fw:
-	release_firmware(fw);
-
-	return ret;
-}
-
-static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	u8 status, buf;
-	int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
-
-	if (onoff) {
-		gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
-		if (! (status & bm8pskStarted)) {  /* started */
-			if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)
-				gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0);
-			if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
-				return -EINVAL;
-			gp8psk_info(d);
-		}
-
-		if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
-			if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */
-				if(gp8psk_load_bcm4500fw(d))
-					return -EINVAL;
-
-		if (! (status & bmIntersilOn)) /* LNB Power */
-			if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0,
-					&buf, 1))
-				return -EINVAL;
-
-		/* Set DVB mode to 1 */
-		if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
-			if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
-				return -EINVAL;
-		/* Abort possible TS (if previous tune crashed) */
-		if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0))
-			return -EINVAL;
-	} else {
-		/* Turn off LNB power */
-		if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1))
-			return -EINVAL;
-		/* Turn off 8psk power */
-		if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
-			return -EINVAL;
-		if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)
-			gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0);
-	}
-	return 0;
-}
-
-int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
-{
-	u8 buf;
-	int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
-	/* Turn off 8psk power */
-	if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
-		return -EINVAL;
-	/* Turn On 8psk power */
-	if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
-		return -EINVAL;
-	/* load BCM4500 firmware */
-	if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
-		if (gp8psk_load_bcm4500fw(d))
-			return -EINVAL;
-	return 0;
-}
-
-static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0);
-}
-
-static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	adap->fe_adap[0].fe = gp8psk_fe_attach(adap->dev);
-	return 0;
-}
-
-static struct dvb_usb_device_properties gp8psk_properties;
-
-static int gp8psk_usb_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	int ret;
-	struct usb_device *udev = interface_to_usbdev(intf);
-	ret = dvb_usb_device_init(intf, &gp8psk_properties,
-				  THIS_MODULE, NULL, adapter_nr);
-	if (ret == 0) {
-		info("found Genpix USB device pID = %x (hex)",
-			le16_to_cpu(udev->descriptor.idProduct));
-	}
-	return ret;
-}
-
-static struct usb_device_id gp8psk_usb_table [] = {
-	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) },
-	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
-	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
-	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
-	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_2) },
-/*	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */
-	    { 0 },
-};
-MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
-
-static struct dvb_usb_device_properties gp8psk_properties = {
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware = "dvb-usb-gp8psk-01.fw",
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = gp8psk_streaming_ctrl,
-			.frontend_attach  = gp8psk_frontend_attach,
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 7,
-				.endpoint = 0x82,
-				.u = {
-					.bulk = {
-						.buffersize = 8192,
-					}
-				}
-			},
-		}},
-		}
-	},
-	.power_ctrl       = gp8psk_power_ctrl,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 4,
-	.devices = {
-		{ .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
-		  .cold_ids = { &gp8psk_usb_table[0], NULL },
-		  .warm_ids = { &gp8psk_usb_table[1], NULL },
-		},
-		{ .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver",
-		  .cold_ids = { NULL },
-		  .warm_ids = { &gp8psk_usb_table[2], NULL },
-		},
-		{ .name = "Genpix SkyWalker-1 DVB-S receiver",
-		  .cold_ids = { NULL },
-		  .warm_ids = { &gp8psk_usb_table[3], NULL },
-		},
-		{ .name = "Genpix SkyWalker-2 DVB-S receiver",
-		  .cold_ids = { NULL },
-		  .warm_ids = { &gp8psk_usb_table[4], NULL },
-		},
-		{ NULL },
-	}
-};
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver gp8psk_usb_driver = {
-	.name		= "dvb_usb_gp8psk",
-	.probe		= gp8psk_usb_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table	= gp8psk_usb_table,
-};
-
-module_usb_driver(gp8psk_usb_driver);
-
-MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");
-MODULE_DESCRIPTION("Driver for Genpix DVB-S");
-MODULE_VERSION("1.1");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h
deleted file mode 100644
index ed32b9d..0000000
--- a/drivers/media/dvb/dvb-usb/gp8psk.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/* DVB USB compliant Linux driver for the
- *  - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
- *
- * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
- * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
- *
- * Thanks to GENPIX for the sample code used to implement this module.
- *
- * This module is based off the vp7045 and vp702x modules
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#ifndef _DVB_USB_GP8PSK_H_
-#define _DVB_USB_GP8PSK_H_
-
-#define DVB_USB_LOG_PREFIX "gp8psk"
-#include "dvb-usb.h"
-
-extern int dvb_usb_gp8psk_debug;
-#define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args)
-#define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args)
-#define deb_rc(args...)   dprintk(dvb_usb_gp8psk_debug,0x04,args)
-#define deb_fe(args...)   dprintk(dvb_usb_gp8psk_debug,0x08,args)
-
-/* Twinhan Vendor requests */
-#define TH_COMMAND_IN                     0xC0
-#define TH_COMMAND_OUT                    0xC1
-
-/* gp8psk commands */
-
-#define GET_8PSK_CONFIG                 0x80    /* in */
-#define SET_8PSK_CONFIG                 0x81
-#define I2C_WRITE			0x83
-#define I2C_READ			0x84
-#define ARM_TRANSFER                    0x85
-#define TUNE_8PSK                       0x86
-#define GET_SIGNAL_STRENGTH             0x87    /* in */
-#define LOAD_BCM4500                    0x88
-#define BOOT_8PSK                       0x89    /* in */
-#define START_INTERSIL                  0x8A    /* in */
-#define SET_LNB_VOLTAGE                 0x8B
-#define SET_22KHZ_TONE                  0x8C
-#define SEND_DISEQC_COMMAND             0x8D
-#define SET_DVB_MODE                    0x8E
-#define SET_DN_SWITCH                   0x8F
-#define GET_SIGNAL_LOCK                 0x90    /* in */
-#define GET_FW_VERS			0x92
-#define GET_SERIAL_NUMBER               0x93    /* in */
-#define USE_EXTRA_VOLT                  0x94
-#define GET_FPGA_VERS			0x95
-#define CW3K_INIT			0x9d
-
-/* PSK_configuration bits */
-#define bm8pskStarted                   0x01
-#define bm8pskFW_Loaded                 0x02
-#define bmIntersilOn                    0x04
-#define bmDVBmode                       0x08
-#define bm22kHz                         0x10
-#define bmSEL18V                        0x20
-#define bmDCtuned                       0x40
-#define bmArmed                         0x80
-
-/* Satellite modulation modes */
-#define ADV_MOD_DVB_QPSK 0     /* DVB-S QPSK */
-#define ADV_MOD_TURBO_QPSK 1   /* Turbo QPSK */
-#define ADV_MOD_TURBO_8PSK 2   /* Turbo 8PSK (also used for Trellis 8PSK) */
-#define ADV_MOD_TURBO_16QAM 3  /* Turbo 16QAM (also used for Trellis 8PSK) */
-
-#define ADV_MOD_DCII_C_QPSK 4  /* Digicipher II Combo */
-#define ADV_MOD_DCII_I_QPSK 5  /* Digicipher II I-stream */
-#define ADV_MOD_DCII_Q_QPSK 6  /* Digicipher II Q-stream */
-#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */
-#define ADV_MOD_DSS_QPSK 8     /* DSS (DIRECTV) QPSK */
-#define ADV_MOD_DVB_BPSK 9     /* DVB-S BPSK */
-
-#define GET_USB_SPEED                     0x07
-
-#define RESET_FX2                         0x13
-
-#define FW_VERSION_READ                   0x0B
-#define VENDOR_STRING_READ                0x0C
-#define PRODUCT_STRING_READ               0x0D
-#define FW_BCD_VERSION_READ               0x14
-
-/* firmware revision id's */
-#define GP8PSK_FW_REV1			0x020604
-#define GP8PSK_FW_REV2			0x020704
-#define GP8PSK_FW_VERS(_fw_vers)	((_fw_vers)[2]<<0x10 | (_fw_vers)[1]<<0x08 | (_fw_vers)[0])
-
-extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
-extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
-extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
-			     u16 index, u8 *b, int blen);
-extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c
deleted file mode 100644
index 6244fe9..0000000
--- a/drivers/media/dvb/dvb-usb/it913x.c
+++ /dev/null
@@ -1,931 +0,0 @@
-/* DVB USB compliant linux driver for IT9137
- *
- * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
- * IT9137 (C) ITE Tech Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * see Documentation/dvb/README.dvb-usb for more information
- * see Documentation/dvb/it9137.txt for firmware information
- *
- */
-#define DVB_USB_LOG_PREFIX "it913x"
-
-#include <linux/usb.h>
-#include <linux/usb/input.h>
-#include <media/rc-core.h>
-
-#include "dvb-usb.h"
-#include "it913x-fe.h"
-
-/* debug */
-static int dvb_usb_it913x_debug;
-#define l_dprintk(var, level, args...) do { \
-	if ((var >= level)) \
-		printk(KERN_DEBUG DVB_USB_LOG_PREFIX ": " args); \
-} while (0)
-
-#define deb_info(level, args...) l_dprintk(dvb_usb_it913x_debug, level, args)
-#define debug_data_snipet(level, name, p) \
-	 deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \
-		*p, *(p+1), *(p+2), *(p+3), *(p+4), \
-			*(p+5), *(p+6), *(p+7));
-
-
-module_param_named(debug, dvb_usb_it913x_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."
-			DVB_USB_DEBUG_STATUS);
-
-static int pid_filter;
-module_param_named(pid, pid_filter, int, 0644);
-MODULE_PARM_DESC(pid, "set default 0=on 1=off");
-
-static int dvb_usb_it913x_firmware;
-module_param_named(firmware, dvb_usb_it913x_firmware, int, 0644);
-MODULE_PARM_DESC(firmware, "set firmware 0=auto 1=IT9137 2=IT9135V1");
-
-
-int cmd_counter;
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-struct it913x_state {
-	u8 id;
-	struct ite_config it913x_config;
-	u8 pid_filter_onoff;
-};
-
-struct ite_config it913x_config;
-
-#define IT913X_RETRY	10
-#define IT913X_SND_TIMEOUT	100
-#define IT913X_RCV_TIMEOUT	200
-
-static int it913x_bulk_write(struct usb_device *dev,
-				u8 *snd, int len, u8 pipe)
-{
-	int ret, actual_l, i;
-
-	for (i = 0; i < IT913X_RETRY; i++) {
-		ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
-				snd, len , &actual_l, IT913X_SND_TIMEOUT);
-		if (ret != -EBUSY && ret != -ETIMEDOUT)
-			break;
-	}
-
-	if (len != actual_l && ret == 0)
-		ret = -EAGAIN;
-
-	return ret;
-}
-
-static int it913x_bulk_read(struct usb_device *dev,
-				u8 *rev, int len, u8 pipe)
-{
-	int ret, actual_l, i;
-
-	for (i = 0; i < IT913X_RETRY; i++) {
-		ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
-				 rev, len , &actual_l, IT913X_RCV_TIMEOUT);
-		if (ret != -EBUSY && ret != -ETIMEDOUT)
-			break;
-	}
-
-	if (len != actual_l && ret == 0)
-		ret = -EAGAIN;
-
-	return ret;
-}
-
-static u16 check_sum(u8 *p, u8 len)
-{
-	u16 sum = 0;
-	u8 i = 1;
-	while (i < len)
-		sum += (i++ & 1) ? (*p++) << 8 : *p++;
-	return ~sum;
-}
-
-static int it913x_usb_talk(struct usb_device *udev, u8 mode, u8 pro,
-			u8 cmd, u32 reg, u8 addr, u8 *data, u8 len)
-{
-	int ret = 0, i, buf_size = 1;
-	u8 *buff;
-	u8 rlen;
-	u16 chk_sum;
-
-	buff = kzalloc(256, GFP_KERNEL);
-	if (!buff) {
-		info("USB Buffer Failed");
-		return -ENOMEM;
-	}
-
-	buff[buf_size++] = pro;
-	buff[buf_size++] = cmd;
-	buff[buf_size++] = cmd_counter;
-
-	switch (mode) {
-	case READ_LONG:
-	case WRITE_LONG:
-		buff[buf_size++] = len;
-		buff[buf_size++] = 2;
-		buff[buf_size++] = (reg >> 24);
-		buff[buf_size++] = (reg >> 16) & 0xff;
-		buff[buf_size++] = (reg >> 8) & 0xff;
-		buff[buf_size++] = reg & 0xff;
-	break;
-	case READ_SHORT:
-		buff[buf_size++] = addr;
-		break;
-	case WRITE_SHORT:
-		buff[buf_size++] = len;
-		buff[buf_size++] = addr;
-		buff[buf_size++] = (reg >> 8) & 0xff;
-		buff[buf_size++] = reg & 0xff;
-	break;
-	case READ_DATA:
-	case WRITE_DATA:
-		break;
-	case WRITE_CMD:
-		mode = 7;
-		break;
-	default:
-		kfree(buff);
-		return -EINVAL;
-	}
-
-	if (mode & 1) {
-		for (i = 0; i < len ; i++)
-			buff[buf_size++] = data[i];
-	}
-	chk_sum = check_sum(&buff[1], buf_size);
-
-	buff[buf_size++] = chk_sum >> 8;
-	buff[0] = buf_size;
-	buff[buf_size++] = (chk_sum & 0xff);
-
-	ret = it913x_bulk_write(udev, buff, buf_size , 0x02);
-	if (ret < 0)
-		goto error;
-
-	ret = it913x_bulk_read(udev, buff, (mode & 1) ?
-			5 : len + 5 , 0x01);
-	if (ret < 0)
-		goto error;
-
-	rlen = (mode & 0x1) ? 0x1 : len;
-
-	if (mode & 1)
-		ret = buff[2];
-	else
-		memcpy(data, &buff[3], rlen);
-
-	cmd_counter++;
-
-error:	kfree(buff);
-
-	return ret;
-}
-
-static int it913x_io(struct usb_device *udev, u8 mode, u8 pro,
-			u8 cmd, u32 reg, u8 addr, u8 *data, u8 len)
-{
-	int ret, i;
-
-	for (i = 0; i < IT913X_RETRY; i++) {
-		ret = it913x_usb_talk(udev, mode, pro,
-			cmd, reg, addr, data, len);
-		if (ret != -EAGAIN)
-			break;
-	}
-
-	return ret;
-}
-
-static int it913x_wr_reg(struct usb_device *udev, u8 pro, u32 reg , u8 data)
-{
-	int ret;
-	u8 b[1];
-	b[0] = data;
-	ret = it913x_io(udev, WRITE_LONG, pro,
-			CMD_DEMOD_WRITE, reg, 0, b, sizeof(b));
-
-	return ret;
-}
-
-static int it913x_read_reg(struct usb_device *udev, u32 reg)
-{
-	int ret;
-	u8 data[1];
-
-	ret = it913x_io(udev, READ_LONG, DEV_0,
-			CMD_DEMOD_READ, reg, 0, &data[0], 1);
-
-	return (ret < 0) ? ret : data[0];
-}
-
-static u32 it913x_query(struct usb_device *udev, u8 pro)
-{
-	int ret, i;
-	u8 data[4];
-	u8 ver;
-
-	for (i = 0; i < 5; i++) {
-		ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ,
-			0x1222, 0, &data[0], 3);
-		ver = data[0];
-		if (ver > 0 && ver < 3)
-			break;
-		msleep(100);
-	}
-
-	if (ver < 1 || ver > 2) {
-		info("Failed to identify chip version applying 1");
-		it913x_config.chip_ver = 0x1;
-		it913x_config.chip_type = 0x9135;
-		return 0;
-	}
-
-	it913x_config.chip_ver = ver;
-	it913x_config.chip_type = (u16)(data[2] << 8) + data[1];
-
-	info("Chip Version=%02x Chip Type=%04x", it913x_config.chip_ver,
-		it913x_config.chip_type);
-
-	ret |= it913x_io(udev, READ_SHORT, pro,
-			CMD_QUERYINFO, 0, 0x1, &data[0], 4);
-
-	it913x_config.firmware = (data[0] << 24) + (data[1] << 16) +
-			(data[2] << 8) + data[3];
-
-	return (ret < 0) ? 0 : it913x_config.firmware;
-}
-
-static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	struct it913x_state *st = adap->dev->priv;
-	struct usb_device *udev = adap->dev->udev;
-	int ret;
-	u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
-
-	mutex_lock(&adap->dev->i2c_mutex);
-
-	deb_info(1, "PID_C  (%02x)", onoff);
-
-	ret = it913x_wr_reg(udev, pro, PID_EN, st->pid_filter_onoff);
-
-	mutex_unlock(&adap->dev->i2c_mutex);
-	return ret;
-}
-
-static int it913x_pid_filter(struct dvb_usb_adapter *adap,
-		int index, u16 pid, int onoff)
-{
-	struct it913x_state *st = adap->dev->priv;
-	struct usb_device *udev = adap->dev->udev;
-	int ret;
-	u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
-
-	mutex_lock(&adap->dev->i2c_mutex);
-
-	deb_info(1, "PID_F  (%02x)", onoff);
-
-	ret = it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff));
-
-	ret |= it913x_wr_reg(udev, pro, PID_MSB, (u8)(pid >> 8));
-
-	ret |= it913x_wr_reg(udev, pro, PID_INX_EN, (u8)onoff);
-
-	ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f));
-
-	if (udev->speed == USB_SPEED_HIGH && pid == 0x2000) {
-			ret |= it913x_wr_reg(udev, pro, PID_EN, !onoff);
-			st->pid_filter_onoff = !onoff;
-	} else
-		st->pid_filter_onoff =
-			adap->fe_adap[adap->active_fe].pid_filtering;
-
-	mutex_unlock(&adap->dev->i2c_mutex);
-	return 0;
-}
-
-
-static int it913x_return_status(struct usb_device *udev)
-{
-	u32 firm = 0;
-
-	firm = it913x_query(udev, DEV_0);
-	if (firm > 0)
-		info("Firmware Version %d", firm);
-
-	return (firm > 0) ? firm : 0;
-}
-
-static int it913x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-				 int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	static u8 data[256];
-	int ret;
-	u32 reg;
-	u8 pro;
-
-	mutex_lock(&d->i2c_mutex);
-
-	debug_data_snipet(1, "Message out", msg[0].buf);
-	deb_info(2, "num of messages %d address %02x", num, msg[0].addr);
-
-	pro = (msg[0].addr & 0x2) ?  DEV_0_DMOD : 0x0;
-	pro |= (msg[0].addr & 0x20) ? DEV_1 : DEV_0;
-	memcpy(data, msg[0].buf, msg[0].len);
-	reg = (data[0] << 24) + (data[1] << 16) +
-			(data[2] << 8) + data[3];
-	if (num == 2) {
-		ret = it913x_io(d->udev, READ_LONG, pro,
-			CMD_DEMOD_READ, reg, 0, data, msg[1].len);
-		memcpy(msg[1].buf, data, msg[1].len);
-	} else
-		ret = it913x_io(d->udev, WRITE_LONG, pro, CMD_DEMOD_WRITE,
-			reg, 0, &data[4], msg[0].len - 4);
-
-	mutex_unlock(&d->i2c_mutex);
-
-	return ret;
-}
-
-static u32 it913x_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm it913x_i2c_algo = {
-	.master_xfer   = it913x_i2c_xfer,
-	.functionality = it913x_i2c_func,
-};
-
-/* Callbacks for DVB USB */
-#define IT913X_POLL 250
-static int it913x_rc_query(struct dvb_usb_device *d)
-{
-	u8 ibuf[4];
-	int ret;
-	u32 key;
-	/* Avoid conflict with frontends*/
-	mutex_lock(&d->i2c_mutex);
-
-	ret = it913x_io(d->udev, READ_LONG, PRO_LINK, CMD_IR_GET,
-		0, 0, &ibuf[0], sizeof(ibuf));
-
-	if ((ibuf[2] + ibuf[3]) == 0xff) {
-		key = ibuf[2];
-		key += ibuf[0] << 16;
-		key += ibuf[1] << 8;
-		deb_info(1, "NEC Extended Key =%08x", key);
-		if (d->rc_dev != NULL)
-			rc_keydown(d->rc_dev, key, 0);
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-
-	return ret;
-}
-
-/* Firmware sets raw */
-const char fw_it9135_v1[] = "dvb-usb-it9135-01.fw";
-const char fw_it9135_v2[] = "dvb-usb-it9135-02.fw";
-const char fw_it9137[] = "dvb-usb-it9137-01.fw";
-
-static int ite_firmware_select(struct usb_device *udev,
-	struct dvb_usb_device_properties *props)
-{
-	int sw;
-	/* auto switch */
-	if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_KWORLD_2)
-		sw = IT9137_FW;
-	else if (it913x_config.chip_ver == 1)
-		sw = IT9135_V1_FW;
-	else
-		sw = IT9135_V2_FW;
-
-	/* force switch */
-	if (dvb_usb_it913x_firmware != IT9135_AUTO)
-		sw = dvb_usb_it913x_firmware;
-
-	switch (sw) {
-	case IT9135_V1_FW:
-		it913x_config.firmware_ver = 1;
-		it913x_config.adc_x2 = 1;
-		it913x_config.read_slevel = false;
-		props->firmware = fw_it9135_v1;
-		break;
-	case IT9135_V2_FW:
-		it913x_config.firmware_ver = 1;
-		it913x_config.adc_x2 = 1;
-		it913x_config.read_slevel = false;
-		props->firmware = fw_it9135_v2;
-		switch (it913x_config.tuner_id_0) {
-		case IT9135_61:
-		case IT9135_62:
-			break;
-		default:
-			info("Unknown tuner ID applying default 0x60");
-		case IT9135_60:
-			it913x_config.tuner_id_0 = IT9135_60;
-		}
-		break;
-	case IT9137_FW:
-	default:
-		it913x_config.firmware_ver = 0;
-		it913x_config.adc_x2 = 0;
-		it913x_config.read_slevel = true;
-		props->firmware = fw_it9137;
-	}
-
-	return 0;
-}
-
-static void it913x_select_remote(struct usb_device *udev,
-	struct dvb_usb_device_properties *props)
-{
-	switch (le16_to_cpu(udev->descriptor.idProduct)) {
-	case USB_PID_ITETECH_IT9135_9005:
-		props->rc.core.rc_codes = RC_MAP_IT913X_V2;
-		return;
-	default:
-		props->rc.core.rc_codes = RC_MAP_IT913X_V1;
-	}
-	return;
-}
-
-#define TS_MPEG_PKT_SIZE	188
-#define EP_LOW			21
-#define TS_BUFFER_SIZE_PID	(EP_LOW*TS_MPEG_PKT_SIZE)
-#define EP_HIGH			348
-#define TS_BUFFER_SIZE_MAX	(EP_HIGH*TS_MPEG_PKT_SIZE)
-
-static int it913x_select_config(struct usb_device *udev,
-	struct dvb_usb_device_properties *props)
-{
-	int ret = 0, reg;
-	bool proprietary_ir = false;
-
-	if (it913x_config.chip_ver == 0x02
-			&& it913x_config.chip_type == 0x9135)
-		reg = it913x_read_reg(udev, 0x461d);
-	else
-		reg = it913x_read_reg(udev, 0x461b);
-
-	if (reg < 0)
-		return reg;
-
-	if (reg == 0) {
-		it913x_config.dual_mode = 0;
-		it913x_config.tuner_id_0 = IT9135_38;
-		proprietary_ir = true;
-	} else {
-		/* TS mode */
-		reg =  it913x_read_reg(udev, 0x49c5);
-		if (reg < 0)
-			return reg;
-		it913x_config.dual_mode = reg;
-
-		/* IR mode type */
-		reg = it913x_read_reg(udev, 0x49ac);
-		if (reg < 0)
-			return reg;
-		if (reg == 5) {
-			info("Remote propriety (raw) mode");
-			proprietary_ir = true;
-		} else if (reg == 1) {
-			info("Remote HID mode NOT SUPPORTED");
-			proprietary_ir = false;
-			props->rc.core.rc_codes = NULL;
-		} else
-			props->rc.core.rc_codes = NULL;
-
-		/* Tuner_id */
-		reg = it913x_read_reg(udev, 0x49d0);
-		if (reg < 0)
-			return reg;
-		it913x_config.tuner_id_0 = reg;
-	}
-
-	if (proprietary_ir)
-		it913x_select_remote(udev, props);
-
-	if (udev->speed != USB_SPEED_HIGH) {
-		props->adapter[0].fe[0].pid_filter_count = 5;
-		info("USB 1 low speed mode - connect to USB 2 port");
-		if (pid_filter > 0)
-			pid_filter = 0;
-		if (it913x_config.dual_mode) {
-			it913x_config.dual_mode = 0;
-			info("Dual mode not supported in USB 1");
-		}
-	} else /* For replugging */
-		if(props->adapter[0].fe[0].pid_filter_count == 5)
-			props->adapter[0].fe[0].pid_filter_count = 31;
-
-	/* Select Stream Buffer Size and pid filter option*/
-	if (pid_filter) {
-		props->adapter[0].fe[0].stream.u.bulk.buffersize =
-			TS_BUFFER_SIZE_MAX;
-		props->adapter[0].fe[0].caps &=
-			~DVB_USB_ADAP_NEED_PID_FILTERING;
-	} else
-		props->adapter[0].fe[0].stream.u.bulk.buffersize =
-			TS_BUFFER_SIZE_PID;
-
-	if (it913x_config.dual_mode) {
-		props->adapter[1].fe[0].stream.u.bulk.buffersize =
-			props->adapter[0].fe[0].stream.u.bulk.buffersize;
-		props->num_adapters = 2;
-		if (pid_filter)
-			props->adapter[1].fe[0].caps =
-				props->adapter[0].fe[0].caps;
-	} else
-		props->num_adapters = 1;
-
-	info("Dual mode=%x Tuner Type=%x", it913x_config.dual_mode,
-		it913x_config.tuner_id_0);
-
-	ret = ite_firmware_select(udev, props);
-
-	return ret;
-}
-
-static int it913x_identify_state(struct usb_device *udev,
-		struct dvb_usb_device_properties *props,
-		struct dvb_usb_device_description **desc,
-		int *cold)
-{
-	int ret = 0, firm_no;
-	u8 reg;
-
-	firm_no = it913x_return_status(udev);
-
-	/* Read and select config */
-	ret = it913x_select_config(udev, props);
-	if (ret < 0)
-		return ret;
-
-	if (firm_no > 0) {
-		*cold = 0;
-		return 0;
-	}
-
-	if (it913x_config.dual_mode) {
-		it913x_config.tuner_id_1 = it913x_read_reg(udev, 0x49e0);
-		ret = it913x_wr_reg(udev, DEV_0, GPIOH1_EN, 0x1);
-		ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_ON, 0x1);
-		ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x1);
-		msleep(50);
-		ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x0);
-		msleep(50);
-		reg = it913x_read_reg(udev, GPIOH1_O);
-		if (reg == 0) {
-			ret |= it913x_wr_reg(udev, DEV_0,  GPIOH1_O, 0x1);
-			ret |= it913x_return_status(udev);
-			if (ret != 0)
-				ret = it913x_wr_reg(udev, DEV_0,
-					GPIOH1_O, 0x0);
-		}
-	}
-
-	reg = it913x_read_reg(udev, IO_MUX_POWER_CLK);
-
-	if (it913x_config.dual_mode) {
-		ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR);
-		if (it913x_config.firmware_ver == 1)
-			ret |= it913x_wr_reg(udev, DEV_0,  0xcfff, 0x1);
-		else
-			ret |= it913x_wr_reg(udev, DEV_0,  CLK_O_EN, 0x1);
-	} else {
-		ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, 0x0);
-		if (it913x_config.firmware_ver == 1)
-			ret |= it913x_wr_reg(udev, DEV_0,  0xcfff, 0x0);
-		else
-			ret |= it913x_wr_reg(udev, DEV_0,  CLK_O_EN, 0x0);
-	}
-
-	*cold = 1;
-
-	return (ret < 0) ? -ENODEV : 0;
-}
-
-static int it913x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	struct it913x_state *st = adap->dev->priv;
-	int ret = 0;
-	u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
-
-	deb_info(1, "STM  (%02x)", onoff);
-
-	if (!onoff) {
-		mutex_lock(&adap->dev->i2c_mutex);
-
-		ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1);
-
-		mutex_unlock(&adap->dev->i2c_mutex);
-		st->pid_filter_onoff =
-			adap->fe_adap[adap->active_fe].pid_filtering;
-
-	}
-
-	return ret;
-}
-
-static int it913x_download_firmware(struct usb_device *udev,
-					const struct firmware *fw)
-{
-	int ret = 0, i = 0, pos = 0;
-	u8 packet_size, min_pkt;
-	u8 *fw_data;
-
-	ret = it913x_wr_reg(udev, DEV_0,  I2C_CLK, I2C_CLK_100);
-
-	info("FRM Starting Firmware Download");
-
-	/* Multi firmware loader */
-	/* This uses scatter write firmware headers */
-	/* The firmware must start with 03 XX 00 */
-	/* and be the extact firmware length */
-
-	if (it913x_config.chip_ver == 2)
-		min_pkt = 0x11;
-	else
-		min_pkt = 0x19;
-
-	while (i <= fw->size) {
-		if (((fw->data[i] == 0x3) && (fw->data[i + 2] == 0x0))
-			|| (i == fw->size)) {
-			packet_size = i - pos;
-			if ((packet_size > min_pkt) || (i == fw->size)) {
-				fw_data = (u8 *)(fw->data + pos);
-				pos += packet_size;
-				if (packet_size > 0) {
-					ret = it913x_io(udev, WRITE_DATA,
-						DEV_0, CMD_SCATTER_WRITE, 0,
-						0, fw_data, packet_size);
-					if (ret < 0)
-						break;
-				}
-				udelay(1000);
-			}
-		}
-		i++;
-	}
-
-	if (ret < 0)
-		info("FRM Firmware Download Failed (%d)" , ret);
-	else
-		info("FRM Firmware Download Completed - Resetting Device");
-
-	msleep(30);
-
-	ret = it913x_io(udev, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0);
-	if (ret < 0)
-		info("FRM Device not responding to reboot");
-
-	ret = it913x_return_status(udev);
-	if (ret == 0) {
-		info("FRM Failed to reboot device");
-		return -ENODEV;
-	}
-
-	msleep(30);
-
-	ret = it913x_wr_reg(udev, DEV_0,  I2C_CLK, I2C_CLK_400);
-
-	msleep(30);
-
-	/* Tuner function */
-	if (it913x_config.dual_mode)
-		ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0);
-	else
-		ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0x68);
-
-	if ((it913x_config.chip_ver == 1) &&
-		(it913x_config.chip_type == 0x9135)) {
-		ret |= it913x_wr_reg(udev, DEV_0,  PADODPU, 0x0);
-		ret |= it913x_wr_reg(udev, DEV_0,  AGC_O_D, 0x0);
-		if (it913x_config.dual_mode) {
-			ret |= it913x_wr_reg(udev, DEV_1,  PADODPU, 0x0);
-			ret |= it913x_wr_reg(udev, DEV_1,  AGC_O_D, 0x0);
-		}
-	}
-
-	return (ret < 0) ? -ENODEV : 0;
-}
-
-static int it913x_name(struct dvb_usb_adapter *adap)
-{
-	const char *desc = adap->dev->desc->name;
-	char *fe_name[] = {"_1", "_2", "_3", "_4"};
-	char *name = adap->fe_adap[0].fe->ops.info.name;
-
-	strlcpy(name, desc, 128);
-	strlcat(name, fe_name[adap->id], 128);
-
-	return 0;
-}
-
-static int it913x_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct usb_device *udev = adap->dev->udev;
-	struct it913x_state *st = adap->dev->priv;
-	int ret = 0;
-	u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5);
-	u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize / 4;
-	u8 pkt_size = 0x80;
-
-	if (adap->dev->udev->speed != USB_SPEED_HIGH)
-		pkt_size = 0x10;
-
-	it913x_config.adf = it913x_read_reg(udev, IO_MUX_POWER_CLK);
-
-	if (adap->id == 0)
-		memcpy(&st->it913x_config, &it913x_config,
-			sizeof(struct ite_config));
-
-	adap->fe_adap[0].fe = dvb_attach(it913x_fe_attach,
-		&adap->dev->i2c_adap, adap_addr, &st->it913x_config);
-
-	if (adap->id == 0 && adap->fe_adap[0].fe) {
-		ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x1);
-		ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_SW_RST, 0x1);
-		ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x0f);
-		ret = it913x_wr_reg(udev, DEV_0, EP0_TX_NAK, 0x1b);
-		ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x2f);
-		ret = it913x_wr_reg(udev, DEV_0, EP4_TX_LEN_LSB,
-					ep_size & 0xff);
-		ret = it913x_wr_reg(udev, DEV_0, EP4_TX_LEN_MSB, ep_size >> 8);
-		ret = it913x_wr_reg(udev, DEV_0, EP4_MAX_PKT, pkt_size);
-	} else if (adap->id == 1 && adap->fe_adap[0].fe) {
-		ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x6f);
-		ret = it913x_wr_reg(udev, DEV_0, EP5_TX_LEN_LSB,
-					ep_size & 0xff);
-		ret = it913x_wr_reg(udev, DEV_0, EP5_TX_LEN_MSB, ep_size >> 8);
-		ret = it913x_wr_reg(udev, DEV_0, EP5_MAX_PKT, pkt_size);
-		ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_EN, 0x1);
-		ret = it913x_wr_reg(udev, DEV_1_DMOD, MP2IF_SERIAL, 0x1);
-		ret = it913x_wr_reg(udev, DEV_1, TOP_HOSTB_SER_MODE, 0x1);
-		ret = it913x_wr_reg(udev, DEV_0_DMOD, TSIS_ENABLE, 0x1);
-		ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x0);
-		ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_SW_RST, 0x0);
-		ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_HALF_PSB, 0x0);
-		ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF_STOP_EN, 0x1);
-		ret = it913x_wr_reg(udev, DEV_1_DMOD, MPEG_FULL_SPEED, 0x0);
-		ret = it913x_wr_reg(udev, DEV_1_DMOD, MP2IF_STOP_EN, 0x0);
-	} else
-		return -ENODEV;
-
-	ret = it913x_name(adap);
-
-	return ret;
-}
-
-/* DVB USB Driver */
-static struct dvb_usb_device_properties it913x_properties;
-
-static int it913x_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	cmd_counter = 0;
-	if (0 == dvb_usb_device_init(intf, &it913x_properties,
-				     THIS_MODULE, NULL, adapter_nr)) {
-		info("DEV registering device driver");
-		return 0;
-	}
-
-	info("DEV it913x Error");
-	return -ENODEV;
-
-}
-
-static struct usb_device_id it913x_table[] = {
-	{ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09) },
-	{ USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135) },
-	{ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22_IT9137) },
-	{ USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9005) },
-	{ USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9006) },
-	{}		/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, it913x_table);
-
-static struct dvb_usb_device_properties it913x_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-	.usb_ctrl = DEVICE_SPECIFIC,
-	.download_firmware = it913x_download_firmware,
-	.firmware = "dvb-usb-it9137-01.fw",
-	.no_reconnect = 1,
-	.size_of_priv = sizeof(struct it913x_state),
-	.num_adapters = 2,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.caps = DVB_USB_ADAP_HAS_PID_FILTER|
-				DVB_USB_ADAP_NEED_PID_FILTERING|
-				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-			.streaming_ctrl   = it913x_streaming_ctrl,
-			.pid_filter_count = 31,
-			.pid_filter = it913x_pid_filter,
-			.pid_filter_ctrl  = it913x_pid_filter_ctrl,
-			.frontend_attach  = it913x_frontend_attach,
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 10,
-				.endpoint = 0x04,
-				.u = {/* Keep Low if PID filter on */
-					.bulk = {
-					.buffersize =
-						TS_BUFFER_SIZE_PID,
-					}
-				}
-			}
-		}},
-		},
-			{
-		.num_frontends = 1,
-		.fe = {{
-			.caps = DVB_USB_ADAP_HAS_PID_FILTER|
-				DVB_USB_ADAP_NEED_PID_FILTERING|
-				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-			.streaming_ctrl   = it913x_streaming_ctrl,
-			.pid_filter_count = 31,
-			.pid_filter = it913x_pid_filter,
-			.pid_filter_ctrl  = it913x_pid_filter_ctrl,
-			.frontend_attach  = it913x_frontend_attach,
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 5,
-				.endpoint = 0x05,
-				.u = {
-					.bulk = {
-						.buffersize =
-							TS_BUFFER_SIZE_PID,
-					}
-				}
-			}
-		}},
-		}
-	},
-	.identify_state   = it913x_identify_state,
-	.rc.core = {
-		.protocol	= RC_TYPE_NEC,
-		.module_name	= "it913x",
-		.rc_query	= it913x_rc_query,
-		.rc_interval	= IT913X_POLL,
-		.allowed_protos	= RC_TYPE_NEC,
-		.rc_codes	= RC_MAP_IT913X_V1,
-	},
-	.i2c_algo         = &it913x_i2c_algo,
-	.num_device_descs = 5,
-	.devices = {
-		{   "Kworld UB499-2T T09(IT9137)",
-			{ &it913x_table[0], NULL },
-			},
-		{   "ITE 9135 Generic",
-			{ &it913x_table[1], NULL },
-			},
-		{   "Sveon STV22 Dual DVB-T HDTV(IT9137)",
-			{ &it913x_table[2], NULL },
-			},
-		{   "ITE 9135(9005) Generic",
-			{ &it913x_table[3], NULL },
-			},
-		{   "ITE 9135(9006) Generic",
-			{ &it913x_table[4], NULL },
-			},
-	}
-};
-
-static struct usb_driver it913x_driver = {
-	.name		= "it913x",
-	.probe		= it913x_probe,
-	.disconnect	= dvb_usb_device_exit,
-	.id_table	= it913x_table,
-};
-
-module_usb_driver(it913x_driver);
-
-MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
-MODULE_DESCRIPTION("it913x USB 2 Driver");
-MODULE_VERSION("1.28");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c
deleted file mode 100644
index 25d1031..0000000
--- a/drivers/media/dvb/dvb-usb/lmedm04.c
+++ /dev/null
@@ -1,1407 +0,0 @@
-/* DVB USB compliant linux driver for
- *
- * DM04/QQBOX DVB-S USB BOX	LME2510C + SHARP:BS2F7HZ7395
- *				LME2510C + LG TDQY-P001F
- *				LME2510C + BS2F7HZ0194
- *				LME2510 + LG TDQY-P001F
- *				LME2510 + BS2F7HZ0194
- *
- * MVB7395 (LME2510C+SHARP:BS2F7HZ7395)
- * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V)
- *
- * MV001F (LME2510+LGTDQY-P001F)
- * LG TDQY - P001F =(TDA8263 + TDA10086H)
- *
- * MVB0001F (LME2510C+LGTDQT-P001F)
- *
- * MV0194 (LME2510+SHARP:BS2F7HZ0194)
- * SHARP:BS2F7HZ0194 = (STV0299+IX2410)
- *
- * MVB0194 (LME2510C+SHARP0194)
- *
- * For firmware see Documentation/dvb/lmedm04.txt
- *
- * I2C addresses:
- * 0xd0 - STV0288	- Demodulator
- * 0xc0 - Sharp IX2505V	- Tuner
- * --
- * 0x1c - TDA10086   - Demodulator
- * 0xc0 - TDA8263    - Tuner
- * --
- * 0xd0 - STV0299	- Demodulator
- * 0xc0 - IX2410	- Tuner
- *
- *
- * VID = 3344  PID LME2510=1122 LME2510C=1120
- *
- * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com)
- * LME2510(C)(C) Leaguerme (Shenzhen) MicroElectronics Co., Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * see Documentation/dvb/README.dvb-usb for more information
- *
- * Known Issues :
- *	LME2510: Non Intel USB chipsets fail to maintain High Speed on
- * Boot or Hot Plug.
- *
- * QQbox suffers from noise on LNB voltage.
- *
- *	LME2510: SHARP:BS2F7HZ0194(MV0194) cannot cold reset and share system
- * with other tuners. After a cold reset streaming will not start.
- *
- */
-#define DVB_USB_LOG_PREFIX "LME2510(C)"
-#include <linux/usb.h>
-#include <linux/usb/input.h>
-#include <media/rc-core.h>
-
-#include "dvb-usb.h"
-#include "lmedm04.h"
-#include "tda826x.h"
-#include "tda10086.h"
-#include "stv0288.h"
-#include "ix2505v.h"
-#include "stv0299.h"
-#include "dvb-pll.h"
-#include "z0194a.h"
-#include "m88rs2000.h"
-
-
-
-/* debug */
-static int dvb_usb_lme2510_debug;
-#define l_dprintk(var, level, args...) do { \
-	if ((var >= level)) \
-		printk(KERN_DEBUG DVB_USB_LOG_PREFIX ": " args); \
-} while (0)
-
-#define deb_info(level, args...) l_dprintk(dvb_usb_lme2510_debug, level, args)
-#define debug_data_snipet(level, name, p) \
-	 deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \
-		*p, *(p+1), *(p+2), *(p+3), *(p+4), \
-			*(p+5), *(p+6), *(p+7));
-
-
-module_param_named(debug, dvb_usb_lme2510_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."
-			DVB_USB_DEBUG_STATUS);
-
-static int dvb_usb_lme2510_firmware;
-module_param_named(firmware, dvb_usb_lme2510_firmware, int, 0644);
-MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG");
-
-static int pid_filter;
-module_param_named(pid, pid_filter, int, 0644);
-MODULE_PARM_DESC(pid, "set default 0=default 1=off 2=on");
-
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define TUNER_DEFAULT	0x0
-#define TUNER_LG	0x1
-#define TUNER_S7395	0x2
-#define TUNER_S0194	0x3
-#define TUNER_RS2000	0x4
-
-struct lme2510_state {
-	u8 id;
-	u8 tuner_config;
-	u8 signal_lock;
-	u8 signal_level;
-	u8 signal_sn;
-	u8 time_key;
-	u8 last_key;
-	u8 key_timeout;
-	u8 i2c_talk_onoff;
-	u8 i2c_gate;
-	u8 i2c_tuner_gate_w;
-	u8 i2c_tuner_gate_r;
-	u8 i2c_tuner_addr;
-	u8 stream_on;
-	u8 pid_size;
-	u8 pid_off;
-	void *buffer;
-	struct urb *lme_urb;
-	void *usb_buffer;
-
-};
-
-static int lme2510_bulk_write(struct usb_device *dev,
-				u8 *snd, int len, u8 pipe)
-{
-	int ret, actual_l;
-
-	ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
-				snd, len , &actual_l, 100);
-	return ret;
-}
-
-static int lme2510_bulk_read(struct usb_device *dev,
-				u8 *rev, int len, u8 pipe)
-{
-	int ret, actual_l;
-
-	ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
-				 rev, len , &actual_l, 200);
-	return ret;
-}
-
-static int lme2510_usb_talk(struct dvb_usb_device *d,
-		u8 *wbuf, int wlen, u8 *rbuf, int rlen)
-{
-	struct lme2510_state *st = d->priv;
-	u8 *buff;
-	int ret = 0;
-
-	if (st->usb_buffer == NULL) {
-		st->usb_buffer = kmalloc(64, GFP_KERNEL);
-		if (st->usb_buffer == NULL) {
-			info("MEM Error no memory");
-			return -ENOMEM;
-		}
-	}
-	buff = st->usb_buffer;
-
-	ret = mutex_lock_interruptible(&d->usb_mutex);
-
-	if (ret < 0)
-		return -EAGAIN;
-
-	/* the read/write capped at 64 */
-	memcpy(buff, wbuf, (wlen < 64) ? wlen : 64);
-
-	ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01);
-
-	ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ?
-			rlen : 64 , 0x01);
-
-	if (rlen > 0)
-		memcpy(rbuf, buff, rlen);
-
-	mutex_unlock(&d->usb_mutex);
-
-	return (ret < 0) ? -ENODEV : 0;
-}
-
-static int lme2510_stream_restart(struct dvb_usb_device *d)
-{
-	struct lme2510_state *st = d->priv;
-	u8 all_pids[] = LME_ALL_PIDS;
-	u8 stream_on[] = LME_ST_ON_W;
-	int ret;
-	u8 rbuff[1];
-	if (st->pid_off)
-		ret = lme2510_usb_talk(d, all_pids, sizeof(all_pids),
-			rbuff, sizeof(rbuff));
-	/*Restart Stream Command*/
-	ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on),
-			rbuff, sizeof(rbuff));
-	return ret;
-}
-
-static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out)
-{
-	struct lme2510_state *st = d->priv;
-	static u8 pid_buff[] = LME_ZERO_PID;
-	static u8 rbuf[1];
-	u8 pid_no = index * 2;
-	u8 pid_len = pid_no + 2;
-	int ret = 0;
-	deb_info(1, "PID Setting Pid %04x", pid_out);
-
-	if (st->pid_size == 0)
-		ret |= lme2510_stream_restart(d);
-
-	pid_buff[2] = pid_no;
-	pid_buff[3] = (u8)pid_out & 0xff;
-	pid_buff[4] = pid_no + 1;
-	pid_buff[5] = (u8)(pid_out >> 8);
-
-	if (pid_len > st->pid_size)
-		st->pid_size = pid_len;
-	pid_buff[7] = 0x80 + st->pid_size;
-
-	ret |= lme2510_usb_talk(d, pid_buff ,
-		sizeof(pid_buff) , rbuf, sizeof(rbuf));
-
-	if (st->stream_on)
-		ret |= lme2510_stream_restart(d);
-
-	return ret;
-}
-
-static void lme2510_int_response(struct urb *lme_urb)
-{
-	struct dvb_usb_adapter *adap = lme_urb->context;
-	struct lme2510_state *st = adap->dev->priv;
-	static u8 *ibuf, *rbuf;
-	int i = 0, offset;
-	u32 key;
-
-	switch (lme_urb->status) {
-	case 0:
-	case -ETIMEDOUT:
-		break;
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		return;
-	default:
-		info("Error %x", lme_urb->status);
-		break;
-	}
-
-	rbuf = (u8 *) lme_urb->transfer_buffer;
-
-	offset = ((lme_urb->actual_length/8) > 4)
-			? 4 : (lme_urb->actual_length/8) ;
-
-	for (i = 0; i < offset; ++i) {
-		ibuf = (u8 *)&rbuf[i*8];
-		deb_info(5, "INT O/S C =%02x C/O=%02x Type =%02x%02x",
-		offset, i, ibuf[0], ibuf[1]);
-
-		switch (ibuf[0]) {
-		case 0xaa:
-			debug_data_snipet(1, "INT Remote data snipet", ibuf);
-			if ((ibuf[4] + ibuf[5]) == 0xff) {
-				key = ibuf[5];
-				key += (ibuf[3] > 0)
-					? (ibuf[3] ^ 0xff) << 8 : 0;
-				key += (ibuf[2] ^ 0xff) << 16;
-				deb_info(1, "INT Key =%08x", key);
-				if (adap->dev->rc_dev != NULL)
-					rc_keydown(adap->dev->rc_dev, key, 0);
-			}
-			break;
-		case 0xbb:
-			switch (st->tuner_config) {
-			case TUNER_LG:
-				if (ibuf[2] > 0)
-					st->signal_lock = ibuf[2];
-				st->signal_level = ibuf[4];
-				st->signal_sn = ibuf[3];
-				st->time_key = ibuf[7];
-				break;
-			case TUNER_S7395:
-			case TUNER_S0194:
-				/* Tweak for earlier firmware*/
-				if (ibuf[1] == 0x03) {
-					if (ibuf[2] > 1)
-						st->signal_lock = ibuf[2];
-					st->signal_level = ibuf[3];
-					st->signal_sn = ibuf[4];
-				} else {
-					st->signal_level = ibuf[4];
-					st->signal_sn = ibuf[5];
-					st->signal_lock =
-						(st->signal_lock & 0xf7) +
-						((ibuf[2] & 0x01) << 0x03);
-				}
-				break;
-			case TUNER_RS2000:
-				if (ibuf[2] > 0)
-					st->signal_lock = 0xff;
-				else
-					st->signal_lock = 0xf0;
-				st->signal_level = ibuf[4];
-				st->signal_sn = ibuf[5];
-				st->time_key = ibuf[7];
-			default:
-				break;
-			}
-			debug_data_snipet(5, "INT Remote data snipet in", ibuf);
-		break;
-		case 0xcc:
-			debug_data_snipet(1, "INT Control data snipet", ibuf);
-			break;
-		default:
-			debug_data_snipet(1, "INT Unknown data snipet", ibuf);
-		break;
-		}
-	}
-	usb_submit_urb(lme_urb, GFP_ATOMIC);
-}
-
-static int lme2510_int_read(struct dvb_usb_adapter *adap)
-{
-	struct lme2510_state *lme_int = adap->dev->priv;
-
-	lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC);
-
-	if (lme_int->lme_urb == NULL)
-			return -ENOMEM;
-
-	lme_int->buffer = usb_alloc_coherent(adap->dev->udev, 128, GFP_ATOMIC,
-					&lme_int->lme_urb->transfer_dma);
-
-	if (lme_int->buffer == NULL)
-			return -ENOMEM;
-
-	usb_fill_int_urb(lme_int->lme_urb,
-				adap->dev->udev,
-				usb_rcvintpipe(adap->dev->udev, 0xa),
-				lme_int->buffer,
-				128,
-				lme2510_int_response,
-				adap,
-				8);
-
-	lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC);
-	info("INT Interrupt Service Started");
-
-	return 0;
-}
-
-static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	struct lme2510_state *st = adap->dev->priv;
-	static u8 clear_pid_reg[] = LME_ALL_PIDS;
-	static u8 rbuf[1];
-	int ret = 0;
-
-	deb_info(1, "PID Clearing Filter");
-
-	mutex_lock(&adap->dev->i2c_mutex);
-
-	if (!onoff) {
-		ret |= lme2510_usb_talk(adap->dev, clear_pid_reg,
-			sizeof(clear_pid_reg), rbuf, sizeof(rbuf));
-		st->pid_off = true;
-	} else
-		st->pid_off = false;
-
-	st->pid_size = 0;
-
-	mutex_unlock(&adap->dev->i2c_mutex);
-
-	return 0;
-}
-
-static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
-	int onoff)
-{
-	int ret = 0;
-
-	deb_info(3, "%s PID=%04x Index=%04x onoff=%02x", __func__,
-		pid, index, onoff);
-
-	if (onoff) {
-		mutex_lock(&adap->dev->i2c_mutex);
-		ret |= lme2510_enable_pid(adap->dev, index, pid);
-		mutex_unlock(&adap->dev->i2c_mutex);
-	}
-
-
-	return ret;
-}
-
-
-static int lme2510_return_status(struct usb_device *dev)
-{
-	int ret = 0;
-	u8 *data;
-
-	data = kzalloc(10, GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	ret |= usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
-	info("Firmware Status: %x (%x)", ret , data[2]);
-
-	ret = (ret < 0) ? -ENODEV : data[2];
-	kfree(data);
-	return ret;
-}
-
-static int lme2510_msg(struct dvb_usb_device *d,
-		u8 *wbuf, int wlen, u8 *rbuf, int rlen)
-{
-	int ret = 0;
-	struct lme2510_state *st = d->priv;
-
-	if (st->i2c_talk_onoff == 1) {
-
-		ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
-
-		switch (st->tuner_config) {
-		case TUNER_LG:
-			if (wbuf[2] == 0x1c) {
-				if (wbuf[3] == 0x0e) {
-					st->signal_lock = rbuf[1];
-					if ((st->stream_on & 1) &&
-						(st->signal_lock & 0x10)) {
-						lme2510_stream_restart(d);
-						st->i2c_talk_onoff = 0;
-					}
-					msleep(80);
-				}
-			}
-			break;
-		case TUNER_S7395:
-			if (wbuf[2] == 0xd0) {
-				if (wbuf[3] == 0x24) {
-					st->signal_lock = rbuf[1];
-					if ((st->stream_on & 1) &&
-						(st->signal_lock & 0x8)) {
-						lme2510_stream_restart(d);
-						st->i2c_talk_onoff = 0;
-					}
-				}
-			}
-			break;
-		case TUNER_S0194:
-			if (wbuf[2] == 0xd0) {
-				if (wbuf[3] == 0x1b) {
-					st->signal_lock = rbuf[1];
-					if ((st->stream_on & 1) &&
-						(st->signal_lock & 0x8)) {
-						lme2510_stream_restart(d);
-						st->i2c_talk_onoff = 0;
-					}
-				}
-			}
-			break;
-		case TUNER_RS2000:
-		default:
-			break;
-		}
-	} else {
-		/* TODO rewrite this section */
-		switch (st->tuner_config) {
-		case TUNER_LG:
-			switch (wbuf[3]) {
-			case 0x0e:
-				rbuf[0] = 0x55;
-				rbuf[1] = st->signal_lock;
-				break;
-			case 0x43:
-				rbuf[0] = 0x55;
-				rbuf[1] = st->signal_level;
-				break;
-			case 0x1c:
-				rbuf[0] = 0x55;
-				rbuf[1] = st->signal_sn;
-				break;
-			case 0x15:
-			case 0x16:
-			case 0x17:
-			case 0x18:
-				rbuf[0] = 0x55;
-				rbuf[1] = 0x00;
-				break;
-			default:
-				lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
-				st->i2c_talk_onoff = 1;
-				break;
-			}
-			break;
-		case TUNER_S7395:
-			switch (wbuf[3]) {
-			case 0x10:
-				rbuf[0] = 0x55;
-				rbuf[1] = (st->signal_level & 0x80)
-						? 0 : (st->signal_level * 2);
-				break;
-			case 0x2d:
-				rbuf[0] = 0x55;
-				rbuf[1] = st->signal_sn;
-				break;
-			case 0x24:
-				rbuf[0] = 0x55;
-				rbuf[1] = st->signal_lock;
-				break;
-			case 0x2e:
-			case 0x26:
-			case 0x27:
-				rbuf[0] = 0x55;
-				rbuf[1] = 0x00;
-				break;
-			default:
-				lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
-				st->i2c_talk_onoff = 1;
-				break;
-			}
-			break;
-		case TUNER_S0194:
-			switch (wbuf[3]) {
-			case 0x18:
-				rbuf[0] = 0x55;
-				rbuf[1] = (st->signal_level & 0x80)
-						? 0 : (st->signal_level * 2);
-				break;
-			case 0x24:
-				rbuf[0] = 0x55;
-				rbuf[1] = st->signal_sn;
-				break;
-			case 0x1b:
-				rbuf[0] = 0x55;
-				rbuf[1] = st->signal_lock;
-				break;
-			case 0x19:
-			case 0x25:
-			case 0x1e:
-			case 0x1d:
-				rbuf[0] = 0x55;
-				rbuf[1] = 0x00;
-				break;
-			default:
-				lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
-				st->i2c_talk_onoff = 1;
-				break;
-			}
-			break;
-		case TUNER_RS2000:
-			switch (wbuf[3]) {
-			case 0x8c:
-				rbuf[0] = 0x55;
-				rbuf[1] = 0xff;
-				if (st->last_key == st->time_key) {
-					st->key_timeout++;
-					if (st->key_timeout > 5)
-						rbuf[1] = 0;
-				} else
-					st->key_timeout = 0;
-				st->last_key = st->time_key;
-				break;
-			default:
-				lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
-				st->i2c_talk_onoff = 1;
-				break;
-			}
-		default:
-			break;
-		}
-
-		deb_info(4, "I2C From Interrupt Message out(%02x) in(%02x)",
-				wbuf[3], rbuf[1]);
-
-	}
-
-	return ret;
-}
-
-
-static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-				 int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	struct lme2510_state *st = d->priv;
-	static u8 obuf[64], ibuf[64];
-	int i, read, read_o;
-	u16 len;
-	u8 gate = st->i2c_gate;
-
-	mutex_lock(&d->i2c_mutex);
-
-	if (gate == 0)
-		gate = 5;
-
-	if (num > 2)
-		warn("more than 2 i2c messages"
-			"at a time is not handled yet.	TODO.");
-
-	for (i = 0; i < num; i++) {
-		read_o = 1 & (msg[i].flags & I2C_M_RD);
-		read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
-		read |= read_o;
-		gate = (msg[i].addr == st->i2c_tuner_addr)
-			? (read)	? st->i2c_tuner_gate_r
-					: st->i2c_tuner_gate_w
-			: st->i2c_gate;
-		obuf[0] = gate | (read << 7);
-
-		if (gate == 5)
-			obuf[1] = (read) ? 2 : msg[i].len + 1;
-		else
-			obuf[1] = msg[i].len + read + 1;
-
-		obuf[2] = msg[i].addr;
-		if (read) {
-			if (read_o)
-				len = 3;
-			else {
-				memcpy(&obuf[3], msg[i].buf, msg[i].len);
-				obuf[msg[i].len+3] = msg[i+1].len;
-				len = msg[i].len+4;
-			}
-		} else {
-			memcpy(&obuf[3], msg[i].buf, msg[i].len);
-			len = msg[i].len+3;
-		}
-
-		if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) {
-			deb_info(1, "i2c transfer failed.");
-			mutex_unlock(&d->i2c_mutex);
-			return -EAGAIN;
-		}
-
-		if (read) {
-			if (read_o)
-				memcpy(msg[i].buf, &ibuf[1], msg[i].len);
-			else {
-				memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
-				i++;
-			}
-		}
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return i;
-}
-
-static u32 lme2510_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm lme2510_i2c_algo = {
-	.master_xfer   = lme2510_i2c_xfer,
-	.functionality = lme2510_i2c_func,
-};
-
-/* Callbacks for DVB USB */
-static int lme2510_identify_state(struct usb_device *udev,
-		struct dvb_usb_device_properties *props,
-		struct dvb_usb_device_description **desc,
-		int *cold)
-{
-	if (pid_filter != 2)
-		props->adapter[0].fe[0].caps &=
-			~DVB_USB_ADAP_NEED_PID_FILTERING;
-	*cold = 0;
-	return 0;
-}
-
-static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	struct lme2510_state *st = adap->dev->priv;
-	static u8 clear_reg_3[] = LME_ALL_PIDS;
-	static u8 rbuf[1];
-	int ret = 0, rlen = sizeof(rbuf);
-
-	deb_info(1, "STM  (%02x)", onoff);
-
-	/* Streaming is started by FE_HAS_LOCK */
-	if (onoff == 1)
-		st->stream_on = 1;
-	else {
-		deb_info(1, "STM Steam Off");
-		/* mutex is here only to avoid collision with I2C */
-		mutex_lock(&adap->dev->i2c_mutex);
-
-		ret = lme2510_usb_talk(adap->dev, clear_reg_3,
-				sizeof(clear_reg_3), rbuf, rlen);
-		st->stream_on = 0;
-		st->i2c_talk_onoff = 1;
-
-		mutex_unlock(&adap->dev->i2c_mutex);
-	}
-
-	return (ret < 0) ? -ENODEV : 0;
-}
-
-static u8 check_sum(u8 *p, u8 len)
-{
-	u8 sum = 0;
-	while (len--)
-		sum += *p++;
-	return sum;
-}
-
-static int lme2510_download_firmware(struct usb_device *dev,
-					const struct firmware *fw)
-{
-	int ret = 0;
-	u8 *data;
-	u16 j, wlen, len_in, start, end;
-	u8 packet_size, dlen, i;
-	u8 *fw_data;
-
-	packet_size = 0x31;
-	len_in = 1;
-
-	data = kzalloc(512, GFP_KERNEL);
-	if (!data) {
-		info("FRM Could not start Firmware Download (Buffer allocation failed)");
-		return -ENOMEM;
-	}
-
-	info("FRM Starting Firmware Download");
-
-	for (i = 1; i < 3; i++) {
-		start = (i == 1) ? 0 : 512;
-		end = (i == 1) ? 512 : fw->size;
-		for (j = start; j < end; j += (packet_size+1)) {
-			fw_data = (u8 *)(fw->data + j);
-			if ((end - j) > packet_size) {
-				data[0] = i;
-				dlen = packet_size;
-			} else {
-				data[0] = i | 0x80;
-				dlen = (u8)(end - j)-1;
-			}
-			data[1] = dlen;
-			memcpy(&data[2], fw_data, dlen+1);
-			wlen = (u8) dlen + 4;
-			data[wlen-1] = check_sum(fw_data, dlen+1);
-			deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3],
-				data[dlen+2], data[dlen+3]);
-			ret |= lme2510_bulk_write(dev, data,  wlen, 1);
-			ret |= lme2510_bulk_read(dev, data, len_in , 1);
-			ret |= (data[0] == 0x88) ? 0 : -1;
-		}
-	}
-
-	usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			0x06, 0x80, 0x0200, 0x00, data, 0x0109, 1000);
-
-
-	data[0] = 0x8a;
-	len_in = 1;
-	msleep(2000);
-	ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Resetting*/
-	ret |= lme2510_bulk_read(dev, data, len_in, 1);
-	msleep(400);
-
-	if (ret < 0)
-		info("FRM Firmware Download Failed (%04x)" , ret);
-	else
-		info("FRM Firmware Download Completed - Resetting Device");
-
-	kfree(data);
-	return (ret < 0) ? -ENODEV : 0;
-}
-
-static void lme_coldreset(struct usb_device *dev)
-{
-	int ret = 0, len_in;
-	u8 data[512] = {0};
-
-	data[0] = 0x0a;
-	len_in = 1;
-	info("FRM Firmware Cold Reset");
-	ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Cold Resetting*/
-	ret |= lme2510_bulk_read(dev, data, len_in, 1);
-
-	return;
-}
-
-static int lme_firmware_switch(struct usb_device *udev, int cold)
-{
-	const struct firmware *fw = NULL;
-	const char fw_c_s7395[] = "dvb-usb-lme2510c-s7395.fw";
-	const char fw_c_lg[] = "dvb-usb-lme2510c-lg.fw";
-	const char fw_c_s0194[] = "dvb-usb-lme2510c-s0194.fw";
-	const char fw_c_rs2000[] = "dvb-usb-lme2510c-rs2000.fw";
-	const char fw_lg[] = "dvb-usb-lme2510-lg.fw";
-	const char fw_s0194[] = "dvb-usb-lme2510-s0194.fw";
-	const char *fw_lme;
-	int ret = 0, cold_fw;
-
-	cold = (cold > 0) ? (cold & 1) : 0;
-
-	cold_fw = !cold;
-
-	switch (le16_to_cpu(udev->descriptor.idProduct)) {
-	case 0x1122:
-		switch (dvb_usb_lme2510_firmware) {
-		default:
-			dvb_usb_lme2510_firmware = TUNER_S0194;
-		case TUNER_S0194:
-			fw_lme = fw_s0194;
-			ret = request_firmware(&fw, fw_lme, &udev->dev);
-			if (ret == 0) {
-				cold = 0;
-				break;
-			}
-			dvb_usb_lme2510_firmware = TUNER_LG;
-		case TUNER_LG:
-			fw_lme = fw_lg;
-			ret = request_firmware(&fw, fw_lme, &udev->dev);
-			if (ret == 0)
-				break;
-			info("FRM No Firmware Found - please install");
-			dvb_usb_lme2510_firmware = TUNER_DEFAULT;
-			cold = 0;
-			cold_fw = 0;
-			break;
-		}
-		break;
-	case 0x1120:
-		switch (dvb_usb_lme2510_firmware) {
-		default:
-			dvb_usb_lme2510_firmware = TUNER_S7395;
-		case TUNER_S7395:
-			fw_lme = fw_c_s7395;
-			ret = request_firmware(&fw, fw_lme, &udev->dev);
-			if (ret == 0) {
-				cold = 0;
-				break;
-			}
-			dvb_usb_lme2510_firmware = TUNER_LG;
-		case TUNER_LG:
-			fw_lme = fw_c_lg;
-			ret = request_firmware(&fw, fw_lme, &udev->dev);
-			if (ret == 0)
-				break;
-			dvb_usb_lme2510_firmware = TUNER_S0194;
-		case TUNER_S0194:
-			fw_lme = fw_c_s0194;
-			ret = request_firmware(&fw, fw_lme, &udev->dev);
-			if (ret == 0)
-				break;
-			info("FRM No Firmware Found - please install");
-			dvb_usb_lme2510_firmware = TUNER_DEFAULT;
-			cold = 0;
-			cold_fw = 0;
-			break;
-		}
-		break;
-	case 0x22f0:
-		fw_lme = fw_c_rs2000;
-		ret = request_firmware(&fw, fw_lme, &udev->dev);
-		dvb_usb_lme2510_firmware = TUNER_RS2000;
-		break;
-	default:
-		fw_lme = fw_c_s7395;
-	}
-
-
-	if (cold_fw) {
-		info("FRM Loading %s file", fw_lme);
-		ret = lme2510_download_firmware(udev, fw);
-	}
-
-	release_firmware(fw);
-
-	if (cold) {
-		info("FRM Changing to %s firmware", fw_lme);
-		lme_coldreset(udev);
-		return -ENODEV;
-	}
-
-	return ret;
-}
-
-static int lme2510_kill_urb(struct usb_data_stream *stream)
-{
-	int i;
-
-	for (i = 0; i < stream->urbs_submitted; i++) {
-		deb_info(3, "killing URB no. %d.", i);
-		/* stop the URB */
-		usb_kill_urb(stream->urb_list[i]);
-	}
-	stream->urbs_submitted = 0;
-
-	return 0;
-}
-
-static struct tda10086_config tda10086_config = {
-	.demod_address = 0x1c,
-	.invert = 0,
-	.diseqc_tone = 1,
-	.xtal_freq = TDA10086_XTAL_16M,
-};
-
-static struct stv0288_config lme_config = {
-	.demod_address = 0xd0,
-	.min_delay_ms = 15,
-	.inittab = s7395_inittab,
-};
-
-static struct ix2505v_config lme_tuner = {
-	.tuner_address = 0xc0,
-	.min_delay_ms = 100,
-	.tuner_gain = 0x0,
-	.tuner_chargepump = 0x3,
-};
-
-static struct stv0299_config sharp_z0194_config = {
-	.demod_address = 0xd0,
-	.inittab = sharp_z0194a_inittab,
-	.mclk = 88000000UL,
-	.invert = 0,
-	.skip_reinit = 0,
-	.lock_output = STV0299_LOCKOUTPUT_1,
-	.volt13_op0_op1 = STV0299_VOLT13_OP1,
-	.min_delay_ms = 100,
-	.set_symbol_rate = sharp_z0194a_set_symbol_rate,
-};
-
-static int dm04_rs2000_set_ts_param(struct dvb_frontend *fe,
-	int caller)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct dvb_usb_device *d = adap->dev;
-	struct lme2510_state *st = d->priv;
-
-	mutex_lock(&d->i2c_mutex);
-	if ((st->i2c_talk_onoff == 1) && (st->stream_on & 1)) {
-		st->i2c_talk_onoff = 0;
-		lme2510_stream_restart(d);
-	}
-	mutex_unlock(&d->i2c_mutex);
-
-	return 0;
-}
-
-static struct m88rs2000_config m88rs2000_config = {
-	.demod_addr = 0xd0,
-	.tuner_addr = 0xc0,
-	.set_ts_params = dm04_rs2000_set_ts_param,
-};
-
-static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
-					fe_sec_voltage_t voltage)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	static u8 voltage_low[]	= LME_VOLTAGE_L;
-	static u8 voltage_high[] = LME_VOLTAGE_H;
-	static u8 rbuf[1];
-	int ret = 0, len = 3, rlen = 1;
-
-	mutex_lock(&adap->dev->i2c_mutex);
-
-	switch (voltage) {
-	case SEC_VOLTAGE_18:
-		ret |= lme2510_usb_talk(adap->dev,
-			voltage_high, len, rbuf, rlen);
-		break;
-
-	case SEC_VOLTAGE_OFF:
-	case SEC_VOLTAGE_13:
-	default:
-		ret |= lme2510_usb_talk(adap->dev,
-				voltage_low, len, rbuf, rlen);
-		break;
-	}
-
-	mutex_unlock(&adap->dev->i2c_mutex);
-
-	return (ret < 0) ? -ENODEV : 0;
-}
-
-static int dm04_rs2000_read_signal_strength(struct dvb_frontend *fe,
-	u16 *strength)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct lme2510_state *st = adap->dev->priv;
-
-	*strength = (u16)((u32)st->signal_level * 0xffff / 0x7f);
-	return 0;
-}
-
-static int dm04_rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct lme2510_state *st = adap->dev->priv;
-
-	*snr = (u16)((u32)st->signal_sn * 0xffff / 0xff);
-	return 0;
-}
-
-static int lme_name(struct dvb_usb_adapter *adap)
-{
-	struct lme2510_state *st = adap->dev->priv;
-	const char *desc = adap->dev->desc->name;
-	char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395",
-				" SHARP:BS2F7HZ0194", " RS2000"};
-	char *name = adap->fe_adap[0].fe->ops.info.name;
-
-	strlcpy(name, desc, 128);
-	strlcat(name, fe_name[st->tuner_config], 128);
-
-	return 0;
-}
-
-static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct lme2510_state *st = adap->dev->priv;
-
-	int ret = 0;
-
-	st->i2c_talk_onoff = 1;
-	switch (le16_to_cpu(adap->dev->udev->descriptor.idProduct)) {
-	case 0x1122:
-	case 0x1120:
-		st->i2c_gate = 4;
-		adap->fe_adap[0].fe = dvb_attach(tda10086_attach,
-			&tda10086_config, &adap->dev->i2c_adap);
-		if (adap->fe_adap[0].fe) {
-			info("TUN Found Frontend TDA10086");
-			st->i2c_tuner_gate_w = 4;
-			st->i2c_tuner_gate_r = 4;
-			st->i2c_tuner_addr = 0xc0;
-			st->tuner_config = TUNER_LG;
-			if (dvb_usb_lme2510_firmware != TUNER_LG) {
-				dvb_usb_lme2510_firmware = TUNER_LG;
-				ret = lme_firmware_switch(adap->dev->udev, 1);
-			}
-			break;
-		}
-
-		st->i2c_gate = 4;
-		adap->fe_adap[0].fe = dvb_attach(stv0299_attach,
-				&sharp_z0194_config, &adap->dev->i2c_adap);
-		if (adap->fe_adap[0].fe) {
-			info("FE Found Stv0299");
-			st->i2c_tuner_gate_w = 4;
-			st->i2c_tuner_gate_r = 5;
-			st->i2c_tuner_addr = 0xc0;
-			st->tuner_config = TUNER_S0194;
-			if (dvb_usb_lme2510_firmware != TUNER_S0194) {
-				dvb_usb_lme2510_firmware = TUNER_S0194;
-				ret = lme_firmware_switch(adap->dev->udev, 1);
-			}
-			break;
-		}
-
-		st->i2c_gate = 5;
-		adap->fe_adap[0].fe = dvb_attach(stv0288_attach, &lme_config,
-			&adap->dev->i2c_adap);
-
-		if (adap->fe_adap[0].fe) {
-			info("FE Found Stv0288");
-			st->i2c_tuner_gate_w = 4;
-			st->i2c_tuner_gate_r = 5;
-			st->i2c_tuner_addr = 0xc0;
-			st->tuner_config = TUNER_S7395;
-			if (dvb_usb_lme2510_firmware != TUNER_S7395) {
-				dvb_usb_lme2510_firmware = TUNER_S7395;
-				ret = lme_firmware_switch(adap->dev->udev, 1);
-			}
-			break;
-		}
-	case 0x22f0:
-		st->i2c_gate = 5;
-		adap->fe_adap[0].fe = dvb_attach(m88rs2000_attach,
-			&m88rs2000_config, &adap->dev->i2c_adap);
-
-		if (adap->fe_adap[0].fe) {
-			info("FE Found M88RS2000");
-			st->i2c_tuner_gate_w = 5;
-			st->i2c_tuner_gate_r = 5;
-			st->i2c_tuner_addr = 0xc0;
-			st->tuner_config = TUNER_RS2000;
-			adap->fe_adap[0].fe->ops.read_signal_strength =
-				dm04_rs2000_read_signal_strength;
-			adap->fe_adap[0].fe->ops.read_snr =
-				dm04_rs2000_read_snr;
-		}
-		break;
-	}
-
-	if (adap->fe_adap[0].fe == NULL) {
-			info("DM04/QQBOX Not Powered up or not Supported");
-			return -ENODEV;
-	}
-
-	if (ret) {
-		if (adap->fe_adap[0].fe) {
-			dvb_frontend_detach(adap->fe_adap[0].fe);
-			adap->fe_adap[0].fe = NULL;
-		}
-		adap->dev->props.rc.core.rc_codes = NULL;
-		return -ENODEV;
-	}
-
-	adap->fe_adap[0].fe->ops.set_voltage = dm04_lme2510_set_voltage;
-	ret = lme_name(adap);
-	return ret;
-}
-
-static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
-{
-	struct lme2510_state *st = adap->dev->priv;
-	char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA", "RS2000"};
-	int ret = 0;
-
-	switch (st->tuner_config) {
-	case TUNER_LG:
-		if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0xc0,
-			&adap->dev->i2c_adap, 1))
-			ret = st->tuner_config;
-		break;
-	case TUNER_S7395:
-		if (dvb_attach(ix2505v_attach , adap->fe_adap[0].fe, &lme_tuner,
-			&adap->dev->i2c_adap))
-			ret = st->tuner_config;
-		break;
-	case TUNER_S0194:
-		if (dvb_attach(dvb_pll_attach , adap->fe_adap[0].fe, 0xc0,
-			&adap->dev->i2c_adap, DVB_PLL_OPERA1))
-			ret = st->tuner_config;
-		break;
-	case TUNER_RS2000:
-		ret = st->tuner_config;
-		break;
-	default:
-		break;
-	}
-
-	if (ret)
-		info("TUN Found %s tuner", tun_msg[ret]);
-	else {
-		info("TUN No tuner found --- resetting device");
-		lme_coldreset(adap->dev->udev);
-		return -ENODEV;
-	}
-
-	/* Start the Interrupt*/
-	ret = lme2510_int_read(adap);
-	if (ret < 0) {
-		info("INT Unable to start Interrupt Service");
-		return -ENODEV;
-	}
-
-	return ret;
-}
-
-static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
-{
-	struct lme2510_state *st = d->priv;
-	static u8 lnb_on[] = LNB_ON;
-	static u8 lnb_off[] = LNB_OFF;
-	static u8 rbuf[1];
-	int ret = 0, len = 3, rlen = 1;
-
-	mutex_lock(&d->i2c_mutex);
-
-	if (onoff)
-		ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen);
-	else
-		ret = lme2510_usb_talk(d, lnb_off, len, rbuf, rlen);
-
-	st->i2c_talk_onoff = 1;
-
-	mutex_unlock(&d->i2c_mutex);
-
-	return ret;
-}
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties lme2510_properties;
-static struct dvb_usb_device_properties lme2510c_properties;
-
-static int lme2510_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	struct usb_device *udev = interface_to_usbdev(intf);
-
-	usb_reset_configuration(udev);
-
-	usb_set_interface(udev, intf->cur_altsetting->desc.bInterfaceNumber, 1);
-
-	if (udev->speed != USB_SPEED_HIGH) {
-		usb_reset_device(udev);
-		info("DEV Failed to connect in HIGH SPEED mode");
-		return -ENODEV;
-	}
-
-	if (lme2510_return_status(udev) == 0x44) {
-		lme_firmware_switch(udev, 0);
-		return -ENODEV;
-	}
-
-	if (0 == dvb_usb_device_init(intf, &lme2510_properties,
-				     THIS_MODULE, NULL, adapter_nr)) {
-		info("DEV registering device driver");
-		return 0;
-	}
-	if (0 == dvb_usb_device_init(intf, &lme2510c_properties,
-				     THIS_MODULE, NULL, adapter_nr)) {
-		info("DEV registering device driver");
-		return 0;
-	}
-
-	info("DEV lme2510 Error");
-	return -ENODEV;
-
-}
-
-static struct usb_device_id lme2510_table[] = {
-	{ USB_DEVICE(0x3344, 0x1122) },  /* LME2510 */
-	{ USB_DEVICE(0x3344, 0x1120) },  /* LME2510C */
-	{ USB_DEVICE(0x3344, 0x22f0) },  /* LME2510C RS2000 */
-	{}		/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, lme2510_table);
-
-static struct dvb_usb_device_properties lme2510_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-	.size_of_priv = sizeof(struct lme2510_state),
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.caps = DVB_USB_ADAP_HAS_PID_FILTER|
-				DVB_USB_ADAP_NEED_PID_FILTERING|
-				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-			.streaming_ctrl   = lme2510_streaming_ctrl,
-			.pid_filter_count = 32,
-			.pid_filter = lme2510_pid_filter,
-			.pid_filter_ctrl  = lme2510_pid_filter_ctrl,
-			.frontend_attach  = dm04_lme2510_frontend_attach,
-			.tuner_attach = dm04_lme2510_tuner,
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 10,
-				.endpoint = 0x06,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-
-					}
-				}
-			}
-		}},
-		}
-	},
-	.rc.core = {
-		.protocol	= RC_TYPE_NEC,
-		.module_name	= "LME2510 Remote Control",
-		.allowed_protos	= RC_TYPE_NEC,
-		.rc_codes	= RC_MAP_LME2510,
-	},
-	.power_ctrl       = lme2510_powerup,
-	.identify_state   = lme2510_identify_state,
-	.i2c_algo         = &lme2510_i2c_algo,
-	.generic_bulk_ctrl_endpoint = 0,
-	.num_device_descs = 1,
-	.devices = {
-		{   "DM04_LME2510_DVB-S",
-			{ &lme2510_table[0], NULL },
-			},
-
-	}
-};
-
-static struct dvb_usb_device_properties lme2510c_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-	.size_of_priv = sizeof(struct lme2510_state),
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.caps = DVB_USB_ADAP_HAS_PID_FILTER|
-				DVB_USB_ADAP_NEED_PID_FILTERING|
-				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-			.streaming_ctrl   = lme2510_streaming_ctrl,
-			.pid_filter_count = 32,
-			.pid_filter = lme2510_pid_filter,
-			.pid_filter_ctrl  = lme2510_pid_filter_ctrl,
-			.frontend_attach  = dm04_lme2510_frontend_attach,
-			.tuner_attach = dm04_lme2510_tuner,
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 10,
-				.endpoint = 0x8,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-
-					}
-				}
-			}
-		}},
-		}
-	},
-	.rc.core = {
-		.protocol	= RC_TYPE_NEC,
-		.module_name	= "LME2510 Remote Control",
-		.allowed_protos	= RC_TYPE_NEC,
-		.rc_codes	= RC_MAP_LME2510,
-	},
-	.power_ctrl       = lme2510_powerup,
-	.identify_state   = lme2510_identify_state,
-	.i2c_algo         = &lme2510_i2c_algo,
-	.generic_bulk_ctrl_endpoint = 0,
-	.num_device_descs = 2,
-	.devices = {
-		{   "DM04_LME2510C_DVB-S",
-			{ &lme2510_table[1], NULL },
-			},
-		{   "DM04_LME2510C_DVB-S RS2000",
-			{ &lme2510_table[2], NULL },
-			},
-	}
-};
-
-static void *lme2510_exit_int(struct dvb_usb_device *d)
-{
-	struct lme2510_state *st = d->priv;
-	struct dvb_usb_adapter *adap = &d->adapter[0];
-	void *buffer = NULL;
-
-	if (adap != NULL) {
-		lme2510_kill_urb(&adap->fe_adap[0].stream);
-		adap->feedcount = 0;
-	}
-
-	if (st->usb_buffer != NULL) {
-		st->i2c_talk_onoff = 1;
-		st->signal_lock = 0;
-		st->signal_level = 0;
-		st->signal_sn = 0;
-		buffer = st->usb_buffer;
-	}
-
-	if (st->lme_urb != NULL) {
-		usb_kill_urb(st->lme_urb);
-		usb_free_coherent(d->udev, 128, st->buffer,
-				  st->lme_urb->transfer_dma);
-		info("Interrupt Service Stopped");
-	}
-
-	return buffer;
-}
-
-static void lme2510_exit(struct usb_interface *intf)
-{
-	struct dvb_usb_device *d = usb_get_intfdata(intf);
-	void *usb_buffer;
-
-	if (d != NULL) {
-		usb_buffer = lme2510_exit_int(d);
-		dvb_usb_device_exit(intf);
-		if (usb_buffer != NULL)
-			kfree(usb_buffer);
-	}
-}
-
-static struct usb_driver lme2510_driver = {
-	.name		= "LME2510C_DVB-S",
-	.probe		= lme2510_probe,
-	.disconnect	= lme2510_exit,
-	.id_table	= lme2510_table,
-};
-
-module_usb_driver(lme2510_driver);
-
-MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
-MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
-MODULE_VERSION("1.99");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.h b/drivers/media/dvb/dvb-usb/lmedm04.h
deleted file mode 100644
index e9c2072..0000000
--- a/drivers/media/dvb/dvb-usb/lmedm04.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/* DVB USB compliant linux driver for
- *
- * DM04/QQBOX DVB-S USB BOX	LME2510C + SHARP:BS2F7HZ7395
- *				LME2510C + LG TDQY-P001F
- *				LME2510 + LG TDQY-P001F
- *
- * MVB7395 (LME2510C+SHARP:BS2F7HZ7395)
- * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V)
- *
- * MVB001F (LME2510+LGTDQT-P001F)
- * LG TDQY - P001F =(TDA8263 + TDA10086H)
- *
- * MVB0001F (LME2510C+LGTDQT-P001F)
- *
- * 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,  version 2.
- * *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#ifndef _DVB_USB_LME2510_H_
-#define _DVB_USB_LME2510_H_
-
-/* Streamer &  PID
- *
- * Note:	These commands do not actually stop the streaming
- *		but form some kind of packet filtering/stream count
- *		or tuning related functions.
- *  06 XX
- *  offset 1 = 00 Enable Streaming
- *
- *
- *  PID
- *  03 XX XX  ----> reg number ---> setting....20 XX
- *  offset 1 = length
- *  offset 2 = start of data
- *  end byte -1 = 20
- *  end byte = clear pid always a0, other wise 9c, 9a ??
- *
-*/
-#define LME_ST_ON_W	{0x06, 0x00}
-#define LME_CLEAR_PID   {0x03, 0x02, 0x20, 0xa0}
-#define LME_ZERO_PID	{0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c}
-#define LME_ALL_PIDS	{0x03, 0x06, 0x00, 0xff, 0x01, 0x1f, 0x20, 0x81}
-
-/*  LNB Voltage
- *  07 XX XX
- *  offset 1 = 01
- *  offset 2 = 00=Voltage low 01=Voltage high
- *
- *  LNB Power
- *  03 01 XX
- *  offset 2 = 00=ON 01=OFF
- */
-
-#define LME_VOLTAGE_L	{0x07, 0x01, 0x00}
-#define LME_VOLTAGE_H	{0x07, 0x01, 0x01}
-#define LNB_ON		{0x3a, 0x01, 0x00}
-#define LNB_OFF		{0x3a, 0x01, 0x01}
-
-/* Initial stv0288 settings for 7395 Frontend */
-static u8 s7395_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x20,
-	0x03, 0xa0,
-	0x04, 0xa0,
-	0x05, 0x12,
-	0x06, 0x00,
-	0x09, 0x00,
-	0x0a, 0x04,
-	0x0b, 0x00,
-	0x0c, 0x00,
-	0x0d, 0x00,
-	0x0e, 0xc1,
-	0x0f, 0x54,
-	0x11, 0x7a,
-	0x12, 0x03,
-	0x13, 0x48,
-	0x14, 0x84,
-	0x15, 0xc5,
-	0x16, 0xb8,
-	0x17, 0x9c,
-	0x18, 0x00,
-	0x19, 0xa6,
-	0x1a, 0x88,
-	0x1b, 0x8f,
-	0x1c, 0xf0,
-	0x20, 0x0b,
-	0x21, 0x54,
-	0x22, 0xff,
-	0x23, 0x01,
-	0x28, 0x46,
-	0x29, 0x66,
-	0x2a, 0x90,
-	0x2b, 0xfa,
-	0x2c, 0xd9,
-	0x30, 0x0,
-	0x31, 0x1e,
-	0x32, 0x14,
-	0x33, 0x0f,
-	0x34, 0x09,
-	0x35, 0x0c,
-	0x36, 0x05,
-	0x37, 0x2f,
-	0x38, 0x16,
-	0x39, 0xbd,
-	0x3a, 0x0,
-	0x3b, 0x13,
-	0x3c, 0x11,
-	0x3d, 0x30,
-	0x40, 0x63,
-	0x41, 0x04,
-	0x42, 0x20,
-	0x43, 0x00,
-	0x44, 0x00,
-	0x45, 0x00,
-	0x46, 0x00,
-	0x47, 0x00,
-	0x4a, 0x00,
-	0x50, 0x10,
-	0x51, 0x36,
-	0x52, 0x21,
-	0x53, 0x94,
-	0x54, 0xb2,
-	0x55, 0x29,
-	0x56, 0x64,
-	0x57, 0x2b,
-	0x58, 0x54,
-	0x59, 0x86,
-	0x5a, 0x00,
-	0x5b, 0x9b,
-	0x5c, 0x08,
-	0x5d, 0x7f,
-	0x5e, 0xff,
-	0x5f, 0x8d,
-	0x70, 0x0,
-	0x71, 0x0,
-	0x72, 0x0,
-	0x74, 0x0,
-	0x75, 0x0,
-	0x76, 0x0,
-	0x81, 0x0,
-	0x82, 0x3f,
-	0x83, 0x3f,
-	0x84, 0x0,
-	0x85, 0x0,
-	0x88, 0x0,
-	0x89, 0x0,
-	0x8a, 0x0,
-	0x8b, 0x0,
-	0x8c, 0x0,
-	0x90, 0x0,
-	0x91, 0x0,
-	0x92, 0x0,
-	0x93, 0x0,
-	0x94, 0x1c,
-	0x97, 0x0,
-	0xa0, 0x48,
-	0xa1, 0x0,
-	0xb0, 0xb8,
-	0xb1, 0x3a,
-	0xb2, 0x10,
-	0xb3, 0x82,
-	0xb4, 0x80,
-	0xb5, 0x82,
-	0xb6, 0x82,
-	0xb7, 0x82,
-	0xb8, 0x20,
-	0xb9, 0x0,
-	0xf0, 0x0,
-	0xf1, 0x0,
-	0xf2, 0xc0,
-	0xff, 0xff,
-};
-#endif
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
deleted file mode 100644
index 288af29..0000000
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ /dev/null
@@ -1,1099 +0,0 @@
-/* DVB USB compliant linux driver for MSI Mega Sky 580 DVB-T USB2.0 receiver
- *
- * Copyright (C) 2006 Aapo Tahkola (aet@rasterburn.org)
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-
-#include "m920x.h"
-
-#include "mt352.h"
-#include "mt352_priv.h"
-#include "qt1010.h"
-#include "tda1004x.h"
-#include "tda827x.h"
-
-#include <media/tuner.h>
-#include "tuner-simple.h"
-#include <asm/unaligned.h>
-
-/* debug */
-static int dvb_usb_m920x_debug;
-module_param_named(debug,dvb_usb_m920x_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid);
-
-static inline int m920x_read(struct usb_device *udev, u8 request, u16 value,
-			     u16 index, void *data, int size)
-{
-	int ret;
-
-	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-			      request, USB_TYPE_VENDOR | USB_DIR_IN,
-			      value, index, data, size, 2000);
-	if (ret < 0) {
-		printk(KERN_INFO "m920x_read = error: %d\n", ret);
-		return ret;
-	}
-
-	if (ret != size) {
-		deb("m920x_read = no data\n");
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static inline int m920x_write(struct usb_device *udev, u8 request,
-			      u16 value, u16 index)
-{
-	int ret;
-
-	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-			      request, USB_TYPE_VENDOR | USB_DIR_OUT,
-			      value, index, NULL, 0, 2000);
-
-	return ret;
-}
-
-static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
-{
-	int ret = 0, i, epi, flags = 0;
-	int adap_enabled[M9206_MAX_ADAPTERS] = { 0 };
-
-	/* Remote controller init. */
-	if (d->props.rc.legacy.rc_query) {
-		deb("Initialising remote control\n");
-		while (rc_seq->address) {
-			if ((ret = m920x_write(d->udev, M9206_CORE,
-					       rc_seq->data,
-					       rc_seq->address)) != 0) {
-				deb("Initialising remote control failed\n");
-				return ret;
-			}
-
-			rc_seq++;
-		}
-
-		deb("Initialising remote control success\n");
-	}
-
-	for (i = 0; i < d->props.num_adapters; i++)
-		flags |= d->adapter[i].props.fe[0].caps;
-
-	/* Some devices(Dposh) might crash if we attempt touch at all. */
-	if (flags & DVB_USB_ADAP_HAS_PID_FILTER) {
-		for (i = 0; i < d->props.num_adapters; i++) {
-			epi = d->adapter[i].props.fe[0].stream.endpoint - 0x81;
-
-			if (epi < 0 || epi >= M9206_MAX_ADAPTERS) {
-				printk(KERN_INFO "m920x: Unexpected adapter endpoint!\n");
-				return -EINVAL;
-			}
-
-			adap_enabled[epi] = 1;
-		}
-
-		for (i = 0; i < M9206_MAX_ADAPTERS; i++) {
-			if (adap_enabled[i])
-				continue;
-
-			if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x0)) != 0)
-				return ret;
-
-			if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x02f5)) != 0)
-				return ret;
-		}
-	}
-
-	return ret;
-}
-
-static int m920x_init_ep(struct usb_interface *intf)
-{
-	struct usb_device *udev = interface_to_usbdev(intf);
-	struct usb_host_interface *alt;
-
-	if ((alt = usb_altnum_to_altsetting(intf, 1)) == NULL) {
-		deb("No alt found!\n");
-		return -ENODEV;
-	}
-
-	return usb_set_interface(udev, alt->desc.bInterfaceNumber,
-				 alt->desc.bAlternateSetting);
-}
-
-static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
-{
-	struct m920x_state *m = d->priv;
-	int i, ret = 0;
-	u8 *rc_state;
-
-	rc_state = kmalloc(2, GFP_KERNEL);
-	if (!rc_state)
-		return -ENOMEM;
-
-	if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0)
-		goto out;
-
-	if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
-		goto out;
-
-	for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
-		if (rc5_data(&d->props.rc.legacy.rc_map_table[i]) == rc_state[1]) {
-			*event = d->props.rc.legacy.rc_map_table[i].keycode;
-
-			switch(rc_state[0]) {
-			case 0x80:
-				*state = REMOTE_NO_KEY_PRESSED;
-				goto out;
-
-			case 0x88: /* framing error or "invalid code" */
-			case 0x99:
-			case 0xc0:
-			case 0xd8:
-				*state = REMOTE_NO_KEY_PRESSED;
-				m->rep_count = 0;
-				goto out;
-
-			case 0x93:
-			case 0x92:
-			case 0x83: /* pinnacle PCTV310e */
-			case 0x82:
-				m->rep_count = 0;
-				*state = REMOTE_KEY_PRESSED;
-				goto out;
-
-			case 0x91:
-			case 0x81: /* pinnacle PCTV310e */
-				/* prevent immediate auto-repeat */
-				if (++m->rep_count > 2)
-					*state = REMOTE_KEY_REPEAT;
-				else
-					*state = REMOTE_NO_KEY_PRESSED;
-				goto out;
-
-			default:
-				deb("Unexpected rc state %02x\n", rc_state[0]);
-				*state = REMOTE_NO_KEY_PRESSED;
-				goto out;
-			}
-		}
-
-	if (rc_state[1] != 0)
-		deb("Unknown rc key %02x\n", rc_state[1]);
-
-	*state = REMOTE_NO_KEY_PRESSED;
-
- out:
-	kfree(rc_state);
-	return ret;
-}
-
-/* I2C */
-static int m920x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int i, j;
-	int ret = 0;
-
-	if (!num)
-		return -EINVAL;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	for (i = 0; i < num; i++) {
-		if (msg[i].flags & (I2C_M_NO_RD_ACK | I2C_M_IGNORE_NAK | I2C_M_TEN) || msg[i].len == 0) {
-			/* For a 0 byte message, I think sending the address
-			 * to index 0x80|0x40 would be the correct thing to
-			 * do.  However, zero byte messages are only used for
-			 * probing, and since we don't know how to get the
-			 * slave's ack, we can't probe. */
-			ret = -ENOTSUPP;
-			goto unlock;
-		}
-		/* Send START & address/RW bit */
-		if (!(msg[i].flags & I2C_M_NOSTART)) {
-			if ((ret = m920x_write(d->udev, M9206_I2C,
-					(msg[i].addr << 1) |
-					(msg[i].flags & I2C_M_RD ? 0x01 : 0), 0x80)) != 0)
-				goto unlock;
-			/* Should check for ack here, if we knew how. */
-		}
-		if (msg[i].flags & I2C_M_RD) {
-			for (j = 0; j < msg[i].len; j++) {
-				/* Last byte of transaction?
-				 * Send STOP, otherwise send ACK. */
-				int stop = (i+1 == num && j+1 == msg[i].len) ? 0x40 : 0x01;
-
-				if ((ret = m920x_read(d->udev, M9206_I2C, 0x0,
-						      0x20 | stop,
-						      &msg[i].buf[j], 1)) != 0)
-					goto unlock;
-			}
-		} else {
-			for (j = 0; j < msg[i].len; j++) {
-				/* Last byte of transaction? Then send STOP. */
-				int stop = (i+1 == num && j+1 == msg[i].len) ? 0x40 : 0x00;
-
-				if ((ret = m920x_write(d->udev, M9206_I2C, msg[i].buf[j], stop)) != 0)
-					goto unlock;
-				/* Should check for ack here too. */
-			}
-		}
-	}
-	ret = num;
-
- unlock:
-	mutex_unlock(&d->i2c_mutex);
-
-	return ret;
-}
-
-static u32 m920x_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm m920x_i2c_algo = {
-	.master_xfer   = m920x_i2c_xfer,
-	.functionality = m920x_i2c_func,
-};
-
-/* pid filter */
-static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid)
-{
-	int ret = 0;
-
-	if (pid >= 0x8000)
-		return -EINVAL;
-
-	pid |= 0x8000;
-
-	if ((ret = m920x_write(d->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
-		return ret;
-
-	if ((ret = m920x_write(d->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
-		return ret;
-
-	return ret;
-}
-
-static int m920x_update_filters(struct dvb_usb_adapter *adap)
-{
-	struct m920x_state *m = adap->dev->priv;
-	int enabled = m->filtering_enabled[adap->id];
-	int i, ret = 0, filter = 0;
-	int ep = adap->props.fe[0].stream.endpoint;
-
-	for (i = 0; i < M9206_MAX_FILTERS; i++)
-		if (m->filters[adap->id][i] == 8192)
-			enabled = 0;
-
-	/* Disable all filters */
-	if ((ret = m920x_set_filter(adap->dev, ep, 1, enabled)) != 0)
-		return ret;
-
-	for (i = 0; i < M9206_MAX_FILTERS; i++)
-		if ((ret = m920x_set_filter(adap->dev, ep, i + 2, 0)) != 0)
-			return ret;
-
-	/* Set */
-	if (enabled) {
-		for (i = 0; i < M9206_MAX_FILTERS; i++) {
-			if (m->filters[adap->id][i] == 0)
-				continue;
-
-			if ((ret = m920x_set_filter(adap->dev, ep, filter + 2, m->filters[adap->id][i])) != 0)
-				return ret;
-
-			filter++;
-		}
-	}
-
-	return ret;
-}
-
-static int m920x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	struct m920x_state *m = adap->dev->priv;
-
-	m->filtering_enabled[adap->id] = onoff ? 1 : 0;
-
-	return m920x_update_filters(adap);
-}
-
-static int m920x_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
-{
-	struct m920x_state *m = adap->dev->priv;
-
-	m->filters[adap->id][index] = onoff ? pid : 0;
-
-	return m920x_update_filters(adap);
-}
-
-static int m920x_firmware_download(struct usb_device *udev, const struct firmware *fw)
-{
-	u16 value, index, size;
-	u8 *read, *buff;
-	int i, pass, ret = 0;
-
-	buff = kmalloc(65536, GFP_KERNEL);
-	if (buff == NULL)
-		return -ENOMEM;
-
-	read = kmalloc(4, GFP_KERNEL);
-	if (!read) {
-		kfree(buff);
-		return -ENOMEM;
-	}
-
-	if ((ret = m920x_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0)
-		goto done;
-	deb("%x %x %x %x\n", read[0], read[1], read[2], read[3]);
-
-	if ((ret = m920x_read(udev, M9206_FW, 0x0, 0x0, read, 1)) != 0)
-		goto done;
-	deb("%x\n", read[0]);
-
-	for (pass = 0; pass < 2; pass++) {
-		for (i = 0; i + (sizeof(u16) * 3) < fw->size;) {
-			value = get_unaligned_le16(fw->data + i);
-			i += sizeof(u16);
-
-			index = get_unaligned_le16(fw->data + i);
-			i += sizeof(u16);
-
-			size = get_unaligned_le16(fw->data + i);
-			i += sizeof(u16);
-
-			if (pass == 1) {
-				/* Will stall if using fw->data ... */
-				memcpy(buff, fw->data + i, size);
-
-				ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0),
-						      M9206_FW,
-						      USB_TYPE_VENDOR | USB_DIR_OUT,
-						      value, index, buff, size, 20);
-				if (ret != size) {
-					deb("error while uploading fw!\n");
-					ret = -EIO;
-					goto done;
-				}
-				msleep(3);
-			}
-			i += size;
-		}
-		if (i != fw->size) {
-			deb("bad firmware file!\n");
-			ret = -EINVAL;
-			goto done;
-		}
-	}
-
-	msleep(36);
-
-	/* m920x will disconnect itself from the bus after this. */
-	(void) m920x_write(udev, M9206_CORE, 0x01, M9206_FW_GO);
-	deb("firmware uploaded!\n");
-
- done:
-	kfree(read);
-	kfree(buff);
-
-	return ret;
-}
-
-/* Callbacks for DVB USB */
-static int m920x_identify_state(struct usb_device *udev,
-				struct dvb_usb_device_properties *props,
-				struct dvb_usb_device_description **desc,
-				int *cold)
-{
-	struct usb_host_interface *alt;
-
-	alt = usb_altnum_to_altsetting(usb_ifnum_to_if(udev, 0), 1);
-	*cold = (alt == NULL) ? 1 : 0;
-
-	return 0;
-}
-
-/* demod configurations */
-static int m920x_mt352_demod_init(struct dvb_frontend *fe)
-{
-	int ret;
-	u8 config[] = { CONFIG, 0x3d };
-	u8 clock[] = { CLOCK_CTL, 0x30 };
-	u8 reset[] = { RESET, 0x80 };
-	u8 adc_ctl[] = { ADC_CTL_1, 0x40 };
-	u8 agc[] = { AGC_TARGET, 0x1c, 0x20 };
-	u8 sec_agc[] = { 0x69, 0x00, 0xff, 0xff, 0x40, 0xff, 0x00, 0x40, 0x40 };
-	u8 unk1[] = { 0x93, 0x1a };
-	u8 unk2[] = { 0xb5, 0x7a };
-
-	deb("Demod init!\n");
-
-	if ((ret = mt352_write(fe, config, ARRAY_SIZE(config))) != 0)
-		return ret;
-	if ((ret = mt352_write(fe, clock, ARRAY_SIZE(clock))) != 0)
-		return ret;
-	if ((ret = mt352_write(fe, reset, ARRAY_SIZE(reset))) != 0)
-		return ret;
-	if ((ret = mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl))) != 0)
-		return ret;
-	if ((ret = mt352_write(fe, agc, ARRAY_SIZE(agc))) != 0)
-		return ret;
-	if ((ret = mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc))) != 0)
-		return ret;
-	if ((ret = mt352_write(fe, unk1, ARRAY_SIZE(unk1))) != 0)
-		return ret;
-	if ((ret = mt352_write(fe, unk2, ARRAY_SIZE(unk2))) != 0)
-		return ret;
-
-	return 0;
-}
-
-static struct mt352_config m920x_mt352_config = {
-	.demod_address = 0x0f,
-	.no_tuner = 1,
-	.demod_init = m920x_mt352_demod_init,
-};
-
-static struct tda1004x_config m920x_tda10046_08_config = {
-	.demod_address = 0x08,
-	.invert = 0,
-	.invert_oclk = 0,
-	.ts_mode = TDA10046_TS_SERIAL,
-	.xtal_freq = TDA10046_XTAL_16M,
-	.if_freq = TDA10046_FREQ_045,
-	.agc_config = TDA10046_AGC_TDA827X,
-	.gpio_config = TDA10046_GPTRI,
-	.request_firmware = NULL,
-};
-
-static struct tda1004x_config m920x_tda10046_0b_config = {
-	.demod_address = 0x0b,
-	.invert = 0,
-	.invert_oclk = 0,
-	.ts_mode = TDA10046_TS_SERIAL,
-	.xtal_freq = TDA10046_XTAL_16M,
-	.if_freq = TDA10046_FREQ_045,
-	.agc_config = TDA10046_AGC_TDA827X,
-	.gpio_config = TDA10046_GPTRI,
-	.request_firmware = NULL, /* uses firmware EEPROM */
-};
-
-/* tuner configurations */
-static struct qt1010_config m920x_qt1010_config = {
-	.i2c_address = 0x62
-};
-
-/* Callbacks for DVB USB */
-static int m920x_mt352_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	deb("%s\n",__func__);
-
-	adap->fe_adap[0].fe = dvb_attach(mt352_attach,
-					 &m920x_mt352_config,
-					 &adap->dev->i2c_adap);
-	if ((adap->fe_adap[0].fe) == NULL)
-		return -EIO;
-
-	return 0;
-}
-
-static int m920x_tda10046_08_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	deb("%s\n",__func__);
-
-	adap->fe_adap[0].fe = dvb_attach(tda10046_attach,
-					 &m920x_tda10046_08_config,
-					 &adap->dev->i2c_adap);
-	if ((adap->fe_adap[0].fe) == NULL)
-		return -EIO;
-
-	return 0;
-}
-
-static int m920x_tda10046_0b_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	deb("%s\n",__func__);
-
-	adap->fe_adap[0].fe = dvb_attach(tda10046_attach,
-					 &m920x_tda10046_0b_config,
-					 &adap->dev->i2c_adap);
-	if ((adap->fe_adap[0].fe) == NULL)
-		return -EIO;
-
-	return 0;
-}
-
-static int m920x_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	deb("%s\n",__func__);
-
-	if (dvb_attach(qt1010_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL)
-		return -ENODEV;
-
-	return 0;
-}
-
-static int m920x_tda8275_60_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	deb("%s\n",__func__);
-
-	if (dvb_attach(tda827x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, NULL) == NULL)
-		return -ENODEV;
-
-	return 0;
-}
-
-static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	deb("%s\n",__func__);
-
-	if (dvb_attach(tda827x_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL)
-		return -ENODEV;
-
-	return 0;
-}
-
-static int m920x_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe,
-		   &adap->dev->i2c_adap, 0x61,
-		   TUNER_PHILIPS_FMD1216ME_MK3);
-	return 0;
-}
-
-/* device-specific initialization */
-static struct m920x_inits megasky_rc_init [] = {
-	{ M9206_RC_INIT2, 0xa8 },
-	{ M9206_RC_INIT1, 0x51 },
-	{ } /* terminating entry */
-};
-
-static struct m920x_inits tvwalkertwin_rc_init [] = {
-	{ M9206_RC_INIT2, 0x00 },
-	{ M9206_RC_INIT1, 0xef },
-	{ 0xff28,         0x00 },
-	{ 0xff23,         0x00 },
-	{ 0xff21,         0x30 },
-	{ } /* terminating entry */
-};
-
-static struct m920x_inits pinnacle310e_init[] = {
-	/* without these the tuner don't work */
-	{ 0xff20,         0x9b },
-	{ 0xff22,         0x70 },
-
-	/* rc settings */
-	{ 0xff50,         0x80 },
-	{ M9206_RC_INIT1, 0x00 },
-	{ M9206_RC_INIT2, 0xff },
-	{ } /* terminating entry */
-};
-
-/* ir keymaps */
-static struct rc_map_table rc_map_megasky_table[] = {
-	{ 0x0012, KEY_POWER },
-	{ 0x001e, KEY_CYCLEWINDOWS }, /* min/max */
-	{ 0x0002, KEY_CHANNELUP },
-	{ 0x0005, KEY_CHANNELDOWN },
-	{ 0x0003, KEY_VOLUMEUP },
-	{ 0x0006, KEY_VOLUMEDOWN },
-	{ 0x0004, KEY_MUTE },
-	{ 0x0007, KEY_OK }, /* TS */
-	{ 0x0008, KEY_STOP },
-	{ 0x0009, KEY_MENU }, /* swap */
-	{ 0x000a, KEY_REWIND },
-	{ 0x001b, KEY_PAUSE },
-	{ 0x001f, KEY_FASTFORWARD },
-	{ 0x000c, KEY_RECORD },
-	{ 0x000d, KEY_CAMERA }, /* screenshot */
-	{ 0x000e, KEY_COFFEE }, /* "MTS" */
-};
-
-static struct rc_map_table rc_map_tvwalkertwin_table[] = {
-	{ 0x0001, KEY_ZOOM }, /* Full Screen */
-	{ 0x0002, KEY_CAMERA }, /* snapshot */
-	{ 0x0003, KEY_MUTE },
-	{ 0x0004, KEY_REWIND },
-	{ 0x0005, KEY_PLAYPAUSE }, /* Play/Pause */
-	{ 0x0006, KEY_FASTFORWARD },
-	{ 0x0007, KEY_RECORD },
-	{ 0x0008, KEY_STOP },
-	{ 0x0009, KEY_TIME }, /* Timeshift */
-	{ 0x000c, KEY_COFFEE }, /* Recall */
-	{ 0x000e, KEY_CHANNELUP },
-	{ 0x0012, KEY_POWER },
-	{ 0x0015, KEY_MENU }, /* source */
-	{ 0x0018, KEY_CYCLEWINDOWS }, /* TWIN PIP */
-	{ 0x001a, KEY_CHANNELDOWN },
-	{ 0x001b, KEY_VOLUMEDOWN },
-	{ 0x001e, KEY_VOLUMEUP },
-};
-
-static struct rc_map_table rc_map_pinnacle310e_table[] = {
-	{ 0x16, KEY_POWER },
-	{ 0x17, KEY_FAVORITES },
-	{ 0x0f, KEY_TEXT },
-	{ 0x48, KEY_PROGRAM },		/* preview */
-	{ 0x1c, KEY_EPG },
-	{ 0x04, KEY_LIST },		/* record list */
-	{ 0x03, KEY_1 },
-	{ 0x01, KEY_2 },
-	{ 0x06, KEY_3 },
-	{ 0x09, KEY_4 },
-	{ 0x1d, KEY_5 },
-	{ 0x1f, KEY_6 },
-	{ 0x0d, KEY_7 },
-	{ 0x19, KEY_8 },
-	{ 0x1b, KEY_9 },
-	{ 0x15, KEY_0 },
-	{ 0x0c, KEY_CANCEL },
-	{ 0x4a, KEY_CLEAR },
-	{ 0x13, KEY_BACK },
-	{ 0x00, KEY_TAB },
-	{ 0x4b, KEY_UP },
-	{ 0x4e, KEY_LEFT },
-	{ 0x52, KEY_RIGHT },
-	{ 0x51, KEY_DOWN },
-	{ 0x4f, KEY_ENTER },		/* could also be KEY_OK */
-	{ 0x1e, KEY_VOLUMEUP },
-	{ 0x0a, KEY_VOLUMEDOWN },
-	{ 0x05, KEY_CHANNELUP },
-	{ 0x02, KEY_CHANNELDOWN },
-	{ 0x11, KEY_RECORD },
-	{ 0x14, KEY_PLAY },
-	{ 0x4c, KEY_PAUSE },
-	{ 0x1a, KEY_STOP },
-	{ 0x40, KEY_REWIND },
-	{ 0x12, KEY_FASTFORWARD },
-	{ 0x41, KEY_PREVIOUSSONG },	/* Replay */
-	{ 0x42, KEY_NEXTSONG },		/* Skip */
-	{ 0x54, KEY_CAMERA },		/* Capture */
-/*	{ 0x50, KEY_SAP },	*/		/* Sap */
-	{ 0x47, KEY_CYCLEWINDOWS },	/* Pip */
-	{ 0x4d, KEY_SCREEN },		/* FullScreen */
-	{ 0x08, KEY_SUBTITLE },
-	{ 0x0e, KEY_MUTE },
-/*	{ 0x49, KEY_LR },	*/		/* L/R */
-	{ 0x07, KEY_SLEEP },		/* Hibernate */
-	{ 0x08, KEY_VIDEO },		/* A/V */
-	{ 0x0e, KEY_MENU },		/* Recall */
-	{ 0x45, KEY_ZOOMIN },
-	{ 0x46, KEY_ZOOMOUT },
-	{ 0x18, KEY_RED },		/* Red */
-	{ 0x53, KEY_GREEN },		/* Green */
-	{ 0x5e, KEY_YELLOW },		/* Yellow */
-	{ 0x5f, KEY_BLUE },		/* Blue */
-};
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties megasky_properties;
-static struct dvb_usb_device_properties digivox_mini_ii_properties;
-static struct dvb_usb_device_properties tvwalkertwin_properties;
-static struct dvb_usb_device_properties dposh_properties;
-static struct dvb_usb_device_properties pinnacle_pctv310e_properties;
-
-static int m920x_probe(struct usb_interface *intf,
-		       const struct usb_device_id *id)
-{
-	struct dvb_usb_device *d = NULL;
-	int ret;
-	struct m920x_inits *rc_init_seq = NULL;
-	int bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber;
-
-	deb("Probing for m920x device at interface %d\n", bInterfaceNumber);
-
-	if (bInterfaceNumber == 0) {
-		/* Single-tuner device, or first interface on
-		 * multi-tuner device
-		 */
-
-		ret = dvb_usb_device_init(intf, &megasky_properties,
-					  THIS_MODULE, &d, adapter_nr);
-		if (ret == 0) {
-			rc_init_seq = megasky_rc_init;
-			goto found;
-		}
-
-		ret = dvb_usb_device_init(intf, &digivox_mini_ii_properties,
-					  THIS_MODULE, &d, adapter_nr);
-		if (ret == 0) {
-			/* No remote control, so no rc_init_seq */
-			goto found;
-		}
-
-		/* This configures both tuners on the TV Walker Twin */
-		ret = dvb_usb_device_init(intf, &tvwalkertwin_properties,
-					  THIS_MODULE, &d, adapter_nr);
-		if (ret == 0) {
-			rc_init_seq = tvwalkertwin_rc_init;
-			goto found;
-		}
-
-		ret = dvb_usb_device_init(intf, &dposh_properties,
-					  THIS_MODULE, &d, adapter_nr);
-		if (ret == 0) {
-			/* Remote controller not supported yet. */
-			goto found;
-		}
-
-		ret = dvb_usb_device_init(intf, &pinnacle_pctv310e_properties,
-					  THIS_MODULE, &d, adapter_nr);
-		if (ret == 0) {
-			rc_init_seq = pinnacle310e_init;
-			goto found;
-		}
-
-		return ret;
-	} else {
-		/* Another interface on a multi-tuner device */
-
-		/* The LifeView TV Walker Twin gets here, but struct
-		 * tvwalkertwin_properties already configured both
-		 * tuners, so there is nothing for us to do here
-		 */
-	}
-
- found:
-	if ((ret = m920x_init_ep(intf)) < 0)
-		return ret;
-
-	if (d && (ret = m920x_init(d, rc_init_seq)) != 0)
-		return ret;
-
-	return ret;
-}
-
-static struct usb_device_id m920x_table [] = {
-		{ USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) },
-		{ USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC,
-			     USB_PID_MSI_DIGI_VOX_MINI_II) },
-		{ USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC,
-			     USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD) },
-		{ USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC,
-			     USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM) },
-		{ USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_COLD) },
-		{ USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_WARM) },
-		{ USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_PINNACLE_PCTV310E) },
-		{ }		/* Terminating entry */
-};
-MODULE_DEVICE_TABLE (usb, m920x_table);
-
-static struct dvb_usb_device_properties megasky_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = DEVICE_SPECIFIC,
-	.firmware = "dvb-usb-megasky-02.fw",
-	.download_firmware = m920x_firmware_download,
-
-	.rc.legacy = {
-		.rc_interval      = 100,
-		.rc_map_table     = rc_map_megasky_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_megasky_table),
-		.rc_query         = m920x_rc_query,
-	},
-
-	.size_of_priv     = sizeof(struct m920x_state),
-
-	.identify_state   = m920x_identify_state,
-	.num_adapters = 1,
-	.adapter = {{
-		.num_frontends = 1,
-		.fe = {{
-
-		.caps = DVB_USB_ADAP_HAS_PID_FILTER |
-			DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-
-		.pid_filter_count = 8,
-		.pid_filter       = m920x_pid_filter,
-		.pid_filter_ctrl  = m920x_pid_filter_ctrl,
-
-		.frontend_attach  = m920x_mt352_frontend_attach,
-		.tuner_attach     = m920x_qt1010_tuner_attach,
-
-		.stream = {
-			.type = USB_BULK,
-			.count = 8,
-			.endpoint = 0x81,
-			.u = {
-				.bulk = {
-					.buffersize = 512,
-				}
-			}
-		},
-		}},
-	}},
-	.i2c_algo         = &m920x_i2c_algo,
-
-	.num_device_descs = 1,
-	.devices = {
-		{   "MSI Mega Sky 580 DVB-T USB2.0",
-			{ &m920x_table[0], NULL },
-			{ NULL },
-		}
-	}
-};
-
-static struct dvb_usb_device_properties digivox_mini_ii_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = DEVICE_SPECIFIC,
-	.firmware = "dvb-usb-digivox-02.fw",
-	.download_firmware = m920x_firmware_download,
-
-	.size_of_priv     = sizeof(struct m920x_state),
-
-	.identify_state   = m920x_identify_state,
-	.num_adapters = 1,
-	.adapter = {{
-		.num_frontends = 1,
-		.fe = {{
-
-		.caps = DVB_USB_ADAP_HAS_PID_FILTER |
-			DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-
-		.pid_filter_count = 8,
-		.pid_filter       = m920x_pid_filter,
-		.pid_filter_ctrl  = m920x_pid_filter_ctrl,
-
-		.frontend_attach  = m920x_tda10046_08_frontend_attach,
-		.tuner_attach     = m920x_tda8275_60_tuner_attach,
-
-		.stream = {
-			.type = USB_BULK,
-			.count = 8,
-			.endpoint = 0x81,
-			.u = {
-				.bulk = {
-					.buffersize = 0x4000,
-				}
-			}
-		},
-		}},
-	}},
-	.i2c_algo         = &m920x_i2c_algo,
-
-	.num_device_descs = 1,
-	.devices = {
-		{   "MSI DIGI VOX mini II DVB-T USB2.0",
-			{ &m920x_table[1], NULL },
-			{ NULL },
-		},
-	}
-};
-
-/* LifeView TV Walker Twin support by Nick Andrew <nick@nick-andrew.net>
- *
- * LifeView TV Walker Twin has 1 x M9206, 2 x TDA10046, 2 x TDA8275A
- * TDA10046 #0 is located at i2c address 0x08
- * TDA10046 #1 is located at i2c address 0x0b
- * TDA8275A #0 is located at i2c address 0x60
- * TDA8275A #1 is located at i2c address 0x61
- */
-static struct dvb_usb_device_properties tvwalkertwin_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = DEVICE_SPECIFIC,
-	.firmware = "dvb-usb-tvwalkert.fw",
-	.download_firmware = m920x_firmware_download,
-
-	.rc.legacy = {
-		.rc_interval      = 100,
-		.rc_map_table     = rc_map_tvwalkertwin_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_tvwalkertwin_table),
-		.rc_query         = m920x_rc_query,
-	},
-
-	.size_of_priv     = sizeof(struct m920x_state),
-
-	.identify_state   = m920x_identify_state,
-	.num_adapters = 2,
-	.adapter = {{
-		.num_frontends = 1,
-		.fe = {{
-
-		.caps = DVB_USB_ADAP_HAS_PID_FILTER |
-			DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-
-		.pid_filter_count = 8,
-		.pid_filter       = m920x_pid_filter,
-		.pid_filter_ctrl  = m920x_pid_filter_ctrl,
-
-		.frontend_attach  = m920x_tda10046_08_frontend_attach,
-		.tuner_attach     = m920x_tda8275_60_tuner_attach,
-
-		.stream = {
-			.type = USB_BULK,
-			.count = 8,
-			.endpoint = 0x81,
-			.u = {
-				 .bulk = {
-					 .buffersize = 512,
-				 }
-			}
-		}},
-		}},{
-		.num_frontends = 1,
-		.fe = {{
-
-		.caps = DVB_USB_ADAP_HAS_PID_FILTER |
-			DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-
-		.pid_filter_count = 8,
-		.pid_filter       = m920x_pid_filter,
-		.pid_filter_ctrl  = m920x_pid_filter_ctrl,
-
-		.frontend_attach  = m920x_tda10046_0b_frontend_attach,
-		.tuner_attach     = m920x_tda8275_61_tuner_attach,
-
-		.stream = {
-			.type = USB_BULK,
-			.count = 8,
-			.endpoint = 0x82,
-			.u = {
-				 .bulk = {
-					 .buffersize = 512,
-				 }
-			}
-		}},
-		},
-	}},
-	.i2c_algo         = &m920x_i2c_algo,
-
-	.num_device_descs = 1,
-	.devices = {
-		{   .name = "LifeView TV Walker Twin DVB-T USB2.0",
-		    .cold_ids = { &m920x_table[2], NULL },
-		    .warm_ids = { &m920x_table[3], NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties dposh_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = DEVICE_SPECIFIC,
-	.firmware = "dvb-usb-dposh-01.fw",
-	.download_firmware = m920x_firmware_download,
-
-	.size_of_priv     = sizeof(struct m920x_state),
-
-	.identify_state   = m920x_identify_state,
-	.num_adapters = 1,
-	.adapter = {{
-		.num_frontends = 1,
-		.fe = {{
-		/* Hardware pid filters don't work with this device/firmware */
-
-		.frontend_attach  = m920x_mt352_frontend_attach,
-		.tuner_attach     = m920x_qt1010_tuner_attach,
-
-		.stream = {
-			.type = USB_BULK,
-			.count = 8,
-			.endpoint = 0x81,
-			.u = {
-				 .bulk = {
-					 .buffersize = 512,
-				 }
-			}
-		},
-		}},
-	}},
-	.i2c_algo         = &m920x_i2c_algo,
-
-	.num_device_descs = 1,
-	.devices = {
-		 {   .name = "Dposh DVB-T USB2.0",
-		     .cold_ids = { &m920x_table[4], NULL },
-		     .warm_ids = { &m920x_table[5], NULL },
-		 },
-	 }
-};
-
-static struct dvb_usb_device_properties pinnacle_pctv310e_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = DEVICE_SPECIFIC,
-	.download_firmware = NULL,
-
-	.rc.legacy = {
-		.rc_interval      = 100,
-		.rc_map_table     = rc_map_pinnacle310e_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_pinnacle310e_table),
-		.rc_query         = m920x_rc_query,
-	},
-
-	.size_of_priv     = sizeof(struct m920x_state),
-
-	.identify_state   = m920x_identify_state,
-	.num_adapters = 1,
-	.adapter = {{
-		.num_frontends = 1,
-		.fe = {{
-
-		.caps = DVB_USB_ADAP_HAS_PID_FILTER |
-			DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-
-		.pid_filter_count = 8,
-		.pid_filter       = m920x_pid_filter,
-		.pid_filter_ctrl  = m920x_pid_filter_ctrl,
-
-		.frontend_attach  = m920x_mt352_frontend_attach,
-		.tuner_attach     = m920x_fmd1216me_tuner_attach,
-
-		.stream = {
-			.type = USB_ISOC,
-			.count = 5,
-			.endpoint = 0x84,
-			.u = {
-				.isoc = {
-					.framesperurb = 128,
-					.framesize = 564,
-					.interval = 1,
-				}
-			}
-		},
-		}},
-	} },
-	.i2c_algo         = &m920x_i2c_algo,
-
-	.num_device_descs = 1,
-	.devices = {
-		{   "Pinnacle PCTV 310e",
-			{ &m920x_table[6], NULL },
-			{ NULL },
-		}
-	}
-};
-
-static struct usb_driver m920x_driver = {
-	.name		= "dvb_usb_m920x",
-	.probe		= m920x_probe,
-	.disconnect	= dvb_usb_device_exit,
-	.id_table	= m920x_table,
-};
-
-module_usb_driver(m920x_driver);
-
-MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
-MODULE_DESCRIPTION("DVB Driver for ULI M920x");
-MODULE_VERSION("0.1");
-MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/dvb/dvb-usb/m920x.h b/drivers/media/dvb/dvb-usb/m920x.h
deleted file mode 100644
index 3c06151..0000000
--- a/drivers/media/dvb/dvb-usb/m920x.h
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef _DVB_USB_M920X_H_
-#define _DVB_USB_M920X_H_
-
-#define DVB_USB_LOG_PREFIX "m920x"
-#include "dvb-usb.h"
-
-#define deb(args...)   dprintk(dvb_usb_m920x_debug,0x01,args)
-
-#define M9206_CORE	0x22
-#define M9206_RC_STATE	0xff51
-#define M9206_RC_KEY	0xff52
-#define M9206_RC_INIT1	0xff54
-#define M9206_RC_INIT2	0xff55
-#define M9206_FW_GO	0xff69
-
-#define M9206_I2C	0x23
-#define M9206_FILTER	0x25
-#define M9206_FW	0x30
-
-#define M9206_MAX_FILTERS 8
-#define M9206_MAX_ADAPTERS 4
-
-/*
-sequences found in logs:
-[index value]
-0x80 write addr
-(0x00 out byte)*
-0x40 out byte
-
-0x80 write addr
-(0x00 out byte)*
-0x80 read addr
-(0x21 in byte)*
-0x60 in byte
-
-this sequence works:
-0x80 read addr
-(0x21 in byte)*
-0x60 in byte
-
-Guess at API of the I2C function:
-I2C operation is done one byte at a time with USB control messages.  The
-index the messages is sent to is made up of a set of flags that control
-the I2C bus state:
-0x80:  Send START condition.  After a START condition, one would normally
-       always send the 7-bit slave I2C address as the 7 MSB, followed by
-       the read/write bit as the LSB.
-0x40:  Send STOP condition.  This should be set on the last byte of an
-       I2C transaction.
-0x20:  Read a byte from the slave.  As opposed to writing a byte to the
-       slave.  The slave will normally not produce any data unless you
-       set the R/W bit to 1 when sending the slave's address after the
-       START condition.
-0x01:  Respond with ACK, as opposed to a NACK.  For a multi-byte read,
-       the master should send an ACK, that is pull SDA low during the 9th
-       clock cycle, after every byte but the last.  This flags only makes
-       sense when bit 0x20 is set, indicating a read.
-
-What any other bits might mean, or how to get the slave's ACK/NACK
-response to a write, is unknown.
-*/
-
-struct m920x_state {
-	u16 filters[M9206_MAX_ADAPTERS][M9206_MAX_FILTERS];
-	int filtering_enabled[M9206_MAX_ADAPTERS];
-	int rep_count;
-};
-
-/* Initialisation data for the m920x
- */
-
-struct m920x_inits {
-	u16 address;
-	u8  data;
-};
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c
deleted file mode 100644
index d83df4b..0000000
--- a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c
+++ /dev/null
@@ -1,612 +0,0 @@
-/*
- *  mxl111sf-demod.c - driver for the MaxLinear MXL111SF DVB-T demodulator
- *
- *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "mxl111sf-demod.h"
-#include "mxl111sf-reg.h"
-
-/* debug */
-static int mxl111sf_demod_debug;
-module_param_named(debug, mxl111sf_demod_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
-
-#define mxl_dbg(fmt, arg...) \
-	if (mxl111sf_demod_debug) \
-		mxl_printk(KERN_DEBUG, fmt, ##arg)
-
-/* ------------------------------------------------------------------------ */
-
-struct mxl111sf_demod_state {
-	struct mxl111sf_state *mxl_state;
-
-	struct mxl111sf_demod_config *cfg;
-
-	struct dvb_frontend fe;
-};
-
-/* ------------------------------------------------------------------------ */
-
-static int mxl111sf_demod_read_reg(struct mxl111sf_demod_state *state,
-				   u8 addr, u8 *data)
-{
-	return (state->cfg->read_reg) ?
-		state->cfg->read_reg(state->mxl_state, addr, data) :
-		-EINVAL;
-}
-
-static int mxl111sf_demod_write_reg(struct mxl111sf_demod_state *state,
-				    u8 addr, u8 data)
-{
-	return (state->cfg->write_reg) ?
-		state->cfg->write_reg(state->mxl_state, addr, data) :
-		-EINVAL;
-}
-
-static
-int mxl111sf_demod_program_regs(struct mxl111sf_demod_state *state,
-				struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
-{
-	return (state->cfg->program_regs) ?
-		state->cfg->program_regs(state->mxl_state, ctrl_reg_info) :
-		-EINVAL;
-}
-
-/* ------------------------------------------------------------------------ */
-/* TPS */
-
-static
-int mxl1x1sf_demod_get_tps_code_rate(struct mxl111sf_demod_state *state,
-				     fe_code_rate_t *code_rate)
-{
-	u8 val;
-	int ret = mxl111sf_demod_read_reg(state, V6_CODE_RATE_TPS_REG, &val);
-	/* bit<2:0> - 000:1/2, 001:2/3, 010:3/4, 011:5/6, 100:7/8 */
-	if (mxl_fail(ret))
-		goto fail;
-
-	switch (val & V6_CODE_RATE_TPS_MASK) {
-	case 0:
-		*code_rate = FEC_1_2;
-		break;
-	case 1:
-		*code_rate = FEC_2_3;
-		break;
-	case 2:
-		*code_rate = FEC_3_4;
-		break;
-	case 3:
-		*code_rate = FEC_5_6;
-		break;
-	case 4:
-		*code_rate = FEC_7_8;
-		break;
-	}
-fail:
-	return ret;
-}
-
-static
-int mxl1x1sf_demod_get_tps_modulation(struct mxl111sf_demod_state *state,
-					 fe_modulation_t *modulation)
-{
-	u8 val;
-	int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val);
-	/* Constellation, 00 : QPSK, 01 : 16QAM, 10:64QAM */
-	if (mxl_fail(ret))
-		goto fail;
-
-	switch ((val & V6_PARAM_CONSTELLATION_MASK) >> 4) {
-	case 0:
-		*modulation = QPSK;
-		break;
-	case 1:
-		*modulation = QAM_16;
-		break;
-	case 2:
-		*modulation = QAM_64;
-		break;
-	}
-fail:
-	return ret;
-}
-
-static
-int mxl1x1sf_demod_get_tps_guard_fft_mode(struct mxl111sf_demod_state *state,
-					  fe_transmit_mode_t *fft_mode)
-{
-	u8 val;
-	int ret = mxl111sf_demod_read_reg(state, V6_MODE_TPS_REG, &val);
-	/* FFT Mode, 00:2K, 01:8K, 10:4K */
-	if (mxl_fail(ret))
-		goto fail;
-
-	switch ((val & V6_PARAM_FFT_MODE_MASK) >> 2) {
-	case 0:
-		*fft_mode = TRANSMISSION_MODE_2K;
-		break;
-	case 1:
-		*fft_mode = TRANSMISSION_MODE_8K;
-		break;
-	case 2:
-		*fft_mode = TRANSMISSION_MODE_4K;
-		break;
-	}
-fail:
-	return ret;
-}
-
-static
-int mxl1x1sf_demod_get_tps_guard_interval(struct mxl111sf_demod_state *state,
-					  fe_guard_interval_t *guard)
-{
-	u8 val;
-	int ret = mxl111sf_demod_read_reg(state, V6_CP_TPS_REG, &val);
-	/* 00:1/32, 01:1/16, 10:1/8, 11:1/4 */
-	if (mxl_fail(ret))
-		goto fail;
-
-	switch ((val & V6_PARAM_GI_MASK) >> 4) {
-	case 0:
-		*guard = GUARD_INTERVAL_1_32;
-		break;
-	case 1:
-		*guard = GUARD_INTERVAL_1_16;
-		break;
-	case 2:
-		*guard = GUARD_INTERVAL_1_8;
-		break;
-	case 3:
-		*guard = GUARD_INTERVAL_1_4;
-		break;
-	}
-fail:
-	return ret;
-}
-
-static
-int mxl1x1sf_demod_get_tps_hierarchy(struct mxl111sf_demod_state *state,
-				     fe_hierarchy_t *hierarchy)
-{
-	u8 val;
-	int ret = mxl111sf_demod_read_reg(state, V6_TPS_HIERACHY_REG, &val);
-	/* bit<6:4> - 000:Non hierarchy, 001:1, 010:2, 011:4 */
-	if (mxl_fail(ret))
-		goto fail;
-
-	switch ((val & V6_TPS_HIERARCHY_INFO_MASK) >> 6) {
-	case 0:
-		*hierarchy = HIERARCHY_NONE;
-		break;
-	case 1:
-		*hierarchy = HIERARCHY_1;
-		break;
-	case 2:
-		*hierarchy = HIERARCHY_2;
-		break;
-	case 3:
-		*hierarchy = HIERARCHY_4;
-		break;
-	}
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-/* LOCKS */
-
-static
-int mxl1x1sf_demod_get_sync_lock_status(struct mxl111sf_demod_state *state,
-					int *sync_lock)
-{
-	u8 val = 0;
-	int ret = mxl111sf_demod_read_reg(state, V6_SYNC_LOCK_REG, &val);
-	if (mxl_fail(ret))
-		goto fail;
-	*sync_lock = (val & SYNC_LOCK_MASK) >> 4;
-fail:
-	return ret;
-}
-
-static
-int mxl1x1sf_demod_get_rs_lock_status(struct mxl111sf_demod_state *state,
-				      int *rs_lock)
-{
-	u8 val = 0;
-	int ret = mxl111sf_demod_read_reg(state, V6_RS_LOCK_DET_REG, &val);
-	if (mxl_fail(ret))
-		goto fail;
-	*rs_lock = (val & RS_LOCK_DET_MASK) >> 3;
-fail:
-	return ret;
-}
-
-static
-int mxl1x1sf_demod_get_tps_lock_status(struct mxl111sf_demod_state *state,
-				       int *tps_lock)
-{
-	u8 val = 0;
-	int ret = mxl111sf_demod_read_reg(state, V6_TPS_LOCK_REG, &val);
-	if (mxl_fail(ret))
-		goto fail;
-	*tps_lock = (val & V6_PARAM_TPS_LOCK_MASK) >> 6;
-fail:
-	return ret;
-}
-
-static
-int mxl1x1sf_demod_get_fec_lock_status(struct mxl111sf_demod_state *state,
-				       int *fec_lock)
-{
-	u8 val = 0;
-	int ret = mxl111sf_demod_read_reg(state, V6_IRQ_STATUS_REG, &val);
-	if (mxl_fail(ret))
-		goto fail;
-	*fec_lock = (val & IRQ_MASK_FEC_LOCK) >> 4;
-fail:
-	return ret;
-}
-
-#if 0
-static
-int mxl1x1sf_demod_get_cp_lock_status(struct mxl111sf_demod_state *state,
-				      int *cp_lock)
-{
-	u8 val = 0;
-	int ret = mxl111sf_demod_read_reg(state, V6_CP_LOCK_DET_REG, &val);
-	if (mxl_fail(ret))
-		goto fail;
-	*cp_lock = (val & V6_CP_LOCK_DET_MASK) >> 2;
-fail:
-	return ret;
-}
-#endif
-
-static int mxl1x1sf_demod_reset_irq_status(struct mxl111sf_demod_state *state)
-{
-	return mxl111sf_demod_write_reg(state, 0x0e, 0xff);
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe)
-{
-	struct mxl111sf_demod_state *state = fe->demodulator_priv;
-	int ret = 0;
-
-	struct mxl111sf_reg_ctrl_info phy_pll_patch[] = {
-		{0x00, 0xff, 0x01}, /* change page to 1 */
-		{0x40, 0xff, 0x05},
-		{0x40, 0xff, 0x01},
-		{0x41, 0xff, 0xca},
-		{0x41, 0xff, 0xc0},
-		{0x00, 0xff, 0x00}, /* change page to 0 */
-		{0,    0,    0}
-	};
-
-	mxl_dbg("()");
-
-	if (fe->ops.tuner_ops.set_params) {
-		ret = fe->ops.tuner_ops.set_params(fe);
-		if (mxl_fail(ret))
-			goto fail;
-		msleep(50);
-	}
-	ret = mxl111sf_demod_program_regs(state, phy_pll_patch);
-	mxl_fail(ret);
-	msleep(50);
-	ret = mxl1x1sf_demod_reset_irq_status(state);
-	mxl_fail(ret);
-	msleep(100);
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-#if 0
-/* resets TS Packet error count */
-/* After setting 7th bit of V5_PER_COUNT_RESET_REG, it should be reset to 0. */
-static
-int mxl1x1sf_demod_reset_packet_error_count(struct mxl111sf_demod_state *state)
-{
-	struct mxl111sf_reg_ctrl_info reset_per_count[] = {
-		{0x20, 0x01, 0x01},
-		{0x20, 0x01, 0x00},
-		{0,    0,    0}
-	};
-	return mxl111sf_demod_program_regs(state, reset_per_count);
-}
-#endif
-
-/* returns TS Packet error count */
-/* PER Count = FEC_PER_COUNT * (2 ** (FEC_PER_SCALE * 4)) */
-static int mxl111sf_demod_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct mxl111sf_demod_state *state = fe->demodulator_priv;
-	u32 fec_per_count, fec_per_scale;
-	u8 val;
-	int ret;
-
-	*ucblocks = 0;
-
-	/* FEC_PER_COUNT Register */
-	ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_COUNT_REG, &val);
-	if (mxl_fail(ret))
-		goto fail;
-
-	fec_per_count = val;
-
-	/* FEC_PER_SCALE Register */
-	ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_SCALE_REG, &val);
-	if (mxl_fail(ret))
-		goto fail;
-
-	val &= V6_FEC_PER_SCALE_MASK;
-	val *= 4;
-
-	fec_per_scale = 1 << val;
-
-	fec_per_count *= fec_per_scale;
-
-	*ucblocks = fec_per_count;
-fail:
-	return ret;
-}
-
-#ifdef MXL111SF_DEMOD_ENABLE_CALCULATIONS
-/* FIXME: leaving this enabled breaks the build on some architectures,
- * and we shouldn't have any floating point math in the kernel, anyway.
- *
- * These macros need to be re-written, but it's harmless to simply
- * return zero for now. */
-#define CALCULATE_BER(avg_errors, count) \
-	((u32)(avg_errors * 4)/(count*64*188*8))
-#define CALCULATE_SNR(data) \
-	((u32)((10 * (u32)data / 64) - 2.5))
-#else
-#define CALCULATE_BER(avg_errors, count) 0
-#define CALCULATE_SNR(data) 0
-#endif
-
-static int mxl111sf_demod_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct mxl111sf_demod_state *state = fe->demodulator_priv;
-	u8 val1, val2, val3;
-	int ret;
-
-	*ber = 0;
-
-	ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_LSB_REG, &val1);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_MSB_REG, &val2);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_demod_read_reg(state, V6_N_ACCUMULATE_REG, &val3);
-	if (mxl_fail(ret))
-		goto fail;
-
-	*ber = CALCULATE_BER((val1 | (val2 << 8)), val3);
-fail:
-	return ret;
-}
-
-static int mxl111sf_demod_calc_snr(struct mxl111sf_demod_state *state,
-				   u16 *snr)
-{
-	u8 val1, val2;
-	int ret;
-
-	*snr = 0;
-
-	ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_LSB_REG, &val1);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_MSB_REG, &val2);
-	if (mxl_fail(ret))
-		goto fail;
-
-	*snr = CALCULATE_SNR(val1 | ((val2 & 0x03) << 8));
-fail:
-	return ret;
-}
-
-static int mxl111sf_demod_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct mxl111sf_demod_state *state = fe->demodulator_priv;
-
-	int ret = mxl111sf_demod_calc_snr(state, snr);
-	if (mxl_fail(ret))
-		goto fail;
-
-	*snr /= 10; /* 0.1 dB */
-fail:
-	return ret;
-}
-
-static int mxl111sf_demod_read_status(struct dvb_frontend *fe,
-				      fe_status_t *status)
-{
-	struct mxl111sf_demod_state *state = fe->demodulator_priv;
-	int ret, locked, cr_lock, sync_lock, fec_lock;
-
-	*status = 0;
-
-	ret = mxl1x1sf_demod_get_rs_lock_status(state, &locked);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl1x1sf_demod_get_tps_lock_status(state, &cr_lock);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl1x1sf_demod_get_sync_lock_status(state, &sync_lock);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl1x1sf_demod_get_fec_lock_status(state, &fec_lock);
-	if (mxl_fail(ret))
-		goto fail;
-
-	if (locked)
-		*status |= FE_HAS_SIGNAL;
-	if (cr_lock)
-		*status |= FE_HAS_CARRIER;
-	if (sync_lock)
-		*status |= FE_HAS_SYNC;
-	if (fec_lock) /* false positives? */
-		*status |= FE_HAS_VITERBI;
-
-	if ((locked) && (cr_lock) && (sync_lock))
-		*status |= FE_HAS_LOCK;
-fail:
-	return ret;
-}
-
-static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe,
-					       u16 *signal_strength)
-{
-	struct mxl111sf_demod_state *state = fe->demodulator_priv;
-	fe_modulation_t modulation;
-	u16 snr;
-
-	mxl111sf_demod_calc_snr(state, &snr);
-	mxl1x1sf_demod_get_tps_modulation(state, &modulation);
-
-	switch (modulation) {
-	case QPSK:
-		*signal_strength = (snr >= 1300) ?
-			min(65535, snr * 44) : snr * 38;
-		break;
-	case QAM_16:
-		*signal_strength = (snr >= 1500) ?
-			min(65535, snr * 38) : snr * 33;
-		break;
-	case QAM_64:
-		*signal_strength = (snr >= 2000) ?
-			min(65535, snr * 29) : snr * 25;
-		break;
-	default:
-		*signal_strength = 0;
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct mxl111sf_demod_state *state = fe->demodulator_priv;
-
-	mxl_dbg("()");
-#if 0
-	p->inversion = /* FIXME */ ? INVERSION_ON : INVERSION_OFF;
-#endif
-	if (fe->ops.tuner_ops.get_bandwidth)
-		fe->ops.tuner_ops.get_bandwidth(fe, &p->bandwidth_hz);
-	if (fe->ops.tuner_ops.get_frequency)
-		fe->ops.tuner_ops.get_frequency(fe, &p->frequency);
-	mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_HP);
-	mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_LP);
-	mxl1x1sf_demod_get_tps_modulation(state, &p->modulation);
-	mxl1x1sf_demod_get_tps_guard_fft_mode(state,
-					      &p->transmission_mode);
-	mxl1x1sf_demod_get_tps_guard_interval(state,
-					      &p->guard_interval);
-	mxl1x1sf_demod_get_tps_hierarchy(state,
-					 &p->hierarchy);
-
-	return 0;
-}
-
-static
-int mxl111sf_demod_get_tune_settings(struct dvb_frontend *fe,
-				     struct dvb_frontend_tune_settings *tune)
-{
-	tune->min_delay_ms = 1000;
-	return 0;
-}
-
-static void mxl111sf_demod_release(struct dvb_frontend *fe)
-{
-	struct mxl111sf_demod_state *state = fe->demodulator_priv;
-	mxl_dbg("()");
-	kfree(state);
-	fe->demodulator_priv = NULL;
-}
-
-static struct dvb_frontend_ops mxl111sf_demod_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name               = "MaxLinear MxL111SF DVB-T demodulator",
-		.frequency_min      = 177000000,
-		.frequency_max      = 858000000,
-		.frequency_stepsize = 166666,
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
-			FE_CAN_QAM_AUTO |
-			FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
-	},
-	.release              = mxl111sf_demod_release,
-#if 0
-	.init                 = mxl111sf_init,
-	.i2c_gate_ctrl        = mxl111sf_i2c_gate_ctrl,
-#endif
-	.set_frontend         = mxl111sf_demod_set_frontend,
-	.get_frontend         = mxl111sf_demod_get_frontend,
-	.get_tune_settings    = mxl111sf_demod_get_tune_settings,
-	.read_status          = mxl111sf_demod_read_status,
-	.read_signal_strength = mxl111sf_demod_read_signal_strength,
-	.read_ber             = mxl111sf_demod_read_ber,
-	.read_snr             = mxl111sf_demod_read_snr,
-	.read_ucblocks        = mxl111sf_demod_read_ucblocks,
-};
-
-struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
-					   struct mxl111sf_demod_config *cfg)
-{
-	struct mxl111sf_demod_state *state = NULL;
-
-	mxl_dbg("()");
-
-	state = kzalloc(sizeof(struct mxl111sf_demod_state), GFP_KERNEL);
-	if (state == NULL)
-		return NULL;
-
-	state->mxl_state = mxl_state;
-	state->cfg = cfg;
-
-	memcpy(&state->fe.ops, &mxl111sf_demod_ops,
-	       sizeof(struct dvb_frontend_ops));
-
-	state->fe.demodulator_priv = state;
-	return &state->fe;
-}
-EXPORT_SYMBOL_GPL(mxl111sf_demod_attach);
-
-MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver");
-MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.1");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.h b/drivers/media/dvb/dvb-usb/mxl111sf-demod.h
deleted file mode 100644
index 432706a..0000000
--- a/drivers/media/dvb/dvb-usb/mxl111sf-demod.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *  mxl111sf-demod.h - driver for the MaxLinear MXL111SF DVB-T demodulator
- *
- *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __MXL111SF_DEMOD_H__
-#define __MXL111SF_DEMOD_H__
-
-#include "dvb_frontend.h"
-#include "mxl111sf.h"
-
-struct mxl111sf_demod_config {
-	int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data);
-	int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data);
-	int (*program_regs)(struct mxl111sf_state *state,
-			    struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
-};
-
-#if defined(CONFIG_DVB_USB_MXL111SF) || \
-	(defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE))
-extern
-struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
-					   struct mxl111sf_demod_config *cfg);
-#else
-static inline
-struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
-					   struct mxl111sf_demod_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_USB_MXL111SF */
-
-#endif /* __MXL111SF_DEMOD_H__ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.c b/drivers/media/dvb/dvb-usb/mxl111sf-gpio.c
deleted file mode 100644
index e4121cb..0000000
--- a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.c
+++ /dev/null
@@ -1,763 +0,0 @@
-/*
- *  mxl111sf-gpio.c - driver for the MaxLinear MXL111SF
- *
- *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "mxl111sf-gpio.h"
-#include "mxl111sf-i2c.h"
-#include "mxl111sf.h"
-
-/* ------------------------------------------------------------------------- */
-
-#define MXL_GPIO_MUX_REG_0 0x84
-#define MXL_GPIO_MUX_REG_1 0x89
-#define MXL_GPIO_MUX_REG_2 0x82
-
-#define MXL_GPIO_DIR_INPUT  0
-#define MXL_GPIO_DIR_OUTPUT 1
-
-
-static int mxl111sf_set_gpo_state(struct mxl111sf_state *state, u8 pin, u8 val)
-{
-	int ret;
-	u8 tmp;
-
-	mxl_debug_adv("(%d, %d)", pin, val);
-
-	if ((pin > 0) && (pin < 8)) {
-		ret = mxl111sf_read_reg(state, 0x19, &tmp);
-		if (mxl_fail(ret))
-			goto fail;
-		tmp &= ~(1 << (pin - 1));
-		tmp |= (val << (pin - 1));
-		ret = mxl111sf_write_reg(state, 0x19, tmp);
-		if (mxl_fail(ret))
-			goto fail;
-	} else if (pin <= 10) {
-		if (pin == 0)
-			pin += 7;
-		ret = mxl111sf_read_reg(state, 0x30, &tmp);
-		if (mxl_fail(ret))
-			goto fail;
-		tmp &= ~(1 << (pin - 3));
-		tmp |= (val << (pin - 3));
-		ret = mxl111sf_write_reg(state, 0x30, tmp);
-		if (mxl_fail(ret))
-			goto fail;
-	} else
-		ret = -EINVAL;
-fail:
-	return ret;
-}
-
-static int mxl111sf_get_gpi_state(struct mxl111sf_state *state, u8 pin, u8 *val)
-{
-	int ret;
-	u8 tmp;
-
-	mxl_debug("(0x%02x)", pin);
-
-	*val = 0;
-
-	switch (pin) {
-	case 0:
-	case 1:
-	case 2:
-	case 3:
-		ret = mxl111sf_read_reg(state, 0x23, &tmp);
-		if (mxl_fail(ret))
-			goto fail;
-		*val = (tmp >> (pin + 4)) & 0x01;
-		break;
-	case 4:
-	case 5:
-	case 6:
-	case 7:
-		ret = mxl111sf_read_reg(state, 0x2f, &tmp);
-		if (mxl_fail(ret))
-			goto fail;
-		*val = (tmp >> pin) & 0x01;
-		break;
-	case 8:
-	case 9:
-	case 10:
-		ret = mxl111sf_read_reg(state, 0x22, &tmp);
-		if (mxl_fail(ret))
-			goto fail;
-		*val = (tmp >> (pin - 3)) & 0x01;
-		break;
-	default:
-		return -EINVAL; /* invalid pin */
-	}
-fail:
-	return ret;
-}
-
-struct mxl_gpio_cfg {
-	u8 pin;
-	u8 dir;
-	u8 val;
-};
-
-static int mxl111sf_config_gpio_pins(struct mxl111sf_state *state,
-				     struct mxl_gpio_cfg *gpio_cfg)
-{
-	int ret;
-	u8 tmp;
-
-	mxl_debug_adv("(%d, %d)", gpio_cfg->pin, gpio_cfg->dir);
-
-	switch (gpio_cfg->pin) {
-	case 0:
-	case 1:
-	case 2:
-	case 3:
-		ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_0, &tmp);
-		if (mxl_fail(ret))
-			goto fail;
-		tmp &= ~(1 << (gpio_cfg->pin + 4));
-		tmp |= (gpio_cfg->dir << (gpio_cfg->pin + 4));
-		ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_0, tmp);
-		if (mxl_fail(ret))
-			goto fail;
-		break;
-	case 4:
-	case 5:
-	case 6:
-	case 7:
-		ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_1, &tmp);
-		if (mxl_fail(ret))
-			goto fail;
-		tmp &= ~(1 << gpio_cfg->pin);
-		tmp |= (gpio_cfg->dir << gpio_cfg->pin);
-		ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_1, tmp);
-		if (mxl_fail(ret))
-			goto fail;
-		break;
-	case 8:
-	case 9:
-	case 10:
-		ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_2, &tmp);
-		if (mxl_fail(ret))
-			goto fail;
-		tmp &= ~(1 << (gpio_cfg->pin - 3));
-		tmp |= (gpio_cfg->dir << (gpio_cfg->pin - 3));
-		ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_2, tmp);
-		if (mxl_fail(ret))
-			goto fail;
-		break;
-	default:
-		return -EINVAL; /* invalid pin */
-	}
-
-	ret = (MXL_GPIO_DIR_OUTPUT == gpio_cfg->dir) ?
-		mxl111sf_set_gpo_state(state,
-				       gpio_cfg->pin, gpio_cfg->val) :
-		mxl111sf_get_gpi_state(state,
-				       gpio_cfg->pin, &gpio_cfg->val);
-	mxl_fail(ret);
-fail:
-	return ret;
-}
-
-static int mxl111sf_hw_do_set_gpio(struct mxl111sf_state *state,
-				   int gpio, int direction, int val)
-{
-	struct mxl_gpio_cfg gpio_config = {
-		.pin = gpio,
-		.dir = direction,
-		.val = val,
-	};
-
-	mxl_debug("(%d, %d, %d)", gpio, direction, val);
-
-	return mxl111sf_config_gpio_pins(state, &gpio_config);
-}
-
-/* ------------------------------------------------------------------------- */
-
-#define PIN_MUX_MPEG_MODE_MASK          0x40   /* 0x17 <6> */
-#define PIN_MUX_MPEG_PAR_EN_MASK        0x01   /* 0x18 <0> */
-#define PIN_MUX_MPEG_SER_EN_MASK        0x02   /* 0x18 <1> */
-#define PIN_MUX_MPG_IN_MUX_MASK         0x80   /* 0x3D <7> */
-#define PIN_MUX_BT656_ENABLE_MASK       0x04   /* 0x12 <2> */
-#define PIN_MUX_I2S_ENABLE_MASK         0x40   /* 0x15 <6> */
-#define PIN_MUX_SPI_MODE_MASK           0x10   /* 0x3D <4> */
-#define PIN_MUX_MCLK_EN_CTRL_MASK       0x10   /* 0x82 <4> */
-#define PIN_MUX_MPSYN_EN_CTRL_MASK      0x20   /* 0x82 <5> */
-#define PIN_MUX_MDVAL_EN_CTRL_MASK      0x40   /* 0x82 <6> */
-#define PIN_MUX_MPERR_EN_CTRL_MASK      0x80   /* 0x82 <7> */
-#define PIN_MUX_MDAT_EN_0_MASK          0x10   /* 0x84 <4> */
-#define PIN_MUX_MDAT_EN_1_MASK          0x20   /* 0x84 <5> */
-#define PIN_MUX_MDAT_EN_2_MASK          0x40   /* 0x84 <6> */
-#define PIN_MUX_MDAT_EN_3_MASK          0x80   /* 0x84 <7> */
-#define PIN_MUX_MDAT_EN_4_MASK          0x10   /* 0x89 <4> */
-#define PIN_MUX_MDAT_EN_5_MASK          0x20   /* 0x89 <5> */
-#define PIN_MUX_MDAT_EN_6_MASK          0x40   /* 0x89 <6> */
-#define PIN_MUX_MDAT_EN_7_MASK          0x80   /* 0x89 <7> */
-
-int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state,
-				  enum mxl111sf_mux_config pin_mux_config)
-{
-	u8 r12, r15, r17, r18, r3D, r82, r84, r89;
-	int ret;
-
-	mxl_debug("(%d)", pin_mux_config);
-
-	ret = mxl111sf_read_reg(state, 0x17, &r17);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_read_reg(state, 0x18, &r18);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_read_reg(state, 0x12, &r12);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_read_reg(state, 0x15, &r15);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_read_reg(state, 0x82, &r82);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_read_reg(state, 0x84, &r84);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_read_reg(state, 0x89, &r89);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_read_reg(state, 0x3D, &r3D);
-	if (mxl_fail(ret))
-		goto fail;
-
-	switch (pin_mux_config) {
-	case PIN_MUX_TS_OUT_PARALLEL:
-		/* mpeg_mode = 1 */
-		r17 |= PIN_MUX_MPEG_MODE_MASK;
-		/* mpeg_par_en = 1 */
-		r18 |= PIN_MUX_MPEG_PAR_EN_MASK;
-		/* mpeg_ser_en = 0 */
-		r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
-		/* mpg_in_mux = 0 */
-		r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
-		/* bt656_enable = 0 */
-		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
-		/* i2s_enable = 0 */
-		r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
-		/* spi_mode = 0 */
-		r3D &= ~PIN_MUX_SPI_MODE_MASK;
-		/* mclk_en_ctrl = 1 */
-		r82 |= PIN_MUX_MCLK_EN_CTRL_MASK;
-		/* mperr_en_ctrl = 1 */
-		r82 |= PIN_MUX_MPERR_EN_CTRL_MASK;
-		/* mdval_en_ctrl = 1 */
-		r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK;
-		/* mpsyn_en_ctrl = 1 */
-		r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK;
-		/* mdat_en_ctrl[3:0] = 0xF */
-		r84 |= 0xF0;
-		/* mdat_en_ctrl[7:4] = 0xF */
-		r89 |= 0xF0;
-		break;
-	case PIN_MUX_TS_OUT_SERIAL:
-		/* mpeg_mode = 1 */
-		r17 |= PIN_MUX_MPEG_MODE_MASK;
-		/* mpeg_par_en = 0 */
-		r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
-		/* mpeg_ser_en = 1 */
-		r18 |= PIN_MUX_MPEG_SER_EN_MASK;
-		/* mpg_in_mux = 0 */
-		r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
-		/* bt656_enable = 0 */
-		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
-		/* i2s_enable = 0 */
-		r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
-		/* spi_mode = 0 */
-		r3D &= ~PIN_MUX_SPI_MODE_MASK;
-		/* mclk_en_ctrl = 1 */
-		r82 |= PIN_MUX_MCLK_EN_CTRL_MASK;
-		/* mperr_en_ctrl = 1 */
-		r82 |= PIN_MUX_MPERR_EN_CTRL_MASK;
-		/* mdval_en_ctrl = 1 */
-		r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK;
-		/* mpsyn_en_ctrl = 1 */
-		r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK;
-		/* mdat_en_ctrl[3:0] = 0xF */
-		r84 |= 0xF0;
-		/* mdat_en_ctrl[7:4] = 0xF */
-		r89 |= 0xF0;
-		break;
-	case PIN_MUX_GPIO_MODE:
-		/* mpeg_mode = 0 */
-		r17 &= ~PIN_MUX_MPEG_MODE_MASK;
-		/* mpeg_par_en = 0 */
-		r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
-		/* mpeg_ser_en = 0 */
-		r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
-		/* mpg_in_mux = 0 */
-		r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
-		/* bt656_enable = 0 */
-		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
-		/* i2s_enable = 0 */
-		r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
-		/* spi_mode = 0 */
-		r3D &= ~PIN_MUX_SPI_MODE_MASK;
-		/* mclk_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
-		/* mperr_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
-		/* mdval_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
-		/* mpsyn_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
-		/* mdat_en_ctrl[3:0] = 0x0 */
-		r84 &= 0x0F;
-		/* mdat_en_ctrl[7:4] = 0x0 */
-		r89 &= 0x0F;
-		break;
-	case PIN_MUX_TS_SERIAL_IN_MODE_0:
-		/* mpeg_mode = 0 */
-		r17 &= ~PIN_MUX_MPEG_MODE_MASK;
-		/* mpeg_par_en = 0 */
-		r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
-		/* mpeg_ser_en = 1 */
-		r18 |= PIN_MUX_MPEG_SER_EN_MASK;
-		/* mpg_in_mux = 0 */
-		r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
-		/* bt656_enable = 0 */
-		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
-		/* i2s_enable = 0 */
-		r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
-		/* spi_mode = 0 */
-		r3D &= ~PIN_MUX_SPI_MODE_MASK;
-		/* mclk_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
-		/* mperr_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
-		/* mdval_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
-		/* mpsyn_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
-		/* mdat_en_ctrl[3:0] = 0x0 */
-		r84 &= 0x0F;
-		/* mdat_en_ctrl[7:4] = 0x0 */
-		r89 &= 0x0F;
-		break;
-	case PIN_MUX_TS_SERIAL_IN_MODE_1:
-		/* mpeg_mode = 0 */
-		r17 &= ~PIN_MUX_MPEG_MODE_MASK;
-		/* mpeg_par_en = 0 */
-		r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
-		/* mpeg_ser_en = 1 */
-		r18 |= PIN_MUX_MPEG_SER_EN_MASK;
-		/* mpg_in_mux = 1 */
-		r3D |= PIN_MUX_MPG_IN_MUX_MASK;
-		/* bt656_enable = 0 */
-		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
-		/* i2s_enable = 0 */
-		r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
-		/* spi_mode = 0 */
-		r3D &= ~PIN_MUX_SPI_MODE_MASK;
-		/* mclk_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
-		/* mperr_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
-		/* mdval_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
-		/* mpsyn_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
-		/* mdat_en_ctrl[3:0] = 0x0 */
-		r84 &= 0x0F;
-		/* mdat_en_ctrl[7:4] = 0x0 */
-		r89 &= 0x0F;
-		break;
-	case PIN_MUX_TS_SPI_IN_MODE_1:
-		/* mpeg_mode = 0 */
-		r17 &= ~PIN_MUX_MPEG_MODE_MASK;
-		/* mpeg_par_en = 0 */
-		r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
-		/* mpeg_ser_en = 1 */
-		r18 |= PIN_MUX_MPEG_SER_EN_MASK;
-		/* mpg_in_mux = 1 */
-		r3D |= PIN_MUX_MPG_IN_MUX_MASK;
-		/* bt656_enable = 0 */
-		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
-		/* i2s_enable = 1 */
-		r15 |= PIN_MUX_I2S_ENABLE_MASK;
-		/* spi_mode = 1 */
-		r3D |= PIN_MUX_SPI_MODE_MASK;
-		/* mclk_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
-		/* mperr_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
-		/* mdval_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
-		/* mpsyn_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
-		/* mdat_en_ctrl[3:0] = 0x0 */
-		r84 &= 0x0F;
-		/* mdat_en_ctrl[7:4] = 0x0 */
-		r89 &= 0x0F;
-		break;
-	case PIN_MUX_TS_SPI_IN_MODE_0:
-		/* mpeg_mode = 0 */
-		r17 &= ~PIN_MUX_MPEG_MODE_MASK;
-		/* mpeg_par_en = 0 */
-		r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
-		/* mpeg_ser_en = 1 */
-		r18 |= PIN_MUX_MPEG_SER_EN_MASK;
-		/* mpg_in_mux = 0 */
-		r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
-		/* bt656_enable = 0 */
-		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
-		/* i2s_enable = 1 */
-		r15 |= PIN_MUX_I2S_ENABLE_MASK;
-		/* spi_mode = 1 */
-		r3D |= PIN_MUX_SPI_MODE_MASK;
-		/* mclk_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
-		/* mperr_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
-		/* mdval_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
-		/* mpsyn_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
-		/* mdat_en_ctrl[3:0] = 0x0 */
-		r84 &= 0x0F;
-		/* mdat_en_ctrl[7:4] = 0x0 */
-		r89 &= 0x0F;
-		break;
-	case PIN_MUX_TS_PARALLEL_IN:
-		/* mpeg_mode = 0 */
-		r17 &= ~PIN_MUX_MPEG_MODE_MASK;
-		/* mpeg_par_en = 1 */
-		r18 |= PIN_MUX_MPEG_PAR_EN_MASK;
-		/* mpeg_ser_en = 0 */
-		r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
-		/* mpg_in_mux = 0 */
-		r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
-		/* bt656_enable = 0 */
-		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
-		/* i2s_enable = 0 */
-		r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
-		/* spi_mode = 0 */
-		r3D &= ~PIN_MUX_SPI_MODE_MASK;
-		/* mclk_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
-		/* mperr_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
-		/* mdval_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
-		/* mpsyn_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
-		/* mdat_en_ctrl[3:0] = 0x0 */
-		r84 &= 0x0F;
-		/* mdat_en_ctrl[7:4] = 0x0 */
-		r89 &= 0x0F;
-		break;
-	case PIN_MUX_BT656_I2S_MODE:
-		/* mpeg_mode = 0 */
-		r17 &= ~PIN_MUX_MPEG_MODE_MASK;
-		/* mpeg_par_en = 0 */
-		r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
-		/* mpeg_ser_en = 0 */
-		r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
-		/* mpg_in_mux = 0 */
-		r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
-		/* bt656_enable = 1 */
-		r12 |= PIN_MUX_BT656_ENABLE_MASK;
-		/* i2s_enable = 1 */
-		r15 |= PIN_MUX_I2S_ENABLE_MASK;
-		/* spi_mode = 0 */
-		r3D &= ~PIN_MUX_SPI_MODE_MASK;
-		/* mclk_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
-		/* mperr_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
-		/* mdval_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
-		/* mpsyn_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
-		/* mdat_en_ctrl[3:0] = 0x0 */
-		r84 &= 0x0F;
-		/* mdat_en_ctrl[7:4] = 0x0 */
-		r89 &= 0x0F;
-		break;
-	case PIN_MUX_DEFAULT:
-	default:
-		/* mpeg_mode = 1 */
-		r17 |= PIN_MUX_MPEG_MODE_MASK;
-		/* mpeg_par_en = 0 */
-		r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
-		/* mpeg_ser_en = 0 */
-		r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
-		/* mpg_in_mux = 0 */
-		r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
-		/* bt656_enable = 0 */
-		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
-		/* i2s_enable = 0 */
-		r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
-		/* spi_mode = 0 */
-		r3D &= ~PIN_MUX_SPI_MODE_MASK;
-		/* mclk_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
-		/* mperr_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
-		/* mdval_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
-		/* mpsyn_en_ctrl = 0 */
-		r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
-		/* mdat_en_ctrl[3:0] = 0x0 */
-		r84 &= 0x0F;
-		/* mdat_en_ctrl[7:4] = 0x0 */
-		r89 &= 0x0F;
-		break;
-	}
-
-	ret = mxl111sf_write_reg(state, 0x17, r17);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_write_reg(state, 0x18, r18);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_write_reg(state, 0x12, r12);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_write_reg(state, 0x15, r15);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_write_reg(state, 0x82, r82);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_write_reg(state, 0x84, r84);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_write_reg(state, 0x89, r89);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_write_reg(state, 0x3D, r3D);
-	if (mxl_fail(ret))
-		goto fail;
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static int mxl111sf_hw_set_gpio(struct mxl111sf_state *state, int gpio, int val)
-{
-	return mxl111sf_hw_do_set_gpio(state, gpio, MXL_GPIO_DIR_OUTPUT, val);
-}
-
-static int mxl111sf_hw_gpio_initialize(struct mxl111sf_state *state)
-{
-	u8 gpioval = 0x07; /* write protect enabled, signal LEDs off */
-	int i, ret;
-
-	mxl_debug("()");
-
-	for (i = 3; i < 8; i++) {
-		ret = mxl111sf_hw_set_gpio(state, i, (gpioval >> i) & 0x01);
-		if (mxl_fail(ret))
-			break;
-	}
-
-	return ret;
-}
-
-#define PCA9534_I2C_ADDR (0x40 >> 1)
-static int pca9534_set_gpio(struct mxl111sf_state *state, int gpio, int val)
-{
-	u8 w[2] = { 1, 0 };
-	u8 r = 0;
-	struct i2c_msg msg[] = {
-		{ .addr = PCA9534_I2C_ADDR,
-		  .flags = 0, .buf = w, .len = 1 },
-		{ .addr = PCA9534_I2C_ADDR,
-		  .flags = I2C_M_RD, .buf = &r, .len = 1 },
-	};
-
-	mxl_debug("(%d, %d)", gpio, val);
-
-	/* read current GPIO levels from flip-flop */
-	i2c_transfer(&state->d->i2c_adap, msg, 2);
-
-	/* prepare write buffer with current GPIO levels */
-	msg[0].len = 2;
-#if 0
-	w[0] = 1;
-#endif
-	w[1] = r;
-
-	/* clear the desired GPIO */
-	w[1] &= ~(1 << gpio);
-
-	/* set the desired GPIO value */
-	w[1] |= ((val ? 1 : 0) << gpio);
-
-	/* write new GPIO levels to flip-flop */
-	i2c_transfer(&state->d->i2c_adap, &msg[0], 1);
-
-	return 0;
-}
-
-static int pca9534_init_port_expander(struct mxl111sf_state *state)
-{
-	u8 w[2] = { 1, 0x07 }; /* write protect enabled, signal LEDs off */
-
-	struct i2c_msg msg = {
-		.addr = PCA9534_I2C_ADDR,
-		.flags = 0, .buf = w, .len = 2
-	};
-
-	mxl_debug("()");
-
-	i2c_transfer(&state->d->i2c_adap, &msg, 1);
-
-	/* configure all pins as outputs */
-	w[0] = 3;
-	w[1] = 0;
-
-	i2c_transfer(&state->d->i2c_adap, &msg, 1);
-
-	return 0;
-}
-
-int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val)
-{
-	mxl_debug("(%d, %d)", gpio, val);
-
-	switch (state->gpio_port_expander) {
-	default:
-		mxl_printk(KERN_ERR,
-			   "gpio_port_expander undefined, assuming PCA9534");
-		/* fall-thru */
-	case mxl111sf_PCA9534:
-		return pca9534_set_gpio(state, gpio, val);
-	case mxl111sf_gpio_hw:
-		return mxl111sf_hw_set_gpio(state, gpio, val);
-	}
-}
-
-static int mxl111sf_probe_port_expander(struct mxl111sf_state *state)
-{
-	int ret;
-	u8 w = 1;
-	u8 r = 0;
-	struct i2c_msg msg[] = {
-		{ .flags = 0,        .buf = &w, .len = 1 },
-		{ .flags = I2C_M_RD, .buf = &r, .len = 1 },
-	};
-
-	mxl_debug("()");
-
-	msg[0].addr = 0x70 >> 1;
-	msg[1].addr = 0x70 >> 1;
-
-	/* read current GPIO levels from flip-flop */
-	ret = i2c_transfer(&state->d->i2c_adap, msg, 2);
-	if (ret == 2) {
-		state->port_expander_addr = msg[0].addr;
-		state->gpio_port_expander = mxl111sf_PCA9534;
-		mxl_debug("found port expander at 0x%02x",
-			  state->port_expander_addr);
-		return 0;
-	}
-
-	msg[0].addr = 0x40 >> 1;
-	msg[1].addr = 0x40 >> 1;
-
-	ret = i2c_transfer(&state->d->i2c_adap, msg, 2);
-	if (ret == 2) {
-		state->port_expander_addr = msg[0].addr;
-		state->gpio_port_expander = mxl111sf_PCA9534;
-		mxl_debug("found port expander at 0x%02x",
-			  state->port_expander_addr);
-		return 0;
-	}
-	state->port_expander_addr = 0xff;
-	state->gpio_port_expander = mxl111sf_gpio_hw;
-	mxl_debug("using hardware gpio");
-	return 0;
-}
-
-int mxl111sf_init_port_expander(struct mxl111sf_state *state)
-{
-	mxl_debug("()");
-
-	if (0x00 == state->port_expander_addr)
-		mxl111sf_probe_port_expander(state);
-
-	switch (state->gpio_port_expander) {
-	default:
-		mxl_printk(KERN_ERR,
-			   "gpio_port_expander undefined, assuming PCA9534");
-		/* fall-thru */
-	case mxl111sf_PCA9534:
-		return pca9534_init_port_expander(state);
-	case mxl111sf_gpio_hw:
-		return mxl111sf_hw_gpio_initialize(state);
-	}
-}
-
-/* ------------------------------------------------------------------------ */
-
-int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode)
-{
-/*	GPO:
- *	3 - ATSC/MH#   | 1 = ATSC transport, 0 = MH transport      | default 0
- *	4 - ATSC_RST## | 1 = ATSC enable, 0 = ATSC Reset           | default 0
- *	5 - ATSC_EN    | 1 = ATSC power enable, 0 = ATSC power off | default 0
- *	6 - MH_RESET#  | 1 = MH enable, 0 = MH Reset               | default 0
- *	7 - MH_EN      | 1 = MH power enable, 0 = MH power off     | default 0
- */
-	mxl_debug("(%d)", mode);
-
-	switch (mode) {
-	case MXL111SF_GPIO_MOD_MH:
-		mxl111sf_set_gpio(state, 4, 0);
-		mxl111sf_set_gpio(state, 5, 0);
-		msleep(50);
-		mxl111sf_set_gpio(state, 7, 1);
-		msleep(50);
-		mxl111sf_set_gpio(state, 6, 1);
-		msleep(50);
-
-		mxl111sf_set_gpio(state, 3, 0);
-		break;
-	case MXL111SF_GPIO_MOD_ATSC:
-		mxl111sf_set_gpio(state, 6, 0);
-		mxl111sf_set_gpio(state, 7, 0);
-		msleep(50);
-		mxl111sf_set_gpio(state, 5, 1);
-		msleep(50);
-		mxl111sf_set_gpio(state, 4, 1);
-		msleep(50);
-		mxl111sf_set_gpio(state, 3, 1);
-		break;
-	default: /* DVBT / STANDBY */
-		mxl111sf_init_port_expander(state);
-		break;
-	}
-	return 0;
-}
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.h b/drivers/media/dvb/dvb-usb/mxl111sf-gpio.h
deleted file mode 100644
index 0220f54..0000000
--- a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- *  mxl111sf-gpio.h - driver for the MaxLinear MXL111SF
- *
- *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _DVB_USB_MXL111SF_GPIO_H_
-#define _DVB_USB_MXL111SF_GPIO_H_
-
-#include "mxl111sf.h"
-
-int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val);
-int mxl111sf_init_port_expander(struct mxl111sf_state *state);
-
-#define MXL111SF_GPIO_MOD_DVBT	0
-#define MXL111SF_GPIO_MOD_MH	1
-#define MXL111SF_GPIO_MOD_ATSC	2
-int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode);
-
-enum mxl111sf_mux_config {
-	PIN_MUX_DEFAULT = 0,
-	PIN_MUX_TS_OUT_PARALLEL,
-	PIN_MUX_TS_OUT_SERIAL,
-	PIN_MUX_GPIO_MODE,
-	PIN_MUX_TS_SERIAL_IN_MODE_0,
-	PIN_MUX_TS_SERIAL_IN_MODE_1,
-	PIN_MUX_TS_SPI_IN_MODE_0,
-	PIN_MUX_TS_SPI_IN_MODE_1,
-	PIN_MUX_TS_PARALLEL_IN,
-	PIN_MUX_BT656_I2S_MODE,
-};
-
-int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state,
-				  enum mxl111sf_mux_config pin_mux_config);
-
-#endif /* _DVB_USB_MXL111SF_GPIO_H_ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c b/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c
deleted file mode 100644
index 3443455..0000000
--- a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c
+++ /dev/null
@@ -1,850 +0,0 @@
-/*
- *  mxl111sf-i2c.c - driver for the MaxLinear MXL111SF
- *
- *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "mxl111sf-i2c.h"
-#include "mxl111sf.h"
-
-/* SW-I2C ----------------------------------------------------------------- */
-
-#define SW_I2C_ADDR		0x1a
-#define SW_I2C_EN		0x02
-#define SW_SCL_OUT		0x04
-#define SW_SDA_OUT		0x08
-#define SW_SDA_IN		0x04
-
-#define SW_I2C_BUSY_ADDR	0x2f
-#define SW_I2C_BUSY		0x02
-
-static int mxl111sf_i2c_bitbang_sendbyte(struct mxl111sf_state *state,
-					 u8 byte)
-{
-	int i, ret;
-	u8 data = 0;
-
-	mxl_i2c("(0x%02x)", byte);
-
-	ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
-	if (mxl_fail(ret))
-		goto fail;
-
-	for (i = 0; i < 8; i++) {
-
-		data = (byte & (0x80 >> i)) ? SW_SDA_OUT : 0;
-
-		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-					 0x10 | SW_I2C_EN | data);
-		if (mxl_fail(ret))
-			goto fail;
-
-		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-					 0x10 | SW_I2C_EN | data | SW_SCL_OUT);
-		if (mxl_fail(ret))
-			goto fail;
-
-		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-					 0x10 | SW_I2C_EN | data);
-		if (mxl_fail(ret))
-			goto fail;
-	}
-
-	/* last bit was 0 so we need to release SDA */
-	if (!(byte & 1)) {
-		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-					 0x10 | SW_I2C_EN | SW_SDA_OUT);
-		if (mxl_fail(ret))
-			goto fail;
-	}
-
-	/* CLK high for ACK readback */
-	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
-	if (mxl_fail(ret))
-		goto fail;
-
-	/* drop the CLK after getting ACK, SDA will go high right away */
-	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-				 0x10 | SW_I2C_EN | SW_SDA_OUT);
-	if (mxl_fail(ret))
-		goto fail;
-
-	if (data & SW_SDA_IN)
-		ret = -EIO;
-fail:
-	return ret;
-}
-
-static int mxl111sf_i2c_bitbang_recvbyte(struct mxl111sf_state *state,
-					 u8 *pbyte)
-{
-	int i, ret;
-	u8 byte = 0;
-	u8 data = 0;
-
-	mxl_i2c("()");
-
-	*pbyte = 0;
-
-	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-				 0x10 | SW_I2C_EN | SW_SDA_OUT);
-	if (mxl_fail(ret))
-		goto fail;
-
-	for (i = 0; i < 8; i++) {
-		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-					 0x10 | SW_I2C_EN |
-					 SW_SCL_OUT | SW_SDA_OUT);
-		if (mxl_fail(ret))
-			goto fail;
-
-		ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
-		if (mxl_fail(ret))
-			goto fail;
-
-		if (data & SW_SDA_IN)
-			byte |= (0x80 >> i);
-
-		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-					 0x10 | SW_I2C_EN | SW_SDA_OUT);
-		if (mxl_fail(ret))
-			goto fail;
-	}
-	*pbyte = byte;
-fail:
-	return ret;
-}
-
-static int mxl111sf_i2c_start(struct mxl111sf_state *state)
-{
-	int ret;
-
-	mxl_i2c("()");
-
-	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-				 0x10 | SW_I2C_EN | SW_SCL_OUT);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-				 0x10 | SW_I2C_EN); /* start */
-	mxl_fail(ret);
-fail:
-	return ret;
-}
-
-static int mxl111sf_i2c_stop(struct mxl111sf_state *state)
-{
-	int ret;
-
-	mxl_i2c("()");
-
-	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-				 0x10 | SW_I2C_EN); /* stop */
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-				 0x10 | SW_I2C_EN | SW_SCL_OUT);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-				 0x10 | SW_SCL_OUT | SW_SDA_OUT);
-	mxl_fail(ret);
-fail:
-	return ret;
-}
-
-static int mxl111sf_i2c_ack(struct mxl111sf_state *state)
-{
-	int ret;
-	u8 b = 0;
-
-	mxl_i2c("()");
-
-	ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &b);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-				 0x10 | SW_I2C_EN);
-	if (mxl_fail(ret))
-		goto fail;
-
-	/* pull SDA low */
-	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-				 0x10 | SW_I2C_EN | SW_SCL_OUT);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-				 0x10 | SW_I2C_EN | SW_SDA_OUT);
-	mxl_fail(ret);
-fail:
-	return ret;
-}
-
-static int mxl111sf_i2c_nack(struct mxl111sf_state *state)
-{
-	int ret;
-
-	mxl_i2c("()");
-
-	/* SDA high to signal last byte read from slave */
-	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
-				 0x10 | SW_I2C_EN | SW_SDA_OUT);
-	mxl_fail(ret);
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int mxl111sf_i2c_sw_xfer_msg(struct mxl111sf_state *state,
-				    struct i2c_msg *msg)
-{
-	int i, ret;
-
-	mxl_i2c("()");
-
-	if (msg->flags & I2C_M_RD) {
-
-		ret = mxl111sf_i2c_start(state);
-		if (mxl_fail(ret))
-			goto fail;
-
-		ret = mxl111sf_i2c_bitbang_sendbyte(state,
-						    (msg->addr << 1) | 0x01);
-		if (mxl_fail(ret)) {
-			mxl111sf_i2c_stop(state);
-			goto fail;
-		}
-
-		for (i = 0; i < msg->len; i++) {
-			ret = mxl111sf_i2c_bitbang_recvbyte(state,
-							    &msg->buf[i]);
-			if (mxl_fail(ret)) {
-				mxl111sf_i2c_stop(state);
-				goto fail;
-			}
-
-			if (i < msg->len - 1)
-				mxl111sf_i2c_ack(state);
-		}
-
-		mxl111sf_i2c_nack(state);
-
-		ret = mxl111sf_i2c_stop(state);
-		if (mxl_fail(ret))
-			goto fail;
-
-	} else {
-
-		ret = mxl111sf_i2c_start(state);
-		if (mxl_fail(ret))
-			goto fail;
-
-		ret = mxl111sf_i2c_bitbang_sendbyte(state,
-						    (msg->addr << 1) & 0xfe);
-		if (mxl_fail(ret)) {
-			mxl111sf_i2c_stop(state);
-			goto fail;
-		}
-
-		for (i = 0; i < msg->len; i++) {
-			ret = mxl111sf_i2c_bitbang_sendbyte(state,
-							    msg->buf[i]);
-			if (mxl_fail(ret)) {
-				mxl111sf_i2c_stop(state);
-				goto fail;
-			}
-		}
-
-		/* FIXME: we only want to do this on the last transaction */
-		mxl111sf_i2c_stop(state);
-	}
-fail:
-	return ret;
-}
-
-/* HW-I2C ----------------------------------------------------------------- */
-
-#define USB_WRITE_I2C_CMD     0x99
-#define USB_READ_I2C_CMD      0xdd
-#define USB_END_I2C_CMD       0xfe
-
-#define USB_WRITE_I2C_CMD_LEN   26
-#define USB_READ_I2C_CMD_LEN    24
-
-#define I2C_MUX_REG           0x30
-#define I2C_CONTROL_REG       0x00
-#define I2C_SLAVE_ADDR_REG    0x08
-#define I2C_DATA_REG          0x0c
-#define I2C_INT_STATUS_REG    0x10
-
-static int mxl111sf_i2c_send_data(struct mxl111sf_state *state,
-				  u8 index, u8 *wdata)
-{
-	int ret = mxl111sf_ctrl_msg(state->d, wdata[0],
-				    &wdata[1], 25, NULL, 0);
-	mxl_fail(ret);
-
-	return ret;
-}
-
-static int mxl111sf_i2c_get_data(struct mxl111sf_state *state,
-				 u8 index, u8 *wdata, u8 *rdata)
-{
-	int ret = mxl111sf_ctrl_msg(state->d, wdata[0],
-				    &wdata[1], 25, rdata, 24);
-	mxl_fail(ret);
-
-	return ret;
-}
-
-static u8 mxl111sf_i2c_check_status(struct mxl111sf_state *state)
-{
-	u8 status = 0;
-	u8 buf[26];
-
-	mxl_i2c_adv("()");
-
-	buf[0] = USB_READ_I2C_CMD;
-	buf[1] = 0x00;
-
-	buf[2] = I2C_INT_STATUS_REG;
-	buf[3] = 0x00;
-	buf[4] = 0x00;
-
-	buf[5] = USB_END_I2C_CMD;
-
-	mxl111sf_i2c_get_data(state, 0, buf, buf);
-
-	if (buf[1] & 0x04)
-		status = 1;
-
-	return status;
-}
-
-static u8 mxl111sf_i2c_check_fifo(struct mxl111sf_state *state)
-{
-	u8 status = 0;
-	u8 buf[26];
-
-	mxl_i2c("()");
-
-	buf[0] = USB_READ_I2C_CMD;
-	buf[1] = 0x00;
-
-	buf[2] = I2C_MUX_REG;
-	buf[3] = 0x00;
-	buf[4] = 0x00;
-
-	buf[5] = I2C_INT_STATUS_REG;
-	buf[6] = 0x00;
-	buf[7] = 0x00;
-	buf[8] = USB_END_I2C_CMD;
-
-	mxl111sf_i2c_get_data(state, 0, buf, buf);
-
-	if (0x08 == (buf[1] & 0x08))
-		status = 1;
-
-	if ((buf[5] & 0x02) == 0x02)
-		mxl_i2c("(buf[5] & 0x02) == 0x02"); /* FIXME */
-
-	return status;
-}
-
-static int mxl111sf_i2c_readagain(struct mxl111sf_state *state,
-				  u8 count, u8 *rbuf)
-{
-	u8 i2c_w_data[26];
-	u8 i2c_r_data[24];
-	u8 i = 0;
-	u8 fifo_status = 0;
-	int status = 0;
-
-	mxl_i2c("read %d bytes", count);
-
-	while ((fifo_status == 0) && (i++ < 5))
-		fifo_status = mxl111sf_i2c_check_fifo(state);
-
-	i2c_w_data[0] = 0xDD;
-	i2c_w_data[1] = 0x00;
-
-	for (i = 2; i < 26; i++)
-		i2c_w_data[i] = 0xFE;
-
-	for (i = 0; i < count; i++) {
-		i2c_w_data[2+(i*3)] = 0x0C;
-		i2c_w_data[3+(i*3)] = 0x00;
-		i2c_w_data[4+(i*3)] = 0x00;
-	}
-
-	mxl111sf_i2c_get_data(state, 0, i2c_w_data, i2c_r_data);
-
-	/* Check for I2C NACK status */
-	if (mxl111sf_i2c_check_status(state) == 1) {
-		mxl_i2c("error!");
-	} else {
-		for (i = 0; i < count; i++) {
-			rbuf[i] = i2c_r_data[(i*3)+1];
-			mxl_i2c("%02x\t %02x",
-				i2c_r_data[(i*3)+1],
-				i2c_r_data[(i*3)+2]);
-		}
-
-		status = 1;
-	}
-
-	return status;
-}
-
-#define HWI2C400 1
-static int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state,
-				    struct i2c_msg *msg)
-{
-	int i, k, ret = 0;
-	u16 index = 0;
-	u8 buf[26];
-	u8 i2c_r_data[24];
-	u16 block_len;
-	u16 left_over_len;
-	u8 rd_status[8];
-	u8 ret_status;
-	u8 readbuff[26];
-
-	mxl_i2c("addr: 0x%02x, read buff len: %d, write buff len: %d",
-		msg->addr, (msg->flags & I2C_M_RD) ? msg->len : 0,
-		(!(msg->flags & I2C_M_RD)) ? msg->len : 0);
-
-	for (index = 0; index < 26; index++)
-		buf[index] = USB_END_I2C_CMD;
-
-	/* command to indicate data payload is destined for I2C interface */
-	buf[0] = USB_WRITE_I2C_CMD;
-	buf[1] = 0x00;
-
-	/* enable I2C interface */
-	buf[2] = I2C_MUX_REG;
-	buf[3] = 0x80;
-	buf[4] = 0x00;
-
-	/* enable I2C interface */
-	buf[5] = I2C_MUX_REG;
-	buf[6] = 0x81;
-	buf[7] = 0x00;
-
-	/* set Timeout register on I2C interface */
-	buf[8] = 0x14;
-	buf[9] = 0xff;
-	buf[10] = 0x00;
-#if 0
-	/* enable Interrupts on I2C interface */
-	buf[8] = 0x24;
-	buf[9] = 0xF7;
-	buf[10] = 0x00;
-#endif
-	buf[11] = 0x24;
-	buf[12] = 0xF7;
-	buf[13] = 0x00;
-
-	ret = mxl111sf_i2c_send_data(state, 0, buf);
-
-	/* write data on I2C bus */
-	if (!(msg->flags & I2C_M_RD) && (msg->len > 0)) {
-		mxl_i2c("%d\t%02x", msg->len, msg->buf[0]);
-
-		/* control register on I2C interface to initialize I2C bus */
-		buf[2] = I2C_CONTROL_REG;
-		buf[3] = 0x5E;
-		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
-
-		/* I2C Slave device Address */
-		buf[5] = I2C_SLAVE_ADDR_REG;
-		buf[6] = (msg->addr);
-		buf[7] = 0x00;
-		buf[8] = USB_END_I2C_CMD;
-		ret = mxl111sf_i2c_send_data(state, 0, buf);
-
-		/* check for slave device status */
-		if (mxl111sf_i2c_check_status(state) == 1) {
-			mxl_i2c("NACK writing slave address %02x",
-				msg->addr);
-			/* if NACK, stop I2C bus and exit */
-			buf[2] = I2C_CONTROL_REG;
-			buf[3] = 0x4E;
-			buf[4] = (HWI2C400) ? 0x03 : 0x0D;
-			ret = -EIO;
-			goto exit;
-		}
-
-		/* I2C interface can do I2C operations in block of 8 bytes of
-		   I2C data. calculation to figure out number of blocks of i2c
-		   data required to program */
-		block_len = (msg->len / 8);
-		left_over_len = (msg->len % 8);
-		index = 0;
-
-		mxl_i2c("block_len %d, left_over_len %d",
-			block_len, left_over_len);
-
-		for (index = 0; index < block_len; index++) {
-			for (i = 0; i < 8; i++) {
-				/* write data on I2C interface */
-				buf[2+(i*3)] = I2C_DATA_REG;
-				buf[3+(i*3)] = msg->buf[(index*8)+i];
-				buf[4+(i*3)] = 0x00;
-			}
-
-			ret = mxl111sf_i2c_send_data(state, 0, buf);
-
-			/* check for I2C NACK status */
-			if (mxl111sf_i2c_check_status(state) == 1) {
-				mxl_i2c("NACK writing slave address %02x",
-					msg->addr);
-
-				/* if NACK, stop I2C bus and exit */
-				buf[2] = I2C_CONTROL_REG;
-				buf[3] = 0x4E;
-				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
-				ret = -EIO;
-				goto exit;
-			}
-
-		}
-
-		if (left_over_len) {
-			for (k = 0; k < 26; k++)
-				buf[k] = USB_END_I2C_CMD;
-
-			buf[0] = 0x99;
-			buf[1] = 0x00;
-
-			for (i = 0; i < left_over_len; i++) {
-				buf[2+(i*3)] = I2C_DATA_REG;
-				buf[3+(i*3)] = msg->buf[(index*8)+i];
-				mxl_i2c("index = %d %d data %d",
-					index, i, msg->buf[(index*8)+i]);
-				buf[4+(i*3)] = 0x00;
-			}
-			ret = mxl111sf_i2c_send_data(state, 0, buf);
-
-			/* check for I2C NACK status */
-			if (mxl111sf_i2c_check_status(state) == 1) {
-				mxl_i2c("NACK writing slave address %02x",
-					msg->addr);
-
-				/* if NACK, stop I2C bus and exit */
-				buf[2] = I2C_CONTROL_REG;
-				buf[3] = 0x4E;
-				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
-				ret = -EIO;
-				goto exit;
-			}
-
-		}
-
-		/* issue I2C STOP after write */
-		buf[2] = I2C_CONTROL_REG;
-		buf[3] = 0x4E;
-		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
-
-	}
-
-	/* read data from I2C bus */
-	if ((msg->flags & I2C_M_RD) && (msg->len > 0)) {
-		mxl_i2c("read buf len %d", msg->len);
-
-		/* command to indicate data payload is
-		   destined for I2C interface */
-		buf[2] = I2C_CONTROL_REG;
-		buf[3] = 0xDF;
-		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
-
-		/* I2C xfer length */
-		buf[5] = 0x14;
-		buf[6] = (msg->len & 0xFF);
-		buf[7] = 0;
-
-		/* I2C slave device Address */
-		buf[8] = I2C_SLAVE_ADDR_REG;
-		buf[9] = msg->addr;
-		buf[10] = 0x00;
-		buf[11] = USB_END_I2C_CMD;
-		ret = mxl111sf_i2c_send_data(state, 0, buf);
-
-		/* check for I2C NACK status */
-		if (mxl111sf_i2c_check_status(state) == 1) {
-			mxl_i2c("NACK reading slave address %02x",
-				msg->addr);
-
-			/* if NACK, stop I2C bus and exit */
-			buf[2] = I2C_CONTROL_REG;
-			buf[3] = 0xC7;
-			buf[4] = (HWI2C400) ? 0x03 : 0x0D;
-			ret = -EIO;
-			goto exit;
-		}
-
-		/* I2C interface can do I2C operations in block of 8 bytes of
-		   I2C data. calculation to figure out number of blocks of
-		   i2c data required to program */
-		block_len = ((msg->len) / 8);
-		left_over_len = ((msg->len) % 8);
-		index = 0;
-
-		mxl_i2c("block_len %d, left_over_len %d",
-			block_len, left_over_len);
-
-		/* command to read data from I2C interface */
-		buf[0] = USB_READ_I2C_CMD;
-		buf[1] = 0x00;
-
-		for (index = 0; index < block_len; index++) {
-			/* setup I2C read request packet on I2C interface */
-			for (i = 0; i < 8; i++) {
-				buf[2+(i*3)] = I2C_DATA_REG;
-				buf[3+(i*3)] = 0x00;
-				buf[4+(i*3)] = 0x00;
-			}
-
-			ret = mxl111sf_i2c_get_data(state, 0, buf, i2c_r_data);
-
-			/* check for I2C NACK status */
-			if (mxl111sf_i2c_check_status(state) == 1) {
-				mxl_i2c("NACK reading slave address %02x",
-					msg->addr);
-
-				/* if NACK, stop I2C bus and exit */
-				buf[2] = I2C_CONTROL_REG;
-				buf[3] = 0xC7;
-				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
-				ret = -EIO;
-				goto exit;
-			}
-
-			/* copy data from i2c data payload to read buffer */
-			for (i = 0; i < 8; i++) {
-				rd_status[i] = i2c_r_data[(i*3)+2];
-
-				if (rd_status[i] == 0x04) {
-					if (i < 7) {
-						mxl_i2c("i2c fifo empty!"
-							" @ %d", i);
-						msg->buf[(index*8)+i] =
-							i2c_r_data[(i*3)+1];
-						/* read again */
-						ret_status =
-							mxl111sf_i2c_readagain(
-								state, 8-(i+1),
-								readbuff);
-						if (ret_status == 1) {
-							for (k = 0;
-							     k < 8-(i+1);
-							     k++) {
-
-					msg->buf[(index*8)+(k+i+1)] =
-						readbuff[k];
-					mxl_i2c("read data: %02x\t %02x",
-						msg->buf[(index*8)+(k+i)],
-						(index*8)+(k+i));
-					mxl_i2c("read data: %02x\t %02x",
-						msg->buf[(index*8)+(k+i+1)],
-						readbuff[k]);
-
-							}
-							goto stop_copy;
-						} else {
-							mxl_i2c("readagain "
-								"ERROR!");
-						}
-					} else {
-						msg->buf[(index*8)+i] =
-							i2c_r_data[(i*3)+1];
-					}
-				} else {
-					msg->buf[(index*8)+i] =
-						i2c_r_data[(i*3)+1];
-				}
-			}
-stop_copy:
-			;
-
-		}
-
-		if (left_over_len) {
-			for (k = 0; k < 26; k++)
-				buf[k] = USB_END_I2C_CMD;
-
-			buf[0] = 0xDD;
-			buf[1] = 0x00;
-
-			for (i = 0; i < left_over_len; i++) {
-				buf[2+(i*3)] = I2C_DATA_REG;
-				buf[3+(i*3)] = 0x00;
-				buf[4+(i*3)] = 0x00;
-			}
-			ret = mxl111sf_i2c_get_data(state, 0, buf,
-						    i2c_r_data);
-
-			/* check for I2C NACK status */
-			if (mxl111sf_i2c_check_status(state) == 1) {
-				mxl_i2c("NACK reading slave address %02x",
-					msg->addr);
-
-				/* if NACK, stop I2C bus and exit */
-				buf[2] = I2C_CONTROL_REG;
-				buf[3] = 0xC7;
-				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
-				ret = -EIO;
-				goto exit;
-			}
-
-			for (i = 0; i < left_over_len; i++) {
-				msg->buf[(block_len*8)+i] =
-					i2c_r_data[(i*3)+1];
-				mxl_i2c("read data: %02x\t %02x",
-					i2c_r_data[(i*3)+1],
-					i2c_r_data[(i*3)+2]);
-			}
-		}
-
-		/* indicate I2C interface to issue NACK
-		   after next I2C read op */
-		buf[0] = USB_WRITE_I2C_CMD;
-		buf[1] = 0x00;
-
-		/* control register */
-		buf[2] = I2C_CONTROL_REG;
-		buf[3] = 0x17;
-		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
-
-		buf[5] = USB_END_I2C_CMD;
-		ret = mxl111sf_i2c_send_data(state, 0, buf);
-
-		/* control register */
-		buf[2] = I2C_CONTROL_REG;
-		buf[3] = 0xC7;
-		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
-
-	}
-exit:
-	/* STOP and disable I2C MUX */
-	buf[0] = USB_WRITE_I2C_CMD;
-	buf[1] = 0x00;
-
-	/* de-initilize I2C BUS */
-	buf[5] = USB_END_I2C_CMD;
-	mxl111sf_i2c_send_data(state, 0, buf);
-
-	/* Control Register */
-	buf[2] = I2C_CONTROL_REG;
-	buf[3] = 0xDF;
-	buf[4] = 0x03;
-
-	/* disable I2C interface */
-	buf[5] = I2C_MUX_REG;
-	buf[6] = 0x00;
-	buf[7] = 0x00;
-
-	/* de-initilize I2C BUS */
-	buf[8] = USB_END_I2C_CMD;
-	mxl111sf_i2c_send_data(state, 0, buf);
-
-	/* disable I2C interface */
-	buf[2] = I2C_MUX_REG;
-	buf[3] = 0x81;
-	buf[4] = 0x00;
-
-	/* disable I2C interface */
-	buf[5] = I2C_MUX_REG;
-	buf[6] = 0x00;
-	buf[7] = 0x00;
-
-	/* disable I2C interface */
-	buf[8] = I2C_MUX_REG;
-	buf[9] = 0x00;
-	buf[10] = 0x00;
-
-	buf[11] = USB_END_I2C_CMD;
-	mxl111sf_i2c_send_data(state, 0, buf);
-
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-int mxl111sf_i2c_xfer(struct i2c_adapter *adap,
-		      struct i2c_msg msg[], int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	struct mxl111sf_state *state = d->priv;
-	int hwi2c = (state->chip_rev > MXL111SF_V6);
-	int i, ret;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	for (i = 0; i < num; i++) {
-		ret = (hwi2c) ?
-			mxl111sf_i2c_hw_xfer_msg(state, &msg[i]) :
-			mxl111sf_i2c_sw_xfer_msg(state, &msg[i]);
-		if (mxl_fail(ret)) {
-			mxl_debug_adv("failed with error %d on i2c "
-				      "transaction %d of %d, %sing %d bytes "
-				      "to/from 0x%02x", ret, i+1, num,
-				      (msg[i].flags & I2C_M_RD) ?
-				      "read" : "writ",
-				      msg[i].len, msg[i].addr);
-
-			break;
-		}
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-
-	return i == num ? num : -EREMOTEIO;
-}
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.h b/drivers/media/dvb/dvb-usb/mxl111sf-i2c.h
deleted file mode 100644
index a57a45f..0000000
--- a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *  mxl111sf-i2c.h - driver for the MaxLinear MXL111SF
- *
- *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _DVB_USB_MXL111SF_I2C_H_
-#define _DVB_USB_MXL111SF_I2C_H_
-
-#include <linux/i2c.h>
-
-int mxl111sf_i2c_xfer(struct i2c_adapter *adap,
-		      struct i2c_msg msg[], int num);
-
-#endif /* _DVB_USB_MXL111SF_I2C_H_ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-phy.c b/drivers/media/dvb/dvb-usb/mxl111sf-phy.c
deleted file mode 100644
index b741b3a..0000000
--- a/drivers/media/dvb/dvb-usb/mxl111sf-phy.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- *  mxl111sf-phy.c - driver for the MaxLinear MXL111SF
- *
- *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "mxl111sf-phy.h"
-#include "mxl111sf-reg.h"
-
-int mxl111sf_init_tuner_demod(struct mxl111sf_state *state)
-{
-	struct mxl111sf_reg_ctrl_info mxl_111_overwrite_default[] = {
-		{0x07, 0xff, 0x0c},
-		{0x58, 0xff, 0x9d},
-		{0x09, 0xff, 0x00},
-		{0x06, 0xff, 0x06},
-		{0xc8, 0xff, 0x40}, /* ED_LE_WIN_OLD = 0 */
-		{0x8d, 0x01, 0x01}, /* NEGATE_Q */
-		{0x32, 0xff, 0xac}, /* DIG_RFREFSELECT = 12 */
-		{0x42, 0xff, 0x43}, /* DIG_REG_AMP = 4 */
-		{0x74, 0xff, 0xc4}, /* SSPUR_FS_PRIO = 4 */
-		{0x71, 0xff, 0xe6}, /* SPUR_ROT_PRIO_VAL = 1 */
-		{0x83, 0xff, 0x64}, /* INF_FILT1_THD_SC = 100 */
-		{0x85, 0xff, 0x64}, /* INF_FILT2_THD_SC = 100 */
-		{0x88, 0xff, 0xf0}, /* INF_THD = 240 */
-		{0x6f, 0xf0, 0xb0}, /* DFE_DLY = 11 */
-		{0x00, 0xff, 0x01}, /* Change to page 1 */
-		{0x81, 0xff, 0x11}, /* DSM_FERR_BYPASS = 1 */
-		{0xf4, 0xff, 0x07}, /* DIG_FREQ_CORR = 1 */
-		{0xd4, 0x1f, 0x0f}, /* SPUR_TEST_NOISE_TH = 15 */
-		{0xd6, 0xff, 0x0c}, /* SPUR_TEST_NOISE_PAPR = 12 */
-		{0x00, 0xff, 0x00}, /* Change to page 0 */
-		{0,    0,    0}
-	};
-
-	mxl_debug("()");
-
-	return mxl111sf_ctrl_program_regs(state, mxl_111_overwrite_default);
-}
-
-int mxl1x1sf_soft_reset(struct mxl111sf_state *state)
-{
-	int ret;
-	mxl_debug("()");
-
-	ret = mxl111sf_write_reg(state, 0xff, 0x00); /* AIC */
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_write_reg(state, 0x02, 0x01); /* get out of reset */
-	mxl_fail(ret);
-fail:
-	return ret;
-}
-
-int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode)
-{
-	int ret;
-
-	mxl_debug("(%s)", MXL_SOC_MODE == mode ?
-		"MXL_SOC_MODE" : "MXL_TUNER_MODE");
-
-	/* set device mode */
-	ret = mxl111sf_write_reg(state, 0x03,
-				 MXL_SOC_MODE == mode ? 0x01 : 0x00);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_write_reg_mask(state,
-				      0x7d, 0x40, MXL_SOC_MODE == mode ?
-				      0x00 : /* enable impulse noise filter,
-						INF_BYP = 0 */
-				      0x40); /* disable impulse noise filter,
-						INF_BYP = 1 */
-	if (mxl_fail(ret))
-		goto fail;
-
-	state->device_mode = mode;
-fail:
-	return ret;
-}
-
-/* power up tuner */
-int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff)
-{
-	mxl_debug("(%d)", onoff);
-
-	return mxl111sf_write_reg(state, 0x01, onoff ? 0x01 : 0x00);
-}
-
-int mxl111sf_disable_656_port(struct mxl111sf_state *state)
-{
-	mxl_debug("()");
-
-	return mxl111sf_write_reg_mask(state, 0x12, 0x04, 0x00);
-}
-
-int mxl111sf_enable_usb_output(struct mxl111sf_state *state)
-{
-	mxl_debug("()");
-
-	return mxl111sf_write_reg_mask(state, 0x17, 0x40, 0x00);
-}
-
-/* initialize TSIF as input port of MxL1X1SF for MPEG2 data transfer */
-int mxl111sf_config_mpeg_in(struct mxl111sf_state *state,
-			    unsigned int parallel_serial,
-			    unsigned int msb_lsb_1st,
-			    unsigned int clock_phase,
-			    unsigned int mpeg_valid_pol,
-			    unsigned int mpeg_sync_pol)
-{
-	int ret;
-	u8 mode, tmp;
-
-	mxl_debug("(%u,%u,%u,%u,%u)", parallel_serial, msb_lsb_1st,
-		  clock_phase, mpeg_valid_pol, mpeg_sync_pol);
-
-	/* Enable PIN MUX */
-	ret = mxl111sf_write_reg(state, V6_PIN_MUX_MODE_REG, V6_ENABLE_PIN_MUX);
-	mxl_fail(ret);
-
-	/* Configure MPEG Clock phase */
-	mxl111sf_read_reg(state, V6_MPEG_IN_CLK_INV_REG, &mode);
-
-	if (clock_phase == TSIF_NORMAL)
-		mode &= ~V6_INVERTED_CLK_PHASE;
-	else
-		mode |= V6_INVERTED_CLK_PHASE;
-
-	ret = mxl111sf_write_reg(state, V6_MPEG_IN_CLK_INV_REG, mode);
-	mxl_fail(ret);
-
-	/* Configure data input mode, MPEG Valid polarity, MPEG Sync polarity
-	 * Get current configuration */
-	ret = mxl111sf_read_reg(state, V6_MPEG_IN_CTRL_REG, &mode);
-	mxl_fail(ret);
-
-	/* Data Input mode */
-	if (parallel_serial == TSIF_INPUT_PARALLEL) {
-		/* Disable serial mode */
-		mode &= ~V6_MPEG_IN_DATA_SERIAL;
-
-		/* Enable Parallel mode */
-		mode |= V6_MPEG_IN_DATA_PARALLEL;
-	} else {
-		/* Disable Parallel mode */
-		mode &= ~V6_MPEG_IN_DATA_PARALLEL;
-
-		/* Enable Serial Mode */
-		mode |= V6_MPEG_IN_DATA_SERIAL;
-
-		/* If serial interface is chosen, configure
-		   MSB or LSB order in transmission */
-		ret = mxl111sf_read_reg(state,
-					V6_MPEG_INOUT_BIT_ORDER_CTRL_REG,
-					&tmp);
-		mxl_fail(ret);
-
-		if (msb_lsb_1st == MPEG_SER_MSB_FIRST_ENABLED)
-			tmp |= V6_MPEG_SER_MSB_FIRST;
-		else
-			tmp &= ~V6_MPEG_SER_MSB_FIRST;
-
-		ret = mxl111sf_write_reg(state,
-					 V6_MPEG_INOUT_BIT_ORDER_CTRL_REG,
-					 tmp);
-		mxl_fail(ret);
-	}
-
-	/* MPEG Sync polarity */
-	if (mpeg_sync_pol == TSIF_NORMAL)
-		mode &= ~V6_INVERTED_MPEG_SYNC;
-	else
-		mode |= V6_INVERTED_MPEG_SYNC;
-
-	/* MPEG Valid polarity */
-	if (mpeg_valid_pol == 0)
-		mode &= ~V6_INVERTED_MPEG_VALID;
-	else
-		mode |= V6_INVERTED_MPEG_VALID;
-
-	ret = mxl111sf_write_reg(state, V6_MPEG_IN_CTRL_REG, mode);
-	mxl_fail(ret);
-
-	return ret;
-}
-
-int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size)
-{
-	static struct mxl111sf_reg_ctrl_info init_i2s[] = {
-		{0x1b, 0xff, 0x1e}, /* pin mux mode, Choose 656/I2S input */
-		{0x15, 0x60, 0x60}, /* Enable I2S */
-		{0x17, 0xe0, 0x20}, /* Input, MPEG MODE USB,
-				       Inverted 656 Clock, I2S_SOFT_RESET,
-				       0 : Normal operation, 1 : Reset State */
-#if 0
-		{0x12, 0x01, 0x00}, /* AUDIO_IRQ_CLR (Overflow Indicator) */
-#endif
-		{0x00, 0xff, 0x02}, /* Change to Control Page */
-		{0x26, 0x0d, 0x0d}, /* I2S_MODE & BT656_SRC_SEL for FPGA only */
-		{0x00, 0xff, 0x00},
-		{0,    0,    0}
-	};
-	int ret;
-
-	mxl_debug("(0x%02x)", sample_size);
-
-	ret = mxl111sf_ctrl_program_regs(state, init_i2s);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_write_reg(state, V6_I2S_NUM_SAMPLES_REG, sample_size);
-	mxl_fail(ret);
-fail:
-	return ret;
-}
-
-int mxl111sf_disable_i2s_port(struct mxl111sf_state *state)
-{
-	static struct mxl111sf_reg_ctrl_info disable_i2s[] = {
-		{0x15, 0x40, 0x00},
-		{0,    0,    0}
-	};
-
-	mxl_debug("()");
-
-	return mxl111sf_ctrl_program_regs(state, disable_i2s);
-}
-
-int mxl111sf_config_i2s(struct mxl111sf_state *state,
-			u8 msb_start_pos, u8 data_width)
-{
-	int ret;
-	u8 tmp;
-
-	mxl_debug("(0x%02x, 0x%02x)", msb_start_pos, data_width);
-
-	ret = mxl111sf_read_reg(state, V6_I2S_STREAM_START_BIT_REG, &tmp);
-	if (mxl_fail(ret))
-		goto fail;
-
-	tmp &= 0xe0;
-	tmp |= msb_start_pos;
-	ret = mxl111sf_write_reg(state, V6_I2S_STREAM_START_BIT_REG, tmp);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_read_reg(state, V6_I2S_STREAM_END_BIT_REG, &tmp);
-	if (mxl_fail(ret))
-		goto fail;
-
-	tmp &= 0xe0;
-	tmp |= data_width;
-	ret = mxl111sf_write_reg(state, V6_I2S_STREAM_END_BIT_REG, tmp);
-	mxl_fail(ret);
-fail:
-	return ret;
-}
-
-int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff)
-{
-	u8 val;
-	int ret;
-
-	mxl_debug("(%d)", onoff);
-
-	ret = mxl111sf_write_reg(state, 0x00, 0x02);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_read_reg(state, V8_SPI_MODE_REG, &val);
-	if (mxl_fail(ret))
-		goto fail;
-
-	if (onoff)
-		val |= 0x04;
-	else
-		val &= ~0x04;
-
-	ret = mxl111sf_write_reg(state, V8_SPI_MODE_REG, val);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_write_reg(state, 0x00, 0x00);
-	mxl_fail(ret);
-fail:
-	return ret;
-}
-
-int mxl111sf_idac_config(struct mxl111sf_state *state,
-			 u8 control_mode, u8 current_setting,
-			 u8 current_value, u8 hysteresis_value)
-{
-	int ret;
-	u8 val;
-	/* current value will be set for both automatic & manual IDAC control */
-	val = current_value;
-
-	if (control_mode == IDAC_MANUAL_CONTROL) {
-		/* enable manual control of IDAC */
-		val |= IDAC_MANUAL_CONTROL_BIT_MASK;
-
-		if (current_setting == IDAC_CURRENT_SINKING_ENABLE)
-			/* enable current sinking in manual mode */
-			val |= IDAC_CURRENT_SINKING_BIT_MASK;
-		else
-			/* disable current sinking in manual mode */
-			val &= ~IDAC_CURRENT_SINKING_BIT_MASK;
-	} else {
-		/* disable manual control of IDAC */
-		val &= ~IDAC_MANUAL_CONTROL_BIT_MASK;
-
-		/* set hysteresis value  reg: 0x0B<5:0> */
-		ret = mxl111sf_write_reg(state, V6_IDAC_HYSTERESIS_REG,
-					 (hysteresis_value & 0x3F));
-		mxl_fail(ret);
-	}
-
-	ret = mxl111sf_write_reg(state, V6_IDAC_SETTINGS_REG, val);
-	mxl_fail(ret);
-
-	return ret;
-}
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-phy.h b/drivers/media/dvb/dvb-usb/mxl111sf-phy.h
deleted file mode 100644
index f075607..0000000
--- a/drivers/media/dvb/dvb-usb/mxl111sf-phy.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *  mxl111sf-phy.h - driver for the MaxLinear MXL111SF
- *
- *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _DVB_USB_MXL111SF_PHY_H_
-#define _DVB_USB_MXL111SF_PHY_H_
-
-#include "mxl111sf.h"
-
-int mxl1x1sf_soft_reset(struct mxl111sf_state *state);
-int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode);
-int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff);
-int mxl111sf_disable_656_port(struct mxl111sf_state *state);
-int mxl111sf_init_tuner_demod(struct mxl111sf_state *state);
-int mxl111sf_enable_usb_output(struct mxl111sf_state *state);
-int mxl111sf_config_mpeg_in(struct mxl111sf_state *state,
-			    unsigned int parallel_serial,
-			    unsigned int msb_lsb_1st,
-			    unsigned int clock_phase,
-			    unsigned int mpeg_valid_pol,
-			    unsigned int mpeg_sync_pol);
-int mxl111sf_config_i2s(struct mxl111sf_state *state,
-			u8 msb_start_pos, u8 data_width);
-int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size);
-int mxl111sf_disable_i2s_port(struct mxl111sf_state *state);
-int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff);
-int mxl111sf_idac_config(struct mxl111sf_state *state,
-			 u8 control_mode, u8 current_setting,
-			 u8 current_value, u8 hysteresis_value);
-
-#endif /* _DVB_USB_MXL111SF_PHY_H_ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-reg.h b/drivers/media/dvb/dvb-usb/mxl111sf-reg.h
deleted file mode 100644
index 17831b0..0000000
--- a/drivers/media/dvb/dvb-usb/mxl111sf-reg.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- *  mxl111sf-reg.h - driver for the MaxLinear MXL111SF
- *
- *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _DVB_USB_MXL111SF_REG_H_
-#define _DVB_USB_MXL111SF_REG_H_
-
-#define CHIP_ID_REG                  0xFC
-#define TOP_CHIP_REV_ID_REG          0xFA
-
-#define V6_SNR_RB_LSB_REG            0x27
-#define V6_SNR_RB_MSB_REG            0x28
-
-#define V6_N_ACCUMULATE_REG          0x11
-#define V6_RS_AVG_ERRORS_LSB_REG     0x2C
-#define V6_RS_AVG_ERRORS_MSB_REG     0x2D
-
-#define V6_IRQ_STATUS_REG            0x24
-#define  IRQ_MASK_FEC_LOCK       0x10
-
-#define V6_SYNC_LOCK_REG             0x28
-#define SYNC_LOCK_MASK           0x10
-
-#define V6_RS_LOCK_DET_REG           0x28
-#define  RS_LOCK_DET_MASK        0x08
-
-#define V6_INITACQ_NODETECT_REG    0x20
-#define V6_FORCE_NFFT_CPSIZE_REG   0x20
-
-#define V6_CODE_RATE_TPS_REG       0x29
-#define V6_CODE_RATE_TPS_MASK      0x07
-
-
-#define V6_CP_LOCK_DET_REG        0x28
-#define V6_CP_LOCK_DET_MASK       0x04
-
-#define V6_TPS_HIERACHY_REG        0x29
-#define V6_TPS_HIERARCHY_INFO_MASK  0x40
-
-#define V6_MODORDER_TPS_REG        0x2A
-#define V6_PARAM_CONSTELLATION_MASK   0x30
-
-#define V6_MODE_TPS_REG            0x2A
-#define V6_PARAM_FFT_MODE_MASK        0x0C
-
-
-#define V6_CP_TPS_REG             0x29
-#define V6_PARAM_GI_MASK              0x30
-
-#define V6_TPS_LOCK_REG           0x2A
-#define V6_PARAM_TPS_LOCK_MASK        0x40
-
-#define V6_FEC_PER_COUNT_REG      0x2E
-#define V6_FEC_PER_SCALE_REG      0x2B
-#define V6_FEC_PER_SCALE_MASK        0x03
-#define V6_FEC_PER_CLR_REG        0x20
-#define V6_FEC_PER_CLR_MASK          0x01
-
-#define V6_PIN_MUX_MODE_REG       0x1B
-#define V6_ENABLE_PIN_MUX            0x1E
-
-#define V6_I2S_NUM_SAMPLES_REG    0x16
-
-#define V6_MPEG_IN_CLK_INV_REG    0x17
-#define V6_MPEG_IN_CTRL_REG       0x18
-
-#define V6_INVERTED_CLK_PHASE       0x20
-#define V6_MPEG_IN_DATA_PARALLEL    0x01
-#define V6_MPEG_IN_DATA_SERIAL      0x02
-
-#define V6_INVERTED_MPEG_SYNC       0x04
-#define V6_INVERTED_MPEG_VALID      0x08
-
-#define TSIF_INPUT_PARALLEL         0
-#define TSIF_INPUT_SERIAL           1
-#define TSIF_NORMAL                 0
-
-#define V6_MPEG_INOUT_BIT_ORDER_CTRL_REG  0x19
-#define V6_MPEG_SER_MSB_FIRST                0x80
-#define MPEG_SER_MSB_FIRST_ENABLED        0x01
-
-#define V6_656_I2S_BUFF_STATUS_REG   0x2F
-#define V6_656_OVERFLOW_MASK_BIT         0x08
-#define V6_I2S_OVERFLOW_MASK_BIT         0x01
-
-#define V6_I2S_STREAM_START_BIT_REG  0x14
-#define V6_I2S_STREAM_END_BIT_REG    0x15
-#define I2S_RIGHT_JUSTIFIED     0
-#define I2S_LEFT_JUSTIFIED      1
-#define I2S_DATA_FORMAT         2
-
-#define V6_TUNER_LOOP_THRU_CONTROL_REG  0x09
-#define V6_ENABLE_LOOP_THRU               0x01
-
-#define TOTAL_NUM_IF_OUTPUT_FREQ       16
-
-#define TUNER_NORMAL_IF_SPECTRUM       0x0
-#define TUNER_INVERT_IF_SPECTRUM       0x10
-
-#define V6_TUNER_IF_SEL_REG              0x06
-#define V6_TUNER_IF_FCW_REG              0x3C
-#define V6_TUNER_IF_FCW_BYP_REG          0x3D
-#define V6_RF_LOCK_STATUS_REG            0x23
-
-#define NUM_DIG_TV_CHANNEL     1000
-
-#define V6_DIG_CLK_FREQ_SEL_REG  0x07
-#define V6_REF_SYNTH_INT_REG     0x5C
-#define V6_REF_SYNTH_REMAIN_REG  0x58
-#define V6_DIG_RFREFSELECT_REG   0x32
-#define V6_XTAL_CLK_OUT_GAIN_REG   0x31
-#define V6_TUNER_LOOP_THRU_CTRL_REG      0x09
-#define V6_DIG_XTAL_ENABLE_REG  0x06
-#define V6_DIG_XTAL_BIAS_REG  0x66
-#define V6_XTAL_CAP_REG    0x08
-
-#define V6_GPO_CTRL_REG     0x18
-#define MXL_GPO_0           0x00
-#define MXL_GPO_1           0x01
-#define V6_GPO_0_MASK       0x10
-#define V6_GPO_1_MASK       0x20
-
-#define V6_111SF_GPO_CTRL_REG     0x19
-#define MXL_111SF_GPO_1               0x00
-#define MXL_111SF_GPO_2               0x01
-#define MXL_111SF_GPO_3               0x02
-#define MXL_111SF_GPO_4               0x03
-#define MXL_111SF_GPO_5               0x04
-#define MXL_111SF_GPO_6               0x05
-#define MXL_111SF_GPO_7               0x06
-
-#define MXL_111SF_GPO_0_MASK          0x01
-#define MXL_111SF_GPO_1_MASK          0x02
-#define MXL_111SF_GPO_2_MASK          0x04
-#define MXL_111SF_GPO_3_MASK          0x08
-#define MXL_111SF_GPO_4_MASK          0x10
-#define MXL_111SF_GPO_5_MASK          0x20
-#define MXL_111SF_GPO_6_MASK          0x40
-
-#define V6_ATSC_CONFIG_REG  0x0A
-
-#define MXL_MODE_REG    0x03
-#define START_TUNE_REG  0x1C
-
-#define V6_IDAC_HYSTERESIS_REG    0x0B
-#define V6_IDAC_SETTINGS_REG      0x0C
-#define IDAC_MANUAL_CONTROL             1
-#define IDAC_CURRENT_SINKING_ENABLE     1
-#define IDAC_MANUAL_CONTROL_BIT_MASK      0x80
-#define IDAC_CURRENT_SINKING_BIT_MASK     0x40
-
-#define V8_SPI_MODE_REG  0xE9
-
-#define V6_DIG_RF_PWR_LSB_REG  0x46
-#define V6_DIG_RF_PWR_MSB_REG  0x47
-
-#endif /* _DVB_USB_MXL111SF_REG_H_ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c
deleted file mode 100644
index 74da5bb1..0000000
--- a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- *  mxl111sf-tuner.c - driver for the MaxLinear MXL111SF CMOS tuner
- *
- *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "mxl111sf-tuner.h"
-#include "mxl111sf-phy.h"
-#include "mxl111sf-reg.h"
-
-/* debug */
-static int mxl111sf_tuner_debug;
-module_param_named(debug, mxl111sf_tuner_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
-
-#define mxl_dbg(fmt, arg...) \
-	if (mxl111sf_tuner_debug) \
-		mxl_printk(KERN_DEBUG, fmt, ##arg)
-
-/* ------------------------------------------------------------------------ */
-
-struct mxl111sf_tuner_state {
-	struct mxl111sf_state *mxl_state;
-
-	struct mxl111sf_tuner_config *cfg;
-
-	enum mxl_if_freq if_freq;
-
-	u32 frequency;
-	u32 bandwidth;
-};
-
-static int mxl111sf_tuner_read_reg(struct mxl111sf_tuner_state *state,
-				   u8 addr, u8 *data)
-{
-	return (state->cfg->read_reg) ?
-		state->cfg->read_reg(state->mxl_state, addr, data) :
-		-EINVAL;
-}
-
-static int mxl111sf_tuner_write_reg(struct mxl111sf_tuner_state *state,
-				    u8 addr, u8 data)
-{
-	return (state->cfg->write_reg) ?
-		state->cfg->write_reg(state->mxl_state, addr, data) :
-		-EINVAL;
-}
-
-static int mxl111sf_tuner_program_regs(struct mxl111sf_tuner_state *state,
-			       struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
-{
-	return (state->cfg->program_regs) ?
-		state->cfg->program_regs(state->mxl_state, ctrl_reg_info) :
-		-EINVAL;
-}
-
-static int mxl1x1sf_tuner_top_master_ctrl(struct mxl111sf_tuner_state *state,
-					  int onoff)
-{
-	return (state->cfg->top_master_ctrl) ?
-		state->cfg->top_master_ctrl(state->mxl_state, onoff) :
-		-EINVAL;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static struct mxl111sf_reg_ctrl_info mxl_phy_tune_rf[] = {
-	{0x1d, 0x7f, 0x00}, /* channel bandwidth section 1/2/3,
-			       DIG_MODEINDEX, _A, _CSF, */
-	{0x1e, 0xff, 0x00}, /* channel frequency (lo and fractional) */
-	{0x1f, 0xff, 0x00}, /* channel frequency (hi for integer portion) */
-	{0,    0,    0}
-};
-
-/* ------------------------------------------------------------------------ */
-
-static struct mxl111sf_reg_ctrl_info *mxl111sf_calc_phy_tune_regs(u32 freq,
-								  u8 bw)
-{
-	u8 filt_bw;
-
-	/* set channel bandwidth */
-	switch (bw) {
-	case 0: /* ATSC */
-		filt_bw = 25;
-		break;
-	case 1: /* QAM */
-		filt_bw = 69;
-		break;
-	case 6:
-		filt_bw = 21;
-		break;
-	case 7:
-		filt_bw = 42;
-		break;
-	case 8:
-		filt_bw = 63;
-		break;
-	default:
-		err("%s: invalid bandwidth setting!", __func__);
-		return NULL;
-	}
-
-	/* calculate RF channel */
-	freq /= 1000000;
-
-	freq *= 64;
-#if 0
-	/* do round */
-	freq += 0.5;
-#endif
-	/* set bandwidth */
-	mxl_phy_tune_rf[0].data = filt_bw;
-
-	/* set RF */
-	mxl_phy_tune_rf[1].data = (freq & 0xff);
-	mxl_phy_tune_rf[2].data = (freq >> 8) & 0xff;
-
-	/* start tune */
-	return mxl_phy_tune_rf;
-}
-
-static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state)
-{
-	int ret;
-	u8 ctrl;
-#if 0
-	u16 iffcw;
-	u32 if_freq;
-#endif
-	mxl_dbg("(IF polarity = %d, IF freq = 0x%02x)",
-		state->cfg->invert_spectrum, state->cfg->if_freq);
-
-	/* set IF polarity */
-	ctrl = state->cfg->invert_spectrum;
-
-	ctrl |= state->cfg->if_freq;
-
-	ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_SEL_REG, ctrl);
-	if (mxl_fail(ret))
-		goto fail;
-
-#if 0
-	if_freq /= 1000000;
-
-	/* do round */
-	if_freq += 0.5;
-
-	if (MXL_IF_LO == state->cfg->if_freq) {
-		ctrl = 0x08;
-		iffcw = (u16)(if_freq / (108 * 4096));
-	} else if (MXL_IF_HI == state->cfg->if_freq) {
-		ctrl = 0x08;
-		iffcw = (u16)(if_freq / (216 * 4096));
-	} else {
-		ctrl = 0;
-		iffcw = 0;
-	}
-
-	ctrl |= (iffcw >> 8);
-#endif
-	ret = mxl111sf_tuner_read_reg(state, V6_TUNER_IF_FCW_BYP_REG, &ctrl);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ctrl &= 0xf0;
-	ctrl |= 0x90;
-
-	ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_BYP_REG, ctrl);
-	if (mxl_fail(ret))
-		goto fail;
-
-#if 0
-	ctrl = iffcw & 0x00ff;
-#endif
-	ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl);
-	if (mxl_fail(ret))
-		goto fail;
-
-	state->if_freq = state->cfg->if_freq;
-fail:
-	return ret;
-}
-
-static int mxl1x1sf_tune_rf(struct dvb_frontend *fe, u32 freq, u8 bw)
-{
-	struct mxl111sf_tuner_state *state = fe->tuner_priv;
-	static struct mxl111sf_reg_ctrl_info *reg_ctrl_array;
-	int ret;
-	u8 mxl_mode;
-
-	mxl_dbg("(freq = %d, bw = 0x%x)", freq, bw);
-
-	/* stop tune */
-	ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 0);
-	if (mxl_fail(ret))
-		goto fail;
-
-	/* check device mode */
-	ret = mxl111sf_tuner_read_reg(state, MXL_MODE_REG, &mxl_mode);
-	if (mxl_fail(ret))
-		goto fail;
-
-	/* Fill out registers for channel tune */
-	reg_ctrl_array = mxl111sf_calc_phy_tune_regs(freq, bw);
-	if (!reg_ctrl_array)
-		return -EINVAL;
-
-	ret = mxl111sf_tuner_program_regs(state, reg_ctrl_array);
-	if (mxl_fail(ret))
-		goto fail;
-
-	if ((mxl_mode & MXL_DEV_MODE_MASK) == MXL_TUNER_MODE) {
-		/* IF tuner mode only */
-		mxl1x1sf_tuner_top_master_ctrl(state, 0);
-		mxl1x1sf_tuner_top_master_ctrl(state, 1);
-		mxl1x1sf_tuner_set_if_output_freq(state);
-	}
-
-	ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 1);
-	if (mxl_fail(ret))
-		goto fail;
-
-	if (state->cfg->ant_hunt)
-		state->cfg->ant_hunt(fe);
-fail:
-	return ret;
-}
-
-static int mxl1x1sf_tuner_get_lock_status(struct mxl111sf_tuner_state *state,
-					  int *rf_synth_lock,
-					  int *ref_synth_lock)
-{
-	int ret;
-	u8 data;
-
-	*rf_synth_lock = 0;
-	*ref_synth_lock = 0;
-
-	ret = mxl111sf_tuner_read_reg(state, V6_RF_LOCK_STATUS_REG, &data);
-	if (mxl_fail(ret))
-		goto fail;
-
-	*ref_synth_lock = ((data & 0x03) == 0x03) ? 1 : 0;
-	*rf_synth_lock  = ((data & 0x0c) == 0x0c) ? 1 : 0;
-fail:
-	return ret;
-}
-
-#if 0
-static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state,
-					 int onoff)
-{
-	return mxl111sf_tuner_write_reg(state, V6_TUNER_LOOP_THRU_CTRL_REG,
-					onoff ? 1 : 0);
-}
-#endif
-
-/* ------------------------------------------------------------------------ */
-
-static int mxl111sf_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 delsys  = c->delivery_system;
-	struct mxl111sf_tuner_state *state = fe->tuner_priv;
-	int ret;
-	u8 bw;
-
-	mxl_dbg("()");
-
-	switch (delsys) {
-	case SYS_ATSC:
-	case SYS_ATSCMH:
-		bw = 0; /* ATSC */
-		break;
-	case SYS_DVBC_ANNEX_B:
-		bw = 1; /* US CABLE */
-		break;
-	case SYS_DVBT:
-		switch (c->bandwidth_hz) {
-		case 6000000:
-			bw = 6;
-			break;
-		case 7000000:
-			bw = 7;
-			break;
-		case 8000000:
-			bw = 8;
-			break;
-		default:
-			err("%s: bandwidth not set!", __func__);
-			return -EINVAL;
-		}
-		break;
-	default:
-		err("%s: modulation type not supported!", __func__);
-		return -EINVAL;
-	}
-	ret = mxl1x1sf_tune_rf(fe, c->frequency, bw);
-	if (mxl_fail(ret))
-		goto fail;
-
-	state->frequency = c->frequency;
-	state->bandwidth = c->bandwidth_hz;
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-#if 0
-static int mxl111sf_tuner_init(struct dvb_frontend *fe)
-{
-	struct mxl111sf_tuner_state *state = fe->tuner_priv;
-	int ret;
-
-	/* wake from standby handled by usb driver */
-
-	return ret;
-}
-
-static int mxl111sf_tuner_sleep(struct dvb_frontend *fe)
-{
-	struct mxl111sf_tuner_state *state = fe->tuner_priv;
-	int ret;
-
-	/* enter standby mode handled by usb driver */
-
-	return ret;
-}
-#endif
-
-/* ------------------------------------------------------------------------ */
-
-static int mxl111sf_tuner_get_status(struct dvb_frontend *fe, u32 *status)
-{
-	struct mxl111sf_tuner_state *state = fe->tuner_priv;
-	int rf_locked, ref_locked, ret;
-
-	*status = 0;
-
-	ret = mxl1x1sf_tuner_get_lock_status(state, &rf_locked, &ref_locked);
-	if (mxl_fail(ret))
-		goto fail;
-	mxl_info("%s%s", rf_locked ? "rf locked " : "",
-		 ref_locked ? "ref locked" : "");
-
-	if ((rf_locked) || (ref_locked))
-		*status |= TUNER_STATUS_LOCKED;
-fail:
-	return ret;
-}
-
-static int mxl111sf_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct mxl111sf_tuner_state *state = fe->tuner_priv;
-	u8 val1, val2;
-	int ret;
-
-	*strength = 0;
-
-	ret = mxl111sf_tuner_write_reg(state, 0x00, 0x02);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_LSB_REG, &val1);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_MSB_REG, &val2);
-	if (mxl_fail(ret))
-		goto fail;
-
-	*strength = val1 | ((val2 & 0x07) << 8);
-fail:
-	ret = mxl111sf_tuner_write_reg(state, 0x00, 0x00);
-	mxl_fail(ret);
-
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int mxl111sf_tuner_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct mxl111sf_tuner_state *state = fe->tuner_priv;
-	*frequency = state->frequency;
-	return 0;
-}
-
-static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	struct mxl111sf_tuner_state *state = fe->tuner_priv;
-	*bandwidth = state->bandwidth;
-	return 0;
-}
-
-static int mxl111sf_tuner_get_if_frequency(struct dvb_frontend *fe,
-					   u32 *frequency)
-{
-	struct mxl111sf_tuner_state *state = fe->tuner_priv;
-
-	*frequency = 0;
-
-	switch (state->if_freq) {
-	case MXL_IF_4_0:   /* 4.0   MHz */
-		*frequency = 4000000;
-		break;
-	case MXL_IF_4_5:   /* 4.5   MHz */
-		*frequency = 4500000;
-		break;
-	case MXL_IF_4_57:  /* 4.57  MHz */
-		*frequency = 4570000;
-		break;
-	case MXL_IF_5_0:   /* 5.0   MHz */
-		*frequency = 5000000;
-		break;
-	case MXL_IF_5_38:  /* 5.38  MHz */
-		*frequency = 5380000;
-		break;
-	case MXL_IF_6_0:   /* 6.0   MHz */
-		*frequency = 6000000;
-		break;
-	case MXL_IF_6_28:  /* 6.28  MHz */
-		*frequency = 6280000;
-		break;
-	case MXL_IF_7_2:   /* 7.2   MHz */
-		*frequency = 7200000;
-		break;
-	case MXL_IF_35_25: /* 35.25 MHz */
-		*frequency = 35250000;
-		break;
-	case MXL_IF_36:    /* 36    MHz */
-		*frequency = 36000000;
-		break;
-	case MXL_IF_36_15: /* 36.15 MHz */
-		*frequency = 36150000;
-		break;
-	case MXL_IF_44:    /* 44    MHz */
-		*frequency = 44000000;
-		break;
-	}
-	return 0;
-}
-
-static int mxl111sf_tuner_release(struct dvb_frontend *fe)
-{
-	struct mxl111sf_tuner_state *state = fe->tuner_priv;
-	mxl_dbg("()");
-	kfree(state);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = {
-	.info = {
-		.name = "MaxLinear MxL111SF",
-#if 0
-		.frequency_min  = ,
-		.frequency_max  = ,
-		.frequency_step = ,
-#endif
-	},
-#if 0
-	.init              = mxl111sf_tuner_init,
-	.sleep             = mxl111sf_tuner_sleep,
-#endif
-	.set_params        = mxl111sf_tuner_set_params,
-	.get_status        = mxl111sf_tuner_get_status,
-	.get_rf_strength   = mxl111sf_get_rf_strength,
-	.get_frequency     = mxl111sf_tuner_get_frequency,
-	.get_bandwidth     = mxl111sf_tuner_get_bandwidth,
-	.get_if_frequency  = mxl111sf_tuner_get_if_frequency,
-	.release           = mxl111sf_tuner_release,
-};
-
-struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
-					   struct mxl111sf_state *mxl_state,
-					   struct mxl111sf_tuner_config *cfg)
-{
-	struct mxl111sf_tuner_state *state = NULL;
-
-	mxl_dbg("()");
-
-	state = kzalloc(sizeof(struct mxl111sf_tuner_state), GFP_KERNEL);
-	if (state == NULL)
-		return NULL;
-
-	state->mxl_state = mxl_state;
-	state->cfg = cfg;
-
-	memcpy(&fe->ops.tuner_ops, &mxl111sf_tuner_tuner_ops,
-	       sizeof(struct dvb_tuner_ops));
-
-	fe->tuner_priv = state;
-	return fe;
-}
-EXPORT_SYMBOL_GPL(mxl111sf_tuner_attach);
-
-MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver");
-MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.1");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.h b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.h
deleted file mode 100644
index ff33396..0000000
--- a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- *  mxl111sf-tuner.h - driver for the MaxLinear MXL111SF CMOS tuner
- *
- *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __MXL111SF_TUNER_H__
-#define __MXL111SF_TUNER_H__
-
-#include "dvb_frontend.h"
-
-#include "mxl111sf.h"
-
-enum mxl_if_freq {
-#if 0
-	MXL_IF_LO    = 0x00, /* other IF < 9MHz */
-#endif
-	MXL_IF_4_0   = 0x01, /* 4.0   MHz */
-	MXL_IF_4_5   = 0x02, /* 4.5   MHz */
-	MXL_IF_4_57  = 0x03, /* 4.57  MHz */
-	MXL_IF_5_0   = 0x04, /* 5.0   MHz */
-	MXL_IF_5_38  = 0x05, /* 5.38  MHz */
-	MXL_IF_6_0   = 0x06, /* 6.0   MHz */
-	MXL_IF_6_28  = 0x07, /* 6.28  MHz */
-	MXL_IF_7_2   = 0x08, /* 7.2   MHz */
-	MXL_IF_35_25 = 0x09, /* 35.25 MHz */
-	MXL_IF_36    = 0x0a, /* 36    MHz */
-	MXL_IF_36_15 = 0x0b, /* 36.15 MHz */
-	MXL_IF_44    = 0x0c, /* 44    MHz */
-#if 0
-	MXL_IF_HI    = 0x0f, /* other IF > 35 MHz and < 45 MHz */
-#endif
-};
-
-struct mxl111sf_tuner_config {
-	enum mxl_if_freq if_freq;
-	unsigned int invert_spectrum:1;
-
-	int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data);
-	int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data);
-	int (*program_regs)(struct mxl111sf_state *state,
-			    struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
-	int (*top_master_ctrl)(struct mxl111sf_state *state, int onoff);
-	int (*ant_hunt)(struct dvb_frontend *fe);
-};
-
-/* ------------------------------------------------------------------------ */
-
-#if defined(CONFIG_DVB_USB_MXL111SF) || \
-	(defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE))
-extern
-struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
-					   struct mxl111sf_state *mxl_state,
-					   struct mxl111sf_tuner_config *cfg);
-#else
-static inline
-struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
-					   struct mxl111sf_state *mxl_state
-					   struct mxl111sf_tuner_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* __MXL111SF_TUNER_H__ */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
-
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c
deleted file mode 100644
index cd84279..0000000
--- a/drivers/media/dvb/dvb-usb/mxl111sf.c
+++ /dev/null
@@ -1,1835 +0,0 @@
-/*
- * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com)
- *
- *   This program is free software; you can redistribute it and/or modify it
- *   under the terms of the GNU General Public License as published by the Free
- *   Software Foundation, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-
-#include <linux/vmalloc.h>
-#include <linux/i2c.h>
-
-#include "mxl111sf.h"
-#include "mxl111sf-reg.h"
-#include "mxl111sf-phy.h"
-#include "mxl111sf-i2c.h"
-#include "mxl111sf-gpio.h"
-
-#include "mxl111sf-demod.h"
-#include "mxl111sf-tuner.h"
-
-#include "lgdt3305.h"
-#include "lg2160.h"
-
-int dvb_usb_mxl111sf_debug;
-module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level "
-		 "(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able)).");
-
-int dvb_usb_mxl111sf_isoc;
-module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644);
-MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc).");
-
-int dvb_usb_mxl111sf_spi;
-module_param_named(spi, dvb_usb_mxl111sf_spi, int, 0644);
-MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi).");
-
-#define ANT_PATH_AUTO 0
-#define ANT_PATH_EXTERNAL 1
-#define ANT_PATH_INTERNAL 2
-
-int dvb_usb_mxl111sf_rfswitch =
-#if 0
-		ANT_PATH_AUTO;
-#else
-		ANT_PATH_EXTERNAL;
-#endif
-
-module_param_named(rfswitch, dvb_usb_mxl111sf_rfswitch, int, 0644);
-MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int).");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define deb_info(args...)   dprintk(dvb_usb_mxl111sf_debug, 0x13, args)
-#define deb_reg(args...)    dprintk(dvb_usb_mxl111sf_debug, 0x08, args)
-#define deb_adv(args...)    dprintk(dvb_usb_mxl111sf_debug, MXL_ADV_DBG, args)
-
-int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
-		      u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
-{
-	int wo = (rbuf == NULL || rlen == 0); /* write-only */
-	int ret;
-	u8 sndbuf[1+wlen];
-
-	deb_adv("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen);
-
-	memset(sndbuf, 0, 1+wlen);
-
-	sndbuf[0] = cmd;
-	memcpy(&sndbuf[1], wbuf, wlen);
-
-	ret = (wo) ? dvb_usb_generic_write(d, sndbuf, 1+wlen) :
-		dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
-	mxl_fail(ret);
-
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-#define MXL_CMD_REG_READ	0xaa
-#define MXL_CMD_REG_WRITE	0x55
-
-int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data)
-{
-	u8 buf[2];
-	int ret;
-
-	ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_READ, &addr, 1, buf, 2);
-	if (mxl_fail(ret)) {
-		mxl_debug("error reading reg: 0x%02x", addr);
-		goto fail;
-	}
-
-	if (buf[0] == addr)
-		*data = buf[1];
-	else {
-		err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x",
-		    addr, buf[0], buf[1]);
-		ret = -EINVAL;
-	}
-
-	deb_reg("R: (0x%02x, 0x%02x)\n", addr, *data);
-fail:
-	return ret;
-}
-
-int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data)
-{
-	u8 buf[] = { addr, data };
-	int ret;
-
-	deb_reg("W: (0x%02x, 0x%02x)\n", addr, data);
-
-	ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0);
-	if (mxl_fail(ret))
-		err("error writing reg: 0x%02x, val: 0x%02x", addr, data);
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
-				   u8 addr, u8 mask, u8 data)
-{
-	int ret;
-	u8 val;
-
-	if (mask != 0xff) {
-		ret = mxl111sf_read_reg(state, addr, &val);
-#if 1
-		/* dont know why this usually errors out on the first try */
-		if (mxl_fail(ret))
-			err("error writing addr: 0x%02x, mask: 0x%02x, "
-			    "data: 0x%02x, retrying...", addr, mask, data);
-
-		ret = mxl111sf_read_reg(state, addr, &val);
-#endif
-		if (mxl_fail(ret))
-			goto fail;
-	}
-	val &= ~mask;
-	val |= data;
-
-	ret = mxl111sf_write_reg(state, addr, val);
-	mxl_fail(ret);
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state,
-			       struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
-{
-	int i, ret = 0;
-
-	for (i = 0;  ctrl_reg_info[i].addr |
-		     ctrl_reg_info[i].mask |
-		     ctrl_reg_info[i].data;  i++) {
-
-		ret = mxl111sf_write_reg_mask(state,
-					      ctrl_reg_info[i].addr,
-					      ctrl_reg_info[i].mask,
-					      ctrl_reg_info[i].data);
-		if (mxl_fail(ret)) {
-			err("failed on reg #%d (0x%02x)", i,
-			    ctrl_reg_info[i].addr);
-			break;
-		}
-	}
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int mxl1x1sf_get_chip_info(struct mxl111sf_state *state)
-{
-	int ret;
-	u8 id, ver;
-	char *mxl_chip, *mxl_rev;
-
-	if ((state->chip_id) && (state->chip_ver))
-		return 0;
-
-	ret = mxl111sf_read_reg(state, CHIP_ID_REG, &id);
-	if (mxl_fail(ret))
-		goto fail;
-	state->chip_id = id;
-
-	ret = mxl111sf_read_reg(state, TOP_CHIP_REV_ID_REG, &ver);
-	if (mxl_fail(ret))
-		goto fail;
-	state->chip_ver = ver;
-
-	switch (id) {
-	case 0x61:
-		mxl_chip = "MxL101SF";
-		break;
-	case 0x63:
-		mxl_chip = "MxL111SF";
-		break;
-	default:
-		mxl_chip = "UNKNOWN MxL1X1";
-		break;
-	}
-	switch (ver) {
-	case 0x36:
-		state->chip_rev = MXL111SF_V6;
-		mxl_rev = "v6";
-		break;
-	case 0x08:
-		state->chip_rev = MXL111SF_V8_100;
-		mxl_rev = "v8_100";
-		break;
-	case 0x18:
-		state->chip_rev = MXL111SF_V8_200;
-		mxl_rev = "v8_200";
-		break;
-	default:
-		state->chip_rev = 0;
-		mxl_rev = "UNKNOWN REVISION";
-		break;
-	}
-	info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver);
-fail:
-	return ret;
-}
-
-#define get_chip_info(state)						\
-({									\
-	int ___ret;							\
-	___ret = mxl1x1sf_get_chip_info(state);				\
-	if (mxl_fail(___ret)) {						\
-		mxl_debug("failed to get chip info"			\
-			  " on first probe attempt");			\
-		___ret = mxl1x1sf_get_chip_info(state);			\
-		if (mxl_fail(___ret))					\
-			err("failed to get chip info during probe");	\
-		else							\
-			mxl_debug("probe needed a retry "		\
-				  "in order to succeed.");		\
-	}								\
-	___ret;								\
-})
-
-/* ------------------------------------------------------------------------ */
-
-static int mxl111sf_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	/* power control depends on which adapter is being woken:
-	 * save this for init, instead, via mxl111sf_adap_fe_init */
-	return 0;
-}
-
-static int mxl111sf_adap_fe_init(struct dvb_frontend *fe)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct dvb_usb_device *d = adap->dev;
-	struct mxl111sf_state *state = d->priv;
-	struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe->id].priv;
-
-	int err;
-
-	/* exit if we didnt initialize the driver yet */
-	if (!state->chip_id) {
-		mxl_debug("driver not yet initialized, exit.");
-		goto fail;
-	}
-
-	deb_info("%s()\n", __func__);
-
-	mutex_lock(&state->fe_lock);
-
-	state->alt_mode = adap_state->alt_mode;
-
-	if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
-		err("set interface failed");
-
-	err = mxl1x1sf_soft_reset(state);
-	mxl_fail(err);
-	err = mxl111sf_init_tuner_demod(state);
-	mxl_fail(err);
-	err = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
-
-	mxl_fail(err);
-	mxl111sf_enable_usb_output(state);
-	mxl_fail(err);
-	mxl1x1sf_top_master_ctrl(state, 1);
-	mxl_fail(err);
-
-	if ((MXL111SF_GPIO_MOD_DVBT != adap_state->gpio_mode) &&
-	    (state->chip_rev > MXL111SF_V6)) {
-		mxl111sf_config_pin_mux_modes(state,
-					      PIN_MUX_TS_SPI_IN_MODE_1);
-		mxl_fail(err);
-	}
-	err = mxl111sf_init_port_expander(state);
-	if (!mxl_fail(err)) {
-		state->gpio_mode = adap_state->gpio_mode;
-		err = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
-		mxl_fail(err);
-#if 0
-		err = fe->ops.init(fe);
-#endif
-		msleep(100); /* add short delay after enabling
-			      * the demod before touching it */
-	}
-
-	return (adap_state->fe_init) ? adap_state->fe_init(fe) : 0;
-fail:
-	return -ENODEV;
-}
-
-static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct dvb_usb_device *d = adap->dev;
-	struct mxl111sf_state *state = d->priv;
-	struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe->id].priv;
-	int err;
-
-	/* exit if we didnt initialize the driver yet */
-	if (!state->chip_id) {
-		mxl_debug("driver not yet initialized, exit.");
-		goto fail;
-	}
-
-	deb_info("%s()\n", __func__);
-
-	err = (adap_state->fe_sleep) ? adap_state->fe_sleep(fe) : 0;
-
-	mutex_unlock(&state->fe_lock);
-
-	return err;
-fail:
-	return -ENODEV;
-}
-
-
-static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	struct dvb_usb_device *d = adap->dev;
-	struct mxl111sf_state *state = d->priv;
-	struct mxl111sf_adap_state *adap_state = adap->fe_adap[adap->active_fe].priv;
-	int ret = 0;
-
-	deb_info("%s(%d)\n", __func__, onoff);
-
-	if (onoff) {
-		ret = mxl111sf_enable_usb_output(state);
-		mxl_fail(ret);
-		ret = mxl111sf_config_mpeg_in(state, 1, 1,
-					      adap_state->ep6_clockphase,
-					      0, 0);
-		mxl_fail(ret);
-#if 0
-	} else {
-		ret = mxl111sf_disable_656_port(state);
-		mxl_fail(ret);
-#endif
-	}
-
-	return ret;
-}
-
-static int mxl111sf_ep5_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	struct dvb_usb_device *d = adap->dev;
-	struct mxl111sf_state *state = d->priv;
-	int ret = 0;
-
-	deb_info("%s(%d)\n", __func__, onoff);
-
-	if (onoff) {
-		ret = mxl111sf_enable_usb_output(state);
-		mxl_fail(ret);
-
-		ret = mxl111sf_init_i2s_port(state, 200);
-		mxl_fail(ret);
-		ret = mxl111sf_config_i2s(state, 0, 15);
-		mxl_fail(ret);
-	} else {
-		ret = mxl111sf_disable_i2s_port(state);
-		mxl_fail(ret);
-	}
-	if (state->chip_rev > MXL111SF_V6)
-		ret = mxl111sf_config_spi(state, onoff);
-	mxl_fail(ret);
-
-	return ret;
-}
-
-static int mxl111sf_ep4_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	struct dvb_usb_device *d = adap->dev;
-	struct mxl111sf_state *state = d->priv;
-	int ret = 0;
-
-	deb_info("%s(%d)\n", __func__, onoff);
-
-	if (onoff) {
-		ret = mxl111sf_enable_usb_output(state);
-		mxl_fail(ret);
-	}
-
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static struct lgdt3305_config hauppauge_lgdt3305_config = {
-	.i2c_addr           = 0xb2 >> 1,
-	.mpeg_mode          = LGDT3305_MPEG_SERIAL,
-	.tpclk_edge         = LGDT3305_TPCLK_RISING_EDGE,
-	.tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
-	.deny_i2c_rptr      = 1,
-	.spectral_inversion = 0,
-	.qam_if_khz         = 6000,
-	.vsb_if_khz         = 6000,
-};
-
-static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct dvb_usb_device *d = adap->dev;
-	struct mxl111sf_state *state = d->priv;
-	int fe_id = adap->num_frontends_initialized;
-	struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
-	int ret;
-
-	deb_adv("%s()\n", __func__);
-
-	/* save a pointer to the dvb_usb_device in device state */
-	state->d = d;
-	adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
-	state->alt_mode = adap_state->alt_mode;
-
-	if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
-		err("set interface failed");
-
-	state->gpio_mode = MXL111SF_GPIO_MOD_ATSC;
-	adap_state->gpio_mode = state->gpio_mode;
-	adap_state->device_mode = MXL_TUNER_MODE;
-	adap_state->ep6_clockphase = 1;
-
-	ret = mxl1x1sf_soft_reset(state);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_init_tuner_demod(state);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_enable_usb_output(state);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl1x1sf_top_master_ctrl(state, 1);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_init_port_expander(state);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
-	if (mxl_fail(ret))
-		goto fail;
-
-	adap->fe_adap[fe_id].fe = dvb_attach(lgdt3305_attach,
-				 &hauppauge_lgdt3305_config,
-				 &adap->dev->i2c_adap);
-	if (adap->fe_adap[fe_id].fe) {
-		adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
-		adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
-		adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
-		adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
-		return 0;
-	}
-	ret = -EIO;
-fail:
-	return ret;
-}
-
-static struct lg2160_config hauppauge_lg2160_config = {
-	.lg_chip            = LG2160,
-	.i2c_addr           = 0x1c >> 1,
-	.deny_i2c_rptr      = 1,
-	.spectral_inversion = 0,
-	.if_khz             = 6000,
-};
-
-static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct dvb_usb_device *d = adap->dev;
-	struct mxl111sf_state *state = d->priv;
-	int fe_id = adap->num_frontends_initialized;
-	struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
-	int ret;
-
-	deb_adv("%s()\n", __func__);
-
-	/* save a pointer to the dvb_usb_device in device state */
-	state->d = d;
-	adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
-	state->alt_mode = adap_state->alt_mode;
-
-	if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
-		err("set interface failed");
-
-	state->gpio_mode = MXL111SF_GPIO_MOD_MH;
-	adap_state->gpio_mode = state->gpio_mode;
-	adap_state->device_mode = MXL_TUNER_MODE;
-	adap_state->ep6_clockphase = 1;
-
-	ret = mxl1x1sf_soft_reset(state);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_init_tuner_demod(state);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_enable_usb_output(state);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl1x1sf_top_master_ctrl(state, 1);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_init_port_expander(state);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = get_chip_info(state);
-	if (mxl_fail(ret))
-		goto fail;
-
-	adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach,
-			      &hauppauge_lg2160_config,
-			      &adap->dev->i2c_adap);
-	if (adap->fe_adap[fe_id].fe) {
-		adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
-		adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
-		adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
-		adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
-		return 0;
-	}
-	ret = -EIO;
-fail:
-	return ret;
-}
-
-static struct lg2160_config hauppauge_lg2161_1019_config = {
-	.lg_chip            = LG2161_1019,
-	.i2c_addr           = 0x1c >> 1,
-	.deny_i2c_rptr      = 1,
-	.spectral_inversion = 0,
-	.if_khz             = 6000,
-	.output_if          = 2, /* LG2161_OIF_SPI_MAS */
-};
-
-static struct lg2160_config hauppauge_lg2161_1040_config = {
-	.lg_chip            = LG2161_1040,
-	.i2c_addr           = 0x1c >> 1,
-	.deny_i2c_rptr      = 1,
-	.spectral_inversion = 0,
-	.if_khz             = 6000,
-	.output_if          = 4, /* LG2161_OIF_SPI_MAS */
-};
-
-static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct dvb_usb_device *d = adap->dev;
-	struct mxl111sf_state *state = d->priv;
-	int fe_id = adap->num_frontends_initialized;
-	struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
-	int ret;
-
-	deb_adv("%s()\n", __func__);
-
-	/* save a pointer to the dvb_usb_device in device state */
-	state->d = d;
-	adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
-	state->alt_mode = adap_state->alt_mode;
-
-	if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
-		err("set interface failed");
-
-	state->gpio_mode = MXL111SF_GPIO_MOD_MH;
-	adap_state->gpio_mode = state->gpio_mode;
-	adap_state->device_mode = MXL_TUNER_MODE;
-	adap_state->ep6_clockphase = 1;
-
-	ret = mxl1x1sf_soft_reset(state);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_init_tuner_demod(state);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_enable_usb_output(state);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl1x1sf_top_master_ctrl(state, 1);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_init_port_expander(state);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = get_chip_info(state);
-	if (mxl_fail(ret))
-		goto fail;
-
-	adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach,
-			      (MXL111SF_V8_200 == state->chip_rev) ?
-			      &hauppauge_lg2161_1040_config :
-			      &hauppauge_lg2161_1019_config,
-			      &adap->dev->i2c_adap);
-	if (adap->fe_adap[fe_id].fe) {
-		adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
-		adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
-		adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
-		adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
-		return 0;
-	}
-	ret = -EIO;
-fail:
-	return ret;
-}
-
-static struct lg2160_config hauppauge_lg2161_1019_ep6_config = {
-	.lg_chip            = LG2161_1019,
-	.i2c_addr           = 0x1c >> 1,
-	.deny_i2c_rptr      = 1,
-	.spectral_inversion = 0,
-	.if_khz             = 6000,
-	.output_if          = 1, /* LG2161_OIF_SERIAL_TS */
-};
-
-static struct lg2160_config hauppauge_lg2161_1040_ep6_config = {
-	.lg_chip            = LG2161_1040,
-	.i2c_addr           = 0x1c >> 1,
-	.deny_i2c_rptr      = 1,
-	.spectral_inversion = 0,
-	.if_khz             = 6000,
-	.output_if          = 7, /* LG2161_OIF_SERIAL_TS */
-};
-
-static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct dvb_usb_device *d = adap->dev;
-	struct mxl111sf_state *state = d->priv;
-	int fe_id = adap->num_frontends_initialized;
-	struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
-	int ret;
-
-	deb_adv("%s()\n", __func__);
-
-	/* save a pointer to the dvb_usb_device in device state */
-	state->d = d;
-	adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
-	state->alt_mode = adap_state->alt_mode;
-
-	if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
-		err("set interface failed");
-
-	state->gpio_mode = MXL111SF_GPIO_MOD_MH;
-	adap_state->gpio_mode = state->gpio_mode;
-	adap_state->device_mode = MXL_TUNER_MODE;
-	adap_state->ep6_clockphase = 0;
-
-	ret = mxl1x1sf_soft_reset(state);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_init_tuner_demod(state);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_enable_usb_output(state);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl1x1sf_top_master_ctrl(state, 1);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_init_port_expander(state);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = get_chip_info(state);
-	if (mxl_fail(ret))
-		goto fail;
-
-	adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach,
-			      (MXL111SF_V8_200 == state->chip_rev) ?
-			      &hauppauge_lg2161_1040_ep6_config :
-			      &hauppauge_lg2161_1019_ep6_config,
-			      &adap->dev->i2c_adap);
-	if (adap->fe_adap[fe_id].fe) {
-		adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
-		adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
-		adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
-		adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
-		return 0;
-	}
-	ret = -EIO;
-fail:
-	return ret;
-}
-
-static struct mxl111sf_demod_config mxl_demod_config = {
-	.read_reg        = mxl111sf_read_reg,
-	.write_reg       = mxl111sf_write_reg,
-	.program_regs    = mxl111sf_ctrl_program_regs,
-};
-
-static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap)
-{
-	struct dvb_usb_device *d = adap->dev;
-	struct mxl111sf_state *state = d->priv;
-	int fe_id = adap->num_frontends_initialized;
-	struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
-	int ret;
-
-	deb_adv("%s()\n", __func__);
-
-	/* save a pointer to the dvb_usb_device in device state */
-	state->d = d;
-	adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 1 : 2;
-	state->alt_mode = adap_state->alt_mode;
-
-	if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
-		err("set interface failed");
-
-	state->gpio_mode = MXL111SF_GPIO_MOD_DVBT;
-	adap_state->gpio_mode = state->gpio_mode;
-	adap_state->device_mode = MXL_SOC_MODE;
-	adap_state->ep6_clockphase = 1;
-
-	ret = mxl1x1sf_soft_reset(state);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl111sf_init_tuner_demod(state);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
-	if (mxl_fail(ret))
-		goto fail;
-
-	ret = mxl111sf_enable_usb_output(state);
-	if (mxl_fail(ret))
-		goto fail;
-	ret = mxl1x1sf_top_master_ctrl(state, 1);
-	if (mxl_fail(ret))
-		goto fail;
-
-	/* dont care if this fails */
-	mxl111sf_init_port_expander(state);
-
-	adap->fe_adap[fe_id].fe = dvb_attach(mxl111sf_demod_attach, state,
-			      &mxl_demod_config);
-	if (adap->fe_adap[fe_id].fe) {
-		adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
-		adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
-		adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
-		adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
-		return 0;
-	}
-	ret = -EIO;
-fail:
-	return ret;
-}
-
-static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state,
-					int antpath)
-{
-	return mxl111sf_idac_config(state, 1, 1,
-				    (antpath == ANT_PATH_INTERNAL) ?
-				    0x3f : 0x00, 0);
-}
-
-#define DbgAntHunt(x, pwr0, pwr1, pwr2, pwr3) \
-	err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \
-	    __func__, __LINE__, \
-	    (ANT_PATH_EXTERNAL == x) ? "EXTERNAL" : "INTERNAL", \
-	    pwr0, pwr1, pwr2, pwr3)
-
-#define ANT_HUNT_SLEEP 90
-#define ANT_EXT_TWEAK 0
-
-static int mxl111sf_ant_hunt(struct dvb_frontend *fe)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct dvb_usb_device *d = adap->dev;
-	struct mxl111sf_state *state = d->priv;
-
-	int antctrl = dvb_usb_mxl111sf_rfswitch;
-
-	u16 rxPwrA, rxPwr0, rxPwr1, rxPwr2;
-
-	/* FIXME: must force EXTERNAL for QAM - done elsewhere */
-	mxl111sf_set_ant_path(state, antctrl == ANT_PATH_AUTO ?
-			      ANT_PATH_EXTERNAL : antctrl);
-
-	if (antctrl == ANT_PATH_AUTO) {
-#if 0
-		msleep(ANT_HUNT_SLEEP);
-#endif
-		fe->ops.tuner_ops.get_rf_strength(fe, &rxPwrA);
-
-		mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
-		msleep(ANT_HUNT_SLEEP);
-		fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr0);
-
-		mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
-		msleep(ANT_HUNT_SLEEP);
-		fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr1);
-
-		mxl111sf_set_ant_path(state, ANT_PATH_INTERNAL);
-		msleep(ANT_HUNT_SLEEP);
-		fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr2);
-
-		if (rxPwr1+ANT_EXT_TWEAK >= rxPwr2) {
-			/* return with EXTERNAL enabled */
-			mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
-			DbgAntHunt(ANT_PATH_EXTERNAL, rxPwrA,
-				   rxPwr0, rxPwr1, rxPwr2);
-		} else {
-			/* return with INTERNAL enabled */
-			DbgAntHunt(ANT_PATH_INTERNAL, rxPwrA,
-				   rxPwr0, rxPwr1, rxPwr2);
-		}
-	}
-	return 0;
-}
-
-static struct mxl111sf_tuner_config mxl_tuner_config = {
-	.if_freq         = MXL_IF_6_0, /* applies to external IF output, only */
-	.invert_spectrum = 0,
-	.read_reg        = mxl111sf_read_reg,
-	.write_reg       = mxl111sf_write_reg,
-	.program_regs    = mxl111sf_ctrl_program_regs,
-	.top_master_ctrl = mxl1x1sf_top_master_ctrl,
-	.ant_hunt        = mxl111sf_ant_hunt,
-};
-
-static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap)
-{
-	struct dvb_usb_device *d = adap->dev;
-	struct mxl111sf_state *state = d->priv;
-	int fe_id = adap->num_frontends_initialized;
-
-	deb_adv("%s()\n", __func__);
-
-	if (NULL != dvb_attach(mxl111sf_tuner_attach,
-			       adap->fe_adap[fe_id].fe, state,
-			       &mxl_tuner_config))
-		return 0;
-
-	return -EIO;
-}
-
-static int mxl111sf_fe_ioctl_override(struct dvb_frontend *fe,
-				      unsigned int cmd, void *parg,
-				      unsigned int stage)
-{
-	int err = 0;
-
-	switch (stage) {
-	case DVB_FE_IOCTL_PRE:
-
-		switch (cmd) {
-		case FE_READ_SIGNAL_STRENGTH:
-			err = fe->ops.tuner_ops.get_rf_strength(fe, parg);
-			/* If no error occurs, prevent dvb-core from handling
-			 * this IOCTL, otherwise return the error */
-			if (0 == err)
-				err = 1;
-			break;
-		}
-		break;
-
-	case DVB_FE_IOCTL_POST:
-		/* no post-ioctl handling required */
-		break;
-	}
-	return err;
-};
-
-static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-struct i2c_algorithm mxl111sf_i2c_algo = {
-	.master_xfer   = mxl111sf_i2c_xfer,
-	.functionality = mxl111sf_i2c_func,
-#ifdef NEED_ALGO_CONTROL
-	.algo_control = dummy_algo_control,
-#endif
-};
-
-static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_atsc_mh_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_atsc_mh_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_mh_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_mh_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_spi_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_spi_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_tp_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_tp_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_isoc_properties;
-
-static int mxl111sf_probe(struct usb_interface *intf,
-			  const struct usb_device_id *id)
-{
-	struct dvb_usb_device *d = NULL;
-
-	deb_adv("%s()\n", __func__);
-
-	if (((dvb_usb_mxl111sf_isoc) &&
-	     (0 == dvb_usb_device_init(intf,
-				       &mxl111sf_dvbt_isoc_properties,
-				       THIS_MODULE, &d, adapter_nr) ||
-	      0 == dvb_usb_device_init(intf,
-				       &mxl111sf_atsc_isoc_properties,
-				       THIS_MODULE, &d, adapter_nr) ||
-	      0 == dvb_usb_device_init(intf,
-				       &mxl111sf_atsc_mh_isoc_properties,
-				       THIS_MODULE, &d, adapter_nr) ||
-	      0 == dvb_usb_device_init(intf,
-				       &mxl111sf_mh_isoc_properties,
-				       THIS_MODULE, &d, adapter_nr) ||
-	      ((dvb_usb_mxl111sf_spi) &&
-	       (0 == dvb_usb_device_init(intf,
-					 &mxl111sf_mercury_spi_isoc_properties,
-					 THIS_MODULE, &d, adapter_nr) ||
-		0 == dvb_usb_device_init(intf,
-					 &mxl111sf_mercury_mh_spi_isoc_properties,
-					 THIS_MODULE, &d, adapter_nr))) ||
-	      0 == dvb_usb_device_init(intf,
-				       &mxl111sf_mercury_tp_isoc_properties,
-				       THIS_MODULE, &d, adapter_nr) ||
-	      0 == dvb_usb_device_init(intf,
-				       &mxl111sf_mercury_mh_tp_isoc_properties,
-				       THIS_MODULE, &d, adapter_nr))) ||
-	    0 == dvb_usb_device_init(intf,
-				     &mxl111sf_dvbt_bulk_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf,
-				     &mxl111sf_atsc_bulk_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf,
-				     &mxl111sf_atsc_mh_bulk_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf,
-				     &mxl111sf_mh_bulk_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
-	    ((dvb_usb_mxl111sf_spi) &&
-	     (0 == dvb_usb_device_init(intf,
-				       &mxl111sf_mercury_spi_bulk_properties,
-				       THIS_MODULE, &d, adapter_nr) ||
-	      0 == dvb_usb_device_init(intf,
-				       &mxl111sf_mercury_mh_spi_bulk_properties,
-				       THIS_MODULE, &d, adapter_nr))) ||
-	    0 == dvb_usb_device_init(intf,
-				     &mxl111sf_mercury_tp_bulk_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf,
-				     &mxl111sf_mercury_mh_tp_bulk_properties,
-				     THIS_MODULE, &d, adapter_nr) || 0) {
-
-		struct mxl111sf_state *state = d->priv;
-		static u8 eeprom[256];
-		struct i2c_client c;
-		int ret;
-
-		ret = get_chip_info(state);
-		if (mxl_fail(ret))
-			err("failed to get chip info during probe");
-
-		mutex_init(&state->fe_lock);
-
-		if (state->chip_rev > MXL111SF_V6)
-			mxl111sf_config_pin_mux_modes(state,
-						      PIN_MUX_TS_SPI_IN_MODE_1);
-
-		c.adapter = &d->i2c_adap;
-		c.addr = 0xa0 >> 1;
-
-		ret = tveeprom_read(&c, eeprom, sizeof(eeprom));
-		if (mxl_fail(ret))
-			return 0;
-		tveeprom_hauppauge_analog(&c, &state->tv,
-					  (0x84 == eeprom[0xa0]) ?
-					  eeprom + 0xa0 : eeprom + 0x80);
-#if 0
-		switch (state->tv.model) {
-		case 117001:
-		case 126001:
-		case 138001:
-			break;
-		default:
-			printk(KERN_WARNING "%s: warning: "
-			       "unknown hauppauge model #%d\n",
-			       __func__, state->tv.model);
-		}
-#endif
-		return 0;
-	}
-	err("Your device is not yet supported by this driver. "
-	    "See kernellabs.com for more info");
-	return -EINVAL;
-}
-
-static struct usb_device_id mxl111sf_table[] = {
-/* 0 */	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc600) }, /* ATSC+ IR     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc601) }, /* ATSC         */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc602) }, /*     +        */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc603) }, /* ATSC+        */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc604) }, /* DVBT         */
-/* 5 */	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc609) }, /* ATSC  IR     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60a) }, /*     + IR     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60b) }, /* ATSC+ IR     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60c) }, /* DVBT  IR     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc653) }, /* ATSC+        */
-/*10 */	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc65b) }, /* ATSC+ IR     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb700) }, /* ATSC+ sw     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb701) }, /* ATSC  sw     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb702) }, /*     + sw     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb703) }, /* ATSC+ sw     */
-/*15 */	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb704) }, /* DVBT  sw     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb753) }, /* ATSC+ sw     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb763) }, /* ATSC+ no     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb764) }, /* DVBT  no     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xd853) }, /* ATSC+ sw     */
-/*20 */	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xd854) }, /* DVBT  sw     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xd863) }, /* ATSC+ no     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xd864) }, /* DVBT  no     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d3) }, /* ATSC+ sw     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d4) }, /* DVBT  sw     */
-/*25 */	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e3) }, /* ATSC+ no     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e4) }, /* DVBT  no     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8ff) }, /* ATSC+        */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc612) }, /*     +        */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc613) }, /* ATSC+        */
-/*30 */	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61a) }, /*     + IR     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61b) }, /* ATSC+ IR     */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb757) }, /* ATSC+DVBT sw */
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, 0xb767) }, /* ATSC+DVBT no */
-	{}		/* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, mxl111sf_table);
-
-
-#define MXL111SF_EP4_BULK_STREAMING_CONFIG		\
-	.size_of_priv = sizeof(struct mxl111sf_adap_state), \
-	.streaming_ctrl = mxl111sf_ep4_streaming_ctrl,	\
-	.stream = {					\
-		.type = USB_BULK,			\
-		.count = 5,				\
-		.endpoint = 0x04,			\
-		.u = {					\
-			.bulk = {			\
-				.buffersize = 8192,	\
-			}				\
-		}					\
-	}
-
-/* FIXME: works for v6 but not v8 silicon */
-#define MXL111SF_EP4_ISOC_STREAMING_CONFIG		\
-	.size_of_priv = sizeof(struct mxl111sf_adap_state), \
-	.streaming_ctrl = mxl111sf_ep4_streaming_ctrl,	\
-	.stream = {					\
-		.type = USB_ISOC,			\
-		.count = 5,				\
-		.endpoint = 0x04,			\
-		.u = {					\
-			.isoc = {			\
-				.framesperurb = 96,	\
-				/* FIXME: v6 SILICON: */	\
-				.framesize = 564,	\
-				.interval = 1,		\
-			}				\
-		}					\
-	}
-
-#define MXL111SF_EP5_BULK_STREAMING_CONFIG		\
-	.size_of_priv = sizeof(struct mxl111sf_adap_state), \
-	.streaming_ctrl = mxl111sf_ep5_streaming_ctrl,	\
-	.stream = {					\
-		.type = USB_BULK,			\
-		.count = 5,				\
-		.endpoint = 0x05,			\
-		.u = {					\
-			.bulk = {			\
-				.buffersize = 8192,	\
-			}				\
-		}					\
-	}
-
-#define MXL111SF_EP5_ISOC_STREAMING_CONFIG		\
-	.size_of_priv = sizeof(struct mxl111sf_adap_state), \
-	.streaming_ctrl = mxl111sf_ep5_streaming_ctrl,	\
-	.stream = {					\
-		.type = USB_ISOC,			\
-		.count = 5,				\
-		.endpoint = 0x05,			\
-		.u = {					\
-			.isoc = {			\
-				.framesperurb = 96,	\
-				.framesize = 200,	\
-				.interval = 1,		\
-			}				\
-		}					\
-	}
-
-#define MXL111SF_EP6_BULK_STREAMING_CONFIG		\
-	.size_of_priv = sizeof(struct mxl111sf_adap_state), \
-	.streaming_ctrl = mxl111sf_ep6_streaming_ctrl,	\
-	.stream = {					\
-		.type = USB_BULK,			\
-		.count = 5,				\
-		.endpoint = 0x06,			\
-		.u = {					\
-			.bulk = {			\
-				.buffersize = 8192,	\
-			}				\
-		}					\
-	}
-
-/* FIXME */
-#define MXL111SF_EP6_ISOC_STREAMING_CONFIG		\
-	.size_of_priv = sizeof(struct mxl111sf_adap_state), \
-	.streaming_ctrl = mxl111sf_ep6_streaming_ctrl,	\
-	.stream = {					\
-		.type = USB_ISOC,			\
-		.count = 5,				\
-		.endpoint = 0x06,			\
-		.u = {					\
-			.isoc = {			\
-				.framesperurb = 24,	\
-				.framesize = 3072,	\
-				.interval = 1,		\
-			}				\
-		}					\
-	}
-
-#define MXL111SF_DEFAULT_DEVICE_PROPERTIES			\
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,			\
-	.usb_ctrl = DEVICE_SPECIFIC,				\
-	/* use usb alt setting 1 for EP4 ISOC transfer (dvb-t),	\
-				     EP6 BULK transfer (atsc/qam), \
-	   use usb alt setting 2 for EP4 BULK transfer (dvb-t),	\
-				     EP6 ISOC transfer (atsc/qam), \
-	*/							\
-	.power_ctrl       = mxl111sf_power_ctrl,		\
-	.i2c_algo         = &mxl111sf_i2c_algo,			\
-	.generic_bulk_ctrl_endpoint          = MXL_EP2_REG_WRITE, \
-	.generic_bulk_ctrl_endpoint_response = MXL_EP1_REG_READ, \
-	.size_of_priv     = sizeof(struct mxl111sf_state)
-
-static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties = {
-	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 1,
-		.fe = {{
-			.frontend_attach  = mxl111sf_attach_demod,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP4_BULK_STREAMING_CONFIG,
-		} },
-		},
-	},
-	.num_device_descs = 3,
-	.devices = {
-		{   "Hauppauge 126xxx DVBT (bulk)",
-			{ NULL },
-			{ &mxl111sf_table[4], &mxl111sf_table[8],
-			  NULL },
-		},
-		{   "Hauppauge 117xxx DVBT (bulk)",
-			{ NULL },
-			{ &mxl111sf_table[15], &mxl111sf_table[18],
-			  NULL },
-		},
-		{   "Hauppauge 138xxx DVBT (bulk)",
-			{ NULL },
-			{ &mxl111sf_table[20], &mxl111sf_table[22],
-			  &mxl111sf_table[24], &mxl111sf_table[26],
-			  NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties = {
-	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 1,
-		.fe = {{
-			.frontend_attach  = mxl111sf_attach_demod,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP4_ISOC_STREAMING_CONFIG,
-		} },
-		},
-	},
-	.num_device_descs = 3,
-	.devices = {
-		{   "Hauppauge 126xxx DVBT (isoc)",
-			{ NULL },
-			{ &mxl111sf_table[4], &mxl111sf_table[8],
-			  NULL },
-		},
-		{   "Hauppauge 117xxx DVBT (isoc)",
-			{ NULL },
-			{ &mxl111sf_table[15], &mxl111sf_table[18],
-			  NULL },
-		},
-		{   "Hauppauge 138xxx DVBT (isoc)",
-			{ NULL },
-			{ &mxl111sf_table[20], &mxl111sf_table[22],
-			  &mxl111sf_table[24], &mxl111sf_table[26],
-			  NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = {
-	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 1,
-		.fe = {{
-			.frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP6_BULK_STREAMING_CONFIG,
-		}},
-		},
-	},
-	.num_device_descs = 2,
-	.devices = {
-		{   "Hauppauge 126xxx ATSC (bulk)",
-			{ NULL },
-			{ &mxl111sf_table[1], &mxl111sf_table[5],
-			  NULL },
-		},
-		{   "Hauppauge 117xxx ATSC (bulk)",
-			{ NULL },
-			{ &mxl111sf_table[12],
-			  NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = {
-	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 1,
-		.fe = {{
-			.frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP6_ISOC_STREAMING_CONFIG,
-		}},
-		},
-	},
-	.num_device_descs = 2,
-	.devices = {
-		{   "Hauppauge 126xxx ATSC (isoc)",
-			{ NULL },
-			{ &mxl111sf_table[1], &mxl111sf_table[5],
-			  NULL },
-		},
-		{   "Hauppauge 117xxx ATSC (isoc)",
-			{ NULL },
-			{ &mxl111sf_table[12],
-			  NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties mxl111sf_mh_bulk_properties = {
-	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 1,
-		.fe = {{
-			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-			.frontend_attach  = mxl111sf_lg2160_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP5_BULK_STREAMING_CONFIG,
-		}},
-		},
-	},
-	.num_device_descs = 2,
-	.devices = {
-		{   "HCW 126xxx (bulk)",
-			{ NULL },
-			{ &mxl111sf_table[2], &mxl111sf_table[6],
-			  NULL },
-		},
-		{   "HCW 117xxx (bulk)",
-			{ NULL },
-			{ &mxl111sf_table[13],
-			  NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties mxl111sf_mh_isoc_properties = {
-	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 1,
-		.fe = {{
-			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-			.frontend_attach  = mxl111sf_lg2160_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP5_ISOC_STREAMING_CONFIG,
-		}},
-		},
-	},
-	.num_device_descs = 2,
-	.devices = {
-		{   "HCW 126xxx (isoc)",
-			{ NULL },
-			{ &mxl111sf_table[2], &mxl111sf_table[6],
-			  NULL },
-		},
-		{   "HCW 117xxx (isoc)",
-			{ NULL },
-			{ &mxl111sf_table[13],
-			  NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties mxl111sf_atsc_mh_bulk_properties = {
-	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 3,
-		.fe = {{
-			.frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP6_BULK_STREAMING_CONFIG,
-		},
-		{
-			.frontend_attach  = mxl111sf_attach_demod,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP4_BULK_STREAMING_CONFIG,
-		},
-		{
-			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-			.frontend_attach  = mxl111sf_lg2160_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP5_BULK_STREAMING_CONFIG,
-		}},
-		},
-	},
-	.num_device_descs = 2,
-	.devices = {
-		{   "Hauppauge 126xxx ATSC+ (bulk)",
-			{ NULL },
-			{ &mxl111sf_table[0], &mxl111sf_table[3],
-			  &mxl111sf_table[7], &mxl111sf_table[9],
-			  &mxl111sf_table[10], NULL },
-		},
-		{   "Hauppauge 117xxx ATSC+ (bulk)",
-			{ NULL },
-			{ &mxl111sf_table[11], &mxl111sf_table[14],
-			  &mxl111sf_table[16], &mxl111sf_table[17],
-			  &mxl111sf_table[32], &mxl111sf_table[33],
-			  NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties mxl111sf_atsc_mh_isoc_properties = {
-	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 3,
-		.fe = {{
-			.frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP6_ISOC_STREAMING_CONFIG,
-		},
-		{
-			.frontend_attach  = mxl111sf_attach_demod,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP4_ISOC_STREAMING_CONFIG,
-		},
-		{
-			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-			.frontend_attach  = mxl111sf_lg2160_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP5_ISOC_STREAMING_CONFIG,
-		}},
-		},
-	},
-	.num_device_descs = 2,
-	.devices = {
-		{   "Hauppauge 126xxx ATSC+ (isoc)",
-			{ NULL },
-			{ &mxl111sf_table[0], &mxl111sf_table[3],
-			  &mxl111sf_table[7], &mxl111sf_table[9],
-			  &mxl111sf_table[10], NULL },
-		},
-		{   "Hauppauge 117xxx ATSC+ (isoc)",
-			{ NULL },
-			{ &mxl111sf_table[11], &mxl111sf_table[14],
-			  &mxl111sf_table[16], &mxl111sf_table[17],
-			  &mxl111sf_table[32], &mxl111sf_table[33],
-			  NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties mxl111sf_mercury_spi_bulk_properties = {
-	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 3,
-		.fe = {{
-			.frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP6_BULK_STREAMING_CONFIG,
-		},
-		{
-			.frontend_attach  = mxl111sf_attach_demod,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP4_BULK_STREAMING_CONFIG,
-		},
-		{
-			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-			.frontend_attach  = mxl111sf_lg2161_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP5_BULK_STREAMING_CONFIG,
-		}},
-		},
-	},
-	.num_device_descs = 2,
-	.devices = {
-		{   "Hauppauge Mercury (spi-bulk)",
-			{ NULL },
-			{ &mxl111sf_table[19], &mxl111sf_table[21],
-			  &mxl111sf_table[23], &mxl111sf_table[25],
-			  NULL },
-		},
-		{   "Hauppauge WinTV-Aero-M (spi-bulk)",
-			{ NULL },
-			{ &mxl111sf_table[29], &mxl111sf_table[31],
-			  NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties mxl111sf_mercury_spi_isoc_properties = {
-	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 3,
-		.fe = {{
-			.frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP6_ISOC_STREAMING_CONFIG,
-		},
-		{
-			.frontend_attach  = mxl111sf_attach_demod,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP4_ISOC_STREAMING_CONFIG,
-		},
-		{
-			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-			.frontend_attach  = mxl111sf_lg2161_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP5_ISOC_STREAMING_CONFIG,
-		}},
-		},
-	},
-	.num_device_descs = 2,
-	.devices = {
-		{   "Hauppauge Mercury (spi-isoc)",
-			{ NULL },
-			{ &mxl111sf_table[19], &mxl111sf_table[21],
-			  &mxl111sf_table[23], &mxl111sf_table[25],
-			  NULL },
-		},
-		{   "Hauppauge WinTV-Aero-M (spi-isoc)",
-			{ NULL },
-			{ &mxl111sf_table[29], &mxl111sf_table[31],
-			  NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties mxl111sf_mercury_tp_bulk_properties = {
-	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 3,
-		.fe = {{
-			.frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP6_BULK_STREAMING_CONFIG,
-		},
-		{
-			.frontend_attach  = mxl111sf_attach_demod,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP4_BULK_STREAMING_CONFIG,
-		},
-		{
-			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-			.frontend_attach  = mxl111sf_lg2161_ep6_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP6_BULK_STREAMING_CONFIG,
-		}},
-		},
-	},
-	.num_device_descs = 2,
-	.devices = {
-		{   "Hauppauge Mercury (tp-bulk)",
-			{ NULL },
-			{ &mxl111sf_table[19], &mxl111sf_table[21],
-			  &mxl111sf_table[23], &mxl111sf_table[25],
-			  &mxl111sf_table[27], NULL },
-		},
-		{   "Hauppauge WinTV-Aero-M",
-			{ NULL },
-			{ &mxl111sf_table[29], &mxl111sf_table[31],
-			  NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties mxl111sf_mercury_tp_isoc_properties = {
-	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 3,
-		.fe = {{
-			.frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP6_ISOC_STREAMING_CONFIG,
-		},
-		{
-			.frontend_attach  = mxl111sf_attach_demod,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP4_ISOC_STREAMING_CONFIG,
-		},
-		{
-			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-			.frontend_attach  = mxl111sf_lg2161_ep6_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP6_ISOC_STREAMING_CONFIG,
-		}},
-		},
-	},
-	.num_device_descs = 2,
-	.devices = {
-		{   "Hauppauge Mercury (tp-isoc)",
-			{ NULL },
-			{ &mxl111sf_table[19], &mxl111sf_table[21],
-			  &mxl111sf_table[23], &mxl111sf_table[25],
-			  &mxl111sf_table[27], NULL },
-		},
-		{   "Hauppauge WinTV-Aero-M (tp-isoc)",
-			{ NULL },
-			{ &mxl111sf_table[29], &mxl111sf_table[31],
-			  NULL },
-		},
-	}
-};
-
-static
-struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_bulk_properties = {
-	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 2,
-		.fe = {{
-			.frontend_attach  = mxl111sf_attach_demod,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP4_BULK_STREAMING_CONFIG,
-		},
-		{
-			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-			.frontend_attach  = mxl111sf_lg2161_ep6_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP6_BULK_STREAMING_CONFIG,
-		}},
-		},
-	},
-	.num_device_descs = 1,
-	.devices = {
-		{   "Hauppauge 126xxx (tp-bulk)",
-			{ NULL },
-			{ &mxl111sf_table[28], &mxl111sf_table[30],
-			  NULL },
-		},
-	}
-};
-
-static
-struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_isoc_properties = {
-	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 2,
-		.fe = {{
-			.frontend_attach  = mxl111sf_attach_demod,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP4_ISOC_STREAMING_CONFIG,
-		},
-		{
-			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-			.frontend_attach  = mxl111sf_lg2161_ep6_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP6_ISOC_STREAMING_CONFIG,
-		}},
-		},
-	},
-	.num_device_descs = 1,
-	.devices = {
-		{   "Hauppauge 126xxx (tp-isoc)",
-			{ NULL },
-			{ &mxl111sf_table[28], &mxl111sf_table[30],
-			  NULL },
-		},
-	}
-};
-
-static
-struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_bulk_properties = {
-	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 2,
-		.fe = {{
-			.frontend_attach  = mxl111sf_attach_demod,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP4_BULK_STREAMING_CONFIG,
-		},
-		{
-			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-			.frontend_attach  = mxl111sf_lg2161_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP5_BULK_STREAMING_CONFIG,
-		}},
-		},
-	},
-	.num_device_descs = 1,
-	.devices = {
-		{   "Hauppauge 126xxx (spi-bulk)",
-			{ NULL },
-			{ &mxl111sf_table[28], &mxl111sf_table[30],
-			  NULL },
-		},
-	}
-};
-
-static
-struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_isoc_properties = {
-	MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.fe_ioctl_override = mxl111sf_fe_ioctl_override,
-		.num_frontends = 2,
-		.fe = {{
-			.frontend_attach  = mxl111sf_attach_demod,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP4_ISOC_STREAMING_CONFIG,
-		},
-		{
-			.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-			.frontend_attach  = mxl111sf_lg2161_frontend_attach,
-			.tuner_attach     = mxl111sf_attach_tuner,
-
-			MXL111SF_EP5_ISOC_STREAMING_CONFIG,
-		}},
-		},
-	},
-	.num_device_descs = 1,
-	.devices = {
-		{   "Hauppauge 126xxx (spi-isoc)",
-			{ NULL },
-			{ &mxl111sf_table[28], &mxl111sf_table[30],
-			  NULL },
-		},
-	}
-};
-
-static struct usb_driver mxl111sf_driver = {
-	.name		= "dvb_usb_mxl111sf",
-	.probe		= mxl111sf_probe,
-	.disconnect     = dvb_usb_device_exit,
-	.id_table	= mxl111sf_table,
-};
-
-module_usb_driver(mxl111sf_driver);
-
-MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
-MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.h b/drivers/media/dvb/dvb-usb/mxl111sf.h
deleted file mode 100644
index 364d89f..0000000
--- a/drivers/media/dvb/dvb-usb/mxl111sf.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com)
- *
- *   This program is free software; you can redistribute it and/or modify it
- *   under the terms of the GNU General Public License as published by the Free
- *   Software Foundation, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-
-#ifndef _DVB_USB_MXL111SF_H_
-#define _DVB_USB_MXL111SF_H_
-
-#ifdef DVB_USB_LOG_PREFIX
-#undef DVB_USB_LOG_PREFIX
-#endif
-#define DVB_USB_LOG_PREFIX "mxl111sf"
-#include "dvb-usb.h"
-#include <media/tveeprom.h>
-
-#define MXL_EP1_REG_READ     1
-#define MXL_EP2_REG_WRITE    2
-#define MXL_EP3_INTERRUPT    3
-#define MXL_EP4_MPEG2        4
-#define MXL_EP5_I2S          5
-#define MXL_EP6_656          6
-#define MXL_EP6_MPEG2        6
-
-#ifdef USING_ENUM_mxl111sf_current_mode
-enum mxl111sf_current_mode {
-	mxl_mode_dvbt = MXL_EP4_MPEG2,
-	mxl_mode_mh   = MXL_EP5_I2S,
-	mxl_mode_atsc = MXL_EP6_MPEG2,
-};
-#endif
-
-enum mxl111sf_gpio_port_expander {
-	mxl111sf_gpio_hw,
-	mxl111sf_PCA9534,
-};
-
-struct mxl111sf_state {
-	struct dvb_usb_device *d;
-
-	enum mxl111sf_gpio_port_expander gpio_port_expander;
-	u8 port_expander_addr;
-
-	u8 chip_id;
-	u8 chip_ver;
-#define MXL111SF_V6     1
-#define MXL111SF_V8_100 2
-#define MXL111SF_V8_200 3
-	u8 chip_rev;
-
-#ifdef USING_ENUM_mxl111sf_current_mode
-	enum mxl111sf_current_mode current_mode;
-#endif
-
-#define MXL_TUNER_MODE         0
-#define MXL_SOC_MODE           1
-#define MXL_DEV_MODE_MASK      0x01
-#if 1
-	int device_mode;
-#endif
-	/* use usb alt setting 1 for EP4 ISOC transfer (dvb-t),
-				     EP5 BULK transfer (atsc-mh),
-				     EP6 BULK transfer (atsc/qam),
-	   use usb alt setting 2 for EP4 BULK transfer (dvb-t),
-				     EP5 ISOC transfer (atsc-mh),
-				     EP6 ISOC transfer (atsc/qam),
-	 */
-	int alt_mode;
-	int gpio_mode;
-	struct tveeprom tv;
-
-	struct mutex fe_lock;
-};
-
-struct mxl111sf_adap_state {
-	int alt_mode;
-	int gpio_mode;
-	int device_mode;
-	int ep6_clockphase;
-	int (*fe_init)(struct dvb_frontend *);
-	int (*fe_sleep)(struct dvb_frontend *);
-};
-
-int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data);
-int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data);
-
-struct mxl111sf_reg_ctrl_info {
-	u8 addr;
-	u8 mask;
-	u8 data;
-};
-
-int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
-			    u8 addr, u8 mask, u8 data);
-int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state,
-			       struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
-
-/* needed for hardware i2c functions in mxl111sf-i2c.c:
- * mxl111sf_i2c_send_data / mxl111sf_i2c_get_data */
-int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
-		      u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen);
-
-#define mxl_printk(kern, fmt, arg...) \
-	printk(kern "%s: " fmt "\n", __func__, ##arg)
-
-#define mxl_info(fmt, arg...) \
-	mxl_printk(KERN_INFO, fmt, ##arg)
-
-extern int dvb_usb_mxl111sf_debug;
-#define mxl_debug(fmt, arg...) \
-	if (dvb_usb_mxl111sf_debug) \
-		mxl_printk(KERN_DEBUG, fmt, ##arg)
-
-#define MXL_I2C_DBG 0x04
-#define MXL_ADV_DBG 0x10
-#define mxl_debug_adv(fmt, arg...) \
-	if (dvb_usb_mxl111sf_debug & MXL_ADV_DBG) \
-		mxl_printk(KERN_DEBUG, fmt, ##arg)
-
-#define mxl_i2c(fmt, arg...) \
-	if (dvb_usb_mxl111sf_debug & MXL_I2C_DBG) \
-		mxl_printk(KERN_DEBUG, fmt, ##arg)
-
-#define mxl_i2c_adv(fmt, arg...) \
-	if ((dvb_usb_mxl111sf_debug & (MXL_I2C_DBG | MXL_ADV_DBG)) == \
-		(MXL_I2C_DBG | MXL_ADV_DBG)) \
-			mxl_printk(KERN_DEBUG, fmt, ##arg)
-
-/* The following allows the mxl_fail() macro defined below to work
- * in externel modules, such as mxl111sf-tuner.ko, even though
- * dvb_usb_mxl111sf_debug is not defined within those modules */
-#if (defined(__MXL111SF_TUNER_H__)) || (defined(__MXL111SF_DEMOD_H__))
-#define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG
-#else
-#define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug
-#endif
-
-#define mxl_fail(ret)							\
-({									\
-	int __ret;							\
-	__ret = (ret < 0);						\
-	if ((__ret) && (MXL_ADV_DEBUG_ENABLED & MXL_ADV_DBG))		\
-		mxl_printk(KERN_ERR, "error %d on line %d",		\
-			   ret, __LINE__);				\
-	__ret;								\
-})
-
-#endif /* _DVB_USB_MXL111SF_H_ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
deleted file mode 100644
index 6c55384..0000000
--- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/* DVB USB framework compliant Linux driver for the Hauppauge WinTV-NOVA-T usb2
- * DVB-T receiver.
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License as published by the Free
- *	Software Foundation, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "dibusb.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=rc,2=eeprom (|-able))." DVB_USB_DEBUG_STATUS);
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define deb_rc(args...) dprintk(debug,0x01,args)
-#define deb_ee(args...) dprintk(debug,0x02,args)
-
-/* Hauppauge NOVA-T USB2 keys */
-static struct rc_map_table rc_map_haupp_table[] = {
-	{ 0x1e00, KEY_0 },
-	{ 0x1e01, KEY_1 },
-	{ 0x1e02, KEY_2 },
-	{ 0x1e03, KEY_3 },
-	{ 0x1e04, KEY_4 },
-	{ 0x1e05, KEY_5 },
-	{ 0x1e06, KEY_6 },
-	{ 0x1e07, KEY_7 },
-	{ 0x1e08, KEY_8 },
-	{ 0x1e09, KEY_9 },
-	{ 0x1e0a, KEY_KPASTERISK },
-	{ 0x1e0b, KEY_RED },
-	{ 0x1e0c, KEY_RADIO },
-	{ 0x1e0d, KEY_MENU },
-	{ 0x1e0e, KEY_GRAVE }, /* # */
-	{ 0x1e0f, KEY_MUTE },
-	{ 0x1e10, KEY_VOLUMEUP },
-	{ 0x1e11, KEY_VOLUMEDOWN },
-	{ 0x1e12, KEY_CHANNEL },
-	{ 0x1e14, KEY_UP },
-	{ 0x1e15, KEY_DOWN },
-	{ 0x1e16, KEY_LEFT },
-	{ 0x1e17, KEY_RIGHT },
-	{ 0x1e18, KEY_VIDEO },
-	{ 0x1e19, KEY_AUDIO },
-	{ 0x1e1a, KEY_IMAGES },
-	{ 0x1e1b, KEY_EPG },
-	{ 0x1e1c, KEY_TV },
-	{ 0x1e1e, KEY_NEXT },
-	{ 0x1e1f, KEY_BACK },
-	{ 0x1e20, KEY_CHANNELUP },
-	{ 0x1e21, KEY_CHANNELDOWN },
-	{ 0x1e24, KEY_LAST }, /* Skip backwards */
-	{ 0x1e25, KEY_OK },
-	{ 0x1e29, KEY_BLUE},
-	{ 0x1e2e, KEY_GREEN },
-	{ 0x1e30, KEY_PAUSE },
-	{ 0x1e32, KEY_REWIND },
-	{ 0x1e34, KEY_FASTFORWARD },
-	{ 0x1e35, KEY_PLAY },
-	{ 0x1e36, KEY_STOP },
-	{ 0x1e37, KEY_RECORD },
-	{ 0x1e38, KEY_YELLOW },
-	{ 0x1e3b, KEY_GOTO },
-	{ 0x1e3d, KEY_POWER },
-};
-
-/* Firmware bug? sometimes, when a new key is pressed, the previous pressed key
- * is delivered. No workaround yet, maybe a new firmware.
- */
-static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
-{
-	u8 key[5],cmd[2] = { DIBUSB_REQ_POLL_REMOTE, 0x35 }, data,toggle,custom;
-	u16 raw;
-	int i;
-	struct dibusb_device_state *st = d->priv;
-
-	dvb_usb_generic_rw(d,cmd,2,key,5,0);
-
-	*state = REMOTE_NO_KEY_PRESSED;
-	switch (key[0]) {
-		case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED:
-			raw = ((key[1] << 8) | key[2]) >> 3;
-			toggle = !!(raw & 0x800);
-			data = raw & 0x3f;
-			custom = (raw >> 6) & 0x1f;
-
-			deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle);
-
-			for (i = 0; i < ARRAY_SIZE(rc_map_haupp_table); i++) {
-				if (rc5_data(&rc_map_haupp_table[i]) == data &&
-					rc5_custom(&rc_map_haupp_table[i]) == custom) {
-
-					deb_rc("c: %x, d: %x\n", rc5_data(&rc_map_haupp_table[i]),
-								 rc5_custom(&rc_map_haupp_table[i]));
-
-					*event = rc_map_haupp_table[i].keycode;
-					*state = REMOTE_KEY_PRESSED;
-					if (st->old_toggle == toggle) {
-						if (st->last_repeat_count++ < 2)
-							*state = REMOTE_NO_KEY_PRESSED;
-					} else {
-						st->last_repeat_count = 0;
-						st->old_toggle = toggle;
-					}
-					break;
-				}
-			}
-
-			break;
-		case DIBUSB_RC_HAUPPAUGE_KEY_EMPTY:
-		default:
-			break;
-	}
-
-	return 0;
-}
-
-static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6])
-{
-	int i;
-	u8 b;
-
-	mac[0] = 0x00;
-	mac[1] = 0x0d;
-	mac[2] = 0xfe;
-
-	/* this is a complete guess, but works for my box */
-	for (i = 136; i < 139; i++) {
-		dibusb_read_eeprom_byte(d,i, &b);
-
-		mac[5 - (i - 136)] = b;
-	}
-
-	return 0;
-}
-
-/* USB Driver stuff */
-static struct dvb_usb_device_properties nova_t_properties;
-
-static int nova_t_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	return dvb_usb_device_init(intf, &nova_t_properties,
-				   THIS_MODULE, NULL, adapter_nr);
-}
-
-/* do not change the order of the ID table */
-static struct usb_device_id nova_t_table [] = {
-/* 00 */	{ USB_DEVICE(USB_VID_HAUPPAUGE,     USB_PID_WINTV_NOVA_T_USB2_COLD) },
-/* 01 */	{ USB_DEVICE(USB_VID_HAUPPAUGE,     USB_PID_WINTV_NOVA_T_USB2_WARM) },
-			{ }		/* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, nova_t_table);
-
-static struct dvb_usb_device_properties nova_t_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware = "dvb-usb-nova-t-usb2-02.fw",
-
-	.num_adapters     = 1,
-	.adapter          = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-			.pid_filter_count = 32,
-
-			.streaming_ctrl   = dibusb2_0_streaming_ctrl,
-			.pid_filter       = dibusb_pid_filter,
-			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
-			.frontend_attach  = dibusb_dib3000mc_frontend_attach,
-			.tuner_attach     = dibusb_dib3000mc_tuner_attach,
-
-			/* parameter for the MPEG2-data transfer */
-					.stream = {
-						.type = USB_BULK,
-				.count = 7,
-				.endpoint = 0x06,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-			.size_of_priv     = sizeof(struct dibusb_state),
-		}
-	},
-	.size_of_priv     = sizeof(struct dibusb_device_state),
-
-	.power_ctrl       = dibusb2_0_power_ctrl,
-	.read_mac_address = nova_t_read_mac_address,
-
-	.rc.legacy = {
-		.rc_interval      = 100,
-		.rc_map_table     = rc_map_haupp_table,
-		.rc_map_size      = ARRAY_SIZE(rc_map_haupp_table),
-		.rc_query         = nova_t_rc_query,
-	},
-
-	.i2c_algo         = &dibusb_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 1,
-	.devices = {
-		{   "Hauppauge WinTV-NOVA-T usb2",
-			{ &nova_t_table[0], NULL },
-			{ &nova_t_table[1], NULL },
-		},
-		{ NULL },
-	}
-};
-
-static struct usb_driver nova_t_driver = {
-	.name		= "dvb_usb_nova_t_usb2",
-	.probe		= nova_t_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table	= nova_t_table,
-};
-
-module_usb_driver(nova_t_driver);
-
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("Hauppauge WinTV-NOVA-T usb2");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
deleted file mode 100644
index c8a9504..0000000
--- a/drivers/media/dvb/dvb-usb/opera1.c
+++ /dev/null
@@ -1,583 +0,0 @@
-/* DVB USB framework compliant Linux driver for the Opera1 DVB-S Card
-*
-* Copyright (C) 2006 Mario Hlawitschka (dh1pa@amsat.org)
-* Copyright (C) 2006 Marco Gittler (g.marco@freenet.de)
-*
-*	This program is free software; you can redistribute it and/or modify it
-*	under the terms of the GNU General Public License as published by the Free
-*	Software Foundation, version 2.
-*
-* see Documentation/dvb/README.dvb-usb for more information
-*/
-
-#define DVB_USB_LOG_PREFIX "opera"
-
-#include "dvb-usb.h"
-#include "stv0299.h"
-
-#define OPERA_READ_MSG 0
-#define OPERA_WRITE_MSG 1
-#define OPERA_I2C_TUNER 0xd1
-
-#define READ_FX2_REG_REQ  0xba
-#define READ_MAC_ADDR 0x08
-#define OPERA_WRITE_FX2 0xbb
-#define OPERA_TUNER_REQ 0xb1
-#define REG_1F_SYMBOLRATE_BYTE0 0x1f
-#define REG_20_SYMBOLRATE_BYTE1 0x20
-#define REG_21_SYMBOLRATE_BYTE2 0x21
-
-#define ADDR_B600_VOLTAGE_13V (0x02)
-#define ADDR_B601_VOLTAGE_18V (0x03)
-#define ADDR_B1A6_STREAM_CTRL (0x04)
-#define ADDR_B880_READ_REMOTE (0x05)
-
-struct opera1_state {
-	u32 last_key_pressed;
-};
-struct rc_map_opera_table {
-	u32 keycode;
-	u32 event;
-};
-
-static int dvb_usb_opera1_debug;
-module_param_named(debug, dvb_usb_opera1_debug, int, 0644);
-MODULE_PARM_DESC(debug,
-		 "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))."
-		 DVB_USB_DEBUG_STATUS);
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-
-static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value,
-			    u8 * data, u16 len, int flags)
-{
-	int ret;
-	u8 tmp;
-	u8 *buf;
-	unsigned int pipe = (flags == OPERA_READ_MSG) ?
-		usb_rcvctrlpipe(dev,0) : usb_sndctrlpipe(dev, 0);
-	u8 request_type = (flags == OPERA_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
-
-	buf = kmalloc(len, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	if (flags == OPERA_WRITE_MSG)
-		memcpy(buf, data, len);
-	ret = usb_control_msg(dev, pipe, request,
-			request_type | USB_TYPE_VENDOR, value, 0x0,
-			buf, len, 2000);
-
-	if (request == OPERA_TUNER_REQ) {
-		tmp = buf[0];
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			    OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR,
-			    0x01, 0x0, buf, 1, 2000) < 1 || buf[0] != 0x08) {
-			ret = 0;
-			goto out;
-		}
-		buf[0] = tmp;
-	}
-	if (flags == OPERA_READ_MSG)
-		memcpy(data, buf, len);
-out:
-	kfree(buf);
-	return ret;
-}
-
-/* I2C */
-
-static int opera1_usb_i2c_msgxfer(struct dvb_usb_device *dev, u16 addr,
-				  u8 * buf, u16 len)
-{
-	int ret = 0;
-	u8 request;
-	u16 value;
-
-	if (!dev) {
-		info("no usb_device");
-		return -EINVAL;
-	}
-	if (mutex_lock_interruptible(&dev->usb_mutex) < 0)
-		return -EAGAIN;
-
-	switch (addr>>1){
-		case ADDR_B600_VOLTAGE_13V:
-			request=0xb6;
-			value=0x00;
-			break;
-		case ADDR_B601_VOLTAGE_18V:
-			request=0xb6;
-			value=0x01;
-			break;
-		case ADDR_B1A6_STREAM_CTRL:
-			request=0xb1;
-			value=0xa6;
-			break;
-		case ADDR_B880_READ_REMOTE:
-			request=0xb8;
-			value=0x80;
-			break;
-		default:
-			request=0xb1;
-			value=addr;
-	}
-	ret = opera1_xilinx_rw(dev->udev, request,
-		value, buf, len,
-		addr&0x01?OPERA_READ_MSG:OPERA_WRITE_MSG);
-
-	mutex_unlock(&dev->usb_mutex);
-	return ret;
-}
-
-static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-			   int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	int i = 0, tmp = 0;
-
-	if (!d)
-		return -ENODEV;
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	for (i = 0; i < num; i++) {
-		if ((tmp = opera1_usb_i2c_msgxfer(d,
-					(msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0),
-					msg[i].buf,
-					msg[i].len
-					)) != msg[i].len) {
-			break;
-		}
-		if (dvb_usb_opera1_debug & 0x10)
-			info("sending i2c mesage %d %d", tmp, msg[i].len);
-	}
-	mutex_unlock(&d->i2c_mutex);
-	return num;
-}
-
-static u32 opera1_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm opera1_i2c_algo = {
-	.master_xfer = opera1_i2c_xfer,
-	.functionality = opera1_i2c_func,
-};
-
-static int opera1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
-	static u8 command_13v[1]={0x00};
-	static u8 command_18v[1]={0x01};
-	struct i2c_msg msg[] = {
-		{.addr = ADDR_B600_VOLTAGE_13V,.flags = 0,.buf = command_13v,.len = 1},
-	};
-	struct dvb_usb_adapter *udev_adap =
-	    (struct dvb_usb_adapter *)(fe->dvb->priv);
-	if (voltage == SEC_VOLTAGE_18) {
-		msg[0].addr = ADDR_B601_VOLTAGE_18V;
-		msg[0].buf = command_18v;
-	}
-	i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
-	return 0;
-}
-
-static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate,
-					  u32 ratio)
-{
-	stv0299_writereg(fe, 0x13, 0x98);
-	stv0299_writereg(fe, 0x14, 0x95);
-	stv0299_writereg(fe, REG_1F_SYMBOLRATE_BYTE0, (ratio >> 16) & 0xff);
-	stv0299_writereg(fe, REG_20_SYMBOLRATE_BYTE1, (ratio >> 8) & 0xff);
-	stv0299_writereg(fe, REG_21_SYMBOLRATE_BYTE2, (ratio) & 0xf0);
-	return 0;
-
-}
-static u8 opera1_inittab[] = {
-	0x00, 0xa1,
-	0x01, 0x15,
-	0x02, 0x30,
-	0x03, 0x00,
-	0x04, 0x7d,
-	0x05, 0x05,
-	0x06, 0x02,
-	0x07, 0x00,
-	0x0b, 0x00,
-	0x0c, 0x01,
-	0x0d, 0x81,
-	0x0e, 0x44,
-	0x0f, 0x19,
-	0x10, 0x3f,
-	0x11, 0x84,
-	0x12, 0xda,
-	0x13, 0x98,
-	0x14, 0x95,
-	0x15, 0xc9,
-	0x16, 0xeb,
-	0x17, 0x00,
-	0x18, 0x19,
-	0x19, 0x8b,
-	0x1a, 0x00,
-	0x1b, 0x82,
-	0x1c, 0x7f,
-	0x1d, 0x00,
-	0x1e, 0x00,
-	REG_1F_SYMBOLRATE_BYTE0, 0x06,
-	REG_20_SYMBOLRATE_BYTE1, 0x50,
-	REG_21_SYMBOLRATE_BYTE2, 0x10,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x24, 0x37,
-	0x25, 0xbc,
-	0x26, 0x00,
-	0x27, 0x00,
-	0x28, 0x00,
-	0x29, 0x1e,
-	0x2a, 0x14,
-	0x2b, 0x1f,
-	0x2c, 0x09,
-	0x2d, 0x0a,
-	0x2e, 0x00,
-	0x2f, 0x00,
-	0x30, 0x00,
-	0x31, 0x1f,
-	0x32, 0x19,
-	0x33, 0xfc,
-	0x34, 0x13,
-	0xff, 0xff,
-};
-
-static struct stv0299_config opera1_stv0299_config = {
-	.demod_address = 0xd0>>1,
-	.min_delay_ms = 100,
-	.mclk = 88000000UL,
-	.invert = 1,
-	.skip_reinit = 0,
-	.lock_output = STV0299_LOCKOUTPUT_0,
-	.volt13_op0_op1 = STV0299_VOLT13_OP0,
-	.inittab = opera1_inittab,
-	.set_symbol_rate = opera1_stv0299_set_symbol_rate,
-};
-
-static int opera1_frontend_attach(struct dvb_usb_adapter *d)
-{
-	d->fe_adap[0].fe = dvb_attach(stv0299_attach, &opera1_stv0299_config,
-				      &d->dev->i2c_adap);
-	if ((d->fe_adap[0].fe) != NULL) {
-		d->fe_adap[0].fe->ops.set_voltage = opera1_set_voltage;
-		return 0;
-	}
-	info("not attached stv0299");
-	return -EIO;
-}
-
-static int opera1_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	dvb_attach(
-		dvb_pll_attach, adap->fe_adap[0].fe, 0xc0>>1,
-		&adap->dev->i2c_adap, DVB_PLL_OPERA1
-	);
-	return 0;
-}
-
-static int opera1_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	u8 val = onoff ? 0x01 : 0x00;
-
-	if (dvb_usb_opera1_debug)
-		info("power %s", onoff ? "on" : "off");
-	return opera1_xilinx_rw(d->udev, 0xb7, val,
-				&val, 1, OPERA_WRITE_MSG);
-}
-
-static int opera1_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	static u8 buf_start[2] = { 0xff, 0x03 };
-	static u8 buf_stop[2] = { 0xff, 0x00 };
-	struct i2c_msg start_tuner[] = {
-		{.addr = ADDR_B1A6_STREAM_CTRL,.buf = onoff ? buf_start : buf_stop,.len = 2},
-	};
-	if (dvb_usb_opera1_debug)
-		info("streaming %s", onoff ? "on" : "off");
-	i2c_transfer(&adap->dev->i2c_adap, start_tuner, 1);
-	return 0;
-}
-
-static int opera1_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
-			     int onoff)
-{
-	u8 b_pid[3];
-	struct i2c_msg msg[] = {
-		{.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3},
-	};
-	if (dvb_usb_opera1_debug)
-		info("pidfilter index: %d pid: %d %s", index, pid,
-			onoff ? "on" : "off");
-	b_pid[0] = (2 * index) + 4;
-	b_pid[1] = onoff ? (pid & 0xff) : (0x00);
-	b_pid[2] = onoff ? ((pid >> 8) & 0xff) : (0x00);
-	i2c_transfer(&adap->dev->i2c_adap, msg, 1);
-	return 0;
-}
-
-static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
-{
-	int u = 0x04;
-	u8 b_pid[3];
-	struct i2c_msg msg[] = {
-		{.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3},
-	};
-	if (dvb_usb_opera1_debug)
-		info("%s hw-pidfilter", onoff ? "enable" : "disable");
-	for (; u < 0x7e; u += 2) {
-		b_pid[0] = u;
-		b_pid[1] = 0;
-		b_pid[2] = 0x80;
-		i2c_transfer(&adap->dev->i2c_adap, msg, 1);
-	}
-	return 0;
-}
-
-static struct rc_map_table rc_map_opera1_table[] = {
-	{0x5fa0, KEY_1},
-	{0x51af, KEY_2},
-	{0x5da2, KEY_3},
-	{0x41be, KEY_4},
-	{0x0bf5, KEY_5},
-	{0x43bd, KEY_6},
-	{0x47b8, KEY_7},
-	{0x49b6, KEY_8},
-	{0x05fa, KEY_9},
-	{0x45ba, KEY_0},
-	{0x09f6, KEY_CHANNELUP},	/*chanup */
-	{0x1be5, KEY_CHANNELDOWN},	/*chandown */
-	{0x5da3, KEY_VOLUMEDOWN},	/*voldown */
-	{0x5fa1, KEY_VOLUMEUP},		/*volup */
-	{0x07f8, KEY_SPACE},		/*tab */
-	{0x1fe1, KEY_OK},		/*play ok */
-	{0x1be4, KEY_ZOOM},		/*zoom */
-	{0x59a6, KEY_MUTE},		/*mute */
-	{0x5ba5, KEY_RADIO},		/*tv/f */
-	{0x19e7, KEY_RECORD},		/*rec */
-	{0x01fe, KEY_STOP},		/*Stop */
-	{0x03fd, KEY_PAUSE},		/*pause */
-	{0x03fc, KEY_SCREEN},		/*<- -> */
-	{0x07f9, KEY_CAMERA},		/*capture */
-	{0x47b9, KEY_ESC},		/*exit */
-	{0x43bc, KEY_POWER2},		/*power */
-};
-
-static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state)
-{
-	struct opera1_state *opst = dev->priv;
-	u8 rcbuffer[32];
-	const u16 startmarker1 = 0x10ed;
-	const u16 startmarker2 = 0x11ec;
-	struct i2c_msg read_remote[] = {
-		{.addr = ADDR_B880_READ_REMOTE,.buf = rcbuffer,.flags = I2C_M_RD,.len = 32},
-	};
-	int i = 0;
-	u32 send_key = 0;
-
-	if (i2c_transfer(&dev->i2c_adap, read_remote, 1) == 1) {
-		for (i = 0; i < 32; i++) {
-			if (rcbuffer[i])
-				send_key |= 1;
-			if (i < 31)
-				send_key = send_key << 1;
-		}
-		if (send_key & 0x8000)
-			send_key = (send_key << 1) | (send_key >> 15 & 0x01);
-
-		if (send_key == 0xffff && opst->last_key_pressed != 0) {
-			*state = REMOTE_KEY_REPEAT;
-			*event = opst->last_key_pressed;
-			return 0;
-		}
-		for (; send_key != 0;) {
-			if (send_key >> 16 == startmarker2) {
-				break;
-			} else if (send_key >> 16 == startmarker1) {
-				send_key =
-					(send_key & 0xfffeffff) | (startmarker1 << 16);
-				break;
-			} else
-				send_key >>= 1;
-		}
-
-		if (send_key == 0)
-			return 0;
-
-		send_key = (send_key & 0xffff) | 0x0100;
-
-		for (i = 0; i < ARRAY_SIZE(rc_map_opera1_table); i++) {
-			if (rc5_scan(&rc_map_opera1_table[i]) == (send_key & 0xffff)) {
-				*state = REMOTE_KEY_PRESSED;
-				*event = rc_map_opera1_table[i].keycode;
-				opst->last_key_pressed =
-					rc_map_opera1_table[i].keycode;
-				break;
-			}
-			opst->last_key_pressed = 0;
-		}
-	} else
-		*state = REMOTE_NO_KEY_PRESSED;
-	return 0;
-}
-
-static struct usb_device_id opera1_table[] = {
-	{USB_DEVICE(USB_VID_CYPRESS, USB_PID_OPERA1_COLD)},
-	{USB_DEVICE(USB_VID_OPERA1, USB_PID_OPERA1_WARM)},
-	{}
-};
-
-MODULE_DEVICE_TABLE(usb, opera1_table);
-
-static int opera1_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
-{
-	u8 command[] = { READ_MAC_ADDR };
-	opera1_xilinx_rw(d->udev, 0xb1, 0xa0, command, 1, OPERA_WRITE_MSG);
-	opera1_xilinx_rw(d->udev, 0xb1, 0xa1, mac, 6, OPERA_READ_MSG);
-	return 0;
-}
-static int opera1_xilinx_load_firmware(struct usb_device *dev,
-				       const char *filename)
-{
-	const struct firmware *fw = NULL;
-	u8 *b, *p;
-	int ret = 0, i,fpgasize=40;
-	u8 testval;
-	info("start downloading fpga firmware %s",filename);
-
-	if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) {
-		err("did not find the firmware file. (%s) "
-			"Please see linux/Documentation/dvb/ for more details on firmware-problems.",
-			filename);
-		return ret;
-	} else {
-		p = kmalloc(fw->size, GFP_KERNEL);
-		opera1_xilinx_rw(dev, 0xbc, 0x00, &testval, 1, OPERA_READ_MSG);
-		if (p != NULL && testval != 0x67) {
-
-			u8 reset = 0, fpga_command = 0;
-			memcpy(p, fw->data, fw->size);
-			/* clear fpga ? */
-			opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1,
-					 OPERA_WRITE_MSG);
-			for (i = 0; i < fw->size;) {
-				if ( (fw->size - i) <fpgasize){
-				    fpgasize=fw->size-i;
-				}
-				b = (u8 *) p + i;
-				if (opera1_xilinx_rw
-					(dev, OPERA_WRITE_FX2, 0x0, b , fpgasize,
-						OPERA_WRITE_MSG) != fpgasize
-					) {
-					err("error while transferring firmware");
-					ret = -EINVAL;
-					break;
-				}
-				i = i + fpgasize;
-			}
-			/* restart the CPU */
-			if (ret || opera1_xilinx_rw
-					(dev, 0xa0, 0xe600, &reset, 1,
-					OPERA_WRITE_MSG) != 1) {
-				err("could not restart the USB controller CPU.");
-				ret = -EINVAL;
-			}
-		}
-	}
-	kfree(p);
-	release_firmware(fw);
-	return ret;
-}
-
-static struct dvb_usb_device_properties opera1_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware = "dvb-usb-opera-01.fw",
-	.size_of_priv = sizeof(struct opera1_state),
-
-	.power_ctrl = opera1_power_ctrl,
-	.i2c_algo = &opera1_i2c_algo,
-
-	.rc.legacy = {
-		.rc_map_table = rc_map_opera1_table,
-		.rc_map_size = ARRAY_SIZE(rc_map_opera1_table),
-		.rc_interval = 200,
-		.rc_query = opera1_rc_query,
-	},
-	.read_mac_address = opera1_read_mac_address,
-	.generic_bulk_ctrl_endpoint = 0x00,
-	/* parameter for the MPEG2-data transfer */
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.frontend_attach = opera1_frontend_attach,
-			.streaming_ctrl = opera1_streaming_ctrl,
-			.tuner_attach = opera1_tuner_attach,
-			.caps =
-				DVB_USB_ADAP_HAS_PID_FILTER |
-				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-			.pid_filter = opera1_pid_filter,
-			.pid_filter_ctrl = opera1_pid_filter_control,
-			.pid_filter_count = 252,
-			.stream = {
-				.type = USB_BULK,
-				.count = 10,
-				.endpoint = 0x82,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-		}
-	},
-	.num_device_descs = 1,
-	.devices = {
-		{"Opera1 DVB-S USB2.0",
-			{&opera1_table[0], NULL},
-			{&opera1_table[1], NULL},
-		},
-	}
-};
-
-static int opera1_probe(struct usb_interface *intf,
-			const struct usb_device_id *id)
-{
-	struct usb_device *udev = interface_to_usbdev(intf);
-
-	if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM &&
-		udev->descriptor.idVendor == USB_VID_OPERA1 &&
-		opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0
-	    ) {
-		return -EINVAL;
-	}
-
-	if (0 != dvb_usb_device_init(intf, &opera1_properties,
-				     THIS_MODULE, NULL, adapter_nr))
-		return -EINVAL;
-	return 0;
-}
-
-static struct usb_driver opera1_driver = {
-	.name = "opera1",
-	.probe = opera1_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table = opera1_table,
-};
-
-module_usb_driver(opera1_driver);
-
-MODULE_AUTHOR("Mario Hlawitschka (c) dh1pa@amsat.org");
-MODULE_AUTHOR("Marco Gittler (c) g.marco@freenet.de");
-MODULE_DESCRIPTION("Driver for Opera1 DVB-S device");
-MODULE_VERSION("0.1");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/pctv452e.c b/drivers/media/dvb/dvb-usb/pctv452e.c
deleted file mode 100644
index f526eb0..0000000
--- a/drivers/media/dvb/dvb-usb/pctv452e.c
+++ /dev/null
@@ -1,1064 +0,0 @@
-/*
- * PCTV 452e DVB driver
- *
- * Copyright (c) 2006-2008 Dominik Kuhlen <dkuhlen@gmx.net>
- *
- * TT connect S2-3650-CI Common Interface support, MAC readout
- * Copyright (C) 2008 Michael H. Schimek <mschimek@gmx.at>
- *
- * 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.
- */
-
-/* dvb usb framework */
-#define DVB_USB_LOG_PREFIX "pctv452e"
-#include "dvb-usb.h"
-
-/* Demodulator */
-#include "stb0899_drv.h"
-#include "stb0899_reg.h"
-#include "stb0899_cfg.h"
-/* Tuner */
-#include "stb6100.h"
-#include "stb6100_cfg.h"
-/* FE Power */
-#include "lnbp22.h"
-
-#include "dvb_ca_en50221.h"
-#include "ttpci-eeprom.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define ISOC_INTERFACE_ALTERNATIVE 3
-
-#define SYNC_BYTE_OUT 0xaa
-#define SYNC_BYTE_IN  0x55
-
-/* guessed: (copied from ttusb-budget) */
-#define PCTV_CMD_RESET 0x15
-/* command to poll IR receiver */
-#define PCTV_CMD_IR    0x1b
-/* command to send I2C  */
-#define PCTV_CMD_I2C   0x31
-
-#define I2C_ADDR_STB0899 (0xd0 >> 1)
-#define I2C_ADDR_STB6100 (0xc0 >> 1)
-#define I2C_ADDR_LNBP22  (0x10 >> 1)
-#define I2C_ADDR_24C16   (0xa0 >> 1)
-#define I2C_ADDR_24C64   (0xa2 >> 1)
-
-
-/* pctv452e sends us this amount of data for each issued usb-command */
-#define PCTV_ANSWER_LEN 64
-/* Wait up to 1000ms for device  */
-#define PCTV_TIMEOUT 1000
-
-
-#define PCTV_LED_GPIO   STB0899_GPIO01
-#define PCTV_LED_GREEN  0x82
-#define PCTV_LED_ORANGE 0x02
-
-#define ci_dbg(format, arg...)				\
-do {							\
-	if (0)						\
-		printk(KERN_DEBUG DVB_USB_LOG_PREFIX	\
-			": " format "\n" , ## arg);	\
-} while (0)
-
-enum {
-	TT3650_CMD_CI_TEST = 0x40,
-	TT3650_CMD_CI_RD_CTRL,
-	TT3650_CMD_CI_WR_CTRL,
-	TT3650_CMD_CI_RD_ATTR,
-	TT3650_CMD_CI_WR_ATTR,
-	TT3650_CMD_CI_RESET,
-	TT3650_CMD_CI_SET_VIDEO_PORT
-};
-
-
-static struct stb0899_postproc pctv45e_postproc[] = {
-	{ PCTV_LED_GPIO, STB0899_GPIOPULLUP },
-	{ 0, 0 }
-};
-
-/*
- * stores all private variables for communication with the PCTV452e DVB-S2
- */
-struct pctv452e_state {
-	struct dvb_ca_en50221 ca;
-	struct mutex ca_mutex;
-
-	u8 c;	   /* transaction counter, wraps around...  */
-	u8 initialized; /* set to 1 if 0x15 has been sent */
-	u16 last_rc_key;
-};
-
-static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data,
-			 unsigned int write_len, unsigned int read_len)
-{
-	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
-	u8 buf[64];
-	u8 id;
-	unsigned int rlen;
-	int ret;
-
-	BUG_ON(NULL == data && 0 != (write_len | read_len));
-	BUG_ON(write_len > 64 - 4);
-	BUG_ON(read_len > 64 - 4);
-
-	id = state->c++;
-
-	buf[0] = SYNC_BYTE_OUT;
-	buf[1] = id;
-	buf[2] = cmd;
-	buf[3] = write_len;
-
-	memcpy(buf + 4, data, write_len);
-
-	rlen = (read_len > 0) ? 64 : 0;
-	ret = dvb_usb_generic_rw(d, buf, 4 + write_len,
-				  buf, rlen, /* delay_ms */ 0);
-	if (0 != ret)
-		goto failed;
-
-	ret = -EIO;
-	if (SYNC_BYTE_IN != buf[0] || id != buf[1])
-		goto failed;
-
-	memcpy(data, buf + 4, read_len);
-
-	return 0;
-
-failed:
-	err("CI error %d; %02X %02X %02X -> %02X %02X %02X.",
-	     ret, SYNC_BYTE_OUT, id, cmd, buf[0], buf[1], buf[2]);
-
-	return ret;
-}
-
-static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca,
-				u8 cmd, u8 *data, unsigned int write_len,
-				unsigned int read_len)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
-	int ret;
-
-	mutex_lock(&state->ca_mutex);
-	ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
-	mutex_unlock(&state->ca_mutex);
-
-	return ret;
-}
-
-static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
-				 int slot, int address)
-{
-	u8 buf[3];
-	int ret;
-
-	if (0 != slot)
-		return -EINVAL;
-
-	buf[0] = (address >> 8) & 0x0F;
-	buf[1] = address;
-
-	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
-
-	ci_dbg("%s %04x -> %d 0x%02x",
-		__func__, address, ret, buf[2]);
-
-	if (ret < 0)
-		return ret;
-
-	return buf[2];
-}
-
-static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
-				 int slot, int address, u8 value)
-{
-	u8 buf[3];
-
-	ci_dbg("%s %d 0x%04x 0x%02x",
-		__func__, slot, address, value);
-
-	if (0 != slot)
-		return -EINVAL;
-
-	buf[0] = (address >> 8) & 0x0F;
-	buf[1] = address;
-	buf[2] = value;
-
-	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
-}
-
-static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca,
-				 int			slot,
-				 u8			address)
-{
-	u8 buf[2];
-	int ret;
-
-	if (0 != slot)
-		return -EINVAL;
-
-	buf[0] = address & 3;
-
-	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
-
-	ci_dbg("%s 0x%02x -> %d 0x%02x",
-		__func__, address, ret, buf[1]);
-
-	if (ret < 0)
-		return ret;
-
-	return buf[1];
-}
-
-static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca,
-				 int			slot,
-				 u8			address,
-				 u8			value)
-{
-	u8 buf[2];
-
-	ci_dbg("%s %d 0x%02x 0x%02x",
-		__func__, slot, address, value);
-
-	if (0 != slot)
-		return -EINVAL;
-
-	buf[0] = address;
-	buf[1] = value;
-
-	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
-}
-
-static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca,
-				 int			slot,
-				 int			enable)
-{
-	u8 buf[1];
-	int ret;
-
-	ci_dbg("%s %d %d", __func__, slot, enable);
-
-	if (0 != slot)
-		return -EINVAL;
-
-	enable = !!enable;
-	buf[0] = enable;
-
-	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
-	if (ret < 0)
-		return ret;
-
-	if (enable != buf[0]) {
-		err("CI not %sabled.", enable ? "en" : "dis");
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
-{
-	return tt3650_ci_set_video_port(ca, slot, /* enable */ 0);
-}
-
-static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
-{
-	return tt3650_ci_set_video_port(ca, slot, /* enable */ 1);
-}
-
-static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
-{
-	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
-	u8 buf[1];
-	int ret;
-
-	ci_dbg("%s %d", __func__, slot);
-
-	if (0 != slot)
-		return -EINVAL;
-
-	buf[0] = 0;
-
-	mutex_lock(&state->ca_mutex);
-
-	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
-	if (0 != ret)
-		goto failed;
-
-	msleep(500);
-
-	buf[0] = 1;
-
-	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
-	if (0 != ret)
-		goto failed;
-
-	msleep(500);
-
-	buf[0] = 0; /* FTA */
-
-	ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
-
- failed:
-	mutex_unlock(&state->ca_mutex);
-
-	return ret;
-}
-
-static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca,
-				 int			slot,
-				 int			open)
-{
-	u8 buf[1];
-	int ret;
-
-	if (0 != slot)
-		return -EINVAL;
-
-	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
-	if (0 != ret)
-		return ret;
-
-	if (1 == buf[0])
-		return DVB_CA_EN50221_POLL_CAM_PRESENT |
-			DVB_CA_EN50221_POLL_CAM_READY;
-
-	return 0;
-
-}
-
-static void tt3650_ci_uninit(struct dvb_usb_device *d)
-{
-	struct pctv452e_state *state;
-
-	ci_dbg("%s", __func__);
-
-	if (NULL == d)
-		return;
-
-	state = (struct pctv452e_state *)d->priv;
-	if (NULL == state)
-		return;
-
-	if (NULL == state->ca.data)
-		return;
-
-	/* Error ignored. */
-	tt3650_ci_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0);
-
-	dvb_ca_en50221_release(&state->ca);
-
-	memset(&state->ca, 0, sizeof(state->ca));
-}
-
-static int tt3650_ci_init(struct dvb_usb_adapter *a)
-{
-	struct dvb_usb_device *d = a->dev;
-	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
-	int ret;
-
-	ci_dbg("%s", __func__);
-
-	mutex_init(&state->ca_mutex);
-
-	state->ca.owner = THIS_MODULE;
-	state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
-	state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
-	state->ca.read_cam_control = tt3650_ci_read_cam_control;
-	state->ca.write_cam_control = tt3650_ci_write_cam_control;
-	state->ca.slot_reset = tt3650_ci_slot_reset;
-	state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
-	state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
-	state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
-	state->ca.data = d;
-
-	ret = dvb_ca_en50221_init(&a->dvb_adap,
-				   &state->ca,
-				   /* flags */ 0,
-				   /* n_slots */ 1);
-	if (0 != ret) {
-		err("Cannot initialize CI: Error %d.", ret);
-		memset(&state->ca, 0, sizeof(state->ca));
-		return ret;
-	}
-
-	info("CI initialized.");
-
-	return 0;
-}
-
-#define CMD_BUFFER_SIZE 0x28
-static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr,
-				const u8 *snd_buf, u8 snd_len,
-				u8 *rcv_buf, u8 rcv_len)
-{
-	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
-	u8 buf[64];
-	u8 id;
-	int ret;
-
-	id = state->c++;
-
-	ret = -EINVAL;
-	if (snd_len > 64 - 7 || rcv_len > 64 - 7)
-		goto failed;
-
-	buf[0] = SYNC_BYTE_OUT;
-	buf[1] = id;
-	buf[2] = PCTV_CMD_I2C;
-	buf[3] = snd_len + 3;
-	buf[4] = addr << 1;
-	buf[5] = snd_len;
-	buf[6] = rcv_len;
-
-	memcpy(buf + 7, snd_buf, snd_len);
-
-	ret = dvb_usb_generic_rw(d, buf, 7 + snd_len,
-				  buf, /* rcv_len */ 64,
-				  /* delay_ms */ 0);
-	if (ret < 0)
-		goto failed;
-
-	/* TT USB protocol error. */
-	ret = -EIO;
-	if (SYNC_BYTE_IN != buf[0] || id != buf[1])
-		goto failed;
-
-	/* I2C device didn't respond as expected. */
-	ret = -EREMOTEIO;
-	if (buf[5] < snd_len || buf[6] < rcv_len)
-		goto failed;
-
-	memcpy(rcv_buf, buf + 7, rcv_len);
-
-	return rcv_len;
-
-failed:
-	err("I2C error %d; %02X %02X  %02X %02X %02X -> "
-	     "%02X %02X  %02X %02X %02X.",
-	     ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len,
-	     buf[0], buf[1], buf[4], buf[5], buf[6]);
-
-	return ret;
-}
-
-static int pctv452e_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg,
-				int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adapter);
-	int i;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	for (i = 0; i < num; i++) {
-		u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf;
-		int ret;
-
-		if (msg[i].flags & I2C_M_RD) {
-			addr = msg[i].addr;
-			snd_buf = NULL;
-			snd_len = 0;
-			rcv_buf = msg[i].buf;
-			rcv_len = msg[i].len;
-		} else {
-			addr = msg[i].addr;
-			snd_buf = msg[i].buf;
-			snd_len = msg[i].len;
-			rcv_buf = NULL;
-			rcv_len = 0;
-		}
-
-		ret = pctv452e_i2c_msg(d, addr, snd_buf, snd_len, rcv_buf,
-					rcv_len);
-		if (ret < rcv_len)
-			break;
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return i;
-}
-
-static u32 pctv452e_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i)
-{
-	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
-	u8 b0[] = { 0xaa, 0, PCTV_CMD_RESET, 1, 0 };
-	u8 rx[PCTV_ANSWER_LEN];
-	int ret;
-
-	info("%s: %d\n", __func__, i);
-
-	if (!i)
-		return 0;
-
-	if (state->initialized)
-		return 0;
-
-	/* hmm where shoud this should go? */
-	ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE);
-	if (ret != 0)
-		info("%s: Warning set interface returned: %d\n",
-			__func__, ret);
-
-	/* this is a one-time initialization, dont know where to put */
-	b0[1] = state->c++;
-	/* reset board */
-	ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0);
-	if (ret)
-		return ret;
-
-	b0[1] = state->c++;
-	b0[4] = 1;
-	/* reset board (again?) */
-	ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0);
-	if (ret)
-		return ret;
-
-	state->initialized = 1;
-
-	return 0;
-}
-
-static int pctv452e_rc_query(struct dvb_usb_device *d)
-{
-	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
-	u8 b[CMD_BUFFER_SIZE];
-	u8 rx[PCTV_ANSWER_LEN];
-	int ret, i;
-	u8 id = state->c++;
-
-	/* prepare command header  */
-	b[0] = SYNC_BYTE_OUT;
-	b[1] = id;
-	b[2] = PCTV_CMD_IR;
-	b[3] = 0;
-
-	/* send ir request */
-	ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0);
-	if (ret != 0)
-		return ret;
-
-	if (debug > 3) {
-		info("%s: read: %2d: %02x %02x %02x: ", __func__,
-				ret, rx[0], rx[1], rx[2]);
-		for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++)
-			info(" %02x", rx[i+3]);
-
-		info("\n");
-	}
-
-	if ((rx[3] == 9) &&  (rx[12] & 0x01)) {
-		/* got a "press" event */
-		state->last_rc_key = (rx[7] << 8) | rx[6];
-		if (debug > 2)
-			info("%s: cmd=0x%02x sys=0x%02x\n",
-				__func__, rx[6], rx[7]);
-
-		rc_keydown(d->rc_dev, state->last_rc_key, 0);
-	} else if (state->last_rc_key) {
-		rc_keyup(d->rc_dev);
-		state->last_rc_key = 0;
-	}
-
-	return 0;
-}
-
-static int pctv452e_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
-{
-	const u8 mem_addr[] = { 0x1f, 0xcc };
-	u8 encoded_mac[20];
-	int ret;
-
-	ret = -EAGAIN;
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		goto failed;
-
-	ret = pctv452e_i2c_msg(d, I2C_ADDR_24C16,
-				mem_addr + 1, /* snd_len */ 1,
-				encoded_mac, /* rcv_len */ 20);
-	if (-EREMOTEIO == ret)
-		/* Caution! A 24C16 interprets 0xA2 0x1F 0xCC as a
-		   byte write if /WC is low. */
-		ret = pctv452e_i2c_msg(d, I2C_ADDR_24C64,
-					mem_addr, 2,
-					encoded_mac, 20);
-
-	mutex_unlock(&d->i2c_mutex);
-
-	if (20 != ret)
-		goto failed;
-
-	ret = ttpci_eeprom_decode_mac(mac, encoded_mac);
-	if (0 != ret)
-		goto failed;
-
-	return 0;
-
-failed:
-	memset(mac, 0, 6);
-
-	return ret;
-}
-
-static const struct stb0899_s1_reg pctv452e_init_dev[] = {
-	{ STB0899_DISCNTRL1,	0x26 },
-	{ STB0899_DISCNTRL2,	0x80 },
-	{ STB0899_DISRX_ST0,	0x04 },
-	{ STB0899_DISRX_ST1,	0x20 },
-	{ STB0899_DISPARITY,	0x00 },
-	{ STB0899_DISFIFO,	0x00 },
-	{ STB0899_DISF22,	0x99 },
-	{ STB0899_DISF22RX,	0x85 }, /* 0xa8 */
-	{ STB0899_ACRPRESC,	0x11 },
-	{ STB0899_ACRDIV1,	0x0a },
-	{ STB0899_ACRDIV2,	0x05 },
-	{ STB0899_DACR1	,	0x00 },
-	{ STB0899_DACR2	,	0x00 },
-	{ STB0899_OUTCFG,	0x00 },
-	{ STB0899_MODECFG,	0x00 }, /* Inversion */
-	{ STB0899_IRQMSK_3,	0xf3 },
-	{ STB0899_IRQMSK_2,	0xfc },
-	{ STB0899_IRQMSK_1,	0xff },
-	{ STB0899_IRQMSK_0,	0xff },
-	{ STB0899_I2CCFG,	0x88 },
-	{ STB0899_I2CRPT,	0x58 },
-	{ STB0899_GPIO00CFG,	0x82 },
-	{ STB0899_GPIO01CFG,	0x82 }, /* LED: 0x02 green, 0x82 orange */
-	{ STB0899_GPIO02CFG,	0x82 },
-	{ STB0899_GPIO03CFG,	0x82 },
-	{ STB0899_GPIO04CFG,	0x82 },
-	{ STB0899_GPIO05CFG,	0x82 },
-	{ STB0899_GPIO06CFG,	0x82 },
-	{ STB0899_GPIO07CFG,	0x82 },
-	{ STB0899_GPIO08CFG,	0x82 },
-	{ STB0899_GPIO09CFG,	0x82 },
-	{ STB0899_GPIO10CFG,	0x82 },
-	{ STB0899_GPIO11CFG,	0x82 },
-	{ STB0899_GPIO12CFG,	0x82 },
-	{ STB0899_GPIO13CFG,	0x82 },
-	{ STB0899_GPIO14CFG,	0x82 },
-	{ STB0899_GPIO15CFG,	0x82 },
-	{ STB0899_GPIO16CFG,	0x82 },
-	{ STB0899_GPIO17CFG,	0x82 },
-	{ STB0899_GPIO18CFG,	0x82 },
-	{ STB0899_GPIO19CFG,	0x82 },
-	{ STB0899_GPIO20CFG,	0x82 },
-	{ STB0899_SDATCFG,	0xb8 },
-	{ STB0899_SCLTCFG,	0xba },
-	{ STB0899_AGCRFCFG,	0x1c }, /* 0x11 DVB-S; 0x1c DVB-S2 (1c, rjkm) */
-	{ STB0899_GPIO22,	0x82 },
-	{ STB0899_GPIO21,	0x91 },
-	{ STB0899_DIRCLKCFG,	0x82 },
-	{ STB0899_CLKOUT27CFG,	0x7e },
-	{ STB0899_STDBYCFG,	0x82 },
-	{ STB0899_CS0CFG,	0x82 },
-	{ STB0899_CS1CFG,	0x82 },
-	{ STB0899_DISEQCOCFG,	0x20 },
-	{ STB0899_NCOARSE,	0x15 }, /* 0x15 27Mhz, F/3 198MHz, F/6 108MHz */
-	{ STB0899_SYNTCTRL,	0x00 }, /* 0x00 CLKI, 0x02 XTALI */
-	{ STB0899_FILTCTRL,	0x00 },
-	{ STB0899_SYSCTRL,	0x00 },
-	{ STB0899_STOPCLK1,	0x20 }, /* orig: 0x00 budget-ci: 0x20 */
-	{ STB0899_STOPCLK2,	0x00 },
-	{ STB0899_INTBUFCTRL,	0x0a },
-	{ STB0899_AGC2I1,	0x00 },
-	{ STB0899_AGC2I2,	0x00 },
-	{ STB0899_AGCIQIN,	0x00 },
-	{ STB0899_TSTRES,	0x40 }, /* rjkm */
-	{ 0xffff,		0xff },
-};
-
-static const struct stb0899_s1_reg pctv452e_init_s1_demod[] = {
-	{ STB0899_DEMOD,	0x00 },
-	{ STB0899_RCOMPC,	0xc9 },
-	{ STB0899_AGC1CN,	0x01 },
-	{ STB0899_AGC1REF,	0x10 },
-	{ STB0899_RTC,		0x23 },
-	{ STB0899_TMGCFG,	0x4e },
-	{ STB0899_AGC2REF,	0x34 },
-	{ STB0899_TLSR,		0x84 },
-	{ STB0899_CFD,		0xf7 },
-	{ STB0899_ACLC,		0x87 },
-	{ STB0899_BCLC,		0x94 },
-	{ STB0899_EQON,		0x41 },
-	{ STB0899_LDT,		0xf1 },
-	{ STB0899_LDT2,		0xe3 },
-	{ STB0899_EQUALREF,	0xb4 },
-	{ STB0899_TMGRAMP,	0x10 },
-	{ STB0899_TMGTHD,	0x30 },
-	{ STB0899_IDCCOMP,	0xfd },
-	{ STB0899_QDCCOMP,	0xff },
-	{ STB0899_POWERI,	0x0c },
-	{ STB0899_POWERQ,	0x0f },
-	{ STB0899_RCOMP,	0x6c },
-	{ STB0899_AGCIQIN,	0x80 },
-	{ STB0899_AGC2I1,	0x06 },
-	{ STB0899_AGC2I2,	0x00 },
-	{ STB0899_TLIR,		0x30 },
-	{ STB0899_RTF,		0x7f },
-	{ STB0899_DSTATUS,	0x00 },
-	{ STB0899_LDI,		0xbc },
-	{ STB0899_CFRM,		0xea },
-	{ STB0899_CFRL,		0x31 },
-	{ STB0899_NIRM,		0x2b },
-	{ STB0899_NIRL,		0x80 },
-	{ STB0899_ISYMB,	0x1d },
-	{ STB0899_QSYMB,	0xa6 },
-	{ STB0899_SFRH,		0x2f },
-	{ STB0899_SFRM,		0x68 },
-	{ STB0899_SFRL,		0x40 },
-	{ STB0899_SFRUPH,	0x2f },
-	{ STB0899_SFRUPM,	0x68 },
-	{ STB0899_SFRUPL,	0x40 },
-	{ STB0899_EQUAI1,	0x02 },
-	{ STB0899_EQUAQ1,	0xff },
-	{ STB0899_EQUAI2,	0x04 },
-	{ STB0899_EQUAQ2,	0x05 },
-	{ STB0899_EQUAI3,	0x02 },
-	{ STB0899_EQUAQ3,	0xfd },
-	{ STB0899_EQUAI4,	0x03 },
-	{ STB0899_EQUAQ4,	0x07 },
-	{ STB0899_EQUAI5,	0x08 },
-	{ STB0899_EQUAQ5,	0xf5 },
-	{ STB0899_DSTATUS2,	0x00 },
-	{ STB0899_VSTATUS,	0x00 },
-	{ STB0899_VERROR,	0x86 },
-	{ STB0899_IQSWAP,	0x2a },
-	{ STB0899_ECNT1M,	0x00 },
-	{ STB0899_ECNT1L,	0x00 },
-	{ STB0899_ECNT2M,	0x00 },
-	{ STB0899_ECNT2L,	0x00 },
-	{ STB0899_ECNT3M,	0x0a },
-	{ STB0899_ECNT3L,	0xad },
-	{ STB0899_FECAUTO1,	0x06 },
-	{ STB0899_FECM,		0x01 },
-	{ STB0899_VTH12,	0xb0 },
-	{ STB0899_VTH23,	0x7a },
-	{ STB0899_VTH34,	0x58 },
-	{ STB0899_VTH56,	0x38 },
-	{ STB0899_VTH67,	0x34 },
-	{ STB0899_VTH78,	0x24 },
-	{ STB0899_PRVIT,	0xff },
-	{ STB0899_VITSYNC,	0x19 },
-	{ STB0899_RSULC,	0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
-	{ STB0899_TSULC,	0x42 },
-	{ STB0899_RSLLC,	0x41 },
-	{ STB0899_TSLPL,	0x12 },
-	{ STB0899_TSCFGH,	0x0c },
-	{ STB0899_TSCFGM,	0x00 },
-	{ STB0899_TSCFGL,	0x00 },
-	{ STB0899_TSOUT,	0x69 }, /* 0x0d for CAM */
-	{ STB0899_RSSYNCDEL,	0x00 },
-	{ STB0899_TSINHDELH,	0x02 },
-	{ STB0899_TSINHDELM,	0x00 },
-	{ STB0899_TSINHDELL,	0x00 },
-	{ STB0899_TSLLSTKM,	0x1b },
-	{ STB0899_TSLLSTKL,	0xb3 },
-	{ STB0899_TSULSTKM,	0x00 },
-	{ STB0899_TSULSTKL,	0x00 },
-	{ STB0899_PCKLENUL,	0xbc },
-	{ STB0899_PCKLENLL,	0xcc },
-	{ STB0899_RSPCKLEN,	0xbd },
-	{ STB0899_TSSTATUS,	0x90 },
-	{ STB0899_ERRCTRL1,	0xb6 },
-	{ STB0899_ERRCTRL2,	0x95 },
-	{ STB0899_ERRCTRL3,	0x8d },
-	{ STB0899_DMONMSK1,	0x27 },
-	{ STB0899_DMONMSK0,	0x03 },
-	{ STB0899_DEMAPVIT,	0x5c },
-	{ STB0899_PLPARM,	0x19 },
-	{ STB0899_PDELCTRL,	0x48 },
-	{ STB0899_PDELCTRL2,	0x00 },
-	{ STB0899_BBHCTRL1,	0x00 },
-	{ STB0899_BBHCTRL2,	0x00 },
-	{ STB0899_HYSTTHRESH,	0x77 },
-	{ STB0899_MATCSTM,	0x00 },
-	{ STB0899_MATCSTL,	0x00 },
-	{ STB0899_UPLCSTM,	0x00 },
-	{ STB0899_UPLCSTL,	0x00 },
-	{ STB0899_DFLCSTM,	0x00 },
-	{ STB0899_DFLCSTL,	0x00 },
-	{ STB0899_SYNCCST,	0x00 },
-	{ STB0899_SYNCDCSTM,	0x00 },
-	{ STB0899_SYNCDCSTL,	0x00 },
-	{ STB0899_ISI_ENTRY,	0x00 },
-	{ STB0899_ISI_BIT_EN,	0x00 },
-	{ STB0899_MATSTRM,	0xf0 },
-	{ STB0899_MATSTRL,	0x02 },
-	{ STB0899_UPLSTRM,	0x45 },
-	{ STB0899_UPLSTRL,	0x60 },
-	{ STB0899_DFLSTRM,	0xe3 },
-	{ STB0899_DFLSTRL,	0x00 },
-	{ STB0899_SYNCSTR,	0x47 },
-	{ STB0899_SYNCDSTRM,	0x05 },
-	{ STB0899_SYNCDSTRL,	0x18 },
-	{ STB0899_CFGPDELSTATUS1, 0x19 },
-	{ STB0899_CFGPDELSTATUS2, 0x2b },
-	{ STB0899_BBFERRORM,	0x00 },
-	{ STB0899_BBFERRORL,	0x01 },
-	{ STB0899_UPKTERRORM,	0x00 },
-	{ STB0899_UPKTERRORL,	0x00 },
-	{ 0xffff,		0xff },
-};
-
-static struct stb0899_config stb0899_config = {
-	.init_dev	= pctv452e_init_dev,
-	.init_s2_demod	= stb0899_s2_init_2,
-	.init_s1_demod	= pctv452e_init_s1_demod,
-	.init_s2_fec	= stb0899_s2_init_4,
-	.init_tst	= stb0899_s1_init_5,
-
-	.demod_address   = I2C_ADDR_STB0899, /* I2C Address */
-	.block_sync_mode = STB0899_SYNC_FORCED, /* ? */
-
-	.xtal_freq       = 27000000,	 /* Assume Hz ? */
-	.inversion       = IQ_SWAP_ON,       /* ? */
-
-	.lo_clk	  = 76500000,
-	.hi_clk	  = 99000000,
-
-	.ts_output_mode  = 0,	/* Use parallel mode */
-	.clock_polarity  = 0,
-	.data_clk_parity = 0,
-	.fec_mode	= 0,
-
-	.esno_ave	    = STB0899_DVBS2_ESNO_AVE,
-	.esno_quant	  = STB0899_DVBS2_ESNO_QUANT,
-	.avframes_coarse     = STB0899_DVBS2_AVFRAMES_COARSE,
-	.avframes_fine       = STB0899_DVBS2_AVFRAMES_FINE,
-	.miss_threshold      = STB0899_DVBS2_MISS_THRESHOLD,
-	.uwp_threshold_acq   = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
-	.uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
-	.uwp_threshold_sof   = STB0899_DVBS2_UWP_THRESHOLD_SOF,
-	.sof_search_timeout  = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
-
-	.btr_nco_bits	  = STB0899_DVBS2_BTR_NCO_BITS,
-	.btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
-	.crl_nco_bits	  = STB0899_DVBS2_CRL_NCO_BITS,
-	.ldpc_max_iter	 = STB0899_DVBS2_LDPC_MAX_ITER,
-
-	.tuner_get_frequency	= stb6100_get_frequency,
-	.tuner_set_frequency	= stb6100_set_frequency,
-	.tuner_set_bandwidth	= stb6100_set_bandwidth,
-	.tuner_get_bandwidth	= stb6100_get_bandwidth,
-	.tuner_set_rfsiggain	= NULL,
-
-	/* helper for switching LED green/orange */
-	.postproc = pctv45e_postproc
-};
-
-static struct stb6100_config stb6100_config = {
-	.tuner_address = I2C_ADDR_STB6100,
-	.refclock      = 27000000
-};
-
-
-static struct i2c_algorithm pctv452e_i2c_algo = {
-	.master_xfer   = pctv452e_i2c_xfer,
-	.functionality = pctv452e_i2c_func
-};
-
-static int pctv452e_frontend_attach(struct dvb_usb_adapter *a)
-{
-	struct usb_device_id *id;
-
-	a->fe_adap[0].fe = dvb_attach(stb0899_attach, &stb0899_config,
-						&a->dev->i2c_adap);
-	if (!a->fe_adap[0].fe)
-		return -ENODEV;
-	if ((dvb_attach(lnbp22_attach, a->fe_adap[0].fe,
-					&a->dev->i2c_adap)) == 0)
-		err("Cannot attach lnbp22\n");
-
-	id = a->dev->desc->warm_ids[0];
-	if (USB_VID_TECHNOTREND == id->idVendor
-	    && USB_PID_TECHNOTREND_CONNECT_S2_3650_CI == id->idProduct)
-		/* Error ignored. */
-		tt3650_ci_init(a);
-
-	return 0;
-}
-
-static int pctv452e_tuner_attach(struct dvb_usb_adapter *a)
-{
-	if (!a->fe_adap[0].fe)
-		return -ENODEV;
-	if (dvb_attach(stb6100_attach, a->fe_adap[0].fe, &stb6100_config,
-					&a->dev->i2c_adap) == 0) {
-		err("%s failed\n", __func__);
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static struct usb_device_id pctv452e_usb_table[] = {
-	{USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_452E)},
-	{USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3600)},
-	{USB_DEVICE(USB_VID_TECHNOTREND,
-				USB_PID_TECHNOTREND_CONNECT_S2_3650_CI)},
-	{}
-};
-MODULE_DEVICE_TABLE(usb, pctv452e_usb_table);
-
-static struct dvb_usb_device_properties pctv452e_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
-	.usb_ctrl = DEVICE_SPECIFIC,
-
-	.size_of_priv     = sizeof(struct pctv452e_state),
-
-	.power_ctrl       = pctv452e_power_ctrl,
-
-	.rc.core = {
-		.rc_codes	= RC_MAP_DIB0700_RC5_TABLE,
-		.allowed_protos	= RC_TYPE_UNKNOWN,
-		.rc_query	= pctv452e_rc_query,
-		.rc_interval	= 100,
-	},
-
-	.num_adapters     = 1,
-	.adapter = {{
-		.num_frontends = 1,
-		.fe = {{
-			.frontend_attach  = pctv452e_frontend_attach,
-			.tuner_attach     = pctv452e_tuner_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type     = USB_ISOC,
-				.count    = 4,
-				.endpoint = 0x02,
-				.u = {
-					.isoc = {
-						.framesperurb = 4,
-						.framesize    = 940,
-						.interval     = 1
-					}
-				}
-			},
-		} },
-	} },
-
-	.i2c_algo = &pctv452e_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 1, /* allow generice rw function */
-
-	.num_device_descs = 1,
-	.devices = {
-		{ .name = "PCTV HDTV USB",
-		  .cold_ids = { NULL, NULL }, /* this is a warm only device */
-		  .warm_ids = { &pctv452e_usb_table[0], NULL }
-		},
-		{ 0 },
-	}
-};
-
-static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
-	.usb_ctrl = DEVICE_SPECIFIC,
-
-	.size_of_priv		= sizeof(struct pctv452e_state),
-
-	.power_ctrl		= pctv452e_power_ctrl,
-	.read_mac_address	= pctv452e_read_mac_address,
-
-	.rc.core = {
-		.rc_codes	= RC_MAP_TT_1500,
-		.allowed_protos	= RC_TYPE_UNKNOWN,
-		.rc_query	= pctv452e_rc_query,
-		.rc_interval	= 100,
-	},
-
-	.num_adapters		= 1,
-	.adapter = {{
-		.num_frontends = 1,
-		.fe = {{
-			.frontend_attach = pctv452e_frontend_attach,
-			.tuner_attach = pctv452e_tuner_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_ISOC,
-				.count = 7,
-				.endpoint = 0x02,
-				.u = {
-					.isoc = {
-						.framesperurb = 4,
-						.framesize = 940,
-						.interval = 1
-					}
-				}
-			},
-
-		} },
-	} },
-
-	.i2c_algo = &pctv452e_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 1, /* allow generic rw function*/
-
-	.num_device_descs = 2,
-	.devices = {
-		{ .name = "Technotrend TT Connect S2-3600",
-		  .cold_ids = { NULL, NULL }, /* this is a warm only device */
-		  .warm_ids = { &pctv452e_usb_table[1], NULL }
-		},
-		{ .name = "Technotrend TT Connect S2-3650-CI",
-		  .cold_ids = { NULL, NULL },
-		  .warm_ids = { &pctv452e_usb_table[2], NULL }
-		},
-		{ 0 },
-	}
-};
-
-static void pctv452e_usb_disconnect(struct usb_interface *intf)
-{
-	struct dvb_usb_device *d = usb_get_intfdata(intf);
-
-	tt3650_ci_uninit(d);
-	dvb_usb_device_exit(intf);
-}
-
-static int pctv452e_usb_probe(struct usb_interface *intf,
-				const struct usb_device_id *id)
-{
-	if (0 == dvb_usb_device_init(intf, &pctv452e_properties,
-					THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &tt_connect_s2_3600_properties,
-					THIS_MODULE, NULL, adapter_nr))
-		return 0;
-
-	return -ENODEV;
-}
-
-static struct usb_driver pctv452e_usb_driver = {
-	.name       = "pctv452e",
-	.probe      = pctv452e_usb_probe,
-	.disconnect = pctv452e_usb_disconnect,
-	.id_table   = pctv452e_usb_table,
-};
-
-module_usb_driver(pctv452e_usb_driver);
-
-MODULE_AUTHOR("Dominik Kuhlen <dkuhlen@gmx.net>");
-MODULE_AUTHOR("Andre Weidemann <Andre.Weidemann@web.de>");
-MODULE_AUTHOR("Michael H. Schimek <mschimek@gmx.at>");
-MODULE_DESCRIPTION("Pinnacle PCTV HDTV USB DVB / TT connect S2-3600 Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c b/drivers/media/dvb/dvb-usb/rtl28xxu.c
deleted file mode 100644
index 6bd0bd7..0000000
--- a/drivers/media/dvb/dvb-usb/rtl28xxu.c
+++ /dev/null
@@ -1,1428 +0,0 @@
-/*
- * Realtek RTL28xxU DVB USB driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
- * Copyright (C) 2012 Thomas Mair <thomas.mair86@googlemail.com>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "rtl28xxu.h"
-
-#include "rtl2830.h"
-#include "rtl2832.h"
-
-#include "qt1010.h"
-#include "mt2060.h"
-#include "mxl5005s.h"
-#include "fc0012.h"
-#include "fc0013.h"
-
-/* debug */
-static int dvb_usb_rtl28xxu_debug;
-module_param_named(debug, dvb_usb_rtl28xxu_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req)
-{
-	int ret;
-	unsigned int pipe;
-	u8 requesttype;
-	u8 *buf;
-
-	buf = kmalloc(req->size, GFP_KERNEL);
-	if (!buf) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	if (req->index & CMD_WR_FLAG) {
-		/* write */
-		memcpy(buf, req->data, req->size);
-		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
-		pipe = usb_sndctrlpipe(d->udev, 0);
-	} else {
-		/* read */
-		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
-		pipe = usb_rcvctrlpipe(d->udev, 0);
-	}
-
-	ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value,
-			req->index, buf, req->size, 1000);
-	if (ret > 0)
-		ret = 0;
-
-	deb_dump(0, requesttype, req->value, req->index, buf, req->size,
-			deb_xfer);
-
-	/* read request, copy returned data to return buf */
-	if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
-		memcpy(req->data, buf, req->size);
-
-	kfree(buf);
-
-	if (ret)
-		goto err;
-
-	return ret;
-err:
-	deb_info("%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int rtl28xx_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
-{
-	struct rtl28xxu_req req;
-
-	if (reg < 0x3000)
-		req.index = CMD_USB_WR;
-	else if (reg < 0x4000)
-		req.index = CMD_SYS_WR;
-	else
-		req.index = CMD_IR_WR;
-
-	req.value = reg;
-	req.size = len;
-	req.data = val;
-
-	return rtl28xxu_ctrl_msg(d, &req);
-}
-
-static int rtl2831_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
-{
-	struct rtl28xxu_req req;
-
-	if (reg < 0x3000)
-		req.index = CMD_USB_RD;
-	else if (reg < 0x4000)
-		req.index = CMD_SYS_RD;
-	else
-		req.index = CMD_IR_RD;
-
-	req.value = reg;
-	req.size = len;
-	req.data = val;
-
-	return rtl28xxu_ctrl_msg(d, &req);
-}
-
-static int rtl28xx_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val)
-{
-	return rtl28xx_wr_regs(d, reg, &val, 1);
-}
-
-static int rtl28xx_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
-{
-	return rtl2831_rd_regs(d, reg, val, 1);
-}
-
-/* I2C */
-static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-	int num)
-{
-	int ret;
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	struct rtl28xxu_priv *priv = d->priv;
-	struct rtl28xxu_req req;
-
-	/*
-	 * It is not known which are real I2C bus xfer limits, but testing
-	 * with RTL2831U + MT2060 gives max RD 24 and max WR 22 bytes.
-	 * TODO: find out RTL2832U lens
-	 */
-
-	/*
-	 * I2C adapter logic looks rather complicated due to fact it handles
-	 * three different access methods. Those methods are;
-	 * 1) integrated demod access
-	 * 2) old I2C access
-	 * 3) new I2C access
-	 *
-	 * Used method is selected in order 1, 2, 3. Method 3 can handle all
-	 * requests but there is two reasons why not use it always;
-	 * 1) It is most expensive, usually two USB messages are needed
-	 * 2) At least RTL2831U does not support it
-	 *
-	 * Method 3 is needed in case of I2C write+read (typical register read)
-	 * where write is more than one byte.
-	 */
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
-		(msg[1].flags & I2C_M_RD)) {
-		if (msg[0].len > 24 || msg[1].len > 24) {
-			/* TODO: check msg[0].len max */
-			ret = -EOPNOTSUPP;
-			goto err_mutex_unlock;
-		} else if (msg[0].addr == 0x10) {
-			/* method 1 - integrated demod */
-			req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
-			req.index = CMD_DEMOD_RD | priv->page;
-			req.size = msg[1].len;
-			req.data = &msg[1].buf[0];
-			ret = rtl28xxu_ctrl_msg(d, &req);
-		} else if (msg[0].len < 2) {
-			/* method 2 - old I2C */
-			req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
-			req.index = CMD_I2C_RD;
-			req.size = msg[1].len;
-			req.data = &msg[1].buf[0];
-			ret = rtl28xxu_ctrl_msg(d, &req);
-		} else {
-			/* method 3 - new I2C */
-			req.value = (msg[0].addr << 1);
-			req.index = CMD_I2C_DA_WR;
-			req.size = msg[0].len;
-			req.data = msg[0].buf;
-			ret = rtl28xxu_ctrl_msg(d, &req);
-			if (ret)
-				goto err_mutex_unlock;
-
-			req.value = (msg[0].addr << 1);
-			req.index = CMD_I2C_DA_RD;
-			req.size = msg[1].len;
-			req.data = msg[1].buf;
-			ret = rtl28xxu_ctrl_msg(d, &req);
-		}
-	} else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
-		if (msg[0].len > 22) {
-			/* TODO: check msg[0].len max */
-			ret = -EOPNOTSUPP;
-			goto err_mutex_unlock;
-		} else if (msg[0].addr == 0x10) {
-			/* method 1 - integrated demod */
-			if (msg[0].buf[0] == 0x00) {
-				/* save demod page for later demod access */
-				priv->page = msg[0].buf[1];
-				ret = 0;
-			} else {
-				req.value = (msg[0].buf[0] << 8) |
-					(msg[0].addr << 1);
-				req.index = CMD_DEMOD_WR | priv->page;
-				req.size = msg[0].len-1;
-				req.data = &msg[0].buf[1];
-				ret = rtl28xxu_ctrl_msg(d, &req);
-			}
-		} else if (msg[0].len < 23) {
-			/* method 2 - old I2C */
-			req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
-			req.index = CMD_I2C_WR;
-			req.size = msg[0].len-1;
-			req.data = &msg[0].buf[1];
-			ret = rtl28xxu_ctrl_msg(d, &req);
-		} else {
-			/* method 3 - new I2C */
-			req.value = (msg[0].addr << 1);
-			req.index = CMD_I2C_DA_WR;
-			req.size = msg[0].len;
-			req.data = msg[0].buf;
-			ret = rtl28xxu_ctrl_msg(d, &req);
-		}
-	} else {
-		ret = -EINVAL;
-	}
-
-err_mutex_unlock:
-	mutex_unlock(&d->i2c_mutex);
-
-	return ret ? ret : num;
-}
-
-static u32 rtl28xxu_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm rtl28xxu_i2c_algo = {
-	.master_xfer   = rtl28xxu_i2c_xfer,
-	.functionality = rtl28xxu_i2c_func,
-};
-
-static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
-	.i2c_addr = 0x10, /* 0x20 */
-	.xtal = 28800000,
-	.ts_mode = 0,
-	.spec_inv = 1,
-	.if_dvbt = 36150000,
-	.vtop = 0x20,
-	.krf = 0x04,
-	.agc_targ_val = 0x2d,
-
-};
-
-static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
-	.i2c_addr = 0x10, /* 0x20 */
-	.xtal = 28800000,
-	.ts_mode = 0,
-	.spec_inv = 1,
-	.if_dvbt = 36125000,
-	.vtop = 0x20,
-	.krf = 0x04,
-	.agc_targ_val = 0x2d,
-};
-
-static struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = {
-	.i2c_addr = 0x10, /* 0x20 */
-	.xtal = 28800000,
-	.ts_mode = 0,
-	.spec_inv = 0,
-	.if_dvbt = 4570000,
-	.vtop = 0x3f,
-	.krf = 0x04,
-	.agc_targ_val = 0x3e,
-};
-
-static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	int ret;
-	struct rtl28xxu_priv *priv = adap->dev->priv;
-	u8 buf[1];
-	struct rtl2830_config *rtl2830_config;
-	/* open RTL2831U/RTL2830 I2C gate */
-	struct rtl28xxu_req req_gate = { 0x0120, 0x0011, 0x0001, "\x08" };
-	/* for MT2060 tuner probe */
-	struct rtl28xxu_req req_mt2060 = { 0x00c0, CMD_I2C_RD, 1, buf };
-	/* for QT1010 tuner probe */
-	struct rtl28xxu_req req_qt1010 = { 0x0fc4, CMD_I2C_RD, 1, buf };
-
-	deb_info("%s:\n", __func__);
-
-	/*
-	 * RTL2831U GPIOs
-	 * =========================================================
-	 * GPIO0 | tuner#0 | 0 off | 1 on  | MXL5005S (?)
-	 * GPIO2 | LED     | 0 off | 1 on  |
-	 * GPIO4 | tuner#1 | 0 on  | 1 off | MT2060
-	 */
-
-	/* GPIO direction */
-	ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
-	if (ret)
-		goto err;
-
-	/* enable as output GPIO0, GPIO2, GPIO4 */
-	ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
-	if (ret)
-		goto err;
-
-	/*
-	 * Probe used tuner. We need to know used tuner before demod attach
-	 * since there is some demod params needed to set according to tuner.
-	 */
-
-	/* demod needs some time to wake up */
-	msleep(20);
-
-	/* open demod I2C gate */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate);
-	if (ret)
-		goto err;
-
-	/* check QT1010 ID(?) register; reg=0f val=2c */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_qt1010);
-	if (ret == 0 && buf[0] == 0x2c) {
-		priv->tuner = TUNER_RTL2830_QT1010;
-		rtl2830_config = &rtl28xxu_rtl2830_qt1010_config;
-		deb_info("%s: QT1010\n", __func__);
-		goto found;
-	} else {
-		deb_info("%s: QT1010 probe failed=%d - %02x\n",
-			__func__, ret, buf[0]);
-	}
-
-	/* open demod I2C gate */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate);
-	if (ret)
-		goto err;
-
-	/* check MT2060 ID register; reg=00 val=63 */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2060);
-	if (ret == 0 && buf[0] == 0x63) {
-		priv->tuner = TUNER_RTL2830_MT2060;
-		rtl2830_config = &rtl28xxu_rtl2830_mt2060_config;
-		deb_info("%s: MT2060\n", __func__);
-		goto found;
-	} else {
-		deb_info("%s: MT2060 probe failed=%d - %02x\n",
-			__func__, ret, buf[0]);
-	}
-
-	/* assume MXL5005S */
-	ret = 0;
-	priv->tuner = TUNER_RTL2830_MXL5005S;
-	rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config;
-	deb_info("%s: MXL5005S\n", __func__);
-	goto found;
-
-found:
-	/* attach demodulator */
-	adap->fe_adap[0].fe = dvb_attach(rtl2830_attach, rtl2830_config,
-		&adap->dev->i2c_adap);
-	if (adap->fe_adap[0].fe == NULL) {
-		ret = -ENODEV;
-		goto err;
-	}
-
-	return ret;
-err:
-	deb_info("%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
-	.i2c_addr = 0x10, /* 0x20 */
-	.xtal = 28800000,
-	.if_dvbt = 0,
-	.tuner = TUNER_RTL2832_FC0012
-};
-
-static struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = {
-	.i2c_addr = 0x10, /* 0x20 */
-	.xtal = 28800000,
-	.if_dvbt = 0,
-	.tuner = TUNER_RTL2832_FC0013
-};
-
-static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d,
-		int cmd, int arg)
-{
-	int ret;
-	u8 val;
-
-	deb_info("%s cmd=%d arg=%d\n", __func__, cmd, arg);
-	switch (cmd) {
-	case FC_FE_CALLBACK_VHF_ENABLE:
-		/* set output values */
-		ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
-		if (ret)
-			goto err;
-
-		if (arg)
-			val &= 0xbf; /* set GPIO6 low */
-		else
-			val |= 0x40; /* set GPIO6 high */
-
-
-		ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
-		if (ret)
-			goto err;
-		break;
-	default:
-		ret = -EINVAL;
-		goto err;
-	}
-	return 0;
-
-err:
-	err("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-
-static int rtl2832u_fc0013_tuner_callback(struct dvb_usb_device *d,
-		int cmd, int arg)
-{
-	/* TODO implement*/
-	return 0;
-}
-
-static int rtl2832u_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
-{
-	struct rtl28xxu_priv *priv = d->priv;
-
-	switch (priv->tuner) {
-	case TUNER_RTL2832_FC0012:
-		return rtl2832u_fc0012_tuner_callback(d, cmd, arg);
-
-	case TUNER_RTL2832_FC0013:
-		return rtl2832u_fc0013_tuner_callback(d, cmd, arg);
-	default:
-		break;
-	}
-
-	return -ENODEV;
-}
-
-static int rtl2832u_frontend_callback(void *adapter_priv, int component,
-				    int cmd, int arg)
-{
-	struct i2c_adapter *adap = adapter_priv;
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-
-	switch (component) {
-	case DVB_FRONTEND_COMPONENT_TUNER:
-		return rtl2832u_tuner_callback(d, cmd, arg);
-	default:
-		break;
-	}
-
-	return -EINVAL;
-}
-
-
-
-
-static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	int ret;
-	struct rtl28xxu_priv *priv = adap->dev->priv;
-	struct rtl2832_config *rtl2832_config;
-
-	u8 buf[2], val;
-	/* open RTL2832U/RTL2832 I2C gate */
-	struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"};
-	/* close RTL2832U/RTL2832 I2C gate */
-	struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"};
-	/* for FC0012 tuner probe */
-	struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf};
-	/* for FC0013 tuner probe */
-	struct rtl28xxu_req req_fc0013 = {0x00c6, CMD_I2C_RD, 1, buf};
-	/* for MT2266 tuner probe */
-	struct rtl28xxu_req req_mt2266 = {0x00c0, CMD_I2C_RD, 1, buf};
-	/* for FC2580 tuner probe */
-	struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf};
-	/* for MT2063 tuner probe */
-	struct rtl28xxu_req req_mt2063 = {0x00c0, CMD_I2C_RD, 1, buf};
-	/* for MAX3543 tuner probe */
-	struct rtl28xxu_req req_max3543 = {0x00c0, CMD_I2C_RD, 1, buf};
-	/* for TUA9001 tuner probe */
-	struct rtl28xxu_req req_tua9001 = {0x7ec0, CMD_I2C_RD, 2, buf};
-	/* for MXL5007T tuner probe */
-	struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf};
-	/* for E4000 tuner probe */
-	struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf};
-	/* for TDA18272 tuner probe */
-	struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf};
-
-	deb_info("%s:\n", __func__);
-
-
-	ret = rtl28xx_rd_reg(adap->dev, SYS_GPIO_DIR, &val);
-	if (ret)
-		goto err;
-
-	val &= 0xbf;
-
-	ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_DIR, val);
-	if (ret)
-		goto err;
-
-
-	/* enable as output GPIO3 and GPIO6*/
-	ret = rtl28xx_rd_reg(adap->dev, SYS_GPIO_OUT_EN, &val);
-	if (ret)
-		goto err;
-
-	val |= 0x48;
-
-	ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_OUT_EN, val);
-	if (ret)
-		goto err;
-
-
-
-	/*
-	 * Probe used tuner. We need to know used tuner before demod attach
-	 * since there is some demod params needed to set according to tuner.
-	 */
-
-	/* open demod I2C gate */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_open);
-	if (ret)
-		goto err;
-
-	priv->tuner = TUNER_NONE;
-
-	/* check FC0012 ID register; reg=00 val=a1 */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc0012);
-	if (ret == 0 && buf[0] == 0xa1) {
-		priv->tuner = TUNER_RTL2832_FC0012;
-		rtl2832_config = &rtl28xxu_rtl2832_fc0012_config;
-		info("%s: FC0012 tuner found", __func__);
-		goto found;
-	}
-
-	/* check FC0013 ID register; reg=00 val=a3 */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc0013);
-	if (ret == 0 && buf[0] == 0xa3) {
-		priv->tuner = TUNER_RTL2832_FC0013;
-		rtl2832_config = &rtl28xxu_rtl2832_fc0013_config;
-		info("%s: FC0013 tuner found", __func__);
-		goto found;
-	}
-
-	/* check MT2266 ID register; reg=00 val=85 */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2266);
-	if (ret == 0 && buf[0] == 0x85) {
-		priv->tuner = TUNER_RTL2832_MT2266;
-		/* TODO implement tuner */
-		info("%s: MT2266 tuner found", __func__);
-		goto unsupported;
-	}
-
-	/* check FC2580 ID register; reg=01 val=56 */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc2580);
-	if (ret == 0 && buf[0] == 0x56) {
-		priv->tuner = TUNER_RTL2832_FC2580;
-		/* TODO implement tuner */
-		info("%s: FC2580 tuner found", __func__);
-		goto unsupported;
-	}
-
-	/* check MT2063 ID register; reg=00 val=9e || 9c */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2063);
-	if (ret == 0 && (buf[0] == 0x9e || buf[0] == 0x9c)) {
-		priv->tuner = TUNER_RTL2832_MT2063;
-		/* TODO implement tuner */
-		info("%s: MT2063 tuner found", __func__);
-		goto unsupported;
-	}
-
-	/* check MAX3543 ID register; reg=00 val=38 */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_max3543);
-	if (ret == 0 && buf[0] == 0x38) {
-		priv->tuner = TUNER_RTL2832_MAX3543;
-		/* TODO implement tuner */
-		info("%s: MAX3534 tuner found", __func__);
-		goto unsupported;
-	}
-
-	/* check TUA9001 ID register; reg=7e val=2328 */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_tua9001);
-	if (ret == 0 && buf[0] == 0x23 && buf[1] == 0x28) {
-		priv->tuner = TUNER_RTL2832_TUA9001;
-		/* TODO implement tuner */
-		info("%s: TUA9001 tuner found", __func__);
-		goto unsupported;
-	}
-
-	/* check MXL5007R ID register; reg=d9 val=14 */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_mxl5007t);
-	if (ret == 0 && buf[0] == 0x14) {
-		priv->tuner = TUNER_RTL2832_MXL5007T;
-		/* TODO implement tuner */
-		info("%s: MXL5007T tuner found", __func__);
-		goto unsupported;
-	}
-
-	/* check E4000 ID register; reg=02 val=40 */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_e4000);
-	if (ret == 0 && buf[0] == 0x40) {
-		priv->tuner = TUNER_RTL2832_E4000;
-		/* TODO implement tuner */
-		info("%s: E4000 tuner found", __func__);
-		goto unsupported;
-	}
-
-	/* check TDA18272 ID register; reg=00 val=c760  */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_tda18272);
-	if (ret == 0 && (buf[0] == 0xc7 || buf[1] == 0x60)) {
-		priv->tuner = TUNER_RTL2832_TDA18272;
-		/* TODO implement tuner */
-		info("%s: TDA18272 tuner found", __func__);
-		goto unsupported;
-	}
-
-unsupported:
-	/* close demod I2C gate */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
-	if (ret)
-		goto err;
-
-	/* tuner not found */
-	deb_info("No compatible tuner found");
-	ret = -ENODEV;
-	return ret;
-
-found:
-	/* close demod I2C gate */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
-	if (ret)
-		goto err;
-
-	/* attach demodulator */
-	adap->fe_adap[0].fe = dvb_attach(rtl2832_attach, rtl2832_config,
-		&adap->dev->i2c_adap);
-		if (adap->fe_adap[0].fe == NULL) {
-			ret = -ENODEV;
-			goto err;
-		}
-
-	/* set fe callbacks */
-	adap->fe_adap[0].fe->callback = rtl2832u_frontend_callback;
-
-	return ret;
-
-err:
-	deb_info("%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static struct qt1010_config rtl28xxu_qt1010_config = {
-	.i2c_address = 0x62, /* 0xc4 */
-};
-
-static struct mt2060_config rtl28xxu_mt2060_config = {
-	.i2c_address = 0x60, /* 0xc0 */
-	.clock_out = 0,
-};
-
-static struct mxl5005s_config rtl28xxu_mxl5005s_config = {
-	.i2c_address     = 0x63, /* 0xc6 */
-	.if_freq         = IF_FREQ_4570000HZ,
-	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
-	.agc_mode        = MXL_SINGLE_AGC,
-	.tracking_filter = MXL_TF_C_H,
-	.rssi_enable     = MXL_RSSI_ENABLE,
-	.cap_select      = MXL_CAP_SEL_ENABLE,
-	.div_out         = MXL_DIV_OUT_4,
-	.clock_out       = MXL_CLOCK_OUT_DISABLE,
-	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
-	.top		 = MXL5005S_TOP_25P2,
-	.mod_mode        = MXL_DIGITAL_MODE,
-	.if_mode         = MXL_ZERO_IF,
-	.AgcMasterByte   = 0x00,
-};
-
-static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	int ret;
-	struct rtl28xxu_priv *priv = adap->dev->priv;
-	struct i2c_adapter *rtl2830_tuner_i2c;
-	struct dvb_frontend *fe;
-
-	deb_info("%s:\n", __func__);
-
-	/* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */
-	rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe_adap[0].fe);
-
-	switch (priv->tuner) {
-	case TUNER_RTL2830_QT1010:
-		fe = dvb_attach(qt1010_attach, adap->fe_adap[0].fe,
-				rtl2830_tuner_i2c, &rtl28xxu_qt1010_config);
-		break;
-	case TUNER_RTL2830_MT2060:
-		fe = dvb_attach(mt2060_attach, adap->fe_adap[0].fe,
-				rtl2830_tuner_i2c, &rtl28xxu_mt2060_config,
-				1220);
-		break;
-	case TUNER_RTL2830_MXL5005S:
-		fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
-				rtl2830_tuner_i2c, &rtl28xxu_mxl5005s_config);
-		break;
-	default:
-		fe = NULL;
-		err("unknown tuner=%d", priv->tuner);
-	}
-
-	if (fe == NULL) {
-		ret = -ENODEV;
-		goto err;
-	}
-
-	return 0;
-err:
-	deb_info("%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	int ret;
-	struct rtl28xxu_priv *priv = adap->dev->priv;
-	struct dvb_frontend *fe;
-
-	deb_info("%s:\n", __func__);
-
-	switch (priv->tuner) {
-	case TUNER_RTL2832_FC0012:
-		fe = dvb_attach(fc0012_attach, adap->fe_adap[0].fe,
-			&adap->dev->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ);
-
-		/* since fc0012 includs reading the signal strength delegate
-		 * that to the tuner driver */
-		adap->fe_adap[0].fe->ops.read_signal_strength = adap->fe_adap[0].
-				fe->ops.tuner_ops.get_rf_strength;
-		return 0;
-		break;
-	case TUNER_RTL2832_FC0013:
-		fe = dvb_attach(fc0013_attach, adap->fe_adap[0].fe,
-			&adap->dev->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ);
-
-		/* fc0013 also supports signal strength reading */
-		adap->fe_adap[0].fe->ops.read_signal_strength = adap->fe_adap[0]
-			.fe->ops.tuner_ops.get_rf_strength;
-		return 0;
-	default:
-		fe = NULL;
-		err("unknown tuner=%d", priv->tuner);
-	}
-
-	if (fe == NULL) {
-		ret = -ENODEV;
-		goto err;
-	}
-
-	return 0;
-err:
-	deb_info("%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int rtl2831u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
-{
-	int ret;
-	u8 buf[2], gpio;
-
-	deb_info("%s: onoff=%d\n", __func__, onoff);
-
-	ret = rtl28xx_rd_reg(adap->dev, SYS_GPIO_OUT_VAL, &gpio);
-	if (ret)
-		goto err;
-
-	if (onoff) {
-		buf[0] = 0x00;
-		buf[1] = 0x00;
-		gpio |= 0x04; /* LED on */
-	} else {
-		buf[0] = 0x10; /* stall EPA */
-		buf[1] = 0x02; /* reset EPA */
-		gpio &= (~0x04); /* LED off */
-	}
-
-	ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_OUT_VAL, gpio);
-	if (ret)
-		goto err;
-
-	ret = rtl28xx_wr_regs(adap->dev, USB_EPA_CTL, buf, 2);
-	if (ret)
-		goto err;
-
-	return ret;
-err:
-	deb_info("%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int rtl2832u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
-{
-	int ret;
-	u8 buf[2];
-
-	deb_info("%s: onoff=%d\n", __func__, onoff);
-
-
-	if (onoff) {
-		buf[0] = 0x00;
-		buf[1] = 0x00;
-	} else {
-		buf[0] = 0x10; /* stall EPA */
-		buf[1] = 0x02; /* reset EPA */
-	}
-
-	ret = rtl28xx_wr_regs(adap->dev, USB_EPA_CTL, buf, 2);
-	if (ret)
-		goto err;
-
-	return ret;
-err:
-	deb_info("%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	int ret;
-	u8 gpio, sys0;
-
-	deb_info("%s: onoff=%d\n", __func__, onoff);
-
-	/* demod adc */
-	ret = rtl28xx_rd_reg(d, SYS_SYS0, &sys0);
-	if (ret)
-		goto err;
-
-	/* tuner power, read GPIOs */
-	ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio);
-	if (ret)
-		goto err;
-
-	deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
-
-	if (onoff) {
-		gpio |= 0x01; /* GPIO0 = 1 */
-		gpio &= (~0x10); /* GPIO4 = 0 */
-		sys0 = sys0 & 0x0f;
-		sys0 |= 0xe0;
-	} else {
-		gpio &= (~0x01); /* GPIO0 = 0 */
-		gpio |= 0x10; /* GPIO4 = 1 */
-		sys0 = sys0 & (~0xc0);
-	}
-
-	deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
-
-	/* demod adc */
-	ret = rtl28xx_wr_reg(d, SYS_SYS0, sys0);
-	if (ret)
-		goto err;
-
-	/* tuner power, write GPIOs */
-	ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, gpio);
-	if (ret)
-		goto err;
-
-	return ret;
-err:
-	deb_info("%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	int ret;
-	u8 val;
-
-	deb_info("%s: onoff=%d\n", __func__, onoff);
-
-	if (onoff) {
-		/* set output values */
-		ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
-		if (ret)
-			goto err;
-
-		val |= 0x08;
-		val &= 0xef;
-
-		ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
-		if (ret)
-			goto err;
-
-		/* demod_ctl_1 */
-		ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val);
-		if (ret)
-			goto err;
-
-		val &= 0xef;
-
-		ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val);
-		if (ret)
-			goto err;
-
-		/* demod control */
-		/* PLL enable */
-		ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
-		if (ret)
-			goto err;
-
-		/* bit 7 to 1 */
-		val |= 0x80;
-
-		ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
-		if (ret)
-			goto err;
-
-		/* demod HW reset */
-		ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
-		if (ret)
-			goto err;
-		/* bit 5 to 0 */
-		val &= 0xdf;
-
-		ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
-		if (ret)
-			goto err;
-
-		ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
-		if (ret)
-			goto err;
-
-		val |= 0x20;
-
-		ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
-		if (ret)
-			goto err;
-
-		mdelay(5);
-
-		/*enable ADC_Q and ADC_I */
-		ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
-		if (ret)
-			goto err;
-
-		val |= 0x48;
-
-		ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
-		if (ret)
-			goto err;
-
-
-	} else {
-		/* demod_ctl_1 */
-		ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val);
-		if (ret)
-			goto err;
-
-		val |= 0x0c;
-
-		ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val);
-		if (ret)
-			goto err;
-
-		/* set output values */
-		ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
-		if (ret)
-				goto err;
-
-		val |= 0x10;
-
-		ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
-		if (ret)
-			goto err;
-
-		/* demod control */
-		ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
-		if (ret)
-			goto err;
-
-		val &= 0x37;
-
-		ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
-		if (ret)
-			goto err;
-
-	}
-
-	return ret;
-err:
-	deb_info("%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-
-static int rtl2831u_rc_query(struct dvb_usb_device *d)
-{
-	int ret, i;
-	struct rtl28xxu_priv *priv = d->priv;
-	u8 buf[5];
-	u32 rc_code;
-	struct rtl28xxu_reg_val rc_nec_tab[] = {
-		{ 0x3033, 0x80 },
-		{ 0x3020, 0x43 },
-		{ 0x3021, 0x16 },
-		{ 0x3022, 0x16 },
-		{ 0x3023, 0x5a },
-		{ 0x3024, 0x2d },
-		{ 0x3025, 0x16 },
-		{ 0x3026, 0x01 },
-		{ 0x3028, 0xb0 },
-		{ 0x3029, 0x04 },
-		{ 0x302c, 0x88 },
-		{ 0x302e, 0x13 },
-		{ 0x3030, 0xdf },
-		{ 0x3031, 0x05 },
-	};
-
-	/* init remote controller */
-	if (!priv->rc_active) {
-		for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) {
-			ret = rtl28xx_wr_reg(d, rc_nec_tab[i].reg,
-					rc_nec_tab[i].val);
-			if (ret)
-				goto err;
-		}
-		priv->rc_active = true;
-	}
-
-	ret = rtl2831_rd_regs(d, SYS_IRRC_RP, buf, 5);
-	if (ret)
-		goto err;
-
-	if (buf[4] & 0x01) {
-		if (buf[2] == (u8) ~buf[3]) {
-			if (buf[0] == (u8) ~buf[1]) {
-				/* NEC standard (16 bit) */
-				rc_code = buf[0] << 8 | buf[2];
-			} else {
-				/* NEC extended (24 bit) */
-				rc_code = buf[0] << 16 |
-						buf[1] << 8 | buf[2];
-			}
-		} else {
-			/* NEC full (32 bit) */
-			rc_code = buf[0] << 24 | buf[1] << 16 |
-					buf[2] << 8 | buf[3];
-		}
-
-		rc_keydown(d->rc_dev, rc_code, 0);
-
-		ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1);
-		if (ret)
-			goto err;
-
-		/* repeated intentionally to avoid extra keypress */
-		ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1);
-		if (ret)
-			goto err;
-	}
-
-	return ret;
-err:
-	deb_info("%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int rtl2832u_rc_query(struct dvb_usb_device *d)
-{
-	int ret, i;
-	struct rtl28xxu_priv *priv = d->priv;
-	u8 buf[128];
-	int len;
-	struct rtl28xxu_reg_val rc_nec_tab[] = {
-		{ IR_RX_CTRL,             0x20 },
-		{ IR_RX_BUF_CTRL,         0x80 },
-		{ IR_RX_IF,               0xff },
-		{ IR_RX_IE,               0xff },
-		{ IR_MAX_DURATION0,       0xd0 },
-		{ IR_MAX_DURATION1,       0x07 },
-		{ IR_IDLE_LEN0,           0xc0 },
-		{ IR_IDLE_LEN1,           0x00 },
-		{ IR_GLITCH_LEN,          0x03 },
-		{ IR_RX_CLK,              0x09 },
-		{ IR_RX_CFG,              0x1c },
-		{ IR_MAX_H_TOL_LEN,       0x1e },
-		{ IR_MAX_L_TOL_LEN,       0x1e },
-		{ IR_RX_CTRL,             0x80 },
-	};
-
-	/* init remote controller */
-	if (!priv->rc_active) {
-		for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) {
-			ret = rtl28xx_wr_reg(d, rc_nec_tab[i].reg,
-					rc_nec_tab[i].val);
-			if (ret)
-				goto err;
-		}
-		priv->rc_active = true;
-	}
-
-	ret = rtl28xx_rd_reg(d, IR_RX_IF, &buf[0]);
-	if (ret)
-		goto err;
-
-	if (buf[0] != 0x83)
-		goto exit;
-
-	ret = rtl28xx_rd_reg(d, IR_RX_BC, &buf[0]);
-	if (ret)
-		goto err;
-
-	len = buf[0];
-	ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len);
-
-	/* TODO: pass raw IR to Kernel IR decoder */
-
-	ret = rtl28xx_wr_reg(d, IR_RX_IF, 0x03);
-	ret = rtl28xx_wr_reg(d, IR_RX_BUF_CTRL, 0x80);
-	ret = rtl28xx_wr_reg(d, IR_RX_CTRL, 0x80);
-
-exit:
-	return ret;
-err:
-	deb_info("%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-enum rtl28xxu_usb_table_entry {
-	RTL2831U_0BDA_2831,
-	RTL2831U_14AA_0160,
-	RTL2831U_14AA_0161,
-	RTL2832U_0CCD_00A9,
-	RTL2832U_1F4D_B803,
-	RTL2832U_0CCD_00B3,
-};
-
-static struct usb_device_id rtl28xxu_table[] = {
-	/* RTL2831U */
-	[RTL2831U_0BDA_2831] = {
-		USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U)},
-	[RTL2831U_14AA_0160] = {
-		USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT)},
-	[RTL2831U_14AA_0161] = {
-		USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2)},
-
-	/* RTL2832U */
-	[RTL2832U_0CCD_00A9] = {
-		USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1)},
-	[RTL2832U_1F4D_B803] = {
-		USB_DEVICE(USB_VID_GTEK, USB_PID_DELOCK_USB2_DVBT)},
-	[RTL2832U_0CCD_00B3] = {
-		USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK)},
-	{} /* terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, rtl28xxu_table);
-
-static struct dvb_usb_device_properties rtl28xxu_properties[] = {
-	{
-		.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-		.usb_ctrl = DEVICE_SPECIFIC,
-		.no_reconnect = 1,
-
-		.size_of_priv = sizeof(struct rtl28xxu_priv),
-
-		.num_adapters = 1,
-		.adapter = {
-			{
-				.num_frontends = 1,
-				.fe = {
-					{
-						.frontend_attach = rtl2831u_frontend_attach,
-						.tuner_attach    = rtl2831u_tuner_attach,
-						.streaming_ctrl  = rtl2831u_streaming_ctrl,
-						.stream = {
-							.type = USB_BULK,
-							.count = 6,
-							.endpoint = 0x81,
-							.u = {
-								.bulk = {
-									.buffersize = 8*512,
-								}
-							}
-						}
-					}
-				}
-			}
-		},
-
-		.power_ctrl = rtl2831u_power_ctrl,
-
-		.rc.core = {
-			.protocol       = RC_TYPE_NEC,
-			.module_name    = "rtl28xxu",
-			.rc_query       = rtl2831u_rc_query,
-			.rc_interval    = 400,
-			.allowed_protos = RC_TYPE_NEC,
-			.rc_codes       = RC_MAP_EMPTY,
-		},
-
-		.i2c_algo = &rtl28xxu_i2c_algo,
-
-		.num_device_descs = 2,
-		.devices = {
-			{
-				.name = "Realtek RTL2831U reference design",
-				.warm_ids = {
-					&rtl28xxu_table[RTL2831U_0BDA_2831],
-				},
-			},
-			{
-				.name = "Freecom USB2.0 DVB-T",
-				.warm_ids = {
-					&rtl28xxu_table[RTL2831U_14AA_0160],
-					&rtl28xxu_table[RTL2831U_14AA_0161],
-				},
-			},
-		}
-	},
-	{
-		.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-		.usb_ctrl = DEVICE_SPECIFIC,
-		.no_reconnect = 1,
-
-		.size_of_priv = sizeof(struct rtl28xxu_priv),
-
-		.num_adapters = 1,
-		.adapter = {
-			{
-				.num_frontends = 1,
-				.fe = {
-					{
-						.frontend_attach = rtl2832u_frontend_attach,
-						.tuner_attach    = rtl2832u_tuner_attach,
-						.streaming_ctrl  = rtl2832u_streaming_ctrl,
-						.stream = {
-							.type = USB_BULK,
-							.count = 6,
-							.endpoint = 0x81,
-							.u = {
-								.bulk = {
-									.buffersize = 8*512,
-								}
-							}
-						}
-					}
-				}
-			}
-		},
-
-		.power_ctrl = rtl2832u_power_ctrl,
-
-		.rc.core = {
-			.protocol       = RC_TYPE_NEC,
-			.module_name    = "rtl28xxu",
-			.rc_query       = rtl2832u_rc_query,
-			.rc_interval    = 400,
-			.allowed_protos = RC_TYPE_NEC,
-			.rc_codes       = RC_MAP_EMPTY,
-		},
-
-		.i2c_algo = &rtl28xxu_i2c_algo,
-
-		.num_device_descs = 3,
-		.devices = {
-			{
-				.name = "Terratec Cinergy T Stick Black",
-				.warm_ids = {
-					&rtl28xxu_table[RTL2832U_0CCD_00A9],
-				},
-			},
-			{
-				.name = "G-Tek Electronics Group Lifeview LV5TDLX DVB-T",
-				.warm_ids = {
-					&rtl28xxu_table[RTL2832U_1F4D_B803],
-				},
-			},
-			{
-				.name = "NOXON DAB/DAB+ USB dongle",
-				.warm_ids = {
-					&rtl28xxu_table[RTL2832U_0CCD_00B3],
-				},
-			},
-		}
-	},
-
-};
-
-static int rtl28xxu_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	int ret, i;
-	u8 val;
-	int properties_count = ARRAY_SIZE(rtl28xxu_properties);
-	struct dvb_usb_device *d;
-	struct usb_device *udev;
-	bool found;
-
-	deb_info("%s: interface=%d\n", __func__,
-		intf->cur_altsetting->desc.bInterfaceNumber);
-
-	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
-		return 0;
-
-	/* Dynamic USB ID support. Replaces first device ID with current one .*/
-	udev = interface_to_usbdev(intf);
-
-	for (i = 0, found = false; i < ARRAY_SIZE(rtl28xxu_table) - 1; i++) {
-		if (rtl28xxu_table[i].idVendor ==
-				le16_to_cpu(udev->descriptor.idVendor) &&
-				rtl28xxu_table[i].idProduct ==
-				le16_to_cpu(udev->descriptor.idProduct)) {
-			found = true;
-			break;
-		}
-	}
-
-	if (!found) {
-		deb_info("%s: using dynamic ID %04x:%04x\n", __func__,
-				le16_to_cpu(udev->descriptor.idVendor),
-				le16_to_cpu(udev->descriptor.idProduct));
-		rtl28xxu_properties[0].devices[0].warm_ids[0]->idVendor =
-				le16_to_cpu(udev->descriptor.idVendor);
-		rtl28xxu_properties[0].devices[0].warm_ids[0]->idProduct =
-				le16_to_cpu(udev->descriptor.idProduct);
-	}
-
-	for (i = 0; i < properties_count; i++) {
-		ret = dvb_usb_device_init(intf, &rtl28xxu_properties[i],
-				THIS_MODULE, &d, adapter_nr);
-		if (ret == 0 || ret != -ENODEV)
-			break;
-	}
-
-	if (ret)
-		goto err;
-
-
-	/* init USB endpoints */
-	ret = rtl28xx_rd_reg(d, USB_SYSCTL_0, &val);
-	if (ret)
-			goto err;
-
-	/* enable DMA and Full Packet Mode*/
-	val |= 0x09;
-	ret = rtl28xx_wr_reg(d, USB_SYSCTL_0, val);
-	if (ret)
-		goto err;
-
-	/* set EPA maximum packet size to 0x0200 */
-	ret = rtl28xx_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4);
-	if (ret)
-		goto err;
-
-	/* change EPA FIFO length */
-	ret = rtl28xx_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4);
-	if (ret)
-		goto err;
-
-	return ret;
-err:
-	deb_info("%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static struct usb_driver rtl28xxu_driver = {
-	.name       = "dvb_usb_rtl28xxu",
-	.probe      = rtl28xxu_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table   = rtl28xxu_table,
-};
-
-/* module stuff */
-static int __init rtl28xxu_module_init(void)
-{
-	int ret;
-
-	deb_info("%s:\n", __func__);
-
-	ret = usb_register(&rtl28xxu_driver);
-	if (ret)
-		err("usb_register failed=%d", ret);
-
-	return ret;
-}
-
-static void __exit rtl28xxu_module_exit(void)
-{
-	deb_info("%s:\n", __func__);
-
-	/* deregister this driver from the USB subsystem */
-	usb_deregister(&rtl28xxu_driver);
-}
-
-module_init(rtl28xxu_module_init);
-module_exit(rtl28xxu_module_exit);
-
-MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver");
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_AUTHOR("Thomas Mair <thomas.mair86@googlemail.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.h b/drivers/media/dvb/dvb-usb/rtl28xxu.h
deleted file mode 100644
index 90f3bb4..0000000
--- a/drivers/media/dvb/dvb-usb/rtl28xxu.h
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Realtek RTL28xxU DVB USB driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef RTL28XXU_H
-#define RTL28XXU_H
-
-#define DVB_USB_LOG_PREFIX "rtl28xxu"
-#include "dvb-usb.h"
-
-#define deb_info(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x01, args)
-#define deb_rc(args...)   dprintk(dvb_usb_rtl28xxu_debug, 0x02, args)
-#define deb_xfer(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x04, args)
-#define deb_reg(args...)  dprintk(dvb_usb_rtl28xxu_debug, 0x08, args)
-#define deb_i2c(args...)  dprintk(dvb_usb_rtl28xxu_debug, 0x10, args)
-#define deb_fw(args...)   dprintk(dvb_usb_rtl28xxu_debug, 0x20, args)
-
-#define deb_dump(r, t, v, i, b, l, func) { \
-	int loop_; \
-	func("%02x %02x %02x %02x %02x %02x %02x %02x", \
-		t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \
-	if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
-		func(" >>> "); \
-	else \
-		func(" <<< "); \
-	for (loop_ = 0; loop_ < l; loop_++) \
-		func("%02x ", b[loop_]); \
-	func("\n");\
-}
-
-/*
- * USB commands
- * (usb_control_msg() index parameter)
- */
-
-#define DEMOD            0x0000
-#define USB              0x0100
-#define SYS              0x0200
-#define I2C              0x0300
-#define I2C_DA           0x0600
-
-#define CMD_WR_FLAG      0x0010
-#define CMD_DEMOD_RD     0x0000
-#define CMD_DEMOD_WR     0x0010
-#define CMD_USB_RD       0x0100
-#define CMD_USB_WR       0x0110
-#define CMD_SYS_RD       0x0200
-#define CMD_IR_RD        0x0201
-#define CMD_IR_WR        0x0211
-#define CMD_SYS_WR       0x0210
-#define CMD_I2C_RD       0x0300
-#define CMD_I2C_WR       0x0310
-#define CMD_I2C_DA_RD    0x0600
-#define CMD_I2C_DA_WR    0x0610
-
-
-struct rtl28xxu_priv {
-	u8 chip_id;
-	u8 tuner;
-	u8 page; /* integrated demod active register page */
-	bool rc_active;
-};
-
-enum rtl28xxu_chip_id {
-	CHIP_ID_NONE,
-	CHIP_ID_RTL2831U,
-	CHIP_ID_RTL2832U,
-};
-
-enum rtl28xxu_tuner {
-	TUNER_NONE,
-
-	TUNER_RTL2830_QT1010,
-	TUNER_RTL2830_MT2060,
-	TUNER_RTL2830_MXL5005S,
-
-	TUNER_RTL2832_MT2266,
-	TUNER_RTL2832_FC2580,
-	TUNER_RTL2832_MT2063,
-	TUNER_RTL2832_MAX3543,
-	TUNER_RTL2832_TUA9001,
-	TUNER_RTL2832_MXL5007T,
-	TUNER_RTL2832_FC0012,
-	TUNER_RTL2832_E4000,
-	TUNER_RTL2832_TDA18272,
-	TUNER_RTL2832_FC0013,
-};
-
-struct rtl28xxu_req {
-	u16 value;
-	u16 index;
-	u16 size;
-	u8 *data;
-};
-
-struct rtl28xxu_reg_val {
-	u16 reg;
-	u8 val;
-};
-
-/*
- * memory map
- *
- * 0x0000 DEMOD : demodulator
- * 0x2000 USB   : SIE, USB endpoint, debug, DMA
- * 0x3000 SYS   : system
- * 0xfc00 RC    : remote controller (not RTL2831U)
- */
-
-/*
- * USB registers
- */
-/* SIE Control Registers */
-#define USB_SYSCTL         0x2000 /* USB system control */
-#define USB_SYSCTL_0       0x2000 /* USB system control */
-#define USB_SYSCTL_1       0x2001 /* USB system control */
-#define USB_SYSCTL_2       0x2002 /* USB system control */
-#define USB_SYSCTL_3       0x2003 /* USB system control */
-#define USB_IRQSTAT        0x2008 /* SIE interrupt status */
-#define USB_IRQEN          0x200C /* SIE interrupt enable */
-#define USB_CTRL           0x2010 /* USB control */
-#define USB_STAT           0x2014 /* USB status */
-#define USB_DEVADDR        0x2018 /* USB device address */
-#define USB_TEST           0x201C /* USB test mode */
-#define USB_FRAME_NUMBER   0x2020 /* frame number */
-#define USB_FIFO_ADDR      0x2028 /* address of SIE FIFO RAM */
-#define USB_FIFO_CMD       0x202A /* SIE FIFO RAM access command */
-#define USB_FIFO_DATA      0x2030 /* SIE FIFO RAM data */
-/* Endpoint Registers */
-#define EP0_SETUPA         0x20F8 /* EP 0 setup packet lower byte */
-#define EP0_SETUPB         0x20FC /* EP 0 setup packet higher byte */
-#define USB_EP0_CFG        0x2104 /* EP 0 configure */
-#define USB_EP0_CTL        0x2108 /* EP 0 control */
-#define USB_EP0_STAT       0x210C /* EP 0 status */
-#define USB_EP0_IRQSTAT    0x2110 /* EP 0 interrupt status */
-#define USB_EP0_IRQEN      0x2114 /* EP 0 interrupt enable */
-#define USB_EP0_MAXPKT     0x2118 /* EP 0 max packet size */
-#define USB_EP0_BC         0x2120 /* EP 0 FIFO byte counter */
-#define USB_EPA_CFG        0x2144 /* EP A configure */
-#define USB_EPA_CFG_0      0x2144 /* EP A configure */
-#define USB_EPA_CFG_1      0x2145 /* EP A configure */
-#define USB_EPA_CFG_2      0x2146 /* EP A configure */
-#define USB_EPA_CFG_3      0x2147 /* EP A configure */
-#define USB_EPA_CTL        0x2148 /* EP A control */
-#define USB_EPA_CTL_0      0x2148 /* EP A control */
-#define USB_EPA_CTL_1      0x2149 /* EP A control */
-#define USB_EPA_CTL_2      0x214A /* EP A control */
-#define USB_EPA_CTL_3      0x214B /* EP A control */
-#define USB_EPA_STAT       0x214C /* EP A status */
-#define USB_EPA_IRQSTAT    0x2150 /* EP A interrupt status */
-#define USB_EPA_IRQEN      0x2154 /* EP A interrupt enable */
-#define USB_EPA_MAXPKT     0x2158 /* EP A max packet size */
-#define USB_EPA_MAXPKT_0   0x2158 /* EP A max packet size */
-#define USB_EPA_MAXPKT_1   0x2159 /* EP A max packet size */
-#define USB_EPA_MAXPKT_2   0x215A /* EP A max packet size */
-#define USB_EPA_MAXPKT_3   0x215B /* EP A max packet size */
-#define USB_EPA_FIFO_CFG   0x2160 /* EP A FIFO configure */
-#define USB_EPA_FIFO_CFG_0 0x2160 /* EP A FIFO configure */
-#define USB_EPA_FIFO_CFG_1 0x2161 /* EP A FIFO configure */
-#define USB_EPA_FIFO_CFG_2 0x2162 /* EP A FIFO configure */
-#define USB_EPA_FIFO_CFG_3 0x2163 /* EP A FIFO configure */
-/* Debug Registers */
-#define USB_PHYTSTDIS      0x2F04 /* PHY test disable */
-#define USB_TOUT_VAL       0x2F08 /* USB time-out time */
-#define USB_VDRCTRL        0x2F10 /* UTMI vendor signal control */
-#define USB_VSTAIN         0x2F14 /* UTMI vendor signal status in */
-#define USB_VLOADM         0x2F18 /* UTMI load vendor signal status in */
-#define USB_VSTAOUT        0x2F1C /* UTMI vendor signal status out */
-#define USB_UTMI_TST       0x2F80 /* UTMI test */
-#define USB_UTMI_STATUS    0x2F84 /* UTMI status */
-#define USB_TSTCTL         0x2F88 /* test control */
-#define USB_TSTCTL2        0x2F8C /* test control 2 */
-#define USB_PID_FORCE      0x2F90 /* force PID */
-#define USB_PKTERR_CNT     0x2F94 /* packet error counter */
-#define USB_RXERR_CNT      0x2F98 /* RX error counter */
-#define USB_MEM_BIST       0x2F9C /* MEM BIST test */
-#define USB_SLBBIST        0x2FA0 /* self-loop-back BIST */
-#define USB_CNTTEST        0x2FA4 /* counter test */
-#define USB_PHYTST         0x2FC0 /* USB PHY test */
-#define USB_DBGIDX         0x2FF0 /* select individual block debug signal */
-#define USB_DBGMUX         0x2FF4 /* debug signal module mux */
-
-/*
- * SYS registers
- */
-/* demod control registers */
-#define SYS_SYS0           0x3000 /* include DEMOD_CTL, GPO, GPI, GPOE */
-#define SYS_DEMOD_CTL      0x3000 /* control register for DVB-T demodulator */
-/* GPIO registers */
-#define SYS_GPIO_OUT_VAL   0x3001 /* output value of GPIO */
-#define SYS_GPIO_IN_VAL    0x3002 /* input value of GPIO */
-#define SYS_GPIO_OUT_EN    0x3003 /* output enable of GPIO */
-#define SYS_SYS1           0x3004 /* include GPD, SYSINTE, SYSINTS, GP_CFG0 */
-#define SYS_GPIO_DIR       0x3004 /* direction control for GPIO */
-#define SYS_SYSINTE        0x3005 /* system interrupt enable */
-#define SYS_SYSINTS        0x3006 /* system interrupt status */
-#define SYS_GPIO_CFG0      0x3007 /* PAD configuration for GPIO0-GPIO3 */
-#define SYS_SYS2           0x3008 /* include GP_CFG1 and 3 reserved bytes */
-#define SYS_GPIO_CFG1      0x3008 /* PAD configuration for GPIO4 */
-#define SYS_DEMOD_CTL1     0x300B
-
-/* IrDA registers */
-#define SYS_IRRC_PSR       0x3020 /* IR protocol selection */
-#define SYS_IRRC_PER       0x3024 /* IR protocol extension */
-#define SYS_IRRC_SF        0x3028 /* IR sampling frequency */
-#define SYS_IRRC_DPIR      0x302C /* IR data package interval */
-#define SYS_IRRC_CR        0x3030 /* IR control */
-#define SYS_IRRC_RP        0x3034 /* IR read port */
-#define SYS_IRRC_SR        0x3038 /* IR status */
-/* I2C master registers */
-#define SYS_I2CCR          0x3040 /* I2C clock */
-#define SYS_I2CMCR         0x3044 /* I2C master control */
-#define SYS_I2CMSTR        0x3048 /* I2C master SCL timing */
-#define SYS_I2CMSR         0x304C /* I2C master status */
-#define SYS_I2CMFR         0x3050 /* I2C master FIFO */
-
-/*
- * IR registers
- */
-#define IR_RX_BUF          0xFC00
-#define IR_RX_IE           0xFD00
-#define IR_RX_IF           0xFD01
-#define IR_RX_CTRL         0xFD02
-#define IR_RX_CFG          0xFD03
-#define IR_MAX_DURATION0   0xFD04
-#define IR_MAX_DURATION1   0xFD05
-#define IR_IDLE_LEN0       0xFD06
-#define IR_IDLE_LEN1       0xFD07
-#define IR_GLITCH_LEN      0xFD08
-#define IR_RX_BUF_CTRL     0xFD09
-#define IR_RX_BUF_DATA     0xFD0A
-#define IR_RX_BC           0xFD0B
-#define IR_RX_CLK          0xFD0C
-#define IR_RX_C_COUNT_L    0xFD0D
-#define IR_RX_C_COUNT_H    0xFD0E
-#define IR_SUSPEND_CTRL    0xFD10
-#define IR_ERR_TOL_CTRL    0xFD11
-#define IR_UNIT_LEN        0xFD12
-#define IR_ERR_TOL_LEN     0xFD13
-#define IR_MAX_H_TOL_LEN   0xFD14
-#define IR_MAX_L_TOL_LEN   0xFD15
-#define IR_MASK_CTRL       0xFD16
-#define IR_MASK_DATA       0xFD17
-#define IR_RES_MASK_ADDR   0xFD18
-#define IR_RES_MASK_T_LEN  0xFD19
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/technisat-usb2.c b/drivers/media/dvb/dvb-usb/technisat-usb2.c
deleted file mode 100644
index acefaa8..0000000
--- a/drivers/media/dvb/dvb-usb/technisat-usb2.c
+++ /dev/null
@@ -1,789 +0,0 @@
-/*
- * Linux driver for Technisat DVB-S/S2 USB 2.0 device
- *
- * Copyright (C) 2010 Patrick Boettcher,
- *                    Kernel Labs Inc. PO Box 745, St James, NY 11780
- *
- * Development was sponsored by Technisat Digital UK Limited, whose
- * registered office is Witan Gate House 500 - 600 Witan Gate West,
- * Milton Keynes, MK9 1SH
- *
- * 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.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * THIS PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND
- * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO
- * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR
- * FITNESS FOR A PARTICULAR PURPOSE.  NEITHER THE COPYRIGHT HOLDER
- * NOR TECHNISAT DIGITAL UK LIMITED SHALL BE LIABLE FOR ANY SPECIAL,
- * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
- * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PROGRAM. See the
- * GNU General Public License for more details.
- */
-
-#define DVB_USB_LOG_PREFIX "technisat-usb2"
-#include "dvb-usb.h"
-
-#include "stv6110x.h"
-#include "stv090x.h"
-
-/* module parameters */
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug,
-		"set debugging level (bit-mask: 1=info,2=eeprom,4=i2c,8=rc)." \
-		DVB_USB_DEBUG_STATUS);
-
-/* disables all LED control command and
- * also does not start the signal polling thread */
-static int disable_led_control;
-module_param(disable_led_control, int, 0444);
-MODULE_PARM_DESC(disable_led_control,
-		"disable LED control of the device "
-		"(default: 0 - LED control is active).");
-
-/* device private data */
-struct technisat_usb2_state {
-	struct dvb_usb_device *dev;
-	struct delayed_work green_led_work;
-	u8 power_state;
-
-	u16 last_scan_code;
-};
-
-/* debug print helpers */
-#define deb_info(args...)    dprintk(debug, 0x01, args)
-#define deb_eeprom(args...)  dprintk(debug, 0x02, args)
-#define deb_i2c(args...)     dprintk(debug, 0x04, args)
-#define deb_rc(args...)      dprintk(debug, 0x08, args)
-
-/* vendor requests */
-#define SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST 0xB3
-#define SET_FRONT_END_RESET_VENDOR_REQUEST         0xB4
-#define GET_VERSION_INFO_VENDOR_REQUEST            0xB5
-#define SET_GREEN_LED_VENDOR_REQUEST               0xB6
-#define SET_RED_LED_VENDOR_REQUEST                 0xB7
-#define GET_IR_DATA_VENDOR_REQUEST                 0xB8
-#define SET_LED_TIMER_DIVIDER_VENDOR_REQUEST       0xB9
-#define SET_USB_REENUMERATION                      0xBA
-
-/* i2c-access methods */
-#define I2C_SPEED_100KHZ_BIT 0x40
-
-#define I2C_STATUS_NAK 7
-#define I2C_STATUS_OK 8
-
-static int technisat_usb2_i2c_access(struct usb_device *udev,
-		u8 device_addr, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
-{
-	u8 b[64];
-	int ret, actual_length;
-
-	deb_i2c("i2c-access: %02x, tx: ", device_addr);
-	debug_dump(tx, txlen, deb_i2c);
-	deb_i2c(" ");
-
-	if (txlen > 62) {
-		err("i2c TX buffer can't exceed 62 bytes (dev 0x%02x)",
-				device_addr);
-		txlen = 62;
-	}
-	if (rxlen > 62) {
-		err("i2c RX buffer can't exceed 62 bytes (dev 0x%02x)",
-				device_addr);
-		txlen = 62;
-	}
-
-	b[0] = I2C_SPEED_100KHZ_BIT;
-	b[1] = device_addr << 1;
-
-	if (rx != NULL) {
-		b[0] |= rxlen;
-		b[1] |= 1;
-	}
-
-	memcpy(&b[2], tx, txlen);
-	ret = usb_bulk_msg(udev,
-			usb_sndbulkpipe(udev, 0x01),
-			b, 2 + txlen,
-			NULL, 1000);
-
-	if (ret < 0) {
-		err("i2c-error: out failed %02x = %d", device_addr, ret);
-		return -ENODEV;
-	}
-
-	ret = usb_bulk_msg(udev,
-			usb_rcvbulkpipe(udev, 0x01),
-			b, 64, &actual_length, 1000);
-	if (ret < 0) {
-		err("i2c-error: in failed %02x = %d", device_addr, ret);
-		return -ENODEV;
-	}
-
-	if (b[0] != I2C_STATUS_OK) {
-		err("i2c-error: %02x = %d", device_addr, b[0]);
-		/* handle tuner-i2c-nak */
-		if (!(b[0] == I2C_STATUS_NAK &&
-				device_addr == 0x60
-				/* && device_is_technisat_usb2 */))
-			return -ENODEV;
-	}
-
-	deb_i2c("status: %d, ", b[0]);
-
-	if (rx != NULL) {
-		memcpy(rx, &b[2], rxlen);
-
-		deb_i2c("rx (%d): ", rxlen);
-		debug_dump(rx, rxlen, deb_i2c);
-	}
-
-	deb_i2c("\n");
-
-	return 0;
-}
-
-static int technisat_usb2_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
-				int num)
-{
-	int ret = 0, i;
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-
-	/* Ensure nobody else hits the i2c bus while we're sending our
-	   sequence of messages, (such as the remote control thread) */
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	for (i = 0; i < num; i++) {
-		if (i+1 < num && msg[i+1].flags & I2C_M_RD) {
-			ret = technisat_usb2_i2c_access(d->udev, msg[i+1].addr,
-						msg[i].buf, msg[i].len,
-						msg[i+1].buf, msg[i+1].len);
-			if (ret != 0)
-				break;
-			i++;
-		} else {
-			ret = technisat_usb2_i2c_access(d->udev, msg[i].addr,
-						msg[i].buf, msg[i].len,
-						NULL, 0);
-			if (ret != 0)
-				break;
-		}
-	}
-
-	if (ret == 0)
-		ret = i;
-
-	mutex_unlock(&d->i2c_mutex);
-
-	return ret;
-}
-
-static u32 technisat_usb2_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm technisat_usb2_i2c_algo = {
-	.master_xfer   = technisat_usb2_i2c_xfer,
-	.functionality = technisat_usb2_i2c_func,
-};
-
-#if 0
-static void technisat_usb2_frontend_reset(struct usb_device *udev)
-{
-	usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-			SET_FRONT_END_RESET_VENDOR_REQUEST,
-			USB_TYPE_VENDOR | USB_DIR_OUT,
-			10, 0,
-			NULL, 0, 500);
-}
-#endif
-
-/* LED control */
-enum technisat_usb2_led_state {
-	LED_OFF,
-	LED_BLINK,
-	LED_ON,
-	LED_UNDEFINED
-};
-
-static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum technisat_usb2_led_state state)
-{
-	int ret;
-
-	u8 led[8] = {
-		red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST,
-		0
-	};
-
-	if (disable_led_control && state != LED_OFF)
-		return 0;
-
-	switch (state) {
-	case LED_ON:
-		led[1] = 0x82;
-		break;
-	case LED_BLINK:
-		led[1] = 0x82;
-		if (red) {
-			led[2] = 0x02;
-			led[3] = 10;
-			led[4] = 10;
-		} else {
-			led[2] = 0xff;
-			led[3] = 50;
-			led[4] = 50;
-		}
-		led[5] = 1;
-		break;
-
-	default:
-	case LED_OFF:
-		led[1] = 0x80;
-		break;
-	}
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
-		red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST,
-		USB_TYPE_VENDOR | USB_DIR_OUT,
-		0, 0,
-		led, sizeof(led), 500);
-
-	mutex_unlock(&d->i2c_mutex);
-	return ret;
-}
-
-static int technisat_usb2_set_led_timer(struct dvb_usb_device *d, u8 red, u8 green)
-{
-	int ret;
-	u8 b = 0;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
-		SET_LED_TIMER_DIVIDER_VENDOR_REQUEST,
-		USB_TYPE_VENDOR | USB_DIR_OUT,
-		(red << 8) | green, 0,
-		&b, 1, 500);
-
-	mutex_unlock(&d->i2c_mutex);
-
-	return ret;
-}
-
-static void technisat_usb2_green_led_control(struct work_struct *work)
-{
-	struct technisat_usb2_state *state =
-		container_of(work, struct technisat_usb2_state, green_led_work.work);
-	struct dvb_frontend *fe = state->dev->adapter[0].fe_adap[0].fe;
-
-	if (state->power_state == 0)
-		goto schedule;
-
-	if (fe != NULL) {
-		enum fe_status status;
-
-		if (fe->ops.read_status(fe, &status) != 0)
-			goto schedule;
-
-		if (status & FE_HAS_LOCK) {
-			u32 ber;
-
-			if (fe->ops.read_ber(fe, &ber) != 0)
-				goto schedule;
-
-			if (ber > 1000)
-				technisat_usb2_set_led(state->dev, 0, LED_BLINK);
-			else
-				technisat_usb2_set_led(state->dev, 0, LED_ON);
-		} else
-			technisat_usb2_set_led(state->dev, 0, LED_OFF);
-	}
-
-schedule:
-	schedule_delayed_work(&state->green_led_work,
-			msecs_to_jiffies(500));
-}
-
-/* method to find out whether the firmware has to be downloaded or not */
-static int technisat_usb2_identify_state(struct usb_device *udev,
-		struct dvb_usb_device_properties *props,
-		struct dvb_usb_device_description **desc, int *cold)
-{
-	int ret;
-	u8 version[3];
-
-	/* first select the interface */
-	if (usb_set_interface(udev, 0, 1) != 0)
-		err("could not set alternate setting to 0");
-	else
-		info("set alternate setting");
-
-	*cold = 0; /* by default do not download a firmware - just in case something is wrong */
-
-	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-		GET_VERSION_INFO_VENDOR_REQUEST,
-		USB_TYPE_VENDOR | USB_DIR_IN,
-		0, 0,
-		version, sizeof(version), 500);
-
-	if (ret < 0)
-		*cold = 1;
-	else {
-		info("firmware version: %d.%d", version[1], version[2]);
-		*cold = 0;
-	}
-
-	return 0;
-}
-
-/* power control */
-static int technisat_usb2_power_ctrl(struct dvb_usb_device *d, int level)
-{
-	struct technisat_usb2_state *state = d->priv;
-
-	state->power_state = level;
-
-	if (disable_led_control)
-		return 0;
-
-	/* green led is turned off in any case - will be turned on when tuning */
-	technisat_usb2_set_led(d, 0, LED_OFF);
-	/* red led is turned on all the time */
-	technisat_usb2_set_led(d, 1, LED_ON);
-	return 0;
-}
-
-/* mac address reading - from the eeprom */
-#if 0
-static void technisat_usb2_eeprom_dump(struct dvb_usb_device *d)
-{
-	u8 reg;
-	u8 b[16];
-	int i, j;
-
-	/* full EEPROM dump */
-	for (j = 0; j < 256 * 4; j += 16) {
-		reg = j;
-		if (technisat_usb2_i2c_access(d->udev, 0x50 + j / 256, &reg, 1, b, 16) != 0)
-			break;
-
-		deb_eeprom("EEPROM: %01x%02x: ", j / 256, reg);
-		for (i = 0; i < 16; i++)
-			deb_eeprom("%02x ", b[i]);
-		deb_eeprom("\n");
-	}
-}
-#endif
-
-static u8 technisat_usb2_calc_lrc(const u8 *b, u16 length)
-{
-	u8 lrc = 0;
-	while (--length)
-		lrc ^= *b++;
-	return lrc;
-}
-
-static int technisat_usb2_eeprom_lrc_read(struct dvb_usb_device *d,
-	u16 offset, u8 *b, u16 length, u8 tries)
-{
-	u8 bo = offset & 0xff;
-	struct i2c_msg msg[] = {
-		{
-			.addr = 0x50 | ((offset >> 8) & 0x3),
-			.buf = &bo,
-			.len = 1
-		}, {
-			.addr = 0x50 | ((offset >> 8) & 0x3),
-			.flags	= I2C_M_RD,
-			.buf = b,
-			.len = length
-		}
-	};
-
-	while (tries--) {
-		int status;
-
-		if (i2c_transfer(&d->i2c_adap, msg, 2) != 2)
-			break;
-
-		status =
-			technisat_usb2_calc_lrc(b, length - 1) == b[length - 1];
-
-		if (status)
-			return 0;
-	}
-
-	return -EREMOTEIO;
-}
-
-#define EEPROM_MAC_START 0x3f8
-#define EEPROM_MAC_TOTAL 8
-static int technisat_usb2_read_mac_address(struct dvb_usb_device *d,
-		u8 mac[])
-{
-	u8 buf[EEPROM_MAC_TOTAL];
-
-	if (technisat_usb2_eeprom_lrc_read(d, EEPROM_MAC_START,
-				buf, EEPROM_MAC_TOTAL, 4) != 0)
-		return -ENODEV;
-
-	memcpy(mac, buf, 6);
-	return 0;
-}
-
-/* frontend attach */
-static int technisat_usb2_set_voltage(struct dvb_frontend *fe,
-		fe_sec_voltage_t voltage)
-{
-	int i;
-	u8 gpio[3] = { 0 }; /* 0 = 2, 1 = 3, 2 = 4 */
-
-	gpio[2] = 1; /* high - voltage ? */
-
-	switch (voltage) {
-	case SEC_VOLTAGE_13:
-		gpio[0] = 1;
-		break;
-	case SEC_VOLTAGE_18:
-		gpio[0] = 1;
-		gpio[1] = 1;
-		break;
-	default:
-	case SEC_VOLTAGE_OFF:
-		break;
-	}
-
-	for (i = 0; i < 3; i++)
-		if (stv090x_set_gpio(fe, i+2, 0, gpio[i], 0) != 0)
-			return -EREMOTEIO;
-	return 0;
-}
-
-static struct stv090x_config technisat_usb2_stv090x_config = {
-	.device         = STV0903,
-	.demod_mode     = STV090x_SINGLE,
-	.clk_mode       = STV090x_CLK_EXT,
-
-	.xtal           = 8000000,
-	.address        = 0x68,
-
-	.ts1_mode       = STV090x_TSMODE_DVBCI,
-	.ts1_clk        = 13400000,
-	.ts1_tei        = 1,
-
-	.repeater_level = STV090x_RPTLEVEL_64,
-
-	.tuner_bbgain   = 6,
-};
-
-static struct stv6110x_config technisat_usb2_stv6110x_config = {
-	.addr           = 0x60,
-	.refclk         = 16000000,
-	.clk_div        = 2,
-};
-
-static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a)
-{
-	struct usb_device *udev = a->dev->udev;
-	int ret;
-
-	a->fe_adap[0].fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config,
-			&a->dev->i2c_adap, STV090x_DEMODULATOR_0);
-
-	if (a->fe_adap[0].fe) {
-		struct stv6110x_devctl *ctl;
-
-		ctl = dvb_attach(stv6110x_attach,
-				a->fe_adap[0].fe,
-				&technisat_usb2_stv6110x_config,
-				&a->dev->i2c_adap);
-
-		if (ctl) {
-			technisat_usb2_stv090x_config.tuner_init          = ctl->tuner_init;
-			technisat_usb2_stv090x_config.tuner_sleep         = ctl->tuner_sleep;
-			technisat_usb2_stv090x_config.tuner_set_mode      = ctl->tuner_set_mode;
-			technisat_usb2_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
-			technisat_usb2_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
-			technisat_usb2_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
-			technisat_usb2_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
-			technisat_usb2_stv090x_config.tuner_set_bbgain    = ctl->tuner_set_bbgain;
-			technisat_usb2_stv090x_config.tuner_get_bbgain    = ctl->tuner_get_bbgain;
-			technisat_usb2_stv090x_config.tuner_set_refclk    = ctl->tuner_set_refclk;
-			technisat_usb2_stv090x_config.tuner_get_status    = ctl->tuner_get_status;
-
-			/* call the init function once to initialize
-			   tuner's clock output divider and demod's
-			   master clock */
-			if (a->fe_adap[0].fe->ops.init)
-				a->fe_adap[0].fe->ops.init(a->fe_adap[0].fe);
-
-			if (mutex_lock_interruptible(&a->dev->i2c_mutex) < 0)
-				return -EAGAIN;
-
-			ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-					SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST,
-					USB_TYPE_VENDOR | USB_DIR_OUT,
-					0, 0,
-					NULL, 0, 500);
-			mutex_unlock(&a->dev->i2c_mutex);
-
-			if (ret != 0)
-				err("could not set IF_CLK to external");
-
-			a->fe_adap[0].fe->ops.set_voltage = technisat_usb2_set_voltage;
-
-			/* if everything was successful assign a nice name to the frontend */
-			strlcpy(a->fe_adap[0].fe->ops.info.name, a->dev->desc->name,
-					sizeof(a->fe_adap[0].fe->ops.info.name));
-		} else {
-			dvb_frontend_detach(a->fe_adap[0].fe);
-			a->fe_adap[0].fe = NULL;
-		}
-	}
-
-	technisat_usb2_set_led_timer(a->dev, 1, 1);
-
-	return a->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-/* Remote control */
-
-/* the device is giving providing raw IR-signals to the host mapping
- * it only to one remote control is just the default implementation
- */
-#define NOMINAL_IR_BIT_TRANSITION_TIME_US 889
-#define NOMINAL_IR_BIT_TIME_US (2 * NOMINAL_IR_BIT_TRANSITION_TIME_US)
-
-#define FIRMWARE_CLOCK_TICK 83333
-#define FIRMWARE_CLOCK_DIVISOR 256
-
-#define IR_PERCENT_TOLERANCE 15
-
-#define NOMINAL_IR_BIT_TRANSITION_TICKS ((NOMINAL_IR_BIT_TRANSITION_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK)
-#define NOMINAL_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICKS / FIRMWARE_CLOCK_DIVISOR)
-
-#define NOMINAL_IR_BIT_TIME_TICKS ((NOMINAL_IR_BIT_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK)
-#define NOMINAL_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICKS / FIRMWARE_CLOCK_DIVISOR)
-
-#define MINIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT - ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
-#define MAXIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT + ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
-
-#define MINIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT - ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
-#define MAXIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT + ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
-
-static int technisat_usb2_get_ir(struct dvb_usb_device *d)
-{
-	u8 buf[62], *b;
-	int ret;
-	struct ir_raw_event ev;
-
-	buf[0] = GET_IR_DATA_VENDOR_REQUEST;
-	buf[1] = 0x08;
-	buf[2] = 0x8f;
-	buf[3] = MINIMUM_IR_BIT_TRANSITION_TICK_COUNT;
-	buf[4] = MAXIMUM_IR_BIT_TIME_TICK_COUNT;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-	ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
-			GET_IR_DATA_VENDOR_REQUEST,
-			USB_TYPE_VENDOR | USB_DIR_OUT,
-			0, 0,
-			buf, 5, 500);
-	if (ret < 0)
-		goto unlock;
-
-	buf[1] = 0;
-	buf[2] = 0;
-	ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
-			GET_IR_DATA_VENDOR_REQUEST,
-			USB_TYPE_VENDOR | USB_DIR_IN,
-			0x8080, 0,
-			buf, sizeof(buf), 500);
-
-unlock:
-	mutex_unlock(&d->i2c_mutex);
-
-	if (ret < 0)
-		return ret;
-
-	if (ret == 1)
-		return 0; /* no key pressed */
-
-	/* decoding */
-	b = buf+1;
-
-#if 0
-	deb_rc("RC: %d ", ret);
-	debug_dump(b, ret, deb_rc);
-#endif
-
-	ev.pulse = 0;
-	while (1) {
-		ev.pulse = !ev.pulse;
-		ev.duration = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000;
-		ir_raw_event_store(d->rc_dev, &ev);
-
-		b++;
-		if (*b == 0xff) {
-			ev.pulse = 0;
-			ev.duration = 888888*2;
-			ir_raw_event_store(d->rc_dev, &ev);
-			break;
-		}
-	}
-
-	ir_raw_event_handle(d->rc_dev);
-
-	return 1;
-}
-
-static int technisat_usb2_rc_query(struct dvb_usb_device *d)
-{
-	int ret = technisat_usb2_get_ir(d);
-
-	if (ret < 0)
-		return ret;
-
-	if (ret == 0)
-		return 0;
-
-	if (!disable_led_control)
-		technisat_usb2_set_led(d, 1, LED_BLINK);
-
-	return 0;
-}
-
-/* DVB-USB and USB stuff follows */
-static struct usb_device_id technisat_usb2_id_table[] = {
-	{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_DVB_S2) },
-	{ 0 }		/* Terminating entry */
-};
-
-/* device description */
-static struct dvb_usb_device_properties technisat_usb2_devices = {
-	.caps              = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl          = CYPRESS_FX2,
-
-	.identify_state    = technisat_usb2_identify_state,
-	.firmware          = "dvb-usb-SkyStar_USB_HD_FW_v17_63.HEX.fw",
-
-	.size_of_priv      = sizeof(struct technisat_usb2_state),
-
-	.i2c_algo          = &technisat_usb2_i2c_algo,
-
-	.power_ctrl        = technisat_usb2_power_ctrl,
-	.read_mac_address  = technisat_usb2_read_mac_address,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.frontend_attach  = technisat_usb2_frontend_attach,
-
-			.stream = {
-				.type = USB_ISOC,
-				.count = 8,
-				.endpoint = 0x2,
-				.u = {
-					.isoc = {
-						.framesperurb = 32,
-						.framesize = 2048,
-						.interval = 3,
-					}
-				}
-			},
-		}},
-			.size_of_priv = 0,
-		},
-	},
-
-	.num_device_descs = 1,
-	.devices = {
-		{   "Technisat SkyStar USB HD (DVB-S/S2)",
-			{ &technisat_usb2_id_table[0], NULL },
-			{ NULL },
-		},
-	},
-
-	.rc.core = {
-		.rc_interval = 100,
-		.rc_codes    = RC_MAP_TECHNISAT_USB2,
-		.module_name = "technisat-usb2",
-		.rc_query    = technisat_usb2_rc_query,
-		.allowed_protos = RC_TYPE_ALL,
-		.driver_type    = RC_DRIVER_IR_RAW,
-	}
-};
-
-static int technisat_usb2_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	struct dvb_usb_device *dev;
-
-	if (dvb_usb_device_init(intf, &technisat_usb2_devices, THIS_MODULE,
-				&dev, adapter_nr) != 0)
-		return -ENODEV;
-
-	if (dev) {
-		struct technisat_usb2_state *state = dev->priv;
-		state->dev = dev;
-
-		if (!disable_led_control) {
-			INIT_DELAYED_WORK(&state->green_led_work,
-					technisat_usb2_green_led_control);
-			schedule_delayed_work(&state->green_led_work,
-					msecs_to_jiffies(500));
-		}
-	}
-
-	return 0;
-}
-
-static void technisat_usb2_disconnect(struct usb_interface *intf)
-{
-	struct dvb_usb_device *dev = usb_get_intfdata(intf);
-
-	/* work and stuff was only created when the device is is hot-state */
-	if (dev != NULL) {
-		struct technisat_usb2_state *state = dev->priv;
-		if (state != NULL)
-			cancel_delayed_work_sync(&state->green_led_work);
-	}
-
-	dvb_usb_device_exit(intf);
-}
-
-static struct usb_driver technisat_usb2_driver = {
-	.name       = "dvb_usb_technisat_usb2",
-	.probe      = technisat_usb2_probe,
-	.disconnect = technisat_usb2_disconnect,
-	.id_table   = technisat_usb2_id_table,
-};
-
-module_usb_driver(technisat_usb2_driver);
-
-MODULE_AUTHOR("Patrick Boettcher <pboettcher@kernellabs.com>");
-MODULE_DESCRIPTION("Driver for Technisat DVB-S/S2 USB 2.0 device");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c
deleted file mode 100644
index e53a106..0000000
--- a/drivers/media/dvb/dvb-usb/ttusb2.c
+++ /dev/null
@@ -1,820 +0,0 @@
-/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones
- * (e.g. Pinnacle 400e DVB-S USB2.0).
- *
- * The Pinnacle 400e uses the same protocol as the Technotrend USB1.1 boxes.
- *
- * TDA8263 + TDA10086
- *
- * I2C addresses:
- * 0x08 - LNBP21PD   - LNB power supply
- * 0x0e - TDA10086   - Demodulator
- * 0x50 - FX2 eeprom
- * 0x60 - TDA8263    - Tuner
- * 0x78 ???
- *
- * Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
- * Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net>
- * Copyright (C) 2005-6 Patrick Boettcher <pb@linuxtv.org>
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#define DVB_USB_LOG_PREFIX "ttusb2"
-#include "dvb-usb.h"
-
-#include "ttusb2.h"
-
-#include "tda826x.h"
-#include "tda10086.h"
-#include "tda1002x.h"
-#include "tda10048.h"
-#include "tda827x.h"
-#include "lnbp21.h"
-/* CA */
-#include "dvb_ca_en50221.h"
-
-/* debug */
-static int dvb_usb_ttusb2_debug;
-#define deb_info(args...)   dprintk(dvb_usb_ttusb2_debug,0x01,args)
-module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS);
-static int dvb_usb_ttusb2_debug_ci;
-module_param_named(debug_ci,dvb_usb_ttusb2_debug_ci, int, 0644);
-MODULE_PARM_DESC(debug_ci, "set debugging ci." DVB_USB_DEBUG_STATUS);
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define ci_dbg(format, arg...)                \
-do {                                          \
-	if (dvb_usb_ttusb2_debug_ci)                                    \
-		printk(KERN_DEBUG DVB_USB_LOG_PREFIX \
-			": %s " format "\n" , __func__, ## arg);       \
-} while (0)
-
-enum {
-	TT3650_CMD_CI_TEST = 0x40,
-	TT3650_CMD_CI_RD_CTRL,
-	TT3650_CMD_CI_WR_CTRL,
-	TT3650_CMD_CI_RD_ATTR,
-	TT3650_CMD_CI_WR_ATTR,
-	TT3650_CMD_CI_RESET,
-	TT3650_CMD_CI_SET_VIDEO_PORT
-};
-
-struct ttusb2_state {
-	struct dvb_ca_en50221 ca;
-	struct mutex ca_mutex;
-	u8 id;
-	u16 last_rc_key;
-};
-
-static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd,
-		u8 *wbuf, int wlen, u8 *rbuf, int rlen)
-{
-	struct ttusb2_state *st = d->priv;
-	u8 *s, *r = NULL;
-	int ret = 0;
-
-	s = kzalloc(wlen+4, GFP_KERNEL);
-	if (!s)
-		return -ENOMEM;
-
-	r = kzalloc(64, GFP_KERNEL);
-	if (!r) {
-		kfree(s);
-		return -ENOMEM;
-	}
-
-	s[0] = 0xaa;
-	s[1] = ++st->id;
-	s[2] = cmd;
-	s[3] = wlen;
-	memcpy(&s[4],wbuf,wlen);
-
-	ret = dvb_usb_generic_rw(d, s, wlen+4, r, 64, 0);
-
-	if (ret  != 0 ||
-		r[0] != 0x55 ||
-		r[1] != s[1] ||
-		r[2] != cmd ||
-		(rlen > 0 && r[3] != rlen)) {
-		warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]);
-		kfree(s);
-		kfree(r);
-		return -EIO;
-	}
-
-	if (rlen > 0)
-		memcpy(rbuf, &r[4], rlen);
-
-	kfree(s);
-	kfree(r);
-
-	return 0;
-}
-
-/* ci */
-static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len)
-{
-	int ret;
-	u8 rx[60];/* (64 -4) */
-	ret = ttusb2_msg(d, cmd, data, write_len, rx, read_len);
-	if (!ret)
-		memcpy(data, rx, read_len);
-	return ret;
-}
-
-static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len)
-{
-	struct dvb_usb_device *d = ca->data;
-	struct ttusb2_state *state = d->priv;
-	int ret;
-
-	mutex_lock(&state->ca_mutex);
-	ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
-	mutex_unlock(&state->ca_mutex);
-
-	return ret;
-}
-
-static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
-{
-	u8 buf[3];
-	int ret = 0;
-
-	if (slot)
-		return -EINVAL;
-
-	buf[0] = (address >> 8) & 0x0F;
-	buf[1] = address;
-
-
-	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
-
-	ci_dbg("%04x -> %d 0x%02x", address, ret, buf[2]);
-
-	if (ret < 0)
-		return ret;
-
-	return buf[2];
-}
-
-static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
-{
-	u8 buf[3];
-
-	ci_dbg("%d 0x%04x 0x%02x", slot, address, value);
-
-	if (slot)
-		return -EINVAL;
-
-	buf[0] = (address >> 8) & 0x0F;
-	buf[1] = address;
-	buf[2] = value;
-
-	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
-}
-
-static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
-{
-	u8 buf[2];
-	int ret;
-
-	if (slot)
-		return -EINVAL;
-
-	buf[0] = address & 3;
-
-	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
-
-	ci_dbg("0x%02x -> %d 0x%02x", address, ret, buf[1]);
-
-	if (ret < 0)
-		return ret;
-
-	return buf[1];
-}
-
-static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
-{
-	u8 buf[2];
-
-	ci_dbg("%d 0x%02x 0x%02x", slot, address, value);
-
-	if (slot)
-		return -EINVAL;
-
-	buf[0] = address;
-	buf[1] = value;
-
-	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
-}
-
-static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca, int slot, int enable)
-{
-	u8 buf[1];
-	int ret;
-
-	ci_dbg("%d %d", slot, enable);
-
-	if (slot)
-		return -EINVAL;
-
-	buf[0] = enable;
-
-	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
-	if (ret < 0)
-		return ret;
-
-	if (enable != buf[0]) {
-		err("CI not %sabled.", enable ? "en" : "dis");
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
-{
-	return tt3650_ci_set_video_port(ca, slot, 0);
-}
-
-static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
-{
-	return tt3650_ci_set_video_port(ca, slot, 1);
-}
-
-static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
-{
-	struct dvb_usb_device *d = ca->data;
-	struct ttusb2_state *state = d->priv;
-	u8 buf[1];
-	int ret;
-
-	ci_dbg("%d", slot);
-
-	if (slot)
-		return -EINVAL;
-
-	buf[0] = 0;
-
-	mutex_lock(&state->ca_mutex);
-
-	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
-	if (ret)
-		goto failed;
-
-	msleep(500);
-
-	buf[0] = 1;
-
-	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
-	if (ret)
-		goto failed;
-
-	msleep(500);
-
-	buf[0] = 0; /* FTA */
-
-	ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
-
-	msleep(1100);
-
- failed:
-	mutex_unlock(&state->ca_mutex);
-
-	return ret;
-}
-
-static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
-{
-	u8 buf[1];
-	int ret;
-
-	if (slot)
-		return -EINVAL;
-
-	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
-	if (ret)
-		return ret;
-
-	if (1 == buf[0]) {
-		return DVB_CA_EN50221_POLL_CAM_PRESENT |
-			DVB_CA_EN50221_POLL_CAM_READY;
-	}
-	return 0;
-}
-
-static void tt3650_ci_uninit(struct dvb_usb_device *d)
-{
-	struct ttusb2_state *state;
-
-	ci_dbg("");
-
-	if (NULL == d)
-		return;
-
-	state = d->priv;
-	if (NULL == state)
-		return;
-
-	if (NULL == state->ca.data)
-		return;
-
-	dvb_ca_en50221_release(&state->ca);
-
-	memset(&state->ca, 0, sizeof(state->ca));
-}
-
-static int tt3650_ci_init(struct dvb_usb_adapter *a)
-{
-	struct dvb_usb_device *d = a->dev;
-	struct ttusb2_state *state = d->priv;
-	int ret;
-
-	ci_dbg("");
-
-	mutex_init(&state->ca_mutex);
-
-	state->ca.owner = THIS_MODULE;
-	state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
-	state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
-	state->ca.read_cam_control = tt3650_ci_read_cam_control;
-	state->ca.write_cam_control = tt3650_ci_write_cam_control;
-	state->ca.slot_reset = tt3650_ci_slot_reset;
-	state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
-	state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
-	state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
-	state->ca.data = d;
-
-	ret = dvb_ca_en50221_init(&a->dvb_adap,
-				  &state->ca,
-				  /* flags */ 0,
-				  /* n_slots */ 1);
-	if (ret) {
-		err("Cannot initialize CI: Error %d.", ret);
-		memset(&state->ca, 0, sizeof(state->ca));
-		return ret;
-	}
-
-	info("CI initialized.");
-
-	return 0;
-}
-
-static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
-{
-	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	static u8 obuf[60], ibuf[60];
-	int i, write_read, read;
-
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
-	if (num > 2)
-		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
-
-	for (i = 0; i < num; i++) {
-		write_read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
-		read = msg[i].flags & I2C_M_RD;
-
-		obuf[0] = (msg[i].addr << 1) | (write_read | read);
-		if (read)
-			obuf[1] = 0;
-		else
-			obuf[1] = msg[i].len;
-
-		/* read request */
-		if (write_read)
-			obuf[2] = msg[i+1].len;
-		else if (read)
-			obuf[2] = msg[i].len;
-		else
-			obuf[2] = 0;
-
-		memcpy(&obuf[3], msg[i].buf, msg[i].len);
-
-		if (ttusb2_msg(d, CMD_I2C_XFER, obuf, obuf[1]+3, ibuf, obuf[2] + 3) < 0) {
-			err("i2c transfer failed.");
-			break;
-		}
-
-		if (write_read) {
-			memcpy(msg[i+1].buf, &ibuf[3], msg[i+1].len);
-			i++;
-		} else if (read)
-			memcpy(msg[i].buf, &ibuf[3], msg[i].len);
-	}
-
-	mutex_unlock(&d->i2c_mutex);
-	return i;
-}
-
-static u32 ttusb2_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm ttusb2_i2c_algo = {
-	.master_xfer   = ttusb2_i2c_xfer,
-	.functionality = ttusb2_i2c_func,
-};
-
-/* command to poll IR receiver (copied from pctv452e.c) */
-#define CMD_GET_IR_CODE     0x1b
-
-/* IR */
-static int tt3650_rc_query(struct dvb_usb_device *d)
-{
-	int ret;
-	u8 rx[9]; /* A CMD_GET_IR_CODE reply is 9 bytes long */
-	struct ttusb2_state *st = d->priv;
-	ret = ttusb2_msg(d, CMD_GET_IR_CODE, NULL, 0, rx, sizeof(rx));
-	if (ret != 0)
-		return ret;
-
-	if (rx[8] & 0x01) {
-		/* got a "press" event */
-		st->last_rc_key = (rx[3] << 8) | rx[2];
-		deb_info("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[2], rx[3]);
-		rc_keydown(d->rc_dev, st->last_rc_key, 0);
-	} else if (st->last_rc_key) {
-		rc_keyup(d->rc_dev);
-		st->last_rc_key = 0;
-	}
-
-	return 0;
-}
-
-
-/* Callbacks for DVB USB */
-static int ttusb2_identify_state (struct usb_device *udev, struct
-		dvb_usb_device_properties *props, struct dvb_usb_device_description **desc,
-		int *cold)
-{
-	*cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
-	return 0;
-}
-
-static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	u8 b = onoff;
-	ttusb2_msg(d, CMD_POWER, &b, 0, NULL, 0);
-	return ttusb2_msg(d, CMD_POWER, &b, 1, NULL, 0);
-}
-
-
-static struct tda10086_config tda10086_config = {
-	.demod_address = 0x0e,
-	.invert = 0,
-	.diseqc_tone = 1,
-	.xtal_freq = TDA10086_XTAL_16M,
-};
-
-static struct tda10023_config tda10023_config = {
-	.demod_address = 0x0c,
-	.invert = 0,
-	.xtal = 16000000,
-	.pll_m = 11,
-	.pll_p = 3,
-	.pll_n = 1,
-	.deltaf = 0xa511,
-};
-
-static struct tda10048_config tda10048_config = {
-	.demod_address    = 0x10 >> 1,
-	.output_mode      = TDA10048_PARALLEL_OUTPUT,
-	.inversion        = TDA10048_INVERSION_ON,
-	.dtv6_if_freq_khz = TDA10048_IF_4000,
-	.dtv7_if_freq_khz = TDA10048_IF_4500,
-	.dtv8_if_freq_khz = TDA10048_IF_5000,
-	.clk_freq_khz     = TDA10048_CLK_16000,
-	.no_firmware      = 1,
-	.set_pll          = true ,
-	.pll_m            = 5,
-	.pll_n            = 3,
-	.pll_p            = 0,
-};
-
-static struct tda827x_config tda827x_config = {
-	.config = 0,
-};
-
-static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
-{
-	if (usb_set_interface(adap->dev->udev,0,3) < 0)
-		err("set interface to alts=3 failed");
-
-	if ((adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) {
-		deb_info("TDA10086 attach failed\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static int ttusb2_ct3650_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-
-	return adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, enable);
-}
-
-static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap)
-{
-	if (usb_set_interface(adap->dev->udev, 0, 3) < 0)
-		err("set interface to alts=3 failed");
-
-	if (adap->fe_adap[0].fe == NULL) {
-		/* FE 0 DVB-C */
-		adap->fe_adap[0].fe = dvb_attach(tda10023_attach,
-			&tda10023_config, &adap->dev->i2c_adap, 0x48);
-
-		if (adap->fe_adap[0].fe == NULL) {
-			deb_info("TDA10023 attach failed\n");
-			return -ENODEV;
-		}
-		tt3650_ci_init(adap);
-	} else {
-		adap->fe_adap[1].fe = dvb_attach(tda10048_attach,
-			&tda10048_config, &adap->dev->i2c_adap);
-
-		if (adap->fe_adap[1].fe == NULL) {
-			deb_info("TDA10048 attach failed\n");
-			return -ENODEV;
-		}
-
-		/* tuner is behind TDA10023 I2C-gate */
-		adap->fe_adap[1].fe->ops.i2c_gate_ctrl = ttusb2_ct3650_i2c_gate_ctrl;
-
-	}
-
-	return 0;
-}
-
-static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap)
-{
-	struct dvb_frontend *fe;
-
-	/* MFE: select correct FE to attach tuner since that's called twice */
-	if (adap->fe_adap[1].fe == NULL)
-		fe = adap->fe_adap[0].fe;
-	else
-		fe = adap->fe_adap[1].fe;
-
-	/* attach tuner */
-	if (dvb_attach(tda827x_attach, fe, 0x61, &adap->dev->i2c_adap, &tda827x_config) == NULL) {
-		printk(KERN_ERR "%s: No tda827x found!\n", __func__);
-		return -ENODEV;
-	}
-	return 0;
-}
-
-static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap)
-{
-	if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) {
-		deb_info("TDA8263 attach failed\n");
-		return -ENODEV;
-	}
-
-	if (dvb_attach(lnbp21_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, 0, 0) == NULL) {
-		deb_info("LNBP21 attach failed\n");
-		return -ENODEV;
-	}
-	return 0;
-}
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties ttusb2_properties;
-static struct dvb_usb_device_properties ttusb2_properties_s2400;
-static struct dvb_usb_device_properties ttusb2_properties_ct3650;
-
-static void ttusb2_usb_disconnect(struct usb_interface *intf)
-{
-	struct dvb_usb_device *d = usb_get_intfdata(intf);
-
-	tt3650_ci_uninit(d);
-	dvb_usb_device_exit(intf);
-}
-
-static int ttusb2_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	if (0 == dvb_usb_device_init(intf, &ttusb2_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400,
-				     THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650,
-				     THIS_MODULE, NULL, adapter_nr))
-		return 0;
-	return -ENODEV;
-}
-
-static struct usb_device_id ttusb2_table [] = {
-	{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) },
-	{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) },
-	{ USB_DEVICE(USB_VID_TECHNOTREND,
-		USB_PID_TECHNOTREND_CONNECT_S2400) },
-	{ USB_DEVICE(USB_VID_TECHNOTREND,
-		USB_PID_TECHNOTREND_CONNECT_CT3650) },
-	{}		/* Terminating entry */
-};
-MODULE_DEVICE_TABLE (usb, ttusb2_table);
-
-static struct dvb_usb_device_properties ttusb2_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware = "dvb-usb-pctv-400e-01.fw",
-
-	.size_of_priv = sizeof(struct ttusb2_state),
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = NULL, // ttusb2_streaming_ctrl,
-
-			.frontend_attach  = ttusb2_frontend_tda10086_attach,
-			.tuner_attach     = ttusb2_tuner_tda826x_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_ISOC,
-				.count = 5,
-				.endpoint = 0x02,
-				.u = {
-					.isoc = {
-						.framesperurb = 4,
-						.framesize = 940,
-						.interval = 1,
-					}
-				}
-			}
-		}},
-		}
-	},
-
-	.power_ctrl       = ttusb2_power_ctrl,
-	.identify_state   = ttusb2_identify_state,
-
-	.i2c_algo         = &ttusb2_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 2,
-	.devices = {
-		{   "Pinnacle 400e DVB-S USB2.0",
-			{ &ttusb2_table[0], NULL },
-			{ NULL },
-		},
-		{   "Pinnacle 450e DVB-S USB2.0",
-			{ &ttusb2_table[1], NULL },
-			{ NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware = "dvb-usb-tt-s2400-01.fw",
-
-	.size_of_priv = sizeof(struct ttusb2_state),
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = NULL,
-
-			.frontend_attach  = ttusb2_frontend_tda10086_attach,
-			.tuner_attach     = ttusb2_tuner_tda826x_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_ISOC,
-				.count = 5,
-				.endpoint = 0x02,
-				.u = {
-					.isoc = {
-						.framesperurb = 4,
-						.framesize = 940,
-						.interval = 1,
-					}
-				}
-			}
-		}},
-		}
-	},
-
-	.power_ctrl       = ttusb2_power_ctrl,
-	.identify_state   = ttusb2_identify_state,
-
-	.i2c_algo         = &ttusb2_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 1,
-	.devices = {
-		{   "Technotrend TT-connect S-2400",
-			{ &ttusb2_table[2], NULL },
-			{ NULL },
-		},
-	}
-};
-
-static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = CYPRESS_FX2,
-
-	.size_of_priv = sizeof(struct ttusb2_state),
-
-	.rc.core = {
-		.rc_interval      = 150, /* Less than IR_KEYPRESS_TIMEOUT */
-		.rc_codes         = RC_MAP_TT_1500,
-		.rc_query         = tt3650_rc_query,
-		.allowed_protos   = RC_TYPE_UNKNOWN,
-	},
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 2,
-		.fe = {{
-			.streaming_ctrl   = NULL,
-
-			.frontend_attach  = ttusb2_frontend_tda10023_attach,
-			.tuner_attach = ttusb2_tuner_tda827x_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_ISOC,
-				.count = 5,
-				.endpoint = 0x02,
-				.u = {
-					.isoc = {
-						.framesperurb = 4,
-						.framesize = 940,
-						.interval = 1,
-					}
-				}
-			}
-		}, {
-			.streaming_ctrl   = NULL,
-
-			.frontend_attach  = ttusb2_frontend_tda10023_attach,
-			.tuner_attach = ttusb2_tuner_tda827x_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_ISOC,
-				.count = 5,
-				.endpoint = 0x02,
-				.u = {
-					.isoc = {
-						.framesperurb = 4,
-						.framesize = 940,
-						.interval = 1,
-					}
-				}
-			}
-		}},
-		},
-	},
-
-	.power_ctrl       = ttusb2_power_ctrl,
-	.identify_state   = ttusb2_identify_state,
-
-	.i2c_algo         = &ttusb2_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 1,
-	.devices = {
-		{   "Technotrend TT-connect CT-3650",
-			.warm_ids = { &ttusb2_table[3], NULL },
-		},
-	}
-};
-
-static struct usb_driver ttusb2_driver = {
-	.name		= "dvb_usb_ttusb2",
-	.probe		= ttusb2_probe,
-	.disconnect	= ttusb2_usb_disconnect,
-	.id_table	= ttusb2_table,
-};
-
-module_usb_driver(ttusb2_driver);
-
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.h b/drivers/media/dvb/dvb-usb/ttusb2.h
deleted file mode 100644
index 52a63af..0000000
--- a/drivers/media/dvb/dvb-usb/ttusb2.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones
- * (e.g. Pinnacle 400e DVB-S USB2.0).
- *
- * Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
- * Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net>
- * Copyright (C) 2005-6 Patrick Boettcher <pb@linuxtv.de>
- *
- *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License as published by the Free
- *	Software Foundation, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#ifndef _DVB_USB_TTUSB2_H_
-#define _DVB_USB_TTUSB2_H_
-
-/* TTUSB protocol
- *
- * always to messages (out/in)
- * out message:
- * 0xaa <id> <cmdbyte> <datalen> <data...>
- *
- * in message (complete block is always 0x40 bytes long)
- * 0x55 <id> <cmdbyte> <datalen> <data...>
- *
- * id is incremented for each transaction
- */
-
-#define CMD_DSP_DOWNLOAD    0x13
-/* out data: <byte>[28]
- * last block must be empty */
-
-#define CMD_DSP_BOOT        0x14
-/* out data: nothing */
-
-#define CMD_POWER           0x15
-/* out data: <on=1/off=0> */
-
-#define CMD_LNB             0x16
-/* out data: <power=1> <18V=0,13V=1> <tone> <??=1> <??=1> */
-
-#define CMD_GET_VERSION     0x17
-/* in  data: <version_byte>[5] */
-
-#define CMD_DISEQC          0x18
-/* out data: <master=0xff/burst=??> <cmdlen> <cmdbytes>[cmdlen] */
-
-#define CMD_PID_ENABLE      0x22
-/* out data: <index> <type: ts=1/sec=2> <pid msb> <pid lsb> */
-
-#define CMD_PID_DISABLE     0x23
-/* out data: <index> */
-
-#define CMD_FILTER_ENABLE   0x24
-/* out data: <index> <pid_idx> <filter>[12] <mask>[12] */
-
-#define CMD_FILTER_DISABLE  0x25
-/* out data: <index> */
-
-#define CMD_GET_DSP_VERSION 0x26
-/* in  data: <version_byte>[28] */
-
-#define CMD_I2C_XFER        0x31
-/* out data: <addr << 1> <sndlen> <rcvlen> <data>[sndlen]
- * in  data: <addr << 1> <sndlen> <rcvlen> <data>[rcvlen] */
-
-#define CMD_I2C_BITRATE     0x32
-/* out data: <default=0> */
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
deleted file mode 100644
index 9b04229..0000000
--- a/drivers/media/dvb/dvb-usb/umt-010.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/* DVB USB framework compliant Linux driver for the HanfTek UMT-010 USB2.0
- * DVB-T receiver.
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License as published by the Free
- *	Software Foundation, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "dibusb.h"
-
-#include "mt352.h"
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static int umt_mt352_demod_init(struct dvb_frontend *fe)
-{
-	static u8 mt352_clock_config[] = { 0x89, 0xb8, 0x2d };
-	static u8 mt352_reset[] = { 0x50, 0x80 };
-	static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 };
-	static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
-	static u8 mt352_agc_cfg[] = { 0x67, 0x10, 0xa0 };
-
-	static u8 mt352_sec_agc_cfg1[] = { 0x6a, 0xff };
-	static u8 mt352_sec_agc_cfg2[] = { 0x6d, 0xff };
-	static u8 mt352_sec_agc_cfg3[] = { 0x70, 0x40 };
-	static u8 mt352_sec_agc_cfg4[] = { 0x7b, 0x03 };
-	static u8 mt352_sec_agc_cfg5[] = { 0x7d, 0x0f };
-
-	static u8 mt352_acq_ctl[] = { 0x53, 0x50 };
-	static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x06 };
-
-	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
-	udelay(2000);
-	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
-	mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio));
-
-	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
-
-	mt352_write(fe, mt352_sec_agc_cfg1, sizeof(mt352_sec_agc_cfg1));
-	mt352_write(fe, mt352_sec_agc_cfg2, sizeof(mt352_sec_agc_cfg2));
-	mt352_write(fe, mt352_sec_agc_cfg3, sizeof(mt352_sec_agc_cfg3));
-	mt352_write(fe, mt352_sec_agc_cfg4, sizeof(mt352_sec_agc_cfg4));
-	mt352_write(fe, mt352_sec_agc_cfg5, sizeof(mt352_sec_agc_cfg5));
-
-	mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl));
-	mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1));
-
-	return 0;
-}
-
-static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	struct mt352_config umt_config;
-
-	memset(&umt_config,0,sizeof(struct mt352_config));
-	umt_config.demod_init = umt_mt352_demod_init;
-	umt_config.demod_address = 0xf;
-
-	adap->fe_adap[0].fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap);
-
-	return 0;
-}
-
-static int umt_tuner_attach (struct dvb_usb_adapter *adap)
-{
-	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_TUA6034);
-	return 0;
-}
-
-/* USB Driver stuff */
-static struct dvb_usb_device_properties umt_properties;
-
-static int umt_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	if (0 == dvb_usb_device_init(intf, &umt_properties,
-				     THIS_MODULE, NULL, adapter_nr))
-		return 0;
-	return -EINVAL;
-}
-
-/* do not change the order of the ID table */
-static struct usb_device_id umt_table [] = {
-/* 00 */	{ USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) },
-/* 01 */	{ USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) },
-			{ }		/* Terminating entry */
-};
-MODULE_DEVICE_TABLE (usb, umt_table);
-
-static struct dvb_usb_device_properties umt_properties = {
-	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware = "dvb-usb-umt-010-02.fw",
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.streaming_ctrl   = dibusb2_0_streaming_ctrl,
-			.frontend_attach  = umt_mt352_frontend_attach,
-			.tuner_attach     = umt_tuner_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = MAX_NO_URBS_FOR_DATA_STREAM,
-				.endpoint = 0x06,
-				.u = {
-					.bulk = {
-						.buffersize = 512,
-					}
-				}
-			},
-		}},
-			.size_of_priv     = sizeof(struct dibusb_state),
-		}
-	},
-	.power_ctrl       = dibusb_power_ctrl,
-
-	.i2c_algo         = &dibusb_i2c_algo,
-
-	.generic_bulk_ctrl_endpoint = 0x01,
-
-	.num_device_descs = 1,
-	.devices = {
-		{	"Hanftek UMT-010 DVB-T USB2.0",
-			{ &umt_table[0], NULL },
-			{ &umt_table[1], NULL },
-		},
-	}
-};
-
-static struct usb_driver umt_driver = {
-	.name		= "dvb_usb_umt_010",
-	.probe		= umt_probe,
-	.disconnect = dvb_usb_device_exit,
-	.id_table	= umt_table,
-};
-
-module_usb_driver(umt_driver);
-
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("Driver for HanfTek UMT 010 USB2.0 DVB-T device");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/usb-urb.c b/drivers/media/dvb/dvb-usb/usb-urb.c
deleted file mode 100644
index d62ee0f..0000000
--- a/drivers/media/dvb/dvb-usb/usb-urb.c
+++ /dev/null
@@ -1,254 +0,0 @@
-/* usb-urb.c is part of the DVB USB library.
- *
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
- * see dvb-usb-init.c for copyright information.
- *
- * This file keeps functions for initializing and handling the
- * BULK and ISOC USB data transfers in a generic way.
- * Can be used for DVB-only and also, that's the plan, for
- * Hybrid USB devices (analog and DVB).
- */
-#include "dvb-usb-common.h"
-
-/* URB stuff for streaming */
-static void usb_urb_complete(struct urb *urb)
-{
-	struct usb_data_stream *stream = urb->context;
-	int ptype = usb_pipetype(urb->pipe);
-	int i;
-	u8 *b;
-
-	deb_uxfer("'%s' urb completed. status: %d, length: %d/%d, pack_num: %d, errors: %d\n",
-		ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
-		urb->status,urb->actual_length,urb->transfer_buffer_length,
-		urb->number_of_packets,urb->error_count);
-
-	switch (urb->status) {
-		case 0:         /* success */
-		case -ETIMEDOUT:    /* NAK */
-			break;
-		case -ECONNRESET:   /* kill */
-		case -ENOENT:
-		case -ESHUTDOWN:
-			return;
-		default:        /* error */
-			deb_ts("urb completition error %d.\n", urb->status);
-			break;
-	}
-
-	b = (u8 *) urb->transfer_buffer;
-	switch (ptype) {
-		case PIPE_ISOCHRONOUS:
-			for (i = 0; i < urb->number_of_packets; i++) {
-
-				if (urb->iso_frame_desc[i].status != 0)
-					deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status);
-				else if (urb->iso_frame_desc[i].actual_length > 0)
-					stream->complete(stream, b + urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length);
-
-				urb->iso_frame_desc[i].status = 0;
-				urb->iso_frame_desc[i].actual_length = 0;
-			}
-			debug_dump(b,20,deb_uxfer);
-			break;
-		case PIPE_BULK:
-			if (urb->actual_length > 0)
-				stream->complete(stream, b, urb->actual_length);
-			break;
-		default:
-			err("unknown endpoint type in completition handler.");
-			return;
-	}
-	usb_submit_urb(urb,GFP_ATOMIC);
-}
-
-int usb_urb_kill(struct usb_data_stream *stream)
-{
-	int i;
-	for (i = 0; i < stream->urbs_submitted; i++) {
-		deb_ts("killing URB no. %d.\n",i);
-
-		/* stop the URB */
-		usb_kill_urb(stream->urb_list[i]);
-	}
-	stream->urbs_submitted = 0;
-	return 0;
-}
-
-int usb_urb_submit(struct usb_data_stream *stream)
-{
-	int i,ret;
-	for (i = 0; i < stream->urbs_initialized; i++) {
-		deb_ts("submitting URB no. %d\n",i);
-		if ((ret = usb_submit_urb(stream->urb_list[i],GFP_ATOMIC))) {
-			err("could not submit URB no. %d - get them all back",i);
-			usb_urb_kill(stream);
-			return ret;
-		}
-		stream->urbs_submitted++;
-	}
-	return 0;
-}
-
-static int usb_free_stream_buffers(struct usb_data_stream *stream)
-{
-	if (stream->state & USB_STATE_URB_BUF) {
-		while (stream->buf_num) {
-			stream->buf_num--;
-			deb_mem("freeing buffer %d\n",stream->buf_num);
-			usb_free_coherent(stream->udev, stream->buf_size,
-					  stream->buf_list[stream->buf_num],
-					  stream->dma_addr[stream->buf_num]);
-		}
-	}
-
-	stream->state &= ~USB_STATE_URB_BUF;
-
-	return 0;
-}
-
-static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, unsigned long size)
-{
-	stream->buf_num = 0;
-	stream->buf_size = size;
-
-	deb_mem("all in all I will use %lu bytes for streaming\n",num*size);
-
-	for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
-		deb_mem("allocating buffer %d\n",stream->buf_num);
-		if (( stream->buf_list[stream->buf_num] =
-					usb_alloc_coherent(stream->udev, size, GFP_ATOMIC,
-					&stream->dma_addr[stream->buf_num]) ) == NULL) {
-			deb_mem("not enough memory for urb-buffer allocation.\n");
-			usb_free_stream_buffers(stream);
-			return -ENOMEM;
-		}
-		deb_mem("buffer %d: %p (dma: %Lu)\n",
-			stream->buf_num,
-stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]);
-		memset(stream->buf_list[stream->buf_num],0,size);
-		stream->state |= USB_STATE_URB_BUF;
-	}
-	deb_mem("allocation successful\n");
-
-	return 0;
-}
-
-static int usb_bulk_urb_init(struct usb_data_stream *stream)
-{
-	int i, j;
-
-	if ((i = usb_allocate_stream_buffers(stream,stream->props.count,
-					stream->props.u.bulk.buffersize)) < 0)
-		return i;
-
-	/* allocate the URBs */
-	for (i = 0; i < stream->props.count; i++) {
-		stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
-		if (!stream->urb_list[i]) {
-			deb_mem("not enough memory for urb_alloc_urb!.\n");
-			for (j = 0; j < i; j++)
-				usb_free_urb(stream->urb_list[j]);
-			return -ENOMEM;
-		}
-		usb_fill_bulk_urb( stream->urb_list[i], stream->udev,
-				usb_rcvbulkpipe(stream->udev,stream->props.endpoint),
-				stream->buf_list[i],
-				stream->props.u.bulk.buffersize,
-				usb_urb_complete, stream);
-
-		stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
-		stream->urb_list[i]->transfer_dma = stream->dma_addr[i];
-		stream->urbs_initialized++;
-	}
-	return 0;
-}
-
-static int usb_isoc_urb_init(struct usb_data_stream *stream)
-{
-	int i,j;
-
-	if ((i = usb_allocate_stream_buffers(stream,stream->props.count,
-					stream->props.u.isoc.framesize*stream->props.u.isoc.framesperurb)) < 0)
-		return i;
-
-	/* allocate the URBs */
-	for (i = 0; i < stream->props.count; i++) {
-		struct urb *urb;
-		int frame_offset = 0;
-
-		stream->urb_list[i] = usb_alloc_urb(stream->props.u.isoc.framesperurb, GFP_ATOMIC);
-		if (!stream->urb_list[i]) {
-			deb_mem("not enough memory for urb_alloc_urb!\n");
-			for (j = 0; j < i; j++)
-				usb_free_urb(stream->urb_list[j]);
-			return -ENOMEM;
-		}
-
-		urb = stream->urb_list[i];
-
-		urb->dev = stream->udev;
-		urb->context = stream;
-		urb->complete = usb_urb_complete;
-		urb->pipe = usb_rcvisocpipe(stream->udev,stream->props.endpoint);
-		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
-		urb->interval = stream->props.u.isoc.interval;
-		urb->number_of_packets = stream->props.u.isoc.framesperurb;
-		urb->transfer_buffer_length = stream->buf_size;
-		urb->transfer_buffer = stream->buf_list[i];
-		urb->transfer_dma = stream->dma_addr[i];
-
-		for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
-			urb->iso_frame_desc[j].offset = frame_offset;
-			urb->iso_frame_desc[j].length = stream->props.u.isoc.framesize;
-			frame_offset += stream->props.u.isoc.framesize;
-		}
-
-		stream->urbs_initialized++;
-	}
-	return 0;
-}
-
-int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props)
-{
-	if (stream == NULL || props == NULL)
-		return -EINVAL;
-
-	memcpy(&stream->props, props, sizeof(*props));
-
-	usb_clear_halt(stream->udev,usb_rcvbulkpipe(stream->udev,stream->props.endpoint));
-
-	if (stream->complete == NULL) {
-		err("there is no data callback - this doesn't make sense.");
-		return -EINVAL;
-	}
-
-	switch (stream->props.type) {
-		case USB_BULK:
-			return usb_bulk_urb_init(stream);
-		case USB_ISOC:
-			return usb_isoc_urb_init(stream);
-		default:
-			err("unknown URB-type for data transfer.");
-			return -EINVAL;
-	}
-}
-
-int usb_urb_exit(struct usb_data_stream *stream)
-{
-	int i;
-
-	usb_urb_kill(stream);
-
-	for (i = 0; i < stream->urbs_initialized; i++) {
-		if (stream->urb_list[i] != NULL) {
-			deb_mem("freeing URB no. %d.\n",i);
-			/* free the URBs */
-			usb_free_urb(stream->urb_list[i]);
-		}
-	}
-	stream->urbs_initialized = 0;
-
-	usb_free_stream_buffers(stream);
-	return 0;
-}
diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c
deleted file mode 100644
index 5eab468..0000000
--- a/drivers/media/dvb/dvb-usb/vp702x-fe.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/* DVB frontend part of the Linux driver for the TwinhanDTV StarBox USB2.0
- * DVB-S receiver.
- *
- * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
- *                    Metzler Brothers Systementwicklung GbR
- *
- * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
- *
- * Thanks to Twinhan who kindly provided hardware and information.
- *
- * This file can be removed soon, after the DST-driver is rewritten to provice
- * the frontend-controlling separately.
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- *
- */
-#include "vp702x.h"
-
-struct vp702x_fe_state {
-	struct dvb_frontend fe;
-	struct dvb_usb_device *d;
-
-	struct dvb_frontend_ops ops;
-
-	fe_sec_voltage_t voltage;
-	fe_sec_tone_mode_t tone_mode;
-
-	u8 lnb_buf[8];
-
-	u8 lock;
-	u8 sig;
-	u8 snr;
-
-	unsigned long next_status_check;
-	unsigned long status_check_interval;
-};
-
-static int vp702x_fe_refresh_state(struct vp702x_fe_state *st)
-{
-	struct vp702x_device_state *dst = st->d->priv;
-	u8 *buf;
-
-	if (time_after(jiffies, st->next_status_check)) {
-		mutex_lock(&dst->buf_mutex);
-		buf = dst->buf;
-
-		vp702x_usb_in_op(st->d, READ_STATUS, 0, 0, buf, 10);
-		st->lock = buf[4];
-
-		vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x11, 0, buf, 1);
-		st->snr = buf[0];
-
-		vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x15, 0, buf, 1);
-		st->sig = buf[0];
-
-		mutex_unlock(&dst->buf_mutex);
-		st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
-	}
-	return 0;
-}
-
-static u8 vp702x_chksum(u8 *buf,int f, int count)
-{
-	u8 s = 0;
-	int i;
-	for (i = f; i < f+count; i++)
-		s += buf[i];
-	return ~s+1;
-}
-
-static int vp702x_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
-{
-	struct vp702x_fe_state *st = fe->demodulator_priv;
-	vp702x_fe_refresh_state(st);
-	deb_fe("%s\n",__func__);
-
-	if (st->lock == 0)
-		*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
-	else
-		*status = 0;
-
-	if (*status & FE_HAS_LOCK)
-		st->status_check_interval = 1000;
-	else
-		st->status_check_interval = 250;
-	return 0;
-}
-
-/* not supported by this Frontend */
-static int vp702x_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
-{
-	struct vp702x_fe_state *st = fe->demodulator_priv;
-	vp702x_fe_refresh_state(st);
-	*ber = 0;
-	return 0;
-}
-
-/* not supported by this Frontend */
-static int vp702x_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
-{
-	struct vp702x_fe_state *st = fe->demodulator_priv;
-	vp702x_fe_refresh_state(st);
-	*unc = 0;
-	return 0;
-}
-
-static int vp702x_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
-{
-	struct vp702x_fe_state *st = fe->demodulator_priv;
-	vp702x_fe_refresh_state(st);
-
-	*strength = (st->sig << 8) | st->sig;
-	return 0;
-}
-
-static int vp702x_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
-{
-	u8 _snr;
-	struct vp702x_fe_state *st = fe->demodulator_priv;
-	vp702x_fe_refresh_state(st);
-
-	_snr = (st->snr & 0x1f) * 0xff / 0x1f;
-	*snr = (_snr << 8) | _snr;
-	return 0;
-}
-
-static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
-{
-	deb_fe("%s\n",__func__);
-	tune->min_delay_ms = 2000;
-	return 0;
-}
-
-static int vp702x_fe_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
-	struct vp702x_fe_state *st = fe->demodulator_priv;
-	struct vp702x_device_state *dst = st->d->priv;
-	u32 freq = fep->frequency/1000;
-	/*CalFrequency*/
-/*	u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */
-	u64 sr;
-	u8 *cmd;
-
-	mutex_lock(&dst->buf_mutex);
-
-	cmd = dst->buf;
-	memset(cmd, 0, 10);
-
-	cmd[0] = (freq >> 8) & 0x7f;
-	cmd[1] =  freq       & 0xff;
-	cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */
-
-	sr = (u64) (fep->symbol_rate/1000) << 20;
-	do_div(sr,88000);
-	cmd[3] = (sr >> 12) & 0xff;
-	cmd[4] = (sr >> 4)  & 0xff;
-	cmd[5] = (sr << 4)  & 0xf0;
-
-	deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n",
-			fep->frequency, freq, freq, fep->symbol_rate,
-			(unsigned long) sr, (unsigned long) sr);
-
-/*	if (fep->inversion == INVERSION_ON)
-		cmd[6] |= 0x80; */
-
-	if (st->voltage == SEC_VOLTAGE_18)
-		cmd[6] |= 0x40;
-
-/*	if (fep->symbol_rate > 8000000)
-		cmd[6] |= 0x20;
-
-	if (fep->frequency < 1531000)
-		cmd[6] |= 0x04;
-
-	if (st->tone_mode == SEC_TONE_ON)
-		cmd[6] |= 0x01;*/
-
-	cmd[7] = vp702x_chksum(cmd,0,7);
-
-	st->status_check_interval = 250;
-	st->next_status_check = jiffies;
-
-	vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100);
-
-	if (cmd[2] == 0 && cmd[3] == 0)
-		deb_fe("tuning failed.\n");
-	else
-		deb_fe("tuning succeeded.\n");
-
-	mutex_unlock(&dst->buf_mutex);
-
-	return 0;
-}
-
-static int vp702x_fe_init(struct dvb_frontend *fe)
-{
-	struct vp702x_fe_state *st = fe->demodulator_priv;
-	deb_fe("%s\n",__func__);
-	vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0);
-	return 0;
-}
-
-static int vp702x_fe_sleep(struct dvb_frontend *fe)
-{
-	deb_fe("%s\n",__func__);
-	return 0;
-}
-
-static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
-				    struct dvb_diseqc_master_cmd *m)
-{
-	u8 *cmd;
-	struct vp702x_fe_state *st = fe->demodulator_priv;
-	struct vp702x_device_state *dst = st->d->priv;
-
-	deb_fe("%s\n",__func__);
-
-	if (m->msg_len > 4)
-		return -EINVAL;
-
-	mutex_lock(&dst->buf_mutex);
-
-	cmd = dst->buf;
-	cmd[1] = SET_DISEQC_CMD;
-	cmd[2] = m->msg_len;
-	memcpy(&cmd[3], m->msg, m->msg_len);
-	cmd[7] = vp702x_chksum(cmd, 0, 7);
-
-	vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100);
-
-	if (cmd[2] == 0 && cmd[3] == 0)
-		deb_fe("diseqc cmd failed.\n");
-	else
-		deb_fe("diseqc cmd succeeded.\n");
-
-	mutex_unlock(&dst->buf_mutex);
-
-	return 0;
-}
-
-static int vp702x_fe_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
-{
-	deb_fe("%s\n",__func__);
-	return 0;
-}
-
-static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
-	struct vp702x_fe_state *st = fe->demodulator_priv;
-	struct vp702x_device_state *dst = st->d->priv;
-	u8 *buf;
-
-	deb_fe("%s\n",__func__);
-
-	st->tone_mode = tone;
-
-	if (tone == SEC_TONE_ON)
-		st->lnb_buf[2] = 0x02;
-	else
-		st->lnb_buf[2] = 0x00;
-
-	st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7);
-
-	mutex_lock(&dst->buf_mutex);
-
-	buf = dst->buf;
-	memcpy(buf, st->lnb_buf, 8);
-
-	vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100);
-	if (buf[2] == 0 && buf[3] == 0)
-		deb_fe("set_tone cmd failed.\n");
-	else
-		deb_fe("set_tone cmd succeeded.\n");
-
-	mutex_unlock(&dst->buf_mutex);
-
-	return 0;
-}
-
-static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t
-		voltage)
-{
-	struct vp702x_fe_state *st = fe->demodulator_priv;
-	struct vp702x_device_state *dst = st->d->priv;
-	u8 *buf;
-	deb_fe("%s\n",__func__);
-
-	st->voltage = voltage;
-
-	if (voltage != SEC_VOLTAGE_OFF)
-		st->lnb_buf[4] = 0x01;
-	else
-		st->lnb_buf[4] = 0x00;
-
-	st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7);
-
-	mutex_lock(&dst->buf_mutex);
-
-	buf = dst->buf;
-	memcpy(buf, st->lnb_buf, 8);
-
-	vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100);
-	if (buf[2] == 0 && buf[3] == 0)
-		deb_fe("set_voltage cmd failed.\n");
-	else
-		deb_fe("set_voltage cmd succeeded.\n");
-
-	mutex_unlock(&dst->buf_mutex);
-	return 0;
-}
-
-static void vp702x_fe_release(struct dvb_frontend* fe)
-{
-	struct vp702x_fe_state *st = fe->demodulator_priv;
-	kfree(st);
-}
-
-static struct dvb_frontend_ops vp702x_fe_ops;
-
-struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d)
-{
-	struct vp702x_fe_state *s = kzalloc(sizeof(struct vp702x_fe_state), GFP_KERNEL);
-	if (s == NULL)
-		goto error;
-
-	s->d = d;
-
-	memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops));
-	s->fe.demodulator_priv = s;
-
-	s->lnb_buf[1] = SET_LNB_POWER;
-	s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */
-
-	return &s->fe;
-error:
-	return NULL;
-}
-
-
-static struct dvb_frontend_ops vp702x_fe_ops = {
-	.delsys = { SYS_DVBS },
-	.info = {
-		.name           = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S",
-		.frequency_min       = 950000,
-		.frequency_max       = 2150000,
-		.frequency_stepsize  = 1000,   /* kHz for QPSK frontends */
-		.frequency_tolerance = 0,
-		.symbol_rate_min     = 1000000,
-		.symbol_rate_max     = 45000000,
-		.symbol_rate_tolerance = 500,  /* ppm */
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
-		FE_CAN_QPSK |
-		FE_CAN_FEC_AUTO
-	},
-	.release = vp702x_fe_release,
-
-	.init  = vp702x_fe_init,
-	.sleep = vp702x_fe_sleep,
-
-	.set_frontend = vp702x_fe_set_frontend,
-	.get_tune_settings = vp702x_fe_get_tune_settings,
-
-	.read_status = vp702x_fe_read_status,
-	.read_ber = vp702x_fe_read_ber,
-	.read_signal_strength = vp702x_fe_read_signal_strength,
-	.read_snr = vp702x_fe_read_snr,
-	.read_ucblocks = vp702x_fe_read_unc_blocks,
-
-	.diseqc_send_master_cmd = vp702x_fe_send_diseqc_msg,
-	.diseqc_send_burst = vp702x_fe_send_diseqc_burst,
-	.set_tone = vp702x_fe_set_tone,
-	.set_voltage = vp702x_fe_set_voltage,
-};
diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c
deleted file mode 100644
index 07c673a..0000000
--- a/drivers/media/dvb/dvb-usb/vp702x.c
+++ /dev/null
@@ -1,444 +0,0 @@
-/* DVB USB compliant Linux driver for the TwinhanDTV StarBox USB2.0 DVB-S
- * receiver.
- *
- * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
- *                    Metzler Brothers Systementwicklung GbR
- *
- * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
- *
- * Thanks to Twinhan who kindly provided hardware and information.
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "vp702x.h"
-#include <linux/mutex.h>
-
-/* debug */
-int dvb_usb_vp702x_debug;
-module_param_named(debug,dvb_usb_vp702x_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-struct vp702x_adapter_state {
-	int pid_filter_count;
-	int pid_filter_can_bypass;
-	u8  pid_filter_state;
-};
-
-static int vp702x_usb_in_op_unlocked(struct dvb_usb_device *d, u8 req,
-				     u16 value, u16 index, u8 *b, int blen)
-{
-	int ret;
-
-	ret = usb_control_msg(d->udev,
-		usb_rcvctrlpipe(d->udev, 0),
-		req,
-		USB_TYPE_VENDOR | USB_DIR_IN,
-		value, index, b, blen,
-		2000);
-
-	if (ret < 0) {
-		warn("usb in operation failed. (%d)", ret);
-		ret = -EIO;
-	} else
-		ret = 0;
-
-
-	deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
-	debug_dump(b,blen,deb_xfer);
-
-	return ret;
-}
-
-int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value,
-			    u16 index, u8 *b, int blen)
-{
-	int ret;
-
-	mutex_lock(&d->usb_mutex);
-	ret = vp702x_usb_in_op_unlocked(d, req, value, index, b, blen);
-	mutex_unlock(&d->usb_mutex);
-
-	return ret;
-}
-
-int vp702x_usb_out_op_unlocked(struct dvb_usb_device *d, u8 req, u16 value,
-				      u16 index, u8 *b, int blen)
-{
-	int ret;
-	deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
-	debug_dump(b,blen,deb_xfer);
-
-	if ((ret = usb_control_msg(d->udev,
-			usb_sndctrlpipe(d->udev,0),
-			req,
-			USB_TYPE_VENDOR | USB_DIR_OUT,
-			value,index,b,blen,
-			2000)) != blen) {
-		warn("usb out operation failed. (%d)",ret);
-		return -EIO;
-	} else
-		return 0;
-}
-
-int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
-			     u16 index, u8 *b, int blen)
-{
-	int ret;
-
-	mutex_lock(&d->usb_mutex);
-	ret = vp702x_usb_out_op_unlocked(d, req, value, index, b, blen);
-	mutex_unlock(&d->usb_mutex);
-
-	return ret;
-}
-
-int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec)
-{
-	int ret;
-
-	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
-		return ret;
-
-	ret = vp702x_usb_out_op_unlocked(d, REQUEST_OUT, 0, 0, o, olen);
-	msleep(msec);
-	ret = vp702x_usb_in_op_unlocked(d, REQUEST_IN, 0, 0, i, ilen);
-
-	mutex_unlock(&d->usb_mutex);
-	return ret;
-}
-
-static int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o,
-				int olen, u8 *i, int ilen, int msec)
-{
-	struct vp702x_device_state *st = d->priv;
-	int ret = 0;
-	u8 *buf;
-	int buflen = max(olen + 2, ilen + 1);
-
-	ret = mutex_lock_interruptible(&st->buf_mutex);
-	if (ret < 0)
-		return ret;
-
-	if (buflen > st->buf_len) {
-		buf = kmalloc(buflen, GFP_KERNEL);
-		if (!buf) {
-			mutex_unlock(&st->buf_mutex);
-			return -ENOMEM;
-		}
-		info("successfully reallocated a bigger buffer");
-		kfree(st->buf);
-		st->buf = buf;
-		st->buf_len = buflen;
-	} else {
-		buf = st->buf;
-	}
-
-	buf[0] = 0x00;
-	buf[1] = cmd;
-	memcpy(&buf[2], o, olen);
-
-	ret = vp702x_usb_inout_op(d, buf, olen+2, buf, ilen+1, msec);
-
-	if (ret == 0)
-		memcpy(i, &buf[1], ilen);
-	mutex_unlock(&st->buf_mutex);
-
-	return ret;
-}
-
-static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass)
-{
-	int ret;
-	struct vp702x_device_state *st = adap->dev->priv;
-	u8 *buf;
-
-	mutex_lock(&st->buf_mutex);
-
-	buf = st->buf;
-	memset(buf, 0, 16);
-
-	ret = vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e,
-			0, buf, 16);
-	mutex_unlock(&st->buf_mutex);
-	return ret;
-}
-
-static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state)
-{
-	int ret;
-	struct vp702x_device_state *st = adap->dev->priv;
-	u8 *buf;
-
-	mutex_lock(&st->buf_mutex);
-
-	buf = st->buf;
-	memset(buf, 0, 16);
-	ret = vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f,
-			0, buf, 16);
-
-	mutex_unlock(&st->buf_mutex);
-
-	return ret;
-}
-
-static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff)
-{
-	struct vp702x_adapter_state *st = adap->priv;
-	struct vp702x_device_state *dst = adap->dev->priv;
-	u8 *buf;
-
-	if (onoff)
-		st->pid_filter_state |=  (1 << id);
-	else {
-		st->pid_filter_state &= ~(1 << id);
-		pid = 0xffff;
-	}
-
-	id = 0x10 + id*2;
-
-	vp702x_set_pld_state(adap, st->pid_filter_state);
-
-	mutex_lock(&dst->buf_mutex);
-
-	buf = dst->buf;
-	memset(buf, 0, 16);
-	vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16);
-	vp702x_usb_in_op(adap->dev, 0xe0, (((pid     ) & 0xff) << 8) | (id+1), 0, buf, 16);
-
-	mutex_unlock(&dst->buf_mutex);
-
-	return 0;
-}
-
-
-static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap)
-{
-	struct vp702x_adapter_state *st = adap->priv;
-	struct vp702x_device_state *dst = adap->dev->priv;
-	int i;
-	u8 *b;
-
-	st->pid_filter_count = 8;
-	st->pid_filter_can_bypass = 1;
-	st->pid_filter_state = 0x00;
-
-	vp702x_set_pld_mode(adap, 1); /* bypass */
-
-	for (i = 0; i < st->pid_filter_count; i++)
-		vp702x_set_pid(adap, 0xffff, i, 1);
-
-	mutex_lock(&dst->buf_mutex);
-	b = dst->buf;
-	memset(b, 0, 10);
-	vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10);
-	vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10);
-	vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10);
-	mutex_unlock(&dst->buf_mutex);
-	/*vp702x_set_pld_mode(d, 0); // filter */
-
-	return 0;
-}
-
-static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-	return 0;
-}
-
-/* keys for the enclosed remote control */
-static struct rc_map_table rc_map_vp702x_table[] = {
-	{ 0x0001, KEY_1 },
-	{ 0x0002, KEY_2 },
-};
-
-/* remote control stuff (does not work with my box) */
-static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
-{
-	u8 *key;
-	int i;
-
-/* remove the following return to enabled remote querying */
-	return 0;
-
-	key = kmalloc(10, GFP_KERNEL);
-	if (!key)
-		return -ENOMEM;
-
-	vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
-
-	deb_rc("remote query key: %x %d\n",key[1],key[1]);
-
-	if (key[1] == 0x44) {
-		*state = REMOTE_NO_KEY_PRESSED;
-		kfree(key);
-		return 0;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(rc_map_vp702x_table); i++)
-		if (rc5_custom(&rc_map_vp702x_table[i]) == key[1]) {
-			*state = REMOTE_KEY_PRESSED;
-			*event = rc_map_vp702x_table[i].keycode;
-			break;
-		}
-	kfree(key);
-	return 0;
-}
-
-
-static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
-{
-	u8 i, *buf;
-	struct vp702x_device_state *st = d->priv;
-
-	mutex_lock(&st->buf_mutex);
-	buf = st->buf;
-	for (i = 6; i < 12; i++)
-		vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &buf[i - 6], 1);
-
-	memcpy(mac, buf, 6);
-	mutex_unlock(&st->buf_mutex);
-	return 0;
-}
-
-static int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	u8 buf[10] = { 0 };
-
-	vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
-
-	if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0,
-				   buf, 10, 10))
-		return -EIO;
-
-	buf[9] = '\0';
-	info("system string: %s",&buf[1]);
-
-	vp702x_init_pid_filter(adap);
-
-	adap->fe_adap[0].fe = vp702x_fe_attach(adap->dev);
-	vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
-
-	return 0;
-}
-
-static struct dvb_usb_device_properties vp702x_properties;
-
-static int vp702x_usb_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	struct dvb_usb_device *d;
-	struct vp702x_device_state *st;
-	int ret;
-
-	ret = dvb_usb_device_init(intf, &vp702x_properties,
-				   THIS_MODULE, &d, adapter_nr);
-	if (ret)
-		goto out;
-
-	st = d->priv;
-	st->buf_len = 16;
-	st->buf = kmalloc(st->buf_len, GFP_KERNEL);
-	if (!st->buf) {
-		ret = -ENOMEM;
-		dvb_usb_device_exit(intf);
-		goto out;
-	}
-	mutex_init(&st->buf_mutex);
-
-out:
-	return ret;
-
-}
-
-static void vp702x_usb_disconnect(struct usb_interface *intf)
-{
-	struct dvb_usb_device *d = usb_get_intfdata(intf);
-	struct vp702x_device_state *st = d->priv;
-	mutex_lock(&st->buf_mutex);
-	kfree(st->buf);
-	mutex_unlock(&st->buf_mutex);
-	dvb_usb_device_exit(intf);
-}
-
-static struct usb_device_id vp702x_usb_table [] = {
-	    { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) },
-//	    { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) },
-//	    { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) },
-	    { 0 },
-};
-MODULE_DEVICE_TABLE(usb, vp702x_usb_table);
-
-static struct dvb_usb_device_properties vp702x_properties = {
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware            = "dvb-usb-vp702x-02.fw",
-	.no_reconnect        = 1,
-
-	.size_of_priv     = sizeof(struct vp702x_device_state),
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.caps             = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
-
-			.streaming_ctrl   = vp702x_streaming_ctrl,
-			.frontend_attach  = vp702x_frontend_attach,
-
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 10,
-				.endpoint = 0x02,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-			.size_of_priv     = sizeof(struct vp702x_adapter_state),
-		}
-	},
-	.read_mac_address = vp702x_read_mac_addr,
-
-	.rc.legacy = {
-		.rc_map_table       = rc_map_vp702x_table,
-		.rc_map_size  = ARRAY_SIZE(rc_map_vp702x_table),
-		.rc_interval      = 400,
-		.rc_query         = vp702x_rc_query,
-	},
-
-	.num_device_descs = 1,
-	.devices = {
-		{ .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)",
-		  .cold_ids = { &vp702x_usb_table[0], NULL },
-		  .warm_ids = { NULL },
-		},
-/*		{ .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)",
-		  .cold_ids = { &vp702x_usb_table[2], NULL },
-		  .warm_ids = { &vp702x_usb_table[3], NULL },
-		},
-*/		{ NULL },
-	}
-};
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver vp702x_usb_driver = {
-	.name		= "dvb_usb_vp702x",
-	.probe		= vp702x_usb_probe,
-	.disconnect	= vp702x_usb_disconnect,
-	.id_table	= vp702x_usb_table,
-};
-
-module_usb_driver(vp702x_usb_driver);
-
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/dvb/dvb-usb/vp702x.h
deleted file mode 100644
index 20b9005..0000000
--- a/drivers/media/dvb/dvb-usb/vp702x.h
+++ /dev/null
@@ -1,113 +0,0 @@
-#ifndef _DVB_USB_VP7021_H_
-#define _DVB_USB_VP7021_H_
-
-#define DVB_USB_LOG_PREFIX "vp702x"
-#include "dvb-usb.h"
-
-extern int dvb_usb_vp702x_debug;
-#define deb_info(args...) dprintk(dvb_usb_vp702x_debug,0x01,args)
-#define deb_xfer(args...) dprintk(dvb_usb_vp702x_debug,0x02,args)
-#define deb_rc(args...)   dprintk(dvb_usb_vp702x_debug,0x04,args)
-#define deb_fe(args...)   dprintk(dvb_usb_vp702x_debug,0x08,args)
-
-/* commands are read and written with USB control messages */
-
-/* consecutive read/write operation */
-#define REQUEST_OUT		0xB2
-#define REQUEST_IN		0xB3
-
-/* the out-buffer of these consecutive operations contain sub-commands when b[0] = 0
- * request: 0xB2; i: 0; v: 0; b[0] = 0, b[1] = subcmd, additional buffer
- * the returning buffer looks as follows
- * request: 0xB3; i: 0; v: 0; b[0] = 0xB3, additional buffer */
-
-#define GET_TUNER_STATUS	0x05
-/* additional in buffer:
- * 0   1   2    3              4   5   6               7       8
- * N/A N/A 0x05 signal-quality N/A N/A signal-strength lock==0 N/A */
-
-#define GET_SYSTEM_STRING	0x06
-/* additional in buffer:
- * 0   1   2   3   4   5   6   7   8
- * N/A 'U' 'S' 'B' '7' '0' '2' 'X' N/A */
-
-#define SET_DISEQC_CMD		0x08
-/* additional out buffer:
- * 0    1  2  3  4
- * len  X1 X2 X3 X4
- * additional in buffer:
- * 0   1 2
- * N/A 0 0   b[1] == b[2] == 0 -> success, failure otherwise */
-
-#define SET_LNB_POWER		0x09
-/* additional out buffer:
- * 0    1    2
- * 0x00 0xff 1 = on, 0 = off
- * additional in buffer:
- * 0   1 2
- * N/A 0 0   b[1] == b[2] == 0 -> success failure otherwise */
-
-#define GET_MAC_ADDRESS		0x0A
-/* #define GET_MAC_ADDRESS   0x0B */
-/* additional in buffer:
- * 0   1   2            3    4    5    6    7    8
- * N/A N/A 0x0A or 0x0B MAC0 MAC1 MAC2 MAC3 MAC4 MAC5 */
-
-#define SET_PID_FILTER		0x11
-/* additional in buffer:
- * 0        1        ... 14       15       16
- * PID0_MSB PID0_LSB ... PID7_MSB PID7_LSB PID_active (bits) */
-
-/* request: 0xB2; i: 0; v: 0;
- * b[0] != 0 -> tune and lock a channel
- * 0     1     2       3      4      5      6    7
- * freq0 freq1 divstep srate0 srate1 srate2 flag chksum
- */
-
-/* one direction requests */
-#define READ_REMOTE_REQ		0xB4
-/* IN  i: 0; v: 0; b[0] == request, b[1] == key */
-
-#define READ_PID_NUMBER_REQ	0xB5
-/* IN  i: 0; v: 0; b[0] == request, b[1] == 0, b[2] = pid number */
-
-#define WRITE_EEPROM_REQ	0xB6
-/* OUT i: offset; v: value to write; no extra buffer */
-
-#define READ_EEPROM_REQ		0xB7
-/* IN  i: bufferlen; v: offset; buffer with bufferlen bytes */
-
-#define READ_STATUS		0xB8
-/* IN  i: 0; v: 0; bufferlen 10 */
-
-#define READ_TUNER_REG_REQ	0xB9
-/* IN  i: 0; v: register; b[0] = value */
-
-#define READ_FX2_REG_REQ	0xBA
-/* IN  i: offset; v: 0; b[0] = value */
-
-#define WRITE_FX2_REG_REQ	0xBB
-/* OUT i: offset; v: value to write; 1 byte extra buffer */
-
-#define SET_TUNER_POWER_REQ	0xBC
-/* IN  i: 0 = power off, 1 = power on */
-
-#define WRITE_TUNER_REG_REQ	0xBD
-/* IN  i: register, v: value to write, no extra buffer */
-
-#define RESET_TUNER		0xBE
-/* IN  i: 0, v: 0, no extra buffer */
-
-struct vp702x_device_state {
-	struct mutex buf_mutex;
-	int buf_len;
-	u8 *buf;
-};
-
-
-extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d);
-
-extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec);
-extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/vp7045-fe.c b/drivers/media/dvb/dvb-usb/vp7045-fe.c
deleted file mode 100644
index b8825b1..0000000
--- a/drivers/media/dvb/dvb-usb/vp7045-fe.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/* DVB frontend part of the Linux driver for TwinhanDTV Alpha/MagicBoxII USB2.0
- * DVB-T receiver.
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * Thanks to Twinhan who kindly provided hardware and information.
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- *
- */
-#include "vp7045.h"
-
-/* It is a Zarlink MT352 within a Samsung Tuner (DNOS404ZH102A) - 040929 - AAT
- *
- * Programming is hidden inside the firmware, so set_frontend is very easy.
- * Even though there is a Firmware command that one can use to access the demod
- * via its registers. This is used for status information.
- */
-
-struct vp7045_fe_state {
-	struct dvb_frontend fe;
-	struct dvb_usb_device *d;
-};
-
-static int vp7045_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
-{
-	struct vp7045_fe_state *state = fe->demodulator_priv;
-	u8 s0 = vp7045_read_reg(state->d,0x00),
-	   s1 = vp7045_read_reg(state->d,0x01),
-	   s3 = vp7045_read_reg(state->d,0x03);
-
-	*status = 0;
-	if (s0 & (1 << 4))
-		*status |= FE_HAS_CARRIER;
-	if (s0 & (1 << 1))
-		*status |= FE_HAS_VITERBI;
-	if (s0 & (1 << 5))
-		*status |= FE_HAS_LOCK;
-	if (s1 & (1 << 1))
-		*status |= FE_HAS_SYNC;
-	if (s3 & (1 << 6))
-		*status |= FE_HAS_SIGNAL;
-
-	if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
-			(FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
-		*status &= ~FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int vp7045_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
-{
-	struct vp7045_fe_state *state = fe->demodulator_priv;
-	*ber = (vp7045_read_reg(state->d, 0x0D) << 16) |
-	       (vp7045_read_reg(state->d, 0x0E) << 8) |
-		vp7045_read_reg(state->d, 0x0F);
-	return 0;
-}
-
-static int vp7045_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
-{
-	struct vp7045_fe_state *state = fe->demodulator_priv;
-	*unc = (vp7045_read_reg(state->d, 0x10) << 8) |
-		    vp7045_read_reg(state->d, 0x11);
-	return 0;
-}
-
-static int vp7045_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
-{
-	struct vp7045_fe_state *state = fe->demodulator_priv;
-	u16 signal = (vp7045_read_reg(state->d, 0x14) << 8) |
-		vp7045_read_reg(state->d, 0x15);
-
-	*strength = ~signal;
-	return 0;
-}
-
-static int vp7045_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
-{
-	struct vp7045_fe_state *state = fe->demodulator_priv;
-	u8 _snr = vp7045_read_reg(state->d, 0x09);
-	*snr = (_snr << 8) | _snr;
-	return 0;
-}
-
-static int vp7045_fe_init(struct dvb_frontend* fe)
-{
-	return 0;
-}
-
-static int vp7045_fe_sleep(struct dvb_frontend* fe)
-{
-	return 0;
-}
-
-static int vp7045_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
-{
-	tune->min_delay_ms = 800;
-	return 0;
-}
-
-static int vp7045_fe_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
-	struct vp7045_fe_state *state = fe->demodulator_priv;
-	u8 buf[5];
-	u32 freq = fep->frequency / 1000;
-
-	buf[0] = (freq >> 16) & 0xff;
-	buf[1] = (freq >>  8) & 0xff;
-	buf[2] =  freq        & 0xff;
-	buf[3] = 0;
-
-	switch (fep->bandwidth_hz) {
-	case 8000000:
-		buf[4] = 8;
-		break;
-	case 7000000:
-		buf[4] = 7;
-		break;
-	case 6000000:
-		buf[4] = 6;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	vp7045_usb_op(state->d,LOCK_TUNER_COMMAND,buf,5,NULL,0,200);
-	return 0;
-}
-
-static void vp7045_fe_release(struct dvb_frontend* fe)
-{
-	struct vp7045_fe_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops vp7045_fe_ops;
-
-struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d)
-{
-	struct vp7045_fe_state *s = kzalloc(sizeof(struct vp7045_fe_state), GFP_KERNEL);
-	if (s == NULL)
-		goto error;
-
-	s->d = d;
-	memcpy(&s->fe.ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops));
-	s->fe.demodulator_priv = s;
-
-	return &s->fe;
-error:
-	return NULL;
-}
-
-
-static struct dvb_frontend_ops vp7045_fe_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name			= "Twinhan VP7045/46 USB DVB-T",
-		.frequency_min		= 44250000,
-		.frequency_max		= 867250000,
-		.frequency_stepsize	= 1000,
-		.caps = FE_CAN_INVERSION_AUTO |
-				FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-				FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-				FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-				FE_CAN_TRANSMISSION_MODE_AUTO |
-				FE_CAN_GUARD_INTERVAL_AUTO |
-				FE_CAN_RECOVER |
-				FE_CAN_HIERARCHY_AUTO,
-	},
-
-	.release = vp7045_fe_release,
-
-	.init = vp7045_fe_init,
-	.sleep = vp7045_fe_sleep,
-
-	.set_frontend = vp7045_fe_set_frontend,
-	.get_tune_settings = vp7045_fe_get_tune_settings,
-
-	.read_status = vp7045_fe_read_status,
-	.read_ber = vp7045_fe_read_ber,
-	.read_signal_strength = vp7045_fe_read_signal_strength,
-	.read_snr = vp7045_fe_read_snr,
-	.read_ucblocks = vp7045_fe_read_unc_blocks,
-};
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
deleted file mode 100644
index d750724..0000000
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/* DVB USB compliant Linux driver for the
- *  - TwinhanDTV Alpha/MagicBoxII USB2.0 DVB-T receiver
- *  - DigitalNow TinyUSB2 DVB-t receiver
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * Thanks to Twinhan who kindly provided hardware and information.
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "vp7045.h"
-
-/* debug */
-static int dvb_usb_vp7045_debug;
-module_param_named(debug,dvb_usb_vp7045_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
-#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
-#define deb_rc(args...)   dprintk(dvb_usb_vp7045_debug,0x04,args)
-
-int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec)
-{
-	int ret = 0;
-	u8 *buf = d->priv;
-
-	buf[0] = cmd;
-
-	if (outlen > 19)
-		outlen = 19;
-
-	if (inlen > 11)
-		inlen = 11;
-
-	ret = mutex_lock_interruptible(&d->usb_mutex);
-	if (ret)
-		return ret;
-
-	if (out != NULL && outlen > 0)
-		memcpy(&buf[1], out, outlen);
-
-	deb_xfer("out buffer: ");
-	debug_dump(buf, outlen+1, deb_xfer);
-
-
-	if (usb_control_msg(d->udev,
-			usb_sndctrlpipe(d->udev,0),
-			TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0,
-			buf, 20, 2000) != 20) {
-		err("USB control message 'out' went wrong.");
-		ret = -EIO;
-		goto unlock;
-	}
-
-	msleep(msec);
-
-	if (usb_control_msg(d->udev,
-			usb_rcvctrlpipe(d->udev,0),
-			TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
-			buf, 12, 2000) != 12) {
-		err("USB control message 'in' went wrong.");
-		ret = -EIO;
-		goto unlock;
-	}
-
-	deb_xfer("in buffer: ");
-	debug_dump(buf, 12, deb_xfer);
-
-	if (in != NULL && inlen > 0)
-		memcpy(in, &buf[1], inlen);
-
-unlock:
-	mutex_unlock(&d->usb_mutex);
-
-	return ret;
-}
-
-u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg)
-{
-	u8 obuf[2] = { 0 },v;
-	obuf[1] = reg;
-
-	vp7045_usb_op(d,TUNER_REG_READ,obuf,2,&v,1,30);
-
-	return v;
-}
-
-static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	u8 v = onoff;
-	return vp7045_usb_op(d,SET_TUNER_POWER,&v,1,NULL,0,150);
-}
-
-/* remote control stuff */
-
-/* The keymapping struct. Somehow this should be loaded to the driver, but
- * currently it is hardcoded. */
-static struct rc_map_table rc_map_vp7045_table[] = {
-	{ 0x0016, KEY_POWER },
-	{ 0x0010, KEY_MUTE },
-	{ 0x0003, KEY_1 },
-	{ 0x0001, KEY_2 },
-	{ 0x0006, KEY_3 },
-	{ 0x0009, KEY_4 },
-	{ 0x001d, KEY_5 },
-	{ 0x001f, KEY_6 },
-	{ 0x000d, KEY_7 },
-	{ 0x0019, KEY_8 },
-	{ 0x001b, KEY_9 },
-	{ 0x0015, KEY_0 },
-	{ 0x0005, KEY_CHANNELUP },
-	{ 0x0002, KEY_CHANNELDOWN },
-	{ 0x001e, KEY_VOLUMEUP },
-	{ 0x000a, KEY_VOLUMEDOWN },
-	{ 0x0011, KEY_RECORD },
-	{ 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */
-	{ 0x0014, KEY_PLAY },
-	{ 0x001a, KEY_STOP },
-	{ 0x0040, KEY_REWIND },
-	{ 0x0012, KEY_FASTFORWARD },
-	{ 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */
-	{ 0x004c, KEY_PAUSE },
-	{ 0x004d, KEY_SCREEN }, /* Full screen mode. */
-	{ 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
-	{ 0x000c, KEY_CANCEL }, /* Cancel */
-	{ 0x001c, KEY_EPG }, /* EPG */
-	{ 0x0000, KEY_TAB }, /* Tab */
-	{ 0x0048, KEY_INFO }, /* Preview */
-	{ 0x0004, KEY_LIST }, /* RecordList */
-	{ 0x000f, KEY_TEXT }, /* Teletext */
-	{ 0x0041, KEY_PREVIOUSSONG },
-	{ 0x0042, KEY_NEXTSONG },
-	{ 0x004b, KEY_UP },
-	{ 0x0051, KEY_DOWN },
-	{ 0x004e, KEY_LEFT },
-	{ 0x0052, KEY_RIGHT },
-	{ 0x004f, KEY_ENTER },
-	{ 0x0013, KEY_CANCEL },
-	{ 0x004a, KEY_CLEAR },
-	{ 0x0054, KEY_PRINT }, /* Capture */
-	{ 0x0043, KEY_SUBTITLE }, /* Subtitle/CC */
-	{ 0x0008, KEY_VIDEO }, /* A/V */
-	{ 0x0007, KEY_SLEEP }, /* Hibernate */
-	{ 0x0045, KEY_ZOOM }, /* Zoom+ */
-	{ 0x0018, KEY_RED},
-	{ 0x0053, KEY_GREEN},
-	{ 0x005e, KEY_YELLOW},
-	{ 0x005f, KEY_BLUE}
-};
-
-static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
-{
-	u8 key;
-	int i;
-	vp7045_usb_op(d,RC_VAL_READ,NULL,0,&key,1,20);
-
-	deb_rc("remote query key: %x %d\n",key,key);
-
-	if (key == 0x44) {
-		*state = REMOTE_NO_KEY_PRESSED;
-		return 0;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(rc_map_vp7045_table); i++)
-		if (rc5_data(&rc_map_vp7045_table[i]) == key) {
-			*state = REMOTE_KEY_PRESSED;
-			*event = rc_map_vp7045_table[i].keycode;
-			break;
-		}
-	return 0;
-}
-
-static int vp7045_read_eeprom(struct dvb_usb_device *d,u8 *buf, int len, int offset)
-{
-	int i = 0;
-	u8 v,br[2];
-	for (i=0; i < len; i++) {
-		v = offset + i;
-		vp7045_usb_op(d,GET_EE_VALUE,&v,1,br,2,5);
-		buf[i] = br[1];
-	}
-	deb_info("VP7045 EEPROM read (offs: %d, len: %d) : ",offset, i);
-	debug_dump(buf,i,deb_info);
-	return 0;
-}
-
-static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
-{
-	return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR);
-}
-
-static int vp7045_frontend_attach(struct dvb_usb_adapter *adap)
-{
-	u8 buf[255] = { 0 };
-
-	vp7045_usb_op(adap->dev,VENDOR_STRING_READ,NULL,0,buf,20,0);
-	buf[10] = '\0';
-	deb_info("firmware says: %s ",buf);
-
-	vp7045_usb_op(adap->dev,PRODUCT_STRING_READ,NULL,0,buf,20,0);
-	buf[10] = '\0';
-	deb_info("%s ",buf);
-
-	vp7045_usb_op(adap->dev,FW_VERSION_READ,NULL,0,buf,20,0);
-	buf[10] = '\0';
-	deb_info("v%s\n",buf);
-
-/*	Dump the EEPROM */
-/*	vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */
-
-	adap->fe_adap[0].fe = vp7045_fe_attach(adap->dev);
-
-	return 0;
-}
-
-static struct dvb_usb_device_properties vp7045_properties;
-
-static int vp7045_usb_probe(struct usb_interface *intf,
-		const struct usb_device_id *id)
-{
-	return dvb_usb_device_init(intf, &vp7045_properties,
-				   THIS_MODULE, NULL, adapter_nr);
-}
-
-static struct usb_device_id vp7045_usb_table [] = {
-	    { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_COLD) },
-	    { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_WARM) },
-	    { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_COLD) },
-	    { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_WARM) },
-	    { 0 },
-};
-MODULE_DEVICE_TABLE(usb, vp7045_usb_table);
-
-static struct dvb_usb_device_properties vp7045_properties = {
-	.usb_ctrl = CYPRESS_FX2,
-	.firmware = "dvb-usb-vp7045-01.fw",
-	.size_of_priv = 20,
-
-	.num_adapters = 1,
-	.adapter = {
-		{
-		.num_frontends = 1,
-		.fe = {{
-			.frontend_attach  = vp7045_frontend_attach,
-			/* parameter for the MPEG2-data transfer */
-			.stream = {
-				.type = USB_BULK,
-				.count = 7,
-				.endpoint = 0x02,
-				.u = {
-					.bulk = {
-						.buffersize = 4096,
-					}
-				}
-			},
-		}},
-		}
-	},
-	.power_ctrl       = vp7045_power_ctrl,
-	.read_mac_address = vp7045_read_mac_addr,
-
-	.rc.legacy = {
-		.rc_interval      = 400,
-		.rc_map_table       = rc_map_vp7045_table,
-		.rc_map_size  = ARRAY_SIZE(rc_map_vp7045_table),
-		.rc_query         = vp7045_rc_query,
-	},
-
-	.num_device_descs = 2,
-	.devices = {
-		{ .name = "Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)",
-		  .cold_ids = { &vp7045_usb_table[0], NULL },
-		  .warm_ids = { &vp7045_usb_table[1], NULL },
-		},
-		{ .name = "DigitalNow TinyUSB 2 DVB-t Receiver",
-		  .cold_ids = { &vp7045_usb_table[2], NULL },
-		  .warm_ids = { &vp7045_usb_table[3], NULL },
-		},
-		{ NULL },
-	}
-};
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver vp7045_usb_driver = {
-	.name		= "dvb_usb_vp7045",
-	.probe		= vp7045_usb_probe,
-	.disconnect	= dvb_usb_device_exit,
-	.id_table	= vp7045_usb_table,
-};
-
-module_usb_driver(vp7045_usb_driver);
-
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/vp7045.h b/drivers/media/dvb/dvb-usb/vp7045.h
deleted file mode 100644
index cf5ec46..0000000
--- a/drivers/media/dvb/dvb-usb/vp7045.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Common header-file of the Linux driver for the TwinhanDTV Alpha/MagicBoxII
- * USB2.0 DVB-T receiver.
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * Thanks to Twinhan who kindly provided hardware and information.
- *
- *	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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#ifndef _DVB_USB_VP7045_H_
-#define _DVB_USB_VP7045_H_
-
-#define DVB_USB_LOG_PREFIX "vp7045"
-#include "dvb-usb.h"
-
-/* vp7045 commands */
-
-/* Twinhan Vendor requests */
-#define TH_COMMAND_IN                     0xC0
-#define TH_COMMAND_OUT                    0xC1
-
-/* command bytes */
-#define TUNER_REG_READ                    0x03
-#define TUNER_REG_WRITE                   0x04
-
-#define RC_VAL_READ                       0x05
- #define RC_NO_KEY                        0x44
-
-#define SET_TUNER_POWER                   0x06
-#define CHECK_TUNER_POWER                 0x12
- #define Tuner_Power_ON                   1
- #define Tuner_Power_OFF                  0
-
-#define GET_USB_SPEED                     0x07
-
-#define LOCK_TUNER_COMMAND                0x09
-
-#define TUNER_SIGNAL_READ                 0x0A
-
-/* FX2 eeprom */
-#define SET_EE_VALUE                      0x10
-#define GET_EE_VALUE                      0x11
- #define FX2_ID_ADDR                      0x00
- #define VID_MSB_ADDR                     0x02
- #define VID_LSB_ADDR                     0x01
- #define PID_MSB_ADDR                     0x04
- #define PID_LSB_ADDR                     0x03
- #define MAC_0_ADDR                       0x07
- #define MAC_1_ADDR                       0x08
- #define MAC_2_ADDR                       0x09
- #define MAC_3_ADDR                       0x0a
- #define MAC_4_ADDR                       0x0b
- #define MAC_5_ADDR                       0x0c
-
-#define RESET_FX2                         0x13
-
-#define FW_VERSION_READ                   0x0B
-#define VENDOR_STRING_READ                0x0C
-#define PRODUCT_STRING_READ               0x0D
-#define FW_BCD_VERSION_READ               0x14
-
-extern struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d);
-extern int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen,int msec);
-extern u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg);
-
-#endif
diff --git a/drivers/media/dvb/firewire/Kconfig b/drivers/media/dvb/firewire/Kconfig
deleted file mode 100644
index f3e9448..0000000
--- a/drivers/media/dvb/firewire/Kconfig
+++ /dev/null
@@ -1,19 +0,0 @@
-config DVB_FIREDTV
-	tristate "FireDTV and FloppyDTV"
-	depends on DVB_CORE && FIREWIRE
-	help
-	  Support for DVB receivers from Digital Everywhere
-	  which are connected via IEEE 1394 (FireWire).
-
-	  These devices don't have an MPEG decoder built in,
-	  so you need an external software decoder to watch TV.
-
-	  To compile this driver as a module, say M here:
-	  the module will be called firedtv.
-
-if DVB_FIREDTV
-
-config DVB_FIREDTV_INPUT
-	def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m)
-
-endif # DVB_FIREDTV
diff --git a/drivers/media/dvb/firewire/Makefile b/drivers/media/dvb/firewire/Makefile
deleted file mode 100644
index 357b3aa..0000000
--- a/drivers/media/dvb/firewire/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-obj-$(CONFIG_DVB_FIREDTV) += firedtv.o
-
-firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o firedtv-fw.o
-firedtv-$(CONFIG_DVB_FIREDTV_INPUT)    += firedtv-rc.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c
deleted file mode 100644
index d1a1a13..0000000
--- a/drivers/media/dvb/firewire/firedtv-avc.c
+++ /dev/null
@@ -1,1457 +0,0 @@
-/*
- * FireDTV driver (formerly known as FireSAT)
- *
- * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
- * Copyright (C) 2008 Ben Backx <ben@bbackx.com>
- * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
- *
- *	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.
- */
-
-#include <linux/bug.h>
-#include <linux/crc32.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/jiffies.h>
-#include <linux/kernel.h>
-#include <linux/moduleparam.h>
-#include <linux/mutex.h>
-#include <linux/string.h>
-#include <linux/stringify.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-
-#include <dvb_frontend.h>
-
-#include "firedtv.h"
-
-#define FCP_COMMAND_REGISTER		0xfffff0000b00ULL
-
-#define AVC_CTYPE_CONTROL		0x0
-#define AVC_CTYPE_STATUS		0x1
-#define AVC_CTYPE_NOTIFY		0x3
-
-#define AVC_RESPONSE_ACCEPTED		0x9
-#define AVC_RESPONSE_STABLE		0xc
-#define AVC_RESPONSE_CHANGED		0xd
-#define AVC_RESPONSE_INTERIM		0xf
-
-#define AVC_SUBUNIT_TYPE_TUNER		(0x05 << 3)
-#define AVC_SUBUNIT_TYPE_UNIT		(0x1f << 3)
-
-#define AVC_OPCODE_VENDOR		0x00
-#define AVC_OPCODE_READ_DESCRIPTOR	0x09
-#define AVC_OPCODE_DSIT			0xc8
-#define AVC_OPCODE_DSD			0xcb
-
-#define DESCRIPTOR_TUNER_STATUS 	0x80
-#define DESCRIPTOR_SUBUNIT_IDENTIFIER	0x00
-
-#define SFE_VENDOR_DE_COMPANYID_0	0x00 /* OUI of Digital Everywhere */
-#define SFE_VENDOR_DE_COMPANYID_1	0x12
-#define SFE_VENDOR_DE_COMPANYID_2	0x87
-
-#define SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL 0x0a
-#define SFE_VENDOR_OPCODE_LNB_CONTROL		0x52
-#define SFE_VENDOR_OPCODE_TUNE_QPSK		0x58 /* for DVB-S */
-
-#define SFE_VENDOR_OPCODE_GET_FIRMWARE_VERSION	0x00
-#define SFE_VENDOR_OPCODE_HOST2CA		0x56
-#define SFE_VENDOR_OPCODE_CA2HOST		0x57
-#define SFE_VENDOR_OPCODE_CISTATUS		0x59
-#define SFE_VENDOR_OPCODE_TUNE_QPSK2		0x60 /* for DVB-S2 */
-
-#define SFE_VENDOR_TAG_CA_RESET			0x00
-#define SFE_VENDOR_TAG_CA_APPLICATION_INFO	0x01
-#define SFE_VENDOR_TAG_CA_PMT			0x02
-#define SFE_VENDOR_TAG_CA_DATE_TIME		0x04
-#define SFE_VENDOR_TAG_CA_MMI			0x05
-#define SFE_VENDOR_TAG_CA_ENTER_MENU		0x07
-
-#define EN50221_LIST_MANAGEMENT_ONLY	0x03
-#define EN50221_TAG_APP_INFO		0x9f8021
-#define EN50221_TAG_CA_INFO		0x9f8031
-
-struct avc_command_frame {
-	u8 ctype;
-	u8 subunit;
-	u8 opcode;
-	u8 operand[509];
-};
-
-struct avc_response_frame {
-	u8 response;
-	u8 subunit;
-	u8 opcode;
-	u8 operand[509];
-};
-
-#define LAST_OPERAND (509 - 1)
-
-static inline void clear_operands(struct avc_command_frame *c, int from, int to)
-{
-	memset(&c->operand[from], 0, to - from + 1);
-}
-
-static void pad_operands(struct avc_command_frame *c, int from)
-{
-	int to = ALIGN(from, 4);
-
-	if (from <= to && to <= LAST_OPERAND)
-		clear_operands(c, from, to);
-}
-
-#define AVC_DEBUG_READ_DESCRIPTOR              0x0001
-#define AVC_DEBUG_DSIT                         0x0002
-#define AVC_DEBUG_DSD                          0x0004
-#define AVC_DEBUG_REGISTER_REMOTE_CONTROL      0x0008
-#define AVC_DEBUG_LNB_CONTROL                  0x0010
-#define AVC_DEBUG_TUNE_QPSK                    0x0020
-#define AVC_DEBUG_TUNE_QPSK2                   0x0040
-#define AVC_DEBUG_HOST2CA                      0x0080
-#define AVC_DEBUG_CA2HOST                      0x0100
-#define AVC_DEBUG_APPLICATION_PMT              0x4000
-#define AVC_DEBUG_FCP_PAYLOADS                 0x8000
-
-static int avc_debug;
-module_param_named(debug, avc_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Verbose logging (none = 0"
-	", FCP subactions"
-	": READ DESCRIPTOR = "		__stringify(AVC_DEBUG_READ_DESCRIPTOR)
-	", DSIT = "			__stringify(AVC_DEBUG_DSIT)
-	", REGISTER_REMOTE_CONTROL = "	__stringify(AVC_DEBUG_REGISTER_REMOTE_CONTROL)
-	", LNB CONTROL = "		__stringify(AVC_DEBUG_LNB_CONTROL)
-	", TUNE QPSK = "		__stringify(AVC_DEBUG_TUNE_QPSK)
-	", TUNE QPSK2 = "		__stringify(AVC_DEBUG_TUNE_QPSK2)
-	", HOST2CA = "			__stringify(AVC_DEBUG_HOST2CA)
-	", CA2HOST = "			__stringify(AVC_DEBUG_CA2HOST)
-	"; Application sent PMT = "	__stringify(AVC_DEBUG_APPLICATION_PMT)
-	", FCP payloads = "		__stringify(AVC_DEBUG_FCP_PAYLOADS)
-	", or a combination, or all = -1)");
-
-/*
- * This is a workaround since there is no vendor specific command to retrieve
- * ca_info using AVC. If this parameter is not used, ca_system_id will be
- * filled with application_manufacturer from ca_app_info.
- * Digital Everywhere have said that adding ca_info is on their TODO list.
- */
-static unsigned int num_fake_ca_system_ids;
-static int fake_ca_system_ids[4] = { -1, -1, -1, -1 };
-module_param_array(fake_ca_system_ids, int, &num_fake_ca_system_ids, 0644);
-MODULE_PARM_DESC(fake_ca_system_ids, "If your CAM application manufacturer "
-		 "does not have the same ca_system_id as your CAS, you can "
-		 "override what ca_system_ids are presented to the "
-		 "application by setting this field to an array of ids.");
-
-static const char *debug_fcp_ctype(unsigned int ctype)
-{
-	static const char *ctypes[] = {
-		[0x0] = "CONTROL",		[0x1] = "STATUS",
-		[0x2] = "SPECIFIC INQUIRY",	[0x3] = "NOTIFY",
-		[0x4] = "GENERAL INQUIRY",	[0x8] = "NOT IMPLEMENTED",
-		[0x9] = "ACCEPTED",		[0xa] = "REJECTED",
-		[0xb] = "IN TRANSITION",	[0xc] = "IMPLEMENTED/STABLE",
-		[0xd] = "CHANGED",		[0xf] = "INTERIM",
-	};
-	const char *ret = ctype < ARRAY_SIZE(ctypes) ? ctypes[ctype] : NULL;
-
-	return ret ? ret : "?";
-}
-
-static const char *debug_fcp_opcode(unsigned int opcode,
-				    const u8 *data, int length)
-{
-	switch (opcode) {
-	case AVC_OPCODE_VENDOR:
-		break;
-	case AVC_OPCODE_READ_DESCRIPTOR:
-		return avc_debug & AVC_DEBUG_READ_DESCRIPTOR ?
-				"ReadDescriptor" : NULL;
-	case AVC_OPCODE_DSIT:
-		return avc_debug & AVC_DEBUG_DSIT ?
-				"DirectSelectInfo.Type" : NULL;
-	case AVC_OPCODE_DSD:
-		return avc_debug & AVC_DEBUG_DSD ? "DirectSelectData" : NULL;
-	default:
-		return "Unknown";
-	}
-
-	if (length < 7 ||
-	    data[3] != SFE_VENDOR_DE_COMPANYID_0 ||
-	    data[4] != SFE_VENDOR_DE_COMPANYID_1 ||
-	    data[5] != SFE_VENDOR_DE_COMPANYID_2)
-		return "Vendor/Unknown";
-
-	switch (data[6]) {
-	case SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL:
-		return avc_debug & AVC_DEBUG_REGISTER_REMOTE_CONTROL ?
-				"RegisterRC" : NULL;
-	case SFE_VENDOR_OPCODE_LNB_CONTROL:
-		return avc_debug & AVC_DEBUG_LNB_CONTROL ? "LNBControl" : NULL;
-	case SFE_VENDOR_OPCODE_TUNE_QPSK:
-		return avc_debug & AVC_DEBUG_TUNE_QPSK ? "TuneQPSK" : NULL;
-	case SFE_VENDOR_OPCODE_TUNE_QPSK2:
-		return avc_debug & AVC_DEBUG_TUNE_QPSK2 ? "TuneQPSK2" : NULL;
-	case SFE_VENDOR_OPCODE_HOST2CA:
-		return avc_debug & AVC_DEBUG_HOST2CA ? "Host2CA" : NULL;
-	case SFE_VENDOR_OPCODE_CA2HOST:
-		return avc_debug & AVC_DEBUG_CA2HOST ? "CA2Host" : NULL;
-	}
-	return "Vendor/Unknown";
-}
-
-static void debug_fcp(const u8 *data, int length)
-{
-	unsigned int subunit_type, subunit_id, opcode;
-	const char *op, *prefix;
-
-	prefix       = data[0] > 7 ? "FCP <- " : "FCP -> ";
-	subunit_type = data[1] >> 3;
-	subunit_id   = data[1] & 7;
-	opcode       = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2];
-	op           = debug_fcp_opcode(opcode, data, length);
-
-	if (op) {
-		printk(KERN_INFO "%ssu=%x.%x l=%d: %-8s - %s\n",
-		       prefix, subunit_type, subunit_id, length,
-		       debug_fcp_ctype(data[0]), op);
-		if (avc_debug & AVC_DEBUG_FCP_PAYLOADS)
-			print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_NONE,
-				       16, 1, data, length, false);
-	}
-}
-
-static void debug_pmt(char *msg, int length)
-{
-	printk(KERN_INFO "APP PMT -> l=%d\n", length);
-	print_hex_dump(KERN_INFO, "APP PMT -> ", DUMP_PREFIX_NONE,
-		       16, 1, msg, length, false);
-}
-
-static int avc_write(struct firedtv *fdtv)
-{
-	int err, retry;
-
-	fdtv->avc_reply_received = false;
-
-	for (retry = 0; retry < 6; retry++) {
-		if (unlikely(avc_debug))
-			debug_fcp(fdtv->avc_data, fdtv->avc_data_length);
-
-		err = fdtv_write(fdtv, FCP_COMMAND_REGISTER,
-				 fdtv->avc_data, fdtv->avc_data_length);
-		if (err) {
-			dev_err(fdtv->device, "FCP command write failed\n");
-
-			return err;
-		}
-
-		/*
-		 * AV/C specs say that answers should be sent within 150 ms.
-		 * Time out after 200 ms.
-		 */
-		if (wait_event_timeout(fdtv->avc_wait,
-				       fdtv->avc_reply_received,
-				       msecs_to_jiffies(200)) != 0)
-			return 0;
-	}
-	dev_err(fdtv->device, "FCP response timed out\n");
-
-	return -ETIMEDOUT;
-}
-
-static bool is_register_rc(struct avc_response_frame *r)
-{
-	return r->opcode     == AVC_OPCODE_VENDOR &&
-	       r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
-	       r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
-	       r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 &&
-	       r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
-}
-
-int avc_recv(struct firedtv *fdtv, void *data, size_t length)
-{
-	struct avc_response_frame *r = data;
-
-	if (unlikely(avc_debug))
-		debug_fcp(data, length);
-
-	if (length >= 8 && is_register_rc(r)) {
-		switch (r->response) {
-		case AVC_RESPONSE_CHANGED:
-			fdtv_handle_rc(fdtv, r->operand[4] << 8 | r->operand[5]);
-			schedule_work(&fdtv->remote_ctrl_work);
-			break;
-		case AVC_RESPONSE_INTERIM:
-			if (is_register_rc((void *)fdtv->avc_data))
-				goto wake;
-			break;
-		default:
-			dev_info(fdtv->device,
-				 "remote control result = %d\n", r->response);
-		}
-		return 0;
-	}
-
-	if (fdtv->avc_reply_received) {
-		dev_err(fdtv->device, "out-of-order AVC response, ignored\n");
-		return -EIO;
-	}
-
-	memcpy(fdtv->avc_data, data, length);
-	fdtv->avc_data_length = length;
-wake:
-	fdtv->avc_reply_received = true;
-	wake_up(&fdtv->avc_wait);
-
-	return 0;
-}
-
-static int add_pid_filter(struct firedtv *fdtv, u8 *operand)
-{
-	int i, n, pos = 1;
-
-	for (i = 0, n = 0; i < 16; i++) {
-		if (test_bit(i, &fdtv->channel_active)) {
-			operand[pos++] = 0x13; /* flowfunction relay */
-			operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */
-			operand[pos++] = (fdtv->channel_pid[i] >> 8) & 0x1f;
-			operand[pos++] = fdtv->channel_pid[i] & 0xff;
-			operand[pos++] = 0x00; /* tableID */
-			operand[pos++] = 0x00; /* filter_length */
-			n++;
-		}
-	}
-	operand[0] = n;
-
-	return pos;
-}
-
-/*
- * tuning command for setting the relative LNB frequency
- * (not supported by the AVC standard)
- */
-static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
-			      struct dtv_frontend_properties *p)
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-
-	c->opcode = AVC_OPCODE_VENDOR;
-
-	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
-	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
-	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
-	if (fdtv->type == FIREDTV_DVB_S2)
-		c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK2;
-	else
-		c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK;
-
-	c->operand[4] = (p->frequency >> 24) & 0xff;
-	c->operand[5] = (p->frequency >> 16) & 0xff;
-	c->operand[6] = (p->frequency >> 8) & 0xff;
-	c->operand[7] = p->frequency & 0xff;
-
-	c->operand[8] = ((p->symbol_rate / 1000) >> 8) & 0xff;
-	c->operand[9] = (p->symbol_rate / 1000) & 0xff;
-
-	switch (p->fec_inner) {
-	case FEC_1_2:	c->operand[10] = 0x1; break;
-	case FEC_2_3:	c->operand[10] = 0x2; break;
-	case FEC_3_4:	c->operand[10] = 0x3; break;
-	case FEC_5_6:	c->operand[10] = 0x4; break;
-	case FEC_7_8:	c->operand[10] = 0x5; break;
-	case FEC_4_5:
-	case FEC_8_9:
-	case FEC_AUTO:
-	default:	c->operand[10] = 0x0;
-	}
-
-	if (fdtv->voltage == 0xff)
-		c->operand[11] = 0xff;
-	else if (fdtv->voltage == SEC_VOLTAGE_18) /* polarisation */
-		c->operand[11] = 0;
-	else
-		c->operand[11] = 1;
-
-	if (fdtv->tone == 0xff)
-		c->operand[12] = 0xff;
-	else if (fdtv->tone == SEC_TONE_ON) /* band */
-		c->operand[12] = 1;
-	else
-		c->operand[12] = 0;
-
-	if (fdtv->type == FIREDTV_DVB_S2) {
-		if (fdtv->fe.dtv_property_cache.delivery_system == SYS_DVBS2) {
-			switch (fdtv->fe.dtv_property_cache.modulation) {
-			case QAM_16:		c->operand[13] = 0x1; break;
-			case QPSK:		c->operand[13] = 0x2; break;
-			case PSK_8:		c->operand[13] = 0x3; break;
-			default:		c->operand[13] = 0x2; break;
-			}
-			switch (fdtv->fe.dtv_property_cache.rolloff) {
-			case ROLLOFF_35:	c->operand[14] = 0x2; break;
-			case ROLLOFF_20:	c->operand[14] = 0x0; break;
-			case ROLLOFF_25:	c->operand[14] = 0x1; break;
-			case ROLLOFF_AUTO:
-			default:		c->operand[14] = 0x2; break;
-			/* case ROLLOFF_NONE:	c->operand[14] = 0xff; break; */
-			}
-			switch (fdtv->fe.dtv_property_cache.pilot) {
-			case PILOT_AUTO:	c->operand[15] = 0x0; break;
-			case PILOT_OFF:		c->operand[15] = 0x0; break;
-			case PILOT_ON:		c->operand[15] = 0x1; break;
-			}
-		} else {
-			c->operand[13] = 0x1;  /* auto modulation */
-			c->operand[14] = 0xff; /* disable rolloff */
-			c->operand[15] = 0xff; /* disable pilot */
-		}
-		return 16;
-	} else {
-		return 13;
-	}
-}
-
-static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
-			       struct dtv_frontend_properties *p)
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-
-	c->opcode = AVC_OPCODE_DSD;
-
-	c->operand[0] = 0;    /* source plug */
-	c->operand[1] = 0xd2; /* subfunction replace */
-	c->operand[2] = 0x20; /* system id = DVB */
-	c->operand[3] = 0x00; /* antenna number */
-	c->operand[4] = 0x11; /* system_specific_multiplex selection_length */
-
-	/* multiplex_valid_flags, high byte */
-	c->operand[5] =   0 << 7 /* reserved */
-			| 0 << 6 /* Polarisation */
-			| 0 << 5 /* Orbital_Pos */
-			| 1 << 4 /* Frequency */
-			| 1 << 3 /* Symbol_Rate */
-			| 0 << 2 /* FEC_outer */
-			| (p->fec_inner  != FEC_AUTO ? 1 << 1 : 0)
-			| (p->modulation != QAM_AUTO ? 1 << 0 : 0);
-
-	/* multiplex_valid_flags, low byte */
-	c->operand[6] =   0 << 7 /* NetworkID */
-			| 0 << 0 /* reserved */ ;
-
-	c->operand[7]  = 0x00;
-	c->operand[8]  = 0x00;
-	c->operand[9]  = 0x00;
-	c->operand[10] = 0x00;
-
-	c->operand[11] = (((p->frequency / 4000) >> 16) & 0xff) | (2 << 6);
-	c->operand[12] = ((p->frequency / 4000) >> 8) & 0xff;
-	c->operand[13] = (p->frequency / 4000) & 0xff;
-	c->operand[14] = ((p->symbol_rate / 1000) >> 12) & 0xff;
-	c->operand[15] = ((p->symbol_rate / 1000) >> 4) & 0xff;
-	c->operand[16] = ((p->symbol_rate / 1000) << 4) & 0xf0;
-	c->operand[17] = 0x00;
-
-	switch (p->fec_inner) {
-	case FEC_1_2:	c->operand[18] = 0x1; break;
-	case FEC_2_3:	c->operand[18] = 0x2; break;
-	case FEC_3_4:	c->operand[18] = 0x3; break;
-	case FEC_5_6:	c->operand[18] = 0x4; break;
-	case FEC_7_8:	c->operand[18] = 0x5; break;
-	case FEC_8_9:	c->operand[18] = 0x6; break;
-	case FEC_4_5:	c->operand[18] = 0x8; break;
-	case FEC_AUTO:
-	default:	c->operand[18] = 0x0;
-	}
-
-	switch (p->modulation) {
-	case QAM_16:	c->operand[19] = 0x08; break;
-	case QAM_32:	c->operand[19] = 0x10; break;
-	case QAM_64:	c->operand[19] = 0x18; break;
-	case QAM_128:	c->operand[19] = 0x20; break;
-	case QAM_256:	c->operand[19] = 0x28; break;
-	case QAM_AUTO:
-	default:	c->operand[19] = 0x00;
-	}
-
-	c->operand[20] = 0x00;
-	c->operand[21] = 0x00;
-
-	return 22 + add_pid_filter(fdtv, &c->operand[22]);
-}
-
-static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
-			       struct dtv_frontend_properties *p)
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-
-	c->opcode = AVC_OPCODE_DSD;
-
-	c->operand[0] = 0;    /* source plug */
-	c->operand[1] = 0xd2; /* subfunction replace */
-	c->operand[2] = 0x20; /* system id = DVB */
-	c->operand[3] = 0x00; /* antenna number */
-	c->operand[4] = 0x0c; /* system_specific_multiplex selection_length */
-
-	/* multiplex_valid_flags, high byte */
-	c->operand[5] =
-	      0 << 7 /* reserved */
-	    | 1 << 6 /* CenterFrequency */
-	    | (p->bandwidth_hz != 0        ? 1 << 5 : 0)
-	    | (p->modulation  != QAM_AUTO              ? 1 << 4 : 0)
-	    | (p->hierarchy != HIERARCHY_AUTO ? 1 << 3 : 0)
-	    | (p->code_rate_HP   != FEC_AUTO              ? 1 << 2 : 0)
-	    | (p->code_rate_LP   != FEC_AUTO              ? 1 << 1 : 0)
-	    | (p->guard_interval != GUARD_INTERVAL_AUTO   ? 1 << 0 : 0);
-
-	/* multiplex_valid_flags, low byte */
-	c->operand[6] =
-	      0 << 7 /* NetworkID */
-	    | (p->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0)
-	    | 0 << 5 /* OtherFrequencyFlag */
-	    | 0 << 0 /* reserved */ ;
-
-	c->operand[7]  = 0x0;
-	c->operand[8]  = (p->frequency / 10) >> 24;
-	c->operand[9]  = ((p->frequency / 10) >> 16) & 0xff;
-	c->operand[10] = ((p->frequency / 10) >>  8) & 0xff;
-	c->operand[11] = (p->frequency / 10) & 0xff;
-
-	switch (p->bandwidth_hz) {
-	case 7000000:	c->operand[12] = 0x20; break;
-	case 8000000:
-	case 6000000:	/* not defined by AVC spec */
-	case 0:
-	default:		c->operand[12] = 0x00;
-	}
-
-	switch (p->modulation) {
-	case QAM_16:	c->operand[13] = 1 << 6; break;
-	case QAM_64:	c->operand[13] = 2 << 6; break;
-	case QPSK:
-	default:	c->operand[13] = 0x00;
-	}
-
-	switch (p->hierarchy) {
-	case HIERARCHY_1:	c->operand[13] |= 1 << 3; break;
-	case HIERARCHY_2:	c->operand[13] |= 2 << 3; break;
-	case HIERARCHY_4:	c->operand[13] |= 3 << 3; break;
-	case HIERARCHY_AUTO:
-	case HIERARCHY_NONE:
-	default:		break;
-	}
-
-	switch (p->code_rate_HP) {
-	case FEC_2_3:	c->operand[13] |= 1; break;
-	case FEC_3_4:	c->operand[13] |= 2; break;
-	case FEC_5_6:	c->operand[13] |= 3; break;
-	case FEC_7_8:	c->operand[13] |= 4; break;
-	case FEC_1_2:
-	default:	break;
-	}
-
-	switch (p->code_rate_LP) {
-	case FEC_2_3:	c->operand[14] = 1 << 5; break;
-	case FEC_3_4:	c->operand[14] = 2 << 5; break;
-	case FEC_5_6:	c->operand[14] = 3 << 5; break;
-	case FEC_7_8:	c->operand[14] = 4 << 5; break;
-	case FEC_1_2:
-	default:	c->operand[14] = 0x00; break;
-	}
-
-	switch (p->guard_interval) {
-	case GUARD_INTERVAL_1_16:	c->operand[14] |= 1 << 3; break;
-	case GUARD_INTERVAL_1_8:	c->operand[14] |= 2 << 3; break;
-	case GUARD_INTERVAL_1_4:	c->operand[14] |= 3 << 3; break;
-	case GUARD_INTERVAL_1_32:
-	case GUARD_INTERVAL_AUTO:
-	default:			break;
-	}
-
-	switch (p->transmission_mode) {
-	case TRANSMISSION_MODE_8K:	c->operand[14] |= 1 << 1; break;
-	case TRANSMISSION_MODE_2K:
-	case TRANSMISSION_MODE_AUTO:
-	default:			break;
-	}
-
-	c->operand[15] = 0x00; /* network_ID[0] */
-	c->operand[16] = 0x00; /* network_ID[1] */
-
-	return 17 + add_pid_filter(fdtv, &c->operand[17]);
-}
-
-int avc_tuner_dsd(struct firedtv *fdtv,
-		  struct dtv_frontend_properties *p)
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-	int pos, ret;
-
-	mutex_lock(&fdtv->avc_mutex);
-
-	c->ctype   = AVC_CTYPE_CONTROL;
-	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
-
-	switch (fdtv->type) {
-	case FIREDTV_DVB_S:
-	case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, p); break;
-	case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, p); break;
-	case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, p); break;
-	default:
-		BUG();
-	}
-	pad_operands(c, pos);
-
-	fdtv->avc_data_length = ALIGN(3 + pos, 4);
-	ret = avc_write(fdtv);
-#if 0
-	/*
-	 * FIXME:
-	 * u8 *status was an out-parameter of avc_tuner_dsd, unused by caller.
-	 * Check for AVC_RESPONSE_ACCEPTED here instead?
-	 */
-	if (status)
-		*status = r->operand[2];
-#endif
-	mutex_unlock(&fdtv->avc_mutex);
-
-	if (ret == 0)
-		msleep(500);
-
-	return ret;
-}
-
-int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[])
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-	int ret, pos, k;
-
-	if (pidc > 16 && pidc != 0xff)
-		return -EINVAL;
-
-	mutex_lock(&fdtv->avc_mutex);
-
-	c->ctype   = AVC_CTYPE_CONTROL;
-	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
-	c->opcode  = AVC_OPCODE_DSD;
-
-	c->operand[0] = 0;	/* source plug */
-	c->operand[1] = 0xd2;	/* subfunction replace */
-	c->operand[2] = 0x20;	/* system id = DVB */
-	c->operand[3] = 0x00;	/* antenna number */
-	c->operand[4] = 0x00;	/* system_specific_multiplex selection_length */
-	c->operand[5] = pidc;	/* Nr_of_dsd_sel_specs */
-
-	pos = 6;
-	if (pidc != 0xff)
-		for (k = 0; k < pidc; k++) {
-			c->operand[pos++] = 0x13; /* flowfunction relay */
-			c->operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */
-			c->operand[pos++] = (pid[k] >> 8) & 0x1f;
-			c->operand[pos++] = pid[k] & 0xff;
-			c->operand[pos++] = 0x00; /* tableID */
-			c->operand[pos++] = 0x00; /* filter_length */
-		}
-	pad_operands(c, pos);
-
-	fdtv->avc_data_length = ALIGN(3 + pos, 4);
-	ret = avc_write(fdtv);
-
-	/* FIXME: check response code? */
-
-	mutex_unlock(&fdtv->avc_mutex);
-
-	if (ret == 0)
-		msleep(50);
-
-	return ret;
-}
-
-int avc_tuner_get_ts(struct firedtv *fdtv)
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-	int ret, sl;
-
-	mutex_lock(&fdtv->avc_mutex);
-
-	c->ctype   = AVC_CTYPE_CONTROL;
-	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
-	c->opcode  = AVC_OPCODE_DSIT;
-
-	sl = fdtv->type == FIREDTV_DVB_T ? 0x0c : 0x11;
-
-	c->operand[0] = 0;	/* source plug */
-	c->operand[1] = 0xd2;	/* subfunction replace */
-	c->operand[2] = 0xff;	/* status */
-	c->operand[3] = 0x20;	/* system id = DVB */
-	c->operand[4] = 0x00;	/* antenna number */
-	c->operand[5] = 0x0; 	/* system_specific_search_flags */
-	c->operand[6] = sl;	/* system_specific_multiplex selection_length */
-	/*
-	 * operand[7]: valid_flags[0]
-	 * operand[8]: valid_flags[1]
-	 * operand[7 + sl]: nr_of_dsit_sel_specs (always 0)
-	 */
-	clear_operands(c, 7, 24);
-
-	fdtv->avc_data_length = fdtv->type == FIREDTV_DVB_T ? 24 : 28;
-	ret = avc_write(fdtv);
-
-	/* FIXME: check response code? */
-
-	mutex_unlock(&fdtv->avc_mutex);
-
-	if (ret == 0)
-		msleep(250);
-
-	return ret;
-}
-
-int avc_identify_subunit(struct firedtv *fdtv)
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-	struct avc_response_frame *r = (void *)fdtv->avc_data;
-	int ret;
-
-	mutex_lock(&fdtv->avc_mutex);
-
-	c->ctype   = AVC_CTYPE_CONTROL;
-	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
-	c->opcode  = AVC_OPCODE_READ_DESCRIPTOR;
-
-	c->operand[0] = DESCRIPTOR_SUBUNIT_IDENTIFIER;
-	c->operand[1] = 0xff;
-	c->operand[2] = 0x00;
-	c->operand[3] = 0x00; /* length highbyte */
-	c->operand[4] = 0x08; /* length lowbyte  */
-	c->operand[5] = 0x00; /* offset highbyte */
-	c->operand[6] = 0x0d; /* offset lowbyte  */
-	clear_operands(c, 7, 8); /* padding */
-
-	fdtv->avc_data_length = 12;
-	ret = avc_write(fdtv);
-	if (ret < 0)
-		goto out;
-
-	if ((r->response != AVC_RESPONSE_STABLE &&
-	     r->response != AVC_RESPONSE_ACCEPTED) ||
-	    (r->operand[3] << 8) + r->operand[4] != 8) {
-		dev_err(fdtv->device, "cannot read subunit identifier\n");
-		ret = -EINVAL;
-	}
-out:
-	mutex_unlock(&fdtv->avc_mutex);
-
-	return ret;
-}
-
-#define SIZEOF_ANTENNA_INPUT_INFO 22
-
-int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-	struct avc_response_frame *r = (void *)fdtv->avc_data;
-	int length, ret;
-
-	mutex_lock(&fdtv->avc_mutex);
-
-	c->ctype   = AVC_CTYPE_CONTROL;
-	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
-	c->opcode  = AVC_OPCODE_READ_DESCRIPTOR;
-
-	c->operand[0] = DESCRIPTOR_TUNER_STATUS;
-	c->operand[1] = 0xff;	/* read_result_status */
-	/*
-	 * operand[2]: reserved
-	 * operand[3]: SIZEOF_ANTENNA_INPUT_INFO >> 8
-	 * operand[4]: SIZEOF_ANTENNA_INPUT_INFO & 0xff
-	 */
-	clear_operands(c, 2, 31);
-
-	fdtv->avc_data_length = 12;
-	ret = avc_write(fdtv);
-	if (ret < 0)
-		goto out;
-
-	if (r->response != AVC_RESPONSE_STABLE &&
-	    r->response != AVC_RESPONSE_ACCEPTED) {
-		dev_err(fdtv->device, "cannot read tuner status\n");
-		ret = -EINVAL;
-		goto out;
-	}
-
-	length = r->operand[9];
-	if (r->operand[1] != 0x10 || length != SIZEOF_ANTENNA_INPUT_INFO) {
-		dev_err(fdtv->device, "got invalid tuner status\n");
-		ret = -EINVAL;
-		goto out;
-	}
-
-	stat->active_system		= r->operand[10];
-	stat->searching			= r->operand[11] >> 7 & 1;
-	stat->moving			= r->operand[11] >> 6 & 1;
-	stat->no_rf			= r->operand[11] >> 5 & 1;
-	stat->input			= r->operand[12] >> 7 & 1;
-	stat->selected_antenna		= r->operand[12] & 0x7f;
-	stat->ber			= r->operand[13] << 24 |
-					  r->operand[14] << 16 |
-					  r->operand[15] << 8 |
-					  r->operand[16];
-	stat->signal_strength		= r->operand[17];
-	stat->raster_frequency		= r->operand[18] >> 6 & 2;
-	stat->rf_frequency		= (r->operand[18] & 0x3f) << 16 |
-					  r->operand[19] << 8 |
-					  r->operand[20];
-	stat->man_dep_info_length	= r->operand[21];
-	stat->front_end_error		= r->operand[22] >> 4 & 1;
-	stat->antenna_error		= r->operand[22] >> 3 & 1;
-	stat->front_end_power_status	= r->operand[22] >> 1 & 1;
-	stat->power_supply		= r->operand[22] & 1;
-	stat->carrier_noise_ratio	= r->operand[23] << 8 |
-					  r->operand[24];
-	stat->power_supply_voltage	= r->operand[27];
-	stat->antenna_voltage		= r->operand[28];
-	stat->firewire_bus_voltage	= r->operand[29];
-	stat->ca_mmi			= r->operand[30] & 1;
-	stat->ca_pmt_reply		= r->operand[31] >> 7 & 1;
-	stat->ca_date_time_request	= r->operand[31] >> 6 & 1;
-	stat->ca_application_info	= r->operand[31] >> 5 & 1;
-	stat->ca_module_present_status	= r->operand[31] >> 4 & 1;
-	stat->ca_dvb_flag		= r->operand[31] >> 3 & 1;
-	stat->ca_error_flag		= r->operand[31] >> 2 & 1;
-	stat->ca_initialization_status	= r->operand[31] >> 1 & 1;
-out:
-	mutex_unlock(&fdtv->avc_mutex);
-
-	return ret;
-}
-
-int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
-		    char conttone, char nrdiseq,
-		    struct dvb_diseqc_master_cmd *diseqcmd)
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-	struct avc_response_frame *r = (void *)fdtv->avc_data;
-	int pos, j, k, ret;
-
-	mutex_lock(&fdtv->avc_mutex);
-
-	c->ctype   = AVC_CTYPE_CONTROL;
-	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
-	c->opcode  = AVC_OPCODE_VENDOR;
-
-	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
-	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
-	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
-	c->operand[3] = SFE_VENDOR_OPCODE_LNB_CONTROL;
-	c->operand[4] = voltage;
-	c->operand[5] = nrdiseq;
-
-	pos = 6;
-	for (j = 0; j < nrdiseq; j++) {
-		c->operand[pos++] = diseqcmd[j].msg_len;
-
-		for (k = 0; k < diseqcmd[j].msg_len; k++)
-			c->operand[pos++] = diseqcmd[j].msg[k];
-	}
-	c->operand[pos++] = burst;
-	c->operand[pos++] = conttone;
-	pad_operands(c, pos);
-
-	fdtv->avc_data_length = ALIGN(3 + pos, 4);
-	ret = avc_write(fdtv);
-	if (ret < 0)
-		goto out;
-
-	if (r->response != AVC_RESPONSE_ACCEPTED) {
-		dev_err(fdtv->device, "LNB control failed\n");
-		ret = -EINVAL;
-	}
-out:
-	mutex_unlock(&fdtv->avc_mutex);
-
-	return ret;
-}
-
-int avc_register_remote_control(struct firedtv *fdtv)
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-	int ret;
-
-	mutex_lock(&fdtv->avc_mutex);
-
-	c->ctype   = AVC_CTYPE_NOTIFY;
-	c->subunit = AVC_SUBUNIT_TYPE_UNIT | 7;
-	c->opcode  = AVC_OPCODE_VENDOR;
-
-	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
-	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
-	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
-	c->operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
-	c->operand[4] = 0; /* padding */
-
-	fdtv->avc_data_length = 8;
-	ret = avc_write(fdtv);
-
-	/* FIXME: check response code? */
-
-	mutex_unlock(&fdtv->avc_mutex);
-
-	return ret;
-}
-
-void avc_remote_ctrl_work(struct work_struct *work)
-{
-	struct firedtv *fdtv =
-			container_of(work, struct firedtv, remote_ctrl_work);
-
-	/* Should it be rescheduled in failure cases? */
-	avc_register_remote_control(fdtv);
-}
-
-#if 0 /* FIXME: unused */
-int avc_tuner_host2ca(struct firedtv *fdtv)
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-	int ret;
-
-	mutex_lock(&fdtv->avc_mutex);
-
-	c->ctype   = AVC_CTYPE_CONTROL;
-	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
-	c->opcode  = AVC_OPCODE_VENDOR;
-
-	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
-	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
-	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
-	c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
-	c->operand[4] = 0; /* slot */
-	c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
-	clear_operands(c, 6, 8);
-
-	fdtv->avc_data_length = 12;
-	ret = avc_write(fdtv);
-
-	/* FIXME: check response code? */
-
-	mutex_unlock(&fdtv->avc_mutex);
-
-	return ret;
-}
-#endif
-
-static int get_ca_object_pos(struct avc_response_frame *r)
-{
-	int length = 1;
-
-	/* Check length of length field */
-	if (r->operand[7] & 0x80)
-		length = (r->operand[7] & 0x7f) + 1;
-	return length + 7;
-}
-
-static int get_ca_object_length(struct avc_response_frame *r)
-{
-#if 0 /* FIXME: unused */
-	int size = 0;
-	int i;
-
-	if (r->operand[7] & 0x80)
-		for (i = 0; i < (r->operand[7] & 0x7f); i++) {
-			size <<= 8;
-			size += r->operand[8 + i];
-		}
-#endif
-	return r->operand[7];
-}
-
-int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-	struct avc_response_frame *r = (void *)fdtv->avc_data;
-	int pos, ret;
-
-	mutex_lock(&fdtv->avc_mutex);
-
-	c->ctype   = AVC_CTYPE_STATUS;
-	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
-	c->opcode  = AVC_OPCODE_VENDOR;
-
-	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
-	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
-	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
-	c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
-	c->operand[4] = 0; /* slot */
-	c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
-	clear_operands(c, 6, LAST_OPERAND);
-
-	fdtv->avc_data_length = 12;
-	ret = avc_write(fdtv);
-	if (ret < 0)
-		goto out;
-
-	/* FIXME: check response code and validate response data */
-
-	pos = get_ca_object_pos(r);
-	app_info[0] = (EN50221_TAG_APP_INFO >> 16) & 0xff;
-	app_info[1] = (EN50221_TAG_APP_INFO >>  8) & 0xff;
-	app_info[2] = (EN50221_TAG_APP_INFO >>  0) & 0xff;
-	app_info[3] = 6 + r->operand[pos + 4];
-	app_info[4] = 0x01;
-	memcpy(&app_info[5], &r->operand[pos], 5 + r->operand[pos + 4]);
-	*len = app_info[3] + 4;
-out:
-	mutex_unlock(&fdtv->avc_mutex);
-
-	return ret;
-}
-
-int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-	struct avc_response_frame *r = (void *)fdtv->avc_data;
-	int i, pos, ret;
-
-	mutex_lock(&fdtv->avc_mutex);
-
-	c->ctype   = AVC_CTYPE_STATUS;
-	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
-	c->opcode  = AVC_OPCODE_VENDOR;
-
-	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
-	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
-	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
-	c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
-	c->operand[4] = 0; /* slot */
-	c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
-	clear_operands(c, 6, LAST_OPERAND);
-
-	fdtv->avc_data_length = 12;
-	ret = avc_write(fdtv);
-	if (ret < 0)
-		goto out;
-
-	/* FIXME: check response code and validate response data */
-
-	pos = get_ca_object_pos(r);
-	app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff;
-	app_info[1] = (EN50221_TAG_CA_INFO >>  8) & 0xff;
-	app_info[2] = (EN50221_TAG_CA_INFO >>  0) & 0xff;
-	if (num_fake_ca_system_ids == 0) {
-		app_info[3] = 2;
-		app_info[4] = r->operand[pos + 0];
-		app_info[5] = r->operand[pos + 1];
-	} else {
-		app_info[3] = num_fake_ca_system_ids * 2;
-		for (i = 0; i < num_fake_ca_system_ids; i++) {
-			app_info[4 + i * 2] =
-				(fake_ca_system_ids[i] >> 8) & 0xff;
-			app_info[5 + i * 2] = fake_ca_system_ids[i] & 0xff;
-		}
-	}
-	*len = app_info[3] + 4;
-out:
-	mutex_unlock(&fdtv->avc_mutex);
-
-	return ret;
-}
-
-int avc_ca_reset(struct firedtv *fdtv)
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-	int ret;
-
-	mutex_lock(&fdtv->avc_mutex);
-
-	c->ctype   = AVC_CTYPE_CONTROL;
-	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
-	c->opcode  = AVC_OPCODE_VENDOR;
-
-	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
-	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
-	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
-	c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
-	c->operand[4] = 0; /* slot */
-	c->operand[5] = SFE_VENDOR_TAG_CA_RESET; /* ca tag */
-	c->operand[6] = 0; /* more/last */
-	c->operand[7] = 1; /* length */
-	c->operand[8] = 0; /* force hardware reset */
-
-	fdtv->avc_data_length = 12;
-	ret = avc_write(fdtv);
-
-	/* FIXME: check response code? */
-
-	mutex_unlock(&fdtv->avc_mutex);
-
-	return ret;
-}
-
-int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-	struct avc_response_frame *r = (void *)fdtv->avc_data;
-	int list_management;
-	int program_info_length;
-	int pmt_cmd_id;
-	int read_pos;
-	int write_pos;
-	int es_info_length;
-	int crc32_csum;
-	int ret;
-
-	if (unlikely(avc_debug & AVC_DEBUG_APPLICATION_PMT))
-		debug_pmt(msg, length);
-
-	mutex_lock(&fdtv->avc_mutex);
-
-	c->ctype   = AVC_CTYPE_CONTROL;
-	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
-	c->opcode  = AVC_OPCODE_VENDOR;
-
-	if (msg[0] != EN50221_LIST_MANAGEMENT_ONLY) {
-		dev_info(fdtv->device, "forcing list_management to ONLY\n");
-		msg[0] = EN50221_LIST_MANAGEMENT_ONLY;
-	}
-	/* We take the cmd_id from the programme level only! */
-	list_management = msg[0];
-	program_info_length = ((msg[4] & 0x0f) << 8) + msg[5];
-	if (program_info_length > 0)
-		program_info_length--; /* Remove pmt_cmd_id */
-	pmt_cmd_id = msg[6];
-
-	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
-	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
-	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
-	c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
-	c->operand[4] = 0; /* slot */
-	c->operand[5] = SFE_VENDOR_TAG_CA_PMT; /* ca tag */
-	c->operand[6] = 0; /* more/last */
-	/* Use three bytes for length field in case length > 127 */
-	c->operand[10] = list_management;
-	c->operand[11] = 0x01; /* pmt_cmd=OK_descramble */
-
-	/* TS program map table */
-
-	c->operand[12] = 0x02; /* Table id=2 */
-	c->operand[13] = 0x80; /* Section syntax + length */
-
-	c->operand[15] = msg[1]; /* Program number */
-	c->operand[16] = msg[2];
-	c->operand[17] = msg[3]; /* Version number and current/next */
-	c->operand[18] = 0x00; /* Section number=0 */
-	c->operand[19] = 0x00; /* Last section number=0 */
-	c->operand[20] = 0x1f; /* PCR_PID=1FFF */
-	c->operand[21] = 0xff;
-	c->operand[22] = (program_info_length >> 8); /* Program info length */
-	c->operand[23] = (program_info_length & 0xff);
-
-	/* CA descriptors at programme level */
-	read_pos = 6;
-	write_pos = 24;
-	if (program_info_length > 0) {
-		pmt_cmd_id = msg[read_pos++];
-		if (pmt_cmd_id != 1 && pmt_cmd_id != 4)
-			dev_err(fdtv->device,
-				"invalid pmt_cmd_id %d\n", pmt_cmd_id);
-
-		memcpy(&c->operand[write_pos], &msg[read_pos],
-		       program_info_length);
-		read_pos += program_info_length;
-		write_pos += program_info_length;
-	}
-	while (read_pos < length) {
-		c->operand[write_pos++] = msg[read_pos++];
-		c->operand[write_pos++] = msg[read_pos++];
-		c->operand[write_pos++] = msg[read_pos++];
-		es_info_length =
-			((msg[read_pos] & 0x0f) << 8) + msg[read_pos + 1];
-		read_pos += 2;
-		if (es_info_length > 0)
-			es_info_length--; /* Remove pmt_cmd_id */
-		c->operand[write_pos++] = es_info_length >> 8;
-		c->operand[write_pos++] = es_info_length & 0xff;
-		if (es_info_length > 0) {
-			pmt_cmd_id = msg[read_pos++];
-			if (pmt_cmd_id != 1 && pmt_cmd_id != 4)
-				dev_err(fdtv->device, "invalid pmt_cmd_id %d "
-					"at stream level\n", pmt_cmd_id);
-
-			memcpy(&c->operand[write_pos], &msg[read_pos],
-			       es_info_length);
-			read_pos += es_info_length;
-			write_pos += es_info_length;
-		}
-	}
-	write_pos += 4; /* CRC */
-
-	c->operand[7] = 0x82;
-	c->operand[8] = (write_pos - 10) >> 8;
-	c->operand[9] = (write_pos - 10) & 0xff;
-	c->operand[14] = write_pos - 15;
-
-	crc32_csum = crc32_be(0, &c->operand[10], c->operand[12] - 1);
-	c->operand[write_pos - 4] = (crc32_csum >> 24) & 0xff;
-	c->operand[write_pos - 3] = (crc32_csum >> 16) & 0xff;
-	c->operand[write_pos - 2] = (crc32_csum >>  8) & 0xff;
-	c->operand[write_pos - 1] = (crc32_csum >>  0) & 0xff;
-	pad_operands(c, write_pos);
-
-	fdtv->avc_data_length = ALIGN(3 + write_pos, 4);
-	ret = avc_write(fdtv);
-	if (ret < 0)
-		goto out;
-
-	if (r->response != AVC_RESPONSE_ACCEPTED) {
-		dev_err(fdtv->device,
-			"CA PMT failed with response 0x%x\n", r->response);
-		ret = -EACCES;
-	}
-out:
-	mutex_unlock(&fdtv->avc_mutex);
-
-	return ret;
-}
-
-int avc_ca_get_time_date(struct firedtv *fdtv, int *interval)
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-	struct avc_response_frame *r = (void *)fdtv->avc_data;
-	int ret;
-
-	mutex_lock(&fdtv->avc_mutex);
-
-	c->ctype   = AVC_CTYPE_STATUS;
-	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
-	c->opcode  = AVC_OPCODE_VENDOR;
-
-	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
-	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
-	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
-	c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
-	c->operand[4] = 0; /* slot */
-	c->operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; /* ca tag */
-	clear_operands(c, 6, LAST_OPERAND);
-
-	fdtv->avc_data_length = 12;
-	ret = avc_write(fdtv);
-	if (ret < 0)
-		goto out;
-
-	/* FIXME: check response code and validate response data */
-
-	*interval = r->operand[get_ca_object_pos(r)];
-out:
-	mutex_unlock(&fdtv->avc_mutex);
-
-	return ret;
-}
-
-int avc_ca_enter_menu(struct firedtv *fdtv)
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-	int ret;
-
-	mutex_lock(&fdtv->avc_mutex);
-
-	c->ctype   = AVC_CTYPE_STATUS;
-	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
-	c->opcode  = AVC_OPCODE_VENDOR;
-
-	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
-	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
-	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
-	c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
-	c->operand[4] = 0; /* slot */
-	c->operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU;
-	clear_operands(c, 6, 8);
-
-	fdtv->avc_data_length = 12;
-	ret = avc_write(fdtv);
-
-	/* FIXME: check response code? */
-
-	mutex_unlock(&fdtv->avc_mutex);
-
-	return ret;
-}
-
-int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
-{
-	struct avc_command_frame *c = (void *)fdtv->avc_data;
-	struct avc_response_frame *r = (void *)fdtv->avc_data;
-	int ret;
-
-	mutex_lock(&fdtv->avc_mutex);
-
-	c->ctype   = AVC_CTYPE_STATUS;
-	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
-	c->opcode  = AVC_OPCODE_VENDOR;
-
-	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
-	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
-	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
-	c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
-	c->operand[4] = 0; /* slot */
-	c->operand[5] = SFE_VENDOR_TAG_CA_MMI;
-	clear_operands(c, 6, LAST_OPERAND);
-
-	fdtv->avc_data_length = 12;
-	ret = avc_write(fdtv);
-	if (ret < 0)
-		goto out;
-
-	/* FIXME: check response code and validate response data */
-
-	*len = get_ca_object_length(r);
-	memcpy(mmi_object, &r->operand[get_ca_object_pos(r)], *len);
-out:
-	mutex_unlock(&fdtv->avc_mutex);
-
-	return ret;
-}
-
-#define CMP_OUTPUT_PLUG_CONTROL_REG_0	0xfffff0000904ULL
-
-static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data)
-{
-	int ret;
-
-	ret = fdtv_read(fdtv, addr, data);
-	if (ret < 0)
-		dev_err(fdtv->device, "CMP: read I/O error\n");
-
-	return ret;
-}
-
-static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
-{
-	int ret;
-
-	ret = fdtv_lock(fdtv, addr, data);
-	if (ret < 0)
-		dev_err(fdtv->device, "CMP: lock I/O error\n");
-
-	return ret;
-}
-
-static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift)
-{
-	return (be32_to_cpu(opcr) >> shift) & mask;
-}
-
-static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift)
-{
-	*opcr &= ~cpu_to_be32(mask << shift);
-	*opcr |= cpu_to_be32((value & mask) << shift);
-}
-
-#define get_opcr_online(v)		get_opcr((v), 0x1, 31)
-#define get_opcr_p2p_connections(v)	get_opcr((v), 0x3f, 24)
-#define get_opcr_channel(v)		get_opcr((v), 0x3f, 16)
-
-#define set_opcr_p2p_connections(p, v)	set_opcr((p), (v), 0x3f, 24)
-#define set_opcr_channel(p, v)		set_opcr((p), (v), 0x3f, 16)
-#define set_opcr_data_rate(p, v)	set_opcr((p), (v), 0x3, 14)
-#define set_opcr_overhead_id(p, v)	set_opcr((p), (v), 0xf, 10)
-
-int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel)
-{
-	__be32 old_opcr, opcr[2];
-	u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
-	int attempts = 0;
-	int ret;
-
-	ret = cmp_read(fdtv, opcr_address, opcr);
-	if (ret < 0)
-		return ret;
-
-repeat:
-	if (!get_opcr_online(*opcr)) {
-		dev_err(fdtv->device, "CMP: output offline\n");
-		return -EBUSY;
-	}
-
-	old_opcr = *opcr;
-
-	if (get_opcr_p2p_connections(*opcr)) {
-		if (get_opcr_channel(*opcr) != channel) {
-			dev_err(fdtv->device, "CMP: cannot change channel\n");
-			return -EBUSY;
-		}
-		dev_info(fdtv->device, "CMP: overlaying connection\n");
-
-		/* We don't allocate isochronous resources. */
-	} else {
-		set_opcr_channel(opcr, channel);
-		set_opcr_data_rate(opcr, 2); /* S400 */
-
-		/* FIXME: this is for the worst case - optimize */
-		set_opcr_overhead_id(opcr, 0);
-
-		/* FIXME: allocate isochronous channel and bandwidth at IRM */
-	}
-
-	set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) + 1);
-
-	opcr[1] = *opcr;
-	opcr[0] = old_opcr;
-
-	ret = cmp_lock(fdtv, opcr_address, opcr);
-	if (ret < 0)
-		return ret;
-
-	if (old_opcr != *opcr) {
-		/*
-		 * FIXME: if old_opcr.P2P_Connections > 0,
-		 * deallocate isochronous channel and bandwidth at IRM
-		 */
-
-		if (++attempts < 6) /* arbitrary limit */
-			goto repeat;
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel)
-{
-	__be32 old_opcr, opcr[2];
-	u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
-	int attempts = 0;
-
-	if (cmp_read(fdtv, opcr_address, opcr) < 0)
-		return;
-
-repeat:
-	if (!get_opcr_online(*opcr) || !get_opcr_p2p_connections(*opcr) ||
-	    get_opcr_channel(*opcr) != channel) {
-		dev_err(fdtv->device, "CMP: no connection to break\n");
-		return;
-	}
-
-	old_opcr = *opcr;
-	set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) - 1);
-
-	opcr[1] = *opcr;
-	opcr[0] = old_opcr;
-
-	if (cmp_lock(fdtv, opcr_address, opcr) < 0)
-		return;
-
-	if (old_opcr != *opcr) {
-		/*
-		 * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last
-		 * owner, deallocate isochronous channel and bandwidth at IRM
-		 * if (...)
-		 *	fdtv->backend->dealloc_resources(fdtv, channel, bw);
-		 */
-
-		if (++attempts < 6) /* arbitrary limit */
-			goto repeat;
-	}
-}
diff --git a/drivers/media/dvb/firewire/firedtv-ci.c b/drivers/media/dvb/firewire/firedtv-ci.c
deleted file mode 100644
index e5ebdbf..0000000
--- a/drivers/media/dvb/firewire/firedtv-ci.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * FireDTV driver (formerly known as FireSAT)
- *
- * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
- * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
- *
- *	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.
- */
-
-#include <linux/device.h>
-#include <linux/dvb/ca.h>
-#include <linux/fs.h>
-#include <linux/module.h>
-
-#include <dvbdev.h>
-
-#include "firedtv.h"
-
-#define EN50221_TAG_APP_INFO_ENQUIRY	0x9f8020
-#define EN50221_TAG_CA_INFO_ENQUIRY	0x9f8030
-#define EN50221_TAG_CA_PMT		0x9f8032
-#define EN50221_TAG_ENTER_MENU		0x9f8022
-
-static int fdtv_ca_ready(struct firedtv_tuner_status *stat)
-{
-	return stat->ca_initialization_status	== 1 &&
-	       stat->ca_error_flag		== 0 &&
-	       stat->ca_dvb_flag		== 1 &&
-	       stat->ca_module_present_status	== 1;
-}
-
-static int fdtv_get_ca_flags(struct firedtv_tuner_status *stat)
-{
-	int flags = 0;
-
-	if (stat->ca_module_present_status == 1)
-		flags |= CA_CI_MODULE_PRESENT;
-	if (stat->ca_initialization_status == 1 &&
-	    stat->ca_error_flag            == 0 &&
-	    stat->ca_dvb_flag              == 1)
-		flags |= CA_CI_MODULE_READY;
-	return flags;
-}
-
-static int fdtv_ca_get_caps(void *arg)
-{
-	struct ca_caps *cap = arg;
-
-	cap->slot_num = 1;
-	cap->slot_type = CA_CI;
-	cap->descr_num = 1;
-	cap->descr_type = CA_ECD;
-	return 0;
-}
-
-static int fdtv_ca_get_slot_info(struct firedtv *fdtv, void *arg)
-{
-	struct firedtv_tuner_status stat;
-	struct ca_slot_info *slot = arg;
-	int err;
-
-	err = avc_tuner_status(fdtv, &stat);
-	if (err)
-		return err;
-
-	if (slot->num != 0)
-		return -EACCES;
-
-	slot->type = CA_CI;
-	slot->flags = fdtv_get_ca_flags(&stat);
-	return 0;
-}
-
-static int fdtv_ca_app_info(struct firedtv *fdtv, void *arg)
-{
-	struct ca_msg *reply = arg;
-
-	return avc_ca_app_info(fdtv, reply->msg, &reply->length);
-}
-
-static int fdtv_ca_info(struct firedtv *fdtv, void *arg)
-{
-	struct ca_msg *reply = arg;
-
-	return avc_ca_info(fdtv, reply->msg, &reply->length);
-}
-
-static int fdtv_ca_get_mmi(struct firedtv *fdtv, void *arg)
-{
-	struct ca_msg *reply = arg;
-
-	return avc_ca_get_mmi(fdtv, reply->msg, &reply->length);
-}
-
-static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg)
-{
-	struct firedtv_tuner_status stat;
-	int err;
-
-	switch (fdtv->ca_last_command) {
-	case EN50221_TAG_APP_INFO_ENQUIRY:
-		err = fdtv_ca_app_info(fdtv, arg);
-		break;
-	case EN50221_TAG_CA_INFO_ENQUIRY:
-		err = fdtv_ca_info(fdtv, arg);
-		break;
-	default:
-		err = avc_tuner_status(fdtv, &stat);
-		if (err)
-			break;
-		if (stat.ca_mmi == 1)
-			err = fdtv_ca_get_mmi(fdtv, arg);
-		else {
-			dev_info(fdtv->device, "unhandled CA message 0x%08x\n",
-				 fdtv->ca_last_command);
-			err = -EACCES;
-		}
-	}
-	fdtv->ca_last_command = 0;
-	return err;
-}
-
-static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg)
-{
-	struct ca_msg *msg = arg;
-	int data_pos;
-	int data_length;
-	int i;
-
-	data_pos = 4;
-	if (msg->msg[3] & 0x80) {
-		data_length = 0;
-		for (i = 0; i < (msg->msg[3] & 0x7f); i++)
-			data_length = (data_length << 8) + msg->msg[data_pos++];
-	} else {
-		data_length = msg->msg[3];
-	}
-
-	return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length);
-}
-
-static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg)
-{
-	struct ca_msg *msg = arg;
-	int err;
-
-	/* Do we need a semaphore for this? */
-	fdtv->ca_last_command =
-		(msg->msg[0] << 16) + (msg->msg[1] << 8) + msg->msg[2];
-	switch (fdtv->ca_last_command) {
-	case EN50221_TAG_CA_PMT:
-		err = fdtv_ca_pmt(fdtv, arg);
-		break;
-	case EN50221_TAG_APP_INFO_ENQUIRY:
-		/* handled in ca_get_msg */
-		err = 0;
-		break;
-	case EN50221_TAG_CA_INFO_ENQUIRY:
-		/* handled in ca_get_msg */
-		err = 0;
-		break;
-	case EN50221_TAG_ENTER_MENU:
-		err = avc_ca_enter_menu(fdtv);
-		break;
-	default:
-		dev_err(fdtv->device, "unhandled CA message 0x%08x\n",
-			fdtv->ca_last_command);
-		err = -EACCES;
-	}
-	return err;
-}
-
-static int fdtv_ca_ioctl(struct file *file, unsigned int cmd, void *arg)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct firedtv *fdtv = dvbdev->priv;
-	struct firedtv_tuner_status stat;
-	int err;
-
-	switch (cmd) {
-	case CA_RESET:
-		err = avc_ca_reset(fdtv);
-		break;
-	case CA_GET_CAP:
-		err = fdtv_ca_get_caps(arg);
-		break;
-	case CA_GET_SLOT_INFO:
-		err = fdtv_ca_get_slot_info(fdtv, arg);
-		break;
-	case CA_GET_MSG:
-		err = fdtv_ca_get_msg(fdtv, arg);
-		break;
-	case CA_SEND_MSG:
-		err = fdtv_ca_send_msg(fdtv, arg);
-		break;
-	default:
-		dev_info(fdtv->device, "unhandled CA ioctl %u\n", cmd);
-		err = -EOPNOTSUPP;
-	}
-
-	/* FIXME Is this necessary? */
-	avc_tuner_status(fdtv, &stat);
-
-	return err;
-}
-
-static unsigned int fdtv_ca_io_poll(struct file *file, poll_table *wait)
-{
-	return POLLIN;
-}
-
-static const struct file_operations fdtv_ca_fops = {
-	.owner		= THIS_MODULE,
-	.unlocked_ioctl	= dvb_generic_ioctl,
-	.open		= dvb_generic_open,
-	.release	= dvb_generic_release,
-	.poll		= fdtv_ca_io_poll,
-	.llseek		= noop_llseek,
-};
-
-static struct dvb_device fdtv_ca = {
-	.users		= 1,
-	.readers	= 1,
-	.writers	= 1,
-	.fops		= &fdtv_ca_fops,
-	.kernel_ioctl	= fdtv_ca_ioctl,
-};
-
-int fdtv_ca_register(struct firedtv *fdtv)
-{
-	struct firedtv_tuner_status stat;
-	int err;
-
-	if (avc_tuner_status(fdtv, &stat))
-		return -EINVAL;
-
-	if (!fdtv_ca_ready(&stat))
-		return -EFAULT;
-
-	err = dvb_register_device(&fdtv->adapter, &fdtv->cadev,
-				  &fdtv_ca, fdtv, DVB_DEVICE_CA);
-
-	if (stat.ca_application_info == 0)
-		dev_err(fdtv->device, "CaApplicationInfo is not set\n");
-	if (stat.ca_date_time_request == 1)
-		avc_ca_get_time_date(fdtv, &fdtv->ca_time_interval);
-
-	return err;
-}
-
-void fdtv_ca_release(struct firedtv *fdtv)
-{
-	if (fdtv->cadev)
-		dvb_unregister_device(fdtv->cadev);
-}
diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c
deleted file mode 100644
index eb7496e..0000000
--- a/drivers/media/dvb/firewire/firedtv-dvb.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * FireDTV driver (formerly known as FireSAT)
- *
- * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
- * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
- *
- *	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.
- */
-
-#include <linux/bitops.h>
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/types.h>
-
-#include <dmxdev.h>
-#include <dvb_demux.h>
-#include <dvbdev.h>
-#include <dvb_frontend.h>
-
-#include "firedtv.h"
-
-static int alloc_channel(struct firedtv *fdtv)
-{
-	int i;
-
-	for (i = 0; i < 16; i++)
-		if (!__test_and_set_bit(i, &fdtv->channel_active))
-			break;
-	return i;
-}
-
-static void collect_channels(struct firedtv *fdtv, int *pidc, u16 pid[])
-{
-	int i, n;
-
-	for (i = 0, n = 0; i < 16; i++)
-		if (test_bit(i, &fdtv->channel_active))
-			pid[n++] = fdtv->channel_pid[i];
-	*pidc = n;
-}
-
-static inline void dealloc_channel(struct firedtv *fdtv, int i)
-{
-	__clear_bit(i, &fdtv->channel_active);
-}
-
-int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct firedtv *fdtv = dvbdmxfeed->demux->priv;
-	int pidc, c, ret;
-	u16 pids[16];
-
-	switch (dvbdmxfeed->type) {
-	case DMX_TYPE_TS:
-	case DMX_TYPE_SEC:
-		break;
-	default:
-		dev_err(fdtv->device, "can't start dmx feed: invalid type %u\n",
-			dvbdmxfeed->type);
-		return -EINVAL;
-	}
-
-	if (mutex_lock_interruptible(&fdtv->demux_mutex))
-		return -EINTR;
-
-	if (dvbdmxfeed->type == DMX_TYPE_TS) {
-		switch (dvbdmxfeed->pes_type) {
-		case DMX_TS_PES_VIDEO:
-		case DMX_TS_PES_AUDIO:
-		case DMX_TS_PES_TELETEXT:
-		case DMX_TS_PES_PCR:
-		case DMX_TS_PES_OTHER:
-			c = alloc_channel(fdtv);
-			break;
-		default:
-			dev_err(fdtv->device,
-				"can't start dmx feed: invalid pes type %u\n",
-				dvbdmxfeed->pes_type);
-			ret = -EINVAL;
-			goto out;
-		}
-	} else {
-		c = alloc_channel(fdtv);
-	}
-
-	if (c > 15) {
-		dev_err(fdtv->device, "can't start dmx feed: busy\n");
-		ret = -EBUSY;
-		goto out;
-	}
-
-	dvbdmxfeed->priv = (typeof(dvbdmxfeed->priv))(unsigned long)c;
-	fdtv->channel_pid[c] = dvbdmxfeed->pid;
-	collect_channels(fdtv, &pidc, pids);
-
-	if (dvbdmxfeed->pid == 8192) {
-		ret = avc_tuner_get_ts(fdtv);
-		if (ret) {
-			dealloc_channel(fdtv, c);
-			dev_err(fdtv->device, "can't get TS\n");
-			goto out;
-		}
-	} else {
-		ret = avc_tuner_set_pids(fdtv, pidc, pids);
-		if (ret) {
-			dealloc_channel(fdtv, c);
-			dev_err(fdtv->device, "can't set PIDs\n");
-			goto out;
-		}
-	}
-out:
-	mutex_unlock(&fdtv->demux_mutex);
-
-	return ret;
-}
-
-int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *demux = dvbdmxfeed->demux;
-	struct firedtv *fdtv = demux->priv;
-	int pidc, c, ret;
-	u16 pids[16];
-
-	if (dvbdmxfeed->type == DMX_TYPE_TS &&
-	    !((dvbdmxfeed->ts_type & TS_PACKET) &&
-	      (demux->dmx.frontend->source != DMX_MEMORY_FE))) {
-
-		if (dvbdmxfeed->ts_type & TS_DECODER) {
-			if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER ||
-			    !demux->pesfilter[dvbdmxfeed->pes_type])
-				return -EINVAL;
-
-			demux->pids[dvbdmxfeed->pes_type] |= 0x8000;
-			demux->pesfilter[dvbdmxfeed->pes_type] = NULL;
-		}
-
-		if (!(dvbdmxfeed->ts_type & TS_DECODER &&
-		      dvbdmxfeed->pes_type < DMX_TS_PES_OTHER))
-			return 0;
-	}
-
-	if (mutex_lock_interruptible(&fdtv->demux_mutex))
-		return -EINTR;
-
-	c = (unsigned long)dvbdmxfeed->priv;
-	dealloc_channel(fdtv, c);
-	collect_channels(fdtv, &pidc, pids);
-
-	ret = avc_tuner_set_pids(fdtv, pidc, pids);
-
-	mutex_unlock(&fdtv->demux_mutex);
-
-	return ret;
-}
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-int fdtv_dvb_register(struct firedtv *fdtv, const char *name)
-{
-	int err;
-
-	err = dvb_register_adapter(&fdtv->adapter, name,
-				   THIS_MODULE, fdtv->device, adapter_nr);
-	if (err < 0)
-		goto fail_log;
-
-	/*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/
-	fdtv->demux.dmx.capabilities = 0;
-
-	fdtv->demux.priv	= fdtv;
-	fdtv->demux.filternum	= 16;
-	fdtv->demux.feednum	= 16;
-	fdtv->demux.start_feed	= fdtv_start_feed;
-	fdtv->demux.stop_feed	= fdtv_stop_feed;
-	fdtv->demux.write_to_decoder = NULL;
-
-	err = dvb_dmx_init(&fdtv->demux);
-	if (err)
-		goto fail_unreg_adapter;
-
-	fdtv->dmxdev.filternum    = 16;
-	fdtv->dmxdev.demux        = &fdtv->demux.dmx;
-	fdtv->dmxdev.capabilities = 0;
-
-	err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter);
-	if (err)
-		goto fail_dmx_release;
-
-	fdtv->frontend.source = DMX_FRONTEND_0;
-
-	err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, &fdtv->frontend);
-	if (err)
-		goto fail_dmxdev_release;
-
-	err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx,
-					       &fdtv->frontend);
-	if (err)
-		goto fail_rem_frontend;
-
-	err = dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx);
-	if (err)
-		goto fail_disconnect_frontend;
-
-	fdtv_frontend_init(fdtv, name);
-	err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe);
-	if (err)
-		goto fail_net_release;
-
-	err = fdtv_ca_register(fdtv);
-	if (err)
-		dev_info(fdtv->device,
-			 "Conditional Access Module not enabled\n");
-	return 0;
-
-fail_net_release:
-	dvb_net_release(&fdtv->dvbnet);
-fail_disconnect_frontend:
-	fdtv->demux.dmx.close(&fdtv->demux.dmx);
-fail_rem_frontend:
-	fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
-fail_dmxdev_release:
-	dvb_dmxdev_release(&fdtv->dmxdev);
-fail_dmx_release:
-	dvb_dmx_release(&fdtv->demux);
-fail_unreg_adapter:
-	dvb_unregister_adapter(&fdtv->adapter);
-fail_log:
-	dev_err(fdtv->device, "DVB initialization failed\n");
-	return err;
-}
-
-void fdtv_dvb_unregister(struct firedtv *fdtv)
-{
-	fdtv_ca_release(fdtv);
-	dvb_unregister_frontend(&fdtv->fe);
-	dvb_net_release(&fdtv->dvbnet);
-	fdtv->demux.dmx.close(&fdtv->demux.dmx);
-	fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
-	dvb_dmxdev_release(&fdtv->dmxdev);
-	dvb_dmx_release(&fdtv->demux);
-	dvb_unregister_adapter(&fdtv->adapter);
-}
diff --git a/drivers/media/dvb/firewire/firedtv-fe.c b/drivers/media/dvb/firewire/firedtv-fe.c
deleted file mode 100644
index 6fe9793..0000000
--- a/drivers/media/dvb/firewire/firedtv-fe.c
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * FireDTV driver (formerly known as FireSAT)
- *
- * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
- * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
- *
- *	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.
- */
-
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-
-#include <dvb_frontend.h>
-
-#include "firedtv.h"
-
-static int fdtv_dvb_init(struct dvb_frontend *fe)
-{
-	struct firedtv *fdtv = fe->sec_priv;
-	int err;
-
-	/* FIXME - allocate free channel at IRM */
-	fdtv->isochannel = fdtv->adapter.num;
-
-	err = cmp_establish_pp_connection(fdtv, fdtv->subunit,
-					  fdtv->isochannel);
-	if (err) {
-		dev_err(fdtv->device,
-			"could not establish point to point connection\n");
-		return err;
-	}
-
-	return fdtv_start_iso(fdtv);
-}
-
-static int fdtv_sleep(struct dvb_frontend *fe)
-{
-	struct firedtv *fdtv = fe->sec_priv;
-
-	fdtv_stop_iso(fdtv);
-	cmp_break_pp_connection(fdtv, fdtv->subunit, fdtv->isochannel);
-	fdtv->isochannel = -1;
-	return 0;
-}
-
-#define LNBCONTROL_DONTCARE 0xff
-
-static int fdtv_diseqc_send_master_cmd(struct dvb_frontend *fe,
-				       struct dvb_diseqc_master_cmd *cmd)
-{
-	struct firedtv *fdtv = fe->sec_priv;
-
-	return avc_lnb_control(fdtv, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE,
-			       LNBCONTROL_DONTCARE, 1, cmd);
-}
-
-static int fdtv_diseqc_send_burst(struct dvb_frontend *fe,
-				  fe_sec_mini_cmd_t minicmd)
-{
-	return 0;
-}
-
-static int fdtv_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
-{
-	struct firedtv *fdtv = fe->sec_priv;
-
-	fdtv->tone = tone;
-	return 0;
-}
-
-static int fdtv_set_voltage(struct dvb_frontend *fe,
-			    fe_sec_voltage_t voltage)
-{
-	struct firedtv *fdtv = fe->sec_priv;
-
-	fdtv->voltage = voltage;
-	return 0;
-}
-
-static int fdtv_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct firedtv *fdtv = fe->sec_priv;
-	struct firedtv_tuner_status stat;
-
-	if (avc_tuner_status(fdtv, &stat))
-		return -EINVAL;
-
-	if (stat.no_rf)
-		*status = 0;
-	else
-		*status = FE_HAS_SIGNAL | FE_HAS_VITERBI | FE_HAS_SYNC |
-			  FE_HAS_CARRIER | FE_HAS_LOCK;
-	return 0;
-}
-
-static int fdtv_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct firedtv *fdtv = fe->sec_priv;
-	struct firedtv_tuner_status stat;
-
-	if (avc_tuner_status(fdtv, &stat))
-		return -EINVAL;
-
-	*ber = stat.ber;
-	return 0;
-}
-
-static int fdtv_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct firedtv *fdtv = fe->sec_priv;
-	struct firedtv_tuner_status stat;
-
-	if (avc_tuner_status(fdtv, &stat))
-		return -EINVAL;
-
-	*strength = stat.signal_strength << 8;
-	return 0;
-}
-
-static int fdtv_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct firedtv *fdtv = fe->sec_priv;
-	struct firedtv_tuner_status stat;
-
-	if (avc_tuner_status(fdtv, &stat))
-		return -EINVAL;
-
-	/* C/N[dB] = -10 * log10(snr / 65535) */
-	*snr = stat.carrier_noise_ratio * 257;
-	return 0;
-}
-
-static int fdtv_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	return -EOPNOTSUPP;
-}
-
-static int fdtv_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct firedtv *fdtv = fe->sec_priv;
-
-	return avc_tuner_dsd(fdtv, p);
-}
-
-void fdtv_frontend_init(struct firedtv *fdtv, const char *name)
-{
-	struct dvb_frontend_ops *ops = &fdtv->fe.ops;
-	struct dvb_frontend_info *fi = &ops->info;
-
-	ops->init			= fdtv_dvb_init;
-	ops->sleep			= fdtv_sleep;
-
-	ops->set_frontend		= fdtv_set_frontend;
-
-	ops->read_status		= fdtv_read_status;
-	ops->read_ber			= fdtv_read_ber;
-	ops->read_signal_strength	= fdtv_read_signal_strength;
-	ops->read_snr			= fdtv_read_snr;
-	ops->read_ucblocks		= fdtv_read_uncorrected_blocks;
-
-	ops->diseqc_send_master_cmd 	= fdtv_diseqc_send_master_cmd;
-	ops->diseqc_send_burst		= fdtv_diseqc_send_burst;
-	ops->set_tone			= fdtv_set_tone;
-	ops->set_voltage		= fdtv_set_voltage;
-
-	switch (fdtv->type) {
-	case FIREDTV_DVB_S:
-		ops->delsys[0]		= SYS_DVBS;
-
-		fi->frequency_min	= 950000;
-		fi->frequency_max	= 2150000;
-		fi->frequency_stepsize	= 125;
-		fi->symbol_rate_min	= 1000000;
-		fi->symbol_rate_max	= 40000000;
-
-		fi->caps		= FE_CAN_INVERSION_AUTO |
-					  FE_CAN_FEC_1_2	|
-					  FE_CAN_FEC_2_3	|
-					  FE_CAN_FEC_3_4	|
-					  FE_CAN_FEC_5_6	|
-					  FE_CAN_FEC_7_8	|
-					  FE_CAN_FEC_AUTO	|
-					  FE_CAN_QPSK;
-		break;
-
-	case FIREDTV_DVB_S2:
-		ops->delsys[0]		= SYS_DVBS;
-		ops->delsys[1]		= SYS_DVBS2;
-
-		fi->frequency_min	= 950000;
-		fi->frequency_max	= 2150000;
-		fi->frequency_stepsize	= 125;
-		fi->symbol_rate_min	= 1000000;
-		fi->symbol_rate_max	= 40000000;
-
-		fi->caps		= FE_CAN_INVERSION_AUTO |
-					  FE_CAN_FEC_1_2        |
-					  FE_CAN_FEC_2_3        |
-					  FE_CAN_FEC_3_4        |
-					  FE_CAN_FEC_5_6        |
-					  FE_CAN_FEC_7_8        |
-					  FE_CAN_FEC_AUTO       |
-					  FE_CAN_QPSK           |
-					  FE_CAN_2G_MODULATION;
-		break;
-
-	case FIREDTV_DVB_C:
-		ops->delsys[0]		= SYS_DVBC_ANNEX_A;
-
-		fi->frequency_min	= 47000000;
-		fi->frequency_max	= 866000000;
-		fi->frequency_stepsize	= 62500;
-		fi->symbol_rate_min	= 870000;
-		fi->symbol_rate_max	= 6900000;
-
-		fi->caps 		= FE_CAN_INVERSION_AUTO |
-					  FE_CAN_QAM_16		|
-					  FE_CAN_QAM_32		|
-					  FE_CAN_QAM_64		|
-					  FE_CAN_QAM_128	|
-					  FE_CAN_QAM_256	|
-					  FE_CAN_QAM_AUTO;
-		break;
-
-	case FIREDTV_DVB_T:
-		ops->delsys[0]		= SYS_DVBT;
-
-		fi->frequency_min	= 49000000;
-		fi->frequency_max	= 861000000;
-		fi->frequency_stepsize	= 62500;
-
-		fi->caps 		= FE_CAN_INVERSION_AUTO		|
-					  FE_CAN_FEC_2_3		|
-					  FE_CAN_TRANSMISSION_MODE_AUTO |
-					  FE_CAN_GUARD_INTERVAL_AUTO	|
-					  FE_CAN_HIERARCHY_AUTO;
-		break;
-
-	default:
-		dev_err(fdtv->device, "no frontend for model type %d\n",
-			fdtv->type);
-	}
-	strcpy(fi->name, name);
-
-	fdtv->fe.dvb = &fdtv->adapter;
-	fdtv->fe.sec_priv = fdtv;
-}
diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c
deleted file mode 100644
index e24ec53..0000000
--- a/drivers/media/dvb/firewire/firedtv-fw.c
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * FireDTV driver -- firewire I/O backend
- */
-
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/firewire.h>
-#include <linux/firewire-constants.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/mod_devicetable.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-
-#include <asm/page.h>
-
-#include <dvb_demux.h>
-
-#include "firedtv.h"
-
-static LIST_HEAD(node_list);
-static DEFINE_SPINLOCK(node_list_lock);
-
-static inline struct fw_device *device_of(struct firedtv *fdtv)
-{
-	return fw_device(fdtv->device->parent);
-}
-
-static int node_req(struct firedtv *fdtv, u64 addr, void *data, size_t len,
-		    int tcode)
-{
-	struct fw_device *device = device_of(fdtv);
-	int rcode, generation = device->generation;
-
-	smp_rmb(); /* node_id vs. generation */
-
-	rcode = fw_run_transaction(device->card, tcode, device->node_id,
-			generation, device->max_speed, addr, data, len);
-
-	return rcode != RCODE_COMPLETE ? -EIO : 0;
-}
-
-int fdtv_lock(struct firedtv *fdtv, u64 addr, void *data)
-{
-	return node_req(fdtv, addr, data, 8, TCODE_LOCK_COMPARE_SWAP);
-}
-
-int fdtv_read(struct firedtv *fdtv, u64 addr, void *data)
-{
-	return node_req(fdtv, addr, data, 4, TCODE_READ_QUADLET_REQUEST);
-}
-
-int fdtv_write(struct firedtv *fdtv, u64 addr, void *data, size_t len)
-{
-	return node_req(fdtv, addr, data, len, TCODE_WRITE_BLOCK_REQUEST);
-}
-
-#define ISO_HEADER_SIZE			4
-#define CIP_HEADER_SIZE			8
-#define MPEG2_TS_HEADER_SIZE		4
-#define MPEG2_TS_SOURCE_PACKET_SIZE	(4 + 188)
-
-#define MAX_PACKET_SIZE		1024  /* 776, rounded up to 2^n */
-#define PACKETS_PER_PAGE	(PAGE_SIZE / MAX_PACKET_SIZE)
-#define N_PACKETS		64    /* buffer size */
-#define N_PAGES			DIV_ROUND_UP(N_PACKETS, PACKETS_PER_PAGE)
-#define IRQ_INTERVAL		16
-
-struct fdtv_ir_context {
-	struct fw_iso_context *context;
-	struct fw_iso_buffer buffer;
-	int interrupt_packet;
-	int current_packet;
-	char *pages[N_PAGES];
-};
-
-static int queue_iso(struct fdtv_ir_context *ctx, int index)
-{
-	struct fw_iso_packet p;
-
-	p.payload_length = MAX_PACKET_SIZE;
-	p.interrupt = !(++ctx->interrupt_packet & (IRQ_INTERVAL - 1));
-	p.skip = 0;
-	p.header_length = ISO_HEADER_SIZE;
-
-	return fw_iso_context_queue(ctx->context, &p, &ctx->buffer,
-				    index * MAX_PACKET_SIZE);
-}
-
-static void handle_iso(struct fw_iso_context *context, u32 cycle,
-		       size_t header_length, void *header, void *data)
-{
-	struct firedtv *fdtv = data;
-	struct fdtv_ir_context *ctx = fdtv->ir_context;
-	__be32 *h, *h_end;
-	int length, err, i = ctx->current_packet;
-	char *p, *p_end;
-
-	for (h = header, h_end = h + header_length / 4; h < h_end; h++) {
-		length = be32_to_cpup(h) >> 16;
-		if (unlikely(length > MAX_PACKET_SIZE)) {
-			dev_err(fdtv->device, "length = %d\n", length);
-			length = MAX_PACKET_SIZE;
-		}
-
-		p = ctx->pages[i / PACKETS_PER_PAGE]
-				+ (i % PACKETS_PER_PAGE) * MAX_PACKET_SIZE;
-		p_end = p + length;
-
-		for (p += CIP_HEADER_SIZE + MPEG2_TS_HEADER_SIZE; p < p_end;
-		     p += MPEG2_TS_SOURCE_PACKET_SIZE)
-			dvb_dmx_swfilter_packets(&fdtv->demux, p, 1);
-
-		err = queue_iso(ctx, i);
-		if (unlikely(err))
-			dev_err(fdtv->device, "requeue failed\n");
-
-		i = (i + 1) & (N_PACKETS - 1);
-	}
-	fw_iso_context_queue_flush(ctx->context);
-	ctx->current_packet = i;
-}
-
-int fdtv_start_iso(struct firedtv *fdtv)
-{
-	struct fdtv_ir_context *ctx;
-	struct fw_device *device = device_of(fdtv);
-	int i, err;
-
-	ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
-	if (!ctx)
-		return -ENOMEM;
-
-	ctx->context = fw_iso_context_create(device->card,
-			FW_ISO_CONTEXT_RECEIVE, fdtv->isochannel,
-			device->max_speed, ISO_HEADER_SIZE, handle_iso, fdtv);
-	if (IS_ERR(ctx->context)) {
-		err = PTR_ERR(ctx->context);
-		goto fail_free;
-	}
-
-	err = fw_iso_buffer_init(&ctx->buffer, device->card,
-				 N_PAGES, DMA_FROM_DEVICE);
-	if (err)
-		goto fail_context_destroy;
-
-	ctx->interrupt_packet = 0;
-	ctx->current_packet = 0;
-
-	for (i = 0; i < N_PAGES; i++)
-		ctx->pages[i] = page_address(ctx->buffer.pages[i]);
-
-	for (i = 0; i < N_PACKETS; i++) {
-		err = queue_iso(ctx, i);
-		if (err)
-			goto fail;
-	}
-
-	err = fw_iso_context_start(ctx->context, -1, 0,
-				   FW_ISO_CONTEXT_MATCH_ALL_TAGS);
-	if (err)
-		goto fail;
-
-	fdtv->ir_context = ctx;
-
-	return 0;
-fail:
-	fw_iso_buffer_destroy(&ctx->buffer, device->card);
-fail_context_destroy:
-	fw_iso_context_destroy(ctx->context);
-fail_free:
-	kfree(ctx);
-
-	return err;
-}
-
-void fdtv_stop_iso(struct firedtv *fdtv)
-{
-	struct fdtv_ir_context *ctx = fdtv->ir_context;
-
-	fw_iso_context_stop(ctx->context);
-	fw_iso_buffer_destroy(&ctx->buffer, device_of(fdtv)->card);
-	fw_iso_context_destroy(ctx->context);
-	kfree(ctx);
-}
-
-static void handle_fcp(struct fw_card *card, struct fw_request *request,
-		       int tcode, int destination, int source, int generation,
-		       unsigned long long offset, void *payload, size_t length,
-		       void *callback_data)
-{
-	struct firedtv *f, *fdtv = NULL;
-	struct fw_device *device;
-	unsigned long flags;
-	int su;
-
-	if (length < 2 || (((u8 *)payload)[0] & 0xf0) != 0)
-		return;
-
-	su = ((u8 *)payload)[1] & 0x7;
-
-	spin_lock_irqsave(&node_list_lock, flags);
-	list_for_each_entry(f, &node_list, list) {
-		device = device_of(f);
-		if (device->generation != generation)
-			continue;
-
-		smp_rmb(); /* node_id vs. generation */
-
-		if (device->card == card &&
-		    device->node_id == source &&
-		    (f->subunit == su || (f->subunit == 0 && su == 0x7))) {
-			fdtv = f;
-			break;
-		}
-	}
-	spin_unlock_irqrestore(&node_list_lock, flags);
-
-	if (fdtv)
-		avc_recv(fdtv, payload, length);
-}
-
-static struct fw_address_handler fcp_handler = {
-	.length           = CSR_FCP_END - CSR_FCP_RESPONSE,
-	.address_callback = handle_fcp,
-};
-
-static const struct fw_address_region fcp_region = {
-	.start	= CSR_REGISTER_BASE + CSR_FCP_RESPONSE,
-	.end	= CSR_REGISTER_BASE + CSR_FCP_END,
-};
-
-static const char * const model_names[] = {
-	[FIREDTV_UNKNOWN] = "unknown type",
-	[FIREDTV_DVB_S]   = "FireDTV S/CI",
-	[FIREDTV_DVB_C]   = "FireDTV C/CI",
-	[FIREDTV_DVB_T]   = "FireDTV T/CI",
-	[FIREDTV_DVB_S2]  = "FireDTV S2  ",
-};
-
-/* Adjust the template string if models with longer names appear. */
-#define MAX_MODEL_NAME_LEN sizeof("FireDTV ????")
-
-static int node_probe(struct device *dev)
-{
-	struct firedtv *fdtv;
-	char name[MAX_MODEL_NAME_LEN];
-	int name_len, i, err;
-
-	fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL);
-	if (!fdtv)
-		return -ENOMEM;
-
-	dev_set_drvdata(dev, fdtv);
-	fdtv->device		= dev;
-	fdtv->isochannel	= -1;
-	fdtv->voltage		= 0xff;
-	fdtv->tone		= 0xff;
-
-	mutex_init(&fdtv->avc_mutex);
-	init_waitqueue_head(&fdtv->avc_wait);
-	mutex_init(&fdtv->demux_mutex);
-	INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work);
-
-	name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL,
-				 name, sizeof(name));
-	for (i = ARRAY_SIZE(model_names); --i; )
-		if (strlen(model_names[i]) <= name_len &&
-		    strncmp(name, model_names[i], name_len) == 0)
-			break;
-	fdtv->type = i;
-
-	err = fdtv_register_rc(fdtv, dev);
-	if (err)
-		goto fail_free;
-
-	spin_lock_irq(&node_list_lock);
-	list_add_tail(&fdtv->list, &node_list);
-	spin_unlock_irq(&node_list_lock);
-
-	err = avc_identify_subunit(fdtv);
-	if (err)
-		goto fail;
-
-	err = fdtv_dvb_register(fdtv, model_names[fdtv->type]);
-	if (err)
-		goto fail;
-
-	avc_register_remote_control(fdtv);
-
-	return 0;
-fail:
-	spin_lock_irq(&node_list_lock);
-	list_del(&fdtv->list);
-	spin_unlock_irq(&node_list_lock);
-	fdtv_unregister_rc(fdtv);
-fail_free:
-	kfree(fdtv);
-
-	return err;
-}
-
-static int node_remove(struct device *dev)
-{
-	struct firedtv *fdtv = dev_get_drvdata(dev);
-
-	fdtv_dvb_unregister(fdtv);
-
-	spin_lock_irq(&node_list_lock);
-	list_del(&fdtv->list);
-	spin_unlock_irq(&node_list_lock);
-
-	fdtv_unregister_rc(fdtv);
-
-	kfree(fdtv);
-	return 0;
-}
-
-static void node_update(struct fw_unit *unit)
-{
-	struct firedtv *fdtv = dev_get_drvdata(&unit->device);
-
-	if (fdtv->isochannel >= 0)
-		cmp_establish_pp_connection(fdtv, fdtv->subunit,
-					    fdtv->isochannel);
-}
-
-#define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \
-		     IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION)
-
-#define DIGITAL_EVERYWHERE_OUI	0x001287
-#define AVC_UNIT_SPEC_ID_ENTRY	0x00a02d
-#define AVC_SW_VERSION_ENTRY	0x010001
-
-static const struct ieee1394_device_id fdtv_id_table[] = {
-	{
-		/* FloppyDTV S/CI and FloppyDTV S2 */
-		.match_flags	= MATCH_FLAGS,
-		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
-		.model_id	= 0x000024,
-		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
-		.version	= AVC_SW_VERSION_ENTRY,
-	}, {
-		/* FloppyDTV T/CI */
-		.match_flags	= MATCH_FLAGS,
-		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
-		.model_id	= 0x000025,
-		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
-		.version	= AVC_SW_VERSION_ENTRY,
-	}, {
-		/* FloppyDTV C/CI */
-		.match_flags	= MATCH_FLAGS,
-		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
-		.model_id	= 0x000026,
-		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
-		.version	= AVC_SW_VERSION_ENTRY,
-	}, {
-		/* FireDTV S/CI and FloppyDTV S2 */
-		.match_flags	= MATCH_FLAGS,
-		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
-		.model_id	= 0x000034,
-		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
-		.version	= AVC_SW_VERSION_ENTRY,
-	}, {
-		/* FireDTV T/CI */
-		.match_flags	= MATCH_FLAGS,
-		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
-		.model_id	= 0x000035,
-		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
-		.version	= AVC_SW_VERSION_ENTRY,
-	}, {
-		/* FireDTV C/CI */
-		.match_flags	= MATCH_FLAGS,
-		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
-		.model_id	= 0x000036,
-		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
-		.version	= AVC_SW_VERSION_ENTRY,
-	}, {}
-};
-MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table);
-
-static struct fw_driver fdtv_driver = {
-	.driver   = {
-		.owner  = THIS_MODULE,
-		.name   = "firedtv",
-		.bus    = &fw_bus_type,
-		.probe  = node_probe,
-		.remove = node_remove,
-	},
-	.update   = node_update,
-	.id_table = fdtv_id_table,
-};
-
-static int __init fdtv_init(void)
-{
-	int ret;
-
-	ret = fw_core_add_address_handler(&fcp_handler, &fcp_region);
-	if (ret < 0)
-		return ret;
-
-	ret = driver_register(&fdtv_driver.driver);
-	if (ret < 0)
-		fw_core_remove_address_handler(&fcp_handler);
-
-	return ret;
-}
-
-static void __exit fdtv_exit(void)
-{
-	driver_unregister(&fdtv_driver.driver);
-	fw_core_remove_address_handler(&fcp_handler);
-}
-
-module_init(fdtv_init);
-module_exit(fdtv_exit);
-
-MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
-MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
-MODULE_DESCRIPTION("FireDTV DVB Driver");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("FireDTV DVB");
diff --git a/drivers/media/dvb/firewire/firedtv-rc.c b/drivers/media/dvb/firewire/firedtv-rc.c
deleted file mode 100644
index f82d4a9..0000000
--- a/drivers/media/dvb/firewire/firedtv-rc.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * FireDTV driver (formerly known as FireSAT)
- *
- * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License as
- *	published by the Free Software Foundation; either version 2 of
- *	the License, or (at your option) any later version.
- */
-
-#include <linux/bitops.h>
-#include <linux/input.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/workqueue.h>
-
-#include "firedtv.h"
-
-/* fixed table with older keycodes, geared towards MythTV */
-static const u16 oldtable[] = {
-
-	/* code from device: 0x4501...0x451f */
-
-	KEY_ESC,
-	KEY_F9,
-	KEY_1,
-	KEY_2,
-	KEY_3,
-	KEY_4,
-	KEY_5,
-	KEY_6,
-	KEY_7,
-	KEY_8,
-	KEY_9,
-	KEY_I,
-	KEY_0,
-	KEY_ENTER,
-	KEY_RED,
-	KEY_UP,
-	KEY_GREEN,
-	KEY_F10,
-	KEY_SPACE,
-	KEY_F11,
-	KEY_YELLOW,
-	KEY_DOWN,
-	KEY_BLUE,
-	KEY_Z,
-	KEY_P,
-	KEY_PAGEDOWN,
-	KEY_LEFT,
-	KEY_W,
-	KEY_RIGHT,
-	KEY_P,
-	KEY_M,
-
-	/* code from device: 0x4540...0x4542 */
-
-	KEY_R,
-	KEY_V,
-	KEY_C,
-};
-
-/* user-modifiable table for a remote as sold in 2008 */
-static const u16 keytable[] = {
-
-	/* code from device: 0x0300...0x031f */
-
-	[0x00] = KEY_POWER,
-	[0x01] = KEY_SLEEP,
-	[0x02] = KEY_STOP,
-	[0x03] = KEY_OK,
-	[0x04] = KEY_RIGHT,
-	[0x05] = KEY_1,
-	[0x06] = KEY_2,
-	[0x07] = KEY_3,
-	[0x08] = KEY_LEFT,
-	[0x09] = KEY_4,
-	[0x0a] = KEY_5,
-	[0x0b] = KEY_6,
-	[0x0c] = KEY_UP,
-	[0x0d] = KEY_7,
-	[0x0e] = KEY_8,
-	[0x0f] = KEY_9,
-	[0x10] = KEY_DOWN,
-	[0x11] = KEY_TITLE,	/* "OSD" - fixme */
-	[0x12] = KEY_0,
-	[0x13] = KEY_F20,	/* "16:9" - fixme */
-	[0x14] = KEY_SCREEN,	/* "FULL" - fixme */
-	[0x15] = KEY_MUTE,
-	[0x16] = KEY_SUBTITLE,
-	[0x17] = KEY_RECORD,
-	[0x18] = KEY_TEXT,
-	[0x19] = KEY_AUDIO,
-	[0x1a] = KEY_RED,
-	[0x1b] = KEY_PREVIOUS,
-	[0x1c] = KEY_REWIND,
-	[0x1d] = KEY_PLAYPAUSE,
-	[0x1e] = KEY_NEXT,
-	[0x1f] = KEY_VOLUMEUP,
-
-	/* code from device: 0x0340...0x0354 */
-
-	[0x20] = KEY_CHANNELUP,
-	[0x21] = KEY_F21,	/* "4:3" - fixme */
-	[0x22] = KEY_TV,
-	[0x23] = KEY_DVD,
-	[0x24] = KEY_VCR,
-	[0x25] = KEY_AUX,
-	[0x26] = KEY_GREEN,
-	[0x27] = KEY_YELLOW,
-	[0x28] = KEY_BLUE,
-	[0x29] = KEY_CHANNEL,	/* "CH.LIST" */
-	[0x2a] = KEY_VENDOR,	/* "CI" - fixme */
-	[0x2b] = KEY_VOLUMEDOWN,
-	[0x2c] = KEY_CHANNELDOWN,
-	[0x2d] = KEY_LAST,
-	[0x2e] = KEY_INFO,
-	[0x2f] = KEY_FORWARD,
-	[0x30] = KEY_LIST,
-	[0x31] = KEY_FAVORITES,
-	[0x32] = KEY_MENU,
-	[0x33] = KEY_EPG,
-	[0x34] = KEY_EXIT,
-};
-
-int fdtv_register_rc(struct firedtv *fdtv, struct device *dev)
-{
-	struct input_dev *idev;
-	int i, err;
-
-	idev = input_allocate_device();
-	if (!idev)
-		return -ENOMEM;
-
-	fdtv->remote_ctrl_dev = idev;
-	idev->name = "FireDTV remote control";
-	idev->dev.parent = dev;
-	idev->evbit[0] = BIT_MASK(EV_KEY);
-	idev->keycode = kmemdup(keytable, sizeof(keytable), GFP_KERNEL);
-	if (!idev->keycode) {
-		err = -ENOMEM;
-		goto fail;
-	}
-	idev->keycodesize = sizeof(keytable[0]);
-	idev->keycodemax = ARRAY_SIZE(keytable);
-
-	for (i = 0; i < ARRAY_SIZE(keytable); i++)
-		set_bit(keytable[i], idev->keybit);
-
-	err = input_register_device(idev);
-	if (err)
-		goto fail_free_keymap;
-
-	return 0;
-
-fail_free_keymap:
-	kfree(idev->keycode);
-fail:
-	input_free_device(idev);
-	return err;
-}
-
-void fdtv_unregister_rc(struct firedtv *fdtv)
-{
-	cancel_work_sync(&fdtv->remote_ctrl_work);
-	kfree(fdtv->remote_ctrl_dev->keycode);
-	input_unregister_device(fdtv->remote_ctrl_dev);
-}
-
-void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code)
-{
-	struct input_dev *idev = fdtv->remote_ctrl_dev;
-	u16 *keycode = idev->keycode;
-
-	if (code >= 0x0300 && code <= 0x031f)
-		code = keycode[code - 0x0300];
-	else if (code >= 0x0340 && code <= 0x0354)
-		code = keycode[code - 0x0320];
-	else if (code >= 0x4501 && code <= 0x451f)
-		code = oldtable[code - 0x4501];
-	else if (code >= 0x4540 && code <= 0x4542)
-		code = oldtable[code - 0x4521];
-	else {
-		printk(KERN_DEBUG "firedtv: invalid key code 0x%04x "
-		       "from remote control\n", code);
-		return;
-	}
-
-	input_report_key(idev, code, 1);
-	input_sync(idev);
-	input_report_key(idev, code, 0);
-	input_sync(idev);
-}
diff --git a/drivers/media/dvb/firewire/firedtv.h b/drivers/media/dvb/firewire/firedtv.h
deleted file mode 100644
index 4fdcd8c..0000000
--- a/drivers/media/dvb/firewire/firedtv.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * FireDTV driver (formerly known as FireSAT)
- *
- * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
- * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
- *
- *	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.
- */
-
-#ifndef _FIREDTV_H
-#define _FIREDTV_H
-
-#include <linux/dvb/dmx.h>
-#include <linux/dvb/frontend.h>
-#include <linux/list.h>
-#include <linux/mod_devicetable.h>
-#include <linux/mutex.h>
-#include <linux/spinlock_types.h>
-#include <linux/types.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-
-#include <demux.h>
-#include <dmxdev.h>
-#include <dvb_demux.h>
-#include <dvb_frontend.h>
-#include <dvb_net.h>
-#include <dvbdev.h>
-
-struct firedtv_tuner_status {
-	unsigned active_system:8;
-	unsigned searching:1;
-	unsigned moving:1;
-	unsigned no_rf:1;
-	unsigned input:1;
-	unsigned selected_antenna:7;
-	unsigned ber:32;
-	unsigned signal_strength:8;
-	unsigned raster_frequency:2;
-	unsigned rf_frequency:22;
-	unsigned man_dep_info_length:8;
-	unsigned front_end_error:1;
-	unsigned antenna_error:1;
-	unsigned front_end_power_status:1;
-	unsigned power_supply:1;
-	unsigned carrier_noise_ratio:16;
-	unsigned power_supply_voltage:8;
-	unsigned antenna_voltage:8;
-	unsigned firewire_bus_voltage:8;
-	unsigned ca_mmi:1;
-	unsigned ca_pmt_reply:1;
-	unsigned ca_date_time_request:1;
-	unsigned ca_application_info:1;
-	unsigned ca_module_present_status:1;
-	unsigned ca_dvb_flag:1;
-	unsigned ca_error_flag:1;
-	unsigned ca_initialization_status:1;
-};
-
-enum model_type {
-	FIREDTV_UNKNOWN = 0,
-	FIREDTV_DVB_S   = 1,
-	FIREDTV_DVB_C   = 2,
-	FIREDTV_DVB_T   = 3,
-	FIREDTV_DVB_S2  = 4,
-};
-
-struct device;
-struct input_dev;
-struct fdtv_ir_context;
-
-struct firedtv {
-	struct device *device;
-	struct list_head list;
-
-	struct dvb_adapter	adapter;
-	struct dmxdev		dmxdev;
-	struct dvb_demux	demux;
-	struct dmx_frontend	frontend;
-	struct dvb_net		dvbnet;
-	struct dvb_frontend	fe;
-
-	struct dvb_device	*cadev;
-	int			ca_last_command;
-	int			ca_time_interval;
-
-	struct mutex		avc_mutex;
-	wait_queue_head_t	avc_wait;
-	bool			avc_reply_received;
-	struct work_struct	remote_ctrl_work;
-	struct input_dev	*remote_ctrl_dev;
-
-	enum model_type		type;
-	char			subunit;
-	char			isochannel;
-	struct fdtv_ir_context	*ir_context;
-
-	fe_sec_voltage_t	voltage;
-	fe_sec_tone_mode_t	tone;
-
-	struct mutex		demux_mutex;
-	unsigned long		channel_active;
-	u16			channel_pid[16];
-
-	int			avc_data_length;
-	u8			avc_data[512];
-};
-
-/* firedtv-avc.c */
-int avc_recv(struct firedtv *fdtv, void *data, size_t length);
-int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat);
-struct dtv_frontend_properties;
-int avc_tuner_dsd(struct firedtv *fdtv, struct dtv_frontend_properties *params);
-int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]);
-int avc_tuner_get_ts(struct firedtv *fdtv);
-int avc_identify_subunit(struct firedtv *fdtv);
-struct dvb_diseqc_master_cmd;
-int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
-		    char conttone, char nrdiseq,
-		    struct dvb_diseqc_master_cmd *diseqcmd);
-void avc_remote_ctrl_work(struct work_struct *work);
-int avc_register_remote_control(struct firedtv *fdtv);
-int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
-int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
-int avc_ca_reset(struct firedtv *fdtv);
-int avc_ca_pmt(struct firedtv *fdtv, char *app_info, int length);
-int avc_ca_get_time_date(struct firedtv *fdtv, int *interval);
-int avc_ca_enter_menu(struct firedtv *fdtv);
-int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len);
-int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel);
-void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel);
-
-/* firedtv-ci.c */
-int fdtv_ca_register(struct firedtv *fdtv);
-void fdtv_ca_release(struct firedtv *fdtv);
-
-/* firedtv-dvb.c */
-int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed);
-int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed);
-int fdtv_dvb_register(struct firedtv *fdtv, const char *name);
-void fdtv_dvb_unregister(struct firedtv *fdtv);
-
-/* firedtv-fe.c */
-void fdtv_frontend_init(struct firedtv *fdtv, const char *name);
-
-/* firedtv-fw.c */
-int fdtv_lock(struct firedtv *fdtv, u64 addr, void *data);
-int fdtv_read(struct firedtv *fdtv, u64 addr, void *data);
-int fdtv_write(struct firedtv *fdtv, u64 addr, void *data, size_t len);
-int fdtv_start_iso(struct firedtv *fdtv);
-void fdtv_stop_iso(struct firedtv *fdtv);
-
-/* firedtv-rc.c */
-#ifdef CONFIG_DVB_FIREDTV_INPUT
-int fdtv_register_rc(struct firedtv *fdtv, struct device *dev);
-void fdtv_unregister_rc(struct firedtv *fdtv);
-void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code);
-#else
-static inline int fdtv_register_rc(struct firedtv *fdtv,
-				   struct device *dev) { return 0; }
-static inline void fdtv_unregister_rc(struct firedtv *fdtv) {}
-static inline void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code) {}
-#endif
-
-#endif /* _FIREDTV_H */
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
deleted file mode 100644
index a08c215..0000000
--- a/drivers/media/dvb/frontends/Kconfig
+++ /dev/null
@@ -1,756 +0,0 @@
-config DVB_FE_CUSTOMISE
-	bool "Customise the frontend modules to build"
-	depends on DVB_CORE
-	depends on EXPERT
-	default y if EXPERT
-	help
-	  This allows the user to select/deselect frontend drivers for their
-	  hardware from the build.
-
-	  Use this option with care as deselecting frontends which are in fact
-	  necessary will result in DVB devices which cannot be tuned due to lack
-	  of driver support.
-
-	  If unsure say N.
-
-menu "Customise DVB Frontends"
-	visible if DVB_FE_CUSTOMISE
-
-comment "Multistandard (satellite) frontends"
-	depends on DVB_CORE
-
-config DVB_STB0899
-	tristate "STB0899 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S/S2/DSS Multistandard demodulator. Say Y when you want
-	  to support this demodulator based frontends
-
-config DVB_STB6100
-	tristate "STB6100 based tuners"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A Silicon tuner from ST used in conjunction with the STB0899
-	  demodulator. Say Y when you want to support this tuner.
-
-config DVB_STV090x
-	tristate "STV0900/STV0903(A/B) based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators.
-	  Say Y when you want to support these frontends.
-
-config DVB_STV6110x
-	tristate "STV6110/(A) based tuners"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A Silicon tuner that supports DVB-S and DVB-S2 modes
-
-comment "Multistandard (cable + terrestrial) frontends"
-	depends on DVB_CORE
-
-config DVB_DRXK
-	tristate "Micronas DRXK based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  Micronas DRX-K DVB-C/T demodulator.
-
-	  Say Y when you want to support this frontend.
-
-config DVB_TDA18271C2DD
-	tristate "NXP TDA18271C2 silicon tuner"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  NXP TDA18271 silicon tuner.
-
-	  Say Y when you want to support this tuner.
-
-comment "DVB-S (satellite) frontends"
-	depends on DVB_CORE
-
-config DVB_CX24110
-	tristate "Conexant CX24110 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
-
-config DVB_CX24123
-	tristate "Conexant CX24123 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
-
-config DVB_MT312
-	tristate "Zarlink VP310/MT312/ZL10313 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
-
-config DVB_ZL10036
-	tristate "Zarlink ZL10036 silicon tuner"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
-
-config DVB_ZL10039
-	tristate "Zarlink ZL10039 silicon tuner"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
-
-config DVB_S5H1420
-	tristate "Samsung S5H1420 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
-
-config DVB_STV0288
-	tristate "ST STV0288 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
-
-config DVB_STB6000
-	tristate "ST STB6000 silicon tuner"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	  help
-	  A DVB-S silicon tuner module. Say Y when you want to support this tuner.
-
-config DVB_STV0299
-	tristate "ST STV0299 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
-
-config DVB_STV6110
-	tristate "ST STV6110 silicon tuner"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	  help
-	  A DVB-S silicon tuner module. Say Y when you want to support this tuner.
-
-config DVB_STV0900
-	tristate "ST STV0900 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S/S2 demodulator. Say Y when you want to support this frontend.
-
-config DVB_TDA8083
-	tristate "Philips TDA8083 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
-
-config DVB_TDA10086
-	tristate "Philips TDA10086 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
-
-config DVB_TDA8261
-	tristate "Philips TDA8261 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
-
-config DVB_VES1X93
-	tristate "VLSI VES1893 or VES1993 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
-
-config DVB_TUNER_ITD1000
-	tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
-
-config DVB_TUNER_CX24113
-	tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
-
-
-config DVB_TDA826X
-	tristate "Philips TDA826X silicon tuner"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S silicon tuner module. Say Y when you want to support this tuner.
-
-config DVB_TUA6100
-	tristate "Infineon TUA6100 PLL"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S PLL chip.
-
-config DVB_CX24116
-	tristate "Conexant CX24116 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
-
-config DVB_SI21XX
-	tristate "Silicon Labs SI21XX based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
-
-config DVB_DS3000
-	tristate "Montage Tehnology DS3000 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
-
-config DVB_MB86A16
-	tristate "Fujitsu MB86A16 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S/DSS Direct Conversion reveiver.
-	  Say Y when you want to support this frontend.
-
-config DVB_TDA10071
-	tristate "NXP TDA10071"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  Say Y when you want to support this frontend.
-
-comment "DVB-T (terrestrial) frontends"
-	depends on DVB_CORE
-
-config DVB_SP8870
-	tristate "Spase sp8870 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module. Say Y when you want to support this frontend.
-
-	  This driver needs external firmware. Please use the command
-	  "<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to
-	  download/extract it, and then copy it to /usr/lib/hotplug/firmware
-	  or /lib/firmware (depending on configuration of firmware hotplug).
-
-config DVB_SP887X
-	tristate "Spase sp887x based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module. Say Y when you want to support this frontend.
-
-	  This driver needs external firmware. Please use the command
-	  "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
-	  download/extract it, and then copy it to /usr/lib/hotplug/firmware
-	  or /lib/firmware (depending on configuration of firmware hotplug).
-
-config DVB_CX22700
-	tristate "Conexant CX22700 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module. Say Y when you want to support this frontend.
-
-config DVB_CX22702
-	tristate "Conexant cx22702 demodulator (OFDM)"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module. Say Y when you want to support this frontend.
-
-config DVB_S5H1432
-	tristate "Samsung s5h1432 demodulator (OFDM)"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module. Say Y when you want to support this frontend.
-
-config DVB_DRXD
-	tristate "Micronas DRXD driver"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module. Say Y when you want to support this frontend.
-
-	  Note: this driver was based on vendor driver reference code (released
-	  under the GPL) as opposed to the existing drx397xd driver, which
-	  was written via reverse engineering.
-
-config DVB_L64781
-	tristate "LSI L64781"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module. Say Y when you want to support this frontend.
-
-config DVB_TDA1004X
-	tristate "Philips TDA10045H/TDA10046H based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module. Say Y when you want to support this frontend.
-
-	  This driver needs external firmware. Please use the commands
-	  "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
-	  "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
-	  download/extract them, and then copy them to /usr/lib/hotplug/firmware
-	  or /lib/firmware (depending on configuration of firmware hotplug).
-
-config DVB_NXT6000
-	tristate "NxtWave Communications NXT6000 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module. Say Y when you want to support this frontend.
-
-config DVB_MT352
-	tristate "Zarlink MT352 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module. Say Y when you want to support this frontend.
-
-config DVB_ZL10353
-	tristate "Zarlink ZL10353 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module. Say Y when you want to support this frontend.
-
-config DVB_DIB3000MB
-	tristate "DiBcom 3000M-B"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
-	  to support this frontend.
-
-config DVB_DIB3000MC
-	tristate "DiBcom 3000P/M-C"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
-	  to support this frontend.
-
-config DVB_DIB7000M
-	tristate "DiBcom 7000MA/MB/PA/PB/MC"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
-	  to support this frontend.
-
-config DVB_DIB7000P
-	tristate "DiBcom 7000PC"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
-	  to support this frontend.
-
-config DVB_DIB9000
-	tristate "DiBcom 9000"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
-	  to support this frontend.
-
-config DVB_TDA10048
-	tristate "Philips TDA10048HN based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module. Say Y when you want to support this frontend.
-
-config DVB_AF9013
-	tristate "Afatech AF9013 demodulator"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  Say Y when you want to support this frontend.
-
-config DVB_EC100
-	tristate "E3C EC100"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  Say Y when you want to support this frontend.
-
-config DVB_HD29L2
-	tristate "HDIC HD29L2"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  Say Y when you want to support this frontend.
-
-config DVB_STV0367
-	tristate "ST STV0367 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T/C tuner module. Say Y when you want to support this frontend.
-
-config DVB_CXD2820R
-	tristate "Sony CXD2820R"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  Say Y when you want to support this frontend.
-
-config DVB_RTL2830
-	tristate "Realtek RTL2830 DVB-T"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  Say Y when you want to support this frontend.
-
-config DVB_RTL2832
-	tristate "Realtek RTL2832 DVB-T"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  Say Y when you want to support this frontend.
-
-comment "DVB-C (cable) frontends"
-	depends on DVB_CORE
-
-config DVB_VES1820
-	tristate "VLSI VES1820 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-C tuner module. Say Y when you want to support this frontend.
-
-config DVB_TDA10021
-	tristate "Philips TDA10021 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-C tuner module. Say Y when you want to support this frontend.
-
-config DVB_TDA10023
-	tristate "Philips TDA10023 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-C tuner module. Say Y when you want to support this frontend.
-
-config DVB_STV0297
-	tristate "ST STV0297 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-C tuner module. Say Y when you want to support this frontend.
-
-comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
-	depends on DVB_CORE
-
-config DVB_NXT200X
-	tristate "NxtWave Communications NXT2002/NXT2004 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
-	  to support this frontend.
-
-	  This driver needs external firmware. Please use the commands
-	  "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" and
-	  "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
-	  download/extract them, and then copy them to /usr/lib/hotplug/firmware
-	  or /lib/firmware (depending on configuration of firmware hotplug).
-
-config DVB_OR51211
-	tristate "Oren OR51211 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
-
-	  This driver needs external firmware. Please use the command
-	  "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
-	  download it, and then copy it to /usr/lib/hotplug/firmware
-	  or /lib/firmware (depending on configuration of firmware hotplug).
-
-config DVB_OR51132
-	tristate "Oren OR51132 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
-	  to support this frontend.
-
-	  This driver needs external firmware. Please use the commands
-	  "<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_vsb" and/or
-	  "<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_qam" to
-	  download firmwares for 8VSB and QAM64/256, respectively. Copy them to
-	  /usr/lib/hotplug/firmware or /lib/firmware (depending on
-	  configuration of firmware hotplug).
-
-config DVB_BCM3510
-	tristate "Broadcom BCM3510"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
-	  support this frontend.
-
-config DVB_LGDT330X
-	tristate "LG Electronics LGDT3302/LGDT3303 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
-	  to support this frontend.
-
-config DVB_LGDT3305
-	tristate "LG Electronics LGDT3304 and LGDT3305 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
-	  to support this frontend.
-
-config DVB_LG2160
-	tristate "LG Electronics LG216x based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  An ATSC/MH demodulator module. Say Y when you want
-	  to support this frontend.
-
-config DVB_S5H1409
-	tristate "Samsung S5H1409 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
-	  to support this frontend.
-
-config DVB_AU8522
-	depends on I2C
-	tristate
-
-config DVB_AU8522_DTV
-	tristate "Auvitek AU8522 based DTV demod"
-	depends on DVB_CORE && I2C
-	select DVB_AU8522
-	default m if DVB_FE_CUSTOMISE
-	help
-	  An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
-	  you want to enable DTV demodulation support for this frontend.
-
-config DVB_AU8522_V4L
-	tristate "Auvitek AU8522 based ATV demod"
-	depends on VIDEO_V4L2 && I2C
-	select DVB_AU8522
-	default m if DVB_FE_CUSTOMISE
-	help
-	  An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
-	  you want to enable ATV demodulation support for this frontend.
-
-config DVB_S5H1411
-	tristate "Samsung S5H1411 based"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
-	  to support this frontend.
-
-comment "ISDB-T (terrestrial) frontends"
-	depends on DVB_CORE
-
-config DVB_S921
-	tristate "Sharp S921 frontend"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module.
-	  Say Y when you want to support this frontend.
-
-config DVB_DIB8000
-	tristate "DiBcom 8000MB/MC"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A driver for DiBcom's DiB8000 ISDB-T/ISDB-Tsb demodulator.
-	  Say Y when you want to support this frontend.
-
-config DVB_MB86A20S
-	tristate "Fujitsu mb86a20s"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator.
-	  Say Y when you want to support this frontend.
-
-comment "Digital terrestrial only tuners/PLL"
-	depends on DVB_CORE
-
-config DVB_PLL
-	tristate "Generic I2C PLL based tuners"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  This module drives a number of tuners based on PLL chips with a
-	  common I2C interface. Say Y when you want to support these tuners.
-
-config DVB_TUNER_DIB0070
-	tristate "DiBcom DiB0070 silicon base-band tuner"
-	depends on I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A driver for the silicon baseband tuner DiB0070 from DiBcom.
-	  This device is only used inside a SiP called together with a
-	  demodulator for now.
-
-config DVB_TUNER_DIB0090
-	tristate "DiBcom DiB0090 silicon base-band tuner"
-	depends on I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A driver for the silicon baseband tuner DiB0090 from DiBcom.
-	  This device is only used inside a SiP called together with a
-	  demodulator for now.
-
-comment "SEC control devices for DVB-S"
-	depends on DVB_CORE
-
-config DVB_LNBP21
-	tristate "LNBP21/LNBH24 SEC controllers"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  An SEC control chips.
-
-config DVB_LNBP22
-	tristate "LNBP22 SEC controllers"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  LNB power supply and control voltage
-	  regulator chip with step-up converter
-	  and I2C interface.
-	  Say Y when you want to support this chip.
-
-config DVB_ISL6405
-	tristate "ISL6405 SEC controller"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  An SEC control chip.
-
-config DVB_ISL6421
-	tristate "ISL6421 SEC controller"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  An SEC control chip.
-
-config DVB_ISL6423
-	tristate "ISL6423 SEC controller"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A SEC controller chip from Intersil
-
-config DVB_A8293
-	tristate "Allegro A8293"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-
-config DVB_LGS8GL5
-	tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DMB-TH tuner module. Say Y when you want to support this frontend.
-
-config DVB_LGS8GXX
-	tristate "Legend Silicon LGS8913/LGS8GL5/LGS8GXX DMB-TH demodulator"
-	depends on DVB_CORE && I2C
-	select FW_LOADER
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DMB-TH tuner module. Say Y when you want to support this frontend.
-
-config DVB_ATBM8830
-	tristate "AltoBeam ATBM8830/8831 DMB-TH demodulator"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DMB-TH tuner module. Say Y when you want to support this frontend.
-
-config DVB_TDA665x
-	tristate "TDA665x tuner"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  Support for tuner modules based on Philips TDA6650/TDA6651 chips.
-	  Say Y when you want to support this chip.
-
-	  Currently supported tuners:
-	  * Panasonic ENV57H12D5 (ET-50DT)
-
-config DVB_IX2505V
-	tristate "Sharp IX2505V silicon tuner"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
-
-config DVB_IT913X_FE
-	tristate "it913x frontend and it9137 tuner"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-T tuner module.
-	  Say Y when you want to support this frontend.
-
-config DVB_M88RS2000
-	tristate "M88RS2000 DVB-S demodulator and tuner"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A DVB-S tuner module.
-	  Say Y when you want to support this frontend.
-
-config DVB_AF9033
-	tristate "Afatech AF9033 DVB-T demodulator"
-	depends on DVB_CORE && I2C
-	default m if DVB_FE_CUSTOMISE
-
-comment "Tools to develop new frontends"
-
-config DVB_DUMMY_FE
-	tristate "Dummy frontend driver"
-	default n
-endmenu
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
deleted file mode 100644
index 185bb8b..0000000
--- a/drivers/media/dvb/frontends/Makefile
+++ /dev/null
@@ -1,105 +0,0 @@
-#
-# Makefile for the kernel DVB frontend device drivers.
-#
-
-ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core/
-ccflags-y += -I$(srctree)/drivers/media/common/tuners/
-
-stb0899-objs = stb0899_drv.o stb0899_algo.o
-stv0900-objs = stv0900_core.o stv0900_sw.o
-drxd-objs = drxd_firm.o drxd_hard.o
-cxd2820r-objs = cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o
-drxk-objs := drxk_hard.o
-
-obj-$(CONFIG_DVB_PLL) += dvb-pll.o
-obj-$(CONFIG_DVB_STV0299) += stv0299.o
-obj-$(CONFIG_DVB_STB0899) += stb0899.o
-obj-$(CONFIG_DVB_STB6100) += stb6100.o
-obj-$(CONFIG_DVB_SP8870) += sp8870.o
-obj-$(CONFIG_DVB_CX22700) += cx22700.o
-obj-$(CONFIG_DVB_S5H1432) += s5h1432.o
-obj-$(CONFIG_DVB_CX24110) += cx24110.o
-obj-$(CONFIG_DVB_TDA8083) += tda8083.o
-obj-$(CONFIG_DVB_L64781) += l64781.o
-obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o
-obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o
-obj-$(CONFIG_DVB_DIB7000M) += dib7000m.o dibx000_common.o
-obj-$(CONFIG_DVB_DIB7000P) += dib7000p.o dibx000_common.o
-obj-$(CONFIG_DVB_DIB8000) += dib8000.o dibx000_common.o
-obj-$(CONFIG_DVB_DIB9000) += dib9000.o dibx000_common.o
-obj-$(CONFIG_DVB_MT312) += mt312.o
-obj-$(CONFIG_DVB_VES1820) += ves1820.o
-obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
-obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o
-obj-$(CONFIG_DVB_SP887X) += sp887x.o
-obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
-obj-$(CONFIG_DVB_MT352) += mt352.o
-obj-$(CONFIG_DVB_ZL10036) += zl10036.o
-obj-$(CONFIG_DVB_ZL10039) += zl10039.o
-obj-$(CONFIG_DVB_ZL10353) += zl10353.o
-obj-$(CONFIG_DVB_CX22702) += cx22702.o
-obj-$(CONFIG_DVB_DRXD) += drxd.o
-obj-$(CONFIG_DVB_TDA10021) += tda10021.o
-obj-$(CONFIG_DVB_TDA10023) += tda10023.o
-obj-$(CONFIG_DVB_STV0297) += stv0297.o
-obj-$(CONFIG_DVB_NXT200X) += nxt200x.o
-obj-$(CONFIG_DVB_OR51211) += or51211.o
-obj-$(CONFIG_DVB_OR51132) += or51132.o
-obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
-obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
-obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
-obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
-obj-$(CONFIG_DVB_LG2160) += lg2160.o
-obj-$(CONFIG_DVB_CX24123) += cx24123.o
-obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
-obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
-obj-$(CONFIG_DVB_ISL6405) += isl6405.o
-obj-$(CONFIG_DVB_ISL6421) += isl6421.o
-obj-$(CONFIG_DVB_TDA10086) += tda10086.o
-obj-$(CONFIG_DVB_TDA826X) += tda826x.o
-obj-$(CONFIG_DVB_TDA8261) += tda8261.o
-obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
-obj-$(CONFIG_DVB_TUNER_DIB0090) += dib0090.o
-obj-$(CONFIG_DVB_TUA6100) += tua6100.o
-obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
-obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
-obj-$(CONFIG_DVB_AU8522) += au8522_common.o
-obj-$(CONFIG_DVB_AU8522_DTV) += au8522_dig.o
-obj-$(CONFIG_DVB_AU8522_V4L) += au8522_decoder.o
-obj-$(CONFIG_DVB_TDA10048) += tda10048.o
-obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
-obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
-obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
-obj-$(CONFIG_DVB_TDA665x) += tda665x.o
-obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o
-obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o
-obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
-obj-$(CONFIG_DVB_AF9013) += af9013.o
-obj-$(CONFIG_DVB_CX24116) += cx24116.o
-obj-$(CONFIG_DVB_SI21XX) += si21xx.o
-obj-$(CONFIG_DVB_STV0288) += stv0288.o
-obj-$(CONFIG_DVB_STB6000) += stb6000.o
-obj-$(CONFIG_DVB_S921) += s921.o
-obj-$(CONFIG_DVB_STV6110) += stv6110.o
-obj-$(CONFIG_DVB_STV0900) += stv0900.o
-obj-$(CONFIG_DVB_STV090x) += stv090x.o
-obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
-obj-$(CONFIG_DVB_ISL6423) += isl6423.o
-obj-$(CONFIG_DVB_EC100) += ec100.o
-obj-$(CONFIG_DVB_HD29L2) += hd29l2.o
-obj-$(CONFIG_DVB_DS3000) += ds3000.o
-obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
-obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
-obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
-obj-$(CONFIG_DVB_STV0367) += stv0367.o
-obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
-obj-$(CONFIG_DVB_DRXK) += drxk.o
-obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
-obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o
-obj-$(CONFIG_DVB_A8293) += a8293.o
-obj-$(CONFIG_DVB_TDA10071) += tda10071.o
-obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
-obj-$(CONFIG_DVB_RTL2832) += rtl2832.o
-obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
-obj-$(CONFIG_DVB_AF9033) += af9033.o
-
diff --git a/drivers/media/dvb/frontends/a8293.c b/drivers/media/dvb/frontends/a8293.c
deleted file mode 100644
index cff44a3..0000000
--- a/drivers/media/dvb/frontends/a8293.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Allegro A8293 SEC driver
- *
- * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "dvb_frontend.h"
-#include "a8293.h"
-
-struct a8293_priv {
-	struct i2c_adapter *i2c;
-	const struct a8293_config *cfg;
-	u8 reg[2];
-};
-
-static int a8293_i2c(struct a8293_priv *priv, u8 *val, int len, bool rd)
-{
-	int ret;
-	struct i2c_msg msg[1] = {
-		{
-			.addr = priv->cfg->i2c_addr,
-			.len = len,
-			.buf = val,
-		}
-	};
-
-	if (rd)
-		msg[0].flags = I2C_M_RD;
-	else
-		msg[0].flags = 0;
-
-	ret = i2c_transfer(priv->i2c, msg, 1);
-	if (ret == 1) {
-		ret = 0;
-	} else {
-		dev_warn(&priv->i2c->dev, "%s: i2c failed=%d rd=%d\n",
-				KBUILD_MODNAME, ret, rd);
-		ret = -EREMOTEIO;
-	}
-
-	return ret;
-}
-
-static int a8293_wr(struct a8293_priv *priv, u8 *val, int len)
-{
-	return a8293_i2c(priv, val, len, 0);
-}
-
-static int a8293_rd(struct a8293_priv *priv, u8 *val, int len)
-{
-	return a8293_i2c(priv, val, len, 1);
-}
-
-static int a8293_set_voltage(struct dvb_frontend *fe,
-	fe_sec_voltage_t fe_sec_voltage)
-{
-	struct a8293_priv *priv = fe->sec_priv;
-	int ret;
-
-	dev_dbg(&priv->i2c->dev, "%s: fe_sec_voltage=%d\n", __func__,
-			fe_sec_voltage);
-
-	switch (fe_sec_voltage) {
-	case SEC_VOLTAGE_OFF:
-		/* ENB=0 */
-		priv->reg[0] = 0x10;
-		break;
-	case SEC_VOLTAGE_13:
-		/* VSEL0=1, VSEL1=0, VSEL2=0, VSEL3=0, ENB=1*/
-		priv->reg[0] = 0x31;
-		break;
-	case SEC_VOLTAGE_18:
-		/* VSEL0=0, VSEL1=0, VSEL2=0, VSEL3=1, ENB=1*/
-		priv->reg[0] = 0x38;
-		break;
-	default:
-		ret = -EINVAL;
-		goto err;
-	};
-
-	ret = a8293_wr(priv, &priv->reg[0], 1);
-	if (ret)
-		goto err;
-
-	return ret;
-err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static void a8293_release_sec(struct dvb_frontend *fe)
-{
-	a8293_set_voltage(fe, SEC_VOLTAGE_OFF);
-
-	kfree(fe->sec_priv);
-	fe->sec_priv = NULL;
-}
-
-struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, const struct a8293_config *cfg)
-{
-	int ret;
-	struct a8293_priv *priv = NULL;
-	u8 buf[2];
-
-	/* allocate memory for the internal priv */
-	priv = kzalloc(sizeof(struct a8293_priv), GFP_KERNEL);
-	if (priv == NULL) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	/* setup the priv */
-	priv->i2c = i2c;
-	priv->cfg = cfg;
-	fe->sec_priv = priv;
-
-	/* check if the SEC is there */
-	ret = a8293_rd(priv, buf, 2);
-	if (ret)
-		goto err;
-
-	/* ENB=0 */
-	priv->reg[0] = 0x10;
-	ret = a8293_wr(priv, &priv->reg[0], 1);
-	if (ret)
-		goto err;
-
-	/* TMODE=0, TGATE=1 */
-	priv->reg[1] = 0x82;
-	ret = a8293_wr(priv, &priv->reg[1], 1);
-	if (ret)
-		goto err;
-
-	fe->ops.release_sec = a8293_release_sec;
-
-	/* override frontend ops */
-	fe->ops.set_voltage = a8293_set_voltage;
-
-	dev_info(&priv->i2c->dev, "%s: Allegro A8293 SEC attached\n",
-			KBUILD_MODNAME);
-
-	return fe;
-err:
-	dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
-	kfree(priv);
-	return NULL;
-}
-EXPORT_SYMBOL(a8293_attach);
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Allegro A8293 SEC driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/a8293.h b/drivers/media/dvb/frontends/a8293.h
deleted file mode 100644
index ed29e55..0000000
--- a/drivers/media/dvb/frontends/a8293.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Allegro A8293 SEC driver
- *
- * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef A8293_H
-#define A8293_H
-
-struct a8293_config {
-	u8 i2c_addr;
-};
-
-#if defined(CONFIG_DVB_A8293) || \
-	(defined(CONFIG_DVB_A8293_MODULE) && defined(MODULE))
-extern struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, const struct a8293_config *cfg);
-#else
-static inline struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, const struct a8293_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* A8293_H */
diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c
deleted file mode 100644
index 5bc570d..0000000
--- a/drivers/media/dvb/frontends/af9013.c
+++ /dev/null
@@ -1,1524 +0,0 @@
-/*
- * Afatech AF9013 demodulator driver
- *
- * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
- * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
- *
- * Thanks to Afatech who kindly provided information.
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include "af9013_priv.h"
-
-int af9013_debug;
-module_param_named(debug, af9013_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-struct af9013_state {
-	struct i2c_adapter *i2c;
-	struct dvb_frontend fe;
-	struct af9013_config config;
-
-	/* tuner/demod RF and IF AGC limits used for signal strength calc */
-	u8 signal_strength_en, rf_50, rf_80, if_50, if_80;
-	u16 signal_strength;
-	u32 ber;
-	u32 ucblocks;
-	u16 snr;
-	u32 bandwidth_hz;
-	fe_status_t fe_status;
-	unsigned long set_frontend_jiffies;
-	unsigned long read_status_jiffies;
-	bool first_tune;
-	bool i2c_gate_state;
-	unsigned int statistics_step:3;
-	struct delayed_work statistics_work;
-};
-
-/* write multiple registers */
-static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg,
-	const u8 *val, int len)
-{
-	int ret;
-	u8 buf[3+len];
-	struct i2c_msg msg[1] = {
-		{
-			.addr = priv->config.i2c_addr,
-			.flags = 0,
-			.len = sizeof(buf),
-			.buf = buf,
-		}
-	};
-
-	buf[0] = (reg >> 8) & 0xff;
-	buf[1] = (reg >> 0) & 0xff;
-	buf[2] = mbox;
-	memcpy(&buf[3], val, len);
-
-	ret = i2c_transfer(priv->i2c, msg, 1);
-	if (ret == 1) {
-		ret = 0;
-	} else {
-		warn("i2c wr failed=%d reg=%04x len=%d", ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-	return ret;
-}
-
-/* read multiple registers */
-static int af9013_rd_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg,
-	u8 *val, int len)
-{
-	int ret;
-	u8 buf[3];
-	struct i2c_msg msg[2] = {
-		{
-			.addr = priv->config.i2c_addr,
-			.flags = 0,
-			.len = 3,
-			.buf = buf,
-		}, {
-			.addr = priv->config.i2c_addr,
-			.flags = I2C_M_RD,
-			.len = len,
-			.buf = val,
-		}
-	};
-
-	buf[0] = (reg >> 8) & 0xff;
-	buf[1] = (reg >> 0) & 0xff;
-	buf[2] = mbox;
-
-	ret = i2c_transfer(priv->i2c, msg, 2);
-	if (ret == 2) {
-		ret = 0;
-	} else {
-		warn("i2c rd failed=%d reg=%04x len=%d", ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-	return ret;
-}
-
-/* write multiple registers */
-static int af9013_wr_regs(struct af9013_state *priv, u16 reg, const u8 *val,
-	int len)
-{
-	int ret, i;
-	u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(1 << 0);
-
-	if ((priv->config.ts_mode == AF9013_TS_USB) &&
-		((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) {
-		mbox |= ((len - 1) << 2);
-		ret = af9013_wr_regs_i2c(priv, mbox, reg, val, len);
-	} else {
-		for (i = 0; i < len; i++) {
-			ret = af9013_wr_regs_i2c(priv, mbox, reg+i, val+i, 1);
-			if (ret)
-				goto err;
-		}
-	}
-
-err:
-	return 0;
-}
-
-/* read multiple registers */
-static int af9013_rd_regs(struct af9013_state *priv, u16 reg, u8 *val, int len)
-{
-	int ret, i;
-	u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(0 << 0);
-
-	if ((priv->config.ts_mode == AF9013_TS_USB) &&
-		((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) {
-		mbox |= ((len - 1) << 2);
-		ret = af9013_rd_regs_i2c(priv, mbox, reg, val, len);
-	} else {
-		for (i = 0; i < len; i++) {
-			ret = af9013_rd_regs_i2c(priv, mbox, reg+i, val+i, 1);
-			if (ret)
-				goto err;
-		}
-	}
-
-err:
-	return 0;
-}
-
-/* write single register */
-static int af9013_wr_reg(struct af9013_state *priv, u16 reg, u8 val)
-{
-	return af9013_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-static int af9013_rd_reg(struct af9013_state *priv, u16 reg, u8 *val)
-{
-	return af9013_rd_regs(priv, reg, val, 1);
-}
-
-static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val,
-	u8 len)
-{
-	u8 mbox = (1 << 7)|(1 << 6)|((len - 1) << 2)|(1 << 1)|(1 << 0);
-	return af9013_wr_regs_i2c(state, mbox, reg, val, len);
-}
-
-static int af9013_wr_reg_bits(struct af9013_state *state, u16 reg, int pos,
-	int len, u8 val)
-{
-	int ret;
-	u8 tmp, mask;
-
-	/* no need for read if whole reg is written */
-	if (len != 8) {
-		ret = af9013_rd_reg(state, reg, &tmp);
-		if (ret)
-			return ret;
-
-		mask = (0xff >> (8 - len)) << pos;
-		val <<= pos;
-		tmp &= ~mask;
-		val |= tmp;
-	}
-
-	return af9013_wr_reg(state, reg, val);
-}
-
-static int af9013_rd_reg_bits(struct af9013_state *state, u16 reg, int pos,
-	int len, u8 *val)
-{
-	int ret;
-	u8 tmp;
-
-	ret = af9013_rd_reg(state, reg, &tmp);
-	if (ret)
-		return ret;
-
-	*val = (tmp >> pos);
-	*val &= (0xff >> (8 - len));
-
-	return 0;
-}
-
-static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval)
-{
-	int ret;
-	u8 pos;
-	u16 addr;
-
-	dbg("%s: gpio=%d gpioval=%02x", __func__, gpio, gpioval);
-
-	/*
-	 * GPIO0 & GPIO1 0xd735
-	 * GPIO2 & GPIO3 0xd736
-	 */
-
-	switch (gpio) {
-	case 0:
-	case 1:
-		addr = 0xd735;
-		break;
-	case 2:
-	case 3:
-		addr = 0xd736;
-		break;
-
-	default:
-		err("invalid gpio:%d\n", gpio);
-		ret = -EINVAL;
-		goto err;
-	};
-
-	switch (gpio) {
-	case 0:
-	case 2:
-		pos = 0;
-		break;
-	case 1:
-	case 3:
-	default:
-		pos = 4;
-		break;
-	};
-
-	ret = af9013_wr_reg_bits(state, addr, pos, 4, gpioval);
-	if (ret)
-		goto err;
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static u32 af913_div(u32 a, u32 b, u32 x)
-{
-	u32 r = 0, c = 0, i;
-
-	dbg("%s: a=%d b=%d x=%d", __func__, a, b, x);
-
-	if (a > b) {
-		c = a / b;
-		a = a - c * b;
-	}
-
-	for (i = 0; i < x; i++) {
-		if (a >= b) {
-			r += 1;
-			a -= b;
-		}
-		a <<= 1;
-		r <<= 1;
-	}
-	r = (c << (u32)x) + r;
-
-	dbg("%s: a=%d b=%d x=%d r=%x", __func__, a, b, x, r);
-	return r;
-}
-
-static int af9013_power_ctrl(struct af9013_state *state, u8 onoff)
-{
-	int ret, i;
-	u8 tmp;
-
-	dbg("%s: onoff=%d", __func__, onoff);
-
-	/* enable reset */
-	ret = af9013_wr_reg_bits(state, 0xd417, 4, 1, 1);
-	if (ret)
-		goto err;
-
-	/* start reset mechanism */
-	ret = af9013_wr_reg(state, 0xaeff, 1);
-	if (ret)
-		goto err;
-
-	/* wait reset performs */
-	for (i = 0; i < 150; i++) {
-		ret = af9013_rd_reg_bits(state, 0xd417, 1, 1, &tmp);
-		if (ret)
-			goto err;
-
-		if (tmp)
-			break; /* reset done */
-
-		usleep_range(5000, 25000);
-	}
-
-	if (!tmp)
-		return -ETIMEDOUT;
-
-	if (onoff) {
-		/* clear reset */
-		ret = af9013_wr_reg_bits(state, 0xd417, 1, 1, 0);
-		if (ret)
-			goto err;
-
-		/* disable reset */
-		ret = af9013_wr_reg_bits(state, 0xd417, 4, 1, 0);
-
-		/* power on */
-		ret = af9013_wr_reg_bits(state, 0xd73a, 3, 1, 0);
-	} else {
-		/* power off */
-		ret = af9013_wr_reg_bits(state, 0xd73a, 3, 1, 1);
-	}
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int af9013_statistics_ber_unc_start(struct dvb_frontend *fe)
-{
-	struct af9013_state *state = fe->demodulator_priv;
-	int ret;
-
-	dbg("%s", __func__);
-
-	/* reset and start BER counter */
-	ret = af9013_wr_reg_bits(state, 0xd391, 4, 1, 1);
-	if (ret)
-		goto err;
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int af9013_statistics_ber_unc_result(struct dvb_frontend *fe)
-{
-	struct af9013_state *state = fe->demodulator_priv;
-	int ret;
-	u8 buf[5];
-
-	dbg("%s", __func__);
-
-	/* check if error bit count is ready */
-	ret = af9013_rd_reg_bits(state, 0xd391, 4, 1, &buf[0]);
-	if (ret)
-		goto err;
-
-	if (!buf[0]) {
-		dbg("%s: not ready", __func__);
-		return 0;
-	}
-
-	ret = af9013_rd_regs(state, 0xd387, buf, 5);
-	if (ret)
-		goto err;
-
-	state->ber = (buf[2] << 16) | (buf[1] << 8) | buf[0];
-	state->ucblocks += (buf[4] << 8) | buf[3];
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int af9013_statistics_snr_start(struct dvb_frontend *fe)
-{
-	struct af9013_state *state = fe->demodulator_priv;
-	int ret;
-
-	dbg("%s", __func__);
-
-	/* start SNR meas */
-	ret = af9013_wr_reg_bits(state, 0xd2e1, 3, 1, 1);
-	if (ret)
-		goto err;
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int af9013_statistics_snr_result(struct dvb_frontend *fe)
-{
-	struct af9013_state *state = fe->demodulator_priv;
-	int ret, i, len;
-	u8 buf[3], tmp;
-	u32 snr_val;
-	const struct af9013_snr *uninitialized_var(snr_lut);
-
-	dbg("%s", __func__);
-
-	/* check if SNR ready */
-	ret = af9013_rd_reg_bits(state, 0xd2e1, 3, 1, &tmp);
-	if (ret)
-		goto err;
-
-	if (!tmp) {
-		dbg("%s: not ready", __func__);
-		return 0;
-	}
-
-	/* read value */
-	ret = af9013_rd_regs(state, 0xd2e3, buf, 3);
-	if (ret)
-		goto err;
-
-	snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0];
-
-	/* read current modulation */
-	ret = af9013_rd_reg(state, 0xd3c1, &tmp);
-	if (ret)
-		goto err;
-
-	switch ((tmp >> 6) & 3) {
-	case 0:
-		len = ARRAY_SIZE(qpsk_snr_lut);
-		snr_lut = qpsk_snr_lut;
-		break;
-	case 1:
-		len = ARRAY_SIZE(qam16_snr_lut);
-		snr_lut = qam16_snr_lut;
-		break;
-	case 2:
-		len = ARRAY_SIZE(qam64_snr_lut);
-		snr_lut = qam64_snr_lut;
-		break;
-	default:
-		goto err;
-		break;
-	}
-
-	for (i = 0; i < len; i++) {
-		tmp = snr_lut[i].snr;
-
-		if (snr_val < snr_lut[i].val)
-			break;
-	}
-	state->snr = tmp * 10; /* dB/10 */
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int af9013_statistics_signal_strength(struct dvb_frontend *fe)
-{
-	struct af9013_state *state = fe->demodulator_priv;
-	int ret = 0;
-	u8 buf[2], rf_gain, if_gain;
-	int signal_strength;
-
-	dbg("%s", __func__);
-
-	if (!state->signal_strength_en)
-		return 0;
-
-	ret = af9013_rd_regs(state, 0xd07c, buf, 2);
-	if (ret)
-		goto err;
-
-	rf_gain = buf[0];
-	if_gain = buf[1];
-
-	signal_strength = (0xffff / \
-		(9 * (state->rf_50 + state->if_50) - \
-		11 * (state->rf_80 + state->if_80))) * \
-		(10 * (rf_gain + if_gain) - \
-		11 * (state->rf_80 + state->if_80));
-	if (signal_strength < 0)
-		signal_strength = 0;
-	else if (signal_strength > 0xffff)
-		signal_strength = 0xffff;
-
-	state->signal_strength = signal_strength;
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static void af9013_statistics_work(struct work_struct *work)
-{
-	struct af9013_state *state = container_of(work,
-		struct af9013_state, statistics_work.work);
-	unsigned int next_msec;
-
-	/* update only signal strength when demod is not locked */
-	if (!(state->fe_status & FE_HAS_LOCK)) {
-		state->statistics_step = 0;
-		state->ber = 0;
-		state->snr = 0;
-	}
-
-	switch (state->statistics_step) {
-	default:
-		state->statistics_step = 0;
-	case 0:
-		af9013_statistics_signal_strength(&state->fe);
-		state->statistics_step++;
-		next_msec = 300;
-		break;
-	case 1:
-		af9013_statistics_snr_start(&state->fe);
-		state->statistics_step++;
-		next_msec = 200;
-		break;
-	case 2:
-		af9013_statistics_ber_unc_start(&state->fe);
-		state->statistics_step++;
-		next_msec = 1000;
-		break;
-	case 3:
-		af9013_statistics_snr_result(&state->fe);
-		state->statistics_step++;
-		next_msec = 400;
-		break;
-	case 4:
-		af9013_statistics_ber_unc_result(&state->fe);
-		state->statistics_step++;
-		next_msec = 100;
-		break;
-	}
-
-	schedule_delayed_work(&state->statistics_work,
-		msecs_to_jiffies(next_msec));
-}
-
-static int af9013_get_tune_settings(struct dvb_frontend *fe,
-	struct dvb_frontend_tune_settings *fesettings)
-{
-	fesettings->min_delay_ms = 800;
-	fesettings->step_size = 0;
-	fesettings->max_drift = 0;
-
-	return 0;
-}
-
-static int af9013_set_frontend(struct dvb_frontend *fe)
-{
-	struct af9013_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret, i, sampling_freq;
-	bool auto_mode, spec_inv;
-	u8 buf[6];
-	u32 if_frequency, freq_cw;
-
-	dbg("%s: frequency=%d bandwidth_hz=%d", __func__,
-		c->frequency, c->bandwidth_hz);
-
-	/* program tuner */
-	if (fe->ops.tuner_ops.set_params)
-		fe->ops.tuner_ops.set_params(fe);
-
-	/* program CFOE coefficients */
-	if (c->bandwidth_hz != state->bandwidth_hz) {
-		for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) {
-			if (coeff_lut[i].clock == state->config.clock &&
-				coeff_lut[i].bandwidth_hz == c->bandwidth_hz) {
-				break;
-			}
-		}
-
-		ret = af9013_wr_regs(state, 0xae00, coeff_lut[i].val,
-			sizeof(coeff_lut[i].val));
-	}
-
-	/* program frequency control */
-	if (c->bandwidth_hz != state->bandwidth_hz || state->first_tune) {
-		/* get used IF frequency */
-		if (fe->ops.tuner_ops.get_if_frequency)
-			fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
-		else
-			if_frequency = state->config.if_frequency;
-
-		sampling_freq = if_frequency;
-
-		while (sampling_freq > (state->config.clock / 2))
-			sampling_freq -= state->config.clock;
-
-		if (sampling_freq < 0) {
-			sampling_freq *= -1;
-			spec_inv = state->config.spec_inv;
-		} else {
-			spec_inv = !state->config.spec_inv;
-		}
-
-		freq_cw = af913_div(sampling_freq, state->config.clock, 23);
-
-		if (spec_inv)
-			freq_cw = 0x800000 - freq_cw;
-
-		buf[0] = (freq_cw >>  0) & 0xff;
-		buf[1] = (freq_cw >>  8) & 0xff;
-		buf[2] = (freq_cw >> 16) & 0x7f;
-
-		freq_cw = 0x800000 - freq_cw;
-
-		buf[3] = (freq_cw >>  0) & 0xff;
-		buf[4] = (freq_cw >>  8) & 0xff;
-		buf[5] = (freq_cw >> 16) & 0x7f;
-
-		ret = af9013_wr_regs(state, 0xd140, buf, 3);
-		if (ret)
-			goto err;
-
-		ret = af9013_wr_regs(state, 0x9be7, buf, 6);
-		if (ret)
-			goto err;
-	}
-
-	/* clear TPS lock flag */
-	ret = af9013_wr_reg_bits(state, 0xd330, 3, 1, 1);
-	if (ret)
-		goto err;
-
-	/* clear MPEG2 lock flag */
-	ret = af9013_wr_reg_bits(state, 0xd507, 6, 1, 0);
-	if (ret)
-		goto err;
-
-	/* empty channel function */
-	ret = af9013_wr_reg_bits(state, 0x9bfe, 0, 1, 0);
-	if (ret)
-		goto err;
-
-	/* empty DVB-T channel function */
-	ret = af9013_wr_reg_bits(state, 0x9bc2, 0, 1, 0);
-	if (ret)
-		goto err;
-
-	/* transmission parameters */
-	auto_mode = false;
-	memset(buf, 0, 3);
-
-	switch (c->transmission_mode) {
-	case TRANSMISSION_MODE_AUTO:
-		auto_mode = 1;
-		break;
-	case TRANSMISSION_MODE_2K:
-		break;
-	case TRANSMISSION_MODE_8K:
-		buf[0] |= (1 << 0);
-		break;
-	default:
-		dbg("%s: invalid transmission_mode", __func__);
-		auto_mode = 1;
-	}
-
-	switch (c->guard_interval) {
-	case GUARD_INTERVAL_AUTO:
-		auto_mode = 1;
-		break;
-	case GUARD_INTERVAL_1_32:
-		break;
-	case GUARD_INTERVAL_1_16:
-		buf[0] |= (1 << 2);
-		break;
-	case GUARD_INTERVAL_1_8:
-		buf[0] |= (2 << 2);
-		break;
-	case GUARD_INTERVAL_1_4:
-		buf[0] |= (3 << 2);
-		break;
-	default:
-		dbg("%s: invalid guard_interval", __func__);
-		auto_mode = 1;
-	}
-
-	switch (c->hierarchy) {
-	case HIERARCHY_AUTO:
-		auto_mode = 1;
-		break;
-	case HIERARCHY_NONE:
-		break;
-	case HIERARCHY_1:
-		buf[0] |= (1 << 4);
-		break;
-	case HIERARCHY_2:
-		buf[0] |= (2 << 4);
-		break;
-	case HIERARCHY_4:
-		buf[0] |= (3 << 4);
-		break;
-	default:
-		dbg("%s: invalid hierarchy", __func__);
-		auto_mode = 1;
-	};
-
-	switch (c->modulation) {
-	case QAM_AUTO:
-		auto_mode = 1;
-		break;
-	case QPSK:
-		break;
-	case QAM_16:
-		buf[1] |= (1 << 6);
-		break;
-	case QAM_64:
-		buf[1] |= (2 << 6);
-		break;
-	default:
-		dbg("%s: invalid modulation", __func__);
-		auto_mode = 1;
-	}
-
-	/* Use HP. How and which case we can switch to LP? */
-	buf[1] |= (1 << 4);
-
-	switch (c->code_rate_HP) {
-	case FEC_AUTO:
-		auto_mode = 1;
-		break;
-	case FEC_1_2:
-		break;
-	case FEC_2_3:
-		buf[2] |= (1 << 0);
-		break;
-	case FEC_3_4:
-		buf[2] |= (2 << 0);
-		break;
-	case FEC_5_6:
-		buf[2] |= (3 << 0);
-		break;
-	case FEC_7_8:
-		buf[2] |= (4 << 0);
-		break;
-	default:
-		dbg("%s: invalid code_rate_HP", __func__);
-		auto_mode = 1;
-	}
-
-	switch (c->code_rate_LP) {
-	case FEC_AUTO:
-		auto_mode = 1;
-		break;
-	case FEC_1_2:
-		break;
-	case FEC_2_3:
-		buf[2] |= (1 << 3);
-		break;
-	case FEC_3_4:
-		buf[2] |= (2 << 3);
-		break;
-	case FEC_5_6:
-		buf[2] |= (3 << 3);
-		break;
-	case FEC_7_8:
-		buf[2] |= (4 << 3);
-		break;
-	case FEC_NONE:
-		break;
-	default:
-		dbg("%s: invalid code_rate_LP", __func__);
-		auto_mode = 1;
-	}
-
-	switch (c->bandwidth_hz) {
-	case 6000000:
-		break;
-	case 7000000:
-		buf[1] |= (1 << 2);
-		break;
-	case 8000000:
-		buf[1] |= (2 << 2);
-		break;
-	default:
-		dbg("%s: invalid bandwidth_hz", __func__);
-		ret = -EINVAL;
-		goto err;
-	}
-
-	ret = af9013_wr_regs(state, 0xd3c0, buf, 3);
-	if (ret)
-		goto err;
-
-	if (auto_mode) {
-		/* clear easy mode flag */
-		ret = af9013_wr_reg(state, 0xaefd, 0);
-		if (ret)
-			goto err;
-
-		dbg("%s: auto params", __func__);
-	} else {
-		/* set easy mode flag */
-		ret = af9013_wr_reg(state, 0xaefd, 1);
-		if (ret)
-			goto err;
-
-		ret = af9013_wr_reg(state, 0xaefe, 0);
-		if (ret)
-			goto err;
-
-		dbg("%s: manual params", __func__);
-	}
-
-	/* tune */
-	ret = af9013_wr_reg(state, 0xffff, 0);
-	if (ret)
-		goto err;
-
-	state->bandwidth_hz = c->bandwidth_hz;
-	state->set_frontend_jiffies = jiffies;
-	state->first_tune = false;
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int af9013_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct af9013_state *state = fe->demodulator_priv;
-	int ret;
-	u8 buf[3];
-
-	dbg("%s", __func__);
-
-	ret = af9013_rd_regs(state, 0xd3c0, buf, 3);
-	if (ret)
-		goto err;
-
-	switch ((buf[1] >> 6) & 3) {
-	case 0:
-		c->modulation = QPSK;
-		break;
-	case 1:
-		c->modulation = QAM_16;
-		break;
-	case 2:
-		c->modulation = QAM_64;
-		break;
-	}
-
-	switch ((buf[0] >> 0) & 3) {
-	case 0:
-		c->transmission_mode = TRANSMISSION_MODE_2K;
-		break;
-	case 1:
-		c->transmission_mode = TRANSMISSION_MODE_8K;
-	}
-
-	switch ((buf[0] >> 2) & 3) {
-	case 0:
-		c->guard_interval = GUARD_INTERVAL_1_32;
-		break;
-	case 1:
-		c->guard_interval = GUARD_INTERVAL_1_16;
-		break;
-	case 2:
-		c->guard_interval = GUARD_INTERVAL_1_8;
-		break;
-	case 3:
-		c->guard_interval = GUARD_INTERVAL_1_4;
-		break;
-	}
-
-	switch ((buf[0] >> 4) & 7) {
-	case 0:
-		c->hierarchy = HIERARCHY_NONE;
-		break;
-	case 1:
-		c->hierarchy = HIERARCHY_1;
-		break;
-	case 2:
-		c->hierarchy = HIERARCHY_2;
-		break;
-	case 3:
-		c->hierarchy = HIERARCHY_4;
-		break;
-	}
-
-	switch ((buf[2] >> 0) & 7) {
-	case 0:
-		c->code_rate_HP = FEC_1_2;
-		break;
-	case 1:
-		c->code_rate_HP = FEC_2_3;
-		break;
-	case 2:
-		c->code_rate_HP = FEC_3_4;
-		break;
-	case 3:
-		c->code_rate_HP = FEC_5_6;
-		break;
-	case 4:
-		c->code_rate_HP = FEC_7_8;
-		break;
-	}
-
-	switch ((buf[2] >> 3) & 7) {
-	case 0:
-		c->code_rate_LP = FEC_1_2;
-		break;
-	case 1:
-		c->code_rate_LP = FEC_2_3;
-		break;
-	case 2:
-		c->code_rate_LP = FEC_3_4;
-		break;
-	case 3:
-		c->code_rate_LP = FEC_5_6;
-		break;
-	case 4:
-		c->code_rate_LP = FEC_7_8;
-		break;
-	}
-
-	switch ((buf[1] >> 2) & 3) {
-	case 0:
-		c->bandwidth_hz = 6000000;
-		break;
-	case 1:
-		c->bandwidth_hz = 7000000;
-		break;
-	case 2:
-		c->bandwidth_hz = 8000000;
-		break;
-	}
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct af9013_state *state = fe->demodulator_priv;
-	int ret;
-	u8 tmp;
-
-	/*
-	 * Return status from the cache if it is younger than 2000ms with the
-	 * exception of last tune is done during 4000ms.
-	 */
-	if (time_is_after_jiffies(
-		state->read_status_jiffies + msecs_to_jiffies(2000)) &&
-		time_is_before_jiffies(
-		state->set_frontend_jiffies + msecs_to_jiffies(4000))
-	) {
-			*status = state->fe_status;
-			return 0;
-	} else {
-		*status = 0;
-	}
-
-	/* MPEG2 lock */
-	ret = af9013_rd_reg_bits(state, 0xd507, 6, 1, &tmp);
-	if (ret)
-		goto err;
-
-	if (tmp)
-		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
-			FE_HAS_SYNC | FE_HAS_LOCK;
-
-	if (!*status) {
-		/* TPS lock */
-		ret = af9013_rd_reg_bits(state, 0xd330, 3, 1, &tmp);
-		if (ret)
-			goto err;
-
-		if (tmp)
-			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-				FE_HAS_VITERBI;
-	}
-
-	state->fe_status = *status;
-	state->read_status_jiffies = jiffies;
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct af9013_state *state = fe->demodulator_priv;
-	*snr = state->snr;
-	return 0;
-}
-
-static int af9013_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct af9013_state *state = fe->demodulator_priv;
-	*strength = state->signal_strength;
-	return 0;
-}
-
-static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct af9013_state *state = fe->demodulator_priv;
-	*ber = state->ber;
-	return 0;
-}
-
-static int af9013_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct af9013_state *state = fe->demodulator_priv;
-	*ucblocks = state->ucblocks;
-	return 0;
-}
-
-static int af9013_init(struct dvb_frontend *fe)
-{
-	struct af9013_state *state = fe->demodulator_priv;
-	int ret, i, len;
-	u8 buf[3], tmp;
-	u32 adc_cw;
-	const struct af9013_reg_bit *init;
-
-	dbg("%s", __func__);
-
-	/* power on */
-	ret = af9013_power_ctrl(state, 1);
-	if (ret)
-		goto err;
-
-	/* enable ADC */
-	ret = af9013_wr_reg(state, 0xd73a, 0xa4);
-	if (ret)
-		goto err;
-
-	/* write API version to firmware */
-	ret = af9013_wr_regs(state, 0x9bf2, state->config.api_version, 4);
-	if (ret)
-		goto err;
-
-	/* program ADC control */
-	switch (state->config.clock) {
-	case 28800000: /* 28.800 MHz */
-		tmp = 0;
-		break;
-	case 20480000: /* 20.480 MHz */
-		tmp = 1;
-		break;
-	case 28000000: /* 28.000 MHz */
-		tmp = 2;
-		break;
-	case 25000000: /* 25.000 MHz */
-		tmp = 3;
-		break;
-	default:
-		err("invalid clock");
-		return -EINVAL;
-	}
-
-	adc_cw = af913_div(state->config.clock, 1000000ul, 19);
-	buf[0] = (adc_cw >>  0) & 0xff;
-	buf[1] = (adc_cw >>  8) & 0xff;
-	buf[2] = (adc_cw >> 16) & 0xff;
-
-	ret = af9013_wr_regs(state, 0xd180, buf, 3);
-	if (ret)
-		goto err;
-
-	ret = af9013_wr_reg_bits(state, 0x9bd2, 0, 4, tmp);
-	if (ret)
-		goto err;
-
-	/* set I2C master clock */
-	ret = af9013_wr_reg(state, 0xd416, 0x14);
-	if (ret)
-		goto err;
-
-	/* set 16 embx */
-	ret = af9013_wr_reg_bits(state, 0xd700, 1, 1, 1);
-	if (ret)
-		goto err;
-
-	/* set no trigger */
-	ret = af9013_wr_reg_bits(state, 0xd700, 2, 1, 0);
-	if (ret)
-		goto err;
-
-	/* set read-update bit for constellation */
-	ret = af9013_wr_reg_bits(state, 0xd371, 1, 1, 1);
-	if (ret)
-		goto err;
-
-	/* settings for mp2if */
-	if (state->config.ts_mode == AF9013_TS_USB) {
-		/* AF9015 split PSB to 1.5k + 0.5k */
-		ret = af9013_wr_reg_bits(state, 0xd50b, 2, 1, 1);
-		if (ret)
-			goto err;
-	} else {
-		/* AF9013 change the output bit to data7 */
-		ret = af9013_wr_reg_bits(state, 0xd500, 3, 1, 1);
-		if (ret)
-			goto err;
-
-		/* AF9013 set mpeg to full speed */
-		ret = af9013_wr_reg_bits(state, 0xd502, 4, 1, 1);
-		if (ret)
-			goto err;
-	}
-
-	ret = af9013_wr_reg_bits(state, 0xd520, 4, 1, 1);
-	if (ret)
-		goto err;
-
-	/* load OFSM settings */
-	dbg("%s: load ofsm settings", __func__);
-	len = ARRAY_SIZE(ofsm_init);
-	init = ofsm_init;
-	for (i = 0; i < len; i++) {
-		ret = af9013_wr_reg_bits(state, init[i].addr, init[i].pos,
-			init[i].len, init[i].val);
-		if (ret)
-			goto err;
-	}
-
-	/* load tuner specific settings */
-	dbg("%s: load tuner specific settings", __func__);
-	switch (state->config.tuner) {
-	case AF9013_TUNER_MXL5003D:
-		len = ARRAY_SIZE(tuner_init_mxl5003d);
-		init = tuner_init_mxl5003d;
-		break;
-	case AF9013_TUNER_MXL5005D:
-	case AF9013_TUNER_MXL5005R:
-	case AF9013_TUNER_MXL5007T:
-		len = ARRAY_SIZE(tuner_init_mxl5005);
-		init = tuner_init_mxl5005;
-		break;
-	case AF9013_TUNER_ENV77H11D5:
-		len = ARRAY_SIZE(tuner_init_env77h11d5);
-		init = tuner_init_env77h11d5;
-		break;
-	case AF9013_TUNER_MT2060:
-		len = ARRAY_SIZE(tuner_init_mt2060);
-		init = tuner_init_mt2060;
-		break;
-	case AF9013_TUNER_MC44S803:
-		len = ARRAY_SIZE(tuner_init_mc44s803);
-		init = tuner_init_mc44s803;
-		break;
-	case AF9013_TUNER_QT1010:
-	case AF9013_TUNER_QT1010A:
-		len = ARRAY_SIZE(tuner_init_qt1010);
-		init = tuner_init_qt1010;
-		break;
-	case AF9013_TUNER_MT2060_2:
-		len = ARRAY_SIZE(tuner_init_mt2060_2);
-		init = tuner_init_mt2060_2;
-		break;
-	case AF9013_TUNER_TDA18271:
-	case AF9013_TUNER_TDA18218:
-		len = ARRAY_SIZE(tuner_init_tda18271);
-		init = tuner_init_tda18271;
-		break;
-	case AF9013_TUNER_UNKNOWN:
-	default:
-		len = ARRAY_SIZE(tuner_init_unknown);
-		init = tuner_init_unknown;
-		break;
-	}
-
-	for (i = 0; i < len; i++) {
-		ret = af9013_wr_reg_bits(state, init[i].addr, init[i].pos,
-			init[i].len, init[i].val);
-		if (ret)
-			goto err;
-	}
-
-	/* TS mode */
-	ret = af9013_wr_reg_bits(state, 0xd500, 1, 2, state->config.ts_mode);
-	if (ret)
-		goto err;
-
-	/* enable lock led */
-	ret = af9013_wr_reg_bits(state, 0xd730, 0, 1, 1);
-	if (ret)
-		goto err;
-
-	/* check if we support signal strength */
-	if (!state->signal_strength_en) {
-		ret = af9013_rd_reg_bits(state, 0x9bee, 0, 1,
-			&state->signal_strength_en);
-		if (ret)
-			goto err;
-	}
-
-	/* read values needed for signal strength calculation */
-	if (state->signal_strength_en && !state->rf_50) {
-		ret = af9013_rd_reg(state, 0x9bbd, &state->rf_50);
-		if (ret)
-			goto err;
-
-		ret = af9013_rd_reg(state, 0x9bd0, &state->rf_80);
-		if (ret)
-			goto err;
-
-		ret = af9013_rd_reg(state, 0x9be2, &state->if_50);
-		if (ret)
-			goto err;
-
-		ret = af9013_rd_reg(state, 0x9be4, &state->if_80);
-		if (ret)
-			goto err;
-	}
-
-	/* SNR */
-	ret = af9013_wr_reg(state, 0xd2e2, 1);
-	if (ret)
-		goto err;
-
-	/* BER / UCB */
-	buf[0] = (10000 >> 0) & 0xff;
-	buf[1] = (10000 >> 8) & 0xff;
-	ret = af9013_wr_regs(state, 0xd385, buf, 2);
-	if (ret)
-		goto err;
-
-	/* enable FEC monitor */
-	ret = af9013_wr_reg_bits(state, 0xd392, 1, 1, 1);
-	if (ret)
-		goto err;
-
-	state->first_tune = true;
-	schedule_delayed_work(&state->statistics_work, msecs_to_jiffies(400));
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int af9013_sleep(struct dvb_frontend *fe)
-{
-	struct af9013_state *state = fe->demodulator_priv;
-	int ret;
-
-	dbg("%s", __func__);
-
-	/* stop statistics polling */
-	cancel_delayed_work_sync(&state->statistics_work);
-
-	/* disable lock led */
-	ret = af9013_wr_reg_bits(state, 0xd730, 0, 1, 0);
-	if (ret)
-		goto err;
-
-	/* power off */
-	ret = af9013_power_ctrl(state, 0);
-	if (ret)
-		goto err;
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	int ret;
-	struct af9013_state *state = fe->demodulator_priv;
-
-	dbg("%s: enable=%d", __func__, enable);
-
-	/* gate already open or close */
-	if (state->i2c_gate_state == enable)
-		return 0;
-
-	if (state->config.ts_mode == AF9013_TS_USB)
-		ret = af9013_wr_reg_bits(state, 0xd417, 3, 1, enable);
-	else
-		ret = af9013_wr_reg_bits(state, 0xd607, 2, 1, enable);
-	if (ret)
-		goto err;
-
-	state->i2c_gate_state = enable;
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static void af9013_release(struct dvb_frontend *fe)
-{
-	struct af9013_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops af9013_ops;
-
-static int af9013_download_firmware(struct af9013_state *state)
-{
-	int i, len, remaining, ret;
-	const struct firmware *fw;
-	u16 checksum = 0;
-	u8 val;
-	u8 fw_params[4];
-	u8 *fw_file = AF9013_DEFAULT_FIRMWARE;
-
-	msleep(100);
-	/* check whether firmware is already running */
-	ret = af9013_rd_reg(state, 0x98be, &val);
-	if (ret)
-		goto err;
-	else
-		dbg("%s: firmware status=%02x", __func__, val);
-
-	if (val == 0x0c) /* fw is running, no need for download */
-		goto exit;
-
-	info("found a '%s' in cold state, will try to load a firmware",
-		af9013_ops.info.name);
-
-	/* request the firmware, this will block and timeout */
-	ret = request_firmware(&fw, fw_file, state->i2c->dev.parent);
-	if (ret) {
-		err("did not find the firmware file. (%s) "
-			"Please see linux/Documentation/dvb/ for more details" \
-			" on firmware-problems. (%d)",
-			fw_file, ret);
-		goto err;
-	}
-
-	info("downloading firmware from file '%s'", fw_file);
-
-	/* calc checksum */
-	for (i = 0; i < fw->size; i++)
-		checksum += fw->data[i];
-
-	fw_params[0] = checksum >> 8;
-	fw_params[1] = checksum & 0xff;
-	fw_params[2] = fw->size >> 8;
-	fw_params[3] = fw->size & 0xff;
-
-	/* write fw checksum & size */
-	ret = af9013_write_ofsm_regs(state, 0x50fc,
-		fw_params, sizeof(fw_params));
-	if (ret)
-		goto err_release;
-
-	#define FW_ADDR 0x5100 /* firmware start address */
-	#define LEN_MAX 16 /* max packet size */
-	for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) {
-		len = remaining;
-		if (len > LEN_MAX)
-			len = LEN_MAX;
-
-		ret = af9013_write_ofsm_regs(state,
-			FW_ADDR + fw->size - remaining,
-			(u8 *) &fw->data[fw->size - remaining], len);
-		if (ret) {
-			err("firmware download failed:%d", ret);
-			goto err_release;
-		}
-	}
-
-	/* request boot firmware */
-	ret = af9013_wr_reg(state, 0xe205, 1);
-	if (ret)
-		goto err_release;
-
-	for (i = 0; i < 15; i++) {
-		msleep(100);
-
-		/* check firmware status */
-		ret = af9013_rd_reg(state, 0x98be, &val);
-		if (ret)
-			goto err_release;
-
-		dbg("%s: firmware status=%02x", __func__, val);
-
-		if (val == 0x0c || val == 0x04) /* success or fail */
-			break;
-	}
-
-	if (val == 0x04) {
-		err("firmware did not run");
-		ret = -ENODEV;
-	} else if (val != 0x0c) {
-		err("firmware boot timeout");
-		ret = -ENODEV;
-	}
-
-err_release:
-	release_firmware(fw);
-err:
-exit:
-	if (!ret)
-		info("found a '%s' in warm state.", af9013_ops.info.name);
-	return ret;
-}
-
-struct dvb_frontend *af9013_attach(const struct af9013_config *config,
-	struct i2c_adapter *i2c)
-{
-	int ret;
-	struct af9013_state *state = NULL;
-	u8 buf[4], i;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct af9013_state), GFP_KERNEL);
-	if (state == NULL)
-		goto err;
-
-	/* setup the state */
-	state->i2c = i2c;
-	memcpy(&state->config, config, sizeof(struct af9013_config));
-
-	/* download firmware */
-	if (state->config.ts_mode != AF9013_TS_USB) {
-		ret = af9013_download_firmware(state);
-		if (ret)
-			goto err;
-	}
-
-	/* firmware version */
-	ret = af9013_rd_regs(state, 0x5103, buf, 4);
-	if (ret)
-		goto err;
-
-	info("firmware version %d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]);
-
-	/* set GPIOs */
-	for (i = 0; i < sizeof(state->config.gpio); i++) {
-		ret = af9013_set_gpio(state, i, state->config.gpio[i]);
-		if (ret)
-			goto err;
-	}
-
-	/* create dvb_frontend */
-	memcpy(&state->fe.ops, &af9013_ops,
-		sizeof(struct dvb_frontend_ops));
-	state->fe.demodulator_priv = state;
-
-	INIT_DELAYED_WORK(&state->statistics_work, af9013_statistics_work);
-
-	return &state->fe;
-err:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(af9013_attach);
-
-static struct dvb_frontend_ops af9013_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name = "Afatech AF9013",
-		.frequency_min = 174000000,
-		.frequency_max = 862000000,
-		.frequency_stepsize = 250000,
-		.frequency_tolerance = 0,
-		.caps =	FE_CAN_FEC_1_2 |
-			FE_CAN_FEC_2_3 |
-			FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 |
-			FE_CAN_FEC_7_8 |
-			FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK |
-			FE_CAN_QAM_16 |
-			FE_CAN_QAM_64 |
-			FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_HIERARCHY_AUTO |
-			FE_CAN_RECOVER |
-			FE_CAN_MUTE_TS
-	},
-
-	.release = af9013_release,
-
-	.init = af9013_init,
-	.sleep = af9013_sleep,
-
-	.get_tune_settings = af9013_get_tune_settings,
-	.set_frontend = af9013_set_frontend,
-	.get_frontend = af9013_get_frontend,
-
-	.read_status = af9013_read_status,
-	.read_snr = af9013_read_snr,
-	.read_signal_strength = af9013_read_signal_strength,
-	.read_ber = af9013_read_ber,
-	.read_ucblocks = af9013_read_ucblocks,
-
-	.i2c_gate_ctrl = af9013_i2c_gate_ctrl,
-};
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Afatech AF9013 DVB-T demodulator driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/af9013.h b/drivers/media/dvb/frontends/af9013.h
deleted file mode 100644
index b973fc5..0000000
--- a/drivers/media/dvb/frontends/af9013.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Afatech AF9013 demodulator driver
- *
- * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
- * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
- *
- * Thanks to Afatech who kindly provided information.
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef AF9013_H
-#define AF9013_H
-
-#include <linux/dvb/frontend.h>
-
-/* AF9013/5 GPIOs (mostly guessed)
-   demod#1-gpio#0 - set demod#2 i2c-addr for dual devices
-   demod#1-gpio#1 - xtal setting (?)
-   demod#1-gpio#3 - tuner#1
-   demod#2-gpio#0 - tuner#2
-   demod#2-gpio#1 - xtal setting (?)
-*/
-
-struct af9013_config {
-	/*
-	 * I2C address
-	 */
-	u8 i2c_addr;
-
-	/*
-	 * clock
-	 * 20480000, 25000000, 28000000, 28800000
-	 */
-	u32 clock;
-
-	/*
-	 * tuner
-	 */
-#define AF9013_TUNER_MXL5003D      3 /* MaxLinear */
-#define AF9013_TUNER_MXL5005D     13 /* MaxLinear */
-#define AF9013_TUNER_MXL5005R     30 /* MaxLinear */
-#define AF9013_TUNER_ENV77H11D5  129 /* Panasonic */
-#define AF9013_TUNER_MT2060      130 /* Microtune */
-#define AF9013_TUNER_MC44S803    133 /* Freescale */
-#define AF9013_TUNER_QT1010      134 /* Quantek */
-#define AF9013_TUNER_UNKNOWN     140 /* for can tuners ? */
-#define AF9013_TUNER_MT2060_2    147 /* Microtune */
-#define AF9013_TUNER_TDA18271    156 /* NXP */
-#define AF9013_TUNER_QT1010A     162 /* Quantek */
-#define AF9013_TUNER_MXL5007T    177 /* MaxLinear */
-#define AF9013_TUNER_TDA18218    179 /* NXP */
-	u8 tuner;
-
-	/*
-	 * IF frequency
-	 */
-	u32 if_frequency;
-
-	/*
-	 * TS settings
-	 */
-#define AF9013_TS_USB       0
-#define AF9013_TS_PARALLEL  1
-#define AF9013_TS_SERIAL    2
-	u8 ts_mode:2;
-
-	/*
-	 * input spectrum inversion
-	 */
-	bool spec_inv;
-
-	/*
-	 * firmware API version
-	 */
-	u8 api_version[4];
-
-	/*
-	 * GPIOs
-	 */
-#define AF9013_GPIO_ON (1 << 0)
-#define AF9013_GPIO_EN (1 << 1)
-#define AF9013_GPIO_O  (1 << 2)
-#define AF9013_GPIO_I  (1 << 3)
-#define AF9013_GPIO_LO (AF9013_GPIO_ON|AF9013_GPIO_EN)
-#define AF9013_GPIO_HI (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O)
-#define AF9013_GPIO_TUNER_ON  (AF9013_GPIO_ON|AF9013_GPIO_EN)
-#define AF9013_GPIO_TUNER_OFF (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O)
-	u8 gpio[4];
-};
-
-#if defined(CONFIG_DVB_AF9013) || \
-	(defined(CONFIG_DVB_AF9013_MODULE) && defined(MODULE))
-extern struct dvb_frontend *af9013_attach(const struct af9013_config *config,
-	struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *af9013_attach(
-const struct af9013_config *config, struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_AF9013 */
-
-#endif /* AF9013_H */
diff --git a/drivers/media/dvb/frontends/af9013_priv.h b/drivers/media/dvb/frontends/af9013_priv.h
deleted file mode 100644
index fa848af..0000000
--- a/drivers/media/dvb/frontends/af9013_priv.h
+++ /dev/null
@@ -1,922 +0,0 @@
-/*
- * Afatech AF9013 demodulator driver
- *
- * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
- * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
- *
- * Thanks to Afatech who kindly provided information.
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef AF9013_PRIV_H
-#define AF9013_PRIV_H
-
-#include "dvb_frontend.h"
-#include "af9013.h"
-#include <linux/firmware.h>
-
-#define LOG_PREFIX "af9013"
-
-#undef dbg
-#define dbg(f, arg...) \
-	if (af9013_debug) \
-		printk(KERN_INFO   LOG_PREFIX": " f "\n" , ## arg)
-#undef err
-#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
-#undef info
-#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
-#undef warn
-#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
-
-#define AF9013_DEFAULT_FIRMWARE     "dvb-fe-af9013.fw"
-
-struct af9013_reg_bit {
-	u16 addr;
-	u8  pos:4;
-	u8  len:4;
-	u8  val;
-};
-
-struct af9013_snr {
-	u32 val;
-	u8 snr;
-};
-
-struct af9013_coeff {
-	u32 clock;
-	u32 bandwidth_hz;
-	u8 val[24];
-};
-
-/* pre-calculated coeff lookup table */
-static const struct af9013_coeff coeff_lut[] = {
-	/* 28.800 MHz */
-	{ 28800000, 8000000, { 0x02, 0x8a, 0x28, 0xa3, 0x05, 0x14,
-		0x51, 0x11, 0x00, 0xa2, 0x8f, 0x3d, 0x00, 0xa2, 0x8a,
-		0x29, 0x00, 0xa2, 0x85, 0x14, 0x01, 0x45, 0x14, 0x14 } },
-	{ 28800000, 7000000, { 0x02, 0x38, 0xe3, 0x8e, 0x04, 0x71,
-		0xc7, 0x07, 0x00, 0x8e, 0x3d, 0x55, 0x00, 0x8e, 0x38,
-		0xe4, 0x00, 0x8e, 0x34, 0x72, 0x01, 0x1c, 0x71, 0x32 } },
-	{ 28800000, 6000000, { 0x01, 0xe7, 0x9e, 0x7a, 0x03, 0xcf,
-		0x3c, 0x3d, 0x00, 0x79, 0xeb, 0x6e, 0x00, 0x79, 0xe7,
-		0x9e, 0x00, 0x79, 0xe3, 0xcf, 0x00, 0xf3, 0xcf, 0x0f } },
-	/* 20.480 MHz */
-	{ 20480000, 8000000, { 0x03, 0x92, 0x49, 0x26, 0x07, 0x24,
-		0x92, 0x13, 0x00, 0xe4, 0x99, 0x6e, 0x00, 0xe4, 0x92,
-		0x49, 0x00, 0xe4, 0x8b, 0x25, 0x01, 0xc9, 0x24, 0x25 } },
-	{ 20480000, 7000000, { 0x03, 0x20, 0x00, 0x01, 0x06, 0x40,
-		0x00, 0x00, 0x00, 0xc8, 0x06, 0x40, 0x00, 0xc8, 0x00,
-		0x00, 0x00, 0xc7, 0xf9, 0xc0, 0x01, 0x90, 0x00, 0x00 } },
-	{ 20480000, 6000000, { 0x02, 0xad, 0xb6, 0xdc, 0x05, 0x5b,
-		0x6d, 0x2e, 0x00, 0xab, 0x73, 0x13, 0x00, 0xab, 0x6d,
-		0xb7, 0x00, 0xab, 0x68, 0x5c, 0x01, 0x56, 0xdb, 0x1c } },
-	/* 28.000 MHz */
-	{ 28000000, 8000000, { 0x02, 0x9c, 0xbc, 0x15, 0x05, 0x39,
-		0x78, 0x0a, 0x00, 0xa7, 0x34, 0x3f, 0x00, 0xa7, 0x2f,
-		0x05, 0x00, 0xa7, 0x29, 0xcc, 0x01, 0x4e, 0x5e, 0x03 } },
-	{ 28000000, 7000000, { 0x02, 0x49, 0x24, 0x92, 0x04, 0x92,
-		0x49, 0x09, 0x00, 0x92, 0x4d, 0xb7, 0x00, 0x92, 0x49,
-		0x25, 0x00, 0x92, 0x44, 0x92, 0x01, 0x24, 0x92, 0x12 } },
-	{ 28000000, 6000000, { 0x01, 0xf5, 0x8d, 0x10, 0x03, 0xeb,
-		0x1a, 0x08, 0x00, 0x7d, 0x67, 0x2f, 0x00, 0x7d, 0x63,
-		0x44, 0x00, 0x7d, 0x5f, 0x59, 0x00, 0xfa, 0xc6, 0x22 } },
-	/* 25.000 MHz */
-	{ 25000000, 8000000, { 0x02, 0xec, 0xfb, 0x9d, 0x05, 0xd9,
-		0xf7, 0x0e, 0x00, 0xbb, 0x44, 0xc1, 0x00, 0xbb, 0x3e,
-		0xe7, 0x00, 0xbb, 0x39, 0x0d, 0x01, 0x76, 0x7d, 0x34 } },
-	{ 25000000, 7000000, { 0x02, 0x8f, 0x5c, 0x29, 0x05, 0x1e,
-		0xb8, 0x14, 0x00, 0xa3, 0xdc, 0x29, 0x00, 0xa3, 0xd7,
-		0x0a, 0x00, 0xa3, 0xd1, 0xec, 0x01, 0x47, 0xae, 0x05 } },
-	{ 25000000, 6000000, { 0x02, 0x31, 0xbc, 0xb5, 0x04, 0x63,
-		0x79, 0x1b, 0x00, 0x8c, 0x73, 0x91, 0x00, 0x8c, 0x6f,
-		0x2d, 0x00, 0x8c, 0x6a, 0xca, 0x01, 0x18, 0xde, 0x17 } },
-};
-
-/* QPSK SNR lookup table */
-static const struct af9013_snr qpsk_snr_lut[] = {
-	{ 0x000000,  0 },
-	{ 0x0b4771,  0 },
-	{ 0x0c1aed,  1 },
-	{ 0x0d0d27,  2 },
-	{ 0x0e4d19,  3 },
-	{ 0x0e5da8,  4 },
-	{ 0x107097,  5 },
-	{ 0x116975,  6 },
-	{ 0x1252d9,  7 },
-	{ 0x131fa4,  8 },
-	{ 0x13d5e1,  9 },
-	{ 0x148e53, 10 },
-	{ 0x15358b, 11 },
-	{ 0x15dd29, 12 },
-	{ 0x168112, 13 },
-	{ 0x170b61, 14 },
-	{ 0xffffff, 15 },
-};
-
-/* QAM16 SNR lookup table */
-static const struct af9013_snr qam16_snr_lut[] = {
-	{ 0x000000,  0 },
-	{ 0x05eb62,  5 },
-	{ 0x05fecf,  6 },
-	{ 0x060b80,  7 },
-	{ 0x062501,  8 },
-	{ 0x064865,  9 },
-	{ 0x069604, 10 },
-	{ 0x06f356, 11 },
-	{ 0x07706a, 12 },
-	{ 0x0804d3, 13 },
-	{ 0x089d1a, 14 },
-	{ 0x093e3d, 15 },
-	{ 0x09e35d, 16 },
-	{ 0x0a7c3c, 17 },
-	{ 0x0afaf8, 18 },
-	{ 0x0b719d, 19 },
-	{ 0xffffff, 20 },
-};
-
-/* QAM64 SNR lookup table */
-static const struct af9013_snr qam64_snr_lut[] = {
-	{ 0x000000,  0 },
-	{ 0x03109b, 12 },
-	{ 0x0310d4, 13 },
-	{ 0x031920, 14 },
-	{ 0x0322d0, 15 },
-	{ 0x0339fc, 16 },
-	{ 0x0364a1, 17 },
-	{ 0x038bcc, 18 },
-	{ 0x03c7d3, 19 },
-	{ 0x0408cc, 20 },
-	{ 0x043bed, 21 },
-	{ 0x048061, 22 },
-	{ 0x04be95, 23 },
-	{ 0x04fa7d, 24 },
-	{ 0x052405, 25 },
-	{ 0x05570d, 26 },
-	{ 0xffffff, 27 },
-};
-
-static const struct af9013_reg_bit ofsm_init[] = {
-	{ 0xd73a, 0, 8, 0xa1 },
-	{ 0xd73b, 0, 8, 0x1f },
-	{ 0xd73c, 4, 4, 0x0a },
-	{ 0xd732, 3, 1, 0x00 },
-	{ 0xd731, 4, 2, 0x03 },
-	{ 0xd73d, 7, 1, 0x01 },
-	{ 0xd740, 0, 1, 0x00 },
-	{ 0xd740, 1, 1, 0x00 },
-	{ 0xd740, 2, 1, 0x00 },
-	{ 0xd740, 3, 1, 0x01 },
-	{ 0xd3c1, 4, 1, 0x01 },
-	{ 0x9124, 0, 8, 0x58 },
-	{ 0x9125, 0, 2, 0x02 },
-	{ 0xd3a2, 0, 8, 0x00 },
-	{ 0xd3a3, 0, 8, 0x04 },
-	{ 0xd305, 0, 8, 0x32 },
-	{ 0xd306, 0, 8, 0x10 },
-	{ 0xd304, 0, 8, 0x04 },
-	{ 0x9112, 0, 1, 0x01 },
-	{ 0x911d, 0, 1, 0x01 },
-	{ 0x911a, 0, 1, 0x01 },
-	{ 0x911b, 0, 1, 0x01 },
-	{ 0x9bce, 0, 4, 0x02 },
-	{ 0x9116, 0, 1, 0x01 },
-	{ 0x9122, 0, 8, 0xd0 },
-	{ 0xd2e0, 0, 8, 0xd0 },
-	{ 0xd2e9, 0, 4, 0x0d },
-	{ 0xd38c, 0, 8, 0xfc },
-	{ 0xd38d, 0, 8, 0x00 },
-	{ 0xd38e, 0, 8, 0x7e },
-	{ 0xd38f, 0, 8, 0x00 },
-	{ 0xd390, 0, 8, 0x2f },
-	{ 0xd145, 4, 1, 0x01 },
-	{ 0xd1a9, 4, 1, 0x01 },
-	{ 0xd158, 5, 3, 0x01 },
-	{ 0xd159, 0, 6, 0x06 },
-	{ 0xd167, 0, 8, 0x00 },
-	{ 0xd168, 0, 4, 0x07 },
-	{ 0xd1c3, 5, 3, 0x00 },
-	{ 0xd1c4, 0, 6, 0x00 },
-	{ 0xd1c5, 0, 7, 0x10 },
-	{ 0xd1c6, 0, 3, 0x02 },
-	{ 0xd080, 2, 5, 0x03 },
-	{ 0xd081, 4, 4, 0x09 },
-	{ 0xd098, 4, 4, 0x0f },
-	{ 0xd098, 0, 4, 0x03 },
-	{ 0xdbc0, 4, 1, 0x01 },
-	{ 0xdbc7, 0, 8, 0x08 },
-	{ 0xdbc8, 4, 4, 0x00 },
-	{ 0xdbc9, 0, 5, 0x01 },
-	{ 0xd280, 0, 8, 0xe0 },
-	{ 0xd281, 0, 8, 0xff },
-	{ 0xd282, 0, 8, 0xff },
-	{ 0xd283, 0, 8, 0xc3 },
-	{ 0xd284, 0, 8, 0xff },
-	{ 0xd285, 0, 4, 0x01 },
-	{ 0xd0f0, 0, 7, 0x1a },
-	{ 0xd0f1, 4, 1, 0x01 },
-	{ 0xd0f2, 0, 8, 0x0c },
-	{ 0xd101, 5, 3, 0x06 },
-	{ 0xd103, 0, 4, 0x08 },
-	{ 0xd0f8, 0, 7, 0x20 },
-	{ 0xd111, 5, 1, 0x00 },
-	{ 0xd111, 6, 1, 0x00 },
-	{ 0x910b, 0, 8, 0x0a },
-	{ 0x9115, 0, 8, 0x02 },
-	{ 0x910c, 0, 8, 0x02 },
-	{ 0x910d, 0, 8, 0x08 },
-	{ 0x910e, 0, 8, 0x0a },
-	{ 0x9bf6, 0, 8, 0x06 },
-	{ 0x9bf8, 0, 8, 0x02 },
-	{ 0x9bf7, 0, 8, 0x05 },
-	{ 0x9bf9, 0, 8, 0x0f },
-	{ 0x9bfc, 0, 8, 0x13 },
-	{ 0x9bd3, 0, 8, 0xff },
-	{ 0x9bbe, 0, 1, 0x01 },
-	{ 0x9bcc, 0, 1, 0x01 },
-};
-
-/* Panasonic ENV77H11D5 tuner init
-   AF9013_TUNER_ENV77H11D5 = 129 */
-static const struct af9013_reg_bit tuner_init_env77h11d5[] = {
-	{ 0x9bd5, 0, 8, 0x01 },
-	{ 0x9bd6, 0, 8, 0x03 },
-	{ 0x9bbe, 0, 8, 0x01 },
-	{ 0xd1a0, 1, 1, 0x01 },
-	{ 0xd000, 0, 1, 0x01 },
-	{ 0xd000, 1, 1, 0x00 },
-	{ 0xd001, 1, 1, 0x01 },
-	{ 0xd001, 0, 1, 0x00 },
-	{ 0xd001, 5, 1, 0x00 },
-	{ 0xd002, 0, 5, 0x19 },
-	{ 0xd003, 0, 5, 0x1a },
-	{ 0xd004, 0, 5, 0x19 },
-	{ 0xd005, 0, 5, 0x1a },
-	{ 0xd00e, 0, 5, 0x10 },
-	{ 0xd00f, 0, 3, 0x04 },
-	{ 0xd00f, 3, 3, 0x05 },
-	{ 0xd010, 0, 3, 0x04 },
-	{ 0xd010, 3, 3, 0x05 },
-	{ 0xd016, 4, 4, 0x03 },
-	{ 0xd01f, 0, 6, 0x0a },
-	{ 0xd020, 0, 6, 0x0a },
-	{ 0x9bda, 0, 8, 0x00 },
-	{ 0x9be3, 0, 8, 0x00 },
-	{ 0xd015, 0, 8, 0x50 },
-	{ 0xd016, 0, 1, 0x00 },
-	{ 0xd044, 0, 8, 0x46 },
-	{ 0xd045, 0, 1, 0x00 },
-	{ 0xd008, 0, 8, 0xdf },
-	{ 0xd009, 0, 2, 0x02 },
-	{ 0xd006, 0, 8, 0x44 },
-	{ 0xd007, 0, 2, 0x01 },
-	{ 0xd00c, 0, 8, 0xeb },
-	{ 0xd00d, 0, 2, 0x02 },
-	{ 0xd00a, 0, 8, 0xf4 },
-	{ 0xd00b, 0, 2, 0x01 },
-	{ 0x9bba, 0, 8, 0xf9 },
-	{ 0x9bc3, 0, 8, 0xdf },
-	{ 0x9bc4, 0, 8, 0x02 },
-	{ 0x9bc5, 0, 8, 0xeb },
-	{ 0x9bc6, 0, 8, 0x02 },
-	{ 0x9bc9, 0, 8, 0x52 },
-	{ 0xd011, 0, 8, 0x3c },
-	{ 0xd012, 0, 2, 0x01 },
-	{ 0xd013, 0, 8, 0xf7 },
-	{ 0xd014, 0, 2, 0x02 },
-	{ 0xd040, 0, 8, 0x0b },
-	{ 0xd041, 0, 2, 0x02 },
-	{ 0xd042, 0, 8, 0x4d },
-	{ 0xd043, 0, 2, 0x00 },
-	{ 0xd045, 1, 1, 0x00 },
-	{ 0x9bcf, 0, 1, 0x01 },
-	{ 0xd045, 2, 1, 0x01 },
-	{ 0xd04f, 0, 8, 0x9a },
-	{ 0xd050, 0, 1, 0x01 },
-	{ 0xd051, 0, 8, 0x5a },
-	{ 0xd052, 0, 1, 0x01 },
-	{ 0xd053, 0, 8, 0x50 },
-	{ 0xd054, 0, 8, 0x46 },
-	{ 0x9bd7, 0, 8, 0x0a },
-	{ 0x9bd8, 0, 8, 0x14 },
-	{ 0x9bd9, 0, 8, 0x08 },
-};
-
-/* Microtune MT2060 tuner init
-   AF9013_TUNER_MT2060     = 130 */
-static const struct af9013_reg_bit tuner_init_mt2060[] = {
-	{ 0x9bd5, 0, 8, 0x01 },
-	{ 0x9bd6, 0, 8, 0x07 },
-	{ 0xd1a0, 1, 1, 0x01 },
-	{ 0xd000, 0, 1, 0x01 },
-	{ 0xd000, 1, 1, 0x00 },
-	{ 0xd001, 1, 1, 0x01 },
-	{ 0xd001, 0, 1, 0x00 },
-	{ 0xd001, 5, 1, 0x00 },
-	{ 0xd002, 0, 5, 0x19 },
-	{ 0xd003, 0, 5, 0x1a },
-	{ 0xd004, 0, 5, 0x19 },
-	{ 0xd005, 0, 5, 0x1a },
-	{ 0xd00e, 0, 5, 0x10 },
-	{ 0xd00f, 0, 3, 0x04 },
-	{ 0xd00f, 3, 3, 0x05 },
-	{ 0xd010, 0, 3, 0x04 },
-	{ 0xd010, 3, 3, 0x05 },
-	{ 0xd016, 4, 4, 0x03 },
-	{ 0xd01f, 0, 6, 0x0a },
-	{ 0xd020, 0, 6, 0x0a },
-	{ 0x9bda, 0, 8, 0x00 },
-	{ 0x9be3, 0, 8, 0x00 },
-	{ 0x9bbe, 0, 1, 0x00 },
-	{ 0x9bcc, 0, 1, 0x00 },
-	{ 0x9bb9, 0, 8, 0x75 },
-	{ 0x9bcd, 0, 8, 0x24 },
-	{ 0x9bff, 0, 8, 0x30 },
-	{ 0xd015, 0, 8, 0x46 },
-	{ 0xd016, 0, 1, 0x00 },
-	{ 0xd044, 0, 8, 0x46 },
-	{ 0xd045, 0, 1, 0x00 },
-	{ 0xd008, 0, 8, 0x0f },
-	{ 0xd009, 0, 2, 0x02 },
-	{ 0xd006, 0, 8, 0x32 },
-	{ 0xd007, 0, 2, 0x01 },
-	{ 0xd00c, 0, 8, 0x36 },
-	{ 0xd00d, 0, 2, 0x03 },
-	{ 0xd00a, 0, 8, 0x35 },
-	{ 0xd00b, 0, 2, 0x01 },
-	{ 0x9bc7, 0, 8, 0x07 },
-	{ 0x9bc8, 0, 8, 0x90 },
-	{ 0x9bc3, 0, 8, 0x0f },
-	{ 0x9bc4, 0, 8, 0x02 },
-	{ 0x9bc5, 0, 8, 0x36 },
-	{ 0x9bc6, 0, 8, 0x03 },
-	{ 0x9bba, 0, 8, 0xc9 },
-	{ 0x9bc9, 0, 8, 0x79 },
-	{ 0xd011, 0, 8, 0x10 },
-	{ 0xd012, 0, 2, 0x01 },
-	{ 0xd013, 0, 8, 0x45 },
-	{ 0xd014, 0, 2, 0x03 },
-	{ 0xd040, 0, 8, 0x98 },
-	{ 0xd041, 0, 2, 0x00 },
-	{ 0xd042, 0, 8, 0xcf },
-	{ 0xd043, 0, 2, 0x03 },
-	{ 0xd045, 1, 1, 0x00 },
-	{ 0x9bcf, 0, 1, 0x01 },
-	{ 0xd045, 2, 1, 0x01 },
-	{ 0xd04f, 0, 8, 0x9a },
-	{ 0xd050, 0, 1, 0x01 },
-	{ 0xd051, 0, 8, 0x5a },
-	{ 0xd052, 0, 1, 0x01 },
-	{ 0xd053, 0, 8, 0x50 },
-	{ 0xd054, 0, 8, 0x46 },
-	{ 0x9bd7, 0, 8, 0x0a },
-	{ 0x9bd8, 0, 8, 0x14 },
-	{ 0x9bd9, 0, 8, 0x08 },
-	{ 0x9bd0, 0, 8, 0xcc },
-	{ 0x9be4, 0, 8, 0xa0 },
-	{ 0x9bbd, 0, 8, 0x8e },
-	{ 0x9be2, 0, 8, 0x4d },
-	{ 0x9bee, 0, 1, 0x01 },
-};
-
-/* Microtune MT2060 tuner init
-   AF9013_TUNER_MT2060_2   = 147 */
-static const struct af9013_reg_bit tuner_init_mt2060_2[] = {
-	{ 0x9bd5, 0, 8, 0x01 },
-	{ 0x9bd6, 0, 8, 0x06 },
-	{ 0x9bbe, 0, 8, 0x01 },
-	{ 0xd1a0, 1, 1, 0x01 },
-	{ 0xd000, 0, 1, 0x01 },
-	{ 0xd000, 1, 1, 0x00 },
-	{ 0xd001, 1, 1, 0x01 },
-	{ 0xd001, 0, 1, 0x00 },
-	{ 0xd001, 5, 1, 0x00 },
-	{ 0xd002, 0, 5, 0x19 },
-	{ 0xd003, 0, 5, 0x1a },
-	{ 0xd004, 0, 5, 0x19 },
-	{ 0xd005, 0, 5, 0x1a },
-	{ 0xd00e, 0, 5, 0x10 },
-	{ 0xd00f, 0, 3, 0x04 },
-	{ 0xd00f, 3, 3, 0x05 },
-	{ 0xd010, 0, 3, 0x04 },
-	{ 0xd010, 3, 3, 0x05 },
-	{ 0xd016, 4, 4, 0x03 },
-	{ 0xd01f, 0, 6, 0x0a },
-	{ 0xd020, 0, 6, 0x0a },
-	{ 0xd015, 0, 8, 0x46 },
-	{ 0xd016, 0, 1, 0x00 },
-	{ 0xd044, 0, 8, 0x46 },
-	{ 0xd045, 0, 1, 0x00 },
-	{ 0xd008, 0, 8, 0x0f },
-	{ 0xd009, 0, 2, 0x02 },
-	{ 0xd006, 0, 8, 0x32 },
-	{ 0xd007, 0, 2, 0x01 },
-	{ 0xd00c, 0, 8, 0x36 },
-	{ 0xd00d, 0, 2, 0x03 },
-	{ 0xd00a, 0, 8, 0x35 },
-	{ 0xd00b, 0, 2, 0x01 },
-	{ 0x9bc7, 0, 8, 0x07 },
-	{ 0x9bc8, 0, 8, 0x90 },
-	{ 0x9bc3, 0, 8, 0x0f },
-	{ 0x9bc4, 0, 8, 0x02 },
-	{ 0x9bc5, 0, 8, 0x36 },
-	{ 0x9bc6, 0, 8, 0x03 },
-	{ 0x9bba, 0, 8, 0xc9 },
-	{ 0x9bc9, 0, 8, 0x79 },
-	{ 0xd011, 0, 8, 0x10 },
-	{ 0xd012, 0, 2, 0x01 },
-	{ 0xd013, 0, 8, 0x45 },
-	{ 0xd014, 0, 2, 0x03 },
-	{ 0xd040, 0, 8, 0x98 },
-	{ 0xd041, 0, 2, 0x00 },
-	{ 0xd042, 0, 8, 0xcf },
-	{ 0xd043, 0, 2, 0x03 },
-	{ 0xd045, 1, 1, 0x00 },
-	{ 0x9bcf, 0, 8, 0x01 },
-	{ 0xd045, 2, 1, 0x01 },
-	{ 0xd04f, 0, 8, 0x9a },
-	{ 0xd050, 0, 1, 0x01 },
-	{ 0xd051, 0, 8, 0x5a },
-	{ 0xd052, 0, 1, 0x01 },
-	{ 0xd053, 0, 8, 0x96 },
-	{ 0xd054, 0, 8, 0x46 },
-	{ 0xd045, 7, 1, 0x00 },
-	{ 0x9bd7, 0, 8, 0x0a },
-	{ 0x9bd8, 0, 8, 0x14 },
-	{ 0x9bd9, 0, 8, 0x08 },
-};
-
-/* MaxLinear MXL5003 tuner init
-   AF9013_TUNER_MXL5003D   =   3 */
-static const struct af9013_reg_bit tuner_init_mxl5003d[] = {
-	{ 0x9bd5, 0, 8, 0x01 },
-	{ 0x9bd6, 0, 8, 0x09 },
-	{ 0xd1a0, 1, 1, 0x01 },
-	{ 0xd000, 0, 1, 0x01 },
-	{ 0xd000, 1, 1, 0x00 },
-	{ 0xd001, 1, 1, 0x01 },
-	{ 0xd001, 0, 1, 0x00 },
-	{ 0xd001, 5, 1, 0x00 },
-	{ 0xd002, 0, 5, 0x19 },
-	{ 0xd003, 0, 5, 0x1a },
-	{ 0xd004, 0, 5, 0x19 },
-	{ 0xd005, 0, 5, 0x1a },
-	{ 0xd00e, 0, 5, 0x10 },
-	{ 0xd00f, 0, 3, 0x04 },
-	{ 0xd00f, 3, 3, 0x05 },
-	{ 0xd010, 0, 3, 0x04 },
-	{ 0xd010, 3, 3, 0x05 },
-	{ 0xd016, 4, 4, 0x03 },
-	{ 0xd01f, 0, 6, 0x0a },
-	{ 0xd020, 0, 6, 0x0a },
-	{ 0x9bda, 0, 8, 0x00 },
-	{ 0x9be3, 0, 8, 0x00 },
-	{ 0x9bfc, 0, 8, 0x0f },
-	{ 0x9bf6, 0, 8, 0x01 },
-	{ 0x9bbe, 0, 1, 0x01 },
-	{ 0xd015, 0, 8, 0x33 },
-	{ 0xd016, 0, 1, 0x00 },
-	{ 0xd044, 0, 8, 0x40 },
-	{ 0xd045, 0, 1, 0x00 },
-	{ 0xd008, 0, 8, 0x0f },
-	{ 0xd009, 0, 2, 0x02 },
-	{ 0xd006, 0, 8, 0x6c },
-	{ 0xd007, 0, 2, 0x00 },
-	{ 0xd00c, 0, 8, 0x3d },
-	{ 0xd00d, 0, 2, 0x00 },
-	{ 0xd00a, 0, 8, 0x45 },
-	{ 0xd00b, 0, 2, 0x01 },
-	{ 0x9bc7, 0, 8, 0x07 },
-	{ 0x9bc8, 0, 8, 0x52 },
-	{ 0x9bc3, 0, 8, 0x0f },
-	{ 0x9bc4, 0, 8, 0x02 },
-	{ 0x9bc5, 0, 8, 0x3d },
-	{ 0x9bc6, 0, 8, 0x00 },
-	{ 0x9bba, 0, 8, 0xa2 },
-	{ 0x9bc9, 0, 8, 0xa0 },
-	{ 0xd011, 0, 8, 0x56 },
-	{ 0xd012, 0, 2, 0x00 },
-	{ 0xd013, 0, 8, 0x50 },
-	{ 0xd014, 0, 2, 0x00 },
-	{ 0xd040, 0, 8, 0x56 },
-	{ 0xd041, 0, 2, 0x00 },
-	{ 0xd042, 0, 8, 0x50 },
-	{ 0xd043, 0, 2, 0x00 },
-	{ 0xd045, 1, 1, 0x00 },
-	{ 0x9bcf, 0, 8, 0x01 },
-	{ 0xd045, 2, 1, 0x01 },
-	{ 0xd04f, 0, 8, 0x9a },
-	{ 0xd050, 0, 1, 0x01 },
-	{ 0xd051, 0, 8, 0x5a },
-	{ 0xd052, 0, 1, 0x01 },
-	{ 0xd053, 0, 8, 0x50 },
-	{ 0xd054, 0, 8, 0x46 },
-	{ 0x9bd7, 0, 8, 0x0a },
-	{ 0x9bd8, 0, 8, 0x14 },
-	{ 0x9bd9, 0, 8, 0x08 },
-};
-
-/* MaxLinear MXL5005S & MXL5007T tuner init
-   AF9013_TUNER_MXL5005D   =  13
-   AF9013_TUNER_MXL5005R   =  30
-   AF9013_TUNER_MXL5007T   = 177 */
-static const struct af9013_reg_bit tuner_init_mxl5005[] = {
-	{ 0x9bd5, 0, 8, 0x01 },
-	{ 0x9bd6, 0, 8, 0x07 },
-	{ 0xd1a0, 1, 1, 0x01 },
-	{ 0xd000, 0, 1, 0x01 },
-	{ 0xd000, 1, 1, 0x00 },
-	{ 0xd001, 1, 1, 0x01 },
-	{ 0xd001, 0, 1, 0x00 },
-	{ 0xd001, 5, 1, 0x00 },
-	{ 0xd002, 0, 5, 0x19 },
-	{ 0xd003, 0, 5, 0x1a },
-	{ 0xd004, 0, 5, 0x19 },
-	{ 0xd005, 0, 5, 0x1a },
-	{ 0xd00e, 0, 5, 0x10 },
-	{ 0xd00f, 0, 3, 0x04 },
-	{ 0xd00f, 3, 3, 0x05 },
-	{ 0xd010, 0, 3, 0x04 },
-	{ 0xd010, 3, 3, 0x05 },
-	{ 0xd016, 4, 4, 0x03 },
-	{ 0xd01f, 0, 6, 0x0a },
-	{ 0xd020, 0, 6, 0x0a },
-	{ 0x9bda, 0, 8, 0x01 },
-	{ 0x9be3, 0, 8, 0x01 },
-	{ 0x9bbe, 0, 1, 0x01 },
-	{ 0x9bcc, 0, 1, 0x01 },
-	{ 0x9bb9, 0, 8, 0x00 },
-	{ 0x9bcd, 0, 8, 0x28 },
-	{ 0x9bff, 0, 8, 0x24 },
-	{ 0xd015, 0, 8, 0x40 },
-	{ 0xd016, 0, 1, 0x00 },
-	{ 0xd044, 0, 8, 0x40 },
-	{ 0xd045, 0, 1, 0x00 },
-	{ 0xd008, 0, 8, 0x0f },
-	{ 0xd009, 0, 2, 0x02 },
-	{ 0xd006, 0, 8, 0x73 },
-	{ 0xd007, 0, 2, 0x01 },
-	{ 0xd00c, 0, 8, 0xfa },
-	{ 0xd00d, 0, 2, 0x01 },
-	{ 0xd00a, 0, 8, 0xff },
-	{ 0xd00b, 0, 2, 0x01 },
-	{ 0x9bc7, 0, 8, 0x23 },
-	{ 0x9bc8, 0, 8, 0x55 },
-	{ 0x9bc3, 0, 8, 0x01 },
-	{ 0x9bc4, 0, 8, 0x02 },
-	{ 0x9bc5, 0, 8, 0xfa },
-	{ 0x9bc6, 0, 8, 0x01 },
-	{ 0x9bba, 0, 8, 0xff },
-	{ 0x9bc9, 0, 8, 0xff },
-	{ 0x9bd3, 0, 8, 0x95 },
-	{ 0xd011, 0, 8, 0x70 },
-	{ 0xd012, 0, 2, 0x01 },
-	{ 0xd013, 0, 8, 0xfb },
-	{ 0xd014, 0, 2, 0x01 },
-	{ 0xd040, 0, 8, 0x70 },
-	{ 0xd041, 0, 2, 0x01 },
-	{ 0xd042, 0, 8, 0xfb },
-	{ 0xd043, 0, 2, 0x01 },
-	{ 0xd045, 1, 1, 0x00 },
-	{ 0x9bcf, 0, 1, 0x01 },
-	{ 0xd045, 2, 1, 0x01 },
-	{ 0xd04f, 0, 8, 0x9a },
-	{ 0xd050, 0, 1, 0x01 },
-	{ 0xd051, 0, 8, 0x5a },
-	{ 0xd052, 0, 1, 0x01 },
-	{ 0xd053, 0, 8, 0x50 },
-	{ 0xd054, 0, 8, 0x46 },
-	{ 0x9bd7, 0, 8, 0x0a },
-	{ 0x9bd8, 0, 8, 0x14 },
-	{ 0x9bd9, 0, 8, 0x08 },
-	{ 0x9bd0, 0, 8, 0x93 },
-	{ 0x9be4, 0, 8, 0xfe },
-	{ 0x9bbd, 0, 8, 0x63 },
-	{ 0x9be2, 0, 8, 0xfe },
-	{ 0x9bee, 0, 1, 0x01 },
-};
-
-/* Quantek QT1010 tuner init
-   AF9013_TUNER_QT1010     = 134
-   AF9013_TUNER_QT1010A    = 162 */
-static const struct af9013_reg_bit tuner_init_qt1010[] = {
-	{ 0x9bd5, 0, 8, 0x01 },
-	{ 0x9bd6, 0, 8, 0x09 },
-	{ 0xd1a0, 1, 1, 0x01 },
-	{ 0xd000, 0, 1, 0x01 },
-	{ 0xd000, 1, 1, 0x00 },
-	{ 0xd001, 1, 1, 0x01 },
-	{ 0xd001, 0, 1, 0x00 },
-	{ 0xd001, 5, 1, 0x00 },
-	{ 0xd002, 0, 5, 0x19 },
-	{ 0xd003, 0, 5, 0x1a },
-	{ 0xd004, 0, 5, 0x19 },
-	{ 0xd005, 0, 5, 0x1a },
-	{ 0xd00e, 0, 5, 0x10 },
-	{ 0xd00f, 0, 3, 0x04 },
-	{ 0xd00f, 3, 3, 0x05 },
-	{ 0xd010, 0, 3, 0x04 },
-	{ 0xd010, 3, 3, 0x05 },
-	{ 0xd016, 4, 4, 0x03 },
-	{ 0xd01f, 0, 6, 0x0a },
-	{ 0xd020, 0, 6, 0x0a },
-	{ 0x9bda, 0, 8, 0x01 },
-	{ 0x9be3, 0, 8, 0x01 },
-	{ 0xd015, 0, 8, 0x46 },
-	{ 0xd016, 0, 1, 0x00 },
-	{ 0xd044, 0, 8, 0x46 },
-	{ 0xd045, 0, 1, 0x00 },
-	{ 0x9bbe, 0, 1, 0x01 },
-	{ 0x9bcc, 0, 1, 0x01 },
-	{ 0x9bb9, 0, 8, 0x00 },
-	{ 0x9bcd, 0, 8, 0x28 },
-	{ 0x9bff, 0, 8, 0x20 },
-	{ 0xd008, 0, 8, 0x0f },
-	{ 0xd009, 0, 2, 0x02 },
-	{ 0xd006, 0, 8, 0x99 },
-	{ 0xd007, 0, 2, 0x01 },
-	{ 0xd00c, 0, 8, 0x0f },
-	{ 0xd00d, 0, 2, 0x02 },
-	{ 0xd00a, 0, 8, 0x50 },
-	{ 0xd00b, 0, 2, 0x01 },
-	{ 0x9bc7, 0, 8, 0x00 },
-	{ 0x9bc8, 0, 8, 0x00 },
-	{ 0x9bc3, 0, 8, 0x0f },
-	{ 0x9bc4, 0, 8, 0x02 },
-	{ 0x9bc5, 0, 8, 0x0f },
-	{ 0x9bc6, 0, 8, 0x02 },
-	{ 0x9bba, 0, 8, 0xc5 },
-	{ 0x9bc9, 0, 8, 0xff },
-	{ 0xd011, 0, 8, 0x58 },
-	{ 0xd012, 0, 2, 0x02 },
-	{ 0xd013, 0, 8, 0x89 },
-	{ 0xd014, 0, 2, 0x01 },
-	{ 0xd040, 0, 8, 0x58 },
-	{ 0xd041, 0, 2, 0x02 },
-	{ 0xd042, 0, 8, 0x89 },
-	{ 0xd043, 0, 2, 0x01 },
-	{ 0xd045, 1, 1, 0x00 },
-	{ 0x9bcf, 0, 1, 0x01 },
-	{ 0xd045, 2, 1, 0x01 },
-	{ 0xd04f, 0, 8, 0x9a },
-	{ 0xd050, 0, 1, 0x01 },
-	{ 0xd051, 0, 8, 0x5a },
-	{ 0xd052, 0, 1, 0x01 },
-	{ 0xd053, 0, 8, 0x50 },
-	{ 0xd054, 0, 8, 0x46 },
-	{ 0x9bd7, 0, 8, 0x0a },
-	{ 0x9bd8, 0, 8, 0x14 },
-	{ 0x9bd9, 0, 8, 0x08 },
-	{ 0x9bd0, 0, 8, 0xcd },
-	{ 0x9be4, 0, 8, 0xbb },
-	{ 0x9bbd, 0, 8, 0x93 },
-	{ 0x9be2, 0, 8, 0x80 },
-	{ 0x9bee, 0, 1, 0x01 },
-};
-
-/* Freescale MC44S803 tuner init
-   AF9013_TUNER_MC44S803   = 133 */
-static const struct af9013_reg_bit tuner_init_mc44s803[] = {
-	{ 0x9bd5, 0, 8, 0x01 },
-	{ 0x9bd6, 0, 8, 0x06 },
-	{ 0xd1a0, 1, 1, 0x01 },
-	{ 0xd000, 0, 1, 0x01 },
-	{ 0xd000, 1, 1, 0x00 },
-	{ 0xd001, 1, 1, 0x01 },
-	{ 0xd001, 0, 1, 0x00 },
-	{ 0xd001, 5, 1, 0x00 },
-	{ 0xd002, 0, 5, 0x19 },
-	{ 0xd003, 0, 5, 0x1a },
-	{ 0xd004, 0, 5, 0x19 },
-	{ 0xd005, 0, 5, 0x1a },
-	{ 0xd00e, 0, 5, 0x10 },
-	{ 0xd00f, 0, 3, 0x04 },
-	{ 0xd00f, 3, 3, 0x05 },
-	{ 0xd010, 0, 3, 0x04 },
-	{ 0xd010, 3, 3, 0x05 },
-	{ 0xd016, 4, 4, 0x03 },
-	{ 0xd01f, 0, 6, 0x0a },
-	{ 0xd020, 0, 6, 0x0a },
-	{ 0x9bda, 0, 8, 0x00 },
-	{ 0x9be3, 0, 8, 0x00 },
-	{ 0x9bf6, 0, 8, 0x01 },
-	{ 0x9bf8, 0, 8, 0x02 },
-	{ 0x9bf9, 0, 8, 0x02 },
-	{ 0x9bfc, 0, 8, 0x1f },
-	{ 0x9bbe, 0, 1, 0x01 },
-	{ 0x9bcc, 0, 1, 0x01 },
-	{ 0x9bb9, 0, 8, 0x00 },
-	{ 0x9bcd, 0, 8, 0x24 },
-	{ 0x9bff, 0, 8, 0x24 },
-	{ 0xd015, 0, 8, 0x46 },
-	{ 0xd016, 0, 1, 0x00 },
-	{ 0xd044, 0, 8, 0x46 },
-	{ 0xd045, 0, 1, 0x00 },
-	{ 0xd008, 0, 8, 0x01 },
-	{ 0xd009, 0, 2, 0x02 },
-	{ 0xd006, 0, 8, 0x7b },
-	{ 0xd007, 0, 2, 0x00 },
-	{ 0xd00c, 0, 8, 0x7c },
-	{ 0xd00d, 0, 2, 0x02 },
-	{ 0xd00a, 0, 8, 0xfe },
-	{ 0xd00b, 0, 2, 0x01 },
-	{ 0x9bc7, 0, 8, 0x08 },
-	{ 0x9bc8, 0, 8, 0x9a },
-	{ 0x9bc3, 0, 8, 0x01 },
-	{ 0x9bc4, 0, 8, 0x02 },
-	{ 0x9bc5, 0, 8, 0x7c },
-	{ 0x9bc6, 0, 8, 0x02 },
-	{ 0x9bba, 0, 8, 0xfc },
-	{ 0x9bc9, 0, 8, 0xaa },
-	{ 0xd011, 0, 8, 0x6b },
-	{ 0xd012, 0, 2, 0x00 },
-	{ 0xd013, 0, 8, 0x88 },
-	{ 0xd014, 0, 2, 0x02 },
-	{ 0xd040, 0, 8, 0x6b },
-	{ 0xd041, 0, 2, 0x00 },
-	{ 0xd042, 0, 8, 0x7c },
-	{ 0xd043, 0, 2, 0x02 },
-	{ 0xd045, 1, 1, 0x00 },
-	{ 0x9bcf, 0, 1, 0x01 },
-	{ 0xd045, 2, 1, 0x01 },
-	{ 0xd04f, 0, 8, 0x9a },
-	{ 0xd050, 0, 1, 0x01 },
-	{ 0xd051, 0, 8, 0x5a },
-	{ 0xd052, 0, 1, 0x01 },
-	{ 0xd053, 0, 8, 0x50 },
-	{ 0xd054, 0, 8, 0x46 },
-	{ 0x9bd7, 0, 8, 0x0a },
-	{ 0x9bd8, 0, 8, 0x14 },
-	{ 0x9bd9, 0, 8, 0x08 },
-	{ 0x9bd0, 0, 8, 0x9e },
-	{ 0x9be4, 0, 8, 0xff },
-	{ 0x9bbd, 0, 8, 0x9e },
-	{ 0x9be2, 0, 8, 0x25 },
-	{ 0x9bee, 0, 1, 0x01 },
-	{ 0xd73b, 3, 1, 0x00 },
-};
-
-/* unknown, probably for tin can tuner, tuner init
-   AF9013_TUNER_UNKNOWN   = 140 */
-static const struct af9013_reg_bit tuner_init_unknown[] = {
-	{ 0x9bd5, 0, 8, 0x01 },
-	{ 0x9bd6, 0, 8, 0x02 },
-	{ 0xd1a0, 1, 1, 0x01 },
-	{ 0xd000, 0, 1, 0x01 },
-	{ 0xd000, 1, 1, 0x00 },
-	{ 0xd001, 1, 1, 0x01 },
-	{ 0xd001, 0, 1, 0x00 },
-	{ 0xd001, 5, 1, 0x00 },
-	{ 0xd002, 0, 5, 0x19 },
-	{ 0xd003, 0, 5, 0x1a },
-	{ 0xd004, 0, 5, 0x19 },
-	{ 0xd005, 0, 5, 0x1a },
-	{ 0xd00e, 0, 5, 0x10 },
-	{ 0xd00f, 0, 3, 0x04 },
-	{ 0xd00f, 3, 3, 0x05 },
-	{ 0xd010, 0, 3, 0x04 },
-	{ 0xd010, 3, 3, 0x05 },
-	{ 0xd016, 4, 4, 0x03 },
-	{ 0xd01f, 0, 6, 0x0a },
-	{ 0xd020, 0, 6, 0x0a },
-	{ 0x9bda, 0, 8, 0x01 },
-	{ 0x9be3, 0, 8, 0x01 },
-	{ 0xd1a0, 1, 1, 0x00 },
-	{ 0x9bbe, 0, 1, 0x01 },
-	{ 0x9bcc, 0, 1, 0x01 },
-	{ 0x9bb9, 0, 8, 0x00 },
-	{ 0x9bcd, 0, 8, 0x18 },
-	{ 0x9bff, 0, 8, 0x2c },
-	{ 0xd015, 0, 8, 0x46 },
-	{ 0xd016, 0, 1, 0x00 },
-	{ 0xd044, 0, 8, 0x46 },
-	{ 0xd045, 0, 1, 0x00 },
-	{ 0xd008, 0, 8, 0xdf },
-	{ 0xd009, 0, 2, 0x02 },
-	{ 0xd006, 0, 8, 0x44 },
-	{ 0xd007, 0, 2, 0x01 },
-	{ 0xd00c, 0, 8, 0x00 },
-	{ 0xd00d, 0, 2, 0x02 },
-	{ 0xd00a, 0, 8, 0xf6 },
-	{ 0xd00b, 0, 2, 0x01 },
-	{ 0x9bba, 0, 8, 0xf9 },
-	{ 0x9bc8, 0, 8, 0xaa },
-	{ 0x9bc3, 0, 8, 0xdf },
-	{ 0x9bc4, 0, 8, 0x02 },
-	{ 0x9bc5, 0, 8, 0x00 },
-	{ 0x9bc6, 0, 8, 0x02 },
-	{ 0x9bc9, 0, 8, 0xf0 },
-	{ 0xd011, 0, 8, 0x3c },
-	{ 0xd012, 0, 2, 0x01 },
-	{ 0xd013, 0, 8, 0xf7 },
-	{ 0xd014, 0, 2, 0x02 },
-	{ 0xd040, 0, 8, 0x0b },
-	{ 0xd041, 0, 2, 0x02 },
-	{ 0xd042, 0, 8, 0x4d },
-	{ 0xd043, 0, 2, 0x00 },
-	{ 0xd045, 1, 1, 0x00 },
-	{ 0x9bcf, 0, 1, 0x01 },
-	{ 0xd045, 2, 1, 0x01 },
-	{ 0xd04f, 0, 8, 0x9a },
-	{ 0xd050, 0, 1, 0x01 },
-	{ 0xd051, 0, 8, 0x5a },
-	{ 0xd052, 0, 1, 0x01 },
-	{ 0xd053, 0, 8, 0x50 },
-	{ 0xd054, 0, 8, 0x46 },
-	{ 0x9bd7, 0, 8, 0x0a },
-	{ 0x9bd8, 0, 8, 0x14 },
-	{ 0x9bd9, 0, 8, 0x08 },
-};
-
-/* NXP TDA18271 & TDA18218 tuner init
-   AF9013_TUNER_TDA18271   = 156
-   AF9013_TUNER_TDA18218   = 179 */
-static const struct af9013_reg_bit tuner_init_tda18271[] = {
-	{ 0x9bd5, 0, 8, 0x01 },
-	{ 0x9bd6, 0, 8, 0x04 },
-	{ 0xd1a0, 1, 1, 0x01 },
-	{ 0xd000, 0, 1, 0x01 },
-	{ 0xd000, 1, 1, 0x00 },
-	{ 0xd001, 1, 1, 0x01 },
-	{ 0xd001, 0, 1, 0x00 },
-	{ 0xd001, 5, 1, 0x00 },
-	{ 0xd002, 0, 5, 0x19 },
-	{ 0xd003, 0, 5, 0x1a },
-	{ 0xd004, 0, 5, 0x19 },
-	{ 0xd005, 0, 5, 0x1a },
-	{ 0xd00e, 0, 5, 0x10 },
-	{ 0xd00f, 0, 3, 0x04 },
-	{ 0xd00f, 3, 3, 0x05 },
-	{ 0xd010, 0, 3, 0x04 },
-	{ 0xd010, 3, 3, 0x05 },
-	{ 0xd016, 4, 4, 0x03 },
-	{ 0xd01f, 0, 6, 0x0a },
-	{ 0xd020, 0, 6, 0x0a },
-	{ 0x9bda, 0, 8, 0x01 },
-	{ 0x9be3, 0, 8, 0x01 },
-	{ 0xd1a0, 1, 1, 0x00 },
-	{ 0x9bbe, 0, 1, 0x01 },
-	{ 0x9bcc, 0, 1, 0x01 },
-	{ 0x9bb9, 0, 8, 0x00 },
-	{ 0x9bcd, 0, 8, 0x18 },
-	{ 0x9bff, 0, 8, 0x2c },
-	{ 0xd015, 0, 8, 0x46 },
-	{ 0xd016, 0, 1, 0x00 },
-	{ 0xd044, 0, 8, 0x46 },
-	{ 0xd045, 0, 1, 0x00 },
-	{ 0xd008, 0, 8, 0xdf },
-	{ 0xd009, 0, 2, 0x02 },
-	{ 0xd006, 0, 8, 0x44 },
-	{ 0xd007, 0, 2, 0x01 },
-	{ 0xd00c, 0, 8, 0x00 },
-	{ 0xd00d, 0, 2, 0x02 },
-	{ 0xd00a, 0, 8, 0xf6 },
-	{ 0xd00b, 0, 2, 0x01 },
-	{ 0x9bba, 0, 8, 0xf9 },
-	{ 0x9bc8, 0, 8, 0xaa },
-	{ 0x9bc3, 0, 8, 0xdf },
-	{ 0x9bc4, 0, 8, 0x02 },
-	{ 0x9bc5, 0, 8, 0x00 },
-	{ 0x9bc6, 0, 8, 0x02 },
-	{ 0x9bc9, 0, 8, 0xf0 },
-	{ 0xd011, 0, 8, 0x3c },
-	{ 0xd012, 0, 2, 0x01 },
-	{ 0xd013, 0, 8, 0xf7 },
-	{ 0xd014, 0, 2, 0x02 },
-	{ 0xd040, 0, 8, 0x0b },
-	{ 0xd041, 0, 2, 0x02 },
-	{ 0xd042, 0, 8, 0x4d },
-	{ 0xd043, 0, 2, 0x00 },
-	{ 0xd045, 1, 1, 0x00 },
-	{ 0x9bcf, 0, 1, 0x01 },
-	{ 0xd045, 2, 1, 0x01 },
-	{ 0xd04f, 0, 8, 0x9a },
-	{ 0xd050, 0, 1, 0x01 },
-	{ 0xd051, 0, 8, 0x5a },
-	{ 0xd052, 0, 1, 0x01 },
-	{ 0xd053, 0, 8, 0x50 },
-	{ 0xd054, 0, 8, 0x46 },
-	{ 0x9bd7, 0, 8, 0x0a },
-	{ 0x9bd8, 0, 8, 0x14 },
-	{ 0x9bd9, 0, 8, 0x08 },
-	{ 0x9bd0, 0, 8, 0xa8 },
-	{ 0x9be4, 0, 8, 0x7f },
-	{ 0x9bbd, 0, 8, 0xa8 },
-	{ 0x9be2, 0, 8, 0x20 },
-	{ 0x9bee, 0, 1, 0x01 },
-};
-
-#endif /* AF9013_PRIV_H */
diff --git a/drivers/media/dvb/frontends/af9033.c b/drivers/media/dvb/frontends/af9033.c
deleted file mode 100644
index a389982..0000000
--- a/drivers/media/dvb/frontends/af9033.c
+++ /dev/null
@@ -1,980 +0,0 @@
-/*
- * Afatech AF9033 demodulator driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "af9033_priv.h"
-
-struct af9033_state {
-	struct i2c_adapter *i2c;
-	struct dvb_frontend fe;
-	struct af9033_config cfg;
-
-	u32 bandwidth_hz;
-	bool ts_mode_parallel;
-	bool ts_mode_serial;
-
-	u32 ber;
-	u32 ucb;
-	unsigned long last_stat_check;
-};
-
-/* write multiple registers */
-static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val,
-		int len)
-{
-	int ret;
-	u8 buf[3 + len];
-	struct i2c_msg msg[1] = {
-		{
-			.addr = state->cfg.i2c_addr,
-			.flags = 0,
-			.len = sizeof(buf),
-			.buf = buf,
-		}
-	};
-
-	buf[0] = (reg >> 16) & 0xff;
-	buf[1] = (reg >>  8) & 0xff;
-	buf[2] = (reg >>  0) & 0xff;
-	memcpy(&buf[3], val, len);
-
-	ret = i2c_transfer(state->i2c, msg, 1);
-	if (ret == 1) {
-		ret = 0;
-	} else {
-		printk(KERN_WARNING "%s: i2c wr failed=%d reg=%06x len=%d\n",
-				__func__, ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-
-	return ret;
-}
-
-/* read multiple registers */
-static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len)
-{
-	int ret;
-	u8 buf[3] = { (reg >> 16) & 0xff, (reg >> 8) & 0xff,
-			(reg >> 0) & 0xff };
-	struct i2c_msg msg[2] = {
-		{
-			.addr = state->cfg.i2c_addr,
-			.flags = 0,
-			.len = sizeof(buf),
-			.buf = buf
-		}, {
-			.addr = state->cfg.i2c_addr,
-			.flags = I2C_M_RD,
-			.len = len,
-			.buf = val
-		}
-	};
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-	if (ret == 2) {
-		ret = 0;
-	} else {
-		printk(KERN_WARNING "%s: i2c rd failed=%d reg=%06x len=%d\n",
-				__func__, ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-
-	return ret;
-}
-
-
-/* write single register */
-static int af9033_wr_reg(struct af9033_state *state, u32 reg, u8 val)
-{
-	return af9033_wr_regs(state, reg, &val, 1);
-}
-
-/* read single register */
-static int af9033_rd_reg(struct af9033_state *state, u32 reg, u8 *val)
-{
-	return af9033_rd_regs(state, reg, val, 1);
-}
-
-/* write single register with mask */
-static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val,
-		u8 mask)
-{
-	int ret;
-	u8 tmp;
-
-	/* no need for read if whole reg is written */
-	if (mask != 0xff) {
-		ret = af9033_rd_regs(state, reg, &tmp, 1);
-		if (ret)
-			return ret;
-
-		val &= mask;
-		tmp &= ~mask;
-		val |= tmp;
-	}
-
-	return af9033_wr_regs(state, reg, &val, 1);
-}
-
-/* read single register with mask */
-static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val,
-		u8 mask)
-{
-	int ret, i;
-	u8 tmp;
-
-	ret = af9033_rd_regs(state, reg, &tmp, 1);
-	if (ret)
-		return ret;
-
-	tmp &= mask;
-
-	/* find position of the first bit */
-	for (i = 0; i < 8; i++) {
-		if ((mask >> i) & 0x01)
-			break;
-	}
-	*val = tmp >> i;
-
-	return 0;
-}
-
-static u32 af9033_div(u32 a, u32 b, u32 x)
-{
-	u32 r = 0, c = 0, i;
-
-	pr_debug("%s: a=%d b=%d x=%d\n", __func__, a, b, x);
-
-	if (a > b) {
-		c = a / b;
-		a = a - c * b;
-	}
-
-	for (i = 0; i < x; i++) {
-		if (a >= b) {
-			r += 1;
-			a -= b;
-		}
-		a <<= 1;
-		r <<= 1;
-	}
-	r = (c << (u32)x) + r;
-
-	pr_debug("%s: a=%d b=%d x=%d r=%d r=%x\n", __func__, a, b, x, r, r);
-
-	return r;
-}
-
-static void af9033_release(struct dvb_frontend *fe)
-{
-	struct af9033_state *state = fe->demodulator_priv;
-
-	kfree(state);
-}
-
-static int af9033_init(struct dvb_frontend *fe)
-{
-	struct af9033_state *state = fe->demodulator_priv;
-	int ret, i, len;
-	const struct reg_val *init;
-	u8 buf[4];
-	u32 adc_cw, clock_cw;
-	struct reg_val_mask tab[] = {
-		{ 0x80fb24, 0x00, 0x08 },
-		{ 0x80004c, 0x00, 0xff },
-		{ 0x00f641, state->cfg.tuner, 0xff },
-		{ 0x80f5ca, 0x01, 0x01 },
-		{ 0x80f715, 0x01, 0x01 },
-		{ 0x00f41f, 0x04, 0x04 },
-		{ 0x00f41a, 0x01, 0x01 },
-		{ 0x80f731, 0x00, 0x01 },
-		{ 0x00d91e, 0x00, 0x01 },
-		{ 0x00d919, 0x00, 0x01 },
-		{ 0x80f732, 0x00, 0x01 },
-		{ 0x00d91f, 0x00, 0x01 },
-		{ 0x00d91a, 0x00, 0x01 },
-		{ 0x80f730, 0x00, 0x01 },
-		{ 0x80f778, 0x00, 0xff },
-		{ 0x80f73c, 0x01, 0x01 },
-		{ 0x80f776, 0x00, 0x01 },
-		{ 0x00d8fd, 0x01, 0xff },
-		{ 0x00d830, 0x01, 0xff },
-		{ 0x00d831, 0x00, 0xff },
-		{ 0x00d832, 0x00, 0xff },
-		{ 0x80f985, state->ts_mode_serial, 0x01 },
-		{ 0x80f986, state->ts_mode_parallel, 0x01 },
-		{ 0x00d827, 0x00, 0xff },
-		{ 0x00d829, 0x00, 0xff },
-	};
-
-	/* program clock control */
-	clock_cw = af9033_div(state->cfg.clock, 1000000ul, 19ul);
-	buf[0] = (clock_cw >>  0) & 0xff;
-	buf[1] = (clock_cw >>  8) & 0xff;
-	buf[2] = (clock_cw >> 16) & 0xff;
-	buf[3] = (clock_cw >> 24) & 0xff;
-
-	pr_debug("%s: clock=%d clock_cw=%08x\n", __func__, state->cfg.clock,
-			clock_cw);
-
-	ret = af9033_wr_regs(state, 0x800025, buf, 4);
-	if (ret < 0)
-		goto err;
-
-	/* program ADC control */
-	for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) {
-		if (clock_adc_lut[i].clock == state->cfg.clock)
-			break;
-	}
-
-	adc_cw = af9033_div(clock_adc_lut[i].adc, 1000000ul, 19ul);
-	buf[0] = (adc_cw >>  0) & 0xff;
-	buf[1] = (adc_cw >>  8) & 0xff;
-	buf[2] = (adc_cw >> 16) & 0xff;
-
-	pr_debug("%s: adc=%d adc_cw=%06x\n", __func__, clock_adc_lut[i].adc,
-			adc_cw);
-
-	ret = af9033_wr_regs(state, 0x80f1cd, buf, 3);
-	if (ret < 0)
-		goto err;
-
-	/* program register table */
-	for (i = 0; i < ARRAY_SIZE(tab); i++) {
-		ret = af9033_wr_reg_mask(state, tab[i].reg, tab[i].val,
-				tab[i].mask);
-		if (ret < 0)
-			goto err;
-	}
-
-	/* settings for TS interface */
-	if (state->cfg.ts_mode == AF9033_TS_MODE_USB) {
-		ret = af9033_wr_reg_mask(state, 0x80f9a5, 0x00, 0x01);
-		if (ret < 0)
-			goto err;
-
-		ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x01, 0x01);
-		if (ret < 0)
-			goto err;
-	} else {
-		ret = af9033_wr_reg_mask(state, 0x80f990, 0x00, 0x01);
-		if (ret < 0)
-			goto err;
-
-		ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x00, 0x01);
-		if (ret < 0)
-			goto err;
-	}
-
-	/* load OFSM settings */
-	pr_debug("%s: load ofsm settings\n", __func__);
-	len = ARRAY_SIZE(ofsm_init);
-	init = ofsm_init;
-	for (i = 0; i < len; i++) {
-		ret = af9033_wr_reg(state, init[i].reg, init[i].val);
-		if (ret < 0)
-			goto err;
-	}
-
-	/* load tuner specific settings */
-	pr_debug("%s: load tuner specific settings\n",
-			__func__);
-	switch (state->cfg.tuner) {
-	case AF9033_TUNER_TUA9001:
-		len = ARRAY_SIZE(tuner_init_tua9001);
-		init = tuner_init_tua9001;
-		break;
-	case AF9033_TUNER_FC0011:
-		len = ARRAY_SIZE(tuner_init_fc0011);
-		init = tuner_init_fc0011;
-		break;
-	case AF9033_TUNER_MXL5007T:
-		len = ARRAY_SIZE(tuner_init_mxl5007t);
-		init = tuner_init_mxl5007t;
-		break;
-	case AF9033_TUNER_TDA18218:
-		len = ARRAY_SIZE(tuner_init_tda18218);
-		init = tuner_init_tda18218;
-		break;
-	default:
-		pr_debug("%s: unsupported tuner ID=%d\n", __func__,
-				state->cfg.tuner);
-		ret = -ENODEV;
-		goto err;
-	}
-
-	for (i = 0; i < len; i++) {
-		ret = af9033_wr_reg(state, init[i].reg, init[i].val);
-		if (ret < 0)
-			goto err;
-	}
-
-	state->bandwidth_hz = 0; /* force to program all parameters */
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static int af9033_sleep(struct dvb_frontend *fe)
-{
-	struct af9033_state *state = fe->demodulator_priv;
-	int ret, i;
-	u8 tmp;
-
-	ret = af9033_wr_reg(state, 0x80004c, 1);
-	if (ret < 0)
-		goto err;
-
-	ret = af9033_wr_reg(state, 0x800000, 0);
-	if (ret < 0)
-		goto err;
-
-	for (i = 100, tmp = 1; i && tmp; i--) {
-		ret = af9033_rd_reg(state, 0x80004c, &tmp);
-		if (ret < 0)
-			goto err;
-
-		usleep_range(200, 10000);
-	}
-
-	pr_debug("%s: loop=%d\n", __func__, i);
-
-	if (i == 0) {
-		ret = -ETIMEDOUT;
-		goto err;
-	}
-
-	ret = af9033_wr_reg_mask(state, 0x80fb24, 0x08, 0x08);
-	if (ret < 0)
-		goto err;
-
-	/* prevent current leak (?) */
-	if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
-		/* enable parallel TS */
-		ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01);
-		if (ret < 0)
-			goto err;
-
-		ret = af9033_wr_reg_mask(state, 0x00d916, 0x01, 0x01);
-		if (ret < 0)
-			goto err;
-	}
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static int af9033_get_tune_settings(struct dvb_frontend *fe,
-		struct dvb_frontend_tune_settings *fesettings)
-{
-	fesettings->min_delay_ms = 800;
-	fesettings->step_size = 0;
-	fesettings->max_drift = 0;
-
-	return 0;
-}
-
-static int af9033_set_frontend(struct dvb_frontend *fe)
-{
-	struct af9033_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret, i, spec_inv;
-	u8 tmp, buf[3], bandwidth_reg_val;
-	u32 if_frequency, freq_cw, adc_freq;
-
-	pr_debug("%s: frequency=%d bandwidth_hz=%d\n", __func__, c->frequency,
-			c->bandwidth_hz);
-
-	/* check bandwidth */
-	switch (c->bandwidth_hz) {
-	case 6000000:
-		bandwidth_reg_val = 0x00;
-		break;
-	case 7000000:
-		bandwidth_reg_val = 0x01;
-		break;
-	case 8000000:
-		bandwidth_reg_val = 0x02;
-		break;
-	default:
-		pr_debug("%s: invalid bandwidth_hz\n", __func__);
-		ret = -EINVAL;
-		goto err;
-	}
-
-	/* program tuner */
-	if (fe->ops.tuner_ops.set_params)
-		fe->ops.tuner_ops.set_params(fe);
-
-	/* program CFOE coefficients */
-	if (c->bandwidth_hz != state->bandwidth_hz) {
-		for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) {
-			if (coeff_lut[i].clock == state->cfg.clock &&
-				coeff_lut[i].bandwidth_hz == c->bandwidth_hz) {
-				break;
-			}
-		}
-		ret =  af9033_wr_regs(state, 0x800001,
-				coeff_lut[i].val, sizeof(coeff_lut[i].val));
-	}
-
-	/* program frequency control */
-	if (c->bandwidth_hz != state->bandwidth_hz) {
-		spec_inv = state->cfg.spec_inv ? -1 : 1;
-
-		for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) {
-			if (clock_adc_lut[i].clock == state->cfg.clock)
-				break;
-		}
-		adc_freq = clock_adc_lut[i].adc;
-
-		/* get used IF frequency */
-		if (fe->ops.tuner_ops.get_if_frequency)
-			fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
-		else
-			if_frequency = 0;
-
-		while (if_frequency > (adc_freq / 2))
-			if_frequency -= adc_freq;
-
-		if (if_frequency >= 0)
-			spec_inv *= -1;
-		else
-			if_frequency *= -1;
-
-		freq_cw = af9033_div(if_frequency, adc_freq, 23ul);
-
-		if (spec_inv == -1)
-			freq_cw *= -1;
-
-		/* get adc multiplies */
-		ret = af9033_rd_reg(state, 0x800045, &tmp);
-		if (ret < 0)
-			goto err;
-
-		if (tmp == 1)
-			freq_cw /= 2;
-
-		buf[0] = (freq_cw >>  0) & 0xff;
-		buf[1] = (freq_cw >>  8) & 0xff;
-		buf[2] = (freq_cw >> 16) & 0x7f;
-		ret = af9033_wr_regs(state, 0x800029, buf, 3);
-		if (ret < 0)
-			goto err;
-
-		state->bandwidth_hz = c->bandwidth_hz;
-	}
-
-	ret = af9033_wr_reg_mask(state, 0x80f904, bandwidth_reg_val, 0x03);
-	if (ret < 0)
-		goto err;
-
-	ret = af9033_wr_reg(state, 0x800040, 0x00);
-	if (ret < 0)
-		goto err;
-
-	ret = af9033_wr_reg(state, 0x800047, 0x00);
-	if (ret < 0)
-		goto err;
-
-	ret = af9033_wr_reg_mask(state, 0x80f999, 0x00, 0x01);
-	if (ret < 0)
-		goto err;
-
-	if (c->frequency <= 230000000)
-		tmp = 0x00; /* VHF */
-	else
-		tmp = 0x01; /* UHF */
-
-	ret = af9033_wr_reg(state, 0x80004b, tmp);
-	if (ret < 0)
-		goto err;
-
-	ret = af9033_wr_reg(state, 0x800000, 0x00);
-	if (ret < 0)
-		goto err;
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static int af9033_get_frontend(struct dvb_frontend *fe)
-{
-	struct af9033_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret;
-	u8 buf[8];
-
-	pr_debug("%s\n", __func__);
-
-	/* read all needed registers */
-	ret = af9033_rd_regs(state, 0x80f900, buf, sizeof(buf));
-	if (ret < 0)
-		goto err;
-
-	switch ((buf[0] >> 0) & 3) {
-	case 0:
-		c->transmission_mode = TRANSMISSION_MODE_2K;
-		break;
-	case 1:
-		c->transmission_mode = TRANSMISSION_MODE_8K;
-		break;
-	}
-
-	switch ((buf[1] >> 0) & 3) {
-	case 0:
-		c->guard_interval = GUARD_INTERVAL_1_32;
-		break;
-	case 1:
-		c->guard_interval = GUARD_INTERVAL_1_16;
-		break;
-	case 2:
-		c->guard_interval = GUARD_INTERVAL_1_8;
-		break;
-	case 3:
-		c->guard_interval = GUARD_INTERVAL_1_4;
-		break;
-	}
-
-	switch ((buf[2] >> 0) & 7) {
-	case 0:
-		c->hierarchy = HIERARCHY_NONE;
-		break;
-	case 1:
-		c->hierarchy = HIERARCHY_1;
-		break;
-	case 2:
-		c->hierarchy = HIERARCHY_2;
-		break;
-	case 3:
-		c->hierarchy = HIERARCHY_4;
-		break;
-	}
-
-	switch ((buf[3] >> 0) & 3) {
-	case 0:
-		c->modulation = QPSK;
-		break;
-	case 1:
-		c->modulation = QAM_16;
-		break;
-	case 2:
-		c->modulation = QAM_64;
-		break;
-	}
-
-	switch ((buf[4] >> 0) & 3) {
-	case 0:
-		c->bandwidth_hz = 6000000;
-		break;
-	case 1:
-		c->bandwidth_hz = 7000000;
-		break;
-	case 2:
-		c->bandwidth_hz = 8000000;
-		break;
-	}
-
-	switch ((buf[6] >> 0) & 7) {
-	case 0:
-		c->code_rate_HP = FEC_1_2;
-		break;
-	case 1:
-		c->code_rate_HP = FEC_2_3;
-		break;
-	case 2:
-		c->code_rate_HP = FEC_3_4;
-		break;
-	case 3:
-		c->code_rate_HP = FEC_5_6;
-		break;
-	case 4:
-		c->code_rate_HP = FEC_7_8;
-		break;
-	case 5:
-		c->code_rate_HP = FEC_NONE;
-		break;
-	}
-
-	switch ((buf[7] >> 0) & 7) {
-	case 0:
-		c->code_rate_LP = FEC_1_2;
-		break;
-	case 1:
-		c->code_rate_LP = FEC_2_3;
-		break;
-	case 2:
-		c->code_rate_LP = FEC_3_4;
-		break;
-	case 3:
-		c->code_rate_LP = FEC_5_6;
-		break;
-	case 4:
-		c->code_rate_LP = FEC_7_8;
-		break;
-	case 5:
-		c->code_rate_LP = FEC_NONE;
-		break;
-	}
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct af9033_state *state = fe->demodulator_priv;
-	int ret;
-	u8 tmp;
-
-	*status = 0;
-
-	/* radio channel status, 0=no result, 1=has signal, 2=no signal */
-	ret = af9033_rd_reg(state, 0x800047, &tmp);
-	if (ret < 0)
-		goto err;
-
-	/* has signal */
-	if (tmp == 0x01)
-		*status |= FE_HAS_SIGNAL;
-
-	if (tmp != 0x02) {
-		/* TPS lock */
-		ret = af9033_rd_reg_mask(state, 0x80f5a9, &tmp, 0x01);
-		if (ret < 0)
-			goto err;
-
-		if (tmp)
-			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-					FE_HAS_VITERBI;
-
-		/* full lock */
-		ret = af9033_rd_reg_mask(state, 0x80f999, &tmp, 0x01);
-		if (ret < 0)
-			goto err;
-
-		if (tmp)
-			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-					FE_HAS_VITERBI | FE_HAS_SYNC |
-					FE_HAS_LOCK;
-	}
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct af9033_state *state = fe->demodulator_priv;
-	int ret, i, len;
-	u8 buf[3], tmp;
-	u32 snr_val;
-	const struct val_snr *uninitialized_var(snr_lut);
-
-	/* read value */
-	ret = af9033_rd_regs(state, 0x80002c, buf, 3);
-	if (ret < 0)
-		goto err;
-
-	snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0];
-
-	/* read current modulation */
-	ret = af9033_rd_reg(state, 0x80f903, &tmp);
-	if (ret < 0)
-		goto err;
-
-	switch ((tmp >> 0) & 3) {
-	case 0:
-		len = ARRAY_SIZE(qpsk_snr_lut);
-		snr_lut = qpsk_snr_lut;
-		break;
-	case 1:
-		len = ARRAY_SIZE(qam16_snr_lut);
-		snr_lut = qam16_snr_lut;
-		break;
-	case 2:
-		len = ARRAY_SIZE(qam64_snr_lut);
-		snr_lut = qam64_snr_lut;
-		break;
-	default:
-		goto err;
-	}
-
-	for (i = 0; i < len; i++) {
-		tmp = snr_lut[i].snr;
-
-		if (snr_val < snr_lut[i].val)
-			break;
-	}
-
-	*snr = tmp * 10; /* dB/10 */
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct af9033_state *state = fe->demodulator_priv;
-	int ret;
-	u8 strength2;
-
-	/* read signal strength of 0-100 scale */
-	ret = af9033_rd_reg(state, 0x800048, &strength2);
-	if (ret < 0)
-		goto err;
-
-	/* scale value to 0x0000-0xffff */
-	*strength = strength2 * 0xffff / 100;
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static int af9033_update_ch_stat(struct af9033_state *state)
-{
-	int ret = 0;
-	u32 err_cnt, bit_cnt;
-	u16 abort_cnt;
-	u8 buf[7];
-
-	/* only update data every half second */
-	if (time_after(jiffies, state->last_stat_check + msecs_to_jiffies(500))) {
-		ret = af9033_rd_regs(state, 0x800032, buf, sizeof(buf));
-		if (ret < 0)
-			goto err;
-		/* in 8 byte packets? */
-		abort_cnt = (buf[1] << 8) + buf[0];
-		/* in bits */
-		err_cnt = (buf[4] << 16) + (buf[3] << 8) + buf[2];
-		/* in 8 byte packets? always(?) 0x2710 = 10000 */
-		bit_cnt = (buf[6] << 8) + buf[5];
-
-		if (bit_cnt < abort_cnt) {
-			abort_cnt = 1000;
-			state->ber = 0xffffffff;
-		} else {
-			/* 8 byte packets, that have not been rejected already */
-			bit_cnt -= (u32)abort_cnt;
-			if (bit_cnt == 0) {
-				state->ber = 0xffffffff;
-			} else {
-				err_cnt -= (u32)abort_cnt * 8 * 8;
-				bit_cnt *= 8 * 8;
-				state->ber = err_cnt * (0xffffffff / bit_cnt);
-			}
-		}
-		state->ucb += abort_cnt;
-		state->last_stat_check = jiffies;
-	}
-
-	return 0;
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int af9033_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct af9033_state *state = fe->demodulator_priv;
-	int ret;
-
-	ret = af9033_update_ch_stat(state);
-	if (ret < 0)
-		return ret;
-
-	*ber = state->ber;
-
-	return 0;
-}
-
-static int af9033_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct af9033_state *state = fe->demodulator_priv;
-	int ret;
-
-	ret = af9033_update_ch_stat(state);
-	if (ret < 0)
-		return ret;
-
-	*ucblocks = state->ucb;
-
-	return 0;
-}
-
-static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct af9033_state *state = fe->demodulator_priv;
-	int ret;
-
-	pr_debug("%s: enable=%d\n", __func__, enable);
-
-	ret = af9033_wr_reg_mask(state, 0x00fa04, enable, 0x01);
-	if (ret < 0)
-		goto err;
-
-	return 0;
-
-err:
-	pr_debug("%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static struct dvb_frontend_ops af9033_ops;
-
-struct dvb_frontend *af9033_attach(const struct af9033_config *config,
-		struct i2c_adapter *i2c)
-{
-	int ret;
-	struct af9033_state *state;
-	u8 buf[8];
-
-	pr_debug("%s:\n", __func__);
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct af9033_state), GFP_KERNEL);
-	if (state == NULL)
-		goto err;
-
-	/* setup the state */
-	state->i2c = i2c;
-	memcpy(&state->cfg, config, sizeof(struct af9033_config));
-
-	if (state->cfg.clock != 12000000) {
-		printk(KERN_INFO "af9033: unsupported clock=%d, only " \
-				"12000000 Hz is supported currently\n",
-				state->cfg.clock);
-		goto err;
-	}
-
-	/* firmware version */
-	ret = af9033_rd_regs(state, 0x0083e9, &buf[0], 4);
-	if (ret < 0)
-		goto err;
-
-	ret = af9033_rd_regs(state, 0x804191, &buf[4], 4);
-	if (ret < 0)
-		goto err;
-
-	printk(KERN_INFO "af9033: firmware version: LINK=%d.%d.%d.%d " \
-			"OFDM=%d.%d.%d.%d\n", buf[0], buf[1], buf[2], buf[3],
-			buf[4], buf[5], buf[6], buf[7]);
-
-	/* configure internal TS mode */
-	switch (state->cfg.ts_mode) {
-	case AF9033_TS_MODE_PARALLEL:
-		state->ts_mode_parallel = true;
-		break;
-	case AF9033_TS_MODE_SERIAL:
-		state->ts_mode_serial = true;
-		break;
-	case AF9033_TS_MODE_USB:
-		/* usb mode for AF9035 */
-	default:
-		break;
-	}
-
-	/* create dvb_frontend */
-	memcpy(&state->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops));
-	state->fe.demodulator_priv = state;
-
-	return &state->fe;
-
-err:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(af9033_attach);
-
-static struct dvb_frontend_ops af9033_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name = "Afatech AF9033 (DVB-T)",
-		.frequency_min = 174000000,
-		.frequency_max = 862000000,
-		.frequency_stepsize = 250000,
-		.frequency_tolerance = 0,
-		.caps =	FE_CAN_FEC_1_2 |
-			FE_CAN_FEC_2_3 |
-			FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 |
-			FE_CAN_FEC_7_8 |
-			FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK |
-			FE_CAN_QAM_16 |
-			FE_CAN_QAM_64 |
-			FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_HIERARCHY_AUTO |
-			FE_CAN_RECOVER |
-			FE_CAN_MUTE_TS
-	},
-
-	.release = af9033_release,
-
-	.init = af9033_init,
-	.sleep = af9033_sleep,
-
-	.get_tune_settings = af9033_get_tune_settings,
-	.set_frontend = af9033_set_frontend,
-	.get_frontend = af9033_get_frontend,
-
-	.read_status = af9033_read_status,
-	.read_snr = af9033_read_snr,
-	.read_signal_strength = af9033_read_signal_strength,
-	.read_ber = af9033_read_ber,
-	.read_ucblocks = af9033_read_ucblocks,
-
-	.i2c_gate_ctrl = af9033_i2c_gate_ctrl,
-};
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Afatech AF9033 DVB-T demodulator driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/af9033.h b/drivers/media/dvb/frontends/af9033.h
deleted file mode 100644
index 9e302c3..0000000
--- a/drivers/media/dvb/frontends/af9033.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Afatech AF9033 demodulator driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef AF9033_H
-#define AF9033_H
-
-struct af9033_config {
-	/*
-	 * I2C address
-	 */
-	u8 i2c_addr;
-
-	/*
-	 * clock Hz
-	 * 12000000, 22000000, 24000000, 34000000, 32000000, 28000000, 26000000,
-	 * 30000000, 36000000, 20480000, 16384000
-	 */
-	u32 clock;
-
-	/*
-	 * tuner
-	 */
-#define AF9033_TUNER_TUA9001     0x27 /* Infineon TUA 9001 */
-#define AF9033_TUNER_FC0011      0x28 /* Fitipower FC0011 */
-#define AF9033_TUNER_MXL5007T    0xa0 /* MaxLinear MxL5007T */
-#define AF9033_TUNER_TDA18218    0xa1 /* NXP TDA 18218HN */
-	u8 tuner;
-
-	/*
-	 * TS settings
-	 */
-#define AF9033_TS_MODE_USB       0
-#define AF9033_TS_MODE_PARALLEL  1
-#define AF9033_TS_MODE_SERIAL    2
-	u8 ts_mode:2;
-
-	/*
-	 * input spectrum inversion
-	 */
-	bool spec_inv;
-};
-
-
-#if defined(CONFIG_DVB_AF9033) || \
-	(defined(CONFIG_DVB_AF9033_MODULE) && defined(MODULE))
-extern struct dvb_frontend *af9033_attach(const struct af9033_config *config,
-	struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *af9033_attach(
-	const struct af9033_config *config, struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* AF9033_H */
diff --git a/drivers/media/dvb/frontends/af9033_priv.h b/drivers/media/dvb/frontends/af9033_priv.h
deleted file mode 100644
index 0b783b9..0000000
--- a/drivers/media/dvb/frontends/af9033_priv.h
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * Afatech AF9033 demodulator driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef AF9033_PRIV_H
-#define AF9033_PRIV_H
-
-#include "dvb_frontend.h"
-#include "af9033.h"
-
-struct reg_val {
-	u32 reg;
-	u8  val;
-};
-
-struct reg_val_mask {
-	u32 reg;
-	u8  val;
-	u8  mask;
-};
-
-struct coeff {
-	u32 clock;
-	u32 bandwidth_hz;
-	u8 val[36];
-};
-
-struct clock_adc {
-	u32 clock;
-	u32 adc;
-};
-
-struct val_snr {
-	u32 val;
-	u8 snr;
-};
-
-/* Xtal clock vs. ADC clock lookup table */
-static const struct clock_adc clock_adc_lut[] = {
-	{ 16384000, 20480000 },
-	{ 20480000, 20480000 },
-	{ 36000000, 20250000 },
-	{ 30000000, 20156250 },
-	{ 26000000, 20583333 },
-	{ 28000000, 20416667 },
-	{ 32000000, 20500000 },
-	{ 34000000, 20187500 },
-	{ 24000000, 20500000 },
-	{ 22000000, 20625000 },
-	{ 12000000, 20250000 },
-};
-
-/* pre-calculated coeff lookup table */
-static const struct coeff coeff_lut[] = {
-	/* 12.000 MHz */
-	{ 12000000, 8000000, {
-		0x01, 0xce, 0x55, 0xc9, 0x00, 0xe7, 0x2a, 0xe4, 0x00, 0x73,
-		0x99, 0x0f, 0x00, 0x73, 0x95, 0x72, 0x00, 0x73, 0x91, 0xd5,
-		0x00, 0x39, 0xca, 0xb9, 0x00, 0xe7, 0x2a, 0xe4, 0x00, 0x73,
-		0x95, 0x72, 0x37, 0x02, 0xce, 0x01 }
-	},
-	{ 12000000, 7000000, {
-		0x01, 0x94, 0x8b, 0x10, 0x00, 0xca, 0x45, 0x88, 0x00, 0x65,
-		0x25, 0xed, 0x00, 0x65, 0x22, 0xc4, 0x00, 0x65, 0x1f, 0x9b,
-		0x00, 0x32, 0x91, 0x62, 0x00, 0xca, 0x45, 0x88, 0x00, 0x65,
-		0x22, 0xc4, 0x88, 0x02, 0x95, 0x01 }
-	},
-	{ 12000000, 6000000, {
-		0x01, 0x5a, 0xc0, 0x56, 0x00, 0xad, 0x60, 0x2b, 0x00, 0x56,
-		0xb2, 0xcb, 0x00, 0x56, 0xb0, 0x15, 0x00, 0x56, 0xad, 0x60,
-		0x00, 0x2b, 0x58, 0x0b, 0x00, 0xad, 0x60, 0x2b, 0x00, 0x56,
-		0xb0, 0x15, 0xf4, 0x02, 0x5b, 0x01 }
-	},
-};
-
-/* QPSK SNR lookup table */
-static const struct val_snr qpsk_snr_lut[] = {
-	{ 0x0b4771,  0 },
-	{ 0x0c1aed,  1 },
-	{ 0x0d0d27,  2 },
-	{ 0x0e4d19,  3 },
-	{ 0x0e5da8,  4 },
-	{ 0x107097,  5 },
-	{ 0x116975,  6 },
-	{ 0x1252d9,  7 },
-	{ 0x131fa4,  8 },
-	{ 0x13d5e1,  9 },
-	{ 0x148e53, 10 },
-	{ 0x15358b, 11 },
-	{ 0x15dd29, 12 },
-	{ 0x168112, 13 },
-	{ 0x170b61, 14 },
-	{ 0x17a532, 15 },
-	{ 0x180f94, 16 },
-	{ 0x186ed2, 17 },
-	{ 0x18b271, 18 },
-	{ 0x18e118, 19 },
-	{ 0x18ff4b, 20 },
-	{ 0x190af1, 21 },
-	{ 0x191451, 22 },
-	{ 0xffffff, 23 },
-};
-
-/* QAM16 SNR lookup table */
-static const struct val_snr qam16_snr_lut[] = {
-	{ 0x04f0d5,  0 },
-	{ 0x05387a,  1 },
-	{ 0x0573a4,  2 },
-	{ 0x05a99e,  3 },
-	{ 0x05cc80,  4 },
-	{ 0x05eb62,  5 },
-	{ 0x05fecf,  6 },
-	{ 0x060b80,  7 },
-	{ 0x062501,  8 },
-	{ 0x064865,  9 },
-	{ 0x069604, 10 },
-	{ 0x06f356, 11 },
-	{ 0x07706a, 12 },
-	{ 0x0804d3, 13 },
-	{ 0x089d1a, 14 },
-	{ 0x093e3d, 15 },
-	{ 0x09e35d, 16 },
-	{ 0x0a7c3c, 17 },
-	{ 0x0afaf8, 18 },
-	{ 0x0b719d, 19 },
-	{ 0x0bda6a, 20 },
-	{ 0x0c0c75, 21 },
-	{ 0x0c3f7d, 22 },
-	{ 0x0c5e62, 23 },
-	{ 0x0c6c31, 24 },
-	{ 0x0c7925, 25 },
-	{ 0xffffff, 26 },
-};
-
-/* QAM64 SNR lookup table */
-static const struct val_snr qam64_snr_lut[] = {
-	{ 0x0256d0,  0 },
-	{ 0x027a65,  1 },
-	{ 0x029873,  2 },
-	{ 0x02b7fe,  3 },
-	{ 0x02cf1e,  4 },
-	{ 0x02e234,  5 },
-	{ 0x02f409,  6 },
-	{ 0x030046,  7 },
-	{ 0x030844,  8 },
-	{ 0x030a02,  9 },
-	{ 0x030cde, 10 },
-	{ 0x031031, 11 },
-	{ 0x03144c, 12 },
-	{ 0x0315dd, 13 },
-	{ 0x031920, 14 },
-	{ 0x0322d0, 15 },
-	{ 0x0339fc, 16 },
-	{ 0x0364a1, 17 },
-	{ 0x038bcc, 18 },
-	{ 0x03c7d3, 19 },
-	{ 0x0408cc, 20 },
-	{ 0x043bed, 21 },
-	{ 0x048061, 22 },
-	{ 0x04be95, 23 },
-	{ 0x04fa7d, 24 },
-	{ 0x052405, 25 },
-	{ 0x05570d, 26 },
-	{ 0x059feb, 27 },
-	{ 0x05bf38, 28 },
-	{ 0xffffff, 29 },
-};
-
-static const struct reg_val ofsm_init[] = {
-	{ 0x800051, 0x01 },
-	{ 0x800070, 0x0a },
-	{ 0x80007e, 0x04 },
-	{ 0x800081, 0x0a },
-	{ 0x80008a, 0x01 },
-	{ 0x80008e, 0x01 },
-	{ 0x800092, 0x06 },
-	{ 0x800099, 0x01 },
-	{ 0x80009f, 0xe1 },
-	{ 0x8000a0, 0xcf },
-	{ 0x8000a3, 0x01 },
-	{ 0x8000a5, 0x01 },
-	{ 0x8000a6, 0x01 },
-	{ 0x8000a9, 0x00 },
-	{ 0x8000aa, 0x01 },
-	{ 0x8000ab, 0x01 },
-	{ 0x8000b0, 0x01 },
-	{ 0x8000c0, 0x05 },
-	{ 0x8000c4, 0x19 },
-	{ 0x80f000, 0x0f },
-	{ 0x80f016, 0x10 },
-	{ 0x80f017, 0x04 },
-	{ 0x80f018, 0x05 },
-	{ 0x80f019, 0x04 },
-	{ 0x80f01a, 0x05 },
-	{ 0x80f021, 0x03 },
-	{ 0x80f022, 0x0a },
-	{ 0x80f023, 0x0a },
-	{ 0x80f02b, 0x00 },
-	{ 0x80f02c, 0x01 },
-	{ 0x80f064, 0x03 },
-	{ 0x80f065, 0xf9 },
-	{ 0x80f066, 0x03 },
-	{ 0x80f067, 0x01 },
-	{ 0x80f06f, 0xe0 },
-	{ 0x80f070, 0x03 },
-	{ 0x80f072, 0x0f },
-	{ 0x80f073, 0x03 },
-	{ 0x80f078, 0x00 },
-	{ 0x80f087, 0x00 },
-	{ 0x80f09b, 0x3f },
-	{ 0x80f09c, 0x00 },
-	{ 0x80f09d, 0x20 },
-	{ 0x80f09e, 0x00 },
-	{ 0x80f09f, 0x0c },
-	{ 0x80f0a0, 0x00 },
-	{ 0x80f130, 0x04 },
-	{ 0x80f132, 0x04 },
-	{ 0x80f144, 0x1a },
-	{ 0x80f146, 0x00 },
-	{ 0x80f14a, 0x01 },
-	{ 0x80f14c, 0x00 },
-	{ 0x80f14d, 0x00 },
-	{ 0x80f14f, 0x04 },
-	{ 0x80f158, 0x7f },
-	{ 0x80f15a, 0x00 },
-	{ 0x80f15b, 0x08 },
-	{ 0x80f15d, 0x03 },
-	{ 0x80f15e, 0x05 },
-	{ 0x80f163, 0x05 },
-	{ 0x80f166, 0x01 },
-	{ 0x80f167, 0x40 },
-	{ 0x80f168, 0x0f },
-	{ 0x80f17a, 0x00 },
-	{ 0x80f17b, 0x00 },
-	{ 0x80f183, 0x01 },
-	{ 0x80f19d, 0x40 },
-	{ 0x80f1bc, 0x36 },
-	{ 0x80f1bd, 0x00 },
-	{ 0x80f1cb, 0xa0 },
-	{ 0x80f1cc, 0x01 },
-	{ 0x80f204, 0x10 },
-	{ 0x80f214, 0x00 },
-	{ 0x80f40e, 0x0a },
-	{ 0x80f40f, 0x40 },
-	{ 0x80f410, 0x08 },
-	{ 0x80f55f, 0x0a },
-	{ 0x80f561, 0x15 },
-	{ 0x80f562, 0x20 },
-	{ 0x80f5df, 0xfb },
-	{ 0x80f5e0, 0x00 },
-	{ 0x80f5e3, 0x09 },
-	{ 0x80f5e4, 0x01 },
-	{ 0x80f5e5, 0x01 },
-	{ 0x80f5f8, 0x01 },
-	{ 0x80f5fd, 0x01 },
-	{ 0x80f600, 0x05 },
-	{ 0x80f601, 0x08 },
-	{ 0x80f602, 0x0b },
-	{ 0x80f603, 0x0e },
-	{ 0x80f604, 0x11 },
-	{ 0x80f605, 0x14 },
-	{ 0x80f606, 0x17 },
-	{ 0x80f607, 0x1f },
-	{ 0x80f60e, 0x00 },
-	{ 0x80f60f, 0x04 },
-	{ 0x80f610, 0x32 },
-	{ 0x80f611, 0x10 },
-	{ 0x80f707, 0xfc },
-	{ 0x80f708, 0x00 },
-	{ 0x80f709, 0x37 },
-	{ 0x80f70a, 0x00 },
-	{ 0x80f78b, 0x01 },
-	{ 0x80f80f, 0x40 },
-	{ 0x80f810, 0x54 },
-	{ 0x80f811, 0x5a },
-	{ 0x80f905, 0x01 },
-	{ 0x80fb06, 0x03 },
-	{ 0x80fd8b, 0x00 },
-};
-
-/* Infineon TUA 9001 tuner init
-   AF9033_TUNER_TUA9001    = 0x27 */
-static const struct reg_val tuner_init_tua9001[] = {
-	{ 0x800046, 0x27 },
-	{ 0x800057, 0x00 },
-	{ 0x800058, 0x01 },
-	{ 0x80005f, 0x00 },
-	{ 0x800060, 0x00 },
-	{ 0x80006d, 0x00 },
-	{ 0x800071, 0x05 },
-	{ 0x800072, 0x02 },
-	{ 0x800074, 0x01 },
-	{ 0x800075, 0x03 },
-	{ 0x800076, 0x02 },
-	{ 0x800077, 0x00 },
-	{ 0x800078, 0x01 },
-	{ 0x800079, 0x00 },
-	{ 0x80007a, 0x7e },
-	{ 0x80007b, 0x3e },
-	{ 0x800093, 0x00 },
-	{ 0x800094, 0x01 },
-	{ 0x800095, 0x02 },
-	{ 0x800096, 0x01 },
-	{ 0x800098, 0x0a },
-	{ 0x80009b, 0x05 },
-	{ 0x80009c, 0x80 },
-	{ 0x8000b3, 0x00 },
-	{ 0x8000c1, 0x01 },
-	{ 0x8000c2, 0x00 },
-	{ 0x80f007, 0x00 },
-	{ 0x80f01f, 0x82 },
-	{ 0x80f020, 0x00 },
-	{ 0x80f029, 0x82 },
-	{ 0x80f02a, 0x00 },
-	{ 0x80f047, 0x00 },
-	{ 0x80f054, 0x00 },
-	{ 0x80f055, 0x00 },
-	{ 0x80f077, 0x01 },
-	{ 0x80f1e6, 0x00 },
-};
-
-/* Fitipower fc0011 tuner init
-   AF9033_TUNER_FC0011    = 0x28 */
-static const struct reg_val tuner_init_fc0011[] = {
-	{ 0x800046, AF9033_TUNER_FC0011 },
-	{ 0x800057, 0x00 },
-	{ 0x800058, 0x01 },
-	{ 0x80005f, 0x00 },
-	{ 0x800060, 0x00 },
-	{ 0x800068, 0xa5 },
-	{ 0x80006e, 0x01 },
-	{ 0x800071, 0x0A },
-	{ 0x800072, 0x02 },
-	{ 0x800074, 0x01 },
-	{ 0x800079, 0x01 },
-	{ 0x800093, 0x00 },
-	{ 0x800094, 0x00 },
-	{ 0x800095, 0x00 },
-	{ 0x800096, 0x00 },
-	{ 0x80009b, 0x2D },
-	{ 0x80009c, 0x60 },
-	{ 0x80009d, 0x23 },
-	{ 0x8000a4, 0x50 },
-	{ 0x8000ad, 0x50 },
-	{ 0x8000b3, 0x01 },
-	{ 0x8000b7, 0x88 },
-	{ 0x8000b8, 0xa6 },
-	{ 0x8000c3, 0x01 },
-	{ 0x8000c4, 0x01 },
-	{ 0x8000c7, 0x69 },
-	{ 0x80F007, 0x00 },
-	{ 0x80F00A, 0x1B },
-	{ 0x80F00B, 0x1B },
-	{ 0x80F00C, 0x1B },
-	{ 0x80F00D, 0x1B },
-	{ 0x80F00E, 0xFF },
-	{ 0x80F00F, 0x01 },
-	{ 0x80F010, 0x00 },
-	{ 0x80F011, 0x02 },
-	{ 0x80F012, 0xFF },
-	{ 0x80F013, 0x01 },
-	{ 0x80F014, 0x00 },
-	{ 0x80F015, 0x02 },
-	{ 0x80F01B, 0xEF },
-	{ 0x80F01C, 0x01 },
-	{ 0x80F01D, 0x0f },
-	{ 0x80F01E, 0x02 },
-	{ 0x80F01F, 0x6E },
-	{ 0x80F020, 0x00 },
-	{ 0x80F025, 0xDE },
-	{ 0x80F026, 0x00 },
-	{ 0x80F027, 0x0A },
-	{ 0x80F028, 0x03 },
-	{ 0x80F029, 0x6E },
-	{ 0x80F02A, 0x00 },
-	{ 0x80F047, 0x00 },
-	{ 0x80F054, 0x00 },
-	{ 0x80F055, 0x00 },
-	{ 0x80F077, 0x01 },
-	{ 0x80F1E6, 0x00 },
-};
-
-/* MaxLinear MxL5007T tuner init
-   AF9033_TUNER_MXL5007T    = 0xa0 */
-static const struct reg_val tuner_init_mxl5007t[] = {
-	{ 0x800046, 0x1b },
-	{ 0x800057, 0x01 },
-	{ 0x800058, 0x01 },
-	{ 0x80005f, 0x00 },
-	{ 0x800060, 0x00 },
-	{ 0x800068, 0x96 },
-	{ 0x800071, 0x05 },
-	{ 0x800072, 0x02 },
-	{ 0x800074, 0x01 },
-	{ 0x800079, 0x01 },
-	{ 0x800093, 0x00 },
-	{ 0x800094, 0x00 },
-	{ 0x800095, 0x00 },
-	{ 0x800096, 0x00 },
-	{ 0x8000b3, 0x01 },
-	{ 0x8000c1, 0x01 },
-	{ 0x8000c2, 0x00 },
-	{ 0x80f007, 0x00 },
-	{ 0x80f00c, 0x19 },
-	{ 0x80f00d, 0x1a },
-	{ 0x80f012, 0xda },
-	{ 0x80f013, 0x00 },
-	{ 0x80f014, 0x00 },
-	{ 0x80f015, 0x02 },
-	{ 0x80f01f, 0x82 },
-	{ 0x80f020, 0x00 },
-	{ 0x80f029, 0x82 },
-	{ 0x80f02a, 0x00 },
-	{ 0x80f077, 0x02 },
-	{ 0x80f1e6, 0x00 },
-};
-
-/* NXP TDA 18218HN tuner init
-   AF9033_TUNER_TDA18218    = 0xa1 */
-static const struct reg_val tuner_init_tda18218[] = {
-	{0x800046, 0xa1},
-	{0x800057, 0x01},
-	{0x800058, 0x01},
-	{0x80005f, 0x00},
-	{0x800060, 0x00},
-	{0x800071, 0x05},
-	{0x800072, 0x02},
-	{0x800074, 0x01},
-	{0x800079, 0x01},
-	{0x800093, 0x00},
-	{0x800094, 0x00},
-	{0x800095, 0x00},
-	{0x800096, 0x00},
-	{0x8000b3, 0x01},
-	{0x8000c3, 0x01},
-	{0x8000c4, 0x00},
-	{0x80f007, 0x00},
-	{0x80f00c, 0x19},
-	{0x80f00d, 0x1a},
-	{0x80f012, 0xda},
-	{0x80f013, 0x00},
-	{0x80f014, 0x00},
-	{0x80f015, 0x02},
-	{0x80f01f, 0x82},
-	{0x80f020, 0x00},
-	{0x80f029, 0x82},
-	{0x80f02a, 0x00},
-	{0x80f077, 0x02},
-	{0x80f1e6, 0x00},
-};
-
-#endif /* AF9033_PRIV_H */
-
diff --git a/drivers/media/dvb/frontends/atbm8830.c b/drivers/media/dvb/frontends/atbm8830.c
deleted file mode 100644
index a2261ea..0000000
--- a/drivers/media/dvb/frontends/atbm8830.c
+++ /dev/null
@@ -1,508 +0,0 @@
-/*
- *    Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator
- *    ATBM8830, ATBM8831
- *
- *    Copyright (C) 2009 David T.L. Wong <davidtlwong@gmail.com>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <asm/div64.h>
-#include "dvb_frontend.h"
-
-#include "atbm8830.h"
-#include "atbm8830_priv.h"
-
-#define dprintk(args...) \
-	do { \
-		if (debug) \
-			printk(KERN_DEBUG "atbm8830: " args); \
-	} while (0)
-
-static int debug;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-static int atbm8830_write_reg(struct atbm_state *priv, u16 reg, u8 data)
-{
-	int ret = 0;
-	u8 dev_addr;
-	u8 buf1[] = { reg >> 8, reg & 0xFF };
-	u8 buf2[] = { data };
-	struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 };
-	struct i2c_msg msg2 = { .flags = 0, .buf = buf2, .len = 1 };
-
-	dev_addr = priv->config->demod_address;
-	msg1.addr = dev_addr;
-	msg2.addr = dev_addr;
-
-	if (debug >= 2)
-		dprintk("%s: reg=0x%04X, data=0x%02X\n", __func__, reg, data);
-
-	ret = i2c_transfer(priv->i2c, &msg1, 1);
-	if (ret != 1)
-		return -EIO;
-
-	ret = i2c_transfer(priv->i2c, &msg2, 1);
-	return (ret != 1) ? -EIO : 0;
-}
-
-static int atbm8830_read_reg(struct atbm_state *priv, u16 reg, u8 *p_data)
-{
-	int ret;
-	u8 dev_addr;
-
-	u8 buf1[] = { reg >> 8, reg & 0xFF };
-	u8 buf2[] = { 0 };
-	struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 };
-	struct i2c_msg msg2 = { .flags = I2C_M_RD, .buf = buf2, .len = 1 };
-
-	dev_addr = priv->config->demod_address;
-	msg1.addr = dev_addr;
-	msg2.addr = dev_addr;
-
-	ret = i2c_transfer(priv->i2c, &msg1, 1);
-	if (ret != 1) {
-		dprintk("%s: error reg=0x%04x, ret=%i\n", __func__, reg, ret);
-		return -EIO;
-	}
-
-	ret = i2c_transfer(priv->i2c, &msg2, 1);
-	if (ret != 1)
-		return -EIO;
-
-	*p_data = buf2[0];
-	if (debug >= 2)
-		dprintk("%s: reg=0x%04X, data=0x%02X\n",
-			__func__, reg, buf2[0]);
-
-	return 0;
-}
-
-/* Lock register latch so that multi-register read is atomic */
-static inline int atbm8830_reglatch_lock(struct atbm_state *priv, int lock)
-{
-	return atbm8830_write_reg(priv, REG_READ_LATCH, lock ? 1 : 0);
-}
-
-static int set_osc_freq(struct atbm_state *priv, u32 freq /*in kHz*/)
-{
-	u32 val;
-	u64 t;
-
-	/* 0x100000 * freq / 30.4MHz */
-	t = (u64)0x100000 * freq;
-	do_div(t, 30400);
-	val = t;
-
-	atbm8830_write_reg(priv, REG_OSC_CLK, val);
-	atbm8830_write_reg(priv, REG_OSC_CLK + 1, val >> 8);
-	atbm8830_write_reg(priv, REG_OSC_CLK + 2, val >> 16);
-
-	return 0;
-}
-
-static int set_if_freq(struct atbm_state *priv, u32 freq /*in kHz*/)
-{
-
-	u32 fs = priv->config->osc_clk_freq;
-	u64 t;
-	u32 val;
-	u8 dat;
-
-	if (freq != 0) {
-		/* 2 * PI * (freq - fs) / fs * (2 ^ 22) */
-		t = (u64) 2 * 31416 * (freq - fs);
-		t <<= 22;
-		do_div(t, fs);
-		do_div(t, 1000);
-		val = t;
-
-		atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 1);
-		atbm8830_write_reg(priv, REG_IF_FREQ, val);
-		atbm8830_write_reg(priv, REG_IF_FREQ+1, val >> 8);
-		atbm8830_write_reg(priv, REG_IF_FREQ+2, val >> 16);
-
-		atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat);
-		dat &= 0xFC;
-		atbm8830_write_reg(priv, REG_ADC_CONFIG, dat);
-	} else {
-		/* Zero IF */
-		atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 0);
-
-		atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat);
-		dat &= 0xFC;
-		dat |= 0x02;
-		atbm8830_write_reg(priv, REG_ADC_CONFIG, dat);
-
-		if (priv->config->zif_swap_iq)
-			atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x03);
-		else
-			atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x01);
-	}
-
-	return 0;
-}
-
-static int is_locked(struct atbm_state *priv, u8 *locked)
-{
-	u8 status;
-
-	atbm8830_read_reg(priv, REG_LOCK_STATUS, &status);
-
-	if (locked != NULL)
-		*locked = (status == 1);
-	return 0;
-}
-
-static int set_agc_config(struct atbm_state *priv,
-	u8 min, u8 max, u8 hold_loop)
-{
-	/* no effect if both min and max are zero */
-	if (!min && !max)
-	    return 0;
-
-	atbm8830_write_reg(priv, REG_AGC_MIN, min);
-	atbm8830_write_reg(priv, REG_AGC_MAX, max);
-	atbm8830_write_reg(priv, REG_AGC_HOLD_LOOP, hold_loop);
-
-	return 0;
-}
-
-static int set_static_channel_mode(struct atbm_state *priv)
-{
-	int i;
-
-	for (i = 0; i < 5; i++)
-		atbm8830_write_reg(priv, 0x099B + i, 0x08);
-
-	atbm8830_write_reg(priv, 0x095B, 0x7F);
-	atbm8830_write_reg(priv, 0x09CB, 0x01);
-	atbm8830_write_reg(priv, 0x09CC, 0x7F);
-	atbm8830_write_reg(priv, 0x09CD, 0x7F);
-	atbm8830_write_reg(priv, 0x0E01, 0x20);
-
-	/* For single carrier */
-	atbm8830_write_reg(priv, 0x0B03, 0x0A);
-	atbm8830_write_reg(priv, 0x0935, 0x10);
-	atbm8830_write_reg(priv, 0x0936, 0x08);
-	atbm8830_write_reg(priv, 0x093E, 0x08);
-	atbm8830_write_reg(priv, 0x096E, 0x06);
-
-	/* frame_count_max0 */
-	atbm8830_write_reg(priv, 0x0B09, 0x00);
-	/* frame_count_max1 */
-	atbm8830_write_reg(priv, 0x0B0A, 0x08);
-
-	return 0;
-}
-
-static int set_ts_config(struct atbm_state *priv)
-{
-	const struct atbm8830_config *cfg = priv->config;
-
-	/*Set parallel/serial ts mode*/
-	atbm8830_write_reg(priv, REG_TS_SERIAL, cfg->serial_ts ? 1 : 0);
-	atbm8830_write_reg(priv, REG_TS_CLK_MODE, cfg->serial_ts ? 1 : 0);
-	/*Set ts sampling edge*/
-	atbm8830_write_reg(priv, REG_TS_SAMPLE_EDGE,
-		cfg->ts_sampling_edge ? 1 : 0);
-	/*Set ts clock freerun*/
-	atbm8830_write_reg(priv, REG_TS_CLK_FREERUN,
-		cfg->ts_clk_gated ? 0 : 1);
-
-	return 0;
-}
-
-static int atbm8830_init(struct dvb_frontend *fe)
-{
-	struct atbm_state *priv = fe->demodulator_priv;
-	const struct atbm8830_config *cfg = priv->config;
-
-	/*Set oscillator frequency*/
-	set_osc_freq(priv, cfg->osc_clk_freq);
-
-	/*Set IF frequency*/
-	set_if_freq(priv, cfg->if_freq);
-
-	/*Set AGC Config*/
-	set_agc_config(priv, cfg->agc_min, cfg->agc_max,
-		cfg->agc_hold_loop);
-
-	/*Set static channel mode*/
-	set_static_channel_mode(priv);
-
-	set_ts_config(priv);
-	/*Turn off DSP reset*/
-	atbm8830_write_reg(priv, 0x000A, 0);
-
-	/*SW version test*/
-	atbm8830_write_reg(priv, 0x020C, 11);
-
-	/* Run */
-	atbm8830_write_reg(priv, REG_DEMOD_RUN, 1);
-
-	return 0;
-}
-
-
-static void atbm8830_release(struct dvb_frontend *fe)
-{
-	struct atbm_state *state = fe->demodulator_priv;
-	dprintk("%s\n", __func__);
-
-	kfree(state);
-}
-
-static int atbm8830_set_fe(struct dvb_frontend *fe)
-{
-	struct atbm_state *priv = fe->demodulator_priv;
-	int i;
-	u8 locked = 0;
-	dprintk("%s\n", __func__);
-
-	/* set frequency */
-	if (fe->ops.tuner_ops.set_params) {
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	/* start auto lock */
-	for (i = 0; i < 10; i++) {
-		mdelay(100);
-		dprintk("Try %d\n", i);
-		is_locked(priv, &locked);
-		if (locked != 0) {
-			dprintk("ATBM8830 locked!\n");
-			break;
-		}
-	}
-
-	return 0;
-}
-
-static int atbm8830_get_fe(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	dprintk("%s\n", __func__);
-
-	/* TODO: get real readings from device */
-	/* inversion status */
-	c->inversion = INVERSION_OFF;
-
-	/* bandwidth */
-	c->bandwidth_hz = 8000000;
-
-	c->code_rate_HP = FEC_AUTO;
-	c->code_rate_LP = FEC_AUTO;
-
-	c->modulation = QAM_AUTO;
-
-	/* transmission mode */
-	c->transmission_mode = TRANSMISSION_MODE_AUTO;
-
-	/* guard interval */
-	c->guard_interval = GUARD_INTERVAL_AUTO;
-
-	/* hierarchy */
-	c->hierarchy = HIERARCHY_NONE;
-
-	return 0;
-}
-
-static int atbm8830_get_tune_settings(struct dvb_frontend *fe,
-	struct dvb_frontend_tune_settings *fesettings)
-{
-	fesettings->min_delay_ms = 0;
-	fesettings->step_size = 0;
-	fesettings->max_drift = 0;
-	return 0;
-}
-
-static int atbm8830_read_status(struct dvb_frontend *fe, fe_status_t *fe_status)
-{
-	struct atbm_state *priv = fe->demodulator_priv;
-	u8 locked = 0;
-	u8 agc_locked = 0;
-
-	dprintk("%s\n", __func__);
-	*fe_status = 0;
-
-	is_locked(priv, &locked);
-	if (locked) {
-		*fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-			FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
-	}
-	dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
-
-	atbm8830_read_reg(priv, REG_AGC_LOCK, &agc_locked);
-	dprintk("AGC Lock: %d\n", agc_locked);
-
-	return 0;
-}
-
-static int atbm8830_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct atbm_state *priv = fe->demodulator_priv;
-	u32 frame_err;
-	u8 t;
-
-	dprintk("%s\n", __func__);
-
-	atbm8830_reglatch_lock(priv, 1);
-
-	atbm8830_read_reg(priv, REG_FRAME_ERR_CNT + 1, &t);
-	frame_err = t & 0x7F;
-	frame_err <<= 8;
-	atbm8830_read_reg(priv, REG_FRAME_ERR_CNT, &t);
-	frame_err |= t;
-
-	atbm8830_reglatch_lock(priv, 0);
-
-	*ber = frame_err * 100 / 32767;
-
-	dprintk("%s: ber=0x%x\n", __func__, *ber);
-	return 0;
-}
-
-static int atbm8830_read_signal_strength(struct dvb_frontend *fe, u16 *signal)
-{
-	struct atbm_state *priv = fe->demodulator_priv;
-	u32 pwm;
-	u8 t;
-
-	dprintk("%s\n", __func__);
-	atbm8830_reglatch_lock(priv, 1);
-
-	atbm8830_read_reg(priv, REG_AGC_PWM_VAL + 1, &t);
-	pwm = t & 0x03;
-	pwm <<= 8;
-	atbm8830_read_reg(priv, REG_AGC_PWM_VAL, &t);
-	pwm |= t;
-
-	atbm8830_reglatch_lock(priv, 0);
-
-	dprintk("AGC PWM = 0x%02X\n", pwm);
-	pwm = 0x400 - pwm;
-
-	*signal = pwm * 0x10000 / 0x400;
-
-	return 0;
-}
-
-static int atbm8830_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	dprintk("%s\n", __func__);
-	*snr = 0;
-	return 0;
-}
-
-static int atbm8830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	dprintk("%s\n", __func__);
-	*ucblocks = 0;
-	return 0;
-}
-
-static int atbm8830_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct atbm_state *priv = fe->demodulator_priv;
-
-	return atbm8830_write_reg(priv, REG_I2C_GATE, enable ? 1 : 0);
-}
-
-static struct dvb_frontend_ops atbm8830_ops = {
-	.delsys = { SYS_DMBTH },
-	.info = {
-		.name = "AltoBeam ATBM8830/8831 DMB-TH",
-		.frequency_min = 474000000,
-		.frequency_max = 858000000,
-		.frequency_stepsize = 10000,
-		.caps =
-			FE_CAN_FEC_AUTO |
-			FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO
-	},
-
-	.release = atbm8830_release,
-
-	.init = atbm8830_init,
-	.sleep = NULL,
-	.write = NULL,
-	.i2c_gate_ctrl = atbm8830_i2c_gate_ctrl,
-
-	.set_frontend = atbm8830_set_fe,
-	.get_frontend = atbm8830_get_fe,
-	.get_tune_settings = atbm8830_get_tune_settings,
-
-	.read_status = atbm8830_read_status,
-	.read_ber = atbm8830_read_ber,
-	.read_signal_strength = atbm8830_read_signal_strength,
-	.read_snr = atbm8830_read_snr,
-	.read_ucblocks = atbm8830_read_ucblocks,
-};
-
-struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
-	struct i2c_adapter *i2c)
-{
-	struct atbm_state *priv = NULL;
-	u8 data = 0;
-
-	dprintk("%s()\n", __func__);
-
-	if (config == NULL || i2c == NULL)
-		return NULL;
-
-	priv = kzalloc(sizeof(struct atbm_state), GFP_KERNEL);
-	if (priv == NULL)
-		goto error_out;
-
-	priv->config = config;
-	priv->i2c = i2c;
-
-	/* check if the demod is there */
-	if (atbm8830_read_reg(priv, REG_CHIP_ID, &data) != 0) {
-		dprintk("%s atbm8830/8831 not found at i2c addr 0x%02X\n",
-			__func__, priv->config->demod_address);
-		goto error_out;
-	}
-	dprintk("atbm8830 chip id: 0x%02X\n", data);
-
-	memcpy(&priv->frontend.ops, &atbm8830_ops,
-	       sizeof(struct dvb_frontend_ops));
-	priv->frontend.demodulator_priv = priv;
-
-	atbm8830_init(&priv->frontend);
-
-	atbm8830_i2c_gate_ctrl(&priv->frontend, 1);
-
-	return &priv->frontend;
-
-error_out:
-	dprintk("%s() error_out\n", __func__);
-	kfree(priv);
-	return NULL;
-
-}
-EXPORT_SYMBOL(atbm8830_attach);
-
-MODULE_DESCRIPTION("AltoBeam ATBM8830/8831 GB20600 demodulator driver");
-MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/atbm8830.h b/drivers/media/dvb/frontends/atbm8830.h
deleted file mode 100644
index 0242733..0000000
--- a/drivers/media/dvb/frontends/atbm8830.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- *    Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator
- *    ATBM8830, ATBM8831
- *
- *    Copyright (C) 2009 David T.L. Wong <davidtlwong@gmail.com>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __ATBM8830_H__
-#define __ATBM8830_H__
-
-#include <linux/dvb/frontend.h>
-#include <linux/i2c.h>
-
-#define ATBM8830_PROD_8830 0
-#define ATBM8830_PROD_8831 1
-
-struct atbm8830_config {
-
-	/* product type */
-	u8 prod;
-
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* parallel or serial transport stream */
-	u8 serial_ts;
-
-	/* transport stream clock output only when receiving valid stream */
-	u8 ts_clk_gated;
-
-	/* Decoder sample TS data at rising edge of clock */
-	u8 ts_sampling_edge;
-
-	/* Oscillator clock frequency */
-	u32 osc_clk_freq; /* in kHz */
-
-	/* IF frequency */
-	u32 if_freq; /* in kHz */
-
-	/* Swap I/Q for zero IF */
-	u8 zif_swap_iq;
-
-	/* Tuner AGC settings */
-	u8 agc_min;
-	u8 agc_max;
-	u8 agc_hold_loop;
-};
-
-#if defined(CONFIG_DVB_ATBM8830) || \
-	(defined(CONFIG_DVB_ATBM8830_MODULE) && defined(MODULE))
-extern struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
-		struct i2c_adapter *i2c);
-#else
-static inline
-struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
-		struct i2c_adapter *i2c) {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_ATBM8830 */
-
-#endif /* __ATBM8830_H__ */
diff --git a/drivers/media/dvb/frontends/atbm8830_priv.h b/drivers/media/dvb/frontends/atbm8830_priv.h
deleted file mode 100644
index d460058..0000000
--- a/drivers/media/dvb/frontends/atbm8830_priv.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- *    Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator
- *    ATBM8830, ATBM8831
- *
- *    Copyright (C) 2009 David T.L. Wong <davidtlwong@gmail.com>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __ATBM8830_PRIV_H
-#define __ATBM8830_PRIV_H
-
-struct atbm_state {
-	struct i2c_adapter *i2c;
-	/* configuration settings */
-	const struct atbm8830_config *config;
-	struct dvb_frontend frontend;
-};
-
-#define REG_CHIP_ID	0x0000
-#define REG_TUNER_BASEBAND	0x0001
-#define REG_DEMOD_RUN	0x0004
-#define REG_DSP_RESET	0x0005
-#define REG_RAM_RESET	0x0006
-#define REG_ADC_RESET	0x0007
-#define REG_TSPORT_RESET	0x0008
-#define REG_BLKERR_POL	0x000C
-#define REG_I2C_GATE	0x0103
-#define REG_TS_SAMPLE_EDGE	0x0301
-#define REG_TS_PKT_LEN_204	0x0302
-#define REG_TS_PKT_LEN_AUTO	0x0303
-#define REG_TS_SERIAL	0x0305
-#define REG_TS_CLK_FREERUN	0x0306
-#define REG_TS_VALID_MODE	0x0307
-#define REG_TS_CLK_MODE	0x030B /* 1 for serial, 0 for parallel */
-
-#define REG_TS_ERRBIT_USE	0x030C
-#define REG_LOCK_STATUS	0x030D
-#define REG_ADC_CONFIG	0x0602
-#define REG_CARRIER_OFFSET	0x0827 /* 0x0827-0x0829 little endian */
-#define REG_DETECTED_PN_MODE	0x082D
-#define REG_READ_LATCH	0x084D
-#define REG_IF_FREQ	0x0A00 /* 0x0A00-0x0A02 little endian */
-#define REG_OSC_CLK	0x0A03 /* 0x0A03-0x0A05 little endian */
-#define REG_BYPASS_CCI	0x0A06
-#define REG_ANALOG_LUMA_DETECTED	0x0A25
-#define REG_ANALOG_AUDIO_DETECTED	0x0A26
-#define REG_ANALOG_CHROMA_DETECTED	0x0A39
-#define REG_FRAME_ERR_CNT	0x0B04
-#define REG_USE_EXT_ADC	0x0C00
-#define REG_SWAP_I_Q	0x0C01
-#define REG_TPS_MANUAL	0x0D01
-#define REG_TPS_CONFIG	0x0D02
-#define REG_BYPASS_DEINTERLEAVER	0x0E00
-#define REG_AGC_TARGET	0x1003 /* 0x1003-0x1005 little endian */
-#define REG_AGC_MIN	0x1020
-#define REG_AGC_MAX	0x1023
-#define REG_AGC_LOCK	0x1027
-#define REG_AGC_PWM_VAL	0x1028 /* 0x1028-0x1029 little endian */
-#define REG_AGC_HOLD_LOOP	0x1031
-
-#endif
-
diff --git a/drivers/media/dvb/frontends/au8522.h b/drivers/media/dvb/frontends/au8522.h
deleted file mode 100644
index 565dcf3..0000000
--- a/drivers/media/dvb/frontends/au8522.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
-    Auvitek AU8522 QAM/8VSB demodulator driver
-
-    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef __AU8522_H__
-#define __AU8522_H__
-
-#include <linux/dvb/frontend.h>
-
-enum au8522_if_freq {
-	AU8522_IF_6MHZ = 0,
-	AU8522_IF_4MHZ,
-	AU8522_IF_3_25MHZ,
-};
-
-struct au8522_led_config {
-	u16 vsb8_strong;
-	u16 qam64_strong;
-	u16 qam256_strong;
-
-	u16 gpio_output;
-	/* unset hi bits, set low bits */
-	u16 gpio_output_enable;
-	u16 gpio_output_disable;
-
-	u16 gpio_leds;
-	u8 *led_states;
-	unsigned int num_led_states;
-};
-
-struct au8522_config {
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* Return lock status based on tuner lock, or demod lock */
-#define AU8522_TUNERLOCKING 0
-#define AU8522_DEMODLOCKING 1
-	u8 status_mode;
-
-	struct au8522_led_config *led_cfg;
-
-	enum au8522_if_freq vsb_if;
-	enum au8522_if_freq qam_if;
-};
-
-#if defined(CONFIG_DVB_AU8522) || 				\
-	    (defined(CONFIG_DVB_AU8522_MODULE) && defined(MODULE))
-extern struct dvb_frontend *au8522_attach(const struct au8522_config *config,
-					  struct i2c_adapter *i2c);
-#else
-static inline
-struct dvb_frontend *au8522_attach(const struct au8522_config *config,
-				   struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_AU8522 */
-
-/* Other modes may need to be added later */
-enum au8522_video_input {
-	AU8522_COMPOSITE_CH1 = 1,
-	AU8522_COMPOSITE_CH2,
-	AU8522_COMPOSITE_CH3,
-	AU8522_COMPOSITE_CH4,
-	AU8522_COMPOSITE_CH4_SIF,
-	AU8522_SVIDEO_CH13,
-	AU8522_SVIDEO_CH24,
-};
-
-enum au8522_audio_input {
-	AU8522_AUDIO_NONE,
-	AU8522_AUDIO_SIF,
-};
-
-#endif /* __AU8522_H__ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/dvb/frontends/au8522_common.c b/drivers/media/dvb/frontends/au8522_common.c
deleted file mode 100644
index 5cfe151..0000000
--- a/drivers/media/dvb/frontends/au8522_common.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
-    Auvitek AU8522 QAM/8VSB demodulator driver
-
-    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
-    Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org>
-    Copyright (C) 2005-2008 Auvitek International, Ltd.
-    Copyright (C) 2012 Michael Krufky <mkrufky@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-#include "au8522_priv.h"
-
-MODULE_LICENSE("GPL");
-
-static int debug;
-
-#define dprintk(arg...)\
-  do { if (debug)\
-	 printk(arg);\
-  } while (0)
-
-/* Despite the name "hybrid_tuner", the framework works just as well for
-   hybrid demodulators as well... */
-static LIST_HEAD(hybrid_tuner_instance_list);
-static DEFINE_MUTEX(au8522_list_mutex);
-
-/* 16 bit registers, 8 bit values */
-int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
-{
-	int ret;
-	u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
-
-	struct i2c_msg msg = { .addr = state->config->demod_address,
-			       .flags = 0, .buf = buf, .len = 3 };
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-
-	if (ret != 1)
-		printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
-		       "ret == %i)\n", __func__, reg, data, ret);
-
-	return (ret != 1) ? -1 : 0;
-}
-EXPORT_SYMBOL(au8522_writereg);
-
-u8 au8522_readreg(struct au8522_state *state, u16 reg)
-{
-	int ret;
-	u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff };
-	u8 b1[] = { 0 };
-
-	struct i2c_msg msg[] = {
-		{ .addr = state->config->demod_address, .flags = 0,
-		  .buf = b0, .len = 2 },
-		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
-		  .buf = b1, .len = 1 } };
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2)
-		printk(KERN_ERR "%s: readreg error (ret == %i)\n",
-		       __func__, ret);
-	return b1[0];
-}
-EXPORT_SYMBOL(au8522_readreg);
-
-int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct au8522_state *state = fe->demodulator_priv;
-
-	dprintk("%s(%d)\n", __func__, enable);
-
-	if (state->operational_mode == AU8522_ANALOG_MODE) {
-		/* We're being asked to manage the gate even though we're
-		   not in digital mode.  This can occur if we get switched
-		   over to analog mode before the dvb_frontend kernel thread
-		   has completely shutdown */
-		return 0;
-	}
-
-	if (enable)
-		return au8522_writereg(state, 0x106, 1);
-	else
-		return au8522_writereg(state, 0x106, 0);
-}
-EXPORT_SYMBOL(au8522_i2c_gate_ctrl);
-
-/* Reset the demod hardware and reset all of the configuration registers
-   to a default state. */
-int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
-		     u8 client_address)
-{
-	int ret;
-
-	mutex_lock(&au8522_list_mutex);
-	ret = hybrid_tuner_request_state(struct au8522_state, (*state),
-					 hybrid_tuner_instance_list,
-					 i2c, client_address, "au8522");
-	mutex_unlock(&au8522_list_mutex);
-
-	return ret;
-}
-EXPORT_SYMBOL(au8522_get_state);
-
-void au8522_release_state(struct au8522_state *state)
-{
-	mutex_lock(&au8522_list_mutex);
-	if (state != NULL)
-		hybrid_tuner_release_state(state);
-	mutex_unlock(&au8522_list_mutex);
-}
-EXPORT_SYMBOL(au8522_release_state);
-
-static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
-{
-	struct au8522_led_config *led_config = state->config->led_cfg;
-	u8 val;
-
-	/* bail out if we can't control an LED */
-	if (!led_config || !led_config->gpio_output ||
-	    !led_config->gpio_output_enable || !led_config->gpio_output_disable)
-		return 0;
-
-	val = au8522_readreg(state, 0x4000 |
-			     (led_config->gpio_output & ~0xc000));
-	if (onoff) {
-		/* enable GPIO output */
-		val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
-		val |=  (led_config->gpio_output_enable & 0xff);
-	} else {
-		/* disable GPIO output */
-		val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
-		val |=  (led_config->gpio_output_disable & 0xff);
-	}
-	return au8522_writereg(state, 0x8000 |
-			       (led_config->gpio_output & ~0xc000), val);
-}
-
-/* led = 0 | off
- * led = 1 | signal ok
- * led = 2 | signal strong
- * led < 0 | only light led if leds are currently off
- */
-int au8522_led_ctrl(struct au8522_state *state, int led)
-{
-	struct au8522_led_config *led_config = state->config->led_cfg;
-	int i, ret = 0;
-
-	/* bail out if we can't control an LED */
-	if (!led_config || !led_config->gpio_leds ||
-	    !led_config->num_led_states || !led_config->led_states)
-		return 0;
-
-	if (led < 0) {
-		/* if LED is already lit, then leave it as-is */
-		if (state->led_state)
-			return 0;
-		else
-			led *= -1;
-	}
-
-	/* toggle LED if changing state */
-	if (state->led_state != led) {
-		u8 val;
-
-		dprintk("%s: %d\n", __func__, led);
-
-		au8522_led_gpio_enable(state, 1);
-
-		val = au8522_readreg(state, 0x4000 |
-				     (led_config->gpio_leds & ~0xc000));
-
-		/* start with all leds off */
-		for (i = 0; i < led_config->num_led_states; i++)
-			val &= ~led_config->led_states[i];
-
-		/* set selected LED state */
-		if (led < led_config->num_led_states)
-			val |= led_config->led_states[led];
-		else if (led_config->num_led_states)
-			val |=
-			led_config->led_states[led_config->num_led_states - 1];
-
-		ret = au8522_writereg(state, 0x8000 |
-				      (led_config->gpio_leds & ~0xc000), val);
-		if (ret < 0)
-			return ret;
-
-		state->led_state = led;
-
-		if (led == 0)
-			au8522_led_gpio_enable(state, 0);
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(au8522_led_ctrl);
-
-int au8522_init(struct dvb_frontend *fe)
-{
-	struct au8522_state *state = fe->demodulator_priv;
-	dprintk("%s()\n", __func__);
-
-	state->operational_mode = AU8522_DIGITAL_MODE;
-
-	/* Clear out any state associated with the digital side of the
-	   chip, so that when it gets powered back up it won't think
-	   that it is already tuned */
-	state->current_frequency = 0;
-
-	au8522_writereg(state, 0xa4, 1 << 5);
-
-	au8522_i2c_gate_ctrl(fe, 1);
-
-	return 0;
-}
-EXPORT_SYMBOL(au8522_init);
-
-int au8522_sleep(struct dvb_frontend *fe)
-{
-	struct au8522_state *state = fe->demodulator_priv;
-	dprintk("%s()\n", __func__);
-
-	/* Only power down if the digital side is currently using the chip */
-	if (state->operational_mode == AU8522_ANALOG_MODE) {
-		/* We're not in one of the expected power modes, which means
-		   that the DVB thread is probably telling us to go to sleep
-		   even though the analog frontend has already started using
-		   the chip.  So ignore the request */
-		return 0;
-	}
-
-	/* turn off led */
-	au8522_led_ctrl(state, 0);
-
-	/* Power down the chip */
-	au8522_writereg(state, 0xa4, 1 << 5);
-
-	state->current_frequency = 0;
-
-	return 0;
-}
-EXPORT_SYMBOL(au8522_sleep);
diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c
deleted file mode 100644
index 55b6390..0000000
--- a/drivers/media/dvb/frontends/au8522_decoder.c
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
- * Auvitek AU8522 QAM/8VSB demodulator driver and video decoder
- *
- * Copyright (C) 2009 Devin Heitmueller <dheitmueller@linuxtv.org>
- * Copyright (C) 2005-2008 Auvitek International, Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * As published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-/* Developer notes:
- *
- * VBI support is not yet working
- * Enough is implemented here for CVBS and S-Video inputs, but the actual
- *  analog demodulator code isn't implemented (not needed for xc5000 since it
- *  has its own demodulator and outputs CVBS)
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-device.h>
-#include "au8522.h"
-#include "au8522_priv.h"
-
-MODULE_AUTHOR("Devin Heitmueller");
-MODULE_LICENSE("GPL");
-
-static int au8522_analog_debug;
-
-
-module_param_named(analog_debug, au8522_analog_debug, int, 0644);
-
-MODULE_PARM_DESC(analog_debug,
-		 "Analog debugging messages [0=Off (default) 1=On]");
-
-struct au8522_register_config {
-	u16 reg_name;
-	u8 reg_val[8];
-};
-
-
-/* Video Decoder Filter Coefficients
-   The values are as follows from left to right
-   0="ATV RF" 1="ATV RF13" 2="CVBS" 3="S-Video" 4="PAL" 5=CVBS13" 6="SVideo13"
-*/
-static const struct au8522_register_config filter_coef[] = {
-	{AU8522_FILTER_COEF_R410, {0x25, 0x00, 0x25, 0x25, 0x00, 0x00, 0x00} },
-	{AU8522_FILTER_COEF_R411, {0x20, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00} },
-	{AU8522_FILTER_COEF_R412, {0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00} },
-	{AU8522_FILTER_COEF_R413, {0xe6, 0x00, 0xe6, 0xe6, 0x00, 0x00, 0x00} },
-	{AU8522_FILTER_COEF_R414, {0x40, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00} },
-	{AU8522_FILTER_COEF_R415, {0x1b, 0x00, 0x1b, 0x1b, 0x00, 0x00, 0x00} },
-	{AU8522_FILTER_COEF_R416, {0xc0, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x00} },
-	{AU8522_FILTER_COEF_R417, {0x04, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00} },
-	{AU8522_FILTER_COEF_R418, {0x8c, 0x00, 0x8c, 0x8c, 0x00, 0x00, 0x00} },
-	{AU8522_FILTER_COEF_R419, {0xa0, 0x40, 0xa0, 0xa0, 0x40, 0x40, 0x40} },
-	{AU8522_FILTER_COEF_R41A, {0x21, 0x09, 0x21, 0x21, 0x09, 0x09, 0x09} },
-	{AU8522_FILTER_COEF_R41B, {0x6c, 0x38, 0x6c, 0x6c, 0x38, 0x38, 0x38} },
-	{AU8522_FILTER_COEF_R41C, {0x03, 0xff, 0x03, 0x03, 0xff, 0xff, 0xff} },
-	{AU8522_FILTER_COEF_R41D, {0xbf, 0xc7, 0xbf, 0xbf, 0xc7, 0xc7, 0xc7} },
-	{AU8522_FILTER_COEF_R41E, {0xa0, 0xdf, 0xa0, 0xa0, 0xdf, 0xdf, 0xdf} },
-	{AU8522_FILTER_COEF_R41F, {0x10, 0x06, 0x10, 0x10, 0x06, 0x06, 0x06} },
-	{AU8522_FILTER_COEF_R420, {0xae, 0x30, 0xae, 0xae, 0x30, 0x30, 0x30} },
-	{AU8522_FILTER_COEF_R421, {0xc4, 0x01, 0xc4, 0xc4, 0x01, 0x01, 0x01} },
-	{AU8522_FILTER_COEF_R422, {0x54, 0xdd, 0x54, 0x54, 0xdd, 0xdd, 0xdd} },
-	{AU8522_FILTER_COEF_R423, {0xd0, 0xaf, 0xd0, 0xd0, 0xaf, 0xaf, 0xaf} },
-	{AU8522_FILTER_COEF_R424, {0x1c, 0xf7, 0x1c, 0x1c, 0xf7, 0xf7, 0xf7} },
-	{AU8522_FILTER_COEF_R425, {0x76, 0xdb, 0x76, 0x76, 0xdb, 0xdb, 0xdb} },
-	{AU8522_FILTER_COEF_R426, {0x61, 0xc0, 0x61, 0x61, 0xc0, 0xc0, 0xc0} },
-	{AU8522_FILTER_COEF_R427, {0xd1, 0x2f, 0xd1, 0xd1, 0x2f, 0x2f, 0x2f} },
-	{AU8522_FILTER_COEF_R428, {0x84, 0xd8, 0x84, 0x84, 0xd8, 0xd8, 0xd8} },
-	{AU8522_FILTER_COEF_R429, {0x06, 0xfb, 0x06, 0x06, 0xfb, 0xfb, 0xfb} },
-	{AU8522_FILTER_COEF_R42A, {0x21, 0xd5, 0x21, 0x21, 0xd5, 0xd5, 0xd5} },
-	{AU8522_FILTER_COEF_R42B, {0x0a, 0x3e, 0x0a, 0x0a, 0x3e, 0x3e, 0x3e} },
-	{AU8522_FILTER_COEF_R42C, {0xe6, 0x15, 0xe6, 0xe6, 0x15, 0x15, 0x15} },
-	{AU8522_FILTER_COEF_R42D, {0x01, 0x34, 0x01, 0x01, 0x34, 0x34, 0x34} },
-
-};
-#define NUM_FILTER_COEF (sizeof(filter_coef)\
-			 / sizeof(struct au8522_register_config))
-
-
-/* Registers 0x060b through 0x0652 are the LP Filter coefficients
-   The values are as follows from left to right
-   0="SIF" 1="ATVRF/ATVRF13"
-   Note: the "ATVRF/ATVRF13" mode has never been tested
-*/
-static const struct au8522_register_config lpfilter_coef[] = {
-	{0x060b, {0x21, 0x0b} },
-	{0x060c, {0xad, 0xad} },
-	{0x060d, {0x70, 0xf0} },
-	{0x060e, {0xea, 0xe9} },
-	{0x060f, {0xdd, 0xdd} },
-	{0x0610, {0x08, 0x64} },
-	{0x0611, {0x60, 0x60} },
-	{0x0612, {0xf8, 0xb2} },
-	{0x0613, {0x01, 0x02} },
-	{0x0614, {0xe4, 0xb4} },
-	{0x0615, {0x19, 0x02} },
-	{0x0616, {0xae, 0x2e} },
-	{0x0617, {0xee, 0xc5} },
-	{0x0618, {0x56, 0x56} },
-	{0x0619, {0x30, 0x58} },
-	{0x061a, {0xf9, 0xf8} },
-	{0x061b, {0x24, 0x64} },
-	{0x061c, {0x07, 0x07} },
-	{0x061d, {0x30, 0x30} },
-	{0x061e, {0xa9, 0xed} },
-	{0x061f, {0x09, 0x0b} },
-	{0x0620, {0x42, 0xc2} },
-	{0x0621, {0x1d, 0x2a} },
-	{0x0622, {0xd6, 0x56} },
-	{0x0623, {0x95, 0x8b} },
-	{0x0624, {0x2b, 0x2b} },
-	{0x0625, {0x30, 0x24} },
-	{0x0626, {0x3e, 0x3e} },
-	{0x0627, {0x62, 0xe2} },
-	{0x0628, {0xe9, 0xf5} },
-	{0x0629, {0x99, 0x19} },
-	{0x062a, {0xd4, 0x11} },
-	{0x062b, {0x03, 0x04} },
-	{0x062c, {0xb5, 0x85} },
-	{0x062d, {0x1e, 0x20} },
-	{0x062e, {0x2a, 0xea} },
-	{0x062f, {0xd7, 0xd2} },
-	{0x0630, {0x15, 0x15} },
-	{0x0631, {0xa3, 0xa9} },
-	{0x0632, {0x1f, 0x1f} },
-	{0x0633, {0xf9, 0xd1} },
-	{0x0634, {0xc0, 0xc3} },
-	{0x0635, {0x4d, 0x8d} },
-	{0x0636, {0x21, 0x31} },
-	{0x0637, {0x83, 0x83} },
-	{0x0638, {0x08, 0x8c} },
-	{0x0639, {0x19, 0x19} },
-	{0x063a, {0x45, 0xa5} },
-	{0x063b, {0xef, 0xec} },
-	{0x063c, {0x8a, 0x8a} },
-	{0x063d, {0xf4, 0xf6} },
-	{0x063e, {0x8f, 0x8f} },
-	{0x063f, {0x44, 0x0c} },
-	{0x0640, {0xef, 0xf0} },
-	{0x0641, {0x66, 0x66} },
-	{0x0642, {0xcc, 0xd2} },
-	{0x0643, {0x41, 0x41} },
-	{0x0644, {0x63, 0x93} },
-	{0x0645, {0x8e, 0x8e} },
-	{0x0646, {0xa2, 0x42} },
-	{0x0647, {0x7b, 0x7b} },
-	{0x0648, {0x04, 0x04} },
-	{0x0649, {0x00, 0x00} },
-	{0x064a, {0x40, 0x40} },
-	{0x064b, {0x8c, 0x98} },
-	{0x064c, {0x00, 0x00} },
-	{0x064d, {0x63, 0xc3} },
-	{0x064e, {0x04, 0x04} },
-	{0x064f, {0x20, 0x20} },
-	{0x0650, {0x00, 0x00} },
-	{0x0651, {0x40, 0x40} },
-	{0x0652, {0x01, 0x01} },
-};
-#define NUM_LPFILTER_COEF (sizeof(lpfilter_coef)\
-			   / sizeof(struct au8522_register_config))
-
-static inline struct au8522_state *to_state(struct v4l2_subdev *sd)
-{
-	return container_of(sd, struct au8522_state, sd);
-}
-
-static void setup_vbi(struct au8522_state *state, int aud_input)
-{
-	int i;
-
-	/* These are set to zero regardless of what mode we're in */
-	au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H, 0x00);
-	au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_L_REG018H, 0x00);
-	au8522_writereg(state, AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H, 0x00);
-	au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH, 0x00);
-	au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH, 0x00);
-	au8522_writereg(state, AU8522_TVDEC_VBI_USER_THRESH1_REG01CH, 0x00);
-	au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH, 0x00);
-	au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH, 0x00);
-	au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H, 0x00);
-	au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H,
-			0x00);
-	au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H,
-			0x00);
-	au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H,
-			0x00);
-
-	/* Setup the VBI registers */
-	for (i = 0x30; i < 0x60; i++)
-		au8522_writereg(state, i, 0x40);
-
-	/* For some reason, every register is 0x40 except register 0x44
-	   (confirmed via the HVR-950q USB capture) */
-	au8522_writereg(state, 0x44, 0x60);
-
-	/* Enable VBI (we always do this regardless of whether the user is
-	   viewing closed caption info) */
-	au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H,
-			AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON);
-
-}
-
-static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
-{
-	int i;
-	int filter_coef_type;
-
-	/* Provide reasonable defaults for picture tuning values */
-	au8522_writereg(state, AU8522_TVDEC_SHARPNESSREG009H, 0x07);
-	au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH, 0xed);
-	state->brightness = 0xed - 128;
-	au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH, 0x79);
-	state->contrast = 0x79;
-	au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, 0x80);
-	au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, 0x80);
-	state->saturation = 0x80;
-	au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, 0x00);
-	au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, 0x00);
-	state->hue = 0x00;
-
-	/* Other decoder registers */
-	au8522_writereg(state, AU8522_TVDEC_INT_MASK_REG010H, 0x00);
-
-	if (input_mode == 0x23) {
-		/* S-Video input mapping */
-		au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x04);
-	} else {
-		/* All other modes (CVBS/ATVRF etc.) */
-		au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x00);
-	}
-
-	au8522_writereg(state, AU8522_TVDEC_PGA_REG012H,
-			AU8522_TVDEC_PGA_REG012H_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_COMB_MODE_REG015H,
-			AU8522_TVDEC_COMB_MODE_REG015H_CVBS);
-	au8522_writereg(state, AU8522_TVDED_DBG_MODE_REG060H,
-			AU8522_TVDED_DBG_MODE_REG060H_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H,
-			AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS13);
-	au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H,
-			AU8522_TVDEC_FORMAT_CTRL2_REG062H_CVBS13);
-	au8522_writereg(state, AU8522_TVDEC_VCR_DET_LLIM_REG063H,
-			AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_VCR_DET_HLIM_REG064H,
-			AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR1_REG065H,
-			AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR2_REG066H,
-			AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR3_REG067H,
-			AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_COMB_NOTCH_THR_REG068H,
-			AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR1_REG069H,
-			AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR2_REG06AH,
-			AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR3_REG06BH,
-			AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS);
-	if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 ||
-	    input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) {
-		au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
-				AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO);
-		au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
-				AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO);
-	} else {
-		au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
-				AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS);
-		au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
-				AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS);
-	}
-	au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH,
-			AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_UV_SEP_THR_REG06FH,
-			AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H,
-			AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS);
-	au8522_writereg(state, AU8522_REG071H, AU8522_REG071H_CVBS);
-	au8522_writereg(state, AU8522_REG072H, AU8522_REG072H_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H,
-			AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS);
-	au8522_writereg(state, AU8522_REG074H, AU8522_REG074H_CVBS);
-	au8522_writereg(state, AU8522_REG075H, AU8522_REG075H_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_DCAGC_CTRL_REG077H,
-			AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_PIC_START_ADJ_REG078H,
-			AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H,
-			AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH,
-			AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_INTRP_CTRL_REG07BH,
-			AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H,
-			AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS);
-	au8522_writereg(state, AU8522_TOREGAAGC_REG0E5H,
-			AU8522_TOREGAAGC_REG0E5H_CVBS);
-	au8522_writereg(state, AU8522_REG016H, AU8522_REG016H_CVBS);
-
-	setup_vbi(state, 0);
-
-	if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 ||
-	    input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) {
-		/* Despite what the table says, for the HVR-950q we still need
-		   to be in CVBS mode for the S-Video input (reason unknown). */
-		/* filter_coef_type = 3; */
-		filter_coef_type = 5;
-	} else {
-		filter_coef_type = 5;
-	}
-
-	/* Load the Video Decoder Filter Coefficients */
-	for (i = 0; i < NUM_FILTER_COEF; i++) {
-		au8522_writereg(state, filter_coef[i].reg_name,
-				filter_coef[i].reg_val[filter_coef_type]);
-	}
-
-	/* It's not clear what these registers are for, but they are always
-	   set to the same value regardless of what mode we're in */
-	au8522_writereg(state, AU8522_REG42EH, 0x87);
-	au8522_writereg(state, AU8522_REG42FH, 0xa2);
-	au8522_writereg(state, AU8522_REG430H, 0xbf);
-	au8522_writereg(state, AU8522_REG431H, 0xcb);
-	au8522_writereg(state, AU8522_REG432H, 0xa1);
-	au8522_writereg(state, AU8522_REG433H, 0x41);
-	au8522_writereg(state, AU8522_REG434H, 0x88);
-	au8522_writereg(state, AU8522_REG435H, 0xc2);
-	au8522_writereg(state, AU8522_REG436H, 0x3c);
-}
-
-static void au8522_setup_cvbs_mode(struct au8522_state *state)
-{
-	/* here we're going to try the pre-programmed route */
-	au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
-			AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
-
-	/* PGA in automatic mode */
-	au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
-
-	/* Enable clamping control */
-	au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
-
-	au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
-			AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
-
-	setup_decoder_defaults(state, AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
-
-	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
-			AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
-}
-
-static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state)
-{
-	/* here we're going to try the pre-programmed route */
-	au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
-			AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
-
-	/* It's not clear why we have to have the PGA in automatic mode while
-	   enabling clamp control, but it's what Windows does */
-	au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
-
-	/* Enable clamping control */
-	au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x0e);
-
-	/* Disable automatic PGA (since the CVBS is coming from the tuner) */
-	au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10);
-
-	/* Set input mode to CVBS on channel 4 with SIF audio input enabled */
-	au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
-			AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF);
-
-	setup_decoder_defaults(state,
-			       AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF);
-
-	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
-			AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
-}
-
-static void au8522_setup_svideo_mode(struct au8522_state *state)
-{
-	au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
-			AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO);
-
-	/* Set input to Y on Channe1, C on Channel 3 */
-	au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
-			AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
-
-	/* PGA in automatic mode */
-	au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
-
-	/* Enable clamping control */
-	au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
-
-	setup_decoder_defaults(state,
-			       AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
-
-	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
-			AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static void disable_audio_input(struct au8522_state *state)
-{
-	au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00);
-	au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00);
-	au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00);
-
-	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x04);
-	au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0x02);
-
-	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
-			AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO);
-}
-
-/* 0=disable, 1=SIF */
-static void set_audio_input(struct au8522_state *state, int aud_input)
-{
-	int i;
-
-	/* Note that this function needs to be used in conjunction with setting
-	   the input routing via register 0x81 */
-
-	if (aud_input == AU8522_AUDIO_NONE) {
-		disable_audio_input(state);
-		return;
-	}
-
-	if (aud_input != AU8522_AUDIO_SIF) {
-		/* The caller asked for a mode we don't currently support */
-		printk(KERN_ERR "Unsupported audio mode requested! mode=%d\n",
-		       aud_input);
-		return;
-	}
-
-	/* Load the Audio Decoder Filter Coefficients */
-	for (i = 0; i < NUM_LPFILTER_COEF; i++) {
-		au8522_writereg(state, lpfilter_coef[i].reg_name,
-				lpfilter_coef[i].reg_val[0]);
-	}
-
-	/* Setup audio */
-	au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00);
-	au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00);
-	au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00);
-	au8522_writereg(state, AU8522_I2C_CONTROL_REG1_REG091H, 0x80);
-	au8522_writereg(state, AU8522_I2C_CONTROL_REG0_REG090H, 0x84);
-	msleep(150);
-	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x00);
-	msleep(1);
-	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x9d);
-	msleep(50);
-	au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
-	au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
-	au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0xff);
-	msleep(80);
-	au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
-	au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
-	au8522_writereg(state, AU8522_REG0F9H, AU8522_REG0F9H_AUDIO);
-	au8522_writereg(state, AU8522_AUDIO_MODE_REG0F1H, 0x82);
-	msleep(70);
-	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x09);
-	au8522_writereg(state, AU8522_AUDIOFREQ_REG606H, 0x03);
-	au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0xc2);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int au8522_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-	struct au8522_state *state = to_state(sd);
-
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		state->brightness = ctrl->value;
-		au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH,
-				ctrl->value - 128);
-		break;
-	case V4L2_CID_CONTRAST:
-		state->contrast = ctrl->value;
-		au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH,
-				ctrl->value);
-		break;
-	case V4L2_CID_SATURATION:
-		state->saturation = ctrl->value;
-		au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH,
-				ctrl->value);
-		au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH,
-				ctrl->value);
-		break;
-	case V4L2_CID_HUE:
-		state->hue = ctrl->value;
-		au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH,
-				ctrl->value >> 8);
-		au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH,
-				ctrl->value & 0xFF);
-		break;
-	case V4L2_CID_AUDIO_VOLUME:
-	case V4L2_CID_AUDIO_BASS:
-	case V4L2_CID_AUDIO_TREBLE:
-	case V4L2_CID_AUDIO_BALANCE:
-	case V4L2_CID_AUDIO_MUTE:
-		/* Not yet implemented */
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int au8522_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-	struct au8522_state *state = to_state(sd);
-
-	/* Note that we are using values cached in the state structure instead
-	   of reading the registers due to issues with i2c reads not working
-	   properly/consistently yet on the HVR-950q */
-
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		ctrl->value = state->brightness;
-		break;
-	case V4L2_CID_CONTRAST:
-		ctrl->value = state->contrast;
-		break;
-	case V4L2_CID_SATURATION:
-		ctrl->value = state->saturation;
-		break;
-	case V4L2_CID_HUE:
-		ctrl->value = state->hue;
-		break;
-	case V4L2_CID_AUDIO_VOLUME:
-	case V4L2_CID_AUDIO_BASS:
-	case V4L2_CID_AUDIO_TREBLE:
-	case V4L2_CID_AUDIO_BALANCE:
-	case V4L2_CID_AUDIO_MUTE:
-		/* Not yet supported */
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int au8522_g_register(struct v4l2_subdev *sd,
-			     struct v4l2_dbg_register *reg)
-{
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
-	struct au8522_state *state = to_state(sd);
-
-	if (!v4l2_chip_match_i2c_client(client, &reg->match))
-		return -EINVAL;
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-	reg->val = au8522_readreg(state, reg->reg & 0xffff);
-	return 0;
-}
-
-static int au8522_s_register(struct v4l2_subdev *sd,
-			     struct v4l2_dbg_register *reg)
-{
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
-	struct au8522_state *state = to_state(sd);
-
-	if (!v4l2_chip_match_i2c_client(client, &reg->match))
-		return -EINVAL;
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-	au8522_writereg(state, reg->reg, reg->val & 0xff);
-	return 0;
-}
-#endif
-
-static int au8522_s_stream(struct v4l2_subdev *sd, int enable)
-{
-	struct au8522_state *state = to_state(sd);
-
-	if (enable) {
-		au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
-				0x01);
-		msleep(1);
-		au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
-				AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
-	} else {
-		/* This does not completely power down the device
-		   (it only reduces it from around 140ma to 80ma) */
-		au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
-				1 << 5);
-	}
-	return 0;
-}
-
-static int au8522_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_CONTRAST:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1,
-					    AU8522_TVDEC_CONTRAST_REG00BH_CVBS);
-	case V4L2_CID_BRIGHTNESS:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 109);
-	case V4L2_CID_SATURATION:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
-	case V4L2_CID_HUE:
-		return v4l2_ctrl_query_fill(qc, -32768, 32768, 1, 0);
-	default:
-		break;
-	}
-
-	qc->type = 0;
-	return -EINVAL;
-}
-
-static int au8522_reset(struct v4l2_subdev *sd, u32 val)
-{
-	struct au8522_state *state = to_state(sd);
-
-	state->operational_mode = AU8522_ANALOG_MODE;
-
-	/* Clear out any state associated with the digital side of the
-	   chip, so that when it gets powered back up it won't think
-	   that it is already tuned */
-	state->current_frequency = 0;
-
-	au8522_writereg(state, 0xa4, 1 << 5);
-
-	return 0;
-}
-
-static int au8522_s_video_routing(struct v4l2_subdev *sd,
-					u32 input, u32 output, u32 config)
-{
-	struct au8522_state *state = to_state(sd);
-
-	au8522_reset(sd, 0);
-
-	/* Jam open the i2c gate to the tuner.  We do this here to handle the
-	   case where the user went into digital mode (causing the gate to be
-	   closed), and then came back to analog mode */
-	au8522_writereg(state, 0x106, 1);
-
-	if (input == AU8522_COMPOSITE_CH1) {
-		au8522_setup_cvbs_mode(state);
-	} else if (input == AU8522_SVIDEO_CH13) {
-		au8522_setup_svideo_mode(state);
-	} else if (input == AU8522_COMPOSITE_CH4_SIF) {
-		au8522_setup_cvbs_tuner_mode(state);
-	} else {
-		printk(KERN_ERR "au8522 mode not currently supported\n");
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int au8522_s_audio_routing(struct v4l2_subdev *sd,
-					u32 input, u32 output, u32 config)
-{
-	struct au8522_state *state = to_state(sd);
-	set_audio_input(state, input);
-	return 0;
-}
-
-static int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
-{
-	int val = 0;
-	struct au8522_state *state = to_state(sd);
-	u8 lock_status;
-
-	/* Interrogate the decoder to see if we are getting a real signal */
-	lock_status = au8522_readreg(state, 0x00);
-	if (lock_status == 0xa2)
-		vt->signal = 0xffff;
-	else
-		vt->signal = 0x00;
-
-	vt->capability |=
-		V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
-		V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
-
-	val = V4L2_TUNER_SUB_MONO;
-	vt->rxsubchans = val;
-	vt->audmode = V4L2_TUNER_MODE_STEREO;
-	return 0;
-}
-
-static int au8522_g_chip_ident(struct v4l2_subdev *sd,
-			       struct v4l2_dbg_chip_ident *chip)
-{
-	struct au8522_state *state = to_state(sd);
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-	return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev);
-}
-
-static int au8522_log_status(struct v4l2_subdev *sd)
-{
-	/* FIXME: Add some status info here */
-	return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const struct v4l2_subdev_core_ops au8522_core_ops = {
-	.log_status = au8522_log_status,
-	.g_chip_ident = au8522_g_chip_ident,
-	.g_ctrl = au8522_g_ctrl,
-	.s_ctrl = au8522_s_ctrl,
-	.queryctrl = au8522_queryctrl,
-	.reset = au8522_reset,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	.g_register = au8522_g_register,
-	.s_register = au8522_s_register,
-#endif
-};
-
-static const struct v4l2_subdev_tuner_ops au8522_tuner_ops = {
-	.g_tuner = au8522_g_tuner,
-};
-
-static const struct v4l2_subdev_audio_ops au8522_audio_ops = {
-	.s_routing = au8522_s_audio_routing,
-};
-
-static const struct v4l2_subdev_video_ops au8522_video_ops = {
-	.s_routing = au8522_s_video_routing,
-	.s_stream = au8522_s_stream,
-};
-
-static const struct v4l2_subdev_ops au8522_ops = {
-	.core = &au8522_core_ops,
-	.tuner = &au8522_tuner_ops,
-	.audio = &au8522_audio_ops,
-	.video = &au8522_video_ops,
-};
-
-/* ----------------------------------------------------------------------- */
-
-static int au8522_probe(struct i2c_client *client,
-			const struct i2c_device_id *did)
-{
-	struct au8522_state *state;
-	struct v4l2_subdev *sd;
-	int instance;
-	struct au8522_config *demod_config;
-
-	/* Check if the adapter supports the needed features */
-	if (!i2c_check_functionality(client->adapter,
-				     I2C_FUNC_SMBUS_BYTE_DATA)) {
-		return -EIO;
-	}
-
-	/* allocate memory for the internal state */
-	instance = au8522_get_state(&state, client->adapter, client->addr);
-	switch (instance) {
-	case 0:
-		printk(KERN_ERR "au8522_decoder allocation failed\n");
-		return -EIO;
-	case 1:
-		/* new demod instance */
-		printk(KERN_INFO "au8522_decoder creating new instance...\n");
-		break;
-	default:
-		/* existing demod instance */
-		printk(KERN_INFO "au8522_decoder attach existing instance.\n");
-		break;
-	}
-
-	demod_config = kzalloc(sizeof(struct au8522_config), GFP_KERNEL);
-	if (demod_config == NULL) {
-		if (instance == 1)
-			kfree(state);
-		return -ENOMEM;
-	}
-	demod_config->demod_address = 0x8e >> 1;
-
-	state->config = demod_config;
-	state->i2c = client->adapter;
-
-	sd = &state->sd;
-	v4l2_i2c_subdev_init(sd, client, &au8522_ops);
-
-	state->c = client;
-	state->vid_input = AU8522_COMPOSITE_CH1;
-	state->aud_input = AU8522_AUDIO_NONE;
-	state->id = 8522;
-	state->rev = 0;
-
-	/* Jam open the i2c gate to the tuner */
-	au8522_writereg(state, 0x106, 1);
-
-	return 0;
-}
-
-static int au8522_remove(struct i2c_client *client)
-{
-	struct v4l2_subdev *sd = i2c_get_clientdata(client);
-	v4l2_device_unregister_subdev(sd);
-	au8522_release_state(to_state(sd));
-	return 0;
-}
-
-static const struct i2c_device_id au8522_id[] = {
-	{"au8522", 0},
-	{}
-};
-
-MODULE_DEVICE_TABLE(i2c, au8522_id);
-
-static struct i2c_driver au8522_driver = {
-	.driver = {
-		.owner	= THIS_MODULE,
-		.name	= "au8522",
-	},
-	.probe		= au8522_probe,
-	.remove		= au8522_remove,
-	.id_table	= au8522_id,
-};
-
-module_i2c_driver(au8522_driver);
diff --git a/drivers/media/dvb/frontends/au8522_dig.c b/drivers/media/dvb/frontends/au8522_dig.c
deleted file mode 100644
index 5fc70d6..0000000
--- a/drivers/media/dvb/frontends/au8522_dig.c
+++ /dev/null
@@ -1,826 +0,0 @@
-/*
-    Auvitek AU8522 QAM/8VSB demodulator driver
-
-    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include "dvb_frontend.h"
-#include "au8522.h"
-#include "au8522_priv.h"
-
-static int debug;
-
-#define dprintk(arg...)\
-	do { if (debug)\
-		printk(arg);\
-	} while (0)
-
-struct mse2snr_tab {
-	u16 val;
-	u16 data;
-};
-
-/* VSB SNR lookup table */
-static struct mse2snr_tab vsb_mse2snr_tab[] = {
-	{   0, 270 },
-	{   2, 250 },
-	{   3, 240 },
-	{   5, 230 },
-	{   7, 220 },
-	{   9, 210 },
-	{  12, 200 },
-	{  13, 195 },
-	{  15, 190 },
-	{  17, 185 },
-	{  19, 180 },
-	{  21, 175 },
-	{  24, 170 },
-	{  27, 165 },
-	{  31, 160 },
-	{  32, 158 },
-	{  33, 156 },
-	{  36, 152 },
-	{  37, 150 },
-	{  39, 148 },
-	{  40, 146 },
-	{  41, 144 },
-	{  43, 142 },
-	{  44, 140 },
-	{  48, 135 },
-	{  50, 130 },
-	{  43, 142 },
-	{  53, 125 },
-	{  56, 120 },
-	{ 256, 115 },
-};
-
-/* QAM64 SNR lookup table */
-static struct mse2snr_tab qam64_mse2snr_tab[] = {
-	{  15,   0 },
-	{  16, 290 },
-	{  17, 288 },
-	{  18, 286 },
-	{  19, 284 },
-	{  20, 282 },
-	{  21, 281 },
-	{  22, 279 },
-	{  23, 277 },
-	{  24, 275 },
-	{  25, 273 },
-	{  26, 271 },
-	{  27, 269 },
-	{  28, 268 },
-	{  29, 266 },
-	{  30, 264 },
-	{  31, 262 },
-	{  32, 260 },
-	{  33, 259 },
-	{  34, 258 },
-	{  35, 256 },
-	{  36, 255 },
-	{  37, 254 },
-	{  38, 252 },
-	{  39, 251 },
-	{  40, 250 },
-	{  41, 249 },
-	{  42, 248 },
-	{  43, 246 },
-	{  44, 245 },
-	{  45, 244 },
-	{  46, 242 },
-	{  47, 241 },
-	{  48, 240 },
-	{  50, 239 },
-	{  51, 238 },
-	{  53, 237 },
-	{  54, 236 },
-	{  56, 235 },
-	{  57, 234 },
-	{  59, 233 },
-	{  60, 232 },
-	{  62, 231 },
-	{  63, 230 },
-	{  65, 229 },
-	{  67, 228 },
-	{  68, 227 },
-	{  70, 226 },
-	{  71, 225 },
-	{  73, 224 },
-	{  74, 223 },
-	{  76, 222 },
-	{  78, 221 },
-	{  80, 220 },
-	{  82, 219 },
-	{  85, 218 },
-	{  88, 217 },
-	{  90, 216 },
-	{  92, 215 },
-	{  93, 214 },
-	{  94, 212 },
-	{  95, 211 },
-	{  97, 210 },
-	{  99, 209 },
-	{ 101, 208 },
-	{ 102, 207 },
-	{ 104, 206 },
-	{ 107, 205 },
-	{ 111, 204 },
-	{ 114, 203 },
-	{ 118, 202 },
-	{ 122, 201 },
-	{ 125, 200 },
-	{ 128, 199 },
-	{ 130, 198 },
-	{ 132, 197 },
-	{ 256, 190 },
-};
-
-/* QAM256 SNR lookup table */
-static struct mse2snr_tab qam256_mse2snr_tab[] = {
-	{  16,   0 },
-	{  17, 400 },
-	{  18, 398 },
-	{  19, 396 },
-	{  20, 394 },
-	{  21, 392 },
-	{  22, 390 },
-	{  23, 388 },
-	{  24, 386 },
-	{  25, 384 },
-	{  26, 382 },
-	{  27, 380 },
-	{  28, 379 },
-	{  29, 378 },
-	{  30, 377 },
-	{  31, 376 },
-	{  32, 375 },
-	{  33, 374 },
-	{  34, 373 },
-	{  35, 372 },
-	{  36, 371 },
-	{  37, 370 },
-	{  38, 362 },
-	{  39, 354 },
-	{  40, 346 },
-	{  41, 338 },
-	{  42, 330 },
-	{  43, 328 },
-	{  44, 326 },
-	{  45, 324 },
-	{  46, 322 },
-	{  47, 320 },
-	{  48, 319 },
-	{  49, 318 },
-	{  50, 317 },
-	{  51, 316 },
-	{  52, 315 },
-	{  53, 314 },
-	{  54, 313 },
-	{  55, 312 },
-	{  56, 311 },
-	{  57, 310 },
-	{  58, 308 },
-	{  59, 306 },
-	{  60, 304 },
-	{  61, 302 },
-	{  62, 300 },
-	{  63, 298 },
-	{  65, 295 },
-	{  68, 294 },
-	{  70, 293 },
-	{  73, 292 },
-	{  76, 291 },
-	{  78, 290 },
-	{  79, 289 },
-	{  81, 288 },
-	{  82, 287 },
-	{  83, 286 },
-	{  84, 285 },
-	{  85, 284 },
-	{  86, 283 },
-	{  88, 282 },
-	{  89, 281 },
-	{ 256, 280 },
-};
-
-static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
-				 u16 *snr)
-{
-	int i, ret = -EINVAL;
-	dprintk("%s()\n", __func__);
-
-	for (i = 0; i < sz; i++) {
-		if (mse < tab[i].val) {
-			*snr = tab[i].data;
-			ret = 0;
-			break;
-		}
-	}
-	dprintk("%s() snr=%d\n", __func__, *snr);
-	return ret;
-}
-
-static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq)
-{
-	struct au8522_state *state = fe->demodulator_priv;
-	u8 r0b5, r0b6, r0b7;
-	char *ifmhz;
-
-	switch (if_freq) {
-	case AU8522_IF_3_25MHZ:
-		ifmhz = "3.25";
-		r0b5 = 0x00;
-		r0b6 = 0x3d;
-		r0b7 = 0xa0;
-		break;
-	case AU8522_IF_4MHZ:
-		ifmhz = "4.00";
-		r0b5 = 0x00;
-		r0b6 = 0x4b;
-		r0b7 = 0xd9;
-		break;
-	case AU8522_IF_6MHZ:
-		ifmhz = "6.00";
-		r0b5 = 0xfb;
-		r0b6 = 0x8e;
-		r0b7 = 0x39;
-		break;
-	default:
-		dprintk("%s() IF Frequency not supported\n", __func__);
-		return -EINVAL;
-	}
-	dprintk("%s() %s MHz\n", __func__, ifmhz);
-	au8522_writereg(state, 0x80b5, r0b5);
-	au8522_writereg(state, 0x80b6, r0b6);
-	au8522_writereg(state, 0x80b7, r0b7);
-
-	return 0;
-}
-
-/* VSB Modulation table */
-static struct {
-	u16 reg;
-	u16 data;
-} VSB_mod_tab[] = {
-	{ 0x8090, 0x84 },
-	{ 0x4092, 0x11 },
-	{ 0x2005, 0x00 },
-	{ 0x8091, 0x80 },
-	{ 0x80a3, 0x0c },
-	{ 0x80a4, 0xe8 },
-	{ 0x8081, 0xc4 },
-	{ 0x80a5, 0x40 },
-	{ 0x80a7, 0x40 },
-	{ 0x80a6, 0x67 },
-	{ 0x8262, 0x20 },
-	{ 0x821c, 0x30 },
-	{ 0x80d8, 0x1a },
-	{ 0x8227, 0xa0 },
-	{ 0x8121, 0xff },
-	{ 0x80a8, 0xf0 },
-	{ 0x80a9, 0x05 },
-	{ 0x80aa, 0x77 },
-	{ 0x80ab, 0xf0 },
-	{ 0x80ac, 0x05 },
-	{ 0x80ad, 0x77 },
-	{ 0x80ae, 0x41 },
-	{ 0x80af, 0x66 },
-	{ 0x821b, 0xcc },
-	{ 0x821d, 0x80 },
-	{ 0x80a4, 0xe8 },
-	{ 0x8231, 0x13 },
-};
-
-/* QAM64 Modulation table */
-static struct {
-	u16 reg;
-	u16 data;
-} QAM64_mod_tab[] = {
-	{ 0x00a3, 0x09 },
-	{ 0x00a4, 0x00 },
-	{ 0x0081, 0xc4 },
-	{ 0x00a5, 0x40 },
-	{ 0x00aa, 0x77 },
-	{ 0x00ad, 0x77 },
-	{ 0x00a6, 0x67 },
-	{ 0x0262, 0x20 },
-	{ 0x021c, 0x30 },
-	{ 0x00b8, 0x3e },
-	{ 0x00b9, 0xf0 },
-	{ 0x00ba, 0x01 },
-	{ 0x00bb, 0x18 },
-	{ 0x00bc, 0x50 },
-	{ 0x00bd, 0x00 },
-	{ 0x00be, 0xea },
-	{ 0x00bf, 0xef },
-	{ 0x00c0, 0xfc },
-	{ 0x00c1, 0xbd },
-	{ 0x00c2, 0x1f },
-	{ 0x00c3, 0xfc },
-	{ 0x00c4, 0xdd },
-	{ 0x00c5, 0xaf },
-	{ 0x00c6, 0x00 },
-	{ 0x00c7, 0x38 },
-	{ 0x00c8, 0x30 },
-	{ 0x00c9, 0x05 },
-	{ 0x00ca, 0x4a },
-	{ 0x00cb, 0xd0 },
-	{ 0x00cc, 0x01 },
-	{ 0x00cd, 0xd9 },
-	{ 0x00ce, 0x6f },
-	{ 0x00cf, 0xf9 },
-	{ 0x00d0, 0x70 },
-	{ 0x00d1, 0xdf },
-	{ 0x00d2, 0xf7 },
-	{ 0x00d3, 0xc2 },
-	{ 0x00d4, 0xdf },
-	{ 0x00d5, 0x02 },
-	{ 0x00d6, 0x9a },
-	{ 0x00d7, 0xd0 },
-	{ 0x0250, 0x0d },
-	{ 0x0251, 0xcd },
-	{ 0x0252, 0xe0 },
-	{ 0x0253, 0x05 },
-	{ 0x0254, 0xa7 },
-	{ 0x0255, 0xff },
-	{ 0x0256, 0xed },
-	{ 0x0257, 0x5b },
-	{ 0x0258, 0xae },
-	{ 0x0259, 0xe6 },
-	{ 0x025a, 0x3d },
-	{ 0x025b, 0x0f },
-	{ 0x025c, 0x0d },
-	{ 0x025d, 0xea },
-	{ 0x025e, 0xf2 },
-	{ 0x025f, 0x51 },
-	{ 0x0260, 0xf5 },
-	{ 0x0261, 0x06 },
-	{ 0x021a, 0x00 },
-	{ 0x0546, 0x40 },
-	{ 0x0210, 0xc7 },
-	{ 0x0211, 0xaa },
-	{ 0x0212, 0xab },
-	{ 0x0213, 0x02 },
-	{ 0x0502, 0x00 },
-	{ 0x0121, 0x04 },
-	{ 0x0122, 0x04 },
-	{ 0x052e, 0x10 },
-	{ 0x00a4, 0xca },
-	{ 0x00a7, 0x40 },
-	{ 0x0526, 0x01 },
-};
-
-/* QAM256 Modulation table */
-static struct {
-	u16 reg;
-	u16 data;
-} QAM256_mod_tab[] = {
-	{ 0x80a3, 0x09 },
-	{ 0x80a4, 0x00 },
-	{ 0x8081, 0xc4 },
-	{ 0x80a5, 0x40 },
-	{ 0x80aa, 0x77 },
-	{ 0x80ad, 0x77 },
-	{ 0x80a6, 0x67 },
-	{ 0x8262, 0x20 },
-	{ 0x821c, 0x30 },
-	{ 0x80b8, 0x3e },
-	{ 0x80b9, 0xf0 },
-	{ 0x80ba, 0x01 },
-	{ 0x80bb, 0x18 },
-	{ 0x80bc, 0x50 },
-	{ 0x80bd, 0x00 },
-	{ 0x80be, 0xea },
-	{ 0x80bf, 0xef },
-	{ 0x80c0, 0xfc },
-	{ 0x80c1, 0xbd },
-	{ 0x80c2, 0x1f },
-	{ 0x80c3, 0xfc },
-	{ 0x80c4, 0xdd },
-	{ 0x80c5, 0xaf },
-	{ 0x80c6, 0x00 },
-	{ 0x80c7, 0x38 },
-	{ 0x80c8, 0x30 },
-	{ 0x80c9, 0x05 },
-	{ 0x80ca, 0x4a },
-	{ 0x80cb, 0xd0 },
-	{ 0x80cc, 0x01 },
-	{ 0x80cd, 0xd9 },
-	{ 0x80ce, 0x6f },
-	{ 0x80cf, 0xf9 },
-	{ 0x80d0, 0x70 },
-	{ 0x80d1, 0xdf },
-	{ 0x80d2, 0xf7 },
-	{ 0x80d3, 0xc2 },
-	{ 0x80d4, 0xdf },
-	{ 0x80d5, 0x02 },
-	{ 0x80d6, 0x9a },
-	{ 0x80d7, 0xd0 },
-	{ 0x8250, 0x0d },
-	{ 0x8251, 0xcd },
-	{ 0x8252, 0xe0 },
-	{ 0x8253, 0x05 },
-	{ 0x8254, 0xa7 },
-	{ 0x8255, 0xff },
-	{ 0x8256, 0xed },
-	{ 0x8257, 0x5b },
-	{ 0x8258, 0xae },
-	{ 0x8259, 0xe6 },
-	{ 0x825a, 0x3d },
-	{ 0x825b, 0x0f },
-	{ 0x825c, 0x0d },
-	{ 0x825d, 0xea },
-	{ 0x825e, 0xf2 },
-	{ 0x825f, 0x51 },
-	{ 0x8260, 0xf5 },
-	{ 0x8261, 0x06 },
-	{ 0x821a, 0x00 },
-	{ 0x8546, 0x40 },
-	{ 0x8210, 0x26 },
-	{ 0x8211, 0xf6 },
-	{ 0x8212, 0x84 },
-	{ 0x8213, 0x02 },
-	{ 0x8502, 0x01 },
-	{ 0x8121, 0x04 },
-	{ 0x8122, 0x04 },
-	{ 0x852e, 0x10 },
-	{ 0x80a4, 0xca },
-	{ 0x80a7, 0x40 },
-	{ 0x8526, 0x01 },
-};
-
-static int au8522_enable_modulation(struct dvb_frontend *fe,
-				    fe_modulation_t m)
-{
-	struct au8522_state *state = fe->demodulator_priv;
-	int i;
-
-	dprintk("%s(0x%08x)\n", __func__, m);
-
-	switch (m) {
-	case VSB_8:
-		dprintk("%s() VSB_8\n", __func__);
-		for (i = 0; i < ARRAY_SIZE(VSB_mod_tab); i++)
-			au8522_writereg(state,
-				VSB_mod_tab[i].reg,
-				VSB_mod_tab[i].data);
-		au8522_set_if(fe, state->config->vsb_if);
-		break;
-	case QAM_64:
-		dprintk("%s() QAM 64\n", __func__);
-		for (i = 0; i < ARRAY_SIZE(QAM64_mod_tab); i++)
-			au8522_writereg(state,
-				QAM64_mod_tab[i].reg,
-				QAM64_mod_tab[i].data);
-		au8522_set_if(fe, state->config->qam_if);
-		break;
-	case QAM_256:
-		dprintk("%s() QAM 256\n", __func__);
-		for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++)
-			au8522_writereg(state,
-				QAM256_mod_tab[i].reg,
-				QAM256_mod_tab[i].data);
-		au8522_set_if(fe, state->config->qam_if);
-		break;
-	default:
-		dprintk("%s() Invalid modulation\n", __func__);
-		return -EINVAL;
-	}
-
-	state->current_modulation = m;
-
-	return 0;
-}
-
-/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int au8522_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct au8522_state *state = fe->demodulator_priv;
-	int ret = -EINVAL;
-
-	dprintk("%s(frequency=%d)\n", __func__, c->frequency);
-
-	if ((state->current_frequency == c->frequency) &&
-	    (state->current_modulation == c->modulation))
-		return 0;
-
-	if (fe->ops.tuner_ops.set_params) {
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-		ret = fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	if (ret < 0)
-		return ret;
-
-	/* Allow the tuner to settle */
-	msleep(100);
-
-	au8522_enable_modulation(fe, c->modulation);
-
-	state->current_frequency = c->frequency;
-
-	return 0;
-}
-
-static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct au8522_state *state = fe->demodulator_priv;
-	u8 reg;
-	u32 tuner_status = 0;
-
-	*status = 0;
-
-	if (state->current_modulation == VSB_8) {
-		dprintk("%s() Checking VSB_8\n", __func__);
-		reg = au8522_readreg(state, 0x4088);
-		if ((reg & 0x03) == 0x03)
-			*status |= FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
-	} else {
-		dprintk("%s() Checking QAM\n", __func__);
-		reg = au8522_readreg(state, 0x4541);
-		if (reg & 0x80)
-			*status |= FE_HAS_VITERBI;
-		if (reg & 0x20)
-			*status |= FE_HAS_LOCK | FE_HAS_SYNC;
-	}
-
-	switch (state->config->status_mode) {
-	case AU8522_DEMODLOCKING:
-		dprintk("%s() DEMODLOCKING\n", __func__);
-		if (*status & FE_HAS_VITERBI)
-			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
-		break;
-	case AU8522_TUNERLOCKING:
-		/* Get the tuner status */
-		dprintk("%s() TUNERLOCKING\n", __func__);
-		if (fe->ops.tuner_ops.get_status) {
-			if (fe->ops.i2c_gate_ctrl)
-				fe->ops.i2c_gate_ctrl(fe, 1);
-
-			fe->ops.tuner_ops.get_status(fe, &tuner_status);
-
-			if (fe->ops.i2c_gate_ctrl)
-				fe->ops.i2c_gate_ctrl(fe, 0);
-		}
-		if (tuner_status)
-			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
-		break;
-	}
-	state->fe_status = *status;
-
-	if (*status & FE_HAS_LOCK)
-		/* turn on LED, if it isn't on already */
-		au8522_led_ctrl(state, -1);
-	else
-		/* turn off LED */
-		au8522_led_ctrl(state, 0);
-
-	dprintk("%s() status 0x%08x\n", __func__, *status);
-
-	return 0;
-}
-
-static int au8522_led_status(struct au8522_state *state, const u16 *snr)
-{
-	struct au8522_led_config *led_config = state->config->led_cfg;
-	int led;
-	u16 strong;
-
-	/* bail out if we can't control an LED */
-	if (!led_config)
-		return 0;
-
-	if (0 == (state->fe_status & FE_HAS_LOCK))
-		return au8522_led_ctrl(state, 0);
-	else if (state->current_modulation == QAM_256)
-		strong = led_config->qam256_strong;
-	else if (state->current_modulation == QAM_64)
-		strong = led_config->qam64_strong;
-	else /* (state->current_modulation == VSB_8) */
-		strong = led_config->vsb8_strong;
-
-	if (*snr >= strong)
-		led = 2;
-	else
-		led = 1;
-
-	if ((state->led_state) &&
-	    (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10))
-		/* snr didn't change enough to bother
-		 * changing the color of the led */
-		return 0;
-
-	return au8522_led_ctrl(state, led);
-}
-
-static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct au8522_state *state = fe->demodulator_priv;
-	int ret = -EINVAL;
-
-	dprintk("%s()\n", __func__);
-
-	if (state->current_modulation == QAM_256)
-		ret = au8522_mse2snr_lookup(qam256_mse2snr_tab,
-					    ARRAY_SIZE(qam256_mse2snr_tab),
-					    au8522_readreg(state, 0x4522),
-					    snr);
-	else if (state->current_modulation == QAM_64)
-		ret = au8522_mse2snr_lookup(qam64_mse2snr_tab,
-					    ARRAY_SIZE(qam64_mse2snr_tab),
-					    au8522_readreg(state, 0x4522),
-					    snr);
-	else /* VSB_8 */
-		ret = au8522_mse2snr_lookup(vsb_mse2snr_tab,
-					    ARRAY_SIZE(vsb_mse2snr_tab),
-					    au8522_readreg(state, 0x4311),
-					    snr);
-
-	if (state->config->led_cfg)
-		au8522_led_status(state, snr);
-
-	return ret;
-}
-
-static int au8522_read_signal_strength(struct dvb_frontend *fe,
-				       u16 *signal_strength)
-{
-	/* borrowed from lgdt330x.c
-	 *
-	 * Calculate strength from SNR up to 35dB
-	 * Even though the SNR can go higher than 35dB,
-	 * there is some comfort factor in having a range of
-	 * strong signals that can show at 100%
-	 */
-	u16 snr;
-	u32 tmp;
-	int ret = au8522_read_snr(fe, &snr);
-
-	*signal_strength = 0;
-
-	if (0 == ret) {
-		/* The following calculation method was chosen
-		 * purely for the sake of code re-use from the
-		 * other demod drivers that use this method */
-
-		/* Convert from SNR in dB * 10 to 8.24 fixed-point */
-		tmp = (snr * ((1 << 24) / 10));
-
-		/* Convert from 8.24 fixed-point to
-		 * scale the range 0 - 35*2^24 into 0 - 65535*/
-		if (tmp >= 8960 * 0x10000)
-			*signal_strength = 0xffff;
-		else
-			*signal_strength = tmp / 8960;
-	}
-
-	return ret;
-}
-
-static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct au8522_state *state = fe->demodulator_priv;
-
-	if (state->current_modulation == VSB_8)
-		*ucblocks = au8522_readreg(state, 0x4087);
-	else
-		*ucblocks = au8522_readreg(state, 0x4543);
-
-	return 0;
-}
-
-static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	return au8522_read_ucblocks(fe, ber);
-}
-
-static int au8522_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct au8522_state *state = fe->demodulator_priv;
-
-	c->frequency = state->current_frequency;
-	c->modulation = state->current_modulation;
-
-	return 0;
-}
-
-static int au8522_get_tune_settings(struct dvb_frontend *fe,
-				    struct dvb_frontend_tune_settings *tune)
-{
-	tune->min_delay_ms = 1000;
-	return 0;
-}
-
-static struct dvb_frontend_ops au8522_ops;
-
-
-static void au8522_release(struct dvb_frontend *fe)
-{
-	struct au8522_state *state = fe->demodulator_priv;
-	au8522_release_state(state);
-}
-
-struct dvb_frontend *au8522_attach(const struct au8522_config *config,
-				   struct i2c_adapter *i2c)
-{
-	struct au8522_state *state = NULL;
-	int instance;
-
-	/* allocate memory for the internal state */
-	instance = au8522_get_state(&state, i2c, config->demod_address);
-	switch (instance) {
-	case 0:
-		dprintk("%s state allocation failed\n", __func__);
-		break;
-	case 1:
-		/* new demod instance */
-		dprintk("%s using new instance\n", __func__);
-		break;
-	default:
-		/* existing demod instance */
-		dprintk("%s using existing instance\n", __func__);
-		break;
-	}
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->operational_mode = AU8522_DIGITAL_MODE;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &au8522_ops,
-	       sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-
-	if (au8522_init(&state->frontend) != 0) {
-		printk(KERN_ERR "%s: Failed to initialize correctly\n",
-			__func__);
-		goto error;
-	}
-
-	/* Note: Leaving the I2C gate open here. */
-	au8522_i2c_gate_ctrl(&state->frontend, 1);
-
-	return &state->frontend;
-
-error:
-	au8522_release_state(state);
-	return NULL;
-}
-EXPORT_SYMBOL(au8522_attach);
-
-static struct dvb_frontend_ops au8522_ops = {
-	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
-	.info = {
-		.name			= "Auvitek AU8522 QAM/8VSB Frontend",
-		.frequency_min		= 54000000,
-		.frequency_max		= 858000000,
-		.frequency_stepsize	= 62500,
-		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
-	},
-
-	.init                 = au8522_init,
-	.sleep                = au8522_sleep,
-	.i2c_gate_ctrl        = au8522_i2c_gate_ctrl,
-	.set_frontend         = au8522_set_frontend,
-	.get_frontend         = au8522_get_frontend,
-	.get_tune_settings    = au8522_get_tune_settings,
-	.read_status          = au8522_read_status,
-	.read_ber             = au8522_read_ber,
-	.read_signal_strength = au8522_read_signal_strength,
-	.read_snr             = au8522_read_snr,
-	.read_ucblocks        = au8522_read_ucblocks,
-	.release              = au8522_release,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Enable verbose debug messages");
-
-MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
-MODULE_AUTHOR("Steven Toth");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/au8522_priv.h b/drivers/media/dvb/frontends/au8522_priv.h
deleted file mode 100644
index 6e4a438..0000000
--- a/drivers/media/dvb/frontends/au8522_priv.h
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
-    Auvitek AU8522 QAM/8VSB demodulator driver
-
-    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
-    Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org>
-    Copyright (C) 2005-2008 Auvitek International, Ltd.
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-device.h>
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-#include "au8522.h"
-#include "tuner-i2c.h"
-
-#define AU8522_ANALOG_MODE 0
-#define AU8522_DIGITAL_MODE 1
-
-struct au8522_state {
-	struct i2c_client *c;
-	struct i2c_adapter *i2c;
-
-	u8 operational_mode;
-
-	/* Used for sharing of the state between analog and digital mode */
-	struct tuner_i2c_props i2c_props;
-	struct list_head hybrid_tuner_instance_list;
-
-	/* configuration settings */
-	const struct au8522_config *config;
-
-	struct dvb_frontend frontend;
-
-	u32 current_frequency;
-	fe_modulation_t current_modulation;
-
-	u32 fe_status;
-	unsigned int led_state;
-
-	/* Analog settings */
-	struct v4l2_subdev sd;
-	v4l2_std_id std;
-	int vid_input;
-	int aud_input;
-	u32 id;
-	u32 rev;
-	u8 brightness;
-	u8 contrast;
-	u8 saturation;
-	s16 hue;
-};
-
-/* These are routines shared by both the VSB/QAM demodulator and the analog
-   decoder */
-int au8522_writereg(struct au8522_state *state, u16 reg, u8 data);
-u8 au8522_readreg(struct au8522_state *state, u16 reg);
-int au8522_init(struct dvb_frontend *fe);
-int au8522_sleep(struct dvb_frontend *fe);
-
-int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
-		     u8 client_address);
-void au8522_release_state(struct au8522_state *state);
-int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
-int au8522_led_ctrl(struct au8522_state *state, int led);
-
-/* REGISTERS */
-#define AU8522_INPUT_CONTROL_REG081H			0x081
-#define AU8522_PGA_CONTROL_REG082H			0x082
-#define AU8522_CLAMPING_CONTROL_REG083H			0x083
-
-#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H		0x0A3
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H		0x0A4
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H		0x0A5
-#define AU8522_AGC_CONTROL_RANGE_REG0A6H		0x0A6
-#define AU8522_SYSTEM_GAIN_CONTROL_REG0A7H		0x0A7
-#define AU8522_TUNER_AGC_RF_STOP_REG0A8H  		0x0A8
-#define AU8522_TUNER_AGC_RF_START_REG0A9H		0x0A9
-#define AU8522_TUNER_RF_AGC_DEFAULT_REG0AAH		0x0AA
-#define AU8522_TUNER_AGC_IF_STOP_REG0ABH		0x0AB
-#define AU8522_TUNER_AGC_IF_START_REG0ACH		0x0AC
-#define AU8522_TUNER_AGC_IF_DEFAULT_REG0ADH		0x0AD
-#define AU8522_TUNER_AGC_STEP_REG0AEH			0x0AE
-#define AU8522_TUNER_GAIN_STEP_REG0AFH			0x0AF
-
-/* Receiver registers */
-#define AU8522_FRMREGTHRD1_REG0B0H			0x0B0
-#define AU8522_FRMREGAGC1H_REG0B1H 			0x0B1
-#define AU8522_FRMREGSHIFT1_REG0B2H 			0x0B2
-#define AU8522_TOREGAGC1_REG0B3H 			0x0B3
-#define AU8522_TOREGASHIFT1_REG0B4H 			0x0B4
-#define AU8522_FRMREGBBH_REG0B5H			0x0B5
-#define AU8522_FRMREGBBM_REG0B6H 			0x0B6
-#define AU8522_FRMREGBBL_REG0B7H     			0x0B7
-/* 0xB8 TO 0xD7 are the filter coefficients */
-#define AU8522_FRMREGTHRD2_REG0D8H 			0x0D8
-#define AU8522_FRMREGAGC2H_REG0D9H 			0x0D9
-#define AU8522_TOREGAGC2_REG0DAH 			0x0DA
-#define AU8522_TOREGSHIFT2_REG0DBH 			0x0DB
-#define AU8522_FRMREGPILOTH_REG0DCH			0x0DC
-#define AU8522_FRMREGPILOTM_REG0DDH			0x0DD
-#define AU8522_FRMREGPILOTL_REG0DEH			0x0DE
-#define AU8522_TOREGFREQ_REG0DFH			0x0DF
-
-#define AU8522_RX_PGA_RFOUT_REG0EBH			0x0EB
-#define AU8522_RX_PGA_IFOUT_REG0ECH			0x0EC
-#define AU8522_RX_PGA_PGAOUT_REG0EDH			0x0ED
-
-#define AU8522_CHIP_MODE_REG0FEH			0x0FE
-
-/* I2C bus control registers */
-#define AU8522_I2C_CONTROL_REG0_REG090H    		0x090
-#define AU8522_I2C_CONTROL_REG1_REG091H    		0x091
-#define AU8522_I2C_STATUS_REG092H          		0x092
-#define AU8522_I2C_WR_DATA0_REG093H			0x093
-#define AU8522_I2C_WR_DATA1_REG094H			0x094
-#define AU8522_I2C_WR_DATA2_REG095H			0x095
-#define AU8522_I2C_WR_DATA3_REG096H			0x096
-#define AU8522_I2C_WR_DATA4_REG097H			0x097
-#define AU8522_I2C_WR_DATA5_REG098H			0x098
-#define AU8522_I2C_WR_DATA6_REG099H			0x099
-#define AU8522_I2C_WR_DATA7_REG09AH			0x09A
-#define AU8522_I2C_RD_DATA0_REG09BH			0x09B
-#define AU8522_I2C_RD_DATA1_REG09CH			0x09C
-#define AU8522_I2C_RD_DATA2_REG09DH			0x09D
-#define AU8522_I2C_RD_DATA3_REG09EH			0x09E
-#define AU8522_I2C_RD_DATA4_REG09FH			0x09F
-#define AU8522_I2C_RD_DATA5_REG0A0H			0x0A0
-#define AU8522_I2C_RD_DATA6_REG0A1H			0x0A1
-#define AU8522_I2C_RD_DATA7_REG0A2H			0x0A2
-
-#define AU8522_ENA_USB_REG101H				0x101
-
-#define AU8522_I2S_CTRL_0_REG110H  			0x110
-#define AU8522_I2S_CTRL_1_REG111H 			0x111
-#define AU8522_I2S_CTRL_2_REG112H 			0x112
-
-#define AU8522_FRMREGFFECONTROL_REG121H    		0x121
-#define AU8522_FRMREGDFECONTROL_REG122H    		0x122
-
-#define AU8522_CARRFREQOFFSET0_REG201H 			0x201
-#define AU8522_CARRFREQOFFSET1_REG202H			0x202
-
-#define AU8522_DECIMATION_GAIN_REG21AH			0x21A
-#define AU8522_FRMREGIFSLP_REG21BH 			0x21B
-#define AU8522_FRMREGTHRDL2_REG21CH 			0x21C
-#define AU8522_FRMREGSTEP3DB_REG21DH 			0x21D
-#define AU8522_DAGC_GAIN_ADJUSTMENT_REG21EH		0x21E
-#define AU8522_FRMREGPLLMODE_REG21FH 			0x21F
-#define AU8522_FRMREGCSTHRD_REG220H 			0x220
-#define AU8522_FRMREGCRLOCKDMAX_REG221H 		0x221
-#define AU8522_FRMREGCRPERIODMASK_REG222H 		0x222
-#define AU8522_FRMREGCRLOCK0THH_REG223H 		0x223
-#define AU8522_FRMREGCRLOCK1THH_REG224H 		0x224
-#define AU8522_FRMREGCRLOCK0THL_REG225H 		0x225
-#define AU8522_FRMREGCRLOCK1THL_REG226H 		0x226
-#define AU_FRMREGPLLACQPHASESCL_REG227H			0x227
-#define AU8522_FRMREGFREQFBCTRL_REG228H 		0x228
-
-/* Analog TV Decoder */
-#define AU8522_TVDEC_STATUS_REG000H			0x000
-#define AU8522_TVDEC_INT_STATUS_REG001H			0x001
-#define AU8522_TVDEC_MACROVISION_STATUS_REG002H 	0x002
-#define AU8522_TVDEC_SHARPNESSREG009H			0x009
-#define AU8522_TVDEC_BRIGHTNESS_REG00AH			0x00A
-#define AU8522_TVDEC_CONTRAST_REG00BH			0x00B
-#define AU8522_TVDEC_SATURATION_CB_REG00CH		0x00C
-#define AU8522_TVDEC_SATURATION_CR_REG00DH		0x00D
-#define AU8522_TVDEC_HUE_H_REG00EH			0x00E
-#define AU8522_TVDEC_HUE_L_REG00FH                   	0x00F
-#define AU8522_TVDEC_INT_MASK_REG010H			0x010
-#define AU8522_VIDEO_MODE_REG011H			0x011
-#define AU8522_TVDEC_PGA_REG012H			0x012
-#define AU8522_TVDEC_COMB_MODE_REG015H			0x015
-#define AU8522_REG016H                            	0x016
-#define AU8522_TVDED_DBG_MODE_REG060H			0x060
-#define AU8522_TVDEC_FORMAT_CTRL1_REG061H		0x061
-#define AU8522_TVDEC_FORMAT_CTRL2_REG062H		0x062
-#define AU8522_TVDEC_VCR_DET_LLIM_REG063H		0x063
-#define AU8522_TVDEC_VCR_DET_HLIM_REG064H		0x064
-#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H		0x065
-#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H		0x066
-#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H		0x067
-#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H		0x068
-#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H   		0x069
-#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH		0x06A
-#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH   		0x06B
-#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH  		0x06C
-#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH 		0x06D
-#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH       	0x06E
-#define AU8522_TVDEC_UV_SEP_THR_REG06FH  		0x06F
-#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H		0x070
-#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H		0x073
-#define AU8522_TVDEC_DCAGC_CTRL_REG077H			0x077
-#define AU8522_TVDEC_PIC_START_ADJ_REG078H		0x078
-#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H		0x079
-#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH	0x07A
-#define AU8522_TVDEC_INTRP_CTRL_REG07BH			0x07B
-#define AU8522_TVDEC_PLL_STATUS_REG07EH			0x07E
-#define AU8522_TVDEC_FSC_FREQ_REG07FH			0x07F
-
-#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H		0x0E4
-#define AU8522_TOREGAAGC_REG0E5H			0x0E5
-
-#define AU8522_TVDEC_CHROMA_AGC_REG401H		0x401
-#define AU8522_TVDEC_CHROMA_SFT_REG402H		0x402
-#define AU8522_FILTER_COEF_R410     		0x410
-#define AU8522_FILTER_COEF_R411     		0x411
-#define AU8522_FILTER_COEF_R412     		0x412
-#define AU8522_FILTER_COEF_R413     		0x413
-#define AU8522_FILTER_COEF_R414     		0x414
-#define AU8522_FILTER_COEF_R415     		0x415
-#define AU8522_FILTER_COEF_R416     		0x416
-#define AU8522_FILTER_COEF_R417     		0x417
-#define AU8522_FILTER_COEF_R418     		0x418
-#define AU8522_FILTER_COEF_R419     		0x419
-#define AU8522_FILTER_COEF_R41A     		0x41A
-#define AU8522_FILTER_COEF_R41B     		0x41B
-#define AU8522_FILTER_COEF_R41C     		0x41C
-#define AU8522_FILTER_COEF_R41D     		0x41D
-#define AU8522_FILTER_COEF_R41E     		0x41E
-#define AU8522_FILTER_COEF_R41F     		0x41F
-#define AU8522_FILTER_COEF_R420     		0x420
-#define AU8522_FILTER_COEF_R421     		0x421
-#define AU8522_FILTER_COEF_R422     		0x422
-#define AU8522_FILTER_COEF_R423     		0x423
-#define AU8522_FILTER_COEF_R424     		0x424
-#define AU8522_FILTER_COEF_R425     		0x425
-#define AU8522_FILTER_COEF_R426     		0x426
-#define AU8522_FILTER_COEF_R427     		0x427
-#define AU8522_FILTER_COEF_R428     		0x428
-#define AU8522_FILTER_COEF_R429     		0x429
-#define AU8522_FILTER_COEF_R42A     		0x42A
-#define AU8522_FILTER_COEF_R42B     		0x42B
-#define AU8522_FILTER_COEF_R42C     		0x42C
-#define AU8522_FILTER_COEF_R42D     		0x42D
-
-/* VBI Control Registers */
-#define AU8522_TVDEC_VBI_RX_FIFO_CONTAIN_REG004H  	0x004
-#define AU8522_TVDEC_VBI_TX_FIFO_CONTAIN_REG005H  	0x005
-#define AU8522_TVDEC_VBI_RX_FIFO_READ_REG006H      	0x006
-#define AU8522_TVDEC_VBI_FIFO_STATUS_REG007H       	0x007
-#define AU8522_TVDEC_VBI_CTRL_H_REG017H			0x017
-#define AU8522_TVDEC_VBI_CTRL_L_REG018H			0x018
-#define AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H	0x019
-#define AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH		0x01A
-#define AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH		0x01B
-#define AU8522_TVDEC_VBI_USER_THRESH1_REG01CH		0x01C
-#define AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH	0x01E
-#define AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH   	0x01F
-#define AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H   	0x020
-#define AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H 	0x021
-#define AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H  	0x022
-#define AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H	0x023
-
-#define AU8522_REG071H					0x071
-#define AU8522_REG072H					0x072
-#define AU8522_REG074H					0x074
-#define AU8522_REG075H					0x075
-
-/* Digital Demodulator Registers */
-#define AU8522_FRAME_COUNT0_REG084H			0x084
-#define AU8522_RS_STATUS_G0_REG085H			0x085
-#define AU8522_RS_STATUS_B0_REG086H			0x086
-#define AU8522_RS_STATUS_E_REG087H			0x087
-#define AU8522_DEMODULATION_STATUS_REG088H		0x088
-#define AU8522_TOREGTRESTATUS_REG0E6H			0x0E6
-#define AU8522_TSPORT_CONTROL_REG10BH			0x10B
-#define AU8522_TSTHES_REG10CH				0x10C
-#define AU8522_FRMREGDFEKEEP_REG301H			0x301
-#define AU8522_DFE_AVERAGE_REG302H			0x302
-#define AU8522_FRMREGEQLERRWIN_REG303H			0x303
-#define AU8522_FRMREGFFEKEEP_REG304H			0x304
-#define AU8522_FRMREGDFECONTROL1_REG305H		0x305
-#define AU8522_FRMREGEQLERRLOW_REG306H			0x306
-
-#define AU8522_REG42EH				0x42E
-#define AU8522_REG42FH				0x42F
-#define AU8522_REG430H				0x430
-#define AU8522_REG431H				0x431
-#define AU8522_REG432H				0x432
-#define AU8522_REG433H				0x433
-#define AU8522_REG434H				0x434
-#define AU8522_REG435H				0x435
-#define AU8522_REG436H				0x436
-
-/* GPIO Registers */
-#define AU8522_GPIO_CONTROL_REG0E0H			0x0E0
-#define AU8522_GPIO_STATUS_REG0E1H			0x0E1
-#define AU8522_GPIO_DATA_REG0E2H			0x0E2
-
-/* Audio Control Registers */
-#define AU8522_AUDIOAGC_REG0EEH 			0x0EE
-#define AU8522_AUDIO_STATUS_REG0F0H 			0x0F0
-#define AU8522_AUDIO_MODE_REG0F1H 			0x0F1
-#define AU8522_AUDIO_VOLUME_L_REG0F2H 			0x0F2
-#define AU8522_AUDIO_VOLUME_R_REG0F3H 			0x0F3
-#define AU8522_AUDIO_VOLUME_REG0F4H 			0x0F4
-#define AU8522_FRMREGAUPHASE_REG0F7H 			0x0F7
-#define AU8522_REG0F9H					0x0F9
-
-#define AU8522_AUDIOAGC2_REG605H 			0x605
-#define AU8522_AUDIOFREQ_REG606H 			0x606
-
-
-/**************************************************************/
-
-#define AU8522_INPUT_CONTROL_REG081H_ATSC               	0xC4
-#define AU8522_INPUT_CONTROL_REG081H_ATVRF			0xC4
-#define AU8522_INPUT_CONTROL_REG081H_ATVRF13			0xC4
-#define AU8522_INPUT_CONTROL_REG081H_J83B64             	0xC4
-#define AU8522_INPUT_CONTROL_REG081H_J83B256            	0xC4
-#define AU8522_INPUT_CONTROL_REG081H_CVBS               	0x20
-#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH1			0xA2
-#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH2			0xA0
-#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH3			0x69
-#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4			0x68
-#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF        	0x28
-/* CH1 AS Y,CH3 AS C */
-#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13        	0x23
-/* CH2 AS Y,CH4 AS C */
-#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24        	0x20
-#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATSC        	0x0C
-#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B64      	0x09
-#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B256    		0x09
-#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS        	0x12
-#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF       	0x1A
-#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF13		0x1A
-#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO		0x02
-
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CLEAR		0x00
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO		0x9C
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS     	0x9D
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATSC		0xE8
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B256 		0xCA
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B64  		0xCA
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF   		0xDD
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF13		0xDD
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_PAL		0xDD
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_FM		0xDD
-
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATSC		0x80
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B256 		0x80
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B64  		0x80
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_ATSC	0x40
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B256	0x40
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B64	0x40
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_CLEAR	0x00
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF		0x01
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF13		0x01
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_SVIDEO  		0x04
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_CVBS		0x01
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PWM     		0x03
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_IIS      	0x09
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PAL		0x01
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_FM		0x01
-
-/* STILL NEED TO BE REFACTORED @@@@@@@@@@@@@@ */
-#define AU8522_TVDEC_CONTRAST_REG00BH_CVBS			0x79
-#define AU8522_TVDEC_SATURATION_CB_REG00CH_CVBS			0x80
-#define AU8522_TVDEC_SATURATION_CR_REG00DH_CVBS			0x80
-#define AU8522_TVDEC_HUE_H_REG00EH_CVBS				0x00
-#define AU8522_TVDEC_HUE_L_REG00FH_CVBS				0x00
-#define AU8522_TVDEC_PGA_REG012H_CVBS				0x0F
-#define AU8522_TVDEC_COMB_MODE_REG015H_CVBS			0x00
-#define AU8522_REG016H_CVBS					0x00
-#define AU8522_TVDED_DBG_MODE_REG060H_CVBS			0x00
-#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS			0x0B
-#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS13		0x03
-#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_CVBS13		0x00
-#define AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS			0x19
-#define AU8522_REG0F9H_AUDIO					0x20
-#define AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS			0xA7
-#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS		0x0A
-#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS		0x32
-#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS		0x19
-#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS		0x23
-#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS		0x41
-#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS		0x0A
-#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS		0x32
-#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS		0x34
-#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO		0x2a
-#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS		0x05
-#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO		0x15
-#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS		0x6E
-#define AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS			0x0F
-#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS		0x80
-#define AU8522_REG071H_CVBS					0x18
-#define AU8522_REG072H_CVBS					0x30
-#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS		0xF0
-#define AU8522_REG074H_CVBS					0x80
-#define AU8522_REG075H_CVBS					0xF0
-#define AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS			0xFB
-#define AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS			0x04
-#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS		0x00
-#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS		0x00
-#define AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS			0xEE
-#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS			0xFE
-#define AU8522_TOREGAAGC_REG0E5H_CVBS				0x00
-#define AU8522_TVDEC_VBI6A_REG035H_CVBS				0x40
-
-/* Enables Closed captioning */
-#define AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON			0x21
diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c
deleted file mode 100644
index 033cd7a..0000000
--- a/drivers/media/dvb/frontends/bcm3510.c
+++ /dev/null
@@ -1,856 +0,0 @@
-/*
- * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC)
- *
- *  Copyright (C) 2001-5, B2C2 inc.
- *
- *  GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de>
- *
- *  This driver is "hard-coded" to be used with the 1st generation of
- *  Technisat/B2C2's Air2PC ATSC PCI/USB cards/boxes. The pll-programming
- *  (Panasonic CT10S) is located here, which is actually wrong. Unless there is
- *  another device with a BCM3510, this is no problem.
- *
- *  The driver works also with QAM64 DVB-C, but had an unreasonable high
- *  UNC. (Tested with the Air2PC ATSC 1st generation)
- *
- *  You'll need a firmware for this driver in order to get it running. It is
- *  called "dvb-fe-bcm3510-01.fw".
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 675 Mass
- * Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/firmware.h>
-#include <linux/jiffies.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-
-#include "dvb_frontend.h"
-#include "bcm3510.h"
-#include "bcm3510_priv.h"
-
-struct bcm3510_state {
-
-	struct i2c_adapter* i2c;
-	const struct bcm3510_config* config;
-	struct dvb_frontend frontend;
-
-	/* demodulator private data */
-	struct mutex hab_mutex;
-	u8 firmware_loaded:1;
-
-	unsigned long next_status_check;
-	unsigned long status_check_interval;
-	struct bcm3510_hab_cmd_status1 status1;
-	struct bcm3510_hab_cmd_status2 status2;
-};
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c (|-able)).");
-
-#define dprintk(level,x...) if (level & debug) printk(x)
-#define dbufout(b,l,m) {\
-	    int i; \
-	    for (i = 0; i < l; i++) \
-		m("%02x ",b[i]); \
-}
-#define deb_info(args...) dprintk(0x01,args)
-#define deb_i2c(args...)  dprintk(0x02,args)
-#define deb_hab(args...)  dprintk(0x04,args)
-
-/* transfer functions */
-static int bcm3510_writebytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len)
-{
-	u8 b[256];
-	int err;
-	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = len + 1 };
-
-	b[0] = reg;
-	memcpy(&b[1],buf,len);
-
-	deb_i2c("i2c wr %02x: ",reg);
-	dbufout(buf,len,deb_i2c);
-	deb_i2c("\n");
-
-	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
-
-		deb_info("%s: i2c write error (addr %02x, reg %02x, err == %i)\n",
-			__func__, state->config->demod_address, reg,  err);
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static int bcm3510_readbytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len)
-{
-	struct i2c_msg msg[] = {
-		{ .addr = state->config->demod_address, .flags = 0,        .buf = &reg, .len = 1 },
-		{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf,  .len = len }
-	};
-	int err;
-
-	memset(buf,0,len);
-
-	if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {
-		deb_info("%s: i2c read error (addr %02x, reg %02x, err == %i)\n",
-			__func__, state->config->demod_address, reg,  err);
-		return -EREMOTEIO;
-	}
-	deb_i2c("i2c rd %02x: ",reg);
-	dbufout(buf,len,deb_i2c);
-	deb_i2c("\n");
-
-	return 0;
-}
-
-static int bcm3510_writeB(struct bcm3510_state *state, u8 reg, bcm3510_register_value v)
-{
-	return bcm3510_writebytes(state,reg,&v.raw,1);
-}
-
-static int bcm3510_readB(struct bcm3510_state *state, u8 reg, bcm3510_register_value *v)
-{
-	return bcm3510_readbytes(state,reg,&v->raw,1);
-}
-
-/* Host Access Buffer transfers */
-static int bcm3510_hab_get_response(struct bcm3510_state *st, u8 *buf, int len)
-{
-	bcm3510_register_value v;
-	int ret,i;
-
-	v.HABADR_a6.HABADR = 0;
-	if ((ret = bcm3510_writeB(st,0xa6,v)) < 0)
-		return ret;
-
-	for (i = 0; i < len; i++) {
-		if ((ret = bcm3510_readB(st,0xa7,&v)) < 0)
-			return ret;
-		buf[i] = v.HABDATA_a7;
-	}
-	return 0;
-}
-
-static int bcm3510_hab_send_request(struct bcm3510_state *st, u8 *buf, int len)
-{
-	bcm3510_register_value v,hab;
-	int ret,i;
-	unsigned long t;
-
-/* Check if any previous HAB request still needs to be serviced by the
- * Acquisition Processor before sending new request */
-	if ((ret = bcm3510_readB(st,0xa8,&v)) < 0)
-		return ret;
-	if (v.HABSTAT_a8.HABR) {
-		deb_info("HAB is running already - clearing it.\n");
-		v.HABSTAT_a8.HABR = 0;
-		bcm3510_writeB(st,0xa8,v);
-//		return -EBUSY;
-	}
-
-/* Send the start HAB Address (automatically incremented after write of
- * HABDATA) and write the HAB Data */
-	hab.HABADR_a6.HABADR = 0;
-	if ((ret = bcm3510_writeB(st,0xa6,hab)) < 0)
-		return ret;
-
-	for (i = 0; i < len; i++) {
-		hab.HABDATA_a7 = buf[i];
-		if ((ret = bcm3510_writeB(st,0xa7,hab)) < 0)
-			return ret;
-	}
-
-/* Set the HABR bit to indicate AP request in progress (LBHABR allows HABR to
- * be written) */
-	v.raw = 0; v.HABSTAT_a8.HABR = 1; v.HABSTAT_a8.LDHABR = 1;
-	if ((ret = bcm3510_writeB(st,0xa8,v)) < 0)
-		return ret;
-
-/* Polling method: Wait until the AP finishes processing the HAB request */
-	t = jiffies + 1*HZ;
-	while (time_before(jiffies, t)) {
-		deb_info("waiting for HAB to complete\n");
-		msleep(10);
-		if ((ret = bcm3510_readB(st,0xa8,&v)) < 0)
-			return ret;
-
-		if (!v.HABSTAT_a8.HABR)
-			return 0;
-	}
-
-	deb_info("send_request execution timed out.\n");
-	return -ETIMEDOUT;
-}
-
-static int bcm3510_do_hab_cmd(struct bcm3510_state *st, u8 cmd, u8 msgid, u8 *obuf, u8 olen, u8 *ibuf, u8 ilen)
-{
-	u8 ob[olen+2],ib[ilen+2];
-	int ret = 0;
-
-	ob[0] = cmd;
-	ob[1] = msgid;
-	memcpy(&ob[2],obuf,olen);
-
-	deb_hab("hab snd: ");
-	dbufout(ob,olen+2,deb_hab);
-	deb_hab("\n");
-
-	if (mutex_lock_interruptible(&st->hab_mutex) < 0)
-		return -EAGAIN;
-
-	if ((ret = bcm3510_hab_send_request(st, ob, olen+2)) < 0 ||
-		(ret = bcm3510_hab_get_response(st, ib, ilen+2)) < 0)
-		goto error;
-
-	deb_hab("hab get: ");
-	dbufout(ib,ilen+2,deb_hab);
-	deb_hab("\n");
-
-	memcpy(ibuf,&ib[2],ilen);
-error:
-	mutex_unlock(&st->hab_mutex);
-	return ret;
-}
-
-#if 0
-/* not needed, we use a semaphore to prevent HAB races */
-static int bcm3510_is_ap_ready(struct bcm3510_state *st)
-{
-	bcm3510_register_value ap,hab;
-	int ret;
-
-	if ((ret = bcm3510_readB(st,0xa8,&hab)) < 0 ||
-		(ret = bcm3510_readB(st,0xa2,&ap) < 0))
-		return ret;
-
-	if (ap.APSTAT1_a2.RESET || ap.APSTAT1_a2.IDLE || ap.APSTAT1_a2.STOP || hab.HABSTAT_a8.HABR) {
-		deb_info("AP is busy\n");
-		return -EBUSY;
-	}
-
-	return 0;
-}
-#endif
-
-static int bcm3510_bert_reset(struct bcm3510_state *st)
-{
-	bcm3510_register_value b;
-	int ret;
-
-	if ((ret = bcm3510_readB(st,0xfa,&b)) < 0)
-		return ret;
-
-	b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b);
-	b.BERCTL_fa.RESYNC = 1; bcm3510_writeB(st,0xfa,b);
-	b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b);
-	b.BERCTL_fa.CNTCTL = 1; b.BERCTL_fa.BITCNT = 1; bcm3510_writeB(st,0xfa,b);
-
-	/* clear residual bit counter TODO  */
-	return 0;
-}
-
-static int bcm3510_refresh_state(struct bcm3510_state *st)
-{
-	if (time_after(jiffies,st->next_status_check)) {
-		bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS1, NULL,0, (u8 *)&st->status1, sizeof(st->status1));
-		bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS2, NULL,0, (u8 *)&st->status2, sizeof(st->status2));
-		st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
-	}
-	return 0;
-}
-
-static int bcm3510_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct bcm3510_state* st = fe->demodulator_priv;
-	bcm3510_refresh_state(st);
-
-	*status = 0;
-	if (st->status1.STATUS1.RECEIVER_LOCK)
-		*status |= FE_HAS_LOCK | FE_HAS_SYNC;
-
-	if (st->status1.STATUS1.FEC_LOCK)
-		*status |= FE_HAS_VITERBI;
-
-	if (st->status1.STATUS1.OUT_PLL_LOCK)
-		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
-
-	if (*status & FE_HAS_LOCK)
-		st->status_check_interval = 1500;
-	else /* more frequently checks if no lock has been achieved yet */
-		st->status_check_interval = 500;
-
-	deb_info("real_status: %02x\n",*status);
-	return 0;
-}
-
-static int bcm3510_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	struct bcm3510_state* st = fe->demodulator_priv;
-	bcm3510_refresh_state(st);
-
-	*ber = (st->status2.LDBER0 << 16) | (st->status2.LDBER1 << 8) | st->status2.LDBER2;
-	return 0;
-}
-
-static int bcm3510_read_unc(struct dvb_frontend* fe, u32* unc)
-{
-	struct bcm3510_state* st = fe->demodulator_priv;
-	bcm3510_refresh_state(st);
-	*unc = (st->status2.LDUERC0 << 8) | st->status2.LDUERC1;
-	return 0;
-}
-
-static int bcm3510_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-{
-	struct bcm3510_state* st = fe->demodulator_priv;
-	s32 t;
-
-	bcm3510_refresh_state(st);
-	t = st->status2.SIGNAL;
-
-	if (t > 190)
-		t = 190;
-	if (t < 90)
-		t = 90;
-
-	t -= 90;
-	t = t * 0xff / 100;
-	/* normalize if necessary */
-	*strength = (t << 8) | t;
-	return 0;
-}
-
-static int bcm3510_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct bcm3510_state* st = fe->demodulator_priv;
-	bcm3510_refresh_state(st);
-
-	*snr = st->status1.SNR_EST0*1000 + ((st->status1.SNR_EST1*1000) >> 8);
-	return 0;
-}
-
-/* tuner frontend programming */
-static int bcm3510_tuner_cmd(struct bcm3510_state* st,u8 bc, u16 n, u8 a)
-{
-	struct bcm3510_hab_cmd_tune c;
-	memset(&c,0,sizeof(struct bcm3510_hab_cmd_tune));
-
-/* I2C Mode disabled,  set 16 control / Data pairs */
-	c.length = 0x10;
-	c.clock_width = 0;
-/* CS1, CS0, DATA, CLK bits control the tuner RF_AGC_SEL pin is set to
- * logic high (as Configuration) */
-	c.misc = 0x10;
-/* Set duration of the initial state of TUNCTL = 3.34 micro Sec */
-	c.TUNCTL_state = 0x40;
-
-/* PRESCALER DIVIDE RATIO | BC1_2_3_4; (band switch), 1stosc REFERENCE COUNTER REF_S12 and REF_S11 */
-	c.ctl_dat[0].ctrl.size = BITS_8;
-	c.ctl_dat[0].data      = 0x80 | bc;
-
-/* Control DATA pin, 1stosc REFERENCE COUNTER REF_S10 to REF_S3 */
-	c.ctl_dat[1].ctrl.size = BITS_8;
-	c.ctl_dat[1].data      = 4;
-
-/* set CONTROL BIT 1 to 1, 1stosc REFERENCE COUNTER REF_S2 to REF_S1 */
-	c.ctl_dat[2].ctrl.size = BITS_3;
-	c.ctl_dat[2].data      = 0x20;
-
-/* control CS0 pin, pulse byte ? */
-	c.ctl_dat[3].ctrl.size = BITS_3;
-	c.ctl_dat[3].ctrl.clk_off = 1;
-	c.ctl_dat[3].ctrl.cs0  = 1;
-	c.ctl_dat[3].data      = 0x40;
-
-/* PGM_S18 to PGM_S11 */
-	c.ctl_dat[4].ctrl.size = BITS_8;
-	c.ctl_dat[4].data      = n >> 3;
-
-/* PGM_S10 to PGM_S8, SWL_S7 to SWL_S3 */
-	c.ctl_dat[5].ctrl.size = BITS_8;
-	c.ctl_dat[5].data      = ((n & 0x7) << 5) | (a >> 2);
-
-/* SWL_S2 and SWL_S1, set CONTROL BIT 2 to 0 */
-	c.ctl_dat[6].ctrl.size = BITS_3;
-	c.ctl_dat[6].data      = (a << 6) & 0xdf;
-
-/* control CS0 pin, pulse byte ? */
-	c.ctl_dat[7].ctrl.size = BITS_3;
-	c.ctl_dat[7].ctrl.clk_off = 1;
-	c.ctl_dat[7].ctrl.cs0  = 1;
-	c.ctl_dat[7].data      = 0x40;
-
-/* PRESCALER DIVIDE RATIO, 2ndosc REFERENCE COUNTER REF_S12 and REF_S11 */
-	c.ctl_dat[8].ctrl.size = BITS_8;
-	c.ctl_dat[8].data      = 0x80;
-
-/* 2ndosc REFERENCE COUNTER REF_S10 to REF_S3 */
-	c.ctl_dat[9].ctrl.size = BITS_8;
-	c.ctl_dat[9].data      = 0x10;
-
-/* set CONTROL BIT 1 to 1, 2ndosc REFERENCE COUNTER REF_S2 to REF_S1 */
-	c.ctl_dat[10].ctrl.size = BITS_3;
-	c.ctl_dat[10].data      = 0x20;
-
-/* pulse byte */
-	c.ctl_dat[11].ctrl.size = BITS_3;
-	c.ctl_dat[11].ctrl.clk_off = 1;
-	c.ctl_dat[11].ctrl.cs1  = 1;
-	c.ctl_dat[11].data      = 0x40;
-
-/* PGM_S18 to PGM_S11 */
-	c.ctl_dat[12].ctrl.size = BITS_8;
-	c.ctl_dat[12].data      = 0x2a;
-
-/* PGM_S10 to PGM_S8 and SWL_S7 to SWL_S3 */
-	c.ctl_dat[13].ctrl.size = BITS_8;
-	c.ctl_dat[13].data      = 0x8e;
-
-/* SWL_S2 and SWL_S1 and set CONTROL BIT 2 to 0 */
-	c.ctl_dat[14].ctrl.size = BITS_3;
-	c.ctl_dat[14].data      = 0;
-
-/* Pulse Byte */
-	c.ctl_dat[15].ctrl.size = BITS_3;
-	c.ctl_dat[15].ctrl.clk_off = 1;
-	c.ctl_dat[15].ctrl.cs1  = 1;
-	c.ctl_dat[15].data      = 0x40;
-
-	return bcm3510_do_hab_cmd(st,CMD_TUNE, MSGID_TUNE,(u8 *) &c,sizeof(c), NULL, 0);
-}
-
-static int bcm3510_set_freq(struct bcm3510_state* st,u32 freq)
-{
-	u8 bc,a;
-	u16 n;
-	s32 YIntercept,Tfvco1;
-
-	freq /= 1000;
-
-	deb_info("%dkHz:",freq);
-	/* set Band Switch */
-	if (freq <= 168000)
-		bc = 0x1c;
-	else if (freq <= 378000)
-		bc = 0x2c;
-	else
-		bc = 0x30;
-
-	if (freq >= 470000) {
-		freq -= 470001;
-		YIntercept = 18805;
-	} else if (freq >= 90000) {
-		freq -= 90001;
-		YIntercept = 15005;
-	} else if (freq >= 76000){
-		freq -= 76001;
-		YIntercept = 14865;
-	} else {
-		freq -= 54001;
-		YIntercept = 14645;
-	}
-
-	Tfvco1 = (((freq/6000)*60 + YIntercept)*4)/10;
-
-	n = Tfvco1 >> 6;
-	a = Tfvco1 & 0x3f;
-
-	deb_info(" BC1_2_3_4: %x, N: %x A: %x\n", bc, n, a);
-	if (n >= 16 && n <= 2047)
-		return bcm3510_tuner_cmd(st,bc,n,a);
-
-	return -EINVAL;
-}
-
-static int bcm3510_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct bcm3510_state* st = fe->demodulator_priv;
-	struct bcm3510_hab_cmd_ext_acquire cmd;
-	struct bcm3510_hab_cmd_bert_control bert;
-	int ret;
-
-	memset(&cmd,0,sizeof(cmd));
-	switch (c->modulation) {
-		case QAM_256:
-			cmd.ACQUIRE0.MODE = 0x1;
-			cmd.ACQUIRE1.SYM_RATE = 0x1;
-			cmd.ACQUIRE1.IF_FREQ = 0x1;
-			break;
-		case QAM_64:
-			cmd.ACQUIRE0.MODE = 0x2;
-			cmd.ACQUIRE1.SYM_RATE = 0x2;
-			cmd.ACQUIRE1.IF_FREQ = 0x1;
-			break;
-#if 0
-		case QAM_256:
-			cmd.ACQUIRE0.MODE = 0x3;
-			break;
-		case QAM_128:
-			cmd.ACQUIRE0.MODE = 0x4;
-			break;
-		case QAM_64:
-			cmd.ACQUIRE0.MODE = 0x5;
-			break;
-		case QAM_32:
-			cmd.ACQUIRE0.MODE = 0x6;
-			break;
-		case QAM_16:
-			cmd.ACQUIRE0.MODE = 0x7;
-			break;
-#endif
-		case VSB_8:
-			cmd.ACQUIRE0.MODE = 0x8;
-			cmd.ACQUIRE1.SYM_RATE = 0x0;
-			cmd.ACQUIRE1.IF_FREQ = 0x0;
-			break;
-		case VSB_16:
-			cmd.ACQUIRE0.MODE = 0x9;
-			cmd.ACQUIRE1.SYM_RATE = 0x0;
-			cmd.ACQUIRE1.IF_FREQ = 0x0;
-		default:
-			return -EINVAL;
-	};
-	cmd.ACQUIRE0.OFFSET = 0;
-	cmd.ACQUIRE0.NTSCSWEEP = 1;
-	cmd.ACQUIRE0.FA = 1;
-	cmd.ACQUIRE0.BW = 0;
-
-/*	if (enableOffset) {
-		cmd.IF_OFFSET0 = xx;
-		cmd.IF_OFFSET1 = xx;
-
-		cmd.SYM_OFFSET0 = xx;
-		cmd.SYM_OFFSET1 = xx;
-		if (enableNtscSweep) {
-			cmd.NTSC_OFFSET0;
-			cmd.NTSC_OFFSET1;
-		}
-	} */
-	bcm3510_do_hab_cmd(st, CMD_ACQUIRE, MSGID_EXT_TUNER_ACQUIRE, (u8 *) &cmd, sizeof(cmd), NULL, 0);
-
-/* doing it with different MSGIDs, data book and source differs */
-	bert.BE = 0;
-	bert.unused = 0;
-	bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_CONTROL, (u8 *) &bert, sizeof(bert), NULL, 0);
-	bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_SET, (u8 *) &bert, sizeof(bert), NULL, 0);
-
-	bcm3510_bert_reset(st);
-
-	ret = bcm3510_set_freq(st, c->frequency);
-	if (ret < 0)
-		return ret;
-
-	memset(&st->status1,0,sizeof(st->status1));
-	memset(&st->status2,0,sizeof(st->status2));
-	st->status_check_interval = 500;
-
-/* Give the AP some time */
-	msleep(200);
-
-	return 0;
-}
-
-static int bcm3510_sleep(struct dvb_frontend* fe)
-{
-	return 0;
-}
-
-static int bcm3510_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *s)
-{
-	s->min_delay_ms = 1000;
-	s->step_size = 0;
-	s->max_drift = 0;
-	return 0;
-}
-
-static void bcm3510_release(struct dvb_frontend* fe)
-{
-	struct bcm3510_state* state = fe->demodulator_priv;
-	kfree(state);
-}
-
-/* firmware download:
- * firmware file is build up like this:
- * 16bit addr, 16bit length, 8byte of length
- */
-#define BCM3510_DEFAULT_FIRMWARE "dvb-fe-bcm3510-01.fw"
-
-static int bcm3510_write_ram(struct bcm3510_state *st, u16 addr, const u8 *b,
-			     u16 len)
-{
-	int ret = 0,i;
-	bcm3510_register_value vH, vL,vD;
-
-	vH.MADRH_a9 = addr >> 8;
-	vL.MADRL_aa = addr;
-	if ((ret = bcm3510_writeB(st,0xa9,vH)) < 0) return ret;
-	if ((ret = bcm3510_writeB(st,0xaa,vL)) < 0) return ret;
-
-	for (i = 0; i < len; i++) {
-		vD.MDATA_ab = b[i];
-		if ((ret = bcm3510_writeB(st,0xab,vD)) < 0)
-			return ret;
-	}
-
-	return 0;
-}
-
-static int bcm3510_download_firmware(struct dvb_frontend* fe)
-{
-	struct bcm3510_state* st = fe->demodulator_priv;
-	const struct firmware *fw;
-	u16 addr,len;
-	const u8 *b;
-	int ret,i;
-
-	deb_info("requesting firmware\n");
-	if ((ret = st->config->request_firmware(fe, &fw, BCM3510_DEFAULT_FIRMWARE)) < 0) {
-		err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret);
-		return ret;
-	}
-	deb_info("got firmware: %zd\n",fw->size);
-
-	b = fw->data;
-	for (i = 0; i < fw->size;) {
-		addr = le16_to_cpu( *( (u16 *)&b[i] ) );
-		len  = le16_to_cpu( *( (u16 *)&b[i+2] ) );
-		deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size);
-		if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) {
-			err("firmware download failed: %d\n",ret);
-			return ret;
-		}
-		i += 4 + len;
-	}
-	release_firmware(fw);
-	deb_info("firmware download successfully completed\n");
-	return 0;
-}
-
-static int bcm3510_check_firmware_version(struct bcm3510_state *st)
-{
-	struct bcm3510_hab_cmd_get_version_info ver;
-	bcm3510_do_hab_cmd(st,CMD_GET_VERSION_INFO,MSGID_GET_VERSION_INFO,NULL,0,(u8*)&ver,sizeof(ver));
-
-	deb_info("Version information: 0x%02x 0x%02x 0x%02x 0x%02x\n",
-		ver.microcode_version, ver.script_version, ver.config_version, ver.demod_version);
-
-	if (ver.script_version == BCM3510_DEF_SCRIPT_VERSION &&
-		ver.config_version == BCM3510_DEF_CONFIG_VERSION &&
-		ver.demod_version  == BCM3510_DEF_DEMOD_VERSION)
-		return 0;
-
-	deb_info("version check failed\n");
-	return -ENODEV;
-}
-
-/* (un)resetting the AP */
-static int bcm3510_reset(struct bcm3510_state *st)
-{
-	int ret;
-	unsigned long  t;
-	bcm3510_register_value v;
-
-	bcm3510_readB(st,0xa0,&v); v.HCTL1_a0.RESET = 1;
-	if ((ret = bcm3510_writeB(st,0xa0,v)) < 0)
-		return ret;
-
-    t = jiffies + 3*HZ;
-	while (time_before(jiffies, t)) {
-		msleep(10);
-		if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
-			return ret;
-
-		if (v.APSTAT1_a2.RESET)
-			return 0;
-	}
-	deb_info("reset timed out\n");
-	return -ETIMEDOUT;
-}
-
-static int bcm3510_clear_reset(struct bcm3510_state *st)
-{
-	bcm3510_register_value v;
-	int ret;
-	unsigned long t;
-
-	v.raw = 0;
-	if ((ret = bcm3510_writeB(st,0xa0,v)) < 0)
-		return ret;
-
-    t = jiffies + 3*HZ;
-	while (time_before(jiffies, t)) {
-		msleep(10);
-		if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
-			return ret;
-
-		/* verify that reset is cleared */
-		if (!v.APSTAT1_a2.RESET)
-			return 0;
-	}
-	deb_info("reset clear timed out\n");
-	return -ETIMEDOUT;
-}
-
-static int bcm3510_init_cold(struct bcm3510_state *st)
-{
-	int ret;
-	bcm3510_register_value v;
-
-	/* read Acquisation Processor status register and check it is not in RUN mode */
-	if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
-		return ret;
-	if (v.APSTAT1_a2.RUN) {
-		deb_info("AP is already running - firmware already loaded.\n");
-		return 0;
-	}
-
-	deb_info("reset?\n");
-	if ((ret = bcm3510_reset(st)) < 0)
-		return ret;
-
-	deb_info("tristate?\n");
-	/* tri-state */
-	v.TSTCTL_2e.CTL = 0;
-	if ((ret = bcm3510_writeB(st,0x2e,v)) < 0)
-		return ret;
-
-	deb_info("firmware?\n");
-	if ((ret = bcm3510_download_firmware(&st->frontend)) < 0 ||
-		(ret = bcm3510_clear_reset(st)) < 0)
-		return ret;
-
-	/* anything left here to Let the acquisition processor begin execution at program counter 0000 ??? */
-
-	return 0;
-}
-
-static int bcm3510_init(struct dvb_frontend* fe)
-{
-	struct bcm3510_state* st = fe->demodulator_priv;
-	bcm3510_register_value j;
-	struct bcm3510_hab_cmd_set_agc c;
-	int ret;
-
-	if ((ret = bcm3510_readB(st,0xca,&j)) < 0)
-		return ret;
-
-	deb_info("JDEC: %02x\n",j.raw);
-
-	switch (j.JDEC_ca.JDEC) {
-		case JDEC_WAIT_AT_RAM:
-			deb_info("attempting to download firmware\n");
-			if ((ret = bcm3510_init_cold(st)) < 0)
-				return ret;
-		case JDEC_EEPROM_LOAD_WAIT: /* fall-through is wanted */
-			deb_info("firmware is loaded\n");
-			bcm3510_check_firmware_version(st);
-			break;
-		default:
-			return -ENODEV;
-	}
-
-	memset(&c,0,1);
-	c.SEL = 1;
-	bcm3510_do_hab_cmd(st,CMD_AUTO_PARAM,MSGID_SET_RF_AGC_SEL,(u8 *)&c,sizeof(c),NULL,0);
-
-	return 0;
-}
-
-
-static struct dvb_frontend_ops bcm3510_ops;
-
-struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config,
-				   struct i2c_adapter *i2c)
-{
-	struct bcm3510_state* state = NULL;
-	int ret;
-	bcm3510_register_value v;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct bcm3510_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* setup the state */
-
-	state->config = config;
-	state->i2c = i2c;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-
-	mutex_init(&state->hab_mutex);
-
-	if ((ret = bcm3510_readB(state,0xe0,&v)) < 0)
-		goto error;
-
-	deb_info("Revision: 0x%1x, Layer: 0x%1x.\n",v.REVID_e0.REV,v.REVID_e0.LAYER);
-
-	if ((v.REVID_e0.REV != 0x1 && v.REVID_e0.LAYER != 0xb) && /* cold */
-		(v.REVID_e0.REV != 0x8 && v.REVID_e0.LAYER != 0x0))   /* warm */
-		goto error;
-
-	info("Revision: 0x%1x, Layer: 0x%1x.",v.REVID_e0.REV,v.REVID_e0.LAYER);
-
-	bcm3510_reset(state);
-
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(bcm3510_attach);
-
-static struct dvb_frontend_ops bcm3510_ops = {
-	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
-	.info = {
-		.name = "Broadcom BCM3510 VSB/QAM frontend",
-		.frequency_min =  54000000,
-		.frequency_max = 803000000,
-		/* stepsize is just a guess */
-		.frequency_stepsize = 0,
-		.caps =
-			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_8VSB | FE_CAN_16VSB |
-			FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256
-	},
-
-	.release = bcm3510_release,
-
-	.init = bcm3510_init,
-	.sleep = bcm3510_sleep,
-
-	.set_frontend = bcm3510_set_frontend,
-	.get_tune_settings = bcm3510_get_tune_settings,
-
-	.read_status = bcm3510_read_status,
-	.read_ber = bcm3510_read_ber,
-	.read_signal_strength = bcm3510_read_signal_strength,
-	.read_snr = bcm3510_read_snr,
-	.read_ucblocks = bcm3510_read_unc,
-};
-
-MODULE_DESCRIPTION("Broadcom BCM3510 ATSC (8VSB/16VSB & ITU J83 AnnexB FEC QAM64/256) demodulator driver");
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/bcm3510.h b/drivers/media/dvb/frontends/bcm3510.h
deleted file mode 100644
index f4575c0..0000000
--- a/drivers/media/dvb/frontends/bcm3510.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC)
- *
- *  Copyright (C) 2001-5, B2C2 inc.
- *
- *  GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#ifndef BCM3510_H
-#define BCM3510_H
-
-#include <linux/dvb/frontend.h>
-#include <linux/firmware.h>
-
-struct bcm3510_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* request firmware for device */
-	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
-};
-
-#if defined(CONFIG_DVB_BCM3510) || (defined(CONFIG_DVB_BCM3510_MODULE) && defined(MODULE))
-extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
-					   struct i2c_adapter* i2c);
-#else
-static inline struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
-						  struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_BCM3510
-
-#endif
diff --git a/drivers/media/dvb/frontends/bcm3510_priv.h b/drivers/media/dvb/frontends/bcm3510_priv.h
deleted file mode 100644
index 3bb1bc2..0000000
--- a/drivers/media/dvb/frontends/bcm3510_priv.h
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC)
- *
- *  Copyright (C) 2001-5, B2C2 inc.
- *
- *  GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#ifndef __BCM3510_PRIV_H__
-#define __BCM3510_PRIV_H__
-
-#define PACKED __attribute__((packed))
-
-#undef err
-#define err(format, arg...)  printk(KERN_ERR     "bcm3510: " format "\n" , ## arg)
-#undef info
-#define info(format, arg...) printk(KERN_INFO    "bcm3510: " format "\n" , ## arg)
-#undef warn
-#define warn(format, arg...) printk(KERN_WARNING "bcm3510: " format "\n" , ## arg)
-
-
-#define PANASONIC_FIRST_IF_BASE_IN_KHz  1407500
-#define BCM3510_SYMBOL_RATE             5381000
-
-typedef union {
-	u8 raw;
-
-	struct {
-		u8 CTL   :8;
-	} TSTCTL_2e;
-
-	u8 LDCERC_4e;
-	u8 LDUERC_4f;
-	u8 LD_BER0_65;
-	u8 LD_BER1_66;
-	u8 LD_BER2_67;
-	u8 LD_BER3_68;
-
-	struct {
-		u8 RESET :1;
-		u8 IDLE  :1;
-		u8 STOP  :1;
-		u8 HIRQ0 :1;
-		u8 HIRQ1 :1;
-		u8 na0   :1;
-		u8 HABAV :1;
-		u8 na1   :1;
-	} HCTL1_a0;
-
-	struct {
-		u8 na0    :1;
-		u8 IDLMSK :1;
-		u8 STMSK  :1;
-		u8 I0MSK  :1;
-		u8 I1MSK  :1;
-		u8 na1    :1;
-		u8 HABMSK :1;
-		u8 na2    :1;
-	} HCTLMSK_a1;
-
-	struct {
-		u8 RESET  :1;
-		u8 IDLE   :1;
-		u8 STOP   :1;
-		u8 RUN    :1;
-		u8 HABAV  :1;
-		u8 MEMAV  :1;
-		u8 ALDONE :1;
-		u8 REIRQ  :1;
-	} APSTAT1_a2;
-
-	struct {
-		u8 RSTMSK :1;
-		u8 IMSK   :1;
-		u8 SMSK   :1;
-		u8 RMSK   :1;
-		u8 HABMSK :1;
-		u8 MAVMSK :1;
-		u8 ALDMSK :1;
-		u8 REMSK  :1;
-	} APMSK1_a3;
-
-	u8 APSTAT2_a4;
-	u8 APMSK2_a5;
-
-	struct {
-		u8 HABADR :7;
-		u8 na     :1;
-	} HABADR_a6;
-
-	u8 HABDATA_a7;
-
-	struct {
-		u8 HABR   :1;
-		u8 LDHABR :1;
-		u8 APMSK  :1;
-		u8 HMSK   :1;
-		u8 LDMSK  :1;
-		u8 na     :3;
-	} HABSTAT_a8;
-
-	u8 MADRH_a9;
-	u8 MADRL_aa;
-	u8 MDATA_ab;
-
-	struct {
-#define JDEC_WAIT_AT_RAM      0x7
-#define JDEC_EEPROM_LOAD_WAIT 0x4
-		u8 JDEC   :3;
-		u8 na     :5;
-	} JDEC_ca;
-
-	struct {
-		u8 REV   :4;
-		u8 LAYER :4;
-	} REVID_e0;
-
-	struct {
-		u8 unk0   :1;
-		u8 CNTCTL :1;
-		u8 BITCNT :1;
-		u8 unk1   :1;
-		u8 RESYNC :1;
-		u8 unk2   :3;
-	} BERCTL_fa;
-
-	struct {
-		u8 CSEL0  :1;
-		u8 CLKED0 :1;
-		u8 CSEL1  :1;
-		u8 CLKED1 :1;
-		u8 CLKLEV :1;
-		u8 SPIVAR :1;
-		u8 na     :2;
-	} TUNSET_fc;
-
-	struct {
-		u8 CLK    :1;
-		u8 DATA   :1;
-		u8 CS0    :1;
-		u8 CS1    :1;
-		u8 AGCSEL :1;
-		u8 na0    :1;
-		u8 TUNSEL :1;
-		u8 na1    :1;
-	} TUNCTL_fd;
-
-	u8 TUNSEL0_fe;
-	u8 TUNSEL1_ff;
-
-} bcm3510_register_value;
-
-/* HAB commands */
-
-/* version */
-#define CMD_GET_VERSION_INFO   0x3D
-#define MSGID_GET_VERSION_INFO 0x15
-struct bcm3510_hab_cmd_get_version_info {
-	u8 microcode_version;
-	u8 script_version;
-	u8 config_version;
-	u8 demod_version;
-} PACKED;
-
-#define BCM3510_DEF_MICROCODE_VERSION 0x0E
-#define BCM3510_DEF_SCRIPT_VERSION    0x06
-#define BCM3510_DEF_CONFIG_VERSION    0x01
-#define BCM3510_DEF_DEMOD_VERSION     0xB1
-
-/* acquire */
-#define CMD_ACQUIRE            0x38
-
-#define MSGID_EXT_TUNER_ACQUIRE 0x0A
-struct bcm3510_hab_cmd_ext_acquire {
-	struct {
-		u8 MODE      :4;
-		u8 BW        :1;
-		u8 FA        :1;
-		u8 NTSCSWEEP :1;
-		u8 OFFSET    :1;
-	} PACKED ACQUIRE0; /* control_byte */
-
-	struct {
-		u8 IF_FREQ  :3;
-		u8 zero0    :1;
-		u8 SYM_RATE :3;
-		u8 zero1    :1;
-	} PACKED ACQUIRE1; /* sym_if */
-
-	u8 IF_OFFSET0;   /* IF_Offset_10hz */
-	u8 IF_OFFSET1;
-	u8 SYM_OFFSET0;  /* SymbolRateOffset */
-	u8 SYM_OFFSET1;
-	u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */
-	u8 NTSC_OFFSET1;
-} PACKED;
-
-#define MSGID_INT_TUNER_ACQUIRE 0x0B
-struct bcm3510_hab_cmd_int_acquire {
-	struct {
-		u8 MODE      :4;
-		u8 BW        :1;
-		u8 FA        :1;
-		u8 NTSCSWEEP :1;
-		u8 OFFSET    :1;
-	} PACKED ACQUIRE0; /* control_byte */
-
-	struct {
-		u8 IF_FREQ  :3;
-		u8 zero0    :1;
-		u8 SYM_RATE :3;
-		u8 zero1    :1;
-	} PACKED ACQUIRE1; /* sym_if */
-
-	u8 TUNER_FREQ0;
-	u8 TUNER_FREQ1;
-	u8 TUNER_FREQ2;
-	u8 TUNER_FREQ3;
-	u8 IF_OFFSET0;   /* IF_Offset_10hz */
-	u8 IF_OFFSET1;
-	u8 SYM_OFFSET0;  /* SymbolRateOffset */
-	u8 SYM_OFFSET1;
-	u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */
-	u8 NTSC_OFFSET1;
-} PACKED;
-
-/* modes */
-#define BCM3510_QAM16           =   0x01
-#define BCM3510_QAM32           =   0x02
-#define BCM3510_QAM64           =   0x03
-#define BCM3510_QAM128          =   0x04
-#define BCM3510_QAM256          =   0x05
-#define BCM3510_8VSB            =   0x0B
-#define BCM3510_16VSB           =   0x0D
-
-/* IF_FREQS */
-#define BCM3510_IF_TERRESTRIAL 0x0
-#define BCM3510_IF_CABLE       0x1
-#define BCM3510_IF_USE_CMD     0x7
-
-/* SYM_RATE */
-#define BCM3510_SR_8VSB        0x0 /* 5381119 s/sec */
-#define BCM3510_SR_256QAM      0x1 /* 5360537 s/sec */
-#define BCM3510_SR_16QAM       0x2 /* 5056971 s/sec */
-#define BCM3510_SR_MISC        0x3 /* 5000000 s/sec */
-#define BCM3510_SR_USE_CMD     0x7
-
-/* special symbol rate */
-#define CMD_SET_VALUE_NOT_LISTED  0x2d
-#define MSGID_SET_SYMBOL_RATE_NOT_LISTED 0x0c
-struct bcm3510_hab_cmd_set_sr_not_listed {
-	u8 HOST_SYM_RATE0;
-	u8 HOST_SYM_RATE1;
-	u8 HOST_SYM_RATE2;
-	u8 HOST_SYM_RATE3;
-} PACKED;
-
-/* special IF */
-#define MSGID_SET_IF_FREQ_NOT_LISTED 0x0d
-struct bcm3510_hab_cmd_set_if_freq_not_listed {
-	u8 HOST_IF_FREQ0;
-	u8 HOST_IF_FREQ1;
-	u8 HOST_IF_FREQ2;
-	u8 HOST_IF_FREQ3;
-} PACKED;
-
-/* auto reacquire */
-#define CMD_AUTO_PARAM       0x2a
-#define MSGID_AUTO_REACQUIRE 0x0e
-struct bcm3510_hab_cmd_auto_reacquire {
-	u8 ACQ    :1; /* on/off*/
-	u8 unused :7;
-} PACKED;
-
-#define MSGID_SET_RF_AGC_SEL 0x12
-struct bcm3510_hab_cmd_set_agc {
-	u8 LVL    :1;
-	u8 unused :6;
-	u8 SEL    :1;
-} PACKED;
-
-#define MSGID_SET_AUTO_INVERSION 0x14
-struct bcm3510_hab_cmd_auto_inversion {
-	u8 AI     :1;
-	u8 unused :7;
-} PACKED;
-
-
-/* bert control */
-#define CMD_STATE_CONTROL  0x12
-#define MSGID_BERT_CONTROL 0x0e
-#define MSGID_BERT_SET     0xfa
-struct bcm3510_hab_cmd_bert_control {
-	u8 BE     :1;
-	u8 unused :7;
-} PACKED;
-
-#define MSGID_TRI_STATE 0x2e
-struct bcm3510_hab_cmd_tri_state {
-	u8 RE :1; /* a/d ram port pins */
-	u8 PE :1; /* baud clock pin */
-	u8 AC :1; /* a/d clock pin */
-	u8 BE :1; /* baud clock pin */
-	u8 unused :4;
-} PACKED;
-
-
-/* tune */
-#define CMD_TUNE   0x38
-#define MSGID_TUNE 0x16
-struct bcm3510_hab_cmd_tune_ctrl_data_pair {
-	struct {
-#define BITS_8 0x07
-#define BITS_7 0x06
-#define BITS_6 0x05
-#define BITS_5 0x04
-#define BITS_4 0x03
-#define BITS_3 0x02
-#define BITS_2 0x01
-#define BITS_1 0x00
-		u8 size    :3;
-		u8 unk     :2;
-		u8 clk_off :1;
-		u8 cs0     :1;
-		u8 cs1     :1;
-
-	} PACKED ctrl;
-
-	u8 data;
-} PACKED;
-
-struct bcm3510_hab_cmd_tune {
-	u8 length;
-	u8 clock_width;
-	u8 misc;
-	u8 TUNCTL_state;
-
-	struct bcm3510_hab_cmd_tune_ctrl_data_pair ctl_dat[16];
-} PACKED;
-
-#define CMD_STATUS    0x38
-#define MSGID_STATUS1 0x08
-struct bcm3510_hab_cmd_status1 {
-	struct {
-		u8 EQ_MODE       :4;
-		u8 reserved      :2;
-		u8 QRE           :1; /* if QSE and the spectrum is inversed */
-		u8 QSE           :1; /* automatic spectral inversion */
-	} PACKED STATUS0;
-
-	struct {
-		u8 RECEIVER_LOCK :1;
-		u8 FEC_LOCK      :1;
-		u8 OUT_PLL_LOCK  :1;
-		u8 reserved      :5;
-	} PACKED STATUS1;
-
-	struct {
-		u8 reserved      :2;
-		u8 BW            :1;
-		u8 NTE           :1; /* NTSC filter sweep enabled */
-		u8 AQI           :1; /* currently acquiring */
-		u8 FA            :1; /* fast acquisition */
-		u8 ARI           :1; /* auto reacquire */
-		u8 TI            :1; /* programming the tuner */
-	} PACKED STATUS2;
-	u8 STATUS3;
-	u8 SNR_EST0;
-	u8 SNR_EST1;
-	u8 TUNER_FREQ0;
-	u8 TUNER_FREQ1;
-	u8 TUNER_FREQ2;
-	u8 TUNER_FREQ3;
-	u8 SYM_RATE0;
-	u8 SYM_RATE1;
-	u8 SYM_RATE2;
-	u8 SYM_RATE3;
-	u8 SYM_OFFSET0;
-	u8 SYM_OFFSET1;
-	u8 SYM_ERROR0;
-	u8 SYM_ERROR1;
-	u8 IF_FREQ0;
-	u8 IF_FREQ1;
-	u8 IF_FREQ2;
-	u8 IF_FREQ3;
-	u8 IF_OFFSET0;
-	u8 IF_OFFSET1;
-	u8 IF_ERROR0;
-	u8 IF_ERROR1;
-	u8 NTSC_FILTER0;
-	u8 NTSC_FILTER1;
-	u8 NTSC_FILTER2;
-	u8 NTSC_FILTER3;
-	u8 NTSC_OFFSET0;
-	u8 NTSC_OFFSET1;
-	u8 NTSC_ERROR0;
-	u8 NTSC_ERROR1;
-	u8 INT_AGC_LEVEL0;
-	u8 INT_AGC_LEVEL1;
-	u8 EXT_AGC_LEVEL0;
-	u8 EXT_AGC_LEVEL1;
-} PACKED;
-
-#define MSGID_STATUS2 0x14
-struct bcm3510_hab_cmd_status2 {
-	struct {
-		u8 EQ_MODE  :4;
-		u8 reserved :2;
-		u8 QRE      :1;
-		u8 QSR      :1;
-	} PACKED STATUS0;
-	struct {
-		u8 RL       :1;
-		u8 FL       :1;
-		u8 OL       :1;
-		u8 reserved :5;
-	} PACKED STATUS1;
-	u8 SYMBOL_RATE0;
-	u8 SYMBOL_RATE1;
-	u8 SYMBOL_RATE2;
-	u8 SYMBOL_RATE3;
-	u8 LDCERC0;
-	u8 LDCERC1;
-	u8 LDCERC2;
-	u8 LDCERC3;
-	u8 LDUERC0;
-	u8 LDUERC1;
-	u8 LDUERC2;
-	u8 LDUERC3;
-	u8 LDBER0;
-	u8 LDBER1;
-	u8 LDBER2;
-	u8 LDBER3;
-	struct {
-		u8 MODE_TYPE :4; /* acquire mode 0 */
-		u8 reservd   :4;
-	} MODE_TYPE;
-	u8 SNR_EST0;
-	u8 SNR_EST1;
-	u8 SIGNAL;
-} PACKED;
-
-#define CMD_SET_RF_BW_NOT_LISTED   0x3f
-#define MSGID_SET_RF_BW_NOT_LISTED 0x11
-/* TODO */
-
-#endif
diff --git a/drivers/media/dvb/frontends/bsbe1-d01a.h b/drivers/media/dvb/frontends/bsbe1-d01a.h
deleted file mode 100644
index 7ed3c42..0000000
--- a/drivers/media/dvb/frontends/bsbe1-d01a.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * bsbe1-d01a.h - ALPS BSBE1-D01A tuner support
- *
- * Copyright (C) 2011 Oliver Endriss <o.endriss@gmx.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org
- */
-
-#ifndef BSBE1_D01A_H
-#define BSBE1_D01A_H
-
-#include "stb6000.h"
-#include "stv0288.h"
-
-static u8 stv0288_bsbe1_d01a_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x20,
-	0x09, 0x0,
-	0x0a, 0x4,
-	0x0b, 0x0,
-	0x0c, 0x0,
-	0x0d, 0x0,
-	0x0e, 0xd4,
-	0x0f, 0x30,
-	0x11, 0x80,
-	0x12, 0x03,
-	0x13, 0x48,
-	0x14, 0x84,
-	0x15, 0x45,
-	0x16, 0xb7,
-	0x17, 0x9c,
-	0x18, 0x0,
-	0x19, 0xa6,
-	0x1a, 0x88,
-	0x1b, 0x8f,
-	0x1c, 0xf0,
-	0x20, 0x0b,
-	0x21, 0x54,
-	0x22, 0x0,
-	0x23, 0x0,
-	0x2b, 0xff,
-	0x2c, 0xf7,
-	0x30, 0x0,
-	0x31, 0x1e,
-	0x32, 0x14,
-	0x33, 0x0f,
-	0x34, 0x09,
-	0x35, 0x0c,
-	0x36, 0x05,
-	0x37, 0x2f,
-	0x38, 0x16,
-	0x39, 0xbd,
-	0x3a, 0x03,
-	0x3b, 0x13,
-	0x3c, 0x11,
-	0x3d, 0x30,
-	0x40, 0x63,
-	0x41, 0x04,
-	0x42, 0x60,
-	0x43, 0x00,
-	0x44, 0x00,
-	0x45, 0x00,
-	0x46, 0x00,
-	0x47, 0x00,
-	0x4a, 0x00,
-	0x50, 0x10,
-	0x51, 0x36,
-	0x52, 0x09,
-	0x53, 0x94,
-	0x54, 0x62,
-	0x55, 0x29,
-	0x56, 0x64,
-	0x57, 0x2b,
-	0x58, 0x54,
-	0x59, 0x86,
-	0x5a, 0x0,
-	0x5b, 0x9b,
-	0x5c, 0x08,
-	0x5d, 0x7f,
-	0x5e, 0x0,
-	0x5f, 0xff,
-	0x70, 0x0,
-	0x71, 0x0,
-	0x72, 0x0,
-	0x74, 0x0,
-	0x75, 0x0,
-	0x76, 0x0,
-	0x81, 0x0,
-	0x82, 0x3f,
-	0x83, 0x3f,
-	0x84, 0x0,
-	0x85, 0x0,
-	0x88, 0x0,
-	0x89, 0x0,
-	0x8a, 0x0,
-	0x8b, 0x0,
-	0x8c, 0x0,
-	0x90, 0x0,
-	0x91, 0x0,
-	0x92, 0x0,
-	0x93, 0x0,
-	0x94, 0x1c,
-	0x97, 0x0,
-	0xa0, 0x48,
-	0xa1, 0x0,
-	0xb0, 0xb8,
-	0xb1, 0x3a,
-	0xb2, 0x10,
-	0xb3, 0x82,
-	0xb4, 0x80,
-	0xb5, 0x82,
-	0xb6, 0x82,
-	0xb7, 0x82,
-	0xb8, 0x20,
-	0xb9, 0x0,
-	0xf0, 0x0,
-	0xf1, 0x0,
-	0xf2, 0xc0,
-	0xff, 0xff,
-};
-
-static struct stv0288_config stv0288_bsbe1_d01a_config = {
-	.demod_address = 0x68,
-	.min_delay_ms = 100,
-	.inittab = stv0288_bsbe1_d01a_inittab,
-};
-
-#endif
diff --git a/drivers/media/dvb/frontends/bsbe1.h b/drivers/media/dvb/frontends/bsbe1.h
deleted file mode 100644
index 53e4d0d..0000000
--- a/drivers/media/dvb/frontends/bsbe1.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * bsbe1.h - ALPS BSBE1 tuner support
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org
- */
-
-#ifndef BSBE1_H
-#define BSBE1_H
-
-static u8 alps_bsbe1_inittab[] = {
-	0x01, 0x15,   /* XTAL = 4MHz, VCO = 352 MHz */
-	0x02, 0x30,   /* MCLK = 88 MHz */
-	0x03, 0x00,   /* ACR output 0 */
-	0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-	0x05, 0x05,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
-	0x06, 0x00,   /* DAC output 0 */
-	0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
-	0x09, 0x00,   /* FIFO */
-	0x0c, 0x51,   /* OP1/OP0 normal, val = 1 (LNB power on) */
-	0x0d, 0x82,   /* DC offset compensation = on, beta_agc1 = 2 */
-	0x0f, 0x92,   /* AGC1R */
-	0x10, 0x34,   /* AGC2O */
-	0x11, 0x84,   /* TLSR */
-	0x12, 0xb9,   /* CFD */
-	0x15, 0xc9,   /* lock detector threshold */
-	0x28, 0x00,   /* out imp: normal, type: parallel, FEC mode: QPSK */
-	0x33, 0xfc,   /* RS control */
-	0x34, 0x93,   /* count viterbi bit errors per 2E18 bytes */
-	0xff, 0xff
-};
-
-
-static int alps_bsbe1_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
-{
-	u8 aclk = 0;
-	u8 bclk = 0;
-
-	if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
-	else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
-	else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
-	else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
-	else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
-	else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
-
-	stv0299_writereg(fe, 0x13, aclk);
-	stv0299_writereg(fe, 0x14, bclk);
-	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
-	stv0299_writereg(fe, 0x20, (ratio >>  8) & 0xff);
-	stv0299_writereg(fe, 0x21, (ratio      ) & 0xf0);
-
-	return 0;
-}
-
-static int alps_bsbe1_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	int ret;
-	u8 data[4];
-	u32 div;
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-	struct i2c_adapter *i2c = fe->tuner_priv;
-
-	if ((p->frequency < 950000) || (p->frequency > 2150000))
-		return -EINVAL;
-
-	div = p->frequency / 1000;
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0x80 | ((div & 0x18000) >> 10) | 0x1;
-	data[3] = 0xe0;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	ret = i2c_transfer(i2c, &msg, 1);
-	return (ret != 1) ? -EIO : 0;
-}
-
-static struct stv0299_config alps_bsbe1_config = {
-	.demod_address = 0x68,
-	.inittab = alps_bsbe1_inittab,
-	.mclk = 88000000UL,
-	.invert = 1,
-	.skip_reinit = 0,
-	.min_delay_ms = 100,
-	.set_symbol_rate = alps_bsbe1_set_symbol_rate,
-};
-
-#endif
diff --git a/drivers/media/dvb/frontends/bsru6.h b/drivers/media/dvb/frontends/bsru6.h
deleted file mode 100644
index c2a578e..0000000
--- a/drivers/media/dvb/frontends/bsru6.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * bsru6.h - ALPS BSRU6 tuner support (moved from budget-ci.c)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org
- */
-
-#ifndef BSRU6_H
-#define BSRU6_H
-
-static u8 alps_bsru6_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x30,
-	0x03, 0x00,
-	0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-	0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
-	0x06, 0x40,   /* DAC not used, set to high impendance mode */
-	0x07, 0x00,   /* DAC LSB */
-	0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
-	0x09, 0x00,   /* FIFO */
-	0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
-	0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
-	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
-	0x10, 0x3f,   // AGC2  0x3d
-	0x11, 0x84,
-	0x12, 0xb9,
-	0x15, 0xc9,   // lock detector threshold
-	0x16, 0x00,
-	0x17, 0x00,
-	0x18, 0x00,
-	0x19, 0x00,
-	0x1a, 0x00,
-	0x1f, 0x50,
-	0x20, 0x00,
-	0x21, 0x00,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
-	0x29, 0x1e,  // 1/2 threshold
-	0x2a, 0x14,  // 2/3 threshold
-	0x2b, 0x0f,  // 3/4 threshold
-	0x2c, 0x09,  // 5/6 threshold
-	0x2d, 0x05,  // 7/8 threshold
-	0x2e, 0x01,
-	0x31, 0x1f,  // test all FECs
-	0x32, 0x19,  // viterbi and synchro search
-	0x33, 0xfc,  // rs control
-	0x34, 0x93,  // error control
-	0x0f, 0x52,
-	0xff, 0xff
-};
-
-static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
-{
-	u8 aclk = 0;
-	u8 bclk = 0;
-
-	if (srate < 1500000) {
-		aclk = 0xb7;
-		bclk = 0x47;
-	} else if (srate < 3000000) {
-		aclk = 0xb7;
-		bclk = 0x4b;
-	} else if (srate < 7000000) {
-		aclk = 0xb7;
-		bclk = 0x4f;
-	} else if (srate < 14000000) {
-		aclk = 0xb7;
-		bclk = 0x53;
-	} else if (srate < 30000000) {
-		aclk = 0xb6;
-		bclk = 0x53;
-	} else if (srate < 45000000) {
-		aclk = 0xb4;
-		bclk = 0x51;
-	}
-
-	stv0299_writereg(fe, 0x13, aclk);
-	stv0299_writereg(fe, 0x14, bclk);
-	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
-	stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
-	stv0299_writereg(fe, 0x21, ratio & 0xf0);
-
-	return 0;
-}
-
-static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	u8 buf[4];
-	u32 div;
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-	struct i2c_adapter *i2c = fe->tuner_priv;
-
-	if ((p->frequency < 950000) || (p->frequency > 2150000))
-		return -EINVAL;
-
-	div = (p->frequency + (125 - 1)) / 125;	/* round correctly */
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = div & 0xff;
-	buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
-	buf[3] = 0xC4;
-
-	if (p->frequency > 1530000)
-		buf[3] = 0xc0;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(i2c, &msg, 1) != 1)
-		return -EIO;
-	return 0;
-}
-
-static struct stv0299_config alps_bsru6_config = {
-	.demod_address = 0x68,
-	.inittab = alps_bsru6_inittab,
-	.mclk = 88000000UL,
-	.invert = 1,
-	.skip_reinit = 0,
-	.lock_output = STV0299_LOCKOUTPUT_1,
-	.volt13_op0_op1 = STV0299_VOLT13_OP1,
-	.min_delay_ms = 100,
-	.set_symbol_rate = alps_bsru6_set_symbol_rate,
-};
-
-#endif
diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c
deleted file mode 100644
index f2a90f9..0000000
--- a/drivers/media/dvb/frontends/cx22700.c
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
-    Conexant cx22700 DVB OFDM demodulator driver
-
-    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
-	Holger Waechtler <holger@convergence.de>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include "dvb_frontend.h"
-#include "cx22700.h"
-
-
-struct cx22700_state {
-
-	struct i2c_adapter* i2c;
-
-	const struct cx22700_config* config;
-
-	struct dvb_frontend frontend;
-};
-
-
-static int debug;
-#define dprintk(args...) \
-	do { \
-		if (debug) printk(KERN_DEBUG "cx22700: " args); \
-	} while (0)
-
-static u8 init_tab [] = {
-	0x04, 0x10,
-	0x05, 0x09,
-	0x06, 0x00,
-	0x08, 0x04,
-	0x09, 0x00,
-	0x0a, 0x01,
-	0x15, 0x40,
-	0x16, 0x10,
-	0x17, 0x87,
-	0x18, 0x17,
-	0x1a, 0x10,
-	0x25, 0x04,
-	0x2e, 0x00,
-	0x39, 0x00,
-	0x3a, 0x04,
-	0x45, 0x08,
-	0x46, 0x02,
-	0x47, 0x05,
-};
-
-
-static int cx22700_writereg (struct cx22700_state* state, u8 reg, u8 data)
-{
-	int ret;
-	u8 buf [] = { reg, data };
-	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
-
-	dprintk ("%s\n", __func__);
-
-	ret = i2c_transfer (state->i2c, &msg, 1);
-
-	if (ret != 1)
-		printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
-			__func__, reg, data, ret);
-
-	return (ret != 1) ? -1 : 0;
-}
-
-static int cx22700_readreg (struct cx22700_state* state, u8 reg)
-{
-	int ret;
-	u8 b0 [] = { reg };
-	u8 b1 [] = { 0 };
-	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
-			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-
-	dprintk ("%s\n", __func__);
-
-	ret = i2c_transfer (state->i2c, msg, 2);
-
-	if (ret != 2) return -EIO;
-
-	return b1[0];
-}
-
-static int cx22700_set_inversion (struct cx22700_state* state, int inversion)
-{
-	u8 val;
-
-	dprintk ("%s\n", __func__);
-
-	switch (inversion) {
-	case INVERSION_AUTO:
-		return -EOPNOTSUPP;
-	case INVERSION_ON:
-		val = cx22700_readreg (state, 0x09);
-		return cx22700_writereg (state, 0x09, val | 0x01);
-	case INVERSION_OFF:
-		val = cx22700_readreg (state, 0x09);
-		return cx22700_writereg (state, 0x09, val & 0xfe);
-	default:
-		return -EINVAL;
-	}
-}
-
-static int cx22700_set_tps(struct cx22700_state *state,
-			   struct dtv_frontend_properties *p)
-{
-	static const u8 qam_tab [4] = { 0, 1, 0, 2 };
-	static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 };
-	u8 val;
-
-	dprintk ("%s\n", __func__);
-
-	if (p->code_rate_HP < FEC_1_2 || p->code_rate_HP > FEC_7_8)
-		return -EINVAL;
-
-	if (p->code_rate_LP < FEC_1_2 || p->code_rate_LP > FEC_7_8)
-		return -EINVAL;
-
-	if (p->code_rate_HP == FEC_4_5 || p->code_rate_LP == FEC_4_5)
-		return -EINVAL;
-
-	if (p->guard_interval < GUARD_INTERVAL_1_32 ||
-	    p->guard_interval > GUARD_INTERVAL_1_4)
-		return -EINVAL;
-
-	if (p->transmission_mode != TRANSMISSION_MODE_2K &&
-	    p->transmission_mode != TRANSMISSION_MODE_8K)
-		return -EINVAL;
-
-	if (p->modulation != QPSK &&
-	    p->modulation != QAM_16 &&
-	    p->modulation != QAM_64)
-		return -EINVAL;
-
-	if (p->hierarchy < HIERARCHY_NONE ||
-	    p->hierarchy > HIERARCHY_4)
-		return -EINVAL;
-
-	if (p->bandwidth_hz > 8000000 || p->bandwidth_hz < 6000000)
-		return -EINVAL;
-
-	if (p->bandwidth_hz == 7000000)
-		cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 | 0x10));
-	else
-		cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 & ~0x10));
-
-	val = qam_tab[p->modulation - QPSK];
-	val |= p->hierarchy - HIERARCHY_NONE;
-
-	cx22700_writereg (state, 0x04, val);
-
-	val = fec_tab[p->code_rate_HP - FEC_1_2] << 3;
-	val |= fec_tab[p->code_rate_LP - FEC_1_2];
-
-	cx22700_writereg (state, 0x05, val);
-
-	val = (p->guard_interval - GUARD_INTERVAL_1_32) << 2;
-	val |= p->transmission_mode - TRANSMISSION_MODE_2K;
-
-	cx22700_writereg (state, 0x06, val);
-
-	cx22700_writereg (state, 0x08, 0x04 | 0x02);  /* use user tps parameters */
-	cx22700_writereg (state, 0x08, 0x04);         /* restart acquisition */
-
-	return 0;
-}
-
-static int cx22700_get_tps(struct cx22700_state *state,
-			   struct dtv_frontend_properties *p)
-{
-	static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 };
-	static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4,
-						    FEC_5_6, FEC_7_8 };
-	u8 val;
-
-	dprintk ("%s\n", __func__);
-
-	if (!(cx22700_readreg(state, 0x07) & 0x20))  /*  tps valid? */
-		return -EAGAIN;
-
-	val = cx22700_readreg (state, 0x01);
-
-	if ((val & 0x7) > 4)
-		p->hierarchy = HIERARCHY_AUTO;
-	else
-		p->hierarchy = HIERARCHY_NONE + (val & 0x7);
-
-	if (((val >> 3) & 0x3) > 2)
-		p->modulation = QAM_AUTO;
-	else
-		p->modulation = qam_tab[(val >> 3) & 0x3];
-
-	val = cx22700_readreg (state, 0x02);
-
-	if (((val >> 3) & 0x07) > 4)
-		p->code_rate_HP = FEC_AUTO;
-	else
-		p->code_rate_HP = fec_tab[(val >> 3) & 0x07];
-
-	if ((val & 0x07) > 4)
-		p->code_rate_LP = FEC_AUTO;
-	else
-		p->code_rate_LP = fec_tab[val & 0x07];
-
-	val = cx22700_readreg (state, 0x03);
-
-	p->guard_interval = GUARD_INTERVAL_1_32 + ((val >> 6) & 0x3);
-	p->transmission_mode = TRANSMISSION_MODE_2K + ((val >> 5) & 0x1);
-
-	return 0;
-}
-
-static int cx22700_init (struct dvb_frontend* fe)
-
-{	struct cx22700_state* state = fe->demodulator_priv;
-	int i;
-
-	dprintk("cx22700_init: init chip\n");
-
-	cx22700_writereg (state, 0x00, 0x02);   /*  soft reset */
-	cx22700_writereg (state, 0x00, 0x00);
-
-	msleep(10);
-
-	for (i=0; i<sizeof(init_tab); i+=2)
-		cx22700_writereg (state, init_tab[i], init_tab[i+1]);
-
-	cx22700_writereg (state, 0x00, 0x01);
-
-	return 0;
-}
-
-static int cx22700_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct cx22700_state* state = fe->demodulator_priv;
-
-	u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
-		   | (cx22700_readreg (state, 0x0e) << 1);
-	u8 sync = cx22700_readreg (state, 0x07);
-
-	*status = 0;
-
-	if (rs_ber < 0xff00)
-		*status |= FE_HAS_SIGNAL;
-
-	if (sync & 0x20)
-		*status |= FE_HAS_CARRIER;
-
-	if (sync & 0x10)
-		*status |= FE_HAS_VITERBI;
-
-	if (sync & 0x10)
-		*status |= FE_HAS_SYNC;
-
-	if (*status == 0x0f)
-		*status |= FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int cx22700_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	struct cx22700_state* state = fe->demodulator_priv;
-
-	*ber = cx22700_readreg (state, 0x0c) & 0x7f;
-	cx22700_writereg (state, 0x0c, 0x00);
-
-	return 0;
-}
-
-static int cx22700_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
-{
-	struct cx22700_state* state = fe->demodulator_priv;
-
-	u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
-		   | (cx22700_readreg (state, 0x0e) << 1);
-	*signal_strength = ~rs_ber;
-
-	return 0;
-}
-
-static int cx22700_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct cx22700_state* state = fe->demodulator_priv;
-
-	u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
-		   | (cx22700_readreg (state, 0x0e) << 1);
-	*snr = ~rs_ber;
-
-	return 0;
-}
-
-static int cx22700_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	struct cx22700_state* state = fe->demodulator_priv;
-
-	*ucblocks = cx22700_readreg (state, 0x0f);
-	cx22700_writereg (state, 0x0f, 0x00);
-
-	return 0;
-}
-
-static int cx22700_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct cx22700_state* state = fe->demodulator_priv;
-
-	cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/
-	cx22700_writereg (state, 0x00, 0x00);
-
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	cx22700_set_inversion(state, c->inversion);
-	cx22700_set_tps(state, c);
-	cx22700_writereg (state, 0x37, 0x01);  /* PAL loop filter off */
-	cx22700_writereg (state, 0x00, 0x01);  /* restart acquire */
-
-	return 0;
-}
-
-static int cx22700_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct cx22700_state* state = fe->demodulator_priv;
-	u8 reg09 = cx22700_readreg (state, 0x09);
-
-	c->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF;
-	return cx22700_get_tps(state, c);
-}
-
-static int cx22700_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
-{
-	struct cx22700_state* state = fe->demodulator_priv;
-
-	if (enable) {
-		return cx22700_writereg(state, 0x0a, 0x00);
-	} else {
-		return cx22700_writereg(state, 0x0a, 0x01);
-	}
-}
-
-static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
-{
-	fesettings->min_delay_ms = 150;
-	fesettings->step_size = 166667;
-	fesettings->max_drift = 166667*2;
-	return 0;
-}
-
-static void cx22700_release(struct dvb_frontend* fe)
-{
-	struct cx22700_state* state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops cx22700_ops;
-
-struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
-				    struct i2c_adapter* i2c)
-{
-	struct cx22700_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct cx22700_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-
-	/* check if the demod is there */
-	if (cx22700_readreg(state, 0x07) < 0) goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops cx22700_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name			= "Conexant CX22700 DVB-T",
-		.frequency_min		= 470000000,
-		.frequency_max		= 860000000,
-		.frequency_stepsize	= 166667,
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-		      FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
-		      FE_CAN_RECOVER
-	},
-
-	.release = cx22700_release,
-
-	.init = cx22700_init,
-	.i2c_gate_ctrl = cx22700_i2c_gate_ctrl,
-
-	.set_frontend = cx22700_set_frontend,
-	.get_frontend = cx22700_get_frontend,
-	.get_tune_settings = cx22700_get_tune_settings,
-
-	.read_status = cx22700_read_status,
-	.read_ber = cx22700_read_ber,
-	.read_signal_strength = cx22700_read_signal_strength,
-	.read_snr = cx22700_read_snr,
-	.read_ucblocks = cx22700_read_ucblocks,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("Conexant CX22700 DVB-T Demodulator driver");
-MODULE_AUTHOR("Holger Waechtler");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(cx22700_attach);
diff --git a/drivers/media/dvb/frontends/cx22700.h b/drivers/media/dvb/frontends/cx22700.h
deleted file mode 100644
index 4757a93..0000000
--- a/drivers/media/dvb/frontends/cx22700.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-    Conexant CX22700 DVB OFDM demodulator driver
-
-    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
-	Holger Waechtler <holger@convergence.de>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef CX22700_H
-#define CX22700_H
-
-#include <linux/dvb/frontend.h>
-
-struct cx22700_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-};
-
-#if defined(CONFIG_DVB_CX22700) || (defined(CONFIG_DVB_CX22700_MODULE) && defined(MODULE))
-extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
-					   struct i2c_adapter* i2c);
-#else
-static inline struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
-					   struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_CX22700
-
-#endif // CX22700_H
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
deleted file mode 100644
index edc8eaf..0000000
--- a/drivers/media/dvb/frontends/cx22702.c
+++ /dev/null
@@ -1,653 +0,0 @@
-/*
-    Conexant 22702 DVB OFDM demodulator driver
-
-    based on:
-	Alps TDMB7 DVB OFDM demodulator driver
-
-    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
-	  Holger Waechtler <holger@convergence.de>
-
-    Copyright (C) 2004 Steven Toth <stoth@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include "dvb_frontend.h"
-#include "cx22702.h"
-
-struct cx22702_state {
-
-	struct i2c_adapter *i2c;
-
-	/* configuration settings */
-	const struct cx22702_config *config;
-
-	struct dvb_frontend frontend;
-
-	/* previous uncorrected block counter */
-	u8 prevUCBlocks;
-};
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Enable verbose debug messages");
-
-#define dprintk	if (debug) printk
-
-/* Register values to initialise the demod */
-static const u8 init_tab[] = {
-	0x00, 0x00, /* Stop acquisition */
-	0x0B, 0x06,
-	0x09, 0x01,
-	0x0D, 0x41,
-	0x16, 0x32,
-	0x20, 0x0A,
-	0x21, 0x17,
-	0x24, 0x3e,
-	0x26, 0xff,
-	0x27, 0x10,
-	0x28, 0x00,
-	0x29, 0x00,
-	0x2a, 0x10,
-	0x2b, 0x00,
-	0x2c, 0x10,
-	0x2d, 0x00,
-	0x48, 0xd4,
-	0x49, 0x56,
-	0x6b, 0x1e,
-	0xc8, 0x02,
-	0xf9, 0x00,
-	0xfa, 0x00,
-	0xfb, 0x00,
-	0xfc, 0x00,
-	0xfd, 0x00,
-};
-
-static int cx22702_writereg(struct cx22702_state *state, u8 reg, u8 data)
-{
-	int ret;
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = {
-		.addr = state->config->demod_address, .flags = 0,
-			.buf = buf, .len = 2 };
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-
-	if (unlikely(ret != 1)) {
-		printk(KERN_ERR
-			"%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
-			__func__, reg, data, ret);
-		return -1;
-	}
-
-	return 0;
-}
-
-static u8 cx22702_readreg(struct cx22702_state *state, u8 reg)
-{
-	int ret;
-	u8 data;
-
-	struct i2c_msg msg[] = {
-		{ .addr = state->config->demod_address, .flags = 0,
-			.buf = &reg, .len = 1 },
-		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
-			.buf = &data, .len = 1 } };
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (unlikely(ret != 2)) {
-		printk(KERN_ERR "%s: error (reg == 0x%02x, ret == %i)\n",
-			__func__, reg, ret);
-		return 0;
-	}
-
-	return data;
-}
-
-static int cx22702_set_inversion(struct cx22702_state *state, int inversion)
-{
-	u8 val;
-
-	val = cx22702_readreg(state, 0x0C);
-	switch (inversion) {
-	case INVERSION_AUTO:
-		return -EOPNOTSUPP;
-	case INVERSION_ON:
-		val |= 0x01;
-		break;
-	case INVERSION_OFF:
-		val &= 0xfe;
-		break;
-	default:
-		return -EINVAL;
-	}
-	return cx22702_writereg(state, 0x0C, val);
-}
-
-/* Retrieve the demod settings */
-static int cx22702_get_tps(struct cx22702_state *state,
-			   struct dtv_frontend_properties *p)
-{
-	u8 val;
-
-	/* Make sure the TPS regs are valid */
-	if (!(cx22702_readreg(state, 0x0A) & 0x20))
-		return -EAGAIN;
-
-	val = cx22702_readreg(state, 0x01);
-	switch ((val & 0x18) >> 3) {
-	case 0:
-		p->modulation = QPSK;
-		break;
-	case 1:
-		p->modulation = QAM_16;
-		break;
-	case 2:
-		p->modulation = QAM_64;
-		break;
-	}
-	switch (val & 0x07) {
-	case 0:
-		p->hierarchy = HIERARCHY_NONE;
-		break;
-	case 1:
-		p->hierarchy = HIERARCHY_1;
-		break;
-	case 2:
-		p->hierarchy = HIERARCHY_2;
-		break;
-	case 3:
-		p->hierarchy = HIERARCHY_4;
-		break;
-	}
-
-
-	val = cx22702_readreg(state, 0x02);
-	switch ((val & 0x38) >> 3) {
-	case 0:
-		p->code_rate_HP = FEC_1_2;
-		break;
-	case 1:
-		p->code_rate_HP = FEC_2_3;
-		break;
-	case 2:
-		p->code_rate_HP = FEC_3_4;
-		break;
-	case 3:
-		p->code_rate_HP = FEC_5_6;
-		break;
-	case 4:
-		p->code_rate_HP = FEC_7_8;
-		break;
-	}
-	switch (val & 0x07) {
-	case 0:
-		p->code_rate_LP = FEC_1_2;
-		break;
-	case 1:
-		p->code_rate_LP = FEC_2_3;
-		break;
-	case 2:
-		p->code_rate_LP = FEC_3_4;
-		break;
-	case 3:
-		p->code_rate_LP = FEC_5_6;
-		break;
-	case 4:
-		p->code_rate_LP = FEC_7_8;
-		break;
-	}
-
-	val = cx22702_readreg(state, 0x03);
-	switch ((val & 0x0c) >> 2) {
-	case 0:
-		p->guard_interval = GUARD_INTERVAL_1_32;
-		break;
-	case 1:
-		p->guard_interval = GUARD_INTERVAL_1_16;
-		break;
-	case 2:
-		p->guard_interval = GUARD_INTERVAL_1_8;
-		break;
-	case 3:
-		p->guard_interval = GUARD_INTERVAL_1_4;
-		break;
-	}
-	switch (val & 0x03) {
-	case 0:
-		p->transmission_mode = TRANSMISSION_MODE_2K;
-		break;
-	case 1:
-		p->transmission_mode = TRANSMISSION_MODE_8K;
-		break;
-	}
-
-	return 0;
-}
-
-static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct cx22702_state *state = fe->demodulator_priv;
-	u8 val;
-
-	dprintk("%s(%d)\n", __func__, enable);
-	val = cx22702_readreg(state, 0x0D);
-	if (enable)
-		val &= 0xfe;
-	else
-		val |= 0x01;
-	return cx22702_writereg(state, 0x0D, val);
-}
-
-/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int cx22702_set_tps(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	u8 val;
-	struct cx22702_state *state = fe->demodulator_priv;
-
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	/* set inversion */
-	cx22702_set_inversion(state, p->inversion);
-
-	/* set bandwidth */
-	val = cx22702_readreg(state, 0x0C) & 0xcf;
-	switch (p->bandwidth_hz) {
-	case 6000000:
-		val |= 0x20;
-		break;
-	case 7000000:
-		val |= 0x10;
-		break;
-	case 8000000:
-		break;
-	default:
-		dprintk("%s: invalid bandwidth\n", __func__);
-		return -EINVAL;
-	}
-	cx22702_writereg(state, 0x0C, val);
-
-	p->code_rate_LP = FEC_AUTO; /* temp hack as manual not working */
-
-	/* use auto configuration? */
-	if ((p->hierarchy == HIERARCHY_AUTO) ||
-	   (p->modulation == QAM_AUTO) ||
-	   (p->code_rate_HP == FEC_AUTO) ||
-	   (p->code_rate_LP == FEC_AUTO) ||
-	   (p->guard_interval == GUARD_INTERVAL_AUTO) ||
-	   (p->transmission_mode == TRANSMISSION_MODE_AUTO)) {
-
-		/* TPS Source - use hardware driven values */
-		cx22702_writereg(state, 0x06, 0x10);
-		cx22702_writereg(state, 0x07, 0x9);
-		cx22702_writereg(state, 0x08, 0xC1);
-		cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B)
-			& 0xfc);
-		cx22702_writereg(state, 0x0C,
-			(cx22702_readreg(state, 0x0C) & 0xBF) | 0x40);
-		cx22702_writereg(state, 0x00, 0x01); /* Begin acquisition */
-		dprintk("%s: Autodetecting\n", __func__);
-		return 0;
-	}
-
-	/* manually programmed values */
-	switch (p->modulation) {		/* mask 0x18 */
-	case QPSK:
-		val = 0x00;
-		break;
-	case QAM_16:
-		val = 0x08;
-		break;
-	case QAM_64:
-		val = 0x10;
-		break;
-	default:
-		dprintk("%s: invalid modulation\n", __func__);
-		return -EINVAL;
-	}
-	switch (p->hierarchy) {	/* mask 0x07 */
-	case HIERARCHY_NONE:
-		break;
-	case HIERARCHY_1:
-		val |= 0x01;
-		break;
-	case HIERARCHY_2:
-		val |= 0x02;
-		break;
-	case HIERARCHY_4:
-		val |= 0x03;
-		break;
-	default:
-		dprintk("%s: invalid hierarchy\n", __func__);
-		return -EINVAL;
-	}
-	cx22702_writereg(state, 0x06, val);
-
-	switch (p->code_rate_HP) {		/* mask 0x38 */
-	case FEC_NONE:
-	case FEC_1_2:
-		val = 0x00;
-		break;
-	case FEC_2_3:
-		val = 0x08;
-		break;
-	case FEC_3_4:
-		val = 0x10;
-		break;
-	case FEC_5_6:
-		val = 0x18;
-		break;
-	case FEC_7_8:
-		val = 0x20;
-		break;
-	default:
-		dprintk("%s: invalid code_rate_HP\n", __func__);
-		return -EINVAL;
-	}
-	switch (p->code_rate_LP) {		/* mask 0x07 */
-	case FEC_NONE:
-	case FEC_1_2:
-		break;
-	case FEC_2_3:
-		val |= 0x01;
-		break;
-	case FEC_3_4:
-		val |= 0x02;
-		break;
-	case FEC_5_6:
-		val |= 0x03;
-		break;
-	case FEC_7_8:
-		val |= 0x04;
-		break;
-	default:
-		dprintk("%s: invalid code_rate_LP\n", __func__);
-		return -EINVAL;
-	}
-	cx22702_writereg(state, 0x07, val);
-
-	switch (p->guard_interval) {		/* mask 0x0c */
-	case GUARD_INTERVAL_1_32:
-		val = 0x00;
-		break;
-	case GUARD_INTERVAL_1_16:
-		val = 0x04;
-		break;
-	case GUARD_INTERVAL_1_8:
-		val = 0x08;
-		break;
-	case GUARD_INTERVAL_1_4:
-		val = 0x0c;
-		break;
-	default:
-		dprintk("%s: invalid guard_interval\n", __func__);
-		return -EINVAL;
-	}
-	switch (p->transmission_mode) {		/* mask 0x03 */
-	case TRANSMISSION_MODE_2K:
-		break;
-	case TRANSMISSION_MODE_8K:
-		val |= 0x1;
-		break;
-	default:
-		dprintk("%s: invalid transmission_mode\n", __func__);
-		return -EINVAL;
-	}
-	cx22702_writereg(state, 0x08, val);
-	cx22702_writereg(state, 0x0B,
-		(cx22702_readreg(state, 0x0B) & 0xfc) | 0x02);
-	cx22702_writereg(state, 0x0C,
-		(cx22702_readreg(state, 0x0C) & 0xBF) | 0x40);
-
-	/* Begin channel acquisition */
-	cx22702_writereg(state, 0x00, 0x01);
-
-	return 0;
-}
-
-/* Reset the demod hardware and reset all of the configuration registers
-   to a default state. */
-static int cx22702_init(struct dvb_frontend *fe)
-{
-	int i;
-	struct cx22702_state *state = fe->demodulator_priv;
-
-	cx22702_writereg(state, 0x00, 0x02);
-
-	msleep(10);
-
-	for (i = 0; i < ARRAY_SIZE(init_tab); i += 2)
-		cx22702_writereg(state, init_tab[i], init_tab[i + 1]);
-
-	cx22702_writereg(state, 0xf8, (state->config->output_mode << 1)
-		& 0x02);
-
-	cx22702_i2c_gate_ctrl(fe, 0);
-
-	return 0;
-}
-
-static int cx22702_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct cx22702_state *state = fe->demodulator_priv;
-	u8 reg0A;
-	u8 reg23;
-
-	*status = 0;
-
-	reg0A = cx22702_readreg(state, 0x0A);
-	reg23 = cx22702_readreg(state, 0x23);
-
-	dprintk("%s: status demod=0x%02x agc=0x%02x\n"
-		, __func__, reg0A, reg23);
-
-	if (reg0A & 0x10) {
-		*status |= FE_HAS_LOCK;
-		*status |= FE_HAS_VITERBI;
-		*status |= FE_HAS_SYNC;
-	}
-
-	if (reg0A & 0x20)
-		*status |= FE_HAS_CARRIER;
-
-	if (reg23 < 0xf0)
-		*status |= FE_HAS_SIGNAL;
-
-	return 0;
-}
-
-static int cx22702_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct cx22702_state *state = fe->demodulator_priv;
-
-	if (cx22702_readreg(state, 0xE4) & 0x02) {
-		/* Realtime statistics */
-		*ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
-			| (cx22702_readreg(state, 0xDF) & 0x7F);
-	} else {
-		/* Averagtine statistics */
-		*ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
-			| cx22702_readreg(state, 0xDF);
-	}
-
-	return 0;
-}
-
-static int cx22702_read_signal_strength(struct dvb_frontend *fe,
-	u16 *signal_strength)
-{
-	struct cx22702_state *state = fe->demodulator_priv;
-	u8 reg23;
-
-	/*
-	 * Experience suggests that the strength signal register works as
-	 * follows:
-	 * - In the absence of signal, value is 0xff.
-	 * - In the presence of a weak signal, bit 7 is set, not sure what
-	 *   the lower 7 bits mean.
-	 * - In the presence of a strong signal, the register holds a 7-bit
-	 *   value (bit 7 is cleared), with greater values standing for
-	 *   weaker signals.
-	 */
-	reg23 = cx22702_readreg(state, 0x23);
-	if (reg23 & 0x80) {
-		*signal_strength = 0;
-	} else {
-		reg23 = ~reg23 & 0x7f;
-		/* Scale to 16 bit */
-		*signal_strength = (reg23 << 9) | (reg23 << 2) | (reg23 >> 5);
-	}
-
-	return 0;
-}
-
-static int cx22702_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct cx22702_state *state = fe->demodulator_priv;
-
-	u16 rs_ber;
-	if (cx22702_readreg(state, 0xE4) & 0x02) {
-		/* Realtime statistics */
-		rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
-			| (cx22702_readreg(state, 0xDF) & 0x7F);
-	} else {
-		/* Averagine statistics */
-		rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 8
-			| cx22702_readreg(state, 0xDF);
-	}
-	*snr = ~rs_ber;
-
-	return 0;
-}
-
-static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct cx22702_state *state = fe->demodulator_priv;
-
-	u8 _ucblocks;
-
-	/* RS Uncorrectable Packet Count then reset */
-	_ucblocks = cx22702_readreg(state, 0xE3);
-	if (state->prevUCBlocks < _ucblocks)
-		*ucblocks = (_ucblocks - state->prevUCBlocks);
-	else
-		*ucblocks = state->prevUCBlocks - _ucblocks;
-	state->prevUCBlocks = _ucblocks;
-
-	return 0;
-}
-
-static int cx22702_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct cx22702_state *state = fe->demodulator_priv;
-
-	u8 reg0C = cx22702_readreg(state, 0x0C);
-
-	c->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
-	return cx22702_get_tps(state, c);
-}
-
-static int cx22702_get_tune_settings(struct dvb_frontend *fe,
-	struct dvb_frontend_tune_settings *tune)
-{
-	tune->min_delay_ms = 1000;
-	return 0;
-}
-
-static void cx22702_release(struct dvb_frontend *fe)
-{
-	struct cx22702_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static const struct dvb_frontend_ops cx22702_ops;
-
-struct dvb_frontend *cx22702_attach(const struct cx22702_config *config,
-	struct i2c_adapter *i2c)
-{
-	struct cx22702_state *state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct cx22702_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-
-	/* check if the demod is there */
-	if (cx22702_readreg(state, 0x1f) != 0x3)
-		goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &cx22702_ops,
-		sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(cx22702_attach);
-
-static const struct dvb_frontend_ops cx22702_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name			= "Conexant CX22702 DVB-T",
-		.frequency_min		= 177000000,
-		.frequency_max		= 858000000,
-		.frequency_stepsize	= 166666,
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-		FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-		FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-		FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
-	},
-
-	.release = cx22702_release,
-
-	.init = cx22702_init,
-	.i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
-
-	.set_frontend = cx22702_set_tps,
-	.get_frontend = cx22702_get_frontend,
-	.get_tune_settings = cx22702_get_tune_settings,
-
-	.read_status = cx22702_read_status,
-	.read_ber = cx22702_read_ber,
-	.read_signal_strength = cx22702_read_signal_strength,
-	.read_snr = cx22702_read_snr,
-	.read_ucblocks = cx22702_read_ucblocks,
-};
-
-MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver");
-MODULE_AUTHOR("Steven Toth");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
deleted file mode 100644
index f154e1f..0000000
--- a/drivers/media/dvb/frontends/cx22702.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-    Conexant 22702 DVB OFDM demodulator driver
-
-    based on:
-	Alps TDMB7 DVB OFDM demodulator driver
-
-    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
-	  Holger Waechtler <holger@convergence.de>
-
-    Copyright (C) 2004 Steven Toth <stoth@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef CX22702_H
-#define CX22702_H
-
-#include <linux/dvb/frontend.h>
-
-struct cx22702_config {
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* serial/parallel output */
-#define CX22702_PARALLEL_OUTPUT 0
-#define CX22702_SERIAL_OUTPUT   1
-	u8 output_mode;
-};
-
-#if defined(CONFIG_DVB_CX22702) || (defined(CONFIG_DVB_CX22702_MODULE) \
-	&& defined(MODULE))
-extern struct dvb_frontend *cx22702_attach(
-	const struct cx22702_config *config,
-	struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *cx22702_attach(
-	const struct cx22702_config *config,
-	struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
deleted file mode 100644
index 3180f5b..0000000
--- a/drivers/media/dvb/frontends/cx24110.c
+++ /dev/null
@@ -1,666 +0,0 @@
-/*
-    cx24110 - Single Chip Satellite Channel Receiver driver module
-
-    Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> based on
-    work
-    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include "dvb_frontend.h"
-#include "cx24110.h"
-
-
-struct cx24110_state {
-
-	struct i2c_adapter* i2c;
-
-	const struct cx24110_config* config;
-
-	struct dvb_frontend frontend;
-
-	u32 lastber;
-	u32 lastbler;
-	u32 lastesn0;
-};
-
-static int debug;
-#define dprintk(args...) \
-	do { \
-		if (debug) printk(KERN_DEBUG "cx24110: " args); \
-	} while (0)
-
-static struct {u8 reg; u8 data;} cx24110_regdata[]=
-		      /* Comments beginning with @ denote this value should
-			 be the default */
-	{{0x09,0x01}, /* SoftResetAll */
-	 {0x09,0x00}, /* release reset */
-	 {0x01,0xe8}, /* MSB of code rate 27.5MS/s */
-	 {0x02,0x17}, /* middle byte " */
-	 {0x03,0x29}, /* LSB         " */
-	 {0x05,0x03}, /* @ DVB mode, standard code rate 3/4 */
-	 {0x06,0xa5}, /* @ PLL 60MHz */
-	 {0x07,0x01}, /* @ Fclk, i.e. sampling clock, 60MHz */
-	 {0x0a,0x00}, /* @ partial chip disables, do not set */
-	 {0x0b,0x01}, /* set output clock in gapped mode, start signal low
-			 active for first byte */
-	 {0x0c,0x11}, /* no parity bytes, large hold time, serial data out */
-	 {0x0d,0x6f}, /* @ RS Sync/Unsync thresholds */
-	 {0x10,0x40}, /* chip doc is misleading here: write bit 6 as 1
-			 to avoid starting the BER counter. Reset the
-			 CRC test bit. Finite counting selected */
-	 {0x15,0xff}, /* @ size of the limited time window for RS BER
-			 estimation. It is <value>*256 RS blocks, this
-			 gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */
-	 {0x16,0x00}, /* @ enable all RS output ports */
-	 {0x17,0x04}, /* @ time window allowed for the RS to sync */
-	 {0x18,0xae}, /* @ allow all standard DVB code rates to be scanned
-			 for automatically */
-		      /* leave the current code rate and normalization
-			 registers as they are after reset... */
-	 {0x21,0x10}, /* @ during AutoAcq, search each viterbi setting
-			 only once */
-	 {0x23,0x18}, /* @ size of the limited time window for Viterbi BER
-			 estimation. It is <value>*65536 channel bits, i.e.
-			 approx. 38ms at 27.5MS/s, rate 3/4 */
-	 {0x24,0x24}, /* do not trigger Viterbi CRC test. Finite count window */
-		      /* leave front-end AGC parameters at default values */
-		      /* leave decimation AGC parameters at default values */
-	 {0x35,0x40}, /* disable all interrupts. They are not connected anyway */
-	 {0x36,0xff}, /* clear all interrupt pending flags */
-	 {0x37,0x00}, /* @ fully enable AutoAcqq state machine */
-	 {0x38,0x07}, /* @ enable fade recovery, but not autostart AutoAcq */
-		      /* leave the equalizer parameters on their default values */
-		      /* leave the final AGC parameters on their default values */
-	 {0x41,0x00}, /* @ MSB of front-end derotator frequency */
-	 {0x42,0x00}, /* @ middle bytes " */
-	 {0x43,0x00}, /* @ LSB          " */
-		      /* leave the carrier tracking loop parameters on default */
-		      /* leave the bit timing loop parameters at default */
-	 {0x56,0x4d}, /* set the filtune voltage to 2.7V, as recommended by */
-		      /* the cx24108 data sheet for symbol rates above 15MS/s */
-	 {0x57,0x00}, /* @ Filter sigma delta enabled, positive */
-	 {0x61,0x95}, /* GPIO pins 1-4 have special function */
-	 {0x62,0x05}, /* GPIO pin 5 has special function, pin 6 is GPIO */
-	 {0x63,0x00}, /* All GPIO pins use CMOS output characteristics */
-	 {0x64,0x20}, /* GPIO 6 is input, all others are outputs */
-	 {0x6d,0x30}, /* tuner auto mode clock freq 62kHz */
-	 {0x70,0x15}, /* use auto mode, tuner word is 21 bits long */
-	 {0x73,0x00}, /* @ disable several demod bypasses */
-	 {0x74,0x00}, /* @  " */
-	 {0x75,0x00}  /* @  " */
-		      /* the remaining registers are for SEC */
-	};
-
-
-static int cx24110_writereg (struct cx24110_state* state, int reg, int data)
-{
-	u8 buf [] = { reg, data };
-	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
-	int err;
-
-	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
-		dprintk ("%s: writereg error (err == %i, reg == 0x%02x,"
-			 " data == 0x%02x)\n", __func__, err, reg, data);
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static int cx24110_readreg (struct cx24110_state* state, u8 reg)
-{
-	int ret;
-	u8 b0 [] = { reg };
-	u8 b1 [] = { 0 };
-	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
-			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2) return ret;
-
-	return b1[0];
-}
-
-static int cx24110_set_inversion (struct cx24110_state* state, fe_spectral_inversion_t inversion)
-{
-/* fixme (low): error handling */
-
-	switch (inversion) {
-	case INVERSION_OFF:
-		cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1);
-		/* AcqSpectrInvDis on. No idea why someone should want this */
-		cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)&0xf7);
-		/* Initial value 0 at start of acq */
-		cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)&0xef);
-		/* current value 0 */
-		/* The cx24110 manual tells us this reg is read-only.
-		   But what the heck... set it ayways */
-		break;
-	case INVERSION_ON:
-		cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1);
-		/* AcqSpectrInvDis on. No idea why someone should want this */
-		cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)|0x08);
-		/* Initial value 1 at start of acq */
-		cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)|0x10);
-		/* current value 1 */
-		break;
-	case INVERSION_AUTO:
-		cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xfe);
-		/* AcqSpectrInvDis off. Leave initial & current states as is */
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int cx24110_set_fec (struct cx24110_state* state, fe_code_rate_t fec)
-{
-/* fixme (low): error handling */
-
-	static const int rate[]={-1,1,2,3,5,7,-1};
-	static const int g1[]={-1,0x01,0x02,0x05,0x15,0x45,-1};
-	static const int g2[]={-1,0x01,0x03,0x06,0x1a,0x7a,-1};
-
-	/* Well, the AutoAcq engine of the cx24106 and 24110 automatically
-	   searches all enabled viterbi rates, and can handle non-standard
-	   rates as well. */
-
-	if (fec>FEC_AUTO)
-		fec=FEC_AUTO;
-
-	if (fec==FEC_AUTO) { /* (re-)establish AutoAcq behaviour */
-		cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xdf);
-		/* clear AcqVitDis bit */
-		cx24110_writereg(state,0x18,0xae);
-		/* allow all DVB standard code rates */
-		cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|0x3);
-		/* set nominal Viterbi rate 3/4 */
-		cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|0x3);
-		/* set current Viterbi rate 3/4 */
-		cx24110_writereg(state,0x1a,0x05); cx24110_writereg(state,0x1b,0x06);
-		/* set the puncture registers for code rate 3/4 */
-		return 0;
-	} else {
-		cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x20);
-		/* set AcqVitDis bit */
-		if(rate[fec]>0) {
-			cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|rate[fec]);
-			/* set nominal Viterbi rate */
-			cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|rate[fec]);
-			/* set current Viterbi rate */
-			cx24110_writereg(state,0x1a,g1[fec]);
-			cx24110_writereg(state,0x1b,g2[fec]);
-			/* not sure if this is the right way: I always used AutoAcq mode */
-	   } else
-		   return -EOPNOTSUPP;
-/* fixme (low): which is the correct return code? */
-	};
-	return 0;
-}
-
-static fe_code_rate_t cx24110_get_fec (struct cx24110_state* state)
-{
-	int i;
-
-	i=cx24110_readreg(state,0x22)&0x0f;
-	if(!(i&0x08)) {
-		return FEC_1_2 + i - 1;
-	} else {
-/* fixme (low): a special code rate has been selected. In theory, we need to
-   return a denominator value, a numerator value, and a pair of puncture
-   maps to correctly describe this mode. But this should never happen in
-   practice, because it cannot be set by cx24110_get_fec. */
-	   return FEC_NONE;
-	}
-}
-
-static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
-{
-/* fixme (low): add error handling */
-	u32 ratio;
-	u32 tmp, fclk, BDRI;
-
-	static const u32 bands[]={5000000UL,15000000UL,90999000UL/2};
-	int i;
-
-	dprintk("cx24110 debug: entering %s(%d)\n",__func__,srate);
-	if (srate>90999000UL/2)
-		srate=90999000UL/2;
-	if (srate<500000)
-		srate=500000;
-
-	for(i = 0; (i < ARRAY_SIZE(bands)) && (srate>bands[i]); i++)
-		;
-	/* first, check which sample rate is appropriate: 45, 60 80 or 90 MHz,
-	   and set the PLL accordingly (R07[1:0] Fclk, R06[7:4] PLLmult,
-	   R06[3:0] PLLphaseDetGain */
-	tmp=cx24110_readreg(state,0x07)&0xfc;
-	if(srate<90999000UL/4) { /* sample rate 45MHz*/
-		cx24110_writereg(state,0x07,tmp);
-		cx24110_writereg(state,0x06,0x78);
-		fclk=90999000UL/2;
-	} else if(srate<60666000UL/2) { /* sample rate 60MHz */
-		cx24110_writereg(state,0x07,tmp|0x1);
-		cx24110_writereg(state,0x06,0xa5);
-		fclk=60666000UL;
-	} else if(srate<80888000UL/2) { /* sample rate 80MHz */
-		cx24110_writereg(state,0x07,tmp|0x2);
-		cx24110_writereg(state,0x06,0x87);
-		fclk=80888000UL;
-	} else { /* sample rate 90MHz */
-		cx24110_writereg(state,0x07,tmp|0x3);
-		cx24110_writereg(state,0x06,0x78);
-		fclk=90999000UL;
-	};
-	dprintk("cx24110 debug: fclk %d Hz\n",fclk);
-	/* we need to divide two integers with approx. 27 bits in 32 bit
-	   arithmetic giving a 25 bit result */
-	/* the maximum dividend is 90999000/2, 0x02b6446c, this number is
-	   also the most complex divisor. Hence, the dividend has,
-	   assuming 32bit unsigned arithmetic, 6 clear bits on top, the
-	   divisor 2 unused bits at the bottom. Also, the quotient is
-	   always less than 1/2. Borrowed from VES1893.c, of course */
-
-	tmp=srate<<6;
-	BDRI=fclk>>2;
-	ratio=(tmp/BDRI);
-
-	tmp=(tmp%BDRI)<<8;
-	ratio=(ratio<<8)+(tmp/BDRI);
-
-	tmp=(tmp%BDRI)<<8;
-	ratio=(ratio<<8)+(tmp/BDRI);
-
-	tmp=(tmp%BDRI)<<1;
-	ratio=(ratio<<1)+(tmp/BDRI);
-
-	dprintk("srate= %d (range %d, up to %d)\n", srate,i,bands[i]);
-	dprintk("fclk = %d\n", fclk);
-	dprintk("ratio= %08x\n", ratio);
-
-	cx24110_writereg(state, 0x1, (ratio>>16)&0xff);
-	cx24110_writereg(state, 0x2, (ratio>>8)&0xff);
-	cx24110_writereg(state, 0x3, (ratio)&0xff);
-
-	return 0;
-
-}
-
-static int _cx24110_pll_write (struct dvb_frontend* fe, const u8 buf[], int len)
-{
-	struct cx24110_state *state = fe->demodulator_priv;
-
-	if (len != 3)
-		return -EINVAL;
-
-/* tuner data is 21 bits long, must be left-aligned in data */
-/* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */
-/* FIXME (low): add error handling, avoid infinite loops if HW fails... */
-
-	cx24110_writereg(state,0x6d,0x30); /* auto mode at 62kHz */
-	cx24110_writereg(state,0x70,0x15); /* auto mode 21 bits */
-
-	/* if the auto tuner writer is still busy, clear it out */
-	while (cx24110_readreg(state,0x6d)&0x80)
-		cx24110_writereg(state,0x72,0);
-
-	/* write the topmost 8 bits */
-	cx24110_writereg(state,0x72,buf[0]);
-
-	/* wait for the send to be completed */
-	while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
-		;
-
-	/* send another 8 bytes */
-	cx24110_writereg(state,0x72,buf[1]);
-	while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
-		;
-
-	/* and the topmost 5 bits of this byte */
-	cx24110_writereg(state,0x72,buf[2]);
-	while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
-		;
-
-	/* now strobe the enable line once */
-	cx24110_writereg(state,0x6d,0x32);
-	cx24110_writereg(state,0x6d,0x30);
-
-	return 0;
-}
-
-static int cx24110_initfe(struct dvb_frontend* fe)
-{
-	struct cx24110_state *state = fe->demodulator_priv;
-/* fixme (low): error handling */
-	int i;
-
-	dprintk("%s: init chip\n", __func__);
-
-	for(i = 0; i < ARRAY_SIZE(cx24110_regdata); i++) {
-		cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
-	};
-
-	return 0;
-}
-
-static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
-	struct cx24110_state *state = fe->demodulator_priv;
-
-	switch (voltage) {
-	case SEC_VOLTAGE_13:
-		return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0xc0);
-	case SEC_VOLTAGE_18:
-		return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0x40);
-	default:
-		return -EINVAL;
-	};
-}
-
-static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
-{
-	int rv, bit;
-	struct cx24110_state *state = fe->demodulator_priv;
-	unsigned long timeout;
-
-	if (burst == SEC_MINI_A)
-		bit = 0x00;
-	else if (burst == SEC_MINI_B)
-		bit = 0x08;
-	else
-		return -EINVAL;
-
-	rv = cx24110_readreg(state, 0x77);
-	if (!(rv & 0x04))
-		cx24110_writereg(state, 0x77, rv | 0x04);
-
-	rv = cx24110_readreg(state, 0x76);
-	cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40 | bit));
-	timeout = jiffies + msecs_to_jiffies(100);
-	while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40))
-		; /* wait for LNB ready */
-
-	return 0;
-}
-
-static int cx24110_send_diseqc_msg(struct dvb_frontend* fe,
-				   struct dvb_diseqc_master_cmd *cmd)
-{
-	int i, rv;
-	struct cx24110_state *state = fe->demodulator_priv;
-	unsigned long timeout;
-
-	if (cmd->msg_len < 3 || cmd->msg_len > 6)
-		return -EINVAL;  /* not implemented */
-
-	for (i = 0; i < cmd->msg_len; i++)
-		cx24110_writereg(state, 0x79 + i, cmd->msg[i]);
-
-	rv = cx24110_readreg(state, 0x77);
-	if (rv & 0x04) {
-		cx24110_writereg(state, 0x77, rv & ~0x04);
-		msleep(30); /* reportedly fixes switching problems */
-	}
-
-	rv = cx24110_readreg(state, 0x76);
-
-	cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3));
-	timeout = jiffies + msecs_to_jiffies(100);
-	while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40))
-		; /* wait for LNB ready */
-
-	return 0;
-}
-
-static int cx24110_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct cx24110_state *state = fe->demodulator_priv;
-
-	int sync = cx24110_readreg (state, 0x55);
-
-	*status = 0;
-
-	if (sync & 0x10)
-		*status |= FE_HAS_SIGNAL;
-
-	if (sync & 0x08)
-		*status |= FE_HAS_CARRIER;
-
-	sync = cx24110_readreg (state, 0x08);
-
-	if (sync & 0x40)
-		*status |= FE_HAS_VITERBI;
-
-	if (sync & 0x20)
-		*status |= FE_HAS_SYNC;
-
-	if ((sync & 0x60) == 0x60)
-		*status |= FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int cx24110_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	struct cx24110_state *state = fe->demodulator_priv;
-
-	/* fixme (maybe): value range is 16 bit. Scale? */
-	if(cx24110_readreg(state,0x24)&0x10) {
-		/* the Viterbi error counter has finished one counting window */
-		cx24110_writereg(state,0x24,0x04); /* select the ber reg */
-		state->lastber=cx24110_readreg(state,0x25)|
-			(cx24110_readreg(state,0x26)<<8);
-		cx24110_writereg(state,0x24,0x04); /* start new count window */
-		cx24110_writereg(state,0x24,0x14);
-	}
-	*ber = state->lastber;
-
-	return 0;
-}
-
-static int cx24110_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
-{
-	struct cx24110_state *state = fe->demodulator_priv;
-
-/* no provision in hardware. Read the frontend AGC accumulator. No idea how to scale this, but I know it is 2s complement */
-	u8 signal = cx24110_readreg (state, 0x27)+128;
-	*signal_strength = (signal << 8) | signal;
-
-	return 0;
-}
-
-static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct cx24110_state *state = fe->demodulator_priv;
-
-	/* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */
-	if(cx24110_readreg(state,0x6a)&0x80) {
-		/* the Es/N0 error counter has finished one counting window */
-		state->lastesn0=cx24110_readreg(state,0x69)|
-			(cx24110_readreg(state,0x68)<<8);
-		cx24110_writereg(state,0x6a,0x84); /* start new count window */
-	}
-	*snr = state->lastesn0;
-
-	return 0;
-}
-
-static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	struct cx24110_state *state = fe->demodulator_priv;
-
-	if(cx24110_readreg(state,0x10)&0x40) {
-		/* the RS error counter has finished one counting window */
-		cx24110_writereg(state,0x10,0x60); /* select the byer reg */
-		(void)(cx24110_readreg(state, 0x12) |
-			(cx24110_readreg(state, 0x13) << 8) |
-			(cx24110_readreg(state, 0x14) << 16));
-		cx24110_writereg(state,0x10,0x70); /* select the bler reg */
-		state->lastbler=cx24110_readreg(state,0x12)|
-			(cx24110_readreg(state,0x13)<<8)|
-			(cx24110_readreg(state,0x14)<<16);
-		cx24110_writereg(state,0x10,0x20); /* start new count window */
-	}
-	*ucblocks = state->lastbler;
-
-	return 0;
-}
-
-static int cx24110_set_frontend(struct dvb_frontend *fe)
-{
-	struct cx24110_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	cx24110_set_inversion(state, p->inversion);
-	cx24110_set_fec(state, p->fec_inner);
-	cx24110_set_symbolrate(state, p->symbol_rate);
-	cx24110_writereg(state,0x04,0x05); /* start acquisition */
-
-	return 0;
-}
-
-static int cx24110_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct cx24110_state *state = fe->demodulator_priv;
-	s32 afc; unsigned sclk;
-
-/* cannot read back tuner settings (freq). Need to have some private storage */
-
-	sclk = cx24110_readreg (state, 0x07) & 0x03;
-/* ok, real AFC (FEDR) freq. is afc/2^24*fsamp, fsamp=45/60/80/90MHz.
- * Need 64 bit arithmetic. Is thiss possible in the kernel? */
-	if (sclk==0) sclk=90999000L/2L;
-	else if (sclk==1) sclk=60666000L;
-	else if (sclk==2) sclk=80888000L;
-	else sclk=90999000L;
-	sclk>>=8;
-	afc = sclk*(cx24110_readreg (state, 0x44)&0x1f)+
-	      ((sclk*cx24110_readreg (state, 0x45))>>8)+
-	      ((sclk*cx24110_readreg (state, 0x46))>>16);
-
-	p->frequency += afc;
-	p->inversion = (cx24110_readreg (state, 0x22) & 0x10) ?
-				INVERSION_ON : INVERSION_OFF;
-	p->fec_inner = cx24110_get_fec(state);
-
-	return 0;
-}
-
-static int cx24110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
-	struct cx24110_state *state = fe->demodulator_priv;
-
-	return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&~0x10)|(((tone==SEC_TONE_ON))?0x10:0));
-}
-
-static void cx24110_release(struct dvb_frontend* fe)
-{
-	struct cx24110_state* state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops cx24110_ops;
-
-struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
-				    struct i2c_adapter* i2c)
-{
-	struct cx24110_state* state = NULL;
-	int ret;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct cx24110_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->lastber = 0;
-	state->lastbler = 0;
-	state->lastesn0 = 0;
-
-	/* check if the demod is there */
-	ret = cx24110_readreg(state, 0x00);
-	if ((ret != 0x5a) && (ret != 0x69)) goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops cx24110_ops = {
-	.delsys = { SYS_DVBS },
-	.info = {
-		.name = "Conexant CX24110 DVB-S",
-		.frequency_min = 950000,
-		.frequency_max = 2150000,
-		.frequency_stepsize = 1011,  /* kHz for QPSK frontends */
-		.frequency_tolerance = 29500,
-		.symbol_rate_min = 1000000,
-		.symbol_rate_max = 45000000,
-		.caps = FE_CAN_INVERSION_AUTO |
-			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK | FE_CAN_RECOVER
-	},
-
-	.release = cx24110_release,
-
-	.init = cx24110_initfe,
-	.write = _cx24110_pll_write,
-	.set_frontend = cx24110_set_frontend,
-	.get_frontend = cx24110_get_frontend,
-	.read_status = cx24110_read_status,
-	.read_ber = cx24110_read_ber,
-	.read_signal_strength = cx24110_read_signal_strength,
-	.read_snr = cx24110_read_snr,
-	.read_ucblocks = cx24110_read_ucblocks,
-
-	.diseqc_send_master_cmd = cx24110_send_diseqc_msg,
-	.set_tone = cx24110_set_tone,
-	.set_voltage = cx24110_set_voltage,
-	.diseqc_send_burst = cx24110_diseqc_send_burst,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("Conexant CX24110 DVB-S Demodulator driver");
-MODULE_AUTHOR("Peter Hettkamp");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(cx24110_attach);
diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h
deleted file mode 100644
index fdcceee..0000000
--- a/drivers/media/dvb/frontends/cx24110.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-    cx24110 - Single Chip Satellite Channel Receiver driver module
-
-    Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> based on
-    work
-    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef CX24110_H
-#define CX24110_H
-
-#include <linux/dvb/frontend.h>
-
-struct cx24110_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-};
-
-static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val)
-{
-	u8 buf[] = {
-		(u8)((val >> 24) & 0xff),
-		(u8)((val >> 16) & 0xff),
-		(u8)((val >> 8) & 0xff)
-	};
-
-	if (fe->ops.write)
-		return fe->ops.write(fe, buf, 3);
-	return 0;
-}
-
-#if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE))
-extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
-					   struct i2c_adapter* i2c);
-#else
-static inline struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
-						  struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_CX24110
-
-#endif // CX24110_H
diff --git a/drivers/media/dvb/frontends/cx24113.c b/drivers/media/dvb/frontends/cx24113.c
deleted file mode 100644
index 3883c3b..0000000
--- a/drivers/media/dvb/frontends/cx24113.c
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- *  Driver for Conexant CX24113/CX24128 Tuner (Satellite)
- *
- *  Copyright (C) 2007-8 Patrick Boettcher <pb@linuxtv.org>
- *
- *  Developed for BBTI / Technisat
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include "dvb_frontend.h"
-#include "cx24113.h"
-
-static int debug;
-
-#define cx_info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0)
-#define cx_err(args...)  do { printk(KERN_ERR  "CX24113: " args); } while (0)
-
-#define dprintk(args...) \
-	do { \
-		if (debug) { \
-			printk(KERN_DEBUG "CX24113: %s: ", __func__); \
-			printk(args); \
-		} \
-	} while (0)
-
-struct cx24113_state {
-	struct i2c_adapter *i2c;
-	const struct cx24113_config *config;
-
-#define REV_CX24113 0x23
-	u8 rev;
-	u8 ver;
-
-	u8 icp_mode:1;
-
-#define ICP_LEVEL1 0
-#define ICP_LEVEL2 1
-#define ICP_LEVEL3 2
-#define ICP_LEVEL4 3
-	u8 icp_man:2;
-	u8 icp_auto_low:2;
-	u8 icp_auto_mlow:2;
-	u8 icp_auto_mhi:2;
-	u8 icp_auto_hi:2;
-	u8 icp_dig;
-
-#define LNA_MIN_GAIN 0
-#define LNA_MID_GAIN 1
-#define LNA_MAX_GAIN 2
-	u8 lna_gain:2;
-
-	u8 acp_on:1;
-
-	u8 vco_mode:2;
-	u8 vco_shift:1;
-#define VCOBANDSEL_6 0x80
-#define VCOBANDSEL_5 0x01
-#define VCOBANDSEL_4 0x02
-#define VCOBANDSEL_3 0x04
-#define VCOBANDSEL_2 0x08
-#define VCOBANDSEL_1 0x10
-	u8 vco_band;
-
-#define VCODIV4 4
-#define VCODIV2 2
-	u8 vcodiv;
-
-	u8 bs_delay:4;
-	u16 bs_freqcnt:13;
-	u16 bs_rdiv;
-	u8 prescaler_mode:1;
-
-	u8 rfvga_bias_ctrl;
-
-	s16 tuner_gain_thres;
-	u8  gain_level;
-
-	u32 frequency;
-
-	u8 refdiv;
-
-	u8 Fwindow_enabled;
-};
-
-static int cx24113_writereg(struct cx24113_state *state, int reg, int data)
-{
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = { .addr = state->config->i2c_addr,
-		.flags = 0, .buf = buf, .len = 2 };
-	int err = i2c_transfer(state->i2c, &msg, 1);
-	if (err != 1) {
-		printk(KERN_DEBUG "%s: writereg error(err == %i, reg == 0x%02x,"
-			 " data == 0x%02x)\n", __func__, err, reg, data);
-		return err;
-	}
-
-	return 0;
-}
-
-static int cx24113_readreg(struct cx24113_state *state, u8 reg)
-{
-	int ret;
-	u8 b;
-	struct i2c_msg msg[] = {
-		{ .addr = state->config->i2c_addr,
-			.flags = 0, .buf = &reg, .len = 1 },
-		{ .addr = state->config->i2c_addr,
-			.flags = I2C_M_RD, .buf = &b, .len = 1 }
-	};
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2) {
-		printk(KERN_DEBUG "%s: reg=0x%x (error=%d)\n",
-			__func__, reg, ret);
-		return ret;
-	}
-
-	return b;
-}
-
-static void cx24113_set_parameters(struct cx24113_state *state)
-{
-	u8 r;
-
-	r = cx24113_readreg(state, 0x10) & 0x82;
-	r |= state->icp_mode;
-	r |= state->icp_man << 4;
-	r |= state->icp_dig << 2;
-	r |= state->prescaler_mode << 5;
-	cx24113_writereg(state, 0x10, r);
-
-	r = (state->icp_auto_low  << 0) | (state->icp_auto_mlow << 2)
-		| (state->icp_auto_mhi << 4) | (state->icp_auto_hi << 6);
-	cx24113_writereg(state, 0x11, r);
-
-	if (state->rev == REV_CX24113) {
-		r = cx24113_readreg(state, 0x20) & 0xec;
-		r |= state->lna_gain;
-		r |= state->rfvga_bias_ctrl << 4;
-		cx24113_writereg(state, 0x20, r);
-	}
-
-	r = cx24113_readreg(state, 0x12) & 0x03;
-	r |= state->acp_on << 2;
-	r |= state->bs_delay << 4;
-	cx24113_writereg(state, 0x12, r);
-
-	r = cx24113_readreg(state, 0x18) & 0x40;
-	r |= state->vco_shift;
-	if (state->vco_band == VCOBANDSEL_6)
-		r |= (1 << 7);
-	else
-		r |= (state->vco_band << 1);
-	cx24113_writereg(state, 0x18, r);
-
-	r  = cx24113_readreg(state, 0x14) & 0x20;
-	r |= (state->vco_mode << 6) | ((state->bs_freqcnt >> 8) & 0x1f);
-	cx24113_writereg(state, 0x14, r);
-	cx24113_writereg(state, 0x15, (state->bs_freqcnt        & 0xff));
-
-	cx24113_writereg(state, 0x16, (state->bs_rdiv >> 4) & 0xff);
-	r = (cx24113_readreg(state, 0x17) & 0x0f) |
-		((state->bs_rdiv & 0x0f) << 4);
-	cx24113_writereg(state, 0x17, r);
-}
-
-#define VGA_0 0x00
-#define VGA_1 0x04
-#define VGA_2 0x02
-#define VGA_3 0x06
-#define VGA_4 0x01
-#define VGA_5 0x05
-#define VGA_6 0x03
-#define VGA_7 0x07
-
-#define RFVGA_0 0x00
-#define RFVGA_1 0x01
-#define RFVGA_2 0x02
-#define RFVGA_3 0x03
-
-static int cx24113_set_gain_settings(struct cx24113_state *state,
-		s16 power_estimation)
-{
-	u8 ampout = cx24113_readreg(state, 0x1d) & 0xf0,
-	   vga    = cx24113_readreg(state, 0x1f) & 0x3f,
-	   rfvga  = cx24113_readreg(state, 0x20) & 0xf3;
-	u8 gain_level = power_estimation >= state->tuner_gain_thres;
-
-	dprintk("power estimation: %d, thres: %d, gain_level: %d/%d\n",
-			power_estimation, state->tuner_gain_thres,
-			state->gain_level, gain_level);
-
-	if (gain_level == state->gain_level)
-		return 0; /* nothing to be done */
-
-	ampout |= 0xf;
-
-	if (gain_level) {
-		rfvga |= RFVGA_0 << 2;
-		vga   |= (VGA_7 << 3) | VGA_7;
-	} else {
-		rfvga |= RFVGA_2 << 2;
-		vga  |= (VGA_6 << 3) | VGA_2;
-	}
-	state->gain_level = gain_level;
-
-	cx24113_writereg(state, 0x1d, ampout);
-	cx24113_writereg(state, 0x1f, vga);
-	cx24113_writereg(state, 0x20, rfvga);
-
-	return 1; /* did something */
-}
-
-static int cx24113_set_Fref(struct cx24113_state *state, u8 high)
-{
-	u8 xtal = cx24113_readreg(state, 0x02);
-	if (state->rev == 0x43 && state->vcodiv == VCODIV4)
-		high = 1;
-
-	xtal &= ~0x2;
-	if (high)
-		xtal |= high << 1;
-	return cx24113_writereg(state, 0x02, xtal);
-}
-
-static int cx24113_enable(struct cx24113_state *state, u8 enable)
-{
-	u8 r21 = (cx24113_readreg(state, 0x21) & 0xc0) | enable;
-	if (state->rev == REV_CX24113)
-		r21 |= (1 << 1);
-	return cx24113_writereg(state, 0x21, r21);
-}
-
-static int cx24113_set_bandwidth(struct cx24113_state *state, u32 bandwidth_khz)
-{
-	u8 r;
-
-	if (bandwidth_khz <= 19000)
-		r = 0x03 << 6;
-	else if (bandwidth_khz <= 25000)
-		r = 0x02 << 6;
-	else
-		r = 0x01 << 6;
-
-	dprintk("bandwidth to be set: %d\n", bandwidth_khz);
-	bandwidth_khz *= 10;
-	bandwidth_khz -= 10000;
-	bandwidth_khz /= 1000;
-	bandwidth_khz += 5;
-	bandwidth_khz /= 10;
-
-	dprintk("bandwidth: %d %d\n", r >> 6, bandwidth_khz);
-
-	r |= bandwidth_khz & 0x3f;
-
-	return cx24113_writereg(state, 0x1e, r);
-}
-
-static int cx24113_set_clk_inversion(struct cx24113_state *state, u8 on)
-{
-	u8 r = (cx24113_readreg(state, 0x10) & 0x7f) | ((on & 0x1) << 7);
-	return cx24113_writereg(state, 0x10, r);
-}
-
-static int cx24113_get_status(struct dvb_frontend *fe, u32 *status)
-{
-	struct cx24113_state *state = fe->tuner_priv;
-	u8 r = (cx24113_readreg(state, 0x10) & 0x02) >> 1;
-	if (r)
-		*status |= TUNER_STATUS_LOCKED;
-	dprintk("PLL locked: %d\n", r);
-	return 0;
-}
-
-static u8 cx24113_set_ref_div(struct cx24113_state *state, u8 refdiv)
-{
-	if (state->rev == 0x43 && state->vcodiv == VCODIV4)
-		refdiv = 2;
-	return state->refdiv = refdiv;
-}
-
-static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f)
-{
-	s32 N;
-	s64 F;
-	u64 dividend;
-	u8 R, r;
-	u8 vcodiv;
-	u8 factor;
-	s32 freq_hz = state->frequency * 1000;
-
-	if (state->config->xtal_khz < 20000)
-		factor = 1;
-	else
-		factor = 2;
-
-	if (state->rev == REV_CX24113) {
-		if (state->frequency >= 1100000)
-			vcodiv = VCODIV2;
-		else
-			vcodiv = VCODIV4;
-	} else {
-		if (state->frequency >= 1165000)
-			vcodiv = VCODIV2;
-		else
-			vcodiv = VCODIV4;
-	}
-	state->vcodiv = vcodiv;
-
-	dprintk("calculating N/F for %dHz with vcodiv %d\n", freq_hz, vcodiv);
-	R = 0;
-	do {
-		R = cx24113_set_ref_div(state, R + 1);
-
-		/* calculate tuner PLL settings: */
-		N =  (freq_hz / 100 * vcodiv) * R;
-		N /= (state->config->xtal_khz) * factor * 2;
-		N += 5;     /* For round up. */
-		N /= 10;
-		N -= 32;
-	} while (N < 6 && R < 3);
-
-	if (N < 6) {
-		cx_err("strange frequency: N < 6\n");
-		return;
-	}
-	F = freq_hz;
-	F *= (u64) (R * vcodiv * 262144);
-	dprintk("1 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
-	/* do_div needs an u64 as first argument */
-	dividend = F;
-	do_div(dividend, state->config->xtal_khz * 1000 * factor * 2);
-	F = dividend;
-	dprintk("2 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
-	F -= (N + 32) * 262144;
-
-	dprintk("3 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
-
-	if (state->Fwindow_enabled) {
-		if (F > (262144 / 2 - 1638))
-			F = 262144 / 2 - 1638;
-		if (F < (-262144 / 2 + 1638))
-			F = -262144 / 2 + 1638;
-		if ((F < 3277 && F > 0) || (F > -3277 && F < 0)) {
-			F = 0;
-			r = cx24113_readreg(state, 0x10);
-			cx24113_writereg(state, 0x10, r | (1 << 6));
-		}
-	}
-	dprintk("4 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
-
-	*n = (u16) N;
-	*f = (s32) F;
-}
-
-
-static void cx24113_set_nfr(struct cx24113_state *state, u16 n, s32 f, u8 r)
-{
-	u8 reg;
-	cx24113_writereg(state, 0x19, (n >> 1) & 0xff);
-
-	reg = ((n & 0x1) << 7) | ((f >> 11) & 0x7f);
-	cx24113_writereg(state, 0x1a, reg);
-
-	cx24113_writereg(state, 0x1b, (f >> 3) & 0xff);
-
-	reg = cx24113_readreg(state, 0x1c) & 0x1f;
-	cx24113_writereg(state, 0x1c, reg | ((f & 0x7) << 5));
-
-	cx24113_set_Fref(state, r - 1);
-}
-
-static int cx24113_set_frequency(struct cx24113_state *state, u32 frequency)
-{
-	u8 r = 1; /* or 2 */
-	u16 n = 6;
-	s32 f = 0;
-
-	r = cx24113_readreg(state, 0x14);
-	cx24113_writereg(state, 0x14, r & 0x3f);
-
-	r = cx24113_readreg(state, 0x10);
-	cx24113_writereg(state, 0x10, r & 0xbf);
-
-	state->frequency = frequency;
-
-	dprintk("tuning to frequency: %d\n", frequency);
-
-	cx24113_calc_pll_nf(state, &n, &f);
-	cx24113_set_nfr(state, n, f, state->refdiv);
-
-	r = cx24113_readreg(state, 0x18) & 0xbf;
-	if (state->vcodiv != VCODIV2)
-		r |= 1 << 6;
-	cx24113_writereg(state, 0x18, r);
-
-	/* The need for this sleep is not clear. But helps in some cases */
-	msleep(5);
-
-	r = cx24113_readreg(state, 0x1c) & 0xef;
-	cx24113_writereg(state, 0x1c, r | (1 << 4));
-	return 0;
-}
-
-static int cx24113_init(struct dvb_frontend *fe)
-{
-	struct cx24113_state *state = fe->tuner_priv;
-	int ret;
-
-	state->tuner_gain_thres = -50;
-	state->gain_level = 255; /* to force a gain-setting initialization */
-	state->icp_mode = 0;
-
-	if (state->config->xtal_khz < 11000) {
-		state->icp_auto_hi  = ICP_LEVEL4;
-		state->icp_auto_mhi  = ICP_LEVEL4;
-		state->icp_auto_mlow = ICP_LEVEL3;
-		state->icp_auto_low = ICP_LEVEL3;
-	} else {
-		state->icp_auto_hi  = ICP_LEVEL4;
-		state->icp_auto_mhi  = ICP_LEVEL4;
-		state->icp_auto_mlow = ICP_LEVEL3;
-		state->icp_auto_low = ICP_LEVEL2;
-	}
-
-	state->icp_dig = ICP_LEVEL3;
-	state->icp_man = ICP_LEVEL1;
-	state->acp_on  = 1;
-	state->vco_mode = 0;
-	state->vco_shift = 0;
-	state->vco_band = VCOBANDSEL_1;
-	state->bs_delay = 8;
-	state->bs_freqcnt = 0x0fff;
-	state->bs_rdiv = 0x0fff;
-	state->prescaler_mode = 0;
-	state->lna_gain = LNA_MAX_GAIN;
-	state->rfvga_bias_ctrl = 1;
-	state->Fwindow_enabled = 1;
-
-	cx24113_set_Fref(state, 0);
-	cx24113_enable(state, 0x3d);
-	cx24113_set_parameters(state);
-
-	cx24113_set_gain_settings(state, -30);
-
-	cx24113_set_bandwidth(state, 18025);
-	cx24113_set_clk_inversion(state, 1);
-
-	if (state->config->xtal_khz >= 40000)
-		ret = cx24113_writereg(state, 0x02,
-			(cx24113_readreg(state, 0x02) & 0xfb) | (1 << 2));
-	else
-		ret = cx24113_writereg(state, 0x02,
-			(cx24113_readreg(state, 0x02) & 0xfb) | (0 << 2));
-
-	return ret;
-}
-
-static int cx24113_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct cx24113_state *state = fe->tuner_priv;
-	/* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */
-	u32 roll_off = 675;
-	u32 bw;
-
-	bw  = ((c->symbol_rate/100) * roll_off) / 1000;
-	bw += (10000000/100) + 5;
-	bw /= 10;
-	bw += 1000;
-	cx24113_set_bandwidth(state, bw);
-
-	cx24113_set_frequency(state, c->frequency);
-	msleep(5);
-	return cx24113_get_status(fe, &bw);
-}
-
-static s8 cx24113_agc_table[2][10] = {
-	{-54, -41, -35, -30, -25, -21, -16, -10,  -6,  -2},
-	{-39, -35, -30, -25, -19, -15, -11,  -5,   1,   9},
-};
-
-void cx24113_agc_callback(struct dvb_frontend *fe)
-{
-	struct cx24113_state *state = fe->tuner_priv;
-	s16 s, i;
-	if (!fe->ops.read_signal_strength)
-		return;
-
-	do {
-		/* this only works with the current CX24123 implementation */
-		fe->ops.read_signal_strength(fe, (u16 *) &s);
-		s >>= 8;
-		dprintk("signal strength: %d\n", s);
-		for (i = 0; i < sizeof(cx24113_agc_table[0]); i++)
-			if (cx24113_agc_table[state->gain_level][i] > s)
-				break;
-		s = -25 - i*5;
-	} while (cx24113_set_gain_settings(state, s));
-}
-EXPORT_SYMBOL(cx24113_agc_callback);
-
-static int cx24113_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct cx24113_state *state = fe->tuner_priv;
-	*frequency = state->frequency;
-	return 0;
-}
-
-static int cx24113_release(struct dvb_frontend *fe)
-{
-	struct cx24113_state *state = fe->tuner_priv;
-	dprintk("\n");
-	fe->tuner_priv = NULL;
-	kfree(state);
-	return 0;
-}
-
-static const struct dvb_tuner_ops cx24113_tuner_ops = {
-	.info = {
-		.name           = "Conexant CX24113",
-		.frequency_min  = 950000,
-		.frequency_max  = 2150000,
-		.frequency_step = 125,
-	},
-
-	.release       = cx24113_release,
-
-	.init          = cx24113_init,
-
-	.set_params    = cx24113_set_params,
-	.get_frequency = cx24113_get_frequency,
-	.get_status    = cx24113_get_status,
-};
-
-struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
-		const struct cx24113_config *config, struct i2c_adapter *i2c)
-{
-	/* allocate memory for the internal state */
-	struct cx24113_state *state =
-		kzalloc(sizeof(struct cx24113_state), GFP_KERNEL);
-	int rc;
-	if (state == NULL) {
-		cx_err("Unable to kzalloc\n");
-		goto error;
-	}
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-
-	cx_info("trying to detect myself\n");
-
-	/* making a dummy read, because of some expected troubles
-	 * after power on */
-	cx24113_readreg(state, 0x00);
-
-	rc = cx24113_readreg(state, 0x00);
-	if (rc < 0) {
-		cx_info("CX24113 not found.\n");
-		goto error;
-	}
-	state->rev = rc;
-
-	switch (rc) {
-	case 0x43:
-		cx_info("detected CX24113 variant\n");
-		break;
-	case REV_CX24113:
-		cx_info("successfully detected\n");
-		break;
-	default:
-		cx_err("unsupported device id: %x\n", state->rev);
-		goto error;
-	}
-	state->ver = cx24113_readreg(state, 0x01);
-	cx_info("version: %x\n", state->ver);
-
-	/* create dvb_frontend */
-	memcpy(&fe->ops.tuner_ops, &cx24113_tuner_ops,
-			sizeof(struct dvb_tuner_ops));
-	fe->tuner_priv = state;
-	return fe;
-
-error:
-	kfree(state);
-
-	return NULL;
-}
-EXPORT_SYMBOL(cx24113_attach);
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
-
-MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>");
-MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24113/CX24128hardware");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/media/dvb/frontends/cx24113.h b/drivers/media/dvb/frontends/cx24113.h
deleted file mode 100644
index 01eb7b9..0000000
--- a/drivers/media/dvb/frontends/cx24113.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *  Driver for Conexant CX24113/CX24128 Tuner (Satellite)
- *
- *  Copyright (C) 2007-8 Patrick Boettcher <pb@linuxtv.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef CX24113_H
-#define CX24113_H
-
-struct dvb_frontend;
-
-struct cx24113_config {
-	u8 i2c_addr; /* 0x14 or 0x54 */
-
-	u32 xtal_khz;
-};
-
-#if defined(CONFIG_DVB_TUNER_CX24113) || \
-	(defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE))
-extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *,
-	const struct cx24113_config *config, struct i2c_adapter *i2c);
-
-extern void cx24113_agc_callback(struct dvb_frontend *fe);
-#else
-static inline struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
-	const struct cx24113_config *config, struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline void cx24113_agc_callback(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-}
-#endif
-
-#endif /* CX24113_H */
diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c
deleted file mode 100644
index b488791..0000000
--- a/drivers/media/dvb/frontends/cx24116.c
+++ /dev/null
@@ -1,1508 +0,0 @@
-/*
-    Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver
-
-    Copyright (C) 2006-2008 Steven Toth <stoth@hauppauge.com>
-    Copyright (C) 2006-2007 Georg Acher
-    Copyright (C) 2007-2008 Darron Broad
-	March 2007
-	    Fixed some bugs.
-	    Added diseqc support.
-	    Added corrected signal strength support.
-	August 2007
-	    Sync with legacy version.
-	    Some clean ups.
-    Copyright (C) 2008 Igor Liplianin
-	September, 9th 2008
-	    Fixed locking on high symbol rates (>30000).
-	    Implement MPEG initialization parameter.
-	January, 17th 2009
-	    Fill set_voltage with actually control voltage code.
-	    Correct set tone to not affect voltage.
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/firmware.h>
-
-#include "dvb_frontend.h"
-#include "cx24116.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
-
-#define dprintk(args...) \
-	do { \
-		if (debug) \
-			printk(KERN_INFO "cx24116: " args); \
-	} while (0)
-
-#define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw"
-#define CX24116_SEARCH_RANGE_KHZ 5000
-
-/* known registers */
-#define CX24116_REG_COMMAND (0x00)      /* command args 0x00..0x1e */
-#define CX24116_REG_EXECUTE (0x1f)      /* execute command */
-#define CX24116_REG_MAILBOX (0x96)      /* FW or multipurpose mailbox? */
-#define CX24116_REG_RESET   (0x20)      /* reset status > 0     */
-#define CX24116_REG_SIGNAL  (0x9e)      /* signal low           */
-#define CX24116_REG_SSTATUS (0x9d)      /* signal high / status */
-#define CX24116_REG_QUALITY8 (0xa3)
-#define CX24116_REG_QSTATUS (0xbc)
-#define CX24116_REG_QUALITY0 (0xd5)
-#define CX24116_REG_BER0    (0xc9)
-#define CX24116_REG_BER8    (0xc8)
-#define CX24116_REG_BER16   (0xc7)
-#define CX24116_REG_BER24   (0xc6)
-#define CX24116_REG_UCB0    (0xcb)
-#define CX24116_REG_UCB8    (0xca)
-#define CX24116_REG_CLKDIV  (0xf3)
-#define CX24116_REG_RATEDIV (0xf9)
-
-/* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */
-#define CX24116_REG_FECSTATUS (0x9c)
-
-/* FECSTATUS bits */
-/* mask to determine configured fec (not tuned) or actual fec (tuned) */
-#define CX24116_FEC_FECMASK   (0x1f)
-
-/* Select DVB-S demodulator, else DVB-S2 */
-#define CX24116_FEC_DVBS      (0x20)
-#define CX24116_FEC_UNKNOWN   (0x40)    /* Unknown/unused */
-
-/* Pilot mode requested when tuning else always reset when tuned */
-#define CX24116_FEC_PILOT     (0x80)
-
-/* arg buffer size */
-#define CX24116_ARGLEN (0x1e)
-
-/* rolloff */
-#define CX24116_ROLLOFF_020 (0x00)
-#define CX24116_ROLLOFF_025 (0x01)
-#define CX24116_ROLLOFF_035 (0x02)
-
-/* pilot bit */
-#define CX24116_PILOT_OFF (0x00)
-#define CX24116_PILOT_ON (0x40)
-
-/* signal status */
-#define CX24116_HAS_SIGNAL   (0x01)
-#define CX24116_HAS_CARRIER  (0x02)
-#define CX24116_HAS_VITERBI  (0x04)
-#define CX24116_HAS_SYNCLOCK (0x08)
-#define CX24116_HAS_UNKNOWN1 (0x10)
-#define CX24116_HAS_UNKNOWN2 (0x20)
-#define CX24116_STATUS_MASK  (0x0f)
-#define CX24116_SIGNAL_MASK  (0xc0)
-
-#define CX24116_DISEQC_TONEOFF   (0)    /* toneburst never sent */
-#define CX24116_DISEQC_TONECACHE (1)    /* toneburst cached     */
-#define CX24116_DISEQC_MESGCACHE (2)    /* message cached       */
-
-/* arg offset for DiSEqC */
-#define CX24116_DISEQC_BURST  (1)
-#define CX24116_DISEQC_ARG2_2 (2)   /* unknown value=2 */
-#define CX24116_DISEQC_ARG3_0 (3)   /* unknown value=0 */
-#define CX24116_DISEQC_ARG4_0 (4)   /* unknown value=0 */
-#define CX24116_DISEQC_MSGLEN (5)
-#define CX24116_DISEQC_MSGOFS (6)
-
-/* DiSEqC burst */
-#define CX24116_DISEQC_MINI_A (0)
-#define CX24116_DISEQC_MINI_B (1)
-
-/* DiSEqC tone burst */
-static int toneburst = 1;
-module_param(toneburst, int, 0644);
-MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, "\
-	"2=MESSAGE CACHE (default:1)");
-
-/* SNR measurements */
-static int esno_snr;
-module_param(esno_snr, int, 0644);
-MODULE_PARM_DESC(esno_snr, "SNR return units, 0=PERCENTAGE 0-100, "\
-	"1=ESNO(db * 10) (default:0)");
-
-enum cmds {
-	CMD_SET_VCO     = 0x10,
-	CMD_TUNEREQUEST = 0x11,
-	CMD_MPEGCONFIG  = 0x13,
-	CMD_TUNERINIT   = 0x14,
-	CMD_BANDWIDTH   = 0x15,
-	CMD_GETAGC      = 0x19,
-	CMD_LNBCONFIG   = 0x20,
-	CMD_LNBSEND     = 0x21, /* Formerly CMD_SEND_DISEQC */
-	CMD_LNBDCLEVEL  = 0x22,
-	CMD_SET_TONE    = 0x23,
-	CMD_UPDFWVERS   = 0x35,
-	CMD_TUNERSLEEP  = 0x36,
-	CMD_AGCCONTROL  = 0x3b, /* Unknown */
-};
-
-/* The Demod/Tuner can't easily provide these, we cache them */
-struct cx24116_tuning {
-	u32 frequency;
-	u32 symbol_rate;
-	fe_spectral_inversion_t inversion;
-	fe_code_rate_t fec;
-
-	fe_delivery_system_t delsys;
-	fe_modulation_t modulation;
-	fe_pilot_t pilot;
-	fe_rolloff_t rolloff;
-
-	/* Demod values */
-	u8 fec_val;
-	u8 fec_mask;
-	u8 inversion_val;
-	u8 pilot_val;
-	u8 rolloff_val;
-};
-
-/* Basic commands that are sent to the firmware */
-struct cx24116_cmd {
-	u8 len;
-	u8 args[CX24116_ARGLEN];
-};
-
-struct cx24116_state {
-	struct i2c_adapter *i2c;
-	const struct cx24116_config *config;
-
-	struct dvb_frontend frontend;
-
-	struct cx24116_tuning dcur;
-	struct cx24116_tuning dnxt;
-
-	u8 skip_fw_load;
-	u8 burst;
-	struct cx24116_cmd dsec_cmd;
-};
-
-static int cx24116_writereg(struct cx24116_state *state, int reg, int data)
-{
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = { .addr = state->config->demod_address,
-		.flags = 0, .buf = buf, .len = 2 };
-	int err;
-
-	if (debug > 1)
-		printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n",
-			__func__, reg, data);
-
-	err = i2c_transfer(state->i2c, &msg, 1);
-	if (err != 1) {
-		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
-			 " value == 0x%02x)\n", __func__, err, reg, data);
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-/* Bulk byte writes to a single I2C address, for 32k firmware load */
-static int cx24116_writeregN(struct cx24116_state *state, int reg,
-			     const u8 *data, u16 len)
-{
-	int ret = -EREMOTEIO;
-	struct i2c_msg msg;
-	u8 *buf;
-
-	buf = kmalloc(len + 1, GFP_KERNEL);
-	if (buf == NULL) {
-		printk("Unable to kmalloc\n");
-		ret = -ENOMEM;
-		goto error;
-	}
-
-	*(buf) = reg;
-	memcpy(buf + 1, data, len);
-
-	msg.addr = state->config->demod_address;
-	msg.flags = 0;
-	msg.buf = buf;
-	msg.len = len + 1;
-
-	if (debug > 1)
-		printk(KERN_INFO "cx24116: %s:  write regN 0x%02x, len = %d\n",
-			__func__, reg, len);
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-	if (ret != 1) {
-		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n",
-			 __func__, ret, reg);
-		ret = -EREMOTEIO;
-	}
-
-error:
-	kfree(buf);
-
-	return ret;
-}
-
-static int cx24116_readreg(struct cx24116_state *state, u8 reg)
-{
-	int ret;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
-	struct i2c_msg msg[] = {
-		{ .addr = state->config->demod_address, .flags = 0,
-			.buf = b0, .len = 1 },
-		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
-			.buf = b1, .len = 1 }
-	};
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2) {
-		printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
-			__func__, reg, ret);
-		return ret;
-	}
-
-	if (debug > 1)
-		printk(KERN_INFO "cx24116: read reg 0x%02x, value 0x%02x\n",
-			reg, b1[0]);
-
-	return b1[0];
-}
-
-static int cx24116_set_inversion(struct cx24116_state *state,
-	fe_spectral_inversion_t inversion)
-{
-	dprintk("%s(%d)\n", __func__, inversion);
-
-	switch (inversion) {
-	case INVERSION_OFF:
-		state->dnxt.inversion_val = 0x00;
-		break;
-	case INVERSION_ON:
-		state->dnxt.inversion_val = 0x04;
-		break;
-	case INVERSION_AUTO:
-		state->dnxt.inversion_val = 0x0C;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	state->dnxt.inversion = inversion;
-
-	return 0;
-}
-
-/*
- * modfec (modulation and FEC)
- * ===========================
- *
- * MOD          FEC             mask/val    standard
- * ----         --------        ----------- --------
- * QPSK         FEC_1_2         0x02 0x02+X DVB-S
- * QPSK         FEC_2_3         0x04 0x02+X DVB-S
- * QPSK         FEC_3_4         0x08 0x02+X DVB-S
- * QPSK         FEC_4_5         0x10 0x02+X DVB-S (?)
- * QPSK         FEC_5_6         0x20 0x02+X DVB-S
- * QPSK         FEC_6_7         0x40 0x02+X DVB-S
- * QPSK         FEC_7_8         0x80 0x02+X DVB-S
- * QPSK         FEC_8_9         0x01 0x02+X DVB-S (?) (NOT SUPPORTED?)
- * QPSK         AUTO            0xff 0x02+X DVB-S
- *
- * For DVB-S high byte probably represents FEC
- * and low byte selects the modulator. The high
- * byte is search range mask. Bit 5 may turn
- * on DVB-S and remaining bits represent some
- * kind of calibration (how/what i do not know).
- *
- * Eg.(2/3) szap "Zone Horror"
- *
- * mask/val = 0x04, 0x20
- * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 0 | FE_HAS_LOCK
- *
- * mask/val = 0x04, 0x30
- * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 0 | FE_HAS_LOCK
- *
- * After tuning FECSTATUS contains actual FEC
- * in use numbered 1 through to 8 for 1/2 .. 2/3 etc
- *
- * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only)
- *
- * NBC-QPSK     FEC_1_2         0x00, 0x04      DVB-S2
- * NBC-QPSK     FEC_3_5         0x00, 0x05      DVB-S2
- * NBC-QPSK     FEC_2_3         0x00, 0x06      DVB-S2
- * NBC-QPSK     FEC_3_4         0x00, 0x07      DVB-S2
- * NBC-QPSK     FEC_4_5         0x00, 0x08      DVB-S2
- * NBC-QPSK     FEC_5_6         0x00, 0x09      DVB-S2
- * NBC-QPSK     FEC_8_9         0x00, 0x0a      DVB-S2
- * NBC-QPSK     FEC_9_10        0x00, 0x0b      DVB-S2
- *
- * NBC-8PSK     FEC_3_5         0x00, 0x0c      DVB-S2
- * NBC-8PSK     FEC_2_3         0x00, 0x0d      DVB-S2
- * NBC-8PSK     FEC_3_4         0x00, 0x0e      DVB-S2
- * NBC-8PSK     FEC_5_6         0x00, 0x0f      DVB-S2
- * NBC-8PSK     FEC_8_9         0x00, 0x10      DVB-S2
- * NBC-8PSK     FEC_9_10        0x00, 0x11      DVB-S2
- *
- * For DVB-S2 low bytes selects both modulator
- * and FEC. High byte is meaningless here. To
- * set pilot, bit 6 (0x40) is set. When inspecting
- * FECSTATUS bit 7 (0x80) represents the pilot
- * selection whilst not tuned. When tuned, actual FEC
- * in use is found in FECSTATUS as per above. Pilot
- * value is reset.
- */
-
-/* A table of modulation, fec and configuration bytes for the demod.
- * Not all S2 mmodulation schemes are support and not all rates with
- * a scheme are support. Especially, no auto detect when in S2 mode.
- */
-static struct cx24116_modfec {
-	fe_delivery_system_t delivery_system;
-	fe_modulation_t modulation;
-	fe_code_rate_t fec;
-	u8 mask;	/* In DVBS mode this is used to autodetect */
-	u8 val;		/* Passed to the firmware to indicate mode selection */
-} CX24116_MODFEC_MODES[] = {
- /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */
-
- /*mod   fec       mask  val */
- { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 },
- { SYS_DVBS, QPSK, FEC_1_2,  0x02, 0x2e }, /* 00000010 00101110 */
- { SYS_DVBS, QPSK, FEC_2_3,  0x04, 0x2f }, /* 00000100 00101111 */
- { SYS_DVBS, QPSK, FEC_3_4,  0x08, 0x30 }, /* 00001000 00110000 */
- { SYS_DVBS, QPSK, FEC_4_5,  0xfe, 0x30 }, /* 000?0000 ?        */
- { SYS_DVBS, QPSK, FEC_5_6,  0x20, 0x31 }, /* 00100000 00110001 */
- { SYS_DVBS, QPSK, FEC_6_7,  0xfe, 0x30 }, /* 0?000000 ?        */
- { SYS_DVBS, QPSK, FEC_7_8,  0x80, 0x32 }, /* 10000000 00110010 */
- { SYS_DVBS, QPSK, FEC_8_9,  0xfe, 0x30 }, /* 0000000? ?        */
- { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 },
- /* NBC-QPSK */
- { SYS_DVBS2, QPSK, FEC_1_2,  0x00, 0x04 },
- { SYS_DVBS2, QPSK, FEC_3_5,  0x00, 0x05 },
- { SYS_DVBS2, QPSK, FEC_2_3,  0x00, 0x06 },
- { SYS_DVBS2, QPSK, FEC_3_4,  0x00, 0x07 },
- { SYS_DVBS2, QPSK, FEC_4_5,  0x00, 0x08 },
- { SYS_DVBS2, QPSK, FEC_5_6,  0x00, 0x09 },
- { SYS_DVBS2, QPSK, FEC_8_9,  0x00, 0x0a },
- { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b },
- /* 8PSK */
- { SYS_DVBS2, PSK_8, FEC_3_5,  0x00, 0x0c },
- { SYS_DVBS2, PSK_8, FEC_2_3,  0x00, 0x0d },
- { SYS_DVBS2, PSK_8, FEC_3_4,  0x00, 0x0e },
- { SYS_DVBS2, PSK_8, FEC_5_6,  0x00, 0x0f },
- { SYS_DVBS2, PSK_8, FEC_8_9,  0x00, 0x10 },
- { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 },
- /*
-  * `val' can be found in the FECSTATUS register when tuning.
-  * FECSTATUS will give the actual FEC in use if tuning was successful.
-  */
-};
-
-static int cx24116_lookup_fecmod(struct cx24116_state *state,
-	fe_delivery_system_t d, fe_modulation_t m, fe_code_rate_t f)
-{
-	int i, ret = -EOPNOTSUPP;
-
-	dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
-
-	for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) {
-		if ((d == CX24116_MODFEC_MODES[i].delivery_system) &&
-			(m == CX24116_MODFEC_MODES[i].modulation) &&
-			(f == CX24116_MODFEC_MODES[i].fec)) {
-				ret = i;
-				break;
-			}
-	}
-
-	return ret;
-}
-
-static int cx24116_set_fec(struct cx24116_state *state,
-	fe_delivery_system_t delsys, fe_modulation_t mod, fe_code_rate_t fec)
-{
-	int ret = 0;
-
-	dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
-
-	ret = cx24116_lookup_fecmod(state, delsys, mod, fec);
-
-	if (ret < 0)
-		return ret;
-
-	state->dnxt.fec = fec;
-	state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val;
-	state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask;
-	dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__,
-		state->dnxt.fec_mask, state->dnxt.fec_val);
-
-	return 0;
-}
-
-static int cx24116_set_symbolrate(struct cx24116_state *state, u32 rate)
-{
-	dprintk("%s(%d)\n", __func__, rate);
-
-	/*  check if symbol rate is within limits */
-	if ((rate > state->frontend.ops.info.symbol_rate_max) ||
-	    (rate < state->frontend.ops.info.symbol_rate_min)) {
-		dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate);
-		return -EOPNOTSUPP;
-	}
-
-	state->dnxt.symbol_rate = rate;
-	dprintk("%s() symbol_rate = %d\n", __func__, rate);
-
-	return 0;
-}
-
-static int cx24116_load_firmware(struct dvb_frontend *fe,
-	const struct firmware *fw);
-
-static int cx24116_firmware_ondemand(struct dvb_frontend *fe)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-	const struct firmware *fw;
-	int ret = 0;
-
-	dprintk("%s()\n", __func__);
-
-	if (cx24116_readreg(state, 0x20) > 0) {
-
-		if (state->skip_fw_load)
-			return 0;
-
-		/* Load firmware */
-		/* request the firmware, this will block until loaded */
-		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n",
-			__func__, CX24116_DEFAULT_FIRMWARE);
-		ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE,
-			state->i2c->dev.parent);
-		printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n",
-			__func__);
-		if (ret) {
-			printk(KERN_ERR "%s: No firmware uploaded "
-				"(timeout or file not found?)\n", __func__);
-			return ret;
-		}
-
-		/* Make sure we don't recurse back through here
-		 * during loading */
-		state->skip_fw_load = 1;
-
-		ret = cx24116_load_firmware(fe, fw);
-		if (ret)
-			printk(KERN_ERR "%s: Writing firmware to device failed\n",
-				__func__);
-
-		release_firmware(fw);
-
-		printk(KERN_INFO "%s: Firmware upload %s\n", __func__,
-			ret == 0 ? "complete" : "failed");
-
-		/* Ensure firmware is always loaded if required */
-		state->skip_fw_load = 0;
-	}
-
-	return ret;
-}
-
-/* Take a basic firmware command structure, format it
- * and forward it for processing
- */
-static int cx24116_cmd_execute(struct dvb_frontend *fe, struct cx24116_cmd *cmd)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-	int i, ret;
-
-	dprintk("%s()\n", __func__);
-
-	/* Load the firmware if required */
-	ret = cx24116_firmware_ondemand(fe);
-	if (ret != 0) {
-		printk(KERN_ERR "%s(): Unable initialise the firmware\n",
-			__func__);
-		return ret;
-	}
-
-	/* Write the command */
-	for (i = 0; i < cmd->len ; i++) {
-		dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]);
-		cx24116_writereg(state, i, cmd->args[i]);
-	}
-
-	/* Start execution and wait for cmd to terminate */
-	cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01);
-	while (cx24116_readreg(state, CX24116_REG_EXECUTE)) {
-		msleep(10);
-		if (i++ > 64) {
-			/* Avoid looping forever if the firmware does
-				not respond */
-			printk(KERN_WARNING "%s() Firmware not responding\n",
-				__func__);
-			return -EREMOTEIO;
-		}
-	}
-	return 0;
-}
-
-static int cx24116_load_firmware(struct dvb_frontend *fe,
-	const struct firmware *fw)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-	struct cx24116_cmd cmd;
-	int i, ret, len, max, remaining;
-	unsigned char vers[4];
-
-	dprintk("%s\n", __func__);
-	dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
-			fw->size,
-			fw->data[0],
-			fw->data[1],
-			fw->data[fw->size-2],
-			fw->data[fw->size-1]);
-
-	/* Toggle 88x SRST pin to reset demod */
-	if (state->config->reset_device)
-		state->config->reset_device(fe);
-
-	/* Begin the firmware load process */
-	/* Prepare the demod, load the firmware, cleanup after load */
-
-	/* Init PLL */
-	cx24116_writereg(state, 0xE5, 0x00);
-	cx24116_writereg(state, 0xF1, 0x08);
-	cx24116_writereg(state, 0xF2, 0x13);
-
-	/* Start PLL */
-	cx24116_writereg(state, 0xe0, 0x03);
-	cx24116_writereg(state, 0xe0, 0x00);
-
-	/* Unknown */
-	cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
-	cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
-
-	/* Unknown */
-	cx24116_writereg(state, 0xF0, 0x03);
-	cx24116_writereg(state, 0xF4, 0x81);
-	cx24116_writereg(state, 0xF5, 0x00);
-	cx24116_writereg(state, 0xF6, 0x00);
-
-	/* Split firmware to the max I2C write len and write.
-	 * Writes whole firmware as one write when i2c_wr_max is set to 0. */
-	if (state->config->i2c_wr_max)
-		max = state->config->i2c_wr_max;
-	else
-		max = INT_MAX; /* enough for 32k firmware */
-
-	for (remaining = fw->size; remaining > 0; remaining -= max - 1) {
-		len = remaining;
-		if (len > max - 1)
-			len = max - 1;
-
-		cx24116_writeregN(state, 0xF7, &fw->data[fw->size - remaining],
-			len);
-	}
-
-	cx24116_writereg(state, 0xF4, 0x10);
-	cx24116_writereg(state, 0xF0, 0x00);
-	cx24116_writereg(state, 0xF8, 0x06);
-
-	/* Firmware CMD 10: VCO config */
-	cmd.args[0x00] = CMD_SET_VCO;
-	cmd.args[0x01] = 0x05;
-	cmd.args[0x02] = 0xdc;
-	cmd.args[0x03] = 0xda;
-	cmd.args[0x04] = 0xae;
-	cmd.args[0x05] = 0xaa;
-	cmd.args[0x06] = 0x04;
-	cmd.args[0x07] = 0x9d;
-	cmd.args[0x08] = 0xfc;
-	cmd.args[0x09] = 0x06;
-	cmd.len = 0x0a;
-	ret = cx24116_cmd_execute(fe, &cmd);
-	if (ret != 0)
-		return ret;
-
-	cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00);
-
-	/* Firmware CMD 14: Tuner config */
-	cmd.args[0x00] = CMD_TUNERINIT;
-	cmd.args[0x01] = 0x00;
-	cmd.args[0x02] = 0x00;
-	cmd.len = 0x03;
-	ret = cx24116_cmd_execute(fe, &cmd);
-	if (ret != 0)
-		return ret;
-
-	cx24116_writereg(state, 0xe5, 0x00);
-
-	/* Firmware CMD 13: MPEG config */
-	cmd.args[0x00] = CMD_MPEGCONFIG;
-	cmd.args[0x01] = 0x01;
-	cmd.args[0x02] = 0x75;
-	cmd.args[0x03] = 0x00;
-	if (state->config->mpg_clk_pos_pol)
-		cmd.args[0x04] = state->config->mpg_clk_pos_pol;
-	else
-		cmd.args[0x04] = 0x02;
-	cmd.args[0x05] = 0x00;
-	cmd.len = 0x06;
-	ret = cx24116_cmd_execute(fe, &cmd);
-	if (ret != 0)
-		return ret;
-
-	/* Firmware CMD 35: Get firmware version */
-	cmd.args[0x00] = CMD_UPDFWVERS;
-	cmd.len = 0x02;
-	for (i = 0; i < 4; i++) {
-		cmd.args[0x01] = i;
-		ret = cx24116_cmd_execute(fe, &cmd);
-		if (ret != 0)
-			return ret;
-		vers[i] = cx24116_readreg(state, CX24116_REG_MAILBOX);
-	}
-	printk(KERN_INFO "%s: FW version %i.%i.%i.%i\n", __func__,
-		vers[0], vers[1], vers[2], vers[3]);
-
-	return 0;
-}
-
-static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-
-	int lock = cx24116_readreg(state, CX24116_REG_SSTATUS) &
-		CX24116_STATUS_MASK;
-
-	dprintk("%s: status = 0x%02x\n", __func__, lock);
-
-	*status = 0;
-
-	if (lock & CX24116_HAS_SIGNAL)
-		*status |= FE_HAS_SIGNAL;
-	if (lock & CX24116_HAS_CARRIER)
-		*status |= FE_HAS_CARRIER;
-	if (lock & CX24116_HAS_VITERBI)
-		*status |= FE_HAS_VITERBI;
-	if (lock & CX24116_HAS_SYNCLOCK)
-		*status |= FE_HAS_SYNC | FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int cx24116_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-
-	dprintk("%s()\n", __func__);
-
-	*ber =  (cx24116_readreg(state, CX24116_REG_BER24) << 24) |
-		(cx24116_readreg(state, CX24116_REG_BER16) << 16) |
-		(cx24116_readreg(state, CX24116_REG_BER8)  << 8)  |
-		 cx24116_readreg(state, CX24116_REG_BER0);
-
-	return 0;
-}
-
-/* TODO Determine function and scale appropriately */
-static int cx24116_read_signal_strength(struct dvb_frontend *fe,
-	u16 *signal_strength)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-	struct cx24116_cmd cmd;
-	int ret;
-	u16 sig_reading;
-
-	dprintk("%s()\n", __func__);
-
-	/* Firmware CMD 19: Get AGC */
-	cmd.args[0x00] = CMD_GETAGC;
-	cmd.len = 0x01;
-	ret = cx24116_cmd_execute(fe, &cmd);
-	if (ret != 0)
-		return ret;
-
-	sig_reading =
-		(cx24116_readreg(state,
-			CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK) |
-		(cx24116_readreg(state, CX24116_REG_SIGNAL) << 6);
-	*signal_strength = 0 - sig_reading;
-
-	dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n",
-		__func__, sig_reading, *signal_strength);
-
-	return 0;
-}
-
-/* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */
-static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-	u8 snr_reading;
-	static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
-		0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667,
-		0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667,
-		0x10000, 0x1199A, 0x13333, 0x14ccD, 0x16667,
-		0x18000 };
-
-	dprintk("%s()\n", __func__);
-
-	snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0);
-
-	if (snr_reading >= 0xa0 /* 100% */)
-		*snr = 0xffff;
-	else
-		*snr = snr_tab[(snr_reading & 0xf0) >> 4] +
-			(snr_tab[(snr_reading & 0x0f)] >> 4);
-
-	dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
-		snr_reading, *snr);
-
-	return 0;
-}
-
-/* The reelbox patches show the value in the registers represents
- * ESNO, from 0->30db (values 0->300). We provide this value by
- * default.
- */
-static int cx24116_read_snr_esno(struct dvb_frontend *fe, u16 *snr)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-
-	dprintk("%s()\n", __func__);
-
-	*snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 |
-		cx24116_readreg(state, CX24116_REG_QUALITY0);
-
-	dprintk("%s: raw 0x%04x\n", __func__, *snr);
-
-	return 0;
-}
-
-static int cx24116_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	if (esno_snr == 1)
-		return cx24116_read_snr_esno(fe, snr);
-	else
-		return cx24116_read_snr_pct(fe, snr);
-}
-
-static int cx24116_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-
-	dprintk("%s()\n", __func__);
-
-	*ucblocks = (cx24116_readreg(state, CX24116_REG_UCB8) << 8) |
-		cx24116_readreg(state, CX24116_REG_UCB0);
-
-	return 0;
-}
-
-/* Overwrite the current tuning params, we are about to tune */
-static void cx24116_clone_params(struct dvb_frontend *fe)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-	memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
-}
-
-/* Wait for LNB */
-static int cx24116_wait_for_lnb(struct dvb_frontend *fe)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-	int i;
-
-	dprintk("%s() qstatus = 0x%02x\n", __func__,
-		cx24116_readreg(state, CX24116_REG_QSTATUS));
-
-	/* Wait for up to 300 ms */
-	for (i = 0; i < 30 ; i++) {
-		if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20)
-			return 0;
-		msleep(10);
-	}
-
-	dprintk("%s(): LNB not ready\n", __func__);
-
-	return -ETIMEDOUT; /* -EBUSY ? */
-}
-
-static int cx24116_set_voltage(struct dvb_frontend *fe,
-	fe_sec_voltage_t voltage)
-{
-	struct cx24116_cmd cmd;
-	int ret;
-
-	dprintk("%s: %s\n", __func__,
-		voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
-		voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
-
-	/* Wait for LNB ready */
-	ret = cx24116_wait_for_lnb(fe);
-	if (ret != 0)
-		return ret;
-
-	/* Wait for voltage/min repeat delay */
-	msleep(100);
-
-	cmd.args[0x00] = CMD_LNBDCLEVEL;
-	cmd.args[0x01] = (voltage == SEC_VOLTAGE_18 ? 0x01 : 0x00);
-	cmd.len = 0x02;
-
-	/* Min delay time before DiSEqC send */
-	msleep(15);
-
-	return cx24116_cmd_execute(fe, &cmd);
-}
-
-static int cx24116_set_tone(struct dvb_frontend *fe,
-	fe_sec_tone_mode_t tone)
-{
-	struct cx24116_cmd cmd;
-	int ret;
-
-	dprintk("%s(%d)\n", __func__, tone);
-	if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
-		printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
-		return -EINVAL;
-	}
-
-	/* Wait for LNB ready */
-	ret = cx24116_wait_for_lnb(fe);
-	if (ret != 0)
-		return ret;
-
-	/* Min delay time after DiSEqC send */
-	msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
-
-	/* Now we set the tone */
-	cmd.args[0x00] = CMD_SET_TONE;
-	cmd.args[0x01] = 0x00;
-	cmd.args[0x02] = 0x00;
-
-	switch (tone) {
-	case SEC_TONE_ON:
-		dprintk("%s: setting tone on\n", __func__);
-		cmd.args[0x03] = 0x01;
-		break;
-	case SEC_TONE_OFF:
-		dprintk("%s: setting tone off\n", __func__);
-		cmd.args[0x03] = 0x00;
-		break;
-	}
-	cmd.len = 0x04;
-
-	/* Min delay time before DiSEqC send */
-	msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
-
-	return cx24116_cmd_execute(fe, &cmd);
-}
-
-/* Initialise DiSEqC */
-static int cx24116_diseqc_init(struct dvb_frontend *fe)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-	struct cx24116_cmd cmd;
-	int ret;
-
-	/* Firmware CMD 20: LNB/DiSEqC config */
-	cmd.args[0x00] = CMD_LNBCONFIG;
-	cmd.args[0x01] = 0x00;
-	cmd.args[0x02] = 0x10;
-	cmd.args[0x03] = 0x00;
-	cmd.args[0x04] = 0x8f;
-	cmd.args[0x05] = 0x28;
-	cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01;
-	cmd.args[0x07] = 0x01;
-	cmd.len = 0x08;
-	ret = cx24116_cmd_execute(fe, &cmd);
-	if (ret != 0)
-		return ret;
-
-	/* Prepare a DiSEqC command */
-	state->dsec_cmd.args[0x00] = CMD_LNBSEND;
-
-	/* DiSEqC burst */
-	state->dsec_cmd.args[CX24116_DISEQC_BURST]  = CX24116_DISEQC_MINI_A;
-
-	/* Unknown */
-	state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02;
-	state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00;
-	/* Continuation flag? */
-	state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00;
-
-	/* DiSEqC message length */
-	state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00;
-
-	/* Command length */
-	state->dsec_cmd.len = CX24116_DISEQC_MSGOFS;
-
-	return 0;
-}
-
-/* Send DiSEqC message with derived burst (hack) || previous burst */
-static int cx24116_send_diseqc_msg(struct dvb_frontend *fe,
-	struct dvb_diseqc_master_cmd *d)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-	int i, ret;
-
-	/* Dump DiSEqC message */
-	if (debug) {
-		printk(KERN_INFO "cx24116: %s(", __func__);
-		for (i = 0 ; i < d->msg_len ;) {
-			printk(KERN_INFO "0x%02x", d->msg[i]);
-			if (++i < d->msg_len)
-				printk(KERN_INFO ", ");
-		}
-		printk(") toneburst=%d\n", toneburst);
-	}
-
-	/* Validate length */
-	if (d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS))
-		return -EINVAL;
-
-	/* DiSEqC message */
-	for (i = 0; i < d->msg_len; i++)
-		state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i];
-
-	/* DiSEqC message length */
-	state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len;
-
-	/* Command length */
-	state->dsec_cmd.len = CX24116_DISEQC_MSGOFS +
-		state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
-
-	/* DiSEqC toneburst */
-	if (toneburst == CX24116_DISEQC_MESGCACHE)
-		/* Message is cached */
-		return 0;
-
-	else if (toneburst == CX24116_DISEQC_TONEOFF)
-		/* Message is sent without burst */
-		state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0;
-
-	else if (toneburst == CX24116_DISEQC_TONECACHE) {
-		/*
-		 * Message is sent with derived else cached burst
-		 *
-		 * WRITE PORT GROUP COMMAND 38
-		 *
-		 * 0/A/A: E0 10 38 F0..F3
-		 * 1/B/B: E0 10 38 F4..F7
-		 * 2/C/A: E0 10 38 F8..FB
-		 * 3/D/B: E0 10 38 FC..FF
-		 *
-		 * databyte[3]= 8421:8421
-		 *              ABCD:WXYZ
-		 *              CLR :SET
-		 *
-		 *              WX= PORT SELECT 0..3    (X=TONEBURST)
-		 *              Y = VOLTAGE             (0=13V, 1=18V)
-		 *              Z = BAND                (0=LOW, 1=HIGH(22K))
-		 */
-		if (d->msg_len >= 4 && d->msg[2] == 0x38)
-			state->dsec_cmd.args[CX24116_DISEQC_BURST] =
-				((d->msg[3] & 4) >> 2);
-		if (debug)
-			dprintk("%s burst=%d\n", __func__,
-				state->dsec_cmd.args[CX24116_DISEQC_BURST]);
-	}
-
-	/* Wait for LNB ready */
-	ret = cx24116_wait_for_lnb(fe);
-	if (ret != 0)
-		return ret;
-
-	/* Wait for voltage/min repeat delay */
-	msleep(100);
-
-	/* Command */
-	ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
-	if (ret != 0)
-		return ret;
-	/*
-	 * Wait for send
-	 *
-	 * Eutelsat spec:
-	 * >15ms delay          + (XXX determine if FW does this, see set_tone)
-	 *  13.5ms per byte     +
-	 * >15ms delay          +
-	 *  12.5ms burst        +
-	 * >15ms delay            (XXX determine if FW does this, see set_tone)
-	 */
-	msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) +
-		((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60));
-
-	return 0;
-}
-
-/* Send DiSEqC burst */
-static int cx24116_diseqc_send_burst(struct dvb_frontend *fe,
-	fe_sec_mini_cmd_t burst)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-	int ret;
-
-	dprintk("%s(%d) toneburst=%d\n", __func__, burst, toneburst);
-
-	/* DiSEqC burst */
-	if (burst == SEC_MINI_A)
-		state->dsec_cmd.args[CX24116_DISEQC_BURST] =
-			CX24116_DISEQC_MINI_A;
-	else if (burst == SEC_MINI_B)
-		state->dsec_cmd.args[CX24116_DISEQC_BURST] =
-			CX24116_DISEQC_MINI_B;
-	else
-		return -EINVAL;
-
-	/* DiSEqC toneburst */
-	if (toneburst != CX24116_DISEQC_MESGCACHE)
-		/* Burst is cached */
-		return 0;
-
-	/* Burst is to be sent with cached message */
-
-	/* Wait for LNB ready */
-	ret = cx24116_wait_for_lnb(fe);
-	if (ret != 0)
-		return ret;
-
-	/* Wait for voltage/min repeat delay */
-	msleep(100);
-
-	/* Command */
-	ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
-	if (ret != 0)
-		return ret;
-
-	/*
-	 * Wait for send
-	 *
-	 * Eutelsat spec:
-	 * >15ms delay          + (XXX determine if FW does this, see set_tone)
-	 *  13.5ms per byte     +
-	 * >15ms delay          +
-	 *  12.5ms burst        +
-	 * >15ms delay            (XXX determine if FW does this, see set_tone)
-	 */
-	msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60);
-
-	return 0;
-}
-
-static void cx24116_release(struct dvb_frontend *fe)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-	dprintk("%s\n", __func__);
-	kfree(state);
-}
-
-static struct dvb_frontend_ops cx24116_ops;
-
-struct dvb_frontend *cx24116_attach(const struct cx24116_config *config,
-	struct i2c_adapter *i2c)
-{
-	struct cx24116_state *state = NULL;
-	int ret;
-
-	dprintk("%s\n", __func__);
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct cx24116_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error1;
-
-	state->config = config;
-	state->i2c = i2c;
-
-	/* check if the demod is present */
-	ret = (cx24116_readreg(state, 0xFF) << 8) |
-		cx24116_readreg(state, 0xFE);
-	if (ret != 0x0501) {
-		printk(KERN_INFO "Invalid probe, probably not a CX24116 device\n");
-		goto error2;
-	}
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &cx24116_ops,
-		sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error2: kfree(state);
-error1: return NULL;
-}
-EXPORT_SYMBOL(cx24116_attach);
-
-/*
- * Initialise or wake up device
- *
- * Power config will reset and load initial firmware if required
- */
-static int cx24116_initfe(struct dvb_frontend *fe)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-	struct cx24116_cmd cmd;
-	int ret;
-
-	dprintk("%s()\n", __func__);
-
-	/* Power on */
-	cx24116_writereg(state, 0xe0, 0);
-	cx24116_writereg(state, 0xe1, 0);
-	cx24116_writereg(state, 0xea, 0);
-
-	/* Firmware CMD 36: Power config */
-	cmd.args[0x00] = CMD_TUNERSLEEP;
-	cmd.args[0x01] = 0;
-	cmd.len = 0x02;
-	ret = cx24116_cmd_execute(fe, &cmd);
-	if (ret != 0)
-		return ret;
-
-	ret = cx24116_diseqc_init(fe);
-	if (ret != 0)
-		return ret;
-
-	/* HVR-4000 needs this */
-	return cx24116_set_voltage(fe, SEC_VOLTAGE_13);
-}
-
-/*
- * Put device to sleep
- */
-static int cx24116_sleep(struct dvb_frontend *fe)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-	struct cx24116_cmd cmd;
-	int ret;
-
-	dprintk("%s()\n", __func__);
-
-	/* Firmware CMD 36: Power config */
-	cmd.args[0x00] = CMD_TUNERSLEEP;
-	cmd.args[0x01] = 1;
-	cmd.len = 0x02;
-	ret = cx24116_cmd_execute(fe, &cmd);
-	if (ret != 0)
-		return ret;
-
-	/* Power off (Shutdown clocks) */
-	cx24116_writereg(state, 0xea, 0xff);
-	cx24116_writereg(state, 0xe1, 1);
-	cx24116_writereg(state, 0xe0, 1);
-
-	return 0;
-}
-
-/* dvb-core told us to tune, the tv property cache will be complete,
- * it's safe for is to pull values and use them for tuning purposes.
- */
-static int cx24116_set_frontend(struct dvb_frontend *fe)
-{
-	struct cx24116_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct cx24116_cmd cmd;
-	fe_status_t tunerstat;
-	int i, status, ret, retune = 1;
-
-	dprintk("%s()\n", __func__);
-
-	switch (c->delivery_system) {
-	case SYS_DVBS:
-		dprintk("%s: DVB-S delivery system selected\n", __func__);
-
-		/* Only QPSK is supported for DVB-S */
-		if (c->modulation != QPSK) {
-			dprintk("%s: unsupported modulation selected (%d)\n",
-				__func__, c->modulation);
-			return -EOPNOTSUPP;
-		}
-
-		/* Pilot doesn't exist in DVB-S, turn bit off */
-		state->dnxt.pilot_val = CX24116_PILOT_OFF;
-
-		/* DVB-S only supports 0.35 */
-		if (c->rolloff != ROLLOFF_35) {
-			dprintk("%s: unsupported rolloff selected (%d)\n",
-				__func__, c->rolloff);
-			return -EOPNOTSUPP;
-		}
-		state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
-		break;
-
-	case SYS_DVBS2:
-		dprintk("%s: DVB-S2 delivery system selected\n", __func__);
-
-		/*
-		 * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2,
-		 * but not hardware auto detection
-		 */
-		if (c->modulation != PSK_8 && c->modulation != QPSK) {
-			dprintk("%s: unsupported modulation selected (%d)\n",
-				__func__, c->modulation);
-			return -EOPNOTSUPP;
-		}
-
-		switch (c->pilot) {
-		case PILOT_AUTO:	/* Not supported but emulated */
-			state->dnxt.pilot_val = (c->modulation == QPSK)
-				? CX24116_PILOT_OFF : CX24116_PILOT_ON;
-			retune++;
-			break;
-		case PILOT_OFF:
-			state->dnxt.pilot_val = CX24116_PILOT_OFF;
-			break;
-		case PILOT_ON:
-			state->dnxt.pilot_val = CX24116_PILOT_ON;
-			break;
-		default:
-			dprintk("%s: unsupported pilot mode selected (%d)\n",
-				__func__, c->pilot);
-			return -EOPNOTSUPP;
-		}
-
-		switch (c->rolloff) {
-		case ROLLOFF_20:
-			state->dnxt.rolloff_val = CX24116_ROLLOFF_020;
-			break;
-		case ROLLOFF_25:
-			state->dnxt.rolloff_val = CX24116_ROLLOFF_025;
-			break;
-		case ROLLOFF_35:
-			state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
-			break;
-		case ROLLOFF_AUTO:	/* Rolloff must be explicit */
-		default:
-			dprintk("%s: unsupported rolloff selected (%d)\n",
-				__func__, c->rolloff);
-			return -EOPNOTSUPP;
-		}
-		break;
-
-	default:
-		dprintk("%s: unsupported delivery system selected (%d)\n",
-			__func__, c->delivery_system);
-		return -EOPNOTSUPP;
-	}
-	state->dnxt.delsys = c->delivery_system;
-	state->dnxt.modulation = c->modulation;
-	state->dnxt.frequency = c->frequency;
-	state->dnxt.pilot = c->pilot;
-	state->dnxt.rolloff = c->rolloff;
-
-	ret = cx24116_set_inversion(state, c->inversion);
-	if (ret !=  0)
-		return ret;
-
-	/* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */
-	ret = cx24116_set_fec(state, c->delivery_system, c->modulation, c->fec_inner);
-	if (ret !=  0)
-		return ret;
-
-	ret = cx24116_set_symbolrate(state, c->symbol_rate);
-	if (ret !=  0)
-		return ret;
-
-	/* discard the 'current' tuning parameters and prepare to tune */
-	cx24116_clone_params(fe);
-
-	dprintk("%s:   delsys      = %d\n", __func__, state->dcur.delsys);
-	dprintk("%s:   modulation  = %d\n", __func__, state->dcur.modulation);
-	dprintk("%s:   frequency   = %d\n", __func__, state->dcur.frequency);
-	dprintk("%s:   pilot       = %d (val = 0x%02x)\n", __func__,
-		state->dcur.pilot, state->dcur.pilot_val);
-	dprintk("%s:   retune      = %d\n", __func__, retune);
-	dprintk("%s:   rolloff     = %d (val = 0x%02x)\n", __func__,
-		state->dcur.rolloff, state->dcur.rolloff_val);
-	dprintk("%s:   symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
-	dprintk("%s:   FEC         = %d (mask/val = 0x%02x/0x%02x)\n", __func__,
-		state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val);
-	dprintk("%s:   Inversion   = %d (val = 0x%02x)\n", __func__,
-		state->dcur.inversion, state->dcur.inversion_val);
-
-	/* This is also done in advise/acquire on HVR4000 but not on LITE */
-	if (state->config->set_ts_params)
-		state->config->set_ts_params(fe, 0);
-
-	/* Set/Reset B/W */
-	cmd.args[0x00] = CMD_BANDWIDTH;
-	cmd.args[0x01] = 0x01;
-	cmd.len = 0x02;
-	ret = cx24116_cmd_execute(fe, &cmd);
-	if (ret != 0)
-		return ret;
-
-	/* Prepare a tune request */
-	cmd.args[0x00] = CMD_TUNEREQUEST;
-
-	/* Frequency */
-	cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16;
-	cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8;
-	cmd.args[0x03] = (state->dcur.frequency & 0x0000ff);
-
-	/* Symbol Rate */
-	cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8;
-	cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff);
-
-	/* Automatic Inversion */
-	cmd.args[0x06] = state->dcur.inversion_val;
-
-	/* Modulation / FEC / Pilot */
-	cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val;
-
-	cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8;
-	cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff;
-	cmd.args[0x0a] = 0x00;
-	cmd.args[0x0b] = 0x00;
-	cmd.args[0x0c] = state->dcur.rolloff_val;
-	cmd.args[0x0d] = state->dcur.fec_mask;
-
-	if (state->dcur.symbol_rate > 30000000) {
-		cmd.args[0x0e] = 0x04;
-		cmd.args[0x0f] = 0x00;
-		cmd.args[0x10] = 0x01;
-		cmd.args[0x11] = 0x77;
-		cmd.args[0x12] = 0x36;
-		cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44);
-		cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01);
-	} else {
-		cmd.args[0x0e] = 0x06;
-		cmd.args[0x0f] = 0x00;
-		cmd.args[0x10] = 0x00;
-		cmd.args[0x11] = 0xFA;
-		cmd.args[0x12] = 0x24;
-		cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
-		cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
-	}
-
-	cmd.len = 0x13;
-
-	/* We need to support pilot and non-pilot tuning in the
-	 * driver automatically. This is a workaround for because
-	 * the demod does not support autodetect.
-	 */
-	do {
-		/* Reset status register */
-		status = cx24116_readreg(state, CX24116_REG_SSTATUS)
-			& CX24116_SIGNAL_MASK;
-		cx24116_writereg(state, CX24116_REG_SSTATUS, status);
-
-		/* Tune */
-		ret = cx24116_cmd_execute(fe, &cmd);
-		if (ret != 0)
-			break;
-
-		/*
-		 * Wait for up to 500 ms before retrying
-		 *
-		 * If we are able to tune then generally it occurs within 100ms.
-		 * If it takes longer, try a different toneburst setting.
-		 */
-		for (i = 0; i < 50 ; i++) {
-			cx24116_read_status(fe, &tunerstat);
-			status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC);
-			if (status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
-				dprintk("%s: Tuned\n", __func__);
-				goto tuned;
-			}
-			msleep(10);
-		}
-
-		dprintk("%s: Not tuned\n", __func__);
-
-		/* Toggle pilot bit when in auto-pilot */
-		if (state->dcur.pilot == PILOT_AUTO)
-			cmd.args[0x07] ^= CX24116_PILOT_ON;
-	} while (--retune);
-
-tuned:  /* Set/Reset B/W */
-	cmd.args[0x00] = CMD_BANDWIDTH;
-	cmd.args[0x01] = 0x00;
-	cmd.len = 0x02;
-	return cx24116_cmd_execute(fe, &cmd);
-}
-
-static int cx24116_tune(struct dvb_frontend *fe, bool re_tune,
-	unsigned int mode_flags, unsigned int *delay, fe_status_t *status)
-{
-	/*
-	 * It is safe to discard "params" here, as the DVB core will sync
-	 * fe->dtv_property_cache with fepriv->parameters_in, where the
-	 * DVBv3 params are stored. The only practical usage for it indicate
-	 * that re-tuning is needed, e. g. (fepriv->state & FESTATE_RETUNE) is
-	 * true.
-	 */
-
-	*delay = HZ / 5;
-	if (re_tune) {
-		int ret = cx24116_set_frontend(fe);
-		if (ret)
-			return ret;
-	}
-	return cx24116_read_status(fe, status);
-}
-
-static int cx24116_get_algo(struct dvb_frontend *fe)
-{
-	return DVBFE_ALGO_HW;
-}
-
-static struct dvb_frontend_ops cx24116_ops = {
-	.delsys = { SYS_DVBS, SYS_DVBS2 },
-	.info = {
-		.name = "Conexant CX24116/CX24118",
-		.frequency_min = 950000,
-		.frequency_max = 2150000,
-		.frequency_stepsize = 1011, /* kHz for QPSK frontends */
-		.frequency_tolerance = 5000,
-		.symbol_rate_min = 1000000,
-		.symbol_rate_max = 45000000,
-		.caps = FE_CAN_INVERSION_AUTO |
-			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
-			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_2G_MODULATION |
-			FE_CAN_QPSK | FE_CAN_RECOVER
-	},
-
-	.release = cx24116_release,
-
-	.init = cx24116_initfe,
-	.sleep = cx24116_sleep,
-	.read_status = cx24116_read_status,
-	.read_ber = cx24116_read_ber,
-	.read_signal_strength = cx24116_read_signal_strength,
-	.read_snr = cx24116_read_snr,
-	.read_ucblocks = cx24116_read_ucblocks,
-	.set_tone = cx24116_set_tone,
-	.set_voltage = cx24116_set_voltage,
-	.diseqc_send_master_cmd = cx24116_send_diseqc_msg,
-	.diseqc_send_burst = cx24116_diseqc_send_burst,
-	.get_frontend_algo = cx24116_get_algo,
-	.tune = cx24116_tune,
-
-	.set_frontend = cx24116_set_frontend,
-};
-
-MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware");
-MODULE_AUTHOR("Steven Toth");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/media/dvb/frontends/cx24116.h b/drivers/media/dvb/frontends/cx24116.h
deleted file mode 100644
index 7d90ab9..0000000
--- a/drivers/media/dvb/frontends/cx24116.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-    Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver
-
-    Copyright (C) 2006 Steven Toth <stoth@linuxtv.com>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef CX24116_H
-#define CX24116_H
-
-#include <linux/dvb/frontend.h>
-
-struct cx24116_config {
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* Need to set device param for start_dma */
-	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
-
-	/* Need to reset device during firmware loading */
-	int (*reset_device)(struct dvb_frontend *fe);
-
-	/* Need to set MPEG parameters */
-	u8 mpg_clk_pos_pol:0x02;
-
-	/* max bytes I2C provider can write at once */
-	u16 i2c_wr_max;
-};
-
-#if defined(CONFIG_DVB_CX24116) || \
-	(defined(CONFIG_DVB_CX24116_MODULE) && defined(MODULE))
-extern struct dvb_frontend *cx24116_attach(
-	const struct cx24116_config *config,
-	struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *cx24116_attach(
-	const struct cx24116_config *config,
-	struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* CX24116_H */
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
deleted file mode 100644
index 7e28b4e..0000000
--- a/drivers/media/dvb/frontends/cx24123.c
+++ /dev/null
@@ -1,1165 +0,0 @@
-/*
- *   Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
- *
- *   Copyright (C) 2005 Steven Toth <stoth@linuxtv.org>
- *
- *   Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc>
- *
- *   Support for CX24123/CX24113-NIM by Patrick Boettcher <pb@linuxtv.org>
- *
- *   This program is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU General Public License as
- *   published by the Free Software Foundation; either version 2 of
- *   the License, or (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *   General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include "dvb_frontend.h"
-#include "cx24123.h"
-
-#define XTAL 10111000
-
-static int force_band;
-module_param(force_band, int, 0644);
-MODULE_PARM_DESC(force_band, "Force a specific band select "\
-	"(1-9, default:off).");
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
-
-#define info(args...) do { printk(KERN_INFO "CX24123: " args); } while (0)
-#define err(args...)  do { printk(KERN_ERR  "CX24123: " args); } while (0)
-
-#define dprintk(args...) \
-	do { \
-		if (debug) { \
-			printk(KERN_DEBUG "CX24123: %s: ", __func__); \
-			printk(args); \
-		} \
-	} while (0)
-
-struct cx24123_state {
-	struct i2c_adapter *i2c;
-	const struct cx24123_config *config;
-
-	struct dvb_frontend frontend;
-
-	/* Some PLL specifics for tuning */
-	u32 VCAarg;
-	u32 VGAarg;
-	u32 bandselectarg;
-	u32 pllarg;
-	u32 FILTune;
-
-	struct i2c_adapter tuner_i2c_adapter;
-
-	u8 demod_rev;
-
-	/* The Demod/Tuner can't easily provide these, we cache them */
-	u32 currentfreq;
-	u32 currentsymbolrate;
-};
-
-/* Various tuner defaults need to be established for a given symbol rate Sps */
-static struct cx24123_AGC_val {
-	u32 symbolrate_low;
-	u32 symbolrate_high;
-	u32 VCAprogdata;
-	u32 VGAprogdata;
-	u32 FILTune;
-} cx24123_AGC_vals[] =
-{
-	{
-		.symbolrate_low		= 1000000,
-		.symbolrate_high	= 4999999,
-		/* the specs recommend other values for VGA offsets,
-		   but tests show they are wrong */
-		.VGAprogdata		= (1 << 19) | (0x180 << 9) | 0x1e0,
-		.VCAprogdata		= (2 << 19) | (0x07 << 9) | 0x07,
-		.FILTune		= 0x27f /* 0.41 V */
-	},
-	{
-		.symbolrate_low		=  5000000,
-		.symbolrate_high	= 14999999,
-		.VGAprogdata		= (1 << 19) | (0x180 << 9) | 0x1e0,
-		.VCAprogdata		= (2 << 19) | (0x07 << 9) | 0x1f,
-		.FILTune		= 0x317 /* 0.90 V */
-	},
-	{
-		.symbolrate_low		= 15000000,
-		.symbolrate_high	= 45000000,
-		.VGAprogdata		= (1 << 19) | (0x100 << 9) | 0x180,
-		.VCAprogdata		= (2 << 19) | (0x07 << 9) | 0x3f,
-		.FILTune		= 0x145 /* 2.70 V */
-	},
-};
-
-/*
- * Various tuner defaults need to be established for a given frequency kHz.
- * fixme: The bounds on the bands do not match the doc in real life.
- * fixme: Some of them have been moved, other might need adjustment.
- */
-static struct cx24123_bandselect_val {
-	u32 freq_low;
-	u32 freq_high;
-	u32 VCOdivider;
-	u32 progdata;
-} cx24123_bandselect_vals[] =
-{
-	/* band 1 */
-	{
-		.freq_low	= 950000,
-		.freq_high	= 1074999,
-		.VCOdivider	= 4,
-		.progdata	= (0 << 19) | (0 << 9) | 0x40,
-	},
-
-	/* band 2 */
-	{
-		.freq_low	= 1075000,
-		.freq_high	= 1177999,
-		.VCOdivider	= 4,
-		.progdata	= (0 << 19) | (0 << 9) | 0x80,
-	},
-
-	/* band 3 */
-	{
-		.freq_low	= 1178000,
-		.freq_high	= 1295999,
-		.VCOdivider	= 2,
-		.progdata	= (0 << 19) | (1 << 9) | 0x01,
-	},
-
-	/* band 4 */
-	{
-		.freq_low	= 1296000,
-		.freq_high	= 1431999,
-		.VCOdivider	= 2,
-		.progdata	= (0 << 19) | (1 << 9) | 0x02,
-	},
-
-	/* band 5 */
-	{
-		.freq_low	= 1432000,
-		.freq_high	= 1575999,
-		.VCOdivider	= 2,
-		.progdata	= (0 << 19) | (1 << 9) | 0x04,
-	},
-
-	/* band 6 */
-	{
-		.freq_low	= 1576000,
-		.freq_high	= 1717999,
-		.VCOdivider	= 2,
-		.progdata	= (0 << 19) | (1 << 9) | 0x08,
-	},
-
-	/* band 7 */
-	{
-		.freq_low	= 1718000,
-		.freq_high	= 1855999,
-		.VCOdivider	= 2,
-		.progdata	= (0 << 19) | (1 << 9) | 0x10,
-	},
-
-	/* band 8 */
-	{
-		.freq_low	= 1856000,
-		.freq_high	= 2035999,
-		.VCOdivider	= 2,
-		.progdata	= (0 << 19) | (1 << 9) | 0x20,
-	},
-
-	/* band 9 */
-	{
-		.freq_low	= 2036000,
-		.freq_high	= 2150000,
-		.VCOdivider	= 2,
-		.progdata	= (0 << 19) | (1 << 9) | 0x40,
-	},
-};
-
-static struct {
-	u8 reg;
-	u8 data;
-} cx24123_regdata[] =
-{
-	{0x00, 0x03}, /* Reset system */
-	{0x00, 0x00}, /* Clear reset */
-	{0x03, 0x07}, /* QPSK, DVB, Auto Acquisition (default) */
-	{0x04, 0x10}, /* MPEG */
-	{0x05, 0x04}, /* MPEG */
-	{0x06, 0x31}, /* MPEG (default) */
-	{0x0b, 0x00}, /* Freq search start point (default) */
-	{0x0c, 0x00}, /* Demodulator sample gain (default) */
-	{0x0d, 0x7f}, /* Force driver to shift until the maximum (+-10 MHz) */
-	{0x0e, 0x03}, /* Default non-inverted, FEC 3/4 (default) */
-	{0x0f, 0xfe}, /* FEC search mask (all supported codes) */
-	{0x10, 0x01}, /* Default search inversion, no repeat (default) */
-	{0x16, 0x00}, /* Enable reading of frequency */
-	{0x17, 0x01}, /* Enable EsNO Ready Counter */
-	{0x1c, 0x80}, /* Enable error counter */
-	{0x20, 0x00}, /* Tuner burst clock rate = 500KHz */
-	{0x21, 0x15}, /* Tuner burst mode, word length = 0x15 */
-	{0x28, 0x00}, /* Enable FILTERV with positive pol., DiSEqC 2.x off */
-	{0x29, 0x00}, /* DiSEqC LNB_DC off */
-	{0x2a, 0xb0}, /* DiSEqC Parameters (default) */
-	{0x2b, 0x73}, /* DiSEqC Tone Frequency (default) */
-	{0x2c, 0x00}, /* DiSEqC Message (0x2c - 0x31) */
-	{0x2d, 0x00},
-	{0x2e, 0x00},
-	{0x2f, 0x00},
-	{0x30, 0x00},
-	{0x31, 0x00},
-	{0x32, 0x8c}, /* DiSEqC Parameters (default) */
-	{0x33, 0x00}, /* Interrupts off (0x33 - 0x34) */
-	{0x34, 0x00},
-	{0x35, 0x03}, /* DiSEqC Tone Amplitude (default) */
-	{0x36, 0x02}, /* DiSEqC Parameters (default) */
-	{0x37, 0x3a}, /* DiSEqC Parameters (default) */
-	{0x3a, 0x00}, /* Enable AGC accumulator (for signal strength) */
-	{0x44, 0x00}, /* Constellation (default) */
-	{0x45, 0x00}, /* Symbol count (default) */
-	{0x46, 0x0d}, /* Symbol rate estimator on (default) */
-	{0x56, 0xc1}, /* Error Counter = Viterbi BER */
-	{0x57, 0xff}, /* Error Counter Window (default) */
-	{0x5c, 0x20}, /* Acquisition AFC Expiration window (default is 0x10) */
-	{0x67, 0x83}, /* Non-DCII symbol clock */
-};
-
-static int cx24123_i2c_writereg(struct cx24123_state *state,
-	u8 i2c_addr, int reg, int data)
-{
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = {
-		.addr = i2c_addr, .flags = 0, .buf = buf, .len = 2
-	};
-	int err;
-
-	/* printk(KERN_DEBUG "wr(%02x): %02x %02x\n", i2c_addr, reg, data); */
-
-	err = i2c_transfer(state->i2c, &msg, 1);
-	if (err != 1) {
-		printk("%s: writereg error(err == %i, reg == 0x%02x,"
-			 " data == 0x%02x)\n", __func__, err, reg, data);
-		return err;
-	}
-
-	return 0;
-}
-
-static int cx24123_i2c_readreg(struct cx24123_state *state, u8 i2c_addr, u8 reg)
-{
-	int ret;
-	u8 b = 0;
-	struct i2c_msg msg[] = {
-		{ .addr = i2c_addr, .flags = 0, .buf = &reg, .len = 1 },
-		{ .addr = i2c_addr, .flags = I2C_M_RD, .buf = &b, .len = 1 }
-	};
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2) {
-		err("%s: reg=0x%x (error=%d)\n", __func__, reg, ret);
-		return ret;
-	}
-
-	/* printk(KERN_DEBUG "rd(%02x): %02x %02x\n", i2c_addr, reg, b); */
-
-	return b;
-}
-
-#define cx24123_readreg(state, reg) \
-	cx24123_i2c_readreg(state, state->config->demod_address, reg)
-#define cx24123_writereg(state, reg, val) \
-	cx24123_i2c_writereg(state, state->config->demod_address, reg, val)
-
-static int cx24123_set_inversion(struct cx24123_state *state,
-	fe_spectral_inversion_t inversion)
-{
-	u8 nom_reg = cx24123_readreg(state, 0x0e);
-	u8 auto_reg = cx24123_readreg(state, 0x10);
-
-	switch (inversion) {
-	case INVERSION_OFF:
-		dprintk("inversion off\n");
-		cx24123_writereg(state, 0x0e, nom_reg & ~0x80);
-		cx24123_writereg(state, 0x10, auto_reg | 0x80);
-		break;
-	case INVERSION_ON:
-		dprintk("inversion on\n");
-		cx24123_writereg(state, 0x0e, nom_reg | 0x80);
-		cx24123_writereg(state, 0x10, auto_reg | 0x80);
-		break;
-	case INVERSION_AUTO:
-		dprintk("inversion auto\n");
-		cx24123_writereg(state, 0x10, auto_reg & ~0x80);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int cx24123_get_inversion(struct cx24123_state *state,
-	fe_spectral_inversion_t *inversion)
-{
-	u8 val;
-
-	val = cx24123_readreg(state, 0x1b) >> 7;
-
-	if (val == 0) {
-		dprintk("read inversion off\n");
-		*inversion = INVERSION_OFF;
-	} else {
-		dprintk("read inversion on\n");
-		*inversion = INVERSION_ON;
-	}
-
-	return 0;
-}
-
-static int cx24123_set_fec(struct cx24123_state *state, fe_code_rate_t fec)
-{
-	u8 nom_reg = cx24123_readreg(state, 0x0e) & ~0x07;
-
-	if ((fec < FEC_NONE) || (fec > FEC_AUTO))
-		fec = FEC_AUTO;
-
-	/* Set the soft decision threshold */
-	if (fec == FEC_1_2)
-		cx24123_writereg(state, 0x43,
-			cx24123_readreg(state, 0x43) | 0x01);
-	else
-		cx24123_writereg(state, 0x43,
-			cx24123_readreg(state, 0x43) & ~0x01);
-
-	switch (fec) {
-	case FEC_1_2:
-		dprintk("set FEC to 1/2\n");
-		cx24123_writereg(state, 0x0e, nom_reg | 0x01);
-		cx24123_writereg(state, 0x0f, 0x02);
-		break;
-	case FEC_2_3:
-		dprintk("set FEC to 2/3\n");
-		cx24123_writereg(state, 0x0e, nom_reg | 0x02);
-		cx24123_writereg(state, 0x0f, 0x04);
-		break;
-	case FEC_3_4:
-		dprintk("set FEC to 3/4\n");
-		cx24123_writereg(state, 0x0e, nom_reg | 0x03);
-		cx24123_writereg(state, 0x0f, 0x08);
-		break;
-	case FEC_4_5:
-		dprintk("set FEC to 4/5\n");
-		cx24123_writereg(state, 0x0e, nom_reg | 0x04);
-		cx24123_writereg(state, 0x0f, 0x10);
-		break;
-	case FEC_5_6:
-		dprintk("set FEC to 5/6\n");
-		cx24123_writereg(state, 0x0e, nom_reg | 0x05);
-		cx24123_writereg(state, 0x0f, 0x20);
-		break;
-	case FEC_6_7:
-		dprintk("set FEC to 6/7\n");
-		cx24123_writereg(state, 0x0e, nom_reg | 0x06);
-		cx24123_writereg(state, 0x0f, 0x40);
-		break;
-	case FEC_7_8:
-		dprintk("set FEC to 7/8\n");
-		cx24123_writereg(state, 0x0e, nom_reg | 0x07);
-		cx24123_writereg(state, 0x0f, 0x80);
-		break;
-	case FEC_AUTO:
-		dprintk("set FEC to auto\n");
-		cx24123_writereg(state, 0x0f, 0xfe);
-		break;
-	default:
-		return -EOPNOTSUPP;
-	}
-
-	return 0;
-}
-
-static int cx24123_get_fec(struct cx24123_state *state, fe_code_rate_t *fec)
-{
-	int ret;
-
-	ret = cx24123_readreg(state, 0x1b);
-	if (ret < 0)
-		return ret;
-	ret = ret & 0x07;
-
-	switch (ret) {
-	case 1:
-		*fec = FEC_1_2;
-		break;
-	case 2:
-		*fec = FEC_2_3;
-		break;
-	case 3:
-		*fec = FEC_3_4;
-		break;
-	case 4:
-		*fec = FEC_4_5;
-		break;
-	case 5:
-		*fec = FEC_5_6;
-		break;
-	case 6:
-		*fec = FEC_6_7;
-		break;
-	case 7:
-		*fec = FEC_7_8;
-		break;
-	default:
-		/* this can happen when there's no lock */
-		*fec = FEC_NONE;
-	}
-
-	return 0;
-}
-
-/* Approximation of closest integer of log2(a/b). It actually gives the
-   lowest integer i such that 2^i >= round(a/b) */
-static u32 cx24123_int_log2(u32 a, u32 b)
-{
-	u32 exp, nearest = 0;
-	u32 div = a / b;
-	if (a % b >= b / 2)
-		++div;
-	if (div < (1 << 31)) {
-		for (exp = 1; div > exp; nearest++)
-			exp += exp;
-	}
-	return nearest;
-}
-
-static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate)
-{
-	u32 tmp, sample_rate, ratio, sample_gain;
-	u8 pll_mult;
-
-	/*  check if symbol rate is within limits */
-	if ((srate > state->frontend.ops.info.symbol_rate_max) ||
-	    (srate < state->frontend.ops.info.symbol_rate_min))
-		return -EOPNOTSUPP;
-
-	/* choose the sampling rate high enough for the required operation,
-	   while optimizing the power consumed by the demodulator */
-	if (srate < (XTAL*2)/2)
-		pll_mult = 2;
-	else if (srate < (XTAL*3)/2)
-		pll_mult = 3;
-	else if (srate < (XTAL*4)/2)
-		pll_mult = 4;
-	else if (srate < (XTAL*5)/2)
-		pll_mult = 5;
-	else if (srate < (XTAL*6)/2)
-		pll_mult = 6;
-	else if (srate < (XTAL*7)/2)
-		pll_mult = 7;
-	else if (srate < (XTAL*8)/2)
-		pll_mult = 8;
-	else
-		pll_mult = 9;
-
-
-	sample_rate = pll_mult * XTAL;
-
-	/*
-	    SYSSymbolRate[21:0] = (srate << 23) / sample_rate
-
-	    We have to use 32 bit unsigned arithmetic without precision loss.
-	    The maximum srate is 45000000 or 0x02AEA540. This number has
-	    only 6 clear bits on top, hence we can shift it left only 6 bits
-	    at a time. Borrowed from cx24110.c
-	*/
-
-	tmp = srate << 6;
-	ratio = tmp / sample_rate;
-
-	tmp = (tmp % sample_rate) << 6;
-	ratio = (ratio << 6) + (tmp / sample_rate);
-
-	tmp = (tmp % sample_rate) << 6;
-	ratio = (ratio << 6) + (tmp / sample_rate);
-
-	tmp = (tmp % sample_rate) << 5;
-	ratio = (ratio << 5) + (tmp / sample_rate);
-
-
-	cx24123_writereg(state, 0x01, pll_mult * 6);
-
-	cx24123_writereg(state, 0x08, (ratio >> 16) & 0x3f);
-	cx24123_writereg(state, 0x09, (ratio >> 8) & 0xff);
-	cx24123_writereg(state, 0x0a, ratio & 0xff);
-
-	/* also set the demodulator sample gain */
-	sample_gain = cx24123_int_log2(sample_rate, srate);
-	tmp = cx24123_readreg(state, 0x0c) & ~0xe0;
-	cx24123_writereg(state, 0x0c, tmp | sample_gain << 5);
-
-	dprintk("srate=%d, ratio=0x%08x, sample_rate=%i sample_gain=%d\n",
-		srate, ratio, sample_rate, sample_gain);
-
-	return 0;
-}
-
-/*
- * Based on the required frequency and symbolrate, the tuner AGC has
- * to be configured and the correct band selected.
- * Calculate those values.
- */
-static int cx24123_pll_calculate(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct cx24123_state *state = fe->demodulator_priv;
-	u32 ndiv = 0, adiv = 0, vco_div = 0;
-	int i = 0;
-	int pump = 2;
-	int band = 0;
-	int num_bands = ARRAY_SIZE(cx24123_bandselect_vals);
-	struct cx24123_bandselect_val *bsv = NULL;
-	struct cx24123_AGC_val *agcv = NULL;
-
-	/* Defaults for low freq, low rate */
-	state->VCAarg = cx24123_AGC_vals[0].VCAprogdata;
-	state->VGAarg = cx24123_AGC_vals[0].VGAprogdata;
-	state->bandselectarg = cx24123_bandselect_vals[0].progdata;
-	vco_div = cx24123_bandselect_vals[0].VCOdivider;
-
-	/* For the given symbol rate, determine the VCA, VGA and
-	 * FILTUNE programming bits */
-	for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++) {
-		agcv = &cx24123_AGC_vals[i];
-		if ((agcv->symbolrate_low <= p->symbol_rate) &&
-		    (agcv->symbolrate_high >= p->symbol_rate)) {
-			state->VCAarg = agcv->VCAprogdata;
-			state->VGAarg = agcv->VGAprogdata;
-			state->FILTune = agcv->FILTune;
-		}
-	}
-
-	/* determine the band to use */
-	if (force_band < 1 || force_band > num_bands) {
-		for (i = 0; i < num_bands; i++) {
-			bsv = &cx24123_bandselect_vals[i];
-			if ((bsv->freq_low <= p->frequency) &&
-				(bsv->freq_high >= p->frequency))
-				band = i;
-		}
-	} else
-		band = force_band - 1;
-
-	state->bandselectarg = cx24123_bandselect_vals[band].progdata;
-	vco_div = cx24123_bandselect_vals[band].VCOdivider;
-
-	/* determine the charge pump current */
-	if (p->frequency < (cx24123_bandselect_vals[band].freq_low +
-		cx24123_bandselect_vals[band].freq_high) / 2)
-		pump = 0x01;
-	else
-		pump = 0x02;
-
-	/* Determine the N/A dividers for the requested lband freq (in kHz). */
-	/* Note: the reference divider R=10, frequency is in KHz,
-	 * XTAL is in Hz */
-	ndiv = (((p->frequency * vco_div * 10) /
-		(2 * XTAL / 1000)) / 32) & 0x1ff;
-	adiv = (((p->frequency * vco_div * 10) /
-		(2 * XTAL / 1000)) % 32) & 0x1f;
-
-	if (adiv == 0 && ndiv > 0)
-		ndiv--;
-
-	/* control bits 11, refdiv 11, charge pump polarity 1,
-	 * charge pump current, ndiv, adiv */
-	state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) |
-		(pump << 14) | (ndiv << 5) | adiv;
-
-	return 0;
-}
-
-/*
- * Tuner data is 21 bits long, must be left-aligned in data.
- * Tuner cx24109 is written through a dedicated 3wire interface
- * on the demod chip.
- */
-static int cx24123_pll_writereg(struct dvb_frontend *fe, u32 data)
-{
-	struct cx24123_state *state = fe->demodulator_priv;
-	unsigned long timeout;
-
-	dprintk("pll writereg called, data=0x%08x\n", data);
-
-	/* align the 21 bytes into to bit23 boundary */
-	data = data << 3;
-
-	/* Reset the demod pll word length to 0x15 bits */
-	cx24123_writereg(state, 0x21, 0x15);
-
-	/* write the msb 8 bits, wait for the send to be completed */
-	timeout = jiffies + msecs_to_jiffies(40);
-	cx24123_writereg(state, 0x22, (data >> 16) & 0xff);
-	while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
-		if (time_after(jiffies, timeout)) {
-			err("%s:  demodulator is not responding, "\
-				"possibly hung, aborting.\n", __func__);
-			return -EREMOTEIO;
-		}
-		msleep(10);
-	}
-
-	/* send another 8 bytes, wait for the send to be completed */
-	timeout = jiffies + msecs_to_jiffies(40);
-	cx24123_writereg(state, 0x22, (data >> 8) & 0xff);
-	while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
-		if (time_after(jiffies, timeout)) {
-			err("%s:  demodulator is not responding, "\
-				"possibly hung, aborting.\n", __func__);
-			return -EREMOTEIO;
-		}
-		msleep(10);
-	}
-
-	/* send the lower 5 bits of this byte, padded with 3 LBB,
-	 * wait for the send to be completed */
-	timeout = jiffies + msecs_to_jiffies(40);
-	cx24123_writereg(state, 0x22, (data) & 0xff);
-	while ((cx24123_readreg(state, 0x20) & 0x80)) {
-		if (time_after(jiffies, timeout)) {
-			err("%s:  demodulator is not responding," \
-				"possibly hung, aborting.\n", __func__);
-			return -EREMOTEIO;
-		}
-		msleep(10);
-	}
-
-	/* Trigger the demod to configure the tuner */
-	cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) | 2);
-	cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) & 0xfd);
-
-	return 0;
-}
-
-static int cx24123_pll_tune(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct cx24123_state *state = fe->demodulator_priv;
-	u8 val;
-
-	dprintk("frequency=%i\n", p->frequency);
-
-	if (cx24123_pll_calculate(fe) != 0) {
-		err("%s: cx24123_pll_calcutate failed\n", __func__);
-		return -EINVAL;
-	}
-
-	/* Write the new VCO/VGA */
-	cx24123_pll_writereg(fe, state->VCAarg);
-	cx24123_pll_writereg(fe, state->VGAarg);
-
-	/* Write the new bandselect and pll args */
-	cx24123_pll_writereg(fe, state->bandselectarg);
-	cx24123_pll_writereg(fe, state->pllarg);
-
-	/* set the FILTUNE voltage */
-	val = cx24123_readreg(state, 0x28) & ~0x3;
-	cx24123_writereg(state, 0x27, state->FILTune >> 2);
-	cx24123_writereg(state, 0x28, val | (state->FILTune & 0x3));
-
-	dprintk("pll tune VCA=%d, band=%d, pll=%d\n", state->VCAarg,
-			state->bandselectarg, state->pllarg);
-
-	return 0;
-}
-
-
-/*
- * 0x23:
- *    [7:7] = BTI enabled
- *    [6:6] = I2C repeater enabled
- *    [5:5] = I2C repeater start
- *    [0:0] = BTI start
- */
-
-/* mode == 1 -> i2c-repeater, 0 -> bti */
-static int cx24123_repeater_mode(struct cx24123_state *state, u8 mode, u8 start)
-{
-	u8 r = cx24123_readreg(state, 0x23) & 0x1e;
-	if (mode)
-		r |= (1 << 6) | (start << 5);
-	else
-		r |= (1 << 7) | (start);
-	return cx24123_writereg(state, 0x23, r);
-}
-
-static int cx24123_initfe(struct dvb_frontend *fe)
-{
-	struct cx24123_state *state = fe->demodulator_priv;
-	int i;
-
-	dprintk("init frontend\n");
-
-	/* Configure the demod to a good set of defaults */
-	for (i = 0; i < ARRAY_SIZE(cx24123_regdata); i++)
-		cx24123_writereg(state, cx24123_regdata[i].reg,
-			cx24123_regdata[i].data);
-
-	/* Set the LNB polarity */
-	if (state->config->lnb_polarity)
-		cx24123_writereg(state, 0x32,
-			cx24123_readreg(state, 0x32) | 0x02);
-
-	if (state->config->dont_use_pll)
-		cx24123_repeater_mode(state, 1, 0);
-
-	return 0;
-}
-
-static int cx24123_set_voltage(struct dvb_frontend *fe,
-	fe_sec_voltage_t voltage)
-{
-	struct cx24123_state *state = fe->demodulator_priv;
-	u8 val;
-
-	val = cx24123_readreg(state, 0x29) & ~0x40;
-
-	switch (voltage) {
-	case SEC_VOLTAGE_13:
-		dprintk("setting voltage 13V\n");
-		return cx24123_writereg(state, 0x29, val & 0x7f);
-	case SEC_VOLTAGE_18:
-		dprintk("setting voltage 18V\n");
-		return cx24123_writereg(state, 0x29, val | 0x80);
-	case SEC_VOLTAGE_OFF:
-		/* already handled in cx88-dvb */
-		return 0;
-	default:
-		return -EINVAL;
-	};
-
-	return 0;
-}
-
-/* wait for diseqc queue to become ready (or timeout) */
-static void cx24123_wait_for_diseqc(struct cx24123_state *state)
-{
-	unsigned long timeout = jiffies + msecs_to_jiffies(200);
-	while (!(cx24123_readreg(state, 0x29) & 0x40)) {
-		if (time_after(jiffies, timeout)) {
-			err("%s: diseqc queue not ready, " \
-				"command may be lost.\n", __func__);
-			break;
-		}
-		msleep(10);
-	}
-}
-
-static int cx24123_send_diseqc_msg(struct dvb_frontend *fe,
-	struct dvb_diseqc_master_cmd *cmd)
-{
-	struct cx24123_state *state = fe->demodulator_priv;
-	int i, val, tone;
-
-	dprintk("\n");
-
-	/* stop continuous tone if enabled */
-	tone = cx24123_readreg(state, 0x29);
-	if (tone & 0x10)
-		cx24123_writereg(state, 0x29, tone & ~0x50);
-
-	/* wait for diseqc queue ready */
-	cx24123_wait_for_diseqc(state);
-
-	/* select tone mode */
-	cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
-
-	for (i = 0; i < cmd->msg_len; i++)
-		cx24123_writereg(state, 0x2C + i, cmd->msg[i]);
-
-	val = cx24123_readreg(state, 0x29);
-	cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40) |
-		((cmd->msg_len-3) & 3));
-
-	/* wait for diseqc message to finish sending */
-	cx24123_wait_for_diseqc(state);
-
-	/* restart continuous tone if enabled */
-	if (tone & 0x10)
-		cx24123_writereg(state, 0x29, tone & ~0x40);
-
-	return 0;
-}
-
-static int cx24123_diseqc_send_burst(struct dvb_frontend *fe,
-	fe_sec_mini_cmd_t burst)
-{
-	struct cx24123_state *state = fe->demodulator_priv;
-	int val, tone;
-
-	dprintk("\n");
-
-	/* stop continuous tone if enabled */
-	tone = cx24123_readreg(state, 0x29);
-	if (tone & 0x10)
-		cx24123_writereg(state, 0x29, tone & ~0x50);
-
-	/* wait for diseqc queue ready */
-	cx24123_wait_for_diseqc(state);
-
-	/* select tone mode */
-	cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) | 0x4);
-	msleep(30);
-	val = cx24123_readreg(state, 0x29);
-	if (burst == SEC_MINI_A)
-		cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00));
-	else if (burst == SEC_MINI_B)
-		cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x08));
-	else
-		return -EINVAL;
-
-	cx24123_wait_for_diseqc(state);
-	cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
-
-	/* restart continuous tone if enabled */
-	if (tone & 0x10)
-		cx24123_writereg(state, 0x29, tone & ~0x40);
-
-	return 0;
-}
-
-static int cx24123_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct cx24123_state *state = fe->demodulator_priv;
-	int sync = cx24123_readreg(state, 0x14);
-
-	*status = 0;
-	if (state->config->dont_use_pll) {
-		u32 tun_status = 0;
-		if (fe->ops.tuner_ops.get_status)
-			fe->ops.tuner_ops.get_status(fe, &tun_status);
-		if (tun_status & TUNER_STATUS_LOCKED)
-			*status |= FE_HAS_SIGNAL;
-	} else {
-		int lock = cx24123_readreg(state, 0x20);
-		if (lock & 0x01)
-			*status |= FE_HAS_SIGNAL;
-	}
-
-	if (sync & 0x02)
-		*status |= FE_HAS_CARRIER;	/* Phase locked */
-	if (sync & 0x04)
-		*status |= FE_HAS_VITERBI;
-
-	/* Reed-Solomon Status */
-	if (sync & 0x08)
-		*status |= FE_HAS_SYNC;
-	if (sync & 0x80)
-		*status |= FE_HAS_LOCK;		/*Full Sync */
-
-	return 0;
-}
-
-/*
- * Configured to return the measurement of errors in blocks,
- * because no UCBLOCKS value is available, so this value doubles up
- * to satisfy both measurements.
- */
-static int cx24123_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct cx24123_state *state = fe->demodulator_priv;
-
-	/* The true bit error rate is this value divided by
-	   the window size (set as 256 * 255) */
-	*ber = ((cx24123_readreg(state, 0x1c) & 0x3f) << 16) |
-		(cx24123_readreg(state, 0x1d) << 8 |
-		 cx24123_readreg(state, 0x1e));
-
-	dprintk("BER = %d\n", *ber);
-
-	return 0;
-}
-
-static int cx24123_read_signal_strength(struct dvb_frontend *fe,
-	u16 *signal_strength)
-{
-	struct cx24123_state *state = fe->demodulator_priv;
-
-	/* larger = better */
-	*signal_strength = cx24123_readreg(state, 0x3b) << 8;
-
-	dprintk("Signal strength = %d\n", *signal_strength);
-
-	return 0;
-}
-
-static int cx24123_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct cx24123_state *state = fe->demodulator_priv;
-
-	/* Inverted raw Es/N0 count, totally bogus but better than the
-	   BER threshold. */
-	*snr = 65535 - (((u16)cx24123_readreg(state, 0x18) << 8) |
-			 (u16)cx24123_readreg(state, 0x19));
-
-	dprintk("read S/N index = %d\n", *snr);
-
-	return 0;
-}
-
-static int cx24123_set_frontend(struct dvb_frontend *fe)
-{
-	struct cx24123_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-
-	dprintk("\n");
-
-	if (state->config->set_ts_params)
-		state->config->set_ts_params(fe, 0);
-
-	state->currentfreq = p->frequency;
-	state->currentsymbolrate = p->symbol_rate;
-
-	cx24123_set_inversion(state, p->inversion);
-	cx24123_set_fec(state, p->fec_inner);
-	cx24123_set_symbolrate(state, p->symbol_rate);
-
-	if (!state->config->dont_use_pll)
-		cx24123_pll_tune(fe);
-	else if (fe->ops.tuner_ops.set_params)
-		fe->ops.tuner_ops.set_params(fe);
-	else
-		err("it seems I don't have a tuner...");
-
-	/* Enable automatic acquisition and reset cycle */
-	cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07));
-	cx24123_writereg(state, 0x00, 0x10);
-	cx24123_writereg(state, 0x00, 0);
-
-	if (state->config->agc_callback)
-		state->config->agc_callback(fe);
-
-	return 0;
-}
-
-static int cx24123_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct cx24123_state *state = fe->demodulator_priv;
-
-	dprintk("\n");
-
-	if (cx24123_get_inversion(state, &p->inversion) != 0) {
-		err("%s: Failed to get inversion status\n", __func__);
-		return -EREMOTEIO;
-	}
-	if (cx24123_get_fec(state, &p->fec_inner) != 0) {
-		err("%s: Failed to get fec status\n", __func__);
-		return -EREMOTEIO;
-	}
-	p->frequency = state->currentfreq;
-	p->symbol_rate = state->currentsymbolrate;
-
-	return 0;
-}
-
-static int cx24123_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
-{
-	struct cx24123_state *state = fe->demodulator_priv;
-	u8 val;
-
-	/* wait for diseqc queue ready */
-	cx24123_wait_for_diseqc(state);
-
-	val = cx24123_readreg(state, 0x29) & ~0x40;
-
-	switch (tone) {
-	case SEC_TONE_ON:
-		dprintk("setting tone on\n");
-		return cx24123_writereg(state, 0x29, val | 0x10);
-	case SEC_TONE_OFF:
-		dprintk("setting tone off\n");
-		return cx24123_writereg(state, 0x29, val & 0xef);
-	default:
-		err("CASE reached default with tone=%d\n", tone);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int cx24123_tune(struct dvb_frontend *fe,
-			bool re_tune,
-			unsigned int mode_flags,
-			unsigned int *delay,
-			fe_status_t *status)
-{
-	int retval = 0;
-
-	if (re_tune)
-		retval = cx24123_set_frontend(fe);
-
-	if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
-		cx24123_read_status(fe, status);
-	*delay = HZ/10;
-
-	return retval;
-}
-
-static int cx24123_get_algo(struct dvb_frontend *fe)
-{
-	return 1; /* FE_ALGO_HW */
-}
-
-static void cx24123_release(struct dvb_frontend *fe)
-{
-	struct cx24123_state *state = fe->demodulator_priv;
-	dprintk("\n");
-	i2c_del_adapter(&state->tuner_i2c_adapter);
-	kfree(state);
-}
-
-static int cx24123_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap,
-	struct i2c_msg msg[], int num)
-{
-	struct cx24123_state *state = i2c_get_adapdata(i2c_adap);
-	/* this repeater closes after the first stop */
-	cx24123_repeater_mode(state, 1, 1);
-	return i2c_transfer(state->i2c, msg, num);
-}
-
-static u32 cx24123_tuner_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm cx24123_tuner_i2c_algo = {
-	.master_xfer   = cx24123_tuner_i2c_tuner_xfer,
-	.functionality = cx24123_tuner_i2c_func,
-};
-
-struct i2c_adapter *
-	cx24123_get_tuner_i2c_adapter(struct dvb_frontend *fe)
-{
-	struct cx24123_state *state = fe->demodulator_priv;
-	return &state->tuner_i2c_adapter;
-}
-EXPORT_SYMBOL(cx24123_get_tuner_i2c_adapter);
-
-static struct dvb_frontend_ops cx24123_ops;
-
-struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
-				    struct i2c_adapter *i2c)
-{
-	/* allocate memory for the internal state */
-	struct cx24123_state *state =
-		kzalloc(sizeof(struct cx24123_state), GFP_KERNEL);
-
-	dprintk("\n");
-	if (state == NULL) {
-		err("Unable to kzalloc\n");
-		goto error;
-	}
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-
-	/* check if the demod is there */
-	state->demod_rev = cx24123_readreg(state, 0x00);
-	switch (state->demod_rev) {
-	case 0xe1:
-		info("detected CX24123C\n");
-		break;
-	case 0xd1:
-		info("detected CX24123\n");
-		break;
-	default:
-		err("wrong demod revision: %x\n", state->demod_rev);
-		goto error;
-	}
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &cx24123_ops,
-		sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-
-	/* create tuner i2c adapter */
-	if (config->dont_use_pll)
-		cx24123_repeater_mode(state, 1, 0);
-
-	strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus",
-		sizeof(state->tuner_i2c_adapter.name));
-	state->tuner_i2c_adapter.algo      = &cx24123_tuner_i2c_algo;
-	state->tuner_i2c_adapter.algo_data = NULL;
-	i2c_set_adapdata(&state->tuner_i2c_adapter, state);
-	if (i2c_add_adapter(&state->tuner_i2c_adapter) < 0) {
-		err("tuner i2c bus could not be initialized\n");
-		goto error;
-	}
-
-	return &state->frontend;
-
-error:
-	kfree(state);
-
-	return NULL;
-}
-EXPORT_SYMBOL(cx24123_attach);
-
-static struct dvb_frontend_ops cx24123_ops = {
-	.delsys = { SYS_DVBS },
-	.info = {
-		.name = "Conexant CX24123/CX24109",
-		.frequency_min = 950000,
-		.frequency_max = 2150000,
-		.frequency_stepsize = 1011, /* kHz for QPSK frontends */
-		.frequency_tolerance = 5000,
-		.symbol_rate_min = 1000000,
-		.symbol_rate_max = 45000000,
-		.caps = FE_CAN_INVERSION_AUTO |
-			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
-			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK | FE_CAN_RECOVER
-	},
-
-	.release = cx24123_release,
-
-	.init = cx24123_initfe,
-	.set_frontend = cx24123_set_frontend,
-	.get_frontend = cx24123_get_frontend,
-	.read_status = cx24123_read_status,
-	.read_ber = cx24123_read_ber,
-	.read_signal_strength = cx24123_read_signal_strength,
-	.read_snr = cx24123_read_snr,
-	.diseqc_send_master_cmd = cx24123_send_diseqc_msg,
-	.diseqc_send_burst = cx24123_diseqc_send_burst,
-	.set_tone = cx24123_set_tone,
-	.set_voltage = cx24123_set_voltage,
-	.tune = cx24123_tune,
-	.get_frontend_algo = cx24123_get_algo,
-};
-
-MODULE_DESCRIPTION("DVB Frontend module for Conexant " \
-	"CX24123/CX24109/CX24113 hardware");
-MODULE_AUTHOR("Steven Toth");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
deleted file mode 100644
index 51ae866..0000000
--- a/drivers/media/dvb/frontends/cx24123.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-    Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
-
-    Copyright (C) 2005 Steven Toth <stoth@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef CX24123_H
-#define CX24123_H
-
-#include <linux/dvb/frontend.h>
-
-struct cx24123_config {
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* Need to set device param for start_dma */
-	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
-
-	/* 0 = LNB voltage normal, 1 = LNB voltage inverted */
-	int lnb_polarity;
-
-	/* this device has another tuner */
-	u8 dont_use_pll;
-	void (*agc_callback) (struct dvb_frontend *);
-};
-
-#if defined(CONFIG_DVB_CX24123) || (defined(CONFIG_DVB_CX24123_MODULE) \
-	&& defined(MODULE))
-extern struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
-					   struct i2c_adapter *i2c);
-extern struct i2c_adapter *cx24123_get_tuner_i2c_adapter(struct dvb_frontend *);
-#else
-static inline struct dvb_frontend *cx24123_attach(
-	const struct cx24123_config *config, struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-static struct i2c_adapter *
-	cx24123_get_tuner_i2c_adapter(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* CX24123_H */
diff --git a/drivers/media/dvb/frontends/cxd2820r.h b/drivers/media/dvb/frontends/cxd2820r.h
deleted file mode 100644
index 5aa306e..0000000
--- a/drivers/media/dvb/frontends/cxd2820r.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Sony CXD2820R demodulator driver
- *
- * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-
-#ifndef CXD2820R_H
-#define CXD2820R_H
-
-#include <linux/dvb/frontend.h>
-
-#define CXD2820R_GPIO_D (0 << 0) /* disable */
-#define CXD2820R_GPIO_E (1 << 0) /* enable */
-#define CXD2820R_GPIO_O (0 << 1) /* output */
-#define CXD2820R_GPIO_I (1 << 1) /* input */
-#define CXD2820R_GPIO_L (0 << 2) /* output low */
-#define CXD2820R_GPIO_H (1 << 2) /* output high */
-
-#define CXD2820R_TS_SERIAL        0x08
-#define CXD2820R_TS_SERIAL_MSB    0x28
-#define CXD2820R_TS_PARALLEL      0x30
-#define CXD2820R_TS_PARALLEL_MSB  0x70
-
-struct cxd2820r_config {
-	/* Demodulator I2C address.
-	 * Driver determines DVB-C slave I2C address automatically from master
-	 * address.
-	 * Default: none, must set
-	 * Values: 0x6c, 0x6d
-	 */
-	u8 i2c_address;
-
-	/* TS output mode.
-	 * Default: none, must set.
-	 * Values:
-	 */
-	u8 ts_mode;
-
-	/* IF AGC polarity.
-	 * Default: 0
-	 * Values: 0, 1
-	 */
-	bool if_agc_polarity;
-
-	/* Spectrum inversion.
-	 * Default: 0
-	 * Values: 0, 1
-	 */
-	bool spec_inv;
-
-	/* GPIOs for all used modes.
-	 * Default: none, disabled
-	 * Values: <see above>
-	 */
-	u8 gpio_dvbt[3];
-	u8 gpio_dvbt2[3];
-	u8 gpio_dvbc[3];
-};
-
-
-#if defined(CONFIG_DVB_CXD2820R) || \
-	(defined(CONFIG_DVB_CXD2820R_MODULE) && defined(MODULE))
-extern struct dvb_frontend *cxd2820r_attach(
-	const struct cxd2820r_config *config,
-	struct i2c_adapter *i2c
-);
-#else
-static inline struct dvb_frontend *cxd2820r_attach(
-	const struct cxd2820r_config *config,
-	struct i2c_adapter *i2c
-)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-#endif
-
-#endif /* CXD2820R_H */
diff --git a/drivers/media/dvb/frontends/cxd2820r_c.c b/drivers/media/dvb/frontends/cxd2820r_c.c
deleted file mode 100644
index ed3b0ba6..0000000
--- a/drivers/media/dvb/frontends/cxd2820r_c.c
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * Sony CXD2820R demodulator driver
- *
- * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-
-#include "cxd2820r_priv.h"
-
-int cxd2820r_set_frontend_c(struct dvb_frontend *fe)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret, i;
-	u8 buf[2];
-	u32 if_freq;
-	u16 if_ctl;
-	u64 num;
-	struct reg_val_mask tab[] = {
-		{ 0x00080, 0x01, 0xff },
-		{ 0x00081, 0x05, 0xff },
-		{ 0x00085, 0x07, 0xff },
-		{ 0x00088, 0x01, 0xff },
-
-		{ 0x00082, 0x20, 0x60 },
-		{ 0x1016a, 0x48, 0xff },
-		{ 0x100a5, 0x00, 0x01 },
-		{ 0x10020, 0x06, 0x07 },
-		{ 0x10059, 0x50, 0xff },
-		{ 0x10087, 0x0c, 0x3c },
-		{ 0x1008b, 0x07, 0xff },
-		{ 0x1001f, priv->cfg.if_agc_polarity << 7, 0x80 },
-		{ 0x10070, priv->cfg.ts_mode, 0xff },
-	};
-
-	dbg("%s: RF=%d SR=%d", __func__, c->frequency, c->symbol_rate);
-
-	/* update GPIOs */
-	ret = cxd2820r_gpio(fe);
-	if (ret)
-		goto error;
-
-	/* program tuner */
-	if (fe->ops.tuner_ops.set_params)
-		fe->ops.tuner_ops.set_params(fe);
-
-	if (priv->delivery_system !=  SYS_DVBC_ANNEX_A) {
-		for (i = 0; i < ARRAY_SIZE(tab); i++) {
-			ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
-				tab[i].val, tab[i].mask);
-			if (ret)
-				goto error;
-		}
-	}
-
-	priv->delivery_system = SYS_DVBC_ANNEX_A;
-	priv->ber_running = 0; /* tune stops BER counter */
-
-	/* program IF frequency */
-	if (fe->ops.tuner_ops.get_if_frequency) {
-		ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
-		if (ret)
-			goto error;
-	} else
-		if_freq = 0;
-
-	dbg("%s: if_freq=%d", __func__, if_freq);
-
-	num = if_freq / 1000; /* Hz => kHz */
-	num *= 0x4000;
-	if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
-	buf[0] = (if_ctl >> 8) & 0x3f;
-	buf[1] = (if_ctl >> 0) & 0xff;
-
-	ret = cxd2820r_wr_regs(priv, 0x10042, buf, 2);
-	if (ret)
-		goto error;
-
-	ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
-	if (ret)
-		goto error;
-
-	ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
-	if (ret)
-		goto error;
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_get_frontend_c(struct dvb_frontend *fe)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret;
-	u8 buf[2];
-
-	ret = cxd2820r_rd_regs(priv, 0x1001a, buf, 2);
-	if (ret)
-		goto error;
-
-	c->symbol_rate = 2500 * ((buf[0] & 0x0f) << 8 | buf[1]);
-
-	ret = cxd2820r_rd_reg(priv, 0x10019, &buf[0]);
-	if (ret)
-		goto error;
-
-	switch ((buf[0] >> 0) & 0x07) {
-	case 0:
-		c->modulation = QAM_16;
-		break;
-	case 1:
-		c->modulation = QAM_32;
-		break;
-	case 2:
-		c->modulation = QAM_64;
-		break;
-	case 3:
-		c->modulation = QAM_128;
-		break;
-	case 4:
-		c->modulation = QAM_256;
-		break;
-	}
-
-	switch ((buf[0] >> 7) & 0x01) {
-	case 0:
-		c->inversion = INVERSION_OFF;
-		break;
-	case 1:
-		c->inversion = INVERSION_ON;
-		break;
-	}
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 buf[3], start_ber = 0;
-	*ber = 0;
-
-	if (priv->ber_running) {
-		ret = cxd2820r_rd_regs(priv, 0x10076, buf, sizeof(buf));
-		if (ret)
-			goto error;
-
-		if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) {
-			*ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0];
-			start_ber = 1;
-		}
-	} else {
-		priv->ber_running = 1;
-		start_ber = 1;
-	}
-
-	if (start_ber) {
-		/* (re)start BER */
-		ret = cxd2820r_wr_reg(priv, 0x10079, 0x01);
-		if (ret)
-			goto error;
-	}
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_read_signal_strength_c(struct dvb_frontend *fe,
-	u16 *strength)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 buf[2];
-	u16 tmp;
-
-	ret = cxd2820r_rd_regs(priv, 0x10049, buf, sizeof(buf));
-	if (ret)
-		goto error;
-
-	tmp = (buf[0] & 0x03) << 8 | buf[1];
-	tmp = (~tmp & 0x03ff);
-
-	if (tmp == 512)
-		/* ~no signal */
-		tmp = 0;
-	else if (tmp > 350)
-		tmp = 350;
-
-	/* scale value to 0x0000-0xffff */
-	*strength = tmp * 0xffff / (350-0);
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_read_snr_c(struct dvb_frontend *fe, u16 *snr)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 tmp;
-	unsigned int A, B;
-	/* report SNR in dB * 10 */
-
-	ret = cxd2820r_rd_reg(priv, 0x10019, &tmp);
-	if (ret)
-		goto error;
-
-	if (((tmp >> 0) & 0x03) % 2) {
-		A = 875;
-		B = 650;
-	} else {
-		A = 950;
-		B = 760;
-	}
-
-	ret = cxd2820r_rd_reg(priv, 0x1004d, &tmp);
-	if (ret)
-		goto error;
-
-	#define CXD2820R_LOG2_E_24 24204406 /* log2(e) << 24 */
-	if (tmp)
-		*snr = A * (intlog2(B / tmp) >> 5) / (CXD2820R_LOG2_E_24 >> 5)
-			/ 10;
-	else
-		*snr = 0;
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	*ucblocks = 0;
-	/* no way to read ? */
-	return 0;
-}
-
-int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 buf[2];
-	*status = 0;
-
-	ret = cxd2820r_rd_regs(priv, 0x10088, buf, sizeof(buf));
-	if (ret)
-		goto error;
-
-	if (((buf[0] >> 0) & 0x01) == 1) {
-		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-			FE_HAS_VITERBI | FE_HAS_SYNC;
-
-		if (((buf[1] >> 3) & 0x01) == 1) {
-			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-				FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
-		}
-	}
-
-	dbg("%s: lock=%02x %02x", __func__, buf[0], buf[1]);
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_init_c(struct dvb_frontend *fe)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret;
-
-	ret = cxd2820r_wr_reg(priv, 0x00085, 0x07);
-	if (ret)
-		goto error;
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_sleep_c(struct dvb_frontend *fe)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret, i;
-	struct reg_val_mask tab[] = {
-		{ 0x000ff, 0x1f, 0xff },
-		{ 0x00085, 0x00, 0xff },
-		{ 0x00088, 0x01, 0xff },
-		{ 0x00081, 0x00, 0xff },
-		{ 0x00080, 0x00, 0xff },
-	};
-
-	dbg("%s", __func__);
-
-	priv->delivery_system = SYS_UNDEFINED;
-
-	for (i = 0; i < ARRAY_SIZE(tab); i++) {
-		ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
-			tab[i].mask);
-		if (ret)
-			goto error;
-	}
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe,
-	struct dvb_frontend_tune_settings *s)
-{
-	s->min_delay_ms = 500;
-	s->step_size = 0; /* no zigzag */
-	s->max_drift = 0;
-
-	return 0;
-}
diff --git a/drivers/media/dvb/frontends/cxd2820r_core.c b/drivers/media/dvb/frontends/cxd2820r_core.c
deleted file mode 100644
index 3bba37d..0000000
--- a/drivers/media/dvb/frontends/cxd2820r_core.c
+++ /dev/null
@@ -1,646 +0,0 @@
-/*
- * Sony CXD2820R demodulator driver
- *
- * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-
-#include "cxd2820r_priv.h"
-
-int cxd2820r_debug;
-module_param_named(debug, cxd2820r_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-/* write multiple registers */
-static int cxd2820r_wr_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg,
-	u8 *val, int len)
-{
-	int ret;
-	u8 buf[len+1];
-	struct i2c_msg msg[1] = {
-		{
-			.addr = i2c,
-			.flags = 0,
-			.len = sizeof(buf),
-			.buf = buf,
-		}
-	};
-
-	buf[0] = reg;
-	memcpy(&buf[1], val, len);
-
-	ret = i2c_transfer(priv->i2c, msg, 1);
-	if (ret == 1) {
-		ret = 0;
-	} else {
-		warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-	return ret;
-}
-
-/* read multiple registers */
-static int cxd2820r_rd_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg,
-	u8 *val, int len)
-{
-	int ret;
-	u8 buf[len];
-	struct i2c_msg msg[2] = {
-		{
-			.addr = i2c,
-			.flags = 0,
-			.len = 1,
-			.buf = &reg,
-		}, {
-			.addr = i2c,
-			.flags = I2C_M_RD,
-			.len = sizeof(buf),
-			.buf = buf,
-		}
-	};
-
-	ret = i2c_transfer(priv->i2c, msg, 2);
-	if (ret == 2) {
-		memcpy(val, buf, len);
-		ret = 0;
-	} else {
-		warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-
-	return ret;
-}
-
-/* write multiple registers */
-int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
-	int len)
-{
-	int ret;
-	u8 i2c_addr;
-	u8 reg = (reginfo >> 0) & 0xff;
-	u8 bank = (reginfo >> 8) & 0xff;
-	u8 i2c = (reginfo >> 16) & 0x01;
-
-	/* select I2C */
-	if (i2c)
-		i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */
-	else
-		i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */
-
-	/* switch bank if needed */
-	if (bank != priv->bank[i2c]) {
-		ret = cxd2820r_wr_regs_i2c(priv, i2c_addr, 0x00, &bank, 1);
-		if (ret)
-			return ret;
-		priv->bank[i2c] = bank;
-	}
-	return cxd2820r_wr_regs_i2c(priv, i2c_addr, reg, val, len);
-}
-
-/* read multiple registers */
-int cxd2820r_rd_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
-	int len)
-{
-	int ret;
-	u8 i2c_addr;
-	u8 reg = (reginfo >> 0) & 0xff;
-	u8 bank = (reginfo >> 8) & 0xff;
-	u8 i2c = (reginfo >> 16) & 0x01;
-
-	/* select I2C */
-	if (i2c)
-		i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */
-	else
-		i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */
-
-	/* switch bank if needed */
-	if (bank != priv->bank[i2c]) {
-		ret = cxd2820r_wr_regs_i2c(priv, i2c_addr, 0x00, &bank, 1);
-		if (ret)
-			return ret;
-		priv->bank[i2c] = bank;
-	}
-	return cxd2820r_rd_regs_i2c(priv, i2c_addr, reg, val, len);
-}
-
-/* write single register */
-int cxd2820r_wr_reg(struct cxd2820r_priv *priv, u32 reg, u8 val)
-{
-	return cxd2820r_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val)
-{
-	return cxd2820r_rd_regs(priv, reg, val, 1);
-}
-
-/* write single register with mask */
-int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val,
-	u8 mask)
-{
-	int ret;
-	u8 tmp;
-
-	/* no need for read if whole reg is written */
-	if (mask != 0xff) {
-		ret = cxd2820r_rd_reg(priv, reg, &tmp);
-		if (ret)
-			return ret;
-
-		val &= mask;
-		tmp &= ~mask;
-		val |= tmp;
-	}
-
-	return cxd2820r_wr_reg(priv, reg, val);
-}
-
-int cxd2820r_gpio(struct dvb_frontend *fe)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret, i;
-	u8 *gpio, tmp0, tmp1;
-	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
-	switch (fe->dtv_property_cache.delivery_system) {
-	case SYS_DVBT:
-		gpio = priv->cfg.gpio_dvbt;
-		break;
-	case SYS_DVBT2:
-		gpio = priv->cfg.gpio_dvbt2;
-		break;
-	case SYS_DVBC_ANNEX_AC:
-		gpio = priv->cfg.gpio_dvbc;
-		break;
-	default:
-		ret = -EINVAL;
-		goto error;
-	}
-
-	/* update GPIOs only when needed */
-	if (!memcmp(gpio, priv->gpio, sizeof(priv->gpio)))
-		return 0;
-
-	tmp0 = 0x00;
-	tmp1 = 0x00;
-	for (i = 0; i < sizeof(priv->gpio); i++) {
-		/* enable / disable */
-		if (gpio[i] & CXD2820R_GPIO_E)
-			tmp0 |= (2 << 6) >> (2 * i);
-		else
-			tmp0 |= (1 << 6) >> (2 * i);
-
-		/* input / output */
-		if (gpio[i] & CXD2820R_GPIO_I)
-			tmp1 |= (1 << (3 + i));
-		else
-			tmp1 |= (0 << (3 + i));
-
-		/* high / low */
-		if (gpio[i] & CXD2820R_GPIO_H)
-			tmp1 |= (1 << (0 + i));
-		else
-			tmp1 |= (0 << (0 + i));
-
-		dbg("%s: GPIO i=%d %02x %02x", __func__, i, tmp0, tmp1);
-	}
-
-	dbg("%s: wr gpio=%02x %02x", __func__, tmp0, tmp1);
-
-	/* write bits [7:2] */
-	ret = cxd2820r_wr_reg_mask(priv, 0x00089, tmp0, 0xfc);
-	if (ret)
-		goto error;
-
-	/* write bits [5:0] */
-	ret = cxd2820r_wr_reg_mask(priv, 0x0008e, tmp1, 0x3f);
-	if (ret)
-		goto error;
-
-	memcpy(priv->gpio, gpio, sizeof(priv->gpio));
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-/* 64 bit div with round closest, like DIV_ROUND_CLOSEST but 64 bit */
-u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor)
-{
-	return div_u64(dividend + (divisor / 2), divisor);
-}
-
-static int cxd2820r_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret;
-
-	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-	switch (c->delivery_system) {
-	case SYS_DVBT:
-		ret = cxd2820r_init_t(fe);
-		if (ret < 0)
-			goto err;
-		ret = cxd2820r_set_frontend_t(fe);
-		if (ret < 0)
-			goto err;
-		break;
-	case SYS_DVBT2:
-		ret = cxd2820r_init_t(fe);
-		if (ret < 0)
-			goto err;
-		ret = cxd2820r_set_frontend_t2(fe);
-		if (ret < 0)
-			goto err;
-		break;
-	case SYS_DVBC_ANNEX_A:
-		ret = cxd2820r_init_c(fe);
-		if (ret < 0)
-			goto err;
-		ret = cxd2820r_set_frontend_c(fe);
-		if (ret < 0)
-			goto err;
-		break;
-	default:
-		dbg("%s: error state=%d", __func__, fe->dtv_property_cache.delivery_system);
-		ret = -EINVAL;
-		break;
-	}
-err:
-	return ret;
-}
-static int cxd2820r_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	int ret;
-
-	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-	switch (fe->dtv_property_cache.delivery_system) {
-	case SYS_DVBT:
-		ret = cxd2820r_read_status_t(fe, status);
-		break;
-	case SYS_DVBT2:
-		ret = cxd2820r_read_status_t2(fe, status);
-		break;
-	case SYS_DVBC_ANNEX_A:
-		ret = cxd2820r_read_status_c(fe, status);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
-
-static int cxd2820r_get_frontend(struct dvb_frontend *fe)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret;
-
-	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
-	if (priv->delivery_system == SYS_UNDEFINED)
-		return 0;
-
-	switch (fe->dtv_property_cache.delivery_system) {
-	case SYS_DVBT:
-		ret = cxd2820r_get_frontend_t(fe);
-		break;
-	case SYS_DVBT2:
-		ret = cxd2820r_get_frontend_t2(fe);
-		break;
-	case SYS_DVBC_ANNEX_A:
-		ret = cxd2820r_get_frontend_c(fe);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
-
-static int cxd2820r_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	int ret;
-
-	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-	switch (fe->dtv_property_cache.delivery_system) {
-	case SYS_DVBT:
-		ret = cxd2820r_read_ber_t(fe, ber);
-		break;
-	case SYS_DVBT2:
-		ret = cxd2820r_read_ber_t2(fe, ber);
-		break;
-	case SYS_DVBC_ANNEX_A:
-		ret = cxd2820r_read_ber_c(fe, ber);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
-
-static int cxd2820r_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	int ret;
-
-	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-	switch (fe->dtv_property_cache.delivery_system) {
-	case SYS_DVBT:
-		ret = cxd2820r_read_signal_strength_t(fe, strength);
-		break;
-	case SYS_DVBT2:
-		ret = cxd2820r_read_signal_strength_t2(fe, strength);
-		break;
-	case SYS_DVBC_ANNEX_A:
-		ret = cxd2820r_read_signal_strength_c(fe, strength);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
-
-static int cxd2820r_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	int ret;
-
-	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-	switch (fe->dtv_property_cache.delivery_system) {
-	case SYS_DVBT:
-		ret = cxd2820r_read_snr_t(fe, snr);
-		break;
-	case SYS_DVBT2:
-		ret = cxd2820r_read_snr_t2(fe, snr);
-		break;
-	case SYS_DVBC_ANNEX_A:
-		ret = cxd2820r_read_snr_c(fe, snr);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
-
-static int cxd2820r_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	int ret;
-
-	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-	switch (fe->dtv_property_cache.delivery_system) {
-	case SYS_DVBT:
-		ret = cxd2820r_read_ucblocks_t(fe, ucblocks);
-		break;
-	case SYS_DVBT2:
-		ret = cxd2820r_read_ucblocks_t2(fe, ucblocks);
-		break;
-	case SYS_DVBC_ANNEX_A:
-		ret = cxd2820r_read_ucblocks_c(fe, ucblocks);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
-
-static int cxd2820r_init(struct dvb_frontend *fe)
-{
-	return 0;
-}
-
-static int cxd2820r_sleep(struct dvb_frontend *fe)
-{
-	int ret;
-
-	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-	switch (fe->dtv_property_cache.delivery_system) {
-	case SYS_DVBT:
-		ret = cxd2820r_sleep_t(fe);
-		break;
-	case SYS_DVBT2:
-		ret = cxd2820r_sleep_t2(fe);
-		break;
-	case SYS_DVBC_ANNEX_A:
-		ret = cxd2820r_sleep_c(fe);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
-
-static int cxd2820r_get_tune_settings(struct dvb_frontend *fe,
-				      struct dvb_frontend_tune_settings *s)
-{
-	int ret;
-
-	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-	switch (fe->dtv_property_cache.delivery_system) {
-	case SYS_DVBT:
-		ret = cxd2820r_get_tune_settings_t(fe, s);
-		break;
-	case SYS_DVBT2:
-		ret = cxd2820r_get_tune_settings_t2(fe, s);
-		break;
-	case SYS_DVBC_ANNEX_A:
-		ret = cxd2820r_get_tune_settings_c(fe, s);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
-
-static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret, i;
-	fe_status_t status = 0;
-	dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
-	/* switch between DVB-T and DVB-T2 when tune fails */
-	if (priv->last_tune_failed) {
-		if (priv->delivery_system == SYS_DVBT) {
-			ret = cxd2820r_sleep_t(fe);
-			if (ret)
-				goto error;
-
-			c->delivery_system = SYS_DVBT2;
-		} else if (priv->delivery_system == SYS_DVBT2) {
-			ret = cxd2820r_sleep_t2(fe);
-			if (ret)
-				goto error;
-
-			c->delivery_system = SYS_DVBT;
-		}
-	}
-
-	/* set frontend */
-	ret = cxd2820r_set_frontend(fe);
-	if (ret)
-		goto error;
-
-
-	/* frontend lock wait loop count */
-	switch (priv->delivery_system) {
-	case SYS_DVBT:
-	case SYS_DVBC_ANNEX_A:
-		i = 20;
-		break;
-	case SYS_DVBT2:
-		i = 40;
-		break;
-	case SYS_UNDEFINED:
-	default:
-		i = 0;
-		break;
-	}
-
-	/* wait frontend lock */
-	for (; i > 0; i--) {
-		dbg("%s: LOOP=%d", __func__, i);
-		msleep(50);
-		ret = cxd2820r_read_status(fe, &status);
-		if (ret)
-			goto error;
-
-		if (status & FE_HAS_LOCK)
-			break;
-	}
-
-	/* check if we have a valid signal */
-	if (status & FE_HAS_LOCK) {
-		priv->last_tune_failed = 0;
-		return DVBFE_ALGO_SEARCH_SUCCESS;
-	} else {
-		priv->last_tune_failed = 1;
-		return DVBFE_ALGO_SEARCH_AGAIN;
-	}
-
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return DVBFE_ALGO_SEARCH_ERROR;
-}
-
-static int cxd2820r_get_frontend_algo(struct dvb_frontend *fe)
-{
-	return DVBFE_ALGO_CUSTOM;
-}
-
-static void cxd2820r_release(struct dvb_frontend *fe)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	dbg("%s", __func__);
-
-	kfree(priv);
-	return;
-}
-
-static int cxd2820r_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	dbg("%s: %d", __func__, enable);
-
-	/* Bit 0 of reg 0xdb in bank 0x00 controls I2C repeater */
-	return cxd2820r_wr_reg_mask(priv, 0xdb, enable ? 1 : 0, 0x1);
-}
-
-static const struct dvb_frontend_ops cxd2820r_ops = {
-	.delsys = { SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A },
-	/* default: DVB-T/T2 */
-	.info = {
-		.name = "Sony CXD2820R",
-
-		.caps =	FE_CAN_FEC_1_2			|
-			FE_CAN_FEC_2_3			|
-			FE_CAN_FEC_3_4			|
-			FE_CAN_FEC_5_6			|
-			FE_CAN_FEC_7_8			|
-			FE_CAN_FEC_AUTO			|
-			FE_CAN_QPSK			|
-			FE_CAN_QAM_16			|
-			FE_CAN_QAM_32			|
-			FE_CAN_QAM_64			|
-			FE_CAN_QAM_128			|
-			FE_CAN_QAM_256			|
-			FE_CAN_QAM_AUTO			|
-			FE_CAN_TRANSMISSION_MODE_AUTO	|
-			FE_CAN_GUARD_INTERVAL_AUTO	|
-			FE_CAN_HIERARCHY_AUTO		|
-			FE_CAN_MUTE_TS			|
-			FE_CAN_2G_MODULATION
-		},
-
-	.release		= cxd2820r_release,
-	.init			= cxd2820r_init,
-	.sleep			= cxd2820r_sleep,
-
-	.get_tune_settings	= cxd2820r_get_tune_settings,
-	.i2c_gate_ctrl		= cxd2820r_i2c_gate_ctrl,
-
-	.get_frontend		= cxd2820r_get_frontend,
-
-	.get_frontend_algo	= cxd2820r_get_frontend_algo,
-	.search			= cxd2820r_search,
-
-	.read_status		= cxd2820r_read_status,
-	.read_snr		= cxd2820r_read_snr,
-	.read_ber		= cxd2820r_read_ber,
-	.read_ucblocks		= cxd2820r_read_ucblocks,
-	.read_signal_strength	= cxd2820r_read_signal_strength,
-};
-
-struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg,
-		struct i2c_adapter *i2c)
-{
-	struct cxd2820r_priv *priv = NULL;
-	int ret;
-	u8 tmp;
-
-	priv = kzalloc(sizeof (struct cxd2820r_priv), GFP_KERNEL);
-	if (!priv)
-		goto error;
-
-	priv->i2c = i2c;
-	memcpy(&priv->cfg, cfg, sizeof (struct cxd2820r_config));
-
-	priv->bank[0] = priv->bank[1] = 0xff;
-	ret = cxd2820r_rd_reg(priv, 0x000fd, &tmp);
-	dbg("%s: chip id=%02x", __func__, tmp);
-	if (ret || tmp != 0xe1)
-		goto error;
-
-	memcpy(&priv->fe.ops, &cxd2820r_ops, sizeof (struct dvb_frontend_ops));
-	priv->fe.demodulator_priv = priv;
-	return &priv->fe;
-error:
-	kfree(priv);
-	return NULL;
-}
-EXPORT_SYMBOL(cxd2820r_attach);
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Sony CXD2820R demodulator driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/cxd2820r_priv.h b/drivers/media/dvb/frontends/cxd2820r_priv.h
deleted file mode 100644
index 9a9822c..0000000
--- a/drivers/media/dvb/frontends/cxd2820r_priv.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Sony CXD2820R demodulator driver
- *
- * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-
-#ifndef CXD2820R_PRIV_H
-#define CXD2820R_PRIV_H
-
-#include <linux/dvb/version.h>
-#include "dvb_frontend.h"
-#include "dvb_math.h"
-#include "cxd2820r.h"
-
-#define LOG_PREFIX "cxd2820r"
-
-#undef dbg
-#define dbg(f, arg...) \
-	if (cxd2820r_debug) \
-		printk(KERN_INFO   LOG_PREFIX": " f "\n" , ## arg)
-#undef err
-#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
-#undef info
-#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
-#undef warn
-#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
-
-struct reg_val_mask {
-	u32 reg;
-	u8  val;
-	u8  mask;
-};
-
-struct cxd2820r_priv {
-	struct i2c_adapter *i2c;
-	struct dvb_frontend fe;
-	struct cxd2820r_config cfg;
-
-	bool ber_running;
-
-	u8 bank[2];
-	u8 gpio[3];
-
-	fe_delivery_system_t delivery_system;
-	bool last_tune_failed; /* for switch between T and T2 tune */
-};
-
-/* cxd2820r_core.c */
-
-extern int cxd2820r_debug;
-
-int cxd2820r_gpio(struct dvb_frontend *fe);
-
-int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val,
-	u8 mask);
-
-int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
-	int len);
-
-u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor);
-
-int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
-	int len);
-
-int cxd2820r_rd_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
-	int len);
-
-int cxd2820r_wr_reg(struct cxd2820r_priv *priv, u32 reg, u8 val);
-
-int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val);
-
-/* cxd2820r_c.c */
-
-int cxd2820r_get_frontend_c(struct dvb_frontend *fe);
-
-int cxd2820r_set_frontend_c(struct dvb_frontend *fe);
-
-int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status);
-
-int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber);
-
-int cxd2820r_read_signal_strength_c(struct dvb_frontend *fe, u16 *strength);
-
-int cxd2820r_read_snr_c(struct dvb_frontend *fe, u16 *snr);
-
-int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks);
-
-int cxd2820r_init_c(struct dvb_frontend *fe);
-
-int cxd2820r_sleep_c(struct dvb_frontend *fe);
-
-int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe,
-	struct dvb_frontend_tune_settings *s);
-
-/* cxd2820r_t.c */
-
-int cxd2820r_get_frontend_t(struct dvb_frontend *fe);
-
-int cxd2820r_set_frontend_t(struct dvb_frontend *fe);
-
-int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status);
-
-int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber);
-
-int cxd2820r_read_signal_strength_t(struct dvb_frontend *fe, u16 *strength);
-
-int cxd2820r_read_snr_t(struct dvb_frontend *fe, u16 *snr);
-
-int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks);
-
-int cxd2820r_init_t(struct dvb_frontend *fe);
-
-int cxd2820r_sleep_t(struct dvb_frontend *fe);
-
-int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe,
-	struct dvb_frontend_tune_settings *s);
-
-/* cxd2820r_t2.c */
-
-int cxd2820r_get_frontend_t2(struct dvb_frontend *fe);
-
-int cxd2820r_set_frontend_t2(struct dvb_frontend *fe);
-
-int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status);
-
-int cxd2820r_read_ber_t2(struct dvb_frontend *fe, u32 *ber);
-
-int cxd2820r_read_signal_strength_t2(struct dvb_frontend *fe, u16 *strength);
-
-int cxd2820r_read_snr_t2(struct dvb_frontend *fe, u16 *snr);
-
-int cxd2820r_read_ucblocks_t2(struct dvb_frontend *fe, u32 *ucblocks);
-
-int cxd2820r_init_t2(struct dvb_frontend *fe);
-
-int cxd2820r_sleep_t2(struct dvb_frontend *fe);
-
-int cxd2820r_get_tune_settings_t2(struct dvb_frontend *fe,
-	struct dvb_frontend_tune_settings *s);
-
-#endif /* CXD2820R_PRIV_H */
diff --git a/drivers/media/dvb/frontends/cxd2820r_t.c b/drivers/media/dvb/frontends/cxd2820r_t.c
deleted file mode 100644
index 1a02623..0000000
--- a/drivers/media/dvb/frontends/cxd2820r_t.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * Sony CXD2820R demodulator driver
- *
- * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-
-#include "cxd2820r_priv.h"
-
-int cxd2820r_set_frontend_t(struct dvb_frontend *fe)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret, i, bw_i;
-	u32 if_freq, if_ctl;
-	u64 num;
-	u8 buf[3], bw_param;
-	u8 bw_params1[][5] = {
-		{ 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */
-		{ 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */
-		{ 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */
-	};
-	u8 bw_params2[][2] = {
-		{ 0x1f, 0xdc }, /* 6 MHz */
-		{ 0x12, 0xf8 }, /* 7 MHz */
-		{ 0x01, 0xe0 }, /* 8 MHz */
-	};
-	struct reg_val_mask tab[] = {
-		{ 0x00080, 0x00, 0xff },
-		{ 0x00081, 0x03, 0xff },
-		{ 0x00085, 0x07, 0xff },
-		{ 0x00088, 0x01, 0xff },
-
-		{ 0x00070, priv->cfg.ts_mode, 0xff },
-		{ 0x000cb, priv->cfg.if_agc_polarity << 6, 0x40 },
-		{ 0x000a5, 0x00, 0x01 },
-		{ 0x00082, 0x20, 0x60 },
-		{ 0x000c2, 0xc3, 0xff },
-		{ 0x0016a, 0x50, 0xff },
-		{ 0x00427, 0x41, 0xff },
-	};
-
-	dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz);
-
-	switch (c->bandwidth_hz) {
-	case 6000000:
-		bw_i = 0;
-		bw_param = 2;
-		break;
-	case 7000000:
-		bw_i = 1;
-		bw_param = 1;
-		break;
-	case 8000000:
-		bw_i = 2;
-		bw_param = 0;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* update GPIOs */
-	ret = cxd2820r_gpio(fe);
-	if (ret)
-		goto error;
-
-	/* program tuner */
-	if (fe->ops.tuner_ops.set_params)
-		fe->ops.tuner_ops.set_params(fe);
-
-	if (priv->delivery_system != SYS_DVBT) {
-		for (i = 0; i < ARRAY_SIZE(tab); i++) {
-			ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
-				tab[i].val, tab[i].mask);
-			if (ret)
-				goto error;
-		}
-	}
-
-	priv->delivery_system = SYS_DVBT;
-	priv->ber_running = 0; /* tune stops BER counter */
-
-	/* program IF frequency */
-	if (fe->ops.tuner_ops.get_if_frequency) {
-		ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
-		if (ret)
-			goto error;
-	} else
-		if_freq = 0;
-
-	dbg("%s: if_freq=%d", __func__, if_freq);
-
-	num = if_freq / 1000; /* Hz => kHz */
-	num *= 0x1000000;
-	if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
-	buf[0] = ((if_ctl >> 16) & 0xff);
-	buf[1] = ((if_ctl >>  8) & 0xff);
-	buf[2] = ((if_ctl >>  0) & 0xff);
-
-	ret = cxd2820r_wr_regs(priv, 0x000b6, buf, 3);
-	if (ret)
-		goto error;
-
-	ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[bw_i], 5);
-	if (ret)
-		goto error;
-
-	ret = cxd2820r_wr_reg_mask(priv, 0x000d7, bw_param << 6, 0xc0);
-	if (ret)
-		goto error;
-
-	ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[bw_i], 2);
-	if (ret)
-		goto error;
-
-	ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
-	if (ret)
-		goto error;
-
-	ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
-	if (ret)
-		goto error;
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_get_frontend_t(struct dvb_frontend *fe)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret;
-	u8 buf[2];
-
-	ret = cxd2820r_rd_regs(priv, 0x0002f, buf, sizeof(buf));
-	if (ret)
-		goto error;
-
-	switch ((buf[0] >> 6) & 0x03) {
-	case 0:
-		c->modulation = QPSK;
-		break;
-	case 1:
-		c->modulation = QAM_16;
-		break;
-	case 2:
-		c->modulation = QAM_64;
-		break;
-	}
-
-	switch ((buf[1] >> 1) & 0x03) {
-	case 0:
-		c->transmission_mode = TRANSMISSION_MODE_2K;
-		break;
-	case 1:
-		c->transmission_mode = TRANSMISSION_MODE_8K;
-		break;
-	}
-
-	switch ((buf[1] >> 3) & 0x03) {
-	case 0:
-		c->guard_interval = GUARD_INTERVAL_1_32;
-		break;
-	case 1:
-		c->guard_interval = GUARD_INTERVAL_1_16;
-		break;
-	case 2:
-		c->guard_interval = GUARD_INTERVAL_1_8;
-		break;
-	case 3:
-		c->guard_interval = GUARD_INTERVAL_1_4;
-		break;
-	}
-
-	switch ((buf[0] >> 3) & 0x07) {
-	case 0:
-		c->hierarchy = HIERARCHY_NONE;
-		break;
-	case 1:
-		c->hierarchy = HIERARCHY_1;
-		break;
-	case 2:
-		c->hierarchy = HIERARCHY_2;
-		break;
-	case 3:
-		c->hierarchy = HIERARCHY_4;
-		break;
-	}
-
-	switch ((buf[0] >> 0) & 0x07) {
-	case 0:
-		c->code_rate_HP = FEC_1_2;
-		break;
-	case 1:
-		c->code_rate_HP = FEC_2_3;
-		break;
-	case 2:
-		c->code_rate_HP = FEC_3_4;
-		break;
-	case 3:
-		c->code_rate_HP = FEC_5_6;
-		break;
-	case 4:
-		c->code_rate_HP = FEC_7_8;
-		break;
-	}
-
-	switch ((buf[1] >> 5) & 0x07) {
-	case 0:
-		c->code_rate_LP = FEC_1_2;
-		break;
-	case 1:
-		c->code_rate_LP = FEC_2_3;
-		break;
-	case 2:
-		c->code_rate_LP = FEC_3_4;
-		break;
-	case 3:
-		c->code_rate_LP = FEC_5_6;
-		break;
-	case 4:
-		c->code_rate_LP = FEC_7_8;
-		break;
-	}
-
-	ret = cxd2820r_rd_reg(priv, 0x007c6, &buf[0]);
-	if (ret)
-		goto error;
-
-	switch ((buf[0] >> 0) & 0x01) {
-	case 0:
-		c->inversion = INVERSION_OFF;
-		break;
-	case 1:
-		c->inversion = INVERSION_ON;
-		break;
-	}
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 buf[3], start_ber = 0;
-	*ber = 0;
-
-	if (priv->ber_running) {
-		ret = cxd2820r_rd_regs(priv, 0x00076, buf, sizeof(buf));
-		if (ret)
-			goto error;
-
-		if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) {
-			*ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0];
-			start_ber = 1;
-		}
-	} else {
-		priv->ber_running = 1;
-		start_ber = 1;
-	}
-
-	if (start_ber) {
-		/* (re)start BER */
-		ret = cxd2820r_wr_reg(priv, 0x00079, 0x01);
-		if (ret)
-			goto error;
-	}
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_read_signal_strength_t(struct dvb_frontend *fe,
-	u16 *strength)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 buf[2];
-	u16 tmp;
-
-	ret = cxd2820r_rd_regs(priv, 0x00026, buf, sizeof(buf));
-	if (ret)
-		goto error;
-
-	tmp = (buf[0] & 0x0f) << 8 | buf[1];
-	tmp = ~tmp & 0x0fff;
-
-	/* scale value to 0x0000-0xffff from 0x0000-0x0fff */
-	*strength = tmp * 0xffff / 0x0fff;
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_read_snr_t(struct dvb_frontend *fe, u16 *snr)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 buf[2];
-	u16 tmp;
-	/* report SNR in dB * 10 */
-
-	ret = cxd2820r_rd_regs(priv, 0x00028, buf, sizeof(buf));
-	if (ret)
-		goto error;
-
-	tmp = (buf[0] & 0x1f) << 8 | buf[1];
-	#define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */
-	if (tmp)
-		*snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24)
-			/ 100);
-	else
-		*snr = 0;
-
-	dbg("%s: dBx10=%d val=%04x", __func__, *snr, tmp);
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	*ucblocks = 0;
-	/* no way to read ? */
-	return 0;
-}
-
-int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 buf[4];
-	*status = 0;
-
-	ret = cxd2820r_rd_reg(priv, 0x00010, &buf[0]);
-	if (ret)
-		goto error;
-
-	if ((buf[0] & 0x07) == 6) {
-		ret = cxd2820r_rd_reg(priv, 0x00073, &buf[1]);
-		if (ret)
-			goto error;
-
-		if (((buf[1] >> 3) & 0x01) == 1) {
-			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-				FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
-		} else {
-			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-				FE_HAS_VITERBI | FE_HAS_SYNC;
-		}
-	} else {
-		ret = cxd2820r_rd_reg(priv, 0x00014, &buf[2]);
-		if (ret)
-			goto error;
-
-		if ((buf[2] & 0x0f) >= 4) {
-			ret = cxd2820r_rd_reg(priv, 0x00a14, &buf[3]);
-			if (ret)
-				goto error;
-
-			if (((buf[3] >> 4) & 0x01) == 1)
-				*status |= FE_HAS_SIGNAL;
-		}
-	}
-
-	dbg("%s: lock=%02x %02x %02x %02x", __func__,
-		buf[0], buf[1], buf[2], buf[3]);
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_init_t(struct dvb_frontend *fe)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret;
-
-	ret = cxd2820r_wr_reg(priv, 0x00085, 0x07);
-	if (ret)
-		goto error;
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_sleep_t(struct dvb_frontend *fe)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret, i;
-	struct reg_val_mask tab[] = {
-		{ 0x000ff, 0x1f, 0xff },
-		{ 0x00085, 0x00, 0xff },
-		{ 0x00088, 0x01, 0xff },
-		{ 0x00081, 0x00, 0xff },
-		{ 0x00080, 0x00, 0xff },
-	};
-
-	dbg("%s", __func__);
-
-	priv->delivery_system = SYS_UNDEFINED;
-
-	for (i = 0; i < ARRAY_SIZE(tab); i++) {
-		ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
-			tab[i].mask);
-		if (ret)
-			goto error;
-	}
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe,
-	struct dvb_frontend_tune_settings *s)
-{
-	s->min_delay_ms = 500;
-	s->step_size = fe->ops.info.frequency_stepsize * 2;
-	s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
-
-	return 0;
-}
diff --git a/drivers/media/dvb/frontends/cxd2820r_t2.c b/drivers/media/dvb/frontends/cxd2820r_t2.c
deleted file mode 100644
index 3a5759e..0000000
--- a/drivers/media/dvb/frontends/cxd2820r_t2.c
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * Sony CXD2820R demodulator driver
- *
- * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-
-#include "cxd2820r_priv.h"
-
-int cxd2820r_set_frontend_t2(struct dvb_frontend *fe)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret, i, bw_i;
-	u32 if_freq, if_ctl;
-	u64 num;
-	u8 buf[3], bw_param;
-	u8 bw_params1[][5] = {
-		{ 0x1c, 0xb3, 0x33, 0x33, 0x33 }, /* 5 MHz */
-		{ 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */
-		{ 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */
-		{ 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */
-	};
-	struct reg_val_mask tab[] = {
-		{ 0x00080, 0x02, 0xff },
-		{ 0x00081, 0x20, 0xff },
-		{ 0x00085, 0x07, 0xff },
-		{ 0x00088, 0x01, 0xff },
-		{ 0x02069, 0x01, 0xff },
-
-		{ 0x0207f, 0x2a, 0xff },
-		{ 0x02082, 0x0a, 0xff },
-		{ 0x02083, 0x0a, 0xff },
-		{ 0x020cb, priv->cfg.if_agc_polarity << 6, 0x40 },
-		{ 0x02070, priv->cfg.ts_mode, 0xff },
-		{ 0x020b5, priv->cfg.spec_inv << 4, 0x10 },
-		{ 0x02567, 0x07, 0x0f },
-		{ 0x02569, 0x03, 0x03 },
-		{ 0x02595, 0x1a, 0xff },
-		{ 0x02596, 0x50, 0xff },
-		{ 0x02a8c, 0x00, 0xff },
-		{ 0x02a8d, 0x34, 0xff },
-		{ 0x02a45, 0x06, 0x07 },
-		{ 0x03f10, 0x0d, 0xff },
-		{ 0x03f11, 0x02, 0xff },
-		{ 0x03f12, 0x01, 0xff },
-		{ 0x03f23, 0x2c, 0xff },
-		{ 0x03f51, 0x13, 0xff },
-		{ 0x03f52, 0x01, 0xff },
-		{ 0x03f53, 0x00, 0xff },
-		{ 0x027e6, 0x14, 0xff },
-		{ 0x02786, 0x02, 0x07 },
-		{ 0x02787, 0x40, 0xe0 },
-		{ 0x027ef, 0x10, 0x18 },
-	};
-
-	dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz);
-
-	switch (c->bandwidth_hz) {
-	case 5000000:
-		bw_i = 0;
-		bw_param = 3;
-		break;
-	case 6000000:
-		bw_i = 1;
-		bw_param = 2;
-		break;
-	case 7000000:
-		bw_i = 2;
-		bw_param = 1;
-		break;
-	case 8000000:
-		bw_i = 3;
-		bw_param = 0;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* update GPIOs */
-	ret = cxd2820r_gpio(fe);
-	if (ret)
-		goto error;
-
-	/* program tuner */
-	if (fe->ops.tuner_ops.set_params)
-		fe->ops.tuner_ops.set_params(fe);
-
-	if (priv->delivery_system != SYS_DVBT2) {
-		for (i = 0; i < ARRAY_SIZE(tab); i++) {
-			ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
-				tab[i].val, tab[i].mask);
-			if (ret)
-				goto error;
-		}
-	}
-
-	priv->delivery_system = SYS_DVBT2;
-
-	/* program IF frequency */
-	if (fe->ops.tuner_ops.get_if_frequency) {
-		ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
-		if (ret)
-			goto error;
-	} else
-		if_freq = 0;
-
-	dbg("%s: if_freq=%d", __func__, if_freq);
-
-	num = if_freq / 1000; /* Hz => kHz */
-	num *= 0x1000000;
-	if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
-	buf[0] = ((if_ctl >> 16) & 0xff);
-	buf[1] = ((if_ctl >>  8) & 0xff);
-	buf[2] = ((if_ctl >>  0) & 0xff);
-
-	ret = cxd2820r_wr_regs(priv, 0x020b6, buf, 3);
-	if (ret)
-		goto error;
-
-	ret = cxd2820r_wr_regs(priv, 0x0209f, bw_params1[bw_i], 5);
-	if (ret)
-		goto error;
-
-	ret = cxd2820r_wr_reg_mask(priv, 0x020d7, bw_param << 6, 0xc0);
-	if (ret)
-		goto error;
-
-	ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
-	if (ret)
-		goto error;
-
-	ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
-	if (ret)
-		goto error;
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-
-}
-
-int cxd2820r_get_frontend_t2(struct dvb_frontend *fe)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret;
-	u8 buf[2];
-
-	ret = cxd2820r_rd_regs(priv, 0x0205c, buf, 2);
-	if (ret)
-		goto error;
-
-	switch ((buf[0] >> 0) & 0x07) {
-	case 0:
-		c->transmission_mode = TRANSMISSION_MODE_2K;
-		break;
-	case 1:
-		c->transmission_mode = TRANSMISSION_MODE_8K;
-		break;
-	case 2:
-		c->transmission_mode = TRANSMISSION_MODE_4K;
-		break;
-	case 3:
-		c->transmission_mode = TRANSMISSION_MODE_1K;
-		break;
-	case 4:
-		c->transmission_mode = TRANSMISSION_MODE_16K;
-		break;
-	case 5:
-		c->transmission_mode = TRANSMISSION_MODE_32K;
-		break;
-	}
-
-	switch ((buf[1] >> 4) & 0x07) {
-	case 0:
-		c->guard_interval = GUARD_INTERVAL_1_32;
-		break;
-	case 1:
-		c->guard_interval = GUARD_INTERVAL_1_16;
-		break;
-	case 2:
-		c->guard_interval = GUARD_INTERVAL_1_8;
-		break;
-	case 3:
-		c->guard_interval = GUARD_INTERVAL_1_4;
-		break;
-	case 4:
-		c->guard_interval = GUARD_INTERVAL_1_128;
-		break;
-	case 5:
-		c->guard_interval = GUARD_INTERVAL_19_128;
-		break;
-	case 6:
-		c->guard_interval = GUARD_INTERVAL_19_256;
-		break;
-	}
-
-	ret = cxd2820r_rd_regs(priv, 0x0225b, buf, 2);
-	if (ret)
-		goto error;
-
-	switch ((buf[0] >> 0) & 0x07) {
-	case 0:
-		c->fec_inner = FEC_1_2;
-		break;
-	case 1:
-		c->fec_inner = FEC_3_5;
-		break;
-	case 2:
-		c->fec_inner = FEC_2_3;
-		break;
-	case 3:
-		c->fec_inner = FEC_3_4;
-		break;
-	case 4:
-		c->fec_inner = FEC_4_5;
-		break;
-	case 5:
-		c->fec_inner = FEC_5_6;
-		break;
-	}
-
-	switch ((buf[1] >> 0) & 0x07) {
-	case 0:
-		c->modulation = QPSK;
-		break;
-	case 1:
-		c->modulation = QAM_16;
-		break;
-	case 2:
-		c->modulation = QAM_64;
-		break;
-	case 3:
-		c->modulation = QAM_256;
-		break;
-	}
-
-	ret = cxd2820r_rd_reg(priv, 0x020b5, &buf[0]);
-	if (ret)
-		goto error;
-
-	switch ((buf[0] >> 4) & 0x01) {
-	case 0:
-		c->inversion = INVERSION_OFF;
-		break;
-	case 1:
-		c->inversion = INVERSION_ON;
-		break;
-	}
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 buf[1];
-	*status = 0;
-
-	ret = cxd2820r_rd_reg(priv, 0x02010 , &buf[0]);
-	if (ret)
-		goto error;
-
-	if ((buf[0] & 0x07) == 6) {
-		if (((buf[0] >> 5) & 0x01) == 1) {
-			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-				FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
-		} else {
-			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-				FE_HAS_VITERBI | FE_HAS_SYNC;
-		}
-	}
-
-	dbg("%s: lock=%02x", __func__, buf[0]);
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_read_ber_t2(struct dvb_frontend *fe, u32 *ber)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 buf[4];
-	unsigned int errbits;
-	*ber = 0;
-	/* FIXME: correct calculation */
-
-	ret = cxd2820r_rd_regs(priv, 0x02039, buf, sizeof(buf));
-	if (ret)
-		goto error;
-
-	if ((buf[0] >> 4) & 0x01) {
-		errbits = (buf[0] & 0x0f) << 24 | buf[1] << 16 |
-			buf[2] << 8 | buf[3];
-
-		if (errbits)
-			*ber = errbits * 64 / 16588800;
-	}
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_read_signal_strength_t2(struct dvb_frontend *fe,
-	u16 *strength)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 buf[2];
-	u16 tmp;
-
-	ret = cxd2820r_rd_regs(priv, 0x02026, buf, sizeof(buf));
-	if (ret)
-		goto error;
-
-	tmp = (buf[0] & 0x0f) << 8 | buf[1];
-	tmp = ~tmp & 0x0fff;
-
-	/* scale value to 0x0000-0xffff from 0x0000-0x0fff */
-	*strength = tmp * 0xffff / 0x0fff;
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_read_snr_t2(struct dvb_frontend *fe, u16 *snr)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 buf[2];
-	u16 tmp;
-	/* report SNR in dB * 10 */
-
-	ret = cxd2820r_rd_regs(priv, 0x02028, buf, sizeof(buf));
-	if (ret)
-		goto error;
-
-	tmp = (buf[0] & 0x0f) << 8 | buf[1];
-	#define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */
-	if (tmp)
-		*snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24)
-			/ 100);
-	else
-		*snr = 0;
-
-	dbg("%s: dBx10=%d val=%04x", __func__, *snr, tmp);
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_read_ucblocks_t2(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	*ucblocks = 0;
-	/* no way to read ? */
-	return 0;
-}
-
-int cxd2820r_sleep_t2(struct dvb_frontend *fe)
-{
-	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int ret, i;
-	struct reg_val_mask tab[] = {
-		{ 0x000ff, 0x1f, 0xff },
-		{ 0x00085, 0x00, 0xff },
-		{ 0x00088, 0x01, 0xff },
-		{ 0x02069, 0x00, 0xff },
-		{ 0x00081, 0x00, 0xff },
-		{ 0x00080, 0x00, 0xff },
-	};
-
-	dbg("%s", __func__);
-
-	for (i = 0; i < ARRAY_SIZE(tab); i++) {
-		ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
-			tab[i].mask);
-		if (ret)
-			goto error;
-	}
-
-	priv->delivery_system = SYS_UNDEFINED;
-
-	return ret;
-error:
-	dbg("%s: failed:%d", __func__, ret);
-	return ret;
-}
-
-int cxd2820r_get_tune_settings_t2(struct dvb_frontend *fe,
-	struct dvb_frontend_tune_settings *s)
-{
-	s->min_delay_ms = 1500;
-	s->step_size = fe->ops.info.frequency_stepsize * 2;
-	s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
-
-	return 0;
-}
diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c
deleted file mode 100644
index 3b024bf..0000000
--- a/drivers/media/dvb/frontends/dib0070.c
+++ /dev/null
@@ -1,780 +0,0 @@
-/*
- * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
- *
- * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * This code is more or less generated from another driver, please
- * excuse some codingstyle oddities.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-
-#include "dvb_frontend.h"
-
-#include "dib0070.h"
-#include "dibx000_common.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
-
-#define dprintk(args...) do { \
-	if (debug) { \
-		printk(KERN_DEBUG "DiB0070: "); \
-		printk(args); \
-		printk("\n"); \
-	} \
-} while (0)
-
-#define DIB0070_P1D  0x00
-#define DIB0070_P1F  0x01
-#define DIB0070_P1G  0x03
-#define DIB0070S_P1A 0x02
-
-struct dib0070_state {
-	struct i2c_adapter *i2c;
-	struct dvb_frontend *fe;
-	const struct dib0070_config *cfg;
-	u16 wbd_ff_offset;
-	u8 revision;
-
-    enum frontend_tune_state tune_state;
-    u32 current_rf;
-
-    /* for the captrim binary search */
-	s8 step;
-	u16 adc_diff;
-
-	s8 captrim;
-	s8 fcaptrim;
-	u16 lo4;
-
-	const struct dib0070_tuning *current_tune_table_index;
-	const struct dib0070_lna_match *lna_match;
-
-    u8  wbd_gain_current;
-	u16 wbd_offset_3_3[2];
-
-	/* for the I2C transfer */
-	struct i2c_msg msg[2];
-	u8 i2c_write_buffer[3];
-	u8 i2c_read_buffer[2];
-	struct mutex i2c_buffer_lock;
-};
-
-static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg)
-{
-	u16 ret;
-
-	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return 0;
-	}
-
-	state->i2c_write_buffer[0] = reg;
-
-	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
-	state->msg[0].addr = state->cfg->i2c_address;
-	state->msg[0].flags = 0;
-	state->msg[0].buf = state->i2c_write_buffer;
-	state->msg[0].len = 1;
-	state->msg[1].addr = state->cfg->i2c_address;
-	state->msg[1].flags = I2C_M_RD;
-	state->msg[1].buf = state->i2c_read_buffer;
-	state->msg[1].len = 2;
-
-	if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
-		printk(KERN_WARNING "DiB0070 I2C read failed\n");
-		ret = 0;
-	} else
-		ret = (state->i2c_read_buffer[0] << 8)
-			| state->i2c_read_buffer[1];
-
-	mutex_unlock(&state->i2c_buffer_lock);
-	return ret;
-}
-
-static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
-{
-	int ret;
-
-	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return -EINVAL;
-	}
-	state->i2c_write_buffer[0] = reg;
-	state->i2c_write_buffer[1] = val >> 8;
-	state->i2c_write_buffer[2] = val & 0xff;
-
-	memset(state->msg, 0, sizeof(struct i2c_msg));
-	state->msg[0].addr = state->cfg->i2c_address;
-	state->msg[0].flags = 0;
-	state->msg[0].buf = state->i2c_write_buffer;
-	state->msg[0].len = 3;
-
-	if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
-		printk(KERN_WARNING "DiB0070 I2C write failed\n");
-		ret = -EREMOTEIO;
-	} else
-		ret = 0;
-
-	mutex_unlock(&state->i2c_buffer_lock);
-	return ret;
-}
-
-#define HARD_RESET(state) do { \
-    state->cfg->sleep(state->fe, 0); \
-    if (state->cfg->reset) { \
-	state->cfg->reset(state->fe,1); msleep(10); \
-	state->cfg->reset(state->fe,0); msleep(10); \
-    } \
-} while (0)
-
-static int dib0070_set_bandwidth(struct dvb_frontend *fe)
-{
-    struct dib0070_state *state = fe->tuner_priv;
-    u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff;
-
-    if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 7000)
-	tmp |= (0 << 14);
-    else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 6000)
-	tmp |= (1 << 14);
-    else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 5000)
-	tmp |= (2 << 14);
-    else
-	tmp |= (3 << 14);
-
-    dib0070_write_reg(state, 0x02, tmp);
-
-    /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */
-    if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) {
-	u16 value = dib0070_read_reg(state, 0x17);
-
-	dib0070_write_reg(state, 0x17, value & 0xfffc);
-	tmp = dib0070_read_reg(state, 0x01) & 0x01ff;
-	dib0070_write_reg(state, 0x01, tmp | (60 << 9));
-
-	dib0070_write_reg(state, 0x17, value);
-    }
-	return 0;
-}
-
-static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state *tune_state)
-{
-	int8_t step_sign;
-	u16 adc;
-	int ret = 0;
-
-	if (*tune_state == CT_TUNER_STEP_0) {
-
-		dib0070_write_reg(state, 0x0f, 0xed10);
-		dib0070_write_reg(state, 0x17,    0x0034);
-
-		dib0070_write_reg(state, 0x18, 0x0032);
-		state->step = state->captrim = state->fcaptrim = 64;
-		state->adc_diff = 3000;
-		ret = 20;
-
-	*tune_state = CT_TUNER_STEP_1;
-	} else if (*tune_state == CT_TUNER_STEP_1) {
-		state->step /= 2;
-		dib0070_write_reg(state, 0x14, state->lo4 | state->captrim);
-		ret = 15;
-
-		*tune_state = CT_TUNER_STEP_2;
-	} else if (*tune_state == CT_TUNER_STEP_2) {
-
-		adc = dib0070_read_reg(state, 0x19);
-
-		dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->captrim, adc, (u32) adc*(u32)1800/(u32)1024);
-
-		if (adc >= 400) {
-			adc -= 400;
-			step_sign = -1;
-		} else {
-			adc = 400 - adc;
-			step_sign = 1;
-		}
-
-		if (adc < state->adc_diff) {
-			dprintk("CAPTRIM=%hd is closer to target (%hd/%hd)", state->captrim, adc, state->adc_diff);
-			state->adc_diff = adc;
-			state->fcaptrim = state->captrim;
-
-
-
-		}
-		state->captrim += (step_sign * state->step);
-
-		if (state->step >= 1)
-			*tune_state = CT_TUNER_STEP_1;
-		else
-			*tune_state = CT_TUNER_STEP_3;
-
-	} else if (*tune_state == CT_TUNER_STEP_3) {
-		dib0070_write_reg(state, 0x14, state->lo4 | state->fcaptrim);
-		dib0070_write_reg(state, 0x18, 0x07ff);
-		*tune_state = CT_TUNER_STEP_4;
-	}
-
-	return ret;
-}
-
-static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt)
-{
-	struct dib0070_state *state = fe->tuner_priv;
-    u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
-	dprintk("CTRL_LO5: 0x%x", lo5);
-	return dib0070_write_reg(state, 0x15, lo5);
-}
-
-void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open)
-{
-	struct dib0070_state *state = fe->tuner_priv;
-
-	if (open) {
-		dib0070_write_reg(state, 0x1b, 0xff00);
-		dib0070_write_reg(state, 0x1a, 0x0000);
-	} else {
-		dib0070_write_reg(state, 0x1b, 0x4112);
-	if (state->cfg->vga_filter != 0) {
-		dib0070_write_reg(state, 0x1a, state->cfg->vga_filter);
-		dprintk("vga filter register is set to %x", state->cfg->vga_filter);
-	} else
-		dib0070_write_reg(state, 0x1a, 0x0009);
-	}
-}
-
-EXPORT_SYMBOL(dib0070_ctrl_agc_filter);
-struct dib0070_tuning {
-    u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
-    u8 switch_trim;
-    u8 vco_band;
-    u8 hfdiv;
-    u8 vco_multi;
-    u8 presc;
-    u8 wbdmux;
-    u16 tuner_enable;
-};
-
-struct dib0070_lna_match {
-    u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
-    u8 lna_band;
-};
-
-static const struct dib0070_tuning dib0070s_tuning_table[] = {
-    {     570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */
-    {     700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 },
-    {     863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 },
-    {    1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */
-    {    1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
-    {    2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
-    { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */
-};
-
-static const struct dib0070_tuning dib0070_tuning_table[] = {
-    {     115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */
-    {     179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */
-    {     189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 },
-    {     250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 },
-    {     569999, 2, 1, 5,  6, 2, 2, 0x4000 | 0x0800 }, /* UHF */
-    {     699999, 2, 0, 1,  4, 2, 2, 0x4000 | 0x0800 },
-    {     863999, 2, 1, 1,  4, 2, 2, 0x4000 | 0x0800 },
-    { 0xffffffff, 0, 1, 0,  2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */
-};
-
-static const struct dib0070_lna_match dib0070_lna_flip_chip[] = {
-    {     180000, 0 }, /* VHF */
-    {     188000, 1 },
-    {     196400, 2 },
-    {     250000, 3 },
-    {     550000, 0 }, /* UHF */
-    {     590000, 1 },
-    {     666000, 3 },
-    {     864000, 5 },
-    {    1500000, 0 }, /* LBAND or everything higher than UHF */
-    {    1600000, 1 },
-    {    2000000, 3 },
-    { 0xffffffff, 7 },
-};
-
-static const struct dib0070_lna_match dib0070_lna[] = {
-    {     180000, 0 }, /* VHF */
-    {     188000, 1 },
-    {     196400, 2 },
-    {     250000, 3 },
-    {     550000, 2 }, /* UHF */
-    {     650000, 3 },
-    {     750000, 5 },
-    {     850000, 6 },
-    {     864000, 7 },
-    {    1500000, 0 }, /* LBAND or everything higher than UHF */
-    {    1600000, 1 },
-    {    2000000, 3 },
-    { 0xffffffff, 7 },
-};
-
-#define LPF	100
-static int dib0070_tune_digital(struct dvb_frontend *fe)
-{
-    struct dib0070_state *state = fe->tuner_priv;
-
-    const struct dib0070_tuning *tune;
-    const struct dib0070_lna_match *lna_match;
-
-    enum frontend_tune_state *tune_state = &state->tune_state;
-    int ret = 10; /* 1ms is the default delay most of the time */
-
-    u8  band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000);
-    u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf);
-
-#ifdef CONFIG_SYS_ISDBT
-    if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1)
-		if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2)
-		     && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
-		    || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
-			&& (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2)))
-		    || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
-			&& (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))))
-			freq += 850;
-#endif
-    if (state->current_rf != freq) {
-
-	switch (state->revision) {
-	case DIB0070S_P1A:
-	    tune = dib0070s_tuning_table;
-	    lna_match = dib0070_lna;
-	    break;
-	default:
-	    tune = dib0070_tuning_table;
-	    if (state->cfg->flip_chip)
-		lna_match = dib0070_lna_flip_chip;
-	    else
-		lna_match = dib0070_lna;
-	    break;
-	}
-	while (freq > tune->max_freq) /* find the right one */
-	    tune++;
-	while (freq > lna_match->max_freq) /* find the right one */
-	    lna_match++;
-
-	state->current_tune_table_index = tune;
-	state->lna_match = lna_match;
-    }
-
-    if (*tune_state == CT_TUNER_START) {
-	dprintk("Tuning for Band: %hd (%d kHz)", band, freq);
-	if (state->current_rf != freq) {
-		u8 REFDIV;
-		u32 FBDiv, Rest, FREF, VCOF_kHz;
-		u8 Den;
-
-		state->current_rf = freq;
-		state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7);
-
-
-		dib0070_write_reg(state, 0x17, 0x30);
-
-
-		VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2;
-
-		switch (band) {
-		case BAND_VHF:
-			REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000);
-			break;
-		case BAND_FM:
-			REFDIV = (u8) ((state->cfg->clock_khz) / 1000);
-			break;
-		default:
-			REFDIV = (u8) (state->cfg->clock_khz  / 10000);
-			break;
-		}
-		FREF = state->cfg->clock_khz / REFDIV;
-
-
-
-		switch (state->revision) {
-		case DIB0070S_P1A:
-			FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF);
-			Rest  = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF;
-			break;
-
-		case DIB0070_P1G:
-		case DIB0070_P1F:
-		default:
-			FBDiv = (freq / (FREF / 2));
-			Rest  = 2 * freq - FBDiv * FREF;
-			break;
-		}
-
-		if (Rest < LPF)
-			Rest = 0;
-		else if (Rest < 2 * LPF)
-			Rest = 2 * LPF;
-		else if (Rest > (FREF - LPF)) {
-			Rest = 0;
-			FBDiv += 1;
-		} else if (Rest > (FREF - 2 * LPF))
-			Rest = FREF - 2 * LPF;
-		Rest = (Rest * 6528) / (FREF / 10);
-
-		Den = 1;
-		if (Rest > 0) {
-			state->lo4 |= (1 << 14) | (1 << 12);
-			Den = 255;
-		}
-
-
-		dib0070_write_reg(state, 0x11, (u16)FBDiv);
-		dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV);
-		dib0070_write_reg(state, 0x13, (u16) Rest);
-
-		if (state->revision == DIB0070S_P1A) {
-
-			if (band == BAND_SBAND) {
-				dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
-				dib0070_write_reg(state, 0x1d, 0xFFFF);
-			} else
-				dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1);
-		}
-
-		dib0070_write_reg(state, 0x20,
-			0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable);
-
-		dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF);
-		dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest);
-		dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1);
-		dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv);
-		dprintk("VCO = %hd", state->current_tune_table_index->vco_band);
-		dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq);
-
-		*tune_state = CT_TUNER_STEP_0;
-	} else { /* we are already tuned to this frequency - the configuration is correct  */
-		ret = 50; /* wakeup time */
-		*tune_state = CT_TUNER_STEP_5;
-	}
-    } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) {
-
-	ret = dib0070_captrim(state, tune_state);
-
-    } else if (*tune_state == CT_TUNER_STEP_4) {
-	const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
-	if (tmp != NULL) {
-		while (freq/1000 > tmp->freq) /* find the right one */
-			tmp++;
-		dib0070_write_reg(state, 0x0f,
-			(0 << 15) | (1 << 14) | (3 << 12)
-			| (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7)
-			| (state->current_tune_table_index->wbdmux << 0));
-		state->wbd_gain_current = tmp->wbd_gain_val;
-	} else {
-			dib0070_write_reg(state, 0x0f,
-					  (0 << 15) | (1 << 14) | (3 << 12) | (6 << 9) | (0 << 8) | (1 << 7) | (state->current_tune_table_index->
-														wbdmux << 0));
-	    state->wbd_gain_current = 6;
-	}
-
-	dib0070_write_reg(state, 0x06, 0x3fff);
-		dib0070_write_reg(state, 0x07,
-				  (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0));
-	dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127));
-	dib0070_write_reg(state, 0x0d, 0x0d80);
-
-
-	dib0070_write_reg(state, 0x18,   0x07ff);
-	dib0070_write_reg(state, 0x17, 0x0033);
-
-
-	*tune_state = CT_TUNER_STEP_5;
-    } else if (*tune_state == CT_TUNER_STEP_5) {
-	dib0070_set_bandwidth(fe);
-	*tune_state = CT_TUNER_STOP;
-    } else {
-	ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */
-    }
-    return ret;
-}
-
-
-static int dib0070_tune(struct dvb_frontend *fe)
-{
-    struct dib0070_state *state = fe->tuner_priv;
-    uint32_t ret;
-
-    state->tune_state = CT_TUNER_START;
-
-    do {
-	ret = dib0070_tune_digital(fe);
-	if (ret != FE_CALLBACK_TIME_NEVER)
-		msleep(ret/10);
-	else
-	    break;
-    } while (state->tune_state != CT_TUNER_STOP);
-
-    return 0;
-}
-
-static int dib0070_wakeup(struct dvb_frontend *fe)
-{
-	struct dib0070_state *state = fe->tuner_priv;
-	if (state->cfg->sleep)
-		state->cfg->sleep(fe, 0);
-	return 0;
-}
-
-static int dib0070_sleep(struct dvb_frontend *fe)
-{
-	struct dib0070_state *state = fe->tuner_priv;
-	if (state->cfg->sleep)
-		state->cfg->sleep(fe, 1);
-	return 0;
-}
-
-u8 dib0070_get_rf_output(struct dvb_frontend *fe)
-{
-	struct dib0070_state *state = fe->tuner_priv;
-	return (dib0070_read_reg(state, 0x07) >> 11) & 0x3;
-}
-EXPORT_SYMBOL(dib0070_get_rf_output);
-
-int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no)
-{
-	struct dib0070_state *state = fe->tuner_priv;
-	u16 rxrf2 = dib0070_read_reg(state, 0x07) & 0xfe7ff;
-	if (no > 3)
-		no = 3;
-	if (no < 1)
-		no = 1;
-	return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11));
-}
-EXPORT_SYMBOL(dib0070_set_rf_output);
-
-static const u16 dib0070_p1f_defaults[] =
-
-{
-	7, 0x02,
-		0x0008,
-		0x0000,
-		0x0000,
-		0x0000,
-		0x0000,
-		0x0002,
-		0x0100,
-
-	3, 0x0d,
-		0x0d80,
-		0x0001,
-		0x0000,
-
-	4, 0x11,
-		0x0000,
-		0x0103,
-		0x0000,
-		0x0000,
-
-	3, 0x16,
-		0x0004 | 0x0040,
-		0x0030,
-		0x07ff,
-
-	6, 0x1b,
-		0x4112,
-		0xff00,
-		0xc07f,
-		0x0000,
-		0x0180,
-		0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
-
-	0,
-};
-
-static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain)
-{
-    u16 tuner_en = dib0070_read_reg(state, 0x20);
-    u16 offset;
-
-    dib0070_write_reg(state, 0x18, 0x07ff);
-    dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
-    dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0));
-    msleep(9);
-    offset = dib0070_read_reg(state, 0x19);
-    dib0070_write_reg(state, 0x20, tuner_en);
-    return offset;
-}
-
-static void dib0070_wbd_offset_calibration(struct dib0070_state *state)
-{
-    u8 gain;
-    for (gain = 6; gain < 8; gain++) {
-	state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2);
-	dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain-6]);
-    }
-}
-
-u16 dib0070_wbd_offset(struct dvb_frontend *fe)
-{
-    struct dib0070_state *state = fe->tuner_priv;
-    const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
-    u32 freq = fe->dtv_property_cache.frequency/1000;
-
-    if (tmp != NULL) {
-	while (freq/1000 > tmp->freq) /* find the right one */
-	    tmp++;
-	state->wbd_gain_current = tmp->wbd_gain_val;
-	} else
-	state->wbd_gain_current = 6;
-
-    return state->wbd_offset_3_3[state->wbd_gain_current - 6];
-}
-EXPORT_SYMBOL(dib0070_wbd_offset);
-
-#define pgm_read_word(w) (*w)
-static int dib0070_reset(struct dvb_frontend *fe)
-{
-    struct dib0070_state *state = fe->tuner_priv;
-	u16 l, r, *n;
-
-	HARD_RESET(state);
-
-
-#ifndef FORCE_SBAND_TUNER
-	if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
-		state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
-	else
-#else
-#warning forcing SBAND
-#endif
-		state->revision = DIB0070S_P1A;
-
-	/* P1F or not */
-	dprintk("Revision: %x", state->revision);
-
-	if (state->revision == DIB0070_P1D) {
-		dprintk("Error: this driver is not to be used meant for P1D or earlier");
-		return -EINVAL;
-	}
-
-	n = (u16 *) dib0070_p1f_defaults;
-	l = pgm_read_word(n++);
-	while (l) {
-		r = pgm_read_word(n++);
-		do {
-			dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
-			r++;
-		} while (--l);
-		l = pgm_read_word(n++);
-	}
-
-	if (state->cfg->force_crystal_mode != 0)
-		r = state->cfg->force_crystal_mode;
-	else if (state->cfg->clock_khz >= 24000)
-		r = 1;
-	else
-		r = 2;
-
-
-	r |= state->cfg->osc_buffer_state << 3;
-
-	dib0070_write_reg(state, 0x10, r);
-	dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5));
-
-	if (state->cfg->invert_iq) {
-		r = dib0070_read_reg(state, 0x02) & 0xffdf;
-		dib0070_write_reg(state, 0x02, r | (1 << 5));
-	}
-
-    if (state->revision == DIB0070S_P1A)
-	dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
-    else
-		dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, state->cfg->enable_third_order_filter);
-
-	dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
-
-    dib0070_wbd_offset_calibration(state);
-
-    return 0;
-}
-
-static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-    struct dib0070_state *state = fe->tuner_priv;
-
-    *frequency = 1000 * state->current_rf;
-    return 0;
-}
-
-static int dib0070_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static const struct dvb_tuner_ops dib0070_ops = {
-	.info = {
-		.name           = "DiBcom DiB0070",
-		.frequency_min  =  45000000,
-		.frequency_max  = 860000000,
-		.frequency_step =      1000,
-	},
-	.release       = dib0070_release,
-
-	.init          = dib0070_wakeup,
-	.sleep         = dib0070_sleep,
-	.set_params    = dib0070_tune,
-
-	.get_frequency = dib0070_get_frequency,
-//      .get_bandwidth = dib0070_get_bandwidth
-};
-
-struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
-{
-	struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
-	if (state == NULL)
-		return NULL;
-
-	state->cfg = cfg;
-	state->i2c = i2c;
-	state->fe  = fe;
-	mutex_init(&state->i2c_buffer_lock);
-	fe->tuner_priv = state;
-
-	if (dib0070_reset(fe) != 0)
-		goto free_mem;
-
-	printk(KERN_INFO "DiB0070: successfully identified\n");
-	memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
-
-	fe->tuner_priv = state;
-	return fe;
-
-free_mem:
-	kfree(state);
-	fe->tuner_priv = NULL;
-	return NULL;
-}
-EXPORT_SYMBOL(dib0070_attach);
-
-MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
-MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h
deleted file mode 100644
index 45c31fa..0000000
--- a/drivers/media/dvb/frontends/dib0070.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
- *
- * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
- *
- * 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, version 2.
- */
-#ifndef DIB0070_H
-#define DIB0070_H
-
-struct dvb_frontend;
-struct i2c_adapter;
-
-#define DEFAULT_DIB0070_I2C_ADDRESS 0x60
-
-struct dib0070_wbd_gain_cfg {
-	u16 freq;
-	u16 wbd_gain_val;
-};
-
-struct dib0070_config {
-	u8 i2c_address;
-
-	/* tuner pins controlled externally */
-	int (*reset) (struct dvb_frontend *, int);
-	int (*sleep) (struct dvb_frontend *, int);
-
-	/*  offset in kHz */
-	int freq_offset_khz_uhf;
-	int freq_offset_khz_vhf;
-
-	u8 osc_buffer_state;	/* 0= normal, 1= tri-state */
-	u32 clock_khz;
-	u8 clock_pad_drive;	/* (Drive + 1) * 2mA */
-
-	u8 invert_iq;		/* invert Q - in case I or Q is inverted on the board */
-
-	u8 force_crystal_mode;	/* if == 0 -> decision is made in the driver default: <24 -> 2, >=24 -> 1 */
-
-	u8 flip_chip;
-	u8 enable_third_order_filter;
-	u8 charge_pump;
-
-	const struct dib0070_wbd_gain_cfg *wbd_gain;
-
-	u8 vga_filter;
-};
-
-#if defined(CONFIG_DVB_TUNER_DIB0070) || (defined(CONFIG_DVB_TUNER_DIB0070_MODULE) && defined(MODULE))
-extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg);
-extern u16 dib0070_wbd_offset(struct dvb_frontend *);
-extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, u8 open);
-extern u8 dib0070_get_rf_output(struct dvb_frontend *fe);
-extern int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no);
-#else
-static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return 0;
-}
-
-static inline void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-}
-#endif
-
-#endif
diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c
deleted file mode 100644
index d9fe60b..0000000
--- a/drivers/media/dvb/frontends/dib0090.c
+++ /dev/null
@@ -1,2686 +0,0 @@
-/*
- * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner.
- *
- * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * This code is more or less generated from another driver, please
- * excuse some codingstyle oddities.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-
-#include "dvb_frontend.h"
-
-#include "dib0090.h"
-#include "dibx000_common.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
-
-#define dprintk(args...) do { \
-	if (debug) { \
-		printk(KERN_DEBUG "DiB0090: "); \
-		printk(args); \
-		printk("\n"); \
-	} \
-} while (0)
-
-#define CONFIG_SYS_DVBT
-#define CONFIG_SYS_ISDBT
-#define CONFIG_BAND_CBAND
-#define CONFIG_BAND_VHF
-#define CONFIG_BAND_UHF
-#define CONFIG_DIB0090_USE_PWM_AGC
-
-#define EN_LNA0      0x8000
-#define EN_LNA1      0x4000
-#define EN_LNA2      0x2000
-#define EN_LNA3      0x1000
-#define EN_MIX0      0x0800
-#define EN_MIX1      0x0400
-#define EN_MIX2      0x0200
-#define EN_MIX3      0x0100
-#define EN_IQADC     0x0040
-#define EN_PLL       0x0020
-#define EN_TX        0x0010
-#define EN_BB        0x0008
-#define EN_LO        0x0004
-#define EN_BIAS      0x0001
-
-#define EN_IQANA     0x0002
-#define EN_DIGCLK    0x0080	/* not in the 0x24 reg, only in 0x1b */
-#define EN_CRYSTAL   0x0002
-
-#define EN_UHF		 0x22E9
-#define EN_VHF		 0x44E9
-#define EN_LBD		 0x11E9
-#define EN_SBD		 0x44E9
-#define EN_CAB		 0x88E9
-
-/* Calibration defines */
-#define      DC_CAL 0x1
-#define     WBD_CAL 0x2
-#define    TEMP_CAL 0x4
-#define CAPTRIM_CAL 0x8
-
-#define KROSUS_PLL_LOCKED   0x800
-#define KROSUS              0x2
-
-/* Use those defines to identify SOC version */
-#define SOC               0x02
-#define SOC_7090_P1G_11R1 0x82
-#define SOC_7090_P1G_21R1 0x8a
-#define SOC_8090_P1G_11R1 0x86
-#define SOC_8090_P1G_21R1 0x8e
-
-/* else use thos ones to check */
-#define P1A_B      0x0
-#define P1C	   0x1
-#define P1D_E_F    0x3
-#define P1G	   0x7
-#define P1G_21R2   0xf
-
-#define MP001 0x1		/* Single 9090/8096 */
-#define MP005 0x4		/* Single Sband */
-#define MP008 0x6		/* Dual diversity VHF-UHF-LBAND */
-#define MP009 0x7		/* Dual diversity 29098 CBAND-UHF-LBAND-SBAND */
-
-#define pgm_read_word(w) (*w)
-
-struct dc_calibration;
-
-struct dib0090_tuning {
-	u32 max_freq;		/* for every frequency less than or equal to that field: this information is correct */
-	u8 switch_trim;
-	u8 lna_tune;
-	u16 lna_bias;
-	u16 v2i;
-	u16 mix;
-	u16 load;
-	u16 tuner_enable;
-};
-
-struct dib0090_pll {
-	u32 max_freq;		/* for every frequency less than or equal to that field: this information is correct */
-	u8 vco_band;
-	u8 hfdiv_code;
-	u8 hfdiv;
-	u8 topresc;
-};
-
-struct dib0090_identity {
-	u8 version;
-	u8 product;
-	u8 p1g;
-	u8 in_soc;
-};
-
-struct dib0090_state {
-	struct i2c_adapter *i2c;
-	struct dvb_frontend *fe;
-	const struct dib0090_config *config;
-
-	u8 current_band;
-	enum frontend_tune_state tune_state;
-	u32 current_rf;
-
-	u16 wbd_offset;
-	s16 wbd_target;		/* in dB */
-
-	s16 rf_gain_limit;	/* take-over-point: where to split between bb and rf gain */
-	s16 current_gain;	/* keeps the currently programmed gain */
-	u8 agc_step;		/* new binary search */
-
-	u16 gain[2];		/* for channel monitoring */
-
-	const u16 *rf_ramp;
-	const u16 *bb_ramp;
-
-	/* for the software AGC ramps */
-	u16 bb_1_def;
-	u16 rf_lt_def;
-	u16 gain_reg[4];
-
-	/* for the captrim/dc-offset search */
-	s8 step;
-	s16 adc_diff;
-	s16 min_adc_diff;
-
-	s8 captrim;
-	s8 fcaptrim;
-
-	const struct dc_calibration *dc;
-	u16 bb6, bb7;
-
-	const struct dib0090_tuning *current_tune_table_index;
-	const struct dib0090_pll *current_pll_table_index;
-
-	u8 tuner_is_tuned;
-	u8 agc_freeze;
-
-	struct dib0090_identity identity;
-
-	u32 rf_request;
-	u8 current_standard;
-
-	u8 calibrate;
-	u32 rest;
-	u16 bias;
-	s16 temperature;
-
-	u8 wbd_calibration_gain;
-	const struct dib0090_wbd_slope *current_wbd_table;
-	u16 wbdmux;
-
-	/* for the I2C transfer */
-	struct i2c_msg msg[2];
-	u8 i2c_write_buffer[3];
-	u8 i2c_read_buffer[2];
-	struct mutex i2c_buffer_lock;
-};
-
-struct dib0090_fw_state {
-	struct i2c_adapter *i2c;
-	struct dvb_frontend *fe;
-	struct dib0090_identity identity;
-	const struct dib0090_config *config;
-
-	/* for the I2C transfer */
-	struct i2c_msg msg;
-	u8 i2c_write_buffer[2];
-	u8 i2c_read_buffer[2];
-	struct mutex i2c_buffer_lock;
-};
-
-static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
-{
-	u16 ret;
-
-	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return 0;
-	}
-
-	state->i2c_write_buffer[0] = reg;
-
-	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
-	state->msg[0].addr = state->config->i2c_address;
-	state->msg[0].flags = 0;
-	state->msg[0].buf = state->i2c_write_buffer;
-	state->msg[0].len = 1;
-	state->msg[1].addr = state->config->i2c_address;
-	state->msg[1].flags = I2C_M_RD;
-	state->msg[1].buf = state->i2c_read_buffer;
-	state->msg[1].len = 2;
-
-	if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
-		printk(KERN_WARNING "DiB0090 I2C read failed\n");
-		ret = 0;
-	} else
-		ret = (state->i2c_read_buffer[0] << 8)
-			| state->i2c_read_buffer[1];
-
-	mutex_unlock(&state->i2c_buffer_lock);
-	return ret;
-}
-
-static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
-{
-	int ret;
-
-	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return -EINVAL;
-	}
-
-	state->i2c_write_buffer[0] = reg & 0xff;
-	state->i2c_write_buffer[1] = val >> 8;
-	state->i2c_write_buffer[2] = val & 0xff;
-
-	memset(state->msg, 0, sizeof(struct i2c_msg));
-	state->msg[0].addr = state->config->i2c_address;
-	state->msg[0].flags = 0;
-	state->msg[0].buf = state->i2c_write_buffer;
-	state->msg[0].len = 3;
-
-	if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
-		printk(KERN_WARNING "DiB0090 I2C write failed\n");
-		ret = -EREMOTEIO;
-	} else
-		ret = 0;
-
-	mutex_unlock(&state->i2c_buffer_lock);
-	return ret;
-}
-
-static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
-{
-	u16 ret;
-
-	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return 0;
-	}
-
-	state->i2c_write_buffer[0] = reg;
-
-	memset(&state->msg, 0, sizeof(struct i2c_msg));
-	state->msg.addr = reg;
-	state->msg.flags = I2C_M_RD;
-	state->msg.buf = state->i2c_read_buffer;
-	state->msg.len = 2;
-	if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
-		printk(KERN_WARNING "DiB0090 I2C read failed\n");
-		ret = 0;
-	} else
-		ret = (state->i2c_read_buffer[0] << 8)
-			| state->i2c_read_buffer[1];
-
-	mutex_unlock(&state->i2c_buffer_lock);
-	return ret;
-}
-
-static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
-{
-	int ret;
-
-	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return -EINVAL;
-	}
-
-	state->i2c_write_buffer[0] = val >> 8;
-	state->i2c_write_buffer[1] = val & 0xff;
-
-	memset(&state->msg, 0, sizeof(struct i2c_msg));
-	state->msg.addr = reg;
-	state->msg.flags = 0;
-	state->msg.buf = state->i2c_write_buffer;
-	state->msg.len = 2;
-	if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
-		printk(KERN_WARNING "DiB0090 I2C write failed\n");
-		ret = -EREMOTEIO;
-	} else
-		ret = 0;
-
-	mutex_unlock(&state->i2c_buffer_lock);
-	return ret;
-}
-
-#define HARD_RESET(state) do {  if (cfg->reset) {  if (cfg->sleep) cfg->sleep(fe, 0); msleep(10);  cfg->reset(fe, 1); msleep(10);  cfg->reset(fe, 0); msleep(10);  }  } while (0)
-#define ADC_TARGET -220
-#define GAIN_ALPHA 5
-#define WBD_ALPHA 6
-#define LPF	100
-static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, u8 c)
-{
-	do {
-		dib0090_write_reg(state, r++, *b++);
-	} while (--c);
-}
-
-static int dib0090_identify(struct dvb_frontend *fe)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-	u16 v;
-	struct dib0090_identity *identity = &state->identity;
-
-	v = dib0090_read_reg(state, 0x1a);
-
-	identity->p1g = 0;
-	identity->in_soc = 0;
-
-	dprintk("Tuner identification (Version = 0x%04x)", v);
-
-	/* without PLL lock info */
-	v &= ~KROSUS_PLL_LOCKED;
-
-	identity->version = v & 0xff;
-	identity->product = (v >> 8) & 0xf;
-
-	if (identity->product != KROSUS)
-		goto identification_error;
-
-	if ((identity->version & 0x3) == SOC) {
-		identity->in_soc = 1;
-		switch (identity->version) {
-		case SOC_8090_P1G_11R1:
-			dprintk("SOC 8090 P1-G11R1 Has been detected");
-			identity->p1g = 1;
-			break;
-		case SOC_8090_P1G_21R1:
-			dprintk("SOC 8090 P1-G21R1 Has been detected");
-			identity->p1g = 1;
-			break;
-		case SOC_7090_P1G_11R1:
-			dprintk("SOC 7090 P1-G11R1 Has been detected");
-			identity->p1g = 1;
-			break;
-		case SOC_7090_P1G_21R1:
-			dprintk("SOC 7090 P1-G21R1 Has been detected");
-			identity->p1g = 1;
-			break;
-		default:
-			goto identification_error;
-		}
-	} else {
-		switch ((identity->version >> 5) & 0x7) {
-		case MP001:
-			dprintk("MP001 : 9090/8096");
-			break;
-		case MP005:
-			dprintk("MP005 : Single Sband");
-			break;
-		case MP008:
-			dprintk("MP008 : diversity VHF-UHF-LBAND");
-			break;
-		case MP009:
-			dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND");
-			break;
-		default:
-			goto identification_error;
-		}
-
-		switch (identity->version & 0x1f) {
-		case P1G_21R2:
-			dprintk("P1G_21R2 detected");
-			identity->p1g = 1;
-			break;
-		case P1G:
-			dprintk("P1G detected");
-			identity->p1g = 1;
-			break;
-		case P1D_E_F:
-			dprintk("P1D/E/F detected");
-			break;
-		case P1C:
-			dprintk("P1C detected");
-			break;
-		case P1A_B:
-			dprintk("P1-A/B detected: driver is deactivated - not available");
-			goto identification_error;
-			break;
-		default:
-			goto identification_error;
-		}
-	}
-
-	return 0;
-
-identification_error:
-	return -EIO;
-}
-
-static int dib0090_fw_identify(struct dvb_frontend *fe)
-{
-	struct dib0090_fw_state *state = fe->tuner_priv;
-	struct dib0090_identity *identity = &state->identity;
-
-	u16 v = dib0090_fw_read_reg(state, 0x1a);
-	identity->p1g = 0;
-	identity->in_soc = 0;
-
-	dprintk("FE: Tuner identification (Version = 0x%04x)", v);
-
-	/* without PLL lock info */
-	v &= ~KROSUS_PLL_LOCKED;
-
-	identity->version = v & 0xff;
-	identity->product = (v >> 8) & 0xf;
-
-	if (identity->product != KROSUS)
-		goto identification_error;
-
-	if ((identity->version & 0x3) == SOC) {
-		identity->in_soc = 1;
-		switch (identity->version) {
-		case SOC_8090_P1G_11R1:
-			dprintk("SOC 8090 P1-G11R1 Has been detected");
-			identity->p1g = 1;
-			break;
-		case SOC_8090_P1G_21R1:
-			dprintk("SOC 8090 P1-G21R1 Has been detected");
-			identity->p1g = 1;
-			break;
-		case SOC_7090_P1G_11R1:
-			dprintk("SOC 7090 P1-G11R1 Has been detected");
-			identity->p1g = 1;
-			break;
-		case SOC_7090_P1G_21R1:
-			dprintk("SOC 7090 P1-G21R1 Has been detected");
-			identity->p1g = 1;
-			break;
-		default:
-			goto identification_error;
-		}
-	} else {
-		switch ((identity->version >> 5) & 0x7) {
-		case MP001:
-			dprintk("MP001 : 9090/8096");
-			break;
-		case MP005:
-			dprintk("MP005 : Single Sband");
-			break;
-		case MP008:
-			dprintk("MP008 : diversity VHF-UHF-LBAND");
-			break;
-		case MP009:
-			dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND");
-			break;
-		default:
-			goto identification_error;
-		}
-
-		switch (identity->version & 0x1f) {
-		case P1G_21R2:
-			dprintk("P1G_21R2 detected");
-			identity->p1g = 1;
-			break;
-		case P1G:
-			dprintk("P1G detected");
-			identity->p1g = 1;
-			break;
-		case P1D_E_F:
-			dprintk("P1D/E/F detected");
-			break;
-		case P1C:
-			dprintk("P1C detected");
-			break;
-		case P1A_B:
-			dprintk("P1-A/B detected: driver is deactivated - not available");
-			goto identification_error;
-			break;
-		default:
-			goto identification_error;
-		}
-	}
-
-	return 0;
-
-identification_error:
-	return -EIO;
-}
-
-static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-	u16 PllCfg, i, v;
-
-	HARD_RESET(state);
-
-	dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
-	dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL);	/* PLL, DIG_CLK and CRYSTAL remain */
-
-	if (!cfg->in_soc) {
-		/* adcClkOutRatio=8->7, release reset */
-		dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0);
-		if (cfg->clkoutdrive != 0)
-			dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
-					  | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
-		else
-			dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
-					  | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
-	}
-
-	/* Read Pll current config * */
-	PllCfg = dib0090_read_reg(state, 0x21);
-
-	/** Reconfigure PLL if current setting is different from default setting **/
-	if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && (!cfg->in_soc)
-			&& !cfg->io.pll_bypass) {
-
-		/* Set Bypass mode */
-		PllCfg |= (1 << 15);
-		dib0090_write_reg(state, 0x21, PllCfg);
-
-		/* Set Reset Pll */
-		PllCfg &= ~(1 << 13);
-		dib0090_write_reg(state, 0x21, PllCfg);
-
-	/*** Set new Pll configuration in bypass and reset state ***/
-		PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
-		dib0090_write_reg(state, 0x21, PllCfg);
-
-		/* Remove Reset Pll */
-		PllCfg |= (1 << 13);
-		dib0090_write_reg(state, 0x21, PllCfg);
-
-	/*** Wait for PLL lock ***/
-		i = 100;
-		do {
-			v = !!(dib0090_read_reg(state, 0x1a) & 0x800);
-			if (v)
-				break;
-		} while (--i);
-
-		if (i == 0) {
-			dprintk("Pll: Unable to lock Pll");
-			return;
-		}
-
-		/* Finally Remove Bypass mode */
-		PllCfg &= ~(1 << 15);
-		dib0090_write_reg(state, 0x21, PllCfg);
-	}
-
-	if (cfg->io.pll_bypass) {
-		PllCfg |= (cfg->io.pll_bypass << 15);
-		dib0090_write_reg(state, 0x21, PllCfg);
-	}
-}
-
-static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
-{
-	struct dib0090_fw_state *state = fe->tuner_priv;
-	u16 PllCfg;
-	u16 v;
-	int i;
-
-	dprintk("fw reset digital");
-	HARD_RESET(state);
-
-	dib0090_fw_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
-	dib0090_fw_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL);	/* PLL, DIG_CLK and CRYSTAL remain */
-
-	dib0090_fw_write_reg(state, 0x20,
-			((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (cfg->data_tx_drv << 4) | cfg->ls_cfg_pad_drv);
-
-	v = (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 9) | (0 << 8) | (cfg->clkouttobamse << 4) | (0 << 2) | (0);
-	if (cfg->clkoutdrive != 0)
-		v |= cfg->clkoutdrive << 5;
-	else
-		v |= 7 << 5;
-
-	v |= 2 << 10;
-	dib0090_fw_write_reg(state, 0x23, v);
-
-	/* Read Pll current config * */
-	PllCfg = dib0090_fw_read_reg(state, 0x21);
-
-	/** Reconfigure PLL if current setting is different from default setting **/
-	if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && !cfg->io.pll_bypass) {
-
-		/* Set Bypass mode */
-		PllCfg |= (1 << 15);
-		dib0090_fw_write_reg(state, 0x21, PllCfg);
-
-		/* Set Reset Pll */
-		PllCfg &= ~(1 << 13);
-		dib0090_fw_write_reg(state, 0x21, PllCfg);
-
-	/*** Set new Pll configuration in bypass and reset state ***/
-		PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
-		dib0090_fw_write_reg(state, 0x21, PllCfg);
-
-		/* Remove Reset Pll */
-		PllCfg |= (1 << 13);
-		dib0090_fw_write_reg(state, 0x21, PllCfg);
-
-	/*** Wait for PLL lock ***/
-		i = 100;
-		do {
-			v = !!(dib0090_fw_read_reg(state, 0x1a) & 0x800);
-			if (v)
-				break;
-		} while (--i);
-
-		if (i == 0) {
-			dprintk("Pll: Unable to lock Pll");
-			return -EIO;
-		}
-
-		/* Finally Remove Bypass mode */
-		PllCfg &= ~(1 << 15);
-		dib0090_fw_write_reg(state, 0x21, PllCfg);
-	}
-
-	if (cfg->io.pll_bypass) {
-		PllCfg |= (cfg->io.pll_bypass << 15);
-		dib0090_fw_write_reg(state, 0x21, PllCfg);
-	}
-
-	return dib0090_fw_identify(fe);
-}
-
-static int dib0090_wakeup(struct dvb_frontend *fe)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-	if (state->config->sleep)
-		state->config->sleep(fe, 0);
-
-	/* enable dataTX in case we have been restarted in the wrong moment */
-	dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
-	return 0;
-}
-
-static int dib0090_sleep(struct dvb_frontend *fe)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-	if (state->config->sleep)
-		state->config->sleep(fe, 1);
-	return 0;
-}
-
-void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-	if (fast)
-		dib0090_write_reg(state, 0x04, 0);
-	else
-		dib0090_write_reg(state, 0x04, 1);
-}
-
-EXPORT_SYMBOL(dib0090_dcc_freq);
-
-static const u16 bb_ramp_pwm_normal_socs[] = {
-	550,			/* max BB gain in 10th of dB */
-	(1 << 9) | 8,		/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
-	440,
-	(4 << 9) | 0,		/* BB_RAMP3 = 26dB */
-	(0 << 9) | 208,		/* BB_RAMP4 */
-	(4 << 9) | 208,		/* BB_RAMP5 = 29dB */
-	(0 << 9) | 440,		/* BB_RAMP6 */
-};
-
-static const u16 rf_ramp_pwm_cband_7090[] = {
-	280,			/* max RF gain in 10th of dB */
-	18,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
-	504,			/* ramp_max = maximum X used on the ramp */
-	(29 << 10) | 364,	/* RF_RAMP5, LNA 1 = 8dB */
-	(0 << 10) | 504,	/* RF_RAMP6, LNA 1 */
-	(60 << 10) | 228,	/* RF_RAMP7, LNA 2 = 7.7dB */
-	(0 << 10) | 364,	/* RF_RAMP8, LNA 2 */
-	(34 << 10) | 109,	/* GAIN_4_1, LNA 3 = 6.8dB */
-	(0 << 10) | 228,	/* GAIN_4_2, LNA 3 */
-	(37 << 10) | 0,		/* RF_RAMP3, LNA 4 = 6.2dB */
-	(0 << 10) | 109,	/* RF_RAMP4, LNA 4 */
-};
-
-static const uint16_t rf_ramp_pwm_cband_7090e_sensitivity[] = {
-	186,
-	40,
-	746,
-	(10 << 10) | 345,
-	(0  << 10) | 746,
-	(0 << 10) | 0,
-	(0  << 10) | 0,
-	(28 << 10) | 200,
-	(0  << 10) | 345,
-	(20 << 10) | 0,
-	(0  << 10) | 200,
-};
-
-static const uint16_t rf_ramp_pwm_cband_7090e_aci[] = {
-	86,
-	40,
-	345,
-	(0 << 10) | 0,
-	(0 << 10) | 0,
-	(0 << 10) | 0,
-	(0 << 10) | 0,
-	(28 << 10) | 200,
-	(0  << 10) | 345,
-	(20 << 10) | 0,
-	(0  << 10) | 200,
-};
-
-static const u16 rf_ramp_pwm_cband_8090[] = {
-	345,			/* max RF gain in 10th of dB */
-	29,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
-	1000,			/* ramp_max = maximum X used on the ramp */
-	(35 << 10) | 772,	/* RF_RAMP3, LNA 1 = 8dB */
-	(0 << 10) | 1000,	/* RF_RAMP4, LNA 1 */
-	(58 << 10) | 496,	/* RF_RAMP5, LNA 2 = 9.5dB */
-	(0 << 10) | 772,	/* RF_RAMP6, LNA 2 */
-	(27 << 10) | 200,	/* RF_RAMP7, LNA 3 = 10.5dB */
-	(0 << 10) | 496,	/* RF_RAMP8, LNA 3 */
-	(40 << 10) | 0,		/* GAIN_4_1, LNA 4 = 7dB */
-	(0 << 10) | 200,	/* GAIN_4_2, LNA 4 */
-};
-
-static const u16 rf_ramp_pwm_uhf_7090[] = {
-	407,			/* max RF gain in 10th of dB */
-	13,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
-	529,			/* ramp_max = maximum X used on the ramp */
-	(23 << 10) | 0,		/* RF_RAMP3, LNA 1 = 14.7dB */
-	(0 << 10) | 176,	/* RF_RAMP4, LNA 1 */
-	(63 << 10) | 400,	/* RF_RAMP5, LNA 2 = 8dB */
-	(0 << 10) | 529,	/* RF_RAMP6, LNA 2 */
-	(48 << 10) | 316,	/* RF_RAMP7, LNA 3 = 6.8dB */
-	(0 << 10) | 400,	/* RF_RAMP8, LNA 3 */
-	(29 << 10) | 176,	/* GAIN_4_1, LNA 4 = 11.5dB */
-	(0 << 10) | 316,	/* GAIN_4_2, LNA 4 */
-};
-
-static const u16 rf_ramp_pwm_uhf_8090[] = {
-	388,			/* max RF gain in 10th of dB */
-	26,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
-	1008,			/* ramp_max = maximum X used on the ramp */
-	(11 << 10) | 0,		/* RF_RAMP3, LNA 1 = 14.7dB */
-	(0 << 10) | 369,	/* RF_RAMP4, LNA 1 */
-	(41 << 10) | 809,	/* RF_RAMP5, LNA 2 = 8dB */
-	(0 << 10) | 1008,	/* RF_RAMP6, LNA 2 */
-	(27 << 10) | 659,	/* RF_RAMP7, LNA 3 = 6dB */
-	(0 << 10) | 809,	/* RF_RAMP8, LNA 3 */
-	(14 << 10) | 369,	/* GAIN_4_1, LNA 4 = 11.5dB */
-	(0 << 10) | 659,	/* GAIN_4_2, LNA 4 */
-};
-
-static const u16 rf_ramp_pwm_cband[] = {
-	0,			/* max RF gain in 10th of dB */
-	0,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
-	0,			/* ramp_max = maximum X used on the ramp */
-	(0 << 10) | 0,		/* 0x2c, LNA 1 = 0dB */
-	(0 << 10) | 0,		/* 0x2d, LNA 1 */
-	(0 << 10) | 0,		/* 0x2e, LNA 2 = 0dB */
-	(0 << 10) | 0,		/* 0x2f, LNA 2 */
-	(0 << 10) | 0,		/* 0x30, LNA 3 = 0dB */
-	(0 << 10) | 0,		/* 0x31, LNA 3 */
-	(0 << 10) | 0,		/* GAIN_4_1, LNA 4 = 0dB */
-	(0 << 10) | 0,		/* GAIN_4_2, LNA 4 */
-};
-
-static const u16 rf_ramp_vhf[] = {
-	412,			/* max RF gain in 10th of dB */
-	132, 307, 127,		/* LNA1,  13.2dB */
-	105, 412, 255,		/* LNA2,  10.5dB */
-	50, 50, 127,		/* LNA3,  5dB */
-	125, 175, 127,		/* LNA4,  12.5dB */
-	0, 0, 127,		/* CBAND, 0dB */
-};
-
-static const u16 rf_ramp_uhf[] = {
-	412,			/* max RF gain in 10th of dB */
-	132, 307, 127,		/* LNA1  : total gain = 13.2dB, point on the ramp where this amp is full gain, value to write to get full gain */
-	105, 412, 255,		/* LNA2  : 10.5 dB */
-	50, 50, 127,		/* LNA3  :  5.0 dB */
-	125, 175, 127,		/* LNA4  : 12.5 dB */
-	0, 0, 127,		/* CBAND :  0.0 dB */
-};
-
-static const u16 rf_ramp_cband_broadmatching[] =	/* for p1G only */
-{
-	314,			/* Calibrated at 200MHz order has been changed g4-g3-g2-g1 */
-	84, 314, 127,		/* LNA1 */
-	80, 230, 255,		/* LNA2 */
-	80, 150, 127,		/* LNA3  It was measured 12dB, do not lock if 120 */
-	70, 70, 127,		/* LNA4 */
-	0, 0, 127,		/* CBAND */
-};
-
-static const u16 rf_ramp_cband[] = {
-	332,			/* max RF gain in 10th of dB */
-	132, 252, 127,		/* LNA1,  dB */
-	80, 332, 255,		/* LNA2,  dB */
-	0, 0, 127,		/* LNA3,  dB */
-	0, 0, 127,		/* LNA4,  dB */
-	120, 120, 127,		/* LT1 CBAND */
-};
-
-static const u16 rf_ramp_pwm_vhf[] = {
-	404,			/* max RF gain in 10th of dB */
-	25,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
-	1011,			/* ramp_max = maximum X used on the ramp */
-	(6 << 10) | 417,	/* 0x2c, LNA 1 = 13.2dB */
-	(0 << 10) | 756,	/* 0x2d, LNA 1 */
-	(16 << 10) | 756,	/* 0x2e, LNA 2 = 10.5dB */
-	(0 << 10) | 1011,	/* 0x2f, LNA 2 */
-	(16 << 10) | 290,	/* 0x30, LNA 3 = 5dB */
-	(0 << 10) | 417,	/* 0x31, LNA 3 */
-	(7 << 10) | 0,		/* GAIN_4_1, LNA 4 = 12.5dB */
-	(0 << 10) | 290,	/* GAIN_4_2, LNA 4 */
-};
-
-static const u16 rf_ramp_pwm_uhf[] = {
-	404,			/* max RF gain in 10th of dB */
-	25,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
-	1011,			/* ramp_max = maximum X used on the ramp */
-	(6 << 10) | 417,	/* 0x2c, LNA 1 = 13.2dB */
-	(0 << 10) | 756,	/* 0x2d, LNA 1 */
-	(16 << 10) | 756,	/* 0x2e, LNA 2 = 10.5dB */
-	(0 << 10) | 1011,	/* 0x2f, LNA 2 */
-	(16 << 10) | 0,		/* 0x30, LNA 3 = 5dB */
-	(0 << 10) | 127,	/* 0x31, LNA 3 */
-	(7 << 10) | 127,	/* GAIN_4_1, LNA 4 = 12.5dB */
-	(0 << 10) | 417,	/* GAIN_4_2, LNA 4 */
-};
-
-static const u16 bb_ramp_boost[] = {
-	550,			/* max BB gain in 10th of dB */
-	260, 260, 26,		/* BB1, 26dB */
-	290, 550, 29,		/* BB2, 29dB */
-};
-
-static const u16 bb_ramp_pwm_normal[] = {
-	500,			/* max RF gain in 10th of dB */
-	8,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */
-	400,
-	(2 << 9) | 0,		/* 0x35 = 21dB */
-	(0 << 9) | 168,		/* 0x36 */
-	(2 << 9) | 168,		/* 0x37 = 29dB */
-	(0 << 9) | 400,		/* 0x38 */
-};
-
-struct slope {
-	s16 range;
-	s16 slope;
-};
-static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val)
-{
-	u8 i;
-	u16 rest;
-	u16 ret = 0;
-	for (i = 0; i < num; i++) {
-		if (val > slopes[i].range)
-			rest = slopes[i].range;
-		else
-			rest = val;
-		ret += (rest * slopes[i].slope) / slopes[i].range;
-		val -= rest;
-	}
-	return ret;
-}
-
-static const struct slope dib0090_wbd_slopes[3] = {
-	{66, 120},		/* -64,-52: offset -   65 */
-	{600, 170},		/* -52,-35: 65     -  665 */
-	{170, 250},		/* -45,-10: 665    - 835 */
-};
-
-static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd)
-{
-	wbd &= 0x3ff;
-	if (wbd < state->wbd_offset)
-		wbd = 0;
-	else
-		wbd -= state->wbd_offset;
-	/* -64dB is the floor */
-	return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd);
-}
-
-static void dib0090_wbd_target(struct dib0090_state *state, u32 rf)
-{
-	u16 offset = 250;
-
-	/* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */
-
-	if (state->current_band == BAND_VHF)
-		offset = 650;
-#ifndef FIRMWARE_FIREFLY
-	if (state->current_band == BAND_VHF)
-		offset = state->config->wbd_vhf_offset;
-	if (state->current_band == BAND_CBAND)
-		offset = state->config->wbd_cband_offset;
-#endif
-
-	state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset);
-	dprintk("wbd-target: %d dB", (u32) state->wbd_target);
-}
-
-static const int gain_reg_addr[4] = {
-	0x08, 0x0a, 0x0f, 0x01
-};
-
-static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force)
-{
-	u16 rf, bb, ref;
-	u16 i, v, gain_reg[4] = { 0 }, gain;
-	const u16 *g;
-
-	if (top_delta < -511)
-		top_delta = -511;
-	if (top_delta > 511)
-		top_delta = 511;
-
-	if (force) {
-		top_delta *= (1 << WBD_ALPHA);
-		gain_delta *= (1 << GAIN_ALPHA);
-	}
-
-	if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit))	/* overflow */
-		state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
-	else
-		state->rf_gain_limit += top_delta;
-
-	if (state->rf_gain_limit < 0)	/*underflow */
-		state->rf_gain_limit = 0;
-
-	/* use gain as a temporary variable and correct current_gain */
-	gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA;
-	if (gain_delta >= ((s16) gain - state->current_gain))	/* overflow */
-		state->current_gain = gain;
-	else
-		state->current_gain += gain_delta;
-	/* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */
-	if (state->current_gain < 0)
-		state->current_gain = 0;
-
-	/* now split total gain to rf and bb gain */
-	gain = state->current_gain >> GAIN_ALPHA;
-
-	/* requested gain is bigger than rf gain limit - ACI/WBD adjustment */
-	if (gain > (state->rf_gain_limit >> WBD_ALPHA)) {
-		rf = state->rf_gain_limit >> WBD_ALPHA;
-		bb = gain - rf;
-		if (bb > state->bb_ramp[0])
-			bb = state->bb_ramp[0];
-	} else {		/* high signal level -> all gains put on RF */
-		rf = gain;
-		bb = 0;
-	}
-
-	state->gain[0] = rf;
-	state->gain[1] = bb;
-
-	/* software ramp */
-	/* Start with RF gains */
-	g = state->rf_ramp + 1;	/* point on RF LNA1 max gain */
-	ref = rf;
-	for (i = 0; i < 7; i++) {	/* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */
-		if (g[0] == 0 || ref < (g[1] - g[0]))	/* if total gain of the current amp is null or this amp is not concerned because it starts to work from an higher gain value */
-			v = 0;	/* force the gain to write for the current amp to be null */
-		else if (ref >= g[1])	/* Gain to set is higher than the high working point of this amp */
-			v = g[2];	/* force this amp to be full gain */
-		else		/* compute the value to set to this amp because we are somewhere in his range */
-			v = ((ref - (g[1] - g[0])) * g[2]) / g[0];
-
-		if (i == 0)	/* LNA 1 reg mapping */
-			gain_reg[0] = v;
-		else if (i == 1)	/* LNA 2 reg mapping */
-			gain_reg[0] |= v << 7;
-		else if (i == 2)	/* LNA 3 reg mapping */
-			gain_reg[1] = v;
-		else if (i == 3)	/* LNA 4 reg mapping */
-			gain_reg[1] |= v << 7;
-		else if (i == 4)	/* CBAND LNA reg mapping */
-			gain_reg[2] = v | state->rf_lt_def;
-		else if (i == 5)	/* BB gain 1 reg mapping */
-			gain_reg[3] = v << 3;
-		else if (i == 6)	/* BB gain 2 reg mapping */
-			gain_reg[3] |= v << 8;
-
-		g += 3;		/* go to next gain bloc */
-
-		/* When RF is finished, start with BB */
-		if (i == 4) {
-			g = state->bb_ramp + 1;	/* point on BB gain 1 max gain */
-			ref = bb;
-		}
-	}
-	gain_reg[3] |= state->bb_1_def;
-	gain_reg[3] |= ((bb % 10) * 100) / 125;
-
-#ifdef DEBUG_AGC
-	dprintk("GA CALC: DB: %3d(rf) + %3d(bb) = %3d gain_reg[0]=%04x gain_reg[1]=%04x gain_reg[2]=%04x gain_reg[0]=%04x", rf, bb, rf + bb,
-		gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]);
-#endif
-
-	/* Write the amplifier regs */
-	for (i = 0; i < 4; i++) {
-		v = gain_reg[i];
-		if (force || state->gain_reg[i] != v) {
-			state->gain_reg[i] = v;
-			dib0090_write_reg(state, gain_reg_addr[i], v);
-		}
-	}
-}
-
-static void dib0090_set_boost(struct dib0090_state *state, int onoff)
-{
-	state->bb_1_def &= 0xdfff;
-	state->bb_1_def |= onoff << 13;
-}
-
-static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg)
-{
-	state->rf_ramp = cfg;
-}
-
-static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg)
-{
-	state->rf_ramp = cfg;
-
-	dib0090_write_reg(state, 0x2a, 0xffff);
-
-	dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a));
-
-	dib0090_write_regs(state, 0x2c, cfg + 3, 6);
-	dib0090_write_regs(state, 0x3e, cfg + 9, 2);
-}
-
-static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg)
-{
-	state->bb_ramp = cfg;
-	dib0090_set_boost(state, cfg[0] > 500);	/* we want the boost if the gain is higher that 50dB */
-}
-
-static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)
-{
-	state->bb_ramp = cfg;
-
-	dib0090_set_boost(state, cfg[0] > 500);	/* we want the boost if the gain is higher that 50dB */
-
-	dib0090_write_reg(state, 0x33, 0xffff);
-	dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33));
-	dib0090_write_regs(state, 0x35, cfg + 3, 4);
-}
-
-void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-	/* reset the AGC */
-
-	if (state->config->use_pwm_agc) {
-#ifdef CONFIG_BAND_SBAND
-		if (state->current_band == BAND_SBAND) {
-			dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband);
-			dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost);
-		} else
-#endif
-#ifdef CONFIG_BAND_CBAND
-		if (state->current_band == BAND_CBAND) {
-			if (state->identity.in_soc) {
-				dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
-				if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
-					dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090);
-				else if (state->identity.version == SOC_7090_P1G_11R1
-						|| state->identity.version == SOC_7090_P1G_21R1) {
-					if (state->config->is_dib7090e) {
-						if (state->rf_ramp == NULL)
-							dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090e_sensitivity);
-						else
-							dib0090_set_rframp_pwm(state, state->rf_ramp);
-					} else
-						dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090);
-				}
-			} else {
-				dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband);
-				dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
-			}
-		} else
-#endif
-#ifdef CONFIG_BAND_VHF
-		if (state->current_band == BAND_VHF) {
-			if (state->identity.in_soc) {
-				dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
-			} else {
-				dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf);
-				dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
-			}
-		} else
-#endif
-		{
-			if (state->identity.in_soc) {
-				if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
-					dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_8090);
-				else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
-					dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_7090);
-				dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
-			} else {
-				dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf);
-				dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
-			}
-		}
-
-		if (state->rf_ramp[0] != 0)
-			dib0090_write_reg(state, 0x32, (3 << 11));
-		else
-			dib0090_write_reg(state, 0x32, (0 << 11));
-
-		dib0090_write_reg(state, 0x04, 0x03);
-		dib0090_write_reg(state, 0x39, (1 << 10));
-	}
-}
-
-EXPORT_SYMBOL(dib0090_pwm_gain_reset);
-
-void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-	if (DC_servo_cutoff < 4)
-		dib0090_write_reg(state, 0x04, DC_servo_cutoff);
-}
-EXPORT_SYMBOL(dib0090_set_dc_servo);
-
-static u32 dib0090_get_slow_adc_val(struct dib0090_state *state)
-{
-	u16 adc_val = dib0090_read_reg(state, 0x1d);
-	if (state->identity.in_soc)
-		adc_val >>= 2;
-	return adc_val;
-}
-
-int dib0090_gain_control(struct dvb_frontend *fe)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-	enum frontend_tune_state *tune_state = &state->tune_state;
-	int ret = 10;
-
-	u16 wbd_val = 0;
-	u8 apply_gain_immediatly = 1;
-	s16 wbd_error = 0, adc_error = 0;
-
-	if (*tune_state == CT_AGC_START) {
-		state->agc_freeze = 0;
-		dib0090_write_reg(state, 0x04, 0x0);
-
-#ifdef CONFIG_BAND_SBAND
-		if (state->current_band == BAND_SBAND) {
-			dib0090_set_rframp(state, rf_ramp_sband);
-			dib0090_set_bbramp(state, bb_ramp_boost);
-		} else
-#endif
-#ifdef CONFIG_BAND_VHF
-		if (state->current_band == BAND_VHF && !state->identity.p1g) {
-			dib0090_set_rframp(state, rf_ramp_vhf);
-			dib0090_set_bbramp(state, bb_ramp_boost);
-		} else
-#endif
-#ifdef CONFIG_BAND_CBAND
-		if (state->current_band == BAND_CBAND && !state->identity.p1g) {
-			dib0090_set_rframp(state, rf_ramp_cband);
-			dib0090_set_bbramp(state, bb_ramp_boost);
-		} else
-#endif
-		if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) {
-			dib0090_set_rframp(state, rf_ramp_cband_broadmatching);
-			dib0090_set_bbramp(state, bb_ramp_boost);
-		} else {
-			dib0090_set_rframp(state, rf_ramp_uhf);
-			dib0090_set_bbramp(state, bb_ramp_boost);
-		}
-
-		dib0090_write_reg(state, 0x32, 0);
-		dib0090_write_reg(state, 0x39, 0);
-
-		dib0090_wbd_target(state, state->current_rf);
-
-		state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
-		state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA;
-
-		*tune_state = CT_AGC_STEP_0;
-	} else if (!state->agc_freeze) {
-		s16 wbd = 0, i, cnt;
-
-		int adc;
-		wbd_val = dib0090_get_slow_adc_val(state);
-
-		if (*tune_state == CT_AGC_STEP_0)
-			cnt = 5;
-		else
-			cnt = 1;
-
-		for (i = 0; i < cnt; i++) {
-			wbd_val = dib0090_get_slow_adc_val(state);
-			wbd += dib0090_wbd_to_db(state, wbd_val);
-		}
-		wbd /= cnt;
-		wbd_error = state->wbd_target - wbd;
-
-		if (*tune_state == CT_AGC_STEP_0) {
-			if (wbd_error < 0 && state->rf_gain_limit > 0 && !state->identity.p1g) {
-#ifdef CONFIG_BAND_CBAND
-				/* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */
-				u8 ltg2 = (state->rf_lt_def >> 10) & 0x7;
-				if (state->current_band == BAND_CBAND && ltg2) {
-					ltg2 >>= 1;
-					state->rf_lt_def &= ltg2 << 10;	/* reduce in 3 steps from 7 to 0 */
-				}
-#endif
-			} else {
-				state->agc_step = 0;
-				*tune_state = CT_AGC_STEP_1;
-			}
-		} else {
-			/* calc the adc power */
-			adc = state->config->get_adc_power(fe);
-			adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21;	/* included in [0:-700] */
-
-			adc_error = (s16) (((s32) ADC_TARGET) - adc);
-#ifdef CONFIG_STANDARD_DAB
-			if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB)
-				adc_error -= 10;
-#endif
-#ifdef CONFIG_STANDARD_DVBT
-			if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT &&
-					(state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16))
-				adc_error += 60;
-#endif
-#ifdef CONFIG_SYS_ISDBT
-			if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) && (((state->fe->dtv_property_cache.layer[0].segment_count >
-								0)
-							&&
-							((state->fe->dtv_property_cache.layer[0].modulation ==
-							  QAM_64)
-							 || (state->fe->dtv_property_cache.
-								 layer[0].modulation == QAM_16)))
-						||
-						((state->fe->dtv_property_cache.layer[1].segment_count >
-						  0)
-						 &&
-						 ((state->fe->dtv_property_cache.layer[1].modulation ==
-						   QAM_64)
-						  || (state->fe->dtv_property_cache.
-							  layer[1].modulation == QAM_16)))
-						||
-						((state->fe->dtv_property_cache.layer[2].segment_count >
-						  0)
-						 &&
-						 ((state->fe->dtv_property_cache.layer[2].modulation ==
-						   QAM_64)
-						  || (state->fe->dtv_property_cache.
-							  layer[2].modulation == QAM_16)))
-						)
-				)
-				adc_error += 60;
-#endif
-
-			if (*tune_state == CT_AGC_STEP_1) {	/* quickly go to the correct range of the ADC power */
-				if (ABS(adc_error) < 50 || state->agc_step++ > 5) {
-
-#ifdef CONFIG_STANDARD_DAB
-					if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) {
-						dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63));	/* cap value = 63 : narrow BB filter : Fc = 1.8MHz */
-						dib0090_write_reg(state, 0x04, 0x0);
-					} else
-#endif
-					{
-						dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32));
-						dib0090_write_reg(state, 0x04, 0x01);	/*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */
-					}
-
-					*tune_state = CT_AGC_STOP;
-				}
-			} else {
-				/* everything higher than or equal to CT_AGC_STOP means tracking */
-				ret = 100;	/* 10ms interval */
-				apply_gain_immediatly = 0;
-			}
-		}
-#ifdef DEBUG_AGC
-		dprintk
-			("tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm",
-			 (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val,
-			 (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA));
-#endif
-	}
-
-	/* apply gain */
-	if (!state->agc_freeze)
-		dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly);
-	return ret;
-}
-
-EXPORT_SYMBOL(dib0090_gain_control);
-
-void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-	if (rf)
-		*rf = state->gain[0];
-	if (bb)
-		*bb = state->gain[1];
-	if (rf_gain_limit)
-		*rf_gain_limit = state->rf_gain_limit;
-	if (rflt)
-		*rflt = (state->rf_lt_def >> 10) & 0x7;
-}
-
-EXPORT_SYMBOL(dib0090_get_current_gain);
-
-u16 dib0090_get_wbd_target(struct dvb_frontend *fe)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-	u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000;
-	s32 current_temp = state->temperature;
-	s32 wbd_thot, wbd_tcold;
-	const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
-
-	while (f_MHz > wbd->max_freq)
-		wbd++;
-
-	dprintk("using wbd-table-entry with max freq %d", wbd->max_freq);
-
-	if (current_temp < 0)
-		current_temp = 0;
-	if (current_temp > 128)
-		current_temp = 128;
-
-	state->wbdmux &= ~(7 << 13);
-	if (wbd->wbd_gain != 0)
-		state->wbdmux |= (wbd->wbd_gain << 13);
-	else
-		state->wbdmux |= (4 << 13);
-
-	dib0090_write_reg(state, 0x10, state->wbdmux);
-
-	wbd_thot = wbd->offset_hot - (((u32) wbd->slope_hot * f_MHz) >> 6);
-	wbd_tcold = wbd->offset_cold - (((u32) wbd->slope_cold * f_MHz) >> 6);
-
-	wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7;
-
-	state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold);
-	dprintk("wbd-target: %d dB", (u32) state->wbd_target);
-	dprintk("wbd offset applied is %d", wbd_tcold);
-
-	return state->wbd_offset + wbd_tcold;
-}
-EXPORT_SYMBOL(dib0090_get_wbd_target);
-
-u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-	return state->wbd_offset;
-}
-EXPORT_SYMBOL(dib0090_get_wbd_offset);
-
-int dib0090_set_switch(struct dvb_frontend *fe, u8 sw1, u8 sw2, u8 sw3)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-
-	dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xfff8)
-			| ((sw3 & 1) << 2) | ((sw2 & 1) << 1) | (sw1 & 1));
-
-	return 0;
-}
-EXPORT_SYMBOL(dib0090_set_switch);
-
-int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-
-	dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x7fff)
-			| ((onoff & 1) << 15));
-	return 0;
-}
-EXPORT_SYMBOL(dib0090_set_vga);
-
-int dib0090_update_rframp_7090(struct dvb_frontend *fe, u8 cfg_sensitivity)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-
-	if ((!state->identity.p1g) || (!state->identity.in_soc)
-			|| ((state->identity.version != SOC_7090_P1G_21R1)
-				&& (state->identity.version != SOC_7090_P1G_11R1))) {
-		dprintk("%s() function can only be used for dib7090P", __func__);
-		return -ENODEV;
-	}
-
-	if (cfg_sensitivity)
-		state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_sensitivity;
-	else
-		state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_aci;
-	dib0090_pwm_gain_reset(fe);
-
-	return 0;
-}
-EXPORT_SYMBOL(dib0090_update_rframp_7090);
-
-static const u16 dib0090_defaults[] = {
-
-	25, 0x01,
-	0x0000,
-	0x99a0,
-	0x6008,
-	0x0000,
-	0x8bcb,
-	0x0000,
-	0x0405,
-	0x0000,
-	0x0000,
-	0x0000,
-	0xb802,
-	0x0300,
-	0x2d12,
-	0xbac0,
-	0x7c00,
-	0xdbb9,
-	0x0954,
-	0x0743,
-	0x8000,
-	0x0001,
-	0x0040,
-	0x0100,
-	0x0000,
-	0xe910,
-	0x149e,
-
-	1, 0x1c,
-	0xff2d,
-
-	1, 0x39,
-	0x0000,
-
-	2, 0x1e,
-	0x07FF,
-	0x0007,
-
-	1, 0x24,
-	EN_UHF | EN_CRYSTAL,
-
-	2, 0x3c,
-	0x3ff,
-	0x111,
-	0
-};
-
-static const u16 dib0090_p1g_additionnal_defaults[] = {
-	1, 0x05,
-	0xabcd,
-
-	1, 0x11,
-	0x00b4,
-
-	1, 0x1c,
-	0xfffd,
-
-	1, 0x40,
-	0x108,
-	0
-};
-
-static void dib0090_set_default_config(struct dib0090_state *state, const u16 * n)
-{
-	u16 l, r;
-
-	l = pgm_read_word(n++);
-	while (l) {
-		r = pgm_read_word(n++);
-		do {
-			dib0090_write_reg(state, r, pgm_read_word(n++));
-			r++;
-		} while (--l);
-		l = pgm_read_word(n++);
-	}
-}
-
-#define CAP_VALUE_MIN (u8)  9
-#define CAP_VALUE_MAX (u8) 40
-#define HR_MIN	      (u8) 25
-#define HR_MAX	      (u8) 40
-#define POLY_MIN      (u8)  0
-#define POLY_MAX      (u8)  8
-
-static void dib0090_set_EFUSE(struct dib0090_state *state)
-{
-	u8 c, h, n;
-	u16 e2, e4;
-	u16 cal;
-
-	e2 = dib0090_read_reg(state, 0x26);
-	e4 = dib0090_read_reg(state, 0x28);
-
-	if ((state->identity.version == P1D_E_F) ||
-			(state->identity.version == P1G) || (e2 == 0xffff)) {
-
-		dib0090_write_reg(state, 0x22, 0x10);
-		cal = (dib0090_read_reg(state, 0x22) >> 6) & 0x3ff;
-
-		if ((cal < 670) || (cal == 1023))
-			cal = 850;
-		n = 165 - ((cal * 10)>>6) ;
-		e2 = e4 = (3<<12) | (34<<6) | (n);
-	}
-
-	if (e2 != e4)
-		e2 &= e4; /* Remove the redundancy  */
-
-	if (e2 != 0xffff) {
-		c = e2 & 0x3f;
-		n = (e2 >> 12) & 0xf;
-		h = (e2 >> 6) & 0x3f;
-
-		if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN))
-			c = 32;
-		if ((h >= HR_MAX) || (h <= HR_MIN))
-			h = 34;
-		if ((n >= POLY_MAX) || (n <= POLY_MIN))
-			n = 3;
-
-		dib0090_write_reg(state, 0x13, (h << 10)) ;
-		e2 = (n<<11) | ((h>>2)<<6) | (c);
-		dib0090_write_reg(state, 0x2, e2) ; /* Load the BB_2 */
-	}
-}
-
-static int dib0090_reset(struct dvb_frontend *fe)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-
-	dib0090_reset_digital(fe, state->config);
-	if (dib0090_identify(fe) < 0)
-		return -EIO;
-
-#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT
-	if (!(state->identity.version & 0x1))	/* it is P1B - reset is already done */
-		return 0;
-#endif
-
-	if (!state->identity.in_soc) {
-		if ((dib0090_read_reg(state, 0x1a) >> 5) & 0x2)
-			dib0090_write_reg(state, 0x1b, (EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL));
-		else
-			dib0090_write_reg(state, 0x1b, (EN_DIGCLK | EN_PLL | EN_CRYSTAL));
-	}
-
-	dib0090_set_default_config(state, dib0090_defaults);
-
-	if (state->identity.in_soc)
-		dib0090_write_reg(state, 0x18, 0x2910);  /* charge pump current = 0 */
-
-	if (state->identity.p1g)
-		dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults);
-
-	/* Update the efuse : Only available for KROSUS > P1C  and SOC as well*/
-	if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc))
-		dib0090_set_EFUSE(state);
-
-	/* Congigure in function of the crystal */
-	if (state->config->force_crystal_mode != 0)
-		dib0090_write_reg(state, 0x14,
-				state->config->force_crystal_mode & 3);
-	else if (state->config->io.clock_khz >= 24000)
-		dib0090_write_reg(state, 0x14, 1);
-	else
-		dib0090_write_reg(state, 0x14, 2);
-	dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1);
-
-	state->calibrate = DC_CAL | WBD_CAL | TEMP_CAL;	/* enable iq-offset-calibration and wbd-calibration when tuning next time */
-
-	return 0;
-}
-
-#define steps(u) (((u) > 15) ? ((u)-16) : (u))
-#define INTERN_WAIT 10
-static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state)
-{
-	int ret = INTERN_WAIT * 10;
-
-	switch (*tune_state) {
-	case CT_TUNER_STEP_2:
-		/* Turns to positive */
-		dib0090_write_reg(state, 0x1f, 0x7);
-		*tune_state = CT_TUNER_STEP_3;
-		break;
-
-	case CT_TUNER_STEP_3:
-		state->adc_diff = dib0090_read_reg(state, 0x1d);
-
-		/* Turns to negative */
-		dib0090_write_reg(state, 0x1f, 0x4);
-		*tune_state = CT_TUNER_STEP_4;
-		break;
-
-	case CT_TUNER_STEP_4:
-		state->adc_diff -= dib0090_read_reg(state, 0x1d);
-		*tune_state = CT_TUNER_STEP_5;
-		ret = 0;
-		break;
-
-	default:
-		break;
-	}
-
-	return ret;
-}
-
-struct dc_calibration {
-	u8 addr;
-	u8 offset;
-	u8 pga:1;
-	u16 bb1;
-	u8 i:1;
-};
-
-static const struct dc_calibration dc_table[] = {
-	/* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
-	{0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1},
-	{0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0},
-	/* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
-	{0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1},
-	{0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0},
-	{0},
-};
-
-static const struct dc_calibration dc_p1g_table[] = {
-	/* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
-	/* addr ; trim reg offset ; pga ; CTRL_BB1 value ; i or q */
-	{0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1},
-	{0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0},
-	/* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
-	{0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1},
-	{0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0},
-	{0},
-};
-
-static void dib0090_set_trim(struct dib0090_state *state)
-{
-	u16 *val;
-
-	if (state->dc->addr == 0x07)
-		val = &state->bb7;
-	else
-		val = &state->bb6;
-
-	*val &= ~(0x1f << state->dc->offset);
-	*val |= state->step << state->dc->offset;
-
-	dib0090_write_reg(state, state->dc->addr, *val);
-}
-
-static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
-{
-	int ret = 0;
-	u16 reg;
-
-	switch (*tune_state) {
-	case CT_TUNER_START:
-		dprintk("Start DC offset calibration");
-
-		/* force vcm2 = 0.8V */
-		state->bb6 = 0;
-		state->bb7 = 0x040d;
-
-		/* the LNA AND LO are off */
-		reg = dib0090_read_reg(state, 0x24) & 0x0ffb;	/* shutdown lna and lo */
-		dib0090_write_reg(state, 0x24, reg);
-
-		state->wbdmux = dib0090_read_reg(state, 0x10);
-		dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3);
-		dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
-
-		state->dc = dc_table;
-
-		if (state->identity.p1g)
-			state->dc = dc_p1g_table;
-		*tune_state = CT_TUNER_STEP_0;
-
-		/* fall through */
-
-	case CT_TUNER_STEP_0:
-		dprintk("Sart/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q");
-		dib0090_write_reg(state, 0x01, state->dc->bb1);
-		dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7));
-
-		state->step = 0;
-		state->min_adc_diff = 1023;
-		*tune_state = CT_TUNER_STEP_1;
-		ret = 50;
-		break;
-
-	case CT_TUNER_STEP_1:
-		dib0090_set_trim(state);
-		*tune_state = CT_TUNER_STEP_2;
-		break;
-
-	case CT_TUNER_STEP_2:
-	case CT_TUNER_STEP_3:
-	case CT_TUNER_STEP_4:
-		ret = dib0090_get_offset(state, tune_state);
-		break;
-
-	case CT_TUNER_STEP_5:	/* found an offset */
-		dprintk("adc_diff = %d, current step= %d", (u32) state->adc_diff, state->step);
-		if (state->step == 0 && state->adc_diff < 0) {
-			state->min_adc_diff = -1023;
-			dprintk("Change of sign of the minimum adc diff");
-		}
-
-		dprintk("adc_diff = %d, min_adc_diff = %d current_step = %d", state->adc_diff, state->min_adc_diff, state->step);
-
-		/* first turn for this frequency */
-		if (state->step == 0) {
-			if (state->dc->pga && state->adc_diff < 0)
-				state->step = 0x10;
-			if (state->dc->pga == 0 && state->adc_diff > 0)
-				state->step = 0x10;
-		}
-
-		/* Look for a change of Sign in the Adc_diff.min_adc_diff is used to STORE the setp N-1 */
-		if ((state->adc_diff & 0x8000) == (state->min_adc_diff & 0x8000) && steps(state->step) < 15) {
-			/* stop search when the delta the sign is changing and Steps =15 and Step=0 is force for continuance */
-			state->step++;
-			state->min_adc_diff = state->adc_diff;
-			*tune_state = CT_TUNER_STEP_1;
-		} else {
-			/* the minimum was what we have seen in the step before */
-			if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) {
-				dprintk("Since adc_diff N = %d  > adc_diff step N-1 = %d, Come back one step", state->adc_diff, state->min_adc_diff);
-				state->step--;
-			}
-
-			dib0090_set_trim(state);
-			dprintk("BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->dc->addr, state->adc_diff, state->step);
-
-			state->dc++;
-			if (state->dc->addr == 0)	/* done */
-				*tune_state = CT_TUNER_STEP_6;
-			else
-				*tune_state = CT_TUNER_STEP_0;
-
-		}
-		break;
-
-	case CT_TUNER_STEP_6:
-		dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008);
-		dib0090_write_reg(state, 0x1f, 0x7);
-		*tune_state = CT_TUNER_START;	/* reset done -> real tuning can now begin */
-		state->calibrate &= ~DC_CAL;
-	default:
-		break;
-	}
-	return ret;
-}
-
-static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
-{
-	u8 wbd_gain;
-	const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
-
-	switch (*tune_state) {
-	case CT_TUNER_START:
-		while (state->current_rf / 1000 > wbd->max_freq)
-			wbd++;
-		if (wbd->wbd_gain != 0)
-			wbd_gain = wbd->wbd_gain;
-		else {
-			wbd_gain = 4;
-#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND)
-			if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND))
-				wbd_gain = 2;
-#endif
-		}
-
-		if (wbd_gain == state->wbd_calibration_gain) {	/* the WBD calibration has already been done */
-			*tune_state = CT_TUNER_START;
-			state->calibrate &= ~WBD_CAL;
-			return 0;
-		}
-
-		dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3));
-
-		dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1)));
-		*tune_state = CT_TUNER_STEP_0;
-		state->wbd_calibration_gain = wbd_gain;
-		return 90;	/* wait for the WBDMUX to switch and for the ADC to sample */
-
-	case CT_TUNER_STEP_0:
-		state->wbd_offset = dib0090_get_slow_adc_val(state);
-		dprintk("WBD calibration offset = %d", state->wbd_offset);
-		*tune_state = CT_TUNER_START;	/* reset done -> real tuning can now begin */
-		state->calibrate &= ~WBD_CAL;
-		break;
-
-	default:
-		break;
-	}
-	return 0;
-}
-
-static void dib0090_set_bandwidth(struct dib0090_state *state)
-{
-	u16 tmp;
-
-	if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000)
-		tmp = (3 << 14);
-	else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000)
-		tmp = (2 << 14);
-	else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000)
-		tmp = (1 << 14);
-	else
-		tmp = (0 << 14);
-
-	state->bb_1_def &= 0x3fff;
-	state->bb_1_def |= tmp;
-
-	dib0090_write_reg(state, 0x01, state->bb_1_def);	/* be sure that we have the right bb-filter */
-
-	dib0090_write_reg(state, 0x03, 0x6008);	/* = 0x6008 : vcm3_trim = 1 ; filter2_gm1_trim = 8 ; filter2_cutoff_freq = 0 */
-	dib0090_write_reg(state, 0x04, 0x1);	/* 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast */
-	if (state->identity.in_soc) {
-		dib0090_write_reg(state, 0x05, 0x9bcf); /* attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 1 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 15 */
-	} else {
-		dib0090_write_reg(state, 0x02, (5 << 11) | (8 << 6) | (22 & 0x3f));	/* 22 = cap_value */
-		dib0090_write_reg(state, 0x05, 0xabcd);	/* = 0xabcd : attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 2 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 13 */
-	}
-}
-
-static const struct dib0090_pll dib0090_pll_table[] = {
-#ifdef CONFIG_BAND_CBAND
-	{56000, 0, 9, 48, 6},
-	{70000, 1, 9, 48, 6},
-	{87000, 0, 8, 32, 4},
-	{105000, 1, 8, 32, 4},
-	{115000, 0, 7, 24, 6},
-	{140000, 1, 7, 24, 6},
-	{170000, 0, 6, 16, 4},
-#endif
-#ifdef CONFIG_BAND_VHF
-	{200000, 1, 6, 16, 4},
-	{230000, 0, 5, 12, 6},
-	{280000, 1, 5, 12, 6},
-	{340000, 0, 4, 8, 4},
-	{380000, 1, 4, 8, 4},
-	{450000, 0, 3, 6, 6},
-#endif
-#ifdef CONFIG_BAND_UHF
-	{580000, 1, 3, 6, 6},
-	{700000, 0, 2, 4, 4},
-	{860000, 1, 2, 4, 4},
-#endif
-#ifdef CONFIG_BAND_LBAND
-	{1800000, 1, 0, 2, 4},
-#endif
-#ifdef CONFIG_BAND_SBAND
-	{2900000, 0, 14, 1, 4},
-#endif
-};
-
-static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = {
-
-#ifdef CONFIG_BAND_CBAND
-	{184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
-	{227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
-	{380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
-#endif
-#ifdef CONFIG_BAND_UHF
-	{520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-#endif
-#ifdef CONFIG_BAND_LBAND
-	{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
-	{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
-	{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
-#endif
-#ifdef CONFIG_BAND_SBAND
-	{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
-	{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
-#endif
-};
-
-static const struct dib0090_tuning dib0090_tuning_table[] = {
-
-#ifdef CONFIG_BAND_CBAND
-	{170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
-#endif
-#ifdef CONFIG_BAND_VHF
-	{184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
-	{227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
-	{380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
-#endif
-#ifdef CONFIG_BAND_UHF
-	{520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-#endif
-#ifdef CONFIG_BAND_LBAND
-	{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
-	{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
-	{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
-#endif
-#ifdef CONFIG_BAND_SBAND
-	{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
-	{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
-#endif
-};
-
-static const struct dib0090_tuning dib0090_p1g_tuning_table[] = {
-#ifdef CONFIG_BAND_CBAND
-	{170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB},
-#endif
-#ifdef CONFIG_BAND_VHF
-	{184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
-	{227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
-	{380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
-#endif
-#ifdef CONFIG_BAND_UHF
-	{510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-#endif
-#ifdef CONFIG_BAND_LBAND
-	{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
-	{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
-	{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
-#endif
-#ifdef CONFIG_BAND_SBAND
-	{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
-	{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
-#endif
-};
-
-static const struct dib0090_pll dib0090_p1g_pll_table[] = {
-#ifdef CONFIG_BAND_CBAND
-	{57000, 0, 11, 48, 6},
-	{70000, 1, 11, 48, 6},
-	{86000, 0, 10, 32, 4},
-	{105000, 1, 10, 32, 4},
-	{115000, 0, 9, 24, 6},
-	{140000, 1, 9, 24, 6},
-	{170000, 0, 8, 16, 4},
-#endif
-#ifdef CONFIG_BAND_VHF
-	{200000, 1, 8, 16, 4},
-	{230000, 0, 7, 12, 6},
-	{280000, 1, 7, 12, 6},
-	{340000, 0, 6, 8, 4},
-	{380000, 1, 6, 8, 4},
-	{455000, 0, 5, 6, 6},
-#endif
-#ifdef CONFIG_BAND_UHF
-	{580000, 1, 5, 6, 6},
-	{680000, 0, 4, 4, 4},
-	{860000, 1, 4, 4, 4},
-#endif
-#ifdef CONFIG_BAND_LBAND
-	{1800000, 1, 2, 2, 4},
-#endif
-#ifdef CONFIG_BAND_SBAND
-	{2900000, 0, 1, 1, 6},
-#endif
-};
-
-static const struct dib0090_tuning dib0090_p1g_tuning_table_fm_vhf_on_cband[] = {
-#ifdef CONFIG_BAND_CBAND
-	{184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
-	{227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
-	{380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
-#endif
-#ifdef CONFIG_BAND_UHF
-	{520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-	{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
-#endif
-#ifdef CONFIG_BAND_LBAND
-	{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
-	{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
-	{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
-#endif
-#ifdef CONFIG_BAND_SBAND
-	{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
-	{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
-#endif
-};
-
-static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = {
-#ifdef CONFIG_BAND_CBAND
-	{300000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
-	{380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
-	{570000, 4, 10, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
-	{858000, 4, 5, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
-#endif
-};
-
-static const struct dib0090_tuning dib0090_tuning_table_cband_7090e_sensitivity[] = {
-#ifdef CONFIG_BAND_CBAND
-	{ 300000,  0 ,  3,  0x8105, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
-	{ 380000,  0 ,  10, 0x810F, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
-	{ 600000,  0 ,  10, 0x815E, 0x280, 0x2d12, 0xb84e, EN_CAB },
-	{ 660000,  0 ,  5,  0x85E3, 0x280, 0x2d12, 0xb84e, EN_CAB },
-	{ 720000,  0 ,  5,  0x852E, 0x280, 0x2d12, 0xb84e, EN_CAB },
-	{ 860000,  0 ,  4,  0x85E5, 0x280, 0x2d12, 0xb84e, EN_CAB },
-#endif
-};
-
-int dib0090_update_tuning_table_7090(struct dvb_frontend *fe,
-		u8 cfg_sensitivity)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-	const struct dib0090_tuning *tune =
-		dib0090_tuning_table_cband_7090e_sensitivity;
-	const struct dib0090_tuning dib0090_tuning_table_cband_7090e_aci[] = {
-		{ 300000,  0 ,  3,  0x8165, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
-		{ 650000,  0 ,  4,  0x815B, 0x280, 0x2d12, 0xb84e, EN_CAB },
-		{ 860000,  0 ,  5,  0x84EF, 0x280, 0x2d12, 0xb84e, EN_CAB },
-	};
-
-	if ((!state->identity.p1g) || (!state->identity.in_soc)
-			|| ((state->identity.version != SOC_7090_P1G_21R1)
-				&& (state->identity.version != SOC_7090_P1G_11R1))) {
-		dprintk("%s() function can only be used for dib7090", __func__);
-		return -ENODEV;
-	}
-
-	if (cfg_sensitivity)
-		tune = dib0090_tuning_table_cband_7090e_sensitivity;
-	else
-		tune = dib0090_tuning_table_cband_7090e_aci;
-
-	while (state->rf_request > tune->max_freq)
-		tune++;
-
-	dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x8000)
-			| (tune->lna_bias & 0x7fff));
-	dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xf83f)
-			| ((tune->lna_tune << 6) & 0x07c0));
-	return 0;
-}
-EXPORT_SYMBOL(dib0090_update_tuning_table_7090);
-
-static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state)
-{
-	int ret = 0;
-	u16 lo4 = 0xe900;
-
-	s16 adc_target;
-	u16 adc;
-	s8 step_sign;
-	u8 force_soft_search = 0;
-
-	if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
-		force_soft_search = 1;
-
-	if (*tune_state == CT_TUNER_START) {
-		dprintk("Start Captrim search : %s", (force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO");
-		dib0090_write_reg(state, 0x10, 0x2B1);
-		dib0090_write_reg(state, 0x1e, 0x0032);
-
-		if (!state->tuner_is_tuned) {
-			/* prepare a complete captrim */
-			if (!state->identity.p1g || force_soft_search)
-				state->step = state->captrim = state->fcaptrim = 64;
-
-			state->current_rf = state->rf_request;
-		} else {	/* we are already tuned to this frequency - the configuration is correct  */
-			if (!state->identity.p1g || force_soft_search) {
-				/* do a minimal captrim even if the frequency has not changed */
-				state->step = 4;
-				state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f;
-			}
-		}
-		state->adc_diff = 3000;
-		*tune_state = CT_TUNER_STEP_0;
-
-	} else if (*tune_state == CT_TUNER_STEP_0) {
-		if (state->identity.p1g && !force_soft_search) {
-			u8 ratio = 31;
-
-			dib0090_write_reg(state, 0x40, (3 << 7) | (ratio << 2) | (1 << 1) | 1);
-			dib0090_read_reg(state, 0x40);
-			ret = 50;
-		} else {
-			state->step /= 2;
-			dib0090_write_reg(state, 0x18, lo4 | state->captrim);
-
-			if (state->identity.in_soc)
-				ret = 25;
-		}
-		*tune_state = CT_TUNER_STEP_1;
-
-	} else if (*tune_state == CT_TUNER_STEP_1) {
-		if (state->identity.p1g && !force_soft_search) {
-			dib0090_write_reg(state, 0x40, 0x18c | (0 << 1) | 0);
-			dib0090_read_reg(state, 0x40);
-
-			state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F;
-			dprintk("***Final Captrim= 0x%x", state->fcaptrim);
-			*tune_state = CT_TUNER_STEP_3;
-
-		} else {
-			/* MERGE for all krosus before P1G */
-			adc = dib0090_get_slow_adc_val(state);
-			dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024);
-
-			if (state->rest == 0 || state->identity.in_soc) {	/* Just for 8090P SOCS where auto captrim HW bug : TO CHECK IN ACI for SOCS !!! if 400 for 8090p SOC => tune issue !!! */
-				adc_target = 200;
-			} else
-				adc_target = 400;
-
-			if (adc >= adc_target) {
-				adc -= adc_target;
-				step_sign = -1;
-			} else {
-				adc = adc_target - adc;
-				step_sign = 1;
-			}
-
-			if (adc < state->adc_diff) {
-				dprintk("CAPTRIM=%d is closer to target (%d/%d)", (u32) state->captrim, (u32) adc, (u32) state->adc_diff);
-				state->adc_diff = adc;
-				state->fcaptrim = state->captrim;
-			}
-
-			state->captrim += step_sign * state->step;
-			if (state->step >= 1)
-				*tune_state = CT_TUNER_STEP_0;
-			else
-				*tune_state = CT_TUNER_STEP_2;
-
-			ret = 25;
-		}
-	} else if (*tune_state == CT_TUNER_STEP_2) {	/* this step is only used by krosus < P1G */
-		/*write the final cptrim config */
-		dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim);
-
-		*tune_state = CT_TUNER_STEP_3;
-
-	} else if (*tune_state == CT_TUNER_STEP_3) {
-		state->calibrate &= ~CAPTRIM_CAL;
-		*tune_state = CT_TUNER_STEP_0;
-	}
-
-	return ret;
-}
-
-static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tune_state *tune_state)
-{
-	int ret = 15;
-	s16 val;
-
-	switch (*tune_state) {
-	case CT_TUNER_START:
-		state->wbdmux = dib0090_read_reg(state, 0x10);
-		dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3));
-
-		state->bias = dib0090_read_reg(state, 0x13);
-		dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8));
-
-		*tune_state = CT_TUNER_STEP_0;
-		/* wait for the WBDMUX to switch and for the ADC to sample */
-		break;
-
-	case CT_TUNER_STEP_0:
-		state->adc_diff = dib0090_get_slow_adc_val(state);
-		dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8));
-		*tune_state = CT_TUNER_STEP_1;
-		break;
-
-	case CT_TUNER_STEP_1:
-		val = dib0090_get_slow_adc_val(state);
-		state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55;
-
-		dprintk("temperature: %d C", state->temperature - 30);
-
-		*tune_state = CT_TUNER_STEP_2;
-		break;
-
-	case CT_TUNER_STEP_2:
-		dib0090_write_reg(state, 0x13, state->bias);
-		dib0090_write_reg(state, 0x10, state->wbdmux);	/* write back original WBDMUX */
-
-		*tune_state = CT_TUNER_START;
-		state->calibrate &= ~TEMP_CAL;
-		if (state->config->analog_output == 0)
-			dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
-
-		break;
-
-	default:
-		ret = 0;
-		break;
-	}
-	return ret;
-}
-
-#define WBD     0x781		/* 1 1 1 1 0000 0 0 1 */
-static int dib0090_tune(struct dvb_frontend *fe)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-	const struct dib0090_tuning *tune = state->current_tune_table_index;
-	const struct dib0090_pll *pll = state->current_pll_table_index;
-	enum frontend_tune_state *tune_state = &state->tune_state;
-
-	u16 lo5, lo6, Den, tmp;
-	u32 FBDiv, Rest, FREF, VCOF_kHz = 0;
-	int ret = 10;		/* 1ms is the default delay most of the time */
-	u8 c, i;
-
-	/************************* VCO ***************************/
-	/* Default values for FG                                 */
-	/* from these are needed :                               */
-	/* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv             */
-
-	/* in any case we first need to do a calibration if needed */
-	if (*tune_state == CT_TUNER_START) {
-		/* deactivate DataTX before some calibrations */
-		if (state->calibrate & (DC_CAL | TEMP_CAL | WBD_CAL))
-			dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
-		else
-			/* Activate DataTX in case a calibration has been done before */
-			if (state->config->analog_output == 0)
-				dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
-	}
-
-	if (state->calibrate & DC_CAL)
-		return dib0090_dc_offset_calibration(state, tune_state);
-	else if (state->calibrate & WBD_CAL) {
-		if (state->current_rf == 0)
-			state->current_rf = state->fe->dtv_property_cache.frequency / 1000;
-		return dib0090_wbd_calibration(state, tune_state);
-	} else if (state->calibrate & TEMP_CAL)
-		return dib0090_get_temperature(state, tune_state);
-	else if (state->calibrate & CAPTRIM_CAL)
-		return dib0090_captrim_search(state, tune_state);
-
-	if (*tune_state == CT_TUNER_START) {
-		/* if soc and AGC pwm control, disengage mux to be able to R/W access to 0x01 register to set the right filter (cutoff_freq_select) during the tune sequence, otherwise, SOC SERPAR error when accessing to 0x01 */
-		if (state->config->use_pwm_agc && state->identity.in_soc) {
-			tmp = dib0090_read_reg(state, 0x39);
-			if ((tmp >> 10) & 0x1)
-				dib0090_write_reg(state, 0x39, tmp & ~(1 << 10));
-		}
-
-		state->current_band = (u8) BAND_OF_FREQUENCY(state->fe->dtv_property_cache.frequency / 1000);
-		state->rf_request =
-			state->fe->dtv_property_cache.frequency / 1000 + (state->current_band ==
-					BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->
-					freq_offset_khz_vhf);
-
-		/* in ISDB-T 1seg we shift tuning frequency */
-		if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1
-					&& state->fe->dtv_property_cache.isdbt_partial_reception == 0)) {
-			const struct dib0090_low_if_offset_table *LUT_offset = state->config->low_if;
-			u8 found_offset = 0;
-			u32 margin_khz = 100;
-
-			if (LUT_offset != NULL) {
-				while (LUT_offset->RF_freq != 0xffff) {
-					if (((state->rf_request > (LUT_offset->RF_freq - margin_khz))
-								&& (state->rf_request < (LUT_offset->RF_freq + margin_khz)))
-							&& LUT_offset->std == state->fe->dtv_property_cache.delivery_system) {
-						state->rf_request += LUT_offset->offset_khz;
-						found_offset = 1;
-						break;
-					}
-					LUT_offset++;
-				}
-			}
-
-			if (found_offset == 0)
-				state->rf_request += 400;
-		}
-		if (state->current_rf != state->rf_request || (state->current_standard != state->fe->dtv_property_cache.delivery_system)) {
-			state->tuner_is_tuned = 0;
-			state->current_rf = 0;
-			state->current_standard = 0;
-
-			tune = dib0090_tuning_table;
-			if (state->identity.p1g)
-				tune = dib0090_p1g_tuning_table;
-
-			tmp = (state->identity.version >> 5) & 0x7;
-
-			if (state->identity.in_soc) {
-				if (state->config->force_cband_input) {	/* Use the CBAND input for all band */
-					if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF
-							|| state->current_band & BAND_UHF) {
-						state->current_band = BAND_CBAND;
-						if (state->config->is_dib7090e)
-							tune = dib0090_tuning_table_cband_7090e_sensitivity;
-						else
-							tune = dib0090_tuning_table_cband_7090;
-					}
-				} else {	/* Use the CBAND input for all band under UHF */
-					if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) {
-						state->current_band = BAND_CBAND;
-						if (state->config->is_dib7090e)
-							tune = dib0090_tuning_table_cband_7090e_sensitivity;
-						else
-							tune = dib0090_tuning_table_cband_7090;
-					}
-				}
-			} else
-			 if (tmp == 0x4 || tmp == 0x7) {
-				/* CBAND tuner version for VHF */
-				if (state->current_band == BAND_FM || state->current_band == BAND_CBAND || state->current_band == BAND_VHF) {
-					state->current_band = BAND_CBAND;	/* Force CBAND */
-
-					tune = dib0090_tuning_table_fm_vhf_on_cband;
-					if (state->identity.p1g)
-						tune = dib0090_p1g_tuning_table_fm_vhf_on_cband;
-				}
-			}
-
-			pll = dib0090_pll_table;
-			if (state->identity.p1g)
-				pll = dib0090_p1g_pll_table;
-
-			/* Look for the interval */
-			while (state->rf_request > tune->max_freq)
-				tune++;
-			while (state->rf_request > pll->max_freq)
-				pll++;
-
-			state->current_tune_table_index = tune;
-			state->current_pll_table_index = pll;
-
-			dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim));
-
-			VCOF_kHz = (pll->hfdiv * state->rf_request) * 2;
-
-			FREF = state->config->io.clock_khz;
-			if (state->config->fref_clock_ratio != 0)
-				FREF /= state->config->fref_clock_ratio;
-
-			FBDiv = (VCOF_kHz / pll->topresc / FREF);
-			Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF;
-
-			if (Rest < LPF)
-				Rest = 0;
-			else if (Rest < 2 * LPF)
-				Rest = 2 * LPF;
-			else if (Rest > (FREF - LPF)) {
-				Rest = 0;
-				FBDiv += 1;
-			} else if (Rest > (FREF - 2 * LPF))
-				Rest = FREF - 2 * LPF;
-			Rest = (Rest * 6528) / (FREF / 10);
-			state->rest = Rest;
-
-			/* external loop filter, otherwise:
-			 * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4;
-			 * lo6 = 0x0e34 */
-
-			if (Rest == 0) {
-				if (pll->vco_band)
-					lo5 = 0x049f;
-				else
-					lo5 = 0x041f;
-			} else {
-				if (pll->vco_band)
-					lo5 = 0x049e;
-				else if (state->config->analog_output)
-					lo5 = 0x041d;
-				else
-					lo5 = 0x041c;
-			}
-
-			if (state->identity.p1g) {	/* Bias is done automatically in P1G */
-				if (state->identity.in_soc) {
-					if (state->identity.version == SOC_8090_P1G_11R1)
-						lo5 = 0x46f;
-					else
-						lo5 = 0x42f;
-				} else
-					lo5 = 0x42c;
-			}
-
-			lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7);	/* bit 15 is the split to the slave, we do not do it here */
-
-			if (!state->config->io.pll_int_loop_filt) {
-				if (state->identity.in_soc)
-					lo6 = 0xff98;
-				else if (state->identity.p1g || (Rest == 0))
-					lo6 = 0xfff8;
-				else
-					lo6 = 0xff28;
-			} else
-				lo6 = (state->config->io.pll_int_loop_filt << 3);
-
-			Den = 1;
-
-			if (Rest > 0) {
-				if (state->config->analog_output)
-					lo6 |= (1 << 2) | 2;
-				else {
-					if (state->identity.in_soc)
-						lo6 |= (1 << 2) | 2;
-					else
-						lo6 |= (1 << 2) | 2;
-				}
-				Den = 255;
-			}
-			dib0090_write_reg(state, 0x15, (u16) FBDiv);
-			if (state->config->fref_clock_ratio != 0)
-				dib0090_write_reg(state, 0x16, (Den << 8) | state->config->fref_clock_ratio);
-			else
-				dib0090_write_reg(state, 0x16, (Den << 8) | 1);
-			dib0090_write_reg(state, 0x17, (u16) Rest);
-			dib0090_write_reg(state, 0x19, lo5);
-			dib0090_write_reg(state, 0x1c, lo6);
-
-			lo6 = tune->tuner_enable;
-			if (state->config->analog_output)
-				lo6 = (lo6 & 0xff9f) | 0x2;
-
-			dib0090_write_reg(state, 0x24, lo6 | EN_LO | state->config->use_pwm_agc * EN_CRYSTAL);
-
-		}
-
-		state->current_rf = state->rf_request;
-		state->current_standard = state->fe->dtv_property_cache.delivery_system;
-
-		ret = 20;
-		state->calibrate = CAPTRIM_CAL;	/* captrim serach now */
-	}
-
-	else if (*tune_state == CT_TUNER_STEP_0) {	/* Warning : because of captrim cal, if you change this step, change it also in _cal.c file because it is the step following captrim cal state machine */
-		const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
-
-		while (state->current_rf / 1000 > wbd->max_freq)
-			wbd++;
-
-		dib0090_write_reg(state, 0x1e, 0x07ff);
-		dprintk("Final Captrim: %d", (u32) state->fcaptrim);
-		dprintk("HFDIV code: %d", (u32) pll->hfdiv_code);
-		dprintk("VCO = %d", (u32) pll->vco_band);
-		dprintk("VCOF in kHz: %d ((%d*%d) << 1))", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request);
-		dprintk("REFDIV: %d, FREF: %d", (u32) 1, (u32) state->config->io.clock_khz);
-		dprintk("FBDIV: %d, Rest: %d", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17));
-		dprintk("Num: %d, Den: %d, SD: %d", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8),
-			(u32) dib0090_read_reg(state, 0x1c) & 0x3);
-
-#define WBD     0x781		/* 1 1 1 1 0000 0 0 1 */
-		c = 4;
-		i = 3;
-
-		if (wbd->wbd_gain != 0)
-			c = wbd->wbd_gain;
-
-		state->wbdmux = (c << 13) | (i << 11) | (WBD | (state->config->use_pwm_agc << 1));
-		dib0090_write_reg(state, 0x10, state->wbdmux);
-
-		if ((tune->tuner_enable == EN_CAB) && state->identity.p1g) {
-			dprintk("P1G : The cable band is selected and lna_tune = %d", tune->lna_tune);
-			dib0090_write_reg(state, 0x09, tune->lna_bias);
-			dib0090_write_reg(state, 0x0b, 0xb800 | (tune->lna_tune << 6) | (tune->switch_trim));
-		} else
-			dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | tune->lna_bias);
-
-		dib0090_write_reg(state, 0x0c, tune->v2i);
-		dib0090_write_reg(state, 0x0d, tune->mix);
-		dib0090_write_reg(state, 0x0e, tune->load);
-		*tune_state = CT_TUNER_STEP_1;
-
-	} else if (*tune_state == CT_TUNER_STEP_1) {
-		/* initialize the lt gain register */
-		state->rf_lt_def = 0x7c00;
-
-		dib0090_set_bandwidth(state);
-		state->tuner_is_tuned = 1;
-
-		state->calibrate |= WBD_CAL;
-		state->calibrate |= TEMP_CAL;
-		*tune_state = CT_TUNER_STOP;
-	} else
-		ret = FE_CALLBACK_TIME_NEVER;
-	return ret;
-}
-
-static int dib0090_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-
-	return state->tune_state;
-}
-
-EXPORT_SYMBOL(dib0090_get_tune_state);
-
-int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-
-	state->tune_state = tune_state;
-	return 0;
-}
-
-EXPORT_SYMBOL(dib0090_set_tune_state);
-
-static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-
-	*frequency = 1000 * state->current_rf;
-	return 0;
-}
-
-static int dib0090_set_params(struct dvb_frontend *fe)
-{
-	struct dib0090_state *state = fe->tuner_priv;
-	u32 ret;
-
-	state->tune_state = CT_TUNER_START;
-
-	do {
-		ret = dib0090_tune(fe);
-		if (ret != FE_CALLBACK_TIME_NEVER)
-			msleep(ret / 10);
-		else
-			break;
-	} while (state->tune_state != CT_TUNER_STOP);
-
-	return 0;
-}
-
-static const struct dvb_tuner_ops dib0090_ops = {
-	.info = {
-		 .name = "DiBcom DiB0090",
-		 .frequency_min = 45000000,
-		 .frequency_max = 860000000,
-		 .frequency_step = 1000,
-		 },
-	.release = dib0090_release,
-
-	.init = dib0090_wakeup,
-	.sleep = dib0090_sleep,
-	.set_params = dib0090_set_params,
-	.get_frequency = dib0090_get_frequency,
-};
-
-static const struct dvb_tuner_ops dib0090_fw_ops = {
-	.info = {
-		 .name = "DiBcom DiB0090",
-		 .frequency_min = 45000000,
-		 .frequency_max = 860000000,
-		 .frequency_step = 1000,
-		 },
-	.release = dib0090_release,
-
-	.init = NULL,
-	.sleep = NULL,
-	.set_params = NULL,
-	.get_frequency = NULL,
-};
-
-static const struct dib0090_wbd_slope dib0090_wbd_table_default[] = {
-	{470, 0, 250, 0, 100, 4},
-	{860, 51, 866, 21, 375, 4},
-	{1700, 0, 800, 0, 850, 4},
-	{2900, 0, 250, 0, 100, 6},
-	{0xFFFF, 0, 0, 0, 0, 0},
-};
-
-struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
-{
-	struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL);
-	if (st == NULL)
-		return NULL;
-
-	st->config = config;
-	st->i2c = i2c;
-	st->fe = fe;
-	mutex_init(&st->i2c_buffer_lock);
-	fe->tuner_priv = st;
-
-	if (config->wbd == NULL)
-		st->current_wbd_table = dib0090_wbd_table_default;
-	else
-		st->current_wbd_table = config->wbd;
-
-	if (dib0090_reset(fe) != 0)
-		goto free_mem;
-
-	printk(KERN_INFO "DiB0090: successfully identified\n");
-	memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops));
-
-	return fe;
- free_mem:
-	kfree(st);
-	fe->tuner_priv = NULL;
-	return NULL;
-}
-
-EXPORT_SYMBOL(dib0090_register);
-
-struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
-{
-	struct dib0090_fw_state *st = kzalloc(sizeof(struct dib0090_fw_state), GFP_KERNEL);
-	if (st == NULL)
-		return NULL;
-
-	st->config = config;
-	st->i2c = i2c;
-	st->fe = fe;
-	mutex_init(&st->i2c_buffer_lock);
-	fe->tuner_priv = st;
-
-	if (dib0090_fw_reset_digital(fe, st->config) != 0)
-		goto free_mem;
-
-	dprintk("DiB0090 FW: successfully identified");
-	memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops));
-
-	return fe;
-free_mem:
-	kfree(st);
-	fe->tuner_priv = NULL;
-	return NULL;
-}
-EXPORT_SYMBOL(dib0090_fw_register);
-
-MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
-MODULE_AUTHOR("Olivier Grenie <olivier.grenie@dibcom.fr>");
-MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dib0090.h b/drivers/media/dvb/frontends/dib0090.h
deleted file mode 100644
index 781dc49..0000000
--- a/drivers/media/dvb/frontends/dib0090.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner.
- *
- * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
- *
- * 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, version 2.
- */
-#ifndef DIB0090_H
-#define DIB0090_H
-
-struct dvb_frontend;
-struct i2c_adapter;
-
-#define DEFAULT_DIB0090_I2C_ADDRESS 0x60
-
-struct dib0090_io_config {
-	u32 clock_khz;
-
-	u8 pll_bypass:1;
-	u8 pll_range:1;
-	u8 pll_prediv:6;
-	u8 pll_loopdiv:6;
-
-	u8 adc_clock_ratio;	/* valid is 8, 7 ,6 */
-	u16 pll_int_loop_filt;
-};
-
-struct dib0090_wbd_slope {
-	u16 max_freq;		/* for every frequency less than or equal to that field: this information is correct */
-	u16 slope_cold;
-	u16 offset_cold;
-	u16 slope_hot;
-	u16 offset_hot;
-	u8 wbd_gain;
-};
-
-struct dib0090_low_if_offset_table {
-	int std;
-	u32 RF_freq;
-	s32 offset_khz;
-};
-
-struct dib0090_config {
-	struct dib0090_io_config io;
-	int (*reset) (struct dvb_frontend *, int);
-	int (*sleep) (struct dvb_frontend *, int);
-
-	/*  offset in kHz */
-	int freq_offset_khz_uhf;
-	int freq_offset_khz_vhf;
-
-	int (*get_adc_power) (struct dvb_frontend *);
-
-	u8 clkouttobamse:1;	/* activate or deactivate clock output */
-	u8 analog_output;
-
-	u8 i2c_address;
-	/* add drives and other things if necessary */
-	u16 wbd_vhf_offset;
-	u16 wbd_cband_offset;
-	u8 use_pwm_agc;
-	u8 clkoutdrive;
-
-	u8 ls_cfg_pad_drv;
-	u8 data_tx_drv;
-
-	u8 in_soc;
-	const struct dib0090_low_if_offset_table *low_if;
-	u8 fref_clock_ratio;
-	u16 force_cband_input;
-	struct dib0090_wbd_slope *wbd;
-	u8 is_dib7090e;
-	u8 force_crystal_mode;
-};
-
-#if defined(CONFIG_DVB_TUNER_DIB0090) || (defined(CONFIG_DVB_TUNER_DIB0090_MODULE) && defined(MODULE))
-extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config);
-extern struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config);
-extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast);
-extern void dib0090_pwm_gain_reset(struct dvb_frontend *fe);
-extern u16 dib0090_get_wbd_target(struct dvb_frontend *tuner);
-extern u16 dib0090_get_wbd_offset(struct dvb_frontend *fe);
-extern int dib0090_gain_control(struct dvb_frontend *fe);
-extern enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe);
-extern int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state);
-extern void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt);
-extern void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff);
-extern int dib0090_set_switch(struct dvb_frontend *fe, u8 sw1, u8 sw2, u8 sw3);
-extern int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff);
-extern int dib0090_update_rframp_7090(struct dvb_frontend *fe,
-		u8 cfg_sensitivity);
-extern int dib0090_update_tuning_table_7090(struct dvb_frontend *fe,
-		u8 cfg_sensitivity);
-#else
-static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0090_config *config)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-}
-
-static inline void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-}
-
-static inline u16 dib0090_get_wbd_target(struct dvb_frontend *tuner)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return 0;
-}
-
-static inline u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return 0;
-}
-
-static inline int dib0090_gain_control(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return CT_DONE;
-}
-
-static inline int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-}
-
-static inline void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-}
-
-static inline int dib0090_set_switch(struct dvb_frontend *fe,
-		u8 sw1, u8 sw2, u8 sw3)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib0090_update_rframp_7090(struct dvb_frontend *fe,
-		u8 cfg_sensitivity)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib0090_update_tuning_table_7090(struct dvb_frontend *fe,
-		u8 cfg_sensitivity)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-#endif
-
-#endif
diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h
deleted file mode 100644
index 404f63a..0000000
--- a/drivers/media/dvb/frontends/dib3000.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * public header file of the frontend drivers for mobile DVB-T demodulators
- * DiBcom 3000M-B and DiBcom 3000P/M-C (http://www.dibcom.fr/)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * based on GPL code from DibCom, which has
- *
- * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
- *
- *	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, version 2.
- *
- * Acknowledgements
- *
- *  Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
- *  sources, on which this driver (and the dvb-dibusb) are based.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- *
- */
-
-#ifndef DIB3000_H
-#define DIB3000_H
-
-#include <linux/dvb/frontend.h>
-
-struct dib3000_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-};
-
-struct dib_fe_xfer_ops
-{
-	/* pid and transfer handling is done in the demodulator */
-	int (*pid_parse)(struct dvb_frontend *fe, int onoff);
-	int (*fifo_ctrl)(struct dvb_frontend *fe, int onoff);
-	int (*pid_ctrl)(struct dvb_frontend *fe, int index, int pid, int onoff);
-	int (*tuner_pass_ctrl)(struct dvb_frontend *fe, int onoff, u8 pll_ctrl);
-};
-
-#if defined(CONFIG_DVB_DIB3000MB) || (defined(CONFIG_DVB_DIB3000MB_MODULE) && defined(MODULE))
-extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
-					     struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops);
-#else
-static inline struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
-					     struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_DIB3000MB
-
-#endif // DIB3000_H
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
deleted file mode 100644
index af91e0c..0000000
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ /dev/null
@@ -1,829 +0,0 @@
-/*
- * Frontend driver for mobile DVB-T demodulator DiBcom 3000M-B
- * DiBcom (http://www.dibcom.fr/)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * based on GPL code from DibCom, which has
- *
- * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
- *
- *	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, version 2.
- *
- * Acknowledgements
- *
- *  Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
- *  sources, on which this driver (and the dvb-dibusb) are based.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-
-#include "dib3000.h"
-#include "dib3000mb_priv.h"
-
-/* Version information */
-#define DRIVER_VERSION "0.1"
-#define DRIVER_DESC "DiBcom 3000M-B DVB-T demodulator"
-#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able)).");
-
-#define deb_info(args...) dprintk(0x01,args)
-#define deb_i2c(args...)  dprintk(0x02,args)
-#define deb_srch(args...) dprintk(0x04,args)
-#define deb_info(args...) dprintk(0x01,args)
-#define deb_xfer(args...) dprintk(0x02,args)
-#define deb_setf(args...) dprintk(0x04,args)
-#define deb_getf(args...) dprintk(0x08,args)
-
-static int dib3000_read_reg(struct dib3000_state *state, u16 reg)
-{
-	u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
-	u8 rb[2];
-	struct i2c_msg msg[] = {
-		{ .addr = state->config.demod_address, .flags = 0,        .buf = wb, .len = 2 },
-		{ .addr = state->config.demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 },
-	};
-
-	if (i2c_transfer(state->i2c, msg, 2) != 2)
-		deb_i2c("i2c read error\n");
-
-	deb_i2c("reading i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,
-			(rb[0] << 8) | rb[1],(rb[0] << 8) | rb[1]);
-
-	return (rb[0] << 8) | rb[1];
-}
-
-static int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val)
-{
-	u8 b[] = {
-		(reg >> 8) & 0xff, reg & 0xff,
-		(val >> 8) & 0xff, val & 0xff,
-	};
-	struct i2c_msg msg[] = {
-		{ .addr = state->config.demod_address, .flags = 0, .buf = b, .len = 4 }
-	};
-	deb_i2c("writing i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,val,val);
-
-	return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0;
-}
-
-static int dib3000_search_status(u16 irq,u16 lock)
-{
-	if (irq & 0x02) {
-		if (lock & 0x01) {
-			deb_srch("auto search succeeded\n");
-			return 1; // auto search succeeded
-		} else {
-			deb_srch("auto search not successful\n");
-			return 0; // auto search failed
-		}
-	} else if (irq & 0x01)  {
-		deb_srch("auto search failed\n");
-		return 0; // auto search failed
-	}
-	return -1; // try again
-}
-
-/* for auto search */
-static u16 dib3000_seq[2][2][2] =     /* fft,gua,   inv   */
-	{ /* fft */
-		{ /* gua */
-			{ 0, 1 },                   /*  0   0   { 0,1 } */
-			{ 3, 9 },                   /*  0   1   { 0,1 } */
-		},
-		{
-			{ 2, 5 },                   /*  1   0   { 0,1 } */
-			{ 6, 11 },                  /*  1   1   { 0,1 } */
-		}
-	};
-
-static int dib3000mb_get_frontend(struct dvb_frontend* fe);
-
-static int dib3000mb_set_frontend(struct dvb_frontend *fe, int tuner)
-{
-	struct dib3000_state* state = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	fe_code_rate_t fe_cr = FEC_NONE;
-	int search_state, seq;
-
-	if (tuner && fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-
-		deb_setf("bandwidth: ");
-		switch (c->bandwidth_hz) {
-			case 8000000:
-				deb_setf("8 MHz\n");
-				wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]);
-				wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz);
-				break;
-			case 7000000:
-				deb_setf("7 MHz\n");
-				wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[1]);
-				wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_7mhz);
-				break;
-			case 6000000:
-				deb_setf("6 MHz\n");
-				wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[0]);
-				wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_6mhz);
-				break;
-			case 0:
-				return -EOPNOTSUPP;
-			default:
-				err("unknown bandwidth value.");
-				return -EINVAL;
-		}
-	}
-	wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4);
-
-	deb_setf("transmission mode: ");
-	switch (c->transmission_mode) {
-		case TRANSMISSION_MODE_2K:
-			deb_setf("2k\n");
-			wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_2K);
-			break;
-		case TRANSMISSION_MODE_8K:
-			deb_setf("8k\n");
-			wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_8K);
-			break;
-		case TRANSMISSION_MODE_AUTO:
-			deb_setf("auto\n");
-			break;
-		default:
-			return -EINVAL;
-	}
-
-	deb_setf("guard: ");
-	switch (c->guard_interval) {
-		case GUARD_INTERVAL_1_32:
-			deb_setf("1_32\n");
-			wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_32);
-			break;
-		case GUARD_INTERVAL_1_16:
-			deb_setf("1_16\n");
-			wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_16);
-			break;
-		case GUARD_INTERVAL_1_8:
-			deb_setf("1_8\n");
-			wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_8);
-			break;
-		case GUARD_INTERVAL_1_4:
-			deb_setf("1_4\n");
-			wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_4);
-			break;
-		case GUARD_INTERVAL_AUTO:
-			deb_setf("auto\n");
-			break;
-		default:
-			return -EINVAL;
-	}
-
-	deb_setf("inversion: ");
-	switch (c->inversion) {
-		case INVERSION_OFF:
-			deb_setf("off\n");
-			wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_OFF);
-			break;
-		case INVERSION_AUTO:
-			deb_setf("auto ");
-			break;
-		case INVERSION_ON:
-			deb_setf("on\n");
-			wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_ON);
-			break;
-		default:
-			return -EINVAL;
-	}
-
-	deb_setf("modulation: ");
-	switch (c->modulation) {
-		case QPSK:
-			deb_setf("qpsk\n");
-			wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_QPSK);
-			break;
-		case QAM_16:
-			deb_setf("qam16\n");
-			wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_16QAM);
-			break;
-		case QAM_64:
-			deb_setf("qam64\n");
-			wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_64QAM);
-			break;
-		case QAM_AUTO:
-			break;
-		default:
-			return -EINVAL;
-	}
-	deb_setf("hierarchy: ");
-	switch (c->hierarchy) {
-		case HIERARCHY_NONE:
-			deb_setf("none ");
-			/* fall through */
-		case HIERARCHY_1:
-			deb_setf("alpha=1\n");
-			wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_1);
-			break;
-		case HIERARCHY_2:
-			deb_setf("alpha=2\n");
-			wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_2);
-			break;
-		case HIERARCHY_4:
-			deb_setf("alpha=4\n");
-			wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_4);
-			break;
-		case HIERARCHY_AUTO:
-			deb_setf("alpha=auto\n");
-			break;
-		default:
-			return -EINVAL;
-	}
-
-	deb_setf("hierarchy: ");
-	if (c->hierarchy == HIERARCHY_NONE) {
-		deb_setf("none\n");
-		wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_OFF);
-		wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_HP);
-		fe_cr = c->code_rate_HP;
-	} else if (c->hierarchy != HIERARCHY_AUTO) {
-		deb_setf("on\n");
-		wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_ON);
-		wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_LP);
-		fe_cr = c->code_rate_LP;
-	}
-	deb_setf("fec: ");
-	switch (fe_cr) {
-		case FEC_1_2:
-			deb_setf("1_2\n");
-			wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_1_2);
-			break;
-		case FEC_2_3:
-			deb_setf("2_3\n");
-			wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_2_3);
-			break;
-		case FEC_3_4:
-			deb_setf("3_4\n");
-			wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_3_4);
-			break;
-		case FEC_5_6:
-			deb_setf("5_6\n");
-			wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_5_6);
-			break;
-		case FEC_7_8:
-			deb_setf("7_8\n");
-			wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_7_8);
-			break;
-		case FEC_NONE:
-			deb_setf("none ");
-			break;
-		case FEC_AUTO:
-			deb_setf("auto\n");
-			break;
-		default:
-			return -EINVAL;
-	}
-
-	seq = dib3000_seq
-		[c->transmission_mode == TRANSMISSION_MODE_AUTO]
-		[c->guard_interval == GUARD_INTERVAL_AUTO]
-		[c->inversion == INVERSION_AUTO];
-
-	deb_setf("seq? %d\n", seq);
-
-	wr(DIB3000MB_REG_SEQ, seq);
-
-	wr(DIB3000MB_REG_ISI, seq ? DIB3000MB_ISI_INHIBIT : DIB3000MB_ISI_ACTIVATE);
-
-	if (c->transmission_mode == TRANSMISSION_MODE_2K) {
-		if (c->guard_interval == GUARD_INTERVAL_1_8) {
-			wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_2K_1_8);
-		} else {
-			wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_DEFAULT);
-		}
-
-		wr(DIB3000MB_REG_UNK_121, DIB3000MB_UNK_121_2K);
-	} else {
-		wr(DIB3000MB_REG_UNK_121, DIB3000MB_UNK_121_DEFAULT);
-	}
-
-	wr(DIB3000MB_REG_MOBILE_ALGO, DIB3000MB_MOBILE_ALGO_OFF);
-	wr(DIB3000MB_REG_MOBILE_MODE_QAM, DIB3000MB_MOBILE_MODE_QAM_OFF);
-	wr(DIB3000MB_REG_MOBILE_MODE, DIB3000MB_MOBILE_MODE_OFF);
-
-	wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_high);
-
-	wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_ACTIVATE);
-
-	wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC + DIB3000MB_RESTART_CTRL);
-	wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF);
-
-	/* wait for AGC lock */
-	msleep(70);
-
-	wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low);
-
-	/* something has to be auto searched */
-	if (c->modulation == QAM_AUTO ||
-		c->hierarchy == HIERARCHY_AUTO ||
-		fe_cr == FEC_AUTO ||
-		c->inversion == INVERSION_AUTO) {
-		int as_count=0;
-
-		deb_setf("autosearch enabled.\n");
-
-		wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_INHIBIT);
-
-		wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AUTO_SEARCH);
-		wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF);
-
-		while ((search_state =
-				dib3000_search_status(
-					rd(DIB3000MB_REG_AS_IRQ_PENDING),
-					rd(DIB3000MB_REG_LOCK2_VALUE))) < 0 && as_count++ < 100)
-			msleep(1);
-
-		deb_setf("search_state after autosearch %d after %d checks\n",search_state,as_count);
-
-		if (search_state == 1) {
-			if (dib3000mb_get_frontend(fe) == 0) {
-				deb_setf("reading tuning data from frontend succeeded.\n");
-				return dib3000mb_set_frontend(fe, 0);
-			}
-		}
-
-	} else {
-		wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_CTRL);
-		wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF);
-	}
-
-	return 0;
-}
-
-static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
-{
-	struct dib3000_state* state = fe->demodulator_priv;
-
-	deb_info("dib3000mb is getting up.\n");
-	wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_UP);
-
-	wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC);
-
-	wr(DIB3000MB_REG_RESET_DEVICE, DIB3000MB_RESET_DEVICE);
-	wr(DIB3000MB_REG_RESET_DEVICE, DIB3000MB_RESET_DEVICE_RST);
-
-	wr(DIB3000MB_REG_CLOCK, DIB3000MB_CLOCK_DEFAULT);
-
-	wr(DIB3000MB_REG_ELECT_OUT_MODE, DIB3000MB_ELECT_OUT_MODE_ON);
-
-	wr(DIB3000MB_REG_DDS_FREQ_MSB, DIB3000MB_DDS_FREQ_MSB);
-	wr(DIB3000MB_REG_DDS_FREQ_LSB, DIB3000MB_DDS_FREQ_LSB);
-
-	wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]);
-
-	wr_foreach(dib3000mb_reg_impulse_noise,
-			dib3000mb_impulse_noise_values[DIB3000MB_IMPNOISE_OFF]);
-
-	wr_foreach(dib3000mb_reg_agc_gain, dib3000mb_default_agc_gain);
-
-	wr(DIB3000MB_REG_PHASE_NOISE, DIB3000MB_PHASE_NOISE_DEFAULT);
-
-	wr_foreach(dib3000mb_reg_phase_noise, dib3000mb_default_noise_phase);
-
-	wr_foreach(dib3000mb_reg_lock_duration, dib3000mb_default_lock_duration);
-
-	wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low);
-
-	wr(DIB3000MB_REG_LOCK0_MASK, DIB3000MB_LOCK0_DEFAULT);
-	wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4);
-	wr(DIB3000MB_REG_LOCK2_MASK, DIB3000MB_LOCK2_DEFAULT);
-	wr(DIB3000MB_REG_SEQ, dib3000_seq[1][1][1]);
-
-	wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz);
-
-	wr(DIB3000MB_REG_UNK_68, DIB3000MB_UNK_68);
-	wr(DIB3000MB_REG_UNK_69, DIB3000MB_UNK_69);
-	wr(DIB3000MB_REG_UNK_71, DIB3000MB_UNK_71);
-	wr(DIB3000MB_REG_UNK_77, DIB3000MB_UNK_77);
-	wr(DIB3000MB_REG_UNK_78, DIB3000MB_UNK_78);
-	wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_INHIBIT);
-	wr(DIB3000MB_REG_UNK_92, DIB3000MB_UNK_92);
-	wr(DIB3000MB_REG_UNK_96, DIB3000MB_UNK_96);
-	wr(DIB3000MB_REG_UNK_97, DIB3000MB_UNK_97);
-	wr(DIB3000MB_REG_UNK_106, DIB3000MB_UNK_106);
-	wr(DIB3000MB_REG_UNK_107, DIB3000MB_UNK_107);
-	wr(DIB3000MB_REG_UNK_108, DIB3000MB_UNK_108);
-	wr(DIB3000MB_REG_UNK_122, DIB3000MB_UNK_122);
-	wr(DIB3000MB_REG_MOBILE_MODE_QAM, DIB3000MB_MOBILE_MODE_QAM_OFF);
-	wr(DIB3000MB_REG_BERLEN, DIB3000MB_BERLEN_DEFAULT);
-
-	wr_foreach(dib3000mb_reg_filter_coeffs, dib3000mb_filter_coeffs);
-
-	wr(DIB3000MB_REG_MOBILE_ALGO, DIB3000MB_MOBILE_ALGO_ON);
-	wr(DIB3000MB_REG_MULTI_DEMOD_MSB, DIB3000MB_MULTI_DEMOD_MSB);
-	wr(DIB3000MB_REG_MULTI_DEMOD_LSB, DIB3000MB_MULTI_DEMOD_LSB);
-
-	wr(DIB3000MB_REG_OUTPUT_MODE, DIB3000MB_OUTPUT_MODE_SLAVE);
-
-	wr(DIB3000MB_REG_FIFO_142, DIB3000MB_FIFO_142);
-	wr(DIB3000MB_REG_MPEG2_OUT_MODE, DIB3000MB_MPEG2_OUT_MODE_188);
-	wr(DIB3000MB_REG_PID_PARSE, DIB3000MB_PID_PARSE_ACTIVATE);
-	wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_INHIBIT);
-	wr(DIB3000MB_REG_FIFO_146, DIB3000MB_FIFO_146);
-	wr(DIB3000MB_REG_FIFO_147, DIB3000MB_FIFO_147);
-
-	wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF);
-
-	return 0;
-}
-
-static int dib3000mb_get_frontend(struct dvb_frontend* fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct dib3000_state* state = fe->demodulator_priv;
-	fe_code_rate_t *cr;
-	u16 tps_val;
-	int inv_test1,inv_test2;
-	u32 dds_val, threshold = 0x800000;
-
-	if (!rd(DIB3000MB_REG_TPS_LOCK))
-		return 0;
-
-	dds_val = ((rd(DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_VALUE_LSB);
-	deb_getf("DDS_VAL: %x %x %x",dds_val, rd(DIB3000MB_REG_DDS_VALUE_MSB), rd(DIB3000MB_REG_DDS_VALUE_LSB));
-	if (dds_val < threshold)
-		inv_test1 = 0;
-	else if (dds_val == threshold)
-		inv_test1 = 1;
-	else
-		inv_test1 = 2;
-
-	dds_val = ((rd(DIB3000MB_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_FREQ_LSB);
-	deb_getf("DDS_FREQ: %x %x %x",dds_val, rd(DIB3000MB_REG_DDS_FREQ_MSB), rd(DIB3000MB_REG_DDS_FREQ_LSB));
-	if (dds_val < threshold)
-		inv_test2 = 0;
-	else if (dds_val == threshold)
-		inv_test2 = 1;
-	else
-		inv_test2 = 2;
-
-	c->inversion =
-		((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) ||
-		((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ?
-		INVERSION_ON : INVERSION_OFF;
-
-	deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, c->inversion);
-
-	switch ((tps_val = rd(DIB3000MB_REG_TPS_QAM))) {
-		case DIB3000_CONSTELLATION_QPSK:
-			deb_getf("QPSK ");
-			c->modulation = QPSK;
-			break;
-		case DIB3000_CONSTELLATION_16QAM:
-			deb_getf("QAM16 ");
-			c->modulation = QAM_16;
-			break;
-		case DIB3000_CONSTELLATION_64QAM:
-			deb_getf("QAM64 ");
-			c->modulation = QAM_64;
-			break;
-		default:
-			err("Unexpected constellation returned by TPS (%d)", tps_val);
-			break;
-	}
-	deb_getf("TPS: %d\n", tps_val);
-
-	if (rd(DIB3000MB_REG_TPS_HRCH)) {
-		deb_getf("HRCH ON\n");
-		cr = &c->code_rate_LP;
-		c->code_rate_HP = FEC_NONE;
-		switch ((tps_val = rd(DIB3000MB_REG_TPS_VIT_ALPHA))) {
-			case DIB3000_ALPHA_0:
-				deb_getf("HIERARCHY_NONE ");
-				c->hierarchy = HIERARCHY_NONE;
-				break;
-			case DIB3000_ALPHA_1:
-				deb_getf("HIERARCHY_1 ");
-				c->hierarchy = HIERARCHY_1;
-				break;
-			case DIB3000_ALPHA_2:
-				deb_getf("HIERARCHY_2 ");
-				c->hierarchy = HIERARCHY_2;
-				break;
-			case DIB3000_ALPHA_4:
-				deb_getf("HIERARCHY_4 ");
-				c->hierarchy = HIERARCHY_4;
-				break;
-			default:
-				err("Unexpected ALPHA value returned by TPS (%d)", tps_val);
-				break;
-		}
-		deb_getf("TPS: %d\n", tps_val);
-
-		tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP);
-	} else {
-		deb_getf("HRCH OFF\n");
-		cr = &c->code_rate_HP;
-		c->code_rate_LP = FEC_NONE;
-		c->hierarchy = HIERARCHY_NONE;
-
-		tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP);
-	}
-
-	switch (tps_val) {
-		case DIB3000_FEC_1_2:
-			deb_getf("FEC_1_2 ");
-			*cr = FEC_1_2;
-			break;
-		case DIB3000_FEC_2_3:
-			deb_getf("FEC_2_3 ");
-			*cr = FEC_2_3;
-			break;
-		case DIB3000_FEC_3_4:
-			deb_getf("FEC_3_4 ");
-			*cr = FEC_3_4;
-			break;
-		case DIB3000_FEC_5_6:
-			deb_getf("FEC_5_6 ");
-			*cr = FEC_4_5;
-			break;
-		case DIB3000_FEC_7_8:
-			deb_getf("FEC_7_8 ");
-			*cr = FEC_7_8;
-			break;
-		default:
-			err("Unexpected FEC returned by TPS (%d)", tps_val);
-			break;
-	}
-	deb_getf("TPS: %d\n",tps_val);
-
-	switch ((tps_val = rd(DIB3000MB_REG_TPS_GUARD_TIME))) {
-		case DIB3000_GUARD_TIME_1_32:
-			deb_getf("GUARD_INTERVAL_1_32 ");
-			c->guard_interval = GUARD_INTERVAL_1_32;
-			break;
-		case DIB3000_GUARD_TIME_1_16:
-			deb_getf("GUARD_INTERVAL_1_16 ");
-			c->guard_interval = GUARD_INTERVAL_1_16;
-			break;
-		case DIB3000_GUARD_TIME_1_8:
-			deb_getf("GUARD_INTERVAL_1_8 ");
-			c->guard_interval = GUARD_INTERVAL_1_8;
-			break;
-		case DIB3000_GUARD_TIME_1_4:
-			deb_getf("GUARD_INTERVAL_1_4 ");
-			c->guard_interval = GUARD_INTERVAL_1_4;
-			break;
-		default:
-			err("Unexpected Guard Time returned by TPS (%d)", tps_val);
-			break;
-	}
-	deb_getf("TPS: %d\n", tps_val);
-
-	switch ((tps_val = rd(DIB3000MB_REG_TPS_FFT))) {
-		case DIB3000_TRANSMISSION_MODE_2K:
-			deb_getf("TRANSMISSION_MODE_2K ");
-			c->transmission_mode = TRANSMISSION_MODE_2K;
-			break;
-		case DIB3000_TRANSMISSION_MODE_8K:
-			deb_getf("TRANSMISSION_MODE_8K ");
-			c->transmission_mode = TRANSMISSION_MODE_8K;
-			break;
-		default:
-			err("unexpected transmission mode return by TPS (%d)", tps_val);
-			break;
-	}
-	deb_getf("TPS: %d\n", tps_val);
-
-	return 0;
-}
-
-static int dib3000mb_read_status(struct dvb_frontend* fe, fe_status_t *stat)
-{
-	struct dib3000_state* state = fe->demodulator_priv;
-
-	*stat = 0;
-
-	if (rd(DIB3000MB_REG_AGC_LOCK))
-		*stat |= FE_HAS_SIGNAL;
-	if (rd(DIB3000MB_REG_CARRIER_LOCK))
-		*stat |= FE_HAS_CARRIER;
-	if (rd(DIB3000MB_REG_VIT_LCK))
-		*stat |= FE_HAS_VITERBI;
-	if (rd(DIB3000MB_REG_TS_SYNC_LOCK))
-		*stat |= (FE_HAS_SYNC | FE_HAS_LOCK);
-
-	deb_getf("actual status is %2x\n",*stat);
-
-	deb_getf("autoval: tps: %d, qam: %d, hrch: %d, alpha: %d, hp: %d, lp: %d, guard: %d, fft: %d cell: %d\n",
-			rd(DIB3000MB_REG_TPS_LOCK),
-			rd(DIB3000MB_REG_TPS_QAM),
-			rd(DIB3000MB_REG_TPS_HRCH),
-			rd(DIB3000MB_REG_TPS_VIT_ALPHA),
-			rd(DIB3000MB_REG_TPS_CODE_RATE_HP),
-			rd(DIB3000MB_REG_TPS_CODE_RATE_LP),
-			rd(DIB3000MB_REG_TPS_GUARD_TIME),
-			rd(DIB3000MB_REG_TPS_FFT),
-			rd(DIB3000MB_REG_TPS_CELL_ID));
-
-	//*stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
-	return 0;
-}
-
-static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber)
-{
-	struct dib3000_state* state = fe->demodulator_priv;
-
-	*ber = ((rd(DIB3000MB_REG_BER_MSB) << 16) | rd(DIB3000MB_REG_BER_LSB));
-	return 0;
-}
-
-/* see dib3000-watch dvb-apps for exact calcuations of signal_strength and snr */
-static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
-{
-	struct dib3000_state* state = fe->demodulator_priv;
-
-	*strength = rd(DIB3000MB_REG_SIGNAL_POWER) * 0xffff / 0x170;
-	return 0;
-}
-
-static int dib3000mb_read_snr(struct dvb_frontend* fe, u16 *snr)
-{
-	struct dib3000_state* state = fe->demodulator_priv;
-	short sigpow = rd(DIB3000MB_REG_SIGNAL_POWER);
-	int icipow = ((rd(DIB3000MB_REG_NOISE_POWER_MSB) & 0xff) << 16) |
-		rd(DIB3000MB_REG_NOISE_POWER_LSB);
-	*snr = (sigpow << 8) / ((icipow > 0) ? icipow : 1);
-	return 0;
-}
-
-static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
-{
-	struct dib3000_state* state = fe->demodulator_priv;
-
-	*unc = rd(DIB3000MB_REG_PACKET_ERROR_RATE);
-	return 0;
-}
-
-static int dib3000mb_sleep(struct dvb_frontend* fe)
-{
-	struct dib3000_state* state = fe->demodulator_priv;
-	deb_info("dib3000mb is going to bed.\n");
-	wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_DOWN);
-	return 0;
-}
-
-static int dib3000mb_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
-{
-	tune->min_delay_ms = 800;
-	return 0;
-}
-
-static int dib3000mb_fe_init_nonmobile(struct dvb_frontend* fe)
-{
-	return dib3000mb_fe_init(fe, 0);
-}
-
-static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend *fe)
-{
-	return dib3000mb_set_frontend(fe, 1);
-}
-
-static void dib3000mb_release(struct dvb_frontend* fe)
-{
-	struct dib3000_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-/* pid filter and transfer stuff */
-static int dib3000mb_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff)
-{
-	struct dib3000_state *state = fe->demodulator_priv;
-	pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0);
-	wr(index+DIB3000MB_REG_FIRST_PID,pid);
-	return 0;
-}
-
-static int dib3000mb_fifo_control(struct dvb_frontend *fe, int onoff)
-{
-	struct dib3000_state *state = fe->demodulator_priv;
-
-	deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling");
-	if (onoff) {
-		wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_ACTIVATE);
-	} else {
-		wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_INHIBIT);
-	}
-	return 0;
-}
-
-static int dib3000mb_pid_parse(struct dvb_frontend *fe, int onoff)
-{
-	struct dib3000_state *state = fe->demodulator_priv;
-	deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling");
-	wr(DIB3000MB_REG_PID_PARSE,onoff);
-	return 0;
-}
-
-static int dib3000mb_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr)
-{
-	struct dib3000_state *state = fe->demodulator_priv;
-	if (onoff) {
-		wr(DIB3000MB_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr));
-	} else {
-		wr(DIB3000MB_REG_TUNER, DIB3000_TUNER_WRITE_DISABLE(pll_addr));
-	}
-	return 0;
-}
-
-static struct dvb_frontend_ops dib3000mb_ops;
-
-struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
-				      struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops)
-{
-	struct dib3000_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct dib3000_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->i2c = i2c;
-	memcpy(&state->config,config,sizeof(struct dib3000_config));
-
-	/* check for the correct demod */
-	if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
-		goto error;
-
-	if (rd(DIB3000_REG_DEVICE_ID) != DIB3000MB_DEVICE_ID)
-		goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-
-	/* set the xfer operations */
-	xfer_ops->pid_parse = dib3000mb_pid_parse;
-	xfer_ops->fifo_ctrl = dib3000mb_fifo_control;
-	xfer_ops->pid_ctrl = dib3000mb_pid_control;
-	xfer_ops->tuner_pass_ctrl = dib3000mb_tuner_pass_ctrl;
-
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops dib3000mb_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name			= "DiBcom 3000M-B DVB-T",
-		.frequency_min		= 44250000,
-		.frequency_max		= 867250000,
-		.frequency_stepsize	= 62500,
-		.caps = FE_CAN_INVERSION_AUTO |
-				FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-				FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-				FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-				FE_CAN_TRANSMISSION_MODE_AUTO |
-				FE_CAN_GUARD_INTERVAL_AUTO |
-				FE_CAN_RECOVER |
-				FE_CAN_HIERARCHY_AUTO,
-	},
-
-	.release = dib3000mb_release,
-
-	.init = dib3000mb_fe_init_nonmobile,
-	.sleep = dib3000mb_sleep,
-
-	.set_frontend = dib3000mb_set_frontend_and_tuner,
-	.get_frontend = dib3000mb_get_frontend,
-	.get_tune_settings = dib3000mb_fe_get_tune_settings,
-
-	.read_status = dib3000mb_read_status,
-	.read_ber = dib3000mb_read_ber,
-	.read_signal_strength = dib3000mb_read_signal_strength,
-	.read_snr = dib3000mb_read_snr,
-	.read_ucblocks = dib3000mb_read_unc_blocks,
-};
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(dib3000mb_attach);
diff --git a/drivers/media/dvb/frontends/dib3000mb_priv.h b/drivers/media/dvb/frontends/dib3000mb_priv.h
deleted file mode 100644
index 9dc235a..0000000
--- a/drivers/media/dvb/frontends/dib3000mb_priv.h
+++ /dev/null
@@ -1,556 +0,0 @@
-/*
- * dib3000mb_priv.h
- *
- * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License as
- *	published by the Free Software Foundation, version 2.
- *
- * for more information see dib3000mb.c .
- */
-
-#ifndef __DIB3000MB_PRIV_H_INCLUDED__
-#define __DIB3000MB_PRIV_H_INCLUDED__
-
-/* info and err, taken from usb.h, if there is anything available like by default. */
-#define err(format, arg...)  printk(KERN_ERR     "dib3000: " format "\n" , ## arg)
-#define info(format, arg...) printk(KERN_INFO    "dib3000: " format "\n" , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "dib3000: " format "\n" , ## arg)
-
-/* handy shortcuts */
-#define rd(reg) dib3000_read_reg(state,reg)
-
-#define wr(reg,val) if (dib3000_write_reg(state,reg,val)) \
-	{ err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; }
-
-#define wr_foreach(a,v) { int i; \
-	if (sizeof(a) != sizeof(v)) \
-		err("sizeof: %zu %zu is different",sizeof(a),sizeof(v));\
-	for (i=0; i < sizeof(a)/sizeof(u16); i++) \
-		wr(a[i],v[i]); \
-	}
-
-#define set_or(reg,val) wr(reg,rd(reg) | val)
-
-#define set_and(reg,val) wr(reg,rd(reg) & val)
-
-/* debug */
-
-#define dprintk(level,args...) \
-    do { if ((debug & level)) { printk(args); } } while (0)
-
-/* mask for enabling a specific pid for the pid_filter */
-#define DIB3000_ACTIVATE_PID_FILTERING	(0x2000)
-
-/* common values for tuning */
-#define DIB3000_ALPHA_0					(     0)
-#define DIB3000_ALPHA_1					(     1)
-#define DIB3000_ALPHA_2					(     2)
-#define DIB3000_ALPHA_4					(     4)
-
-#define DIB3000_CONSTELLATION_QPSK		(     0)
-#define DIB3000_CONSTELLATION_16QAM		(     1)
-#define DIB3000_CONSTELLATION_64QAM		(     2)
-
-#define DIB3000_GUARD_TIME_1_32			(     0)
-#define DIB3000_GUARD_TIME_1_16			(     1)
-#define DIB3000_GUARD_TIME_1_8			(     2)
-#define DIB3000_GUARD_TIME_1_4			(     3)
-
-#define DIB3000_TRANSMISSION_MODE_2K	(     0)
-#define DIB3000_TRANSMISSION_MODE_8K	(     1)
-
-#define DIB3000_SELECT_LP				(     0)
-#define DIB3000_SELECT_HP				(     1)
-
-#define DIB3000_FEC_1_2					(     1)
-#define DIB3000_FEC_2_3					(     2)
-#define DIB3000_FEC_3_4					(     3)
-#define DIB3000_FEC_5_6					(     5)
-#define DIB3000_FEC_7_8					(     7)
-
-#define DIB3000_HRCH_OFF				(     0)
-#define DIB3000_HRCH_ON					(     1)
-
-#define DIB3000_DDS_INVERSION_OFF		(     0)
-#define DIB3000_DDS_INVERSION_ON		(     1)
-
-#define DIB3000_TUNER_WRITE_ENABLE(a)	(0xffff & (a << 8))
-#define DIB3000_TUNER_WRITE_DISABLE(a)	(0xffff & ((a << 8) | (1 << 7)))
-
-#define DIB3000_REG_MANUFACTOR_ID		(  1025)
-#define DIB3000_I2C_ID_DIBCOM			(0x01b3)
-
-#define DIB3000_REG_DEVICE_ID			(  1026)
-#define DIB3000MB_DEVICE_ID				(0x3000)
-#define DIB3000MC_DEVICE_ID				(0x3001)
-#define DIB3000P_DEVICE_ID				(0x3002)
-
-/* frontend state */
-struct dib3000_state {
-	struct i2c_adapter* i2c;
-
-/* configuration settings */
-	struct dib3000_config config;
-
-	struct dvb_frontend frontend;
-	int timing_offset;
-	int timing_offset_comp_done;
-
-	u32 last_tuned_bw;
-	u32 last_tuned_freq;
-};
-
-/* register addresses and some of their default values */
-
-/* restart subsystems */
-#define DIB3000MB_REG_RESTART			(     0)
-
-#define DIB3000MB_RESTART_OFF			(     0)
-#define DIB3000MB_RESTART_AUTO_SEARCH		(1 << 1)
-#define DIB3000MB_RESTART_CTRL				(1 << 2)
-#define DIB3000MB_RESTART_AGC				(1 << 3)
-
-/* FFT size */
-#define DIB3000MB_REG_FFT				(     1)
-
-/* Guard time */
-#define DIB3000MB_REG_GUARD_TIME		(     2)
-
-/* QAM */
-#define DIB3000MB_REG_QAM				(     3)
-
-/* Alpha coefficient high priority Viterbi algorithm */
-#define DIB3000MB_REG_VIT_ALPHA			(     4)
-
-/* spectrum inversion */
-#define DIB3000MB_REG_DDS_INV			(     5)
-
-/* DDS frequency value (IF position) ad ? values don't match reg_3000mb.txt */
-#define DIB3000MB_REG_DDS_FREQ_MSB		(     6)
-#define DIB3000MB_REG_DDS_FREQ_LSB		(     7)
-#define DIB3000MB_DDS_FREQ_MSB				(   178)
-#define DIB3000MB_DDS_FREQ_LSB				(  8990)
-
-/* timing frequency (carrier spacing) */
-static u16 dib3000mb_reg_timing_freq[] = { 8,9 };
-static u16 dib3000mb_timing_freq[][2] = {
-	{ 126 , 48873 }, /* 6 MHz */
-	{ 147 , 57019 }, /* 7 MHz */
-	{ 168 , 65164 }, /* 8 MHz */
-};
-
-/* impulse noise parameter */
-/* 36 ??? */
-
-static u16 dib3000mb_reg_impulse_noise[] = { 10,11,12,15,36 };
-
-enum dib3000mb_impulse_noise_type {
-	DIB3000MB_IMPNOISE_OFF,
-	DIB3000MB_IMPNOISE_MOBILE,
-	DIB3000MB_IMPNOISE_FIXED,
-	DIB3000MB_IMPNOISE_DEFAULT
-};
-
-static u16 dib3000mb_impulse_noise_values[][5] = {
-	{ 0x0000, 0x0004, 0x0014, 0x01ff, 0x0399 }, /* off */
-	{ 0x0001, 0x0004, 0x0014, 0x01ff, 0x037b }, /* mobile */
-	{ 0x0001, 0x0004, 0x0020, 0x01bd, 0x0399 }, /* fixed */
-	{ 0x0000, 0x0002, 0x000a, 0x01ff, 0x0399 }, /* default */
-};
-
-/*
- * Dual Automatic-Gain-Control
- * - gains RF in tuner (AGC1)
- * - gains IF after filtering (AGC2)
- */
-
-/* also from 16 to 18 */
-static u16 dib3000mb_reg_agc_gain[] = {
-	19,20,21,22,23,24,25,26,27,28,29,30,31,32
-};
-
-static u16 dib3000mb_default_agc_gain[] =
-	{ 0x0001, 52429,   623, 128, 166, 195, 61,   /* RF ??? */
-	  0x0001, 53766, 38011,   0,  90,  33, 23 }; /* IF ??? */
-
-/* phase noise */
-/* 36 is set when setting the impulse noise */
-static u16 dib3000mb_reg_phase_noise[] = { 33,34,35,37,38 };
-
-static u16 dib3000mb_default_noise_phase[] = { 2, 544, 0, 5, 4 };
-
-/* lock duration */
-static u16 dib3000mb_reg_lock_duration[] = { 39,40 };
-static u16 dib3000mb_default_lock_duration[] = { 135, 135 };
-
-/* AGC loop bandwidth */
-static u16 dib3000mb_reg_agc_bandwidth[] = { 43,44,45,46,47,48,49,50 };
-
-static u16 dib3000mb_agc_bandwidth_low[]  =
-	{ 2088, 10, 2088, 10, 3448, 5, 3448, 5 };
-static u16 dib3000mb_agc_bandwidth_high[] =
-	{ 2349,  5, 2349,  5, 2586, 2, 2586, 2 };
-
-/*
- * lock0 definition (coff_lock)
- */
-#define DIB3000MB_REG_LOCK0_MASK		(    51)
-#define DIB3000MB_LOCK0_DEFAULT				(     4)
-
-/*
- * lock1 definition (cpil_lock)
- * for auto search
- * which values hide behind the lock masks
- */
-#define DIB3000MB_REG_LOCK1_MASK		(    52)
-#define DIB3000MB_LOCK1_SEARCH_4			(0x0004)
-#define DIB3000MB_LOCK1_SEARCH_2048			(0x0800)
-#define DIB3000MB_LOCK1_DEFAULT				(0x0001)
-
-/*
- * lock2 definition (fec_lock) */
-#define DIB3000MB_REG_LOCK2_MASK		(    53)
-#define DIB3000MB_LOCK2_DEFAULT				(0x0080)
-
-/*
- * SEQ ? what was that again ... :)
- * changes when, inversion, guard time and fft is
- * either automatically detected or not
- */
-#define DIB3000MB_REG_SEQ				(    54)
-
-/* bandwidth */
-static u16 dib3000mb_reg_bandwidth[] = { 55,56,57,58,59,60,61,62,63,64,65,66,67 };
-static u16 dib3000mb_bandwidth_6mhz[] =
-	{ 0, 33, 53312, 112, 46635, 563, 36565, 0, 1000, 0, 1010, 1, 45264 };
-
-static u16 dib3000mb_bandwidth_7mhz[] =
-	{ 0, 28, 64421,  96, 39973, 483,  3255, 0, 1000, 0, 1010, 1, 45264 };
-
-static u16 dib3000mb_bandwidth_8mhz[] =
-	{ 0, 25, 23600,  84, 34976, 422, 43808, 0, 1000, 0, 1010, 1, 45264 };
-
-#define DIB3000MB_REG_UNK_68				(    68)
-#define DIB3000MB_UNK_68						(     0)
-
-#define DIB3000MB_REG_UNK_69				(    69)
-#define DIB3000MB_UNK_69						(     0)
-
-#define DIB3000MB_REG_UNK_71				(    71)
-#define DIB3000MB_UNK_71						(     0)
-
-#define DIB3000MB_REG_UNK_77				(    77)
-#define DIB3000MB_UNK_77						(     6)
-
-#define DIB3000MB_REG_UNK_78				(    78)
-#define DIB3000MB_UNK_78						(0x0080)
-
-/* isi */
-#define DIB3000MB_REG_ISI				(    79)
-#define DIB3000MB_ISI_ACTIVATE				(     0)
-#define DIB3000MB_ISI_INHIBIT				(     1)
-
-/* sync impovement */
-#define DIB3000MB_REG_SYNC_IMPROVEMENT	(    84)
-#define DIB3000MB_SYNC_IMPROVE_2K_1_8		(     3)
-#define DIB3000MB_SYNC_IMPROVE_DEFAULT		(     0)
-
-/* phase noise compensation inhibition */
-#define DIB3000MB_REG_PHASE_NOISE		(    87)
-#define DIB3000MB_PHASE_NOISE_DEFAULT	(     0)
-
-#define DIB3000MB_REG_UNK_92				(    92)
-#define DIB3000MB_UNK_92						(0x0080)
-
-#define DIB3000MB_REG_UNK_96				(    96)
-#define DIB3000MB_UNK_96						(0x0010)
-
-#define DIB3000MB_REG_UNK_97				(    97)
-#define DIB3000MB_UNK_97						(0x0009)
-
-/* mobile mode ??? */
-#define DIB3000MB_REG_MOBILE_MODE		(   101)
-#define DIB3000MB_MOBILE_MODE_ON			(     1)
-#define DIB3000MB_MOBILE_MODE_OFF			(     0)
-
-#define DIB3000MB_REG_UNK_106			(   106)
-#define DIB3000MB_UNK_106					(0x0080)
-
-#define DIB3000MB_REG_UNK_107			(   107)
-#define DIB3000MB_UNK_107					(0x0080)
-
-#define DIB3000MB_REG_UNK_108			(   108)
-#define DIB3000MB_UNK_108					(0x0080)
-
-/* fft */
-#define DIB3000MB_REG_UNK_121			(   121)
-#define DIB3000MB_UNK_121_2K				(     7)
-#define DIB3000MB_UNK_121_DEFAULT			(     5)
-
-#define DIB3000MB_REG_UNK_122			(   122)
-#define DIB3000MB_UNK_122					(  2867)
-
-/* QAM for mobile mode */
-#define DIB3000MB_REG_MOBILE_MODE_QAM	(   126)
-#define DIB3000MB_MOBILE_MODE_QAM_64		(     3)
-#define DIB3000MB_MOBILE_MODE_QAM_QPSK_16	(     1)
-#define DIB3000MB_MOBILE_MODE_QAM_OFF		(     0)
-
-/*
- * data diversity when having more than one chip on-board
- * see also DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY
- */
-#define DIB3000MB_REG_DATA_IN_DIVERSITY		(   127)
-#define DIB3000MB_DATA_DIVERSITY_IN_OFF			(     0)
-#define DIB3000MB_DATA_DIVERSITY_IN_ON			(     2)
-
-/* vit hrch */
-#define DIB3000MB_REG_VIT_HRCH			(   128)
-
-/* vit code rate */
-#define DIB3000MB_REG_VIT_CODE_RATE		(   129)
-
-/* vit select hp */
-#define DIB3000MB_REG_VIT_HP			(   130)
-
-/* time frame for Bit-Error-Rate calculation */
-#define DIB3000MB_REG_BERLEN			(   135)
-#define DIB3000MB_BERLEN_LONG				(     0)
-#define DIB3000MB_BERLEN_DEFAULT			(     1)
-#define DIB3000MB_BERLEN_MEDIUM				(     2)
-#define DIB3000MB_BERLEN_SHORT				(     3)
-
-/* 142 - 152 FIFO parameters
- * which is what ?
- */
-
-#define DIB3000MB_REG_FIFO_142			(   142)
-#define DIB3000MB_FIFO_142					(     0)
-
-/* MPEG2 TS output mode */
-#define DIB3000MB_REG_MPEG2_OUT_MODE	(   143)
-#define DIB3000MB_MPEG2_OUT_MODE_204		(     0)
-#define DIB3000MB_MPEG2_OUT_MODE_188		(     1)
-
-#define DIB3000MB_REG_PID_PARSE			(   144)
-#define DIB3000MB_PID_PARSE_INHIBIT		(     0)
-#define DIB3000MB_PID_PARSE_ACTIVATE	(     1)
-
-#define DIB3000MB_REG_FIFO				(   145)
-#define DIB3000MB_FIFO_INHIBIT				(     1)
-#define DIB3000MB_FIFO_ACTIVATE				(     0)
-
-#define DIB3000MB_REG_FIFO_146			(   146)
-#define DIB3000MB_FIFO_146					(     3)
-
-#define DIB3000MB_REG_FIFO_147			(   147)
-#define DIB3000MB_FIFO_147					(0x0100)
-
-/*
- * pidfilter
- * it is not a hardware pidfilter but a filter which drops all pids
- * except the ones set. Necessary because of the limited USB1.1 bandwidth.
- * regs 153-168
- */
-
-#define DIB3000MB_REG_FIRST_PID			(   153)
-#define DIB3000MB_NUM_PIDS				(    16)
-
-/*
- * output mode
- * USB devices have to use 'slave'-mode
- * see also DIB3000MB_REG_ELECT_OUT_MODE
- */
-#define DIB3000MB_REG_OUTPUT_MODE		(   169)
-#define DIB3000MB_OUTPUT_MODE_GATED_CLK		(     0)
-#define DIB3000MB_OUTPUT_MODE_CONT_CLK		(     1)
-#define DIB3000MB_OUTPUT_MODE_SERIAL		(     2)
-#define DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY	(     5)
-#define DIB3000MB_OUTPUT_MODE_SLAVE			(     6)
-
-/* irq event mask */
-#define DIB3000MB_REG_IRQ_EVENT_MASK		(   170)
-#define DIB3000MB_IRQ_EVENT_MASK				(     0)
-
-/* filter coefficients */
-static u16 dib3000mb_reg_filter_coeffs[] = {
-	171, 172, 173, 174, 175, 176, 177, 178,
-	179, 180, 181, 182, 183, 184, 185, 186,
-	188, 189, 190, 191, 192, 194
-};
-
-static u16 dib3000mb_filter_coeffs[] = {
-	 226,  160,   29,
-	 979,  998,   19,
-	  22, 1019, 1006,
-	1022,   12,    6,
-	1017, 1017,    3,
-	   6,       1019,
-	1021,    2,    3,
-	   1,          0,
-};
-
-/*
- * mobile algorithm (when you are moving with your device)
- * but not faster than 90 km/h
- */
-#define DIB3000MB_REG_MOBILE_ALGO		(   195)
-#define DIB3000MB_MOBILE_ALGO_ON			(     0)
-#define DIB3000MB_MOBILE_ALGO_OFF			(     1)
-
-/* multiple demodulators algorithm */
-#define DIB3000MB_REG_MULTI_DEMOD_MSB	(   206)
-#define DIB3000MB_REG_MULTI_DEMOD_LSB	(   207)
-
-/* terminator, no more demods */
-#define DIB3000MB_MULTI_DEMOD_MSB			( 32767)
-#define DIB3000MB_MULTI_DEMOD_LSB			(  4095)
-
-/* bring the device into a known  */
-#define DIB3000MB_REG_RESET_DEVICE		(  1024)
-#define DIB3000MB_RESET_DEVICE				(0x812c)
-#define DIB3000MB_RESET_DEVICE_RST			(     0)
-
-/* hardware clock configuration */
-#define DIB3000MB_REG_CLOCK				(  1027)
-#define DIB3000MB_CLOCK_DEFAULT				(0x9000)
-#define DIB3000MB_CLOCK_DIVERSITY			(0x92b0)
-
-/* power down config */
-#define DIB3000MB_REG_POWER_CONTROL		(  1028)
-#define DIB3000MB_POWER_DOWN				(     1)
-#define DIB3000MB_POWER_UP					(     0)
-
-/* electrical output mode */
-#define DIB3000MB_REG_ELECT_OUT_MODE	(  1029)
-#define DIB3000MB_ELECT_OUT_MODE_OFF		(     0)
-#define DIB3000MB_ELECT_OUT_MODE_ON			(     1)
-
-/* set the tuner i2c address */
-#define DIB3000MB_REG_TUNER				(  1089)
-
-/* monitoring registers (read only) */
-
-/* agc loop locked (size: 1) */
-#define DIB3000MB_REG_AGC_LOCK			(   324)
-
-/* agc power (size: 16) */
-#define DIB3000MB_REG_AGC_POWER			(   325)
-
-/* agc1 value (16) */
-#define DIB3000MB_REG_AGC1_VALUE		(   326)
-
-/* agc2 value (16) */
-#define DIB3000MB_REG_AGC2_VALUE		(   327)
-
-/* total RF power (16), can be used for signal strength */
-#define DIB3000MB_REG_RF_POWER			(   328)
-
-/* dds_frequency with offset (24) */
-#define DIB3000MB_REG_DDS_VALUE_MSB		(   339)
-#define DIB3000MB_REG_DDS_VALUE_LSB		(   340)
-
-/* timing offset signed (24) */
-#define DIB3000MB_REG_TIMING_OFFSET_MSB	(   341)
-#define DIB3000MB_REG_TIMING_OFFSET_LSB	(   342)
-
-/* fft start position (13) */
-#define DIB3000MB_REG_FFT_WINDOW_POS	(   353)
-
-/* carriers locked (1) */
-#define DIB3000MB_REG_CARRIER_LOCK		(   355)
-
-/* noise power (24) */
-#define DIB3000MB_REG_NOISE_POWER_MSB	(   372)
-#define DIB3000MB_REG_NOISE_POWER_LSB	(   373)
-
-#define DIB3000MB_REG_MOBILE_NOISE_MSB	(   374)
-#define DIB3000MB_REG_MOBILE_NOISE_LSB	(   375)
-
-/*
- * signal power (16), this and the above can be
- * used to calculate the signal/noise - ratio
- */
-#define DIB3000MB_REG_SIGNAL_POWER		(   380)
-
-/* mer (24) */
-#define DIB3000MB_REG_MER_MSB			(   381)
-#define DIB3000MB_REG_MER_LSB			(   382)
-
-/*
- * Transmission Parameter Signalling (TPS)
- * the following registers can be used to get TPS-information.
- * The values are according to the DVB-T standard.
- */
-
-/* TPS locked (1) */
-#define DIB3000MB_REG_TPS_LOCK			(   394)
-
-/* QAM from TPS (2) (values according to DIB3000MB_REG_QAM) */
-#define DIB3000MB_REG_TPS_QAM			(   398)
-
-/* hierarchy from TPS (1) */
-#define DIB3000MB_REG_TPS_HRCH			(   399)
-
-/* alpha from TPS (3) (values according to DIB3000MB_REG_VIT_ALPHA) */
-#define DIB3000MB_REG_TPS_VIT_ALPHA		(   400)
-
-/* code rate high priority from TPS (3) (values according to DIB3000MB_FEC_*) */
-#define DIB3000MB_REG_TPS_CODE_RATE_HP	(   401)
-
-/* code rate low priority from TPS (3) if DIB3000MB_REG_TPS_VIT_ALPHA */
-#define DIB3000MB_REG_TPS_CODE_RATE_LP	(   402)
-
-/* guard time from TPS (2) (values according to DIB3000MB_REG_GUARD_TIME */
-#define DIB3000MB_REG_TPS_GUARD_TIME	(   403)
-
-/* fft size from TPS (2) (values according to DIB3000MB_REG_FFT) */
-#define DIB3000MB_REG_TPS_FFT			(   404)
-
-/* cell id from TPS (16) */
-#define DIB3000MB_REG_TPS_CELL_ID		(   406)
-
-/* TPS (68) */
-#define DIB3000MB_REG_TPS_1				(   408)
-#define DIB3000MB_REG_TPS_2				(   409)
-#define DIB3000MB_REG_TPS_3				(   410)
-#define DIB3000MB_REG_TPS_4				(   411)
-#define DIB3000MB_REG_TPS_5				(   412)
-
-/* bit error rate (before RS correction) (21) */
-#define DIB3000MB_REG_BER_MSB			(   414)
-#define DIB3000MB_REG_BER_LSB			(   415)
-
-/* packet error rate (uncorrected TS packets) (16) */
-#define DIB3000MB_REG_PACKET_ERROR_RATE	(   417)
-
-/* uncorrected packet count (16) */
-#define DIB3000MB_REG_UNC				(   420)
-
-/* viterbi locked (1) */
-#define DIB3000MB_REG_VIT_LCK			(   421)
-
-/* viterbi inidcator (16) */
-#define DIB3000MB_REG_VIT_INDICATOR		(   422)
-
-/* transport stream sync lock (1) */
-#define DIB3000MB_REG_TS_SYNC_LOCK		(   423)
-
-/* transport stream RS lock (1) */
-#define DIB3000MB_REG_TS_RS_LOCK		(   424)
-
-/* lock mask 0 value (1) */
-#define DIB3000MB_REG_LOCK0_VALUE		(   425)
-
-/* lock mask 1 value (1) */
-#define DIB3000MB_REG_LOCK1_VALUE		(   426)
-
-/* lock mask 2 value (1) */
-#define DIB3000MB_REG_LOCK2_VALUE		(   427)
-
-/* interrupt pending for auto search */
-#define DIB3000MB_REG_AS_IRQ_PENDING	(   434)
-
-#endif
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
deleted file mode 100644
index ffad181..0000000
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ /dev/null
@@ -1,940 +0,0 @@
-/*
- * Driver for DiBcom DiB3000MC/P-demodulator.
- *
- * Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/)
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * This code is partially based on the previous dib3000mc.c .
- *
- * 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, version 2.
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-
-#include "dvb_frontend.h"
-
-#include "dib3000mc.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
-
-static int buggy_sfn_workaround;
-module_param(buggy_sfn_workaround, int, 0644);
-MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
-
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0)
-
-struct dib3000mc_state {
-	struct dvb_frontend demod;
-	struct dib3000mc_config *cfg;
-
-	u8 i2c_addr;
-	struct i2c_adapter *i2c_adap;
-
-	struct dibx000_i2c_master i2c_master;
-
-	u32 timf;
-
-	u32 current_bandwidth;
-
-	u16 dev_id;
-
-	u8 sfn_workaround_active :1;
-};
-
-static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg)
-{
-	u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff };
-	u8 rb[2];
-	struct i2c_msg msg[2] = {
-		{ .addr = state->i2c_addr >> 1, .flags = 0,        .buf = wb, .len = 2 },
-		{ .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
-	};
-
-	if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
-		dprintk("i2c read error on %d\n",reg);
-
-	return (rb[0] << 8) | rb[1];
-}
-
-static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val)
-{
-	u8 b[4] = {
-		(reg >> 8) & 0xff, reg & 0xff,
-		(val >> 8) & 0xff, val & 0xff,
-	};
-	struct i2c_msg msg = {
-		.addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
-	};
-	return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
-}
-
-static int dib3000mc_identify(struct dib3000mc_state *state)
-{
-	u16 value;
-	if ((value = dib3000mc_read_word(state, 1025)) != 0x01b3) {
-		dprintk("-E-  DiB3000MC/P: wrong Vendor ID (read=0x%x)\n",value);
-		return -EREMOTEIO;
-	}
-
-	value = dib3000mc_read_word(state, 1026);
-	if (value != 0x3001 && value != 0x3002) {
-		dprintk("-E-  DiB3000MC/P: wrong Device ID (%x)\n",value);
-		return -EREMOTEIO;
-	}
-	state->dev_id = value;
-
-	dprintk("-I-  found DiB3000MC/P: %x\n",state->dev_id);
-
-	return 0;
-}
-
-static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset)
-{
-	u32 timf;
-
-	if (state->timf == 0) {
-		timf = 1384402; // default value for 8MHz
-		if (update_offset)
-			msleep(200); // first time we do an update
-	} else
-		timf = state->timf;
-
-	timf *= (bw / 1000);
-
-	if (update_offset) {
-		s16 tim_offs = dib3000mc_read_word(state, 416);
-
-		if (tim_offs &  0x2000)
-			tim_offs -= 0x4000;
-
-		if (nfft == TRANSMISSION_MODE_2K)
-			tim_offs *= 4;
-
-		timf += tim_offs;
-		state->timf = timf / (bw / 1000);
-	}
-
-	dprintk("timf: %d\n", timf);
-
-	dib3000mc_write_word(state, 23, (u16) (timf >> 16));
-	dib3000mc_write_word(state, 24, (u16) (timf      ) & 0xffff);
-
-	return 0;
-}
-
-static int dib3000mc_setup_pwm_state(struct dib3000mc_state *state)
-{
-	u16 reg_51, reg_52 = state->cfg->agc->setup & 0xfefb;
-    if (state->cfg->pwm3_inversion) {
-		reg_51 =  (2 << 14) | (0 << 10) | (7 << 6) | (2 << 2) | (2 << 0);
-		reg_52 |= (1 << 2);
-	} else {
-		reg_51 = (2 << 14) | (4 << 10) | (7 << 6) | (2 << 2) | (2 << 0);
-		reg_52 |= (1 << 8);
-	}
-	dib3000mc_write_word(state, 51, reg_51);
-	dib3000mc_write_word(state, 52, reg_52);
-
-    if (state->cfg->use_pwm3)
-		dib3000mc_write_word(state, 245, (1 << 3) | (1 << 0));
-	else
-		dib3000mc_write_word(state, 245, 0);
-
-    dib3000mc_write_word(state, 1040, 0x3);
-	return 0;
-}
-
-static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode)
-{
-	int    ret = 0;
-	u16 fifo_threshold = 1792;
-	u16 outreg = 0;
-	u16 outmode = 0;
-	u16 elecout = 1;
-	u16 smo_reg = dib3000mc_read_word(state, 206) & 0x0010; /* keep the pid_parse bit */
-
-	dprintk("-I-  Setting output mode for demod %p to %d\n",
-			&state->demod, mode);
-
-	switch (mode) {
-		case OUTMODE_HIGH_Z:  // disable
-			elecout = 0;
-			break;
-		case OUTMODE_MPEG2_PAR_GATED_CLK:   // STBs with parallel gated clock
-			outmode = 0;
-			break;
-		case OUTMODE_MPEG2_PAR_CONT_CLK:    // STBs with parallel continues clock
-			outmode = 1;
-			break;
-		case OUTMODE_MPEG2_SERIAL:          // STBs with serial input
-			outmode = 2;
-			break;
-		case OUTMODE_MPEG2_FIFO:            // e.g. USB feeding
-			elecout = 3;
-			/*ADDR @ 206 :
-			P_smo_error_discard  [1;6:6] = 0
-			P_smo_rs_discard     [1;5:5] = 0
-			P_smo_pid_parse      [1;4:4] = 0
-			P_smo_fifo_flush     [1;3:3] = 0
-			P_smo_mode           [2;2:1] = 11
-			P_smo_ovf_prot       [1;0:0] = 0
-			*/
-			smo_reg |= 3 << 1;
-			fifo_threshold = 512;
-			outmode = 5;
-			break;
-		case OUTMODE_DIVERSITY:
-			outmode = 4;
-			elecout = 1;
-			break;
-		default:
-			dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
-			outmode = 0;
-			break;
-	}
-
-	if ((state->cfg->output_mpeg2_in_188_bytes))
-		smo_reg |= (1 << 5); // P_smo_rs_discard     [1;5:5] = 1
-
-	outreg = dib3000mc_read_word(state, 244) & 0x07FF;
-	outreg |= (outmode << 11);
-	ret |= dib3000mc_write_word(state,  244, outreg);
-	ret |= dib3000mc_write_word(state,  206, smo_reg);   /*smo_ mode*/
-	ret |= dib3000mc_write_word(state,  207, fifo_threshold); /* synchronous fread */
-	ret |= dib3000mc_write_word(state, 1040, elecout);         /* P_out_cfg */
-	return ret;
-}
-
-static int dib3000mc_set_bandwidth(struct dib3000mc_state *state, u32 bw)
-{
-	u16 bw_cfg[6] = { 0 };
-	u16 imp_bw_cfg[3] = { 0 };
-	u16 reg;
-
-/* settings here are for 27.7MHz */
-	switch (bw) {
-		case 8000:
-			bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20;
-			imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7;
-			break;
-
-		case 7000:
-			bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7;
-			imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0;
-			break;
-
-		case 6000:
-			bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5;
-			imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089;
-			break;
-
-		case 5000:
-			bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500;
-			imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072;
-			break;
-
-		default: return -EINVAL;
-	}
-
-	for (reg = 6; reg < 12; reg++)
-		dib3000mc_write_word(state, reg, bw_cfg[reg - 6]);
-	dib3000mc_write_word(state, 12, 0x0000);
-	dib3000mc_write_word(state, 13, 0x03e8);
-	dib3000mc_write_word(state, 14, 0x0000);
-	dib3000mc_write_word(state, 15, 0x03f2);
-	dib3000mc_write_word(state, 16, 0x0001);
-	dib3000mc_write_word(state, 17, 0xb0d0);
-	// P_sec_len
-	dib3000mc_write_word(state, 18, 0x0393);
-	dib3000mc_write_word(state, 19, 0x8700);
-
-	for (reg = 55; reg < 58; reg++)
-		dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]);
-
-	// Timing configuration
-	dib3000mc_set_timing(state, TRANSMISSION_MODE_2K, bw, 0);
-
-	return 0;
-}
-
-static u16 impulse_noise_val[29] =
-
-{
-	0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c, 0x3ffe, 0x7f3,
-	0x2d94, 0x76, 0x53d, 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3, 0x3feb, 0x7d2,
-	0x365e, 0x76, 0x48c, 0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0000, 0xd
-};
-
-static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, s16 nfft)
-{
-	u16 i;
-	for (i = 58; i < 87; i++)
-		dib3000mc_write_word(state, i, impulse_noise_val[i-58]);
-
-	if (nfft == TRANSMISSION_MODE_8K) {
-		dib3000mc_write_word(state, 58, 0x3b);
-		dib3000mc_write_word(state, 84, 0x00);
-		dib3000mc_write_word(state, 85, 0x8200);
-	}
-
-	dib3000mc_write_word(state, 34, 0x1294);
-	dib3000mc_write_word(state, 35, 0x1ff8);
-	if (mode == 1)
-		dib3000mc_write_word(state, 55, dib3000mc_read_word(state, 55) | (1 << 10));
-}
-
-static int dib3000mc_init(struct dvb_frontend *demod)
-{
-	struct dib3000mc_state *state = demod->demodulator_priv;
-	struct dibx000_agc_config *agc = state->cfg->agc;
-
-	// Restart Configuration
-	dib3000mc_write_word(state, 1027, 0x8000);
-	dib3000mc_write_word(state, 1027, 0x0000);
-
-	// power up the demod + mobility configuration
-	dib3000mc_write_word(state, 140, 0x0000);
-	dib3000mc_write_word(state, 1031, 0);
-
-	if (state->cfg->mobile_mode) {
-		dib3000mc_write_word(state, 139,  0x0000);
-		dib3000mc_write_word(state, 141,  0x0000);
-		dib3000mc_write_word(state, 175,  0x0002);
-		dib3000mc_write_word(state, 1032, 0x0000);
-	} else {
-		dib3000mc_write_word(state, 139,  0x0001);
-		dib3000mc_write_word(state, 141,  0x0000);
-		dib3000mc_write_word(state, 175,  0x0000);
-		dib3000mc_write_word(state, 1032, 0x012C);
-	}
-	dib3000mc_write_word(state, 1033, 0x0000);
-
-	// P_clk_cfg
-	dib3000mc_write_word(state, 1037, 0x3130);
-
-	// other configurations
-
-	// P_ctrl_sfreq
-	dib3000mc_write_word(state, 33, (5 << 0));
-	dib3000mc_write_word(state, 88, (1 << 10) | (0x10 << 0));
-
-	// Phase noise control
-	// P_fft_phacor_inh, P_fft_phacor_cpe, P_fft_powrange
-	dib3000mc_write_word(state, 99, (1 << 9) | (0x20 << 0));
-
-	if (state->cfg->phase_noise_mode == 0)
-		dib3000mc_write_word(state, 111, 0x00);
-	else
-		dib3000mc_write_word(state, 111, 0x02);
-
-	// P_agc_global
-	dib3000mc_write_word(state, 50, 0x8000);
-
-	// agc setup misc
-	dib3000mc_setup_pwm_state(state);
-
-	// P_agc_counter_lock
-	dib3000mc_write_word(state, 53, 0x87);
-	// P_agc_counter_unlock
-	dib3000mc_write_word(state, 54, 0x87);
-
-	/* agc */
-	dib3000mc_write_word(state, 36, state->cfg->max_time);
-	dib3000mc_write_word(state, 37, (state->cfg->agc_command1 << 13) | (state->cfg->agc_command2 << 12) | (0x1d << 0));
-	dib3000mc_write_word(state, 38, state->cfg->pwm3_value);
-	dib3000mc_write_word(state, 39, state->cfg->ln_adc_level);
-
-	// set_agc_loop_Bw
-	dib3000mc_write_word(state, 40, 0x0179);
-	dib3000mc_write_word(state, 41, 0x03f0);
-
-	dib3000mc_write_word(state, 42, agc->agc1_max);
-	dib3000mc_write_word(state, 43, agc->agc1_min);
-	dib3000mc_write_word(state, 44, agc->agc2_max);
-	dib3000mc_write_word(state, 45, agc->agc2_min);
-	dib3000mc_write_word(state, 46, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
-	dib3000mc_write_word(state, 47, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
-	dib3000mc_write_word(state, 48, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
-	dib3000mc_write_word(state, 49, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
-
-// Begin: TimeOut registers
-	// P_pha3_thres
-	dib3000mc_write_word(state, 110, 3277);
-	// P_timf_alpha = 6, P_corm_alpha = 6, P_corm_thres = 0x80
-	dib3000mc_write_word(state,  26, 0x6680);
-	// lock_mask0
-	dib3000mc_write_word(state, 1, 4);
-	// lock_mask1
-	dib3000mc_write_word(state, 2, 4);
-	// lock_mask2
-	dib3000mc_write_word(state, 3, 0x1000);
-	// P_search_maxtrial=1
-	dib3000mc_write_word(state, 5, 1);
-
-	dib3000mc_set_bandwidth(state, 8000);
-
-	// div_lock_mask
-	dib3000mc_write_word(state,  4, 0x814);
-
-	dib3000mc_write_word(state, 21, (1 << 9) | 0x164);
-	dib3000mc_write_word(state, 22, 0x463d);
-
-	// Spurious rm cfg
-	// P_cspu_regul, P_cspu_win_cut
-	dib3000mc_write_word(state, 120, 0x200f);
-	// P_adp_selec_monit
-	dib3000mc_write_word(state, 134, 0);
-
-	// Fec cfg
-	dib3000mc_write_word(state, 195, 0x10);
-
-	// diversity register: P_dvsy_sync_wait..
-	dib3000mc_write_word(state, 180, 0x2FF0);
-
-	// Impulse noise configuration
-	dib3000mc_set_impulse_noise(state, 0, TRANSMISSION_MODE_8K);
-
-	// output mode set-up
-	dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
-
-	/* close the i2c-gate */
-	dib3000mc_write_word(state, 769, (1 << 7) );
-
-	return 0;
-}
-
-static int dib3000mc_sleep(struct dvb_frontend *demod)
-{
-	struct dib3000mc_state *state = demod->demodulator_priv;
-
-	dib3000mc_write_word(state, 1031, 0xFFFF);
-	dib3000mc_write_word(state, 1032, 0xFFFF);
-	dib3000mc_write_word(state, 1033, 0xFFF0);
-
-    return 0;
-}
-
-static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
-{
-	u16 cfg[4] = { 0 },reg;
-	switch (qam) {
-		case QPSK:
-			cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0;
-			break;
-		case QAM_16:
-			cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0;
-			break;
-		case QAM_64:
-			cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8;
-			break;
-	}
-	for (reg = 129; reg < 133; reg++)
-		dib3000mc_write_word(state, reg, cfg[reg - 129]);
-}
-
-static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state,
-				      struct dtv_frontend_properties *ch, u16 seq)
-{
-	u16 value;
-	u32 bw = BANDWIDTH_TO_KHZ(ch->bandwidth_hz);
-
-	dib3000mc_set_bandwidth(state, bw);
-	dib3000mc_set_timing(state, ch->transmission_mode, bw, 0);
-
-//	if (boost)
-//		dib3000mc_write_word(state, 100, (11 << 6) + 6);
-//	else
-		dib3000mc_write_word(state, 100, (16 << 6) + 9);
-
-	dib3000mc_write_word(state, 1027, 0x0800);
-	dib3000mc_write_word(state, 1027, 0x0000);
-
-	//Default cfg isi offset adp
-	dib3000mc_write_word(state, 26,  0x6680);
-	dib3000mc_write_word(state, 29,  0x1273);
-	dib3000mc_write_word(state, 33,       5);
-	dib3000mc_set_adp_cfg(state, QAM_16);
-	dib3000mc_write_word(state, 133,  15564);
-
-	dib3000mc_write_word(state, 12 , 0x0);
-	dib3000mc_write_word(state, 13 , 0x3e8);
-	dib3000mc_write_word(state, 14 , 0x0);
-	dib3000mc_write_word(state, 15 , 0x3f2);
-
-	dib3000mc_write_word(state, 93,0);
-	dib3000mc_write_word(state, 94,0);
-	dib3000mc_write_word(state, 95,0);
-	dib3000mc_write_word(state, 96,0);
-	dib3000mc_write_word(state, 97,0);
-	dib3000mc_write_word(state, 98,0);
-
-	dib3000mc_set_impulse_noise(state, 0, ch->transmission_mode);
-
-	value = 0;
-	switch (ch->transmission_mode) {
-		case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
-		default:
-		case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
-	}
-	switch (ch->guard_interval) {
-		case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
-		case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
-		case GUARD_INTERVAL_1_4:  value |= (3 << 5); break;
-		default:
-		case GUARD_INTERVAL_1_8:  value |= (2 << 5); break;
-	}
-	switch (ch->modulation) {
-		case QPSK:  value |= (0 << 3); break;
-		case QAM_16: value |= (1 << 3); break;
-		default:
-		case QAM_64: value |= (2 << 3); break;
-	}
-	switch (HIERARCHY_1) {
-		case HIERARCHY_2: value |= 2; break;
-		case HIERARCHY_4: value |= 4; break;
-		default:
-		case HIERARCHY_1: value |= 1; break;
-	}
-	dib3000mc_write_word(state, 0, value);
-	dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4));
-
-	value = 0;
-	if (ch->hierarchy == 1)
-		value |= (1 << 4);
-	if (1 == 1)
-		value |= 1;
-	switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
-		case FEC_2_3: value |= (2 << 1); break;
-		case FEC_3_4: value |= (3 << 1); break;
-		case FEC_5_6: value |= (5 << 1); break;
-		case FEC_7_8: value |= (7 << 1); break;
-		default:
-		case FEC_1_2: value |= (1 << 1); break;
-	}
-	dib3000mc_write_word(state, 181, value);
-
-	// diversity synchro delay add 50% SFN margin
-	switch (ch->transmission_mode) {
-		case TRANSMISSION_MODE_8K: value = 256; break;
-		case TRANSMISSION_MODE_2K:
-		default: value = 64; break;
-	}
-	switch (ch->guard_interval) {
-		case GUARD_INTERVAL_1_16: value *= 2; break;
-		case GUARD_INTERVAL_1_8:  value *= 4; break;
-		case GUARD_INTERVAL_1_4:  value *= 8; break;
-		default:
-		case GUARD_INTERVAL_1_32: value *= 1; break;
-	}
-	value <<= 4;
-	value |= dib3000mc_read_word(state, 180) & 0x000f;
-	dib3000mc_write_word(state, 180, value);
-
-	// restart demod
-	value = dib3000mc_read_word(state, 0);
-	dib3000mc_write_word(state, 0, value | (1 << 9));
-	dib3000mc_write_word(state, 0, value);
-
-	msleep(30);
-
-	dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->transmission_mode);
-}
-
-static int dib3000mc_autosearch_start(struct dvb_frontend *demod)
-{
-	struct dtv_frontend_properties *chan = &demod->dtv_property_cache;
-	struct dib3000mc_state *state = demod->demodulator_priv;
-	u16 reg;
-//	u32 val;
-	struct dtv_frontend_properties schan;
-
-	schan = *chan;
-
-	/* TODO what is that ? */
-
-	/* a channel for autosearch */
-	schan.transmission_mode = TRANSMISSION_MODE_8K;
-	schan.guard_interval = GUARD_INTERVAL_1_32;
-	schan.modulation = QAM_64;
-	schan.code_rate_HP = FEC_2_3;
-	schan.code_rate_LP = FEC_2_3;
-	schan.hierarchy = 0;
-
-	dib3000mc_set_channel_cfg(state, &schan, 11);
-
-	reg = dib3000mc_read_word(state, 0);
-	dib3000mc_write_word(state, 0, reg | (1 << 8));
-	dib3000mc_read_word(state, 511);
-	dib3000mc_write_word(state, 0, reg);
-
-	return 0;
-}
-
-static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod)
-{
-	struct dib3000mc_state *state = demod->demodulator_priv;
-	u16 irq_pending = dib3000mc_read_word(state, 511);
-
-	if (irq_pending & 0x1) // failed
-		return 1;
-
-	if (irq_pending & 0x2) // succeeded
-		return 2;
-
-	return 0; // still pending
-}
-
-static int dib3000mc_tune(struct dvb_frontend *demod)
-{
-	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
-	struct dib3000mc_state *state = demod->demodulator_priv;
-
-	// ** configure demod **
-	dib3000mc_set_channel_cfg(state, ch, 0);
-
-	// activates isi
-	if (state->sfn_workaround_active) {
-		dprintk("SFN workaround is active\n");
-		dib3000mc_write_word(state, 29, 0x1273);
-		dib3000mc_write_word(state, 108, 0x4000); // P_pha3_force_pha_shift
-	} else {
-		dib3000mc_write_word(state, 29, 0x1073);
-		dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift
-	}
-
-	dib3000mc_set_adp_cfg(state, (u8)ch->modulation);
-	if (ch->transmission_mode == TRANSMISSION_MODE_8K) {
-		dib3000mc_write_word(state, 26, 38528);
-		dib3000mc_write_word(state, 33, 8);
-	} else {
-		dib3000mc_write_word(state, 26, 30336);
-		dib3000mc_write_word(state, 33, 6);
-	}
-
-	if (dib3000mc_read_word(state, 509) & 0x80)
-		dib3000mc_set_timing(state, ch->transmission_mode,
-				     BANDWIDTH_TO_KHZ(ch->bandwidth_hz), 1);
-
-	return 0;
-}
-
-struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating)
-{
-	struct dib3000mc_state *st = demod->demodulator_priv;
-	return dibx000_get_i2c_adapter(&st->i2c_master, DIBX000_I2C_INTERFACE_TUNER, gating);
-}
-
-EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master);
-
-static int dib3000mc_get_frontend(struct dvb_frontend* fe)
-{
-	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
-	struct dib3000mc_state *state = fe->demodulator_priv;
-	u16 tps = dib3000mc_read_word(state,458);
-
-	fep->inversion = INVERSION_AUTO;
-
-	fep->bandwidth_hz = state->current_bandwidth;
-
-	switch ((tps >> 8) & 0x1) {
-		case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break;
-		case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break;
-	}
-
-	switch (tps & 0x3) {
-		case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break;
-		case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break;
-		case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break;
-		case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break;
-	}
-
-	switch ((tps >> 13) & 0x3) {
-		case 0: fep->modulation = QPSK; break;
-		case 1: fep->modulation = QAM_16; break;
-		case 2:
-		default: fep->modulation = QAM_64; break;
-	}
-
-	/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
-	/* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */
-
-	fep->hierarchy = HIERARCHY_NONE;
-	switch ((tps >> 5) & 0x7) {
-		case 1: fep->code_rate_HP = FEC_1_2; break;
-		case 2: fep->code_rate_HP = FEC_2_3; break;
-		case 3: fep->code_rate_HP = FEC_3_4; break;
-		case 5: fep->code_rate_HP = FEC_5_6; break;
-		case 7:
-		default: fep->code_rate_HP = FEC_7_8; break;
-
-	}
-
-	switch ((tps >> 2) & 0x7) {
-		case 1: fep->code_rate_LP = FEC_1_2; break;
-		case 2: fep->code_rate_LP = FEC_2_3; break;
-		case 3: fep->code_rate_LP = FEC_3_4; break;
-		case 5: fep->code_rate_LP = FEC_5_6; break;
-		case 7:
-		default: fep->code_rate_LP = FEC_7_8; break;
-	}
-
-	return 0;
-}
-
-static int dib3000mc_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
-	struct dib3000mc_state *state = fe->demodulator_priv;
-	int ret;
-
-	dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
-
-	state->current_bandwidth = fep->bandwidth_hz;
-	dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz));
-
-	/* maybe the parameter has been changed */
-	state->sfn_workaround_active = buggy_sfn_workaround;
-
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		msleep(100);
-	}
-
-	if (fep->transmission_mode  == TRANSMISSION_MODE_AUTO ||
-	    fep->guard_interval == GUARD_INTERVAL_AUTO ||
-	    fep->modulation     == QAM_AUTO ||
-	    fep->code_rate_HP   == FEC_AUTO) {
-		int i = 1000, found;
-
-		dib3000mc_autosearch_start(fe);
-		do {
-			msleep(1);
-			found = dib3000mc_autosearch_is_irq(fe);
-		} while (found == 0 && i--);
-
-		dprintk("autosearch returns: %d\n",found);
-		if (found == 0 || found == 1)
-			return 0; // no channel found
-
-		dib3000mc_get_frontend(fe);
-	}
-
-	ret = dib3000mc_tune(fe);
-
-	/* make this a config parameter */
-	dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
-	return ret;
-}
-
-static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
-{
-	struct dib3000mc_state *state = fe->demodulator_priv;
-	u16 lock = dib3000mc_read_word(state, 509);
-
-	*stat = 0;
-
-	if (lock & 0x8000)
-		*stat |= FE_HAS_SIGNAL;
-	if (lock & 0x3000)
-		*stat |= FE_HAS_CARRIER;
-	if (lock & 0x0100)
-		*stat |= FE_HAS_VITERBI;
-	if (lock & 0x0010)
-		*stat |= FE_HAS_SYNC;
-	if (lock & 0x0008)
-		*stat |= FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int dib3000mc_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct dib3000mc_state *state = fe->demodulator_priv;
-	*ber = (dib3000mc_read_word(state, 500) << 16) | dib3000mc_read_word(state, 501);
-	return 0;
-}
-
-static int dib3000mc_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
-{
-	struct dib3000mc_state *state = fe->demodulator_priv;
-	*unc = dib3000mc_read_word(state, 508);
-	return 0;
-}
-
-static int dib3000mc_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct dib3000mc_state *state = fe->demodulator_priv;
-	u16 val = dib3000mc_read_word(state, 392);
-	*strength = 65535 - val;
-	return 0;
-}
-
-static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr)
-{
-	*snr = 0x0000;
-	return 0;
-}
-
-static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
-{
-	tune->min_delay_ms = 1000;
-	return 0;
-}
-
-static void dib3000mc_release(struct dvb_frontend *fe)
-{
-	struct dib3000mc_state *state = fe->demodulator_priv;
-	dibx000_exit_i2c_master(&state->i2c_master);
-	kfree(state);
-}
-
-int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff)
-{
-	struct dib3000mc_state *state = fe->demodulator_priv;
-	dib3000mc_write_word(state, 212 + index,  onoff ? (1 << 13) | pid : 0);
-	return 0;
-}
-EXPORT_SYMBOL(dib3000mc_pid_control);
-
-int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
-{
-	struct dib3000mc_state *state = fe->demodulator_priv;
-	u16 tmp = dib3000mc_read_word(state, 206) & ~(1 << 4);
-	tmp |= (onoff << 4);
-	return dib3000mc_write_word(state, 206, tmp);
-}
-EXPORT_SYMBOL(dib3000mc_pid_parse);
-
-void dib3000mc_set_config(struct dvb_frontend *fe, struct dib3000mc_config *cfg)
-{
-	struct dib3000mc_state *state = fe->demodulator_priv;
-	state->cfg = cfg;
-}
-EXPORT_SYMBOL(dib3000mc_set_config);
-
-int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib3000mc_config cfg[])
-{
-	struct dib3000mc_state *dmcst;
-	int k;
-	u8 new_addr;
-
-	static u8 DIB3000MC_I2C_ADDRESS[] = {20,22,24,26};
-
-	dmcst = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);
-	if (dmcst == NULL)
-		return -ENOMEM;
-
-	dmcst->i2c_adap = i2c;
-
-	for (k = no_of_demods-1; k >= 0; k--) {
-		dmcst->cfg = &cfg[k];
-
-		/* designated i2c address */
-		new_addr          = DIB3000MC_I2C_ADDRESS[k];
-		dmcst->i2c_addr = new_addr;
-		if (dib3000mc_identify(dmcst) != 0) {
-			dmcst->i2c_addr = default_addr;
-			if (dib3000mc_identify(dmcst) != 0) {
-				dprintk("-E-  DiB3000P/MC #%d: not identified\n", k);
-				kfree(dmcst);
-				return -ENODEV;
-			}
-		}
-
-		dib3000mc_set_output_mode(dmcst, OUTMODE_MPEG2_PAR_CONT_CLK);
-
-		// set new i2c address and force divstr (Bit 1) to value 0 (Bit 0)
-		dib3000mc_write_word(dmcst, 1024, (new_addr << 3) | 0x1);
-		dmcst->i2c_addr = new_addr;
-	}
-
-	for (k = 0; k < no_of_demods; k++) {
-		dmcst->cfg = &cfg[k];
-		dmcst->i2c_addr = DIB3000MC_I2C_ADDRESS[k];
-
-		dib3000mc_write_word(dmcst, 1024, dmcst->i2c_addr << 3);
-
-		/* turn off data output */
-		dib3000mc_set_output_mode(dmcst, OUTMODE_HIGH_Z);
-	}
-
-	kfree(dmcst);
-	return 0;
-}
-EXPORT_SYMBOL(dib3000mc_i2c_enumeration);
-
-static struct dvb_frontend_ops dib3000mc_ops;
-
-struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg)
-{
-	struct dvb_frontend *demod;
-	struct dib3000mc_state *st;
-	st = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);
-	if (st == NULL)
-		return NULL;
-
-	st->cfg = cfg;
-	st->i2c_adap = i2c_adap;
-	st->i2c_addr = i2c_addr;
-
-	demod                   = &st->demod;
-	demod->demodulator_priv = st;
-	memcpy(&st->demod.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
-
-	if (dib3000mc_identify(st) != 0)
-		goto error;
-
-	dibx000_init_i2c_master(&st->i2c_master, DIB3000MC, st->i2c_adap, st->i2c_addr);
-
-	dib3000mc_write_word(st, 1037, 0x3130);
-
-	return demod;
-
-error:
-	kfree(st);
-	return NULL;
-}
-EXPORT_SYMBOL(dib3000mc_attach);
-
-static struct dvb_frontend_ops dib3000mc_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name = "DiBcom 3000MC/P",
-		.frequency_min      = 44250000,
-		.frequency_max      = 867250000,
-		.frequency_stepsize = 62500,
-		.caps = FE_CAN_INVERSION_AUTO |
-			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_RECOVER |
-			FE_CAN_HIERARCHY_AUTO,
-	},
-
-	.release              = dib3000mc_release,
-
-	.init                 = dib3000mc_init,
-	.sleep                = dib3000mc_sleep,
-
-	.set_frontend         = dib3000mc_set_frontend,
-	.get_tune_settings    = dib3000mc_fe_get_tune_settings,
-	.get_frontend         = dib3000mc_get_frontend,
-
-	.read_status          = dib3000mc_read_status,
-	.read_ber             = dib3000mc_read_ber,
-	.read_signal_strength = dib3000mc_read_signal_strength,
-	.read_snr             = dib3000mc_read_snr,
-	.read_ucblocks        = dib3000mc_read_unc_blocks,
-};
-
-MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
-MODULE_DESCRIPTION("Driver for the DiBcom 3000MC/P COFDM demodulator");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dib3000mc.h b/drivers/media/dvb/frontends/dib3000mc.h
deleted file mode 100644
index d75ffad..0000000
--- a/drivers/media/dvb/frontends/dib3000mc.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Driver for DiBcom DiB3000MC/P-demodulator.
- *
- * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/)
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher\@desy.de)
- *
- * This code is partially based on the previous dib3000mc.c .
- *
- * 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, version 2.
- */
-#ifndef DIB3000MC_H
-#define DIB3000MC_H
-
-#include "dibx000_common.h"
-
-struct dib3000mc_config {
-	struct dibx000_agc_config *agc;
-
-	u8 phase_noise_mode;
-	u8 impulse_noise_mode;
-
-	u8  pwm3_inversion;
-	u8  use_pwm3;
-	u16 pwm3_value;
-
-	u16 max_time;
-	u16 ln_adc_level;
-
-	u8 agc_command1 :1;
-	u8 agc_command2 :1;
-
-	u8 mobile_mode;
-
-	u8 output_mpeg2_in_188_bytes;
-};
-
-#define DEFAULT_DIB3000MC_I2C_ADDRESS 16
-#define DEFAULT_DIB3000P_I2C_ADDRESS  24
-
-#if defined(CONFIG_DVB_DIB3000MC) || (defined(CONFIG_DVB_DIB3000MC_MODULE) && \
-				      defined(MODULE))
-extern struct dvb_frontend *dib3000mc_attach(struct i2c_adapter *i2c_adap,
-					     u8 i2c_addr,
-					     struct dib3000mc_config *cfg);
-extern int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c,
-				     int no_of_demods, u8 default_addr,
-				     struct dib3000mc_config cfg[]);
-extern
-struct i2c_adapter *dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod,
-						   int gating);
-#else
-static inline
-struct dvb_frontend *dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
-				      struct dib3000mc_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline
-int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c,
-			      int no_of_demods, u8 default_addr,
-			      struct dib3000mc_config cfg[])
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline
-struct i2c_adapter *dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod,
-						   int gating)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_DIB3000MC
-
-extern int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff);
-extern int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff);
-
-extern void dib3000mc_set_config(struct dvb_frontend *, struct dib3000mc_config *);
-
-#endif
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
deleted file mode 100644
index 148bf79..0000000
--- a/drivers/media/dvb/frontends/dib7000m.c
+++ /dev/null
@@ -1,1473 +0,0 @@
-/*
- * Linux-DVB Driver for DiBcom's DiB7000M and
- *              first generation DiB7000P-demodulator-family.
- *
- * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
- *
- * 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, version 2.
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-
-#include "dvb_frontend.h"
-
-#include "dib7000m.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
-
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M: "); printk(args); printk("\n"); } } while (0)
-
-struct dib7000m_state {
-	struct dvb_frontend demod;
-    struct dib7000m_config cfg;
-
-	u8 i2c_addr;
-	struct i2c_adapter   *i2c_adap;
-
-	struct dibx000_i2c_master i2c_master;
-
-/* offset is 1 in case of the 7000MC */
-	u8 reg_offs;
-
-	u16 wbd_ref;
-
-	u8 current_band;
-	u32 current_bandwidth;
-	struct dibx000_agc_config *current_agc;
-	u32 timf;
-	u32 timf_default;
-	u32 internal_clk;
-
-	u8 div_force_off : 1;
-	u8 div_state : 1;
-	u16 div_sync_wait;
-
-	u16 revision;
-
-	u8 agc_state;
-
-	/* for the I2C transfer */
-	struct i2c_msg msg[2];
-	u8 i2c_write_buffer[4];
-	u8 i2c_read_buffer[2];
-	struct mutex i2c_buffer_lock;
-};
-
-enum dib7000m_power_mode {
-	DIB7000M_POWER_ALL = 0,
-
-	DIB7000M_POWER_NO,
-	DIB7000M_POWER_INTERF_ANALOG_AGC,
-	DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD,
-	DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD,
-	DIB7000M_POWER_INTERFACE_ONLY,
-};
-
-static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
-{
-	u16 ret;
-
-	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return 0;
-	}
-
-	state->i2c_write_buffer[0] = (reg >> 8) | 0x80;
-	state->i2c_write_buffer[1] = reg & 0xff;
-
-	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
-	state->msg[0].addr = state->i2c_addr >> 1;
-	state->msg[0].flags = 0;
-	state->msg[0].buf = state->i2c_write_buffer;
-	state->msg[0].len = 2;
-	state->msg[1].addr = state->i2c_addr >> 1;
-	state->msg[1].flags = I2C_M_RD;
-	state->msg[1].buf = state->i2c_read_buffer;
-	state->msg[1].len = 2;
-
-	if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
-		dprintk("i2c read error on %d",reg);
-
-	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
-	mutex_unlock(&state->i2c_buffer_lock);
-
-	return ret;
-}
-
-static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
-{
-	int ret;
-
-	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return -EINVAL;
-	}
-
-	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
-	state->i2c_write_buffer[1] = reg & 0xff;
-	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
-	state->i2c_write_buffer[3] = val & 0xff;
-
-	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
-	state->msg[0].addr = state->i2c_addr >> 1;
-	state->msg[0].flags = 0;
-	state->msg[0].buf = state->i2c_write_buffer;
-	state->msg[0].len = 4;
-
-	ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
-			-EREMOTEIO : 0);
-	mutex_unlock(&state->i2c_buffer_lock);
-	return ret;
-}
-static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
-{
-	u16 l = 0, r, *n;
-	n = buf;
-	l = *n++;
-	while (l) {
-		r = *n++;
-
-		if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC
-			r++;
-
-		do {
-			dib7000m_write_word(state, r, *n++);
-			r++;
-		} while (--l);
-		l = *n++;
-	}
-}
-
-static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
-{
-	int    ret = 0;
-	u16 outreg, fifo_threshold, smo_mode,
-		sram = 0x0005; /* by default SRAM output is disabled */
-
-	outreg = 0;
-	fifo_threshold = 1792;
-	smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1);
-
-	dprintk( "setting output mode for demod %p to %d", &state->demod, mode);
-
-	switch (mode) {
-		case OUTMODE_MPEG2_PAR_GATED_CLK:   // STBs with parallel gated clock
-			outreg = (1 << 10);  /* 0x0400 */
-			break;
-		case OUTMODE_MPEG2_PAR_CONT_CLK:    // STBs with parallel continues clock
-			outreg = (1 << 10) | (1 << 6); /* 0x0440 */
-			break;
-		case OUTMODE_MPEG2_SERIAL:          // STBs with serial input
-			outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
-			break;
-		case OUTMODE_DIVERSITY:
-			if (state->cfg.hostbus_diversity)
-				outreg = (1 << 10) | (4 << 6); /* 0x0500 */
-			else
-				sram   |= 0x0c00;
-			break;
-		case OUTMODE_MPEG2_FIFO:            // e.g. USB feeding
-			smo_mode |= (3 << 1);
-			fifo_threshold = 512;
-			outreg = (1 << 10) | (5 << 6);
-			break;
-		case OUTMODE_HIGH_Z:  // disable
-			outreg = 0;
-			break;
-		default:
-			dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod);
-			break;
-	}
-
-	if (state->cfg.output_mpeg2_in_188_bytes)
-		smo_mode |= (1 << 5) ;
-
-	ret |= dib7000m_write_word(state,  294 + state->reg_offs, smo_mode);
-	ret |= dib7000m_write_word(state,  295 + state->reg_offs, fifo_threshold); /* synchronous fread */
-	ret |= dib7000m_write_word(state, 1795, outreg);
-	ret |= dib7000m_write_word(state, 1805, sram);
-
-	if (state->revision == 0x4003) {
-		u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd;
-		if (mode == OUTMODE_DIVERSITY)
-			clk_cfg1 |= (1 << 1); // P_O_CLK_en
-		dib7000m_write_word(state, 909, clk_cfg1);
-	}
-	return ret;
-}
-
-static void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode)
-{
-	/* by default everything is going to be powered off */
-	u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906  = 0x3fff;
-	u8  offset = 0;
-
-	/* now, depending on the requested mode, we power on */
-	switch (mode) {
-		/* power up everything in the demod */
-		case DIB7000M_POWER_ALL:
-			reg_903 = 0x0000; reg_904 = 0x0000; reg_905 = 0x0000; reg_906 = 0x0000;
-			break;
-
-		/* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */
-		case DIB7000M_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */
-			reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2));
-			break;
-
-		case DIB7000M_POWER_INTERF_ANALOG_AGC:
-			reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10));
-			reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2));
-			reg_906 &= ~((1 << 0));
-			break;
-
-		case DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD:
-			reg_903 = 0x0000; reg_904 = 0x801f; reg_905 = 0x0000; reg_906 = 0x0000;
-			break;
-
-		case DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD:
-			reg_903 = 0x0000; reg_904 = 0x8000; reg_905 = 0x010b; reg_906 = 0x0000;
-			break;
-		case DIB7000M_POWER_NO:
-			break;
-	}
-
-	/* always power down unused parts */
-	if (!state->cfg.mobile_mode)
-		reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1);
-
-	/* P_sdio_select_clk = 0 on MC and after*/
-	if (state->revision != 0x4000)
-		reg_906 <<= 1;
-
-	if (state->revision == 0x4003)
-		offset = 1;
-
-	dib7000m_write_word(state, 903 + offset, reg_903);
-	dib7000m_write_word(state, 904 + offset, reg_904);
-	dib7000m_write_word(state, 905 + offset, reg_905);
-	dib7000m_write_word(state, 906 + offset, reg_906);
-}
-
-static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no)
-{
-	int ret = 0;
-	u16 reg_913 = dib7000m_read_word(state, 913),
-	       reg_914 = dib7000m_read_word(state, 914);
-
-	switch (no) {
-		case DIBX000_SLOW_ADC_ON:
-			reg_914 |= (1 << 1) | (1 << 0);
-			ret |= dib7000m_write_word(state, 914, reg_914);
-			reg_914 &= ~(1 << 1);
-			break;
-
-		case DIBX000_SLOW_ADC_OFF:
-			reg_914 |=  (1 << 1) | (1 << 0);
-			break;
-
-		case DIBX000_ADC_ON:
-			if (state->revision == 0x4000) { // workaround for PA/MA
-				// power-up ADC
-				dib7000m_write_word(state, 913, 0);
-				dib7000m_write_word(state, 914, reg_914 & 0x3);
-				// power-down bandgag
-				dib7000m_write_word(state, 913, (1 << 15));
-				dib7000m_write_word(state, 914, reg_914 & 0x3);
-			}
-
-			reg_913 &= 0x0fff;
-			reg_914 &= 0x0003;
-			break;
-
-		case DIBX000_ADC_OFF: // leave the VBG voltage on
-			reg_913 |= (1 << 14) | (1 << 13) | (1 << 12);
-			reg_914 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
-			break;
-
-		case DIBX000_VBG_ENABLE:
-			reg_913 &= ~(1 << 15);
-			break;
-
-		case DIBX000_VBG_DISABLE:
-			reg_913 |= (1 << 15);
-			break;
-
-		default:
-			break;
-	}
-
-//	dprintk( "913: %x, 914: %x", reg_913, reg_914);
-	ret |= dib7000m_write_word(state, 913, reg_913);
-	ret |= dib7000m_write_word(state, 914, reg_914);
-
-	return ret;
-}
-
-static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw)
-{
-	u32 timf;
-
-	if (!bw)
-		bw = 8000;
-
-	// store the current bandwidth for later use
-	state->current_bandwidth = bw;
-
-	if (state->timf == 0) {
-		dprintk( "using default timf");
-		timf = state->timf_default;
-	} else {
-		dprintk( "using updated timf");
-		timf = state->timf;
-	}
-
-	timf = timf * (bw / 50) / 160;
-
-	dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
-	dib7000m_write_word(state, 24, (u16) ((timf      ) & 0xffff));
-
-	return 0;
-}
-
-static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff)
-{
-	struct dib7000m_state *state = demod->demodulator_priv;
-
-	if (state->div_force_off) {
-		dprintk( "diversity combination deactivated - forced by COFDM parameters");
-		onoff = 0;
-	}
-	state->div_state = (u8)onoff;
-
-	if (onoff) {
-		dib7000m_write_word(state, 263 + state->reg_offs, 6);
-		dib7000m_write_word(state, 264 + state->reg_offs, 6);
-		dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
-	} else {
-		dib7000m_write_word(state, 263 + state->reg_offs, 1);
-		dib7000m_write_word(state, 264 + state->reg_offs, 0);
-		dib7000m_write_word(state, 266 + state->reg_offs, 0);
-	}
-
-	return 0;
-}
-
-static int dib7000m_sad_calib(struct dib7000m_state *state)
-{
-
-/* internal */
-//	dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
-	dib7000m_write_word(state, 929, (0 << 1) | (0 << 0));
-	dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096
-
-	/* do the calibration */
-	dib7000m_write_word(state, 929, (1 << 0));
-	dib7000m_write_word(state, 929, (0 << 0));
-
-	msleep(1);
-
-	return 0;
-}
-
-static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw)
-{
-	dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
-	dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000)        & 0xffff));
-	dib7000m_write_word(state, 21, (u16) ( (bw->ifreq          >> 16) & 0xffff));
-	dib7000m_write_word(state, 22, (u16) (  bw->ifreq                 & 0xffff));
-
-	dib7000m_write_word(state, 928, bw->sad_cfg);
-}
-
-static void dib7000m_reset_pll(struct dib7000m_state *state)
-{
-	const struct dibx000_bandwidth_config *bw = state->cfg.bw;
-	u16 reg_907,reg_910;
-
-	/* default */
-	reg_907 = (bw->pll_bypass << 15) | (bw->modulo << 7) |
-		(bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) |
-		(bw->enable_refdiv << 1) | (0 << 0);
-	reg_910 = (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset;
-
-	// for this oscillator frequency should be 30 MHz for the Master (default values in the board_parameters give that value)
-	// this is only working only for 30 MHz crystals
-	if (!state->cfg.quartz_direct) {
-		reg_910 |= (1 << 5);  // forcing the predivider to 1
-
-		// if the previous front-end is baseband, its output frequency is 15 MHz (prev freq divided by 2)
-		if(state->cfg.input_clk_is_div_2)
-			reg_907 |= (16 << 9);
-		else // otherwise the previous front-end puts out its input (default 30MHz) - no extra division necessary
-			reg_907 |= (8 << 9);
-	} else {
-		reg_907 |= (bw->pll_ratio & 0x3f) << 9;
-		reg_910 |= (bw->pll_prediv << 5);
-	}
-
-	dib7000m_write_word(state, 910, reg_910); // pll cfg
-	dib7000m_write_word(state, 907, reg_907); // clk cfg0
-	dib7000m_write_word(state, 908, 0x0006);  // clk_cfg1
-
-	dib7000m_reset_pll_common(state, bw);
-}
-
-static void dib7000mc_reset_pll(struct dib7000m_state *state)
-{
-	const struct dibx000_bandwidth_config *bw = state->cfg.bw;
-	u16 clk_cfg1;
-
-	// clk_cfg0
-	dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0));
-
-	// clk_cfg1
-	//dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) |
-	clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) |
-			(bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) |
-			(1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0);
-	dib7000m_write_word(state, 908, clk_cfg1);
-	clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3);
-	dib7000m_write_word(state, 908, clk_cfg1);
-
-	// smpl_cfg
-	dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7));
-
-	dib7000m_reset_pll_common(state, bw);
-}
-
-static int dib7000m_reset_gpio(struct dib7000m_state *st)
-{
-	/* reset the GPIOs */
-	dib7000m_write_word(st, 773, st->cfg.gpio_dir);
-	dib7000m_write_word(st, 774, st->cfg.gpio_val);
-
-	/* TODO 782 is P_gpio_od */
-
-	dib7000m_write_word(st, 775, st->cfg.gpio_pwm_pos);
-
-	dib7000m_write_word(st, 780, st->cfg.pwm_freq_div);
-	return 0;
-}
-
-static u16 dib7000m_defaults_common[] =
-
-{
-	// auto search configuration
-	3, 2,
-		0x0004,
-		0x1000,
-		0x0814,
-
-	12, 6,
-		0x001b,
-		0x7740,
-		0x005b,
-		0x8d80,
-		0x01c9,
-		0xc380,
-		0x0000,
-		0x0080,
-		0x0000,
-		0x0090,
-		0x0001,
-		0xd4c0,
-
-	1, 26,
-		0x6680, // P_corm_thres Lock algorithms configuration
-
-	1, 170,
-		0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on
-
-	8, 173,
-		0,
-		0,
-		0,
-		0,
-		0,
-		0,
-		0,
-		0,
-
-	1, 182,
-		8192, // P_fft_nb_to_cut
-
-	2, 195,
-		0x0ccd, // P_pha3_thres
-		0,      // P_cti_use_cpe, P_cti_use_prog
-
-	1, 205,
-		0x200f, // P_cspu_regul, P_cspu_win_cut
-
-	5, 214,
-		0x023d, // P_adp_regul_cnt
-		0x00a4, // P_adp_noise_cnt
-		0x00a4, // P_adp_regul_ext
-		0x7ff0, // P_adp_noise_ext
-		0x3ccc, // P_adp_fil
-
-	1, 226,
-		0, // P_2d_byp_ti_num
-
-	1, 255,
-		0x800, // P_equal_thres_wgn
-
-	1, 263,
-		0x0001,
-
-	1, 281,
-		0x0010, // P_fec_*
-
-	1, 294,
-		0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
-
-	0
-};
-
-static u16 dib7000m_defaults[] =
-
-{
-	/* set ADC level to -16 */
-	11, 76,
-		(1 << 13) - 825 - 117,
-		(1 << 13) - 837 - 117,
-		(1 << 13) - 811 - 117,
-		(1 << 13) - 766 - 117,
-		(1 << 13) - 737 - 117,
-		(1 << 13) - 693 - 117,
-		(1 << 13) - 648 - 117,
-		(1 << 13) - 619 - 117,
-		(1 << 13) - 575 - 117,
-		(1 << 13) - 531 - 117,
-		(1 << 13) - 501 - 117,
-
-	// Tuner IO bank: max drive (14mA)
-	1, 912,
-		0x2c8a,
-
-	1, 1817,
-		1,
-
-	0,
-};
-
-static int dib7000m_demod_reset(struct dib7000m_state *state)
-{
-	dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
-
-	/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
-	dib7000m_set_adc_state(state, DIBX000_VBG_ENABLE);
-
-	/* restart all parts */
-	dib7000m_write_word(state,  898, 0xffff);
-	dib7000m_write_word(state,  899, 0xffff);
-	dib7000m_write_word(state,  900, 0xff0f);
-	dib7000m_write_word(state,  901, 0xfffc);
-
-	dib7000m_write_word(state,  898, 0);
-	dib7000m_write_word(state,  899, 0);
-	dib7000m_write_word(state,  900, 0);
-	dib7000m_write_word(state,  901, 0);
-
-	if (state->revision == 0x4000)
-		dib7000m_reset_pll(state);
-	else
-		dib7000mc_reset_pll(state);
-
-	if (dib7000m_reset_gpio(state) != 0)
-		dprintk( "GPIO reset was not successful.");
-
-	if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
-		dprintk( "OUTPUT_MODE could not be reset.");
-
-	/* unforce divstr regardless whether i2c enumeration was done or not */
-	dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) );
-
-	dib7000m_set_bandwidth(state, 8000);
-
-	dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON);
-	dib7000m_sad_calib(state);
-	dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
-
-	if (state->cfg.dvbt_mode)
-		dib7000m_write_word(state, 1796, 0x0); // select DVB-T output
-
-	if (state->cfg.mobile_mode)
-		dib7000m_write_word(state, 261 + state->reg_offs, 2);
-	else
-		dib7000m_write_word(state, 224 + state->reg_offs, 1);
-
-	// P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
-	if(state->cfg.tuner_is_baseband)
-		dib7000m_write_word(state, 36, 0x0755);
-	else
-		dib7000m_write_word(state, 36, 0x1f55);
-
-	// P_divclksel=3 P_divbitsel=1
-	if (state->revision == 0x4000)
-		dib7000m_write_word(state, 909, (3 << 10) | (1 << 6));
-	else
-		dib7000m_write_word(state, 909, (3 << 4) | 1);
-
-	dib7000m_write_tab(state, dib7000m_defaults_common);
-	dib7000m_write_tab(state, dib7000m_defaults);
-
-	dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY);
-
-	state->internal_clk = state->cfg.bw->internal;
-
-	return 0;
-}
-
-static void dib7000m_restart_agc(struct dib7000m_state *state)
-{
-	// P_restart_iqc & P_restart_agc
-	dib7000m_write_word(state, 898, 0x0c00);
-	dib7000m_write_word(state, 898, 0x0000);
-}
-
-static int dib7000m_agc_soft_split(struct dib7000m_state *state)
-{
-	u16 agc,split_offset;
-
-	if(!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
-		return 0;
-
-	// n_agc_global
-	agc = dib7000m_read_word(state, 390);
-
-	if (agc > state->current_agc->split.min_thres)
-		split_offset = state->current_agc->split.min;
-	else if (agc < state->current_agc->split.max_thres)
-		split_offset = state->current_agc->split.max;
-	else
-		split_offset = state->current_agc->split.max *
-			(agc - state->current_agc->split.min_thres) /
-			(state->current_agc->split.max_thres - state->current_agc->split.min_thres);
-
-	dprintk( "AGC split_offset: %d",split_offset);
-
-	// P_agc_force_split and P_agc_split_offset
-	return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset);
-}
-
-static int dib7000m_update_lna(struct dib7000m_state *state)
-{
-	u16 dyn_gain;
-
-	if (state->cfg.update_lna) {
-		// read dyn_gain here (because it is demod-dependent and not fe)
-		dyn_gain = dib7000m_read_word(state, 390);
-
-		if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
-			dib7000m_restart_agc(state);
-			return 1;
-		}
-	}
-	return 0;
-}
-
-static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
-{
-	struct dibx000_agc_config *agc = NULL;
-	int i;
-	if (state->current_band == band && state->current_agc != NULL)
-		return 0;
-	state->current_band = band;
-
-	for (i = 0; i < state->cfg.agc_config_count; i++)
-		if (state->cfg.agc[i].band_caps & band) {
-			agc = &state->cfg.agc[i];
-			break;
-		}
-
-	if (agc == NULL) {
-		dprintk( "no valid AGC configuration found for band 0x%02x",band);
-		return -EINVAL;
-	}
-
-	state->current_agc = agc;
-
-	/* AGC */
-	dib7000m_write_word(state, 72 ,  agc->setup);
-	dib7000m_write_word(state, 73 ,  agc->inv_gain);
-	dib7000m_write_word(state, 74 ,  agc->time_stabiliz);
-	dib7000m_write_word(state, 97 , (agc->alpha_level << 12) | agc->thlock);
-
-	// Demod AGC loop configuration
-	dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp);
-	dib7000m_write_word(state, 99, (agc->beta_mant  << 6) | agc->beta_exp);
-
-	dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",
-		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
-
-	/* AGC continued */
-	if (state->wbd_ref != 0)
-		dib7000m_write_word(state, 102, state->wbd_ref);
-	else // use default
-		dib7000m_write_word(state, 102, agc->wbd_ref);
-
-	dib7000m_write_word(state, 103, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) );
-	dib7000m_write_word(state, 104,  agc->agc1_max);
-	dib7000m_write_word(state, 105,  agc->agc1_min);
-	dib7000m_write_word(state, 106,  agc->agc2_max);
-	dib7000m_write_word(state, 107,  agc->agc2_min);
-	dib7000m_write_word(state, 108, (agc->agc1_pt1 << 8) | agc->agc1_pt2 );
-	dib7000m_write_word(state, 109, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
-	dib7000m_write_word(state, 110, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
-	dib7000m_write_word(state, 111, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
-
-	if (state->revision > 0x4000) { // settings for the MC
-		dib7000m_write_word(state, 71,   agc->agc1_pt3);
-//		dprintk( "929: %x %d %d",
-//			(dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel);
-		dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
-	} else {
-		// wrong default values
-		u16 b[9] = { 676, 696, 717, 737, 758, 778, 799, 819, 840 };
-		for (i = 0; i < 9; i++)
-			dib7000m_write_word(state, 88 + i, b[i]);
-	}
-	return 0;
-}
-
-static void dib7000m_update_timf(struct dib7000m_state *state)
-{
-	u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437);
-	state->timf = timf * 160 / (state->current_bandwidth / 50);
-	dib7000m_write_word(state, 23, (u16) (timf >> 16));
-	dib7000m_write_word(state, 24, (u16) (timf & 0xffff));
-	dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default);
-}
-
-static int dib7000m_agc_startup(struct dvb_frontend *demod)
-{
-	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
-	struct dib7000m_state *state = demod->demodulator_priv;
-	u16 cfg_72 = dib7000m_read_word(state, 72);
-	int ret = -1;
-	u8 *agc_state = &state->agc_state;
-	u8 agc_split;
-
-	switch (state->agc_state) {
-		case 0:
-			// set power-up level: interf+analog+AGC
-			dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC);
-			dib7000m_set_adc_state(state, DIBX000_ADC_ON);
-
-			if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
-				return -1;
-
-			ret = 7; /* ADC power up */
-			(*agc_state)++;
-			break;
-
-		case 1:
-			/* AGC initialization */
-			if (state->cfg.agc_control)
-				state->cfg.agc_control(&state->demod, 1);
-
-			dib7000m_write_word(state, 75, 32768);
-			if (!state->current_agc->perform_agc_softsplit) {
-				/* we are using the wbd - so slow AGC startup */
-				dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */
-				(*agc_state)++;
-				ret = 5;
-			} else {
-				/* default AGC startup */
-				(*agc_state) = 4;
-				/* wait AGC rough lock time */
-				ret = 7;
-			}
-
-			dib7000m_restart_agc(state);
-			break;
-
-		case 2: /* fast split search path after 5sec */
-			dib7000m_write_word(state,  72, cfg_72 | (1 << 4)); /* freeze AGC loop */
-			dib7000m_write_word(state, 103, 2 << 9);            /* fast split search 0.25kHz */
-			(*agc_state)++;
-			ret = 14;
-			break;
-
-	case 3: /* split search ended */
-			agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */
-			dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */
-
-			dib7000m_write_word(state, 72,  cfg_72 & ~(1 << 4));   /* std AGC loop */
-			dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
-
-			dib7000m_restart_agc(state);
-
-			dprintk( "SPLIT %p: %hd", demod, agc_split);
-
-			(*agc_state)++;
-			ret = 5;
-			break;
-
-		case 4: /* LNA startup */
-			/* wait AGC accurate lock time */
-			ret = 7;
-
-			if (dib7000m_update_lna(state))
-				// wait only AGC rough lock time
-				ret = 5;
-			else
-				(*agc_state)++;
-			break;
-
-		case 5:
-			dib7000m_agc_soft_split(state);
-
-			if (state->cfg.agc_control)
-				state->cfg.agc_control(&state->demod, 0);
-
-			(*agc_state)++;
-			break;
-
-		default:
-			break;
-	}
-	return ret;
-}
-
-static void dib7000m_set_channel(struct dib7000m_state *state, struct dtv_frontend_properties *ch,
-				 u8 seq)
-{
-	u16 value, est[4];
-
-	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
-
-	/* nfft, guard, qam, alpha */
-	value = 0;
-	switch (ch->transmission_mode) {
-		case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
-		case TRANSMISSION_MODE_4K: value |= (2 << 7); break;
-		default:
-		case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
-	}
-	switch (ch->guard_interval) {
-		case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
-		case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
-		case GUARD_INTERVAL_1_4:  value |= (3 << 5); break;
-		default:
-		case GUARD_INTERVAL_1_8:  value |= (2 << 5); break;
-	}
-	switch (ch->modulation) {
-		case QPSK:  value |= (0 << 3); break;
-		case QAM_16: value |= (1 << 3); break;
-		default:
-		case QAM_64: value |= (2 << 3); break;
-	}
-	switch (HIERARCHY_1) {
-		case HIERARCHY_2: value |= 2; break;
-		case HIERARCHY_4: value |= 4; break;
-		default:
-		case HIERARCHY_1: value |= 1; break;
-	}
-	dib7000m_write_word(state, 0, value);
-	dib7000m_write_word(state, 5, (seq << 4));
-
-	/* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
-	value = 0;
-	if (1 != 0)
-		value |= (1 << 6);
-	if (ch->hierarchy == 1)
-		value |= (1 << 4);
-	if (1 == 1)
-		value |= 1;
-	switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
-		case FEC_2_3: value |= (2 << 1); break;
-		case FEC_3_4: value |= (3 << 1); break;
-		case FEC_5_6: value |= (5 << 1); break;
-		case FEC_7_8: value |= (7 << 1); break;
-		default:
-		case FEC_1_2: value |= (1 << 1); break;
-	}
-	dib7000m_write_word(state, 267 + state->reg_offs, value);
-
-	/* offset loop parameters */
-
-	/* P_timf_alpha = 6, P_corm_alpha=6, P_corm_thres=0x80 */
-	dib7000m_write_word(state, 26, (6 << 12) | (6 << 8) | 0x80);
-
-	/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=1, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
-	dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (1 << 9) | (3 << 5) | (1 << 4) | (0x3));
-
-	/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max=3 */
-	dib7000m_write_word(state, 32, (0 << 4) | 0x3);
-
-	/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step=5 */
-	dib7000m_write_word(state, 33, (0 << 4) | 0x5);
-
-	/* P_dvsy_sync_wait */
-	switch (ch->transmission_mode) {
-		case TRANSMISSION_MODE_8K: value = 256; break;
-		case TRANSMISSION_MODE_4K: value = 128; break;
-		case TRANSMISSION_MODE_2K:
-		default: value = 64; break;
-	}
-	switch (ch->guard_interval) {
-		case GUARD_INTERVAL_1_16: value *= 2; break;
-		case GUARD_INTERVAL_1_8:  value *= 4; break;
-		case GUARD_INTERVAL_1_4:  value *= 8; break;
-		default:
-		case GUARD_INTERVAL_1_32: value *= 1; break;
-	}
-	state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO
-
-	/* deactive the possibility of diversity reception if extended interleave - not for 7000MC */
-	/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
-	if (1 == 1 || state->revision > 0x4000)
-		state->div_force_off = 0;
-	else
-		state->div_force_off = 1;
-	dib7000m_set_diversity_in(&state->demod, state->div_state);
-
-	/* channel estimation fine configuration */
-	switch (ch->modulation) {
-		case QAM_64:
-			est[0] = 0x0148;       /* P_adp_regul_cnt 0.04 */
-			est[1] = 0xfff0;       /* P_adp_noise_cnt -0.002 */
-			est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
-			est[3] = 0xfff8;       /* P_adp_noise_ext -0.001 */
-			break;
-		case QAM_16:
-			est[0] = 0x023d;       /* P_adp_regul_cnt 0.07 */
-			est[1] = 0xffdf;       /* P_adp_noise_cnt -0.004 */
-			est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
-			est[3] = 0xfff0;       /* P_adp_noise_ext -0.002 */
-			break;
-		default:
-			est[0] = 0x099a;       /* P_adp_regul_cnt 0.3 */
-			est[1] = 0xffae;       /* P_adp_noise_cnt -0.01 */
-			est[2] = 0x0333;       /* P_adp_regul_ext 0.1 */
-			est[3] = 0xfff8;       /* P_adp_noise_ext -0.002 */
-			break;
-	}
-	for (value = 0; value < 4; value++)
-		dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]);
-
-	// set power-up level: autosearch
-	dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD);
-}
-
-static int dib7000m_autosearch_start(struct dvb_frontend *demod)
-{
-	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
-	struct dib7000m_state *state = demod->demodulator_priv;
-	struct dtv_frontend_properties schan;
-	int ret = 0;
-	u32 value, factor;
-
-	schan = *ch;
-
-	schan.modulation = QAM_64;
-	schan.guard_interval        = GUARD_INTERVAL_1_32;
-	schan.transmission_mode         = TRANSMISSION_MODE_8K;
-	schan.code_rate_HP = FEC_2_3;
-	schan.code_rate_LP = FEC_3_4;
-	schan.hierarchy    = 0;
-
-	dib7000m_set_channel(state, &schan, 7);
-
-	factor = BANDWIDTH_TO_KHZ(schan.bandwidth_hz);
-	if (factor >= 5000)
-		factor = 1;
-	else
-		factor = 6;
-
-	// always use the setting for 8MHz here lock_time for 7,6 MHz are longer
-	value = 30 * state->internal_clk * factor;
-	ret |= dib7000m_write_word(state, 6,  (u16) ((value >> 16) & 0xffff)); // lock0 wait time
-	ret |= dib7000m_write_word(state, 7,  (u16)  (value        & 0xffff)); // lock0 wait time
-	value = 100 * state->internal_clk * factor;
-	ret |= dib7000m_write_word(state, 8,  (u16) ((value >> 16) & 0xffff)); // lock1 wait time
-	ret |= dib7000m_write_word(state, 9,  (u16)  (value        & 0xffff)); // lock1 wait time
-	value = 500 * state->internal_clk * factor;
-	ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
-	ret |= dib7000m_write_word(state, 11, (u16)  (value        & 0xffff)); // lock2 wait time
-
-	// start search
-	value = dib7000m_read_word(state, 0);
-	ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9)));
-
-	/* clear n_irq_pending */
-	if (state->revision == 0x4000)
-		dib7000m_write_word(state, 1793, 0);
-	else
-		dib7000m_read_word(state, 537);
-
-	ret |= dib7000m_write_word(state, 0, (u16) value);
-
-	return ret;
-}
-
-static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg)
-{
-	u16 irq_pending = dib7000m_read_word(state, reg);
-
-	if (irq_pending & 0x1) { // failed
-		dprintk( "autosearch failed");
-		return 1;
-	}
-
-	if (irq_pending & 0x2) { // succeeded
-		dprintk( "autosearch succeeded");
-		return 2;
-	}
-	return 0; // still pending
-}
-
-static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod)
-{
-	struct dib7000m_state *state = demod->demodulator_priv;
-	if (state->revision == 0x4000)
-		return dib7000m_autosearch_irq(state, 1793);
-	else
-		return dib7000m_autosearch_irq(state, 537);
-}
-
-static int dib7000m_tune(struct dvb_frontend *demod)
-{
-	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
-	struct dib7000m_state *state = demod->demodulator_priv;
-	int ret = 0;
-	u16 value;
-
-	// we are already tuned - just resuming from suspend
-	if (ch != NULL)
-		dib7000m_set_channel(state, ch, 0);
-	else
-		return -EINVAL;
-
-	// restart demod
-	ret |= dib7000m_write_word(state, 898, 0x4000);
-	ret |= dib7000m_write_word(state, 898, 0x0000);
-	msleep(45);
-
-	dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD);
-	/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
-	ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
-
-	// never achieved a lock before - wait for timfreq to update
-	if (state->timf == 0)
-		msleep(200);
-
-	//dump_reg(state);
-	/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
-	value = (6 << 8) | 0x80;
-	switch (ch->transmission_mode) {
-		case TRANSMISSION_MODE_2K: value |= (7 << 12); break;
-		case TRANSMISSION_MODE_4K: value |= (8 << 12); break;
-		default:
-		case TRANSMISSION_MODE_8K: value |= (9 << 12); break;
-	}
-	ret |= dib7000m_write_word(state, 26, value);
-
-	/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
-	value = (0 << 4);
-	switch (ch->transmission_mode) {
-		case TRANSMISSION_MODE_2K: value |= 0x6; break;
-		case TRANSMISSION_MODE_4K: value |= 0x7; break;
-		default:
-		case TRANSMISSION_MODE_8K: value |= 0x8; break;
-	}
-	ret |= dib7000m_write_word(state, 32, value);
-
-	/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
-	value = (0 << 4);
-	switch (ch->transmission_mode) {
-		case TRANSMISSION_MODE_2K: value |= 0x6; break;
-		case TRANSMISSION_MODE_4K: value |= 0x7; break;
-		default:
-		case TRANSMISSION_MODE_8K: value |= 0x8; break;
-	}
-	ret |= dib7000m_write_word(state, 33,  value);
-
-	// we achieved a lock - it's time to update the timf freq
-	if ((dib7000m_read_word(state, 535) >> 6)  & 0x1)
-		dib7000m_update_timf(state);
-
-	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
-	return ret;
-}
-
-static int dib7000m_wakeup(struct dvb_frontend *demod)
-{
-	struct dib7000m_state *state = demod->demodulator_priv;
-
-	dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
-
-	if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
-		dprintk( "could not start Slow ADC");
-
-	return 0;
-}
-
-static int dib7000m_sleep(struct dvb_frontend *demod)
-{
-	struct dib7000m_state *st = demod->demodulator_priv;
-	dib7000m_set_output_mode(st, OUTMODE_HIGH_Z);
-	dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY);
-	return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) |
-		dib7000m_set_adc_state(st, DIBX000_ADC_OFF);
-}
-
-static int dib7000m_identify(struct dib7000m_state *state)
-{
-	u16 value;
-
-	if ((value = dib7000m_read_word(state, 896)) != 0x01b3) {
-		dprintk( "wrong Vendor ID (0x%x)",value);
-		return -EREMOTEIO;
-	}
-
-	state->revision = dib7000m_read_word(state, 897);
-	if (state->revision != 0x4000 &&
-		state->revision != 0x4001 &&
-		state->revision != 0x4002 &&
-		state->revision != 0x4003) {
-		dprintk( "wrong Device ID (0x%x)",value);
-		return -EREMOTEIO;
-	}
-
-	/* protect this driver to be used with 7000PC */
-	if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) {
-		dprintk( "this driver does not work with DiB7000PC");
-		return -EREMOTEIO;
-	}
-
-	switch (state->revision) {
-		case 0x4000: dprintk( "found DiB7000MA/PA/MB/PB"); break;
-		case 0x4001: state->reg_offs = 1; dprintk( "found DiB7000HC"); break;
-		case 0x4002: state->reg_offs = 1; dprintk( "found DiB7000MC"); break;
-		case 0x4003: state->reg_offs = 1; dprintk( "found DiB9000"); break;
-	}
-
-	return 0;
-}
-
-
-static int dib7000m_get_frontend(struct dvb_frontend* fe)
-{
-	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
-	struct dib7000m_state *state = fe->demodulator_priv;
-	u16 tps = dib7000m_read_word(state,480);
-
-	fep->inversion = INVERSION_AUTO;
-
-	fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
-
-	switch ((tps >> 8) & 0x3) {
-		case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break;
-		case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break;
-		/* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
-	}
-
-	switch (tps & 0x3) {
-		case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break;
-		case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break;
-		case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break;
-		case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break;
-	}
-
-	switch ((tps >> 14) & 0x3) {
-		case 0: fep->modulation = QPSK; break;
-		case 1: fep->modulation = QAM_16; break;
-		case 2:
-		default: fep->modulation = QAM_64; break;
-	}
-
-	/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
-	/* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
-
-	fep->hierarchy = HIERARCHY_NONE;
-	switch ((tps >> 5) & 0x7) {
-		case 1: fep->code_rate_HP = FEC_1_2; break;
-		case 2: fep->code_rate_HP = FEC_2_3; break;
-		case 3: fep->code_rate_HP = FEC_3_4; break;
-		case 5: fep->code_rate_HP = FEC_5_6; break;
-		case 7:
-		default: fep->code_rate_HP = FEC_7_8; break;
-
-	}
-
-	switch ((tps >> 2) & 0x7) {
-		case 1: fep->code_rate_LP = FEC_1_2; break;
-		case 2: fep->code_rate_LP = FEC_2_3; break;
-		case 3: fep->code_rate_LP = FEC_3_4; break;
-		case 5: fep->code_rate_LP = FEC_5_6; break;
-		case 7:
-		default: fep->code_rate_LP = FEC_7_8; break;
-	}
-
-	/* native interleaver: (dib7000m_read_word(state, 481) >>  5) & 0x1 */
-
-	return 0;
-}
-
-static int dib7000m_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
-	struct dib7000m_state *state = fe->demodulator_priv;
-	int time, ret;
-
-	dib7000m_set_output_mode(state, OUTMODE_HIGH_Z);
-
-	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz));
-
-	if (fe->ops.tuner_ops.set_params)
-		fe->ops.tuner_ops.set_params(fe);
-
-	/* start up the AGC */
-	state->agc_state = 0;
-	do {
-		time = dib7000m_agc_startup(fe);
-		if (time != -1)
-			msleep(time);
-	} while (time != -1);
-
-	if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
-		fep->guard_interval    == GUARD_INTERVAL_AUTO ||
-		fep->modulation        == QAM_AUTO ||
-		fep->code_rate_HP      == FEC_AUTO) {
-		int i = 800, found;
-
-		dib7000m_autosearch_start(fe);
-		do {
-			msleep(1);
-			found = dib7000m_autosearch_is_irq(fe);
-		} while (found == 0 && i--);
-
-		dprintk("autosearch returns: %d",found);
-		if (found == 0 || found == 1)
-			return 0; // no channel found
-
-		dib7000m_get_frontend(fe);
-	}
-
-	ret = dib7000m_tune(fe);
-
-	/* make this a config parameter */
-	dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
-	return ret;
-}
-
-static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat)
-{
-	struct dib7000m_state *state = fe->demodulator_priv;
-	u16 lock = dib7000m_read_word(state, 535);
-
-	*stat = 0;
-
-	if (lock & 0x8000)
-		*stat |= FE_HAS_SIGNAL;
-	if (lock & 0x3000)
-		*stat |= FE_HAS_CARRIER;
-	if (lock & 0x0100)
-		*stat |= FE_HAS_VITERBI;
-	if (lock & 0x0010)
-		*stat |= FE_HAS_SYNC;
-	if (lock & 0x0008)
-		*stat |= FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int dib7000m_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct dib7000m_state *state = fe->demodulator_priv;
-	*ber = (dib7000m_read_word(state, 526) << 16) | dib7000m_read_word(state, 527);
-	return 0;
-}
-
-static int dib7000m_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
-{
-	struct dib7000m_state *state = fe->demodulator_priv;
-	*unc = dib7000m_read_word(state, 534);
-	return 0;
-}
-
-static int dib7000m_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct dib7000m_state *state = fe->demodulator_priv;
-	u16 val = dib7000m_read_word(state, 390);
-	*strength = 65535 - val;
-	return 0;
-}
-
-static int dib7000m_read_snr(struct dvb_frontend* fe, u16 *snr)
-{
-	*snr = 0x0000;
-	return 0;
-}
-
-static int dib7000m_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
-{
-	tune->min_delay_ms = 1000;
-	return 0;
-}
-
-static void dib7000m_release(struct dvb_frontend *demod)
-{
-	struct dib7000m_state *st = demod->demodulator_priv;
-	dibx000_exit_i2c_master(&st->i2c_master);
-	kfree(st);
-}
-
-struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
-{
-	struct dib7000m_state *st = demod->demodulator_priv;
-	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
-}
-EXPORT_SYMBOL(dib7000m_get_i2c_master);
-
-int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
-{
-	struct dib7000m_state *state = fe->demodulator_priv;
-	u16 val = dib7000m_read_word(state, 294 + state->reg_offs) & 0xffef;
-	val |= (onoff & 0x1) << 4;
-	dprintk("PID filter enabled %d", onoff);
-	return dib7000m_write_word(state, 294 + state->reg_offs, val);
-}
-EXPORT_SYMBOL(dib7000m_pid_filter_ctrl);
-
-int dib7000m_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
-{
-	struct dib7000m_state *state = fe->demodulator_priv;
-	dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
-	return dib7000m_write_word(state, 300 + state->reg_offs + id,
-			onoff ? (1 << 13) | pid : 0);
-}
-EXPORT_SYMBOL(dib7000m_pid_filter);
-
-#if 0
-/* used with some prototype boards */
-int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods,
-		u8 default_addr, struct dib7000m_config cfg[])
-{
-	struct dib7000m_state st = { .i2c_adap = i2c };
-	int k = 0;
-	u8 new_addr = 0;
-
-	for (k = no_of_demods-1; k >= 0; k--) {
-		st.cfg = cfg[k];
-
-		/* designated i2c address */
-		new_addr          = (0x40 + k) << 1;
-		st.i2c_addr = new_addr;
-		if (dib7000m_identify(&st) != 0) {
-			st.i2c_addr = default_addr;
-			if (dib7000m_identify(&st) != 0) {
-				dprintk("DiB7000M #%d: not identified", k);
-				return -EIO;
-			}
-		}
-
-		/* start diversity to pull_down div_str - just for i2c-enumeration */
-		dib7000m_set_output_mode(&st, OUTMODE_DIVERSITY);
-
-		dib7000m_write_word(&st, 1796, 0x0); // select DVB-T output
-
-		/* set new i2c address and force divstart */
-		dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2);
-
-		dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
-	}
-
-	for (k = 0; k < no_of_demods; k++) {
-		st.cfg = cfg[k];
-		st.i2c_addr = (0x40 + k) << 1;
-
-		// unforce divstr
-		dib7000m_write_word(&st,1794, st.i2c_addr << 2);
-
-		/* deactivate div - it was just for i2c-enumeration */
-		dib7000m_set_output_mode(&st, OUTMODE_HIGH_Z);
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(dib7000m_i2c_enumeration);
-#endif
-
-static struct dvb_frontend_ops dib7000m_ops;
-struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg)
-{
-	struct dvb_frontend *demod;
-	struct dib7000m_state *st;
-	st = kzalloc(sizeof(struct dib7000m_state), GFP_KERNEL);
-	if (st == NULL)
-		return NULL;
-
-	memcpy(&st->cfg, cfg, sizeof(struct dib7000m_config));
-	st->i2c_adap = i2c_adap;
-	st->i2c_addr = i2c_addr;
-
-	demod                   = &st->demod;
-	demod->demodulator_priv = st;
-	memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
-	mutex_init(&st->i2c_buffer_lock);
-
-	st->timf_default = cfg->bw->timf;
-
-	if (dib7000m_identify(st) != 0)
-		goto error;
-
-	if (st->revision == 0x4000)
-		dibx000_init_i2c_master(&st->i2c_master, DIB7000, st->i2c_adap, st->i2c_addr);
-	else
-		dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c_adap, st->i2c_addr);
-
-	dib7000m_demod_reset(st);
-
-	return demod;
-
-error:
-	kfree(st);
-	return NULL;
-}
-EXPORT_SYMBOL(dib7000m_attach);
-
-static struct dvb_frontend_ops dib7000m_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name = "DiBcom 7000MA/MB/PA/PB/MC",
-		.frequency_min      = 44250000,
-		.frequency_max      = 867250000,
-		.frequency_stepsize = 62500,
-		.caps = FE_CAN_INVERSION_AUTO |
-			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_RECOVER |
-			FE_CAN_HIERARCHY_AUTO,
-	},
-
-	.release              = dib7000m_release,
-
-	.init                 = dib7000m_wakeup,
-	.sleep                = dib7000m_sleep,
-
-	.set_frontend         = dib7000m_set_frontend,
-	.get_tune_settings    = dib7000m_fe_get_tune_settings,
-	.get_frontend         = dib7000m_get_frontend,
-
-	.read_status          = dib7000m_read_status,
-	.read_ber             = dib7000m_read_ber,
-	.read_signal_strength = dib7000m_read_signal_strength,
-	.read_snr             = dib7000m_read_snr,
-	.read_ucblocks        = dib7000m_read_unc_blocks,
-};
-
-MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
-MODULE_DESCRIPTION("Driver for the DiBcom 7000MA/MB/PA/PB/MC COFDM demodulator");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dib7000m.h b/drivers/media/dvb/frontends/dib7000m.h
deleted file mode 100644
index 81fcf22..0000000
--- a/drivers/media/dvb/frontends/dib7000m.h
+++ /dev/null
@@ -1,90 +0,0 @@
-#ifndef DIB7000M_H
-#define DIB7000M_H
-
-#include "dibx000_common.h"
-
-struct dib7000m_config {
-	u8 dvbt_mode;
-	u8 output_mpeg2_in_188_bytes;
-	u8 hostbus_diversity;
-	u8 tuner_is_baseband;
-	u8 mobile_mode;
-	int (*update_lna) (struct dvb_frontend *, u16 agc_global);
-
-	u8 agc_config_count;
-	struct dibx000_agc_config *agc;
-
-	struct dibx000_bandwidth_config *bw;
-
-#define DIB7000M_GPIO_DEFAULT_DIRECTIONS 0xffff
-	u16 gpio_dir;
-#define DIB7000M_GPIO_DEFAULT_VALUES     0x0000
-	u16 gpio_val;
-#define DIB7000M_GPIO_PWM_POS0(v)        ((v & 0xf) << 12)
-#define DIB7000M_GPIO_PWM_POS1(v)        ((v & 0xf) << 8 )
-#define DIB7000M_GPIO_PWM_POS2(v)        ((v & 0xf) << 4 )
-#define DIB7000M_GPIO_PWM_POS3(v)         (v & 0xf)
-#define DIB7000M_GPIO_DEFAULT_PWM_POS    0xffff
-	u16 gpio_pwm_pos;
-
-	u16 pwm_freq_div;
-
-	u8 quartz_direct;
-
-	u8 input_clk_is_div_2;
-
-	int (*agc_control) (struct dvb_frontend *, u8 before);
-};
-
-#define DEFAULT_DIB7000M_I2C_ADDRESS 18
-
-#if defined(CONFIG_DVB_DIB7000M) || (defined(CONFIG_DVB_DIB7000M_MODULE) && \
-				     defined(MODULE))
-extern struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap,
-					    u8 i2c_addr,
-					    struct dib7000m_config *cfg);
-extern struct i2c_adapter *dib7000m_get_i2c_master(struct dvb_frontend *,
-						   enum dibx000_i2c_interface,
-						   int);
-extern int dib7000m_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
-extern int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff);
-#else
-static inline
-struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap,
-				     u8 i2c_addr, struct dib7000m_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline
-struct i2c_adapter *dib7000m_get_i2c_master(struct dvb_frontend *demod,
-					    enum dibx000_i2c_interface intf,
-					    int gating)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-static inline int dib7000m_pid_filter(struct dvb_frontend *fe, u8 id,
-						u16 pid, u8 onoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe,
-						uint8_t onoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-#endif
-
-/* TODO
-extern INT dib7000m_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val);
-extern INT dib7000m_enable_vbg_voltage(struct dibDemod *demod);
-extern void dib7000m_set_hostbus_diversity(struct dibDemod *demod, UCHAR onoff);
-extern USHORT dib7000m_get_current_agc_global(struct dibDemod *demod);
-*/
-
-#endif
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
deleted file mode 100644
index 3e1eefa..0000000
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ /dev/null
@@ -1,2457 +0,0 @@
-/*
- * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).
- *
- * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
- *
- * 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, version 2.
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-
-#include "dvb_math.h"
-#include "dvb_frontend.h"
-
-#include "dib7000p.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
-
-static int buggy_sfn_workaround;
-module_param(buggy_sfn_workaround, int, 0644);
-MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
-
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)
-
-struct i2c_device {
-	struct i2c_adapter *i2c_adap;
-	u8 i2c_addr;
-};
-
-struct dib7000p_state {
-	struct dvb_frontend demod;
-	struct dib7000p_config cfg;
-
-	u8 i2c_addr;
-	struct i2c_adapter *i2c_adap;
-
-	struct dibx000_i2c_master i2c_master;
-
-	u16 wbd_ref;
-
-	u8 current_band;
-	u32 current_bandwidth;
-	struct dibx000_agc_config *current_agc;
-	u32 timf;
-
-	u8 div_force_off:1;
-	u8 div_state:1;
-	u16 div_sync_wait;
-
-	u8 agc_state;
-
-	u16 gpio_dir;
-	u16 gpio_val;
-
-	u8 sfn_workaround_active:1;
-
-#define SOC7090 0x7090
-	u16 version;
-
-	u16 tuner_enable;
-	struct i2c_adapter dib7090_tuner_adap;
-
-	/* for the I2C transfer */
-	struct i2c_msg msg[2];
-	u8 i2c_write_buffer[4];
-	u8 i2c_read_buffer[2];
-	struct mutex i2c_buffer_lock;
-
-	u8 input_mode_mpeg;
-};
-
-enum dib7000p_power_mode {
-	DIB7000P_POWER_ALL = 0,
-	DIB7000P_POWER_ANALOG_ADC,
-	DIB7000P_POWER_INTERFACE_ONLY,
-};
-
-/* dib7090 specific fonctions */
-static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
-static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
-static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode);
-static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode);
-
-static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
-{
-	u16 ret;
-
-	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return 0;
-	}
-
-	state->i2c_write_buffer[0] = reg >> 8;
-	state->i2c_write_buffer[1] = reg & 0xff;
-
-	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
-	state->msg[0].addr = state->i2c_addr >> 1;
-	state->msg[0].flags = 0;
-	state->msg[0].buf = state->i2c_write_buffer;
-	state->msg[0].len = 2;
-	state->msg[1].addr = state->i2c_addr >> 1;
-	state->msg[1].flags = I2C_M_RD;
-	state->msg[1].buf = state->i2c_read_buffer;
-	state->msg[1].len = 2;
-
-	if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
-		dprintk("i2c read error on %d", reg);
-
-	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
-	mutex_unlock(&state->i2c_buffer_lock);
-	return ret;
-}
-
-static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
-{
-	int ret;
-
-	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return -EINVAL;
-	}
-
-	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
-	state->i2c_write_buffer[1] = reg & 0xff;
-	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
-	state->i2c_write_buffer[3] = val & 0xff;
-
-	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
-	state->msg[0].addr = state->i2c_addr >> 1;
-	state->msg[0].flags = 0;
-	state->msg[0].buf = state->i2c_write_buffer;
-	state->msg[0].len = 4;
-
-	ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
-			-EREMOTEIO : 0);
-	mutex_unlock(&state->i2c_buffer_lock);
-	return ret;
-}
-
-static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
-{
-	u16 l = 0, r, *n;
-	n = buf;
-	l = *n++;
-	while (l) {
-		r = *n++;
-
-		do {
-			dib7000p_write_word(state, r, *n++);
-			r++;
-		} while (--l);
-		l = *n++;
-	}
-}
-
-static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
-{
-	int ret = 0;
-	u16 outreg, fifo_threshold, smo_mode;
-
-	outreg = 0;
-	fifo_threshold = 1792;
-	smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
-
-	dprintk("setting output mode for demod %p to %d", &state->demod, mode);
-
-	switch (mode) {
-	case OUTMODE_MPEG2_PAR_GATED_CLK:
-		outreg = (1 << 10);	/* 0x0400 */
-		break;
-	case OUTMODE_MPEG2_PAR_CONT_CLK:
-		outreg = (1 << 10) | (1 << 6);	/* 0x0440 */
-		break;
-	case OUTMODE_MPEG2_SERIAL:
-		outreg = (1 << 10) | (2 << 6) | (0 << 1);	/* 0x0480 */
-		break;
-	case OUTMODE_DIVERSITY:
-		if (state->cfg.hostbus_diversity)
-			outreg = (1 << 10) | (4 << 6);	/* 0x0500 */
-		else
-			outreg = (1 << 11);
-		break;
-	case OUTMODE_MPEG2_FIFO:
-		smo_mode |= (3 << 1);
-		fifo_threshold = 512;
-		outreg = (1 << 10) | (5 << 6);
-		break;
-	case OUTMODE_ANALOG_ADC:
-		outreg = (1 << 10) | (3 << 6);
-		break;
-	case OUTMODE_HIGH_Z:
-		outreg = 0;
-		break;
-	default:
-		dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod);
-		break;
-	}
-
-	if (state->cfg.output_mpeg2_in_188_bytes)
-		smo_mode |= (1 << 5);
-
-	ret |= dib7000p_write_word(state, 235, smo_mode);
-	ret |= dib7000p_write_word(state, 236, fifo_threshold);	/* synchronous fread */
-	if (state->version != SOC7090)
-		ret |= dib7000p_write_word(state, 1286, outreg);	/* P_Div_active */
-
-	return ret;
-}
-
-static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
-{
-	struct dib7000p_state *state = demod->demodulator_priv;
-
-	if (state->div_force_off) {
-		dprintk("diversity combination deactivated - forced by COFDM parameters");
-		onoff = 0;
-		dib7000p_write_word(state, 207, 0);
-	} else
-		dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
-
-	state->div_state = (u8) onoff;
-
-	if (onoff) {
-		dib7000p_write_word(state, 204, 6);
-		dib7000p_write_word(state, 205, 16);
-		/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
-	} else {
-		dib7000p_write_word(state, 204, 1);
-		dib7000p_write_word(state, 205, 0);
-	}
-
-	return 0;
-}
-
-static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
-{
-	/* by default everything is powered off */
-	u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
-
-	/* now, depending on the requested mode, we power on */
-	switch (mode) {
-		/* power up everything in the demod */
-	case DIB7000P_POWER_ALL:
-		reg_774 = 0x0000;
-		reg_775 = 0x0000;
-		reg_776 = 0x0;
-		reg_899 = 0x0;
-		if (state->version == SOC7090)
-			reg_1280 &= 0x001f;
-		else
-			reg_1280 &= 0x01ff;
-		break;
-
-	case DIB7000P_POWER_ANALOG_ADC:
-		/* dem, cfg, iqc, sad, agc */
-		reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
-		/* nud */
-		reg_776 &= ~((1 << 0));
-		/* Dout */
-		if (state->version != SOC7090)
-			reg_1280 &= ~((1 << 11));
-		reg_1280 &= ~(1 << 6);
-		/* fall through wanted to enable the interfaces */
-
-		/* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
-	case DIB7000P_POWER_INTERFACE_ONLY:	/* TODO power up either SDIO or I2C */
-		if (state->version == SOC7090)
-			reg_1280 &= ~((1 << 7) | (1 << 5));
-		else
-			reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
-		break;
-
-/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
-	}
-
-	dib7000p_write_word(state, 774, reg_774);
-	dib7000p_write_word(state, 775, reg_775);
-	dib7000p_write_word(state, 776, reg_776);
-	dib7000p_write_word(state, 1280, reg_1280);
-	if (state->version != SOC7090)
-		dib7000p_write_word(state, 899, reg_899);
-
-	return 0;
-}
-
-static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
-{
-	u16 reg_908 = 0, reg_909 = 0;
-	u16 reg;
-
-	if (state->version != SOC7090) {
-		reg_908 = dib7000p_read_word(state, 908);
-		reg_909 = dib7000p_read_word(state, 909);
-	}
-
-	switch (no) {
-	case DIBX000_SLOW_ADC_ON:
-		if (state->version == SOC7090) {
-			reg = dib7000p_read_word(state, 1925);
-
-			dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2));	/* en_slowAdc = 1 & reset_sladc = 1 */
-
-			reg = dib7000p_read_word(state, 1925);	/* read acces to make it works... strange ... */
-			msleep(200);
-			dib7000p_write_word(state, 1925, reg & ~(1 << 4));	/* en_slowAdc = 1 & reset_sladc = 0 */
-
-			reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));
-			dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524);	/* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */
-		} else {
-			reg_909 |= (1 << 1) | (1 << 0);
-			dib7000p_write_word(state, 909, reg_909);
-			reg_909 &= ~(1 << 1);
-		}
-		break;
-
-	case DIBX000_SLOW_ADC_OFF:
-		if (state->version == SOC7090) {
-			reg = dib7000p_read_word(state, 1925);
-			dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4));	/* reset_sladc = 1 en_slowAdc = 0 */
-		} else
-			reg_909 |= (1 << 1) | (1 << 0);
-		break;
-
-	case DIBX000_ADC_ON:
-		reg_908 &= 0x0fff;
-		reg_909 &= 0x0003;
-		break;
-
-	case DIBX000_ADC_OFF:
-		reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
-		reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
-		break;
-
-	case DIBX000_VBG_ENABLE:
-		reg_908 &= ~(1 << 15);
-		break;
-
-	case DIBX000_VBG_DISABLE:
-		reg_908 |= (1 << 15);
-		break;
-
-	default:
-		break;
-	}
-
-//	dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
-
-	reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
-	reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
-
-	if (state->version != SOC7090) {
-		dib7000p_write_word(state, 908, reg_908);
-		dib7000p_write_word(state, 909, reg_909);
-	}
-}
-
-static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
-{
-	u32 timf;
-
-	// store the current bandwidth for later use
-	state->current_bandwidth = bw;
-
-	if (state->timf == 0) {
-		dprintk("using default timf");
-		timf = state->cfg.bw->timf;
-	} else {
-		dprintk("using updated timf");
-		timf = state->timf;
-	}
-
-	timf = timf * (bw / 50) / 160;
-
-	dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
-	dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));
-
-	return 0;
-}
-
-static int dib7000p_sad_calib(struct dib7000p_state *state)
-{
-/* internal */
-	dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
-
-	if (state->version == SOC7090)
-		dib7000p_write_word(state, 74, 2048);
-	else
-		dib7000p_write_word(state, 74, 776);
-
-	/* do the calibration */
-	dib7000p_write_word(state, 73, (1 << 0));
-	dib7000p_write_word(state, 73, (0 << 0));
-
-	msleep(1);
-
-	return 0;
-}
-
-int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
-{
-	struct dib7000p_state *state = demod->demodulator_priv;
-	if (value > 4095)
-		value = 4095;
-	state->wbd_ref = value;
-	return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
-}
-EXPORT_SYMBOL(dib7000p_set_wbd_ref);
-
-int dib7000p_get_agc_values(struct dvb_frontend *fe,
-		u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
-{
-	struct dib7000p_state *state = fe->demodulator_priv;
-
-	if (agc_global != NULL)
-		*agc_global = dib7000p_read_word(state, 394);
-	if (agc1 != NULL)
-		*agc1 = dib7000p_read_word(state, 392);
-	if (agc2 != NULL)
-		*agc2 = dib7000p_read_word(state, 393);
-	if (wbd != NULL)
-		*wbd = dib7000p_read_word(state, 397);
-
-	return 0;
-}
-EXPORT_SYMBOL(dib7000p_get_agc_values);
-
-static void dib7000p_reset_pll(struct dib7000p_state *state)
-{
-	struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
-	u16 clk_cfg0;
-
-	if (state->version == SOC7090) {
-		dib7000p_write_word(state, 1856, (!bw->pll_reset << 13) | (bw->pll_range << 12) | (bw->pll_ratio << 6) | (bw->pll_prediv));
-
-		while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
-			;
-
-		dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
-	} else {
-		/* force PLL bypass */
-		clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
-			(bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
-
-		dib7000p_write_word(state, 900, clk_cfg0);
-
-		/* P_pll_cfg */
-		dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
-		clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
-		dib7000p_write_word(state, 900, clk_cfg0);
-	}
-
-	dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
-	dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
-	dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
-	dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
-
-	dib7000p_write_word(state, 72, bw->sad_cfg);
-}
-
-static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
-{
-	u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
-	internal |= (u32) dib7000p_read_word(state, 19);
-	internal /= 1000;
-
-	return internal;
-}
-
-int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
-{
-	struct dib7000p_state *state = fe->demodulator_priv;
-	u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
-	u8 loopdiv, prediv;
-	u32 internal, xtal;
-
-	/* get back old values */
-	prediv = reg_1856 & 0x3f;
-	loopdiv = (reg_1856 >> 6) & 0x3f;
-
-	if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
-		dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
-		reg_1856 &= 0xf000;
-		reg_1857 = dib7000p_read_word(state, 1857);
-		dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
-
-		dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
-
-		/* write new system clk into P_sec_len */
-		internal = dib7000p_get_internal_freq(state);
-		xtal = (internal / loopdiv) * prediv;
-		internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio;	/* new internal */
-		dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
-		dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
-
-		dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
-
-		while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
-			dprintk("Waiting for PLL to lock");
-
-		return 0;
-	}
-	return -EIO;
-}
-EXPORT_SYMBOL(dib7000p_update_pll);
-
-static int dib7000p_reset_gpio(struct dib7000p_state *st)
-{
-	/* reset the GPIOs */
-	dprintk("gpio dir: %x: val: %x, pwm_pos: %x", st->gpio_dir, st->gpio_val, st->cfg.gpio_pwm_pos);
-
-	dib7000p_write_word(st, 1029, st->gpio_dir);
-	dib7000p_write_word(st, 1030, st->gpio_val);
-
-	/* TODO 1031 is P_gpio_od */
-
-	dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
-
-	dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
-	return 0;
-}
-
-static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
-{
-	st->gpio_dir = dib7000p_read_word(st, 1029);
-	st->gpio_dir &= ~(1 << num);	/* reset the direction bit */
-	st->gpio_dir |= (dir & 0x1) << num;	/* set the new direction */
-	dib7000p_write_word(st, 1029, st->gpio_dir);
-
-	st->gpio_val = dib7000p_read_word(st, 1030);
-	st->gpio_val &= ~(1 << num);	/* reset the direction bit */
-	st->gpio_val |= (val & 0x01) << num;	/* set the new value */
-	dib7000p_write_word(st, 1030, st->gpio_val);
-
-	return 0;
-}
-
-int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
-{
-	struct dib7000p_state *state = demod->demodulator_priv;
-	return dib7000p_cfg_gpio(state, num, dir, val);
-}
-EXPORT_SYMBOL(dib7000p_set_gpio);
-
-static u16 dib7000p_defaults[] = {
-	// auto search configuration
-	3, 2,
-	0x0004,
-	(1<<3)|(1<<11)|(1<<12)|(1<<13),
-	0x0814,			/* Equal Lock */
-
-	12, 6,
-	0x001b,
-	0x7740,
-	0x005b,
-	0x8d80,
-	0x01c9,
-	0xc380,
-	0x0000,
-	0x0080,
-	0x0000,
-	0x0090,
-	0x0001,
-	0xd4c0,
-
-	1, 26,
-	0x6680,
-
-	/* set ADC level to -16 */
-	11, 79,
-	(1 << 13) - 825 - 117,
-	(1 << 13) - 837 - 117,
-	(1 << 13) - 811 - 117,
-	(1 << 13) - 766 - 117,
-	(1 << 13) - 737 - 117,
-	(1 << 13) - 693 - 117,
-	(1 << 13) - 648 - 117,
-	(1 << 13) - 619 - 117,
-	(1 << 13) - 575 - 117,
-	(1 << 13) - 531 - 117,
-	(1 << 13) - 501 - 117,
-
-	1, 142,
-	0x0410,
-
-	/* disable power smoothing */
-	8, 145,
-	0,
-	0,
-	0,
-	0,
-	0,
-	0,
-	0,
-	0,
-
-	1, 154,
-	1 << 13,
-
-	1, 168,
-	0x0ccd,
-
-	1, 183,
-	0x200f,
-
-	1, 212,
-		0x169,
-
-	5, 187,
-	0x023d,
-	0x00a4,
-	0x00a4,
-	0x7ff0,
-	0x3ccc,
-
-	1, 198,
-	0x800,
-
-	1, 222,
-	0x0010,
-
-	1, 235,
-	0x0062,
-
-	0,
-};
-
-static int dib7000p_demod_reset(struct dib7000p_state *state)
-{
-	dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
-
-	if (state->version == SOC7090)
-		dibx000_reset_i2c_master(&state->i2c_master);
-
-	dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
-
-	/* restart all parts */
-	dib7000p_write_word(state, 770, 0xffff);
-	dib7000p_write_word(state, 771, 0xffff);
-	dib7000p_write_word(state, 772, 0x001f);
-	dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
-
-	dib7000p_write_word(state, 770, 0);
-	dib7000p_write_word(state, 771, 0);
-	dib7000p_write_word(state, 772, 0);
-	dib7000p_write_word(state, 1280, 0);
-
-	if (state->version != SOC7090) {
-		dib7000p_write_word(state,  898, 0x0003);
-		dib7000p_write_word(state,  898, 0);
-	}
-
-	/* default */
-	dib7000p_reset_pll(state);
-
-	if (dib7000p_reset_gpio(state) != 0)
-		dprintk("GPIO reset was not successful.");
-
-	if (state->version == SOC7090) {
-		dib7000p_write_word(state, 899, 0);
-
-		/* impulse noise */
-		dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
-		dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
-		dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
-		dib7000p_write_word(state, 273, (0<<6) | 30);
-	}
-	if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
-		dprintk("OUTPUT_MODE could not be reset.");
-
-	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
-	dib7000p_sad_calib(state);
-	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
-
-	/* unforce divstr regardless whether i2c enumeration was done or not */
-	dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
-
-	dib7000p_set_bandwidth(state, 8000);
-
-	if (state->version == SOC7090) {
-		dib7000p_write_word(state, 36, 0x0755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
-	} else {
-		if (state->cfg.tuner_is_baseband)
-			dib7000p_write_word(state, 36, 0x0755);
-		else
-			dib7000p_write_word(state, 36, 0x1f55);
-	}
-
-	dib7000p_write_tab(state, dib7000p_defaults);
-	if (state->version != SOC7090) {
-		dib7000p_write_word(state, 901, 0x0006);
-		dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
-		dib7000p_write_word(state, 905, 0x2c8e);
-	}
-
-	dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
-
-	return 0;
-}
-
-static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
-{
-	u16 tmp = 0;
-	tmp = dib7000p_read_word(state, 903);
-	dib7000p_write_word(state, 903, (tmp | 0x1));
-	tmp = dib7000p_read_word(state, 900);
-	dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
-}
-
-static void dib7000p_restart_agc(struct dib7000p_state *state)
-{
-	// P_restart_iqc & P_restart_agc
-	dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
-	dib7000p_write_word(state, 770, 0x0000);
-}
-
-static int dib7000p_update_lna(struct dib7000p_state *state)
-{
-	u16 dyn_gain;
-
-	if (state->cfg.update_lna) {
-		dyn_gain = dib7000p_read_word(state, 394);
-		if (state->cfg.update_lna(&state->demod, dyn_gain)) {
-			dib7000p_restart_agc(state);
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
-{
-	struct dibx000_agc_config *agc = NULL;
-	int i;
-	if (state->current_band == band && state->current_agc != NULL)
-		return 0;
-	state->current_band = band;
-
-	for (i = 0; i < state->cfg.agc_config_count; i++)
-		if (state->cfg.agc[i].band_caps & band) {
-			agc = &state->cfg.agc[i];
-			break;
-		}
-
-	if (agc == NULL) {
-		dprintk("no valid AGC configuration found for band 0x%02x", band);
-		return -EINVAL;
-	}
-
-	state->current_agc = agc;
-
-	/* AGC */
-	dib7000p_write_word(state, 75, agc->setup);
-	dib7000p_write_word(state, 76, agc->inv_gain);
-	dib7000p_write_word(state, 77, agc->time_stabiliz);
-	dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
-
-	// Demod AGC loop configuration
-	dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
-	dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
-
-	/* AGC continued */
-	dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
-		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
-
-	if (state->wbd_ref != 0)
-		dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
-	else
-		dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
-
-	dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
-
-	dib7000p_write_word(state, 107, agc->agc1_max);
-	dib7000p_write_word(state, 108, agc->agc1_min);
-	dib7000p_write_word(state, 109, agc->agc2_max);
-	dib7000p_write_word(state, 110, agc->agc2_min);
-	dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
-	dib7000p_write_word(state, 112, agc->agc1_pt3);
-	dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
-	dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
-	dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
-	return 0;
-}
-
-static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
-{
-	u32 internal = dib7000p_get_internal_freq(state);
-	s32 unit_khz_dds_val = 67108864 / (internal);	/* 2**26 / Fsampling is the unit 1KHz offset */
-	u32 abs_offset_khz = ABS(offset_khz);
-	u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
-	u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
-
-	dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert);
-
-	if (offset_khz < 0)
-		unit_khz_dds_val *= -1;
-
-	/* IF tuner */
-	if (invert)
-		dds -= (abs_offset_khz * unit_khz_dds_val);	/* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */
-	else
-		dds += (abs_offset_khz * unit_khz_dds_val);
-
-	if (abs_offset_khz <= (internal / 2)) {	/* Max dds offset is the half of the demod freq */
-		dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
-		dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
-	}
-}
-
-static int dib7000p_agc_startup(struct dvb_frontend *demod)
-{
-	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
-	struct dib7000p_state *state = demod->demodulator_priv;
-	int ret = -1;
-	u8 *agc_state = &state->agc_state;
-	u8 agc_split;
-	u16 reg;
-	u32 upd_demod_gain_period = 0x1000;
-
-	switch (state->agc_state) {
-	case 0:
-		dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
-		if (state->version == SOC7090) {
-			reg = dib7000p_read_word(state, 0x79b) & 0xff00;
-			dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF);	/* lsb */
-			dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
-
-			/* enable adc i & q */
-			reg = dib7000p_read_word(state, 0x780);
-			dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
-		} else {
-			dib7000p_set_adc_state(state, DIBX000_ADC_ON);
-			dib7000p_pll_clk_cfg(state);
-		}
-
-		if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
-			return -1;
-
-		dib7000p_set_dds(state, 0);
-		ret = 7;
-		(*agc_state)++;
-		break;
-
-	case 1:
-		if (state->cfg.agc_control)
-			state->cfg.agc_control(&state->demod, 1);
-
-		dib7000p_write_word(state, 78, 32768);
-		if (!state->current_agc->perform_agc_softsplit) {
-			/* we are using the wbd - so slow AGC startup */
-			/* force 0 split on WBD and restart AGC */
-			dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
-			(*agc_state)++;
-			ret = 5;
-		} else {
-			/* default AGC startup */
-			(*agc_state) = 4;
-			/* wait AGC rough lock time */
-			ret = 7;
-		}
-
-		dib7000p_restart_agc(state);
-		break;
-
-	case 2:		/* fast split search path after 5sec */
-		dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4));	/* freeze AGC loop */
-		dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8));	/* fast split search 0.25kHz */
-		(*agc_state)++;
-		ret = 14;
-		break;
-
-	case 3:		/* split search ended */
-		agc_split = (u8) dib7000p_read_word(state, 396);	/* store the split value for the next time */
-		dib7000p_write_word(state, 78, dib7000p_read_word(state, 394));	/* set AGC gain start value */
-
-		dib7000p_write_word(state, 75, state->current_agc->setup);	/* std AGC loop */
-		dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split);	/* standard split search */
-
-		dib7000p_restart_agc(state);
-
-		dprintk("SPLIT %p: %hd", demod, agc_split);
-
-		(*agc_state)++;
-		ret = 5;
-		break;
-
-	case 4:		/* LNA startup */
-		ret = 7;
-
-		if (dib7000p_update_lna(state))
-			ret = 5;
-		else
-			(*agc_state)++;
-		break;
-
-	case 5:
-		if (state->cfg.agc_control)
-			state->cfg.agc_control(&state->demod, 0);
-		(*agc_state)++;
-		break;
-	default:
-		break;
-	}
-	return ret;
-}
-
-static void dib7000p_update_timf(struct dib7000p_state *state)
-{
-	u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
-	state->timf = timf * 160 / (state->current_bandwidth / 50);
-	dib7000p_write_word(state, 23, (u16) (timf >> 16));
-	dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
-	dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf);
-
-}
-
-u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
-{
-	struct dib7000p_state *state = fe->demodulator_priv;
-	switch (op) {
-	case DEMOD_TIMF_SET:
-		state->timf = timf;
-		break;
-	case DEMOD_TIMF_UPDATE:
-		dib7000p_update_timf(state);
-		break;
-	case DEMOD_TIMF_GET:
-		break;
-	}
-	dib7000p_set_bandwidth(state, state->current_bandwidth);
-	return state->timf;
-}
-EXPORT_SYMBOL(dib7000p_ctrl_timf);
-
-static void dib7000p_set_channel(struct dib7000p_state *state,
-				 struct dtv_frontend_properties *ch, u8 seq)
-{
-	u16 value, est[4];
-
-	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
-
-	/* nfft, guard, qam, alpha */
-	value = 0;
-	switch (ch->transmission_mode) {
-	case TRANSMISSION_MODE_2K:
-		value |= (0 << 7);
-		break;
-	case TRANSMISSION_MODE_4K:
-		value |= (2 << 7);
-		break;
-	default:
-	case TRANSMISSION_MODE_8K:
-		value |= (1 << 7);
-		break;
-	}
-	switch (ch->guard_interval) {
-	case GUARD_INTERVAL_1_32:
-		value |= (0 << 5);
-		break;
-	case GUARD_INTERVAL_1_16:
-		value |= (1 << 5);
-		break;
-	case GUARD_INTERVAL_1_4:
-		value |= (3 << 5);
-		break;
-	default:
-	case GUARD_INTERVAL_1_8:
-		value |= (2 << 5);
-		break;
-	}
-	switch (ch->modulation) {
-	case QPSK:
-		value |= (0 << 3);
-		break;
-	case QAM_16:
-		value |= (1 << 3);
-		break;
-	default:
-	case QAM_64:
-		value |= (2 << 3);
-		break;
-	}
-	switch (HIERARCHY_1) {
-	case HIERARCHY_2:
-		value |= 2;
-		break;
-	case HIERARCHY_4:
-		value |= 4;
-		break;
-	default:
-	case HIERARCHY_1:
-		value |= 1;
-		break;
-	}
-	dib7000p_write_word(state, 0, value);
-	dib7000p_write_word(state, 5, (seq << 4) | 1);	/* do not force tps, search list 0 */
-
-	/* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
-	value = 0;
-	if (1 != 0)
-		value |= (1 << 6);
-	if (ch->hierarchy == 1)
-		value |= (1 << 4);
-	if (1 == 1)
-		value |= 1;
-	switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
-	case FEC_2_3:
-		value |= (2 << 1);
-		break;
-	case FEC_3_4:
-		value |= (3 << 1);
-		break;
-	case FEC_5_6:
-		value |= (5 << 1);
-		break;
-	case FEC_7_8:
-		value |= (7 << 1);
-		break;
-	default:
-	case FEC_1_2:
-		value |= (1 << 1);
-		break;
-	}
-	dib7000p_write_word(state, 208, value);
-
-	/* offset loop parameters */
-	dib7000p_write_word(state, 26, 0x6680);
-	dib7000p_write_word(state, 32, 0x0003);
-	dib7000p_write_word(state, 29, 0x1273);
-	dib7000p_write_word(state, 33, 0x0005);
-
-	/* P_dvsy_sync_wait */
-	switch (ch->transmission_mode) {
-	case TRANSMISSION_MODE_8K:
-		value = 256;
-		break;
-	case TRANSMISSION_MODE_4K:
-		value = 128;
-		break;
-	case TRANSMISSION_MODE_2K:
-	default:
-		value = 64;
-		break;
-	}
-	switch (ch->guard_interval) {
-	case GUARD_INTERVAL_1_16:
-		value *= 2;
-		break;
-	case GUARD_INTERVAL_1_8:
-		value *= 4;
-		break;
-	case GUARD_INTERVAL_1_4:
-		value *= 8;
-		break;
-	default:
-	case GUARD_INTERVAL_1_32:
-		value *= 1;
-		break;
-	}
-	if (state->cfg.diversity_delay == 0)
-		state->div_sync_wait = (value * 3) / 2 + 48;
-	else
-		state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
-
-	/* deactive the possibility of diversity reception if extended interleaver */
-	state->div_force_off = !1 && ch->transmission_mode != TRANSMISSION_MODE_8K;
-	dib7000p_set_diversity_in(&state->demod, state->div_state);
-
-	/* channel estimation fine configuration */
-	switch (ch->modulation) {
-	case QAM_64:
-		est[0] = 0x0148;	/* P_adp_regul_cnt 0.04 */
-		est[1] = 0xfff0;	/* P_adp_noise_cnt -0.002 */
-		est[2] = 0x00a4;	/* P_adp_regul_ext 0.02 */
-		est[3] = 0xfff8;	/* P_adp_noise_ext -0.001 */
-		break;
-	case QAM_16:
-		est[0] = 0x023d;	/* P_adp_regul_cnt 0.07 */
-		est[1] = 0xffdf;	/* P_adp_noise_cnt -0.004 */
-		est[2] = 0x00a4;	/* P_adp_regul_ext 0.02 */
-		est[3] = 0xfff0;	/* P_adp_noise_ext -0.002 */
-		break;
-	default:
-		est[0] = 0x099a;	/* P_adp_regul_cnt 0.3 */
-		est[1] = 0xffae;	/* P_adp_noise_cnt -0.01 */
-		est[2] = 0x0333;	/* P_adp_regul_ext 0.1 */
-		est[3] = 0xfff8;	/* P_adp_noise_ext -0.002 */
-		break;
-	}
-	for (value = 0; value < 4; value++)
-		dib7000p_write_word(state, 187 + value, est[value]);
-}
-
-static int dib7000p_autosearch_start(struct dvb_frontend *demod)
-{
-	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
-	struct dib7000p_state *state = demod->demodulator_priv;
-	struct dtv_frontend_properties schan;
-	u32 value, factor;
-	u32 internal = dib7000p_get_internal_freq(state);
-
-	schan = *ch;
-	schan.modulation = QAM_64;
-	schan.guard_interval = GUARD_INTERVAL_1_32;
-	schan.transmission_mode = TRANSMISSION_MODE_8K;
-	schan.code_rate_HP = FEC_2_3;
-	schan.code_rate_LP = FEC_3_4;
-	schan.hierarchy = 0;
-
-	dib7000p_set_channel(state, &schan, 7);
-
-	factor = BANDWIDTH_TO_KHZ(ch->bandwidth_hz);
-	if (factor >= 5000) {
-		if (state->version == SOC7090)
-			factor = 2;
-		else
-			factor = 1;
-	} else
-		factor = 6;
-
-	value = 30 * internal * factor;
-	dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
-	dib7000p_write_word(state, 7, (u16) (value & 0xffff));
-	value = 100 * internal * factor;
-	dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
-	dib7000p_write_word(state, 9, (u16) (value & 0xffff));
-	value = 500 * internal * factor;
-	dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
-	dib7000p_write_word(state, 11, (u16) (value & 0xffff));
-
-	value = dib7000p_read_word(state, 0);
-	dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
-	dib7000p_read_word(state, 1284);
-	dib7000p_write_word(state, 0, (u16) value);
-
-	return 0;
-}
-
-static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
-{
-	struct dib7000p_state *state = demod->demodulator_priv;
-	u16 irq_pending = dib7000p_read_word(state, 1284);
-
-	if (irq_pending & 0x1)
-		return 1;
-
-	if (irq_pending & 0x2)
-		return 2;
-
-	return 0;
-}
-
-static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
-{
-	static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
-	static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
-		24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
-		53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
-		82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
-		107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
-		128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
-		147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
-		166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
-		183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
-		199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
-		213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
-		225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
-		235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
-		244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
-		250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
-		254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-		255, 255, 255, 255, 255, 255
-	};
-
-	u32 xtal = state->cfg.bw->xtal_hz / 1000;
-	int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
-	int k;
-	int coef_re[8], coef_im[8];
-	int bw_khz = bw;
-	u32 pha;
-
-	dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
-
-	if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
-		return;
-
-	bw_khz /= 100;
-
-	dib7000p_write_word(state, 142, 0x0610);
-
-	for (k = 0; k < 8; k++) {
-		pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
-
-		if (pha == 0) {
-			coef_re[k] = 256;
-			coef_im[k] = 0;
-		} else if (pha < 256) {
-			coef_re[k] = sine[256 - (pha & 0xff)];
-			coef_im[k] = sine[pha & 0xff];
-		} else if (pha == 256) {
-			coef_re[k] = 0;
-			coef_im[k] = 256;
-		} else if (pha < 512) {
-			coef_re[k] = -sine[pha & 0xff];
-			coef_im[k] = sine[256 - (pha & 0xff)];
-		} else if (pha == 512) {
-			coef_re[k] = -256;
-			coef_im[k] = 0;
-		} else if (pha < 768) {
-			coef_re[k] = -sine[256 - (pha & 0xff)];
-			coef_im[k] = -sine[pha & 0xff];
-		} else if (pha == 768) {
-			coef_re[k] = 0;
-			coef_im[k] = -256;
-		} else {
-			coef_re[k] = sine[pha & 0xff];
-			coef_im[k] = -sine[256 - (pha & 0xff)];
-		}
-
-		coef_re[k] *= notch[k];
-		coef_re[k] += (1 << 14);
-		if (coef_re[k] >= (1 << 24))
-			coef_re[k] = (1 << 24) - 1;
-		coef_re[k] /= (1 << 15);
-
-		coef_im[k] *= notch[k];
-		coef_im[k] += (1 << 14);
-		if (coef_im[k] >= (1 << 24))
-			coef_im[k] = (1 << 24) - 1;
-		coef_im[k] /= (1 << 15);
-
-		dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
-
-		dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
-		dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
-		dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
-	}
-	dib7000p_write_word(state, 143, 0);
-}
-
-static int dib7000p_tune(struct dvb_frontend *demod)
-{
-	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
-	struct dib7000p_state *state = demod->demodulator_priv;
-	u16 tmp = 0;
-
-	if (ch != NULL)
-		dib7000p_set_channel(state, ch, 0);
-	else
-		return -EINVAL;
-
-	// restart demod
-	dib7000p_write_word(state, 770, 0x4000);
-	dib7000p_write_word(state, 770, 0x0000);
-	msleep(45);
-
-	/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
-	tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
-	if (state->sfn_workaround_active) {
-		dprintk("SFN workaround is active");
-		tmp |= (1 << 9);
-		dib7000p_write_word(state, 166, 0x4000);
-	} else {
-		dib7000p_write_word(state, 166, 0x0000);
-	}
-	dib7000p_write_word(state, 29, tmp);
-
-	// never achieved a lock with that bandwidth so far - wait for osc-freq to update
-	if (state->timf == 0)
-		msleep(200);
-
-	/* offset loop parameters */
-
-	/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
-	tmp = (6 << 8) | 0x80;
-	switch (ch->transmission_mode) {
-	case TRANSMISSION_MODE_2K:
-		tmp |= (2 << 12);
-		break;
-	case TRANSMISSION_MODE_4K:
-		tmp |= (3 << 12);
-		break;
-	default:
-	case TRANSMISSION_MODE_8K:
-		tmp |= (4 << 12);
-		break;
-	}
-	dib7000p_write_word(state, 26, tmp);	/* timf_a(6xxx) */
-
-	/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
-	tmp = (0 << 4);
-	switch (ch->transmission_mode) {
-	case TRANSMISSION_MODE_2K:
-		tmp |= 0x6;
-		break;
-	case TRANSMISSION_MODE_4K:
-		tmp |= 0x7;
-		break;
-	default:
-	case TRANSMISSION_MODE_8K:
-		tmp |= 0x8;
-		break;
-	}
-	dib7000p_write_word(state, 32, tmp);
-
-	/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
-	tmp = (0 << 4);
-	switch (ch->transmission_mode) {
-	case TRANSMISSION_MODE_2K:
-		tmp |= 0x6;
-		break;
-	case TRANSMISSION_MODE_4K:
-		tmp |= 0x7;
-		break;
-	default:
-	case TRANSMISSION_MODE_8K:
-		tmp |= 0x8;
-		break;
-	}
-	dib7000p_write_word(state, 33, tmp);
-
-	tmp = dib7000p_read_word(state, 509);
-	if (!((tmp >> 6) & 0x1)) {
-		/* restart the fec */
-		tmp = dib7000p_read_word(state, 771);
-		dib7000p_write_word(state, 771, tmp | (1 << 1));
-		dib7000p_write_word(state, 771, tmp);
-		msleep(40);
-		tmp = dib7000p_read_word(state, 509);
-	}
-	// we achieved a lock - it's time to update the osc freq
-	if ((tmp >> 6) & 0x1) {
-		dib7000p_update_timf(state);
-		/* P_timf_alpha += 2 */
-		tmp = dib7000p_read_word(state, 26);
-		dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
-	}
-
-	if (state->cfg.spur_protect)
-		dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
-
-	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
-	return 0;
-}
-
-static int dib7000p_wakeup(struct dvb_frontend *demod)
-{
-	struct dib7000p_state *state = demod->demodulator_priv;
-	dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
-	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
-	if (state->version == SOC7090)
-		dib7000p_sad_calib(state);
-	return 0;
-}
-
-static int dib7000p_sleep(struct dvb_frontend *demod)
-{
-	struct dib7000p_state *state = demod->demodulator_priv;
-	if (state->version == SOC7090)
-		return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
-	return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
-}
-
-static int dib7000p_identify(struct dib7000p_state *st)
-{
-	u16 value;
-	dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr);
-
-	if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
-		dprintk("wrong Vendor ID (read=0x%x)", value);
-		return -EREMOTEIO;
-	}
-
-	if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
-		dprintk("wrong Device ID (%x)", value);
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static int dib7000p_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
-	struct dib7000p_state *state = fe->demodulator_priv;
-	u16 tps = dib7000p_read_word(state, 463);
-
-	fep->inversion = INVERSION_AUTO;
-
-	fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
-
-	switch ((tps >> 8) & 0x3) {
-	case 0:
-		fep->transmission_mode = TRANSMISSION_MODE_2K;
-		break;
-	case 1:
-		fep->transmission_mode = TRANSMISSION_MODE_8K;
-		break;
-	/* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
-	}
-
-	switch (tps & 0x3) {
-	case 0:
-		fep->guard_interval = GUARD_INTERVAL_1_32;
-		break;
-	case 1:
-		fep->guard_interval = GUARD_INTERVAL_1_16;
-		break;
-	case 2:
-		fep->guard_interval = GUARD_INTERVAL_1_8;
-		break;
-	case 3:
-		fep->guard_interval = GUARD_INTERVAL_1_4;
-		break;
-	}
-
-	switch ((tps >> 14) & 0x3) {
-	case 0:
-		fep->modulation = QPSK;
-		break;
-	case 1:
-		fep->modulation = QAM_16;
-		break;
-	case 2:
-	default:
-		fep->modulation = QAM_64;
-		break;
-	}
-
-	/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
-	/* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
-
-	fep->hierarchy = HIERARCHY_NONE;
-	switch ((tps >> 5) & 0x7) {
-	case 1:
-		fep->code_rate_HP = FEC_1_2;
-		break;
-	case 2:
-		fep->code_rate_HP = FEC_2_3;
-		break;
-	case 3:
-		fep->code_rate_HP = FEC_3_4;
-		break;
-	case 5:
-		fep->code_rate_HP = FEC_5_6;
-		break;
-	case 7:
-	default:
-		fep->code_rate_HP = FEC_7_8;
-		break;
-
-	}
-
-	switch ((tps >> 2) & 0x7) {
-	case 1:
-		fep->code_rate_LP = FEC_1_2;
-		break;
-	case 2:
-		fep->code_rate_LP = FEC_2_3;
-		break;
-	case 3:
-		fep->code_rate_LP = FEC_3_4;
-		break;
-	case 5:
-		fep->code_rate_LP = FEC_5_6;
-		break;
-	case 7:
-	default:
-		fep->code_rate_LP = FEC_7_8;
-		break;
-	}
-
-	/* native interleaver: (dib7000p_read_word(state, 464) >>  5) & 0x1 */
-
-	return 0;
-}
-
-static int dib7000p_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
-	struct dib7000p_state *state = fe->demodulator_priv;
-	int time, ret;
-
-	if (state->version == SOC7090)
-		dib7090_set_diversity_in(fe, 0);
-	else
-		dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
-
-	/* maybe the parameter has been changed */
-	state->sfn_workaround_active = buggy_sfn_workaround;
-
-	if (fe->ops.tuner_ops.set_params)
-		fe->ops.tuner_ops.set_params(fe);
-
-	/* start up the AGC */
-	state->agc_state = 0;
-	do {
-		time = dib7000p_agc_startup(fe);
-		if (time != -1)
-			msleep(time);
-	} while (time != -1);
-
-	if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
-		fep->guard_interval == GUARD_INTERVAL_AUTO || fep->modulation == QAM_AUTO || fep->code_rate_HP == FEC_AUTO) {
-		int i = 800, found;
-
-		dib7000p_autosearch_start(fe);
-		do {
-			msleep(1);
-			found = dib7000p_autosearch_is_irq(fe);
-		} while (found == 0 && i--);
-
-		dprintk("autosearch returns: %d", found);
-		if (found == 0 || found == 1)
-			return 0;
-
-		dib7000p_get_frontend(fe);
-	}
-
-	ret = dib7000p_tune(fe);
-
-	/* make this a config parameter */
-	if (state->version == SOC7090) {
-		dib7090_set_output_mode(fe, state->cfg.output_mode);
-		if (state->cfg.enMpegOutput == 0) {
-			dib7090_setDibTxMux(state, MPEG_ON_DIBTX);
-			dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
-		}
-	} else
-		dib7000p_set_output_mode(state, state->cfg.output_mode);
-
-	return ret;
-}
-
-static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
-{
-	struct dib7000p_state *state = fe->demodulator_priv;
-	u16 lock = dib7000p_read_word(state, 509);
-
-	*stat = 0;
-
-	if (lock & 0x8000)
-		*stat |= FE_HAS_SIGNAL;
-	if (lock & 0x3000)
-		*stat |= FE_HAS_CARRIER;
-	if (lock & 0x0100)
-		*stat |= FE_HAS_VITERBI;
-	if (lock & 0x0010)
-		*stat |= FE_HAS_SYNC;
-	if ((lock & 0x0038) == 0x38)
-		*stat |= FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
-{
-	struct dib7000p_state *state = fe->demodulator_priv;
-	*ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
-	return 0;
-}
-
-static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
-{
-	struct dib7000p_state *state = fe->demodulator_priv;
-	*unc = dib7000p_read_word(state, 506);
-	return 0;
-}
-
-static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
-{
-	struct dib7000p_state *state = fe->demodulator_priv;
-	u16 val = dib7000p_read_word(state, 394);
-	*strength = 65535 - val;
-	return 0;
-}
-
-static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
-{
-	struct dib7000p_state *state = fe->demodulator_priv;
-	u16 val;
-	s32 signal_mant, signal_exp, noise_mant, noise_exp;
-	u32 result = 0;
-
-	val = dib7000p_read_word(state, 479);
-	noise_mant = (val >> 4) & 0xff;
-	noise_exp = ((val & 0xf) << 2);
-	val = dib7000p_read_word(state, 480);
-	noise_exp += ((val >> 14) & 0x3);
-	if ((noise_exp & 0x20) != 0)
-		noise_exp -= 0x40;
-
-	signal_mant = (val >> 6) & 0xFF;
-	signal_exp = (val & 0x3F);
-	if ((signal_exp & 0x20) != 0)
-		signal_exp -= 0x40;
-
-	if (signal_mant != 0)
-		result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
-	else
-		result = intlog10(2) * 10 * signal_exp - 100;
-
-	if (noise_mant != 0)
-		result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
-	else
-		result -= intlog10(2) * 10 * noise_exp - 100;
-
-	*snr = result / ((1 << 24) / 10);
-	return 0;
-}
-
-static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
-{
-	tune->min_delay_ms = 1000;
-	return 0;
-}
-
-static void dib7000p_release(struct dvb_frontend *demod)
-{
-	struct dib7000p_state *st = demod->demodulator_priv;
-	dibx000_exit_i2c_master(&st->i2c_master);
-	i2c_del_adapter(&st->dib7090_tuner_adap);
-	kfree(st);
-}
-
-int dib7000pc_detection(struct i2c_adapter *i2c_adap)
-{
-	u8 *tx, *rx;
-	struct i2c_msg msg[2] = {
-		{.addr = 18 >> 1, .flags = 0, .len = 2},
-		{.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
-	};
-	int ret = 0;
-
-	tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
-	if (!tx)
-		return -ENOMEM;
-	rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
-	if (!rx) {
-		ret = -ENOMEM;
-		goto rx_memory_error;
-	}
-
-	msg[0].buf = tx;
-	msg[1].buf = rx;
-
-	tx[0] = 0x03;
-	tx[1] = 0x00;
-
-	if (i2c_transfer(i2c_adap, msg, 2) == 2)
-		if (rx[0] == 0x01 && rx[1] == 0xb3) {
-			dprintk("-D-  DiB7000PC detected");
-			return 1;
-		}
-
-	msg[0].addr = msg[1].addr = 0x40;
-
-	if (i2c_transfer(i2c_adap, msg, 2) == 2)
-		if (rx[0] == 0x01 && rx[1] == 0xb3) {
-			dprintk("-D-  DiB7000PC detected");
-			return 1;
-		}
-
-	dprintk("-D-  DiB7000PC not detected");
-
-	kfree(rx);
-rx_memory_error:
-	kfree(tx);
-	return ret;
-}
-EXPORT_SYMBOL(dib7000pc_detection);
-
-struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
-{
-	struct dib7000p_state *st = demod->demodulator_priv;
-	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
-}
-EXPORT_SYMBOL(dib7000p_get_i2c_master);
-
-int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
-{
-	struct dib7000p_state *state = fe->demodulator_priv;
-	u16 val = dib7000p_read_word(state, 235) & 0xffef;
-	val |= (onoff & 0x1) << 4;
-	dprintk("PID filter enabled %d", onoff);
-	return dib7000p_write_word(state, 235, val);
-}
-EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
-
-int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
-{
-	struct dib7000p_state *state = fe->demodulator_priv;
-	dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
-	return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
-}
-EXPORT_SYMBOL(dib7000p_pid_filter);
-
-int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
-{
-	struct dib7000p_state *dpst;
-	int k = 0;
-	u8 new_addr = 0;
-
-	dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
-	if (!dpst)
-		return -ENOMEM;
-
-	dpst->i2c_adap = i2c;
-	mutex_init(&dpst->i2c_buffer_lock);
-
-	for (k = no_of_demods - 1; k >= 0; k--) {
-		dpst->cfg = cfg[k];
-
-		/* designated i2c address */
-		if (cfg[k].default_i2c_addr != 0)
-			new_addr = cfg[k].default_i2c_addr + (k << 1);
-		else
-			new_addr = (0x40 + k) << 1;
-		dpst->i2c_addr = new_addr;
-		dib7000p_write_word(dpst, 1287, 0x0003);	/* sram lead in, rdy */
-		if (dib7000p_identify(dpst) != 0) {
-			dpst->i2c_addr = default_addr;
-			dib7000p_write_word(dpst, 1287, 0x0003);	/* sram lead in, rdy */
-			if (dib7000p_identify(dpst) != 0) {
-				dprintk("DiB7000P #%d: not identified\n", k);
-				kfree(dpst);
-				return -EIO;
-			}
-		}
-
-		/* start diversity to pull_down div_str - just for i2c-enumeration */
-		dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
-
-		/* set new i2c address and force divstart */
-		dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
-
-		dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
-	}
-
-	for (k = 0; k < no_of_demods; k++) {
-		dpst->cfg = cfg[k];
-		if (cfg[k].default_i2c_addr != 0)
-			dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
-		else
-			dpst->i2c_addr = (0x40 + k) << 1;
-
-		// unforce divstr
-		dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
-
-		/* deactivate div - it was just for i2c-enumeration */
-		dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
-	}
-
-	kfree(dpst);
-	return 0;
-}
-EXPORT_SYMBOL(dib7000p_i2c_enumeration);
-
-static const s32 lut_1000ln_mant[] = {
-	6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
-};
-
-static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
-{
-	struct dib7000p_state *state = fe->demodulator_priv;
-	u32 tmp_val = 0, exp = 0, mant = 0;
-	s32 pow_i;
-	u16 buf[2];
-	u8 ix = 0;
-
-	buf[0] = dib7000p_read_word(state, 0x184);
-	buf[1] = dib7000p_read_word(state, 0x185);
-	pow_i = (buf[0] << 16) | buf[1];
-	dprintk("raw pow_i = %d", pow_i);
-
-	tmp_val = pow_i;
-	while (tmp_val >>= 1)
-		exp++;
-
-	mant = (pow_i * 1000 / (1 << exp));
-	dprintk(" mant = %d exp = %d", mant / 1000, exp);
-
-	ix = (u8) ((mant - 1000) / 100);	/* index of the LUT */
-	dprintk(" ix = %d", ix);
-
-	pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
-	pow_i = (pow_i << 8) / 1000;
-	dprintk(" pow_i = %d", pow_i);
-
-	return pow_i;
-}
-
-static int map_addr_to_serpar_number(struct i2c_msg *msg)
-{
-	if ((msg->buf[0] <= 15))
-		msg->buf[0] -= 1;
-	else if (msg->buf[0] == 17)
-		msg->buf[0] = 15;
-	else if (msg->buf[0] == 16)
-		msg->buf[0] = 17;
-	else if (msg->buf[0] == 19)
-		msg->buf[0] = 16;
-	else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
-		msg->buf[0] -= 3;
-	else if (msg->buf[0] == 28)
-		msg->buf[0] = 23;
-	else
-		return -EINVAL;
-	return 0;
-}
-
-static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
-{
-	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
-	u8 n_overflow = 1;
-	u16 i = 1000;
-	u16 serpar_num = msg[0].buf[0];
-
-	while (n_overflow == 1 && i) {
-		n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
-		i--;
-		if (i == 0)
-			dprintk("Tuner ITF: write busy (overflow)");
-	}
-	dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
-	dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
-
-	return num;
-}
-
-static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
-{
-	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
-	u8 n_overflow = 1, n_empty = 1;
-	u16 i = 1000;
-	u16 serpar_num = msg[0].buf[0];
-	u16 read_word;
-
-	while (n_overflow == 1 && i) {
-		n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
-		i--;
-		if (i == 0)
-			dprintk("TunerITF: read busy (overflow)");
-	}
-	dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
-
-	i = 1000;
-	while (n_empty == 1 && i) {
-		n_empty = dib7000p_read_word(state, 1984) & 0x1;
-		i--;
-		if (i == 0)
-			dprintk("TunerITF: read busy (empty)");
-	}
-	read_word = dib7000p_read_word(state, 1987);
-	msg[1].buf[0] = (read_word >> 8) & 0xff;
-	msg[1].buf[1] = (read_word) & 0xff;
-
-	return num;
-}
-
-static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
-{
-	if (map_addr_to_serpar_number(&msg[0]) == 0) {	/* else = Tuner regs to ignore : DIG_CFG, CTRL_RF_LT, PLL_CFG, PWM1_REG, ADCCLK, DIG_CFG_3; SLEEP_EN... */
-		if (num == 1) {	/* write */
-			return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
-		} else {	/* read */
-			return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
-		}
-	}
-	return num;
-}
-
-static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap,
-		struct i2c_msg msg[], int num, u16 apb_address)
-{
-	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
-	u16 word;
-
-	if (num == 1) {		/* write */
-		dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
-	} else {
-		word = dib7000p_read_word(state, apb_address);
-		msg[1].buf[0] = (word >> 8) & 0xff;
-		msg[1].buf[1] = (word) & 0xff;
-	}
-
-	return num;
-}
-
-static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
-{
-	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
-
-	u16 apb_address = 0, word;
-	int i = 0;
-	switch (msg[0].buf[0]) {
-	case 0x12:
-		apb_address = 1920;
-		break;
-	case 0x14:
-		apb_address = 1921;
-		break;
-	case 0x24:
-		apb_address = 1922;
-		break;
-	case 0x1a:
-		apb_address = 1923;
-		break;
-	case 0x22:
-		apb_address = 1924;
-		break;
-	case 0x33:
-		apb_address = 1926;
-		break;
-	case 0x34:
-		apb_address = 1927;
-		break;
-	case 0x35:
-		apb_address = 1928;
-		break;
-	case 0x36:
-		apb_address = 1929;
-		break;
-	case 0x37:
-		apb_address = 1930;
-		break;
-	case 0x38:
-		apb_address = 1931;
-		break;
-	case 0x39:
-		apb_address = 1932;
-		break;
-	case 0x2a:
-		apb_address = 1935;
-		break;
-	case 0x2b:
-		apb_address = 1936;
-		break;
-	case 0x2c:
-		apb_address = 1937;
-		break;
-	case 0x2d:
-		apb_address = 1938;
-		break;
-	case 0x2e:
-		apb_address = 1939;
-		break;
-	case 0x2f:
-		apb_address = 1940;
-		break;
-	case 0x30:
-		apb_address = 1941;
-		break;
-	case 0x31:
-		apb_address = 1942;
-		break;
-	case 0x32:
-		apb_address = 1943;
-		break;
-	case 0x3e:
-		apb_address = 1944;
-		break;
-	case 0x3f:
-		apb_address = 1945;
-		break;
-	case 0x40:
-		apb_address = 1948;
-		break;
-	case 0x25:
-		apb_address = 914;
-		break;
-	case 0x26:
-		apb_address = 915;
-		break;
-	case 0x27:
-		apb_address = 917;
-		break;
-	case 0x28:
-		apb_address = 916;
-		break;
-	case 0x1d:
-		i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
-		word = dib7000p_read_word(state, 384 + i);
-		msg[1].buf[0] = (word >> 8) & 0xff;
-		msg[1].buf[1] = (word) & 0xff;
-		return num;
-	case 0x1f:
-		if (num == 1) {	/* write */
-			word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
-			word &= 0x3;
-			word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
-			dib7000p_write_word(state, 72, word);	/* Set the proper input */
-			return num;
-		}
-	}
-
-	if (apb_address != 0)	/* R/W acces via APB */
-		return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
-	else			/* R/W access via SERPAR  */
-		return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
-
-	return 0;
-}
-
-static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm dib7090_tuner_xfer_algo = {
-	.master_xfer = dib7090_tuner_xfer,
-	.functionality = dib7000p_i2c_func,
-};
-
-struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
-{
-	struct dib7000p_state *st = fe->demodulator_priv;
-	return &st->dib7090_tuner_adap;
-}
-EXPORT_SYMBOL(dib7090_get_i2c_tuner);
-
-static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
-{
-	u16 reg;
-
-	/* drive host bus 2, 3, 4 */
-	reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
-	reg |= (drive << 12) | (drive << 6) | drive;
-	dib7000p_write_word(state, 1798, reg);
-
-	/* drive host bus 5,6 */
-	reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
-	reg |= (drive << 8) | (drive << 2);
-	dib7000p_write_word(state, 1799, reg);
-
-	/* drive host bus 7, 8, 9 */
-	reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
-	reg |= (drive << 12) | (drive << 6) | drive;
-	dib7000p_write_word(state, 1800, reg);
-
-	/* drive host bus 10, 11 */
-	reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
-	reg |= (drive << 8) | (drive << 2);
-	dib7000p_write_word(state, 1801, reg);
-
-	/* drive host bus 12, 13, 14 */
-	reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
-	reg |= (drive << 12) | (drive << 6) | drive;
-	dib7000p_write_word(state, 1802, reg);
-
-	return 0;
-}
-
-static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
-{
-	u32 quantif = 3;
-	u32 nom = (insertExtSynchro * P_Kin + syncSize);
-	u32 denom = P_Kout;
-	u32 syncFreq = ((nom << quantif) / denom);
-
-	if ((syncFreq & ((1 << quantif) - 1)) != 0)
-		syncFreq = (syncFreq >> quantif) + 1;
-	else
-		syncFreq = (syncFreq >> quantif);
-
-	if (syncFreq != 0)
-		syncFreq = syncFreq - 1;
-
-	return syncFreq;
-}
-
-static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
-{
-	dprintk("Configure DibStream Tx");
-
-	dib7000p_write_word(state, 1615, 1);
-	dib7000p_write_word(state, 1603, P_Kin);
-	dib7000p_write_word(state, 1605, P_Kout);
-	dib7000p_write_word(state, 1606, insertExtSynchro);
-	dib7000p_write_word(state, 1608, synchroMode);
-	dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
-	dib7000p_write_word(state, 1610, syncWord & 0xffff);
-	dib7000p_write_word(state, 1612, syncSize);
-	dib7000p_write_word(state, 1615, 0);
-
-	return 0;
-}
-
-static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,
-		u32 dataOutRate)
-{
-	u32 syncFreq;
-
-	dprintk("Configure DibStream Rx");
-	if ((P_Kin != 0) && (P_Kout != 0)) {
-		syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
-		dib7000p_write_word(state, 1542, syncFreq);
-	}
-	dib7000p_write_word(state, 1554, 1);
-	dib7000p_write_word(state, 1536, P_Kin);
-	dib7000p_write_word(state, 1537, P_Kout);
-	dib7000p_write_word(state, 1539, synchroMode);
-	dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
-	dib7000p_write_word(state, 1541, syncWord & 0xffff);
-	dib7000p_write_word(state, 1543, syncSize);
-	dib7000p_write_word(state, 1544, dataOutRate);
-	dib7000p_write_word(state, 1554, 0);
-
-	return 0;
-}
-
-static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff)
-{
-	u16 reg_1287 = dib7000p_read_word(state, 1287);
-
-	switch (onoff) {
-	case 1:
-			reg_1287 &= ~(1<<7);
-			break;
-	case 0:
-			reg_1287 |= (1<<7);
-			break;
-	}
-
-	dib7000p_write_word(state, 1287, reg_1287);
-}
-
-static void dib7090_configMpegMux(struct dib7000p_state *state,
-		u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
-{
-	dprintk("Enable Mpeg mux");
-
-	dib7090_enMpegMux(state, 0);
-
-	/* If the input mode is MPEG do not divide the serial clock */
-	if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
-		enSerialClkDiv2 = 0;
-
-	dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2)
-			| ((enSerialMode & 0x1) << 1)
-			| (enSerialClkDiv2 & 0x1));
-
-	dib7090_enMpegMux(state, 1);
-}
-
-static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode)
-{
-	u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7);
-
-	switch (mode) {
-	case MPEG_ON_DIBTX:
-			dprintk("SET MPEG ON DIBSTREAM TX");
-			dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
-			reg_1288 |= (1<<9);
-			break;
-	case DIV_ON_DIBTX:
-			dprintk("SET DIV_OUT ON DIBSTREAM TX");
-			dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
-			reg_1288 |= (1<<8);
-			break;
-	case ADC_ON_DIBTX:
-			dprintk("SET ADC_OUT ON DIBSTREAM TX");
-			dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
-			reg_1288 |= (1<<7);
-			break;
-	default:
-			break;
-	}
-	dib7000p_write_word(state, 1288, reg_1288);
-}
-
-static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
-{
-	u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4);
-
-	switch (mode) {
-	case DEMOUT_ON_HOSTBUS:
-			dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
-			dib7090_enMpegMux(state, 0);
-			reg_1288 |= (1<<6);
-			break;
-	case DIBTX_ON_HOSTBUS:
-			dprintk("SET DIBSTREAM TX ON HOST BUS");
-			dib7090_enMpegMux(state, 0);
-			reg_1288 |= (1<<5);
-			break;
-	case MPEG_ON_HOSTBUS:
-			dprintk("SET MPEG MUX ON HOST BUS");
-			reg_1288 |= (1<<4);
-			break;
-	default:
-			break;
-	}
-	dib7000p_write_word(state, 1288, reg_1288);
-}
-
-int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
-{
-	struct dib7000p_state *state = fe->demodulator_priv;
-	u16 reg_1287;
-
-	switch (onoff) {
-	case 0: /* only use the internal way - not the diversity input */
-			dprintk("%s mode OFF : by default Enable Mpeg INPUT", __func__);
-			dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
-
-			/* Do not divide the serial clock of MPEG MUX */
-			/* in SERIAL MODE in case input mode MPEG is used */
-			reg_1287 = dib7000p_read_word(state, 1287);
-			/* enSerialClkDiv2 == 1 ? */
-			if ((reg_1287 & 0x1) == 1) {
-				/* force enSerialClkDiv2 = 0 */
-				reg_1287 &= ~0x1;
-				dib7000p_write_word(state, 1287, reg_1287);
-			}
-			state->input_mode_mpeg = 1;
-			break;
-	case 1: /* both ways */
-	case 2: /* only the diversity input */
-			dprintk("%s ON : Enable diversity INPUT", __func__);
-			dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
-			state->input_mode_mpeg = 0;
-			break;
-	}
-
-	dib7000p_set_diversity_in(&state->demod, onoff);
-	return 0;
-}
-
-static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
-{
-	struct dib7000p_state *state = fe->demodulator_priv;
-
-	u16 outreg, smo_mode, fifo_threshold;
-	u8 prefer_mpeg_mux_use = 1;
-	int ret = 0;
-
-	dib7090_host_bus_drive(state, 1);
-
-	fifo_threshold = 1792;
-	smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
-	outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
-
-	switch (mode) {
-	case OUTMODE_HIGH_Z:
-		outreg = 0;
-		break;
-
-	case OUTMODE_MPEG2_SERIAL:
-		if (prefer_mpeg_mux_use) {
-			dprintk("setting output mode TS_SERIAL using Mpeg Mux");
-			dib7090_configMpegMux(state, 3, 1, 1);
-			dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
-		} else {/* Use Smooth block */
-			dprintk("setting output mode TS_SERIAL using Smooth bloc");
-			dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
-			outreg |= (2<<6) | (0 << 1);
-		}
-		break;
-
-	case OUTMODE_MPEG2_PAR_GATED_CLK:
-		if (prefer_mpeg_mux_use) {
-			dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux");
-			dib7090_configMpegMux(state, 2, 0, 0);
-			dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
-		} else { /* Use Smooth block */
-			dprintk("setting output mode TS_PARALLEL_GATED using Smooth block");
-			dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
-			outreg |= (0<<6);
-		}
-		break;
-
-	case OUTMODE_MPEG2_PAR_CONT_CLK:	/* Using Smooth block only */
-		dprintk("setting output mode TS_PARALLEL_CONT using Smooth block");
-		dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
-		outreg |= (1<<6);
-		break;
-
-	case OUTMODE_MPEG2_FIFO:	/* Using Smooth block because not supported by new Mpeg Mux bloc */
-		dprintk("setting output mode TS_FIFO using Smooth block");
-		dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
-		outreg |= (5<<6);
-		smo_mode |= (3 << 1);
-		fifo_threshold = 512;
-		break;
-
-	case OUTMODE_DIVERSITY:
-		dprintk("setting output mode MODE_DIVERSITY");
-		dib7090_setDibTxMux(state, DIV_ON_DIBTX);
-		dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
-		break;
-
-	case OUTMODE_ANALOG_ADC:
-		dprintk("setting output mode MODE_ANALOG_ADC");
-		dib7090_setDibTxMux(state, ADC_ON_DIBTX);
-		dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
-		break;
-	}
-	if (mode != OUTMODE_HIGH_Z)
-		outreg |= (1 << 10);
-
-	if (state->cfg.output_mpeg2_in_188_bytes)
-		smo_mode |= (1 << 5);
-
-	ret |= dib7000p_write_word(state, 235, smo_mode);
-	ret |= dib7000p_write_word(state, 236, fifo_threshold);	/* synchronous fread */
-	ret |= dib7000p_write_word(state, 1286, outreg);
-
-	return ret;
-}
-
-int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
-{
-	struct dib7000p_state *state = fe->demodulator_priv;
-	u16 en_cur_state;
-
-	dprintk("sleep dib7090: %d", onoff);
-
-	en_cur_state = dib7000p_read_word(state, 1922);
-
-	if (en_cur_state > 0xff)
-		state->tuner_enable = en_cur_state;
-
-	if (onoff)
-		en_cur_state &= 0x00ff;
-	else {
-		if (state->tuner_enable != 0)
-			en_cur_state = state->tuner_enable;
-	}
-
-	dib7000p_write_word(state, 1922, en_cur_state);
-
-	return 0;
-}
-EXPORT_SYMBOL(dib7090_tuner_sleep);
-
-int dib7090_get_adc_power(struct dvb_frontend *fe)
-{
-	return dib7000p_get_adc_power(fe);
-}
-EXPORT_SYMBOL(dib7090_get_adc_power);
-
-int dib7090_slave_reset(struct dvb_frontend *fe)
-{
-	struct dib7000p_state *state = fe->demodulator_priv;
-	u16 reg;
-
-	reg = dib7000p_read_word(state, 1794);
-	dib7000p_write_word(state, 1794, reg | (4 << 12));
-
-	dib7000p_write_word(state, 1032, 0xffff);
-	return 0;
-}
-EXPORT_SYMBOL(dib7090_slave_reset);
-
-static struct dvb_frontend_ops dib7000p_ops;
-struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
-{
-	struct dvb_frontend *demod;
-	struct dib7000p_state *st;
-	st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
-	if (st == NULL)
-		return NULL;
-
-	memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
-	st->i2c_adap = i2c_adap;
-	st->i2c_addr = i2c_addr;
-	st->gpio_val = cfg->gpio_val;
-	st->gpio_dir = cfg->gpio_dir;
-
-	/* Ensure the output mode remains at the previous default if it's
-	 * not specifically set by the caller.
-	 */
-	if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
-		st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
-
-	demod = &st->demod;
-	demod->demodulator_priv = st;
-	memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
-	mutex_init(&st->i2c_buffer_lock);
-
-	dib7000p_write_word(st, 1287, 0x0003);	/* sram lead in, rdy */
-
-	if (dib7000p_identify(st) != 0)
-		goto error;
-
-	st->version = dib7000p_read_word(st, 897);
-
-	/* FIXME: make sure the dev.parent field is initialized, or else
-	   request_firmware() will hit an OOPS (this should be moved somewhere
-	   more common) */
-	st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
-
-	dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
-
-	/* init 7090 tuner adapter */
-	strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));
-	st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
-	st->dib7090_tuner_adap.algo_data = NULL;
-	st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
-	i2c_set_adapdata(&st->dib7090_tuner_adap, st);
-	i2c_add_adapter(&st->dib7090_tuner_adap);
-
-	dib7000p_demod_reset(st);
-
-	if (st->version == SOC7090) {
-		dib7090_set_output_mode(demod, st->cfg.output_mode);
-		dib7090_set_diversity_in(demod, 0);
-	}
-
-	return demod;
-
-error:
-	kfree(st);
-	return NULL;
-}
-EXPORT_SYMBOL(dib7000p_attach);
-
-static struct dvb_frontend_ops dib7000p_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		 .name = "DiBcom 7000PC",
-		 .frequency_min = 44250000,
-		 .frequency_max = 867250000,
-		 .frequency_stepsize = 62500,
-		 .caps = FE_CAN_INVERSION_AUTO |
-		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
-		 },
-
-	.release = dib7000p_release,
-
-	.init = dib7000p_wakeup,
-	.sleep = dib7000p_sleep,
-
-	.set_frontend = dib7000p_set_frontend,
-	.get_tune_settings = dib7000p_fe_get_tune_settings,
-	.get_frontend = dib7000p_get_frontend,
-
-	.read_status = dib7000p_read_status,
-	.read_ber = dib7000p_read_ber,
-	.read_signal_strength = dib7000p_read_signal_strength,
-	.read_snr = dib7000p_read_snr,
-	.read_ucblocks = dib7000p_read_unc_blocks,
-};
-
-MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
-MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
-MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h
deleted file mode 100644
index b61b03a..0000000
--- a/drivers/media/dvb/frontends/dib7000p.h
+++ /dev/null
@@ -1,158 +0,0 @@
-#ifndef DIB7000P_H
-#define DIB7000P_H
-
-#include "dibx000_common.h"
-
-struct dib7000p_config {
-	u8 output_mpeg2_in_188_bytes;
-	u8 hostbus_diversity;
-	u8 tuner_is_baseband;
-	int (*update_lna) (struct dvb_frontend *, u16 agc_global);
-
-	u8 agc_config_count;
-	struct dibx000_agc_config *agc;
-	struct dibx000_bandwidth_config *bw;
-
-#define DIB7000P_GPIO_DEFAULT_DIRECTIONS 0xffff
-	u16 gpio_dir;
-#define DIB7000P_GPIO_DEFAULT_VALUES     0x0000
-	u16 gpio_val;
-#define DIB7000P_GPIO_PWM_POS0(v)        ((v & 0xf) << 12)
-#define DIB7000P_GPIO_PWM_POS1(v)        ((v & 0xf) << 8 )
-#define DIB7000P_GPIO_PWM_POS2(v)        ((v & 0xf) << 4 )
-#define DIB7000P_GPIO_PWM_POS3(v)         (v & 0xf)
-#define DIB7000P_GPIO_DEFAULT_PWM_POS    0xffff
-	u16 gpio_pwm_pos;
-
-	u16 pwm_freq_div;
-
-	u8 quartz_direct;
-
-	u8 spur_protect;
-
-	int (*agc_control) (struct dvb_frontend *, u8 before);
-
-	u8 output_mode;
-	u8 disable_sample_and_hold:1;
-
-	u8 enable_current_mirror:1;
-	u16 diversity_delay;
-
-	u8 default_i2c_addr;
-	u8 enMpegOutput:1;
-};
-
-#define DEFAULT_DIB7000P_I2C_ADDRESS 18
-
-#if defined(CONFIG_DVB_DIB7000P) || (defined(CONFIG_DVB_DIB7000P_MODULE) && \
-					defined(MODULE))
-extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg);
-extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
-extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
-extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
-extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
-extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
-extern int dib7000p_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
-extern int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff);
-extern int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw);
-extern u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf);
-extern int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff);
-extern int dib7090_get_adc_power(struct dvb_frontend *fe);
-extern struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe);
-extern int dib7090_slave_reset(struct dvb_frontend *fe);
-extern int dib7000p_get_agc_values(struct dvb_frontend *fe,
-		u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd);
-#else
-static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface i, int x)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7000pc_detection(struct i2c_adapter *i2c_adap)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, uint8_t onoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return 0;
-}
-
-static inline int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7090_get_adc_power(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline int dib7090_slave_reset(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7000p_get_agc_values(struct dvb_frontend *fe,
-		u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-#endif
-
-#endif
diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c
deleted file mode 100644
index 1f3bcb5..0000000
--- a/drivers/media/dvb/frontends/dib8000.c
+++ /dev/null
@@ -1,3560 +0,0 @@
-/*
- * Linux-DVB Driver for DiBcom's DiB8000 chip (ISDB-T).
- *
- * Copyright (C) 2009 DiBcom (http://www.dibcom.fr/)
- *
- * 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, version 2.
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-
-#include "dvb_math.h"
-
-#include "dvb_frontend.h"
-
-#include "dib8000.h"
-
-#define LAYER_ALL -1
-#define LAYER_A   1
-#define LAYER_B   2
-#define LAYER_C   3
-
-#define FE_CALLBACK_TIME_NEVER 0xffffffff
-#define MAX_NUMBER_OF_FRONTENDS 6
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
-
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0)
-
-#define FE_STATUS_TUNE_FAILED 0
-
-struct i2c_device {
-	struct i2c_adapter *adap;
-	u8 addr;
-	u8 *i2c_write_buffer;
-	u8 *i2c_read_buffer;
-	struct mutex *i2c_buffer_lock;
-};
-
-struct dib8000_state {
-	struct dib8000_config cfg;
-
-	struct i2c_device i2c;
-
-	struct dibx000_i2c_master i2c_master;
-
-	u16 wbd_ref;
-
-	u8 current_band;
-	u32 current_bandwidth;
-	struct dibx000_agc_config *current_agc;
-	u32 timf;
-	u32 timf_default;
-
-	u8 div_force_off:1;
-	u8 div_state:1;
-	u16 div_sync_wait;
-
-	u8 agc_state;
-	u8 differential_constellation;
-	u8 diversity_onoff;
-
-	s16 ber_monitored_layer;
-	u16 gpio_dir;
-	u16 gpio_val;
-
-	u16 revision;
-	u8 isdbt_cfg_loaded;
-	enum frontend_tune_state tune_state;
-	u32 status;
-
-	struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
-
-	/* for the I2C transfer */
-	struct i2c_msg msg[2];
-	u8 i2c_write_buffer[4];
-	u8 i2c_read_buffer[2];
-	struct mutex i2c_buffer_lock;
-	u8 input_mode_mpeg;
-
-	u16 tuner_enable;
-	struct i2c_adapter dib8096p_tuner_adap;
-};
-
-enum dib8000_power_mode {
-	DIB8000_POWER_ALL = 0,
-	DIB8000_POWER_INTERFACE_ONLY,
-};
-
-static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
-{
-	u16 ret;
-	struct i2c_msg msg[2] = {
-		{.addr = i2c->addr >> 1, .flags = 0, .len = 2},
-		{.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
-	};
-
-	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return 0;
-	}
-
-	msg[0].buf    = i2c->i2c_write_buffer;
-	msg[0].buf[0] = reg >> 8;
-	msg[0].buf[1] = reg & 0xff;
-	msg[1].buf    = i2c->i2c_read_buffer;
-
-	if (i2c_transfer(i2c->adap, msg, 2) != 2)
-		dprintk("i2c read error on %d", reg);
-
-	ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
-	mutex_unlock(i2c->i2c_buffer_lock);
-	return ret;
-}
-
-static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
-{
-	u16 ret;
-
-	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return 0;
-	}
-
-	state->i2c_write_buffer[0] = reg >> 8;
-	state->i2c_write_buffer[1] = reg & 0xff;
-
-	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
-	state->msg[0].addr = state->i2c.addr >> 1;
-	state->msg[0].flags = 0;
-	state->msg[0].buf = state->i2c_write_buffer;
-	state->msg[0].len = 2;
-	state->msg[1].addr = state->i2c.addr >> 1;
-	state->msg[1].flags = I2C_M_RD;
-	state->msg[1].buf = state->i2c_read_buffer;
-	state->msg[1].len = 2;
-
-	if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
-		dprintk("i2c read error on %d", reg);
-
-	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
-	mutex_unlock(&state->i2c_buffer_lock);
-
-	return ret;
-}
-
-static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
-{
-	u16 rw[2];
-
-	rw[0] = dib8000_read_word(state, reg + 0);
-	rw[1] = dib8000_read_word(state, reg + 1);
-
-	return ((rw[0] << 16) | (rw[1]));
-}
-
-static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
-{
-	struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
-	int ret = 0;
-
-	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return -EINVAL;
-	}
-
-	msg.buf    = i2c->i2c_write_buffer;
-	msg.buf[0] = (reg >> 8) & 0xff;
-	msg.buf[1] = reg & 0xff;
-	msg.buf[2] = (val >> 8) & 0xff;
-	msg.buf[3] = val & 0xff;
-
-	ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
-	mutex_unlock(i2c->i2c_buffer_lock);
-
-	return ret;
-}
-
-static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
-{
-	int ret;
-
-	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return -EINVAL;
-	}
-
-	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
-	state->i2c_write_buffer[1] = reg & 0xff;
-	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
-	state->i2c_write_buffer[3] = val & 0xff;
-
-	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
-	state->msg[0].addr = state->i2c.addr >> 1;
-	state->msg[0].flags = 0;
-	state->msg[0].buf = state->i2c_write_buffer;
-	state->msg[0].len = 4;
-
-	ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
-			-EREMOTEIO : 0);
-	mutex_unlock(&state->i2c_buffer_lock);
-
-	return ret;
-}
-
-static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
-	(769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c,
-		(920 << 5) | 0x09
-};
-
-static const s16 coeff_2k_sb_1seg[8] = {
-	(692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
-};
-
-static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
-	(832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11,
-		(-931 << 5) | 0x0f
-};
-
-static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {
-	(622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e,
-		(982 << 5) | 0x0c
-};
-
-static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {
-	(699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12,
-		(-720 << 5) | 0x0d
-};
-
-static const s16 coeff_2k_sb_3seg[8] = {
-	(664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e,
-		(-610 << 5) | 0x0a
-};
-
-static const s16 coeff_4k_sb_1seg_dqpsk[8] = {
-	(-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f,
-		(-922 << 5) | 0x0d
-};
-
-static const s16 coeff_4k_sb_1seg[8] = {
-	(638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d,
-		(-655 << 5) | 0x0a
-};
-
-static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
-	(-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14,
-		(-958 << 5) | 0x13
-};
-
-static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {
-	(-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12,
-		(-568 << 5) | 0x0f
-};
-
-static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {
-	(-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14,
-		(-848 << 5) | 0x13
-};
-
-static const s16 coeff_4k_sb_3seg[8] = {
-	(612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12,
-		(-869 << 5) | 0x13
-};
-
-static const s16 coeff_8k_sb_1seg_dqpsk[8] = {
-	(-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13,
-		(-598 << 5) | 0x10
-};
-
-static const s16 coeff_8k_sb_1seg[8] = {
-	(673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f,
-		(585 << 5) | 0x0f
-};
-
-static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
-	(863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18,
-		(0 << 5) | 0x14
-};
-
-static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {
-	(-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15,
-		(-877 << 5) | 0x15
-};
-
-static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {
-	(-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18,
-		(-921 << 5) | 0x14
-};
-
-static const s16 coeff_8k_sb_3seg[8] = {
-	(514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15,
-		(690 << 5) | 0x14
-};
-
-static const s16 ana_fe_coeff_3seg[24] = {
-	81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017
-};
-
-static const s16 ana_fe_coeff_1seg[24] = {
-	249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003
-};
-
-static const s16 ana_fe_coeff_13seg[24] = {
-	396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1
-};
-
-static u16 fft_to_mode(struct dib8000_state *state)
-{
-	u16 mode;
-	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
-	case TRANSMISSION_MODE_2K:
-		mode = 1;
-		break;
-	case TRANSMISSION_MODE_4K:
-		mode = 2;
-		break;
-	default:
-	case TRANSMISSION_MODE_AUTO:
-	case TRANSMISSION_MODE_8K:
-		mode = 3;
-		break;
-	}
-	return mode;
-}
-
-static void dib8000_set_acquisition_mode(struct dib8000_state *state)
-{
-	u16 nud = dib8000_read_word(state, 298);
-	nud |= (1 << 3) | (1 << 0);
-	dprintk("acquisition mode activated");
-	dib8000_write_word(state, 298, nud);
-}
-static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-
-	u16 outreg, fifo_threshold, smo_mode, sram = 0x0205;	/* by default SDRAM deintlv is enabled */
-
-	outreg = 0;
-	fifo_threshold = 1792;
-	smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
-
-	dprintk("-I-	Setting output mode for demod %p to %d",
-			&state->fe[0], mode);
-
-	switch (mode) {
-	case OUTMODE_MPEG2_PAR_GATED_CLK:	// STBs with parallel gated clock
-		outreg = (1 << 10);	/* 0x0400 */
-		break;
-	case OUTMODE_MPEG2_PAR_CONT_CLK:	// STBs with parallel continues clock
-		outreg = (1 << 10) | (1 << 6);	/* 0x0440 */
-		break;
-	case OUTMODE_MPEG2_SERIAL:	// STBs with serial input
-		outreg = (1 << 10) | (2 << 6) | (0 << 1);	/* 0x0482 */
-		break;
-	case OUTMODE_DIVERSITY:
-		if (state->cfg.hostbus_diversity) {
-			outreg = (1 << 10) | (4 << 6);	/* 0x0500 */
-			sram &= 0xfdff;
-		} else
-			sram |= 0x0c00;
-		break;
-	case OUTMODE_MPEG2_FIFO:	// e.g. USB feeding
-		smo_mode |= (3 << 1);
-		fifo_threshold = 512;
-		outreg = (1 << 10) | (5 << 6);
-		break;
-	case OUTMODE_HIGH_Z:	// disable
-		outreg = 0;
-		break;
-
-	case OUTMODE_ANALOG_ADC:
-		outreg = (1 << 10) | (3 << 6);
-		dib8000_set_acquisition_mode(state);
-		break;
-
-	default:
-		dprintk("Unhandled output_mode passed to be set for demod %p",
-				&state->fe[0]);
-		return -EINVAL;
-	}
-
-	if (state->cfg.output_mpeg2_in_188_bytes)
-		smo_mode |= (1 << 5);
-
-	dib8000_write_word(state, 299, smo_mode);
-	dib8000_write_word(state, 300, fifo_threshold);	/* synchronous fread */
-	dib8000_write_word(state, 1286, outreg);
-	dib8000_write_word(state, 1291, sram);
-
-	return 0;
-}
-
-static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u16 sync_wait = dib8000_read_word(state, 273) & 0xfff0;
-
-	if (!state->differential_constellation) {
-		dib8000_write_word(state, 272, 1 << 9);	//dvsy_off_lmod4 = 1
-		dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2);	// sync_enable = 1; comb_mode = 2
-	} else {
-		dib8000_write_word(state, 272, 0);	//dvsy_off_lmod4 = 0
-		dib8000_write_word(state, 273, sync_wait);	// sync_enable = 0; comb_mode = 0
-	}
-	state->diversity_onoff = onoff;
-
-	switch (onoff) {
-	case 0:		/* only use the internal way - not the diversity input */
-		dib8000_write_word(state, 270, 1);
-		dib8000_write_word(state, 271, 0);
-		break;
-	case 1:		/* both ways */
-		dib8000_write_word(state, 270, 6);
-		dib8000_write_word(state, 271, 6);
-		break;
-	case 2:		/* only the diversity input */
-		dib8000_write_word(state, 270, 0);
-		dib8000_write_word(state, 271, 1);
-		break;
-	}
-	return 0;
-}
-
-static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)
-{
-	/* by default everything is going to be powered off */
-	u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
-		reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
-		reg_1280;
-
-	if (state->revision != 0x8090)
-		reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
-	else
-		reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80;
-
-	/* now, depending on the requested mode, we power on */
-	switch (mode) {
-		/* power up everything in the demod */
-	case DIB8000_POWER_ALL:
-		reg_774 = 0x0000;
-		reg_775 = 0x0000;
-		reg_776 = 0x0000;
-		reg_900 &= 0xfffc;
-		if (state->revision != 0x8090)
-			reg_1280 &= 0x00ff;
-		else
-			reg_1280 &= 0x707f;
-		break;
-	case DIB8000_POWER_INTERFACE_ONLY:
-		if (state->revision != 0x8090)
-			reg_1280 &= 0x00ff;
-		else
-			reg_1280 &= 0xfa7b;
-		break;
-	}
-
-	dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280);
-	dib8000_write_word(state, 774, reg_774);
-	dib8000_write_word(state, 775, reg_775);
-	dib8000_write_word(state, 776, reg_776);
-	dib8000_write_word(state, 900, reg_900);
-	dib8000_write_word(state, 1280, reg_1280);
-}
-
-static int dib8000_init_sdram(struct dib8000_state *state)
-{
-	u16 reg = 0;
-	dprintk("Init sdram");
-
-	reg = dib8000_read_word(state, 274)&0xfff0;
-	/* P_dintlv_delay_ram = 7 because of MobileSdram */
-	dib8000_write_word(state, 274, reg | 0x7);
-
-	dib8000_write_word(state, 1803, (7<<2));
-
-	reg = dib8000_read_word(state, 1280);
-	/* force restart P_restart_sdram */
-	dib8000_write_word(state, 1280,  reg | (1<<2));
-
-	/* release restart P_restart_sdram */
-	dib8000_write_word(state, 1280,  reg);
-
-	return 0;
-}
-
-static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
-{
-	int ret = 0;
-	u16 reg, reg_907 = dib8000_read_word(state, 907);
-	u16 reg_908 = dib8000_read_word(state, 908);
-
-	switch (no) {
-	case DIBX000_SLOW_ADC_ON:
-		if (state->revision != 0x8090) {
-			reg_908 |= (1 << 1) | (1 << 0);
-			ret |= dib8000_write_word(state, 908, reg_908);
-			reg_908 &= ~(1 << 1);
-		} else {
-			reg = dib8000_read_word(state, 1925);
-			/* en_slowAdc = 1 & reset_sladc = 1 */
-			dib8000_write_word(state, 1925, reg |
-					(1<<4) | (1<<2));
-
-			/* read acces to make it works... strange ... */
-			reg = dib8000_read_word(state, 1925);
-			msleep(20);
-			/* en_slowAdc = 1 & reset_sladc = 0 */
-			dib8000_write_word(state, 1925, reg & ~(1<<4));
-
-			reg = dib8000_read_word(state, 921) & ~((0x3 << 14)
-					| (0x3 << 12));
-			/* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ;
-			   (Vin2 = Vcm) */
-			dib8000_write_word(state, 921, reg | (1 << 14)
-					| (3 << 12));
-		}
-		break;
-
-	case DIBX000_SLOW_ADC_OFF:
-		if (state->revision == 0x8090) {
-			reg = dib8000_read_word(state, 1925);
-			/* reset_sladc = 1 en_slowAdc = 0 */
-			dib8000_write_word(state, 1925,
-					(reg & ~(1<<2)) | (1<<4));
-		}
-		reg_908 |= (1 << 1) | (1 << 0);
-		break;
-
-	case DIBX000_ADC_ON:
-		reg_907 &= 0x0fff;
-		reg_908 &= 0x0003;
-		break;
-
-	case DIBX000_ADC_OFF:	// leave the VBG voltage on
-		reg_907 |= (1 << 14) | (1 << 13) | (1 << 12);
-		reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
-		break;
-
-	case DIBX000_VBG_ENABLE:
-		reg_907 &= ~(1 << 15);
-		break;
-
-	case DIBX000_VBG_DISABLE:
-		reg_907 |= (1 << 15);
-		break;
-
-	default:
-		break;
-	}
-
-	ret |= dib8000_write_word(state, 907, reg_907);
-	ret |= dib8000_write_word(state, 908, reg_908);
-
-	return ret;
-}
-
-static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u32 timf;
-
-	if (bw == 0)
-		bw = 6000;
-
-	if (state->timf == 0) {
-		dprintk("using default timf");
-		timf = state->timf_default;
-	} else {
-		dprintk("using updated timf");
-		timf = state->timf;
-	}
-
-	dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));
-	dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));
-
-	return 0;
-}
-
-static int dib8000_sad_calib(struct dib8000_state *state)
-{
-	if (state->revision == 0x8090) {
-		dprintk("%s: the sad calibration is not needed for the dib8096P",
-				__func__);
-		return 0;
-	}
-	/* internal */
-	dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
-	dib8000_write_word(state, 924, 776);	// 0.625*3.3 / 4096
-
-	/* do the calibration */
-	dib8000_write_word(state, 923, (1 << 0));
-	dib8000_write_word(state, 923, (0 << 0));
-
-	msleep(1);
-	return 0;
-}
-
-int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	if (value > 4095)
-		value = 4095;
-	state->wbd_ref = value;
-	return dib8000_write_word(state, 106, value);
-}
-
-EXPORT_SYMBOL(dib8000_set_wbd_ref);
-static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
-{
-	dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
-	if (state->revision != 0x8090) {
-		dib8000_write_word(state, 23,
-				(u16) (((bw->internal * 1000) >> 16) & 0xffff));
-		dib8000_write_word(state, 24,
-				(u16) ((bw->internal * 1000) & 0xffff));
-	} else {
-		dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff));
-		dib8000_write_word(state, 24,
-				(u16) ((bw->internal  / 2 * 1000) & 0xffff));
-	}
-	dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
-	dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
-	dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
-
-	if (state->revision != 0x8090)
-		dib8000_write_word(state, 922, bw->sad_cfg);
-}
-
-static void dib8000_reset_pll(struct dib8000_state *state)
-{
-	const struct dibx000_bandwidth_config *pll = state->cfg.pll;
-	u16 clk_cfg1, reg;
-
-	if (state->revision != 0x8090) {
-		dib8000_write_word(state, 901,
-				(pll->pll_prediv << 8) | (pll->pll_ratio << 0));
-
-		clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
-			(pll->bypclk_div << 5) | (pll->enable_refdiv << 4) |
-			(1 << 3) | (pll->pll_range << 1) |
-			(pll->pll_reset << 0);
-
-		dib8000_write_word(state, 902, clk_cfg1);
-		clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
-		dib8000_write_word(state, 902, clk_cfg1);
-
-		dprintk("clk_cfg1: 0x%04x", clk_cfg1);
-
-		/* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
-		if (state->cfg.pll->ADClkSrc == 0)
-			dib8000_write_word(state, 904,
-					(0 << 15) | (0 << 12) | (0 << 10) |
-					(pll->modulo << 8) |
-					(pll->ADClkSrc << 7) | (0 << 1));
-		else if (state->cfg.refclksel != 0)
-			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
-					((state->cfg.refclksel & 0x3) << 10) |
-					(pll->modulo << 8) |
-					(pll->ADClkSrc << 7) | (0 << 1));
-		else
-			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
-					(3 << 10) | (pll->modulo << 8) |
-					(pll->ADClkSrc << 7) | (0 << 1));
-	} else {
-		dib8000_write_word(state, 1856, (!pll->pll_reset<<13) |
-				(pll->pll_range<<12) | (pll->pll_ratio<<6) |
-				(pll->pll_prediv));
-
-		reg = dib8000_read_word(state, 1857);
-		dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15));
-
-		reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */
-		dib8000_write_word(state, 1858, reg | 1);
-
-		dib8000_write_word(state, 904, (pll->modulo << 8));
-	}
-
-	dib8000_reset_pll_common(state, pll);
-}
-
-int dib8000_update_pll(struct dvb_frontend *fe,
-		struct dibx000_bandwidth_config *pll)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
-	u8 loopdiv, prediv;
-	u32 internal, xtal;
-
-	/* get back old values */
-	prediv = reg_1856 & 0x3f;
-	loopdiv = (reg_1856 >> 6) & 0x3f;
-
-	if ((pll != NULL) && (pll->pll_prediv != prediv ||
-				pll->pll_ratio != loopdiv)) {
-		dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
-		reg_1856 &= 0xf000;
-		reg_1857 = dib8000_read_word(state, 1857);
-		/* disable PLL */
-		dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15));
-
-		dib8000_write_word(state, 1856, reg_1856 |
-				((pll->pll_ratio & 0x3f) << 6) |
-				(pll->pll_prediv & 0x3f));
-
-		/* write new system clk into P_sec_len */
-		internal = dib8000_read32(state, 23) / 1000;
-		dprintk("Old Internal = %d", internal);
-		xtal = 2 * (internal / loopdiv) * prediv;
-		internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio;
-		dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d", xtal, internal/1000, internal/2000, internal/8000);
-		dprintk("New Internal = %d", internal);
-
-		dib8000_write_word(state, 23,
-				(u16) (((internal / 2) >> 16) & 0xffff));
-		dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff));
-		/* enable PLL */
-		dib8000_write_word(state, 1857, reg_1857 | (1 << 15));
-
-		while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1)
-			dprintk("Waiting for PLL to lock");
-
-		/* verify */
-		reg_1856 = dib8000_read_word(state, 1856);
-		dprintk("PLL Updated with prediv = %d and loopdiv = %d",
-				reg_1856&0x3f, (reg_1856>>6)&0x3f);
-
-		return 0;
-	}
-	return -EINVAL;
-}
-EXPORT_SYMBOL(dib8000_update_pll);
-
-
-static int dib8000_reset_gpio(struct dib8000_state *st)
-{
-	/* reset the GPIOs */
-	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
-	dib8000_write_word(st, 1030, st->cfg.gpio_val);
-
-	/* TODO 782 is P_gpio_od */
-
-	dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
-
-	dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
-	return 0;
-}
-
-static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
-{
-	st->cfg.gpio_dir = dib8000_read_word(st, 1029);
-	st->cfg.gpio_dir &= ~(1 << num);	/* reset the direction bit */
-	st->cfg.gpio_dir |= (dir & 0x1) << num;	/* set the new direction */
-	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
-
-	st->cfg.gpio_val = dib8000_read_word(st, 1030);
-	st->cfg.gpio_val &= ~(1 << num);	/* reset the direction bit */
-	st->cfg.gpio_val |= (val & 0x01) << num;	/* set the new value */
-	dib8000_write_word(st, 1030, st->cfg.gpio_val);
-
-	dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val);
-
-	return 0;
-}
-
-int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	return dib8000_cfg_gpio(state, num, dir, val);
-}
-
-EXPORT_SYMBOL(dib8000_set_gpio);
-static const u16 dib8000_defaults[] = {
-	/* auto search configuration - lock0 by default waiting
-	 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
-	3, 7,
-	0x0004,
-	0x0400,
-	0x0814,
-
-	12, 11,
-	0x001b,
-	0x7740,
-	0x005b,
-	0x8d80,
-	0x01c9,
-	0xc380,
-	0x0000,
-	0x0080,
-	0x0000,
-	0x0090,
-	0x0001,
-	0xd4c0,
-
-	/*1, 32,
-		0x6680 // P_corm_thres Lock algorithms configuration */
-
-	11, 80,			/* set ADC level to -16 */
-	(1 << 13) - 825 - 117,
-	(1 << 13) - 837 - 117,
-	(1 << 13) - 811 - 117,
-	(1 << 13) - 766 - 117,
-	(1 << 13) - 737 - 117,
-	(1 << 13) - 693 - 117,
-	(1 << 13) - 648 - 117,
-	(1 << 13) - 619 - 117,
-	(1 << 13) - 575 - 117,
-	(1 << 13) - 531 - 117,
-	(1 << 13) - 501 - 117,
-
-	4, 108,
-	0,
-	0,
-	0,
-	0,
-
-	1, 175,
-	0x0410,
-	1, 179,
-	8192,			// P_fft_nb_to_cut
-
-	6, 181,
-	0x2800,			// P_coff_corthres_ ( 2k 4k 8k ) 0x2800
-	0x2800,
-	0x2800,
-	0x2800,			// P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
-	0x2800,
-	0x2800,
-
-	2, 193,
-	0x0666,			// P_pha3_thres
-	0x0000,			// P_cti_use_cpe, P_cti_use_prog
-
-	2, 205,
-	0x200f,			// P_cspu_regul, P_cspu_win_cut
-	0x000f,			// P_des_shift_work
-
-	5, 215,
-	0x023d,			// P_adp_regul_cnt
-	0x00a4,			// P_adp_noise_cnt
-	0x00a4,			// P_adp_regul_ext
-	0x7ff0,			// P_adp_noise_ext
-	0x3ccc,			// P_adp_fil
-
-	1, 230,
-	0x0000,			// P_2d_byp_ti_num
-
-	1, 263,
-	0x800,			//P_equal_thres_wgn
-
-	1, 268,
-	(2 << 9) | 39,		// P_equal_ctrl_synchro, P_equal_speedmode
-
-	1, 270,
-	0x0001,			// P_div_lock0_wait
-	1, 285,
-	0x0020,			//p_fec_
-	1, 299,
-	0x0062,			/* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */
-
-	1, 338,
-	(1 << 12) |		// P_ctrl_corm_thres4pre_freq_inh=1
-		(1 << 10) |
-		(0 << 9) |		/* P_ctrl_pre_freq_inh=0 */
-		(3 << 5) |		/* P_ctrl_pre_freq_step=3 */
-		(1 << 0),		/* P_pre_freq_win_len=1 */
-
-	0,
-};
-
-static u16 dib8000_identify(struct i2c_device *client)
-{
-	u16 value;
-
-	//because of glitches sometimes
-	value = dib8000_i2c_read16(client, 896);
-
-	if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
-		dprintk("wrong Vendor ID (read=0x%x)", value);
-		return 0;
-	}
-
-	value = dib8000_i2c_read16(client, 897);
-	if (value != 0x8000 && value != 0x8001 &&
-			value != 0x8002 && value != 0x8090) {
-		dprintk("wrong Device ID (%x)", value);
-		return 0;
-	}
-
-	switch (value) {
-	case 0x8000:
-		dprintk("found DiB8000A");
-		break;
-	case 0x8001:
-		dprintk("found DiB8000B");
-		break;
-	case 0x8002:
-		dprintk("found DiB8000C");
-		break;
-	case 0x8090:
-		dprintk("found DiB8096P");
-		break;
-	}
-	return value;
-}
-
-static int dib8000_reset(struct dvb_frontend *fe)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-
-	if ((state->revision = dib8000_identify(&state->i2c)) == 0)
-		return -EINVAL;
-
-	/* sram lead in, rdy */
-	if (state->revision != 0x8090)
-		dib8000_write_word(state, 1287, 0x0003);
-
-	if (state->revision == 0x8000)
-		dprintk("error : dib8000 MA not supported");
-
-	dibx000_reset_i2c_master(&state->i2c_master);
-
-	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
-
-	/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
-	dib8000_set_adc_state(state, DIBX000_VBG_ENABLE);
-
-	/* restart all parts */
-	dib8000_write_word(state, 770, 0xffff);
-	dib8000_write_word(state, 771, 0xffff);
-	dib8000_write_word(state, 772, 0xfffc);
-	if (state->revision == 0x8090)
-		dib8000_write_word(state, 1280, 0x0045);
-	else
-		dib8000_write_word(state, 1280, 0x004d);
-	dib8000_write_word(state, 1281, 0x000c);
-
-	dib8000_write_word(state, 770, 0x0000);
-	dib8000_write_word(state, 771, 0x0000);
-	dib8000_write_word(state, 772, 0x0000);
-	dib8000_write_word(state, 898, 0x0004);	// sad
-	dib8000_write_word(state, 1280, 0x0000);
-	dib8000_write_word(state, 1281, 0x0000);
-
-	/* drives */
-	if (state->revision != 0x8090) {
-		if (state->cfg.drives)
-			dib8000_write_word(state, 906, state->cfg.drives);
-		else {
-			dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
-			/* min drive SDRAM - not optimal - adjust */
-			dib8000_write_word(state, 906, 0x2d98);
-		}
-	}
-
-	dib8000_reset_pll(state);
-	if (state->revision != 0x8090)
-		dib8000_write_word(state, 898, 0x0004);
-
-	if (dib8000_reset_gpio(state) != 0)
-		dprintk("GPIO reset was not successful.");
-
-	if ((state->revision != 0x8090) &&
-			(dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0))
-		dprintk("OUTPUT_MODE could not be resetted.");
-
-	state->current_agc = NULL;
-
-	// P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
-	/* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
-	if (state->cfg.pll->ifreq == 0)
-		dib8000_write_word(state, 40, 0x0755);	/* P_iqc_corr_inh = 0 enable IQcorr block */
-	else
-		dib8000_write_word(state, 40, 0x1f55);	/* P_iqc_corr_inh = 1 disable IQcorr block */
-
-	{
-		u16 l = 0, r;
-		const u16 *n;
-		n = dib8000_defaults;
-		l = *n++;
-		while (l) {
-			r = *n++;
-			do {
-				dib8000_write_word(state, r, *n++);
-				r++;
-			} while (--l);
-			l = *n++;
-		}
-	}
-	if (state->revision != 0x8090)
-		dib8000_write_word(state, 903, (0 << 4) | 2);
-	state->isdbt_cfg_loaded = 0;
-
-	//div_cfg override for special configs
-	if (state->cfg.div_cfg != 0)
-		dib8000_write_word(state, 903, state->cfg.div_cfg);
-
-	/* unforce divstr regardless whether i2c enumeration was done or not */
-	dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
-
-	dib8000_set_bandwidth(fe, 6000);
-
-	dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
-	if (state->revision != 0x8090) {
-		dib8000_sad_calib(state);
-		dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
-	}
-
-	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
-
-	return 0;
-}
-
-static void dib8000_restart_agc(struct dib8000_state *state)
-{
-	// P_restart_iqc & P_restart_agc
-	dib8000_write_word(state, 770, 0x0a00);
-	dib8000_write_word(state, 770, 0x0000);
-}
-
-static int dib8000_update_lna(struct dib8000_state *state)
-{
-	u16 dyn_gain;
-
-	if (state->cfg.update_lna) {
-		// read dyn_gain here (because it is demod-dependent and not tuner)
-		dyn_gain = dib8000_read_word(state, 390);
-
-		if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
-			dib8000_restart_agc(state);
-			return 1;
-		}
-	}
-	return 0;
-}
-
-static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
-{
-	struct dibx000_agc_config *agc = NULL;
-	int i;
-	u16 reg;
-
-	if (state->current_band == band && state->current_agc != NULL)
-		return 0;
-	state->current_band = band;
-
-	for (i = 0; i < state->cfg.agc_config_count; i++)
-		if (state->cfg.agc[i].band_caps & band) {
-			agc = &state->cfg.agc[i];
-			break;
-		}
-
-	if (agc == NULL) {
-		dprintk("no valid AGC configuration found for band 0x%02x", band);
-		return -EINVAL;
-	}
-
-	state->current_agc = agc;
-
-	/* AGC */
-	dib8000_write_word(state, 76, agc->setup);
-	dib8000_write_word(state, 77, agc->inv_gain);
-	dib8000_write_word(state, 78, agc->time_stabiliz);
-	dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
-
-	// Demod AGC loop configuration
-	dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
-	dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
-
-	dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
-		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
-
-	/* AGC continued */
-	if (state->wbd_ref != 0)
-		dib8000_write_word(state, 106, state->wbd_ref);
-	else			// use default
-		dib8000_write_word(state, 106, agc->wbd_ref);
-
-	if (state->revision == 0x8090) {
-		reg = dib8000_read_word(state, 922) & (0x3 << 2);
-		dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2));
-	}
-
-	dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
-	dib8000_write_word(state, 108, agc->agc1_max);
-	dib8000_write_word(state, 109, agc->agc1_min);
-	dib8000_write_word(state, 110, agc->agc2_max);
-	dib8000_write_word(state, 111, agc->agc2_min);
-	dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
-	dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
-	dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
-	dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
-
-	dib8000_write_word(state, 75, agc->agc1_pt3);
-	if (state->revision != 0x8090)
-		dib8000_write_word(state, 923,
-				(dib8000_read_word(state, 923) & 0xffe3) |
-				(agc->wbd_inv << 4) | (agc->wbd_sel << 2));
-
-	return 0;
-}
-
-void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	dib8000_set_adc_state(state, DIBX000_ADC_ON);
-	dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
-}
-EXPORT_SYMBOL(dib8000_pwm_agc_reset);
-
-static int dib8000_agc_soft_split(struct dib8000_state *state)
-{
-	u16 agc, split_offset;
-
-	if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
-		return FE_CALLBACK_TIME_NEVER;
-
-	// n_agc_global
-	agc = dib8000_read_word(state, 390);
-
-	if (agc > state->current_agc->split.min_thres)
-		split_offset = state->current_agc->split.min;
-	else if (agc < state->current_agc->split.max_thres)
-		split_offset = state->current_agc->split.max;
-	else
-		split_offset = state->current_agc->split.max *
-			(agc - state->current_agc->split.min_thres) /
-			(state->current_agc->split.max_thres - state->current_agc->split.min_thres);
-
-	dprintk("AGC split_offset: %d", split_offset);
-
-	// P_agc_force_split and P_agc_split_offset
-	dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
-	return 5000;
-}
-
-static int dib8000_agc_startup(struct dvb_frontend *fe)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	enum frontend_tune_state *tune_state = &state->tune_state;
-	int ret = 0;
-	u16 reg, upd_demod_gain_period = 0x8000;
-
-	switch (*tune_state) {
-	case CT_AGC_START:
-		// set power-up level: interf+analog+AGC
-
-		if (state->revision != 0x8090)
-			dib8000_set_adc_state(state, DIBX000_ADC_ON);
-		else {
-			dib8000_set_power_mode(state, DIB8000_POWER_ALL);
-
-			reg = dib8000_read_word(state, 1947)&0xff00;
-			dib8000_write_word(state, 1946,
-					upd_demod_gain_period & 0xFFFF);
-			/* bit 14 = enDemodGain */
-			dib8000_write_word(state, 1947, reg | (1<<14) |
-					((upd_demod_gain_period >> 16) & 0xFF));
-
-			/* enable adc i & q */
-			reg = dib8000_read_word(state, 1920);
-			dib8000_write_word(state, 1920, (reg | 0x3) &
-					(~(1 << 7)));
-		}
-
-		if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
-			*tune_state = CT_AGC_STOP;
-			state->status = FE_STATUS_TUNE_FAILED;
-			break;
-		}
-
-		ret = 70;
-		*tune_state = CT_AGC_STEP_0;
-		break;
-
-	case CT_AGC_STEP_0:
-		//AGC initialization
-		if (state->cfg.agc_control)
-			state->cfg.agc_control(fe, 1);
-
-		dib8000_restart_agc(state);
-
-		// wait AGC rough lock time
-		ret = 50;
-		*tune_state = CT_AGC_STEP_1;
-		break;
-
-	case CT_AGC_STEP_1:
-		// wait AGC accurate lock time
-		ret = 70;
-
-		if (dib8000_update_lna(state))
-			// wait only AGC rough lock time
-			ret = 50;
-		else
-			*tune_state = CT_AGC_STEP_2;
-		break;
-
-	case CT_AGC_STEP_2:
-		dib8000_agc_soft_split(state);
-
-		if (state->cfg.agc_control)
-			state->cfg.agc_control(fe, 0);
-
-		*tune_state = CT_AGC_STOP;
-		break;
-	default:
-		ret = dib8000_agc_soft_split(state);
-		break;
-	}
-	return ret;
-
-}
-
-static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive)
-{
-	u16 reg;
-
-	drive &= 0x7;
-
-	/* drive host bus 2, 3, 4 */
-	reg = dib8000_read_word(state, 1798) &
-		~(0x7 | (0x7 << 6) | (0x7 << 12));
-	reg |= (drive<<12) | (drive<<6) | drive;
-	dib8000_write_word(state, 1798, reg);
-
-	/* drive host bus 5,6 */
-	reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
-	reg |= (drive<<8) | (drive<<2);
-	dib8000_write_word(state, 1799, reg);
-
-	/* drive host bus 7, 8, 9 */
-	reg = dib8000_read_word(state, 1800) &
-		~(0x7 | (0x7 << 6) | (0x7 << 12));
-	reg |= (drive<<12) | (drive<<6) | drive;
-	dib8000_write_word(state, 1800, reg);
-
-	/* drive host bus 10, 11 */
-	reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
-	reg |= (drive<<8) | (drive<<2);
-	dib8000_write_word(state, 1801, reg);
-
-	/* drive host bus 12, 13, 14 */
-	reg = dib8000_read_word(state, 1802) &
-		~(0x7 | (0x7 << 6) | (0x7 << 12));
-	reg |= (drive<<12) | (drive<<6) | drive;
-	dib8000_write_word(state, 1802, reg);
-}
-
-static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout,
-		u32 insertExtSynchro, u32 syncSize)
-{
-	u32 quantif = 3;
-	u32 nom = (insertExtSynchro * P_Kin+syncSize);
-	u32 denom = P_Kout;
-	u32 syncFreq = ((nom << quantif) / denom);
-
-	if ((syncFreq & ((1 << quantif) - 1)) != 0)
-		syncFreq = (syncFreq >> quantif) + 1;
-	else
-		syncFreq = (syncFreq >> quantif);
-
-	if (syncFreq != 0)
-		syncFreq = syncFreq - 1;
-
-	return syncFreq;
-}
-
-static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin,
-		u32 P_Kout, u32 insertExtSynchro, u32 synchroMode,
-		u32 syncWord, u32 syncSize)
-{
-	dprintk("Configure DibStream Tx");
-
-	dib8000_write_word(state, 1615, 1);
-	dib8000_write_word(state, 1603, P_Kin);
-	dib8000_write_word(state, 1605, P_Kout);
-	dib8000_write_word(state, 1606, insertExtSynchro);
-	dib8000_write_word(state, 1608, synchroMode);
-	dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff);
-	dib8000_write_word(state, 1610, syncWord & 0xffff);
-	dib8000_write_word(state, 1612, syncSize);
-	dib8000_write_word(state, 1615, 0);
-}
-
-static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin,
-		u32 P_Kout, u32 synchroMode, u32 insertExtSynchro,
-		u32 syncWord, u32 syncSize, u32 dataOutRate)
-{
-	u32 syncFreq;
-
-	dprintk("Configure DibStream Rx synchroMode = %d", synchroMode);
-
-	if ((P_Kin != 0) && (P_Kout != 0)) {
-		syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout,
-				insertExtSynchro, syncSize);
-		dib8000_write_word(state, 1542, syncFreq);
-	}
-
-	dib8000_write_word(state, 1554, 1);
-	dib8000_write_word(state, 1536, P_Kin);
-	dib8000_write_word(state, 1537, P_Kout);
-	dib8000_write_word(state, 1539, synchroMode);
-	dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff);
-	dib8000_write_word(state, 1541, syncWord & 0xffff);
-	dib8000_write_word(state, 1543, syncSize);
-	dib8000_write_word(state, 1544, dataOutRate);
-	dib8000_write_word(state, 1554, 0);
-}
-
-static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff)
-{
-	u16 reg_1287;
-
-	reg_1287 = dib8000_read_word(state, 1287);
-
-	switch (onoff) {
-	case 1:
-			reg_1287 &= ~(1 << 8);
-			break;
-	case 0:
-			reg_1287 |= (1 << 8);
-			break;
-	}
-
-	dib8000_write_word(state, 1287, reg_1287);
-}
-
-static void dib8096p_configMpegMux(struct dib8000_state *state,
-		u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
-{
-	u16 reg_1287;
-
-	dprintk("Enable Mpeg mux");
-
-	dib8096p_enMpegMux(state, 0);
-
-	/* If the input mode is MPEG do not divide the serial clock */
-	if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
-		enSerialClkDiv2 = 0;
-
-	reg_1287 = ((pulseWidth & 0x1f) << 3) |
-		((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1);
-	dib8000_write_word(state, 1287, reg_1287);
-
-	dib8096p_enMpegMux(state, 1);
-}
-
-static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode)
-{
-	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7);
-
-	switch (mode) {
-	case MPEG_ON_DIBTX:
-			dprintk("SET MPEG ON DIBSTREAM TX");
-			dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
-			reg_1288 |= (1 << 9); break;
-	case DIV_ON_DIBTX:
-			dprintk("SET DIV_OUT ON DIBSTREAM TX");
-			dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
-			reg_1288 |= (1 << 8); break;
-	case ADC_ON_DIBTX:
-			dprintk("SET ADC_OUT ON DIBSTREAM TX");
-			dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
-			reg_1288 |= (1 << 7); break;
-	default:
-			break;
-	}
-	dib8000_write_word(state, 1288, reg_1288);
-}
-
-static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode)
-{
-	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4);
-
-	switch (mode) {
-	case DEMOUT_ON_HOSTBUS:
-			dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
-			dib8096p_enMpegMux(state, 0);
-			reg_1288 |= (1 << 6);
-			break;
-	case DIBTX_ON_HOSTBUS:
-			dprintk("SET DIBSTREAM TX ON HOST BUS");
-			dib8096p_enMpegMux(state, 0);
-			reg_1288 |= (1 << 5);
-			break;
-	case MPEG_ON_HOSTBUS:
-			dprintk("SET MPEG MUX ON HOST BUS");
-			reg_1288 |= (1 << 4);
-			break;
-	default:
-			break;
-	}
-	dib8000_write_word(state, 1288, reg_1288);
-}
-
-static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u16 reg_1287;
-
-	switch (onoff) {
-	case 0: /* only use the internal way - not the diversity input */
-			dprintk("%s mode OFF : by default Enable Mpeg INPUT",
-					__func__);
-			/* outputRate = 8 */
-			dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
-
-			/* Do not divide the serial clock of MPEG MUX in
-			   SERIAL MODE in case input mode MPEG is used */
-			reg_1287 = dib8000_read_word(state, 1287);
-			/* enSerialClkDiv2 == 1 ? */
-			if ((reg_1287 & 0x1) == 1) {
-				/* force enSerialClkDiv2 = 0 */
-				reg_1287 &= ~0x1;
-				dib8000_write_word(state, 1287, reg_1287);
-			}
-			state->input_mode_mpeg = 1;
-			break;
-	case 1: /* both ways */
-	case 2: /* only the diversity input */
-			dprintk("%s ON : Enable diversity INPUT", __func__);
-			dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
-			state->input_mode_mpeg = 0;
-			break;
-	}
-
-	dib8000_set_diversity_in(state->fe[0], onoff);
-	return 0;
-}
-
-static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u16 outreg, smo_mode, fifo_threshold;
-	u8 prefer_mpeg_mux_use = 1;
-	int ret = 0;
-
-	dib8096p_host_bus_drive(state, 1);
-
-	fifo_threshold = 1792;
-	smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
-	outreg   = dib8000_read_word(state, 1286) &
-		~((1 << 10) | (0x7 << 6) | (1 << 1));
-
-	switch (mode) {
-	case OUTMODE_HIGH_Z:
-			outreg = 0;
-			break;
-
-	case OUTMODE_MPEG2_SERIAL:
-			if (prefer_mpeg_mux_use) {
-				dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux");
-				dib8096p_configMpegMux(state, 3, 1, 1);
-				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
-			} else {/* Use Smooth block */
-				dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc");
-				dib8096p_setHostBusMux(state,
-						DEMOUT_ON_HOSTBUS);
-				outreg |= (2 << 6) | (0 << 1);
-			}
-			break;
-
-	case OUTMODE_MPEG2_PAR_GATED_CLK:
-			if (prefer_mpeg_mux_use) {
-				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
-				dib8096p_configMpegMux(state, 2, 0, 0);
-				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
-			} else { /* Use Smooth block */
-				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block");
-				dib8096p_setHostBusMux(state,
-						DEMOUT_ON_HOSTBUS);
-				outreg |= (0 << 6);
-			}
-			break;
-
-	case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
-			dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block");
-			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
-			outreg |= (1 << 6);
-			break;
-
-	case OUTMODE_MPEG2_FIFO:
-			/* Using Smooth block because not supported
-			   by new Mpeg Mux bloc */
-			dprintk("dib8096P setting output mode TS_FIFO using Smooth block");
-			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
-			outreg |= (5 << 6);
-			smo_mode |= (3 << 1);
-			fifo_threshold = 512;
-			break;
-
-	case OUTMODE_DIVERSITY:
-			dprintk("dib8096P setting output mode MODE_DIVERSITY");
-			dib8096p_setDibTxMux(state, DIV_ON_DIBTX);
-			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
-			break;
-
-	case OUTMODE_ANALOG_ADC:
-			dprintk("dib8096P setting output mode MODE_ANALOG_ADC");
-			dib8096p_setDibTxMux(state, ADC_ON_DIBTX);
-			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
-			break;
-	}
-
-	if (mode != OUTMODE_HIGH_Z)
-		outreg |= (1<<10);
-
-	dprintk("output_mpeg2_in_188_bytes = %d",
-			state->cfg.output_mpeg2_in_188_bytes);
-	if (state->cfg.output_mpeg2_in_188_bytes)
-		smo_mode |= (1 << 5);
-
-	ret |= dib8000_write_word(state, 299, smo_mode);
-	/* synchronous fread */
-	ret |= dib8000_write_word(state, 299 + 1, fifo_threshold);
-	ret |= dib8000_write_word(state, 1286, outreg);
-
-	return ret;
-}
-
-static int map_addr_to_serpar_number(struct i2c_msg *msg)
-{
-	if (msg->buf[0] <= 15)
-		msg->buf[0] -= 1;
-	else if (msg->buf[0] == 17)
-		msg->buf[0] = 15;
-	else if (msg->buf[0] == 16)
-		msg->buf[0] = 17;
-	else if (msg->buf[0] == 19)
-		msg->buf[0] = 16;
-	else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
-		msg->buf[0] -= 3;
-	else if (msg->buf[0] == 28)
-		msg->buf[0] = 23;
-	else if (msg->buf[0] == 99)
-		msg->buf[0] = 99;
-	else
-		return -EINVAL;
-	return 0;
-}
-
-static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap,
-		struct i2c_msg msg[], int num)
-{
-	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
-	u8 n_overflow = 1;
-	u16 i = 1000;
-	u16 serpar_num = msg[0].buf[0];
-
-	while (n_overflow == 1 && i) {
-		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
-		i--;
-		if (i == 0)
-			dprintk("Tuner ITF: write busy (overflow)");
-	}
-	dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
-	dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
-
-	return num;
-}
-
-static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap,
-		struct i2c_msg msg[], int num)
-{
-	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
-	u8 n_overflow = 1, n_empty = 1;
-	u16 i = 1000;
-	u16 serpar_num = msg[0].buf[0];
-	u16 read_word;
-
-	while (n_overflow == 1 && i) {
-		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
-		i--;
-		if (i == 0)
-			dprintk("TunerITF: read busy (overflow)");
-	}
-	dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f));
-
-	i = 1000;
-	while (n_empty == 1 && i) {
-		n_empty = dib8000_read_word(state, 1984)&0x1;
-		i--;
-		if (i == 0)
-			dprintk("TunerITF: read busy (empty)");
-	}
-
-	read_word = dib8000_read_word(state, 1987);
-	msg[1].buf[0] = (read_word >> 8) & 0xff;
-	msg[1].buf[1] = (read_word) & 0xff;
-
-	return num;
-}
-
-static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap,
-		struct i2c_msg msg[], int num)
-{
-	if (map_addr_to_serpar_number(&msg[0]) == 0) {
-		if (num == 1) /* write */
-			return dib8096p_tuner_write_serpar(i2c_adap, msg, 1);
-		else /* read */
-			return dib8096p_tuner_read_serpar(i2c_adap, msg, 2);
-	}
-	return num;
-}
-
-static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap,
-		struct i2c_msg msg[], int num, u16 apb_address)
-{
-	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
-	u16 word;
-
-	if (num == 1) {		/* write */
-		dib8000_write_word(state, apb_address,
-				((msg[0].buf[1] << 8) | (msg[0].buf[2])));
-	} else {
-		word = dib8000_read_word(state, apb_address);
-		msg[1].buf[0] = (word >> 8) & 0xff;
-		msg[1].buf[1] = (word) & 0xff;
-	}
-	return num;
-}
-
-static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap,
-		struct i2c_msg msg[], int num)
-{
-	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
-	u16 apb_address = 0, word;
-	int i = 0;
-
-	switch (msg[0].buf[0]) {
-	case 0x12:
-			apb_address = 1920;
-			break;
-	case 0x14:
-			apb_address = 1921;
-			break;
-	case 0x24:
-			apb_address = 1922;
-			break;
-	case 0x1a:
-			apb_address = 1923;
-			break;
-	case 0x22:
-			apb_address = 1924;
-			break;
-	case 0x33:
-			apb_address = 1926;
-			break;
-	case 0x34:
-			apb_address = 1927;
-			break;
-	case 0x35:
-			apb_address = 1928;
-			break;
-	case 0x36:
-			apb_address = 1929;
-			break;
-	case 0x37:
-			apb_address = 1930;
-			break;
-	case 0x38:
-			apb_address = 1931;
-			break;
-	case 0x39:
-			apb_address = 1932;
-			break;
-	case 0x2a:
-			apb_address = 1935;
-			break;
-	case 0x2b:
-			apb_address = 1936;
-			break;
-	case 0x2c:
-			apb_address = 1937;
-			break;
-	case 0x2d:
-			apb_address = 1938;
-			break;
-	case 0x2e:
-			apb_address = 1939;
-			break;
-	case 0x2f:
-			apb_address = 1940;
-			break;
-	case 0x30:
-			apb_address = 1941;
-			break;
-	case 0x31:
-			apb_address = 1942;
-			break;
-	case 0x32:
-			apb_address = 1943;
-			break;
-	case 0x3e:
-			apb_address = 1944;
-			break;
-	case 0x3f:
-			apb_address = 1945;
-			break;
-	case 0x40:
-			apb_address = 1948;
-			break;
-	case 0x25:
-			apb_address = 936;
-			break;
-	case 0x26:
-			apb_address = 937;
-			break;
-	case 0x27:
-			apb_address = 938;
-			break;
-	case 0x28:
-			apb_address = 939;
-			break;
-	case 0x1d:
-			/* get sad sel request */
-			i = ((dib8000_read_word(state, 921) >> 12)&0x3);
-			word = dib8000_read_word(state, 924+i);
-			msg[1].buf[0] = (word >> 8) & 0xff;
-			msg[1].buf[1] = (word) & 0xff;
-			return num;
-	case 0x1f:
-			if (num == 1) {	/* write */
-				word = (u16) ((msg[0].buf[1] << 8) |
-						msg[0].buf[2]);
-				/* in the VGAMODE Sel are located on bit 0/1 */
-				word &= 0x3;
-				word = (dib8000_read_word(state, 921) &
-						~(3<<12)) | (word<<12);
-				/* Set the proper input */
-				dib8000_write_word(state, 921, word);
-				return num;
-			}
-	}
-
-	if (apb_address != 0) /* R/W acces via APB */
-		return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address);
-	else  /* R/W access via SERPAR  */
-		return dib8096p_tuner_rw_serpar(i2c_adap, msg, num);
-
-	return 0;
-}
-
-static u32 dib8096p_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm dib8096p_tuner_xfer_algo = {
-	.master_xfer = dib8096p_tuner_xfer,
-	.functionality = dib8096p_i2c_func,
-};
-
-struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
-{
-	struct dib8000_state *st = fe->demodulator_priv;
-	return &st->dib8096p_tuner_adap;
-}
-EXPORT_SYMBOL(dib8096p_get_i2c_tuner);
-
-int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u16 en_cur_state;
-
-	dprintk("sleep dib8096p: %d", onoff);
-
-	en_cur_state = dib8000_read_word(state, 1922);
-
-	/* LNAs and MIX are ON and therefore it is a valid configuration */
-	if (en_cur_state > 0xff)
-		state->tuner_enable = en_cur_state ;
-
-	if (onoff)
-		en_cur_state &= 0x00ff;
-	else {
-		if (state->tuner_enable != 0)
-			en_cur_state = state->tuner_enable;
-	}
-
-	dib8000_write_word(state, 1922, en_cur_state);
-
-	return 0;
-}
-EXPORT_SYMBOL(dib8096p_tuner_sleep);
-
-static const s32 lut_1000ln_mant[] =
-{
-	908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
-};
-
-s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
-	s32 val;
-
-	val = dib8000_read32(state, 384);
-	if (mode) {
-		tmp_val = val;
-		while (tmp_val >>= 1)
-			exp++;
-		mant = (val * 1000 / (1<<exp));
-		ix = (u8)((mant-1000)/100); /* index of the LUT */
-		val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
-		val = (val*256)/1000;
-	}
-	return val;
-}
-EXPORT_SYMBOL(dib8000_get_adc_power);
-
-int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	int val = 0;
-
-	switch (IQ) {
-	case 1:
-			val = dib8000_read_word(state, 403);
-			break;
-	case 0:
-			val = dib8000_read_word(state, 404);
-			break;
-	}
-	if (val  & 0x200)
-		val -= 1024;
-
-	return val;
-}
-EXPORT_SYMBOL(dib8090p_get_dc_power);
-
-static void dib8000_update_timf(struct dib8000_state *state)
-{
-	u32 timf = state->timf = dib8000_read32(state, 435);
-
-	dib8000_write_word(state, 29, (u16) (timf >> 16));
-	dib8000_write_word(state, 30, (u16) (timf & 0xffff));
-	dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
-}
-
-u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-
-	switch (op) {
-	case DEMOD_TIMF_SET:
-			state->timf = timf;
-			break;
-	case DEMOD_TIMF_UPDATE:
-			dib8000_update_timf(state);
-			break;
-	case DEMOD_TIMF_GET:
-			break;
-	}
-	dib8000_set_bandwidth(state->fe[0], 6000);
-
-	return state->timf;
-}
-EXPORT_SYMBOL(dib8000_ctrl_timf);
-
-static const u16 adc_target_16dB[11] = {
-	(1 << 13) - 825 - 117,
-	(1 << 13) - 837 - 117,
-	(1 << 13) - 811 - 117,
-	(1 << 13) - 766 - 117,
-	(1 << 13) - 737 - 117,
-	(1 << 13) - 693 - 117,
-	(1 << 13) - 648 - 117,
-	(1 << 13) - 619 - 117,
-	(1 << 13) - 575 - 117,
-	(1 << 13) - 531 - 117,
-	(1 << 13) - 501 - 117
-};
-static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
-
-static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
-{
-	u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0;
-	u8 guard, crate, constellation, timeI;
-	u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff;	// All 13 segments enabled
-	const s16 *ncoeff = NULL, *ana_fe;
-	u16 tmcc_pow = 0;
-	u16 coff_pow = 0x2800;
-	u16 init_prbs = 0xfff;
-	u16 ana_gain = 0;
-
-	if (state->revision == 0x8090)
-		dib8000_init_sdram(state);
-
-	if (state->ber_monitored_layer != LAYER_ALL)
-		dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer);
-	else
-		dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
-
-	i = dib8000_read_word(state, 26) & 1;	// P_dds_invspec
-	dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion^i);
-
-	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
-		//compute new dds_freq for the seg and adjust prbs
-		int seg_offset =
-			state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx -
-			(state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) -
-			(state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2);
-		int clk = state->cfg.pll->internal;
-		u32 segtodds = ((u32) (430 << 23) / clk) << 3;	// segtodds = SegBW / Fclk * pow(2,26)
-		int dds_offset = seg_offset * segtodds;
-		int new_dds, sub_channel;
-		if ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
-			dds_offset -= (int)(segtodds / 2);
-
-		if (state->cfg.pll->ifreq == 0) {
-			if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) {
-				dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
-				new_dds = dds_offset;
-			} else
-				new_dds = dds_offset;
-
-			// We shift tuning frequency if the wanted segment is :
-			//  - the segment of center frequency with an odd total number of segments
-			//  - the segment to the left of center frequency with an even total number of segments
-			//  - the segment to the right of center frequency with an even total number of segments
-			if ((state->fe[0]->dtv_property_cache.delivery_system == SYS_ISDBT)
-				&& (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
-					&& (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
-					  && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
-				  ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
-					 || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
-						 && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2)))
-					 || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
-						 && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
-							 ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
-					)) {
-				new_dds -= ((u32) (850 << 22) / clk) << 4;	// new_dds = 850 (freq shift in KHz) / Fclk * pow(2,26)
-			}
-		} else {
-			if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0)
-				new_dds = state->cfg.pll->ifreq - dds_offset;
-			else
-				new_dds = state->cfg.pll->ifreq + dds_offset;
-		}
-		dib8000_write_word(state, 27, (u16) ((new_dds >> 16) & 0x01ff));
-		dib8000_write_word(state, 28, (u16) (new_dds & 0xffff));
-		if (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
-			sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3;
-		else
-			sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3;
-		sub_channel -= 6;
-
-		if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K
-				|| state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) {
-			dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1);	//adp_pass =1
-			dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14));	//pha3_force_pha_shift = 1
-		} else {
-			dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe);	//adp_pass =0
-			dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff);	//pha3_force_pha_shift = 0
-		}
-
-		switch (state->fe[0]->dtv_property_cache.transmission_mode) {
-		case TRANSMISSION_MODE_2K:
-			switch (sub_channel) {
-			case -6:
-				init_prbs = 0x0;
-				break;	// 41, 0, 1
-			case -5:
-				init_prbs = 0x423;
-				break;	// 02~04
-			case -4:
-				init_prbs = 0x9;
-				break;	// 05~07
-			case -3:
-				init_prbs = 0x5C7;
-				break;	// 08~10
-			case -2:
-				init_prbs = 0x7A6;
-				break;	// 11~13
-			case -1:
-				init_prbs = 0x3D8;
-				break;	// 14~16
-			case 0:
-				init_prbs = 0x527;
-				break;	// 17~19
-			case 1:
-				init_prbs = 0x7FF;
-				break;	// 20~22
-			case 2:
-				init_prbs = 0x79B;
-				break;	// 23~25
-			case 3:
-				init_prbs = 0x3D6;
-				break;	// 26~28
-			case 4:
-				init_prbs = 0x3A2;
-				break;	// 29~31
-			case 5:
-				init_prbs = 0x53B;
-				break;	// 32~34
-			case 6:
-				init_prbs = 0x2F4;
-				break;	// 35~37
-			default:
-			case 7:
-				init_prbs = 0x213;
-				break;	// 38~40
-			}
-			break;
-
-		case TRANSMISSION_MODE_4K:
-			switch (sub_channel) {
-			case -6:
-				init_prbs = 0x0;
-				break;	// 41, 0, 1
-			case -5:
-				init_prbs = 0x208;
-				break;	// 02~04
-			case -4:
-				init_prbs = 0xC3;
-				break;	// 05~07
-			case -3:
-				init_prbs = 0x7B9;
-				break;	// 08~10
-			case -2:
-				init_prbs = 0x423;
-				break;	// 11~13
-			case -1:
-				init_prbs = 0x5C7;
-				break;	// 14~16
-			case 0:
-				init_prbs = 0x3D8;
-				break;	// 17~19
-			case 1:
-				init_prbs = 0x7FF;
-				break;	// 20~22
-			case 2:
-				init_prbs = 0x3D6;
-				break;	// 23~25
-			case 3:
-				init_prbs = 0x53B;
-				break;	// 26~28
-			case 4:
-				init_prbs = 0x213;
-				break;	// 29~31
-			case 5:
-				init_prbs = 0x29;
-				break;	// 32~34
-			case 6:
-				init_prbs = 0xD0;
-				break;	// 35~37
-			default:
-			case 7:
-				init_prbs = 0x48E;
-				break;	// 38~40
-			}
-			break;
-
-		default:
-		case TRANSMISSION_MODE_8K:
-			switch (sub_channel) {
-			case -6:
-				init_prbs = 0x0;
-				break;	// 41, 0, 1
-			case -5:
-				init_prbs = 0x740;
-				break;	// 02~04
-			case -4:
-				init_prbs = 0x069;
-				break;	// 05~07
-			case -3:
-				init_prbs = 0x7DD;
-				break;	// 08~10
-			case -2:
-				init_prbs = 0x208;
-				break;	// 11~13
-			case -1:
-				init_prbs = 0x7B9;
-				break;	// 14~16
-			case 0:
-				init_prbs = 0x5C7;
-				break;	// 17~19
-			case 1:
-				init_prbs = 0x7FF;
-				break;	// 20~22
-			case 2:
-				init_prbs = 0x53B;
-				break;	// 23~25
-			case 3:
-				init_prbs = 0x29;
-				break;	// 26~28
-			case 4:
-				init_prbs = 0x48E;
-				break;	// 29~31
-			case 5:
-				init_prbs = 0x4C4;
-				break;	// 32~34
-			case 6:
-				init_prbs = 0x367;
-				break;	// 33~37
-			default:
-			case 7:
-				init_prbs = 0x684;
-				break;	// 38~40
-			}
-			break;
-		}
-	} else {
-		dib8000_write_word(state, 27, (u16) ((state->cfg.pll->ifreq >> 16) & 0x01ff));
-		dib8000_write_word(state, 28, (u16) (state->cfg.pll->ifreq & 0xffff));
-		dib8000_write_word(state, 26, (u16) ((state->cfg.pll->ifreq >> 25) & 0x0003));
-	}
-	/*P_mode == ?? */
-	dib8000_write_word(state, 10, (seq << 4));
-	//  dib8000_write_word(state, 287, (dib8000_read_word(state, 287) & 0xe000) | 0x1000);
-
-	switch (state->fe[0]->dtv_property_cache.guard_interval) {
-	case GUARD_INTERVAL_1_32:
-		guard = 0;
-		break;
-	case GUARD_INTERVAL_1_16:
-		guard = 1;
-		break;
-	case GUARD_INTERVAL_1_8:
-		guard = 2;
-		break;
-	case GUARD_INTERVAL_1_4:
-	default:
-		guard = 3;
-		break;
-	}
-
-	dib8000_write_word(state, 1, (init_prbs << 2) | (guard & 0x3));	// ADDR 1
-
-	max_constellation = DQPSK;
-	for (i = 0; i < 3; i++) {
-		switch (state->fe[0]->dtv_property_cache.layer[i].modulation) {
-		case DQPSK:
-			constellation = 0;
-			break;
-		case QPSK:
-			constellation = 1;
-			break;
-		case QAM_16:
-			constellation = 2;
-			break;
-		case QAM_64:
-		default:
-			constellation = 3;
-			break;
-		}
-
-		switch (state->fe[0]->dtv_property_cache.layer[i].fec) {
-		case FEC_1_2:
-			crate = 1;
-			break;
-		case FEC_2_3:
-			crate = 2;
-			break;
-		case FEC_3_4:
-			crate = 3;
-			break;
-		case FEC_5_6:
-			crate = 5;
-			break;
-		case FEC_7_8:
-		default:
-			crate = 7;
-			break;
-		}
-
-		if ((state->fe[0]->dtv_property_cache.layer[i].interleaving > 0) &&
-				((state->fe[0]->dtv_property_cache.layer[i].interleaving <= 3) ||
-				 (state->fe[0]->dtv_property_cache.layer[i].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1))
-			)
-			timeI = state->fe[0]->dtv_property_cache.layer[i].interleaving;
-		else
-			timeI = 0;
-		dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[i].segment_count & 0xf) << 6) |
-					(crate << 3) | timeI);
-		if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) {
-			switch (max_constellation) {
-			case DQPSK:
-			case QPSK:
-				if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_16 ||
-					state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
-					max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
-				break;
-			case QAM_16:
-				if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
-					max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
-				break;
-			}
-		}
-	}
-
-	mode = fft_to_mode(state);
-
-	//dib8000_write_word(state, 5, 13); /*p_last_seg = 13*/
-
-	dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) |
-				((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache.
-												 isdbt_sb_mode & 1) << 4));
-
-	dprintk("mode = %d ; guard = %d", mode, state->fe[0]->dtv_property_cache.guard_interval);
-
-	/* signal optimization parameter */
-
-	if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) {
-		seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0];
-		for (i = 1; i < 3; i++)
-			nbseg_diff +=
-				(state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
-		for (i = 0; i < nbseg_diff; i++)
-			seg_diff_mask |= 1 << permu_seg[i + 1];
-	} else {
-		for (i = 0; i < 3; i++)
-			nbseg_diff +=
-				(state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
-		for (i = 0; i < nbseg_diff; i++)
-			seg_diff_mask |= 1 << permu_seg[i];
-	}
-	dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask);
-
-	state->differential_constellation = (seg_diff_mask != 0);
-	if (state->revision != 0x8090)
-		dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
-	else
-		dib8096p_set_diversity_in(state->fe[0], state->diversity_onoff);
-
-	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
-		if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
-			seg_mask13 = 0x00E0;
-		else		// 1-segment
-			seg_mask13 = 0x0040;
-	} else
-		seg_mask13 = 0x1fff;
-
-	// WRITE: Mode & Diff mask
-	dib8000_write_word(state, 0, (mode << 13) | seg_diff_mask);
-
-	if ((seg_diff_mask) || (state->fe[0]->dtv_property_cache.isdbt_sb_mode))
-		dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
-	else
-		dib8000_write_word(state, 268, (2 << 9) | 39);	//init value
-
-	// ---- SMALL ----
-	// P_small_seg_diff
-	dib8000_write_word(state, 352, seg_diff_mask);	// ADDR 352
-
-	dib8000_write_word(state, 353, seg_mask13);	// ADDR 353
-
-/*	// P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */
-
-	// ---- SMALL ----
-	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
-		switch (state->fe[0]->dtv_property_cache.transmission_mode) {
-		case TRANSMISSION_MODE_2K:
-			if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
-				if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
-					ncoeff = coeff_2k_sb_1seg_dqpsk;
-				else	// QPSK or QAM
-					ncoeff = coeff_2k_sb_1seg;
-			} else {	// 3-segments
-				if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
-					if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
-						ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
-					else	// QPSK or QAM on external segments
-						ncoeff = coeff_2k_sb_3seg_0dqpsk;
-				} else {	// QPSK or QAM on central segment
-					if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
-						ncoeff = coeff_2k_sb_3seg_1dqpsk;
-					else	// QPSK or QAM on external segments
-						ncoeff = coeff_2k_sb_3seg;
-				}
-			}
-			break;
-
-		case TRANSMISSION_MODE_4K:
-			if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
-				if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
-					ncoeff = coeff_4k_sb_1seg_dqpsk;
-				else	// QPSK or QAM
-					ncoeff = coeff_4k_sb_1seg;
-			} else {	// 3-segments
-				if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
-					if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
-						ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
-					} else {	// QPSK or QAM on external segments
-						ncoeff = coeff_4k_sb_3seg_0dqpsk;
-					}
-				} else {	// QPSK or QAM on central segment
-					if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
-						ncoeff = coeff_4k_sb_3seg_1dqpsk;
-					} else	// QPSK or QAM on external segments
-						ncoeff = coeff_4k_sb_3seg;
-				}
-			}
-			break;
-
-		case TRANSMISSION_MODE_AUTO:
-		case TRANSMISSION_MODE_8K:
-		default:
-			if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
-				if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
-					ncoeff = coeff_8k_sb_1seg_dqpsk;
-				else	// QPSK or QAM
-					ncoeff = coeff_8k_sb_1seg;
-			} else {	// 3-segments
-				if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
-					if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
-						ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
-					} else {	// QPSK or QAM on external segments
-						ncoeff = coeff_8k_sb_3seg_0dqpsk;
-					}
-				} else {	// QPSK or QAM on central segment
-					if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
-						ncoeff = coeff_8k_sb_3seg_1dqpsk;
-					} else	// QPSK or QAM on external segments
-						ncoeff = coeff_8k_sb_3seg;
-				}
-			}
-			break;
-		}
-		for (i = 0; i < 8; i++)
-			dib8000_write_word(state, 343 + i, ncoeff[i]);
-	}
-
-	// P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5
-	dib8000_write_word(state, 351,
-				(state->fe[0]->dtv_property_cache.isdbt_sb_mode << 9) | (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5);
-
-	// ---- COFF ----
-	// Carloff, the most robust
-	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
-
-		// P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64
-		// P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1
-		dib8000_write_word(state, 187,
-					(4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2)
-					| 0x3);
-
-/*		// P_small_coef_ext_enable = 1 */
-/*		dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */
-
-		if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
-
-			// P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width= (P_mode == 3) , P_coff_one_seg_sym= (P_mode-1)
-			if (mode == 3)
-				dib8000_write_word(state, 180, 0x1fcf | ((mode - 1) << 14));
-			else
-				dib8000_write_word(state, 180, 0x0fcf | ((mode - 1) << 14));
-			// P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1,
-			// P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4
-			dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
-			// P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8
-			dib8000_write_word(state, 340, (16 << 6) | (8 << 0));
-			// P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1
-			dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
-
-			// P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k
-			dib8000_write_word(state, 181, 300);
-			dib8000_write_word(state, 182, 150);
-			dib8000_write_word(state, 183, 80);
-			dib8000_write_word(state, 184, 300);
-			dib8000_write_word(state, 185, 150);
-			dib8000_write_word(state, 186, 80);
-		} else {	// Sound Broadcasting mode 3 seg
-			// P_coff_one_seg_sym= 1, P_coff_one_seg_width= 1, P_coff_winlen=63, P_coff_thres_lock=15
-			/*	if (mode == 3) */
-			/*		dib8000_write_word(state, 180, 0x2fca | ((0) << 14)); */
-			/*	else */
-			/*		dib8000_write_word(state, 180, 0x2fca | ((1) << 14)); */
-			dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
-
-			// P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1,
-			// P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4
-			dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
-			// P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8
-			dib8000_write_word(state, 340, (16 << 6) | (8 << 0));
-			//P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1
-			dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
-
-			// P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k
-			dib8000_write_word(state, 181, 350);
-			dib8000_write_word(state, 182, 300);
-			dib8000_write_word(state, 183, 250);
-			dib8000_write_word(state, 184, 350);
-			dib8000_write_word(state, 185, 300);
-			dib8000_write_word(state, 186, 250);
-		}
-
-	} else if (state->isdbt_cfg_loaded == 0) {	// if not Sound Broadcasting mode : put default values for 13 segments
-		dib8000_write_word(state, 180, (16 << 6) | 9);
-		dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
-		coff_pow = 0x2800;
-		for (i = 0; i < 6; i++)
-			dib8000_write_word(state, 181 + i, coff_pow);
-
-		// P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1,
-		// P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=1
-		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
-
-		// P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6
-		dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
-		// P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1
-		dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
-	}
-	// ---- FFT ----
-	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 && state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
-		dib8000_write_word(state, 178, 64);	// P_fft_powrange=64
-	else
-		dib8000_write_word(state, 178, 32);	// P_fft_powrange=32
-
-	/* make the cpil_coff_lock more robust but slower p_coff_winlen
-	 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
-	 */
-	/* if ( ( nbseg_diff>0)&&(nbseg_diff<13))
-		dib8000_write_word(state, 187, (dib8000_read_word(state, 187) & 0xfffb) | (1 << 3)); */
-
-	dib8000_write_word(state, 189, ~seg_mask13 | seg_diff_mask);	/* P_lmod4_seg_inh       */
-	dib8000_write_word(state, 192, ~seg_mask13 | seg_diff_mask);	/* P_pha3_seg_inh        */
-	dib8000_write_word(state, 225, ~seg_mask13 | seg_diff_mask);	/* P_tac_seg_inh         */
-	if ((!state->fe[0]->dtv_property_cache.isdbt_sb_mode) && (state->cfg.pll->ifreq == 0))
-		dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask | 0x40);	/* P_equal_noise_seg_inh */
-	else
-		dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask);	/* P_equal_noise_seg_inh */
-	dib8000_write_word(state, 287, ~seg_mask13 | 0x1000);	/* P_tmcc_seg_inh        */
-	//dib8000_write_word(state, 288, ~seg_mask13 | seg_diff_mask); /* P_tmcc_seg_eq_inh */
-	if (!autosearching)
-		dib8000_write_word(state, 288, (~seg_mask13 | seg_diff_mask) & 0x1fff);	/* P_tmcc_seg_eq_inh */
-	else
-		dib8000_write_word(state, 288, 0x1fff);	//disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels.
-	dprintk("287 = %X (%d)", ~seg_mask13 | 0x1000, ~seg_mask13 | 0x1000);
-
-	dib8000_write_word(state, 211, seg_mask13 & (~seg_diff_mask));	/* P_des_seg_enabled     */
-
-	/* offset loop parameters */
-	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
-		if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
-			/* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */
-			dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x40);
-
-		else		// Sound Broadcasting mode 3 seg
-			/* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */
-			dib8000_write_word(state, 32, ((10 - mode) << 12) | (6 << 8) | 0x60);
-	} else
-		// TODO in 13 seg, timf_alpha can always be the same or not ?
-		/* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
-		dib8000_write_word(state, 32, ((9 - mode) << 12) | (6 << 8) | 0x80);
-
-	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
-		if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
-			/* P_ctrl_pha_off_max=3   P_ctrl_sfreq_inh =0  P_ctrl_sfreq_step = (11-P_mode)  */
-			dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (10 - mode));
-
-		else		// Sound Broadcasting mode 3 seg
-			/* P_ctrl_pha_off_max=3   P_ctrl_sfreq_inh =0  P_ctrl_sfreq_step = (10-P_mode)  */
-			dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (9 - mode));
-	} else
-		/* P_ctrl_pha_off_max=3   P_ctrl_sfreq_inh =0  P_ctrl_sfreq_step = 9  */
-		dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (8 - mode));
-
-	/* P_dvsy_sync_wait - reuse mode */
-	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
-	case TRANSMISSION_MODE_8K:
-		mode = 256;
-		break;
-	case TRANSMISSION_MODE_4K:
-		mode = 128;
-		break;
-	default:
-	case TRANSMISSION_MODE_2K:
-		mode = 64;
-		break;
-	}
-	if (state->cfg.diversity_delay == 0)
-		mode = (mode * (1 << (guard)) * 3) / 2 + 48;	// add 50% SFN margin + compensate for one DVSY-fifo
-	else
-		mode = (mode * (1 << (guard)) * 3) / 2 + state->cfg.diversity_delay;	// add 50% SFN margin + compensate for DVSY-fifo
-	mode <<= 4;
-	dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | mode);
-
-	/* channel estimation fine configuration */
-	switch (max_constellation) {
-	case QAM_64:
-		ana_gain = 0x7;	// -1 : avoid def_est saturation when ADC target is -16dB
-		coeff[0] = 0x0148;	/* P_adp_regul_cnt 0.04 */
-		coeff[1] = 0xfff0;	/* P_adp_noise_cnt -0.002 */
-		coeff[2] = 0x00a4;	/* P_adp_regul_ext 0.02 */
-		coeff[3] = 0xfff8;	/* P_adp_noise_ext -0.001 */
-		//if (!state->cfg.hostbus_diversity) //if diversity, we should prehaps use the configuration of the max_constallation -1
-		break;
-	case QAM_16:
-		ana_gain = 0x7;	// -1 : avoid def_est saturation when ADC target is -16dB
-		coeff[0] = 0x023d;	/* P_adp_regul_cnt 0.07 */
-		coeff[1] = 0xffdf;	/* P_adp_noise_cnt -0.004 */
-		coeff[2] = 0x00a4;	/* P_adp_regul_ext 0.02 */
-		coeff[3] = 0xfff0;	/* P_adp_noise_ext -0.002 */
-		//if (!((state->cfg.hostbus_diversity) && (max_constellation == QAM_16)))
-		break;
-	default:
-		ana_gain = 0;	// 0 : goes along with ADC target at -22dB to keep good mobile performance and lock at sensitivity level
-		coeff[0] = 0x099a;	/* P_adp_regul_cnt 0.3 */
-		coeff[1] = 0xffae;	/* P_adp_noise_cnt -0.01 */
-		coeff[2] = 0x0333;	/* P_adp_regul_ext 0.1 */
-		coeff[3] = 0xfff8;	/* P_adp_noise_ext -0.002 */
-		break;
-	}
-	for (mode = 0; mode < 4; mode++)
-		dib8000_write_word(state, 215 + mode, coeff[mode]);
-
-	// update ana_gain depending on max constellation
-	dib8000_write_word(state, 116, ana_gain);
-	// update ADC target depending on ana_gain
-	if (ana_gain) {		// set -16dB ADC target for ana_gain=-1
-		for (i = 0; i < 10; i++)
-			dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
-	} else {		// set -22dB ADC target for ana_gain=0
-		for (i = 0; i < 10; i++)
-			dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
-	}
-
-	// ---- ANA_FE ----
-	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
-		if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
-			ana_fe = ana_fe_coeff_3seg;
-		else		// 1-segment
-			ana_fe = ana_fe_coeff_1seg;
-	} else
-		ana_fe = ana_fe_coeff_13seg;
-
-	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 || state->isdbt_cfg_loaded == 0)
-		for (mode = 0; mode < 24; mode++)
-			dib8000_write_word(state, 117 + mode, ana_fe[mode]);
-
-	// ---- CHAN_BLK ----
-	for (i = 0; i < 13; i++) {
-		if ((((~seg_diff_mask) >> i) & 1) == 1) {
-			P_cfr_left_edge += (1 << i) * ((i == 0) || ((((seg_mask13 & (~seg_diff_mask)) >> (i - 1)) & 1) == 0));
-			P_cfr_right_edge += (1 << i) * ((i == 12) || ((((seg_mask13 & (~seg_diff_mask)) >> (i + 1)) & 1) == 0));
-		}
-	}
-	dib8000_write_word(state, 222, P_cfr_left_edge);	// P_cfr_left_edge
-	dib8000_write_word(state, 223, P_cfr_right_edge);	// P_cfr_right_edge
-	// "P_cspu_left_edge"  not used => do not care
-	// "P_cspu_right_edge" not used => do not care
-
-	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
-		dib8000_write_word(state, 228, 1);	// P_2d_mode_byp=1
-		dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0);	// P_cspu_win_cut = 0
-		if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0
-			&& state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) {
-			//dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); // P_adp_pass = 0
-			dib8000_write_word(state, 265, 15);	// P_equal_noise_sel = 15
-		}
-	} else if (state->isdbt_cfg_loaded == 0) {
-		dib8000_write_word(state, 228, 0);	// default value
-		dib8000_write_word(state, 265, 31);	// default value
-		dib8000_write_word(state, 205, 0x200f);	// init value
-	}
-	// ---- TMCC ----
-	for (i = 0; i < 3; i++)
-		tmcc_pow +=
-			(((state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe[0]->dtv_property_cache.layer[i].segment_count);
-	// Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9);
-	// Threshold is set at 1/4 of max power.
-	tmcc_pow *= (1 << (9 - 2));
-
-	dib8000_write_word(state, 290, tmcc_pow);	// P_tmcc_dec_thres_2k
-	dib8000_write_word(state, 291, tmcc_pow);	// P_tmcc_dec_thres_4k
-	dib8000_write_word(state, 292, tmcc_pow);	// P_tmcc_dec_thres_8k
-	//dib8000_write_word(state, 287, (1 << 13) | 0x1000 );
-	// ---- PHA3 ----
-
-	if (state->isdbt_cfg_loaded == 0)
-		dib8000_write_word(state, 250, 3285);	/*p_2d_hspeed_thr0 */
-
-	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
-		state->isdbt_cfg_loaded = 0;
-	else
-		state->isdbt_cfg_loaded = 1;
-
-}
-
-static int dib8000_autosearch_start(struct dvb_frontend *fe)
-{
-	u8 factor;
-	u32 value;
-	struct dib8000_state *state = fe->demodulator_priv;
-
-	int slist = 0;
-
-	state->fe[0]->dtv_property_cache.inversion = 0;
-	if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode)
-		state->fe[0]->dtv_property_cache.layer[0].segment_count = 13;
-	state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64;
-	state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3;
-	state->fe[0]->dtv_property_cache.layer[0].interleaving = 0;
-
-	//choose the right list, in sb, always do everything
-	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
-		state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
-		state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
-		slist = 7;
-		dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
-	} else {
-		if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) {
-			if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
-				slist = 7;
-				dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));	// P_mode = 1 to have autosearch start ok with mode2
-			} else
-				slist = 3;
-		} else {
-			if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
-				slist = 2;
-				dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));	// P_mode = 1
-			} else
-				slist = 0;
-		}
-
-		if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO)
-			state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
-		if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO)
-			state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
-
-		dprintk("using list for autosearch : %d", slist);
-		dib8000_set_channel(state, (unsigned char)slist, 1);
-		//dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));  // P_mode = 1
-
-		factor = 1;
-
-		//set lock_mask values
-		dib8000_write_word(state, 6, 0x4);
-		dib8000_write_word(state, 7, 0x8);
-		dib8000_write_word(state, 8, 0x1000);
-
-		//set lock_mask wait time values
-		value = 50 * state->cfg.pll->internal * factor;
-		dib8000_write_word(state, 11, (u16) ((value >> 16) & 0xffff));	// lock0 wait time
-		dib8000_write_word(state, 12, (u16) (value & 0xffff));	// lock0 wait time
-		value = 100 * state->cfg.pll->internal * factor;
-		dib8000_write_word(state, 13, (u16) ((value >> 16) & 0xffff));	// lock1 wait time
-		dib8000_write_word(state, 14, (u16) (value & 0xffff));	// lock1 wait time
-		value = 1000 * state->cfg.pll->internal * factor;
-		dib8000_write_word(state, 15, (u16) ((value >> 16) & 0xffff));	// lock2 wait time
-		dib8000_write_word(state, 16, (u16) (value & 0xffff));	// lock2 wait time
-
-		value = dib8000_read_word(state, 0);
-		dib8000_write_word(state, 0, (u16) ((1 << 15) | value));
-		dib8000_read_word(state, 1284);	// reset the INT. n_irq_pending
-		dib8000_write_word(state, 0, (u16) value);
-
-	}
-
-	return 0;
-}
-
-static int dib8000_autosearch_irq(struct dvb_frontend *fe)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u16 irq_pending = dib8000_read_word(state, 1284);
-
-	if (irq_pending & 0x1) {	// failed
-		dprintk("dib8000_autosearch_irq failed");
-		return 1;
-	}
-
-	if (irq_pending & 0x2) {	// succeeded
-		dprintk("dib8000_autosearch_irq succeeded");
-		return 2;
-	}
-
-	return 0;		// still pending
-}
-
-static int dib8000_tune(struct dvb_frontend *fe)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	int ret = 0;
-	u16 lock, value, mode;
-
-	// we are already tuned - just resuming from suspend
-	if (state == NULL)
-		return -EINVAL;
-
-	mode = fft_to_mode(state);
-
-	dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000);
-	dib8000_set_channel(state, 0, 0);
-
-	// restart demod
-	ret |= dib8000_write_word(state, 770, 0x4000);
-	ret |= dib8000_write_word(state, 770, 0x0000);
-	msleep(45);
-
-	/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3 */
-	/*  ret |= dib8000_write_word(state, 29, (0 << 9) | (4 << 5) | (0 << 4) | (3 << 0) );  workaround inh_isi stays at 1 */
-
-	// never achieved a lock before - wait for timfreq to update
-	if (state->timf == 0) {
-		if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
-			if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
-				msleep(300);
-			else	// Sound Broadcasting mode 3 seg
-				msleep(500);
-		} else		// 13 seg
-			msleep(200);
-	}
-	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
-		if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
-
-			/* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40  alpha to check on board */
-			dib8000_write_word(state, 32, ((13 - mode) << 12) | (6 << 8) | 0x40);
-			//dib8000_write_word(state, 32, (8 << 12) | (6 << 8) | 0x80);
-
-			/*  P_ctrl_sfreq_step= (12-P_mode)   P_ctrl_sfreq_inh =0     P_ctrl_pha_off_max  */
-			ret |= dib8000_write_word(state, 37, (12 - mode) | ((5 + mode) << 5));
-
-		} else {	// Sound Broadcasting mode 3 seg
-
-			/* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60  alpha to check on board */
-			dib8000_write_word(state, 32, ((12 - mode) << 12) | (6 << 8) | 0x60);
-
-			ret |= dib8000_write_word(state, 37, (11 - mode) | ((5 + mode) << 5));
-		}
-
-	} else {		// 13 seg
-		/* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80  alpha to check on board */
-		dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x80);
-
-		ret |= dib8000_write_word(state, 37, (10 - mode) | ((5 + mode) << 5));
-
-	}
-
-	// we achieved a coff_cpil_lock - it's time to update the timf
-	if (state->revision != 0x8090)
-		lock = dib8000_read_word(state, 568);
-	else
-		lock = dib8000_read_word(state, 570);
-	if ((lock >> 11) & 0x1)
-		dib8000_update_timf(state);
-
-	//now that tune is finished, lock0 should lock on fec_mpeg to output this lock on MP_LOCK. It's changed in autosearch start
-	dib8000_write_word(state, 6, 0x200);
-
-	if (state->revision == 0x8002) {
-		value = dib8000_read_word(state, 903);
-		dib8000_write_word(state, 903, value & ~(1 << 3));
-		msleep(1);
-		dib8000_write_word(state, 903, value | (1 << 3));
-	}
-
-	return ret;
-}
-
-static int dib8000_wakeup(struct dvb_frontend *fe)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u8 index_frontend;
-	int ret;
-
-	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
-	dib8000_set_adc_state(state, DIBX000_ADC_ON);
-	if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
-		dprintk("could not start Slow ADC");
-
-	if (state->revision != 0x8090)
-		dib8000_sad_calib(state);
-
-	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-		ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
-		if (ret < 0)
-			return ret;
-	}
-
-	return 0;
-}
-
-static int dib8000_sleep(struct dvb_frontend *fe)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u8 index_frontend;
-	int ret;
-
-	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-		ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
-		if (ret < 0)
-			return ret;
-	}
-
-	if (state->revision != 0x8090)
-		dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
-	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
-	return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
-}
-
-enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	return state->tune_state;
-}
-EXPORT_SYMBOL(dib8000_get_tune_state);
-
-int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	state->tune_state = tune_state;
-	return 0;
-}
-EXPORT_SYMBOL(dib8000_set_tune_state);
-
-static int dib8000_get_frontend(struct dvb_frontend *fe)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u16 i, val = 0;
-	fe_status_t stat;
-	u8 index_frontend, sub_index_frontend;
-
-	fe->dtv_property_cache.bandwidth_hz = 6000000;
-
-	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-		state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
-		if (stat&FE_HAS_SYNC) {
-			dprintk("TMCC lock on the slave%i", index_frontend);
-			/* synchronize the cache with the other frontends */
-			state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]);
-			for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) {
-				if (sub_index_frontend != index_frontend) {
-					state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
-					state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
-					state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
-					state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
-					state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
-					for (i = 0; i < 3; i++) {
-						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
-						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
-						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
-						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
-					}
-				}
-			}
-			return 0;
-		}
-	}
-
-	fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
-
-	if (state->revision == 0x8090)
-		val = dib8000_read_word(state, 572);
-	else
-		val = dib8000_read_word(state, 570);
-	fe->dtv_property_cache.inversion = (val & 0x40) >> 6;
-	switch ((val & 0x30) >> 4) {
-	case 1:
-		fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
-		break;
-	case 3:
-	default:
-		fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
-		break;
-	}
-
-	switch (val & 0x3) {
-	case 0:
-		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
-		dprintk("dib8000_get_frontend GI = 1/32 ");
-		break;
-	case 1:
-		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
-		dprintk("dib8000_get_frontend GI = 1/16 ");
-		break;
-	case 2:
-		dprintk("dib8000_get_frontend GI = 1/8 ");
-		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
-		break;
-	case 3:
-		dprintk("dib8000_get_frontend GI = 1/4 ");
-		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
-		break;
-	}
-
-	val = dib8000_read_word(state, 505);
-	fe->dtv_property_cache.isdbt_partial_reception = val & 1;
-	dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
-
-	for (i = 0; i < 3; i++) {
-		val = dib8000_read_word(state, 493 + i);
-		fe->dtv_property_cache.layer[i].segment_count = val & 0x0F;
-		dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count);
-
-		val = dib8000_read_word(state, 499 + i);
-		fe->dtv_property_cache.layer[i].interleaving = val & 0x3;
-		dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving);
-
-		val = dib8000_read_word(state, 481 + i);
-		switch (val & 0x7) {
-		case 1:
-			fe->dtv_property_cache.layer[i].fec = FEC_1_2;
-			dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i);
-			break;
-		case 2:
-			fe->dtv_property_cache.layer[i].fec = FEC_2_3;
-			dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i);
-			break;
-		case 3:
-			fe->dtv_property_cache.layer[i].fec = FEC_3_4;
-			dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i);
-			break;
-		case 5:
-			fe->dtv_property_cache.layer[i].fec = FEC_5_6;
-			dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i);
-			break;
-		default:
-			fe->dtv_property_cache.layer[i].fec = FEC_7_8;
-			dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i);
-			break;
-		}
-
-		val = dib8000_read_word(state, 487 + i);
-		switch (val & 0x3) {
-		case 0:
-			dprintk("dib8000_get_frontend : Layer %d DQPSK ", i);
-			fe->dtv_property_cache.layer[i].modulation = DQPSK;
-			break;
-		case 1:
-			fe->dtv_property_cache.layer[i].modulation = QPSK;
-			dprintk("dib8000_get_frontend : Layer %d QPSK ", i);
-			break;
-		case 2:
-			fe->dtv_property_cache.layer[i].modulation = QAM_16;
-			dprintk("dib8000_get_frontend : Layer %d QAM16 ", i);
-			break;
-		case 3:
-		default:
-			dprintk("dib8000_get_frontend : Layer %d QAM64 ", i);
-			fe->dtv_property_cache.layer[i].modulation = QAM_64;
-			break;
-		}
-	}
-
-	/* synchronize the cache with the other frontends */
-	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-		state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode;
-		state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
-		state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
-		state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
-		state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception;
-		for (i = 0; i < 3; i++) {
-			state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count;
-			state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving;
-			state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec;
-			state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation;
-		}
-	}
-	return 0;
-}
-
-static int dib8000_set_frontend(struct dvb_frontend *fe)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u8 nbr_pending, exit_condition, index_frontend;
-	s8 index_frontend_success = -1;
-	int time, ret;
-	int  time_slave = FE_CALLBACK_TIME_NEVER;
-
-	if (state->fe[0]->dtv_property_cache.frequency == 0) {
-		dprintk("dib8000: must at least specify frequency ");
-		return 0;
-	}
-
-	if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) {
-		dprintk("dib8000: no bandwidth specified, set to default ");
-		state->fe[0]->dtv_property_cache.bandwidth_hz = 6000000;
-	}
-
-	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-		/* synchronization of the cache */
-		state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
-		memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
-
-		if (state->revision != 0x8090)
-			dib8000_set_output_mode(state->fe[index_frontend],
-					OUTMODE_HIGH_Z);
-		else
-			dib8096p_set_output_mode(state->fe[index_frontend],
-					OUTMODE_HIGH_Z);
-		if (state->fe[index_frontend]->ops.tuner_ops.set_params)
-			state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
-
-		dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
-	}
-
-	/* start up the AGC */
-	do {
-		time = dib8000_agc_startup(state->fe[0]);
-		for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-			time_slave = dib8000_agc_startup(state->fe[index_frontend]);
-			if (time == FE_CALLBACK_TIME_NEVER)
-				time = time_slave;
-			else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time))
-				time = time_slave;
-		}
-		if (time != FE_CALLBACK_TIME_NEVER)
-			msleep(time / 10);
-		else
-			break;
-		exit_condition = 1;
-		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-			if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
-				exit_condition = 0;
-				break;
-			}
-		}
-	} while (exit_condition == 0);
-
-	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
-		dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
-
-	if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) ||
-			(state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) ||
-			(state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) ||
-			(state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) ||
-			(((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) &&
-			 (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) &&
-			 (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) &&
-			 ((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) ||
-			  (state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) ||
-			(((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) &&
-			 (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) &&
-			 (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) &&
-			 ((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) ||
-			  (state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) ||
-			(((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) &&
-			 (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) &&
-			 (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) &&
-			 ((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) ||
-			  (state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) ||
-			(((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) ||
-			  ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) &&
-			 ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) ||
-			  ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) &&
-			 ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) {
-		int i = 100;
-		u8 found = 0;
-		u8 tune_failed = 0;
-
-		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-			dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000);
-			dib8000_autosearch_start(state->fe[index_frontend]);
-		}
-
-		do {
-			msleep(20);
-			nbr_pending = 0;
-			exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */
-			for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-				if (((tune_failed >> index_frontend) & 0x1) == 0) {
-					found = dib8000_autosearch_irq(state->fe[index_frontend]);
-					switch (found) {
-					case 0: /* tune pending */
-						 nbr_pending++;
-						 break;
-					case 2:
-						 dprintk("autosearch succeed on the frontend%i", index_frontend);
-						 exit_condition = 2;
-						 index_frontend_success = index_frontend;
-						 break;
-					default:
-						 dprintk("unhandled autosearch result");
-					case 1:
-						 tune_failed |= (1 << index_frontend);
-						 dprintk("autosearch failed for the frontend%i", index_frontend);
-						 break;
-					}
-				}
-			}
-
-			/* if all tune are done and no success, exit: tune failed */
-			if ((nbr_pending == 0) && (exit_condition == 0))
-				exit_condition = 1;
-		} while ((exit_condition == 0) && i--);
-
-		if (exit_condition == 1) { /* tune failed */
-			dprintk("tune failed");
-			return 0;
-		}
-
-		dprintk("tune success on frontend%i", index_frontend_success);
-
-		dib8000_get_frontend(fe);
-	}
-
-	for (index_frontend = 0, ret = 0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
-		ret = dib8000_tune(state->fe[index_frontend]);
-
-	/* set output mode and diversity input */
-	if (state->revision != 0x8090) {
-		dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
-		for (index_frontend = 1;
-				(index_frontend < MAX_NUMBER_OF_FRONTENDS) &&
-				(state->fe[index_frontend] != NULL);
-				index_frontend++) {
-			dib8000_set_output_mode(state->fe[index_frontend],
-					OUTMODE_DIVERSITY);
-			dib8000_set_diversity_in(state->fe[index_frontend-1], 1);
-		}
-
-		/* turn off the diversity of the last chip */
-		dib8000_set_diversity_in(state->fe[index_frontend-1], 0);
-	} else {
-		dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
-		if (state->cfg.enMpegOutput == 0) {
-			dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
-			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
-		}
-		for (index_frontend = 1;
-				(index_frontend < MAX_NUMBER_OF_FRONTENDS) &&
-				(state->fe[index_frontend] != NULL);
-				index_frontend++) {
-			dib8096p_set_output_mode(state->fe[index_frontend],
-					OUTMODE_DIVERSITY);
-			dib8096p_set_diversity_in(state->fe[index_frontend-1], 1);
-		}
-
-		/* turn off the diversity of the last chip */
-		dib8096p_set_diversity_in(state->fe[index_frontend-1], 0);
-	}
-
-	return ret;
-}
-
-static u16 dib8000_read_lock(struct dvb_frontend *fe)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-
-	if (state->revision == 0x8090)
-		return dib8000_read_word(state, 570);
-	return dib8000_read_word(state, 568);
-}
-
-static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u16 lock_slave = 0, lock;
-	u8 index_frontend;
-
-	if (state->revision == 0x8090)
-		lock = dib8000_read_word(state, 570);
-	else
-		lock = dib8000_read_word(state, 568);
-
-	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
-		lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
-
-	*stat = 0;
-
-	if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
-		*stat |= FE_HAS_SIGNAL;
-
-	if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
-		*stat |= FE_HAS_CARRIER;
-
-	if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
-		*stat |= FE_HAS_SYNC;
-
-	if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
-		*stat |= FE_HAS_LOCK;
-
-	if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
-		lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
-		if (lock & 0x01)
-			*stat |= FE_HAS_VITERBI;
-
-		lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
-		if (lock & 0x01)
-			*stat |= FE_HAS_VITERBI;
-
-		lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
-		if (lock & 0x01)
-			*stat |= FE_HAS_VITERBI;
-	}
-
-	return 0;
-}
-
-static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-
-	/* 13 segments */
-	if (state->revision == 0x8090)
-		*ber = (dib8000_read_word(state, 562) << 16) |
-			dib8000_read_word(state, 563);
-	else
-		*ber = (dib8000_read_word(state, 560) << 16) |
-			dib8000_read_word(state, 561);
-	return 0;
-}
-
-static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-
-	/* packet error on 13 seg */
-	if (state->revision == 0x8090)
-		*unc = dib8000_read_word(state, 567);
-	else
-		*unc = dib8000_read_word(state, 565);
-	return 0;
-}
-
-static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u8 index_frontend;
-	u16 val;
-
-	*strength = 0;
-	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-		state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
-		if (val > 65535 - *strength)
-			*strength = 65535;
-		else
-			*strength += val;
-	}
-
-	val = 65535 - dib8000_read_word(state, 390);
-	if (val > 65535 - *strength)
-		*strength = 65535;
-	else
-		*strength += val;
-	return 0;
-}
-
-static u32 dib8000_get_snr(struct dvb_frontend *fe)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u32 n, s, exp;
-	u16 val;
-
-	if (state->revision != 0x8090)
-		val = dib8000_read_word(state, 542);
-	else
-		val = dib8000_read_word(state, 544);
-	n = (val >> 6) & 0xff;
-	exp = (val & 0x3f);
-	if ((exp & 0x20) != 0)
-		exp -= 0x40;
-	n <<= exp+16;
-
-	if (state->revision != 0x8090)
-		val = dib8000_read_word(state, 543);
-	else
-		val = dib8000_read_word(state, 545);
-	s = (val >> 6) & 0xff;
-	exp = (val & 0x3f);
-	if ((exp & 0x20) != 0)
-		exp -= 0x40;
-	s <<= exp+16;
-
-	if (n > 0) {
-		u32 t = (s/n) << 16;
-		return t + ((s << 16) - n*t) / n;
-	}
-	return 0xffffffff;
-}
-
-static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u8 index_frontend;
-	u32 snr_master;
-
-	snr_master = dib8000_get_snr(fe);
-	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
-		snr_master += dib8000_get_snr(state->fe[index_frontend]);
-
-	if ((snr_master >> 16) != 0) {
-		snr_master = 10*intlog10(snr_master>>16);
-		*snr = snr_master / ((1 << 24) / 10);
-	}
-	else
-		*snr = 0;
-
-	return 0;
-}
-
-int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u8 index_frontend = 1;
-
-	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
-		index_frontend++;
-	if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
-		dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
-		state->fe[index_frontend] = fe_slave;
-		return 0;
-	}
-
-	dprintk("too many slave frontend");
-	return -ENOMEM;
-}
-EXPORT_SYMBOL(dib8000_set_slave_frontend);
-
-int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-	u8 index_frontend = 1;
-
-	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
-		index_frontend++;
-	if (index_frontend != 1) {
-		dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1);
-		state->fe[index_frontend] = NULL;
-		return 0;
-	}
-
-	dprintk("no frontend to be removed");
-	return -ENODEV;
-}
-EXPORT_SYMBOL(dib8000_remove_slave_frontend);
-
-struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
-{
-	struct dib8000_state *state = fe->demodulator_priv;
-
-	if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
-		return NULL;
-	return state->fe[slave_index];
-}
-EXPORT_SYMBOL(dib8000_get_slave_frontend);
-
-
-int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
-		u8 default_addr, u8 first_addr, u8 is_dib8096p)
-{
-	int k = 0, ret = 0;
-	u8 new_addr = 0;
-	struct i2c_device client = {.adap = host };
-
-	client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
-	if (!client.i2c_write_buffer) {
-		dprintk("%s: not enough memory", __func__);
-		return -ENOMEM;
-	}
-	client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
-	if (!client.i2c_read_buffer) {
-		dprintk("%s: not enough memory", __func__);
-		ret = -ENOMEM;
-		goto error_memory_read;
-	}
-	client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
-	if (!client.i2c_buffer_lock) {
-		dprintk("%s: not enough memory", __func__);
-		ret = -ENOMEM;
-		goto error_memory_lock;
-	}
-	mutex_init(client.i2c_buffer_lock);
-
-	for (k = no_of_demods - 1; k >= 0; k--) {
-		/* designated i2c address */
-		new_addr = first_addr + (k << 1);
-
-		client.addr = new_addr;
-		if (!is_dib8096p)
-			dib8000_i2c_write16(&client, 1287, 0x0003);	/* sram lead in, rdy */
-		if (dib8000_identify(&client) == 0) {
-			/* sram lead in, rdy */
-			if (!is_dib8096p)
-				dib8000_i2c_write16(&client, 1287, 0x0003);
-			client.addr = default_addr;
-			if (dib8000_identify(&client) == 0) {
-				dprintk("#%d: not identified", k);
-				ret  = -EINVAL;
-				goto error;
-			}
-		}
-
-		/* start diversity to pull_down div_str - just for i2c-enumeration */
-		dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
-
-		/* set new i2c address and force divstart */
-		dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
-		client.addr = new_addr;
-		dib8000_identify(&client);
-
-		dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
-	}
-
-	for (k = 0; k < no_of_demods; k++) {
-		new_addr = first_addr | (k << 1);
-		client.addr = new_addr;
-
-		// unforce divstr
-		dib8000_i2c_write16(&client, 1285, new_addr << 2);
-
-		/* deactivate div - it was just for i2c-enumeration */
-		dib8000_i2c_write16(&client, 1286, 0);
-	}
-
-error:
-	kfree(client.i2c_buffer_lock);
-error_memory_lock:
-	kfree(client.i2c_read_buffer);
-error_memory_read:
-	kfree(client.i2c_write_buffer);
-
-	return ret;
-}
-
-EXPORT_SYMBOL(dib8000_i2c_enumeration);
-static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
-{
-	tune->min_delay_ms = 1000;
-	tune->step_size = 0;
-	tune->max_drift = 0;
-	return 0;
-}
-
-static void dib8000_release(struct dvb_frontend *fe)
-{
-	struct dib8000_state *st = fe->demodulator_priv;
-	u8 index_frontend;
-
-	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
-		dvb_frontend_detach(st->fe[index_frontend]);
-
-	dibx000_exit_i2c_master(&st->i2c_master);
-	i2c_del_adapter(&st->dib8096p_tuner_adap);
-	kfree(st->fe[0]);
-	kfree(st);
-}
-
-struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
-{
-	struct dib8000_state *st = fe->demodulator_priv;
-	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
-}
-
-EXPORT_SYMBOL(dib8000_get_i2c_master);
-
-int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
-{
-	struct dib8000_state *st = fe->demodulator_priv;
-	u16 val = dib8000_read_word(st, 299) & 0xffef;
-	val |= (onoff & 0x1) << 4;
-
-	dprintk("pid filter enabled %d", onoff);
-	return dib8000_write_word(st, 299, val);
-}
-EXPORT_SYMBOL(dib8000_pid_filter_ctrl);
-
-int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
-{
-	struct dib8000_state *st = fe->demodulator_priv;
-	dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
-	return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
-}
-EXPORT_SYMBOL(dib8000_pid_filter);
-
-static const struct dvb_frontend_ops dib8000_ops = {
-	.delsys = { SYS_ISDBT },
-	.info = {
-		 .name = "DiBcom 8000 ISDB-T",
-		 .frequency_min = 44250000,
-		 .frequency_max = 867250000,
-		 .frequency_stepsize = 62500,
-		 .caps = FE_CAN_INVERSION_AUTO |
-		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
-		 },
-
-	.release = dib8000_release,
-
-	.init = dib8000_wakeup,
-	.sleep = dib8000_sleep,
-
-	.set_frontend = dib8000_set_frontend,
-	.get_tune_settings = dib8000_fe_get_tune_settings,
-	.get_frontend = dib8000_get_frontend,
-
-	.read_status = dib8000_read_status,
-	.read_ber = dib8000_read_ber,
-	.read_signal_strength = dib8000_read_signal_strength,
-	.read_snr = dib8000_read_snr,
-	.read_ucblocks = dib8000_read_unc_blocks,
-};
-
-struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
-{
-	struct dvb_frontend *fe;
-	struct dib8000_state *state;
-
-	dprintk("dib8000_attach");
-
-	state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
-	if (state == NULL)
-		return NULL;
-	fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
-	if (fe == NULL)
-		goto error;
-
-	memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
-	state->i2c.adap = i2c_adap;
-	state->i2c.addr = i2c_addr;
-	state->i2c.i2c_write_buffer = state->i2c_write_buffer;
-	state->i2c.i2c_read_buffer = state->i2c_read_buffer;
-	mutex_init(&state->i2c_buffer_lock);
-	state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
-	state->gpio_val = cfg->gpio_val;
-	state->gpio_dir = cfg->gpio_dir;
-
-	/* Ensure the output mode remains at the previous default if it's
-	 * not specifically set by the caller.
-	 */
-	if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
-		state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
-
-	state->fe[0] = fe;
-	fe->demodulator_priv = state;
-	memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
-
-	state->timf_default = cfg->pll->timf;
-
-	if (dib8000_identify(&state->i2c) == 0)
-		goto error;
-
-	dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
-
-	/* init 8096p tuner adapter */
-	strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface",
-			sizeof(state->dib8096p_tuner_adap.name));
-	state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo;
-	state->dib8096p_tuner_adap.algo_data = NULL;
-	state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent;
-	i2c_set_adapdata(&state->dib8096p_tuner_adap, state);
-	i2c_add_adapter(&state->dib8096p_tuner_adap);
-
-	dib8000_reset(fe);
-
-	dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));	/* ber_rs_len = 3 */
-
-	return fe;
-
- error:
-	kfree(state);
-	return NULL;
-}
-
-EXPORT_SYMBOL(dib8000_attach);
-
-MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>");
-MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dib8000.h b/drivers/media/dvb/frontends/dib8000.h
deleted file mode 100644
index 39591bb..0000000
--- a/drivers/media/dvb/frontends/dib8000.h
+++ /dev/null
@@ -1,174 +0,0 @@
-#ifndef DIB8000_H
-#define DIB8000_H
-
-#include "dibx000_common.h"
-
-struct dib8000_config {
-	u8 output_mpeg2_in_188_bytes;
-	u8 hostbus_diversity;
-	u8 tuner_is_baseband;
-	int (*update_lna) (struct dvb_frontend *, u16 agc_global);
-
-	u8 agc_config_count;
-	struct dibx000_agc_config *agc;
-	struct dibx000_bandwidth_config *pll;
-
-#define DIB8000_GPIO_DEFAULT_DIRECTIONS 0xffff
-	u16 gpio_dir;
-#define DIB8000_GPIO_DEFAULT_VALUES     0x0000
-	u16 gpio_val;
-#define DIB8000_GPIO_PWM_POS0(v)        ((v & 0xf) << 12)
-#define DIB8000_GPIO_PWM_POS1(v)        ((v & 0xf) << 8 )
-#define DIB8000_GPIO_PWM_POS2(v)        ((v & 0xf) << 4 )
-#define DIB8000_GPIO_PWM_POS3(v)         (v & 0xf)
-#define DIB8000_GPIO_DEFAULT_PWM_POS    0xffff
-	u16 gpio_pwm_pos;
-	u16 pwm_freq_div;
-
-	void (*agc_control) (struct dvb_frontend *, u8 before);
-
-	u16 drives;
-	u16 diversity_delay;
-	u8 div_cfg;
-	u8 output_mode;
-	u8 refclksel;
-	u8 enMpegOutput:1;
-};
-
-#define DEFAULT_DIB8000_I2C_ADDRESS 18
-
-#if defined(CONFIG_DVB_DIB8000) || (defined(CONFIG_DVB_DIB8000_MODULE) && defined(MODULE))
-extern struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg);
-extern struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
-
-extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
-		u8 default_addr, u8 first_addr, u8 is_dib8096p);
-
-extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
-extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value);
-extern int dib8000_pid_filter_ctrl(struct dvb_frontend *, u8 onoff);
-extern int dib8000_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
-extern int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state);
-extern enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe);
-extern void dib8000_pwm_agc_reset(struct dvb_frontend *fe);
-extern s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode);
-extern struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe);
-extern int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff);
-extern int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ);
-extern u32 dib8000_ctrl_timf(struct dvb_frontend *fe,
-		uint8_t op, uint32_t timf);
-extern int dib8000_update_pll(struct dvb_frontend *fe,
-		struct dibx000_bandwidth_config *pll);
-extern int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave);
-extern int dib8000_remove_slave_frontend(struct dvb_frontend *fe);
-extern struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index);
-#else
-static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface i, int x)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline int dib8000_i2c_enumeration(struct i2c_adapter *host,
-		int no_of_demods, u8 default_addr, u8 first_addr,
-		u8 is_dib8096p)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-static inline int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-static inline enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return CT_SHUTDOWN;
-}
-static inline void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-}
-static inline struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-static inline int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return 0;
-}
-static inline s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return 0;
-}
-static inline int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return 0;
-}
-static inline u32 dib8000_ctrl_timf(struct dvb_frontend *fe,
-		uint8_t op, uint32_t timf)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return 0;
-}
-static inline int dib8000_update_pll(struct dvb_frontend *fe,
-		struct dibx000_bandwidth_config *pll)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-static inline int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c
deleted file mode 100644
index 6201c59..0000000
--- a/drivers/media/dvb/frontends/dib9000.c
+++ /dev/null
@@ -1,2590 +0,0 @@
-/*
- * Linux-DVB Driver for DiBcom's DiB9000 and demodulator-family.
- *
- * Copyright (C) 2005-10 DiBcom (http://www.dibcom.fr/)
- *
- * 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, version 2.
- */
-#include <linux/kernel.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-
-#include "dvb_math.h"
-#include "dvb_frontend.h"
-
-#include "dib9000.h"
-#include "dibx000_common.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
-
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB9000: "); printk(args); printk("\n"); } } while (0)
-#define MAX_NUMBER_OF_FRONTENDS 6
-
-struct i2c_device {
-	struct i2c_adapter *i2c_adap;
-	u8 i2c_addr;
-	u8 *i2c_read_buffer;
-	u8 *i2c_write_buffer;
-};
-
-struct dib9000_pid_ctrl {
-#define DIB9000_PID_FILTER_CTRL 0
-#define DIB9000_PID_FILTER      1
-	u8 cmd;
-	u8 id;
-	u16 pid;
-	u8 onoff;
-};
-
-struct dib9000_state {
-	struct i2c_device i2c;
-
-	struct dibx000_i2c_master i2c_master;
-	struct i2c_adapter tuner_adap;
-	struct i2c_adapter component_bus;
-
-	u16 revision;
-	u8 reg_offs;
-
-	enum frontend_tune_state tune_state;
-	u32 status;
-	struct dvb_frontend_parametersContext channel_status;
-
-	u8 fe_id;
-
-#define DIB9000_GPIO_DEFAULT_DIRECTIONS 0xffff
-	u16 gpio_dir;
-#define DIB9000_GPIO_DEFAULT_VALUES     0x0000
-	u16 gpio_val;
-#define DIB9000_GPIO_DEFAULT_PWM_POS    0xffff
-	u16 gpio_pwm_pos;
-
-	union {			/* common for all chips */
-		struct {
-			u8 mobile_mode:1;
-		} host;
-
-		struct {
-			struct dib9000_fe_memory_map {
-				u16 addr;
-				u16 size;
-			} fe_mm[18];
-			u8 memcmd;
-
-			struct mutex mbx_if_lock;	/* to protect read/write operations */
-			struct mutex mbx_lock;	/* to protect the whole mailbox handling */
-
-			struct mutex mem_lock;	/* to protect the memory accesses */
-			struct mutex mem_mbx_lock;	/* to protect the memory-based mailbox */
-
-#define MBX_MAX_WORDS (256 - 200 - 2)
-#define DIB9000_MSG_CACHE_SIZE 2
-			u16 message_cache[DIB9000_MSG_CACHE_SIZE][MBX_MAX_WORDS];
-			u8 fw_is_running;
-		} risc;
-	} platform;
-
-	union {			/* common for all platforms */
-		struct {
-			struct dib9000_config cfg;
-		} d9;
-	} chip;
-
-	struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
-	u16 component_bus_speed;
-
-	/* for the I2C transfer */
-	struct i2c_msg msg[2];
-	u8 i2c_write_buffer[255];
-	u8 i2c_read_buffer[255];
-	struct mutex demod_lock;
-	u8 get_frontend_internal;
-	struct dib9000_pid_ctrl pid_ctrl[10];
-	s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */
-};
-
-static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0
-};
-
-enum dib9000_power_mode {
-	DIB9000_POWER_ALL = 0,
-
-	DIB9000_POWER_NO,
-	DIB9000_POWER_INTERF_ANALOG_AGC,
-	DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD,
-	DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD,
-	DIB9000_POWER_INTERFACE_ONLY,
-};
-
-enum dib9000_out_messages {
-	OUT_MSG_HBM_ACK,
-	OUT_MSG_HOST_BUF_FAIL,
-	OUT_MSG_REQ_VERSION,
-	OUT_MSG_BRIDGE_I2C_W,
-	OUT_MSG_BRIDGE_I2C_R,
-	OUT_MSG_BRIDGE_APB_W,
-	OUT_MSG_BRIDGE_APB_R,
-	OUT_MSG_SCAN_CHANNEL,
-	OUT_MSG_MONIT_DEMOD,
-	OUT_MSG_CONF_GPIO,
-	OUT_MSG_DEBUG_HELP,
-	OUT_MSG_SUBBAND_SEL,
-	OUT_MSG_ENABLE_TIME_SLICE,
-	OUT_MSG_FE_FW_DL,
-	OUT_MSG_FE_CHANNEL_SEARCH,
-	OUT_MSG_FE_CHANNEL_TUNE,
-	OUT_MSG_FE_SLEEP,
-	OUT_MSG_FE_SYNC,
-	OUT_MSG_CTL_MONIT,
-
-	OUT_MSG_CONF_SVC,
-	OUT_MSG_SET_HBM,
-	OUT_MSG_INIT_DEMOD,
-	OUT_MSG_ENABLE_DIVERSITY,
-	OUT_MSG_SET_OUTPUT_MODE,
-	OUT_MSG_SET_PRIORITARY_CHANNEL,
-	OUT_MSG_ACK_FRG,
-	OUT_MSG_INIT_PMU,
-};
-
-enum dib9000_in_messages {
-	IN_MSG_DATA,
-	IN_MSG_FRAME_INFO,
-	IN_MSG_CTL_MONIT,
-	IN_MSG_ACK_FREE_ITEM,
-	IN_MSG_DEBUG_BUF,
-	IN_MSG_MPE_MONITOR,
-	IN_MSG_RAWTS_MONITOR,
-	IN_MSG_END_BRIDGE_I2C_RW,
-	IN_MSG_END_BRIDGE_APB_RW,
-	IN_MSG_VERSION,
-	IN_MSG_END_OF_SCAN,
-	IN_MSG_MONIT_DEMOD,
-	IN_MSG_ERROR,
-	IN_MSG_FE_FW_DL_DONE,
-	IN_MSG_EVENT,
-	IN_MSG_ACK_CHANGE_SVC,
-	IN_MSG_HBM_PROF,
-};
-
-/* memory_access requests */
-#define FE_MM_W_CHANNEL                   0
-#define FE_MM_W_FE_INFO                   1
-#define FE_MM_RW_SYNC                     2
-
-#define FE_SYNC_CHANNEL          1
-#define FE_SYNC_W_GENERIC_MONIT	 2
-#define FE_SYNC_COMPONENT_ACCESS 3
-
-#define FE_MM_R_CHANNEL_SEARCH_STATE      3
-#define FE_MM_R_CHANNEL_UNION_CONTEXT     4
-#define FE_MM_R_FE_INFO                   5
-#define FE_MM_R_FE_MONITOR                6
-
-#define FE_MM_W_CHANNEL_HEAD              7
-#define FE_MM_W_CHANNEL_UNION             8
-#define FE_MM_W_CHANNEL_CONTEXT           9
-#define FE_MM_R_CHANNEL_UNION            10
-#define FE_MM_R_CHANNEL_CONTEXT          11
-#define FE_MM_R_CHANNEL_TUNE_STATE       12
-
-#define FE_MM_R_GENERIC_MONITORING_SIZE	 13
-#define FE_MM_W_GENERIC_MONITORING	     14
-#define FE_MM_R_GENERIC_MONITORING	     15
-
-#define FE_MM_W_COMPONENT_ACCESS         16
-#define FE_MM_RW_COMPONENT_ACCESS_BUFFER 17
-static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len);
-static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len);
-
-static u16 to_fw_output_mode(u16 mode)
-{
-	switch (mode) {
-	case OUTMODE_HIGH_Z:
-		return 0;
-	case OUTMODE_MPEG2_PAR_GATED_CLK:
-		return 4;
-	case OUTMODE_MPEG2_PAR_CONT_CLK:
-		return 8;
-	case OUTMODE_MPEG2_SERIAL:
-		return 16;
-	case OUTMODE_DIVERSITY:
-		return 128;
-	case OUTMODE_MPEG2_FIFO:
-		return 2;
-	case OUTMODE_ANALOG_ADC:
-		return 1;
-	default:
-		return 0;
-	}
-}
-
-static u16 dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 * b, u32 len, u16 attribute)
-{
-	u32 chunk_size = 126;
-	u32 l;
-	int ret;
-
-	if (state->platform.risc.fw_is_running && (reg < 1024))
-		return dib9000_risc_apb_access_read(state, reg, attribute, NULL, 0, b, len);
-
-	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
-	state->msg[0].addr = state->i2c.i2c_addr >> 1;
-	state->msg[0].flags = 0;
-	state->msg[0].buf = state->i2c_write_buffer;
-	state->msg[0].len = 2;
-	state->msg[1].addr = state->i2c.i2c_addr >> 1;
-	state->msg[1].flags = I2C_M_RD;
-	state->msg[1].buf = b;
-	state->msg[1].len = len;
-
-	state->i2c_write_buffer[0] = reg >> 8;
-	state->i2c_write_buffer[1] = reg & 0xff;
-
-	if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
-		state->i2c_write_buffer[0] |= (1 << 5);
-	if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
-		state->i2c_write_buffer[0] |= (1 << 4);
-
-	do {
-		l = len < chunk_size ? len : chunk_size;
-		state->msg[1].len = l;
-		state->msg[1].buf = b;
-		ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 2) != 2 ? -EREMOTEIO : 0;
-		if (ret != 0) {
-			dprintk("i2c read error on %d", reg);
-			return -EREMOTEIO;
-		}
-
-		b += l;
-		len -= l;
-
-		if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT))
-			reg += l / 2;
-	} while ((ret == 0) && len);
-
-	return 0;
-}
-
-static u16 dib9000_i2c_read16(struct i2c_device *i2c, u16 reg)
-{
-	struct i2c_msg msg[2] = {
-		{.addr = i2c->i2c_addr >> 1, .flags = 0,
-			.buf = i2c->i2c_write_buffer, .len = 2},
-		{.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD,
-			.buf = i2c->i2c_read_buffer, .len = 2},
-	};
-
-	i2c->i2c_write_buffer[0] = reg >> 8;
-	i2c->i2c_write_buffer[1] = reg & 0xff;
-
-	if (i2c_transfer(i2c->i2c_adap, msg, 2) != 2) {
-		dprintk("read register %x error", reg);
-		return 0;
-	}
-
-	return (i2c->i2c_read_buffer[0] << 8) | i2c->i2c_read_buffer[1];
-}
-
-static inline u16 dib9000_read_word(struct dib9000_state *state, u16 reg)
-{
-	if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2, 0) != 0)
-		return 0;
-	return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
-}
-
-static inline u16 dib9000_read_word_attr(struct dib9000_state *state, u16 reg, u16 attribute)
-{
-	if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2,
-				attribute) != 0)
-		return 0;
-	return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
-}
-
-#define dib9000_read16_noinc_attr(state, reg, b, len, attribute) dib9000_read16_attr(state, reg, b, len, (attribute) | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
-
-static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 * buf, u32 len, u16 attribute)
-{
-	u32 chunk_size = 126;
-	u32 l;
-	int ret;
-
-	if (state->platform.risc.fw_is_running && (reg < 1024)) {
-		if (dib9000_risc_apb_access_write
-		    (state, reg, DATA_BUS_ACCESS_MODE_16BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | attribute, buf, len) != 0)
-			return -EINVAL;
-		return 0;
-	}
-
-	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
-	state->msg[0].addr = state->i2c.i2c_addr >> 1;
-	state->msg[0].flags = 0;
-	state->msg[0].buf = state->i2c_write_buffer;
-	state->msg[0].len = len + 2;
-
-	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
-	state->i2c_write_buffer[1] = (reg) & 0xff;
-
-	if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
-		state->i2c_write_buffer[0] |= (1 << 5);
-	if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
-		state->i2c_write_buffer[0] |= (1 << 4);
-
-	do {
-		l = len < chunk_size ? len : chunk_size;
-		state->msg[0].len = l + 2;
-		memcpy(&state->i2c_write_buffer[2], buf, l);
-
-		ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
-
-		buf += l;
-		len -= l;
-
-		if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT))
-			reg += l / 2;
-	} while ((ret == 0) && len);
-
-	return ret;
-}
-
-static int dib9000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
-{
-	struct i2c_msg msg = {
-		.addr = i2c->i2c_addr >> 1, .flags = 0,
-		.buf = i2c->i2c_write_buffer, .len = 4
-	};
-
-	i2c->i2c_write_buffer[0] = (reg >> 8) & 0xff;
-	i2c->i2c_write_buffer[1] = reg & 0xff;
-	i2c->i2c_write_buffer[2] = (val >> 8) & 0xff;
-	i2c->i2c_write_buffer[3] = val & 0xff;
-
-	return i2c_transfer(i2c->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
-}
-
-static inline int dib9000_write_word(struct dib9000_state *state, u16 reg, u16 val)
-{
-	u8 b[2] = { val >> 8, val & 0xff };
-	return dib9000_write16_attr(state, reg, b, 2, 0);
-}
-
-static inline int dib9000_write_word_attr(struct dib9000_state *state, u16 reg, u16 val, u16 attribute)
-{
-	u8 b[2] = { val >> 8, val & 0xff };
-	return dib9000_write16_attr(state, reg, b, 2, attribute);
-}
-
-#define dib9000_write(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, 0)
-#define dib9000_write16_noinc(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
-#define dib9000_write16_noinc_attr(state, reg, buf, len, attribute) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | (attribute))
-
-#define dib9000_mbx_send(state, id, data, len) dib9000_mbx_send_attr(state, id, data, len, 0)
-#define dib9000_mbx_get_message(state, id, msg, len) dib9000_mbx_get_message_attr(state, id, msg, len, 0)
-
-#define MAC_IRQ      (1 << 1)
-#define IRQ_POL_MSK  (1 << 4)
-
-#define dib9000_risc_mem_read_chunks(state, b, len) dib9000_read16_attr(state, 1063, b, len, DATA_BUS_ACCESS_MODE_8BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
-#define dib9000_risc_mem_write_chunks(state, buf, len) dib9000_write16_attr(state, 1063, buf, len, DATA_BUS_ACCESS_MODE_8BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
-
-static void dib9000_risc_mem_setup_cmd(struct dib9000_state *state, u32 addr, u32 len, u8 reading)
-{
-	u8 b[14] = { 0 };
-
-/*      dprintk("%d memcmd: %d %d %d\n", state->fe_id, addr, addr+len, len); */
-/*      b[0] = 0 << 7; */
-	b[1] = 1;
-
-/*      b[2] = 0; */
-/*      b[3] = 0; */
-	b[4] = (u8) (addr >> 8);
-	b[5] = (u8) (addr & 0xff);
-
-/*      b[10] = 0; */
-/*      b[11] = 0; */
-	b[12] = (u8) (addr >> 8);
-	b[13] = (u8) (addr & 0xff);
-
-	addr += len;
-/*      b[6] = 0; */
-/*      b[7] = 0; */
-	b[8] = (u8) (addr >> 8);
-	b[9] = (u8) (addr & 0xff);
-
-	dib9000_write(state, 1056, b, 14);
-	if (reading)
-		dib9000_write_word(state, 1056, (1 << 15) | 1);
-	state->platform.risc.memcmd = -1;	/* if it was called directly reset it - to force a future setup-call to set it */
-}
-
-static void dib9000_risc_mem_setup(struct dib9000_state *state, u8 cmd)
-{
-	struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd & 0x7f];
-	/* decide whether we need to "refresh" the memory controller */
-	if (state->platform.risc.memcmd == cmd &&	/* same command */
-	    !(cmd & 0x80 && m->size < 67))	/* and we do not want to read something with less than 67 bytes looping - working around a bug in the memory controller */
-		return;
-	dib9000_risc_mem_setup_cmd(state, m->addr, m->size, cmd & 0x80);
-	state->platform.risc.memcmd = cmd;
-}
-
-static int dib9000_risc_mem_read(struct dib9000_state *state, u8 cmd, u8 * b, u16 len)
-{
-	if (!state->platform.risc.fw_is_running)
-		return -EIO;
-
-	if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) {
-		dprintk("could not get the lock");
-		return -EINTR;
-	}
-	dib9000_risc_mem_setup(state, cmd | 0x80);
-	dib9000_risc_mem_read_chunks(state, b, len);
-	mutex_unlock(&state->platform.risc.mem_lock);
-	return 0;
-}
-
-static int dib9000_risc_mem_write(struct dib9000_state *state, u8 cmd, const u8 * b)
-{
-	struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd];
-	if (!state->platform.risc.fw_is_running)
-		return -EIO;
-
-	if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) {
-		dprintk("could not get the lock");
-		return -EINTR;
-	}
-	dib9000_risc_mem_setup(state, cmd);
-	dib9000_risc_mem_write_chunks(state, b, m->size);
-	mutex_unlock(&state->platform.risc.mem_lock);
-	return 0;
-}
-
-static int dib9000_firmware_download(struct dib9000_state *state, u8 risc_id, u16 key, const u8 * code, u32 len)
-{
-	u16 offs;
-
-	if (risc_id == 1)
-		offs = 16;
-	else
-		offs = 0;
-
-	/* config crtl reg */
-	dib9000_write_word(state, 1024 + offs, 0x000f);
-	dib9000_write_word(state, 1025 + offs, 0);
-	dib9000_write_word(state, 1031 + offs, key);
-
-	dprintk("going to download %dB of microcode", len);
-	if (dib9000_write16_noinc(state, 1026 + offs, (u8 *) code, (u16) len) != 0) {
-		dprintk("error while downloading microcode for RISC %c", 'A' + risc_id);
-		return -EIO;
-	}
-
-	dprintk("Microcode for RISC %c loaded", 'A' + risc_id);
-
-	return 0;
-}
-
-static int dib9000_mbx_host_init(struct dib9000_state *state, u8 risc_id)
-{
-	u16 mbox_offs;
-	u16 reset_reg;
-	u16 tries = 1000;
-
-	if (risc_id == 1)
-		mbox_offs = 16;
-	else
-		mbox_offs = 0;
-
-	/* Reset mailbox  */
-	dib9000_write_word(state, 1027 + mbox_offs, 0x8000);
-
-	/* Read reset status */
-	do {
-		reset_reg = dib9000_read_word(state, 1027 + mbox_offs);
-		msleep(100);
-	} while ((reset_reg & 0x8000) && --tries);
-
-	if (reset_reg & 0x8000) {
-		dprintk("MBX: init ERROR, no response from RISC %c", 'A' + risc_id);
-		return -EIO;
-	}
-	dprintk("MBX: initialized");
-	return 0;
-}
-
-#define MAX_MAILBOX_TRY 100
-static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, u8 len, u16 attr)
-{
-	u8 *d, b[2];
-	u16 tmp;
-	u16 size;
-	u32 i;
-	int ret = 0;
-
-	if (!state->platform.risc.fw_is_running)
-		return -EINVAL;
-
-	if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) {
-		dprintk("could not get the lock");
-		return -EINTR;
-	}
-	tmp = MAX_MAILBOX_TRY;
-	do {
-		size = dib9000_read_word_attr(state, 1043, attr) & 0xff;
-		if ((size + len + 1) > MBX_MAX_WORDS && --tmp) {
-			dprintk("MBX: RISC mbx full, retrying");
-			msleep(100);
-		} else
-			break;
-	} while (1);
-
-	/*dprintk( "MBX: size: %d", size); */
-
-	if (tmp == 0) {
-		ret = -EINVAL;
-		goto out;
-	}
-#ifdef DUMP_MSG
-	dprintk("--> %02x %d ", id, len + 1);
-	for (i = 0; i < len; i++)
-		dprintk("%04x ", data[i]);
-	dprintk("\n");
-#endif
-
-	/* byte-order conversion - works on big (where it is not necessary) or little endian */
-	d = (u8 *) data;
-	for (i = 0; i < len; i++) {
-		tmp = data[i];
-		*d++ = tmp >> 8;
-		*d++ = tmp & 0xff;
-	}
-
-	/* write msg */
-	b[0] = id;
-	b[1] = len + 1;
-	if (dib9000_write16_noinc_attr(state, 1045, b, 2, attr) != 0 || dib9000_write16_noinc_attr(state, 1045, (u8 *) data, len * 2, attr) != 0) {
-		ret = -EIO;
-		goto out;
-	}
-
-	/* update register nb_mes_in_RX */
-	ret = (u8) dib9000_write_word_attr(state, 1043, 1 << 14, attr);
-
-out:
-	mutex_unlock(&state->platform.risc.mbx_if_lock);
-
-	return ret;
-}
-
-static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id, u16 attr)
-{
-#ifdef DUMP_MSG
-	u16 *d = data;
-#endif
-
-	u16 tmp, i;
-	u8 size;
-	u8 mc_base;
-
-	if (!state->platform.risc.fw_is_running)
-		return 0;
-
-	if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) {
-		dprintk("could not get the lock");
-		return 0;
-	}
-	if (risc_id == 1)
-		mc_base = 16;
-	else
-		mc_base = 0;
-
-	/* Length and type in the first word */
-	*data = dib9000_read_word_attr(state, 1029 + mc_base, attr);
-
-	size = *data & 0xff;
-	if (size <= MBX_MAX_WORDS) {
-		data++;
-		size--;		/* Initial word already read */
-
-		dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, size * 2, attr);
-
-		/* to word conversion */
-		for (i = 0; i < size; i++) {
-			tmp = *data;
-			*data = (tmp >> 8) | (tmp << 8);
-			data++;
-		}
-
-#ifdef DUMP_MSG
-		dprintk("<-- ");
-		for (i = 0; i < size + 1; i++)
-			dprintk("%04x ", d[i]);
-		dprintk("\n");
-#endif
-	} else {
-		dprintk("MBX: message is too big for message cache (%d), flushing message", size);
-		size--;		/* Initial word already read */
-		while (size--)
-			dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, 2, attr);
-	}
-	/* Update register nb_mes_in_TX */
-	dib9000_write_word_attr(state, 1028 + mc_base, 1 << 14, attr);
-
-	mutex_unlock(&state->platform.risc.mbx_if_lock);
-
-	return size + 1;
-}
-
-static int dib9000_risc_debug_buf(struct dib9000_state *state, u16 * data, u8 size)
-{
-	u32 ts = data[1] << 16 | data[0];
-	char *b = (char *)&data[2];
-
-	b[2 * (size - 2) - 1] = '\0';	/* Bullet proof the buffer */
-	if (*b == '~') {
-		b++;
-		dprintk(b);
-	} else
-		dprintk("RISC%d: %d.%04d %s", state->fe_id, ts / 10000, ts % 10000, *b ? b : "<emtpy>");
-	return 1;
-}
-
-static int dib9000_mbx_fetch_to_cache(struct dib9000_state *state, u16 attr)
-{
-	int i;
-	u8 size;
-	u16 *block;
-	/* find a free slot */
-	for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) {
-		block = state->platform.risc.message_cache[i];
-		if (*block == 0) {
-			size = dib9000_mbx_read(state, block, 1, attr);
-
-/*                      dprintk( "MBX: fetched %04x message to cache", *block); */
-
-			switch (*block >> 8) {
-			case IN_MSG_DEBUG_BUF:
-				dib9000_risc_debug_buf(state, block + 1, size);	/* debug-messages are going to be printed right away */
-				*block = 0;	/* free the block */
-				break;
-#if 0
-			case IN_MSG_DATA:	/* FE-TRACE */
-				dib9000_risc_data_process(state, block + 1, size);
-				*block = 0;
-				break;
-#endif
-			default:
-				break;
-			}
-
-			return 1;
-		}
-	}
-	dprintk("MBX: no free cache-slot found for new message...");
-	return -1;
-}
-
-static u8 dib9000_mbx_count(struct dib9000_state *state, u8 risc_id, u16 attr)
-{
-	if (risc_id == 0)
-		return (u8) (dib9000_read_word_attr(state, 1028, attr) >> 10) & 0x1f;	/* 5 bit field */
-	else
-		return (u8) (dib9000_read_word_attr(state, 1044, attr) >> 8) & 0x7f;	/* 7 bit field */
-}
-
-static int dib9000_mbx_process(struct dib9000_state *state, u16 attr)
-{
-	int ret = 0;
-
-	if (!state->platform.risc.fw_is_running)
-		return -1;
-
-	if (mutex_lock_interruptible(&state->platform.risc.mbx_lock) < 0) {
-		dprintk("could not get the lock");
-		return -1;
-	}
-
-	if (dib9000_mbx_count(state, 1, attr))	/* 1=RiscB */
-		ret = dib9000_mbx_fetch_to_cache(state, attr);
-
-	dib9000_read_word_attr(state, 1229, attr);	/* Clear the IRQ */
-/*      if (tmp) */
-/*              dprintk( "cleared IRQ: %x", tmp); */
-	mutex_unlock(&state->platform.risc.mbx_lock);
-
-	return ret;
-}
-
-static int dib9000_mbx_get_message_attr(struct dib9000_state *state, u16 id, u16 * msg, u8 * size, u16 attr)
-{
-	u8 i;
-	u16 *block;
-	u16 timeout = 30;
-
-	*msg = 0;
-	do {
-		/* dib9000_mbx_get_from_cache(); */
-		for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) {
-			block = state->platform.risc.message_cache[i];
-			if ((*block >> 8) == id) {
-				*size = (*block & 0xff) - 1;
-				memcpy(msg, block + 1, (*size) * 2);
-				*block = 0;	/* free the block */
-				i = 0;	/* signal that we found a message */
-				break;
-			}
-		}
-
-		if (i == 0)
-			break;
-
-		if (dib9000_mbx_process(state, attr) == -1)	/* try to fetch one message - if any */
-			return -1;
-
-	} while (--timeout);
-
-	if (timeout == 0) {
-		dprintk("waiting for message %d timed out", id);
-		return -1;
-	}
-
-	return i == 0;
-}
-
-static int dib9000_risc_check_version(struct dib9000_state *state)
-{
-	u8 r[4];
-	u8 size;
-	u16 fw_version = 0;
-
-	if (dib9000_mbx_send(state, OUT_MSG_REQ_VERSION, &fw_version, 1) != 0)
-		return -EIO;
-
-	if (dib9000_mbx_get_message(state, IN_MSG_VERSION, (u16 *) r, &size) < 0)
-		return -EIO;
-
-	fw_version = (r[0] << 8) | r[1];
-	dprintk("RISC: ver: %d.%02d (IC: %d)", fw_version >> 10, fw_version & 0x3ff, (r[2] << 8) | r[3]);
-
-	if ((fw_version >> 10) != 7)
-		return -EINVAL;
-
-	switch (fw_version & 0x3ff) {
-	case 11:
-	case 12:
-	case 14:
-	case 15:
-	case 16:
-	case 17:
-		break;
-	default:
-		dprintk("RISC: invalid firmware version");
-		return -EINVAL;
-	}
-
-	dprintk("RISC: valid firmware version");
-	return 0;
-}
-
-static int dib9000_fw_boot(struct dib9000_state *state, const u8 * codeA, u32 lenA, const u8 * codeB, u32 lenB)
-{
-	/* Reconfig pool mac ram */
-	dib9000_write_word(state, 1225, 0x02);	/* A: 8k C, 4 k D - B: 32k C 6 k D - IRAM 96k */
-	dib9000_write_word(state, 1226, 0x05);
-
-	/* Toggles IP crypto to Host APB interface. */
-	dib9000_write_word(state, 1542, 1);
-
-	/* Set jump and no jump in the dma box */
-	dib9000_write_word(state, 1074, 0);
-	dib9000_write_word(state, 1075, 0);
-
-	/* Set MAC as APB Master. */
-	dib9000_write_word(state, 1237, 0);
-
-	/* Reset the RISCs */
-	if (codeA != NULL)
-		dib9000_write_word(state, 1024, 2);
-	else
-		dib9000_write_word(state, 1024, 15);
-	if (codeB != NULL)
-		dib9000_write_word(state, 1040, 2);
-
-	if (codeA != NULL)
-		dib9000_firmware_download(state, 0, 0x1234, codeA, lenA);
-	if (codeB != NULL)
-		dib9000_firmware_download(state, 1, 0x1234, codeB, lenB);
-
-	/* Run the RISCs */
-	if (codeA != NULL)
-		dib9000_write_word(state, 1024, 0);
-	if (codeB != NULL)
-		dib9000_write_word(state, 1040, 0);
-
-	if (codeA != NULL)
-		if (dib9000_mbx_host_init(state, 0) != 0)
-			return -EIO;
-	if (codeB != NULL)
-		if (dib9000_mbx_host_init(state, 1) != 0)
-			return -EIO;
-
-	msleep(100);
-	state->platform.risc.fw_is_running = 1;
-
-	if (dib9000_risc_check_version(state) != 0)
-		return -EINVAL;
-
-	state->platform.risc.memcmd = 0xff;
-	return 0;
-}
-
-static u16 dib9000_identify(struct i2c_device *client)
-{
-	u16 value;
-
-	value = dib9000_i2c_read16(client, 896);
-	if (value != 0x01b3) {
-		dprintk("wrong Vendor ID (0x%x)", value);
-		return 0;
-	}
-
-	value = dib9000_i2c_read16(client, 897);
-	if (value != 0x4000 && value != 0x4001 && value != 0x4002 && value != 0x4003 && value != 0x4004 && value != 0x4005) {
-		dprintk("wrong Device ID (0x%x)", value);
-		return 0;
-	}
-
-	/* protect this driver to be used with 7000PC */
-	if (value == 0x4000 && dib9000_i2c_read16(client, 769) == 0x4000) {
-		dprintk("this driver does not work with DiB7000PC");
-		return 0;
-	}
-
-	switch (value) {
-	case 0x4000:
-		dprintk("found DiB7000MA/PA/MB/PB");
-		break;
-	case 0x4001:
-		dprintk("found DiB7000HC");
-		break;
-	case 0x4002:
-		dprintk("found DiB7000MC");
-		break;
-	case 0x4003:
-		dprintk("found DiB9000A");
-		break;
-	case 0x4004:
-		dprintk("found DiB9000H");
-		break;
-	case 0x4005:
-		dprintk("found DiB9000M");
-		break;
-	}
-
-	return value;
-}
-
-static void dib9000_set_power_mode(struct dib9000_state *state, enum dib9000_power_mode mode)
-{
-	/* by default everything is going to be powered off */
-	u16 reg_903 = 0x3fff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906;
-	u8 offset;
-
-	if (state->revision == 0x4003 || state->revision == 0x4004 || state->revision == 0x4005)
-		offset = 1;
-	else
-		offset = 0;
-
-	reg_906 = dib9000_read_word(state, 906 + offset) | 0x3;	/* keep settings for RISC */
-
-	/* now, depending on the requested mode, we power on */
-	switch (mode) {
-		/* power up everything in the demod */
-	case DIB9000_POWER_ALL:
-		reg_903 = 0x0000;
-		reg_904 = 0x0000;
-		reg_905 = 0x0000;
-		reg_906 = 0x0000;
-		break;
-
-		/* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */
-	case DIB9000_POWER_INTERFACE_ONLY:	/* TODO power up either SDIO or I2C or SRAM */
-		reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2));
-		break;
-
-	case DIB9000_POWER_INTERF_ANALOG_AGC:
-		reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10));
-		reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2));
-		reg_906 &= ~((1 << 0));
-		break;
-
-	case DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD:
-		reg_903 = 0x0000;
-		reg_904 = 0x801f;
-		reg_905 = 0x0000;
-		reg_906 &= ~((1 << 0));
-		break;
-
-	case DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD:
-		reg_903 = 0x0000;
-		reg_904 = 0x8000;
-		reg_905 = 0x010b;
-		reg_906 &= ~((1 << 0));
-		break;
-	default:
-	case DIB9000_POWER_NO:
-		break;
-	}
-
-	/* always power down unused parts */
-	if (!state->platform.host.mobile_mode)
-		reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1);
-
-	/* P_sdio_select_clk = 0 on MC and after */
-	if (state->revision != 0x4000)
-		reg_906 <<= 1;
-
-	dib9000_write_word(state, 903 + offset, reg_903);
-	dib9000_write_word(state, 904 + offset, reg_904);
-	dib9000_write_word(state, 905 + offset, reg_905);
-	dib9000_write_word(state, 906 + offset, reg_906);
-}
-
-static int dib9000_fw_reset(struct dvb_frontend *fe)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-
-	dib9000_write_word(state, 1817, 0x0003);
-
-	dib9000_write_word(state, 1227, 1);
-	dib9000_write_word(state, 1227, 0);
-
-	switch ((state->revision = dib9000_identify(&state->i2c))) {
-	case 0x4003:
-	case 0x4004:
-	case 0x4005:
-		state->reg_offs = 1;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* reset the i2c-master to use the host interface */
-	dibx000_reset_i2c_master(&state->i2c_master);
-
-	dib9000_set_power_mode(state, DIB9000_POWER_ALL);
-
-	/* unforce divstr regardless whether i2c enumeration was done or not */
-	dib9000_write_word(state, 1794, dib9000_read_word(state, 1794) & ~(1 << 1));
-	dib9000_write_word(state, 1796, 0);
-	dib9000_write_word(state, 1805, 0x805);
-
-	/* restart all parts */
-	dib9000_write_word(state, 898, 0xffff);
-	dib9000_write_word(state, 899, 0xffff);
-	dib9000_write_word(state, 900, 0x0001);
-	dib9000_write_word(state, 901, 0xff19);
-	dib9000_write_word(state, 902, 0x003c);
-
-	dib9000_write_word(state, 898, 0);
-	dib9000_write_word(state, 899, 0);
-	dib9000_write_word(state, 900, 0);
-	dib9000_write_word(state, 901, 0);
-	dib9000_write_word(state, 902, 0);
-
-	dib9000_write_word(state, 911, state->chip.d9.cfg.if_drives);
-
-	dib9000_set_power_mode(state, DIB9000_POWER_INTERFACE_ONLY);
-
-	return 0;
-}
-
-static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len)
-{
-	u16 mb[10];
-	u8 i, s;
-
-	if (address >= 1024 || !state->platform.risc.fw_is_running)
-		return -EINVAL;
-
-	/* dprintk( "APB access thru rd fw %d %x", address, attribute); */
-
-	mb[0] = (u16) address;
-	mb[1] = len / 2;
-	dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_R, mb, 2, attribute);
-	switch (dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute)) {
-	case 1:
-		s--;
-		for (i = 0; i < s; i++) {
-			b[i * 2] = (mb[i + 1] >> 8) & 0xff;
-			b[i * 2 + 1] = (mb[i + 1]) & 0xff;
-		}
-		return 0;
-	default:
-		return -EIO;
-	}
-	return -EIO;
-}
-
-static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len)
-{
-	u16 mb[10];
-	u8 s, i;
-
-	if (address >= 1024 || !state->platform.risc.fw_is_running)
-		return -EINVAL;
-
-	/* dprintk( "APB access thru wr fw %d %x", address, attribute); */
-
-	mb[0] = (unsigned short)address;
-	for (i = 0; i < len && i < 20; i += 2)
-		mb[1 + (i / 2)] = (b[i] << 8 | b[i + 1]);
-
-	dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_W, mb, 1 + len / 2, attribute);
-	return dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute) == 1 ? 0 : -EINVAL;
-}
-
-static int dib9000_fw_memmbx_sync(struct dib9000_state *state, u8 i)
-{
-	u8 index_loop = 10;
-
-	if (!state->platform.risc.fw_is_running)
-		return 0;
-	dib9000_risc_mem_write(state, FE_MM_RW_SYNC, &i);
-	do {
-		dib9000_risc_mem_read(state, FE_MM_RW_SYNC, state->i2c_read_buffer, 1);
-	} while (state->i2c_read_buffer[0] && index_loop--);
-
-	if (index_loop > 0)
-		return 0;
-	return -EIO;
-}
-
-static int dib9000_fw_init(struct dib9000_state *state)
-{
-	struct dibGPIOFunction *f;
-	u16 b[40] = { 0 };
-	u8 i;
-	u8 size;
-
-	if (dib9000_fw_boot(state, NULL, 0, state->chip.d9.cfg.microcode_B_fe_buffer, state->chip.d9.cfg.microcode_B_fe_size) != 0)
-		return -EIO;
-
-	/* initialize the firmware */
-	for (i = 0; i < ARRAY_SIZE(state->chip.d9.cfg.gpio_function); i++) {
-		f = &state->chip.d9.cfg.gpio_function[i];
-		if (f->mask) {
-			switch (f->function) {
-			case BOARD_GPIO_FUNCTION_COMPONENT_ON:
-				b[0] = (u16) f->mask;
-				b[1] = (u16) f->direction;
-				b[2] = (u16) f->value;
-				break;
-			case BOARD_GPIO_FUNCTION_COMPONENT_OFF:
-				b[3] = (u16) f->mask;
-				b[4] = (u16) f->direction;
-				b[5] = (u16) f->value;
-				break;
-			}
-		}
-	}
-	if (dib9000_mbx_send(state, OUT_MSG_CONF_GPIO, b, 15) != 0)
-		return -EIO;
-
-	/* subband */
-	b[0] = state->chip.d9.cfg.subband.size;	/* type == 0 -> GPIO - PWM not yet supported */
-	for (i = 0; i < state->chip.d9.cfg.subband.size; i++) {
-		b[1 + i * 4] = state->chip.d9.cfg.subband.subband[i].f_mhz;
-		b[2 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.mask;
-		b[3 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.direction;
-		b[4 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.value;
-	}
-	b[1 + i * 4] = 0;	/* fe_id */
-	if (dib9000_mbx_send(state, OUT_MSG_SUBBAND_SEL, b, 2 + 4 * i) != 0)
-		return -EIO;
-
-	/* 0 - id, 1 - no_of_frontends */
-	b[0] = (0 << 8) | 1;
-	/* 0 = i2c-address demod, 0 = tuner */
-	b[1] = (0 << 8) | (0);
-	b[2] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000) >> 16) & 0xffff);
-	b[3] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000)) & 0xffff);
-	b[4] = (u16) ((state->chip.d9.cfg.vcxo_timer >> 16) & 0xffff);
-	b[5] = (u16) ((state->chip.d9.cfg.vcxo_timer) & 0xffff);
-	b[6] = (u16) ((state->chip.d9.cfg.timing_frequency >> 16) & 0xffff);
-	b[7] = (u16) ((state->chip.d9.cfg.timing_frequency) & 0xffff);
-	b[29] = state->chip.d9.cfg.if_drives;
-	if (dib9000_mbx_send(state, OUT_MSG_INIT_DEMOD, b, ARRAY_SIZE(b)) != 0)
-		return -EIO;
-
-	if (dib9000_mbx_send(state, OUT_MSG_FE_FW_DL, NULL, 0) != 0)
-		return -EIO;
-
-	if (dib9000_mbx_get_message(state, IN_MSG_FE_FW_DL_DONE, b, &size) < 0)
-		return -EIO;
-
-	if (size > ARRAY_SIZE(b)) {
-		dprintk("error : firmware returned %dbytes needed but the used buffer has only %dbytes\n Firmware init ABORTED", size,
-			(int)ARRAY_SIZE(b));
-		return -EINVAL;
-	}
-
-	for (i = 0; i < size; i += 2) {
-		state->platform.risc.fe_mm[i / 2].addr = b[i + 0];
-		state->platform.risc.fe_mm[i / 2].size = b[i + 1];
-	}
-
-	return 0;
-}
-
-static void dib9000_fw_set_channel_head(struct dib9000_state *state)
-{
-	u8 b[9];
-	u32 freq = state->fe[0]->dtv_property_cache.frequency / 1000;
-	if (state->fe_id % 2)
-		freq += 101;
-
-	b[0] = (u8) ((freq >> 0) & 0xff);
-	b[1] = (u8) ((freq >> 8) & 0xff);
-	b[2] = (u8) ((freq >> 16) & 0xff);
-	b[3] = (u8) ((freq >> 24) & 0xff);
-	b[4] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 0) & 0xff);
-	b[5] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 8) & 0xff);
-	b[6] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 16) & 0xff);
-	b[7] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 24) & 0xff);
-	b[8] = 0x80;		/* do not wait for CELL ID when doing autosearch */
-	if (state->fe[0]->dtv_property_cache.delivery_system == SYS_DVBT)
-		b[8] |= 1;
-	dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_HEAD, b);
-}
-
-static int dib9000_fw_get_channel(struct dvb_frontend *fe)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	struct dibDVBTChannel {
-		s8 spectrum_inversion;
-
-		s8 nfft;
-		s8 guard;
-		s8 constellation;
-
-		s8 hrch;
-		s8 alpha;
-		s8 code_rate_hp;
-		s8 code_rate_lp;
-		s8 select_hp;
-
-		s8 intlv_native;
-	};
-	struct dibDVBTChannel *ch;
-	int ret = 0;
-
-	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
-		dprintk("could not get the lock");
-		return -EINTR;
-	}
-	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
-		ret = -EIO;
-		goto error;
-	}
-
-	dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION,
-			state->i2c_read_buffer, sizeof(struct dibDVBTChannel));
-	ch = (struct dibDVBTChannel *)state->i2c_read_buffer;
-
-
-	switch (ch->spectrum_inversion & 0x7) {
-	case 1:
-		state->fe[0]->dtv_property_cache.inversion = INVERSION_ON;
-		break;
-	case 0:
-		state->fe[0]->dtv_property_cache.inversion = INVERSION_OFF;
-		break;
-	default:
-	case -1:
-		state->fe[0]->dtv_property_cache.inversion = INVERSION_AUTO;
-		break;
-	}
-	switch (ch->nfft) {
-	case 0:
-		state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
-		break;
-	case 2:
-		state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_4K;
-		break;
-	case 1:
-		state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
-		break;
-	default:
-	case -1:
-		state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
-		break;
-	}
-	switch (ch->guard) {
-	case 0:
-		state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
-		break;
-	case 1:
-		state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
-		break;
-	case 2:
-		state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
-		break;
-	case 3:
-		state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
-		break;
-	default:
-	case -1:
-		state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
-		break;
-	}
-	switch (ch->constellation) {
-	case 2:
-		state->fe[0]->dtv_property_cache.modulation = QAM_64;
-		break;
-	case 1:
-		state->fe[0]->dtv_property_cache.modulation = QAM_16;
-		break;
-	case 0:
-		state->fe[0]->dtv_property_cache.modulation = QPSK;
-		break;
-	default:
-	case -1:
-		state->fe[0]->dtv_property_cache.modulation = QAM_AUTO;
-		break;
-	}
-	switch (ch->hrch) {
-	case 0:
-		state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_NONE;
-		break;
-	case 1:
-		state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_1;
-		break;
-	default:
-	case -1:
-		state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_AUTO;
-		break;
-	}
-	switch (ch->code_rate_hp) {
-	case 1:
-		state->fe[0]->dtv_property_cache.code_rate_HP = FEC_1_2;
-		break;
-	case 2:
-		state->fe[0]->dtv_property_cache.code_rate_HP = FEC_2_3;
-		break;
-	case 3:
-		state->fe[0]->dtv_property_cache.code_rate_HP = FEC_3_4;
-		break;
-	case 5:
-		state->fe[0]->dtv_property_cache.code_rate_HP = FEC_5_6;
-		break;
-	case 7:
-		state->fe[0]->dtv_property_cache.code_rate_HP = FEC_7_8;
-		break;
-	default:
-	case -1:
-		state->fe[0]->dtv_property_cache.code_rate_HP = FEC_AUTO;
-		break;
-	}
-	switch (ch->code_rate_lp) {
-	case 1:
-		state->fe[0]->dtv_property_cache.code_rate_LP = FEC_1_2;
-		break;
-	case 2:
-		state->fe[0]->dtv_property_cache.code_rate_LP = FEC_2_3;
-		break;
-	case 3:
-		state->fe[0]->dtv_property_cache.code_rate_LP = FEC_3_4;
-		break;
-	case 5:
-		state->fe[0]->dtv_property_cache.code_rate_LP = FEC_5_6;
-		break;
-	case 7:
-		state->fe[0]->dtv_property_cache.code_rate_LP = FEC_7_8;
-		break;
-	default:
-	case -1:
-		state->fe[0]->dtv_property_cache.code_rate_LP = FEC_AUTO;
-		break;
-	}
-
-error:
-	mutex_unlock(&state->platform.risc.mem_mbx_lock);
-	return ret;
-}
-
-static int dib9000_fw_set_channel_union(struct dvb_frontend *fe)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	struct dibDVBTChannel {
-		s8 spectrum_inversion;
-
-		s8 nfft;
-		s8 guard;
-		s8 constellation;
-
-		s8 hrch;
-		s8 alpha;
-		s8 code_rate_hp;
-		s8 code_rate_lp;
-		s8 select_hp;
-
-		s8 intlv_native;
-	};
-	struct dibDVBTChannel ch;
-
-	switch (state->fe[0]->dtv_property_cache.inversion) {
-	case INVERSION_ON:
-		ch.spectrum_inversion = 1;
-		break;
-	case INVERSION_OFF:
-		ch.spectrum_inversion = 0;
-		break;
-	default:
-	case INVERSION_AUTO:
-		ch.spectrum_inversion = -1;
-		break;
-	}
-	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
-	case TRANSMISSION_MODE_2K:
-		ch.nfft = 0;
-		break;
-	case TRANSMISSION_MODE_4K:
-		ch.nfft = 2;
-		break;
-	case TRANSMISSION_MODE_8K:
-		ch.nfft = 1;
-		break;
-	default:
-	case TRANSMISSION_MODE_AUTO:
-		ch.nfft = 1;
-		break;
-	}
-	switch (state->fe[0]->dtv_property_cache.guard_interval) {
-	case GUARD_INTERVAL_1_32:
-		ch.guard = 0;
-		break;
-	case GUARD_INTERVAL_1_16:
-		ch.guard = 1;
-		break;
-	case GUARD_INTERVAL_1_8:
-		ch.guard = 2;
-		break;
-	case GUARD_INTERVAL_1_4:
-		ch.guard = 3;
-		break;
-	default:
-	case GUARD_INTERVAL_AUTO:
-		ch.guard = -1;
-		break;
-	}
-	switch (state->fe[0]->dtv_property_cache.modulation) {
-	case QAM_64:
-		ch.constellation = 2;
-		break;
-	case QAM_16:
-		ch.constellation = 1;
-		break;
-	case QPSK:
-		ch.constellation = 0;
-		break;
-	default:
-	case QAM_AUTO:
-		ch.constellation = -1;
-		break;
-	}
-	switch (state->fe[0]->dtv_property_cache.hierarchy) {
-	case HIERARCHY_NONE:
-		ch.hrch = 0;
-		break;
-	case HIERARCHY_1:
-	case HIERARCHY_2:
-	case HIERARCHY_4:
-		ch.hrch = 1;
-		break;
-	default:
-	case HIERARCHY_AUTO:
-		ch.hrch = -1;
-		break;
-	}
-	ch.alpha = 1;
-	switch (state->fe[0]->dtv_property_cache.code_rate_HP) {
-	case FEC_1_2:
-		ch.code_rate_hp = 1;
-		break;
-	case FEC_2_3:
-		ch.code_rate_hp = 2;
-		break;
-	case FEC_3_4:
-		ch.code_rate_hp = 3;
-		break;
-	case FEC_5_6:
-		ch.code_rate_hp = 5;
-		break;
-	case FEC_7_8:
-		ch.code_rate_hp = 7;
-		break;
-	default:
-	case FEC_AUTO:
-		ch.code_rate_hp = -1;
-		break;
-	}
-	switch (state->fe[0]->dtv_property_cache.code_rate_LP) {
-	case FEC_1_2:
-		ch.code_rate_lp = 1;
-		break;
-	case FEC_2_3:
-		ch.code_rate_lp = 2;
-		break;
-	case FEC_3_4:
-		ch.code_rate_lp = 3;
-		break;
-	case FEC_5_6:
-		ch.code_rate_lp = 5;
-		break;
-	case FEC_7_8:
-		ch.code_rate_lp = 7;
-		break;
-	default:
-	case FEC_AUTO:
-		ch.code_rate_lp = -1;
-		break;
-	}
-	ch.select_hp = 1;
-	ch.intlv_native = 1;
-
-	dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_UNION, (u8 *) &ch);
-
-	return 0;
-}
-
-static int dib9000_fw_tune(struct dvb_frontend *fe)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	int ret = 10, search = state->channel_status.status == CHANNEL_STATUS_PARAMETERS_UNKNOWN;
-	s8 i;
-
-	switch (state->tune_state) {
-	case CT_DEMOD_START:
-		dib9000_fw_set_channel_head(state);
-
-		/* write the channel context - a channel is initialized to 0, so it is OK */
-		dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_CONTEXT, (u8 *) fe_info);
-		dib9000_risc_mem_write(state, FE_MM_W_FE_INFO, (u8 *) fe_info);
-
-		if (search)
-			dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_SEARCH, NULL, 0);
-		else {
-			dib9000_fw_set_channel_union(fe);
-			dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_TUNE, NULL, 0);
-		}
-		state->tune_state = CT_DEMOD_STEP_1;
-		break;
-	case CT_DEMOD_STEP_1:
-		if (search)
-			dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, state->i2c_read_buffer, 1);
-		else
-			dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, state->i2c_read_buffer, 1);
-		i = (s8)state->i2c_read_buffer[0];
-		switch (i) {	/* something happened */
-		case 0:
-			break;
-		case -2:	/* tps locks are "slower" than MPEG locks -> even in autosearch data is OK here */
-			if (search)
-				state->status = FE_STATUS_DEMOD_SUCCESS;
-			else {
-				state->tune_state = CT_DEMOD_STOP;
-				state->status = FE_STATUS_LOCKED;
-			}
-			break;
-		default:
-			state->status = FE_STATUS_TUNE_FAILED;
-			state->tune_state = CT_DEMOD_STOP;
-			break;
-		}
-		break;
-	default:
-		ret = FE_CALLBACK_TIME_NEVER;
-		break;
-	}
-
-	return ret;
-}
-
-static int dib9000_fw_set_diversity_in(struct dvb_frontend *fe, int onoff)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	u16 mode = (u16) onoff;
-	return dib9000_mbx_send(state, OUT_MSG_ENABLE_DIVERSITY, &mode, 1);
-}
-
-static int dib9000_fw_set_output_mode(struct dvb_frontend *fe, int mode)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	u16 outreg, smo_mode;
-
-	dprintk("setting output mode for demod %p to %d", fe, mode);
-
-	switch (mode) {
-	case OUTMODE_MPEG2_PAR_GATED_CLK:
-		outreg = (1 << 10);	/* 0x0400 */
-		break;
-	case OUTMODE_MPEG2_PAR_CONT_CLK:
-		outreg = (1 << 10) | (1 << 6);	/* 0x0440 */
-		break;
-	case OUTMODE_MPEG2_SERIAL:
-		outreg = (1 << 10) | (2 << 6) | (0 << 1);	/* 0x0482 */
-		break;
-	case OUTMODE_DIVERSITY:
-		outreg = (1 << 10) | (4 << 6);	/* 0x0500 */
-		break;
-	case OUTMODE_MPEG2_FIFO:
-		outreg = (1 << 10) | (5 << 6);
-		break;
-	case OUTMODE_HIGH_Z:
-		outreg = 0;
-		break;
-	default:
-		dprintk("Unhandled output_mode passed to be set for demod %p", &state->fe[0]);
-		return -EINVAL;
-	}
-
-	dib9000_write_word(state, 1795, outreg);
-
-	switch (mode) {
-	case OUTMODE_MPEG2_PAR_GATED_CLK:
-	case OUTMODE_MPEG2_PAR_CONT_CLK:
-	case OUTMODE_MPEG2_SERIAL:
-	case OUTMODE_MPEG2_FIFO:
-		smo_mode = (dib9000_read_word(state, 295) & 0x0010) | (1 << 1);
-		if (state->chip.d9.cfg.output_mpeg2_in_188_bytes)
-			smo_mode |= (1 << 5);
-		dib9000_write_word(state, 295, smo_mode);
-		break;
-	}
-
-	outreg = to_fw_output_mode(mode);
-	return dib9000_mbx_send(state, OUT_MSG_SET_OUTPUT_MODE, &outreg, 1);
-}
-
-static int dib9000_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
-{
-	struct dib9000_state *state = i2c_get_adapdata(i2c_adap);
-	u16 i, len, t, index_msg;
-
-	for (index_msg = 0; index_msg < num; index_msg++) {
-		if (msg[index_msg].flags & I2C_M_RD) {	/* read */
-			len = msg[index_msg].len;
-			if (len > 16)
-				len = 16;
-
-			if (dib9000_read_word(state, 790) != 0)
-				dprintk("TunerITF: read busy");
-
-			dib9000_write_word(state, 784, (u16) (msg[index_msg].addr));
-			dib9000_write_word(state, 787, (len / 2) - 1);
-			dib9000_write_word(state, 786, 1);	/* start read */
-
-			i = 1000;
-			while (dib9000_read_word(state, 790) != (len / 2) && i)
-				i--;
-
-			if (i == 0)
-				dprintk("TunerITF: read failed");
-
-			for (i = 0; i < len; i += 2) {
-				t = dib9000_read_word(state, 785);
-				msg[index_msg].buf[i] = (t >> 8) & 0xff;
-				msg[index_msg].buf[i + 1] = (t) & 0xff;
-			}
-			if (dib9000_read_word(state, 790) != 0)
-				dprintk("TunerITF: read more data than expected");
-		} else {
-			i = 1000;
-			while (dib9000_read_word(state, 789) && i)
-				i--;
-			if (i == 0)
-				dprintk("TunerITF: write busy");
-
-			len = msg[index_msg].len;
-			if (len > 16)
-				len = 16;
-
-			for (i = 0; i < len; i += 2)
-				dib9000_write_word(state, 785, (msg[index_msg].buf[i] << 8) | msg[index_msg].buf[i + 1]);
-			dib9000_write_word(state, 784, (u16) msg[index_msg].addr);
-			dib9000_write_word(state, 787, (len / 2) - 1);
-			dib9000_write_word(state, 786, 0);	/* start write */
-
-			i = 1000;
-			while (dib9000_read_word(state, 791) > 0 && i)
-				i--;
-			if (i == 0)
-				dprintk("TunerITF: write failed");
-		}
-	}
-	return num;
-}
-
-int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-
-	state->component_bus_speed = speed;
-	return 0;
-}
-EXPORT_SYMBOL(dib9000_fw_set_component_bus_speed);
-
-static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
-{
-	struct dib9000_state *state = i2c_get_adapdata(i2c_adap);
-	u8 type = 0;		/* I2C */
-	u8 port = DIBX000_I2C_INTERFACE_GPIO_3_4;
-	u16 scl = state->component_bus_speed;	/* SCL frequency */
-	struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[FE_MM_RW_COMPONENT_ACCESS_BUFFER];
-	u8 p[13] = { 0 };
-
-	p[0] = type;
-	p[1] = port;
-	p[2] = msg[0].addr << 1;
-
-	p[3] = (u8) scl & 0xff;	/* scl */
-	p[4] = (u8) (scl >> 8);
-
-	p[7] = 0;
-	p[8] = 0;
-
-	p[9] = (u8) (msg[0].len);
-	p[10] = (u8) (msg[0].len >> 8);
-	if ((num > 1) && (msg[1].flags & I2C_M_RD)) {
-		p[11] = (u8) (msg[1].len);
-		p[12] = (u8) (msg[1].len >> 8);
-	} else {
-		p[11] = 0;
-		p[12] = 0;
-	}
-
-	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
-		dprintk("could not get the lock");
-		return 0;
-	}
-
-	dib9000_risc_mem_write(state, FE_MM_W_COMPONENT_ACCESS, p);
-
-	{			/* write-part */
-		dib9000_risc_mem_setup_cmd(state, m->addr, msg[0].len, 0);
-		dib9000_risc_mem_write_chunks(state, msg[0].buf, msg[0].len);
-	}
-
-	/* do the transaction */
-	if (dib9000_fw_memmbx_sync(state, FE_SYNC_COMPONENT_ACCESS) < 0) {
-		mutex_unlock(&state->platform.risc.mem_mbx_lock);
-		return 0;
-	}
-
-	/* read back any possible result */
-	if ((num > 1) && (msg[1].flags & I2C_M_RD))
-		dib9000_risc_mem_read(state, FE_MM_RW_COMPONENT_ACCESS_BUFFER, msg[1].buf, msg[1].len);
-
-	mutex_unlock(&state->platform.risc.mem_mbx_lock);
-
-	return num;
-}
-
-static u32 dib9000_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm dib9000_tuner_algo = {
-	.master_xfer = dib9000_tuner_xfer,
-	.functionality = dib9000_i2c_func,
-};
-
-static struct i2c_algorithm dib9000_component_bus_algo = {
-	.master_xfer = dib9000_fw_component_bus_xfer,
-	.functionality = dib9000_i2c_func,
-};
-
-struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe)
-{
-	struct dib9000_state *st = fe->demodulator_priv;
-	return &st->tuner_adap;
-}
-EXPORT_SYMBOL(dib9000_get_tuner_interface);
-
-struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe)
-{
-	struct dib9000_state *st = fe->demodulator_priv;
-	return &st->component_bus;
-}
-EXPORT_SYMBOL(dib9000_get_component_bus_interface);
-
-struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
-{
-	struct dib9000_state *st = fe->demodulator_priv;
-	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
-}
-EXPORT_SYMBOL(dib9000_get_i2c_master);
-
-int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c)
-{
-	struct dib9000_state *st = fe->demodulator_priv;
-
-	st->i2c.i2c_adap = i2c;
-	return 0;
-}
-EXPORT_SYMBOL(dib9000_set_i2c_adapter);
-
-static int dib9000_cfg_gpio(struct dib9000_state *st, u8 num, u8 dir, u8 val)
-{
-	st->gpio_dir = dib9000_read_word(st, 773);
-	st->gpio_dir &= ~(1 << num);	/* reset the direction bit */
-	st->gpio_dir |= (dir & 0x1) << num;	/* set the new direction */
-	dib9000_write_word(st, 773, st->gpio_dir);
-
-	st->gpio_val = dib9000_read_word(st, 774);
-	st->gpio_val &= ~(1 << num);	/* reset the direction bit */
-	st->gpio_val |= (val & 0x01) << num;	/* set the new value */
-	dib9000_write_word(st, 774, st->gpio_val);
-
-	dprintk("gpio dir: %04x: gpio val: %04x", st->gpio_dir, st->gpio_val);
-
-	return 0;
-}
-
-int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	return dib9000_cfg_gpio(state, num, dir, val);
-}
-EXPORT_SYMBOL(dib9000_set_gpio);
-
-int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	u16 val;
-	int ret;
-
-	if ((state->pid_ctrl_index != -2) && (state->pid_ctrl_index < 9)) {
-		/* postpone the pid filtering cmd */
-		dprintk("pid filter cmd postpone");
-		state->pid_ctrl_index++;
-		state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER_CTRL;
-		state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
-		return 0;
-	}
-
-	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
-		dprintk("could not get the lock");
-		return -EINTR;
-	}
-
-	val = dib9000_read_word(state, 294 + 1) & 0xffef;
-	val |= (onoff & 0x1) << 4;
-
-	dprintk("PID filter enabled %d", onoff);
-	ret = dib9000_write_word(state, 294 + 1, val);
-	mutex_unlock(&state->demod_lock);
-	return ret;
-
-}
-EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl);
-
-int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	int ret;
-
-	if (state->pid_ctrl_index != -2) {
-		/* postpone the pid filtering cmd */
-		dprintk("pid filter postpone");
-		if (state->pid_ctrl_index < 9) {
-			state->pid_ctrl_index++;
-			state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER;
-			state->pid_ctrl[state->pid_ctrl_index].id = id;
-			state->pid_ctrl[state->pid_ctrl_index].pid = pid;
-			state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
-		} else
-			dprintk("can not add any more pid ctrl cmd");
-		return 0;
-	}
-
-	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
-		dprintk("could not get the lock");
-		return -EINTR;
-	}
-	dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
-	ret = dib9000_write_word(state, 300 + 1 + id,
-			onoff ? (1 << 13) | pid : 0);
-	mutex_unlock(&state->demod_lock);
-	return ret;
-}
-EXPORT_SYMBOL(dib9000_fw_pid_filter);
-
-int dib9000_firmware_post_pll_init(struct dvb_frontend *fe)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	return dib9000_fw_init(state);
-}
-EXPORT_SYMBOL(dib9000_firmware_post_pll_init);
-
-static void dib9000_release(struct dvb_frontend *demod)
-{
-	struct dib9000_state *st = demod->demodulator_priv;
-	u8 index_frontend;
-
-	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
-		dvb_frontend_detach(st->fe[index_frontend]);
-
-	dibx000_exit_i2c_master(&st->i2c_master);
-
-	i2c_del_adapter(&st->tuner_adap);
-	i2c_del_adapter(&st->component_bus);
-	kfree(st->fe[0]);
-	kfree(st);
-}
-
-static int dib9000_wakeup(struct dvb_frontend *fe)
-{
-	return 0;
-}
-
-static int dib9000_sleep(struct dvb_frontend *fe)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	u8 index_frontend;
-	int ret = 0;
-
-	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
-		dprintk("could not get the lock");
-		return -EINTR;
-	}
-	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-		ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
-		if (ret < 0)
-			goto error;
-	}
-	ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0);
-
-error:
-	mutex_unlock(&state->demod_lock);
-	return ret;
-}
-
-static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
-{
-	tune->min_delay_ms = 1000;
-	return 0;
-}
-
-static int dib9000_get_frontend(struct dvb_frontend *fe)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	u8 index_frontend, sub_index_frontend;
-	fe_status_t stat;
-	int ret = 0;
-
-	if (state->get_frontend_internal == 0) {
-		if (mutex_lock_interruptible(&state->demod_lock) < 0) {
-			dprintk("could not get the lock");
-			return -EINTR;
-		}
-	}
-
-	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-		state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
-		if (stat & FE_HAS_SYNC) {
-			dprintk("TPS lock on the slave%i", index_frontend);
-
-			/* synchronize the cache with the other frontends */
-			state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]);
-			for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL);
-			     sub_index_frontend++) {
-				if (sub_index_frontend != index_frontend) {
-					state->fe[sub_index_frontend]->dtv_property_cache.modulation =
-					    state->fe[index_frontend]->dtv_property_cache.modulation;
-					state->fe[sub_index_frontend]->dtv_property_cache.inversion =
-					    state->fe[index_frontend]->dtv_property_cache.inversion;
-					state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode =
-					    state->fe[index_frontend]->dtv_property_cache.transmission_mode;
-					state->fe[sub_index_frontend]->dtv_property_cache.guard_interval =
-					    state->fe[index_frontend]->dtv_property_cache.guard_interval;
-					state->fe[sub_index_frontend]->dtv_property_cache.hierarchy =
-					    state->fe[index_frontend]->dtv_property_cache.hierarchy;
-					state->fe[sub_index_frontend]->dtv_property_cache.code_rate_HP =
-					    state->fe[index_frontend]->dtv_property_cache.code_rate_HP;
-					state->fe[sub_index_frontend]->dtv_property_cache.code_rate_LP =
-					    state->fe[index_frontend]->dtv_property_cache.code_rate_LP;
-					state->fe[sub_index_frontend]->dtv_property_cache.rolloff =
-					    state->fe[index_frontend]->dtv_property_cache.rolloff;
-				}
-			}
-			ret = 0;
-			goto return_value;
-		}
-	}
-
-	/* get the channel from master chip */
-	ret = dib9000_fw_get_channel(fe);
-	if (ret != 0)
-		goto return_value;
-
-	/* synchronize the cache with the other frontends */
-	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-		state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
-		state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
-		state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
-		state->fe[index_frontend]->dtv_property_cache.modulation = fe->dtv_property_cache.modulation;
-		state->fe[index_frontend]->dtv_property_cache.hierarchy = fe->dtv_property_cache.hierarchy;
-		state->fe[index_frontend]->dtv_property_cache.code_rate_HP = fe->dtv_property_cache.code_rate_HP;
-		state->fe[index_frontend]->dtv_property_cache.code_rate_LP = fe->dtv_property_cache.code_rate_LP;
-		state->fe[index_frontend]->dtv_property_cache.rolloff = fe->dtv_property_cache.rolloff;
-	}
-	ret = 0;
-
-return_value:
-	if (state->get_frontend_internal == 0)
-		mutex_unlock(&state->demod_lock);
-	return ret;
-}
-
-static int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	state->tune_state = tune_state;
-	if (tune_state == CT_DEMOD_START)
-		state->status = FE_STATUS_TUNE_PENDING;
-
-	return 0;
-}
-
-static u32 dib9000_get_status(struct dvb_frontend *fe)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	return state->status;
-}
-
-static int dib9000_set_channel_status(struct dvb_frontend *fe, struct dvb_frontend_parametersContext *channel_status)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-
-	memcpy(&state->channel_status, channel_status, sizeof(struct dvb_frontend_parametersContext));
-	return 0;
-}
-
-static int dib9000_set_frontend(struct dvb_frontend *fe)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	int sleep_time, sleep_time_slave;
-	u32 frontend_status;
-	u8 nbr_pending, exit_condition, index_frontend, index_frontend_success;
-	struct dvb_frontend_parametersContext channel_status;
-
-	/* check that the correct parameters are set */
-	if (state->fe[0]->dtv_property_cache.frequency == 0) {
-		dprintk("dib9000: must specify frequency ");
-		return 0;
-	}
-
-	if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) {
-		dprintk("dib9000: must specify bandwidth ");
-		return 0;
-	}
-
-	state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */
-	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
-		dprintk("could not get the lock");
-		return 0;
-	}
-
-	fe->dtv_property_cache.delivery_system = SYS_DVBT;
-
-	/* set the master status */
-	if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO ||
-	    state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO ||
-	    state->fe[0]->dtv_property_cache.modulation == QAM_AUTO ||
-	    state->fe[0]->dtv_property_cache.code_rate_HP == FEC_AUTO) {
-		/* no channel specified, autosearch the channel */
-		state->channel_status.status = CHANNEL_STATUS_PARAMETERS_UNKNOWN;
-	} else
-		state->channel_status.status = CHANNEL_STATUS_PARAMETERS_SET;
-
-	/* set mode and status for the different frontends */
-	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-		dib9000_fw_set_diversity_in(state->fe[index_frontend], 1);
-
-		/* synchronization of the cache */
-		memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
-
-		state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_DVBT;
-		dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z);
-
-		dib9000_set_channel_status(state->fe[index_frontend], &state->channel_status);
-		dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
-	}
-
-	/* actual tune */
-	exit_condition = 0;	/* 0: tune pending; 1: tune failed; 2:tune success */
-	index_frontend_success = 0;
-	do {
-		sleep_time = dib9000_fw_tune(state->fe[0]);
-		for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-			sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]);
-			if (sleep_time == FE_CALLBACK_TIME_NEVER)
-				sleep_time = sleep_time_slave;
-			else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time))
-				sleep_time = sleep_time_slave;
-		}
-		if (sleep_time != FE_CALLBACK_TIME_NEVER)
-			msleep(sleep_time / 10);
-		else
-			break;
-
-		nbr_pending = 0;
-		exit_condition = 0;
-		index_frontend_success = 0;
-		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-			frontend_status = -dib9000_get_status(state->fe[index_frontend]);
-			if (frontend_status > -FE_STATUS_TUNE_PENDING) {
-				exit_condition = 2;	/* tune success */
-				index_frontend_success = index_frontend;
-				break;
-			}
-			if (frontend_status == -FE_STATUS_TUNE_PENDING)
-				nbr_pending++;	/* some frontends are still tuning */
-		}
-		if ((exit_condition != 2) && (nbr_pending == 0))
-			exit_condition = 1;	/* if all tune are done and no success, exit: tune failed */
-
-	} while (exit_condition == 0);
-
-	/* check the tune result */
-	if (exit_condition == 1) {	/* tune failed */
-		dprintk("tune failed");
-		mutex_unlock(&state->demod_lock);
-		/* tune failed; put all the pid filtering cmd to junk */
-		state->pid_ctrl_index = -1;
-		return 0;
-	}
-
-	dprintk("tune success on frontend%i", index_frontend_success);
-
-	/* synchronize all the channel cache */
-	state->get_frontend_internal = 1;
-	dib9000_get_frontend(state->fe[0]);
-	state->get_frontend_internal = 0;
-
-	/* retune the other frontends with the found channel */
-	channel_status.status = CHANNEL_STATUS_PARAMETERS_SET;
-	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-		/* only retune the frontends which was not tuned success */
-		if (index_frontend != index_frontend_success) {
-			dib9000_set_channel_status(state->fe[index_frontend], &channel_status);
-			dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
-		}
-	}
-	do {
-		sleep_time = FE_CALLBACK_TIME_NEVER;
-		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-			if (index_frontend != index_frontend_success) {
-				sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]);
-				if (sleep_time == FE_CALLBACK_TIME_NEVER)
-					sleep_time = sleep_time_slave;
-				else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time))
-					sleep_time = sleep_time_slave;
-			}
-		}
-		if (sleep_time != FE_CALLBACK_TIME_NEVER)
-			msleep(sleep_time / 10);
-		else
-			break;
-
-		nbr_pending = 0;
-		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-			if (index_frontend != index_frontend_success) {
-				frontend_status = -dib9000_get_status(state->fe[index_frontend]);
-				if ((index_frontend != index_frontend_success) && (frontend_status == -FE_STATUS_TUNE_PENDING))
-					nbr_pending++;	/* some frontends are still tuning */
-			}
-		}
-	} while (nbr_pending != 0);
-
-	/* set the output mode */
-	dib9000_fw_set_output_mode(state->fe[0], state->chip.d9.cfg.output_mode);
-	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
-		dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY);
-
-	/* turn off the diversity for the last frontend */
-	dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0);
-
-	mutex_unlock(&state->demod_lock);
-	if (state->pid_ctrl_index >= 0) {
-		u8 index_pid_filter_cmd;
-		u8 pid_ctrl_index = state->pid_ctrl_index;
-
-		state->pid_ctrl_index = -2;
-		for (index_pid_filter_cmd = 0;
-				index_pid_filter_cmd <= pid_ctrl_index;
-				index_pid_filter_cmd++) {
-			if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER_CTRL)
-				dib9000_fw_pid_filter_ctrl(state->fe[0],
-						state->pid_ctrl[index_pid_filter_cmd].onoff);
-			else if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER)
-				dib9000_fw_pid_filter(state->fe[0],
-						state->pid_ctrl[index_pid_filter_cmd].id,
-						state->pid_ctrl[index_pid_filter_cmd].pid,
-						state->pid_ctrl[index_pid_filter_cmd].onoff);
-		}
-	}
-	/* do not postpone any more the pid filtering */
-	state->pid_ctrl_index = -2;
-
-	return 0;
-}
-
-static u16 dib9000_read_lock(struct dvb_frontend *fe)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-
-	return dib9000_read_word(state, 535);
-}
-
-static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	u8 index_frontend;
-	u16 lock = 0, lock_slave = 0;
-
-	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
-		dprintk("could not get the lock");
-		return -EINTR;
-	}
-	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
-		lock_slave |= dib9000_read_lock(state->fe[index_frontend]);
-
-	lock = dib9000_read_word(state, 535);
-
-	*stat = 0;
-
-	if ((lock & 0x8000) || (lock_slave & 0x8000))
-		*stat |= FE_HAS_SIGNAL;
-	if ((lock & 0x3000) || (lock_slave & 0x3000))
-		*stat |= FE_HAS_CARRIER;
-	if ((lock & 0x0100) || (lock_slave & 0x0100))
-		*stat |= FE_HAS_VITERBI;
-	if (((lock & 0x0038) == 0x38) || ((lock_slave & 0x0038) == 0x38))
-		*stat |= FE_HAS_SYNC;
-	if ((lock & 0x0008) || (lock_slave & 0x0008))
-		*stat |= FE_HAS_LOCK;
-
-	mutex_unlock(&state->demod_lock);
-
-	return 0;
-}
-
-static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	u16 *c;
-	int ret = 0;
-
-	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
-		dprintk("could not get the lock");
-		return -EINTR;
-	}
-	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
-		dprintk("could not get the lock");
-		ret = -EINTR;
-		goto error;
-	}
-	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
-		mutex_unlock(&state->platform.risc.mem_mbx_lock);
-		ret = -EIO;
-		goto error;
-	}
-	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR,
-			state->i2c_read_buffer, 16 * 2);
-	mutex_unlock(&state->platform.risc.mem_mbx_lock);
-
-	c = (u16 *)state->i2c_read_buffer;
-
-	*ber = c[10] << 16 | c[11];
-
-error:
-	mutex_unlock(&state->demod_lock);
-	return ret;
-}
-
-static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	u8 index_frontend;
-	u16 *c = (u16 *)state->i2c_read_buffer;
-	u16 val;
-	int ret = 0;
-
-	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
-		dprintk("could not get the lock");
-		return -EINTR;
-	}
-	*strength = 0;
-	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-		state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
-		if (val > 65535 - *strength)
-			*strength = 65535;
-		else
-			*strength += val;
-	}
-
-	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
-		dprintk("could not get the lock");
-		ret = -EINTR;
-		goto error;
-	}
-	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
-		mutex_unlock(&state->platform.risc.mem_mbx_lock);
-		ret = -EIO;
-		goto error;
-	}
-	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
-	mutex_unlock(&state->platform.risc.mem_mbx_lock);
-
-	val = 65535 - c[4];
-	if (val > 65535 - *strength)
-		*strength = 65535;
-	else
-		*strength += val;
-
-error:
-	mutex_unlock(&state->demod_lock);
-	return ret;
-}
-
-static u32 dib9000_get_snr(struct dvb_frontend *fe)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	u16 *c = (u16 *)state->i2c_read_buffer;
-	u32 n, s, exp;
-	u16 val;
-
-	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
-		dprintk("could not get the lock");
-		return 0;
-	}
-	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
-		mutex_unlock(&state->platform.risc.mem_mbx_lock);
-		return 0;
-	}
-	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
-	mutex_unlock(&state->platform.risc.mem_mbx_lock);
-
-	val = c[7];
-	n = (val >> 4) & 0xff;
-	exp = ((val & 0xf) << 2);
-	val = c[8];
-	exp += ((val >> 14) & 0x3);
-	if ((exp & 0x20) != 0)
-		exp -= 0x40;
-	n <<= exp + 16;
-
-	s = (val >> 6) & 0xFF;
-	exp = (val & 0x3F);
-	if ((exp & 0x20) != 0)
-		exp -= 0x40;
-	s <<= exp + 16;
-
-	if (n > 0) {
-		u32 t = (s / n) << 16;
-		return t + ((s << 16) - n * t) / n;
-	}
-	return 0xffffffff;
-}
-
-static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	u8 index_frontend;
-	u32 snr_master;
-
-	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
-		dprintk("could not get the lock");
-		return -EINTR;
-	}
-	snr_master = dib9000_get_snr(fe);
-	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
-		snr_master += dib9000_get_snr(state->fe[index_frontend]);
-
-	if ((snr_master >> 16) != 0) {
-		snr_master = 10 * intlog10(snr_master >> 16);
-		*snr = snr_master / ((1 << 24) / 10);
-	} else
-		*snr = 0;
-
-	mutex_unlock(&state->demod_lock);
-
-	return 0;
-}
-
-static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	u16 *c = (u16 *)state->i2c_read_buffer;
-	int ret = 0;
-
-	if (mutex_lock_interruptible(&state->demod_lock) < 0) {
-		dprintk("could not get the lock");
-		return -EINTR;
-	}
-	if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
-		dprintk("could not get the lock");
-		ret = -EINTR;
-		goto error;
-	}
-	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
-		mutex_unlock(&state->platform.risc.mem_mbx_lock);
-		ret = -EIO;
-		goto error;
-	}
-	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
-	mutex_unlock(&state->platform.risc.mem_mbx_lock);
-
-	*unc = c[12];
-
-error:
-	mutex_unlock(&state->demod_lock);
-	return ret;
-}
-
-int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr)
-{
-	int k = 0, ret = 0;
-	u8 new_addr = 0;
-	struct i2c_device client = {.i2c_adap = i2c };
-
-	client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
-	if (!client.i2c_write_buffer) {
-		dprintk("%s: not enough memory", __func__);
-		return -ENOMEM;
-	}
-	client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
-	if (!client.i2c_read_buffer) {
-		dprintk("%s: not enough memory", __func__);
-		ret = -ENOMEM;
-		goto error_memory;
-	}
-
-	client.i2c_addr = default_addr + 16;
-	dib9000_i2c_write16(&client, 1796, 0x0);
-
-	for (k = no_of_demods - 1; k >= 0; k--) {
-		/* designated i2c address */
-		new_addr = first_addr + (k << 1);
-		client.i2c_addr = default_addr;
-
-		dib9000_i2c_write16(&client, 1817, 3);
-		dib9000_i2c_write16(&client, 1796, 0);
-		dib9000_i2c_write16(&client, 1227, 1);
-		dib9000_i2c_write16(&client, 1227, 0);
-
-		client.i2c_addr = new_addr;
-		dib9000_i2c_write16(&client, 1817, 3);
-		dib9000_i2c_write16(&client, 1796, 0);
-		dib9000_i2c_write16(&client, 1227, 1);
-		dib9000_i2c_write16(&client, 1227, 0);
-
-		if (dib9000_identify(&client) == 0) {
-			client.i2c_addr = default_addr;
-			if (dib9000_identify(&client) == 0) {
-				dprintk("DiB9000 #%d: not identified", k);
-				ret = -EIO;
-				goto error;
-			}
-		}
-
-		dib9000_i2c_write16(&client, 1795, (1 << 10) | (4 << 6));
-		dib9000_i2c_write16(&client, 1794, (new_addr << 2) | 2);
-
-		dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
-	}
-
-	for (k = 0; k < no_of_demods; k++) {
-		new_addr = first_addr | (k << 1);
-		client.i2c_addr = new_addr;
-
-		dib9000_i2c_write16(&client, 1794, (new_addr << 2));
-		dib9000_i2c_write16(&client, 1795, 0);
-	}
-
-error:
-	kfree(client.i2c_read_buffer);
-error_memory:
-	kfree(client.i2c_write_buffer);
-
-	return ret;
-}
-EXPORT_SYMBOL(dib9000_i2c_enumeration);
-
-int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	u8 index_frontend = 1;
-
-	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
-		index_frontend++;
-	if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
-		dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
-		state->fe[index_frontend] = fe_slave;
-		return 0;
-	}
-
-	dprintk("too many slave frontend");
-	return -ENOMEM;
-}
-EXPORT_SYMBOL(dib9000_set_slave_frontend);
-
-int dib9000_remove_slave_frontend(struct dvb_frontend *fe)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-	u8 index_frontend = 1;
-
-	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
-		index_frontend++;
-	if (index_frontend != 1) {
-		dprintk("remove slave fe %p (index %i)", state->fe[index_frontend - 1], index_frontend - 1);
-		state->fe[index_frontend] = NULL;
-		return 0;
-	}
-
-	dprintk("no frontend to be removed");
-	return -ENODEV;
-}
-EXPORT_SYMBOL(dib9000_remove_slave_frontend);
-
-struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
-{
-	struct dib9000_state *state = fe->demodulator_priv;
-
-	if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
-		return NULL;
-	return state->fe[slave_index];
-}
-EXPORT_SYMBOL(dib9000_get_slave_frontend);
-
-static struct dvb_frontend_ops dib9000_ops;
-struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg)
-{
-	struct dvb_frontend *fe;
-	struct dib9000_state *st;
-	st = kzalloc(sizeof(struct dib9000_state), GFP_KERNEL);
-	if (st == NULL)
-		return NULL;
-	fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
-	if (fe == NULL) {
-		kfree(st);
-		return NULL;
-	}
-
-	memcpy(&st->chip.d9.cfg, cfg, sizeof(struct dib9000_config));
-	st->i2c.i2c_adap = i2c_adap;
-	st->i2c.i2c_addr = i2c_addr;
-	st->i2c.i2c_write_buffer = st->i2c_write_buffer;
-	st->i2c.i2c_read_buffer = st->i2c_read_buffer;
-
-	st->gpio_dir = DIB9000_GPIO_DEFAULT_DIRECTIONS;
-	st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES;
-	st->gpio_pwm_pos = DIB9000_GPIO_DEFAULT_PWM_POS;
-
-	mutex_init(&st->platform.risc.mbx_if_lock);
-	mutex_init(&st->platform.risc.mbx_lock);
-	mutex_init(&st->platform.risc.mem_lock);
-	mutex_init(&st->platform.risc.mem_mbx_lock);
-	mutex_init(&st->demod_lock);
-	st->get_frontend_internal = 0;
-
-	st->pid_ctrl_index = -2;
-
-	st->fe[0] = fe;
-	fe->demodulator_priv = st;
-	memcpy(&st->fe[0]->ops, &dib9000_ops, sizeof(struct dvb_frontend_ops));
-
-	/* Ensure the output mode remains at the previous default if it's
-	 * not specifically set by the caller.
-	 */
-	if ((st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
-		st->chip.d9.cfg.output_mode = OUTMODE_MPEG2_FIFO;
-
-	if (dib9000_identify(&st->i2c) == 0)
-		goto error;
-
-	dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c.i2c_adap, st->i2c.i2c_addr);
-
-	st->tuner_adap.dev.parent = i2c_adap->dev.parent;
-	strncpy(st->tuner_adap.name, "DIB9000_FW TUNER ACCESS", sizeof(st->tuner_adap.name));
-	st->tuner_adap.algo = &dib9000_tuner_algo;
-	st->tuner_adap.algo_data = NULL;
-	i2c_set_adapdata(&st->tuner_adap, st);
-	if (i2c_add_adapter(&st->tuner_adap) < 0)
-		goto error;
-
-	st->component_bus.dev.parent = i2c_adap->dev.parent;
-	strncpy(st->component_bus.name, "DIB9000_FW COMPONENT BUS ACCESS", sizeof(st->component_bus.name));
-	st->component_bus.algo = &dib9000_component_bus_algo;
-	st->component_bus.algo_data = NULL;
-	st->component_bus_speed = 340;
-	i2c_set_adapdata(&st->component_bus, st);
-	if (i2c_add_adapter(&st->component_bus) < 0)
-		goto component_bus_add_error;
-
-	dib9000_fw_reset(fe);
-
-	return fe;
-
-component_bus_add_error:
-	i2c_del_adapter(&st->tuner_adap);
-error:
-	kfree(st);
-	return NULL;
-}
-EXPORT_SYMBOL(dib9000_attach);
-
-static struct dvb_frontend_ops dib9000_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		 .name = "DiBcom 9000",
-		 .frequency_min = 44250000,
-		 .frequency_max = 867250000,
-		 .frequency_stepsize = 62500,
-		 .caps = FE_CAN_INVERSION_AUTO |
-		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
-		 },
-
-	.release = dib9000_release,
-
-	.init = dib9000_wakeup,
-	.sleep = dib9000_sleep,
-
-	.set_frontend = dib9000_set_frontend,
-	.get_tune_settings = dib9000_fe_get_tune_settings,
-	.get_frontend = dib9000_get_frontend,
-
-	.read_status = dib9000_read_status,
-	.read_ber = dib9000_read_ber,
-	.read_signal_strength = dib9000_read_signal_strength,
-	.read_snr = dib9000_read_snr,
-	.read_ucblocks = dib9000_read_unc_blocks,
-};
-
-MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
-MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
-MODULE_DESCRIPTION("Driver for the DiBcom 9000 COFDM demodulator");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dib9000.h b/drivers/media/dvb/frontends/dib9000.h
deleted file mode 100644
index b5781a4..0000000
--- a/drivers/media/dvb/frontends/dib9000.h
+++ /dev/null
@@ -1,131 +0,0 @@
-#ifndef DIB9000_H
-#define DIB9000_H
-
-#include "dibx000_common.h"
-
-struct dib9000_config {
-	u8 dvbt_mode;
-	u8 output_mpeg2_in_188_bytes;
-	u8 hostbus_diversity;
-	struct dibx000_bandwidth_config *bw;
-
-	u16 if_drives;
-
-	u32 timing_frequency;
-	u32 xtal_clock_khz;
-	u32 vcxo_timer;
-	u32 demod_clock_khz;
-
-	const u8 *microcode_B_fe_buffer;
-	u32 microcode_B_fe_size;
-
-	struct dibGPIOFunction gpio_function[2];
-	struct dibSubbandSelection subband;
-
-	u8 output_mode;
-};
-
-#define DEFAULT_DIB9000_I2C_ADDRESS 18
-
-#if defined(CONFIG_DVB_DIB9000) || (defined(CONFIG_DVB_DIB9000_MODULE) && defined(MODULE))
-extern struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg);
-extern int dib9000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr);
-extern struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe);
-extern struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating);
-extern int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val);
-extern int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff);
-extern int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff);
-extern int dib9000_firmware_post_pll_init(struct dvb_frontend *fe);
-extern int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave);
-extern int dib9000_remove_slave_frontend(struct dvb_frontend *fe);
-extern struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index);
-extern struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe);
-extern int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c);
-extern int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed);
-#else
-static inline struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib9000_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline int dib9000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib9000_firmware_post_pll_init(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-int dib9000_remove_slave_frontend(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-#endif
-
-#endif
diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c
deleted file mode 100644
index 43be723..0000000
--- a/drivers/media/dvb/frontends/dibx000_common.c
+++ /dev/null
@@ -1,515 +0,0 @@
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <linux/module.h>
-
-#include "dibx000_common.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
-
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); printk("\n"); } } while (0)
-
-static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
-{
-	int ret;
-
-	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return -EINVAL;
-	}
-
-	mst->i2c_write_buffer[0] = (reg >> 8) & 0xff;
-	mst->i2c_write_buffer[1] = reg & 0xff;
-	mst->i2c_write_buffer[2] = (val >> 8) & 0xff;
-	mst->i2c_write_buffer[3] = val & 0xff;
-
-	memset(mst->msg, 0, sizeof(struct i2c_msg));
-	mst->msg[0].addr = mst->i2c_addr;
-	mst->msg[0].flags = 0;
-	mst->msg[0].buf = mst->i2c_write_buffer;
-	mst->msg[0].len = 4;
-
-	ret = i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0;
-	mutex_unlock(&mst->i2c_buffer_lock);
-
-	return ret;
-}
-
-static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg)
-{
-	u16 ret;
-
-	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return 0;
-	}
-
-	mst->i2c_write_buffer[0] = reg >> 8;
-	mst->i2c_write_buffer[1] = reg & 0xff;
-
-	memset(mst->msg, 0, 2 * sizeof(struct i2c_msg));
-	mst->msg[0].addr = mst->i2c_addr;
-	mst->msg[0].flags = 0;
-	mst->msg[0].buf = mst->i2c_write_buffer;
-	mst->msg[0].len = 2;
-	mst->msg[1].addr = mst->i2c_addr;
-	mst->msg[1].flags = I2C_M_RD;
-	mst->msg[1].buf = mst->i2c_read_buffer;
-	mst->msg[1].len = 2;
-
-	if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2)
-		dprintk("i2c read error on %d", reg);
-
-	ret = (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1];
-	mutex_unlock(&mst->i2c_buffer_lock);
-
-	return ret;
-}
-
-static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst)
-{
-	int i = 100;
-	u16 status;
-
-	while (((status = dibx000_read_word(mst, mst->base_reg + 2)) & 0x0100) == 0 && --i > 0)
-		;
-
-	/* i2c timed out */
-	if (i == 0)
-		return -EREMOTEIO;
-
-	/* no acknowledge */
-	if ((status & 0x0080) == 0)
-		return -EREMOTEIO;
-
-	return 0;
-}
-
-static int dibx000_master_i2c_write(struct dibx000_i2c_master *mst, struct i2c_msg *msg, u8 stop)
-{
-	u16 data;
-	u16 da;
-	u16 i;
-	u16 txlen = msg->len, len;
-	const u8 *b = msg->buf;
-
-	while (txlen) {
-		dibx000_read_word(mst, mst->base_reg + 2);
-
-		len = txlen > 8 ? 8 : txlen;
-		for (i = 0; i < len; i += 2) {
-			data = *b++ << 8;
-			if (i+1 < len)
-				data |= *b++;
-			dibx000_write_word(mst, mst->base_reg, data);
-		}
-		da = (((u8) (msg->addr))  << 9) |
-			(1           << 8) |
-			(1           << 7) |
-			(0           << 6) |
-			(0           << 5) |
-			((len & 0x7) << 2) |
-			(0           << 1) |
-			(0           << 0);
-
-		if (txlen == msg->len)
-			da |= 1 << 5; /* start */
-
-		if (txlen-len == 0 && stop)
-			da |= 1 << 6; /* stop */
-
-		dibx000_write_word(mst, mst->base_reg+1, da);
-
-		if (dibx000_is_i2c_done(mst) != 0)
-			return -EREMOTEIO;
-		txlen -= len;
-	}
-
-	return 0;
-}
-
-static int dibx000_master_i2c_read(struct dibx000_i2c_master *mst, struct i2c_msg *msg)
-{
-	u16 da;
-	u8 *b = msg->buf;
-	u16 rxlen = msg->len, len;
-
-	while (rxlen) {
-		len = rxlen > 8 ? 8 : rxlen;
-		da = (((u8) (msg->addr)) << 9) |
-			(1           << 8) |
-			(1           << 7) |
-			(0           << 6) |
-			(0           << 5) |
-			((len & 0x7) << 2) |
-			(1           << 1) |
-			(0           << 0);
-
-		if (rxlen == msg->len)
-			da |= 1 << 5; /* start */
-
-		if (rxlen-len == 0)
-			da |= 1 << 6; /* stop */
-		dibx000_write_word(mst, mst->base_reg+1, da);
-
-		if (dibx000_is_i2c_done(mst) != 0)
-			return -EREMOTEIO;
-
-		rxlen -= len;
-
-		while (len) {
-			da = dibx000_read_word(mst, mst->base_reg);
-			*b++ = (da >> 8) & 0xff;
-			len--;
-			if (len >= 1) {
-				*b++ =  da   & 0xff;
-				len--;
-			}
-		}
-	}
-
-	return 0;
-}
-
-int dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed)
-{
-	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
-
-	if (mst->device_rev < DIB7000MC && speed < 235)
-		speed = 235;
-	return dibx000_write_word(mst, mst->base_reg + 3, (u16)(60000 / speed));
-
-}
-EXPORT_SYMBOL(dibx000_i2c_set_speed);
-
-static u32 dibx000_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst,
-					enum dibx000_i2c_interface intf)
-{
-	if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) {
-		dprintk("selecting interface: %d", intf);
-		mst->selected_interface = intf;
-		return dibx000_write_word(mst, mst->base_reg + 4, intf);
-	}
-	return 0;
-}
-
-static int dibx000_i2c_master_xfer_gpio12(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
-{
-	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
-	int msg_index;
-	int ret = 0;
-
-	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_1_2);
-	for (msg_index = 0; msg_index < num; msg_index++) {
-		if (msg[msg_index].flags & I2C_M_RD) {
-			ret = dibx000_master_i2c_read(mst, &msg[msg_index]);
-			if (ret != 0)
-				return 0;
-		} else {
-			ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1);
-			if (ret != 0)
-				return 0;
-		}
-	}
-
-	return num;
-}
-
-static int dibx000_i2c_master_xfer_gpio34(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
-{
-	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
-	int msg_index;
-	int ret = 0;
-
-	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_3_4);
-	for (msg_index = 0; msg_index < num; msg_index++) {
-		if (msg[msg_index].flags & I2C_M_RD) {
-			ret = dibx000_master_i2c_read(mst, &msg[msg_index]);
-			if (ret != 0)
-				return 0;
-		} else {
-			ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1);
-			if (ret != 0)
-				return 0;
-		}
-	}
-
-	return num;
-}
-
-static struct i2c_algorithm dibx000_i2c_master_gpio12_xfer_algo = {
-	.master_xfer = dibx000_i2c_master_xfer_gpio12,
-	.functionality = dibx000_i2c_func,
-};
-
-static struct i2c_algorithm dibx000_i2c_master_gpio34_xfer_algo = {
-	.master_xfer = dibx000_i2c_master_xfer_gpio34,
-	.functionality = dibx000_i2c_func,
-};
-
-static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4],
-				 u8 addr, int onoff)
-{
-	u16 val;
-
-
-	if (onoff)
-		val = addr << 8;	// bit 7 = use master or not, if 0, the gate is open
-	else
-		val = 1 << 7;
-
-	if (mst->device_rev > DIB7000)
-		val <<= 1;
-
-	tx[0] = (((mst->base_reg + 1) >> 8) & 0xff);
-	tx[1] = ((mst->base_reg + 1) & 0xff);
-	tx[2] = val >> 8;
-	tx[3] = val & 0xff;
-
-	return 0;
-}
-
-static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap,
-					struct i2c_msg msg[], int num)
-{
-	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
-	int ret;
-
-	if (num > 32) {
-		dprintk("%s: too much I2C message to be transmitted (%i).\
-				Maximum is 32", __func__, num);
-		return -ENOMEM;
-	}
-
-	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7);
-
-	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return -EINVAL;
-	}
-
-	memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
-
-	/* open the gate */
-	dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
-	mst->msg[0].addr = mst->i2c_addr;
-	mst->msg[0].buf = &mst->i2c_write_buffer[0];
-	mst->msg[0].len = 4;
-
-	memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num);
-
-	/* close the gate */
-	dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0);
-	mst->msg[num + 1].addr = mst->i2c_addr;
-	mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
-	mst->msg[num + 1].len = 4;
-
-	ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ?
-			num : -EIO);
-
-	mutex_unlock(&mst->i2c_buffer_lock);
-	return ret;
-}
-
-static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = {
-	.master_xfer = dibx000_i2c_gated_gpio67_xfer,
-	.functionality = dibx000_i2c_func,
-};
-
-static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap,
-					struct i2c_msg msg[], int num)
-{
-	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
-	int ret;
-
-	if (num > 32) {
-		dprintk("%s: too much I2C message to be transmitted (%i).\
-				Maximum is 32", __func__, num);
-		return -ENOMEM;
-	}
-
-	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
-
-	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return -EINVAL;
-	}
-	memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
-
-	/* open the gate */
-	dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
-	mst->msg[0].addr = mst->i2c_addr;
-	mst->msg[0].buf = &mst->i2c_write_buffer[0];
-	mst->msg[0].len = 4;
-
-	memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num);
-
-	/* close the gate */
-	dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0);
-	mst->msg[num + 1].addr = mst->i2c_addr;
-	mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
-	mst->msg[num + 1].len = 4;
-
-	ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ?
-			num : -EIO);
-	mutex_unlock(&mst->i2c_buffer_lock);
-	return ret;
-}
-
-static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
-	.master_xfer = dibx000_i2c_gated_tuner_xfer,
-	.functionality = dibx000_i2c_func,
-};
-
-struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst,
-						enum dibx000_i2c_interface intf,
-						int gating)
-{
-	struct i2c_adapter *i2c = NULL;
-
-	switch (intf) {
-	case DIBX000_I2C_INTERFACE_TUNER:
-		if (gating)
-			i2c = &mst->gated_tuner_i2c_adap;
-		break;
-	case DIBX000_I2C_INTERFACE_GPIO_1_2:
-		if (!gating)
-			i2c = &mst->master_i2c_adap_gpio12;
-		break;
-	case DIBX000_I2C_INTERFACE_GPIO_3_4:
-		if (!gating)
-			i2c = &mst->master_i2c_adap_gpio34;
-		break;
-	case DIBX000_I2C_INTERFACE_GPIO_6_7:
-		if (gating)
-			i2c = &mst->master_i2c_adap_gpio67;
-		break;
-	default:
-		printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n");
-		break;
-	}
-
-	return i2c;
-}
-
-EXPORT_SYMBOL(dibx000_get_i2c_adapter);
-
-void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst)
-{
-	/* initialize the i2c-master by closing the gate */
-	u8 tx[4];
-	struct i2c_msg m = {.addr = mst->i2c_addr,.buf = tx,.len = 4 };
-
-	dibx000_i2c_gate_ctrl(mst, tx, 0, 0);
-	i2c_transfer(mst->i2c_adap, &m, 1);
-	mst->selected_interface = 0xff;	// the first time force a select of the I2C
-	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
-}
-
-EXPORT_SYMBOL(dibx000_reset_i2c_master);
-
-static int i2c_adapter_init(struct i2c_adapter *i2c_adap,
-				struct i2c_algorithm *algo, const char *name,
-				struct dibx000_i2c_master *mst)
-{
-	strncpy(i2c_adap->name, name, sizeof(i2c_adap->name));
-	i2c_adap->algo = algo;
-	i2c_adap->algo_data = NULL;
-	i2c_set_adapdata(i2c_adap, mst);
-	if (i2c_add_adapter(i2c_adap) < 0)
-		return -ENODEV;
-	return 0;
-}
-
-int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev,
-				struct i2c_adapter *i2c_adap, u8 i2c_addr)
-{
-	int ret;
-
-	mutex_init(&mst->i2c_buffer_lock);
-	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
-		dprintk("could not acquire lock");
-		return -EINVAL;
-	}
-	memset(mst->msg, 0, sizeof(struct i2c_msg));
-	mst->msg[0].addr = i2c_addr >> 1;
-	mst->msg[0].flags = 0;
-	mst->msg[0].buf = mst->i2c_write_buffer;
-	mst->msg[0].len = 4;
-
-	mst->device_rev = device_rev;
-	mst->i2c_adap = i2c_adap;
-	mst->i2c_addr = i2c_addr >> 1;
-
-	if (device_rev == DIB7000P || device_rev == DIB8000)
-		mst->base_reg = 1024;
-	else
-		mst->base_reg = 768;
-
-	mst->gated_tuner_i2c_adap.dev.parent = mst->i2c_adap->dev.parent;
-	if (i2c_adapter_init
-			(&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo,
-			 "DiBX000 tuner I2C bus", mst) != 0)
-		printk(KERN_ERR
-				"DiBX000: could not initialize the tuner i2c_adapter\n");
-
-	mst->master_i2c_adap_gpio12.dev.parent = mst->i2c_adap->dev.parent;
-	if (i2c_adapter_init
-			(&mst->master_i2c_adap_gpio12, &dibx000_i2c_master_gpio12_xfer_algo,
-			 "DiBX000 master GPIO12 I2C bus", mst) != 0)
-		printk(KERN_ERR
-				"DiBX000: could not initialize the master i2c_adapter\n");
-
-	mst->master_i2c_adap_gpio34.dev.parent = mst->i2c_adap->dev.parent;
-	if (i2c_adapter_init
-			(&mst->master_i2c_adap_gpio34, &dibx000_i2c_master_gpio34_xfer_algo,
-			 "DiBX000 master GPIO34 I2C bus", mst) != 0)
-		printk(KERN_ERR
-				"DiBX000: could not initialize the master i2c_adapter\n");
-
-	mst->master_i2c_adap_gpio67.dev.parent = mst->i2c_adap->dev.parent;
-	if (i2c_adapter_init
-			(&mst->master_i2c_adap_gpio67, &dibx000_i2c_gated_gpio67_algo,
-			 "DiBX000 master GPIO67 I2C bus", mst) != 0)
-		printk(KERN_ERR
-				"DiBX000: could not initialize the master i2c_adapter\n");
-
-	/* initialize the i2c-master by closing the gate */
-	dibx000_i2c_gate_ctrl(mst, mst->i2c_write_buffer, 0, 0);
-
-	ret = (i2c_transfer(i2c_adap, mst->msg, 1) == 1);
-	mutex_unlock(&mst->i2c_buffer_lock);
-
-	return ret;
-}
-
-EXPORT_SYMBOL(dibx000_init_i2c_master);
-
-void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst)
-{
-	i2c_del_adapter(&mst->gated_tuner_i2c_adap);
-	i2c_del_adapter(&mst->master_i2c_adap_gpio12);
-	i2c_del_adapter(&mst->master_i2c_adap_gpio34);
-	i2c_del_adapter(&mst->master_i2c_adap_gpio67);
-}
-EXPORT_SYMBOL(dibx000_exit_i2c_master);
-
-
-u32 systime(void)
-{
-	struct timespec t;
-
-	t = current_kernel_time();
-	return (t.tv_sec * 10000) + (t.tv_nsec / 100000);
-}
-EXPORT_SYMBOL(systime);
-
-MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
-MODULE_DESCRIPTION("Common function the DiBcom demodulator family");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h
deleted file mode 100644
index 5f48488..0000000
--- a/drivers/media/dvb/frontends/dibx000_common.h
+++ /dev/null
@@ -1,280 +0,0 @@
-#ifndef DIBX000_COMMON_H
-#define DIBX000_COMMON_H
-
-enum dibx000_i2c_interface {
-	DIBX000_I2C_INTERFACE_TUNER = 0,
-	DIBX000_I2C_INTERFACE_GPIO_1_2 = 1,
-	DIBX000_I2C_INTERFACE_GPIO_3_4 = 2,
-	DIBX000_I2C_INTERFACE_GPIO_6_7 = 3
-};
-
-struct dibx000_i2c_master {
-#define DIB3000MC 1
-#define DIB7000   2
-#define DIB7000P  11
-#define DIB7000MC 12
-#define DIB8000   13
-	u16 device_rev;
-
-	enum dibx000_i2c_interface selected_interface;
-
-/*	struct i2c_adapter  tuner_i2c_adap; */
-	struct i2c_adapter gated_tuner_i2c_adap;
-	struct i2c_adapter master_i2c_adap_gpio12;
-	struct i2c_adapter master_i2c_adap_gpio34;
-	struct i2c_adapter master_i2c_adap_gpio67;
-
-	struct i2c_adapter *i2c_adap;
-	u8 i2c_addr;
-
-	u16 base_reg;
-
-	/* for the I2C transfer */
-	struct i2c_msg msg[34];
-	u8 i2c_write_buffer[8];
-	u8 i2c_read_buffer[2];
-	struct mutex i2c_buffer_lock;
-};
-
-extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst,
-					u16 device_rev, struct i2c_adapter *i2c_adap,
-					u8 i2c_addr);
-extern struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master
-							*mst,
-							enum dibx000_i2c_interface
-							intf, int gating);
-extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst);
-extern void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst);
-extern int dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed);
-
-extern u32 systime(void);
-
-#define BAND_LBAND 0x01
-#define BAND_UHF   0x02
-#define BAND_VHF   0x04
-#define BAND_SBAND 0x08
-#define BAND_FM	   0x10
-#define BAND_CBAND 0x20
-
-#define BAND_OF_FREQUENCY(freq_kHz) ((freq_kHz) <= 170000 ? BAND_CBAND : \
-									(freq_kHz) <= 115000 ? BAND_FM : \
-									(freq_kHz) <= 250000 ? BAND_VHF : \
-									(freq_kHz) <= 863000 ? BAND_UHF : \
-									(freq_kHz) <= 2000000 ? BAND_LBAND : BAND_SBAND )
-
-struct dibx000_agc_config {
-	/* defines the capabilities of this AGC-setting - using the BAND_-defines */
-	u8 band_caps;
-
-	u16 setup;
-
-	u16 inv_gain;
-	u16 time_stabiliz;
-
-	u8 alpha_level;
-	u16 thlock;
-
-	u8 wbd_inv;
-	u16 wbd_ref;
-	u8 wbd_sel;
-	u8 wbd_alpha;
-
-	u16 agc1_max;
-	u16 agc1_min;
-	u16 agc2_max;
-	u16 agc2_min;
-
-	u8 agc1_pt1;
-	u8 agc1_pt2;
-	u8 agc1_pt3;
-
-	u8 agc1_slope1;
-	u8 agc1_slope2;
-
-	u8 agc2_pt1;
-	u8 agc2_pt2;
-
-	u8 agc2_slope1;
-	u8 agc2_slope2;
-
-	u8 alpha_mant;
-	u8 alpha_exp;
-
-	u8 beta_mant;
-	u8 beta_exp;
-
-	u8 perform_agc_softsplit;
-
-	struct {
-		u16 min;
-		u16 max;
-		u16 min_thres;
-		u16 max_thres;
-	} split;
-};
-
-struct dibx000_bandwidth_config {
-	u32 internal;
-	u32 sampling;
-
-	u8 pll_prediv;
-	u8 pll_ratio;
-	u8 pll_range;
-	u8 pll_reset;
-	u8 pll_bypass;
-
-	u8 enable_refdiv;
-	u8 bypclk_div;
-	u8 IO_CLK_en_core;
-	u8 ADClkSrc;
-	u8 modulo;
-
-	u16 sad_cfg;
-
-	u32 ifreq;
-	u32 timf;
-
-	u32 xtal_hz;
-};
-
-enum dibx000_adc_states {
-	DIBX000_SLOW_ADC_ON = 0,
-	DIBX000_SLOW_ADC_OFF,
-	DIBX000_ADC_ON,
-	DIBX000_ADC_OFF,
-	DIBX000_VBG_ENABLE,
-	DIBX000_VBG_DISABLE,
-};
-
-#define BANDWIDTH_TO_KHZ(v)	((v) / 1000)
-#define BANDWIDTH_TO_HZ(v)	((v) * 1000)
-
-/* Chip output mode. */
-#define OUTMODE_HIGH_Z              0
-#define OUTMODE_MPEG2_PAR_GATED_CLK 1
-#define OUTMODE_MPEG2_PAR_CONT_CLK  2
-#define OUTMODE_MPEG2_SERIAL        7
-#define OUTMODE_DIVERSITY           4
-#define OUTMODE_MPEG2_FIFO          5
-#define OUTMODE_ANALOG_ADC          6
-
-#define INPUT_MODE_OFF                0x11
-#define INPUT_MODE_DIVERSITY          0x12
-#define INPUT_MODE_MPEG               0x13
-
-enum frontend_tune_state {
-	CT_TUNER_START = 10,
-	CT_TUNER_STEP_0,
-	CT_TUNER_STEP_1,
-	CT_TUNER_STEP_2,
-	CT_TUNER_STEP_3,
-	CT_TUNER_STEP_4,
-	CT_TUNER_STEP_5,
-	CT_TUNER_STEP_6,
-	CT_TUNER_STEP_7,
-	CT_TUNER_STOP,
-
-	CT_AGC_START = 20,
-	CT_AGC_STEP_0,
-	CT_AGC_STEP_1,
-	CT_AGC_STEP_2,
-	CT_AGC_STEP_3,
-	CT_AGC_STEP_4,
-	CT_AGC_STOP,
-
-	CT_DEMOD_START = 30,
-	CT_DEMOD_STEP_1,
-	CT_DEMOD_STEP_2,
-	CT_DEMOD_STEP_3,
-	CT_DEMOD_STEP_4,
-	CT_DEMOD_STEP_5,
-	CT_DEMOD_STEP_6,
-	CT_DEMOD_STEP_7,
-	CT_DEMOD_STEP_8,
-	CT_DEMOD_STEP_9,
-	CT_DEMOD_STEP_10,
-	CT_DEMOD_SEARCH_NEXT = 41,
-	CT_DEMOD_STEP_LOCKED,
-	CT_DEMOD_STOP,
-
-	CT_DONE = 100,
-	CT_SHUTDOWN,
-
-};
-
-struct dvb_frontend_parametersContext {
-#define CHANNEL_STATUS_PARAMETERS_UNKNOWN   0x01
-#define CHANNEL_STATUS_PARAMETERS_SET       0x02
-	u8 status;
-	u32 tune_time_estimation[2];
-	s32 tps_available;
-	u16 tps[9];
-};
-
-#define FE_STATUS_TUNE_FAILED          0
-#define FE_STATUS_TUNE_TIMED_OUT      -1
-#define FE_STATUS_TUNE_TIME_TOO_SHORT -2
-#define FE_STATUS_TUNE_PENDING        -3
-#define FE_STATUS_STD_SUCCESS         -4
-#define FE_STATUS_FFT_SUCCESS         -5
-#define FE_STATUS_DEMOD_SUCCESS       -6
-#define FE_STATUS_LOCKED              -7
-#define FE_STATUS_DATA_LOCKED         -8
-
-#define FE_CALLBACK_TIME_NEVER 0xffffffff
-
-#define ABS(x) ((x < 0) ? (-x) : (x))
-
-#define DATA_BUS_ACCESS_MODE_8BIT                 0x01
-#define DATA_BUS_ACCESS_MODE_16BIT                0x02
-#define DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT 0x10
-
-struct dibGPIOFunction {
-#define BOARD_GPIO_COMPONENT_BUS_ADAPTER 1
-#define BOARD_GPIO_COMPONENT_DEMOD       2
-	u8 component;
-
-#define BOARD_GPIO_FUNCTION_BOARD_ON      1
-#define BOARD_GPIO_FUNCTION_BOARD_OFF     2
-#define BOARD_GPIO_FUNCTION_COMPONENT_ON  3
-#define BOARD_GPIO_FUNCTION_COMPONENT_OFF 4
-#define BOARD_GPIO_FUNCTION_SUBBAND_PWM   5
-#define BOARD_GPIO_FUNCTION_SUBBAND_GPIO   6
-	u8 function;
-
-/* mask, direction and value are used specify which GPIO to change GPIO0
- * is LSB and possible GPIO31 is MSB.  The same bit-position as in the
- * mask is used for the direction and the value. Direction == 1 is OUT,
- * 0 == IN. For direction "OUT" value is either 1 or 0, for direction IN
- * value has no meaning.
- *
- * In case of BOARD_GPIO_FUNCTION_PWM mask is giving the GPIO to be
- * used to do the PWM. Direction gives the PWModulator to be used.
- * Value gives the PWM value in device-dependent scale.
- */
-	u32 mask;
-	u32 direction;
-	u32 value;
-};
-
-#define MAX_NB_SUBBANDS   8
-struct dibSubbandSelection {
-	u8  size; /* Actual number of subbands. */
-	struct {
-		u16 f_mhz;
-		struct dibGPIOFunction gpio;
-	} subband[MAX_NB_SUBBANDS];
-};
-
-#define DEMOD_TIMF_SET    0x00
-#define DEMOD_TIMF_GET    0x01
-#define DEMOD_TIMF_UPDATE 0x02
-
-#define MPEG_ON_DIBTX		1
-#define DIV_ON_DIBTX		2
-#define ADC_ON_DIBTX		3
-#define DEMOUT_ON_HOSTBUS	4
-#define DIBTX_ON_HOSTBUS	5
-#define MPEG_ON_HOSTBUS		6
-
-#endif
diff --git a/drivers/media/dvb/frontends/drxd.h b/drivers/media/dvb/frontends/drxd.h
deleted file mode 100644
index 216c8c3..0000000
--- a/drivers/media/dvb/frontends/drxd.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * drxd.h: DRXD DVB-T demodulator driver
- *
- * Copyright (C) 2005-2007 Micronas
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#ifndef _DRXD_H_
-#define _DRXD_H_
-
-#include <linux/types.h>
-#include <linux/i2c.h>
-
-struct drxd_config {
-	u8 index;
-
-	u8 pll_address;
-	u8 pll_type;
-#define DRXD_PLL_NONE     0
-#define DRXD_PLL_DTT7520X 1
-#define DRXD_PLL_MT3X0823 2
-
-	u32 clock;
-	u8 insert_rs_byte;
-
-	u8 demod_address;
-	u8 demoda_address;
-	u8 demod_revision;
-
-	/* If the tuner is not behind an i2c gate, be sure to flip this bit
-	   or else the i2c bus could get wedged */
-	u8 disable_i2c_gate_ctrl;
-
-	u32 IF;
-	 s16(*osc_deviation) (void *priv, s16 dev, int flag);
-};
-
-#if defined(CONFIG_DVB_DRXD) || \
-			(defined(CONFIG_DVB_DRXD_MODULE) && defined(MODULE))
-extern
-struct dvb_frontend *drxd_attach(const struct drxd_config *config,
-				 void *priv, struct i2c_adapter *i2c,
-				 struct device *dev);
-#else
-static inline
-struct dvb_frontend *drxd_attach(const struct drxd_config *config,
-				 void *priv, struct i2c_adapter *i2c,
-				 struct device *dev)
-{
-	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
-	       __func__);
-	return NULL;
-}
-#endif
-
-extern int drxd_config_i2c(struct dvb_frontend *, int);
-#endif
diff --git a/drivers/media/dvb/frontends/drxd_firm.c b/drivers/media/dvb/frontends/drxd_firm.c
deleted file mode 100644
index 5418b0b..0000000
--- a/drivers/media/dvb/frontends/drxd_firm.c
+++ /dev/null
@@ -1,929 +0,0 @@
-/*
- * drxd_firm.c : DRXD firmware tables
- *
- * Copyright (C) 2006-2007 Micronas
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-/* TODO: generate this file with a script from a settings file */
-
-/* Contains A2 firmware version: 1.4.2
- * Contains B1 firmware version: 3.3.33
- * Contains settings from driver 1.4.23
-*/
-
-#include "drxd_firm.h"
-
-#define ADDRESS(x)     ((x) & 0xFF), (((x)>>8) & 0xFF), (((x)>>16) & 0xFF), (((x)>>24) & 0xFF)
-#define LENGTH(x)      ((x) & 0xFF), (((x)>>8) & 0xFF)
-
-/* Is written via block write, must be little endian */
-#define DATA16(x)      ((x) & 0xFF), (((x)>>8) & 0xFF)
-
-#define WRBLOCK(a, l) ADDRESS(a), LENGTH(l)
-#define WR16(a, d) ADDRESS(a), LENGTH(1), DATA16(d)
-
-#define END_OF_TABLE      0xFF, 0xFF, 0xFF, 0xFF
-
-/* HI firmware patches */
-
-#define HI_TR_FUNC_ADDR HI_IF_RAM_USR_BEGIN__A
-#define HI_TR_FUNC_SIZE 9	/* size of this function in instruction words */
-
-u8 DRXD_InitAtomicRead[] = {
-	WRBLOCK(HI_TR_FUNC_ADDR, HI_TR_FUNC_SIZE),
-	0x26, 0x00,		/* 0         -> ring.rdy;           */
-	0x60, 0x04,		/* r0rami.dt -> ring.xba;           */
-	0x61, 0x04,		/* r0rami.dt -> ring.xad;           */
-	0xE3, 0x07,		/* HI_RA_RAM_USR_BEGIN -> ring.iad; */
-	0x40, 0x00,		/* (long immediate)                 */
-	0x64, 0x04,		/* r0rami.dt -> ring.len;           */
-	0x65, 0x04,		/* r0rami.dt -> ring.ctl;           */
-	0x26, 0x00,		/* 0         -> ring.rdy;           */
-	0x38, 0x00,		/* 0         -> jumps.ad;           */
-	END_OF_TABLE
-};
-
-/* Pins D0 and D1 of the parallel MPEG output can be used
-   to set the I2C address of a device. */
-
-#define HI_RST_FUNC_ADDR (HI_IF_RAM_USR_BEGIN__A + HI_TR_FUNC_SIZE)
-#define HI_RST_FUNC_SIZE 54	/* size of this function in instruction words */
-
-/* D0 Version */
-u8 DRXD_HiI2cPatch_1[] = {
-	WRBLOCK(HI_RST_FUNC_ADDR, HI_RST_FUNC_SIZE),
-	0xC8, 0x07, 0x01, 0x00,	/* MASK      -> reg0.dt;                        */
-	0xE0, 0x07, 0x15, 0x02,	/* (EC__BLK << 6) + EC_OC_REG__BNK -> ring.xba; */
-	0xE1, 0x07, 0x12, 0x00,	/* EC_OC_REG_OC_MPG_SIO__A -> ring.xad;         */
-	0xA2, 0x00,		/* M_BNK_ID_DAT -> ring.iba;                    */
-	0x23, 0x00,		/* &data     -> ring.iad;                       */
-	0x24, 0x00,		/* 0         -> ring.len;                       */
-	0xA5, 0x02,		/* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl;   */
-	0x26, 0x00,		/* 0         -> ring.rdy;                       */
-	0x42, 0x00,		/* &data+1   -> w0ram.ad;                       */
-	0xC0, 0x07, 0xFF, 0x0F,	/* -1        -> w0ram.dt;                       */
-	0x63, 0x00,		/* &data+1   -> ring.iad;                       */
-	0x65, 0x02,		/* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl;  */
-	0x26, 0x00,		/* 0         -> ring.rdy;                       */
-	0xE1, 0x07, 0x38, 0x00,	/* EC_OC_REG_OCR_MPG_USR_DAT__A -> ring.xad;    */
-	0xA5, 0x02,		/* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl;   */
-	0x26, 0x00,		/* 0         -> ring.rdy;                       */
-	0xE1, 0x07, 0x12, 0x00,	/* EC_OC_REG_OC_MPG_SIO__A -> ring.xad;         */
-	0x23, 0x00,		/* &data     -> ring.iad;                       */
-	0x65, 0x02,		/* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl;  */
-	0x26, 0x00,		/* 0         -> ring.rdy;                       */
-	0x42, 0x00,		/* &data+1   -> w0ram.ad;                       */
-	0x0F, 0x04,		/* r0ram.dt  -> and.op;                         */
-	0x1C, 0x06,		/* reg0.dt   -> and.tr;                         */
-	0xCF, 0x04,		/* and.rs    -> add.op;                         */
-	0xD0, 0x07, 0x70, 0x00,	/* DEF_DEV_ID -> add.tr;                        */
-	0xD0, 0x04,		/* add.rs    -> add.tr;                         */
-	0xC8, 0x04,		/* add.rs    -> reg0.dt;                        */
-	0x60, 0x00,		/* reg0.dt   -> w0ram.dt;                       */
-	0xC2, 0x07, 0x10, 0x00,	/* SLV0_BASE -> w0rami.ad;                      */
-	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
-	0x01, 0x06,		/* reg0.dt   -> w0rami.dt;                      */
-	0xC2, 0x07, 0x20, 0x00,	/* SLV1_BASE -> w0rami.ad;                      */
-	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
-	0x01, 0x06,		/* reg0.dt   -> w0rami.dt;                      */
-	0xC2, 0x07, 0x30, 0x00,	/* CMD_BASE  -> w0rami.ad;                      */
-	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
-	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
-	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
-	0x68, 0x00,		/* M_IC_SEL_PT1 -> i2c.sel;                     */
-	0x29, 0x00,		/* M_IC_CMD_RESET -> i2c.cmd;                   */
-	0x28, 0x00,		/* M_IC_SEL_PT0 -> i2c.sel;                     */
-	0x29, 0x00,		/* M_IC_CMD_RESET -> i2c.cmd;                   */
-	0xF8, 0x07, 0x2F, 0x00,	/* 0x2F      -> jumps.ad;                       */
-
-	WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 0) + 1)),
-	     (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
-	WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 1) + 1)),
-	     (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
-	WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 2) + 1)),
-	     (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
-	WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 3) + 1)),
-	     (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
-
-	/* Force quick and dirty reset */
-	WR16(B_HI_CT_REG_COMM_STATE__A, 0),
-	END_OF_TABLE
-};
-
-/* D0,D1 Version */
-u8 DRXD_HiI2cPatch_3[] = {
-	WRBLOCK(HI_RST_FUNC_ADDR, HI_RST_FUNC_SIZE),
-	0xC8, 0x07, 0x03, 0x00,	/* MASK      -> reg0.dt;                        */
-	0xE0, 0x07, 0x15, 0x02,	/* (EC__BLK << 6) + EC_OC_REG__BNK -> ring.xba; */
-	0xE1, 0x07, 0x12, 0x00,	/* EC_OC_REG_OC_MPG_SIO__A -> ring.xad;         */
-	0xA2, 0x00,		/* M_BNK_ID_DAT -> ring.iba;                    */
-	0x23, 0x00,		/* &data     -> ring.iad;                       */
-	0x24, 0x00,		/* 0         -> ring.len;                       */
-	0xA5, 0x02,		/* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl;   */
-	0x26, 0x00,		/* 0         -> ring.rdy;                       */
-	0x42, 0x00,		/* &data+1   -> w0ram.ad;                       */
-	0xC0, 0x07, 0xFF, 0x0F,	/* -1        -> w0ram.dt;                       */
-	0x63, 0x00,		/* &data+1   -> ring.iad;                       */
-	0x65, 0x02,		/* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl;  */
-	0x26, 0x00,		/* 0         -> ring.rdy;                       */
-	0xE1, 0x07, 0x38, 0x00,	/* EC_OC_REG_OCR_MPG_USR_DAT__A -> ring.xad;    */
-	0xA5, 0x02,		/* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl;   */
-	0x26, 0x00,		/* 0         -> ring.rdy;                       */
-	0xE1, 0x07, 0x12, 0x00,	/* EC_OC_REG_OC_MPG_SIO__A -> ring.xad;         */
-	0x23, 0x00,		/* &data     -> ring.iad;                       */
-	0x65, 0x02,		/* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl;  */
-	0x26, 0x00,		/* 0         -> ring.rdy;                       */
-	0x42, 0x00,		/* &data+1   -> w0ram.ad;                       */
-	0x0F, 0x04,		/* r0ram.dt  -> and.op;                         */
-	0x1C, 0x06,		/* reg0.dt   -> and.tr;                         */
-	0xCF, 0x04,		/* and.rs    -> add.op;                         */
-	0xD0, 0x07, 0x70, 0x00,	/* DEF_DEV_ID -> add.tr;                        */
-	0xD0, 0x04,		/* add.rs    -> add.tr;                         */
-	0xC8, 0x04,		/* add.rs    -> reg0.dt;                        */
-	0x60, 0x00,		/* reg0.dt   -> w0ram.dt;                       */
-	0xC2, 0x07, 0x10, 0x00,	/* SLV0_BASE -> w0rami.ad;                      */
-	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
-	0x01, 0x06,		/* reg0.dt   -> w0rami.dt;                      */
-	0xC2, 0x07, 0x20, 0x00,	/* SLV1_BASE -> w0rami.ad;                      */
-	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
-	0x01, 0x06,		/* reg0.dt   -> w0rami.dt;                      */
-	0xC2, 0x07, 0x30, 0x00,	/* CMD_BASE  -> w0rami.ad;                      */
-	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
-	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
-	0x01, 0x00,		/* 0         -> w0rami.dt;                      */
-	0x68, 0x00,		/* M_IC_SEL_PT1 -> i2c.sel;                     */
-	0x29, 0x00,		/* M_IC_CMD_RESET -> i2c.cmd;                   */
-	0x28, 0x00,		/* M_IC_SEL_PT0 -> i2c.sel;                     */
-	0x29, 0x00,		/* M_IC_CMD_RESET -> i2c.cmd;                   */
-	0xF8, 0x07, 0x2F, 0x00,	/* 0x2F      -> jumps.ad;                       */
-
-	WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 0) + 1)),
-	     (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
-	WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 1) + 1)),
-	     (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
-	WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 2) + 1)),
-	     (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
-	WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 3) + 1)),
-	     (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
-
-	/* Force quick and dirty reset */
-	WR16(B_HI_CT_REG_COMM_STATE__A, 0),
-	END_OF_TABLE
-};
-
-u8 DRXD_ResetCEFR[] = {
-	WRBLOCK(CE_REG_FR_TREAL00__A, 57),
-	0x52, 0x00,		/* CE_REG_FR_TREAL00__A */
-	0x00, 0x00,		/* CE_REG_FR_TIMAG00__A */
-	0x52, 0x00,		/* CE_REG_FR_TREAL01__A */
-	0x00, 0x00,		/* CE_REG_FR_TIMAG01__A */
-	0x52, 0x00,		/* CE_REG_FR_TREAL02__A */
-	0x00, 0x00,		/* CE_REG_FR_TIMAG02__A */
-	0x52, 0x00,		/* CE_REG_FR_TREAL03__A */
-	0x00, 0x00,		/* CE_REG_FR_TIMAG03__A */
-	0x52, 0x00,		/* CE_REG_FR_TREAL04__A */
-	0x00, 0x00,		/* CE_REG_FR_TIMAG04__A */
-	0x52, 0x00,		/* CE_REG_FR_TREAL05__A */
-	0x00, 0x00,		/* CE_REG_FR_TIMAG05__A */
-	0x52, 0x00,		/* CE_REG_FR_TREAL06__A */
-	0x00, 0x00,		/* CE_REG_FR_TIMAG06__A */
-	0x52, 0x00,		/* CE_REG_FR_TREAL07__A */
-	0x00, 0x00,		/* CE_REG_FR_TIMAG07__A */
-	0x52, 0x00,		/* CE_REG_FR_TREAL08__A */
-	0x00, 0x00,		/* CE_REG_FR_TIMAG08__A */
-	0x52, 0x00,		/* CE_REG_FR_TREAL09__A */
-	0x00, 0x00,		/* CE_REG_FR_TIMAG09__A */
-	0x52, 0x00,		/* CE_REG_FR_TREAL10__A */
-	0x00, 0x00,		/* CE_REG_FR_TIMAG10__A */
-	0x52, 0x00,		/* CE_REG_FR_TREAL11__A */
-	0x00, 0x00,		/* CE_REG_FR_TIMAG11__A */
-
-	0x52, 0x00,		/* CE_REG_FR_MID_TAP__A */
-
-	0x0B, 0x00,		/* CE_REG_FR_SQS_G00__A */
-	0x0B, 0x00,		/* CE_REG_FR_SQS_G01__A */
-	0x0B, 0x00,		/* CE_REG_FR_SQS_G02__A */
-	0x0B, 0x00,		/* CE_REG_FR_SQS_G03__A */
-	0x0B, 0x00,		/* CE_REG_FR_SQS_G04__A */
-	0x0B, 0x00,		/* CE_REG_FR_SQS_G05__A */
-	0x0B, 0x00,		/* CE_REG_FR_SQS_G06__A */
-	0x0B, 0x00,		/* CE_REG_FR_SQS_G07__A */
-	0x0B, 0x00,		/* CE_REG_FR_SQS_G08__A */
-	0x0B, 0x00,		/* CE_REG_FR_SQS_G09__A */
-	0x0B, 0x00,		/* CE_REG_FR_SQS_G10__A */
-	0x0B, 0x00,		/* CE_REG_FR_SQS_G11__A */
-	0x0B, 0x00,		/* CE_REG_FR_SQS_G12__A */
-
-	0xFF, 0x01,		/* CE_REG_FR_RIO_G00__A */
-	0x90, 0x01,		/* CE_REG_FR_RIO_G01__A */
-	0x0B, 0x01,		/* CE_REG_FR_RIO_G02__A */
-	0xC8, 0x00,		/* CE_REG_FR_RIO_G03__A */
-	0xA0, 0x00,		/* CE_REG_FR_RIO_G04__A */
-	0x85, 0x00,		/* CE_REG_FR_RIO_G05__A */
-	0x72, 0x00,		/* CE_REG_FR_RIO_G06__A */
-	0x64, 0x00,		/* CE_REG_FR_RIO_G07__A */
-	0x59, 0x00,		/* CE_REG_FR_RIO_G08__A */
-	0x50, 0x00,		/* CE_REG_FR_RIO_G09__A */
-	0x49, 0x00,		/* CE_REG_FR_RIO_G10__A */
-
-	0x10, 0x00,		/* CE_REG_FR_MODE__A     */
-	0x78, 0x00,		/* CE_REG_FR_SQS_TRH__A  */
-	0x00, 0x00,		/* CE_REG_FR_RIO_GAIN__A */
-	0x00, 0x02,		/* CE_REG_FR_BYPASS__A   */
-	0x0D, 0x00,		/* CE_REG_FR_PM_SET__A   */
-	0x07, 0x00,		/* CE_REG_FR_ERR_SH__A   */
-	0x04, 0x00,		/* CE_REG_FR_MAN_SH__A   */
-	0x06, 0x00,		/* CE_REG_FR_TAP_SH__A   */
-
-	END_OF_TABLE
-};
-
-u8 DRXD_InitFEA2_1[] = {
-	WRBLOCK(FE_AD_REG_PD__A, 3),
-	0x00, 0x00,		/* FE_AD_REG_PD__A          */
-	0x01, 0x00,		/* FE_AD_REG_INVEXT__A      */
-	0x00, 0x00,		/* FE_AD_REG_CLKNEG__A      */
-
-	WRBLOCK(FE_AG_REG_DCE_AUR_CNT__A, 2),
-	0x10, 0x00,		/* FE_AG_REG_DCE_AUR_CNT__A */
-	0x10, 0x00,		/* FE_AG_REG_DCE_RUR_CNT__A */
-
-	WRBLOCK(FE_AG_REG_ACE_AUR_CNT__A, 2),
-	0x0E, 0x00,		/* FE_AG_REG_ACE_AUR_CNT__A */
-	0x00, 0x00,		/* FE_AG_REG_ACE_RUR_CNT__A */
-
-	WRBLOCK(FE_AG_REG_EGC_FLA_RGN__A, 5),
-	0x04, 0x00,		/* FE_AG_REG_EGC_FLA_RGN__A */
-	0x1F, 0x00,		/* FE_AG_REG_EGC_SLO_RGN__A */
-	0x00, 0x00,		/* FE_AG_REG_EGC_JMP_PSN__A */
-	0x00, 0x00,		/* FE_AG_REG_EGC_FLA_INC__A */
-	0x00, 0x00,		/* FE_AG_REG_EGC_FLA_DEC__A */
-
-	WRBLOCK(FE_AG_REG_GC1_AGC_MAX__A, 2),
-	0xFF, 0x01,		/* FE_AG_REG_GC1_AGC_MAX__A */
-	0x00, 0xFE,		/* FE_AG_REG_GC1_AGC_MIN__A */
-
-	WRBLOCK(FE_AG_REG_IND_WIN__A, 29),
-	0x00, 0x00,		/* FE_AG_REG_IND_WIN__A     */
-	0x05, 0x00,		/* FE_AG_REG_IND_THD_LOL__A */
-	0x0F, 0x00,		/* FE_AG_REG_IND_THD_HIL__A */
-	0x00, 0x00,		/* FE_AG_REG_IND_DEL__A     don't care */
-	0x1E, 0x00,		/* FE_AG_REG_IND_PD1_WRI__A */
-	0x0C, 0x00,		/* FE_AG_REG_PDA_AUR_CNT__A */
-	0x00, 0x00,		/* FE_AG_REG_PDA_RUR_CNT__A */
-	0x00, 0x00,		/* FE_AG_REG_PDA_AVE_DAT__A don't care  */
-	0x00, 0x00,		/* FE_AG_REG_PDC_RUR_CNT__A */
-	0x01, 0x00,		/* FE_AG_REG_PDC_SET_LVL__A */
-	0x02, 0x00,		/* FE_AG_REG_PDC_FLA_RGN__A */
-	0x00, 0x00,		/* FE_AG_REG_PDC_JMP_PSN__A don't care  */
-	0xFF, 0xFF,		/* FE_AG_REG_PDC_FLA_STP__A */
-	0xFF, 0xFF,		/* FE_AG_REG_PDC_SLO_STP__A */
-	0x00, 0x1F,		/* FE_AG_REG_PDC_PD2_WRI__A don't care  */
-	0x00, 0x00,		/* FE_AG_REG_PDC_MAP_DAT__A don't care  */
-	0x02, 0x00,		/* FE_AG_REG_PDC_MAX__A     */
-	0x0C, 0x00,		/* FE_AG_REG_TGA_AUR_CNT__A */
-	0x00, 0x00,		/* FE_AG_REG_TGA_RUR_CNT__A */
-	0x00, 0x00,		/* FE_AG_REG_TGA_AVE_DAT__A don't care  */
-	0x00, 0x00,		/* FE_AG_REG_TGC_RUR_CNT__A */
-	0x22, 0x00,		/* FE_AG_REG_TGC_SET_LVL__A */
-	0x15, 0x00,		/* FE_AG_REG_TGC_FLA_RGN__A */
-	0x00, 0x00,		/* FE_AG_REG_TGC_JMP_PSN__A don't care  */
-	0x01, 0x00,		/* FE_AG_REG_TGC_FLA_STP__A */
-	0x0A, 0x00,		/* FE_AG_REG_TGC_SLO_STP__A */
-	0x00, 0x00,		/* FE_AG_REG_TGC_MAP_DAT__A don't care  */
-	0x10, 0x00,		/* FE_AG_REG_FGA_AUR_CNT__A */
-	0x10, 0x00,		/* FE_AG_REG_FGA_RUR_CNT__A */
-
-	WRBLOCK(FE_AG_REG_BGC_FGC_WRI__A, 2),
-	0x00, 0x00,		/* FE_AG_REG_BGC_FGC_WRI__A */
-	0x00, 0x00,		/* FE_AG_REG_BGC_CGC_WRI__A */
-
-	WRBLOCK(FE_FD_REG_SCL__A, 3),
-	0x05, 0x00,		/* FE_FD_REG_SCL__A         */
-	0x03, 0x00,		/* FE_FD_REG_MAX_LEV__A     */
-	0x05, 0x00,		/* FE_FD_REG_NR__A          */
-
-	WRBLOCK(FE_CF_REG_SCL__A, 5),
-	0x16, 0x00,		/* FE_CF_REG_SCL__A         */
-	0x04, 0x00,		/* FE_CF_REG_MAX_LEV__A     */
-	0x06, 0x00,		/* FE_CF_REG_NR__A          */
-	0x00, 0x00,		/* FE_CF_REG_IMP_VAL__A     */
-	0x01, 0x00,		/* FE_CF_REG_MEAS_VAL__A    */
-
-	WRBLOCK(FE_CU_REG_FRM_CNT_RST__A, 2),
-	0x00, 0x08,		/* FE_CU_REG_FRM_CNT_RST__A */
-	0x00, 0x00,		/* FE_CU_REG_FRM_CNT_STR__A */
-
-	END_OF_TABLE
-};
-
-   /* with PGA */
-/*   WR16COND( DRXD_WITH_PGA, FE_AG_REG_AG_PGA_MODE__A   , 0x0004), */
-   /* without PGA */
-/*   WR16COND( DRXD_WITHOUT_PGA, FE_AG_REG_AG_PGA_MODE__A   , 0x0001), */
-/*   WR16(FE_AG_REG_AG_AGC_SIO__A,  (extAttr -> FeAgRegAgAgcSio), 0x0000 );*/
-/*   WR16(FE_AG_REG_AG_PWD__A        ,(extAttr -> FeAgRegAgPwd), 0x0000 );*/
-
-u8 DRXD_InitFEA2_2[] = {
-	WR16(FE_AG_REG_CDR_RUR_CNT__A, 0x0010),
-	WR16(FE_AG_REG_FGM_WRI__A, 48),
-	/* Activate measurement, activate scale */
-	WR16(FE_FD_REG_MEAS_VAL__A, 0x0001),
-
-	WR16(FE_CU_REG_COMM_EXEC__A, 0x0001),
-	WR16(FE_CF_REG_COMM_EXEC__A, 0x0001),
-	WR16(FE_IF_REG_COMM_EXEC__A, 0x0001),
-	WR16(FE_FD_REG_COMM_EXEC__A, 0x0001),
-	WR16(FE_FS_REG_COMM_EXEC__A, 0x0001),
-	WR16(FE_AD_REG_COMM_EXEC__A, 0x0001),
-	WR16(FE_AG_REG_COMM_EXEC__A, 0x0001),
-	WR16(FE_AG_REG_AG_MODE_LOP__A, 0x895E),
-
-	END_OF_TABLE
-};
-
-u8 DRXD_InitFEB1_1[] = {
-	WR16(B_FE_AD_REG_PD__A, 0x0000),
-	WR16(B_FE_AD_REG_CLKNEG__A, 0x0000),
-	WR16(B_FE_AG_REG_BGC_FGC_WRI__A, 0x0000),
-	WR16(B_FE_AG_REG_BGC_CGC_WRI__A, 0x0000),
-	WR16(B_FE_AG_REG_AG_MODE_LOP__A, 0x000a),
-	WR16(B_FE_AG_REG_IND_PD1_WRI__A, 35),
-	WR16(B_FE_AG_REG_IND_WIN__A, 0),
-	WR16(B_FE_AG_REG_IND_THD_LOL__A, 8),
-	WR16(B_FE_AG_REG_IND_THD_HIL__A, 8),
-	WR16(B_FE_CF_REG_IMP_VAL__A, 1),
-	WR16(B_FE_AG_REG_EGC_FLA_RGN__A, 7),
-	END_OF_TABLE
-};
-
-	/* with PGA */
-/*      WR16(B_FE_AG_REG_AG_PGA_MODE__A   , 0x0000, 0x0000); */
-       /* without PGA */
-/*      WR16(B_FE_AG_REG_AG_PGA_MODE__A   ,
-	     B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN, 0x0000);*/
-									     /*   WR16(B_FE_AG_REG_AG_AGC_SIO__A,(extAttr -> FeAgRegAgAgcSio), 0x0000 );*//*added HS 23-05-2005 */
-/*   WR16(B_FE_AG_REG_AG_PWD__A    ,(extAttr -> FeAgRegAgPwd), 0x0000 );*/
-
-u8 DRXD_InitFEB1_2[] = {
-	WR16(B_FE_COMM_EXEC__A, 0x0001),
-
-	/* RF-AGC setup */
-	WR16(B_FE_AG_REG_PDA_AUR_CNT__A, 0x0C),
-	WR16(B_FE_AG_REG_PDC_SET_LVL__A, 0x01),
-	WR16(B_FE_AG_REG_PDC_FLA_RGN__A, 0x02),
-	WR16(B_FE_AG_REG_PDC_FLA_STP__A, 0xFFFF),
-	WR16(B_FE_AG_REG_PDC_SLO_STP__A, 0xFFFF),
-	WR16(B_FE_AG_REG_PDC_MAX__A, 0x02),
-	WR16(B_FE_AG_REG_TGA_AUR_CNT__A, 0x0C),
-	WR16(B_FE_AG_REG_TGC_SET_LVL__A, 0x22),
-	WR16(B_FE_AG_REG_TGC_FLA_RGN__A, 0x15),
-	WR16(B_FE_AG_REG_TGC_FLA_STP__A, 0x01),
-	WR16(B_FE_AG_REG_TGC_SLO_STP__A, 0x0A),
-
-	WR16(B_FE_CU_REG_DIV_NFC_CLP__A, 0),
-	WR16(B_FE_CU_REG_CTR_NFC_OCR__A, 25000),
-	WR16(B_FE_CU_REG_CTR_NFC_ICR__A, 1),
-	END_OF_TABLE
-};
-
-u8 DRXD_InitCPA2[] = {
-	WRBLOCK(CP_REG_BR_SPL_OFFSET__A, 2),
-	0x07, 0x00,		/* CP_REG_BR_SPL_OFFSET__A  */
-	0x0A, 0x00,		/* CP_REG_BR_STR_DEL__A     */
-
-	WRBLOCK(CP_REG_RT_ANG_INC0__A, 4),
-	0x00, 0x00,		/* CP_REG_RT_ANG_INC0__A    */
-	0x00, 0x00,		/* CP_REG_RT_ANG_INC1__A    */
-	0x03, 0x00,		/* CP_REG_RT_DETECT_ENA__A  */
-	0x03, 0x00,		/* CP_REG_RT_DETECT_TRH__A  */
-
-	WRBLOCK(CP_REG_AC_NEXP_OFFS__A, 5),
-	0x32, 0x00,		/* CP_REG_AC_NEXP_OFFS__A   */
-	0x62, 0x00,		/* CP_REG_AC_AVER_POW__A    */
-	0x82, 0x00,		/* CP_REG_AC_MAX_POW__A     */
-	0x26, 0x00,		/* CP_REG_AC_WEIGHT_MAN__A  */
-	0x0F, 0x00,		/* CP_REG_AC_WEIGHT_EXP__A  */
-
-	WRBLOCK(CP_REG_AC_AMP_MODE__A, 2),
-	0x02, 0x00,		/* CP_REG_AC_AMP_MODE__A    */
-	0x01, 0x00,		/* CP_REG_AC_AMP_FIX__A     */
-
-	WR16(CP_REG_INTERVAL__A, 0x0005),
-	WR16(CP_REG_RT_EXP_MARG__A, 0x0004),
-	WR16(CP_REG_AC_ANG_MODE__A, 0x0003),
-
-	WR16(CP_REG_COMM_EXEC__A, 0x0001),
-	END_OF_TABLE
-};
-
-u8 DRXD_InitCPB1[] = {
-	WR16(B_CP_REG_BR_SPL_OFFSET__A, 0x0008),
-	WR16(B_CP_COMM_EXEC__A, 0x0001),
-	END_OF_TABLE
-};
-
-u8 DRXD_InitCEA2[] = {
-	WRBLOCK(CE_REG_AVG_POW__A, 4),
-	0x62, 0x00,		/* CE_REG_AVG_POW__A        */
-	0x78, 0x00,		/* CE_REG_MAX_POW__A        */
-	0x62, 0x00,		/* CE_REG_ATT__A            */
-	0x17, 0x00,		/* CE_REG_NRED__A           */
-
-	WRBLOCK(CE_REG_NE_ERR_SELECT__A, 2),
-	0x07, 0x00,		/* CE_REG_NE_ERR_SELECT__A  */
-	0xEB, 0xFF,		/* CE_REG_NE_TD_CAL__A      */
-
-	WRBLOCK(CE_REG_NE_MIXAVG__A, 2),
-	0x06, 0x00,		/* CE_REG_NE_MIXAVG__A      */
-	0x00, 0x00,		/* CE_REG_NE_NUPD_OFS__A    */
-
-	WRBLOCK(CE_REG_PE_NEXP_OFFS__A, 2),
-	0x00, 0x00,		/* CE_REG_PE_NEXP_OFFS__A   */
-	0x00, 0x00,		/* CE_REG_PE_TIMESHIFT__A   */
-
-	WRBLOCK(CE_REG_TP_A0_TAP_NEW__A, 3),
-	0x00, 0x01,		/* CE_REG_TP_A0_TAP_NEW__A       */
-	0x01, 0x00,		/* CE_REG_TP_A0_TAP_NEW_VALID__A */
-	0x0E, 0x00,		/* CE_REG_TP_A0_MU_LMS_STEP__A   */
-
-	WRBLOCK(CE_REG_TP_A1_TAP_NEW__A, 3),
-	0x00, 0x00,		/* CE_REG_TP_A1_TAP_NEW__A        */
-	0x01, 0x00,		/* CE_REG_TP_A1_TAP_NEW_VALID__A  */
-	0x0A, 0x00,		/* CE_REG_TP_A1_MU_LMS_STEP__A    */
-
-	WRBLOCK(CE_REG_FI_SHT_INCR__A, 2),
-	0x12, 0x00,		/* CE_REG_FI_SHT_INCR__A          */
-	0x0C, 0x00,		/* CE_REG_FI_EXP_NORM__A          */
-
-	WRBLOCK(CE_REG_IR_INPUTSEL__A, 3),
-	0x00, 0x00,		/* CE_REG_IR_INPUTSEL__A          */
-	0x00, 0x00,		/* CE_REG_IR_STARTPOS__A          */
-	0xFF, 0x00,		/* CE_REG_IR_NEXP_THRES__A        */
-
-	WR16(CE_REG_TI_NEXP_OFFS__A, 0x0000),
-
-	END_OF_TABLE
-};
-
-u8 DRXD_InitCEB1[] = {
-	WR16(B_CE_REG_TI_PHN_ENABLE__A, 0x0001),
-	WR16(B_CE_REG_FR_PM_SET__A, 0x000D),
-
-	END_OF_TABLE
-};
-
-u8 DRXD_InitEQA2[] = {
-	WRBLOCK(EQ_REG_OT_QNT_THRES0__A, 4),
-	0x1E, 0x00,		/* EQ_REG_OT_QNT_THRES0__A        */
-	0x1F, 0x00,		/* EQ_REG_OT_QNT_THRES1__A        */
-	0x06, 0x00,		/* EQ_REG_OT_CSI_STEP__A          */
-	0x02, 0x00,		/* EQ_REG_OT_CSI_OFFSET__A        */
-
-	WR16(EQ_REG_TD_REQ_SMB_CNT__A, 0x0200),
-	WR16(EQ_REG_IS_CLIP_EXP__A, 0x001F),
-	WR16(EQ_REG_SN_OFFSET__A, (u16) (-7)),
-	WR16(EQ_REG_RC_SEL_CAR__A, 0x0002),
-	WR16(EQ_REG_COMM_EXEC__A, 0x0001),
-	END_OF_TABLE
-};
-
-u8 DRXD_InitEQB1[] = {
-	WR16(B_EQ_REG_COMM_EXEC__A, 0x0001),
-	END_OF_TABLE
-};
-
-u8 DRXD_ResetECRAM[] = {
-	/* Reset packet sync bytes in EC_VD ram */
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000),
-
-	/* Reset packet sync bytes in EC_RS ram */
-	WR16(EC_RS_EC_RAM__A, 0x0000),
-	WR16(EC_RS_EC_RAM__A + 204, 0x0000),
-	END_OF_TABLE
-};
-
-u8 DRXD_InitECA2[] = {
-	WRBLOCK(EC_SB_REG_CSI_HI__A, 6),
-	0x1F, 0x00,		/* EC_SB_REG_CSI_HI__A            */
-	0x1E, 0x00,		/* EC_SB_REG_CSI_LO__A            */
-	0x01, 0x00,		/* EC_SB_REG_SMB_TGL__A           */
-	0x7F, 0x00,		/* EC_SB_REG_SNR_HI__A            */
-	0x7F, 0x00,		/* EC_SB_REG_SNR_MID__A           */
-	0x7F, 0x00,		/* EC_SB_REG_SNR_LO__A            */
-
-	WRBLOCK(EC_RS_REG_REQ_PCK_CNT__A, 2),
-	0x00, 0x10,		/* EC_RS_REG_REQ_PCK_CNT__A       */
-	DATA16(EC_RS_REG_VAL_PCK),	/* EC_RS_REG_VAL__A               */
-
-	WRBLOCK(EC_OC_REG_TMD_TOP_MODE__A, 5),
-	0x03, 0x00,		/* EC_OC_REG_TMD_TOP_MODE__A      */
-	0xF4, 0x01,		/* EC_OC_REG_TMD_TOP_CNT__A       */
-	0xC0, 0x03,		/* EC_OC_REG_TMD_HIL_MAR__A       */
-	0x40, 0x00,		/* EC_OC_REG_TMD_LOL_MAR__A       */
-	0x03, 0x00,		/* EC_OC_REG_TMD_CUR_CNT__A       */
-
-	WRBLOCK(EC_OC_REG_AVR_ASH_CNT__A, 2),
-	0x06, 0x00,		/* EC_OC_REG_AVR_ASH_CNT__A       */
-	0x02, 0x00,		/* EC_OC_REG_AVR_BSH_CNT__A       */
-
-	WRBLOCK(EC_OC_REG_RCN_MODE__A, 7),
-	0x07, 0x00,		/* EC_OC_REG_RCN_MODE__A          */
-	0x00, 0x00,		/* EC_OC_REG_RCN_CRA_LOP__A       */
-	0xc0, 0x00,		/* EC_OC_REG_RCN_CRA_HIP__A       */
-	0x00, 0x10,		/* EC_OC_REG_RCN_CST_LOP__A       */
-	0x00, 0x00,		/* EC_OC_REG_RCN_CST_HIP__A       */
-	0xFF, 0x01,		/* EC_OC_REG_RCN_SET_LVL__A       */
-	0x0D, 0x00,		/* EC_OC_REG_RCN_GAI_LVL__A       */
-
-	WRBLOCK(EC_OC_REG_RCN_CLP_LOP__A, 2),
-	0x00, 0x00,		/* EC_OC_REG_RCN_CLP_LOP__A       */
-	0xC0, 0x00,		/* EC_OC_REG_RCN_CLP_HIP__A       */
-
-	WR16(EC_SB_REG_CSI_OFS__A, 0x0001),
-	WR16(EC_VD_REG_FORCE__A, 0x0002),
-	WR16(EC_VD_REG_REQ_SMB_CNT__A, 0x0001),
-	WR16(EC_VD_REG_RLK_ENA__A, 0x0001),
-	WR16(EC_OD_REG_SYNC__A, 0x0664),
-	WR16(EC_OC_REG_OC_MON_SIO__A, 0x0000),
-	WR16(EC_OC_REG_SNC_ISC_LVL__A, 0x0D0C),
-	/* Output zero on monitorbus pads, power saving */
-	WR16(EC_OC_REG_OCR_MON_UOS__A,
-	     (EC_OC_REG_OCR_MON_UOS_DAT_0_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_1_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_2_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_3_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_4_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_5_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_6_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_7_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_8_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_9_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_VAL_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_CLK_ENABLE)),
-	WR16(EC_OC_REG_OCR_MON_WRI__A,
-	     EC_OC_REG_OCR_MON_WRI_INIT),
-
-/*   CHK_ERROR(ResetECRAM(demod)); */
-	/* Reset packet sync bytes in EC_VD ram */
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000),
-
-	/* Reset packet sync bytes in EC_RS ram */
-	WR16(EC_RS_EC_RAM__A, 0x0000),
-	WR16(EC_RS_EC_RAM__A + 204, 0x0000),
-
-	WR16(EC_SB_REG_COMM_EXEC__A, 0x0001),
-	WR16(EC_VD_REG_COMM_EXEC__A, 0x0001),
-	WR16(EC_OD_REG_COMM_EXEC__A, 0x0001),
-	WR16(EC_RS_REG_COMM_EXEC__A, 0x0001),
-	END_OF_TABLE
-};
-
-u8 DRXD_InitECB1[] = {
-	WR16(B_EC_SB_REG_CSI_OFS0__A, 0x0001),
-	WR16(B_EC_SB_REG_CSI_OFS1__A, 0x0001),
-	WR16(B_EC_SB_REG_CSI_OFS2__A, 0x0001),
-	WR16(B_EC_SB_REG_CSI_LO__A, 0x000c),
-	WR16(B_EC_SB_REG_CSI_HI__A, 0x0018),
-	WR16(B_EC_SB_REG_SNR_HI__A, 0x007f),
-	WR16(B_EC_SB_REG_SNR_MID__A, 0x007f),
-	WR16(B_EC_SB_REG_SNR_LO__A, 0x007f),
-
-	WR16(B_EC_OC_REG_DTO_CLKMODE__A, 0x0002),
-	WR16(B_EC_OC_REG_DTO_PER__A, 0x0006),
-	WR16(B_EC_OC_REG_DTO_BUR__A, 0x0001),
-	WR16(B_EC_OC_REG_RCR_CLKMODE__A, 0x0000),
-	WR16(B_EC_OC_REG_RCN_GAI_LVL__A, 0x000D),
-	WR16(B_EC_OC_REG_OC_MPG_SIO__A, 0x0000),
-
-	/* Needed because shadow registers do not have correct default value */
-	WR16(B_EC_OC_REG_RCN_CST_LOP__A, 0x1000),
-	WR16(B_EC_OC_REG_RCN_CST_HIP__A, 0x0000),
-	WR16(B_EC_OC_REG_RCN_CRA_LOP__A, 0x0000),
-	WR16(B_EC_OC_REG_RCN_CRA_HIP__A, 0x00C0),
-	WR16(B_EC_OC_REG_RCN_CLP_LOP__A, 0x0000),
-	WR16(B_EC_OC_REG_RCN_CLP_HIP__A, 0x00C0),
-	WR16(B_EC_OC_REG_DTO_INC_LOP__A, 0x0000),
-	WR16(B_EC_OC_REG_DTO_INC_HIP__A, 0x00C0),
-
-	WR16(B_EC_OD_REG_SYNC__A, 0x0664),
-	WR16(B_EC_RS_REG_REQ_PCK_CNT__A, 0x1000),
-
-/*   CHK_ERROR(ResetECRAM(demod)); */
-	/* Reset packet sync bytes in EC_VD ram */
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000),
-
-	/* Reset packet sync bytes in EC_RS ram */
-	WR16(EC_RS_EC_RAM__A, 0x0000),
-	WR16(EC_RS_EC_RAM__A + 204, 0x0000),
-
-	WR16(B_EC_SB_REG_COMM_EXEC__A, 0x0001),
-	WR16(B_EC_VD_REG_COMM_EXEC__A, 0x0001),
-	WR16(B_EC_OD_REG_COMM_EXEC__A, 0x0001),
-	WR16(B_EC_RS_REG_COMM_EXEC__A, 0x0001),
-	END_OF_TABLE
-};
-
-u8 DRXD_ResetECA2[] = {
-
-	WR16(EC_OC_REG_COMM_EXEC__A, 0x0000),
-	WR16(EC_OD_REG_COMM_EXEC__A, 0x0000),
-
-	WRBLOCK(EC_OC_REG_TMD_TOP_MODE__A, 5),
-	0x03, 0x00,		/* EC_OC_REG_TMD_TOP_MODE__A      */
-	0xF4, 0x01,		/* EC_OC_REG_TMD_TOP_CNT__A       */
-	0xC0, 0x03,		/* EC_OC_REG_TMD_HIL_MAR__A       */
-	0x40, 0x00,		/* EC_OC_REG_TMD_LOL_MAR__A       */
-	0x03, 0x00,		/* EC_OC_REG_TMD_CUR_CNT__A       */
-
-	WRBLOCK(EC_OC_REG_AVR_ASH_CNT__A, 2),
-	0x06, 0x00,		/* EC_OC_REG_AVR_ASH_CNT__A       */
-	0x02, 0x00,		/* EC_OC_REG_AVR_BSH_CNT__A       */
-
-	WRBLOCK(EC_OC_REG_RCN_MODE__A, 7),
-	0x07, 0x00,		/* EC_OC_REG_RCN_MODE__A          */
-	0x00, 0x00,		/* EC_OC_REG_RCN_CRA_LOP__A       */
-	0xc0, 0x00,		/* EC_OC_REG_RCN_CRA_HIP__A       */
-	0x00, 0x10,		/* EC_OC_REG_RCN_CST_LOP__A       */
-	0x00, 0x00,		/* EC_OC_REG_RCN_CST_HIP__A       */
-	0xFF, 0x01,		/* EC_OC_REG_RCN_SET_LVL__A       */
-	0x0D, 0x00,		/* EC_OC_REG_RCN_GAI_LVL__A       */
-
-	WRBLOCK(EC_OC_REG_RCN_CLP_LOP__A, 2),
-	0x00, 0x00,		/* EC_OC_REG_RCN_CLP_LOP__A       */
-	0xC0, 0x00,		/* EC_OC_REG_RCN_CLP_HIP__A       */
-
-	WR16(EC_OD_REG_SYNC__A, 0x0664),
-	WR16(EC_OC_REG_OC_MON_SIO__A, 0x0000),
-	WR16(EC_OC_REG_SNC_ISC_LVL__A, 0x0D0C),
-	/* Output zero on monitorbus pads, power saving */
-	WR16(EC_OC_REG_OCR_MON_UOS__A,
-	     (EC_OC_REG_OCR_MON_UOS_DAT_0_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_1_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_2_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_3_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_4_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_5_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_6_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_7_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_8_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_DAT_9_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_VAL_ENABLE |
-	      EC_OC_REG_OCR_MON_UOS_CLK_ENABLE)),
-	WR16(EC_OC_REG_OCR_MON_WRI__A,
-	     EC_OC_REG_OCR_MON_WRI_INIT),
-
-/*   CHK_ERROR(ResetECRAM(demod)); */
-	/* Reset packet sync bytes in EC_VD ram */
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000),
-	WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000),
-
-	/* Reset packet sync bytes in EC_RS ram */
-	WR16(EC_RS_EC_RAM__A, 0x0000),
-	WR16(EC_RS_EC_RAM__A + 204, 0x0000),
-
-	WR16(EC_OD_REG_COMM_EXEC__A, 0x0001),
-	END_OF_TABLE
-};
-
-u8 DRXD_InitSC[] = {
-	WR16(SC_COMM_EXEC__A, 0),
-	WR16(SC_COMM_STATE__A, 0),
-
-#ifdef COMPILE_FOR_QT
-	WR16(SC_RA_RAM_BE_OPT_DELAY__A, 0x100),
-#endif
-
-	/* SC is not started, this is done in SetChannels() */
-	END_OF_TABLE
-};
-
-/* Diversity settings */
-
-u8 DRXD_InitDiversityFront[] = {
-	/* Start demod ********* RF in , diversity out **************************** */
-	WR16(B_SC_RA_RAM_CONFIG__A, B_SC_RA_RAM_CONFIG_FR_ENABLE__M |
-	     B_SC_RA_RAM_CONFIG_FREQSCAN__M),
-
-	WR16(B_SC_RA_RAM_LC_ABS_2K__A, 0x7),
-	WR16(B_SC_RA_RAM_LC_ABS_8K__A, 0x7),
-	WR16(B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A, IRLEN_COARSE_8K),
-	WR16(B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A, 1 << (11 - IRLEN_COARSE_8K)),
-	WR16(B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A, 1 << (17 - IRLEN_COARSE_8K)),
-	WR16(B_SC_RA_RAM_IR_FINE_8K_LENGTH__A, IRLEN_FINE_8K),
-	WR16(B_SC_RA_RAM_IR_FINE_8K_FREQINC__A, 1 << (11 - IRLEN_FINE_8K)),
-	WR16(B_SC_RA_RAM_IR_FINE_8K_KAISINC__A, 1 << (17 - IRLEN_FINE_8K)),
-
-	WR16(B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A, IRLEN_COARSE_2K),
-	WR16(B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A, 1 << (11 - IRLEN_COARSE_2K)),
-	WR16(B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A, 1 << (17 - IRLEN_COARSE_2K)),
-	WR16(B_SC_RA_RAM_IR_FINE_2K_LENGTH__A, IRLEN_FINE_2K),
-	WR16(B_SC_RA_RAM_IR_FINE_2K_FREQINC__A, 1 << (11 - IRLEN_FINE_2K)),
-	WR16(B_SC_RA_RAM_IR_FINE_2K_KAISINC__A, 1 << (17 - IRLEN_FINE_2K)),
-
-	WR16(B_LC_RA_RAM_FILTER_CRMM_A__A, 7),
-	WR16(B_LC_RA_RAM_FILTER_CRMM_B__A, 4),
-	WR16(B_LC_RA_RAM_FILTER_SRMM_A__A, 7),
-	WR16(B_LC_RA_RAM_FILTER_SRMM_B__A, 4),
-	WR16(B_LC_RA_RAM_FILTER_SYM_SET__A, 500),
-
-	WR16(B_CC_REG_DIVERSITY__A, 0x0001),
-	WR16(B_EC_OC_REG_OC_MODE_HIP__A, 0x0010),
-	WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_PASS_B_CE |
-	     B_EQ_REG_RC_SEL_CAR_LOCAL_B_CE | B_EQ_REG_RC_SEL_CAR_MEAS_B_CE),
-
-	/*    0x2a ), *//* CE to PASS mux */
-
-	END_OF_TABLE
-};
-
-u8 DRXD_InitDiversityEnd[] = {
-	/* End demod *********** combining RF in and diversity in, MPEG TS out **** */
-	/* disable near/far; switch on timing slave mode */
-	WR16(B_SC_RA_RAM_CONFIG__A, B_SC_RA_RAM_CONFIG_FR_ENABLE__M |
-	     B_SC_RA_RAM_CONFIG_FREQSCAN__M |
-	     B_SC_RA_RAM_CONFIG_DIV_ECHO_ENABLE__M |
-	     B_SC_RA_RAM_CONFIG_SLAVE__M |
-	     B_SC_RA_RAM_CONFIG_DIV_BLANK_ENABLE__M
-/* MV from CtrlDiversity */
-	    ),
-#ifdef DRXDDIV_SRMM_SLAVING
-	WR16(SC_RA_RAM_LC_ABS_2K__A, 0x3c7),
-	WR16(SC_RA_RAM_LC_ABS_8K__A, 0x3c7),
-#else
-	WR16(SC_RA_RAM_LC_ABS_2K__A, 0x7),
-	WR16(SC_RA_RAM_LC_ABS_8K__A, 0x7),
-#endif
-
-	WR16(B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A, IRLEN_COARSE_8K),
-	WR16(B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A, 1 << (11 - IRLEN_COARSE_8K)),
-	WR16(B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A, 1 << (17 - IRLEN_COARSE_8K)),
-	WR16(B_SC_RA_RAM_IR_FINE_8K_LENGTH__A, IRLEN_FINE_8K),
-	WR16(B_SC_RA_RAM_IR_FINE_8K_FREQINC__A, 1 << (11 - IRLEN_FINE_8K)),
-	WR16(B_SC_RA_RAM_IR_FINE_8K_KAISINC__A, 1 << (17 - IRLEN_FINE_8K)),
-
-	WR16(B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A, IRLEN_COARSE_2K),
-	WR16(B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A, 1 << (11 - IRLEN_COARSE_2K)),
-	WR16(B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A, 1 << (17 - IRLEN_COARSE_2K)),
-	WR16(B_SC_RA_RAM_IR_FINE_2K_LENGTH__A, IRLEN_FINE_2K),
-	WR16(B_SC_RA_RAM_IR_FINE_2K_FREQINC__A, 1 << (11 - IRLEN_FINE_2K)),
-	WR16(B_SC_RA_RAM_IR_FINE_2K_KAISINC__A, 1 << (17 - IRLEN_FINE_2K)),
-
-	WR16(B_LC_RA_RAM_FILTER_CRMM_A__A, 7),
-	WR16(B_LC_RA_RAM_FILTER_CRMM_B__A, 4),
-	WR16(B_LC_RA_RAM_FILTER_SRMM_A__A, 7),
-	WR16(B_LC_RA_RAM_FILTER_SRMM_B__A, 4),
-	WR16(B_LC_RA_RAM_FILTER_SYM_SET__A, 500),
-
-	WR16(B_CC_REG_DIVERSITY__A, 0x0001),
-	END_OF_TABLE
-};
-
-u8 DRXD_DisableDiversity[] = {
-	WR16(B_SC_RA_RAM_LC_ABS_2K__A, B_SC_RA_RAM_LC_ABS_2K__PRE),
-	WR16(B_SC_RA_RAM_LC_ABS_8K__A, B_SC_RA_RAM_LC_ABS_8K__PRE),
-	WR16(B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A,
-	     B_SC_RA_RAM_IR_COARSE_8K_LENGTH__PRE),
-	WR16(B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A,
-	     B_SC_RA_RAM_IR_COARSE_8K_FREQINC__PRE),
-	WR16(B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A,
-	     B_SC_RA_RAM_IR_COARSE_8K_KAISINC__PRE),
-	WR16(B_SC_RA_RAM_IR_FINE_8K_LENGTH__A,
-	     B_SC_RA_RAM_IR_FINE_8K_LENGTH__PRE),
-	WR16(B_SC_RA_RAM_IR_FINE_8K_FREQINC__A,
-	     B_SC_RA_RAM_IR_FINE_8K_FREQINC__PRE),
-	WR16(B_SC_RA_RAM_IR_FINE_8K_KAISINC__A,
-	     B_SC_RA_RAM_IR_FINE_8K_KAISINC__PRE),
-
-	WR16(B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A,
-	     B_SC_RA_RAM_IR_COARSE_2K_LENGTH__PRE),
-	WR16(B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A,
-	     B_SC_RA_RAM_IR_COARSE_2K_FREQINC__PRE),
-	WR16(B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A,
-	     B_SC_RA_RAM_IR_COARSE_2K_KAISINC__PRE),
-	WR16(B_SC_RA_RAM_IR_FINE_2K_LENGTH__A,
-	     B_SC_RA_RAM_IR_FINE_2K_LENGTH__PRE),
-	WR16(B_SC_RA_RAM_IR_FINE_2K_FREQINC__A,
-	     B_SC_RA_RAM_IR_FINE_2K_FREQINC__PRE),
-	WR16(B_SC_RA_RAM_IR_FINE_2K_KAISINC__A,
-	     B_SC_RA_RAM_IR_FINE_2K_KAISINC__PRE),
-
-	WR16(B_LC_RA_RAM_FILTER_CRMM_A__A, B_LC_RA_RAM_FILTER_CRMM_A__PRE),
-	WR16(B_LC_RA_RAM_FILTER_CRMM_B__A, B_LC_RA_RAM_FILTER_CRMM_B__PRE),
-	WR16(B_LC_RA_RAM_FILTER_SRMM_A__A, B_LC_RA_RAM_FILTER_SRMM_A__PRE),
-	WR16(B_LC_RA_RAM_FILTER_SRMM_B__A, B_LC_RA_RAM_FILTER_SRMM_B__PRE),
-	WR16(B_LC_RA_RAM_FILTER_SYM_SET__A, B_LC_RA_RAM_FILTER_SYM_SET__PRE),
-
-	WR16(B_CC_REG_DIVERSITY__A, 0x0000),
-	WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_INIT),	/* combining disabled */
-
-	END_OF_TABLE
-};
-
-u8 DRXD_StartDiversityFront[] = {
-	/* Start demod, RF in and diversity out, no combining */
-	WR16(B_FE_CF_REG_IMP_VAL__A, 0x0),
-	WR16(B_FE_AD_REG_FDB_IN__A, 0x0),
-	WR16(B_FE_AD_REG_INVEXT__A, 0x0),
-	WR16(B_EQ_REG_COMM_MB__A, 0x12),	/* EQ to MB out */
-	WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_PASS_B_CE |	/* CE to PASS mux */
-	     B_EQ_REG_RC_SEL_CAR_LOCAL_B_CE | B_EQ_REG_RC_SEL_CAR_MEAS_B_CE),
-
-	WR16(SC_RA_RAM_ECHO_SHIFT_LIM__A, 2),
-
-	END_OF_TABLE
-};
-
-u8 DRXD_StartDiversityEnd[] = {
-	/* End demod, combining RF in and diversity in, MPEG TS out */
-	WR16(B_FE_CF_REG_IMP_VAL__A, 0x0),	/* disable impulse noise cruncher */
-	WR16(B_FE_AD_REG_INVEXT__A, 0x0),	/* clock inversion (for sohard board) */
-	WR16(B_CP_REG_BR_STR_DEL__A, 10),	/* apperently no mb delay matching is best */
-
-	WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_DIV_ON |	/* org = 0x81 combining enabled */
-	     B_EQ_REG_RC_SEL_CAR_MEAS_A_CC |
-	     B_EQ_REG_RC_SEL_CAR_PASS_A_CC | B_EQ_REG_RC_SEL_CAR_LOCAL_A_CC),
-
-	END_OF_TABLE
-};
-
-u8 DRXD_DiversityDelay8MHZ[] = {
-	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_32__A, 1150 - 50),
-	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_16__A, 1100 - 50),
-	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_8__A, 1000 - 50),
-	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_4__A, 800 - 50),
-	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_32__A, 5420 - 50),
-	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_16__A, 5200 - 50),
-	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_8__A, 4800 - 50),
-	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_4__A, 4000 - 50),
-	END_OF_TABLE
-};
-
-u8 DRXD_DiversityDelay6MHZ[] =	/* also used ok for 7 MHz */
-{
-	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_32__A, 1100 - 50),
-	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_16__A, 1000 - 50),
-	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_8__A, 900 - 50),
-	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_4__A, 600 - 50),
-	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_32__A, 5300 - 50),
-	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_16__A, 5000 - 50),
-	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_8__A, 4500 - 50),
-	WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_4__A, 3500 - 50),
-	END_OF_TABLE
-};
diff --git a/drivers/media/dvb/frontends/drxd_firm.h b/drivers/media/dvb/frontends/drxd_firm.h
deleted file mode 100644
index 41597e8..0000000
--- a/drivers/media/dvb/frontends/drxd_firm.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * drxd_firm.h
- *
- * Copyright (C) 2006-2007 Micronas
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#ifndef _DRXD_FIRM_H_
-#define _DRXD_FIRM_H_
-
-#include <linux/types.h>
-#include "drxd_map_firm.h"
-
-#define VERSION_MAJOR 1
-#define VERSION_MINOR 4
-#define VERSION_PATCH 23
-
-#define HI_TR_FUNC_ADDR HI_IF_RAM_USR_BEGIN__A
-
-#define DRXD_MAX_RETRIES (1000)
-#define HI_I2C_DELAY     84
-#define HI_I2C_BRIDGE_DELAY   750
-
-#define EQ_TD_TPS_PWR_UNKNOWN          0x00C0	/* Unknown configurations */
-#define EQ_TD_TPS_PWR_QPSK             0x016a
-#define EQ_TD_TPS_PWR_QAM16_ALPHAN     0x0195
-#define EQ_TD_TPS_PWR_QAM16_ALPHA1     0x0195
-#define EQ_TD_TPS_PWR_QAM16_ALPHA2     0x011E
-#define EQ_TD_TPS_PWR_QAM16_ALPHA4     0x01CE
-#define EQ_TD_TPS_PWR_QAM64_ALPHAN     0x019F
-#define EQ_TD_TPS_PWR_QAM64_ALPHA1     0x019F
-#define EQ_TD_TPS_PWR_QAM64_ALPHA2     0x00F8
-#define EQ_TD_TPS_PWR_QAM64_ALPHA4     0x014D
-
-#define DRXD_DEF_AG_PWD_CONSUMER 0x000E
-#define DRXD_DEF_AG_PWD_PRO 0x0000
-#define DRXD_DEF_AG_AGC_SIO 0x0000
-
-#define DRXD_FE_CTRL_MAX 1023
-
-#define DRXD_OSCDEV_DO_SCAN  (16)
-
-#define DRXD_OSCDEV_DONT_SCAN  (0)
-
-#define DRXD_OSCDEV_STEP  (275)
-
-#define DRXD_SCAN_TIMEOUT    (650)
-
-#define DRXD_BANDWIDTH_8MHZ_IN_HZ  (0x8B8249L)
-#define DRXD_BANDWIDTH_7MHZ_IN_HZ  (0x7A1200L)
-#define DRXD_BANDWIDTH_6MHZ_IN_HZ  (0x68A1B6L)
-
-#define IRLEN_COARSE_8K       (10)
-#define IRLEN_FINE_8K         (10)
-#define IRLEN_COARSE_2K       (7)
-#define IRLEN_FINE_2K         (9)
-#define DIFF_INVALID          (511)
-#define DIFF_TARGET           (4)
-#define DIFF_MARGIN           (1)
-
-extern u8 DRXD_InitAtomicRead[];
-extern u8 DRXD_HiI2cPatch_1[];
-extern u8 DRXD_HiI2cPatch_3[];
-
-extern u8 DRXD_InitSC[];
-
-extern u8 DRXD_ResetCEFR[];
-extern u8 DRXD_InitFEA2_1[];
-extern u8 DRXD_InitFEA2_2[];
-extern u8 DRXD_InitCPA2[];
-extern u8 DRXD_InitCEA2[];
-extern u8 DRXD_InitEQA2[];
-extern u8 DRXD_InitECA2[];
-extern u8 DRXD_ResetECA2[];
-extern u8 DRXD_ResetECRAM[];
-
-extern u8 DRXD_A2_microcode[];
-extern u32 DRXD_A2_microcode_length;
-
-extern u8 DRXD_InitFEB1_1[];
-extern u8 DRXD_InitFEB1_2[];
-extern u8 DRXD_InitCPB1[];
-extern u8 DRXD_InitCEB1[];
-extern u8 DRXD_InitEQB1[];
-extern u8 DRXD_InitECB1[];
-
-extern u8 DRXD_InitDiversityFront[];
-extern u8 DRXD_InitDiversityEnd[];
-extern u8 DRXD_DisableDiversity[];
-extern u8 DRXD_StartDiversityFront[];
-extern u8 DRXD_StartDiversityEnd[];
-
-extern u8 DRXD_DiversityDelay8MHZ[];
-extern u8 DRXD_DiversityDelay6MHZ[];
-
-extern u8 DRXD_B1_microcode[];
-extern u32 DRXD_B1_microcode_length;
-
-#endif
diff --git a/drivers/media/dvb/frontends/drxd_hard.c b/drivers/media/dvb/frontends/drxd_hard.c
deleted file mode 100644
index f380eb4..0000000
--- a/drivers/media/dvb/frontends/drxd_hard.c
+++ /dev/null
@@ -1,2992 +0,0 @@
-/*
- * drxd_hard.c: DVB-T Demodulator Micronas DRX3975D-A2,DRX397xD-B1
- *
- * Copyright (C) 2003-2007 Micronas
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/i2c.h>
-#include <asm/div64.h>
-
-#include "dvb_frontend.h"
-#include "drxd.h"
-#include "drxd_firm.h"
-
-#define DRX_FW_FILENAME_A2 "drxd-a2-1.1.fw"
-#define DRX_FW_FILENAME_B1 "drxd-b1-1.1.fw"
-
-#define CHUNK_SIZE 48
-
-#define DRX_I2C_RMW           0x10
-#define DRX_I2C_BROADCAST     0x20
-#define DRX_I2C_CLEARCRC      0x80
-#define DRX_I2C_SINGLE_MASTER 0xC0
-#define DRX_I2C_MODEFLAGS     0xC0
-#define DRX_I2C_FLAGS         0xF0
-
-#ifndef SIZEOF_ARRAY
-#define SIZEOF_ARRAY(array) (sizeof((array))/sizeof((array)[0]))
-#endif
-
-#define DEFAULT_LOCK_TIMEOUT    1100
-
-#define DRX_CHANNEL_AUTO 0
-#define DRX_CHANNEL_HIGH 1
-#define DRX_CHANNEL_LOW  2
-
-#define DRX_LOCK_MPEG  1
-#define DRX_LOCK_FEC   2
-#define DRX_LOCK_DEMOD 4
-
-/****************************************************************************/
-
-enum CSCDState {
-	CSCD_INIT = 0,
-	CSCD_SET,
-	CSCD_SAVED
-};
-
-enum CDrxdState {
-	DRXD_UNINITIALIZED = 0,
-	DRXD_STOPPED,
-	DRXD_STARTED
-};
-
-enum AGC_CTRL_MODE {
-	AGC_CTRL_AUTO = 0,
-	AGC_CTRL_USER,
-	AGC_CTRL_OFF
-};
-
-enum OperationMode {
-	OM_Default,
-	OM_DVBT_Diversity_Front,
-	OM_DVBT_Diversity_End
-};
-
-struct SCfgAgc {
-	enum AGC_CTRL_MODE ctrlMode;
-	u16 outputLevel;	/* range [0, ... , 1023], 1/n of fullscale range */
-	u16 settleLevel;	/* range [0, ... , 1023], 1/n of fullscale range */
-	u16 minOutputLevel;	/* range [0, ... , 1023], 1/n of fullscale range */
-	u16 maxOutputLevel;	/* range [0, ... , 1023], 1/n of fullscale range */
-	u16 speed;		/* range [0, ... , 1023], 1/n of fullscale range */
-
-	u16 R1;
-	u16 R2;
-	u16 R3;
-};
-
-struct SNoiseCal {
-	int cpOpt;
-	short cpNexpOfs;
-	short tdCal2k;
-	short tdCal8k;
-};
-
-enum app_env {
-	APPENV_STATIC = 0,
-	APPENV_PORTABLE = 1,
-	APPENV_MOBILE = 2
-};
-
-enum EIFFilter {
-	IFFILTER_SAW = 0,
-	IFFILTER_DISCRETE = 1
-};
-
-struct drxd_state {
-	struct dvb_frontend frontend;
-	struct dvb_frontend_ops ops;
-	struct dtv_frontend_properties props;
-
-	const struct firmware *fw;
-	struct device *dev;
-
-	struct i2c_adapter *i2c;
-	void *priv;
-	struct drxd_config config;
-
-	int i2c_access;
-	int init_done;
-	struct mutex mutex;
-
-	u8 chip_adr;
-	u16 hi_cfg_timing_div;
-	u16 hi_cfg_bridge_delay;
-	u16 hi_cfg_wakeup_key;
-	u16 hi_cfg_ctrl;
-
-	u16 intermediate_freq;
-	u16 osc_clock_freq;
-
-	enum CSCDState cscd_state;
-	enum CDrxdState drxd_state;
-
-	u16 sys_clock_freq;
-	s16 osc_clock_deviation;
-	u16 expected_sys_clock_freq;
-
-	u16 insert_rs_byte;
-	u16 enable_parallel;
-
-	int operation_mode;
-
-	struct SCfgAgc if_agc_cfg;
-	struct SCfgAgc rf_agc_cfg;
-
-	struct SNoiseCal noise_cal;
-
-	u32 fe_fs_add_incr;
-	u32 org_fe_fs_add_incr;
-	u16 current_fe_if_incr;
-
-	u16 m_FeAgRegAgPwd;
-	u16 m_FeAgRegAgAgcSio;
-
-	u16 m_EcOcRegOcModeLop;
-	u16 m_EcOcRegSncSncLvl;
-	u8 *m_InitAtomicRead;
-	u8 *m_HiI2cPatch;
-
-	u8 *m_ResetCEFR;
-	u8 *m_InitFE_1;
-	u8 *m_InitFE_2;
-	u8 *m_InitCP;
-	u8 *m_InitCE;
-	u8 *m_InitEQ;
-	u8 *m_InitSC;
-	u8 *m_InitEC;
-	u8 *m_ResetECRAM;
-	u8 *m_InitDiversityFront;
-	u8 *m_InitDiversityEnd;
-	u8 *m_DisableDiversity;
-	u8 *m_StartDiversityFront;
-	u8 *m_StartDiversityEnd;
-
-	u8 *m_DiversityDelay8MHZ;
-	u8 *m_DiversityDelay6MHZ;
-
-	u8 *microcode;
-	u32 microcode_length;
-
-	int type_A;
-	int PGA;
-	int diversity;
-	int tuner_mirrors;
-
-	enum app_env app_env_default;
-	enum app_env app_env_diversity;
-
-};
-
-/****************************************************************************/
-/* I2C **********************************************************************/
-/****************************************************************************/
-
-static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 * data, int len)
-{
-	struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len };
-
-	if (i2c_transfer(adap, &msg, 1) != 1)
-		return -1;
-	return 0;
-}
-
-static int i2c_read(struct i2c_adapter *adap,
-		    u8 adr, u8 *msg, int len, u8 *answ, int alen)
-{
-	struct i2c_msg msgs[2] = {
-		{
-			.addr = adr, .flags = 0,
-			.buf = msg, .len = len
-		}, {
-			.addr = adr, .flags = I2C_M_RD,
-			.buf = answ, .len = alen
-		}
-	};
-	if (i2c_transfer(adap, msgs, 2) != 2)
-		return -1;
-	return 0;
-}
-
-static inline u32 MulDiv32(u32 a, u32 b, u32 c)
-{
-	u64 tmp64;
-
-	tmp64 = (u64)a * (u64)b;
-	do_div(tmp64, c);
-
-	return (u32) tmp64;
-}
-
-static int Read16(struct drxd_state *state, u32 reg, u16 *data, u8 flags)
-{
-	u8 adr = state->config.demod_address;
-	u8 mm1[4] = { reg & 0xff, (reg >> 16) & 0xff,
-		flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff
-	};
-	u8 mm2[2];
-	if (i2c_read(state->i2c, adr, mm1, 4, mm2, 2) < 0)
-		return -1;
-	if (data)
-		*data = mm2[0] | (mm2[1] << 8);
-	return mm2[0] | (mm2[1] << 8);
-}
-
-static int Read32(struct drxd_state *state, u32 reg, u32 *data, u8 flags)
-{
-	u8 adr = state->config.demod_address;
-	u8 mm1[4] = { reg & 0xff, (reg >> 16) & 0xff,
-		flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff
-	};
-	u8 mm2[4];
-
-	if (i2c_read(state->i2c, adr, mm1, 4, mm2, 4) < 0)
-		return -1;
-	if (data)
-		*data =
-		    mm2[0] | (mm2[1] << 8) | (mm2[2] << 16) | (mm2[3] << 24);
-	return 0;
-}
-
-static int Write16(struct drxd_state *state, u32 reg, u16 data, u8 flags)
-{
-	u8 adr = state->config.demod_address;
-	u8 mm[6] = { reg & 0xff, (reg >> 16) & 0xff,
-		flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff,
-		data & 0xff, (data >> 8) & 0xff
-	};
-
-	if (i2c_write(state->i2c, adr, mm, 6) < 0)
-		return -1;
-	return 0;
-}
-
-static int Write32(struct drxd_state *state, u32 reg, u32 data, u8 flags)
-{
-	u8 adr = state->config.demod_address;
-	u8 mm[8] = { reg & 0xff, (reg >> 16) & 0xff,
-		flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff,
-		data & 0xff, (data >> 8) & 0xff,
-		(data >> 16) & 0xff, (data >> 24) & 0xff
-	};
-
-	if (i2c_write(state->i2c, adr, mm, 8) < 0)
-		return -1;
-	return 0;
-}
-
-static int write_chunk(struct drxd_state *state,
-		       u32 reg, u8 *data, u32 len, u8 flags)
-{
-	u8 adr = state->config.demod_address;
-	u8 mm[CHUNK_SIZE + 4] = { reg & 0xff, (reg >> 16) & 0xff,
-		flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff
-	};
-	int i;
-
-	for (i = 0; i < len; i++)
-		mm[4 + i] = data[i];
-	if (i2c_write(state->i2c, adr, mm, 4 + len) < 0) {
-		printk(KERN_ERR "error in write_chunk\n");
-		return -1;
-	}
-	return 0;
-}
-
-static int WriteBlock(struct drxd_state *state,
-		      u32 Address, u16 BlockSize, u8 *pBlock, u8 Flags)
-{
-	while (BlockSize > 0) {
-		u16 Chunk = BlockSize > CHUNK_SIZE ? CHUNK_SIZE : BlockSize;
-
-		if (write_chunk(state, Address, pBlock, Chunk, Flags) < 0)
-			return -1;
-		pBlock += Chunk;
-		Address += (Chunk >> 1);
-		BlockSize -= Chunk;
-	}
-	return 0;
-}
-
-static int WriteTable(struct drxd_state *state, u8 * pTable)
-{
-	int status = 0;
-
-	if (pTable == NULL)
-		return 0;
-
-	while (!status) {
-		u16 Length;
-		u32 Address = pTable[0] | (pTable[1] << 8) |
-		    (pTable[2] << 16) | (pTable[3] << 24);
-
-		if (Address == 0xFFFFFFFF)
-			break;
-		pTable += sizeof(u32);
-
-		Length = pTable[0] | (pTable[1] << 8);
-		pTable += sizeof(u16);
-		if (!Length)
-			break;
-		status = WriteBlock(state, Address, Length * 2, pTable, 0);
-		pTable += (Length * 2);
-	}
-	return status;
-}
-
-/****************************************************************************/
-/****************************************************************************/
-/****************************************************************************/
-
-static int ResetCEFR(struct drxd_state *state)
-{
-	return WriteTable(state, state->m_ResetCEFR);
-}
-
-static int InitCP(struct drxd_state *state)
-{
-	return WriteTable(state, state->m_InitCP);
-}
-
-static int InitCE(struct drxd_state *state)
-{
-	int status;
-	enum app_env AppEnv = state->app_env_default;
-
-	do {
-		status = WriteTable(state, state->m_InitCE);
-		if (status < 0)
-			break;
-
-		if (state->operation_mode == OM_DVBT_Diversity_Front ||
-		    state->operation_mode == OM_DVBT_Diversity_End) {
-			AppEnv = state->app_env_diversity;
-		}
-		if (AppEnv == APPENV_STATIC) {
-			status = Write16(state, CE_REG_TAPSET__A, 0x0000, 0);
-			if (status < 0)
-				break;
-		} else if (AppEnv == APPENV_PORTABLE) {
-			status = Write16(state, CE_REG_TAPSET__A, 0x0001, 0);
-			if (status < 0)
-				break;
-		} else if (AppEnv == APPENV_MOBILE && state->type_A) {
-			status = Write16(state, CE_REG_TAPSET__A, 0x0002, 0);
-			if (status < 0)
-				break;
-		} else if (AppEnv == APPENV_MOBILE && !state->type_A) {
-			status = Write16(state, CE_REG_TAPSET__A, 0x0006, 0);
-			if (status < 0)
-				break;
-		}
-
-		/* start ce */
-		status = Write16(state, B_CE_REG_COMM_EXEC__A, 0x0001, 0);
-		if (status < 0)
-			break;
-	} while (0);
-	return status;
-}
-
-static int StopOC(struct drxd_state *state)
-{
-	int status = 0;
-	u16 ocSyncLvl = 0;
-	u16 ocModeLop = state->m_EcOcRegOcModeLop;
-	u16 dtoIncLop = 0;
-	u16 dtoIncHip = 0;
-
-	do {
-		/* Store output configuration */
-		status = Read16(state, EC_OC_REG_SNC_ISC_LVL__A, &ocSyncLvl, 0);
-		if (status < 0)
-			break;
-		/* CHK_ERROR(Read16(EC_OC_REG_OC_MODE_LOP__A, &ocModeLop)); */
-		state->m_EcOcRegSncSncLvl = ocSyncLvl;
-		/* m_EcOcRegOcModeLop = ocModeLop; */
-
-		/* Flush FIFO (byte-boundary) at fixed rate */
-		status = Read16(state, EC_OC_REG_RCN_MAP_LOP__A, &dtoIncLop, 0);
-		if (status < 0)
-			break;
-		status = Read16(state, EC_OC_REG_RCN_MAP_HIP__A, &dtoIncHip, 0);
-		if (status < 0)
-			break;
-		status = Write16(state, EC_OC_REG_DTO_INC_LOP__A, dtoIncLop, 0);
-		if (status < 0)
-			break;
-		status = Write16(state, EC_OC_REG_DTO_INC_HIP__A, dtoIncHip, 0);
-		if (status < 0)
-			break;
-		ocModeLop &= ~(EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC__M);
-		ocModeLop |= EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC_STATIC;
-		status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, ocModeLop, 0);
-		if (status < 0)
-			break;
-		status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_HOLD, 0);
-		if (status < 0)
-			break;
-
-		msleep(1);
-		/* Output pins to '0' */
-		status = Write16(state, EC_OC_REG_OCR_MPG_UOS__A, EC_OC_REG_OCR_MPG_UOS__M, 0);
-		if (status < 0)
-			break;
-
-		/* Force the OC out of sync */
-		ocSyncLvl &= ~(EC_OC_REG_SNC_ISC_LVL_OSC__M);
-		status = Write16(state, EC_OC_REG_SNC_ISC_LVL__A, ocSyncLvl, 0);
-		if (status < 0)
-			break;
-		ocModeLop &= ~(EC_OC_REG_OC_MODE_LOP_PAR_ENA__M);
-		ocModeLop |= EC_OC_REG_OC_MODE_LOP_PAR_ENA_ENABLE;
-		ocModeLop |= 0x2;	/* Magically-out-of-sync */
-		status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, ocModeLop, 0);
-		if (status < 0)
-			break;
-		status = Write16(state, EC_OC_REG_COMM_INT_STA__A, 0x0, 0);
-		if (status < 0)
-			break;
-		status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_ACTIVE, 0);
-		if (status < 0)
-			break;
-	} while (0);
-
-	return status;
-}
-
-static int StartOC(struct drxd_state *state)
-{
-	int status = 0;
-
-	do {
-		/* Stop OC */
-		status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_HOLD, 0);
-		if (status < 0)
-			break;
-
-		/* Restore output configuration */
-		status = Write16(state, EC_OC_REG_SNC_ISC_LVL__A, state->m_EcOcRegSncSncLvl, 0);
-		if (status < 0)
-			break;
-		status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, state->m_EcOcRegOcModeLop, 0);
-		if (status < 0)
-			break;
-
-		/* Output pins active again */
-		status = Write16(state, EC_OC_REG_OCR_MPG_UOS__A, EC_OC_REG_OCR_MPG_UOS_INIT, 0);
-		if (status < 0)
-			break;
-
-		/* Start OC */
-		status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_ACTIVE, 0);
-		if (status < 0)
-			break;
-	} while (0);
-	return status;
-}
-
-static int InitEQ(struct drxd_state *state)
-{
-	return WriteTable(state, state->m_InitEQ);
-}
-
-static int InitEC(struct drxd_state *state)
-{
-	return WriteTable(state, state->m_InitEC);
-}
-
-static int InitSC(struct drxd_state *state)
-{
-	return WriteTable(state, state->m_InitSC);
-}
-
-static int InitAtomicRead(struct drxd_state *state)
-{
-	return WriteTable(state, state->m_InitAtomicRead);
-}
-
-static int CorrectSysClockDeviation(struct drxd_state *state);
-
-static int DRX_GetLockStatus(struct drxd_state *state, u32 * pLockStatus)
-{
-	u16 ScRaRamLock = 0;
-	const u16 mpeg_lock_mask = (SC_RA_RAM_LOCK_MPEG__M |
-				    SC_RA_RAM_LOCK_FEC__M |
-				    SC_RA_RAM_LOCK_DEMOD__M);
-	const u16 fec_lock_mask = (SC_RA_RAM_LOCK_FEC__M |
-				   SC_RA_RAM_LOCK_DEMOD__M);
-	const u16 demod_lock_mask = SC_RA_RAM_LOCK_DEMOD__M;
-
-	int status;
-
-	*pLockStatus = 0;
-
-	status = Read16(state, SC_RA_RAM_LOCK__A, &ScRaRamLock, 0x0000);
-	if (status < 0) {
-		printk(KERN_ERR "Can't read SC_RA_RAM_LOCK__A status = %08x\n", status);
-		return status;
-	}
-
-	if (state->drxd_state != DRXD_STARTED)
-		return 0;
-
-	if ((ScRaRamLock & mpeg_lock_mask) == mpeg_lock_mask) {
-		*pLockStatus |= DRX_LOCK_MPEG;
-		CorrectSysClockDeviation(state);
-	}
-
-	if ((ScRaRamLock & fec_lock_mask) == fec_lock_mask)
-		*pLockStatus |= DRX_LOCK_FEC;
-
-	if ((ScRaRamLock & demod_lock_mask) == demod_lock_mask)
-		*pLockStatus |= DRX_LOCK_DEMOD;
-	return 0;
-}
-
-/****************************************************************************/
-
-static int SetCfgIfAgc(struct drxd_state *state, struct SCfgAgc *cfg)
-{
-	int status;
-
-	if (cfg->outputLevel > DRXD_FE_CTRL_MAX)
-		return -1;
-
-	if (cfg->ctrlMode == AGC_CTRL_USER) {
-		do {
-			u16 FeAgRegPm1AgcWri;
-			u16 FeAgRegAgModeLop;
-
-			status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &FeAgRegAgModeLop, 0);
-			if (status < 0)
-				break;
-			FeAgRegAgModeLop &= (~FE_AG_REG_AG_MODE_LOP_MODE_4__M);
-			FeAgRegAgModeLop |= FE_AG_REG_AG_MODE_LOP_MODE_4_STATIC;
-			status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, FeAgRegAgModeLop, 0);
-			if (status < 0)
-				break;
-
-			FeAgRegPm1AgcWri = (u16) (cfg->outputLevel &
-						  FE_AG_REG_PM1_AGC_WRI__M);
-			status = Write16(state, FE_AG_REG_PM1_AGC_WRI__A, FeAgRegPm1AgcWri, 0);
-			if (status < 0)
-				break;
-		} while (0);
-	} else if (cfg->ctrlMode == AGC_CTRL_AUTO) {
-		if (((cfg->maxOutputLevel) < (cfg->minOutputLevel)) ||
-		    ((cfg->maxOutputLevel) > DRXD_FE_CTRL_MAX) ||
-		    ((cfg->speed) > DRXD_FE_CTRL_MAX) ||
-		    ((cfg->settleLevel) > DRXD_FE_CTRL_MAX)
-		    )
-			return -1;
-		do {
-			u16 FeAgRegAgModeLop;
-			u16 FeAgRegEgcSetLvl;
-			u16 slope, offset;
-
-			/* == Mode == */
-
-			status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &FeAgRegAgModeLop, 0);
-			if (status < 0)
-				break;
-			FeAgRegAgModeLop &= (~FE_AG_REG_AG_MODE_LOP_MODE_4__M);
-			FeAgRegAgModeLop |=
-			    FE_AG_REG_AG_MODE_LOP_MODE_4_DYNAMIC;
-			status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, FeAgRegAgModeLop, 0);
-			if (status < 0)
-				break;
-
-			/* == Settle level == */
-
-			FeAgRegEgcSetLvl = (u16) ((cfg->settleLevel >> 1) &
-						  FE_AG_REG_EGC_SET_LVL__M);
-			status = Write16(state, FE_AG_REG_EGC_SET_LVL__A, FeAgRegEgcSetLvl, 0);
-			if (status < 0)
-				break;
-
-			/* == Min/Max == */
-
-			slope = (u16) ((cfg->maxOutputLevel -
-					cfg->minOutputLevel) / 2);
-			offset = (u16) ((cfg->maxOutputLevel +
-					 cfg->minOutputLevel) / 2 - 511);
-
-			status = Write16(state, FE_AG_REG_GC1_AGC_RIC__A, slope, 0);
-			if (status < 0)
-				break;
-			status = Write16(state, FE_AG_REG_GC1_AGC_OFF__A, offset, 0);
-			if (status < 0)
-				break;
-
-			/* == Speed == */
-			{
-				const u16 maxRur = 8;
-				const u16 slowIncrDecLUT[] = { 3, 4, 4, 5, 6 };
-				const u16 fastIncrDecLUT[] = { 14, 15, 15, 16,
-					17, 18, 18, 19,
-					20, 21, 22, 23,
-					24, 26, 27, 28,
-					29, 31
-				};
-
-				u16 fineSteps = (DRXD_FE_CTRL_MAX + 1) /
-				    (maxRur + 1);
-				u16 fineSpeed = (u16) (cfg->speed -
-						       ((cfg->speed /
-							 fineSteps) *
-							fineSteps));
-				u16 invRurCount = (u16) (cfg->speed /
-							 fineSteps);
-				u16 rurCount;
-				if (invRurCount > maxRur) {
-					rurCount = 0;
-					fineSpeed += fineSteps;
-				} else {
-					rurCount = maxRur - invRurCount;
-				}
-
-				/*
-				   fastInc = default *
-				   (2^(fineSpeed/fineSteps))
-				   => range[default...2*default>
-				   slowInc = default *
-				   (2^(fineSpeed/fineSteps))
-				 */
-				{
-					u16 fastIncrDec =
-					    fastIncrDecLUT[fineSpeed /
-							   ((fineSteps /
-							     (14 + 1)) + 1)];
-					u16 slowIncrDec =
-					    slowIncrDecLUT[fineSpeed /
-							   (fineSteps /
-							    (3 + 1))];
-
-					status = Write16(state, FE_AG_REG_EGC_RUR_CNT__A, rurCount, 0);
-					if (status < 0)
-						break;
-					status = Write16(state, FE_AG_REG_EGC_FAS_INC__A, fastIncrDec, 0);
-					if (status < 0)
-						break;
-					status = Write16(state, FE_AG_REG_EGC_FAS_DEC__A, fastIncrDec, 0);
-					if (status < 0)
-						break;
-					status = Write16(state, FE_AG_REG_EGC_SLO_INC__A, slowIncrDec, 0);
-					if (status < 0)
-						break;
-					status = Write16(state, FE_AG_REG_EGC_SLO_DEC__A, slowIncrDec, 0);
-					if (status < 0)
-						break;
-				}
-			}
-		} while (0);
-
-	} else {
-		/* No OFF mode for IF control */
-		return -1;
-	}
-	return status;
-}
-
-static int SetCfgRfAgc(struct drxd_state *state, struct SCfgAgc *cfg)
-{
-	int status = 0;
-
-	if (cfg->outputLevel > DRXD_FE_CTRL_MAX)
-		return -1;
-
-	if (cfg->ctrlMode == AGC_CTRL_USER) {
-		do {
-			u16 AgModeLop = 0;
-			u16 level = (cfg->outputLevel);
-
-			if (level == DRXD_FE_CTRL_MAX)
-				level++;
-
-			status = Write16(state, FE_AG_REG_PM2_AGC_WRI__A, level, 0x0000);
-			if (status < 0)
-				break;
-
-			/*==== Mode ====*/
-
-			/* Powerdown PD2, WRI source */
-			state->m_FeAgRegAgPwd &= ~(FE_AG_REG_AG_PWD_PWD_PD2__M);
-			state->m_FeAgRegAgPwd |=
-			    FE_AG_REG_AG_PWD_PWD_PD2_DISABLE;
-			status = Write16(state, FE_AG_REG_AG_PWD__A, state->m_FeAgRegAgPwd, 0x0000);
-			if (status < 0)
-				break;
-
-			status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
-			if (status < 0)
-				break;
-			AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M |
-					FE_AG_REG_AG_MODE_LOP_MODE_E__M));
-			AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC |
-				      FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC);
-			status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
-			if (status < 0)
-				break;
-
-			/* enable AGC2 pin */
-			{
-				u16 FeAgRegAgAgcSio = 0;
-				status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000);
-				if (status < 0)
-					break;
-				FeAgRegAgAgcSio &=
-				    ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M);
-				FeAgRegAgAgcSio |=
-				    FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT;
-				status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000);
-				if (status < 0)
-					break;
-			}
-
-		} while (0);
-	} else if (cfg->ctrlMode == AGC_CTRL_AUTO) {
-		u16 AgModeLop = 0;
-
-		do {
-			u16 level;
-			/* Automatic control */
-			/* Powerup PD2, AGC2 as output, TGC source */
-			(state->m_FeAgRegAgPwd) &=
-			    ~(FE_AG_REG_AG_PWD_PWD_PD2__M);
-			(state->m_FeAgRegAgPwd) |=
-			    FE_AG_REG_AG_PWD_PWD_PD2_DISABLE;
-			status = Write16(state, FE_AG_REG_AG_PWD__A, (state->m_FeAgRegAgPwd), 0x0000);
-			if (status < 0)
-				break;
-
-			status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
-			if (status < 0)
-				break;
-			AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M |
-					FE_AG_REG_AG_MODE_LOP_MODE_E__M));
-			AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC |
-				      FE_AG_REG_AG_MODE_LOP_MODE_E_DYNAMIC);
-			status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
-			if (status < 0)
-				break;
-			/* Settle level */
-			level = (((cfg->settleLevel) >> 4) &
-				 FE_AG_REG_TGC_SET_LVL__M);
-			status = Write16(state, FE_AG_REG_TGC_SET_LVL__A, level, 0x0000);
-			if (status < 0)
-				break;
-
-			/* Min/max: don't care */
-
-			/* Speed: TODO */
-
-			/* enable AGC2 pin */
-			{
-				u16 FeAgRegAgAgcSio = 0;
-				status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000);
-				if (status < 0)
-					break;
-				FeAgRegAgAgcSio &=
-				    ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M);
-				FeAgRegAgAgcSio |=
-				    FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT;
-				status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000);
-				if (status < 0)
-					break;
-			}
-
-		} while (0);
-	} else {
-		u16 AgModeLop = 0;
-
-		do {
-			/* No RF AGC control */
-			/* Powerdown PD2, AGC2 as output, WRI source */
-			(state->m_FeAgRegAgPwd) &=
-			    ~(FE_AG_REG_AG_PWD_PWD_PD2__M);
-			(state->m_FeAgRegAgPwd) |=
-			    FE_AG_REG_AG_PWD_PWD_PD2_ENABLE;
-			status = Write16(state, FE_AG_REG_AG_PWD__A, (state->m_FeAgRegAgPwd), 0x0000);
-			if (status < 0)
-				break;
-
-			status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
-			if (status < 0)
-				break;
-			AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M |
-					FE_AG_REG_AG_MODE_LOP_MODE_E__M));
-			AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC |
-				      FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC);
-			status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
-			if (status < 0)
-				break;
-
-			/* set FeAgRegAgAgcSio AGC2 (RF) as input */
-			{
-				u16 FeAgRegAgAgcSio = 0;
-				status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000);
-				if (status < 0)
-					break;
-				FeAgRegAgAgcSio &=
-				    ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M);
-				FeAgRegAgAgcSio |=
-				    FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_INPUT;
-				status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000);
-				if (status < 0)
-					break;
-			}
-		} while (0);
-	}
-	return status;
-}
-
-static int ReadIFAgc(struct drxd_state *state, u32 * pValue)
-{
-	int status = 0;
-
-	*pValue = 0;
-	if (state->if_agc_cfg.ctrlMode != AGC_CTRL_OFF) {
-		u16 Value;
-		status = Read16(state, FE_AG_REG_GC1_AGC_DAT__A, &Value, 0);
-		Value &= FE_AG_REG_GC1_AGC_DAT__M;
-		if (status >= 0) {
-			/*           3.3V
-			   |
-			   R1
-			   |
-			   Vin - R3 - * -- Vout
-			   |
-			   R2
-			   |
-			   GND
-			 */
-			u32 R1 = state->if_agc_cfg.R1;
-			u32 R2 = state->if_agc_cfg.R2;
-			u32 R3 = state->if_agc_cfg.R3;
-
-			u32 Vmax, Rpar, Vmin, Vout;
-
-			if (R2 == 0 && (R1 == 0 || R3 == 0))
-				return 0;
-
-			Vmax = (3300 * R2) / (R1 + R2);
-			Rpar = (R2 * R3) / (R3 + R2);
-			Vmin = (3300 * Rpar) / (R1 + Rpar);
-			Vout = Vmin + ((Vmax - Vmin) * Value) / 1024;
-
-			*pValue = Vout;
-		}
-	}
-	return status;
-}
-
-static int load_firmware(struct drxd_state *state, const char *fw_name)
-{
-	const struct firmware *fw;
-
-	if (request_firmware(&fw, fw_name, state->dev) < 0) {
-		printk(KERN_ERR "drxd: firmware load failure [%s]\n", fw_name);
-		return -EIO;
-	}
-
-	state->microcode = kmemdup(fw->data, fw->size, GFP_KERNEL);
-	if (state->microcode == NULL) {
-		release_firmware(fw);
-		printk(KERN_ERR "drxd: firmware load failure: no memory\n");
-		return -ENOMEM;
-	}
-
-	state->microcode_length = fw->size;
-	release_firmware(fw);
-	return 0;
-}
-
-static int DownloadMicrocode(struct drxd_state *state,
-			     const u8 *pMCImage, u32 Length)
-{
-	u8 *pSrc;
-	u32 Address;
-	u16 nBlocks;
-	u16 BlockSize;
-	u32 offset = 0;
-	int i, status = 0;
-
-	pSrc = (u8 *) pMCImage;
-	/* We're not using Flags */
-	/* Flags = (pSrc[0] << 8) | pSrc[1]; */
-	pSrc += sizeof(u16);
-	offset += sizeof(u16);
-	nBlocks = (pSrc[0] << 8) | pSrc[1];
-	pSrc += sizeof(u16);
-	offset += sizeof(u16);
-
-	for (i = 0; i < nBlocks; i++) {
-		Address = (pSrc[0] << 24) | (pSrc[1] << 16) |
-		    (pSrc[2] << 8) | pSrc[3];
-		pSrc += sizeof(u32);
-		offset += sizeof(u32);
-
-		BlockSize = ((pSrc[0] << 8) | pSrc[1]) * sizeof(u16);
-		pSrc += sizeof(u16);
-		offset += sizeof(u16);
-
-		/* We're not using Flags */
-		/* u16 Flags = (pSrc[0] << 8) | pSrc[1]; */
-		pSrc += sizeof(u16);
-		offset += sizeof(u16);
-
-		/* We're not using BlockCRC */
-		/* u16 BlockCRC = (pSrc[0] << 8) | pSrc[1]; */
-		pSrc += sizeof(u16);
-		offset += sizeof(u16);
-
-		status = WriteBlock(state, Address, BlockSize,
-				    pSrc, DRX_I2C_CLEARCRC);
-		if (status < 0)
-			break;
-		pSrc += BlockSize;
-		offset += BlockSize;
-	}
-
-	return status;
-}
-
-static int HI_Command(struct drxd_state *state, u16 cmd, u16 * pResult)
-{
-	u32 nrRetries = 0;
-	u16 waitCmd;
-	int status;
-
-	status = Write16(state, HI_RA_RAM_SRV_CMD__A, cmd, 0);
-	if (status < 0)
-		return status;
-
-	do {
-		nrRetries += 1;
-		if (nrRetries > DRXD_MAX_RETRIES) {
-			status = -1;
-			break;
-		};
-		status = Read16(state, HI_RA_RAM_SRV_CMD__A, &waitCmd, 0);
-	} while (waitCmd != 0);
-
-	if (status >= 0)
-		status = Read16(state, HI_RA_RAM_SRV_RES__A, pResult, 0);
-	return status;
-}
-
-static int HI_CfgCommand(struct drxd_state *state)
-{
-	int status = 0;
-
-	mutex_lock(&state->mutex);
-	Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, HI_RA_RAM_SRV_RST_KEY_ACT, 0);
-	Write16(state, HI_RA_RAM_SRV_CFG_DIV__A, state->hi_cfg_timing_div, 0);
-	Write16(state, HI_RA_RAM_SRV_CFG_BDL__A, state->hi_cfg_bridge_delay, 0);
-	Write16(state, HI_RA_RAM_SRV_CFG_WUP__A, state->hi_cfg_wakeup_key, 0);
-	Write16(state, HI_RA_RAM_SRV_CFG_ACT__A, state->hi_cfg_ctrl, 0);
-
-	Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, HI_RA_RAM_SRV_RST_KEY_ACT, 0);
-
-	if ((state->hi_cfg_ctrl & HI_RA_RAM_SRV_CFG_ACT_PWD_EXE) ==
-	    HI_RA_RAM_SRV_CFG_ACT_PWD_EXE)
-		status = Write16(state, HI_RA_RAM_SRV_CMD__A,
-				 HI_RA_RAM_SRV_CMD_CONFIG, 0);
-	else
-		status = HI_Command(state, HI_RA_RAM_SRV_CMD_CONFIG, 0);
-	mutex_unlock(&state->mutex);
-	return status;
-}
-
-static int InitHI(struct drxd_state *state)
-{
-	state->hi_cfg_wakeup_key = (state->chip_adr);
-	/* port/bridge/power down ctrl */
-	state->hi_cfg_ctrl = HI_RA_RAM_SRV_CFG_ACT_SLV0_ON;
-	return HI_CfgCommand(state);
-}
-
-static int HI_ResetCommand(struct drxd_state *state)
-{
-	int status;
-
-	mutex_lock(&state->mutex);
-	status = Write16(state, HI_RA_RAM_SRV_RST_KEY__A,
-			 HI_RA_RAM_SRV_RST_KEY_ACT, 0);
-	if (status == 0)
-		status = HI_Command(state, HI_RA_RAM_SRV_CMD_RESET, 0);
-	mutex_unlock(&state->mutex);
-	msleep(1);
-	return status;
-}
-
-static int DRX_ConfigureI2CBridge(struct drxd_state *state, int bEnableBridge)
-{
-	state->hi_cfg_ctrl &= (~HI_RA_RAM_SRV_CFG_ACT_BRD__M);
-	if (bEnableBridge)
-		state->hi_cfg_ctrl |= HI_RA_RAM_SRV_CFG_ACT_BRD_ON;
-	else
-		state->hi_cfg_ctrl |= HI_RA_RAM_SRV_CFG_ACT_BRD_OFF;
-
-	return HI_CfgCommand(state);
-}
-
-#define HI_TR_WRITE      0x9
-#define HI_TR_READ       0xA
-#define HI_TR_READ_WRITE 0xB
-#define HI_TR_BROADCAST  0x4
-
-#if 0
-static int AtomicReadBlock(struct drxd_state *state,
-			   u32 Addr, u16 DataSize, u8 *pData, u8 Flags)
-{
-	int status;
-	int i = 0;
-
-	/* Parameter check */
-	if ((!pData) || ((DataSize & 1) != 0))
-		return -1;
-
-	mutex_lock(&state->mutex);
-
-	do {
-		/* Instruct HI to read n bytes */
-		/* TODO use proper names forthese egisters */
-		status = Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, (HI_TR_FUNC_ADDR & 0xFFFF), 0);
-		if (status < 0)
-			break;
-		status = Write16(state, HI_RA_RAM_SRV_CFG_DIV__A, (u16) (Addr >> 16), 0);
-		if (status < 0)
-			break;
-		status = Write16(state, HI_RA_RAM_SRV_CFG_BDL__A, (u16) (Addr & 0xFFFF), 0);
-		if (status < 0)
-			break;
-		status = Write16(state, HI_RA_RAM_SRV_CFG_WUP__A, (u16) ((DataSize / 2) - 1), 0);
-		if (status < 0)
-			break;
-		status = Write16(state, HI_RA_RAM_SRV_CFG_ACT__A, HI_TR_READ, 0);
-		if (status < 0)
-			break;
-
-		status = HI_Command(state, HI_RA_RAM_SRV_CMD_EXECUTE, 0);
-		if (status < 0)
-			break;
-
-	} while (0);
-
-	if (status >= 0) {
-		for (i = 0; i < (DataSize / 2); i += 1) {
-			u16 word;
-
-			status = Read16(state, (HI_RA_RAM_USR_BEGIN__A + i),
-					&word, 0);
-			if (status < 0)
-				break;
-			pData[2 * i] = (u8) (word & 0xFF);
-			pData[(2 * i) + 1] = (u8) (word >> 8);
-		}
-	}
-	mutex_unlock(&state->mutex);
-	return status;
-}
-
-static int AtomicReadReg32(struct drxd_state *state,
-			   u32 Addr, u32 *pData, u8 Flags)
-{
-	u8 buf[sizeof(u32)];
-	int status;
-
-	if (!pData)
-		return -1;
-	status = AtomicReadBlock(state, Addr, sizeof(u32), buf, Flags);
-	*pData = (((u32) buf[0]) << 0) +
-	    (((u32) buf[1]) << 8) +
-	    (((u32) buf[2]) << 16) + (((u32) buf[3]) << 24);
-	return status;
-}
-#endif
-
-static int StopAllProcessors(struct drxd_state *state)
-{
-	return Write16(state, HI_COMM_EXEC__A,
-		       SC_COMM_EXEC_CTL_STOP, DRX_I2C_BROADCAST);
-}
-
-static int EnableAndResetMB(struct drxd_state *state)
-{
-	if (state->type_A) {
-		/* disable? monitor bus observe @ EC_OC */
-		Write16(state, EC_OC_REG_OC_MON_SIO__A, 0x0000, 0x0000);
-	}
-
-	/* do inverse broadcast, followed by explicit write to HI */
-	Write16(state, HI_COMM_MB__A, 0x0000, DRX_I2C_BROADCAST);
-	Write16(state, HI_COMM_MB__A, 0x0000, 0x0000);
-	return 0;
-}
-
-static int InitCC(struct drxd_state *state)
-{
-	if (state->osc_clock_freq == 0 ||
-	    state->osc_clock_freq > 20000 ||
-	    (state->osc_clock_freq % 4000) != 0) {
-		printk(KERN_ERR "invalid osc frequency %d\n", state->osc_clock_freq);
-		return -1;
-	}
-
-	Write16(state, CC_REG_OSC_MODE__A, CC_REG_OSC_MODE_M20, 0);
-	Write16(state, CC_REG_PLL_MODE__A, CC_REG_PLL_MODE_BYPASS_PLL |
-		CC_REG_PLL_MODE_PUMP_CUR_12, 0);
-	Write16(state, CC_REG_REF_DIVIDE__A, state->osc_clock_freq / 4000, 0);
-	Write16(state, CC_REG_PWD_MODE__A, CC_REG_PWD_MODE_DOWN_PLL, 0);
-	Write16(state, CC_REG_UPDATE__A, CC_REG_UPDATE_KEY, 0);
-
-	return 0;
-}
-
-static int ResetECOD(struct drxd_state *state)
-{
-	int status = 0;
-
-	if (state->type_A)
-		status = Write16(state, EC_OD_REG_SYNC__A, 0x0664, 0);
-	else
-		status = Write16(state, B_EC_OD_REG_SYNC__A, 0x0664, 0);
-
-	if (!(status < 0))
-		status = WriteTable(state, state->m_ResetECRAM);
-	if (!(status < 0))
-		status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0001, 0);
-	return status;
-}
-
-/* Configure PGA switch */
-
-static int SetCfgPga(struct drxd_state *state, int pgaSwitch)
-{
-	int status;
-	u16 AgModeLop = 0;
-	u16 AgModeHip = 0;
-	do {
-		if (pgaSwitch) {
-			/* PGA on */
-			/* fine gain */
-			status = Read16(state, B_FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
-			if (status < 0)
-				break;
-			AgModeLop &= (~(B_FE_AG_REG_AG_MODE_LOP_MODE_C__M));
-			AgModeLop |= B_FE_AG_REG_AG_MODE_LOP_MODE_C_DYNAMIC;
-			status = Write16(state, B_FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
-			if (status < 0)
-				break;
-
-			/* coarse gain */
-			status = Read16(state, B_FE_AG_REG_AG_MODE_HIP__A, &AgModeHip, 0x0000);
-			if (status < 0)
-				break;
-			AgModeHip &= (~(B_FE_AG_REG_AG_MODE_HIP_MODE_J__M));
-			AgModeHip |= B_FE_AG_REG_AG_MODE_HIP_MODE_J_DYNAMIC;
-			status = Write16(state, B_FE_AG_REG_AG_MODE_HIP__A, AgModeHip, 0x0000);
-			if (status < 0)
-				break;
-
-			/* enable fine and coarse gain, enable AAF,
-			   no ext resistor */
-			status = Write16(state, B_FE_AG_REG_AG_PGA_MODE__A, B_FE_AG_REG_AG_PGA_MODE_PFY_PCY_AFY_REN, 0x0000);
-			if (status < 0)
-				break;
-		} else {
-			/* PGA off, bypass */
-
-			/* fine gain */
-			status = Read16(state, B_FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
-			if (status < 0)
-				break;
-			AgModeLop &= (~(B_FE_AG_REG_AG_MODE_LOP_MODE_C__M));
-			AgModeLop |= B_FE_AG_REG_AG_MODE_LOP_MODE_C_STATIC;
-			status = Write16(state, B_FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
-			if (status < 0)
-				break;
-
-			/* coarse gain */
-			status = Read16(state, B_FE_AG_REG_AG_MODE_HIP__A, &AgModeHip, 0x0000);
-			if (status < 0)
-				break;
-			AgModeHip &= (~(B_FE_AG_REG_AG_MODE_HIP_MODE_J__M));
-			AgModeHip |= B_FE_AG_REG_AG_MODE_HIP_MODE_J_STATIC;
-			status = Write16(state, B_FE_AG_REG_AG_MODE_HIP__A, AgModeHip, 0x0000);
-			if (status < 0)
-				break;
-
-			/* disable fine and coarse gain, enable AAF,
-			   no ext resistor */
-			status = Write16(state, B_FE_AG_REG_AG_PGA_MODE__A, B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN, 0x0000);
-			if (status < 0)
-				break;
-		}
-	} while (0);
-	return status;
-}
-
-static int InitFE(struct drxd_state *state)
-{
-	int status;
-
-	do {
-		status = WriteTable(state, state->m_InitFE_1);
-		if (status < 0)
-			break;
-
-		if (state->type_A) {
-			status = Write16(state, FE_AG_REG_AG_PGA_MODE__A,
-					 FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN,
-					 0);
-		} else {
-			if (state->PGA)
-				status = SetCfgPga(state, 0);
-			else
-				status =
-				    Write16(state, B_FE_AG_REG_AG_PGA_MODE__A,
-					    B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN,
-					    0);
-		}
-
-		if (status < 0)
-			break;
-		status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, state->m_FeAgRegAgAgcSio, 0x0000);
-		if (status < 0)
-			break;
-		status = Write16(state, FE_AG_REG_AG_PWD__A, state->m_FeAgRegAgPwd, 0x0000);
-		if (status < 0)
-			break;
-
-		status = WriteTable(state, state->m_InitFE_2);
-		if (status < 0)
-			break;
-
-	} while (0);
-
-	return status;
-}
-
-static int InitFT(struct drxd_state *state)
-{
-	/*
-	   norm OFFSET,  MB says =2 voor 8K en =3 voor 2K waarschijnlijk
-	   SC stuff
-	 */
-	return Write16(state, FT_REG_COMM_EXEC__A, 0x0001, 0x0000);
-}
-
-static int SC_WaitForReady(struct drxd_state *state)
-{
-	u16 curCmd;
-	int i;
-
-	for (i = 0; i < DRXD_MAX_RETRIES; i += 1) {
-		int status = Read16(state, SC_RA_RAM_CMD__A, &curCmd, 0);
-		if (status == 0 || curCmd == 0)
-			return status;
-	}
-	return -1;
-}
-
-static int SC_SendCommand(struct drxd_state *state, u16 cmd)
-{
-	int status = 0;
-	u16 errCode;
-
-	Write16(state, SC_RA_RAM_CMD__A, cmd, 0);
-	SC_WaitForReady(state);
-
-	Read16(state, SC_RA_RAM_CMD_ADDR__A, &errCode, 0);
-
-	if (errCode == 0xFFFF) {
-		printk(KERN_ERR "Command Error\n");
-		status = -1;
-	}
-
-	return status;
-}
-
-static int SC_ProcStartCommand(struct drxd_state *state,
-			       u16 subCmd, u16 param0, u16 param1)
-{
-	int status = 0;
-	u16 scExec;
-
-	mutex_lock(&state->mutex);
-	do {
-		Read16(state, SC_COMM_EXEC__A, &scExec, 0);
-		if (scExec != 1) {
-			status = -1;
-			break;
-		}
-		SC_WaitForReady(state);
-		Write16(state, SC_RA_RAM_CMD_ADDR__A, subCmd, 0);
-		Write16(state, SC_RA_RAM_PARAM1__A, param1, 0);
-		Write16(state, SC_RA_RAM_PARAM0__A, param0, 0);
-
-		SC_SendCommand(state, SC_RA_RAM_CMD_PROC_START);
-	} while (0);
-	mutex_unlock(&state->mutex);
-	return status;
-}
-
-static int SC_SetPrefParamCommand(struct drxd_state *state,
-				  u16 subCmd, u16 param0, u16 param1)
-{
-	int status;
-
-	mutex_lock(&state->mutex);
-	do {
-		status = SC_WaitForReady(state);
-		if (status < 0)
-			break;
-		status = Write16(state, SC_RA_RAM_CMD_ADDR__A, subCmd, 0);
-		if (status < 0)
-			break;
-		status = Write16(state, SC_RA_RAM_PARAM1__A, param1, 0);
-		if (status < 0)
-			break;
-		status = Write16(state, SC_RA_RAM_PARAM0__A, param0, 0);
-		if (status < 0)
-			break;
-
-		status = SC_SendCommand(state, SC_RA_RAM_CMD_SET_PREF_PARAM);
-		if (status < 0)
-			break;
-	} while (0);
-	mutex_unlock(&state->mutex);
-	return status;
-}
-
-#if 0
-static int SC_GetOpParamCommand(struct drxd_state *state, u16 * result)
-{
-	int status = 0;
-
-	mutex_lock(&state->mutex);
-	do {
-		status = SC_WaitForReady(state);
-		if (status < 0)
-			break;
-		status = SC_SendCommand(state, SC_RA_RAM_CMD_GET_OP_PARAM);
-		if (status < 0)
-			break;
-		status = Read16(state, SC_RA_RAM_PARAM0__A, result, 0);
-		if (status < 0)
-			break;
-	} while (0);
-	mutex_unlock(&state->mutex);
-	return status;
-}
-#endif
-
-static int ConfigureMPEGOutput(struct drxd_state *state, int bEnableOutput)
-{
-	int status;
-
-	do {
-		u16 EcOcRegIprInvMpg = 0;
-		u16 EcOcRegOcModeLop = 0;
-		u16 EcOcRegOcModeHip = 0;
-		u16 EcOcRegOcMpgSio = 0;
-
-		/*CHK_ERROR(Read16(state, EC_OC_REG_OC_MODE_LOP__A, &EcOcRegOcModeLop, 0)); */
-
-		if (state->operation_mode == OM_DVBT_Diversity_Front) {
-			if (bEnableOutput) {
-				EcOcRegOcModeHip |=
-				    B_EC_OC_REG_OC_MODE_HIP_MPG_BUS_SRC_MONITOR;
-			} else
-				EcOcRegOcMpgSio |= EC_OC_REG_OC_MPG_SIO__M;
-			EcOcRegOcModeLop |=
-			    EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE;
-		} else {
-			EcOcRegOcModeLop = state->m_EcOcRegOcModeLop;
-
-			if (bEnableOutput)
-				EcOcRegOcMpgSio &= (~(EC_OC_REG_OC_MPG_SIO__M));
-			else
-				EcOcRegOcMpgSio |= EC_OC_REG_OC_MPG_SIO__M;
-
-			/* Don't Insert RS Byte */
-			if (state->insert_rs_byte) {
-				EcOcRegOcModeLop &=
-				    (~(EC_OC_REG_OC_MODE_LOP_PAR_ENA__M));
-				EcOcRegOcModeHip &=
-				    (~EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M);
-				EcOcRegOcModeHip |=
-				    EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_ENABLE;
-			} else {
-				EcOcRegOcModeLop |=
-				    EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE;
-				EcOcRegOcModeHip &=
-				    (~EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M);
-				EcOcRegOcModeHip |=
-				    EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_DISABLE;
-			}
-
-			/* Mode = Parallel */
-			if (state->enable_parallel)
-				EcOcRegOcModeLop &=
-				    (~(EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE__M));
-			else
-				EcOcRegOcModeLop |=
-				    EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE_SERIAL;
-		}
-		/* Invert Data */
-		/* EcOcRegIprInvMpg |= 0x00FF; */
-		EcOcRegIprInvMpg &= (~(0x00FF));
-
-		/* Invert Error ( we don't use the pin ) */
-		/*  EcOcRegIprInvMpg |= 0x0100; */
-		EcOcRegIprInvMpg &= (~(0x0100));
-
-		/* Invert Start ( we don't use the pin ) */
-		/* EcOcRegIprInvMpg |= 0x0200; */
-		EcOcRegIprInvMpg &= (~(0x0200));
-
-		/* Invert Valid ( we don't use the pin ) */
-		/* EcOcRegIprInvMpg |= 0x0400; */
-		EcOcRegIprInvMpg &= (~(0x0400));
-
-		/* Invert Clock */
-		/* EcOcRegIprInvMpg |= 0x0800; */
-		EcOcRegIprInvMpg &= (~(0x0800));
-
-		/* EcOcRegOcModeLop =0x05; */
-		status = Write16(state, EC_OC_REG_IPR_INV_MPG__A, EcOcRegIprInvMpg, 0);
-		if (status < 0)
-			break;
-		status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, EcOcRegOcModeLop, 0);
-		if (status < 0)
-			break;
-		status = Write16(state, EC_OC_REG_OC_MODE_HIP__A, EcOcRegOcModeHip, 0x0000);
-		if (status < 0)
-			break;
-		status = Write16(state, EC_OC_REG_OC_MPG_SIO__A, EcOcRegOcMpgSio, 0);
-		if (status < 0)
-			break;
-	} while (0);
-	return status;
-}
-
-static int SetDeviceTypeId(struct drxd_state *state)
-{
-	int status = 0;
-	u16 deviceId = 0;
-
-	do {
-		status = Read16(state, CC_REG_JTAGID_L__A, &deviceId, 0);
-		if (status < 0)
-			break;
-		/* TODO: why twice? */
-		status = Read16(state, CC_REG_JTAGID_L__A, &deviceId, 0);
-		if (status < 0)
-			break;
-		printk(KERN_INFO "drxd: deviceId = %04x\n", deviceId);
-
-		state->type_A = 0;
-		state->PGA = 0;
-		state->diversity = 0;
-		if (deviceId == 0) {	/* on A2 only 3975 available */
-			state->type_A = 1;
-			printk(KERN_INFO "DRX3975D-A2\n");
-		} else {
-			deviceId >>= 12;
-			printk(KERN_INFO "DRX397%dD-B1\n", deviceId);
-			switch (deviceId) {
-			case 4:
-				state->diversity = 1;
-			case 3:
-			case 7:
-				state->PGA = 1;
-				break;
-			case 6:
-				state->diversity = 1;
-			case 5:
-			case 8:
-				break;
-			default:
-				status = -1;
-				break;
-			}
-		}
-	} while (0);
-
-	if (status < 0)
-		return status;
-
-	/* Init Table selection */
-	state->m_InitAtomicRead = DRXD_InitAtomicRead;
-	state->m_InitSC = DRXD_InitSC;
-	state->m_ResetECRAM = DRXD_ResetECRAM;
-	if (state->type_A) {
-		state->m_ResetCEFR = DRXD_ResetCEFR;
-		state->m_InitFE_1 = DRXD_InitFEA2_1;
-		state->m_InitFE_2 = DRXD_InitFEA2_2;
-		state->m_InitCP = DRXD_InitCPA2;
-		state->m_InitCE = DRXD_InitCEA2;
-		state->m_InitEQ = DRXD_InitEQA2;
-		state->m_InitEC = DRXD_InitECA2;
-		if (load_firmware(state, DRX_FW_FILENAME_A2))
-			return -EIO;
-	} else {
-		state->m_ResetCEFR = NULL;
-		state->m_InitFE_1 = DRXD_InitFEB1_1;
-		state->m_InitFE_2 = DRXD_InitFEB1_2;
-		state->m_InitCP = DRXD_InitCPB1;
-		state->m_InitCE = DRXD_InitCEB1;
-		state->m_InitEQ = DRXD_InitEQB1;
-		state->m_InitEC = DRXD_InitECB1;
-		if (load_firmware(state, DRX_FW_FILENAME_B1))
-			return -EIO;
-	}
-	if (state->diversity) {
-		state->m_InitDiversityFront = DRXD_InitDiversityFront;
-		state->m_InitDiversityEnd = DRXD_InitDiversityEnd;
-		state->m_DisableDiversity = DRXD_DisableDiversity;
-		state->m_StartDiversityFront = DRXD_StartDiversityFront;
-		state->m_StartDiversityEnd = DRXD_StartDiversityEnd;
-		state->m_DiversityDelay8MHZ = DRXD_DiversityDelay8MHZ;
-		state->m_DiversityDelay6MHZ = DRXD_DiversityDelay6MHZ;
-	} else {
-		state->m_InitDiversityFront = NULL;
-		state->m_InitDiversityEnd = NULL;
-		state->m_DisableDiversity = NULL;
-		state->m_StartDiversityFront = NULL;
-		state->m_StartDiversityEnd = NULL;
-		state->m_DiversityDelay8MHZ = NULL;
-		state->m_DiversityDelay6MHZ = NULL;
-	}
-
-	return status;
-}
-
-static int CorrectSysClockDeviation(struct drxd_state *state)
-{
-	int status;
-	s32 incr = 0;
-	s32 nomincr = 0;
-	u32 bandwidth = 0;
-	u32 sysClockInHz = 0;
-	u32 sysClockFreq = 0;	/* in kHz */
-	s16 oscClockDeviation;
-	s16 Diff;
-
-	do {
-		/* Retrieve bandwidth and incr, sanity check */
-
-		/* These accesses should be AtomicReadReg32, but that
-		   causes trouble (at least for diversity */
-		status = Read32(state, LC_RA_RAM_IFINCR_NOM_L__A, ((u32 *) &nomincr), 0);
-		if (status < 0)
-			break;
-		status = Read32(state, FE_IF_REG_INCR0__A, (u32 *) &incr, 0);
-		if (status < 0)
-			break;
-
-		if (state->type_A) {
-			if ((nomincr - incr < -500) || (nomincr - incr > 500))
-				break;
-		} else {
-			if ((nomincr - incr < -2000) || (nomincr - incr > 2000))
-				break;
-		}
-
-		switch (state->props.bandwidth_hz) {
-		case 8000000:
-			bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ;
-			break;
-		case 7000000:
-			bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ;
-			break;
-		case 6000000:
-			bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ;
-			break;
-		default:
-			return -1;
-			break;
-		}
-
-		/* Compute new sysclock value
-		   sysClockFreq = (((incr + 2^23)*bandwidth)/2^21)/1000 */
-		incr += (1 << 23);
-		sysClockInHz = MulDiv32(incr, bandwidth, 1 << 21);
-		sysClockFreq = (u32) (sysClockInHz / 1000);
-		/* rounding */
-		if ((sysClockInHz % 1000) > 500)
-			sysClockFreq++;
-
-		/* Compute clock deviation in ppm */
-		oscClockDeviation = (u16) ((((s32) (sysClockFreq) -
-					     (s32)
-					     (state->expected_sys_clock_freq)) *
-					    1000000L) /
-					   (s32)
-					   (state->expected_sys_clock_freq));
-
-		Diff = oscClockDeviation - state->osc_clock_deviation;
-		/*printk(KERN_INFO "sysclockdiff=%d\n", Diff); */
-		if (Diff >= -200 && Diff <= 200) {
-			state->sys_clock_freq = (u16) sysClockFreq;
-			if (oscClockDeviation != state->osc_clock_deviation) {
-				if (state->config.osc_deviation) {
-					state->config.osc_deviation(state->priv,
-								    oscClockDeviation,
-								    1);
-					state->osc_clock_deviation =
-					    oscClockDeviation;
-				}
-			}
-			/* switch OFF SRMM scan in SC */
-			status = Write16(state, SC_RA_RAM_SAMPLE_RATE_COUNT__A, DRXD_OSCDEV_DONT_SCAN, 0);
-			if (status < 0)
-				break;
-			/* overrule FE_IF internal value for
-			   proper re-locking */
-			status = Write16(state, SC_RA_RAM_IF_SAVE__AX, state->current_fe_if_incr, 0);
-			if (status < 0)
-				break;
-			state->cscd_state = CSCD_SAVED;
-		}
-	} while (0);
-
-	return status;
-}
-
-static int DRX_Stop(struct drxd_state *state)
-{
-	int status;
-
-	if (state->drxd_state != DRXD_STARTED)
-		return 0;
-
-	do {
-		if (state->cscd_state != CSCD_SAVED) {
-			u32 lock;
-			status = DRX_GetLockStatus(state, &lock);
-			if (status < 0)
-				break;
-		}
-
-		status = StopOC(state);
-		if (status < 0)
-			break;
-
-		state->drxd_state = DRXD_STOPPED;
-
-		status = ConfigureMPEGOutput(state, 0);
-		if (status < 0)
-			break;
-
-		if (state->type_A) {
-			/* Stop relevant processors off the device */
-			status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0000, 0x0000);
-			if (status < 0)
-				break;
-
-			status = Write16(state, SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
-			if (status < 0)
-				break;
-			status = Write16(state, LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
-			if (status < 0)
-				break;
-		} else {
-			/* Stop all processors except HI & CC & FE */
-			status = Write16(state, B_SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
-			if (status < 0)
-				break;
-			status = Write16(state, B_LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
-			if (status < 0)
-				break;
-			status = Write16(state, B_FT_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
-			if (status < 0)
-				break;
-			status = Write16(state, B_CP_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
-			if (status < 0)
-				break;
-			status = Write16(state, B_CE_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
-			if (status < 0)
-				break;
-			status = Write16(state, B_EQ_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
-			if (status < 0)
-				break;
-			status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0000, 0);
-			if (status < 0)
-				break;
-		}
-
-	} while (0);
-	return status;
-}
-
-int SetOperationMode(struct drxd_state *state, int oMode)
-{
-	int status;
-
-	do {
-		if (state->drxd_state != DRXD_STOPPED) {
-			status = -1;
-			break;
-		}
-
-		if (oMode == state->operation_mode) {
-			status = 0;
-			break;
-		}
-
-		if (oMode != OM_Default && !state->diversity) {
-			status = -1;
-			break;
-		}
-
-		switch (oMode) {
-		case OM_DVBT_Diversity_Front:
-			status = WriteTable(state, state->m_InitDiversityFront);
-			break;
-		case OM_DVBT_Diversity_End:
-			status = WriteTable(state, state->m_InitDiversityEnd);
-			break;
-		case OM_Default:
-			/* We need to check how to
-			   get DRXD out of diversity */
-		default:
-			status = WriteTable(state, state->m_DisableDiversity);
-			break;
-		}
-	} while (0);
-
-	if (!status)
-		state->operation_mode = oMode;
-	return status;
-}
-
-static int StartDiversity(struct drxd_state *state)
-{
-	int status = 0;
-	u16 rcControl;
-
-	do {
-		if (state->operation_mode == OM_DVBT_Diversity_Front) {
-			status = WriteTable(state, state->m_StartDiversityFront);
-			if (status < 0)
-				break;
-		} else if (state->operation_mode == OM_DVBT_Diversity_End) {
-			status = WriteTable(state, state->m_StartDiversityEnd);
-			if (status < 0)
-				break;
-			if (state->props.bandwidth_hz == 8000000) {
-				status = WriteTable(state, state->m_DiversityDelay8MHZ);
-				if (status < 0)
-					break;
-			} else {
-				status = WriteTable(state, state->m_DiversityDelay6MHZ);
-				if (status < 0)
-					break;
-			}
-
-			status = Read16(state, B_EQ_REG_RC_SEL_CAR__A, &rcControl, 0);
-			if (status < 0)
-				break;
-			rcControl &= ~(B_EQ_REG_RC_SEL_CAR_FFTMODE__M);
-			rcControl |= B_EQ_REG_RC_SEL_CAR_DIV_ON |
-			    /*  combining enabled */
-			    B_EQ_REG_RC_SEL_CAR_MEAS_A_CC |
-			    B_EQ_REG_RC_SEL_CAR_PASS_A_CC |
-			    B_EQ_REG_RC_SEL_CAR_LOCAL_A_CC;
-			status = Write16(state, B_EQ_REG_RC_SEL_CAR__A, rcControl, 0);
-			if (status < 0)
-				break;
-		}
-	} while (0);
-	return status;
-}
-
-static int SetFrequencyShift(struct drxd_state *state,
-			     u32 offsetFreq, int channelMirrored)
-{
-	int negativeShift = (state->tuner_mirrors == channelMirrored);
-
-	/* Handle all mirroring
-	 *
-	 * Note: ADC mirroring (aliasing) is implictly handled by limiting
-	 * feFsRegAddInc to 28 bits below
-	 * (if the result before masking is more than 28 bits, this means
-	 *  that the ADC is mirroring.
-	 * The masking is in fact the aliasing of the ADC)
-	 *
-	 */
-
-	/* Compute register value, unsigned computation */
-	state->fe_fs_add_incr = MulDiv32(state->intermediate_freq +
-					 offsetFreq,
-					 1 << 28, state->sys_clock_freq);
-	/* Remove integer part */
-	state->fe_fs_add_incr &= 0x0FFFFFFFL;
-	if (negativeShift)
-		state->fe_fs_add_incr = ((1 << 28) - state->fe_fs_add_incr);
-
-	/* Save the frequency shift without tunerOffset compensation
-	   for CtrlGetChannel. */
-	state->org_fe_fs_add_incr = MulDiv32(state->intermediate_freq,
-					     1 << 28, state->sys_clock_freq);
-	/* Remove integer part */
-	state->org_fe_fs_add_incr &= 0x0FFFFFFFL;
-	if (negativeShift)
-		state->org_fe_fs_add_incr = ((1L << 28) -
-					     state->org_fe_fs_add_incr);
-
-	return Write32(state, FE_FS_REG_ADD_INC_LOP__A,
-		       state->fe_fs_add_incr, 0);
-}
-
-static int SetCfgNoiseCalibration(struct drxd_state *state,
-				  struct SNoiseCal *noiseCal)
-{
-	u16 beOptEna;
-	int status = 0;
-
-	do {
-		status = Read16(state, SC_RA_RAM_BE_OPT_ENA__A, &beOptEna, 0);
-		if (status < 0)
-			break;
-		if (noiseCal->cpOpt) {
-			beOptEna |= (1 << SC_RA_RAM_BE_OPT_ENA_CP_OPT);
-		} else {
-			beOptEna &= ~(1 << SC_RA_RAM_BE_OPT_ENA_CP_OPT);
-			status = Write16(state, CP_REG_AC_NEXP_OFFS__A, noiseCal->cpNexpOfs, 0);
-			if (status < 0)
-				break;
-		}
-		status = Write16(state, SC_RA_RAM_BE_OPT_ENA__A, beOptEna, 0);
-		if (status < 0)
-			break;
-
-		if (!state->type_A) {
-			status = Write16(state, B_SC_RA_RAM_CO_TD_CAL_2K__A, noiseCal->tdCal2k, 0);
-			if (status < 0)
-				break;
-			status = Write16(state, B_SC_RA_RAM_CO_TD_CAL_8K__A, noiseCal->tdCal8k, 0);
-			if (status < 0)
-				break;
-		}
-	} while (0);
-
-	return status;
-}
-
-static int DRX_Start(struct drxd_state *state, s32 off)
-{
-	struct dtv_frontend_properties *p = &state->props;
-	int status;
-
-	u16 transmissionParams = 0;
-	u16 operationMode = 0;
-	u16 qpskTdTpsPwr = 0;
-	u16 qam16TdTpsPwr = 0;
-	u16 qam64TdTpsPwr = 0;
-	u32 feIfIncr = 0;
-	u32 bandwidth = 0;
-	int mirrorFreqSpect;
-
-	u16 qpskSnCeGain = 0;
-	u16 qam16SnCeGain = 0;
-	u16 qam64SnCeGain = 0;
-	u16 qpskIsGainMan = 0;
-	u16 qam16IsGainMan = 0;
-	u16 qam64IsGainMan = 0;
-	u16 qpskIsGainExp = 0;
-	u16 qam16IsGainExp = 0;
-	u16 qam64IsGainExp = 0;
-	u16 bandwidthParam = 0;
-
-	if (off < 0)
-		off = (off - 500) / 1000;
-	else
-		off = (off + 500) / 1000;
-
-	do {
-		if (state->drxd_state != DRXD_STOPPED)
-			return -1;
-		status = ResetECOD(state);
-		if (status < 0)
-			break;
-		if (state->type_A) {
-			status = InitSC(state);
-			if (status < 0)
-				break;
-		} else {
-			status = InitFT(state);
-			if (status < 0)
-				break;
-			status = InitCP(state);
-			if (status < 0)
-				break;
-			status = InitCE(state);
-			if (status < 0)
-				break;
-			status = InitEQ(state);
-			if (status < 0)
-				break;
-			status = InitSC(state);
-			if (status < 0)
-				break;
-		}
-
-		/* Restore current IF & RF AGC settings */
-
-		status = SetCfgIfAgc(state, &state->if_agc_cfg);
-		if (status < 0)
-			break;
-		status = SetCfgRfAgc(state, &state->rf_agc_cfg);
-		if (status < 0)
-			break;
-
-		mirrorFreqSpect = (state->props.inversion == INVERSION_ON);
-
-		switch (p->transmission_mode) {
-		default:	/* Not set, detect it automatically */
-			operationMode |= SC_RA_RAM_OP_AUTO_MODE__M;
-			/* fall through , try first guess DRX_FFTMODE_8K */
-		case TRANSMISSION_MODE_8K:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_MODE_8K;
-			if (state->type_A) {
-				status = Write16(state, EC_SB_REG_TR_MODE__A, EC_SB_REG_TR_MODE_8K, 0x0000);
-				if (status < 0)
-					break;
-				qpskSnCeGain = 99;
-				qam16SnCeGain = 83;
-				qam64SnCeGain = 67;
-			}
-			break;
-		case TRANSMISSION_MODE_2K:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_MODE_2K;
-			if (state->type_A) {
-				status = Write16(state, EC_SB_REG_TR_MODE__A, EC_SB_REG_TR_MODE_2K, 0x0000);
-				if (status < 0)
-					break;
-				qpskSnCeGain = 97;
-				qam16SnCeGain = 71;
-				qam64SnCeGain = 65;
-			}
-			break;
-		}
-
-		switch (p->guard_interval) {
-		case GUARD_INTERVAL_1_4:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_4;
-			break;
-		case GUARD_INTERVAL_1_8:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_8;
-			break;
-		case GUARD_INTERVAL_1_16:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_16;
-			break;
-		case GUARD_INTERVAL_1_32:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_32;
-			break;
-		default:	/* Not set, detect it automatically */
-			operationMode |= SC_RA_RAM_OP_AUTO_GUARD__M;
-			/* try first guess 1/4 */
-			transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_4;
-			break;
-		}
-
-		switch (p->hierarchy) {
-		case HIERARCHY_1:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A1;
-			if (state->type_A) {
-				status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0001, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EC_SB_REG_ALPHA__A, 0x0001, 0x0000);
-				if (status < 0)
-					break;
-
-				qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN;
-				qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA1;
-				qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA1;
-
-				qpskIsGainMan =
-				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE;
-				qam16IsGainMan =
-				    SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE;
-				qam64IsGainMan =
-				    SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE;
-
-				qpskIsGainExp =
-				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE;
-				qam16IsGainExp =
-				    SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE;
-				qam64IsGainExp =
-				    SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE;
-			}
-			break;
-
-		case HIERARCHY_2:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A2;
-			if (state->type_A) {
-				status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0002, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EC_SB_REG_ALPHA__A, 0x0002, 0x0000);
-				if (status < 0)
-					break;
-
-				qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN;
-				qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA2;
-				qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA2;
-
-				qpskIsGainMan =
-				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE;
-				qam16IsGainMan =
-				    SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_MAN__PRE;
-				qam64IsGainMan =
-				    SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_MAN__PRE;
-
-				qpskIsGainExp =
-				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE;
-				qam16IsGainExp =
-				    SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_EXP__PRE;
-				qam64IsGainExp =
-				    SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_EXP__PRE;
-			}
-			break;
-		case HIERARCHY_4:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A4;
-			if (state->type_A) {
-				status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0003, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EC_SB_REG_ALPHA__A, 0x0003, 0x0000);
-				if (status < 0)
-					break;
-
-				qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN;
-				qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA4;
-				qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA4;
-
-				qpskIsGainMan =
-				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE;
-				qam16IsGainMan =
-				    SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_MAN__PRE;
-				qam64IsGainMan =
-				    SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_MAN__PRE;
-
-				qpskIsGainExp =
-				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE;
-				qam16IsGainExp =
-				    SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_EXP__PRE;
-				qam64IsGainExp =
-				    SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_EXP__PRE;
-			}
-			break;
-		case HIERARCHY_AUTO:
-		default:
-			/* Not set, detect it automatically, start with none */
-			operationMode |= SC_RA_RAM_OP_AUTO_HIER__M;
-			transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_NO;
-			if (state->type_A) {
-				status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0000, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EC_SB_REG_ALPHA__A, 0x0000, 0x0000);
-				if (status < 0)
-					break;
-
-				qpskTdTpsPwr = EQ_TD_TPS_PWR_QPSK;
-				qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHAN;
-				qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHAN;
-
-				qpskIsGainMan =
-				    SC_RA_RAM_EQ_IS_GAIN_QPSK_MAN__PRE;
-				qam16IsGainMan =
-				    SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE;
-				qam64IsGainMan =
-				    SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE;
-
-				qpskIsGainExp =
-				    SC_RA_RAM_EQ_IS_GAIN_QPSK_EXP__PRE;
-				qam16IsGainExp =
-				    SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE;
-				qam64IsGainExp =
-				    SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE;
-			}
-			break;
-		}
-		status = status;
-		if (status < 0)
-			break;
-
-		switch (p->modulation) {
-		default:
-			operationMode |= SC_RA_RAM_OP_AUTO_CONST__M;
-			/* fall through , try first guess
-			   DRX_CONSTELLATION_QAM64 */
-		case QAM_64:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QAM64;
-			if (state->type_A) {
-				status = Write16(state, EQ_REG_OT_CONST__A, 0x0002, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_64QAM, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0020, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0008, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0002, 0x0000);
-				if (status < 0)
-					break;
-
-				status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qam64TdTpsPwr, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EQ_REG_SN_CEGAIN__A, qam64SnCeGain, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qam64IsGainMan, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qam64IsGainExp, 0x0000);
-				if (status < 0)
-					break;
-			}
-			break;
-		case QPSK:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QPSK;
-			if (state->type_A) {
-				status = Write16(state, EQ_REG_OT_CONST__A, 0x0000, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_QPSK, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0010, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0000, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0000, 0x0000);
-				if (status < 0)
-					break;
-
-				status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qpskTdTpsPwr, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EQ_REG_SN_CEGAIN__A, qpskSnCeGain, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qpskIsGainMan, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qpskIsGainExp, 0x0000);
-				if (status < 0)
-					break;
-			}
-			break;
-
-		case QAM_16:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QAM16;
-			if (state->type_A) {
-				status = Write16(state, EQ_REG_OT_CONST__A, 0x0001, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_16QAM, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0010, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0004, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0000, 0x0000);
-				if (status < 0)
-					break;
-
-				status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qam16TdTpsPwr, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EQ_REG_SN_CEGAIN__A, qam16SnCeGain, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qam16IsGainMan, 0x0000);
-				if (status < 0)
-					break;
-				status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qam16IsGainExp, 0x0000);
-				if (status < 0)
-					break;
-			}
-			break;
-
-		}
-		status = status;
-		if (status < 0)
-			break;
-
-		switch (DRX_CHANNEL_HIGH) {
-		default:
-		case DRX_CHANNEL_AUTO:
-		case DRX_CHANNEL_LOW:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_PRIO_LO;
-			status = Write16(state, EC_SB_REG_PRIOR__A, EC_SB_REG_PRIOR_LO, 0x0000);
-			if (status < 0)
-				break;
-			break;
-		case DRX_CHANNEL_HIGH:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_PRIO_HI;
-			status = Write16(state, EC_SB_REG_PRIOR__A, EC_SB_REG_PRIOR_HI, 0x0000);
-			if (status < 0)
-				break;
-			break;
-
-		}
-
-		switch (p->code_rate_HP) {
-		case FEC_1_2:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_1_2;
-			if (state->type_A) {
-				status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C1_2, 0x0000);
-				if (status < 0)
-					break;
-			}
-			break;
-		default:
-			operationMode |= SC_RA_RAM_OP_AUTO_RATE__M;
-		case FEC_2_3:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_2_3;
-			if (state->type_A) {
-				status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C2_3, 0x0000);
-				if (status < 0)
-					break;
-			}
-			break;
-		case FEC_3_4:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_3_4;
-			if (state->type_A) {
-				status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C3_4, 0x0000);
-				if (status < 0)
-					break;
-			}
-			break;
-		case FEC_5_6:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_5_6;
-			if (state->type_A) {
-				status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C5_6, 0x0000);
-				if (status < 0)
-					break;
-			}
-			break;
-		case FEC_7_8:
-			transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_7_8;
-			if (state->type_A) {
-				status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C7_8, 0x0000);
-				if (status < 0)
-					break;
-			}
-			break;
-		}
-		status = status;
-		if (status < 0)
-			break;
-
-		/* First determine real bandwidth (Hz) */
-		/* Also set delay for impulse noise cruncher (only A2) */
-		/* Also set parameters for EC_OC fix, note
-		   EC_OC_REG_TMD_HIL_MAR is changed
-		   by SC for fix for some 8K,1/8 guard but is restored by
-		   InitEC and ResetEC
-		   functions */
-		switch (p->bandwidth_hz) {
-		case 0:
-			p->bandwidth_hz = 8000000;
-			/* fall through */
-		case 8000000:
-			/* (64/7)*(8/8)*1000000 */
-			bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ;
-
-			bandwidthParam = 0;
-			status = Write16(state,
-					 FE_AG_REG_IND_DEL__A, 50, 0x0000);
-			break;
-		case 7000000:
-			/* (64/7)*(7/8)*1000000 */
-			bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ;
-			bandwidthParam = 0x4807;	/*binary:0100 1000 0000 0111 */
-			status = Write16(state,
-					 FE_AG_REG_IND_DEL__A, 59, 0x0000);
-			break;
-		case 6000000:
-			/* (64/7)*(6/8)*1000000 */
-			bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ;
-			bandwidthParam = 0x0F07;	/*binary: 0000 1111 0000 0111 */
-			status = Write16(state,
-					 FE_AG_REG_IND_DEL__A, 71, 0x0000);
-			break;
-		default:
-			status = -EINVAL;
-		}
-		if (status < 0)
-			break;
-
-		status = Write16(state, SC_RA_RAM_BAND__A, bandwidthParam, 0x0000);
-		if (status < 0)
-			break;
-
-		{
-			u16 sc_config;
-			status = Read16(state, SC_RA_RAM_CONFIG__A, &sc_config, 0);
-			if (status < 0)
-				break;
-
-			/* enable SLAVE mode in 2k 1/32 to
-			   prevent timing change glitches */
-			if ((p->transmission_mode == TRANSMISSION_MODE_2K) &&
-			    (p->guard_interval == GUARD_INTERVAL_1_32)) {
-				/* enable slave */
-				sc_config |= SC_RA_RAM_CONFIG_SLAVE__M;
-			} else {
-				/* disable slave */
-				sc_config &= ~SC_RA_RAM_CONFIG_SLAVE__M;
-			}
-			status = Write16(state, SC_RA_RAM_CONFIG__A, sc_config, 0);
-			if (status < 0)
-				break;
-		}
-
-		status = SetCfgNoiseCalibration(state, &state->noise_cal);
-		if (status < 0)
-			break;
-
-		if (state->cscd_state == CSCD_INIT) {
-			/* switch on SRMM scan in SC */
-			status = Write16(state, SC_RA_RAM_SAMPLE_RATE_COUNT__A, DRXD_OSCDEV_DO_SCAN, 0x0000);
-			if (status < 0)
-				break;
-/*            CHK_ERROR(Write16(SC_RA_RAM_SAMPLE_RATE_STEP__A, DRXD_OSCDEV_STEP, 0x0000));*/
-			state->cscd_state = CSCD_SET;
-		}
-
-		/* Now compute FE_IF_REG_INCR */
-		/*((( SysFreq/BandWidth)/2)/2) -1) * 2^23) =>
-		   ((SysFreq / BandWidth) * (2^21) ) - (2^23) */
-		feIfIncr = MulDiv32(state->sys_clock_freq * 1000,
-				    (1ULL << 21), bandwidth) - (1 << 23);
-		status = Write16(state, FE_IF_REG_INCR0__A, (u16) (feIfIncr & FE_IF_REG_INCR0__M), 0x0000);
-		if (status < 0)
-			break;
-		status = Write16(state, FE_IF_REG_INCR1__A, (u16) ((feIfIncr >> FE_IF_REG_INCR0__W) & FE_IF_REG_INCR1__M), 0x0000);
-		if (status < 0)
-			break;
-		/* Bandwidth setting done */
-
-		/* Mirror & frequency offset */
-		SetFrequencyShift(state, off, mirrorFreqSpect);
-
-		/* Start SC, write channel settings to SC */
-
-		/* Enable SC after setting all other parameters */
-		status = Write16(state, SC_COMM_STATE__A, 0, 0x0000);
-		if (status < 0)
-			break;
-		status = Write16(state, SC_COMM_EXEC__A, 1, 0x0000);
-		if (status < 0)
-			break;
-
-		/* Write SC parameter registers, operation mode */
-#if 1
-		operationMode = (SC_RA_RAM_OP_AUTO_MODE__M |
-				 SC_RA_RAM_OP_AUTO_GUARD__M |
-				 SC_RA_RAM_OP_AUTO_CONST__M |
-				 SC_RA_RAM_OP_AUTO_HIER__M |
-				 SC_RA_RAM_OP_AUTO_RATE__M);
-#endif
-		status = SC_SetPrefParamCommand(state, 0x0000, transmissionParams, operationMode);
-		if (status < 0)
-			break;
-
-		/* Start correct processes to get in lock */
-		status = SC_ProcStartCommand(state, SC_RA_RAM_PROC_LOCKTRACK, SC_RA_RAM_SW_EVENT_RUN_NMASK__M, SC_RA_RAM_LOCKTRACK_MIN);
-		if (status < 0)
-			break;
-
-		status = StartOC(state);
-		if (status < 0)
-			break;
-
-		if (state->operation_mode != OM_Default) {
-			status = StartDiversity(state);
-			if (status < 0)
-				break;
-		}
-
-		state->drxd_state = DRXD_STARTED;
-	} while (0);
-
-	return status;
-}
-
-static int CDRXD(struct drxd_state *state, u32 IntermediateFrequency)
-{
-	u32 ulRfAgcOutputLevel = 0xffffffff;
-	u32 ulRfAgcSettleLevel = 528;	/* Optimum value for MT2060 */
-	u32 ulRfAgcMinLevel = 0;	/* Currently unused */
-	u32 ulRfAgcMaxLevel = DRXD_FE_CTRL_MAX;	/* Currently unused */
-	u32 ulRfAgcSpeed = 0;	/* Currently unused */
-	u32 ulRfAgcMode = 0;	/*2;   Off */
-	u32 ulRfAgcR1 = 820;
-	u32 ulRfAgcR2 = 2200;
-	u32 ulRfAgcR3 = 150;
-	u32 ulIfAgcMode = 0;	/* Auto */
-	u32 ulIfAgcOutputLevel = 0xffffffff;
-	u32 ulIfAgcSettleLevel = 0xffffffff;
-	u32 ulIfAgcMinLevel = 0xffffffff;
-	u32 ulIfAgcMaxLevel = 0xffffffff;
-	u32 ulIfAgcSpeed = 0xffffffff;
-	u32 ulIfAgcR1 = 820;
-	u32 ulIfAgcR2 = 2200;
-	u32 ulIfAgcR3 = 150;
-	u32 ulClock = state->config.clock;
-	u32 ulSerialMode = 0;
-	u32 ulEcOcRegOcModeLop = 4;	/* Dynamic DTO source */
-	u32 ulHiI2cDelay = HI_I2C_DELAY;
-	u32 ulHiI2cBridgeDelay = HI_I2C_BRIDGE_DELAY;
-	u32 ulHiI2cPatch = 0;
-	u32 ulEnvironment = APPENV_PORTABLE;
-	u32 ulEnvironmentDiversity = APPENV_MOBILE;
-	u32 ulIFFilter = IFFILTER_SAW;
-
-	state->if_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
-	state->if_agc_cfg.outputLevel = 0;
-	state->if_agc_cfg.settleLevel = 140;
-	state->if_agc_cfg.minOutputLevel = 0;
-	state->if_agc_cfg.maxOutputLevel = 1023;
-	state->if_agc_cfg.speed = 904;
-
-	if (ulIfAgcMode == 1 && ulIfAgcOutputLevel <= DRXD_FE_CTRL_MAX) {
-		state->if_agc_cfg.ctrlMode = AGC_CTRL_USER;
-		state->if_agc_cfg.outputLevel = (u16) (ulIfAgcOutputLevel);
-	}
-
-	if (ulIfAgcMode == 0 &&
-	    ulIfAgcSettleLevel <= DRXD_FE_CTRL_MAX &&
-	    ulIfAgcMinLevel <= DRXD_FE_CTRL_MAX &&
-	    ulIfAgcMaxLevel <= DRXD_FE_CTRL_MAX &&
-	    ulIfAgcSpeed <= DRXD_FE_CTRL_MAX) {
-		state->if_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
-		state->if_agc_cfg.settleLevel = (u16) (ulIfAgcSettleLevel);
-		state->if_agc_cfg.minOutputLevel = (u16) (ulIfAgcMinLevel);
-		state->if_agc_cfg.maxOutputLevel = (u16) (ulIfAgcMaxLevel);
-		state->if_agc_cfg.speed = (u16) (ulIfAgcSpeed);
-	}
-
-	state->if_agc_cfg.R1 = (u16) (ulIfAgcR1);
-	state->if_agc_cfg.R2 = (u16) (ulIfAgcR2);
-	state->if_agc_cfg.R3 = (u16) (ulIfAgcR3);
-
-	state->rf_agc_cfg.R1 = (u16) (ulRfAgcR1);
-	state->rf_agc_cfg.R2 = (u16) (ulRfAgcR2);
-	state->rf_agc_cfg.R3 = (u16) (ulRfAgcR3);
-
-	state->rf_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
-	/* rest of the RFAgcCfg structure currently unused */
-	if (ulRfAgcMode == 1 && ulRfAgcOutputLevel <= DRXD_FE_CTRL_MAX) {
-		state->rf_agc_cfg.ctrlMode = AGC_CTRL_USER;
-		state->rf_agc_cfg.outputLevel = (u16) (ulRfAgcOutputLevel);
-	}
-
-	if (ulRfAgcMode == 0 &&
-	    ulRfAgcSettleLevel <= DRXD_FE_CTRL_MAX &&
-	    ulRfAgcMinLevel <= DRXD_FE_CTRL_MAX &&
-	    ulRfAgcMaxLevel <= DRXD_FE_CTRL_MAX &&
-	    ulRfAgcSpeed <= DRXD_FE_CTRL_MAX) {
-		state->rf_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
-		state->rf_agc_cfg.settleLevel = (u16) (ulRfAgcSettleLevel);
-		state->rf_agc_cfg.minOutputLevel = (u16) (ulRfAgcMinLevel);
-		state->rf_agc_cfg.maxOutputLevel = (u16) (ulRfAgcMaxLevel);
-		state->rf_agc_cfg.speed = (u16) (ulRfAgcSpeed);
-	}
-
-	if (ulRfAgcMode == 2)
-		state->rf_agc_cfg.ctrlMode = AGC_CTRL_OFF;
-
-	if (ulEnvironment <= 2)
-		state->app_env_default = (enum app_env)
-		    (ulEnvironment);
-	if (ulEnvironmentDiversity <= 2)
-		state->app_env_diversity = (enum app_env)
-		    (ulEnvironmentDiversity);
-
-	if (ulIFFilter == IFFILTER_DISCRETE) {
-		/* discrete filter */
-		state->noise_cal.cpOpt = 0;
-		state->noise_cal.cpNexpOfs = 40;
-		state->noise_cal.tdCal2k = -40;
-		state->noise_cal.tdCal8k = -24;
-	} else {
-		/* SAW filter */
-		state->noise_cal.cpOpt = 1;
-		state->noise_cal.cpNexpOfs = 0;
-		state->noise_cal.tdCal2k = -21;
-		state->noise_cal.tdCal8k = -24;
-	}
-	state->m_EcOcRegOcModeLop = (u16) (ulEcOcRegOcModeLop);
-
-	state->chip_adr = (state->config.demod_address << 1) | 1;
-	switch (ulHiI2cPatch) {
-	case 1:
-		state->m_HiI2cPatch = DRXD_HiI2cPatch_1;
-		break;
-	case 3:
-		state->m_HiI2cPatch = DRXD_HiI2cPatch_3;
-		break;
-	default:
-		state->m_HiI2cPatch = NULL;
-	}
-
-	/* modify tuner and clock attributes */
-	state->intermediate_freq = (u16) (IntermediateFrequency / 1000);
-	/* expected system clock frequency in kHz */
-	state->expected_sys_clock_freq = 48000;
-	/* real system clock frequency in kHz */
-	state->sys_clock_freq = 48000;
-	state->osc_clock_freq = (u16) ulClock;
-	state->osc_clock_deviation = 0;
-	state->cscd_state = CSCD_INIT;
-	state->drxd_state = DRXD_UNINITIALIZED;
-
-	state->PGA = 0;
-	state->type_A = 0;
-	state->tuner_mirrors = 0;
-
-	/* modify MPEG output attributes */
-	state->insert_rs_byte = state->config.insert_rs_byte;
-	state->enable_parallel = (ulSerialMode != 1);
-
-	/* Timing div, 250ns/Psys */
-	/* Timing div, = ( delay (nano seconds) * sysclk (kHz) )/ 1000 */
-
-	state->hi_cfg_timing_div = (u16) ((state->sys_clock_freq / 1000) *
-					  ulHiI2cDelay) / 1000;
-	/* Bridge delay, uses oscilator clock */
-	/* Delay = ( delay (nano seconds) * oscclk (kHz) )/ 1000 */
-	state->hi_cfg_bridge_delay = (u16) ((state->osc_clock_freq / 1000) *
-					    ulHiI2cBridgeDelay) / 1000;
-
-	state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_CONSUMER;
-	/* state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_PRO; */
-	state->m_FeAgRegAgAgcSio = DRXD_DEF_AG_AGC_SIO;
-	return 0;
-}
-
-int DRXD_init(struct drxd_state *state, const u8 * fw, u32 fw_size)
-{
-	int status = 0;
-	u32 driverVersion;
-
-	if (state->init_done)
-		return 0;
-
-	CDRXD(state, state->config.IF ? state->config.IF : 36000000);
-
-	do {
-		state->operation_mode = OM_Default;
-
-		status = SetDeviceTypeId(state);
-		if (status < 0)
-			break;
-
-		/* Apply I2c address patch to B1 */
-		if (!state->type_A && state->m_HiI2cPatch != NULL)
-			status = WriteTable(state, state->m_HiI2cPatch);
-			if (status < 0)
-				break;
-
-		if (state->type_A) {
-			/* HI firmware patch for UIO readout,
-			   avoid clearing of result register */
-			status = Write16(state, 0x43012D, 0x047f, 0);
-			if (status < 0)
-				break;
-		}
-
-		status = HI_ResetCommand(state);
-		if (status < 0)
-			break;
-
-		status = StopAllProcessors(state);
-		if (status < 0)
-			break;
-		status = InitCC(state);
-		if (status < 0)
-			break;
-
-		state->osc_clock_deviation = 0;
-
-		if (state->config.osc_deviation)
-			state->osc_clock_deviation =
-			    state->config.osc_deviation(state->priv, 0, 0);
-		{
-			/* Handle clock deviation */
-			s32 devB;
-			s32 devA = (s32) (state->osc_clock_deviation) *
-			    (s32) (state->expected_sys_clock_freq);
-			/* deviation in kHz */
-			s32 deviation = (devA / (1000000L));
-			/* rounding, signed */
-			if (devA > 0)
-				devB = (2);
-			else
-				devB = (-2);
-			if ((devB * (devA % 1000000L) > 1000000L)) {
-				/* add +1 or -1 */
-				deviation += (devB / 2);
-			}
-
-			state->sys_clock_freq =
-			    (u16) ((state->expected_sys_clock_freq) +
-				   deviation);
-		}
-		status = InitHI(state);
-		if (status < 0)
-			break;
-		status = InitAtomicRead(state);
-		if (status < 0)
-			break;
-
-		status = EnableAndResetMB(state);
-		if (status < 0)
-			break;
-		if (state->type_A)
-			status = ResetCEFR(state);
-			if (status < 0)
-				break;
-
-		if (fw) {
-			status = DownloadMicrocode(state, fw, fw_size);
-			if (status < 0)
-				break;
-		} else {
-			status = DownloadMicrocode(state, state->microcode, state->microcode_length);
-			if (status < 0)
-				break;
-		}
-
-		if (state->PGA) {
-			state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_PRO;
-			SetCfgPga(state, 0);	/* PGA = 0 dB */
-		} else {
-			state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_CONSUMER;
-		}
-
-		state->m_FeAgRegAgAgcSio = DRXD_DEF_AG_AGC_SIO;
-
-		status = InitFE(state);
-		if (status < 0)
-			break;
-		status = InitFT(state);
-		if (status < 0)
-			break;
-		status = InitCP(state);
-		if (status < 0)
-			break;
-		status = InitCE(state);
-		if (status < 0)
-			break;
-		status = InitEQ(state);
-		if (status < 0)
-			break;
-		status = InitEC(state);
-		if (status < 0)
-			break;
-		status = InitSC(state);
-		if (status < 0)
-			break;
-
-		status = SetCfgIfAgc(state, &state->if_agc_cfg);
-		if (status < 0)
-			break;
-		status = SetCfgRfAgc(state, &state->rf_agc_cfg);
-		if (status < 0)
-			break;
-
-		state->cscd_state = CSCD_INIT;
-		status = Write16(state, SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
-		if (status < 0)
-			break;
-		status = Write16(state, LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
-		if (status < 0)
-			break;
-
-		driverVersion = (((VERSION_MAJOR / 10) << 4) +
-				 (VERSION_MAJOR % 10)) << 24;
-		driverVersion += (((VERSION_MINOR / 10) << 4) +
-				  (VERSION_MINOR % 10)) << 16;
-		driverVersion += ((VERSION_PATCH / 1000) << 12) +
-		    ((VERSION_PATCH / 100) << 8) +
-		    ((VERSION_PATCH / 10) << 4) + (VERSION_PATCH % 10);
-
-		status = Write32(state, SC_RA_RAM_DRIVER_VERSION__AX, driverVersion, 0);
-		if (status < 0)
-			break;
-
-		status = StopOC(state);
-		if (status < 0)
-			break;
-
-		state->drxd_state = DRXD_STOPPED;
-		state->init_done = 1;
-		status = 0;
-	} while (0);
-	return status;
-}
-
-int DRXD_status(struct drxd_state *state, u32 * pLockStatus)
-{
-	DRX_GetLockStatus(state, pLockStatus);
-
-	/*if (*pLockStatus&DRX_LOCK_MPEG) */
-	if (*pLockStatus & DRX_LOCK_FEC) {
-		ConfigureMPEGOutput(state, 1);
-		/* Get status again, in case we have MPEG lock now */
-		/*DRX_GetLockStatus(state, pLockStatus); */
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-/****************************************************************************/
-/****************************************************************************/
-
-static int drxd_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
-{
-	struct drxd_state *state = fe->demodulator_priv;
-	u32 value;
-	int res;
-
-	res = ReadIFAgc(state, &value);
-	if (res < 0)
-		*strength = 0;
-	else
-		*strength = 0xffff - (value << 4);
-	return 0;
-}
-
-static int drxd_read_status(struct dvb_frontend *fe, fe_status_t * status)
-{
-	struct drxd_state *state = fe->demodulator_priv;
-	u32 lock;
-
-	DRXD_status(state, &lock);
-	*status = 0;
-	/* No MPEG lock in V255 firmware, bug ? */
-#if 1
-	if (lock & DRX_LOCK_MPEG)
-		*status |= FE_HAS_LOCK;
-#else
-	if (lock & DRX_LOCK_FEC)
-		*status |= FE_HAS_LOCK;
-#endif
-	if (lock & DRX_LOCK_FEC)
-		*status |= FE_HAS_VITERBI | FE_HAS_SYNC;
-	if (lock & DRX_LOCK_DEMOD)
-		*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
-
-	return 0;
-}
-
-static int drxd_init(struct dvb_frontend *fe)
-{
-	struct drxd_state *state = fe->demodulator_priv;
-	int err = 0;
-
-/*	if (request_firmware(&state->fw, "drxd.fw", state->dev)<0) */
-	return DRXD_init(state, 0, 0);
-
-	err = DRXD_init(state, state->fw->data, state->fw->size);
-	release_firmware(state->fw);
-	return err;
-}
-
-int drxd_config_i2c(struct dvb_frontend *fe, int onoff)
-{
-	struct drxd_state *state = fe->demodulator_priv;
-
-	if (state->config.disable_i2c_gate_ctrl == 1)
-		return 0;
-
-	return DRX_ConfigureI2CBridge(state, onoff);
-}
-EXPORT_SYMBOL(drxd_config_i2c);
-
-static int drxd_get_tune_settings(struct dvb_frontend *fe,
-				  struct dvb_frontend_tune_settings *sets)
-{
-	sets->min_delay_ms = 10000;
-	sets->max_drift = 0;
-	sets->step_size = 0;
-	return 0;
-}
-
-static int drxd_read_ber(struct dvb_frontend *fe, u32 * ber)
-{
-	*ber = 0;
-	return 0;
-}
-
-static int drxd_read_snr(struct dvb_frontend *fe, u16 * snr)
-{
-	*snr = 0;
-	return 0;
-}
-
-static int drxd_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
-{
-	*ucblocks = 0;
-	return 0;
-}
-
-static int drxd_sleep(struct dvb_frontend *fe)
-{
-	struct drxd_state *state = fe->demodulator_priv;
-
-	ConfigureMPEGOutput(state, 0);
-	return 0;
-}
-
-static int drxd_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	return drxd_config_i2c(fe, enable);
-}
-
-static int drxd_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct drxd_state *state = fe->demodulator_priv;
-	s32 off = 0;
-
-	state->props = *p;
-	DRX_Stop(state);
-
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	msleep(200);
-
-	return DRX_Start(state, off);
-}
-
-static void drxd_release(struct dvb_frontend *fe)
-{
-	struct drxd_state *state = fe->demodulator_priv;
-
-	kfree(state);
-}
-
-static struct dvb_frontend_ops drxd_ops = {
-	.delsys = { SYS_DVBT},
-	.info = {
-		 .name = "Micronas DRXD DVB-T",
-		 .frequency_min = 47125000,
-		 .frequency_max = 855250000,
-		 .frequency_stepsize = 166667,
-		 .frequency_tolerance = 0,
-		 .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
-		 FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
-		 FE_CAN_FEC_AUTO |
-		 FE_CAN_QAM_16 | FE_CAN_QAM_64 |
-		 FE_CAN_QAM_AUTO |
-		 FE_CAN_TRANSMISSION_MODE_AUTO |
-		 FE_CAN_GUARD_INTERVAL_AUTO |
-		 FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS},
-
-	.release = drxd_release,
-	.init = drxd_init,
-	.sleep = drxd_sleep,
-	.i2c_gate_ctrl = drxd_i2c_gate_ctrl,
-
-	.set_frontend = drxd_set_frontend,
-	.get_tune_settings = drxd_get_tune_settings,
-
-	.read_status = drxd_read_status,
-	.read_ber = drxd_read_ber,
-	.read_signal_strength = drxd_read_signal_strength,
-	.read_snr = drxd_read_snr,
-	.read_ucblocks = drxd_read_ucblocks,
-};
-
-struct dvb_frontend *drxd_attach(const struct drxd_config *config,
-				 void *priv, struct i2c_adapter *i2c,
-				 struct device *dev)
-{
-	struct drxd_state *state = NULL;
-
-	state = kmalloc(sizeof(struct drxd_state), GFP_KERNEL);
-	if (!state)
-		return NULL;
-	memset(state, 0, sizeof(*state));
-
-	memcpy(&state->ops, &drxd_ops, sizeof(struct dvb_frontend_ops));
-	state->dev = dev;
-	state->config = *config;
-	state->i2c = i2c;
-	state->priv = priv;
-
-	mutex_init(&state->mutex);
-
-	if (Read16(state, 0, 0, 0) < 0)
-		goto error;
-
-	memcpy(&state->frontend.ops, &drxd_ops,
-	       sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	ConfigureMPEGOutput(state, 0);
-	return &state->frontend;
-
-error:
-	printk(KERN_ERR "drxd: not found\n");
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(drxd_attach);
-
-MODULE_DESCRIPTION("DRXD driver");
-MODULE_AUTHOR("Micronas");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/drxd_map_firm.h b/drivers/media/dvb/frontends/drxd_map_firm.h
deleted file mode 100644
index 6bc553a..0000000
--- a/drivers/media/dvb/frontends/drxd_map_firm.h
+++ /dev/null
@@ -1,1013 +0,0 @@
-/*
- * drx3973d_map_firm.h
- *
- * Copyright (C) 2006-2007 Micronas
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#ifndef __DRX3973D_MAP__H__
-#define __DRX3973D_MAP__H__
-
-/*
- * Note: originally, this file contained 12000+ lines of data
- * Probably a few lines for every firwmare assembler instruction. However,
- * only a few defines were actually used. So, removed all uneeded lines.
- * If ever needed, the other lines can be easily obtained via git history.
- */
-
-#define HI_COMM_EXEC__A                                              0x400000
-#define HI_COMM_MB__A                                                0x400002
-#define HI_CT_REG_COMM_STATE__A                                      0x410001
-#define HI_RA_RAM_SRV_RES__A                                         0x420031
-#define HI_RA_RAM_SRV_CMD__A                                         0x420032
-#define   HI_RA_RAM_SRV_CMD_RESET                                    0x2
-#define   HI_RA_RAM_SRV_CMD_CONFIG                                   0x3
-#define   HI_RA_RAM_SRV_CMD_EXECUTE                                  0x6
-#define HI_RA_RAM_SRV_RST_KEY__A                                     0x420033
-#define   HI_RA_RAM_SRV_RST_KEY_ACT                                  0x3973
-#define HI_RA_RAM_SRV_CFG_KEY__A                                     0x420033
-#define HI_RA_RAM_SRV_CFG_DIV__A                                     0x420034
-#define HI_RA_RAM_SRV_CFG_BDL__A                                     0x420035
-#define HI_RA_RAM_SRV_CFG_WUP__A                                     0x420036
-#define HI_RA_RAM_SRV_CFG_ACT__A                                     0x420037
-#define     HI_RA_RAM_SRV_CFG_ACT_SLV0_ON                            0x1
-#define   HI_RA_RAM_SRV_CFG_ACT_BRD__M                               0x4
-#define     HI_RA_RAM_SRV_CFG_ACT_BRD_OFF                            0x0
-#define     HI_RA_RAM_SRV_CFG_ACT_BRD_ON                             0x4
-#define     HI_RA_RAM_SRV_CFG_ACT_PWD_EXE                            0x8
-#define HI_RA_RAM_USR_BEGIN__A                                       0x420040
-#define HI_IF_RAM_TRP_BPT0__AX                                       0x430000
-#define HI_IF_RAM_USR_BEGIN__A                                       0x430200
-#define SC_COMM_EXEC__A                                              0x800000
-#define     SC_COMM_EXEC_CTL_STOP                                    0x0
-#define SC_COMM_STATE__A                                             0x800001
-#define SC_RA_RAM_PARAM0__A                                          0x820040
-#define SC_RA_RAM_PARAM1__A                                          0x820041
-#define SC_RA_RAM_CMD_ADDR__A                                        0x820042
-#define SC_RA_RAM_CMD__A                                             0x820043
-#define   SC_RA_RAM_CMD_PROC_START                                   0x1
-#define   SC_RA_RAM_CMD_SET_PREF_PARAM                               0x3
-#define   SC_RA_RAM_CMD_GET_OP_PARAM                                 0x5
-#define   SC_RA_RAM_SW_EVENT_RUN_NMASK__M                            0x1
-#define   SC_RA_RAM_LOCKTRACK_MIN                                    0x1
-#define     SC_RA_RAM_OP_PARAM_MODE_2K                               0x0
-#define     SC_RA_RAM_OP_PARAM_MODE_8K                               0x1
-#define     SC_RA_RAM_OP_PARAM_GUARD_32                              0x0
-#define     SC_RA_RAM_OP_PARAM_GUARD_16                              0x4
-#define     SC_RA_RAM_OP_PARAM_GUARD_8                               0x8
-#define     SC_RA_RAM_OP_PARAM_GUARD_4                               0xC
-#define     SC_RA_RAM_OP_PARAM_CONST_QPSK                            0x0
-#define     SC_RA_RAM_OP_PARAM_CONST_QAM16                           0x10
-#define     SC_RA_RAM_OP_PARAM_CONST_QAM64                           0x20
-#define     SC_RA_RAM_OP_PARAM_HIER_NO                               0x0
-#define     SC_RA_RAM_OP_PARAM_HIER_A1                               0x40
-#define     SC_RA_RAM_OP_PARAM_HIER_A2                               0x80
-#define     SC_RA_RAM_OP_PARAM_HIER_A4                               0xC0
-#define     SC_RA_RAM_OP_PARAM_RATE_1_2                              0x0
-#define     SC_RA_RAM_OP_PARAM_RATE_2_3                              0x200
-#define     SC_RA_RAM_OP_PARAM_RATE_3_4                              0x400
-#define     SC_RA_RAM_OP_PARAM_RATE_5_6                              0x600
-#define     SC_RA_RAM_OP_PARAM_RATE_7_8                              0x800
-#define     SC_RA_RAM_OP_PARAM_PRIO_HI                               0x0
-#define     SC_RA_RAM_OP_PARAM_PRIO_LO                               0x1000
-#define   SC_RA_RAM_OP_AUTO_MODE__M                                  0x1
-#define   SC_RA_RAM_OP_AUTO_GUARD__M                                 0x2
-#define   SC_RA_RAM_OP_AUTO_CONST__M                                 0x4
-#define   SC_RA_RAM_OP_AUTO_HIER__M                                  0x8
-#define   SC_RA_RAM_OP_AUTO_RATE__M                                  0x10
-#define SC_RA_RAM_LOCK__A                                            0x82004B
-#define   SC_RA_RAM_LOCK_DEMOD__M                                    0x1
-#define   SC_RA_RAM_LOCK_FEC__M                                      0x2
-#define   SC_RA_RAM_LOCK_MPEG__M                                     0x4
-#define SC_RA_RAM_BE_OPT_ENA__A                                      0x82004C
-#define   SC_RA_RAM_BE_OPT_ENA_CP_OPT                                0x1
-#define SC_RA_RAM_BE_OPT_DELAY__A                                    0x82004D
-#define SC_RA_RAM_CONFIG__A                                          0x820050
-#define   SC_RA_RAM_CONFIG_FR_ENABLE__M                              0x4
-#define   SC_RA_RAM_CONFIG_FREQSCAN__M                               0x10
-#define   SC_RA_RAM_CONFIG_SLAVE__M                                  0x20
-#define SC_RA_RAM_IF_SAVE__AX                                        0x82008E
-#define SC_RA_RAM_IR_COARSE_2K_LENGTH__A                             0x8200D1
-#define SC_RA_RAM_IR_COARSE_2K_LENGTH__PRE                           0x9
-#define SC_RA_RAM_IR_COARSE_2K_FREQINC__A                            0x8200D2
-#define SC_RA_RAM_IR_COARSE_2K_FREQINC__PRE                          0x4
-#define SC_RA_RAM_IR_COARSE_2K_KAISINC__A                            0x8200D3
-#define SC_RA_RAM_IR_COARSE_2K_KAISINC__PRE                          0x100
-#define SC_RA_RAM_IR_COARSE_8K_LENGTH__A                             0x8200D4
-#define SC_RA_RAM_IR_COARSE_8K_LENGTH__PRE                           0x8
-#define SC_RA_RAM_IR_COARSE_8K_FREQINC__A                            0x8200D5
-#define SC_RA_RAM_IR_COARSE_8K_FREQINC__PRE                          0x8
-#define SC_RA_RAM_IR_COARSE_8K_KAISINC__A                            0x8200D6
-#define SC_RA_RAM_IR_COARSE_8K_KAISINC__PRE                          0x200
-#define SC_RA_RAM_IR_FINE_2K_LENGTH__A                               0x8200D7
-#define SC_RA_RAM_IR_FINE_2K_LENGTH__PRE                             0x9
-#define SC_RA_RAM_IR_FINE_2K_FREQINC__A                              0x8200D8
-#define SC_RA_RAM_IR_FINE_2K_FREQINC__PRE                            0x4
-#define SC_RA_RAM_IR_FINE_2K_KAISINC__A                              0x8200D9
-#define SC_RA_RAM_IR_FINE_2K_KAISINC__PRE                            0x100
-#define SC_RA_RAM_IR_FINE_8K_LENGTH__A                               0x8200DA
-#define SC_RA_RAM_IR_FINE_8K_LENGTH__PRE                             0xB
-#define SC_RA_RAM_IR_FINE_8K_FREQINC__A                              0x8200DB
-#define SC_RA_RAM_IR_FINE_8K_FREQINC__PRE                            0x1
-#define SC_RA_RAM_IR_FINE_8K_KAISINC__A                              0x8200DC
-#define SC_RA_RAM_IR_FINE_8K_KAISINC__PRE                            0x40
-#define SC_RA_RAM_ECHO_SHIFT_LIM__A                                  0x8200DD
-#define SC_RA_RAM_SAMPLE_RATE_COUNT__A                               0x8200E8
-#define SC_RA_RAM_SAMPLE_RATE_STEP__A                                0x8200E9
-#define SC_RA_RAM_BAND__A                                            0x8200EC
-#define SC_RA_RAM_LC_ABS_2K__A                                       0x8200F4
-#define SC_RA_RAM_LC_ABS_2K__PRE                                     0x1F
-#define SC_RA_RAM_LC_ABS_8K__A                                       0x8200F5
-#define SC_RA_RAM_LC_ABS_8K__PRE                                     0x1F
-#define SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE                        0x1D6
-#define SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE                        0x4
-#define SC_RA_RAM_EQ_IS_GAIN_QPSK_MAN__PRE                           0x1BB
-#define SC_RA_RAM_EQ_IS_GAIN_QPSK_EXP__PRE                           0x5
-#define SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE                          0x1EF
-#define SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE                          0x5
-#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_MAN__PRE                       0x15E
-#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_EXP__PRE                       0x5
-#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_MAN__PRE                       0x11A
-#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_EXP__PRE                       0x6
-#define SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE                          0x1FB
-#define SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE                          0x5
-#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_MAN__PRE                       0x12F
-#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_EXP__PRE                       0x5
-#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_MAN__PRE                       0x197
-#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_EXP__PRE                       0x5
-#define SC_RA_RAM_DRIVER_VERSION__AX                                 0x8201FE
-#define   SC_RA_RAM_PROC_LOCKTRACK                                   0x0
-#define FE_COMM_EXEC__A                                              0xC00000
-#define FE_AD_REG_COMM_EXEC__A                                       0xC10000
-#define FE_AD_REG_FDB_IN__A                                          0xC10012
-#define FE_AD_REG_PD__A                                              0xC10013
-#define FE_AD_REG_INVEXT__A                                          0xC10014
-#define FE_AD_REG_CLKNEG__A                                          0xC10015
-#define FE_AG_REG_COMM_EXEC__A                                       0xC20000
-#define FE_AG_REG_AG_MODE_LOP__A                                     0xC20010
-#define   FE_AG_REG_AG_MODE_LOP_MODE_4__M                            0x10
-#define     FE_AG_REG_AG_MODE_LOP_MODE_4_STATIC                      0x0
-#define     FE_AG_REG_AG_MODE_LOP_MODE_4_DYNAMIC                     0x10
-#define   FE_AG_REG_AG_MODE_LOP_MODE_5__M                            0x20
-#define     FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC                      0x0
-#define   FE_AG_REG_AG_MODE_LOP_MODE_C__M                            0x1000
-#define     FE_AG_REG_AG_MODE_LOP_MODE_C_STATIC                      0x0
-#define     FE_AG_REG_AG_MODE_LOP_MODE_C_DYNAMIC                     0x1000
-#define   FE_AG_REG_AG_MODE_LOP_MODE_E__M                            0x4000
-#define     FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC                      0x0
-#define     FE_AG_REG_AG_MODE_LOP_MODE_E_DYNAMIC                     0x4000
-#define FE_AG_REG_AG_MODE_HIP__A                                     0xC20011
-#define FE_AG_REG_AG_PGA_MODE__A                                     0xC20012
-#define   FE_AG_REG_AG_PGA_MODE_PFY_PCY_AFY_REN                      0x0
-#define   FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN                      0x1
-#define FE_AG_REG_AG_AGC_SIO__A                                      0xC20013
-#define   FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M                          0x2
-#define     FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT                    0x0
-#define     FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_INPUT                     0x2
-#define FE_AG_REG_AG_PWD__A                                          0xC20015
-#define   FE_AG_REG_AG_PWD_PWD_PD2__M                                0x2
-#define     FE_AG_REG_AG_PWD_PWD_PD2_DISABLE                         0x0
-#define     FE_AG_REG_AG_PWD_PWD_PD2_ENABLE                          0x2
-#define FE_AG_REG_DCE_AUR_CNT__A                                     0xC20016
-#define FE_AG_REG_DCE_RUR_CNT__A                                     0xC20017
-#define FE_AG_REG_ACE_AUR_CNT__A                                     0xC2001A
-#define FE_AG_REG_ACE_RUR_CNT__A                                     0xC2001B
-#define FE_AG_REG_CDR_RUR_CNT__A                                     0xC20020
-#define FE_AG_REG_EGC_RUR_CNT__A                                     0xC20024
-#define FE_AG_REG_EGC_SET_LVL__A                                     0xC20025
-#define FE_AG_REG_EGC_SET_LVL__M                                     0x1FF
-#define FE_AG_REG_EGC_FLA_RGN__A                                     0xC20026
-#define FE_AG_REG_EGC_SLO_RGN__A                                     0xC20027
-#define FE_AG_REG_EGC_JMP_PSN__A                                     0xC20028
-#define FE_AG_REG_EGC_FLA_INC__A                                     0xC20029
-#define FE_AG_REG_EGC_FLA_DEC__A                                     0xC2002A
-#define FE_AG_REG_EGC_SLO_INC__A                                     0xC2002B
-#define FE_AG_REG_EGC_SLO_DEC__A                                     0xC2002C
-#define FE_AG_REG_EGC_FAS_INC__A                                     0xC2002D
-#define FE_AG_REG_EGC_FAS_DEC__A                                     0xC2002E
-#define FE_AG_REG_PM1_AGC_WRI__A                                     0xC20030
-#define FE_AG_REG_PM1_AGC_WRI__M                                     0x7FF
-#define FE_AG_REG_GC1_AGC_RIC__A                                     0xC20031
-#define FE_AG_REG_GC1_AGC_OFF__A                                     0xC20032
-#define FE_AG_REG_GC1_AGC_MAX__A                                     0xC20033
-#define FE_AG_REG_GC1_AGC_MIN__A                                     0xC20034
-#define FE_AG_REG_GC1_AGC_DAT__A                                     0xC20035
-#define FE_AG_REG_GC1_AGC_DAT__M                                     0x3FF
-#define FE_AG_REG_PM2_AGC_WRI__A                                     0xC20036
-#define FE_AG_REG_IND_WIN__A                                         0xC2003C
-#define FE_AG_REG_IND_THD_LOL__A                                     0xC2003D
-#define FE_AG_REG_IND_THD_HIL__A                                     0xC2003E
-#define FE_AG_REG_IND_DEL__A                                         0xC2003F
-#define FE_AG_REG_IND_PD1_WRI__A                                     0xC20040
-#define FE_AG_REG_PDA_AUR_CNT__A                                     0xC20041
-#define FE_AG_REG_PDA_RUR_CNT__A                                     0xC20042
-#define FE_AG_REG_PDA_AVE_DAT__A                                     0xC20043
-#define FE_AG_REG_PDC_RUR_CNT__A                                     0xC20044
-#define FE_AG_REG_PDC_SET_LVL__A                                     0xC20045
-#define FE_AG_REG_PDC_FLA_RGN__A                                     0xC20046
-#define FE_AG_REG_PDC_JMP_PSN__A                                     0xC20047
-#define FE_AG_REG_PDC_FLA_STP__A                                     0xC20048
-#define FE_AG_REG_PDC_SLO_STP__A                                     0xC20049
-#define FE_AG_REG_PDC_PD2_WRI__A                                     0xC2004A
-#define FE_AG_REG_PDC_MAP_DAT__A                                     0xC2004B
-#define FE_AG_REG_PDC_MAX__A                                         0xC2004C
-#define FE_AG_REG_TGA_AUR_CNT__A                                     0xC2004D
-#define FE_AG_REG_TGA_RUR_CNT__A                                     0xC2004E
-#define FE_AG_REG_TGA_AVE_DAT__A                                     0xC2004F
-#define FE_AG_REG_TGC_RUR_CNT__A                                     0xC20050
-#define FE_AG_REG_TGC_SET_LVL__A                                     0xC20051
-#define FE_AG_REG_TGC_SET_LVL__M                                     0x3F
-#define FE_AG_REG_TGC_FLA_RGN__A                                     0xC20052
-#define FE_AG_REG_TGC_JMP_PSN__A                                     0xC20053
-#define FE_AG_REG_TGC_FLA_STP__A                                     0xC20054
-#define FE_AG_REG_TGC_SLO_STP__A                                     0xC20055
-#define FE_AG_REG_TGC_MAP_DAT__A                                     0xC20056
-#define FE_AG_REG_FGA_AUR_CNT__A                                     0xC20057
-#define FE_AG_REG_FGA_RUR_CNT__A                                     0xC20058
-#define FE_AG_REG_FGM_WRI__A                                         0xC20061
-#define FE_AG_REG_BGC_FGC_WRI__A                                     0xC20068
-#define FE_AG_REG_BGC_CGC_WRI__A                                     0xC20069
-#define FE_FS_REG_COMM_EXEC__A                                       0xC30000
-#define FE_FS_REG_ADD_INC_LOP__A                                     0xC30010
-#define FE_FD_REG_COMM_EXEC__A                                       0xC40000
-#define FE_FD_REG_SCL__A                                             0xC40010
-#define FE_FD_REG_MAX_LEV__A                                         0xC40011
-#define FE_FD_REG_NR__A                                              0xC40012
-#define FE_FD_REG_MEAS_VAL__A                                        0xC40014
-#define FE_IF_REG_COMM_EXEC__A                                       0xC50000
-#define FE_IF_REG_INCR0__A                                           0xC50010
-#define FE_IF_REG_INCR0__W                                           16
-#define FE_IF_REG_INCR0__M                                           0xFFFF
-#define FE_IF_REG_INCR1__A                                           0xC50011
-#define FE_IF_REG_INCR1__M                                           0xFF
-#define FE_CF_REG_COMM_EXEC__A                                       0xC60000
-#define FE_CF_REG_SCL__A                                             0xC60010
-#define FE_CF_REG_MAX_LEV__A                                         0xC60011
-#define FE_CF_REG_NR__A                                              0xC60012
-#define FE_CF_REG_IMP_VAL__A                                         0xC60013
-#define FE_CF_REG_MEAS_VAL__A                                        0xC60014
-#define FE_CU_REG_COMM_EXEC__A                                       0xC70000
-#define FE_CU_REG_FRM_CNT_RST__A                                     0xC70011
-#define FE_CU_REG_FRM_CNT_STR__A                                     0xC70012
-#define FT_COMM_EXEC__A                                              0x1000000
-#define FT_REG_COMM_EXEC__A                                          0x1010000
-#define CP_COMM_EXEC__A                                              0x1400000
-#define CP_REG_COMM_EXEC__A                                          0x1410000
-#define CP_REG_INTERVAL__A                                           0x1410011
-#define CP_REG_BR_SPL_OFFSET__A                                      0x1410023
-#define CP_REG_BR_STR_DEL__A                                         0x1410024
-#define CP_REG_RT_ANG_INC0__A                                        0x1410030
-#define CP_REG_RT_ANG_INC1__A                                        0x1410031
-#define CP_REG_RT_DETECT_ENA__A                                      0x1410032
-#define CP_REG_RT_DETECT_TRH__A                                      0x1410033
-#define CP_REG_RT_EXP_MARG__A                                        0x141003E
-#define CP_REG_AC_NEXP_OFFS__A                                       0x1410040
-#define CP_REG_AC_AVER_POW__A                                        0x1410041
-#define CP_REG_AC_MAX_POW__A                                         0x1410042
-#define CP_REG_AC_WEIGHT_MAN__A                                      0x1410043
-#define CP_REG_AC_WEIGHT_EXP__A                                      0x1410044
-#define CP_REG_AC_AMP_MODE__A                                        0x1410047
-#define CP_REG_AC_AMP_FIX__A                                         0x1410048
-#define CP_REG_AC_ANG_MODE__A                                        0x141004A
-#define CE_COMM_EXEC__A                                              0x1800000
-#define CE_REG_COMM_EXEC__A                                          0x1810000
-#define CE_REG_TAPSET__A                                             0x1810011
-#define CE_REG_AVG_POW__A                                            0x1810012
-#define CE_REG_MAX_POW__A                                            0x1810013
-#define CE_REG_ATT__A                                                0x1810014
-#define CE_REG_NRED__A                                               0x1810015
-#define CE_REG_NE_ERR_SELECT__A                                      0x1810043
-#define CE_REG_NE_TD_CAL__A                                          0x1810044
-#define CE_REG_NE_MIXAVG__A                                          0x1810046
-#define CE_REG_NE_NUPD_OFS__A                                        0x1810047
-#define CE_REG_PE_NEXP_OFFS__A                                       0x1810050
-#define CE_REG_PE_TIMESHIFT__A                                       0x1810051
-#define CE_REG_TP_A0_TAP_NEW__A                                      0x1810064
-#define CE_REG_TP_A0_TAP_NEW_VALID__A                                0x1810065
-#define CE_REG_TP_A0_MU_LMS_STEP__A                                  0x1810066
-#define CE_REG_TP_A1_TAP_NEW__A                                      0x1810068
-#define CE_REG_TP_A1_TAP_NEW_VALID__A                                0x1810069
-#define CE_REG_TP_A1_MU_LMS_STEP__A                                  0x181006A
-#define CE_REG_TI_NEXP_OFFS__A                                       0x1810070
-#define CE_REG_FI_SHT_INCR__A                                        0x1810090
-#define CE_REG_FI_EXP_NORM__A                                        0x1810091
-#define CE_REG_IR_INPUTSEL__A                                        0x18100A0
-#define CE_REG_IR_STARTPOS__A                                        0x18100A1
-#define CE_REG_IR_NEXP_THRES__A                                      0x18100A2
-#define CE_REG_FR_TREAL00__A                                         0x1820010
-#define CE_REG_FR_TIMAG00__A                                         0x1820011
-#define CE_REG_FR_TREAL01__A                                         0x1820012
-#define CE_REG_FR_TIMAG01__A                                         0x1820013
-#define CE_REG_FR_TREAL02__A                                         0x1820014
-#define CE_REG_FR_TIMAG02__A                                         0x1820015
-#define CE_REG_FR_TREAL03__A                                         0x1820016
-#define CE_REG_FR_TIMAG03__A                                         0x1820017
-#define CE_REG_FR_TREAL04__A                                         0x1820018
-#define CE_REG_FR_TIMAG04__A                                         0x1820019
-#define CE_REG_FR_TREAL05__A                                         0x182001A
-#define CE_REG_FR_TIMAG05__A                                         0x182001B
-#define CE_REG_FR_TREAL06__A                                         0x182001C
-#define CE_REG_FR_TIMAG06__A                                         0x182001D
-#define CE_REG_FR_TREAL07__A                                         0x182001E
-#define CE_REG_FR_TIMAG07__A                                         0x182001F
-#define CE_REG_FR_TREAL08__A                                         0x1820020
-#define CE_REG_FR_TIMAG08__A                                         0x1820021
-#define CE_REG_FR_TREAL09__A                                         0x1820022
-#define CE_REG_FR_TIMAG09__A                                         0x1820023
-#define CE_REG_FR_TREAL10__A                                         0x1820024
-#define CE_REG_FR_TIMAG10__A                                         0x1820025
-#define CE_REG_FR_TREAL11__A                                         0x1820026
-#define CE_REG_FR_TIMAG11__A                                         0x1820027
-#define CE_REG_FR_MID_TAP__A                                         0x1820028
-#define CE_REG_FR_SQS_G00__A                                         0x1820029
-#define CE_REG_FR_SQS_G01__A                                         0x182002A
-#define CE_REG_FR_SQS_G02__A                                         0x182002B
-#define CE_REG_FR_SQS_G03__A                                         0x182002C
-#define CE_REG_FR_SQS_G04__A                                         0x182002D
-#define CE_REG_FR_SQS_G05__A                                         0x182002E
-#define CE_REG_FR_SQS_G06__A                                         0x182002F
-#define CE_REG_FR_SQS_G07__A                                         0x1820030
-#define CE_REG_FR_SQS_G08__A                                         0x1820031
-#define CE_REG_FR_SQS_G09__A                                         0x1820032
-#define CE_REG_FR_SQS_G10__A                                         0x1820033
-#define CE_REG_FR_SQS_G11__A                                         0x1820034
-#define CE_REG_FR_SQS_G12__A                                         0x1820035
-#define CE_REG_FR_RIO_G00__A                                         0x1820036
-#define CE_REG_FR_RIO_G01__A                                         0x1820037
-#define CE_REG_FR_RIO_G02__A                                         0x1820038
-#define CE_REG_FR_RIO_G03__A                                         0x1820039
-#define CE_REG_FR_RIO_G04__A                                         0x182003A
-#define CE_REG_FR_RIO_G05__A                                         0x182003B
-#define CE_REG_FR_RIO_G06__A                                         0x182003C
-#define CE_REG_FR_RIO_G07__A                                         0x182003D
-#define CE_REG_FR_RIO_G08__A                                         0x182003E
-#define CE_REG_FR_RIO_G09__A                                         0x182003F
-#define CE_REG_FR_RIO_G10__A                                         0x1820040
-#define CE_REG_FR_MODE__A                                            0x1820041
-#define CE_REG_FR_SQS_TRH__A                                         0x1820042
-#define CE_REG_FR_RIO_GAIN__A                                        0x1820043
-#define CE_REG_FR_BYPASS__A                                          0x1820044
-#define CE_REG_FR_PM_SET__A                                          0x1820045
-#define CE_REG_FR_ERR_SH__A                                          0x1820046
-#define CE_REG_FR_MAN_SH__A                                          0x1820047
-#define CE_REG_FR_TAP_SH__A                                          0x1820048
-#define EQ_COMM_EXEC__A                                              0x1C00000
-#define EQ_REG_COMM_EXEC__A                                          0x1C10000
-#define EQ_REG_COMM_MB__A                                            0x1C10002
-#define EQ_REG_IS_GAIN_MAN__A                                        0x1C10015
-#define EQ_REG_IS_GAIN_EXP__A                                        0x1C10016
-#define EQ_REG_IS_CLIP_EXP__A                                        0x1C10017
-#define EQ_REG_SN_CEGAIN__A                                          0x1C1002A
-#define EQ_REG_SN_OFFSET__A                                          0x1C1002B
-#define EQ_REG_RC_SEL_CAR__A                                         0x1C10032
-#define   EQ_REG_RC_SEL_CAR_INIT                                     0x0
-#define     EQ_REG_RC_SEL_CAR_DIV_ON                                 0x1
-#define     EQ_REG_RC_SEL_CAR_PASS_A_CC                              0x0
-#define     EQ_REG_RC_SEL_CAR_PASS_B_CE                              0x2
-#define     EQ_REG_RC_SEL_CAR_LOCAL_A_CC                             0x0
-#define     EQ_REG_RC_SEL_CAR_LOCAL_B_CE                             0x8
-#define     EQ_REG_RC_SEL_CAR_MEAS_A_CC                              0x0
-#define     EQ_REG_RC_SEL_CAR_MEAS_B_CE                              0x20
-#define EQ_REG_OT_CONST__A                                           0x1C10046
-#define EQ_REG_OT_ALPHA__A                                           0x1C10047
-#define EQ_REG_OT_QNT_THRES0__A                                      0x1C10048
-#define EQ_REG_OT_QNT_THRES1__A                                      0x1C10049
-#define EQ_REG_OT_CSI_STEP__A                                        0x1C1004A
-#define EQ_REG_OT_CSI_OFFSET__A                                      0x1C1004B
-#define EQ_REG_TD_REQ_SMB_CNT__A                                     0x1C10061
-#define EQ_REG_TD_TPS_PWR_OFS__A                                     0x1C10062
-#define EC_SB_REG_COMM_EXEC__A                                       0x2010000
-#define EC_SB_REG_TR_MODE__A                                         0x2010010
-#define   EC_SB_REG_TR_MODE_8K                                       0x0
-#define   EC_SB_REG_TR_MODE_2K                                       0x1
-#define EC_SB_REG_CONST__A                                           0x2010011
-#define   EC_SB_REG_CONST_QPSK                                       0x0
-#define   EC_SB_REG_CONST_16QAM                                      0x1
-#define   EC_SB_REG_CONST_64QAM                                      0x2
-#define EC_SB_REG_ALPHA__A                                           0x2010012
-#define EC_SB_REG_PRIOR__A                                           0x2010013
-#define   EC_SB_REG_PRIOR_HI                                         0x0
-#define   EC_SB_REG_PRIOR_LO                                         0x1
-#define EC_SB_REG_CSI_HI__A                                          0x2010014
-#define EC_SB_REG_CSI_LO__A                                          0x2010015
-#define EC_SB_REG_SMB_TGL__A                                         0x2010016
-#define EC_SB_REG_SNR_HI__A                                          0x2010017
-#define EC_SB_REG_SNR_MID__A                                         0x2010018
-#define EC_SB_REG_SNR_LO__A                                          0x2010019
-#define EC_SB_REG_SCALE_MSB__A                                       0x201001A
-#define EC_SB_REG_SCALE_BIT2__A                                      0x201001B
-#define EC_SB_REG_SCALE_LSB__A                                       0x201001C
-#define EC_SB_REG_CSI_OFS__A                                         0x201001D
-#define EC_VD_REG_COMM_EXEC__A                                       0x2090000
-#define EC_VD_REG_FORCE__A                                           0x2090010
-#define EC_VD_REG_SET_CODERATE__A                                    0x2090011
-#define   EC_VD_REG_SET_CODERATE_C1_2                                0x0
-#define   EC_VD_REG_SET_CODERATE_C2_3                                0x1
-#define   EC_VD_REG_SET_CODERATE_C3_4                                0x2
-#define   EC_VD_REG_SET_CODERATE_C5_6                                0x3
-#define   EC_VD_REG_SET_CODERATE_C7_8                                0x4
-#define EC_VD_REG_REQ_SMB_CNT__A                                     0x2090012
-#define EC_VD_REG_RLK_ENA__A                                         0x2090014
-#define EC_OD_REG_COMM_EXEC__A                                       0x2110000
-#define EC_OD_REG_SYNC__A                                            0x2110010
-#define EC_OD_DEINT_RAM__A                                           0x2120000
-#define EC_RS_REG_COMM_EXEC__A                                       0x2130000
-#define EC_RS_REG_REQ_PCK_CNT__A                                     0x2130010
-#define EC_RS_REG_VAL__A                                             0x2130011
-#define   EC_RS_REG_VAL_PCK                                          0x1
-#define EC_RS_EC_RAM__A                                              0x2140000
-#define EC_OC_REG_COMM_EXEC__A                                       0x2150000
-#define     EC_OC_REG_COMM_EXEC_CTL_ACTIVE                           0x1
-#define     EC_OC_REG_COMM_EXEC_CTL_HOLD                             0x2
-#define EC_OC_REG_COMM_INT_STA__A                                    0x2150007
-#define EC_OC_REG_OC_MODE_LOP__A                                     0x2150010
-#define   EC_OC_REG_OC_MODE_LOP_PAR_ENA__M                           0x1
-#define     EC_OC_REG_OC_MODE_LOP_PAR_ENA_ENABLE                     0x0
-#define     EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE                    0x1
-#define   EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC__M                       0x4
-#define     EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC_STATIC                 0x0
-#define   EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE__M                       0x80
-#define     EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE_SERIAL                 0x80
-#define EC_OC_REG_OC_MODE_HIP__A                                     0x2150011
-#define     EC_OC_REG_OC_MODE_HIP_MPG_BUS_SRC_MONITOR                0x10
-#define   EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M                       0x200
-#define     EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_DISABLE                0x0
-#define     EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_ENABLE                 0x200
-#define EC_OC_REG_OC_MPG_SIO__A                                      0x2150012
-#define EC_OC_REG_OC_MPG_SIO__M                                      0xFFF
-#define EC_OC_REG_OC_MON_SIO__A                                      0x2150013
-#define EC_OC_REG_DTO_INC_LOP__A                                     0x2150014
-#define EC_OC_REG_DTO_INC_HIP__A                                     0x2150015
-#define EC_OC_REG_SNC_ISC_LVL__A                                     0x2150016
-#define   EC_OC_REG_SNC_ISC_LVL_OSC__M                               0xF0
-#define EC_OC_REG_TMD_TOP_MODE__A                                    0x215001D
-#define EC_OC_REG_TMD_TOP_CNT__A                                     0x215001E
-#define EC_OC_REG_TMD_HIL_MAR__A                                     0x215001F
-#define EC_OC_REG_TMD_LOL_MAR__A                                     0x2150020
-#define EC_OC_REG_TMD_CUR_CNT__A                                     0x2150021
-#define EC_OC_REG_AVR_ASH_CNT__A                                     0x2150023
-#define EC_OC_REG_AVR_BSH_CNT__A                                     0x2150024
-#define EC_OC_REG_RCN_MODE__A                                        0x2150027
-#define EC_OC_REG_RCN_CRA_LOP__A                                     0x2150028
-#define EC_OC_REG_RCN_CRA_HIP__A                                     0x2150029
-#define EC_OC_REG_RCN_CST_LOP__A                                     0x215002A
-#define EC_OC_REG_RCN_CST_HIP__A                                     0x215002B
-#define EC_OC_REG_RCN_SET_LVL__A                                     0x215002C
-#define EC_OC_REG_RCN_GAI_LVL__A                                     0x215002D
-#define EC_OC_REG_RCN_CLP_LOP__A                                     0x2150032
-#define EC_OC_REG_RCN_CLP_HIP__A                                     0x2150033
-#define EC_OC_REG_RCN_MAP_LOP__A                                     0x2150034
-#define EC_OC_REG_RCN_MAP_HIP__A                                     0x2150035
-#define EC_OC_REG_OCR_MPG_UOS__A                                     0x2150036
-#define EC_OC_REG_OCR_MPG_UOS__M                                     0xFFF
-#define   EC_OC_REG_OCR_MPG_UOS_INIT                                 0x0
-#define EC_OC_REG_OCR_MPG_USR_DAT__A                                 0x2150038
-#define EC_OC_REG_OCR_MON_UOS__A                                     0x2150039
-#define     EC_OC_REG_OCR_MON_UOS_DAT_0_ENABLE                       0x1
-#define     EC_OC_REG_OCR_MON_UOS_DAT_1_ENABLE                       0x2
-#define     EC_OC_REG_OCR_MON_UOS_DAT_2_ENABLE                       0x4
-#define     EC_OC_REG_OCR_MON_UOS_DAT_3_ENABLE                       0x8
-#define     EC_OC_REG_OCR_MON_UOS_DAT_4_ENABLE                       0x10
-#define     EC_OC_REG_OCR_MON_UOS_DAT_5_ENABLE                       0x20
-#define     EC_OC_REG_OCR_MON_UOS_DAT_6_ENABLE                       0x40
-#define     EC_OC_REG_OCR_MON_UOS_DAT_7_ENABLE                       0x80
-#define     EC_OC_REG_OCR_MON_UOS_DAT_8_ENABLE                       0x100
-#define     EC_OC_REG_OCR_MON_UOS_DAT_9_ENABLE                       0x200
-#define     EC_OC_REG_OCR_MON_UOS_VAL_ENABLE                         0x400
-#define     EC_OC_REG_OCR_MON_UOS_CLK_ENABLE                         0x800
-#define EC_OC_REG_OCR_MON_WRI__A                                     0x215003A
-#define   EC_OC_REG_OCR_MON_WRI_INIT                                 0x0
-#define EC_OC_REG_IPR_INV_MPG__A                                     0x2150045
-#define CC_REG_OSC_MODE__A                                           0x2410010
-#define   CC_REG_OSC_MODE_M20                                        0x1
-#define CC_REG_PLL_MODE__A                                           0x2410011
-#define     CC_REG_PLL_MODE_BYPASS_PLL                               0x1
-#define     CC_REG_PLL_MODE_PUMP_CUR_12                              0x14
-#define CC_REG_REF_DIVIDE__A                                         0x2410012
-#define CC_REG_PWD_MODE__A                                           0x2410015
-#define   CC_REG_PWD_MODE_DOWN_PLL                                   0x2
-#define CC_REG_UPDATE__A                                             0x2410017
-#define   CC_REG_UPDATE_KEY                                          0x3973
-#define CC_REG_JTAGID_L__A                                           0x2410019
-#define LC_COMM_EXEC__A                                              0x2800000
-#define LC_RA_RAM_IFINCR_NOM_L__A                                    0x282000C
-#define LC_RA_RAM_FILTER_SYM_SET__A                                  0x282001A
-#define LC_RA_RAM_FILTER_SYM_SET__PRE                                0x3E8
-#define LC_RA_RAM_FILTER_CRMM_A__A                                   0x2820060
-#define LC_RA_RAM_FILTER_CRMM_A__PRE                                 0x4
-#define LC_RA_RAM_FILTER_CRMM_B__A                                   0x2820061
-#define LC_RA_RAM_FILTER_CRMM_B__PRE                                 0x1
-#define LC_RA_RAM_FILTER_SRMM_A__A                                   0x2820068
-#define LC_RA_RAM_FILTER_SRMM_A__PRE                                 0x4
-#define LC_RA_RAM_FILTER_SRMM_B__A                                   0x2820069
-#define LC_RA_RAM_FILTER_SRMM_B__PRE                                 0x1
-#define B_HI_COMM_EXEC__A                                            0x400000
-#define B_HI_COMM_MB__A                                              0x400002
-#define B_HI_CT_REG_COMM_STATE__A                                    0x410001
-#define B_HI_RA_RAM_SRV_RES__A                                       0x420031
-#define B_HI_RA_RAM_SRV_CMD__A                                       0x420032
-#define   B_HI_RA_RAM_SRV_CMD_RESET                                  0x2
-#define   B_HI_RA_RAM_SRV_CMD_CONFIG                                 0x3
-#define   B_HI_RA_RAM_SRV_CMD_EXECUTE                                0x6
-#define B_HI_RA_RAM_SRV_RST_KEY__A                                   0x420033
-#define   B_HI_RA_RAM_SRV_RST_KEY_ACT                                0x3973
-#define B_HI_RA_RAM_SRV_CFG_KEY__A                                   0x420033
-#define B_HI_RA_RAM_SRV_CFG_DIV__A                                   0x420034
-#define B_HI_RA_RAM_SRV_CFG_BDL__A                                   0x420035
-#define B_HI_RA_RAM_SRV_CFG_WUP__A                                   0x420036
-#define B_HI_RA_RAM_SRV_CFG_ACT__A                                   0x420037
-#define     B_HI_RA_RAM_SRV_CFG_ACT_SLV0_ON                          0x1
-#define   B_HI_RA_RAM_SRV_CFG_ACT_BRD__M                             0x4
-#define     B_HI_RA_RAM_SRV_CFG_ACT_BRD_OFF                          0x0
-#define     B_HI_RA_RAM_SRV_CFG_ACT_BRD_ON                           0x4
-#define     B_HI_RA_RAM_SRV_CFG_ACT_PWD_EXE                          0x8
-#define B_HI_RA_RAM_USR_BEGIN__A                                     0x420040
-#define B_HI_IF_RAM_TRP_BPT0__AX                                     0x430000
-#define B_HI_IF_RAM_USR_BEGIN__A                                     0x430200
-#define B_SC_COMM_EXEC__A                                            0x800000
-#define     B_SC_COMM_EXEC_CTL_STOP                                  0x0
-#define B_SC_COMM_STATE__A                                           0x800001
-#define B_SC_RA_RAM_PARAM0__A                                        0x820040
-#define B_SC_RA_RAM_PARAM1__A                                        0x820041
-#define B_SC_RA_RAM_CMD_ADDR__A                                      0x820042
-#define B_SC_RA_RAM_CMD__A                                           0x820043
-#define   B_SC_RA_RAM_CMD_PROC_START                                 0x1
-#define   B_SC_RA_RAM_CMD_SET_PREF_PARAM                             0x3
-#define   B_SC_RA_RAM_CMD_GET_OP_PARAM                               0x5
-#define   B_SC_RA_RAM_SW_EVENT_RUN_NMASK__M                          0x1
-#define   B_SC_RA_RAM_LOCKTRACK_MIN                                  0x1
-#define     B_SC_RA_RAM_OP_PARAM_MODE_2K                             0x0
-#define     B_SC_RA_RAM_OP_PARAM_MODE_8K                             0x1
-#define     B_SC_RA_RAM_OP_PARAM_GUARD_32                            0x0
-#define     B_SC_RA_RAM_OP_PARAM_GUARD_16                            0x4
-#define     B_SC_RA_RAM_OP_PARAM_GUARD_8                             0x8
-#define     B_SC_RA_RAM_OP_PARAM_GUARD_4                             0xC
-#define     B_SC_RA_RAM_OP_PARAM_CONST_QPSK                          0x0
-#define     B_SC_RA_RAM_OP_PARAM_CONST_QAM16                         0x10
-#define     B_SC_RA_RAM_OP_PARAM_CONST_QAM64                         0x20
-#define     B_SC_RA_RAM_OP_PARAM_HIER_NO                             0x0
-#define     B_SC_RA_RAM_OP_PARAM_HIER_A1                             0x40
-#define     B_SC_RA_RAM_OP_PARAM_HIER_A2                             0x80
-#define     B_SC_RA_RAM_OP_PARAM_HIER_A4                             0xC0
-#define     B_SC_RA_RAM_OP_PARAM_RATE_1_2                            0x0
-#define     B_SC_RA_RAM_OP_PARAM_RATE_2_3                            0x200
-#define     B_SC_RA_RAM_OP_PARAM_RATE_3_4                            0x400
-#define     B_SC_RA_RAM_OP_PARAM_RATE_5_6                            0x600
-#define     B_SC_RA_RAM_OP_PARAM_RATE_7_8                            0x800
-#define     B_SC_RA_RAM_OP_PARAM_PRIO_HI                             0x0
-#define     B_SC_RA_RAM_OP_PARAM_PRIO_LO                             0x1000
-#define   B_SC_RA_RAM_OP_AUTO_MODE__M                                0x1
-#define   B_SC_RA_RAM_OP_AUTO_GUARD__M                               0x2
-#define   B_SC_RA_RAM_OP_AUTO_CONST__M                               0x4
-#define   B_SC_RA_RAM_OP_AUTO_HIER__M                                0x8
-#define   B_SC_RA_RAM_OP_AUTO_RATE__M                                0x10
-#define B_SC_RA_RAM_LOCK__A                                          0x82004B
-#define   B_SC_RA_RAM_LOCK_DEMOD__M                                  0x1
-#define   B_SC_RA_RAM_LOCK_FEC__M                                    0x2
-#define   B_SC_RA_RAM_LOCK_MPEG__M                                   0x4
-#define B_SC_RA_RAM_BE_OPT_ENA__A                                    0x82004C
-#define   B_SC_RA_RAM_BE_OPT_ENA_CP_OPT                              0x1
-#define B_SC_RA_RAM_BE_OPT_DELAY__A                                  0x82004D
-#define B_SC_RA_RAM_CONFIG__A                                        0x820050
-#define   B_SC_RA_RAM_CONFIG_FR_ENABLE__M                            0x4
-#define   B_SC_RA_RAM_CONFIG_FREQSCAN__M                             0x10
-#define   B_SC_RA_RAM_CONFIG_SLAVE__M                                0x20
-#define   B_SC_RA_RAM_CONFIG_DIV_BLANK_ENABLE__M                     0x200
-#define   B_SC_RA_RAM_CONFIG_DIV_ECHO_ENABLE__M                      0x400
-#define B_SC_RA_RAM_CO_TD_CAL_2K__A                                  0x82005D
-#define B_SC_RA_RAM_CO_TD_CAL_8K__A                                  0x82005E
-#define B_SC_RA_RAM_IF_SAVE__AX                                      0x82008E
-#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_32__A                         0x820098
-#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_16__A                         0x820099
-#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_8__A                          0x82009A
-#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_4__A                          0x82009B
-#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_32__A                         0x82009C
-#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_16__A                         0x82009D
-#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_8__A                          0x82009E
-#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_4__A                          0x82009F
-#define B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A                           0x8200D1
-#define B_SC_RA_RAM_IR_COARSE_2K_LENGTH__PRE                         0x9
-#define B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A                          0x8200D2
-#define B_SC_RA_RAM_IR_COARSE_2K_FREQINC__PRE                        0x4
-#define B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A                          0x8200D3
-#define B_SC_RA_RAM_IR_COARSE_2K_KAISINC__PRE                        0x100
-#define B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A                           0x8200D4
-#define B_SC_RA_RAM_IR_COARSE_8K_LENGTH__PRE                         0x8
-#define B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A                          0x8200D5
-#define B_SC_RA_RAM_IR_COARSE_8K_FREQINC__PRE                        0x8
-#define B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A                          0x8200D6
-#define B_SC_RA_RAM_IR_COARSE_8K_KAISINC__PRE                        0x200
-#define B_SC_RA_RAM_IR_FINE_2K_LENGTH__A                             0x8200D7
-#define B_SC_RA_RAM_IR_FINE_2K_LENGTH__PRE                           0x9
-#define B_SC_RA_RAM_IR_FINE_2K_FREQINC__A                            0x8200D8
-#define B_SC_RA_RAM_IR_FINE_2K_FREQINC__PRE                          0x4
-#define B_SC_RA_RAM_IR_FINE_2K_KAISINC__A                            0x8200D9
-#define B_SC_RA_RAM_IR_FINE_2K_KAISINC__PRE                          0x100
-#define B_SC_RA_RAM_IR_FINE_8K_LENGTH__A                             0x8200DA
-#define B_SC_RA_RAM_IR_FINE_8K_LENGTH__PRE                           0xB
-#define B_SC_RA_RAM_IR_FINE_8K_FREQINC__A                            0x8200DB
-#define B_SC_RA_RAM_IR_FINE_8K_FREQINC__PRE                          0x1
-#define B_SC_RA_RAM_IR_FINE_8K_KAISINC__A                            0x8200DC
-#define B_SC_RA_RAM_IR_FINE_8K_KAISINC__PRE                          0x40
-#define B_SC_RA_RAM_ECHO_SHIFT_LIM__A                                0x8200DD
-#define B_SC_RA_RAM_SAMPLE_RATE_COUNT__A                             0x8200E8
-#define B_SC_RA_RAM_SAMPLE_RATE_STEP__A                              0x8200E9
-#define B_SC_RA_RAM_BAND__A                                          0x8200EC
-#define B_SC_RA_RAM_LC_ABS_2K__A                                     0x8200F4
-#define B_SC_RA_RAM_LC_ABS_2K__PRE                                   0x1F
-#define B_SC_RA_RAM_LC_ABS_8K__A                                     0x8200F5
-#define B_SC_RA_RAM_LC_ABS_8K__PRE                                   0x1F
-#define B_SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE                      0x100
-#define B_SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE                      0x4
-#define B_SC_RA_RAM_EQ_IS_GAIN_QPSK_MAN__PRE                         0x1E2
-#define B_SC_RA_RAM_EQ_IS_GAIN_QPSK_EXP__PRE                         0x4
-#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE                        0x10D
-#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE                        0x5
-#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_MAN__PRE                     0x17D
-#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_EXP__PRE                     0x4
-#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_MAN__PRE                     0x133
-#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_EXP__PRE                     0x5
-#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE                        0x114
-#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE                        0x5
-#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_MAN__PRE                     0x14A
-#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_EXP__PRE                     0x4
-#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_MAN__PRE                     0x1BB
-#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_EXP__PRE                     0x4
-#define B_SC_RA_RAM_DRIVER_VERSION__AX                               0x8201FE
-#define   B_SC_RA_RAM_PROC_LOCKTRACK                                 0x0
-#define B_FE_COMM_EXEC__A                                            0xC00000
-#define B_FE_AD_REG_COMM_EXEC__A                                     0xC10000
-#define B_FE_AD_REG_FDB_IN__A                                        0xC10012
-#define B_FE_AD_REG_PD__A                                            0xC10013
-#define B_FE_AD_REG_INVEXT__A                                        0xC10014
-#define B_FE_AD_REG_CLKNEG__A                                        0xC10015
-#define B_FE_AG_REG_COMM_EXEC__A                                     0xC20000
-#define B_FE_AG_REG_AG_MODE_LOP__A                                   0xC20010
-#define   B_FE_AG_REG_AG_MODE_LOP_MODE_4__M                          0x10
-#define     B_FE_AG_REG_AG_MODE_LOP_MODE_4_STATIC                    0x0
-#define     B_FE_AG_REG_AG_MODE_LOP_MODE_4_DYNAMIC                   0x10
-#define   B_FE_AG_REG_AG_MODE_LOP_MODE_5__M                          0x20
-#define     B_FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC                    0x0
-#define   B_FE_AG_REG_AG_MODE_LOP_MODE_C__M                          0x1000
-#define     B_FE_AG_REG_AG_MODE_LOP_MODE_C_STATIC                    0x0
-#define     B_FE_AG_REG_AG_MODE_LOP_MODE_C_DYNAMIC                   0x1000
-#define   B_FE_AG_REG_AG_MODE_LOP_MODE_E__M                          0x4000
-#define     B_FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC                    0x0
-#define     B_FE_AG_REG_AG_MODE_LOP_MODE_E_DYNAMIC                   0x4000
-#define B_FE_AG_REG_AG_MODE_HIP__A                                   0xC20011
-#define   B_FE_AG_REG_AG_MODE_HIP_MODE_J__M                          0x8
-#define     B_FE_AG_REG_AG_MODE_HIP_MODE_J_STATIC                    0x0
-#define     B_FE_AG_REG_AG_MODE_HIP_MODE_J_DYNAMIC                   0x8
-#define B_FE_AG_REG_AG_PGA_MODE__A                                   0xC20012
-#define   B_FE_AG_REG_AG_PGA_MODE_PFY_PCY_AFY_REN                    0x0
-#define   B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN                    0x1
-#define B_FE_AG_REG_AG_AGC_SIO__A                                    0xC20013
-#define   B_FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M                        0x2
-#define     B_FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT                  0x0
-#define     B_FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_INPUT                   0x2
-#define B_FE_AG_REG_AG_PWD__A                                        0xC20015
-#define   B_FE_AG_REG_AG_PWD_PWD_PD2__M                              0x2
-#define     B_FE_AG_REG_AG_PWD_PWD_PD2_DISABLE                       0x0
-#define     B_FE_AG_REG_AG_PWD_PWD_PD2_ENABLE                        0x2
-#define B_FE_AG_REG_DCE_AUR_CNT__A                                   0xC20016
-#define B_FE_AG_REG_DCE_RUR_CNT__A                                   0xC20017
-#define B_FE_AG_REG_ACE_AUR_CNT__A                                   0xC2001A
-#define B_FE_AG_REG_ACE_RUR_CNT__A                                   0xC2001B
-#define B_FE_AG_REG_CDR_RUR_CNT__A                                   0xC20020
-#define B_FE_AG_REG_EGC_RUR_CNT__A                                   0xC20024
-#define B_FE_AG_REG_EGC_SET_LVL__A                                   0xC20025
-#define B_FE_AG_REG_EGC_SET_LVL__M                                   0x1FF
-#define B_FE_AG_REG_EGC_FLA_RGN__A                                   0xC20026
-#define B_FE_AG_REG_EGC_SLO_RGN__A                                   0xC20027
-#define B_FE_AG_REG_EGC_JMP_PSN__A                                   0xC20028
-#define B_FE_AG_REG_EGC_FLA_INC__A                                   0xC20029
-#define B_FE_AG_REG_EGC_FLA_DEC__A                                   0xC2002A
-#define B_FE_AG_REG_EGC_SLO_INC__A                                   0xC2002B
-#define B_FE_AG_REG_EGC_SLO_DEC__A                                   0xC2002C
-#define B_FE_AG_REG_EGC_FAS_INC__A                                   0xC2002D
-#define B_FE_AG_REG_EGC_FAS_DEC__A                                   0xC2002E
-#define B_FE_AG_REG_PM1_AGC_WRI__A                                   0xC20030
-#define B_FE_AG_REG_PM1_AGC_WRI__M                                   0x7FF
-#define B_FE_AG_REG_GC1_AGC_RIC__A                                   0xC20031
-#define B_FE_AG_REG_GC1_AGC_OFF__A                                   0xC20032
-#define B_FE_AG_REG_GC1_AGC_MAX__A                                   0xC20033
-#define B_FE_AG_REG_GC1_AGC_MIN__A                                   0xC20034
-#define B_FE_AG_REG_GC1_AGC_DAT__A                                   0xC20035
-#define B_FE_AG_REG_GC1_AGC_DAT__M                                   0x3FF
-#define B_FE_AG_REG_PM2_AGC_WRI__A                                   0xC20036
-#define B_FE_AG_REG_IND_WIN__A                                       0xC2003C
-#define B_FE_AG_REG_IND_THD_LOL__A                                   0xC2003D
-#define B_FE_AG_REG_IND_THD_HIL__A                                   0xC2003E
-#define B_FE_AG_REG_IND_DEL__A                                       0xC2003F
-#define B_FE_AG_REG_IND_PD1_WRI__A                                   0xC20040
-#define B_FE_AG_REG_PDA_AUR_CNT__A                                   0xC20041
-#define B_FE_AG_REG_PDA_RUR_CNT__A                                   0xC20042
-#define B_FE_AG_REG_PDA_AVE_DAT__A                                   0xC20043
-#define B_FE_AG_REG_PDC_RUR_CNT__A                                   0xC20044
-#define B_FE_AG_REG_PDC_SET_LVL__A                                   0xC20045
-#define B_FE_AG_REG_PDC_FLA_RGN__A                                   0xC20046
-#define B_FE_AG_REG_PDC_JMP_PSN__A                                   0xC20047
-#define B_FE_AG_REG_PDC_FLA_STP__A                                   0xC20048
-#define B_FE_AG_REG_PDC_SLO_STP__A                                   0xC20049
-#define B_FE_AG_REG_PDC_PD2_WRI__A                                   0xC2004A
-#define B_FE_AG_REG_PDC_MAP_DAT__A                                   0xC2004B
-#define B_FE_AG_REG_PDC_MAX__A                                       0xC2004C
-#define B_FE_AG_REG_TGA_AUR_CNT__A                                   0xC2004D
-#define B_FE_AG_REG_TGA_RUR_CNT__A                                   0xC2004E
-#define B_FE_AG_REG_TGA_AVE_DAT__A                                   0xC2004F
-#define B_FE_AG_REG_TGC_RUR_CNT__A                                   0xC20050
-#define B_FE_AG_REG_TGC_SET_LVL__A                                   0xC20051
-#define B_FE_AG_REG_TGC_SET_LVL__M                                   0x3F
-#define B_FE_AG_REG_TGC_FLA_RGN__A                                   0xC20052
-#define B_FE_AG_REG_TGC_JMP_PSN__A                                   0xC20053
-#define B_FE_AG_REG_TGC_FLA_STP__A                                   0xC20054
-#define B_FE_AG_REG_TGC_SLO_STP__A                                   0xC20055
-#define B_FE_AG_REG_TGC_MAP_DAT__A                                   0xC20056
-#define B_FE_AG_REG_FGM_WRI__A                                       0xC20061
-#define B_FE_AG_REG_BGC_FGC_WRI__A                                   0xC20068
-#define B_FE_AG_REG_BGC_CGC_WRI__A                                   0xC20069
-#define B_FE_FS_REG_COMM_EXEC__A                                     0xC30000
-#define B_FE_FS_REG_ADD_INC_LOP__A                                   0xC30010
-#define B_FE_FD_REG_COMM_EXEC__A                                     0xC40000
-#define B_FE_FD_REG_SCL__A                                           0xC40010
-#define B_FE_FD_REG_MAX_LEV__A                                       0xC40011
-#define B_FE_FD_REG_NR__A                                            0xC40012
-#define B_FE_FD_REG_MEAS_VAL__A                                      0xC40014
-#define B_FE_IF_REG_COMM_EXEC__A                                     0xC50000
-#define B_FE_IF_REG_INCR0__A                                         0xC50010
-#define B_FE_IF_REG_INCR0__W                                         16
-#define B_FE_IF_REG_INCR0__M                                         0xFFFF
-#define B_FE_IF_REG_INCR1__A                                         0xC50011
-#define B_FE_IF_REG_INCR1__M                                         0xFF
-#define B_FE_CF_REG_COMM_EXEC__A                                     0xC60000
-#define B_FE_CF_REG_SCL__A                                           0xC60010
-#define B_FE_CF_REG_MAX_LEV__A                                       0xC60011
-#define B_FE_CF_REG_NR__A                                            0xC60012
-#define B_FE_CF_REG_IMP_VAL__A                                       0xC60013
-#define B_FE_CF_REG_MEAS_VAL__A                                      0xC60014
-#define B_FE_CU_REG_COMM_EXEC__A                                     0xC70000
-#define B_FE_CU_REG_FRM_CNT_RST__A                                   0xC70011
-#define B_FE_CU_REG_FRM_CNT_STR__A                                   0xC70012
-#define B_FE_CU_REG_CTR_NFC_ICR__A                                   0xC70020
-#define B_FE_CU_REG_CTR_NFC_OCR__A                                   0xC70021
-#define B_FE_CU_REG_DIV_NFC_CLP__A                                   0xC70027
-#define B_FT_COMM_EXEC__A                                            0x1000000
-#define B_FT_REG_COMM_EXEC__A                                        0x1010000
-#define B_CP_COMM_EXEC__A                                            0x1400000
-#define B_CP_REG_COMM_EXEC__A                                        0x1410000
-#define B_CP_REG_INTERVAL__A                                         0x1410011
-#define B_CP_REG_BR_SPL_OFFSET__A                                    0x1410023
-#define B_CP_REG_BR_STR_DEL__A                                       0x1410024
-#define B_CP_REG_RT_ANG_INC0__A                                      0x1410030
-#define B_CP_REG_RT_ANG_INC1__A                                      0x1410031
-#define B_CP_REG_RT_DETECT_TRH__A                                    0x1410033
-#define B_CP_REG_AC_NEXP_OFFS__A                                     0x1410040
-#define B_CP_REG_AC_AVER_POW__A                                      0x1410041
-#define B_CP_REG_AC_MAX_POW__A                                       0x1410042
-#define B_CP_REG_AC_WEIGHT_MAN__A                                    0x1410043
-#define B_CP_REG_AC_WEIGHT_EXP__A                                    0x1410044
-#define B_CP_REG_AC_AMP_MODE__A                                      0x1410047
-#define B_CP_REG_AC_AMP_FIX__A                                       0x1410048
-#define B_CP_REG_AC_ANG_MODE__A                                      0x141004A
-#define B_CE_COMM_EXEC__A                                            0x1800000
-#define B_CE_REG_COMM_EXEC__A                                        0x1810000
-#define B_CE_REG_TAPSET__A                                           0x1810011
-#define B_CE_REG_AVG_POW__A                                          0x1810012
-#define B_CE_REG_MAX_POW__A                                          0x1810013
-#define B_CE_REG_ATT__A                                              0x1810014
-#define B_CE_REG_NRED__A                                             0x1810015
-#define B_CE_REG_NE_ERR_SELECT__A                                    0x1810043
-#define B_CE_REG_NE_TD_CAL__A                                        0x1810044
-#define B_CE_REG_NE_MIXAVG__A                                        0x1810046
-#define B_CE_REG_NE_NUPD_OFS__A                                      0x1810047
-#define B_CE_REG_PE_NEXP_OFFS__A                                     0x1810050
-#define B_CE_REG_PE_TIMESHIFT__A                                     0x1810051
-#define B_CE_REG_TP_A0_TAP_NEW__A                                    0x1810064
-#define B_CE_REG_TP_A0_TAP_NEW_VALID__A                              0x1810065
-#define B_CE_REG_TP_A0_MU_LMS_STEP__A                                0x1810066
-#define B_CE_REG_TP_A1_TAP_NEW__A                                    0x1810068
-#define B_CE_REG_TP_A1_TAP_NEW_VALID__A                              0x1810069
-#define B_CE_REG_TP_A1_MU_LMS_STEP__A                                0x181006A
-#define B_CE_REG_TI_PHN_ENABLE__A                                    0x1810073
-#define B_CE_REG_FI_SHT_INCR__A                                      0x1810090
-#define B_CE_REG_FI_EXP_NORM__A                                      0x1810091
-#define B_CE_REG_IR_INPUTSEL__A                                      0x18100A0
-#define B_CE_REG_IR_STARTPOS__A                                      0x18100A1
-#define B_CE_REG_IR_NEXP_THRES__A                                    0x18100A2
-#define B_CE_REG_FR_TREAL00__A                                       0x1820010
-#define B_CE_REG_FR_TIMAG00__A                                       0x1820011
-#define B_CE_REG_FR_TREAL01__A                                       0x1820012
-#define B_CE_REG_FR_TIMAG01__A                                       0x1820013
-#define B_CE_REG_FR_TREAL02__A                                       0x1820014
-#define B_CE_REG_FR_TIMAG02__A                                       0x1820015
-#define B_CE_REG_FR_TREAL03__A                                       0x1820016
-#define B_CE_REG_FR_TIMAG03__A                                       0x1820017
-#define B_CE_REG_FR_TREAL04__A                                       0x1820018
-#define B_CE_REG_FR_TIMAG04__A                                       0x1820019
-#define B_CE_REG_FR_TREAL05__A                                       0x182001A
-#define B_CE_REG_FR_TIMAG05__A                                       0x182001B
-#define B_CE_REG_FR_TREAL06__A                                       0x182001C
-#define B_CE_REG_FR_TIMAG06__A                                       0x182001D
-#define B_CE_REG_FR_TREAL07__A                                       0x182001E
-#define B_CE_REG_FR_TIMAG07__A                                       0x182001F
-#define B_CE_REG_FR_TREAL08__A                                       0x1820020
-#define B_CE_REG_FR_TIMAG08__A                                       0x1820021
-#define B_CE_REG_FR_TREAL09__A                                       0x1820022
-#define B_CE_REG_FR_TIMAG09__A                                       0x1820023
-#define B_CE_REG_FR_TREAL10__A                                       0x1820024
-#define B_CE_REG_FR_TIMAG10__A                                       0x1820025
-#define B_CE_REG_FR_TREAL11__A                                       0x1820026
-#define B_CE_REG_FR_TIMAG11__A                                       0x1820027
-#define B_CE_REG_FR_MID_TAP__A                                       0x1820028
-#define B_CE_REG_FR_SQS_G00__A                                       0x1820029
-#define B_CE_REG_FR_SQS_G01__A                                       0x182002A
-#define B_CE_REG_FR_SQS_G02__A                                       0x182002B
-#define B_CE_REG_FR_SQS_G03__A                                       0x182002C
-#define B_CE_REG_FR_SQS_G04__A                                       0x182002D
-#define B_CE_REG_FR_SQS_G05__A                                       0x182002E
-#define B_CE_REG_FR_SQS_G06__A                                       0x182002F
-#define B_CE_REG_FR_SQS_G07__A                                       0x1820030
-#define B_CE_REG_FR_SQS_G08__A                                       0x1820031
-#define B_CE_REG_FR_SQS_G09__A                                       0x1820032
-#define B_CE_REG_FR_SQS_G10__A                                       0x1820033
-#define B_CE_REG_FR_SQS_G11__A                                       0x1820034
-#define B_CE_REG_FR_SQS_G12__A                                       0x1820035
-#define B_CE_REG_FR_RIO_G00__A                                       0x1820036
-#define B_CE_REG_FR_RIO_G01__A                                       0x1820037
-#define B_CE_REG_FR_RIO_G02__A                                       0x1820038
-#define B_CE_REG_FR_RIO_G03__A                                       0x1820039
-#define B_CE_REG_FR_RIO_G04__A                                       0x182003A
-#define B_CE_REG_FR_RIO_G05__A                                       0x182003B
-#define B_CE_REG_FR_RIO_G06__A                                       0x182003C
-#define B_CE_REG_FR_RIO_G07__A                                       0x182003D
-#define B_CE_REG_FR_RIO_G08__A                                       0x182003E
-#define B_CE_REG_FR_RIO_G09__A                                       0x182003F
-#define B_CE_REG_FR_RIO_G10__A                                       0x1820040
-#define B_CE_REG_FR_MODE__A                                          0x1820041
-#define B_CE_REG_FR_SQS_TRH__A                                       0x1820042
-#define B_CE_REG_FR_RIO_GAIN__A                                      0x1820043
-#define B_CE_REG_FR_BYPASS__A                                        0x1820044
-#define B_CE_REG_FR_PM_SET__A                                        0x1820045
-#define B_CE_REG_FR_ERR_SH__A                                        0x1820046
-#define B_CE_REG_FR_MAN_SH__A                                        0x1820047
-#define B_CE_REG_FR_TAP_SH__A                                        0x1820048
-#define B_EQ_COMM_EXEC__A                                            0x1C00000
-#define B_EQ_REG_COMM_EXEC__A                                        0x1C10000
-#define B_EQ_REG_COMM_MB__A                                          0x1C10002
-#define B_EQ_REG_IS_GAIN_MAN__A                                      0x1C10015
-#define B_EQ_REG_IS_GAIN_EXP__A                                      0x1C10016
-#define B_EQ_REG_IS_CLIP_EXP__A                                      0x1C10017
-#define B_EQ_REG_SN_CEGAIN__A                                        0x1C1002A
-#define B_EQ_REG_SN_OFFSET__A                                        0x1C1002B
-#define B_EQ_REG_RC_SEL_CAR__A                                       0x1C10032
-#define   B_EQ_REG_RC_SEL_CAR_INIT                                   0x2
-#define     B_EQ_REG_RC_SEL_CAR_DIV_ON                               0x1
-#define     B_EQ_REG_RC_SEL_CAR_PASS_A_CC                            0x0
-#define     B_EQ_REG_RC_SEL_CAR_PASS_B_CE                            0x2
-#define     B_EQ_REG_RC_SEL_CAR_LOCAL_A_CC                           0x0
-#define     B_EQ_REG_RC_SEL_CAR_LOCAL_B_CE                           0x8
-#define     B_EQ_REG_RC_SEL_CAR_MEAS_A_CC                            0x0
-#define     B_EQ_REG_RC_SEL_CAR_MEAS_B_CE                            0x20
-#define   B_EQ_REG_RC_SEL_CAR_FFTMODE__M                             0x80
-#define B_EQ_REG_OT_CONST__A                                         0x1C10046
-#define B_EQ_REG_OT_ALPHA__A                                         0x1C10047
-#define B_EQ_REG_OT_QNT_THRES0__A                                    0x1C10048
-#define B_EQ_REG_OT_QNT_THRES1__A                                    0x1C10049
-#define B_EQ_REG_OT_CSI_STEP__A                                      0x1C1004A
-#define B_EQ_REG_OT_CSI_OFFSET__A                                    0x1C1004B
-#define B_EQ_REG_TD_REQ_SMB_CNT__A                                   0x1C10061
-#define B_EQ_REG_TD_TPS_PWR_OFS__A                                   0x1C10062
-#define B_EC_SB_REG_COMM_EXEC__A                                     0x2010000
-#define B_EC_SB_REG_TR_MODE__A                                       0x2010010
-#define   B_EC_SB_REG_TR_MODE_8K                                     0x0
-#define   B_EC_SB_REG_TR_MODE_2K                                     0x1
-#define B_EC_SB_REG_CONST__A                                         0x2010011
-#define   B_EC_SB_REG_CONST_QPSK                                     0x0
-#define   B_EC_SB_REG_CONST_16QAM                                    0x1
-#define   B_EC_SB_REG_CONST_64QAM                                    0x2
-#define B_EC_SB_REG_ALPHA__A                                         0x2010012
-#define B_EC_SB_REG_PRIOR__A                                         0x2010013
-#define   B_EC_SB_REG_PRIOR_HI                                       0x0
-#define   B_EC_SB_REG_PRIOR_LO                                       0x1
-#define B_EC_SB_REG_CSI_HI__A                                        0x2010014
-#define B_EC_SB_REG_CSI_LO__A                                        0x2010015
-#define B_EC_SB_REG_SMB_TGL__A                                       0x2010016
-#define B_EC_SB_REG_SNR_HI__A                                        0x2010017
-#define B_EC_SB_REG_SNR_MID__A                                       0x2010018
-#define B_EC_SB_REG_SNR_LO__A                                        0x2010019
-#define B_EC_SB_REG_SCALE_MSB__A                                     0x201001A
-#define B_EC_SB_REG_SCALE_BIT2__A                                    0x201001B
-#define B_EC_SB_REG_SCALE_LSB__A                                     0x201001C
-#define B_EC_SB_REG_CSI_OFS0__A                                      0x201001D
-#define B_EC_SB_REG_CSI_OFS1__A                                      0x201001E
-#define B_EC_SB_REG_CSI_OFS2__A                                      0x201001F
-#define B_EC_VD_REG_COMM_EXEC__A                                     0x2090000
-#define B_EC_VD_REG_FORCE__A                                         0x2090010
-#define B_EC_VD_REG_SET_CODERATE__A                                  0x2090011
-#define   B_EC_VD_REG_SET_CODERATE_C1_2                              0x0
-#define   B_EC_VD_REG_SET_CODERATE_C2_3                              0x1
-#define   B_EC_VD_REG_SET_CODERATE_C3_4                              0x2
-#define   B_EC_VD_REG_SET_CODERATE_C5_6                              0x3
-#define   B_EC_VD_REG_SET_CODERATE_C7_8                              0x4
-#define B_EC_VD_REG_REQ_SMB_CNT__A                                   0x2090012
-#define B_EC_VD_REG_RLK_ENA__A                                       0x2090014
-#define B_EC_OD_REG_COMM_EXEC__A                                     0x2110000
-#define B_EC_OD_REG_SYNC__A                                          0x2110664
-#define B_EC_OD_DEINT_RAM__A                                         0x2120000
-#define B_EC_RS_REG_COMM_EXEC__A                                     0x2130000
-#define B_EC_RS_REG_REQ_PCK_CNT__A                                   0x2130010
-#define B_EC_RS_REG_VAL__A                                           0x2130011
-#define   B_EC_RS_REG_VAL_PCK                                        0x1
-#define B_EC_RS_EC_RAM__A                                            0x2140000
-#define B_EC_OC_REG_COMM_EXEC__A                                     0x2150000
-#define     B_EC_OC_REG_COMM_EXEC_CTL_ACTIVE                         0x1
-#define     B_EC_OC_REG_COMM_EXEC_CTL_HOLD                           0x2
-#define B_EC_OC_REG_COMM_INT_STA__A                                  0x2150007
-#define B_EC_OC_REG_OC_MODE_LOP__A                                   0x2150010
-#define   B_EC_OC_REG_OC_MODE_LOP_PAR_ENA__M                         0x1
-#define     B_EC_OC_REG_OC_MODE_LOP_PAR_ENA_ENABLE                   0x0
-#define     B_EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE                  0x1
-#define   B_EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC__M                     0x4
-#define     B_EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC_STATIC               0x0
-#define   B_EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE__M                     0x80
-#define     B_EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE_SERIAL               0x80
-#define B_EC_OC_REG_OC_MODE_HIP__A                                   0x2150011
-#define     B_EC_OC_REG_OC_MODE_HIP_MPG_BUS_SRC_MONITOR              0x10
-#define   B_EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M                     0x200
-#define     B_EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_DISABLE              0x0
-#define     B_EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_ENABLE               0x200
-#define B_EC_OC_REG_OC_MPG_SIO__A                                    0x2150012
-#define B_EC_OC_REG_OC_MPG_SIO__M                                    0xFFF
-#define B_EC_OC_REG_DTO_INC_LOP__A                                   0x2150014
-#define B_EC_OC_REG_DTO_INC_HIP__A                                   0x2150015
-#define B_EC_OC_REG_SNC_ISC_LVL__A                                   0x2150016
-#define   B_EC_OC_REG_SNC_ISC_LVL_OSC__M                             0xF0
-#define B_EC_OC_REG_TMD_TOP_MODE__A                                  0x215001D
-#define B_EC_OC_REG_TMD_TOP_CNT__A                                   0x215001E
-#define B_EC_OC_REG_TMD_HIL_MAR__A                                   0x215001F
-#define B_EC_OC_REG_TMD_LOL_MAR__A                                   0x2150020
-#define B_EC_OC_REG_TMD_CUR_CNT__A                                   0x2150021
-#define B_EC_OC_REG_AVR_ASH_CNT__A                                   0x2150023
-#define B_EC_OC_REG_AVR_BSH_CNT__A                                   0x2150024
-#define B_EC_OC_REG_RCN_MODE__A                                      0x2150027
-#define B_EC_OC_REG_RCN_CRA_LOP__A                                   0x2150028
-#define B_EC_OC_REG_RCN_CRA_HIP__A                                   0x2150029
-#define B_EC_OC_REG_RCN_CST_LOP__A                                   0x215002A
-#define B_EC_OC_REG_RCN_CST_HIP__A                                   0x215002B
-#define B_EC_OC_REG_RCN_SET_LVL__A                                   0x215002C
-#define B_EC_OC_REG_RCN_GAI_LVL__A                                   0x215002D
-#define B_EC_OC_REG_RCN_CLP_LOP__A                                   0x2150032
-#define B_EC_OC_REG_RCN_CLP_HIP__A                                   0x2150033
-#define B_EC_OC_REG_RCN_MAP_LOP__A                                   0x2150034
-#define B_EC_OC_REG_RCN_MAP_HIP__A                                   0x2150035
-#define B_EC_OC_REG_OCR_MPG_UOS__A                                   0x2150036
-#define B_EC_OC_REG_OCR_MPG_UOS__M                                   0xFFF
-#define   B_EC_OC_REG_OCR_MPG_UOS_INIT                               0x0
-#define B_EC_OC_REG_OCR_MPG_USR_DAT__A                               0x2150038
-#define B_EC_OC_REG_IPR_INV_MPG__A                                   0x2150045
-#define B_EC_OC_REG_DTO_CLKMODE__A                                   0x2150047
-#define B_EC_OC_REG_DTO_PER__A                                       0x2150048
-#define B_EC_OC_REG_DTO_BUR__A                                       0x2150049
-#define B_EC_OC_REG_RCR_CLKMODE__A                                   0x215004A
-#define B_CC_REG_OSC_MODE__A                                         0x2410010
-#define   B_CC_REG_OSC_MODE_M20                                      0x1
-#define B_CC_REG_PLL_MODE__A                                         0x2410011
-#define     B_CC_REG_PLL_MODE_BYPASS_PLL                             0x1
-#define     B_CC_REG_PLL_MODE_PUMP_CUR_12                            0x14
-#define B_CC_REG_REF_DIVIDE__A                                       0x2410012
-#define B_CC_REG_PWD_MODE__A                                         0x2410015
-#define   B_CC_REG_PWD_MODE_DOWN_PLL                                 0x2
-#define B_CC_REG_UPDATE__A                                           0x2410017
-#define   B_CC_REG_UPDATE_KEY                                        0x3973
-#define B_CC_REG_JTAGID_L__A                                         0x2410019
-#define B_CC_REG_DIVERSITY__A                                        0x241001B
-#define B_LC_COMM_EXEC__A                                            0x2800000
-#define B_LC_RA_RAM_IFINCR_NOM_L__A                                  0x282000C
-#define B_LC_RA_RAM_FILTER_SYM_SET__A                                0x282001A
-#define B_LC_RA_RAM_FILTER_SYM_SET__PRE                              0x3E8
-#define B_LC_RA_RAM_FILTER_CRMM_A__A                                 0x2820060
-#define B_LC_RA_RAM_FILTER_CRMM_A__PRE                               0x4
-#define B_LC_RA_RAM_FILTER_CRMM_B__A                                 0x2820061
-#define B_LC_RA_RAM_FILTER_CRMM_B__PRE                               0x1
-#define B_LC_RA_RAM_FILTER_SRMM_A__A                                 0x2820068
-#define B_LC_RA_RAM_FILTER_SRMM_A__PRE                               0x4
-#define B_LC_RA_RAM_FILTER_SRMM_B__A                                 0x2820069
-#define B_LC_RA_RAM_FILTER_SRMM_B__PRE                               0x1
-
-#endif
diff --git a/drivers/media/dvb/frontends/drxk.h b/drivers/media/dvb/frontends/drxk.h
deleted file mode 100644
index d615d7d..0000000
--- a/drivers/media/dvb/frontends/drxk.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef _DRXK_H_
-#define _DRXK_H_
-
-#include <linux/types.h>
-#include <linux/i2c.h>
-
-/**
- * struct drxk_config - Configure the initial parameters for DRX-K
- *
- * @adr:		I2C Address of the DRX-K
- * @parallel_ts:	True means that the device uses parallel TS,
- * 			Serial otherwise.
- * @dynamic_clk:	True means that the clock will be dynamically
- *			adjusted. Static clock otherwise.
- * @enable_merr_cfg:	Enable SIO_PDR_PERR_CFG/SIO_PDR_MVAL_CFG.
- * @single_master:	Device is on the single master mode
- * @no_i2c_bridge:	Don't switch the I2C bridge to talk with tuner
- * @antenna_gpio:	GPIO bit used to control the antenna
- * @antenna_dvbt:	GPIO bit for changing antenna to DVB-C. A value of 1
- *			means that 1=DVBC, 0 = DVBT. Zero means the opposite.
- * @mpeg_out_clk_strength: DRXK Mpeg output clock drive strength.
- * @microcode_name:	Name of the firmware file with the microcode
- * @qam_demod_parameter_count:	The number of parameters used for the command
- *				to set the demodulator parameters. All
- *				firmwares are using the 2-parameter commmand.
- *				An exception is the "drxk_a3.mc" firmware,
- *				which uses the 4-parameter command.
- *				A value of 0 (default) or lower indicates that
- *				the correct number of parameters will be
- *				automatically detected.
- *
- * On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is
- * UIO-3.
- */
-struct drxk_config {
-	u8	adr;
-	bool	single_master;
-	bool	no_i2c_bridge;
-	bool	parallel_ts;
-	bool	dynamic_clk;
-	bool	enable_merr_cfg;
-
-	bool	antenna_dvbt;
-	u16	antenna_gpio;
-
-	u8	mpeg_out_clk_strength;
-	int	chunk_size;
-
-	const char	*microcode_name;
-	int		 qam_demod_parameter_count;
-};
-
-#if defined(CONFIG_DVB_DRXK) || (defined(CONFIG_DVB_DRXK_MODULE) \
-        && defined(MODULE))
-extern struct dvb_frontend *drxk_attach(const struct drxk_config *config,
-					struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *drxk_attach(const struct drxk_config *config,
-					struct i2c_adapter *i2c)
-{
-        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-        return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/dvb/frontends/drxk_hard.c b/drivers/media/dvb/frontends/drxk_hard.c
deleted file mode 100644
index 1ab8154..0000000
--- a/drivers/media/dvb/frontends/drxk_hard.c
+++ /dev/null
@@ -1,6637 +0,0 @@
-/*
- * drxk_hard: DRX-K DVB-C/T demodulator driver
- *
- * Copyright (C) 2010-2011 Digital Devices GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/i2c.h>
-#include <linux/hardirq.h>
-#include <asm/div64.h>
-
-#include "dvb_frontend.h"
-#include "drxk.h"
-#include "drxk_hard.h"
-
-static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode);
-static int PowerDownQAM(struct drxk_state *state);
-static int SetDVBTStandard(struct drxk_state *state,
-			   enum OperationMode oMode);
-static int SetQAMStandard(struct drxk_state *state,
-			  enum OperationMode oMode);
-static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
-		  s32 tunerFreqOffset);
-static int SetDVBTStandard(struct drxk_state *state,
-			   enum OperationMode oMode);
-static int DVBTStart(struct drxk_state *state);
-static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
-		   s32 tunerFreqOffset);
-static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus);
-static int GetDVBTLockStatus(struct drxk_state *state, u32 *pLockStatus);
-static int SwitchAntennaToQAM(struct drxk_state *state);
-static int SwitchAntennaToDVBT(struct drxk_state *state);
-
-static bool IsDVBT(struct drxk_state *state)
-{
-	return state->m_OperationMode == OM_DVBT;
-}
-
-static bool IsQAM(struct drxk_state *state)
-{
-	return state->m_OperationMode == OM_QAM_ITU_A ||
-	    state->m_OperationMode == OM_QAM_ITU_B ||
-	    state->m_OperationMode == OM_QAM_ITU_C;
-}
-
-bool IsA1WithPatchCode(struct drxk_state *state)
-{
-	return state->m_DRXK_A1_PATCH_CODE;
-}
-
-bool IsA1WithRomCode(struct drxk_state *state)
-{
-	return state->m_DRXK_A1_ROM_CODE;
-}
-
-#define NOA1ROM 0
-
-#define DRXDAP_FASI_SHORT_FORMAT(addr) (((addr) & 0xFC30FF80) == 0)
-#define DRXDAP_FASI_LONG_FORMAT(addr)  (((addr) & 0xFC30FF80) != 0)
-
-#define DEFAULT_MER_83  165
-#define DEFAULT_MER_93  250
-
-#ifndef DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH
-#define DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH (0x02)
-#endif
-
-#ifndef DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH
-#define DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH (0x03)
-#endif
-
-#define DEFAULT_DRXK_MPEG_LOCK_TIMEOUT 700
-#define DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT 500
-
-#ifndef DRXK_KI_RAGC_ATV
-#define DRXK_KI_RAGC_ATV   4
-#endif
-#ifndef DRXK_KI_IAGC_ATV
-#define DRXK_KI_IAGC_ATV   6
-#endif
-#ifndef DRXK_KI_DAGC_ATV
-#define DRXK_KI_DAGC_ATV   7
-#endif
-
-#ifndef DRXK_KI_RAGC_QAM
-#define DRXK_KI_RAGC_QAM   3
-#endif
-#ifndef DRXK_KI_IAGC_QAM
-#define DRXK_KI_IAGC_QAM   4
-#endif
-#ifndef DRXK_KI_DAGC_QAM
-#define DRXK_KI_DAGC_QAM   7
-#endif
-#ifndef DRXK_KI_RAGC_DVBT
-#define DRXK_KI_RAGC_DVBT  (IsA1WithPatchCode(state) ? 3 : 2)
-#endif
-#ifndef DRXK_KI_IAGC_DVBT
-#define DRXK_KI_IAGC_DVBT  (IsA1WithPatchCode(state) ? 4 : 2)
-#endif
-#ifndef DRXK_KI_DAGC_DVBT
-#define DRXK_KI_DAGC_DVBT  (IsA1WithPatchCode(state) ? 10 : 7)
-#endif
-
-#ifndef DRXK_AGC_DAC_OFFSET
-#define DRXK_AGC_DAC_OFFSET (0x800)
-#endif
-
-#ifndef DRXK_BANDWIDTH_8MHZ_IN_HZ
-#define DRXK_BANDWIDTH_8MHZ_IN_HZ  (0x8B8249L)
-#endif
-
-#ifndef DRXK_BANDWIDTH_7MHZ_IN_HZ
-#define DRXK_BANDWIDTH_7MHZ_IN_HZ  (0x7A1200L)
-#endif
-
-#ifndef DRXK_BANDWIDTH_6MHZ_IN_HZ
-#define DRXK_BANDWIDTH_6MHZ_IN_HZ  (0x68A1B6L)
-#endif
-
-#ifndef DRXK_QAM_SYMBOLRATE_MAX
-#define DRXK_QAM_SYMBOLRATE_MAX         (7233000)
-#endif
-
-#define DRXK_BL_ROM_OFFSET_TAPS_DVBT    56
-#define DRXK_BL_ROM_OFFSET_TAPS_ITU_A   64
-#define DRXK_BL_ROM_OFFSET_TAPS_ITU_C   0x5FE0
-#define DRXK_BL_ROM_OFFSET_TAPS_BG      24
-#define DRXK_BL_ROM_OFFSET_TAPS_DKILLP  32
-#define DRXK_BL_ROM_OFFSET_TAPS_NTSC    40
-#define DRXK_BL_ROM_OFFSET_TAPS_FM      48
-#define DRXK_BL_ROM_OFFSET_UCODE        0
-
-#define DRXK_BLC_TIMEOUT                100
-
-#define DRXK_BLCC_NR_ELEMENTS_TAPS      2
-#define DRXK_BLCC_NR_ELEMENTS_UCODE     6
-
-#define DRXK_BLDC_NR_ELEMENTS_TAPS      28
-
-#ifndef DRXK_OFDM_NE_NOTCH_WIDTH
-#define DRXK_OFDM_NE_NOTCH_WIDTH             (4)
-#endif
-
-#define DRXK_QAM_SL_SIG_POWER_QAM16       (40960)
-#define DRXK_QAM_SL_SIG_POWER_QAM32       (20480)
-#define DRXK_QAM_SL_SIG_POWER_QAM64       (43008)
-#define DRXK_QAM_SL_SIG_POWER_QAM128      (20992)
-#define DRXK_QAM_SL_SIG_POWER_QAM256      (43520)
-
-static unsigned int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable debug messages");
-
-#define dprintk(level, fmt, arg...) do {			\
-if (debug >= level)						\
-	printk(KERN_DEBUG "drxk: %s" fmt, __func__, ## arg);	\
-} while (0)
-
-
-static inline u32 MulDiv32(u32 a, u32 b, u32 c)
-{
-	u64 tmp64;
-
-	tmp64 = (u64) a * (u64) b;
-	do_div(tmp64, c);
-
-	return (u32) tmp64;
-}
-
-inline u32 Frac28a(u32 a, u32 c)
-{
-	int i = 0;
-	u32 Q1 = 0;
-	u32 R0 = 0;
-
-	R0 = (a % c) << 4;	/* 32-28 == 4 shifts possible at max */
-	Q1 = a / c;		/* integer part, only the 4 least significant bits
-				   will be visible in the result */
-
-	/* division using radix 16, 7 nibbles in the result */
-	for (i = 0; i < 7; i++) {
-		Q1 = (Q1 << 4) | (R0 / c);
-		R0 = (R0 % c) << 4;
-	}
-	/* rounding */
-	if ((R0 >> 3) >= c)
-		Q1++;
-
-	return Q1;
-}
-
-static u32 Log10Times100(u32 x)
-{
-	static const u8 scale = 15;
-	static const u8 indexWidth = 5;
-	u8 i = 0;
-	u32 y = 0;
-	u32 d = 0;
-	u32 k = 0;
-	u32 r = 0;
-	/*
-	   log2lut[n] = (1<<scale) * 200 * log2(1.0 + ((1.0/(1<<INDEXWIDTH)) * n))
-	   0 <= n < ((1<<INDEXWIDTH)+1)
-	 */
-
-	static const u32 log2lut[] = {
-		0,		/* 0.000000 */
-		290941,		/* 290941.300628 */
-		573196,		/* 573196.476418 */
-		847269,		/* 847269.179851 */
-		1113620,	/* 1113620.489452 */
-		1372674,	/* 1372673.576986 */
-		1624818,	/* 1624817.752104 */
-		1870412,	/* 1870411.981536 */
-		2109788,	/* 2109787.962654 */
-		2343253,	/* 2343252.817465 */
-		2571091,	/* 2571091.461923 */
-		2793569,	/* 2793568.696416 */
-		3010931,	/* 3010931.055901 */
-		3223408,	/* 3223408.452106 */
-		3431216,	/* 3431215.635215 */
-		3634553,	/* 3634553.498355 */
-		3833610,	/* 3833610.244726 */
-		4028562,	/* 4028562.434393 */
-		4219576,	/* 4219575.925308 */
-		4406807,	/* 4406806.721144 */
-		4590402,	/* 4590401.736809 */
-		4770499,	/* 4770499.491025 */
-		4947231,	/* 4947230.734179 */
-		5120719,	/* 5120719.018555 */
-		5291081,	/* 5291081.217197 */
-		5458428,	/* 5458427.996830 */
-		5622864,	/* 5622864.249668 */
-		5784489,	/* 5784489.488298 */
-		5943398,	/* 5943398.207380 */
-		6099680,	/* 6099680.215452 */
-		6253421,	/* 6253420.939751 */
-		6404702,	/* 6404701.706649 */
-		6553600,	/* 6553600.000000 */
-	};
-
-
-	if (x == 0)
-		return 0;
-
-	/* Scale x (normalize) */
-	/* computing y in log(x/y) = log(x) - log(y) */
-	if ((x & ((0xffffffff) << (scale + 1))) == 0) {
-		for (k = scale; k > 0; k--) {
-			if (x & (((u32) 1) << scale))
-				break;
-			x <<= 1;
-		}
-	} else {
-		for (k = scale; k < 31; k++) {
-			if ((x & (((u32) (-1)) << (scale + 1))) == 0)
-				break;
-			x >>= 1;
-		}
-	}
-	/*
-	   Now x has binary point between bit[scale] and bit[scale-1]
-	   and 1.0 <= x < 2.0 */
-
-	/* correction for divison: log(x) = log(x/y)+log(y) */
-	y = k * ((((u32) 1) << scale) * 200);
-
-	/* remove integer part */
-	x &= ((((u32) 1) << scale) - 1);
-	/* get index */
-	i = (u8) (x >> (scale - indexWidth));
-	/* compute delta (x - a) */
-	d = x & ((((u32) 1) << (scale - indexWidth)) - 1);
-	/* compute log, multiplication (d* (..)) must be within range ! */
-	y += log2lut[i] +
-	    ((d * (log2lut[i + 1] - log2lut[i])) >> (scale - indexWidth));
-	/* Conver to log10() */
-	y /= 108853;		/* (log2(10) << scale) */
-	r = (y >> 1);
-	/* rounding */
-	if (y & ((u32) 1))
-		r++;
-	return r;
-}
-
-/****************************************************************************/
-/* I2C **********************************************************************/
-/****************************************************************************/
-
-static int drxk_i2c_lock(struct drxk_state *state)
-{
-	i2c_lock_adapter(state->i2c);
-	state->drxk_i2c_exclusive_lock = true;
-
-	return 0;
-}
-
-static void drxk_i2c_unlock(struct drxk_state *state)
-{
-	if (!state->drxk_i2c_exclusive_lock)
-		return;
-
-	i2c_unlock_adapter(state->i2c);
-	state->drxk_i2c_exclusive_lock = false;
-}
-
-static int drxk_i2c_transfer(struct drxk_state *state, struct i2c_msg *msgs,
-			     unsigned len)
-{
-	if (state->drxk_i2c_exclusive_lock)
-		return __i2c_transfer(state->i2c, msgs, len);
-	else
-		return i2c_transfer(state->i2c, msgs, len);
-}
-
-static int i2c_read1(struct drxk_state *state, u8 adr, u8 *val)
-{
-	struct i2c_msg msgs[1] = { {.addr = adr, .flags = I2C_M_RD,
-				    .buf = val, .len = 1}
-	};
-
-	return drxk_i2c_transfer(state, msgs, 1);
-}
-
-static int i2c_write(struct drxk_state *state, u8 adr, u8 *data, int len)
-{
-	int status;
-	struct i2c_msg msg = {
-	    .addr = adr, .flags = 0, .buf = data, .len = len };
-
-	dprintk(3, ":");
-	if (debug > 2) {
-		int i;
-		for (i = 0; i < len; i++)
-			printk(KERN_CONT " %02x", data[i]);
-		printk(KERN_CONT "\n");
-	}
-	status = drxk_i2c_transfer(state, &msg, 1);
-	if (status >= 0 && status != 1)
-		status = -EIO;
-
-	if (status < 0)
-		printk(KERN_ERR "drxk: i2c write error at addr 0x%02x\n", adr);
-
-	return status;
-}
-
-static int i2c_read(struct drxk_state *state,
-		    u8 adr, u8 *msg, int len, u8 *answ, int alen)
-{
-	int status;
-	struct i2c_msg msgs[2] = {
-		{.addr = adr, .flags = 0,
-				    .buf = msg, .len = len},
-		{.addr = adr, .flags = I2C_M_RD,
-		 .buf = answ, .len = alen}
-	};
-
-	status = drxk_i2c_transfer(state, msgs, 2);
-	if (status != 2) {
-		if (debug > 2)
-			printk(KERN_CONT ": ERROR!\n");
-		if (status >= 0)
-			status = -EIO;
-
-		printk(KERN_ERR "drxk: i2c read error at addr 0x%02x\n", adr);
-		return status;
-	}
-	if (debug > 2) {
-		int i;
-		dprintk(2, ": read from");
-		for (i = 0; i < len; i++)
-			printk(KERN_CONT " %02x", msg[i]);
-		printk(KERN_CONT ", value = ");
-		for (i = 0; i < alen; i++)
-			printk(KERN_CONT " %02x", answ[i]);
-		printk(KERN_CONT "\n");
-	}
-	return 0;
-}
-
-static int read16_flags(struct drxk_state *state, u32 reg, u16 *data, u8 flags)
-{
-	int status;
-	u8 adr = state->demod_address, mm1[4], mm2[2], len;
-
-	if (state->single_master)
-		flags |= 0xC0;
-
-	if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
-		mm1[0] = (((reg << 1) & 0xFF) | 0x01);
-		mm1[1] = ((reg >> 16) & 0xFF);
-		mm1[2] = ((reg >> 24) & 0xFF) | flags;
-		mm1[3] = ((reg >> 7) & 0xFF);
-		len = 4;
-	} else {
-		mm1[0] = ((reg << 1) & 0xFF);
-		mm1[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
-		len = 2;
-	}
-	dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags);
-	status = i2c_read(state, adr, mm1, len, mm2, 2);
-	if (status < 0)
-		return status;
-	if (data)
-		*data = mm2[0] | (mm2[1] << 8);
-
-	return 0;
-}
-
-static int read16(struct drxk_state *state, u32 reg, u16 *data)
-{
-	return read16_flags(state, reg, data, 0);
-}
-
-static int read32_flags(struct drxk_state *state, u32 reg, u32 *data, u8 flags)
-{
-	int status;
-	u8 adr = state->demod_address, mm1[4], mm2[4], len;
-
-	if (state->single_master)
-		flags |= 0xC0;
-
-	if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
-		mm1[0] = (((reg << 1) & 0xFF) | 0x01);
-		mm1[1] = ((reg >> 16) & 0xFF);
-		mm1[2] = ((reg >> 24) & 0xFF) | flags;
-		mm1[3] = ((reg >> 7) & 0xFF);
-		len = 4;
-	} else {
-		mm1[0] = ((reg << 1) & 0xFF);
-		mm1[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
-		len = 2;
-	}
-	dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags);
-	status = i2c_read(state, adr, mm1, len, mm2, 4);
-	if (status < 0)
-		return status;
-	if (data)
-		*data = mm2[0] | (mm2[1] << 8) |
-		    (mm2[2] << 16) | (mm2[3] << 24);
-
-	return 0;
-}
-
-static int read32(struct drxk_state *state, u32 reg, u32 *data)
-{
-	return read32_flags(state, reg, data, 0);
-}
-
-static int write16_flags(struct drxk_state *state, u32 reg, u16 data, u8 flags)
-{
-	u8 adr = state->demod_address, mm[6], len;
-
-	if (state->single_master)
-		flags |= 0xC0;
-	if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
-		mm[0] = (((reg << 1) & 0xFF) | 0x01);
-		mm[1] = ((reg >> 16) & 0xFF);
-		mm[2] = ((reg >> 24) & 0xFF) | flags;
-		mm[3] = ((reg >> 7) & 0xFF);
-		len = 4;
-	} else {
-		mm[0] = ((reg << 1) & 0xFF);
-		mm[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
-		len = 2;
-	}
-	mm[len] = data & 0xff;
-	mm[len + 1] = (data >> 8) & 0xff;
-
-	dprintk(2, "(0x%08x, 0x%04x, 0x%02x)\n", reg, data, flags);
-	return i2c_write(state, adr, mm, len + 2);
-}
-
-static int write16(struct drxk_state *state, u32 reg, u16 data)
-{
-	return write16_flags(state, reg, data, 0);
-}
-
-static int write32_flags(struct drxk_state *state, u32 reg, u32 data, u8 flags)
-{
-	u8 adr = state->demod_address, mm[8], len;
-
-	if (state->single_master)
-		flags |= 0xC0;
-	if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
-		mm[0] = (((reg << 1) & 0xFF) | 0x01);
-		mm[1] = ((reg >> 16) & 0xFF);
-		mm[2] = ((reg >> 24) & 0xFF) | flags;
-		mm[3] = ((reg >> 7) & 0xFF);
-		len = 4;
-	} else {
-		mm[0] = ((reg << 1) & 0xFF);
-		mm[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
-		len = 2;
-	}
-	mm[len] = data & 0xff;
-	mm[len + 1] = (data >> 8) & 0xff;
-	mm[len + 2] = (data >> 16) & 0xff;
-	mm[len + 3] = (data >> 24) & 0xff;
-	dprintk(2, "(0x%08x, 0x%08x, 0x%02x)\n", reg, data, flags);
-
-	return i2c_write(state, adr, mm, len + 4);
-}
-
-static int write32(struct drxk_state *state, u32 reg, u32 data)
-{
-	return write32_flags(state, reg, data, 0);
-}
-
-static int write_block(struct drxk_state *state, u32 Address,
-		      const int BlockSize, const u8 pBlock[])
-{
-	int status = 0, BlkSize = BlockSize;
-	u8 Flags = 0;
-
-	if (state->single_master)
-		Flags |= 0xC0;
-
-	while (BlkSize > 0) {
-		int Chunk = BlkSize > state->m_ChunkSize ?
-		    state->m_ChunkSize : BlkSize;
-		u8 *AdrBuf = &state->Chunk[0];
-		u32 AdrLength = 0;
-
-		if (DRXDAP_FASI_LONG_FORMAT(Address) || (Flags != 0)) {
-			AdrBuf[0] = (((Address << 1) & 0xFF) | 0x01);
-			AdrBuf[1] = ((Address >> 16) & 0xFF);
-			AdrBuf[2] = ((Address >> 24) & 0xFF);
-			AdrBuf[3] = ((Address >> 7) & 0xFF);
-			AdrBuf[2] |= Flags;
-			AdrLength = 4;
-			if (Chunk == state->m_ChunkSize)
-				Chunk -= 2;
-		} else {
-			AdrBuf[0] = ((Address << 1) & 0xFF);
-			AdrBuf[1] = (((Address >> 16) & 0x0F) |
-				     ((Address >> 18) & 0xF0));
-			AdrLength = 2;
-		}
-		memcpy(&state->Chunk[AdrLength], pBlock, Chunk);
-		dprintk(2, "(0x%08x, 0x%02x)\n", Address, Flags);
-		if (debug > 1) {
-			int i;
-			if (pBlock)
-				for (i = 0; i < Chunk; i++)
-					printk(KERN_CONT " %02x", pBlock[i]);
-			printk(KERN_CONT "\n");
-		}
-		status = i2c_write(state, state->demod_address,
-				   &state->Chunk[0], Chunk + AdrLength);
-		if (status < 0) {
-			printk(KERN_ERR "drxk: %s: i2c write error at addr 0x%02x\n",
-			       __func__, Address);
-			break;
-		}
-		pBlock += Chunk;
-		Address += (Chunk >> 1);
-		BlkSize -= Chunk;
-	}
-	return status;
-}
-
-#ifndef DRXK_MAX_RETRIES_POWERUP
-#define DRXK_MAX_RETRIES_POWERUP 20
-#endif
-
-int PowerUpDevice(struct drxk_state *state)
-{
-	int status;
-	u8 data = 0;
-	u16 retryCount = 0;
-
-	dprintk(1, "\n");
-
-	status = i2c_read1(state, state->demod_address, &data);
-	if (status < 0) {
-		do {
-			data = 0;
-			status = i2c_write(state, state->demod_address,
-					   &data, 1);
-			msleep(10);
-			retryCount++;
-			if (status < 0)
-				continue;
-			status = i2c_read1(state, state->demod_address,
-					   &data);
-		} while (status < 0 &&
-			 (retryCount < DRXK_MAX_RETRIES_POWERUP));
-		if (status < 0 && retryCount >= DRXK_MAX_RETRIES_POWERUP)
-			goto error;
-	}
-
-	/* Make sure all clk domains are active */
-	status = write16(state, SIO_CC_PWD_MODE__A, SIO_CC_PWD_MODE_LEVEL_NONE);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
-	if (status < 0)
-		goto error;
-	/* Enable pll lock tests */
-	status = write16(state, SIO_CC_PLL_LOCK__A, 1);
-	if (status < 0)
-		goto error;
-
-	state->m_currentPowerMode = DRX_POWER_UP;
-
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-
-	return status;
-}
-
-
-static int init_state(struct drxk_state *state)
-{
-	/*
-	 * FIXME: most (all?) of the values bellow should be moved into
-	 * struct drxk_config, as they are probably board-specific
-	 */
-	u32 ulVSBIfAgcMode = DRXK_AGC_CTRL_AUTO;
-	u32 ulVSBIfAgcOutputLevel = 0;
-	u32 ulVSBIfAgcMinLevel = 0;
-	u32 ulVSBIfAgcMaxLevel = 0x7FFF;
-	u32 ulVSBIfAgcSpeed = 3;
-
-	u32 ulVSBRfAgcMode = DRXK_AGC_CTRL_AUTO;
-	u32 ulVSBRfAgcOutputLevel = 0;
-	u32 ulVSBRfAgcMinLevel = 0;
-	u32 ulVSBRfAgcMaxLevel = 0x7FFF;
-	u32 ulVSBRfAgcSpeed = 3;
-	u32 ulVSBRfAgcTop = 9500;
-	u32 ulVSBRfAgcCutOffCurrent = 4000;
-
-	u32 ulATVIfAgcMode = DRXK_AGC_CTRL_AUTO;
-	u32 ulATVIfAgcOutputLevel = 0;
-	u32 ulATVIfAgcMinLevel = 0;
-	u32 ulATVIfAgcMaxLevel = 0;
-	u32 ulATVIfAgcSpeed = 3;
-
-	u32 ulATVRfAgcMode = DRXK_AGC_CTRL_OFF;
-	u32 ulATVRfAgcOutputLevel = 0;
-	u32 ulATVRfAgcMinLevel = 0;
-	u32 ulATVRfAgcMaxLevel = 0;
-	u32 ulATVRfAgcTop = 9500;
-	u32 ulATVRfAgcCutOffCurrent = 4000;
-	u32 ulATVRfAgcSpeed = 3;
-
-	u32 ulQual83 = DEFAULT_MER_83;
-	u32 ulQual93 = DEFAULT_MER_93;
-
-	u32 ulMpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
-	u32 ulDemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
-
-	/* io_pad_cfg register (8 bit reg.) MSB bit is 1 (default value) */
-	/* io_pad_cfg_mode output mode is drive always */
-	/* io_pad_cfg_drive is set to power 2 (23 mA) */
-	u32 ulGPIOCfg = 0x0113;
-	u32 ulInvertTSClock = 0;
-	u32 ulTSDataStrength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH;
-	u32 ulDVBTBitrate = 50000000;
-	u32 ulDVBCBitrate = DRXK_QAM_SYMBOLRATE_MAX * 8;
-
-	u32 ulInsertRSByte = 0;
-
-	u32 ulRfMirror = 1;
-	u32 ulPowerDown = 0;
-
-	dprintk(1, "\n");
-
-	state->m_hasLNA = false;
-	state->m_hasDVBT = false;
-	state->m_hasDVBC = false;
-	state->m_hasATV = false;
-	state->m_hasOOB = false;
-	state->m_hasAudio = false;
-
-	if (!state->m_ChunkSize)
-		state->m_ChunkSize = 124;
-
-	state->m_oscClockFreq = 0;
-	state->m_smartAntInverted = false;
-	state->m_bPDownOpenBridge = false;
-
-	/* real system clock frequency in kHz */
-	state->m_sysClockFreq = 151875;
-	/* Timing div, 250ns/Psys */
-	/* Timing div, = (delay (nano seconds) * sysclk (kHz))/ 1000 */
-	state->m_HICfgTimingDiv = ((state->m_sysClockFreq / 1000) *
-				   HI_I2C_DELAY) / 1000;
-	/* Clipping */
-	if (state->m_HICfgTimingDiv > SIO_HI_RA_RAM_PAR_2_CFG_DIV__M)
-		state->m_HICfgTimingDiv = SIO_HI_RA_RAM_PAR_2_CFG_DIV__M;
-	state->m_HICfgWakeUpKey = (state->demod_address << 1);
-	/* port/bridge/power down ctrl */
-	state->m_HICfgCtrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;
-
-	state->m_bPowerDown = (ulPowerDown != 0);
-
-	state->m_DRXK_A1_PATCH_CODE = false;
-	state->m_DRXK_A1_ROM_CODE = false;
-	state->m_DRXK_A2_ROM_CODE = false;
-	state->m_DRXK_A3_ROM_CODE = false;
-	state->m_DRXK_A2_PATCH_CODE = false;
-	state->m_DRXK_A3_PATCH_CODE = false;
-
-	/* Init AGC and PGA parameters */
-	/* VSB IF */
-	state->m_vsbIfAgcCfg.ctrlMode = (ulVSBIfAgcMode);
-	state->m_vsbIfAgcCfg.outputLevel = (ulVSBIfAgcOutputLevel);
-	state->m_vsbIfAgcCfg.minOutputLevel = (ulVSBIfAgcMinLevel);
-	state->m_vsbIfAgcCfg.maxOutputLevel = (ulVSBIfAgcMaxLevel);
-	state->m_vsbIfAgcCfg.speed = (ulVSBIfAgcSpeed);
-	state->m_vsbPgaCfg = 140;
-
-	/* VSB RF */
-	state->m_vsbRfAgcCfg.ctrlMode = (ulVSBRfAgcMode);
-	state->m_vsbRfAgcCfg.outputLevel = (ulVSBRfAgcOutputLevel);
-	state->m_vsbRfAgcCfg.minOutputLevel = (ulVSBRfAgcMinLevel);
-	state->m_vsbRfAgcCfg.maxOutputLevel = (ulVSBRfAgcMaxLevel);
-	state->m_vsbRfAgcCfg.speed = (ulVSBRfAgcSpeed);
-	state->m_vsbRfAgcCfg.top = (ulVSBRfAgcTop);
-	state->m_vsbRfAgcCfg.cutOffCurrent = (ulVSBRfAgcCutOffCurrent);
-	state->m_vsbPreSawCfg.reference = 0x07;
-	state->m_vsbPreSawCfg.usePreSaw = true;
-
-	state->m_Quality83percent = DEFAULT_MER_83;
-	state->m_Quality93percent = DEFAULT_MER_93;
-	if (ulQual93 <= 500 && ulQual83 < ulQual93) {
-		state->m_Quality83percent = ulQual83;
-		state->m_Quality93percent = ulQual93;
-	}
-
-	/* ATV IF */
-	state->m_atvIfAgcCfg.ctrlMode = (ulATVIfAgcMode);
-	state->m_atvIfAgcCfg.outputLevel = (ulATVIfAgcOutputLevel);
-	state->m_atvIfAgcCfg.minOutputLevel = (ulATVIfAgcMinLevel);
-	state->m_atvIfAgcCfg.maxOutputLevel = (ulATVIfAgcMaxLevel);
-	state->m_atvIfAgcCfg.speed = (ulATVIfAgcSpeed);
-
-	/* ATV RF */
-	state->m_atvRfAgcCfg.ctrlMode = (ulATVRfAgcMode);
-	state->m_atvRfAgcCfg.outputLevel = (ulATVRfAgcOutputLevel);
-	state->m_atvRfAgcCfg.minOutputLevel = (ulATVRfAgcMinLevel);
-	state->m_atvRfAgcCfg.maxOutputLevel = (ulATVRfAgcMaxLevel);
-	state->m_atvRfAgcCfg.speed = (ulATVRfAgcSpeed);
-	state->m_atvRfAgcCfg.top = (ulATVRfAgcTop);
-	state->m_atvRfAgcCfg.cutOffCurrent = (ulATVRfAgcCutOffCurrent);
-	state->m_atvPreSawCfg.reference = 0x04;
-	state->m_atvPreSawCfg.usePreSaw = true;
-
-
-	/* DVBT RF */
-	state->m_dvbtRfAgcCfg.ctrlMode = DRXK_AGC_CTRL_OFF;
-	state->m_dvbtRfAgcCfg.outputLevel = 0;
-	state->m_dvbtRfAgcCfg.minOutputLevel = 0;
-	state->m_dvbtRfAgcCfg.maxOutputLevel = 0xFFFF;
-	state->m_dvbtRfAgcCfg.top = 0x2100;
-	state->m_dvbtRfAgcCfg.cutOffCurrent = 4000;
-	state->m_dvbtRfAgcCfg.speed = 1;
-
-
-	/* DVBT IF */
-	state->m_dvbtIfAgcCfg.ctrlMode = DRXK_AGC_CTRL_AUTO;
-	state->m_dvbtIfAgcCfg.outputLevel = 0;
-	state->m_dvbtIfAgcCfg.minOutputLevel = 0;
-	state->m_dvbtIfAgcCfg.maxOutputLevel = 9000;
-	state->m_dvbtIfAgcCfg.top = 13424;
-	state->m_dvbtIfAgcCfg.cutOffCurrent = 0;
-	state->m_dvbtIfAgcCfg.speed = 3;
-	state->m_dvbtIfAgcCfg.FastClipCtrlDelay = 30;
-	state->m_dvbtIfAgcCfg.IngainTgtMax = 30000;
-	/* state->m_dvbtPgaCfg = 140; */
-
-	state->m_dvbtPreSawCfg.reference = 4;
-	state->m_dvbtPreSawCfg.usePreSaw = false;
-
-	/* QAM RF */
-	state->m_qamRfAgcCfg.ctrlMode = DRXK_AGC_CTRL_OFF;
-	state->m_qamRfAgcCfg.outputLevel = 0;
-	state->m_qamRfAgcCfg.minOutputLevel = 6023;
-	state->m_qamRfAgcCfg.maxOutputLevel = 27000;
-	state->m_qamRfAgcCfg.top = 0x2380;
-	state->m_qamRfAgcCfg.cutOffCurrent = 4000;
-	state->m_qamRfAgcCfg.speed = 3;
-
-	/* QAM IF */
-	state->m_qamIfAgcCfg.ctrlMode = DRXK_AGC_CTRL_AUTO;
-	state->m_qamIfAgcCfg.outputLevel = 0;
-	state->m_qamIfAgcCfg.minOutputLevel = 0;
-	state->m_qamIfAgcCfg.maxOutputLevel = 9000;
-	state->m_qamIfAgcCfg.top = 0x0511;
-	state->m_qamIfAgcCfg.cutOffCurrent = 0;
-	state->m_qamIfAgcCfg.speed = 3;
-	state->m_qamIfAgcCfg.IngainTgtMax = 5119;
-	state->m_qamIfAgcCfg.FastClipCtrlDelay = 50;
-
-	state->m_qamPgaCfg = 140;
-	state->m_qamPreSawCfg.reference = 4;
-	state->m_qamPreSawCfg.usePreSaw = false;
-
-	state->m_OperationMode = OM_NONE;
-	state->m_DrxkState = DRXK_UNINITIALIZED;
-
-	/* MPEG output configuration */
-	state->m_enableMPEGOutput = true;	/* If TRUE; enable MPEG ouput */
-	state->m_insertRSByte = false;	/* If TRUE; insert RS byte */
-	state->m_invertDATA = false;	/* If TRUE; invert DATA signals */
-	state->m_invertERR = false;	/* If TRUE; invert ERR signal */
-	state->m_invertSTR = false;	/* If TRUE; invert STR signals */
-	state->m_invertVAL = false;	/* If TRUE; invert VAL signals */
-	state->m_invertCLK = (ulInvertTSClock != 0);	/* If TRUE; invert CLK signals */
-
-	/* If TRUE; static MPEG clockrate will be used;
-	   otherwise clockrate will adapt to the bitrate of the TS */
-
-	state->m_DVBTBitrate = ulDVBTBitrate;
-	state->m_DVBCBitrate = ulDVBCBitrate;
-
-	state->m_TSDataStrength = (ulTSDataStrength & 0x07);
-
-	/* Maximum bitrate in b/s in case static clockrate is selected */
-	state->m_mpegTsStaticBitrate = 19392658;
-	state->m_disableTEIhandling = false;
-
-	if (ulInsertRSByte)
-		state->m_insertRSByte = true;
-
-	state->m_MpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
-	if (ulMpegLockTimeOut < 10000)
-		state->m_MpegLockTimeOut = ulMpegLockTimeOut;
-	state->m_DemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
-	if (ulDemodLockTimeOut < 10000)
-		state->m_DemodLockTimeOut = ulDemodLockTimeOut;
-
-	/* QAM defaults */
-	state->m_Constellation = DRX_CONSTELLATION_AUTO;
-	state->m_qamInterleaveMode = DRXK_QAM_I12_J17;
-	state->m_fecRsPlen = 204 * 8;	/* fecRsPlen  annex A */
-	state->m_fecRsPrescale = 1;
-
-	state->m_sqiSpeed = DRXK_DVBT_SQI_SPEED_MEDIUM;
-	state->m_agcFastClipCtrlDelay = 0;
-
-	state->m_GPIOCfg = (ulGPIOCfg);
-
-	state->m_bPowerDown = false;
-	state->m_currentPowerMode = DRX_POWER_DOWN;
-
-	state->m_rfmirror = (ulRfMirror == 0);
-	state->m_IfAgcPol = false;
-	return 0;
-}
-
-static int DRXX_Open(struct drxk_state *state)
-{
-	int status = 0;
-	u32 jtag = 0;
-	u16 bid = 0;
-	u16 key = 0;
-
-	dprintk(1, "\n");
-	/* stop lock indicator process */
-	status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
-	if (status < 0)
-		goto error;
-	/* Check device id */
-	status = read16(state, SIO_TOP_COMM_KEY__A, &key);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY);
-	if (status < 0)
-		goto error;
-	status = read32(state, SIO_TOP_JTAGID_LO__A, &jtag);
-	if (status < 0)
-		goto error;
-	status = read16(state, SIO_PDR_UIO_IN_HI__A, &bid);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_TOP_COMM_KEY__A, key);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int GetDeviceCapabilities(struct drxk_state *state)
-{
-	u16 sioPdrOhwCfg = 0;
-	u32 sioTopJtagidLo = 0;
-	int status;
-	const char *spin = "";
-
-	dprintk(1, "\n");
-
-	/* driver 0.9.0 */
-	/* stop lock indicator process */
-	status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_TOP_COMM_KEY__A, 0xFABA);
-	if (status < 0)
-		goto error;
-	status = read16(state, SIO_PDR_OHW_CFG__A, &sioPdrOhwCfg);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
-	if (status < 0)
-		goto error;
-
-	switch ((sioPdrOhwCfg & SIO_PDR_OHW_CFG_FREF_SEL__M)) {
-	case 0:
-		/* ignore (bypass ?) */
-		break;
-	case 1:
-		/* 27 MHz */
-		state->m_oscClockFreq = 27000;
-		break;
-	case 2:
-		/* 20.25 MHz */
-		state->m_oscClockFreq = 20250;
-		break;
-	case 3:
-		/* 4 MHz */
-		state->m_oscClockFreq = 20250;
-		break;
-	default:
-		printk(KERN_ERR "drxk: Clock Frequency is unkonwn\n");
-		return -EINVAL;
-	}
-	/*
-		Determine device capabilities
-		Based on pinning v14
-		*/
-	status = read32(state, SIO_TOP_JTAGID_LO__A, &sioTopJtagidLo);
-	if (status < 0)
-		goto error;
-
-	printk(KERN_INFO "drxk: status = 0x%08x\n", sioTopJtagidLo);
-
-	/* driver 0.9.0 */
-	switch ((sioTopJtagidLo >> 29) & 0xF) {
-	case 0:
-		state->m_deviceSpin = DRXK_SPIN_A1;
-		spin = "A1";
-		break;
-	case 2:
-		state->m_deviceSpin = DRXK_SPIN_A2;
-		spin = "A2";
-		break;
-	case 3:
-		state->m_deviceSpin = DRXK_SPIN_A3;
-		spin = "A3";
-		break;
-	default:
-		state->m_deviceSpin = DRXK_SPIN_UNKNOWN;
-		status = -EINVAL;
-		printk(KERN_ERR "drxk: Spin %d unknown\n",
-		       (sioTopJtagidLo >> 29) & 0xF);
-		goto error2;
-	}
-	switch ((sioTopJtagidLo >> 12) & 0xFF) {
-	case 0x13:
-		/* typeId = DRX3913K_TYPE_ID */
-		state->m_hasLNA = false;
-		state->m_hasOOB = false;
-		state->m_hasATV = false;
-		state->m_hasAudio = false;
-		state->m_hasDVBT = true;
-		state->m_hasDVBC = true;
-		state->m_hasSAWSW = true;
-		state->m_hasGPIO2 = false;
-		state->m_hasGPIO1 = false;
-		state->m_hasIRQN = false;
-		break;
-	case 0x15:
-		/* typeId = DRX3915K_TYPE_ID */
-		state->m_hasLNA = false;
-		state->m_hasOOB = false;
-		state->m_hasATV = true;
-		state->m_hasAudio = false;
-		state->m_hasDVBT = true;
-		state->m_hasDVBC = false;
-		state->m_hasSAWSW = true;
-		state->m_hasGPIO2 = true;
-		state->m_hasGPIO1 = true;
-		state->m_hasIRQN = false;
-		break;
-	case 0x16:
-		/* typeId = DRX3916K_TYPE_ID */
-		state->m_hasLNA = false;
-		state->m_hasOOB = false;
-		state->m_hasATV = true;
-		state->m_hasAudio = false;
-		state->m_hasDVBT = true;
-		state->m_hasDVBC = false;
-		state->m_hasSAWSW = true;
-		state->m_hasGPIO2 = true;
-		state->m_hasGPIO1 = true;
-		state->m_hasIRQN = false;
-		break;
-	case 0x18:
-		/* typeId = DRX3918K_TYPE_ID */
-		state->m_hasLNA = false;
-		state->m_hasOOB = false;
-		state->m_hasATV = true;
-		state->m_hasAudio = true;
-		state->m_hasDVBT = true;
-		state->m_hasDVBC = false;
-		state->m_hasSAWSW = true;
-		state->m_hasGPIO2 = true;
-		state->m_hasGPIO1 = true;
-		state->m_hasIRQN = false;
-		break;
-	case 0x21:
-		/* typeId = DRX3921K_TYPE_ID */
-		state->m_hasLNA = false;
-		state->m_hasOOB = false;
-		state->m_hasATV = true;
-		state->m_hasAudio = true;
-		state->m_hasDVBT = true;
-		state->m_hasDVBC = true;
-		state->m_hasSAWSW = true;
-		state->m_hasGPIO2 = true;
-		state->m_hasGPIO1 = true;
-		state->m_hasIRQN = false;
-		break;
-	case 0x23:
-		/* typeId = DRX3923K_TYPE_ID */
-		state->m_hasLNA = false;
-		state->m_hasOOB = false;
-		state->m_hasATV = true;
-		state->m_hasAudio = true;
-		state->m_hasDVBT = true;
-		state->m_hasDVBC = true;
-		state->m_hasSAWSW = true;
-		state->m_hasGPIO2 = true;
-		state->m_hasGPIO1 = true;
-		state->m_hasIRQN = false;
-		break;
-	case 0x25:
-		/* typeId = DRX3925K_TYPE_ID */
-		state->m_hasLNA = false;
-		state->m_hasOOB = false;
-		state->m_hasATV = true;
-		state->m_hasAudio = true;
-		state->m_hasDVBT = true;
-		state->m_hasDVBC = true;
-		state->m_hasSAWSW = true;
-		state->m_hasGPIO2 = true;
-		state->m_hasGPIO1 = true;
-		state->m_hasIRQN = false;
-		break;
-	case 0x26:
-		/* typeId = DRX3926K_TYPE_ID */
-		state->m_hasLNA = false;
-		state->m_hasOOB = false;
-		state->m_hasATV = true;
-		state->m_hasAudio = false;
-		state->m_hasDVBT = true;
-		state->m_hasDVBC = true;
-		state->m_hasSAWSW = true;
-		state->m_hasGPIO2 = true;
-		state->m_hasGPIO1 = true;
-		state->m_hasIRQN = false;
-		break;
-	default:
-		printk(KERN_ERR "drxk: DeviceID 0x%02x not supported\n",
-			((sioTopJtagidLo >> 12) & 0xFF));
-		status = -EINVAL;
-		goto error2;
-	}
-
-	printk(KERN_INFO
-	       "drxk: detected a drx-39%02xk, spin %s, xtal %d.%03d MHz\n",
-	       ((sioTopJtagidLo >> 12) & 0xFF), spin,
-	       state->m_oscClockFreq / 1000,
-	       state->m_oscClockFreq % 1000);
-
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-
-error2:
-	return status;
-}
-
-static int HI_Command(struct drxk_state *state, u16 cmd, u16 *pResult)
-{
-	int status;
-	bool powerdown_cmd;
-
-	dprintk(1, "\n");
-
-	/* Write command */
-	status = write16(state, SIO_HI_RA_RAM_CMD__A, cmd);
-	if (status < 0)
-		goto error;
-	if (cmd == SIO_HI_RA_RAM_CMD_RESET)
-		msleep(1);
-
-	powerdown_cmd =
-	    (bool) ((cmd == SIO_HI_RA_RAM_CMD_CONFIG) &&
-		    ((state->m_HICfgCtrl) &
-		     SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M) ==
-		    SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ);
-	if (powerdown_cmd == false) {
-		/* Wait until command rdy */
-		u32 retryCount = 0;
-		u16 waitCmd;
-
-		do {
-			msleep(1);
-			retryCount += 1;
-			status = read16(state, SIO_HI_RA_RAM_CMD__A,
-					  &waitCmd);
-		} while ((status < 0) && (retryCount < DRXK_MAX_RETRIES)
-			 && (waitCmd != 0));
-		if (status < 0)
-			goto error;
-		status = read16(state, SIO_HI_RA_RAM_RES__A, pResult);
-	}
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-
-	return status;
-}
-
-static int HI_CfgCommand(struct drxk_state *state)
-{
-	int status;
-
-	dprintk(1, "\n");
-
-	mutex_lock(&state->mutex);
-
-	status = write16(state, SIO_HI_RA_RAM_PAR_6__A, state->m_HICfgTimeout);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_HI_RA_RAM_PAR_5__A, state->m_HICfgCtrl);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_HI_RA_RAM_PAR_4__A, state->m_HICfgWakeUpKey);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_HI_RA_RAM_PAR_3__A, state->m_HICfgBridgeDelay);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_HI_RA_RAM_PAR_2__A, state->m_HICfgTimingDiv);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_HI_RA_RAM_PAR_1__A, SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
-	if (status < 0)
-		goto error;
-	status = HI_Command(state, SIO_HI_RA_RAM_CMD_CONFIG, 0);
-	if (status < 0)
-		goto error;
-
-	state->m_HICfgCtrl &= ~SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
-error:
-	mutex_unlock(&state->mutex);
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int InitHI(struct drxk_state *state)
-{
-	dprintk(1, "\n");
-
-	state->m_HICfgWakeUpKey = (state->demod_address << 1);
-	state->m_HICfgTimeout = 0x96FF;
-	/* port/bridge/power down ctrl */
-	state->m_HICfgCtrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;
-
-	return HI_CfgCommand(state);
-}
-
-static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
-{
-	int status = -1;
-	u16 sioPdrMclkCfg = 0;
-	u16 sioPdrMdxCfg = 0;
-	u16 err_cfg = 0;
-
-	dprintk(1, ": mpeg %s, %s mode\n",
-		mpegEnable ? "enable" : "disable",
-		state->m_enableParallel ? "parallel" : "serial");
-
-	/* stop lock indicator process */
-	status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
-	if (status < 0)
-		goto error;
-
-	/*  MPEG TS pad configuration */
-	status = write16(state, SIO_TOP_COMM_KEY__A, 0xFABA);
-	if (status < 0)
-		goto error;
-
-	if (mpegEnable == false) {
-		/*  Set MPEG TS pads to inputmode */
-		status = write16(state, SIO_PDR_MSTRT_CFG__A, 0x0000);
-		if (status < 0)
-			goto error;
-		status = write16(state, SIO_PDR_MERR_CFG__A, 0x0000);
-		if (status < 0)
-			goto error;
-		status = write16(state, SIO_PDR_MCLK_CFG__A, 0x0000);
-		if (status < 0)
-			goto error;
-		status = write16(state, SIO_PDR_MVAL_CFG__A, 0x0000);
-		if (status < 0)
-			goto error;
-		status = write16(state, SIO_PDR_MD0_CFG__A, 0x0000);
-		if (status < 0)
-			goto error;
-		status = write16(state, SIO_PDR_MD1_CFG__A, 0x0000);
-		if (status < 0)
-			goto error;
-		status = write16(state, SIO_PDR_MD2_CFG__A, 0x0000);
-		if (status < 0)
-			goto error;
-		status = write16(state, SIO_PDR_MD3_CFG__A, 0x0000);
-		if (status < 0)
-			goto error;
-		status = write16(state, SIO_PDR_MD4_CFG__A, 0x0000);
-		if (status < 0)
-			goto error;
-		status = write16(state, SIO_PDR_MD5_CFG__A, 0x0000);
-		if (status < 0)
-			goto error;
-		status = write16(state, SIO_PDR_MD6_CFG__A, 0x0000);
-		if (status < 0)
-			goto error;
-		status = write16(state, SIO_PDR_MD7_CFG__A, 0x0000);
-		if (status < 0)
-			goto error;
-	} else {
-		/* Enable MPEG output */
-		sioPdrMdxCfg =
-			((state->m_TSDataStrength <<
-			SIO_PDR_MD0_CFG_DRIVE__B) | 0x0003);
-		sioPdrMclkCfg = ((state->m_TSClockkStrength <<
-					SIO_PDR_MCLK_CFG_DRIVE__B) |
-					0x0003);
-
-		status = write16(state, SIO_PDR_MSTRT_CFG__A, sioPdrMdxCfg);
-		if (status < 0)
-			goto error;
-
-		if (state->enable_merr_cfg)
-			err_cfg = sioPdrMdxCfg;
-
-		status = write16(state, SIO_PDR_MERR_CFG__A, err_cfg);
-		if (status < 0)
-			goto error;
-		status = write16(state, SIO_PDR_MVAL_CFG__A, err_cfg);
-		if (status < 0)
-			goto error;
-
-		if (state->m_enableParallel == true) {
-			/* paralel -> enable MD1 to MD7 */
-			status = write16(state, SIO_PDR_MD1_CFG__A, sioPdrMdxCfg);
-			if (status < 0)
-				goto error;
-			status = write16(state, SIO_PDR_MD2_CFG__A, sioPdrMdxCfg);
-			if (status < 0)
-				goto error;
-			status = write16(state, SIO_PDR_MD3_CFG__A, sioPdrMdxCfg);
-			if (status < 0)
-				goto error;
-			status = write16(state, SIO_PDR_MD4_CFG__A, sioPdrMdxCfg);
-			if (status < 0)
-				goto error;
-			status = write16(state, SIO_PDR_MD5_CFG__A, sioPdrMdxCfg);
-			if (status < 0)
-				goto error;
-			status = write16(state, SIO_PDR_MD6_CFG__A, sioPdrMdxCfg);
-			if (status < 0)
-				goto error;
-			status = write16(state, SIO_PDR_MD7_CFG__A, sioPdrMdxCfg);
-			if (status < 0)
-				goto error;
-		} else {
-			sioPdrMdxCfg = ((state->m_TSDataStrength <<
-						SIO_PDR_MD0_CFG_DRIVE__B)
-					| 0x0003);
-			/* serial -> disable MD1 to MD7 */
-			status = write16(state, SIO_PDR_MD1_CFG__A, 0x0000);
-			if (status < 0)
-				goto error;
-			status = write16(state, SIO_PDR_MD2_CFG__A, 0x0000);
-			if (status < 0)
-				goto error;
-			status = write16(state, SIO_PDR_MD3_CFG__A, 0x0000);
-			if (status < 0)
-				goto error;
-			status = write16(state, SIO_PDR_MD4_CFG__A, 0x0000);
-			if (status < 0)
-				goto error;
-			status = write16(state, SIO_PDR_MD5_CFG__A, 0x0000);
-			if (status < 0)
-				goto error;
-			status = write16(state, SIO_PDR_MD6_CFG__A, 0x0000);
-			if (status < 0)
-				goto error;
-			status = write16(state, SIO_PDR_MD7_CFG__A, 0x0000);
-			if (status < 0)
-				goto error;
-		}
-		status = write16(state, SIO_PDR_MCLK_CFG__A, sioPdrMclkCfg);
-		if (status < 0)
-			goto error;
-		status = write16(state, SIO_PDR_MD0_CFG__A, sioPdrMdxCfg);
-		if (status < 0)
-			goto error;
-	}
-	/*  Enable MB output over MPEG pads and ctl input */
-	status = write16(state, SIO_PDR_MON_CFG__A, 0x0000);
-	if (status < 0)
-		goto error;
-	/*  Write nomagic word to enable pdr reg write */
-	status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int MPEGTSDisable(struct drxk_state *state)
-{
-	dprintk(1, "\n");
-
-	return MPEGTSConfigurePins(state, false);
-}
-
-static int BLChainCmd(struct drxk_state *state,
-		      u16 romOffset, u16 nrOfElements, u32 timeOut)
-{
-	u16 blStatus = 0;
-	int status;
-	unsigned long end;
-
-	dprintk(1, "\n");
-	mutex_lock(&state->mutex);
-	status = write16(state, SIO_BL_MODE__A, SIO_BL_MODE_CHAIN);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_BL_CHAIN_ADDR__A, romOffset);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_BL_CHAIN_LEN__A, nrOfElements);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_BL_ENABLE__A, SIO_BL_ENABLE_ON);
-	if (status < 0)
-		goto error;
-
-	end = jiffies + msecs_to_jiffies(timeOut);
-	do {
-		msleep(1);
-		status = read16(state, SIO_BL_STATUS__A, &blStatus);
-		if (status < 0)
-			goto error;
-	} while ((blStatus == 0x1) &&
-			((time_is_after_jiffies(end))));
-
-	if (blStatus == 0x1) {
-		printk(KERN_ERR "drxk: SIO not ready\n");
-		status = -EINVAL;
-		goto error2;
-	}
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-error2:
-	mutex_unlock(&state->mutex);
-	return status;
-}
-
-
-static int DownloadMicrocode(struct drxk_state *state,
-			     const u8 pMCImage[], u32 Length)
-{
-	const u8 *pSrc = pMCImage;
-	u32 Address;
-	u16 nBlocks;
-	u16 BlockSize;
-	u32 offset = 0;
-	u32 i;
-	int status = 0;
-
-	dprintk(1, "\n");
-
-	/* down the drain (we don't care about MAGIC_WORD) */
-#if 0
-	/* For future reference */
-	Drain = (pSrc[0] << 8) | pSrc[1];
-#endif
-	pSrc += sizeof(u16);
-	offset += sizeof(u16);
-	nBlocks = (pSrc[0] << 8) | pSrc[1];
-	pSrc += sizeof(u16);
-	offset += sizeof(u16);
-
-	for (i = 0; i < nBlocks; i += 1) {
-		Address = (pSrc[0] << 24) | (pSrc[1] << 16) |
-		    (pSrc[2] << 8) | pSrc[3];
-		pSrc += sizeof(u32);
-		offset += sizeof(u32);
-
-		BlockSize = ((pSrc[0] << 8) | pSrc[1]) * sizeof(u16);
-		pSrc += sizeof(u16);
-		offset += sizeof(u16);
-
-#if 0
-		/* For future reference */
-		Flags = (pSrc[0] << 8) | pSrc[1];
-#endif
-		pSrc += sizeof(u16);
-		offset += sizeof(u16);
-
-#if 0
-		/* For future reference */
-		BlockCRC = (pSrc[0] << 8) | pSrc[1];
-#endif
-		pSrc += sizeof(u16);
-		offset += sizeof(u16);
-
-		if (offset + BlockSize > Length) {
-			printk(KERN_ERR "drxk: Firmware is corrupted.\n");
-			return -EINVAL;
-		}
-
-		status = write_block(state, Address, BlockSize, pSrc);
-		if (status < 0) {
-			printk(KERN_ERR "drxk: Error %d while loading firmware\n", status);
-			break;
-		}
-		pSrc += BlockSize;
-		offset += BlockSize;
-	}
-	return status;
-}
-
-static int DVBTEnableOFDMTokenRing(struct drxk_state *state, bool enable)
-{
-	int status;
-	u16 data = 0;
-	u16 desiredCtrl = SIO_OFDM_SH_OFDM_RING_ENABLE_ON;
-	u16 desiredStatus = SIO_OFDM_SH_OFDM_RING_STATUS_ENABLED;
-	unsigned long end;
-
-	dprintk(1, "\n");
-
-	if (enable == false) {
-		desiredCtrl = SIO_OFDM_SH_OFDM_RING_ENABLE_OFF;
-		desiredStatus = SIO_OFDM_SH_OFDM_RING_STATUS_DOWN;
-	}
-
-	status = read16(state, SIO_OFDM_SH_OFDM_RING_STATUS__A, &data);
-	if (status >= 0 && data == desiredStatus) {
-		/* tokenring already has correct status */
-		return status;
-	}
-	/* Disable/enable dvbt tokenring bridge   */
-	status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, desiredCtrl);
-
-	end = jiffies + msecs_to_jiffies(DRXK_OFDM_TR_SHUTDOWN_TIMEOUT);
-	do {
-		status = read16(state, SIO_OFDM_SH_OFDM_RING_STATUS__A, &data);
-		if ((status >= 0 && data == desiredStatus) || time_is_after_jiffies(end))
-			break;
-		msleep(1);
-	} while (1);
-	if (data != desiredStatus) {
-		printk(KERN_ERR "drxk: SIO not ready\n");
-		return -EINVAL;
-	}
-	return status;
-}
-
-static int MPEGTSStop(struct drxk_state *state)
-{
-	int status = 0;
-	u16 fecOcSncMode = 0;
-	u16 fecOcIprMode = 0;
-
-	dprintk(1, "\n");
-
-	/* Gracefull shutdown (byte boundaries) */
-	status = read16(state, FEC_OC_SNC_MODE__A, &fecOcSncMode);
-	if (status < 0)
-		goto error;
-	fecOcSncMode |= FEC_OC_SNC_MODE_SHUTDOWN__M;
-	status = write16(state, FEC_OC_SNC_MODE__A, fecOcSncMode);
-	if (status < 0)
-		goto error;
-
-	/* Suppress MCLK during absence of data */
-	status = read16(state, FEC_OC_IPR_MODE__A, &fecOcIprMode);
-	if (status < 0)
-		goto error;
-	fecOcIprMode |= FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__M;
-	status = write16(state, FEC_OC_IPR_MODE__A, fecOcIprMode);
-
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-
-	return status;
-}
-
-static int scu_command(struct drxk_state *state,
-		       u16 cmd, u8 parameterLen,
-		       u16 *parameter, u8 resultLen, u16 *result)
-{
-#if (SCU_RAM_PARAM_0__A - SCU_RAM_PARAM_15__A) != 15
-#error DRXK register mapping no longer compatible with this routine!
-#endif
-	u16 curCmd = 0;
-	int status = -EINVAL;
-	unsigned long end;
-	u8 buffer[34];
-	int cnt = 0, ii;
-	const char *p;
-	char errname[30];
-
-	dprintk(1, "\n");
-
-	if ((cmd == 0) || ((parameterLen > 0) && (parameter == NULL)) ||
-	    ((resultLen > 0) && (result == NULL))) {
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-		return status;
-	}
-
-	mutex_lock(&state->mutex);
-
-	/* assume that the command register is ready
-		since it is checked afterwards */
-	for (ii = parameterLen - 1; ii >= 0; ii -= 1) {
-		buffer[cnt++] = (parameter[ii] & 0xFF);
-		buffer[cnt++] = ((parameter[ii] >> 8) & 0xFF);
-	}
-	buffer[cnt++] = (cmd & 0xFF);
-	buffer[cnt++] = ((cmd >> 8) & 0xFF);
-
-	write_block(state, SCU_RAM_PARAM_0__A -
-			(parameterLen - 1), cnt, buffer);
-	/* Wait until SCU has processed command */
-	end = jiffies + msecs_to_jiffies(DRXK_MAX_WAITTIME);
-	do {
-		msleep(1);
-		status = read16(state, SCU_RAM_COMMAND__A, &curCmd);
-		if (status < 0)
-			goto error;
-	} while (!(curCmd == DRX_SCU_READY) && (time_is_after_jiffies(end)));
-	if (curCmd != DRX_SCU_READY) {
-		printk(KERN_ERR "drxk: SCU not ready\n");
-		status = -EIO;
-		goto error2;
-	}
-	/* read results */
-	if ((resultLen > 0) && (result != NULL)) {
-		s16 err;
-		int ii;
-
-		for (ii = resultLen - 1; ii >= 0; ii -= 1) {
-			status = read16(state, SCU_RAM_PARAM_0__A - ii, &result[ii]);
-			if (status < 0)
-				goto error;
-		}
-
-		/* Check if an error was reported by SCU */
-		err = (s16)result[0];
-		if (err >= 0)
-			goto error;
-
-		/* check for the known error codes */
-		switch (err) {
-		case SCU_RESULT_UNKCMD:
-			p = "SCU_RESULT_UNKCMD";
-			break;
-		case SCU_RESULT_UNKSTD:
-			p = "SCU_RESULT_UNKSTD";
-			break;
-		case SCU_RESULT_SIZE:
-			p = "SCU_RESULT_SIZE";
-			break;
-		case SCU_RESULT_INVPAR:
-			p = "SCU_RESULT_INVPAR";
-			break;
-		default: /* Other negative values are errors */
-			sprintf(errname, "ERROR: %d\n", err);
-			p = errname;
-		}
-		printk(KERN_ERR "drxk: %s while sending cmd 0x%04x with params:", p, cmd);
-		print_hex_dump_bytes("drxk: ", DUMP_PREFIX_NONE, buffer, cnt);
-		status = -EINVAL;
-		goto error2;
-	}
-
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-error2:
-	mutex_unlock(&state->mutex);
-	return status;
-}
-
-static int SetIqmAf(struct drxk_state *state, bool active)
-{
-	u16 data = 0;
-	int status;
-
-	dprintk(1, "\n");
-
-	/* Configure IQM */
-	status = read16(state, IQM_AF_STDBY__A, &data);
-	if (status < 0)
-		goto error;
-
-	if (!active) {
-		data |= (IQM_AF_STDBY_STDBY_ADC_STANDBY
-				| IQM_AF_STDBY_STDBY_AMP_STANDBY
-				| IQM_AF_STDBY_STDBY_PD_STANDBY
-				| IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY
-				| IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY);
-	} else {
-		data &= ((~IQM_AF_STDBY_STDBY_ADC_STANDBY)
-				& (~IQM_AF_STDBY_STDBY_AMP_STANDBY)
-				& (~IQM_AF_STDBY_STDBY_PD_STANDBY)
-				& (~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY)
-				& (~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY)
-			);
-	}
-	status = write16(state, IQM_AF_STDBY__A, data);
-
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int CtrlPowerMode(struct drxk_state *state, enum DRXPowerMode *mode)
-{
-	int status = 0;
-	u16 sioCcPwdMode = 0;
-
-	dprintk(1, "\n");
-
-	/* Check arguments */
-	if (mode == NULL)
-		return -EINVAL;
-
-	switch (*mode) {
-	case DRX_POWER_UP:
-		sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_NONE;
-		break;
-	case DRXK_POWER_DOWN_OFDM:
-		sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_OFDM;
-		break;
-	case DRXK_POWER_DOWN_CORE:
-		sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_CLOCK;
-		break;
-	case DRXK_POWER_DOWN_PLL:
-		sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_PLL;
-		break;
-	case DRX_POWER_DOWN:
-		sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_OSC;
-		break;
-	default:
-		/* Unknow sleep mode */
-		return -EINVAL;
-	}
-
-	/* If already in requested power mode, do nothing */
-	if (state->m_currentPowerMode == *mode)
-		return 0;
-
-	/* For next steps make sure to start from DRX_POWER_UP mode */
-	if (state->m_currentPowerMode != DRX_POWER_UP) {
-		status = PowerUpDevice(state);
-		if (status < 0)
-			goto error;
-		status = DVBTEnableOFDMTokenRing(state, true);
-		if (status < 0)
-			goto error;
-	}
-
-	if (*mode == DRX_POWER_UP) {
-		/* Restore analog & pin configuartion */
-	} else {
-		/* Power down to requested mode */
-		/* Backup some register settings */
-		/* Set pins with possible pull-ups connected
-		   to them in input mode */
-		/* Analog power down */
-		/* ADC power down */
-		/* Power down device */
-		/* stop all comm_exec */
-		/* Stop and power down previous standard */
-		switch (state->m_OperationMode) {
-		case OM_DVBT:
-			status = MPEGTSStop(state);
-			if (status < 0)
-				goto error;
-			status = PowerDownDVBT(state, false);
-			if (status < 0)
-				goto error;
-			break;
-		case OM_QAM_ITU_A:
-		case OM_QAM_ITU_C:
-			status = MPEGTSStop(state);
-			if (status < 0)
-				goto error;
-			status = PowerDownQAM(state);
-			if (status < 0)
-				goto error;
-			break;
-		default:
-			break;
-		}
-		status = DVBTEnableOFDMTokenRing(state, false);
-		if (status < 0)
-			goto error;
-		status = write16(state, SIO_CC_PWD_MODE__A, sioCcPwdMode);
-		if (status < 0)
-			goto error;
-		status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
-		if (status < 0)
-			goto error;
-
-		if (*mode != DRXK_POWER_DOWN_OFDM) {
-			state->m_HICfgCtrl |=
-				SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
-			status = HI_CfgCommand(state);
-			if (status < 0)
-				goto error;
-		}
-	}
-	state->m_currentPowerMode = *mode;
-
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-
-	return status;
-}
-
-static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode)
-{
-	enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
-	u16 cmdResult = 0;
-	u16 data = 0;
-	int status;
-
-	dprintk(1, "\n");
-
-	status = read16(state, SCU_COMM_EXEC__A, &data);
-	if (status < 0)
-		goto error;
-	if (data == SCU_COMM_EXEC_ACTIVE) {
-		/* Send OFDM stop command */
-		status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
-		if (status < 0)
-			goto error;
-		/* Send OFDM reset command */
-		status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
-		if (status < 0)
-			goto error;
-	}
-
-	/* Reset datapath for OFDM, processors first */
-	status = write16(state, OFDM_SC_COMM_EXEC__A, OFDM_SC_COMM_EXEC_STOP);
-	if (status < 0)
-		goto error;
-	status = write16(state, OFDM_LC_COMM_EXEC__A, OFDM_LC_COMM_EXEC_STOP);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_STOP);
-	if (status < 0)
-		goto error;
-
-	/* powerdown AFE                   */
-	status = SetIqmAf(state, false);
-	if (status < 0)
-		goto error;
-
-	/* powerdown to OFDM mode          */
-	if (setPowerMode) {
-		status = CtrlPowerMode(state, &powerMode);
-		if (status < 0)
-			goto error;
-	}
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int SetOperationMode(struct drxk_state *state,
-			    enum OperationMode oMode)
-{
-	int status = 0;
-
-	dprintk(1, "\n");
-	/*
-	   Stop and power down previous standard
-	   TODO investigate total power down instead of partial
-	   power down depending on "previous" standard.
-	 */
-
-	/* disable HW lock indicator */
-	status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
-	if (status < 0)
-		goto error;
-
-	/* Device is already at the required mode */
-	if (state->m_OperationMode == oMode)
-		return 0;
-
-	switch (state->m_OperationMode) {
-		/* OM_NONE was added for start up */
-	case OM_NONE:
-		break;
-	case OM_DVBT:
-		status = MPEGTSStop(state);
-		if (status < 0)
-			goto error;
-		status = PowerDownDVBT(state, true);
-		if (status < 0)
-			goto error;
-		state->m_OperationMode = OM_NONE;
-		break;
-	case OM_QAM_ITU_A:	/* fallthrough */
-	case OM_QAM_ITU_C:
-		status = MPEGTSStop(state);
-		if (status < 0)
-			goto error;
-		status = PowerDownQAM(state);
-		if (status < 0)
-			goto error;
-		state->m_OperationMode = OM_NONE;
-		break;
-	case OM_QAM_ITU_B:
-	default:
-		status = -EINVAL;
-		goto error;
-	}
-
-	/*
-		Power up new standard
-		*/
-	switch (oMode) {
-	case OM_DVBT:
-		dprintk(1, ": DVB-T\n");
-		state->m_OperationMode = oMode;
-		status = SetDVBTStandard(state, oMode);
-		if (status < 0)
-			goto error;
-		break;
-	case OM_QAM_ITU_A:	/* fallthrough */
-	case OM_QAM_ITU_C:
-		dprintk(1, ": DVB-C Annex %c\n",
-			(state->m_OperationMode == OM_QAM_ITU_A) ? 'A' : 'C');
-		state->m_OperationMode = oMode;
-		status = SetQAMStandard(state, oMode);
-		if (status < 0)
-			goto error;
-		break;
-	case OM_QAM_ITU_B:
-	default:
-		status = -EINVAL;
-	}
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int Start(struct drxk_state *state, s32 offsetFreq,
-		 s32 IntermediateFrequency)
-{
-	int status = -EINVAL;
-
-	u16 IFreqkHz;
-	s32 OffsetkHz = offsetFreq / 1000;
-
-	dprintk(1, "\n");
-	if (state->m_DrxkState != DRXK_STOPPED &&
-		state->m_DrxkState != DRXK_DTV_STARTED)
-		goto error;
-
-	state->m_bMirrorFreqSpect = (state->props.inversion == INVERSION_ON);
-
-	if (IntermediateFrequency < 0) {
-		state->m_bMirrorFreqSpect = !state->m_bMirrorFreqSpect;
-		IntermediateFrequency = -IntermediateFrequency;
-	}
-
-	switch (state->m_OperationMode) {
-	case OM_QAM_ITU_A:
-	case OM_QAM_ITU_C:
-		IFreqkHz = (IntermediateFrequency / 1000);
-		status = SetQAM(state, IFreqkHz, OffsetkHz);
-		if (status < 0)
-			goto error;
-		state->m_DrxkState = DRXK_DTV_STARTED;
-		break;
-	case OM_DVBT:
-		IFreqkHz = (IntermediateFrequency / 1000);
-		status = MPEGTSStop(state);
-		if (status < 0)
-			goto error;
-		status = SetDVBT(state, IFreqkHz, OffsetkHz);
-		if (status < 0)
-			goto error;
-		status = DVBTStart(state);
-		if (status < 0)
-			goto error;
-		state->m_DrxkState = DRXK_DTV_STARTED;
-		break;
-	default:
-		break;
-	}
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int ShutDown(struct drxk_state *state)
-{
-	dprintk(1, "\n");
-
-	MPEGTSStop(state);
-	return 0;
-}
-
-static int GetLockStatus(struct drxk_state *state, u32 *pLockStatus,
-			 u32 Time)
-{
-	int status = -EINVAL;
-
-	dprintk(1, "\n");
-
-	if (pLockStatus == NULL)
-		goto error;
-
-	*pLockStatus = NOT_LOCKED;
-
-	/* define the SCU command code */
-	switch (state->m_OperationMode) {
-	case OM_QAM_ITU_A:
-	case OM_QAM_ITU_B:
-	case OM_QAM_ITU_C:
-		status = GetQAMLockStatus(state, pLockStatus);
-		break;
-	case OM_DVBT:
-		status = GetDVBTLockStatus(state, pLockStatus);
-		break;
-	default:
-		break;
-	}
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int MPEGTSStart(struct drxk_state *state)
-{
-	int status;
-
-	u16 fecOcSncMode = 0;
-
-	/* Allow OC to sync again */
-	status = read16(state, FEC_OC_SNC_MODE__A, &fecOcSncMode);
-	if (status < 0)
-		goto error;
-	fecOcSncMode &= ~FEC_OC_SNC_MODE_SHUTDOWN__M;
-	status = write16(state, FEC_OC_SNC_MODE__A, fecOcSncMode);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_SNC_UNLOCK__A, 1);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int MPEGTSDtoInit(struct drxk_state *state)
-{
-	int status;
-
-	dprintk(1, "\n");
-
-	/* Rate integration settings */
-	status = write16(state, FEC_OC_RCN_CTL_STEP_LO__A, 0x0000);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_RCN_CTL_STEP_HI__A, 0x000C);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_RCN_GAIN__A, 0x000A);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_AVR_PARM_A__A, 0x0008);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_AVR_PARM_B__A, 0x0006);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_TMD_HI_MARGIN__A, 0x0680);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_TMD_LO_MARGIN__A, 0x0080);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_TMD_COUNT__A, 0x03F4);
-	if (status < 0)
-		goto error;
-
-	/* Additional configuration */
-	status = write16(state, FEC_OC_OCR_INVERT__A, 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_SNC_LWM__A, 2);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_SNC_HWM__A, 12);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-
-	return status;
-}
-
-static int MPEGTSDtoSetup(struct drxk_state *state,
-			  enum OperationMode oMode)
-{
-	int status;
-
-	u16 fecOcRegMode = 0;	/* FEC_OC_MODE       register value */
-	u16 fecOcRegIprMode = 0;	/* FEC_OC_IPR_MODE   register value */
-	u16 fecOcDtoMode = 0;	/* FEC_OC_IPR_INVERT register value */
-	u16 fecOcFctMode = 0;	/* FEC_OC_IPR_INVERT register value */
-	u16 fecOcDtoPeriod = 2;	/* FEC_OC_IPR_INVERT register value */
-	u16 fecOcDtoBurstLen = 188;	/* FEC_OC_IPR_INVERT register value */
-	u32 fecOcRcnCtlRate = 0;	/* FEC_OC_IPR_INVERT register value */
-	u16 fecOcTmdMode = 0;
-	u16 fecOcTmdIntUpdRate = 0;
-	u32 maxBitRate = 0;
-	bool staticCLK = false;
-
-	dprintk(1, "\n");
-
-	/* Check insertion of the Reed-Solomon parity bytes */
-	status = read16(state, FEC_OC_MODE__A, &fecOcRegMode);
-	if (status < 0)
-		goto error;
-	status = read16(state, FEC_OC_IPR_MODE__A, &fecOcRegIprMode);
-	if (status < 0)
-		goto error;
-	fecOcRegMode &= (~FEC_OC_MODE_PARITY__M);
-	fecOcRegIprMode &= (~FEC_OC_IPR_MODE_MVAL_DIS_PAR__M);
-	if (state->m_insertRSByte == true) {
-		/* enable parity symbol forward */
-		fecOcRegMode |= FEC_OC_MODE_PARITY__M;
-		/* MVAL disable during parity bytes */
-		fecOcRegIprMode |= FEC_OC_IPR_MODE_MVAL_DIS_PAR__M;
-		/* TS burst length to 204 */
-		fecOcDtoBurstLen = 204;
-	}
-
-	/* Check serial or parrallel output */
-	fecOcRegIprMode &= (~(FEC_OC_IPR_MODE_SERIAL__M));
-	if (state->m_enableParallel == false) {
-		/* MPEG data output is serial -> set ipr_mode[0] */
-		fecOcRegIprMode |= FEC_OC_IPR_MODE_SERIAL__M;
-	}
-
-	switch (oMode) {
-	case OM_DVBT:
-		maxBitRate = state->m_DVBTBitrate;
-		fecOcTmdMode = 3;
-		fecOcRcnCtlRate = 0xC00000;
-		staticCLK = state->m_DVBTStaticCLK;
-		break;
-	case OM_QAM_ITU_A:	/* fallthrough */
-	case OM_QAM_ITU_C:
-		fecOcTmdMode = 0x0004;
-		fecOcRcnCtlRate = 0xD2B4EE;	/* good for >63 Mb/s */
-		maxBitRate = state->m_DVBCBitrate;
-		staticCLK = state->m_DVBCStaticCLK;
-		break;
-	default:
-		status = -EINVAL;
-	}		/* switch (standard) */
-	if (status < 0)
-		goto error;
-
-	/* Configure DTO's */
-	if (staticCLK) {
-		u32 bitRate = 0;
-
-		/* Rational DTO for MCLK source (static MCLK rate),
-			Dynamic DTO for optimal grouping
-			(avoid intra-packet gaps),
-			DTO offset enable to sync TS burst with MSTRT */
-		fecOcDtoMode = (FEC_OC_DTO_MODE_DYNAMIC__M |
-				FEC_OC_DTO_MODE_OFFSET_ENABLE__M);
-		fecOcFctMode = (FEC_OC_FCT_MODE_RAT_ENA__M |
-				FEC_OC_FCT_MODE_VIRT_ENA__M);
-
-		/* Check user defined bitrate */
-		bitRate = maxBitRate;
-		if (bitRate > 75900000UL) {	/* max is 75.9 Mb/s */
-			bitRate = 75900000UL;
-		}
-		/* Rational DTO period:
-			dto_period = (Fsys / bitrate) - 2
-
-			Result should be floored,
-			to make sure >= requested bitrate
-			*/
-		fecOcDtoPeriod = (u16) (((state->m_sysClockFreq)
-						* 1000) / bitRate);
-		if (fecOcDtoPeriod <= 2)
-			fecOcDtoPeriod = 0;
-		else
-			fecOcDtoPeriod -= 2;
-		fecOcTmdIntUpdRate = 8;
-	} else {
-		/* (commonAttr->staticCLK == false) => dynamic mode */
-		fecOcDtoMode = FEC_OC_DTO_MODE_DYNAMIC__M;
-		fecOcFctMode = FEC_OC_FCT_MODE__PRE;
-		fecOcTmdIntUpdRate = 5;
-	}
-
-	/* Write appropriate registers with requested configuration */
-	status = write16(state, FEC_OC_DTO_BURST_LEN__A, fecOcDtoBurstLen);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_DTO_PERIOD__A, fecOcDtoPeriod);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_DTO_MODE__A, fecOcDtoMode);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_FCT_MODE__A, fecOcFctMode);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_MODE__A, fecOcRegMode);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_IPR_MODE__A, fecOcRegIprMode);
-	if (status < 0)
-		goto error;
-
-	/* Rate integration settings */
-	status = write32(state, FEC_OC_RCN_CTL_RATE_LO__A, fecOcRcnCtlRate);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_TMD_INT_UPD_RATE__A, fecOcTmdIntUpdRate);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_TMD_MODE__A, fecOcTmdMode);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int MPEGTSConfigurePolarity(struct drxk_state *state)
-{
-	u16 fecOcRegIprInvert = 0;
-
-	/* Data mask for the output data byte */
-	u16 InvertDataMask =
-	    FEC_OC_IPR_INVERT_MD7__M | FEC_OC_IPR_INVERT_MD6__M |
-	    FEC_OC_IPR_INVERT_MD5__M | FEC_OC_IPR_INVERT_MD4__M |
-	    FEC_OC_IPR_INVERT_MD3__M | FEC_OC_IPR_INVERT_MD2__M |
-	    FEC_OC_IPR_INVERT_MD1__M | FEC_OC_IPR_INVERT_MD0__M;
-
-	dprintk(1, "\n");
-
-	/* Control selective inversion of output bits */
-	fecOcRegIprInvert &= (~(InvertDataMask));
-	if (state->m_invertDATA == true)
-		fecOcRegIprInvert |= InvertDataMask;
-	fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MERR__M));
-	if (state->m_invertERR == true)
-		fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MERR__M;
-	fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MSTRT__M));
-	if (state->m_invertSTR == true)
-		fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MSTRT__M;
-	fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MVAL__M));
-	if (state->m_invertVAL == true)
-		fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MVAL__M;
-	fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MCLK__M));
-	if (state->m_invertCLK == true)
-		fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MCLK__M;
-
-	return write16(state, FEC_OC_IPR_INVERT__A, fecOcRegIprInvert);
-}
-
-#define   SCU_RAM_AGC_KI_INV_RF_POL__M 0x4000
-
-static int SetAgcRf(struct drxk_state *state,
-		    struct SCfgAgc *pAgcCfg, bool isDTV)
-{
-	int status = -EINVAL;
-	u16 data = 0;
-	struct SCfgAgc *pIfAgcSettings;
-
-	dprintk(1, "\n");
-
-	if (pAgcCfg == NULL)
-		goto error;
-
-	switch (pAgcCfg->ctrlMode) {
-	case DRXK_AGC_CTRL_AUTO:
-		/* Enable RF AGC DAC */
-		status = read16(state, IQM_AF_STDBY__A, &data);
-		if (status < 0)
-			goto error;
-		data &= ~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY;
-		status = write16(state, IQM_AF_STDBY__A, data);
-		if (status < 0)
-			goto error;
-		status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
-		if (status < 0)
-			goto error;
-
-		/* Enable SCU RF AGC loop */
-		data &= ~SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
-
-		/* Polarity */
-		if (state->m_RfAgcPol)
-			data |= SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
-		else
-			data &= ~SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
-		status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
-		if (status < 0)
-			goto error;
-
-		/* Set speed (using complementary reduction value) */
-		status = read16(state, SCU_RAM_AGC_KI_RED__A, &data);
-		if (status < 0)
-			goto error;
-
-		data &= ~SCU_RAM_AGC_KI_RED_RAGC_RED__M;
-		data |= (~(pAgcCfg->speed <<
-				SCU_RAM_AGC_KI_RED_RAGC_RED__B)
-				& SCU_RAM_AGC_KI_RED_RAGC_RED__M);
-
-		status = write16(state, SCU_RAM_AGC_KI_RED__A, data);
-		if (status < 0)
-			goto error;
-
-		if (IsDVBT(state))
-			pIfAgcSettings = &state->m_dvbtIfAgcCfg;
-		else if (IsQAM(state))
-			pIfAgcSettings = &state->m_qamIfAgcCfg;
-		else
-			pIfAgcSettings = &state->m_atvIfAgcCfg;
-		if (pIfAgcSettings == NULL) {
-			status = -EINVAL;
-			goto error;
-		}
-
-		/* Set TOP, only if IF-AGC is in AUTO mode */
-		if (pIfAgcSettings->ctrlMode == DRXK_AGC_CTRL_AUTO)
-			status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pAgcCfg->top);
-			if (status < 0)
-				goto error;
-
-		/* Cut-Off current */
-		status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, pAgcCfg->cutOffCurrent);
-		if (status < 0)
-			goto error;
-
-		/* Max. output level */
-		status = write16(state, SCU_RAM_AGC_RF_MAX__A, pAgcCfg->maxOutputLevel);
-		if (status < 0)
-			goto error;
-
-		break;
-
-	case DRXK_AGC_CTRL_USER:
-		/* Enable RF AGC DAC */
-		status = read16(state, IQM_AF_STDBY__A, &data);
-		if (status < 0)
-			goto error;
-		data &= ~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY;
-		status = write16(state, IQM_AF_STDBY__A, data);
-		if (status < 0)
-			goto error;
-
-		/* Disable SCU RF AGC loop */
-		status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
-		if (status < 0)
-			goto error;
-		data |= SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
-		if (state->m_RfAgcPol)
-			data |= SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
-		else
-			data &= ~SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
-		status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
-		if (status < 0)
-			goto error;
-
-		/* SCU c.o.c. to 0, enabling full control range */
-		status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, 0);
-		if (status < 0)
-			goto error;
-
-		/* Write value to output pin */
-		status = write16(state, SCU_RAM_AGC_RF_IACCU_HI__A, pAgcCfg->outputLevel);
-		if (status < 0)
-			goto error;
-		break;
-
-	case DRXK_AGC_CTRL_OFF:
-		/* Disable RF AGC DAC */
-		status = read16(state, IQM_AF_STDBY__A, &data);
-		if (status < 0)
-			goto error;
-		data |= IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY;
-		status = write16(state, IQM_AF_STDBY__A, data);
-		if (status < 0)
-			goto error;
-
-		/* Disable SCU RF AGC loop */
-		status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
-		if (status < 0)
-			goto error;
-		data |= SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
-		status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
-		if (status < 0)
-			goto error;
-		break;
-
-	default:
-		status = -EINVAL;
-
-	}
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-#define SCU_RAM_AGC_KI_INV_IF_POL__M 0x2000
-
-static int SetAgcIf(struct drxk_state *state,
-		    struct SCfgAgc *pAgcCfg, bool isDTV)
-{
-	u16 data = 0;
-	int status = 0;
-	struct SCfgAgc *pRfAgcSettings;
-
-	dprintk(1, "\n");
-
-	switch (pAgcCfg->ctrlMode) {
-	case DRXK_AGC_CTRL_AUTO:
-
-		/* Enable IF AGC DAC */
-		status = read16(state, IQM_AF_STDBY__A, &data);
-		if (status < 0)
-			goto error;
-		data &= ~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY;
-		status = write16(state, IQM_AF_STDBY__A, data);
-		if (status < 0)
-			goto error;
-
-		status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
-		if (status < 0)
-			goto error;
-
-		/* Enable SCU IF AGC loop */
-		data &= ~SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;
-
-		/* Polarity */
-		if (state->m_IfAgcPol)
-			data |= SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
-		else
-			data &= ~SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
-		status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
-		if (status < 0)
-			goto error;
-
-		/* Set speed (using complementary reduction value) */
-		status = read16(state, SCU_RAM_AGC_KI_RED__A, &data);
-		if (status < 0)
-			goto error;
-		data &= ~SCU_RAM_AGC_KI_RED_IAGC_RED__M;
-		data |= (~(pAgcCfg->speed <<
-				SCU_RAM_AGC_KI_RED_IAGC_RED__B)
-				& SCU_RAM_AGC_KI_RED_IAGC_RED__M);
-
-		status = write16(state, SCU_RAM_AGC_KI_RED__A, data);
-		if (status < 0)
-			goto error;
-
-		if (IsQAM(state))
-			pRfAgcSettings = &state->m_qamRfAgcCfg;
-		else
-			pRfAgcSettings = &state->m_atvRfAgcCfg;
-		if (pRfAgcSettings == NULL)
-			return -1;
-		/* Restore TOP */
-		status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pRfAgcSettings->top);
-		if (status < 0)
-			goto error;
-		break;
-
-	case DRXK_AGC_CTRL_USER:
-
-		/* Enable IF AGC DAC */
-		status = read16(state, IQM_AF_STDBY__A, &data);
-		if (status < 0)
-			goto error;
-		data &= ~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY;
-		status = write16(state, IQM_AF_STDBY__A, data);
-		if (status < 0)
-			goto error;
-
-		status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
-		if (status < 0)
-			goto error;
-
-		/* Disable SCU IF AGC loop */
-		data |= SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;
-
-		/* Polarity */
-		if (state->m_IfAgcPol)
-			data |= SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
-		else
-			data &= ~SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
-		status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
-		if (status < 0)
-			goto error;
-
-		/* Write value to output pin */
-		status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pAgcCfg->outputLevel);
-		if (status < 0)
-			goto error;
-		break;
-
-	case DRXK_AGC_CTRL_OFF:
-
-		/* Disable If AGC DAC */
-		status = read16(state, IQM_AF_STDBY__A, &data);
-		if (status < 0)
-			goto error;
-		data |= IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY;
-		status = write16(state, IQM_AF_STDBY__A, data);
-		if (status < 0)
-			goto error;
-
-		/* Disable SCU IF AGC loop */
-		status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
-		if (status < 0)
-			goto error;
-		data |= SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;
-		status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
-		if (status < 0)
-			goto error;
-		break;
-	}		/* switch (agcSettingsIf->ctrlMode) */
-
-	/* always set the top to support
-		configurations without if-loop */
-	status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, pAgcCfg->top);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int ReadIFAgc(struct drxk_state *state, u32 *pValue)
-{
-	u16 agcDacLvl;
-	int status;
-	u16 Level = 0;
-
-	dprintk(1, "\n");
-
-	status = read16(state, IQM_AF_AGC_IF__A, &agcDacLvl);
-	if (status < 0) {
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-		return status;
-	}
-
-	*pValue = 0;
-
-	if (agcDacLvl > DRXK_AGC_DAC_OFFSET)
-		Level = agcDacLvl - DRXK_AGC_DAC_OFFSET;
-	if (Level < 14000)
-		*pValue = (14000 - Level) / 4;
-	else
-		*pValue = 0;
-
-	return status;
-}
-
-static int GetQAMSignalToNoise(struct drxk_state *state,
-			       s32 *pSignalToNoise)
-{
-	int status = 0;
-	u16 qamSlErrPower = 0;	/* accum. error between
-					raw and sliced symbols */
-	u32 qamSlSigPower = 0;	/* used for MER, depends of
-					QAM modulation */
-	u32 qamSlMer = 0;	/* QAM MER */
-
-	dprintk(1, "\n");
-
-	/* MER calculation */
-
-	/* get the register value needed for MER */
-	status = read16(state, QAM_SL_ERR_POWER__A, &qamSlErrPower);
-	if (status < 0) {
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-		return -EINVAL;
-	}
-
-	switch (state->props.modulation) {
-	case QAM_16:
-		qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM16 << 2;
-		break;
-	case QAM_32:
-		qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM32 << 2;
-		break;
-	case QAM_64:
-		qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM64 << 2;
-		break;
-	case QAM_128:
-		qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM128 << 2;
-		break;
-	default:
-	case QAM_256:
-		qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM256 << 2;
-		break;
-	}
-
-	if (qamSlErrPower > 0) {
-		qamSlMer = Log10Times100(qamSlSigPower) -
-			Log10Times100((u32) qamSlErrPower);
-	}
-	*pSignalToNoise = qamSlMer;
-
-	return status;
-}
-
-static int GetDVBTSignalToNoise(struct drxk_state *state,
-				s32 *pSignalToNoise)
-{
-	int status;
-	u16 regData = 0;
-	u32 EqRegTdSqrErrI = 0;
-	u32 EqRegTdSqrErrQ = 0;
-	u16 EqRegTdSqrErrExp = 0;
-	u16 EqRegTdTpsPwrOfs = 0;
-	u16 EqRegTdReqSmbCnt = 0;
-	u32 tpsCnt = 0;
-	u32 SqrErrIQ = 0;
-	u32 a = 0;
-	u32 b = 0;
-	u32 c = 0;
-	u32 iMER = 0;
-	u16 transmissionParams = 0;
-
-	dprintk(1, "\n");
-
-	status = read16(state, OFDM_EQ_TOP_TD_TPS_PWR_OFS__A, &EqRegTdTpsPwrOfs);
-	if (status < 0)
-		goto error;
-	status = read16(state, OFDM_EQ_TOP_TD_REQ_SMB_CNT__A, &EqRegTdReqSmbCnt);
-	if (status < 0)
-		goto error;
-	status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_EXP__A, &EqRegTdSqrErrExp);
-	if (status < 0)
-		goto error;
-	status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_I__A, &regData);
-	if (status < 0)
-		goto error;
-	/* Extend SQR_ERR_I operational range */
-	EqRegTdSqrErrI = (u32) regData;
-	if ((EqRegTdSqrErrExp > 11) &&
-		(EqRegTdSqrErrI < 0x00000FFFUL)) {
-		EqRegTdSqrErrI += 0x00010000UL;
-	}
-	status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_Q__A, &regData);
-	if (status < 0)
-		goto error;
-	/* Extend SQR_ERR_Q operational range */
-	EqRegTdSqrErrQ = (u32) regData;
-	if ((EqRegTdSqrErrExp > 11) &&
-		(EqRegTdSqrErrQ < 0x00000FFFUL))
-		EqRegTdSqrErrQ += 0x00010000UL;
-
-	status = read16(state, OFDM_SC_RA_RAM_OP_PARAM__A, &transmissionParams);
-	if (status < 0)
-		goto error;
-
-	/* Check input data for MER */
-
-	/* MER calculation (in 0.1 dB) without math.h */
-	if ((EqRegTdTpsPwrOfs == 0) || (EqRegTdReqSmbCnt == 0))
-		iMER = 0;
-	else if ((EqRegTdSqrErrI + EqRegTdSqrErrQ) == 0) {
-		/* No error at all, this must be the HW reset value
-			* Apparently no first measurement yet
-			* Set MER to 0.0 */
-		iMER = 0;
-	} else {
-		SqrErrIQ = (EqRegTdSqrErrI + EqRegTdSqrErrQ) <<
-			EqRegTdSqrErrExp;
-		if ((transmissionParams &
-			OFDM_SC_RA_RAM_OP_PARAM_MODE__M)
-			== OFDM_SC_RA_RAM_OP_PARAM_MODE_2K)
-			tpsCnt = 17;
-		else
-			tpsCnt = 68;
-
-		/* IMER = 100 * log10 (x)
-			where x = (EqRegTdTpsPwrOfs^2 *
-			EqRegTdReqSmbCnt * tpsCnt)/SqrErrIQ
-
-			=> IMER = a + b -c
-			where a = 100 * log10 (EqRegTdTpsPwrOfs^2)
-			b = 100 * log10 (EqRegTdReqSmbCnt * tpsCnt)
-			c = 100 * log10 (SqrErrIQ)
-			*/
-
-		/* log(x) x = 9bits * 9bits->18 bits  */
-		a = Log10Times100(EqRegTdTpsPwrOfs *
-					EqRegTdTpsPwrOfs);
-		/* log(x) x = 16bits * 7bits->23 bits  */
-		b = Log10Times100(EqRegTdReqSmbCnt * tpsCnt);
-		/* log(x) x = (16bits + 16bits) << 15 ->32 bits  */
-		c = Log10Times100(SqrErrIQ);
-
-		iMER = a + b;
-		/* No negative MER, clip to zero */
-		if (iMER > c)
-			iMER -= c;
-		else
-			iMER = 0;
-	}
-	*pSignalToNoise = iMER;
-
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int GetSignalToNoise(struct drxk_state *state, s32 *pSignalToNoise)
-{
-	dprintk(1, "\n");
-
-	*pSignalToNoise = 0;
-	switch (state->m_OperationMode) {
-	case OM_DVBT:
-		return GetDVBTSignalToNoise(state, pSignalToNoise);
-	case OM_QAM_ITU_A:
-	case OM_QAM_ITU_C:
-		return GetQAMSignalToNoise(state, pSignalToNoise);
-	default:
-		break;
-	}
-	return 0;
-}
-
-#if 0
-static int GetDVBTQuality(struct drxk_state *state, s32 *pQuality)
-{
-	/* SNR Values for quasi errorfree reception rom Nordig 2.2 */
-	int status = 0;
-
-	dprintk(1, "\n");
-
-	static s32 QE_SN[] = {
-		51,		/* QPSK 1/2 */
-		69,		/* QPSK 2/3 */
-		79,		/* QPSK 3/4 */
-		89,		/* QPSK 5/6 */
-		97,		/* QPSK 7/8 */
-		108,		/* 16-QAM 1/2 */
-		131,		/* 16-QAM 2/3 */
-		146,		/* 16-QAM 3/4 */
-		156,		/* 16-QAM 5/6 */
-		160,		/* 16-QAM 7/8 */
-		165,		/* 64-QAM 1/2 */
-		187,		/* 64-QAM 2/3 */
-		202,		/* 64-QAM 3/4 */
-		216,		/* 64-QAM 5/6 */
-		225,		/* 64-QAM 7/8 */
-	};
-
-	*pQuality = 0;
-
-	do {
-		s32 SignalToNoise = 0;
-		u16 Constellation = 0;
-		u16 CodeRate = 0;
-		u32 SignalToNoiseRel;
-		u32 BERQuality;
-
-		status = GetDVBTSignalToNoise(state, &SignalToNoise);
-		if (status < 0)
-			break;
-		status = read16(state, OFDM_EQ_TOP_TD_TPS_CONST__A, &Constellation);
-		if (status < 0)
-			break;
-		Constellation &= OFDM_EQ_TOP_TD_TPS_CONST__M;
-
-		status = read16(state, OFDM_EQ_TOP_TD_TPS_CODE_HP__A, &CodeRate);
-		if (status < 0)
-			break;
-		CodeRate &= OFDM_EQ_TOP_TD_TPS_CODE_HP__M;
-
-		if (Constellation > OFDM_EQ_TOP_TD_TPS_CONST_64QAM ||
-		    CodeRate > OFDM_EQ_TOP_TD_TPS_CODE_LP_7_8)
-			break;
-		SignalToNoiseRel = SignalToNoise -
-		    QE_SN[Constellation * 5 + CodeRate];
-		BERQuality = 100;
-
-		if (SignalToNoiseRel < -70)
-			*pQuality = 0;
-		else if (SignalToNoiseRel < 30)
-			*pQuality = ((SignalToNoiseRel + 70) *
-				     BERQuality) / 100;
-		else
-			*pQuality = BERQuality;
-	} while (0);
-	return 0;
-};
-
-static int GetDVBCQuality(struct drxk_state *state, s32 *pQuality)
-{
-	int status = 0;
-	*pQuality = 0;
-
-	dprintk(1, "\n");
-
-	do {
-		u32 SignalToNoise = 0;
-		u32 BERQuality = 100;
-		u32 SignalToNoiseRel = 0;
-
-		status = GetQAMSignalToNoise(state, &SignalToNoise);
-		if (status < 0)
-			break;
-
-		switch (state->props.modulation) {
-		case QAM_16:
-			SignalToNoiseRel = SignalToNoise - 200;
-			break;
-		case QAM_32:
-			SignalToNoiseRel = SignalToNoise - 230;
-			break;	/* Not in NorDig */
-		case QAM_64:
-			SignalToNoiseRel = SignalToNoise - 260;
-			break;
-		case QAM_128:
-			SignalToNoiseRel = SignalToNoise - 290;
-			break;
-		default:
-		case QAM_256:
-			SignalToNoiseRel = SignalToNoise - 320;
-			break;
-		}
-
-		if (SignalToNoiseRel < -70)
-			*pQuality = 0;
-		else if (SignalToNoiseRel < 30)
-			*pQuality = ((SignalToNoiseRel + 70) *
-				     BERQuality) / 100;
-		else
-			*pQuality = BERQuality;
-	} while (0);
-
-	return status;
-}
-
-static int GetQuality(struct drxk_state *state, s32 *pQuality)
-{
-	dprintk(1, "\n");
-
-	switch (state->m_OperationMode) {
-	case OM_DVBT:
-		return GetDVBTQuality(state, pQuality);
-	case OM_QAM_ITU_A:
-		return GetDVBCQuality(state, pQuality);
-	default:
-		break;
-	}
-
-	return 0;
-}
-#endif
-
-/* Free data ram in SIO HI */
-#define SIO_HI_RA_RAM_USR_BEGIN__A 0x420040
-#define SIO_HI_RA_RAM_USR_END__A   0x420060
-
-#define DRXK_HI_ATOMIC_BUF_START (SIO_HI_RA_RAM_USR_BEGIN__A)
-#define DRXK_HI_ATOMIC_BUF_END   (SIO_HI_RA_RAM_USR_BEGIN__A + 7)
-#define DRXK_HI_ATOMIC_READ      SIO_HI_RA_RAM_PAR_3_ACP_RW_READ
-#define DRXK_HI_ATOMIC_WRITE     SIO_HI_RA_RAM_PAR_3_ACP_RW_WRITE
-
-#define DRXDAP_FASI_ADDR2BLOCK(addr)  (((addr) >> 22) & 0x3F)
-#define DRXDAP_FASI_ADDR2BANK(addr)   (((addr) >> 16) & 0x3F)
-#define DRXDAP_FASI_ADDR2OFFSET(addr) ((addr) & 0x7FFF)
-
-static int ConfigureI2CBridge(struct drxk_state *state, bool bEnableBridge)
-{
-	int status = -EINVAL;
-
-	dprintk(1, "\n");
-
-	if (state->m_DrxkState == DRXK_UNINITIALIZED)
-		return 0;
-	if (state->m_DrxkState == DRXK_POWERED_DOWN)
-		goto error;
-
-	if (state->no_i2c_bridge)
-		return 0;
-
-	status = write16(state, SIO_HI_RA_RAM_PAR_1__A, SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
-	if (status < 0)
-		goto error;
-	if (bEnableBridge) {
-		status = write16(state, SIO_HI_RA_RAM_PAR_2__A, SIO_HI_RA_RAM_PAR_2_BRD_CFG_CLOSED);
-		if (status < 0)
-			goto error;
-	} else {
-		status = write16(state, SIO_HI_RA_RAM_PAR_2__A, SIO_HI_RA_RAM_PAR_2_BRD_CFG_OPEN);
-		if (status < 0)
-			goto error;
-	}
-
-	status = HI_Command(state, SIO_HI_RA_RAM_CMD_BRDCTRL, 0);
-
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int SetPreSaw(struct drxk_state *state,
-		     struct SCfgPreSaw *pPreSawCfg)
-{
-	int status = -EINVAL;
-
-	dprintk(1, "\n");
-
-	if ((pPreSawCfg == NULL)
-	    || (pPreSawCfg->reference > IQM_AF_PDREF__M))
-		goto error;
-
-	status = write16(state, IQM_AF_PDREF__A, pPreSawCfg->reference);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int BLDirectCmd(struct drxk_state *state, u32 targetAddr,
-		       u16 romOffset, u16 nrOfElements, u32 timeOut)
-{
-	u16 blStatus = 0;
-	u16 offset = (u16) ((targetAddr >> 0) & 0x00FFFF);
-	u16 blockbank = (u16) ((targetAddr >> 16) & 0x000FFF);
-	int status;
-	unsigned long end;
-
-	dprintk(1, "\n");
-
-	mutex_lock(&state->mutex);
-	status = write16(state, SIO_BL_MODE__A, SIO_BL_MODE_DIRECT);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_BL_TGT_HDR__A, blockbank);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_BL_TGT_ADDR__A, offset);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_BL_SRC_ADDR__A, romOffset);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_BL_SRC_LEN__A, nrOfElements);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_BL_ENABLE__A, SIO_BL_ENABLE_ON);
-	if (status < 0)
-		goto error;
-
-	end = jiffies + msecs_to_jiffies(timeOut);
-	do {
-		status = read16(state, SIO_BL_STATUS__A, &blStatus);
-		if (status < 0)
-			goto error;
-	} while ((blStatus == 0x1) && time_is_after_jiffies(end));
-	if (blStatus == 0x1) {
-		printk(KERN_ERR "drxk: SIO not ready\n");
-		status = -EINVAL;
-		goto error2;
-	}
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-error2:
-	mutex_unlock(&state->mutex);
-	return status;
-
-}
-
-static int ADCSyncMeasurement(struct drxk_state *state, u16 *count)
-{
-	u16 data = 0;
-	int status;
-
-	dprintk(1, "\n");
-
-	/* Start measurement */
-	status = write16(state, IQM_AF_COMM_EXEC__A, IQM_AF_COMM_EXEC_ACTIVE);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_AF_START_LOCK__A, 1);
-	if (status < 0)
-		goto error;
-
-	*count = 0;
-	status = read16(state, IQM_AF_PHASE0__A, &data);
-	if (status < 0)
-		goto error;
-	if (data == 127)
-		*count = *count + 1;
-	status = read16(state, IQM_AF_PHASE1__A, &data);
-	if (status < 0)
-		goto error;
-	if (data == 127)
-		*count = *count + 1;
-	status = read16(state, IQM_AF_PHASE2__A, &data);
-	if (status < 0)
-		goto error;
-	if (data == 127)
-		*count = *count + 1;
-
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int ADCSynchronization(struct drxk_state *state)
-{
-	u16 count = 0;
-	int status;
-
-	dprintk(1, "\n");
-
-	status = ADCSyncMeasurement(state, &count);
-	if (status < 0)
-		goto error;
-
-	if (count == 1) {
-		/* Try sampling on a diffrent edge */
-		u16 clkNeg = 0;
-
-		status = read16(state, IQM_AF_CLKNEG__A, &clkNeg);
-		if (status < 0)
-			goto error;
-		if ((clkNeg & IQM_AF_CLKNEG_CLKNEGDATA__M) ==
-			IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS) {
-			clkNeg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
-			clkNeg |=
-				IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_NEG;
-		} else {
-			clkNeg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
-			clkNeg |=
-				IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS;
-		}
-		status = write16(state, IQM_AF_CLKNEG__A, clkNeg);
-		if (status < 0)
-			goto error;
-		status = ADCSyncMeasurement(state, &count);
-		if (status < 0)
-			goto error;
-	}
-
-	if (count < 2)
-		status = -EINVAL;
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int SetFrequencyShifter(struct drxk_state *state,
-			       u16 intermediateFreqkHz,
-			       s32 tunerFreqOffset, bool isDTV)
-{
-	bool selectPosImage = false;
-	u32 rfFreqResidual = tunerFreqOffset;
-	u32 fmFrequencyShift = 0;
-	bool tunerMirror = !state->m_bMirrorFreqSpect;
-	u32 adcFreq;
-	bool adcFlip;
-	int status;
-	u32 ifFreqActual;
-	u32 samplingFrequency = (u32) (state->m_sysClockFreq / 3);
-	u32 frequencyShift;
-	bool imageToSelect;
-
-	dprintk(1, "\n");
-
-	/*
-	   Program frequency shifter
-	   No need to account for mirroring on RF
-	 */
-	if (isDTV) {
-		if ((state->m_OperationMode == OM_QAM_ITU_A) ||
-		    (state->m_OperationMode == OM_QAM_ITU_C) ||
-		    (state->m_OperationMode == OM_DVBT))
-			selectPosImage = true;
-		else
-			selectPosImage = false;
-	}
-	if (tunerMirror)
-		/* tuner doesn't mirror */
-		ifFreqActual = intermediateFreqkHz +
-		    rfFreqResidual + fmFrequencyShift;
-	else
-		/* tuner mirrors */
-		ifFreqActual = intermediateFreqkHz -
-		    rfFreqResidual - fmFrequencyShift;
-	if (ifFreqActual > samplingFrequency / 2) {
-		/* adc mirrors */
-		adcFreq = samplingFrequency - ifFreqActual;
-		adcFlip = true;
-	} else {
-		/* adc doesn't mirror */
-		adcFreq = ifFreqActual;
-		adcFlip = false;
-	}
-
-	frequencyShift = adcFreq;
-	imageToSelect = state->m_rfmirror ^ tunerMirror ^
-	    adcFlip ^ selectPosImage;
-	state->m_IqmFsRateOfs =
-	    Frac28a((frequencyShift), samplingFrequency);
-
-	if (imageToSelect)
-		state->m_IqmFsRateOfs = ~state->m_IqmFsRateOfs + 1;
-
-	/* Program frequency shifter with tuner offset compensation */
-	/* frequencyShift += tunerFreqOffset; TODO */
-	status = write32(state, IQM_FS_RATE_OFS_LO__A,
-			 state->m_IqmFsRateOfs);
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int InitAGC(struct drxk_state *state, bool isDTV)
-{
-	u16 ingainTgt = 0;
-	u16 ingainTgtMin = 0;
-	u16 ingainTgtMax = 0;
-	u16 clpCyclen = 0;
-	u16 clpSumMin = 0;
-	u16 clpDirTo = 0;
-	u16 snsSumMin = 0;
-	u16 snsSumMax = 0;
-	u16 clpSumMax = 0;
-	u16 snsDirTo = 0;
-	u16 kiInnergainMin = 0;
-	u16 ifIaccuHiTgt = 0;
-	u16 ifIaccuHiTgtMin = 0;
-	u16 ifIaccuHiTgtMax = 0;
-	u16 data = 0;
-	u16 fastClpCtrlDelay = 0;
-	u16 clpCtrlMode = 0;
-	int status = 0;
-
-	dprintk(1, "\n");
-
-	/* Common settings */
-	snsSumMax = 1023;
-	ifIaccuHiTgtMin = 2047;
-	clpCyclen = 500;
-	clpSumMax = 1023;
-
-	/* AGCInit() not available for DVBT; init done in microcode */
-	if (!IsQAM(state)) {
-		printk(KERN_ERR "drxk: %s: mode %d is not DVB-C\n", __func__, state->m_OperationMode);
-		return -EINVAL;
-	}
-
-	/* FIXME: Analog TV AGC require different settings */
-
-	/* Standard specific settings */
-	clpSumMin = 8;
-	clpDirTo = (u16) -9;
-	clpCtrlMode = 0;
-	snsSumMin = 8;
-	snsDirTo = (u16) -9;
-	kiInnergainMin = (u16) -1030;
-	ifIaccuHiTgtMax = 0x2380;
-	ifIaccuHiTgt = 0x2380;
-	ingainTgtMin = 0x0511;
-	ingainTgt = 0x0511;
-	ingainTgtMax = 5119;
-	fastClpCtrlDelay = state->m_qamIfAgcCfg.FastClipCtrlDelay;
-
-	status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A, fastClpCtrlDelay);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, SCU_RAM_AGC_CLP_CTRL_MODE__A, clpCtrlMode);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_INGAIN_TGT__A, ingainTgt);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, ingainTgtMin);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A, ingainTgtMax);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__A, ifIaccuHiTgtMin);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, ifIaccuHiTgtMax);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_IF_IACCU_HI__A, 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_IF_IACCU_LO__A, 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_RF_IACCU_HI__A, 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_RF_IACCU_LO__A, 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_CLP_SUM_MAX__A, clpSumMax);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_SNS_SUM_MAX__A, snsSumMax);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, SCU_RAM_AGC_KI_INNERGAIN_MIN__A, kiInnergainMin);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT__A, ifIaccuHiTgt);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_CLP_CYCLEN__A, clpCyclen);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, SCU_RAM_AGC_RF_SNS_DEV_MAX__A, 1023);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_RF_SNS_DEV_MIN__A, (u16) -1023);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_FAST_SNS_CTRL_DELAY__A, 50);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, SCU_RAM_AGC_KI_MAXMINGAIN_TH__A, 20);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_CLP_SUM_MIN__A, clpSumMin);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_SNS_SUM_MIN__A, snsSumMin);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_CLP_DIR_TO__A, clpDirTo);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_SNS_DIR_TO__A, snsDirTo);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_KI_MINGAIN__A, 0x7fff);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_KI_MAXGAIN__A, 0x0);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_KI_MIN__A, 0x0117);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_KI_MAX__A, 0x0657);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_CLP_SUM__A, 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_CLP_CYCCNT__A, 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_CLP_DIR_WD__A, 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_CLP_DIR_STP__A, 1);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_SNS_SUM__A, 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_SNS_CYCCNT__A, 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_SNS_DIR_WD__A, 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_SNS_DIR_STP__A, 1);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_SNS_CYCLEN__A, 500);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_KI_CYCLEN__A, 500);
-	if (status < 0)
-		goto error;
-
-	/* Initialize inner-loop KI gain factors */
-	status = read16(state, SCU_RAM_AGC_KI__A, &data);
-	if (status < 0)
-		goto error;
-
-	data = 0x0657;
-	data &= ~SCU_RAM_AGC_KI_RF__M;
-	data |= (DRXK_KI_RAGC_QAM << SCU_RAM_AGC_KI_RF__B);
-	data &= ~SCU_RAM_AGC_KI_IF__M;
-	data |= (DRXK_KI_IAGC_QAM << SCU_RAM_AGC_KI_IF__B);
-
-	status = write16(state, SCU_RAM_AGC_KI__A, data);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int DVBTQAMGetAccPktErr(struct drxk_state *state, u16 *packetErr)
-{
-	int status;
-
-	dprintk(1, "\n");
-	if (packetErr == NULL)
-		status = write16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, 0);
-	else
-		status = read16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, packetErr);
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int DVBTScCommand(struct drxk_state *state,
-			 u16 cmd, u16 subcmd,
-			 u16 param0, u16 param1, u16 param2,
-			 u16 param3, u16 param4)
-{
-	u16 curCmd = 0;
-	u16 errCode = 0;
-	u16 retryCnt = 0;
-	u16 scExec = 0;
-	int status;
-
-	dprintk(1, "\n");
-	status = read16(state, OFDM_SC_COMM_EXEC__A, &scExec);
-	if (scExec != 1) {
-		/* SC is not running */
-		status = -EINVAL;
-	}
-	if (status < 0)
-		goto error;
-
-	/* Wait until sc is ready to receive command */
-	retryCnt = 0;
-	do {
-		msleep(1);
-		status = read16(state, OFDM_SC_RA_RAM_CMD__A, &curCmd);
-		retryCnt++;
-	} while ((curCmd != 0) && (retryCnt < DRXK_MAX_RETRIES));
-	if (retryCnt >= DRXK_MAX_RETRIES && (status < 0))
-		goto error;
-
-	/* Write sub-command */
-	switch (cmd) {
-		/* All commands using sub-cmd */
-	case OFDM_SC_RA_RAM_CMD_PROC_START:
-	case OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM:
-	case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM:
-		status = write16(state, OFDM_SC_RA_RAM_CMD_ADDR__A, subcmd);
-		if (status < 0)
-			goto error;
-		break;
-	default:
-		/* Do nothing */
-		break;
-	}
-
-	/* Write needed parameters and the command */
-	switch (cmd) {
-		/* All commands using 5 parameters */
-		/* All commands using 4 parameters */
-		/* All commands using 3 parameters */
-		/* All commands using 2 parameters */
-	case OFDM_SC_RA_RAM_CMD_PROC_START:
-	case OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM:
-	case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM:
-		status = write16(state, OFDM_SC_RA_RAM_PARAM1__A, param1);
-		/* All commands using 1 parameters */
-	case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING:
-	case OFDM_SC_RA_RAM_CMD_USER_IO:
-		status = write16(state, OFDM_SC_RA_RAM_PARAM0__A, param0);
-		/* All commands using 0 parameters */
-	case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM:
-	case OFDM_SC_RA_RAM_CMD_NULL:
-		/* Write command */
-		status = write16(state, OFDM_SC_RA_RAM_CMD__A, cmd);
-		break;
-	default:
-		/* Unknown command */
-		status = -EINVAL;
-	}
-	if (status < 0)
-		goto error;
-
-	/* Wait until sc is ready processing command */
-	retryCnt = 0;
-	do {
-		msleep(1);
-		status = read16(state, OFDM_SC_RA_RAM_CMD__A, &curCmd);
-		retryCnt++;
-	} while ((curCmd != 0) && (retryCnt < DRXK_MAX_RETRIES));
-	if (retryCnt >= DRXK_MAX_RETRIES && (status < 0))
-		goto error;
-
-	/* Check for illegal cmd */
-	status = read16(state, OFDM_SC_RA_RAM_CMD_ADDR__A, &errCode);
-	if (errCode == 0xFFFF) {
-		/* illegal command */
-		status = -EINVAL;
-	}
-	if (status < 0)
-		goto error;
-
-	/* Retreive results parameters from SC */
-	switch (cmd) {
-		/* All commands yielding 5 results */
-		/* All commands yielding 4 results */
-		/* All commands yielding 3 results */
-		/* All commands yielding 2 results */
-		/* All commands yielding 1 result */
-	case OFDM_SC_RA_RAM_CMD_USER_IO:
-	case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM:
-		status = read16(state, OFDM_SC_RA_RAM_PARAM0__A, &(param0));
-		/* All commands yielding 0 results */
-	case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING:
-	case OFDM_SC_RA_RAM_CMD_SET_TIMER:
-	case OFDM_SC_RA_RAM_CMD_PROC_START:
-	case OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM:
-	case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM:
-	case OFDM_SC_RA_RAM_CMD_NULL:
-		break;
-	default:
-		/* Unknown command */
-		status = -EINVAL;
-		break;
-	}			/* switch (cmd->cmd) */
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int PowerUpDVBT(struct drxk_state *state)
-{
-	enum DRXPowerMode powerMode = DRX_POWER_UP;
-	int status;
-
-	dprintk(1, "\n");
-	status = CtrlPowerMode(state, &powerMode);
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int DVBTCtrlSetIncEnable(struct drxk_state *state, bool *enabled)
-{
-	int status;
-
-	dprintk(1, "\n");
-	if (*enabled == true)
-		status = write16(state, IQM_CF_BYPASSDET__A, 0);
-	else
-		status = write16(state, IQM_CF_BYPASSDET__A, 1);
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-#define DEFAULT_FR_THRES_8K     4000
-static int DVBTCtrlSetFrEnable(struct drxk_state *state, bool *enabled)
-{
-
-	int status;
-
-	dprintk(1, "\n");
-	if (*enabled == true) {
-		/* write mask to 1 */
-		status = write16(state, OFDM_SC_RA_RAM_FR_THRES_8K__A,
-				   DEFAULT_FR_THRES_8K);
-	} else {
-		/* write mask to 0 */
-		status = write16(state, OFDM_SC_RA_RAM_FR_THRES_8K__A, 0);
-	}
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-
-	return status;
-}
-
-static int DVBTCtrlSetEchoThreshold(struct drxk_state *state,
-				    struct DRXKCfgDvbtEchoThres_t *echoThres)
-{
-	u16 data = 0;
-	int status;
-
-	dprintk(1, "\n");
-	status = read16(state, OFDM_SC_RA_RAM_ECHO_THRES__A, &data);
-	if (status < 0)
-		goto error;
-
-	switch (echoThres->fftMode) {
-	case DRX_FFTMODE_2K:
-		data &= ~OFDM_SC_RA_RAM_ECHO_THRES_2K__M;
-		data |= ((echoThres->threshold <<
-			OFDM_SC_RA_RAM_ECHO_THRES_2K__B)
-			& (OFDM_SC_RA_RAM_ECHO_THRES_2K__M));
-		break;
-	case DRX_FFTMODE_8K:
-		data &= ~OFDM_SC_RA_RAM_ECHO_THRES_8K__M;
-		data |= ((echoThres->threshold <<
-			OFDM_SC_RA_RAM_ECHO_THRES_8K__B)
-			& (OFDM_SC_RA_RAM_ECHO_THRES_8K__M));
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	status = write16(state, OFDM_SC_RA_RAM_ECHO_THRES__A, data);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int DVBTCtrlSetSqiSpeed(struct drxk_state *state,
-			       enum DRXKCfgDvbtSqiSpeed *speed)
-{
-	int status = -EINVAL;
-
-	dprintk(1, "\n");
-
-	switch (*speed) {
-	case DRXK_DVBT_SQI_SPEED_FAST:
-	case DRXK_DVBT_SQI_SPEED_MEDIUM:
-	case DRXK_DVBT_SQI_SPEED_SLOW:
-		break;
-	default:
-		goto error;
-	}
-	status = write16(state, SCU_RAM_FEC_PRE_RS_BER_FILTER_SH__A,
-			   (u16) *speed);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-/*============================================================================*/
-
-/**
-* \brief Activate DVBT specific presets
-* \param demod instance of demodulator.
-* \return DRXStatus_t.
-*
-* Called in DVBTSetStandard
-*
-*/
-static int DVBTActivatePresets(struct drxk_state *state)
-{
-	int status;
-	bool setincenable = false;
-	bool setfrenable = true;
-
-	struct DRXKCfgDvbtEchoThres_t echoThres2k = { 0, DRX_FFTMODE_2K };
-	struct DRXKCfgDvbtEchoThres_t echoThres8k = { 0, DRX_FFTMODE_8K };
-
-	dprintk(1, "\n");
-	status = DVBTCtrlSetIncEnable(state, &setincenable);
-	if (status < 0)
-		goto error;
-	status = DVBTCtrlSetFrEnable(state, &setfrenable);
-	if (status < 0)
-		goto error;
-	status = DVBTCtrlSetEchoThreshold(state, &echoThres2k);
-	if (status < 0)
-		goto error;
-	status = DVBTCtrlSetEchoThreshold(state, &echoThres8k);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A, state->m_dvbtIfAgcCfg.IngainTgtMax);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-/*============================================================================*/
-
-/**
-* \brief Initialize channelswitch-independent settings for DVBT.
-* \param demod instance of demodulator.
-* \return DRXStatus_t.
-*
-* For ROM code channel filter taps are loaded from the bootloader. For microcode
-* the DVB-T taps from the drxk_filters.h are used.
-*/
-static int SetDVBTStandard(struct drxk_state *state,
-			   enum OperationMode oMode)
-{
-	u16 cmdResult = 0;
-	u16 data = 0;
-	int status;
-
-	dprintk(1, "\n");
-
-	PowerUpDVBT(state);
-	/* added antenna switch */
-	SwitchAntennaToDVBT(state);
-	/* send OFDM reset command */
-	status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
-	if (status < 0)
-		goto error;
-
-	/* send OFDM setenv command */
-	status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV, 0, NULL, 1, &cmdResult);
-	if (status < 0)
-		goto error;
-
-	/* reset datapath for OFDM, processors first */
-	status = write16(state, OFDM_SC_COMM_EXEC__A, OFDM_SC_COMM_EXEC_STOP);
-	if (status < 0)
-		goto error;
-	status = write16(state, OFDM_LC_COMM_EXEC__A, OFDM_LC_COMM_EXEC_STOP);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_STOP);
-	if (status < 0)
-		goto error;
-
-	/* IQM setup */
-	/* synchronize on ofdstate->m_festart */
-	status = write16(state, IQM_AF_UPD_SEL__A, 1);
-	if (status < 0)
-		goto error;
-	/* window size for clipping ADC detection */
-	status = write16(state, IQM_AF_CLP_LEN__A, 0);
-	if (status < 0)
-		goto error;
-	/* window size for for sense pre-SAW detection */
-	status = write16(state, IQM_AF_SNS_LEN__A, 0);
-	if (status < 0)
-		goto error;
-	/* sense threshold for sense pre-SAW detection */
-	status = write16(state, IQM_AF_AMUX__A, IQM_AF_AMUX_SIGNAL2ADC);
-	if (status < 0)
-		goto error;
-	status = SetIqmAf(state, true);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, IQM_AF_AGC_RF__A, 0);
-	if (status < 0)
-		goto error;
-
-	/* Impulse noise cruncher setup */
-	status = write16(state, IQM_AF_INC_LCT__A, 0);	/* crunch in IQM_CF */
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_CF_DET_LCT__A, 0);	/* detect in IQM_CF */
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_CF_WND_LEN__A, 3);	/* peak detector window length */
-	if (status < 0)
-		goto error;
-
-	status = write16(state, IQM_RC_STRETCH__A, 16);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_CF_OUT_ENA__A, 0x4);	/* enable output 2 */
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_CF_DS_ENA__A, 0x4);	/* decimate output 2 */
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_CF_SCALE__A, 1600);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_CF_SCALE_SH__A, 0);
-	if (status < 0)
-		goto error;
-
-	/* virtual clipping threshold for clipping ADC detection */
-	status = write16(state, IQM_AF_CLP_TH__A, 448);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_CF_DATATH__A, 495);	/* crunching threshold */
-	if (status < 0)
-		goto error;
-
-	status = BLChainCmd(state, DRXK_BL_ROM_OFFSET_TAPS_DVBT, DRXK_BLCC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, IQM_CF_PKDTH__A, 2);	/* peak detector threshold */
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_CF_POW_MEAS_LEN__A, 2);
-	if (status < 0)
-		goto error;
-	/* enable power measurement interrupt */
-	status = write16(state, IQM_CF_COMM_INT_MSK__A, 1);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_ACTIVE);
-	if (status < 0)
-		goto error;
-
-	/* IQM will not be reset from here, sync ADC and update/init AGC */
-	status = ADCSynchronization(state);
-	if (status < 0)
-		goto error;
-	status = SetPreSaw(state, &state->m_dvbtPreSawCfg);
-	if (status < 0)
-		goto error;
-
-	/* Halt SCU to enable safe non-atomic accesses */
-	status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD);
-	if (status < 0)
-		goto error;
-
-	status = SetAgcRf(state, &state->m_dvbtRfAgcCfg, true);
-	if (status < 0)
-		goto error;
-	status = SetAgcIf(state, &state->m_dvbtIfAgcCfg, true);
-	if (status < 0)
-		goto error;
-
-	/* Set Noise Estimation notch width and enable DC fix */
-	status = read16(state, OFDM_SC_RA_RAM_CONFIG__A, &data);
-	if (status < 0)
-		goto error;
-	data |= OFDM_SC_RA_RAM_CONFIG_NE_FIX_ENABLE__M;
-	status = write16(state, OFDM_SC_RA_RAM_CONFIG__A, data);
-	if (status < 0)
-		goto error;
-
-	/* Activate SCU to enable SCU commands */
-	status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
-	if (status < 0)
-		goto error;
-
-	if (!state->m_DRXK_A3_ROM_CODE) {
-		/* AGCInit() is not done for DVBT, so set agcFastClipCtrlDelay  */
-		status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A, state->m_dvbtIfAgcCfg.FastClipCtrlDelay);
-		if (status < 0)
-			goto error;
-	}
-
-	/* OFDM_SC setup */
-#ifdef COMPILE_FOR_NONRT
-	status = write16(state, OFDM_SC_RA_RAM_BE_OPT_DELAY__A, 1);
-	if (status < 0)
-		goto error;
-	status = write16(state, OFDM_SC_RA_RAM_BE_OPT_INIT_DELAY__A, 2);
-	if (status < 0)
-		goto error;
-#endif
-
-	/* FEC setup */
-	status = write16(state, FEC_DI_INPUT_CTL__A, 1);	/* OFDM input */
-	if (status < 0)
-		goto error;
-
-
-#ifdef COMPILE_FOR_NONRT
-	status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, 0x400);
-	if (status < 0)
-		goto error;
-#else
-	status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, 0x1000);
-	if (status < 0)
-		goto error;
-#endif
-	status = write16(state, FEC_RS_MEASUREMENT_PRESCALE__A, 0x0001);
-	if (status < 0)
-		goto error;
-
-	/* Setup MPEG bus */
-	status = MPEGTSDtoSetup(state, OM_DVBT);
-	if (status < 0)
-		goto error;
-	/* Set DVBT Presets */
-	status = DVBTActivatePresets(state);
-	if (status < 0)
-		goto error;
-
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-/*============================================================================*/
-/**
-* \brief Start dvbt demodulating for channel.
-* \param demod instance of demodulator.
-* \return DRXStatus_t.
-*/
-static int DVBTStart(struct drxk_state *state)
-{
-	u16 param1;
-	int status;
-	/* DRXKOfdmScCmd_t scCmd; */
-
-	dprintk(1, "\n");
-	/* Start correct processes to get in lock */
-	/* DRXK: OFDM_SC_RA_RAM_PROC_LOCKTRACK is no longer in mapfile! */
-	param1 = OFDM_SC_RA_RAM_LOCKTRACK_MIN;
-	status = DVBTScCommand(state, OFDM_SC_RA_RAM_CMD_PROC_START, 0, OFDM_SC_RA_RAM_SW_EVENT_RUN_NMASK__M, param1, 0, 0, 0);
-	if (status < 0)
-		goto error;
-	/* Start FEC OC */
-	status = MPEGTSStart(state);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_ACTIVE);
-	if (status < 0)
-		goto error;
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-
-/*============================================================================*/
-
-/**
-* \brief Set up dvbt demodulator for channel.
-* \param demod instance of demodulator.
-* \return DRXStatus_t.
-* // original DVBTSetChannel()
-*/
-static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
-		   s32 tunerFreqOffset)
-{
-	u16 cmdResult = 0;
-	u16 transmissionParams = 0;
-	u16 operationMode = 0;
-	u32 iqmRcRateOfs = 0;
-	u32 bandwidth = 0;
-	u16 param1;
-	int status;
-
-	dprintk(1, "IF =%d, TFO = %d\n", IntermediateFreqkHz, tunerFreqOffset);
-
-	status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
-	if (status < 0)
-		goto error;
-
-	/* Halt SCU to enable safe non-atomic accesses */
-	status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD);
-	if (status < 0)
-		goto error;
-
-	/* Stop processors */
-	status = write16(state, OFDM_SC_COMM_EXEC__A, OFDM_SC_COMM_EXEC_STOP);
-	if (status < 0)
-		goto error;
-	status = write16(state, OFDM_LC_COMM_EXEC__A, OFDM_LC_COMM_EXEC_STOP);
-	if (status < 0)
-		goto error;
-
-	/* Mandatory fix, always stop CP, required to set spl offset back to
-		hardware default (is set to 0 by ucode during pilot detection */
-	status = write16(state, OFDM_CP_COMM_EXEC__A, OFDM_CP_COMM_EXEC_STOP);
-	if (status < 0)
-		goto error;
-
-	/*== Write channel settings to device =====================================*/
-
-	/* mode */
-	switch (state->props.transmission_mode) {
-	case TRANSMISSION_MODE_AUTO:
-	default:
-		operationMode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M;
-		/* fall through , try first guess DRX_FFTMODE_8K */
-	case TRANSMISSION_MODE_8K:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_8K;
-		break;
-	case TRANSMISSION_MODE_2K:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_2K;
-		break;
-	}
-
-	/* guard */
-	switch (state->props.guard_interval) {
-	default:
-	case GUARD_INTERVAL_AUTO:
-		operationMode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M;
-		/* fall through , try first guess DRX_GUARD_1DIV4 */
-	case GUARD_INTERVAL_1_4:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_4;
-		break;
-	case GUARD_INTERVAL_1_32:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_32;
-		break;
-	case GUARD_INTERVAL_1_16:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_16;
-		break;
-	case GUARD_INTERVAL_1_8:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_8;
-		break;
-	}
-
-	/* hierarchy */
-	switch (state->props.hierarchy) {
-	case HIERARCHY_AUTO:
-	case HIERARCHY_NONE:
-	default:
-		operationMode |= OFDM_SC_RA_RAM_OP_AUTO_HIER__M;
-		/* fall through , try first guess SC_RA_RAM_OP_PARAM_HIER_NO */
-		/* transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_NO; */
-		/* break; */
-	case HIERARCHY_1:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A1;
-		break;
-	case HIERARCHY_2:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A2;
-		break;
-	case HIERARCHY_4:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A4;
-		break;
-	}
-
-
-	/* modulation */
-	switch (state->props.modulation) {
-	case QAM_AUTO:
-	default:
-		operationMode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M;
-		/* fall through , try first guess DRX_CONSTELLATION_QAM64 */
-	case QAM_64:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64;
-		break;
-	case QPSK:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QPSK;
-		break;
-	case QAM_16:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM16;
-		break;
-	}
-#if 0
-	/* No hierachical channels support in BDA */
-	/* Priority (only for hierarchical channels) */
-	switch (channel->priority) {
-	case DRX_PRIORITY_LOW:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_LO;
-		WR16(devAddr, OFDM_EC_SB_PRIOR__A,
-			OFDM_EC_SB_PRIOR_LO);
-		break;
-	case DRX_PRIORITY_HIGH:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI;
-		WR16(devAddr, OFDM_EC_SB_PRIOR__A,
-			OFDM_EC_SB_PRIOR_HI));
-		break;
-	case DRX_PRIORITY_UNKNOWN:	/* fall through */
-	default:
-		status = -EINVAL;
-		goto error;
-	}
-#else
-	/* Set Priorty high */
-	transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI;
-	status = write16(state, OFDM_EC_SB_PRIOR__A, OFDM_EC_SB_PRIOR_HI);
-	if (status < 0)
-		goto error;
-#endif
-
-	/* coderate */
-	switch (state->props.code_rate_HP) {
-	case FEC_AUTO:
-	default:
-		operationMode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M;
-		/* fall through , try first guess DRX_CODERATE_2DIV3 */
-	case FEC_2_3:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3;
-		break;
-	case FEC_1_2:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_1_2;
-		break;
-	case FEC_3_4:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_3_4;
-		break;
-	case FEC_5_6:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_5_6;
-		break;
-	case FEC_7_8:
-		transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_7_8;
-		break;
-	}
-
-	/* SAW filter selection: normaly not necesarry, but if wanted
-		the application can select a SAW filter via the driver by using UIOs */
-	/* First determine real bandwidth (Hz) */
-	/* Also set delay for impulse noise cruncher */
-	/* Also set parameters for EC_OC fix, note EC_OC_REG_TMD_HIL_MAR is changed
-		by SC for fix for some 8K,1/8 guard but is restored by InitEC and ResetEC
-		functions */
-	switch (state->props.bandwidth_hz) {
-	case 0:
-		state->props.bandwidth_hz = 8000000;
-		/* fall though */
-	case 8000000:
-		bandwidth = DRXK_BANDWIDTH_8MHZ_IN_HZ;
-		status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3052);
-		if (status < 0)
-			goto error;
-		/* cochannel protection for PAL 8 MHz */
-		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 7);
-		if (status < 0)
-			goto error;
-		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 7);
-		if (status < 0)
-			goto error;
-		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 7);
-		if (status < 0)
-			goto error;
-		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
-		if (status < 0)
-			goto error;
-		break;
-	case 7000000:
-		bandwidth = DRXK_BANDWIDTH_7MHZ_IN_HZ;
-		status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3491);
-		if (status < 0)
-			goto error;
-		/* cochannel protection for PAL 7 MHz */
-		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 8);
-		if (status < 0)
-			goto error;
-		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 8);
-		if (status < 0)
-			goto error;
-		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 4);
-		if (status < 0)
-			goto error;
-		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
-		if (status < 0)
-			goto error;
-		break;
-	case 6000000:
-		bandwidth = DRXK_BANDWIDTH_6MHZ_IN_HZ;
-		status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 4073);
-		if (status < 0)
-			goto error;
-		/* cochannel protection for NTSC 6 MHz */
-		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 19);
-		if (status < 0)
-			goto error;
-		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 19);
-		if (status < 0)
-			goto error;
-		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 14);
-		if (status < 0)
-			goto error;
-		status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
-		if (status < 0)
-			goto error;
-		break;
-	default:
-		status = -EINVAL;
-		goto error;
-	}
-
-	if (iqmRcRateOfs == 0) {
-		/* Now compute IQM_RC_RATE_OFS
-			(((SysFreq/BandWidth)/2)/2) -1) * 2^23)
-			=>
-			((SysFreq / BandWidth) * (2^21)) - (2^23)
-			*/
-		/* (SysFreq / BandWidth) * (2^28)  */
-		/* assert (MAX(sysClk)/MIN(bandwidth) < 16)
-			=> assert(MAX(sysClk) < 16*MIN(bandwidth))
-			=> assert(109714272 > 48000000) = true so Frac 28 can be used  */
-		iqmRcRateOfs = Frac28a((u32)
-					((state->m_sysClockFreq *
-						1000) / 3), bandwidth);
-		/* (SysFreq / BandWidth) * (2^21), rounding before truncating  */
-		if ((iqmRcRateOfs & 0x7fL) >= 0x40)
-			iqmRcRateOfs += 0x80L;
-		iqmRcRateOfs = iqmRcRateOfs >> 7;
-		/* ((SysFreq / BandWidth) * (2^21)) - (2^23)  */
-		iqmRcRateOfs = iqmRcRateOfs - (1 << 23);
-	}
-
-	iqmRcRateOfs &=
-		((((u32) IQM_RC_RATE_OFS_HI__M) <<
-		IQM_RC_RATE_OFS_LO__W) | IQM_RC_RATE_OFS_LO__M);
-	status = write32(state, IQM_RC_RATE_OFS_LO__A, iqmRcRateOfs);
-	if (status < 0)
-		goto error;
-
-	/* Bandwidth setting done */
-
-#if 0
-	status = DVBTSetFrequencyShift(demod, channel, tunerOffset);
-	if (status < 0)
-		goto error;
-#endif
-	status = SetFrequencyShifter(state, IntermediateFreqkHz, tunerFreqOffset, true);
-	if (status < 0)
-		goto error;
-
-	/*== Start SC, write channel settings to SC ===============================*/
-
-	/* Activate SCU to enable SCU commands */
-	status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
-	if (status < 0)
-		goto error;
-
-	/* Enable SC after setting all other parameters */
-	status = write16(state, OFDM_SC_COMM_STATE__A, 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, OFDM_SC_COMM_EXEC__A, 1);
-	if (status < 0)
-		goto error;
-
-
-	status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_START, 0, NULL, 1, &cmdResult);
-	if (status < 0)
-		goto error;
-
-	/* Write SC parameter registers, set all AUTO flags in operation mode */
-	param1 = (OFDM_SC_RA_RAM_OP_AUTO_MODE__M |
-			OFDM_SC_RA_RAM_OP_AUTO_GUARD__M |
-			OFDM_SC_RA_RAM_OP_AUTO_CONST__M |
-			OFDM_SC_RA_RAM_OP_AUTO_HIER__M |
-			OFDM_SC_RA_RAM_OP_AUTO_RATE__M);
-	status = DVBTScCommand(state, OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM,
-				0, transmissionParams, param1, 0, 0, 0);
-	if (status < 0)
-		goto error;
-
-	if (!state->m_DRXK_A3_ROM_CODE)
-		status = DVBTCtrlSetSqiSpeed(state, &state->m_sqiSpeed);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-
-	return status;
-}
-
-
-/*============================================================================*/
-
-/**
-* \brief Retreive lock status .
-* \param demod    Pointer to demodulator instance.
-* \param lockStat Pointer to lock status structure.
-* \return DRXStatus_t.
-*
-*/
-static int GetDVBTLockStatus(struct drxk_state *state, u32 *pLockStatus)
-{
-	int status;
-	const u16 mpeg_lock_mask = (OFDM_SC_RA_RAM_LOCK_MPEG__M |
-				    OFDM_SC_RA_RAM_LOCK_FEC__M);
-	const u16 fec_lock_mask = (OFDM_SC_RA_RAM_LOCK_FEC__M);
-	const u16 demod_lock_mask = OFDM_SC_RA_RAM_LOCK_DEMOD__M;
-
-	u16 ScRaRamLock = 0;
-	u16 ScCommExec = 0;
-
-	dprintk(1, "\n");
-
-	*pLockStatus = NOT_LOCKED;
-	/* driver 0.9.0 */
-	/* Check if SC is running */
-	status = read16(state, OFDM_SC_COMM_EXEC__A, &ScCommExec);
-	if (status < 0)
-		goto end;
-	if (ScCommExec == OFDM_SC_COMM_EXEC_STOP)
-		goto end;
-
-	status = read16(state, OFDM_SC_RA_RAM_LOCK__A, &ScRaRamLock);
-	if (status < 0)
-		goto end;
-
-	if ((ScRaRamLock & mpeg_lock_mask) == mpeg_lock_mask)
-		*pLockStatus = MPEG_LOCK;
-	else if ((ScRaRamLock & fec_lock_mask) == fec_lock_mask)
-		*pLockStatus = FEC_LOCK;
-	else if ((ScRaRamLock & demod_lock_mask) == demod_lock_mask)
-		*pLockStatus = DEMOD_LOCK;
-	else if (ScRaRamLock & OFDM_SC_RA_RAM_LOCK_NODVBT__M)
-		*pLockStatus = NEVER_LOCK;
-end:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-
-	return status;
-}
-
-static int PowerUpQAM(struct drxk_state *state)
-{
-	enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
-	int status;
-
-	dprintk(1, "\n");
-	status = CtrlPowerMode(state, &powerMode);
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-
-	return status;
-}
-
-
-/** Power Down QAM */
-static int PowerDownQAM(struct drxk_state *state)
-{
-	u16 data = 0;
-	u16 cmdResult;
-	int status = 0;
-
-	dprintk(1, "\n");
-	status = read16(state, SCU_COMM_EXEC__A, &data);
-	if (status < 0)
-		goto error;
-	if (data == SCU_COMM_EXEC_ACTIVE) {
-		/*
-			STOP demodulator
-			QAM and HW blocks
-			*/
-		/* stop all comstate->m_exec */
-		status = write16(state, QAM_COMM_EXEC__A, QAM_COMM_EXEC_STOP);
-		if (status < 0)
-			goto error;
-		status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
-		if (status < 0)
-			goto error;
-	}
-	/* powerdown AFE                   */
-	status = SetIqmAf(state, false);
-
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-
-	return status;
-}
-
-/*============================================================================*/
-
-/**
-* \brief Setup of the QAM Measurement intervals for signal quality
-* \param demod instance of demod.
-* \param modulation current modulation.
-* \return DRXStatus_t.
-*
-*  NOTE:
-*  Take into account that for certain settings the errorcounters can overflow.
-*  The implementation does not check this.
-*
-*/
-static int SetQAMMeasurement(struct drxk_state *state,
-			     enum EDrxkConstellation modulation,
-			     u32 symbolRate)
-{
-	u32 fecBitsDesired = 0;	/* BER accounting period */
-	u32 fecRsPeriodTotal = 0;	/* Total period */
-	u16 fecRsPrescale = 0;	/* ReedSolomon Measurement Prescale */
-	u16 fecRsPeriod = 0;	/* Value for corresponding I2C register */
-	int status = 0;
-
-	dprintk(1, "\n");
-
-	fecRsPrescale = 1;
-	/* fecBitsDesired = symbolRate [kHz] *
-		FrameLenght [ms] *
-		(modulation + 1) *
-		SyncLoss (== 1) *
-		ViterbiLoss (==1)
-		*/
-	switch (modulation) {
-	case DRX_CONSTELLATION_QAM16:
-		fecBitsDesired = 4 * symbolRate;
-		break;
-	case DRX_CONSTELLATION_QAM32:
-		fecBitsDesired = 5 * symbolRate;
-		break;
-	case DRX_CONSTELLATION_QAM64:
-		fecBitsDesired = 6 * symbolRate;
-		break;
-	case DRX_CONSTELLATION_QAM128:
-		fecBitsDesired = 7 * symbolRate;
-		break;
-	case DRX_CONSTELLATION_QAM256:
-		fecBitsDesired = 8 * symbolRate;
-		break;
-	default:
-		status = -EINVAL;
-	}
-	if (status < 0)
-		goto error;
-
-	fecBitsDesired /= 1000;	/* symbolRate [Hz] -> symbolRate [kHz]  */
-	fecBitsDesired *= 500;	/* meas. period [ms] */
-
-	/* Annex A/C: bits/RsPeriod = 204 * 8 = 1632 */
-	/* fecRsPeriodTotal = fecBitsDesired / 1632 */
-	fecRsPeriodTotal = (fecBitsDesired / 1632UL) + 1;	/* roughly ceil */
-
-	/* fecRsPeriodTotal =  fecRsPrescale * fecRsPeriod  */
-	fecRsPrescale = 1 + (u16) (fecRsPeriodTotal >> 16);
-	if (fecRsPrescale == 0) {
-		/* Divide by zero (though impossible) */
-		status = -EINVAL;
-		if (status < 0)
-			goto error;
-	}
-	fecRsPeriod =
-		((u16) fecRsPeriodTotal +
-		(fecRsPrescale >> 1)) / fecRsPrescale;
-
-	/* write corresponding registers */
-	status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, fecRsPeriod);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_RS_MEASUREMENT_PRESCALE__A, fecRsPrescale);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_OC_SNC_FAIL_PERIOD__A, fecRsPeriod);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int SetQAM16(struct drxk_state *state)
-{
-	int status = 0;
-
-	dprintk(1, "\n");
-	/* QAM Equalizer Setup */
-	/* Equalizer */
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 13517);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 13517);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 13517);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 13517);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 13517);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 13517);
-	if (status < 0)
-		goto error;
-	/* Decision Feedback Equalizer */
-	status = write16(state, QAM_DQ_QUAL_FUN0__A, 2);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN1__A, 2);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN2__A, 2);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN3__A, 2);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN4__A, 2);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, QAM_SY_SYNC_HWM__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_SY_SYNC_AWM__A, 4);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_SY_SYNC_LWM__A, 3);
-	if (status < 0)
-		goto error;
-
-	/* QAM Slicer Settings */
-	status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM16);
-	if (status < 0)
-		goto error;
-
-	/* QAM Loop Controller Coeficients */
-	status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 20);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 80);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 20);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 50);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 16);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 32);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 10);
-	if (status < 0)
-		goto error;
-
-
-	/* QAM State Machine (FSM) Thresholds */
-
-	status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 140);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 50);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 95);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 120);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 230);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 105);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 24);
-	if (status < 0)
-		goto error;
-
-
-	/* QAM FSM Tracking Parameters */
-
-	status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 16);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 220);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 25);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 6);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -24);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -65);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -127);
-	if (status < 0)
-		goto error;
-
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-/*============================================================================*/
-
-/**
-* \brief QAM32 specific setup
-* \param demod instance of demod.
-* \return DRXStatus_t.
-*/
-static int SetQAM32(struct drxk_state *state)
-{
-	int status = 0;
-
-	dprintk(1, "\n");
-
-	/* QAM Equalizer Setup */
-	/* Equalizer */
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 6707);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 6707);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 6707);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 6707);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 6707);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 6707);
-	if (status < 0)
-		goto error;
-
-	/* Decision Feedback Equalizer */
-	status = write16(state, QAM_DQ_QUAL_FUN0__A, 3);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN1__A, 3);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN2__A, 3);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN3__A, 3);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN4__A, 3);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, QAM_SY_SYNC_HWM__A, 6);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_SY_SYNC_AWM__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_SY_SYNC_LWM__A, 3);
-	if (status < 0)
-		goto error;
-
-	/* QAM Slicer Settings */
-
-	status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM32);
-	if (status < 0)
-		goto error;
-
-
-	/* QAM Loop Controller Coeficients */
-
-	status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 20);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 80);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 20);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 50);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 16);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 16);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 0);
-	if (status < 0)
-		goto error;
-
-
-	/* QAM State Machine (FSM) Thresholds */
-
-	status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 90);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 50);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 100);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 170);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 100);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 10);
-	if (status < 0)
-		goto error;
-
-
-	/* QAM FSM Tracking Parameters */
-
-	status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 12);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 140);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) -8);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) -16);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -26);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -56);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -86);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-/*============================================================================*/
-
-/**
-* \brief QAM64 specific setup
-* \param demod instance of demod.
-* \return DRXStatus_t.
-*/
-static int SetQAM64(struct drxk_state *state)
-{
-	int status = 0;
-
-	dprintk(1, "\n");
-	/* QAM Equalizer Setup */
-	/* Equalizer */
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 13336);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 12618);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 11988);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 13809);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 13809);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 15609);
-	if (status < 0)
-		goto error;
-
-	/* Decision Feedback Equalizer */
-	status = write16(state, QAM_DQ_QUAL_FUN0__A, 4);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN1__A, 4);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN2__A, 4);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN3__A, 4);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN4__A, 3);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, QAM_SY_SYNC_HWM__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_SY_SYNC_AWM__A, 4);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_SY_SYNC_LWM__A, 3);
-	if (status < 0)
-		goto error;
-
-	/* QAM Slicer Settings */
-	status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM64);
-	if (status < 0)
-		goto error;
-
-
-	/* QAM Loop Controller Coeficients */
-
-	status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 30);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 100);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 30);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 50);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 25);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 48);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 10);
-	if (status < 0)
-		goto error;
-
-
-	/* QAM State Machine (FSM) Thresholds */
-
-	status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 100);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 60);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 110);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 200);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 95);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 15);
-	if (status < 0)
-		goto error;
-
-
-	/* QAM FSM Tracking Parameters */
-
-	status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 12);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 141);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 7);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -15);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -45);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -80);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-
-	return status;
-}
-
-/*============================================================================*/
-
-/**
-* \brief QAM128 specific setup
-* \param demod: instance of demod.
-* \return DRXStatus_t.
-*/
-static int SetQAM128(struct drxk_state *state)
-{
-	int status = 0;
-
-	dprintk(1, "\n");
-	/* QAM Equalizer Setup */
-	/* Equalizer */
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 6564);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 6598);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 6394);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 6409);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 6656);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 7238);
-	if (status < 0)
-		goto error;
-
-	/* Decision Feedback Equalizer */
-	status = write16(state, QAM_DQ_QUAL_FUN0__A, 6);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN1__A, 6);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN2__A, 6);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN3__A, 6);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN4__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, QAM_SY_SYNC_HWM__A, 6);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_SY_SYNC_AWM__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_SY_SYNC_LWM__A, 3);
-	if (status < 0)
-		goto error;
-
-
-	/* QAM Slicer Settings */
-
-	status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM128);
-	if (status < 0)
-		goto error;
-
-
-	/* QAM Loop Controller Coeficients */
-
-	status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 40);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 120);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 40);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 60);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 25);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 64);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 0);
-	if (status < 0)
-		goto error;
-
-
-	/* QAM State Machine (FSM) Thresholds */
-
-	status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 50);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 60);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 100);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 140);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 100);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 5);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 12);
-	if (status < 0)
-		goto error;
-
-	/* QAM FSM Tracking Parameters */
-
-	status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 8);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 65);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 3);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -1);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -12);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -23);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-
-	return status;
-}
-
-/*============================================================================*/
-
-/**
-* \brief QAM256 specific setup
-* \param demod: instance of demod.
-* \return DRXStatus_t.
-*/
-static int SetQAM256(struct drxk_state *state)
-{
-	int status = 0;
-
-	dprintk(1, "\n");
-	/* QAM Equalizer Setup */
-	/* Equalizer */
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 11502);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 12084);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 12543);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 12931);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 13629);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 15385);
-	if (status < 0)
-		goto error;
-
-	/* Decision Feedback Equalizer */
-	status = write16(state, QAM_DQ_QUAL_FUN0__A, 8);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN1__A, 8);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN2__A, 8);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN3__A, 8);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN4__A, 6);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, QAM_SY_SYNC_HWM__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_SY_SYNC_AWM__A, 4);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_SY_SYNC_LWM__A, 3);
-	if (status < 0)
-		goto error;
-
-	/* QAM Slicer Settings */
-
-	status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM256);
-	if (status < 0)
-		goto error;
-
-
-	/* QAM Loop Controller Coeficients */
-
-	status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 50);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 250);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 50);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 125);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 25);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 48);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 10);
-	if (status < 0)
-		goto error;
-
-
-	/* QAM State Machine (FSM) Thresholds */
-
-	status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 50);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 60);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 100);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 150);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 110);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 12);
-	if (status < 0)
-		goto error;
-
-
-	/* QAM FSM Tracking Parameters */
-
-	status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 8);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 74);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 18);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 13);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) 7);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -8);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-
-/*============================================================================*/
-/**
-* \brief Reset QAM block.
-* \param demod:   instance of demod.
-* \param channel: pointer to channel data.
-* \return DRXStatus_t.
-*/
-static int QAMResetQAM(struct drxk_state *state)
-{
-	int status;
-	u16 cmdResult;
-
-	dprintk(1, "\n");
-	/* Stop QAM comstate->m_exec */
-	status = write16(state, QAM_COMM_EXEC__A, QAM_COMM_EXEC_STOP);
-	if (status < 0)
-		goto error;
-
-	status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-/*============================================================================*/
-
-/**
-* \brief Set QAM symbolrate.
-* \param demod:   instance of demod.
-* \param channel: pointer to channel data.
-* \return DRXStatus_t.
-*/
-static int QAMSetSymbolrate(struct drxk_state *state)
-{
-	u32 adcFrequency = 0;
-	u32 symbFreq = 0;
-	u32 iqmRcRate = 0;
-	u16 ratesel = 0;
-	u32 lcSymbRate = 0;
-	int status;
-
-	dprintk(1, "\n");
-	/* Select & calculate correct IQM rate */
-	adcFrequency = (state->m_sysClockFreq * 1000) / 3;
-	ratesel = 0;
-	/* printk(KERN_DEBUG "drxk: SR %d\n", state->props.symbol_rate); */
-	if (state->props.symbol_rate <= 1188750)
-		ratesel = 3;
-	else if (state->props.symbol_rate <= 2377500)
-		ratesel = 2;
-	else if (state->props.symbol_rate <= 4755000)
-		ratesel = 1;
-	status = write16(state, IQM_FD_RATESEL__A, ratesel);
-	if (status < 0)
-		goto error;
-
-	/*
-		IqmRcRate = ((Fadc / (symbolrate * (4<<ratesel))) - 1) * (1<<23)
-		*/
-	symbFreq = state->props.symbol_rate * (1 << ratesel);
-	if (symbFreq == 0) {
-		/* Divide by zero */
-		status = -EINVAL;
-		goto error;
-	}
-	iqmRcRate = (adcFrequency / symbFreq) * (1 << 21) +
-		(Frac28a((adcFrequency % symbFreq), symbFreq) >> 7) -
-		(1 << 23);
-	status = write32(state, IQM_RC_RATE_OFS_LO__A, iqmRcRate);
-	if (status < 0)
-		goto error;
-	state->m_iqmRcRate = iqmRcRate;
-	/*
-		LcSymbFreq = round (.125 *  symbolrate / adcFreq * (1<<15))
-		*/
-	symbFreq = state->props.symbol_rate;
-	if (adcFrequency == 0) {
-		/* Divide by zero */
-		status = -EINVAL;
-		goto error;
-	}
-	lcSymbRate = (symbFreq / adcFrequency) * (1 << 12) +
-		(Frac28a((symbFreq % adcFrequency), adcFrequency) >>
-		16);
-	if (lcSymbRate > 511)
-		lcSymbRate = 511;
-	status = write16(state, QAM_LC_SYMBOL_FREQ__A, (u16) lcSymbRate);
-
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-/*============================================================================*/
-
-/**
-* \brief Get QAM lock status.
-* \param demod:   instance of demod.
-* \param channel: pointer to channel data.
-* \return DRXStatus_t.
-*/
-
-static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus)
-{
-	int status;
-	u16 Result[2] = { 0, 0 };
-
-	dprintk(1, "\n");
-	*pLockStatus = NOT_LOCKED;
-	status = scu_command(state,
-			SCU_RAM_COMMAND_STANDARD_QAM |
-			SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK, 0, NULL, 2,
-			Result);
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-
-	if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED) {
-		/* 0x0000 NOT LOCKED */
-	} else if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_LOCKED) {
-		/* 0x4000 DEMOD LOCKED */
-		*pLockStatus = DEMOD_LOCK;
-	} else if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_NEVER_LOCK) {
-		/* 0x8000 DEMOD + FEC LOCKED (system lock) */
-		*pLockStatus = MPEG_LOCK;
-	} else {
-		/* 0xC000 NEVER LOCKED */
-		/* (system will never be able to lock to the signal) */
-		/* TODO: check this, intermediate & standard specific lock states are not
-		   taken into account here */
-		*pLockStatus = NEVER_LOCK;
-	}
-	return status;
-}
-
-#define QAM_MIRROR__M         0x03
-#define QAM_MIRROR_NORMAL     0x00
-#define QAM_MIRRORED          0x01
-#define QAM_MIRROR_AUTO_ON    0x02
-#define QAM_LOCKRANGE__M      0x10
-#define QAM_LOCKRANGE_NORMAL  0x10
-
-static int QAMDemodulatorCommand(struct drxk_state *state,
-				 int numberOfParameters)
-{
-	int status;
-	u16 cmdResult;
-	u16 setParamParameters[4] = { 0, 0, 0, 0 };
-
-	setParamParameters[0] = state->m_Constellation;	/* modulation     */
-	setParamParameters[1] = DRXK_QAM_I12_J17;	/* interleave mode   */
-
-	if (numberOfParameters == 2) {
-		u16 setEnvParameters[1] = { 0 };
-
-		if (state->m_OperationMode == OM_QAM_ITU_C)
-			setEnvParameters[0] = QAM_TOP_ANNEX_C;
-		else
-			setEnvParameters[0] = QAM_TOP_ANNEX_A;
-
-		status = scu_command(state,
-				     SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV,
-				     1, setEnvParameters, 1, &cmdResult);
-		if (status < 0)
-			goto error;
-
-		status = scu_command(state,
-				     SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM,
-				     numberOfParameters, setParamParameters,
-				     1, &cmdResult);
-	} else if (numberOfParameters == 4) {
-		if (state->m_OperationMode == OM_QAM_ITU_C)
-			setParamParameters[2] = QAM_TOP_ANNEX_C;
-		else
-			setParamParameters[2] = QAM_TOP_ANNEX_A;
-
-		setParamParameters[3] |= (QAM_MIRROR_AUTO_ON);
-		/* Env parameters */
-		/* check for LOCKRANGE Extented */
-		/* setParamParameters[3] |= QAM_LOCKRANGE_NORMAL; */
-
-		status = scu_command(state,
-				     SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM,
-				     numberOfParameters, setParamParameters,
-				     1, &cmdResult);
-	} else {
-		printk(KERN_WARNING "drxk: Unknown QAM demodulator parameter "
-			"count %d\n", numberOfParameters);
-	}
-
-error:
-	if (status < 0)
-		printk(KERN_WARNING "drxk: Warning %d on %s\n",
-		       status, __func__);
-	return status;
-}
-
-static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
-		  s32 tunerFreqOffset)
-{
-	int status;
-	u16 cmdResult;
-	int qamDemodParamCount = state->qam_demod_parameter_count;
-
-	dprintk(1, "\n");
-	/*
-	 * STEP 1: reset demodulator
-	 *	resets FEC DI and FEC RS
-	 *	resets QAM block
-	 *	resets SCU variables
-	 */
-	status = write16(state, FEC_DI_COMM_EXEC__A, FEC_DI_COMM_EXEC_STOP);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_RS_COMM_EXEC__A, FEC_RS_COMM_EXEC_STOP);
-	if (status < 0)
-		goto error;
-	status = QAMResetQAM(state);
-	if (status < 0)
-		goto error;
-
-	/*
-	 * STEP 2: configure demodulator
-	 *	-set params; resets IQM,QAM,FEC HW; initializes some
-	 *       SCU variables
-	 */
-	status = QAMSetSymbolrate(state);
-	if (status < 0)
-		goto error;
-
-	/* Set params */
-	switch (state->props.modulation) {
-	case QAM_256:
-		state->m_Constellation = DRX_CONSTELLATION_QAM256;
-		break;
-	case QAM_AUTO:
-	case QAM_64:
-		state->m_Constellation = DRX_CONSTELLATION_QAM64;
-		break;
-	case QAM_16:
-		state->m_Constellation = DRX_CONSTELLATION_QAM16;
-		break;
-	case QAM_32:
-		state->m_Constellation = DRX_CONSTELLATION_QAM32;
-		break;
-	case QAM_128:
-		state->m_Constellation = DRX_CONSTELLATION_QAM128;
-		break;
-	default:
-		status = -EINVAL;
-		break;
-	}
-	if (status < 0)
-		goto error;
-
-	/* Use the 4-parameter if it's requested or we're probing for
-	 * the correct command. */
-	if (state->qam_demod_parameter_count == 4
-		|| !state->qam_demod_parameter_count) {
-		qamDemodParamCount = 4;
-		status = QAMDemodulatorCommand(state, qamDemodParamCount);
-	}
-
-	/* Use the 2-parameter command if it was requested or if we're
-	 * probing for the correct command and the 4-parameter command
-	 * failed. */
-	if (state->qam_demod_parameter_count == 2
-		|| (!state->qam_demod_parameter_count && status < 0)) {
-		qamDemodParamCount = 2;
-		status = QAMDemodulatorCommand(state, qamDemodParamCount);
-	}
-
-	if (status < 0) {
-		dprintk(1, "Could not set demodulator parameters. Make "
-			"sure qam_demod_parameter_count (%d) is correct for "
-			"your firmware (%s).\n",
-			state->qam_demod_parameter_count,
-			state->microcode_name);
-		goto error;
-	} else if (!state->qam_demod_parameter_count) {
-		dprintk(1, "Auto-probing the correct QAM demodulator command "
-			"parameters was successful - using %d parameters.\n",
-			qamDemodParamCount);
-
-		/*
-		 * One of our commands was successful. We don't need to
-		 * auto-probe anymore, now that we got the correct command.
-		 */
-		state->qam_demod_parameter_count = qamDemodParamCount;
-	}
-
-	/*
-	 * STEP 3: enable the system in a mode where the ADC provides valid
-	 * signal setup modulation independent registers
-	 */
-#if 0
-	status = SetFrequency(channel, tunerFreqOffset));
-	if (status < 0)
-		goto error;
-#endif
-	status = SetFrequencyShifter(state, IntermediateFreqkHz, tunerFreqOffset, true);
-	if (status < 0)
-		goto error;
-
-	/* Setup BER measurement */
-	status = SetQAMMeasurement(state, state->m_Constellation, state->props.symbol_rate);
-	if (status < 0)
-		goto error;
-
-	/* Reset default values */
-	status = write16(state, IQM_CF_SCALE_SH__A, IQM_CF_SCALE_SH__PRE);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_SY_TIMEOUT__A, QAM_SY_TIMEOUT__PRE);
-	if (status < 0)
-		goto error;
-
-	/* Reset default LC values */
-	status = write16(state, QAM_LC_RATE_LIMIT__A, 3);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_LC_LPF_FACTORP__A, 4);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_LC_LPF_FACTORI__A, 4);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_LC_MODE__A, 7);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, QAM_LC_QUAL_TAB0__A, 1);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_LC_QUAL_TAB1__A, 1);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_LC_QUAL_TAB2__A, 1);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_LC_QUAL_TAB3__A, 1);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_LC_QUAL_TAB4__A, 2);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_LC_QUAL_TAB5__A, 2);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_LC_QUAL_TAB6__A, 2);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_LC_QUAL_TAB8__A, 2);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_LC_QUAL_TAB9__A, 2);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_LC_QUAL_TAB10__A, 2);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_LC_QUAL_TAB12__A, 2);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_LC_QUAL_TAB15__A, 3);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_LC_QUAL_TAB16__A, 3);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_LC_QUAL_TAB20__A, 4);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_LC_QUAL_TAB25__A, 4);
-	if (status < 0)
-		goto error;
-
-	/* Mirroring, QAM-block starting point not inverted */
-	status = write16(state, QAM_SY_SP_INV__A, QAM_SY_SP_INV_SPECTRUM_INV_DIS);
-	if (status < 0)
-		goto error;
-
-	/* Halt SCU to enable safe non-atomic accesses */
-	status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD);
-	if (status < 0)
-		goto error;
-
-	/* STEP 4: modulation specific setup */
-	switch (state->props.modulation) {
-	case QAM_16:
-		status = SetQAM16(state);
-		break;
-	case QAM_32:
-		status = SetQAM32(state);
-		break;
-	case QAM_AUTO:
-	case QAM_64:
-		status = SetQAM64(state);
-		break;
-	case QAM_128:
-		status = SetQAM128(state);
-		break;
-	case QAM_256:
-		status = SetQAM256(state);
-		break;
-	default:
-		status = -EINVAL;
-		break;
-	}
-	if (status < 0)
-		goto error;
-
-	/* Activate SCU to enable SCU commands */
-	status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
-	if (status < 0)
-		goto error;
-
-	/* Re-configure MPEG output, requires knowledge of channel bitrate */
-	/* extAttr->currentChannel.modulation = channel->modulation; */
-	/* extAttr->currentChannel.symbolrate    = channel->symbolrate; */
-	status = MPEGTSDtoSetup(state, state->m_OperationMode);
-	if (status < 0)
-		goto error;
-
-	/* Start processes */
-	status = MPEGTSStart(state);
-	if (status < 0)
-		goto error;
-	status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_ACTIVE);
-	if (status < 0)
-		goto error;
-	status = write16(state, QAM_COMM_EXEC__A, QAM_COMM_EXEC_ACTIVE);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_ACTIVE);
-	if (status < 0)
-		goto error;
-
-	/* STEP 5: start QAM demodulator (starts FEC, QAM and IQM HW) */
-	status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_START, 0, NULL, 1, &cmdResult);
-	if (status < 0)
-		goto error;
-
-	/* update global DRXK data container */
-/*?     extAttr->qamInterleaveMode = DRXK_QAM_I12_J17; */
-
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int SetQAMStandard(struct drxk_state *state,
-			  enum OperationMode oMode)
-{
-	int status;
-#ifdef DRXK_QAM_TAPS
-#define DRXK_QAMA_TAPS_SELECT
-#include "drxk_filters.h"
-#undef DRXK_QAMA_TAPS_SELECT
-#endif
-
-	dprintk(1, "\n");
-
-	/* added antenna switch */
-	SwitchAntennaToQAM(state);
-
-	/* Ensure correct power-up mode */
-	status = PowerUpQAM(state);
-	if (status < 0)
-		goto error;
-	/* Reset QAM block */
-	status = QAMResetQAM(state);
-	if (status < 0)
-		goto error;
-
-	/* Setup IQM */
-
-	status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_STOP);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_AF_AMUX__A, IQM_AF_AMUX_SIGNAL2ADC);
-	if (status < 0)
-		goto error;
-
-	/* Upload IQM Channel Filter settings by
-		boot loader from ROM table */
-	switch (oMode) {
-	case OM_QAM_ITU_A:
-		status = BLChainCmd(state, DRXK_BL_ROM_OFFSET_TAPS_ITU_A, DRXK_BLCC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
-		break;
-	case OM_QAM_ITU_C:
-		status = BLDirectCmd(state, IQM_CF_TAP_RE0__A, DRXK_BL_ROM_OFFSET_TAPS_ITU_C, DRXK_BLDC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
-		if (status < 0)
-			goto error;
-		status = BLDirectCmd(state, IQM_CF_TAP_IM0__A, DRXK_BL_ROM_OFFSET_TAPS_ITU_C, DRXK_BLDC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
-		break;
-	default:
-		status = -EINVAL;
-	}
-	if (status < 0)
-		goto error;
-
-	status = write16(state, IQM_CF_OUT_ENA__A, (1 << IQM_CF_OUT_ENA_QAM__B));
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_CF_SYMMETRIC__A, 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_CF_MIDTAP__A, ((1 << IQM_CF_MIDTAP_RE__B) | (1 << IQM_CF_MIDTAP_IM__B)));
-	if (status < 0)
-		goto error;
-
-	status = write16(state, IQM_RC_STRETCH__A, 21);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_AF_CLP_LEN__A, 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_AF_CLP_TH__A, 448);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_AF_SNS_LEN__A, 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_CF_POW_MEAS_LEN__A, 0);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, IQM_FS_ADJ_SEL__A, 1);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_RC_ADJ_SEL__A, 1);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_CF_ADJ_SEL__A, 1);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_AF_UPD_SEL__A, 0);
-	if (status < 0)
-		goto error;
-
-	/* IQM Impulse Noise Processing Unit */
-	status = write16(state, IQM_CF_CLP_VAL__A, 500);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_CF_DATATH__A, 1000);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_CF_BYPASSDET__A, 1);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_CF_DET_LCT__A, 0);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_CF_WND_LEN__A, 1);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_CF_PKDTH__A, 1);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_AF_INC_BYPASS__A, 1);
-	if (status < 0)
-		goto error;
-
-	/* turn on IQMAF. Must be done before setAgc**() */
-	status = SetIqmAf(state, true);
-	if (status < 0)
-		goto error;
-	status = write16(state, IQM_AF_START_LOCK__A, 0x01);
-	if (status < 0)
-		goto error;
-
-	/* IQM will not be reset from here, sync ADC and update/init AGC */
-	status = ADCSynchronization(state);
-	if (status < 0)
-		goto error;
-
-	/* Set the FSM step period */
-	status = write16(state, SCU_RAM_QAM_FSM_STEP_PERIOD__A, 2000);
-	if (status < 0)
-		goto error;
-
-	/* Halt SCU to enable safe non-atomic accesses */
-	status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD);
-	if (status < 0)
-		goto error;
-
-	/* No more resets of the IQM, current standard correctly set =>
-		now AGCs can be configured. */
-
-	status = InitAGC(state, true);
-	if (status < 0)
-		goto error;
-	status = SetPreSaw(state, &(state->m_qamPreSawCfg));
-	if (status < 0)
-		goto error;
-
-	/* Configure AGC's */
-	status = SetAgcRf(state, &(state->m_qamRfAgcCfg), true);
-	if (status < 0)
-		goto error;
-	status = SetAgcIf(state, &(state->m_qamIfAgcCfg), true);
-	if (status < 0)
-		goto error;
-
-	/* Activate SCU to enable SCU commands */
-	status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int WriteGPIO(struct drxk_state *state)
-{
-	int status;
-	u16 value = 0;
-
-	dprintk(1, "\n");
-	/* stop lock indicator process */
-	status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
-	if (status < 0)
-		goto error;
-
-	/*  Write magic word to enable pdr reg write               */
-	status = write16(state, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY);
-	if (status < 0)
-		goto error;
-
-	if (state->m_hasSAWSW) {
-		if (state->UIO_mask & 0x0001) { /* UIO-1 */
-			/* write to io pad configuration register - output mode */
-			status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg);
-			if (status < 0)
-				goto error;
-
-			/* use corresponding bit in io data output registar */
-			status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
-			if (status < 0)
-				goto error;
-			if ((state->m_GPIO & 0x0001) == 0)
-				value &= 0x7FFF;	/* write zero to 15th bit - 1st UIO */
-			else
-				value |= 0x8000;	/* write one to 15th bit - 1st UIO */
-			/* write back to io data output register */
-			status = write16(state, SIO_PDR_UIO_OUT_LO__A, value);
-			if (status < 0)
-				goto error;
-		}
-		if (state->UIO_mask & 0x0002) { /* UIO-2 */
-			/* write to io pad configuration register - output mode */
-			status = write16(state, SIO_PDR_SMA_RX_CFG__A, state->m_GPIOCfg);
-			if (status < 0)
-				goto error;
-
-			/* use corresponding bit in io data output registar */
-			status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
-			if (status < 0)
-				goto error;
-			if ((state->m_GPIO & 0x0002) == 0)
-				value &= 0xBFFF;	/* write zero to 14th bit - 2st UIO */
-			else
-				value |= 0x4000;	/* write one to 14th bit - 2st UIO */
-			/* write back to io data output register */
-			status = write16(state, SIO_PDR_UIO_OUT_LO__A, value);
-			if (status < 0)
-				goto error;
-		}
-		if (state->UIO_mask & 0x0004) { /* UIO-3 */
-			/* write to io pad configuration register - output mode */
-			status = write16(state, SIO_PDR_GPIO_CFG__A, state->m_GPIOCfg);
-			if (status < 0)
-				goto error;
-
-			/* use corresponding bit in io data output registar */
-			status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
-			if (status < 0)
-				goto error;
-			if ((state->m_GPIO & 0x0004) == 0)
-				value &= 0xFFFB;            /* write zero to 2nd bit - 3rd UIO */
-			else
-				value |= 0x0004;            /* write one to 2nd bit - 3rd UIO */
-			/* write back to io data output register */
-			status = write16(state, SIO_PDR_UIO_OUT_LO__A, value);
-			if (status < 0)
-				goto error;
-		}
-	}
-	/*  Write magic word to disable pdr reg write               */
-	status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int SwitchAntennaToQAM(struct drxk_state *state)
-{
-	int status = 0;
-	bool gpio_state;
-
-	dprintk(1, "\n");
-
-	if (!state->antenna_gpio)
-		return 0;
-
-	gpio_state = state->m_GPIO & state->antenna_gpio;
-
-	if (state->antenna_dvbt ^ gpio_state) {
-		/* Antenna is on DVB-T mode. Switch */
-		if (state->antenna_dvbt)
-			state->m_GPIO &= ~state->antenna_gpio;
-		else
-			state->m_GPIO |= state->antenna_gpio;
-		status = WriteGPIO(state);
-	}
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-static int SwitchAntennaToDVBT(struct drxk_state *state)
-{
-	int status = 0;
-	bool gpio_state;
-
-	dprintk(1, "\n");
-
-	if (!state->antenna_gpio)
-		return 0;
-
-	gpio_state = state->m_GPIO & state->antenna_gpio;
-
-	if (!(state->antenna_dvbt ^ gpio_state)) {
-		/* Antenna is on DVB-C mode. Switch */
-		if (state->antenna_dvbt)
-			state->m_GPIO |= state->antenna_gpio;
-		else
-			state->m_GPIO &= ~state->antenna_gpio;
-		status = WriteGPIO(state);
-	}
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	return status;
-}
-
-
-static int PowerDownDevice(struct drxk_state *state)
-{
-	/* Power down to requested mode */
-	/* Backup some register settings */
-	/* Set pins with possible pull-ups connected to them in input mode */
-	/* Analog power down */
-	/* ADC power down */
-	/* Power down device */
-	int status;
-
-	dprintk(1, "\n");
-	if (state->m_bPDownOpenBridge) {
-		/* Open I2C bridge before power down of DRXK */
-		status = ConfigureI2CBridge(state, true);
-		if (status < 0)
-			goto error;
-	}
-	/* driver 0.9.0 */
-	status = DVBTEnableOFDMTokenRing(state, false);
-	if (status < 0)
-		goto error;
-
-	status = write16(state, SIO_CC_PWD_MODE__A, SIO_CC_PWD_MODE_LEVEL_CLOCK);
-	if (status < 0)
-		goto error;
-	status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
-	if (status < 0)
-		goto error;
-	state->m_HICfgCtrl |= SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
-	status = HI_CfgCommand(state);
-error:
-	if (status < 0)
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-
-	return status;
-}
-
-static int init_drxk(struct drxk_state *state)
-{
-	int status = 0, n = 0;
-	enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
-	u16 driverVersion;
-
-	dprintk(1, "\n");
-	if ((state->m_DrxkState == DRXK_UNINITIALIZED)) {
-		drxk_i2c_lock(state);
-		status = PowerUpDevice(state);
-		if (status < 0)
-			goto error;
-		status = DRXX_Open(state);
-		if (status < 0)
-			goto error;
-		/* Soft reset of OFDM-, sys- and osc-clockdomain */
-		status = write16(state, SIO_CC_SOFT_RST__A, SIO_CC_SOFT_RST_OFDM__M | SIO_CC_SOFT_RST_SYS__M | SIO_CC_SOFT_RST_OSC__M);
-		if (status < 0)
-			goto error;
-		status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
-		if (status < 0)
-			goto error;
-		/* TODO is this needed, if yes how much delay in worst case scenario */
-		msleep(1);
-		state->m_DRXK_A3_PATCH_CODE = true;
-		status = GetDeviceCapabilities(state);
-		if (status < 0)
-			goto error;
-
-		/* Bridge delay, uses oscilator clock */
-		/* Delay = (delay (nano seconds) * oscclk (kHz))/ 1000 */
-		/* SDA brdige delay */
-		state->m_HICfgBridgeDelay =
-			(u16) ((state->m_oscClockFreq / 1000) *
-				HI_I2C_BRIDGE_DELAY) / 1000;
-		/* Clipping */
-		if (state->m_HICfgBridgeDelay >
-			SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M) {
-			state->m_HICfgBridgeDelay =
-				SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M;
-		}
-		/* SCL bridge delay, same as SDA for now */
-		state->m_HICfgBridgeDelay +=
-			state->m_HICfgBridgeDelay <<
-			SIO_HI_RA_RAM_PAR_3_CFG_DBL_SCL__B;
-
-		status = InitHI(state);
-		if (status < 0)
-			goto error;
-		/* disable various processes */
-#if NOA1ROM
-		if (!(state->m_DRXK_A1_ROM_CODE)
-			&& !(state->m_DRXK_A2_ROM_CODE))
-#endif
-		{
-			status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
-			if (status < 0)
-				goto error;
-		}
-
-		/* disable MPEG port */
-		status = MPEGTSDisable(state);
-		if (status < 0)
-			goto error;
-
-		/* Stop AUD and SCU */
-		status = write16(state, AUD_COMM_EXEC__A, AUD_COMM_EXEC_STOP);
-		if (status < 0)
-			goto error;
-		status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_STOP);
-		if (status < 0)
-			goto error;
-
-		/* enable token-ring bus through OFDM block for possible ucode upload */
-		status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_ON);
-		if (status < 0)
-			goto error;
-
-		/* include boot loader section */
-		status = write16(state, SIO_BL_COMM_EXEC__A, SIO_BL_COMM_EXEC_ACTIVE);
-		if (status < 0)
-			goto error;
-		status = BLChainCmd(state, 0, 6, 100);
-		if (status < 0)
-			goto error;
-
-		if (state->fw) {
-			status = DownloadMicrocode(state, state->fw->data,
-						   state->fw->size);
-			if (status < 0)
-				goto error;
-		}
-
-		/* disable token-ring bus through OFDM block for possible ucode upload */
-		status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_OFF);
-		if (status < 0)
-			goto error;
-
-		/* Run SCU for a little while to initialize microcode version numbers */
-		status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
-		if (status < 0)
-			goto error;
-		status = DRXX_Open(state);
-		if (status < 0)
-			goto error;
-		/* added for test */
-		msleep(30);
-
-		powerMode = DRXK_POWER_DOWN_OFDM;
-		status = CtrlPowerMode(state, &powerMode);
-		if (status < 0)
-			goto error;
-
-		/* Stamp driver version number in SCU data RAM in BCD code
-			Done to enable field application engineers to retreive drxdriver version
-			via I2C from SCU RAM.
-			Not using SCU command interface for SCU register access since no
-			microcode may be present.
-			*/
-		driverVersion =
-			(((DRXK_VERSION_MAJOR / 100) % 10) << 12) +
-			(((DRXK_VERSION_MAJOR / 10) % 10) << 8) +
-			((DRXK_VERSION_MAJOR % 10) << 4) +
-			(DRXK_VERSION_MINOR % 10);
-		status = write16(state, SCU_RAM_DRIVER_VER_HI__A, driverVersion);
-		if (status < 0)
-			goto error;
-		driverVersion =
-			(((DRXK_VERSION_PATCH / 1000) % 10) << 12) +
-			(((DRXK_VERSION_PATCH / 100) % 10) << 8) +
-			(((DRXK_VERSION_PATCH / 10) % 10) << 4) +
-			(DRXK_VERSION_PATCH % 10);
-		status = write16(state, SCU_RAM_DRIVER_VER_LO__A, driverVersion);
-		if (status < 0)
-			goto error;
-
-		printk(KERN_INFO "DRXK driver version %d.%d.%d\n",
-			DRXK_VERSION_MAJOR, DRXK_VERSION_MINOR,
-			DRXK_VERSION_PATCH);
-
-		/* Dirty fix of default values for ROM/PATCH microcode
-			Dirty because this fix makes it impossible to setup suitable values
-			before calling DRX_Open. This solution requires changes to RF AGC speed
-			to be done via the CTRL function after calling DRX_Open */
-
-		/* m_dvbtRfAgcCfg.speed = 3; */
-
-		/* Reset driver debug flags to 0 */
-		status = write16(state, SCU_RAM_DRIVER_DEBUG__A, 0);
-		if (status < 0)
-			goto error;
-		/* driver 0.9.0 */
-		/* Setup FEC OC:
-			NOTE: No more full FEC resets allowed afterwards!! */
-		status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_STOP);
-		if (status < 0)
-			goto error;
-		/* MPEGTS functions are still the same */
-		status = MPEGTSDtoInit(state);
-		if (status < 0)
-			goto error;
-		status = MPEGTSStop(state);
-		if (status < 0)
-			goto error;
-		status = MPEGTSConfigurePolarity(state);
-		if (status < 0)
-			goto error;
-		status = MPEGTSConfigurePins(state, state->m_enableMPEGOutput);
-		if (status < 0)
-			goto error;
-		/* added: configure GPIO */
-		status = WriteGPIO(state);
-		if (status < 0)
-			goto error;
-
-		state->m_DrxkState = DRXK_STOPPED;
-
-		if (state->m_bPowerDown) {
-			status = PowerDownDevice(state);
-			if (status < 0)
-				goto error;
-			state->m_DrxkState = DRXK_POWERED_DOWN;
-		} else
-			state->m_DrxkState = DRXK_STOPPED;
-
-		/* Initialize the supported delivery systems */
-		n = 0;
-		if (state->m_hasDVBC) {
-			state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_A;
-			state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_C;
-			strlcat(state->frontend.ops.info.name, " DVB-C",
-				sizeof(state->frontend.ops.info.name));
-		}
-		if (state->m_hasDVBT) {
-			state->frontend.ops.delsys[n++] = SYS_DVBT;
-			strlcat(state->frontend.ops.info.name, " DVB-T",
-				sizeof(state->frontend.ops.info.name));
-		}
-		drxk_i2c_unlock(state);
-	}
-error:
-	if (status < 0) {
-		state->m_DrxkState = DRXK_NO_DEV;
-		drxk_i2c_unlock(state);
-		printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
-	}
-
-	return status;
-}
-
-static void load_firmware_cb(const struct firmware *fw,
-			     void *context)
-{
-	struct drxk_state *state = context;
-
-	dprintk(1, ": %s\n", fw ? "firmware loaded" : "firmware not loaded");
-	if (!fw) {
-		printk(KERN_ERR
-		       "drxk: Could not load firmware file %s.\n",
-			state->microcode_name);
-		printk(KERN_INFO
-		       "drxk: Copy %s to your hotplug directory!\n",
-			state->microcode_name);
-		state->microcode_name = NULL;
-
-		/*
-		 * As firmware is now load asynchronous, it is not possible
-		 * anymore to fail at frontend attach. We might silently
-		 * return here, and hope that the driver won't crash.
-		 * We might also change all DVB callbacks to return -ENODEV
-		 * if the device is not initialized.
-		 * As the DRX-K devices have their own internal firmware,
-		 * let's just hope that it will match a firmware revision
-		 * compatible with this driver and proceed.
-		 */
-	}
-	state->fw = fw;
-
-	init_drxk(state);
-}
-
-static void drxk_release(struct dvb_frontend *fe)
-{
-	struct drxk_state *state = fe->demodulator_priv;
-
-	dprintk(1, "\n");
-	if (state->fw)
-		release_firmware(state->fw);
-
-	kfree(state);
-}
-
-static int drxk_sleep(struct dvb_frontend *fe)
-{
-	struct drxk_state *state = fe->demodulator_priv;
-
-	dprintk(1, "\n");
-
-	if (state->m_DrxkState == DRXK_NO_DEV)
-		return -ENODEV;
-	if (state->m_DrxkState == DRXK_UNINITIALIZED)
-		return 0;
-
-	ShutDown(state);
-	return 0;
-}
-
-static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct drxk_state *state = fe->demodulator_priv;
-
-	dprintk(1, ": %s\n", enable ? "enable" : "disable");
-
-	if (state->m_DrxkState == DRXK_NO_DEV)
-		return -ENODEV;
-
-	return ConfigureI2CBridge(state, enable ? true : false);
-}
-
-static int drxk_set_parameters(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	u32 delsys  = p->delivery_system, old_delsys;
-	struct drxk_state *state = fe->demodulator_priv;
-	u32 IF;
-
-	dprintk(1, "\n");
-
-	if (state->m_DrxkState == DRXK_NO_DEV)
-		return -ENODEV;
-
-	if (state->m_DrxkState == DRXK_UNINITIALIZED)
-		return -EAGAIN;
-
-	if (!fe->ops.tuner_ops.get_if_frequency) {
-		printk(KERN_ERR
-		       "drxk: Error: get_if_frequency() not defined at tuner. Can't work without it!\n");
-		return -EINVAL;
-	}
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (fe->ops.tuner_ops.set_params)
-		fe->ops.tuner_ops.set_params(fe);
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	old_delsys = state->props.delivery_system;
-	state->props = *p;
-
-	if (old_delsys != delsys) {
-		ShutDown(state);
-		switch (delsys) {
-		case SYS_DVBC_ANNEX_A:
-		case SYS_DVBC_ANNEX_C:
-			if (!state->m_hasDVBC)
-				return -EINVAL;
-			state->m_itut_annex_c = (delsys == SYS_DVBC_ANNEX_C) ? true : false;
-			if (state->m_itut_annex_c)
-				SetOperationMode(state, OM_QAM_ITU_C);
-			else
-				SetOperationMode(state, OM_QAM_ITU_A);
-			break;
-		case SYS_DVBT:
-			if (!state->m_hasDVBT)
-				return -EINVAL;
-			SetOperationMode(state, OM_DVBT);
-			break;
-		default:
-			return -EINVAL;
-		}
-	}
-
-	fe->ops.tuner_ops.get_if_frequency(fe, &IF);
-	Start(state, 0, IF);
-
-	/* printk(KERN_DEBUG "drxk: %s IF=%d done\n", __func__, IF); */
-
-	return 0;
-}
-
-static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct drxk_state *state = fe->demodulator_priv;
-	u32 stat;
-
-	dprintk(1, "\n");
-
-	if (state->m_DrxkState == DRXK_NO_DEV)
-		return -ENODEV;
-	if (state->m_DrxkState == DRXK_UNINITIALIZED)
-		return -EAGAIN;
-
-	*status = 0;
-	GetLockStatus(state, &stat, 0);
-	if (stat == MPEG_LOCK)
-		*status |= 0x1f;
-	if (stat == FEC_LOCK)
-		*status |= 0x0f;
-	if (stat == DEMOD_LOCK)
-		*status |= 0x07;
-	return 0;
-}
-
-static int drxk_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct drxk_state *state = fe->demodulator_priv;
-
-	dprintk(1, "\n");
-
-	if (state->m_DrxkState == DRXK_NO_DEV)
-		return -ENODEV;
-	if (state->m_DrxkState == DRXK_UNINITIALIZED)
-		return -EAGAIN;
-
-	*ber = 0;
-	return 0;
-}
-
-static int drxk_read_signal_strength(struct dvb_frontend *fe,
-				     u16 *strength)
-{
-	struct drxk_state *state = fe->demodulator_priv;
-	u32 val = 0;
-
-	dprintk(1, "\n");
-
-	if (state->m_DrxkState == DRXK_NO_DEV)
-		return -ENODEV;
-	if (state->m_DrxkState == DRXK_UNINITIALIZED)
-		return -EAGAIN;
-
-	ReadIFAgc(state, &val);
-	*strength = val & 0xffff;
-	return 0;
-}
-
-static int drxk_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct drxk_state *state = fe->demodulator_priv;
-	s32 snr2;
-
-	dprintk(1, "\n");
-
-	if (state->m_DrxkState == DRXK_NO_DEV)
-		return -ENODEV;
-	if (state->m_DrxkState == DRXK_UNINITIALIZED)
-		return -EAGAIN;
-
-	GetSignalToNoise(state, &snr2);
-	*snr = snr2 & 0xffff;
-	return 0;
-}
-
-static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct drxk_state *state = fe->demodulator_priv;
-	u16 err;
-
-	dprintk(1, "\n");
-
-	if (state->m_DrxkState == DRXK_NO_DEV)
-		return -ENODEV;
-	if (state->m_DrxkState == DRXK_UNINITIALIZED)
-		return -EAGAIN;
-
-	DVBTQAMGetAccPktErr(state, &err);
-	*ucblocks = (u32) err;
-	return 0;
-}
-
-static int drxk_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings
-				    *sets)
-{
-	struct drxk_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-
-	dprintk(1, "\n");
-
-	if (state->m_DrxkState == DRXK_NO_DEV)
-		return -ENODEV;
-	if (state->m_DrxkState == DRXK_UNINITIALIZED)
-		return -EAGAIN;
-
-	switch (p->delivery_system) {
-	case SYS_DVBC_ANNEX_A:
-	case SYS_DVBC_ANNEX_C:
-	case SYS_DVBT:
-		sets->min_delay_ms = 3000;
-		sets->max_drift = 0;
-		sets->step_size = 0;
-		return 0;
-	default:
-		return -EINVAL;
-	}
-}
-
-static struct dvb_frontend_ops drxk_ops = {
-	/* .delsys will be filled dynamically */
-	.info = {
-		.name = "DRXK",
-		.frequency_min = 47000000,
-		.frequency_max = 865000000,
-		 /* For DVB-C */
-		.symbol_rate_min = 870000,
-		.symbol_rate_max = 11700000,
-		/* For DVB-T */
-		.frequency_stepsize = 166667,
-
-		.caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
-			FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO |
-			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_MUTE_TS |
-			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER |
-			FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO
-	},
-
-	.release = drxk_release,
-	.sleep = drxk_sleep,
-	.i2c_gate_ctrl = drxk_gate_ctrl,
-
-	.set_frontend = drxk_set_parameters,
-	.get_tune_settings = drxk_get_tune_settings,
-
-	.read_status = drxk_read_status,
-	.read_ber = drxk_read_ber,
-	.read_signal_strength = drxk_read_signal_strength,
-	.read_snr = drxk_read_snr,
-	.read_ucblocks = drxk_read_ucblocks,
-};
-
-struct dvb_frontend *drxk_attach(const struct drxk_config *config,
-				 struct i2c_adapter *i2c)
-{
-	struct drxk_state *state = NULL;
-	u8 adr = config->adr;
-	int status;
-
-	dprintk(1, "\n");
-	state = kzalloc(sizeof(struct drxk_state), GFP_KERNEL);
-	if (!state)
-		return NULL;
-
-	state->i2c = i2c;
-	state->demod_address = adr;
-	state->single_master = config->single_master;
-	state->microcode_name = config->microcode_name;
-	state->qam_demod_parameter_count = config->qam_demod_parameter_count;
-	state->no_i2c_bridge = config->no_i2c_bridge;
-	state->antenna_gpio = config->antenna_gpio;
-	state->antenna_dvbt = config->antenna_dvbt;
-	state->m_ChunkSize = config->chunk_size;
-	state->enable_merr_cfg = config->enable_merr_cfg;
-
-	if (config->dynamic_clk) {
-		state->m_DVBTStaticCLK = 0;
-		state->m_DVBCStaticCLK = 0;
-	} else {
-		state->m_DVBTStaticCLK = 1;
-		state->m_DVBCStaticCLK = 1;
-	}
-
-
-	if (config->mpeg_out_clk_strength)
-		state->m_TSClockkStrength = config->mpeg_out_clk_strength & 0x07;
-	else
-		state->m_TSClockkStrength = 0x06;
-
-	if (config->parallel_ts)
-		state->m_enableParallel = true;
-	else
-		state->m_enableParallel = false;
-
-	/* NOTE: as more UIO bits will be used, add them to the mask */
-	state->UIO_mask = config->antenna_gpio;
-
-	/* Default gpio to DVB-C */
-	if (!state->antenna_dvbt && state->antenna_gpio)
-		state->m_GPIO |= state->antenna_gpio;
-	else
-		state->m_GPIO &= ~state->antenna_gpio;
-
-	mutex_init(&state->mutex);
-
-	memcpy(&state->frontend.ops, &drxk_ops, sizeof(drxk_ops));
-	state->frontend.demodulator_priv = state;
-
-	init_state(state);
-
-	/* Load firmware and initialize DRX-K */
-	if (state->microcode_name) {
-		status = request_firmware_nowait(THIS_MODULE, 1,
-					      state->microcode_name,
-					      state->i2c->dev.parent,
-					      GFP_KERNEL,
-					      state, load_firmware_cb);
-		if (status < 0) {
-			printk(KERN_ERR
-			"drxk: failed to request a firmware\n");
-			return NULL;
-		}
-	} else if (init_drxk(state) < 0)
-		goto error;
-
-	printk(KERN_INFO "drxk: frontend initialized.\n");
-	return &state->frontend;
-
-error:
-	printk(KERN_ERR "drxk: not found\n");
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(drxk_attach);
-
-MODULE_DESCRIPTION("DRX-K driver");
-MODULE_AUTHOR("Ralph Metzler");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/drxk_hard.h b/drivers/media/dvb/frontends/drxk_hard.h
deleted file mode 100644
index 6bb9fc4..0000000
--- a/drivers/media/dvb/frontends/drxk_hard.h
+++ /dev/null
@@ -1,364 +0,0 @@
-#include "drxk_map.h"
-
-#define DRXK_VERSION_MAJOR 0
-#define DRXK_VERSION_MINOR 9
-#define DRXK_VERSION_PATCH 4300
-
-#define HI_I2C_DELAY        42
-#define HI_I2C_BRIDGE_DELAY 350
-#define DRXK_MAX_RETRIES    100
-
-#define DRIVER_4400 1
-
-#define DRXX_JTAGID   0x039210D9
-#define DRXX_J_JTAGID 0x239310D9
-#define DRXX_K_JTAGID 0x039210D9
-
-#define DRX_UNKNOWN     254
-#define DRX_AUTO        255
-
-#define DRX_SCU_READY   0
-#define DRXK_MAX_WAITTIME (200)
-#define SCU_RESULT_OK      0
-#define SCU_RESULT_SIZE   -4
-#define SCU_RESULT_INVPAR -3
-#define SCU_RESULT_UNKSTD -2
-#define SCU_RESULT_UNKCMD -1
-
-#ifndef DRXK_OFDM_TR_SHUTDOWN_TIMEOUT
-#define DRXK_OFDM_TR_SHUTDOWN_TIMEOUT (200)
-#endif
-
-#define DRXK_8VSB_MPEG_BIT_RATE     19392658UL  /*bps*/
-#define DRXK_DVBT_MPEG_BIT_RATE     32000000UL  /*bps*/
-#define DRXK_QAM16_MPEG_BIT_RATE    27000000UL  /*bps*/
-#define DRXK_QAM32_MPEG_BIT_RATE    33000000UL  /*bps*/
-#define DRXK_QAM64_MPEG_BIT_RATE    40000000UL  /*bps*/
-#define DRXK_QAM128_MPEG_BIT_RATE   46000000UL  /*bps*/
-#define DRXK_QAM256_MPEG_BIT_RATE   52000000UL  /*bps*/
-#define DRXK_MAX_MPEG_BIT_RATE      52000000UL  /*bps*/
-
-#define   IQM_CF_OUT_ENA_OFDM__M                                            0x4
-#define     IQM_FS_ADJ_SEL_B_QAM                                            0x1
-#define     IQM_FS_ADJ_SEL_B_OFF                                            0x0
-#define     IQM_FS_ADJ_SEL_B_VSB                                            0x2
-#define     IQM_RC_ADJ_SEL_B_OFF                                            0x0
-#define     IQM_RC_ADJ_SEL_B_QAM                                            0x1
-#define     IQM_RC_ADJ_SEL_B_VSB                                            0x2
-
-enum OperationMode {
-	OM_NONE,
-	OM_QAM_ITU_A,
-	OM_QAM_ITU_B,
-	OM_QAM_ITU_C,
-	OM_DVBT
-};
-
-enum DRXPowerMode {
-	DRX_POWER_UP = 0,
-	DRX_POWER_MODE_1,
-	DRX_POWER_MODE_2,
-	DRX_POWER_MODE_3,
-	DRX_POWER_MODE_4,
-	DRX_POWER_MODE_5,
-	DRX_POWER_MODE_6,
-	DRX_POWER_MODE_7,
-	DRX_POWER_MODE_8,
-
-	DRX_POWER_MODE_9,
-	DRX_POWER_MODE_10,
-	DRX_POWER_MODE_11,
-	DRX_POWER_MODE_12,
-	DRX_POWER_MODE_13,
-	DRX_POWER_MODE_14,
-	DRX_POWER_MODE_15,
-	DRX_POWER_MODE_16,
-	DRX_POWER_DOWN = 255
-};
-
-
-/** /brief Intermediate power mode for DRXK, power down OFDM clock domain */
-#ifndef DRXK_POWER_DOWN_OFDM
-#define DRXK_POWER_DOWN_OFDM        DRX_POWER_MODE_1
-#endif
-
-/** /brief Intermediate power mode for DRXK, power down core (sysclk) */
-#ifndef DRXK_POWER_DOWN_CORE
-#define DRXK_POWER_DOWN_CORE        DRX_POWER_MODE_9
-#endif
-
-/** /brief Intermediate power mode for DRXK, power down pll (only osc runs) */
-#ifndef DRXK_POWER_DOWN_PLL
-#define DRXK_POWER_DOWN_PLL         DRX_POWER_MODE_10
-#endif
-
-
-enum AGC_CTRL_MODE { DRXK_AGC_CTRL_AUTO = 0, DRXK_AGC_CTRL_USER, DRXK_AGC_CTRL_OFF };
-enum EDrxkState {
-	DRXK_UNINITIALIZED = 0,
-	DRXK_STOPPED,
-	DRXK_DTV_STARTED,
-	DRXK_ATV_STARTED,
-	DRXK_POWERED_DOWN,
-	DRXK_NO_DEV			/* If drxk init failed */
-};
-
-enum EDrxkCoefArrayIndex {
-	DRXK_COEF_IDX_MN = 0,
-	DRXK_COEF_IDX_FM    ,
-	DRXK_COEF_IDX_L     ,
-	DRXK_COEF_IDX_LP    ,
-	DRXK_COEF_IDX_BG    ,
-	DRXK_COEF_IDX_DK    ,
-	DRXK_COEF_IDX_I     ,
-	DRXK_COEF_IDX_MAX
-};
-enum EDrxkSifAttenuation {
-	DRXK_SIF_ATTENUATION_0DB,
-	DRXK_SIF_ATTENUATION_3DB,
-	DRXK_SIF_ATTENUATION_6DB,
-	DRXK_SIF_ATTENUATION_9DB
-};
-enum EDrxkConstellation {
-	DRX_CONSTELLATION_BPSK = 0,
-	DRX_CONSTELLATION_QPSK,
-	DRX_CONSTELLATION_PSK8,
-	DRX_CONSTELLATION_QAM16,
-	DRX_CONSTELLATION_QAM32,
-	DRX_CONSTELLATION_QAM64,
-	DRX_CONSTELLATION_QAM128,
-	DRX_CONSTELLATION_QAM256,
-	DRX_CONSTELLATION_QAM512,
-	DRX_CONSTELLATION_QAM1024,
-	DRX_CONSTELLATION_UNKNOWN = DRX_UNKNOWN,
-	DRX_CONSTELLATION_AUTO    = DRX_AUTO
-};
-enum EDrxkInterleaveMode {
-	DRXK_QAM_I12_J17    = 16,
-	DRXK_QAM_I_UNKNOWN  = DRX_UNKNOWN
-};
-enum {
-	DRXK_SPIN_A1 = 0,
-	DRXK_SPIN_A2,
-	DRXK_SPIN_A3,
-	DRXK_SPIN_UNKNOWN
-};
-
-enum DRXKCfgDvbtSqiSpeed {
-	DRXK_DVBT_SQI_SPEED_FAST = 0,
-	DRXK_DVBT_SQI_SPEED_MEDIUM,
-	DRXK_DVBT_SQI_SPEED_SLOW,
-	DRXK_DVBT_SQI_SPEED_UNKNOWN = DRX_UNKNOWN
-} ;
-
-enum DRXFftmode_t {
-	DRX_FFTMODE_2K = 0,
-	DRX_FFTMODE_4K,
-	DRX_FFTMODE_8K,
-	DRX_FFTMODE_UNKNOWN = DRX_UNKNOWN,
-	DRX_FFTMODE_AUTO    = DRX_AUTO
-};
-
-enum DRXMPEGStrWidth_t {
-	DRX_MPEG_STR_WIDTH_1,
-	DRX_MPEG_STR_WIDTH_8
-};
-
-enum DRXQamLockRange_t {
-	DRX_QAM_LOCKRANGE_NORMAL,
-	DRX_QAM_LOCKRANGE_EXTENDED
-};
-
-struct DRXKCfgDvbtEchoThres_t {
-	u16             threshold;
-	enum DRXFftmode_t      fftMode;
-} ;
-
-struct SCfgAgc {
-	enum AGC_CTRL_MODE     ctrlMode;        /* off, user, auto */
-	u16            outputLevel;     /* range dependent on AGC */
-	u16            minOutputLevel;  /* range dependent on AGC */
-	u16            maxOutputLevel;  /* range dependent on AGC */
-	u16            speed;           /* range dependent on AGC */
-	u16            top;             /* rf-agc take over point */
-	u16            cutOffCurrent;   /* rf-agc is accelerated if output current
-					   is below cut-off current */
-	u16            IngainTgtMax;
-	u16            FastClipCtrlDelay;
-};
-
-struct SCfgPreSaw {
-	u16        reference; /* pre SAW reference value, range 0 .. 31 */
-	bool          usePreSaw; /* TRUE algorithms must use pre SAW sense */
-};
-
-struct DRXKOfdmScCmd_t {
-	u16 cmd;        /**< Command number */
-	u16 subcmd;     /**< Sub-command parameter*/
-	u16 param0;     /**< General purpous param */
-	u16 param1;     /**< General purpous param */
-	u16 param2;     /**< General purpous param */
-	u16 param3;     /**< General purpous param */
-	u16 param4;     /**< General purpous param */
-};
-
-struct drxk_state {
-	struct dvb_frontend frontend;
-	struct dtv_frontend_properties props;
-	struct device *dev;
-
-	struct i2c_adapter *i2c;
-	u8     demod_address;
-	void  *priv;
-
-	struct mutex mutex;
-
-	u32    m_Instance;           /**< Channel 1,2,3 or 4 */
-
-	int    m_ChunkSize;
-	u8 Chunk[256];
-
-	bool   m_hasLNA;
-	bool   m_hasDVBT;
-	bool   m_hasDVBC;
-	bool   m_hasAudio;
-	bool   m_hasATV;
-	bool   m_hasOOB;
-	bool   m_hasSAWSW;         /**< TRUE if mat_tx is available */
-	bool   m_hasGPIO1;         /**< TRUE if mat_rx is available */
-	bool   m_hasGPIO2;         /**< TRUE if GPIO is available */
-	bool   m_hasIRQN;          /**< TRUE if IRQN is available */
-	u16    m_oscClockFreq;
-	u16    m_HICfgTimingDiv;
-	u16    m_HICfgBridgeDelay;
-	u16    m_HICfgWakeUpKey;
-	u16    m_HICfgTimeout;
-	u16    m_HICfgCtrl;
-	s32    m_sysClockFreq;      /**< system clock frequency in kHz */
-
-	enum EDrxkState    m_DrxkState;      /**< State of Drxk (init,stopped,started) */
-	enum OperationMode m_OperationMode;  /**< digital standards */
-	struct SCfgAgc     m_vsbRfAgcCfg;    /**< settings for VSB RF-AGC */
-	struct SCfgAgc     m_vsbIfAgcCfg;    /**< settings for VSB IF-AGC */
-	u16                m_vsbPgaCfg;      /**< settings for VSB PGA */
-	struct SCfgPreSaw  m_vsbPreSawCfg;   /**< settings for pre SAW sense */
-	s32    m_Quality83percent;  /**< MER level (*0.1 dB) for 83% quality indication */
-	s32    m_Quality93percent;  /**< MER level (*0.1 dB) for 93% quality indication */
-	bool   m_smartAntInverted;
-	bool   m_bDebugEnableBridge;
-	bool   m_bPDownOpenBridge;  /**< only open DRXK bridge before power-down once it has been accessed */
-	bool   m_bPowerDown;        /**< Power down when not used */
-
-	u32    m_IqmFsRateOfs;      /**< frequency shift as written to DRXK register (28bit fixpoint) */
-
-	bool   m_enableMPEGOutput;  /**< If TRUE, enable MPEG output */
-	bool   m_insertRSByte;      /**< If TRUE, insert RS byte */
-	bool   m_enableParallel;    /**< If TRUE, parallel out otherwise serial */
-	bool   m_invertDATA;        /**< If TRUE, invert DATA signals */
-	bool   m_invertERR;         /**< If TRUE, invert ERR signal */
-	bool   m_invertSTR;         /**< If TRUE, invert STR signals */
-	bool   m_invertVAL;         /**< If TRUE, invert VAL signals */
-	bool   m_invertCLK;         /**< If TRUE, invert CLK signals */
-	bool   m_DVBCStaticCLK;
-	bool   m_DVBTStaticCLK;     /**< If TRUE, static MPEG clockrate will
-					 be used, otherwise clockrate will
-					 adapt to the bitrate of the TS */
-	u32    m_DVBTBitrate;
-	u32    m_DVBCBitrate;
-
-	u8     m_TSDataStrength;
-	u8     m_TSClockkStrength;
-
-	bool   m_itut_annex_c;      /* If true, uses ITU-T DVB-C Annex C, instead of Annex A */
-
-	enum DRXMPEGStrWidth_t  m_widthSTR;    /**< MPEG start width */
-	u32    m_mpegTsStaticBitrate;          /**< Maximum bitrate in b/s in case
-						    static clockrate is selected */
-
-	/* LARGE_INTEGER   m_StartTime; */     /**< Contains the time of the last demod start */
-	s32    m_MpegLockTimeOut;      /**< WaitForLockStatus Timeout (counts from start time) */
-	s32    m_DemodLockTimeOut;     /**< WaitForLockStatus Timeout (counts from start time) */
-
-	bool   m_disableTEIhandling;
-
-	bool   m_RfAgcPol;
-	bool   m_IfAgcPol;
-
-	struct SCfgAgc    m_atvRfAgcCfg;  /**< settings for ATV RF-AGC */
-	struct SCfgAgc    m_atvIfAgcCfg;  /**< settings for ATV IF-AGC */
-	struct SCfgPreSaw m_atvPreSawCfg; /**< settings for ATV pre SAW sense */
-	bool              m_phaseCorrectionBypass;
-	s16               m_atvTopVidPeak;
-	u16               m_atvTopNoiseTh;
-	enum EDrxkSifAttenuation m_sifAttenuation;
-	bool              m_enableCVBSOutput;
-	bool              m_enableSIFOutput;
-	bool              m_bMirrorFreqSpect;
-	enum EDrxkConstellation  m_Constellation; /**< Constellation type of the channel */
-	u32               m_CurrSymbolRate;       /**< Current QAM symbol rate */
-	struct SCfgAgc    m_qamRfAgcCfg;          /**< settings for QAM RF-AGC */
-	struct SCfgAgc    m_qamIfAgcCfg;          /**< settings for QAM IF-AGC */
-	u16               m_qamPgaCfg;            /**< settings for QAM PGA */
-	struct SCfgPreSaw m_qamPreSawCfg;         /**< settings for QAM pre SAW sense */
-	enum EDrxkInterleaveMode m_qamInterleaveMode; /**< QAM Interleave mode */
-	u16               m_fecRsPlen;
-	u16               m_fecRsPrescale;
-
-	enum DRXKCfgDvbtSqiSpeed m_sqiSpeed;
-
-	u16               m_GPIO;
-	u16               m_GPIOCfg;
-
-	struct SCfgAgc    m_dvbtRfAgcCfg;     /**< settings for QAM RF-AGC */
-	struct SCfgAgc    m_dvbtIfAgcCfg;     /**< settings for QAM IF-AGC */
-	struct SCfgPreSaw m_dvbtPreSawCfg;    /**< settings for QAM pre SAW sense */
-
-	u16               m_agcFastClipCtrlDelay;
-	bool              m_adcCompPassed;
-	u16               m_adcCompCoef[64];
-	u16               m_adcState;
-
-	u8               *m_microcode;
-	int               m_microcode_length;
-	bool              m_DRXK_A1_PATCH_CODE;
-	bool              m_DRXK_A1_ROM_CODE;
-	bool              m_DRXK_A2_ROM_CODE;
-	bool              m_DRXK_A3_ROM_CODE;
-	bool              m_DRXK_A2_PATCH_CODE;
-	bool              m_DRXK_A3_PATCH_CODE;
-
-	bool              m_rfmirror;
-	u8                m_deviceSpin;
-	u32               m_iqmRcRate;
-
-	enum DRXPowerMode m_currentPowerMode;
-
-	/* when true, avoids other devices to use the I2C bus */
-	bool		  drxk_i2c_exclusive_lock;
-
-	/*
-	 * Configurable parameters at the driver. They stores the values found
-	 * at struct drxk_config.
-	 */
-
-	u16	UIO_mask;	/* Bits used by UIO */
-
-	bool	enable_merr_cfg;
-	bool	single_master;
-	bool	no_i2c_bridge;
-	bool	antenna_dvbt;
-	u16	antenna_gpio;
-
-	/* Firmware */
-	const char *microcode_name;
-	struct completion fw_wait_load;
-	const struct firmware *fw;
-	int qam_demod_parameter_count;
-};
-
-#define NEVER_LOCK 0
-#define NOT_LOCKED 1
-#define DEMOD_LOCK 2
-#define FEC_LOCK   3
-#define MPEG_LOCK  4
-
diff --git a/drivers/media/dvb/frontends/drxk_map.h b/drivers/media/dvb/frontends/drxk_map.h
deleted file mode 100644
index 23e16c1..0000000
--- a/drivers/media/dvb/frontends/drxk_map.h
+++ /dev/null
@@ -1,451 +0,0 @@
-#define  AUD_COMM_EXEC__A                                                  0x1000000
-#define    AUD_COMM_EXEC_STOP                                              0x0
-#define  FEC_COMM_EXEC__A                                                  0x1C00000
-#define    FEC_COMM_EXEC_STOP                                              0x0
-#define    FEC_COMM_EXEC_ACTIVE                                            0x1
-#define  FEC_DI_COMM_EXEC__A                                               0x1C20000
-#define    FEC_DI_COMM_EXEC_STOP                                           0x0
-#define  FEC_DI_INPUT_CTL__A                                               0x1C20016
-#define  FEC_RS_COMM_EXEC__A                                               0x1C30000
-#define    FEC_RS_COMM_EXEC_STOP                                           0x0
-#define  FEC_RS_MEASUREMENT_PERIOD__A                                      0x1C30012
-#define  FEC_RS_MEASUREMENT_PRESCALE__A                                    0x1C30013
-#define  FEC_OC_MODE__A                                                    0x1C40011
-#define    FEC_OC_MODE_PARITY__M                                           0x1
-#define  FEC_OC_DTO_MODE__A                                                0x1C40014
-#define    FEC_OC_DTO_MODE_DYNAMIC__M                                      0x1
-#define    FEC_OC_DTO_MODE_OFFSET_ENABLE__M                                0x4
-#define  FEC_OC_DTO_PERIOD__A                                              0x1C40015
-#define  FEC_OC_DTO_BURST_LEN__A                                           0x1C40018
-#define  FEC_OC_FCT_MODE__A                                                0x1C4001A
-#define  FEC_OC_FCT_MODE__PRE                                              0x0
-#define    FEC_OC_FCT_MODE_RAT_ENA__M                                      0x1
-#define    FEC_OC_FCT_MODE_VIRT_ENA__M                                     0x2
-#define  FEC_OC_TMD_MODE__A                                                0x1C4001E
-#define  FEC_OC_TMD_COUNT__A                                               0x1C4001F
-#define  FEC_OC_TMD_HI_MARGIN__A                                           0x1C40020
-#define  FEC_OC_TMD_LO_MARGIN__A                                           0x1C40021
-#define  FEC_OC_TMD_INT_UPD_RATE__A                                        0x1C40023
-#define  FEC_OC_AVR_PARM_A__A                                              0x1C40026
-#define  FEC_OC_AVR_PARM_B__A                                              0x1C40027
-#define  FEC_OC_RCN_GAIN__A                                                0x1C4002E
-#define  FEC_OC_RCN_CTL_RATE_LO__A                                         0x1C40030
-#define  FEC_OC_RCN_CTL_STEP_LO__A                                         0x1C40032
-#define  FEC_OC_RCN_CTL_STEP_HI__A                                         0x1C40033
-#define  FEC_OC_SNC_MODE__A                                                0x1C40040
-#define    FEC_OC_SNC_MODE_SHUTDOWN__M                                     0x10
-#define  FEC_OC_SNC_LWM__A                                                 0x1C40041
-#define  FEC_OC_SNC_HWM__A                                                 0x1C40042
-#define  FEC_OC_SNC_UNLOCK__A                                              0x1C40043
-#define  FEC_OC_SNC_FAIL_PERIOD__A                                         0x1C40046
-#define  FEC_OC_IPR_MODE__A                                                0x1C40048
-#define    FEC_OC_IPR_MODE_SERIAL__M                                       0x1
-#define    FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__M                             0x4
-#define    FEC_OC_IPR_MODE_MVAL_DIS_PAR__M                                 0x10
-#define  FEC_OC_IPR_INVERT__A                                              0x1C40049
-#define    FEC_OC_IPR_INVERT_MD0__M                                        0x1
-#define    FEC_OC_IPR_INVERT_MD1__M                                        0x2
-#define    FEC_OC_IPR_INVERT_MD2__M                                        0x4
-#define    FEC_OC_IPR_INVERT_MD3__M                                        0x8
-#define    FEC_OC_IPR_INVERT_MD4__M                                        0x10
-#define    FEC_OC_IPR_INVERT_MD5__M                                        0x20
-#define    FEC_OC_IPR_INVERT_MD6__M                                        0x40
-#define    FEC_OC_IPR_INVERT_MD7__M                                        0x80
-#define    FEC_OC_IPR_INVERT_MERR__M                                       0x100
-#define    FEC_OC_IPR_INVERT_MSTRT__M                                      0x200
-#define    FEC_OC_IPR_INVERT_MVAL__M                                       0x400
-#define    FEC_OC_IPR_INVERT_MCLK__M                                       0x800
-#define  FEC_OC_OCR_INVERT__A                                              0x1C40052
-#define  IQM_COMM_EXEC__A                                                  0x1800000
-#define      IQM_COMM_EXEC_B_STOP                                          0x0
-#define      IQM_COMM_EXEC_B_ACTIVE                                        0x1
-#define  IQM_FS_RATE_OFS_LO__A                                             0x1820010
-#define  IQM_FS_ADJ_SEL__A                                                 0x1820014
-#define      IQM_FS_ADJ_SEL_B_OFF                                          0x0
-#define      IQM_FS_ADJ_SEL_B_QAM                                          0x1
-#define      IQM_FS_ADJ_SEL_B_VSB                                          0x2
-#define  IQM_FD_RATESEL__A                                                 0x1830010
-#define  IQM_RC_RATE_OFS_LO__A                                             0x1840010
-#define  IQM_RC_RATE_OFS_LO__W                                             16
-#define  IQM_RC_RATE_OFS_LO__M                                             0xFFFF
-#define  IQM_RC_RATE_OFS_HI__M                                             0xFF
-#define  IQM_RC_ADJ_SEL__A                                                 0x1840014
-#define      IQM_RC_ADJ_SEL_B_OFF                                          0x0
-#define      IQM_RC_ADJ_SEL_B_QAM                                          0x1
-#define      IQM_RC_ADJ_SEL_B_VSB                                          0x2
-#define  IQM_RC_STRETCH__A                                                 0x1840016
-#define  IQM_CF_COMM_INT_MSK__A                                            0x1860006
-#define  IQM_CF_SYMMETRIC__A                                               0x1860010
-#define  IQM_CF_MIDTAP__A                                                  0x1860011
-#define    IQM_CF_MIDTAP_RE__B                                             0
-#define    IQM_CF_MIDTAP_IM__B                                             1
-#define  IQM_CF_OUT_ENA__A                                                 0x1860012
-#define    IQM_CF_OUT_ENA_QAM__B                                           1
-#define    IQM_CF_OUT_ENA_OFDM__M                                          0x4
-#define  IQM_CF_ADJ_SEL__A                                                 0x1860013
-#define  IQM_CF_SCALE__A                                                   0x1860014
-#define  IQM_CF_SCALE_SH__A                                                0x1860015
-#define  IQM_CF_SCALE_SH__PRE                                              0x0
-#define  IQM_CF_POW_MEAS_LEN__A                                            0x1860017
-#define  IQM_CF_DS_ENA__A                                                  0x1860019
-#define  IQM_CF_TAP_RE0__A                                                 0x1860020
-#define  IQM_CF_TAP_IM0__A                                                 0x1860040
-#define  IQM_CF_CLP_VAL__A                                                 0x1860060
-#define  IQM_CF_DATATH__A                                                  0x1860061
-#define  IQM_CF_PKDTH__A                                                   0x1860062
-#define  IQM_CF_WND_LEN__A                                                 0x1860063
-#define  IQM_CF_DET_LCT__A                                                 0x1860064
-#define  IQM_CF_BYPASSDET__A                                               0x1860067
-#define  IQM_AF_COMM_EXEC__A                                               0x1870000
-#define    IQM_AF_COMM_EXEC_ACTIVE                                         0x1
-#define  IQM_AF_CLKNEG__A                                                  0x1870012
-#define    IQM_AF_CLKNEG_CLKNEGDATA__M                                     0x2
-#define      IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS                     0x0
-#define      IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_NEG                     0x2
-#define  IQM_AF_START_LOCK__A                                              0x187001B
-#define  IQM_AF_PHASE0__A                                                  0x187001C
-#define  IQM_AF_PHASE1__A                                                  0x187001D
-#define  IQM_AF_PHASE2__A                                                  0x187001E
-#define  IQM_AF_CLP_LEN__A                                                 0x1870023
-#define  IQM_AF_CLP_TH__A                                                  0x1870024
-#define  IQM_AF_SNS_LEN__A                                                 0x1870026
-#define  IQM_AF_AGC_IF__A                                                  0x1870028
-#define  IQM_AF_AGC_RF__A                                                  0x1870029
-#define  IQM_AF_PDREF__A                                                   0x187002B
-#define  IQM_AF_PDREF__M                                                   0x1F
-#define  IQM_AF_STDBY__A                                                   0x187002C
-#define      IQM_AF_STDBY_STDBY_ADC_STANDBY                                0x2
-#define      IQM_AF_STDBY_STDBY_AMP_STANDBY                                0x4
-#define      IQM_AF_STDBY_STDBY_PD_STANDBY                                 0x8
-#define      IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY                            0x10
-#define      IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY                            0x20
-#define  IQM_AF_AMUX__A                                                    0x187002D
-#define    IQM_AF_AMUX_SIGNAL2ADC                                          0x1
-#define  IQM_AF_UPD_SEL__A                                                 0x187002F
-#define  IQM_AF_INC_LCT__A                                                 0x1870034
-#define  IQM_AF_INC_BYPASS__A                                              0x1870036
-#define  OFDM_CP_COMM_EXEC__A                                              0x2800000
-#define    OFDM_CP_COMM_EXEC_STOP                                          0x0
-#define  OFDM_EC_SB_PRIOR__A                                               0x3410013
-#define    OFDM_EC_SB_PRIOR_HI                                             0x0
-#define    OFDM_EC_SB_PRIOR_LO                                             0x1
-#define  OFDM_EQ_TOP_TD_TPS_CONST__A                                       0x3010054
-#define  OFDM_EQ_TOP_TD_TPS_CONST__M                                       0x3
-#define    OFDM_EQ_TOP_TD_TPS_CONST_64QAM                                  0x2
-#define  OFDM_EQ_TOP_TD_TPS_CODE_HP__A                                     0x3010056
-#define  OFDM_EQ_TOP_TD_TPS_CODE_HP__M                                     0x7
-#define    OFDM_EQ_TOP_TD_TPS_CODE_LP_7_8                                  0x4
-#define  OFDM_EQ_TOP_TD_SQR_ERR_I__A                                       0x301005E
-#define  OFDM_EQ_TOP_TD_SQR_ERR_Q__A                                       0x301005F
-#define  OFDM_EQ_TOP_TD_SQR_ERR_EXP__A                                     0x3010060
-#define  OFDM_EQ_TOP_TD_REQ_SMB_CNT__A                                     0x3010061
-#define  OFDM_EQ_TOP_TD_TPS_PWR_OFS__A                                     0x3010062
-#define  OFDM_LC_COMM_EXEC__A                                              0x3800000
-#define    OFDM_LC_COMM_EXEC_STOP                                          0x0
-#define  OFDM_SC_COMM_EXEC__A                                              0x3C00000
-#define    OFDM_SC_COMM_EXEC_STOP                                          0x0
-#define  OFDM_SC_COMM_STATE__A                                             0x3C00001
-#define  OFDM_SC_RA_RAM_PARAM0__A                                          0x3C20040
-#define  OFDM_SC_RA_RAM_PARAM1__A                                          0x3C20041
-#define  OFDM_SC_RA_RAM_CMD_ADDR__A                                        0x3C20042
-#define  OFDM_SC_RA_RAM_CMD__A                                             0x3C20043
-#define    OFDM_SC_RA_RAM_CMD_NULL                                         0x0
-#define    OFDM_SC_RA_RAM_CMD_PROC_START                                   0x1
-#define    OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM                               0x3
-#define    OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM                                0x4
-#define    OFDM_SC_RA_RAM_CMD_GET_OP_PARAM                                 0x5
-#define    OFDM_SC_RA_RAM_CMD_USER_IO                                      0x6
-#define    OFDM_SC_RA_RAM_CMD_SET_TIMER                                    0x7
-#define    OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING                              0x8
-#define    OFDM_SC_RA_RAM_SW_EVENT_RUN_NMASK__M                            0x1
-#define    OFDM_SC_RA_RAM_LOCKTRACK_MIN                                    0x1
-#define  OFDM_SC_RA_RAM_OP_PARAM__A                                        0x3C20048
-#define    OFDM_SC_RA_RAM_OP_PARAM_MODE__M                                 0x3
-#define      OFDM_SC_RA_RAM_OP_PARAM_MODE_2K                               0x0
-#define      OFDM_SC_RA_RAM_OP_PARAM_MODE_8K                               0x1
-#define      OFDM_SC_RA_RAM_OP_PARAM_GUARD_32                              0x0
-#define      OFDM_SC_RA_RAM_OP_PARAM_GUARD_16                              0x4
-#define      OFDM_SC_RA_RAM_OP_PARAM_GUARD_8                               0x8
-#define      OFDM_SC_RA_RAM_OP_PARAM_GUARD_4                               0xC
-#define      OFDM_SC_RA_RAM_OP_PARAM_CONST_QPSK                            0x0
-#define      OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM16                           0x10
-#define      OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64                           0x20
-#define      OFDM_SC_RA_RAM_OP_PARAM_HIER_NO                               0x0
-#define      OFDM_SC_RA_RAM_OP_PARAM_HIER_A1                               0x40
-#define      OFDM_SC_RA_RAM_OP_PARAM_HIER_A2                               0x80
-#define      OFDM_SC_RA_RAM_OP_PARAM_HIER_A4                               0xC0
-#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_1_2                              0x0
-#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3                              0x200
-#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_3_4                              0x400
-#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_5_6                              0x600
-#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_7_8                              0x800
-#define      OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI                               0x0
-#define      OFDM_SC_RA_RAM_OP_PARAM_PRIO_LO                               0x1000
-#define    OFDM_SC_RA_RAM_OP_AUTO_MODE__M                                  0x1
-#define    OFDM_SC_RA_RAM_OP_AUTO_GUARD__M                                 0x2
-#define    OFDM_SC_RA_RAM_OP_AUTO_CONST__M                                 0x4
-#define    OFDM_SC_RA_RAM_OP_AUTO_HIER__M                                  0x8
-#define    OFDM_SC_RA_RAM_OP_AUTO_RATE__M                                  0x10
-#define  OFDM_SC_RA_RAM_LOCK__A                                            0x3C2004B
-#define    OFDM_SC_RA_RAM_LOCK_DEMOD__M                                    0x1
-#define    OFDM_SC_RA_RAM_LOCK_FEC__M                                      0x2
-#define    OFDM_SC_RA_RAM_LOCK_MPEG__M                                     0x4
-#define    OFDM_SC_RA_RAM_LOCK_NODVBT__M                                   0x8
-#define  OFDM_SC_RA_RAM_BE_OPT_DELAY__A                                    0x3C2004D
-#define  OFDM_SC_RA_RAM_BE_OPT_INIT_DELAY__A                               0x3C2004E
-#define  OFDM_SC_RA_RAM_ECHO_THRES__A                                      0x3C2004F
-#define    OFDM_SC_RA_RAM_ECHO_THRES_8K__B                                 0
-#define    OFDM_SC_RA_RAM_ECHO_THRES_8K__M                                 0xFF
-#define    OFDM_SC_RA_RAM_ECHO_THRES_2K__B                                 8
-#define    OFDM_SC_RA_RAM_ECHO_THRES_2K__M                                 0xFF00
-#define  OFDM_SC_RA_RAM_CONFIG__A                                          0x3C20050
-#define    OFDM_SC_RA_RAM_CONFIG_NE_FIX_ENABLE__M                          0x800
-#define  OFDM_SC_RA_RAM_FR_THRES_8K__A                                     0x3C2007D
-#define  OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A                             0x3C200E0
-#define  OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A                            0x3C200E1
-#define  OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A                             0x3C200E3
-#define  OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A                            0x3C200E4
-#define  OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A                                0x3C200F8
-#define  QAM_COMM_EXEC__A                                                  0x1400000
-#define    QAM_COMM_EXEC_STOP                                              0x0
-#define    QAM_COMM_EXEC_ACTIVE                                            0x1
-#define    QAM_TOP_ANNEX_A                                                 0x0
-#define    QAM_TOP_ANNEX_C                                                 0x2
-#define  QAM_SL_ERR_POWER__A                                               0x1430017
-#define  QAM_DQ_QUAL_FUN0__A                                               0x1440018
-#define  QAM_DQ_QUAL_FUN1__A                                               0x1440019
-#define  QAM_DQ_QUAL_FUN2__A                                               0x144001A
-#define  QAM_DQ_QUAL_FUN3__A                                               0x144001B
-#define  QAM_DQ_QUAL_FUN4__A                                               0x144001C
-#define  QAM_DQ_QUAL_FUN5__A                                               0x144001D
-#define  QAM_LC_MODE__A                                                    0x1450010
-#define  QAM_LC_QUAL_TAB0__A                                               0x1450018
-#define  QAM_LC_QUAL_TAB1__A                                               0x1450019
-#define  QAM_LC_QUAL_TAB2__A                                               0x145001A
-#define  QAM_LC_QUAL_TAB3__A                                               0x145001B
-#define  QAM_LC_QUAL_TAB4__A                                               0x145001C
-#define  QAM_LC_QUAL_TAB5__A                                               0x145001D
-#define  QAM_LC_QUAL_TAB6__A                                               0x145001E
-#define  QAM_LC_QUAL_TAB8__A                                               0x145001F
-#define  QAM_LC_QUAL_TAB9__A                                               0x1450020
-#define  QAM_LC_QUAL_TAB10__A                                              0x1450021
-#define  QAM_LC_QUAL_TAB12__A                                              0x1450022
-#define  QAM_LC_QUAL_TAB15__A                                              0x1450023
-#define  QAM_LC_QUAL_TAB16__A                                              0x1450024
-#define  QAM_LC_QUAL_TAB20__A                                              0x1450025
-#define  QAM_LC_QUAL_TAB25__A                                              0x1450026
-#define  QAM_LC_LPF_FACTORP__A                                             0x1450028
-#define  QAM_LC_LPF_FACTORI__A                                             0x1450029
-#define  QAM_LC_RATE_LIMIT__A                                              0x145002A
-#define  QAM_LC_SYMBOL_FREQ__A                                             0x145002B
-#define  QAM_SY_TIMEOUT__A                                                 0x1470011
-#define  QAM_SY_TIMEOUT__PRE                                               0x3A98
-#define  QAM_SY_SYNC_LWM__A                                                0x1470012
-#define  QAM_SY_SYNC_AWM__A                                                0x1470013
-#define  QAM_SY_SYNC_HWM__A                                                0x1470014
-#define  QAM_SY_SP_INV__A                                                  0x1470017
-#define    QAM_SY_SP_INV_SPECTRUM_INV_DIS                                  0x0
-#define  SCU_COMM_EXEC__A                                                  0x800000
-#define    SCU_COMM_EXEC_STOP                                              0x0
-#define    SCU_COMM_EXEC_ACTIVE                                            0x1
-#define    SCU_COMM_EXEC_HOLD                                              0x2
-#define  SCU_RAM_DRIVER_DEBUG__A                                           0x831EBF
-#define  SCU_RAM_QAM_FSM_STEP_PERIOD__A                                    0x831EC4
-#define  SCU_RAM_GPIO__A                                                   0x831EC7
-#define      SCU_RAM_GPIO_HW_LOCK_IND_DISABLE                              0x0
-#define  SCU_RAM_AGC_CLP_CTRL_MODE__A                                      0x831EC8
-#define  SCU_RAM_FEC_ACCUM_PKT_FAILURES__A                                 0x831ECB
-#define  SCU_RAM_FEC_PRE_RS_BER_FILTER_SH__A                               0x831F05
-#define  SCU_RAM_AGC_FAST_SNS_CTRL_DELAY__A                                0x831F15
-#define  SCU_RAM_AGC_KI_CYCLEN__A                                          0x831F17
-#define  SCU_RAM_AGC_SNS_CYCLEN__A                                         0x831F18
-#define  SCU_RAM_AGC_RF_SNS_DEV_MAX__A                                     0x831F19
-#define  SCU_RAM_AGC_RF_SNS_DEV_MIN__A                                     0x831F1A
-#define  SCU_RAM_AGC_RF_MAX__A                                             0x831F1B
-#define  SCU_RAM_AGC_CONFIG__A                                             0x831F24
-#define    SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M                            0x1
-#define    SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M                            0x2
-#define    SCU_RAM_AGC_CONFIG_INV_IF_POL__M                                0x100
-#define    SCU_RAM_AGC_CONFIG_INV_RF_POL__M                                0x200
-#define  SCU_RAM_AGC_KI__A                                                 0x831F25
-#define    SCU_RAM_AGC_KI_RF__B                                            4
-#define    SCU_RAM_AGC_KI_RF__M                                            0xF0
-#define    SCU_RAM_AGC_KI_IF__B                                            8
-#define    SCU_RAM_AGC_KI_IF__M                                            0xF00
-#define  SCU_RAM_AGC_KI_RED__A                                             0x831F26
-#define    SCU_RAM_AGC_KI_RED_RAGC_RED__B                                  2
-#define    SCU_RAM_AGC_KI_RED_RAGC_RED__M                                  0xC
-#define    SCU_RAM_AGC_KI_RED_IAGC_RED__B                                  4
-#define    SCU_RAM_AGC_KI_RED_IAGC_RED__M                                  0x30
-#define  SCU_RAM_AGC_KI_INNERGAIN_MIN__A                                   0x831F27
-#define  SCU_RAM_AGC_KI_MINGAIN__A                                         0x831F28
-#define  SCU_RAM_AGC_KI_MAXGAIN__A                                         0x831F29
-#define  SCU_RAM_AGC_KI_MAXMINGAIN_TH__A                                   0x831F2A
-#define  SCU_RAM_AGC_KI_MIN__A                                             0x831F2B
-#define  SCU_RAM_AGC_KI_MAX__A                                             0x831F2C
-#define  SCU_RAM_AGC_CLP_SUM__A                                            0x831F2D
-#define  SCU_RAM_AGC_CLP_SUM_MIN__A                                        0x831F2E
-#define  SCU_RAM_AGC_CLP_SUM_MAX__A                                        0x831F2F
-#define  SCU_RAM_AGC_CLP_CYCLEN__A                                         0x831F30
-#define  SCU_RAM_AGC_CLP_CYCCNT__A                                         0x831F31
-#define  SCU_RAM_AGC_CLP_DIR_TO__A                                         0x831F32
-#define  SCU_RAM_AGC_CLP_DIR_WD__A                                         0x831F33
-#define  SCU_RAM_AGC_CLP_DIR_STP__A                                        0x831F34
-#define  SCU_RAM_AGC_SNS_SUM__A                                            0x831F35
-#define  SCU_RAM_AGC_SNS_SUM_MIN__A                                        0x831F36
-#define  SCU_RAM_AGC_SNS_SUM_MAX__A                                        0x831F37
-#define  SCU_RAM_AGC_SNS_CYCCNT__A                                         0x831F38
-#define  SCU_RAM_AGC_SNS_DIR_TO__A                                         0x831F39
-#define  SCU_RAM_AGC_SNS_DIR_WD__A                                         0x831F3A
-#define  SCU_RAM_AGC_SNS_DIR_STP__A                                        0x831F3B
-#define  SCU_RAM_AGC_INGAIN_TGT__A                                         0x831F3D
-#define  SCU_RAM_AGC_INGAIN_TGT_MIN__A                                     0x831F3E
-#define  SCU_RAM_AGC_INGAIN_TGT_MAX__A                                     0x831F3F
-#define  SCU_RAM_AGC_IF_IACCU_HI__A                                        0x831F40
-#define  SCU_RAM_AGC_IF_IACCU_LO__A                                        0x831F41
-#define  SCU_RAM_AGC_IF_IACCU_HI_TGT__A                                    0x831F42
-#define  SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__A                                0x831F43
-#define  SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A                                0x831F44
-#define  SCU_RAM_AGC_RF_IACCU_HI__A                                        0x831F45
-#define  SCU_RAM_AGC_RF_IACCU_LO__A                                        0x831F46
-#define  SCU_RAM_AGC_RF_IACCU_HI_CO__A                                     0x831F47
-#define  SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A                                 0x831F84
-#define  SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A                                0x831F85
-#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A                                  0x831F86
-#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A                                  0x831F87
-#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A                                  0x831F88
-#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A                                  0x831F89
-#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A                                  0x831F8A
-#define  SCU_RAM_QAM_FSM_RTH__A                                            0x831F8E
-#define  SCU_RAM_QAM_FSM_FTH__A                                            0x831F8F
-#define  SCU_RAM_QAM_FSM_PTH__A                                            0x831F90
-#define  SCU_RAM_QAM_FSM_MTH__A                                            0x831F91
-#define  SCU_RAM_QAM_FSM_CTH__A                                            0x831F92
-#define  SCU_RAM_QAM_FSM_QTH__A                                            0x831F93
-#define  SCU_RAM_QAM_FSM_RATE_LIM__A                                       0x831F94
-#define  SCU_RAM_QAM_FSM_FREQ_LIM__A                                       0x831F95
-#define  SCU_RAM_QAM_FSM_COUNT_LIM__A                                      0x831F96
-#define  SCU_RAM_QAM_LC_CA_COARSE__A                                       0x831F97
-#define  SCU_RAM_QAM_LC_CA_FINE__A                                         0x831F99
-#define  SCU_RAM_QAM_LC_CP_COARSE__A                                       0x831F9A
-#define  SCU_RAM_QAM_LC_CP_MEDIUM__A                                       0x831F9B
-#define  SCU_RAM_QAM_LC_CP_FINE__A                                         0x831F9C
-#define  SCU_RAM_QAM_LC_CI_COARSE__A                                       0x831F9D
-#define  SCU_RAM_QAM_LC_CI_MEDIUM__A                                       0x831F9E
-#define  SCU_RAM_QAM_LC_CI_FINE__A                                         0x831F9F
-#define  SCU_RAM_QAM_LC_EP_COARSE__A                                       0x831FA0
-#define  SCU_RAM_QAM_LC_EP_MEDIUM__A                                       0x831FA1
-#define  SCU_RAM_QAM_LC_EP_FINE__A                                         0x831FA2
-#define  SCU_RAM_QAM_LC_EI_COARSE__A                                       0x831FA3
-#define  SCU_RAM_QAM_LC_EI_MEDIUM__A                                       0x831FA4
-#define  SCU_RAM_QAM_LC_EI_FINE__A                                         0x831FA5
-#define  SCU_RAM_QAM_LC_CF_COARSE__A                                       0x831FA6
-#define  SCU_RAM_QAM_LC_CF_MEDIUM__A                                       0x831FA7
-#define  SCU_RAM_QAM_LC_CF_FINE__A                                         0x831FA8
-#define  SCU_RAM_QAM_LC_CF1_COARSE__A                                      0x831FA9
-#define  SCU_RAM_QAM_LC_CF1_MEDIUM__A                                      0x831FAA
-#define  SCU_RAM_QAM_LC_CF1_FINE__A                                        0x831FAB
-#define  SCU_RAM_QAM_SL_SIG_POWER__A                                       0x831FAC
-#define  SCU_RAM_QAM_EQ_CMA_RAD0__A                                        0x831FAD
-#define  SCU_RAM_QAM_EQ_CMA_RAD1__A                                        0x831FAE
-#define  SCU_RAM_QAM_EQ_CMA_RAD2__A                                        0x831FAF
-#define  SCU_RAM_QAM_EQ_CMA_RAD3__A                                        0x831FB0
-#define  SCU_RAM_QAM_EQ_CMA_RAD4__A                                        0x831FB1
-#define  SCU_RAM_QAM_EQ_CMA_RAD5__A                                        0x831FB2
-#define      SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED                        0x4000
-#define      SCU_RAM_QAM_LOCKED_LOCKED_LOCKED                              0x8000
-#define      SCU_RAM_QAM_LOCKED_LOCKED_NEVER_LOCK                          0xC000
-#define  SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A                                0x831FEA
-#define  SCU_RAM_DRIVER_VER_HI__A                                          0x831FEB
-#define  SCU_RAM_DRIVER_VER_LO__A                                          0x831FEC
-#define  SCU_RAM_PARAM_15__A                                               0x831FED
-#define  SCU_RAM_PARAM_0__A                                                0x831FFC
-#define  SCU_RAM_COMMAND__A                                                0x831FFD
-#define    SCU_RAM_COMMAND_CMD_DEMOD_RESET                                 0x1
-#define    SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV                               0x2
-#define    SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM                             0x3
-#define    SCU_RAM_COMMAND_CMD_DEMOD_START                                 0x4
-#define    SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK                              0x5
-#define    SCU_RAM_COMMAND_CMD_DEMOD_STOP                                  0x9
-#define      SCU_RAM_COMMAND_STANDARD_QAM                                  0x200
-#define      SCU_RAM_COMMAND_STANDARD_OFDM                                 0x400
-#define  SIO_TOP_COMM_KEY__A                                               0x41000F
-#define    SIO_TOP_COMM_KEY_KEY                                            0xFABA
-#define  SIO_TOP_JTAGID_LO__A                                              0x410012
-#define  SIO_HI_RA_RAM_RES__A                                              0x420031
-#define  SIO_HI_RA_RAM_CMD__A                                              0x420032
-#define    SIO_HI_RA_RAM_CMD_RESET                                         0x2
-#define    SIO_HI_RA_RAM_CMD_CONFIG                                        0x3
-#define    SIO_HI_RA_RAM_CMD_BRDCTRL                                       0x7
-#define  SIO_HI_RA_RAM_PAR_1__A                                            0x420033
-#define      SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY                              0x3945
-#define  SIO_HI_RA_RAM_PAR_2__A                                            0x420034
-#define    SIO_HI_RA_RAM_PAR_2_CFG_DIV__M                                  0x7F
-#define      SIO_HI_RA_RAM_PAR_2_BRD_CFG_OPEN                              0x0
-#define      SIO_HI_RA_RAM_PAR_2_BRD_CFG_CLOSED                            0x4
-#define  SIO_HI_RA_RAM_PAR_3__A                                            0x420035
-#define    SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M                              0x7F
-#define    SIO_HI_RA_RAM_PAR_3_CFG_DBL_SCL__B                              7
-#define      SIO_HI_RA_RAM_PAR_3_ACP_RW_READ                               0x0
-#define      SIO_HI_RA_RAM_PAR_3_ACP_RW_WRITE                              0x8
-#define  SIO_HI_RA_RAM_PAR_4__A                                            0x420036
-#define  SIO_HI_RA_RAM_PAR_5__A                                            0x420037
-#define      SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE                            0x1
-#define    SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M                                0x8
-#define      SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ                             0x8
-#define  SIO_HI_RA_RAM_PAR_6__A                                            0x420038
-#define  SIO_CC_PLL_LOCK__A                                                0x450012
-#define  SIO_CC_PWD_MODE__A                                                0x450015
-#define      SIO_CC_PWD_MODE_LEVEL_NONE                                    0x0
-#define      SIO_CC_PWD_MODE_LEVEL_OFDM                                    0x1
-#define      SIO_CC_PWD_MODE_LEVEL_CLOCK                                   0x2
-#define      SIO_CC_PWD_MODE_LEVEL_PLL                                     0x3
-#define      SIO_CC_PWD_MODE_LEVEL_OSC                                     0x4
-#define  SIO_CC_SOFT_RST__A                                                0x450016
-#define    SIO_CC_SOFT_RST_OFDM__M                                         0x1
-#define    SIO_CC_SOFT_RST_SYS__M                                          0x2
-#define    SIO_CC_SOFT_RST_OSC__M                                          0x4
-#define  SIO_CC_UPDATE__A                                                  0x450017
-#define    SIO_CC_UPDATE_KEY                                               0xFABA
-#define  SIO_OFDM_SH_OFDM_RING_ENABLE__A                                   0x470010
-#define    SIO_OFDM_SH_OFDM_RING_ENABLE_OFF                                0x0
-#define    SIO_OFDM_SH_OFDM_RING_ENABLE_ON                                 0x1
-#define  SIO_OFDM_SH_OFDM_RING_STATUS__A                                   0x470012
-#define    SIO_OFDM_SH_OFDM_RING_STATUS_DOWN                               0x0
-#define    SIO_OFDM_SH_OFDM_RING_STATUS_ENABLED                            0x1
-#define  SIO_BL_COMM_EXEC__A                                               0x480000
-#define    SIO_BL_COMM_EXEC_ACTIVE                                         0x1
-#define  SIO_BL_STATUS__A                                                  0x480010
-#define  SIO_BL_MODE__A                                                    0x480011
-#define    SIO_BL_MODE_DIRECT                                              0x0
-#define    SIO_BL_MODE_CHAIN                                               0x1
-#define  SIO_BL_ENABLE__A                                                  0x480012
-#define    SIO_BL_ENABLE_ON                                                0x1
-#define  SIO_BL_TGT_HDR__A                                                 0x480014
-#define  SIO_BL_TGT_ADDR__A                                                0x480015
-#define  SIO_BL_SRC_ADDR__A                                                0x480016
-#define  SIO_BL_SRC_LEN__A                                                 0x480017
-#define  SIO_BL_CHAIN_ADDR__A                                              0x480018
-#define  SIO_BL_CHAIN_LEN__A                                               0x480019
-#define  SIO_PDR_MON_CFG__A                                                0x7F0010
-#define  SIO_PDR_UIO_IN_HI__A                                              0x7F0015
-#define  SIO_PDR_UIO_OUT_LO__A                                             0x7F0016
-#define  SIO_PDR_OHW_CFG__A                                                0x7F001F
-#define    SIO_PDR_OHW_CFG_FREF_SEL__M                                     0x3
-#define  SIO_PDR_GPIO_CFG__A                                               0x7F0021
-#define  SIO_PDR_MSTRT_CFG__A                                              0x7F0025
-#define  SIO_PDR_MERR_CFG__A                                               0x7F0026
-#define  SIO_PDR_MCLK_CFG__A                                               0x7F0028
-#define    SIO_PDR_MCLK_CFG_DRIVE__B                                       3
-#define  SIO_PDR_MVAL_CFG__A                                               0x7F0029
-#define  SIO_PDR_MD0_CFG__A                                                0x7F002A
-#define    SIO_PDR_MD0_CFG_DRIVE__B                                        3
-#define  SIO_PDR_MD1_CFG__A                                                0x7F002B
-#define  SIO_PDR_MD2_CFG__A                                                0x7F002C
-#define  SIO_PDR_MD3_CFG__A                                                0x7F002D
-#define  SIO_PDR_MD4_CFG__A                                                0x7F002F
-#define  SIO_PDR_MD5_CFG__A                                                0x7F0030
-#define  SIO_PDR_MD6_CFG__A                                                0x7F0031
-#define  SIO_PDR_MD7_CFG__A                                                0x7F0032
-#define  SIO_PDR_SMA_RX_CFG__A                                             0x7F0037
-#define  SIO_PDR_SMA_TX_CFG__A                                             0x7F0038
diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c
deleted file mode 100644
index 4c8ac26..0000000
--- a/drivers/media/dvb/frontends/ds3000.c
+++ /dev/null
@@ -1,1312 +0,0 @@
-/*
-    Montage Technology DS3000/TS2020 - DVBS/S2 Demodulator/Tuner driver
-    Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
-
-    Copyright (C) 2009 TurboSight.com
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/firmware.h>
-
-#include "dvb_frontend.h"
-#include "ds3000.h"
-
-static int debug;
-
-#define dprintk(args...) \
-	do { \
-		if (debug) \
-			printk(args); \
-	} while (0)
-
-/* as of March 2009 current DS3000 firmware version is 1.78 */
-/* DS3000 FW v1.78 MD5: a32d17910c4f370073f9346e71d34b80 */
-#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds3000.fw"
-
-#define DS3000_SAMPLE_RATE 96000 /* in kHz */
-#define DS3000_XTAL_FREQ   27000 /* in kHz */
-
-/* Register values to initialise the demod in DVB-S mode */
-static u8 ds3000_dvbs_init_tab[] = {
-	0x23, 0x05,
-	0x08, 0x03,
-	0x0c, 0x00,
-	0x21, 0x54,
-	0x25, 0x82,
-	0x27, 0x31,
-	0x30, 0x08,
-	0x31, 0x40,
-	0x32, 0x32,
-	0x33, 0x35,
-	0x35, 0xff,
-	0x3a, 0x00,
-	0x37, 0x10,
-	0x38, 0x10,
-	0x39, 0x02,
-	0x42, 0x60,
-	0x4a, 0x40,
-	0x4b, 0x04,
-	0x4d, 0x91,
-	0x5d, 0xc8,
-	0x50, 0x77,
-	0x51, 0x77,
-	0x52, 0x36,
-	0x53, 0x36,
-	0x56, 0x01,
-	0x63, 0x43,
-	0x64, 0x30,
-	0x65, 0x40,
-	0x68, 0x26,
-	0x69, 0x4c,
-	0x70, 0x20,
-	0x71, 0x70,
-	0x72, 0x04,
-	0x73, 0x00,
-	0x70, 0x40,
-	0x71, 0x70,
-	0x72, 0x04,
-	0x73, 0x00,
-	0x70, 0x60,
-	0x71, 0x70,
-	0x72, 0x04,
-	0x73, 0x00,
-	0x70, 0x80,
-	0x71, 0x70,
-	0x72, 0x04,
-	0x73, 0x00,
-	0x70, 0xa0,
-	0x71, 0x70,
-	0x72, 0x04,
-	0x73, 0x00,
-	0x70, 0x1f,
-	0x76, 0x00,
-	0x77, 0xd1,
-	0x78, 0x0c,
-	0x79, 0x80,
-	0x7f, 0x04,
-	0x7c, 0x00,
-	0x80, 0x86,
-	0x81, 0xa6,
-	0x85, 0x04,
-	0xcd, 0xf4,
-	0x90, 0x33,
-	0xa0, 0x44,
-	0xc0, 0x18,
-	0xc3, 0x10,
-	0xc4, 0x08,
-	0xc5, 0x80,
-	0xc6, 0x80,
-	0xc7, 0x0a,
-	0xc8, 0x1a,
-	0xc9, 0x80,
-	0xfe, 0x92,
-	0xe0, 0xf8,
-	0xe6, 0x8b,
-	0xd0, 0x40,
-	0xf8, 0x20,
-	0xfa, 0x0f,
-	0xfd, 0x20,
-	0xad, 0x20,
-	0xae, 0x07,
-	0xb8, 0x00,
-};
-
-/* Register values to initialise the demod in DVB-S2 mode */
-static u8 ds3000_dvbs2_init_tab[] = {
-	0x23, 0x0f,
-	0x08, 0x07,
-	0x0c, 0x00,
-	0x21, 0x54,
-	0x25, 0x82,
-	0x27, 0x31,
-	0x30, 0x08,
-	0x31, 0x32,
-	0x32, 0x32,
-	0x33, 0x35,
-	0x35, 0xff,
-	0x3a, 0x00,
-	0x37, 0x10,
-	0x38, 0x10,
-	0x39, 0x02,
-	0x42, 0x60,
-	0x4a, 0x80,
-	0x4b, 0x04,
-	0x4d, 0x81,
-	0x5d, 0x88,
-	0x50, 0x36,
-	0x51, 0x36,
-	0x52, 0x36,
-	0x53, 0x36,
-	0x63, 0x60,
-	0x64, 0x10,
-	0x65, 0x10,
-	0x68, 0x04,
-	0x69, 0x29,
-	0x70, 0x20,
-	0x71, 0x70,
-	0x72, 0x04,
-	0x73, 0x00,
-	0x70, 0x40,
-	0x71, 0x70,
-	0x72, 0x04,
-	0x73, 0x00,
-	0x70, 0x60,
-	0x71, 0x70,
-	0x72, 0x04,
-	0x73, 0x00,
-	0x70, 0x80,
-	0x71, 0x70,
-	0x72, 0x04,
-	0x73, 0x00,
-	0x70, 0xa0,
-	0x71, 0x70,
-	0x72, 0x04,
-	0x73, 0x00,
-	0x70, 0x1f,
-	0xa0, 0x44,
-	0xc0, 0x08,
-	0xc1, 0x10,
-	0xc2, 0x08,
-	0xc3, 0x10,
-	0xc4, 0x08,
-	0xc5, 0xf0,
-	0xc6, 0xf0,
-	0xc7, 0x0a,
-	0xc8, 0x1a,
-	0xc9, 0x80,
-	0xca, 0x23,
-	0xcb, 0x24,
-	0xce, 0x74,
-	0x90, 0x03,
-	0x76, 0x80,
-	0x77, 0x42,
-	0x78, 0x0a,
-	0x79, 0x80,
-	0xad, 0x40,
-	0xae, 0x07,
-	0x7f, 0xd4,
-	0x7c, 0x00,
-	0x80, 0xa8,
-	0x81, 0xda,
-	0x7c, 0x01,
-	0x80, 0xda,
-	0x81, 0xec,
-	0x7c, 0x02,
-	0x80, 0xca,
-	0x81, 0xeb,
-	0x7c, 0x03,
-	0x80, 0xba,
-	0x81, 0xdb,
-	0x85, 0x08,
-	0x86, 0x00,
-	0x87, 0x02,
-	0x89, 0x80,
-	0x8b, 0x44,
-	0x8c, 0xaa,
-	0x8a, 0x10,
-	0xba, 0x00,
-	0xf5, 0x04,
-	0xfe, 0x44,
-	0xd2, 0x32,
-	0xb8, 0x00,
-};
-
-struct ds3000_state {
-	struct i2c_adapter *i2c;
-	const struct ds3000_config *config;
-	struct dvb_frontend frontend;
-	u8 skip_fw_load;
-	/* previous uncorrected block counter for DVB-S2 */
-	u16 prevUCBS2;
-};
-
-static int ds3000_writereg(struct ds3000_state *state, int reg, int data)
-{
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = { .addr = state->config->demod_address,
-		.flags = 0, .buf = buf, .len = 2 };
-	int err;
-
-	dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data);
-
-	err = i2c_transfer(state->i2c, &msg, 1);
-	if (err != 1) {
-		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
-			 " value == 0x%02x)\n", __func__, err, reg, data);
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static int ds3000_tuner_writereg(struct ds3000_state *state, int reg, int data)
-{
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = { .addr = 0x60,
-		.flags = 0, .buf = buf, .len = 2 };
-	int err;
-
-	dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data);
-
-	ds3000_writereg(state, 0x03, 0x11);
-	err = i2c_transfer(state->i2c, &msg, 1);
-	if (err != 1) {
-		printk("%s: writereg error(err == %i, reg == 0x%02x,"
-			 " value == 0x%02x)\n", __func__, err, reg, data);
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-/* I2C write for 8k firmware load */
-static int ds3000_writeFW(struct ds3000_state *state, int reg,
-				const u8 *data, u16 len)
-{
-	int i, ret = -EREMOTEIO;
-	struct i2c_msg msg;
-	u8 *buf;
-
-	buf = kmalloc(33, GFP_KERNEL);
-	if (buf == NULL) {
-		printk(KERN_ERR "Unable to kmalloc\n");
-		ret = -ENOMEM;
-		goto error;
-	}
-
-	*(buf) = reg;
-
-	msg.addr = state->config->demod_address;
-	msg.flags = 0;
-	msg.buf = buf;
-	msg.len = 33;
-
-	for (i = 0; i < len; i += 32) {
-		memcpy(buf + 1, data + i, 32);
-
-		dprintk("%s: write reg 0x%02x, len = %d\n", __func__, reg, len);
-
-		ret = i2c_transfer(state->i2c, &msg, 1);
-		if (ret != 1) {
-			printk(KERN_ERR "%s: write error(err == %i, "
-				"reg == 0x%02x\n", __func__, ret, reg);
-			ret = -EREMOTEIO;
-		}
-	}
-
-error:
-	kfree(buf);
-
-	return ret;
-}
-
-static int ds3000_readreg(struct ds3000_state *state, u8 reg)
-{
-	int ret;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
-	struct i2c_msg msg[] = {
-		{
-			.addr = state->config->demod_address,
-			.flags = 0,
-			.buf = b0,
-			.len = 1
-		}, {
-			.addr = state->config->demod_address,
-			.flags = I2C_M_RD,
-			.buf = b1,
-			.len = 1
-		}
-	};
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2) {
-		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
-		return ret;
-	}
-
-	dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]);
-
-	return b1[0];
-}
-
-static int ds3000_tuner_readreg(struct ds3000_state *state, u8 reg)
-{
-	int ret;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
-	struct i2c_msg msg[] = {
-		{
-			.addr = 0x60,
-			.flags = 0,
-			.buf = b0,
-			.len = 1
-		}, {
-			.addr = 0x60,
-			.flags = I2C_M_RD,
-			.buf = b1,
-			.len = 1
-		}
-	};
-
-	ds3000_writereg(state, 0x03, 0x12);
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2) {
-		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
-		return ret;
-	}
-
-	dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]);
-
-	return b1[0];
-}
-
-static int ds3000_load_firmware(struct dvb_frontend *fe,
-					const struct firmware *fw);
-
-static int ds3000_firmware_ondemand(struct dvb_frontend *fe)
-{
-	struct ds3000_state *state = fe->demodulator_priv;
-	const struct firmware *fw;
-	int ret = 0;
-
-	dprintk("%s()\n", __func__);
-
-	if (ds3000_readreg(state, 0xb2) <= 0)
-		return ret;
-
-	if (state->skip_fw_load)
-		return 0;
-	/* Load firmware */
-	/* request the firmware, this will block until someone uploads it */
-	printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
-				DS3000_DEFAULT_FIRMWARE);
-	ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE,
-				state->i2c->dev.parent);
-	printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__);
-	if (ret) {
-		printk(KERN_ERR "%s: No firmware uploaded (timeout or file not "
-				"found?)\n", __func__);
-		return ret;
-	}
-
-	/* Make sure we don't recurse back through here during loading */
-	state->skip_fw_load = 1;
-
-	ret = ds3000_load_firmware(fe, fw);
-	if (ret)
-		printk("%s: Writing firmware to device failed\n", __func__);
-
-	release_firmware(fw);
-
-	dprintk("%s: Firmware upload %s\n", __func__,
-			ret == 0 ? "complete" : "failed");
-
-	/* Ensure firmware is always loaded if required */
-	state->skip_fw_load = 0;
-
-	return ret;
-}
-
-static int ds3000_load_firmware(struct dvb_frontend *fe,
-					const struct firmware *fw)
-{
-	struct ds3000_state *state = fe->demodulator_priv;
-
-	dprintk("%s\n", __func__);
-	dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
-			fw->size,
-			fw->data[0],
-			fw->data[1],
-			fw->data[fw->size - 2],
-			fw->data[fw->size - 1]);
-
-	/* Begin the firmware load process */
-	ds3000_writereg(state, 0xb2, 0x01);
-	/* write the entire firmware */
-	ds3000_writeFW(state, 0xb0, fw->data, fw->size);
-	ds3000_writereg(state, 0xb2, 0x00);
-
-	return 0;
-}
-
-static int ds3000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
-	struct ds3000_state *state = fe->demodulator_priv;
-	u8 data;
-
-	dprintk("%s(%d)\n", __func__, voltage);
-
-	data = ds3000_readreg(state, 0xa2);
-	data |= 0x03; /* bit0 V/H, bit1 off/on */
-
-	switch (voltage) {
-	case SEC_VOLTAGE_18:
-		data &= ~0x03;
-		break;
-	case SEC_VOLTAGE_13:
-		data &= ~0x03;
-		data |= 0x01;
-		break;
-	case SEC_VOLTAGE_OFF:
-		break;
-	}
-
-	ds3000_writereg(state, 0xa2, data);
-
-	return 0;
-}
-
-static int ds3000_read_status(struct dvb_frontend *fe, fe_status_t* status)
-{
-	struct ds3000_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int lock;
-
-	*status = 0;
-
-	switch (c->delivery_system) {
-	case SYS_DVBS:
-		lock = ds3000_readreg(state, 0xd1);
-		if ((lock & 0x07) == 0x07)
-			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
-				FE_HAS_VITERBI | FE_HAS_SYNC |
-				FE_HAS_LOCK;
-
-		break;
-	case SYS_DVBS2:
-		lock = ds3000_readreg(state, 0x0d);
-		if ((lock & 0x8f) == 0x8f)
-			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
-				FE_HAS_VITERBI | FE_HAS_SYNC |
-				FE_HAS_LOCK;
-
-		break;
-	default:
-		return 1;
-	}
-
-	dprintk("%s: status = 0x%02x\n", __func__, lock);
-
-	return 0;
-}
-
-/* read DS3000 BER value */
-static int ds3000_read_ber(struct dvb_frontend *fe, u32* ber)
-{
-	struct ds3000_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u8 data;
-	u32 ber_reading, lpdc_frames;
-
-	dprintk("%s()\n", __func__);
-
-	switch (c->delivery_system) {
-	case SYS_DVBS:
-		/* set the number of bytes checked during
-		BER estimation */
-		ds3000_writereg(state, 0xf9, 0x04);
-		/* read BER estimation status */
-		data = ds3000_readreg(state, 0xf8);
-		/* check if BER estimation is ready */
-		if ((data & 0x10) == 0) {
-			/* this is the number of error bits,
-			to calculate the bit error rate
-			divide to 8388608 */
-			*ber = (ds3000_readreg(state, 0xf7) << 8) |
-				ds3000_readreg(state, 0xf6);
-			/* start counting error bits */
-			/* need to be set twice
-			otherwise it fails sometimes */
-			data |= 0x10;
-			ds3000_writereg(state, 0xf8, data);
-			ds3000_writereg(state, 0xf8, data);
-		} else
-			/* used to indicate that BER estimation
-			is not ready, i.e. BER is unknown */
-			*ber = 0xffffffff;
-		break;
-	case SYS_DVBS2:
-		/* read the number of LPDC decoded frames */
-		lpdc_frames = (ds3000_readreg(state, 0xd7) << 16) |
-				(ds3000_readreg(state, 0xd6) << 8) |
-				ds3000_readreg(state, 0xd5);
-		/* read the number of packets with bad CRC */
-		ber_reading = (ds3000_readreg(state, 0xf8) << 8) |
-				ds3000_readreg(state, 0xf7);
-		if (lpdc_frames > 750) {
-			/* clear LPDC frame counters */
-			ds3000_writereg(state, 0xd1, 0x01);
-			/* clear bad packets counter */
-			ds3000_writereg(state, 0xf9, 0x01);
-			/* enable bad packets counter */
-			ds3000_writereg(state, 0xf9, 0x00);
-			/* enable LPDC frame counters */
-			ds3000_writereg(state, 0xd1, 0x00);
-			*ber = ber_reading;
-		} else
-			/* used to indicate that BER estimation is not ready,
-			i.e. BER is unknown */
-			*ber = 0xffffffff;
-		break;
-	default:
-		return 1;
-	}
-
-	return 0;
-}
-
-/* read TS2020 signal strength */
-static int ds3000_read_signal_strength(struct dvb_frontend *fe,
-						u16 *signal_strength)
-{
-	struct ds3000_state *state = fe->demodulator_priv;
-	u16 sig_reading, sig_strength;
-	u8 rfgain, bbgain;
-
-	dprintk("%s()\n", __func__);
-
-	rfgain = ds3000_tuner_readreg(state, 0x3d) & 0x1f;
-	bbgain = ds3000_tuner_readreg(state, 0x21) & 0x1f;
-
-	if (rfgain > 15)
-		rfgain = 15;
-	if (bbgain > 13)
-		bbgain = 13;
-
-	sig_reading = rfgain * 2 + bbgain * 3;
-
-	sig_strength = 40 + (64 - sig_reading) * 50 / 64 ;
-
-	/* cook the value to be suitable for szap-s2 human readable output */
-	*signal_strength = sig_strength * 1000;
-
-	dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__,
-			sig_reading, *signal_strength);
-
-	return 0;
-}
-
-/* calculate DS3000 snr value in dB */
-static int ds3000_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct ds3000_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u8 snr_reading, snr_value;
-	u32 dvbs2_signal_reading, dvbs2_noise_reading, tmp;
-	static const u16 dvbs_snr_tab[] = { /* 20 x Table (rounded up) */
-		0x0000, 0x1b13, 0x2aea, 0x3627, 0x3ede, 0x45fe, 0x4c03,
-		0x513a, 0x55d4, 0x59f2, 0x5dab, 0x6111, 0x6431, 0x6717,
-		0x69c9, 0x6c4e, 0x6eac, 0x70e8, 0x7304, 0x7505
-	};
-	static const u16 dvbs2_snr_tab[] = { /* 80 x Table (rounded up) */
-		0x0000, 0x0bc2, 0x12a3, 0x1785, 0x1b4e, 0x1e65, 0x2103,
-		0x2347, 0x2546, 0x2710, 0x28ae, 0x2a28, 0x2b83, 0x2cc5,
-		0x2df1, 0x2f09, 0x3010, 0x3109, 0x31f4, 0x32d2, 0x33a6,
-		0x3470, 0x3531, 0x35ea, 0x369b, 0x3746, 0x37ea, 0x3888,
-		0x3920, 0x39b3, 0x3a42, 0x3acc, 0x3b51, 0x3bd3, 0x3c51,
-		0x3ccb, 0x3d42, 0x3db6, 0x3e27, 0x3e95, 0x3f00, 0x3f68,
-		0x3fcf, 0x4033, 0x4094, 0x40f4, 0x4151, 0x41ac, 0x4206,
-		0x425e, 0x42b4, 0x4308, 0x435b, 0x43ac, 0x43fc, 0x444a,
-		0x4497, 0x44e2, 0x452d, 0x4576, 0x45bd, 0x4604, 0x4649,
-		0x468e, 0x46d1, 0x4713, 0x4755, 0x4795, 0x47d4, 0x4813,
-		0x4851, 0x488d, 0x48c9, 0x4904, 0x493f, 0x4978, 0x49b1,
-		0x49e9, 0x4a20, 0x4a57
-	};
-
-	dprintk("%s()\n", __func__);
-
-	switch (c->delivery_system) {
-	case SYS_DVBS:
-		snr_reading = ds3000_readreg(state, 0xff);
-		snr_reading /= 8;
-		if (snr_reading == 0)
-			*snr = 0x0000;
-		else {
-			if (snr_reading > 20)
-				snr_reading = 20;
-			snr_value = dvbs_snr_tab[snr_reading - 1] * 10 / 23026;
-			/* cook the value to be suitable for szap-s2
-			human readable output */
-			*snr = snr_value * 8 * 655;
-		}
-		dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
-				snr_reading, *snr);
-		break;
-	case SYS_DVBS2:
-		dvbs2_noise_reading = (ds3000_readreg(state, 0x8c) & 0x3f) +
-				(ds3000_readreg(state, 0x8d) << 4);
-		dvbs2_signal_reading = ds3000_readreg(state, 0x8e);
-		tmp = dvbs2_signal_reading * dvbs2_signal_reading >> 1;
-		if (tmp == 0) {
-			*snr = 0x0000;
-			return 0;
-		}
-		if (dvbs2_noise_reading == 0) {
-			snr_value = 0x0013;
-			/* cook the value to be suitable for szap-s2
-			human readable output */
-			*snr = 0xffff;
-			return 0;
-		}
-		if (tmp > dvbs2_noise_reading) {
-			snr_reading = tmp / dvbs2_noise_reading;
-			if (snr_reading > 80)
-				snr_reading = 80;
-			snr_value = dvbs2_snr_tab[snr_reading - 1] / 1000;
-			/* cook the value to be suitable for szap-s2
-			human readable output */
-			*snr = snr_value * 5 * 655;
-		} else {
-			snr_reading = dvbs2_noise_reading / tmp;
-			if (snr_reading > 80)
-				snr_reading = 80;
-			*snr = -(dvbs2_snr_tab[snr_reading] / 1000);
-		}
-		dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
-				snr_reading, *snr);
-		break;
-	default:
-		return 1;
-	}
-
-	return 0;
-}
-
-/* read DS3000 uncorrected blocks */
-static int ds3000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct ds3000_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u8 data;
-	u16 _ucblocks;
-
-	dprintk("%s()\n", __func__);
-
-	switch (c->delivery_system) {
-	case SYS_DVBS:
-		*ucblocks = (ds3000_readreg(state, 0xf5) << 8) |
-				ds3000_readreg(state, 0xf4);
-		data = ds3000_readreg(state, 0xf8);
-		/* clear packet counters */
-		data &= ~0x20;
-		ds3000_writereg(state, 0xf8, data);
-		/* enable packet counters */
-		data |= 0x20;
-		ds3000_writereg(state, 0xf8, data);
-		break;
-	case SYS_DVBS2:
-		_ucblocks = (ds3000_readreg(state, 0xe2) << 8) |
-				ds3000_readreg(state, 0xe1);
-		if (_ucblocks > state->prevUCBS2)
-			*ucblocks = _ucblocks - state->prevUCBS2;
-		else
-			*ucblocks = state->prevUCBS2 - _ucblocks;
-		state->prevUCBS2 = _ucblocks;
-		break;
-	default:
-		return 1;
-	}
-
-	return 0;
-}
-
-static int ds3000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
-{
-	struct ds3000_state *state = fe->demodulator_priv;
-	u8 data;
-
-	dprintk("%s(%d)\n", __func__, tone);
-	if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
-		printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
-		return -EINVAL;
-	}
-
-	data = ds3000_readreg(state, 0xa2);
-	data &= ~0xc0;
-	ds3000_writereg(state, 0xa2, data);
-
-	switch (tone) {
-	case SEC_TONE_ON:
-		dprintk("%s: setting tone on\n", __func__);
-		data = ds3000_readreg(state, 0xa1);
-		data &= ~0x43;
-		data |= 0x04;
-		ds3000_writereg(state, 0xa1, data);
-		break;
-	case SEC_TONE_OFF:
-		dprintk("%s: setting tone off\n", __func__);
-		data = ds3000_readreg(state, 0xa2);
-		data |= 0x80;
-		ds3000_writereg(state, 0xa2, data);
-		break;
-	}
-
-	return 0;
-}
-
-static int ds3000_send_diseqc_msg(struct dvb_frontend *fe,
-				struct dvb_diseqc_master_cmd *d)
-{
-	struct ds3000_state *state = fe->demodulator_priv;
-	int i;
-	u8 data;
-
-	/* Dump DiSEqC message */
-	dprintk("%s(", __func__);
-	for (i = 0 ; i < d->msg_len;) {
-		dprintk("0x%02x", d->msg[i]);
-		if (++i < d->msg_len)
-			dprintk(", ");
-	}
-
-	/* enable DiSEqC message send pin */
-	data = ds3000_readreg(state, 0xa2);
-	data &= ~0xc0;
-	ds3000_writereg(state, 0xa2, data);
-
-	/* DiSEqC message */
-	for (i = 0; i < d->msg_len; i++)
-		ds3000_writereg(state, 0xa3 + i, d->msg[i]);
-
-	data = ds3000_readreg(state, 0xa1);
-	/* clear DiSEqC message length and status,
-	enable DiSEqC message send */
-	data &= ~0xf8;
-	/* set DiSEqC mode, modulation active during 33 pulses,
-	set DiSEqC message length */
-	data |= ((d->msg_len - 1) << 3) | 0x07;
-	ds3000_writereg(state, 0xa1, data);
-
-	/* wait up to 150ms for DiSEqC transmission to complete */
-	for (i = 0; i < 15; i++) {
-		data = ds3000_readreg(state, 0xa1);
-		if ((data & 0x40) == 0)
-			break;
-		msleep(10);
-	}
-
-	/* DiSEqC timeout after 150ms */
-	if (i == 15) {
-		data = ds3000_readreg(state, 0xa1);
-		data &= ~0x80;
-		data |= 0x40;
-		ds3000_writereg(state, 0xa1, data);
-
-		data = ds3000_readreg(state, 0xa2);
-		data &= ~0xc0;
-		data |= 0x80;
-		ds3000_writereg(state, 0xa2, data);
-
-		return 1;
-	}
-
-	data = ds3000_readreg(state, 0xa2);
-	data &= ~0xc0;
-	data |= 0x80;
-	ds3000_writereg(state, 0xa2, data);
-
-	return 0;
-}
-
-/* Send DiSEqC burst */
-static int ds3000_diseqc_send_burst(struct dvb_frontend *fe,
-					fe_sec_mini_cmd_t burst)
-{
-	struct ds3000_state *state = fe->demodulator_priv;
-	int i;
-	u8 data;
-
-	dprintk("%s()\n", __func__);
-
-	data = ds3000_readreg(state, 0xa2);
-	data &= ~0xc0;
-	ds3000_writereg(state, 0xa2, data);
-
-	/* DiSEqC burst */
-	if (burst == SEC_MINI_A)
-		/* Unmodulated tone burst */
-		ds3000_writereg(state, 0xa1, 0x02);
-	else if (burst == SEC_MINI_B)
-		/* Modulated tone burst */
-		ds3000_writereg(state, 0xa1, 0x01);
-	else
-		return -EINVAL;
-
-	msleep(13);
-	for (i = 0; i < 5; i++) {
-		data = ds3000_readreg(state, 0xa1);
-		if ((data & 0x40) == 0)
-			break;
-		msleep(1);
-	}
-
-	if (i == 5) {
-		data = ds3000_readreg(state, 0xa1);
-		data &= ~0x80;
-		data |= 0x40;
-		ds3000_writereg(state, 0xa1, data);
-
-		data = ds3000_readreg(state, 0xa2);
-		data &= ~0xc0;
-		data |= 0x80;
-		ds3000_writereg(state, 0xa2, data);
-
-		return 1;
-	}
-
-	data = ds3000_readreg(state, 0xa2);
-	data &= ~0xc0;
-	data |= 0x80;
-	ds3000_writereg(state, 0xa2, data);
-
-	return 0;
-}
-
-static void ds3000_release(struct dvb_frontend *fe)
-{
-	struct ds3000_state *state = fe->demodulator_priv;
-	dprintk("%s\n", __func__);
-	kfree(state);
-}
-
-static struct dvb_frontend_ops ds3000_ops;
-
-struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
-				    struct i2c_adapter *i2c)
-{
-	struct ds3000_state *state = NULL;
-	int ret;
-
-	dprintk("%s\n", __func__);
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct ds3000_state), GFP_KERNEL);
-	if (state == NULL) {
-		printk(KERN_ERR "Unable to kmalloc\n");
-		goto error2;
-	}
-
-	state->config = config;
-	state->i2c = i2c;
-	state->prevUCBS2 = 0;
-
-	/* check if the demod is present */
-	ret = ds3000_readreg(state, 0x00) & 0xfe;
-	if (ret != 0xe0) {
-		printk(KERN_ERR "Invalid probe, probably not a DS3000\n");
-		goto error3;
-	}
-
-	printk(KERN_INFO "DS3000 chip version: %d.%d attached.\n",
-			ds3000_readreg(state, 0x02),
-			ds3000_readreg(state, 0x01));
-
-	memcpy(&state->frontend.ops, &ds3000_ops,
-			sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error3:
-	kfree(state);
-error2:
-	return NULL;
-}
-EXPORT_SYMBOL(ds3000_attach);
-
-static int ds3000_set_carrier_offset(struct dvb_frontend *fe,
-					s32 carrier_offset_khz)
-{
-	struct ds3000_state *state = fe->demodulator_priv;
-	s32 tmp;
-
-	tmp = carrier_offset_khz;
-	tmp *= 65536;
-	tmp = (2 * tmp + DS3000_SAMPLE_RATE) / (2 * DS3000_SAMPLE_RATE);
-
-	if (tmp < 0)
-		tmp += 65536;
-
-	ds3000_writereg(state, 0x5f, tmp >> 8);
-	ds3000_writereg(state, 0x5e, tmp & 0xff);
-
-	return 0;
-}
-
-static int ds3000_set_frontend(struct dvb_frontend *fe)
-{
-	struct ds3000_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-
-	int i;
-	fe_status_t status;
-	u8 mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf, div4;
-	s32 offset_khz;
-	u16 value, ndiv;
-	u32 f3db;
-
-	dprintk("%s() ", __func__);
-
-	if (state->config->set_ts_params)
-		state->config->set_ts_params(fe, 0);
-	/* Tune */
-	/* unknown */
-	ds3000_tuner_writereg(state, 0x07, 0x02);
-	ds3000_tuner_writereg(state, 0x10, 0x00);
-	ds3000_tuner_writereg(state, 0x60, 0x79);
-	ds3000_tuner_writereg(state, 0x08, 0x01);
-	ds3000_tuner_writereg(state, 0x00, 0x01);
-	div4 = 0;
-
-	/* calculate and set freq divider */
-	if (c->frequency < 1146000) {
-		ds3000_tuner_writereg(state, 0x10, 0x11);
-		div4 = 1;
-		ndiv = ((c->frequency * (6 + 8) * 4) +
-				(DS3000_XTAL_FREQ / 2)) /
-				DS3000_XTAL_FREQ - 1024;
-	} else {
-		ds3000_tuner_writereg(state, 0x10, 0x01);
-		ndiv = ((c->frequency * (6 + 8) * 2) +
-				(DS3000_XTAL_FREQ / 2)) /
-				DS3000_XTAL_FREQ - 1024;
-	}
-
-	ds3000_tuner_writereg(state, 0x01, (ndiv & 0x0f00) >> 8);
-	ds3000_tuner_writereg(state, 0x02, ndiv & 0x00ff);
-
-	/* set pll */
-	ds3000_tuner_writereg(state, 0x03, 0x06);
-	ds3000_tuner_writereg(state, 0x51, 0x0f);
-	ds3000_tuner_writereg(state, 0x51, 0x1f);
-	ds3000_tuner_writereg(state, 0x50, 0x10);
-	ds3000_tuner_writereg(state, 0x50, 0x00);
-	msleep(5);
-
-	/* unknown */
-	ds3000_tuner_writereg(state, 0x51, 0x17);
-	ds3000_tuner_writereg(state, 0x51, 0x1f);
-	ds3000_tuner_writereg(state, 0x50, 0x08);
-	ds3000_tuner_writereg(state, 0x50, 0x00);
-	msleep(5);
-
-	value = ds3000_tuner_readreg(state, 0x3d);
-	value &= 0x0f;
-	if ((value > 4) && (value < 15)) {
-		value -= 3;
-		if (value < 4)
-			value = 4;
-		value = ((value << 3) | 0x01) & 0x79;
-	}
-
-	ds3000_tuner_writereg(state, 0x60, value);
-	ds3000_tuner_writereg(state, 0x51, 0x17);
-	ds3000_tuner_writereg(state, 0x51, 0x1f);
-	ds3000_tuner_writereg(state, 0x50, 0x08);
-	ds3000_tuner_writereg(state, 0x50, 0x00);
-
-	/* set low-pass filter period */
-	ds3000_tuner_writereg(state, 0x04, 0x2e);
-	ds3000_tuner_writereg(state, 0x51, 0x1b);
-	ds3000_tuner_writereg(state, 0x51, 0x1f);
-	ds3000_tuner_writereg(state, 0x50, 0x04);
-	ds3000_tuner_writereg(state, 0x50, 0x00);
-	msleep(5);
-
-	f3db = ((c->symbol_rate / 1000) << 2) / 5 + 2000;
-	if ((c->symbol_rate / 1000) < 5000)
-		f3db += 3000;
-	if (f3db < 7000)
-		f3db = 7000;
-	if (f3db > 40000)
-		f3db = 40000;
-
-	/* set low-pass filter baseband */
-	value = ds3000_tuner_readreg(state, 0x26);
-	mlpf = 0x2e * 207 / ((value << 1) + 151);
-	mlpf_max = mlpf * 135 / 100;
-	mlpf_min = mlpf * 78 / 100;
-	if (mlpf_max > 63)
-		mlpf_max = 63;
-
-	/* rounded to the closest integer */
-	nlpf = ((mlpf * f3db * 1000) + (2766 * DS3000_XTAL_FREQ / 2))
-			/ (2766 * DS3000_XTAL_FREQ);
-	if (nlpf > 23)
-		nlpf = 23;
-	if (nlpf < 1)
-		nlpf = 1;
-
-	/* rounded to the closest integer */
-	mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
-			(1000 * f3db / 2)) / (1000 * f3db);
-
-	if (mlpf_new < mlpf_min) {
-		nlpf++;
-		mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
-				(1000 * f3db / 2)) / (1000 * f3db);
-	}
-
-	if (mlpf_new > mlpf_max)
-		mlpf_new = mlpf_max;
-
-	ds3000_tuner_writereg(state, 0x04, mlpf_new);
-	ds3000_tuner_writereg(state, 0x06, nlpf);
-	ds3000_tuner_writereg(state, 0x51, 0x1b);
-	ds3000_tuner_writereg(state, 0x51, 0x1f);
-	ds3000_tuner_writereg(state, 0x50, 0x04);
-	ds3000_tuner_writereg(state, 0x50, 0x00);
-	msleep(5);
-
-	/* unknown */
-	ds3000_tuner_writereg(state, 0x51, 0x1e);
-	ds3000_tuner_writereg(state, 0x51, 0x1f);
-	ds3000_tuner_writereg(state, 0x50, 0x01);
-	ds3000_tuner_writereg(state, 0x50, 0x00);
-	msleep(60);
-
-	offset_khz = (ndiv - ndiv % 2 + 1024) * DS3000_XTAL_FREQ
-		/ (6 + 8) / (div4 + 1) / 2 - c->frequency;
-
-	/* ds3000 global reset */
-	ds3000_writereg(state, 0x07, 0x80);
-	ds3000_writereg(state, 0x07, 0x00);
-	/* ds3000 build-in uC reset */
-	ds3000_writereg(state, 0xb2, 0x01);
-	/* ds3000 software reset */
-	ds3000_writereg(state, 0x00, 0x01);
-
-	switch (c->delivery_system) {
-	case SYS_DVBS:
-		/* initialise the demod in DVB-S mode */
-		for (i = 0; i < sizeof(ds3000_dvbs_init_tab); i += 2)
-			ds3000_writereg(state,
-				ds3000_dvbs_init_tab[i],
-				ds3000_dvbs_init_tab[i + 1]);
-		value = ds3000_readreg(state, 0xfe);
-		value &= 0xc0;
-		value |= 0x1b;
-		ds3000_writereg(state, 0xfe, value);
-		break;
-	case SYS_DVBS2:
-		/* initialise the demod in DVB-S2 mode */
-		for (i = 0; i < sizeof(ds3000_dvbs2_init_tab); i += 2)
-			ds3000_writereg(state,
-				ds3000_dvbs2_init_tab[i],
-				ds3000_dvbs2_init_tab[i + 1]);
-		if (c->symbol_rate >= 30000000)
-			ds3000_writereg(state, 0xfe, 0x54);
-		else
-			ds3000_writereg(state, 0xfe, 0x98);
-		break;
-	default:
-		return 1;
-	}
-
-	/* enable 27MHz clock output */
-	ds3000_writereg(state, 0x29, 0x80);
-	/* enable ac coupling */
-	ds3000_writereg(state, 0x25, 0x8a);
-
-	/* enhance symbol rate performance */
-	if ((c->symbol_rate / 1000) <= 5000) {
-		value = 29777 / (c->symbol_rate / 1000) + 1;
-		if (value % 2 != 0)
-			value++;
-		ds3000_writereg(state, 0xc3, 0x0d);
-		ds3000_writereg(state, 0xc8, value);
-		ds3000_writereg(state, 0xc4, 0x10);
-		ds3000_writereg(state, 0xc7, 0x0e);
-	} else if ((c->symbol_rate / 1000) <= 10000) {
-		value = 92166 / (c->symbol_rate / 1000) + 1;
-		if (value % 2 != 0)
-			value++;
-		ds3000_writereg(state, 0xc3, 0x07);
-		ds3000_writereg(state, 0xc8, value);
-		ds3000_writereg(state, 0xc4, 0x09);
-		ds3000_writereg(state, 0xc7, 0x12);
-	} else if ((c->symbol_rate / 1000) <= 20000) {
-		value = 64516 / (c->symbol_rate / 1000) + 1;
-		ds3000_writereg(state, 0xc3, value);
-		ds3000_writereg(state, 0xc8, 0x0e);
-		ds3000_writereg(state, 0xc4, 0x07);
-		ds3000_writereg(state, 0xc7, 0x18);
-	} else {
-		value = 129032 / (c->symbol_rate / 1000) + 1;
-		ds3000_writereg(state, 0xc3, value);
-		ds3000_writereg(state, 0xc8, 0x0a);
-		ds3000_writereg(state, 0xc4, 0x05);
-		ds3000_writereg(state, 0xc7, 0x24);
-	}
-
-	/* normalized symbol rate rounded to the closest integer */
-	value = (((c->symbol_rate / 1000) << 16) +
-			(DS3000_SAMPLE_RATE / 2)) / DS3000_SAMPLE_RATE;
-	ds3000_writereg(state, 0x61, value & 0x00ff);
-	ds3000_writereg(state, 0x62, (value & 0xff00) >> 8);
-
-	/* co-channel interference cancellation disabled */
-	ds3000_writereg(state, 0x56, 0x00);
-
-	/* equalizer disabled */
-	ds3000_writereg(state, 0x76, 0x00);
-
-	/*ds3000_writereg(state, 0x08, 0x03);
-	ds3000_writereg(state, 0xfd, 0x22);
-	ds3000_writereg(state, 0x08, 0x07);
-	ds3000_writereg(state, 0xfd, 0x42);
-	ds3000_writereg(state, 0x08, 0x07);*/
-
-	if (state->config->ci_mode) {
-		switch (c->delivery_system) {
-		case SYS_DVBS:
-		default:
-			ds3000_writereg(state, 0xfd, 0x80);
-		break;
-		case SYS_DVBS2:
-			ds3000_writereg(state, 0xfd, 0x01);
-			break;
-		}
-	}
-
-	/* ds3000 out of software reset */
-	ds3000_writereg(state, 0x00, 0x00);
-	/* start ds3000 build-in uC */
-	ds3000_writereg(state, 0xb2, 0x00);
-
-	ds3000_set_carrier_offset(fe, offset_khz);
-
-	for (i = 0; i < 30 ; i++) {
-		ds3000_read_status(fe, &status);
-		if (status & FE_HAS_LOCK)
-			break;
-
-		msleep(10);
-	}
-
-	return 0;
-}
-
-static int ds3000_tune(struct dvb_frontend *fe,
-			bool re_tune,
-			unsigned int mode_flags,
-			unsigned int *delay,
-			fe_status_t *status)
-{
-	if (re_tune) {
-		int ret = ds3000_set_frontend(fe);
-		if (ret)
-			return ret;
-	}
-
-	*delay = HZ / 5;
-
-	return ds3000_read_status(fe, status);
-}
-
-static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe)
-{
-	dprintk("%s()\n", __func__);
-	return DVBFE_ALGO_HW;
-}
-
-/*
- * Initialise or wake up device
- *
- * Power config will reset and load initial firmware if required
- */
-static int ds3000_initfe(struct dvb_frontend *fe)
-{
-	struct ds3000_state *state = fe->demodulator_priv;
-	int ret;
-
-	dprintk("%s()\n", __func__);
-	/* hard reset */
-	ds3000_writereg(state, 0x08, 0x01 | ds3000_readreg(state, 0x08));
-	msleep(1);
-
-	/* TS2020 init */
-	ds3000_tuner_writereg(state, 0x42, 0x73);
-	ds3000_tuner_writereg(state, 0x05, 0x01);
-	ds3000_tuner_writereg(state, 0x62, 0xf5);
-	/* Load the firmware if required */
-	ret = ds3000_firmware_ondemand(fe);
-	if (ret != 0) {
-		printk(KERN_ERR "%s: Unable initialize firmware\n", __func__);
-		return ret;
-	}
-
-	return 0;
-}
-
-/* Put device to sleep */
-static int ds3000_sleep(struct dvb_frontend *fe)
-{
-	dprintk("%s()\n", __func__);
-	return 0;
-}
-
-static struct dvb_frontend_ops ds3000_ops = {
-	.delsys = { SYS_DVBS, SYS_DVBS2},
-	.info = {
-		.name = "Montage Technology DS3000/TS2020",
-		.frequency_min = 950000,
-		.frequency_max = 2150000,
-		.frequency_stepsize = 1011, /* kHz for QPSK frontends */
-		.frequency_tolerance = 5000,
-		.symbol_rate_min = 1000000,
-		.symbol_rate_max = 45000000,
-		.caps = FE_CAN_INVERSION_AUTO |
-			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
-			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_2G_MODULATION |
-			FE_CAN_QPSK | FE_CAN_RECOVER
-	},
-
-	.release = ds3000_release,
-
-	.init = ds3000_initfe,
-	.sleep = ds3000_sleep,
-	.read_status = ds3000_read_status,
-	.read_ber = ds3000_read_ber,
-	.read_signal_strength = ds3000_read_signal_strength,
-	.read_snr = ds3000_read_snr,
-	.read_ucblocks = ds3000_read_ucblocks,
-	.set_voltage = ds3000_set_voltage,
-	.set_tone = ds3000_set_tone,
-	.diseqc_send_master_cmd = ds3000_send_diseqc_msg,
-	.diseqc_send_burst = ds3000_diseqc_send_burst,
-	.get_frontend_algo = ds3000_get_algo,
-
-	.set_frontend = ds3000_set_frontend,
-	.tune = ds3000_tune,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
-
-MODULE_DESCRIPTION("DVB Frontend module for Montage Technology "
-			"DS3000/TS2020 hardware");
-MODULE_AUTHOR("Konstantin Dimitrov");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/ds3000.h b/drivers/media/dvb/frontends/ds3000.h
deleted file mode 100644
index 1b73688..0000000
--- a/drivers/media/dvb/frontends/ds3000.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-    Montage Technology DS3000/TS2020 - DVBS/S2 Satellite demod/tuner driver
-    Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
-
-    Copyright (C) 2009 TurboSight.com
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef DS3000_H
-#define DS3000_H
-
-#include <linux/dvb/frontend.h>
-
-struct ds3000_config {
-	/* the demodulator's i2c address */
-	u8 demod_address;
-	u8 ci_mode;
-	/* Set device param to start dma */
-	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
-};
-
-#if defined(CONFIG_DVB_DS3000) || \
-			(defined(CONFIG_DVB_DS3000_MODULE) && defined(MODULE))
-extern struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
-					struct i2c_adapter *i2c);
-#else
-static inline
-struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
-					struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_DS3000 */
-#endif /* DS3000_H */
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
deleted file mode 100644
index 1ab3483..0000000
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ /dev/null
@@ -1,794 +0,0 @@
-/*
- * descriptions + helper functions for simple dvb plls.
- *
- * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/dvb/frontend.h>
-#include <asm/types.h>
-
-#include "dvb-pll.h"
-
-struct dvb_pll_priv {
-	/* pll number */
-	int nr;
-
-	/* i2c details */
-	int pll_i2c_address;
-	struct i2c_adapter *i2c;
-
-	/* the PLL descriptor */
-	struct dvb_pll_desc *pll_desc;
-
-	/* cached frequency/bandwidth */
-	u32 frequency;
-	u32 bandwidth;
-};
-
-#define DVB_PLL_MAX 64
-
-static unsigned int dvb_pll_devcount;
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-static unsigned int id[DVB_PLL_MAX] =
-	{ [ 0 ... (DVB_PLL_MAX-1) ] = DVB_PLL_UNDEFINED };
-module_param_array(id, int, NULL, 0644);
-MODULE_PARM_DESC(id, "force pll id to use (DEBUG ONLY)");
-
-/* ----------------------------------------------------------- */
-
-struct dvb_pll_desc {
-	char *name;
-	u32  min;
-	u32  max;
-	u32  iffreq;
-	void (*set)(struct dvb_frontend *fe, u8 *buf);
-	u8   *initdata;
-	u8   *initdata2;
-	u8   *sleepdata;
-	int  count;
-	struct {
-		u32 limit;
-		u32 stepsize;
-		u8  config;
-		u8  cb;
-	} entries[12];
-};
-
-/* ----------------------------------------------------------- */
-/* descriptions                                                */
-
-static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
-	.name  = "Thomson dtt7579",
-	.min   = 177000000,
-	.max   = 858000000,
-	.iffreq= 36166667,
-	.sleepdata = (u8[]){ 2, 0xb4, 0x03 },
-	.count = 4,
-	.entries = {
-		{  443250000, 166667, 0xb4, 0x02 },
-		{  542000000, 166667, 0xb4, 0x08 },
-		{  771000000, 166667, 0xbc, 0x08 },
-		{  999999999, 166667, 0xf4, 0x08 },
-	},
-};
-
-static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf)
-{
-	u32 bw = fe->dtv_property_cache.bandwidth_hz;
-	if (bw == 7000000)
-		buf[3] |= 0x10;
-}
-
-static struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
-	.name  = "Thomson dtt759x",
-	.min   = 177000000,
-	.max   = 896000000,
-	.set   = thomson_dtt759x_bw,
-	.iffreq= 36166667,
-	.sleepdata = (u8[]){ 2, 0x84, 0x03 },
-	.count = 5,
-	.entries = {
-		{  264000000, 166667, 0xb4, 0x02 },
-		{  470000000, 166667, 0xbc, 0x02 },
-		{  735000000, 166667, 0xbc, 0x08 },
-		{  835000000, 166667, 0xf4, 0x08 },
-		{  999999999, 166667, 0xfc, 0x08 },
-	},
-};
-
-static struct dvb_pll_desc dvb_pll_lg_z201 = {
-	.name  = "LG z201",
-	.min   = 174000000,
-	.max   = 862000000,
-	.iffreq= 36166667,
-	.sleepdata = (u8[]){ 2, 0xbc, 0x03 },
-	.count = 5,
-	.entries = {
-		{  157500000, 166667, 0xbc, 0x01 },
-		{  443250000, 166667, 0xbc, 0x02 },
-		{  542000000, 166667, 0xbc, 0x04 },
-		{  830000000, 166667, 0xf4, 0x04 },
-		{  999999999, 166667, 0xfc, 0x04 },
-	},
-};
-
-static struct dvb_pll_desc dvb_pll_unknown_1 = {
-	.name  = "unknown 1", /* used by dntv live dvb-t */
-	.min   = 174000000,
-	.max   = 862000000,
-	.iffreq= 36166667,
-	.count = 9,
-	.entries = {
-		{  150000000, 166667, 0xb4, 0x01 },
-		{  173000000, 166667, 0xbc, 0x01 },
-		{  250000000, 166667, 0xb4, 0x02 },
-		{  400000000, 166667, 0xbc, 0x02 },
-		{  420000000, 166667, 0xf4, 0x02 },
-		{  470000000, 166667, 0xfc, 0x02 },
-		{  600000000, 166667, 0xbc, 0x08 },
-		{  730000000, 166667, 0xf4, 0x08 },
-		{  999999999, 166667, 0xfc, 0x08 },
-	},
-};
-
-/* Infineon TUA6010XS
- * used in Thomson Cable Tuner
- */
-static struct dvb_pll_desc dvb_pll_tua6010xs = {
-	.name  = "Infineon TUA6010XS",
-	.min   =  44250000,
-	.max   = 858000000,
-	.iffreq= 36125000,
-	.count = 3,
-	.entries = {
-		{  115750000, 62500, 0x8e, 0x03 },
-		{  403250000, 62500, 0x8e, 0x06 },
-		{  999999999, 62500, 0x8e, 0x85 },
-	},
-};
-
-/* Panasonic env57h1xd5 (some Philips PLL ?) */
-static struct dvb_pll_desc dvb_pll_env57h1xd5 = {
-	.name  = "Panasonic ENV57H1XD5",
-	.min   =  44250000,
-	.max   = 858000000,
-	.iffreq= 36125000,
-	.count = 4,
-	.entries = {
-		{  153000000, 166667, 0xc2, 0x41 },
-		{  470000000, 166667, 0xc2, 0x42 },
-		{  526000000, 166667, 0xc2, 0x84 },
-		{  999999999, 166667, 0xc2, 0xa4 },
-	},
-};
-
-/* Philips TDA6650/TDA6651
- * used in Panasonic ENV77H11D5
- */
-static void tda665x_bw(struct dvb_frontend *fe, u8 *buf)
-{
-	u32 bw = fe->dtv_property_cache.bandwidth_hz;
-	if (bw == 8000000)
-		buf[3] |= 0x08;
-}
-
-static struct dvb_pll_desc dvb_pll_tda665x = {
-	.name  = "Philips TDA6650/TDA6651",
-	.min   =  44250000,
-	.max   = 858000000,
-	.set   = tda665x_bw,
-	.iffreq= 36166667,
-	.initdata = (u8[]){ 4, 0x0b, 0xf5, 0x85, 0xab },
-	.count = 12,
-	.entries = {
-		{   93834000, 166667, 0xca, 0x61 /* 011 0 0 0  01 */ },
-		{  123834000, 166667, 0xca, 0xa1 /* 101 0 0 0  01 */ },
-		{  161000000, 166667, 0xca, 0xa1 /* 101 0 0 0  01 */ },
-		{  163834000, 166667, 0xca, 0xc2 /* 110 0 0 0  10 */ },
-		{  253834000, 166667, 0xca, 0x62 /* 011 0 0 0  10 */ },
-		{  383834000, 166667, 0xca, 0xa2 /* 101 0 0 0  10 */ },
-		{  443834000, 166667, 0xca, 0xc2 /* 110 0 0 0  10 */ },
-		{  444000000, 166667, 0xca, 0xc4 /* 110 0 0 1  00 */ },
-		{  583834000, 166667, 0xca, 0x64 /* 011 0 0 1  00 */ },
-		{  793834000, 166667, 0xca, 0xa4 /* 101 0 0 1  00 */ },
-		{  444834000, 166667, 0xca, 0xc4 /* 110 0 0 1  00 */ },
-		{  861000000, 166667, 0xca, 0xe4 /* 111 0 0 1  00 */ },
-	}
-};
-
-/* Infineon TUA6034
- * used in LG TDTP E102P
- */
-static void tua6034_bw(struct dvb_frontend *fe, u8 *buf)
-{
-	u32 bw = fe->dtv_property_cache.bandwidth_hz;
-	if (bw == 7000000)
-		buf[3] |= 0x08;
-}
-
-static struct dvb_pll_desc dvb_pll_tua6034 = {
-	.name  = "Infineon TUA6034",
-	.min   =  44250000,
-	.max   = 858000000,
-	.iffreq= 36166667,
-	.count = 3,
-	.set   = tua6034_bw,
-	.entries = {
-		{  174500000, 62500, 0xce, 0x01 },
-		{  230000000, 62500, 0xce, 0x02 },
-		{  999999999, 62500, 0xce, 0x04 },
-	},
-};
-
-/* ALPS TDED4
- * used in Nebula-Cards and USB boxes
- */
-static void tded4_bw(struct dvb_frontend *fe, u8 *buf)
-{
-	u32 bw = fe->dtv_property_cache.bandwidth_hz;
-	if (bw == 8000000)
-		buf[3] |= 0x04;
-}
-
-static struct dvb_pll_desc dvb_pll_tded4 = {
-	.name = "ALPS TDED4",
-	.min = 47000000,
-	.max = 863000000,
-	.iffreq= 36166667,
-	.set   = tded4_bw,
-	.count = 4,
-	.entries = {
-		{ 153000000, 166667, 0x85, 0x01 },
-		{ 470000000, 166667, 0x85, 0x02 },
-		{ 823000000, 166667, 0x85, 0x08 },
-		{ 999999999, 166667, 0x85, 0x88 },
-	}
-};
-
-/* ALPS TDHU2
- * used in AverTVHD MCE A180
- */
-static struct dvb_pll_desc dvb_pll_tdhu2 = {
-	.name = "ALPS TDHU2",
-	.min = 54000000,
-	.max = 864000000,
-	.iffreq= 44000000,
-	.count = 4,
-	.entries = {
-		{ 162000000, 62500, 0x85, 0x01 },
-		{ 426000000, 62500, 0x85, 0x02 },
-		{ 782000000, 62500, 0x85, 0x08 },
-		{ 999999999, 62500, 0x85, 0x88 },
-	}
-};
-
-/* Samsung TBMV30111IN / TBMV30712IN1
- * used in Air2PC ATSC - 2nd generation (nxt2002)
- */
-static struct dvb_pll_desc dvb_pll_samsung_tbmv = {
-	.name = "Samsung TBMV30111IN / TBMV30712IN1",
-	.min = 54000000,
-	.max = 860000000,
-	.iffreq= 44000000,
-	.count = 6,
-	.entries = {
-		{ 172000000, 166667, 0xb4, 0x01 },
-		{ 214000000, 166667, 0xb4, 0x02 },
-		{ 467000000, 166667, 0xbc, 0x02 },
-		{ 721000000, 166667, 0xbc, 0x08 },
-		{ 841000000, 166667, 0xf4, 0x08 },
-		{ 999999999, 166667, 0xfc, 0x02 },
-	}
-};
-
-/*
- * Philips SD1878 Tuner.
- */
-static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
-	.name  = "Philips SD1878",
-	.min   =  950000,
-	.max   = 2150000,
-	.iffreq= 249, /* zero-IF, offset 249 is to round up */
-	.count = 4,
-	.entries = {
-		{ 1250000, 500, 0xc4, 0x00},
-		{ 1450000, 500, 0xc4, 0x40},
-		{ 2050000, 500, 0xc4, 0x80},
-		{ 2150000, 500, 0xc4, 0xc0},
-	},
-};
-
-static void opera1_bw(struct dvb_frontend *fe, u8 *buf)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct dvb_pll_priv *priv = fe->tuner_priv;
-	u32 b_w  = (c->symbol_rate * 27) / 32000;
-	struct i2c_msg msg = {
-		.addr = priv->pll_i2c_address,
-		.flags = 0,
-		.buf = buf,
-		.len = 4
-	};
-	int result;
-	u8 lpf;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	result = i2c_transfer(priv->i2c, &msg, 1);
-	if (result != 1)
-		printk(KERN_ERR "%s: i2c_transfer failed:%d",
-			__func__, result);
-
-	if (b_w <= 10000)
-		lpf = 0xc;
-	else if (b_w <= 12000)
-		lpf = 0x2;
-	else if (b_w <= 14000)
-		lpf = 0xa;
-	else if (b_w <= 16000)
-		lpf = 0x6;
-	else if (b_w <= 18000)
-		lpf = 0xe;
-	else if (b_w <= 20000)
-		lpf = 0x1;
-	else if (b_w <= 22000)
-		lpf = 0x9;
-	else if (b_w <= 24000)
-		lpf = 0x5;
-	else if (b_w <= 26000)
-		lpf = 0xd;
-	else if (b_w <= 28000)
-		lpf = 0x3;
-		else
-		lpf = 0xb;
-	buf[2] ^= 0x1c; /* Flip bits 3-5 */
-	/* Set lpf */
-	buf[2] |= ((lpf >> 2) & 0x3) << 3;
-	buf[3] |= (lpf & 0x3) << 2;
-
-	return;
-}
-
-static struct dvb_pll_desc dvb_pll_opera1 = {
-	.name  = "Opera Tuner",
-	.min   =  900000,
-	.max   = 2250000,
-	.initdata = (u8[]){ 4, 0x08, 0xe5, 0xe1, 0x00 },
-	.initdata2 = (u8[]){ 4, 0x08, 0xe5, 0xe5, 0x00 },
-	.iffreq= 0,
-	.set   = opera1_bw,
-	.count = 8,
-	.entries = {
-		{ 1064000, 500, 0xf9, 0xc2 },
-		{ 1169000, 500, 0xf9, 0xe2 },
-		{ 1299000, 500, 0xf9, 0x20 },
-		{ 1444000, 500, 0xf9, 0x40 },
-		{ 1606000, 500, 0xf9, 0x60 },
-		{ 1777000, 500, 0xf9, 0x80 },
-		{ 1941000, 500, 0xf9, 0xa0 },
-		{ 2250000, 500, 0xf9, 0xc0 },
-	}
-};
-
-static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf)
-{
-	struct dvb_pll_priv *priv = fe->tuner_priv;
-	struct i2c_msg msg = {
-		.addr = priv->pll_i2c_address,
-		.flags = 0,
-		.buf = buf,
-		.len = 4
-	};
-	int result;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	result = i2c_transfer(priv->i2c, &msg, 1);
-	if (result != 1)
-		printk(KERN_ERR "%s: i2c_transfer failed:%d",
-			__func__, result);
-
-	buf[2] = 0x9e;
-	buf[3] = 0x90;
-
-	return;
-}
-
-/* unknown pll used in Samsung DTOS403IH102A DVB-C tuner */
-static struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = {
-	.name   = "Samsung DTOS403IH102A",
-	.min    =  44250000,
-	.max    = 858000000,
-	.iffreq =  36125000,
-	.count  = 8,
-	.set    = samsung_dtos403ih102a_set,
-	.entries = {
-		{ 135000000, 62500, 0xbe, 0x01 },
-		{ 177000000, 62500, 0xf6, 0x01 },
-		{ 370000000, 62500, 0xbe, 0x02 },
-		{ 450000000, 62500, 0xf6, 0x02 },
-		{ 466000000, 62500, 0xfe, 0x02 },
-		{ 538000000, 62500, 0xbe, 0x08 },
-		{ 826000000, 62500, 0xf6, 0x08 },
-		{ 999999999, 62500, 0xfe, 0x08 },
-	}
-};
-
-/* Samsung TDTC9251DH0 DVB-T NIM, as used on AirStar 2 */
-static struct dvb_pll_desc dvb_pll_samsung_tdtc9251dh0 = {
-	.name	= "Samsung TDTC9251DH0",
-	.min	=  48000000,
-	.max	= 863000000,
-	.iffreq	=  36166667,
-	.count	= 3,
-	.entries = {
-		{ 157500000, 166667, 0xcc, 0x09 },
-		{ 443000000, 166667, 0xcc, 0x0a },
-		{ 863000000, 166667, 0xcc, 0x08 },
-	}
-};
-
-/* Samsung TBDU18132 DVB-S NIM with TSA5059 PLL, used in SkyStar2 DVB-S 2.3 */
-static struct dvb_pll_desc dvb_pll_samsung_tbdu18132 = {
-	.name = "Samsung TBDU18132",
-	.min	=  950000,
-	.max	= 2150000, /* guesses */
-	.iffreq = 0,
-	.count = 2,
-	.entries = {
-		{ 1550000, 125, 0x84, 0x82 },
-		{ 4095937, 125, 0x84, 0x80 },
-	}
-	/* TSA5059 PLL has a 17 bit divisor rather than the 15 bits supported
-	 * by this driver.  The two extra bits are 0x60 in the third byte.  15
-	 * bits is enough for over 4 GHz, which is enough to cover the range
-	 * of this tuner.  We could use the additional divisor bits by adding
-	 * more entries, e.g.
-	 { 0x0ffff * 125 + 125/2, 125, 0x84 | 0x20, },
-	 { 0x17fff * 125 + 125/2, 125, 0x84 | 0x40, },
-	 { 0x1ffff * 125 + 125/2, 125, 0x84 | 0x60, }, */
-};
-
-/* Samsung TBMU24112 DVB-S NIM with SL1935 zero-IF tuner */
-static struct dvb_pll_desc dvb_pll_samsung_tbmu24112 = {
-	.name = "Samsung TBMU24112",
-	.min	=  950000,
-	.max	= 2150000, /* guesses */
-	.iffreq = 0,
-	.count = 2,
-	.entries = {
-		{ 1500000, 125, 0x84, 0x18 },
-		{ 9999999, 125, 0x84, 0x08 },
-	}
-};
-
-/* Alps TDEE4 DVB-C NIM, used on Cablestar 2 */
-/* byte 4 : 1  *   *   AGD R3  R2  R1  R0
- * byte 5 : C1 *   RE  RTS BS4 BS3 BS2 BS1
- * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95
- * Range(MHz)  C1 *  RE RTS BS4 BS3 BS2 BS1  Byte 5
- *  47 - 153   0  *  0   0   0   0   0   1   0x01
- * 153 - 430   0  *  0   0   0   0   1   0   0x02
- * 430 - 822   0  *  0   0   1   0   0   0   0x08
- * 822 - 862   1  *  0   0   1   0   0   0   0x88 */
-static struct dvb_pll_desc dvb_pll_alps_tdee4 = {
-	.name = "ALPS TDEE4",
-	.min	=  47000000,
-	.max	= 862000000,
-	.iffreq	=  36125000,
-	.count = 4,
-	.entries = {
-		{ 153000000, 62500, 0x95, 0x01 },
-		{ 430000000, 62500, 0x95, 0x02 },
-		{ 822000000, 62500, 0x95, 0x08 },
-		{ 999999999, 62500, 0x95, 0x88 },
-	}
-};
-
-/* ----------------------------------------------------------- */
-
-static struct dvb_pll_desc *pll_list[] = {
-	[DVB_PLL_UNDEFINED]              = NULL,
-	[DVB_PLL_THOMSON_DTT7579]        = &dvb_pll_thomson_dtt7579,
-	[DVB_PLL_THOMSON_DTT759X]        = &dvb_pll_thomson_dtt759x,
-	[DVB_PLL_LG_Z201]                = &dvb_pll_lg_z201,
-	[DVB_PLL_UNKNOWN_1]              = &dvb_pll_unknown_1,
-	[DVB_PLL_TUA6010XS]              = &dvb_pll_tua6010xs,
-	[DVB_PLL_ENV57H1XD5]             = &dvb_pll_env57h1xd5,
-	[DVB_PLL_TUA6034]                = &dvb_pll_tua6034,
-	[DVB_PLL_TDA665X]                = &dvb_pll_tda665x,
-	[DVB_PLL_TDED4]                  = &dvb_pll_tded4,
-	[DVB_PLL_TDEE4]                  = &dvb_pll_alps_tdee4,
-	[DVB_PLL_TDHU2]                  = &dvb_pll_tdhu2,
-	[DVB_PLL_SAMSUNG_TBMV]           = &dvb_pll_samsung_tbmv,
-	[DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
-	[DVB_PLL_OPERA1]                 = &dvb_pll_opera1,
-	[DVB_PLL_SAMSUNG_DTOS403IH102A]  = &dvb_pll_samsung_dtos403ih102a,
-	[DVB_PLL_SAMSUNG_TDTC9251DH0]    = &dvb_pll_samsung_tdtc9251dh0,
-	[DVB_PLL_SAMSUNG_TBDU18132]	 = &dvb_pll_samsung_tbdu18132,
-	[DVB_PLL_SAMSUNG_TBMU24112]      = &dvb_pll_samsung_tbmu24112,
-};
-
-/* ----------------------------------------------------------- */
-/* code                                                        */
-
-static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf,
-			     const u32 frequency)
-{
-	struct dvb_pll_priv *priv = fe->tuner_priv;
-	struct dvb_pll_desc *desc = priv->pll_desc;
-	u32 div;
-	int i;
-
-	if (frequency && (frequency < desc->min || frequency > desc->max))
-		return -EINVAL;
-
-	for (i = 0; i < desc->count; i++) {
-		if (frequency > desc->entries[i].limit)
-			continue;
-		break;
-	}
-
-	if (debug)
-		printk("pll: %s: freq=%d | i=%d/%d\n", desc->name,
-		       frequency, i, desc->count);
-	if (i == desc->count)
-		return -EINVAL;
-
-	div = (frequency + desc->iffreq +
-	       desc->entries[i].stepsize/2) / desc->entries[i].stepsize;
-	buf[0] = div >> 8;
-	buf[1] = div & 0xff;
-	buf[2] = desc->entries[i].config;
-	buf[3] = desc->entries[i].cb;
-
-	if (desc->set)
-		desc->set(fe, buf);
-
-	if (debug)
-		printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
-		       desc->name, div, buf[0], buf[1], buf[2], buf[3]);
-
-	// calculate the frequency we set it to
-	return (div * desc->entries[i].stepsize) - desc->iffreq;
-}
-
-static int dvb_pll_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static int dvb_pll_sleep(struct dvb_frontend *fe)
-{
-	struct dvb_pll_priv *priv = fe->tuner_priv;
-
-	if (priv->i2c == NULL)
-		return -EINVAL;
-
-	if (priv->pll_desc->sleepdata) {
-		struct i2c_msg msg = { .flags = 0,
-			.addr = priv->pll_i2c_address,
-			.buf = priv->pll_desc->sleepdata + 1,
-			.len = priv->pll_desc->sleepdata[0] };
-
-		int result;
-
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-		if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
-			return result;
-		}
-		return 0;
-	}
-	/* Shouldn't be called when initdata is NULL, maybe BUG()? */
-	return -EINVAL;
-}
-
-static int dvb_pll_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct dvb_pll_priv *priv = fe->tuner_priv;
-	u8 buf[4];
-	struct i2c_msg msg =
-		{ .addr = priv->pll_i2c_address, .flags = 0,
-		  .buf = buf, .len = sizeof(buf) };
-	int result;
-	u32 frequency = 0;
-
-	if (priv->i2c == NULL)
-		return -EINVAL;
-
-	result = dvb_pll_configure(fe, buf, c->frequency);
-	if (result < 0)
-		return result;
-	else
-		frequency = result;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
-		return result;
-	}
-
-	priv->frequency = frequency;
-	priv->bandwidth = c->bandwidth_hz;
-
-	return 0;
-}
-
-static int dvb_pll_calc_regs(struct dvb_frontend *fe,
-			     u8 *buf, int buf_len)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct dvb_pll_priv *priv = fe->tuner_priv;
-	int result;
-	u32 frequency = 0;
-
-	if (buf_len < 5)
-		return -EINVAL;
-
-	result = dvb_pll_configure(fe, buf + 1, c->frequency);
-	if (result < 0)
-		return result;
-	else
-		frequency = result;
-
-	buf[0] = priv->pll_i2c_address;
-
-	priv->frequency = frequency;
-	priv->bandwidth = c->bandwidth_hz;
-
-	return 5;
-}
-
-static int dvb_pll_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct dvb_pll_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-	return 0;
-}
-
-static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	struct dvb_pll_priv *priv = fe->tuner_priv;
-	*bandwidth = priv->bandwidth;
-	return 0;
-}
-
-static int dvb_pll_init(struct dvb_frontend *fe)
-{
-	struct dvb_pll_priv *priv = fe->tuner_priv;
-
-	if (priv->i2c == NULL)
-		return -EINVAL;
-
-	if (priv->pll_desc->initdata) {
-		struct i2c_msg msg = { .flags = 0,
-			.addr = priv->pll_i2c_address,
-			.buf = priv->pll_desc->initdata + 1,
-			.len = priv->pll_desc->initdata[0] };
-
-		int result;
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-		result = i2c_transfer(priv->i2c, &msg, 1);
-		if (result != 1)
-			return result;
-		if (priv->pll_desc->initdata2) {
-			msg.buf = priv->pll_desc->initdata2 + 1;
-			msg.len = priv->pll_desc->initdata2[0];
-			if (fe->ops.i2c_gate_ctrl)
-				fe->ops.i2c_gate_ctrl(fe, 1);
-			result = i2c_transfer(priv->i2c, &msg, 1);
-			if (result != 1)
-				return result;
-		}
-		return 0;
-	}
-	/* Shouldn't be called when initdata is NULL, maybe BUG()? */
-	return -EINVAL;
-}
-
-static struct dvb_tuner_ops dvb_pll_tuner_ops = {
-	.release = dvb_pll_release,
-	.sleep = dvb_pll_sleep,
-	.init = dvb_pll_init,
-	.set_params = dvb_pll_set_params,
-	.calc_regs = dvb_pll_calc_regs,
-	.get_frequency = dvb_pll_get_frequency,
-	.get_bandwidth = dvb_pll_get_bandwidth,
-};
-
-struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
-				    struct i2c_adapter *i2c,
-				    unsigned int pll_desc_id)
-{
-	u8 b1 [] = { 0 };
-	struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD,
-			       .buf = b1, .len = 1 };
-	struct dvb_pll_priv *priv = NULL;
-	int ret;
-	struct dvb_pll_desc *desc;
-
-	if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) &&
-	    (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list)))
-		pll_desc_id = id[dvb_pll_devcount];
-
-	BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list));
-
-	desc = pll_list[pll_desc_id];
-
-	if (i2c != NULL) {
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-
-		ret = i2c_transfer (i2c, &msg, 1);
-		if (ret != 1)
-			return NULL;
-		if (fe->ops.i2c_gate_ctrl)
-			     fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	priv->pll_i2c_address = pll_addr;
-	priv->i2c = i2c;
-	priv->pll_desc = desc;
-	priv->nr = dvb_pll_devcount++;
-
-	memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops,
-	       sizeof(struct dvb_tuner_ops));
-
-	strncpy(fe->ops.tuner_ops.info.name, desc->name,
-		sizeof(fe->ops.tuner_ops.info.name));
-	fe->ops.tuner_ops.info.frequency_min = desc->min;
-	fe->ops.tuner_ops.info.frequency_max = desc->max;
-	if (!desc->initdata)
-		fe->ops.tuner_ops.init = NULL;
-	if (!desc->sleepdata)
-		fe->ops.tuner_ops.sleep = NULL;
-
-	fe->tuner_priv = priv;
-
-	if ((debug) || (id[priv->nr] == pll_desc_id)) {
-		printk("dvb-pll[%d]", priv->nr);
-		if (i2c != NULL)
-			printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr);
-		printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name,
-		       id[priv->nr] == pll_desc_id ?
-				"insmod option" : "autodetected");
-	}
-
-	return fe;
-}
-EXPORT_SYMBOL(dvb_pll_attach);
-
-MODULE_DESCRIPTION("dvb pll library");
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
deleted file mode 100644
index 0869643..0000000
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * descriptions + helper functions for simple dvb plls.
- */
-
-#ifndef __DVB_PLL_H__
-#define __DVB_PLL_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-#define DVB_PLL_UNDEFINED               0
-#define DVB_PLL_THOMSON_DTT7579         1
-#define DVB_PLL_THOMSON_DTT759X         2
-#define DVB_PLL_LG_Z201                 3
-#define DVB_PLL_UNKNOWN_1               4
-#define DVB_PLL_TUA6010XS               5
-#define DVB_PLL_ENV57H1XD5              6
-#define DVB_PLL_TUA6034                 7
-#define DVB_PLL_TDA665X                 8
-#define DVB_PLL_TDED4                   9
-#define DVB_PLL_TDHU2                  10
-#define DVB_PLL_SAMSUNG_TBMV           11
-#define DVB_PLL_PHILIPS_SD1878_TDA8261 12
-#define DVB_PLL_OPERA1                 13
-#define DVB_PLL_SAMSUNG_DTOS403IH102A  14
-#define DVB_PLL_SAMSUNG_TDTC9251DH0    15
-#define DVB_PLL_SAMSUNG_TBDU18132      16
-#define DVB_PLL_SAMSUNG_TBMU24112      17
-#define DVB_PLL_TDEE4		       18
-
-/**
- * Attach a dvb-pll to the supplied frontend structure.
- *
- * @param fe Frontend to attach to.
- * @param pll_addr i2c address of the PLL (if used).
- * @param i2c i2c adapter to use (set to NULL if not used).
- * @param pll_desc_id dvb_pll_desc to use.
- * @return Frontend pointer on success, NULL on failure
- */
-#if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE))
-extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
-					   int pll_addr,
-					   struct i2c_adapter *i2c,
-					   unsigned int pll_desc_id);
-#else
-static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
-					   int pll_addr,
-					   struct i2c_adapter *i2c,
-					   unsigned int pll_desc_id)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c
deleted file mode 100644
index dcfc902..0000000
--- a/drivers/media/dvb/frontends/dvb_dummy_fe.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- *  Driver for Dummy Frontend
- *
- *  Written by Emard <emard@softhome.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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "dvb_dummy_fe.h"
-
-
-struct dvb_dummy_fe_state {
-	struct dvb_frontend frontend;
-};
-
-
-static int dvb_dummy_fe_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	*status = FE_HAS_SIGNAL
-		| FE_HAS_CARRIER
-		| FE_HAS_VITERBI
-		| FE_HAS_SYNC
-		| FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int dvb_dummy_fe_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	*ber = 0;
-	return 0;
-}
-
-static int dvb_dummy_fe_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-{
-	*strength = 0;
-	return 0;
-}
-
-static int dvb_dummy_fe_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	*snr = 0;
-	return 0;
-}
-
-static int dvb_dummy_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	*ucblocks = 0;
-	return 0;
-}
-
-/*
- * Only needed if it actually reads something from the hardware
- */
-static int dvb_dummy_fe_get_frontend(struct dvb_frontend *fe)
-{
-	return 0;
-}
-
-static int dvb_dummy_fe_set_frontend(struct dvb_frontend *fe)
-{
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	return 0;
-}
-
-static int dvb_dummy_fe_sleep(struct dvb_frontend* fe)
-{
-	return 0;
-}
-
-static int dvb_dummy_fe_init(struct dvb_frontend* fe)
-{
-	return 0;
-}
-
-static int dvb_dummy_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
-	return 0;
-}
-
-static int dvb_dummy_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
-	return 0;
-}
-
-static void dvb_dummy_fe_release(struct dvb_frontend* fe)
-{
-	struct dvb_dummy_fe_state* state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops;
-
-struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void)
-{
-	struct dvb_dummy_fe_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops;
-
-struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void)
-{
-	struct dvb_dummy_fe_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops dvb_dummy_fe_qam_ops;
-
-struct dvb_frontend *dvb_dummy_fe_qam_attach(void)
-{
-	struct dvb_dummy_fe_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name			= "Dummy DVB-T",
-		.frequency_min		= 0,
-		.frequency_max		= 863250000,
-		.frequency_stepsize	= 62500,
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-				FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
-				FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
-				FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-				FE_CAN_TRANSMISSION_MODE_AUTO |
-				FE_CAN_GUARD_INTERVAL_AUTO |
-				FE_CAN_HIERARCHY_AUTO,
-	},
-
-	.release = dvb_dummy_fe_release,
-
-	.init = dvb_dummy_fe_init,
-	.sleep = dvb_dummy_fe_sleep,
-
-	.set_frontend = dvb_dummy_fe_set_frontend,
-	.get_frontend = dvb_dummy_fe_get_frontend,
-
-	.read_status = dvb_dummy_fe_read_status,
-	.read_ber = dvb_dummy_fe_read_ber,
-	.read_signal_strength = dvb_dummy_fe_read_signal_strength,
-	.read_snr = dvb_dummy_fe_read_snr,
-	.read_ucblocks = dvb_dummy_fe_read_ucblocks,
-};
-
-static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = {
-	.delsys = { SYS_DVBC_ANNEX_A },
-	.info = {
-		.name			= "Dummy DVB-C",
-		.frequency_stepsize	= 62500,
-		.frequency_min		= 51000000,
-		.frequency_max		= 858000000,
-		.symbol_rate_min	= (57840000/2)/64,     /* SACLK/64 == (XIN/2)/64 */
-		.symbol_rate_max	= (57840000/2)/4,      /* SACLK/4 */
-		.caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
-			FE_CAN_QAM_128 | FE_CAN_QAM_256 |
-			FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO
-	},
-
-	.release = dvb_dummy_fe_release,
-
-	.init = dvb_dummy_fe_init,
-	.sleep = dvb_dummy_fe_sleep,
-
-	.set_frontend = dvb_dummy_fe_set_frontend,
-	.get_frontend = dvb_dummy_fe_get_frontend,
-
-	.read_status = dvb_dummy_fe_read_status,
-	.read_ber = dvb_dummy_fe_read_ber,
-	.read_signal_strength = dvb_dummy_fe_read_signal_strength,
-	.read_snr = dvb_dummy_fe_read_snr,
-	.read_ucblocks = dvb_dummy_fe_read_ucblocks,
-};
-
-static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = {
-	.delsys = { SYS_DVBS },
-	.info = {
-		.name			= "Dummy DVB-S",
-		.frequency_min		= 950000,
-		.frequency_max		= 2150000,
-		.frequency_stepsize	= 250,           /* kHz for QPSK frontends */
-		.frequency_tolerance	= 29500,
-		.symbol_rate_min	= 1000000,
-		.symbol_rate_max	= 45000000,
-		.caps = FE_CAN_INVERSION_AUTO |
-			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK
-	},
-
-	.release = dvb_dummy_fe_release,
-
-	.init = dvb_dummy_fe_init,
-	.sleep = dvb_dummy_fe_sleep,
-
-	.set_frontend = dvb_dummy_fe_set_frontend,
-	.get_frontend = dvb_dummy_fe_get_frontend,
-
-	.read_status = dvb_dummy_fe_read_status,
-	.read_ber = dvb_dummy_fe_read_ber,
-	.read_signal_strength = dvb_dummy_fe_read_signal_strength,
-	.read_snr = dvb_dummy_fe_read_snr,
-	.read_ucblocks = dvb_dummy_fe_read_ucblocks,
-
-	.set_voltage = dvb_dummy_fe_set_voltage,
-	.set_tone = dvb_dummy_fe_set_tone,
-};
-
-MODULE_DESCRIPTION("DVB DUMMY Frontend");
-MODULE_AUTHOR("Emard");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(dvb_dummy_fe_ofdm_attach);
-EXPORT_SYMBOL(dvb_dummy_fe_qam_attach);
-EXPORT_SYMBOL(dvb_dummy_fe_qpsk_attach);
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.h b/drivers/media/dvb/frontends/dvb_dummy_fe.h
deleted file mode 100644
index 1fcb987..0000000
--- a/drivers/media/dvb/frontends/dvb_dummy_fe.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- *  Driver for Dummy Frontend
- *
- *  Written by Emard <emard@softhome.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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef DVB_DUMMY_FE_H
-#define DVB_DUMMY_FE_H
-
-#include <linux/dvb/frontend.h>
-#include "dvb_frontend.h"
-
-#if defined(CONFIG_DVB_DUMMY_FE) || (defined(CONFIG_DVB_DUMMY_FE_MODULE) && \
-defined(MODULE))
-extern struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void);
-extern struct dvb_frontend* dvb_dummy_fe_qpsk_attach(void);
-extern struct dvb_frontend* dvb_dummy_fe_qam_attach(void);
-#else
-static inline struct dvb_frontend *dvb_dummy_fe_ofdm_attach(void)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-static inline struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-static inline struct dvb_frontend *dvb_dummy_fe_qam_attach(void)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_DUMMY_FE */
-
-#endif // DVB_DUMMY_FE_H
diff --git a/drivers/media/dvb/frontends/ec100.c b/drivers/media/dvb/frontends/ec100.c
deleted file mode 100644
index c56fddb..0000000
--- a/drivers/media/dvb/frontends/ec100.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * E3C EC100 demodulator driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include "dvb_frontend.h"
-#include "ec100_priv.h"
-#include "ec100.h"
-
-int ec100_debug;
-module_param_named(debug, ec100_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-struct ec100_state {
-	struct i2c_adapter *i2c;
-	struct dvb_frontend frontend;
-	struct ec100_config config;
-
-	u16 ber;
-};
-
-/* write single register */
-static int ec100_write_reg(struct ec100_state *state, u8 reg, u8 val)
-{
-	u8 buf[2] = {reg, val};
-	struct i2c_msg msg = {
-		.addr = state->config.demod_address,
-		.flags = 0,
-		.len = 2,
-		.buf = buf};
-
-	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
-		warn("I2C write failed reg:%02x", reg);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-/* read single register */
-static int ec100_read_reg(struct ec100_state *state, u8 reg, u8 *val)
-{
-	struct i2c_msg msg[2] = {
-		{
-			.addr = state->config.demod_address,
-			.flags = 0,
-			.len = 1,
-			.buf = &reg
-		}, {
-			.addr = state->config.demod_address,
-			.flags = I2C_M_RD,
-			.len = 1,
-			.buf = val
-		}
-	};
-
-	if (i2c_transfer(state->i2c, msg, 2) != 2) {
-		warn("I2C read failed reg:%02x", reg);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int ec100_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct ec100_state *state = fe->demodulator_priv;
-	int ret;
-	u8 tmp, tmp2;
-
-	deb_info("%s: freq:%d bw:%d\n", __func__, c->frequency,
-		c->bandwidth_hz);
-
-	/* program tuner */
-	if (fe->ops.tuner_ops.set_params)
-		fe->ops.tuner_ops.set_params(fe);
-
-	ret = ec100_write_reg(state, 0x04, 0x06);
-	if (ret)
-		goto error;
-	ret = ec100_write_reg(state, 0x67, 0x58);
-	if (ret)
-		goto error;
-	ret = ec100_write_reg(state, 0x05, 0x18);
-	if (ret)
-		goto error;
-
-	/* reg/bw |   6  |   7  |   8
-	   -------+------+------+------
-	   A 0x1b | 0xa1 | 0xe7 | 0x2c
-	   A 0x1c | 0x55 | 0x63 | 0x72
-	   -------+------+------+------
-	   B 0x1b | 0xb7 | 0x00 | 0x49
-	   B 0x1c | 0x55 | 0x64 | 0x72 */
-
-	switch (c->bandwidth_hz) {
-	case 6000000:
-		tmp = 0xb7;
-		tmp2 = 0x55;
-		break;
-	case 7000000:
-		tmp = 0x00;
-		tmp2 = 0x64;
-		break;
-	case 8000000:
-	default:
-		tmp = 0x49;
-		tmp2 = 0x72;
-	}
-
-	ret = ec100_write_reg(state, 0x1b, tmp);
-	if (ret)
-		goto error;
-	ret = ec100_write_reg(state, 0x1c, tmp2);
-	if (ret)
-		goto error;
-
-	ret = ec100_write_reg(state, 0x0c, 0xbb); /* if freq */
-	if (ret)
-		goto error;
-	ret = ec100_write_reg(state, 0x0d, 0x31); /* if freq */
-	if (ret)
-		goto error;
-
-	ret = ec100_write_reg(state, 0x08, 0x24);
-	if (ret)
-		goto error;
-
-	ret = ec100_write_reg(state, 0x00, 0x00); /* go */
-	if (ret)
-		goto error;
-	ret = ec100_write_reg(state, 0x00, 0x20); /* go */
-	if (ret)
-		goto error;
-
-	return ret;
-error:
-	deb_info("%s: failed:%d\n", __func__, ret);
-	return ret;
-}
-
-static int ec100_get_tune_settings(struct dvb_frontend *fe,
-	struct dvb_frontend_tune_settings *fesettings)
-{
-	fesettings->min_delay_ms = 300;
-	fesettings->step_size = 0;
-	fesettings->max_drift = 0;
-
-	return 0;
-}
-
-static int ec100_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct ec100_state *state = fe->demodulator_priv;
-	int ret;
-	u8 tmp;
-	*status = 0;
-
-	ret = ec100_read_reg(state, 0x42, &tmp);
-	if (ret)
-		goto error;
-
-	if (tmp & 0x80) {
-		/* bit7 set - have lock */
-		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
-			FE_HAS_SYNC | FE_HAS_LOCK;
-	} else {
-		ret = ec100_read_reg(state, 0x01, &tmp);
-		if (ret)
-			goto error;
-
-		if (tmp & 0x10) {
-			/* bit4 set - have signal */
-			*status |= FE_HAS_SIGNAL;
-			if (!(tmp & 0x01)) {
-				/* bit0 clear - have ~valid signal */
-				*status |= FE_HAS_CARRIER |  FE_HAS_VITERBI;
-			}
-		}
-	}
-
-	return ret;
-error:
-	deb_info("%s: failed:%d\n", __func__, ret);
-	return ret;
-}
-
-static int ec100_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct ec100_state *state = fe->demodulator_priv;
-	int ret;
-	u8 tmp, tmp2;
-	u16 ber2;
-
-	*ber = 0;
-
-	ret = ec100_read_reg(state, 0x65, &tmp);
-	if (ret)
-		goto error;
-	ret = ec100_read_reg(state, 0x66, &tmp2);
-	if (ret)
-		goto error;
-
-	ber2 = (tmp2 << 8) | tmp;
-
-	/* if counter overflow or clear */
-	if (ber2 < state->ber)
-		*ber = ber2;
-	else
-		*ber = ber2 - state->ber;
-
-	state->ber = ber2;
-
-	return ret;
-error:
-	deb_info("%s: failed:%d\n", __func__, ret);
-	return ret;
-}
-
-static int ec100_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct ec100_state *state = fe->demodulator_priv;
-	int ret;
-	u8 tmp;
-
-	ret = ec100_read_reg(state, 0x24, &tmp);
-	if (ret) {
-		*strength = 0;
-		goto error;
-	}
-
-	*strength = ((tmp << 8) | tmp);
-
-	return ret;
-error:
-	deb_info("%s: failed:%d\n", __func__, ret);
-	return ret;
-}
-
-static int ec100_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	*snr = 0;
-	return 0;
-}
-
-static int ec100_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	*ucblocks = 0;
-	return 0;
-}
-
-static void ec100_release(struct dvb_frontend *fe)
-{
-	struct ec100_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops ec100_ops;
-
-struct dvb_frontend *ec100_attach(const struct ec100_config *config,
-	struct i2c_adapter *i2c)
-{
-	int ret;
-	struct ec100_state *state = NULL;
-	u8 tmp;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct ec100_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->i2c = i2c;
-	memcpy(&state->config, config, sizeof(struct ec100_config));
-
-	/* check if the demod is there */
-	ret = ec100_read_reg(state, 0x33, &tmp);
-	if (ret || tmp != 0x0b)
-		goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &ec100_ops,
-		sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-
-	return &state->frontend;
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(ec100_attach);
-
-static struct dvb_frontend_ops ec100_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name = "E3C EC100 DVB-T",
-		.caps =
-			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK | FE_CAN_QAM_16 |
-			FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_HIERARCHY_AUTO |
-			FE_CAN_MUTE_TS
-	},
-
-	.release = ec100_release,
-	.set_frontend = ec100_set_frontend,
-	.get_tune_settings = ec100_get_tune_settings,
-	.read_status = ec100_read_status,
-	.read_ber = ec100_read_ber,
-	.read_signal_strength = ec100_read_signal_strength,
-	.read_snr = ec100_read_snr,
-	.read_ucblocks = ec100_read_ucblocks,
-};
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("E3C EC100 DVB-T demodulator driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/ec100.h b/drivers/media/dvb/frontends/ec100.h
deleted file mode 100644
index ee8e524..0000000
--- a/drivers/media/dvb/frontends/ec100.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * E3C EC100 demodulator driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef EC100_H
-#define EC100_H
-
-#include <linux/dvb/frontend.h>
-
-struct ec100_config {
-	/* demodulator's I2C address */
-	u8 demod_address;
-};
-
-
-#if defined(CONFIG_DVB_EC100) || \
-	(defined(CONFIG_DVB_EC100_MODULE) && defined(MODULE))
-extern struct dvb_frontend *ec100_attach(const struct ec100_config *config,
-	struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *ec100_attach(
-	const struct ec100_config *config, struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* EC100_H */
diff --git a/drivers/media/dvb/frontends/ec100_priv.h b/drivers/media/dvb/frontends/ec100_priv.h
deleted file mode 100644
index 5c99014..0000000
--- a/drivers/media/dvb/frontends/ec100_priv.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * E3C EC100 demodulator driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef EC100_PRIV
-#define EC100_PRIV
-
-#define LOG_PREFIX "ec100"
-
-#define dprintk(var, level, args...) \
-	do { if ((var & level)) printk(args); } while (0)
-
-#define deb_info(args...) dprintk(ec100_debug, 0x01, args)
-
-#undef err
-#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
-#undef info
-#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
-#undef warn
-#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
-
-#endif /* EC100_PRIV */
diff --git a/drivers/media/dvb/frontends/eds1547.h b/drivers/media/dvb/frontends/eds1547.h
deleted file mode 100644
index c983f2f..0000000
--- a/drivers/media/dvb/frontends/eds1547.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/* eds1547.h Earda EDS-1547 tuner support
-*
-* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
-*
-*	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, version 2.
-*
-* see Documentation/dvb/README.dvb-usb for more information
-*/
-
-#ifndef EDS1547
-#define EDS1547
-
-static u8 stv0288_earda_inittab[] = {
-	0x01, 0x57,
-	0x02, 0x20,
-	0x03, 0x8e,
-	0x04, 0x8e,
-	0x05, 0x12,
-	0x06, 0x00,
-	0x07, 0x00,
-	0x09, 0x00,
-	0x0a, 0x04,
-	0x0b, 0x00,
-	0x0c, 0x00,
-	0x0d, 0x00,
-	0x0e, 0xd4,
-	0x0f, 0x30,
-	0x11, 0x44,
-	0x12, 0x03,
-	0x13, 0x48,
-	0x14, 0x84,
-	0x15, 0x45,
-	0x16, 0xb7,
-	0x17, 0x9c,
-	0x18, 0x00,
-	0x19, 0xa6,
-	0x1a, 0x88,
-	0x1b, 0x8f,
-	0x1c, 0xf0,
-	0x20, 0x0b,
-	0x21, 0x54,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x2b, 0xff,
-	0x2c, 0xf7,
-	0x30, 0x00,
-	0x31, 0x1e,
-	0x32, 0x14,
-	0x33, 0x0f,
-	0x34, 0x09,
-	0x35, 0x0c,
-	0x36, 0x05,
-	0x37, 0x2f,
-	0x38, 0x16,
-	0x39, 0xbd,
-	0x3a, 0x00,
-	0x3b, 0x13,
-	0x3c, 0x11,
-	0x3d, 0x30,
-	0x40, 0x63,
-	0x41, 0x04,
-	0x42, 0x20,
-	0x43, 0x00,
-	0x44, 0x00,
-	0x45, 0x00,
-	0x46, 0x00,
-	0x47, 0x00,
-	0x4a, 0x00,
-	0x50, 0x10,
-	0x51, 0x36,
-	0x52, 0x09,
-	0x53, 0x94,
-	0x54, 0x62,
-	0x55, 0x29,
-	0x56, 0x64,
-	0x57, 0x2b,
-	0x58, 0x54,
-	0x59, 0x86,
-	0x5a, 0x00,
-	0x5b, 0x9b,
-	0x5c, 0x08,
-	0x5d, 0x7f,
-	0x5e, 0x00,
-	0x5f, 0xff,
-	0x70, 0x00,
-	0x71, 0x00,
-	0x72, 0x00,
-	0x74, 0x00,
-	0x75, 0x00,
-	0x76, 0x00,
-	0x81, 0x00,
-	0x82, 0x3f,
-	0x83, 0x3f,
-	0x84, 0x00,
-	0x85, 0x00,
-	0x88, 0x00,
-	0x89, 0x00,
-	0x8a, 0x00,
-	0x8b, 0x00,
-	0x8c, 0x00,
-	0x90, 0x00,
-	0x91, 0x00,
-	0x92, 0x00,
-	0x93, 0x00,
-	0x94, 0x1c,
-	0x97, 0x00,
-	0xa0, 0x48,
-	0xa1, 0x00,
-	0xb0, 0xb8,
-	0xb1, 0x3a,
-	0xb2, 0x10,
-	0xb3, 0x82,
-	0xb4, 0x80,
-	0xb5, 0x82,
-	0xb6, 0x82,
-	0xb7, 0x82,
-	0xb8, 0x20,
-	0xb9, 0x00,
-	0xf0, 0x00,
-	0xf1, 0x00,
-	0xf2, 0xc0,
-	0xff,0xff,
-};
-
-static struct stv0288_config earda_config = {
-	.demod_address = 0x68,
-	.min_delay_ms = 100,
-	.inittab = stv0288_earda_inittab,
-};
-
-#endif
diff --git a/drivers/media/dvb/frontends/hd29l2.c b/drivers/media/dvb/frontends/hd29l2.c
deleted file mode 100644
index a003181..0000000
--- a/drivers/media/dvb/frontends/hd29l2.c
+++ /dev/null
@@ -1,861 +0,0 @@
-/*
- * HDIC HD29L2 DMB-TH demodulator driver
- *
- * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D
- *
- * Author: Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "hd29l2_priv.h"
-
-int hd29l2_debug;
-module_param_named(debug, hd29l2_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-/* write multiple registers */
-static int hd29l2_wr_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len)
-{
-	int ret;
-	u8 buf[2 + len];
-	struct i2c_msg msg[1] = {
-		{
-			.addr = priv->cfg.i2c_addr,
-			.flags = 0,
-			.len = sizeof(buf),
-			.buf = buf,
-		}
-	};
-
-	buf[0] = 0x00;
-	buf[1] = reg;
-	memcpy(&buf[2], val, len);
-
-	ret = i2c_transfer(priv->i2c, msg, 1);
-	if (ret == 1) {
-		ret = 0;
-	} else {
-		warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-
-	return ret;
-}
-
-/* read multiple registers */
-static int hd29l2_rd_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len)
-{
-	int ret;
-	u8 buf[2] = { 0x00, reg };
-	struct i2c_msg msg[2] = {
-		{
-			.addr = priv->cfg.i2c_addr,
-			.flags = 0,
-			.len = 2,
-			.buf = buf,
-		}, {
-			.addr = priv->cfg.i2c_addr,
-			.flags = I2C_M_RD,
-			.len = len,
-			.buf = val,
-		}
-	};
-
-	ret = i2c_transfer(priv->i2c, msg, 2);
-	if (ret == 2) {
-		ret = 0;
-	} else {
-		warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-
-	return ret;
-}
-
-/* write single register */
-static int hd29l2_wr_reg(struct hd29l2_priv *priv, u8 reg, u8 val)
-{
-	return hd29l2_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-static int hd29l2_rd_reg(struct hd29l2_priv *priv, u8 reg, u8 *val)
-{
-	return hd29l2_rd_regs(priv, reg, val, 1);
-}
-
-/* write single register with mask */
-static int hd29l2_wr_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 val, u8 mask)
-{
-	int ret;
-	u8 tmp;
-
-	/* no need for read if whole reg is written */
-	if (mask != 0xff) {
-		ret = hd29l2_rd_regs(priv, reg, &tmp, 1);
-		if (ret)
-			return ret;
-
-		val &= mask;
-		tmp &= ~mask;
-		val |= tmp;
-	}
-
-	return hd29l2_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register with mask */
-int hd29l2_rd_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 *val, u8 mask)
-{
-	int ret, i;
-	u8 tmp;
-
-	ret = hd29l2_rd_regs(priv, reg, &tmp, 1);
-	if (ret)
-		return ret;
-
-	tmp &= mask;
-
-	/* find position of the first bit */
-	for (i = 0; i < 8; i++) {
-		if ((mask >> i) & 0x01)
-			break;
-	}
-	*val = tmp >> i;
-
-	return 0;
-}
-
-static int hd29l2_soft_reset(struct hd29l2_priv *priv)
-{
-	int ret;
-	u8 tmp;
-
-	ret = hd29l2_rd_reg(priv, 0x26, &tmp);
-	if (ret)
-		goto err;
-
-	ret = hd29l2_wr_reg(priv, 0x26, 0x0d);
-	if (ret)
-		goto err;
-
-	usleep_range(10000, 20000);
-
-	ret = hd29l2_wr_reg(priv, 0x26, tmp);
-	if (ret)
-		goto err;
-
-	return 0;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int hd29l2_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	int ret, i;
-	struct hd29l2_priv *priv = fe->demodulator_priv;
-	u8 tmp;
-
-	dbg("%s: enable=%d", __func__, enable);
-
-	/* set tuner address for demod */
-	if (!priv->tuner_i2c_addr_programmed && enable) {
-		/* no need to set tuner address every time, once is enough */
-		ret = hd29l2_wr_reg(priv, 0x9d, priv->cfg.tuner_i2c_addr << 1);
-		if (ret)
-			goto err;
-
-		priv->tuner_i2c_addr_programmed = true;
-	}
-
-	/* open / close gate */
-	ret = hd29l2_wr_reg(priv, 0x9f, enable);
-	if (ret)
-		goto err;
-
-	/* wait demod ready */
-	for (i = 10; i; i--) {
-		ret = hd29l2_rd_reg(priv, 0x9e, &tmp);
-		if (ret)
-			goto err;
-
-		if (tmp == enable)
-			break;
-
-		usleep_range(5000, 10000);
-	}
-
-	dbg("%s: loop=%d", __func__, i);
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int hd29l2_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	int ret;
-	struct hd29l2_priv *priv = fe->demodulator_priv;
-	u8 buf[2];
-
-	*status = 0;
-
-	ret = hd29l2_rd_reg(priv, 0x05, &buf[0]);
-	if (ret)
-		goto err;
-
-	if (buf[0] & 0x01) {
-		/* full lock */
-		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
-			FE_HAS_SYNC | FE_HAS_LOCK;
-	} else {
-		ret = hd29l2_rd_reg(priv, 0x0d, &buf[1]);
-		if (ret)
-			goto err;
-
-		if ((buf[1] & 0xfe) == 0x78)
-			/* partial lock */
-			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-				FE_HAS_VITERBI | FE_HAS_SYNC;
-	}
-
-	priv->fe_status = *status;
-
-	return 0;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int hd29l2_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	int ret;
-	struct hd29l2_priv *priv = fe->demodulator_priv;
-	u8 buf[2];
-	u16 tmp;
-
-	if (!(priv->fe_status & FE_HAS_LOCK)) {
-		*snr = 0;
-		ret = 0;
-		goto err;
-	}
-
-	ret = hd29l2_rd_regs(priv, 0x0b, buf, 2);
-	if (ret)
-		goto err;
-
-	tmp = (buf[0] << 8) | buf[1];
-
-	/* report SNR in dB * 10 */
-	#define LOG10_20736_24 72422627 /* log10(20736) << 24 */
-	if (tmp)
-		*snr = (LOG10_20736_24 - intlog10(tmp)) / ((1 << 24) / 100);
-	else
-		*snr = 0;
-
-	return 0;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int hd29l2_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	int ret;
-	struct hd29l2_priv *priv = fe->demodulator_priv;
-	u8 buf[2];
-	u16 tmp;
-
-	*strength = 0;
-
-	ret = hd29l2_rd_regs(priv, 0xd5, buf, 2);
-	if (ret)
-		goto err;
-
-	tmp = buf[0] << 8 | buf[1];
-	tmp = ~tmp & 0x0fff;
-
-	/* scale value to 0x0000-0xffff from 0x0000-0x0fff */
-	*strength = tmp * 0xffff / 0x0fff;
-
-	return 0;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int hd29l2_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	int ret;
-	struct hd29l2_priv *priv = fe->demodulator_priv;
-	u8 buf[2];
-
-	if (!(priv->fe_status & FE_HAS_SYNC)) {
-		*ber = 0;
-		ret = 0;
-		goto err;
-	}
-
-	ret = hd29l2_rd_regs(priv, 0xd9, buf, 2);
-	if (ret) {
-		*ber = 0;
-		goto err;
-	}
-
-	/* LDPC BER */
-	*ber = ((buf[0] & 0x0f) << 8) | buf[1];
-
-	return 0;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int hd29l2_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	/* no way to read? */
-	*ucblocks = 0;
-	return 0;
-}
-
-static enum dvbfe_search hd29l2_search(struct dvb_frontend *fe)
-{
-	int ret, i;
-	struct hd29l2_priv *priv = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u8 tmp, buf[3];
-	u8 modulation, carrier, guard_interval, interleave, code_rate;
-	u64 num64;
-	u32 if_freq, if_ctl;
-	bool auto_mode;
-
-	dbg("%s: delivery_system=%d frequency=%d bandwidth_hz=%d " \
-		"modulation=%d inversion=%d fec_inner=%d guard_interval=%d",
-		 __func__,
-		c->delivery_system, c->frequency, c->bandwidth_hz,
-		c->modulation, c->inversion, c->fec_inner, c->guard_interval);
-
-	/* as for now we detect always params automatically */
-	auto_mode = true;
-
-	/* program tuner */
-	if (fe->ops.tuner_ops.set_params)
-		fe->ops.tuner_ops.set_params(fe);
-
-	/* get and program IF */
-	if (fe->ops.tuner_ops.get_if_frequency)
-		fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
-	else
-		if_freq = 0;
-
-	if (if_freq) {
-		/* normal IF */
-
-		/* calc IF control value */
-		num64 = if_freq;
-		num64 *= 0x800000;
-		num64 = div_u64(num64, HD29L2_XTAL);
-		num64 -= 0x800000;
-		if_ctl = num64;
-
-		tmp = 0xfc; /* tuner type normal */
-	} else {
-		/* zero IF */
-		if_ctl = 0;
-		tmp = 0xfe; /* tuner type Zero-IF */
-	}
-
-	buf[0] = ((if_ctl >>  0) & 0xff);
-	buf[1] = ((if_ctl >>  8) & 0xff);
-	buf[2] = ((if_ctl >> 16) & 0xff);
-
-	/* program IF control */
-	ret = hd29l2_wr_regs(priv, 0x14, buf, 3);
-	if (ret)
-		goto err;
-
-	/* program tuner type */
-	ret = hd29l2_wr_reg(priv, 0xab, tmp);
-	if (ret)
-		goto err;
-
-	dbg("%s: if_freq=%d if_ctl=%x", __func__, if_freq, if_ctl);
-
-	if (auto_mode) {
-		/*
-		 * use auto mode
-		 */
-
-		/* disable quick mode */
-		ret = hd29l2_wr_reg_mask(priv, 0xac, 0 << 7, 0x80);
-		if (ret)
-			goto err;
-
-		ret = hd29l2_wr_reg_mask(priv, 0x82, 1 << 1, 0x02);
-		if (ret)
-			goto err;
-
-		/* enable auto mode */
-		ret = hd29l2_wr_reg_mask(priv, 0x7d, 1 << 6, 0x40);
-		if (ret)
-			goto err;
-
-		ret = hd29l2_wr_reg_mask(priv, 0x81, 1 << 3, 0x08);
-		if (ret)
-			goto err;
-
-		/* soft reset */
-		ret = hd29l2_soft_reset(priv);
-		if (ret)
-			goto err;
-
-		/* detect modulation */
-		for (i = 30; i; i--) {
-			msleep(100);
-
-			ret = hd29l2_rd_reg(priv, 0x0d, &tmp);
-			if (ret)
-				goto err;
-
-			if ((((tmp & 0xf0) >= 0x10) &&
-				((tmp & 0x0f) == 0x08)) || (tmp >= 0x2c))
-				break;
-		}
-
-		dbg("%s: loop=%d", __func__, i);
-
-		if (i == 0)
-			/* detection failed */
-			return DVBFE_ALGO_SEARCH_FAILED;
-
-		/* read modulation */
-		ret = hd29l2_rd_reg_mask(priv, 0x7d, &modulation, 0x07);
-		if (ret)
-			goto err;
-	} else {
-		/*
-		 * use manual mode
-		 */
-
-		modulation = HD29L2_QAM64;
-		carrier = HD29L2_CARRIER_MULTI;
-		guard_interval = HD29L2_PN945;
-		interleave = HD29L2_INTERLEAVER_420;
-		code_rate = HD29L2_CODE_RATE_08;
-
-		tmp = (code_rate << 3) | modulation;
-		ret = hd29l2_wr_reg_mask(priv, 0x7d, tmp, 0x5f);
-		if (ret)
-			goto err;
-
-		tmp = (carrier << 2) | guard_interval;
-		ret = hd29l2_wr_reg_mask(priv, 0x81, tmp, 0x0f);
-		if (ret)
-			goto err;
-
-		tmp = interleave;
-		ret = hd29l2_wr_reg_mask(priv, 0x82, tmp, 0x03);
-		if (ret)
-			goto err;
-	}
-
-	/* ensure modulation validy */
-	/* 0=QAM4_NR, 1=QAM4, 2=QAM16, 3=QAM32, 4=QAM64 */
-	if (modulation > (ARRAY_SIZE(reg_mod_vals_tab[0].val) - 1)) {
-		dbg("%s: modulation=%d not valid", __func__, modulation);
-		goto err;
-	}
-
-	/* program registers according to modulation */
-	for (i = 0; i < ARRAY_SIZE(reg_mod_vals_tab); i++) {
-		ret = hd29l2_wr_reg(priv, reg_mod_vals_tab[i].reg,
-			reg_mod_vals_tab[i].val[modulation]);
-		if (ret)
-			goto err;
-	}
-
-	/* read guard interval */
-	ret = hd29l2_rd_reg_mask(priv, 0x81, &guard_interval, 0x03);
-	if (ret)
-		goto err;
-
-	/* read carrier mode */
-	ret = hd29l2_rd_reg_mask(priv, 0x81, &carrier, 0x04);
-	if (ret)
-		goto err;
-
-	dbg("%s: modulation=%d guard_interval=%d carrier=%d",
-		__func__, modulation, guard_interval, carrier);
-
-	if ((carrier == HD29L2_CARRIER_MULTI) && (modulation == HD29L2_QAM64) &&
-		(guard_interval == HD29L2_PN945)) {
-		dbg("%s: C=3780 && QAM64 && PN945", __func__);
-
-		ret = hd29l2_wr_reg(priv, 0x42, 0x33);
-		if (ret)
-			goto err;
-
-		ret = hd29l2_wr_reg(priv, 0xdd, 0x01);
-		if (ret)
-			goto err;
-	}
-
-	usleep_range(10000, 20000);
-
-	/* soft reset */
-	ret = hd29l2_soft_reset(priv);
-	if (ret)
-		goto err;
-
-	/* wait demod lock */
-	for (i = 30; i; i--) {
-		msleep(100);
-
-		/* read lock bit */
-		ret = hd29l2_rd_reg_mask(priv, 0x05, &tmp, 0x01);
-		if (ret)
-			goto err;
-
-		if (tmp)
-			break;
-	}
-
-	dbg("%s: loop=%d", __func__, i);
-
-	if (i == 0)
-		return DVBFE_ALGO_SEARCH_AGAIN;
-
-	return DVBFE_ALGO_SEARCH_SUCCESS;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return DVBFE_ALGO_SEARCH_ERROR;
-}
-
-static int hd29l2_get_frontend_algo(struct dvb_frontend *fe)
-{
-	return DVBFE_ALGO_CUSTOM;
-}
-
-static int hd29l2_get_frontend(struct dvb_frontend *fe)
-{
-	int ret;
-	struct hd29l2_priv *priv = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u8 buf[3];
-	u32 if_ctl;
-	char *str_constellation, *str_code_rate, *str_constellation_code_rate,
-		*str_guard_interval, *str_carrier, *str_guard_interval_carrier,
-		*str_interleave, *str_interleave_;
-
-	ret = hd29l2_rd_reg(priv, 0x7d, &buf[0]);
-	if (ret)
-		goto err;
-
-	ret = hd29l2_rd_regs(priv, 0x81, &buf[1], 2);
-	if (ret)
-		goto err;
-
-	/* constellation, 0x7d[2:0] */
-	switch ((buf[0] >> 0) & 0x07) {
-	case 0: /* QAM4NR */
-		str_constellation = "QAM4NR";
-		c->modulation = QAM_AUTO; /* FIXME */
-		break;
-	case 1: /* QAM4 */
-		str_constellation = "QAM4";
-		c->modulation = QPSK; /* FIXME */
-		break;
-	case 2:
-		str_constellation = "QAM16";
-		c->modulation = QAM_16;
-		break;
-	case 3:
-		str_constellation = "QAM32";
-		c->modulation = QAM_32;
-		break;
-	case 4:
-		str_constellation = "QAM64";
-		c->modulation = QAM_64;
-		break;
-	default:
-		str_constellation = "?";
-	}
-
-	/* LDPC code rate, 0x7d[4:3] */
-	switch ((buf[0] >> 3) & 0x03) {
-	case 0: /* 0.4 */
-		str_code_rate = "0.4";
-		c->fec_inner = FEC_AUTO; /* FIXME */
-		break;
-	case 1: /* 0.6 */
-		str_code_rate = "0.6";
-		c->fec_inner = FEC_3_5;
-		break;
-	case 2: /* 0.8 */
-		str_code_rate = "0.8";
-		c->fec_inner = FEC_4_5;
-		break;
-	default:
-		str_code_rate = "?";
-	}
-
-	/* constellation & code rate set, 0x7d[6] */
-	switch ((buf[0] >> 6) & 0x01) {
-	case 0:
-		str_constellation_code_rate = "manual";
-		break;
-	case 1:
-		str_constellation_code_rate = "auto";
-		break;
-	default:
-		str_constellation_code_rate = "?";
-	}
-
-	/* frame header, 0x81[1:0] */
-	switch ((buf[1] >> 0) & 0x03) {
-	case 0: /* PN945 */
-		str_guard_interval = "PN945";
-		c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */
-		break;
-	case 1: /* PN595 */
-		str_guard_interval = "PN595";
-		c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */
-		break;
-	case 2: /* PN420 */
-		str_guard_interval = "PN420";
-		c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */
-		break;
-	default:
-		str_guard_interval = "?";
-	}
-
-	/* carrier, 0x81[2] */
-	switch ((buf[1] >> 2) & 0x01) {
-	case 0:
-		str_carrier = "C=1";
-		break;
-	case 1:
-		str_carrier = "C=3780";
-		break;
-	default:
-		str_carrier = "?";
-	}
-
-	/* frame header & carrier set, 0x81[3] */
-	switch ((buf[1] >> 3) & 0x01) {
-	case 0:
-		str_guard_interval_carrier = "manual";
-		break;
-	case 1:
-		str_guard_interval_carrier = "auto";
-		break;
-	default:
-		str_guard_interval_carrier = "?";
-	}
-
-	/* interleave, 0x82[0] */
-	switch ((buf[2] >> 0) & 0x01) {
-	case 0:
-		str_interleave = "M=720";
-		break;
-	case 1:
-		str_interleave = "M=240";
-		break;
-	default:
-		str_interleave = "?";
-	}
-
-	/* interleave set, 0x82[1] */
-	switch ((buf[2] >> 1) & 0x01) {
-	case 0:
-		str_interleave_ = "manual";
-		break;
-	case 1:
-		str_interleave_ = "auto";
-		break;
-	default:
-		str_interleave_ = "?";
-	}
-
-	/*
-	 * We can read out current detected NCO and use that value next
-	 * time instead of calculating new value from targed IF.
-	 * I think it will not effect receiver sensitivity but gaining lock
-	 * after tune could be easier...
-	 */
-	ret = hd29l2_rd_regs(priv, 0xb1, &buf[0], 3);
-	if (ret)
-		goto err;
-
-	if_ctl = (buf[0] << 16) | ((buf[1] - 7) << 8) | buf[2];
-
-	dbg("%s: %s %s %s | %s %s %s | %s %s | NCO=%06x", __func__,
-		str_constellation, str_code_rate, str_constellation_code_rate,
-		str_guard_interval, str_carrier, str_guard_interval_carrier,
-		str_interleave, str_interleave_, if_ctl);
-
-	return 0;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int hd29l2_init(struct dvb_frontend *fe)
-{
-	int ret, i;
-	struct hd29l2_priv *priv = fe->demodulator_priv;
-	u8 tmp;
-	static const struct reg_val tab[] = {
-		{ 0x3a, 0x06 },
-		{ 0x3b, 0x03 },
-		{ 0x3c, 0x04 },
-		{ 0xaf, 0x06 },
-		{ 0xb0, 0x1b },
-		{ 0x80, 0x64 },
-		{ 0x10, 0x38 },
-	};
-
-	dbg("%s:", __func__);
-
-	/* reset demod */
-	/* it is recommended to HW reset chip using RST_N pin */
-	if (fe->callback) {
-		ret = fe->callback(fe, DVB_FRONTEND_COMPONENT_DEMOD, 0, 0);
-		if (ret)
-			goto err;
-
-		/* reprogramming needed because HW reset clears registers */
-		priv->tuner_i2c_addr_programmed = false;
-	}
-
-	/* init */
-	for (i = 0; i < ARRAY_SIZE(tab); i++) {
-		ret = hd29l2_wr_reg(priv, tab[i].reg, tab[i].val);
-		if (ret)
-			goto err;
-	}
-
-	/* TS params */
-	ret = hd29l2_rd_reg(priv, 0x36, &tmp);
-	if (ret)
-		goto err;
-
-	tmp &= 0x1b;
-	tmp |= priv->cfg.ts_mode;
-	ret = hd29l2_wr_reg(priv, 0x36, tmp);
-	if (ret)
-		goto err;
-
-	ret = hd29l2_rd_reg(priv, 0x31, &tmp);
-	tmp &= 0xef;
-
-	if (!(priv->cfg.ts_mode >> 7))
-		/* set b4 for serial TS */
-		tmp |= 0x10;
-
-	ret = hd29l2_wr_reg(priv, 0x31, tmp);
-	if (ret)
-		goto err;
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static void hd29l2_release(struct dvb_frontend *fe)
-{
-	struct hd29l2_priv *priv = fe->demodulator_priv;
-	kfree(priv);
-}
-
-static struct dvb_frontend_ops hd29l2_ops;
-
-struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config,
-	struct i2c_adapter *i2c)
-{
-	int ret;
-	struct hd29l2_priv *priv = NULL;
-	u8 tmp;
-
-	/* allocate memory for the internal state */
-	priv = kzalloc(sizeof(struct hd29l2_priv), GFP_KERNEL);
-	if (priv == NULL)
-		goto err;
-
-	/* setup the state */
-	priv->i2c = i2c;
-	memcpy(&priv->cfg, config, sizeof(struct hd29l2_config));
-
-
-	/* check if the demod is there */
-	ret = hd29l2_rd_reg(priv, 0x00, &tmp);
-	if (ret)
-		goto err;
-
-	/* create dvb_frontend */
-	memcpy(&priv->fe.ops, &hd29l2_ops, sizeof(struct dvb_frontend_ops));
-	priv->fe.demodulator_priv = priv;
-
-	return &priv->fe;
-err:
-	kfree(priv);
-	return NULL;
-}
-EXPORT_SYMBOL(hd29l2_attach);
-
-static struct dvb_frontend_ops hd29l2_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name = "HDIC HD29L2 DMB-TH",
-		.frequency_min = 474000000,
-		.frequency_max = 858000000,
-		.frequency_stepsize = 10000,
-		.caps = FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK |
-			FE_CAN_QAM_16 |
-			FE_CAN_QAM_32 |
-			FE_CAN_QAM_64 |
-			FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_BANDWIDTH_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_HIERARCHY_AUTO |
-			FE_CAN_RECOVER
-	},
-
-	.release = hd29l2_release,
-
-	.init = hd29l2_init,
-
-	.get_frontend_algo = hd29l2_get_frontend_algo,
-	.search = hd29l2_search,
-	.get_frontend = hd29l2_get_frontend,
-
-	.read_status = hd29l2_read_status,
-	.read_snr = hd29l2_read_snr,
-	.read_signal_strength = hd29l2_read_signal_strength,
-	.read_ber = hd29l2_read_ber,
-	.read_ucblocks = hd29l2_read_ucblocks,
-
-	.i2c_gate_ctrl = hd29l2_i2c_gate_ctrl,
-};
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("HDIC HD29L2 DMB-TH demodulator driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/hd29l2.h b/drivers/media/dvb/frontends/hd29l2.h
deleted file mode 100644
index a7a6443..0000000
--- a/drivers/media/dvb/frontends/hd29l2.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * HDIC HD29L2 DMB-TH demodulator driver
- *
- * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D
- *
- * Author: Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef HD29L2_H
-#define HD29L2_H
-
-#include <linux/dvb/frontend.h>
-
-struct hd29l2_config {
-	/*
-	 * demodulator I2C address
-	 */
-	u8 i2c_addr;
-
-	/*
-	 * tuner I2C address
-	 * only needed when tuner is behind demod I2C-gate
-	 */
-	u8 tuner_i2c_addr;
-
-	/*
-	 * TS settings
-	 */
-#define HD29L2_TS_SERIAL            0x00
-#define HD29L2_TS_PARALLEL          0x80
-#define HD29L2_TS_CLK_NORMAL        0x40
-#define HD29L2_TS_CLK_INVERTED      0x00
-#define HD29L2_TS_CLK_GATED         0x20
-#define HD29L2_TS_CLK_FREE          0x00
-	u8 ts_mode;
-};
-
-
-#if defined(CONFIG_DVB_HD29L2) || \
-	(defined(CONFIG_DVB_HD29L2_MODULE) && defined(MODULE))
-extern struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config,
-	struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *hd29l2_attach(
-const struct hd29l2_config *config, struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* HD29L2_H */
diff --git a/drivers/media/dvb/frontends/hd29l2_priv.h b/drivers/media/dvb/frontends/hd29l2_priv.h
deleted file mode 100644
index ba16dc3..0000000
--- a/drivers/media/dvb/frontends/hd29l2_priv.h
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * HDIC HD29L2 DMB-TH demodulator driver
- *
- * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D
- *
- * Author: Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef HD29L2_PRIV
-#define HD29L2_PRIV
-
-#include <linux/dvb/version.h>
-#include "dvb_frontend.h"
-#include "dvb_math.h"
-#include "hd29l2.h"
-
-#define LOG_PREFIX "hd29l2"
-
-#undef dbg
-#define dbg(f, arg...) \
-	if (hd29l2_debug) \
-		printk(KERN_INFO   LOG_PREFIX": " f "\n" , ## arg)
-#undef err
-#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
-#undef info
-#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
-#undef warn
-#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
-
-#define HD29L2_XTAL 30400000 /* Hz */
-
-
-#define HD29L2_QAM4NR 0x00
-#define HD29L2_QAM4   0x01
-#define HD29L2_QAM16  0x02
-#define HD29L2_QAM32  0x03
-#define HD29L2_QAM64  0x04
-
-#define HD29L2_CODE_RATE_04 0x00
-#define HD29L2_CODE_RATE_06 0x08
-#define HD29L2_CODE_RATE_08 0x10
-
-#define HD29L2_PN945 0x00
-#define HD29L2_PN595 0x01
-#define HD29L2_PN420 0x02
-
-#define HD29L2_CARRIER_SINGLE 0x00
-#define HD29L2_CARRIER_MULTI  0x01
-
-#define HD29L2_INTERLEAVER_720 0x00
-#define HD29L2_INTERLEAVER_420 0x01
-
-struct reg_val {
-	u8 reg;
-	u8 val;
-};
-
-struct reg_mod_vals {
-	u8 reg;
-	u8 val[5];
-};
-
-struct hd29l2_priv {
-	struct i2c_adapter *i2c;
-	struct dvb_frontend fe;
-	struct hd29l2_config cfg;
-	u8 tuner_i2c_addr_programmed:1;
-
-	fe_status_t fe_status;
-};
-
-static const struct reg_mod_vals reg_mod_vals_tab[] = {
-	/* REG, QAM4NR, QAM4,QAM16,QAM32,QAM64 */
-	{ 0x01, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
-	{ 0x02, { 0x07, 0x07, 0x07, 0x07, 0x07 } },
-	{ 0x03, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
-	{ 0x04, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0x05, { 0x61, 0x60, 0x60, 0x61, 0x60 } },
-	{ 0x06, { 0xff, 0xff, 0xff, 0xff, 0xff } },
-	{ 0x07, { 0xff, 0xff, 0xff, 0xff, 0xff } },
-	{ 0x08, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0x09, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0x0a, { 0x15, 0x15, 0x03, 0x03, 0x03 } },
-	{ 0x0d, { 0x78, 0x78, 0x88, 0x78, 0x78 } },
-	{ 0x0e, { 0xa0, 0x90, 0xa0, 0xa0, 0xa0 } },
-	{ 0x0f, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0x10, { 0xa0, 0xa0, 0x58, 0x38, 0x38 } },
-	{ 0x11, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0x12, { 0x5a, 0x5a, 0x5a, 0x5a, 0x5a } },
-	{ 0x13, { 0xa2, 0xa2, 0xa2, 0xa2, 0xa2 } },
-	{ 0x17, { 0x40, 0x40, 0x40, 0x40, 0x40 } },
-	{ 0x18, { 0x21, 0x21, 0x42, 0x52, 0x42 } },
-	{ 0x19, { 0x21, 0x21, 0x62, 0x72, 0x62 } },
-	{ 0x1a, { 0x32, 0x43, 0xa9, 0xb9, 0xa9 } },
-	{ 0x1b, { 0x32, 0x43, 0xb9, 0xd8, 0xb9 } },
-	{ 0x1c, { 0x02, 0x02, 0x03, 0x02, 0x03 } },
-	{ 0x1d, { 0x0c, 0x0c, 0x01, 0x02, 0x02 } },
-	{ 0x1e, { 0x02, 0x02, 0x02, 0x01, 0x02 } },
-	{ 0x1f, { 0x02, 0x02, 0x01, 0x02, 0x04 } },
-	{ 0x20, { 0x01, 0x02, 0x01, 0x01, 0x01 } },
-	{ 0x21, { 0x08, 0x08, 0x0a, 0x0a, 0x0a } },
-	{ 0x22, { 0x06, 0x06, 0x04, 0x05, 0x05 } },
-	{ 0x23, { 0x06, 0x06, 0x05, 0x03, 0x05 } },
-	{ 0x24, { 0x08, 0x08, 0x05, 0x07, 0x07 } },
-	{ 0x25, { 0x16, 0x10, 0x10, 0x0a, 0x10 } },
-	{ 0x26, { 0x14, 0x14, 0x04, 0x04, 0x04 } },
-	{ 0x27, { 0x58, 0x58, 0x58, 0x5c, 0x58 } },
-	{ 0x28, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
-	{ 0x29, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
-	{ 0x2a, { 0x08, 0x0a, 0x08, 0x08, 0x08 } },
-	{ 0x2b, { 0x08, 0x08, 0x08, 0x08, 0x08 } },
-	{ 0x2c, { 0x06, 0x06, 0x06, 0x06, 0x06 } },
-	{ 0x2d, { 0x05, 0x06, 0x06, 0x06, 0x06 } },
-	{ 0x2e, { 0x21, 0x21, 0x21, 0x21, 0x21 } },
-	{ 0x2f, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0x30, { 0x14, 0x14, 0x14, 0x14, 0x14 } },
-	{ 0x33, { 0xb7, 0xb7, 0xb7, 0xb7, 0xb7 } },
-	{ 0x34, { 0x81, 0x81, 0x81, 0x81, 0x81 } },
-	{ 0x35, { 0x80, 0x80, 0x80, 0x80, 0x80 } },
-	{ 0x37, { 0x70, 0x70, 0x70, 0x70, 0x70 } },
-	{ 0x38, { 0x04, 0x04, 0x02, 0x02, 0x02 } },
-	{ 0x39, { 0x07, 0x07, 0x05, 0x05, 0x05 } },
-	{ 0x3a, { 0x06, 0x06, 0x06, 0x06, 0x06 } },
-	{ 0x3b, { 0x03, 0x03, 0x03, 0x03, 0x03 } },
-	{ 0x3c, { 0x07, 0x06, 0x04, 0x04, 0x04 } },
-	{ 0x3d, { 0xf0, 0xf0, 0xf0, 0xf0, 0x80 } },
-	{ 0x3e, { 0x60, 0x60, 0x60, 0x60, 0xff } },
-	{ 0x3f, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0x40, { 0x5b, 0x5b, 0x5b, 0x57, 0x50 } },
-	{ 0x41, { 0x30, 0x30, 0x30, 0x30, 0x18 } },
-	{ 0x42, { 0x20, 0x20, 0x20, 0x00, 0x30 } },
-	{ 0x43, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0x44, { 0x3f, 0x3f, 0x3f, 0x3f, 0x3f } },
-	{ 0x45, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0x46, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
-	{ 0x47, { 0x00, 0x00, 0x95, 0x00, 0x95 } },
-	{ 0x48, { 0xc0, 0xc0, 0xc0, 0xc0, 0xc0 } },
-	{ 0x49, { 0xc0, 0xc0, 0xc0, 0xc0, 0xc0 } },
-	{ 0x4a, { 0x40, 0x40, 0x33, 0x11, 0x11 } },
-	{ 0x4b, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
-	{ 0x4c, { 0x40, 0x40, 0x99, 0x11, 0x11 } },
-	{ 0x4d, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
-	{ 0x4e, { 0x40, 0x40, 0x66, 0x77, 0x77 } },
-	{ 0x4f, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
-	{ 0x50, { 0x40, 0x40, 0x88, 0x33, 0x11 } },
-	{ 0x51, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
-	{ 0x52, { 0x40, 0x40, 0x88, 0x02, 0x02 } },
-	{ 0x53, { 0x40, 0x40, 0x00, 0x02, 0x02 } },
-	{ 0x54, { 0x00, 0x00, 0x88, 0x33, 0x33 } },
-	{ 0x55, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
-	{ 0x56, { 0x00, 0x00, 0x00, 0x0b, 0x00 } },
-	{ 0x57, { 0x40, 0x40, 0x0a, 0x0b, 0x0a } },
-	{ 0x58, { 0xaa, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0x59, { 0x7a, 0x40, 0x02, 0x02, 0x02 } },
-	{ 0x5a, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
-	{ 0x5b, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
-	{ 0x5c, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
-	{ 0x5d, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
-	{ 0x5e, { 0xc0, 0xc0, 0xc0, 0xff, 0xc0 } },
-	{ 0x5f, { 0xc0, 0xc0, 0xc0, 0xff, 0xc0 } },
-	{ 0x60, { 0x40, 0x40, 0x00, 0x30, 0x30 } },
-	{ 0x61, { 0x40, 0x40, 0x10, 0x30, 0x30 } },
-	{ 0x62, { 0x40, 0x40, 0x00, 0x30, 0x30 } },
-	{ 0x63, { 0x40, 0x40, 0x05, 0x30, 0x30 } },
-	{ 0x64, { 0x40, 0x40, 0x06, 0x00, 0x30 } },
-	{ 0x65, { 0x40, 0x40, 0x06, 0x08, 0x30 } },
-	{ 0x66, { 0x40, 0x40, 0x00, 0x00, 0x20 } },
-	{ 0x67, { 0x40, 0x40, 0x01, 0x04, 0x20 } },
-	{ 0x68, { 0x00, 0x00, 0x30, 0x00, 0x20 } },
-	{ 0x69, { 0xa0, 0xa0, 0x00, 0x08, 0x20 } },
-	{ 0x6a, { 0x00, 0x00, 0x30, 0x00, 0x25 } },
-	{ 0x6b, { 0xa0, 0xa0, 0x00, 0x06, 0x25 } },
-	{ 0x6c, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0x6d, { 0xa0, 0x60, 0x0c, 0x03, 0x0c } },
-	{ 0x6e, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0x6f, { 0xa0, 0x60, 0x04, 0x01, 0x04 } },
-	{ 0x70, { 0x58, 0x58, 0xaa, 0xaa, 0xaa } },
-	{ 0x71, { 0x58, 0x58, 0xaa, 0xaa, 0xaa } },
-	{ 0x72, { 0x58, 0x58, 0xff, 0xff, 0xff } },
-	{ 0x73, { 0x58, 0x58, 0xff, 0xff, 0xff } },
-	{ 0x74, { 0x06, 0x06, 0x09, 0x05, 0x05 } },
-	{ 0x75, { 0x06, 0x06, 0x0a, 0x10, 0x10 } },
-	{ 0x76, { 0x10, 0x10, 0x06, 0x0a, 0x0a } },
-	{ 0x77, { 0x12, 0x18, 0x28, 0x10, 0x28 } },
-	{ 0x78, { 0xf8, 0xf8, 0xf8, 0xf8, 0xf8 } },
-	{ 0x79, { 0x15, 0x15, 0x03, 0x03, 0x03 } },
-	{ 0x7a, { 0x02, 0x02, 0x01, 0x04, 0x03 } },
-	{ 0x7b, { 0x01, 0x02, 0x03, 0x03, 0x03 } },
-	{ 0x7c, { 0x28, 0x28, 0x28, 0x28, 0x28 } },
-	{ 0x7f, { 0x25, 0x92, 0x5f, 0x17, 0x2d } },
-	{ 0x80, { 0x64, 0x64, 0x64, 0x74, 0x64 } },
-	{ 0x83, { 0x06, 0x03, 0x04, 0x04, 0x04 } },
-	{ 0x84, { 0xff, 0xff, 0xff, 0xff, 0xff } },
-	{ 0x85, { 0x05, 0x05, 0x05, 0x05, 0x05 } },
-	{ 0x86, { 0x00, 0x00, 0x11, 0x11, 0x11 } },
-	{ 0x87, { 0x03, 0x03, 0x03, 0x03, 0x03 } },
-	{ 0x88, { 0x09, 0x09, 0x09, 0x09, 0x09 } },
-	{ 0x89, { 0x20, 0x20, 0x30, 0x20, 0x20 } },
-	{ 0x8a, { 0x03, 0x03, 0x02, 0x03, 0x02 } },
-	{ 0x8b, { 0x00, 0x07, 0x09, 0x00, 0x09 } },
-	{ 0x8c, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0x8d, { 0x4f, 0x4f, 0x4f, 0x3f, 0x4f } },
-	{ 0x8e, { 0xf0, 0xf0, 0x60, 0xf0, 0xa0 } },
-	{ 0x8f, { 0xe8, 0xe8, 0xe8, 0xe8, 0xe8 } },
-	{ 0x90, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
-	{ 0x91, { 0x40, 0x40, 0x70, 0x70, 0x10 } },
-	{ 0x92, { 0x00, 0x00, 0x00, 0x00, 0x04 } },
-	{ 0x93, { 0x60, 0x60, 0x60, 0x60, 0x60 } },
-	{ 0x94, { 0x00, 0x00, 0x00, 0x00, 0x03 } },
-	{ 0x95, { 0x09, 0x09, 0x47, 0x47, 0x47 } },
-	{ 0x96, { 0x80, 0xa0, 0xa0, 0x40, 0xa0 } },
-	{ 0x97, { 0x60, 0x60, 0x60, 0x60, 0x60 } },
-	{ 0x98, { 0x50, 0x50, 0x50, 0x30, 0x50 } },
-	{ 0x99, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
-	{ 0x9a, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0x9b, { 0x40, 0x40, 0x40, 0x30, 0x40 } },
-	{ 0x9c, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xa0, { 0xf0, 0xf0, 0xf0, 0xf0, 0xf0 } },
-	{ 0xa1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xa2, { 0x30, 0x30, 0x00, 0x30, 0x00 } },
-	{ 0xa3, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xa4, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xa5, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xa6, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xa7, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xa8, { 0x77, 0x77, 0x77, 0x77, 0x77 } },
-	{ 0xa9, { 0x02, 0x02, 0x02, 0x02, 0x02 } },
-	{ 0xaa, { 0x40, 0x40, 0x40, 0x40, 0x40 } },
-	{ 0xac, { 0x1f, 0x1f, 0x1f, 0x1f, 0x1f } },
-	{ 0xad, { 0x14, 0x14, 0x14, 0x14, 0x14 } },
-	{ 0xae, { 0x78, 0x78, 0x78, 0x78, 0x78 } },
-	{ 0xaf, { 0x06, 0x06, 0x06, 0x06, 0x07 } },
-	{ 0xb0, { 0x1b, 0x1b, 0x1b, 0x19, 0x1b } },
-	{ 0xb1, { 0x18, 0x17, 0x17, 0x18, 0x17 } },
-	{ 0xb2, { 0x35, 0x82, 0x82, 0x38, 0x82 } },
-	{ 0xb3, { 0xb6, 0xce, 0xc7, 0x5c, 0xb0 } },
-	{ 0xb4, { 0x3f, 0x3e, 0x3e, 0x3f, 0x3e } },
-	{ 0xb5, { 0x70, 0x58, 0x50, 0x68, 0x50 } },
-	{ 0xb6, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xb7, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xb8, { 0x03, 0x03, 0x01, 0x01, 0x01 } },
-	{ 0xb9, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xba, { 0x06, 0x06, 0x0a, 0x05, 0x0a } },
-	{ 0xbb, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xbc, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xbd, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xbe, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xbf, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xc0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xc1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xc2, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xc3, { 0x00, 0x00, 0x88, 0x66, 0x88 } },
-	{ 0xc4, { 0x10, 0x10, 0x00, 0x00, 0x00 } },
-	{ 0xc5, { 0x00, 0x00, 0x44, 0x60, 0x44 } },
-	{ 0xc6, { 0x10, 0x0a, 0x00, 0x00, 0x00 } },
-	{ 0xc7, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xc8, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xc9, { 0x90, 0x04, 0x00, 0x00, 0x00 } },
-	{ 0xca, { 0x90, 0x08, 0x01, 0x01, 0x01 } },
-	{ 0xcb, { 0xa0, 0x04, 0x00, 0x44, 0x00 } },
-	{ 0xcc, { 0xa0, 0x10, 0x03, 0x00, 0x03 } },
-	{ 0xcd, { 0x06, 0x06, 0x06, 0x05, 0x06 } },
-	{ 0xce, { 0x05, 0x05, 0x01, 0x01, 0x01 } },
-	{ 0xcf, { 0x40, 0x20, 0x18, 0x18, 0x18 } },
-	{ 0xd0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xd1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xd2, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xd3, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xd4, { 0x05, 0x05, 0x05, 0x05, 0x05 } },
-	{ 0xd5, { 0x05, 0x05, 0x05, 0x03, 0x05 } },
-	{ 0xd6, { 0xac, 0x22, 0xca, 0x8f, 0xca } },
-	{ 0xd7, { 0x20, 0x20, 0x20, 0x20, 0x20 } },
-	{ 0xd8, { 0x01, 0x01, 0x01, 0x01, 0x01 } },
-	{ 0xd9, { 0x00, 0x00, 0x0f, 0x00, 0x0f } },
-	{ 0xda, { 0x00, 0xff, 0xff, 0x0e, 0xff } },
-	{ 0xdb, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
-	{ 0xdc, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
-	{ 0xdd, { 0x05, 0x05, 0x05, 0x05, 0x05 } },
-	{ 0xde, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
-	{ 0xdf, { 0x42, 0x42, 0x44, 0x44, 0x04 } },
-	{ 0xe0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xe1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xe2, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xe3, { 0x00, 0x00, 0x26, 0x06, 0x26 } },
-	{ 0xe4, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xe5, { 0x01, 0x0a, 0x01, 0x01, 0x01 } },
-	{ 0xe6, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xe7, { 0x08, 0x08, 0x08, 0x08, 0x08 } },
-	{ 0xe8, { 0x63, 0x63, 0x63, 0x63, 0x63 } },
-	{ 0xe9, { 0x59, 0x59, 0x59, 0x59, 0x59 } },
-	{ 0xea, { 0x80, 0x80, 0x20, 0x80, 0x80 } },
-	{ 0xeb, { 0x37, 0x37, 0x78, 0x37, 0x77 } },
-	{ 0xec, { 0x1f, 0x1f, 0x25, 0x25, 0x25 } },
-	{ 0xed, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
-	{ 0xee, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-	{ 0xef, { 0x70, 0x70, 0x58, 0x38, 0x58 } },
-	{ 0xf0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-};
-
-#endif /* HD29L2_PRIV */
diff --git a/drivers/media/dvb/frontends/isl6405.c b/drivers/media/dvb/frontends/isl6405.c
deleted file mode 100644
index 33d33f4..0000000
--- a/drivers/media/dvb/frontends/isl6405.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * isl6405.c - driver for dual lnb supply and control ic ISL6405
- *
- * Copyright (C) 2008 Hartmut Hackmann
- * Copyright (C) 2006 Oliver Endriss
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org
- */
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "isl6405.h"
-
-struct isl6405 {
-	u8			config;
-	u8			override_or;
-	u8			override_and;
-	struct i2c_adapter	*i2c;
-	u8			i2c_addr;
-};
-
-static int isl6405_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
-	struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv;
-	struct i2c_msg msg = {	.addr = isl6405->i2c_addr, .flags = 0,
-				.buf = &isl6405->config,
-				.len = sizeof(isl6405->config) };
-
-	if (isl6405->override_or & 0x80) {
-		isl6405->config &= ~(ISL6405_VSEL2 | ISL6405_EN2);
-		switch (voltage) {
-		case SEC_VOLTAGE_OFF:
-			break;
-		case SEC_VOLTAGE_13:
-			isl6405->config |= ISL6405_EN2;
-			break;
-		case SEC_VOLTAGE_18:
-			isl6405->config |= (ISL6405_EN2 | ISL6405_VSEL2);
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else {
-		isl6405->config &= ~(ISL6405_VSEL1 | ISL6405_EN1);
-		switch (voltage) {
-		case SEC_VOLTAGE_OFF:
-			break;
-		case SEC_VOLTAGE_13:
-			isl6405->config |= ISL6405_EN1;
-			break;
-		case SEC_VOLTAGE_18:
-			isl6405->config |= (ISL6405_EN1 | ISL6405_VSEL1);
-			break;
-		default:
-			return -EINVAL;
-		};
-	}
-	isl6405->config |= isl6405->override_or;
-	isl6405->config &= isl6405->override_and;
-
-	return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static int isl6405_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
-{
-	struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv;
-	struct i2c_msg msg = {	.addr = isl6405->i2c_addr, .flags = 0,
-				.buf = &isl6405->config,
-				.len = sizeof(isl6405->config) };
-
-	if (isl6405->override_or & 0x80) {
-		if (arg)
-			isl6405->config |= ISL6405_LLC2;
-		else
-			isl6405->config &= ~ISL6405_LLC2;
-	} else {
-		if (arg)
-			isl6405->config |= ISL6405_LLC1;
-		else
-			isl6405->config &= ~ISL6405_LLC1;
-	}
-	isl6405->config |= isl6405->override_or;
-	isl6405->config &= isl6405->override_and;
-
-	return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static void isl6405_release(struct dvb_frontend *fe)
-{
-	/* power off */
-	isl6405_set_voltage(fe, SEC_VOLTAGE_OFF);
-
-	/* free */
-	kfree(fe->sec_priv);
-	fe->sec_priv = NULL;
-}
-
-struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c,
-				    u8 i2c_addr, u8 override_set, u8 override_clear)
-{
-	struct isl6405 *isl6405 = kmalloc(sizeof(struct isl6405), GFP_KERNEL);
-	if (!isl6405)
-		return NULL;
-
-	/* default configuration */
-	if (override_set & 0x80)
-		isl6405->config = ISL6405_ISEL2;
-	else
-		isl6405->config = ISL6405_ISEL1;
-	isl6405->i2c = i2c;
-	isl6405->i2c_addr = i2c_addr;
-	fe->sec_priv = isl6405;
-
-	/* bits which should be forced to '1' */
-	isl6405->override_or = override_set;
-
-	/* bits which should be forced to '0' */
-	isl6405->override_and = ~override_clear;
-
-	/* detect if it is present or not */
-	if (isl6405_set_voltage(fe, SEC_VOLTAGE_OFF)) {
-		kfree(isl6405);
-		fe->sec_priv = NULL;
-		return NULL;
-	}
-
-	/* install release callback */
-	fe->ops.release_sec = isl6405_release;
-
-	/* override frontend ops */
-	fe->ops.set_voltage = isl6405_set_voltage;
-	fe->ops.enable_high_lnb_voltage = isl6405_enable_high_lnb_voltage;
-
-	return fe;
-}
-EXPORT_SYMBOL(isl6405_attach);
-
-MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6405");
-MODULE_AUTHOR("Hartmut Hackmann & Oliver Endriss");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/isl6405.h b/drivers/media/dvb/frontends/isl6405.h
deleted file mode 100644
index 1c793d3..0000000
--- a/drivers/media/dvb/frontends/isl6405.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * isl6405.h - driver for dual lnb supply and control ic ISL6405
- *
- * Copyright (C) 2008 Hartmut Hackmann
- * Copyright (C) 2006 Oliver Endriss
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org
- */
-
-#ifndef _ISL6405_H
-#define _ISL6405_H
-
-#include <linux/dvb/frontend.h>
-
-/* system register bits */
-
-/* this bit selects register (control) 1 or 2
-   note that the bit maps are different */
-
-#define ISL6405_SR	0x80
-
-/* SR = 0 */
-#define ISL6405_OLF1	0x01
-#define ISL6405_EN1	0x02
-#define ISL6405_VSEL1	0x04
-#define ISL6405_LLC1	0x08
-#define ISL6405_ENT1	0x10
-#define ISL6405_ISEL1	0x20
-#define ISL6405_DCL	0x40
-
-/* SR = 1 */
-#define ISL6405_OLF2	0x01
-#define ISL6405_OTF	0x02
-#define ISL6405_EN2	0x04
-#define ISL6405_VSEL2	0x08
-#define ISL6405_LLC2	0x10
-#define ISL6405_ENT2	0x20
-#define ISL6405_ISEL2	0x40
-
-#if defined(CONFIG_DVB_ISL6405) || (defined(CONFIG_DVB_ISL6405_MODULE) && defined(MODULE))
-/* override_set and override_clear control which system register bits (above)
- * to always set & clear
- */
-extern struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c,
-					   u8 i2c_addr, u8 override_set, u8 override_clear);
-#else
-static inline struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe,
-						  struct i2c_adapter *i2c, u8 i2c_addr,
-						  u8 override_set, u8 override_clear)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_ISL6405 */
-
-#endif
diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb/frontends/isl6421.c
deleted file mode 100644
index 684c8ec..0000000
--- a/drivers/media/dvb/frontends/isl6421.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * isl6421.h - driver for lnb supply and control ic ISL6421
- *
- * Copyright (C) 2006 Andrew de Quincey
- * Copyright (C) 2006 Oliver Endriss
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org
- */
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "isl6421.h"
-
-struct isl6421 {
-	u8			config;
-	u8			override_or;
-	u8			override_and;
-	struct i2c_adapter	*i2c;
-	u8			i2c_addr;
-};
-
-static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
-	struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv;
-	struct i2c_msg msg = {	.addr = isl6421->i2c_addr, .flags = 0,
-				.buf = &isl6421->config,
-				.len = sizeof(isl6421->config) };
-
-	isl6421->config &= ~(ISL6421_VSEL1 | ISL6421_EN1);
-
-	switch(voltage) {
-	case SEC_VOLTAGE_OFF:
-		break;
-	case SEC_VOLTAGE_13:
-		isl6421->config |= ISL6421_EN1;
-		break;
-	case SEC_VOLTAGE_18:
-		isl6421->config |= (ISL6421_EN1 | ISL6421_VSEL1);
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	isl6421->config |= isl6421->override_or;
-	isl6421->config &= isl6421->override_and;
-
-	return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
-{
-	struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv;
-	struct i2c_msg msg = {	.addr = isl6421->i2c_addr, .flags = 0,
-				.buf = &isl6421->config,
-				.len = sizeof(isl6421->config) };
-
-	if (arg)
-		isl6421->config |= ISL6421_LLC1;
-	else
-		isl6421->config &= ~ISL6421_LLC1;
-
-	isl6421->config |= isl6421->override_or;
-	isl6421->config &= isl6421->override_and;
-
-	return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static void isl6421_release(struct dvb_frontend *fe)
-{
-	/* power off */
-	isl6421_set_voltage(fe, SEC_VOLTAGE_OFF);
-
-	/* free */
-	kfree(fe->sec_priv);
-	fe->sec_priv = NULL;
-}
-
-struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
-		   u8 override_set, u8 override_clear)
-{
-	struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL);
-	if (!isl6421)
-		return NULL;
-
-	/* default configuration */
-	isl6421->config = ISL6421_ISEL1;
-	isl6421->i2c = i2c;
-	isl6421->i2c_addr = i2c_addr;
-	fe->sec_priv = isl6421;
-
-	/* bits which should be forced to '1' */
-	isl6421->override_or = override_set;
-
-	/* bits which should be forced to '0' */
-	isl6421->override_and = ~override_clear;
-
-	/* detect if it is present or not */
-	if (isl6421_set_voltage(fe, SEC_VOLTAGE_OFF)) {
-		kfree(isl6421);
-		fe->sec_priv = NULL;
-		return NULL;
-	}
-
-	/* install release callback */
-	fe->ops.release_sec = isl6421_release;
-
-	/* override frontend ops */
-	fe->ops.set_voltage = isl6421_set_voltage;
-	fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage;
-
-	return fe;
-}
-EXPORT_SYMBOL(isl6421_attach);
-
-MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6421");
-MODULE_AUTHOR("Andrew de Quincey & Oliver Endriss");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/isl6421.h b/drivers/media/dvb/frontends/isl6421.h
deleted file mode 100644
index 47e4518..0000000
--- a/drivers/media/dvb/frontends/isl6421.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * isl6421.h - driver for lnb supply and control ic ISL6421
- *
- * Copyright (C) 2006 Andrew de Quincey
- * Copyright (C) 2006 Oliver Endriss
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org
- */
-
-#ifndef _ISL6421_H
-#define _ISL6421_H
-
-#include <linux/dvb/frontend.h>
-
-/* system register bits */
-#define ISL6421_OLF1	0x01
-#define ISL6421_EN1	0x02
-#define ISL6421_VSEL1	0x04
-#define ISL6421_LLC1	0x08
-#define ISL6421_ENT1	0x10
-#define ISL6421_ISEL1	0x20
-#define ISL6421_DCL	0x40
-
-#if defined(CONFIG_DVB_ISL6421) || (defined(CONFIG_DVB_ISL6421_MODULE) && defined(MODULE))
-/* override_set and override_clear control which system register bits (above) to always set & clear */
-extern struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
-			  u8 override_set, u8 override_clear);
-#else
-static inline struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
-						  u8 override_set, u8 override_clear)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_ISL6421
-
-#endif
diff --git a/drivers/media/dvb/frontends/isl6423.c b/drivers/media/dvb/frontends/isl6423.c
deleted file mode 100644
index dca5beb..0000000
--- a/drivers/media/dvb/frontends/isl6423.c
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
-	Intersil ISL6423 SEC and LNB Power supply controller
-
-	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "isl6423.h"
-
-static unsigned int verbose;
-module_param(verbose, int, 0644);
-MODULE_PARM_DESC(verbose, "Set Verbosity level");
-
-#define FE_ERROR				0
-#define FE_NOTICE				1
-#define FE_INFO					2
-#define FE_DEBUG				3
-#define FE_DEBUGREG				4
-
-#define dprintk(__y, __z, format, arg...) do {						\
-	if (__z) {									\
-		if	((verbose > FE_ERROR) && (verbose > __y))			\
-			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);		\
-		else if	((verbose > FE_NOTICE) && (verbose > __y))			\
-			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
-		else if ((verbose > FE_INFO) && (verbose > __y))			\
-			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);		\
-		else if ((verbose > FE_DEBUG) && (verbose > __y))			\
-			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
-	} else {									\
-		if (verbose > __y)							\
-			printk(format, ##arg);						\
-	}										\
-} while (0)
-
-struct isl6423_dev {
-	const struct isl6423_config	*config;
-	struct i2c_adapter		*i2c;
-
-	u8 reg_3;
-	u8 reg_4;
-
-	unsigned int verbose;
-};
-
-static int isl6423_write(struct isl6423_dev *isl6423, u8 reg)
-{
-	struct i2c_adapter *i2c = isl6423->i2c;
-	u8 addr			= isl6423->config->addr;
-	int err = 0;
-
-	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = &reg, .len = 1 };
-
-	dprintk(FE_DEBUG, 1, "write reg %02X", reg);
-	err = i2c_transfer(i2c, &msg, 1);
-	if (err < 0)
-		goto exit;
-	return 0;
-
-exit:
-	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
-	return err;
-}
-
-static int isl6423_set_modulation(struct dvb_frontend *fe)
-{
-	struct isl6423_dev *isl6423		= (struct isl6423_dev *) fe->sec_priv;
-	const struct isl6423_config *config	= isl6423->config;
-	int err = 0;
-	u8 reg_2 = 0;
-
-	reg_2 = 0x01 << 5;
-
-	if (config->mod_extern)
-		reg_2 |= (1 << 3);
-	else
-		reg_2 |= (1 << 4);
-
-	err = isl6423_write(isl6423, reg_2);
-	if (err < 0)
-		goto exit;
-	return 0;
-
-exit:
-	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
-	return err;
-}
-
-static int isl6423_voltage_boost(struct dvb_frontend *fe, long arg)
-{
-	struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
-	u8 reg_3 = isl6423->reg_3;
-	u8 reg_4 = isl6423->reg_4;
-	int err = 0;
-
-	if (arg) {
-		/* EN = 1, VSPEN = 1, VBOT = 1 */
-		reg_4 |= (1 << 4);
-		reg_4 |= 0x1;
-		reg_3 |= (1 << 3);
-	} else {
-		/* EN = 1, VSPEN = 1, VBOT = 0 */
-		reg_4 |= (1 << 4);
-		reg_4 &= ~0x1;
-		reg_3 |= (1 << 3);
-	}
-	err = isl6423_write(isl6423, reg_3);
-	if (err < 0)
-		goto exit;
-
-	err = isl6423_write(isl6423, reg_4);
-	if (err < 0)
-		goto exit;
-
-	isl6423->reg_3 = reg_3;
-	isl6423->reg_4 = reg_4;
-
-	return 0;
-exit:
-	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
-	return err;
-}
-
-
-static int isl6423_set_voltage(struct dvb_frontend *fe,
-			       enum fe_sec_voltage voltage)
-{
-	struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
-	u8 reg_3 = isl6423->reg_3;
-	u8 reg_4 = isl6423->reg_4;
-	int err = 0;
-
-	switch (voltage) {
-	case SEC_VOLTAGE_OFF:
-		/* EN = 0 */
-		reg_4 &= ~(1 << 4);
-		break;
-
-	case SEC_VOLTAGE_13:
-		/* EN = 1, VSPEN = 1, VTOP = 0, VBOT = 0 */
-		reg_4 |= (1 << 4);
-		reg_4 &= ~0x3;
-		reg_3 |= (1 << 3);
-		break;
-
-	case SEC_VOLTAGE_18:
-		/* EN = 1, VSPEN = 1, VTOP = 1, VBOT = 0 */
-		reg_4 |= (1 << 4);
-		reg_4 |=  0x2;
-		reg_4 &= ~0x1;
-		reg_3 |= (1 << 3);
-		break;
-
-	default:
-		break;
-	}
-	err = isl6423_write(isl6423, reg_3);
-	if (err < 0)
-		goto exit;
-
-	err = isl6423_write(isl6423, reg_4);
-	if (err < 0)
-		goto exit;
-
-	isl6423->reg_3 = reg_3;
-	isl6423->reg_4 = reg_4;
-
-	return 0;
-exit:
-	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
-	return err;
-}
-
-static int isl6423_set_current(struct dvb_frontend *fe)
-{
-	struct isl6423_dev *isl6423		= (struct isl6423_dev *) fe->sec_priv;
-	u8 reg_3 = isl6423->reg_3;
-	const struct isl6423_config *config	= isl6423->config;
-	int err = 0;
-
-	switch (config->current_max) {
-	case SEC_CURRENT_275m:
-		/* 275mA */
-		/* ISELH = 0, ISELL = 0 */
-		reg_3 &= ~0x3;
-		break;
-
-	case SEC_CURRENT_515m:
-		/* 515mA */
-		/* ISELH = 0, ISELL = 1 */
-		reg_3 &= ~0x2;
-		reg_3 |=  0x1;
-		break;
-
-	case SEC_CURRENT_635m:
-		/* 635mA */
-		/* ISELH = 1, ISELL = 0 */
-		reg_3 &= ~0x1;
-		reg_3 |=  0x2;
-		break;
-
-	case SEC_CURRENT_800m:
-		/* 800mA */
-		/* ISELH = 1, ISELL = 1 */
-		reg_3 |= 0x3;
-		break;
-	}
-
-	err = isl6423_write(isl6423, reg_3);
-	if (err < 0)
-		goto exit;
-
-	switch (config->curlim) {
-	case SEC_CURRENT_LIM_ON:
-		/* DCL = 0 */
-		reg_3 &= ~0x10;
-		break;
-
-	case SEC_CURRENT_LIM_OFF:
-		/* DCL = 1 */
-		reg_3 |= 0x10;
-		break;
-	}
-
-	err = isl6423_write(isl6423, reg_3);
-	if (err < 0)
-		goto exit;
-
-	isl6423->reg_3 = reg_3;
-
-	return 0;
-exit:
-	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
-	return err;
-}
-
-static void isl6423_release(struct dvb_frontend *fe)
-{
-	isl6423_set_voltage(fe, SEC_VOLTAGE_OFF);
-
-	kfree(fe->sec_priv);
-	fe->sec_priv = NULL;
-}
-
-struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
-				    struct i2c_adapter *i2c,
-				    const struct isl6423_config *config)
-{
-	struct isl6423_dev *isl6423;
-
-	isl6423 = kzalloc(sizeof(struct isl6423_dev), GFP_KERNEL);
-	if (!isl6423)
-		return NULL;
-
-	isl6423->config	= config;
-	isl6423->i2c	= i2c;
-	fe->sec_priv	= isl6423;
-
-	/* SR3H = 0, SR3M = 1, SR3L = 0 */
-	isl6423->reg_3 = 0x02 << 5;
-	/* SR4H = 0, SR4M = 1, SR4L = 1 */
-	isl6423->reg_4 = 0x03 << 5;
-
-	if (isl6423_set_current(fe))
-		goto exit;
-
-	if (isl6423_set_modulation(fe))
-		goto exit;
-
-	fe->ops.release_sec		= isl6423_release;
-	fe->ops.set_voltage		= isl6423_set_voltage;
-	fe->ops.enable_high_lnb_voltage = isl6423_voltage_boost;
-	isl6423->verbose		= verbose;
-
-	return fe;
-
-exit:
-	kfree(isl6423);
-	fe->sec_priv = NULL;
-	return NULL;
-}
-EXPORT_SYMBOL(isl6423_attach);
-
-MODULE_DESCRIPTION("ISL6423 SEC");
-MODULE_AUTHOR("Manu Abraham");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/isl6423.h b/drivers/media/dvb/frontends/isl6423.h
deleted file mode 100644
index e1a37fb..0000000
--- a/drivers/media/dvb/frontends/isl6423.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
-	Intersil ISL6423 SEC and LNB Power supply controller
-
-	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __ISL_6423_H
-#define __ISL_6423_H
-
-#include <linux/dvb/frontend.h>
-
-enum isl6423_current {
-	SEC_CURRENT_275m = 0,
-	SEC_CURRENT_515m,
-	SEC_CURRENT_635m,
-	SEC_CURRENT_800m,
-};
-
-enum isl6423_curlim {
-	SEC_CURRENT_LIM_ON = 1,
-	SEC_CURRENT_LIM_OFF
-};
-
-struct isl6423_config {
-	enum isl6423_current current_max;
-	enum isl6423_curlim curlim;
-	u8 addr;
-	u8 mod_extern;
-};
-
-#if defined(CONFIG_DVB_ISL6423) || (defined(CONFIG_DVB_ISL6423_MODULE) && defined(MODULE))
-
-
-extern struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
-					   struct i2c_adapter *i2c,
-					   const struct isl6423_config *config);
-
-#else
-static inline struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
-						  struct i2c_adapter *i2c,
-						  const struct isl6423_config *config)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-#endif /* CONFIG_DVB_ISL6423 */
-
-#endif /* __ISL_6423_H */
diff --git a/drivers/media/dvb/frontends/it913x-fe-priv.h b/drivers/media/dvb/frontends/it913x-fe-priv.h
deleted file mode 100644
index eb6fd8a..0000000
--- a/drivers/media/dvb/frontends/it913x-fe-priv.h
+++ /dev/null
@@ -1,1051 +0,0 @@
-
-struct it913xset {	u32 pro;
-			u32 address;
-			u8 reg[15];
-			u8 count;
-};
-
-struct adctable {	u32 adcFrequency;
-			u32 bandwidth;
-			u32 coeff_1_2048;
-			u32 coeff_1_4096;
-			u32 coeff_1_8191;
-			u32 coeff_1_8192;
-			u32 coeff_1_8193;
-			u32 coeff_2_2k;
-			u32 coeff_2_4k;
-			u32 coeff_2_8k;
-			u16 bfsfcw_fftinx_ratio;
-			u16 fftinx_bfsfcw_ratio;
-};
-
-/* clock and coeff tables only table 3 is used with IT9137*/
-/* TODO other tables relate AF9035 may be removed */
-static struct adctable tab1[] = {
-	{	20156250, 6000000,
-		0x02b8ba6e, 0x015c5d37, 0x00ae340d, 0x00ae2e9b, 0x00ae292a,
-		0x015c5d37, 0x00ae2e9b, 0x0057174e, 0x02f1, 0x015c	},
-	{	20156250, 7000000,
-		0x032cd980, 0x01966cc0, 0x00cb3cba, 0x00cb3660, 0x00cb3007,
-		0x01966cc0, 0x00cb3660, 0x00659b30, 0x0285, 0x0196	},
-	{	20156250, 8000000,
-		0x03a0f893, 0x01d07c49, 0x00e84567, 0x00e83e25, 0x00e836e3,
-		0x01d07c49, 0x00e83e25, 0x00741f12, 0x0234, 0x01d0	},
-	{	20156250, 5000000,
-		0x02449b5c, 0x01224dae, 0x00912b60, 0x009126d7, 0x0091224e,
-		0x01224dae, 0x009126d7, 0x0048936b, 0x0387, 0x0122	}
-};
-
-static struct adctable tab2[] = {
-	{	20187500, 6000000,
-		0x02b7a654, 0x015bd32a, 0x00adef04, 0x00ade995, 0x00ade426,
-		0x015bd32a, 0x00ade995, 0x0056f4ca, 0x02f2, 0x015c	},
-	{	20187500, 7000000,
-		0x032b9761, 0x0195cbb1, 0x00caec30, 0x00cae5d8, 0x00cadf81,
-		0x0195cbb1, 0x00cae5d8, 0x006572ec, 0x0286, 0x0196	},
-	{	20187500, 8000000,
-		0x039f886f, 0x01cfc438, 0x00e7e95b, 0x00e7e21c, 0x00e7dadd,
-		0x01cfc438, 0x00e7e21c, 0x0073f10e, 0x0235, 0x01d0	},
-	{	20187500, 5000000,
-		0x0243b546, 0x0121daa3, 0x0090f1d9, 0x0090ed51, 0x0090e8ca,
-		0x0121daa3, 0x0090ed51, 0x004876a9, 0x0388, 0x0122	}
-
-};
-
-static struct adctable tab3[] = {
-	{	20250000, 6000000,
-		0x02b580ad, 0x015ac057, 0x00ad6597, 0x00ad602b, 0x00ad5ac1,
-		0x015ac057, 0x00ad602b, 0x0056b016, 0x02f4, 0x015b	},
-	{	20250000, 7000000,
-		0x03291620, 0x01948b10, 0x00ca4bda, 0x00ca4588, 0x00ca3f36,
-		0x01948b10, 0x00ca4588, 0x006522c4, 0x0288, 0x0195	},
-	{	20250000, 8000000,
-		0x039cab92, 0x01ce55c9, 0x00e7321e, 0x00e72ae4, 0x00e723ab,
-		0x01ce55c9, 0x00e72ae4, 0x00739572, 0x0237, 0x01ce	},
-	{	20250000, 5000000,
-		0x0241eb3b, 0x0120f59e, 0x00907f53, 0x00907acf, 0x0090764b,
-		0x0120f59e, 0x00907acf, 0x00483d67, 0x038b, 0x0121	}
-
-};
-
-static struct adctable tab4[] = {
-	{	20583333, 6000000,
-		0x02aa4598, 0x015522cc, 0x00aa96bb, 0x00aa9166, 0x00aa8c12,
-		0x015522cc, 0x00aa9166, 0x005548b3, 0x0300, 0x0155	},
-	{	20583333, 7000000,
-		0x031bfbdc, 0x018dfdee, 0x00c7052f, 0x00c6fef7, 0x00c6f8bf,
-		0x018dfdee, 0x00c6fef7, 0x00637f7b, 0x0293, 0x018e	},
-	{	20583333, 8000000,
-		0x038db21f, 0x01c6d910, 0x00e373a3, 0x00e36c88, 0x00e3656d,
-		0x01c6d910, 0x00e36c88, 0x0071b644, 0x0240, 0x01c7	},
-	{	20583333, 5000000,
-		0x02388f54, 0x011c47aa, 0x008e2846, 0x008e23d5, 0x008e1f64,
-		0x011c47aa, 0x008e23d5, 0x004711ea, 0x039a, 0x011c	}
-
-};
-
-static struct adctable tab5[] = {
-	{	20416667, 6000000,
-		0x02afd765, 0x0157ebb3, 0x00abfb39, 0x00abf5d9, 0x00abf07a,
-		0x0157ebb3, 0x00abf5d9, 0x0055faed, 0x02fa, 0x0158	},
-	{	20416667, 7000000,
-		0x03227b4b, 0x01913da6, 0x00c8a518, 0x00c89ed3, 0x00c8988e,
-		0x01913da6, 0x00c89ed3, 0x00644f69, 0x028d, 0x0191	},
-	{	20416667, 8000000,
-		0x03951f32, 0x01ca8f99, 0x00e54ef7, 0x00e547cc, 0x00e540a2,
-		0x01ca8f99, 0x00e547cc, 0x0072a3e6, 0x023c, 0x01cb	},
-	{	20416667, 5000000,
-		0x023d337f, 0x011e99c0, 0x008f515a, 0x008f4ce0, 0x008f4865,
-		0x011e99c0, 0x008f4ce0, 0x0047a670, 0x0393, 0x011f	}
-
-};
-
-static struct adctable tab6[] = {
-	{	20480000, 6000000,
-		0x02adb6db, 0x0156db6e, 0x00ab7312, 0x00ab6db7, 0x00ab685c,
-		0x0156db6e, 0x00ab6db7, 0x0055b6db, 0x02fd, 0x0157	},
-	{	20480000, 7000000,
-		0x03200000, 0x01900000, 0x00c80640, 0x00c80000, 0x00c7f9c0,
-		0x01900000, 0x00c80000, 0x00640000, 0x028f, 0x0190	},
-	{	20480000, 8000000,
-		0x03924925, 0x01c92492, 0x00e4996e, 0x00e49249, 0x00e48b25,
-		0x01c92492, 0x00e49249, 0x00724925, 0x023d, 0x01c9	},
-	{	20480000, 5000000,
-		0x023b6db7, 0x011db6db, 0x008edfe5, 0x008edb6e, 0x008ed6f7,
-		0x011db6db, 0x008edb6e, 0x00476db7, 0x0396, 0x011e	}
-};
-
-static struct adctable tab7[] = {
-	{	20500000, 6000000,
-		0x02ad0b99, 0x015685cc, 0x00ab4840, 0x00ab42e6, 0x00ab3d8c,
-		0x015685cc, 0x00ab42e6, 0x0055a173, 0x02fd, 0x0157	},
-	{	20500000, 7000000,
-		0x031f3832, 0x018f9c19, 0x00c7d44b, 0x00c7ce0c, 0x00c7c7ce,
-		0x018f9c19, 0x00c7ce0c, 0x0063e706, 0x0290, 0x0190	},
-	{	20500000, 8000000,
-		0x039164cb, 0x01c8b266, 0x00e46056, 0x00e45933, 0x00e45210,
-		0x01c8b266, 0x00e45933, 0x00722c99, 0x023e, 0x01c9	},
-	{	20500000, 5000000,
-		0x023adeff, 0x011d6f80, 0x008ebc36, 0x008eb7c0, 0x008eb34a,
-		0x011d6f80, 0x008eb7c0, 0x00475be0, 0x0396, 0x011d	}
-
-};
-
-static struct adctable tab8[] = {
-	{	20625000, 6000000,
-		0x02a8e4bd, 0x0154725e, 0x00aa3e81, 0x00aa392f, 0x00aa33de,
-		0x0154725e, 0x00aa392f, 0x00551c98, 0x0302, 0x0154	},
-	{	20625000, 7000000,
-		0x031a6032, 0x018d3019, 0x00c69e41, 0x00c6980c, 0x00c691d8,
-		0x018d3019, 0x00c6980c, 0x00634c06, 0x0294, 0x018d	},
-	{	20625000, 8000000,
-		0x038bdba6, 0x01c5edd3, 0x00e2fe02, 0x00e2f6ea, 0x00e2efd2,
-		0x01c5edd3, 0x00e2f6ea, 0x00717b75, 0x0242, 0x01c6	},
-	{	20625000, 5000000,
-		0x02376948, 0x011bb4a4, 0x008ddec1, 0x008dda52, 0x008dd5e3,
-		0x011bb4a4, 0x008dda52, 0x0046ed29, 0x039c, 0x011c	}
-
-};
-
-struct table {
-		u32 xtal;
-		struct adctable *table;
-};
-
-static struct table fe_clockTable[] = {
-		{12000000, tab3},	/* 12.00MHz */
-		{20480000, tab6},	/* 20.48MHz */
-		{36000000, tab3},	/* 36.00MHz */
-		{30000000, tab1},	/* 30.00MHz */
-		{26000000, tab4},	/* 26.00MHz */
-		{28000000, tab5},	/* 28.00MHz */
-		{32000000, tab7},	/* 32.00MHz */
-		{34000000, tab2},	/* 34.00MHz */
-		{24000000, tab1},	/* 24.00MHz */
-		{22000000, tab8},	/* 22.00MHz */
-};
-
-/* fe get */
-fe_code_rate_t fe_code[] = {
-	FEC_1_2,
-	FEC_2_3,
-	FEC_3_4,
-	FEC_5_6,
-	FEC_7_8,
-	FEC_NONE,
-};
-
-fe_guard_interval_t fe_gi[] = {
-	GUARD_INTERVAL_1_32,
-	GUARD_INTERVAL_1_16,
-	GUARD_INTERVAL_1_8,
-	GUARD_INTERVAL_1_4,
-};
-
-fe_hierarchy_t fe_hi[] = {
-	HIERARCHY_NONE,
-	HIERARCHY_1,
-	HIERARCHY_2,
-	HIERARCHY_4,
-};
-
-fe_transmit_mode_t fe_mode[] = {
-	TRANSMISSION_MODE_2K,
-	TRANSMISSION_MODE_8K,
-	TRANSMISSION_MODE_4K,
-};
-
-fe_modulation_t fe_con[] = {
-	QPSK,
-	QAM_16,
-	QAM_64,
-};
-
-enum {
-	PRIORITY_HIGH = 0,	/* High-priority stream */
-	PRIORITY_LOW,	/* Low-priority stream */
-};
-
-/* Standard demodulator functions */
-static struct it913xset set_solo_fe[] = {
-	{PRO_LINK, GPIOH5_EN, {0x01}, 0x01},
-	{PRO_LINK, GPIOH5_ON, {0x01}, 0x01},
-	{PRO_LINK, GPIOH5_O, {0x00}, 0x01},
-	{PRO_LINK, GPIOH5_O, {0x01}, 0x01},
-	{PRO_LINK, DVBT_INTEN, {0x04}, 0x01},
-	{PRO_LINK, DVBT_ENABLE, {0x05}, 0x01},
-	{PRO_DMOD, MP2IF_MPEG_PAR_MODE, {0x00}, 0x01},
-	{PRO_LINK, HOSTB_MPEG_SER_MODE, {0x00}, 0x01},
-	{PRO_LINK, HOSTB_MPEG_PAR_MODE, {0x00}, 0x01},
-	{PRO_DMOD, DCA_UPPER_CHIP, {0x00}, 0x01},
-	{PRO_LINK, HOSTB_DCA_UPPER, {0x00}, 0x01},
-	{PRO_DMOD, DCA_LOWER_CHIP, {0x00}, 0x01},
-	{PRO_LINK, HOSTB_DCA_LOWER, {0x00}, 0x01},
-	{PRO_DMOD, DCA_PLATCH, {0x00}, 0x01},
-	{PRO_DMOD, DCA_FPGA_LATCH, {0x00}, 0x01},
-	{PRO_DMOD, DCA_STAND_ALONE, {0x01}, 0x01},
-	{PRO_DMOD, DCA_ENABLE, {0x00}, 0x01},
-	{PRO_DMOD, MP2IF_MPEG_PAR_MODE, {0x00}, 0x01},
-	{PRO_DMOD, BFS_FCW, {0x00, 0x00, 0x00}, 0x03},
-	{0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
-};
-
-
-static struct it913xset init_1[] = {
-	{PRO_LINK, LOCK3_OUT, {0x01}, 0x01},
-	{PRO_LINK, PADMISCDRSR, {0x01}, 0x01},
-	{PRO_LINK, PADMISCDR2, {0x00}, 0x01},
-	{PRO_DMOD, 0xec57, {0x00, 0x00}, 0x02},
-	{PRO_LINK, PADMISCDR4, {0x00}, 0x01}, /* Power up */
-	{PRO_LINK, PADMISCDR8, {0x00}, 0x01},
-	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-
-/* Version 1 types */
-static struct it913xset it9135_v1[] = {
-	{PRO_DMOD, 0x0051, {0x01}, 0x01},
-	{PRO_DMOD, 0x0070, {0x0a}, 0x01},
-	{PRO_DMOD, 0x007e, {0x04}, 0x01},
-	{PRO_DMOD, 0x0081, {0x0a}, 0x01},
-	{PRO_DMOD, 0x008a, {0x01}, 0x01},
-	{PRO_DMOD, 0x008e, {0x01}, 0x01},
-	{PRO_DMOD, 0x0092, {0x06}, 0x01},
-	{PRO_DMOD, 0x0099, {0x01}, 0x01},
-	{PRO_DMOD, 0x009f, {0xe1}, 0x01},
-	{PRO_DMOD, 0x00a0, {0xcf}, 0x01},
-	{PRO_DMOD, 0x00a3, {0x01}, 0x01},
-	{PRO_DMOD, 0x00a5, {0x01}, 0x01},
-	{PRO_DMOD, 0x00a6, {0x01}, 0x01},
-	{PRO_DMOD, 0x00a9, {0x00}, 0x01},
-	{PRO_DMOD, 0x00aa, {0x01}, 0x01},
-	{PRO_DMOD, 0x00b0, {0x01}, 0x01},
-	{PRO_DMOD, 0x00c2, {0x05}, 0x01},
-	{PRO_DMOD, 0x00c6, {0x19}, 0x01},
-	{PRO_DMOD, 0xf000, {0x0f}, 0x01},
-	{PRO_DMOD, 0xf016, {0x10}, 0x01},
-	{PRO_DMOD, 0xf017, {0x04}, 0x01},
-	{PRO_DMOD, 0xf018, {0x05}, 0x01},
-	{PRO_DMOD, 0xf019, {0x04}, 0x01},
-	{PRO_DMOD, 0xf01a, {0x05}, 0x01},
-	{PRO_DMOD, 0xf021, {0x03}, 0x01},
-	{PRO_DMOD, 0xf022, {0x0a}, 0x01},
-	{PRO_DMOD, 0xf023, {0x0a}, 0x01},
-	{PRO_DMOD, 0xf02b, {0x00}, 0x01},
-	{PRO_DMOD, 0xf02c, {0x01}, 0x01},
-	{PRO_DMOD, 0xf064, {0x03}, 0x01},
-	{PRO_DMOD, 0xf065, {0xf9}, 0x01},
-	{PRO_DMOD, 0xf066, {0x03}, 0x01},
-	{PRO_DMOD, 0xf067, {0x01}, 0x01},
-	{PRO_DMOD, 0xf06f, {0xe0}, 0x01},
-	{PRO_DMOD, 0xf070, {0x03}, 0x01},
-	{PRO_DMOD, 0xf072, {0x0f}, 0x01},
-	{PRO_DMOD, 0xf073, {0x03}, 0x01},
-	{PRO_DMOD, 0xf078, {0x00}, 0x01},
-	{PRO_DMOD, 0xf087, {0x00}, 0x01},
-	{PRO_DMOD, 0xf09b, {0x3f}, 0x01},
-	{PRO_DMOD, 0xf09c, {0x00}, 0x01},
-	{PRO_DMOD, 0xf09d, {0x20}, 0x01},
-	{PRO_DMOD, 0xf09e, {0x00}, 0x01},
-	{PRO_DMOD, 0xf09f, {0x0c}, 0x01},
-	{PRO_DMOD, 0xf0a0, {0x00}, 0x01},
-	{PRO_DMOD, 0xf130, {0x04}, 0x01},
-	{PRO_DMOD, 0xf132, {0x04}, 0x01},
-	{PRO_DMOD, 0xf144, {0x1a}, 0x01},
-	{PRO_DMOD, 0xf146, {0x00}, 0x01},
-	{PRO_DMOD, 0xf14a, {0x01}, 0x01},
-	{PRO_DMOD, 0xf14c, {0x00}, 0x01},
-	{PRO_DMOD, 0xf14d, {0x00}, 0x01},
-	{PRO_DMOD, 0xf14f, {0x04}, 0x01},
-	{PRO_DMOD, 0xf158, {0x7f}, 0x01},
-	{PRO_DMOD, 0xf15a, {0x00}, 0x01},
-	{PRO_DMOD, 0xf15b, {0x08}, 0x01},
-	{PRO_DMOD, 0xf15d, {0x03}, 0x01},
-	{PRO_DMOD, 0xf15e, {0x05}, 0x01},
-	{PRO_DMOD, 0xf163, {0x05}, 0x01},
-	{PRO_DMOD, 0xf166, {0x01}, 0x01},
-	{PRO_DMOD, 0xf167, {0x40}, 0x01},
-	{PRO_DMOD, 0xf168, {0x0f}, 0x01},
-	{PRO_DMOD, 0xf17a, {0x00}, 0x01},
-	{PRO_DMOD, 0xf17b, {0x00}, 0x01},
-	{PRO_DMOD, 0xf183, {0x01}, 0x01},
-	{PRO_DMOD, 0xf19d, {0x40}, 0x01},
-	{PRO_DMOD, 0xf1bc, {0x36}, 0x01},
-	{PRO_DMOD, 0xf1bd, {0x00}, 0x01},
-	{PRO_DMOD, 0xf1cb, {0xa0}, 0x01},
-	{PRO_DMOD, 0xf1cc, {0x01}, 0x01},
-	{PRO_DMOD, 0xf204, {0x10}, 0x01},
-	{PRO_DMOD, 0xf214, {0x00}, 0x01},
-	{PRO_DMOD, 0xf40e, {0x0a}, 0x01},
-	{PRO_DMOD, 0xf40f, {0x40}, 0x01},
-	{PRO_DMOD, 0xf410, {0x08}, 0x01},
-	{PRO_DMOD, 0xf55f, {0x0a}, 0x01},
-	{PRO_DMOD, 0xf561, {0x15}, 0x01},
-	{PRO_DMOD, 0xf562, {0x20}, 0x01},
-	{PRO_DMOD, 0xf5df, {0xfb}, 0x01},
-	{PRO_DMOD, 0xf5e0, {0x00}, 0x01},
-	{PRO_DMOD, 0xf5e3, {0x09}, 0x01},
-	{PRO_DMOD, 0xf5e4, {0x01}, 0x01},
-	{PRO_DMOD, 0xf5e5, {0x01}, 0x01},
-	{PRO_DMOD, 0xf5f8, {0x01}, 0x01},
-	{PRO_DMOD, 0xf5fd, {0x01}, 0x01},
-	{PRO_DMOD, 0xf600, {0x05}, 0x01},
-	{PRO_DMOD, 0xf601, {0x08}, 0x01},
-	{PRO_DMOD, 0xf602, {0x0b}, 0x01},
-	{PRO_DMOD, 0xf603, {0x0e}, 0x01},
-	{PRO_DMOD, 0xf604, {0x11}, 0x01},
-	{PRO_DMOD, 0xf605, {0x14}, 0x01},
-	{PRO_DMOD, 0xf606, {0x17}, 0x01},
-	{PRO_DMOD, 0xf607, {0x1f}, 0x01},
-	{PRO_DMOD, 0xf60e, {0x00}, 0x01},
-	{PRO_DMOD, 0xf60f, {0x04}, 0x01},
-	{PRO_DMOD, 0xf610, {0x32}, 0x01},
-	{PRO_DMOD, 0xf611, {0x10}, 0x01},
-	{PRO_DMOD, 0xf707, {0xfc}, 0x01},
-	{PRO_DMOD, 0xf708, {0x00}, 0x01},
-	{PRO_DMOD, 0xf709, {0x37}, 0x01},
-	{PRO_DMOD, 0xf70a, {0x00}, 0x01},
-	{PRO_DMOD, 0xf78b, {0x01}, 0x01},
-	{PRO_DMOD, 0xf80f, {0x40}, 0x01},
-	{PRO_DMOD, 0xf810, {0x54}, 0x01},
-	{PRO_DMOD, 0xf811, {0x5a}, 0x01},
-	{PRO_DMOD, 0xf905, {0x01}, 0x01},
-	{PRO_DMOD, 0xfb06, {0x03}, 0x01},
-	{PRO_DMOD, 0xfd8b, {0x00}, 0x01},
-	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-static struct it913xset it9135_38[] = {
-	{PRO_DMOD, 0x0043, {0x00}, 0x01},
-	{PRO_DMOD, 0x0046, {0x38}, 0x01},
-	{PRO_DMOD, 0x0051, {0x01}, 0x01},
-	{PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0x0068, {0x0a}, 0x01},
-	{PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
-	{PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05},
-	{PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02},
-	{PRO_DMOD, 0x0081, {	0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc8, 0xb8,
-				0xd0, 0xc3, 0x01}, 0x0a},
-	{PRO_DMOD, 0x008e, {0x01}, 0x01},
-	{PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
-	{PRO_DMOD, 0x0099, {0x01}, 0x01},
-	{PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
-	{PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
-	{PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
-	{PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
-	{PRO_DMOD, 0x00b0, {0x01}, 0x01},
-	{PRO_DMOD, 0x00b3, {0x02, 0x32}, 0x02},
-	{PRO_DMOD, 0x00b6, {0x14}, 0x01},
-	{PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03},
-	{PRO_DMOD, 0x00c4, {0x00}, 0x01},
-	{PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
-	{PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03},
-	{PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03},
-	{PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
-	{PRO_DMOD, 0x00fc, {	0x02, 0x02, 0x02, 0x09, 0x50, 0x7b, 0x77,
-				0x00, 0x02, 0xc8, 0x05, 0x7b}, 0x0c},
-	{PRO_DMOD, 0x0109, {0x02}, 0x01},
-	{PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04},
-	{PRO_DMOD, 0x011a, {0xc8, 0x7b, 0x8a, 0xa0}, 0x04},
-	{PRO_DMOD, 0x0122, {0x02, 0x18, 0xc3}, 0x03},
-	{PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02},
-	{PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
-	{PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05},
-	{PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc8, 0x59}, 0x05},
-	{PRO_DMOD, 0xf000, {0x0f}, 0x01},
-	{PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05},
-	{PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05},
-	{PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04},
-	{PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
-	{PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
-	{PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
-	{PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
-	{PRO_DMOD, 0xf085, {0x00, 0x02, 0x00}, 0x03},
-	{PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
-	{PRO_DMOD, 0xf130, {0x04}, 0x01},
-	{PRO_DMOD, 0xf132, {0x04}, 0x01},
-	{PRO_DMOD, 0xf144, {0x1a}, 0x01},
-	{PRO_DMOD, 0xf146, {0x00}, 0x01},
-	{PRO_DMOD, 0xf14a, {0x01}, 0x01},
-	{PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0xf14f, {0x04}, 0x01},
-	{PRO_DMOD, 0xf158, {0x7f}, 0x01},
-	{PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
-	{PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
-	{PRO_DMOD, 0xf163, {0x05}, 0x01},
-	{PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
-	{PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0xf183, {0x01}, 0x01},
-	{PRO_DMOD, 0xf19d, {0x40}, 0x01},
-	{PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
-	{PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
-	{PRO_DMOD, 0xf204, {0x10}, 0x01},
-	{PRO_DMOD, 0xf214, {0x00}, 0x01},
-	{PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
-	{PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
-	{PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
-	{PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
-	{PRO_DMOD, 0xf55f, {0x0a}, 0x01},
-	{PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
-	{PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02},
-	{PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
-	{PRO_DMOD, 0xf5f8, {0x01}, 0x01},
-	{PRO_DMOD, 0xf5fd, {0x01}, 0x01},
-	{PRO_DMOD, 0xf600, {	0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
-				0x1f}, 0x08},
-	{PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
-	{PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
-	{PRO_DMOD, 0xf78b, {0x01}, 0x01},
-	{PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
-	{PRO_DMOD, 0xf905, {0x01}, 0x01},
-	{PRO_DMOD, 0xfb06, {0x03}, 0x01},
-	{PRO_DMOD, 0xfd8b, {0x00}, 0x01},
-	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-static struct it913xset it9135_51[] = {
-	{PRO_DMOD, 0x0043, {0x00}, 0x01},
-	{PRO_DMOD, 0x0046, {0x51}, 0x01},
-	{PRO_DMOD, 0x0051, {0x01}, 0x01},
-	{PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0x0068, {0x0a}, 0x01},
-	{PRO_DMOD, 0x0070, {0x0a, 0x06, 0x02}, 0x03},
-	{PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05},
-	{PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02},
-	{PRO_DMOD, 0x0081, {	0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc0, 0x96,
-				0xcf, 0xc3, 0x01}, 0x0a},
-	{PRO_DMOD, 0x008e, {0x01}, 0x01},
-	{PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
-	{PRO_DMOD, 0x0099, {0x01}, 0x01},
-	{PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
-	{PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
-	{PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
-	{PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
-	{PRO_DMOD, 0x00b0, {0x01}, 0x01},
-	{PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02},
-	{PRO_DMOD, 0x00b6, {0x14}, 0x01},
-	{PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03},
-	{PRO_DMOD, 0x00c4, {0x00}, 0x01},
-	{PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
-	{PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03},
-	{PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03},
-	{PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
-	{PRO_DMOD, 0x00fc, {	0x03, 0x02, 0x02, 0x09, 0x50, 0x7a, 0x77,
-				0x01, 0x02, 0xb0, 0x02, 0x7a}, 0x0c},
-	{PRO_DMOD, 0x0109, {0x02}, 0x01},
-	{PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04},
-	{PRO_DMOD, 0x011a, {0xc0, 0x7a, 0xac, 0x8c}, 0x04},
-	{PRO_DMOD, 0x0122, {0x02, 0x70, 0xa4}, 0x03},
-	{PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02},
-	{PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
-	{PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05},
-	{PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc0, 0x59}, 0x05},
-	{PRO_DMOD, 0xf000, {0x0f}, 0x01},
-	{PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05},
-	{PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05},
-	{PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04},
-	{PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
-	{PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
-	{PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
-	{PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
-	{PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03},
-	{PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
-	{PRO_DMOD, 0xf130, {0x04}, 0x01},
-	{PRO_DMOD, 0xf132, {0x04}, 0x01},
-	{PRO_DMOD, 0xf144, {0x1a}, 0x01},
-	{PRO_DMOD, 0xf146, {0x00}, 0x01},
-	{PRO_DMOD, 0xf14a, {0x01}, 0x01},
-	{PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0xf14f, {0x04}, 0x01},
-	{PRO_DMOD, 0xf158, {0x7f}, 0x01},
-	{PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
-	{PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
-	{PRO_DMOD, 0xf163, {0x05}, 0x01},
-	{PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
-	{PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0xf183, {0x01}, 0x01},
-	{PRO_DMOD, 0xf19d, {0x40}, 0x01},
-	{PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
-	{PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
-	{PRO_DMOD, 0xf204, {0x10}, 0x01},
-	{PRO_DMOD, 0xf214, {0x00}, 0x01},
-	{PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
-	{PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
-	{PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
-	{PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
-	{PRO_DMOD, 0xf55f, {0x0a}, 0x01},
-	{PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
-	{PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02},
-	{PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
-	{PRO_DMOD, 0xf5f8, {0x01}, 0x01},
-	{PRO_DMOD, 0xf5fd, {0x01}, 0x01},
-	{PRO_DMOD, 0xf600, {	0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
-				0x1f}, 0x08},
-	{PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
-	{PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
-	{PRO_DMOD, 0xf78b, {0x01}, 0x01},
-	{PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
-	{PRO_DMOD, 0xf905, {0x01}, 0x01},
-	{PRO_DMOD, 0xfb06, {0x03}, 0x01},
-	{PRO_DMOD, 0xfd8b, {0x00}, 0x01},
-	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-static struct it913xset it9135_52[] = {
-	{PRO_DMOD, 0x0043, {0x00}, 0x01},
-	{PRO_DMOD, 0x0046, {0x52}, 0x01},
-	{PRO_DMOD, 0x0051, {0x01}, 0x01},
-	{PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0x0068, {0x10}, 0x01},
-	{PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
-	{PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xa0, 0x01}, 0x05},
-	{PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02},
-	{PRO_DMOD, 0x0081, {	0x0a, 0x12, 0x03, 0x0a, 0x03, 0xb3, 0x97,
-				0xc0, 0x9e, 0x01}, 0x0a},
-	{PRO_DMOD, 0x008e, {0x01}, 0x01},
-	{PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
-	{PRO_DMOD, 0x0099, {0x01}, 0x01},
-	{PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
-	{PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
-	{PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04},
-	{PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
-	{PRO_DMOD, 0x00b0, {0x01}, 0x01},
-	{PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02},
-	{PRO_DMOD, 0x00b6, {0x14}, 0x01},
-	{PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03},
-	{PRO_DMOD, 0x00c4, {0x00}, 0x01},
-	{PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
-	{PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03},
-	{PRO_DMOD, 0x00f3, {0x05, 0x91, 0x8c}, 0x03},
-	{PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
-	{PRO_DMOD, 0x00fc, {	0x03, 0x02, 0x02, 0x09, 0x50, 0x74, 0x77,
-				0x02, 0x02, 0xae, 0x02, 0x6e}, 0x0c},
-	{PRO_DMOD, 0x0109, {0x02}, 0x01},
-	{PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04},
-	{PRO_DMOD, 0x011a, {0xcd, 0x62, 0xa4, 0x8c}, 0x04},
-	{PRO_DMOD, 0x0122, {0x03, 0x18, 0x9e}, 0x03},
-	{PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02},
-	{PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
-	{PRO_DMOD, 0x0137, {0x00, 0x00, 0x07, 0x00, 0x06}, 0x05},
-	{PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xb6, 0x59}, 0x05},
-	{PRO_DMOD, 0xf000, {0x0f}, 0x01},
-	{PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05},
-	{PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05},
-	{PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04},
-	{PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
-	{PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
-	{PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
-	{PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
-	{PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03},
-	{PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
-	{PRO_DMOD, 0xf130, {0x04}, 0x01},
-	{PRO_DMOD, 0xf132, {0x04}, 0x01},
-	{PRO_DMOD, 0xf144, {0x1a}, 0x01},
-	{PRO_DMOD, 0xf146, {0x00}, 0x01},
-	{PRO_DMOD, 0xf14a, {0x01}, 0x01},
-	{PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0xf14f, {0x04}, 0x01},
-	{PRO_DMOD, 0xf158, {0x7f}, 0x01},
-	{PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
-	{PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
-	{PRO_DMOD, 0xf163, {0x05}, 0x01},
-	{PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
-	{PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0xf183, {0x01}, 0x01},
-	{PRO_DMOD, 0xf19d, {0x40}, 0x01},
-	{PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
-	{PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
-	{PRO_DMOD, 0xf204, {0x10}, 0x01},
-	{PRO_DMOD, 0xf214, {0x00}, 0x01},
-	{PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
-	{PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
-	{PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
-	{PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
-	{PRO_DMOD, 0xf55f, {0x0a}, 0x01},
-	{PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
-	{PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02},
-	{PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
-	{PRO_DMOD, 0xf5f8, {0x01}, 0x01},
-	{PRO_DMOD, 0xf5fd, {0x01}, 0x01},
-	{PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
-				0x1f}, 0x08},
-	{PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
-	{PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
-	{PRO_DMOD, 0xf78b, {0x01}, 0x01},
-	{PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
-	{PRO_DMOD, 0xf905, {0x01}, 0x01},
-	{PRO_DMOD, 0xfb06, {0x03}, 0x01},
-	{PRO_DMOD, 0xfd8b, {0x00}, 0x01},
-	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-/* Version 2 types */
-static struct it913xset it9135_v2[] = {
-	{PRO_DMOD, 0x0051, {0x01}, 0x01},
-	{PRO_DMOD, 0x0070, {0x0a}, 0x01},
-	{PRO_DMOD, 0x007e, {0x04}, 0x01},
-	{PRO_DMOD, 0x0081, {0x0a}, 0x01},
-	{PRO_DMOD, 0x008a, {0x01}, 0x01},
-	{PRO_DMOD, 0x008e, {0x01}, 0x01},
-	{PRO_DMOD, 0x0092, {0x06}, 0x01},
-	{PRO_DMOD, 0x0099, {0x01}, 0x01},
-	{PRO_DMOD, 0x009f, {0xe1}, 0x01},
-	{PRO_DMOD, 0x00a0, {0xcf}, 0x01},
-	{PRO_DMOD, 0x00a3, {0x01}, 0x01},
-	{PRO_DMOD, 0x00a5, {0x01}, 0x01},
-	{PRO_DMOD, 0x00a6, {0x01}, 0x01},
-	{PRO_DMOD, 0x00a9, {0x00}, 0x01},
-	{PRO_DMOD, 0x00aa, {0x01}, 0x01},
-	{PRO_DMOD, 0x00b0, {0x01}, 0x01},
-	{PRO_DMOD, 0x00c2, {0x05}, 0x01},
-	{PRO_DMOD, 0x00c6, {0x19}, 0x01},
-	{PRO_DMOD, 0xf000, {0x0f}, 0x01},
-	{PRO_DMOD, 0xf02b, {0x00}, 0x01},
-	{PRO_DMOD, 0xf064, {0x03}, 0x01},
-	{PRO_DMOD, 0xf065, {0xf9}, 0x01},
-	{PRO_DMOD, 0xf066, {0x03}, 0x01},
-	{PRO_DMOD, 0xf067, {0x01}, 0x01},
-	{PRO_DMOD, 0xf06f, {0xe0}, 0x01},
-	{PRO_DMOD, 0xf070, {0x03}, 0x01},
-	{PRO_DMOD, 0xf072, {0x0f}, 0x01},
-	{PRO_DMOD, 0xf073, {0x03}, 0x01},
-	{PRO_DMOD, 0xf078, {0x00}, 0x01},
-	{PRO_DMOD, 0xf087, {0x00}, 0x01},
-	{PRO_DMOD, 0xf09b, {0x3f}, 0x01},
-	{PRO_DMOD, 0xf09c, {0x00}, 0x01},
-	{PRO_DMOD, 0xf09d, {0x20}, 0x01},
-	{PRO_DMOD, 0xf09e, {0x00}, 0x01},
-	{PRO_DMOD, 0xf09f, {0x0c}, 0x01},
-	{PRO_DMOD, 0xf0a0, {0x00}, 0x01},
-	{PRO_DMOD, 0xf130, {0x04}, 0x01},
-	{PRO_DMOD, 0xf132, {0x04}, 0x01},
-	{PRO_DMOD, 0xf144, {0x1a}, 0x01},
-	{PRO_DMOD, 0xf146, {0x00}, 0x01},
-	{PRO_DMOD, 0xf14a, {0x01}, 0x01},
-	{PRO_DMOD, 0xf14c, {0x00}, 0x01},
-	{PRO_DMOD, 0xf14d, {0x00}, 0x01},
-	{PRO_DMOD, 0xf14f, {0x04}, 0x01},
-	{PRO_DMOD, 0xf158, {0x7f}, 0x01},
-	{PRO_DMOD, 0xf15a, {0x00}, 0x01},
-	{PRO_DMOD, 0xf15b, {0x08}, 0x01},
-	{PRO_DMOD, 0xf15d, {0x03}, 0x01},
-	{PRO_DMOD, 0xf15e, {0x05}, 0x01},
-	{PRO_DMOD, 0xf163, {0x05}, 0x01},
-	{PRO_DMOD, 0xf166, {0x01}, 0x01},
-	{PRO_DMOD, 0xf167, {0x40}, 0x01},
-	{PRO_DMOD, 0xf168, {0x0f}, 0x01},
-	{PRO_DMOD, 0xf17a, {0x00}, 0x01},
-	{PRO_DMOD, 0xf17b, {0x00}, 0x01},
-	{PRO_DMOD, 0xf183, {0x01}, 0x01},
-	{PRO_DMOD, 0xf19d, {0x40}, 0x01},
-	{PRO_DMOD, 0xf1bc, {0x36}, 0x01},
-	{PRO_DMOD, 0xf1bd, {0x00}, 0x01},
-	{PRO_DMOD, 0xf1cb, {0xa0}, 0x01},
-	{PRO_DMOD, 0xf1cc, {0x01}, 0x01},
-	{PRO_DMOD, 0xf204, {0x10}, 0x01},
-	{PRO_DMOD, 0xf214, {0x00}, 0x01},
-	{PRO_DMOD, 0xf40e, {0x0a}, 0x01},
-	{PRO_DMOD, 0xf40f, {0x40}, 0x01},
-	{PRO_DMOD, 0xf410, {0x08}, 0x01},
-	{PRO_DMOD, 0xf55f, {0x0a}, 0x01},
-	{PRO_DMOD, 0xf561, {0x15}, 0x01},
-	{PRO_DMOD, 0xf562, {0x20}, 0x01},
-	{PRO_DMOD, 0xf5e3, {0x09}, 0x01},
-	{PRO_DMOD, 0xf5e4, {0x01}, 0x01},
-	{PRO_DMOD, 0xf5e5, {0x01}, 0x01},
-	{PRO_DMOD, 0xf600, {0x05}, 0x01},
-	{PRO_DMOD, 0xf601, {0x08}, 0x01},
-	{PRO_DMOD, 0xf602, {0x0b}, 0x01},
-	{PRO_DMOD, 0xf603, {0x0e}, 0x01},
-	{PRO_DMOD, 0xf604, {0x11}, 0x01},
-	{PRO_DMOD, 0xf605, {0x14}, 0x01},
-	{PRO_DMOD, 0xf606, {0x17}, 0x01},
-	{PRO_DMOD, 0xf607, {0x1f}, 0x01},
-	{PRO_DMOD, 0xf60e, {0x00}, 0x01},
-	{PRO_DMOD, 0xf60f, {0x04}, 0x01},
-	{PRO_DMOD, 0xf610, {0x32}, 0x01},
-	{PRO_DMOD, 0xf611, {0x10}, 0x01},
-	{PRO_DMOD, 0xf707, {0xfc}, 0x01},
-	{PRO_DMOD, 0xf708, {0x00}, 0x01},
-	{PRO_DMOD, 0xf709, {0x37}, 0x01},
-	{PRO_DMOD, 0xf70a, {0x00}, 0x01},
-	{PRO_DMOD, 0xf78b, {0x01}, 0x01},
-	{PRO_DMOD, 0xf80f, {0x40}, 0x01},
-	{PRO_DMOD, 0xf810, {0x54}, 0x01},
-	{PRO_DMOD, 0xf811, {0x5a}, 0x01},
-	{PRO_DMOD, 0xf905, {0x01}, 0x01},
-	{PRO_DMOD, 0xfb06, {0x03}, 0x01},
-	{PRO_DMOD, 0xfd8b, {0x00}, 0x01},
-	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-static struct it913xset it9135_60[] = {
-	{PRO_DMOD, 0x0043, {0x00}, 0x01},
-	{PRO_DMOD, 0x0046, {0x60}, 0x01},
-	{PRO_DMOD, 0x0051, {0x01}, 0x01},
-	{PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0x0068, {0x0a}, 0x01},
-	{PRO_DMOD, 0x006a, {0x03}, 0x01},
-	{PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
-	{PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05},
-	{PRO_DMOD, 0x007e, {0x04}, 0x01},
-	{PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02},
-	{PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbe, 0xa0, 0xc6, 0xb6, 0x01}, 0x07},
-	{PRO_DMOD, 0x008e, {0x01}, 0x01},
-	{PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
-	{PRO_DMOD, 0x0099, {0x01}, 0x01},
-	{PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
-	{PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
-	{PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
-	{PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
-	{PRO_DMOD, 0x00b0, {0x01}, 0x01},
-	{PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02},
-	{PRO_DMOD, 0x00b6, {0x14}, 0x01},
-	{PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05},
-	{PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
-	{PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04},
-	{PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03},
-	{PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
-	{PRO_DMOD, 0x00fc, {	0x03, 0x03, 0x02, 0x0a, 0x50, 0x7b, 0x8c,
-				0x00, 0x02, 0xbe, 0x00}, 0x0b},
-	{PRO_DMOD, 0x0109, {0x02}, 0x01},
-	{PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
-	{PRO_DMOD, 0x011a, {0xbe}, 0x01},
-	{PRO_DMOD, 0x0124, {0xae}, 0x01},
-	{PRO_DMOD, 0x0127, {0x00}, 0x01},
-	{PRO_DMOD, 0x012a, {0x56, 0x50, 0x47, 0x42}, 0x04},
-	{PRO_DMOD, 0x0137, {0x00}, 0x01},
-	{PRO_DMOD, 0x013b, {0x08}, 0x01},
-	{PRO_DMOD, 0x013f, {0x5b}, 0x01},
-	{PRO_DMOD, 0x0141, {	0x59, 0xf9, 0x19, 0x19, 0x8c, 0x8c, 0x8c,
-				0x6e, 0x8c, 0x50, 0x8c, 0x8c, 0xac, 0xc6,
-				0x33}, 0x0f},
-	{PRO_DMOD, 0x0151, {0x28}, 0x01},
-	{PRO_DMOD, 0x0153, {0xbc}, 0x01},
-	{PRO_DMOD, 0x0178, {0x09}, 0x01},
-	{PRO_DMOD, 0x0181, {0x94, 0x6e}, 0x02},
-	{PRO_DMOD, 0x0185, {0x24}, 0x01},
-	{PRO_DMOD, 0x0187, {0x00, 0x00, 0xbe, 0x02, 0x80}, 0x05},
-	{PRO_DMOD, 0xed02, {0xff}, 0x01},
-	{PRO_DMOD, 0xee42, {0xff}, 0x01},
-	{PRO_DMOD, 0xee82, {0xff}, 0x01},
-	{PRO_DMOD, 0xf000, {0x0f}, 0x01},
-	{PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02},
-	{PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03},
-	{PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
-	{PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
-	{PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
-	{PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
-	{PRO_DMOD, 0xf087, {0x00}, 0x01},
-	{PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
-	{PRO_DMOD, 0xf130, {0x04}, 0x01},
-	{PRO_DMOD, 0xf132, {0x04}, 0x01},
-	{PRO_DMOD, 0xf144, {0x1a}, 0x01},
-	{PRO_DMOD, 0xf146, {0x00}, 0x01},
-	{PRO_DMOD, 0xf14a, {0x01}, 0x01},
-	{PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0xf14f, {0x04}, 0x01},
-	{PRO_DMOD, 0xf158, {0x7f}, 0x01},
-	{PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
-	{PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
-	{PRO_DMOD, 0xf163, {0x05}, 0x01},
-	{PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
-	{PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0xf183, {0x01}, 0x01},
-	{PRO_DMOD, 0xf19d, {0x40}, 0x01},
-	{PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
-	{PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
-	{PRO_DMOD, 0xf204, {0x10}, 0x01},
-	{PRO_DMOD, 0xf214, {0x00}, 0x01},
-	{PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
-	{PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
-	{PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
-	{PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
-	{PRO_DMOD, 0xf55f, {0x0a}, 0x01},
-	{PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
-	{PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
-	{PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17
-		, 0x1f}, 0x08},
-	{PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
-	{PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
-	{PRO_DMOD, 0xf78b, {0x01}, 0x01},
-	{PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
-	{PRO_DMOD, 0xf905, {0x01}, 0x01},
-	{PRO_DMOD, 0xfb06, {0x03}, 0x01},
-	{PRO_DMOD, 0xfd8b, {0x00}, 0x01},
-	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-static struct it913xset it9135_61[] = {
-	{PRO_DMOD, 0x0043, {0x00}, 0x01},
-	{PRO_DMOD, 0x0046, {0x61}, 0x01},
-	{PRO_DMOD, 0x0051, {0x01}, 0x01},
-	{PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0x0068, {0x06}, 0x01},
-	{PRO_DMOD, 0x006a, {0x03}, 0x01},
-	{PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
-	{PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x90, 0x01}, 0x05},
-	{PRO_DMOD, 0x007e, {0x04}, 0x01},
-	{PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02},
-	{PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbc, 0x9c, 0xcc, 0xa8, 0x01}, 0x07},
-	{PRO_DMOD, 0x008e, {0x01}, 0x01},
-	{PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
-	{PRO_DMOD, 0x0099, {0x01}, 0x01},
-	{PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
-	{PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
-	{PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04},
-	{PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
-	{PRO_DMOD, 0x00b0, {0x01}, 0x01},
-	{PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02},
-	{PRO_DMOD, 0x00b6, {0x14}, 0x01},
-	{PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05},
-	{PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
-	{PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04},
-	{PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03},
-	{PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
-	{PRO_DMOD, 0x00fc, {	0x03, 0x03, 0x02, 0x08, 0x50, 0x7b, 0x8c,
-				0x01, 0x02, 0xc8, 0x00}, 0x0b},
-	{PRO_DMOD, 0x0109, {0x02}, 0x01},
-	{PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
-	{PRO_DMOD, 0x011a, {0xc6}, 0x01},
-	{PRO_DMOD, 0x0124, {0xa8}, 0x01},
-	{PRO_DMOD, 0x0127, {0x00}, 0x01},
-	{PRO_DMOD, 0x012a, {0x59, 0x50, 0x47, 0x42}, 0x04},
-	{PRO_DMOD, 0x0137, {0x00}, 0x01},
-	{PRO_DMOD, 0x013b, {0x05}, 0x01},
-	{PRO_DMOD, 0x013f, {0x5b}, 0x01},
-	{PRO_DMOD, 0x0141, {	0x59, 0xf9, 0x59, 0x59, 0x8c, 0x8c, 0x8c,
-				0x7b, 0x8c, 0x50, 0x8c, 0x8c, 0xa8, 0xc6,
-				0x33}, 0x0f},
-	{PRO_DMOD, 0x0151, {0x28}, 0x01},
-	{PRO_DMOD, 0x0153, {0xcc}, 0x01},
-	{PRO_DMOD, 0x0178, {0x09}, 0x01},
-	{PRO_DMOD, 0x0181, {0x9c, 0x76}, 0x02},
-	{PRO_DMOD, 0x0185, {0x28}, 0x01},
-	{PRO_DMOD, 0x0187, {0x01, 0x00, 0xaa, 0x02, 0x80}, 0x05},
-	{PRO_DMOD, 0xed02, {0xff}, 0x01},
-	{PRO_DMOD, 0xee42, {0xff}, 0x01},
-	{PRO_DMOD, 0xee82, {0xff}, 0x01},
-	{PRO_DMOD, 0xf000, {0x0f}, 0x01},
-	{PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02},
-	{PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03},
-	{PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
-	{PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
-	{PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
-	{PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
-	{PRO_DMOD, 0xf087, {0x00}, 0x01},
-	{PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
-	{PRO_DMOD, 0xf130, {0x04}, 0x01},
-	{PRO_DMOD, 0xf132, {0x04}, 0x01},
-	{PRO_DMOD, 0xf144, {0x1a}, 0x01},
-	{PRO_DMOD, 0xf146, {0x00}, 0x01},
-	{PRO_DMOD, 0xf14a, {0x01}, 0x01},
-	{PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0xf14f, {0x04}, 0x01},
-	{PRO_DMOD, 0xf158, {0x7f}, 0x01},
-	{PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
-	{PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
-	{PRO_DMOD, 0xf163, {0x05}, 0x01},
-	{PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
-	{PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0xf183, {0x01}, 0x01},
-	{PRO_DMOD, 0xf19d, {0x40}, 0x01},
-	{PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
-	{PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
-	{PRO_DMOD, 0xf204, {0x10}, 0x01},
-	{PRO_DMOD, 0xf214, {0x00}, 0x01},
-	{PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
-	{PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
-	{PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
-	{PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
-	{PRO_DMOD, 0xf55f, {0x0a}, 0x01},
-	{PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
-	{PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
-	{PRO_DMOD, 0xf600, {	0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
-				0x1f}, 0x08},
-	{PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
-	{PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
-	{PRO_DMOD, 0xf78b, {0x01}, 0x01},
-	{PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
-	{PRO_DMOD, 0xf905, {0x01}, 0x01},
-	{PRO_DMOD, 0xfb06, {0x03}, 0x01},
-	{PRO_DMOD, 0xfd8b, {0x00}, 0x01},
-	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-static struct it913xset it9135_62[] = {
-	{PRO_DMOD, 0x0043, {0x00}, 0x01},
-	{PRO_DMOD, 0x0046, {0x62}, 0x01},
-	{PRO_DMOD, 0x0051, {0x01}, 0x01},
-	{PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0x0068, {0x0a}, 0x01},
-	{PRO_DMOD, 0x006a, {0x03}, 0x01},
-	{PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
-	{PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05},
-	{PRO_DMOD, 0x007e, {0x04}, 0x01},
-	{PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02},
-	{PRO_DMOD, 0x0084, {	0x0a, 0x33, 0xb8, 0x9c, 0xb2, 0xa6, 0x01},
-				0x07},
-	{PRO_DMOD, 0x008e, {0x01}, 0x01},
-	{PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
-	{PRO_DMOD, 0x0099, {0x01}, 0x01},
-	{PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
-	{PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
-	{PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
-	{PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
-	{PRO_DMOD, 0x00b0, {0x01}, 0x01},
-	{PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02},
-	{PRO_DMOD, 0x00b6, {0x14}, 0x01},
-	{PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05},
-	{PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
-	{PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04},
-	{PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03},
-	{PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
-	{PRO_DMOD, 0x00fc, {	0x02, 0x03, 0x02, 0x09, 0x50, 0x6e, 0x8c,
-				0x02, 0x02, 0xc2, 0x00}, 0x0b},
-	{PRO_DMOD, 0x0109, {0x02}, 0x01},
-	{PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
-	{PRO_DMOD, 0x011a, {0xb8}, 0x01},
-	{PRO_DMOD, 0x0124, {0xa8}, 0x01},
-	{PRO_DMOD, 0x0127, {0x00}, 0x01},
-	{PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
-	{PRO_DMOD, 0x0137, {0x00}, 0x01},
-	{PRO_DMOD, 0x013b, {0x05}, 0x01},
-	{PRO_DMOD, 0x013f, {0x5b}, 0x01},
-	{PRO_DMOD, 0x0141, {	0x59, 0xf9, 0x59, 0x19, 0x8c, 0x8c, 0x8c,
-				0x7b, 0x8c, 0x50, 0x70, 0x8c, 0x96, 0xd0,
-				0x33}, 0x0f},
-	{PRO_DMOD, 0x0151, {0x28}, 0x01},
-	{PRO_DMOD, 0x0153, {0xb2}, 0x01},
-	{PRO_DMOD, 0x0178, {0x09}, 0x01},
-	{PRO_DMOD, 0x0181, {0x9c, 0x6e}, 0x02},
-	{PRO_DMOD, 0x0185, {0x24}, 0x01},
-	{PRO_DMOD, 0x0187, {0x00, 0x00, 0xb8, 0x02, 0x80}, 0x05},
-	{PRO_DMOD, 0xed02, {0xff}, 0x01},
-	{PRO_DMOD, 0xee42, {0xff}, 0x01},
-	{PRO_DMOD, 0xee82, {0xff}, 0x01},
-	{PRO_DMOD, 0xf000, {0x0f}, 0x01},
-	{PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02},
-	{PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03},
-	{PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
-	{PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
-	{PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
-	{PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
-	{PRO_DMOD, 0xf087, {0x00}, 0x01},
-	{PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
-	{PRO_DMOD, 0xf130, {0x04}, 0x01},
-	{PRO_DMOD, 0xf132, {0x04}, 0x01},
-	{PRO_DMOD, 0xf144, {0x1a}, 0x01},
-	{PRO_DMOD, 0xf146, {0x00}, 0x01},
-	{PRO_DMOD, 0xf14a, {0x01}, 0x01},
-	{PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0xf14f, {0x04}, 0x01},
-	{PRO_DMOD, 0xf158, {0x7f}, 0x01},
-	{PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
-	{PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
-	{PRO_DMOD, 0xf163, {0x05}, 0x01},
-	{PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
-	{PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
-	{PRO_DMOD, 0xf183, {0x01}, 0x01},
-	{PRO_DMOD, 0xf19d, {0x40}, 0x01},
-	{PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
-	{PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
-	{PRO_DMOD, 0xf204, {0x10}, 0x01},
-	{PRO_DMOD, 0xf214, {0x00}, 0x01},
-	{PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
-	{PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
-	{PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
-	{PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
-	{PRO_DMOD, 0xf55f, {0x0a}, 0x01},
-	{PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
-	{PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
-	{PRO_DMOD, 0xf600, {	0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
-				0x1f}, 0x08},
-	{PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
-	{PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
-	{PRO_DMOD, 0xf78b, {0x01}, 0x01},
-	{PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
-	{PRO_DMOD, 0xf905, {0x01}, 0x01},
-	{PRO_DMOD, 0xfb06, {0x03}, 0x01},
-	{PRO_DMOD, 0xfd8b, {0x00}, 0x01},
-	{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-/* Tuner setting scripts (still keeping it9137) */
-static struct it913xset it9137_tuner_off[] = {
-	{PRO_DMOD, 0xfba8, {0x01}, 0x01}, /* Tuner Clock Off  */
-	{PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */
-	{PRO_DMOD, 0xec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04},
-	{PRO_DMOD, 0xec06, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-				0x00, 0x00, 0x00, 0x00}, 0x0c},
-	{PRO_DMOD, 0xec12, {0x00, 0x00, 0x00, 0x00}, 0x04},
-	{PRO_DMOD, 0xec17, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-				0x00}, 0x09},
-	{PRO_DMOD, 0xec22, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-				0x00, 0x00}, 0x0a},
-	{PRO_DMOD, 0xec20, {0x00}, 0x01},
-	{PRO_DMOD, 0xec3f, {0x01}, 0x01},
-	{0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
-};
-
-static struct it913xset set_it9135_template[] = {
-	{PRO_DMOD, 0xee06, {0x00}, 0x01},
-	{PRO_DMOD, 0xec56, {0x00}, 0x01},
-	{PRO_DMOD, 0xec4c, {0x00}, 0x01},
-	{PRO_DMOD, 0xec4d, {0x00}, 0x01},
-	{PRO_DMOD, 0xec4e, {0x00}, 0x01},
-	{PRO_DMOD, 0x011e, {0x00}, 0x01}, /* Older Devices */
-	{PRO_DMOD, 0x011f, {0x00}, 0x01},
-	{0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
-};
-
-static struct it913xset set_it9137_template[] = {
-	{PRO_DMOD, 0xee06, {0x00}, 0x01},
-	{PRO_DMOD, 0xec56, {0x00}, 0x01},
-	{PRO_DMOD, 0xec4c, {0x00}, 0x01},
-	{PRO_DMOD, 0xec4d, {0x00}, 0x01},
-	{PRO_DMOD, 0xec4e, {0x00}, 0x01},
-	{PRO_DMOD, 0xec4f, {0x00}, 0x01},
-	{PRO_DMOD, 0xec50, {0x00}, 0x01},
-	{0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
-};
diff --git a/drivers/media/dvb/frontends/it913x-fe.c b/drivers/media/dvb/frontends/it913x-fe.c
deleted file mode 100644
index 708cbf1..0000000
--- a/drivers/media/dvb/frontends/it913x-fe.c
+++ /dev/null
@@ -1,1045 +0,0 @@
-/*
- *  Driver for it913x-fe Frontend
- *
- *  with support for on chip it9137 integral tuner
- *
- *  Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
- *  IT9137 Copyright (C) ITE Tech Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-#include "dvb_frontend.h"
-#include "it913x-fe.h"
-#include "it913x-fe-priv.h"
-
-static int it913x_debug;
-
-module_param_named(debug, it913x_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
-
-#define dprintk(level, args...) do { \
-	if (level & it913x_debug) \
-		printk(KERN_DEBUG "it913x-fe: " args); \
-} while (0)
-
-#define deb_info(args...)  dprintk(0x01, args)
-#define debug_data_snipet(level, name, p) \
-	  dprintk(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \
-		*p, *(p+1), *(p+2), *(p+3), *(p+4), \
-			*(p+5), *(p+6), *(p+7));
-#define info(format, arg...) \
-	printk(KERN_INFO "it913x-fe: " format "\n" , ## arg)
-
-struct it913x_fe_state {
-	struct dvb_frontend frontend;
-	struct i2c_adapter *i2c_adap;
-	struct ite_config *config;
-	u8 i2c_addr;
-	u32 frequency;
-	fe_modulation_t constellation;
-	fe_transmit_mode_t transmission_mode;
-	u8 priority;
-	u32 crystalFrequency;
-	u32 adcFrequency;
-	u8 tuner_type;
-	struct adctable *table;
-	fe_status_t it913x_status;
-	u16 tun_xtal;
-	u8 tun_fdiv;
-	u8 tun_clk_mode;
-	u32 tun_fn_min;
-	u32 ucblocks;
-};
-
-static int it913x_read_reg(struct it913x_fe_state *state,
-		u32 reg, u8 *data, u8 count)
-{
-	int ret;
-	u8 pro = PRO_DMOD; /* All reads from demodulator */
-	u8 b[4];
-	struct i2c_msg msg[2] = {
-		{ .addr = state->i2c_addr + (pro << 1), .flags = 0,
-			.buf = b, .len = sizeof(b) },
-		{ .addr = state->i2c_addr + (pro << 1), .flags = I2C_M_RD,
-			.buf = data, .len = count }
-	};
-	b[0] = (u8) reg >> 24;
-	b[1] = (u8)(reg >> 16) & 0xff;
-	b[2] = (u8)(reg >> 8) & 0xff;
-	b[3] = (u8) reg & 0xff;
-
-	ret = i2c_transfer(state->i2c_adap, msg, 2);
-
-	return ret;
-}
-
-static int it913x_read_reg_u8(struct it913x_fe_state *state, u32 reg)
-{
-	int ret;
-	u8 b[1];
-	ret = it913x_read_reg(state, reg, &b[0], sizeof(b));
-	return (ret < 0) ? -ENODEV : b[0];
-}
-
-static int it913x_write(struct it913x_fe_state *state,
-		u8 pro, u32 reg, u8 buf[], u8 count)
-{
-	u8 b[256];
-	struct i2c_msg msg[1] = {
-		{ .addr = state->i2c_addr + (pro << 1), .flags = 0,
-		  .buf = b, .len = count + 4 }
-	};
-	int ret;
-
-	b[0] = (u8) reg >> 24;
-	b[1] = (u8)(reg >> 16) & 0xff;
-	b[2] = (u8)(reg >> 8) & 0xff;
-	b[3] = (u8) reg & 0xff;
-	memcpy(&b[4], buf, count);
-
-	ret = i2c_transfer(state->i2c_adap, msg, 1);
-
-	if (ret < 0)
-		return -EIO;
-
-	return 0;
-}
-
-static int it913x_write_reg(struct it913x_fe_state *state,
-		u8 pro, u32 reg, u32 data)
-{
-	int ret;
-	u8 b[4];
-	u8 s;
-
-	b[0] = data >> 24;
-	b[1] = (data >> 16) & 0xff;
-	b[2] = (data >> 8) & 0xff;
-	b[3] = data & 0xff;
-	/* expand write as needed */
-	if (data < 0x100)
-		s = 3;
-	else if (data < 0x1000)
-		s = 2;
-	else if (data < 0x100000)
-		s = 1;
-	else
-		s = 0;
-
-	ret = it913x_write(state, pro, reg, &b[s], sizeof(b) - s);
-
-	return ret;
-}
-
-static int it913x_fe_script_loader(struct it913x_fe_state *state,
-		struct it913xset *loadscript)
-{
-	int ret, i;
-	if (loadscript == NULL)
-		return -EINVAL;
-
-	for (i = 0; i < 1000; ++i) {
-		if (loadscript[i].pro == 0xff)
-			break;
-		ret = it913x_write(state, loadscript[i].pro,
-			loadscript[i].address,
-			loadscript[i].reg, loadscript[i].count);
-		if (ret < 0)
-			return -ENODEV;
-	}
-	return 0;
-}
-
-static int it913x_init_tuner(struct it913x_fe_state *state)
-{
-	int ret, i, reg;
-	u8 val, nv_val;
-	u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2};
-	u8 b[2];
-
-	reg = it913x_read_reg_u8(state, 0xec86);
-	switch (reg) {
-	case 0:
-		state->tun_clk_mode = reg;
-		state->tun_xtal = 2000;
-		state->tun_fdiv = 3;
-		val = 16;
-		break;
-	case -ENODEV:
-		return -ENODEV;
-	case 1:
-	default:
-		state->tun_clk_mode = reg;
-		state->tun_xtal = 640;
-		state->tun_fdiv = 1;
-		val = 6;
-		break;
-	}
-
-	reg = it913x_read_reg_u8(state, 0xed03);
-
-	if (reg < 0)
-		return -ENODEV;
-	else if (reg < sizeof(nv))
-		nv_val = nv[reg];
-	else
-		nv_val = 2;
-
-	for (i = 0; i < 50; i++) {
-		ret = it913x_read_reg(state, 0xed23, &b[0], sizeof(b));
-		reg = (b[1] << 8) + b[0];
-		if (reg > 0)
-			break;
-		if (ret < 0)
-			return -ENODEV;
-		udelay(2000);
-	}
-	state->tun_fn_min = state->tun_xtal * reg;
-	state->tun_fn_min /= (state->tun_fdiv * nv_val);
-	deb_info("Tuner fn_min %d", state->tun_fn_min);
-
-	if (state->config->chip_ver > 1)
-		msleep(50);
-	else {
-		for (i = 0; i < 50; i++) {
-			reg = it913x_read_reg_u8(state, 0xec82);
-			if (reg > 0)
-				break;
-			if (reg < 0)
-				return -ENODEV;
-			udelay(2000);
-		}
-	}
-
-	return it913x_write_reg(state, PRO_DMOD, 0xed81, val);
-}
-
-static int it9137_set_tuner(struct it913x_fe_state *state,
-		u32 bandwidth, u32 frequency_m)
-{
-	struct it913xset *set_tuner = set_it9137_template;
-	int ret, reg;
-	u32 frequency = frequency_m / 1000;
-	u32 freq, temp_f, tmp;
-	u16 iqik_m_cal;
-	u16 n_div;
-	u8 n;
-	u8 l_band;
-	u8 lna_band;
-	u8 bw;
-
-	if (state->config->firmware_ver == 1)
-		set_tuner = set_it9135_template;
-	else
-		set_tuner = set_it9137_template;
-
-	deb_info("Tuner Frequency %d Bandwidth %d", frequency, bandwidth);
-
-	if (frequency >= 51000 && frequency <= 440000) {
-		l_band = 0;
-		lna_band = 0;
-	} else if (frequency > 440000 && frequency <= 484000) {
-		l_band = 1;
-		lna_band = 1;
-	} else if (frequency > 484000 && frequency <= 533000) {
-		l_band = 1;
-		lna_band = 2;
-	} else if (frequency > 533000 && frequency <= 587000) {
-		l_band = 1;
-		lna_band = 3;
-	} else if (frequency > 587000 && frequency <= 645000) {
-		l_band = 1;
-		lna_band = 4;
-	} else if (frequency > 645000 && frequency <= 710000) {
-		l_band = 1;
-		lna_band = 5;
-	} else if (frequency > 710000 && frequency <= 782000) {
-		l_band = 1;
-		lna_band = 6;
-	} else if (frequency > 782000 && frequency <= 860000) {
-		l_band = 1;
-		lna_band = 7;
-	} else if (frequency > 1450000 && frequency <= 1492000) {
-		l_band = 1;
-		lna_band = 0;
-	} else if (frequency > 1660000 && frequency <= 1685000) {
-		l_band = 1;
-		lna_band = 1;
-	} else
-		return -EINVAL;
-	set_tuner[0].reg[0] = lna_band;
-
-	switch (bandwidth) {
-	case 5000000:
-		bw = 0;
-		break;
-	case 6000000:
-		bw = 2;
-		break;
-	case 7000000:
-		bw = 4;
-		break;
-	default:
-	case 8000000:
-		bw = 6;
-		break;
-	}
-
-	set_tuner[1].reg[0] = bw;
-	set_tuner[2].reg[0] = 0xa0 | (l_band << 3);
-
-	if (frequency > 53000 && frequency <= 74000) {
-		n_div = 48;
-		n = 0;
-	} else if (frequency > 74000 && frequency <= 111000) {
-		n_div = 32;
-		n = 1;
-	} else if (frequency > 111000 && frequency <= 148000) {
-		n_div = 24;
-		n = 2;
-	} else if (frequency > 148000 && frequency <= 222000) {
-		n_div = 16;
-		n = 3;
-	} else if (frequency > 222000 && frequency <= 296000) {
-		n_div = 12;
-		n = 4;
-	} else if (frequency > 296000 && frequency <= 445000) {
-		n_div = 8;
-		n = 5;
-	} else if (frequency > 445000 && frequency <= state->tun_fn_min) {
-		n_div = 6;
-		n = 6;
-	} else if (frequency > state->tun_fn_min && frequency <= 950000) {
-		n_div = 4;
-		n = 7;
-	} else if (frequency > 1450000 && frequency <= 1680000) {
-		n_div = 2;
-		n = 0;
-	} else
-		return -EINVAL;
-
-	reg = it913x_read_reg_u8(state, 0xed81);
-	iqik_m_cal = (u16)reg * n_div;
-
-	if (reg < 0x20) {
-		if (state->tun_clk_mode == 0)
-			iqik_m_cal = (iqik_m_cal * 9) >> 5;
-		else
-			iqik_m_cal >>= 1;
-	} else {
-		iqik_m_cal = 0x40 - iqik_m_cal;
-		if (state->tun_clk_mode == 0)
-			iqik_m_cal = ~((iqik_m_cal * 9) >> 5);
-		else
-			iqik_m_cal = ~(iqik_m_cal >> 1);
-	}
-
-	temp_f = frequency * (u32)n_div * (u32)state->tun_fdiv;
-	freq = temp_f / state->tun_xtal;
-	tmp = freq * state->tun_xtal;
-
-	if ((temp_f - tmp) >= (state->tun_xtal >> 1))
-		freq++;
-
-	freq += (u32) n << 13;
-	/* Frequency OMEGA_IQIK_M_CAL_MID*/
-	temp_f = freq + (u32)iqik_m_cal;
-
-	set_tuner[3].reg[0] =  temp_f & 0xff;
-	set_tuner[4].reg[0] =  (temp_f >> 8) & 0xff;
-
-	deb_info("High Frequency = %04x", temp_f);
-
-	/* Lower frequency */
-	set_tuner[5].reg[0] =  freq & 0xff;
-	set_tuner[6].reg[0] =  (freq >> 8) & 0xff;
-
-	deb_info("low Frequency = %04x", freq);
-
-	ret = it913x_fe_script_loader(state, set_tuner);
-
-	return (ret < 0) ? -ENODEV : 0;
-}
-
-static int it913x_fe_select_bw(struct it913x_fe_state *state,
-			u32 bandwidth, u32 adcFrequency)
-{
-	int ret, i;
-	u8 buffer[256];
-	u32 coeff[8];
-	u16 bfsfcw_fftinx_ratio;
-	u16 fftinx_bfsfcw_ratio;
-	u8 count;
-	u8 bw;
-	u8 adcmultiplier;
-
-	deb_info("Bandwidth %d Adc %d", bandwidth, adcFrequency);
-
-	switch (bandwidth) {
-	case 5000000:
-		bw = 3;
-		break;
-	case 6000000:
-		bw = 0;
-		break;
-	case 7000000:
-		bw = 1;
-		break;
-	default:
-	case 8000000:
-		bw = 2;
-		break;
-	}
-	ret = it913x_write_reg(state, PRO_DMOD, REG_BW, bw);
-
-	if (state->table == NULL)
-		return -EINVAL;
-
-	/* In write order */
-	coeff[0] = state->table[bw].coeff_1_2048;
-	coeff[1] = state->table[bw].coeff_2_2k;
-	coeff[2] = state->table[bw].coeff_1_8191;
-	coeff[3] = state->table[bw].coeff_1_8192;
-	coeff[4] = state->table[bw].coeff_1_8193;
-	coeff[5] = state->table[bw].coeff_2_8k;
-	coeff[6] = state->table[bw].coeff_1_4096;
-	coeff[7] = state->table[bw].coeff_2_4k;
-	bfsfcw_fftinx_ratio = state->table[bw].bfsfcw_fftinx_ratio;
-	fftinx_bfsfcw_ratio = state->table[bw].fftinx_bfsfcw_ratio;
-
-	/* ADC multiplier */
-	ret = it913x_read_reg_u8(state, ADC_X_2);
-	if (ret < 0)
-		return -EINVAL;
-
-	adcmultiplier = ret;
-
-	count = 0;
-
-	/*  Build Buffer for COEFF Registers */
-	for (i = 0; i < 8; i++) {
-		if (adcmultiplier == 1)
-			coeff[i] /= 2;
-		buffer[count++] = (coeff[i] >> 24) & 0x3;
-		buffer[count++] = (coeff[i] >> 16) & 0xff;
-		buffer[count++] = (coeff[i] >> 8) & 0xff;
-		buffer[count++] = coeff[i] & 0xff;
-	}
-
-	/* bfsfcw_fftinx_ratio register 0x21-0x22 */
-	buffer[count++] = bfsfcw_fftinx_ratio & 0xff;
-	buffer[count++] = (bfsfcw_fftinx_ratio >> 8) & 0xff;
-	/* fftinx_bfsfcw_ratio register 0x23-0x24 */
-	buffer[count++] = fftinx_bfsfcw_ratio & 0xff;
-	buffer[count++] = (fftinx_bfsfcw_ratio >> 8) & 0xff;
-	/* start at COEFF_1_2048 and write through to fftinx_bfsfcw_ratio*/
-	ret = it913x_write(state, PRO_DMOD, COEFF_1_2048, buffer, count);
-
-	for (i = 0; i < 42; i += 8)
-		debug_data_snipet(0x1, "Buffer", &buffer[i]);
-
-	return ret;
-}
-
-
-
-static int it913x_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct it913x_fe_state *state = fe->demodulator_priv;
-	int ret, i;
-	fe_status_t old_status = state->it913x_status;
-	*status = 0;
-
-	if (state->it913x_status == 0) {
-		ret = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS);
-		if (ret == 0x1) {
-			*status |= FE_HAS_SIGNAL;
-			for (i = 0; i < 40; i++) {
-				ret = it913x_read_reg_u8(state, MP2IF_SYNC_LK);
-				if (ret == 0x1)
-					break;
-				msleep(25);
-			}
-			if (ret == 0x1)
-				*status |= FE_HAS_CARRIER
-					| FE_HAS_VITERBI
-					| FE_HAS_SYNC;
-			state->it913x_status = *status;
-		}
-	}
-
-	if (state->it913x_status & FE_HAS_SYNC) {
-		ret = it913x_read_reg_u8(state, TPSD_LOCK);
-		if (ret == 0x1)
-			*status |= FE_HAS_LOCK
-				| state->it913x_status;
-		else
-			state->it913x_status = 0;
-		if (old_status != state->it913x_status)
-			ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, ret);
-	}
-
-	return 0;
-}
-
-/* FEC values based on fe_code_rate_t non supported values 0*/
-int it913x_qpsk_pval[] = {0, -93, -91, -90, 0, -89, -88};
-int it913x_16qam_pval[] = {0, -87, -85, -84, 0, -83, -82};
-int it913x_64qam_pval[] = {0, -82, -80, -78, 0, -77, -76};
-
-static int it913x_get_signal_strength(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct it913x_fe_state *state = fe->demodulator_priv;
-	u8 code_rate;
-	int ret, temp;
-	u8 lna_gain_os;
-
-	ret = it913x_read_reg_u8(state, VAR_P_INBAND);
-	if (ret < 0)
-		return ret;
-
-	/* VHF/UHF gain offset */
-	if (state->frequency < 300000000)
-		lna_gain_os = 7;
-	else
-		lna_gain_os = 14;
-
-	temp = (ret - 100) - lna_gain_os;
-
-	if (state->priority == PRIORITY_HIGH)
-		code_rate = p->code_rate_HP;
-	else
-		code_rate = p->code_rate_LP;
-
-	if (code_rate >= ARRAY_SIZE(it913x_qpsk_pval))
-		return -EINVAL;
-
-	deb_info("Reg VAR_P_INBAND:%d Calc Offset Value:%d", ret, temp);
-
-	/* Apply FEC offset values*/
-	switch (p->modulation) {
-	case QPSK:
-		temp -= it913x_qpsk_pval[code_rate];
-		break;
-	case QAM_16:
-		temp -= it913x_16qam_pval[code_rate];
-		break;
-	case QAM_64:
-		temp -= it913x_64qam_pval[code_rate];
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (temp < -15)
-		ret = 0;
-	else if ((-15 <= temp) && (temp < 0))
-		ret = (2 * (temp + 15)) / 3;
-	else if ((0 <= temp) && (temp < 20))
-		ret = 4 * temp + 10;
-	else if ((20 <= temp) && (temp < 35))
-		ret = (2 * (temp - 20)) / 3 + 90;
-	else if (temp >= 35)
-		ret = 100;
-
-	deb_info("Signal Strength :%d", ret);
-
-	return ret;
-}
-
-static int it913x_fe_read_signal_strength(struct dvb_frontend *fe,
-		u16 *strength)
-{
-	struct it913x_fe_state *state = fe->demodulator_priv;
-	int ret = 0;
-	if (state->config->read_slevel) {
-		if (state->it913x_status & FE_HAS_SIGNAL)
-			ret = it913x_read_reg_u8(state, SIGNAL_LEVEL);
-	} else
-		ret = it913x_get_signal_strength(fe);
-
-	if (ret >= 0)
-		*strength = (u16)((u32)ret * 0xffff / 0x64);
-
-	return (ret < 0) ? -ENODEV : 0;
-}
-
-static int it913x_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct it913x_fe_state *state = fe->demodulator_priv;
-	int ret;
-	u8 reg[3];
-	u32 snr_val, snr_min, snr_max;
-	u32 temp;
-
-	ret = it913x_read_reg(state, 0x2c, reg, sizeof(reg));
-
-	snr_val = (u32)(reg[2] << 16) | (reg[1] << 8) | reg[0];
-
-	ret |= it913x_read_reg(state, 0xf78b, reg, 1);
-	if (reg[0])
-		snr_val /= reg[0];
-
-	if (state->transmission_mode == TRANSMISSION_MODE_2K)
-		snr_val *= 4;
-	else if (state->transmission_mode == TRANSMISSION_MODE_4K)
-		snr_val *= 2;
-
-	if (state->constellation == QPSK) {
-		snr_min = 0xb4711;
-		snr_max = 0x191451;
-	} else if (state->constellation == QAM_16) {
-		snr_min = 0x4f0d5;
-		snr_max = 0xc7925;
-	} else if (state->constellation == QAM_64) {
-		snr_min = 0x256d0;
-		snr_max = 0x626be;
-	} else
-		return -EINVAL;
-
-	if (snr_val < snr_min)
-		*snr = 0;
-	else if (snr_val < snr_max) {
-		temp = (snr_val - snr_min) >> 5;
-		temp *= 0xffff;
-		temp /= (snr_max - snr_min) >> 5;
-		*snr = (u16)temp;
-	} else
-		*snr = 0xffff;
-
-	return (ret < 0) ? -ENODEV : 0;
-}
-
-static int it913x_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct it913x_fe_state *state = fe->demodulator_priv;
-	u8 reg[5];
-	/* Read Aborted Packets and Pre-Viterbi error rate 5 bytes */
-	it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg));
-	state->ucblocks += (u32)(reg[1] << 8) | reg[0];
-	*ber = (u32)(reg[4] << 16) | (reg[3] << 8) | reg[2];
-	return 0;
-}
-
-static int it913x_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct it913x_fe_state *state = fe->demodulator_priv;
-	int ret;
-	u8 reg[2];
-	/* Aborted Packets */
-	ret = it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg));
-	state->ucblocks += (u32)(reg[1] << 8) | reg[0];
-	*ucblocks = state->ucblocks;
-	return ret;
-}
-
-static int it913x_fe_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct it913x_fe_state *state = fe->demodulator_priv;
-	u8 reg[8];
-
-	it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg));
-
-	if (reg[3] < 3)
-		p->modulation = fe_con[reg[3]];
-
-	if (reg[0] < 3)
-		p->transmission_mode = fe_mode[reg[0]];
-
-	if (reg[1] < 4)
-		p->guard_interval = fe_gi[reg[1]];
-
-	if (reg[2] < 4)
-		p->hierarchy = fe_hi[reg[2]];
-
-	state->priority = reg[5];
-
-	p->code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE;
-	p->code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE;
-
-	/* Update internal state to reflect the autodetected props */
-	state->constellation = p->modulation;
-	state->transmission_mode = p->transmission_mode;
-
-	return 0;
-}
-
-static int it913x_fe_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct it913x_fe_state *state = fe->demodulator_priv;
-	int i;
-	u8 empty_ch, last_ch;
-
-	state->it913x_status = 0;
-
-	/* Set bw*/
-	it913x_fe_select_bw(state, p->bandwidth_hz,
-		state->adcFrequency);
-
-	/* Training Mode Off */
-	it913x_write_reg(state, PRO_LINK, TRAINING_MODE, 0x0);
-
-	/* Clear Empty Channel */
-	it913x_write_reg(state, PRO_DMOD, EMPTY_CHANNEL_STATUS, 0x0);
-
-	/* Clear bits */
-	it913x_write_reg(state, PRO_DMOD, MP2IF_SYNC_LK, 0x0);
-	/* LED on */
-	it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1);
-	/* Select Band*/
-	if ((p->frequency >= 51000000) && (p->frequency <= 230000000))
-		i = 0;
-	else if ((p->frequency >= 350000000) && (p->frequency <= 900000000))
-			i = 1;
-	else if ((p->frequency >= 1450000000) && (p->frequency <= 1680000000))
-			i = 2;
-	else
-		return -EOPNOTSUPP;
-
-	it913x_write_reg(state, PRO_DMOD, FREE_BAND, i);
-
-	deb_info("Frontend Set Tuner Type %02x", state->tuner_type);
-	switch (state->tuner_type) {
-	case IT9135_38:
-	case IT9135_51:
-	case IT9135_52:
-	case IT9135_60:
-	case IT9135_61:
-	case IT9135_62:
-		it9137_set_tuner(state,
-			p->bandwidth_hz, p->frequency);
-		break;
-	default:
-		if (fe->ops.tuner_ops.set_params) {
-			fe->ops.tuner_ops.set_params(fe);
-			if (fe->ops.i2c_gate_ctrl)
-				fe->ops.i2c_gate_ctrl(fe, 0);
-		}
-		break;
-	}
-	/* LED off */
-	it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0);
-	/* Trigger ofsm */
-	it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0);
-	last_ch = 2;
-	for (i = 0; i < 40; ++i) {
-		empty_ch = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS);
-		if (last_ch == 1 && empty_ch == 1)
-			break;
-		if (last_ch == 2 && empty_ch == 2)
-			return 0;
-		last_ch = empty_ch;
-		msleep(25);
-	}
-	for (i = 0; i < 40; ++i) {
-		if (it913x_read_reg_u8(state, D_TPSD_LOCK) == 1)
-			break;
-		msleep(25);
-	}
-
-	state->frequency = p->frequency;
-	return 0;
-}
-
-static int it913x_fe_suspend(struct it913x_fe_state *state)
-{
-	int ret, i;
-	u8 b;
-
-	ret = it913x_write_reg(state, PRO_DMOD, SUSPEND_FLAG, 0x1);
-
-	ret |= it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0);
-
-	for (i = 0; i < 128; i++) {
-		ret = it913x_read_reg(state, SUSPEND_FLAG, &b, 1);
-		if (ret < 0)
-			return -ENODEV;
-		if (b == 0)
-			break;
-
-	}
-
-	ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x8);
-	/* Turn LED off */
-	ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0);
-
-	ret |= it913x_fe_script_loader(state, it9137_tuner_off);
-
-	return (ret < 0) ? -ENODEV : 0;
-}
-
-/* Power sequence */
-/* Power Up	Tuner on -> Frontend suspend off -> Tuner clk on */
-/* Power Down	Frontend suspend on -> Tuner clk off -> Tuner off */
-
-static int it913x_fe_sleep(struct dvb_frontend *fe)
-{
-	struct it913x_fe_state *state = fe->demodulator_priv;
-	return it913x_fe_suspend(state);
-}
-
-static u32 compute_div(u32 a, u32 b, u32 x)
-{
-	u32 res = 0;
-	u32 c = 0;
-	u32 i = 0;
-
-	if (a > b) {
-		c = a / b;
-		a = a - c * b;
-	}
-
-	for (i = 0; i < x; i++) {
-		if (a >= b) {
-			res += 1;
-			a -= b;
-		}
-		a <<= 1;
-		res <<= 1;
-	}
-
-	res = (c << x) + res;
-
-	return res;
-}
-
-static int it913x_fe_start(struct it913x_fe_state *state)
-{
-	struct it913xset *set_lna;
-	struct it913xset *set_mode;
-	int ret;
-	u8 adf = (state->config->adf & 0xf);
-	u32 adc, xtal;
-	u8 b[4];
-
-	if (state->config->chip_ver == 1)
-		ret = it913x_init_tuner(state);
-
-	info("ADF table value	:%02x", adf);
-
-	if (adf < 10) {
-		state->crystalFrequency = fe_clockTable[adf].xtal ;
-		state->table = fe_clockTable[adf].table;
-		state->adcFrequency = state->table->adcFrequency;
-
-		adc = compute_div(state->adcFrequency, 1000000ul, 19ul);
-		xtal = compute_div(state->crystalFrequency, 1000000ul, 19ul);
-
-	} else
-		return -EINVAL;
-
-	/* Set LED indicator on GPIOH3 */
-	ret = it913x_write_reg(state, PRO_LINK, GPIOH3_EN, 0x1);
-	ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_ON, 0x1);
-	ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1);
-
-	ret |= it913x_write_reg(state, PRO_LINK, 0xf641, state->tuner_type);
-	ret |= it913x_write_reg(state, PRO_DMOD, 0xf5ca, 0x01);
-	ret |= it913x_write_reg(state, PRO_DMOD, 0xf715, 0x01);
-
-	b[0] = xtal & 0xff;
-	b[1] = (xtal >> 8) & 0xff;
-	b[2] = (xtal >> 16) & 0xff;
-	b[3] = (xtal >> 24);
-	ret |= it913x_write(state, PRO_DMOD, XTAL_CLK, b , 4);
-
-	b[0] = adc & 0xff;
-	b[1] = (adc >> 8) & 0xff;
-	b[2] = (adc >> 16) & 0xff;
-	ret |= it913x_write(state, PRO_DMOD, ADC_FREQ, b, 3);
-
-	if (state->config->adc_x2)
-		ret |= it913x_write_reg(state, PRO_DMOD, ADC_X_2, 0x01);
-	b[0] = 0;
-	b[1] = 0;
-	b[2] = 0;
-	ret |= it913x_write(state, PRO_DMOD, 0x0029, b, 3);
-
-	info("Crystal Frequency :%d Adc Frequency :%d ADC X2: %02x",
-		state->crystalFrequency, state->adcFrequency,
-			state->config->adc_x2);
-	deb_info("Xtal value :%04x Adc value :%04x", xtal, adc);
-
-	if (ret < 0)
-		return -ENODEV;
-
-	/* v1 or v2 tuner script */
-	if (state->config->chip_ver > 1)
-		ret = it913x_fe_script_loader(state, it9135_v2);
-	else
-		ret = it913x_fe_script_loader(state, it9135_v1);
-	if (ret < 0)
-		return ret;
-
-	/* LNA Scripts */
-	switch (state->tuner_type) {
-	case IT9135_51:
-		set_lna = it9135_51;
-		break;
-	case IT9135_52:
-		set_lna = it9135_52;
-		break;
-	case IT9135_60:
-		set_lna = it9135_60;
-		break;
-	case IT9135_61:
-		set_lna = it9135_61;
-		break;
-	case IT9135_62:
-		set_lna = it9135_62;
-		break;
-	case IT9135_38:
-	default:
-		set_lna = it9135_38;
-	}
-	info("Tuner LNA type :%02x", state->tuner_type);
-
-	ret = it913x_fe_script_loader(state, set_lna);
-	if (ret < 0)
-		return ret;
-
-	if (state->config->chip_ver == 2) {
-		ret = it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x1);
-		ret |= it913x_write_reg(state, PRO_LINK, PADODPU, 0x0);
-		ret |= it913x_write_reg(state, PRO_LINK, AGC_O_D, 0x0);
-		ret |= it913x_init_tuner(state);
-	}
-	if (ret < 0)
-		return -ENODEV;
-
-	/* Always solo frontend */
-	set_mode = set_solo_fe;
-	ret |= it913x_fe_script_loader(state, set_mode);
-
-	ret |= it913x_fe_suspend(state);
-	return (ret < 0) ? -ENODEV : 0;
-}
-
-static int it913x_fe_init(struct dvb_frontend *fe)
-{
-	struct it913x_fe_state *state = fe->demodulator_priv;
-	int ret = 0;
-	/* Power Up Tuner - common all versions */
-	ret = it913x_write_reg(state, PRO_DMOD, 0xec40, 0x1);
-
-	ret |= it913x_fe_script_loader(state, init_1);
-
-	ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0);
-
-	ret |= it913x_write_reg(state, PRO_DMOD, 0xfba8, 0x0);
-
-	return (ret < 0) ? -ENODEV : 0;
-}
-
-static void it913x_fe_release(struct dvb_frontend *fe)
-{
-	struct it913x_fe_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops it913x_fe_ofdm_ops;
-
-struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap,
-		u8 i2c_addr, struct ite_config *config)
-{
-	struct it913x_fe_state *state = NULL;
-	int ret;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct it913x_fe_state), GFP_KERNEL);
-	if (state == NULL)
-		return NULL;
-	if (config == NULL)
-		goto error;
-
-	state->i2c_adap = i2c_adap;
-	state->i2c_addr = i2c_addr;
-	state->config = config;
-
-	switch (state->config->tuner_id_0) {
-	case IT9135_51:
-	case IT9135_52:
-	case IT9135_60:
-	case IT9135_61:
-	case IT9135_62:
-		state->tuner_type = state->config->tuner_id_0;
-		break;
-	default:
-	case IT9135_38:
-		state->tuner_type = IT9135_38;
-	}
-
-	ret = it913x_fe_start(state);
-	if (ret < 0)
-		goto error;
-
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &it913x_fe_ofdm_ops,
-			sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-
-	return &state->frontend;
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(it913x_fe_attach);
-
-static struct dvb_frontend_ops it913x_fe_ofdm_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name			= "it913x-fe DVB-T",
-		.frequency_min		= 51000000,
-		.frequency_max		= 1680000000,
-		.frequency_stepsize	= 62500,
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
-			FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
-			FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_HIERARCHY_AUTO,
-	},
-
-	.release = it913x_fe_release,
-
-	.init = it913x_fe_init,
-	.sleep = it913x_fe_sleep,
-
-	.set_frontend = it913x_fe_set_frontend,
-	.get_frontend = it913x_fe_get_frontend,
-
-	.read_status = it913x_fe_read_status,
-	.read_signal_strength = it913x_fe_read_signal_strength,
-	.read_snr = it913x_fe_read_snr,
-	.read_ber = it913x_fe_read_ber,
-	.read_ucblocks = it913x_fe_read_ucblocks,
-};
-
-MODULE_DESCRIPTION("it913x Frontend and it9137 tuner");
-MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
-MODULE_VERSION("1.15");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/it913x-fe.h b/drivers/media/dvb/frontends/it913x-fe.h
deleted file mode 100644
index 07fa459..0000000
--- a/drivers/media/dvb/frontends/it913x-fe.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- *  Driver for it913x Frontend
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef IT913X_FE_H
-#define IT913X_FE_H
-
-#include <linux/dvb/frontend.h>
-#include "dvb_frontend.h"
-
-struct ite_config {
-	u8 chip_ver;
-	u16 chip_type;
-	u32 firmware;
-	u8 firmware_ver;
-	u8 adc_x2;
-	u8 tuner_id_0;
-	u8 tuner_id_1;
-	u8 dual_mode;
-	u8 adf;
-	/* option to read SIGNAL_LEVEL */
-	u8 read_slevel;
-};
-
-#if defined(CONFIG_DVB_IT913X_FE) || (defined(CONFIG_DVB_IT913X_FE_MODULE) && \
-defined(MODULE))
-extern struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap,
-			u8 i2c_addr, struct ite_config *config);
-#else
-static inline struct dvb_frontend *it913x_fe_attach(
-		struct i2c_adapter *i2c_adap,
-			u8 i2c_addr, struct ite_config *config)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_IT913X_FE */
-#define I2C_BASE_ADDR		0x10
-#define DEV_0			0x0
-#define DEV_1			0x10
-#define PRO_LINK		0x0
-#define PRO_DMOD		0x1
-#define DEV_0_DMOD		(PRO_DMOD << 0x7)
-#define DEV_1_DMOD		(DEV_0_DMOD | DEV_1)
-#define CHIP2_I2C_ADDR		0x3a
-
-#define AFE_MEM0		0xfb24
-
-#define MP2_SW_RST		0xf99d
-#define MP2IF2_SW_RST		0xf9a4
-
-#define	PADODPU			0xd827
-#define THIRDODPU		0xd828
-#define AGC_O_D			0xd829
-
-#define EP0_TX_EN		0xdd11
-#define EP0_TX_NAK		0xdd13
-#define EP4_TX_LEN_LSB		0xdd88
-#define EP4_TX_LEN_MSB		0xdd89
-#define EP4_MAX_PKT		0xdd0c
-#define EP5_TX_LEN_LSB		0xdd8a
-#define EP5_TX_LEN_MSB		0xdd8b
-#define EP5_MAX_PKT		0xdd0d
-
-#define IO_MUX_POWER_CLK	0xd800
-#define CLK_O_EN		0xd81a
-#define I2C_CLK			0xf103
-#define I2C_CLK_100		0x7
-#define I2C_CLK_400		0x1a
-
-#define D_TPSD_LOCK		0xf5a9
-#define MP2IF2_EN		0xf9a3
-#define MP2IF_SERIAL		0xf985
-#define TSIS_ENABLE		0xf9cd
-#define MP2IF2_HALF_PSB		0xf9a5
-#define MP2IF_STOP_EN		0xf9b5
-#define MPEG_FULL_SPEED		0xf990
-#define TOP_HOSTB_SER_MODE	0xd91c
-
-#define PID_RST			0xf992
-#define PID_EN			0xf993
-#define PID_INX_EN		0xf994
-#define PID_INX			0xf995
-#define PID_LSB			0xf996
-#define PID_MSB			0xf997
-
-#define MP2IF_MPEG_PAR_MODE	0xf986
-#define DCA_UPPER_CHIP		0xf731
-#define DCA_LOWER_CHIP		0xf732
-#define DCA_PLATCH		0xf730
-#define DCA_FPGA_LATCH		0xf778
-#define DCA_STAND_ALONE		0xf73c
-#define DCA_ENABLE		0xf776
-
-#define DVBT_INTEN		0xf41f
-#define DVBT_ENABLE		0xf41a
-#define HOSTB_DCA_LOWER		0xd91f
-#define HOSTB_MPEG_PAR_MODE	0xd91b
-#define HOSTB_MPEG_SER_MODE	0xd91c
-#define HOSTB_MPEG_SER_DO7	0xd91d
-#define HOSTB_DCA_UPPER		0xd91e
-#define PADMISCDR2		0xd830
-#define PADMISCDR4		0xd831
-#define PADMISCDR8		0xd832
-#define PADMISCDRSR		0xd833
-#define LOCK3_OUT		0xd8fd
-
-#define GPIOH1_O		0xd8af
-#define GPIOH1_EN		0xd8b0
-#define GPIOH1_ON		0xd8b1
-#define GPIOH3_O		0xd8b3
-#define GPIOH3_EN		0xd8b4
-#define GPIOH3_ON		0xd8b5
-#define GPIOH5_O		0xd8bb
-#define GPIOH5_EN		0xd8bc
-#define GPIOH5_ON		0xd8bd
-
-#define AFE_MEM0		0xfb24
-
-#define REG_TPSD_TX_MODE	0xf900
-#define REG_TPSD_GI		0xf901
-#define REG_TPSD_HIER		0xf902
-#define REG_TPSD_CONST		0xf903
-#define REG_BW			0xf904
-#define REG_PRIV		0xf905
-#define REG_TPSD_HP_CODE	0xf906
-#define REG_TPSD_LP_CODE	0xf907
-
-#define MP2IF_SYNC_LK		0xf999
-#define ADC_FREQ		0xf1cd
-
-#define TRIGGER_OFSM		0x0000
-/* COEFF Registers start at 0x0001 to 0x0020 */
-#define COEFF_1_2048		0x0001
-#define XTAL_CLK		0x0025
-#define BFS_FCW			0x0029
-
-/* Error Regs */
-#define RSD_ABORT_PKT_LSB	0x0032
-#define RSD_ABORT_PKT_MSB	0x0033
-#define RSD_BIT_ERR_0_7		0x0034
-#define RSD_BIT_ERR_8_15	0x0035
-#define RSD_BIT_ERR_23_16	0x0036
-#define RSD_BIT_COUNT_LSB	0x0037
-#define RSD_BIT_COUNT_MSB	0x0038
-
-#define TPSD_LOCK		0x003c
-#define TRAINING_MODE		0x0040
-#define ADC_X_2			0x0045
-#define TUNER_ID		0x0046
-#define EMPTY_CHANNEL_STATUS	0x0047
-#define SIGNAL_LEVEL		0x0048
-#define SIGNAL_QUALITY		0x0049
-#define EST_SIGNAL_LEVEL	0x004a
-#define FREE_BAND		0x004b
-#define SUSPEND_FLAG		0x004c
-#define VAR_P_INBAND		0x00f7
-
-/* Build in tuner types */
-#define IT9137 0x38
-#define IT9135_38 0x38
-#define IT9135_51 0x51
-#define IT9135_52 0x52
-#define IT9135_60 0x60
-#define IT9135_61 0x61
-#define IT9135_62 0x62
-
-enum {
-	CMD_DEMOD_READ = 0,
-	CMD_DEMOD_WRITE,
-	CMD_TUNER_READ,
-	CMD_TUNER_WRITE,
-	CMD_REG_EEPROM_READ,
-	CMD_REG_EEPROM_WRITE,
-	CMD_DATA_READ,
-	CMD_VAR_READ = 8,
-	CMD_VAR_WRITE,
-	CMD_PLATFORM_GET,
-	CMD_PLATFORM_SET,
-	CMD_IP_CACHE,
-	CMD_IP_ADD,
-	CMD_IP_REMOVE,
-	CMD_PID_ADD,
-	CMD_PID_REMOVE,
-	CMD_SIPSI_GET,
-	CMD_SIPSI_MPE_RESET,
-	CMD_H_PID_ADD = 0x15,
-	CMD_H_PID_REMOVE,
-	CMD_ABORT,
-	CMD_IR_GET,
-	CMD_IR_SET,
-	CMD_FW_DOWNLOAD = 0x21,
-	CMD_QUERYINFO,
-	CMD_BOOT,
-	CMD_FW_DOWNLOAD_BEGIN,
-	CMD_FW_DOWNLOAD_END,
-	CMD_RUN_CODE,
-	CMD_SCATTER_READ = 0x28,
-	CMD_SCATTER_WRITE,
-	CMD_GENERIC_READ,
-	CMD_GENERIC_WRITE
-};
-
-enum {
-	READ_LONG,
-	WRITE_LONG,
-	READ_SHORT,
-	WRITE_SHORT,
-	READ_DATA,
-	WRITE_DATA,
-	WRITE_CMD,
-};
-
-enum {
-	IT9135_AUTO = 0,
-	IT9137_FW,
-	IT9135_V1_FW,
-	IT9135_V2_FW,
-};
-
-#endif /* IT913X_FE_H */
diff --git a/drivers/media/dvb/frontends/itd1000.c b/drivers/media/dvb/frontends/itd1000.c
deleted file mode 100644
index 3164575..0000000
--- a/drivers/media/dvb/frontends/itd1000.c
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- *  Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite"
- *
- *  Copyright (c) 2007-8 Patrick Boettcher <pb@linuxtv.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/delay.h>
-#include <linux/dvb/frontend.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-
-#include "itd1000.h"
-#include "itd1000_priv.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-#define itd_dbg(args...)  do { \
-	if (debug) { \
-		printk(KERN_DEBUG   "ITD1000: " args);\
-	} \
-} while (0)
-
-#define itd_warn(args...) do { \
-	printk(KERN_WARNING "ITD1000: " args); \
-} while (0)
-
-#define itd_info(args...) do { \
-	printk(KERN_INFO    "ITD1000: " args); \
-} while (0)
-
-/* don't write more than one byte with flexcop behind */
-static int itd1000_write_regs(struct itd1000_state *state, u8 reg, u8 v[], u8 len)
-{
-	u8 buf[1+len];
-	struct i2c_msg msg = {
-		.addr = state->cfg->i2c_address, .flags = 0, .buf = buf, .len = len+1
-	};
-	buf[0] = reg;
-	memcpy(&buf[1], v, len);
-
-	/* itd_dbg("wr %02x: %02x\n", reg, v[0]); */
-
-	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
-		printk(KERN_WARNING "itd1000 I2C write failed\n");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int itd1000_read_reg(struct itd1000_state *state, u8 reg)
-{
-	u8 val;
-	struct i2c_msg msg[2] = {
-		{ .addr = state->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
-		{ .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = &val, .len = 1 },
-	};
-
-	/* ugly flexcop workaround */
-	itd1000_write_regs(state, (reg - 1) & 0xff, &state->shadow[(reg - 1) & 0xff], 1);
-
-	if (i2c_transfer(state->i2c, msg, 2) != 2) {
-		itd_warn("itd1000 I2C read failed\n");
-		return -EREMOTEIO;
-	}
-	return val;
-}
-
-static inline int itd1000_write_reg(struct itd1000_state *state, u8 r, u8 v)
-{
-	int ret = itd1000_write_regs(state, r, &v, 1);
-	state->shadow[r] = v;
-	return ret;
-}
-
-
-static struct {
-	u32 symbol_rate;
-	u8  pgaext  : 4; /* PLLFH */
-	u8  bbgvmin : 4; /* BBGVMIN */
-} itd1000_lpf_pga[] = {
-	{        0, 0x8, 0x3 },
-	{  5200000, 0x8, 0x3 },
-	{ 12200000, 0x4, 0x3 },
-	{ 15400000, 0x2, 0x3 },
-	{ 19800000, 0x2, 0x3 },
-	{ 21500000, 0x2, 0x3 },
-	{ 24500000, 0x2, 0x3 },
-	{ 28400000, 0x2, 0x3 },
-	{ 33400000, 0x2, 0x3 },
-	{ 34400000, 0x1, 0x4 },
-	{ 34400000, 0x1, 0x4 },
-	{ 38400000, 0x1, 0x4 },
-	{ 38400000, 0x1, 0x4 },
-	{ 40400000, 0x1, 0x4 },
-	{ 45400000, 0x1, 0x4 },
-};
-
-static void itd1000_set_lpf_bw(struct itd1000_state *state, u32 symbol_rate)
-{
-	u8 i;
-	u8 con1    = itd1000_read_reg(state, CON1)    & 0xfd;
-	u8 pllfh   = itd1000_read_reg(state, PLLFH)   & 0x0f;
-	u8 bbgvmin = itd1000_read_reg(state, BBGVMIN) & 0xf0;
-	u8 bw      = itd1000_read_reg(state, BW)      & 0xf0;
-
-	itd_dbg("symbol_rate = %d\n", symbol_rate);
-
-	/* not sure what is that ? - starting to download the table */
-	itd1000_write_reg(state, CON1, con1 | (1 << 1));
-
-	for (i = 0; i < ARRAY_SIZE(itd1000_lpf_pga); i++)
-		if (symbol_rate < itd1000_lpf_pga[i].symbol_rate) {
-			itd_dbg("symrate: index: %d pgaext: %x, bbgvmin: %x\n", i, itd1000_lpf_pga[i].pgaext, itd1000_lpf_pga[i].bbgvmin);
-			itd1000_write_reg(state, PLLFH,   pllfh | (itd1000_lpf_pga[i].pgaext << 4));
-			itd1000_write_reg(state, BBGVMIN, bbgvmin | (itd1000_lpf_pga[i].bbgvmin));
-			itd1000_write_reg(state, BW,      bw | (i & 0x0f));
-			break;
-		}
-
-	itd1000_write_reg(state, CON1, con1 | (0 << 1));
-}
-
-static struct {
-	u8 vcorg;
-	u32 fmax_rg;
-} itd1000_vcorg[] = {
-	{  1,  920000 },
-	{  2,  971000 },
-	{  3, 1031000 },
-	{  4, 1091000 },
-	{  5, 1171000 },
-	{  6, 1281000 },
-	{  7, 1381000 },
-	{  8,  500000 },	/* this is intentional. */
-	{  9, 1451000 },
-	{ 10, 1531000 },
-	{ 11, 1631000 },
-	{ 12, 1741000 },
-	{ 13, 1891000 },
-	{ 14, 2071000 },
-	{ 15, 2250000 },
-};
-
-static void itd1000_set_vco(struct itd1000_state *state, u32 freq_khz)
-{
-	u8 i;
-	u8 gvbb_i2c     = itd1000_read_reg(state, GVBB_I2C) & 0xbf;
-	u8 vco_chp1_i2c = itd1000_read_reg(state, VCO_CHP1_I2C) & 0x0f;
-	u8 adcout;
-
-	/* reserved bit again (reset ?) */
-	itd1000_write_reg(state, GVBB_I2C, gvbb_i2c | (1 << 6));
-
-	for (i = 0; i < ARRAY_SIZE(itd1000_vcorg); i++) {
-		if (freq_khz < itd1000_vcorg[i].fmax_rg) {
-			itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | (itd1000_vcorg[i].vcorg << 4));
-			msleep(1);
-
-			adcout = itd1000_read_reg(state, PLLLOCK) & 0x0f;
-
-			itd_dbg("VCO: %dkHz: %d -> ADCOUT: %d %02x\n", freq_khz, itd1000_vcorg[i].vcorg, adcout, vco_chp1_i2c);
-
-			if (adcout > 13) {
-				if (!(itd1000_vcorg[i].vcorg == 7 || itd1000_vcorg[i].vcorg == 15))
-					itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | ((itd1000_vcorg[i].vcorg + 1) << 4));
-			} else if (adcout < 2) {
-				if (!(itd1000_vcorg[i].vcorg == 1 || itd1000_vcorg[i].vcorg == 9))
-					itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | ((itd1000_vcorg[i].vcorg - 1) << 4));
-			}
-			break;
-		}
-	}
-}
-
-static const struct {
-	u32 freq;
-	u8 values[10]; /* RFTR, RFST1 - RFST9 */
-} itd1000_fre_values[] = {
-	{ 1075000, { 0x59, 0x1d, 0x1c, 0x17, 0x16, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
-	{ 1250000, { 0x89, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
-	{ 1450000, { 0x89, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
-	{ 1650000, { 0x69, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
-	{ 1750000, { 0x69, 0x1e, 0x17, 0x15, 0x14, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
-	{ 1850000, { 0x69, 0x1d, 0x17, 0x16, 0x14, 0x0f, 0x0e, 0x0d, 0x0b, 0x0a } },
-	{ 1900000, { 0x69, 0x1d, 0x17, 0x15, 0x14, 0x0f, 0x0e, 0x0d, 0x0b, 0x0a } },
-	{ 1950000, { 0x69, 0x1d, 0x17, 0x16, 0x14, 0x13, 0x0e, 0x0d, 0x0b, 0x0a } },
-	{ 2050000, { 0x69, 0x1e, 0x1d, 0x17, 0x16, 0x14, 0x13, 0x0e, 0x0b, 0x0a } },
-	{ 2150000, { 0x69, 0x1d, 0x1c, 0x17, 0x15, 0x14, 0x13, 0x0f, 0x0e, 0x0b } }
-};
-
-
-#define FREF 16
-
-static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz)
-{
-	int i, j;
-	u32 plln, pllf;
-	u64 tmp;
-
-	plln = (freq_khz * 1000) / 2 / FREF;
-
-	/* Compute the factional part times 1000 */
-	tmp  = plln % 1000000;
-	plln /= 1000000;
-
-	tmp *= 1048576;
-	do_div(tmp, 1000000);
-	pllf = (u32) tmp;
-
-	state->frequency = ((plln * 1000) + (pllf * 1000)/1048576) * 2*FREF;
-	itd_dbg("frequency: %dkHz (wanted) %dkHz (set), PLLF = %d, PLLN = %d\n", freq_khz, state->frequency, pllf, plln);
-
-	itd1000_write_reg(state, PLLNH, 0x80); /* PLLNH */;
-	itd1000_write_reg(state, PLLNL, plln & 0xff);
-	itd1000_write_reg(state, PLLFH, (itd1000_read_reg(state, PLLFH) & 0xf0) | ((pllf >> 16) & 0x0f));
-	itd1000_write_reg(state, PLLFM, (pllf >> 8) & 0xff);
-	itd1000_write_reg(state, PLLFL, (pllf >> 0) & 0xff);
-
-	for (i = 0; i < ARRAY_SIZE(itd1000_fre_values); i++) {
-		if (freq_khz <= itd1000_fre_values[i].freq) {
-			itd_dbg("fre_values: %d\n", i);
-			itd1000_write_reg(state, RFTR, itd1000_fre_values[i].values[0]);
-			for (j = 0; j < 9; j++)
-				itd1000_write_reg(state, RFST1+j, itd1000_fre_values[i].values[j+1]);
-			break;
-		}
-	}
-
-	itd1000_set_vco(state, freq_khz);
-}
-
-static int itd1000_set_parameters(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct itd1000_state *state = fe->tuner_priv;
-	u8 pllcon1;
-
-	itd1000_set_lo(state, c->frequency);
-	itd1000_set_lpf_bw(state, c->symbol_rate);
-
-	pllcon1 = itd1000_read_reg(state, PLLCON1) & 0x7f;
-	itd1000_write_reg(state, PLLCON1, pllcon1 | (1 << 7));
-	itd1000_write_reg(state, PLLCON1, pllcon1);
-
-	return 0;
-}
-
-static int itd1000_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct itd1000_state *state = fe->tuner_priv;
-	*frequency = state->frequency;
-	return 0;
-}
-
-static int itd1000_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	return 0;
-}
-
-static u8 itd1000_init_tab[][2] = {
-	{ PLLCON1,       0x65 }, /* Register does not change */
-	{ PLLNH,         0x80 }, /* Bits [7:6] do not change */
-	{ RESERVED_0X6D, 0x3b },
-	{ VCO_CHP2_I2C,  0x12 },
-	{ 0x72,          0xf9 }, /* No such regsister defined */
-	{ RESERVED_0X73, 0xff },
-	{ RESERVED_0X74, 0xb2 },
-	{ RESERVED_0X75, 0xc7 },
-	{ EXTGVBBRF,     0xf0 },
-	{ DIVAGCCK,      0x80 },
-	{ BBTR,          0xa0 },
-	{ RESERVED_0X7E, 0x4f },
-	{ 0x82,          0x88 }, /* No such regsister defined */
-	{ 0x83,          0x80 }, /* No such regsister defined */
-	{ 0x84,          0x80 }, /* No such regsister defined */
-	{ RESERVED_0X85, 0x74 },
-	{ RESERVED_0X86, 0xff },
-	{ RESERVED_0X88, 0x02 },
-	{ RESERVED_0X89, 0x16 },
-	{ RFST0,         0x1f },
-	{ RESERVED_0X94, 0x66 },
-	{ RESERVED_0X95, 0x66 },
-	{ RESERVED_0X96, 0x77 },
-	{ RESERVED_0X97, 0x99 },
-	{ RESERVED_0X98, 0xff },
-	{ RESERVED_0X99, 0xfc },
-	{ RESERVED_0X9A, 0xba },
-	{ RESERVED_0X9B, 0xaa },
-};
-
-static u8 itd1000_reinit_tab[][2] = {
-	{ VCO_CHP1_I2C, 0x8a },
-	{ BW,           0x87 },
-	{ GVBB_I2C,     0x03 },
-	{ BBGVMIN,      0x03 },
-	{ CON1,         0x2e },
-};
-
-
-static int itd1000_init(struct dvb_frontend *fe)
-{
-	struct itd1000_state *state = fe->tuner_priv;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(itd1000_init_tab); i++)
-		itd1000_write_reg(state, itd1000_init_tab[i][0], itd1000_init_tab[i][1]);
-
-	for (i = 0; i < ARRAY_SIZE(itd1000_reinit_tab); i++)
-		itd1000_write_reg(state, itd1000_reinit_tab[i][0], itd1000_reinit_tab[i][1]);
-
-	return 0;
-}
-
-static int itd1000_sleep(struct dvb_frontend *fe)
-{
-	return 0;
-}
-
-static int itd1000_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static const struct dvb_tuner_ops itd1000_tuner_ops = {
-	.info = {
-		.name           = "Integrant ITD1000",
-		.frequency_min  = 950000,
-		.frequency_max  = 2150000,
-		.frequency_step = 125,     /* kHz for QPSK frontends */
-	},
-
-	.release       = itd1000_release,
-
-	.init          = itd1000_init,
-	.sleep         = itd1000_sleep,
-
-	.set_params    = itd1000_set_parameters,
-	.get_frequency = itd1000_get_frequency,
-	.get_bandwidth = itd1000_get_bandwidth
-};
-
-
-struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg)
-{
-	struct itd1000_state *state = NULL;
-	u8 i = 0;
-
-	state = kzalloc(sizeof(struct itd1000_state), GFP_KERNEL);
-	if (state == NULL)
-		return NULL;
-
-	state->cfg = cfg;
-	state->i2c = i2c;
-
-	i = itd1000_read_reg(state, 0);
-	if (i != 0) {
-		kfree(state);
-		return NULL;
-	}
-	itd_info("successfully identified (ID: %d)\n", i);
-
-	memset(state->shadow, 0xff, sizeof(state->shadow));
-	for (i = 0x65; i < 0x9c; i++)
-		state->shadow[i] = itd1000_read_reg(state, i);
-
-	memcpy(&fe->ops.tuner_ops, &itd1000_tuner_ops, sizeof(struct dvb_tuner_ops));
-
-	fe->tuner_priv = state;
-
-	return fe;
-}
-EXPORT_SYMBOL(itd1000_attach);
-
-MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>");
-MODULE_DESCRIPTION("Integrant ITD1000 driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/itd1000.h b/drivers/media/dvb/frontends/itd1000.h
deleted file mode 100644
index 5e18df0..0000000
--- a/drivers/media/dvb/frontends/itd1000.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- *  Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite"
- *
- *  Copyright (c) 2007 Patrick Boettcher <pb@linuxtv.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef ITD1000_H
-#define ITD1000_H
-
-struct dvb_frontend;
-struct i2c_adapter;
-
-struct itd1000_config {
-	u8 i2c_address;
-};
-
-#if defined(CONFIG_DVB_TUNER_ITD1000) || (defined(CONFIG_DVB_TUNER_ITD1000_MODULE) && defined(MODULE))
-extern struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg);
-#else
-static inline struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/dvb/frontends/itd1000_priv.h b/drivers/media/dvb/frontends/itd1000_priv.h
deleted file mode 100644
index 08ca851..0000000
--- a/drivers/media/dvb/frontends/itd1000_priv.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- *  Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite"
- *
- *  Copyright (c) 2007 Patrick Boettcher <pb@linuxtv.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef ITD1000_PRIV_H
-#define ITD1000_PRIV_H
-
-struct itd1000_state {
-	struct itd1000_config *cfg;
-	struct i2c_adapter    *i2c;
-
-	u32 frequency; /* contains the value resulting from the LO-setting */
-
-	/* ugly workaround for flexcop's incapable i2c-controller
-	 * FIXME, if possible
-	 */
-	u8 shadow[256];
-};
-
-enum itd1000_register {
-	VCO_CHP1 = 0x65,
-	VCO_CHP2,
-	PLLCON1,
-	PLLNH,
-	PLLNL,
-	PLLFH,
-	PLLFM,
-	PLLFL,
-	RESERVED_0X6D,
-	PLLLOCK,
-	VCO_CHP2_I2C,
-	VCO_CHP1_I2C,
-	BW,
-	RESERVED_0X73 = 0x73,
-	RESERVED_0X74,
-	RESERVED_0X75,
-	GVBB,
-	GVRF,
-	GVBB_I2C,
-	EXTGVBBRF,
-	DIVAGCCK,
-	BBTR,
-	RFTR,
-	BBGVMIN,
-	RESERVED_0X7E,
-	RESERVED_0X85 = 0x85,
-	RESERVED_0X86,
-	CON1,
-	RESERVED_0X88,
-	RESERVED_0X89,
-	RFST0,
-	RFST1,
-	RFST2,
-	RFST3,
-	RFST4,
-	RFST5,
-	RFST6,
-	RFST7,
-	RFST8,
-	RFST9,
-	RESERVED_0X94,
-	RESERVED_0X95,
-	RESERVED_0X96,
-	RESERVED_0X97,
-	RESERVED_0X98,
-	RESERVED_0X99,
-	RESERVED_0X9A,
-	RESERVED_0X9B,
-};
-
-#endif
diff --git a/drivers/media/dvb/frontends/ix2505v.c b/drivers/media/dvb/frontends/ix2505v.c
deleted file mode 100644
index bc5a820..0000000
--- a/drivers/media/dvb/frontends/ix2505v.c
+++ /dev/null
@@ -1,325 +0,0 @@
-/**
- * Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner
- *
- * Copyright (C) 2010 Malcolm Priestley
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/module.h>
-#include <linux/dvb/frontend.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-#include "ix2505v.h"
-
-static int ix2505v_debug;
-#define dprintk(level, args...) do { \
-	if (ix2505v_debug & level) \
-		printk(KERN_DEBUG "ix2505v: " args); \
-} while (0)
-
-#define deb_info(args...)  dprintk(0x01, args)
-#define deb_i2c(args...)  dprintk(0x02, args)
-
-struct ix2505v_state {
-	struct i2c_adapter *i2c;
-	const struct ix2505v_config *config;
-	u32 frequency;
-};
-
-/**
- *  Data read format of the Sharp IX2505V B0017
- *
- *  byte1:   1   |   1   |   0   |   0   |   0   |  MA1  |  MA0  |  1
- *  byte2:  POR  |   FL  |  RD2  |  RD1  |  RD0  |   X   |   X   |  X
- *
- *  byte1 = address
- *  byte2;
- *	POR = Power on Reset (VCC H=<2.2v L=>2.2v)
- *	FL  = Phase Lock (H=lock L=unlock)
- *	RD0-2 = Reserved internal operations
- *
- * Only POR can be used to check the tuner is present
- *
- * Caution: after byte2 the I2C reverts to write mode continuing to read
- *          may corrupt tuning data.
- *
- */
-
-static int ix2505v_read_status_reg(struct ix2505v_state *state)
-{
-	u8 addr = state->config->tuner_address;
-	u8 b2[] = {0};
-	int ret;
-
-	struct i2c_msg msg[1] = {
-		{ .addr = addr, .flags = I2C_M_RD, .buf = b2, .len = 1 }
-	};
-
-	ret = i2c_transfer(state->i2c, msg, 1);
-	deb_i2c("Read %s ", __func__);
-
-	return (ret == 1) ? (int) b2[0] : -1;
-}
-
-static int ix2505v_write(struct ix2505v_state *state, u8 buf[], u8 count)
-{
-	struct i2c_msg msg[1] = {
-		{ .addr = state->config->tuner_address, .flags = 0,
-		  .buf = buf, .len = count },
-	};
-
-	int ret;
-
-	ret = i2c_transfer(state->i2c, msg, 1);
-
-	if (ret != 1) {
-		deb_i2c("%s: i2c error, ret=%d\n", __func__, ret);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int ix2505v_release(struct dvb_frontend *fe)
-{
-	struct ix2505v_state *state = fe->tuner_priv;
-
-	fe->tuner_priv = NULL;
-	kfree(state);
-
-	return 0;
-}
-
-/**
- *  Data write format of the Sharp IX2505V B0017
- *
- *  byte1:   1   |   1   |   0   |   0   |   0   | 0(MA1)| 0(MA0)|  0
- *  byte2:   0   |  BG1  |  BG2  |   N8  |   N7  |   N6  |  N5   |  N4
- *  byte3:   N3  |   N2  |   N1  |   A5  |   A4  |   A3  |   A2  |  A1
- *  byte4:   1   | 1(C1) | 1(C0) |  PD5  |  PD4  |   TM  | 0(RTS)| 1(REF)
- *  byte5:   BA2 |   BA1 |  BA0  |  PSC  |  PD3  |PD2/TS2|DIV/TS1|PD0/TS0
- *
- *  byte1 = address
- *
- *  Write order
- *  1) byte1 -> byte2 -> byte3 -> byte4 -> byte5
- *  2) byte1 -> byte4 -> byte5 -> byte2 -> byte3
- *  3) byte1 -> byte2 -> byte3 -> byte4
- *  4) byte1 -> byte4 -> byte5 -> byte2
- *  5) byte1 -> byte2 -> byte3
- *  6) byte1 -> byte4 -> byte5
- *  7) byte1 -> byte2
- *  8) byte1 -> byte4
- *
- *  Recommended Setup
- *  1 -> 8 -> 6
- */
-
-static int ix2505v_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct ix2505v_state *state = fe->tuner_priv;
-	u32 frequency = c->frequency;
-	u32 b_w  = (c->symbol_rate * 27) / 32000;
-	u32 div_factor, N , A, x;
-	int ret = 0, len;
-	u8 gain, cc, ref, psc, local_osc, lpf;
-	u8 data[4] = {0};
-
-	if ((frequency < fe->ops.info.frequency_min)
-	||  (frequency > fe->ops.info.frequency_max))
-		return -EINVAL;
-
-	if (state->config->tuner_gain)
-		gain = (state->config->tuner_gain < 4)
-			? state->config->tuner_gain : 0;
-	else
-		gain = 0x0;
-
-	if (state->config->tuner_chargepump)
-		cc = state->config->tuner_chargepump;
-	else
-		cc = 0x3;
-
-	ref = 8; /* REF =1 */
-	psc = 32; /* PSC = 0 */
-
-	div_factor = (frequency * ref) / 40; /* local osc = 4Mhz */
-	x = div_factor / psc;
-	N = x/100;
-	A = ((x - (N * 100)) * psc) / 100;
-
-	data[0] = ((gain & 0x3) << 5) | (N >> 3);
-	data[1] = (N << 5) | (A & 0x1f);
-	data[2] = 0x81 | ((cc & 0x3) << 5) ; /*PD5,PD4 & TM = 0|C1,C0|REF=1*/
-
-	deb_info("Frq=%d x=%d N=%d A=%d\n", frequency, x, N, A);
-
-	if (frequency <= 1065000)
-		local_osc = (6 << 5) | 2;
-	else if (frequency <= 1170000)
-		local_osc = (7 << 5) | 2;
-	else if (frequency <= 1300000)
-		local_osc = (1 << 5);
-	else if (frequency <= 1445000)
-		local_osc = (2 << 5);
-	else if (frequency <= 1607000)
-		local_osc = (3 << 5);
-	else if (frequency <= 1778000)
-		local_osc = (4 << 5);
-	else if (frequency <= 1942000)
-		local_osc = (5 << 5);
-	else		/*frequency up to 2150000*/
-		local_osc = (6 << 5);
-
-	data[3] = local_osc; /* all other bits set 0 */
-
-	if (b_w <= 10000)
-		lpf = 0xc;
-	else if (b_w <= 12000)
-		lpf = 0x2;
-	else if (b_w <= 14000)
-		lpf = 0xa;
-	else if (b_w <= 16000)
-		lpf = 0x6;
-	else if (b_w <= 18000)
-		lpf = 0xe;
-	else if (b_w <= 20000)
-		lpf = 0x1;
-	else if (b_w <= 22000)
-		lpf = 0x9;
-	else if (b_w <= 24000)
-		lpf = 0x5;
-	else if (b_w <= 26000)
-		lpf = 0xd;
-	else if (b_w <= 28000)
-		lpf = 0x3;
-		else
-		lpf = 0xb;
-
-	deb_info("Osc=%x b_w=%x lpf=%x\n", local_osc, b_w, lpf);
-	deb_info("Data 0=[%x%x%x%x]\n", data[0], data[1], data[2], data[3]);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	len = sizeof(data);
-	ret |= ix2505v_write(state, data, len);
-
-	data[2] |= 0x4; /* set TM = 1 other bits same */
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	len = 1;
-	ret |= ix2505v_write(state, &data[2], len); /* write byte 4 only */
-
-	msleep(10);
-
-	data[2] |= ((lpf >> 2) & 0x3) << 3; /* lpf */
-	data[3] |= (lpf & 0x3) << 2;
-
-	deb_info("Data 2=[%x%x]\n", data[2], data[3]);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	len = 2;
-	ret |= ix2505v_write(state, &data[2], len); /* write byte 4 & 5 */
-
-	if (state->config->min_delay_ms)
-		msleep(state->config->min_delay_ms);
-
-	state->frequency = frequency;
-
-	return ret;
-}
-
-static int ix2505v_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct ix2505v_state *state = fe->tuner_priv;
-
-	*frequency = state->frequency;
-
-	return 0;
-}
-
-static struct dvb_tuner_ops ix2505v_tuner_ops = {
-	.info = {
-		.name = "Sharp IX2505V (B0017)",
-		.frequency_min = 950000,
-		.frequency_max = 2175000
-	},
-	.release = ix2505v_release,
-	.set_params = ix2505v_set_params,
-	.get_frequency = ix2505v_get_frequency,
-};
-
-struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
-				    const struct ix2505v_config *config,
-				    struct i2c_adapter *i2c)
-{
-	struct ix2505v_state *state = NULL;
-	int ret;
-
-	if (NULL == config) {
-		deb_i2c("%s: no config ", __func__);
-		goto error;
-	}
-
-	state = kzalloc(sizeof(struct ix2505v_state), GFP_KERNEL);
-	if (NULL == state)
-		return NULL;
-
-	state->config = config;
-	state->i2c = i2c;
-
-	if (state->config->tuner_write_only) {
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-
-		ret = ix2505v_read_status_reg(state);
-
-		if (ret & 0x80) {
-			deb_i2c("%s: No IX2505V found\n", __func__);
-			goto error;
-		}
-
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	fe->tuner_priv = state;
-
-	memcpy(&fe->ops.tuner_ops, &ix2505v_tuner_ops,
-		sizeof(struct dvb_tuner_ops));
-	deb_i2c("%s: initialization (%s addr=0x%02x) ok\n",
-		__func__, fe->ops.tuner_ops.info.name, config->tuner_address);
-
-	return fe;
-
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(ix2505v_attach);
-
-module_param_named(debug, ix2505v_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-MODULE_DESCRIPTION("DVB IX2505V tuner driver");
-MODULE_AUTHOR("Malcolm Priestley");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/ix2505v.h b/drivers/media/dvb/frontends/ix2505v.h
deleted file mode 100644
index 67e89d6..0000000
--- a/drivers/media/dvb/frontends/ix2505v.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner
- *
- * Copyright (C) 2010 Malcolm Priestley
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef DVB_IX2505V_H
-#define DVB_IX2505V_H
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-/**
- * Attach a ix2505v tuner to the supplied frontend structure.
- *
- * @param fe Frontend to attach to.
- * @param config ix2505v_config structure
- * @return FE pointer on success, NULL on failure.
- */
-
-struct ix2505v_config {
-	u8 tuner_address;
-
-	/*Baseband AMP gain control 0/1=0dB(default) 2=-2bB 3=-4dB */
-	u8 tuner_gain;
-
-	/*Charge pump output +/- 0=120 1=260 2=555 3=1200(default) */
-	u8 tuner_chargepump;
-
-	/* delay after tune */
-	int min_delay_ms;
-
-	/* disables reads*/
-	u8 tuner_write_only;
-
-};
-
-#if defined(CONFIG_DVB_IX2505V) || \
-	(defined(CONFIG_DVB_IX2505V_MODULE) && defined(MODULE))
-extern struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
-	const struct ix2505v_config *config, struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
-	const struct ix2505v_config *config, struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* DVB_IX2505V_H */
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c
deleted file mode 100644
index 36fcf55..0000000
--- a/drivers/media/dvb/frontends/l64781.c
+++ /dev/null
@@ -1,609 +0,0 @@
-/*
-    driver for LSI L64781 COFDM demodulator
-
-    Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH
-		       Marko Kohtala <marko.kohtala@luukku.com>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include "dvb_frontend.h"
-#include "l64781.h"
-
-
-struct l64781_state {
-	struct i2c_adapter* i2c;
-	const struct l64781_config* config;
-	struct dvb_frontend frontend;
-
-	/* private demodulator data */
-	unsigned int first:1;
-};
-
-#define dprintk(args...) \
-	do { \
-		if (debug) printk(KERN_DEBUG "l64781: " args); \
-	} while (0)
-
-static int debug;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-
-static int l64781_writereg (struct l64781_state* state, u8 reg, u8 data)
-{
-	int ret;
-	u8 buf [] = { reg, data };
-	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
-
-	if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1)
-		dprintk ("%s: write_reg error (reg == %02x) = %02x!\n",
-			 __func__, reg, ret);
-
-	return (ret != 1) ? -1 : 0;
-}
-
-static int l64781_readreg (struct l64781_state* state, u8 reg)
-{
-	int ret;
-	u8 b0 [] = { reg };
-	u8 b1 [] = { 0 };
-	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
-			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2) return ret;
-
-	return b1[0];
-}
-
-static void apply_tps (struct l64781_state* state)
-{
-	l64781_writereg (state, 0x2a, 0x00);
-	l64781_writereg (state, 0x2a, 0x01);
-
-	/* This here is a little bit questionable because it enables
-	   the automatic update of TPS registers. I think we'd need to
-	   handle the IRQ from FE to update some other registers as
-	   well, or at least implement some magic to tuning to correct
-	   to the TPS received from transmission. */
-	l64781_writereg (state, 0x2a, 0x02);
-}
-
-
-static void reset_afc (struct l64781_state* state)
-{
-	/* Set AFC stall for the AFC_INIT_FRQ setting, TIM_STALL for
-	   timing offset */
-	l64781_writereg (state, 0x07, 0x9e); /* stall AFC */
-	l64781_writereg (state, 0x08, 0);    /* AFC INIT FREQ */
-	l64781_writereg (state, 0x09, 0);
-	l64781_writereg (state, 0x0a, 0);
-	l64781_writereg (state, 0x07, 0x8e);
-	l64781_writereg (state, 0x0e, 0);    /* AGC gain to zero in beginning */
-	l64781_writereg (state, 0x11, 0x80); /* stall TIM */
-	l64781_writereg (state, 0x10, 0);    /* TIM_OFFSET_LSB */
-	l64781_writereg (state, 0x12, 0);
-	l64781_writereg (state, 0x13, 0);
-	l64781_writereg (state, 0x11, 0x00);
-}
-
-static int reset_and_configure (struct l64781_state* state)
-{
-	u8 buf [] = { 0x06 };
-	struct i2c_msg msg = { .addr = 0x00, .flags = 0, .buf = buf, .len = 1 };
-	// NOTE: this is correct in writing to address 0x00
-
-	return (i2c_transfer(state->i2c, &msg, 1) == 1) ? 0 : -ENODEV;
-}
-
-static int apply_frontend_param(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct l64781_state* state = fe->demodulator_priv;
-	/* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */
-	static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 };
-	/* QPSK, QAM_16, QAM_64 */
-	static const u8 qam_tab [] = { 2, 4, 0, 6 };
-	static const u8 guard_tab [] = { 1, 2, 4, 8 };
-	/* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */
-	static const u32 ppm = 8000;
-	u32 ddfs_offset_fixed;
-/*	u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */
-/*			bw_tab[p->bandWidth]<<10)/15625; */
-	u32 init_freq;
-	u32 spi_bias;
-	u8 val0x04;
-	u8 val0x05;
-	u8 val0x06;
-	int bw;
-
-	switch (p->bandwidth_hz) {
-	case 8000000:
-		bw = 8;
-		break;
-	case 7000000:
-		bw = 7;
-		break;
-	case 6000000:
-		bw = 6;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	if (p->inversion != INVERSION_ON &&
-	    p->inversion != INVERSION_OFF)
-		return -EINVAL;
-
-	if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 &&
-	    p->code_rate_HP != FEC_3_4 && p->code_rate_HP != FEC_5_6 &&
-	    p->code_rate_HP != FEC_7_8)
-		return -EINVAL;
-
-	if (p->hierarchy != HIERARCHY_NONE &&
-	    (p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 &&
-	     p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 &&
-	     p->code_rate_LP != FEC_7_8))
-		return -EINVAL;
-
-	if (p->modulation != QPSK && p->modulation != QAM_16 &&
-	    p->modulation != QAM_64)
-		return -EINVAL;
-
-	if (p->transmission_mode != TRANSMISSION_MODE_2K &&
-	    p->transmission_mode != TRANSMISSION_MODE_8K)
-		return -EINVAL;
-
-	if (p->guard_interval < GUARD_INTERVAL_1_32 ||
-	    p->guard_interval > GUARD_INTERVAL_1_4)
-		return -EINVAL;
-
-	if (p->hierarchy < HIERARCHY_NONE ||
-	    p->hierarchy > HIERARCHY_4)
-		return -EINVAL;
-
-	ddfs_offset_fixed = 0x4000-(ppm<<16)/bw/1000000;
-
-	/* This works up to 20000 ppm, it overflows if too large ppm! */
-	init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) /
-			bw & 0xFFFFFF);
-
-	/* SPI bias calculation is slightly modified to fit in 32bit */
-	/* will work for high ppm only... */
-	spi_bias = 378 * (1 << 10);
-	spi_bias *= 16;
-	spi_bias *= bw;
-	spi_bias *= qam_tab[p->modulation];
-	spi_bias /= p->code_rate_HP + 1;
-	spi_bias /= (guard_tab[p->guard_interval] + 32);
-	spi_bias *= 1000;
-	spi_bias /= 1000 + ppm/1000;
-	spi_bias *= p->code_rate_HP;
-
-	val0x04 = (p->transmission_mode << 2) | p->guard_interval;
-	val0x05 = fec_tab[p->code_rate_HP];
-
-	if (p->hierarchy != HIERARCHY_NONE)
-		val0x05 |= (p->code_rate_LP - FEC_1_2) << 3;
-
-	val0x06 = (p->hierarchy << 2) | p->modulation;
-
-	l64781_writereg (state, 0x04, val0x04);
-	l64781_writereg (state, 0x05, val0x05);
-	l64781_writereg (state, 0x06, val0x06);
-
-	reset_afc (state);
-
-	/* Technical manual section 2.6.1, TIM_IIR_GAIN optimal values */
-	l64781_writereg (state, 0x15,
-			 p->transmission_mode == TRANSMISSION_MODE_2K ? 1 : 3);
-	l64781_writereg (state, 0x16, init_freq & 0xff);
-	l64781_writereg (state, 0x17, (init_freq >> 8) & 0xff);
-	l64781_writereg (state, 0x18, (init_freq >> 16) & 0xff);
-
-	l64781_writereg (state, 0x1b, spi_bias & 0xff);
-	l64781_writereg (state, 0x1c, (spi_bias >> 8) & 0xff);
-	l64781_writereg (state, 0x1d, ((spi_bias >> 16) & 0x7f) |
-		(p->inversion == INVERSION_ON ? 0x80 : 0x00));
-
-	l64781_writereg (state, 0x22, ddfs_offset_fixed & 0xff);
-	l64781_writereg (state, 0x23, (ddfs_offset_fixed >> 8) & 0x3f);
-
-	l64781_readreg (state, 0x00);  /*  clear interrupt registers... */
-	l64781_readreg (state, 0x01);  /*  dto. */
-
-	apply_tps (state);
-
-	return 0;
-}
-
-static int get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct l64781_state* state = fe->demodulator_priv;
-	int tmp;
-
-
-	tmp = l64781_readreg(state, 0x04);
-	switch(tmp & 3) {
-	case 0:
-		p->guard_interval = GUARD_INTERVAL_1_32;
-		break;
-	case 1:
-		p->guard_interval = GUARD_INTERVAL_1_16;
-		break;
-	case 2:
-		p->guard_interval = GUARD_INTERVAL_1_8;
-		break;
-	case 3:
-		p->guard_interval = GUARD_INTERVAL_1_4;
-		break;
-	}
-	switch((tmp >> 2) & 3) {
-	case 0:
-		p->transmission_mode = TRANSMISSION_MODE_2K;
-		break;
-	case 1:
-		p->transmission_mode = TRANSMISSION_MODE_8K;
-		break;
-	default:
-		printk(KERN_WARNING "Unexpected value for transmission_mode\n");
-	}
-
-	tmp = l64781_readreg(state, 0x05);
-	switch(tmp & 7) {
-	case 0:
-		p->code_rate_HP = FEC_1_2;
-		break;
-	case 1:
-		p->code_rate_HP = FEC_2_3;
-		break;
-	case 2:
-		p->code_rate_HP = FEC_3_4;
-		break;
-	case 3:
-		p->code_rate_HP = FEC_5_6;
-		break;
-	case 4:
-		p->code_rate_HP = FEC_7_8;
-		break;
-	default:
-		printk("Unexpected value for code_rate_HP\n");
-	}
-	switch((tmp >> 3) & 7) {
-	case 0:
-		p->code_rate_LP = FEC_1_2;
-		break;
-	case 1:
-		p->code_rate_LP = FEC_2_3;
-		break;
-	case 2:
-		p->code_rate_LP = FEC_3_4;
-		break;
-	case 3:
-		p->code_rate_LP = FEC_5_6;
-		break;
-	case 4:
-		p->code_rate_LP = FEC_7_8;
-		break;
-	default:
-		printk("Unexpected value for code_rate_LP\n");
-	}
-
-	tmp = l64781_readreg(state, 0x06);
-	switch(tmp & 3) {
-	case 0:
-		p->modulation = QPSK;
-		break;
-	case 1:
-		p->modulation = QAM_16;
-		break;
-	case 2:
-		p->modulation = QAM_64;
-		break;
-	default:
-		printk(KERN_WARNING "Unexpected value for modulation\n");
-	}
-	switch((tmp >> 2) & 7) {
-	case 0:
-		p->hierarchy = HIERARCHY_NONE;
-		break;
-	case 1:
-		p->hierarchy = HIERARCHY_1;
-		break;
-	case 2:
-		p->hierarchy = HIERARCHY_2;
-		break;
-	case 3:
-		p->hierarchy = HIERARCHY_4;
-		break;
-	default:
-		printk("Unexpected value for hierarchy\n");
-	}
-
-
-	tmp = l64781_readreg (state, 0x1d);
-	p->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF;
-
-	tmp = (int) (l64781_readreg (state, 0x08) |
-		     (l64781_readreg (state, 0x09) << 8) |
-		     (l64781_readreg (state, 0x0a) << 16));
-	p->frequency += tmp;
-
-	return 0;
-}
-
-static int l64781_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct l64781_state* state = fe->demodulator_priv;
-	int sync = l64781_readreg (state, 0x32);
-	int gain = l64781_readreg (state, 0x0e);
-
-	l64781_readreg (state, 0x00);  /*  clear interrupt registers... */
-	l64781_readreg (state, 0x01);  /*  dto. */
-
-	*status = 0;
-
-	if (gain > 5)
-		*status |= FE_HAS_SIGNAL;
-
-	if (sync & 0x02) /* VCXO locked, this criteria should be ok */
-		*status |= FE_HAS_CARRIER;
-
-	if (sync & 0x20)
-		*status |= FE_HAS_VITERBI;
-
-	if (sync & 0x40)
-		*status |= FE_HAS_SYNC;
-
-	if (sync == 0x7f)
-		*status |= FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int l64781_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	struct l64781_state* state = fe->demodulator_priv;
-
-	/*   XXX FIXME: set up counting period (reg 0x26...0x28)
-	 */
-	*ber = l64781_readreg (state, 0x39)
-	    | (l64781_readreg (state, 0x3a) << 8);
-
-	return 0;
-}
-
-static int l64781_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
-{
-	struct l64781_state* state = fe->demodulator_priv;
-
-	u8 gain = l64781_readreg (state, 0x0e);
-	*signal_strength = (gain << 8) | gain;
-
-	return 0;
-}
-
-static int l64781_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct l64781_state* state = fe->demodulator_priv;
-
-	u8 avg_quality = 0xff - l64781_readreg (state, 0x33);
-	*snr = (avg_quality << 8) | avg_quality; /* not exact, but...*/
-
-	return 0;
-}
-
-static int l64781_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	struct l64781_state* state = fe->demodulator_priv;
-
-	*ucblocks = l64781_readreg (state, 0x37)
-	   | (l64781_readreg (state, 0x38) << 8);
-
-	return 0;
-}
-
-static int l64781_sleep(struct dvb_frontend* fe)
-{
-	struct l64781_state* state = fe->demodulator_priv;
-
-	/* Power down */
-	return l64781_writereg (state, 0x3e, 0x5a);
-}
-
-static int l64781_init(struct dvb_frontend* fe)
-{
-	struct l64781_state* state = fe->demodulator_priv;
-
-	reset_and_configure (state);
-
-	/* Power up */
-	l64781_writereg (state, 0x3e, 0xa5);
-
-	/* Reset hard */
-	l64781_writereg (state, 0x2a, 0x04);
-	l64781_writereg (state, 0x2a, 0x00);
-
-	/* Set tuner specific things */
-	/* AFC_POL, set also in reset_afc */
-	l64781_writereg (state, 0x07, 0x8e);
-
-	/* Use internal ADC */
-	l64781_writereg (state, 0x0b, 0x81);
-
-	/* AGC loop gain, and polarity is positive */
-	l64781_writereg (state, 0x0c, 0x84);
-
-	/* Internal ADC outputs two's complement */
-	l64781_writereg (state, 0x0d, 0x8c);
-
-	/* With ppm=8000, it seems the DTR_SENSITIVITY will result in
-	   value of 2 with all possible bandwidths and guard
-	   intervals, which is the initial value anyway. */
-	/*l64781_writereg (state, 0x19, 0x92);*/
-
-	/* Everything is two's complement, soft bit and CSI_OUT too */
-	l64781_writereg (state, 0x1e, 0x09);
-
-	/* delay a bit after first init attempt */
-	if (state->first) {
-		state->first = 0;
-		msleep(200);
-	}
-
-	return 0;
-}
-
-static int l64781_get_tune_settings(struct dvb_frontend* fe,
-				    struct dvb_frontend_tune_settings* fesettings)
-{
-	fesettings->min_delay_ms = 4000;
-	fesettings->step_size = 0;
-	fesettings->max_drift = 0;
-	return 0;
-}
-
-static void l64781_release(struct dvb_frontend* fe)
-{
-	struct l64781_state* state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops l64781_ops;
-
-struct dvb_frontend* l64781_attach(const struct l64781_config* config,
-				   struct i2c_adapter* i2c)
-{
-	struct l64781_state* state = NULL;
-	int reg0x3e = -1;
-	u8 b0 [] = { 0x1a };
-	u8 b1 [] = { 0x00 };
-	struct i2c_msg msg [] = { { .addr = config->demod_address, .flags = 0, .buf = b0, .len = 1 },
-			   { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct l64781_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->first = 1;
-
-	/**
-	 *  the L64781 won't show up before we send the reset_and_configure()
-	 *  broadcast. If nothing responds there is no L64781 on the bus...
-	 */
-	if (reset_and_configure(state) < 0) {
-		dprintk("No response to reset and configure broadcast...\n");
-		goto error;
-	}
-
-	/* The chip always responds to reads */
-	if (i2c_transfer(state->i2c, msg, 2) != 2) {
-		dprintk("No response to read on I2C bus\n");
-		goto error;
-	}
-
-	/* Save current register contents for bailout */
-	reg0x3e = l64781_readreg(state, 0x3e);
-
-	/* Reading the POWER_DOWN register always returns 0 */
-	if (reg0x3e != 0) {
-		dprintk("Device doesn't look like L64781\n");
-		goto error;
-	}
-
-	/* Turn the chip off */
-	l64781_writereg (state, 0x3e, 0x5a);
-
-	/* Responds to all reads with 0 */
-	if (l64781_readreg(state, 0x1a) != 0) {
-		dprintk("Read 1 returned unexpcted value\n");
-		goto error;
-	}
-
-	/* Turn the chip on */
-	l64781_writereg (state, 0x3e, 0xa5);
-
-	/* Responds with register default value */
-	if (l64781_readreg(state, 0x1a) != 0xa1) {
-		dprintk("Read 2 returned unexpcted value\n");
-		goto error;
-	}
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	if (reg0x3e >= 0)
-		l64781_writereg (state, 0x3e, reg0x3e);  /* restore reg 0x3e */
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops l64781_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name = "LSI L64781 DVB-T",
-	/*	.frequency_min = ???,*/
-	/*	.frequency_max = ???,*/
-		.frequency_stepsize = 166666,
-	/*      .frequency_tolerance = ???,*/
-	/*      .symbol_rate_tolerance = ???,*/
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
-		      FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
-		      FE_CAN_MUTE_TS
-	},
-
-	.release = l64781_release,
-
-	.init = l64781_init,
-	.sleep = l64781_sleep,
-
-	.set_frontend = apply_frontend_param,
-	.get_frontend = get_frontend,
-	.get_tune_settings = l64781_get_tune_settings,
-
-	.read_status = l64781_read_status,
-	.read_ber = l64781_read_ber,
-	.read_signal_strength = l64781_read_signal_strength,
-	.read_snr = l64781_read_snr,
-	.read_ucblocks = l64781_read_ucblocks,
-};
-
-MODULE_DESCRIPTION("LSI L64781 DVB-T Demodulator driver");
-MODULE_AUTHOR("Holger Waechtler, Marko Kohtala");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(l64781_attach);
diff --git a/drivers/media/dvb/frontends/l64781.h b/drivers/media/dvb/frontends/l64781.h
deleted file mode 100644
index 1305a9e..0000000
--- a/drivers/media/dvb/frontends/l64781.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-    driver for LSI L64781 COFDM demodulator
-
-    Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH
-		       Marko Kohtala <marko.kohtala@luukku.com>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef L64781_H
-#define L64781_H
-
-#include <linux/dvb/frontend.h>
-
-struct l64781_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-};
-
-#if defined(CONFIG_DVB_L64781) || (defined(CONFIG_DVB_L64781_MODULE) && defined(MODULE))
-extern struct dvb_frontend* l64781_attach(const struct l64781_config* config,
-					  struct i2c_adapter* i2c);
-#else
-static inline struct dvb_frontend* l64781_attach(const struct l64781_config* config,
-					  struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_L64781
-
-#endif // L64781_H
diff --git a/drivers/media/dvb/frontends/lg2160.c b/drivers/media/dvb/frontends/lg2160.c
deleted file mode 100644
index cc11260..0000000
--- a/drivers/media/dvb/frontends/lg2160.c
+++ /dev/null
@@ -1,1468 +0,0 @@
-/*
- *    Support for LG2160 - ATSC/MH
- *
- *    Copyright (C) 2010 Michael Krufky <mkrufky@linuxtv.org>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/jiffies.h>
-#include <linux/dvb/frontend.h>
-#include "lg2160.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))");
-
-#define DBG_INFO 1
-#define DBG_REG  2
-
-#define lg_printk(kern, fmt, arg...)					\
-	printk(kern "%s: " fmt, __func__, ##arg)
-
-#define lg_info(fmt, arg...)	printk(KERN_INFO "lg2160: " fmt, ##arg)
-#define lg_warn(fmt, arg...)	lg_printk(KERN_WARNING,       fmt, ##arg)
-#define lg_err(fmt, arg...)	lg_printk(KERN_ERR,           fmt, ##arg)
-#define lg_dbg(fmt, arg...) if (debug & DBG_INFO)			\
-				lg_printk(KERN_DEBUG,         fmt, ##arg)
-#define lg_reg(fmt, arg...) if (debug & DBG_REG)			\
-				lg_printk(KERN_DEBUG,         fmt, ##arg)
-
-#define lg_fail(ret)							\
-({									\
-	int __ret;							\
-	__ret = (ret < 0);						\
-	if (__ret)							\
-		lg_err("error %d on line %d\n",	ret, __LINE__);		\
-	__ret;								\
-})
-
-struct lg216x_state {
-	struct i2c_adapter *i2c_adap;
-	const struct lg2160_config *cfg;
-
-	struct dvb_frontend frontend;
-
-	u32 current_frequency;
-	u8 parade_id;
-	u8 fic_ver;
-	unsigned int last_reset;
-};
-
-/* ------------------------------------------------------------------------ */
-
-static int lg216x_write_reg(struct lg216x_state *state, u16 reg, u8 val)
-{
-	int ret;
-	u8 buf[] = { reg >> 8, reg & 0xff, val };
-	struct i2c_msg msg = {
-		.addr = state->cfg->i2c_addr, .flags = 0,
-		.buf = buf, .len = 3,
-	};
-
-	lg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val);
-
-	ret = i2c_transfer(state->i2c_adap, &msg, 1);
-
-	if (ret != 1) {
-		lg_err("error (addr %02x %02x <- %02x, err = %i)\n",
-		       msg.buf[0], msg.buf[1], msg.buf[2], ret);
-		if (ret < 0)
-			return ret;
-		else
-			return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int lg216x_read_reg(struct lg216x_state *state, u16 reg, u8 *val)
-{
-	int ret;
-	u8 reg_buf[] = { reg >> 8, reg & 0xff };
-	struct i2c_msg msg[] = {
-		{ .addr = state->cfg->i2c_addr,
-		  .flags = 0, .buf = reg_buf, .len = 2 },
-		{ .addr = state->cfg->i2c_addr,
-		  .flags = I2C_M_RD, .buf = val, .len = 1 },
-	};
-
-	lg_reg("reg: 0x%04x\n", reg);
-
-	ret = i2c_transfer(state->i2c_adap, msg, 2);
-
-	if (ret != 2) {
-		lg_err("error (addr %02x reg %04x error (ret == %i)\n",
-		       state->cfg->i2c_addr, reg, ret);
-		if (ret < 0)
-			return ret;
-		else
-			return -EREMOTEIO;
-	}
-	return 0;
-}
-
-struct lg216x_reg {
-	u16 reg;
-	u8 val;
-};
-
-static int lg216x_write_regs(struct lg216x_state *state,
-			     struct lg216x_reg *regs, int len)
-{
-	int i, ret;
-
-	lg_reg("writing %d registers...\n", len);
-
-	for (i = 0; i < len; i++) {
-		ret = lg216x_write_reg(state, regs[i].reg, regs[i].val);
-		if (lg_fail(ret))
-			return ret;
-	}
-	return 0;
-}
-
-static int lg216x_set_reg_bit(struct lg216x_state *state,
-			      u16 reg, int bit, int onoff)
-{
-	u8 val;
-	int ret;
-
-	lg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff);
-
-	ret = lg216x_read_reg(state, reg, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	val &= ~(1 << bit);
-	val |= (onoff & 1) << bit;
-
-	ret = lg216x_write_reg(state, reg, val);
-	lg_fail(ret);
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int lg216x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct lg216x_state *state = fe->demodulator_priv;
-	int ret;
-
-	if (state->cfg->deny_i2c_rptr)
-		return 0;
-
-	lg_dbg("(%d)\n", enable);
-
-	ret = lg216x_set_reg_bit(state, 0x0000, 0, enable ? 0 : 1);
-
-	msleep(1);
-
-	return ret;
-}
-
-static int lg216x_soft_reset(struct lg216x_state *state)
-{
-	int ret;
-
-	lg_dbg("\n");
-
-	ret = lg216x_write_reg(state, 0x0002, 0x00);
-	if (lg_fail(ret))
-		goto fail;
-
-	msleep(20);
-	ret = lg216x_write_reg(state, 0x0002, 0x01);
-	if (lg_fail(ret))
-		goto fail;
-
-	state->last_reset = jiffies_to_msecs(jiffies);
-fail:
-	return ret;
-}
-
-static int lg216x_initialize(struct lg216x_state *state)
-{
-	int ret;
-
-	static struct lg216x_reg lg2160_init[] = {
-#if 0
-		{ .reg = 0x0015, .val = 0xe6 },
-#else
-		{ .reg = 0x0015, .val = 0xf7 },
-		{ .reg = 0x001b, .val = 0x52 },
-		{ .reg = 0x0208, .val = 0x00 },
-		{ .reg = 0x0209, .val = 0x82 },
-		{ .reg = 0x0210, .val = 0xf9 },
-		{ .reg = 0x020a, .val = 0x00 },
-		{ .reg = 0x020b, .val = 0x82 },
-		{ .reg = 0x020d, .val = 0x28 },
-		{ .reg = 0x020f, .val = 0x14 },
-#endif
-	};
-
-	static struct lg216x_reg lg2161_init[] = {
-		{ .reg = 0x0000, .val = 0x41 },
-		{ .reg = 0x0001, .val = 0xfb },
-		{ .reg = 0x0216, .val = 0x00 },
-		{ .reg = 0x0219, .val = 0x00 },
-		{ .reg = 0x021b, .val = 0x55 },
-		{ .reg = 0x0606, .val = 0x0a },
-	};
-
-	switch (state->cfg->lg_chip) {
-	case LG2160:
-		ret = lg216x_write_regs(state,
-					lg2160_init, ARRAY_SIZE(lg2160_init));
-		break;
-	case LG2161:
-		ret = lg216x_write_regs(state,
-					lg2161_init, ARRAY_SIZE(lg2161_init));
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lg216x_soft_reset(state);
-	lg_fail(ret);
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int lg216x_set_if(struct lg216x_state *state)
-{
-	u8 val;
-	int ret;
-
-	lg_dbg("%d KHz\n", state->cfg->if_khz);
-
-	ret = lg216x_read_reg(state, 0x0132, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	val &= 0xfb;
-	val |= (0 == state->cfg->if_khz) ? 0x04 : 0x00;
-
-	ret = lg216x_write_reg(state, 0x0132, val);
-	lg_fail(ret);
-
-	/* if NOT zero IF, 6 MHz is the default */
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int lg2160_agc_fix(struct lg216x_state *state,
-			  int if_agc_fix, int rf_agc_fix)
-{
-	u8 val;
-	int ret;
-
-	ret = lg216x_read_reg(state, 0x0100, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	val &= 0xf3;
-	val |= (if_agc_fix) ? 0x08 : 0x00;
-	val |= (rf_agc_fix) ? 0x04 : 0x00;
-
-	ret = lg216x_write_reg(state, 0x0100, val);
-	lg_fail(ret);
-fail:
-	return ret;
-}
-
-#if 0
-static int lg2160_agc_freeze(struct lg216x_state *state,
-			     int if_agc_freeze, int rf_agc_freeze)
-{
-	u8 val;
-	int ret;
-
-	ret = lg216x_read_reg(state, 0x0100, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	val &= 0xcf;
-	val |= (if_agc_freeze) ? 0x20 : 0x00;
-	val |= (rf_agc_freeze) ? 0x10 : 0x00;
-
-	ret = lg216x_write_reg(state, 0x0100, val);
-	lg_fail(ret);
-fail:
-	return ret;
-}
-#endif
-
-static int lg2160_agc_polarity(struct lg216x_state *state,
-			       int if_agc_polarity, int rf_agc_polarity)
-{
-	u8 val;
-	int ret;
-
-	ret = lg216x_read_reg(state, 0x0100, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	val &= 0xfc;
-	val |= (if_agc_polarity) ? 0x02 : 0x00;
-	val |= (rf_agc_polarity) ? 0x01 : 0x00;
-
-	ret = lg216x_write_reg(state, 0x0100, val);
-	lg_fail(ret);
-fail:
-	return ret;
-}
-
-static int lg2160_tuner_pwr_save_polarity(struct lg216x_state *state,
-					  int polarity)
-{
-	u8 val;
-	int ret;
-
-	ret = lg216x_read_reg(state, 0x0008, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	val &= 0xfe;
-	val |= (polarity) ? 0x01 : 0x00;
-
-	ret = lg216x_write_reg(state, 0x0008, val);
-	lg_fail(ret);
-fail:
-	return ret;
-}
-
-static int lg2160_spectrum_polarity(struct lg216x_state *state,
-				    int inverted)
-{
-	u8 val;
-	int ret;
-
-	ret = lg216x_read_reg(state, 0x0132, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	val &= 0xfd;
-	val |= (inverted) ? 0x02 : 0x00;
-
-	ret = lg216x_write_reg(state, 0x0132, val);
-	lg_fail(ret);
-fail:
-	return lg216x_soft_reset(state);
-}
-
-static int lg2160_tuner_pwr_save(struct lg216x_state *state, int onoff)
-{
-	u8 val;
-	int ret;
-
-	ret = lg216x_read_reg(state, 0x0007, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	val &= 0xbf;
-	val |= (onoff) ? 0x40 : 0x00;
-
-	ret = lg216x_write_reg(state, 0x0007, val);
-	lg_fail(ret);
-fail:
-	return ret;
-}
-
-static int lg216x_set_parade(struct lg216x_state *state, int id)
-{
-	int ret;
-
-	ret = lg216x_write_reg(state, 0x013e, id & 0x7f);
-	if (lg_fail(ret))
-		goto fail;
-
-	state->parade_id = id & 0x7f;
-fail:
-	return ret;
-}
-
-static int lg216x_set_ensemble(struct lg216x_state *state, int id)
-{
-	int ret;
-	u16 reg;
-	u8 val;
-
-	switch (state->cfg->lg_chip) {
-	case LG2160:
-		reg = 0x0400;
-		break;
-	case LG2161:
-	default:
-		reg = 0x0500;
-		break;
-	}
-
-	ret = lg216x_read_reg(state, reg, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	val &= 0xfe;
-	val |= (id) ? 0x01 : 0x00;
-
-	ret = lg216x_write_reg(state, reg, val);
-	lg_fail(ret);
-fail:
-	return ret;
-}
-
-static int lg2160_set_spi_clock(struct lg216x_state *state)
-{
-	u8 val;
-	int ret;
-
-	ret = lg216x_read_reg(state, 0x0014, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	val &= 0xf3;
-	val |= (state->cfg->spi_clock << 2);
-
-	ret = lg216x_write_reg(state, 0x0014, val);
-	lg_fail(ret);
-fail:
-	return ret;
-}
-
-static int lg2161_set_output_interface(struct lg216x_state *state)
-{
-	u8 val;
-	int ret;
-
-	ret = lg216x_read_reg(state, 0x0014, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	val &= ~0x07;
-	val |= state->cfg->output_if; /* FIXME: needs sanity check */
-
-	ret = lg216x_write_reg(state, 0x0014, val);
-	lg_fail(ret);
-fail:
-	return ret;
-}
-
-static int lg216x_enable_fic(struct lg216x_state *state, int onoff)
-{
-	int ret;
-
-	ret = lg216x_write_reg(state, 0x0017, 0x23);
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lg216x_write_reg(state, 0x0016, 0xfc);
-	if (lg_fail(ret))
-		goto fail;
-
-	switch (state->cfg->lg_chip) {
-	case LG2160:
-		ret = lg216x_write_reg(state, 0x0016,
-				       0xfc | ((onoff) ? 0x02 : 0x00));
-		break;
-	case LG2161:
-		ret = lg216x_write_reg(state, 0x0016, (onoff) ? 0x10 : 0x00);
-		break;
-	}
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lg216x_initialize(state);
-	if (lg_fail(ret))
-		goto fail;
-
-	if (onoff) {
-		ret = lg216x_write_reg(state, 0x0017, 0x03);
-		lg_fail(ret);
-	}
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int lg216x_get_fic_version(struct lg216x_state *state, u8 *ficver)
-{
-	u8 val;
-	int ret;
-
-	*ficver = 0xff; /* invalid value */
-
-	ret = lg216x_read_reg(state, 0x0128, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	*ficver = (val >> 3) & 0x1f;
-fail:
-	return ret;
-}
-
-#if 0
-static int lg2160_get_parade_id(struct lg216x_state *state, u8 *id)
-{
-	u8 val;
-	int ret;
-
-	*id = 0xff; /* invalid value */
-
-	ret = lg216x_read_reg(state, 0x0123, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	*id = val & 0x7f;
-fail:
-	return ret;
-}
-#endif
-
-static int lg216x_get_nog(struct lg216x_state *state, u8 *nog)
-{
-	u8 val;
-	int ret;
-
-	*nog = 0xff; /* invalid value */
-
-	ret = lg216x_read_reg(state, 0x0124, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	*nog = ((val >> 4) & 0x07) + 1;
-fail:
-	return ret;
-}
-
-static int lg216x_get_tnog(struct lg216x_state *state, u8 *tnog)
-{
-	u8 val;
-	int ret;
-
-	*tnog = 0xff; /* invalid value */
-
-	ret = lg216x_read_reg(state, 0x0125, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	*tnog = val & 0x1f;
-fail:
-	return ret;
-}
-
-static int lg216x_get_sgn(struct lg216x_state *state, u8 *sgn)
-{
-	u8 val;
-	int ret;
-
-	*sgn = 0xff; /* invalid value */
-
-	ret = lg216x_read_reg(state, 0x0124, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	*sgn = val & 0x0f;
-fail:
-	return ret;
-}
-
-static int lg216x_get_prc(struct lg216x_state *state, u8 *prc)
-{
-	u8 val;
-	int ret;
-
-	*prc = 0xff; /* invalid value */
-
-	ret = lg216x_read_reg(state, 0x0125, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	*prc = ((val >> 5) & 0x07) + 1;
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int lg216x_get_rs_frame_mode(struct lg216x_state *state,
-				    enum atscmh_rs_frame_mode *rs_framemode)
-{
-	u8 val;
-	int ret;
-
-	switch (state->cfg->lg_chip) {
-	case LG2160:
-		ret = lg216x_read_reg(state, 0x0410, &val);
-		break;
-	case LG2161:
-		ret = lg216x_read_reg(state, 0x0513, &val);
-		break;
-	default:
-		ret = -EINVAL;
-	}
-	if (lg_fail(ret))
-		goto fail;
-
-	switch ((val >> 4) & 0x03) {
-#if 1
-	default:
-#endif
-	case 0x00:
-		*rs_framemode = ATSCMH_RSFRAME_PRI_ONLY;
-		break;
-	case 0x01:
-		*rs_framemode = ATSCMH_RSFRAME_PRI_SEC;
-		break;
-#if 0
-	default:
-		*rs_framemode = ATSCMH_RSFRAME_RES;
-		break;
-#endif
-	}
-fail:
-	return ret;
-}
-
-static
-int lg216x_get_rs_frame_ensemble(struct lg216x_state *state,
-				 enum atscmh_rs_frame_ensemble *rs_frame_ens)
-{
-	u8 val;
-	int ret;
-
-	switch (state->cfg->lg_chip) {
-	case LG2160:
-		ret = lg216x_read_reg(state, 0x0400, &val);
-		break;
-	case LG2161:
-		ret = lg216x_read_reg(state, 0x0500, &val);
-		break;
-	default:
-		ret = -EINVAL;
-	}
-	if (lg_fail(ret))
-		goto fail;
-
-	val &= 0x01;
-	*rs_frame_ens = (enum atscmh_rs_frame_ensemble) val;
-fail:
-	return ret;
-}
-
-static int lg216x_get_rs_code_mode(struct lg216x_state *state,
-				   enum atscmh_rs_code_mode *rs_code_pri,
-				   enum atscmh_rs_code_mode *rs_code_sec)
-{
-	u8 val;
-	int ret;
-
-	switch (state->cfg->lg_chip) {
-	case LG2160:
-		ret = lg216x_read_reg(state, 0x0410, &val);
-		break;
-	case LG2161:
-		ret = lg216x_read_reg(state, 0x0513, &val);
-		break;
-	default:
-		ret = -EINVAL;
-	}
-	if (lg_fail(ret))
-		goto fail;
-
-	*rs_code_pri = (enum atscmh_rs_code_mode) ((val >> 2) & 0x03);
-	*rs_code_sec = (enum atscmh_rs_code_mode) (val & 0x03);
-fail:
-	return ret;
-}
-
-static int lg216x_get_sccc_block_mode(struct lg216x_state *state,
-				      enum atscmh_sccc_block_mode *sccc_block)
-{
-	u8 val;
-	int ret;
-
-	switch (state->cfg->lg_chip) {
-	case LG2160:
-		ret = lg216x_read_reg(state, 0x0315, &val);
-		break;
-	case LG2161:
-		ret = lg216x_read_reg(state, 0x0511, &val);
-		break;
-	default:
-		ret = -EINVAL;
-	}
-	if (lg_fail(ret))
-		goto fail;
-
-	switch (val & 0x03) {
-	case 0x00:
-		*sccc_block = ATSCMH_SCCC_BLK_SEP;
-		break;
-	case 0x01:
-		*sccc_block = ATSCMH_SCCC_BLK_COMB;
-		break;
-	default:
-		*sccc_block = ATSCMH_SCCC_BLK_RES;
-		break;
-	}
-fail:
-	return ret;
-}
-
-static int lg216x_get_sccc_code_mode(struct lg216x_state *state,
-				     enum atscmh_sccc_code_mode *mode_a,
-				     enum atscmh_sccc_code_mode *mode_b,
-				     enum atscmh_sccc_code_mode *mode_c,
-				     enum atscmh_sccc_code_mode *mode_d)
-{
-	u8 val;
-	int ret;
-
-	switch (state->cfg->lg_chip) {
-	case LG2160:
-		ret = lg216x_read_reg(state, 0x0316, &val);
-		break;
-	case LG2161:
-		ret = lg216x_read_reg(state, 0x0512, &val);
-		break;
-	default:
-		ret = -EINVAL;
-	}
-	if (lg_fail(ret))
-		goto fail;
-
-	switch ((val >> 6) & 0x03) {
-	case 0x00:
-		*mode_a = ATSCMH_SCCC_CODE_HLF;
-		break;
-	case 0x01:
-		*mode_a = ATSCMH_SCCC_CODE_QTR;
-		break;
-	default:
-		*mode_a = ATSCMH_SCCC_CODE_RES;
-		break;
-	}
-
-	switch ((val >> 4) & 0x03) {
-	case 0x00:
-		*mode_b = ATSCMH_SCCC_CODE_HLF;
-		break;
-	case 0x01:
-		*mode_b = ATSCMH_SCCC_CODE_QTR;
-		break;
-	default:
-		*mode_b = ATSCMH_SCCC_CODE_RES;
-		break;
-	}
-
-	switch ((val >> 2) & 0x03) {
-	case 0x00:
-		*mode_c = ATSCMH_SCCC_CODE_HLF;
-		break;
-	case 0x01:
-		*mode_c = ATSCMH_SCCC_CODE_QTR;
-		break;
-	default:
-		*mode_c = ATSCMH_SCCC_CODE_RES;
-		break;
-	}
-
-	switch (val & 0x03) {
-	case 0x00:
-		*mode_d = ATSCMH_SCCC_CODE_HLF;
-		break;
-	case 0x01:
-		*mode_d = ATSCMH_SCCC_CODE_QTR;
-		break;
-	default:
-		*mode_d = ATSCMH_SCCC_CODE_RES;
-		break;
-	}
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-#if 0
-static int lg216x_read_fic_err_count(struct lg216x_state *state, u8 *err)
-{
-	u8 fic_err;
-	int ret;
-
-	*err = 0;
-
-	switch (state->cfg->lg_chip) {
-	case LG2160:
-		ret = lg216x_read_reg(state, 0x0012, &fic_err);
-		break;
-	case LG2161:
-		ret = lg216x_read_reg(state, 0x001e, &fic_err);
-		break;
-	}
-	if (lg_fail(ret))
-		goto fail;
-
-	*err = fic_err;
-fail:
-	return ret;
-}
-
-static int lg2160_read_crc_err_count(struct lg216x_state *state, u16 *err)
-{
-	u8 crc_err1, crc_err2;
-	int ret;
-
-	*err = 0;
-
-	ret = lg216x_read_reg(state, 0x0411, &crc_err1);
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lg216x_read_reg(state, 0x0412, &crc_err2);
-	if (lg_fail(ret))
-		goto fail;
-
-	*err = (u16)(((crc_err2 & 0x0f) << 8) | crc_err1);
-fail:
-	return ret;
-}
-
-static int lg2161_read_crc_err_count(struct lg216x_state *state, u16 *err)
-{
-	u8 crc_err;
-	int ret;
-
-	*err = 0;
-
-	ret = lg216x_read_reg(state, 0x0612, &crc_err);
-	if (lg_fail(ret))
-		goto fail;
-
-	*err = (u16)crc_err;
-fail:
-	return ret;
-}
-
-static int lg216x_read_crc_err_count(struct lg216x_state *state, u16 *err)
-{
-	int ret;
-	switch (state->cfg->lg_chip) {
-	case LG2160:
-		ret = lg2160_read_crc_err_count(state, err);
-		break;
-	case LG2161:
-		ret = lg2161_read_crc_err_count(state, err);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
-
-static int lg2160_read_rs_err_count(struct lg216x_state *state, u16 *err)
-{
-	u8 rs_err1, rs_err2;
-	int ret;
-
-	*err = 0;
-
-	ret = lg216x_read_reg(state, 0x0413, &rs_err1);
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lg216x_read_reg(state, 0x0414, &rs_err2);
-	if (lg_fail(ret))
-		goto fail;
-
-	*err = (u16)(((rs_err2 & 0x0f) << 8) | rs_err1);
-fail:
-	return ret;
-}
-
-static int lg2161_read_rs_err_count(struct lg216x_state *state, u16 *err)
-{
-	u8 rs_err1, rs_err2;
-	int ret;
-
-	*err = 0;
-
-	ret = lg216x_read_reg(state, 0x0613, &rs_err1);
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lg216x_read_reg(state, 0x0614, &rs_err2);
-	if (lg_fail(ret))
-		goto fail;
-
-	*err = (u16)((rs_err1 << 8) | rs_err2);
-fail:
-	return ret;
-}
-
-static int lg216x_read_rs_err_count(struct lg216x_state *state, u16 *err)
-{
-	int ret;
-	switch (state->cfg->lg_chip) {
-	case LG2160:
-		ret = lg2160_read_rs_err_count(state, err);
-		break;
-	case LG2161:
-		ret = lg2161_read_rs_err_count(state, err);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
-#endif
-
-/* ------------------------------------------------------------------------ */
-
-static int lg216x_get_frontend(struct dvb_frontend *fe)
-{
-	struct lg216x_state *state = fe->demodulator_priv;
-	int ret;
-
-	lg_dbg("\n");
-
-	fe->dtv_property_cache.modulation = VSB_8;
-	fe->dtv_property_cache.frequency = state->current_frequency;
-	fe->dtv_property_cache.delivery_system = SYS_ATSCMH;
-
-	ret = lg216x_get_fic_version(state,
-				     &fe->dtv_property_cache.atscmh_fic_ver);
-	if (lg_fail(ret))
-		goto fail;
-	if (state->fic_ver != fe->dtv_property_cache.atscmh_fic_ver) {
-		state->fic_ver = fe->dtv_property_cache.atscmh_fic_ver;
-
-#if 0
-		ret = lg2160_get_parade_id(state,
-				&fe->dtv_property_cache.atscmh_parade_id);
-		if (lg_fail(ret))
-			goto fail;
-/* #else */
-		fe->dtv_property_cache.atscmh_parade_id = state->parade_id;
-#endif
-		ret = lg216x_get_nog(state,
-				     &fe->dtv_property_cache.atscmh_nog);
-		if (lg_fail(ret))
-			goto fail;
-		ret = lg216x_get_tnog(state,
-				      &fe->dtv_property_cache.atscmh_tnog);
-		if (lg_fail(ret))
-			goto fail;
-		ret = lg216x_get_sgn(state,
-				     &fe->dtv_property_cache.atscmh_sgn);
-		if (lg_fail(ret))
-			goto fail;
-		ret = lg216x_get_prc(state,
-				     &fe->dtv_property_cache.atscmh_prc);
-		if (lg_fail(ret))
-			goto fail;
-
-		ret = lg216x_get_rs_frame_mode(state,
-			(enum atscmh_rs_frame_mode *)
-			&fe->dtv_property_cache.atscmh_rs_frame_mode);
-		if (lg_fail(ret))
-			goto fail;
-		ret = lg216x_get_rs_frame_ensemble(state,
-			(enum atscmh_rs_frame_ensemble *)
-			&fe->dtv_property_cache.atscmh_rs_frame_ensemble);
-		if (lg_fail(ret))
-			goto fail;
-		ret = lg216x_get_rs_code_mode(state,
-			(enum atscmh_rs_code_mode *)
-			&fe->dtv_property_cache.atscmh_rs_code_mode_pri,
-			(enum atscmh_rs_code_mode *)
-			&fe->dtv_property_cache.atscmh_rs_code_mode_sec);
-		if (lg_fail(ret))
-			goto fail;
-		ret = lg216x_get_sccc_block_mode(state,
-			(enum atscmh_sccc_block_mode *)
-			&fe->dtv_property_cache.atscmh_sccc_block_mode);
-		if (lg_fail(ret))
-			goto fail;
-		ret = lg216x_get_sccc_code_mode(state,
-			(enum atscmh_sccc_code_mode *)
-			&fe->dtv_property_cache.atscmh_sccc_code_mode_a,
-			(enum atscmh_sccc_code_mode *)
-			&fe->dtv_property_cache.atscmh_sccc_code_mode_b,
-			(enum atscmh_sccc_code_mode *)
-			&fe->dtv_property_cache.atscmh_sccc_code_mode_c,
-			(enum atscmh_sccc_code_mode *)
-			&fe->dtv_property_cache.atscmh_sccc_code_mode_d);
-		if (lg_fail(ret))
-			goto fail;
-	}
-#if 0
-	ret = lg216x_read_fic_err_count(state,
-				(u8 *)&fe->dtv_property_cache.atscmh_fic_err);
-	if (lg_fail(ret))
-		goto fail;
-	ret = lg216x_read_crc_err_count(state,
-				&fe->dtv_property_cache.atscmh_crc_err);
-	if (lg_fail(ret))
-		goto fail;
-	ret = lg216x_read_rs_err_count(state,
-				&fe->dtv_property_cache.atscmh_rs_err);
-	if (lg_fail(ret))
-		goto fail;
-
-	switch (state->cfg->lg_chip) {
-	case LG2160:
-		if (((fe->dtv_property_cache.atscmh_rs_err >= 240) &&
-		     (fe->dtv_property_cache.atscmh_crc_err >= 240)) &&
-		    ((jiffies_to_msecs(jiffies) - state->last_reset) > 6000))
-			ret = lg216x_soft_reset(state);
-		break;
-	case LG2161:
-		/* no fix needed here (as far as we know) */
-		ret = 0;
-		break;
-	}
-	lg_fail(ret);
-#endif
-fail:
-	return ret;
-}
-
-static int lg216x_get_property(struct dvb_frontend *fe,
-			       struct dtv_property *tvp)
-{
-	return (DTV_ATSCMH_FIC_VER == tvp->cmd) ?
-		lg216x_get_frontend(fe) : 0;
-}
-
-
-static int lg2160_set_frontend(struct dvb_frontend *fe)
-{
-	struct lg216x_state *state = fe->demodulator_priv;
-	int ret;
-
-	lg_dbg("(%d)\n", fe->dtv_property_cache.frequency);
-
-	if (fe->ops.tuner_ops.set_params) {
-		ret = fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-		if (lg_fail(ret))
-			goto fail;
-		state->current_frequency = fe->dtv_property_cache.frequency;
-	}
-
-	ret = lg2160_agc_fix(state, 0, 0);
-	if (lg_fail(ret))
-		goto fail;
-	ret = lg2160_agc_polarity(state, 0, 0);
-	if (lg_fail(ret))
-		goto fail;
-	ret = lg2160_tuner_pwr_save_polarity(state, 1);
-	if (lg_fail(ret))
-		goto fail;
-	ret = lg216x_set_if(state);
-	if (lg_fail(ret))
-		goto fail;
-	ret = lg2160_spectrum_polarity(state, state->cfg->spectral_inversion);
-	if (lg_fail(ret))
-		goto fail;
-
-	/* be tuned before this point */
-	ret = lg216x_soft_reset(state);
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lg2160_tuner_pwr_save(state, 0);
-	if (lg_fail(ret))
-		goto fail;
-
-	switch (state->cfg->lg_chip) {
-	case LG2160:
-		ret = lg2160_set_spi_clock(state);
-		if (lg_fail(ret))
-			goto fail;
-		break;
-	case LG2161:
-		ret = lg2161_set_output_interface(state);
-		if (lg_fail(ret))
-			goto fail;
-		break;
-	}
-
-	ret = lg216x_set_parade(state, fe->dtv_property_cache.atscmh_parade_id);
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lg216x_set_ensemble(state,
-			fe->dtv_property_cache.atscmh_rs_frame_ensemble);
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lg216x_initialize(state);
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lg216x_enable_fic(state, 1);
-	lg_fail(ret);
-
-	lg216x_get_frontend(fe);
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int lg2160_read_lock_status(struct lg216x_state *state,
-				   int *acq_lock, int *sync_lock)
-{
-	u8 val;
-	int ret;
-
-	*acq_lock = 0;
-	*sync_lock = 0;
-
-	ret = lg216x_read_reg(state, 0x011b, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	*sync_lock = (val & 0x20) ? 0 : 1;
-	*acq_lock  = (val & 0x40) ? 0 : 1;
-fail:
-	return ret;
-}
-
-#ifdef USE_LG2161_LOCK_BITS
-static int lg2161_read_lock_status(struct lg216x_state *state,
-				   int *acq_lock, int *sync_lock)
-{
-	u8 val;
-	int ret;
-
-	*acq_lock = 0;
-	*sync_lock = 0;
-
-	ret = lg216x_read_reg(state, 0x0304, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	*sync_lock = (val & 0x80) ? 0 : 1;
-
-	ret = lg216x_read_reg(state, 0x011b, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	*acq_lock  = (val & 0x40) ? 0 : 1;
-fail:
-	return ret;
-}
-#endif
-
-static int lg216x_read_lock_status(struct lg216x_state *state,
-				   int *acq_lock, int *sync_lock)
-{
-#ifdef USE_LG2161_LOCK_BITS
-	int ret;
-	switch (state->cfg->lg_chip) {
-	case LG2160:
-		ret = lg2160_read_lock_status(state, acq_lock, sync_lock);
-		break;
-	case LG2161:
-		ret = lg2161_read_lock_status(state, acq_lock, sync_lock);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-#else
-	return lg2160_read_lock_status(state, acq_lock, sync_lock);
-#endif
-}
-
-static int lg216x_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct lg216x_state *state = fe->demodulator_priv;
-	int ret, acq_lock, sync_lock;
-
-	*status = 0;
-
-	ret = lg216x_read_lock_status(state, &acq_lock, &sync_lock);
-	if (lg_fail(ret))
-		goto fail;
-
-	lg_dbg("%s%s\n",
-	       acq_lock  ? "SIGNALEXIST " : "",
-	       sync_lock ? "SYNCLOCK"     : "");
-
-	if (acq_lock)
-		*status |= FE_HAS_SIGNAL;
-	if (sync_lock)
-		*status |= FE_HAS_SYNC;
-
-	if (*status)
-		*status |= FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK;
-
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int lg2160_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct lg216x_state *state = fe->demodulator_priv;
-	u8 snr1, snr2;
-	int ret;
-
-	*snr = 0;
-
-	ret = lg216x_read_reg(state, 0x0202, &snr1);
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lg216x_read_reg(state, 0x0203, &snr2);
-	if (lg_fail(ret))
-		goto fail;
-
-	if ((snr1 == 0xba) || (snr2 == 0xdf))
-		*snr = 0;
-	else
-#if 1
-	*snr =  ((snr1 >> 4) * 100) + ((snr1 & 0x0f) * 10) + (snr2 >> 4);
-#else /* BCD */
-	*snr =  (snr2 | (snr1 << 8));
-#endif
-fail:
-	return ret;
-}
-
-static int lg2161_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct lg216x_state *state = fe->demodulator_priv;
-	u8 snr1, snr2;
-	int ret;
-
-	*snr = 0;
-
-	ret = lg216x_read_reg(state, 0x0302, &snr1);
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lg216x_read_reg(state, 0x0303, &snr2);
-	if (lg_fail(ret))
-		goto fail;
-
-	if ((snr1 == 0xba) || (snr2 == 0xfd))
-		*snr = 0;
-	else
-
-	*snr =  ((snr1 >> 4) * 100) + ((snr1 & 0x0f) * 10) + (snr2 & 0x0f);
-fail:
-	return ret;
-}
-
-static int lg216x_read_signal_strength(struct dvb_frontend *fe,
-				       u16 *strength)
-{
-#if 0
-	/* borrowed from lgdt330x.c
-	 *
-	 * Calculate strength from SNR up to 35dB
-	 * Even though the SNR can go higher than 35dB,
-	 * there is some comfort factor in having a range of
-	 * strong signals that can show at 100%
-	 */
-	struct lg216x_state *state = fe->demodulator_priv;
-	u16 snr;
-	int ret;
-#endif
-	*strength = 0;
-#if 0
-	ret = fe->ops.read_snr(fe, &snr);
-	if (lg_fail(ret))
-		goto fail;
-	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
-	/* scale the range 0 - 35*2^24 into 0 - 65535 */
-	if (state->snr >= 8960 * 0x10000)
-		*strength = 0xffff;
-	else
-		*strength = state->snr / 8960;
-fail:
-	return ret;
-#else
-	return 0;
-#endif
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int lg216x_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-#if 0
-	struct lg216x_state *state = fe->demodulator_priv;
-	int ret;
-
-	ret = lg216x_read_rs_err_count(state,
-				       &fe->dtv_property_cache.atscmh_rs_err);
-	if (lg_fail(ret))
-		goto fail;
-
-	*ucblocks = fe->dtv_property_cache.atscmh_rs_err;
-fail:
-#else
-	*ucblocks = 0;
-#endif
-	return 0;
-}
-
-static int lg216x_get_tune_settings(struct dvb_frontend *fe,
-				    struct dvb_frontend_tune_settings
-				    *fe_tune_settings)
-{
-	fe_tune_settings->min_delay_ms = 500;
-	lg_dbg("\n");
-	return 0;
-}
-
-static void lg216x_release(struct dvb_frontend *fe)
-{
-	struct lg216x_state *state = fe->demodulator_priv;
-	lg_dbg("\n");
-	kfree(state);
-}
-
-static struct dvb_frontend_ops lg2160_ops = {
-	.delsys = { SYS_ATSCMH },
-	.info = {
-		.name = "LG Electronics LG2160 ATSC/MH Frontend",
-		.frequency_min      = 54000000,
-		.frequency_max      = 858000000,
-		.frequency_stepsize = 62500,
-	},
-	.i2c_gate_ctrl        = lg216x_i2c_gate_ctrl,
-#if 0
-	.init                 = lg216x_init,
-	.sleep                = lg216x_sleep,
-#endif
-	.get_property         = lg216x_get_property,
-
-	.set_frontend         = lg2160_set_frontend,
-	.get_frontend         = lg216x_get_frontend,
-	.get_tune_settings    = lg216x_get_tune_settings,
-	.read_status          = lg216x_read_status,
-#if 0
-	.read_ber             = lg216x_read_ber,
-#endif
-	.read_signal_strength = lg216x_read_signal_strength,
-	.read_snr             = lg2160_read_snr,
-	.read_ucblocks        = lg216x_read_ucblocks,
-	.release              = lg216x_release,
-};
-
-static struct dvb_frontend_ops lg2161_ops = {
-	.delsys = { SYS_ATSCMH },
-	.info = {
-		.name = "LG Electronics LG2161 ATSC/MH Frontend",
-		.frequency_min      = 54000000,
-		.frequency_max      = 858000000,
-		.frequency_stepsize = 62500,
-	},
-	.i2c_gate_ctrl        = lg216x_i2c_gate_ctrl,
-#if 0
-	.init                 = lg216x_init,
-	.sleep                = lg216x_sleep,
-#endif
-	.get_property         = lg216x_get_property,
-
-	.set_frontend         = lg2160_set_frontend,
-	.get_frontend         = lg216x_get_frontend,
-	.get_tune_settings    = lg216x_get_tune_settings,
-	.read_status          = lg216x_read_status,
-#if 0
-	.read_ber             = lg216x_read_ber,
-#endif
-	.read_signal_strength = lg216x_read_signal_strength,
-	.read_snr             = lg2161_read_snr,
-	.read_ucblocks        = lg216x_read_ucblocks,
-	.release              = lg216x_release,
-};
-
-struct dvb_frontend *lg2160_attach(const struct lg2160_config *config,
-				   struct i2c_adapter *i2c_adap)
-{
-	struct lg216x_state *state = NULL;
-
-	lg_dbg("(%d-%04x)\n",
-	       i2c_adap ? i2c_adapter_id(i2c_adap) : 0,
-	       config ? config->i2c_addr : 0);
-
-	state = kzalloc(sizeof(struct lg216x_state), GFP_KERNEL);
-	if (state == NULL)
-		goto fail;
-
-	state->cfg = config;
-	state->i2c_adap = i2c_adap;
-	state->fic_ver = 0xff;
-	state->parade_id = 0xff;
-
-	switch (config->lg_chip) {
-	default:
-		lg_warn("invalid chip requested, defaulting to LG2160");
-		/* fall-thru */
-	case LG2160:
-		memcpy(&state->frontend.ops, &lg2160_ops,
-		       sizeof(struct dvb_frontend_ops));
-		break;
-	case LG2161:
-		memcpy(&state->frontend.ops, &lg2161_ops,
-		       sizeof(struct dvb_frontend_ops));
-		break;
-	}
-
-	state->frontend.demodulator_priv = state;
-	state->current_frequency = -1;
-	/* parade 1 by default */
-	state->frontend.dtv_property_cache.atscmh_parade_id = 1;
-
-	return &state->frontend;
-fail:
-	lg_warn("unable to detect LG216x hardware\n");
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(lg2160_attach);
-
-MODULE_DESCRIPTION("LG Electronics LG216x ATSC/MH Demodulator Driver");
-MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.3");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/frontends/lg2160.h b/drivers/media/dvb/frontends/lg2160.h
deleted file mode 100644
index 9e2c0f4..0000000
--- a/drivers/media/dvb/frontends/lg2160.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- *    Support for LG2160 - ATSC/MH
- *
- *    Copyright (C) 2010 Michael Krufky <mkrufky@linuxtv.org>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef _LG2160_H_
-#define _LG2160_H_
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-enum lg_chip_type {
-	LG2160 = 0,
-	LG2161 = 1,
-};
-
-#define LG2161_1019 LG2161
-#define LG2161_1040 LG2161
-
-enum lg2160_spi_clock {
-	LG2160_SPI_3_125_MHZ = 0,
-	LG2160_SPI_6_25_MHZ = 1,
-	LG2160_SPI_12_5_MHZ = 2,
-};
-
-#if 0
-enum lg2161_oif {
-	LG2161_OIF_EBI2_SLA  = 1,
-	LG2161_OIF_SDIO_SLA  = 2,
-	LG2161_OIF_SPI_SLA   = 3,
-	LG2161_OIF_SPI_MAS   = 4,
-	LG2161_OIF_SERIAL_TS = 7,
-};
-#endif
-
-struct lg2160_config {
-	u8 i2c_addr;
-
-	/* user defined IF frequency in KHz */
-	u16 if_khz;
-
-	/* disable i2c repeater - 0:repeater enabled 1:repeater disabled */
-	int deny_i2c_rptr:1;
-
-	/* spectral inversion - 0:disabled 1:enabled */
-	int spectral_inversion:1;
-
-	unsigned int output_if;
-	enum lg2160_spi_clock spi_clock;
-	enum lg_chip_type lg_chip;
-};
-
-#if defined(CONFIG_DVB_LG2160) || (defined(CONFIG_DVB_LG2160_MODULE) && \
-				     defined(MODULE))
-extern
-struct dvb_frontend *lg2160_attach(const struct lg2160_config *config,
-				     struct i2c_adapter *i2c_adap);
-#else
-static inline
-struct dvb_frontend *lg2160_attach(const struct lg2160_config *config,
-				     struct i2c_adapter *i2c_adap)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_LG2160 */
-
-#endif /* _LG2160_H_ */
diff --git a/drivers/media/dvb/frontends/lgdt3305.c b/drivers/media/dvb/frontends/lgdt3305.c
deleted file mode 100644
index 1d2c473..0000000
--- a/drivers/media/dvb/frontends/lgdt3305.c
+++ /dev/null
@@ -1,1222 +0,0 @@
-/*
- *    Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM
- *
- *    Copyright (C) 2008, 2009, 2010 Michael Krufky <mkrufky@linuxtv.org>
- *
- *    LGDT3304 support by Jarod Wilson <jarod@redhat.com>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <asm/div64.h>
-#include <linux/dvb/frontend.h>
-#include <linux/slab.h>
-#include "dvb_math.h"
-#include "lgdt3305.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))");
-
-#define DBG_INFO 1
-#define DBG_REG  2
-
-#define lg_printk(kern, fmt, arg...)					\
-	printk(kern "%s: " fmt, __func__, ##arg)
-
-#define lg_info(fmt, arg...)	printk(KERN_INFO "lgdt3305: " fmt, ##arg)
-#define lg_warn(fmt, arg...)	lg_printk(KERN_WARNING,       fmt, ##arg)
-#define lg_err(fmt, arg...)	lg_printk(KERN_ERR,           fmt, ##arg)
-#define lg_dbg(fmt, arg...) if (debug & DBG_INFO)			\
-				lg_printk(KERN_DEBUG,         fmt, ##arg)
-#define lg_reg(fmt, arg...) if (debug & DBG_REG)			\
-				lg_printk(KERN_DEBUG,         fmt, ##arg)
-
-#define lg_fail(ret)							\
-({									\
-	int __ret;							\
-	__ret = (ret < 0);						\
-	if (__ret)							\
-		lg_err("error %d on line %d\n",	ret, __LINE__);		\
-	__ret;								\
-})
-
-struct lgdt3305_state {
-	struct i2c_adapter *i2c_adap;
-	const struct lgdt3305_config *cfg;
-
-	struct dvb_frontend frontend;
-
-	fe_modulation_t current_modulation;
-	u32 current_frequency;
-	u32 snr;
-};
-
-/* ------------------------------------------------------------------------ */
-
-/* FIXME: verify & document the LGDT3304 registers */
-
-#define LGDT3305_GEN_CTRL_1                   0x0000
-#define LGDT3305_GEN_CTRL_2                   0x0001
-#define LGDT3305_GEN_CTRL_3                   0x0002
-#define LGDT3305_GEN_STATUS                   0x0003
-#define LGDT3305_GEN_CONTROL                  0x0007
-#define LGDT3305_GEN_CTRL_4                   0x000a
-#define LGDT3305_DGTL_AGC_REF_1               0x0012
-#define LGDT3305_DGTL_AGC_REF_2               0x0013
-#define LGDT3305_CR_CTR_FREQ_1                0x0106
-#define LGDT3305_CR_CTR_FREQ_2                0x0107
-#define LGDT3305_CR_CTR_FREQ_3                0x0108
-#define LGDT3305_CR_CTR_FREQ_4                0x0109
-#define LGDT3305_CR_MSE_1                     0x011b
-#define LGDT3305_CR_MSE_2                     0x011c
-#define LGDT3305_CR_LOCK_STATUS               0x011d
-#define LGDT3305_CR_CTRL_7                    0x0126
-#define LGDT3305_AGC_POWER_REF_1              0x0300
-#define LGDT3305_AGC_POWER_REF_2              0x0301
-#define LGDT3305_AGC_DELAY_PT_1               0x0302
-#define LGDT3305_AGC_DELAY_PT_2               0x0303
-#define LGDT3305_RFAGC_LOOP_FLTR_BW_1         0x0306
-#define LGDT3305_RFAGC_LOOP_FLTR_BW_2         0x0307
-#define LGDT3305_IFBW_1                       0x0308
-#define LGDT3305_IFBW_2                       0x0309
-#define LGDT3305_AGC_CTRL_1                   0x030c
-#define LGDT3305_AGC_CTRL_4                   0x0314
-#define LGDT3305_EQ_MSE_1                     0x0413
-#define LGDT3305_EQ_MSE_2                     0x0414
-#define LGDT3305_EQ_MSE_3                     0x0415
-#define LGDT3305_PT_MSE_1                     0x0417
-#define LGDT3305_PT_MSE_2                     0x0418
-#define LGDT3305_PT_MSE_3                     0x0419
-#define LGDT3305_FEC_BLOCK_CTRL               0x0504
-#define LGDT3305_FEC_LOCK_STATUS              0x050a
-#define LGDT3305_FEC_PKT_ERR_1                0x050c
-#define LGDT3305_FEC_PKT_ERR_2                0x050d
-#define LGDT3305_TP_CTRL_1                    0x050e
-#define LGDT3305_BERT_PERIOD                  0x0801
-#define LGDT3305_BERT_ERROR_COUNT_1           0x080a
-#define LGDT3305_BERT_ERROR_COUNT_2           0x080b
-#define LGDT3305_BERT_ERROR_COUNT_3           0x080c
-#define LGDT3305_BERT_ERROR_COUNT_4           0x080d
-
-static int lgdt3305_write_reg(struct lgdt3305_state *state, u16 reg, u8 val)
-{
-	int ret;
-	u8 buf[] = { reg >> 8, reg & 0xff, val };
-	struct i2c_msg msg = {
-		.addr = state->cfg->i2c_addr, .flags = 0,
-		.buf = buf, .len = 3,
-	};
-
-	lg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val);
-
-	ret = i2c_transfer(state->i2c_adap, &msg, 1);
-
-	if (ret != 1) {
-		lg_err("error (addr %02x %02x <- %02x, err = %i)\n",
-		       msg.buf[0], msg.buf[1], msg.buf[2], ret);
-		if (ret < 0)
-			return ret;
-		else
-			return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int lgdt3305_read_reg(struct lgdt3305_state *state, u16 reg, u8 *val)
-{
-	int ret;
-	u8 reg_buf[] = { reg >> 8, reg & 0xff };
-	struct i2c_msg msg[] = {
-		{ .addr = state->cfg->i2c_addr,
-		  .flags = 0, .buf = reg_buf, .len = 2 },
-		{ .addr = state->cfg->i2c_addr,
-		  .flags = I2C_M_RD, .buf = val, .len = 1 },
-	};
-
-	lg_reg("reg: 0x%04x\n", reg);
-
-	ret = i2c_transfer(state->i2c_adap, msg, 2);
-
-	if (ret != 2) {
-		lg_err("error (addr %02x reg %04x error (ret == %i)\n",
-		       state->cfg->i2c_addr, reg, ret);
-		if (ret < 0)
-			return ret;
-		else
-			return -EREMOTEIO;
-	}
-	return 0;
-}
-
-#define read_reg(state, reg)						\
-({									\
-	u8 __val;							\
-	int ret = lgdt3305_read_reg(state, reg, &__val);		\
-	if (lg_fail(ret))						\
-		__val = 0;						\
-	__val;								\
-})
-
-static int lgdt3305_set_reg_bit(struct lgdt3305_state *state,
-				u16 reg, int bit, int onoff)
-{
-	u8 val;
-	int ret;
-
-	lg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff);
-
-	ret = lgdt3305_read_reg(state, reg, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	val &= ~(1 << bit);
-	val |= (onoff & 1) << bit;
-
-	ret = lgdt3305_write_reg(state, reg, val);
-fail:
-	return ret;
-}
-
-struct lgdt3305_reg {
-	u16 reg;
-	u8 val;
-};
-
-static int lgdt3305_write_regs(struct lgdt3305_state *state,
-			       struct lgdt3305_reg *regs, int len)
-{
-	int i, ret;
-
-	lg_reg("writing %d registers...\n", len);
-
-	for (i = 0; i < len - 1; i++) {
-		ret = lgdt3305_write_reg(state, regs[i].reg, regs[i].val);
-		if (lg_fail(ret))
-			return ret;
-	}
-	return 0;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int lgdt3305_soft_reset(struct lgdt3305_state *state)
-{
-	int ret;
-
-	lg_dbg("\n");
-
-	ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 0);
-	if (lg_fail(ret))
-		goto fail;
-
-	msleep(20);
-	ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 1);
-fail:
-	return ret;
-}
-
-static inline int lgdt3305_mpeg_mode(struct lgdt3305_state *state,
-				     enum lgdt3305_mpeg_mode mode)
-{
-	lg_dbg("(%d)\n", mode);
-	return lgdt3305_set_reg_bit(state, LGDT3305_TP_CTRL_1, 5, mode);
-}
-
-static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state,
-				       enum lgdt3305_tp_clock_edge edge,
-				       enum lgdt3305_tp_valid_polarity valid)
-{
-	u8 val;
-	int ret;
-
-	lg_dbg("edge = %d, valid = %d\n", edge, valid);
-
-	ret = lgdt3305_read_reg(state, LGDT3305_TP_CTRL_1, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	val &= ~0x09;
-
-	if (edge)
-		val |= 0x08;
-	if (valid)
-		val |= 0x01;
-
-	ret = lgdt3305_write_reg(state, LGDT3305_TP_CTRL_1, val);
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lgdt3305_soft_reset(state);
-fail:
-	return ret;
-}
-
-static int lgdt3305_set_modulation(struct lgdt3305_state *state,
-				   struct dtv_frontend_properties *p)
-{
-	u8 opermode;
-	int ret;
-
-	lg_dbg("\n");
-
-	ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_1, &opermode);
-	if (lg_fail(ret))
-		goto fail;
-
-	opermode &= ~0x03;
-
-	switch (p->modulation) {
-	case VSB_8:
-		opermode |= 0x03;
-		break;
-	case QAM_64:
-		opermode |= 0x00;
-		break;
-	case QAM_256:
-		opermode |= 0x01;
-		break;
-	default:
-		return -EINVAL;
-	}
-	ret = lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_1, opermode);
-fail:
-	return ret;
-}
-
-static int lgdt3305_set_filter_extension(struct lgdt3305_state *state,
-					 struct dtv_frontend_properties *p)
-{
-	int val;
-
-	switch (p->modulation) {
-	case VSB_8:
-		val = 0;
-		break;
-	case QAM_64:
-	case QAM_256:
-		val = 1;
-		break;
-	default:
-		return -EINVAL;
-	}
-	lg_dbg("val = %d\n", val);
-
-	return lgdt3305_set_reg_bit(state, 0x043f, 2, val);
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int lgdt3305_passband_digital_agc(struct lgdt3305_state *state,
-					 struct dtv_frontend_properties *p)
-{
-	u16 agc_ref;
-
-	switch (p->modulation) {
-	case VSB_8:
-		agc_ref = 0x32c4;
-		break;
-	case QAM_64:
-		agc_ref = 0x2a00;
-		break;
-	case QAM_256:
-		agc_ref = 0x2a80;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	lg_dbg("agc ref: 0x%04x\n", agc_ref);
-
-	lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_1, agc_ref >> 8);
-	lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_2, agc_ref & 0xff);
-
-	return 0;
-}
-
-static int lgdt3305_rfagc_loop(struct lgdt3305_state *state,
-			       struct dtv_frontend_properties *p)
-{
-	u16 ifbw, rfbw, agcdelay;
-
-	switch (p->modulation) {
-	case VSB_8:
-		agcdelay = 0x04c0;
-		rfbw     = 0x8000;
-		ifbw     = 0x8000;
-		break;
-	case QAM_64:
-	case QAM_256:
-		agcdelay = 0x046b;
-		rfbw     = 0x8889;
-		/* FIXME: investigate optimal ifbw & rfbw values for the
-		 *        DT3304 and re-write this switch..case block */
-		if (state->cfg->demod_chip == LGDT3304)
-			ifbw = 0x6666;
-		else /* (state->cfg->demod_chip == LGDT3305) */
-			ifbw = 0x8888;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (state->cfg->rf_agc_loop) {
-		lg_dbg("agcdelay: 0x%04x, rfbw: 0x%04x\n", agcdelay, rfbw);
-
-		/* rf agc loop filter bandwidth */
-		lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_1,
-				   agcdelay >> 8);
-		lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_2,
-				   agcdelay & 0xff);
-
-		lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_1,
-				   rfbw >> 8);
-		lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_2,
-				   rfbw & 0xff);
-	} else {
-		lg_dbg("ifbw: 0x%04x\n", ifbw);
-
-		/* if agc loop filter bandwidth */
-		lgdt3305_write_reg(state, LGDT3305_IFBW_1, ifbw >> 8);
-		lgdt3305_write_reg(state, LGDT3305_IFBW_2, ifbw & 0xff);
-	}
-
-	return 0;
-}
-
-static int lgdt3305_agc_setup(struct lgdt3305_state *state,
-			      struct dtv_frontend_properties *p)
-{
-	int lockdten, acqen;
-
-	switch (p->modulation) {
-	case VSB_8:
-		lockdten = 0;
-		acqen = 0;
-		break;
-	case QAM_64:
-	case QAM_256:
-		lockdten = 1;
-		acqen = 1;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	lg_dbg("lockdten = %d, acqen = %d\n", lockdten, acqen);
-
-	/* control agc function */
-	switch (state->cfg->demod_chip) {
-	case LGDT3304:
-		lgdt3305_write_reg(state, 0x0314, 0xe1 | lockdten << 1);
-		lgdt3305_set_reg_bit(state, 0x030e, 2, acqen);
-		break;
-	case LGDT3305:
-		lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1);
-		lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return lgdt3305_rfagc_loop(state, p);
-}
-
-static int lgdt3305_set_agc_power_ref(struct lgdt3305_state *state,
-				      struct dtv_frontend_properties *p)
-{
-	u16 usref = 0;
-
-	switch (p->modulation) {
-	case VSB_8:
-		if (state->cfg->usref_8vsb)
-			usref = state->cfg->usref_8vsb;
-		break;
-	case QAM_64:
-		if (state->cfg->usref_qam64)
-			usref = state->cfg->usref_qam64;
-		break;
-	case QAM_256:
-		if (state->cfg->usref_qam256)
-			usref = state->cfg->usref_qam256;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (usref) {
-		lg_dbg("set manual mode: 0x%04x\n", usref);
-
-		lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 3, 1);
-
-		lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_1,
-				   0xff & (usref >> 8));
-		lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_2,
-				   0xff & (usref >> 0));
-	}
-	return 0;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int lgdt3305_spectral_inversion(struct lgdt3305_state *state,
-				       struct dtv_frontend_properties *p,
-				       int inversion)
-{
-	int ret;
-
-	lg_dbg("(%d)\n", inversion);
-
-	switch (p->modulation) {
-	case VSB_8:
-		ret = lgdt3305_write_reg(state, LGDT3305_CR_CTRL_7,
-					 inversion ? 0xf9 : 0x79);
-		break;
-	case QAM_64:
-	case QAM_256:
-		ret = lgdt3305_write_reg(state, LGDT3305_FEC_BLOCK_CTRL,
-					 inversion ? 0xfd : 0xff);
-		break;
-	default:
-		ret = -EINVAL;
-	}
-	return ret;
-}
-
-static int lgdt3305_set_if(struct lgdt3305_state *state,
-			   struct dtv_frontend_properties *p)
-{
-	u16 if_freq_khz;
-	u8 nco1, nco2, nco3, nco4;
-	u64 nco;
-
-	switch (p->modulation) {
-	case VSB_8:
-		if_freq_khz = state->cfg->vsb_if_khz;
-		break;
-	case QAM_64:
-	case QAM_256:
-		if_freq_khz = state->cfg->qam_if_khz;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	nco = if_freq_khz / 10;
-
-	switch (p->modulation) {
-	case VSB_8:
-		nco <<= 24;
-		do_div(nco, 625);
-		break;
-	case QAM_64:
-	case QAM_256:
-		nco <<= 28;
-		do_div(nco, 625);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	nco1 = (nco >> 24) & 0x3f;
-	nco1 |= 0x40;
-	nco2 = (nco >> 16) & 0xff;
-	nco3 = (nco >> 8) & 0xff;
-	nco4 = nco & 0xff;
-
-	lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, nco1);
-	lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, nco2);
-	lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, nco3);
-	lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, nco4);
-
-	lg_dbg("%d KHz -> [%02x%02x%02x%02x]\n",
-	       if_freq_khz, nco1, nco2, nco3, nco4);
-
-	return 0;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int lgdt3305_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct lgdt3305_state *state = fe->demodulator_priv;
-
-	if (state->cfg->deny_i2c_rptr)
-		return 0;
-
-	lg_dbg("(%d)\n", enable);
-
-	return lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_2, 5,
-				    enable ? 0 : 1);
-}
-
-static int lgdt3305_sleep(struct dvb_frontend *fe)
-{
-	struct lgdt3305_state *state = fe->demodulator_priv;
-	u8 gen_ctrl_3, gen_ctrl_4;
-
-	lg_dbg("\n");
-
-	gen_ctrl_3 = read_reg(state, LGDT3305_GEN_CTRL_3);
-	gen_ctrl_4 = read_reg(state, LGDT3305_GEN_CTRL_4);
-
-	/* hold in software reset while sleeping */
-	gen_ctrl_3 &= ~0x01;
-	/* tristate the IF-AGC pin */
-	gen_ctrl_3 |=  0x02;
-	/* tristate the RF-AGC pin */
-	gen_ctrl_3 |=  0x04;
-
-	/* disable vsb/qam module */
-	gen_ctrl_4 &= ~0x01;
-	/* disable adc module */
-	gen_ctrl_4 &= ~0x02;
-
-	lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_3, gen_ctrl_3);
-	lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_4, gen_ctrl_4);
-
-	return 0;
-}
-
-static int lgdt3305_init(struct dvb_frontend *fe)
-{
-	struct lgdt3305_state *state = fe->demodulator_priv;
-	int ret;
-
-	static struct lgdt3305_reg lgdt3304_init_data[] = {
-		{ .reg = LGDT3305_GEN_CTRL_1,           .val = 0x03, },
-		{ .reg = 0x000d,                        .val = 0x02, },
-		{ .reg = 0x000e,                        .val = 0x02, },
-		{ .reg = LGDT3305_DGTL_AGC_REF_1,       .val = 0x32, },
-		{ .reg = LGDT3305_DGTL_AGC_REF_2,       .val = 0xc4, },
-		{ .reg = LGDT3305_CR_CTR_FREQ_1,        .val = 0x00, },
-		{ .reg = LGDT3305_CR_CTR_FREQ_2,        .val = 0x00, },
-		{ .reg = LGDT3305_CR_CTR_FREQ_3,        .val = 0x00, },
-		{ .reg = LGDT3305_CR_CTR_FREQ_4,        .val = 0x00, },
-		{ .reg = LGDT3305_CR_CTRL_7,            .val = 0xf9, },
-		{ .reg = 0x0112,                        .val = 0x17, },
-		{ .reg = 0x0113,                        .val = 0x15, },
-		{ .reg = 0x0114,                        .val = 0x18, },
-		{ .reg = 0x0115,                        .val = 0xff, },
-		{ .reg = 0x0116,                        .val = 0x3c, },
-		{ .reg = 0x0214,                        .val = 0x67, },
-		{ .reg = 0x0424,                        .val = 0x8d, },
-		{ .reg = 0x0427,                        .val = 0x12, },
-		{ .reg = 0x0428,                        .val = 0x4f, },
-		{ .reg = LGDT3305_IFBW_1,               .val = 0x80, },
-		{ .reg = LGDT3305_IFBW_2,               .val = 0x00, },
-		{ .reg = 0x030a,                        .val = 0x08, },
-		{ .reg = 0x030b,                        .val = 0x9b, },
-		{ .reg = 0x030d,                        .val = 0x00, },
-		{ .reg = 0x030e,                        .val = 0x1c, },
-		{ .reg = 0x0314,                        .val = 0xe1, },
-		{ .reg = 0x000d,                        .val = 0x82, },
-		{ .reg = LGDT3305_TP_CTRL_1,            .val = 0x5b, },
-		{ .reg = LGDT3305_TP_CTRL_1,            .val = 0x5b, },
-	};
-
-	static struct lgdt3305_reg lgdt3305_init_data[] = {
-		{ .reg = LGDT3305_GEN_CTRL_1,           .val = 0x03, },
-		{ .reg = LGDT3305_GEN_CTRL_2,           .val = 0xb0, },
-		{ .reg = LGDT3305_GEN_CTRL_3,           .val = 0x01, },
-		{ .reg = LGDT3305_GEN_CONTROL,          .val = 0x6f, },
-		{ .reg = LGDT3305_GEN_CTRL_4,           .val = 0x03, },
-		{ .reg = LGDT3305_DGTL_AGC_REF_1,       .val = 0x32, },
-		{ .reg = LGDT3305_DGTL_AGC_REF_2,       .val = 0xc4, },
-		{ .reg = LGDT3305_CR_CTR_FREQ_1,        .val = 0x00, },
-		{ .reg = LGDT3305_CR_CTR_FREQ_2,        .val = 0x00, },
-		{ .reg = LGDT3305_CR_CTR_FREQ_3,        .val = 0x00, },
-		{ .reg = LGDT3305_CR_CTR_FREQ_4,        .val = 0x00, },
-		{ .reg = LGDT3305_CR_CTRL_7,            .val = 0x79, },
-		{ .reg = LGDT3305_AGC_POWER_REF_1,      .val = 0x32, },
-		{ .reg = LGDT3305_AGC_POWER_REF_2,      .val = 0xc4, },
-		{ .reg = LGDT3305_AGC_DELAY_PT_1,       .val = 0x0d, },
-		{ .reg = LGDT3305_AGC_DELAY_PT_2,       .val = 0x30, },
-		{ .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_1, .val = 0x80, },
-		{ .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_2, .val = 0x00, },
-		{ .reg = LGDT3305_IFBW_1,               .val = 0x80, },
-		{ .reg = LGDT3305_IFBW_2,               .val = 0x00, },
-		{ .reg = LGDT3305_AGC_CTRL_1,           .val = 0x30, },
-		{ .reg = LGDT3305_AGC_CTRL_4,           .val = 0x61, },
-		{ .reg = LGDT3305_FEC_BLOCK_CTRL,       .val = 0xff, },
-		{ .reg = LGDT3305_TP_CTRL_1,            .val = 0x1b, },
-	};
-
-	lg_dbg("\n");
-
-	switch (state->cfg->demod_chip) {
-	case LGDT3304:
-		ret = lgdt3305_write_regs(state, lgdt3304_init_data,
-					  ARRAY_SIZE(lgdt3304_init_data));
-		break;
-	case LGDT3305:
-		ret = lgdt3305_write_regs(state, lgdt3305_init_data,
-					  ARRAY_SIZE(lgdt3305_init_data));
-		break;
-	default:
-		ret = -EINVAL;
-	}
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lgdt3305_soft_reset(state);
-fail:
-	return ret;
-}
-
-static int lgdt3304_set_parameters(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct lgdt3305_state *state = fe->demodulator_priv;
-	int ret;
-
-	lg_dbg("(%d, %d)\n", p->frequency, p->modulation);
-
-	if (fe->ops.tuner_ops.set_params) {
-		ret = fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-		if (lg_fail(ret))
-			goto fail;
-		state->current_frequency = p->frequency;
-	}
-
-	ret = lgdt3305_set_modulation(state, p);
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lgdt3305_passband_digital_agc(state, p);
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lgdt3305_agc_setup(state, p);
-	if (lg_fail(ret))
-		goto fail;
-
-	/* reg 0x030d is 3304-only... seen in vsb and qam usbsnoops... */
-	switch (p->modulation) {
-	case VSB_8:
-		lgdt3305_write_reg(state, 0x030d, 0x00);
-		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, 0x4f);
-		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, 0x0c);
-		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, 0xac);
-		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, 0xba);
-		break;
-	case QAM_64:
-	case QAM_256:
-		lgdt3305_write_reg(state, 0x030d, 0x14);
-		ret = lgdt3305_set_if(state, p);
-		if (lg_fail(ret))
-			goto fail;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-
-	ret = lgdt3305_spectral_inversion(state, p,
-					  state->cfg->spectral_inversion
-					  ? 1 : 0);
-	if (lg_fail(ret))
-		goto fail;
-
-	state->current_modulation = p->modulation;
-
-	ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
-	if (lg_fail(ret))
-		goto fail;
-
-	/* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
-	ret = lgdt3305_mpeg_mode_polarity(state,
-					  state->cfg->tpclk_edge,
-					  state->cfg->tpvalid_polarity);
-fail:
-	return ret;
-}
-
-static int lgdt3305_set_parameters(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct lgdt3305_state *state = fe->demodulator_priv;
-	int ret;
-
-	lg_dbg("(%d, %d)\n", p->frequency, p->modulation);
-
-	if (fe->ops.tuner_ops.set_params) {
-		ret = fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-		if (lg_fail(ret))
-			goto fail;
-		state->current_frequency = p->frequency;
-	}
-
-	ret = lgdt3305_set_modulation(state, p);
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lgdt3305_passband_digital_agc(state, p);
-	if (lg_fail(ret))
-		goto fail;
-	ret = lgdt3305_set_agc_power_ref(state, p);
-	if (lg_fail(ret))
-		goto fail;
-	ret = lgdt3305_agc_setup(state, p);
-	if (lg_fail(ret))
-		goto fail;
-
-	/* low if */
-	ret = lgdt3305_write_reg(state, LGDT3305_GEN_CONTROL, 0x2f);
-	if (lg_fail(ret))
-		goto fail;
-	ret = lgdt3305_set_reg_bit(state, LGDT3305_CR_CTR_FREQ_1, 6, 1);
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lgdt3305_set_if(state, p);
-	if (lg_fail(ret))
-		goto fail;
-	ret = lgdt3305_spectral_inversion(state, p,
-					  state->cfg->spectral_inversion
-					  ? 1 : 0);
-	if (lg_fail(ret))
-		goto fail;
-
-	ret = lgdt3305_set_filter_extension(state, p);
-	if (lg_fail(ret))
-		goto fail;
-
-	state->current_modulation = p->modulation;
-
-	ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
-	if (lg_fail(ret))
-		goto fail;
-
-	/* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
-	ret = lgdt3305_mpeg_mode_polarity(state,
-					  state->cfg->tpclk_edge,
-					  state->cfg->tpvalid_polarity);
-fail:
-	return ret;
-}
-
-static int lgdt3305_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct lgdt3305_state *state = fe->demodulator_priv;
-
-	lg_dbg("\n");
-
-	p->modulation = state->current_modulation;
-	p->frequency = state->current_frequency;
-	return 0;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int lgdt3305_read_cr_lock_status(struct lgdt3305_state *state,
-					int *locked)
-{
-	u8 val;
-	int ret;
-	char *cr_lock_state = "";
-
-	*locked = 0;
-
-	ret = lgdt3305_read_reg(state, LGDT3305_CR_LOCK_STATUS, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	switch (state->current_modulation) {
-	case QAM_256:
-	case QAM_64:
-		if (val & (1 << 1))
-			*locked = 1;
-
-		switch (val & 0x07) {
-		case 0:
-			cr_lock_state = "QAM UNLOCK";
-			break;
-		case 4:
-			cr_lock_state = "QAM 1stLock";
-			break;
-		case 6:
-			cr_lock_state = "QAM 2ndLock";
-			break;
-		case 7:
-			cr_lock_state = "QAM FinalLock";
-			break;
-		default:
-			cr_lock_state = "CLOCKQAM-INVALID!";
-			break;
-		}
-		break;
-	case VSB_8:
-		if (val & (1 << 7)) {
-			*locked = 1;
-			cr_lock_state = "CLOCKVSB";
-		}
-		break;
-	default:
-		ret = -EINVAL;
-	}
-	lg_dbg("(%d) %s\n", *locked, cr_lock_state);
-fail:
-	return ret;
-}
-
-static int lgdt3305_read_fec_lock_status(struct lgdt3305_state *state,
-					 int *locked)
-{
-	u8 val;
-	int ret, mpeg_lock, fec_lock, viterbi_lock;
-
-	*locked = 0;
-
-	switch (state->current_modulation) {
-	case QAM_256:
-	case QAM_64:
-		ret = lgdt3305_read_reg(state,
-					LGDT3305_FEC_LOCK_STATUS, &val);
-		if (lg_fail(ret))
-			goto fail;
-
-		mpeg_lock    = (val & (1 << 0)) ? 1 : 0;
-		fec_lock     = (val & (1 << 2)) ? 1 : 0;
-		viterbi_lock = (val & (1 << 3)) ? 1 : 0;
-
-		*locked = mpeg_lock && fec_lock && viterbi_lock;
-
-		lg_dbg("(%d) %s%s%s\n", *locked,
-		       mpeg_lock    ? "mpeg lock  "  : "",
-		       fec_lock     ? "fec lock  "   : "",
-		       viterbi_lock ? "viterbi lock" : "");
-		break;
-	case VSB_8:
-	default:
-		ret = -EINVAL;
-	}
-fail:
-	return ret;
-}
-
-static int lgdt3305_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct lgdt3305_state *state = fe->demodulator_priv;
-	u8 val;
-	int ret, signal, inlock, nofecerr, snrgood,
-		cr_lock, fec_lock, sync_lock;
-
-	*status = 0;
-
-	ret = lgdt3305_read_reg(state, LGDT3305_GEN_STATUS, &val);
-	if (lg_fail(ret))
-		goto fail;
-
-	signal    = (val & (1 << 4)) ? 1 : 0;
-	inlock    = (val & (1 << 3)) ? 0 : 1;
-	sync_lock = (val & (1 << 2)) ? 1 : 0;
-	nofecerr  = (val & (1 << 1)) ? 1 : 0;
-	snrgood   = (val & (1 << 0)) ? 1 : 0;
-
-	lg_dbg("%s%s%s%s%s\n",
-	       signal    ? "SIGNALEXIST " : "",
-	       inlock    ? "INLOCK "      : "",
-	       sync_lock ? "SYNCLOCK "    : "",
-	       nofecerr  ? "NOFECERR "    : "",
-	       snrgood   ? "SNRGOOD "     : "");
-
-	ret = lgdt3305_read_cr_lock_status(state, &cr_lock);
-	if (lg_fail(ret))
-		goto fail;
-
-	if (signal)
-		*status |= FE_HAS_SIGNAL;
-	if (cr_lock)
-		*status |= FE_HAS_CARRIER;
-	if (nofecerr)
-		*status |= FE_HAS_VITERBI;
-	if (sync_lock)
-		*status |= FE_HAS_SYNC;
-
-	switch (state->current_modulation) {
-	case QAM_256:
-	case QAM_64:
-		/* signal bit is unreliable on the DT3304 in QAM mode */
-		if (((LGDT3304 == state->cfg->demod_chip)) && (cr_lock))
-			*status |= FE_HAS_SIGNAL;
-
-		ret = lgdt3305_read_fec_lock_status(state, &fec_lock);
-		if (lg_fail(ret))
-			goto fail;
-
-		if (fec_lock)
-			*status |= FE_HAS_LOCK;
-		break;
-	case VSB_8:
-		if (inlock)
-			*status |= FE_HAS_LOCK;
-		break;
-	default:
-		ret = -EINVAL;
-	}
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-/* borrowed from lgdt330x.c */
-static u32 calculate_snr(u32 mse, u32 c)
-{
-	if (mse == 0) /* no signal */
-		return 0;
-
-	mse = intlog10(mse);
-	if (mse > c) {
-		/* Negative SNR, which is possible, but realisticly the
-		demod will lose lock before the signal gets this bad.  The
-		API only allows for unsigned values, so just return 0 */
-		return 0;
-	}
-	return 10*(c - mse);
-}
-
-static int lgdt3305_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct lgdt3305_state *state = fe->demodulator_priv;
-	u32 noise;	/* noise value */
-	u32 c;		/* per-modulation SNR calculation constant */
-
-	switch (state->current_modulation) {
-	case VSB_8:
-#ifdef USE_PTMSE
-		/* Use Phase Tracker Mean-Square Error Register */
-		/* SNR for ranges from -13.11 to +44.08 */
-		noise =	((read_reg(state, LGDT3305_PT_MSE_1) & 0x07) << 16) |
-			(read_reg(state, LGDT3305_PT_MSE_2) << 8) |
-			(read_reg(state, LGDT3305_PT_MSE_3) & 0xff);
-		c = 73957994; /* log10(25*32^2)*2^24 */
-#else
-		/* Use Equalizer Mean-Square Error Register */
-		/* SNR for ranges from -16.12 to +44.08 */
-		noise =	((read_reg(state, LGDT3305_EQ_MSE_1) & 0x0f) << 16) |
-			(read_reg(state, LGDT3305_EQ_MSE_2) << 8) |
-			(read_reg(state, LGDT3305_EQ_MSE_3) & 0xff);
-		c = 73957994; /* log10(25*32^2)*2^24 */
-#endif
-		break;
-	case QAM_64:
-	case QAM_256:
-		noise = (read_reg(state, LGDT3305_CR_MSE_1) << 8) |
-			(read_reg(state, LGDT3305_CR_MSE_2) & 0xff);
-
-		c = (state->current_modulation == QAM_64) ?
-			97939837 : 98026066;
-		/* log10(688128)*2^24 and log10(696320)*2^24 */
-		break;
-	default:
-		return -EINVAL;
-	}
-	state->snr = calculate_snr(noise, c);
-	/* report SNR in dB * 10 */
-	*snr = (state->snr / ((1 << 24) / 10));
-	lg_dbg("noise = 0x%08x, snr = %d.%02d dB\n", noise,
-	       state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
-
-	return 0;
-}
-
-static int lgdt3305_read_signal_strength(struct dvb_frontend *fe,
-					 u16 *strength)
-{
-	/* borrowed from lgdt330x.c
-	 *
-	 * Calculate strength from SNR up to 35dB
-	 * Even though the SNR can go higher than 35dB,
-	 * there is some comfort factor in having a range of
-	 * strong signals that can show at 100%
-	 */
-	struct lgdt3305_state *state = fe->demodulator_priv;
-	u16 snr;
-	int ret;
-
-	*strength = 0;
-
-	ret = fe->ops.read_snr(fe, &snr);
-	if (lg_fail(ret))
-		goto fail;
-	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
-	/* scale the range 0 - 35*2^24 into 0 - 65535 */
-	if (state->snr >= 8960 * 0x10000)
-		*strength = 0xffff;
-	else
-		*strength = state->snr / 8960;
-fail:
-	return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int lgdt3305_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	*ber = 0;
-	return 0;
-}
-
-static int lgdt3305_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct lgdt3305_state *state = fe->demodulator_priv;
-
-	*ucblocks =
-		(read_reg(state, LGDT3305_FEC_PKT_ERR_1) << 8) |
-		(read_reg(state, LGDT3305_FEC_PKT_ERR_2) & 0xff);
-
-	return 0;
-}
-
-static int lgdt3305_get_tune_settings(struct dvb_frontend *fe,
-				      struct dvb_frontend_tune_settings
-					*fe_tune_settings)
-{
-	fe_tune_settings->min_delay_ms = 500;
-	lg_dbg("\n");
-	return 0;
-}
-
-static void lgdt3305_release(struct dvb_frontend *fe)
-{
-	struct lgdt3305_state *state = fe->demodulator_priv;
-	lg_dbg("\n");
-	kfree(state);
-}
-
-static struct dvb_frontend_ops lgdt3304_ops;
-static struct dvb_frontend_ops lgdt3305_ops;
-
-struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
-				     struct i2c_adapter *i2c_adap)
-{
-	struct lgdt3305_state *state = NULL;
-	int ret;
-	u8 val;
-
-	lg_dbg("(%d-%04x)\n",
-	       i2c_adap ? i2c_adapter_id(i2c_adap) : 0,
-	       config ? config->i2c_addr : 0);
-
-	state = kzalloc(sizeof(struct lgdt3305_state), GFP_KERNEL);
-	if (state == NULL)
-		goto fail;
-
-	state->cfg = config;
-	state->i2c_adap = i2c_adap;
-
-	switch (config->demod_chip) {
-	case LGDT3304:
-		memcpy(&state->frontend.ops, &lgdt3304_ops,
-		       sizeof(struct dvb_frontend_ops));
-		break;
-	case LGDT3305:
-		memcpy(&state->frontend.ops, &lgdt3305_ops,
-		       sizeof(struct dvb_frontend_ops));
-		break;
-	default:
-		goto fail;
-	}
-	state->frontend.demodulator_priv = state;
-
-	/* verify that we're talking to a lg dt3304/5 */
-	ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_2, &val);
-	if ((lg_fail(ret)) | (val == 0))
-		goto fail;
-	ret = lgdt3305_write_reg(state, 0x0808, 0x80);
-	if (lg_fail(ret))
-		goto fail;
-	ret = lgdt3305_read_reg(state, 0x0808, &val);
-	if ((lg_fail(ret)) | (val != 0x80))
-		goto fail;
-	ret = lgdt3305_write_reg(state, 0x0808, 0x00);
-	if (lg_fail(ret))
-		goto fail;
-
-	state->current_frequency = -1;
-	state->current_modulation = -1;
-
-	return &state->frontend;
-fail:
-	lg_warn("unable to detect %s hardware\n",
-		config->demod_chip ? "LGDT3304" : "LGDT3305");
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(lgdt3305_attach);
-
-static struct dvb_frontend_ops lgdt3304_ops = {
-	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
-	.info = {
-		.name = "LG Electronics LGDT3304 VSB/QAM Frontend",
-		.frequency_min      = 54000000,
-		.frequency_max      = 858000000,
-		.frequency_stepsize = 62500,
-		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
-	},
-	.i2c_gate_ctrl        = lgdt3305_i2c_gate_ctrl,
-	.init                 = lgdt3305_init,
-	.set_frontend         = lgdt3304_set_parameters,
-	.get_frontend         = lgdt3305_get_frontend,
-	.get_tune_settings    = lgdt3305_get_tune_settings,
-	.read_status          = lgdt3305_read_status,
-	.read_ber             = lgdt3305_read_ber,
-	.read_signal_strength = lgdt3305_read_signal_strength,
-	.read_snr             = lgdt3305_read_snr,
-	.read_ucblocks        = lgdt3305_read_ucblocks,
-	.release              = lgdt3305_release,
-};
-
-static struct dvb_frontend_ops lgdt3305_ops = {
-	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
-	.info = {
-		.name = "LG Electronics LGDT3305 VSB/QAM Frontend",
-		.frequency_min      = 54000000,
-		.frequency_max      = 858000000,
-		.frequency_stepsize = 62500,
-		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
-	},
-	.i2c_gate_ctrl        = lgdt3305_i2c_gate_ctrl,
-	.init                 = lgdt3305_init,
-	.sleep                = lgdt3305_sleep,
-	.set_frontend         = lgdt3305_set_parameters,
-	.get_frontend         = lgdt3305_get_frontend,
-	.get_tune_settings    = lgdt3305_get_tune_settings,
-	.read_status          = lgdt3305_read_status,
-	.read_ber             = lgdt3305_read_ber,
-	.read_signal_strength = lgdt3305_read_signal_strength,
-	.read_snr             = lgdt3305_read_snr,
-	.read_ucblocks        = lgdt3305_read_ucblocks,
-	.release              = lgdt3305_release,
-};
-
-MODULE_DESCRIPTION("LG Electronics LGDT3304/5 ATSC/QAM-B Demodulator Driver");
-MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.2");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/frontends/lgdt3305.h b/drivers/media/dvb/frontends/lgdt3305.h
deleted file mode 100644
index 02172ec..0000000
--- a/drivers/media/dvb/frontends/lgdt3305.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- *    Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM
- *
- *    Copyright (C) 2008, 2009, 2010 Michael Krufky <mkrufky@linuxtv.org>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef _LGDT3305_H_
-#define _LGDT3305_H_
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-
-enum lgdt3305_mpeg_mode {
-	LGDT3305_MPEG_PARALLEL = 0,
-	LGDT3305_MPEG_SERIAL = 1,
-};
-
-enum lgdt3305_tp_clock_edge {
-	LGDT3305_TPCLK_RISING_EDGE = 0,
-	LGDT3305_TPCLK_FALLING_EDGE = 1,
-};
-
-enum lgdt3305_tp_valid_polarity {
-	LGDT3305_TP_VALID_LOW = 0,
-	LGDT3305_TP_VALID_HIGH = 1,
-};
-
-enum lgdt_demod_chip_type {
-	LGDT3305 = 0,
-	LGDT3304 = 1,
-};
-
-struct lgdt3305_config {
-	u8 i2c_addr;
-
-	/* user defined IF frequency in KHz */
-	u16 qam_if_khz;
-	u16 vsb_if_khz;
-
-	/* AGC Power reference - defaults are used if left unset */
-	u16 usref_8vsb;   /* default: 0x32c4 */
-	u16 usref_qam64;  /* default: 0x5400 */
-	u16 usref_qam256; /* default: 0x2a80 */
-
-	/* disable i2c repeater - 0:repeater enabled 1:repeater disabled */
-	unsigned int deny_i2c_rptr:1;
-
-	/* spectral inversion - 0:disabled 1:enabled */
-	unsigned int spectral_inversion:1;
-
-	/* use RF AGC loop - 0:disabled 1:enabled */
-	unsigned int rf_agc_loop:1;
-
-	enum lgdt3305_mpeg_mode mpeg_mode;
-	enum lgdt3305_tp_clock_edge tpclk_edge;
-	enum lgdt3305_tp_valid_polarity tpvalid_polarity;
-	enum lgdt_demod_chip_type demod_chip;
-};
-
-#if defined(CONFIG_DVB_LGDT3305) || (defined(CONFIG_DVB_LGDT3305_MODULE) && \
-				     defined(MODULE))
-extern
-struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
-				     struct i2c_adapter *i2c_adap);
-#else
-static inline
-struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
-				     struct i2c_adapter *i2c_adap)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_LGDT3305 */
-
-#endif /* _LGDT3305_H_ */
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
deleted file mode 100644
index e046622..0000000
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ /dev/null
@@ -1,831 +0,0 @@
-/*
- *    Support for LGDT3302 and LGDT3303 - VSB/QAM
- *
- *    Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.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.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/*
- *                      NOTES ABOUT THIS DRIVER
- *
- * This Linux driver supports:
- *   DViCO FusionHDTV 3 Gold-Q
- *   DViCO FusionHDTV 3 Gold-T
- *   DViCO FusionHDTV 5 Gold
- *   DViCO FusionHDTV 5 Lite
- *   DViCO FusionHDTV 5 USB Gold
- *   Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
- *   pcHDTV HD5500
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <asm/byteorder.h>
-
-#include "dvb_frontend.h"
-#include "dvb_math.h"
-#include "lgdt330x_priv.h"
-#include "lgdt330x.h"
-
-/* Use Equalizer Mean Squared Error instead of Phaser Tracker MSE */
-/* #define USE_EQMSE */
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug,"Turn on/off lgdt330x frontend debugging (default:off).");
-#define dprintk(args...) \
-do { \
-if (debug) printk(KERN_DEBUG "lgdt330x: " args); \
-} while (0)
-
-struct lgdt330x_state
-{
-	struct i2c_adapter* i2c;
-
-	/* Configuration settings */
-	const struct lgdt330x_config* config;
-
-	struct dvb_frontend frontend;
-
-	/* Demodulator private data */
-	fe_modulation_t current_modulation;
-	u32 snr; /* Result of last SNR calculation */
-
-	/* Tuner private data */
-	u32 current_frequency;
-};
-
-static int i2c_write_demod_bytes (struct lgdt330x_state* state,
-				  u8 *buf, /* data bytes to send */
-				  int len  /* number of bytes to send */ )
-{
-	struct i2c_msg msg =
-		{ .addr = state->config->demod_address,
-		  .flags = 0,
-		  .buf = buf,
-		  .len = 2 };
-	int i;
-	int err;
-
-	for (i=0; i<len-1; i+=2){
-		if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
-			printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n", __func__, msg.buf[0], msg.buf[1], err);
-			if (err < 0)
-				return err;
-			else
-				return -EREMOTEIO;
-		}
-		msg.buf += 2;
-	}
-	return 0;
-}
-
-/*
- * This routine writes the register (reg) to the demod bus
- * then reads the data returned for (len) bytes.
- */
-
-static int i2c_read_demod_bytes(struct lgdt330x_state *state,
-				enum I2C_REG reg, u8 *buf, int len)
-{
-	u8 wr [] = { reg };
-	struct i2c_msg msg [] = {
-		{ .addr = state->config->demod_address,
-		  .flags = 0, .buf = wr,  .len = 1 },
-		{ .addr = state->config->demod_address,
-		  .flags = I2C_M_RD, .buf = buf, .len = len },
-	};
-	int ret;
-	ret = i2c_transfer(state->i2c, msg, 2);
-	if (ret != 2) {
-		printk(KERN_WARNING "lgdt330x: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __func__, state->config->demod_address, reg, ret);
-		if (ret >= 0)
-			ret = -EIO;
-	} else {
-		ret = 0;
-	}
-	return ret;
-}
-
-/* Software reset */
-static int lgdt3302_SwReset(struct lgdt330x_state* state)
-{
-	u8 ret;
-	u8 reset[] = {
-		IRQ_MASK,
-		0x00 /* bit 6 is active low software reset
-		      *	bits 5-0 are 1 to mask interrupts */
-	};
-
-	ret = i2c_write_demod_bytes(state,
-				    reset, sizeof(reset));
-	if (ret == 0) {
-
-		/* force reset high (inactive) and unmask interrupts */
-		reset[1] = 0x7f;
-		ret = i2c_write_demod_bytes(state,
-					    reset, sizeof(reset));
-	}
-	return ret;
-}
-
-static int lgdt3303_SwReset(struct lgdt330x_state* state)
-{
-	u8 ret;
-	u8 reset[] = {
-		0x02,
-		0x00 /* bit 0 is active low software reset */
-	};
-
-	ret = i2c_write_demod_bytes(state,
-				    reset, sizeof(reset));
-	if (ret == 0) {
-
-		/* force reset high (inactive) */
-		reset[1] = 0x01;
-		ret = i2c_write_demod_bytes(state,
-					    reset, sizeof(reset));
-	}
-	return ret;
-}
-
-static int lgdt330x_SwReset(struct lgdt330x_state* state)
-{
-	switch (state->config->demod_chip) {
-	case LGDT3302:
-		return lgdt3302_SwReset(state);
-	case LGDT3303:
-		return lgdt3303_SwReset(state);
-	default:
-		return -ENODEV;
-	}
-}
-
-static int lgdt330x_init(struct dvb_frontend* fe)
-{
-	/* Hardware reset is done using gpio[0] of cx23880x chip.
-	 * I'd like to do it here, but don't know how to find chip address.
-	 * cx88-cards.c arranges for the reset bit to be inactive (high).
-	 * Maybe there needs to be a callable function in cx88-core or
-	 * the caller of this function needs to do it. */
-
-	/*
-	 * Array of byte pairs <address, value>
-	 * to initialize each different chip
-	 */
-	static u8 lgdt3302_init_data[] = {
-		/* Use 50MHz parameter values from spec sheet since xtal is 50 */
-		/* Change the value of NCOCTFV[25:0] of carrier
-		   recovery center frequency register */
-		VSB_CARRIER_FREQ0, 0x00,
-		VSB_CARRIER_FREQ1, 0x87,
-		VSB_CARRIER_FREQ2, 0x8e,
-		VSB_CARRIER_FREQ3, 0x01,
-		/* Change the TPCLK pin polarity
-		   data is valid on falling clock */
-		DEMUX_CONTROL, 0xfb,
-		/* Change the value of IFBW[11:0] of
-		   AGC IF/RF loop filter bandwidth register */
-		AGC_RF_BANDWIDTH0, 0x40,
-		AGC_RF_BANDWIDTH1, 0x93,
-		AGC_RF_BANDWIDTH2, 0x00,
-		/* Change the value of bit 6, 'nINAGCBY' and
-		   'NSSEL[1:0] of ACG function control register 2 */
-		AGC_FUNC_CTRL2, 0xc6,
-		/* Change the value of bit 6 'RFFIX'
-		   of AGC function control register 3 */
-		AGC_FUNC_CTRL3, 0x40,
-		/* Set the value of 'INLVTHD' register 0x2a/0x2c
-		   to 0x7fe */
-		AGC_DELAY0, 0x07,
-		AGC_DELAY2, 0xfe,
-		/* Change the value of IAGCBW[15:8]
-		   of inner AGC loop filter bandwidth */
-		AGC_LOOP_BANDWIDTH0, 0x08,
-		AGC_LOOP_BANDWIDTH1, 0x9a
-	};
-
-	static u8 lgdt3303_init_data[] = {
-		0x4c, 0x14
-	};
-
-	static u8 flip_1_lgdt3303_init_data[] = {
-		0x4c, 0x14,
-		0x87, 0xf3
-	};
-
-	static u8 flip_2_lgdt3303_init_data[] = {
-		0x4c, 0x14,
-		0x87, 0xda
-	};
-
-	struct lgdt330x_state* state = fe->demodulator_priv;
-	char  *chip_name;
-	int    err;
-
-	switch (state->config->demod_chip) {
-	case LGDT3302:
-		chip_name = "LGDT3302";
-		err = i2c_write_demod_bytes(state, lgdt3302_init_data,
-					    sizeof(lgdt3302_init_data));
-		break;
-	case LGDT3303:
-		chip_name = "LGDT3303";
-		switch (state->config->clock_polarity_flip) {
-		case 2:
-			err = i2c_write_demod_bytes(state,
-					flip_2_lgdt3303_init_data,
-					sizeof(flip_2_lgdt3303_init_data));
-			break;
-		case 1:
-			err = i2c_write_demod_bytes(state,
-					flip_1_lgdt3303_init_data,
-					sizeof(flip_1_lgdt3303_init_data));
-			break;
-		case 0:
-		default:
-			err = i2c_write_demod_bytes(state, lgdt3303_init_data,
-						    sizeof(lgdt3303_init_data));
-		}
-		break;
-	default:
-		chip_name = "undefined";
-		printk (KERN_WARNING "Only LGDT3302 and LGDT3303 are supported chips.\n");
-		err = -ENODEV;
-	}
-	dprintk("%s entered as %s\n", __func__, chip_name);
-	if (err < 0)
-		return err;
-	return lgdt330x_SwReset(state);
-}
-
-static int lgdt330x_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	*ber = 0; /* Not supplied by the demod chips */
-	return 0;
-}
-
-static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	struct lgdt330x_state* state = fe->demodulator_priv;
-	int err;
-	u8 buf[2];
-
-	*ucblocks = 0;
-
-	switch (state->config->demod_chip) {
-	case LGDT3302:
-		err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1,
-					   buf, sizeof(buf));
-		break;
-	case LGDT3303:
-		err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1,
-					   buf, sizeof(buf));
-		break;
-	default:
-		printk(KERN_WARNING
-		       "Only LGDT3302 and LGDT3303 are supported chips.\n");
-		err = -ENODEV;
-	}
-	if (err < 0)
-		return err;
-
-	*ucblocks = (buf[0] << 8) | buf[1];
-	return 0;
-}
-
-static int lgdt330x_set_parameters(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	/*
-	 * Array of byte pairs <address, value>
-	 * to initialize 8VSB for lgdt3303 chip 50 MHz IF
-	 */
-	static u8 lgdt3303_8vsb_44_data[] = {
-		0x04, 0x00,
-		0x0d, 0x40,
-		0x0e, 0x87,
-		0x0f, 0x8e,
-		0x10, 0x01,
-		0x47, 0x8b };
-
-	/*
-	 * Array of byte pairs <address, value>
-	 * to initialize QAM for lgdt3303 chip
-	 */
-	static u8 lgdt3303_qam_data[] = {
-		0x04, 0x00,
-		0x0d, 0x00,
-		0x0e, 0x00,
-		0x0f, 0x00,
-		0x10, 0x00,
-		0x51, 0x63,
-		0x47, 0x66,
-		0x48, 0x66,
-		0x4d, 0x1a,
-		0x49, 0x08,
-		0x4a, 0x9b };
-
-	struct lgdt330x_state* state = fe->demodulator_priv;
-
-	static u8 top_ctrl_cfg[]   = { TOP_CONTROL, 0x03 };
-
-	int err = 0;
-	/* Change only if we are actually changing the modulation */
-	if (state->current_modulation != p->modulation) {
-		switch (p->modulation) {
-		case VSB_8:
-			dprintk("%s: VSB_8 MODE\n", __func__);
-
-			/* Select VSB mode */
-			top_ctrl_cfg[1] = 0x03;
-
-			/* Select ANT connector if supported by card */
-			if (state->config->pll_rf_set)
-				state->config->pll_rf_set(fe, 1);
-
-			if (state->config->demod_chip == LGDT3303) {
-				err = i2c_write_demod_bytes(state, lgdt3303_8vsb_44_data,
-							    sizeof(lgdt3303_8vsb_44_data));
-			}
-			break;
-
-		case QAM_64:
-			dprintk("%s: QAM_64 MODE\n", __func__);
-
-			/* Select QAM_64 mode */
-			top_ctrl_cfg[1] = 0x00;
-
-			/* Select CABLE connector if supported by card */
-			if (state->config->pll_rf_set)
-				state->config->pll_rf_set(fe, 0);
-
-			if (state->config->demod_chip == LGDT3303) {
-				err = i2c_write_demod_bytes(state, lgdt3303_qam_data,
-											sizeof(lgdt3303_qam_data));
-			}
-			break;
-
-		case QAM_256:
-			dprintk("%s: QAM_256 MODE\n", __func__);
-
-			/* Select QAM_256 mode */
-			top_ctrl_cfg[1] = 0x01;
-
-			/* Select CABLE connector if supported by card */
-			if (state->config->pll_rf_set)
-				state->config->pll_rf_set(fe, 0);
-
-			if (state->config->demod_chip == LGDT3303) {
-				err = i2c_write_demod_bytes(state, lgdt3303_qam_data,
-											sizeof(lgdt3303_qam_data));
-			}
-			break;
-		default:
-			printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __func__, p->modulation);
-			return -1;
-		}
-		if (err < 0)
-			printk(KERN_WARNING "lgdt330x: %s: error blasting "
-			       "bytes to lgdt3303 for modulation type(%d)\n",
-			       __func__, p->modulation);
-
-		/*
-		 * select serial or parallel MPEG harware interface
-		 * Serial:   0x04 for LGDT3302 or 0x40 for LGDT3303
-		 * Parallel: 0x00
-		 */
-		top_ctrl_cfg[1] |= state->config->serial_mpeg;
-
-		/* Select the requested mode */
-		i2c_write_demod_bytes(state, top_ctrl_cfg,
-				      sizeof(top_ctrl_cfg));
-		if (state->config->set_ts_params)
-			state->config->set_ts_params(fe, 0);
-		state->current_modulation = p->modulation;
-	}
-
-	/* Tune to the specified frequency */
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	/* Keep track of the new frequency */
-	/* FIXME this is the wrong way to do this...           */
-	/* The tuner is shared with the video4linux analog API */
-	state->current_frequency = p->frequency;
-
-	lgdt330x_SwReset(state);
-	return 0;
-}
-
-static int lgdt330x_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct lgdt330x_state *state = fe->demodulator_priv;
-	p->frequency = state->current_frequency;
-	return 0;
-}
-
-static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct lgdt330x_state* state = fe->demodulator_priv;
-	u8 buf[3];
-
-	*status = 0; /* Reset status result */
-
-	/* AGC status register */
-	i2c_read_demod_bytes(state, AGC_STATUS, buf, 1);
-	dprintk("%s: AGC_STATUS = 0x%02x\n", __func__, buf[0]);
-	if ((buf[0] & 0x0c) == 0x8){
-		/* Test signal does not exist flag */
-		/* as well as the AGC lock flag.   */
-		*status |= FE_HAS_SIGNAL;
-	}
-
-	/*
-	 * You must set the Mask bits to 1 in the IRQ_MASK in order
-	 * to see that status bit in the IRQ_STATUS register.
-	 * This is done in SwReset();
-	 */
-	/* signal status */
-	i2c_read_demod_bytes(state, TOP_CONTROL, buf, sizeof(buf));
-	dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __func__, buf[0], buf[1], buf[2]);
-
-
-	/* sync status */
-	if ((buf[2] & 0x03) == 0x01) {
-		*status |= FE_HAS_SYNC;
-	}
-
-	/* FEC error status */
-	if ((buf[2] & 0x0c) == 0x08) {
-		*status |= FE_HAS_LOCK;
-		*status |= FE_HAS_VITERBI;
-	}
-
-	/* Carrier Recovery Lock Status Register */
-	i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1);
-	dprintk("%s: CARRIER_LOCK = 0x%02x\n", __func__, buf[0]);
-	switch (state->current_modulation) {
-	case QAM_256:
-	case QAM_64:
-		/* Need to understand why there are 3 lock levels here */
-		if ((buf[0] & 0x07) == 0x07)
-			*status |= FE_HAS_CARRIER;
-		break;
-	case VSB_8:
-		if ((buf[0] & 0x80) == 0x80)
-			*status |= FE_HAS_CARRIER;
-		break;
-	default:
-		printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __func__);
-	}
-
-	return 0;
-}
-
-static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct lgdt330x_state* state = fe->demodulator_priv;
-	int err;
-	u8 buf[3];
-
-	*status = 0; /* Reset status result */
-
-	/* lgdt3303 AGC status register */
-	err = i2c_read_demod_bytes(state, 0x58, buf, 1);
-	if (err < 0)
-		return err;
-
-	dprintk("%s: AGC_STATUS = 0x%02x\n", __func__, buf[0]);
-	if ((buf[0] & 0x21) == 0x01){
-		/* Test input signal does not exist flag */
-		/* as well as the AGC lock flag.   */
-		*status |= FE_HAS_SIGNAL;
-	}
-
-	/* Carrier Recovery Lock Status Register */
-	i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1);
-	dprintk("%s: CARRIER_LOCK = 0x%02x\n", __func__, buf[0]);
-	switch (state->current_modulation) {
-	case QAM_256:
-	case QAM_64:
-		/* Need to understand why there are 3 lock levels here */
-		if ((buf[0] & 0x07) == 0x07)
-			*status |= FE_HAS_CARRIER;
-		else
-			break;
-		i2c_read_demod_bytes(state, 0x8a, buf, 1);
-		if ((buf[0] & 0x04) == 0x04)
-			*status |= FE_HAS_SYNC;
-		if ((buf[0] & 0x01) == 0x01)
-			*status |= FE_HAS_LOCK;
-		if ((buf[0] & 0x08) == 0x08)
-			*status |= FE_HAS_VITERBI;
-		break;
-	case VSB_8:
-		if ((buf[0] & 0x80) == 0x80)
-			*status |= FE_HAS_CARRIER;
-		else
-			break;
-		i2c_read_demod_bytes(state, 0x38, buf, 1);
-		if ((buf[0] & 0x02) == 0x00)
-			*status |= FE_HAS_SYNC;
-		if ((buf[0] & 0x01) == 0x01) {
-			*status |= FE_HAS_LOCK;
-			*status |= FE_HAS_VITERBI;
-		}
-		break;
-	default:
-		printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __func__);
-	}
-	return 0;
-}
-
-/* Calculate SNR estimation (scaled by 2^24)
-
-   8-VSB SNR equations from LGDT3302 and LGDT3303 datasheets, QAM
-   equations from LGDT3303 datasheet.  VSB is the same between the '02
-   and '03, so maybe QAM is too?  Perhaps someone with a newer datasheet
-   that has QAM information could verify?
-
-   For 8-VSB: (two ways, take your pick)
-   LGDT3302:
-     SNR_EQ = 10 * log10(25 * 24^2 / EQ_MSE)
-   LGDT3303:
-     SNR_EQ = 10 * log10(25 * 32^2 / EQ_MSE)
-   LGDT3302 & LGDT3303:
-     SNR_PT = 10 * log10(25 * 32^2 / PT_MSE)  (we use this one)
-   For 64-QAM:
-     SNR    = 10 * log10( 688128   / MSEQAM)
-   For 256-QAM:
-     SNR    = 10 * log10( 696320   / MSEQAM)
-
-   We re-write the snr equation as:
-     SNR * 2^24 = 10*(c - intlog10(MSE))
-   Where for 256-QAM, c = log10(696320) * 2^24, and so on. */
-
-static u32 calculate_snr(u32 mse, u32 c)
-{
-	if (mse == 0) /* No signal */
-		return 0;
-
-	mse = intlog10(mse);
-	if (mse > c) {
-		/* Negative SNR, which is possible, but realisticly the
-		demod will lose lock before the signal gets this bad.  The
-		API only allows for unsigned values, so just return 0 */
-		return 0;
-	}
-	return 10*(c - mse);
-}
-
-static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
-	u8 buf[5];	/* read data buffer */
-	u32 noise;	/* noise value */
-	u32 c;		/* per-modulation SNR calculation constant */
-
-	switch(state->current_modulation) {
-	case VSB_8:
-		i2c_read_demod_bytes(state, LGDT3302_EQPH_ERR0, buf, 5);
-#ifdef USE_EQMSE
-		/* Use Equalizer Mean-Square Error Register */
-		/* SNR for ranges from -15.61 to +41.58 */
-		noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
-		c = 69765745; /* log10(25*24^2)*2^24 */
-#else
-		/* Use Phase Tracker Mean-Square Error Register */
-		/* SNR for ranges from -13.11 to +44.08 */
-		noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
-		c = 73957994; /* log10(25*32^2)*2^24 */
-#endif
-		break;
-	case QAM_64:
-	case QAM_256:
-		i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
-		noise = ((buf[0] & 3) << 8) | buf[1];
-		c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
-		/* log10(688128)*2^24 and log10(696320)*2^24 */
-		break;
-	default:
-		printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n",
-		       __func__);
-		return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
-	}
-
-	state->snr = calculate_snr(noise, c);
-	*snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
-
-	dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise,
-		state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
-
-	return 0;
-}
-
-static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
-	u8 buf[5];	/* read data buffer */
-	u32 noise;	/* noise value */
-	u32 c;		/* per-modulation SNR calculation constant */
-
-	switch(state->current_modulation) {
-	case VSB_8:
-		i2c_read_demod_bytes(state, LGDT3303_EQPH_ERR0, buf, 5);
-#ifdef USE_EQMSE
-		/* Use Equalizer Mean-Square Error Register */
-		/* SNR for ranges from -16.12 to +44.08 */
-		noise = ((buf[0] & 0x78) << 13) | (buf[1] << 8) | buf[2];
-		c = 73957994; /* log10(25*32^2)*2^24 */
-#else
-		/* Use Phase Tracker Mean-Square Error Register */
-		/* SNR for ranges from -13.11 to +44.08 */
-		noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4];
-		c = 73957994; /* log10(25*32^2)*2^24 */
-#endif
-		break;
-	case QAM_64:
-	case QAM_256:
-		i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
-		noise = (buf[0] << 8) | buf[1];
-		c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
-		/* log10(688128)*2^24 and log10(696320)*2^24 */
-		break;
-	default:
-		printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n",
-		       __func__);
-		return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
-	}
-
-	state->snr = calculate_snr(noise, c);
-	*snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
-
-	dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise,
-		state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
-
-	return 0;
-}
-
-static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-{
-	/* Calculate Strength from SNR up to 35dB */
-	/* Even though the SNR can go higher than 35dB, there is some comfort */
-	/* factor in having a range of strong signals that can show at 100%   */
-	struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
-	u16 snr;
-	int ret;
-
-	ret = fe->ops.read_snr(fe, &snr);
-	if (ret != 0)
-		return ret;
-	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
-	/* scale the range 0 - 35*2^24 into 0 - 65535 */
-	if (state->snr >= 8960 * 0x10000)
-		*strength = 0xffff;
-	else
-		*strength = state->snr / 8960;
-
-	return 0;
-}
-
-static int lgdt330x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings)
-{
-	/* I have no idea about this - it may not be needed */
-	fe_tune_settings->min_delay_ms = 500;
-	fe_tune_settings->step_size = 0;
-	fe_tune_settings->max_drift = 0;
-	return 0;
-}
-
-static void lgdt330x_release(struct dvb_frontend* fe)
-{
-	struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops lgdt3302_ops;
-static struct dvb_frontend_ops lgdt3303_ops;
-
-struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
-				     struct i2c_adapter* i2c)
-{
-	struct lgdt330x_state* state = NULL;
-	u8 buf[1];
-
-	/* Allocate memory for the internal state */
-	state = kzalloc(sizeof(struct lgdt330x_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* Setup the state */
-	state->config = config;
-	state->i2c = i2c;
-
-	/* Create dvb_frontend */
-	switch (config->demod_chip) {
-	case LGDT3302:
-		memcpy(&state->frontend.ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
-		break;
-	case LGDT3303:
-		memcpy(&state->frontend.ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops));
-		break;
-	default:
-		goto error;
-	}
-	state->frontend.demodulator_priv = state;
-
-	/* Verify communication with demod chip */
-	if (i2c_read_demod_bytes(state, 2, buf, 1))
-		goto error;
-
-	state->current_frequency = -1;
-	state->current_modulation = -1;
-
-	return &state->frontend;
-
-error:
-	kfree(state);
-	dprintk("%s: ERROR\n",__func__);
-	return NULL;
-}
-
-static struct dvb_frontend_ops lgdt3302_ops = {
-	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
-	.info = {
-		.name= "LG Electronics LGDT3302 VSB/QAM Frontend",
-		.frequency_min= 54000000,
-		.frequency_max= 858000000,
-		.frequency_stepsize= 62500,
-		.symbol_rate_min    = 5056941,	/* QAM 64 */
-		.symbol_rate_max    = 10762000,	/* VSB 8  */
-		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
-	},
-	.init                 = lgdt330x_init,
-	.set_frontend         = lgdt330x_set_parameters,
-	.get_frontend         = lgdt330x_get_frontend,
-	.get_tune_settings    = lgdt330x_get_tune_settings,
-	.read_status          = lgdt3302_read_status,
-	.read_ber             = lgdt330x_read_ber,
-	.read_signal_strength = lgdt330x_read_signal_strength,
-	.read_snr             = lgdt3302_read_snr,
-	.read_ucblocks        = lgdt330x_read_ucblocks,
-	.release              = lgdt330x_release,
-};
-
-static struct dvb_frontend_ops lgdt3303_ops = {
-	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
-	.info = {
-		.name= "LG Electronics LGDT3303 VSB/QAM Frontend",
-		.frequency_min= 54000000,
-		.frequency_max= 858000000,
-		.frequency_stepsize= 62500,
-		.symbol_rate_min    = 5056941,	/* QAM 64 */
-		.symbol_rate_max    = 10762000,	/* VSB 8  */
-		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
-	},
-	.init                 = lgdt330x_init,
-	.set_frontend         = lgdt330x_set_parameters,
-	.get_frontend         = lgdt330x_get_frontend,
-	.get_tune_settings    = lgdt330x_get_tune_settings,
-	.read_status          = lgdt3303_read_status,
-	.read_ber             = lgdt330x_read_ber,
-	.read_signal_strength = lgdt330x_read_signal_strength,
-	.read_snr             = lgdt3303_read_snr,
-	.read_ucblocks        = lgdt330x_read_ucblocks,
-	.release              = lgdt330x_release,
-};
-
-MODULE_DESCRIPTION("LGDT330X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
-MODULE_AUTHOR("Wilson Michaels");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(lgdt330x_attach);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/frontends/lgdt330x.h b/drivers/media/dvb/frontends/lgdt330x.h
deleted file mode 100644
index 9012504..0000000
--- a/drivers/media/dvb/frontends/lgdt330x.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- *    Support for LGDT3302 and LGDT3303 - VSB/QAM
- *
- *    Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.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.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef LGDT330X_H
-#define LGDT330X_H
-
-#include <linux/dvb/frontend.h>
-
-typedef enum lg_chip_t {
-		UNDEFINED,
-		LGDT3302,
-		LGDT3303
-}lg_chip_type;
-
-struct lgdt330x_config
-{
-	/* The demodulator's i2c address */
-	u8 demod_address;
-
-	/* LG demodulator chip LGDT3302 or LGDT3303 */
-	lg_chip_type demod_chip;
-
-	/* MPEG hardware interface - 0:parallel 1:serial */
-	int serial_mpeg;
-
-	/* PLL interface */
-	int (*pll_rf_set) (struct dvb_frontend* fe, int index);
-
-	/* Need to set device param for start_dma */
-	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
-
-	/* Flip the polarity of the mpeg data transfer clock using alternate init data
-	 * This option applies ONLY to LGDT3303 - 0:disabled (default) 1:enabled */
-	int clock_polarity_flip;
-};
-
-#if defined(CONFIG_DVB_LGDT330X) || (defined(CONFIG_DVB_LGDT330X_MODULE) && defined(MODULE))
-extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
-					    struct i2c_adapter* i2c);
-#else
-static inline struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
-					    struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_LGDT330X
-
-#endif /* LGDT330X_H */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/frontends/lgdt330x_priv.h b/drivers/media/dvb/frontends/lgdt330x_priv.h
deleted file mode 100644
index 38c7669..0000000
--- a/drivers/media/dvb/frontends/lgdt330x_priv.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- *    Support for LGDT3302 and LGDT3303 - VSB/QAM
- *
- *    Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.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.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef _LGDT330X_PRIV_
-#define _LGDT330X_PRIV_
-
-/* i2c control register addresses */
-enum I2C_REG {
-	TOP_CONTROL= 0x00,
-	IRQ_MASK= 0x01,
-	IRQ_STATUS= 0x02,
-	VSB_CARRIER_FREQ0= 0x16,
-	VSB_CARRIER_FREQ1= 0x17,
-	VSB_CARRIER_FREQ2= 0x18,
-	VSB_CARRIER_FREQ3= 0x19,
-	CARRIER_MSEQAM1= 0x1a,
-	CARRIER_MSEQAM2= 0x1b,
-	CARRIER_LOCK= 0x1c,
-	TIMING_RECOVERY= 0x1d,
-	AGC_DELAY0= 0x2a,
-	AGC_DELAY1= 0x2b,
-	AGC_DELAY2= 0x2c,
-	AGC_RF_BANDWIDTH0= 0x2d,
-	AGC_RF_BANDWIDTH1= 0x2e,
-	AGC_RF_BANDWIDTH2= 0x2f,
-	AGC_LOOP_BANDWIDTH0= 0x30,
-	AGC_LOOP_BANDWIDTH1= 0x31,
-	AGC_FUNC_CTRL1= 0x32,
-	AGC_FUNC_CTRL2= 0x33,
-	AGC_FUNC_CTRL3= 0x34,
-	AGC_RFIF_ACC0= 0x39,
-	AGC_RFIF_ACC1= 0x3a,
-	AGC_RFIF_ACC2= 0x3b,
-	AGC_STATUS= 0x3f,
-	SYNC_STATUS_VSB= 0x43,
-	DEMUX_CONTROL= 0x66,
-	LGDT3302_EQPH_ERR0= 0x47,
-	LGDT3302_EQ_ERR1= 0x48,
-	LGDT3302_EQ_ERR2= 0x49,
-	LGDT3302_PH_ERR1= 0x4a,
-	LGDT3302_PH_ERR2= 0x4b,
-	LGDT3302_PACKET_ERR_COUNTER1= 0x6a,
-	LGDT3302_PACKET_ERR_COUNTER2= 0x6b,
-	LGDT3303_EQPH_ERR0= 0x6e,
-	LGDT3303_EQ_ERR1= 0x6f,
-	LGDT3303_EQ_ERR2= 0x70,
-	LGDT3303_PH_ERR1= 0x71,
-	LGDT3303_PH_ERR2= 0x72,
-	LGDT3303_PACKET_ERR_COUNTER1= 0x8b,
-	LGDT3303_PACKET_ERR_COUNTER2= 0x8c,
-};
-
-#endif /* _LGDT330X_PRIV_ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/frontends/lgs8gl5.c b/drivers/media/dvb/frontends/lgs8gl5.c
deleted file mode 100644
index 2cec804..0000000
--- a/drivers/media/dvb/frontends/lgs8gl5.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
-    Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
-
-    Copyright (C) 2008 Sirius International (Hong Kong) Limited
-	Timothy Lee <timothy.lee@siriushk.com>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include "dvb_frontend.h"
-#include "lgs8gl5.h"
-
-
-#define REG_RESET		0x02
-#define REG_RESET_OFF			0x01
-#define REG_03			0x03
-#define REG_04			0x04
-#define REG_07			0x07
-#define REG_09			0x09
-#define REG_0A			0x0a
-#define REG_0B			0x0b
-#define REG_0C			0x0c
-#define REG_37			0x37
-#define REG_STRENGTH		0x4b
-#define REG_STRENGTH_MASK		0x7f
-#define REG_STRENGTH_CARRIER		0x80
-#define REG_INVERSION		0x7c
-#define REG_INVERSION_ON		0x80
-#define REG_7D			0x7d
-#define REG_7E			0x7e
-#define REG_A2			0xa2
-#define REG_STATUS		0xa4
-#define REG_STATUS_SYNC		0x04
-#define REG_STATUS_LOCK		0x01
-
-
-struct lgs8gl5_state {
-	struct i2c_adapter *i2c;
-	const struct lgs8gl5_config *config;
-	struct dvb_frontend frontend;
-};
-
-
-static int debug;
-#define dprintk(args...) \
-	do { \
-		if (debug) \
-			printk(KERN_DEBUG "lgs8gl5: " args); \
-	} while (0)
-
-
-/* Writes into demod's register */
-static int
-lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
-{
-	int ret;
-	u8 buf[] = {reg, data};
-	struct i2c_msg msg = {
-		.addr  = state->config->demod_address,
-		.flags = 0,
-		.buf   = buf,
-		.len   = 2
-	};
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-	if (ret != 1)
-		dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n",
-			__func__, reg, data, ret);
-	return (ret != 1) ? -1 : 0;
-}
-
-
-/* Reads from demod's register */
-static int
-lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg)
-{
-	int ret;
-	u8 b0[] = {reg};
-	u8 b1[] = {0};
-	struct i2c_msg msg[2] = {
-		{
-			.addr  = state->config->demod_address,
-			.flags = 0,
-			.buf   = b0,
-			.len   = 1
-		},
-		{
-			.addr  = state->config->demod_address,
-			.flags = I2C_M_RD,
-			.buf   = b1,
-			.len   = 1
-		}
-	};
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-	if (ret != 2)
-		return -EIO;
-
-	return b1[0];
-}
-
-
-static int
-lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
-{
-	lgs8gl5_read_reg(state, reg);
-	lgs8gl5_write_reg(state, reg, data);
-	return 0;
-}
-
-
-/* Writes into alternate device's register */
-/* TODO:  Find out what that device is for! */
-static int
-lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
-{
-	int ret;
-	u8 b0[] = {reg};
-	u8 b1[] = {0};
-	u8 b2[] = {reg, data};
-	struct i2c_msg msg[3] = {
-		{
-			.addr  = state->config->demod_address + 2,
-			.flags = 0,
-			.buf   = b0,
-			.len   = 1
-		},
-		{
-			.addr  = state->config->demod_address + 2,
-			.flags = I2C_M_RD,
-			.buf   = b1,
-			.len   = 1
-		},
-		{
-			.addr  = state->config->demod_address + 2,
-			.flags = 0,
-			.buf   = b2,
-			.len   = 2
-		},
-	};
-
-	ret = i2c_transfer(state->i2c, msg, 3);
-	return (ret != 3) ? -1 : 0;
-}
-
-
-static void
-lgs8gl5_soft_reset(struct lgs8gl5_state *state)
-{
-	u8 val;
-
-	dprintk("%s\n", __func__);
-
-	val = lgs8gl5_read_reg(state, REG_RESET);
-	lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF);
-	lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF);
-	msleep(5);
-}
-
-
-/* Starts demodulation */
-static void
-lgs8gl5_start_demod(struct lgs8gl5_state *state)
-{
-	u8  val;
-	int n;
-
-	dprintk("%s\n", __func__);
-
-	lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
-	lgs8gl5_soft_reset(state);
-	lgs8gl5_update_reg(state, REG_07, 0x10);
-	lgs8gl5_update_reg(state, REG_07, 0x10);
-	lgs8gl5_write_reg(state, REG_09, 0x0e);
-	lgs8gl5_write_reg(state, REG_0A, 0xe5);
-	lgs8gl5_write_reg(state, REG_0B, 0x35);
-	lgs8gl5_write_reg(state, REG_0C, 0x30);
-
-	lgs8gl5_update_reg(state, REG_03, 0x00);
-	lgs8gl5_update_reg(state, REG_7E, 0x01);
-	lgs8gl5_update_alt_reg(state, 0xc5, 0x00);
-	lgs8gl5_update_reg(state, REG_04, 0x02);
-	lgs8gl5_update_reg(state, REG_37, 0x01);
-	lgs8gl5_soft_reset(state);
-
-	/* Wait for carrier */
-	for (n = 0;  n < 10;  n++) {
-		val = lgs8gl5_read_reg(state, REG_STRENGTH);
-		dprintk("Wait for carrier[%d] 0x%02X\n", n, val);
-		if (val & REG_STRENGTH_CARRIER)
-			break;
-		msleep(4);
-	}
-	if (!(val & REG_STRENGTH_CARRIER))
-		return;
-
-	/* Wait for lock */
-	for (n = 0;  n < 20;  n++) {
-		val = lgs8gl5_read_reg(state, REG_STATUS);
-		dprintk("Wait for lock[%d] 0x%02X\n", n, val);
-		if (val & REG_STATUS_LOCK)
-			break;
-		msleep(12);
-	}
-	if (!(val & REG_STATUS_LOCK))
-		return;
-
-	lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2));
-	lgs8gl5_soft_reset(state);
-}
-
-
-static int
-lgs8gl5_init(struct dvb_frontend *fe)
-{
-	struct lgs8gl5_state *state = fe->demodulator_priv;
-
-	dprintk("%s\n", __func__);
-
-	lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
-	lgs8gl5_soft_reset(state);
-	lgs8gl5_update_reg(state, REG_07, 0x10);
-	lgs8gl5_update_reg(state, REG_07, 0x10);
-	lgs8gl5_write_reg(state, REG_09, 0x0e);
-	lgs8gl5_write_reg(state, REG_0A, 0xe5);
-	lgs8gl5_write_reg(state, REG_0B, 0x35);
-	lgs8gl5_write_reg(state, REG_0C, 0x30);
-
-	return 0;
-}
-
-
-static int
-lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct lgs8gl5_state *state = fe->demodulator_priv;
-	u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
-	u8 flags = lgs8gl5_read_reg(state, REG_STATUS);
-
-	*status = 0;
-
-	if ((level & REG_STRENGTH_MASK) > 0)
-		*status |= FE_HAS_SIGNAL;
-	if (level & REG_STRENGTH_CARRIER)
-		*status |= FE_HAS_CARRIER;
-	if (flags & REG_STATUS_SYNC)
-		*status |= FE_HAS_SYNC;
-	if (flags & REG_STATUS_LOCK)
-		*status |= FE_HAS_LOCK;
-
-	return 0;
-}
-
-
-static int
-lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	*ber = 0;
-
-	return 0;
-}
-
-
-static int
-lgs8gl5_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength)
-{
-	struct lgs8gl5_state *state = fe->demodulator_priv;
-	u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
-	*signal_strength = (level & REG_STRENGTH_MASK) << 8;
-
-	return 0;
-}
-
-
-static int
-lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct lgs8gl5_state *state = fe->demodulator_priv;
-	u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
-	*snr = (level & REG_STRENGTH_MASK) << 8;
-
-	return 0;
-}
-
-
-static int
-lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	*ucblocks = 0;
-
-	return 0;
-}
-
-
-static int
-lgs8gl5_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct lgs8gl5_state *state = fe->demodulator_priv;
-
-	dprintk("%s\n", __func__);
-
-	if (p->bandwidth_hz != 8000000)
-		return -EINVAL;
-
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	/* lgs8gl5_set_inversion(state, p->inversion); */
-
-	lgs8gl5_start_demod(state);
-
-	return 0;
-}
-
-
-static int
-lgs8gl5_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct lgs8gl5_state *state = fe->demodulator_priv;
-	u8 inv = lgs8gl5_read_reg(state, REG_INVERSION);
-
-	p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF;
-
-	p->code_rate_HP = FEC_1_2;
-	p->code_rate_LP = FEC_7_8;
-	p->guard_interval = GUARD_INTERVAL_1_32;
-	p->transmission_mode = TRANSMISSION_MODE_2K;
-	p->modulation = QAM_64;
-	p->hierarchy = HIERARCHY_NONE;
-	p->bandwidth_hz = 8000000;
-
-	return 0;
-}
-
-
-static int
-lgs8gl5_get_tune_settings(struct dvb_frontend *fe,
-		struct dvb_frontend_tune_settings *fesettings)
-{
-	fesettings->min_delay_ms = 240;
-	fesettings->step_size    = 0;
-	fesettings->max_drift    = 0;
-	return 0;
-}
-
-
-static void
-lgs8gl5_release(struct dvb_frontend *fe)
-{
-	struct lgs8gl5_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-
-static struct dvb_frontend_ops lgs8gl5_ops;
-
-
-struct dvb_frontend*
-lgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c)
-{
-	struct lgs8gl5_state *state = NULL;
-
-	dprintk("%s\n", __func__);
-
-	/* Allocate memory for the internal state */
-	state = kzalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* Setup the state */
-	state->config = config;
-	state->i2c    = i2c;
-
-	/* Check if the demod is there */
-	if (lgs8gl5_read_reg(state, REG_RESET) < 0)
-		goto error;
-
-	/* Create dvb_frontend */
-	memcpy(&state->frontend.ops, &lgs8gl5_ops,
-		sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(lgs8gl5_attach);
-
-
-static struct dvb_frontend_ops lgs8gl5_ops = {
-	.delsys = { SYS_DMBTH },
-	.info = {
-		.name			= "Legend Silicon LGS-8GL5 DMB-TH",
-		.frequency_min		= 474000000,
-		.frequency_max		= 858000000,
-		.frequency_stepsize	= 10000,
-		.frequency_tolerance	= 0,
-		.caps = FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
-			FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_BANDWIDTH_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_HIERARCHY_AUTO |
-			FE_CAN_RECOVER
-	},
-
-	.release = lgs8gl5_release,
-
-	.init = lgs8gl5_init,
-
-	.set_frontend = lgs8gl5_set_frontend,
-	.get_frontend = lgs8gl5_get_frontend,
-	.get_tune_settings = lgs8gl5_get_tune_settings,
-
-	.read_status = lgs8gl5_read_status,
-	.read_ber = lgs8gl5_read_ber,
-	.read_signal_strength = lgs8gl5_read_signal_strength,
-	.read_snr = lgs8gl5_read_snr,
-	.read_ucblocks = lgs8gl5_read_ucblocks,
-};
-
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver");
-MODULE_AUTHOR("Timothy Lee");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lgs8gl5.h b/drivers/media/dvb/frontends/lgs8gl5.h
deleted file mode 100644
index d1417678..0000000
--- a/drivers/media/dvb/frontends/lgs8gl5.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-    Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
-
-    Copyright (C) 2008 Sirius International (Hong Kong) Limited
-	Timothy Lee <timothy.lee@siriushk.com>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef LGS8GL5_H
-#define LGS8GL5_H
-
-#include <linux/dvb/frontend.h>
-
-struct lgs8gl5_config {
-	/* the demodulator's i2c address */
-	u8 demod_address;
-};
-
-#if defined(CONFIG_DVB_LGS8GL5) || \
-	(defined(CONFIG_DVB_LGS8GL5_MODULE) && defined(MODULE))
-extern struct dvb_frontend *lgs8gl5_attach(
-	const struct lgs8gl5_config *config, struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *lgs8gl5_attach(
-	const struct lgs8gl5_config *config, struct i2c_adapter *i2c) {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_LGS8GL5 */
-
-#endif /* LGS8GL5_H */
diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c
deleted file mode 100644
index c2ea274..0000000
--- a/drivers/media/dvb/frontends/lgs8gxx.c
+++ /dev/null
@@ -1,1075 +0,0 @@
-/*
- *    Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
- *    LGS8913, LGS8GL5, LGS8G75
- *    experimental support LGS8G42, LGS8G52
- *
- *    Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
- *    Copyright (C) 2008 Sirius International (Hong Kong) Limited
- *    Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <asm/div64.h>
-#include <linux/firmware.h>
-
-#include "dvb_frontend.h"
-
-#include "lgs8gxx.h"
-#include "lgs8gxx_priv.h"
-
-#define dprintk(args...) \
-	do { \
-		if (debug) \
-			printk(KERN_DEBUG "lgs8gxx: " args); \
-	} while (0)
-
-static int debug;
-static int fake_signal_str = 1;
-
-#define LGS8GXX_FIRMWARE "lgs8g75.fw"
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-module_param(fake_signal_str, int, 0644);
-MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
-"Signal strength calculation is slow.(default:on).");
-
-/* LGS8GXX internal helper functions */
-
-static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
-{
-	int ret;
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
-
-	msg.addr = priv->config->demod_address;
-	if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
-		msg.addr += 0x02;
-
-	if (debug >= 2)
-		dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data);
-
-	ret = i2c_transfer(priv->i2c, &msg, 1);
-
-	if (ret != 1)
-		dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
-			__func__, reg, data, ret);
-
-	return (ret != 1) ? -1 : 0;
-}
-
-static int lgs8gxx_read_reg(struct lgs8gxx_state *priv, u8 reg, u8 *p_data)
-{
-	int ret;
-	u8 dev_addr;
-
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
-	struct i2c_msg msg[] = {
-		{ .flags = 0, .buf = b0, .len = 1 },
-		{ .flags = I2C_M_RD, .buf = b1, .len = 1 },
-	};
-
-	dev_addr = priv->config->demod_address;
-	if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
-		dev_addr += 0x02;
-	msg[1].addr =  msg[0].addr = dev_addr;
-
-	ret = i2c_transfer(priv->i2c, msg, 2);
-	if (ret != 2) {
-		dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret);
-		return -1;
-	}
-
-	*p_data = b1[0];
-	if (debug >= 2)
-		dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, b1[0]);
-	return 0;
-}
-
-static int lgs8gxx_soft_reset(struct lgs8gxx_state *priv)
-{
-	lgs8gxx_write_reg(priv, 0x02, 0x00);
-	msleep(1);
-	lgs8gxx_write_reg(priv, 0x02, 0x01);
-	msleep(100);
-
-	return 0;
-}
-
-static int wait_reg_mask(struct lgs8gxx_state *priv, u8 reg, u8 mask,
-	u8 val, u8 delay, u8 tries)
-{
-	u8 t;
-	int i;
-
-	for (i = 0; i < tries; i++) {
-		lgs8gxx_read_reg(priv, reg, &t);
-
-		if ((t & mask) == val)
-			return 0;
-		msleep(delay);
-	}
-
-	return 1;
-}
-
-static int lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv)
-{
-	const struct lgs8gxx_config *config = priv->config;
-	u8 if_conf;
-
-	if_conf = 0x10; /* AGC output on, RF_AGC output off; */
-
-	if_conf |=
-		((config->ext_adc) ? 0x80 : 0x00) |
-		((config->if_neg_center) ? 0x04 : 0x00) |
-		((config->if_freq == 0) ? 0x08 : 0x00) | /* Baseband */
-		((config->adc_signed) ? 0x02 : 0x00) |
-		((config->if_neg_edge) ? 0x01 : 0x00);
-
-	if (config->ext_adc &&
-		(config->prod == LGS8GXX_PROD_LGS8G52)) {
-		lgs8gxx_write_reg(priv, 0xBA, 0x40);
-	}
-
-	lgs8gxx_write_reg(priv, 0x07, if_conf);
-
-	return 0;
-}
-
-static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/)
-{
-	u64 val;
-	u32 v32;
-	u32 if_clk;
-
-	if_clk = priv->config->if_clk_freq;
-
-	val = freq;
-	if (freq != 0) {
-		val <<= 32;
-		if (if_clk != 0)
-			do_div(val, if_clk);
-		v32 = val & 0xFFFFFFFF;
-		dprintk("Set IF Freq to %dkHz\n", freq);
-	} else {
-		v32 = 0;
-		dprintk("Set IF Freq to baseband\n");
-	}
-	dprintk("AFC_INIT_FREQ = 0x%08X\n", v32);
-
-	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
-		lgs8gxx_write_reg(priv, 0x08, 0xFF & (v32));
-		lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32 >> 8));
-		lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 16));
-		lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 24));
-	} else {
-		lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32));
-		lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8));
-		lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16));
-		lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24));
-	}
-
-	return 0;
-}
-
-static int lgs8gxx_get_afc_phase(struct lgs8gxx_state *priv)
-{
-	u64 val;
-	u32 v32 = 0;
-	u8 reg_addr, t;
-	int i;
-
-	if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
-		reg_addr = 0x23;
-	else
-		reg_addr = 0x48;
-
-	for (i = 0; i < 4; i++) {
-		lgs8gxx_read_reg(priv, reg_addr, &t);
-		v32 <<= 8;
-		v32 |= t;
-		reg_addr--;
-	}
-
-	val = v32;
-	val *= priv->config->if_clk_freq;
-	val >>= 32;
-	dprintk("AFC = %u kHz\n", (u32)val);
-	return 0;
-}
-
-static int lgs8gxx_set_mode_auto(struct lgs8gxx_state *priv)
-{
-	u8 t;
-	u8 prod = priv->config->prod;
-
-	if (prod == LGS8GXX_PROD_LGS8913)
-		lgs8gxx_write_reg(priv, 0xC6, 0x01);
-
-	if (prod == LGS8GXX_PROD_LGS8G75) {
-		lgs8gxx_read_reg(priv, 0x0C, &t);
-		t &= (~0x04);
-		lgs8gxx_write_reg(priv, 0x0C, t | 0x80);
-		lgs8gxx_write_reg(priv, 0x39, 0x00);
-		lgs8gxx_write_reg(priv, 0x3D, 0x04);
-	} else if (prod == LGS8GXX_PROD_LGS8913 ||
-		prod == LGS8GXX_PROD_LGS8GL5 ||
-		prod == LGS8GXX_PROD_LGS8G42 ||
-		prod == LGS8GXX_PROD_LGS8G52 ||
-		prod == LGS8GXX_PROD_LGS8G54) {
-		lgs8gxx_read_reg(priv, 0x7E, &t);
-		lgs8gxx_write_reg(priv, 0x7E, t | 0x01);
-
-		/* clear FEC self reset */
-		lgs8gxx_read_reg(priv, 0xC5, &t);
-		lgs8gxx_write_reg(priv, 0xC5, t & 0xE0);
-	}
-
-	if (prod == LGS8GXX_PROD_LGS8913) {
-		/* FEC auto detect */
-		lgs8gxx_write_reg(priv, 0xC1, 0x03);
-
-		lgs8gxx_read_reg(priv, 0x7C, &t);
-		t = (t & 0x8C) | 0x03;
-		lgs8gxx_write_reg(priv, 0x7C, t);
-
-		/* BER test mode */
-		lgs8gxx_read_reg(priv, 0xC3, &t);
-		t = (t & 0xEF) |  0x10;
-		lgs8gxx_write_reg(priv, 0xC3, t);
-	}
-
-	if (priv->config->prod == LGS8GXX_PROD_LGS8G52)
-		lgs8gxx_write_reg(priv, 0xD9, 0x40);
-
-	return 0;
-}
-
-static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv)
-{
-	u8 t;
-
-	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
-		u8 t2;
-		lgs8gxx_read_reg(priv, 0x0C, &t);
-		t &= (~0x80);
-		lgs8gxx_write_reg(priv, 0x0C, t);
-
-		lgs8gxx_read_reg(priv, 0x0C, &t);
-		lgs8gxx_read_reg(priv, 0x19, &t2);
-
-		if (((t&0x03) == 0x01) && (t2&0x01)) {
-			lgs8gxx_write_reg(priv, 0x6E, 0x05);
-			lgs8gxx_write_reg(priv, 0x39, 0x02);
-			lgs8gxx_write_reg(priv, 0x39, 0x03);
-			lgs8gxx_write_reg(priv, 0x3D, 0x05);
-			lgs8gxx_write_reg(priv, 0x3E, 0x28);
-			lgs8gxx_write_reg(priv, 0x53, 0x80);
-		} else {
-			lgs8gxx_write_reg(priv, 0x6E, 0x3F);
-			lgs8gxx_write_reg(priv, 0x39, 0x00);
-			lgs8gxx_write_reg(priv, 0x3D, 0x04);
-		}
-
-		lgs8gxx_soft_reset(priv);
-		return 0;
-	}
-
-	/* turn off auto-detect; manual settings */
-	lgs8gxx_write_reg(priv, 0x7E, 0);
-	if (priv->config->prod == LGS8GXX_PROD_LGS8913)
-		lgs8gxx_write_reg(priv, 0xC1, 0);
-
-	lgs8gxx_read_reg(priv, 0xC5, &t);
-	t = (t & 0xE0) | 0x06;
-	lgs8gxx_write_reg(priv, 0xC5, t);
-
-	lgs8gxx_soft_reset(priv);
-
-	return 0;
-}
-
-static int lgs8gxx_is_locked(struct lgs8gxx_state *priv, u8 *locked)
-{
-	int ret = 0;
-	u8 t;
-
-	if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
-		ret = lgs8gxx_read_reg(priv, 0x13, &t);
-	else
-		ret = lgs8gxx_read_reg(priv, 0x4B, &t);
-	if (ret != 0)
-		return ret;
-
-	if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
-		*locked = ((t & 0x80) == 0x80) ? 1 : 0;
-	else
-		*locked = ((t & 0xC0) == 0xC0) ? 1 : 0;
-	return 0;
-}
-
-/* Wait for Code Acquisition Lock */
-static int lgs8gxx_wait_ca_lock(struct lgs8gxx_state *priv, u8 *locked)
-{
-	int ret = 0;
-	u8 reg, mask, val;
-
-	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
-		reg = 0x13;
-		mask = 0x80;
-		val = 0x80;
-	} else {
-		reg = 0x4B;
-		mask = 0xC0;
-		val = 0xC0;
-	}
-
-	ret = wait_reg_mask(priv, reg, mask, val, 50, 40);
-	*locked = (ret == 0) ? 1 : 0;
-
-	return 0;
-}
-
-static int lgs8gxx_is_autodetect_finished(struct lgs8gxx_state *priv,
-					  u8 *finished)
-{
-	int ret = 0;
-	u8 reg, mask, val;
-
-	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
-		reg = 0x1f;
-		mask = 0xC0;
-		val = 0x80;
-	} else {
-		reg = 0xA4;
-		mask = 0x03;
-		val = 0x01;
-	}
-
-	ret = wait_reg_mask(priv, reg, mask, val, 10, 20);
-	*finished = (ret == 0) ? 1 : 0;
-
-	return 0;
-}
-
-static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 cpn,
-	u8 *locked)
-{
-	int err = 0;
-	u8 ad_fini = 0;
-	u8 t1, t2;
-
-	if (gi == GI_945)
-		dprintk("try GI 945\n");
-	else if (gi == GI_595)
-		dprintk("try GI 595\n");
-	else if (gi == GI_420)
-		dprintk("try GI 420\n");
-	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
-		lgs8gxx_read_reg(priv, 0x0C, &t1);
-		lgs8gxx_read_reg(priv, 0x18, &t2);
-		t1 &= ~(GI_MASK);
-		t1 |= gi;
-		t2 &= 0xFE;
-		t2 |= cpn ? 0x01 : 0x00;
-		lgs8gxx_write_reg(priv, 0x0C, t1);
-		lgs8gxx_write_reg(priv, 0x18, t2);
-	} else {
-		lgs8gxx_write_reg(priv, 0x04, gi);
-	}
-	lgs8gxx_soft_reset(priv);
-	err = lgs8gxx_wait_ca_lock(priv, locked);
-	if (err || !(*locked))
-		return err;
-	err = lgs8gxx_is_autodetect_finished(priv, &ad_fini);
-	if (err != 0)
-		return err;
-	if (ad_fini) {
-		dprintk("auto detect finished\n");
-	} else
-		*locked = 0;
-
-	return 0;
-}
-
-static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv,
-			       u8 *detected_param, u8 *gi)
-{
-	int i, j;
-	int err = 0;
-	u8 locked = 0, tmp_gi;
-
-	dprintk("%s\n", __func__);
-
-	lgs8gxx_set_mode_auto(priv);
-	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
-		lgs8gxx_write_reg(priv, 0x67, 0xAA);
-		lgs8gxx_write_reg(priv, 0x6E, 0x3F);
-	} else {
-		/* Guard Interval */
-		lgs8gxx_write_reg(priv, 0x03, 00);
-	}
-
-	for (i = 0; i < 2; i++) {
-		for (j = 0; j < 2; j++) {
-			tmp_gi = GI_945;
-			err = lgs8gxx_autolock_gi(priv, GI_945, j, &locked);
-			if (err)
-				goto out;
-			if (locked)
-				goto locked;
-		}
-		for (j = 0; j < 2; j++) {
-			tmp_gi = GI_420;
-			err = lgs8gxx_autolock_gi(priv, GI_420, j, &locked);
-			if (err)
-				goto out;
-			if (locked)
-				goto locked;
-		}
-		tmp_gi = GI_595;
-		err = lgs8gxx_autolock_gi(priv, GI_595, 1, &locked);
-		if (err)
-			goto out;
-		if (locked)
-			goto locked;
-	}
-
-locked:
-	if ((err == 0) && (locked == 1)) {
-		u8 t;
-
-		if (priv->config->prod != LGS8GXX_PROD_LGS8G75) {
-			lgs8gxx_read_reg(priv, 0xA2, &t);
-			*detected_param = t;
-		} else {
-			lgs8gxx_read_reg(priv, 0x1F, &t);
-			*detected_param = t & 0x3F;
-		}
-
-		if (tmp_gi == GI_945)
-			dprintk("GI 945 locked\n");
-		else if (tmp_gi == GI_595)
-			dprintk("GI 595 locked\n");
-		else if (tmp_gi == GI_420)
-			dprintk("GI 420 locked\n");
-		*gi = tmp_gi;
-	}
-	if (!locked)
-		err = -1;
-
-out:
-	return err;
-}
-
-static void lgs8gxx_auto_lock(struct lgs8gxx_state *priv)
-{
-	s8 err;
-	u8 gi = 0x2;
-	u8 detected_param = 0;
-
-	err = lgs8gxx_auto_detect(priv, &detected_param, &gi);
-
-	if (err != 0) {
-		dprintk("lgs8gxx_auto_detect failed\n");
-	} else
-		dprintk("detected param = 0x%02X\n", detected_param);
-
-	/* Apply detected parameters */
-	if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
-		u8 inter_leave_len = detected_param & TIM_MASK ;
-		/* Fix 8913 time interleaver detection bug */
-		inter_leave_len = (inter_leave_len == TIM_MIDDLE) ? 0x60 : 0x40;
-		detected_param &= CF_MASK | SC_MASK  | LGS_FEC_MASK;
-		detected_param |= inter_leave_len;
-	}
-	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
-		u8 t;
-		lgs8gxx_read_reg(priv, 0x19, &t);
-		t &= 0x81;
-		t |= detected_param << 1;
-		lgs8gxx_write_reg(priv, 0x19, t);
-	} else {
-		lgs8gxx_write_reg(priv, 0x7D, detected_param);
-		if (priv->config->prod == LGS8GXX_PROD_LGS8913)
-			lgs8gxx_write_reg(priv, 0xC0, detected_param);
-	}
-	/* lgs8gxx_soft_reset(priv); */
-
-	/* Enter manual mode */
-	lgs8gxx_set_mode_manual(priv);
-
-	switch (gi) {
-	case GI_945:
-		priv->curr_gi = 945; break;
-	case GI_595:
-		priv->curr_gi = 595; break;
-	case GI_420:
-		priv->curr_gi = 420; break;
-	default:
-		priv->curr_gi = 945; break;
-	}
-}
-
-static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv,
-	u8 serial, u8 clk_pol, u8 clk_gated)
-{
-	int ret = 0;
-	u8 t, reg_addr;
-
-	reg_addr = (priv->config->prod == LGS8GXX_PROD_LGS8G75) ? 0x30 : 0xC2;
-	ret = lgs8gxx_read_reg(priv, reg_addr, &t);
-	if (ret != 0)
-		return ret;
-
-	t &= 0xF8;
-	t |= serial ? TS_SERIAL : TS_PARALLEL;
-	t |= clk_pol ? TS_CLK_INVERTED : TS_CLK_NORMAL;
-	t |= clk_gated ? TS_CLK_GATED : TS_CLK_FREERUN;
-
-	ret = lgs8gxx_write_reg(priv, reg_addr, t);
-	if (ret != 0)
-		return ret;
-
-	return 0;
-}
-
-/* A/D input peak-to-peak voltage range */
-static int lgs8g75_set_adc_vpp(struct lgs8gxx_state *priv,
-	u8 sel)
-{
-	u8 r26 = 0x73, r27 = 0x90;
-
-	if (priv->config->prod != LGS8GXX_PROD_LGS8G75)
-		return 0;
-
-	r26 |= (sel & 0x01) << 7;
-	r27 |= (sel & 0x02) >> 1;
-	lgs8gxx_write_reg(priv, 0x26, r26);
-	lgs8gxx_write_reg(priv, 0x27, r27);
-
-	return 0;
-}
-
-/* LGS8913 demod frontend functions */
-
-static int lgs8913_init(struct lgs8gxx_state *priv)
-{
-	u8 t;
-
-	/* LGS8913 specific */
-	lgs8gxx_write_reg(priv, 0xc1, 0x3);
-
-	lgs8gxx_read_reg(priv, 0x7c, &t);
-	lgs8gxx_write_reg(priv, 0x7c, (t&0x8c) | 0x3);
-
-	/* LGS8913 specific */
-	lgs8gxx_read_reg(priv, 0xc3, &t);
-	lgs8gxx_write_reg(priv, 0xc3, t&0x10);
-
-
-	return 0;
-}
-
-static int lgs8g75_init_data(struct lgs8gxx_state *priv)
-{
-	const struct firmware *fw;
-	int rc;
-	int i;
-
-	rc = request_firmware(&fw, LGS8GXX_FIRMWARE, &priv->i2c->dev);
-	if (rc)
-		return rc;
-
-	lgs8gxx_write_reg(priv, 0xC6, 0x40);
-
-	lgs8gxx_write_reg(priv, 0x3D, 0x04);
-	lgs8gxx_write_reg(priv, 0x39, 0x00);
-
-	lgs8gxx_write_reg(priv, 0x3A, 0x00);
-	lgs8gxx_write_reg(priv, 0x38, 0x00);
-	lgs8gxx_write_reg(priv, 0x3B, 0x00);
-	lgs8gxx_write_reg(priv, 0x38, 0x00);
-
-	for (i = 0; i < fw->size; i++) {
-		lgs8gxx_write_reg(priv, 0x38, 0x00);
-		lgs8gxx_write_reg(priv, 0x3A, (u8)(i&0xff));
-		lgs8gxx_write_reg(priv, 0x3B, (u8)(i>>8));
-		lgs8gxx_write_reg(priv, 0x3C, fw->data[i]);
-	}
-
-	lgs8gxx_write_reg(priv, 0x38, 0x00);
-
-	release_firmware(fw);
-	return 0;
-}
-
-static int lgs8gxx_init(struct dvb_frontend *fe)
-{
-	struct lgs8gxx_state *priv =
-		(struct lgs8gxx_state *)fe->demodulator_priv;
-	const struct lgs8gxx_config *config = priv->config;
-	u8 data = 0;
-	s8 err;
-	dprintk("%s\n", __func__);
-
-	lgs8gxx_read_reg(priv, 0, &data);
-	dprintk("reg 0 = 0x%02X\n", data);
-
-	if (config->prod == LGS8GXX_PROD_LGS8G75)
-		lgs8g75_set_adc_vpp(priv, config->adc_vpp);
-
-	/* Setup MPEG output format */
-	err = lgs8gxx_set_mpeg_mode(priv, config->serial_ts,
-				    config->ts_clk_pol,
-				    config->ts_clk_gated);
-	if (err != 0)
-		return -EIO;
-
-	if (config->prod == LGS8GXX_PROD_LGS8913)
-		lgs8913_init(priv);
-	lgs8gxx_set_if_freq(priv, priv->config->if_freq);
-	lgs8gxx_set_ad_mode(priv);
-
-	return 0;
-}
-
-static void lgs8gxx_release(struct dvb_frontend *fe)
-{
-	struct lgs8gxx_state *state = fe->demodulator_priv;
-	dprintk("%s\n", __func__);
-
-	kfree(state);
-}
-
-
-static int lgs8gxx_write(struct dvb_frontend *fe, const u8 buf[], int len)
-{
-	struct lgs8gxx_state *priv = fe->demodulator_priv;
-
-	if (len != 2)
-		return -EINVAL;
-
-	return lgs8gxx_write_reg(priv, buf[0], buf[1]);
-}
-
-static int lgs8gxx_set_fe(struct dvb_frontend *fe)
-{
-
-	struct lgs8gxx_state *priv = fe->demodulator_priv;
-
-	dprintk("%s\n", __func__);
-
-	/* set frequency */
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	/* start auto lock */
-	lgs8gxx_auto_lock(priv);
-
-	msleep(10);
-
-	return 0;
-}
-
-static int lgs8gxx_get_fe(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
-	dprintk("%s\n", __func__);
-
-	/* TODO: get real readings from device */
-	/* inversion status */
-	fe_params->inversion = INVERSION_OFF;
-
-	/* bandwidth */
-	fe_params->bandwidth_hz = 8000000;
-
-	fe_params->code_rate_HP = FEC_AUTO;
-	fe_params->code_rate_LP = FEC_AUTO;
-
-	fe_params->modulation = QAM_AUTO;
-
-	/* transmission mode */
-	fe_params->transmission_mode = TRANSMISSION_MODE_AUTO;
-
-	/* guard interval */
-	fe_params->guard_interval = GUARD_INTERVAL_AUTO;
-
-	/* hierarchy */
-	fe_params->hierarchy = HIERARCHY_NONE;
-
-	return 0;
-}
-
-static
-int lgs8gxx_get_tune_settings(struct dvb_frontend *fe,
-			      struct dvb_frontend_tune_settings *fesettings)
-{
-	/* FIXME: copy from tda1004x.c */
-	fesettings->min_delay_ms = 800;
-	fesettings->step_size = 0;
-	fesettings->max_drift = 0;
-	return 0;
-}
-
-static int lgs8gxx_read_status(struct dvb_frontend *fe, fe_status_t *fe_status)
-{
-	struct lgs8gxx_state *priv = fe->demodulator_priv;
-	s8 ret;
-	u8 t, locked = 0;
-
-	dprintk("%s\n", __func__);
-	*fe_status = 0;
-
-	lgs8gxx_get_afc_phase(priv);
-	lgs8gxx_is_locked(priv, &locked);
-	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
-		if (locked)
-			*fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-				FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
-		return 0;
-	}
-
-	ret = lgs8gxx_read_reg(priv, 0x4B, &t);
-	if (ret != 0)
-		return -EIO;
-
-	dprintk("Reg 0x4B: 0x%02X\n", t);
-
-	*fe_status = 0;
-	if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
-		if ((t & 0x40) == 0x40)
-			*fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
-		if ((t & 0x80) == 0x80)
-			*fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC |
-				FE_HAS_LOCK;
-	} else {
-		if ((t & 0x80) == 0x80)
-			*fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-				FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
-	}
-
-	/* success */
-	dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
-	return 0;
-}
-
-static int lgs8gxx_read_signal_agc(struct lgs8gxx_state *priv, u16 *signal)
-{
-	u16 v;
-	u8 agc_lvl[2], cat;
-
-	dprintk("%s()\n", __func__);
-	lgs8gxx_read_reg(priv, 0x3F, &agc_lvl[0]);
-	lgs8gxx_read_reg(priv, 0x3E, &agc_lvl[1]);
-
-	v = agc_lvl[0];
-	v <<= 8;
-	v |= agc_lvl[1];
-
-	dprintk("agc_lvl: 0x%04X\n", v);
-
-	if (v < 0x100)
-		cat = 0;
-	else if (v < 0x190)
-		cat = 5;
-	else if (v < 0x2A8)
-		cat = 4;
-	else if (v < 0x381)
-		cat = 3;
-	else if (v < 0x400)
-		cat = 2;
-	else if (v == 0x400)
-		cat = 1;
-	else
-		cat = 0;
-
-	*signal = cat * 65535 / 5;
-
-	return 0;
-}
-
-static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
-{
-	u8 t; s8 ret;
-	s16 max_strength = 0;
-	u8 str;
-	u16 i, gi = priv->curr_gi;
-
-	dprintk("%s\n", __func__);
-
-	ret = lgs8gxx_read_reg(priv, 0x4B, &t);
-	if (ret != 0)
-		return -EIO;
-
-	if (fake_signal_str) {
-		if ((t & 0xC0) == 0xC0) {
-			dprintk("Fake signal strength\n");
-			*signal = 0x7FFF;
-		} else
-			*signal = 0;
-		return 0;
-	}
-
-	dprintk("gi = %d\n", gi);
-	for (i = 0; i < gi; i++) {
-
-		if ((i & 0xFF) == 0)
-			lgs8gxx_write_reg(priv, 0x84, 0x03 & (i >> 8));
-		lgs8gxx_write_reg(priv, 0x83, i & 0xFF);
-
-		lgs8gxx_read_reg(priv, 0x94, &str);
-		if (max_strength < str)
-			max_strength = str;
-	}
-
-	*signal = max_strength;
-	dprintk("%s: signal=0x%02X\n", __func__, *signal);
-
-	lgs8gxx_read_reg(priv, 0x95, &t);
-	dprintk("%s: AVG Noise=0x%02X\n", __func__, t);
-
-	return 0;
-}
-
-static int lgs8g75_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
-{
-	u8 t;
-	s16 v = 0;
-
-	dprintk("%s\n", __func__);
-
-	lgs8gxx_read_reg(priv, 0xB1, &t);
-	v |= t;
-	v <<= 8;
-	lgs8gxx_read_reg(priv, 0xB0, &t);
-	v |= t;
-
-	*signal = v;
-	dprintk("%s: signal=0x%02X\n", __func__, *signal);
-
-	return 0;
-}
-
-static int lgs8gxx_read_signal_strength(struct dvb_frontend *fe, u16 *signal)
-{
-	struct lgs8gxx_state *priv = fe->demodulator_priv;
-
-	if (priv->config->prod == LGS8GXX_PROD_LGS8913)
-		return lgs8913_read_signal_strength(priv, signal);
-	else if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
-		return lgs8g75_read_signal_strength(priv, signal);
-	else
-		return lgs8gxx_read_signal_agc(priv, signal);
-}
-
-static int lgs8gxx_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct lgs8gxx_state *priv = fe->demodulator_priv;
-	u8 t;
-	*snr = 0;
-
-	if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
-		lgs8gxx_read_reg(priv, 0x34, &t);
-	else
-		lgs8gxx_read_reg(priv, 0x95, &t);
-	dprintk("AVG Noise=0x%02X\n", t);
-	*snr = 256 - t;
-	*snr <<= 8;
-	dprintk("snr=0x%x\n", *snr);
-
-	return 0;
-}
-
-static int lgs8gxx_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	*ucblocks = 0;
-	dprintk("%s: ucblocks=0x%x\n", __func__, *ucblocks);
-	return 0;
-}
-
-static void packet_counter_start(struct lgs8gxx_state *priv)
-{
-	u8 orig, t;
-
-	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
-		lgs8gxx_read_reg(priv, 0x30, &orig);
-		orig &= 0xE7;
-		t = orig | 0x10;
-		lgs8gxx_write_reg(priv, 0x30, t);
-		t = orig | 0x18;
-		lgs8gxx_write_reg(priv, 0x30, t);
-		t = orig | 0x10;
-		lgs8gxx_write_reg(priv, 0x30, t);
-	} else {
-		lgs8gxx_write_reg(priv, 0xC6, 0x01);
-		lgs8gxx_write_reg(priv, 0xC6, 0x41);
-		lgs8gxx_write_reg(priv, 0xC6, 0x01);
-	}
-}
-
-static void packet_counter_stop(struct lgs8gxx_state *priv)
-{
-	u8 t;
-
-	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
-		lgs8gxx_read_reg(priv, 0x30, &t);
-		t &= 0xE7;
-		lgs8gxx_write_reg(priv, 0x30, t);
-	} else {
-		lgs8gxx_write_reg(priv, 0xC6, 0x81);
-	}
-}
-
-static int lgs8gxx_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct lgs8gxx_state *priv = fe->demodulator_priv;
-	u8 reg_err, reg_total, t;
-	u32 total_cnt = 0, err_cnt = 0;
-	int i;
-
-	dprintk("%s\n", __func__);
-
-	packet_counter_start(priv);
-	msleep(200);
-	packet_counter_stop(priv);
-
-	if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
-		reg_total = 0x28; reg_err = 0x2C;
-	} else {
-		reg_total = 0xD0; reg_err = 0xD4;
-	}
-
-	for (i = 0; i < 4; i++) {
-		total_cnt <<= 8;
-		lgs8gxx_read_reg(priv, reg_total+3-i, &t);
-		total_cnt |= t;
-	}
-	for (i = 0; i < 4; i++) {
-		err_cnt <<= 8;
-		lgs8gxx_read_reg(priv, reg_err+3-i, &t);
-		err_cnt |= t;
-	}
-	dprintk("error=%d total=%d\n", err_cnt, total_cnt);
-
-	if (total_cnt == 0)
-		*ber = 0;
-	else
-		*ber = err_cnt * 100 / total_cnt;
-
-	dprintk("%s: ber=0x%x\n", __func__, *ber);
-	return 0;
-}
-
-static int lgs8gxx_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct lgs8gxx_state *priv = fe->demodulator_priv;
-
-	if (priv->config->tuner_address == 0)
-		return 0;
-	if (enable) {
-		u8 v = 0x80 | priv->config->tuner_address;
-		return lgs8gxx_write_reg(priv, 0x01, v);
-	}
-	return lgs8gxx_write_reg(priv, 0x01, 0);
-}
-
-static struct dvb_frontend_ops lgs8gxx_ops = {
-	.delsys = { SYS_DMBTH },
-	.info = {
-		.name = "Legend Silicon LGS8913/LGS8GXX DMB-TH",
-		.frequency_min = 474000000,
-		.frequency_max = 858000000,
-		.frequency_stepsize = 10000,
-		.caps =
-			FE_CAN_FEC_AUTO |
-			FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO
-	},
-
-	.release = lgs8gxx_release,
-
-	.init = lgs8gxx_init,
-	.write = lgs8gxx_write,
-	.i2c_gate_ctrl = lgs8gxx_i2c_gate_ctrl,
-
-	.set_frontend = lgs8gxx_set_fe,
-	.get_frontend = lgs8gxx_get_fe,
-	.get_tune_settings = lgs8gxx_get_tune_settings,
-
-	.read_status = lgs8gxx_read_status,
-	.read_ber = lgs8gxx_read_ber,
-	.read_signal_strength = lgs8gxx_read_signal_strength,
-	.read_snr = lgs8gxx_read_snr,
-	.read_ucblocks = lgs8gxx_read_ucblocks,
-};
-
-struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,
-	struct i2c_adapter *i2c)
-{
-	struct lgs8gxx_state *priv = NULL;
-	u8 data = 0;
-
-	dprintk("%s()\n", __func__);
-
-	if (config == NULL || i2c == NULL)
-		return NULL;
-
-	priv = kzalloc(sizeof(struct lgs8gxx_state), GFP_KERNEL);
-	if (priv == NULL)
-		goto error_out;
-
-	priv->config = config;
-	priv->i2c = i2c;
-
-	/* check if the demod is there */
-	if (lgs8gxx_read_reg(priv, 0, &data) != 0) {
-		dprintk("%s lgs8gxx not found at i2c addr 0x%02X\n",
-			__func__, priv->config->demod_address);
-		goto error_out;
-	}
-
-	lgs8gxx_read_reg(priv, 1, &data);
-
-	memcpy(&priv->frontend.ops, &lgs8gxx_ops,
-	       sizeof(struct dvb_frontend_ops));
-	priv->frontend.demodulator_priv = priv;
-
-	if (config->prod == LGS8GXX_PROD_LGS8G75)
-		lgs8g75_init_data(priv);
-
-	return &priv->frontend;
-
-error_out:
-	dprintk("%s() error_out\n", __func__);
-	kfree(priv);
-	return NULL;
-
-}
-EXPORT_SYMBOL(lgs8gxx_attach);
-
-MODULE_DESCRIPTION("Legend Silicon LGS8913/LGS8GXX DMB-TH demodulator driver");
-MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(LGS8GXX_FIRMWARE);
diff --git a/drivers/media/dvb/frontends/lgs8gxx.h b/drivers/media/dvb/frontends/lgs8gxx.h
deleted file mode 100644
index 33c3c5e..0000000
--- a/drivers/media/dvb/frontends/lgs8gxx.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- *    Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
- *    LGS8913, LGS8GL5, LGS8G75
- *    experimental support LGS8G42, LGS8G52
- *
- *    Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
- *    Copyright (C) 2008 Sirius International (Hong Kong) Limited
- *    Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef __LGS8GXX_H__
-#define __LGS8GXX_H__
-
-#include <linux/dvb/frontend.h>
-#include <linux/i2c.h>
-
-#define LGS8GXX_PROD_LGS8913 0
-#define LGS8GXX_PROD_LGS8GL5 1
-#define LGS8GXX_PROD_LGS8G42 3
-#define LGS8GXX_PROD_LGS8G52 4
-#define LGS8GXX_PROD_LGS8G54 5
-#define LGS8GXX_PROD_LGS8G75 6
-
-struct lgs8gxx_config {
-
-	/* product type */
-	u8 prod;
-
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* parallel or serial transport stream */
-	u8 serial_ts;
-
-	/* transport stream polarity*/
-	u8 ts_clk_pol;
-
-	/* transport stream clock gated by ts_valid */
-	u8 ts_clk_gated;
-
-	/* A/D Clock frequency */
-	u32 if_clk_freq; /* in kHz */
-
-	/* IF frequency */
-	u32 if_freq; /* in kHz */
-
-	/*Use External ADC*/
-	u8 ext_adc;
-
-	/*External ADC output two's complement*/
-	u8 adc_signed;
-
-	/*Sample IF data at falling edge of IF_CLK*/
-	u8 if_neg_edge;
-
-	/*IF use Negative center frequency*/
-	u8 if_neg_center;
-
-	/*8G75 internal ADC input range selection*/
-	/*0: 0.8Vpp, 1: 1.0Vpp, 2: 1.6Vpp, 3: 2.0Vpp*/
-	u8 adc_vpp;
-
-	/* slave address and configuration of the tuner */
-	u8 tuner_address;
-};
-
-#if defined(CONFIG_DVB_LGS8GXX) || \
-	(defined(CONFIG_DVB_LGS8GXX_MODULE) && defined(MODULE))
-extern struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,
-					   struct i2c_adapter *i2c);
-#else
-static inline
-struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,
-				    struct i2c_adapter *i2c) {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_LGS8GXX */
-
-#endif /* __LGS8GXX_H__ */
diff --git a/drivers/media/dvb/frontends/lgs8gxx_priv.h b/drivers/media/dvb/frontends/lgs8gxx_priv.h
deleted file mode 100644
index 8ef376f..0000000
--- a/drivers/media/dvb/frontends/lgs8gxx_priv.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- *    Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
- *    LGS8913, LGS8GL5, LGS8G75
- *    experimental support LGS8G42, LGS8G52
- *
- *    Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
- *    Copyright (C) 2008 Sirius International (Hong Kong) Limited
- *    Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef LGS8913_PRIV_H
-#define LGS8913_PRIV_H
-
-struct lgs8gxx_state {
-	struct i2c_adapter *i2c;
-	/* configuration settings */
-	const struct lgs8gxx_config *config;
-	struct dvb_frontend frontend;
-	u16 curr_gi; /* current guard interval */
-};
-
-#define SC_MASK		0x1C	/* Sub-Carrier Modulation Mask */
-#define SC_QAM64	0x10	/* 64QAM modulation */
-#define SC_QAM32	0x0C	/* 32QAM modulation */
-#define SC_QAM16	0x08	/* 16QAM modulation */
-#define SC_QAM4NR	0x04	/* 4QAM-NR modulation */
-#define SC_QAM4		0x00	/* 4QAM modulation */
-
-#define LGS_FEC_MASK	0x03	/* FEC Rate Mask */
-#define LGS_FEC_0_4	0x00	/* FEC Rate 0.4 */
-#define LGS_FEC_0_6	0x01	/* FEC Rate 0.6 */
-#define LGS_FEC_0_8	0x02	/* FEC Rate 0.8 */
-
-#define TIM_MASK	  0x20	/* Time Interleave Length Mask */
-#define TIM_LONG	  0x20	/* Time Interleave Length = 720 */
-#define TIM_MIDDLE     0x00   /* Time Interleave Length = 240 */
-
-#define CF_MASK	0x80	/* Control Frame Mask */
-#define CF_EN	0x80	/* Control Frame On */
-
-#define GI_MASK	0x03	/* Guard Interval Mask */
-#define GI_420	0x00	/* 1/9 Guard Interval */
-#define GI_595	0x01	/* */
-#define GI_945	0x02	/* 1/4 Guard Interval */
-
-
-#define TS_PARALLEL	0x00	/* Parallel TS Output a.k.a. SPI */
-#define TS_SERIAL	0x01	/* Serial TS Output a.k.a. SSI */
-#define TS_CLK_NORMAL		0x00	/* MPEG Clock Normal */
-#define TS_CLK_INVERTED		0x02	/* MPEG Clock Inverted */
-#define TS_CLK_GATED		0x00	/* MPEG clock gated */
-#define TS_CLK_FREERUN		0x04	/* MPEG clock free running*/
-
-
-#endif
diff --git a/drivers/media/dvb/frontends/lnbh24.h b/drivers/media/dvb/frontends/lnbh24.h
deleted file mode 100644
index c059b16..0000000
--- a/drivers/media/dvb/frontends/lnbh24.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * lnbh24.h - driver for lnb supply and control ic lnbh24
- *
- * Copyright (C) 2009 NetUP Inc.
- * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _LNBH24_H
-#define _LNBH24_H
-
-/* system register bits */
-#define LNBH24_OLF	0x01
-#define LNBH24_OTF	0x02
-#define LNBH24_EN	0x04
-#define LNBH24_VSEL	0x08
-#define LNBH24_LLC	0x10
-#define LNBH24_TEN	0x20
-#define LNBH24_TTX	0x40
-#define LNBH24_PCL	0x80
-
-#include <linux/dvb/frontend.h>
-
-#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) \
-							&& defined(MODULE))
-/* override_set and override_clear control which
-   system register bits (above) to always set & clear */
-extern struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,
-				struct i2c_adapter *i2c, u8 override_set,
-				u8 override_clear, u8 i2c_addr);
-#else
-static inline struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,
-				struct i2c_adapter *i2c, u8 override_set,
-				u8 override_clear, u8 i2c_addr)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c
deleted file mode 100644
index 1343725..0000000
--- a/drivers/media/dvb/frontends/lnbp21.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * lnbp21.c - driver for lnb supply and control ic lnbp21
- *
- * Copyright (C) 2006, 2009 Oliver Endriss <o.endriss@gmx.de>
- * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org
- */
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "lnbp21.h"
-#include "lnbh24.h"
-
-struct lnbp21 {
-	u8			config;
-	u8			override_or;
-	u8			override_and;
-	struct i2c_adapter	*i2c;
-	u8			i2c_addr;
-};
-
-static int lnbp21_set_voltage(struct dvb_frontend *fe,
-					fe_sec_voltage_t voltage)
-{
-	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
-	struct i2c_msg msg = {	.addr = lnbp21->i2c_addr, .flags = 0,
-				.buf = &lnbp21->config,
-				.len = sizeof(lnbp21->config) };
-
-	lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
-
-	switch(voltage) {
-	case SEC_VOLTAGE_OFF:
-		break;
-	case SEC_VOLTAGE_13:
-		lnbp21->config |= LNBP21_EN;
-		break;
-	case SEC_VOLTAGE_18:
-		lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	lnbp21->config |= lnbp21->override_or;
-	lnbp21->config &= lnbp21->override_and;
-
-	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
-{
-	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
-	struct i2c_msg msg = {	.addr = lnbp21->i2c_addr, .flags = 0,
-				.buf = &lnbp21->config,
-				.len = sizeof(lnbp21->config) };
-
-	if (arg)
-		lnbp21->config |= LNBP21_LLC;
-	else
-		lnbp21->config &= ~LNBP21_LLC;
-
-	lnbp21->config |= lnbp21->override_or;
-	lnbp21->config &= lnbp21->override_and;
-
-	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static int lnbp21_set_tone(struct dvb_frontend *fe,
-				fe_sec_tone_mode_t tone)
-{
-	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
-	struct i2c_msg msg = {	.addr = lnbp21->i2c_addr, .flags = 0,
-				.buf = &lnbp21->config,
-				.len = sizeof(lnbp21->config) };
-
-	switch (tone) {
-	case SEC_TONE_OFF:
-		lnbp21->config &= ~LNBP21_TEN;
-		break;
-	case SEC_TONE_ON:
-		lnbp21->config |= LNBP21_TEN;
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	lnbp21->config |= lnbp21->override_or;
-	lnbp21->config &= lnbp21->override_and;
-
-	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static void lnbp21_release(struct dvb_frontend *fe)
-{
-	/* LNBP power off */
-	lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
-
-	/* free data */
-	kfree(fe->sec_priv);
-	fe->sec_priv = NULL;
-}
-
-static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe,
-				struct i2c_adapter *i2c, u8 override_set,
-				u8 override_clear, u8 i2c_addr, u8 config)
-{
-	struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
-	if (!lnbp21)
-		return NULL;
-
-	/* default configuration */
-	lnbp21->config = config;
-	lnbp21->i2c = i2c;
-	lnbp21->i2c_addr = i2c_addr;
-	fe->sec_priv = lnbp21;
-
-	/* bits which should be forced to '1' */
-	lnbp21->override_or = override_set;
-
-	/* bits which should be forced to '0' */
-	lnbp21->override_and = ~override_clear;
-
-	/* detect if it is present or not */
-	if (lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF)) {
-		kfree(lnbp21);
-		return NULL;
-	}
-
-	/* install release callback */
-	fe->ops.release_sec = lnbp21_release;
-
-	/* override frontend ops */
-	fe->ops.set_voltage = lnbp21_set_voltage;
-	fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-	if (!(override_clear & LNBH24_TEN)) /*22kHz logic controlled by demod*/
-		fe->ops.set_tone = lnbp21_set_tone;
-	printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr);
-
-	return fe;
-}
-
-struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,
-				struct i2c_adapter *i2c, u8 override_set,
-				u8 override_clear, u8 i2c_addr)
-{
-	return lnbx2x_attach(fe, i2c, override_set, override_clear,
-							i2c_addr, LNBH24_TTX);
-}
-EXPORT_SYMBOL(lnbh24_attach);
-
-struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
-				struct i2c_adapter *i2c, u8 override_set,
-				u8 override_clear)
-{
-	return lnbx2x_attach(fe, i2c, override_set, override_clear,
-							0x08, LNBP21_ISEL);
-}
-EXPORT_SYMBOL(lnbp21_attach);
-
-MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21, lnbh24");
-MODULE_AUTHOR("Oliver Endriss, Igor M. Liplianin");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lnbp21.h b/drivers/media/dvb/frontends/lnbp21.h
deleted file mode 100644
index fcdf1c6..0000000
--- a/drivers/media/dvb/frontends/lnbp21.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * lnbp21.h - driver for lnb supply and control ic lnbp21
- *
- * Copyright (C) 2006 Oliver Endriss
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org
- */
-
-#ifndef _LNBP21_H
-#define _LNBP21_H
-
-/* system register bits */
-/* [RO] 0=OK; 1=over current limit flag */
-#define LNBP21_OLF	0x01
-/* [RO] 0=OK; 1=over temperature flag (150 C) */
-#define LNBP21_OTF	0x02
-/* [RW] 0=disable LNB power, enable loopthrough
-	1=enable LNB power, disable loopthrough */
-#define LNBP21_EN	0x04
-/* [RW] 0=low voltage (13/14V, vert pol)
-	1=high voltage (18/19V,horiz pol) */
-#define LNBP21_VSEL	0x08
-/* [RW] increase LNB voltage by 1V:
-	0=13/18V; 1=14/19V */
-#define LNBP21_LLC	0x10
-/* [RW] 0=tone controlled by DSQIN pin
-	1=tone enable, disable DSQIN */
-#define LNBP21_TEN	0x20
-/* [RW] current limit select:
-	0:Iout=500-650mA Isc=300mA
-	1:Iout=400-550mA Isc=200mA */
-#define LNBP21_ISEL	0x40
-/* [RW] short-circuit protect:
-	0=pulsed (dynamic) curr limiting
-	1=static curr limiting */
-#define LNBP21_PCL	0x80
-
-#include <linux/dvb/frontend.h>
-
-#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) \
-							&& defined(MODULE))
-/* override_set and override_clear control which
- system register bits (above) to always set & clear */
-extern struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
-				struct i2c_adapter *i2c, u8 override_set,
-				u8 override_clear);
-#else
-static inline struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
-				struct i2c_adapter *i2c, u8 override_set,
-				u8 override_clear)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/dvb/frontends/lnbp22.c b/drivers/media/dvb/frontends/lnbp22.c
deleted file mode 100644
index 84ad039..0000000
--- a/drivers/media/dvb/frontends/lnbp22.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * lnbp22.h - driver for lnb supply and control ic lnbp22
- *
- * Copyright (C) 2006 Dominik Kuhlen
- * Based on lnbp21 driver
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org
- */
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "lnbp22.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-
-#define dprintk(lvl, arg...) if (debug >= (lvl)) printk(arg)
-
-struct lnbp22 {
-	u8		    config[4];
-	struct i2c_adapter *i2c;
-};
-
-static int lnbp22_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
-	struct lnbp22 *lnbp22 = (struct lnbp22 *)fe->sec_priv;
-	struct i2c_msg msg = {
-		.addr = 0x08,
-		.flags = 0,
-		.buf = (char *)&lnbp22->config,
-		.len = sizeof(lnbp22->config),
-	};
-
-	dprintk(1, "%s: %d (18V=%d 13V=%d)\n", __func__, voltage,
-	       SEC_VOLTAGE_18, SEC_VOLTAGE_13);
-
-	lnbp22->config[3] = 0x60; /* Power down */
-	switch (voltage) {
-	case SEC_VOLTAGE_OFF:
-		break;
-	case SEC_VOLTAGE_13:
-		lnbp22->config[3] |= LNBP22_EN;
-		break;
-	case SEC_VOLTAGE_18:
-		lnbp22->config[3] |= (LNBP22_EN | LNBP22_VSEL);
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	dprintk(1, "%s: 0x%02x)\n", __func__, lnbp22->config[3]);
-	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static int lnbp22_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
-{
-	struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
-	struct i2c_msg msg = {
-		.addr = 0x08,
-		.flags = 0,
-		.buf = (char *)&lnbp22->config,
-		.len = sizeof(lnbp22->config),
-	};
-
-	dprintk(1, "%s: %d\n", __func__, (int)arg);
-	if (arg)
-		lnbp22->config[3] |= LNBP22_LLC;
-	else
-		lnbp22->config[3] &= ~LNBP22_LLC;
-
-	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static void lnbp22_release(struct dvb_frontend *fe)
-{
-	dprintk(1, "%s\n", __func__);
-	/* LNBP power off */
-	lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF);
-
-	/* free data */
-	kfree(fe->sec_priv);
-	fe->sec_priv = NULL;
-}
-
-struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe,
-					struct i2c_adapter *i2c)
-{
-	struct lnbp22 *lnbp22 = kmalloc(sizeof(struct lnbp22), GFP_KERNEL);
-	if (!lnbp22)
-		return NULL;
-
-	/* default configuration */
-	lnbp22->config[0] = 0x00; /* ? */
-	lnbp22->config[1] = 0x28; /* ? */
-	lnbp22->config[2] = 0x48; /* ? */
-	lnbp22->config[3] = 0x60; /* Power down */
-	lnbp22->i2c = i2c;
-	fe->sec_priv = lnbp22;
-
-	/* detect if it is present or not */
-	if (lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF)) {
-		dprintk(0, "%s LNBP22 not found\n", __func__);
-		kfree(lnbp22);
-		fe->sec_priv = NULL;
-		return NULL;
-	}
-
-	/* install release callback */
-	fe->ops.release_sec = lnbp22_release;
-
-	/* override frontend ops */
-	fe->ops.set_voltage = lnbp22_set_voltage;
-	fe->ops.enable_high_lnb_voltage = lnbp22_enable_high_lnb_voltage;
-
-	return fe;
-}
-EXPORT_SYMBOL(lnbp22_attach);
-
-MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp22");
-MODULE_AUTHOR("Dominik Kuhlen");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lnbp22.h b/drivers/media/dvb/frontends/lnbp22.h
deleted file mode 100644
index 63e2dec..0000000
--- a/drivers/media/dvb/frontends/lnbp22.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * lnbp22.h - driver for lnb supply and control ic lnbp22
- *
- * Copyright (C) 2006 Dominik Kuhlen
- * Based on lnbp21.h
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org
- */
-
-#ifndef _LNBP22_H
-#define _LNBP22_H
-
-/* Enable */
-#define LNBP22_EN	  0x10
-/* Voltage selection */
-#define LNBP22_VSEL	0x02
-/* Plus 1 Volt Bit */
-#define LNBP22_LLC	0x01
-
-#include <linux/dvb/frontend.h>
-
-#if defined(CONFIG_DVB_LNBP22) || \
-		(defined(CONFIG_DVB_LNBP22_MODULE) && defined(MODULE))
-/*
- * override_set and override_clear control which system register bits (above)
- * to always set & clear
- */
-extern struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe,
-						struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe,
-						struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_LNBP22 */
-
-#endif /* _LNBP22_H */
diff --git a/drivers/media/dvb/frontends/m88rs2000.c b/drivers/media/dvb/frontends/m88rs2000.c
deleted file mode 100644
index 312588e..0000000
--- a/drivers/media/dvb/frontends/m88rs2000.c
+++ /dev/null
@@ -1,919 +0,0 @@
-/*
-	Driver for M88RS2000 demodulator and tuner
-
-	Copyright (C) 2012 Malcolm Priestley (tvboxspy@gmail.com)
-	Beta Driver
-
-	Include various calculation code from DS3000 driver.
-	Copyright (C) 2009 Konstantin Dimitrov.
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/jiffies.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-
-#include "dvb_frontend.h"
-#include "m88rs2000.h"
-
-struct m88rs2000_state {
-	struct i2c_adapter *i2c;
-	const struct m88rs2000_config *config;
-	struct dvb_frontend frontend;
-	u8 no_lock_count;
-	u32 tuner_frequency;
-	u32 symbol_rate;
-	fe_code_rate_t fec_inner;
-	u8 tuner_level;
-	int errmode;
-};
-
-static int m88rs2000_debug;
-
-module_param_named(debug, m88rs2000_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
-
-#define dprintk(level, args...) do { \
-	if (level & m88rs2000_debug) \
-		printk(KERN_DEBUG "m88rs2000-fe: " args); \
-} while (0)
-
-#define deb_info(args...)  dprintk(0x01, args)
-#define info(format, arg...) \
-	printk(KERN_INFO "m88rs2000-fe: " format "\n" , ## arg)
-
-static int m88rs2000_writereg(struct m88rs2000_state *state, u8 tuner,
-	u8 reg, u8 data)
-{
-	int ret;
-	u8 addr = (tuner == 0) ? state->config->tuner_addr :
-		state->config->demod_addr;
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = {
-		.addr = addr,
-		.flags = 0,
-		.buf = buf,
-		.len = 2
-	};
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-
-	if (ret != 1)
-		deb_info("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
-			"ret == %i)\n", __func__, reg, data, ret);
-
-	return (ret != 1) ? -EREMOTEIO : 0;
-}
-
-static int m88rs2000_demod_write(struct m88rs2000_state *state, u8 reg, u8 data)
-{
-	return m88rs2000_writereg(state, 1, reg, data);
-}
-
-static int m88rs2000_tuner_write(struct m88rs2000_state *state, u8 reg, u8 data)
-{
-	m88rs2000_demod_write(state, 0x81, 0x84);
-	udelay(10);
-	return m88rs2000_writereg(state, 0, reg, data);
-
-}
-
-static int m88rs2000_write(struct dvb_frontend *fe, const u8 buf[], int len)
-{
-	struct m88rs2000_state *state = fe->demodulator_priv;
-
-	if (len != 2)
-		return -EINVAL;
-
-	return m88rs2000_writereg(state, 1, buf[0], buf[1]);
-}
-
-static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 tuner, u8 reg)
-{
-	int ret;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
-	u8 addr = (tuner == 0) ? state->config->tuner_addr :
-		state->config->demod_addr;
-	struct i2c_msg msg[] = {
-		{
-			.addr = addr,
-			.flags = 0,
-			.buf = b0,
-			.len = 1
-		}, {
-			.addr = addr,
-			.flags = I2C_M_RD,
-			.buf = b1,
-			.len = 1
-		}
-	};
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2)
-		deb_info("%s: readreg error (reg == 0x%02x, ret == %i)\n",
-				__func__, reg, ret);
-
-	return b1[0];
-}
-
-static u8 m88rs2000_demod_read(struct m88rs2000_state *state, u8 reg)
-{
-	return m88rs2000_readreg(state, 1, reg);
-}
-
-static u8 m88rs2000_tuner_read(struct m88rs2000_state *state, u8 reg)
-{
-	m88rs2000_demod_write(state, 0x81, 0x85);
-	udelay(10);
-	return m88rs2000_readreg(state, 0, reg);
-}
-
-static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate)
-{
-	struct m88rs2000_state *state = fe->demodulator_priv;
-	int ret;
-	u32 temp;
-	u8 b[3];
-
-	if ((srate < 1000000) || (srate > 45000000))
-		return -EINVAL;
-
-	temp = srate / 1000;
-	temp *= 11831;
-	temp /= 68;
-	temp -= 3;
-
-	b[0] = (u8) (temp >> 16) & 0xff;
-	b[1] = (u8) (temp >> 8) & 0xff;
-	b[2] = (u8) temp & 0xff;
-	ret = m88rs2000_demod_write(state, 0x93, b[2]);
-	ret |= m88rs2000_demod_write(state, 0x94, b[1]);
-	ret |= m88rs2000_demod_write(state, 0x95, b[0]);
-
-	deb_info("m88rs2000: m88rs2000_set_symbolrate\n");
-	return ret;
-}
-
-static int m88rs2000_send_diseqc_msg(struct dvb_frontend *fe,
-				    struct dvb_diseqc_master_cmd *m)
-{
-	struct m88rs2000_state *state = fe->demodulator_priv;
-
-	int i;
-	u8 reg;
-	deb_info("%s\n", __func__);
-	m88rs2000_demod_write(state, 0x9a, 0x30);
-	reg = m88rs2000_demod_read(state, 0xb2);
-	reg &= 0x3f;
-	m88rs2000_demod_write(state, 0xb2, reg);
-	for (i = 0; i <  m->msg_len; i++)
-		m88rs2000_demod_write(state, 0xb3 + i, m->msg[i]);
-
-	reg = m88rs2000_demod_read(state, 0xb1);
-	reg &= 0x87;
-	reg |= ((m->msg_len - 1) << 3) | 0x07;
-	reg &= 0x7f;
-	m88rs2000_demod_write(state, 0xb1, reg);
-
-	for (i = 0; i < 15; i++) {
-		if ((m88rs2000_demod_read(state, 0xb1) & 0x40) == 0x0)
-			break;
-		msleep(20);
-	}
-
-	reg = m88rs2000_demod_read(state, 0xb1);
-	if ((reg & 0x40) > 0x0) {
-		reg &= 0x7f;
-		reg |= 0x40;
-		m88rs2000_demod_write(state, 0xb1, reg);
-	}
-
-	reg = m88rs2000_demod_read(state, 0xb2);
-	reg &= 0x3f;
-	reg |= 0x80;
-	m88rs2000_demod_write(state, 0xb2, reg);
-	m88rs2000_demod_write(state, 0x9a, 0xb0);
-
-
-	return 0;
-}
-
-static int m88rs2000_send_diseqc_burst(struct dvb_frontend *fe,
-						fe_sec_mini_cmd_t burst)
-{
-	struct m88rs2000_state *state = fe->demodulator_priv;
-	u8 reg0, reg1;
-	deb_info("%s\n", __func__);
-	m88rs2000_demod_write(state, 0x9a, 0x30);
-	msleep(50);
-	reg0 = m88rs2000_demod_read(state, 0xb1);
-	reg1 = m88rs2000_demod_read(state, 0xb2);
-	/* TODO complete this section */
-	m88rs2000_demod_write(state, 0xb2, reg1);
-	m88rs2000_demod_write(state, 0xb1, reg0);
-	m88rs2000_demod_write(state, 0x9a, 0xb0);
-
-	return 0;
-}
-
-static int m88rs2000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
-{
-	struct m88rs2000_state *state = fe->demodulator_priv;
-	u8 reg0, reg1;
-	m88rs2000_demod_write(state, 0x9a, 0x30);
-	reg0 = m88rs2000_demod_read(state, 0xb1);
-	reg1 = m88rs2000_demod_read(state, 0xb2);
-
-	reg1 &= 0x3f;
-
-	switch (tone) {
-	case SEC_TONE_ON:
-		reg0 |= 0x4;
-		reg0 &= 0xbc;
-		break;
-	case SEC_TONE_OFF:
-		reg1 |= 0x80;
-		break;
-	default:
-		break;
-	}
-	m88rs2000_demod_write(state, 0xb2, reg1);
-	m88rs2000_demod_write(state, 0xb1, reg0);
-	m88rs2000_demod_write(state, 0x9a, 0xb0);
-	return 0;
-}
-
-struct inittab {
-	u8 cmd;
-	u8 reg;
-	u8 val;
-};
-
-struct inittab m88rs2000_setup[] = {
-	{DEMOD_WRITE, 0x9a, 0x30},
-	{DEMOD_WRITE, 0x00, 0x01},
-	{WRITE_DELAY, 0x19, 0x00},
-	{DEMOD_WRITE, 0x00, 0x00},
-	{DEMOD_WRITE, 0x9a, 0xb0},
-	{DEMOD_WRITE, 0x81, 0xc1},
-	{TUNER_WRITE, 0x42, 0x73},
-	{TUNER_WRITE, 0x05, 0x07},
-	{TUNER_WRITE, 0x20, 0x27},
-	{TUNER_WRITE, 0x07, 0x02},
-	{TUNER_WRITE, 0x11, 0xff},
-	{TUNER_WRITE, 0x60, 0xf9},
-	{TUNER_WRITE, 0x08, 0x01},
-	{TUNER_WRITE, 0x00, 0x41},
-	{DEMOD_WRITE, 0x81, 0x81},
-	{DEMOD_WRITE, 0x86, 0xc6},
-	{DEMOD_WRITE, 0x9a, 0x30},
-	{DEMOD_WRITE, 0xf0, 0x22},
-	{DEMOD_WRITE, 0xf1, 0xbf},
-	{DEMOD_WRITE, 0xb0, 0x45},
-	{DEMOD_WRITE, 0xb2, 0x01}, /* set voltage pin always set 1*/
-	{DEMOD_WRITE, 0x9a, 0xb0},
-	{0xff, 0xaa, 0xff}
-};
-
-struct inittab m88rs2000_shutdown[] = {
-	{DEMOD_WRITE, 0x9a, 0x30},
-	{DEMOD_WRITE, 0xb0, 0x00},
-	{DEMOD_WRITE, 0xf1, 0x89},
-	{DEMOD_WRITE, 0x00, 0x01},
-	{DEMOD_WRITE, 0x9a, 0xb0},
-	{TUNER_WRITE, 0x00, 0x40},
-	{DEMOD_WRITE, 0x81, 0x81},
-	{0xff, 0xaa, 0xff}
-};
-
-struct inittab tuner_reset[] = {
-	{TUNER_WRITE, 0x42, 0x73},
-	{TUNER_WRITE, 0x05, 0x07},
-	{TUNER_WRITE, 0x20, 0x27},
-	{TUNER_WRITE, 0x07, 0x02},
-	{TUNER_WRITE, 0x11, 0xff},
-	{TUNER_WRITE, 0x60, 0xf9},
-	{TUNER_WRITE, 0x08, 0x01},
-	{TUNER_WRITE, 0x00, 0x41},
-	{0xff, 0xaa, 0xff}
-};
-
-struct inittab fe_reset[] = {
-	{DEMOD_WRITE, 0x00, 0x01},
-	{DEMOD_WRITE, 0xf1, 0xbf},
-	{DEMOD_WRITE, 0x00, 0x01},
-	{DEMOD_WRITE, 0x20, 0x81},
-	{DEMOD_WRITE, 0x21, 0x80},
-	{DEMOD_WRITE, 0x10, 0x33},
-	{DEMOD_WRITE, 0x11, 0x44},
-	{DEMOD_WRITE, 0x12, 0x07},
-	{DEMOD_WRITE, 0x18, 0x20},
-	{DEMOD_WRITE, 0x28, 0x04},
-	{DEMOD_WRITE, 0x29, 0x8e},
-	{DEMOD_WRITE, 0x3b, 0xff},
-	{DEMOD_WRITE, 0x32, 0x10},
-	{DEMOD_WRITE, 0x33, 0x02},
-	{DEMOD_WRITE, 0x34, 0x30},
-	{DEMOD_WRITE, 0x35, 0xff},
-	{DEMOD_WRITE, 0x38, 0x50},
-	{DEMOD_WRITE, 0x39, 0x68},
-	{DEMOD_WRITE, 0x3c, 0x7f},
-	{DEMOD_WRITE, 0x3d, 0x0f},
-	{DEMOD_WRITE, 0x45, 0x20},
-	{DEMOD_WRITE, 0x46, 0x24},
-	{DEMOD_WRITE, 0x47, 0x7c},
-	{DEMOD_WRITE, 0x48, 0x16},
-	{DEMOD_WRITE, 0x49, 0x04},
-	{DEMOD_WRITE, 0x4a, 0x01},
-	{DEMOD_WRITE, 0x4b, 0x78},
-	{DEMOD_WRITE, 0X4d, 0xd2},
-	{DEMOD_WRITE, 0x4e, 0x6d},
-	{DEMOD_WRITE, 0x50, 0x30},
-	{DEMOD_WRITE, 0x51, 0x30},
-	{DEMOD_WRITE, 0x54, 0x7b},
-	{DEMOD_WRITE, 0x56, 0x09},
-	{DEMOD_WRITE, 0x58, 0x59},
-	{DEMOD_WRITE, 0x59, 0x37},
-	{DEMOD_WRITE, 0x63, 0xfa},
-	{0xff, 0xaa, 0xff}
-};
-
-struct inittab fe_trigger[] = {
-	{DEMOD_WRITE, 0x97, 0x04},
-	{DEMOD_WRITE, 0x99, 0x77},
-	{DEMOD_WRITE, 0x9b, 0x64},
-	{DEMOD_WRITE, 0x9e, 0x00},
-	{DEMOD_WRITE, 0x9f, 0xf8},
-	{DEMOD_WRITE, 0xa0, 0x20},
-	{DEMOD_WRITE, 0xa1, 0xe0},
-	{DEMOD_WRITE, 0xa3, 0x38},
-	{DEMOD_WRITE, 0x98, 0xff},
-	{DEMOD_WRITE, 0xc0, 0x0f},
-	{DEMOD_WRITE, 0x89, 0x01},
-	{DEMOD_WRITE, 0x00, 0x00},
-	{WRITE_DELAY, 0x0a, 0x00},
-	{DEMOD_WRITE, 0x00, 0x01},
-	{DEMOD_WRITE, 0x00, 0x00},
-	{DEMOD_WRITE, 0x9a, 0xb0},
-	{0xff, 0xaa, 0xff}
-};
-
-static int m88rs2000_tab_set(struct m88rs2000_state *state,
-		struct inittab *tab)
-{
-	int ret = 0;
-	u8 i;
-	if (tab == NULL)
-		return -EINVAL;
-
-	for (i = 0; i < 255; i++) {
-		switch (tab[i].cmd) {
-		case 0x01:
-			ret = m88rs2000_demod_write(state, tab[i].reg,
-				tab[i].val);
-			break;
-		case 0x02:
-			ret = m88rs2000_tuner_write(state, tab[i].reg,
-				tab[i].val);
-			break;
-		case 0x10:
-			if (tab[i].reg > 0)
-				mdelay(tab[i].reg);
-			break;
-		case 0xff:
-			if (tab[i].reg == 0xaa && tab[i].val == 0xff)
-				return 0;
-		case 0x00:
-			break;
-		default:
-			return -EINVAL;
-		}
-		if (ret < 0)
-			return -ENODEV;
-	}
-	return 0;
-}
-
-static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
-{
-	struct m88rs2000_state *state = fe->demodulator_priv;
-	u8 data;
-
-	data = m88rs2000_demod_read(state, 0xb2);
-	data |= 0x03; /* bit0 V/H, bit1 off/on */
-
-	switch (volt) {
-	case SEC_VOLTAGE_18:
-		data &= ~0x03;
-		break;
-	case SEC_VOLTAGE_13:
-		data &= ~0x03;
-		data |= 0x01;
-		break;
-	case SEC_VOLTAGE_OFF:
-		break;
-	}
-
-	m88rs2000_demod_write(state, 0xb2, data);
-
-	return 0;
-}
-
-static int m88rs2000_startup(struct m88rs2000_state *state)
-{
-	int ret = 0;
-	u8 reg;
-
-	reg = m88rs2000_tuner_read(state, 0x00);
-	if ((reg & 0x40) == 0)
-		ret = -ENODEV;
-
-	return ret;
-}
-
-static int m88rs2000_init(struct dvb_frontend *fe)
-{
-	struct m88rs2000_state *state = fe->demodulator_priv;
-	int ret;
-
-	deb_info("m88rs2000: init chip\n");
-	/* Setup frontend from shutdown/cold */
-	ret = m88rs2000_tab_set(state, m88rs2000_setup);
-
-	return ret;
-}
-
-static int m88rs2000_sleep(struct dvb_frontend *fe)
-{
-	struct m88rs2000_state *state = fe->demodulator_priv;
-	int ret;
-	/* Shutdown the frondend */
-	ret = m88rs2000_tab_set(state, m88rs2000_shutdown);
-	return ret;
-}
-
-static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct m88rs2000_state *state = fe->demodulator_priv;
-	u8 reg = m88rs2000_demod_read(state, 0x8c);
-
-	*status = 0;
-
-	if ((reg & 0x7) == 0x7) {
-		*status = FE_HAS_CARRIER | FE_HAS_SIGNAL | FE_HAS_VITERBI
-			| FE_HAS_LOCK;
-		if (state->config->set_ts_params)
-			state->config->set_ts_params(fe, CALL_IS_READ);
-	}
-	return 0;
-}
-
-/* Extact code for these unknown but lmedm04 driver uses interupt callbacks */
-
-static int m88rs2000_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	deb_info("m88rs2000_read_ber %d\n", *ber);
-	*ber = 0;
-	return 0;
-}
-
-static int m88rs2000_read_signal_strength(struct dvb_frontend *fe,
-	u16 *strength)
-{
-	*strength = 0;
-	return 0;
-}
-
-static int m88rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	deb_info("m88rs2000_read_snr %d\n", *snr);
-	*snr = 0;
-	return 0;
-}
-
-static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	deb_info("m88rs2000_read_ber %d\n", *ucblocks);
-	*ucblocks = 0;
-	return 0;
-}
-
-static int m88rs2000_tuner_gate_ctrl(struct m88rs2000_state *state, u8 offset)
-{
-	int ret;
-	ret = m88rs2000_tuner_write(state, 0x51, 0x1f - offset);
-	ret |= m88rs2000_tuner_write(state, 0x51, 0x1f);
-	ret |= m88rs2000_tuner_write(state, 0x50, offset);
-	ret |= m88rs2000_tuner_write(state, 0x50, 0x00);
-	msleep(20);
-	return ret;
-}
-
-static int m88rs2000_set_tuner_rf(struct dvb_frontend *fe)
-{
-	struct m88rs2000_state *state = fe->demodulator_priv;
-	int reg;
-	reg = m88rs2000_tuner_read(state, 0x3d);
-	reg &= 0x7f;
-	if (reg < 0x16)
-		reg = 0xa1;
-	else if (reg == 0x16)
-		reg = 0x99;
-	else
-		reg = 0xf9;
-
-	m88rs2000_tuner_write(state, 0x60, reg);
-	reg = m88rs2000_tuner_gate_ctrl(state, 0x08);
-
-	if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	return reg;
-}
-
-static int m88rs2000_set_tuner(struct dvb_frontend *fe, u16 *offset)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct m88rs2000_state *state = fe->demodulator_priv;
-	int ret;
-	u32 frequency = c->frequency;
-	s32 offset_khz;
-	s32 tmp;
-	u32 symbol_rate = (c->symbol_rate / 1000);
-	u32 f3db, gdiv28;
-	u16 value, ndiv, lpf_coeff;
-	u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf;
-	u8 lo = 0x01, div4 = 0x0;
-
-	/* Reset Tuner */
-	ret = m88rs2000_tab_set(state, tuner_reset);
-
-	/* Calculate frequency divider */
-	if (frequency < 1060000) {
-		lo |= 0x10;
-		div4 = 0x1;
-		ndiv = (frequency * 14 * 4) / FE_CRYSTAL_KHZ;
-	} else
-		ndiv = (frequency * 14 * 2) / FE_CRYSTAL_KHZ;
-	ndiv = ndiv + ndiv % 2;
-	ndiv = ndiv - 1024;
-
-	ret = m88rs2000_tuner_write(state, 0x10, 0x80 | lo);
-
-	/* Set frequency divider */
-	ret |= m88rs2000_tuner_write(state, 0x01, (ndiv >> 8) & 0xf);
-	ret |= m88rs2000_tuner_write(state, 0x02, ndiv & 0xff);
-
-	ret |= m88rs2000_tuner_write(state, 0x03, 0x06);
-	ret |= m88rs2000_tuner_gate_ctrl(state, 0x10);
-	if (ret < 0)
-		return -ENODEV;
-
-	/* Tuner Frequency Range */
-	ret = m88rs2000_tuner_write(state, 0x10, lo);
-
-	ret |= m88rs2000_tuner_gate_ctrl(state, 0x08);
-
-	/* Tuner RF */
-	ret |= m88rs2000_set_tuner_rf(fe);
-
-	gdiv28 = (FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000;
-	ret |= m88rs2000_tuner_write(state, 0x04, gdiv28 & 0xff);
-	ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
-	if (ret < 0)
-		return -ENODEV;
-
-	value = m88rs2000_tuner_read(state, 0x26);
-
-	f3db = (symbol_rate * 135) / 200 + 2000;
-	f3db += FREQ_OFFSET_LOW_SYM_RATE;
-	if (f3db < 7000)
-		f3db = 7000;
-	if (f3db > 40000)
-		f3db = 40000;
-
-	gdiv28 = gdiv28 * 207 / (value * 2 + 151);
-	mlpf_max = gdiv28 * 135 / 100;
-	mlpf_min = gdiv28 * 78 / 100;
-	if (mlpf_max > 63)
-		mlpf_max = 63;
-
-	lpf_coeff = 2766;
-
-	nlpf = (f3db * gdiv28 * 2 / lpf_coeff /
-		(FE_CRYSTAL_KHZ / 1000)  + 1) / 2;
-	if (nlpf > 23)
-		nlpf = 23;
-	if (nlpf < 1)
-		nlpf = 1;
-
-	lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000)
-		* lpf_coeff * 2  / f3db + 1) / 2;
-
-	if (lpf_mxdiv < mlpf_min) {
-		nlpf++;
-		lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000)
-			* lpf_coeff * 2  / f3db + 1) / 2;
-	}
-
-	if (lpf_mxdiv > mlpf_max)
-		lpf_mxdiv = mlpf_max;
-
-	ret = m88rs2000_tuner_write(state, 0x04, lpf_mxdiv);
-	ret |= m88rs2000_tuner_write(state, 0x06, nlpf);
-
-	ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
-
-	ret |= m88rs2000_tuner_gate_ctrl(state, 0x01);
-
-	msleep(80);
-	/* calculate offset assuming 96000kHz*/
-	offset_khz = (ndiv - ndiv % 2 + 1024) * FE_CRYSTAL_KHZ
-		/ 14 / (div4 + 1) / 2;
-
-	offset_khz -= frequency;
-
-	tmp = offset_khz;
-	tmp *= 65536;
-
-	tmp = (2 * tmp + 96000) / (2 * 96000);
-	if (tmp < 0)
-		tmp += 65536;
-
-	*offset = tmp & 0xffff;
-
-	if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-
-	return (ret < 0) ? -EINVAL : 0;
-}
-
-static int m88rs2000_set_fec(struct m88rs2000_state *state,
-		fe_code_rate_t fec)
-{
-	u16 fec_set;
-	switch (fec) {
-	/* This is not confirmed kept for reference */
-/*	case FEC_1_2:
-		fec_set = 0x88;
-		break;
-	case FEC_2_3:
-		fec_set = 0x68;
-		break;
-	case FEC_3_4:
-		fec_set = 0x48;
-		break;
-	case FEC_5_6:
-		fec_set = 0x28;
-		break;
-	case FEC_7_8:
-		fec_set = 0x18;
-		break; */
-	case FEC_AUTO:
-	default:
-		fec_set = 0x08;
-	}
-	m88rs2000_demod_write(state, 0x76, fec_set);
-
-	return 0;
-}
-
-
-static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state)
-{
-	u8 reg;
-	m88rs2000_demod_write(state, 0x9a, 0x30);
-	reg = m88rs2000_demod_read(state, 0x76);
-	m88rs2000_demod_write(state, 0x9a, 0xb0);
-
-	switch (reg) {
-	case 0x88:
-		return FEC_1_2;
-	case 0x68:
-		return FEC_2_3;
-	case 0x48:
-		return FEC_3_4;
-	case 0x28:
-		return FEC_5_6;
-	case 0x18:
-		return FEC_7_8;
-	case 0x08:
-	default:
-		break;
-	}
-
-	return FEC_AUTO;
-}
-
-static int m88rs2000_set_frontend(struct dvb_frontend *fe)
-{
-	struct m88rs2000_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	fe_status_t status;
-	int i, ret;
-	u16 offset = 0;
-	u8 reg;
-
-	state->no_lock_count = 0;
-
-	if (c->delivery_system != SYS_DVBS) {
-			deb_info("%s: unsupported delivery "
-				"system selected (%d)\n",
-				__func__, c->delivery_system);
-			return -EOPNOTSUPP;
-	}
-
-	/* Set Tuner */
-	ret = m88rs2000_set_tuner(fe, &offset);
-	if (ret < 0)
-		return -ENODEV;
-
-	ret = m88rs2000_demod_write(state, 0x9a, 0x30);
-	/* Unknown usually 0xc6 sometimes 0xc1 */
-	reg = m88rs2000_demod_read(state, 0x86);
-	ret |= m88rs2000_demod_write(state, 0x86, reg);
-	/* Offset lower nibble always 0 */
-	ret |= m88rs2000_demod_write(state, 0x9c, (offset >> 8));
-	ret |= m88rs2000_demod_write(state, 0x9d, offset & 0xf0);
-
-
-	/* Reset Demod */
-	ret = m88rs2000_tab_set(state, fe_reset);
-	if (ret < 0)
-		return -ENODEV;
-
-	/* Unknown */
-	reg = m88rs2000_demod_read(state, 0x70);
-	ret = m88rs2000_demod_write(state, 0x70, reg);
-
-	/* Set FEC */
-	ret |= m88rs2000_set_fec(state, c->fec_inner);
-	ret |= m88rs2000_demod_write(state, 0x85, 0x1);
-	ret |= m88rs2000_demod_write(state, 0x8a, 0xbf);
-	ret |= m88rs2000_demod_write(state, 0x8d, 0x1e);
-	ret |= m88rs2000_demod_write(state, 0x90, 0xf1);
-	ret |= m88rs2000_demod_write(state, 0x91, 0x08);
-
-	if (ret < 0)
-		return -ENODEV;
-
-	/* Set Symbol Rate */
-	ret = m88rs2000_set_symbolrate(fe, c->symbol_rate);
-	if (ret < 0)
-		return -ENODEV;
-
-	/* Set up Demod */
-	ret = m88rs2000_tab_set(state, fe_trigger);
-	if (ret < 0)
-		return -ENODEV;
-
-	for (i = 0; i < 25; i++) {
-		reg = m88rs2000_demod_read(state, 0x8c);
-		if ((reg & 0x7) == 0x7) {
-			status = FE_HAS_LOCK;
-			break;
-		}
-		state->no_lock_count++;
-		if (state->no_lock_count == 15) {
-			reg = m88rs2000_demod_read(state, 0x70);
-			reg ^= 0x4;
-			m88rs2000_demod_write(state, 0x70, reg);
-			state->no_lock_count = 0;
-		}
-		if (state->no_lock_count == 20)
-			m88rs2000_set_tuner_rf(fe);
-		msleep(20);
-	}
-
-	if (status & FE_HAS_LOCK) {
-		state->fec_inner = m88rs2000_get_fec(state);
-		/* Uknown suspect SNR level */
-		reg = m88rs2000_demod_read(state, 0x65);
-	}
-
-	state->tuner_frequency = c->frequency;
-	state->symbol_rate = c->symbol_rate;
-	return 0;
-}
-
-static int m88rs2000_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct m88rs2000_state *state = fe->demodulator_priv;
-	c->fec_inner = state->fec_inner;
-	c->frequency = state->tuner_frequency;
-	c->symbol_rate = state->symbol_rate;
-	return 0;
-}
-
-static int m88rs2000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct m88rs2000_state *state = fe->demodulator_priv;
-
-	if (enable)
-		m88rs2000_demod_write(state, 0x81, 0x84);
-	else
-		m88rs2000_demod_write(state, 0x81, 0x81);
-	udelay(10);
-	return 0;
-}
-
-static void m88rs2000_release(struct dvb_frontend *fe)
-{
-	struct m88rs2000_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops m88rs2000_ops = {
-	.delsys = { SYS_DVBS },
-	.info = {
-		.name			= "M88RS2000 DVB-S",
-		.frequency_min		= 950000,
-		.frequency_max		= 2150000,
-		.frequency_stepsize	= 1000,	 /* kHz for QPSK frontends */
-		.frequency_tolerance	= 5000,
-		.symbol_rate_min	= 1000000,
-		.symbol_rate_max	= 45000000,
-		.symbol_rate_tolerance	= 500,	/* ppm */
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
-		      FE_CAN_QPSK |
-		      FE_CAN_FEC_AUTO
-	},
-
-	.release = m88rs2000_release,
-	.init = m88rs2000_init,
-	.sleep = m88rs2000_sleep,
-	.write = m88rs2000_write,
-	.i2c_gate_ctrl = m88rs2000_i2c_gate_ctrl,
-	.read_status = m88rs2000_read_status,
-	.read_ber = m88rs2000_read_ber,
-	.read_signal_strength = m88rs2000_read_signal_strength,
-	.read_snr = m88rs2000_read_snr,
-	.read_ucblocks = m88rs2000_read_ucblocks,
-	.diseqc_send_master_cmd = m88rs2000_send_diseqc_msg,
-	.diseqc_send_burst = m88rs2000_send_diseqc_burst,
-	.set_tone = m88rs2000_set_tone,
-	.set_voltage = m88rs2000_set_voltage,
-
-	.set_frontend = m88rs2000_set_frontend,
-	.get_frontend = m88rs2000_get_frontend,
-};
-
-struct dvb_frontend *m88rs2000_attach(const struct m88rs2000_config *config,
-				    struct i2c_adapter *i2c)
-{
-	struct m88rs2000_state *state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct m88rs2000_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->tuner_frequency = 0;
-	state->symbol_rate = 0;
-	state->fec_inner = 0;
-
-	if (m88rs2000_startup(state) < 0)
-		goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &m88rs2000_ops,
-			sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-
-	return NULL;
-}
-EXPORT_SYMBOL(m88rs2000_attach);
-
-MODULE_DESCRIPTION("M88RS2000 DVB-S Demodulator driver");
-MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("1.13");
-
diff --git a/drivers/media/dvb/frontends/m88rs2000.h b/drivers/media/dvb/frontends/m88rs2000.h
deleted file mode 100644
index 59acdb6..0000000
--- a/drivers/media/dvb/frontends/m88rs2000.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
-	Driver for M88RS2000 demodulator
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef M88RS2000_H
-#define M88RS2000_H
-
-#include <linux/dvb/frontend.h>
-#include "dvb_frontend.h"
-
-struct m88rs2000_config {
-	/* Demodulator i2c address */
-	u8 demod_addr;
-	/* Tuner address */
-	u8 tuner_addr;
-
-	u8 *inittab;
-
-	/* minimum delay before retuning */
-	int min_delay_ms;
-
-	int (*set_ts_params)(struct dvb_frontend *, int);
-};
-
-enum {
-	CALL_IS_SET_FRONTEND = 0x0,
-	CALL_IS_READ,
-};
-
-#if defined(CONFIG_DVB_M88RS2000) || (defined(CONFIG_DVB_M88RS2000_MODULE) && \
-							defined(MODULE))
-extern struct dvb_frontend *m88rs2000_attach(
-	const struct m88rs2000_config *config, struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *m88rs2000_attach(
-	const struct m88rs2000_config *config, struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_M88RS2000 */
-
-#define FE_CRYSTAL_KHZ 27000
-#define FREQ_OFFSET_LOW_SYM_RATE 3000
-
-enum {
-	DEMOD_WRITE = 0x1,
-	TUNER_WRITE,
-	WRITE_DELAY = 0x10,
-};
-#endif /* M88RS2000_H */
diff --git a/drivers/media/dvb/frontends/mb86a16.c b/drivers/media/dvb/frontends/mb86a16.c
deleted file mode 100644
index 9ae40ab..0000000
--- a/drivers/media/dvb/frontends/mb86a16.c
+++ /dev/null
@@ -1,1878 +0,0 @@
-/*
-	Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "mb86a16.h"
-#include "mb86a16_priv.h"
-
-unsigned int verbose = 5;
-module_param(verbose, int, 0644);
-
-#define ABS(x)		((x) < 0 ? (-x) : (x))
-
-struct mb86a16_state {
-	struct i2c_adapter		*i2c_adap;
-	const struct mb86a16_config	*config;
-	struct dvb_frontend		frontend;
-
-	/* tuning parameters */
-	int				frequency;
-	int				srate;
-
-	/* Internal stuff */
-	int				master_clk;
-	int				deci;
-	int				csel;
-	int				rsel;
-};
-
-#define MB86A16_ERROR		0
-#define MB86A16_NOTICE		1
-#define MB86A16_INFO		2
-#define MB86A16_DEBUG		3
-
-#define dprintk(x, y, z, format, arg...) do {						\
-	if (z) {									\
-		if	((x > MB86A16_ERROR) && (x > y))				\
-			printk(KERN_ERR "%s: " format "\n", __func__, ##arg);		\
-		else if ((x > MB86A16_NOTICE) && (x > y))				\
-			printk(KERN_NOTICE "%s: " format "\n", __func__, ##arg);	\
-		else if ((x > MB86A16_INFO) && (x > y))					\
-			printk(KERN_INFO "%s: " format "\n", __func__, ##arg);		\
-		else if ((x > MB86A16_DEBUG) && (x > y))				\
-			printk(KERN_DEBUG "%s: " format "\n", __func__, ##arg);		\
-	} else {									\
-		if (x > y)								\
-			printk(format, ##arg);						\
-	}										\
-} while (0)
-
-#define TRACE_IN	dprintk(verbose, MB86A16_DEBUG, 1, "-->()")
-#define TRACE_OUT	dprintk(verbose, MB86A16_DEBUG, 1, "()-->")
-
-static int mb86a16_write(struct mb86a16_state *state, u8 reg, u8 val)
-{
-	int ret;
-	u8 buf[] = { reg, val };
-
-	struct i2c_msg msg = {
-		.addr = state->config->demod_address,
-		.flags = 0,
-		.buf = buf,
-		.len = 2
-	};
-
-	dprintk(verbose, MB86A16_DEBUG, 1,
-		"writing to [0x%02x],Reg[0x%02x],Data[0x%02x]",
-		state->config->demod_address, buf[0], buf[1]);
-
-	ret = i2c_transfer(state->i2c_adap, &msg, 1);
-
-	return (ret != 1) ? -EREMOTEIO : 0;
-}
-
-static int mb86a16_read(struct mb86a16_state *state, u8 reg, u8 *val)
-{
-	int ret;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
-
-	struct i2c_msg msg[] = {
-		{
-			.addr = state->config->demod_address,
-			.flags = 0,
-			.buf = b0,
-			.len = 1
-		}, {
-			.addr = state->config->demod_address,
-			.flags = I2C_M_RD,
-			.buf = b1,
-			.len = 1
-		}
-	};
-	ret = i2c_transfer(state->i2c_adap, msg, 2);
-	if (ret != 2) {
-		dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=0x%i)",
-			reg, ret);
-
-		return -EREMOTEIO;
-	}
-	*val = b1[0];
-
-	return ret;
-}
-
-static int CNTM_set(struct mb86a16_state *state,
-		    unsigned char timint1,
-		    unsigned char timint2,
-		    unsigned char cnext)
-{
-	unsigned char val;
-
-	val = (timint1 << 4) | (timint2 << 2) | cnext;
-	if (mb86a16_write(state, MB86A16_CNTMR, val) < 0)
-		goto err;
-
-	return 0;
-
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-}
-
-static int smrt_set(struct mb86a16_state *state, int rate)
-{
-	int tmp ;
-	int m ;
-	unsigned char STOFS0, STOFS1;
-
-	m = 1 << state->deci;
-	tmp = (8192 * state->master_clk - 2 * m * rate * 8192 + state->master_clk / 2) / state->master_clk;
-
-	STOFS0 = tmp & 0x0ff;
-	STOFS1 = (tmp & 0xf00) >> 8;
-
-	if (mb86a16_write(state, MB86A16_SRATE1, (state->deci << 2) |
-				       (state->csel << 1) |
-					state->rsel) < 0)
-		goto err;
-	if (mb86a16_write(state, MB86A16_SRATE2, STOFS0) < 0)
-		goto err;
-	if (mb86a16_write(state, MB86A16_SRATE3, STOFS1) < 0)
-		goto err;
-
-	return 0;
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -1;
-}
-
-static int srst(struct mb86a16_state *state)
-{
-	if (mb86a16_write(state, MB86A16_RESET, 0x04) < 0)
-		goto err;
-
-	return 0;
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-
-}
-
-static int afcex_data_set(struct mb86a16_state *state,
-			  unsigned char AFCEX_L,
-			  unsigned char AFCEX_H)
-{
-	if (mb86a16_write(state, MB86A16_AFCEXL, AFCEX_L) < 0)
-		goto err;
-	if (mb86a16_write(state, MB86A16_AFCEXH, AFCEX_H) < 0)
-		goto err;
-
-	return 0;
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-
-	return -1;
-}
-
-static int afcofs_data_set(struct mb86a16_state *state,
-			   unsigned char AFCEX_L,
-			   unsigned char AFCEX_H)
-{
-	if (mb86a16_write(state, 0x58, AFCEX_L) < 0)
-		goto err;
-	if (mb86a16_write(state, 0x59, AFCEX_H) < 0)
-		goto err;
-
-	return 0;
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-}
-
-static int stlp_set(struct mb86a16_state *state,
-		    unsigned char STRAS,
-		    unsigned char STRBS)
-{
-	if (mb86a16_write(state, MB86A16_STRFILTCOEF1, (STRBS << 3) | (STRAS)) < 0)
-		goto err;
-
-	return 0;
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-}
-
-static int Vi_set(struct mb86a16_state *state, unsigned char ETH, unsigned char VIA)
-{
-	if (mb86a16_write(state, MB86A16_VISET2, 0x04) < 0)
-		goto err;
-	if (mb86a16_write(state, MB86A16_VISET3, 0xf5) < 0)
-		goto err;
-
-	return 0;
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-}
-
-static int initial_set(struct mb86a16_state *state)
-{
-	if (stlp_set(state, 5, 7))
-		goto err;
-
-	udelay(100);
-	if (afcex_data_set(state, 0, 0))
-		goto err;
-
-	udelay(100);
-	if (afcofs_data_set(state, 0, 0))
-		goto err;
-
-	udelay(100);
-	if (mb86a16_write(state, MB86A16_CRLFILTCOEF1, 0x16) < 0)
-		goto err;
-	if (mb86a16_write(state, 0x2f, 0x21) < 0)
-		goto err;
-	if (mb86a16_write(state, MB86A16_VIMAG, 0x38) < 0)
-		goto err;
-	if (mb86a16_write(state, MB86A16_FAGCS1, 0x00) < 0)
-		goto err;
-	if (mb86a16_write(state, MB86A16_FAGCS2, 0x1c) < 0)
-		goto err;
-	if (mb86a16_write(state, MB86A16_FAGCS3, 0x20) < 0)
-		goto err;
-	if (mb86a16_write(state, MB86A16_FAGCS4, 0x1e) < 0)
-		goto err;
-	if (mb86a16_write(state, MB86A16_FAGCS5, 0x23) < 0)
-		goto err;
-	if (mb86a16_write(state, 0x54, 0xff) < 0)
-		goto err;
-	if (mb86a16_write(state, MB86A16_TSOUT, 0x00) < 0)
-		goto err;
-
-	return 0;
-
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-}
-
-static int S01T_set(struct mb86a16_state *state,
-		    unsigned char s1t,
-		    unsigned s0t)
-{
-	if (mb86a16_write(state, 0x33, (s1t << 3) | s0t) < 0)
-		goto err;
-
-	return 0;
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-}
-
-
-static int EN_set(struct mb86a16_state *state,
-		  int cren,
-		  int afcen)
-{
-	unsigned char val;
-
-	val = 0x7a | (cren << 7) | (afcen << 2);
-	if (mb86a16_write(state, 0x49, val) < 0)
-		goto err;
-
-	return 0;
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-}
-
-static int AFCEXEN_set(struct mb86a16_state *state,
-		       int afcexen,
-		       int smrt)
-{
-	unsigned char AFCA ;
-
-	if (smrt > 18875)
-		AFCA = 4;
-	else if (smrt > 9375)
-		AFCA = 3;
-	else if (smrt > 2250)
-		AFCA = 2;
-	else
-		AFCA = 1;
-
-	if (mb86a16_write(state, 0x2a, 0x02 | (afcexen << 5) | (AFCA << 2)) < 0)
-		goto err;
-
-	return 0;
-
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-}
-
-static int DAGC_data_set(struct mb86a16_state *state,
-			 unsigned char DAGCA,
-			 unsigned char DAGCW)
-{
-	if (mb86a16_write(state, 0x2d, (DAGCA << 3) | DAGCW) < 0)
-		goto err;
-
-	return 0;
-
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-}
-
-static void smrt_info_get(struct mb86a16_state *state, int rate)
-{
-	if (rate >= 37501) {
-		state->deci = 0; state->csel = 0; state->rsel = 0;
-	} else if (rate >= 30001) {
-		state->deci = 0; state->csel = 0; state->rsel = 1;
-	} else if (rate >= 26251) {
-		state->deci = 0; state->csel = 1; state->rsel = 0;
-	} else if (rate >= 22501) {
-		state->deci = 0; state->csel = 1; state->rsel = 1;
-	} else if (rate >= 18751) {
-		state->deci = 1; state->csel = 0; state->rsel = 0;
-	} else if (rate >= 15001) {
-		state->deci = 1; state->csel = 0; state->rsel = 1;
-	} else if (rate >= 13126) {
-		state->deci = 1; state->csel = 1; state->rsel = 0;
-	} else if (rate >= 11251) {
-		state->deci = 1; state->csel = 1; state->rsel = 1;
-	} else if (rate >= 9376) {
-		state->deci = 2; state->csel = 0; state->rsel = 0;
-	} else if (rate >= 7501) {
-		state->deci = 2; state->csel = 0; state->rsel = 1;
-	} else if (rate >= 6563) {
-		state->deci = 2; state->csel = 1; state->rsel = 0;
-	} else if (rate >= 5626) {
-		state->deci = 2; state->csel = 1; state->rsel = 1;
-	} else if (rate >= 4688) {
-		state->deci = 3; state->csel = 0; state->rsel = 0;
-	} else if (rate >= 3751) {
-		state->deci = 3; state->csel = 0; state->rsel = 1;
-	} else if (rate >= 3282) {
-		state->deci = 3; state->csel = 1; state->rsel = 0;
-	} else if (rate >= 2814) {
-		state->deci = 3; state->csel = 1; state->rsel = 1;
-	} else if (rate >= 2344) {
-		state->deci = 4; state->csel = 0; state->rsel = 0;
-	} else if (rate >= 1876) {
-		state->deci = 4; state->csel = 0; state->rsel = 1;
-	} else if (rate >= 1641) {
-		state->deci = 4; state->csel = 1; state->rsel = 0;
-	} else if (rate >= 1407) {
-		state->deci = 4; state->csel = 1; state->rsel = 1;
-	} else if (rate >= 1172) {
-		state->deci = 5; state->csel = 0; state->rsel = 0;
-	} else if (rate >=  939) {
-		state->deci = 5; state->csel = 0; state->rsel = 1;
-	} else if (rate >=  821) {
-		state->deci = 5; state->csel = 1; state->rsel = 0;
-	} else {
-		state->deci = 5; state->csel = 1; state->rsel = 1;
-	}
-
-	if (state->csel == 0)
-		state->master_clk = 92000;
-	else
-		state->master_clk = 61333;
-
-}
-
-static int signal_det(struct mb86a16_state *state,
-		      int smrt,
-		      unsigned char *SIG)
-{
-
-	int ret ;
-	int smrtd ;
-	int wait_sym ;
-
-	u32 wait_t;
-	unsigned char S[3] ;
-	int i ;
-
-	if (*SIG > 45) {
-		if (CNTM_set(state, 2, 1, 2) < 0) {
-			dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
-			return -1;
-		}
-		wait_sym = 40000;
-	} else {
-		if (CNTM_set(state, 3, 1, 2) < 0) {
-			dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
-			return -1;
-		}
-		wait_sym = 80000;
-	}
-	for (i = 0; i < 3; i++) {
-		if (i == 0)
-			smrtd = smrt * 98 / 100;
-		else if (i == 1)
-			smrtd = smrt;
-		else
-			smrtd = smrt * 102 / 100;
-		smrt_info_get(state, smrtd);
-		smrt_set(state, smrtd);
-		srst(state);
-		wait_t = (wait_sym + 99 * smrtd / 100) / smrtd;
-		if (wait_t == 0)
-			wait_t = 1;
-		msleep_interruptible(10);
-		if (mb86a16_read(state, 0x37, &(S[i])) != 2) {
-			dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-			return -EREMOTEIO;
-		}
-	}
-	if ((S[1] > S[0] * 112 / 100) &&
-	    (S[1] > S[2] * 112 / 100)) {
-
-		ret = 1;
-	} else {
-		ret = 0;
-	}
-	*SIG = S[1];
-
-	if (CNTM_set(state, 0, 1, 2) < 0) {
-		dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
-		return -1;
-	}
-
-	return ret;
-}
-
-static int rf_val_set(struct mb86a16_state *state,
-		      int f,
-		      int smrt,
-		      unsigned char R)
-{
-	unsigned char C, F, B;
-	int M;
-	unsigned char rf_val[5];
-	int ack = -1;
-
-	if (smrt > 37750)
-		C = 1;
-	else if (smrt > 18875)
-		C = 2;
-	else if (smrt > 5500)
-		C = 3;
-	else
-		C = 4;
-
-	if (smrt > 30500)
-		F = 3;
-	else if (smrt > 9375)
-		F = 1;
-	else if (smrt > 4625)
-		F = 0;
-	else
-		F = 2;
-
-	if (f < 1060)
-		B = 0;
-	else if (f < 1175)
-		B = 1;
-	else if (f < 1305)
-		B = 2;
-	else if (f < 1435)
-		B = 3;
-	else if (f < 1570)
-		B = 4;
-	else if (f < 1715)
-		B = 5;
-	else if (f < 1845)
-		B = 6;
-	else if (f < 1980)
-		B = 7;
-	else if (f < 2080)
-		B = 8;
-	else
-		B = 9;
-
-	M = f * (1 << R) / 2;
-
-	rf_val[0] = 0x01 | (C << 3) | (F << 1);
-	rf_val[1] = (R << 5) | ((M & 0x1f000) >> 12);
-	rf_val[2] = (M & 0x00ff0) >> 4;
-	rf_val[3] = ((M & 0x0000f) << 4) | B;
-
-	/* Frequency Set */
-	if (mb86a16_write(state, 0x21, rf_val[0]) < 0)
-		ack = 0;
-	if (mb86a16_write(state, 0x22, rf_val[1]) < 0)
-		ack = 0;
-	if (mb86a16_write(state, 0x23, rf_val[2]) < 0)
-		ack = 0;
-	if (mb86a16_write(state, 0x24, rf_val[3]) < 0)
-		ack = 0;
-	if (mb86a16_write(state, 0x25, 0x01) < 0)
-		ack = 0;
-	if (ack == 0) {
-		dprintk(verbose, MB86A16_ERROR, 1, "RF Setup - I2C transfer error");
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static int afcerr_chk(struct mb86a16_state *state)
-{
-	unsigned char AFCM_L, AFCM_H ;
-	int AFCM ;
-	int afcm, afcerr ;
-
-	if (mb86a16_read(state, 0x0e, &AFCM_L) != 2)
-		goto err;
-	if (mb86a16_read(state, 0x0f, &AFCM_H) != 2)
-		goto err;
-
-	AFCM = (AFCM_H << 8) + AFCM_L;
-
-	if (AFCM > 2048)
-		afcm = AFCM - 4096;
-	else
-		afcm = AFCM;
-	afcerr = afcm * state->master_clk / 8192;
-
-	return afcerr;
-
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-}
-
-static int dagcm_val_get(struct mb86a16_state *state)
-{
-	int DAGCM;
-	unsigned char DAGCM_H, DAGCM_L;
-
-	if (mb86a16_read(state, 0x45, &DAGCM_L) != 2)
-		goto err;
-	if (mb86a16_read(state, 0x46, &DAGCM_H) != 2)
-		goto err;
-
-	DAGCM = (DAGCM_H << 8) + DAGCM_L;
-
-	return DAGCM;
-
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-}
-
-static int mb86a16_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	u8 stat, stat2;
-	struct mb86a16_state *state = fe->demodulator_priv;
-
-	*status = 0;
-
-	if (mb86a16_read(state, MB86A16_SIG1, &stat) != 2)
-		goto err;
-	if (mb86a16_read(state, MB86A16_SIG2, &stat2) != 2)
-		goto err;
-	if ((stat > 25) && (stat2 > 25))
-		*status |= FE_HAS_SIGNAL;
-	if ((stat > 45) && (stat2 > 45))
-		*status |= FE_HAS_CARRIER;
-
-	if (mb86a16_read(state, MB86A16_STATUS, &stat) != 2)
-		goto err;
-
-	if (stat & 0x01)
-		*status |= FE_HAS_SYNC;
-	if (stat & 0x01)
-		*status |= FE_HAS_VITERBI;
-
-	if (mb86a16_read(state, MB86A16_FRAMESYNC, &stat) != 2)
-		goto err;
-
-	if ((stat & 0x0f) && (*status & FE_HAS_VITERBI))
-		*status |= FE_HAS_LOCK;
-
-	return 0;
-
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-}
-
-static int sync_chk(struct mb86a16_state *state,
-		    unsigned char *VIRM)
-{
-	unsigned char val;
-	int sync;
-
-	if (mb86a16_read(state, 0x0d, &val) != 2)
-		goto err;
-
-	dprintk(verbose, MB86A16_INFO, 1, "Status = %02x,", val);
-	sync = val & 0x01;
-	*VIRM = (val & 0x1c) >> 2;
-
-	return sync;
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-
-}
-
-static int freqerr_chk(struct mb86a16_state *state,
-		       int fTP,
-		       int smrt,
-		       int unit)
-{
-	unsigned char CRM, AFCML, AFCMH;
-	unsigned char temp1, temp2, temp3;
-	int crm, afcm, AFCM;
-	int crrerr, afcerr;		/* kHz */
-	int frqerr;			/* MHz */
-	int afcen, afcexen = 0;
-	int R, M, fOSC, fOSC_OFS;
-
-	if (mb86a16_read(state, 0x43, &CRM) != 2)
-		goto err;
-
-	if (CRM > 127)
-		crm = CRM - 256;
-	else
-		crm = CRM;
-
-	crrerr = smrt * crm / 256;
-	if (mb86a16_read(state, 0x49, &temp1) != 2)
-		goto err;
-
-	afcen = (temp1 & 0x04) >> 2;
-	if (afcen == 0) {
-		if (mb86a16_read(state, 0x2a, &temp1) != 2)
-			goto err;
-		afcexen = (temp1 & 0x20) >> 5;
-	}
-
-	if (afcen == 1) {
-		if (mb86a16_read(state, 0x0e, &AFCML) != 2)
-			goto err;
-		if (mb86a16_read(state, 0x0f, &AFCMH) != 2)
-			goto err;
-	} else if (afcexen == 1) {
-		if (mb86a16_read(state, 0x2b, &AFCML) != 2)
-			goto err;
-		if (mb86a16_read(state, 0x2c, &AFCMH) != 2)
-			goto err;
-	}
-	if ((afcen == 1) || (afcexen == 1)) {
-		smrt_info_get(state, smrt);
-		AFCM = ((AFCMH & 0x01) << 8) + AFCML;
-		if (AFCM > 255)
-			afcm = AFCM - 512;
-		else
-			afcm = AFCM;
-
-		afcerr = afcm * state->master_clk / 8192;
-	} else
-		afcerr = 0;
-
-	if (mb86a16_read(state, 0x22, &temp1) != 2)
-		goto err;
-	if (mb86a16_read(state, 0x23, &temp2) != 2)
-		goto err;
-	if (mb86a16_read(state, 0x24, &temp3) != 2)
-		goto err;
-
-	R = (temp1 & 0xe0) >> 5;
-	M = ((temp1 & 0x1f) << 12) + (temp2 << 4) + (temp3 >> 4);
-	if (R == 0)
-		fOSC = 2 * M;
-	else
-		fOSC = M;
-
-	fOSC_OFS = fOSC - fTP;
-
-	if (unit == 0) {	/* MHz */
-		if (crrerr + afcerr + fOSC_OFS * 1000 >= 0)
-			frqerr = (crrerr + afcerr + fOSC_OFS * 1000 + 500) / 1000;
-		else
-			frqerr = (crrerr + afcerr + fOSC_OFS * 1000 - 500) / 1000;
-	} else {	/* kHz */
-		frqerr = crrerr + afcerr + fOSC_OFS * 1000;
-	}
-
-	return frqerr;
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-}
-
-static unsigned char vco_dev_get(struct mb86a16_state *state, int smrt)
-{
-	unsigned char R;
-
-	if (smrt > 9375)
-		R = 0;
-	else
-		R = 1;
-
-	return R;
-}
-
-static void swp_info_get(struct mb86a16_state *state,
-			 int fOSC_start,
-			 int smrt,
-			 int v, int R,
-			 int swp_ofs,
-			 int *fOSC,
-			 int *afcex_freq,
-			 unsigned char *AFCEX_L,
-			 unsigned char *AFCEX_H)
-{
-	int AFCEX ;
-	int crnt_swp_freq ;
-
-	crnt_swp_freq = fOSC_start * 1000 + v * swp_ofs;
-
-	if (R == 0)
-		*fOSC = (crnt_swp_freq + 1000) / 2000 * 2;
-	else
-		*fOSC = (crnt_swp_freq + 500) / 1000;
-
-	if (*fOSC >= crnt_swp_freq)
-		*afcex_freq = *fOSC * 1000 - crnt_swp_freq;
-	else
-		*afcex_freq = crnt_swp_freq - *fOSC * 1000;
-
-	AFCEX = *afcex_freq * 8192 / state->master_clk;
-	*AFCEX_L =  AFCEX & 0x00ff;
-	*AFCEX_H = (AFCEX & 0x0f00) >> 8;
-}
-
-
-static int swp_freq_calcuation(struct mb86a16_state *state, int i, int v, int *V,  int vmax, int vmin,
-			       int SIGMIN, int fOSC, int afcex_freq, int swp_ofs, unsigned char *SIG1)
-{
-	int swp_freq ;
-
-	if ((i % 2 == 1) && (v <= vmax)) {
-		/* positive v (case 1) */
-		if ((v - 1 == vmin)				&&
-		    (*(V + 30 + v) >= 0)			&&
-		    (*(V + 30 + v - 1) >= 0)			&&
-		    (*(V + 30 + v - 1) > *(V + 30 + v))		&&
-		    (*(V + 30 + v - 1) > SIGMIN)) {
-
-			swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
-			*SIG1 = *(V + 30 + v - 1);
-		} else if ((v == vmax)				&&
-			   (*(V + 30 + v) >= 0)			&&
-			   (*(V + 30 + v - 1) >= 0)		&&
-			   (*(V + 30 + v) > *(V + 30 + v - 1))	&&
-			   (*(V + 30 + v) > SIGMIN)) {
-			/* (case 2) */
-			swp_freq = fOSC * 1000 + afcex_freq;
-			*SIG1 = *(V + 30 + v);
-		} else if ((*(V + 30 + v) > 0)			&&
-			   (*(V + 30 + v - 1) > 0)		&&
-			   (*(V + 30 + v - 2) > 0)		&&
-			   (*(V + 30 + v - 3) > 0)		&&
-			   (*(V + 30 + v - 1) > *(V + 30 + v))	&&
-			   (*(V + 30 + v - 2) > *(V + 30 + v - 3)) &&
-			   ((*(V + 30 + v - 1) > SIGMIN)	||
-			   (*(V + 30 + v - 2) > SIGMIN))) {
-			/* (case 3) */
-			if (*(V + 30 + v - 1) >= *(V + 30 + v - 2)) {
-				swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
-				*SIG1 = *(V + 30 + v - 1);
-			} else {
-				swp_freq = fOSC * 1000 + afcex_freq - swp_ofs * 2;
-				*SIG1 = *(V + 30 + v - 2);
-			}
-		} else if ((v == vmax)				&&
-			   (*(V + 30 + v) >= 0)			&&
-			   (*(V + 30 + v - 1) >= 0)		&&
-			   (*(V + 30 + v - 2) >= 0)		&&
-			   (*(V + 30 + v) > *(V + 30 + v - 2))	&&
-			   (*(V + 30 + v - 1) > *(V + 30 + v - 2)) &&
-			   ((*(V + 30 + v) > SIGMIN)		||
-			   (*(V + 30 + v - 1) > SIGMIN))) {
-			/* (case 4) */
-			if (*(V + 30 + v) >= *(V + 30 + v - 1)) {
-				swp_freq = fOSC * 1000 + afcex_freq;
-				*SIG1 = *(V + 30 + v);
-			} else {
-				swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
-				*SIG1 = *(V + 30 + v - 1);
-			}
-		} else  {
-			swp_freq = -1 ;
-		}
-	} else if ((i % 2 == 0) && (v >= vmin)) {
-		/* Negative v (case 1) */
-		if ((*(V + 30 + v) > 0)				&&
-		    (*(V + 30 + v + 1) > 0)			&&
-		    (*(V + 30 + v + 2) > 0)			&&
-		    (*(V + 30 + v + 1) > *(V + 30 + v))		&&
-		    (*(V + 30 + v + 1) > *(V + 30 + v + 2))	&&
-		    (*(V + 30 + v + 1) > SIGMIN)) {
-
-			swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
-			*SIG1 = *(V + 30 + v + 1);
-		} else if ((v + 1 == vmax)			&&
-			   (*(V + 30 + v) >= 0)			&&
-			   (*(V + 30 + v + 1) >= 0)		&&
-			   (*(V + 30 + v + 1) > *(V + 30 + v))	&&
-			   (*(V + 30 + v + 1) > SIGMIN)) {
-			/* (case 2) */
-			swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
-			*SIG1 = *(V + 30 + v);
-		} else if ((v == vmin)				&&
-			   (*(V + 30 + v) > 0)			&&
-			   (*(V + 30 + v + 1) > 0)		&&
-			   (*(V + 30 + v + 2) > 0)		&&
-			   (*(V + 30 + v) > *(V + 30 + v + 1))	&&
-			   (*(V + 30 + v) > *(V + 30 + v + 2))	&&
-			   (*(V + 30 + v) > SIGMIN)) {
-			/* (case 3) */
-			swp_freq = fOSC * 1000 + afcex_freq;
-			*SIG1 = *(V + 30 + v);
-		} else if ((*(V + 30 + v) >= 0)			&&
-			   (*(V + 30 + v + 1) >= 0)		&&
-			   (*(V + 30 + v + 2) >= 0)		&&
-			   (*(V + 30 + v + 3) >= 0)		&&
-			   (*(V + 30 + v + 1) > *(V + 30 + v))	&&
-			   (*(V + 30 + v + 2) > *(V + 30 + v + 3)) &&
-			   ((*(V + 30 + v + 1) > SIGMIN)	||
-			    (*(V + 30 + v + 2) > SIGMIN))) {
-			/* (case 4) */
-			if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) {
-				swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
-				*SIG1 = *(V + 30 + v + 1);
-			} else {
-				swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2;
-				*SIG1 = *(V + 30 + v + 2);
-			}
-		} else if ((*(V + 30 + v) >= 0)			&&
-			   (*(V + 30 + v + 1) >= 0)		&&
-			   (*(V + 30 + v + 2) >= 0)		&&
-			   (*(V + 30 + v + 3) >= 0)		&&
-			   (*(V + 30 + v) > *(V + 30 + v + 2))	&&
-			   (*(V + 30 + v + 1) > *(V + 30 + v + 2)) &&
-			   (*(V + 30 + v) > *(V + 30 + v + 3))	&&
-			   (*(V + 30 + v + 1) > *(V + 30 + v + 3)) &&
-			   ((*(V + 30 + v) > SIGMIN)		||
-			    (*(V + 30 + v + 1) > SIGMIN))) {
-			/* (case 5) */
-			if (*(V + 30 + v) >= *(V + 30 + v + 1)) {
-				swp_freq = fOSC * 1000 + afcex_freq;
-				*SIG1 = *(V + 30 + v);
-			} else {
-				swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
-				*SIG1 = *(V + 30 + v + 1);
-			}
-		} else if ((v + 2 == vmin)			&&
-			   (*(V + 30 + v) >= 0)			&&
-			   (*(V + 30 + v + 1) >= 0)		&&
-			   (*(V + 30 + v + 2) >= 0)		&&
-			   (*(V + 30 + v + 1) > *(V + 30 + v))	&&
-			   (*(V + 30 + v + 2) > *(V + 30 + v))	&&
-			   ((*(V + 30 + v + 1) > SIGMIN)	||
-			    (*(V + 30 + v + 2) > SIGMIN))) {
-			/* (case 6) */
-			if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) {
-				swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
-				*SIG1 = *(V + 30 + v + 1);
-			} else {
-				swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2;
-				*SIG1 = *(V + 30 + v + 2);
-			}
-		} else if ((vmax == 0) && (vmin == 0) && (*(V + 30 + v) > SIGMIN)) {
-			swp_freq = fOSC * 1000;
-			*SIG1 = *(V + 30 + v);
-		} else
-			swp_freq = -1;
-	} else
-		swp_freq = -1;
-
-	return swp_freq;
-}
-
-static void swp_info_get2(struct mb86a16_state *state,
-			  int smrt,
-			  int R,
-			  int swp_freq,
-			  int *afcex_freq,
-			  int *fOSC,
-			  unsigned char *AFCEX_L,
-			  unsigned char *AFCEX_H)
-{
-	int AFCEX ;
-
-	if (R == 0)
-		*fOSC = (swp_freq + 1000) / 2000 * 2;
-	else
-		*fOSC = (swp_freq + 500) / 1000;
-
-	if (*fOSC >= swp_freq)
-		*afcex_freq = *fOSC * 1000 - swp_freq;
-	else
-		*afcex_freq = swp_freq - *fOSC * 1000;
-
-	AFCEX = *afcex_freq * 8192 / state->master_clk;
-	*AFCEX_L =  AFCEX & 0x00ff;
-	*AFCEX_H = (AFCEX & 0x0f00) >> 8;
-}
-
-static void afcex_info_get(struct mb86a16_state *state,
-			   int afcex_freq,
-			   unsigned char *AFCEX_L,
-			   unsigned char *AFCEX_H)
-{
-	int AFCEX ;
-
-	AFCEX = afcex_freq * 8192 / state->master_clk;
-	*AFCEX_L =  AFCEX & 0x00ff;
-	*AFCEX_H = (AFCEX & 0x0f00) >> 8;
-}
-
-static int SEQ_set(struct mb86a16_state *state, unsigned char loop)
-{
-	/* SLOCK0 = 0 */
-	if (mb86a16_write(state, 0x32, 0x02 | (loop << 2)) < 0) {
-		dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static int iq_vt_set(struct mb86a16_state *state, unsigned char IQINV)
-{
-	/* Viterbi Rate, IQ Settings */
-	if (mb86a16_write(state, 0x06, 0xdf | (IQINV << 5)) < 0) {
-		dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static int FEC_srst(struct mb86a16_state *state)
-{
-	if (mb86a16_write(state, MB86A16_RESET, 0x02) < 0) {
-		dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static int S2T_set(struct mb86a16_state *state, unsigned char S2T)
-{
-	if (mb86a16_write(state, 0x34, 0x70 | S2T) < 0) {
-		dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static int S45T_set(struct mb86a16_state *state, unsigned char S4T, unsigned char S5T)
-{
-	if (mb86a16_write(state, 0x35, 0x00 | (S5T << 4) | S4T) < 0) {
-		dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-
-static int mb86a16_set_fe(struct mb86a16_state *state)
-{
-	u8 agcval, cnmval;
-
-	int i, j;
-	int fOSC = 0;
-	int fOSC_start = 0;
-	int wait_t;
-	int fcp;
-	int swp_ofs;
-	int V[60];
-	u8 SIG1MIN;
-
-	unsigned char CREN, AFCEN, AFCEXEN;
-	unsigned char SIG1;
-	unsigned char TIMINT1, TIMINT2, TIMEXT;
-	unsigned char S0T, S1T;
-	unsigned char S2T;
-/*	unsigned char S2T, S3T; */
-	unsigned char S4T, S5T;
-	unsigned char AFCEX_L, AFCEX_H;
-	unsigned char R;
-	unsigned char VIRM;
-	unsigned char ETH, VIA;
-	unsigned char junk;
-
-	int loop;
-	int ftemp;
-	int v, vmax, vmin;
-	int vmax_his, vmin_his;
-	int swp_freq, prev_swp_freq[20];
-	int prev_freq_num;
-	int signal_dupl;
-	int afcex_freq;
-	int signal;
-	int afcerr;
-	int temp_freq, delta_freq;
-	int dagcm[4];
-	int smrt_d;
-/*	int freq_err; */
-	int n;
-	int ret = -1;
-	int sync;
-
-	dprintk(verbose, MB86A16_INFO, 1, "freq=%d Mhz, symbrt=%d Ksps", state->frequency, state->srate);
-
-	fcp = 3000;
-	swp_ofs = state->srate / 4;
-
-	for (i = 0; i < 60; i++)
-		V[i] = -1;
-
-	for (i = 0; i < 20; i++)
-		prev_swp_freq[i] = 0;
-
-	SIG1MIN = 25;
-
-	for (n = 0; ((n < 3) && (ret == -1)); n++) {
-		SEQ_set(state, 0);
-		iq_vt_set(state, 0);
-
-		CREN = 0;
-		AFCEN = 0;
-		AFCEXEN = 1;
-		TIMINT1 = 0;
-		TIMINT2 = 1;
-		TIMEXT = 2;
-		S1T = 0;
-		S0T = 0;
-
-		if (initial_set(state) < 0) {
-			dprintk(verbose, MB86A16_ERROR, 1, "initial set failed");
-			return -1;
-		}
-		if (DAGC_data_set(state, 3, 2) < 0) {
-			dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
-			return -1;
-		}
-		if (EN_set(state, CREN, AFCEN) < 0) {
-			dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
-			return -1; /* (0, 0) */
-		}
-		if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
-			dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
-			return -1; /* (1, smrt) = (1, symbolrate) */
-		}
-		if (CNTM_set(state, TIMINT1, TIMINT2, TIMEXT) < 0) {
-			dprintk(verbose, MB86A16_ERROR, 1, "CNTM set error");
-			return -1; /* (0, 1, 2) */
-		}
-		if (S01T_set(state, S1T, S0T) < 0) {
-			dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
-			return -1; /* (0, 0) */
-		}
-		smrt_info_get(state, state->srate);
-		if (smrt_set(state, state->srate) < 0) {
-			dprintk(verbose, MB86A16_ERROR, 1, "smrt info get error");
-			return -1;
-		}
-
-		R = vco_dev_get(state, state->srate);
-		if (R == 1)
-			fOSC_start = state->frequency;
-
-		else if (R == 0) {
-			if (state->frequency % 2 == 0) {
-				fOSC_start = state->frequency;
-			} else {
-				fOSC_start = state->frequency + 1;
-				if (fOSC_start > 2150)
-					fOSC_start = state->frequency - 1;
-			}
-		}
-		loop = 1;
-		ftemp = fOSC_start * 1000;
-		vmax = 0 ;
-		while (loop == 1) {
-			ftemp = ftemp + swp_ofs;
-			vmax++;
-
-			/* Upper bound */
-			if (ftemp > 2150000) {
-				loop = 0;
-				vmax--;
-			} else {
-				if ((ftemp == 2150000) ||
-				    (ftemp - state->frequency * 1000 >= fcp + state->srate / 4))
-					loop = 0;
-			}
-		}
-
-		loop = 1;
-		ftemp = fOSC_start * 1000;
-		vmin = 0 ;
-		while (loop == 1) {
-			ftemp = ftemp - swp_ofs;
-			vmin--;
-
-			/* Lower bound */
-			if (ftemp < 950000) {
-				loop = 0;
-				vmin++;
-			} else {
-				if ((ftemp == 950000) ||
-				    (state->frequency * 1000 - ftemp >= fcp + state->srate / 4))
-					loop = 0;
-			}
-		}
-
-		wait_t = (8000 + state->srate / 2) / state->srate;
-		if (wait_t == 0)
-			wait_t = 1;
-
-		i = 0;
-		j = 0;
-		prev_freq_num = 0;
-		loop = 1;
-		signal = 0;
-		vmax_his = 0;
-		vmin_his = 0;
-		v = 0;
-
-		while (loop == 1) {
-			swp_info_get(state, fOSC_start, state->srate,
-				     v, R, swp_ofs, &fOSC,
-				     &afcex_freq, &AFCEX_L, &AFCEX_H);
-
-			udelay(100);
-			if (rf_val_set(state, fOSC, state->srate, R) < 0) {
-				dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
-				return -1;
-			}
-			udelay(100);
-			if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
-				dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
-				return -1;
-			}
-			if (srst(state) < 0) {
-				dprintk(verbose, MB86A16_ERROR, 1, "srst error");
-				return -1;
-			}
-			msleep_interruptible(wait_t);
-
-			if (mb86a16_read(state, 0x37, &SIG1) != 2) {
-				dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-				return -1;
-			}
-			V[30 + v] = SIG1 ;
-			swp_freq = swp_freq_calcuation(state, i, v, V, vmax, vmin,
-						      SIG1MIN, fOSC, afcex_freq,
-						      swp_ofs, &SIG1);	/* changed */
-
-			signal_dupl = 0;
-			for (j = 0; j < prev_freq_num; j++) {
-				if ((ABS(prev_swp_freq[j] - swp_freq)) < (swp_ofs * 3 / 2)) {
-					signal_dupl = 1;
-					dprintk(verbose, MB86A16_INFO, 1, "Probably Duplicate Signal, j = %d", j);
-				}
-			}
-			if ((signal_dupl == 0) && (swp_freq > 0) && (ABS(swp_freq - state->frequency * 1000) < fcp + state->srate / 6)) {
-				dprintk(verbose, MB86A16_DEBUG, 1, "------ Signal detect ------ [swp_freq=[%07d, srate=%05d]]", swp_freq, state->srate);
-				prev_swp_freq[prev_freq_num] = swp_freq;
-				prev_freq_num++;
-				swp_info_get2(state, state->srate, R, swp_freq,
-					      &afcex_freq, &fOSC,
-					      &AFCEX_L, &AFCEX_H);
-
-				if (rf_val_set(state, fOSC, state->srate, R) < 0) {
-					dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
-					return -1;
-				}
-				if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
-					dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
-					return -1;
-				}
-				signal = signal_det(state, state->srate, &SIG1);
-				if (signal == 1) {
-					dprintk(verbose, MB86A16_ERROR, 1, "***** Signal Found *****");
-					loop = 0;
-				} else {
-					dprintk(verbose, MB86A16_ERROR, 1, "!!!!! No signal !!!!!, try again...");
-					smrt_info_get(state, state->srate);
-					if (smrt_set(state, state->srate) < 0) {
-						dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
-						return -1;
-					}
-				}
-			}
-			if (v > vmax)
-				vmax_his = 1 ;
-			if (v < vmin)
-				vmin_his = 1 ;
-			i++;
-
-			if ((i % 2 == 1) && (vmax_his == 1))
-				i++;
-			if ((i % 2 == 0) && (vmin_his == 1))
-				i++;
-
-			if (i % 2 == 1)
-				v = (i + 1) / 2;
-			else
-				v = -i / 2;
-
-			if ((vmax_his == 1) && (vmin_his == 1))
-				loop = 0 ;
-		}
-
-		if (signal == 1) {
-			dprintk(verbose, MB86A16_INFO, 1, " Start Freq Error Check");
-			S1T = 7 ;
-			S0T = 1 ;
-			CREN = 0 ;
-			AFCEN = 1 ;
-			AFCEXEN = 0 ;
-
-			if (S01T_set(state, S1T, S0T) < 0) {
-				dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
-				return -1;
-			}
-			smrt_info_get(state, state->srate);
-			if (smrt_set(state, state->srate) < 0) {
-				dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
-				return -1;
-			}
-			if (EN_set(state, CREN, AFCEN) < 0) {
-				dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
-				return -1;
-			}
-			if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
-				dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
-				return -1;
-			}
-			afcex_info_get(state, afcex_freq, &AFCEX_L, &AFCEX_H);
-			if (afcofs_data_set(state, AFCEX_L, AFCEX_H) < 0) {
-				dprintk(verbose, MB86A16_ERROR, 1, "AFCOFS data set error");
-				return -1;
-			}
-			if (srst(state) < 0) {
-				dprintk(verbose, MB86A16_ERROR, 1, "srst error");
-				return -1;
-			}
-			/* delay 4~200 */
-			wait_t = 200000 / state->master_clk + 200000 / state->srate;
-			msleep(wait_t);
-			afcerr = afcerr_chk(state);
-			if (afcerr == -1)
-				return -1;
-
-			swp_freq = fOSC * 1000 + afcerr ;
-			AFCEXEN = 1 ;
-			if (state->srate >= 1500)
-				smrt_d = state->srate / 3;
-			else
-				smrt_d = state->srate / 2;
-			smrt_info_get(state, smrt_d);
-			if (smrt_set(state, smrt_d) < 0) {
-				dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
-				return -1;
-			}
-			if (AFCEXEN_set(state, AFCEXEN, smrt_d) < 0) {
-				dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
-				return -1;
-			}
-			R = vco_dev_get(state, smrt_d);
-			if (DAGC_data_set(state, 2, 0) < 0) {
-				dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
-				return -1;
-			}
-			for (i = 0; i < 3; i++) {
-				temp_freq = swp_freq + (i - 1) * state->srate / 8;
-				swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
-				if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
-					dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
-					return -1;
-				}
-				if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
-					dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
-					return -1;
-				}
-				wait_t = 200000 / state->master_clk + 40000 / smrt_d;
-				msleep(wait_t);
-				dagcm[i] = dagcm_val_get(state);
-			}
-			if ((dagcm[0] > dagcm[1]) &&
-			    (dagcm[0] > dagcm[2]) &&
-			    (dagcm[0] - dagcm[1] > 2 * (dagcm[2] - dagcm[1]))) {
-
-				temp_freq = swp_freq - 2 * state->srate / 8;
-				swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
-				if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
-					dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
-					return -1;
-				}
-				if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
-					dprintk(verbose, MB86A16_ERROR, 1, "afcex data set");
-					return -1;
-				}
-				wait_t = 200000 / state->master_clk + 40000 / smrt_d;
-				msleep(wait_t);
-				dagcm[3] = dagcm_val_get(state);
-				if (dagcm[3] > dagcm[1])
-					delta_freq = (dagcm[2] - dagcm[0] + dagcm[1] - dagcm[3]) * state->srate / 300;
-				else
-					delta_freq = 0;
-			} else if ((dagcm[2] > dagcm[1]) &&
-				   (dagcm[2] > dagcm[0]) &&
-				   (dagcm[2] - dagcm[1] > 2 * (dagcm[0] - dagcm[1]))) {
-
-				temp_freq = swp_freq + 2 * state->srate / 8;
-				swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
-				if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
-					dprintk(verbose, MB86A16_ERROR, 1, "rf val set");
-					return -1;
-				}
-				if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
-					dprintk(verbose, MB86A16_ERROR, 1, "afcex data set");
-					return -1;
-				}
-				wait_t = 200000 / state->master_clk + 40000 / smrt_d;
-				msleep(wait_t);
-				dagcm[3] = dagcm_val_get(state);
-				if (dagcm[3] > dagcm[1])
-					delta_freq = (dagcm[2] - dagcm[0] + dagcm[3] - dagcm[1]) * state->srate / 300;
-				else
-					delta_freq = 0 ;
-
-			} else {
-				delta_freq = 0 ;
-			}
-			dprintk(verbose, MB86A16_INFO, 1, "SWEEP Frequency = %d", swp_freq);
-			swp_freq += delta_freq;
-			dprintk(verbose, MB86A16_INFO, 1, "Adjusting .., DELTA Freq = %d, SWEEP Freq=%d", delta_freq, swp_freq);
-			if (ABS(state->frequency * 1000 - swp_freq) > 3800) {
-				dprintk(verbose, MB86A16_INFO, 1, "NO  --  SIGNAL !");
-			} else {
-
-				S1T = 0;
-				S0T = 3;
-				CREN = 1;
-				AFCEN = 0;
-				AFCEXEN = 1;
-
-				if (S01T_set(state, S1T, S0T) < 0) {
-					dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
-					return -1;
-				}
-				if (DAGC_data_set(state, 0, 0) < 0) {
-					dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
-					return -1;
-				}
-				R = vco_dev_get(state, state->srate);
-				smrt_info_get(state, state->srate);
-				if (smrt_set(state, state->srate) < 0) {
-					dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
-					return -1;
-				}
-				if (EN_set(state, CREN, AFCEN) < 0) {
-					dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
-					return -1;
-				}
-				if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
-					dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
-					return -1;
-				}
-				swp_info_get2(state, state->srate, R, swp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
-				if (rf_val_set(state, fOSC, state->srate, R) < 0) {
-					dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
-					return -1;
-				}
-				if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
-					dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
-					return -1;
-				}
-				if (srst(state) < 0) {
-					dprintk(verbose, MB86A16_ERROR, 1, "srst error");
-					return -1;
-				}
-				wait_t = 7 + (10000 + state->srate / 2) / state->srate;
-				if (wait_t == 0)
-					wait_t = 1;
-				msleep_interruptible(wait_t);
-				if (mb86a16_read(state, 0x37, &SIG1) != 2) {
-					dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-					return -EREMOTEIO;
-				}
-
-				if (SIG1 > 110) {
-					S2T = 4; S4T = 1; S5T = 6; ETH = 4; VIA = 6;
-					wait_t = 7 + (917504 + state->srate / 2) / state->srate;
-				} else if (SIG1 > 105) {
-					S2T = 4; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
-					wait_t = 7 + (1048576 + state->srate / 2) / state->srate;
-				} else if (SIG1 > 85) {
-					S2T = 5; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
-					wait_t = 7 + (1310720 + state->srate / 2) / state->srate;
-				} else if (SIG1 > 65) {
-					S2T = 6; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
-					wait_t = 7 + (1572864 + state->srate / 2) / state->srate;
-				} else {
-					S2T = 7; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
-					wait_t = 7 + (2097152 + state->srate / 2) / state->srate;
-				}
-				wait_t *= 2; /* FOS */
-				S2T_set(state, S2T);
-				S45T_set(state, S4T, S5T);
-				Vi_set(state, ETH, VIA);
-				srst(state);
-				msleep_interruptible(wait_t);
-				sync = sync_chk(state, &VIRM);
-				dprintk(verbose, MB86A16_INFO, 1, "-------- Viterbi=[%d] SYNC=[%d] ---------", VIRM, sync);
-				if (VIRM) {
-					if (VIRM == 4) {
-						/* 5/6 */
-						if (SIG1 > 110)
-							wait_t = (786432 + state->srate / 2) / state->srate;
-						else
-							wait_t = (1572864 + state->srate / 2) / state->srate;
-						if (state->srate < 5000)
-							/* FIXME ! , should be a long wait ! */
-							msleep_interruptible(wait_t);
-						else
-							msleep_interruptible(wait_t);
-
-						if (sync_chk(state, &junk) == 0) {
-							iq_vt_set(state, 1);
-							FEC_srst(state);
-						}
-					}
-					/* 1/2, 2/3, 3/4, 7/8 */
-					if (SIG1 > 110)
-						wait_t = (786432 + state->srate / 2) / state->srate;
-					else
-						wait_t = (1572864 + state->srate / 2) / state->srate;
-					msleep_interruptible(wait_t);
-					SEQ_set(state, 1);
-				} else {
-					dprintk(verbose, MB86A16_INFO, 1, "NO  -- SYNC");
-					SEQ_set(state, 1);
-					ret = -1;
-				}
-			}
-		} else {
-			dprintk(verbose, MB86A16_INFO, 1, "NO  -- SIGNAL");
-			ret = -1;
-		}
-
-		sync = sync_chk(state, &junk);
-		if (sync) {
-			dprintk(verbose, MB86A16_INFO, 1, "******* SYNC *******");
-			freqerr_chk(state, state->frequency, state->srate, 1);
-			ret = 0;
-			break;
-		}
-	}
-
-	mb86a16_read(state, 0x15, &agcval);
-	mb86a16_read(state, 0x26, &cnmval);
-	dprintk(verbose, MB86A16_INFO, 1, "AGC = %02x CNM = %02x", agcval, cnmval);
-
-	return ret;
-}
-
-static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe,
-				   struct dvb_diseqc_master_cmd *cmd)
-{
-	struct mb86a16_state *state = fe->demodulator_priv;
-	int i;
-	u8 regs;
-
-	if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0)
-		goto err;
-	if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0)
-		goto err;
-	if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0)
-		goto err;
-
-	regs = 0x18;
-
-	if (cmd->msg_len > 5 || cmd->msg_len < 4)
-		return -EINVAL;
-
-	for (i = 0; i < cmd->msg_len; i++) {
-		if (mb86a16_write(state, regs, cmd->msg[i]) < 0)
-			goto err;
-
-		regs++;
-	}
-	i += 0x90;
-
-	msleep_interruptible(10);
-
-	if (mb86a16_write(state, MB86A16_DCC1, i) < 0)
-		goto err;
-	if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
-		goto err;
-
-	return 0;
-
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-}
-
-static int mb86a16_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
-{
-	struct mb86a16_state *state = fe->demodulator_priv;
-
-	switch (burst) {
-	case SEC_MINI_A:
-		if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
-						       MB86A16_DCC1_TBEN  |
-						       MB86A16_DCC1_TBO) < 0)
-			goto err;
-		if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
-			goto err;
-		break;
-	case SEC_MINI_B:
-		if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
-						       MB86A16_DCC1_TBEN) < 0)
-			goto err;
-		if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
-			goto err;
-		break;
-	}
-
-	return 0;
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-}
-
-static int mb86a16_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
-{
-	struct mb86a16_state *state = fe->demodulator_priv;
-
-	switch (tone) {
-	case SEC_TONE_ON:
-		if (mb86a16_write(state, MB86A16_TONEOUT2, 0x00) < 0)
-			goto err;
-		if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
-						       MB86A16_DCC1_CTOE) < 0)
-
-			goto err;
-		if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
-			goto err;
-		break;
-	case SEC_TONE_OFF:
-		if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0)
-			goto err;
-		if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0)
-			goto err;
-		if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0)
-			goto err;
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-}
-
-static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct mb86a16_state *state = fe->demodulator_priv;
-
-	state->frequency = p->frequency / 1000;
-	state->srate = p->symbol_rate / 1000;
-
-	if (!mb86a16_set_fe(state)) {
-		dprintk(verbose, MB86A16_ERROR, 1, "Successfully acquired LOCK");
-		return DVBFE_ALGO_SEARCH_SUCCESS;
-	}
-
-	dprintk(verbose, MB86A16_ERROR, 1, "Lock acquisition failed!");
-	return DVBFE_ALGO_SEARCH_FAILED;
-}
-
-static void mb86a16_release(struct dvb_frontend *fe)
-{
-	struct mb86a16_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static int mb86a16_init(struct dvb_frontend *fe)
-{
-	return 0;
-}
-
-static int mb86a16_sleep(struct dvb_frontend *fe)
-{
-	return 0;
-}
-
-static int mb86a16_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	u8 ber_mon, ber_tab, ber_lsb, ber_mid, ber_msb, ber_tim, ber_rst;
-	u32 timer;
-
-	struct mb86a16_state *state = fe->demodulator_priv;
-
-	*ber = 0;
-	if (mb86a16_read(state, MB86A16_BERMON, &ber_mon) != 2)
-		goto err;
-	if (mb86a16_read(state, MB86A16_BERTAB, &ber_tab) != 2)
-		goto err;
-	if (mb86a16_read(state, MB86A16_BERLSB, &ber_lsb) != 2)
-		goto err;
-	if (mb86a16_read(state, MB86A16_BERMID, &ber_mid) != 2)
-		goto err;
-	if (mb86a16_read(state, MB86A16_BERMSB, &ber_msb) != 2)
-		goto err;
-	/* BER monitor invalid when BER_EN = 0	*/
-	if (ber_mon & 0x04) {
-		/* coarse, fast calculation	*/
-		*ber = ber_tab & 0x1f;
-		dprintk(verbose, MB86A16_DEBUG, 1, "BER coarse=[0x%02x]", *ber);
-		if (ber_mon & 0x01) {
-			/*
-			 * BER_SEL = 1, The monitored BER is the estimated
-			 * value with a Reed-Solomon decoder error amount at
-			 * the deinterleaver output.
-			 * monitored BER is expressed as a 20 bit output in total
-			 */
-			ber_rst = ber_mon >> 3;
-			*ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb;
-			if (ber_rst == 0)
-				timer =  12500000;
-			if (ber_rst == 1)
-				timer =  25000000;
-			if (ber_rst == 2)
-				timer =  50000000;
-			if (ber_rst == 3)
-				timer = 100000000;
-
-			*ber /= timer;
-			dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber);
-		} else {
-			/*
-			 * BER_SEL = 0, The monitored BER is the estimated
-			 * value with a Viterbi decoder error amount at the
-			 * QPSK demodulator output.
-			 * monitored BER is expressed as a 24 bit output in total
-			 */
-			ber_tim = ber_mon >> 1;
-			*ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb;
-			if (ber_tim == 0)
-				timer = 16;
-			if (ber_tim == 1)
-				timer = 24;
-
-			*ber /= 2 ^ timer;
-			dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber);
-		}
-	}
-	return 0;
-err:
-	dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-	return -EREMOTEIO;
-}
-
-static int mb86a16_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	u8 agcm = 0;
-	struct mb86a16_state *state = fe->demodulator_priv;
-
-	*strength = 0;
-	if (mb86a16_read(state, MB86A16_AGCM, &agcm) != 2) {
-		dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-		return -EREMOTEIO;
-	}
-
-	*strength = ((0xff - agcm) * 100) / 256;
-	dprintk(verbose, MB86A16_DEBUG, 1, "Signal strength=[%d %%]", (u8) *strength);
-	*strength = (0xffff - 0xff) + agcm;
-
-	return 0;
-}
-
-struct cnr {
-	u8 cn_reg;
-	u8 cn_val;
-};
-
-static const struct cnr cnr_tab[] = {
-	{  35,  2 },
-	{  40,  3 },
-	{  50,  4 },
-	{  60,  5 },
-	{  70,  6 },
-	{  80,  7 },
-	{  92,  8 },
-	{ 103,  9 },
-	{ 115, 10 },
-	{ 138, 12 },
-	{ 162, 15 },
-	{ 180, 18 },
-	{ 185, 19 },
-	{ 189, 20 },
-	{ 195, 22 },
-	{ 199, 24 },
-	{ 201, 25 },
-	{ 202, 26 },
-	{ 203, 27 },
-	{ 205, 28 },
-	{ 208, 30 }
-};
-
-static int mb86a16_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct mb86a16_state *state = fe->demodulator_priv;
-	int i = 0;
-	int low_tide = 2, high_tide = 30, q_level;
-	u8  cn;
-
-	*snr = 0;
-	if (mb86a16_read(state, 0x26, &cn) != 2) {
-		dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-		return -EREMOTEIO;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(cnr_tab); i++) {
-		if (cn < cnr_tab[i].cn_reg) {
-			*snr = cnr_tab[i].cn_val;
-			break;
-		}
-	}
-	q_level = (*snr * 100) / (high_tide - low_tide);
-	dprintk(verbose, MB86A16_ERROR, 1, "SNR (Quality) = [%d dB], Level=%d %%", *snr, q_level);
-	*snr = (0xffff - 0xff) + *snr;
-
-	return 0;
-}
-
-static int mb86a16_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	u8 dist;
-	struct mb86a16_state *state = fe->demodulator_priv;
-
-	if (mb86a16_read(state, MB86A16_DISTMON, &dist) != 2) {
-		dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
-		return -EREMOTEIO;
-	}
-	*ucblocks = dist;
-
-	return 0;
-}
-
-static enum dvbfe_algo mb86a16_frontend_algo(struct dvb_frontend *fe)
-{
-	return DVBFE_ALGO_CUSTOM;
-}
-
-static struct dvb_frontend_ops mb86a16_ops = {
-	.delsys = { SYS_DVBS },
-	.info = {
-		.name			= "Fujitsu MB86A16 DVB-S",
-		.frequency_min		= 950000,
-		.frequency_max		= 2150000,
-		.frequency_stepsize	= 3000,
-		.frequency_tolerance	= 0,
-		.symbol_rate_min	= 1000000,
-		.symbol_rate_max	= 45000000,
-		.symbol_rate_tolerance	= 500,
-		.caps			= FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
-					  FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
-					  FE_CAN_FEC_7_8 | FE_CAN_QPSK    |
-					  FE_CAN_FEC_AUTO
-	},
-	.release			= mb86a16_release,
-
-	.get_frontend_algo		= mb86a16_frontend_algo,
-	.search				= mb86a16_search,
-	.init				= mb86a16_init,
-	.sleep				= mb86a16_sleep,
-	.read_status			= mb86a16_read_status,
-
-	.read_ber			= mb86a16_read_ber,
-	.read_signal_strength		= mb86a16_read_signal_strength,
-	.read_snr			= mb86a16_read_snr,
-	.read_ucblocks			= mb86a16_read_ucblocks,
-
-	.diseqc_send_master_cmd		= mb86a16_send_diseqc_msg,
-	.diseqc_send_burst		= mb86a16_send_diseqc_burst,
-	.set_tone			= mb86a16_set_tone,
-};
-
-struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
-				    struct i2c_adapter *i2c_adap)
-{
-	u8 dev_id = 0;
-	struct mb86a16_state *state = NULL;
-
-	state = kmalloc(sizeof(struct mb86a16_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	state->config = config;
-	state->i2c_adap = i2c_adap;
-
-	mb86a16_read(state, 0x7f, &dev_id);
-	if (dev_id != 0xfe)
-		goto error;
-
-	memcpy(&state->frontend.ops, &mb86a16_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	state->frontend.ops.set_voltage = state->config->set_voltage;
-
-	return &state->frontend;
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(mb86a16_attach);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Manu Abraham");
diff --git a/drivers/media/dvb/frontends/mb86a16.h b/drivers/media/dvb/frontends/mb86a16.h
deleted file mode 100644
index 6ea8c37..0000000
--- a/drivers/media/dvb/frontends/mb86a16.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
-	Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MB86A16_H
-#define __MB86A16_H
-
-#include <linux/dvb/frontend.h>
-#include "dvb_frontend.h"
-
-
-struct mb86a16_config {
-	u8 demod_address;
-
-	int (*set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
-};
-
-
-
-#if defined(CONFIG_DVB_MB86A16) || (defined(CONFIG_DVB_MB86A16_MODULE) && defined(MODULE))
-
-extern struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
-					   struct i2c_adapter *i2c_adap);
-
-#else
-
-static inline struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
-					   struct i2c_adapter *i2c_adap)
-{
-	printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-#endif /* CONFIG_DVB_MB86A16 */
-
-#endif /* __MB86A16_H */
diff --git a/drivers/media/dvb/frontends/mb86a16_priv.h b/drivers/media/dvb/frontends/mb86a16_priv.h
deleted file mode 100644
index 360a35a..0000000
--- a/drivers/media/dvb/frontends/mb86a16_priv.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
-	Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MB86A16_PRIV_H
-#define __MB86A16_PRIV_H
-
-#define MB86A16_TSOUT		0x00
-#define MB86A16_TSOUT_HIZSEL	(0x01 << 5)
-#define MB86A16_TSOUT_HIZCNTI	(0x01 << 4)
-#define MB86A16_TSOUT_MODE	(0x01 << 3)
-#define MB86A16_TSOUT_ORDER	(0x01 << 2)
-#define MB86A16_TSOUT_ERROR	(0x01 << 1)
-#define Mb86A16_TSOUT_EDGE	(0x01 << 0)
-
-#define MB86A16_FEC		0x01
-#define MB86A16_FEC_FSYNC	(0x01 << 5)
-#define MB86A16_FEC_PCKB8	(0x01 << 4)
-#define MB86A16_FEC_DVDS	(0x01 << 3)
-#define MB86A16_FEC_EREN	(0x01 << 2)
-#define Mb86A16_FEC_RSEN	(0x01 << 1)
-#define MB86A16_FEC_DIEN	(0x01 << 0)
-
-#define MB86A16_AGC		0x02
-#define MB86A16_AGC_AGMD	(0x01 << 6)
-#define MB86A16_AGC_AGCW	(0x0f << 2)
-#define MB86A16_AGC_AGCP	(0x01 << 1)
-#define MB86A16_AGC_AGCR	(0x01 << 0)
-
-#define MB86A16_SRATE1		0x03
-#define MB86A16_SRATE1_DECI	(0x07 << 2)
-#define MB86A16_SRATE1_CSEL	(0x01 << 1)
-#define MB86A16_SRATE1_RSEL	(0x01 << 0)
-
-#define MB86A16_SRATE2		0x04
-#define MB86A16_SRATE2_STOFSL	(0xff << 0)
-
-#define MB86A16_SRATE3		0x05
-#define MB86A16_SRATE2_STOFSH	(0xff << 0)
-
-#define MB86A16_VITERBI		0x06
-#define MB86A16_FRAMESYNC	0x07
-#define MB86A16_CRLFILTCOEF1	0x08
-#define MB86A16_CRLFILTCOEF2	0x09
-#define MB86A16_STRFILTCOEF1	0x0a
-#define MB86A16_STRFILTCOEF2	0x0b
-#define MB86A16_RESET		0x0c
-#define MB86A16_STATUS		0x0d
-#define MB86A16_AFCML		0x0e
-#define MB86A16_AFCMH		0x0f
-#define MB86A16_BERMON		0x10
-#define MB86A16_BERTAB		0x11
-#define MB86A16_BERLSB		0x12
-#define MB86A16_BERMID		0x13
-#define MB86A16_BERMSB		0x14
-#define MB86A16_AGCM		0x15
-
-#define MB86A16_DCC1		0x16
-#define MB86A16_DCC1_DISTA	(0x01 << 7)
-#define MB86A16_DCC1_PRTY	(0x01 << 6)
-#define MB86A16_DCC1_CTOE	(0x01 << 5)
-#define MB86A16_DCC1_TBEN	(0x01 << 4)
-#define MB86A16_DCC1_TBO	(0x01 << 3)
-#define MB86A16_DCC1_NUM	(0x07 << 0)
-
-#define MB86A16_DCC2		0x17
-#define MB86A16_DCC2_DCBST	(0x01 << 0)
-
-#define MB86A16_DCC3		0x18
-#define MB86A16_DCC3_CODE0	(0xff << 0)
-
-#define MB86A16_DCC4		0x19
-#define MB86A16_DCC4_CODE1	(0xff << 0)
-
-#define MB86A16_DCC5		0x1a
-#define MB86A16_DCC5_CODE2	(0xff << 0)
-
-#define MB86A16_DCC6		0x1b
-#define MB86A16_DCC6_CODE3	(0xff << 0)
-
-#define MB86A16_DCC7		0x1c
-#define MB86A16_DCC7_CODE4	(0xff << 0)
-
-#define MB86A16_DCC8		0x1d
-#define MB86A16_DCC8_CODE5	(0xff << 0)
-
-#define MB86A16_DCCOUT		0x1e
-#define MB86A16_DCCOUT_DISEN	(0x01 << 0)
-
-#define MB86A16_TONEOUT1	0x1f
-#define MB86A16_TONE_TDIVL	(0xff << 0)
-
-#define MB86A16_TONEOUT2	0x20
-#define MB86A16_TONE_TMD	(0x03 << 2)
-#define MB86A16_TONE_TDIVH	(0x03 << 0)
-
-#define MB86A16_FREQ1		0x21
-#define MB86A16_FREQ2		0x22
-#define MB86A16_FREQ3		0x23
-#define MB86A16_FREQ4		0x24
-#define MB86A16_FREQSET		0x25
-#define MB86A16_CNM		0x26
-#define MB86A16_PORT0		0x27
-#define MB86A16_PORT1		0x28
-#define MB86A16_DRCFILT		0x29
-#define MB86A16_AFC		0x2a
-#define MB86A16_AFCEXL		0x2b
-#define MB86A16_AFCEXH		0x2c
-#define MB86A16_DAGC		0x2d
-#define MB86A16_SEQMODE		0x32
-#define MB86A16_S0S1T		0x33
-#define MB86A16_S2S3T		0x34
-#define MB86A16_S4S5T		0x35
-#define MB86A16_CNTMR		0x36
-#define MB86A16_SIG1		0x37
-#define MB86A16_SIG2		0x38
-#define MB86A16_VIMAG		0x39
-#define MB86A16_VISET1		0x3a
-#define MB86A16_VISET2		0x3b
-#define MB86A16_VISET3		0x3c
-#define MB86A16_FAGCS1		0x3d
-#define MB86A16_FAGCS2		0x3e
-#define MB86A16_FAGCS3		0x3f
-#define MB86A16_FAGCS4		0x40
-#define MB86A16_FAGCS5		0x41
-#define MB86A16_FAGCS6		0x42
-#define MB86A16_CRM		0x43
-#define MB86A16_STRM		0x44
-#define MB86A16_DAGCML		0x45
-#define MB86A16_DAGCMH		0x46
-#define MB86A16_QPSKTST		0x49
-#define MB86A16_DISTMON		0x52
-#define MB86A16_VERSION		0x7f
-
-#endif /* __MB86A16_PRIV_H */
diff --git a/drivers/media/dvb/frontends/mb86a20s.c b/drivers/media/dvb/frontends/mb86a20s.c
deleted file mode 100644
index fade566..0000000
--- a/drivers/media/dvb/frontends/mb86a20s.c
+++ /dev/null
@@ -1,701 +0,0 @@
-/*
- *   Fujitu mb86a20s ISDB-T/ISDB-Tsb Module driver
- *
- *   Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com>
- *   Copyright (C) 2009-2010 Douglas Landgraf <dougsland@redhat.com>
- *
- *   FIXME: Need to port to DVB v5.2 API
- *
- *   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 version 2.
- *
- *   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 <asm/div64.h>
-
-#include "dvb_frontend.h"
-#include "mb86a20s.h"
-
-static int debug = 1;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
-
-#define rc(args...)  do {						\
-	printk(KERN_ERR  "mb86a20s: " args);				\
-} while (0)
-
-#define dprintk(args...)						\
-	do {								\
-		if (debug) {						\
-			printk(KERN_DEBUG "mb86a20s: %s: ", __func__);	\
-			printk(args);					\
-		}							\
-	} while (0)
-
-struct mb86a20s_state {
-	struct i2c_adapter *i2c;
-	const struct mb86a20s_config *config;
-
-	struct dvb_frontend frontend;
-
-	bool need_init;
-};
-
-struct regdata {
-	u8 reg;
-	u8 data;
-};
-
-/*
- * Initialization sequence: Use whatevere default values that PV SBTVD
- * does on its initialisation, obtained via USB snoop
- */
-static struct regdata mb86a20s_init[] = {
-	{ 0x70, 0x0f },
-	{ 0x70, 0xff },
-	{ 0x08, 0x01 },
-	{ 0x09, 0x3e },
-	{ 0x50, 0xd1 }, { 0x51, 0x22 },
-	{ 0x39, 0x01 },
-	{ 0x71, 0x00 },
-	{ 0x28, 0x2a }, { 0x29, 0x00 }, { 0x2a, 0xff }, { 0x2b, 0x80 },
-	{ 0x28, 0x20 }, { 0x29, 0x33 }, { 0x2a, 0xdf }, { 0x2b, 0xa9 },
-	{ 0x28, 0x22 }, { 0x29, 0x00 }, { 0x2a, 0x1f }, { 0x2b, 0xf0 },
-	{ 0x3b, 0x21 },
-	{ 0x3c, 0x3a },
-	{ 0x01, 0x0d },
-	{ 0x04, 0x08 }, { 0x05, 0x05 },
-	{ 0x04, 0x0e }, { 0x05, 0x00 },
-	{ 0x04, 0x0f }, { 0x05, 0x14 },
-	{ 0x04, 0x0b }, { 0x05, 0x8c },
-	{ 0x04, 0x00 }, { 0x05, 0x00 },
-	{ 0x04, 0x01 }, { 0x05, 0x07 },
-	{ 0x04, 0x02 }, { 0x05, 0x0f },
-	{ 0x04, 0x03 }, { 0x05, 0xa0 },
-	{ 0x04, 0x09 }, { 0x05, 0x00 },
-	{ 0x04, 0x0a }, { 0x05, 0xff },
-	{ 0x04, 0x27 }, { 0x05, 0x64 },
-	{ 0x04, 0x28 }, { 0x05, 0x00 },
-	{ 0x04, 0x1e }, { 0x05, 0xff },
-	{ 0x04, 0x29 }, { 0x05, 0x0a },
-	{ 0x04, 0x32 }, { 0x05, 0x0a },
-	{ 0x04, 0x14 }, { 0x05, 0x02 },
-	{ 0x04, 0x04 }, { 0x05, 0x00 },
-	{ 0x04, 0x05 }, { 0x05, 0x22 },
-	{ 0x04, 0x06 }, { 0x05, 0x0e },
-	{ 0x04, 0x07 }, { 0x05, 0xd8 },
-	{ 0x04, 0x12 }, { 0x05, 0x00 },
-	{ 0x04, 0x13 }, { 0x05, 0xff },
-	{ 0x04, 0x15 }, { 0x05, 0x4e },
-	{ 0x04, 0x16 }, { 0x05, 0x20 },
-	{ 0x52, 0x01 },
-	{ 0x50, 0xa7 }, { 0x51, 0xff },
-	{ 0x50, 0xa8 }, { 0x51, 0xff },
-	{ 0x50, 0xa9 }, { 0x51, 0xff },
-	{ 0x50, 0xaa }, { 0x51, 0xff },
-	{ 0x50, 0xab }, { 0x51, 0xff },
-	{ 0x50, 0xac }, { 0x51, 0xff },
-	{ 0x50, 0xad }, { 0x51, 0xff },
-	{ 0x50, 0xae }, { 0x51, 0xff },
-	{ 0x50, 0xaf }, { 0x51, 0xff },
-	{ 0x5e, 0x07 },
-	{ 0x50, 0xdc }, { 0x51, 0x01 },
-	{ 0x50, 0xdd }, { 0x51, 0xf4 },
-	{ 0x50, 0xde }, { 0x51, 0x01 },
-	{ 0x50, 0xdf }, { 0x51, 0xf4 },
-	{ 0x50, 0xe0 }, { 0x51, 0x01 },
-	{ 0x50, 0xe1 }, { 0x51, 0xf4 },
-	{ 0x50, 0xb0 }, { 0x51, 0x07 },
-	{ 0x50, 0xb2 }, { 0x51, 0xff },
-	{ 0x50, 0xb3 }, { 0x51, 0xff },
-	{ 0x50, 0xb4 }, { 0x51, 0xff },
-	{ 0x50, 0xb5 }, { 0x51, 0xff },
-	{ 0x50, 0xb6 }, { 0x51, 0xff },
-	{ 0x50, 0xb7 }, { 0x51, 0xff },
-	{ 0x50, 0x50 }, { 0x51, 0x02 },
-	{ 0x50, 0x51 }, { 0x51, 0x04 },
-	{ 0x45, 0x04 },
-	{ 0x48, 0x04 },
-	{ 0x50, 0xd5 }, { 0x51, 0x01 },		/* Serial */
-	{ 0x50, 0xd6 }, { 0x51, 0x1f },
-	{ 0x50, 0xd2 }, { 0x51, 0x03 },
-	{ 0x50, 0xd7 }, { 0x51, 0x3f },
-	{ 0x28, 0x74 }, { 0x29, 0x00 }, { 0x28, 0x74 }, { 0x29, 0x40 },
-	{ 0x28, 0x46 }, { 0x29, 0x2c }, { 0x28, 0x46 }, { 0x29, 0x0c },
-	{ 0x04, 0x40 }, { 0x05, 0x01 },
-	{ 0x28, 0x00 }, { 0x29, 0x10 },
-	{ 0x28, 0x05 }, { 0x29, 0x02 },
-	{ 0x1c, 0x01 },
-	{ 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x03 },
-	{ 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0d },
-	{ 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 },
-	{ 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x01 },
-	{ 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x21 },
-	{ 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x29 },
-	{ 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 },
-	{ 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x31 },
-	{ 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0e },
-	{ 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x4e },
-	{ 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x46 },
-	{ 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f },
-	{ 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x56 },
-	{ 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x35 },
-	{ 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbe },
-	{ 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0x84 },
-	{ 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x03 }, { 0x2b, 0xee },
-	{ 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x98 },
-	{ 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x9f },
-	{ 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xb2 },
-	{ 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0xc2 },
-	{ 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0x4a },
-	{ 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbc },
-	{ 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x04 }, { 0x2b, 0xba },
-	{ 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0x14 },
-	{ 0x50, 0x1e }, { 0x51, 0x5d },
-	{ 0x50, 0x22 }, { 0x51, 0x00 },
-	{ 0x50, 0x23 }, { 0x51, 0xc8 },
-	{ 0x50, 0x24 }, { 0x51, 0x00 },
-	{ 0x50, 0x25 }, { 0x51, 0xf0 },
-	{ 0x50, 0x26 }, { 0x51, 0x00 },
-	{ 0x50, 0x27 }, { 0x51, 0xc3 },
-	{ 0x50, 0x39 }, { 0x51, 0x02 },
-	{ 0x28, 0x6a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x00 },
-	{ 0xd0, 0x00 },
-};
-
-static struct regdata mb86a20s_reset_reception[] = {
-	{ 0x70, 0xf0 },
-	{ 0x70, 0xff },
-	{ 0x08, 0x01 },
-	{ 0x08, 0x00 },
-};
-
-static int mb86a20s_i2c_writereg(struct mb86a20s_state *state,
-			     u8 i2c_addr, int reg, int data)
-{
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = {
-		.addr = i2c_addr, .flags = 0, .buf = buf, .len = 2
-	};
-	int rc;
-
-	rc = i2c_transfer(state->i2c, &msg, 1);
-	if (rc != 1) {
-		printk("%s: writereg error (rc == %i, reg == 0x%02x,"
-			 " data == 0x%02x)\n", __func__, rc, reg, data);
-		return rc;
-	}
-
-	return 0;
-}
-
-static int mb86a20s_i2c_writeregdata(struct mb86a20s_state *state,
-				     u8 i2c_addr, struct regdata *rd, int size)
-{
-	int i, rc;
-
-	for (i = 0; i < size; i++) {
-		rc = mb86a20s_i2c_writereg(state, i2c_addr, rd[i].reg,
-					   rd[i].data);
-		if (rc < 0)
-			return rc;
-	}
-	return 0;
-}
-
-static int mb86a20s_i2c_readreg(struct mb86a20s_state *state,
-				u8 i2c_addr, u8 reg)
-{
-	u8 val;
-	int rc;
-	struct i2c_msg msg[] = {
-		{ .addr = i2c_addr, .flags = 0, .buf = &reg, .len = 1 },
-		{ .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
-	};
-
-	rc = i2c_transfer(state->i2c, msg, 2);
-
-	if (rc != 2) {
-		rc("%s: reg=0x%x (error=%d)\n", __func__, reg, rc);
-		return rc;
-	}
-
-	return val;
-}
-
-#define mb86a20s_readreg(state, reg) \
-	mb86a20s_i2c_readreg(state, state->config->demod_address, reg)
-#define mb86a20s_writereg(state, reg, val) \
-	mb86a20s_i2c_writereg(state, state->config->demod_address, reg, val)
-#define mb86a20s_writeregdata(state, regdata) \
-	mb86a20s_i2c_writeregdata(state, state->config->demod_address, \
-	regdata, ARRAY_SIZE(regdata))
-
-static int mb86a20s_initfe(struct dvb_frontend *fe)
-{
-	struct mb86a20s_state *state = fe->demodulator_priv;
-	int rc;
-	u8  regD5 = 1;
-
-	dprintk("\n");
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	/* Initialize the frontend */
-	rc = mb86a20s_writeregdata(state, mb86a20s_init);
-	if (rc < 0)
-		goto err;
-
-	if (!state->config->is_serial) {
-		regD5 &= ~1;
-
-		rc = mb86a20s_writereg(state, 0x50, 0xd5);
-		if (rc < 0)
-			goto err;
-		rc = mb86a20s_writereg(state, 0x51, regD5);
-		if (rc < 0)
-			goto err;
-	}
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-err:
-	if (rc < 0) {
-		state->need_init = true;
-		printk(KERN_INFO "mb86a20s: Init failed. Will try again later\n");
-	} else {
-		state->need_init = false;
-		dprintk("Initialization succeeded.\n");
-	}
-	return rc;
-}
-
-static int mb86a20s_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct mb86a20s_state *state = fe->demodulator_priv;
-	unsigned rf_max, rf_min, rf;
-	u8	 val;
-
-	dprintk("\n");
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	/* Does a binary search to get RF strength */
-	rf_max = 0xfff;
-	rf_min = 0;
-	do {
-		rf = (rf_max + rf_min) / 2;
-		mb86a20s_writereg(state, 0x04, 0x1f);
-		mb86a20s_writereg(state, 0x05, rf >> 8);
-		mb86a20s_writereg(state, 0x04, 0x20);
-		mb86a20s_writereg(state, 0x04, rf);
-
-		val = mb86a20s_readreg(state, 0x02);
-		if (val & 0x08)
-			rf_min = (rf_max + rf_min) / 2;
-		else
-			rf_max = (rf_max + rf_min) / 2;
-		if (rf_max - rf_min < 4) {
-			*strength = (((rf_max + rf_min) / 2) * 65535) / 4095;
-			break;
-		}
-	} while (1);
-
-	dprintk("signal strength = %d\n", *strength);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	return 0;
-}
-
-static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct mb86a20s_state *state = fe->demodulator_priv;
-	u8 val;
-
-	dprintk("\n");
-	*status = 0;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-	val = mb86a20s_readreg(state, 0x0a) & 0xf;
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	if (val >= 2)
-		*status |= FE_HAS_SIGNAL;
-
-	if (val >= 4)
-		*status |= FE_HAS_CARRIER;
-
-	if (val >= 5)
-		*status |= FE_HAS_VITERBI;
-
-	if (val >= 7)
-		*status |= FE_HAS_SYNC;
-
-	if (val >= 8)				/* Maybe 9? */
-		*status |= FE_HAS_LOCK;
-
-	dprintk("val = %d, status = 0x%02x\n", val, *status);
-
-	return 0;
-}
-
-static int mb86a20s_set_frontend(struct dvb_frontend *fe)
-{
-	struct mb86a20s_state *state = fe->demodulator_priv;
-	int rc;
-#if 0
-	/*
-	 * FIXME: Properly implement the set frontend properties
-	 */
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-#endif
-
-	dprintk("\n");
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	dprintk("Calling tuner set parameters\n");
-	fe->ops.tuner_ops.set_params(fe);
-
-	/*
-	 * Make it more reliable: if, for some reason, the initial
-	 * device initialization doesn't happen, initialize it when
-	 * a SBTVD parameters are adjusted.
-	 *
-	 * Unfortunately, due to a hard to track bug at tda829x/tda18271,
-	 * the agc callback logic is not called during DVB attach time,
-	 * causing mb86a20s to not be initialized with Kworld SBTVD.
-	 * So, this hack is needed, in order to make Kworld SBTVD to work.
-	 */
-	if (state->need_init)
-		mb86a20s_initfe(fe);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-	rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception);
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	return rc;
-}
-
-static int mb86a20s_get_modulation(struct mb86a20s_state *state,
-				   unsigned layer)
-{
-	int rc;
-	static unsigned char reg[] = {
-		[0] = 0x86,	/* Layer A */
-		[1] = 0x8a,	/* Layer B */
-		[2] = 0x8e,	/* Layer C */
-	};
-
-	if (layer >= ARRAY_SIZE(reg))
-		return -EINVAL;
-	rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
-	if (rc < 0)
-		return rc;
-	rc = mb86a20s_readreg(state, 0x6e);
-	if (rc < 0)
-		return rc;
-	switch ((rc & 0x70) >> 4) {
-	case 0:
-		return DQPSK;
-	case 1:
-		return QPSK;
-	case 2:
-		return QAM_16;
-	case 3:
-		return QAM_64;
-	default:
-		return QAM_AUTO;
-	}
-}
-
-static int mb86a20s_get_fec(struct mb86a20s_state *state,
-			    unsigned layer)
-{
-	int rc;
-
-	static unsigned char reg[] = {
-		[0] = 0x87,	/* Layer A */
-		[1] = 0x8b,	/* Layer B */
-		[2] = 0x8f,	/* Layer C */
-	};
-
-	if (layer >= ARRAY_SIZE(reg))
-		return -EINVAL;
-	rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
-	if (rc < 0)
-		return rc;
-	rc = mb86a20s_readreg(state, 0x6e);
-	if (rc < 0)
-		return rc;
-	switch (rc) {
-	case 0:
-		return FEC_1_2;
-	case 1:
-		return FEC_2_3;
-	case 2:
-		return FEC_3_4;
-	case 3:
-		return FEC_5_6;
-	case 4:
-		return FEC_7_8;
-	default:
-		return FEC_AUTO;
-	}
-}
-
-static int mb86a20s_get_interleaving(struct mb86a20s_state *state,
-				     unsigned layer)
-{
-	int rc;
-
-	static unsigned char reg[] = {
-		[0] = 0x88,	/* Layer A */
-		[1] = 0x8c,	/* Layer B */
-		[2] = 0x90,	/* Layer C */
-	};
-
-	if (layer >= ARRAY_SIZE(reg))
-		return -EINVAL;
-	rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
-	if (rc < 0)
-		return rc;
-	rc = mb86a20s_readreg(state, 0x6e);
-	if (rc < 0)
-		return rc;
-	if (rc > 3)
-		return -EINVAL;	/* Not used */
-	return rc;
-}
-
-static int mb86a20s_get_segment_count(struct mb86a20s_state *state,
-				      unsigned layer)
-{
-	int rc, count;
-
-	static unsigned char reg[] = {
-		[0] = 0x89,	/* Layer A */
-		[1] = 0x8d,	/* Layer B */
-		[2] = 0x91,	/* Layer C */
-	};
-
-	if (layer >= ARRAY_SIZE(reg))
-		return -EINVAL;
-	rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
-	if (rc < 0)
-		return rc;
-	rc = mb86a20s_readreg(state, 0x6e);
-	if (rc < 0)
-		return rc;
-	count = (rc >> 4) & 0x0f;
-
-	return count;
-}
-
-static int mb86a20s_get_frontend(struct dvb_frontend *fe)
-{
-	struct mb86a20s_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	int i, rc;
-
-	/* Fixed parameters */
-	p->delivery_system = SYS_ISDBT;
-	p->bandwidth_hz = 6000000;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	/* Check for partial reception */
-	rc = mb86a20s_writereg(state, 0x6d, 0x85);
-	if (rc >= 0)
-		rc = mb86a20s_readreg(state, 0x6e);
-	if (rc >= 0)
-		p->isdbt_partial_reception = (rc & 0x10) ? 1 : 0;
-
-	/* Get per-layer data */
-	p->isdbt_layer_enabled = 0;
-	for (i = 0; i < 3; i++) {
-		rc = mb86a20s_get_segment_count(state, i);
-			if (rc >= 0 && rc < 14)
-				p->layer[i].segment_count = rc;
-		if (rc == 0x0f)
-			continue;
-		p->isdbt_layer_enabled |= 1 << i;
-		rc = mb86a20s_get_modulation(state, i);
-			if (rc >= 0)
-				p->layer[i].modulation = rc;
-		rc = mb86a20s_get_fec(state, i);
-			if (rc >= 0)
-				p->layer[i].fec = rc;
-		rc = mb86a20s_get_interleaving(state, i);
-			if (rc >= 0)
-				p->layer[i].interleaving = rc;
-	}
-
-	p->isdbt_sb_mode = 0;
-	rc = mb86a20s_writereg(state, 0x6d, 0x84);
-	if ((rc >= 0) && ((rc & 0x60) == 0x20)) {
-		p->isdbt_sb_mode = 1;
-		/* At least, one segment should exist */
-		if (!p->isdbt_sb_segment_count)
-			p->isdbt_sb_segment_count = 1;
-	} else
-		p->isdbt_sb_segment_count = 0;
-
-	/* Get transmission mode and guard interval */
-	p->transmission_mode = TRANSMISSION_MODE_AUTO;
-	p->guard_interval = GUARD_INTERVAL_AUTO;
-	rc = mb86a20s_readreg(state, 0x07);
-	if (rc >= 0) {
-		if ((rc & 0x60) == 0x20) {
-			switch (rc & 0x0c >> 2) {
-			case 0:
-				p->transmission_mode = TRANSMISSION_MODE_2K;
-				break;
-			case 1:
-				p->transmission_mode = TRANSMISSION_MODE_4K;
-				break;
-			case 2:
-				p->transmission_mode = TRANSMISSION_MODE_8K;
-				break;
-			}
-		}
-		if (!(rc & 0x10)) {
-			switch (rc & 0x3) {
-			case 0:
-				p->guard_interval = GUARD_INTERVAL_1_4;
-				break;
-			case 1:
-				p->guard_interval = GUARD_INTERVAL_1_8;
-				break;
-			case 2:
-				p->guard_interval = GUARD_INTERVAL_1_16;
-				break;
-			}
-		}
-	}
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	return 0;
-}
-
-static int mb86a20s_tune(struct dvb_frontend *fe,
-			bool re_tune,
-			unsigned int mode_flags,
-			unsigned int *delay,
-			fe_status_t *status)
-{
-	int rc = 0;
-
-	dprintk("\n");
-
-	if (re_tune)
-		rc = mb86a20s_set_frontend(fe);
-
-	if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
-		mb86a20s_read_status(fe, status);
-
-	return rc;
-}
-
-static void mb86a20s_release(struct dvb_frontend *fe)
-{
-	struct mb86a20s_state *state = fe->demodulator_priv;
-
-	dprintk("\n");
-
-	kfree(state);
-}
-
-static struct dvb_frontend_ops mb86a20s_ops;
-
-struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
-				    struct i2c_adapter *i2c)
-{
-	u8	rev;
-
-	/* allocate memory for the internal state */
-	struct mb86a20s_state *state =
-		kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL);
-
-	dprintk("\n");
-	if (state == NULL) {
-		rc("Unable to kzalloc\n");
-		goto error;
-	}
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &mb86a20s_ops,
-		sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-
-	/* Check if it is a mb86a20s frontend */
-	rev = mb86a20s_readreg(state, 0);
-
-	if (rev == 0x13) {
-		printk(KERN_INFO "Detected a Fujitsu mb86a20s frontend\n");
-	} else {
-		printk(KERN_ERR "Frontend revision %d is unknown - aborting.\n",
-		       rev);
-		goto error;
-	}
-
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(mb86a20s_attach);
-
-static struct dvb_frontend_ops mb86a20s_ops = {
-	.delsys = { SYS_ISDBT },
-	/* Use dib8000 values per default */
-	.info = {
-		.name = "Fujitsu mb86A20s",
-		.caps = FE_CAN_INVERSION_AUTO | FE_CAN_RECOVER |
-			FE_CAN_FEC_1_2  | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6  | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK     | FE_CAN_QAM_16  | FE_CAN_QAM_64 |
-			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_QAM_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO    | FE_CAN_HIERARCHY_AUTO,
-		/* Actually, those values depend on the used tuner */
-		.frequency_min = 45000000,
-		.frequency_max = 864000000,
-		.frequency_stepsize = 62500,
-	},
-
-	.release = mb86a20s_release,
-
-	.init = mb86a20s_initfe,
-	.set_frontend = mb86a20s_set_frontend,
-	.get_frontend = mb86a20s_get_frontend,
-	.read_status = mb86a20s_read_status,
-	.read_signal_strength = mb86a20s_read_signal_strength,
-	.tune = mb86a20s_tune,
-};
-
-MODULE_DESCRIPTION("DVB Frontend module for Fujitsu mb86A20s hardware");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/mb86a20s.h b/drivers/media/dvb/frontends/mb86a20s.h
deleted file mode 100644
index bf22e77..0000000
--- a/drivers/media/dvb/frontends/mb86a20s.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *   Fujitsu mb86a20s driver
- *
- *   Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- *   This program is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU General Public License as
- *   published by the Free Software Foundation version 2.
- *
- *   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 MB86A20S_H
-#define MB86A20S_H
-
-#include <linux/dvb/frontend.h>
-
-/**
- * struct mb86a20s_config - Define the per-device attributes of the frontend
- *
- * @demod_address:	the demodulator's i2c address
- */
-
-struct mb86a20s_config {
-	u8 demod_address;
-	bool is_serial;
-};
-
-#if defined(CONFIG_DVB_MB86A20S) || (defined(CONFIG_DVB_MB86A20S_MODULE) \
-	&& defined(MODULE))
-extern struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
-					   struct i2c_adapter *i2c);
-extern struct i2c_adapter *mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *);
-#else
-static inline struct dvb_frontend *mb86a20s_attach(
-	const struct mb86a20s_config *config, struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-static struct i2c_adapter *
-	mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* MB86A20S */
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
deleted file mode 100644
index e20bf13..0000000
--- a/drivers/media/dvb/frontends/mt312.c
+++ /dev/null
@@ -1,839 +0,0 @@
-/*
-    Driver for Zarlink VP310/MT312/ZL10313 Satellite Channel Decoder
-
-    Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
-    Copyright (C) 2008 Matthias Schwarzott <zzam@gentoo.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    References:
-    http://products.zarlink.com/product_profiles/MT312.htm
-    http://products.zarlink.com/product_profiles/SL1935.htm
-*/
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "mt312_priv.h"
-#include "mt312.h"
-
-
-struct mt312_state {
-	struct i2c_adapter *i2c;
-	/* configuration settings */
-	const struct mt312_config *config;
-	struct dvb_frontend frontend;
-
-	u8 id;
-	unsigned long xtal;
-	u8 freq_mult;
-};
-
-static int debug;
-#define dprintk(args...) \
-	do { \
-		if (debug) \
-			printk(KERN_DEBUG "mt312: " args); \
-	} while (0)
-
-#define MT312_PLL_CLK		10000000UL	/* 10 MHz */
-#define MT312_PLL_CLK_10_111	10111000UL	/* 10.111 MHz */
-
-static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
-		      u8 *buf, const size_t count)
-{
-	int ret;
-	struct i2c_msg msg[2];
-	u8 regbuf[1] = { reg };
-
-	msg[0].addr = state->config->demod_address;
-	msg[0].flags = 0;
-	msg[0].buf = regbuf;
-	msg[0].len = 1;
-	msg[1].addr = state->config->demod_address;
-	msg[1].flags = I2C_M_RD;
-	msg[1].buf = buf;
-	msg[1].len = count;
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2) {
-		printk(KERN_DEBUG "%s: ret == %d\n", __func__, ret);
-		return -EREMOTEIO;
-	}
-
-	if (debug) {
-		int i;
-		dprintk("R(%d):", reg & 0x7f);
-		for (i = 0; i < count; i++)
-			printk(KERN_CONT " %02x", buf[i]);
-		printk("\n");
-	}
-
-	return 0;
-}
-
-static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
-		       const u8 *src, const size_t count)
-{
-	int ret;
-	u8 buf[count + 1];
-	struct i2c_msg msg;
-
-	if (debug) {
-		int i;
-		dprintk("W(%d):", reg & 0x7f);
-		for (i = 0; i < count; i++)
-			printk(KERN_CONT " %02x", src[i]);
-		printk("\n");
-	}
-
-	buf[0] = reg;
-	memcpy(&buf[1], src, count);
-
-	msg.addr = state->config->demod_address;
-	msg.flags = 0;
-	msg.buf = buf;
-	msg.len = count + 1;
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-
-	if (ret != 1) {
-		dprintk("%s: ret == %d\n", __func__, ret);
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static inline int mt312_readreg(struct mt312_state *state,
-				const enum mt312_reg_addr reg, u8 *val)
-{
-	return mt312_read(state, reg, val, 1);
-}
-
-static inline int mt312_writereg(struct mt312_state *state,
-				 const enum mt312_reg_addr reg, const u8 val)
-{
-	return mt312_write(state, reg, &val, 1);
-}
-
-static inline u32 mt312_div(u32 a, u32 b)
-{
-	return (a + (b / 2)) / b;
-}
-
-static int mt312_reset(struct mt312_state *state, const u8 full)
-{
-	return mt312_writereg(state, RESET, full ? 0x80 : 0x40);
-}
-
-static int mt312_get_inversion(struct mt312_state *state,
-			       fe_spectral_inversion_t *i)
-{
-	int ret;
-	u8 vit_mode;
-
-	ret = mt312_readreg(state, VIT_MODE, &vit_mode);
-	if (ret < 0)
-		return ret;
-
-	if (vit_mode & 0x80)	/* auto inversion was used */
-		*i = (vit_mode & 0x40) ? INVERSION_ON : INVERSION_OFF;
-
-	return 0;
-}
-
-static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr)
-{
-	int ret;
-	u8 sym_rate_h;
-	u8 dec_ratio;
-	u16 sym_rat_op;
-	u16 monitor;
-	u8 buf[2];
-
-	ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h);
-	if (ret < 0)
-		return ret;
-
-	if (sym_rate_h & 0x80) {
-		/* symbol rate search was used */
-		ret = mt312_writereg(state, MON_CTRL, 0x03);
-		if (ret < 0)
-			return ret;
-
-		ret = mt312_read(state, MONITOR_H, buf, sizeof(buf));
-		if (ret < 0)
-			return ret;
-
-		monitor = (buf[0] << 8) | buf[1];
-
-		dprintk("sr(auto) = %u\n",
-		       mt312_div(monitor * 15625, 4));
-	} else {
-		ret = mt312_writereg(state, MON_CTRL, 0x05);
-		if (ret < 0)
-			return ret;
-
-		ret = mt312_read(state, MONITOR_H, buf, sizeof(buf));
-		if (ret < 0)
-			return ret;
-
-		dec_ratio = ((buf[0] >> 5) & 0x07) * 32;
-
-		ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf));
-		if (ret < 0)
-			return ret;
-
-		sym_rat_op = (buf[0] << 8) | buf[1];
-
-		dprintk("sym_rat_op=%d dec_ratio=%d\n",
-		       sym_rat_op, dec_ratio);
-		dprintk("*sr(manual) = %lu\n",
-		       (((state->xtal * 8192) / (sym_rat_op + 8192)) *
-			2) - dec_ratio);
-	}
-
-	return 0;
-}
-
-static int mt312_get_code_rate(struct mt312_state *state, fe_code_rate_t *cr)
-{
-	const fe_code_rate_t fec_tab[8] =
-	    { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8,
-		FEC_AUTO, FEC_AUTO };
-
-	int ret;
-	u8 fec_status;
-
-	ret = mt312_readreg(state, FEC_STATUS, &fec_status);
-	if (ret < 0)
-		return ret;
-
-	*cr = fec_tab[(fec_status >> 4) & 0x07];
-
-	return 0;
-}
-
-static int mt312_initfe(struct dvb_frontend *fe)
-{
-	struct mt312_state *state = fe->demodulator_priv;
-	int ret;
-	u8 buf[2];
-
-	/* wake up */
-	ret = mt312_writereg(state, CONFIG,
-			(state->freq_mult == 6 ? 0x88 : 0x8c));
-	if (ret < 0)
-		return ret;
-
-	/* wait at least 150 usec */
-	udelay(150);
-
-	/* full reset */
-	ret = mt312_reset(state, 1);
-	if (ret < 0)
-		return ret;
-
-/* Per datasheet, write correct values. 09/28/03 ACCJr.
- * If we don't do this, we won't get FE_HAS_VITERBI in the VP310. */
-	{
-		u8 buf_def[8] = { 0x14, 0x12, 0x03, 0x02,
-				  0x01, 0x00, 0x00, 0x00 };
-
-		ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def));
-		if (ret < 0)
-			return ret;
-	}
-
-	switch (state->id) {
-	case ID_ZL10313:
-		/* enable ADC */
-		ret = mt312_writereg(state, GPP_CTRL, 0x80);
-		if (ret < 0)
-			return ret;
-
-		/* configure ZL10313 for optimal ADC performance */
-		buf[0] = 0x80;
-		buf[1] = 0xB0;
-		ret = mt312_write(state, HW_CTRL, buf, 2);
-		if (ret < 0)
-			return ret;
-
-		/* enable MPEG output and ADCs */
-		ret = mt312_writereg(state, HW_CTRL, 0x00);
-		if (ret < 0)
-			return ret;
-
-		ret = mt312_writereg(state, MPEG_CTRL, 0x00);
-		if (ret < 0)
-			return ret;
-
-		break;
-	}
-
-	/* SYS_CLK */
-	buf[0] = mt312_div(state->xtal * state->freq_mult * 2, 1000000);
-
-	/* DISEQC_RATIO */
-	buf[1] = mt312_div(state->xtal, 22000 * 4);
-
-	ret = mt312_write(state, SYS_CLK, buf, sizeof(buf));
-	if (ret < 0)
-		return ret;
-
-	ret = mt312_writereg(state, SNR_THS_HIGH, 0x32);
-	if (ret < 0)
-		return ret;
-
-	/* different MOCLK polarity */
-	switch (state->id) {
-	case ID_ZL10313:
-		buf[0] = 0x33;
-		break;
-	default:
-		buf[0] = 0x53;
-		break;
-	}
-
-	ret = mt312_writereg(state, OP_CTRL, buf[0]);
-	if (ret < 0)
-		return ret;
-
-	/* TS_SW_LIM */
-	buf[0] = 0x8c;
-	buf[1] = 0x98;
-
-	ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf));
-	if (ret < 0)
-		return ret;
-
-	ret = mt312_writereg(state, CS_SW_LIM, 0x69);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static int mt312_send_master_cmd(struct dvb_frontend *fe,
-				 struct dvb_diseqc_master_cmd *c)
-{
-	struct mt312_state *state = fe->demodulator_priv;
-	int ret;
-	u8 diseqc_mode;
-
-	if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg)))
-		return -EINVAL;
-
-	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
-	if (ret < 0)
-		return ret;
-
-	ret = mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len);
-	if (ret < 0)
-		return ret;
-
-	ret = mt312_writereg(state, DISEQC_MODE,
-			     (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3)
-			     | 0x04);
-	if (ret < 0)
-		return ret;
-
-	/* is there a better way to wait for message to be transmitted */
-	msleep(100);
-
-	/* set DISEQC_MODE[2:0] to zero if a return message is expected */
-	if (c->msg[0] & 0x02) {
-		ret = mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40));
-		if (ret < 0)
-			return ret;
-	}
-
-	return 0;
-}
-
-static int mt312_send_burst(struct dvb_frontend *fe, const fe_sec_mini_cmd_t c)
-{
-	struct mt312_state *state = fe->demodulator_priv;
-	const u8 mini_tab[2] = { 0x02, 0x03 };
-
-	int ret;
-	u8 diseqc_mode;
-
-	if (c > SEC_MINI_B)
-		return -EINVAL;
-
-	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
-	if (ret < 0)
-		return ret;
-
-	ret = mt312_writereg(state, DISEQC_MODE,
-			     (diseqc_mode & 0x40) | mini_tab[c]);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static int mt312_set_tone(struct dvb_frontend *fe, const fe_sec_tone_mode_t t)
-{
-	struct mt312_state *state = fe->demodulator_priv;
-	const u8 tone_tab[2] = { 0x01, 0x00 };
-
-	int ret;
-	u8 diseqc_mode;
-
-	if (t > SEC_TONE_OFF)
-		return -EINVAL;
-
-	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
-	if (ret < 0)
-		return ret;
-
-	ret = mt312_writereg(state, DISEQC_MODE,
-			     (diseqc_mode & 0x40) | tone_tab[t]);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static int mt312_set_voltage(struct dvb_frontend *fe, const fe_sec_voltage_t v)
-{
-	struct mt312_state *state = fe->demodulator_priv;
-	const u8 volt_tab[3] = { 0x00, 0x40, 0x00 };
-	u8 val;
-
-	if (v > SEC_VOLTAGE_OFF)
-		return -EINVAL;
-
-	val = volt_tab[v];
-	if (state->config->voltage_inverted)
-		val ^= 0x40;
-
-	return mt312_writereg(state, DISEQC_MODE, val);
-}
-
-static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s)
-{
-	struct mt312_state *state = fe->demodulator_priv;
-	int ret;
-	u8 status[3];
-
-	*s = 0;
-
-	ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status));
-	if (ret < 0)
-		return ret;
-
-	dprintk("QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x,"
-		" FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]);
-
-	if (status[0] & 0xc0)
-		*s |= FE_HAS_SIGNAL;	/* signal noise ratio */
-	if (status[0] & 0x04)
-		*s |= FE_HAS_CARRIER;	/* qpsk carrier lock */
-	if (status[2] & 0x02)
-		*s |= FE_HAS_VITERBI;	/* viterbi lock */
-	if (status[2] & 0x04)
-		*s |= FE_HAS_SYNC;	/* byte align lock */
-	if (status[0] & 0x01)
-		*s |= FE_HAS_LOCK;	/* qpsk lock */
-
-	return 0;
-}
-
-static int mt312_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct mt312_state *state = fe->demodulator_priv;
-	int ret;
-	u8 buf[3];
-
-	ret = mt312_read(state, RS_BERCNT_H, buf, 3);
-	if (ret < 0)
-		return ret;
-
-	*ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64;
-
-	return 0;
-}
-
-static int mt312_read_signal_strength(struct dvb_frontend *fe,
-				      u16 *signal_strength)
-{
-	struct mt312_state *state = fe->demodulator_priv;
-	int ret;
-	u8 buf[3];
-	u16 agc;
-	s16 err_db;
-
-	ret = mt312_read(state, AGC_H, buf, sizeof(buf));
-	if (ret < 0)
-		return ret;
-
-	agc = (buf[0] << 6) | (buf[1] >> 2);
-	err_db = (s16) (((buf[1] & 0x03) << 14) | buf[2] << 6) >> 6;
-
-	*signal_strength = agc;
-
-	dprintk("agc=%08x err_db=%hd\n", agc, err_db);
-
-	return 0;
-}
-
-static int mt312_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct mt312_state *state = fe->demodulator_priv;
-	int ret;
-	u8 buf[2];
-
-	ret = mt312_read(state, M_SNR_H, buf, sizeof(buf));
-	if (ret < 0)
-		return ret;
-
-	*snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1);
-
-	return 0;
-}
-
-static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc)
-{
-	struct mt312_state *state = fe->demodulator_priv;
-	int ret;
-	u8 buf[2];
-
-	ret = mt312_read(state, RS_UBC_H, buf, sizeof(buf));
-	if (ret < 0)
-		return ret;
-
-	*ubc = (buf[0] << 8) | buf[1];
-
-	return 0;
-}
-
-static int mt312_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct mt312_state *state = fe->demodulator_priv;
-	int ret;
-	u8 buf[5], config_val;
-	u16 sr;
-
-	const u8 fec_tab[10] =
-	    { 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10, 0x20, 0x3f, 0x3f };
-	const u8 inv_tab[3] = { 0x00, 0x40, 0x80 };
-
-	dprintk("%s: Freq %d\n", __func__, p->frequency);
-
-	if ((p->frequency < fe->ops.info.frequency_min)
-	    || (p->frequency > fe->ops.info.frequency_max))
-		return -EINVAL;
-
-	if ((p->inversion < INVERSION_OFF)
-	    || (p->inversion > INVERSION_ON))
-		return -EINVAL;
-
-	if ((p->symbol_rate < fe->ops.info.symbol_rate_min)
-	    || (p->symbol_rate > fe->ops.info.symbol_rate_max))
-		return -EINVAL;
-
-	if ((p->fec_inner < FEC_NONE)
-	    || (p->fec_inner > FEC_AUTO))
-		return -EINVAL;
-
-	if ((p->fec_inner == FEC_4_5)
-	    || (p->fec_inner == FEC_8_9))
-		return -EINVAL;
-
-	switch (state->id) {
-	case ID_VP310:
-	/* For now we will do this only for the VP310.
-	 * It should be better for the mt312 as well,
-	 * but tuning will be slower. ACCJr 09/29/03
-	 */
-		ret = mt312_readreg(state, CONFIG, &config_val);
-		if (ret < 0)
-			return ret;
-		if (p->symbol_rate >= 30000000) {
-			/* Note that 30MS/s should use 90MHz */
-			if (state->freq_mult == 6) {
-				/* We are running 60MHz */
-				state->freq_mult = 9;
-				ret = mt312_initfe(fe);
-				if (ret < 0)
-					return ret;
-			}
-		} else {
-			if (state->freq_mult == 9) {
-				/* We are running 90MHz */
-				state->freq_mult = 6;
-				ret = mt312_initfe(fe);
-				if (ret < 0)
-					return ret;
-			}
-		}
-		break;
-
-	case ID_MT312:
-	case ID_ZL10313:
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	/* sr = (u16)(sr * 256.0 / 1000000.0) */
-	sr = mt312_div(p->symbol_rate * 4, 15625);
-
-	/* SYM_RATE */
-	buf[0] = (sr >> 8) & 0x3f;
-	buf[1] = (sr >> 0) & 0xff;
-
-	/* VIT_MODE */
-	buf[2] = inv_tab[p->inversion] | fec_tab[p->fec_inner];
-
-	/* QPSK_CTRL */
-	buf[3] = 0x40;		/* swap I and Q before QPSK demodulation */
-
-	if (p->symbol_rate < 10000000)
-		buf[3] |= 0x04;	/* use afc mode */
-
-	/* GO */
-	buf[4] = 0x01;
-
-	ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf));
-	if (ret < 0)
-		return ret;
-
-	mt312_reset(state, 0);
-
-	return 0;
-}
-
-static int mt312_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct mt312_state *state = fe->demodulator_priv;
-	int ret;
-
-	ret = mt312_get_inversion(state, &p->inversion);
-	if (ret < 0)
-		return ret;
-
-	ret = mt312_get_symbol_rate(state, &p->symbol_rate);
-	if (ret < 0)
-		return ret;
-
-	ret = mt312_get_code_rate(state, &p->fec_inner);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static int mt312_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct mt312_state *state = fe->demodulator_priv;
-
-	u8 val = 0x00;
-	int ret;
-
-	switch (state->id) {
-	case ID_ZL10313:
-		ret = mt312_readreg(state, GPP_CTRL, &val);
-		if (ret < 0)
-			goto error;
-
-		/* preserve this bit to not accidentally shutdown ADC */
-		val &= 0x80;
-		break;
-	}
-
-	if (enable)
-		val |= 0x40;
-	else
-		val &= ~0x40;
-
-	ret = mt312_writereg(state, GPP_CTRL, val);
-
-error:
-	return ret;
-}
-
-static int mt312_sleep(struct dvb_frontend *fe)
-{
-	struct mt312_state *state = fe->demodulator_priv;
-	int ret;
-	u8 config;
-
-	/* reset all registers to defaults */
-	ret = mt312_reset(state, 1);
-	if (ret < 0)
-		return ret;
-
-	if (state->id == ID_ZL10313) {
-		/* reset ADC */
-		ret = mt312_writereg(state, GPP_CTRL, 0x00);
-		if (ret < 0)
-			return ret;
-
-		/* full shutdown of ADCs, mpeg bus tristated */
-		ret = mt312_writereg(state, HW_CTRL, 0x0d);
-		if (ret < 0)
-			return ret;
-	}
-
-	ret = mt312_readreg(state, CONFIG, &config);
-	if (ret < 0)
-		return ret;
-
-	/* enter standby */
-	ret = mt312_writereg(state, CONFIG, config & 0x7f);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static int mt312_get_tune_settings(struct dvb_frontend *fe,
-		struct dvb_frontend_tune_settings *fesettings)
-{
-	fesettings->min_delay_ms = 50;
-	fesettings->step_size = 0;
-	fesettings->max_drift = 0;
-	return 0;
-}
-
-static void mt312_release(struct dvb_frontend *fe)
-{
-	struct mt312_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-#define MT312_SYS_CLK		90000000UL	/* 90 MHz */
-static struct dvb_frontend_ops mt312_ops = {
-	.delsys = { SYS_DVBS },
-	.info = {
-		.name = "Zarlink ???? DVB-S",
-		.frequency_min = 950000,
-		.frequency_max = 2150000,
-		/* FIXME: adjust freq to real used xtal */
-		.frequency_stepsize = (MT312_PLL_CLK / 1000) / 128,
-		.symbol_rate_min = MT312_SYS_CLK / 128, /* FIXME as above */
-		.symbol_rate_max = MT312_SYS_CLK / 2,
-		.caps =
-		    FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
-		    FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
-		    FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_MUTE_TS |
-		    FE_CAN_RECOVER
-	},
-
-	.release = mt312_release,
-
-	.init = mt312_initfe,
-	.sleep = mt312_sleep,
-	.i2c_gate_ctrl = mt312_i2c_gate_ctrl,
-
-	.set_frontend = mt312_set_frontend,
-	.get_frontend = mt312_get_frontend,
-	.get_tune_settings = mt312_get_tune_settings,
-
-	.read_status = mt312_read_status,
-	.read_ber = mt312_read_ber,
-	.read_signal_strength = mt312_read_signal_strength,
-	.read_snr = mt312_read_snr,
-	.read_ucblocks = mt312_read_ucblocks,
-
-	.diseqc_send_master_cmd = mt312_send_master_cmd,
-	.diseqc_send_burst = mt312_send_burst,
-	.set_tone = mt312_set_tone,
-	.set_voltage = mt312_set_voltage,
-};
-
-struct dvb_frontend *mt312_attach(const struct mt312_config *config,
-					struct i2c_adapter *i2c)
-{
-	struct mt312_state *state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct mt312_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-
-	/* check if the demod is there */
-	if (mt312_readreg(state, ID, &state->id) < 0)
-		goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &mt312_ops,
-		sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-
-	switch (state->id) {
-	case ID_VP310:
-		strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S");
-		state->xtal = MT312_PLL_CLK;
-		state->freq_mult = 9;
-		break;
-	case ID_MT312:
-		strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S");
-		state->xtal = MT312_PLL_CLK;
-		state->freq_mult = 6;
-		break;
-	case ID_ZL10313:
-		strcpy(state->frontend.ops.info.name, "Zarlink ZL10313 DVB-S");
-		state->xtal = MT312_PLL_CLK_10_111;
-		state->freq_mult = 9;
-		break;
-	default:
-		printk(KERN_WARNING "Only Zarlink VP310/MT312/ZL10313"
-			" are supported chips.\n");
-		goto error;
-	}
-
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(mt312_attach);
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("Zarlink VP310/MT312/ZL10313 DVB-S Demodulator driver");
-MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
-MODULE_AUTHOR("Matthias Schwarzott <zzam@gentoo.org>");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h
deleted file mode 100644
index 29e3bb5..0000000
--- a/drivers/media/dvb/frontends/mt312.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
-    Driver for Zarlink MT312 Satellite Channel Decoder
-
-    Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    References:
-    http://products.zarlink.com/product_profiles/MT312.htm
-    http://products.zarlink.com/product_profiles/SL1935.htm
-*/
-
-#ifndef MT312_H
-#define MT312_H
-
-#include <linux/dvb/frontend.h>
-
-struct mt312_config {
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* inverted voltage setting */
-	unsigned int voltage_inverted:1;
-};
-
-#if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE))
-struct dvb_frontend *mt312_attach(const struct mt312_config *config,
-					struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *mt312_attach(
-	const struct mt312_config *config, struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_MT312 */
-
-#endif /* MT312_H */
diff --git a/drivers/media/dvb/frontends/mt312_priv.h b/drivers/media/dvb/frontends/mt312_priv.h
deleted file mode 100644
index a3959f9..0000000
--- a/drivers/media/dvb/frontends/mt312_priv.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
-    Driver for Zarlink MT312 QPSK Frontend
-
-    Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef _DVB_FRONTENDS_MT312_PRIV
-#define _DVB_FRONTENDS_MT312_PRIV
-
-enum mt312_reg_addr {
-	QPSK_INT_H = 0,
-	QPSK_INT_M = 1,
-	QPSK_INT_L = 2,
-	FEC_INT = 3,
-	QPSK_STAT_H = 4,
-	QPSK_STAT_L = 5,
-	FEC_STATUS = 6,
-	LNB_FREQ_H = 7,
-	LNB_FREQ_L = 8,
-	M_SNR_H = 9,
-	M_SNR_L = 10,
-	VIT_ERRCNT_H = 11,
-	VIT_ERRCNT_M = 12,
-	VIT_ERRCNT_L = 13,
-	RS_BERCNT_H = 14,
-	RS_BERCNT_M = 15,
-	RS_BERCNT_L = 16,
-	RS_UBC_H = 17,
-	RS_UBC_L = 18,
-	SIG_LEVEL = 19,
-	GPP_CTRL = 20,
-	RESET = 21,
-	DISEQC_MODE = 22,
-	SYM_RATE_H = 23,
-	SYM_RATE_L = 24,
-	VIT_MODE = 25,
-	QPSK_CTRL = 26,
-	GO = 27,
-	IE_QPSK_H = 28,
-	IE_QPSK_M = 29,
-	IE_QPSK_L = 30,
-	IE_FEC = 31,
-	QPSK_STAT_EN = 32,
-	FEC_STAT_EN = 33,
-	SYS_CLK = 34,
-	DISEQC_RATIO = 35,
-	DISEQC_INSTR = 36,
-	FR_LIM = 37,
-	FR_OFF = 38,
-	AGC_CTRL = 39,
-	AGC_INIT = 40,
-	AGC_REF = 41,
-	AGC_MAX = 42,
-	AGC_MIN = 43,
-	AGC_LK_TH = 44,
-	TS_AGC_LK_TH = 45,
-	AGC_PWR_SET = 46,
-	QPSK_MISC = 47,
-	SNR_THS_LOW = 48,
-	SNR_THS_HIGH = 49,
-	TS_SW_RATE = 50,
-	TS_SW_LIM_L = 51,
-	TS_SW_LIM_H = 52,
-	CS_SW_RATE_1 = 53,
-	CS_SW_RATE_2 = 54,
-	CS_SW_RATE_3 = 55,
-	CS_SW_RATE_4 = 56,
-	CS_SW_LIM = 57,
-	TS_LPK = 58,
-	TS_LPK_M = 59,
-	TS_LPK_L = 60,
-	CS_KPROP_H = 61,
-	CS_KPROP_L = 62,
-	CS_KINT_H = 63,
-	CS_KINT_L = 64,
-	QPSK_SCALE = 65,
-	TLD_OUTCLK_TH = 66,
-	TLD_INCLK_TH = 67,
-	FLD_TH = 68,
-	PLD_OUTLK3 = 69,
-	PLD_OUTLK2 = 70,
-	PLD_OUTLK1 = 71,
-	PLD_OUTLK0 = 72,
-	PLD_INLK3 = 73,
-	PLD_INLK2 = 74,
-	PLD_INLK1 = 75,
-	PLD_INLK0 = 76,
-	PLD_ACC_TIME = 77,
-	SWEEP_PAR = 78,
-	STARTUP_TIME = 79,
-	LOSSLOCK_TH = 80,
-	FEC_LOCK_TM = 81,
-	LOSSLOCK_TM = 82,
-	VIT_ERRPER_H = 83,
-	VIT_ERRPER_M = 84,
-	VIT_ERRPER_L = 85,
-	HW_CTRL = 84,	/* ZL10313 only */
-	MPEG_CTRL = 85,	/* ZL10313 only */
-	VIT_SETUP = 86,
-	VIT_REF0 = 87,
-	VIT_REF1 = 88,
-	VIT_REF2 = 89,
-	VIT_REF3 = 90,
-	VIT_REF4 = 91,
-	VIT_REF5 = 92,
-	VIT_REF6 = 93,
-	VIT_MAXERR = 94,
-	BA_SETUPT = 95,
-	OP_CTRL = 96,
-	FEC_SETUP = 97,
-	PROG_SYNC = 98,
-	AFC_SEAR_TH = 99,
-	CSACC_DIF_TH = 100,
-	QPSK_LK_CT = 101,
-	QPSK_ST_CT = 102,
-	MON_CTRL = 103,
-	QPSK_RESET = 104,
-	QPSK_TST_CT = 105,
-	QPSK_TST_ST = 106,
-	TEST_R = 107,
-	AGC_H = 108,
-	AGC_M = 109,
-	AGC_L = 110,
-	FREQ_ERR1_H = 111,
-	FREQ_ERR1_M = 112,
-	FREQ_ERR1_L = 113,
-	FREQ_ERR2_H = 114,
-	FREQ_ERR2_L = 115,
-	SYM_RAT_OP_H = 116,
-	SYM_RAT_OP_L = 117,
-	DESEQC2_INT = 118,
-	DISEQC2_STAT = 119,
-	DISEQC2_FIFO = 120,
-	DISEQC2_CTRL1 = 121,
-	DISEQC2_CTRL2 = 122,
-	MONITOR_H = 123,
-	MONITOR_L = 124,
-	TEST_MODE = 125,
-	ID = 126,
-	CONFIG = 127
-};
-
-enum mt312_model_id {
-	ID_VP310 = 1,
-	ID_MT312 = 3,
-	ID_ZL10313 = 5,
-};
-
-#endif				/* DVB_FRONTENDS_MT312_PRIV */
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
deleted file mode 100644
index 2c3b50e..0000000
--- a/drivers/media/dvb/frontends/mt352.c
+++ /dev/null
@@ -1,610 +0,0 @@
-/*
- *  Driver for Zarlink DVB-T MT352 demodulator
- *
- *  Written by Holger Waechtler <holger@qanu.de>
- *	 and Daniel Mack <daniel@qanu.de>
- *
- *  AVerMedia AVerTV DVB-T 771 support by
- *       Wolfram Joost <dbox2@frokaschwei.de>
- *
- *  Support for Samsung TDTC9251DH01C(M) tuner
- *  Copyright (C) 2004 Antonio Mancuso <antonio.mancuso@digitaltelevision.it>
- *                     Amauri  Celani  <acelani@essegi.net>
- *
- *  DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by
- *       Christopher Pascoe <c.pascoe@itee.uq.edu.au>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "mt352_priv.h"
-#include "mt352.h"
-
-struct mt352_state {
-	struct i2c_adapter* i2c;
-	struct dvb_frontend frontend;
-
-	/* configuration settings */
-	struct mt352_config config;
-};
-
-static int debug;
-#define dprintk(args...) \
-	do { \
-		if (debug) printk(KERN_DEBUG "mt352: " args); \
-	} while (0)
-
-static int mt352_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
-{
-	struct mt352_state* state = fe->demodulator_priv;
-	u8 buf[2] = { reg, val };
-	struct i2c_msg msg = { .addr = state->config.demod_address, .flags = 0,
-			       .buf = buf, .len = 2 };
-	int err = i2c_transfer(state->i2c, &msg, 1);
-	if (err != 1) {
-		printk("mt352_write() to reg %x failed (err = %d)!\n", reg, err);
-		return err;
-	}
-	return 0;
-}
-
-static int _mt352_write(struct dvb_frontend* fe, const u8 ibuf[], int ilen)
-{
-	int err,i;
-	for (i=0; i < ilen-1; i++)
-		if ((err = mt352_single_write(fe,ibuf[0]+i,ibuf[i+1])))
-			return err;
-
-	return 0;
-}
-
-static int mt352_read_register(struct mt352_state* state, u8 reg)
-{
-	int ret;
-	u8 b0 [] = { reg };
-	u8 b1 [] = { 0 };
-	struct i2c_msg msg [] = { { .addr = state->config.demod_address,
-				    .flags = 0,
-				    .buf = b0, .len = 1 },
-				  { .addr = state->config.demod_address,
-				    .flags = I2C_M_RD,
-				    .buf = b1, .len = 1 } };
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2) {
-		printk("%s: readreg error (reg=%d, ret==%i)\n",
-		       __func__, reg, ret);
-		return ret;
-	}
-
-	return b1[0];
-}
-
-static int mt352_sleep(struct dvb_frontend* fe)
-{
-	static u8 mt352_softdown[] = { CLOCK_CTL, 0x20, 0x08 };
-
-	_mt352_write(fe, mt352_softdown, sizeof(mt352_softdown));
-	return 0;
-}
-
-static void mt352_calc_nominal_rate(struct mt352_state* state,
-				    u32 bandwidth,
-				    unsigned char *buf)
-{
-	u32 adc_clock = 20480; /* 20.340 MHz */
-	u32 bw,value;
-
-	switch (bandwidth) {
-	case 6000000:
-		bw = 6;
-		break;
-	case 7000000:
-		bw = 7;
-		break;
-	case 8000000:
-	default:
-		bw = 8;
-		break;
-	}
-	if (state->config.adc_clock)
-		adc_clock = state->config.adc_clock;
-
-	value = 64 * bw * (1<<16) / (7 * 8);
-	value = value * 1000 / adc_clock;
-	dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
-		__func__, bw, adc_clock, value);
-	buf[0] = msb(value);
-	buf[1] = lsb(value);
-}
-
-static void mt352_calc_input_freq(struct mt352_state* state,
-				  unsigned char *buf)
-{
-	int adc_clock = 20480; /* 20.480000 MHz */
-	int if2       = 36167; /* 36.166667 MHz */
-	int ife,value;
-
-	if (state->config.adc_clock)
-		adc_clock = state->config.adc_clock;
-	if (state->config.if2)
-		if2 = state->config.if2;
-
-	if (adc_clock >= if2 * 2)
-		ife = if2;
-	else {
-		ife = adc_clock - (if2 % adc_clock);
-		if (ife > adc_clock / 2)
-			ife = adc_clock - ife;
-	}
-	value = -16374 * ife / adc_clock;
-	dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
-		__func__, if2, ife, adc_clock, value, value & 0x3fff);
-	buf[0] = msb(value);
-	buf[1] = lsb(value);
-}
-
-static int mt352_set_parameters(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *op = &fe->dtv_property_cache;
-	struct mt352_state* state = fe->demodulator_priv;
-	unsigned char buf[13];
-	static unsigned char tuner_go[] = { 0x5d, 0x01 };
-	static unsigned char fsm_go[]   = { 0x5e, 0x01 };
-	unsigned int tps = 0;
-
-	switch (op->code_rate_HP) {
-		case FEC_2_3:
-			tps |= (1 << 7);
-			break;
-		case FEC_3_4:
-			tps |= (2 << 7);
-			break;
-		case FEC_5_6:
-			tps |= (3 << 7);
-			break;
-		case FEC_7_8:
-			tps |= (4 << 7);
-			break;
-		case FEC_1_2:
-		case FEC_AUTO:
-			break;
-		default:
-			return -EINVAL;
-	}
-
-	switch (op->code_rate_LP) {
-		case FEC_2_3:
-			tps |= (1 << 4);
-			break;
-		case FEC_3_4:
-			tps |= (2 << 4);
-			break;
-		case FEC_5_6:
-			tps |= (3 << 4);
-			break;
-		case FEC_7_8:
-			tps |= (4 << 4);
-			break;
-		case FEC_1_2:
-		case FEC_AUTO:
-			break;
-		case FEC_NONE:
-			if (op->hierarchy == HIERARCHY_AUTO ||
-			    op->hierarchy == HIERARCHY_NONE)
-				break;
-		default:
-			return -EINVAL;
-	}
-
-	switch (op->modulation) {
-		case QPSK:
-			break;
-		case QAM_AUTO:
-		case QAM_16:
-			tps |= (1 << 13);
-			break;
-		case QAM_64:
-			tps |= (2 << 13);
-			break;
-		default:
-			return -EINVAL;
-	}
-
-	switch (op->transmission_mode) {
-		case TRANSMISSION_MODE_2K:
-		case TRANSMISSION_MODE_AUTO:
-			break;
-		case TRANSMISSION_MODE_8K:
-			tps |= (1 << 0);
-			break;
-		default:
-			return -EINVAL;
-	}
-
-	switch (op->guard_interval) {
-		case GUARD_INTERVAL_1_32:
-		case GUARD_INTERVAL_AUTO:
-			break;
-		case GUARD_INTERVAL_1_16:
-			tps |= (1 << 2);
-			break;
-		case GUARD_INTERVAL_1_8:
-			tps |= (2 << 2);
-			break;
-		case GUARD_INTERVAL_1_4:
-			tps |= (3 << 2);
-			break;
-		default:
-			return -EINVAL;
-	}
-
-	switch (op->hierarchy) {
-		case HIERARCHY_AUTO:
-		case HIERARCHY_NONE:
-			break;
-		case HIERARCHY_1:
-			tps |= (1 << 10);
-			break;
-		case HIERARCHY_2:
-			tps |= (2 << 10);
-			break;
-		case HIERARCHY_4:
-			tps |= (3 << 10);
-			break;
-		default:
-			return -EINVAL;
-	}
-
-
-	buf[0] = TPS_GIVEN_1; /* TPS_GIVEN_1 and following registers */
-
-	buf[1] = msb(tps);      /* TPS_GIVEN_(1|0) */
-	buf[2] = lsb(tps);
-
-	buf[3] = 0x50;  // old
-//	buf[3] = 0xf4;  // pinnacle
-
-	mt352_calc_nominal_rate(state, op->bandwidth_hz, buf+4);
-	mt352_calc_input_freq(state, buf+6);
-
-	if (state->config.no_tuner) {
-		if (fe->ops.tuner_ops.set_params) {
-			fe->ops.tuner_ops.set_params(fe);
-			if (fe->ops.i2c_gate_ctrl)
-				fe->ops.i2c_gate_ctrl(fe, 0);
-		}
-
-		_mt352_write(fe, buf, 8);
-		_mt352_write(fe, fsm_go, 2);
-	} else {
-		if (fe->ops.tuner_ops.calc_regs) {
-			fe->ops.tuner_ops.calc_regs(fe, buf+8, 5);
-			buf[8] <<= 1;
-			_mt352_write(fe, buf, sizeof(buf));
-			_mt352_write(fe, tuner_go, 2);
-		}
-	}
-
-	return 0;
-}
-
-static int mt352_get_parameters(struct dvb_frontend* fe)
-{
-	struct dtv_frontend_properties *op = &fe->dtv_property_cache;
-	struct mt352_state* state = fe->demodulator_priv;
-	u16 tps;
-	u16 div;
-	u8 trl;
-	static const u8 tps_fec_to_api[8] =
-	{
-		FEC_1_2,
-		FEC_2_3,
-		FEC_3_4,
-		FEC_5_6,
-		FEC_7_8,
-		FEC_AUTO,
-		FEC_AUTO,
-		FEC_AUTO
-	};
-
-	if ( (mt352_read_register(state,0x00) & 0xC0) != 0xC0 )
-		return -EINVAL;
-
-	/* Use TPS_RECEIVED-registers, not the TPS_CURRENT-registers because
-	 * the mt352 sometimes works with the wrong parameters
-	 */
-	tps = (mt352_read_register(state, TPS_RECEIVED_1) << 8) | mt352_read_register(state, TPS_RECEIVED_0);
-	div = (mt352_read_register(state, CHAN_START_1) << 8) | mt352_read_register(state, CHAN_START_0);
-	trl = mt352_read_register(state, TRL_NOMINAL_RATE_1);
-
-	op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7];
-	op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7];
-
-	switch ( (tps >> 13) & 3)
-	{
-		case 0:
-			op->modulation = QPSK;
-			break;
-		case 1:
-			op->modulation = QAM_16;
-			break;
-		case 2:
-			op->modulation = QAM_64;
-			break;
-		default:
-			op->modulation = QAM_AUTO;
-			break;
-	}
-
-	op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K : TRANSMISSION_MODE_2K;
-
-	switch ( (tps >> 2) & 3)
-	{
-		case 0:
-			op->guard_interval = GUARD_INTERVAL_1_32;
-			break;
-		case 1:
-			op->guard_interval = GUARD_INTERVAL_1_16;
-			break;
-		case 2:
-			op->guard_interval = GUARD_INTERVAL_1_8;
-			break;
-		case 3:
-			op->guard_interval = GUARD_INTERVAL_1_4;
-			break;
-		default:
-			op->guard_interval = GUARD_INTERVAL_AUTO;
-			break;
-	}
-
-	switch ( (tps >> 10) & 7)
-	{
-		case 0:
-			op->hierarchy = HIERARCHY_NONE;
-			break;
-		case 1:
-			op->hierarchy = HIERARCHY_1;
-			break;
-		case 2:
-			op->hierarchy = HIERARCHY_2;
-			break;
-		case 3:
-			op->hierarchy = HIERARCHY_4;
-			break;
-		default:
-			op->hierarchy = HIERARCHY_AUTO;
-			break;
-	}
-
-	op->frequency = (500 * (div - IF_FREQUENCYx6)) / 3 * 1000;
-
-	if (trl == 0x72)
-		op->bandwidth_hz = 8000000;
-	else if (trl == 0x64)
-		op->bandwidth_hz = 7000000;
-	else
-		op->bandwidth_hz = 6000000;
-
-
-	if (mt352_read_register(state, STATUS_2) & 0x02)
-		op->inversion = INVERSION_OFF;
-	else
-		op->inversion = INVERSION_ON;
-
-	return 0;
-}
-
-static int mt352_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct mt352_state* state = fe->demodulator_priv;
-	int s0, s1, s3;
-
-	/* FIXME:
-	 *
-	 * The MT352 design manual from Zarlink states (page 46-47):
-	 *
-	 * Notes about the TUNER_GO register:
-	 *
-	 * If the Read_Tuner_Byte (bit-1) is activated, then the tuner status
-	 * byte is copied from the tuner to the STATUS_3 register and
-	 * completion of the read operation is indicated by bit-5 of the
-	 * INTERRUPT_3 register.
-	 */
-
-	if ((s0 = mt352_read_register(state, STATUS_0)) < 0)
-		return -EREMOTEIO;
-	if ((s1 = mt352_read_register(state, STATUS_1)) < 0)
-		return -EREMOTEIO;
-	if ((s3 = mt352_read_register(state, STATUS_3)) < 0)
-		return -EREMOTEIO;
-
-	*status = 0;
-	if (s0 & (1 << 4))
-		*status |= FE_HAS_CARRIER;
-	if (s0 & (1 << 1))
-		*status |= FE_HAS_VITERBI;
-	if (s0 & (1 << 5))
-		*status |= FE_HAS_LOCK;
-	if (s1 & (1 << 1))
-		*status |= FE_HAS_SYNC;
-	if (s3 & (1 << 6))
-		*status |= FE_HAS_SIGNAL;
-
-	if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
-		      (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
-		*status &= ~FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int mt352_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	struct mt352_state* state = fe->demodulator_priv;
-
-	*ber = (mt352_read_register (state, RS_ERR_CNT_2) << 16) |
-	       (mt352_read_register (state, RS_ERR_CNT_1) << 8) |
-	       (mt352_read_register (state, RS_ERR_CNT_0));
-
-	return 0;
-}
-
-static int mt352_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-{
-	struct mt352_state* state = fe->demodulator_priv;
-
-	/* align the 12 bit AGC gain with the most significant bits */
-	u16 signal = ((mt352_read_register(state, AGC_GAIN_1) & 0x0f) << 12) |
-		(mt352_read_register(state, AGC_GAIN_0) << 4);
-
-	/* inverse of gain is signal strength */
-	*strength = ~signal;
-	return 0;
-}
-
-static int mt352_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct mt352_state* state = fe->demodulator_priv;
-
-	u8 _snr = mt352_read_register (state, SNR);
-	*snr = (_snr << 8) | _snr;
-
-	return 0;
-}
-
-static int mt352_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	struct mt352_state* state = fe->demodulator_priv;
-
-	*ucblocks = (mt352_read_register (state,  RS_UBC_1) << 8) |
-		    (mt352_read_register (state,  RS_UBC_0));
-
-	return 0;
-}
-
-static int mt352_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings)
-{
-	fe_tune_settings->min_delay_ms = 800;
-	fe_tune_settings->step_size = 0;
-	fe_tune_settings->max_drift = 0;
-
-	return 0;
-}
-
-static int mt352_init(struct dvb_frontend* fe)
-{
-	struct mt352_state* state = fe->demodulator_priv;
-
-	static u8 mt352_reset_attach [] = { RESET, 0xC0 };
-
-	dprintk("%s: hello\n",__func__);
-
-	if ((mt352_read_register(state, CLOCK_CTL) & 0x10) == 0 ||
-	    (mt352_read_register(state, CONFIG) & 0x20) == 0) {
-
-		/* Do a "hard" reset */
-		_mt352_write(fe, mt352_reset_attach, sizeof(mt352_reset_attach));
-		return state->config.demod_init(fe);
-	}
-
-	return 0;
-}
-
-static void mt352_release(struct dvb_frontend* fe)
-{
-	struct mt352_state* state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops mt352_ops;
-
-struct dvb_frontend* mt352_attach(const struct mt352_config* config,
-				  struct i2c_adapter* i2c)
-{
-	struct mt352_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct mt352_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* setup the state */
-	state->i2c = i2c;
-	memcpy(&state->config,config,sizeof(struct mt352_config));
-
-	/* check if the demod is there */
-	if (mt352_read_register(state, CHIP_ID) != ID_MT352) goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &mt352_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops mt352_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name			= "Zarlink MT352 DVB-T",
-		.frequency_min		= 174000000,
-		.frequency_max		= 862000000,
-		.frequency_stepsize	= 166667,
-		.frequency_tolerance	= 0,
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
-			FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
-			FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER |
-			FE_CAN_MUTE_TS
-	},
-
-	.release = mt352_release,
-
-	.init = mt352_init,
-	.sleep = mt352_sleep,
-	.write = _mt352_write,
-
-	.set_frontend = mt352_set_parameters,
-	.get_frontend = mt352_get_parameters,
-	.get_tune_settings = mt352_get_tune_settings,
-
-	.read_status = mt352_read_status,
-	.read_ber = mt352_read_ber,
-	.read_signal_strength = mt352_read_signal_strength,
-	.read_snr = mt352_read_snr,
-	.read_ucblocks = mt352_read_ucblocks,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("Zarlink MT352 DVB-T Demodulator driver");
-MODULE_AUTHOR("Holger Waechtler, Daniel Mack, Antonio Mancuso");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(mt352_attach);
diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h
deleted file mode 100644
index ca2562d..0000000
--- a/drivers/media/dvb/frontends/mt352.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- *  Driver for Zarlink DVB-T MT352 demodulator
- *
- *  Written by Holger Waechtler <holger@qanu.de>
- *	 and Daniel Mack <daniel@qanu.de>
- *
- *  AVerMedia AVerTV DVB-T 771 support by
- *       Wolfram Joost <dbox2@frokaschwei.de>
- *
- *  Support for Samsung TDTC9251DH01C(M) tuner
- *  Copyright (C) 2004 Antonio Mancuso <antonio.mancuso@digitaltelevision.it>
- *                     Amauri  Celani  <acelani@essegi.net>
- *
- *  DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by
- *       Christopher Pascoe <c.pascoe@itee.uq.edu.au>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef MT352_H
-#define MT352_H
-
-#include <linux/dvb/frontend.h>
-
-struct mt352_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* frequencies in kHz */
-	int adc_clock;  // default: 20480
-	int if2;        // default: 36166
-
-	/* set if no pll is connected to the secondary i2c bus */
-	int no_tuner;
-
-	/* Initialise the demodulator and PLL. Cannot be NULL */
-	int (*demod_init)(struct dvb_frontend* fe);
-};
-
-#if defined(CONFIG_DVB_MT352) || (defined(CONFIG_DVB_MT352_MODULE) && defined(MODULE))
-extern struct dvb_frontend* mt352_attach(const struct mt352_config* config,
-					 struct i2c_adapter* i2c);
-#else
-static inline struct dvb_frontend* mt352_attach(const struct mt352_config* config,
-					 struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_MT352
-
-static inline int mt352_write(struct dvb_frontend *fe, const u8 buf[], int len) {
-	int r = 0;
-	if (fe->ops.write)
-		r = fe->ops.write(fe, buf, len);
-	return r;
-}
-
-#endif // MT352_H
diff --git a/drivers/media/dvb/frontends/mt352_priv.h b/drivers/media/dvb/frontends/mt352_priv.h
deleted file mode 100644
index 44ad0d4..0000000
--- a/drivers/media/dvb/frontends/mt352_priv.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- *  Driver for Zarlink DVB-T MT352 demodulator
- *
- *  Written by Holger Waechtler <holger@qanu.de>
- *	 and Daniel Mack <daniel@qanu.de>
- *
- *  AVerMedia AVerTV DVB-T 771 support by
- *       Wolfram Joost <dbox2@frokaschwei.de>
- *
- *  Support for Samsung TDTC9251DH01C(M) tuner
- *  Copyright (C) 2004 Antonio Mancuso <antonio.mancuso@digitaltelevision.it>
- *                     Amauri  Celani  <acelani@essegi.net>
- *
- *  DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by
- *       Christopher Pascoe <c.pascoe@itee.uq.edu.au>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef _MT352_PRIV_
-#define _MT352_PRIV_
-
-#define ID_MT352        0x13
-
-#define msb(x) (((x) >> 8) & 0xff)
-#define lsb(x) ((x) & 0xff)
-
-enum mt352_reg_addr {
-	STATUS_0           = 0x00,
-	STATUS_1           = 0x01,
-	STATUS_2           = 0x02,
-	STATUS_3           = 0x03,
-	STATUS_4           = 0x04,
-	INTERRUPT_0        = 0x05,
-	INTERRUPT_1        = 0x06,
-	INTERRUPT_2        = 0x07,
-	INTERRUPT_3        = 0x08,
-	SNR                = 0x09,
-	VIT_ERR_CNT_2      = 0x0A,
-	VIT_ERR_CNT_1      = 0x0B,
-	VIT_ERR_CNT_0      = 0x0C,
-	RS_ERR_CNT_2       = 0x0D,
-	RS_ERR_CNT_1       = 0x0E,
-	RS_ERR_CNT_0       = 0x0F,
-	RS_UBC_1           = 0x10,
-	RS_UBC_0           = 0x11,
-	AGC_GAIN_3         = 0x12,
-	AGC_GAIN_2         = 0x13,
-	AGC_GAIN_1         = 0x14,
-	AGC_GAIN_0         = 0x15,
-	FREQ_OFFSET_2      = 0x17,
-	FREQ_OFFSET_1      = 0x18,
-	FREQ_OFFSET_0      = 0x19,
-	TIMING_OFFSET_1    = 0x1A,
-	TIMING_OFFSET_0    = 0x1B,
-	CHAN_FREQ_1        = 0x1C,
-	CHAN_FREQ_0        = 0x1D,
-	TPS_RECEIVED_1     = 0x1E,
-	TPS_RECEIVED_0     = 0x1F,
-	TPS_CURRENT_1      = 0x20,
-	TPS_CURRENT_0      = 0x21,
-	TPS_CELL_ID_1      = 0x22,
-	TPS_CELL_ID_0      = 0x23,
-	TPS_MISC_DATA_2    = 0x24,
-	TPS_MISC_DATA_1    = 0x25,
-	TPS_MISC_DATA_0    = 0x26,
-	RESET              = 0x50,
-	TPS_GIVEN_1        = 0x51,
-	TPS_GIVEN_0        = 0x52,
-	ACQ_CTL            = 0x53,
-	TRL_NOMINAL_RATE_1 = 0x54,
-	TRL_NOMINAL_RATE_0 = 0x55,
-	INPUT_FREQ_1       = 0x56,
-	INPUT_FREQ_0       = 0x57,
-	TUNER_ADDR         = 0x58,
-	CHAN_START_1       = 0x59,
-	CHAN_START_0       = 0x5A,
-	CONT_1             = 0x5B,
-	CONT_0             = 0x5C,
-	TUNER_GO           = 0x5D,
-	STATUS_EN_0        = 0x5F,
-	STATUS_EN_1        = 0x60,
-	INTERRUPT_EN_0     = 0x61,
-	INTERRUPT_EN_1     = 0x62,
-	INTERRUPT_EN_2     = 0x63,
-	INTERRUPT_EN_3     = 0x64,
-	AGC_TARGET         = 0x67,
-	AGC_CTL            = 0x68,
-	CAPT_RANGE         = 0x75,
-	SNR_SELECT_1       = 0x79,
-	SNR_SELECT_0       = 0x7A,
-	RS_ERR_PER_1       = 0x7C,
-	RS_ERR_PER_0       = 0x7D,
-	CHIP_ID            = 0x7F,
-	CHAN_STOP_1        = 0x80,
-	CHAN_STOP_0        = 0x81,
-	CHAN_STEP_1        = 0x82,
-	CHAN_STEP_0        = 0x83,
-	FEC_LOCK_TIME      = 0x85,
-	OFDM_LOCK_TIME     = 0x86,
-	ACQ_DELAY          = 0x87,
-	SCAN_CTL           = 0x88,
-	CLOCK_CTL          = 0x89,
-	CONFIG             = 0x8A,
-	MCLK_RATIO         = 0x8B,
-	GPP_CTL            = 0x8C,
-	ADC_CTL_1          = 0x8E,
-	ADC_CTL_0          = 0x8F
-};
-
-/* here we assume 1/6MHz == 166.66kHz stepsize */
-#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
-
-#endif                          /* _MT352_PRIV_ */
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
deleted file mode 100644
index 49ca78d..0000000
--- a/drivers/media/dvb/frontends/nxt200x.c
+++ /dev/null
@@ -1,1240 +0,0 @@
-/*
- *    Support for NXT2002 and NXT2004 - VSB/QAM
- *
- *    Copyright (C) 2005 Kirk Lapray <kirk.lapray@gmail.com>
- *    Copyright (C) 2006 Michael Krufky <mkrufky@m1k.net>
- *    based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net>
- *    and nxt2004 by Jean-Francois Thibert <jeanfrancois@sagetv.com>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
-*/
-
-/*
- *                      NOTES ABOUT THIS DRIVER
- *
- * This Linux driver supports:
- *   B2C2/BBTI Technisat Air2PC - ATSC (NXT2002)
- *   AverTVHD MCE A180 (NXT2004)
- *   ATI HDTV Wonder (NXT2004)
- *
- * This driver needs external firmware. Please use the command
- * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" or
- * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
- * download/extract the appropriate firmware, and then copy it to
- * /usr/lib/hotplug/firmware/ or /lib/firmware/
- * (depending on configuration of firmware hotplug).
- */
-#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
-#define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw"
-#define CRC_CCIT_MASK 0x1021
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-
-#include "dvb_frontend.h"
-#include "nxt200x.h"
-
-struct nxt200x_state {
-
-	struct i2c_adapter* i2c;
-	const struct nxt200x_config* config;
-	struct dvb_frontend frontend;
-
-	/* demodulator private data */
-	nxt_chip_type demod_chip;
-	u8 initialised:1;
-};
-
-static int debug;
-#define dprintk(args...) \
-	do { \
-		if (debug) printk(KERN_DEBUG "nxt200x: " args); \
-	} while (0)
-
-static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len)
-{
-	int err;
-	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len };
-
-	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
-		printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n",
-			__func__, addr, err);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int i2c_readbytes(struct nxt200x_state *state, u8 addr, u8 *buf, u8 len)
-{
-	int err;
-	struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len };
-
-	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
-		printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n",
-			__func__, addr, err);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg,
-			       const u8 *buf, u8 len)
-{
-	u8 buf2 [len+1];
-	int err;
-	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 };
-
-	buf2[0] = reg;
-	memcpy(&buf2[1], buf, len);
-
-	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
-		printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n",
-			__func__, state->config->demod_address, err);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int nxt200x_readbytes(struct nxt200x_state *state, u8 reg, u8 *buf, u8 len)
-{
-	u8 reg2 [] = { reg };
-
-	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = reg2, .len = 1 },
-			{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } };
-
-	int err;
-
-	if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {
-		printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n",
-			__func__, state->config->demod_address, err);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static u16 nxt200x_crc(u16 crc, u8 c)
-{
-	u8 i;
-	u16 input = (u16) c & 0xFF;
-
-	input<<=8;
-	for(i=0; i<8; i++) {
-		if((crc^input) & 0x8000)
-			crc=(crc<<1)^CRC_CCIT_MASK;
-		else
-			crc<<=1;
-		input<<=1;
-	}
-	return crc;
-}
-
-static int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len)
-{
-	u8 attr, len2, buf;
-	dprintk("%s\n", __func__);
-
-	/* set mutli register register */
-	nxt200x_writebytes(state, 0x35, &reg, 1);
-
-	/* send the actual data */
-	nxt200x_writebytes(state, 0x36, data, len);
-
-	switch (state->demod_chip) {
-		case NXT2002:
-			len2 = len;
-			buf = 0x02;
-			break;
-		case NXT2004:
-			/* probably not right, but gives correct values */
-			attr = 0x02;
-			if (reg & 0x80) {
-				attr = attr << 1;
-				if (reg & 0x04)
-					attr = attr >> 1;
-			}
-			/* set write bit */
-			len2 = ((attr << 4) | 0x10) | len;
-			buf = 0x80;
-			break;
-		default:
-			return -EINVAL;
-			break;
-	}
-
-	/* set multi register length */
-	nxt200x_writebytes(state, 0x34, &len2, 1);
-
-	/* toggle the multireg write bit */
-	nxt200x_writebytes(state, 0x21, &buf, 1);
-
-	nxt200x_readbytes(state, 0x21, &buf, 1);
-
-	switch (state->demod_chip) {
-		case NXT2002:
-			if ((buf & 0x02) == 0)
-				return 0;
-			break;
-		case NXT2004:
-			if (buf == 0)
-				return 0;
-			break;
-		default:
-			return -EINVAL;
-			break;
-	}
-
-	printk(KERN_WARNING "nxt200x: Error writing multireg register 0x%02X\n",reg);
-
-	return 0;
-}
-
-static int nxt200x_readreg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len)
-{
-	int i;
-	u8 buf, len2, attr;
-	dprintk("%s\n", __func__);
-
-	/* set mutli register register */
-	nxt200x_writebytes(state, 0x35, &reg, 1);
-
-	switch (state->demod_chip) {
-		case NXT2002:
-			/* set multi register length */
-			len2 = len & 0x80;
-			nxt200x_writebytes(state, 0x34, &len2, 1);
-
-			/* read the actual data */
-			nxt200x_readbytes(state, reg, data, len);
-			return 0;
-			break;
-		case NXT2004:
-			/* probably not right, but gives correct values */
-			attr = 0x02;
-			if (reg & 0x80) {
-				attr = attr << 1;
-				if (reg & 0x04)
-					attr = attr >> 1;
-			}
-
-			/* set multi register length */
-			len2 = (attr << 4) | len;
-			nxt200x_writebytes(state, 0x34, &len2, 1);
-
-			/* toggle the multireg bit*/
-			buf = 0x80;
-			nxt200x_writebytes(state, 0x21, &buf, 1);
-
-			/* read the actual data */
-			for(i = 0; i < len; i++) {
-				nxt200x_readbytes(state, 0x36 + i, &data[i], 1);
-			}
-			return 0;
-			break;
-		default:
-			return -EINVAL;
-			break;
-	}
-}
-
-static void nxt200x_microcontroller_stop (struct nxt200x_state* state)
-{
-	u8 buf, stopval, counter = 0;
-	dprintk("%s\n", __func__);
-
-	/* set correct stop value */
-	switch (state->demod_chip) {
-		case NXT2002:
-			stopval = 0x40;
-			break;
-		case NXT2004:
-			stopval = 0x10;
-			break;
-		default:
-			stopval = 0;
-			break;
-	}
-
-	buf = 0x80;
-	nxt200x_writebytes(state, 0x22, &buf, 1);
-
-	while (counter < 20) {
-		nxt200x_readbytes(state, 0x31, &buf, 1);
-		if (buf & stopval)
-			return;
-		msleep(10);
-		counter++;
-	}
-
-	printk(KERN_WARNING "nxt200x: Timeout waiting for nxt200x to stop. This is ok after firmware upload.\n");
-	return;
-}
-
-static void nxt200x_microcontroller_start (struct nxt200x_state* state)
-{
-	u8 buf;
-	dprintk("%s\n", __func__);
-
-	buf = 0x00;
-	nxt200x_writebytes(state, 0x22, &buf, 1);
-}
-
-static void nxt2004_microcontroller_init (struct nxt200x_state* state)
-{
-	u8 buf[9];
-	u8 counter = 0;
-	dprintk("%s\n", __func__);
-
-	buf[0] = 0x00;
-	nxt200x_writebytes(state, 0x2b, buf, 1);
-	buf[0] = 0x70;
-	nxt200x_writebytes(state, 0x34, buf, 1);
-	buf[0] = 0x04;
-	nxt200x_writebytes(state, 0x35, buf, 1);
-	buf[0] = 0x01; buf[1] = 0x23; buf[2] = 0x45; buf[3] = 0x67; buf[4] = 0x89;
-	buf[5] = 0xAB; buf[6] = 0xCD; buf[7] = 0xEF; buf[8] = 0xC0;
-	nxt200x_writebytes(state, 0x36, buf, 9);
-	buf[0] = 0x80;
-	nxt200x_writebytes(state, 0x21, buf, 1);
-
-	while (counter < 20) {
-		nxt200x_readbytes(state, 0x21, buf, 1);
-		if (buf[0] == 0)
-			return;
-		msleep(10);
-		counter++;
-	}
-
-	printk(KERN_WARNING "nxt200x: Timeout waiting for nxt2004 to init.\n");
-
-	return;
-}
-
-static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
-{
-	u8 buf, count = 0;
-
-	dprintk("%s\n", __func__);
-
-	dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[1], data[2], data[3], data[4]);
-
-	/* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip.
-	 * direct write is required for Philips TUV1236D and ALPS TDHU2 */
-	switch (state->demod_chip) {
-		case NXT2004:
-			if (i2c_writebytes(state, data[0], data+1, 4))
-				printk(KERN_WARNING "nxt200x: error writing to tuner\n");
-			/* wait until we have a lock */
-			while (count < 20) {
-				i2c_readbytes(state, data[0], &buf, 1);
-				if (buf & 0x40)
-					return 0;
-				msleep(100);
-				count++;
-			}
-			printk("nxt2004: timeout waiting for tuner lock\n");
-			break;
-		case NXT2002:
-			/* set the i2c transfer speed to the tuner */
-			buf = 0x03;
-			nxt200x_writebytes(state, 0x20, &buf, 1);
-
-			/* setup to transfer 4 bytes via i2c */
-			buf = 0x04;
-			nxt200x_writebytes(state, 0x34, &buf, 1);
-
-			/* write actual tuner bytes */
-			nxt200x_writebytes(state, 0x36, data+1, 4);
-
-			/* set tuner i2c address */
-			buf = data[0] << 1;
-			nxt200x_writebytes(state, 0x35, &buf, 1);
-
-			/* write UC Opmode to begin transfer */
-			buf = 0x80;
-			nxt200x_writebytes(state, 0x21, &buf, 1);
-
-			while (count < 20) {
-				nxt200x_readbytes(state, 0x21, &buf, 1);
-				if ((buf & 0x80)== 0x00)
-					return 0;
-				msleep(100);
-				count++;
-			}
-			printk("nxt2002: timeout error writing tuner\n");
-			break;
-		default:
-			return -EINVAL;
-			break;
-	}
-	return 0;
-}
-
-static void nxt200x_agc_reset(struct nxt200x_state* state)
-{
-	u8 buf;
-	dprintk("%s\n", __func__);
-
-	switch (state->demod_chip) {
-		case NXT2002:
-			buf = 0x08;
-			nxt200x_writebytes(state, 0x08, &buf, 1);
-			buf = 0x00;
-			nxt200x_writebytes(state, 0x08, &buf, 1);
-			break;
-		case NXT2004:
-			nxt200x_readreg_multibyte(state, 0x08, &buf, 1);
-			buf = 0x08;
-			nxt200x_writereg_multibyte(state, 0x08, &buf, 1);
-			buf = 0x00;
-			nxt200x_writereg_multibyte(state, 0x08, &buf, 1);
-			break;
-		default:
-			break;
-	}
-	return;
-}
-
-static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
-{
-
-	struct nxt200x_state* state = fe->demodulator_priv;
-	u8 buf[3], written = 0, chunkpos = 0;
-	u16 rambase, position, crc = 0;
-
-	dprintk("%s\n", __func__);
-	dprintk("Firmware is %zu bytes\n", fw->size);
-
-	/* Get the RAM base for this nxt2002 */
-	nxt200x_readbytes(state, 0x10, buf, 1);
-
-	if (buf[0] & 0x10)
-		rambase = 0x1000;
-	else
-		rambase = 0x0000;
-
-	dprintk("rambase on this nxt2002 is %04X\n", rambase);
-
-	/* Hold the micro in reset while loading firmware */
-	buf[0] = 0x80;
-	nxt200x_writebytes(state, 0x2B, buf, 1);
-
-	for (position = 0; position < fw->size; position++) {
-		if (written == 0) {
-			crc = 0;
-			chunkpos = 0x28;
-			buf[0] = ((rambase + position) >> 8);
-			buf[1] = (rambase + position) & 0xFF;
-			buf[2] = 0x81;
-			/* write starting address */
-			nxt200x_writebytes(state, 0x29, buf, 3);
-		}
-		written++;
-		chunkpos++;
-
-		if ((written % 4) == 0)
-			nxt200x_writebytes(state, chunkpos, &fw->data[position-3], 4);
-
-		crc = nxt200x_crc(crc, fw->data[position]);
-
-		if ((written == 255) || (position+1 == fw->size)) {
-			/* write remaining bytes of firmware */
-			nxt200x_writebytes(state, chunkpos+4-(written %4),
-				&fw->data[position-(written %4) + 1],
-				written %4);
-			buf[0] = crc << 8;
-			buf[1] = crc & 0xFF;
-
-			/* write crc */
-			nxt200x_writebytes(state, 0x2C, buf, 2);
-
-			/* do a read to stop things */
-			nxt200x_readbytes(state, 0x2A, buf, 1);
-
-			/* set transfer mode to complete */
-			buf[0] = 0x80;
-			nxt200x_writebytes(state, 0x2B, buf, 1);
-
-			written = 0;
-		}
-	}
-
-	return 0;
-};
-
-static int nxt2004_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
-{
-
-	struct nxt200x_state* state = fe->demodulator_priv;
-	u8 buf[3];
-	u16 rambase, position, crc=0;
-
-	dprintk("%s\n", __func__);
-	dprintk("Firmware is %zu bytes\n", fw->size);
-
-	/* set rambase */
-	rambase = 0x1000;
-
-	/* hold the micro in reset while loading firmware */
-	buf[0] = 0x80;
-	nxt200x_writebytes(state, 0x2B, buf,1);
-
-	/* calculate firmware CRC */
-	for (position = 0; position < fw->size; position++) {
-		crc = nxt200x_crc(crc, fw->data[position]);
-	}
-
-	buf[0] = rambase >> 8;
-	buf[1] = rambase & 0xFF;
-	buf[2] = 0x81;
-	/* write starting address */
-	nxt200x_writebytes(state,0x29,buf,3);
-
-	for (position = 0; position < fw->size;) {
-		nxt200x_writebytes(state, 0x2C, &fw->data[position],
-			fw->size-position > 255 ? 255 : fw->size-position);
-		position += (fw->size-position > 255 ? 255 : fw->size-position);
-	}
-	buf[0] = crc >> 8;
-	buf[1] = crc & 0xFF;
-
-	dprintk("firmware crc is 0x%02X 0x%02X\n", buf[0], buf[1]);
-
-	/* write crc */
-	nxt200x_writebytes(state, 0x2C, buf,2);
-
-	/* do a read to stop things */
-	nxt200x_readbytes(state, 0x2C, buf, 1);
-
-	/* set transfer mode to complete */
-	buf[0] = 0x80;
-	nxt200x_writebytes(state, 0x2B, buf,1);
-
-	return 0;
-};
-
-static int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct nxt200x_state* state = fe->demodulator_priv;
-	u8 buf[5];
-
-	/* stop the micro first */
-	nxt200x_microcontroller_stop(state);
-
-	if (state->demod_chip == NXT2004) {
-		/* make sure demod is set to digital */
-		buf[0] = 0x04;
-		nxt200x_writebytes(state, 0x14, buf, 1);
-		buf[0] = 0x00;
-		nxt200x_writebytes(state, 0x17, buf, 1);
-	}
-
-	/* set additional params */
-	switch (p->modulation) {
-		case QAM_64:
-		case QAM_256:
-			/* Set punctured clock for QAM */
-			/* This is just a guess since I am unable to test it */
-			if (state->config->set_ts_params)
-				state->config->set_ts_params(fe, 1);
-			break;
-		case VSB_8:
-			/* Set non-punctured clock for VSB */
-			if (state->config->set_ts_params)
-				state->config->set_ts_params(fe, 0);
-			break;
-		default:
-			return -EINVAL;
-			break;
-	}
-
-	if (fe->ops.tuner_ops.calc_regs) {
-		/* get tuning information */
-		fe->ops.tuner_ops.calc_regs(fe, buf, 5);
-
-		/* write frequency information */
-		nxt200x_writetuner(state, buf);
-	}
-
-	/* reset the agc now that tuning has been completed */
-	nxt200x_agc_reset(state);
-
-	/* set target power level */
-	switch (p->modulation) {
-		case QAM_64:
-		case QAM_256:
-			buf[0] = 0x74;
-			break;
-		case VSB_8:
-			buf[0] = 0x70;
-			break;
-		default:
-			return -EINVAL;
-			break;
-	}
-	nxt200x_writebytes(state, 0x42, buf, 1);
-
-	/* configure sdm */
-	switch (state->demod_chip) {
-		case NXT2002:
-			buf[0] = 0x87;
-			break;
-		case NXT2004:
-			buf[0] = 0x07;
-			break;
-		default:
-			return -EINVAL;
-			break;
-	}
-	nxt200x_writebytes(state, 0x57, buf, 1);
-
-	/* write sdm1 input */
-	buf[0] = 0x10;
-	buf[1] = 0x00;
-	switch (state->demod_chip) {
-		case NXT2002:
-			nxt200x_writereg_multibyte(state, 0x58, buf, 2);
-			break;
-		case NXT2004:
-			nxt200x_writebytes(state, 0x58, buf, 2);
-			break;
-		default:
-			return -EINVAL;
-			break;
-	}
-
-	/* write sdmx input */
-	switch (p->modulation) {
-		case QAM_64:
-				buf[0] = 0x68;
-				break;
-		case QAM_256:
-				buf[0] = 0x64;
-				break;
-		case VSB_8:
-				buf[0] = 0x60;
-				break;
-		default:
-				return -EINVAL;
-				break;
-	}
-	buf[1] = 0x00;
-	switch (state->demod_chip) {
-		case NXT2002:
-			nxt200x_writereg_multibyte(state, 0x5C, buf, 2);
-			break;
-		case NXT2004:
-			nxt200x_writebytes(state, 0x5C, buf, 2);
-			break;
-		default:
-			return -EINVAL;
-			break;
-	}
-
-	/* write adc power lpf fc */
-	buf[0] = 0x05;
-	nxt200x_writebytes(state, 0x43, buf, 1);
-
-	if (state->demod_chip == NXT2004) {
-		/* write ??? */
-		buf[0] = 0x00;
-		buf[1] = 0x00;
-		nxt200x_writebytes(state, 0x46, buf, 2);
-	}
-
-	/* write accumulator2 input */
-	buf[0] = 0x80;
-	buf[1] = 0x00;
-	switch (state->demod_chip) {
-		case NXT2002:
-			nxt200x_writereg_multibyte(state, 0x4B, buf, 2);
-			break;
-		case NXT2004:
-			nxt200x_writebytes(state, 0x4B, buf, 2);
-			break;
-		default:
-			return -EINVAL;
-			break;
-	}
-
-	/* write kg1 */
-	buf[0] = 0x00;
-	nxt200x_writebytes(state, 0x4D, buf, 1);
-
-	/* write sdm12 lpf fc */
-	buf[0] = 0x44;
-	nxt200x_writebytes(state, 0x55, buf, 1);
-
-	/* write agc control reg */
-	buf[0] = 0x04;
-	nxt200x_writebytes(state, 0x41, buf, 1);
-
-	if (state->demod_chip == NXT2004) {
-		nxt200x_readreg_multibyte(state, 0x80, buf, 1);
-		buf[0] = 0x24;
-		nxt200x_writereg_multibyte(state, 0x80, buf, 1);
-
-		/* soft reset? */
-		nxt200x_readreg_multibyte(state, 0x08, buf, 1);
-		buf[0] = 0x10;
-		nxt200x_writereg_multibyte(state, 0x08, buf, 1);
-		nxt200x_readreg_multibyte(state, 0x08, buf, 1);
-		buf[0] = 0x00;
-		nxt200x_writereg_multibyte(state, 0x08, buf, 1);
-
-		nxt200x_readreg_multibyte(state, 0x80, buf, 1);
-		buf[0] = 0x04;
-		nxt200x_writereg_multibyte(state, 0x80, buf, 1);
-		buf[0] = 0x00;
-		nxt200x_writereg_multibyte(state, 0x81, buf, 1);
-		buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00;
-		nxt200x_writereg_multibyte(state, 0x82, buf, 3);
-		nxt200x_readreg_multibyte(state, 0x88, buf, 1);
-		buf[0] = 0x11;
-		nxt200x_writereg_multibyte(state, 0x88, buf, 1);
-		nxt200x_readreg_multibyte(state, 0x80, buf, 1);
-		buf[0] = 0x44;
-		nxt200x_writereg_multibyte(state, 0x80, buf, 1);
-	}
-
-	/* write agc ucgp0 */
-	switch (p->modulation) {
-		case QAM_64:
-				buf[0] = 0x02;
-				break;
-		case QAM_256:
-				buf[0] = 0x03;
-				break;
-		case VSB_8:
-				buf[0] = 0x00;
-				break;
-		default:
-				return -EINVAL;
-				break;
-	}
-	nxt200x_writebytes(state, 0x30, buf, 1);
-
-	/* write agc control reg */
-	buf[0] = 0x00;
-	nxt200x_writebytes(state, 0x41, buf, 1);
-
-	/* write accumulator2 input */
-	buf[0] = 0x80;
-	buf[1] = 0x00;
-	switch (state->demod_chip) {
-		case NXT2002:
-			nxt200x_writereg_multibyte(state, 0x49, buf, 2);
-			nxt200x_writereg_multibyte(state, 0x4B, buf, 2);
-			break;
-		case NXT2004:
-			nxt200x_writebytes(state, 0x49, buf, 2);
-			nxt200x_writebytes(state, 0x4B, buf, 2);
-			break;
-		default:
-			return -EINVAL;
-			break;
-	}
-
-	/* write agc control reg */
-	buf[0] = 0x04;
-	nxt200x_writebytes(state, 0x41, buf, 1);
-
-	nxt200x_microcontroller_start(state);
-
-	if (state->demod_chip == NXT2004) {
-		nxt2004_microcontroller_init(state);
-
-		/* ???? */
-		buf[0] = 0xF0;
-		buf[1] = 0x00;
-		nxt200x_writebytes(state, 0x5C, buf, 2);
-	}
-
-	/* adjacent channel detection should be done here, but I don't
-	have any stations with this need so I cannot test it */
-
-	return 0;
-}
-
-static int nxt200x_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct nxt200x_state* state = fe->demodulator_priv;
-	u8 lock;
-	nxt200x_readbytes(state, 0x31, &lock, 1);
-
-	*status = 0;
-	if (lock & 0x20) {
-		*status |= FE_HAS_SIGNAL;
-		*status |= FE_HAS_CARRIER;
-		*status |= FE_HAS_VITERBI;
-		*status |= FE_HAS_SYNC;
-		*status |= FE_HAS_LOCK;
-	}
-	return 0;
-}
-
-static int nxt200x_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	struct nxt200x_state* state = fe->demodulator_priv;
-	u8 b[3];
-
-	nxt200x_readreg_multibyte(state, 0xE6, b, 3);
-
-	*ber = ((b[0] << 8) + b[1]) * 8;
-
-	return 0;
-}
-
-static int nxt200x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-{
-	struct nxt200x_state* state = fe->demodulator_priv;
-	u8 b[2];
-	u16 temp = 0;
-
-	/* setup to read cluster variance */
-	b[0] = 0x00;
-	nxt200x_writebytes(state, 0xA1, b, 1);
-
-	/* get multreg val */
-	nxt200x_readreg_multibyte(state, 0xA6, b, 2);
-
-	temp = (b[0] << 8) | b[1];
-	*strength = ((0x7FFF - temp) & 0x0FFF) * 16;
-
-	return 0;
-}
-
-static int nxt200x_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-
-	struct nxt200x_state* state = fe->demodulator_priv;
-	u8 b[2];
-	u16 temp = 0, temp2;
-	u32 snrdb = 0;
-
-	/* setup to read cluster variance */
-	b[0] = 0x00;
-	nxt200x_writebytes(state, 0xA1, b, 1);
-
-	/* get multreg val from 0xA6 */
-	nxt200x_readreg_multibyte(state, 0xA6, b, 2);
-
-	temp = (b[0] << 8) | b[1];
-	temp2 = 0x7FFF - temp;
-
-	/* snr will be in db */
-	if (temp2 > 0x7F00)
-		snrdb = 1000*24 + ( 1000*(30-24) * ( temp2 - 0x7F00 ) / ( 0x7FFF - 0x7F00 ) );
-	else if (temp2 > 0x7EC0)
-		snrdb = 1000*18 + ( 1000*(24-18) * ( temp2 - 0x7EC0 ) / ( 0x7F00 - 0x7EC0 ) );
-	else if (temp2 > 0x7C00)
-		snrdb = 1000*12 + ( 1000*(18-12) * ( temp2 - 0x7C00 ) / ( 0x7EC0 - 0x7C00 ) );
-	else
-		snrdb = 1000*0 + ( 1000*(12-0) * ( temp2 - 0 ) / ( 0x7C00 - 0 ) );
-
-	/* the value reported back from the frontend will be FFFF=32db 0000=0db */
-	*snr = snrdb * (0xFFFF/32000);
-
-	return 0;
-}
-
-static int nxt200x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	struct nxt200x_state* state = fe->demodulator_priv;
-	u8 b[3];
-
-	nxt200x_readreg_multibyte(state, 0xE6, b, 3);
-	*ucblocks = b[2];
-
-	return 0;
-}
-
-static int nxt200x_sleep(struct dvb_frontend* fe)
-{
-	return 0;
-}
-
-static int nxt2002_init(struct dvb_frontend* fe)
-{
-	struct nxt200x_state* state = fe->demodulator_priv;
-	const struct firmware *fw;
-	int ret;
-	u8 buf[2];
-
-	/* request the firmware, this will block until someone uploads it */
-	printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE);
-	ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE,
-			       state->i2c->dev.parent);
-	printk("nxt2002: Waiting for firmware upload(2)...\n");
-	if (ret) {
-		printk("nxt2002: No firmware uploaded (timeout or file not found?)\n");
-		return ret;
-	}
-
-	ret = nxt2002_load_firmware(fe, fw);
-	release_firmware(fw);
-	if (ret) {
-		printk("nxt2002: Writing firmware to device failed\n");
-		return ret;
-	}
-	printk("nxt2002: Firmware upload complete\n");
-
-	/* Put the micro into reset */
-	nxt200x_microcontroller_stop(state);
-
-	/* ensure transfer is complete */
-	buf[0]=0x00;
-	nxt200x_writebytes(state, 0x2B, buf, 1);
-
-	/* Put the micro into reset for real this time */
-	nxt200x_microcontroller_stop(state);
-
-	/* soft reset everything (agc,frontend,eq,fec)*/
-	buf[0] = 0x0F;
-	nxt200x_writebytes(state, 0x08, buf, 1);
-	buf[0] = 0x00;
-	nxt200x_writebytes(state, 0x08, buf, 1);
-
-	/* write agc sdm configure */
-	buf[0] = 0xF1;
-	nxt200x_writebytes(state, 0x57, buf, 1);
-
-	/* write mod output format */
-	buf[0] = 0x20;
-	nxt200x_writebytes(state, 0x09, buf, 1);
-
-	/* write fec mpeg mode */
-	buf[0] = 0x7E;
-	buf[1] = 0x00;
-	nxt200x_writebytes(state, 0xE9, buf, 2);
-
-	/* write mux selection */
-	buf[0] = 0x00;
-	nxt200x_writebytes(state, 0xCC, buf, 1);
-
-	return 0;
-}
-
-static int nxt2004_init(struct dvb_frontend* fe)
-{
-	struct nxt200x_state* state = fe->demodulator_priv;
-	const struct firmware *fw;
-	int ret;
-	u8 buf[3];
-
-	/* ??? */
-	buf[0]=0x00;
-	nxt200x_writebytes(state, 0x1E, buf, 1);
-
-	/* request the firmware, this will block until someone uploads it */
-	printk("nxt2004: Waiting for firmware upload (%s)...\n", NXT2004_DEFAULT_FIRMWARE);
-	ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE,
-			       state->i2c->dev.parent);
-	printk("nxt2004: Waiting for firmware upload(2)...\n");
-	if (ret) {
-		printk("nxt2004: No firmware uploaded (timeout or file not found?)\n");
-		return ret;
-	}
-
-	ret = nxt2004_load_firmware(fe, fw);
-	release_firmware(fw);
-	if (ret) {
-		printk("nxt2004: Writing firmware to device failed\n");
-		return ret;
-	}
-	printk("nxt2004: Firmware upload complete\n");
-
-	/* ensure transfer is complete */
-	buf[0] = 0x01;
-	nxt200x_writebytes(state, 0x19, buf, 1);
-
-	nxt2004_microcontroller_init(state);
-	nxt200x_microcontroller_stop(state);
-	nxt200x_microcontroller_stop(state);
-	nxt2004_microcontroller_init(state);
-	nxt200x_microcontroller_stop(state);
-
-	/* soft reset everything (agc,frontend,eq,fec)*/
-	buf[0] = 0xFF;
-	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
-	buf[0] = 0x00;
-	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
-
-	/* write agc sdm configure */
-	buf[0] = 0xD7;
-	nxt200x_writebytes(state, 0x57, buf, 1);
-
-	/* ???*/
-	buf[0] = 0x07;
-	buf[1] = 0xfe;
-	nxt200x_writebytes(state, 0x35, buf, 2);
-	buf[0] = 0x12;
-	nxt200x_writebytes(state, 0x34, buf, 1);
-	buf[0] = 0x80;
-	nxt200x_writebytes(state, 0x21, buf, 1);
-
-	/* ???*/
-	buf[0] = 0x21;
-	nxt200x_writebytes(state, 0x0A, buf, 1);
-
-	/* ???*/
-	buf[0] = 0x01;
-	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
-
-	/* write fec mpeg mode */
-	buf[0] = 0x7E;
-	buf[1] = 0x00;
-	nxt200x_writebytes(state, 0xE9, buf, 2);
-
-	/* write mux selection */
-	buf[0] = 0x00;
-	nxt200x_writebytes(state, 0xCC, buf, 1);
-
-	/* ???*/
-	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
-	buf[0] = 0x00;
-	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
-
-	/* soft reset? */
-	nxt200x_readreg_multibyte(state, 0x08, buf, 1);
-	buf[0] = 0x10;
-	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
-	nxt200x_readreg_multibyte(state, 0x08, buf, 1);
-	buf[0] = 0x00;
-	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
-
-	/* ???*/
-	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
-	buf[0] = 0x01;
-	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
-	buf[0] = 0x70;
-	nxt200x_writereg_multibyte(state, 0x81, buf, 1);
-	buf[0] = 0x31; buf[1] = 0x5E; buf[2] = 0x66;
-	nxt200x_writereg_multibyte(state, 0x82, buf, 3);
-
-	nxt200x_readreg_multibyte(state, 0x88, buf, 1);
-	buf[0] = 0x11;
-	nxt200x_writereg_multibyte(state, 0x88, buf, 1);
-	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
-	buf[0] = 0x40;
-	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
-
-	nxt200x_readbytes(state, 0x10, buf, 1);
-	buf[0] = 0x10;
-	nxt200x_writebytes(state, 0x10, buf, 1);
-	nxt200x_readbytes(state, 0x0A, buf, 1);
-	buf[0] = 0x21;
-	nxt200x_writebytes(state, 0x0A, buf, 1);
-
-	nxt2004_microcontroller_init(state);
-
-	buf[0] = 0x21;
-	nxt200x_writebytes(state, 0x0A, buf, 1);
-	buf[0] = 0x7E;
-	nxt200x_writebytes(state, 0xE9, buf, 1);
-	buf[0] = 0x00;
-	nxt200x_writebytes(state, 0xEA, buf, 1);
-
-	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
-	buf[0] = 0x00;
-	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
-	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
-	buf[0] = 0x00;
-	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
-
-	/* soft reset? */
-	nxt200x_readreg_multibyte(state, 0x08, buf, 1);
-	buf[0] = 0x10;
-	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
-	nxt200x_readreg_multibyte(state, 0x08, buf, 1);
-	buf[0] = 0x00;
-	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
-
-	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
-	buf[0] = 0x04;
-	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
-	buf[0] = 0x00;
-	nxt200x_writereg_multibyte(state, 0x81, buf, 1);
-	buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00;
-	nxt200x_writereg_multibyte(state, 0x82, buf, 3);
-
-	nxt200x_readreg_multibyte(state, 0x88, buf, 1);
-	buf[0] = 0x11;
-	nxt200x_writereg_multibyte(state, 0x88, buf, 1);
-
-	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
-	buf[0] = 0x44;
-	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
-
-	/* initialize tuner */
-	nxt200x_readbytes(state, 0x10, buf, 1);
-	buf[0] = 0x12;
-	nxt200x_writebytes(state, 0x10, buf, 1);
-	buf[0] = 0x04;
-	nxt200x_writebytes(state, 0x13, buf, 1);
-	buf[0] = 0x00;
-	nxt200x_writebytes(state, 0x16, buf, 1);
-	buf[0] = 0x04;
-	nxt200x_writebytes(state, 0x14, buf, 1);
-	buf[0] = 0x00;
-	nxt200x_writebytes(state, 0x14, buf, 1);
-	nxt200x_writebytes(state, 0x17, buf, 1);
-	nxt200x_writebytes(state, 0x14, buf, 1);
-	nxt200x_writebytes(state, 0x17, buf, 1);
-
-	return 0;
-}
-
-static int nxt200x_init(struct dvb_frontend* fe)
-{
-	struct nxt200x_state* state = fe->demodulator_priv;
-	int ret = 0;
-
-	if (!state->initialised) {
-		switch (state->demod_chip) {
-			case NXT2002:
-				ret = nxt2002_init(fe);
-				break;
-			case NXT2004:
-				ret = nxt2004_init(fe);
-				break;
-			default:
-				return -EINVAL;
-				break;
-		}
-		state->initialised = 1;
-	}
-	return ret;
-}
-
-static int nxt200x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
-{
-	fesettings->min_delay_ms = 500;
-	fesettings->step_size = 0;
-	fesettings->max_drift = 0;
-	return 0;
-}
-
-static void nxt200x_release(struct dvb_frontend* fe)
-{
-	struct nxt200x_state* state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops nxt200x_ops;
-
-struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
-				   struct i2c_adapter* i2c)
-{
-	struct nxt200x_state* state = NULL;
-	u8 buf [] = {0,0,0,0,0};
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct nxt200x_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->initialised = 0;
-
-	/* read card id */
-	nxt200x_readbytes(state, 0x00, buf, 5);
-	dprintk("NXT info: %02X %02X %02X %02X %02X\n",
-		buf[0], buf[1], buf[2],	buf[3], buf[4]);
-
-	/* set demod chip */
-	switch (buf[0]) {
-		case 0x04:
-			state->demod_chip = NXT2002;
-			printk("nxt200x: NXT2002 Detected\n");
-			break;
-		case 0x05:
-			state->demod_chip = NXT2004;
-			printk("nxt200x: NXT2004 Detected\n");
-			break;
-		default:
-			goto error;
-	}
-
-	/* make sure demod chip is supported */
-	switch (state->demod_chip) {
-		case NXT2002:
-			if (buf[0] != 0x04) goto error;		/* device id */
-			if (buf[1] != 0x02) goto error;		/* fab id */
-			if (buf[2] != 0x11) goto error;		/* month */
-			if (buf[3] != 0x20) goto error;		/* year msb */
-			if (buf[4] != 0x00) goto error;		/* year lsb */
-			break;
-		case NXT2004:
-			if (buf[0] != 0x05) goto error;		/* device id */
-			break;
-		default:
-			goto error;
-	}
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	printk("Unknown/Unsupported NXT chip: %02X %02X %02X %02X %02X\n",
-		buf[0], buf[1], buf[2], buf[3], buf[4]);
-	return NULL;
-}
-
-static struct dvb_frontend_ops nxt200x_ops = {
-	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
-	.info = {
-		.name = "Nextwave NXT200X VSB/QAM frontend",
-		.frequency_min =  54000000,
-		.frequency_max = 860000000,
-		.frequency_stepsize = 166666,	/* stepsize is just a guess */
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_8VSB | FE_CAN_QAM_64 | FE_CAN_QAM_256
-	},
-
-	.release = nxt200x_release,
-
-	.init = nxt200x_init,
-	.sleep = nxt200x_sleep,
-
-	.set_frontend = nxt200x_setup_frontend_parameters,
-	.get_tune_settings = nxt200x_get_tune_settings,
-
-	.read_status = nxt200x_read_status,
-	.read_ber = nxt200x_read_ber,
-	.read_signal_strength = nxt200x_read_signal_strength,
-	.read_snr = nxt200x_read_snr,
-	.read_ucblocks = nxt200x_read_ucblocks,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("NXT200X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
-MODULE_AUTHOR("Kirk Lapray, Michael Krufky, Jean-Francois Thibert, and Taylor Jacob");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(nxt200x_attach);
-
diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h
deleted file mode 100644
index f3c8458..0000000
--- a/drivers/media/dvb/frontends/nxt200x.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- *    Support for NXT2002 and NXT2004 - VSB/QAM
- *
- *    Copyright (C) 2005 Kirk Lapray (kirk.lapray@gmail.com)
- *    based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net>
- *    and nxt2004 by Jean-Francois Thibert (jeanfrancois@sagetv.com)
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
-*/
-
-#ifndef NXT200X_H
-#define NXT200X_H
-
-#include <linux/dvb/frontend.h>
-#include <linux/firmware.h>
-
-typedef enum nxt_chip_t {
-		NXTUNDEFINED,
-		NXT2002,
-		NXT2004
-}nxt_chip_type;
-
-struct nxt200x_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* need to set device param for start_dma */
-	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
-};
-
-#if defined(CONFIG_DVB_NXT200X) || (defined(CONFIG_DVB_NXT200X_MODULE) && defined(MODULE))
-extern struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
-					   struct i2c_adapter* i2c);
-#else
-static inline struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
-					   struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_NXT200X
-
-#endif /* NXT200X_H */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c
deleted file mode 100644
index 90ae6c7..0000000
--- a/drivers/media/dvb/frontends/nxt6000.c
+++ /dev/null
@@ -1,616 +0,0 @@
-/*
-	NxtWave Communications - NXT6000 demodulator driver
-
-    Copyright (C) 2002-2003 Florian Schirmer <jolt@tuxbox.org>
-    Copyright (C) 2003 Paul Andreassen <paul@andreassen.com.au>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "nxt6000_priv.h"
-#include "nxt6000.h"
-
-
-
-struct nxt6000_state {
-	struct i2c_adapter* i2c;
-	/* configuration settings */
-	const struct nxt6000_config* config;
-	struct dvb_frontend frontend;
-};
-
-static int debug;
-#define dprintk if (debug) printk
-
-static int nxt6000_writereg(struct nxt6000_state* state, u8 reg, u8 data)
-{
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 2 };
-	int ret;
-
-	if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1)
-		dprintk("nxt6000: nxt6000_write error (reg: 0x%02X, data: 0x%02X, ret: %d)\n", reg, data, ret);
-
-	return (ret != 1) ? -EIO : 0;
-}
-
-static u8 nxt6000_readreg(struct nxt6000_state* state, u8 reg)
-{
-	int ret;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
-	struct i2c_msg msgs[] = {
-		{.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1},
-		{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
-	};
-
-	ret = i2c_transfer(state->i2c, msgs, 2);
-
-	if (ret != 2)
-		dprintk("nxt6000: nxt6000_read error (reg: 0x%02X, ret: %d)\n", reg, ret);
-
-	return b1[0];
-}
-
-static void nxt6000_reset(struct nxt6000_state* state)
-{
-	u8 val;
-
-	val = nxt6000_readreg(state, OFDM_COR_CTL);
-
-	nxt6000_writereg(state, OFDM_COR_CTL, val & ~COREACT);
-	nxt6000_writereg(state, OFDM_COR_CTL, val | COREACT);
-}
-
-static int nxt6000_set_bandwidth(struct nxt6000_state *state, u32 bandwidth)
-{
-	u16 nominal_rate;
-	int result;
-
-	switch (bandwidth) {
-	case 6000000:
-		nominal_rate = 0x55B7;
-		break;
-
-	case 7000000:
-		nominal_rate = 0x6400;
-		break;
-
-	case 8000000:
-		nominal_rate = 0x7249;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	if ((result = nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_1, nominal_rate & 0xFF)) < 0)
-		return result;
-
-	return nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, (nominal_rate >> 8) & 0xFF);
-}
-
-static int nxt6000_set_guard_interval(struct nxt6000_state* state, fe_guard_interval_t guard_interval)
-{
-	switch (guard_interval) {
-
-	case GUARD_INTERVAL_1_32:
-		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x00 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
-
-	case GUARD_INTERVAL_1_16:
-		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x01 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
-
-	case GUARD_INTERVAL_AUTO:
-	case GUARD_INTERVAL_1_8:
-		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x02 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
-
-	case GUARD_INTERVAL_1_4:
-		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x03 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
-
-	default:
-		return -EINVAL;
-	}
-}
-
-static int nxt6000_set_inversion(struct nxt6000_state* state, fe_spectral_inversion_t inversion)
-{
-	switch (inversion) {
-
-	case INVERSION_OFF:
-		return nxt6000_writereg(state, OFDM_ITB_CTL, 0x00);
-
-	case INVERSION_ON:
-		return nxt6000_writereg(state, OFDM_ITB_CTL, ITBINV);
-
-	default:
-		return -EINVAL;
-
-	}
-}
-
-static int nxt6000_set_transmission_mode(struct nxt6000_state* state, fe_transmit_mode_t transmission_mode)
-{
-	int result;
-
-	switch (transmission_mode) {
-
-	case TRANSMISSION_MODE_2K:
-		if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x00 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0)
-			return result;
-
-		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x00 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04));
-
-	case TRANSMISSION_MODE_8K:
-	case TRANSMISSION_MODE_AUTO:
-		if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x02 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0)
-			return result;
-
-		return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x01 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04));
-
-	default:
-		return -EINVAL;
-
-	}
-}
-
-static void nxt6000_setup(struct dvb_frontend* fe)
-{
-	struct nxt6000_state* state = fe->demodulator_priv;
-
-	nxt6000_writereg(state, RS_COR_SYNC_PARAM, SYNC_PARAM);
-	nxt6000_writereg(state, BER_CTRL, /*(1 << 2) | */ (0x01 << 1) | 0x01);
-	nxt6000_writereg(state, VIT_BERTIME_2, 0x00);  // BER Timer = 0x000200 * 256 = 131072 bits
-	nxt6000_writereg(state, VIT_BERTIME_1, 0x02);  //
-	nxt6000_writereg(state, VIT_BERTIME_0, 0x00);  //
-	nxt6000_writereg(state, VIT_COR_INTEN, 0x98); // Enable BER interrupts
-	nxt6000_writereg(state, VIT_COR_CTL, 0x82);   // Enable BER measurement
-	nxt6000_writereg(state, VIT_COR_CTL, VIT_COR_RESYNC | 0x02 );
-	nxt6000_writereg(state, OFDM_COR_CTL, (0x01 << 5) | (nxt6000_readreg(state, OFDM_COR_CTL) & 0x0F));
-	nxt6000_writereg(state, OFDM_COR_MODEGUARD, FORCEMODE8K | 0x02);
-	nxt6000_writereg(state, OFDM_AGC_CTL, AGCLAST | INITIAL_AGC_BW);
-	nxt6000_writereg(state, OFDM_ITB_FREQ_1, 0x06);
-	nxt6000_writereg(state, OFDM_ITB_FREQ_2, 0x31);
-	nxt6000_writereg(state, OFDM_CAS_CTL, (0x01 << 7) | (0x02 << 3) | 0x04);
-	nxt6000_writereg(state, CAS_FREQ, 0xBB);	/* CHECKME */
-	nxt6000_writereg(state, OFDM_SYR_CTL, 1 << 2);
-	nxt6000_writereg(state, OFDM_PPM_CTL_1, PPM256);
-	nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_1, 0x49);
-	nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, 0x72);
-	nxt6000_writereg(state, ANALOG_CONTROL_0, 1 << 5);
-	nxt6000_writereg(state, EN_DMD_RACQ, (1 << 7) | (3 << 4) | 2);
-	nxt6000_writereg(state, DIAG_CONFIG, TB_SET);
-
-	if (state->config->clock_inversion)
-		nxt6000_writereg(state, SUB_DIAG_MODE_SEL, CLKINVERSION);
-	else
-		nxt6000_writereg(state, SUB_DIAG_MODE_SEL, 0);
-
-	nxt6000_writereg(state, TS_FORMAT, 0);
-}
-
-static void nxt6000_dump_status(struct nxt6000_state *state)
-{
-	u8 val;
-
-/*
-	printk("RS_COR_STAT: 0x%02X\n", nxt6000_readreg(fe, RS_COR_STAT));
-	printk("VIT_SYNC_STATUS: 0x%02X\n", nxt6000_readreg(fe, VIT_SYNC_STATUS));
-	printk("OFDM_COR_STAT: 0x%02X\n", nxt6000_readreg(fe, OFDM_COR_STAT));
-	printk("OFDM_SYR_STAT: 0x%02X\n", nxt6000_readreg(fe, OFDM_SYR_STAT));
-	printk("OFDM_TPS_RCVD_1: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_1));
-	printk("OFDM_TPS_RCVD_2: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_2));
-	printk("OFDM_TPS_RCVD_3: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_3));
-	printk("OFDM_TPS_RCVD_4: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_4));
-	printk("OFDM_TPS_RESERVED_1: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RESERVED_1));
-	printk("OFDM_TPS_RESERVED_2: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RESERVED_2));
-*/
-	printk("NXT6000 status:");
-
-	val = nxt6000_readreg(state, RS_COR_STAT);
-
-	printk(" DATA DESCR LOCK: %d,", val & 0x01);
-	printk(" DATA SYNC LOCK: %d,", (val >> 1) & 0x01);
-
-	val = nxt6000_readreg(state, VIT_SYNC_STATUS);
-
-	printk(" VITERBI LOCK: %d,", (val >> 7) & 0x01);
-
-	switch ((val >> 4) & 0x07) {
-
-	case 0x00:
-		printk(" VITERBI CODERATE: 1/2,");
-		break;
-
-	case 0x01:
-		printk(" VITERBI CODERATE: 2/3,");
-		break;
-
-	case 0x02:
-		printk(" VITERBI CODERATE: 3/4,");
-		break;
-
-	case 0x03:
-		printk(" VITERBI CODERATE: 5/6,");
-		break;
-
-	case 0x04:
-		printk(" VITERBI CODERATE: 7/8,");
-		break;
-
-	default:
-		printk(" VITERBI CODERATE: Reserved,");
-
-	}
-
-	val = nxt6000_readreg(state, OFDM_COR_STAT);
-
-	printk(" CHCTrack: %d,", (val >> 7) & 0x01);
-	printk(" TPSLock: %d,", (val >> 6) & 0x01);
-	printk(" SYRLock: %d,", (val >> 5) & 0x01);
-	printk(" AGCLock: %d,", (val >> 4) & 0x01);
-
-	switch (val & 0x0F) {
-
-	case 0x00:
-		printk(" CoreState: IDLE,");
-		break;
-
-	case 0x02:
-		printk(" CoreState: WAIT_AGC,");
-		break;
-
-	case 0x03:
-		printk(" CoreState: WAIT_SYR,");
-		break;
-
-	case 0x04:
-		printk(" CoreState: WAIT_PPM,");
-		break;
-
-	case 0x01:
-		printk(" CoreState: WAIT_TRL,");
-		break;
-
-	case 0x05:
-		printk(" CoreState: WAIT_TPS,");
-		break;
-
-	case 0x06:
-		printk(" CoreState: MONITOR_TPS,");
-		break;
-
-	default:
-		printk(" CoreState: Reserved,");
-
-	}
-
-	val = nxt6000_readreg(state, OFDM_SYR_STAT);
-
-	printk(" SYRLock: %d,", (val >> 4) & 0x01);
-	printk(" SYRMode: %s,", (val >> 2) & 0x01 ? "8K" : "2K");
-
-	switch ((val >> 4) & 0x03) {
-
-	case 0x00:
-		printk(" SYRGuard: 1/32,");
-		break;
-
-	case 0x01:
-		printk(" SYRGuard: 1/16,");
-		break;
-
-	case 0x02:
-		printk(" SYRGuard: 1/8,");
-		break;
-
-	case 0x03:
-		printk(" SYRGuard: 1/4,");
-		break;
-	}
-
-	val = nxt6000_readreg(state, OFDM_TPS_RCVD_3);
-
-	switch ((val >> 4) & 0x07) {
-
-	case 0x00:
-		printk(" TPSLP: 1/2,");
-		break;
-
-	case 0x01:
-		printk(" TPSLP: 2/3,");
-		break;
-
-	case 0x02:
-		printk(" TPSLP: 3/4,");
-		break;
-
-	case 0x03:
-		printk(" TPSLP: 5/6,");
-		break;
-
-	case 0x04:
-		printk(" TPSLP: 7/8,");
-		break;
-
-	default:
-		printk(" TPSLP: Reserved,");
-
-	}
-
-	switch (val & 0x07) {
-
-	case 0x00:
-		printk(" TPSHP: 1/2,");
-		break;
-
-	case 0x01:
-		printk(" TPSHP: 2/3,");
-		break;
-
-	case 0x02:
-		printk(" TPSHP: 3/4,");
-		break;
-
-	case 0x03:
-		printk(" TPSHP: 5/6,");
-		break;
-
-	case 0x04:
-		printk(" TPSHP: 7/8,");
-		break;
-
-	default:
-		printk(" TPSHP: Reserved,");
-
-	}
-
-	val = nxt6000_readreg(state, OFDM_TPS_RCVD_4);
-
-	printk(" TPSMode: %s,", val & 0x01 ? "8K" : "2K");
-
-	switch ((val >> 4) & 0x03) {
-
-	case 0x00:
-		printk(" TPSGuard: 1/32,");
-		break;
-
-	case 0x01:
-		printk(" TPSGuard: 1/16,");
-		break;
-
-	case 0x02:
-		printk(" TPSGuard: 1/8,");
-		break;
-
-	case 0x03:
-		printk(" TPSGuard: 1/4,");
-		break;
-
-	}
-
-	/* Strange magic required to gain access to RF_AGC_STATUS */
-	nxt6000_readreg(state, RF_AGC_VAL_1);
-	val = nxt6000_readreg(state, RF_AGC_STATUS);
-	val = nxt6000_readreg(state, RF_AGC_STATUS);
-
-	printk(" RF AGC LOCK: %d,", (val >> 4) & 0x01);
-	printk("\n");
-}
-
-static int nxt6000_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	u8 core_status;
-	struct nxt6000_state* state = fe->demodulator_priv;
-
-	*status = 0;
-
-	core_status = nxt6000_readreg(state, OFDM_COR_STAT);
-
-	if (core_status & AGCLOCKED)
-		*status |= FE_HAS_SIGNAL;
-
-	if (nxt6000_readreg(state, OFDM_SYR_STAT) & GI14_SYR_LOCK)
-		*status |= FE_HAS_CARRIER;
-
-	if (nxt6000_readreg(state, VIT_SYNC_STATUS) & VITINSYNC)
-		*status |= FE_HAS_VITERBI;
-
-	if (nxt6000_readreg(state, RS_COR_STAT) & RSCORESTATUS)
-		*status |= FE_HAS_SYNC;
-
-	if ((core_status & TPSLOCKED) && (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)))
-		*status |= FE_HAS_LOCK;
-
-	if (debug)
-		nxt6000_dump_status(state);
-
-	return 0;
-}
-
-static int nxt6000_init(struct dvb_frontend* fe)
-{
-	struct nxt6000_state* state = fe->demodulator_priv;
-
-	nxt6000_reset(state);
-	nxt6000_setup(fe);
-
-	return 0;
-}
-
-static int nxt6000_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct nxt6000_state* state = fe->demodulator_priv;
-	int result;
-
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	result = nxt6000_set_bandwidth(state, p->bandwidth_hz);
-	if (result < 0)
-		return result;
-
-	result = nxt6000_set_guard_interval(state, p->guard_interval);
-	if (result < 0)
-		return result;
-
-	result = nxt6000_set_transmission_mode(state, p->transmission_mode);
-	if (result < 0)
-		return result;
-
-	result = nxt6000_set_inversion(state, p->inversion);
-	if (result < 0)
-		return result;
-
-	msleep(500);
-	return 0;
-}
-
-static void nxt6000_release(struct dvb_frontend* fe)
-{
-	struct nxt6000_state* state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static int nxt6000_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct nxt6000_state* state = fe->demodulator_priv;
-
-	*snr = nxt6000_readreg( state, OFDM_CHC_SNR) / 8;
-
-	return 0;
-}
-
-static int nxt6000_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	struct nxt6000_state* state = fe->demodulator_priv;
-
-	nxt6000_writereg( state, VIT_COR_INTSTAT, 0x18 );
-
-	*ber = (nxt6000_readreg( state, VIT_BER_1 ) << 8 ) |
-		nxt6000_readreg( state, VIT_BER_0 );
-
-	nxt6000_writereg( state, VIT_COR_INTSTAT, 0x18); // Clear BER Done interrupts
-
-	return 0;
-}
-
-static int nxt6000_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
-{
-	struct nxt6000_state* state = fe->demodulator_priv;
-
-	*signal_strength = (short) (511 -
-		(nxt6000_readreg(state, AGC_GAIN_1) +
-		((nxt6000_readreg(state, AGC_GAIN_2) & 0x03) << 8)));
-
-	return 0;
-}
-
-static int nxt6000_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
-{
-	tune->min_delay_ms = 500;
-	return 0;
-}
-
-static int nxt6000_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
-{
-	struct nxt6000_state* state = fe->demodulator_priv;
-
-	if (enable) {
-		return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01);
-	} else {
-		return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00);
-	}
-}
-
-static struct dvb_frontend_ops nxt6000_ops;
-
-struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
-				    struct i2c_adapter* i2c)
-{
-	struct nxt6000_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct nxt6000_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-
-	/* check if the demod is there */
-	if (nxt6000_readreg(state, OFDM_MSC_REV) != NXT6000ASICDEVICE) goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops nxt6000_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name = "NxtWave NXT6000 DVB-T",
-		.frequency_min = 0,
-		.frequency_max = 863250000,
-		.frequency_stepsize = 62500,
-		/*.frequency_tolerance = *//* FIXME: 12% of SR */
-		.symbol_rate_min = 0,	/* FIXME */
-		.symbol_rate_max = 9360000,	/* FIXME */
-		.symbol_rate_tolerance = 4000,
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
-			FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
-			FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_HIERARCHY_AUTO,
-	},
-
-	.release = nxt6000_release,
-
-	.init = nxt6000_init,
-	.i2c_gate_ctrl = nxt6000_i2c_gate_ctrl,
-
-	.get_tune_settings = nxt6000_fe_get_tune_settings,
-
-	.set_frontend = nxt6000_set_frontend,
-
-	.read_status = nxt6000_read_status,
-	.read_ber = nxt6000_read_ber,
-	.read_signal_strength = nxt6000_read_signal_strength,
-	.read_snr = nxt6000_read_snr,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("NxtWave NXT6000 DVB-T demodulator driver");
-MODULE_AUTHOR("Florian Schirmer");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(nxt6000_attach);
diff --git a/drivers/media/dvb/frontends/nxt6000.h b/drivers/media/dvb/frontends/nxt6000.h
deleted file mode 100644
index 878eb38..0000000
--- a/drivers/media/dvb/frontends/nxt6000.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-	NxtWave Communications - NXT6000 demodulator driver
-
-    Copyright (C) 2002-2003 Florian Schirmer <jolt@tuxbox.org>
-    Copyright (C) 2003 Paul Andreassen <paul@andreassen.com.au>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef NXT6000_H
-#define NXT6000_H
-
-#include <linux/dvb/frontend.h>
-
-struct nxt6000_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* should clock inversion be used? */
-	u8 clock_inversion:1;
-};
-
-#if defined(CONFIG_DVB_NXT6000) || (defined(CONFIG_DVB_NXT6000_MODULE) && defined(MODULE))
-extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
-					   struct i2c_adapter* i2c);
-#else
-static inline struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
-					   struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_NXT6000
-
-#endif // NXT6000_H
diff --git a/drivers/media/dvb/frontends/nxt6000_priv.h b/drivers/media/dvb/frontends/nxt6000_priv.h
deleted file mode 100644
index 0422e58..0000000
--- a/drivers/media/dvb/frontends/nxt6000_priv.h
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Public Include File for DRV6000 users
- * (ie. NxtWave Communications - NXT6000 demodulator driver)
- *
- * Copyright (C) 2001 NxtWave Communications, Inc.
- *
- */
-
-/*  Nxt6000 Register Addresses and Bit Masks */
-
-/* Maximum Register Number */
-#define MAXNXT6000REG          (0x9A)
-
-/* 0x1B A_VIT_BER_0  aka 0x3A */
-#define A_VIT_BER_0            (0x1B)
-
-/* 0x1D A_VIT_BER_TIMER_0 aka 0x38 */
-#define A_VIT_BER_TIMER_0      (0x1D)
-
-/* 0x21 RS_COR_STAT */
-#define RS_COR_STAT            (0x21)
-#define RSCORESTATUS           (0x03)
-
-/* 0x22 RS_COR_INTEN */
-#define RS_COR_INTEN           (0x22)
-
-/* 0x23 RS_COR_INSTAT */
-#define RS_COR_INSTAT          (0x23)
-#define INSTAT_ERROR           (0x04)
-#define LOCK_LOSS_BITS         (0x03)
-
-/* 0x24 RS_COR_SYNC_PARAM */
-#define RS_COR_SYNC_PARAM      (0x24)
-#define SYNC_PARAM             (0x03)
-
-/* 0x25 BER_CTRL */
-#define BER_CTRL               (0x25)
-#define BER_ENABLE             (0x02)
-#define BER_RESET              (0x01)
-
-/* 0x26 BER_PAY */
-#define BER_PAY                (0x26)
-
-/* 0x27 BER_PKT_L */
-#define BER_PKT_L              (0x27)
-#define BER_PKTOVERFLOW        (0x80)
-
-/* 0x30 VIT_COR_CTL */
-#define VIT_COR_CTL            (0x30)
-#define BER_CONTROL            (0x02)
-#define VIT_COR_MASK           (0x82)
-#define VIT_COR_RESYNC         (0x80)
-
-
-/* 0x32 VIT_SYNC_STATUS */
-#define VIT_SYNC_STATUS        (0x32)
-#define VITINSYNC              (0x80)
-
-/* 0x33 VIT_COR_INTEN */
-#define VIT_COR_INTEN          (0x33)
-#define GLOBAL_ENABLE          (0x80)
-
-/* 0x34 VIT_COR_INTSTAT */
-#define VIT_COR_INTSTAT        (0x34)
-#define BER_DONE               (0x08)
-#define BER_OVERFLOW           (0x10)
-
-/* 0x38 VIT_BERTIME_2 */
-#define VIT_BERTIME_2      (0x38)
-
-/* 0x39 VIT_BERTIME_1 */
-#define VIT_BERTIME_1      (0x39)
-
-/* 0x3A VIT_BERTIME_0 */
-#define VIT_BERTIME_0      (0x3a)
-
-			     /* 0x38 OFDM_BERTimer *//* Use the alias registers */
-#define A_VIT_BER_TIMER_0      (0x1D)
-
-			     /* 0x3A VIT_BER_TIMER_0 *//* Use the alias registers */
-#define A_VIT_BER_0            (0x1B)
-
-/* 0x3B VIT_BER_1 */
-#define VIT_BER_1              (0x3b)
-
-/* 0x3C VIT_BER_0 */
-#define VIT_BER_0              (0x3c)
-
-/* 0x40 OFDM_COR_CTL */
-#define OFDM_COR_CTL           (0x40)
-#define COREACT                (0x20)
-#define HOLDSM                 (0x10)
-#define WAIT_AGC               (0x02)
-#define WAIT_SYR               (0x03)
-
-/* 0x41 OFDM_COR_STAT */
-#define OFDM_COR_STAT          (0x41)
-#define COR_STATUS             (0x0F)
-#define MONITOR_TPS            (0x06)
-#define TPSLOCKED              (0x40)
-#define AGCLOCKED              (0x10)
-
-/* 0x42 OFDM_COR_INTEN */
-#define OFDM_COR_INTEN         (0x42)
-#define TPSRCVBAD              (0x04)
-#define TPSRCVCHANGED         (0x02)
-#define TPSRCVUPDATE           (0x01)
-
-/* 0x43 OFDM_COR_INSTAT */
-#define OFDM_COR_INSTAT        (0x43)
-
-/* 0x44 OFDM_COR_MODEGUARD */
-#define OFDM_COR_MODEGUARD     (0x44)
-#define FORCEMODE              (0x08)
-#define FORCEMODE8K			   (0x04)
-
-/* 0x45 OFDM_AGC_CTL */
-#define OFDM_AGC_CTL           (0x45)
-#define INITIAL_AGC_BW		   (0x08)
-#define AGCNEG                 (0x02)
-#define AGCLAST				   (0x10)
-
-/* 0x48 OFDM_AGC_TARGET */
-#define OFDM_AGC_TARGET		   (0x48)
-#define OFDM_AGC_TARGET_DEFAULT (0x28)
-#define OFDM_AGC_TARGET_IMPULSE (0x38)
-
-/* 0x49 OFDM_AGC_GAIN_1 */
-#define OFDM_AGC_GAIN_1        (0x49)
-
-/* 0x4B OFDM_ITB_CTL */
-#define OFDM_ITB_CTL           (0x4B)
-#define ITBINV                 (0x01)
-
-/* 0x49 AGC_GAIN_1 */
-#define AGC_GAIN_1             (0x49)
-
-/* 0x4A AGC_GAIN_2 */
-#define AGC_GAIN_2             (0x4A)
-
-/* 0x4C OFDM_ITB_FREQ_1 */
-#define OFDM_ITB_FREQ_1        (0x4C)
-
-/* 0x4D OFDM_ITB_FREQ_2 */
-#define OFDM_ITB_FREQ_2        (0x4D)
-
-/* 0x4E  OFDM_CAS_CTL */
-#define OFDM_CAS_CTL           (0x4E)
-#define ACSDIS                 (0x40)
-#define CCSEN                  (0x80)
-
-/* 0x4F CAS_FREQ */
-#define CAS_FREQ               (0x4F)
-
-/* 0x51 OFDM_SYR_CTL */
-#define OFDM_SYR_CTL           (0x51)
-#define SIXTH_ENABLE           (0x80)
-#define SYR_TRACKING_DISABLE   (0x01)
-
-/* 0x52 OFDM_SYR_STAT */
-#define OFDM_SYR_STAT		   (0x52)
-#define GI14_2K_SYR_LOCK	   (0x13)
-#define GI14_8K_SYR_LOCK	   (0x17)
-#define GI14_SYR_LOCK		   (0x10)
-
-/* 0x55 OFDM_SYR_OFFSET_1 */
-#define OFDM_SYR_OFFSET_1      (0x55)
-
-/* 0x56 OFDM_SYR_OFFSET_2 */
-#define OFDM_SYR_OFFSET_2      (0x56)
-
-/* 0x58 OFDM_SCR_CTL */
-#define OFDM_SCR_CTL           (0x58)
-#define SYR_ADJ_DECAY_MASK     (0x70)
-#define SYR_ADJ_DECAY          (0x30)
-
-/* 0x59 OFDM_PPM_CTL_1 */
-#define OFDM_PPM_CTL_1         (0x59)
-#define PPMMAX_MASK            (0x30)
-#define PPM256				   (0x30)
-
-/* 0x5B OFDM_TRL_NOMINALRATE_1 */
-#define OFDM_TRL_NOMINALRATE_1 (0x5B)
-
-/* 0x5C OFDM_TRL_NOMINALRATE_2 */
-#define OFDM_TRL_NOMINALRATE_2 (0x5C)
-
-/* 0x5D OFDM_TRL_TIME_1 */
-#define OFDM_TRL_TIME_1        (0x5D)
-
-/* 0x60 OFDM_CRL_FREQ_1 */
-#define OFDM_CRL_FREQ_1        (0x60)
-
-/* 0x63 OFDM_CHC_CTL_1 */
-#define OFDM_CHC_CTL_1         (0x63)
-#define MANMEAN1               (0xF0);
-#define CHCFIR                 (0x01)
-
-/* 0x64 OFDM_CHC_SNR */
-#define OFDM_CHC_SNR           (0x64)
-
-/* 0x65 OFDM_BDI_CTL */
-#define OFDM_BDI_CTL           (0x65)
-#define LP_SELECT              (0x02)
-
-/* 0x67 OFDM_TPS_RCVD_1 */
-#define OFDM_TPS_RCVD_1        (0x67)
-#define TPSFRAME               (0x03)
-
-/* 0x68 OFDM_TPS_RCVD_2 */
-#define OFDM_TPS_RCVD_2        (0x68)
-
-/* 0x69 OFDM_TPS_RCVD_3 */
-#define OFDM_TPS_RCVD_3        (0x69)
-
-/* 0x6A OFDM_TPS_RCVD_4 */
-#define OFDM_TPS_RCVD_4        (0x6A)
-
-/* 0x6B OFDM_TPS_RESERVED_1 */
-#define OFDM_TPS_RESERVED_1    (0x6B)
-
-/* 0x6C OFDM_TPS_RESERVED_2 */
-#define OFDM_TPS_RESERVED_2    (0x6C)
-
-/* 0x73 OFDM_MSC_REV */
-#define OFDM_MSC_REV           (0x73)
-
-/* 0x76 OFDM_SNR_CARRIER_2 */
-#define OFDM_SNR_CARRIER_2     (0x76)
-#define MEAN_MASK              (0x80)
-#define MEANBIT                (0x80)
-
-/* 0x80 ANALOG_CONTROL_0 */
-#define ANALOG_CONTROL_0       (0x80)
-#define POWER_DOWN_ADC         (0x40)
-
-/* 0x81 ENABLE_TUNER_IIC */
-#define ENABLE_TUNER_IIC       (0x81)
-#define ENABLE_TUNER_BIT       (0x01)
-
-/* 0x82 EN_DMD_RACQ */
-#define EN_DMD_RACQ            (0x82)
-#define EN_DMD_RACQ_REG_VAL    (0x81)
-#define EN_DMD_RACQ_REG_VAL_14 (0x01)
-
-/* 0x84 SNR_COMMAND */
-#define SNR_COMMAND            (0x84)
-#define SNRStat                (0x80)
-
-/* 0x85 SNRCARRIERNUMBER_LSB */
-#define SNRCARRIERNUMBER_LSB   (0x85)
-
-/* 0x87 SNRMINTHRESHOLD_LSB */
-#define SNRMINTHRESHOLD_LSB    (0x87)
-
-/* 0x89 SNR_PER_CARRIER_LSB */
-#define SNR_PER_CARRIER_LSB    (0x89)
-
-/* 0x8B SNRBELOWTHRESHOLD_LSB */
-#define SNRBELOWTHRESHOLD_LSB  (0x8B)
-
-/* 0x91 RF_AGC_VAL_1 */
-#define RF_AGC_VAL_1           (0x91)
-
-/* 0x92 RF_AGC_STATUS */
-#define RF_AGC_STATUS          (0x92)
-
-/* 0x98 DIAG_CONFIG */
-#define DIAG_CONFIG            (0x98)
-#define DIAG_MASK              (0x70)
-#define TB_SET                 (0x10)
-#define TRAN_SELECT            (0x07)
-#define SERIAL_SELECT          (0x01)
-
-/* 0x99 SUB_DIAG_MODE_SEL */
-#define SUB_DIAG_MODE_SEL      (0x99)
-#define CLKINVERSION           (0x01)
-
-/* 0x9A TS_FORMAT */
-#define TS_FORMAT              (0x9A)
-#define ERROR_SENSE            (0x08)
-#define VALID_SENSE            (0x04)
-#define SYNC_SENSE             (0x02)
-#define GATED_CLOCK            (0x01)
-
-#define NXT6000ASICDEVICE      (0x0b)
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
deleted file mode 100644
index 5ef9218..0000000
--- a/drivers/media/dvb/frontends/or51132.c
+++ /dev/null
@@ -1,631 +0,0 @@
-/*
- *    Support for OR51132 (pcHDTV HD-3000) - VSB/QAM
- *
- *
- *    Copyright (C) 2007 Trent Piepho <xyzzy@speakeasy.org>
- *
- *    Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com>
- *
- *    Based on code from Jack Kelliher (kelliher@xmission.com)
- *                           Copyright (C) 2002 & pcHDTV, inc.
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
-*/
-
-/*
- * This driver needs two external firmware files. Please copy
- * "dvb-fe-or51132-vsb.fw" and "dvb-fe-or51132-qam.fw" to
- * /usr/lib/hotplug/firmware/ or /lib/firmware/
- * (depending on configuration of firmware hotplug).
- */
-#define OR51132_VSB_FIRMWARE "dvb-fe-or51132-vsb.fw"
-#define OR51132_QAM_FIRMWARE "dvb-fe-or51132-qam.fw"
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <asm/byteorder.h>
-
-#include "dvb_math.h"
-#include "dvb_frontend.h"
-#include "or51132.h"
-
-static int debug;
-#define dprintk(args...) \
-	do { \
-		if (debug) printk(KERN_DEBUG "or51132: " args); \
-	} while (0)
-
-
-struct or51132_state
-{
-	struct i2c_adapter* i2c;
-
-	/* Configuration settings */
-	const struct or51132_config* config;
-
-	struct dvb_frontend frontend;
-
-	/* Demodulator private data */
-	fe_modulation_t current_modulation;
-	u32 snr; /* Result of last SNR calculation */
-
-	/* Tuner private data */
-	u32 current_frequency;
-};
-
-
-/* Write buffer to demod */
-static int or51132_writebuf(struct or51132_state *state, const u8 *buf, int len)
-{
-	int err;
-	struct i2c_msg msg = { .addr = state->config->demod_address,
-			       .flags = 0, .buf = (u8*)buf, .len = len };
-
-	/* msleep(20); */ /* doesn't appear to be necessary */
-	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
-		printk(KERN_WARNING "or51132: I2C write (addr 0x%02x len %d) error: %d\n",
-		       msg.addr, msg.len, err);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-/* Write constant bytes, e.g. or51132_writebytes(state, 0x04, 0x42, 0x00);
-   Less code and more efficient that loading a buffer on the stack with
-   the bytes to send and then calling or51132_writebuf() on that. */
-#define or51132_writebytes(state, data...)  \
-	({ static const u8 _data[] = {data}; \
-	or51132_writebuf(state, _data, sizeof(_data)); })
-
-/* Read data from demod into buffer.  Returns 0 on success. */
-static int or51132_readbuf(struct or51132_state *state, u8 *buf, int len)
-{
-	int err;
-	struct i2c_msg msg = { .addr = state->config->demod_address,
-			       .flags = I2C_M_RD, .buf = buf, .len = len };
-
-	/* msleep(20); */ /* doesn't appear to be necessary */
-	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
-		printk(KERN_WARNING "or51132: I2C read (addr 0x%02x len %d) error: %d\n",
-		       msg.addr, msg.len, err);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-/* Reads a 16-bit demod register.  Returns <0 on error. */
-static int or51132_readreg(struct or51132_state *state, u8 reg)
-{
-	u8 buf[2] = { 0x04, reg };
-	struct i2c_msg msg[2] = {
-		{.addr = state->config->demod_address, .flags = 0,
-		 .buf = buf, .len = 2 },
-		{.addr = state->config->demod_address, .flags = I2C_M_RD,
-		 .buf = buf, .len = 2 }};
-	int err;
-
-	if ((err = i2c_transfer(state->i2c, msg, 2)) != 2) {
-		printk(KERN_WARNING "or51132: I2C error reading register %d: %d\n",
-		       reg, err);
-		return -EREMOTEIO;
-	}
-	return buf[0] | (buf[1] << 8);
-}
-
-static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
-{
-	struct or51132_state* state = fe->demodulator_priv;
-	static const u8 run_buf[] = {0x7F,0x01};
-	u8 rec_buf[8];
-	u32 firmwareAsize, firmwareBsize;
-	int i,ret;
-
-	dprintk("Firmware is %Zd bytes\n",fw->size);
-
-	/* Get size of firmware A and B */
-	firmwareAsize = le32_to_cpu(*((__le32*)fw->data));
-	dprintk("FirmwareA is %i bytes\n",firmwareAsize);
-	firmwareBsize = le32_to_cpu(*((__le32*)(fw->data+4)));
-	dprintk("FirmwareB is %i bytes\n",firmwareBsize);
-
-	/* Upload firmware */
-	if ((ret = or51132_writebuf(state, &fw->data[8], firmwareAsize))) {
-		printk(KERN_WARNING "or51132: load_firmware error 1\n");
-		return ret;
-	}
-	if ((ret = or51132_writebuf(state, &fw->data[8+firmwareAsize],
-				    firmwareBsize))) {
-		printk(KERN_WARNING "or51132: load_firmware error 2\n");
-		return ret;
-	}
-
-	if ((ret = or51132_writebuf(state, run_buf, 2))) {
-		printk(KERN_WARNING "or51132: load_firmware error 3\n");
-		return ret;
-	}
-	if ((ret = or51132_writebuf(state, run_buf, 2))) {
-		printk(KERN_WARNING "or51132: load_firmware error 4\n");
-		return ret;
-	}
-
-	/* 50ms for operation to begin */
-	msleep(50);
-
-	/* Read back ucode version to besure we loaded correctly and are really up and running */
-	/* Get uCode version */
-	if ((ret = or51132_writebytes(state, 0x10, 0x10, 0x00))) {
-		printk(KERN_WARNING "or51132: load_firmware error a\n");
-		return ret;
-	}
-	if ((ret = or51132_writebytes(state, 0x04, 0x17))) {
-		printk(KERN_WARNING "or51132: load_firmware error b\n");
-		return ret;
-	}
-	if ((ret = or51132_writebytes(state, 0x00, 0x00))) {
-		printk(KERN_WARNING "or51132: load_firmware error c\n");
-		return ret;
-	}
-	for (i=0;i<4;i++) {
-		/* Once upon a time, this command might have had something
-		   to do with getting the firmware version, but it's
-		   not used anymore:
-		   {0x04,0x00,0x30,0x00,i+1} */
-		/* Read 8 bytes, two bytes at a time */
-		if ((ret = or51132_readbuf(state, &rec_buf[i*2], 2))) {
-			printk(KERN_WARNING
-			       "or51132: load_firmware error d - %d\n",i);
-			return ret;
-		}
-	}
-
-	printk(KERN_WARNING
-	       "or51132: Version: %02X%02X%02X%02X-%02X%02X%02X%02X (%02X%01X-%01X-%02X%01X-%01X)\n",
-	       rec_buf[1],rec_buf[0],rec_buf[3],rec_buf[2],
-	       rec_buf[5],rec_buf[4],rec_buf[7],rec_buf[6],
-	       rec_buf[3],rec_buf[2]>>4,rec_buf[2]&0x0f,
-	       rec_buf[5],rec_buf[4]>>4,rec_buf[4]&0x0f);
-
-	if ((ret = or51132_writebytes(state, 0x10, 0x00, 0x00))) {
-		printk(KERN_WARNING "or51132: load_firmware error e\n");
-		return ret;
-	}
-	return 0;
-};
-
-static int or51132_init(struct dvb_frontend* fe)
-{
-	return 0;
-}
-
-static int or51132_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	*ber = 0;
-	return 0;
-}
-
-static int or51132_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	*ucblocks = 0;
-	return 0;
-}
-
-static int or51132_sleep(struct dvb_frontend* fe)
-{
-	return 0;
-}
-
-static int or51132_setmode(struct dvb_frontend* fe)
-{
-	struct or51132_state* state = fe->demodulator_priv;
-	u8 cmd_buf1[3] = {0x04, 0x01, 0x5f};
-	u8 cmd_buf2[3] = {0x1c, 0x00, 0 };
-
-	dprintk("setmode %d\n",(int)state->current_modulation);
-
-	switch (state->current_modulation) {
-	case VSB_8:
-		/* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high */
-		cmd_buf1[2] = 0x50;
-		/* REC MODE inv IF spectrum, Normal */
-		cmd_buf2[1] = 0x03;
-		/* Channel MODE ATSC/VSB8 */
-		cmd_buf2[2] = 0x06;
-		break;
-	/* All QAM modes are:
-	   Auto-deinterleave; MPEGser, MPEG2tr, phase noise-high
-	   REC MODE Normal Carrier Lock */
-	case QAM_AUTO:
-		/* Channel MODE Auto QAM64/256 */
-		cmd_buf2[2] = 0x4f;
-		break;
-	case QAM_256:
-		/* Channel MODE QAM256 */
-		cmd_buf2[2] = 0x45;
-		break;
-	case QAM_64:
-		/* Channel MODE QAM64 */
-		cmd_buf2[2] = 0x43;
-		break;
-	default:
-		printk(KERN_WARNING
-		       "or51132: setmode: Modulation set to unsupported value (%d)\n",
-		       state->current_modulation);
-		return -EINVAL;
-	}
-
-	/* Set Receiver 1 register */
-	if (or51132_writebuf(state, cmd_buf1, 3)) {
-		printk(KERN_WARNING "or51132: set_mode error 1\n");
-		return -EREMOTEIO;
-	}
-	dprintk("set #1 to %02x\n", cmd_buf1[2]);
-
-	/* Set operation mode in Receiver 6 register */
-	if (or51132_writebuf(state, cmd_buf2, 3)) {
-		printk(KERN_WARNING "or51132: set_mode error 2\n");
-		return -EREMOTEIO;
-	}
-	dprintk("set #6 to 0x%02x%02x\n", cmd_buf2[1], cmd_buf2[2]);
-
-	return 0;
-}
-
-/* Some modulations use the same firmware.  This classifies modulations
-   by the firmware they use. */
-#define MOD_FWCLASS_UNKNOWN	0
-#define MOD_FWCLASS_VSB		1
-#define MOD_FWCLASS_QAM		2
-static int modulation_fw_class(fe_modulation_t modulation)
-{
-	switch(modulation) {
-	case VSB_8:
-		return MOD_FWCLASS_VSB;
-	case QAM_AUTO:
-	case QAM_64:
-	case QAM_256:
-		return MOD_FWCLASS_QAM;
-	default:
-		return MOD_FWCLASS_UNKNOWN;
-	}
-}
-
-static int or51132_set_parameters(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	int ret;
-	struct or51132_state* state = fe->demodulator_priv;
-	const struct firmware *fw;
-	const char *fwname;
-	int clock_mode;
-
-	/* Upload new firmware only if we need a different one */
-	if (modulation_fw_class(state->current_modulation) !=
-	    modulation_fw_class(p->modulation)) {
-		switch (modulation_fw_class(p->modulation)) {
-		case MOD_FWCLASS_VSB:
-			dprintk("set_parameters VSB MODE\n");
-			fwname = OR51132_VSB_FIRMWARE;
-
-			/* Set non-punctured clock for VSB */
-			clock_mode = 0;
-			break;
-		case MOD_FWCLASS_QAM:
-			dprintk("set_parameters QAM MODE\n");
-			fwname = OR51132_QAM_FIRMWARE;
-
-			/* Set punctured clock for QAM */
-			clock_mode = 1;
-			break;
-		default:
-			printk("or51132: Modulation type(%d) UNSUPPORTED\n",
-			       p->modulation);
-			return -1;
-		}
-		printk("or51132: Waiting for firmware upload(%s)...\n",
-		       fwname);
-		ret = request_firmware(&fw, fwname, state->i2c->dev.parent);
-		if (ret) {
-			printk(KERN_WARNING "or51132: No firmware up"
-			       "loaded(timeout or file not found?)\n");
-			return ret;
-		}
-		ret = or51132_load_firmware(fe, fw);
-		release_firmware(fw);
-		if (ret) {
-			printk(KERN_WARNING "or51132: Writing firmware to "
-			       "device failed!\n");
-			return ret;
-		}
-		printk("or51132: Firmware upload complete.\n");
-		state->config->set_ts_params(fe, clock_mode);
-	}
-	/* Change only if we are actually changing the modulation */
-	if (state->current_modulation != p->modulation) {
-		state->current_modulation = p->modulation;
-		or51132_setmode(fe);
-	}
-
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	/* Set to current mode */
-	or51132_setmode(fe);
-
-	/* Update current frequency */
-	state->current_frequency = p->frequency;
-	return 0;
-}
-
-static int or51132_get_parameters(struct dvb_frontend* fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct or51132_state* state = fe->demodulator_priv;
-	int status;
-	int retry = 1;
-
-start:
-	/* Receiver Status */
-	if ((status = or51132_readreg(state, 0x00)) < 0) {
-		printk(KERN_WARNING "or51132: get_parameters: error reading receiver status\n");
-		return -EREMOTEIO;
-	}
-	switch(status&0xff) {
-	case 0x06:
-		p->modulation = VSB_8;
-		break;
-	case 0x43:
-		p->modulation = QAM_64;
-		break;
-	case 0x45:
-		p->modulation = QAM_256;
-		break;
-	default:
-		if (retry--)
-			goto start;
-		printk(KERN_WARNING "or51132: unknown status 0x%02x\n",
-		       status&0xff);
-		return -EREMOTEIO;
-	}
-
-	/* FIXME: Read frequency from frontend, take AFC into account */
-	p->frequency = state->current_frequency;
-
-	/* FIXME: How to read inversion setting? Receiver 6 register? */
-	p->inversion = INVERSION_AUTO;
-
-	return 0;
-}
-
-static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct or51132_state* state = fe->demodulator_priv;
-	int reg;
-
-	/* Receiver Status */
-	if ((reg = or51132_readreg(state, 0x00)) < 0) {
-		printk(KERN_WARNING "or51132: read_status: error reading receiver status: %d\n", reg);
-		*status = 0;
-		return -EREMOTEIO;
-	}
-	dprintk("%s: read_status %04x\n", __func__, reg);
-
-	if (reg & 0x0100) /* Receiver Lock */
-		*status = FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI|
-			  FE_HAS_SYNC|FE_HAS_LOCK;
-	else
-		*status = 0;
-	return 0;
-}
-
-/* Calculate SNR estimation (scaled by 2^24)
-
-   8-VSB SNR and QAM equations from Oren datasheets
-
-   For 8-VSB:
-     SNR[dB] = 10 * log10(897152044.8282 / MSE^2 ) - K
-
-     Where K = 0 if NTSC rejection filter is OFF; and
-	   K = 3 if NTSC rejection filter is ON
-
-   For QAM64:
-     SNR[dB] = 10 * log10(897152044.8282 / MSE^2 )
-
-   For QAM256:
-     SNR[dB] = 10 * log10(907832426.314266  / MSE^2 )
-
-   We re-write the snr equation as:
-     SNR * 2^24 = 10*(c - 2*intlog10(MSE))
-   Where for QAM256, c = log10(907832426.314266) * 2^24
-   and for 8-VSB and QAM64, c = log10(897152044.8282) * 2^24 */
-
-static u32 calculate_snr(u32 mse, u32 c)
-{
-	if (mse == 0) /* No signal */
-		return 0;
-
-	mse = 2*intlog10(mse);
-	if (mse > c) {
-		/* Negative SNR, which is possible, but realisticly the
-		demod will lose lock before the signal gets this bad.  The
-		API only allows for unsigned values, so just return 0 */
-		return 0;
-	}
-	return 10*(c - mse);
-}
-
-static int or51132_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct or51132_state* state = fe->demodulator_priv;
-	int noise, reg;
-	u32 c, usK = 0;
-	int retry = 1;
-
-start:
-	/* SNR after Equalizer */
-	noise = or51132_readreg(state, 0x02);
-	if (noise < 0) {
-		printk(KERN_WARNING "or51132: read_snr: error reading equalizer\n");
-		return -EREMOTEIO;
-	}
-	dprintk("read_snr noise (%d)\n", noise);
-
-	/* Read status, contains modulation type for QAM_AUTO and
-	   NTSC filter for VSB */
-	reg = or51132_readreg(state, 0x00);
-	if (reg < 0) {
-		printk(KERN_WARNING "or51132: read_snr: error reading receiver status\n");
-		return -EREMOTEIO;
-	}
-
-	switch (reg&0xff) {
-	case 0x06:
-		if (reg & 0x1000) usK = 3 << 24;
-		/* Fall through to QAM64 case */
-	case 0x43:
-		c = 150204167;
-		break;
-	case 0x45:
-		c = 150290396;
-		break;
-	default:
-		printk(KERN_WARNING "or51132: unknown status 0x%02x\n", reg&0xff);
-		if (retry--) goto start;
-		return -EREMOTEIO;
-	}
-	dprintk("%s: modulation %02x, NTSC rej O%s\n", __func__,
-		reg&0xff, reg&0x1000?"n":"ff");
-
-	/* Calculate SNR using noise, c, and NTSC rejection correction */
-	state->snr = calculate_snr(noise, c) - usK;
-	*snr = (state->snr) >> 16;
-
-	dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise,
-		state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
-
-	return 0;
-}
-
-static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-{
-	/* Calculate Strength from SNR up to 35dB */
-	/* Even though the SNR can go higher than 35dB, there is some comfort */
-	/* factor in having a range of strong signals that can show at 100%   */
-	struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv;
-	u16 snr;
-	int ret;
-
-	ret = fe->ops.read_snr(fe, &snr);
-	if (ret != 0)
-		return ret;
-	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
-	/* scale the range 0 - 35*2^24 into 0 - 65535 */
-	if (state->snr >= 8960 * 0x10000)
-		*strength = 0xffff;
-	else
-		*strength = state->snr / 8960;
-
-	return 0;
-}
-
-static int or51132_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings)
-{
-	fe_tune_settings->min_delay_ms = 500;
-	fe_tune_settings->step_size = 0;
-	fe_tune_settings->max_drift = 0;
-
-	return 0;
-}
-
-static void or51132_release(struct dvb_frontend* fe)
-{
-	struct or51132_state* state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops or51132_ops;
-
-struct dvb_frontend* or51132_attach(const struct or51132_config* config,
-				    struct i2c_adapter* i2c)
-{
-	struct or51132_state* state = NULL;
-
-	/* Allocate memory for the internal state */
-	state = kzalloc(sizeof(struct or51132_state), GFP_KERNEL);
-	if (state == NULL)
-		return NULL;
-
-	/* Setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->current_frequency = -1;
-	state->current_modulation = -1;
-
-	/* Create dvb_frontend */
-	memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-}
-
-static struct dvb_frontend_ops or51132_ops = {
-	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
-	.info = {
-		.name			= "Oren OR51132 VSB/QAM Frontend",
-		.frequency_min		= 44000000,
-		.frequency_max		= 958000000,
-		.frequency_stepsize	= 166666,
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO |
-			FE_CAN_8VSB
-	},
-
-	.release = or51132_release,
-
-	.init = or51132_init,
-	.sleep = or51132_sleep,
-
-	.set_frontend = or51132_set_parameters,
-	.get_frontend = or51132_get_parameters,
-	.get_tune_settings = or51132_get_tune_settings,
-
-	.read_status = or51132_read_status,
-	.read_ber = or51132_read_ber,
-	.read_signal_strength = or51132_read_signal_strength,
-	.read_snr = or51132_read_snr,
-	.read_ucblocks = or51132_read_ucblocks,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("OR51132 ATSC [pcHDTV HD-3000] (8VSB & ITU J83 AnnexB FEC QAM64/256) Demodulator Driver");
-MODULE_AUTHOR("Kirk Lapray");
-MODULE_AUTHOR("Trent Piepho");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(or51132_attach);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/frontends/or51132.h b/drivers/media/dvb/frontends/or51132.h
deleted file mode 100644
index 1b8e04d..0000000
--- a/drivers/media/dvb/frontends/or51132.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *    Support for OR51132 (pcHDTV HD-3000) - VSB/QAM
- *
- *    Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
-*/
-
-#ifndef OR51132_H
-#define OR51132_H
-
-#include <linux/firmware.h>
-#include <linux/dvb/frontend.h>
-
-struct or51132_config
-{
-	/* The demodulator's i2c address */
-	u8 demod_address;
-
-	/* Need to set device param for start_dma */
-	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
-};
-
-#if defined(CONFIG_DVB_OR51132) || (defined(CONFIG_DVB_OR51132_MODULE) && defined(MODULE))
-extern struct dvb_frontend* or51132_attach(const struct or51132_config* config,
-					   struct i2c_adapter* i2c);
-#else
-static inline struct dvb_frontend* or51132_attach(const struct or51132_config* config,
-					   struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_OR51132
-
-#endif // OR51132_H
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
deleted file mode 100644
index c625b57..0000000
--- a/drivers/media/dvb/frontends/or51211.c
+++ /dev/null
@@ -1,581 +0,0 @@
-/*
- *    Support for OR51211 (pcHDTV HD-2000) - VSB
- *
- *    Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com>
- *
- *    Based on code from Jack Kelliher (kelliher@xmission.com)
- *                           Copyright (C) 2002 & pcHDTV, inc.
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
-*/
-
-/*
- * This driver needs external firmware. Please use the command
- * "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware
- * or /lib/firmware (depending on configuration of firmware hotplug).
- */
-#define OR51211_DEFAULT_FIRMWARE "dvb-fe-or51211.fw"
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/firmware.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <asm/byteorder.h>
-
-#include "dvb_math.h"
-#include "dvb_frontend.h"
-#include "or51211.h"
-
-static int debug;
-#define dprintk(args...) \
-	do { \
-		if (debug) printk(KERN_DEBUG "or51211: " args); \
-	} while (0)
-
-static u8 run_buf[] = {0x7f,0x01};
-static u8 cmd_buf[] = {0x04,0x01,0x50,0x80,0x06}; // ATSC
-
-struct or51211_state {
-
-	struct i2c_adapter* i2c;
-
-	/* Configuration settings */
-	const struct or51211_config* config;
-
-	struct dvb_frontend frontend;
-	struct bt878* bt;
-
-	/* Demodulator private data */
-	u8 initialized:1;
-	u32 snr; /* Result of last SNR claculation */
-
-	/* Tuner private data */
-	u32 current_frequency;
-};
-
-static int i2c_writebytes (struct or51211_state* state, u8 reg, const u8 *buf,
-			   int len)
-{
-	int err;
-	struct i2c_msg msg;
-	msg.addr	= reg;
-	msg.flags	= 0;
-	msg.len		= len;
-	msg.buf		= (u8 *)buf;
-
-	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
-		printk(KERN_WARNING "or51211: i2c_writebytes error "
-		       "(addr %02x, err == %i)\n", reg, err);
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static int i2c_readbytes(struct or51211_state *state, u8 reg, u8 *buf, int len)
-{
-	int err;
-	struct i2c_msg msg;
-	msg.addr	= reg;
-	msg.flags	= I2C_M_RD;
-	msg.len		= len;
-	msg.buf		= buf;
-
-	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
-		printk(KERN_WARNING "or51211: i2c_readbytes error "
-		       "(addr %02x, err == %i)\n", reg, err);
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static int or51211_load_firmware (struct dvb_frontend* fe,
-				  const struct firmware *fw)
-{
-	struct or51211_state* state = fe->demodulator_priv;
-	u8 tudata[585];
-	int i;
-
-	dprintk("Firmware is %zd bytes\n",fw->size);
-
-	/* Get eprom data */
-	tudata[0] = 17;
-	if (i2c_writebytes(state,0x50,tudata,1)) {
-		printk(KERN_WARNING "or51211:load_firmware error eprom addr\n");
-		return -1;
-	}
-	if (i2c_readbytes(state,0x50,&tudata[145],192)) {
-		printk(KERN_WARNING "or51211: load_firmware error eprom\n");
-		return -1;
-	}
-
-	/* Create firmware buffer */
-	for (i = 0; i < 145; i++)
-		tudata[i] = fw->data[i];
-
-	for (i = 0; i < 248; i++)
-		tudata[i+337] = fw->data[145+i];
-
-	state->config->reset(fe);
-
-	if (i2c_writebytes(state,state->config->demod_address,tudata,585)) {
-		printk(KERN_WARNING "or51211: load_firmware error 1\n");
-		return -1;
-	}
-	msleep(1);
-
-	if (i2c_writebytes(state,state->config->demod_address,
-			   &fw->data[393],8125)) {
-		printk(KERN_WARNING "or51211: load_firmware error 2\n");
-		return -1;
-	}
-	msleep(1);
-
-	if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
-		printk(KERN_WARNING "or51211: load_firmware error 3\n");
-		return -1;
-	}
-
-	/* Wait at least 5 msec */
-	msleep(10);
-	if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
-		printk(KERN_WARNING "or51211: load_firmware error 4\n");
-		return -1;
-	}
-	msleep(10);
-
-	printk("or51211: Done.\n");
-	return 0;
-};
-
-static int or51211_setmode(struct dvb_frontend* fe, int mode)
-{
-	struct or51211_state* state = fe->demodulator_priv;
-	u8 rec_buf[14];
-
-	state->config->setmode(fe, mode);
-
-	if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
-		printk(KERN_WARNING "or51211: setmode error 1\n");
-		return -1;
-	}
-
-	/* Wait at least 5 msec */
-	msleep(10);
-	if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
-		printk(KERN_WARNING "or51211: setmode error 2\n");
-		return -1;
-	}
-
-	msleep(10);
-
-	/* Set operation mode in Receiver 1 register;
-	 * type 1:
-	 * data 0x50h  Automatic sets receiver channel conditions
-	 *             Automatic NTSC rejection filter
-	 *             Enable  MPEG serial data output
-	 *             MPEG2tr
-	 *             High tuner phase noise
-	 *             normal +/-150kHz Carrier acquisition range
-	 */
-	if (i2c_writebytes(state,state->config->demod_address,cmd_buf,3)) {
-		printk(KERN_WARNING "or51211: setmode error 3\n");
-		return -1;
-	}
-
-	rec_buf[0] = 0x04;
-	rec_buf[1] = 0x00;
-	rec_buf[2] = 0x03;
-	rec_buf[3] = 0x00;
-	msleep(20);
-	if (i2c_writebytes(state,state->config->demod_address,rec_buf,3)) {
-		printk(KERN_WARNING "or51211: setmode error 5\n");
-	}
-	msleep(3);
-	if (i2c_readbytes(state,state->config->demod_address,&rec_buf[10],2)) {
-		printk(KERN_WARNING "or51211: setmode error 6");
-		return -1;
-	}
-	dprintk("setmode rec status %02x %02x\n",rec_buf[10],rec_buf[11]);
-
-	return 0;
-}
-
-static int or51211_set_parameters(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct or51211_state* state = fe->demodulator_priv;
-
-	/* Change only if we are actually changing the channel */
-	if (state->current_frequency != p->frequency) {
-		if (fe->ops.tuner_ops.set_params) {
-			fe->ops.tuner_ops.set_params(fe);
-			if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-		}
-
-		/* Set to ATSC mode */
-		or51211_setmode(fe,0);
-
-		/* Update current frequency */
-		state->current_frequency = p->frequency;
-	}
-	return 0;
-}
-
-static int or51211_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct or51211_state* state = fe->demodulator_priv;
-	unsigned char rec_buf[2];
-	unsigned char snd_buf[] = {0x04,0x00,0x03,0x00};
-	*status = 0;
-
-	/* Receiver Status */
-	if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
-		printk(KERN_WARNING "or51132: read_status write error\n");
-		return -1;
-	}
-	msleep(3);
-	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
-		printk(KERN_WARNING "or51132: read_status read error\n");
-		return -1;
-	}
-	dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]);
-
-	if (rec_buf[0] &  0x01) { /* Receiver Lock */
-		*status |= FE_HAS_SIGNAL;
-		*status |= FE_HAS_CARRIER;
-		*status |= FE_HAS_VITERBI;
-		*status |= FE_HAS_SYNC;
-		*status |= FE_HAS_LOCK;
-	}
-	return 0;
-}
-
-/* Calculate SNR estimation (scaled by 2^24)
-
-   8-VSB SNR equation from Oren datasheets
-
-   For 8-VSB:
-     SNR[dB] = 10 * log10(219037.9454 / MSE^2 )
-
-   We re-write the snr equation as:
-     SNR * 2^24 = 10*(c - 2*intlog10(MSE))
-   Where for 8-VSB, c = log10(219037.9454) * 2^24 */
-
-static u32 calculate_snr(u32 mse, u32 c)
-{
-	if (mse == 0) /* No signal */
-		return 0;
-
-	mse = 2*intlog10(mse);
-	if (mse > c) {
-		/* Negative SNR, which is possible, but realisticly the
-		demod will lose lock before the signal gets this bad.  The
-		API only allows for unsigned values, so just return 0 */
-		return 0;
-	}
-	return 10*(c - mse);
-}
-
-static int or51211_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct or51211_state* state = fe->demodulator_priv;
-	u8 rec_buf[2];
-	u8 snd_buf[3];
-
-	/* SNR after Equalizer */
-	snd_buf[0] = 0x04;
-	snd_buf[1] = 0x00;
-	snd_buf[2] = 0x04;
-
-	if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
-		printk(KERN_WARNING "%s: error writing snr reg\n",
-		       __func__);
-		return -1;
-	}
-	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
-		printk(KERN_WARNING "%s: read_status read error\n",
-		       __func__);
-		return -1;
-	}
-
-	state->snr = calculate_snr(rec_buf[0], 89599047);
-	*snr = (state->snr) >> 16;
-
-	dprintk("%s: noise = 0x%02x, snr = %d.%02d dB\n", __func__, rec_buf[0],
-		state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
-
-	return 0;
-}
-
-static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-{
-	/* Calculate Strength from SNR up to 35dB */
-	/* Even though the SNR can go higher than 35dB, there is some comfort */
-	/* factor in having a range of strong signals that can show at 100%   */
-	struct or51211_state* state = (struct or51211_state*)fe->demodulator_priv;
-	u16 snr;
-	int ret;
-
-	ret = fe->ops.read_snr(fe, &snr);
-	if (ret != 0)
-		return ret;
-	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
-	/* scale the range 0 - 35*2^24 into 0 - 65535 */
-	if (state->snr >= 8960 * 0x10000)
-		*strength = 0xffff;
-	else
-		*strength = state->snr / 8960;
-
-	return 0;
-}
-
-static int or51211_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	*ber = -ENOSYS;
-	return 0;
-}
-
-static int or51211_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	*ucblocks = -ENOSYS;
-	return 0;
-}
-
-static int or51211_sleep(struct dvb_frontend* fe)
-{
-	return 0;
-}
-
-static int or51211_init(struct dvb_frontend* fe)
-{
-	struct or51211_state* state = fe->demodulator_priv;
-	const struct or51211_config* config = state->config;
-	const struct firmware* fw;
-	unsigned char get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00};
-	unsigned char rec_buf[14];
-	int ret,i;
-
-	if (!state->initialized) {
-		/* Request the firmware, this will block until it uploads */
-		printk(KERN_INFO "or51211: Waiting for firmware upload "
-		       "(%s)...\n", OR51211_DEFAULT_FIRMWARE);
-		ret = config->request_firmware(fe, &fw,
-					       OR51211_DEFAULT_FIRMWARE);
-		printk(KERN_INFO "or51211:Got Hotplug firmware\n");
-		if (ret) {
-			printk(KERN_WARNING "or51211: No firmware uploaded "
-			       "(timeout or file not found?)\n");
-			return ret;
-		}
-
-		ret = or51211_load_firmware(fe, fw);
-		release_firmware(fw);
-		if (ret) {
-			printk(KERN_WARNING "or51211: Writing firmware to "
-			       "device failed!\n");
-			return ret;
-		}
-		printk(KERN_INFO "or51211: Firmware upload complete.\n");
-
-		/* Set operation mode in Receiver 1 register;
-		 * type 1:
-		 * data 0x50h  Automatic sets receiver channel conditions
-		 *             Automatic NTSC rejection filter
-		 *             Enable  MPEG serial data output
-		 *             MPEG2tr
-		 *             High tuner phase noise
-		 *             normal +/-150kHz Carrier acquisition range
-		 */
-		if (i2c_writebytes(state,state->config->demod_address,
-				   cmd_buf,3)) {
-			printk(KERN_WARNING "or51211: Load DVR Error 5\n");
-			return -1;
-		}
-
-		/* Read back ucode version to besure we loaded correctly */
-		/* and are really up and running */
-		rec_buf[0] = 0x04;
-		rec_buf[1] = 0x00;
-		rec_buf[2] = 0x03;
-		rec_buf[3] = 0x00;
-		msleep(30);
-		if (i2c_writebytes(state,state->config->demod_address,
-				   rec_buf,3)) {
-			printk(KERN_WARNING "or51211: Load DVR Error A\n");
-			return -1;
-		}
-		msleep(3);
-		if (i2c_readbytes(state,state->config->demod_address,
-				  &rec_buf[10],2)) {
-			printk(KERN_WARNING "or51211: Load DVR Error B\n");
-			return -1;
-		}
-
-		rec_buf[0] = 0x04;
-		rec_buf[1] = 0x00;
-		rec_buf[2] = 0x01;
-		rec_buf[3] = 0x00;
-		msleep(20);
-		if (i2c_writebytes(state,state->config->demod_address,
-				   rec_buf,3)) {
-			printk(KERN_WARNING "or51211: Load DVR Error C\n");
-			return -1;
-		}
-		msleep(3);
-		if (i2c_readbytes(state,state->config->demod_address,
-				  &rec_buf[12],2)) {
-			printk(KERN_WARNING "or51211: Load DVR Error D\n");
-			return -1;
-		}
-
-		for (i = 0; i < 8; i++)
-			rec_buf[i]=0xed;
-
-		for (i = 0; i < 5; i++) {
-			msleep(30);
-			get_ver_buf[4] = i+1;
-			if (i2c_writebytes(state,state->config->demod_address,
-					   get_ver_buf,5)) {
-				printk(KERN_WARNING "or51211:Load DVR Error 6"
-				       " - %d\n",i);
-				return -1;
-			}
-			msleep(3);
-
-			if (i2c_readbytes(state,state->config->demod_address,
-					  &rec_buf[i*2],2)) {
-				printk(KERN_WARNING "or51211:Load DVR Error 7"
-				       " - %d\n",i);
-				return -1;
-			}
-			/* If we didn't receive the right index, try again */
-			if ((int)rec_buf[i*2+1]!=i+1){
-			  i--;
-			}
-		}
-		dprintk("read_fwbits %x %x %x %x %x %x %x %x %x %x\n",
-			rec_buf[0], rec_buf[1], rec_buf[2], rec_buf[3],
-			rec_buf[4], rec_buf[5], rec_buf[6], rec_buf[7],
-			rec_buf[8], rec_buf[9]);
-
-		printk(KERN_INFO "or51211: ver TU%02x%02x%02x VSB mode %02x"
-		       " Status %02x\n",
-		       rec_buf[2], rec_buf[4],rec_buf[6],
-		       rec_buf[12],rec_buf[10]);
-
-		rec_buf[0] = 0x04;
-		rec_buf[1] = 0x00;
-		rec_buf[2] = 0x03;
-		rec_buf[3] = 0x00;
-		msleep(20);
-		if (i2c_writebytes(state,state->config->demod_address,
-				   rec_buf,3)) {
-			printk(KERN_WARNING "or51211: Load DVR Error 8\n");
-			return -1;
-		}
-		msleep(20);
-		if (i2c_readbytes(state,state->config->demod_address,
-				  &rec_buf[8],2)) {
-			printk(KERN_WARNING "or51211: Load DVR Error 9\n");
-			return -1;
-		}
-		state->initialized = 1;
-	}
-
-	return 0;
-}
-
-static int or51211_get_tune_settings(struct dvb_frontend* fe,
-				     struct dvb_frontend_tune_settings* fesettings)
-{
-	fesettings->min_delay_ms = 500;
-	fesettings->step_size = 0;
-	fesettings->max_drift = 0;
-	return 0;
-}
-
-static void or51211_release(struct dvb_frontend* fe)
-{
-	struct or51211_state* state = fe->demodulator_priv;
-	state->config->sleep(fe);
-	kfree(state);
-}
-
-static struct dvb_frontend_ops or51211_ops;
-
-struct dvb_frontend* or51211_attach(const struct or51211_config* config,
-				    struct i2c_adapter* i2c)
-{
-	struct or51211_state* state = NULL;
-
-	/* Allocate memory for the internal state */
-	state = kzalloc(sizeof(struct or51211_state), GFP_KERNEL);
-	if (state == NULL)
-		return NULL;
-
-	/* Setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->initialized = 0;
-	state->current_frequency = 0;
-
-	/* Create dvb_frontend */
-	memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-}
-
-static struct dvb_frontend_ops or51211_ops = {
-	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
-	.info = {
-		.name               = "Oren OR51211 VSB Frontend",
-		.frequency_min      = 44000000,
-		.frequency_max      = 958000000,
-		.frequency_stepsize = 166666,
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_8VSB
-	},
-
-	.release = or51211_release,
-
-	.init = or51211_init,
-	.sleep = or51211_sleep,
-
-	.set_frontend = or51211_set_parameters,
-	.get_tune_settings = or51211_get_tune_settings,
-
-	.read_status = or51211_read_status,
-	.read_ber = or51211_read_ber,
-	.read_signal_strength = or51211_read_signal_strength,
-	.read_snr = or51211_read_snr,
-	.read_ucblocks = or51211_read_ucblocks,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("Oren OR51211 VSB [pcHDTV HD-2000] Demodulator Driver");
-MODULE_AUTHOR("Kirk Lapray");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(or51211_attach);
-
diff --git a/drivers/media/dvb/frontends/or51211.h b/drivers/media/dvb/frontends/or51211.h
deleted file mode 100644
index 3ce0508..0000000
--- a/drivers/media/dvb/frontends/or51211.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *    Support for OR51211 (pcHDTV HD-2000) - VSB
- *
- *    Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
-*/
-
-#ifndef OR51211_H
-#define OR51211_H
-
-#include <linux/dvb/frontend.h>
-#include <linux/firmware.h>
-
-struct or51211_config
-{
-	/* The demodulator's i2c address */
-	u8 demod_address;
-
-	/* Request firmware for device */
-	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
-	void (*setmode)(struct dvb_frontend * fe, int mode);
-	void (*reset)(struct dvb_frontend * fe);
-	void (*sleep)(struct dvb_frontend * fe);
-};
-
-#if defined(CONFIG_DVB_OR51211) || (defined(CONFIG_DVB_OR51211_MODULE) && defined(MODULE))
-extern struct dvb_frontend* or51211_attach(const struct or51211_config* config,
-					   struct i2c_adapter* i2c);
-#else
-static inline struct dvb_frontend* or51211_attach(const struct or51211_config* config,
-					   struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_OR51211
-
-#endif // OR51211_H
-
diff --git a/drivers/media/dvb/frontends/rtl2830.c b/drivers/media/dvb/frontends/rtl2830.c
deleted file mode 100644
index 93612eb..0000000
--- a/drivers/media/dvb/frontends/rtl2830.c
+++ /dev/null
@@ -1,757 +0,0 @@
-/*
- * Realtek RTL2830 DVB-T demodulator driver
- *
- * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-
-/*
- * Driver implements own I2C-adapter for tuner I2C access. That's since chip
- * have unusual I2C-gate control which closes gate automatically after each
- * I2C transfer. Using own I2C adapter we can workaround that.
- */
-
-#include "rtl2830_priv.h"
-
-int rtl2830_debug;
-module_param_named(debug, rtl2830_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-/* write multiple hardware registers */
-static int rtl2830_wr(struct rtl2830_priv *priv, u8 reg, u8 *val, int len)
-{
-	int ret;
-	u8 buf[1+len];
-	struct i2c_msg msg[1] = {
-		{
-			.addr = priv->cfg.i2c_addr,
-			.flags = 0,
-			.len = 1+len,
-			.buf = buf,
-		}
-	};
-
-	buf[0] = reg;
-	memcpy(&buf[1], val, len);
-
-	ret = i2c_transfer(priv->i2c, msg, 1);
-	if (ret == 1) {
-		ret = 0;
-	} else {
-		warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-	return ret;
-}
-
-/* read multiple hardware registers */
-static int rtl2830_rd(struct rtl2830_priv *priv, u8 reg, u8 *val, int len)
-{
-	int ret;
-	struct i2c_msg msg[2] = {
-		{
-			.addr = priv->cfg.i2c_addr,
-			.flags = 0,
-			.len = 1,
-			.buf = &reg,
-		}, {
-			.addr = priv->cfg.i2c_addr,
-			.flags = I2C_M_RD,
-			.len = len,
-			.buf = val,
-		}
-	};
-
-	ret = i2c_transfer(priv->i2c, msg, 2);
-	if (ret == 2) {
-		ret = 0;
-	} else {
-		warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-	return ret;
-}
-
-/* write multiple registers */
-static int rtl2830_wr_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len)
-{
-	int ret;
-	u8 reg2 = (reg >> 0) & 0xff;
-	u8 page = (reg >> 8) & 0xff;
-
-	/* switch bank if needed */
-	if (page != priv->page) {
-		ret = rtl2830_wr(priv, 0x00, &page, 1);
-		if (ret)
-			return ret;
-
-		priv->page = page;
-	}
-
-	return rtl2830_wr(priv, reg2, val, len);
-}
-
-/* read multiple registers */
-static int rtl2830_rd_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len)
-{
-	int ret;
-	u8 reg2 = (reg >> 0) & 0xff;
-	u8 page = (reg >> 8) & 0xff;
-
-	/* switch bank if needed */
-	if (page != priv->page) {
-		ret = rtl2830_wr(priv, 0x00, &page, 1);
-		if (ret)
-			return ret;
-
-		priv->page = page;
-	}
-
-	return rtl2830_rd(priv, reg2, val, len);
-}
-
-#if 0 /* currently not used */
-/* write single register */
-static int rtl2830_wr_reg(struct rtl2830_priv *priv, u16 reg, u8 val)
-{
-	return rtl2830_wr_regs(priv, reg, &val, 1);
-}
-#endif
-
-/* read single register */
-static int rtl2830_rd_reg(struct rtl2830_priv *priv, u16 reg, u8 *val)
-{
-	return rtl2830_rd_regs(priv, reg, val, 1);
-}
-
-/* write single register with mask */
-int rtl2830_wr_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 val, u8 mask)
-{
-	int ret;
-	u8 tmp;
-
-	/* no need for read if whole reg is written */
-	if (mask != 0xff) {
-		ret = rtl2830_rd_regs(priv, reg, &tmp, 1);
-		if (ret)
-			return ret;
-
-		val &= mask;
-		tmp &= ~mask;
-		val |= tmp;
-	}
-
-	return rtl2830_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register with mask */
-int rtl2830_rd_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 *val, u8 mask)
-{
-	int ret, i;
-	u8 tmp;
-
-	ret = rtl2830_rd_regs(priv, reg, &tmp, 1);
-	if (ret)
-		return ret;
-
-	tmp &= mask;
-
-	/* find position of the first bit */
-	for (i = 0; i < 8; i++) {
-		if ((mask >> i) & 0x01)
-			break;
-	}
-	*val = tmp >> i;
-
-	return 0;
-}
-
-static int rtl2830_init(struct dvb_frontend *fe)
-{
-	struct rtl2830_priv *priv = fe->demodulator_priv;
-	int ret, i;
-	u64 num;
-	u8 buf[3], tmp;
-	u32 if_ctl;
-	struct rtl2830_reg_val_mask tab[] = {
-		{ 0x00d, 0x01, 0x03 },
-		{ 0x00d, 0x10, 0x10 },
-		{ 0x104, 0x00, 0x1e },
-		{ 0x105, 0x80, 0x80 },
-		{ 0x110, 0x02, 0x03 },
-		{ 0x110, 0x08, 0x0c },
-		{ 0x17b, 0x00, 0x40 },
-		{ 0x17d, 0x05, 0x0f },
-		{ 0x17d, 0x50, 0xf0 },
-		{ 0x18c, 0x08, 0x0f },
-		{ 0x18d, 0x00, 0xc0 },
-		{ 0x188, 0x05, 0x0f },
-		{ 0x189, 0x00, 0xfc },
-		{ 0x2d5, 0x02, 0x02 },
-		{ 0x2f1, 0x02, 0x06 },
-		{ 0x2f1, 0x20, 0xf8 },
-		{ 0x16d, 0x00, 0x01 },
-		{ 0x1a6, 0x00, 0x80 },
-		{ 0x106, priv->cfg.vtop, 0x3f },
-		{ 0x107, priv->cfg.krf, 0x3f },
-		{ 0x112, 0x28, 0xff },
-		{ 0x103, priv->cfg.agc_targ_val, 0xff },
-		{ 0x00a, 0x02, 0x07 },
-		{ 0x140, 0x0c, 0x3c },
-		{ 0x140, 0x40, 0xc0 },
-		{ 0x15b, 0x05, 0x07 },
-		{ 0x15b, 0x28, 0x38 },
-		{ 0x15c, 0x05, 0x07 },
-		{ 0x15c, 0x28, 0x38 },
-		{ 0x115, priv->cfg.spec_inv, 0x01 },
-		{ 0x16f, 0x01, 0x07 },
-		{ 0x170, 0x18, 0x38 },
-		{ 0x172, 0x0f, 0x0f },
-		{ 0x173, 0x08, 0x38 },
-		{ 0x175, 0x01, 0x07 },
-		{ 0x176, 0x00, 0xc0 },
-	};
-
-	for (i = 0; i < ARRAY_SIZE(tab); i++) {
-		ret = rtl2830_wr_reg_mask(priv, tab[i].reg, tab[i].val,
-			tab[i].mask);
-		if (ret)
-			goto err;
-	}
-
-	ret = rtl2830_wr_regs(priv, 0x18f, "\x28\x00", 2);
-	if (ret)
-		goto err;
-
-	ret = rtl2830_wr_regs(priv, 0x195,
-		"\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8);
-	if (ret)
-		goto err;
-
-	num = priv->cfg.if_dvbt % priv->cfg.xtal;
-	num *= 0x400000;
-	num = div_u64(num, priv->cfg.xtal);
-	num = -num;
-	if_ctl = num & 0x3fffff;
-	dbg("%s: if_ctl=%08x", __func__, if_ctl);
-
-	ret = rtl2830_rd_reg_mask(priv, 0x119, &tmp, 0xc0); /* b[7:6] */
-	if (ret)
-		goto err;
-
-	buf[0] = tmp << 6;
-	buf[0] = (if_ctl >> 16) & 0x3f;
-	buf[1] = (if_ctl >>  8) & 0xff;
-	buf[2] = (if_ctl >>  0) & 0xff;
-
-	ret = rtl2830_wr_regs(priv, 0x119, buf, 3);
-	if (ret)
-		goto err;
-
-	/* TODO: spec init */
-
-	/* soft reset */
-	ret = rtl2830_wr_reg_mask(priv, 0x101, 0x04, 0x04);
-	if (ret)
-		goto err;
-
-	ret = rtl2830_wr_reg_mask(priv, 0x101, 0x00, 0x04);
-	if (ret)
-		goto err;
-
-	priv->sleeping = false;
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int rtl2830_sleep(struct dvb_frontend *fe)
-{
-	struct rtl2830_priv *priv = fe->demodulator_priv;
-	priv->sleeping = true;
-	return 0;
-}
-
-int rtl2830_get_tune_settings(struct dvb_frontend *fe,
-	struct dvb_frontend_tune_settings *s)
-{
-	s->min_delay_ms = 500;
-	s->step_size = fe->ops.info.frequency_stepsize * 2;
-	s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
-
-	return 0;
-}
-
-static int rtl2830_set_frontend(struct dvb_frontend *fe)
-{
-	struct rtl2830_priv *priv = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret, i;
-	static u8 bw_params1[3][34] = {
-		{
-		0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xfa, 0x00, 0x17, 0x00, 0x41,
-		0x00, 0x64, 0x00, 0x67, 0x00, 0x38, 0x1f, 0xde, 0x1f, 0x7a,
-		0x1f, 0x47, 0x1f, 0x7c, 0x00, 0x30, 0x01, 0x4b, 0x02, 0x82,
-		0x03, 0x73, 0x03, 0xcf, /* 6 MHz */
-		}, {
-		0x1f, 0xfa, 0x1f, 0xda, 0x1f, 0xc1, 0x1f, 0xb3, 0x1f, 0xca,
-		0x00, 0x07, 0x00, 0x4d, 0x00, 0x6d, 0x00, 0x40, 0x1f, 0xca,
-		0x1f, 0x4d, 0x1f, 0x2a, 0x1f, 0xb2, 0x00, 0xec, 0x02, 0x7e,
-		0x03, 0xd0, 0x04, 0x53, /* 7 MHz */
-		}, {
-		0x00, 0x10, 0x00, 0x0e, 0x1f, 0xf7, 0x1f, 0xc9, 0x1f, 0xa0,
-		0x1f, 0xa6, 0x1f, 0xec, 0x00, 0x4e, 0x00, 0x7d, 0x00, 0x3a,
-		0x1f, 0x98, 0x1f, 0x10, 0x1f, 0x40, 0x00, 0x75, 0x02, 0x5f,
-		0x04, 0x24, 0x04, 0xdb, /* 8 MHz */
-		},
-	};
-	static u8 bw_params2[3][6] = {
-		{0xc3, 0x0c, 0x44, 0x33, 0x33, 0x30,}, /* 6 MHz */
-		{0xb8, 0xe3, 0x93, 0x99, 0x99, 0x98,}, /* 7 MHz */
-		{0xae, 0xba, 0xf3, 0x26, 0x66, 0x64,}, /* 8 MHz */
-	};
-
-
-	dbg("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__,
-		c->frequency, c->bandwidth_hz, c->inversion);
-
-	/* program tuner */
-	if (fe->ops.tuner_ops.set_params)
-		fe->ops.tuner_ops.set_params(fe);
-
-	switch (c->bandwidth_hz) {
-	case 6000000:
-		i = 0;
-		break;
-	case 7000000:
-		i = 1;
-		break;
-	case 8000000:
-		i = 2;
-		break;
-	default:
-		dbg("invalid bandwidth");
-		return -EINVAL;
-	}
-
-	ret = rtl2830_wr_reg_mask(priv, 0x008, i << 1, 0x06);
-	if (ret)
-		goto err;
-
-	/* 1/2 split I2C write */
-	ret = rtl2830_wr_regs(priv, 0x11c, &bw_params1[i][0], 17);
-	if (ret)
-		goto err;
-
-	/* 2/2 split I2C write */
-	ret = rtl2830_wr_regs(priv, 0x12d, &bw_params1[i][17], 17);
-	if (ret)
-		goto err;
-
-	ret = rtl2830_wr_regs(priv, 0x19d, bw_params2[i], 6);
-	if (ret)
-		goto err;
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int rtl2830_get_frontend(struct dvb_frontend *fe)
-{
-	struct rtl2830_priv *priv = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret;
-	u8 buf[3];
-
-	if (priv->sleeping)
-		return 0;
-
-	ret = rtl2830_rd_regs(priv, 0x33c, buf, 2);
-	if (ret)
-		goto err;
-
-	ret = rtl2830_rd_reg(priv, 0x351, &buf[2]);
-	if (ret)
-		goto err;
-
-	dbg("%s: TPS=%02x %02x %02x", __func__, buf[0], buf[1], buf[2]);
-
-	switch ((buf[0] >> 2) & 3) {
-	case 0:
-		c->modulation = QPSK;
-		break;
-	case 1:
-		c->modulation = QAM_16;
-		break;
-	case 2:
-		c->modulation = QAM_64;
-		break;
-	}
-
-	switch ((buf[2] >> 2) & 1) {
-	case 0:
-		c->transmission_mode = TRANSMISSION_MODE_2K;
-		break;
-	case 1:
-		c->transmission_mode = TRANSMISSION_MODE_8K;
-	}
-
-	switch ((buf[2] >> 0) & 3) {
-	case 0:
-		c->guard_interval = GUARD_INTERVAL_1_32;
-		break;
-	case 1:
-		c->guard_interval = GUARD_INTERVAL_1_16;
-		break;
-	case 2:
-		c->guard_interval = GUARD_INTERVAL_1_8;
-		break;
-	case 3:
-		c->guard_interval = GUARD_INTERVAL_1_4;
-		break;
-	}
-
-	switch ((buf[0] >> 4) & 7) {
-	case 0:
-		c->hierarchy = HIERARCHY_NONE;
-		break;
-	case 1:
-		c->hierarchy = HIERARCHY_1;
-		break;
-	case 2:
-		c->hierarchy = HIERARCHY_2;
-		break;
-	case 3:
-		c->hierarchy = HIERARCHY_4;
-		break;
-	}
-
-	switch ((buf[1] >> 3) & 7) {
-	case 0:
-		c->code_rate_HP = FEC_1_2;
-		break;
-	case 1:
-		c->code_rate_HP = FEC_2_3;
-		break;
-	case 2:
-		c->code_rate_HP = FEC_3_4;
-		break;
-	case 3:
-		c->code_rate_HP = FEC_5_6;
-		break;
-	case 4:
-		c->code_rate_HP = FEC_7_8;
-		break;
-	}
-
-	switch ((buf[1] >> 0) & 7) {
-	case 0:
-		c->code_rate_LP = FEC_1_2;
-		break;
-	case 1:
-		c->code_rate_LP = FEC_2_3;
-		break;
-	case 2:
-		c->code_rate_LP = FEC_3_4;
-		break;
-	case 3:
-		c->code_rate_LP = FEC_5_6;
-		break;
-	case 4:
-		c->code_rate_LP = FEC_7_8;
-		break;
-	}
-
-	return 0;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct rtl2830_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 tmp;
-	*status = 0;
-
-	if (priv->sleeping)
-		return 0;
-
-	ret = rtl2830_rd_reg_mask(priv, 0x351, &tmp, 0x78); /* [6:3] */
-	if (ret)
-		goto err;
-
-	if (tmp == 11) {
-		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-			FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
-	} else if (tmp == 10) {
-		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-			FE_HAS_VITERBI;
-	}
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct rtl2830_priv *priv = fe->demodulator_priv;
-	int ret, hierarchy, constellation;
-	u8 buf[2], tmp;
-	u16 tmp16;
-#define CONSTELLATION_NUM 3
-#define HIERARCHY_NUM 4
-	static const u32 snr_constant[CONSTELLATION_NUM][HIERARCHY_NUM] = {
-		{ 70705899, 70705899, 70705899, 70705899 },
-		{ 82433173, 82433173, 87483115, 94445660 },
-		{ 92888734, 92888734, 95487525, 99770748 },
-	};
-
-	if (priv->sleeping)
-		return 0;
-
-	/* reports SNR in resolution of 0.1 dB */
-
-	ret = rtl2830_rd_reg(priv, 0x33c, &tmp);
-	if (ret)
-		goto err;
-
-	constellation = (tmp >> 2) & 0x03; /* [3:2] */
-	if (constellation > CONSTELLATION_NUM - 1)
-		goto err;
-
-	hierarchy = (tmp >> 4) & 0x07; /* [6:4] */
-	if (hierarchy > HIERARCHY_NUM - 1)
-		goto err;
-
-	ret = rtl2830_rd_regs(priv, 0x40c, buf, 2);
-	if (ret)
-		goto err;
-
-	tmp16 = buf[0] << 8 | buf[1];
-
-	if (tmp16)
-		*snr = (snr_constant[constellation][hierarchy] -
-				intlog10(tmp16)) / ((1 << 24) / 100);
-	else
-		*snr = 0;
-
-	return 0;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct rtl2830_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 buf[2];
-
-	if (priv->sleeping)
-		return 0;
-
-	ret = rtl2830_rd_regs(priv, 0x34e, buf, 2);
-	if (ret)
-		goto err;
-
-	*ber = buf[0] << 8 | buf[1];
-
-	return 0;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	*ucblocks = 0;
-	return 0;
-}
-
-static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct rtl2830_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 buf[2];
-	u16 if_agc_raw, if_agc;
-
-	if (priv->sleeping)
-		return 0;
-
-	ret = rtl2830_rd_regs(priv, 0x359, buf, 2);
-	if (ret)
-		goto err;
-
-	if_agc_raw = (buf[0] << 8 | buf[1]) & 0x3fff;
-
-	if (if_agc_raw & (1 << 9))
-		if_agc = -(~(if_agc_raw - 1) & 0x1ff);
-	else
-		if_agc = if_agc_raw;
-
-	*strength = (u8) (55 - if_agc / 182);
-	*strength |= *strength << 8;
-
-	return 0;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static struct dvb_frontend_ops rtl2830_ops;
-
-static u32 rtl2830_tuner_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static int rtl2830_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
-	struct i2c_msg msg[], int num)
-{
-	struct rtl2830_priv *priv = i2c_get_adapdata(i2c_adap);
-	int ret;
-
-	/* open i2c-gate */
-	ret = rtl2830_wr_reg_mask(priv, 0x101, 0x08, 0x08);
-	if (ret)
-		goto err;
-
-	ret = i2c_transfer(priv->i2c, msg, num);
-	if (ret < 0)
-		warn("tuner i2c failed=%d", ret);
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static struct i2c_algorithm rtl2830_tuner_i2c_algo = {
-	.master_xfer   = rtl2830_tuner_i2c_xfer,
-	.functionality = rtl2830_tuner_i2c_func,
-};
-
-struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(struct dvb_frontend *fe)
-{
-	struct rtl2830_priv *priv = fe->demodulator_priv;
-	return &priv->tuner_i2c_adapter;
-}
-EXPORT_SYMBOL(rtl2830_get_tuner_i2c_adapter);
-
-static void rtl2830_release(struct dvb_frontend *fe)
-{
-	struct rtl2830_priv *priv = fe->demodulator_priv;
-
-	i2c_del_adapter(&priv->tuner_i2c_adapter);
-	kfree(priv);
-}
-
-struct dvb_frontend *rtl2830_attach(const struct rtl2830_config *cfg,
-	struct i2c_adapter *i2c)
-{
-	struct rtl2830_priv *priv = NULL;
-	int ret = 0;
-	u8 tmp;
-
-	/* allocate memory for the internal state */
-	priv = kzalloc(sizeof(struct rtl2830_priv), GFP_KERNEL);
-	if (priv == NULL)
-		goto err;
-
-	/* setup the priv */
-	priv->i2c = i2c;
-	memcpy(&priv->cfg, cfg, sizeof(struct rtl2830_config));
-
-	/* check if the demod is there */
-	ret = rtl2830_rd_reg(priv, 0x000, &tmp);
-	if (ret)
-		goto err;
-
-	/* create dvb_frontend */
-	memcpy(&priv->fe.ops, &rtl2830_ops, sizeof(struct dvb_frontend_ops));
-	priv->fe.demodulator_priv = priv;
-
-	/* create tuner i2c adapter */
-	strlcpy(priv->tuner_i2c_adapter.name, "RTL2830 tuner I2C adapter",
-		sizeof(priv->tuner_i2c_adapter.name));
-	priv->tuner_i2c_adapter.algo = &rtl2830_tuner_i2c_algo;
-	priv->tuner_i2c_adapter.algo_data = NULL;
-	i2c_set_adapdata(&priv->tuner_i2c_adapter, priv);
-	if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) {
-		err("tuner I2C bus could not be initialized");
-		goto err;
-	}
-
-	priv->sleeping = true;
-
-	return &priv->fe;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	kfree(priv);
-	return NULL;
-}
-EXPORT_SYMBOL(rtl2830_attach);
-
-static struct dvb_frontend_ops rtl2830_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name = "Realtek RTL2830 (DVB-T)",
-		.caps = FE_CAN_FEC_1_2 |
-			FE_CAN_FEC_2_3 |
-			FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 |
-			FE_CAN_FEC_7_8 |
-			FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK |
-			FE_CAN_QAM_16 |
-			FE_CAN_QAM_64 |
-			FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_HIERARCHY_AUTO |
-			FE_CAN_RECOVER |
-			FE_CAN_MUTE_TS
-	},
-
-	.release = rtl2830_release,
-
-	.init = rtl2830_init,
-	.sleep = rtl2830_sleep,
-
-	.get_tune_settings = rtl2830_get_tune_settings,
-
-	.set_frontend = rtl2830_set_frontend,
-	.get_frontend = rtl2830_get_frontend,
-
-	.read_status = rtl2830_read_status,
-	.read_snr = rtl2830_read_snr,
-	.read_ber = rtl2830_read_ber,
-	.read_ucblocks = rtl2830_read_ucblocks,
-	.read_signal_strength = rtl2830_read_signal_strength,
-};
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/rtl2830.h b/drivers/media/dvb/frontends/rtl2830.h
deleted file mode 100644
index 1c6ee91..0000000
--- a/drivers/media/dvb/frontends/rtl2830.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Realtek RTL2830 DVB-T demodulator driver
- *
- * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef RTL2830_H
-#define RTL2830_H
-
-#include <linux/dvb/frontend.h>
-
-struct rtl2830_config {
-	/*
-	 * Demodulator I2C address.
-	 */
-	u8 i2c_addr;
-
-	/*
-	 * Xtal frequency.
-	 * Hz
-	 * 4000000, 16000000, 25000000, 28800000
-	 */
-	u32 xtal;
-
-	/*
-	 * TS output mode.
-	 */
-	u8 ts_mode;
-
-	/*
-	 * Spectrum inversion.
-	 */
-	bool spec_inv;
-
-	/*
-	 * IFs for all used modes.
-	 * Hz
-	 * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000
-	 */
-	u32 if_dvbt;
-
-	/*
-	 */
-	u8 vtop;
-
-	/*
-	 */
-	u8 krf;
-
-	/*
-	 */
-	u8 agc_targ_val;
-};
-
-#if defined(CONFIG_DVB_RTL2830) || \
-	(defined(CONFIG_DVB_RTL2830_MODULE) && defined(MODULE))
-extern struct dvb_frontend *rtl2830_attach(
-	const struct rtl2830_config *config,
-	struct i2c_adapter *i2c
-);
-
-extern struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(
-	struct dvb_frontend *fe
-);
-#else
-static inline struct dvb_frontend *rtl2830_attach(
-	const struct rtl2830_config *config,
-	struct i2c_adapter *i2c
-)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(
-	struct dvb_frontend *fe
-)
-{
-	return NULL;
-}
-#endif
-
-#endif /* RTL2830_H */
diff --git a/drivers/media/dvb/frontends/rtl2830_priv.h b/drivers/media/dvb/frontends/rtl2830_priv.h
deleted file mode 100644
index 9b20557..0000000
--- a/drivers/media/dvb/frontends/rtl2830_priv.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Realtek RTL2830 DVB-T demodulator driver
- *
- * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef RTL2830_PRIV_H
-#define RTL2830_PRIV_H
-
-#include "dvb_frontend.h"
-#include "dvb_math.h"
-#include "rtl2830.h"
-
-#define LOG_PREFIX "rtl2830"
-
-#undef dbg
-#define dbg(f, arg...) \
-	if (rtl2830_debug) \
-		printk(KERN_INFO            LOG_PREFIX": " f "\n" , ## arg)
-#undef err
-#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
-#undef info
-#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
-#undef warn
-#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
-
-struct rtl2830_priv {
-	struct i2c_adapter *i2c;
-	struct dvb_frontend fe;
-	struct rtl2830_config cfg;
-	struct i2c_adapter tuner_i2c_adapter;
-
-	bool sleeping;
-
-	u8 page; /* active register page */
-};
-
-struct rtl2830_reg_val_mask {
-	u16 reg;
-	u8  val;
-	u8  mask;
-};
-
-#endif /* RTL2830_PRIV_H */
diff --git a/drivers/media/dvb/frontends/rtl2832.c b/drivers/media/dvb/frontends/rtl2832.c
deleted file mode 100644
index 28269cc..0000000
--- a/drivers/media/dvb/frontends/rtl2832.c
+++ /dev/null
@@ -1,789 +0,0 @@
-/*
- * Realtek RTL2832 DVB-T demodulator driver
- *
- * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
- *
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
- *
- *	You should have received a copy of the GNU General Public License along
- *	with this program; if not, write to the Free Software Foundation, Inc.,
- *	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "rtl2832_priv.h"
-#include <linux/bitops.h>
-
-int rtl2832_debug;
-module_param_named(debug, rtl2832_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-#define REG_MASK(b) (BIT(b + 1) - 1)
-
-static const struct rtl2832_reg_entry registers[] = {
-	[DVBT_SOFT_RST]		= {0x1, 0x1,   2, 2},
-	[DVBT_IIC_REPEAT]	= {0x1, 0x1,   3, 3},
-	[DVBT_TR_WAIT_MIN_8K]	= {0x1, 0x88, 11, 2},
-	[DVBT_RSD_BER_FAIL_VAL]	= {0x1, 0x8f, 15, 0},
-	[DVBT_EN_BK_TRK]	= {0x1, 0xa6,  7, 7},
-	[DVBT_AD_EN_REG]	= {0x0, 0x8,   7, 7},
-	[DVBT_AD_EN_REG1]	= {0x0, 0x8,   6, 6},
-	[DVBT_EN_BBIN]		= {0x1, 0xb1,  0, 0},
-	[DVBT_MGD_THD0]		= {0x1, 0x95,  7, 0},
-	[DVBT_MGD_THD1]		= {0x1, 0x96,  7, 0},
-	[DVBT_MGD_THD2]		= {0x1, 0x97,  7, 0},
-	[DVBT_MGD_THD3]		= {0x1, 0x98,  7, 0},
-	[DVBT_MGD_THD4]		= {0x1, 0x99,  7, 0},
-	[DVBT_MGD_THD5]		= {0x1, 0x9a,  7, 0},
-	[DVBT_MGD_THD6]		= {0x1, 0x9b,  7, 0},
-	[DVBT_MGD_THD7]		= {0x1, 0x9c,  7, 0},
-	[DVBT_EN_CACQ_NOTCH]	= {0x1, 0x61,  4, 4},
-	[DVBT_AD_AV_REF]	= {0x0, 0x9,   6, 0},
-	[DVBT_REG_PI]		= {0x0, 0xa,   2, 0},
-	[DVBT_PIP_ON]		= {0x0, 0x21,  3, 3},
-	[DVBT_SCALE1_B92]	= {0x2, 0x92,  7, 0},
-	[DVBT_SCALE1_B93]	= {0x2, 0x93,  7, 0},
-	[DVBT_SCALE1_BA7]	= {0x2, 0xa7,  7, 0},
-	[DVBT_SCALE1_BA9]	= {0x2, 0xa9,  7, 0},
-	[DVBT_SCALE1_BAA]	= {0x2, 0xaa,  7, 0},
-	[DVBT_SCALE1_BAB]	= {0x2, 0xab,  7, 0},
-	[DVBT_SCALE1_BAC]	= {0x2, 0xac,  7, 0},
-	[DVBT_SCALE1_BB0]	= {0x2, 0xb0,  7, 0},
-	[DVBT_SCALE1_BB1]	= {0x2, 0xb1,  7, 0},
-	[DVBT_KB_P1]		= {0x1, 0x64,  3, 1},
-	[DVBT_KB_P2]		= {0x1, 0x64,  6, 4},
-	[DVBT_KB_P3]		= {0x1, 0x65,  2, 0},
-	[DVBT_OPT_ADC_IQ]	= {0x0, 0x6,   5, 4},
-	[DVBT_AD_AVI]		= {0x0, 0x9,   1, 0},
-	[DVBT_AD_AVQ]		= {0x0, 0x9,   3, 2},
-	[DVBT_K1_CR_STEP12]	= {0x2, 0xad,  9, 4},
-	[DVBT_TRK_KS_P2]	= {0x1, 0x6f,  2, 0},
-	[DVBT_TRK_KS_I2]	= {0x1, 0x70,  5, 3},
-	[DVBT_TR_THD_SET2]	= {0x1, 0x72,  3, 0},
-	[DVBT_TRK_KC_P2]	= {0x1, 0x73,  5, 3},
-	[DVBT_TRK_KC_I2]	= {0x1, 0x75,  2, 0},
-	[DVBT_CR_THD_SET2]	= {0x1, 0x76,  7, 6},
-	[DVBT_PSET_IFFREQ]	= {0x1, 0x19, 21, 0},
-	[DVBT_SPEC_INV]		= {0x1, 0x15,  0, 0},
-	[DVBT_RSAMP_RATIO]	= {0x1, 0x9f, 27, 2},
-	[DVBT_CFREQ_OFF_RATIO]	= {0x1, 0x9d, 23, 4},
-	[DVBT_FSM_STAGE]	= {0x3, 0x51,  6, 3},
-	[DVBT_RX_CONSTEL]	= {0x3, 0x3c,  3, 2},
-	[DVBT_RX_HIER]		= {0x3, 0x3c,  6, 4},
-	[DVBT_RX_C_RATE_LP]	= {0x3, 0x3d,  2, 0},
-	[DVBT_RX_C_RATE_HP]	= {0x3, 0x3d,  5, 3},
-	[DVBT_GI_IDX]		= {0x3, 0x51,  1, 0},
-	[DVBT_FFT_MODE_IDX]	= {0x3, 0x51,  2, 2},
-	[DVBT_RSD_BER_EST]	= {0x3, 0x4e, 15, 0},
-	[DVBT_CE_EST_EVM]	= {0x4, 0xc,  15, 0},
-	[DVBT_RF_AGC_VAL]	= {0x3, 0x5b, 13, 0},
-	[DVBT_IF_AGC_VAL]	= {0x3, 0x59, 13, 0},
-	[DVBT_DAGC_VAL]		= {0x3, 0x5,   7, 0},
-	[DVBT_SFREQ_OFF]	= {0x3, 0x18, 13, 0},
-	[DVBT_CFREQ_OFF]	= {0x3, 0x5f, 17, 0},
-	[DVBT_POLAR_RF_AGC]	= {0x0, 0xe,   1, 1},
-	[DVBT_POLAR_IF_AGC]	= {0x0, 0xe,   0, 0},
-	[DVBT_AAGC_HOLD]	= {0x1, 0x4,   5, 5},
-	[DVBT_EN_RF_AGC]	= {0x1, 0x4,   6, 6},
-	[DVBT_EN_IF_AGC]	= {0x1, 0x4,   7, 7},
-	[DVBT_IF_AGC_MIN]	= {0x1, 0x8,   7, 0},
-	[DVBT_IF_AGC_MAX]	= {0x1, 0x9,   7, 0},
-	[DVBT_RF_AGC_MIN]	= {0x1, 0xa,   7, 0},
-	[DVBT_RF_AGC_MAX]	= {0x1, 0xb,   7, 0},
-	[DVBT_IF_AGC_MAN]	= {0x1, 0xc,   6, 6},
-	[DVBT_IF_AGC_MAN_VAL]	= {0x1, 0xc,  13, 0},
-	[DVBT_RF_AGC_MAN]	= {0x1, 0xe,   6, 6},
-	[DVBT_RF_AGC_MAN_VAL]	= {0x1, 0xe,  13, 0},
-	[DVBT_DAGC_TRG_VAL]	= {0x1, 0x12,  7, 0},
-	[DVBT_AGC_TARG_VAL_0]	= {0x1, 0x2,   0, 0},
-	[DVBT_AGC_TARG_VAL_8_1]	= {0x1, 0x3,   7, 0},
-	[DVBT_AAGC_LOOP_GAIN]	= {0x1, 0xc7,  5, 1},
-	[DVBT_LOOP_GAIN2_3_0]	= {0x1, 0x4,   4, 1},
-	[DVBT_LOOP_GAIN2_4]	= {0x1, 0x5,   7, 7},
-	[DVBT_LOOP_GAIN3]	= {0x1, 0xc8,  4, 0},
-	[DVBT_VTOP1]		= {0x1, 0x6,   5, 0},
-	[DVBT_VTOP2]		= {0x1, 0xc9,  5, 0},
-	[DVBT_VTOP3]		= {0x1, 0xca,  5, 0},
-	[DVBT_KRF1]		= {0x1, 0xcb,  7, 0},
-	[DVBT_KRF2]		= {0x1, 0x7,   7, 0},
-	[DVBT_KRF3]		= {0x1, 0xcd,  7, 0},
-	[DVBT_KRF4]		= {0x1, 0xce,  7, 0},
-	[DVBT_EN_GI_PGA]	= {0x1, 0xe5,  0, 0},
-	[DVBT_THD_LOCK_UP]	= {0x1, 0xd9,  8, 0},
-	[DVBT_THD_LOCK_DW]	= {0x1, 0xdb,  8, 0},
-	[DVBT_THD_UP1]		= {0x1, 0xdd,  7, 0},
-	[DVBT_THD_DW1]		= {0x1, 0xde,  7, 0},
-	[DVBT_INTER_CNT_LEN]	= {0x1, 0xd8,  3, 0},
-	[DVBT_GI_PGA_STATE]	= {0x1, 0xe6,  3, 3},
-	[DVBT_EN_AGC_PGA]	= {0x1, 0xd7,  0, 0},
-	[DVBT_CKOUTPAR]		= {0x1, 0x7b,  5, 5},
-	[DVBT_CKOUT_PWR]	= {0x1, 0x7b,  6, 6},
-	[DVBT_SYNC_DUR]		= {0x1, 0x7b,  7, 7},
-	[DVBT_ERR_DUR]		= {0x1, 0x7c,  0, 0},
-	[DVBT_SYNC_LVL]		= {0x1, 0x7c,  1, 1},
-	[DVBT_ERR_LVL]		= {0x1, 0x7c,  2, 2},
-	[DVBT_VAL_LVL]		= {0x1, 0x7c,  3, 3},
-	[DVBT_SERIAL]		= {0x1, 0x7c,  4, 4},
-	[DVBT_SER_LSB]		= {0x1, 0x7c,  5, 5},
-	[DVBT_CDIV_PH0]		= {0x1, 0x7d,  3, 0},
-	[DVBT_CDIV_PH1]		= {0x1, 0x7d,  7, 4},
-	[DVBT_MPEG_IO_OPT_2_2]	= {0x0, 0x6,   7, 7},
-	[DVBT_MPEG_IO_OPT_1_0]	= {0x0, 0x7,   7, 6},
-	[DVBT_CKOUTPAR_PIP]	= {0x0, 0xb7,  4, 4},
-	[DVBT_CKOUT_PWR_PIP]	= {0x0, 0xb7,  3, 3},
-	[DVBT_SYNC_LVL_PIP]	= {0x0, 0xb7,  2, 2},
-	[DVBT_ERR_LVL_PIP]	= {0x0, 0xb7,  1, 1},
-	[DVBT_VAL_LVL_PIP]	= {0x0, 0xb7,  0, 0},
-	[DVBT_CKOUTPAR_PID]	= {0x0, 0xb9,  4, 4},
-	[DVBT_CKOUT_PWR_PID]	= {0x0, 0xb9,  3, 3},
-	[DVBT_SYNC_LVL_PID]	= {0x0, 0xb9,  2, 2},
-	[DVBT_ERR_LVL_PID]	= {0x0, 0xb9,  1, 1},
-	[DVBT_VAL_LVL_PID]	= {0x0, 0xb9,  0, 0},
-	[DVBT_SM_PASS]		= {0x1, 0x93, 11, 0},
-	[DVBT_AD7_SETTING]	= {0x0, 0x11, 15, 0},
-	[DVBT_RSSI_R]		= {0x3, 0x1,   6, 0},
-	[DVBT_ACI_DET_IND]	= {0x3, 0x12,  0, 0},
-	[DVBT_REG_MON]		= {0x0, 0xd,   1, 0},
-	[DVBT_REG_MONSEL]	= {0x0, 0xd,   2, 2},
-	[DVBT_REG_GPE]		= {0x0, 0xd,   7, 7},
-	[DVBT_REG_GPO]		= {0x0, 0x10,  0, 0},
-	[DVBT_REG_4MSEL]	= {0x0, 0x13,  0, 0},
-};
-
-/* write multiple hardware registers */
-static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
-{
-	int ret;
-	u8 buf[1+len];
-	struct i2c_msg msg[1] = {
-		{
-			.addr = priv->cfg.i2c_addr,
-			.flags = 0,
-			.len = 1+len,
-			.buf = buf,
-		}
-	};
-
-	buf[0] = reg;
-	memcpy(&buf[1], val, len);
-
-	ret = i2c_transfer(priv->i2c, msg, 1);
-	if (ret == 1) {
-		ret = 0;
-	} else {
-		warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-	return ret;
-}
-
-/* read multiple hardware registers */
-static int rtl2832_rd(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
-{
-	int ret;
-	struct i2c_msg msg[2] = {
-		{
-			.addr = priv->cfg.i2c_addr,
-			.flags = 0,
-			.len = 1,
-			.buf = &reg,
-		}, {
-			.addr = priv->cfg.i2c_addr,
-			.flags = I2C_M_RD,
-			.len = len,
-			.buf = val,
-		}
-	};
-
-	ret = i2c_transfer(priv->i2c, msg, 2);
-	if (ret == 2) {
-		ret = 0;
-	} else {
-		warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
-		ret = -EREMOTEIO;
-}
-return ret;
-}
-
-/* write multiple registers */
-static int rtl2832_wr_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val,
-	int len)
-{
-	int ret;
-
-
-	/* switch bank if needed */
-	if (page != priv->page) {
-		ret = rtl2832_wr(priv, 0x00, &page, 1);
-		if (ret)
-			return ret;
-
-		priv->page = page;
-}
-
-return rtl2832_wr(priv, reg, val, len);
-}
-
-/* read multiple registers */
-static int rtl2832_rd_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val,
-	int len)
-{
-	int ret;
-
-	/* switch bank if needed */
-	if (page != priv->page) {
-		ret = rtl2832_wr(priv, 0x00, &page, 1);
-		if (ret)
-			return ret;
-
-		priv->page = page;
-	}
-
-	return rtl2832_rd(priv, reg, val, len);
-}
-
-#if 0 /* currently not used */
-/* write single register */
-static int rtl2832_wr_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 val)
-{
-	return rtl2832_wr_regs(priv, reg, page, &val, 1);
-}
-#endif
-
-/* read single register */
-static int rtl2832_rd_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val)
-{
-	return rtl2832_rd_regs(priv, reg, page, val, 1);
-}
-
-int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val)
-{
-	int ret;
-
-	u8 reg_start_addr;
-	u8 msb, lsb;
-	u8 page;
-	u8 reading[4];
-	u32 reading_tmp;
-	int i;
-
-	u8 len;
-	u32 mask;
-
-	reg_start_addr = registers[reg].start_address;
-	msb = registers[reg].msb;
-	lsb = registers[reg].lsb;
-	page = registers[reg].page;
-
-	len = (msb >> 3) + 1;
-	mask = REG_MASK(msb - lsb);
-
-	ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
-	if (ret)
-		goto err;
-
-	reading_tmp = 0;
-	for (i = 0; i < len; i++)
-		reading_tmp |= reading[i] << ((len - 1 - i) * 8);
-
-	*val = (reading_tmp >> lsb) & mask;
-
-	return ret;
-
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-
-}
-
-int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val)
-{
-	int ret, i;
-	u8 len;
-	u8 reg_start_addr;
-	u8 msb, lsb;
-	u8 page;
-	u32 mask;
-
-
-	u8 reading[4];
-	u8 writing[4];
-	u32 reading_tmp;
-	u32 writing_tmp;
-
-
-	reg_start_addr = registers[reg].start_address;
-	msb = registers[reg].msb;
-	lsb = registers[reg].lsb;
-	page = registers[reg].page;
-
-	len = (msb >> 3) + 1;
-	mask = REG_MASK(msb - lsb);
-
-
-	ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
-	if (ret)
-		goto err;
-
-	reading_tmp = 0;
-	for (i = 0; i < len; i++)
-		reading_tmp |= reading[i] << ((len - 1 - i) * 8);
-
-	writing_tmp = reading_tmp & ~(mask << lsb);
-	writing_tmp |= ((val & mask) << lsb);
-
-
-	for (i = 0; i < len; i++)
-		writing[i] = (writing_tmp >> ((len - 1 - i) * 8)) & 0xff;
-
-	ret = rtl2832_wr_regs(priv, reg_start_addr, page, &writing[0], len);
-	if (ret)
-		goto err;
-
-	return ret;
-
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-
-}
-
-
-static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	int ret;
-	struct rtl2832_priv *priv = fe->demodulator_priv;
-
-	dbg("%s: enable=%d", __func__, enable);
-
-	/* gate already open or close */
-	if (priv->i2c_gate_state == enable)
-		return 0;
-
-	ret = rtl2832_wr_demod_reg(priv, DVBT_IIC_REPEAT, (enable ? 0x1 : 0x0));
-	if (ret)
-		goto err;
-
-	priv->i2c_gate_state = enable;
-
-	return ret;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-
-
-static int rtl2832_init(struct dvb_frontend *fe)
-{
-	struct rtl2832_priv *priv = fe->demodulator_priv;
-	int i, ret;
-
-	u8 en_bbin;
-	u64 pset_iffreq;
-
-	/* initialization values for the demodulator registers */
-	struct rtl2832_reg_value rtl2832_initial_regs[] = {
-		{DVBT_AD_EN_REG,		0x1},
-		{DVBT_AD_EN_REG1,		0x1},
-		{DVBT_RSD_BER_FAIL_VAL,		0x2800},
-		{DVBT_MGD_THD0,			0x10},
-		{DVBT_MGD_THD1,			0x20},
-		{DVBT_MGD_THD2,			0x20},
-		{DVBT_MGD_THD3,			0x40},
-		{DVBT_MGD_THD4,			0x22},
-		{DVBT_MGD_THD5,			0x32},
-		{DVBT_MGD_THD6,			0x37},
-		{DVBT_MGD_THD7,			0x39},
-		{DVBT_EN_BK_TRK,		0x0},
-		{DVBT_EN_CACQ_NOTCH,		0x0},
-		{DVBT_AD_AV_REF,		0x2a},
-		{DVBT_REG_PI,			0x6},
-		{DVBT_PIP_ON,			0x0},
-		{DVBT_CDIV_PH0,			0x8},
-		{DVBT_CDIV_PH1,			0x8},
-		{DVBT_SCALE1_B92,		0x4},
-		{DVBT_SCALE1_B93,		0xb0},
-		{DVBT_SCALE1_BA7,		0x78},
-		{DVBT_SCALE1_BA9,		0x28},
-		{DVBT_SCALE1_BAA,		0x59},
-		{DVBT_SCALE1_BAB,		0x83},
-		{DVBT_SCALE1_BAC,		0xd4},
-		{DVBT_SCALE1_BB0,		0x65},
-		{DVBT_SCALE1_BB1,		0x43},
-		{DVBT_KB_P1,			0x1},
-		{DVBT_KB_P2,			0x4},
-		{DVBT_KB_P3,			0x7},
-		{DVBT_K1_CR_STEP12,		0xa},
-		{DVBT_REG_GPE,			0x1},
-		{DVBT_SERIAL,			0x0},
-		{DVBT_CDIV_PH0,			0x9},
-		{DVBT_CDIV_PH1,			0x9},
-		{DVBT_MPEG_IO_OPT_2_2,		0x0},
-		{DVBT_MPEG_IO_OPT_1_0,		0x0},
-		{DVBT_TRK_KS_P2,		0x4},
-		{DVBT_TRK_KS_I2,		0x7},
-		{DVBT_TR_THD_SET2,		0x6},
-		{DVBT_TRK_KC_I2,		0x5},
-		{DVBT_CR_THD_SET2,		0x1},
-		{DVBT_SPEC_INV,			0x0},
-		{DVBT_DAGC_TRG_VAL,		0x5a},
-		{DVBT_AGC_TARG_VAL_0,		0x0},
-		{DVBT_AGC_TARG_VAL_8_1,		0x5a},
-		{DVBT_AAGC_LOOP_GAIN,		0x16},
-		{DVBT_LOOP_GAIN2_3_0,		0x6},
-		{DVBT_LOOP_GAIN2_4,		0x1},
-		{DVBT_LOOP_GAIN3,		0x16},
-		{DVBT_VTOP1,			0x35},
-		{DVBT_VTOP2,			0x21},
-		{DVBT_VTOP3,			0x21},
-		{DVBT_KRF1,			0x0},
-		{DVBT_KRF2,			0x40},
-		{DVBT_KRF3,			0x10},
-		{DVBT_KRF4,			0x10},
-		{DVBT_IF_AGC_MIN,		0x80},
-		{DVBT_IF_AGC_MAX,		0x7f},
-		{DVBT_RF_AGC_MIN,		0x80},
-		{DVBT_RF_AGC_MAX,		0x7f},
-		{DVBT_POLAR_RF_AGC,		0x0},
-		{DVBT_POLAR_IF_AGC,		0x0},
-		{DVBT_AD7_SETTING,		0xe9bf},
-		{DVBT_EN_GI_PGA,		0x0},
-		{DVBT_THD_LOCK_UP,		0x0},
-		{DVBT_THD_LOCK_DW,		0x0},
-		{DVBT_THD_UP1,			0x11},
-		{DVBT_THD_DW1,			0xef},
-		{DVBT_INTER_CNT_LEN,		0xc},
-		{DVBT_GI_PGA_STATE,		0x0},
-		{DVBT_EN_AGC_PGA,		0x1},
-		{DVBT_IF_AGC_MAN,		0x0},
-	};
-
-
-	dbg("%s", __func__);
-
-	en_bbin = (priv->cfg.if_dvbt == 0 ? 0x1 : 0x0);
-
-	/*
-	* PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22)
-	*		/ CrystalFreqHz)
-	*/
-	pset_iffreq = priv->cfg.if_dvbt % priv->cfg.xtal;
-	pset_iffreq *= 0x400000;
-	pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal);
-	pset_iffreq = pset_iffreq & 0x3fffff;
-
-
-
-	for (i = 0; i < ARRAY_SIZE(rtl2832_initial_regs); i++) {
-		ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs[i].reg,
-			rtl2832_initial_regs[i].value);
-		if (ret)
-			goto err;
-	}
-
-	/* if frequency settings */
-	ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin);
-		if (ret)
-			goto err;
-
-	ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq);
-		if (ret)
-			goto err;
-
-	priv->sleeping = false;
-
-	return ret;
-
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int rtl2832_sleep(struct dvb_frontend *fe)
-{
-	struct rtl2832_priv *priv = fe->demodulator_priv;
-
-	dbg("%s", __func__);
-	priv->sleeping = true;
-	return 0;
-}
-
-int rtl2832_get_tune_settings(struct dvb_frontend *fe,
-	struct dvb_frontend_tune_settings *s)
-{
-	dbg("%s", __func__);
-	s->min_delay_ms = 1000;
-	s->step_size = fe->ops.info.frequency_stepsize * 2;
-	s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
-	return 0;
-}
-
-static int rtl2832_set_frontend(struct dvb_frontend *fe)
-{
-	struct rtl2832_priv *priv = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret, i, j;
-	u64 bw_mode, num, num2;
-	u32 resamp_ratio, cfreq_off_ratio;
-
-
-	static u8 bw_params[3][32] = {
-	/* 6 MHz bandwidth */
-		{
-		0xf5, 0xff, 0x15, 0x38, 0x5d, 0x6d, 0x52, 0x07, 0xfa, 0x2f,
-		0x53, 0xf5, 0x3f, 0xca, 0x0b, 0x91, 0xea, 0x30, 0x63, 0xb2,
-		0x13, 0xda, 0x0b, 0xc4, 0x18, 0x7e, 0x16, 0x66, 0x08, 0x67,
-		0x19, 0xe0,
-		},
-
-	/*  7 MHz bandwidth */
-		{
-		0xe7, 0xcc, 0xb5, 0xba, 0xe8, 0x2f, 0x67, 0x61, 0x00, 0xaf,
-		0x86, 0xf2, 0xbf, 0x59, 0x04, 0x11, 0xb6, 0x33, 0xa4, 0x30,
-		0x15, 0x10, 0x0a, 0x42, 0x18, 0xf8, 0x17, 0xd9, 0x07, 0x22,
-		0x19, 0x10,
-		},
-
-	/*  8 MHz bandwidth */
-		{
-		0x09, 0xf6, 0xd2, 0xa7, 0x9a, 0xc9, 0x27, 0x77, 0x06, 0xbf,
-		0xec, 0xf4, 0x4f, 0x0b, 0xfc, 0x01, 0x63, 0x35, 0x54, 0xa7,
-		0x16, 0x66, 0x08, 0xb4, 0x19, 0x6e, 0x19, 0x65, 0x05, 0xc8,
-		0x19, 0xe0,
-		},
-	};
-
-
-	dbg("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__,
-		c->frequency, c->bandwidth_hz, c->inversion);
-
-
-	/* program tuner */
-	if (fe->ops.tuner_ops.set_params)
-		fe->ops.tuner_ops.set_params(fe);
-
-
-	switch (c->bandwidth_hz) {
-	case 6000000:
-		i = 0;
-		bw_mode = 48000000;
-		break;
-	case 7000000:
-		i = 1;
-		bw_mode = 56000000;
-		break;
-	case 8000000:
-		i = 2;
-		bw_mode = 64000000;
-		break;
-	default:
-		dbg("invalid bandwidth");
-		return -EINVAL;
-	}
-
-	for (j = 0; j < sizeof(bw_params[0]); j++) {
-		ret = rtl2832_wr_regs(priv, 0x1c+j, 1, &bw_params[i][j], 1);
-		if (ret)
-			goto err;
-	}
-
-	/* calculate and set resample ratio
-	* RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22)
-	*	/ ConstWithBandwidthMode)
-	*/
-	num = priv->cfg.xtal * 7;
-	num *= 0x400000;
-	num = div_u64(num, bw_mode);
-	resamp_ratio =  num & 0x3ffffff;
-	ret = rtl2832_wr_demod_reg(priv, DVBT_RSAMP_RATIO, resamp_ratio);
-	if (ret)
-		goto err;
-
-	/* calculate and set cfreq off ratio
-	* CFREQ_OFF_RATIO = - floor(ConstWithBandwidthMode * pow(2, 20)
-	*	/ (CrystalFreqHz * 7))
-	*/
-	num = bw_mode << 20;
-	num2 = priv->cfg.xtal * 7;
-	num = div_u64(num, num2);
-	num = -num;
-	cfreq_off_ratio = num & 0xfffff;
-	ret = rtl2832_wr_demod_reg(priv, DVBT_CFREQ_OFF_RATIO, cfreq_off_ratio);
-	if (ret)
-		goto err;
-
-
-	/* soft reset */
-	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
-	if (ret)
-		goto err;
-
-	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0);
-	if (ret)
-		goto err;
-
-	return ret;
-err:
-	info("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int rtl2832_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct rtl2832_priv *priv = fe->demodulator_priv;
-	int ret;
-	u32 tmp;
-	*status = 0;
-
-
-	dbg("%s", __func__);
-	if (priv->sleeping)
-		return 0;
-
-	ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &tmp);
-	if (ret)
-		goto err;
-
-	if (tmp == 11) {
-		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-				FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
-	}
-	/* TODO find out if this is also true for rtl2832? */
-	/*else if (tmp == 10) {
-		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-				FE_HAS_VITERBI;
-	}*/
-
-	return ret;
-err:
-	info("%s: failed=%d", __func__, ret);
-	return ret;
-}
-
-static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	*snr = 0;
-	return 0;
-}
-
-static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	*ber = 0;
-	return 0;
-}
-
-static int rtl2832_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	*ucblocks = 0;
-	return 0;
-}
-
-
-static int rtl2832_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	*strength = 0;
-	return 0;
-}
-
-static struct dvb_frontend_ops rtl2832_ops;
-
-static void rtl2832_release(struct dvb_frontend *fe)
-{
-	struct rtl2832_priv *priv = fe->demodulator_priv;
-
-	dbg("%s", __func__);
-	kfree(priv);
-}
-
-struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg,
-	struct i2c_adapter *i2c)
-{
-	struct rtl2832_priv *priv = NULL;
-	int ret = 0;
-	u8 tmp;
-
-	dbg("%s", __func__);
-
-	/* allocate memory for the internal state */
-	priv = kzalloc(sizeof(struct rtl2832_priv), GFP_KERNEL);
-	if (priv == NULL)
-		goto err;
-
-	/* setup the priv */
-	priv->i2c = i2c;
-	priv->tuner = cfg->tuner;
-	memcpy(&priv->cfg, cfg, sizeof(struct rtl2832_config));
-
-	/* check if the demod is there */
-	ret = rtl2832_rd_reg(priv, 0x00, 0x0, &tmp);
-	if (ret)
-		goto err;
-
-	/* create dvb_frontend */
-	memcpy(&priv->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
-	priv->fe.demodulator_priv = priv;
-
-	/* TODO implement sleep mode */
-	priv->sleeping = true;
-
-	return &priv->fe;
-err:
-	dbg("%s: failed=%d", __func__, ret);
-	kfree(priv);
-	return NULL;
-}
-EXPORT_SYMBOL(rtl2832_attach);
-
-static struct dvb_frontend_ops rtl2832_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name = "Realtek RTL2832 (DVB-T)",
-		.frequency_min	  = 174000000,
-		.frequency_max	  = 862000000,
-		.frequency_stepsize = 166667,
-		.caps = FE_CAN_FEC_1_2 |
-			FE_CAN_FEC_2_3 |
-			FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 |
-			FE_CAN_FEC_7_8 |
-			FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK |
-			FE_CAN_QAM_16 |
-			FE_CAN_QAM_64 |
-			FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_HIERARCHY_AUTO |
-			FE_CAN_RECOVER |
-			FE_CAN_MUTE_TS
-	 },
-
-	.release = rtl2832_release,
-
-	.init = rtl2832_init,
-	.sleep = rtl2832_sleep,
-
-	.get_tune_settings = rtl2832_get_tune_settings,
-
-	.set_frontend = rtl2832_set_frontend,
-
-	.read_status = rtl2832_read_status,
-	.read_snr = rtl2832_read_snr,
-	.read_ber = rtl2832_read_ber,
-	.read_ucblocks = rtl2832_read_ucblocks,
-	.read_signal_strength = rtl2832_read_signal_strength,
-	.i2c_gate_ctrl = rtl2832_i2c_gate_ctrl,
-};
-
-MODULE_AUTHOR("Thomas Mair <mair.thomas86@gmail.com>");
-MODULE_DESCRIPTION("Realtek RTL2832 DVB-T demodulator driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.5");
diff --git a/drivers/media/dvb/frontends/rtl2832.h b/drivers/media/dvb/frontends/rtl2832.h
deleted file mode 100644
index d94dc9a..0000000
--- a/drivers/media/dvb/frontends/rtl2832.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Realtek RTL2832 DVB-T demodulator driver
- *
- * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
- *
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
- *
- *	You should have received a copy of the GNU General Public License along
- *	with this program; if not, write to the Free Software Foundation, Inc.,
- *	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef RTL2832_H
-#define RTL2832_H
-
-#include <linux/dvb/frontend.h>
-
-struct rtl2832_config {
-	/*
-	 * Demodulator I2C address.
-	 */
-	u8 i2c_addr;
-
-	/*
-	 * Xtal frequency.
-	 * Hz
-	 * 4000000, 16000000, 25000000, 28800000
-	 */
-	u32 xtal;
-
-	/*
-	 * IFs for all used modes.
-	 * Hz
-	 * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000
-	 */
-	u32 if_dvbt;
-
-	/*
-	 */
-	u8 tuner;
-};
-
-
-#if defined(CONFIG_DVB_RTL2832) || \
-	(defined(CONFIG_DVB_RTL2832_MODULE) && defined(MODULE))
-extern struct dvb_frontend *rtl2832_attach(
-	const struct rtl2832_config *cfg,
-	struct i2c_adapter *i2c
-);
-
-extern struct i2c_adapter *rtl2832_get_tuner_i2c_adapter(
-	struct dvb_frontend *fe
-);
-#else
-static inline struct dvb_frontend *rtl2832_attach(
-	const struct rtl2832_config *config,
-	struct i2c_adapter *i2c
-)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-
-#endif /* RTL2832_H */
diff --git a/drivers/media/dvb/frontends/rtl2832_priv.h b/drivers/media/dvb/frontends/rtl2832_priv.h
deleted file mode 100644
index 0ce9502..0000000
--- a/drivers/media/dvb/frontends/rtl2832_priv.h
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Realtek RTL2832 DVB-T demodulator driver
- *
- * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
- *
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
- *
- *	You should have received a copy of the GNU General Public License along
- *	with this program; if not, write to the Free Software Foundation, Inc.,
- *	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef RTL2832_PRIV_H
-#define RTL2832_PRIV_H
-
-#include "dvb_frontend.h"
-#include "rtl2832.h"
-
-#define LOG_PREFIX "rtl2832"
-
-#undef dbg
-#define dbg(f, arg...) \
-do { \
-	if (rtl2832_debug)  \
-		printk(KERN_INFO     LOG_PREFIX": " f "\n" , ## arg); \
-} while (0)
-#undef err
-#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
-#undef info
-#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
-#undef warn
-#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
-
-struct rtl2832_priv {
-	struct i2c_adapter *i2c;
-	struct dvb_frontend fe;
-	struct rtl2832_config cfg;
-
-	bool i2c_gate_state;
-	bool sleeping;
-
-	u8 tuner;
-	u8 page; /* active register page */
-};
-
-struct rtl2832_reg_entry {
-	u8 page;
-	u8 start_address;
-	u8 msb;
-	u8 lsb;
-};
-
-struct rtl2832_reg_value {
-	int reg;
-	u32 value;
-};
-
-
-/* Demod register bit names */
-enum DVBT_REG_BIT_NAME {
-	DVBT_SOFT_RST,
-	DVBT_IIC_REPEAT,
-	DVBT_TR_WAIT_MIN_8K,
-	DVBT_RSD_BER_FAIL_VAL,
-	DVBT_EN_BK_TRK,
-	DVBT_REG_PI,
-	DVBT_REG_PFREQ_1_0,
-	DVBT_PD_DA8,
-	DVBT_LOCK_TH,
-	DVBT_BER_PASS_SCAL,
-	DVBT_CE_FFSM_BYPASS,
-	DVBT_ALPHAIIR_N,
-	DVBT_ALPHAIIR_DIF,
-	DVBT_EN_TRK_SPAN,
-	DVBT_LOCK_TH_LEN,
-	DVBT_CCI_THRE,
-	DVBT_CCI_MON_SCAL,
-	DVBT_CCI_M0,
-	DVBT_CCI_M1,
-	DVBT_CCI_M2,
-	DVBT_CCI_M3,
-	DVBT_SPEC_INIT_0,
-	DVBT_SPEC_INIT_1,
-	DVBT_SPEC_INIT_2,
-	DVBT_AD_EN_REG,
-	DVBT_AD_EN_REG1,
-	DVBT_EN_BBIN,
-	DVBT_MGD_THD0,
-	DVBT_MGD_THD1,
-	DVBT_MGD_THD2,
-	DVBT_MGD_THD3,
-	DVBT_MGD_THD4,
-	DVBT_MGD_THD5,
-	DVBT_MGD_THD6,
-	DVBT_MGD_THD7,
-	DVBT_EN_CACQ_NOTCH,
-	DVBT_AD_AV_REF,
-	DVBT_PIP_ON,
-	DVBT_SCALE1_B92,
-	DVBT_SCALE1_B93,
-	DVBT_SCALE1_BA7,
-	DVBT_SCALE1_BA9,
-	DVBT_SCALE1_BAA,
-	DVBT_SCALE1_BAB,
-	DVBT_SCALE1_BAC,
-	DVBT_SCALE1_BB0,
-	DVBT_SCALE1_BB1,
-	DVBT_KB_P1,
-	DVBT_KB_P2,
-	DVBT_KB_P3,
-	DVBT_OPT_ADC_IQ,
-	DVBT_AD_AVI,
-	DVBT_AD_AVQ,
-	DVBT_K1_CR_STEP12,
-	DVBT_TRK_KS_P2,
-	DVBT_TRK_KS_I2,
-	DVBT_TR_THD_SET2,
-	DVBT_TRK_KC_P2,
-	DVBT_TRK_KC_I2,
-	DVBT_CR_THD_SET2,
-	DVBT_PSET_IFFREQ,
-	DVBT_SPEC_INV,
-	DVBT_BW_INDEX,
-	DVBT_RSAMP_RATIO,
-	DVBT_CFREQ_OFF_RATIO,
-	DVBT_FSM_STAGE,
-	DVBT_RX_CONSTEL,
-	DVBT_RX_HIER,
-	DVBT_RX_C_RATE_LP,
-	DVBT_RX_C_RATE_HP,
-	DVBT_GI_IDX,
-	DVBT_FFT_MODE_IDX,
-	DVBT_RSD_BER_EST,
-	DVBT_CE_EST_EVM,
-	DVBT_RF_AGC_VAL,
-	DVBT_IF_AGC_VAL,
-	DVBT_DAGC_VAL,
-	DVBT_SFREQ_OFF,
-	DVBT_CFREQ_OFF,
-	DVBT_POLAR_RF_AGC,
-	DVBT_POLAR_IF_AGC,
-	DVBT_AAGC_HOLD,
-	DVBT_EN_RF_AGC,
-	DVBT_EN_IF_AGC,
-	DVBT_IF_AGC_MIN,
-	DVBT_IF_AGC_MAX,
-	DVBT_RF_AGC_MIN,
-	DVBT_RF_AGC_MAX,
-	DVBT_IF_AGC_MAN,
-	DVBT_IF_AGC_MAN_VAL,
-	DVBT_RF_AGC_MAN,
-	DVBT_RF_AGC_MAN_VAL,
-	DVBT_DAGC_TRG_VAL,
-	DVBT_AGC_TARG_VAL,
-	DVBT_LOOP_GAIN_3_0,
-	DVBT_LOOP_GAIN_4,
-	DVBT_VTOP,
-	DVBT_KRF,
-	DVBT_AGC_TARG_VAL_0,
-	DVBT_AGC_TARG_VAL_8_1,
-	DVBT_AAGC_LOOP_GAIN,
-	DVBT_LOOP_GAIN2_3_0,
-	DVBT_LOOP_GAIN2_4,
-	DVBT_LOOP_GAIN3,
-	DVBT_VTOP1,
-	DVBT_VTOP2,
-	DVBT_VTOP3,
-	DVBT_KRF1,
-	DVBT_KRF2,
-	DVBT_KRF3,
-	DVBT_KRF4,
-	DVBT_EN_GI_PGA,
-	DVBT_THD_LOCK_UP,
-	DVBT_THD_LOCK_DW,
-	DVBT_THD_UP1,
-	DVBT_THD_DW1,
-	DVBT_INTER_CNT_LEN,
-	DVBT_GI_PGA_STATE,
-	DVBT_EN_AGC_PGA,
-	DVBT_CKOUTPAR,
-	DVBT_CKOUT_PWR,
-	DVBT_SYNC_DUR,
-	DVBT_ERR_DUR,
-	DVBT_SYNC_LVL,
-	DVBT_ERR_LVL,
-	DVBT_VAL_LVL,
-	DVBT_SERIAL,
-	DVBT_SER_LSB,
-	DVBT_CDIV_PH0,
-	DVBT_CDIV_PH1,
-	DVBT_MPEG_IO_OPT_2_2,
-	DVBT_MPEG_IO_OPT_1_0,
-	DVBT_CKOUTPAR_PIP,
-	DVBT_CKOUT_PWR_PIP,
-	DVBT_SYNC_LVL_PIP,
-	DVBT_ERR_LVL_PIP,
-	DVBT_VAL_LVL_PIP,
-	DVBT_CKOUTPAR_PID,
-	DVBT_CKOUT_PWR_PID,
-	DVBT_SYNC_LVL_PID,
-	DVBT_ERR_LVL_PID,
-	DVBT_VAL_LVL_PID,
-	DVBT_SM_PASS,
-	DVBT_UPDATE_REG_2,
-	DVBT_BTHD_P3,
-	DVBT_BTHD_D3,
-	DVBT_FUNC4_REG0,
-	DVBT_FUNC4_REG1,
-	DVBT_FUNC4_REG2,
-	DVBT_FUNC4_REG3,
-	DVBT_FUNC4_REG4,
-	DVBT_FUNC4_REG5,
-	DVBT_FUNC4_REG6,
-	DVBT_FUNC4_REG7,
-	DVBT_FUNC4_REG8,
-	DVBT_FUNC4_REG9,
-	DVBT_FUNC4_REG10,
-	DVBT_FUNC5_REG0,
-	DVBT_FUNC5_REG1,
-	DVBT_FUNC5_REG2,
-	DVBT_FUNC5_REG3,
-	DVBT_FUNC5_REG4,
-	DVBT_FUNC5_REG5,
-	DVBT_FUNC5_REG6,
-	DVBT_FUNC5_REG7,
-	DVBT_FUNC5_REG8,
-	DVBT_FUNC5_REG9,
-	DVBT_FUNC5_REG10,
-	DVBT_FUNC5_REG11,
-	DVBT_FUNC5_REG12,
-	DVBT_FUNC5_REG13,
-	DVBT_FUNC5_REG14,
-	DVBT_FUNC5_REG15,
-	DVBT_FUNC5_REG16,
-	DVBT_FUNC5_REG17,
-	DVBT_FUNC5_REG18,
-	DVBT_AD7_SETTING,
-	DVBT_RSSI_R,
-	DVBT_ACI_DET_IND,
-	DVBT_REG_MON,
-	DVBT_REG_MONSEL,
-	DVBT_REG_GPE,
-	DVBT_REG_GPO,
-	DVBT_REG_4MSEL,
-	DVBT_TEST_REG_1,
-	DVBT_TEST_REG_2,
-	DVBT_TEST_REG_3,
-	DVBT_TEST_REG_4,
-	DVBT_REG_BIT_NAME_ITEM_TERMINATOR,
-};
-
-#endif /* RTL2832_PRIV_H */
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
deleted file mode 100644
index f71b062..0000000
--- a/drivers/media/dvb/frontends/s5h1409.c
+++ /dev/null
@@ -1,1029 +0,0 @@
-/*
-    Samsung S5H1409 VSB/QAM demodulator driver
-
-    Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include "dvb_frontend.h"
-#include "s5h1409.h"
-
-struct s5h1409_state {
-
-	struct i2c_adapter *i2c;
-
-	/* configuration settings */
-	const struct s5h1409_config *config;
-
-	struct dvb_frontend frontend;
-
-	/* previous uncorrected block counter */
-	fe_modulation_t current_modulation;
-
-	u32 current_frequency;
-	int if_freq;
-
-	u32 is_qam_locked;
-
-	/* QAM tuning state goes through the following state transitions */
-#define QAM_STATE_UNTUNED 0
-#define QAM_STATE_TUNING_STARTED 1
-#define QAM_STATE_INTERLEAVE_SET 2
-#define QAM_STATE_QAM_OPTIMIZED_L1 3
-#define QAM_STATE_QAM_OPTIMIZED_L2 4
-#define QAM_STATE_QAM_OPTIMIZED_L3 5
-	u8  qam_state;
-};
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Enable verbose debug messages");
-
-#define dprintk	if (debug) printk
-
-/* Register values to initialise the demod, this will set VSB by default */
-static struct init_tab {
-	u8	reg;
-	u16	data;
-} init_tab[] = {
-	{ 0x00, 0x0071, },
-	{ 0x01, 0x3213, },
-	{ 0x09, 0x0025, },
-	{ 0x1c, 0x001d, },
-	{ 0x1f, 0x002d, },
-	{ 0x20, 0x001d, },
-	{ 0x22, 0x0022, },
-	{ 0x23, 0x0020, },
-	{ 0x29, 0x110f, },
-	{ 0x2a, 0x10b4, },
-	{ 0x2b, 0x10ae, },
-	{ 0x2c, 0x0031, },
-	{ 0x31, 0x010d, },
-	{ 0x32, 0x0100, },
-	{ 0x44, 0x0510, },
-	{ 0x54, 0x0104, },
-	{ 0x58, 0x2222, },
-	{ 0x59, 0x1162, },
-	{ 0x5a, 0x3211, },
-	{ 0x5d, 0x0370, },
-	{ 0x5e, 0x0296, },
-	{ 0x61, 0x0010, },
-	{ 0x63, 0x4a00, },
-	{ 0x65, 0x0800, },
-	{ 0x71, 0x0003, },
-	{ 0x72, 0x0470, },
-	{ 0x81, 0x0002, },
-	{ 0x82, 0x0600, },
-	{ 0x86, 0x0002, },
-	{ 0x8a, 0x2c38, },
-	{ 0x8b, 0x2a37, },
-	{ 0x92, 0x302f, },
-	{ 0x93, 0x3332, },
-	{ 0x96, 0x000c, },
-	{ 0x99, 0x0101, },
-	{ 0x9c, 0x2e37, },
-	{ 0x9d, 0x2c37, },
-	{ 0x9e, 0x2c37, },
-	{ 0xab, 0x0100, },
-	{ 0xac, 0x1003, },
-	{ 0xad, 0x103f, },
-	{ 0xe2, 0x0100, },
-	{ 0xe3, 0x1000, },
-	{ 0x28, 0x1010, },
-	{ 0xb1, 0x000e, },
-};
-
-/* VSB SNR lookup table */
-static struct vsb_snr_tab {
-	u16	val;
-	u16	data;
-} vsb_snr_tab[] = {
-	{  924, 300, },
-	{  923, 300, },
-	{  918, 295, },
-	{  915, 290, },
-	{  911, 285, },
-	{  906, 280, },
-	{  901, 275, },
-	{  896, 270, },
-	{  891, 265, },
-	{  885, 260, },
-	{  879, 255, },
-	{  873, 250, },
-	{  864, 245, },
-	{  858, 240, },
-	{  850, 235, },
-	{  841, 230, },
-	{  832, 225, },
-	{  823, 220, },
-	{  812, 215, },
-	{  802, 210, },
-	{  788, 205, },
-	{  778, 200, },
-	{  767, 195, },
-	{  753, 190, },
-	{  740, 185, },
-	{  725, 180, },
-	{  707, 175, },
-	{  689, 170, },
-	{  671, 165, },
-	{  656, 160, },
-	{  637, 155, },
-	{  616, 150, },
-	{  542, 145, },
-	{  519, 140, },
-	{  507, 135, },
-	{  497, 130, },
-	{  492, 125, },
-	{  474, 120, },
-	{  300, 111, },
-	{    0,   0, },
-};
-
-/* QAM64 SNR lookup table */
-static struct qam64_snr_tab {
-	u16	val;
-	u16	data;
-} qam64_snr_tab[] = {
-	{    1,   0, },
-	{   12, 300, },
-	{   15, 290, },
-	{   18, 280, },
-	{   22, 270, },
-	{   23, 268, },
-	{   24, 266, },
-	{   25, 264, },
-	{   27, 262, },
-	{   28, 260, },
-	{   29, 258, },
-	{   30, 256, },
-	{   32, 254, },
-	{   33, 252, },
-	{   34, 250, },
-	{   35, 249, },
-	{   36, 248, },
-	{   37, 247, },
-	{   38, 246, },
-	{   39, 245, },
-	{   40, 244, },
-	{   41, 243, },
-	{   42, 241, },
-	{   43, 240, },
-	{   44, 239, },
-	{   45, 238, },
-	{   46, 237, },
-	{   47, 236, },
-	{   48, 235, },
-	{   49, 234, },
-	{   50, 233, },
-	{   51, 232, },
-	{   52, 231, },
-	{   53, 230, },
-	{   55, 229, },
-	{   56, 228, },
-	{   57, 227, },
-	{   58, 226, },
-	{   59, 225, },
-	{   60, 224, },
-	{   62, 223, },
-	{   63, 222, },
-	{   65, 221, },
-	{   66, 220, },
-	{   68, 219, },
-	{   69, 218, },
-	{   70, 217, },
-	{   72, 216, },
-	{   73, 215, },
-	{   75, 214, },
-	{   76, 213, },
-	{   78, 212, },
-	{   80, 211, },
-	{   81, 210, },
-	{   83, 209, },
-	{   84, 208, },
-	{   85, 207, },
-	{   87, 206, },
-	{   89, 205, },
-	{   91, 204, },
-	{   93, 203, },
-	{   95, 202, },
-	{   96, 201, },
-	{  104, 200, },
-	{  255,   0, },
-};
-
-/* QAM256 SNR lookup table */
-static struct qam256_snr_tab {
-	u16	val;
-	u16	data;
-} qam256_snr_tab[] = {
-	{    1,   0, },
-	{   12, 400, },
-	{   13, 390, },
-	{   15, 380, },
-	{   17, 360, },
-	{   19, 350, },
-	{   22, 348, },
-	{   23, 346, },
-	{   24, 344, },
-	{   25, 342, },
-	{   26, 340, },
-	{   27, 336, },
-	{   28, 334, },
-	{   29, 332, },
-	{   30, 330, },
-	{   31, 328, },
-	{   32, 326, },
-	{   33, 325, },
-	{   34, 322, },
-	{   35, 320, },
-	{   37, 318, },
-	{   39, 316, },
-	{   40, 314, },
-	{   41, 312, },
-	{   42, 310, },
-	{   43, 308, },
-	{   46, 306, },
-	{   47, 304, },
-	{   49, 302, },
-	{   51, 300, },
-	{   53, 298, },
-	{   54, 297, },
-	{   55, 296, },
-	{   56, 295, },
-	{   57, 294, },
-	{   59, 293, },
-	{   60, 292, },
-	{   61, 291, },
-	{   63, 290, },
-	{   64, 289, },
-	{   65, 288, },
-	{   66, 287, },
-	{   68, 286, },
-	{   69, 285, },
-	{   71, 284, },
-	{   72, 283, },
-	{   74, 282, },
-	{   75, 281, },
-	{   76, 280, },
-	{   77, 279, },
-	{   78, 278, },
-	{   81, 277, },
-	{   83, 276, },
-	{   84, 275, },
-	{   86, 274, },
-	{   87, 273, },
-	{   89, 272, },
-	{   90, 271, },
-	{   92, 270, },
-	{   93, 269, },
-	{   95, 268, },
-	{   96, 267, },
-	{   98, 266, },
-	{  100, 265, },
-	{  102, 264, },
-	{  104, 263, },
-	{  105, 262, },
-	{  106, 261, },
-	{  110, 260, },
-	{  255,   0, },
-};
-
-/* 8 bit registers, 16 bit values */
-static int s5h1409_writereg(struct s5h1409_state *state, u8 reg, u16 data)
-{
-	int ret;
-	u8 buf[] = { reg, data >> 8,  data & 0xff };
-
-	struct i2c_msg msg = { .addr = state->config->demod_address,
-			       .flags = 0, .buf = buf, .len = 3 };
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-
-	if (ret != 1)
-		printk(KERN_ERR "%s: error (reg == 0x%02x, val == 0x%04x, "
-		       "ret == %i)\n", __func__, reg, data, ret);
-
-	return (ret != 1) ? -1 : 0;
-}
-
-static u16 s5h1409_readreg(struct s5h1409_state *state, u8 reg)
-{
-	int ret;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0, 0 };
-
-	struct i2c_msg msg[] = {
-		{ .addr = state->config->demod_address, .flags = 0,
-		  .buf = b0, .len = 1 },
-		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
-		  .buf = b1, .len = 2 } };
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2)
-		printk("%s: readreg error (ret == %i)\n", __func__, ret);
-	return (b1[0] << 8) | b1[1];
-}
-
-static int s5h1409_softreset(struct dvb_frontend *fe)
-{
-	struct s5h1409_state *state = fe->demodulator_priv;
-
-	dprintk("%s()\n", __func__);
-
-	s5h1409_writereg(state, 0xf5, 0);
-	s5h1409_writereg(state, 0xf5, 1);
-	state->is_qam_locked = 0;
-	state->qam_state = QAM_STATE_UNTUNED;
-	return 0;
-}
-
-#define S5H1409_VSB_IF_FREQ 5380
-#define S5H1409_QAM_IF_FREQ (state->config->qam_if)
-
-static int s5h1409_set_if_freq(struct dvb_frontend *fe, int KHz)
-{
-	struct s5h1409_state *state = fe->demodulator_priv;
-
-	dprintk("%s(%d KHz)\n", __func__, KHz);
-
-	switch (KHz) {
-	case 4000:
-		s5h1409_writereg(state, 0x87, 0x014b);
-		s5h1409_writereg(state, 0x88, 0x0cb5);
-		s5h1409_writereg(state, 0x89, 0x03e2);
-		break;
-	case 5380:
-	case 44000:
-	default:
-		s5h1409_writereg(state, 0x87, 0x01be);
-		s5h1409_writereg(state, 0x88, 0x0436);
-		s5h1409_writereg(state, 0x89, 0x054d);
-		break;
-	}
-	state->if_freq = KHz;
-
-	return 0;
-}
-
-static int s5h1409_set_spectralinversion(struct dvb_frontend *fe, int inverted)
-{
-	struct s5h1409_state *state = fe->demodulator_priv;
-
-	dprintk("%s(%d)\n", __func__, inverted);
-
-	if (inverted == 1)
-		return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */
-	else
-		return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */
-}
-
-static int s5h1409_enable_modulation(struct dvb_frontend *fe,
-				     fe_modulation_t m)
-{
-	struct s5h1409_state *state = fe->demodulator_priv;
-
-	dprintk("%s(0x%08x)\n", __func__, m);
-
-	switch (m) {
-	case VSB_8:
-		dprintk("%s() VSB_8\n", __func__);
-		if (state->if_freq != S5H1409_VSB_IF_FREQ)
-			s5h1409_set_if_freq(fe, S5H1409_VSB_IF_FREQ);
-		s5h1409_writereg(state, 0xf4, 0);
-		break;
-	case QAM_64:
-	case QAM_256:
-	case QAM_AUTO:
-		dprintk("%s() QAM_AUTO (64/256)\n", __func__);
-		if (state->if_freq != S5H1409_QAM_IF_FREQ)
-			s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ);
-		s5h1409_writereg(state, 0xf4, 1);
-		s5h1409_writereg(state, 0x85, 0x110);
-		break;
-	default:
-		dprintk("%s() Invalid modulation\n", __func__);
-		return -EINVAL;
-	}
-
-	state->current_modulation = m;
-	s5h1409_softreset(fe);
-
-	return 0;
-}
-
-static int s5h1409_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct s5h1409_state *state = fe->demodulator_priv;
-
-	dprintk("%s(%d)\n", __func__, enable);
-
-	if (enable)
-		return s5h1409_writereg(state, 0xf3, 1);
-	else
-		return s5h1409_writereg(state, 0xf3, 0);
-}
-
-static int s5h1409_set_gpio(struct dvb_frontend *fe, int enable)
-{
-	struct s5h1409_state *state = fe->demodulator_priv;
-
-	dprintk("%s(%d)\n", __func__, enable);
-
-	if (enable)
-		return s5h1409_writereg(state, 0xe3,
-			s5h1409_readreg(state, 0xe3) | 0x1100);
-	else
-		return s5h1409_writereg(state, 0xe3,
-			s5h1409_readreg(state, 0xe3) & 0xfeff);
-}
-
-static int s5h1409_sleep(struct dvb_frontend *fe, int enable)
-{
-	struct s5h1409_state *state = fe->demodulator_priv;
-
-	dprintk("%s(%d)\n", __func__, enable);
-
-	return s5h1409_writereg(state, 0xf2, enable);
-}
-
-static int s5h1409_register_reset(struct dvb_frontend *fe)
-{
-	struct s5h1409_state *state = fe->demodulator_priv;
-
-	dprintk("%s()\n", __func__);
-
-	return s5h1409_writereg(state, 0xfa, 0);
-}
-
-static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe)
-{
-	struct s5h1409_state *state = fe->demodulator_priv;
-	u16 reg;
-
-	if (state->qam_state < QAM_STATE_INTERLEAVE_SET) {
-		/* We should not perform amhum optimization until
-		   the interleave mode has been configured */
-		return;
-	}
-
-	if (state->qam_state == QAM_STATE_QAM_OPTIMIZED_L3) {
-		/* We've already reached the maximum optimization level, so
-		   dont bother banging on the status registers */
-		return;
-	}
-
-	/* QAM EQ lock check */
-	reg = s5h1409_readreg(state, 0xf0);
-
-	if ((reg >> 13) & 0x1) {
-		reg &= 0xff;
-
-		s5h1409_writereg(state, 0x96, 0x000c);
-		if (reg < 0x68) {
-			if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L3) {
-				dprintk("%s() setting QAM state to OPT_L3\n",
-					__func__);
-				s5h1409_writereg(state, 0x93, 0x3130);
-				s5h1409_writereg(state, 0x9e, 0x2836);
-				state->qam_state = QAM_STATE_QAM_OPTIMIZED_L3;
-			}
-		} else {
-			if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L2) {
-				dprintk("%s() setting QAM state to OPT_L2\n",
-					__func__);
-				s5h1409_writereg(state, 0x93, 0x3332);
-				s5h1409_writereg(state, 0x9e, 0x2c37);
-				state->qam_state = QAM_STATE_QAM_OPTIMIZED_L2;
-			}
-		}
-
-	} else {
-		if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L1) {
-			dprintk("%s() setting QAM state to OPT_L1\n", __func__);
-			s5h1409_writereg(state, 0x96, 0x0008);
-			s5h1409_writereg(state, 0x93, 0x3332);
-			s5h1409_writereg(state, 0x9e, 0x2c37);
-			state->qam_state = QAM_STATE_QAM_OPTIMIZED_L1;
-		}
-	}
-}
-
-static void s5h1409_set_qam_amhum_mode_legacy(struct dvb_frontend *fe)
-{
-	struct s5h1409_state *state = fe->demodulator_priv;
-	u16 reg;
-
-	if (state->is_qam_locked)
-		return;
-
-	/* QAM EQ lock check */
-	reg = s5h1409_readreg(state, 0xf0);
-
-	if ((reg >> 13) & 0x1) {
-
-		state->is_qam_locked = 1;
-		reg &= 0xff;
-
-		s5h1409_writereg(state, 0x96, 0x00c);
-		if ((reg < 0x38) || (reg > 0x68)) {
-			s5h1409_writereg(state, 0x93, 0x3332);
-			s5h1409_writereg(state, 0x9e, 0x2c37);
-		} else {
-			s5h1409_writereg(state, 0x93, 0x3130);
-			s5h1409_writereg(state, 0x9e, 0x2836);
-		}
-
-	} else {
-		s5h1409_writereg(state, 0x96, 0x0008);
-		s5h1409_writereg(state, 0x93, 0x3332);
-		s5h1409_writereg(state, 0x9e, 0x2c37);
-	}
-}
-
-static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
-{
-	struct s5h1409_state *state = fe->demodulator_priv;
-	u16 reg, reg1, reg2;
-
-	if (state->qam_state >= QAM_STATE_INTERLEAVE_SET) {
-		/* We've done the optimization already */
-		return;
-	}
-
-	reg = s5h1409_readreg(state, 0xf1);
-
-	/* Master lock */
-	if ((reg >> 15) & 0x1) {
-		if (state->qam_state == QAM_STATE_UNTUNED ||
-		    state->qam_state == QAM_STATE_TUNING_STARTED) {
-			dprintk("%s() setting QAM state to INTERLEAVE_SET\n",
-				__func__);
-			reg1 = s5h1409_readreg(state, 0xb2);
-			reg2 = s5h1409_readreg(state, 0xad);
-
-			s5h1409_writereg(state, 0x96, 0x0020);
-			s5h1409_writereg(state, 0xad,
-				(((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)));
-			state->qam_state = QAM_STATE_INTERLEAVE_SET;
-		}
-	} else {
-		if (state->qam_state == QAM_STATE_UNTUNED) {
-			dprintk("%s() setting QAM state to TUNING_STARTED\n",
-				__func__);
-			s5h1409_writereg(state, 0x96, 0x08);
-			s5h1409_writereg(state, 0xab,
-				s5h1409_readreg(state, 0xab) | 0x1001);
-			state->qam_state = QAM_STATE_TUNING_STARTED;
-		}
-	}
-}
-
-static void s5h1409_set_qam_interleave_mode_legacy(struct dvb_frontend *fe)
-{
-	struct s5h1409_state *state = fe->demodulator_priv;
-	u16 reg, reg1, reg2;
-
-	reg = s5h1409_readreg(state, 0xf1);
-
-	/* Master lock */
-	if ((reg >> 15) & 0x1) {
-		if (state->qam_state != 2) {
-			state->qam_state = 2;
-			reg1 = s5h1409_readreg(state, 0xb2);
-			reg2 = s5h1409_readreg(state, 0xad);
-
-			s5h1409_writereg(state, 0x96, 0x20);
-			s5h1409_writereg(state, 0xad,
-				(((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)));
-			s5h1409_writereg(state, 0xab,
-				s5h1409_readreg(state, 0xab) & 0xeffe);
-		}
-	} else {
-		if (state->qam_state != 1) {
-			state->qam_state = 1;
-			s5h1409_writereg(state, 0x96, 0x08);
-			s5h1409_writereg(state, 0xab,
-				s5h1409_readreg(state, 0xab) | 0x1001);
-		}
-	}
-}
-
-/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int s5h1409_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct s5h1409_state *state = fe->demodulator_priv;
-
-	dprintk("%s(frequency=%d)\n", __func__, p->frequency);
-
-	s5h1409_softreset(fe);
-
-	state->current_frequency = p->frequency;
-
-	s5h1409_enable_modulation(fe, p->modulation);
-
-	if (fe->ops.tuner_ops.set_params) {
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	/* Issue a reset to the demod so it knows to resync against the
-	   newly tuned frequency */
-	s5h1409_softreset(fe);
-
-	/* Optimize the demod for QAM */
-	if (state->current_modulation != VSB_8) {
-		/* This almost certainly applies to all boards, but for now
-		   only do it for the HVR-1600.  Once the other boards are
-		   tested, the "legacy" versions can just go away */
-		if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
-			s5h1409_set_qam_interleave_mode(fe);
-			s5h1409_set_qam_amhum_mode(fe);
-		} else {
-			s5h1409_set_qam_amhum_mode_legacy(fe);
-			s5h1409_set_qam_interleave_mode_legacy(fe);
-		}
-	}
-
-	return 0;
-}
-
-static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode)
-{
-	struct s5h1409_state *state = fe->demodulator_priv;
-	u16 val;
-
-	dprintk("%s(%d)\n", __func__, mode);
-
-	val = s5h1409_readreg(state, 0xac) & 0xcfff;
-	switch (mode) {
-	case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK:
-		val |= 0x0000;
-		break;
-	case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK:
-		dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode);
-		val |= 0x1000;
-		break;
-	case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK:
-		val |= 0x2000;
-		break;
-	case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK:
-		val |= 0x3000;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* Configure MPEG Signal Timing charactistics */
-	return s5h1409_writereg(state, 0xac, val);
-}
-
-/* Reset the demod hardware and reset all of the configuration registers
-   to a default state. */
-static int s5h1409_init(struct dvb_frontend *fe)
-{
-	int i;
-
-	struct s5h1409_state *state = fe->demodulator_priv;
-	dprintk("%s()\n", __func__);
-
-	s5h1409_sleep(fe, 0);
-	s5h1409_register_reset(fe);
-
-	for (i = 0; i < ARRAY_SIZE(init_tab); i++)
-		s5h1409_writereg(state, init_tab[i].reg, init_tab[i].data);
-
-	/* The datasheet says that after initialisation, VSB is default */
-	state->current_modulation = VSB_8;
-
-	/* Optimize for the HVR-1600 if appropriate.  Note that some of these
-	   may get folded into the generic case after testing with other
-	   devices */
-	if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
-		/* VSB AGC REF */
-		s5h1409_writereg(state, 0x09, 0x0050);
-
-		/* Unknown but Windows driver does it... */
-		s5h1409_writereg(state, 0x21, 0x0001);
-		s5h1409_writereg(state, 0x50, 0x030e);
-
-		/* QAM AGC REF */
-		s5h1409_writereg(state, 0x82, 0x0800);
-	}
-
-	if (state->config->output_mode == S5H1409_SERIAL_OUTPUT)
-		s5h1409_writereg(state, 0xab,
-			s5h1409_readreg(state, 0xab) | 0x100); /* Serial */
-	else
-		s5h1409_writereg(state, 0xab,
-			s5h1409_readreg(state, 0xab) & 0xfeff); /* Parallel */
-
-	s5h1409_set_spectralinversion(fe, state->config->inversion);
-	s5h1409_set_if_freq(fe, state->if_freq);
-	s5h1409_set_gpio(fe, state->config->gpio);
-	s5h1409_set_mpeg_timing(fe, state->config->mpeg_timing);
-	s5h1409_softreset(fe);
-
-	/* Note: Leaving the I2C gate closed. */
-	s5h1409_i2c_gate_ctrl(fe, 0);
-
-	return 0;
-}
-
-static int s5h1409_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct s5h1409_state *state = fe->demodulator_priv;
-	u16 reg;
-	u32 tuner_status = 0;
-
-	*status = 0;
-
-	/* Optimize the demod for QAM */
-	if (state->current_modulation != VSB_8) {
-		/* This almost certainly applies to all boards, but for now
-		   only do it for the HVR-1600.  Once the other boards are
-		   tested, the "legacy" versions can just go away */
-		if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
-			s5h1409_set_qam_interleave_mode(fe);
-			s5h1409_set_qam_amhum_mode(fe);
-		}
-	}
-
-	/* Get the demodulator status */
-	reg = s5h1409_readreg(state, 0xf1);
-	if (reg & 0x1000)
-		*status |= FE_HAS_VITERBI;
-	if (reg & 0x8000)
-		*status |= FE_HAS_LOCK | FE_HAS_SYNC;
-
-	switch (state->config->status_mode) {
-	case S5H1409_DEMODLOCKING:
-		if (*status & FE_HAS_VITERBI)
-			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
-		break;
-	case S5H1409_TUNERLOCKING:
-		/* Get the tuner status */
-		if (fe->ops.tuner_ops.get_status) {
-			if (fe->ops.i2c_gate_ctrl)
-				fe->ops.i2c_gate_ctrl(fe, 1);
-
-			fe->ops.tuner_ops.get_status(fe, &tuner_status);
-
-			if (fe->ops.i2c_gate_ctrl)
-				fe->ops.i2c_gate_ctrl(fe, 0);
-		}
-		if (tuner_status)
-			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
-		break;
-	}
-
-	dprintk("%s() status 0x%08x\n", __func__, *status);
-
-	return 0;
-}
-
-static int s5h1409_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
-{
-	int i, ret = -EINVAL;
-	dprintk("%s()\n", __func__);
-
-	for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
-		if (v < qam256_snr_tab[i].val) {
-			*snr = qam256_snr_tab[i].data;
-			ret = 0;
-			break;
-		}
-	}
-	return ret;
-}
-
-static int s5h1409_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
-{
-	int i, ret = -EINVAL;
-	dprintk("%s()\n", __func__);
-
-	for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
-		if (v < qam64_snr_tab[i].val) {
-			*snr = qam64_snr_tab[i].data;
-			ret = 0;
-			break;
-		}
-	}
-	return ret;
-}
-
-static int s5h1409_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
-{
-	int i, ret = -EINVAL;
-	dprintk("%s()\n", __func__);
-
-	for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
-		if (v > vsb_snr_tab[i].val) {
-			*snr = vsb_snr_tab[i].data;
-			ret = 0;
-			break;
-		}
-	}
-	dprintk("%s() snr=%d\n", __func__, *snr);
-	return ret;
-}
-
-static int s5h1409_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct s5h1409_state *state = fe->demodulator_priv;
-	u16 reg;
-	dprintk("%s()\n", __func__);
-
-	switch (state->current_modulation) {
-	case QAM_64:
-		reg = s5h1409_readreg(state, 0xf0) & 0xff;
-		return s5h1409_qam64_lookup_snr(fe, snr, reg);
-	case QAM_256:
-		reg = s5h1409_readreg(state, 0xf0) & 0xff;
-		return s5h1409_qam256_lookup_snr(fe, snr, reg);
-	case VSB_8:
-		reg = s5h1409_readreg(state, 0xf1) & 0x3ff;
-		return s5h1409_vsb_lookup_snr(fe, snr, reg);
-	default:
-		break;
-	}
-
-	return -EINVAL;
-}
-
-static int s5h1409_read_signal_strength(struct dvb_frontend *fe,
-					u16 *signal_strength)
-{
-	/* borrowed from lgdt330x.c
-	 *
-	 * Calculate strength from SNR up to 35dB
-	 * Even though the SNR can go higher than 35dB,
-	 * there is some comfort factor in having a range of
-	 * strong signals that can show at 100%
-	 */
-	u16 snr;
-	u32 tmp;
-	int ret = s5h1409_read_snr(fe, &snr);
-
-	*signal_strength = 0;
-
-	if (0 == ret) {
-		/* The following calculation method was chosen
-		 * purely for the sake of code re-use from the
-		 * other demod drivers that use this method */
-
-		/* Convert from SNR in dB * 10 to 8.24 fixed-point */
-		tmp = (snr * ((1 << 24) / 10));
-
-		/* Convert from 8.24 fixed-point to
-		 * scale the range 0 - 35*2^24 into 0 - 65535*/
-		if (tmp >= 8960 * 0x10000)
-			*signal_strength = 0xffff;
-		else
-			*signal_strength = tmp / 8960;
-	}
-
-	return ret;
-}
-
-static int s5h1409_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct s5h1409_state *state = fe->demodulator_priv;
-
-	*ucblocks = s5h1409_readreg(state, 0xb5);
-
-	return 0;
-}
-
-static int s5h1409_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	return s5h1409_read_ucblocks(fe, ber);
-}
-
-static int s5h1409_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct s5h1409_state *state = fe->demodulator_priv;
-
-	p->frequency = state->current_frequency;
-	p->modulation = state->current_modulation;
-
-	return 0;
-}
-
-static int s5h1409_get_tune_settings(struct dvb_frontend *fe,
-				     struct dvb_frontend_tune_settings *tune)
-{
-	tune->min_delay_ms = 1000;
-	return 0;
-}
-
-static void s5h1409_release(struct dvb_frontend *fe)
-{
-	struct s5h1409_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops s5h1409_ops;
-
-struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config,
-				    struct i2c_adapter *i2c)
-{
-	struct s5h1409_state *state = NULL;
-	u16 reg;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct s5h1409_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->current_modulation = 0;
-	state->if_freq = S5H1409_VSB_IF_FREQ;
-
-	/* check if the demod exists */
-	reg = s5h1409_readreg(state, 0x04);
-	if ((reg != 0x0066) && (reg != 0x007f))
-		goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &s5h1409_ops,
-	       sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-
-	if (s5h1409_init(&state->frontend) != 0) {
-		printk(KERN_ERR "%s: Failed to initialize correctly\n",
-			__func__);
-		goto error;
-	}
-
-	/* Note: Leaving the I2C gate open here. */
-	s5h1409_i2c_gate_ctrl(&state->frontend, 1);
-
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(s5h1409_attach);
-
-static struct dvb_frontend_ops s5h1409_ops = {
-	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
-	.info = {
-		.name			= "Samsung S5H1409 QAM/8VSB Frontend",
-		.frequency_min		= 54000000,
-		.frequency_max		= 858000000,
-		.frequency_stepsize	= 62500,
-		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
-	},
-
-	.init                 = s5h1409_init,
-	.i2c_gate_ctrl        = s5h1409_i2c_gate_ctrl,
-	.set_frontend         = s5h1409_set_frontend,
-	.get_frontend         = s5h1409_get_frontend,
-	.get_tune_settings    = s5h1409_get_tune_settings,
-	.read_status          = s5h1409_read_status,
-	.read_ber             = s5h1409_read_ber,
-	.read_signal_strength = s5h1409_read_signal_strength,
-	.read_snr             = s5h1409_read_snr,
-	.read_ucblocks        = s5h1409_read_ucblocks,
-	.release              = s5h1409_release,
-};
-
-MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver");
-MODULE_AUTHOR("Steven Toth");
-MODULE_LICENSE("GPL");
-
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h
deleted file mode 100644
index 91f2ebd..0000000
--- a/drivers/media/dvb/frontends/s5h1409.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
-    Samsung S5H1409 VSB/QAM demodulator driver
-
-    Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef __S5H1409_H__
-#define __S5H1409_H__
-
-#include <linux/dvb/frontend.h>
-
-struct s5h1409_config {
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* serial/parallel output */
-#define S5H1409_PARALLEL_OUTPUT 0
-#define S5H1409_SERIAL_OUTPUT   1
-	u8 output_mode;
-
-	/* GPIO Setting */
-#define S5H1409_GPIO_OFF 0
-#define S5H1409_GPIO_ON  1
-	u8 gpio;
-
-	/* IF Freq for QAM in KHz, VSB is hardcoded to 5380 */
-	u16 qam_if;
-
-	/* Spectral Inversion */
-#define S5H1409_INVERSION_OFF 0
-#define S5H1409_INVERSION_ON  1
-	u8 inversion;
-
-	/* Return lock status based on tuner lock, or demod lock */
-#define S5H1409_TUNERLOCKING 0
-#define S5H1409_DEMODLOCKING 1
-	u8 status_mode;
-
-	/* MPEG signal timing */
-#define S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK       0
-#define S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK    1
-#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK    2
-#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
-	u16 mpeg_timing;
-
-	/* HVR-1600 optimizations (to better work with MXL5005s)
-	   Note: some of these are likely to be folded into the generic driver
-	   after being regression tested with other boards */
-#define S5H1409_HVR1600_NOOPTIMIZE 0
-#define S5H1409_HVR1600_OPTIMIZE   1
-	u8 hvr1600_opt;
-};
-
-#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) \
-	&& defined(MODULE))
-extern struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config,
-					   struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *s5h1409_attach(
-	const struct s5h1409_config *config,
-	struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_S5H1409 */
-
-#endif /* __S5H1409_H__ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/dvb/frontends/s5h1411.c b/drivers/media/dvb/frontends/s5h1411.c
deleted file mode 100644
index 6cc4b7a..0000000
--- a/drivers/media/dvb/frontends/s5h1411.c
+++ /dev/null
@@ -1,951 +0,0 @@
-/*
-    Samsung S5H1411 VSB/QAM demodulator driver
-
-    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include "dvb_frontend.h"
-#include "s5h1411.h"
-
-struct s5h1411_state {
-
-	struct i2c_adapter *i2c;
-
-	/* configuration settings */
-	const struct s5h1411_config *config;
-
-	struct dvb_frontend frontend;
-
-	fe_modulation_t current_modulation;
-	unsigned int first_tune:1;
-
-	u32 current_frequency;
-	int if_freq;
-
-	u8 inversion;
-};
-
-static int debug;
-
-#define dprintk(arg...) do {	\
-	if (debug)		\
-		printk(arg);	\
-	} while (0)
-
-/* Register values to initialise the demod, defaults to VSB */
-static struct init_tab {
-	u8	addr;
-	u8	reg;
-	u16	data;
-} init_tab[] = {
-	{ S5H1411_I2C_TOP_ADDR, 0x00, 0x0071, },
-	{ S5H1411_I2C_TOP_ADDR, 0x08, 0x0047, },
-	{ S5H1411_I2C_TOP_ADDR, 0x1c, 0x0400, },
-	{ S5H1411_I2C_TOP_ADDR, 0x1e, 0x0370, },
-	{ S5H1411_I2C_TOP_ADDR, 0x1f, 0x342c, },
-	{ S5H1411_I2C_TOP_ADDR, 0x24, 0x0231, },
-	{ S5H1411_I2C_TOP_ADDR, 0x25, 0x1011, },
-	{ S5H1411_I2C_TOP_ADDR, 0x26, 0x0f07, },
-	{ S5H1411_I2C_TOP_ADDR, 0x27, 0x0f04, },
-	{ S5H1411_I2C_TOP_ADDR, 0x28, 0x070f, },
-	{ S5H1411_I2C_TOP_ADDR, 0x29, 0x2820, },
-	{ S5H1411_I2C_TOP_ADDR, 0x2a, 0x102e, },
-	{ S5H1411_I2C_TOP_ADDR, 0x2b, 0x0220, },
-	{ S5H1411_I2C_TOP_ADDR, 0x2e, 0x0d0e, },
-	{ S5H1411_I2C_TOP_ADDR, 0x2f, 0x1013, },
-	{ S5H1411_I2C_TOP_ADDR, 0x31, 0x171b, },
-	{ S5H1411_I2C_TOP_ADDR, 0x32, 0x0e0f, },
-	{ S5H1411_I2C_TOP_ADDR, 0x33, 0x0f10, },
-	{ S5H1411_I2C_TOP_ADDR, 0x34, 0x170e, },
-	{ S5H1411_I2C_TOP_ADDR, 0x35, 0x4b10, },
-	{ S5H1411_I2C_TOP_ADDR, 0x36, 0x0f17, },
-	{ S5H1411_I2C_TOP_ADDR, 0x3c, 0x1577, },
-	{ S5H1411_I2C_TOP_ADDR, 0x3d, 0x081a, },
-	{ S5H1411_I2C_TOP_ADDR, 0x3e, 0x77ee, },
-	{ S5H1411_I2C_TOP_ADDR, 0x40, 0x1e09, },
-	{ S5H1411_I2C_TOP_ADDR, 0x41, 0x0f0c, },
-	{ S5H1411_I2C_TOP_ADDR, 0x42, 0x1f10, },
-	{ S5H1411_I2C_TOP_ADDR, 0x4d, 0x0509, },
-	{ S5H1411_I2C_TOP_ADDR, 0x4e, 0x0a00, },
-	{ S5H1411_I2C_TOP_ADDR, 0x50, 0x0000, },
-	{ S5H1411_I2C_TOP_ADDR, 0x5b, 0x0000, },
-	{ S5H1411_I2C_TOP_ADDR, 0x5c, 0x0008, },
-	{ S5H1411_I2C_TOP_ADDR, 0x57, 0x1101, },
-	{ S5H1411_I2C_TOP_ADDR, 0x65, 0x007c, },
-	{ S5H1411_I2C_TOP_ADDR, 0x68, 0x0512, },
-	{ S5H1411_I2C_TOP_ADDR, 0x69, 0x0258, },
-	{ S5H1411_I2C_TOP_ADDR, 0x70, 0x0004, },
-	{ S5H1411_I2C_TOP_ADDR, 0x71, 0x0007, },
-	{ S5H1411_I2C_TOP_ADDR, 0x76, 0x00a9, },
-	{ S5H1411_I2C_TOP_ADDR, 0x78, 0x3141, },
-	{ S5H1411_I2C_TOP_ADDR, 0x7a, 0x3141, },
-	{ S5H1411_I2C_TOP_ADDR, 0xb3, 0x8003, },
-	{ S5H1411_I2C_TOP_ADDR, 0xb5, 0xa6bb, },
-	{ S5H1411_I2C_TOP_ADDR, 0xb6, 0x0609, },
-	{ S5H1411_I2C_TOP_ADDR, 0xb7, 0x2f06, },
-	{ S5H1411_I2C_TOP_ADDR, 0xb8, 0x003f, },
-	{ S5H1411_I2C_TOP_ADDR, 0xb9, 0x2700, },
-	{ S5H1411_I2C_TOP_ADDR, 0xba, 0xfac8, },
-	{ S5H1411_I2C_TOP_ADDR, 0xbe, 0x1003, },
-	{ S5H1411_I2C_TOP_ADDR, 0xbf, 0x103f, },
-	{ S5H1411_I2C_TOP_ADDR, 0xce, 0x2000, },
-	{ S5H1411_I2C_TOP_ADDR, 0xcf, 0x0800, },
-	{ S5H1411_I2C_TOP_ADDR, 0xd0, 0x0800, },
-	{ S5H1411_I2C_TOP_ADDR, 0xd1, 0x0400, },
-	{ S5H1411_I2C_TOP_ADDR, 0xd2, 0x0800, },
-	{ S5H1411_I2C_TOP_ADDR, 0xd3, 0x2000, },
-	{ S5H1411_I2C_TOP_ADDR, 0xd4, 0x3000, },
-	{ S5H1411_I2C_TOP_ADDR, 0xdb, 0x4a9b, },
-	{ S5H1411_I2C_TOP_ADDR, 0xdc, 0x1000, },
-	{ S5H1411_I2C_TOP_ADDR, 0xde, 0x0001, },
-	{ S5H1411_I2C_TOP_ADDR, 0xdf, 0x0000, },
-	{ S5H1411_I2C_TOP_ADDR, 0xe3, 0x0301, },
-	{ S5H1411_I2C_QAM_ADDR, 0xf3, 0x0000, },
-	{ S5H1411_I2C_QAM_ADDR, 0xf3, 0x0001, },
-	{ S5H1411_I2C_QAM_ADDR, 0x08, 0x0600, },
-	{ S5H1411_I2C_QAM_ADDR, 0x18, 0x4201, },
-	{ S5H1411_I2C_QAM_ADDR, 0x1e, 0x6476, },
-	{ S5H1411_I2C_QAM_ADDR, 0x21, 0x0830, },
-	{ S5H1411_I2C_QAM_ADDR, 0x0c, 0x5679, },
-	{ S5H1411_I2C_QAM_ADDR, 0x0d, 0x579b, },
-	{ S5H1411_I2C_QAM_ADDR, 0x24, 0x0102, },
-	{ S5H1411_I2C_QAM_ADDR, 0x31, 0x7488, },
-	{ S5H1411_I2C_QAM_ADDR, 0x32, 0x0a08, },
-	{ S5H1411_I2C_QAM_ADDR, 0x3d, 0x8689, },
-	{ S5H1411_I2C_QAM_ADDR, 0x49, 0x0048, },
-	{ S5H1411_I2C_QAM_ADDR, 0x57, 0x2012, },
-	{ S5H1411_I2C_QAM_ADDR, 0x5d, 0x7676, },
-	{ S5H1411_I2C_QAM_ADDR, 0x04, 0x0400, },
-	{ S5H1411_I2C_QAM_ADDR, 0x58, 0x00c0, },
-	{ S5H1411_I2C_QAM_ADDR, 0x5b, 0x0100, },
-};
-
-/* VSB SNR lookup table */
-static struct vsb_snr_tab {
-	u16	val;
-	u16	data;
-} vsb_snr_tab[] = {
-	{  0x39f, 300, },
-	{  0x39b, 295, },
-	{  0x397, 290, },
-	{  0x394, 285, },
-	{  0x38f, 280, },
-	{  0x38b, 275, },
-	{  0x387, 270, },
-	{  0x382, 265, },
-	{  0x37d, 260, },
-	{  0x377, 255, },
-	{  0x370, 250, },
-	{  0x36a, 245, },
-	{  0x364, 240, },
-	{  0x35b, 235, },
-	{  0x353, 230, },
-	{  0x349, 225, },
-	{  0x340, 320, },
-	{  0x337, 215, },
-	{  0x327, 210, },
-	{  0x31b, 205, },
-	{  0x310, 200, },
-	{  0x302, 195, },
-	{  0x2f3, 190, },
-	{  0x2e4, 185, },
-	{  0x2d7, 180, },
-	{  0x2cd, 175, },
-	{  0x2bb, 170, },
-	{  0x2a9, 165, },
-	{  0x29e, 160, },
-	{  0x284, 155, },
-	{  0x27a, 150, },
-	{  0x260, 145, },
-	{  0x23a, 140, },
-	{  0x224, 135, },
-	{  0x213, 130, },
-	{  0x204, 125, },
-	{  0x1fe, 120, },
-	{      0,   0, },
-};
-
-/* QAM64 SNR lookup table */
-static struct qam64_snr_tab {
-	u16	val;
-	u16	data;
-} qam64_snr_tab[] = {
-	{  0x0001,   0, },
-	{  0x0af0, 300, },
-	{  0x0d80, 290, },
-	{  0x10a0, 280, },
-	{  0x14b5, 270, },
-	{  0x1590, 268, },
-	{  0x1680, 266, },
-	{  0x17b0, 264, },
-	{  0x18c0, 262, },
-	{  0x19b0, 260, },
-	{  0x1ad0, 258, },
-	{  0x1d00, 256, },
-	{  0x1da0, 254, },
-	{  0x1ef0, 252, },
-	{  0x2050, 250, },
-	{  0x20f0, 249, },
-	{  0x21d0, 248, },
-	{  0x22b0, 247, },
-	{  0x23a0, 246, },
-	{  0x2470, 245, },
-	{  0x24f0, 244, },
-	{  0x25a0, 243, },
-	{  0x26c0, 242, },
-	{  0x27b0, 241, },
-	{  0x28d0, 240, },
-	{  0x29b0, 239, },
-	{  0x2ad0, 238, },
-	{  0x2ba0, 237, },
-	{  0x2c80, 236, },
-	{  0x2d20, 235, },
-	{  0x2e00, 234, },
-	{  0x2f10, 233, },
-	{  0x3050, 232, },
-	{  0x3190, 231, },
-	{  0x3300, 230, },
-	{  0x3340, 229, },
-	{  0x3200, 228, },
-	{  0x3550, 227, },
-	{  0x3610, 226, },
-	{  0x3600, 225, },
-	{  0x3700, 224, },
-	{  0x3800, 223, },
-	{  0x3920, 222, },
-	{  0x3a20, 221, },
-	{  0x3b30, 220, },
-	{  0x3d00, 219, },
-	{  0x3e00, 218, },
-	{  0x4000, 217, },
-	{  0x4100, 216, },
-	{  0x4300, 215, },
-	{  0x4400, 214, },
-	{  0x4600, 213, },
-	{  0x4700, 212, },
-	{  0x4800, 211, },
-	{  0x4a00, 210, },
-	{  0x4b00, 209, },
-	{  0x4d00, 208, },
-	{  0x4f00, 207, },
-	{  0x5050, 206, },
-	{  0x5200, 205, },
-	{  0x53c0, 204, },
-	{  0x5450, 203, },
-	{  0x5650, 202, },
-	{  0x5820, 201, },
-	{  0x6000, 200, },
-	{  0xffff,   0, },
-};
-
-/* QAM256 SNR lookup table */
-static struct qam256_snr_tab {
-	u16	val;
-	u16	data;
-} qam256_snr_tab[] = {
-	{  0x0001,   0, },
-	{  0x0970, 400, },
-	{  0x0a90, 390, },
-	{  0x0b90, 380, },
-	{  0x0d90, 370, },
-	{  0x0ff0, 360, },
-	{  0x1240, 350, },
-	{  0x1345, 348, },
-	{  0x13c0, 346, },
-	{  0x14c0, 344, },
-	{  0x1500, 342, },
-	{  0x1610, 340, },
-	{  0x1700, 338, },
-	{  0x1800, 336, },
-	{  0x18b0, 334, },
-	{  0x1900, 332, },
-	{  0x1ab0, 330, },
-	{  0x1bc0, 328, },
-	{  0x1cb0, 326, },
-	{  0x1db0, 324, },
-	{  0x1eb0, 322, },
-	{  0x2030, 320, },
-	{  0x2200, 318, },
-	{  0x2280, 316, },
-	{  0x2410, 314, },
-	{  0x25b0, 312, },
-	{  0x27a0, 310, },
-	{  0x2840, 308, },
-	{  0x29d0, 306, },
-	{  0x2b10, 304, },
-	{  0x2d30, 302, },
-	{  0x2f20, 300, },
-	{  0x30c0, 298, },
-	{  0x3260, 297, },
-	{  0x32c0, 296, },
-	{  0x3300, 295, },
-	{  0x33b0, 294, },
-	{  0x34b0, 293, },
-	{  0x35a0, 292, },
-	{  0x3650, 291, },
-	{  0x3800, 290, },
-	{  0x3900, 289, },
-	{  0x3a50, 288, },
-	{  0x3b30, 287, },
-	{  0x3cb0, 286, },
-	{  0x3e20, 285, },
-	{  0x3fa0, 284, },
-	{  0x40a0, 283, },
-	{  0x41c0, 282, },
-	{  0x42f0, 281, },
-	{  0x44a0, 280, },
-	{  0x4600, 279, },
-	{  0x47b0, 278, },
-	{  0x4900, 277, },
-	{  0x4a00, 276, },
-	{  0x4ba0, 275, },
-	{  0x4d00, 274, },
-	{  0x4f00, 273, },
-	{  0x5000, 272, },
-	{  0x51f0, 272, },
-	{  0x53a0, 270, },
-	{  0x5520, 269, },
-	{  0x5700, 268, },
-	{  0x5800, 267, },
-	{  0x5a00, 266, },
-	{  0x5c00, 265, },
-	{  0x5d00, 264, },
-	{  0x5f00, 263, },
-	{  0x6000, 262, },
-	{  0x6200, 261, },
-	{  0x6400, 260, },
-	{  0xffff,   0, },
-};
-
-/* 8 bit registers, 16 bit values */
-static int s5h1411_writereg(struct s5h1411_state *state,
-	u8 addr, u8 reg, u16 data)
-{
-	int ret;
-	u8 buf[] = { reg, data >> 8,  data & 0xff };
-
-	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-
-	if (ret != 1)
-		printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, "
-		       "ret == %i)\n", __func__, addr, reg, data, ret);
-
-	return (ret != 1) ? -1 : 0;
-}
-
-static u16 s5h1411_readreg(struct s5h1411_state *state, u8 addr, u8 reg)
-{
-	int ret;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0, 0 };
-
-	struct i2c_msg msg[] = {
-		{ .addr = addr, .flags = 0, .buf = b0, .len = 1 },
-		{ .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2)
-		printk(KERN_ERR "%s: readreg error (ret == %i)\n",
-			__func__, ret);
-	return (b1[0] << 8) | b1[1];
-}
-
-static int s5h1411_softreset(struct dvb_frontend *fe)
-{
-	struct s5h1411_state *state = fe->demodulator_priv;
-
-	dprintk("%s()\n", __func__);
-
-	s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 0);
-	s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 1);
-	return 0;
-}
-
-static int s5h1411_set_if_freq(struct dvb_frontend *fe, int KHz)
-{
-	struct s5h1411_state *state = fe->demodulator_priv;
-
-	dprintk("%s(%d KHz)\n", __func__, KHz);
-
-	switch (KHz) {
-	case 3250:
-		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x10d5);
-		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x5342);
-		s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x10d9);
-		break;
-	case 3500:
-		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1225);
-		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x1e96);
-		s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1225);
-		break;
-	case 4000:
-		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x14bc);
-		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0xb53e);
-		s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x14bd);
-		break;
-	default:
-		dprintk("%s(%d KHz) Invalid, defaulting to 5380\n",
-			__func__, KHz);
-		/* no break, need to continue */
-	case 5380:
-	case 44000:
-		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1be4);
-		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x3655);
-		s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1be4);
-		break;
-	}
-
-	state->if_freq = KHz;
-
-	return 0;
-}
-
-static int s5h1411_set_mpeg_timing(struct dvb_frontend *fe, int mode)
-{
-	struct s5h1411_state *state = fe->demodulator_priv;
-	u16 val;
-
-	dprintk("%s(%d)\n", __func__, mode);
-
-	val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbe) & 0xcfff;
-	switch (mode) {
-	case S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK:
-		val |= 0x0000;
-		break;
-	case S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK:
-		dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode);
-		val |= 0x1000;
-		break;
-	case S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK:
-		val |= 0x2000;
-		break;
-	case S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK:
-		val |= 0x3000;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* Configure MPEG Signal Timing charactistics */
-	return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbe, val);
-}
-
-static int s5h1411_set_spectralinversion(struct dvb_frontend *fe, int inversion)
-{
-	struct s5h1411_state *state = fe->demodulator_priv;
-	u16 val;
-
-	dprintk("%s(%d)\n", __func__, inversion);
-	val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x24) & ~0x1000;
-
-	if (inversion == 1)
-		val |= 0x1000; /* Inverted */
-
-	state->inversion = inversion;
-	return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x24, val);
-}
-
-static int s5h1411_set_serialmode(struct dvb_frontend *fe, int serial)
-{
-	struct s5h1411_state *state = fe->demodulator_priv;
-	u16 val;
-
-	dprintk("%s(%d)\n", __func__, serial);
-	val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbd) & ~0x100;
-
-	if (serial == 1)
-		val |= 0x100;
-
-	return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, val);
-}
-
-static int s5h1411_enable_modulation(struct dvb_frontend *fe,
-				     fe_modulation_t m)
-{
-	struct s5h1411_state *state = fe->demodulator_priv;
-
-	dprintk("%s(0x%08x)\n", __func__, m);
-
-	if ((state->first_tune == 0) && (m == state->current_modulation)) {
-		dprintk("%s() Already at desired modulation.  Skipping...\n",
-			__func__);
-		return 0;
-	}
-
-	switch (m) {
-	case VSB_8:
-		dprintk("%s() VSB_8\n", __func__);
-		s5h1411_set_if_freq(fe, state->config->vsb_if);
-		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x71);
-		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x00);
-		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0xf1);
-		break;
-	case QAM_64:
-	case QAM_256:
-	case QAM_AUTO:
-		dprintk("%s() QAM_AUTO (64/256)\n", __func__);
-		s5h1411_set_if_freq(fe, state->config->qam_if);
-		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x0171);
-		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x0001);
-		s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x16, 0x1101);
-		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0x00f0);
-		break;
-	default:
-		dprintk("%s() Invalid modulation\n", __func__);
-		return -EINVAL;
-	}
-
-	state->current_modulation = m;
-	state->first_tune = 0;
-	s5h1411_softreset(fe);
-
-	return 0;
-}
-
-static int s5h1411_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct s5h1411_state *state = fe->demodulator_priv;
-
-	dprintk("%s(%d)\n", __func__, enable);
-
-	if (enable)
-		return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1);
-	else
-		return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 0);
-}
-
-static int s5h1411_set_gpio(struct dvb_frontend *fe, int enable)
-{
-	struct s5h1411_state *state = fe->demodulator_priv;
-	u16 val;
-
-	dprintk("%s(%d)\n", __func__, enable);
-
-	val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xe0) & ~0x02;
-
-	if (enable)
-		return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0,
-				val | 0x02);
-	else
-		return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0, val);
-}
-
-static int s5h1411_set_powerstate(struct dvb_frontend *fe, int enable)
-{
-	struct s5h1411_state *state = fe->demodulator_priv;
-
-	dprintk("%s(%d)\n", __func__, enable);
-
-	if (enable)
-		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 1);
-	else {
-		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 0);
-		s5h1411_softreset(fe);
-	}
-
-	return 0;
-}
-
-static int s5h1411_sleep(struct dvb_frontend *fe)
-{
-	return s5h1411_set_powerstate(fe, 1);
-}
-
-static int s5h1411_register_reset(struct dvb_frontend *fe)
-{
-	struct s5h1411_state *state = fe->demodulator_priv;
-
-	dprintk("%s()\n", __func__);
-
-	return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf3, 0);
-}
-
-/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int s5h1411_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct s5h1411_state *state = fe->demodulator_priv;
-
-	dprintk("%s(frequency=%d)\n", __func__, p->frequency);
-
-	s5h1411_softreset(fe);
-
-	state->current_frequency = p->frequency;
-
-	s5h1411_enable_modulation(fe, p->modulation);
-
-	if (fe->ops.tuner_ops.set_params) {
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-
-		fe->ops.tuner_ops.set_params(fe);
-
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	/* Issue a reset to the demod so it knows to resync against the
-	   newly tuned frequency */
-	s5h1411_softreset(fe);
-
-	return 0;
-}
-
-/* Reset the demod hardware and reset all of the configuration registers
-   to a default state. */
-static int s5h1411_init(struct dvb_frontend *fe)
-{
-	struct s5h1411_state *state = fe->demodulator_priv;
-	int i;
-
-	dprintk("%s()\n", __func__);
-
-	s5h1411_set_powerstate(fe, 0);
-	s5h1411_register_reset(fe);
-
-	for (i = 0; i < ARRAY_SIZE(init_tab); i++)
-		s5h1411_writereg(state, init_tab[i].addr,
-			init_tab[i].reg,
-			init_tab[i].data);
-
-	/* The datasheet says that after initialisation, VSB is default */
-	state->current_modulation = VSB_8;
-
-	/* Although the datasheet says it's in VSB, empirical evidence
-	   shows problems getting lock on the first tuning request.  Make
-	   sure we call enable_modulation the first time around */
-	state->first_tune = 1;
-
-	if (state->config->output_mode == S5H1411_SERIAL_OUTPUT)
-		/* Serial */
-		s5h1411_set_serialmode(fe, 1);
-	else
-		/* Parallel */
-		s5h1411_set_serialmode(fe, 0);
-
-	s5h1411_set_spectralinversion(fe, state->config->inversion);
-	s5h1411_set_if_freq(fe, state->config->vsb_if);
-	s5h1411_set_gpio(fe, state->config->gpio);
-	s5h1411_set_mpeg_timing(fe, state->config->mpeg_timing);
-	s5h1411_softreset(fe);
-
-	/* Note: Leaving the I2C gate closed. */
-	s5h1411_i2c_gate_ctrl(fe, 0);
-
-	return 0;
-}
-
-static int s5h1411_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct s5h1411_state *state = fe->demodulator_priv;
-	u16 reg;
-	u32 tuner_status = 0;
-
-	*status = 0;
-
-	/* Register F2 bit 15 = Master Lock, removed */
-
-	switch (state->current_modulation) {
-	case QAM_64:
-	case QAM_256:
-		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf0);
-		if (reg & 0x10) /* QAM FEC Lock */
-			*status |= FE_HAS_SYNC | FE_HAS_LOCK;
-		if (reg & 0x100) /* QAM EQ Lock */
-			*status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
-
-		break;
-	case VSB_8:
-		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2);
-		if (reg & 0x1000) /* FEC Lock */
-			*status |= FE_HAS_SYNC | FE_HAS_LOCK;
-		if (reg & 0x2000) /* EQ Lock */
-			*status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
-
-		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x53);
-		if (reg & 0x1) /* AFC Lock */
-			*status |= FE_HAS_SIGNAL;
-
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	switch (state->config->status_mode) {
-	case S5H1411_DEMODLOCKING:
-		if (*status & FE_HAS_VITERBI)
-			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
-		break;
-	case S5H1411_TUNERLOCKING:
-		/* Get the tuner status */
-		if (fe->ops.tuner_ops.get_status) {
-			if (fe->ops.i2c_gate_ctrl)
-				fe->ops.i2c_gate_ctrl(fe, 1);
-
-			fe->ops.tuner_ops.get_status(fe, &tuner_status);
-
-			if (fe->ops.i2c_gate_ctrl)
-				fe->ops.i2c_gate_ctrl(fe, 0);
-		}
-		if (tuner_status)
-			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
-		break;
-	}
-
-	dprintk("%s() status 0x%08x\n", __func__, *status);
-
-	return 0;
-}
-
-static int s5h1411_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
-{
-	int i, ret = -EINVAL;
-	dprintk("%s()\n", __func__);
-
-	for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
-		if (v < qam256_snr_tab[i].val) {
-			*snr = qam256_snr_tab[i].data;
-			ret = 0;
-			break;
-		}
-	}
-	return ret;
-}
-
-static int s5h1411_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
-{
-	int i, ret = -EINVAL;
-	dprintk("%s()\n", __func__);
-
-	for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
-		if (v < qam64_snr_tab[i].val) {
-			*snr = qam64_snr_tab[i].data;
-			ret = 0;
-			break;
-		}
-	}
-	return ret;
-}
-
-static int s5h1411_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
-{
-	int i, ret = -EINVAL;
-	dprintk("%s()\n", __func__);
-
-	for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
-		if (v > vsb_snr_tab[i].val) {
-			*snr = vsb_snr_tab[i].data;
-			ret = 0;
-			break;
-		}
-	}
-	dprintk("%s() snr=%d\n", __func__, *snr);
-	return ret;
-}
-
-static int s5h1411_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct s5h1411_state *state = fe->demodulator_priv;
-	u16 reg;
-	dprintk("%s()\n", __func__);
-
-	switch (state->current_modulation) {
-	case QAM_64:
-		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1);
-		return s5h1411_qam64_lookup_snr(fe, snr, reg);
-	case QAM_256:
-		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1);
-		return s5h1411_qam256_lookup_snr(fe, snr, reg);
-	case VSB_8:
-		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR,
-			0xf2) & 0x3ff;
-		return s5h1411_vsb_lookup_snr(fe, snr, reg);
-	default:
-		break;
-	}
-
-	return -EINVAL;
-}
-
-static int s5h1411_read_signal_strength(struct dvb_frontend *fe,
-	u16 *signal_strength)
-{
-	/* borrowed from lgdt330x.c
-	 *
-	 * Calculate strength from SNR up to 35dB
-	 * Even though the SNR can go higher than 35dB,
-	 * there is some comfort factor in having a range of
-	 * strong signals that can show at 100%
-	 */
-	u16 snr;
-	u32 tmp;
-	int ret = s5h1411_read_snr(fe, &snr);
-
-	*signal_strength = 0;
-
-	if (0 == ret) {
-		/* The following calculation method was chosen
-		 * purely for the sake of code re-use from the
-		 * other demod drivers that use this method */
-
-		/* Convert from SNR in dB * 10 to 8.24 fixed-point */
-		tmp = (snr * ((1 << 24) / 10));
-
-		/* Convert from 8.24 fixed-point to
-		 * scale the range 0 - 35*2^24 into 0 - 65535*/
-		if (tmp >= 8960 * 0x10000)
-			*signal_strength = 0xffff;
-		else
-			*signal_strength = tmp / 8960;
-	}
-
-	return ret;
-}
-
-static int s5h1411_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct s5h1411_state *state = fe->demodulator_priv;
-
-	*ucblocks = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xc9);
-
-	return 0;
-}
-
-static int s5h1411_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	return s5h1411_read_ucblocks(fe, ber);
-}
-
-static int s5h1411_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct s5h1411_state *state = fe->demodulator_priv;
-
-	p->frequency = state->current_frequency;
-	p->modulation = state->current_modulation;
-
-	return 0;
-}
-
-static int s5h1411_get_tune_settings(struct dvb_frontend *fe,
-				     struct dvb_frontend_tune_settings *tune)
-{
-	tune->min_delay_ms = 1000;
-	return 0;
-}
-
-static void s5h1411_release(struct dvb_frontend *fe)
-{
-	struct s5h1411_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops s5h1411_ops;
-
-struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config,
-				    struct i2c_adapter *i2c)
-{
-	struct s5h1411_state *state = NULL;
-	u16 reg;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct s5h1411_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->current_modulation = VSB_8;
-	state->inversion = state->config->inversion;
-
-	/* check if the demod exists */
-	reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x05);
-	if (reg != 0x0066)
-		goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &s5h1411_ops,
-	       sizeof(struct dvb_frontend_ops));
-
-	state->frontend.demodulator_priv = state;
-
-	if (s5h1411_init(&state->frontend) != 0) {
-		printk(KERN_ERR "%s: Failed to initialize correctly\n",
-			__func__);
-		goto error;
-	}
-
-	/* Note: Leaving the I2C gate open here. */
-	s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1);
-
-	/* Put the device into low-power mode until first use */
-	s5h1411_set_powerstate(&state->frontend, 1);
-
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(s5h1411_attach);
-
-static struct dvb_frontend_ops s5h1411_ops = {
-	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
-	.info = {
-		.name			= "Samsung S5H1411 QAM/8VSB Frontend",
-		.frequency_min		= 54000000,
-		.frequency_max		= 858000000,
-		.frequency_stepsize	= 62500,
-		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
-	},
-
-	.init                 = s5h1411_init,
-	.sleep                = s5h1411_sleep,
-	.i2c_gate_ctrl        = s5h1411_i2c_gate_ctrl,
-	.set_frontend         = s5h1411_set_frontend,
-	.get_frontend         = s5h1411_get_frontend,
-	.get_tune_settings    = s5h1411_get_tune_settings,
-	.read_status          = s5h1411_read_status,
-	.read_ber             = s5h1411_read_ber,
-	.read_signal_strength = s5h1411_read_signal_strength,
-	.read_snr             = s5h1411_read_snr,
-	.read_ucblocks        = s5h1411_read_ucblocks,
-	.release              = s5h1411_release,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Enable verbose debug messages");
-
-MODULE_DESCRIPTION("Samsung S5H1411 QAM-B/ATSC Demodulator driver");
-MODULE_AUTHOR("Steven Toth");
-MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/dvb/frontends/s5h1411.h b/drivers/media/dvb/frontends/s5h1411.h
deleted file mode 100644
index 45ec0f8..0000000
--- a/drivers/media/dvb/frontends/s5h1411.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
-    Samsung S5H1411 VSB/QAM demodulator driver
-
-    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef __S5H1411_H__
-#define __S5H1411_H__
-
-#include <linux/dvb/frontend.h>
-
-#define S5H1411_I2C_TOP_ADDR (0x32 >> 1)
-#define S5H1411_I2C_QAM_ADDR (0x34 >> 1)
-
-struct s5h1411_config {
-
-	/* serial/parallel output */
-#define S5H1411_PARALLEL_OUTPUT 0
-#define S5H1411_SERIAL_OUTPUT   1
-	u8 output_mode;
-
-	/* GPIO Setting */
-#define S5H1411_GPIO_OFF 0
-#define S5H1411_GPIO_ON  1
-	u8 gpio;
-
-	/* MPEG signal timing */
-#define S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK       0
-#define S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK    1
-#define S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK    2
-#define S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
-	u16 mpeg_timing;
-
-	/* IF Freq for QAM and VSB in KHz */
-#define S5H1411_IF_3250  3250
-#define S5H1411_IF_3500  3500
-#define S5H1411_IF_4000  4000
-#define S5H1411_IF_5380  5380
-#define S5H1411_IF_44000 44000
-#define S5H1411_VSB_IF_DEFAULT S5H1411_IF_44000
-#define S5H1411_QAM_IF_DEFAULT S5H1411_IF_44000
-	u16 qam_if;
-	u16 vsb_if;
-
-	/* Spectral Inversion */
-#define S5H1411_INVERSION_OFF 0
-#define S5H1411_INVERSION_ON  1
-	u8 inversion;
-
-	/* Return lock status based on tuner lock, or demod lock */
-#define S5H1411_TUNERLOCKING 0
-#define S5H1411_DEMODLOCKING 1
-	u8 status_mode;
-};
-
-#if defined(CONFIG_DVB_S5H1411) || \
-	(defined(CONFIG_DVB_S5H1411_MODULE) && defined(MODULE))
-extern struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config,
-					   struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *s5h1411_attach(
-	const struct s5h1411_config *config,
-	struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_S5H1411 */
-
-#endif /* __S5H1411_H__ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
deleted file mode 100644
index e2fec9e..0000000
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ /dev/null
@@ -1,960 +0,0 @@
-/*
- * Driver for
- *    Samsung S5H1420 and
- *    PnpNetwork PN1010 QPSK Demodulator
- *
- * Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
- * Copyright (C) 2005-8 Patrick Boettcher <pb@linuxtv.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/jiffies.h>
-#include <asm/div64.h>
-
-#include <linux/i2c.h>
-
-
-#include "dvb_frontend.h"
-#include "s5h1420.h"
-#include "s5h1420_priv.h"
-
-#define TONE_FREQ 22000
-
-struct s5h1420_state {
-	struct i2c_adapter* i2c;
-	const struct s5h1420_config* config;
-
-	struct dvb_frontend frontend;
-	struct i2c_adapter tuner_i2c_adapter;
-
-	u8 CON_1_val;
-
-	u8 postlocked:1;
-	u32 fclk;
-	u32 tunedfreq;
-	fe_code_rate_t fec_inner;
-	u32 symbol_rate;
-
-	/* FIXME: ugly workaround for flexcop's incapable i2c-controller
-	 * it does not support repeated-start, workaround: write addr-1
-	 * and then read
-	 */
-	u8 shadow[256];
-};
-
-static u32 s5h1420_getsymbolrate(struct s5h1420_state* state);
-static int s5h1420_get_tune_settings(struct dvb_frontend* fe,
-				     struct dvb_frontend_tune_settings* fesettings);
-
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable debugging");
-
-#define dprintk(x...) do { \
-	if (debug) \
-		printk(KERN_DEBUG "S5H1420: " x); \
-} while (0)
-
-static u8 s5h1420_readreg(struct s5h1420_state *state, u8 reg)
-{
-	int ret;
-	u8 b[2];
-	struct i2c_msg msg[] = {
-		{ .addr = state->config->demod_address, .flags = 0, .buf = b, .len = 2 },
-		{ .addr = state->config->demod_address, .flags = 0, .buf = &reg, .len = 1 },
-		{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = 1 },
-	};
-
-	b[0] = (reg - 1) & 0xff;
-	b[1] = state->shadow[(reg - 1) & 0xff];
-
-	if (state->config->repeated_start_workaround) {
-		ret = i2c_transfer(state->i2c, msg, 3);
-		if (ret != 3)
-			return ret;
-	} else {
-		ret = i2c_transfer(state->i2c, &msg[1], 1);
-		if (ret != 1)
-			return ret;
-		ret = i2c_transfer(state->i2c, &msg[2], 1);
-		if (ret != 1)
-			return ret;
-	}
-
-	/* dprintk("rd(%02x): %02x %02x\n", state->config->demod_address, reg, b[0]); */
-
-	return b[0];
-}
-
-static int s5h1420_writereg (struct s5h1420_state* state, u8 reg, u8 data)
-{
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
-	int err;
-
-	/* dprintk("wr(%02x): %02x %02x\n", state->config->demod_address, reg, data); */
-	err = i2c_transfer(state->i2c, &msg, 1);
-	if (err != 1) {
-		dprintk("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
-		return -EREMOTEIO;
-	}
-	state->shadow[reg] = data;
-
-	return 0;
-}
-
-static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
-	struct s5h1420_state* state = fe->demodulator_priv;
-
-	dprintk("enter %s\n", __func__);
-
-	switch(voltage) {
-	case SEC_VOLTAGE_13:
-		s5h1420_writereg(state, 0x3c,
-				 (s5h1420_readreg(state, 0x3c) & 0xfe) | 0x02);
-		break;
-
-	case SEC_VOLTAGE_18:
-		s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) | 0x03);
-		break;
-
-	case SEC_VOLTAGE_OFF:
-		s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) & 0xfd);
-		break;
-	}
-
-	dprintk("leave %s\n", __func__);
-	return 0;
-}
-
-static int s5h1420_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
-	struct s5h1420_state* state = fe->demodulator_priv;
-
-	dprintk("enter %s\n", __func__);
-	switch(tone) {
-	case SEC_TONE_ON:
-		s5h1420_writereg(state, 0x3b,
-				 (s5h1420_readreg(state, 0x3b) & 0x74) | 0x08);
-		break;
-
-	case SEC_TONE_OFF:
-		s5h1420_writereg(state, 0x3b,
-				 (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01);
-		break;
-	}
-	dprintk("leave %s\n", __func__);
-
-	return 0;
-}
-
-static int s5h1420_send_master_cmd (struct dvb_frontend* fe,
-				    struct dvb_diseqc_master_cmd* cmd)
-{
-	struct s5h1420_state* state = fe->demodulator_priv;
-	u8 val;
-	int i;
-	unsigned long timeout;
-	int result = 0;
-
-	dprintk("enter %s\n", __func__);
-	if (cmd->msg_len > 8)
-		return -EINVAL;
-
-	/* setup for DISEQC */
-	val = s5h1420_readreg(state, 0x3b);
-	s5h1420_writereg(state, 0x3b, 0x02);
-	msleep(15);
-
-	/* write the DISEQC command bytes */
-	for(i=0; i< cmd->msg_len; i++) {
-		s5h1420_writereg(state, 0x3d + i, cmd->msg[i]);
-	}
-
-	/* kick off transmission */
-	s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) |
-				      ((cmd->msg_len-1) << 4) | 0x08);
-
-	/* wait for transmission to complete */
-	timeout = jiffies + ((100*HZ) / 1000);
-	while(time_before(jiffies, timeout)) {
-		if (!(s5h1420_readreg(state, 0x3b) & 0x08))
-			break;
-
-		msleep(5);
-	}
-	if (time_after(jiffies, timeout))
-		result = -ETIMEDOUT;
-
-	/* restore original settings */
-	s5h1420_writereg(state, 0x3b, val);
-	msleep(15);
-	dprintk("leave %s\n", __func__);
-	return result;
-}
-
-static int s5h1420_recv_slave_reply (struct dvb_frontend* fe,
-				     struct dvb_diseqc_slave_reply* reply)
-{
-	struct s5h1420_state* state = fe->demodulator_priv;
-	u8 val;
-	int i;
-	int length;
-	unsigned long timeout;
-	int result = 0;
-
-	/* setup for DISEQC receive */
-	val = s5h1420_readreg(state, 0x3b);
-	s5h1420_writereg(state, 0x3b, 0x82); /* FIXME: guess - do we need to set DIS_RDY(0x08) in receive mode? */
-	msleep(15);
-
-	/* wait for reception to complete */
-	timeout = jiffies + ((reply->timeout*HZ) / 1000);
-	while(time_before(jiffies, timeout)) {
-		if (!(s5h1420_readreg(state, 0x3b) & 0x80)) /* FIXME: do we test DIS_RDY(0x08) or RCV_EN(0x80)? */
-			break;
-
-		msleep(5);
-	}
-	if (time_after(jiffies, timeout)) {
-		result = -ETIMEDOUT;
-		goto exit;
-	}
-
-	/* check error flag - FIXME: not sure what this does - docs do not describe
-	 * beyond "error flag for diseqc receive data :( */
-	if (s5h1420_readreg(state, 0x49)) {
-		result = -EIO;
-		goto exit;
-	}
-
-	/* check length */
-	length = (s5h1420_readreg(state, 0x3b) & 0x70) >> 4;
-	if (length > sizeof(reply->msg)) {
-		result = -EOVERFLOW;
-		goto exit;
-	}
-	reply->msg_len = length;
-
-	/* extract data */
-	for(i=0; i< length; i++) {
-		reply->msg[i] = s5h1420_readreg(state, 0x3d + i);
-	}
-
-exit:
-	/* restore original settings */
-	s5h1420_writereg(state, 0x3b, val);
-	msleep(15);
-	return result;
-}
-
-static int s5h1420_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
-{
-	struct s5h1420_state* state = fe->demodulator_priv;
-	u8 val;
-	int result = 0;
-	unsigned long timeout;
-
-	/* setup for tone burst */
-	val = s5h1420_readreg(state, 0x3b);
-	s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x70) | 0x01);
-
-	/* set value for B position if requested */
-	if (minicmd == SEC_MINI_B) {
-		s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x04);
-	}
-	msleep(15);
-
-	/* start transmission */
-	s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x08);
-
-	/* wait for transmission to complete */
-	timeout = jiffies + ((100*HZ) / 1000);
-	while(time_before(jiffies, timeout)) {
-		if (!(s5h1420_readreg(state, 0x3b) & 0x08))
-			break;
-
-		msleep(5);
-	}
-	if (time_after(jiffies, timeout))
-		result = -ETIMEDOUT;
-
-	/* restore original settings */
-	s5h1420_writereg(state, 0x3b, val);
-	msleep(15);
-	return result;
-}
-
-static fe_status_t s5h1420_get_status_bits(struct s5h1420_state* state)
-{
-	u8 val;
-	fe_status_t status = 0;
-
-	val = s5h1420_readreg(state, 0x14);
-	if (val & 0x02)
-		status |=  FE_HAS_SIGNAL;
-	if (val & 0x01)
-		status |=  FE_HAS_CARRIER;
-	val = s5h1420_readreg(state, 0x36);
-	if (val & 0x01)
-		status |=  FE_HAS_VITERBI;
-	if (val & 0x20)
-		status |=  FE_HAS_SYNC;
-	if (status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI|FE_HAS_SYNC))
-		status |=  FE_HAS_LOCK;
-
-	return status;
-}
-
-static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct s5h1420_state* state = fe->demodulator_priv;
-	u8 val;
-
-	dprintk("enter %s\n", __func__);
-
-	if (status == NULL)
-		return -EINVAL;
-
-	/* determine lock state */
-	*status = s5h1420_get_status_bits(state);
-
-	/* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert
-	the inversion, wait a bit and check again */
-	if (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI)) {
-		val = s5h1420_readreg(state, Vit10);
-		if ((val & 0x07) == 0x03) {
-			if (val & 0x08)
-				s5h1420_writereg(state, Vit09, 0x13);
-			else
-				s5h1420_writereg(state, Vit09, 0x1b);
-
-			/* wait a bit then update lock status */
-			mdelay(200);
-			*status = s5h1420_get_status_bits(state);
-		}
-	}
-
-	/* perform post lock setup */
-	if ((*status & FE_HAS_LOCK) && !state->postlocked) {
-
-		/* calculate the data rate */
-		u32 tmp = s5h1420_getsymbolrate(state);
-		switch (s5h1420_readreg(state, Vit10) & 0x07) {
-		case 0: tmp = (tmp * 2 * 1) / 2; break;
-		case 1: tmp = (tmp * 2 * 2) / 3; break;
-		case 2: tmp = (tmp * 2 * 3) / 4; break;
-		case 3: tmp = (tmp * 2 * 5) / 6; break;
-		case 4: tmp = (tmp * 2 * 6) / 7; break;
-		case 5: tmp = (tmp * 2 * 7) / 8; break;
-		}
-
-		if (tmp == 0) {
-			printk(KERN_ERR "s5h1420: avoided division by 0\n");
-			tmp = 1;
-		}
-		tmp = state->fclk / tmp;
-
-
-		/* set the MPEG_CLK_INTL for the calculated data rate */
-		if (tmp < 2)
-			val = 0x00;
-		else if (tmp < 5)
-			val = 0x01;
-		else if (tmp < 9)
-			val = 0x02;
-		else if (tmp < 13)
-			val = 0x03;
-		else if (tmp < 17)
-			val = 0x04;
-		else if (tmp < 25)
-			val = 0x05;
-		else if (tmp < 33)
-			val = 0x06;
-		else
-			val = 0x07;
-		dprintk("for MPEG_CLK_INTL %d %x\n", tmp, val);
-
-		s5h1420_writereg(state, FEC01, 0x18);
-		s5h1420_writereg(state, FEC01, 0x10);
-		s5h1420_writereg(state, FEC01, val);
-
-		/* Enable "MPEG_Out" */
-		val = s5h1420_readreg(state, Mpeg02);
-		s5h1420_writereg(state, Mpeg02, val | (1 << 6));
-
-		/* kicker disable */
-		val = s5h1420_readreg(state, QPSK01) & 0x7f;
-		s5h1420_writereg(state, QPSK01, val);
-
-		/* DC freeze TODO it was never activated by default or it can stay activated */
-
-		if (s5h1420_getsymbolrate(state) >= 20000000) {
-			s5h1420_writereg(state, Loop04, 0x8a);
-			s5h1420_writereg(state, Loop05, 0x6a);
-		} else {
-			s5h1420_writereg(state, Loop04, 0x58);
-			s5h1420_writereg(state, Loop05, 0x27);
-		}
-
-		/* post-lock processing has been done! */
-		state->postlocked = 1;
-	}
-
-	dprintk("leave %s\n", __func__);
-
-	return 0;
-}
-
-static int s5h1420_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	struct s5h1420_state* state = fe->demodulator_priv;
-
-	s5h1420_writereg(state, 0x46, 0x1d);
-	mdelay(25);
-
-	*ber = (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47);
-
-	return 0;
-}
-
-static int s5h1420_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-{
-	struct s5h1420_state* state = fe->demodulator_priv;
-
-	u8 val = s5h1420_readreg(state, 0x15);
-
-	*strength =  (u16) ((val << 8) | val);
-
-	return 0;
-}
-
-static int s5h1420_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	struct s5h1420_state* state = fe->demodulator_priv;
-
-	s5h1420_writereg(state, 0x46, 0x1f);
-	mdelay(25);
-
-	*ucblocks = (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47);
-
-	return 0;
-}
-
-static void s5h1420_reset(struct s5h1420_state* state)
-{
-	dprintk("%s\n", __func__);
-	s5h1420_writereg (state, 0x01, 0x08);
-	s5h1420_writereg (state, 0x01, 0x00);
-	udelay(10);
-}
-
-static void s5h1420_setsymbolrate(struct s5h1420_state* state,
-				  struct dtv_frontend_properties *p)
-{
-	u8 v;
-	u64 val;
-
-	dprintk("enter %s\n", __func__);
-
-	val = ((u64) p->symbol_rate / 1000ULL) * (1ULL<<24);
-	if (p->symbol_rate < 29000000)
-		val *= 2;
-	do_div(val, (state->fclk / 1000));
-
-	dprintk("symbol rate register: %06llx\n", (unsigned long long)val);
-
-	v = s5h1420_readreg(state, Loop01);
-	s5h1420_writereg(state, Loop01, v & 0x7f);
-	s5h1420_writereg(state, Tnco01, val >> 16);
-	s5h1420_writereg(state, Tnco02, val >> 8);
-	s5h1420_writereg(state, Tnco03, val & 0xff);
-	s5h1420_writereg(state, Loop01,  v | 0x80);
-	dprintk("leave %s\n", __func__);
-}
-
-static u32 s5h1420_getsymbolrate(struct s5h1420_state* state)
-{
-	return state->symbol_rate;
-}
-
-static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset)
-{
-	int val;
-	u8 v;
-
-	dprintk("enter %s\n", __func__);
-
-	/* remember freqoffset is in kHz, but the chip wants the offset in Hz, so
-	 * divide fclk by 1000000 to get the correct value. */
-	val = -(int) ((freqoffset * (1<<24)) / (state->fclk / 1000000));
-
-	dprintk("phase rotator/freqoffset: %d %06x\n", freqoffset, val);
-
-	v = s5h1420_readreg(state, Loop01);
-	s5h1420_writereg(state, Loop01, v & 0xbf);
-	s5h1420_writereg(state, Pnco01, val >> 16);
-	s5h1420_writereg(state, Pnco02, val >> 8);
-	s5h1420_writereg(state, Pnco03, val & 0xff);
-	s5h1420_writereg(state, Loop01, v | 0x40);
-	dprintk("leave %s\n", __func__);
-}
-
-static int s5h1420_getfreqoffset(struct s5h1420_state* state)
-{
-	int val;
-
-	s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08);
-	val  = s5h1420_readreg(state, 0x0e) << 16;
-	val |= s5h1420_readreg(state, 0x0f) << 8;
-	val |= s5h1420_readreg(state, 0x10);
-	s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7);
-
-	if (val & 0x800000)
-		val |= 0xff000000;
-
-	/* remember freqoffset is in kHz, but the chip wants the offset in Hz, so
-	 * divide fclk by 1000000 to get the correct value. */
-	val = (((-val) * (state->fclk/1000000)) / (1<<24));
-
-	return val;
-}
-
-static void s5h1420_setfec_inversion(struct s5h1420_state* state,
-				     struct dtv_frontend_properties *p)
-{
-	u8 inversion = 0;
-	u8 vit08, vit09;
-
-	dprintk("enter %s\n", __func__);
-
-	if (p->inversion == INVERSION_OFF)
-		inversion = state->config->invert ? 0x08 : 0;
-	else if (p->inversion == INVERSION_ON)
-		inversion = state->config->invert ? 0 : 0x08;
-
-	if ((p->fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {
-		vit08 = 0x3f;
-		vit09 = 0;
-	} else {
-		switch (p->fec_inner) {
-		case FEC_1_2:
-			vit08 = 0x01; vit09 = 0x10;
-			break;
-
-		case FEC_2_3:
-			vit08 = 0x02; vit09 = 0x11;
-			break;
-
-		case FEC_3_4:
-			vit08 = 0x04; vit09 = 0x12;
-			break;
-
-		case FEC_5_6:
-			vit08 = 0x08; vit09 = 0x13;
-			break;
-
-		case FEC_6_7:
-			vit08 = 0x10; vit09 = 0x14;
-			break;
-
-		case FEC_7_8:
-			vit08 = 0x20; vit09 = 0x15;
-			break;
-
-		default:
-			return;
-		}
-	}
-	vit09 |= inversion;
-	dprintk("fec: %02x %02x\n", vit08, vit09);
-	s5h1420_writereg(state, Vit08, vit08);
-	s5h1420_writereg(state, Vit09, vit09);
-	dprintk("leave %s\n", __func__);
-}
-
-static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state)
-{
-	switch(s5h1420_readreg(state, 0x32) & 0x07) {
-	case 0:
-		return FEC_1_2;
-
-	case 1:
-		return FEC_2_3;
-
-	case 2:
-		return FEC_3_4;
-
-	case 3:
-		return FEC_5_6;
-
-	case 4:
-		return FEC_6_7;
-
-	case 5:
-		return FEC_7_8;
-	}
-
-	return FEC_NONE;
-}
-
-static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state)
-{
-	if (s5h1420_readreg(state, 0x32) & 0x08)
-		return INVERSION_ON;
-
-	return INVERSION_OFF;
-}
-
-static int s5h1420_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct s5h1420_state* state = fe->demodulator_priv;
-	int frequency_delta;
-	struct dvb_frontend_tune_settings fesettings;
-
-	dprintk("enter %s\n", __func__);
-
-	/* check if we should do a fast-tune */
-	s5h1420_get_tune_settings(fe, &fesettings);
-	frequency_delta = p->frequency - state->tunedfreq;
-	if ((frequency_delta > -fesettings.max_drift) &&
-			(frequency_delta < fesettings.max_drift) &&
-			(frequency_delta != 0) &&
-			(state->fec_inner == p->fec_inner) &&
-			(state->symbol_rate == p->symbol_rate)) {
-
-		if (fe->ops.tuner_ops.set_params) {
-			fe->ops.tuner_ops.set_params(fe);
-			if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-		}
-		if (fe->ops.tuner_ops.get_frequency) {
-			u32 tmp;
-			fe->ops.tuner_ops.get_frequency(fe, &tmp);
-			if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-			s5h1420_setfreqoffset(state, p->frequency - tmp);
-		} else {
-			s5h1420_setfreqoffset(state, 0);
-		}
-		dprintk("simple tune\n");
-		return 0;
-	}
-	dprintk("tuning demod\n");
-
-	/* first of all, software reset */
-	s5h1420_reset(state);
-
-	/* set s5h1420 fclk PLL according to desired symbol rate */
-	if (p->symbol_rate > 33000000)
-		state->fclk = 80000000;
-	else if (p->symbol_rate > 28500000)
-		state->fclk = 59000000;
-	else if (p->symbol_rate > 25000000)
-		state->fclk = 86000000;
-	else if (p->symbol_rate > 1900000)
-		state->fclk = 88000000;
-	else
-		state->fclk = 44000000;
-
-	dprintk("pll01: %d, ToneFreq: %d\n", state->fclk/1000000 - 8, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
-	s5h1420_writereg(state, PLL01, state->fclk/1000000 - 8);
-	s5h1420_writereg(state, PLL02, 0x40);
-	s5h1420_writereg(state, DiS01, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
-
-	/* TODO DC offset removal, config parameter ? */
-	if (p->symbol_rate > 29000000)
-		s5h1420_writereg(state, QPSK01, 0xae | 0x10);
-	else
-		s5h1420_writereg(state, QPSK01, 0xac | 0x10);
-
-	/* set misc registers */
-	s5h1420_writereg(state, CON_1, 0x00);
-	s5h1420_writereg(state, QPSK02, 0x00);
-	s5h1420_writereg(state, Pre01, 0xb0);
-
-	s5h1420_writereg(state, Loop01, 0xF0);
-	s5h1420_writereg(state, Loop02, 0x2a); /* e7 for s5h1420 */
-	s5h1420_writereg(state, Loop03, 0x79); /* 78 for s5h1420 */
-	if (p->symbol_rate > 20000000)
-		s5h1420_writereg(state, Loop04, 0x79);
-	else
-		s5h1420_writereg(state, Loop04, 0x58);
-	s5h1420_writereg(state, Loop05, 0x6b);
-
-	if (p->symbol_rate >= 8000000)
-		s5h1420_writereg(state, Post01, (0 << 6) | 0x10);
-	else if (p->symbol_rate >= 4000000)
-		s5h1420_writereg(state, Post01, (1 << 6) | 0x10);
-	else
-		s5h1420_writereg(state, Post01, (3 << 6) | 0x10);
-
-	s5h1420_writereg(state, Monitor12, 0x00); /* unfreeze DC compensation */
-
-	s5h1420_writereg(state, Sync01, 0x33);
-	s5h1420_writereg(state, Mpeg01, state->config->cdclk_polarity);
-	s5h1420_writereg(state, Mpeg02, 0x3d); /* Parallel output more, disabled -> enabled later */
-	s5h1420_writereg(state, Err01, 0x03); /* 0x1d for s5h1420 */
-
-	s5h1420_writereg(state, Vit06, 0x6e); /* 0x8e for s5h1420 */
-	s5h1420_writereg(state, DiS03, 0x00);
-	s5h1420_writereg(state, Rf01, 0x61); /* Tuner i2c address - for the gate controller */
-
-	/* set tuner PLL */
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-		s5h1420_setfreqoffset(state, 0);
-	}
-
-	/* set the reset of the parameters */
-	s5h1420_setsymbolrate(state, p);
-	s5h1420_setfec_inversion(state, p);
-
-	/* start QPSK */
-	s5h1420_writereg(state, QPSK01, s5h1420_readreg(state, QPSK01) | 1);
-
-	state->fec_inner = p->fec_inner;
-	state->symbol_rate = p->symbol_rate;
-	state->postlocked = 0;
-	state->tunedfreq = p->frequency;
-
-	dprintk("leave %s\n", __func__);
-	return 0;
-}
-
-static int s5h1420_get_frontend(struct dvb_frontend* fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct s5h1420_state* state = fe->demodulator_priv;
-
-	p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state);
-	p->inversion = s5h1420_getinversion(state);
-	p->symbol_rate = s5h1420_getsymbolrate(state);
-	p->fec_inner = s5h1420_getfec(state);
-
-	return 0;
-}
-
-static int s5h1420_get_tune_settings(struct dvb_frontend* fe,
-				     struct dvb_frontend_tune_settings* fesettings)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	if (p->symbol_rate > 20000000) {
-		fesettings->min_delay_ms = 50;
-		fesettings->step_size = 2000;
-		fesettings->max_drift = 8000;
-	} else if (p->symbol_rate > 12000000) {
-		fesettings->min_delay_ms = 100;
-		fesettings->step_size = 1500;
-		fesettings->max_drift = 9000;
-	} else if (p->symbol_rate > 8000000) {
-		fesettings->min_delay_ms = 100;
-		fesettings->step_size = 1000;
-		fesettings->max_drift = 8000;
-	} else if (p->symbol_rate > 4000000) {
-		fesettings->min_delay_ms = 100;
-		fesettings->step_size = 500;
-		fesettings->max_drift = 7000;
-	} else if (p->symbol_rate > 2000000) {
-		fesettings->min_delay_ms = 200;
-		fesettings->step_size = (p->symbol_rate / 8000);
-		fesettings->max_drift = 14 * fesettings->step_size;
-	} else {
-		fesettings->min_delay_ms = 200;
-		fesettings->step_size = (p->symbol_rate / 8000);
-		fesettings->max_drift = 18 * fesettings->step_size;
-	}
-
-	return 0;
-}
-
-static int s5h1420_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
-{
-	struct s5h1420_state* state = fe->demodulator_priv;
-
-	if (enable)
-		return s5h1420_writereg(state, 0x02, state->CON_1_val | 1);
-	else
-		return s5h1420_writereg(state, 0x02, state->CON_1_val & 0xfe);
-}
-
-static int s5h1420_init (struct dvb_frontend* fe)
-{
-	struct s5h1420_state* state = fe->demodulator_priv;
-
-	/* disable power down and do reset */
-	state->CON_1_val = state->config->serial_mpeg << 4;
-	s5h1420_writereg(state, 0x02, state->CON_1_val);
-	msleep(10);
-	s5h1420_reset(state);
-
-	return 0;
-}
-
-static int s5h1420_sleep(struct dvb_frontend* fe)
-{
-	struct s5h1420_state* state = fe->demodulator_priv;
-	state->CON_1_val = 0x12;
-	return s5h1420_writereg(state, 0x02, state->CON_1_val);
-}
-
-static void s5h1420_release(struct dvb_frontend* fe)
-{
-	struct s5h1420_state* state = fe->demodulator_priv;
-	i2c_del_adapter(&state->tuner_i2c_adapter);
-	kfree(state);
-}
-
-static u32 s5h1420_tuner_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static int s5h1420_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
-{
-	struct s5h1420_state *state = i2c_get_adapdata(i2c_adap);
-	struct i2c_msg m[1 + num];
-	u8 tx_open[2] = { CON_1, state->CON_1_val | 1 }; /* repeater stops once there was a stop condition */
-
-	memset(m, 0, sizeof(struct i2c_msg) * (1 + num));
-
-	m[0].addr = state->config->demod_address;
-	m[0].buf  = tx_open;
-	m[0].len  = 2;
-
-	memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
-
-	return i2c_transfer(state->i2c, m, 1+num) == 1 + num ? num : -EIO;
-}
-
-static struct i2c_algorithm s5h1420_tuner_i2c_algo = {
-	.master_xfer   = s5h1420_tuner_i2c_tuner_xfer,
-	.functionality = s5h1420_tuner_i2c_func,
-};
-
-struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe)
-{
-	struct s5h1420_state *state = fe->demodulator_priv;
-	return &state->tuner_i2c_adapter;
-}
-EXPORT_SYMBOL(s5h1420_get_tuner_i2c_adapter);
-
-static struct dvb_frontend_ops s5h1420_ops;
-
-struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
-				    struct i2c_adapter *i2c)
-{
-	/* allocate memory for the internal state */
-	struct s5h1420_state *state = kzalloc(sizeof(struct s5h1420_state), GFP_KERNEL);
-	u8 i;
-
-	if (state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->postlocked = 0;
-	state->fclk = 88000000;
-	state->tunedfreq = 0;
-	state->fec_inner = FEC_NONE;
-	state->symbol_rate = 0;
-
-	/* check if the demod is there + identify it */
-	i = s5h1420_readreg(state, ID01);
-	if (i != 0x03)
-		goto error;
-
-	memset(state->shadow, 0xff, sizeof(state->shadow));
-
-	for (i = 0; i < 0x50; i++)
-		state->shadow[i] = s5h1420_readreg(state, i);
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-
-	/* create tuner i2c adapter */
-	strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus",
-		sizeof(state->tuner_i2c_adapter.name));
-	state->tuner_i2c_adapter.algo      = &s5h1420_tuner_i2c_algo;
-	state->tuner_i2c_adapter.algo_data = NULL;
-	i2c_set_adapdata(&state->tuner_i2c_adapter, state);
-	if (i2c_add_adapter(&state->tuner_i2c_adapter) < 0) {
-		printk(KERN_ERR "S5H1420/PN1010: tuner i2c bus could not be initialized\n");
-		goto error;
-	}
-
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(s5h1420_attach);
-
-static struct dvb_frontend_ops s5h1420_ops = {
-	.delsys = { SYS_DVBS },
-	.info = {
-		.name     = "Samsung S5H1420/PnpNetwork PN1010 DVB-S",
-		.frequency_min    = 950000,
-		.frequency_max    = 2150000,
-		.frequency_stepsize = 125,     /* kHz for QPSK frontends */
-		.frequency_tolerance  = 29500,
-		.symbol_rate_min  = 1000000,
-		.symbol_rate_max  = 45000000,
-		/*  .symbol_rate_tolerance  = ???,*/
-		.caps = FE_CAN_INVERSION_AUTO |
-		FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-		FE_CAN_QPSK
-	},
-
-	.release = s5h1420_release,
-
-	.init = s5h1420_init,
-	.sleep = s5h1420_sleep,
-	.i2c_gate_ctrl = s5h1420_i2c_gate_ctrl,
-
-	.set_frontend = s5h1420_set_frontend,
-	.get_frontend = s5h1420_get_frontend,
-	.get_tune_settings = s5h1420_get_tune_settings,
-
-	.read_status = s5h1420_read_status,
-	.read_ber = s5h1420_read_ber,
-	.read_signal_strength = s5h1420_read_signal_strength,
-	.read_ucblocks = s5h1420_read_ucblocks,
-
-	.diseqc_send_master_cmd = s5h1420_send_master_cmd,
-	.diseqc_recv_slave_reply = s5h1420_recv_slave_reply,
-	.diseqc_send_burst = s5h1420_send_burst,
-	.set_tone = s5h1420_set_tone,
-	.set_voltage = s5h1420_set_voltage,
-};
-
-MODULE_DESCRIPTION("Samsung S5H1420/PnpNetwork PN1010 DVB-S Demodulator driver");
-MODULE_AUTHOR("Andrew de Quincey, Patrick Boettcher");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h
deleted file mode 100644
index ff30813..0000000
--- a/drivers/media/dvb/frontends/s5h1420.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Driver for
- *    Samsung S5H1420 and
- *    PnpNetwork PN1010 QPSK Demodulator
- *
- * Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
- * Copyright (C) 2005-8 Patrick Boettcher <pb@linuxtv.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#ifndef S5H1420_H
-#define S5H1420_H
-
-#include <linux/dvb/frontend.h>
-
-struct s5h1420_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* does the inversion require inversion? */
-	u8 invert:1;
-
-	u8 repeated_start_workaround:1;
-	u8 cdclk_polarity:1; /* 1 == falling edge, 0 == raising edge */
-
-	u8 serial_mpeg:1;
-};
-
-#if defined(CONFIG_DVB_S5H1420) || (defined(CONFIG_DVB_S5H1420_MODULE) && defined(MODULE))
-extern struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
-	     struct i2c_adapter *i2c);
-extern struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe);
-#else
-static inline struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
-					   struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe)
-{
-	return NULL;
-}
-#endif // CONFIG_DVB_S5H1420
-
-#endif // S5H1420_H
diff --git a/drivers/media/dvb/frontends/s5h1420_priv.h b/drivers/media/dvb/frontends/s5h1420_priv.h
deleted file mode 100644
index d9c58d2..0000000
--- a/drivers/media/dvb/frontends/s5h1420_priv.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Driver for
- *    Samsung S5H1420 and
- *    PnpNetwork PN1010 QPSK Demodulator
- *
- * Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
- * Copyright (C) 2005 Patrick Boettcher <pb@linuxtv.org>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 675 Mass
- * Ave, Cambridge, MA 02139, USA.
- */
-#ifndef S5H1420_PRIV
-#define S5H1420_PRIV
-
-#include <asm/types.h>
-
-enum s5h1420_register {
-	ID01      = 0x00,
-	CON_0     = 0x01,
-	CON_1     = 0x02,
-	PLL01     = 0x03,
-	PLL02     = 0x04,
-	QPSK01    = 0x05,
-	QPSK02    = 0x06,
-	Pre01     = 0x07,
-	Post01    = 0x08,
-	Loop01    = 0x09,
-	Loop02    = 0x0a,
-	Loop03    = 0x0b,
-	Loop04    = 0x0c,
-	Loop05    = 0x0d,
-	Pnco01    = 0x0e,
-	Pnco02    = 0x0f,
-	Pnco03    = 0x10,
-	Tnco01    = 0x11,
-	Tnco02    = 0x12,
-	Tnco03    = 0x13,
-	Monitor01 = 0x14,
-	Monitor02 = 0x15,
-	Monitor03 = 0x16,
-	Monitor04 = 0x17,
-	Monitor05 = 0x18,
-	Monitor06 = 0x19,
-	Monitor07 = 0x1a,
-	Monitor12 = 0x1f,
-
-	FEC01     = 0x22,
-	Soft01    = 0x23,
-	Soft02    = 0x24,
-	Soft03    = 0x25,
-	Soft04    = 0x26,
-	Soft05    = 0x27,
-	Soft06    = 0x28,
-	Vit01     = 0x29,
-	Vit02     = 0x2a,
-	Vit03     = 0x2b,
-	Vit04     = 0x2c,
-	Vit05     = 0x2d,
-	Vit06     = 0x2e,
-	Vit07     = 0x2f,
-	Vit08     = 0x30,
-	Vit09     = 0x31,
-	Vit10     = 0x32,
-	Vit11     = 0x33,
-	Vit12     = 0x34,
-	Sync01    = 0x35,
-	Sync02    = 0x36,
-	Rs01      = 0x37,
-	Mpeg01    = 0x38,
-	Mpeg02    = 0x39,
-	DiS01     = 0x3a,
-	DiS02     = 0x3b,
-	DiS03     = 0x3c,
-	DiS04     = 0x3d,
-	DiS05     = 0x3e,
-	DiS06     = 0x3f,
-	DiS07     = 0x40,
-	DiS08     = 0x41,
-	DiS09     = 0x42,
-	DiS10     = 0x43,
-	DiS11     = 0x44,
-	Rf01      = 0x45,
-	Err01     = 0x46,
-	Err02     = 0x47,
-	Err03     = 0x48,
-	Err04     = 0x49,
-};
-
-
-#endif
diff --git a/drivers/media/dvb/frontends/s5h1432.c b/drivers/media/dvb/frontends/s5h1432.c
deleted file mode 100644
index 8352ce1..0000000
--- a/drivers/media/dvb/frontends/s5h1432.c
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- *  Samsung s5h1432 DVB-T demodulator driver
- *
- *  Copyright (C) 2009 Bill Liu <Bill.Liu@Conexant.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include "dvb_frontend.h"
-#include "s5h1432.h"
-
-struct s5h1432_state {
-
-	struct i2c_adapter *i2c;
-
-	/* configuration settings */
-	const struct s5h1432_config *config;
-
-	struct dvb_frontend frontend;
-
-	fe_modulation_t current_modulation;
-	unsigned int first_tune:1;
-
-	u32 current_frequency;
-	int if_freq;
-
-	u8 inversion;
-};
-
-static int debug;
-
-#define dprintk(arg...) do {	\
-	if (debug)		\
-		printk(arg);	\
-	} while (0)
-
-static int s5h1432_writereg(struct s5h1432_state *state,
-			    u8 addr, u8 reg, u8 data)
-{
-	int ret;
-	u8 buf[] = { reg, data };
-
-	struct i2c_msg msg = {.addr = addr, .flags = 0, .buf = buf, .len = 2 };
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-
-	if (ret != 1)
-		printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, "
-		       "ret == %i)\n", __func__, addr, reg, data, ret);
-
-	return (ret != 1) ? -1 : 0;
-}
-
-static u8 s5h1432_readreg(struct s5h1432_state *state, u8 addr, u8 reg)
-{
-	int ret;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
-
-	struct i2c_msg msg[] = {
-		{.addr = addr, .flags = 0, .buf = b0, .len = 1},
-		{.addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 1}
-	};
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2)
-		printk(KERN_ERR "%s: readreg error (ret == %i)\n",
-		       __func__, ret);
-	return b1[0];
-}
-
-static int s5h1432_sleep(struct dvb_frontend *fe)
-{
-	return 0;
-}
-
-static int s5h1432_set_channel_bandwidth(struct dvb_frontend *fe,
-					 u32 bandwidth)
-{
-	struct s5h1432_state *state = fe->demodulator_priv;
-
-	u8 reg = 0;
-
-	/* Register [0x2E] bit 3:2 : 8MHz = 0; 7MHz = 1; 6MHz = 2 */
-	reg = s5h1432_readreg(state, S5H1432_I2C_TOP_ADDR, 0x2E);
-	reg &= ~(0x0C);
-	switch (bandwidth) {
-	case 6:
-		reg |= 0x08;
-		break;
-	case 7:
-		reg |= 0x04;
-		break;
-	case 8:
-		reg |= 0x00;
-		break;
-	default:
-		return 0;
-	}
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x2E, reg);
-	return 1;
-}
-
-static int s5h1432_set_IF(struct dvb_frontend *fe, u32 ifFreqHz)
-{
-	struct s5h1432_state *state = fe->demodulator_priv;
-
-	switch (ifFreqHz) {
-	case TAIWAN_HI_IF_FREQ_44_MHZ:
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x55);
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x55);
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0x15);
-		break;
-	case EUROPE_HI_IF_FREQ_36_MHZ:
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x00);
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x00);
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0x40);
-		break;
-	case IF_FREQ_6_MHZ:
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x00);
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x00);
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xe0);
-		break;
-	case IF_FREQ_3point3_MHZ:
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x66);
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x66);
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEE);
-		break;
-	case IF_FREQ_3point5_MHZ:
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x55);
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x55);
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xED);
-		break;
-	case IF_FREQ_4_MHZ:
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0xAA);
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0xAA);
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEA);
-		break;
-	default:
-		{
-			u32 value = 0;
-			value = (u32) (((48000 - (ifFreqHz / 1000)) * 512 *
-					(u32) 32768) / (48 * 1000));
-			printk(KERN_INFO
-			       "Default IFFreq %d :reg value = 0x%x\n",
-			       ifFreqHz, value);
-			s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4,
-					 (u8) value & 0xFF);
-			s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5,
-					 (u8) (value >> 8) & 0xFF);
-			s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7,
-					 (u8) (value >> 16) & 0xFF);
-			break;
-		}
-
-	}
-
-	return 1;
-}
-
-/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int s5h1432_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	u32 dvb_bandwidth = 8;
-	struct s5h1432_state *state = fe->demodulator_priv;
-
-	if (p->frequency == state->current_frequency) {
-		/*current_frequency = p->frequency; */
-		/*state->current_frequency = p->frequency; */
-	} else {
-		fe->ops.tuner_ops.set_params(fe);
-		msleep(300);
-		s5h1432_set_channel_bandwidth(fe, dvb_bandwidth);
-		switch (p->bandwidth_hz) {
-		case 6000000:
-			dvb_bandwidth = 6;
-			s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
-			break;
-		case 7000000:
-			dvb_bandwidth = 7;
-			s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
-			break;
-		case 8000000:
-			dvb_bandwidth = 8;
-			s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
-			break;
-		default:
-			return 0;
-		}
-		/*fe->ops.tuner_ops.set_params(fe); */
-/*Soft Reset chip*/
-		msleep(30);
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
-		msleep(30);
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
-
-		s5h1432_set_channel_bandwidth(fe, dvb_bandwidth);
-		switch (p->bandwidth_hz) {
-		case 6000000:
-			dvb_bandwidth = 6;
-			s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
-			break;
-		case 7000000:
-			dvb_bandwidth = 7;
-			s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
-			break;
-		case 8000000:
-			dvb_bandwidth = 8;
-			s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
-			break;
-		default:
-			return 0;
-		}
-		/*fe->ops.tuner_ops.set_params(fe); */
-		/*Soft Reset chip*/
-		msleep(30);
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
-		msleep(30);
-		s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
-
-	}
-
-	state->current_frequency = p->frequency;
-
-	return 0;
-}
-
-static int s5h1432_init(struct dvb_frontend *fe)
-{
-	struct s5h1432_state *state = fe->demodulator_priv;
-
-	u8 reg = 0;
-	state->current_frequency = 0;
-	printk(KERN_INFO " s5h1432_init().\n");
-
-	/*Set VSB mode as default, this also does a soft reset */
-	/*Initialize registers */
-
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x04, 0xa8);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x05, 0x01);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x07, 0x70);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x19, 0x80);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1b, 0x9D);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1c, 0x30);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1d, 0x20);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1e, 0x1B);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x2e, 0x40);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x42, 0x84);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x50, 0x5a);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x5a, 0xd3);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x68, 0x50);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xb8, 0x3c);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xc4, 0x10);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xcc, 0x9c);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xDA, 0x00);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe1, 0x94);
-	/* s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xf4, 0xa1); */
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xf9, 0x00);
-
-	/*For NXP tuner*/
-
-	/*Set 3.3MHz as default IF frequency */
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x66);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x66);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEE);
-	/* Set reg 0x1E to get the full dynamic range */
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1e, 0x31);
-
-	/* Mode setting in demod */
-	reg = s5h1432_readreg(state, S5H1432_I2C_TOP_ADDR, 0x42);
-	reg |= 0x80;
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x42, reg);
-	/* Serial mode */
-
-	/* Soft Reset chip */
-
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
-	msleep(30);
-	s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
-
-
-	return 0;
-}
-
-static int s5h1432_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	return 0;
-}
-
-static int s5h1432_read_signal_strength(struct dvb_frontend *fe,
-					u16 *signal_strength)
-{
-	return 0;
-}
-
-static int s5h1432_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	return 0;
-}
-
-static int s5h1432_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-
-	return 0;
-}
-
-static int s5h1432_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	return 0;
-}
-
-static int s5h1432_get_tune_settings(struct dvb_frontend *fe,
-				     struct dvb_frontend_tune_settings *tune)
-{
-	return 0;
-}
-
-static void s5h1432_release(struct dvb_frontend *fe)
-{
-	struct s5h1432_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops s5h1432_ops;
-
-struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config,
-				    struct i2c_adapter *i2c)
-{
-	struct s5h1432_state *state = NULL;
-
-	printk(KERN_INFO " Enter s5h1432_attach(). attach success!\n");
-	/* allocate memory for the internal state */
-	state = kmalloc(sizeof(struct s5h1432_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->current_modulation = QAM_16;
-	state->inversion = state->config->inversion;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &s5h1432_ops,
-	       sizeof(struct dvb_frontend_ops));
-
-	state->frontend.demodulator_priv = state;
-
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(s5h1432_attach);
-
-static struct dvb_frontend_ops s5h1432_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		 .name = "Samsung s5h1432 DVB-T Frontend",
-		 .frequency_min = 177000000,
-		 .frequency_max = 858000000,
-		 .frequency_stepsize = 166666,
-		 .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-		 FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER},
-
-	.init = s5h1432_init,
-	.sleep = s5h1432_sleep,
-	.set_frontend = s5h1432_set_frontend,
-	.get_tune_settings = s5h1432_get_tune_settings,
-	.read_status = s5h1432_read_status,
-	.read_ber = s5h1432_read_ber,
-	.read_signal_strength = s5h1432_read_signal_strength,
-	.read_snr = s5h1432_read_snr,
-	.read_ucblocks = s5h1432_read_ucblocks,
-	.release = s5h1432_release,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Enable verbose debug messages");
-
-MODULE_DESCRIPTION("Samsung s5h1432 DVB-T Demodulator driver");
-MODULE_AUTHOR("Bill Liu");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/s5h1432.h b/drivers/media/dvb/frontends/s5h1432.h
deleted file mode 100644
index b57438c..0000000
--- a/drivers/media/dvb/frontends/s5h1432.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- *  Samsung s5h1432 VSB/QAM demodulator driver
- *
- *  Copyright (C) 2009 Bill Liu <Bill.Liu@Conexant.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef __S5H1432_H__
-#define __S5H1432_H__
-
-#include <linux/dvb/frontend.h>
-
-#define S5H1432_I2C_TOP_ADDR (0x02 >> 1)
-
-#define TAIWAN_HI_IF_FREQ_44_MHZ 44000000
-#define EUROPE_HI_IF_FREQ_36_MHZ 36000000
-#define IF_FREQ_6_MHZ             6000000
-#define IF_FREQ_3point3_MHZ       3300000
-#define IF_FREQ_3point5_MHZ       3500000
-#define IF_FREQ_4_MHZ             4000000
-
-struct s5h1432_config {
-
-	/* serial/parallel output */
-#define S5H1432_PARALLEL_OUTPUT 0
-#define S5H1432_SERIAL_OUTPUT   1
-	u8 output_mode;
-
-	/* GPIO Setting */
-#define S5H1432_GPIO_OFF 0
-#define S5H1432_GPIO_ON  1
-	u8 gpio;
-
-	/* MPEG signal timing */
-#define S5H1432_MPEGTIMING_CONTINOUS_INVERTING_CLOCK       0
-#define S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK    1
-#define S5H1432_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK    2
-#define S5H1432_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
-	u16 mpeg_timing;
-
-	/* IF Freq for QAM and VSB in KHz */
-#define S5H1432_IF_3250  3250
-#define S5H1432_IF_3500  3500
-#define S5H1432_IF_4000  4000
-#define S5H1432_IF_5380  5380
-#define S5H1432_IF_44000 44000
-#define S5H1432_VSB_IF_DEFAULT s5h1432_IF_44000
-#define S5H1432_QAM_IF_DEFAULT s5h1432_IF_44000
-	u16 qam_if;
-	u16 vsb_if;
-
-	/* Spectral Inversion */
-#define S5H1432_INVERSION_OFF 0
-#define S5H1432_INVERSION_ON  1
-	u8 inversion;
-
-	/* Return lock status based on tuner lock, or demod lock */
-#define S5H1432_TUNERLOCKING 0
-#define S5H1432_DEMODLOCKING 1
-	u8 status_mode;
-};
-
-#if defined(CONFIG_DVB_S5H1432) || \
-	(defined(CONFIG_DVB_S5H1432_MODULE) && defined(MODULE))
-extern struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config,
-					   struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *s5h1432_attach(const struct s5h1432_config
-						  *config,
-						  struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_s5h1432 */
-
-#endif /* __s5h1432_H__ */
diff --git a/drivers/media/dvb/frontends/s921.c b/drivers/media/dvb/frontends/s921.c
deleted file mode 100644
index cd2288c..0000000
--- a/drivers/media/dvb/frontends/s921.c
+++ /dev/null
@@ -1,549 +0,0 @@
-/*
- *   Sharp VA3A5JZ921 One Seg Broadcast Module driver
- *   This device is labeled as just S. 921 at the top of the frontend can
- *
- *   Copyright (C) 2009-2010 Mauro Carvalho Chehab <mchehab@redhat.com>
- *   Copyright (C) 2009-2010 Douglas Landgraf <dougsland@redhat.com>
- *
- *   Developed for Leadership SBTVD 1seg device sold in Brazil
- *
- *   Frontend module based on cx24123 driver, getting some info from
- *	the old s921 driver.
- *
- *   FIXME: Need to port to DVB v5.2 API
- *
- *   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 version 2.
- *
- *   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 <asm/div64.h>
-
-#include "dvb_frontend.h"
-#include "s921.h"
-
-static int debug = 1;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
-
-#define rc(args...)  do {						\
-	printk(KERN_ERR  "s921: " args);				\
-} while (0)
-
-#define dprintk(args...)						\
-	do {								\
-		if (debug) {						\
-			printk(KERN_DEBUG "s921: %s: ", __func__);	\
-			printk(args);					\
-		}							\
-	} while (0)
-
-struct s921_state {
-	struct i2c_adapter *i2c;
-	const struct s921_config *config;
-
-	struct dvb_frontend frontend;
-
-	/* The Demod can't easily provide these, we cache them */
-	u32 currentfreq;
-};
-
-/*
- * Various tuner defaults need to be established for a given frequency kHz.
- * fixme: The bounds on the bands do not match the doc in real life.
- * fixme: Some of them have been moved, other might need adjustment.
- */
-static struct s921_bandselect_val {
-	u32 freq_low;
-	u8  band_reg;
-} s921_bandselect[] = {
-	{         0, 0x7b },
-	{ 485140000, 0x5b },
-	{ 515140000, 0x3b },
-	{ 545140000, 0x1b },
-	{ 599140000, 0xfb },
-	{ 623140000, 0xdb },
-	{ 659140000, 0xbb },
-	{ 713140000, 0x9b },
-};
-
-struct regdata {
-	u8 reg;
-	u8 data;
-};
-
-static struct regdata s921_init[] = {
-	{ 0x01, 0x80 },		/* Probably, a reset sequence */
-	{ 0x01, 0x40 },
-	{ 0x01, 0x80 },
-	{ 0x01, 0x40 },
-
-	{ 0x02, 0x00 },
-	{ 0x03, 0x40 },
-	{ 0x04, 0x01 },
-	{ 0x05, 0x00 },
-	{ 0x06, 0x00 },
-	{ 0x07, 0x00 },
-	{ 0x08, 0x00 },
-	{ 0x09, 0x00 },
-	{ 0x0a, 0x00 },
-	{ 0x0b, 0x5a },
-	{ 0x0c, 0x00 },
-	{ 0x0d, 0x00 },
-	{ 0x0f, 0x00 },
-	{ 0x13, 0x1b },
-	{ 0x14, 0x80 },
-	{ 0x15, 0x40 },
-	{ 0x17, 0x70 },
-	{ 0x18, 0x01 },
-	{ 0x19, 0x12 },
-	{ 0x1a, 0x01 },
-	{ 0x1b, 0x12 },
-	{ 0x1c, 0xa0 },
-	{ 0x1d, 0x00 },
-	{ 0x1e, 0x0a },
-	{ 0x1f, 0x08 },
-	{ 0x20, 0x40 },
-	{ 0x21, 0xff },
-	{ 0x22, 0x4c },
-	{ 0x23, 0x4e },
-	{ 0x24, 0x4c },
-	{ 0x25, 0x00 },
-	{ 0x26, 0x00 },
-	{ 0x27, 0xf4 },
-	{ 0x28, 0x60 },
-	{ 0x29, 0x88 },
-	{ 0x2a, 0x40 },
-	{ 0x2b, 0x40 },
-	{ 0x2c, 0xff },
-	{ 0x2d, 0x00 },
-	{ 0x2e, 0xff },
-	{ 0x2f, 0x00 },
-	{ 0x30, 0x20 },
-	{ 0x31, 0x06 },
-	{ 0x32, 0x0c },
-	{ 0x34, 0x0f },
-	{ 0x37, 0xfe },
-	{ 0x38, 0x00 },
-	{ 0x39, 0x63 },
-	{ 0x3a, 0x10 },
-	{ 0x3b, 0x10 },
-	{ 0x47, 0x00 },
-	{ 0x49, 0xe5 },
-	{ 0x4b, 0x00 },
-	{ 0x50, 0xc0 },
-	{ 0x52, 0x20 },
-	{ 0x54, 0x5a },
-	{ 0x55, 0x5b },
-	{ 0x56, 0x40 },
-	{ 0x57, 0x70 },
-	{ 0x5c, 0x50 },
-	{ 0x5d, 0x00 },
-	{ 0x62, 0x17 },
-	{ 0x63, 0x2f },
-	{ 0x64, 0x6f },
-	{ 0x68, 0x00 },
-	{ 0x69, 0x89 },
-	{ 0x6a, 0x00 },
-	{ 0x6b, 0x00 },
-	{ 0x6c, 0x00 },
-	{ 0x6d, 0x00 },
-	{ 0x6e, 0x00 },
-	{ 0x70, 0x10 },
-	{ 0x71, 0x00 },
-	{ 0x75, 0x00 },
-	{ 0x76, 0x30 },
-	{ 0x77, 0x01 },
-	{ 0xaf, 0x00 },
-	{ 0xb0, 0xa0 },
-	{ 0xb2, 0x3d },
-	{ 0xb3, 0x25 },
-	{ 0xb4, 0x8b },
-	{ 0xb5, 0x4b },
-	{ 0xb6, 0x3f },
-	{ 0xb7, 0xff },
-	{ 0xb8, 0xff },
-	{ 0xb9, 0xfc },
-	{ 0xba, 0x00 },
-	{ 0xbb, 0x00 },
-	{ 0xbc, 0x00 },
-	{ 0xd0, 0x30 },
-	{ 0xe4, 0x84 },
-	{ 0xf0, 0x48 },
-	{ 0xf1, 0x19 },
-	{ 0xf2, 0x5a },
-	{ 0xf3, 0x8e },
-	{ 0xf4, 0x2d },
-	{ 0xf5, 0x07 },
-	{ 0xf6, 0x5a },
-	{ 0xf7, 0xba },
-	{ 0xf8, 0xd7 },
-};
-
-static struct regdata s921_prefreq[] = {
-	{ 0x47, 0x60 },
-	{ 0x68, 0x00 },
-	{ 0x69, 0x89 },
-	{ 0xf0, 0x48 },
-	{ 0xf1, 0x19 },
-};
-
-static struct regdata s921_postfreq[] = {
-	{ 0xf5, 0xae },
-	{ 0xf6, 0xb7 },
-	{ 0xf7, 0xba },
-	{ 0xf8, 0xd7 },
-	{ 0x68, 0x0a },
-	{ 0x69, 0x09 },
-};
-
-static int s921_i2c_writereg(struct s921_state *state,
-			     u8 i2c_addr, int reg, int data)
-{
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = {
-		.addr = i2c_addr, .flags = 0, .buf = buf, .len = 2
-	};
-	int rc;
-
-	rc = i2c_transfer(state->i2c, &msg, 1);
-	if (rc != 1) {
-		printk("%s: writereg rcor(rc == %i, reg == 0x%02x,"
-			 " data == 0x%02x)\n", __func__, rc, reg, data);
-		return rc;
-	}
-
-	return 0;
-}
-
-static int s921_i2c_writeregdata(struct s921_state *state, u8 i2c_addr,
-				 struct regdata *rd, int size)
-{
-	int i, rc;
-
-	for (i = 0; i < size; i++) {
-		rc = s921_i2c_writereg(state, i2c_addr, rd[i].reg, rd[i].data);
-		if (rc < 0)
-			return rc;
-	}
-	return 0;
-}
-
-static int s921_i2c_readreg(struct s921_state *state, u8 i2c_addr, u8 reg)
-{
-	u8 val;
-	int rc;
-	struct i2c_msg msg[] = {
-		{ .addr = i2c_addr, .flags = 0, .buf = &reg, .len = 1 },
-		{ .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
-	};
-
-	rc = i2c_transfer(state->i2c, msg, 2);
-
-	if (rc != 2) {
-		rc("%s: reg=0x%x (rcor=%d)\n", __func__, reg, rc);
-		return rc;
-	}
-
-	return val;
-}
-
-#define s921_readreg(state, reg) \
-	s921_i2c_readreg(state, state->config->demod_address, reg)
-#define s921_writereg(state, reg, val) \
-	s921_i2c_writereg(state, state->config->demod_address, reg, val)
-#define s921_writeregdata(state, regdata) \
-	s921_i2c_writeregdata(state, state->config->demod_address, \
-	regdata, ARRAY_SIZE(regdata))
-
-static int s921_pll_tune(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct s921_state *state = fe->demodulator_priv;
-	int band, rc, i;
-	unsigned long f_offset;
-	u8 f_switch;
-	u64 offset;
-
-	dprintk("frequency=%i\n", p->frequency);
-
-	for (band = 0; band < ARRAY_SIZE(s921_bandselect); band++)
-		if (p->frequency < s921_bandselect[band].freq_low)
-			break;
-	band--;
-
-	if (band < 0) {
-		rc("%s: frequency out of range\n", __func__);
-		return -EINVAL;
-	}
-
-	f_switch = s921_bandselect[band].band_reg;
-
-	offset = ((u64)p->frequency) * 258;
-	do_div(offset, 6000000);
-	f_offset = ((unsigned long)offset) + 2321;
-
-	rc = s921_writeregdata(state, s921_prefreq);
-	if (rc < 0)
-		return rc;
-
-	rc = s921_writereg(state, 0xf2, (f_offset >> 8) & 0xff);
-	if (rc < 0)
-		return rc;
-
-	rc = s921_writereg(state, 0xf3, f_offset & 0xff);
-	if (rc < 0)
-		return rc;
-
-	rc = s921_writereg(state, 0xf4, f_switch);
-	if (rc < 0)
-		return rc;
-
-	rc = s921_writeregdata(state, s921_postfreq);
-	if (rc < 0)
-		return rc;
-
-	for (i = 0 ; i < 6; i++) {
-		rc = s921_readreg(state, 0x80);
-		dprintk("status 0x80: %02x\n", rc);
-	}
-	rc = s921_writereg(state, 0x01, 0x40);
-	if (rc < 0)
-		return rc;
-
-	rc = s921_readreg(state, 0x01);
-	dprintk("status 0x01: %02x\n", rc);
-
-	rc = s921_readreg(state, 0x80);
-	dprintk("status 0x80: %02x\n", rc);
-
-	rc = s921_readreg(state, 0x80);
-	dprintk("status 0x80: %02x\n", rc);
-
-	rc = s921_readreg(state, 0x32);
-	dprintk("status 0x32: %02x\n", rc);
-
-	dprintk("pll tune band=%d, pll=%d\n", f_switch, (int)f_offset);
-
-	return 0;
-}
-
-static int s921_initfe(struct dvb_frontend *fe)
-{
-	struct s921_state *state = fe->demodulator_priv;
-	int rc;
-
-	dprintk("\n");
-
-	rc = s921_writeregdata(state, s921_init);
-	if (rc < 0)
-		return rc;
-
-	return 0;
-}
-
-static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct s921_state *state = fe->demodulator_priv;
-	int regstatus, rc;
-
-	*status = 0;
-
-	rc = s921_readreg(state, 0x81);
-	if (rc < 0)
-		return rc;
-
-	regstatus = rc << 8;
-
-	rc = s921_readreg(state, 0x82);
-	if (rc < 0)
-		return rc;
-
-	regstatus |= rc;
-
-	dprintk("status = %04x\n", regstatus);
-
-	/* Full Sync - We don't know what each bit means on regs 0x81/0x82 */
-	if ((regstatus & 0xff) == 0x40) {
-		*status = FE_HAS_SIGNAL  |
-			  FE_HAS_CARRIER |
-			  FE_HAS_VITERBI |
-			  FE_HAS_SYNC    |
-			  FE_HAS_LOCK;
-	} else if (regstatus & 0x40) {
-		/* This is close to Full Sync, but not enough to get useful info */
-		*status = FE_HAS_SIGNAL  |
-			  FE_HAS_CARRIER |
-			  FE_HAS_VITERBI |
-			  FE_HAS_SYNC;
-	}
-
-	return 0;
-}
-
-static int s921_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	fe_status_t	status;
-	struct s921_state *state = fe->demodulator_priv;
-	int rc;
-
-	/* FIXME: Use the proper register for it... 0x80? */
-	rc = s921_read_status(fe, &status);
-	if (rc < 0)
-		return rc;
-
-	*strength = (status & FE_HAS_LOCK) ? 0xffff : 0;
-
-	dprintk("strength = 0x%04x\n", *strength);
-
-	rc = s921_readreg(state, 0x01);
-	dprintk("status 0x01: %02x\n", rc);
-
-	rc = s921_readreg(state, 0x80);
-	dprintk("status 0x80: %02x\n", rc);
-
-	rc = s921_readreg(state, 0x32);
-	dprintk("status 0x32: %02x\n", rc);
-
-	return 0;
-}
-
-static int s921_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct s921_state *state = fe->demodulator_priv;
-	int rc;
-
-	dprintk("\n");
-
-	/* FIXME: We don't know how to use non-auto mode */
-
-	rc = s921_pll_tune(fe);
-	if (rc < 0)
-		return rc;
-
-	state->currentfreq = p->frequency;
-
-	return 0;
-}
-
-static int s921_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct s921_state *state = fe->demodulator_priv;
-
-	/* FIXME: Probably it is possible to get it from regs f1 and f2 */
-	p->frequency = state->currentfreq;
-	p->delivery_system = SYS_ISDBT;
-
-	return 0;
-}
-
-static int s921_tune(struct dvb_frontend *fe,
-			bool re_tune,
-			unsigned int mode_flags,
-			unsigned int *delay,
-			fe_status_t *status)
-{
-	int rc = 0;
-
-	dprintk("\n");
-
-	if (re_tune)
-		rc = s921_set_frontend(fe);
-
-	if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
-		s921_read_status(fe, status);
-
-	return rc;
-}
-
-static int s921_get_algo(struct dvb_frontend *fe)
-{
-	return 1; /* FE_ALGO_HW */
-}
-
-static void s921_release(struct dvb_frontend *fe)
-{
-	struct s921_state *state = fe->demodulator_priv;
-
-	dprintk("\n");
-	kfree(state);
-}
-
-static struct dvb_frontend_ops s921_ops;
-
-struct dvb_frontend *s921_attach(const struct s921_config *config,
-				    struct i2c_adapter *i2c)
-{
-	/* allocate memory for the internal state */
-	struct s921_state *state =
-		kzalloc(sizeof(struct s921_state), GFP_KERNEL);
-
-	dprintk("\n");
-	if (state == NULL) {
-		rc("Unable to kzalloc\n");
-		goto rcor;
-	}
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &s921_ops,
-		sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-
-	return &state->frontend;
-
-rcor:
-	kfree(state);
-
-	return NULL;
-}
-EXPORT_SYMBOL(s921_attach);
-
-static struct dvb_frontend_ops s921_ops = {
-	.delsys = { SYS_ISDBT },
-	/* Use dib8000 values per default */
-	.info = {
-		.name = "Sharp S921",
-		.frequency_min = 470000000,
-		/*
-		 * Max should be 770MHz instead, according with Sharp docs,
-		 * but Leadership doc says it works up to 806 MHz. This is
-		 * required to get channel 69, used in Brazil
-		 */
-		.frequency_max = 806000000,
-		.frequency_tolerance = 0,
-		 .caps = FE_CAN_INVERSION_AUTO |
-			 FE_CAN_FEC_1_2  | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			 FE_CAN_FEC_5_6  | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			 FE_CAN_QPSK     | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
-			 FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
-			 FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER |
-			 FE_CAN_HIERARCHY_AUTO,
-	},
-
-	.release = s921_release,
-
-	.init = s921_initfe,
-	.set_frontend = s921_set_frontend,
-	.get_frontend = s921_get_frontend,
-	.read_status = s921_read_status,
-	.read_signal_strength = s921_read_signal_strength,
-	.tune = s921_tune,
-	.get_frontend_algo = s921_get_algo,
-};
-
-MODULE_DESCRIPTION("DVB Frontend module for Sharp S921 hardware");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_AUTHOR("Douglas Landgraf <dougsland@redhat.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/s921.h b/drivers/media/dvb/frontends/s921.h
deleted file mode 100644
index f220d82..0000000
--- a/drivers/media/dvb/frontends/s921.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- *   Sharp s921 driver
- *
- *   Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@redhat.com>
- *   Copyright (C) 2009 Douglas Landgraf <dougsland@redhat.com>
- *
- *   This program is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU General Public License as
- *   published by the Free Software Foundation version 2.
- *
- *   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 S921_H
-#define S921_H
-
-#include <linux/dvb/frontend.h>
-
-struct s921_config {
-	/* the demodulator's i2c address */
-	u8 demod_address;
-};
-
-#if defined(CONFIG_DVB_S921) || (defined(CONFIG_DVB_S921_MODULE) \
-	&& defined(MODULE))
-extern struct dvb_frontend *s921_attach(const struct s921_config *config,
-					   struct i2c_adapter *i2c);
-extern struct i2c_adapter *s921_get_tuner_i2c_adapter(struct dvb_frontend *);
-#else
-static inline struct dvb_frontend *s921_attach(
-	const struct s921_config *config, struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-static struct i2c_adapter *
-	s921_get_tuner_i2c_adapter(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* S921_H */
diff --git a/drivers/media/dvb/frontends/si21xx.c b/drivers/media/dvb/frontends/si21xx.c
deleted file mode 100644
index a68a648..0000000
--- a/drivers/media/dvb/frontends/si21xx.c
+++ /dev/null
@@ -1,951 +0,0 @@
-/* DVB compliant Linux driver for the DVB-S si2109/2110 demodulator
-*
-* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
-*
-*	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.
-*
-*/
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
-#include <asm/div64.h>
-
-#include "dvb_frontend.h"
-#include "si21xx.h"
-
-#define	REVISION_REG			0x00
-#define	SYSTEM_MODE_REG			0x01
-#define	TS_CTRL_REG_1			0x02
-#define	TS_CTRL_REG_2			0x03
-#define	PIN_CTRL_REG_1			0x04
-#define	PIN_CTRL_REG_2			0x05
-#define	LOCK_STATUS_REG_1		0x0f
-#define	LOCK_STATUS_REG_2		0x10
-#define	ACQ_STATUS_REG			0x11
-#define	ACQ_CTRL_REG_1			0x13
-#define	ACQ_CTRL_REG_2			0x14
-#define	PLL_DIVISOR_REG			0x15
-#define	COARSE_TUNE_REG			0x16
-#define	FINE_TUNE_REG_L			0x17
-#define	FINE_TUNE_REG_H			0x18
-
-#define	ANALOG_AGC_POWER_LEVEL_REG	0x28
-#define	CFO_ESTIMATOR_CTRL_REG_1	0x29
-#define	CFO_ESTIMATOR_CTRL_REG_2	0x2a
-#define	CFO_ESTIMATOR_CTRL_REG_3	0x2b
-
-#define	SYM_RATE_ESTIMATE_REG_L		0x31
-#define	SYM_RATE_ESTIMATE_REG_M		0x32
-#define	SYM_RATE_ESTIMATE_REG_H		0x33
-
-#define	CFO_ESTIMATOR_OFFSET_REG_L	0x36
-#define	CFO_ESTIMATOR_OFFSET_REG_H	0x37
-#define	CFO_ERROR_REG_L			0x38
-#define	CFO_ERROR_REG_H			0x39
-#define	SYM_RATE_ESTIMATOR_CTRL_REG	0x3a
-
-#define	SYM_RATE_REG_L			0x3f
-#define	SYM_RATE_REG_M			0x40
-#define	SYM_RATE_REG_H			0x41
-#define	SYM_RATE_ESTIMATOR_MAXIMUM_REG	0x42
-#define	SYM_RATE_ESTIMATOR_MINIMUM_REG	0x43
-
-#define	C_N_ESTIMATOR_CTRL_REG		0x7c
-#define	C_N_ESTIMATOR_THRSHLD_REG	0x7d
-#define	C_N_ESTIMATOR_LEVEL_REG_L	0x7e
-#define	C_N_ESTIMATOR_LEVEL_REG_H	0x7f
-
-#define	BLIND_SCAN_CTRL_REG		0x80
-
-#define	LSA_CTRL_REG_1			0x8D
-#define	SPCTRM_TILT_CORR_THRSHLD_REG	0x8f
-#define	ONE_DB_BNDWDTH_THRSHLD_REG	0x90
-#define	TWO_DB_BNDWDTH_THRSHLD_REG	0x91
-#define	THREE_DB_BNDWDTH_THRSHLD_REG	0x92
-#define	INBAND_POWER_THRSHLD_REG	0x93
-#define	REF_NOISE_LVL_MRGN_THRSHLD_REG	0x94
-
-#define	VIT_SRCH_CTRL_REG_1		0xa0
-#define	VIT_SRCH_CTRL_REG_2		0xa1
-#define	VIT_SRCH_CTRL_REG_3		0xa2
-#define	VIT_SRCH_STATUS_REG		0xa3
-#define	VITERBI_BER_COUNT_REG_L		0xab
-#define	REED_SOLOMON_CTRL_REG		0xb0
-#define	REED_SOLOMON_ERROR_COUNT_REG_L	0xb1
-#define	PRBS_CTRL_REG			0xb5
-
-#define	LNB_CTRL_REG_1			0xc0
-#define	LNB_CTRL_REG_2			0xc1
-#define	LNB_CTRL_REG_3			0xc2
-#define	LNB_CTRL_REG_4			0xc3
-#define	LNB_CTRL_STATUS_REG		0xc4
-#define	LNB_FIFO_REGS_0			0xc5
-#define	LNB_FIFO_REGS_1			0xc6
-#define	LNB_FIFO_REGS_2			0xc7
-#define	LNB_FIFO_REGS_3			0xc8
-#define	LNB_FIFO_REGS_4			0xc9
-#define	LNB_FIFO_REGS_5			0xca
-#define	LNB_SUPPLY_CTRL_REG_1		0xcb
-#define	LNB_SUPPLY_CTRL_REG_2		0xcc
-#define	LNB_SUPPLY_CTRL_REG_3		0xcd
-#define	LNB_SUPPLY_CTRL_REG_4		0xce
-#define	LNB_SUPPLY_STATUS_REG		0xcf
-
-#define FAIL	-1
-#define PASS	0
-
-#define ALLOWABLE_FS_COUNT	10
-#define STATUS_BER		0
-#define STATUS_UCBLOCKS		1
-
-static int debug;
-#define dprintk(args...) \
-	do { \
-		if (debug) \
-			printk(KERN_DEBUG "si21xx: " args); \
-	} while (0)
-
-enum {
-	ACTIVE_HIGH,
-	ACTIVE_LOW
-};
-enum {
-	BYTE_WIDE,
-	BIT_WIDE
-};
-enum {
-	CLK_GAPPED_MODE,
-	CLK_CONTINUOUS_MODE
-};
-enum {
-	RISING_EDGE,
-	FALLING_EDGE
-};
-enum {
-	MSB_FIRST,
-	LSB_FIRST
-};
-enum {
-	SERIAL,
-	PARALLEL
-};
-
-struct si21xx_state {
-	struct i2c_adapter *i2c;
-	const struct si21xx_config *config;
-	struct dvb_frontend frontend;
-	u8 initialised:1;
-	int errmode;
-	int fs;			/*Sampling rate of the ADC in MHz*/
-};
-
-/*	register default initialization */
-static u8 serit_sp1511lhb_inittab[] = {
-	0x01, 0x28,	/* set i2c_inc_disable */
-	0x20, 0x03,
-	0x27, 0x20,
-	0xe0, 0x45,
-	0xe1, 0x08,
-	0xfe, 0x01,
-	0x01, 0x28,
-	0x89, 0x09,
-	0x04, 0x80,
-	0x05, 0x01,
-	0x06, 0x00,
-	0x20, 0x03,
-	0x24, 0x88,
-	0x29, 0x09,
-	0x2a, 0x0f,
-	0x2c, 0x10,
-	0x2d, 0x19,
-	0x2e, 0x08,
-	0x2f, 0x10,
-	0x30, 0x19,
-	0x34, 0x20,
-	0x35, 0x03,
-	0x45, 0x02,
-	0x46, 0x45,
-	0x47, 0xd0,
-	0x48, 0x00,
-	0x49, 0x40,
-	0x4a, 0x03,
-	0x4c, 0xfd,
-	0x4f, 0x2e,
-	0x50, 0x2e,
-	0x51, 0x10,
-	0x52, 0x10,
-	0x56, 0x92,
-	0x59, 0x00,
-	0x5a, 0x2d,
-	0x5b, 0x33,
-	0x5c, 0x1f,
-	0x5f, 0x76,
-	0x62, 0xc0,
-	0x63, 0xc0,
-	0x64, 0xf3,
-	0x65, 0xf3,
-	0x79, 0x40,
-	0x6a, 0x40,
-	0x6b, 0x0a,
-	0x6c, 0x80,
-	0x6d, 0x27,
-	0x71, 0x06,
-	0x75, 0x60,
-	0x78, 0x00,
-	0x79, 0xb5,
-	0x7c, 0x05,
-	0x7d, 0x1a,
-	0x87, 0x55,
-	0x88, 0x72,
-	0x8f, 0x08,
-	0x90, 0xe0,
-	0x94, 0x40,
-	0xa0, 0x3f,
-	0xa1, 0xc0,
-	0xa4, 0xcc,
-	0xa5, 0x66,
-	0xa6, 0x66,
-	0xa7, 0x7b,
-	0xa8, 0x7b,
-	0xa9, 0x7b,
-	0xaa, 0x9a,
-	0xed, 0x04,
-	0xad, 0x00,
-	0xae, 0x03,
-	0xcc, 0xab,
-	0x01, 0x08,
-	0xff, 0xff
-};
-
-/*	low level read/writes */
-static int si21_writeregs(struct si21xx_state *state, u8 reg1,
-							u8 *data, int len)
-{
-	int ret;
-	u8 buf[60];/* = { reg1, data };*/
-	struct i2c_msg msg = {
-				.addr = state->config->demod_address,
-				.flags = 0,
-				.buf = buf,
-				.len = len + 1
-	};
-
-	msg.buf[0] =  reg1;
-	memcpy(msg.buf + 1, data, len);
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-
-	if (ret != 1)
-		dprintk("%s: writereg error (reg1 == 0x%02x, data == 0x%02x, "
-			"ret == %i)\n", __func__, reg1, data[0], ret);
-
-	return (ret != 1) ? -EREMOTEIO : 0;
-}
-
-static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data)
-{
-	int ret;
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = {
-				.addr = state->config->demod_address,
-				.flags = 0,
-				.buf = buf,
-				.len = 2
-	};
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-
-	if (ret != 1)
-		dprintk("%s: writereg error (reg == 0x%02x, data == 0x%02x, "
-			"ret == %i)\n", __func__, reg, data, ret);
-
-	return (ret != 1) ? -EREMOTEIO : 0;
-}
-
-static int si21_write(struct dvb_frontend *fe, const u8 buf[], int len)
-{
-	struct si21xx_state *state = fe->demodulator_priv;
-
-	if (len != 2)
-		return -EINVAL;
-
-	return si21_writereg(state, buf[0], buf[1]);
-}
-
-static u8 si21_readreg(struct si21xx_state *state, u8 reg)
-{
-	int ret;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
-	struct i2c_msg msg[] = {
-		{
-			.addr = state->config->demod_address,
-			.flags = 0,
-			.buf = b0,
-			.len = 1
-		}, {
-			.addr = state->config->demod_address,
-			.flags = I2C_M_RD,
-			.buf = b1,
-			.len = 1
-		}
-	};
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2)
-		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
-			__func__, reg, ret);
-
-	return b1[0];
-}
-
-static int si21_readregs(struct si21xx_state *state, u8 reg1, u8 *b, u8 len)
-{
-	int ret;
-	struct i2c_msg msg[] = {
-		{
-			.addr = state->config->demod_address,
-			.flags = 0,
-			.buf = &reg1,
-			.len = 1
-		}, {
-			.addr = state->config->demod_address,
-			.flags = I2C_M_RD,
-			.buf = b,
-			.len = len
-		}
-	};
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2)
-		dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
-
-	return ret == 2 ? 0 : -1;
-}
-
-static int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout)
-{
-	unsigned long start = jiffies;
-
-	dprintk("%s\n", __func__);
-
-	while ((si21_readreg(state, LNB_CTRL_REG_1) & 0x8) == 8) {
-		if (jiffies - start > timeout) {
-			dprintk("%s: timeout!!\n", __func__);
-			return -ETIMEDOUT;
-		}
-		msleep(10);
-	};
-
-	return 0;
-}
-
-static int si21xx_set_symbolrate(struct dvb_frontend *fe, u32 srate)
-{
-	struct si21xx_state *state = fe->demodulator_priv;
-	u32 sym_rate, data_rate;
-	int i;
-	u8 sym_rate_bytes[3];
-
-	dprintk("%s : srate = %i\n", __func__ , srate);
-
-	if ((srate < 1000000) || (srate > 45000000))
-		return -EINVAL;
-
-	data_rate = srate;
-	sym_rate = 0;
-
-	for (i = 0; i < 4; ++i) {
-		sym_rate /= 100;
-		sym_rate = sym_rate + ((data_rate % 100) * 0x800000) /
-								state->fs;
-		data_rate /= 100;
-	}
-	for (i = 0; i < 3; ++i)
-		sym_rate_bytes[i] = (u8)((sym_rate >> (i * 8)) & 0xff);
-
-	si21_writeregs(state, SYM_RATE_REG_L, sym_rate_bytes, 0x03);
-
-	return 0;
-}
-
-static int si21xx_send_diseqc_msg(struct dvb_frontend *fe,
-					struct dvb_diseqc_master_cmd *m)
-{
-	struct si21xx_state *state = fe->demodulator_priv;
-	u8 lnb_status;
-	u8 LNB_CTRL_1;
-	int status;
-
-	dprintk("%s\n", __func__);
-
-	status = PASS;
-	LNB_CTRL_1 = 0;
-
-	status |= si21_readregs(state, LNB_CTRL_STATUS_REG, &lnb_status, 0x01);
-	status |= si21_readregs(state, LNB_CTRL_REG_1, &lnb_status, 0x01);
-
-	/*fill the FIFO*/
-	status |= si21_writeregs(state, LNB_FIFO_REGS_0, m->msg, m->msg_len);
-
-	LNB_CTRL_1 = (lnb_status & 0x70);
-	LNB_CTRL_1 |= m->msg_len;
-
-	LNB_CTRL_1 |= 0x80;	/* begin LNB signaling */
-
-	status |= si21_writeregs(state, LNB_CTRL_REG_1, &LNB_CTRL_1, 0x01);
-
-	return status;
-}
-
-static int si21xx_send_diseqc_burst(struct dvb_frontend *fe,
-						fe_sec_mini_cmd_t burst)
-{
-	struct si21xx_state *state = fe->demodulator_priv;
-	u8 val;
-
-	dprintk("%s\n", __func__);
-
-	if (si21xx_wait_diseqc_idle(state, 100) < 0)
-		return -ETIMEDOUT;
-
-	val = (0x80 | si21_readreg(state, 0xc1));
-	if (si21_writereg(state, LNB_CTRL_REG_1,
-			burst == SEC_MINI_A ? (val & ~0x10) : (val | 0x10)))
-		return -EREMOTEIO;
-
-	if (si21xx_wait_diseqc_idle(state, 100) < 0)
-		return -ETIMEDOUT;
-
-	if (si21_writereg(state, LNB_CTRL_REG_1, val))
-		return -EREMOTEIO;
-
-	return 0;
-}
-/*	30.06.2008 */
-static int si21xx_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
-{
-	struct si21xx_state *state = fe->demodulator_priv;
-	u8 val;
-
-	dprintk("%s\n", __func__);
-	val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1));
-
-	switch (tone) {
-	case SEC_TONE_ON:
-		return si21_writereg(state, LNB_CTRL_REG_1, val | 0x20);
-
-	case SEC_TONE_OFF:
-		return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x20));
-
-	default:
-		return -EINVAL;
-	}
-}
-
-static int si21xx_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
-{
-	struct si21xx_state *state = fe->demodulator_priv;
-
-	u8 val;
-	dprintk("%s: %s\n", __func__,
-		volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
-		volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
-
-
-	val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1));
-
-	switch (volt) {
-	case SEC_VOLTAGE_18:
-		return si21_writereg(state, LNB_CTRL_REG_1, val | 0x40);
-		break;
-	case SEC_VOLTAGE_13:
-		return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x40));
-		break;
-	default:
-		return -EINVAL;
-	};
-}
-
-static int si21xx_init(struct dvb_frontend *fe)
-{
-	struct si21xx_state *state = fe->demodulator_priv;
-	int i;
-	int status = 0;
-	u8 reg1;
-	u8 val;
-	u8 reg2[2];
-
-	dprintk("%s\n", __func__);
-
-	for (i = 0; ; i += 2) {
-		reg1 = serit_sp1511lhb_inittab[i];
-		val = serit_sp1511lhb_inittab[i+1];
-		if (reg1 == 0xff && val == 0xff)
-			break;
-		si21_writeregs(state, reg1, &val, 1);
-	}
-
-	/*DVB QPSK SYSTEM MODE REG*/
-	reg1 = 0x08;
-	si21_writeregs(state, SYSTEM_MODE_REG, &reg1, 0x01);
-
-	/*transport stream config*/
-	/*
-	mode = PARALLEL;
-	sdata_form = LSB_FIRST;
-	clk_edge = FALLING_EDGE;
-	clk_mode = CLK_GAPPED_MODE;
-	strt_len = BYTE_WIDE;
-	sync_pol = ACTIVE_HIGH;
-	val_pol = ACTIVE_HIGH;
-	err_pol = ACTIVE_HIGH;
-	sclk_rate = 0x00;
-	parity = 0x00 ;
-	data_delay = 0x00;
-	clk_delay = 0x00;
-	pclk_smooth = 0x00;
-	*/
-	reg2[0] =
-		PARALLEL + (LSB_FIRST << 1)
-		+ (FALLING_EDGE << 2) + (CLK_GAPPED_MODE << 3)
-		+ (BYTE_WIDE << 4) + (ACTIVE_HIGH << 5)
-		+ (ACTIVE_HIGH << 6) + (ACTIVE_HIGH << 7);
-
-	reg2[1] = 0;
-	/*	sclk_rate + (parity << 2)
-		+ (data_delay << 3) + (clk_delay << 4)
-		+ (pclk_smooth << 5);
-	*/
-	status |= si21_writeregs(state, TS_CTRL_REG_1, reg2, 0x02);
-	if (status != 0)
-		dprintk(" %s : TS Set Error\n", __func__);
-
-	return 0;
-
-}
-
-static int si21_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct si21xx_state *state = fe->demodulator_priv;
-	u8 regs_read[2];
-	u8 reg_read;
-	u8 i;
-	u8 lock;
-	u8 signal = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG);
-
-	si21_readregs(state, LOCK_STATUS_REG_1, regs_read, 0x02);
-	reg_read = 0;
-
-	for (i = 0; i < 7; ++i)
-		reg_read |= ((regs_read[0] >> i) & 0x01) << (6 - i);
-
-	lock = ((reg_read & 0x7f) | (regs_read[1] & 0x80));
-
-	dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, lock);
-	*status = 0;
-
-	if (signal > 10)
-		*status |= FE_HAS_SIGNAL;
-
-	if (lock & 0x2)
-		*status |= FE_HAS_CARRIER;
-
-	if (lock & 0x20)
-		*status |= FE_HAS_VITERBI;
-
-	if (lock & 0x40)
-		*status |= FE_HAS_SYNC;
-
-	if ((lock & 0x7b) == 0x7b)
-		*status |= FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int si21_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct si21xx_state *state = fe->demodulator_priv;
-
-	/*status = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG,
-						(u8*)agclevel, 0x01);*/
-
-	u16 signal = (3 * si21_readreg(state, 0x27) *
-					si21_readreg(state, 0x28));
-
-	dprintk("%s : AGCPWR: 0x%02x%02x, signal=0x%04x\n", __func__,
-		si21_readreg(state, 0x27),
-		si21_readreg(state, 0x28), (int) signal);
-
-	signal  <<= 4;
-	*strength = signal;
-
-	return 0;
-}
-
-static int si21_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct si21xx_state *state = fe->demodulator_priv;
-
-	dprintk("%s\n", __func__);
-
-	if (state->errmode != STATUS_BER)
-		return 0;
-
-	*ber = (si21_readreg(state, 0x1d) << 8) |
-				si21_readreg(state, 0x1e);
-
-	return 0;
-}
-
-static int si21_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct si21xx_state *state = fe->demodulator_priv;
-
-	s32 xsnr = 0xffff - ((si21_readreg(state, 0x24) << 8) |
-					si21_readreg(state, 0x25));
-	xsnr = 3 * (xsnr - 0xa100);
-	*snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
-
-	dprintk("%s\n", __func__);
-
-	return 0;
-}
-
-static int si21_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct si21xx_state *state = fe->demodulator_priv;
-
-	dprintk("%s\n", __func__);
-
-	if (state->errmode != STATUS_UCBLOCKS)
-		*ucblocks = 0;
-	else
-		*ucblocks = (si21_readreg(state, 0x1d) << 8) |
-					si21_readreg(state, 0x1e);
-
-	return 0;
-}
-
-/*	initiates a channel acquisition sequence
-	using the specified symbol rate and code rate */
-static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate,
-						fe_code_rate_t crate)
-{
-
-	struct si21xx_state *state = fe->demodulator_priv;
-	u8 coderates[] = {
-				0x0, 0x01, 0x02, 0x04, 0x00,
-				0x8, 0x10, 0x20, 0x00, 0x3f
-	};
-
-	u8 coderate_ptr;
-	int status;
-	u8 start_acq = 0x80;
-	u8 reg, regs[3];
-
-	dprintk("%s\n", __func__);
-
-	status = PASS;
-	coderate_ptr = coderates[crate];
-
-	si21xx_set_symbolrate(fe, symbrate);
-
-	/* write code rates to use in the Viterbi search */
-	status |= si21_writeregs(state,
-				VIT_SRCH_CTRL_REG_1,
-				&coderate_ptr, 0x01);
-
-	/* clear acq_start bit */
-	status |= si21_readregs(state, ACQ_CTRL_REG_2, &reg, 0x01);
-	reg &= ~start_acq;
-	status |= si21_writeregs(state, ACQ_CTRL_REG_2, &reg, 0x01);
-
-	/* use new Carrier Frequency Offset Estimator (QuickLock) */
-	regs[0] = 0xCB;
-	regs[1] = 0x40;
-	regs[2] = 0xCB;
-
-	status |= si21_writeregs(state,
-				TWO_DB_BNDWDTH_THRSHLD_REG,
-				&regs[0], 0x03);
-	reg = 0x56;
-	status |= si21_writeregs(state,
-				LSA_CTRL_REG_1, &reg, 1);
-	reg = 0x05;
-	status |= si21_writeregs(state,
-				BLIND_SCAN_CTRL_REG, &reg, 1);
-	/* start automatic acq */
-	status |= si21_writeregs(state,
-				ACQ_CTRL_REG_2, &start_acq, 0x01);
-
-	return status;
-}
-
-static int si21xx_set_frontend(struct dvb_frontend *fe)
-{
-	struct si21xx_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-
-	/* freq		Channel carrier frequency in KHz (i.e. 1550000 KHz)
-	 datarate	Channel symbol rate in Sps (i.e. 22500000 Sps)*/
-
-	/* in MHz */
-	unsigned char coarse_tune_freq;
-	int fine_tune_freq;
-	unsigned char sample_rate = 0;
-	/* boolean */
-	bool inband_interferer_ind;
-
-	/* INTERMEDIATE VALUES */
-	int icoarse_tune_freq; /* MHz */
-	int ifine_tune_freq; /* MHz */
-	unsigned int band_high;
-	unsigned int band_low;
-	unsigned int x1;
-	unsigned int x2;
-	int i;
-	bool inband_interferer_div2[ALLOWABLE_FS_COUNT];
-	bool inband_interferer_div4[ALLOWABLE_FS_COUNT];
-	int status;
-
-	/* allowable sample rates for ADC in MHz */
-	int afs[ALLOWABLE_FS_COUNT] = { 200, 192, 193, 194, 195,
-					196, 204, 205, 206, 207
-	};
-	/* in MHz */
-	int if_limit_high;
-	int if_limit_low;
-	int lnb_lo;
-	int lnb_uncertanity;
-
-	int rf_freq;
-	int data_rate;
-	unsigned char regs[4];
-
-	dprintk("%s : FE_SET_FRONTEND\n", __func__);
-
-	if (c->delivery_system != SYS_DVBS) {
-			dprintk("%s: unsupported delivery system selected (%d)\n",
-				__func__, c->delivery_system);
-			return -EOPNOTSUPP;
-	}
-
-	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i)
-		inband_interferer_div2[i] = inband_interferer_div4[i] = false;
-
-	if_limit_high = -700000;
-	if_limit_low = -100000;
-	/* in MHz */
-	lnb_lo = 0;
-	lnb_uncertanity = 0;
-
-	rf_freq = 10 * c->frequency ;
-	data_rate = c->symbol_rate / 100;
-
-	status = PASS;
-
-	band_low = (rf_freq - lnb_lo) - ((lnb_uncertanity * 200)
-					+ (data_rate * 135)) / 200;
-
-	band_high = (rf_freq - lnb_lo) + ((lnb_uncertanity * 200)
-					+ (data_rate * 135)) / 200;
-
-
-	icoarse_tune_freq = 100000 *
-				(((rf_freq - lnb_lo) -
-					(if_limit_low + if_limit_high) / 2)
-								/ 100000);
-
-	ifine_tune_freq = (rf_freq - lnb_lo) - icoarse_tune_freq ;
-
-	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
-		x1 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) *
-					(afs[i] * 2500) + afs[i] * 2500;
-
-		x2 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) *
-							(afs[i] * 2500);
-
-		if (((band_low < x1) && (x1 < band_high)) ||
-					((band_low < x2) && (x2 < band_high)))
-					inband_interferer_div4[i] = true;
-
-	}
-
-	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
-		x1 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) *
-					(afs[i] * 5000) + afs[i] * 5000;
-
-		x2 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) *
-					(afs[i] * 5000);
-
-		if (((band_low < x1) && (x1 < band_high)) ||
-					((band_low < x2) && (x2 < band_high)))
-					inband_interferer_div2[i] = true;
-	}
-
-	inband_interferer_ind = true;
-	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
-		if (inband_interferer_div2[i] || inband_interferer_div4[i]) {
-			inband_interferer_ind = false;
-			break;
-		}
-	}
-
-	if (inband_interferer_ind) {
-		for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
-			if (!inband_interferer_div2[i]) {
-				sample_rate = (u8) afs[i];
-				break;
-			}
-		}
-	} else {
-		for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
-			if ((inband_interferer_div2[i] ||
-			     !inband_interferer_div4[i])) {
-				sample_rate = (u8) afs[i];
-				break;
-			}
-		}
-
-	}
-
-	if (sample_rate > 207 || sample_rate < 192)
-		sample_rate = 200;
-
-	fine_tune_freq = ((0x4000 * (ifine_tune_freq / 10)) /
-					((sample_rate) * 1000));
-
-	coarse_tune_freq = (u8)(icoarse_tune_freq / 100000);
-
-	regs[0] = sample_rate;
-	regs[1] = coarse_tune_freq;
-	regs[2] = fine_tune_freq & 0xFF;
-	regs[3] = fine_tune_freq >> 8 & 0xFF;
-
-	status |= si21_writeregs(state, PLL_DIVISOR_REG, &regs[0], 0x04);
-
-	state->fs = sample_rate;/*ADC MHz*/
-	si21xx_setacquire(fe, c->symbol_rate, c->fec_inner);
-
-	return 0;
-}
-
-static int si21xx_sleep(struct dvb_frontend *fe)
-{
-	struct si21xx_state *state = fe->demodulator_priv;
-	u8 regdata;
-
-	dprintk("%s\n", __func__);
-
-	si21_readregs(state, SYSTEM_MODE_REG, &regdata, 0x01);
-	regdata |= 1 << 6;
-	si21_writeregs(state, SYSTEM_MODE_REG, &regdata, 0x01);
-	state->initialised = 0;
-
-	return 0;
-}
-
-static void si21xx_release(struct dvb_frontend *fe)
-{
-	struct si21xx_state *state = fe->demodulator_priv;
-
-	dprintk("%s\n", __func__);
-
-	kfree(state);
-}
-
-static struct dvb_frontend_ops si21xx_ops = {
-	.delsys = { SYS_DVBS },
-	.info = {
-		.name			= "SL SI21XX DVB-S",
-		.frequency_min		= 950000,
-		.frequency_max		= 2150000,
-		.frequency_stepsize	= 125,	 /* kHz for QPSK frontends */
-		.frequency_tolerance	= 0,
-		.symbol_rate_min	= 1000000,
-		.symbol_rate_max	= 45000000,
-		.symbol_rate_tolerance	= 500,	/* ppm */
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
-		FE_CAN_QPSK |
-		FE_CAN_FEC_AUTO
-	},
-
-	.release = si21xx_release,
-	.init = si21xx_init,
-	.sleep = si21xx_sleep,
-	.write = si21_write,
-	.read_status = si21_read_status,
-	.read_ber = si21_read_ber,
-	.read_signal_strength = si21_read_signal_strength,
-	.read_snr = si21_read_snr,
-	.read_ucblocks = si21_read_ucblocks,
-	.diseqc_send_master_cmd = si21xx_send_diseqc_msg,
-	.diseqc_send_burst = si21xx_send_diseqc_burst,
-	.set_tone = si21xx_set_tone,
-	.set_voltage = si21xx_set_voltage,
-
-	.set_frontend = si21xx_set_frontend,
-};
-
-struct dvb_frontend *si21xx_attach(const struct si21xx_config *config,
-						struct i2c_adapter *i2c)
-{
-	struct si21xx_state *state = NULL;
-	int id;
-
-	dprintk("%s\n", __func__);
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct si21xx_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->initialised = 0;
-	state->errmode = STATUS_BER;
-
-	/* check if the demod is there */
-	id = si21_readreg(state, SYSTEM_MODE_REG);
-	si21_writereg(state, SYSTEM_MODE_REG, id | 0x40); /* standby off */
-	msleep(200);
-	id = si21_readreg(state, 0x00);
-
-	/* register 0x00 contains:
-		0x34 for SI2107
-		0x24 for SI2108
-		0x14 for SI2109
-		0x04 for SI2110
-	*/
-	if (id != 0x04 && id != 0x14)
-		goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &si21xx_ops,
-					sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(si21xx_attach);
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("SL SI21XX DVB Demodulator driver");
-MODULE_AUTHOR("Igor M. Liplianin");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/si21xx.h b/drivers/media/dvb/frontends/si21xx.h
deleted file mode 100644
index 141b5b8..0000000
--- a/drivers/media/dvb/frontends/si21xx.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef SI21XX_H
-#define SI21XX_H
-
-#include <linux/dvb/frontend.h>
-#include "dvb_frontend.h"
-
-struct si21xx_config {
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* minimum delay before retuning */
-	int min_delay_ms;
-};
-
-#if defined(CONFIG_DVB_SI21XX) || \
-		(defined(CONFIG_DVB_SI21XX_MODULE) && defined(MODULE))
-extern struct dvb_frontend *si21xx_attach(const struct si21xx_config *config,
-						struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *si21xx_attach(
-		const struct si21xx_config *config, struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-static inline int si21xx_writeregister(struct dvb_frontend *fe, u8 reg, u8 val)
-{
-	int r = 0;
-	u8 buf[] = {reg, val};
-	if (fe->ops.write)
-		r = fe->ops.write(fe, buf, 2);
-	return r;
-}
-
-#endif
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c
deleted file mode 100644
index e37274c..0000000
--- a/drivers/media/dvb/frontends/sp8870.c
+++ /dev/null
@@ -1,620 +0,0 @@
-/*
-    Driver for Spase SP8870 demodulator
-
-    Copyright (C) 1999 Juergen Peitz
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-/*
- * This driver needs external firmware. Please use the command
- * "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware
- * or /lib/firmware (depending on configuration of firmware hotplug).
- */
-#define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw"
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/firmware.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "sp8870.h"
-
-
-struct sp8870_state {
-
-	struct i2c_adapter* i2c;
-
-	const struct sp8870_config* config;
-
-	struct dvb_frontend frontend;
-
-	/* demodulator private data */
-	u8 initialised:1;
-};
-
-static int debug;
-#define dprintk(args...) \
-	do { \
-		if (debug) printk(KERN_DEBUG "sp8870: " args); \
-	} while (0)
-
-/* firmware size for sp8870 */
-#define SP8870_FIRMWARE_SIZE 16382
-
-/* starting point for firmware in file 'Sc_main.mc' */
-#define SP8870_FIRMWARE_OFFSET 0x0A
-
-static int sp8870_writereg (struct sp8870_state* state, u16 reg, u16 data)
-{
-	u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff };
-	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 4 };
-	int err;
-
-	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
-		dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static int sp8870_readreg (struct sp8870_state* state, u16 reg)
-{
-	int ret;
-	u8 b0 [] = { reg >> 8 , reg & 0xff };
-	u8 b1 [] = { 0, 0 };
-	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
-			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
-
-	ret = i2c_transfer (state->i2c, msg, 2);
-
-	if (ret != 2) {
-		dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
-		return -1;
-	}
-
-	return (b1[0] << 8 | b1[1]);
-}
-
-static int sp8870_firmware_upload (struct sp8870_state* state, const struct firmware *fw)
-{
-	struct i2c_msg msg;
-	const char *fw_buf = fw->data;
-	int fw_pos;
-	u8 tx_buf[255];
-	int tx_len;
-	int err = 0;
-
-	dprintk ("%s: ...\n", __func__);
-
-	if (fw->size < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET)
-		return -EINVAL;
-
-	// system controller stop
-	sp8870_writereg(state, 0x0F00, 0x0000);
-
-	// instruction RAM register hiword
-	sp8870_writereg(state, 0x8F08, ((SP8870_FIRMWARE_SIZE / 2) & 0xFFFF));
-
-	// instruction RAM MWR
-	sp8870_writereg(state, 0x8F0A, ((SP8870_FIRMWARE_SIZE / 2) >> 16));
-
-	// do firmware upload
-	fw_pos = SP8870_FIRMWARE_OFFSET;
-	while (fw_pos < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET){
-		tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - 252) ? 252 : SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - fw_pos;
-		// write register 0xCF0A
-		tx_buf[0] = 0xCF;
-		tx_buf[1] = 0x0A;
-		memcpy(&tx_buf[2], fw_buf + fw_pos, tx_len);
-		msg.addr = state->config->demod_address;
-		msg.flags = 0;
-		msg.buf = tx_buf;
-		msg.len = tx_len + 2;
-		if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
-			printk("%s: firmware upload failed!\n", __func__);
-			printk ("%s: i2c error (err == %i)\n", __func__, err);
-			return err;
-		}
-		fw_pos += tx_len;
-	}
-
-	dprintk ("%s: done!\n", __func__);
-	return 0;
-};
-
-static void sp8870_microcontroller_stop (struct sp8870_state* state)
-{
-	sp8870_writereg(state, 0x0F08, 0x000);
-	sp8870_writereg(state, 0x0F09, 0x000);
-
-	// microcontroller STOP
-	sp8870_writereg(state, 0x0F00, 0x000);
-}
-
-static void sp8870_microcontroller_start (struct sp8870_state* state)
-{
-	sp8870_writereg(state, 0x0F08, 0x000);
-	sp8870_writereg(state, 0x0F09, 0x000);
-
-	// microcontroller START
-	sp8870_writereg(state, 0x0F00, 0x001);
-	// not documented but if we don't read 0x0D01 out here
-	// we don't get a correct data valid signal
-	sp8870_readreg(state, 0x0D01);
-}
-
-static int sp8870_read_data_valid_signal(struct sp8870_state* state)
-{
-	return (sp8870_readreg(state, 0x0D02) > 0);
-}
-
-static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05)
-{
-	int known_parameters = 1;
-
-	*reg0xc05 = 0x000;
-
-	switch (p->modulation) {
-	case QPSK:
-		break;
-	case QAM_16:
-		*reg0xc05 |= (1 << 10);
-		break;
-	case QAM_64:
-		*reg0xc05 |= (2 << 10);
-		break;
-	case QAM_AUTO:
-		known_parameters = 0;
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	switch (p->hierarchy) {
-	case HIERARCHY_NONE:
-		break;
-	case HIERARCHY_1:
-		*reg0xc05 |= (1 << 7);
-		break;
-	case HIERARCHY_2:
-		*reg0xc05 |= (2 << 7);
-		break;
-	case HIERARCHY_4:
-		*reg0xc05 |= (3 << 7);
-		break;
-	case HIERARCHY_AUTO:
-		known_parameters = 0;
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	switch (p->code_rate_HP) {
-	case FEC_1_2:
-		break;
-	case FEC_2_3:
-		*reg0xc05 |= (1 << 3);
-		break;
-	case FEC_3_4:
-		*reg0xc05 |= (2 << 3);
-		break;
-	case FEC_5_6:
-		*reg0xc05 |= (3 << 3);
-		break;
-	case FEC_7_8:
-		*reg0xc05 |= (4 << 3);
-		break;
-	case FEC_AUTO:
-		known_parameters = 0;
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	if (known_parameters)
-		*reg0xc05 |= (2 << 1);	/* use specified parameters */
-	else
-		*reg0xc05 |= (1 << 1);	/* enable autoprobing */
-
-	return 0;
-}
-
-static int sp8870_wake_up(struct sp8870_state* state)
-{
-	// enable TS output and interface pins
-	return sp8870_writereg(state, 0xC18, 0x00D);
-}
-
-static int sp8870_set_frontend_parameters(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct sp8870_state* state = fe->demodulator_priv;
-	int  err;
-	u16 reg0xc05;
-
-	if ((err = configure_reg0xc05(p, &reg0xc05)))
-		return err;
-
-	// system controller stop
-	sp8870_microcontroller_stop(state);
-
-	// set tuner parameters
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	// sample rate correction bit [23..17]
-	sp8870_writereg(state, 0x0319, 0x000A);
-
-	// sample rate correction bit [16..0]
-	sp8870_writereg(state, 0x031A, 0x0AAB);
-
-	// integer carrier offset
-	sp8870_writereg(state, 0x0309, 0x0400);
-
-	// fractional carrier offset
-	sp8870_writereg(state, 0x030A, 0x0000);
-
-	// filter for 6/7/8 Mhz channel
-	if (p->bandwidth_hz == 6000000)
-		sp8870_writereg(state, 0x0311, 0x0002);
-	else if (p->bandwidth_hz == 7000000)
-		sp8870_writereg(state, 0x0311, 0x0001);
-	else
-		sp8870_writereg(state, 0x0311, 0x0000);
-
-	// scan order: 2k first = 0x0000, 8k first = 0x0001
-	if (p->transmission_mode == TRANSMISSION_MODE_2K)
-		sp8870_writereg(state, 0x0338, 0x0000);
-	else
-		sp8870_writereg(state, 0x0338, 0x0001);
-
-	sp8870_writereg(state, 0xc05, reg0xc05);
-
-	// read status reg in order to clear pending irqs
-	sp8870_readreg(state, 0x200);
-
-	// system controller start
-	sp8870_microcontroller_start(state);
-
-	return 0;
-}
-
-static int sp8870_init (struct dvb_frontend* fe)
-{
-	struct sp8870_state* state = fe->demodulator_priv;
-	const struct firmware *fw = NULL;
-
-	sp8870_wake_up(state);
-	if (state->initialised) return 0;
-	state->initialised = 1;
-
-	dprintk ("%s\n", __func__);
-
-
-	/* request the firmware, this will block until someone uploads it */
-	printk("sp8870: waiting for firmware upload (%s)...\n", SP8870_DEFAULT_FIRMWARE);
-	if (state->config->request_firmware(fe, &fw, SP8870_DEFAULT_FIRMWARE)) {
-		printk("sp8870: no firmware upload (timeout or file not found?)\n");
-		return -EIO;
-	}
-
-	if (sp8870_firmware_upload(state, fw)) {
-		printk("sp8870: writing firmware to device failed\n");
-		release_firmware(fw);
-		return -EIO;
-	}
-	release_firmware(fw);
-	printk("sp8870: firmware upload complete\n");
-
-	/* enable TS output and interface pins */
-	sp8870_writereg(state, 0xc18, 0x00d);
-
-	// system controller stop
-	sp8870_microcontroller_stop(state);
-
-	// ADC mode
-	sp8870_writereg(state, 0x0301, 0x0003);
-
-	// Reed Solomon parity bytes passed to output
-	sp8870_writereg(state, 0x0C13, 0x0001);
-
-	// MPEG clock is suppressed if no valid data
-	sp8870_writereg(state, 0x0C14, 0x0001);
-
-	/* bit 0x010: enable data valid signal */
-	sp8870_writereg(state, 0x0D00, 0x010);
-	sp8870_writereg(state, 0x0D01, 0x000);
-
-	return 0;
-}
-
-static int sp8870_read_status (struct dvb_frontend* fe, fe_status_t * fe_status)
-{
-	struct sp8870_state* state = fe->demodulator_priv;
-	int status;
-	int signal;
-
-	*fe_status = 0;
-
-	status = sp8870_readreg (state, 0x0200);
-	if (status < 0)
-		return -EIO;
-
-	signal = sp8870_readreg (state, 0x0303);
-	if (signal < 0)
-		return -EIO;
-
-	if (signal > 0x0F)
-		*fe_status |= FE_HAS_SIGNAL;
-	if (status & 0x08)
-		*fe_status |= FE_HAS_SYNC;
-	if (status & 0x04)
-		*fe_status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_VITERBI;
-
-	return 0;
-}
-
-static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber)
-{
-	struct sp8870_state* state = fe->demodulator_priv;
-	int ret;
-	u32 tmp;
-
-	*ber = 0;
-
-	ret = sp8870_readreg(state, 0xC08);
-	if (ret < 0)
-		return -EIO;
-
-	tmp = ret & 0x3F;
-
-	ret = sp8870_readreg(state, 0xC07);
-	if (ret < 0)
-		return -EIO;
-
-	 tmp = ret << 6;
-
-	if (tmp >= 0x3FFF0)
-		tmp = ~0;
-
-	*ber = tmp;
-
-	return 0;
-}
-
-static int sp8870_read_signal_strength(struct dvb_frontend* fe,  u16 * signal)
-{
-	struct sp8870_state* state = fe->demodulator_priv;
-	int ret;
-	u16 tmp;
-
-	*signal = 0;
-
-	ret = sp8870_readreg (state, 0x306);
-	if (ret < 0)
-		return -EIO;
-
-	tmp = ret << 8;
-
-	ret = sp8870_readreg (state, 0x303);
-	if (ret < 0)
-		return -EIO;
-
-	tmp |= ret;
-
-	if (tmp)
-		*signal = 0xFFFF - tmp;
-
-	return 0;
-}
-
-static int sp8870_read_uncorrected_blocks (struct dvb_frontend* fe, u32* ublocks)
-{
-	struct sp8870_state* state = fe->demodulator_priv;
-	int ret;
-
-	*ublocks = 0;
-
-	ret = sp8870_readreg(state, 0xC0C);
-	if (ret < 0)
-		return -EIO;
-
-	if (ret == 0xFFFF)
-		ret = ~0;
-
-	*ublocks = ret;
-
-	return 0;
-}
-
-/* number of trials to recover from lockup */
-#define MAXTRIALS 5
-/* maximum checks for data valid signal */
-#define MAXCHECKS 100
-
-/* only for debugging: counter for detected lockups */
-static int lockups;
-/* only for debugging: counter for channel switches */
-static int switches;
-
-static int sp8870_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct sp8870_state* state = fe->demodulator_priv;
-
-	/*
-	    The firmware of the sp8870 sometimes locks up after setting frontend parameters.
-	    We try to detect this by checking the data valid signal.
-	    If it is not set after MAXCHECKS we try to recover the lockup by setting
-	    the frontend parameters again.
-	*/
-
-	int err = 0;
-	int valid = 0;
-	int trials = 0;
-	int check_count = 0;
-
-	dprintk("%s: frequency = %i\n", __func__, p->frequency);
-
-	for (trials = 1; trials <= MAXTRIALS; trials++) {
-
-		err = sp8870_set_frontend_parameters(fe);
-		if (err)
-			return err;
-
-		for (check_count = 0; check_count < MAXCHECKS; check_count++) {
-//			valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0);
-			valid = sp8870_read_data_valid_signal(state);
-			if (valid) {
-				dprintk("%s: delay = %i usec\n",
-					__func__, check_count * 10);
-				break;
-			}
-			udelay(10);
-		}
-		if (valid)
-			break;
-	}
-
-	if (!valid) {
-		printk("%s: firmware crash!!!!!!\n", __func__);
-		return -EIO;
-	}
-
-	if (debug) {
-		if (valid) {
-			if (trials > 1) {
-				printk("%s: firmware lockup!!!\n", __func__);
-				printk("%s: recovered after %i trial(s))\n",  __func__, trials - 1);
-				lockups++;
-			}
-		}
-		switches++;
-		printk("%s: switches = %i lockups = %i\n", __func__, switches, lockups);
-	}
-
-	return 0;
-}
-
-static int sp8870_sleep(struct dvb_frontend* fe)
-{
-	struct sp8870_state* state = fe->demodulator_priv;
-
-	// tristate TS output and disable interface pins
-	return sp8870_writereg(state, 0xC18, 0x000);
-}
-
-static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
-{
-	fesettings->min_delay_ms = 350;
-	fesettings->step_size = 0;
-	fesettings->max_drift = 0;
-	return 0;
-}
-
-static int sp8870_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
-{
-	struct sp8870_state* state = fe->demodulator_priv;
-
-	if (enable) {
-		return sp8870_writereg(state, 0x206, 0x001);
-	} else {
-		return sp8870_writereg(state, 0x206, 0x000);
-	}
-}
-
-static void sp8870_release(struct dvb_frontend* fe)
-{
-	struct sp8870_state* state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops sp8870_ops;
-
-struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
-				   struct i2c_adapter* i2c)
-{
-	struct sp8870_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct sp8870_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->initialised = 0;
-
-	/* check if the demod is there */
-	if (sp8870_readreg(state, 0x0200) < 0) goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops sp8870_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name			= "Spase SP8870 DVB-T",
-		.frequency_min		= 470000000,
-		.frequency_max		= 860000000,
-		.frequency_stepsize	= 166666,
-		.caps			= FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
-					  FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
-					  FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-					  FE_CAN_QPSK | FE_CAN_QAM_16 |
-					  FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-					  FE_CAN_HIERARCHY_AUTO |  FE_CAN_RECOVER
-	},
-
-	.release = sp8870_release,
-
-	.init = sp8870_init,
-	.sleep = sp8870_sleep,
-	.i2c_gate_ctrl = sp8870_i2c_gate_ctrl,
-
-	.set_frontend = sp8870_set_frontend,
-	.get_tune_settings = sp8870_get_tune_settings,
-
-	.read_status = sp8870_read_status,
-	.read_ber = sp8870_read_ber,
-	.read_signal_strength = sp8870_read_signal_strength,
-	.read_ucblocks = sp8870_read_uncorrected_blocks,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("Spase SP8870 DVB-T Demodulator driver");
-MODULE_AUTHOR("Juergen Peitz");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(sp8870_attach);
diff --git a/drivers/media/dvb/frontends/sp8870.h b/drivers/media/dvb/frontends/sp8870.h
deleted file mode 100644
index a764a79..0000000
--- a/drivers/media/dvb/frontends/sp8870.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-    Driver for Spase SP8870 demodulator
-
-    Copyright (C) 1999 Juergen Peitz
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef SP8870_H
-#define SP8870_H
-
-#include <linux/dvb/frontend.h>
-#include <linux/firmware.h>
-
-struct sp8870_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* request firmware for device */
-	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
-};
-
-#if defined(CONFIG_DVB_SP8870) || (defined(CONFIG_DVB_SP8870_MODULE) && defined(MODULE))
-extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
-					  struct i2c_adapter* i2c);
-#else
-static inline struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
-					  struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_SP8870
-
-#endif // SP8870_H
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
deleted file mode 100644
index f4096cc..0000000
--- a/drivers/media/dvb/frontends/sp887x.c
+++ /dev/null
@@ -1,629 +0,0 @@
-/*
-   Driver for the Spase sp887x demodulator
-*/
-
-/*
- * This driver needs external firmware. Please use the command
- * "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware
- * or /lib/firmware (depending on configuration of firmware hotplug).
- */
-#define SP887X_DEFAULT_FIRMWARE "dvb-fe-sp887x.fw"
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/firmware.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "sp887x.h"
-
-
-struct sp887x_state {
-	struct i2c_adapter* i2c;
-	const struct sp887x_config* config;
-	struct dvb_frontend frontend;
-
-	/* demodulator private data */
-	u8 initialised:1;
-};
-
-static int debug;
-#define dprintk(args...) \
-	do { \
-		if (debug) printk(KERN_DEBUG "sp887x: " args); \
-	} while (0)
-
-static int i2c_writebytes (struct sp887x_state* state, u8 *buf, u8 len)
-{
-	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = len };
-	int err;
-
-	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
-		printk ("%s: i2c write error (addr %02x, err == %i)\n",
-			__func__, state->config->demod_address, err);
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static int sp887x_writereg (struct sp887x_state* state, u16 reg, u16 data)
-{
-	u8 b0 [] = { reg >> 8 , reg & 0xff, data >> 8, data & 0xff };
-	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 4 };
-	int ret;
-
-	if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) {
-		/**
-		 *  in case of soft reset we ignore ACK errors...
-		 */
-		if (!(reg == 0xf1a && data == 0x000 &&
-			(ret == -EREMOTEIO || ret == -EFAULT)))
-		{
-			printk("%s: writereg error "
-			       "(reg %03x, data %03x, ret == %i)\n",
-			       __func__, reg & 0xffff, data & 0xffff, ret);
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-static int sp887x_readreg (struct sp887x_state* state, u16 reg)
-{
-	u8 b0 [] = { reg >> 8 , reg & 0xff };
-	u8 b1 [2];
-	int ret;
-	struct i2c_msg msg[] = {{ .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
-			 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 }};
-
-	if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
-		printk("%s: readreg error (ret == %i)\n", __func__, ret);
-		return -1;
-	}
-
-	return (((b1[0] << 8) | b1[1]) & 0xfff);
-}
-
-static void sp887x_microcontroller_stop (struct sp887x_state* state)
-{
-	dprintk("%s\n", __func__);
-	sp887x_writereg(state, 0xf08, 0x000);
-	sp887x_writereg(state, 0xf09, 0x000);
-
-	/* microcontroller STOP */
-	sp887x_writereg(state, 0xf00, 0x000);
-}
-
-static void sp887x_microcontroller_start (struct sp887x_state* state)
-{
-	dprintk("%s\n", __func__);
-	sp887x_writereg(state, 0xf08, 0x000);
-	sp887x_writereg(state, 0xf09, 0x000);
-
-	/* microcontroller START */
-	sp887x_writereg(state, 0xf00, 0x001);
-}
-
-static void sp887x_setup_agc (struct sp887x_state* state)
-{
-	/* setup AGC parameters */
-	dprintk("%s\n", __func__);
-	sp887x_writereg(state, 0x33c, 0x054);
-	sp887x_writereg(state, 0x33b, 0x04c);
-	sp887x_writereg(state, 0x328, 0x000);
-	sp887x_writereg(state, 0x327, 0x005);
-	sp887x_writereg(state, 0x326, 0x001);
-	sp887x_writereg(state, 0x325, 0x001);
-	sp887x_writereg(state, 0x324, 0x001);
-	sp887x_writereg(state, 0x318, 0x050);
-	sp887x_writereg(state, 0x317, 0x3fe);
-	sp887x_writereg(state, 0x316, 0x001);
-	sp887x_writereg(state, 0x313, 0x005);
-	sp887x_writereg(state, 0x312, 0x002);
-	sp887x_writereg(state, 0x306, 0x000);
-	sp887x_writereg(state, 0x303, 0x000);
-}
-
-#define BLOCKSIZE 30
-#define FW_SIZE 0x4000
-/**
- *  load firmware and setup MPEG interface...
- */
-static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware *fw)
-{
-	struct sp887x_state* state = fe->demodulator_priv;
-	u8 buf [BLOCKSIZE+2];
-	int i;
-	int fw_size = fw->size;
-	const unsigned char *mem = fw->data;
-
-	dprintk("%s\n", __func__);
-
-	/* ignore the first 10 bytes, then we expect 0x4000 bytes of firmware */
-	if (fw_size < FW_SIZE+10)
-		return -ENODEV;
-
-	mem = fw->data + 10;
-
-	/* soft reset */
-	sp887x_writereg(state, 0xf1a, 0x000);
-
-	sp887x_microcontroller_stop (state);
-
-	printk ("%s: firmware upload... ", __func__);
-
-	/* setup write pointer to -1 (end of memory) */
-	/* bit 0x8000 in address is set to enable 13bit mode */
-	sp887x_writereg(state, 0x8f08, 0x1fff);
-
-	/* dummy write (wrap around to start of memory) */
-	sp887x_writereg(state, 0x8f0a, 0x0000);
-
-	for (i = 0; i < FW_SIZE; i += BLOCKSIZE) {
-		int c = BLOCKSIZE;
-		int err;
-
-		if (i+c > FW_SIZE)
-			c = FW_SIZE - i;
-
-		/* bit 0x8000 in address is set to enable 13bit mode */
-		/* bit 0x4000 enables multibyte read/write transfers */
-		/* write register is 0xf0a */
-		buf[0] = 0xcf;
-		buf[1] = 0x0a;
-
-		memcpy(&buf[2], mem + i, c);
-
-		if ((err = i2c_writebytes (state, buf, c+2)) < 0) {
-			printk ("failed.\n");
-			printk ("%s: i2c error (err == %i)\n", __func__, err);
-			return err;
-		}
-	}
-
-	/* don't write RS bytes between packets */
-	sp887x_writereg(state, 0xc13, 0x001);
-
-	/* suppress clock if (!data_valid) */
-	sp887x_writereg(state, 0xc14, 0x000);
-
-	/* setup MPEG interface... */
-	sp887x_writereg(state, 0xc1a, 0x872);
-	sp887x_writereg(state, 0xc1b, 0x001);
-	sp887x_writereg(state, 0xc1c, 0x000); /* parallel mode (serial mode == 1) */
-	sp887x_writereg(state, 0xc1a, 0x871);
-
-	/* ADC mode, 2 for MT8872, 3 for SP8870/SP8871 */
-	sp887x_writereg(state, 0x301, 0x002);
-
-	sp887x_setup_agc(state);
-
-	/* bit 0x010: enable data valid signal */
-	sp887x_writereg(state, 0xd00, 0x010);
-	sp887x_writereg(state, 0x0d1, 0x000);
-	return 0;
-};
-
-static int configure_reg0xc05(struct dtv_frontend_properties *p, u16 *reg0xc05)
-{
-	int known_parameters = 1;
-
-	*reg0xc05 = 0x000;
-
-	switch (p->modulation) {
-	case QPSK:
-		break;
-	case QAM_16:
-		*reg0xc05 |= (1 << 10);
-		break;
-	case QAM_64:
-		*reg0xc05 |= (2 << 10);
-		break;
-	case QAM_AUTO:
-		known_parameters = 0;
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	switch (p->hierarchy) {
-	case HIERARCHY_NONE:
-		break;
-	case HIERARCHY_1:
-		*reg0xc05 |= (1 << 7);
-		break;
-	case HIERARCHY_2:
-		*reg0xc05 |= (2 << 7);
-		break;
-	case HIERARCHY_4:
-		*reg0xc05 |= (3 << 7);
-		break;
-	case HIERARCHY_AUTO:
-		known_parameters = 0;
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	switch (p->code_rate_HP) {
-	case FEC_1_2:
-		break;
-	case FEC_2_3:
-		*reg0xc05 |= (1 << 3);
-		break;
-	case FEC_3_4:
-		*reg0xc05 |= (2 << 3);
-		break;
-	case FEC_5_6:
-		*reg0xc05 |= (3 << 3);
-		break;
-	case FEC_7_8:
-		*reg0xc05 |= (4 << 3);
-		break;
-	case FEC_AUTO:
-		known_parameters = 0;
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	if (known_parameters)
-		*reg0xc05 |= (2 << 1);	/* use specified parameters */
-	else
-		*reg0xc05 |= (1 << 1);	/* enable autoprobing */
-
-	return 0;
-}
-
-/**
- *  estimates division of two 24bit numbers,
- *  derived from the ves1820/stv0299 driver code
- */
-static void divide (int n, int d, int *quotient_i, int *quotient_f)
-{
-	unsigned int q, r;
-
-	r = (n % d) << 8;
-	q = (r / d);
-
-	if (quotient_i)
-		*quotient_i = q;
-
-	if (quotient_f) {
-		r = (r % d) << 8;
-		q = (q << 8) | (r / d);
-		r = (r % d) << 8;
-		*quotient_f = (q << 8) | (r / d);
-	}
-}
-
-static void sp887x_correct_offsets (struct sp887x_state* state,
-				    struct dtv_frontend_properties *p,
-				    int actual_freq)
-{
-	static const u32 srate_correction [] = { 1879617, 4544878, 8098561 };
-	int bw_index;
-	int freq_offset = actual_freq - p->frequency;
-	int sysclock = 61003; //[kHz]
-	int ifreq = 36000000;
-	int freq;
-	int frequency_shift;
-
-	switch (p->bandwidth_hz) {
-	default:
-	case 8000000:
-		bw_index = 0;
-		break;
-	case 7000000:
-		bw_index = 1;
-		break;
-	case 6000000:
-		bw_index = 2;
-		break;
-	}
-
-	if (p->inversion == INVERSION_ON)
-		freq = ifreq - freq_offset;
-	else
-		freq = ifreq + freq_offset;
-
-	divide(freq / 333, sysclock, NULL, &frequency_shift);
-
-	if (p->inversion == INVERSION_ON)
-		frequency_shift = -frequency_shift;
-
-	/* sample rate correction */
-	sp887x_writereg(state, 0x319, srate_correction[bw_index] >> 12);
-	sp887x_writereg(state, 0x31a, srate_correction[bw_index] & 0xfff);
-
-	/* carrier offset correction */
-	sp887x_writereg(state, 0x309, frequency_shift >> 12);
-	sp887x_writereg(state, 0x30a, frequency_shift & 0xfff);
-}
-
-static int sp887x_setup_frontend_parameters(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct sp887x_state* state = fe->demodulator_priv;
-	unsigned actual_freq;
-	int err;
-	u16 val, reg0xc05;
-
-	if (p->bandwidth_hz != 8000000 &&
-	    p->bandwidth_hz != 7000000 &&
-	    p->bandwidth_hz != 6000000)
-		return -EINVAL;
-
-	if ((err = configure_reg0xc05(p, &reg0xc05)))
-		return err;
-
-	sp887x_microcontroller_stop(state);
-
-	/* setup the PLL */
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-	if (fe->ops.tuner_ops.get_frequency) {
-		fe->ops.tuner_ops.get_frequency(fe, &actual_freq);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-	} else {
-		actual_freq = p->frequency;
-	}
-
-	/* read status reg in order to clear <pending irqs */
-	sp887x_readreg(state, 0x200);
-
-	sp887x_correct_offsets(state, p, actual_freq);
-
-	/* filter for 6/7/8 Mhz channel */
-	if (p->bandwidth_hz == 6000000)
-		val = 2;
-	else if (p->bandwidth_hz == 7000000)
-		val = 1;
-	else
-		val = 0;
-
-	sp887x_writereg(state, 0x311, val);
-
-	/* scan order: 2k first = 0, 8k first = 1 */
-	if (p->transmission_mode == TRANSMISSION_MODE_2K)
-		sp887x_writereg(state, 0x338, 0x000);
-	else
-		sp887x_writereg(state, 0x338, 0x001);
-
-	sp887x_writereg(state, 0xc05, reg0xc05);
-
-	if (p->bandwidth_hz == 6000000)
-		val = 2 << 3;
-	else if (p->bandwidth_hz == 7000000)
-		val = 3 << 3;
-	else
-		val = 0 << 3;
-
-	/* enable OFDM and SAW bits as lock indicators in sync register 0xf17,
-	 * optimize algorithm for given bandwidth...
-	 */
-	sp887x_writereg(state, 0xf14, 0x160 | val);
-	sp887x_writereg(state, 0xf15, 0x000);
-
-	sp887x_microcontroller_start(state);
-	return 0;
-}
-
-static int sp887x_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct sp887x_state* state = fe->demodulator_priv;
-	u16 snr12 = sp887x_readreg(state, 0xf16);
-	u16 sync0x200 = sp887x_readreg(state, 0x200);
-	u16 sync0xf17 = sp887x_readreg(state, 0xf17);
-
-	*status = 0;
-
-	if (snr12 > 0x00f)
-		*status |= FE_HAS_SIGNAL;
-
-	//if (sync0x200 & 0x004)
-	//	*status |= FE_HAS_SYNC | FE_HAS_CARRIER;
-
-	//if (sync0x200 & 0x008)
-	//	*status |= FE_HAS_VITERBI;
-
-	if ((sync0xf17 & 0x00f) == 0x002) {
-		*status |= FE_HAS_LOCK;
-		*status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_CARRIER;
-	}
-
-	if (sync0x200 & 0x001) {	/* tuner adjustment requested...*/
-		int steps = (sync0x200 >> 4) & 0x00f;
-		if (steps & 0x008)
-			steps = -steps;
-		dprintk("sp887x: implement tuner adjustment (%+i steps)!!\n",
-		       steps);
-	}
-
-	return 0;
-}
-
-static int sp887x_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	struct sp887x_state* state = fe->demodulator_priv;
-
-	*ber = (sp887x_readreg(state, 0xc08) & 0x3f) |
-	       (sp887x_readreg(state, 0xc07) << 6);
-	sp887x_writereg(state, 0xc08, 0x000);
-	sp887x_writereg(state, 0xc07, 0x000);
-	if (*ber >= 0x3fff0)
-		*ber = ~0;
-
-	return 0;
-}
-
-static int sp887x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-{
-	struct sp887x_state* state = fe->demodulator_priv;
-
-	u16 snr12 = sp887x_readreg(state, 0xf16);
-	u32 signal = 3 * (snr12 << 4);
-	*strength = (signal < 0xffff) ? signal : 0xffff;
-
-	return 0;
-}
-
-static int sp887x_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct sp887x_state* state = fe->demodulator_priv;
-
-	u16 snr12 = sp887x_readreg(state, 0xf16);
-	*snr = (snr12 << 4) | (snr12 >> 8);
-
-	return 0;
-}
-
-static int sp887x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	struct sp887x_state* state = fe->demodulator_priv;
-
-	*ucblocks = sp887x_readreg(state, 0xc0c);
-	if (*ucblocks == 0xfff)
-		*ucblocks = ~0;
-
-	return 0;
-}
-
-static int sp887x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
-{
-	struct sp887x_state* state = fe->demodulator_priv;
-
-	if (enable) {
-		return sp887x_writereg(state, 0x206, 0x001);
-	} else {
-		return sp887x_writereg(state, 0x206, 0x000);
-	}
-}
-
-static int sp887x_sleep(struct dvb_frontend* fe)
-{
-	struct sp887x_state* state = fe->demodulator_priv;
-
-	/* tristate TS output and disable interface pins */
-	sp887x_writereg(state, 0xc18, 0x000);
-
-	return 0;
-}
-
-static int sp887x_init(struct dvb_frontend* fe)
-{
-	struct sp887x_state* state = fe->demodulator_priv;
-	const struct firmware *fw = NULL;
-	int ret;
-
-	if (!state->initialised) {
-		/* request the firmware, this will block until someone uploads it */
-		printk("sp887x: waiting for firmware upload (%s)...\n", SP887X_DEFAULT_FIRMWARE);
-		ret = state->config->request_firmware(fe, &fw, SP887X_DEFAULT_FIRMWARE);
-		if (ret) {
-			printk("sp887x: no firmware upload (timeout or file not found?)\n");
-			return ret;
-		}
-
-		ret = sp887x_initial_setup(fe, fw);
-		release_firmware(fw);
-		if (ret) {
-			printk("sp887x: writing firmware to device failed\n");
-			return ret;
-		}
-		printk("sp887x: firmware upload complete\n");
-		state->initialised = 1;
-	}
-
-	/* enable TS output and interface pins */
-	sp887x_writereg(state, 0xc18, 0x00d);
-
-	return 0;
-}
-
-static int sp887x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
-{
-	fesettings->min_delay_ms = 350;
-	fesettings->step_size = 166666*2;
-	fesettings->max_drift = (166666*2)+1;
-	return 0;
-}
-
-static void sp887x_release(struct dvb_frontend* fe)
-{
-	struct sp887x_state* state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops sp887x_ops;
-
-struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
-				   struct i2c_adapter* i2c)
-{
-	struct sp887x_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct sp887x_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->initialised = 0;
-
-	/* check if the demod is there */
-	if (sp887x_readreg(state, 0x0200) < 0) goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &sp887x_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops sp887x_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name = "Spase SP887x DVB-T",
-		.frequency_min =  50500000,
-		.frequency_max = 858000000,
-		.frequency_stepsize = 166666,
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
-			FE_CAN_RECOVER
-	},
-
-	.release = sp887x_release,
-
-	.init = sp887x_init,
-	.sleep = sp887x_sleep,
-	.i2c_gate_ctrl = sp887x_i2c_gate_ctrl,
-
-	.set_frontend = sp887x_setup_frontend_parameters,
-	.get_tune_settings = sp887x_get_tune_settings,
-
-	.read_status = sp887x_read_status,
-	.read_ber = sp887x_read_ber,
-	.read_signal_strength = sp887x_read_signal_strength,
-	.read_snr = sp887x_read_snr,
-	.read_ucblocks = sp887x_read_ucblocks,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("Spase sp887x DVB-T demodulator driver");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(sp887x_attach);
diff --git a/drivers/media/dvb/frontends/sp887x.h b/drivers/media/dvb/frontends/sp887x.h
deleted file mode 100644
index 04eff6e..0000000
--- a/drivers/media/dvb/frontends/sp887x.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-   Driver for the Spase sp887x demodulator
-*/
-
-#ifndef SP887X_H
-#define SP887X_H
-
-#include <linux/dvb/frontend.h>
-#include <linux/firmware.h>
-
-struct sp887x_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* request firmware for device */
-	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
-};
-
-#if defined(CONFIG_DVB_SP887X) || (defined(CONFIG_DVB_SP887X_MODULE) && defined(MODULE))
-extern struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
-					  struct i2c_adapter* i2c);
-#else
-static inline struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
-					  struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_SP887X
-
-#endif // SP887X_H
diff --git a/drivers/media/dvb/frontends/stb0899_algo.c b/drivers/media/dvb/frontends/stb0899_algo.c
deleted file mode 100644
index 117a569..0000000
--- a/drivers/media/dvb/frontends/stb0899_algo.c
+++ /dev/null
@@ -1,1525 +0,0 @@
-/*
-	STB0899 Multistandard Frontend driver
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	Copyright (C) ST Microelectronics
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "stb0899_drv.h"
-#include "stb0899_priv.h"
-#include "stb0899_reg.h"
-
-static inline u32 stb0899_do_div(u64 n, u32 d)
-{
-	/* wrap do_div() for ease of use */
-
-	do_div(n, d);
-	return n;
-}
-
-#if 0
-/* These functions are currently unused */
-/*
- * stb0899_calc_srate
- * Compute symbol rate
- */
-static u32 stb0899_calc_srate(u32 master_clk, u8 *sfr)
-{
-	u64 tmp;
-
-	/* srate = (SFR * master_clk) >> 20 */
-
-	/* sfr is of size 20 bit, stored with an offset of 4 bit */
-	tmp = (((u32)sfr[0]) << 16) | (((u32)sfr[1]) << 8) | sfr[2];
-	tmp &= ~0xf;
-	tmp *= master_clk;
-	tmp >>= 24;
-
-	return tmp;
-}
-
-/*
- * stb0899_get_srate
- * Get the current symbol rate
- */
-static u32 stb0899_get_srate(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal = &state->internal;
-	u8 sfr[3];
-
-	stb0899_read_regs(state, STB0899_SFRH, sfr, 3);
-
-	return stb0899_calc_srate(internal->master_clk, sfr);
-}
-#endif
-
-/*
- * stb0899_set_srate
- * Set symbol frequency
- * MasterClock: master clock frequency (hz)
- * SymbolRate: symbol rate (bauds)
- * return symbol frequency
- */
-static u32 stb0899_set_srate(struct stb0899_state *state, u32 master_clk, u32 srate)
-{
-	u32 tmp;
-	u8 sfr[3];
-
-	dprintk(state->verbose, FE_DEBUG, 1, "-->");
-	/*
-	 * in order to have the maximum precision, the symbol rate entered into
-	 * the chip is computed as the closest value of the "true value".
-	 * In this purpose, the symbol rate value is rounded (1 is added on the bit
-	 * below the LSB )
-	 *
-	 * srate = (SFR * master_clk) >> 20
-	 *      <=>
-	 *   SFR = srate << 20 / master_clk
-	 *
-	 * rounded:
-	 *   SFR = (srate << 21 + master_clk) / (2 * master_clk)
-	 *
-	 * stored as 20 bit number with an offset of 4 bit:
-	 *   sfr = SFR << 4;
-	 */
-
-	tmp = stb0899_do_div((((u64)srate) << 21) + master_clk, 2 * master_clk);
-	tmp <<= 4;
-
-	sfr[0] = tmp >> 16;
-	sfr[1] = tmp >>  8;
-	sfr[2] = tmp;
-
-	stb0899_write_regs(state, STB0899_SFRH, sfr, 3);
-
-	return srate;
-}
-
-/*
- * stb0899_calc_derot_time
- * Compute the amount of time needed by the derotator to lock
- * SymbolRate: Symbol rate
- * return: derotator time constant (ms)
- */
-static long stb0899_calc_derot_time(long srate)
-{
-	if (srate > 0)
-		return (100000 / (srate / 1000));
-	else
-		return 0;
-}
-
-/*
- * stb0899_carr_width
- * Compute the width of the carrier
- * return: width of carrier (kHz or Mhz)
- */
-long stb0899_carr_width(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal = &state->internal;
-
-	return (internal->srate + (internal->srate * internal->rolloff) / 100);
-}
-
-/*
- * stb0899_first_subrange
- * Compute the first subrange of the search
- */
-static void stb0899_first_subrange(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal	= &state->internal;
-	struct stb0899_params *params		= &state->params;
-	struct stb0899_config *config		=  state->config;
-
-	int range = 0;
-	u32 bandwidth = 0;
-
-	if (config->tuner_get_bandwidth) {
-		stb0899_i2c_gate_ctrl(&state->frontend, 1);
-		config->tuner_get_bandwidth(&state->frontend, &bandwidth);
-		stb0899_i2c_gate_ctrl(&state->frontend, 0);
-		range = bandwidth - stb0899_carr_width(state) / 2;
-	}
-
-	if (range > 0)
-		internal->sub_range = min(internal->srch_range, range);
-	else
-		internal->sub_range = 0;
-
-	internal->freq = params->freq;
-	internal->tuner_offst = 0L;
-	internal->sub_dir = 1;
-}
-
-/*
- * stb0899_check_tmg
- * check for timing lock
- * internal.Ttiming: time to wait for loop lock
- */
-static enum stb0899_status stb0899_check_tmg(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal = &state->internal;
-	int lock;
-	u8 reg;
-	s8 timing;
-
-	msleep(internal->t_derot);
-
-	stb0899_write_reg(state, STB0899_RTF, 0xf2);
-	reg = stb0899_read_reg(state, STB0899_TLIR);
-	lock = STB0899_GETFIELD(TLIR_TMG_LOCK_IND, reg);
-	timing = stb0899_read_reg(state, STB0899_RTF);
-
-	if (lock >= 42) {
-		if ((lock > 48) && (abs(timing) >= 110)) {
-			internal->status = ANALOGCARRIER;
-			dprintk(state->verbose, FE_DEBUG, 1, "-->ANALOG Carrier !");
-		} else {
-			internal->status = TIMINGOK;
-			dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK !");
-		}
-	} else {
-		internal->status = NOTIMING;
-		dprintk(state->verbose, FE_DEBUG, 1, "-->NO TIMING !");
-	}
-	return internal->status;
-}
-
-/*
- * stb0899_search_tmg
- * perform a fs/2 zig-zag to find timing
- */
-static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal = &state->internal;
-	struct stb0899_params *params = &state->params;
-
-	short int derot_step, derot_freq = 0, derot_limit, next_loop = 3;
-	int index = 0;
-	u8 cfr[2];
-
-	internal->status = NOTIMING;
-
-	/* timing loop computation & symbol rate optimisation	*/
-	derot_limit = (internal->sub_range / 2L) / internal->mclk;
-	derot_step = (params->srate / 2L) / internal->mclk;
-
-	while ((stb0899_check_tmg(state) != TIMINGOK) && next_loop) {
-		index++;
-		derot_freq += index * internal->direction * derot_step;	/* next derot zig zag position	*/
-
-		if (abs(derot_freq) > derot_limit)
-			next_loop--;
-
-		if (next_loop) {
-			STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
-			STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
-			stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency		*/
-		}
-		internal->direction = -internal->direction;	/* Change zigzag direction		*/
-	}
-
-	if (internal->status == TIMINGOK) {
-		stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency		*/
-		internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
-		dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK ! Derot Freq = %d", internal->derot_freq);
-	}
-
-	return internal->status;
-}
-
-/*
- * stb0899_check_carrier
- * Check for carrier found
- */
-static enum stb0899_status stb0899_check_carrier(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal = &state->internal;
-	u8 reg;
-
-	msleep(internal->t_derot); /* wait for derotator ok	*/
-
-	reg = stb0899_read_reg(state, STB0899_CFD);
-	STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
-	stb0899_write_reg(state, STB0899_CFD, reg);
-
-	reg = stb0899_read_reg(state, STB0899_DSTATUS);
-	dprintk(state->verbose, FE_DEBUG, 1, "--------------------> STB0899_DSTATUS=[0x%02x]", reg);
-	if (STB0899_GETFIELD(CARRIER_FOUND, reg)) {
-		internal->status = CARRIEROK;
-		dprintk(state->verbose, FE_DEBUG, 1, "-------------> CARRIEROK !");
-	} else {
-		internal->status = NOCARRIER;
-		dprintk(state->verbose, FE_DEBUG, 1, "-------------> NOCARRIER !");
-	}
-
-	return internal->status;
-}
-
-/*
- * stb0899_search_carrier
- * Search for a QPSK carrier with the derotator
- */
-static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal = &state->internal;
-
-	short int derot_freq = 0, last_derot_freq = 0, derot_limit, next_loop = 3;
-	int index = 0;
-	u8 cfr[2];
-	u8 reg;
-
-	internal->status = NOCARRIER;
-	derot_limit = (internal->sub_range / 2L) / internal->mclk;
-	derot_freq = internal->derot_freq;
-
-	reg = stb0899_read_reg(state, STB0899_CFD);
-	STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
-	stb0899_write_reg(state, STB0899_CFD, reg);
-
-	do {
-		dprintk(state->verbose, FE_DEBUG, 1, "Derot Freq=%d, mclk=%d", derot_freq, internal->mclk);
-		if (stb0899_check_carrier(state) == NOCARRIER) {
-			index++;
-			last_derot_freq = derot_freq;
-			derot_freq += index * internal->direction * internal->derot_step; /* next zig zag derotator position */
-
-			if(abs(derot_freq) > derot_limit)
-				next_loop--;
-
-			if (next_loop) {
-				reg = stb0899_read_reg(state, STB0899_CFD);
-				STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
-				stb0899_write_reg(state, STB0899_CFD, reg);
-
-				STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
-				STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
-				stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency	*/
-			}
-		}
-
-		internal->direction = -internal->direction; /* Change zigzag direction */
-	} while ((internal->status != CARRIEROK) && next_loop);
-
-	if (internal->status == CARRIEROK) {
-		stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */
-		internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
-		dprintk(state->verbose, FE_DEBUG, 1, "----> CARRIER OK !, Derot Freq=%d", internal->derot_freq);
-	} else {
-		internal->derot_freq = last_derot_freq;
-	}
-
-	return internal->status;
-}
-
-/*
- * stb0899_check_data
- * Check for data found
- */
-static enum stb0899_status stb0899_check_data(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal = &state->internal;
-	struct stb0899_params *params = &state->params;
-
-	int lock = 0, index = 0, dataTime = 500, loop;
-	u8 reg;
-
-	internal->status = NODATA;
-
-	/* RESET FEC	*/
-	reg = stb0899_read_reg(state, STB0899_TSTRES);
-	STB0899_SETFIELD_VAL(FRESACS, reg, 1);
-	stb0899_write_reg(state, STB0899_TSTRES, reg);
-	msleep(1);
-	reg = stb0899_read_reg(state, STB0899_TSTRES);
-	STB0899_SETFIELD_VAL(FRESACS, reg, 0);
-	stb0899_write_reg(state, STB0899_TSTRES, reg);
-
-	if (params->srate <= 2000000)
-		dataTime = 2000;
-	else if (params->srate <= 5000000)
-		dataTime = 1500;
-	else if (params->srate <= 15000000)
-		dataTime = 1000;
-	else
-		dataTime = 500;
-
-	/* clear previous failed END_LOOPVIT */
-	stb0899_read_reg(state, STB0899_VSTATUS);
-
-	stb0899_write_reg(state, STB0899_DSTATUS2, 0x00); /* force search loop	*/
-	while (1) {
-		/* WARNING! VIT LOCKED has to be tested before VIT_END_LOOOP	*/
-		reg = stb0899_read_reg(state, STB0899_VSTATUS);
-		lock = STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg);
-		loop = STB0899_GETFIELD(VSTATUS_END_LOOPVIT, reg);
-
-		if (lock || loop || (index > dataTime))
-			break;
-		index++;
-	}
-
-	if (lock) {	/* DATA LOCK indicator	*/
-		internal->status = DATAOK;
-		dprintk(state->verbose, FE_DEBUG, 1, "-----------------> DATA OK !");
-	}
-
-	return internal->status;
-}
-
-/*
- * stb0899_search_data
- * Search for a QPSK carrier with the derotator
- */
-static enum stb0899_status stb0899_search_data(struct stb0899_state *state)
-{
-	short int derot_freq, derot_step, derot_limit, next_loop = 3;
-	u8 cfr[2];
-	u8 reg;
-	int index = 1;
-
-	struct stb0899_internal *internal = &state->internal;
-	struct stb0899_params *params = &state->params;
-
-	derot_step = (params->srate / 4L) / internal->mclk;
-	derot_limit = (internal->sub_range / 2L) / internal->mclk;
-	derot_freq = internal->derot_freq;
-
-	do {
-		if ((internal->status != CARRIEROK) || (stb0899_check_data(state) != DATAOK)) {
-
-			derot_freq += index * internal->direction * derot_step;	/* next zig zag derotator position */
-			if (abs(derot_freq) > derot_limit)
-				next_loop--;
-
-			if (next_loop) {
-				dprintk(state->verbose, FE_DEBUG, 1, "Derot freq=%d, mclk=%d", derot_freq, internal->mclk);
-				reg = stb0899_read_reg(state, STB0899_CFD);
-				STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
-				stb0899_write_reg(state, STB0899_CFD, reg);
-
-				STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
-				STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
-				stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency	*/
-
-				stb0899_check_carrier(state);
-				index++;
-			}
-		}
-		internal->direction = -internal->direction; /* change zig zag direction */
-	} while ((internal->status != DATAOK) && next_loop);
-
-	if (internal->status == DATAOK) {
-		stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */
-		internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
-		dprintk(state->verbose, FE_DEBUG, 1, "------> DATAOK ! Derot Freq=%d", internal->derot_freq);
-	}
-
-	return internal->status;
-}
-
-/*
- * stb0899_check_range
- * check if the found frequency is in the correct range
- */
-static enum stb0899_status stb0899_check_range(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal = &state->internal;
-	struct stb0899_params *params = &state->params;
-
-	int range_offst, tp_freq;
-
-	range_offst = internal->srch_range / 2000;
-	tp_freq = internal->freq + (internal->derot_freq * internal->mclk) / 1000;
-
-	if ((tp_freq >= params->freq - range_offst) && (tp_freq <= params->freq + range_offst)) {
-		internal->status = RANGEOK;
-		dprintk(state->verbose, FE_DEBUG, 1, "----> RANGEOK !");
-	} else {
-		internal->status = OUTOFRANGE;
-		dprintk(state->verbose, FE_DEBUG, 1, "----> OUT OF RANGE !");
-	}
-
-	return internal->status;
-}
-
-/*
- * NextSubRange
- * Compute the next subrange of the search
- */
-static void next_sub_range(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal = &state->internal;
-	struct stb0899_params *params = &state->params;
-
-	long old_sub_range;
-
-	if (internal->sub_dir > 0) {
-		old_sub_range = internal->sub_range;
-		internal->sub_range = min((internal->srch_range / 2) -
-					  (internal->tuner_offst + internal->sub_range / 2),
-					   internal->sub_range);
-
-		if (internal->sub_range < 0)
-			internal->sub_range = 0;
-
-		internal->tuner_offst += (old_sub_range + internal->sub_range) / 2;
-	}
-
-	internal->freq = params->freq + (internal->sub_dir * internal->tuner_offst) / 1000;
-	internal->sub_dir = -internal->sub_dir;
-}
-
-/*
- * stb0899_dvbs_algo
- * Search for a signal, timing, carrier and data for a
- * given frequency in a given range
- */
-enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state)
-{
-	struct stb0899_params *params		= &state->params;
-	struct stb0899_internal *internal	= &state->internal;
-	struct stb0899_config *config		= state->config;
-
-	u8 bclc, reg;
-	u8 cfr[2];
-	u8 eq_const[10];
-	s32 clnI = 3;
-	u32 bandwidth = 0;
-
-	/* BETA values rated @ 99MHz	*/
-	s32 betaTab[5][4] = {
-	       /*  5   10   20   30MBps */
-		{ 37,  34,  32,  31 }, /* QPSK 1/2	*/
-		{ 37,  35,  33,  31 }, /* QPSK 2/3	*/
-		{ 37,  35,  33,  31 }, /* QPSK 3/4	*/
-		{ 37,  36,  33,	 32 }, /* QPSK 5/6	*/
-		{ 37,  36,  33,	 32 }  /* QPSK 7/8	*/
-	};
-
-	internal->direction = 1;
-
-	stb0899_set_srate(state, internal->master_clk, params->srate);
-	/* Carrier loop optimization versus symbol rate for acquisition*/
-	if (params->srate <= 5000000) {
-		stb0899_write_reg(state, STB0899_ACLC, 0x89);
-		bclc = stb0899_read_reg(state, STB0899_BCLC);
-		STB0899_SETFIELD_VAL(BETA, bclc, 0x1c);
-		stb0899_write_reg(state, STB0899_BCLC, bclc);
-		clnI = 0;
-	} else if (params->srate <= 15000000) {
-		stb0899_write_reg(state, STB0899_ACLC, 0xc9);
-		bclc = stb0899_read_reg(state, STB0899_BCLC);
-		STB0899_SETFIELD_VAL(BETA, bclc, 0x22);
-		stb0899_write_reg(state, STB0899_BCLC, bclc);
-		clnI = 1;
-	} else if(params->srate <= 25000000) {
-		stb0899_write_reg(state, STB0899_ACLC, 0x89);
-		bclc = stb0899_read_reg(state, STB0899_BCLC);
-		STB0899_SETFIELD_VAL(BETA, bclc, 0x27);
-		stb0899_write_reg(state, STB0899_BCLC, bclc);
-		clnI = 2;
-	} else {
-		stb0899_write_reg(state, STB0899_ACLC, 0xc8);
-		bclc = stb0899_read_reg(state, STB0899_BCLC);
-		STB0899_SETFIELD_VAL(BETA, bclc, 0x29);
-		stb0899_write_reg(state, STB0899_BCLC, bclc);
-		clnI = 3;
-	}
-
-	dprintk(state->verbose, FE_DEBUG, 1, "Set the timing loop to acquisition");
-	/* Set the timing loop to acquisition	*/
-	stb0899_write_reg(state, STB0899_RTC, 0x46);
-	stb0899_write_reg(state, STB0899_CFD, 0xee);
-
-	/* !! WARNING !!
-	 * Do not read any status variables while acquisition,
-	 * If any needed, read before the acquisition starts
-	 * querying status while acquiring causes the
-	 * acquisition to go bad and hence no locks.
-	 */
-	dprintk(state->verbose, FE_DEBUG, 1, "Derot Percent=%d Srate=%d mclk=%d",
-		internal->derot_percent, params->srate, internal->mclk);
-
-	/* Initial calculations	*/
-	internal->derot_step = internal->derot_percent * (params->srate / 1000L) / internal->mclk; /* DerotStep/1000 * Fsymbol	*/
-	internal->t_derot = stb0899_calc_derot_time(params->srate);
-	internal->t_data = 500;
-
-	dprintk(state->verbose, FE_DEBUG, 1, "RESET stream merger");
-	/* RESET Stream merger	*/
-	reg = stb0899_read_reg(state, STB0899_TSTRES);
-	STB0899_SETFIELD_VAL(FRESRS, reg, 1);
-	stb0899_write_reg(state, STB0899_TSTRES, reg);
-
-	/*
-	 * Set KDIVIDER to an intermediate value between
-	 * 1/2 and 7/8 for acquisition
-	 */
-	reg = stb0899_read_reg(state, STB0899_DEMAPVIT);
-	STB0899_SETFIELD_VAL(DEMAPVIT_KDIVIDER, reg, 60);
-	stb0899_write_reg(state, STB0899_DEMAPVIT, reg);
-
-	stb0899_write_reg(state, STB0899_EQON, 0x01); /* Equalizer OFF while acquiring */
-	stb0899_write_reg(state, STB0899_VITSYNC, 0x19);
-
-	stb0899_first_subrange(state);
-	do {
-		/* Initialisations */
-		cfr[0] = cfr[1] = 0;
-		stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* RESET derotator frequency	*/
-
-		stb0899_write_reg(state, STB0899_RTF, 0);
-		reg = stb0899_read_reg(state, STB0899_CFD);
-		STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
-		stb0899_write_reg(state, STB0899_CFD, reg);
-
-		internal->derot_freq = 0;
-		internal->status = NOAGC1;
-
-		/* enable tuner I/O */
-		stb0899_i2c_gate_ctrl(&state->frontend, 1);
-
-		/* Move tuner to frequency */
-		dprintk(state->verbose, FE_DEBUG, 1, "Tuner set frequency");
-		if (state->config->tuner_set_frequency)
-			state->config->tuner_set_frequency(&state->frontend, internal->freq);
-
-		if (state->config->tuner_get_frequency)
-			state->config->tuner_get_frequency(&state->frontend, &internal->freq);
-
-		msleep(internal->t_agc1 + internal->t_agc2 + internal->t_derot); /* AGC1, AGC2 and timing loop	*/
-		dprintk(state->verbose, FE_DEBUG, 1, "current derot freq=%d", internal->derot_freq);
-		internal->status = AGC1OK;
-
-		/* There is signal in the band	*/
-		if (config->tuner_get_bandwidth)
-			config->tuner_get_bandwidth(&state->frontend, &bandwidth);
-
-		/* disable tuner I/O */
-		stb0899_i2c_gate_ctrl(&state->frontend, 0);
-
-		if (params->srate <= bandwidth / 2)
-			stb0899_search_tmg(state); /* For low rates (SCPC)	*/
-		else
-			stb0899_check_tmg(state); /* For high rates (MCPC)	*/
-
-		if (internal->status == TIMINGOK) {
-			dprintk(state->verbose, FE_DEBUG, 1,
-				"TIMING OK ! Derot freq=%d, mclk=%d",
-				internal->derot_freq, internal->mclk);
-
-			if (stb0899_search_carrier(state) == CARRIEROK) {	/* Search for carrier	*/
-				dprintk(state->verbose, FE_DEBUG, 1,
-					"CARRIER OK ! Derot freq=%d, mclk=%d",
-					internal->derot_freq, internal->mclk);
-
-				if (stb0899_search_data(state) == DATAOK) {	/* Check for data	*/
-					dprintk(state->verbose, FE_DEBUG, 1,
-						"DATA OK ! Derot freq=%d, mclk=%d",
-						internal->derot_freq, internal->mclk);
-
-					if (stb0899_check_range(state) == RANGEOK) {
-						dprintk(state->verbose, FE_DEBUG, 1,
-							"RANGE OK ! derot freq=%d, mclk=%d",
-							internal->derot_freq, internal->mclk);
-
-						internal->freq = params->freq + ((internal->derot_freq * internal->mclk) / 1000);
-						reg = stb0899_read_reg(state, STB0899_PLPARM);
-						internal->fecrate = STB0899_GETFIELD(VITCURPUN, reg);
-						dprintk(state->verbose, FE_DEBUG, 1,
-							"freq=%d, internal resultant freq=%d",
-							params->freq, internal->freq);
-
-						dprintk(state->verbose, FE_DEBUG, 1,
-							"internal puncture rate=%d",
-							internal->fecrate);
-					}
-				}
-			}
-		}
-		if (internal->status != RANGEOK)
-			next_sub_range(state);
-
-	} while (internal->sub_range && internal->status != RANGEOK);
-
-	/* Set the timing loop to tracking	*/
-	stb0899_write_reg(state, STB0899_RTC, 0x33);
-	stb0899_write_reg(state, STB0899_CFD, 0xf7);
-	/* if locked and range ok, set Kdiv	*/
-	if (internal->status == RANGEOK) {
-		dprintk(state->verbose, FE_DEBUG, 1, "Locked & Range OK !");
-		stb0899_write_reg(state, STB0899_EQON, 0x41);		/* Equalizer OFF while acquiring	*/
-		stb0899_write_reg(state, STB0899_VITSYNC, 0x39);	/* SN to b'11 for acquisition		*/
-
-		/*
-		 * Carrier loop optimization versus
-		 * symbol Rate/Puncture Rate for Tracking
-		 */
-		reg = stb0899_read_reg(state, STB0899_BCLC);
-		switch (internal->fecrate) {
-		case STB0899_FEC_1_2:		/* 13	*/
-			stb0899_write_reg(state, STB0899_DEMAPVIT, 0x1a);
-			STB0899_SETFIELD_VAL(BETA, reg, betaTab[0][clnI]);
-			stb0899_write_reg(state, STB0899_BCLC, reg);
-			break;
-		case STB0899_FEC_2_3:		/* 18	*/
-			stb0899_write_reg(state, STB0899_DEMAPVIT, 44);
-			STB0899_SETFIELD_VAL(BETA, reg, betaTab[1][clnI]);
-			stb0899_write_reg(state, STB0899_BCLC, reg);
-			break;
-		case STB0899_FEC_3_4:		/* 21	*/
-			stb0899_write_reg(state, STB0899_DEMAPVIT, 60);
-			STB0899_SETFIELD_VAL(BETA, reg, betaTab[2][clnI]);
-			stb0899_write_reg(state, STB0899_BCLC, reg);
-			break;
-		case STB0899_FEC_5_6:		/* 24	*/
-			stb0899_write_reg(state, STB0899_DEMAPVIT, 75);
-			STB0899_SETFIELD_VAL(BETA, reg, betaTab[3][clnI]);
-			stb0899_write_reg(state, STB0899_BCLC, reg);
-			break;
-		case STB0899_FEC_6_7:		/* 25	*/
-			stb0899_write_reg(state, STB0899_DEMAPVIT, 88);
-			stb0899_write_reg(state, STB0899_ACLC, 0x88);
-			stb0899_write_reg(state, STB0899_BCLC, 0x9a);
-			break;
-		case STB0899_FEC_7_8:		/* 26	*/
-			stb0899_write_reg(state, STB0899_DEMAPVIT, 94);
-			STB0899_SETFIELD_VAL(BETA, reg, betaTab[4][clnI]);
-			stb0899_write_reg(state, STB0899_BCLC, reg);
-			break;
-		default:
-			dprintk(state->verbose, FE_DEBUG, 1, "Unsupported Puncture Rate");
-			break;
-		}
-		/* release stream merger RESET	*/
-		reg = stb0899_read_reg(state, STB0899_TSTRES);
-		STB0899_SETFIELD_VAL(FRESRS, reg, 0);
-		stb0899_write_reg(state, STB0899_TSTRES, reg);
-
-		/* disable carrier detector	*/
-		reg = stb0899_read_reg(state, STB0899_CFD);
-		STB0899_SETFIELD_VAL(CFD_ON, reg, 0);
-		stb0899_write_reg(state, STB0899_CFD, reg);
-
-		stb0899_read_regs(state, STB0899_EQUAI1, eq_const, 10);
-	}
-
-	return internal->status;
-}
-
-/*
- * stb0899_dvbs2_config_uwp
- * Configure UWP state machine
- */
-static void stb0899_dvbs2_config_uwp(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal = &state->internal;
-	struct stb0899_config *config = state->config;
-	u32 uwp1, uwp2, uwp3, reg;
-
-	uwp1 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL1);
-	uwp2 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL2);
-	uwp3 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL3);
-
-	STB0899_SETFIELD_VAL(UWP_ESN0_AVE, uwp1, config->esno_ave);
-	STB0899_SETFIELD_VAL(UWP_ESN0_QUANT, uwp1, config->esno_quant);
-	STB0899_SETFIELD_VAL(UWP_TH_SOF, uwp1, config->uwp_threshold_sof);
-
-	STB0899_SETFIELD_VAL(FE_COARSE_TRK, uwp2, internal->av_frame_coarse);
-	STB0899_SETFIELD_VAL(FE_FINE_TRK, uwp2, internal->av_frame_fine);
-	STB0899_SETFIELD_VAL(UWP_MISS_TH, uwp2, config->miss_threshold);
-
-	STB0899_SETFIELD_VAL(UWP_TH_ACQ, uwp3, config->uwp_threshold_acq);
-	STB0899_SETFIELD_VAL(UWP_TH_TRACK, uwp3, config->uwp_threshold_track);
-
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL1, STB0899_OFF0_UWP_CNTRL1, uwp1);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL2, STB0899_OFF0_UWP_CNTRL2, uwp2);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL3, STB0899_OFF0_UWP_CNTRL3, uwp3);
-
-	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, SOF_SRCH_TO);
-	STB0899_SETFIELD_VAL(SOF_SEARCH_TIMEOUT, reg, config->sof_search_timeout);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_SOF_SRCH_TO, STB0899_OFF0_SOF_SRCH_TO, reg);
-}
-
-/*
- * stb0899_dvbs2_config_csm_auto
- * Set CSM to AUTO mode
- */
-static void stb0899_dvbs2_config_csm_auto(struct stb0899_state *state)
-{
-	u32 reg;
-
-	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
-	STB0899_SETFIELD_VAL(CSM_AUTO_PARAM, reg, 1);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, reg);
-}
-
-static long Log2Int(int number)
-{
-	int i;
-
-	i = 0;
-	while ((1 << i) <= abs(number))
-		i++;
-
-	if (number == 0)
-		i = 1;
-
-	return i - 1;
-}
-
-/*
- * stb0899_dvbs2_calc_srate
- * compute BTR_NOM_FREQ for the symbol rate
- */
-static u32 stb0899_dvbs2_calc_srate(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal	= &state->internal;
-	struct stb0899_config *config		= state->config;
-
-	u32 dec_ratio, dec_rate, decim, remain, intval, btr_nom_freq;
-	u32 master_clk, srate;
-
-	dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
-	dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
-	dec_rate = Log2Int(dec_ratio);
-	decim = 1 << dec_rate;
-	master_clk = internal->master_clk / 1000;
-	srate = internal->srate / 1000;
-
-	if (decim <= 4) {
-		intval = (decim * (1 << (config->btr_nco_bits - 1))) / master_clk;
-		remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk;
-	} else {
-		intval = (1 << (config->btr_nco_bits - 1)) / (master_clk / 100) * decim / 100;
-		remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk;
-	}
-	btr_nom_freq = (intval * srate) + ((remain * srate) / master_clk);
-
-	return btr_nom_freq;
-}
-
-/*
- * stb0899_dvbs2_calc_dev
- * compute the correction to be applied to symbol rate
- */
-static u32 stb0899_dvbs2_calc_dev(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal = &state->internal;
-	u32 dec_ratio, correction, master_clk, srate;
-
-	dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
-	dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
-
-	master_clk = internal->master_clk / 1000;	/* for integer Caculation*/
-	srate = internal->srate / 1000;	/* for integer Caculation*/
-	correction = (512 * master_clk) / (2 * dec_ratio * srate);
-
-	return	correction;
-}
-
-/*
- * stb0899_dvbs2_set_srate
- * Set DVBS2 symbol rate
- */
-static void stb0899_dvbs2_set_srate(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal = &state->internal;
-
-	u32 dec_ratio, dec_rate, win_sel, decim, f_sym, btr_nom_freq;
-	u32 correction, freq_adj, band_lim, decim_cntrl, reg;
-	u8 anti_alias;
-
-	/*set decimation to 1*/
-	dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
-	dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
-	dec_rate = Log2Int(dec_ratio);
-
-	win_sel = 0;
-	if (dec_rate >= 5)
-		win_sel = dec_rate - 4;
-
-	decim = (1 << dec_rate);
-	/* (FSamp/Fsymbol *100) for integer Caculation */
-	f_sym = internal->master_clk / ((decim * internal->srate) / 1000);
-
-	if (f_sym <= 2250)	/* don't band limit signal going into btr block*/
-		band_lim = 1;
-	else
-		band_lim = 0;	/* band limit signal going into btr block*/
-
-	decim_cntrl = ((win_sel << 3) & 0x18) + ((band_lim << 5) & 0x20) + (dec_rate & 0x7);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DECIM_CNTRL, STB0899_OFF0_DECIM_CNTRL, decim_cntrl);
-
-	if (f_sym <= 3450)
-		anti_alias = 0;
-	else if (f_sym <= 4250)
-		anti_alias = 1;
-	else
-		anti_alias = 2;
-
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ANTI_ALIAS_SEL, STB0899_OFF0_ANTI_ALIAS_SEL, anti_alias);
-	btr_nom_freq = stb0899_dvbs2_calc_srate(state);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_NOM_FREQ, STB0899_OFF0_BTR_NOM_FREQ, btr_nom_freq);
-
-	correction = stb0899_dvbs2_calc_dev(state);
-	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL);
-	STB0899_SETFIELD_VAL(BTR_FREQ_CORR, reg, correction);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg);
-
-	/* scale UWP+CSM frequency to sample rate*/
-	freq_adj =  internal->srate / (internal->master_clk / 4096);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_FREQ_ADJ_SCALE, STB0899_OFF0_FREQ_ADJ_SCALE, freq_adj);
-}
-
-/*
- * stb0899_dvbs2_set_btr_loopbw
- * set bit timing loop bandwidth as a percentage of the symbol rate
- */
-static void stb0899_dvbs2_set_btr_loopbw(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal	= &state->internal;
-	struct stb0899_config *config		= state->config;
-
-	u32 sym_peak = 23, zeta = 707, loopbw_percent = 60;
-	s32 dec_ratio, dec_rate, k_btr1_rshft, k_btr1, k_btr0_rshft;
-	s32 k_btr0, k_btr2_rshft, k_direct_shift, k_indirect_shift;
-	u32 decim, K, wn, k_direct, k_indirect;
-	u32 reg;
-
-	dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
-	dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
-	dec_rate = Log2Int(dec_ratio);
-	decim = (1 << dec_rate);
-
-	sym_peak *= 576000;
-	K = (1 << config->btr_nco_bits) / (internal->master_clk / 1000);
-	K *= (internal->srate / 1000000) * decim; /*k=k 10^-8*/
-
-	if (K != 0) {
-		K = sym_peak / K;
-		wn = (4 * zeta * zeta) + 1000000;
-		wn = (2 * (loopbw_percent * 1000) * 40 * zeta) /wn;  /*wn =wn 10^-8*/
-
-		k_indirect = (wn * wn) / K;
-		k_indirect = k_indirect;	  /*kindirect = kindirect 10^-6*/
-		k_direct   = (2 * wn * zeta) / K;	/*kDirect = kDirect 10^-2*/
-		k_direct  *= 100;
-
-		k_direct_shift = Log2Int(k_direct) - Log2Int(10000) - 2;
-		k_btr1_rshft = (-1 * k_direct_shift) + config->btr_gain_shift_offset;
-		k_btr1 = k_direct / (1 << k_direct_shift);
-		k_btr1 /= 10000;
-
-		k_indirect_shift = Log2Int(k_indirect + 15) - 20 /*- 2*/;
-		k_btr0_rshft = (-1 * k_indirect_shift) + config->btr_gain_shift_offset;
-		k_btr0 = k_indirect * (1 << (-k_indirect_shift));
-		k_btr0 /= 1000000;
-
-		k_btr2_rshft = 0;
-		if (k_btr0_rshft > 15) {
-			k_btr2_rshft = k_btr0_rshft - 15;
-			k_btr0_rshft = 15;
-		}
-		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_LOOP_GAIN);
-		STB0899_SETFIELD_VAL(KBTR0_RSHFT, reg, k_btr0_rshft);
-		STB0899_SETFIELD_VAL(KBTR0, reg, k_btr0);
-		STB0899_SETFIELD_VAL(KBTR1_RSHFT, reg, k_btr1_rshft);
-		STB0899_SETFIELD_VAL(KBTR1, reg, k_btr1);
-		STB0899_SETFIELD_VAL(KBTR2_RSHFT, reg, k_btr2_rshft);
-		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, reg);
-	} else
-		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, 0xc4c4f);
-}
-
-/*
- * stb0899_dvbs2_set_carr_freq
- * set nominal frequency for carrier search
- */
-static void stb0899_dvbs2_set_carr_freq(struct stb0899_state *state, s32 carr_freq, u32 master_clk)
-{
-	struct stb0899_config *config = state->config;
-	s32 crl_nom_freq;
-	u32 reg;
-
-	crl_nom_freq = (1 << config->crl_nco_bits) / master_clk;
-	crl_nom_freq *= carr_freq;
-	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ);
-	STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, crl_nom_freq);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg);
-}
-
-/*
- * stb0899_dvbs2_init_calc
- * Initialize DVBS2 UWP, CSM, carrier and timing loops
- */
-static void stb0899_dvbs2_init_calc(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal = &state->internal;
-	s32 steps, step_size;
-	u32 range, reg;
-
-	/* config uwp and csm */
-	stb0899_dvbs2_config_uwp(state);
-	stb0899_dvbs2_config_csm_auto(state);
-
-	/* initialize BTR	*/
-	stb0899_dvbs2_set_srate(state);
-	stb0899_dvbs2_set_btr_loopbw(state);
-
-	if (internal->srate / 1000000 >= 15)
-		step_size = (1 << 17) / 5;
-	else if (internal->srate / 1000000 >= 10)
-		step_size = (1 << 17) / 7;
-	else if (internal->srate / 1000000 >= 5)
-		step_size = (1 << 17) / 10;
-	else
-		step_size = (1 << 17) / 4;
-
-	range = internal->srch_range / 1000000;
-	steps = (10 * range * (1 << 17)) / (step_size * (internal->srate / 1000000));
-	steps = (steps + 6) / 10;
-	steps = (steps == 0) ? 1 : steps;
-	if (steps % 2 == 0)
-		stb0899_dvbs2_set_carr_freq(state, internal->center_freq -
-					   (internal->step_size * (internal->srate / 20000000)),
-					   (internal->master_clk) / 1000000);
-	else
-		stb0899_dvbs2_set_carr_freq(state, internal->center_freq, (internal->master_clk) / 1000000);
-
-	/*Set Carrier Search params (zigzag, num steps and freq step size*/
-	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, ACQ_CNTRL2);
-	STB0899_SETFIELD_VAL(ZIGZAG, reg, 1);
-	STB0899_SETFIELD_VAL(NUM_STEPS, reg, steps);
-	STB0899_SETFIELD_VAL(FREQ_STEPSIZE, reg, step_size);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQ_CNTRL2, STB0899_OFF0_ACQ_CNTRL2, reg);
-}
-
-/*
- * stb0899_dvbs2_btr_init
- * initialize the timing loop
- */
-static void stb0899_dvbs2_btr_init(struct stb0899_state *state)
-{
-	u32 reg;
-
-	/* set enable BTR loopback	*/
-	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL);
-	STB0899_SETFIELD_VAL(INTRP_PHS_SENSE, reg, 1);
-	STB0899_SETFIELD_VAL(BTR_ERR_ENA, reg, 1);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg);
-
-	/* fix btr freq accum at 0	*/
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x10000000);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x00000000);
-
-	/* fix btr freq accum at 0	*/
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x10000000);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x00000000);
-}
-
-/*
- * stb0899_dvbs2_reacquire
- * trigger a DVB-S2 acquisition
- */
-static void stb0899_dvbs2_reacquire(struct stb0899_state *state)
-{
-	u32 reg = 0;
-
-	/* demod soft reset	*/
-	STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 1);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg);
-
-	/*Reset Timing Loop	*/
-	stb0899_dvbs2_btr_init(state);
-
-	/* reset Carrier loop	*/
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, (1 << 30));
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, 0);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_LOOP_GAIN, STB0899_OFF0_CRL_LOOP_GAIN, 0);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, (1 << 30));
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, 0);
-
-	/*release demod soft reset	*/
-	reg = 0;
-	STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 0);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg);
-
-	/* start acquisition process	*/
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQUIRE_TRIG, STB0899_OFF0_ACQUIRE_TRIG, 1);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_LOCK_LOST, STB0899_OFF0_LOCK_LOST, 0);
-
-	/* equalizer Init	*/
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 1);
-
-	/*Start equilizer	*/
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 0);
-
-	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL);
-	STB0899_SETFIELD_VAL(EQ_SHIFT, reg, 0);
-	STB0899_SETFIELD_VAL(EQ_DISABLE_UPDATE, reg, 0);
-	STB0899_SETFIELD_VAL(EQ_DELAY, reg, 0x05);
-	STB0899_SETFIELD_VAL(EQ_ADAPT_MODE, reg, 0x01);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg);
-
-	/* RESET Packet delineator	*/
-	stb0899_write_reg(state, STB0899_PDELCTRL, 0x4a);
-}
-
-/*
- * stb0899_dvbs2_get_dmd_status
- * get DVB-S2 Demod LOCK status
- */
-static enum stb0899_status stb0899_dvbs2_get_dmd_status(struct stb0899_state *state, int timeout)
-{
-	int time = -10, lock = 0, uwp, csm;
-	u32 reg;
-
-	do {
-		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STATUS);
-		dprintk(state->verbose, FE_DEBUG, 1, "DMD_STATUS=[0x%02x]", reg);
-		if (STB0899_GETFIELD(IF_AGC_LOCK, reg))
-			dprintk(state->verbose, FE_DEBUG, 1, "------------->IF AGC LOCKED !");
-		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STAT2);
-		dprintk(state->verbose, FE_DEBUG, 1, "----------->DMD STAT2=[0x%02x]", reg);
-		uwp = STB0899_GETFIELD(UWP_LOCK, reg);
-		csm = STB0899_GETFIELD(CSM_LOCK, reg);
-		if (uwp && csm)
-			lock = 1;
-
-		time += 10;
-		msleep(10);
-
-	} while ((!lock) && (time <= timeout));
-
-	if (lock) {
-		dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 LOCK !");
-		return DVBS2_DEMOD_LOCK;
-	} else {
-		return DVBS2_DEMOD_NOLOCK;
-	}
-}
-
-/*
- * stb0899_dvbs2_get_data_lock
- * get FEC status
- */
-static int stb0899_dvbs2_get_data_lock(struct stb0899_state *state, int timeout)
-{
-	int time = 0, lock = 0;
-	u8 reg;
-
-	while ((!lock) && (time < timeout)) {
-		reg = stb0899_read_reg(state, STB0899_CFGPDELSTATUS1);
-		dprintk(state->verbose, FE_DEBUG, 1, "---------> CFGPDELSTATUS=[0x%02x]", reg);
-		lock = STB0899_GETFIELD(CFGPDELSTATUS_LOCK, reg);
-		time++;
-	}
-
-	return lock;
-}
-
-/*
- * stb0899_dvbs2_get_fec_status
- * get DVB-S2 FEC LOCK status
- */
-static enum stb0899_status stb0899_dvbs2_get_fec_status(struct stb0899_state *state, int timeout)
-{
-	int time = 0, Locked;
-
-	do {
-		Locked = stb0899_dvbs2_get_data_lock(state, 1);
-		time++;
-		msleep(1);
-
-	} while ((!Locked) && (time < timeout));
-
-	if (Locked) {
-		dprintk(state->verbose, FE_DEBUG, 1, "---------->DVB-S2 FEC LOCK !");
-		return DVBS2_FEC_LOCK;
-	} else {
-		return DVBS2_FEC_NOLOCK;
-	}
-}
-
-
-/*
- * stb0899_dvbs2_init_csm
- * set parameters for manual mode
- */
-static void stb0899_dvbs2_init_csm(struct stb0899_state *state, int pilots, enum stb0899_modcod modcod)
-{
-	struct stb0899_internal *internal = &state->internal;
-
-	s32 dvt_tbl = 1, two_pass = 0, agc_gain = 6, agc_shift = 0, loop_shift = 0, phs_diff_thr = 0x80;
-	s32 gamma_acq, gamma_rho_acq, gamma_trk, gamma_rho_trk, lock_count_thr;
-	u32 csm1, csm2, csm3, csm4;
-
-	if (((internal->master_clk / internal->srate) <= 4) && (modcod <= 11) && (pilots == 1)) {
-		switch (modcod) {
-		case STB0899_QPSK_12:
-			gamma_acq		= 25;
-			gamma_rho_acq		= 2700;
-			gamma_trk		= 12;
-			gamma_rho_trk		= 180;
-			lock_count_thr		= 8;
-			break;
-		case STB0899_QPSK_35:
-			gamma_acq		= 38;
-			gamma_rho_acq		= 7182;
-			gamma_trk		= 14;
-			gamma_rho_trk		= 308;
-			lock_count_thr		= 8;
-			break;
-		case STB0899_QPSK_23:
-			gamma_acq		= 42;
-			gamma_rho_acq		= 9408;
-			gamma_trk		= 17;
-			gamma_rho_trk		= 476;
-			lock_count_thr		= 8;
-			break;
-		case STB0899_QPSK_34:
-			gamma_acq		= 53;
-			gamma_rho_acq		= 16642;
-			gamma_trk		= 19;
-			gamma_rho_trk		= 646;
-			lock_count_thr		= 8;
-			break;
-		case STB0899_QPSK_45:
-			gamma_acq		= 53;
-			gamma_rho_acq		= 17119;
-			gamma_trk		= 22;
-			gamma_rho_trk		= 880;
-			lock_count_thr		= 8;
-			break;
-		case STB0899_QPSK_56:
-			gamma_acq		= 55;
-			gamma_rho_acq		= 19250;
-			gamma_trk		= 23;
-			gamma_rho_trk		= 989;
-			lock_count_thr		= 8;
-			break;
-		case STB0899_QPSK_89:
-			gamma_acq		= 60;
-			gamma_rho_acq		= 24240;
-			gamma_trk		= 24;
-			gamma_rho_trk		= 1176;
-			lock_count_thr		= 8;
-			break;
-		case STB0899_QPSK_910:
-			gamma_acq		= 66;
-			gamma_rho_acq		= 29634;
-			gamma_trk		= 24;
-			gamma_rho_trk		= 1176;
-			lock_count_thr		= 8;
-			break;
-		default:
-			gamma_acq		= 66;
-			gamma_rho_acq		= 29634;
-			gamma_trk		= 24;
-			gamma_rho_trk		= 1176;
-			lock_count_thr		= 8;
-			break;
-		}
-
-		csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
-		STB0899_SETFIELD_VAL(CSM_AUTO_PARAM, csm1, 0);
-		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1);
-
-		csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
-		csm2 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL2);
-		csm3 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL3);
-		csm4 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL4);
-
-		STB0899_SETFIELD_VAL(CSM_DVT_TABLE, csm1, dvt_tbl);
-		STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, two_pass);
-		STB0899_SETFIELD_VAL(CSM_AGC_GAIN, csm1, agc_gain);
-		STB0899_SETFIELD_VAL(CSM_AGC_SHIFT, csm1, agc_shift);
-		STB0899_SETFIELD_VAL(FE_LOOP_SHIFT, csm1, loop_shift);
-		STB0899_SETFIELD_VAL(CSM_GAMMA_ACQ, csm2, gamma_acq);
-		STB0899_SETFIELD_VAL(CSM_GAMMA_RHOACQ, csm2, gamma_rho_acq);
-		STB0899_SETFIELD_VAL(CSM_GAMMA_TRACK, csm3, gamma_trk);
-		STB0899_SETFIELD_VAL(CSM_GAMMA_RHOTRACK, csm3, gamma_rho_trk);
-		STB0899_SETFIELD_VAL(CSM_LOCKCOUNT_THRESH, csm4, lock_count_thr);
-		STB0899_SETFIELD_VAL(CSM_PHASEDIFF_THRESH, csm4, phs_diff_thr);
-
-		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1);
-		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL2, STB0899_OFF0_CSM_CNTRL2, csm2);
-		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL3, STB0899_OFF0_CSM_CNTRL3, csm3);
-		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL4, STB0899_OFF0_CSM_CNTRL4, csm4);
-	}
-}
-
-/*
- * stb0899_dvbs2_get_srate
- * get DVB-S2 Symbol Rate
- */
-static u32 stb0899_dvbs2_get_srate(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal = &state->internal;
-	struct stb0899_config *config = state->config;
-
-	u32 bTrNomFreq, srate, decimRate, intval1, intval2, reg;
-	int div1, div2, rem1, rem2;
-
-	div1 = config->btr_nco_bits / 2;
-	div2 = config->btr_nco_bits - div1 - 1;
-
-	bTrNomFreq = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_NOM_FREQ);
-
-	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DECIM_CNTRL);
-	decimRate = STB0899_GETFIELD(DECIM_RATE, reg);
-	decimRate = (1 << decimRate);
-
-	intval1 = internal->master_clk / (1 << div1);
-	intval2 = bTrNomFreq / (1 << div2);
-
-	rem1 = internal->master_clk % (1 << div1);
-	rem2 = bTrNomFreq % (1 << div2);
-	/* only for integer calculation	*/
-	srate = (intval1 * intval2) + ((intval1 * rem2) / (1 << div2)) + ((intval2 * rem1) / (1 << div1));
-	srate /= decimRate;	/*symbrate = (btrnomfreq_register_val*MasterClock)/2^(27+decim_rate_field) */
-
-	return	srate;
-}
-
-/*
- * stb0899_dvbs2_algo
- * Search for signal, timing, carrier and data for a given
- * frequency in a given range
- */
-enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal = &state->internal;
-	enum stb0899_modcod modcod;
-
-	s32 offsetfreq, searchTime, FecLockTime, pilots, iqSpectrum;
-	int i = 0;
-	u32 reg, csm1;
-
-	if (internal->srate <= 2000000) {
-		searchTime	= 5000;	/* 5000 ms max time to lock UWP and CSM, SYMB <= 2Mbs		*/
-		FecLockTime	= 350;	/* 350  ms max time to lock FEC, SYMB <= 2Mbs			*/
-	} else if (internal->srate <= 5000000) {
-		searchTime	= 2500;	/* 2500 ms max time to lock UWP and CSM, 2Mbs < SYMB <= 5Mbs	*/
-		FecLockTime	= 170;	/* 170  ms max time to lock FEC, 2Mbs< SYMB <= 5Mbs		*/
-	} else if (internal->srate <= 10000000) {
-		searchTime	= 1500;	/* 1500 ms max time to lock UWP and CSM, 5Mbs <SYMB <= 10Mbs	*/
-		FecLockTime	= 80;	/* 80  ms max time to lock FEC, 5Mbs< SYMB <= 10Mbs		*/
-	} else if (internal->srate <= 15000000) {
-		searchTime	= 500;	/* 500 ms max time to lock UWP and CSM, 10Mbs <SYMB <= 15Mbs	*/
-		FecLockTime	= 50;	/* 50  ms max time to lock FEC, 10Mbs< SYMB <= 15Mbs		*/
-	} else if (internal->srate <= 20000000) {
-		searchTime	= 300;	/* 300 ms max time to lock UWP and CSM, 15Mbs < SYMB <= 20Mbs	*/
-		FecLockTime	= 30;	/* 50  ms max time to lock FEC, 15Mbs< SYMB <= 20Mbs		*/
-	} else if (internal->srate <= 25000000) {
-		searchTime	= 250;	/* 250 ms max time to lock UWP and CSM, 20 Mbs < SYMB <= 25Mbs	*/
-		FecLockTime	= 25;	/* 25 ms max time to lock FEC, 20Mbs< SYMB <= 25Mbs		*/
-	} else {
-		searchTime	= 150;	/* 150 ms max time to lock UWP and CSM, SYMB > 25Mbs		*/
-		FecLockTime	= 20;	/* 20 ms max time to lock FEC, 20Mbs< SYMB <= 25Mbs		*/
-	}
-
-	/* Maintain Stream Merger in reset during acquisition	*/
-	reg = stb0899_read_reg(state, STB0899_TSTRES);
-	STB0899_SETFIELD_VAL(FRESRS, reg, 1);
-	stb0899_write_reg(state, STB0899_TSTRES, reg);
-
-	/* enable tuner I/O */
-	stb0899_i2c_gate_ctrl(&state->frontend, 1);
-
-	/* Move tuner to frequency	*/
-	if (state->config->tuner_set_frequency)
-		state->config->tuner_set_frequency(&state->frontend, internal->freq);
-	if (state->config->tuner_get_frequency)
-		state->config->tuner_get_frequency(&state->frontend, &internal->freq);
-
-	/* disable tuner I/O */
-	stb0899_i2c_gate_ctrl(&state->frontend, 0);
-
-	/* Set IF AGC to acquisition	*/
-	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL);
-	STB0899_SETFIELD_VAL(IF_LOOP_GAIN, reg,  4);
-	STB0899_SETFIELD_VAL(IF_AGC_REF, reg, 32);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg);
-
-	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL2);
-	STB0899_SETFIELD_VAL(IF_AGC_DUMP_PER, reg, 0);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL2, STB0899_OFF0_IF_AGC_CNTRL2, reg);
-
-	/* Initialisation	*/
-	stb0899_dvbs2_init_calc(state);
-
-	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
-	switch (internal->inversion) {
-	case IQ_SWAP_OFF:
-		STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 0);
-		break;
-	case IQ_SWAP_ON:
-		STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1);
-		break;
-	case IQ_SWAP_AUTO:	/* use last successful search first	*/
-		STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1);
-		break;
-	}
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg);
-	stb0899_dvbs2_reacquire(state);
-
-	/* Wait for demod lock (UWP and CSM)	*/
-	internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime);
-
-	if (internal->status == DVBS2_DEMOD_LOCK) {
-		dprintk(state->verbose, FE_DEBUG, 1, "------------> DVB-S2 DEMOD LOCK !");
-		i = 0;
-		/* Demod Locked, check FEC status	*/
-		internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
-
-		/*If false lock (UWP and CSM Locked but no FEC) try 3 time max*/
-		while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) {
-			/*	Read the frequency offset*/
-			offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
-
-			/* Set the Nominal frequency to the found frequency offset for the next reacquire*/
-			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ);
-			STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq);
-			stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg);
-			stb0899_dvbs2_reacquire(state);
-			internal->status = stb0899_dvbs2_get_fec_status(state, searchTime);
-			i++;
-		}
-	}
-
-	if (internal->status != DVBS2_FEC_LOCK) {
-		if (internal->inversion == IQ_SWAP_AUTO) {
-			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
-			iqSpectrum = STB0899_GETFIELD(SPECTRUM_INVERT, reg);
-			/* IQ Spectrum Inversion	*/
-			STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, !iqSpectrum);
-			stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg);
-			/* start acquistion process	*/
-			stb0899_dvbs2_reacquire(state);
-
-			/* Wait for demod lock (UWP and CSM)	*/
-			internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime);
-			if (internal->status == DVBS2_DEMOD_LOCK) {
-				i = 0;
-				/* Demod Locked, check FEC	*/
-				internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
-				/*try thrice for false locks, (UWP and CSM Locked but no FEC)	*/
-				while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) {
-					/*	Read the frequency offset*/
-					offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
-
-					/* Set the Nominal frequency to the found frequency offset for the next reacquire*/
-					reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ);
-					STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq);
-					stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg);
-
-					stb0899_dvbs2_reacquire(state);
-					internal->status = stb0899_dvbs2_get_fec_status(state, searchTime);
-					i++;
-				}
-			}
-/*
-			if (pParams->DVBS2State == FE_DVBS2_FEC_LOCKED)
-				pParams->IQLocked = !iqSpectrum;
-*/
-		}
-	}
-	if (internal->status == DVBS2_FEC_LOCK) {
-		dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 FEC Lock !");
-		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2);
-		modcod = STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 2;
-		pilots = STB0899_GETFIELD(UWP_DECODE_MOD, reg) & 0x01;
-
-		if ((((10 * internal->master_clk) / (internal->srate / 10)) <= 410) &&
-		      (INRANGE(STB0899_QPSK_23, modcod, STB0899_QPSK_910)) &&
-		      (pilots == 1)) {
-
-			stb0899_dvbs2_init_csm(state, pilots, modcod);
-			/* Wait for UWP,CSM and data LOCK 20ms max	*/
-			internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
-
-			i = 0;
-			while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) {
-				csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
-				STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, 1);
-				stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1);
-				csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
-				STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, 0);
-				stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1);
-
-				internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
-				i++;
-			}
-		}
-
-		if ((((10 * internal->master_clk) / (internal->srate / 10)) <= 410) &&
-		      (INRANGE(STB0899_QPSK_12, modcod, STB0899_QPSK_35)) &&
-		      (pilots == 1)) {
-
-			/* Equalizer Disable update	 */
-			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL);
-			STB0899_SETFIELD_VAL(EQ_DISABLE_UPDATE, reg, 1);
-			stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg);
-		}
-
-		/* slow down the Equalizer once locked	*/
-		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL);
-		STB0899_SETFIELD_VAL(EQ_SHIFT, reg, 0x02);
-		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg);
-
-		/* Store signal parameters	*/
-		offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
-
-		offsetfreq = offsetfreq / ((1 << 30) / 1000);
-		offsetfreq *= (internal->master_clk / 1000000);
-		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
-		if (STB0899_GETFIELD(SPECTRUM_INVERT, reg))
-			offsetfreq *= -1;
-
-		internal->freq = internal->freq - offsetfreq;
-		internal->srate = stb0899_dvbs2_get_srate(state);
-
-		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2);
-		internal->modcod = STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 2;
-		internal->pilots = STB0899_GETFIELD(UWP_DECODE_MOD, reg) & 0x01;
-		internal->frame_length = (STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 1) & 0x01;
-
-		 /* Set IF AGC to tracking	*/
-		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL);
-		STB0899_SETFIELD_VAL(IF_LOOP_GAIN, reg,  3);
-
-		/* if QPSK 1/2,QPSK 3/5 or QPSK 2/3 set IF AGC reference to 16 otherwise 32*/
-		if (INRANGE(STB0899_QPSK_12, internal->modcod, STB0899_QPSK_23))
-			STB0899_SETFIELD_VAL(IF_AGC_REF, reg, 16);
-
-		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg);
-
-		reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL2);
-		STB0899_SETFIELD_VAL(IF_AGC_DUMP_PER, reg, 7);
-		stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL2, STB0899_OFF0_IF_AGC_CNTRL2, reg);
-	}
-
-	/* Release Stream Merger Reset		*/
-	reg = stb0899_read_reg(state, STB0899_TSTRES);
-	STB0899_SETFIELD_VAL(FRESRS, reg, 0);
-	stb0899_write_reg(state, STB0899_TSTRES, reg);
-
-	return internal->status;
-}
diff --git a/drivers/media/dvb/frontends/stb0899_cfg.h b/drivers/media/dvb/frontends/stb0899_cfg.h
deleted file mode 100644
index 0867906..0000000
--- a/drivers/media/dvb/frontends/stb0899_cfg.h
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
-	STB0899 Multistandard Frontend driver
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	Copyright (C) ST Microelectronics
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __STB0899_CFG_H
-#define __STB0899_CFG_H
-
-static const struct stb0899_s2_reg  stb0899_s2_init_2[] = {
-
-	{ STB0899_OFF0_DMD_STATUS	, STB0899_BASE_DMD_STATUS	, 0x00000103 },	/* DMDSTATUS	*/
-	{ STB0899_OFF0_CRL_FREQ		, STB0899_BASE_CRL_FREQ		, 0x3ed1da56 },	/* CRLFREQ	*/
-	{ STB0899_OFF0_BTR_FREQ		, STB0899_BASE_BTR_FREQ		, 0x00004000 },	/* BTRFREQ	*/
-	{ STB0899_OFF0_IF_AGC_GAIN	, STB0899_BASE_IF_AGC_GAIN	, 0x00002ade },	/* IFAGCGAIN	*/
-	{ STB0899_OFF0_BB_AGC_GAIN	, STB0899_BASE_BB_AGC_GAIN	, 0x000001bc },	/* BBAGCGAIN	*/
-	{ STB0899_OFF0_DC_OFFSET	, STB0899_BASE_DC_OFFSET	, 0x00000200 },	/* DCOFFSET	*/
-	{ STB0899_OFF0_DMD_CNTRL	, STB0899_BASE_DMD_CNTRL	, 0x0000000f },	/* DMDCNTRL	*/
-
-	{ STB0899_OFF0_IF_AGC_CNTRL	, STB0899_BASE_IF_AGC_CNTRL	, 0x03fb4a20 },	/* IFAGCCNTRL	*/
-	{ STB0899_OFF0_BB_AGC_CNTRL	, STB0899_BASE_BB_AGC_CNTRL	, 0x00200c97 },	/* BBAGCCNTRL	*/
-
-	{ STB0899_OFF0_CRL_CNTRL	, STB0899_BASE_CRL_CNTRL	, 0x00000016 },	/* CRLCNTRL	*/
-	{ STB0899_OFF0_CRL_PHS_INIT	, STB0899_BASE_CRL_PHS_INIT	, 0x00000000 },	/* CRLPHSINIT	*/
-	{ STB0899_OFF0_CRL_FREQ_INIT	, STB0899_BASE_CRL_FREQ_INIT	, 0x00000000 },	/* CRLFREQINIT	*/
-	{ STB0899_OFF0_CRL_LOOP_GAIN	, STB0899_BASE_CRL_LOOP_GAIN	, 0x00000000 },	/* CRLLOOPGAIN	*/
-	{ STB0899_OFF0_CRL_NOM_FREQ	, STB0899_BASE_CRL_NOM_FREQ	, 0x3ed097b6 },	/* CRLNOMFREQ	*/
-	{ STB0899_OFF0_CRL_SWP_RATE	, STB0899_BASE_CRL_SWP_RATE	, 0x00000000 },	/* CRLSWPRATE	*/
-	{ STB0899_OFF0_CRL_MAX_SWP	, STB0899_BASE_CRL_MAX_SWP	, 0x00000000 },	/* CRLMAXSWP	*/
-	{ STB0899_OFF0_CRL_LK_CNTRL	, STB0899_BASE_CRL_LK_CNTRL	, 0x0f6cdc01 },	/* CRLLKCNTRL	*/
-	{ STB0899_OFF0_DECIM_CNTRL	, STB0899_BASE_DECIM_CNTRL	, 0x00000000 },	/* DECIMCNTRL	*/
-	{ STB0899_OFF0_BTR_CNTRL	, STB0899_BASE_BTR_CNTRL	, 0x00003993 },	/* BTRCNTRL	*/
-	{ STB0899_OFF0_BTR_LOOP_GAIN	, STB0899_BASE_BTR_LOOP_GAIN	, 0x000d3c6f },	/* BTRLOOPGAIN	*/
-	{ STB0899_OFF0_BTR_PHS_INIT	, STB0899_BASE_BTR_PHS_INIT	, 0x00000000 },	/* BTRPHSINIT	*/
-	{ STB0899_OFF0_BTR_FREQ_INIT	, STB0899_BASE_BTR_FREQ_INIT	, 0x00000000 },	/* BTRFREQINIT	*/
-	{ STB0899_OFF0_BTR_NOM_FREQ	, STB0899_BASE_BTR_NOM_FREQ	, 0x0238e38e },	/* BTRNOMFREQ	*/
-	{ STB0899_OFF0_BTR_LK_CNTRL	, STB0899_BASE_BTR_LK_CNTRL	, 0x00000000 },	/* BTRLKCNTRL	*/
-	{ STB0899_OFF0_DECN_CNTRL	, STB0899_BASE_DECN_CNTRL	, 0x00000000 },	/* DECNCNTRL	*/
-	{ STB0899_OFF0_TP_CNTRL		, STB0899_BASE_TP_CNTRL		, 0x00000000 },	/* TPCNTRL	*/
-	{ STB0899_OFF0_TP_BUF_STATUS	, STB0899_BASE_TP_BUF_STATUS	, 0x00000000 },	/* TPBUFSTATUS	*/
-	{ STB0899_OFF0_DC_ESTIM		, STB0899_BASE_DC_ESTIM		, 0x00000000 },	/* DCESTIM	*/
-	{ STB0899_OFF0_FLL_CNTRL	, STB0899_BASE_FLL_CNTRL	, 0x00000000 },	/* FLLCNTRL	*/
-	{ STB0899_OFF0_FLL_FREQ_WD	, STB0899_BASE_FLL_FREQ_WD	, 0x40070000 },	/* FLLFREQWD	*/
-	{ STB0899_OFF0_ANTI_ALIAS_SEL	, STB0899_BASE_ANTI_ALIAS_SEL	, 0x00000001 },	/* ANTIALIASSEL */
-	{ STB0899_OFF0_RRC_ALPHA	, STB0899_BASE_RRC_ALPHA	, 0x00000002 },	/* RRCALPHA	*/
-	{ STB0899_OFF0_DC_ADAPT_LSHFT	, STB0899_BASE_DC_ADAPT_LSHFT	, 0x00000000 },	/* DCADAPTISHFT */
-	{ STB0899_OFF0_IMB_OFFSET	, STB0899_BASE_IMB_OFFSET	, 0x0000fe01 },	/* IMBOFFSET	*/
-	{ STB0899_OFF0_IMB_ESTIMATE	, STB0899_BASE_IMB_ESTIMATE	, 0x00000000 },	/* IMBESTIMATE	*/
-	{ STB0899_OFF0_IMB_CNTRL	, STB0899_BASE_IMB_CNTRL	, 0x00000001 },	/* IMBCNTRL	*/
-	{ STB0899_OFF0_IF_AGC_CNTRL2	, STB0899_BASE_IF_AGC_CNTRL2	, 0x00005007 },	/* IFAGCCNTRL2	*/
-	{ STB0899_OFF0_DMD_CNTRL2	, STB0899_BASE_DMD_CNTRL2	, 0x00000002 },	/* DMDCNTRL2	*/
-	{ STB0899_OFF0_TP_BUFFER	, STB0899_BASE_TP_BUFFER	, 0x00000000 },	/* TPBUFFER	*/
-	{ STB0899_OFF0_TP_BUFFER1	, STB0899_BASE_TP_BUFFER1	, 0x00000000 },	/* TPBUFFER1	*/
-	{ STB0899_OFF0_TP_BUFFER2	, STB0899_BASE_TP_BUFFER2	, 0x00000000 },	/* TPBUFFER2	*/
-	{ STB0899_OFF0_TP_BUFFER3	, STB0899_BASE_TP_BUFFER3	, 0x00000000 },	/* TPBUFFER3	*/
-	{ STB0899_OFF0_TP_BUFFER4	, STB0899_BASE_TP_BUFFER4	, 0x00000000 },	/* TPBUFFER4	*/
-	{ STB0899_OFF0_TP_BUFFER5	, STB0899_BASE_TP_BUFFER5	, 0x00000000 },	/* TPBUFFER5	*/
-	{ STB0899_OFF0_TP_BUFFER6	, STB0899_BASE_TP_BUFFER6	, 0x00000000 },	/* TPBUFFER6	*/
-	{ STB0899_OFF0_TP_BUFFER7	, STB0899_BASE_TP_BUFFER7	, 0x00000000 },	/* TPBUFFER7	*/
-	{ STB0899_OFF0_TP_BUFFER8	, STB0899_BASE_TP_BUFFER8	, 0x00000000 },	/* TPBUFFER8	*/
-	{ STB0899_OFF0_TP_BUFFER9	, STB0899_BASE_TP_BUFFER9	, 0x00000000 },	/* TPBUFFER9	*/
-	{ STB0899_OFF0_TP_BUFFER10	, STB0899_BASE_TP_BUFFER10	, 0x00000000 },	/* TPBUFFER10	*/
-	{ STB0899_OFF0_TP_BUFFER11	, STB0899_BASE_TP_BUFFER11	, 0x00000000 },	/* TPBUFFER11	*/
-	{ STB0899_OFF0_TP_BUFFER12	, STB0899_BASE_TP_BUFFER12	, 0x00000000 },	/* TPBUFFER12	*/
-	{ STB0899_OFF0_TP_BUFFER13	, STB0899_BASE_TP_BUFFER13	, 0x00000000 },	/* TPBUFFER13	*/
-	{ STB0899_OFF0_TP_BUFFER14	, STB0899_BASE_TP_BUFFER14	, 0x00000000 },	/* TPBUFFER14	*/
-	{ STB0899_OFF0_TP_BUFFER15	, STB0899_BASE_TP_BUFFER15	, 0x00000000 },	/* TPBUFFER15	*/
-	{ STB0899_OFF0_TP_BUFFER16	, STB0899_BASE_TP_BUFFER16	, 0x0000ff00 },	/* TPBUFFER16	*/
-	{ STB0899_OFF0_TP_BUFFER17	, STB0899_BASE_TP_BUFFER17	, 0x00000100 },	/* TPBUFFER17	*/
-	{ STB0899_OFF0_TP_BUFFER18	, STB0899_BASE_TP_BUFFER18	, 0x0000fe01 },	/* TPBUFFER18	*/
-	{ STB0899_OFF0_TP_BUFFER19	, STB0899_BASE_TP_BUFFER19	, 0x000004fe },	/* TPBUFFER19	*/
-	{ STB0899_OFF0_TP_BUFFER20	, STB0899_BASE_TP_BUFFER20	, 0x0000cfe7 },	/* TPBUFFER20	*/
-	{ STB0899_OFF0_TP_BUFFER21	, STB0899_BASE_TP_BUFFER21	, 0x0000bec6 },	/* TPBUFFER21	*/
-	{ STB0899_OFF0_TP_BUFFER22	, STB0899_BASE_TP_BUFFER22	, 0x0000c2bf },	/* TPBUFFER22	*/
-	{ STB0899_OFF0_TP_BUFFER23	, STB0899_BASE_TP_BUFFER23	, 0x0000c1c1 },	/* TPBUFFER23	*/
-	{ STB0899_OFF0_TP_BUFFER24	, STB0899_BASE_TP_BUFFER24	, 0x0000c1c1 },	/* TPBUFFER24	*/
-	{ STB0899_OFF0_TP_BUFFER25	, STB0899_BASE_TP_BUFFER25	, 0x0000c1c1 },	/* TPBUFFER25	*/
-	{ STB0899_OFF0_TP_BUFFER26	, STB0899_BASE_TP_BUFFER26	, 0x0000c1c1 },	/* TPBUFFER26	*/
-	{ STB0899_OFF0_TP_BUFFER27	, STB0899_BASE_TP_BUFFER27	, 0x0000c1c0 },	/* TPBUFFER27	*/
-	{ STB0899_OFF0_TP_BUFFER28	, STB0899_BASE_TP_BUFFER28	, 0x0000c0c0 },	/* TPBUFFER28	*/
-	{ STB0899_OFF0_TP_BUFFER29	, STB0899_BASE_TP_BUFFER29	, 0x0000c1c1 },	/* TPBUFFER29	*/
-	{ STB0899_OFF0_TP_BUFFER30	, STB0899_BASE_TP_BUFFER30	, 0x0000c1c1 },	/* TPBUFFER30	*/
-	{ STB0899_OFF0_TP_BUFFER31	, STB0899_BASE_TP_BUFFER31	, 0x0000c0c1 },	/* TPBUFFER31	*/
-	{ STB0899_OFF0_TP_BUFFER32	, STB0899_BASE_TP_BUFFER32	, 0x0000c0c1 },	/* TPBUFFER32	*/
-	{ STB0899_OFF0_TP_BUFFER33	, STB0899_BASE_TP_BUFFER33	, 0x0000c1c1 },	/* TPBUFFER33	*/
-	{ STB0899_OFF0_TP_BUFFER34	, STB0899_BASE_TP_BUFFER34	, 0x0000c1c1 },	/* TPBUFFER34	*/
-	{ STB0899_OFF0_TP_BUFFER35	, STB0899_BASE_TP_BUFFER35	, 0x0000c0c1 },	/* TPBUFFER35	*/
-	{ STB0899_OFF0_TP_BUFFER36	, STB0899_BASE_TP_BUFFER36	, 0x0000c1c1 },	/* TPBUFFER36	*/
-	{ STB0899_OFF0_TP_BUFFER37	, STB0899_BASE_TP_BUFFER37	, 0x0000c0c1 },	/* TPBUFFER37	*/
-	{ STB0899_OFF0_TP_BUFFER38	, STB0899_BASE_TP_BUFFER38	, 0x0000c1c1 },	/* TPBUFFER38	*/
-	{ STB0899_OFF0_TP_BUFFER39	, STB0899_BASE_TP_BUFFER39	, 0x0000c0c0 },	/* TPBUFFER39	*/
-	{ STB0899_OFF0_TP_BUFFER40	, STB0899_BASE_TP_BUFFER40	, 0x0000c1c0 },	/* TPBUFFER40	*/
-	{ STB0899_OFF0_TP_BUFFER41	, STB0899_BASE_TP_BUFFER41	, 0x0000c1c1 },	/* TPBUFFER41	*/
-	{ STB0899_OFF0_TP_BUFFER42	, STB0899_BASE_TP_BUFFER42	, 0x0000c0c0 },	/* TPBUFFER42	*/
-	{ STB0899_OFF0_TP_BUFFER43	, STB0899_BASE_TP_BUFFER43	, 0x0000c1c0 },	/* TPBUFFER43	*/
-	{ STB0899_OFF0_TP_BUFFER44	, STB0899_BASE_TP_BUFFER44	, 0x0000c0c1 },	/* TPBUFFER44	*/
-	{ STB0899_OFF0_TP_BUFFER45	, STB0899_BASE_TP_BUFFER45	, 0x0000c1be },	/* TPBUFFER45	*/
-	{ STB0899_OFF0_TP_BUFFER46	, STB0899_BASE_TP_BUFFER46	, 0x0000c1c9 },	/* TPBUFFER46	*/
-	{ STB0899_OFF0_TP_BUFFER47	, STB0899_BASE_TP_BUFFER47	, 0x0000c0da },	/* TPBUFFER47	*/
-	{ STB0899_OFF0_TP_BUFFER48	, STB0899_BASE_TP_BUFFER48	, 0x0000c0ba },	/* TPBUFFER48	*/
-	{ STB0899_OFF0_TP_BUFFER49	, STB0899_BASE_TP_BUFFER49	, 0x0000c1c4 },	/* TPBUFFER49	*/
-	{ STB0899_OFF0_TP_BUFFER50	, STB0899_BASE_TP_BUFFER50	, 0x0000c1bf },	/* TPBUFFER50	*/
-	{ STB0899_OFF0_TP_BUFFER51	, STB0899_BASE_TP_BUFFER51	, 0x0000c0c1 },	/* TPBUFFER51	*/
-	{ STB0899_OFF0_TP_BUFFER52	, STB0899_BASE_TP_BUFFER52	, 0x0000c1c0 },	/* TPBUFFER52	*/
-	{ STB0899_OFF0_TP_BUFFER53	, STB0899_BASE_TP_BUFFER53	, 0x0000c0c1 },	/* TPBUFFER53	*/
-	{ STB0899_OFF0_TP_BUFFER54	, STB0899_BASE_TP_BUFFER54	, 0x0000c1c1 },	/* TPBUFFER54	*/
-	{ STB0899_OFF0_TP_BUFFER55	, STB0899_BASE_TP_BUFFER55	, 0x0000c1c1 },	/* TPBUFFER55	*/
-	{ STB0899_OFF0_TP_BUFFER56	, STB0899_BASE_TP_BUFFER56	, 0x0000c1c1 },	/* TPBUFFER56	*/
-	{ STB0899_OFF0_TP_BUFFER57	, STB0899_BASE_TP_BUFFER57	, 0x0000c1c1 },	/* TPBUFFER57	*/
-	{ STB0899_OFF0_TP_BUFFER58	, STB0899_BASE_TP_BUFFER58	, 0x0000c1c1 },	/* TPBUFFER58	*/
-	{ STB0899_OFF0_TP_BUFFER59	, STB0899_BASE_TP_BUFFER59	, 0x0000c1c1 },	/* TPBUFFER59	*/
-	{ STB0899_OFF0_TP_BUFFER60	, STB0899_BASE_TP_BUFFER60	, 0x0000c1c1 },	/* TPBUFFER60	*/
-	{ STB0899_OFF0_TP_BUFFER61	, STB0899_BASE_TP_BUFFER61	, 0x0000c1c1 },	/* TPBUFFER61	*/
-	{ STB0899_OFF0_TP_BUFFER62	, STB0899_BASE_TP_BUFFER62	, 0x0000c1c1 },	/* TPBUFFER62	*/
-	{ STB0899_OFF0_TP_BUFFER63	, STB0899_BASE_TP_BUFFER63	, 0x0000c1c0 },	/* TPBUFFER63	*/
-	{ STB0899_OFF0_RESET_CNTRL	, STB0899_BASE_RESET_CNTRL	, 0x00000001 },	/* RESETCNTRL	*/
-	{ STB0899_OFF0_ACM_ENABLE	, STB0899_BASE_ACM_ENABLE	, 0x00005654 },	/* ACMENABLE	*/
-	{ STB0899_OFF0_DESCR_CNTRL	, STB0899_BASE_DESCR_CNTRL	, 0x00000000 },	/* DESCRCNTRL	*/
-	{ STB0899_OFF0_CSM_CNTRL1	, STB0899_BASE_CSM_CNTRL1	, 0x00020019 },	/* CSMCNTRL1	*/
-	{ STB0899_OFF0_CSM_CNTRL2	, STB0899_BASE_CSM_CNTRL2	, 0x004b3237 },	/* CSMCNTRL2	*/
-	{ STB0899_OFF0_CSM_CNTRL3	, STB0899_BASE_CSM_CNTRL3	, 0x0003dd17 },	/* CSMCNTRL3	*/
-	{ STB0899_OFF0_CSM_CNTRL4	, STB0899_BASE_CSM_CNTRL4	, 0x00008008 },	/* CSMCNTRL4	*/
-	{ STB0899_OFF0_UWP_CNTRL1	, STB0899_BASE_UWP_CNTRL1	, 0x002a3106 },	/* UWPCNTRL1	*/
-	{ STB0899_OFF0_UWP_CNTRL2	, STB0899_BASE_UWP_CNTRL2	, 0x0006140a },	/* UWPCNTRL2	*/
-	{ STB0899_OFF0_UWP_STAT1	, STB0899_BASE_UWP_STAT1	, 0x00008000 },	/* UWPSTAT1	*/
-	{ STB0899_OFF0_UWP_STAT2	, STB0899_BASE_UWP_STAT2	, 0x00000000 },	/* UWPSTAT2	*/
-	{ STB0899_OFF0_DMD_STAT2	, STB0899_BASE_DMD_STAT2	, 0x00000000 },	/* DMDSTAT2	*/
-	{ STB0899_OFF0_FREQ_ADJ_SCALE	, STB0899_BASE_FREQ_ADJ_SCALE	, 0x00000471 },	/* FREQADJSCALE */
-	{ STB0899_OFF0_UWP_CNTRL3	, STB0899_BASE_UWP_CNTRL3	, 0x017b0465 },	/* UWPCNTRL3	*/
-	{ STB0899_OFF0_SYM_CLK_SEL	, STB0899_BASE_SYM_CLK_SEL	, 0x00000002 },	/* SYMCLKSEL	*/
-	{ STB0899_OFF0_SOF_SRCH_TO	, STB0899_BASE_SOF_SRCH_TO	, 0x00196464 },	/* SOFSRCHTO	*/
-	{ STB0899_OFF0_ACQ_CNTRL1	, STB0899_BASE_ACQ_CNTRL1	, 0x00000603 },	/* ACQCNTRL1	*/
-	{ STB0899_OFF0_ACQ_CNTRL2	, STB0899_BASE_ACQ_CNTRL2	, 0x02046666 },	/* ACQCNTRL2	*/
-	{ STB0899_OFF0_ACQ_CNTRL3	, STB0899_BASE_ACQ_CNTRL3	, 0x10046583 },	/* ACQCNTRL3	*/
-	{ STB0899_OFF0_FE_SETTLE	, STB0899_BASE_FE_SETTLE	, 0x00010404 },	/* FESETTLE	*/
-	{ STB0899_OFF0_AC_DWELL		, STB0899_BASE_AC_DWELL		, 0x0002aa8a },	/* ACDWELL	*/
-	{ STB0899_OFF0_ACQUIRE_TRIG	, STB0899_BASE_ACQUIRE_TRIG	, 0x00000000 },	/* ACQUIRETRIG	*/
-	{ STB0899_OFF0_LOCK_LOST	, STB0899_BASE_LOCK_LOST	, 0x00000001 },	/* LOCKLOST	*/
-	{ STB0899_OFF0_ACQ_STAT1	, STB0899_BASE_ACQ_STAT1	, 0x00000500 },	/* ACQSTAT1	*/
-	{ STB0899_OFF0_ACQ_TIMEOUT	, STB0899_BASE_ACQ_TIMEOUT	, 0x0028a0a0 },	/* ACQTIMEOUT	*/
-	{ STB0899_OFF0_ACQ_TIME		, STB0899_BASE_ACQ_TIME		, 0x00000000 },	/* ACQTIME	*/
-	{ STB0899_OFF0_FINAL_AGC_CNTRL	, STB0899_BASE_FINAL_AGC_CNTRL	, 0x00800c17 },	/* FINALAGCCNTRL*/
-	{ STB0899_OFF0_FINAL_AGC_GAIN	, STB0899_BASE_FINAL_AGC_GAIN	, 0x00000000 },	/* FINALAGCCGAIN*/
-	{ STB0899_OFF0_EQUALIZER_INIT	, STB0899_BASE_EQUALIZER_INIT	, 0x00000000 },	/* EQUILIZERINIT*/
-	{ STB0899_OFF0_EQ_CNTRL		, STB0899_BASE_EQ_CNTRL		, 0x00054802 },	/* EQCNTL	*/
-	{ STB0899_OFF0_EQ_I_INIT_COEFF_0, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF0 */
-	{ STB0899_OFF1_EQ_I_INIT_COEFF_1, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF1 */
-	{ STB0899_OFF2_EQ_I_INIT_COEFF_2, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF2 */
-	{ STB0899_OFF3_EQ_I_INIT_COEFF_3, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF3 */
-	{ STB0899_OFF4_EQ_I_INIT_COEFF_4, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF4 */
-	{ STB0899_OFF5_EQ_I_INIT_COEFF_5, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000400 },	/* EQIINITCOEFF5 */
-	{ STB0899_OFF6_EQ_I_INIT_COEFF_6, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF6 */
-	{ STB0899_OFF7_EQ_I_INIT_COEFF_7, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF7 */
-	{ STB0899_OFF8_EQ_I_INIT_COEFF_8, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF8 */
-	{ STB0899_OFF9_EQ_I_INIT_COEFF_9, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF9 */
-	{ STB0899_OFFa_EQ_I_INIT_COEFF_10,STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF10*/
-	{ STB0899_OFF0_EQ_Q_INIT_COEFF_0, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF0 */
-	{ STB0899_OFF1_EQ_Q_INIT_COEFF_1, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF1 */
-	{ STB0899_OFF2_EQ_Q_INIT_COEFF_2, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF2 */
-	{ STB0899_OFF3_EQ_Q_INIT_COEFF_3, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF3 */
-	{ STB0899_OFF4_EQ_Q_INIT_COEFF_4, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF4 */
-	{ STB0899_OFF5_EQ_Q_INIT_COEFF_5, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF5 */
-	{ STB0899_OFF6_EQ_Q_INIT_COEFF_6, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF6 */
-	{ STB0899_OFF7_EQ_Q_INIT_COEFF_7, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF7 */
-	{ STB0899_OFF8_EQ_Q_INIT_COEFF_8, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF8 */
-	{ STB0899_OFF9_EQ_Q_INIT_COEFF_9, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF9 */
-	{ STB0899_OFFa_EQ_Q_INIT_COEFF_10,STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF10*/
-	{ STB0899_OFF0_EQ_I_OUT_COEFF_0	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT0 */
-	{ STB0899_OFF1_EQ_I_OUT_COEFF_1	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT1 */
-	{ STB0899_OFF2_EQ_I_OUT_COEFF_2	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT2 */
-	{ STB0899_OFF3_EQ_I_OUT_COEFF_3	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT3 */
-	{ STB0899_OFF4_EQ_I_OUT_COEFF_4	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT4 */
-	{ STB0899_OFF5_EQ_I_OUT_COEFF_5	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT5 */
-	{ STB0899_OFF6_EQ_I_OUT_COEFF_6	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT6 */
-	{ STB0899_OFF7_EQ_I_OUT_COEFF_7	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT7 */
-	{ STB0899_OFF8_EQ_I_OUT_COEFF_8	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT8 */
-	{ STB0899_OFF9_EQ_I_OUT_COEFF_9	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT9 */
-	{ STB0899_OFFa_EQ_I_OUT_COEFF_10,STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT10*/
-	{ STB0899_OFF0_EQ_Q_OUT_COEFF_0	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT0 */
-	{ STB0899_OFF1_EQ_Q_OUT_COEFF_1	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT1 */
-	{ STB0899_OFF2_EQ_Q_OUT_COEFF_2	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT2 */
-	{ STB0899_OFF3_EQ_Q_OUT_COEFF_3	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT3 */
-	{ STB0899_OFF4_EQ_Q_OUT_COEFF_4	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT4 */
-	{ STB0899_OFF5_EQ_Q_OUT_COEFF_5	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT5 */
-	{ STB0899_OFF6_EQ_Q_OUT_COEFF_6 , STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT6 */
-	{ STB0899_OFF7_EQ_Q_OUT_COEFF_7	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT7 */
-	{ STB0899_OFF8_EQ_Q_OUT_COEFF_8	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT8 */
-	{ STB0899_OFF9_EQ_Q_OUT_COEFF_9	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT9 */
-	{ STB0899_OFFa_EQ_Q_OUT_COEFF_10, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT10*/
-	{ 0xffff			, 0xffffffff			, 0xffffffff },
-};
-static const struct stb0899_s2_reg stb0899_s2_init_4[] = {
-	{ STB0899_OFF0_BLOCK_LNGTH	, STB0899_BASE_BLOCK_LNGTH	, 0x00000008 },	/* BLOCKLNGTH	*/
-	{ STB0899_OFF0_ROW_STR		, STB0899_BASE_ROW_STR		, 0x000000b4 },	/* ROWSTR	*/
-	{ STB0899_OFF0_BN_END_ADDR	, STB0899_BASE_BN_END_ADDR	, 0x000004b5 },	/* BNANDADDR	*/
-	{ STB0899_OFF0_CN_END_ADDR	, STB0899_BASE_CN_END_ADDR	, 0x00000b4b },	/* CNANDADDR	*/
-	{ STB0899_OFF0_INFO_LENGTH	, STB0899_BASE_INFO_LENGTH	, 0x00000078 },	/* INFOLENGTH	*/
-	{ STB0899_OFF0_BOT_ADDR		, STB0899_BASE_BOT_ADDR		, 0x000001e0 },	/* BOT_ADDR	*/
-	{ STB0899_OFF0_BCH_BLK_LN	, STB0899_BASE_BCH_BLK_LN	, 0x0000a8c0 },	/* BCHBLKLN	*/
-	{ STB0899_OFF0_BCH_T		, STB0899_BASE_BCH_T		, 0x0000000c },	/* BCHT		*/
-	{ STB0899_OFF0_CNFG_MODE	, STB0899_BASE_CNFG_MODE	, 0x00000001 },	/* CNFGMODE	*/
-	{ STB0899_OFF0_LDPC_STAT	, STB0899_BASE_LDPC_STAT	, 0x0000000d },	/* LDPCSTAT	*/
-	{ STB0899_OFF0_ITER_SCALE	, STB0899_BASE_ITER_SCALE	, 0x00000040 },	/* ITERSCALE	*/
-	{ STB0899_OFF0_INPUT_MODE	, STB0899_BASE_INPUT_MODE	, 0x00000000 },	/* INPUTMODE	*/
-	{ STB0899_OFF0_LDPCDECRST	, STB0899_BASE_LDPCDECRST	, 0x00000000 },	/* LDPCDECRST	*/
-	{ STB0899_OFF0_CLK_PER_BYTE_RW	, STB0899_BASE_CLK_PER_BYTE_RW	, 0x00000008 },	/* CLKPERBYTE	*/
-	{ STB0899_OFF0_BCH_ERRORS	, STB0899_BASE_BCH_ERRORS	, 0x00000000 },	/* BCHERRORS	*/
-	{ STB0899_OFF0_LDPC_ERRORS	, STB0899_BASE_LDPC_ERRORS	, 0x00000000 },	/* LDPCERRORS	*/
-	{ STB0899_OFF0_BCH_MODE		, STB0899_BASE_BCH_MODE		, 0x00000000 },	/* BCHMODE	*/
-	{ STB0899_OFF0_ERR_ACC_PER	, STB0899_BASE_ERR_ACC_PER	, 0x00000008 },	/* ERRACCPER	*/
-	{ STB0899_OFF0_BCH_ERR_ACC	, STB0899_BASE_BCH_ERR_ACC	, 0x00000000 },	/* BCHERRACC	*/
-	{ STB0899_OFF0_FEC_TP_SEL	, STB0899_BASE_FEC_TP_SEL	, 0x00000000 },	/* FECTPSEL	*/
-	{ 0xffff			, 0xffffffff			, 0xffffffff },
-};
-
-static const struct stb0899_s1_reg stb0899_s1_init_5[] = {
-	{ STB0899_TSTCK		, 0x00 },
-	{ STB0899_TSTRES	, 0x00 },
-	{ STB0899_TSTOUT	, 0x00 },
-	{ STB0899_TSTIN		, 0x00 },
-	{ STB0899_TSTSYS	, 0x00 },
-	{ STB0899_TSTCHIP	, 0x00 },
-	{ STB0899_TSTFREE	, 0x00 },
-	{ STB0899_TSTI2C	, 0x00 },
-	{ STB0899_BITSPEEDM	, 0x00 },
-	{ STB0899_BITSPEEDL	, 0x00 },
-	{ STB0899_TBUSBIT	, 0x00 },
-	{ STB0899_TSTDIS	, 0x00 },
-	{ STB0899_TSTDISRX	, 0x00 },
-	{ STB0899_TSTJETON	, 0x00 },
-	{ STB0899_TSTDCADJ	, 0x00 },
-	{ STB0899_TSTAGC1	, 0x00 },
-	{ STB0899_TSTAGC1N	, 0x00 },
-	{ STB0899_TSTPOLYPH	, 0x00 },
-	{ STB0899_TSTR		, 0x00 },
-	{ STB0899_TSTAGC2	, 0x00 },
-	{ STB0899_TSTCTL1	, 0x00 },
-	{ STB0899_TSTCTL2	, 0x00 },
-	{ STB0899_TSTCTL3	, 0x00 },
-	{ STB0899_TSTDEMAP	, 0x00 },
-	{ STB0899_TSTDEMAP2	, 0x00 },
-	{ STB0899_TSTDEMMON	, 0x00 },
-	{ STB0899_TSTRATE	, 0x00 },
-	{ STB0899_TSTSELOUT	, 0x00 },
-	{ STB0899_TSYNC		, 0x00 },
-	{ STB0899_TSTERR	, 0x00 },
-	{ STB0899_TSTRAM1	, 0x00 },
-	{ STB0899_TSTVSELOUT	, 0x00 },
-	{ STB0899_TSTFORCEIN	, 0x00 },
-	{ STB0899_TSTRS1	, 0x00 },
-	{ STB0899_TSTRS2	, 0x00 },
-	{ STB0899_TSTRS3	, 0x00 },
-	{ STB0899_GHOSTREG	, 0x81 },
-	{ 0xffff		, 0xff },
-};
-
-#define STB0899_DVBS2_ESNO_AVE			3
-#define STB0899_DVBS2_ESNO_QUANT		32
-#define STB0899_DVBS2_AVFRAMES_COARSE		10
-#define STB0899_DVBS2_AVFRAMES_FINE		20
-#define STB0899_DVBS2_MISS_THRESHOLD		6
-#define STB0899_DVBS2_UWP_THRESHOLD_ACQ		1125
-#define STB0899_DVBS2_UWP_THRESHOLD_TRACK	758
-#define STB0899_DVBS2_UWP_THRESHOLD_SOF		1350
-#define STB0899_DVBS2_SOF_SEARCH_TIMEOUT	1664100
-
-#define STB0899_DVBS2_BTR_NCO_BITS		28
-#define STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET	15
-#define STB0899_DVBS2_CRL_NCO_BITS		30
-#define STB0899_DVBS2_LDPC_MAX_ITER		70
-
-#endif //__STB0899_CFG_H
diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c
deleted file mode 100644
index 5d7f8a9..0000000
--- a/drivers/media/dvb/frontends/stb0899_drv.c
+++ /dev/null
@@ -1,1651 +0,0 @@
-/*
-	STB0899 Multistandard Frontend driver
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	Copyright (C) ST Microelectronics
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-
-#include <linux/dvb/frontend.h>
-#include "dvb_frontend.h"
-
-#include "stb0899_drv.h"
-#include "stb0899_priv.h"
-#include "stb0899_reg.h"
-
-static unsigned int verbose = 0;//1;
-module_param(verbose, int, 0644);
-
-/* C/N in dB/10, NIRM/NIRL */
-static const struct stb0899_tab stb0899_cn_tab[] = {
-	{ 200,	2600 },
-	{ 190,	2700 },
-	{ 180,	2860 },
-	{ 170,	3020 },
-	{ 160,	3210 },
-	{ 150,	3440 },
-	{ 140,	3710 },
-	{ 130,	4010 },
-	{ 120,	4360 },
-	{ 110,	4740 },
-	{ 100,	5190 },
-	{ 90,	5670 },
-	{ 80,	6200 },
-	{ 70,	6770 },
-	{ 60,	7360 },
-	{ 50,	7970 },
-	{ 40,	8250 },
-	{ 30,	9000 },
-	{ 20,	9450 },
-	{ 15,	9600 },
-};
-
-/* DVB-S AGCIQ_VALUE vs. signal level in dBm/10.
- * As measured, connected to a modulator.
- * -8.0 to -50.0 dBm directly connected,
- * -52.0 to -74.8 with extra attenuation.
- * Cut-off to AGCIQ_VALUE = 0x80 below -74.8dBm.
- * Crude linear extrapolation below -84.8dBm and above -8.0dBm.
- */
-static const struct stb0899_tab stb0899_dvbsrf_tab[] = {
-	{ -750,	-128 },
-	{ -748,	 -94 },
-	{ -745,	 -92 },
-	{ -735,	 -90 },
-	{ -720,	 -87 },
-	{ -670,	 -77 },
-	{ -640,	 -70 },
-	{ -610,	 -62 },
-	{ -600,	 -60 },
-	{ -590,	 -56 },
-	{ -560,	 -41 },
-	{ -540,	 -25 },
-	{ -530,	 -17 },
-	{ -520,	 -11 },
-	{ -500,	   1 },
-	{ -490,	   6 },
-	{ -480,	  10 },
-	{ -440,	  22 },
-	{ -420,	  27 },
-	{ -400,	  31 },
-	{ -380,	  34 },
-	{ -340,	  40 },
-	{ -320,	  43 },
-	{ -280,	  48 },
-	{ -250,	  52 },
-	{ -230,	  55 },
-	{ -180,	  61 },
-	{ -140,	  66 },
-	{  -90,	  73 },
-	{  -80,	  74 },
-	{  500,	 127 }
-};
-
-/* DVB-S2 IF_AGC_GAIN vs. signal level in dBm/10.
- * As measured, connected to a modulator.
- * -8.0 to -50.1 dBm directly connected,
- * -53.0 to -76.6 with extra attenuation.
- * Cut-off to IF_AGC_GAIN = 0x3fff below -76.6dBm.
- * Crude linear extrapolation below -76.6dBm and above -8.0dBm.
- */
-static const struct stb0899_tab stb0899_dvbs2rf_tab[] = {
-	{  700,	    0 },
-	{  -80,	 3217 },
-	{ -150,	 3893 },
-	{ -190,	 4217 },
-	{ -240,	 4621 },
-	{ -280,	 4945 },
-	{ -320,	 5273 },
-	{ -350,	 5545 },
-	{ -370,	 5741 },
-	{ -410,	 6147 },
-	{ -450,	 6671 },
-	{ -490,	 7413 },
-	{ -501,	 7665 },
-	{ -530,	 8767 },
-	{ -560,	10219 },
-	{ -580,	10939 },
-	{ -590,	11518 },
-	{ -600,	11723 },
-	{ -650,	12659 },
-	{ -690,	13219 },
-	{ -730,	13645 },
-	{ -750,	13909 },
-	{ -766,	14153 },
-	{ -950,	16383 }
-};
-
-/* DVB-S2 Es/N0 quant in dB/100 vs read value * 100*/
-static struct stb0899_tab stb0899_quant_tab[] = {
-	{    0,	    0 },
-	{    0,	  100 },
-	{  600,	  200 },
-	{  950,	  299 },
-	{ 1200,	  398 },
-	{ 1400,	  501 },
-	{ 1560,	  603 },
-	{ 1690,	  700 },
-	{ 1810,	  804 },
-	{ 1910,	  902 },
-	{ 2000,	 1000 },
-	{ 2080,	 1096 },
-	{ 2160,	 1202 },
-	{ 2230,	 1303 },
-	{ 2350,	 1496 },
-	{ 2410,	 1603 },
-	{ 2460,	 1698 },
-	{ 2510,	 1799 },
-	{ 2600,	 1995 },
-	{ 2650,	 2113 },
-	{ 2690,  2213 },
-	{ 2720,	 2291 },
-	{ 2760,	 2399 },
-	{ 2800,	 2512 },
-	{ 2860,	 2692 },
-	{ 2930,	 2917 },
-	{ 2960,	 3020 },
-	{ 3010,	 3199 },
-	{ 3040,	 3311 },
-	{ 3060,	 3388 },
-	{ 3120,	 3631 },
-	{ 3190,	 3936 },
-	{ 3400,	 5012 },
-	{ 3610,	 6383 },
-	{ 3800,	 7943 },
-	{ 4210,	12735 },
-	{ 4500,	17783 },
-	{ 4690,	22131 },
-	{ 4810,	25410 }
-};
-
-/* DVB-S2 Es/N0 estimate in dB/100 vs read value */
-static struct stb0899_tab stb0899_est_tab[] = {
-	{    0,	     0 },
-	{    0,	     1 },
-	{  301,	     2 },
-	{ 1204,	    16 },
-	{ 1806,	    64 },
-	{ 2408,	   256 },
-	{ 2709,	   512 },
-	{ 3010,	  1023 },
-	{ 3311,	  2046 },
-	{ 3612,	  4093 },
-	{ 3823,	  6653 },
-	{ 3913,	  8185 },
-	{ 4010,	 10233 },
-	{ 4107,	 12794 },
-	{ 4214,	 16368 },
-	{ 4266,	 18450 },
-	{ 4311,	 20464 },
-	{ 4353,	 22542 },
-	{ 4391,	 24604 },
-	{ 4425,	 26607 },
-	{ 4457,	 28642 },
-	{ 4487,	 30690 },
-	{ 4515,	 32734 },
-	{ 4612,	 40926 },
-	{ 4692,	 49204 },
-	{ 4816,	 65464 },
-	{ 4913,	 81846 },
-	{ 4993,	 98401 },
-	{ 5060,	114815 },
-	{ 5118,	131220 },
-	{ 5200,	158489 },
-	{ 5300,	199526 },
-	{ 5400,	251189 },
-	{ 5500,	316228 },
-	{ 5600,	398107 },
-	{ 5720,	524807 },
-	{ 5721,	526017 },
-};
-
-static int _stb0899_read_reg(struct stb0899_state *state, unsigned int reg)
-{
-	int ret;
-
-	u8 b0[] = { reg >> 8, reg & 0xff };
-	u8 buf;
-
-	struct i2c_msg msg[] = {
-		{
-			.addr	= state->config->demod_address,
-			.flags	= 0,
-			.buf	= b0,
-			.len	= 2
-		},{
-			.addr	= state->config->demod_address,
-			.flags	= I2C_M_RD,
-			.buf	= &buf,
-			.len	= 1
-		}
-	};
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-	if (ret != 2) {
-		if (ret != -ERESTARTSYS)
-			dprintk(state->verbose, FE_ERROR, 1,
-				"Read error, Reg=[0x%02x], Status=%d",
-				reg, ret);
-
-		return ret < 0 ? ret : -EREMOTEIO;
-	}
-	if (unlikely(*state->verbose >= FE_DEBUGREG))
-		dprintk(state->verbose, FE_ERROR, 1, "Reg=[0x%02x], data=%02x",
-			reg, buf);
-
-	return (unsigned int)buf;
-}
-
-int stb0899_read_reg(struct stb0899_state *state, unsigned int reg)
-{
-	int result;
-
-	result = _stb0899_read_reg(state, reg);
-	/*
-	 * Bug ID 9:
-	 * access to 0xf2xx/0xf6xx
-	 * must be followed by read from 0xf2ff/0xf6ff.
-	 */
-	if ((reg != 0xf2ff) && (reg != 0xf6ff) &&
-	    (((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600)))
-		_stb0899_read_reg(state, (reg | 0x00ff));
-
-	return result;
-}
-
-u32 _stb0899_read_s2reg(struct stb0899_state *state,
-			u32 stb0899_i2cdev,
-			u32 stb0899_base_addr,
-			u16 stb0899_reg_offset)
-{
-	int status;
-	u32 data;
-	u8 buf[7] = { 0 };
-	u16 tmpaddr;
-
-	u8 buf_0[] = {
-		GETBYTE(stb0899_i2cdev, BYTE1),		/* 0xf3	S2 Base Address (MSB)	*/
-		GETBYTE(stb0899_i2cdev, BYTE0),		/* 0xfc	S2 Base Address (LSB)	*/
-		GETBYTE(stb0899_base_addr, BYTE0),	/* 0x00	Base Address (LSB)	*/
-		GETBYTE(stb0899_base_addr, BYTE1),	/* 0x04	Base Address (LSB)	*/
-		GETBYTE(stb0899_base_addr, BYTE2),	/* 0x00	Base Address (MSB)	*/
-		GETBYTE(stb0899_base_addr, BYTE3),	/* 0x00	Base Address (MSB)	*/
-	};
-	u8 buf_1[] = {
-		0x00,	/* 0xf3	Reg Offset	*/
-		0x00,	/* 0x44	Reg Offset	*/
-	};
-
-	struct i2c_msg msg_0 = {
-		.addr	= state->config->demod_address,
-		.flags	= 0,
-		.buf	= buf_0,
-		.len	= 6
-	};
-
-	struct i2c_msg msg_1 = {
-		.addr	= state->config->demod_address,
-		.flags	= 0,
-		.buf	= buf_1,
-		.len	= 2
-	};
-
-	struct i2c_msg msg_r = {
-		.addr	= state->config->demod_address,
-		.flags	= I2C_M_RD,
-		.buf	= buf,
-		.len	= 4
-	};
-
-	tmpaddr = stb0899_reg_offset & 0xff00;
-	if (!(stb0899_reg_offset & 0x8))
-		tmpaddr = stb0899_reg_offset | 0x20;
-
-	buf_1[0] = GETBYTE(tmpaddr, BYTE1);
-	buf_1[1] = GETBYTE(tmpaddr, BYTE0);
-
-	status = i2c_transfer(state->i2c, &msg_0, 1);
-	if (status < 1) {
-		if (status != -ERESTARTSYS)
-			printk(KERN_ERR "%s ERR(1), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n",
-			       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status);
-
-		goto err;
-	}
-
-	/* Dummy	*/
-	status = i2c_transfer(state->i2c, &msg_1, 1);
-	if (status < 1)
-		goto err;
-
-	status = i2c_transfer(state->i2c, &msg_r, 1);
-	if (status < 1)
-		goto err;
-
-	buf_1[0] = GETBYTE(stb0899_reg_offset, BYTE1);
-	buf_1[1] = GETBYTE(stb0899_reg_offset, BYTE0);
-
-	/* Actual	*/
-	status = i2c_transfer(state->i2c, &msg_1, 1);
-	if (status < 1) {
-		if (status != -ERESTARTSYS)
-			printk(KERN_ERR "%s ERR(2), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n",
-			       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status);
-		goto err;
-	}
-
-	status = i2c_transfer(state->i2c, &msg_r, 1);
-	if (status < 1) {
-		if (status != -ERESTARTSYS)
-			printk(KERN_ERR "%s ERR(3), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n",
-			       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status);
-		return status < 0 ? status : -EREMOTEIO;
-	}
-
-	data = MAKEWORD32(buf[3], buf[2], buf[1], buf[0]);
-	if (unlikely(*state->verbose >= FE_DEBUGREG))
-		printk(KERN_DEBUG "%s Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Data=[0x%08x]\n",
-		       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, data);
-
-	return data;
-
-err:
-	return status < 0 ? status : -EREMOTEIO;
-}
-
-int stb0899_write_s2reg(struct stb0899_state *state,
-			u32 stb0899_i2cdev,
-			u32 stb0899_base_addr,
-			u16 stb0899_reg_offset,
-			u32 stb0899_data)
-{
-	int status;
-
-	/* Base Address Setup	*/
-	u8 buf_0[] = {
-		GETBYTE(stb0899_i2cdev, BYTE1),		/* 0xf3	S2 Base Address (MSB)	*/
-		GETBYTE(stb0899_i2cdev, BYTE0),		/* 0xfc	S2 Base Address (LSB)	*/
-		GETBYTE(stb0899_base_addr, BYTE0),	/* 0x00	Base Address (LSB)	*/
-		GETBYTE(stb0899_base_addr, BYTE1),	/* 0x04	Base Address (LSB)	*/
-		GETBYTE(stb0899_base_addr, BYTE2),	/* 0x00	Base Address (MSB)	*/
-		GETBYTE(stb0899_base_addr, BYTE3),	/* 0x00	Base Address (MSB)	*/
-	};
-	u8 buf_1[] = {
-		0x00,	/* 0xf3	Reg Offset	*/
-		0x00,	/* 0x44	Reg Offset	*/
-		0x00,	/* data			*/
-		0x00,	/* data			*/
-		0x00,	/* data			*/
-		0x00,	/* data			*/
-	};
-
-	struct i2c_msg msg_0 = {
-		.addr	= state->config->demod_address,
-		.flags	= 0,
-		.buf	= buf_0,
-		.len	= 6
-	};
-
-	struct i2c_msg msg_1 = {
-		.addr	= state->config->demod_address,
-		.flags	= 0,
-		.buf	= buf_1,
-		.len	= 6
-	};
-
-	buf_1[0] = GETBYTE(stb0899_reg_offset, BYTE1);
-	buf_1[1] = GETBYTE(stb0899_reg_offset, BYTE0);
-	buf_1[2] = GETBYTE(stb0899_data, BYTE0);
-	buf_1[3] = GETBYTE(stb0899_data, BYTE1);
-	buf_1[4] = GETBYTE(stb0899_data, BYTE2);
-	buf_1[5] = GETBYTE(stb0899_data, BYTE3);
-
-	if (unlikely(*state->verbose >= FE_DEBUGREG))
-		printk(KERN_DEBUG "%s Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x]\n",
-		       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data);
-
-	status = i2c_transfer(state->i2c, &msg_0, 1);
-	if (unlikely(status < 1)) {
-		if (status != -ERESTARTSYS)
-			printk(KERN_ERR "%s ERR (1), Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x], status=%d\n",
-			       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data, status);
-		goto err;
-	}
-	status = i2c_transfer(state->i2c, &msg_1, 1);
-	if (unlikely(status < 1)) {
-		if (status != -ERESTARTSYS)
-			printk(KERN_ERR "%s ERR (2), Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x], status=%d\n",
-			       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data, status);
-
-		return status < 0 ? status : -EREMOTEIO;
-	}
-
-	return 0;
-
-err:
-	return status < 0 ? status : -EREMOTEIO;
-}
-
-int stb0899_read_regs(struct stb0899_state *state, unsigned int reg, u8 *buf, u32 count)
-{
-	int status;
-
-	u8 b0[] = { reg >> 8, reg & 0xff };
-
-	struct i2c_msg msg[] = {
-		{
-			.addr	= state->config->demod_address,
-			.flags	= 0,
-			.buf	= b0,
-			.len	= 2
-		},{
-			.addr	= state->config->demod_address,
-			.flags	= I2C_M_RD,
-			.buf	= buf,
-			.len	= count
-		}
-	};
-
-	status = i2c_transfer(state->i2c, msg, 2);
-	if (status != 2) {
-		if (status != -ERESTARTSYS)
-			printk(KERN_ERR "%s Read error, Reg=[0x%04x], Count=%u, Status=%d\n",
-			       __func__, reg, count, status);
-		goto err;
-	}
-	/*
-	 * Bug ID 9:
-	 * access to 0xf2xx/0xf6xx
-	 * must be followed by read from 0xf2ff/0xf6ff.
-	 */
-	if ((reg != 0xf2ff) && (reg != 0xf6ff) &&
-	    (((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600)))
-		_stb0899_read_reg(state, (reg | 0x00ff));
-
-	if (unlikely(*state->verbose >= FE_DEBUGREG)) {
-		int i;
-
-		printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg);
-		for (i = 0; i < count; i++) {
-			printk(" %02x", buf[i]);
-		}
-		printk("\n");
-	}
-
-	return 0;
-err:
-	return status < 0 ? status : -EREMOTEIO;
-}
-
-int stb0899_write_regs(struct stb0899_state *state, unsigned int reg, u8 *data, u32 count)
-{
-	int ret;
-	u8 buf[2 + count];
-	struct i2c_msg i2c_msg = {
-		.addr	= state->config->demod_address,
-		.flags	= 0,
-		.buf	= buf,
-		.len	= 2 + count
-	};
-
-	buf[0] = reg >> 8;
-	buf[1] = reg & 0xff;
-	memcpy(&buf[2], data, count);
-
-	if (unlikely(*state->verbose >= FE_DEBUGREG)) {
-		int i;
-
-		printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg);
-		for (i = 0; i < count; i++)
-			printk(" %02x", data[i]);
-		printk("\n");
-	}
-	ret = i2c_transfer(state->i2c, &i2c_msg, 1);
-
-	/*
-	 * Bug ID 9:
-	 * access to 0xf2xx/0xf6xx
-	 * must be followed by read from 0xf2ff/0xf6ff.
-	 */
-	if ((((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600)))
-		stb0899_read_reg(state, (reg | 0x00ff));
-
-	if (ret != 1) {
-		if (ret != -ERESTARTSYS)
-			dprintk(state->verbose, FE_ERROR, 1, "Reg=[0x%04x], Data=[0x%02x ...], Count=%u, Status=%d",
-				reg, data[0], count, ret);
-		return ret < 0 ? ret : -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-int stb0899_write_reg(struct stb0899_state *state, unsigned int reg, u8 data)
-{
-	return stb0899_write_regs(state, reg, &data, 1);
-}
-
-/*
- * stb0899_get_mclk
- * Get STB0899 master clock frequency
- * ExtClk: external clock frequency (Hz)
- */
-static u32 stb0899_get_mclk(struct stb0899_state *state)
-{
-	u32 mclk = 0, div = 0;
-
-	div = stb0899_read_reg(state, STB0899_NCOARSE);
-	mclk = (div + 1) * state->config->xtal_freq / 6;
-	dprintk(state->verbose, FE_DEBUG, 1, "div=%d, mclk=%d", div, mclk);
-
-	return mclk;
-}
-
-/*
- * stb0899_set_mclk
- * Set STB0899 master Clock frequency
- * Mclk: demodulator master clock
- * ExtClk: external clock frequency (Hz)
- */
-static void stb0899_set_mclk(struct stb0899_state *state, u32 Mclk)
-{
-	struct stb0899_internal *internal = &state->internal;
-	u8 mdiv = 0;
-
-	dprintk(state->verbose, FE_DEBUG, 1, "state->config=%p", state->config);
-	mdiv = ((6 * Mclk) / state->config->xtal_freq) - 1;
-	dprintk(state->verbose, FE_DEBUG, 1, "mdiv=%d", mdiv);
-
-	stb0899_write_reg(state, STB0899_NCOARSE, mdiv);
-	internal->master_clk = stb0899_get_mclk(state);
-
-	dprintk(state->verbose, FE_DEBUG, 1, "MasterCLOCK=%d", internal->master_clk);
-}
-
-static int stb0899_postproc(struct stb0899_state *state, u8 ctl, int enable)
-{
-	struct stb0899_config *config		= state->config;
-	const struct stb0899_postproc *postproc	= config->postproc;
-
-	/* post process event */
-	if (postproc) {
-		if (enable) {
-			if (postproc[ctl].level == STB0899_GPIOPULLUP)
-				stb0899_write_reg(state, postproc[ctl].gpio, 0x02);
-			else
-				stb0899_write_reg(state, postproc[ctl].gpio, 0x82);
-		} else {
-			if (postproc[ctl].level == STB0899_GPIOPULLUP)
-				stb0899_write_reg(state, postproc[ctl].gpio, 0x82);
-			else
-				stb0899_write_reg(state, postproc[ctl].gpio, 0x02);
-		}
-	}
-	return 0;
-}
-
-static void stb0899_release(struct dvb_frontend *fe)
-{
-	struct stb0899_state *state = fe->demodulator_priv;
-
-	dprintk(state->verbose, FE_DEBUG, 1, "Release Frontend");
-	/* post process event */
-	stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 0);
-	kfree(state);
-}
-
-/*
- * stb0899_get_alpha
- * return: rolloff
- */
-static int stb0899_get_alpha(struct stb0899_state *state)
-{
-	u8 mode_coeff;
-
-	mode_coeff = stb0899_read_reg(state, STB0899_DEMOD);
-
-	if (STB0899_GETFIELD(MODECOEFF, mode_coeff) == 1)
-		return 20;
-	else
-		return 35;
-}
-
-/*
- * stb0899_init_calc
- */
-static void stb0899_init_calc(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal = &state->internal;
-	int master_clk;
-	u8 agc[2];
-	u32 reg;
-
-	/* Read registers (in burst mode)	*/
-	stb0899_read_regs(state, STB0899_AGC1REF, agc, 2); /* AGC1R and AGC2O	*/
-
-	/* Initial calculations	*/
-	master_clk			= stb0899_get_mclk(state);
-	internal->t_agc1		= 0;
-	internal->t_agc2		= 0;
-	internal->master_clk		= master_clk;
-	internal->mclk			= master_clk / 65536L;
-	internal->rolloff		= stb0899_get_alpha(state);
-
-	/* DVBS2 Initial calculations	*/
-	/* Set AGC value to the middle	*/
-	internal->agc_gain		= 8154;
-	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL);
-	STB0899_SETFIELD_VAL(IF_GAIN_INIT, reg, internal->agc_gain);
-	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg);
-
-	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, RRC_ALPHA);
-	internal->rrc_alpha		= STB0899_GETFIELD(RRC_ALPHA, reg);
-
-	internal->center_freq		= 0;
-	internal->av_frame_coarse	= 10;
-	internal->av_frame_fine		= 20;
-	internal->step_size		= 2;
-/*
-	if ((pParams->SpectralInv == FE_IQ_NORMAL) || (pParams->SpectralInv == FE_IQ_AUTO))
-		pParams->IQLocked = 0;
-	else
-		pParams->IQLocked = 1;
-*/
-}
-
-static int stb0899_wait_diseqc_fifo_empty(struct stb0899_state *state, int timeout)
-{
-	u8 reg = 0;
-	unsigned long start = jiffies;
-
-	while (1) {
-		reg = stb0899_read_reg(state, STB0899_DISSTATUS);
-		if (!STB0899_GETFIELD(FIFOFULL, reg))
-			break;
-		if ((jiffies - start) > timeout) {
-			dprintk(state->verbose, FE_ERROR, 1, "timed out !!");
-			return -ETIMEDOUT;
-		}
-	}
-
-	return 0;
-}
-
-static int stb0899_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd)
-{
-	struct stb0899_state *state = fe->demodulator_priv;
-	u8 reg, i;
-
-	if (cmd->msg_len > 8)
-		return -EINVAL;
-
-	/* enable FIFO precharge	*/
-	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
-	STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 1);
-	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
-	for (i = 0; i < cmd->msg_len; i++) {
-		/* wait for FIFO empty	*/
-		if (stb0899_wait_diseqc_fifo_empty(state, 100) < 0)
-			return -ETIMEDOUT;
-
-		stb0899_write_reg(state, STB0899_DISFIFO, cmd->msg[i]);
-	}
-	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
-	STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0);
-	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
-	msleep(100);
-	return 0;
-}
-
-static int stb0899_wait_diseqc_rxidle(struct stb0899_state *state, int timeout)
-{
-	u8 reg = 0;
-	unsigned long start = jiffies;
-
-	while (!STB0899_GETFIELD(RXEND, reg)) {
-		reg = stb0899_read_reg(state, STB0899_DISRX_ST0);
-		if (jiffies - start > timeout) {
-			dprintk(state->verbose, FE_ERROR, 1, "timed out!!");
-			return -ETIMEDOUT;
-		}
-		msleep(10);
-	}
-
-	return 0;
-}
-
-static int stb0899_recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_slave_reply *reply)
-{
-	struct stb0899_state *state = fe->demodulator_priv;
-	u8 reg, length = 0, i;
-	int result;
-
-	if (stb0899_wait_diseqc_rxidle(state, 100) < 0)
-		return -ETIMEDOUT;
-
-	reg = stb0899_read_reg(state, STB0899_DISRX_ST0);
-	if (STB0899_GETFIELD(RXEND, reg)) {
-
-		reg = stb0899_read_reg(state, STB0899_DISRX_ST1);
-		length = STB0899_GETFIELD(FIFOBYTENBR, reg);
-
-		if (length > sizeof (reply->msg)) {
-			result = -EOVERFLOW;
-			goto exit;
-		}
-		reply->msg_len = length;
-
-		/* extract data */
-		for (i = 0; i < length; i++)
-			reply->msg[i] = stb0899_read_reg(state, STB0899_DISFIFO);
-	}
-
-	return 0;
-exit:
-
-	return result;
-}
-
-static int stb0899_wait_diseqc_txidle(struct stb0899_state *state, int timeout)
-{
-	u8 reg = 0;
-	unsigned long start = jiffies;
-
-	while (!STB0899_GETFIELD(TXIDLE, reg)) {
-		reg = stb0899_read_reg(state, STB0899_DISSTATUS);
-		if (jiffies - start > timeout) {
-			dprintk(state->verbose, FE_ERROR, 1, "timed out!!");
-			return -ETIMEDOUT;
-		}
-		msleep(10);
-	}
-	return 0;
-}
-
-static int stb0899_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
-{
-	struct stb0899_state *state = fe->demodulator_priv;
-	u8 reg, old_state;
-
-	/* wait for diseqc idle	*/
-	if (stb0899_wait_diseqc_txidle(state, 100) < 0)
-		return -ETIMEDOUT;
-
-	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
-	old_state = reg;
-	/* set to burst mode	*/
-	STB0899_SETFIELD_VAL(DISEQCMODE, reg, 0x03);
-	STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0x01);
-	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
-	switch (burst) {
-	case SEC_MINI_A:
-		/* unmodulated	*/
-		stb0899_write_reg(state, STB0899_DISFIFO, 0x00);
-		break;
-	case SEC_MINI_B:
-		/* modulated	*/
-		stb0899_write_reg(state, STB0899_DISFIFO, 0xff);
-		break;
-	}
-	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
-	STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0x00);
-	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
-	/* wait for diseqc idle	*/
-	if (stb0899_wait_diseqc_txidle(state, 100) < 0)
-		return -ETIMEDOUT;
-
-	/* restore state	*/
-	stb0899_write_reg(state, STB0899_DISCNTRL1, old_state);
-
-	return 0;
-}
-
-static int stb0899_diseqc_init(struct stb0899_state *state)
-{
-/*
-	struct dvb_diseqc_slave_reply rx_data;
-*/
-	u8 f22_tx, reg;
-
-	u32 mclk, tx_freq = 22000;/* count = 0, i; */
-	reg = stb0899_read_reg(state, STB0899_DISCNTRL2);
-	STB0899_SETFIELD_VAL(ONECHIP_TRX, reg, 0);
-	stb0899_write_reg(state, STB0899_DISCNTRL2, reg);
-
-	/* disable Tx spy	*/
-	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
-	STB0899_SETFIELD_VAL(DISEQCRESET, reg, 1);
-	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
-
-	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
-	STB0899_SETFIELD_VAL(DISEQCRESET, reg, 0);
-	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
-
-	mclk = stb0899_get_mclk(state);
-	f22_tx = mclk / (tx_freq * 32);
-	stb0899_write_reg(state, STB0899_DISF22, f22_tx); /* DiSEqC Tx freq	*/
-	state->rx_freq = 20000;
-
-	return 0;
-}
-
-static int stb0899_sleep(struct dvb_frontend *fe)
-{
-	struct stb0899_state *state = fe->demodulator_priv;
-/*
-	u8 reg;
-*/
-	dprintk(state->verbose, FE_DEBUG, 1, "Going to Sleep .. (Really tired .. :-))");
-	/* post process event */
-	stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 0);
-
-	return 0;
-}
-
-static int stb0899_wakeup(struct dvb_frontend *fe)
-{
-	int rc;
-	struct stb0899_state *state = fe->demodulator_priv;
-
-	if ((rc = stb0899_write_reg(state, STB0899_SYNTCTRL, STB0899_SELOSCI)))
-		return rc;
-	/* Activate all clocks; DVB-S2 registers are inaccessible otherwise. */
-	if ((rc = stb0899_write_reg(state, STB0899_STOPCLK1, 0x00)))
-		return rc;
-	if ((rc = stb0899_write_reg(state, STB0899_STOPCLK2, 0x00)))
-		return rc;
-
-	/* post process event */
-	stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 1);
-
-	return 0;
-}
-
-static int stb0899_init(struct dvb_frontend *fe)
-{
-	int i;
-	struct stb0899_state *state = fe->demodulator_priv;
-	struct stb0899_config *config = state->config;
-
-	dprintk(state->verbose, FE_DEBUG, 1, "Initializing STB0899 ... ");
-
-	/* init device		*/
-	dprintk(state->verbose, FE_DEBUG, 1, "init device");
-	for (i = 0; config->init_dev[i].address != 0xffff; i++)
-		stb0899_write_reg(state, config->init_dev[i].address, config->init_dev[i].data);
-
-	dprintk(state->verbose, FE_DEBUG, 1, "init S2 demod");
-	/* init S2 demod	*/
-	for (i = 0; config->init_s2_demod[i].offset != 0xffff; i++)
-		stb0899_write_s2reg(state, STB0899_S2DEMOD,
-				    config->init_s2_demod[i].base_address,
-				    config->init_s2_demod[i].offset,
-				    config->init_s2_demod[i].data);
-
-	dprintk(state->verbose, FE_DEBUG, 1, "init S1 demod");
-	/* init S1 demod	*/
-	for (i = 0; config->init_s1_demod[i].address != 0xffff; i++)
-		stb0899_write_reg(state, config->init_s1_demod[i].address, config->init_s1_demod[i].data);
-
-	dprintk(state->verbose, FE_DEBUG, 1, "init S2 FEC");
-	/* init S2 fec		*/
-	for (i = 0; config->init_s2_fec[i].offset != 0xffff; i++)
-		stb0899_write_s2reg(state, STB0899_S2FEC,
-				    config->init_s2_fec[i].base_address,
-				    config->init_s2_fec[i].offset,
-				    config->init_s2_fec[i].data);
-
-	dprintk(state->verbose, FE_DEBUG, 1, "init TST");
-	/* init test		*/
-	for (i = 0; config->init_tst[i].address != 0xffff; i++)
-		stb0899_write_reg(state, config->init_tst[i].address, config->init_tst[i].data);
-
-	stb0899_init_calc(state);
-	stb0899_diseqc_init(state);
-
-	return 0;
-}
-
-static int stb0899_table_lookup(const struct stb0899_tab *tab, int max, int val)
-{
-	int res = 0;
-	int min = 0, med;
-
-	if (val < tab[min].read)
-		res = tab[min].real;
-	else if (val >= tab[max].read)
-		res = tab[max].real;
-	else {
-		while ((max - min) > 1) {
-			med = (max + min) / 2;
-			if (val >= tab[min].read && val < tab[med].read)
-				max = med;
-			else
-				min = med;
-		}
-		res = ((val - tab[min].read) *
-		       (tab[max].real - tab[min].real) /
-		       (tab[max].read - tab[min].read)) +
-			tab[min].real;
-	}
-
-	return res;
-}
-
-static int stb0899_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct stb0899_state *state		= fe->demodulator_priv;
-	struct stb0899_internal *internal	= &state->internal;
-
-	int val;
-	u32 reg;
-	*strength = 0;
-	switch (state->delsys) {
-	case SYS_DVBS:
-	case SYS_DSS:
-		if (internal->lock) {
-			reg  = stb0899_read_reg(state, STB0899_VSTATUS);
-			if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) {
-
-				reg = stb0899_read_reg(state, STB0899_AGCIQIN);
-				val = (s32)(s8)STB0899_GETFIELD(AGCIQVALUE, reg);
-
-				*strength = stb0899_table_lookup(stb0899_dvbsrf_tab, ARRAY_SIZE(stb0899_dvbsrf_tab) - 1, val);
-				*strength += 750;
-				dprintk(state->verbose, FE_DEBUG, 1, "AGCIQVALUE = 0x%02x, C = %d * 0.1 dBm",
-					val & 0xff, *strength);
-			}
-		}
-		break;
-	case SYS_DVBS2:
-		if (internal->lock) {
-			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_GAIN);
-			val = STB0899_GETFIELD(IF_AGC_GAIN, reg);
-
-			*strength = stb0899_table_lookup(stb0899_dvbs2rf_tab, ARRAY_SIZE(stb0899_dvbs2rf_tab) - 1, val);
-			*strength += 950;
-			dprintk(state->verbose, FE_DEBUG, 1, "IF_AGC_GAIN = 0x%04x, C = %d * 0.1 dBm",
-				val & 0x3fff, *strength);
-		}
-		break;
-	default:
-		dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int stb0899_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct stb0899_state *state		= fe->demodulator_priv;
-	struct stb0899_internal *internal	= &state->internal;
-
-	unsigned int val, quant, quantn = -1, est, estn = -1;
-	u8 buf[2];
-	u32 reg;
-
-	*snr = 0;
-	reg  = stb0899_read_reg(state, STB0899_VSTATUS);
-	switch (state->delsys) {
-	case SYS_DVBS:
-	case SYS_DSS:
-		if (internal->lock) {
-			if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) {
-
-				stb0899_read_regs(state, STB0899_NIRM, buf, 2);
-				val = MAKEWORD16(buf[0], buf[1]);
-
-				*snr = stb0899_table_lookup(stb0899_cn_tab, ARRAY_SIZE(stb0899_cn_tab) - 1, val);
-				dprintk(state->verbose, FE_DEBUG, 1, "NIR = 0x%02x%02x = %u, C/N = %d * 0.1 dBm\n",
-					buf[0], buf[1], val, *snr);
-			}
-		}
-		break;
-	case SYS_DVBS2:
-		if (internal->lock) {
-			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL1);
-			quant = STB0899_GETFIELD(UWP_ESN0_QUANT, reg);
-			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2);
-			est = STB0899_GETFIELD(ESN0_EST, reg);
-			if (est == 1)
-				val = 301; /* C/N = 30.1 dB */
-			else if (est == 2)
-				val = 270; /* C/N = 27.0 dB */
-			else {
-				/* quantn = 100 * log(quant^2) */
-				quantn = stb0899_table_lookup(stb0899_quant_tab, ARRAY_SIZE(stb0899_quant_tab) - 1, quant * 100);
-				/* estn = 100 * log(est) */
-				estn = stb0899_table_lookup(stb0899_est_tab, ARRAY_SIZE(stb0899_est_tab) - 1, est);
-				/* snr(dBm/10) = -10*(log(est)-log(quant^2)) => snr(dBm/10) = (100*log(quant^2)-100*log(est))/10 */
-				val = (quantn - estn) / 10;
-			}
-			*snr = val;
-			dprintk(state->verbose, FE_DEBUG, 1, "Es/N0 quant = %d (%d) estimate = %u (%d), C/N = %d * 0.1 dBm",
-				quant, quantn, est, estn, val);
-		}
-		break;
-	default:
-		dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int stb0899_read_status(struct dvb_frontend *fe, enum fe_status *status)
-{
-	struct stb0899_state *state		= fe->demodulator_priv;
-	struct stb0899_internal *internal	= &state->internal;
-	u8 reg;
-	*status = 0;
-
-	switch (state->delsys) {
-	case SYS_DVBS:
-	case SYS_DSS:
-		dprintk(state->verbose, FE_DEBUG, 1, "Delivery system DVB-S/DSS");
-		if (internal->lock) {
-			reg  = stb0899_read_reg(state, STB0899_VSTATUS);
-			if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) {
-				dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_CARRIER | FE_HAS_LOCK");
-				*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
-
-				reg = stb0899_read_reg(state, STB0899_PLPARM);
-				if (STB0899_GETFIELD(VITCURPUN, reg)) {
-					dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_VITERBI | FE_HAS_SYNC");
-					*status |= FE_HAS_VITERBI | FE_HAS_SYNC;
-					/* post process event */
-					stb0899_postproc(state, STB0899_POSTPROC_GPIO_LOCK, 1);
-				}
-			}
-		}
-		break;
-	case SYS_DVBS2:
-		dprintk(state->verbose, FE_DEBUG, 1, "Delivery system DVB-S2");
-		if (internal->lock) {
-			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STAT2);
-			if (STB0899_GETFIELD(UWP_LOCK, reg) && STB0899_GETFIELD(CSM_LOCK, reg)) {
-				*status |= FE_HAS_CARRIER;
-				dprintk(state->verbose, FE_DEBUG, 1,
-					"UWP & CSM Lock ! ---> DVB-S2 FE_HAS_CARRIER");
-
-				reg = stb0899_read_reg(state, STB0899_CFGPDELSTATUS1);
-				if (STB0899_GETFIELD(CFGPDELSTATUS_LOCK, reg)) {
-					*status |= FE_HAS_LOCK;
-					dprintk(state->verbose, FE_DEBUG, 1,
-						"Packet Delineator Locked ! -----> DVB-S2 FE_HAS_LOCK");
-
-				}
-				if (STB0899_GETFIELD(CONTINUOUS_STREAM, reg)) {
-					*status |= FE_HAS_VITERBI;
-					dprintk(state->verbose, FE_DEBUG, 1,
-						"Packet Delineator found VITERBI ! -----> DVB-S2 FE_HAS_VITERBI");
-				}
-				if (STB0899_GETFIELD(ACCEPTED_STREAM, reg)) {
-					*status |= FE_HAS_SYNC;
-					dprintk(state->verbose, FE_DEBUG, 1,
-						"Packet Delineator found SYNC ! -----> DVB-S2 FE_HAS_SYNC");
-					/* post process event */
-					stb0899_postproc(state, STB0899_POSTPROC_GPIO_LOCK, 1);
-				}
-			}
-		}
-		break;
-	default:
-		dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system");
-		return -EINVAL;
-	}
-	return 0;
-}
-
-/*
- * stb0899_get_error
- * viterbi error for DVB-S/DSS
- * packet error for DVB-S2
- * Bit Error Rate or Packet Error Rate * 10 ^ 7
- */
-static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct stb0899_state *state		= fe->demodulator_priv;
-	struct stb0899_internal *internal	= &state->internal;
-
-	u8  lsb, msb;
-
-	*ber = 0;
-
-	switch (state->delsys) {
-	case SYS_DVBS:
-	case SYS_DSS:
-		if (internal->lock) {
-			lsb = stb0899_read_reg(state, STB0899_ECNT1L);
-			msb = stb0899_read_reg(state, STB0899_ECNT1M);
-			*ber = MAKEWORD16(msb, lsb);
-			/* Viterbi Check	*/
-			if (STB0899_GETFIELD(VSTATUS_PRFVIT, internal->v_status)) {
-				/* Error Rate		*/
-				*ber *= 9766;
-				/* ber = ber * 10 ^ 7	*/
-				*ber /= (-1 + (1 << (2 * STB0899_GETFIELD(NOE, internal->err_ctrl))));
-				*ber /= 8;
-			}
-		}
-		break;
-	case SYS_DVBS2:
-		if (internal->lock) {
-			lsb = stb0899_read_reg(state, STB0899_ECNT1L);
-			msb = stb0899_read_reg(state, STB0899_ECNT1M);
-			*ber = MAKEWORD16(msb, lsb);
-			/* ber = ber * 10 ^ 7	*/
-			*ber *= 10000000;
-			*ber /= (-1 + (1 << (4 + 2 * STB0899_GETFIELD(NOE, internal->err_ctrl))));
-		}
-		break;
-	default:
-		dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int stb0899_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
-	struct stb0899_state *state = fe->demodulator_priv;
-
-	switch (voltage) {
-	case SEC_VOLTAGE_13:
-		stb0899_write_reg(state, STB0899_GPIO00CFG, 0x82);
-		stb0899_write_reg(state, STB0899_GPIO01CFG, 0x02);
-		stb0899_write_reg(state, STB0899_GPIO02CFG, 0x00);
-		break;
-	case SEC_VOLTAGE_18:
-		stb0899_write_reg(state, STB0899_GPIO00CFG, 0x02);
-		stb0899_write_reg(state, STB0899_GPIO01CFG, 0x02);
-		stb0899_write_reg(state, STB0899_GPIO02CFG, 0x82);
-		break;
-	case SEC_VOLTAGE_OFF:
-		stb0899_write_reg(state, STB0899_GPIO00CFG, 0x82);
-		stb0899_write_reg(state, STB0899_GPIO01CFG, 0x82);
-		stb0899_write_reg(state, STB0899_GPIO02CFG, 0x82);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int stb0899_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
-{
-	struct stb0899_state *state = fe->demodulator_priv;
-	struct stb0899_internal *internal = &state->internal;
-
-	u8 div, reg;
-
-	/* wait for diseqc idle	*/
-	if (stb0899_wait_diseqc_txidle(state, 100) < 0)
-		return -ETIMEDOUT;
-
-	switch (tone) {
-	case SEC_TONE_ON:
-		div = (internal->master_clk / 100) / 5632;
-		div = (div + 5) / 10;
-		stb0899_write_reg(state, STB0899_DISEQCOCFG, 0x66);
-		reg = stb0899_read_reg(state, STB0899_ACRPRESC);
-		STB0899_SETFIELD_VAL(ACRPRESC, reg, 0x03);
-		stb0899_write_reg(state, STB0899_ACRPRESC, reg);
-		stb0899_write_reg(state, STB0899_ACRDIV1, div);
-		break;
-	case SEC_TONE_OFF:
-		stb0899_write_reg(state, STB0899_DISEQCOCFG, 0x20);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-int stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	int i2c_stat;
-	struct stb0899_state *state = fe->demodulator_priv;
-
-	i2c_stat = stb0899_read_reg(state, STB0899_I2CRPT);
-	if (i2c_stat < 0)
-		goto err;
-
-	if (enable) {
-		dprintk(state->verbose, FE_DEBUG, 1, "Enabling I2C Repeater ...");
-		i2c_stat |=  STB0899_I2CTON;
-		if (stb0899_write_reg(state, STB0899_I2CRPT, i2c_stat) < 0)
-			goto err;
-	} else {
-		dprintk(state->verbose, FE_DEBUG, 1, "Disabling I2C Repeater ...");
-		i2c_stat &= ~STB0899_I2CTON;
-		if (stb0899_write_reg(state, STB0899_I2CRPT, i2c_stat) < 0)
-			goto err;
-	}
-	return 0;
-err:
-	dprintk(state->verbose, FE_ERROR, 1, "I2C Repeater control failed");
-	return -EREMOTEIO;
-}
-
-
-static inline void CONVERT32(u32 x, char *str)
-{
-	*str++	= (x >> 24) & 0xff;
-	*str++	= (x >> 16) & 0xff;
-	*str++	= (x >>  8) & 0xff;
-	*str++	= (x >>  0) & 0xff;
-	*str	= '\0';
-}
-
-int stb0899_get_dev_id(struct stb0899_state *state)
-{
-	u8 chip_id, release;
-	u16 id;
-	u32 demod_ver = 0, fec_ver = 0;
-	char demod_str[5] = { 0 };
-	char fec_str[5] = { 0 };
-
-	id = stb0899_read_reg(state, STB0899_DEV_ID);
-	dprintk(state->verbose, FE_DEBUG, 1, "ID reg=[0x%02x]", id);
-	chip_id = STB0899_GETFIELD(CHIP_ID, id);
-	release = STB0899_GETFIELD(CHIP_REL, id);
-
-	dprintk(state->verbose, FE_ERROR, 1, "Device ID=[%d], Release=[%d]",
-		chip_id, release);
-
-	CONVERT32(STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CORE_ID), (char *)&demod_str);
-
-	demod_ver = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_VERSION_ID);
-	dprintk(state->verbose, FE_ERROR, 1, "Demodulator Core ID=[%s], Version=[%d]", (char *) &demod_str, demod_ver);
-	CONVERT32(STB0899_READ_S2REG(STB0899_S2FEC, FEC_CORE_ID_REG), (char *)&fec_str);
-	fec_ver = STB0899_READ_S2REG(STB0899_S2FEC, FEC_VER_ID_REG);
-	if (! (chip_id > 0)) {
-		dprintk(state->verbose, FE_ERROR, 1, "couldn't find a STB 0899");
-
-		return -ENODEV;
-	}
-	dprintk(state->verbose, FE_ERROR, 1, "FEC Core ID=[%s], Version=[%d]", (char*) &fec_str, fec_ver);
-
-	return 0;
-}
-
-static void stb0899_set_delivery(struct stb0899_state *state)
-{
-	u8 reg;
-	u8 stop_clk[2];
-
-	stop_clk[0] = stb0899_read_reg(state, STB0899_STOPCLK1);
-	stop_clk[1] = stb0899_read_reg(state, STB0899_STOPCLK2);
-
-	switch (state->delsys) {
-	case SYS_DVBS:
-		dprintk(state->verbose, FE_DEBUG, 1, "Delivery System -- DVB-S");
-		/* FECM/Viterbi ON	*/
-		reg = stb0899_read_reg(state, STB0899_FECM);
-		STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 0);
-		STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 1);
-		stb0899_write_reg(state, STB0899_FECM, reg);
-
-		stb0899_write_reg(state, STB0899_RSULC, 0xb1);
-		stb0899_write_reg(state, STB0899_TSULC, 0x40);
-		stb0899_write_reg(state, STB0899_RSLLC, 0x42);
-		stb0899_write_reg(state, STB0899_TSLPL, 0x12);
-
-		reg = stb0899_read_reg(state, STB0899_TSTRES);
-		STB0899_SETFIELD_VAL(FRESLDPC, reg, 1);
-		stb0899_write_reg(state, STB0899_TSTRES, reg);
-
-		STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1);
-		STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 1);
-		STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 1);
-
-		STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 1);
-		STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 1);
-
-		STB0899_SETFIELD_VAL(STOP_CKINTBUF216, stop_clk[0], 1);
-		STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0);
-
-		STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 1);
-		break;
-	case SYS_DVBS2:
-		/* FECM/Viterbi OFF	*/
-		reg = stb0899_read_reg(state, STB0899_FECM);
-		STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 0);
-		STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 0);
-		stb0899_write_reg(state, STB0899_FECM, reg);
-
-		stb0899_write_reg(state, STB0899_RSULC, 0xb1);
-		stb0899_write_reg(state, STB0899_TSULC, 0x42);
-		stb0899_write_reg(state, STB0899_RSLLC, 0x40);
-		stb0899_write_reg(state, STB0899_TSLPL, 0x02);
-
-		reg = stb0899_read_reg(state, STB0899_TSTRES);
-		STB0899_SETFIELD_VAL(FRESLDPC, reg, 0);
-		stb0899_write_reg(state, STB0899_TSTRES, reg);
-
-		STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1);
-		STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 0);
-		STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 0);
-
-		STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 0);
-		STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 0);
-
-		STB0899_SETFIELD_VAL(STOP_CKINTBUF216, stop_clk[0], 0);
-		STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0);
-
-		STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 0);
-		break;
-	case SYS_DSS:
-		/* FECM/Viterbi ON	*/
-		reg = stb0899_read_reg(state, STB0899_FECM);
-		STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 1);
-		STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 1);
-		stb0899_write_reg(state, STB0899_FECM, reg);
-
-		stb0899_write_reg(state, STB0899_RSULC, 0xa1);
-		stb0899_write_reg(state, STB0899_TSULC, 0x61);
-		stb0899_write_reg(state, STB0899_RSLLC, 0x42);
-
-		reg = stb0899_read_reg(state, STB0899_TSTRES);
-		STB0899_SETFIELD_VAL(FRESLDPC, reg, 1);
-		stb0899_write_reg(state, STB0899_TSTRES, reg);
-
-		STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1);
-		STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 1);
-		STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 1);
-
-		STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 1);
-		STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 1);
-
-		STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0);
-
-		STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 1);
-		break;
-	default:
-		dprintk(state->verbose, FE_ERROR, 1, "Unsupported delivery system");
-		break;
-	}
-	STB0899_SETFIELD_VAL(STOP_CKADCI108, stop_clk[0], 0);
-	stb0899_write_regs(state, STB0899_STOPCLK1, stop_clk, 2);
-}
-
-/*
- * stb0899_set_iterations
- * set the LDPC iteration scale function
- */
-static void stb0899_set_iterations(struct stb0899_state *state)
-{
-	struct stb0899_internal *internal = &state->internal;
-	struct stb0899_config *config = state->config;
-
-	s32 iter_scale;
-	u32 reg;
-
-	iter_scale = 17 * (internal->master_clk / 1000);
-	iter_scale += 410000;
-	iter_scale /= (internal->srate / 1000000);
-	iter_scale /= 1000;
-
-	if (iter_scale > config->ldpc_max_iter)
-		iter_scale = config->ldpc_max_iter;
-
-	reg = STB0899_READ_S2REG(STB0899_S2FEC, MAX_ITER);
-	STB0899_SETFIELD_VAL(MAX_ITERATIONS, reg, iter_scale);
-	stb0899_write_s2reg(state, STB0899_S2FEC, STB0899_BASE_MAX_ITER, STB0899_OFF0_MAX_ITER, reg);
-}
-
-static enum dvbfe_search stb0899_search(struct dvb_frontend *fe)
-{
-	struct stb0899_state *state = fe->demodulator_priv;
-	struct stb0899_params *i_params = &state->params;
-	struct stb0899_internal *internal = &state->internal;
-	struct stb0899_config *config = state->config;
-	struct dtv_frontend_properties *props = &fe->dtv_property_cache;
-
-	u32 SearchRange, gain;
-
-	i_params->freq	= props->frequency;
-	i_params->srate = props->symbol_rate;
-	state->delsys = props->delivery_system;
-	dprintk(state->verbose, FE_DEBUG, 1, "delivery system=%d", state->delsys);
-
-	SearchRange = 10000000;
-	dprintk(state->verbose, FE_DEBUG, 1, "Frequency=%d, Srate=%d", i_params->freq, i_params->srate);
-	/* checking Search Range is meaningless for a fixed 3 Mhz			*/
-	if (INRANGE(i_params->srate, 1000000, 45000000)) {
-		dprintk(state->verbose, FE_DEBUG, 1, "Parameters IN RANGE");
-		stb0899_set_delivery(state);
-
-		if (state->config->tuner_set_rfsiggain) {
-			if (internal->srate > 15000000)
-				gain =  8; /* 15Mb < srate < 45Mb, gain = 8dB	*/
-			else if (internal->srate > 5000000)
-				gain = 12; /*  5Mb < srate < 15Mb, gain = 12dB	*/
-			else
-				gain = 14; /*  1Mb < srate <  5Mb, gain = 14db	*/
-			state->config->tuner_set_rfsiggain(fe, gain);
-		}
-
-		if (i_params->srate <= 5000000)
-			stb0899_set_mclk(state, config->lo_clk);
-		else
-			stb0899_set_mclk(state, config->hi_clk);
-
-		switch (state->delsys) {
-		case SYS_DVBS:
-		case SYS_DSS:
-			dprintk(state->verbose, FE_DEBUG, 1, "DVB-S delivery system");
-			internal->freq	= i_params->freq;
-			internal->srate	= i_params->srate;
-			/*
-			 * search = user search range +
-			 *	    500Khz +
-			 *	    2 * Tuner_step_size +
-			 *	    10% of the symbol rate
-			 */
-			internal->srch_range	= SearchRange + 1500000 + (i_params->srate / 5);
-			internal->derot_percent	= 30;
-
-			/* What to do for tuners having no bandwidth setup ?	*/
-			/* enable tuner I/O */
-			stb0899_i2c_gate_ctrl(&state->frontend, 1);
-
-			if (state->config->tuner_set_bandwidth)
-				state->config->tuner_set_bandwidth(fe, (13 * (stb0899_carr_width(state) + SearchRange)) / 10);
-			if (state->config->tuner_get_bandwidth)
-				state->config->tuner_get_bandwidth(fe, &internal->tuner_bw);
-
-			/* disable tuner I/O */
-			stb0899_i2c_gate_ctrl(&state->frontend, 0);
-
-			/* Set DVB-S1 AGC		*/
-			stb0899_write_reg(state, STB0899_AGCRFCFG, 0x11);
-
-			/* Run the search algorithm	*/
-			dprintk(state->verbose, FE_DEBUG, 1, "running DVB-S search algo ..");
-			if (stb0899_dvbs_algo(state)	== RANGEOK) {
-				internal->lock		= 1;
-				dprintk(state->verbose, FE_DEBUG, 1,
-					"-------------------------------------> DVB-S LOCK !");
-
-//				stb0899_write_reg(state, STB0899_ERRCTRL1, 0x3d); /* Viterbi Errors	*/
-//				internal->v_status = stb0899_read_reg(state, STB0899_VSTATUS);
-//				internal->err_ctrl = stb0899_read_reg(state, STB0899_ERRCTRL1);
-//				dprintk(state->verbose, FE_DEBUG, 1, "VSTATUS=0x%02x", internal->v_status);
-//				dprintk(state->verbose, FE_DEBUG, 1, "ERR_CTRL=0x%02x", internal->err_ctrl);
-
-				return DVBFE_ALGO_SEARCH_SUCCESS;
-			} else {
-				internal->lock		= 0;
-
-				return DVBFE_ALGO_SEARCH_FAILED;
-			}
-			break;
-		case SYS_DVBS2:
-			internal->freq			= i_params->freq;
-			internal->srate			= i_params->srate;
-			internal->srch_range		= SearchRange;
-
-			/* enable tuner I/O */
-			stb0899_i2c_gate_ctrl(&state->frontend, 1);
-
-			if (state->config->tuner_set_bandwidth)
-				state->config->tuner_set_bandwidth(fe, (stb0899_carr_width(state) + SearchRange));
-			if (state->config->tuner_get_bandwidth)
-				state->config->tuner_get_bandwidth(fe, &internal->tuner_bw);
-
-			/* disable tuner I/O */
-			stb0899_i2c_gate_ctrl(&state->frontend, 0);
-
-//			pParams->SpectralInv		= pSearch->IQ_Inversion;
-
-			/* Set DVB-S2 AGC		*/
-			stb0899_write_reg(state, STB0899_AGCRFCFG, 0x1c);
-
-			/* Set IterScale =f(MCLK,SYMB)	*/
-			stb0899_set_iterations(state);
-
-			/* Run the search algorithm	*/
-			dprintk(state->verbose, FE_DEBUG, 1, "running DVB-S2 search algo ..");
-			if (stb0899_dvbs2_algo(state)	== DVBS2_FEC_LOCK) {
-				internal->lock		= 1;
-				dprintk(state->verbose, FE_DEBUG, 1,
-					"-------------------------------------> DVB-S2 LOCK !");
-
-//				stb0899_write_reg(state, STB0899_ERRCTRL1, 0xb6); /* Packet Errors	*/
-//				internal->v_status = stb0899_read_reg(state, STB0899_VSTATUS);
-//				internal->err_ctrl = stb0899_read_reg(state, STB0899_ERRCTRL1);
-
-				return DVBFE_ALGO_SEARCH_SUCCESS;
-			} else {
-				internal->lock		= 0;
-
-				return DVBFE_ALGO_SEARCH_FAILED;
-			}
-			break;
-		default:
-			dprintk(state->verbose, FE_ERROR, 1, "Unsupported delivery system");
-			return DVBFE_ALGO_SEARCH_INVALID;
-		}
-	}
-
-	return DVBFE_ALGO_SEARCH_ERROR;
-}
-
-static int stb0899_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct stb0899_state *state		= fe->demodulator_priv;
-	struct stb0899_internal *internal	= &state->internal;
-
-	dprintk(state->verbose, FE_DEBUG, 1, "Get params");
-	p->symbol_rate = internal->srate;
-
-	return 0;
-}
-
-static enum dvbfe_algo stb0899_frontend_algo(struct dvb_frontend *fe)
-{
-	return DVBFE_ALGO_CUSTOM;
-}
-
-static struct dvb_frontend_ops stb0899_ops = {
-	.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
-	.info = {
-		.name 			= "STB0899 Multistandard",
-		.frequency_min		= 950000,
-		.frequency_max 		= 2150000,
-		.frequency_stepsize	= 0,
-		.frequency_tolerance	= 0,
-		.symbol_rate_min 	=  5000000,
-		.symbol_rate_max 	= 45000000,
-
-		.caps 			= FE_CAN_INVERSION_AUTO	|
-					  FE_CAN_FEC_AUTO	|
-					  FE_CAN_2G_MODULATION	|
-					  FE_CAN_QPSK
-	},
-
-	.release			= stb0899_release,
-	.init				= stb0899_init,
-	.sleep				= stb0899_sleep,
-//	.wakeup				= stb0899_wakeup,
-
-	.i2c_gate_ctrl			= stb0899_i2c_gate_ctrl,
-
-	.get_frontend_algo		= stb0899_frontend_algo,
-	.search				= stb0899_search,
-	.get_frontend                   = stb0899_get_frontend,
-
-
-	.read_status			= stb0899_read_status,
-	.read_snr			= stb0899_read_snr,
-	.read_signal_strength		= stb0899_read_signal_strength,
-	.read_ber			= stb0899_read_ber,
-
-	.set_voltage			= stb0899_set_voltage,
-	.set_tone			= stb0899_set_tone,
-
-	.diseqc_send_master_cmd		= stb0899_send_diseqc_msg,
-	.diseqc_recv_slave_reply	= stb0899_recv_slave_reply,
-	.diseqc_send_burst		= stb0899_send_diseqc_burst,
-};
-
-struct dvb_frontend *stb0899_attach(struct stb0899_config *config, struct i2c_adapter *i2c)
-{
-	struct stb0899_state *state = NULL;
-	enum stb0899_inversion inversion;
-
-	state = kzalloc(sizeof (struct stb0899_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	inversion				= config->inversion;
-	state->verbose				= &verbose;
-	state->config				= config;
-	state->i2c				= i2c;
-	state->frontend.ops			= stb0899_ops;
-	state->frontend.demodulator_priv	= state;
-	state->internal.inversion		= inversion;
-
-	stb0899_wakeup(&state->frontend);
-	if (stb0899_get_dev_id(state) == -ENODEV) {
-		printk("%s: Exiting .. !\n", __func__);
-		goto error;
-	}
-
-	printk("%s: Attaching STB0899 \n", __func__);
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(stb0899_attach);
-MODULE_PARM_DESC(verbose, "Set Verbosity level");
-MODULE_AUTHOR("Manu Abraham");
-MODULE_DESCRIPTION("STB0899 Multi-Std frontend");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stb0899_drv.h b/drivers/media/dvb/frontends/stb0899_drv.h
deleted file mode 100644
index 98b200c..0000000
--- a/drivers/media/dvb/frontends/stb0899_drv.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
-	STB0899 Multistandard Frontend driver
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	Copyright (C) ST Microelectronics
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __STB0899_DRV_H
-#define __STB0899_DRV_H
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include "dvb_frontend.h"
-
-#define STB0899_TSMODE_SERIAL		1
-#define STB0899_CLKPOL_FALLING		2
-#define STB0899_CLKNULL_PARITY		3
-#define STB0899_SYNC_FORCED		4
-#define STB0899_FECMODE_DSS		5
-
-struct stb0899_s1_reg {
-	u16	address;
-	u8	data;
-};
-
-struct stb0899_s2_reg {
-	u16	offset;
-	u32	base_address;
-	u32	data;
-};
-
-enum stb0899_inversion {
-	IQ_SWAP_OFF	= 0,
-	IQ_SWAP_ON,
-	IQ_SWAP_AUTO
-};
-
-#define STB0899_GPIO00				0xf140
-#define STB0899_GPIO01				0xf141
-#define STB0899_GPIO02				0xf142
-#define STB0899_GPIO03				0xf143
-#define STB0899_GPIO04				0xf144
-#define STB0899_GPIO05				0xf145
-#define STB0899_GPIO06				0xf146
-#define STB0899_GPIO07				0xf147
-#define STB0899_GPIO08				0xf148
-#define STB0899_GPIO09				0xf149
-#define STB0899_GPIO10				0xf14a
-#define STB0899_GPIO11				0xf14b
-#define STB0899_GPIO12				0xf14c
-#define STB0899_GPIO13				0xf14d
-#define STB0899_GPIO14				0xf14e
-#define STB0899_GPIO15				0xf14f
-#define STB0899_GPIO16				0xf150
-#define STB0899_GPIO17				0xf151
-#define STB0899_GPIO18				0xf152
-#define STB0899_GPIO19				0xf153
-#define STB0899_GPIO20				0xf154
-
-#define STB0899_GPIOPULLUP			0x01 /* Output device is connected to Vdd */
-#define STB0899_GPIOPULLDN			0x00 /* Output device is connected to Vss */
-
-#define STB0899_POSTPROC_GPIO_POWER		0x00
-#define STB0899_POSTPROC_GPIO_LOCK		0x01
-
-/*
- * Post process output configuration control
- * 1. POWER ON/OFF		(index 0)
- * 2. FE_HAS_LOCK/LOCK_LOSS	(index 1)
- *
- * @gpio 	= one of the above listed GPIO's
- * @level	= output state: pulled up or low
- */
-struct stb0899_postproc {
-	u16	gpio;
-	u8	level;
-};
-
-struct stb0899_config {
-	const struct stb0899_s1_reg	*init_dev;
-	const struct stb0899_s2_reg	*init_s2_demod;
-	const struct stb0899_s1_reg	*init_s1_demod;
-	const struct stb0899_s2_reg	*init_s2_fec;
-	const struct stb0899_s1_reg	*init_tst;
-
-	const struct stb0899_postproc	*postproc;
-
-	enum stb0899_inversion		inversion;
-
-	u32	xtal_freq;
-
-	u8	demod_address;
-	u8	ts_output_mode;
-	u8	block_sync_mode;
-	u8	ts_pfbit_toggle;
-
-	u8	clock_polarity;
-	u8	data_clk_parity;
-	u8	fec_mode;
-	u8	data_output_ctl;
-	u8	data_fifo_mode;
-	u8	out_rate_comp;
-	u8	i2c_repeater;
-//	int	inversion;
-	int	lo_clk;
-	int	hi_clk;
-
-	u32	esno_ave;
-	u32	esno_quant;
-	u32	avframes_coarse;
-	u32	avframes_fine;
-	u32	miss_threshold;
-	u32	uwp_threshold_acq;
-	u32	uwp_threshold_track;
-	u32	uwp_threshold_sof;
-	u32	sof_search_timeout;
-
-	u32	btr_nco_bits;
-	u32	btr_gain_shift_offset;
-	u32	crl_nco_bits;
-	u32	ldpc_max_iter;
-
-	int (*tuner_set_frequency)(struct dvb_frontend *fe, u32 frequency);
-	int (*tuner_get_frequency)(struct dvb_frontend *fe, u32 *frequency);
-	int (*tuner_set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
-	int (*tuner_get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
-	int (*tuner_set_rfsiggain)(struct dvb_frontend *fe, u32 rf_gain);
-};
-
-#if defined(CONFIG_DVB_STB0899) || (defined(CONFIG_DVB_STB0899_MODULE) && defined(MODULE))
-
-extern struct dvb_frontend *stb0899_attach(struct stb0899_config *config,
-					   struct i2c_adapter *i2c);
-
-#else
-
-static inline struct dvb_frontend *stb0899_attach(struct stb0899_config *config,
-						  struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-#endif //CONFIG_DVB_STB0899
-
-
-#endif
diff --git a/drivers/media/dvb/frontends/stb0899_priv.h b/drivers/media/dvb/frontends/stb0899_priv.h
deleted file mode 100644
index 82395b9..0000000
--- a/drivers/media/dvb/frontends/stb0899_priv.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
-	STB0899 Multistandard Frontend driver
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	Copyright (C) ST Microelectronics
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __STB0899_PRIV_H
-#define __STB0899_PRIV_H
-
-#include "dvb_frontend.h"
-#include "stb0899_drv.h"
-
-#define FE_ERROR				0
-#define FE_NOTICE				1
-#define FE_INFO					2
-#define FE_DEBUG				3
-#define FE_DEBUGREG				4
-
-#define dprintk(x, y, z, format, arg...) do {						\
-	if (z) {									\
-		if	((*x > FE_ERROR) && (*x > y))					\
-			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);		\
-		else if	((*x > FE_NOTICE) && (*x > y))					\
-			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
-		else if ((*x > FE_INFO) && (*x > y))					\
-			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);		\
-		else if ((*x > FE_DEBUG) && (*x > y))					\
-			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
-	} else {									\
-		if (*x > y)								\
-			printk(format, ##arg);						\
-	}										\
-} while(0)
-
-#define INRANGE(val, x, y)			(((x <= val) && (val <= y)) ||		\
-						 ((y <= val) && (val <= x)) ? 1 : 0)
-
-#define BYTE0					0
-#define BYTE1					8
-#define BYTE2					16
-#define BYTE3					24
-
-#define GETBYTE(x, y)				(((x) >> (y)) & 0xff)
-#define MAKEWORD32(a, b, c, d)			(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
-#define MAKEWORD16(a, b)			(((a) << 8) | (b))
-
-#define LSB(x)					((x & 0xff))
-#define MSB(y)					((y >> 8) & 0xff)
-
-
-#define STB0899_GETFIELD(bitf, val)		((val >> STB0899_OFFST_##bitf) & ((1 << STB0899_WIDTH_##bitf) - 1))
-
-
-#define STB0899_SETFIELD(mask, val, width, offset)      (mask & (~(((1 << width) - 1) <<	\
-							 offset))) | ((val &			\
-							 ((1 << width) - 1)) << offset)
-
-#define STB0899_SETFIELD_VAL(bitf, mask, val)	(mask = (mask & (~(((1 << STB0899_WIDTH_##bitf) - 1) <<\
-							 STB0899_OFFST_##bitf))) | \
-							 (val << STB0899_OFFST_##bitf))
-
-
-enum stb0899_status {
-	NOAGC1	= 0,
-	AGC1OK,
-	NOTIMING,
-	ANALOGCARRIER,
-	TIMINGOK,
-	NOAGC2,
-	AGC2OK,
-	NOCARRIER,
-	CARRIEROK,
-	NODATA,
-	FALSELOCK,
-	DATAOK,
-	OUTOFRANGE,
-	RANGEOK,
-	DVBS2_DEMOD_LOCK,
-	DVBS2_DEMOD_NOLOCK,
-	DVBS2_FEC_LOCK,
-	DVBS2_FEC_NOLOCK
-};
-
-enum stb0899_modcod {
-	STB0899_DUMMY_PLF,
-	STB0899_QPSK_14,
-	STB0899_QPSK_13,
-	STB0899_QPSK_25,
-	STB0899_QPSK_12,
-	STB0899_QPSK_35,
-	STB0899_QPSK_23,
-	STB0899_QPSK_34,
-	STB0899_QPSK_45,
-	STB0899_QPSK_56,
-	STB0899_QPSK_89,
-	STB0899_QPSK_910,
-	STB0899_8PSK_35,
-	STB0899_8PSK_23,
-	STB0899_8PSK_34,
-	STB0899_8PSK_56,
-	STB0899_8PSK_89,
-	STB0899_8PSK_910,
-	STB0899_16APSK_23,
-	STB0899_16APSK_34,
-	STB0899_16APSK_45,
-	STB0899_16APSK_56,
-	STB0899_16APSK_89,
-	STB0899_16APSK_910,
-	STB0899_32APSK_34,
-	STB0899_32APSK_45,
-	STB0899_32APSK_56,
-	STB0899_32APSK_89,
-	STB0899_32APSK_910
-};
-
-enum stb0899_frame {
-	STB0899_LONG_FRAME,
-	STB0899_SHORT_FRAME
-};
-
-enum stb0899_alpha {
-	RRC_20,
-	RRC_25,
-	RRC_35
-};
-
-struct stb0899_tab {
-	s32 real;
-	s32 read;
-};
-
-enum stb0899_fec {
-	STB0899_FEC_1_2			= 13,
-	STB0899_FEC_2_3			= 18,
-	STB0899_FEC_3_4			= 21,
-	STB0899_FEC_5_6			= 24,
-	STB0899_FEC_6_7			= 25,
-	STB0899_FEC_7_8			= 26
-};
-
-struct stb0899_params {
-	u32	freq;					/* Frequency	*/
-	u32	srate;					/* Symbol rate	*/
-	enum fe_code_rate fecrate;
-};
-
-struct stb0899_internal {
-	u32			master_clk;
-	u32			freq;			/* Demod internal Frequency		*/
-	u32			srate;			/* Demod internal Symbol rate		*/
-	enum stb0899_fec	fecrate;		/* Demod internal FEC rate		*/
-	s32			srch_range;		/* Demod internal Search Range		*/
-	s32			sub_range;		/* Demod current sub range (Hz)		*/
-	s32			tuner_step;		/* Tuner step (Hz)			*/
-	s32			tuner_offst;		/* Relative offset to carrier (Hz)	*/
-	u32			tuner_bw;		/* Current bandwidth of the tuner (Hz)	*/
-
-	s32			mclk;			/* Masterclock Divider factor (binary)	*/
-	s32			rolloff;		/* Current RollOff of the filter (x100)	*/
-
-	s16			derot_freq;		/* Current derotator frequency (Hz)	*/
-	s16			derot_percent;
-
-	s16			direction;		/* Current derotator search direction	*/
-	s16			derot_step;		/* Derotator step (binary value)	*/
-	s16			t_derot;		/* Derotator time constant (ms)		*/
-	s16			t_data;			/* Data recovery time constant (ms)	*/
-	s16			sub_dir;		/* Direction of the next sub range	*/
-
-	s16			t_agc1;			/* Agc1 time constant (ms)		*/
-	s16			t_agc2;			/* Agc2 time constant (ms)		*/
-
-	u32			lock;			/* Demod internal lock state		*/
-	enum stb0899_status	status;			/* Demod internal status		*/
-
-	/* DVB-S2 */
-	s32			agc_gain;		/* RF AGC Gain				*/
-	s32			center_freq;		/* Nominal carrier frequency		*/
-	s32			av_frame_coarse;	/* Coarse carrier freq search frames	*/
-	s32			av_frame_fine;		/* Fine carrier freq search frames	*/
-
-	s16			step_size;		/* Carrier frequency search step size	*/
-
-	enum stb0899_alpha	rrc_alpha;
-	enum stb0899_inversion	inversion;
-	enum stb0899_modcod	modcod;
-	u8			pilots;			/* Pilots found				*/
-
-	enum stb0899_frame	frame_length;
-	u8			v_status;		/* VSTATUS				*/
-	u8			err_ctrl;		/* ERRCTRLn				*/
-};
-
-struct stb0899_state {
-	struct i2c_adapter		*i2c;
-	struct stb0899_config		*config;
-	struct dvb_frontend		frontend;
-
-	u32				*verbose;	/* Cached module verbosity level	*/
-
-	struct stb0899_internal		internal;	/* Device internal parameters		*/
-
-	/*	cached params from API	*/
-	enum fe_delivery_system		delsys;
-	struct stb0899_params		params;
-
-	u32				rx_freq;	/* DiSEqC 2.0 receiver freq		*/
-	struct mutex			search_lock;
-};
-/* stb0899.c		*/
-extern int stb0899_read_reg(struct stb0899_state *state,
-			    unsigned int reg);
-
-extern u32 _stb0899_read_s2reg(struct stb0899_state *state,
-			       u32 stb0899_i2cdev,
-			       u32 stb0899_base_addr,
-			       u16 stb0899_reg_offset);
-
-extern int stb0899_read_regs(struct stb0899_state *state,
-			     unsigned int reg, u8 *buf,
-			     u32 count);
-
-extern int stb0899_write_regs(struct stb0899_state *state,
-			      unsigned int reg, u8 *data,
-			      u32 count);
-
-extern int stb0899_write_reg(struct stb0899_state *state,
-			     unsigned int reg,
-			     u8 data);
-
-extern int stb0899_write_s2reg(struct stb0899_state *state,
-			       u32 stb0899_i2cdev,
-			       u32 stb0899_base_addr,
-			       u16 stb0899_reg_offset,
-			       u32 stb0899_data);
-
-extern int stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
-
-
-#define STB0899_READ_S2REG(DEVICE, REG) 	(_stb0899_read_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG))
-//#define STB0899_WRITE_S2REG(DEVICE, REG, DATA)	(_stb0899_write_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG, DATA))
-
-/* stb0899_algo.c	*/
-extern enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state);
-extern enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state);
-extern long stb0899_carr_width(struct stb0899_state *state);
-
-#endif //__STB0899_PRIV_H
diff --git a/drivers/media/dvb/frontends/stb0899_reg.h b/drivers/media/dvb/frontends/stb0899_reg.h
deleted file mode 100644
index ba1ed56..0000000
--- a/drivers/media/dvb/frontends/stb0899_reg.h
+++ /dev/null
@@ -1,2027 +0,0 @@
-/*
-	STB0899 Multistandard Frontend driver
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	Copyright (C) ST Microelectronics
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __STB0899_REG_H
-#define __STB0899_REG_H
-
-/*	S1	*/
-#define STB0899_DEV_ID				0xf000
-#define STB0899_CHIP_ID				(0x0f << 4)
-#define STB0899_OFFST_CHIP_ID			4
-#define STB0899_WIDTH_CHIP_ID			4
-#define STB0899_CHIP_REL			(0x0f << 0)
-#define STB0899_OFFST_CHIP_REL			0
-#define STB0899_WIDTH_CHIP_REL			4
-
-#define STB0899_DEMOD				0xf40e
-#define STB0899_MODECOEFF			(0x01 << 0)
-#define STB0899_OFFST_MODECOEFF			0
-#define STB0899_WIDTH_MODECOEFF			1
-
-#define STB0899_RCOMPC				0xf410
-#define STB0899_AGC1CN				0xf412
-#define STB0899_AGC1REF				0xf413
-#define STB0899_RTC				0xf417
-#define STB0899_TMGCFG				0xf418
-#define STB0899_AGC2REF				0xf419
-#define STB0899_TLSR				0xf41a
-
-#define STB0899_CFD				0xf41b
-#define STB0899_CFD_ON				(0x01 << 7)
-#define STB0899_OFFST_CFD_ON			7
-#define STB0899_WIDTH_CFD_ON			1
-
-#define STB0899_ACLC				0xf41c
-
-#define STB0899_BCLC				0xf41d
-#define STB0899_OFFST_ALGO			6
-#define STB0899_WIDTH_ALGO_QPSK2		2
-#define STB0899_ALGO_QPSK2			(2 << 6)
-#define STB0899_ALGO_QPSK1			(1 << 6)
-#define STB0899_ALGO_BPSK			(0 << 6)
-#define STB0899_OFFST_BETA			0
-#define STB0899_WIDTH_BETA			6
-
-#define STB0899_EQON				0xf41e
-#define STB0899_LDT				0xf41f
-#define STB0899_LDT2				0xf420
-#define STB0899_EQUALREF			0xf425
-#define STB0899_TMGRAMP				0xf426
-#define STB0899_TMGTHD				0xf427
-#define STB0899_IDCCOMP				0xf428
-#define STB0899_QDCCOMP				0xf429
-#define STB0899_POWERI				0xf42a
-#define STB0899_POWERQ				0xf42b
-#define STB0899_RCOMP				0xf42c
-
-#define STB0899_AGCIQIN				0xf42e
-#define STB0899_AGCIQVALUE			(0xff << 0)
-#define STB0899_OFFST_AGCIQVALUE		0
-#define STB0899_WIDTH_AGCIQVALUE		8
-
-#define STB0899_AGC2I1				0xf436
-#define STB0899_AGC2I2				0xf437
-
-#define STB0899_TLIR				0xf438
-#define STB0899_TLIR_TMG_LOCK_IND		(0xff << 0)
-#define STB0899_OFFST_TLIR_TMG_LOCK_IND		0
-#define STB0899_WIDTH_TLIR_TMG_LOCK_IND		8
-
-#define STB0899_RTF				0xf439
-#define STB0899_RTF_TIMING_LOOP_FREQ		(0xff << 0)
-#define STB0899_OFFST_RTF_TIMING_LOOP_FREQ	0
-#define STB0899_WIDTH_RTF_TIMING_LOOP_FREQ	8
-
-#define STB0899_DSTATUS				0xf43a
-#define STB0899_CARRIER_FOUND			(0x01 << 7)
-#define STB0899_OFFST_CARRIER_FOUND		7
-#define STB0899_WIDTH_CARRIER_FOUND		1
-#define STB0899_TMG_LOCK			(0x01 << 6)
-#define STB0899_OFFST_TMG_LOCK			6
-#define STB0899_WIDTH_TMG_LOCK			1
-#define STB0899_DEMOD_LOCK			(0x01 << 5)
-#define STB0899_OFFST_DEMOD_LOCK		5
-#define STB0899_WIDTH_DEMOD_LOCK		1
-#define STB0899_TMG_AUTO			(0x01 << 4)
-#define STB0899_OFFST_TMG_AUTO			4
-#define STB0899_WIDTH_TMG_AUTO			1
-#define STB0899_END_MAIN			(0x01 << 3)
-#define STB0899_OFFST_END_MAIN			3
-#define STB0899_WIDTH_END_MAIN			1
-
-#define STB0899_LDI				0xf43b
-#define STB0899_OFFST_LDI			0
-#define STB0899_WIDTH_LDI			8
-
-#define STB0899_CFRM				0xf43e
-#define STB0899_OFFST_CFRM			0
-#define STB0899_WIDTH_CFRM			8
-
-#define STB0899_CFRL				0xf43f
-#define STB0899_OFFST_CFRL			0
-#define STB0899_WIDTH_CFRL			8
-
-#define STB0899_NIRM				0xf440
-#define STB0899_OFFST_NIRM			0
-#define STB0899_WIDTH_NIRM			8
-
-#define STB0899_NIRL				0xf441
-#define STB0899_OFFST_NIRL			0
-#define STB0899_WIDTH_NIRL			8
-
-#define STB0899_ISYMB				0xf444
-#define STB0899_QSYMB				0xf445
-
-#define STB0899_SFRH				0xf446
-#define STB0899_OFFST_SFRH			0
-#define STB0899_WIDTH_SFRH			8
-
-#define STB0899_SFRM				0xf447
-#define STB0899_OFFST_SFRM			0
-#define STB0899_WIDTH_SFRM			8
-
-#define STB0899_SFRL				0xf448
-#define STB0899_OFFST_SFRL			4
-#define STB0899_WIDTH_SFRL			4
-
-#define STB0899_SFRUPH				0xf44c
-#define STB0899_SFRUPM				0xf44d
-#define STB0899_SFRUPL				0xf44e
-
-#define STB0899_EQUAI1				0xf4e0
-#define STB0899_EQUAQ1				0xf4e1
-#define STB0899_EQUAI2				0xf4e2
-#define STB0899_EQUAQ2				0xf4e3
-#define STB0899_EQUAI3				0xf4e4
-#define STB0899_EQUAQ3				0xf4e5
-#define STB0899_EQUAI4				0xf4e6
-#define STB0899_EQUAQ4				0xf4e7
-#define STB0899_EQUAI5				0xf4e8
-#define STB0899_EQUAQ5				0xf4e9
-
-#define STB0899_DSTATUS2			0xf50c
-#define STB0899_DS2_TMG_AUTOSRCH		(0x01 << 7)
-#define STB8999_OFFST_DS2_TMG_AUTOSRCH		7
-#define STB0899_WIDTH_DS2_TMG_AUTOSRCH		1
-#define STB0899_DS2_END_MAINLOOP		(0x01 << 6)
-#define STB0899_OFFST_DS2_END_MAINLOOP		6
-#define STB0899_WIDTH_DS2_END_MAINLOOP		1
-#define STB0899_DS2_CFSYNC			(0x01 << 5)
-#define STB0899_OFFST_DS2_CFSYNC		5
-#define STB0899_WIDTH_DS2_CFSYNC		1
-#define STB0899_DS2_TMGLOCK			(0x01 << 4)
-#define STB0899_OFFST_DS2_TMGLOCK		4
-#define STB0899_WIDTH_DS2_TMGLOCK		1
-#define STB0899_DS2_DEMODWAIT			(0x01 << 3)
-#define STB0899_OFFST_DS2_DEMODWAIT		3
-#define STB0899_WIDTH_DS2_DEMODWAIT		1
-#define STB0899_DS2_FECON			(0x01 << 1)
-#define STB0899_OFFST_DS2_FECON			1
-#define STB0899_WIDTH_DS2_FECON			1
-
-/*	S1 FEC	*/
-#define STB0899_VSTATUS				0xf50d
-#define STB0899_VSTATUS_VITERBI_ON		(0x01 << 7)
-#define STB0899_OFFST_VSTATUS_VITERBI_ON	7
-#define STB0899_WIDTH_VSTATUS_VITERBI_ON	1
-#define STB0899_VSTATUS_END_LOOPVIT		(0x01 << 6)
-#define STB0899_OFFST_VSTATUS_END_LOOPVIT	6
-#define STB0899_WIDTH_VSTATUS_END_LOOPVIT	1
-#define STB0899_VSTATUS_PRFVIT			(0x01 << 4)
-#define STB0899_OFFST_VSTATUS_PRFVIT		4
-#define STB0899_WIDTH_VSTATUS_PRFVIT		1
-#define STB0899_VSTATUS_LOCKEDVIT		(0x01 << 3)
-#define STB0899_OFFST_VSTATUS_LOCKEDVIT		3
-#define STB0899_WIDTH_VSTATUS_LOCKEDVIT		1
-
-#define STB0899_VERROR				0xf50f
-
-#define STB0899_IQSWAP				0xf523
-#define STB0899_SYM				(0x01 << 3)
-#define STB0899_OFFST_SYM			3
-#define STB0899_WIDTH_SYM			1
-
-#define STB0899_FECAUTO1			0xf530
-#define STB0899_DSSSRCH				(0x01 << 3)
-#define STB0899_OFFST_DSSSRCH			3
-#define STB0899_WIDTH_DSSSRCH			1
-#define STB0899_SYMSRCH				(0x01 << 2)
-#define STB0899_OFFST_SYMSRCH			2
-#define STB0899_WIDTH_SYMSRCH			1
-#define STB0899_QPSKSRCH			(0x01 << 1)
-#define STB0899_OFFST_QPSKSRCH			1
-#define STB0899_WIDTH_QPSKSRCH			1
-#define STB0899_BPSKSRCH			(0x01 << 0)
-#define STB0899_OFFST_BPSKSRCH			0
-#define STB0899_WIDTH_BPSKSRCH			1
-
-#define STB0899_FECM				0xf533
-#define STB0899_FECM_NOT_DVB			(0x01 << 7)
-#define STB0899_OFFST_FECM_NOT_DVB		7
-#define STB0899_WIDTH_FECM_NOT_DVB		1
-#define STB0899_FECM_RSVD1			(0x07 << 4)
-#define STB0899_OFFST_FECM_RSVD1		4
-#define STB0899_WIDTH_FECM_RSVD1		3
-#define STB0899_FECM_VITERBI_ON			(0x01 << 3)
-#define STB0899_OFFST_FECM_VITERBI_ON		3
-#define STB0899_WIDTH_FECM_VITERBI_ON		1
-#define STB0899_FECM_RSVD0			(0x01 << 2)
-#define STB0899_OFFST_FECM_RSVD0		2
-#define STB0899_WIDTH_FECM_RSVD0		1
-#define STB0899_FECM_SYNCDIS			(0x01 << 1)
-#define STB0899_OFFST_FECM_SYNCDIS		1
-#define STB0899_WIDTH_FECM_SYNCDIS		1
-#define STB0899_FECM_SYMI			(0x01 << 0)
-#define STB0899_OFFST_FECM_SYMI			0
-#define STB0899_WIDTH_FECM_SYMI			1
-
-#define STB0899_VTH12				0xf534
-#define STB0899_VTH23				0xf535
-#define STB0899_VTH34				0xf536
-#define STB0899_VTH56				0xf537
-#define STB0899_VTH67				0xf538
-#define STB0899_VTH78				0xf539
-
-#define STB0899_PRVIT				0xf53c
-#define STB0899_PR_7_8				(0x01 << 5)
-#define STB0899_OFFST_PR_7_8			5
-#define STB0899_WIDTH_PR_7_8			1
-#define STB0899_PR_6_7				(0x01 << 4)
-#define STB0899_OFFST_PR_6_7			4
-#define STB0899_WIDTH_PR_6_7			1
-#define STB0899_PR_5_6				(0x01 << 3)
-#define STB0899_OFFST_PR_5_6			3
-#define STB0899_WIDTH_PR_5_6			1
-#define STB0899_PR_3_4				(0x01 << 2)
-#define STB0899_OFFST_PR_3_4			2
-#define STB0899_WIDTH_PR_3_4			1
-#define STB0899_PR_2_3				(0x01 << 1)
-#define STB0899_OFFST_PR_2_3			1
-#define STB0899_WIDTH_PR_2_3			1
-#define STB0899_PR_1_2				(0x01 << 0)
-#define STB0899_OFFST_PR_1_2			0
-#define STB0899_WIDTH_PR_1_2			1
-
-#define STB0899_VITSYNC				0xf53d
-#define STB0899_AM				(0x01 << 7)
-#define STB0899_OFFST_AM			7
-#define STB0899_WIDTH_AM			1
-#define STB0899_FREEZE				(0x01 << 6)
-#define STB0899_OFFST_FREEZE			6
-#define STB0899_WIDTH_FREEZE			1
-#define STB0899_SN_65536			(0x03 << 4)
-#define STB0899_OFFST_SN_65536			4
-#define STB0899_WIDTH_SN_65536			2
-#define STB0899_SN_16384			(0x01 << 5)
-#define STB0899_OFFST_SN_16384			5
-#define STB0899_WIDTH_SN_16384			1
-#define STB0899_SN_4096				(0x01 << 4)
-#define STB0899_OFFST_SN_4096			4
-#define STB0899_WIDTH_SN_4096			1
-#define STB0899_SN_1024				(0x00 << 4)
-#define STB0899_OFFST_SN_1024			4
-#define STB0899_WIDTH_SN_1024			0
-#define STB0899_TO_128				(0x03 << 2)
-#define STB0899_OFFST_TO_128			2
-#define STB0899_WIDTH_TO_128			2
-#define STB0899_TO_64				(0x01 << 3)
-#define STB0899_OFFST_TO_64			3
-#define STB0899_WIDTH_TO_64			1
-#define STB0899_TO_32				(0x01 << 2)
-#define STB0899_OFFST_TO_32			2
-#define STB0899_WIDTH_TO_32			1
-#define STB0899_TO_16				(0x00 << 2)
-#define STB0899_OFFST_TO_16			2
-#define STB0899_WIDTH_TO_16			0
-#define STB0899_HYST_128			(0x03 << 1)
-#define STB0899_OFFST_HYST_128			1
-#define STB0899_WIDTH_HYST_128			2
-#define STB0899_HYST_64				(0x01 << 1)
-#define STB0899_OFFST_HYST_64			1
-#define STB0899_WIDTH_HYST_64			1
-#define STB0899_HYST_32				(0x01 << 0)
-#define STB0899_OFFST_HYST_32			0
-#define STB0899_WIDTH_HYST_32			1
-#define STB0899_HYST_16				(0x00 << 0)
-#define STB0899_OFFST_HYST_16			0
-#define STB0899_WIDTH_HYST_16			0
-
-#define STB0899_RSULC				0xf548
-#define STB0899_ULDIL_ON			(0x01 << 7)
-#define STB0899_OFFST_ULDIL_ON			7
-#define STB0899_WIDTH_ULDIL_ON			1
-#define STB0899_ULAUTO_ON			(0x01 << 6)
-#define STB0899_OFFST_ULAUTO_ON			6
-#define STB0899_WIDTH_ULAUTO_ON			1
-#define STB0899_ULRS_ON				(0x01 << 5)
-#define STB0899_OFFST_ULRS_ON			5
-#define STB0899_WIDTH_ULRS_ON			1
-#define STB0899_ULDESCRAM_ON			(0x01 << 4)
-#define STB0899_OFFST_ULDESCRAM_ON		4
-#define STB0899_WIDTH_ULDESCRAM_ON		1
-#define STB0899_UL_DISABLE			(0x01 << 2)
-#define STB0899_OFFST_UL_DISABLE		2
-#define STB0899_WIDTH_UL_DISABLE		1
-#define STB0899_NOFTHRESHOLD			(0x01 << 0)
-#define STB0899_OFFST_NOFTHRESHOLD		0
-#define STB0899_WIDTH_NOFTHRESHOLD		1
-
-#define STB0899_RSLLC				0xf54a
-#define STB0899_DEMAPVIT			0xf583
-#define STB0899_DEMAPVIT_RSVD			(0x01 << 7)
-#define STB0899_OFFST_DEMAPVIT_RSVD		7
-#define STB0899_WIDTH_DEMAPVIT_RSVD		1
-#define STB0899_DEMAPVIT_KDIVIDER		(0x7f << 0)
-#define STB0899_OFFST_DEMAPVIT_KDIVIDER		0
-#define STB0899_WIDTH_DEMAPVIT_KDIVIDER		7
-
-#define STB0899_PLPARM				0xf58c
-#define STB0899_VITMAPPING			(0x07 << 5)
-#define STB0899_OFFST_VITMAPPING		5
-#define STB0899_WIDTH_VITMAPPING		3
-#define STB0899_VITMAPPING_BPSK			(0x01 << 5)
-#define STB0899_OFFST_VITMAPPING_BPSK		5
-#define STB0899_WIDTH_VITMAPPING_BPSK		1
-#define STB0899_VITMAPPING_QPSK			(0x00 << 5)
-#define STB0899_OFFST_VITMAPPING_QPSK		5
-#define STB0899_WIDTH_VITMAPPING_QPSK		0
-#define STB0899_VITCURPUN			(0x1f << 0)
-#define STB0899_OFFST_VITCURPUN			0
-#define STB0899_WIDTH_VITCURPUN			5
-#define STB0899_VITCURPUN_1_2			(0x0d << 0)
-#define STB0899_VITCURPUN_2_3			(0x12 << 0)
-#define STB0899_VITCURPUN_3_4			(0x15 << 0)
-#define STB0899_VITCURPUN_5_6			(0x18 << 0)
-#define STB0899_VITCURPUN_6_7			(0x19 << 0)
-#define STB0899_VITCURPUN_7_8			(0x1a << 0)
-
-/*	S2 DEMOD	*/
-#define STB0899_OFF0_DMD_STATUS			0xf300
-#define STB0899_BASE_DMD_STATUS			0x00000000
-#define STB0899_IF_AGC_LOCK			(0x01 << 8)
-#define STB0899_OFFST_IF_AGC_LOCK		0
-#define STB0899_WIDTH_IF_AGC_LOCK		1
-
-#define STB0899_OFF0_CRL_FREQ			0xf304
-#define STB0899_BASE_CRL_FREQ			0x00000000
-#define STB0899_CARR_FREQ			(0x3fffffff << 0)
-#define STB0899_OFFST_CARR_FREQ			0
-#define STB0899_WIDTH_CARR_FREQ			30
-
-#define STB0899_OFF0_BTR_FREQ			0xf308
-#define STB0899_BASE_BTR_FREQ			0x00000000
-#define STB0899_BTR_FREQ			(0xfffffff << 0)
-#define STB0899_OFFST_BTR_FREQ			0
-#define STB0899_WIDTH_BTR_FREQ			28
-
-#define STB0899_OFF0_IF_AGC_GAIN		0xf30c
-#define STB0899_BASE_IF_AGC_GAIN		0x00000000
-#define STB0899_IF_AGC_GAIN			(0x3fff < 0)
-#define STB0899_OFFST_IF_AGC_GAIN		0
-#define STB0899_WIDTH_IF_AGC_GAIN		14
-
-#define STB0899_OFF0_BB_AGC_GAIN		0xf310
-#define STB0899_BASE_BB_AGC_GAIN		0x00000000
-#define STB0899_BB_AGC_GAIN			(0x3fff < 0)
-#define STB0899_OFFST_BB_AGC_GAIN		0
-#define STB0899_WIDTH_BB_AGC_GAIN		14
-
-#define STB0899_OFF0_DC_OFFSET			0xf314
-#define STB0899_BASE_DC_OFFSET			0x00000000
-#define STB0899_I				(0xff < 8)
-#define STB0899_OFFST_I				8
-#define STB0899_WIDTH_I				8
-#define STB0899_Q				(0xff < 0)
-#define STB0899_OFFST_Q				8
-#define STB0899_WIDTH_Q				8
-
-#define STB0899_OFF0_DMD_CNTRL			0xf31c
-#define STB0899_BASE_DMD_CNTRL			0x00000000
-#define STB0899_ADC0_PINS1IN			(0x01 << 6)
-#define STB0899_OFFST_ADC0_PINS1IN              6
-#define STB0899_WIDTH_ADC0_PINS1IN              1
-#define STB0899_IN2COMP1_OFFBIN0		(0x01 << 3)
-#define STB0899_OFFST_IN2COMP1_OFFBIN0          3
-#define STB0899_WIDTH_IN2COMP1_OFFBIN0          1
-#define STB0899_DC_COMP				(0x01 << 2)
-#define STB0899_OFFST_DC_COMP			2
-#define STB0899_WIDTH_DC_COMP			1
-#define STB0899_MODMODE				(0x03 << 0)
-#define STB0899_OFFST_MODMODE			0
-#define STB0899_WIDTH_MODMODE			2
-
-#define STB0899_OFF0_IF_AGC_CNTRL		0xf320
-#define STB0899_BASE_IF_AGC_CNTRL		0x00000000
-#define STB0899_IF_GAIN_INIT			(0x3fff << 13)
-#define STB0899_OFFST_IF_GAIN_INIT		13
-#define STB0899_WIDTH_IF_GAIN_INIT		14
-#define STB0899_IF_GAIN_SENSE			(0x01 << 12)
-#define STB0899_OFFST_IF_GAIN_SENSE		12
-#define STB0899_WIDTH_IF_GAIN_SENSE		1
-#define STB0899_IF_LOOP_GAIN			(0x0f << 8)
-#define STB0899_OFFST_IF_LOOP_GAIN		8
-#define STB0899_WIDTH_IF_LOOP_GAIN		4
-#define STB0899_IF_LD_GAIN_INIT			(0x01 << 7)
-#define STB0899_OFFST_IF_LD_GAIN_INIT		7
-#define STB0899_WIDTH_IF_LD_GAIN_INIT		1
-#define STB0899_IF_AGC_REF			(0x7f << 0)
-#define STB0899_OFFST_IF_AGC_REF		0
-#define STB0899_WIDTH_IF_AGC_REF		7
-
-#define STB0899_OFF0_BB_AGC_CNTRL		0xf324
-#define STB0899_BASE_BB_AGC_CNTRL		0x00000000
-#define STB0899_BB_GAIN_INIT			(0x3fff << 12)
-#define STB0899_OFFST_BB_GAIN_INIT		12
-#define STB0899_WIDTH_BB_GAIN_INIT		14
-#define STB0899_BB_LOOP_GAIN			(0x0f << 8)
-#define STB0899_OFFST_BB_LOOP_GAIN		8
-#define STB0899_WIDTH_BB_LOOP_GAIN		4
-#define STB0899_BB_LD_GAIN_INIT			(0x01 << 7)
-#define STB0899_OFFST_BB_LD_GAIN_INIT		7
-#define STB0899_WIDTH_BB_LD_GAIN_INIT		1
-#define STB0899_BB_AGC_REF			(0x7f << 0)
-#define STB0899_OFFST_BB_AGC_REF		0
-#define STB0899_WIDTH_BB_AGC_REF		7
-
-#define STB0899_OFF0_CRL_CNTRL			0xf328
-#define STB0899_BASE_CRL_CNTRL			0x00000000
-#define STB0899_CRL_LOCK_CLEAR			(0x01 << 5)
-#define STB0899_OFFST_CRL_LOCK_CLEAR		5
-#define STB0899_WIDTH_CRL_LOCK_CLEAR		1
-#define STB0899_CRL_SWPR_CLEAR			(0x01 << 4)
-#define STB0899_OFFST_CRL_SWPR_CLEAR		4
-#define STB0899_WIDTH_CRL_SWPR_CLEAR		1
-#define STB0899_CRL_SWP_ENA			(0x01 << 3)
-#define STB0899_OFFST_CRL_SWP_ENA		3
-#define STB0899_WIDTH_CRL_SWP_ENA		1
-#define STB0899_CRL_DET_SEL			(0x01 << 2)
-#define STB0899_OFFST_CRL_DET_SEL		2
-#define STB0899_WIDTH_CRL_DET_SEL		1
-#define STB0899_CRL_SENSE			(0x01 << 1)
-#define STB0899_OFFST_CRL_SENSE			1
-#define STB0899_WIDTH_CRL_SENSE			1
-#define STB0899_CRL_PHSERR_CLEAR		(0x01 << 0)
-#define STB0899_OFFST_CRL_PHSERR_CLEAR		0
-#define STB0899_WIDTH_CRL_PHSERR_CLEAR		1
-
-#define STB0899_OFF0_CRL_PHS_INIT		0xf32c
-#define STB0899_BASE_CRL_PHS_INIT		0x00000000
-#define STB0899_CRL_PHS_INIT_31			(0x1 << 30)
-#define STB0899_OFFST_CRL_PHS_INIT_31		30
-#define STB0899_WIDTH_CRL_PHS_INIT_31		1
-#define STB0899_CRL_LD_INIT_PHASE		(0x1 << 24)
-#define STB0899_OFFST_CRL_LD_INIT_PHASE		24
-#define STB0899_WIDTH_CRL_LD_INIT_PHASE		1
-#define STB0899_CRL_INIT_PHASE			(0xffffff << 0)
-#define STB0899_OFFST_CRL_INIT_PHASE		0
-#define STB0899_WIDTH_CRL_INIT_PHASE		24
-
-#define STB0899_OFF0_CRL_FREQ_INIT		0xf330
-#define STB0899_BASE_CRL_FREQ_INIT		0x00000000
-#define STB0899_CRL_FREQ_INIT_31		(0x1 << 30)
-#define STB0899_OFFST_CRL_FREQ_INIT_31		30
-#define STB0899_WIDTH_CRL_FREQ_INIT_31		1
-#define STB0899_CRL_LD_FREQ_INIT		(0x1 << 24)
-#define STB0899_OFFST_CRL_LD_FREQ_INIT		24
-#define STB0899_WIDTH_CRL_LD_FREQ_INIT		1
-#define STB0899_CRL_FREQ_INIT			(0xffffff << 0)
-#define STB0899_OFFST_CRL_FREQ_INIT		0
-#define STB0899_WIDTH_CRL_FREQ_INIT		24
-
-#define STB0899_OFF0_CRL_LOOP_GAIN		0xf334
-#define STB0899_BASE_CRL_LOOP_GAIN		0x00000000
-#define STB0899_KCRL2_RSHFT			(0xf << 16)
-#define STB0899_OFFST_KCRL2_RSHFT		16
-#define STB0899_WIDTH_KCRL2_RSHFT		4
-#define STB0899_KCRL1				(0xf << 12)
-#define STB0899_OFFST_KCRL1			12
-#define STB0899_WIDTH_KCRL1			4
-#define STB0899_KCRL1_RSHFT			(0xf << 8)
-#define STB0899_OFFST_KCRL1_RSHFT		8
-#define STB0899_WIDTH_KCRL1_RSHFT		4
-#define STB0899_KCRL0				(0xf << 4)
-#define STB0899_OFFST_KCRL0			4
-#define STB0899_WIDTH_KCRL0			4
-#define STB0899_KCRL0_RSHFT			(0xf << 0)
-#define STB0899_OFFST_KCRL0_RSHFT		0
-#define STB0899_WIDTH_KCRL0_RSHFT		4
-
-#define STB0899_OFF0_CRL_NOM_FREQ		0xf338
-#define STB0899_BASE_CRL_NOM_FREQ		0x00000000
-#define STB0899_CRL_NOM_FREQ			(0x3fffffff << 0)
-#define STB0899_OFFST_CRL_NOM_FREQ		0
-#define STB0899_WIDTH_CRL_NOM_FREQ		30
-
-#define STB0899_OFF0_CRL_SWP_RATE		0xf33c
-#define STB0899_BASE_CRL_SWP_RATE		0x00000000
-#define STB0899_CRL_SWP_RATE			(0x3fffffff << 0)
-#define STB0899_OFFST_CRL_SWP_RATE		0
-#define STB0899_WIDTH_CRL_SWP_RATE		30
-
-#define STB0899_OFF0_CRL_MAX_SWP		0xf340
-#define STB0899_BASE_CRL_MAX_SWP		0x00000000
-#define STB0899_CRL_MAX_SWP			(0x3fffffff << 0)
-#define STB0899_OFFST_CRL_MAX_SWP		0
-#define STB0899_WIDTH_CRL_MAX_SWP		30
-
-#define STB0899_OFF0_CRL_LK_CNTRL		0xf344
-#define STB0899_BASE_CRL_LK_CNTRL		0x00000000
-
-#define STB0899_OFF0_DECIM_CNTRL		0xf348
-#define STB0899_BASE_DECIM_CNTRL		0x00000000
-#define STB0899_BAND_LIMIT_B			(0x01 << 5)
-#define STB0899_OFFST_BAND_LIMIT_B		5
-#define STB0899_WIDTH_BAND_LIMIT_B		1
-#define STB0899_WIN_SEL				(0x03 << 3)
-#define STB0899_OFFST_WIN_SEL			3
-#define STB0899_WIDTH_WIN_SEL			2
-#define STB0899_DECIM_RATE			(0x07 << 0)
-#define STB0899_OFFST_DECIM_RATE		0
-#define STB0899_WIDTH_DECIM_RATE		3
-
-#define STB0899_OFF0_BTR_CNTRL			0xf34c
-#define STB0899_BASE_BTR_CNTRL			0x00000000
-#define STB0899_BTR_FREQ_CORR			(0x7ff << 4)
-#define STB0899_OFFST_BTR_FREQ_CORR		4
-#define STB0899_WIDTH_BTR_FREQ_CORR		11
-#define STB0899_BTR_CLR_LOCK			(0x01 << 3)
-#define STB0899_OFFST_BTR_CLR_LOCK		3
-#define STB0899_WIDTH_BTR_CLR_LOCK		1
-#define STB0899_BTR_SENSE			(0x01 << 2)
-#define STB0899_OFFST_BTR_SENSE			2
-#define STB0899_WIDTH_BTR_SENSE			1
-#define STB0899_BTR_ERR_ENA			(0x01 << 1)
-#define STB0899_OFFST_BTR_ERR_ENA		1
-#define STB0899_WIDTH_BTR_ERR_ENA		1
-#define STB0899_INTRP_PHS_SENSE			(0x01 << 0)
-#define STB0899_OFFST_INTRP_PHS_SENSE		0
-#define STB0899_WIDTH_INTRP_PHS_SENSE		1
-
-#define STB0899_OFF0_BTR_LOOP_GAIN		0xf350
-#define STB0899_BASE_BTR_LOOP_GAIN		0x00000000
-#define STB0899_KBTR2_RSHFT			(0x0f << 16)
-#define STB0899_OFFST_KBTR2_RSHFT		16
-#define STB0899_WIDTH_KBTR2_RSHFT		4
-#define STB0899_KBTR1				(0x0f << 12)
-#define STB0899_OFFST_KBTR1			12
-#define STB0899_WIDTH_KBTR1			4
-#define STB0899_KBTR1_RSHFT			(0x0f << 8)
-#define STB0899_OFFST_KBTR1_RSHFT		8
-#define STB0899_WIDTH_KBTR1_RSHFT		4
-#define STB0899_KBTR0				(0x0f << 4)
-#define STB0899_OFFST_KBTR0			4
-#define STB0899_WIDTH_KBTR0			4
-#define STB0899_KBTR0_RSHFT			(0x0f << 0)
-#define STB0899_OFFST_KBTR0_RSHFT		0
-#define STB0899_WIDTH_KBTR0_RSHFT		4
-
-#define STB0899_OFF0_BTR_PHS_INIT		0xf354
-#define STB0899_BASE_BTR_PHS_INIT		0x00000000
-#define STB0899_BTR_LD_PHASE_INIT		(0x01 << 28)
-#define STB0899_OFFST_BTR_LD_PHASE_INIT		28
-#define STB0899_WIDTH_BTR_LD_PHASE_INIT		1
-#define STB0899_BTR_INIT_PHASE			(0xfffffff << 0)
-#define STB0899_OFFST_BTR_INIT_PHASE		0
-#define STB0899_WIDTH_BTR_INIT_PHASE		28
-
-#define STB0899_OFF0_BTR_FREQ_INIT		0xf358
-#define STB0899_BASE_BTR_FREQ_INIT		0x00000000
-#define STB0899_BTR_LD_FREQ_INIT		(1 << 28)
-#define STB0899_OFFST_BTR_LD_FREQ_INIT		28
-#define STB0899_WIDTH_BTR_LD_FREQ_INIT		1
-#define STB0899_BTR_FREQ_INIT			(0xfffffff << 0)
-#define STB0899_OFFST_BTR_FREQ_INIT		0
-#define STB0899_WIDTH_BTR_FREQ_INIT		28
-
-#define STB0899_OFF0_BTR_NOM_FREQ		0xf35c
-#define STB0899_BASE_BTR_NOM_FREQ		0x00000000
-#define STB0899_BTR_NOM_FREQ			(0xfffffff << 0)
-#define STB0899_OFFST_BTR_NOM_FREQ		0
-#define STB0899_WIDTH_BTR_NOM_FREQ		28
-
-#define STB0899_OFF0_BTR_LK_CNTRL		0xf360
-#define STB0899_BASE_BTR_LK_CNTRL		0x00000000
-#define STB0899_BTR_MIN_ENERGY			(0x0f << 24)
-#define STB0899_OFFST_BTR_MIN_ENERGY		24
-#define STB0899_WIDTH_BTR_MIN_ENERGY		4
-#define STB0899_BTR_LOCK_TH_LO			(0xff << 16)
-#define STB0899_OFFST_BTR_LOCK_TH_LO		16
-#define STB0899_WIDTH_BTR_LOCK_TH_LO		8
-#define STB0899_BTR_LOCK_TH_HI			(0xff << 8)
-#define STB0899_OFFST_BTR_LOCK_TH_HI		8
-#define STB0899_WIDTH_BTR_LOCK_TH_HI		8
-#define STB0899_BTR_LOCK_GAIN			(0x03 << 6)
-#define STB0899_OFFST_BTR_LOCK_GAIN		6
-#define STB0899_WIDTH_BTR_LOCK_GAIN		2
-#define STB0899_BTR_LOCK_LEAK			(0x3f << 0)
-#define STB0899_OFFST_BTR_LOCK_LEAK		0
-#define STB0899_WIDTH_BTR_LOCK_LEAK		6
-
-#define STB0899_OFF0_DECN_CNTRL			0xf364
-#define STB0899_BASE_DECN_CNTRL			0x00000000
-
-#define STB0899_OFF0_TP_CNTRL			0xf368
-#define STB0899_BASE_TP_CNTRL			0x00000000
-
-#define STB0899_OFF0_TP_BUF_STATUS		0xf36c
-#define STB0899_BASE_TP_BUF_STATUS		0x00000000
-#define STB0899_TP_BUFFER_FULL                  (1 << 0)
-
-#define STB0899_OFF0_DC_ESTIM			0xf37c
-#define STB0899_BASE_DC_ESTIM			0x0000
-#define STB0899_I_DC_ESTIMATE			(0xff << 8)
-#define STB0899_OFFST_I_DC_ESTIMATE		8
-#define STB0899_WIDTH_I_DC_ESTIMATE		8
-#define STB0899_Q_DC_ESTIMATE			(0xff << 0)
-#define STB0899_OFFST_Q_DC_ESTIMATE		0
-#define STB0899_WIDTH_Q_DC_ESTIMATE		8
-
-#define STB0899_OFF0_FLL_CNTRL			0xf310
-#define STB0899_BASE_FLL_CNTRL			0x00000020
-#define STB0899_CRL_FLL_ACC			(0x01 << 4)
-#define STB0899_OFFST_CRL_FLL_ACC		4
-#define STB0899_WIDTH_CRL_FLL_ACC		1
-#define STB0899_FLL_AVG_PERIOD			(0x0f << 0)
-#define STB0899_OFFST_FLL_AVG_PERIOD		0
-#define STB0899_WIDTH_FLL_AVG_PERIOD		4
-
-#define STB0899_OFF0_FLL_FREQ_WD		0xf314
-#define STB0899_BASE_FLL_FREQ_WD		0x00000020
-#define STB0899_FLL_FREQ_WD			(0xffffffff << 0)
-#define STB0899_OFFST_FLL_FREQ_WD		0
-#define STB0899_WIDTH_FLL_FREQ_WD		32
-
-#define STB0899_OFF0_ANTI_ALIAS_SEL		0xf358
-#define STB0899_BASE_ANTI_ALIAS_SEL		0x00000020
-#define STB0899_ANTI_ALIAS_SELB			(0x03 << 0)
-#define STB0899_OFFST_ANTI_ALIAS_SELB		0
-#define STB0899_WIDTH_ANTI_ALIAS_SELB		2
-
-#define STB0899_OFF0_RRC_ALPHA			0xf35c
-#define STB0899_BASE_RRC_ALPHA			0x00000020
-#define STB0899_RRC_ALPHA			(0x03 << 0)
-#define STB0899_OFFST_RRC_ALPHA			0
-#define STB0899_WIDTH_RRC_ALPHA			2
-
-#define STB0899_OFF0_DC_ADAPT_LSHFT		0xf360
-#define STB0899_BASE_DC_ADAPT_LSHFT		0x00000020
-#define STB0899_DC_ADAPT_LSHFT			(0x077 << 0)
-#define STB0899_OFFST_DC_ADAPT_LSHFT		0
-#define STB0899_WIDTH_DC_ADAPT_LSHFT		3
-
-#define STB0899_OFF0_IMB_OFFSET			0xf364
-#define STB0899_BASE_IMB_OFFSET			0x00000020
-#define STB0899_PHS_IMB_COMP			(0xff << 8)
-#define STB0899_OFFST_PHS_IMB_COMP		8
-#define STB0899_WIDTH_PHS_IMB_COMP		8
-#define STB0899_AMPL_IMB_COMP			(0xff << 0)
-#define STB0899_OFFST_AMPL_IMB_COMP		0
-#define STB0899_WIDTH_AMPL_IMB_COMP		8
-
-#define STB0899_OFF0_IMB_ESTIMATE		0xf368
-#define STB0899_BASE_IMB_ESTIMATE		0x00000020
-#define STB0899_PHS_IMB_ESTIMATE		(0xff << 8)
-#define STB0899_OFFST_PHS_IMB_ESTIMATE		8
-#define STB0899_WIDTH_PHS_IMB_ESTIMATE		8
-#define STB0899_AMPL_IMB_ESTIMATE		(0xff << 0)
-#define STB0899_OFFST_AMPL_IMB_ESTIMATE		0
-#define STB0899_WIDTH_AMPL_IMB_ESTIMATE		8
-
-#define STB0899_OFF0_IMB_CNTRL			0xf36c
-#define STB0899_BASE_IMB_CNTRL			0x00000020
-#define STB0899_PHS_ADAPT_LSHFT			(0x07 << 4)
-#define STB0899_OFFST_PHS_ADAPT_LSHFT		4
-#define STB0899_WIDTH_PHS_ADAPT_LSHFT		3
-#define STB0899_AMPL_ADAPT_LSHFT		(0x07 << 1)
-#define STB0899_OFFST_AMPL_ADAPT_LSHFT		1
-#define STB0899_WIDTH_AMPL_ADAPT_LSHFT		3
-#define STB0899_IMB_COMP			(0x01 << 0)
-#define STB0899_OFFST_IMB_COMP			0
-#define STB0899_WIDTH_IMB_COMP			1
-
-#define STB0899_OFF0_IF_AGC_CNTRL2		0xf374
-#define STB0899_BASE_IF_AGC_CNTRL2		0x00000020
-#define STB0899_IF_AGC_LOCK_TH			(0xff << 11)
-#define STB0899_OFFST_IF_AGC_LOCK_TH		11
-#define STB0899_WIDTH_IF_AGC_LOCK_TH		8
-#define STB0899_IF_AGC_SD_DIV			(0xff << 3)
-#define STB0899_OFFST_IF_AGC_SD_DIV		3
-#define STB0899_WIDTH_IF_AGC_SD_DIV		8
-#define STB0899_IF_AGC_DUMP_PER			(0x07 << 0)
-#define STB0899_OFFST_IF_AGC_DUMP_PER		0
-#define STB0899_WIDTH_IF_AGC_DUMP_PER		3
-
-#define STB0899_OFF0_DMD_CNTRL2			0xf378
-#define STB0899_BASE_DMD_CNTRL2			0x00000020
-#define STB0899_SPECTRUM_INVERT			(0x01 << 2)
-#define STB0899_OFFST_SPECTRUM_INVERT		2
-#define STB0899_WIDTH_SPECTRUM_INVERT		1
-#define STB0899_AGC_MODE			(0x01 << 1)
-#define STB0899_OFFST_AGC_MODE			1
-#define STB0899_WIDTH_AGC_MODE			1
-#define STB0899_CRL_FREQ_ADJ			(0x01 << 0)
-#define STB0899_OFFST_CRL_FREQ_ADJ		0
-#define STB0899_WIDTH_CRL_FREQ_ADJ		1
-
-#define STB0899_OFF0_TP_BUFFER			0xf300
-#define STB0899_BASE_TP_BUFFER			0x00000040
-#define STB0899_TP_BUFFER_IN			(0xffff << 0)
-#define STB0899_OFFST_TP_BUFFER_IN		0
-#define STB0899_WIDTH_TP_BUFFER_IN		16
-
-#define STB0899_OFF0_TP_BUFFER1			0xf304
-#define STB0899_BASE_TP_BUFFER1			0x00000040
-#define STB0899_OFF0_TP_BUFFER2			0xf308
-#define STB0899_BASE_TP_BUFFER2			0x00000040
-#define STB0899_OFF0_TP_BUFFER3			0xf30c
-#define STB0899_BASE_TP_BUFFER3			0x00000040
-#define STB0899_OFF0_TP_BUFFER4			0xf310
-#define STB0899_BASE_TP_BUFFER4			0x00000040
-#define STB0899_OFF0_TP_BUFFER5			0xf314
-#define STB0899_BASE_TP_BUFFER5			0x00000040
-#define STB0899_OFF0_TP_BUFFER6			0xf318
-#define STB0899_BASE_TP_BUFFER6			0x00000040
-#define STB0899_OFF0_TP_BUFFER7			0xf31c
-#define STB0899_BASE_TP_BUFFER7			0x00000040
-#define STB0899_OFF0_TP_BUFFER8			0xf320
-#define STB0899_BASE_TP_BUFFER8			0x00000040
-#define STB0899_OFF0_TP_BUFFER9			0xf324
-#define STB0899_BASE_TP_BUFFER9			0x00000040
-#define STB0899_OFF0_TP_BUFFER10		0xf328
-#define STB0899_BASE_TP_BUFFER10		0x00000040
-#define STB0899_OFF0_TP_BUFFER11		0xf32c
-#define STB0899_BASE_TP_BUFFER11		0x00000040
-#define STB0899_OFF0_TP_BUFFER12		0xf330
-#define STB0899_BASE_TP_BUFFER12		0x00000040
-#define STB0899_OFF0_TP_BUFFER13		0xf334
-#define STB0899_BASE_TP_BUFFER13		0x00000040
-#define STB0899_OFF0_TP_BUFFER14		0xf338
-#define STB0899_BASE_TP_BUFFER14		0x00000040
-#define STB0899_OFF0_TP_BUFFER15		0xf33c
-#define STB0899_BASE_TP_BUFFER15		0x00000040
-#define STB0899_OFF0_TP_BUFFER16		0xf340
-#define STB0899_BASE_TP_BUFFER16		0x00000040
-#define STB0899_OFF0_TP_BUFFER17		0xf344
-#define STB0899_BASE_TP_BUFFER17		0x00000040
-#define STB0899_OFF0_TP_BUFFER18		0xf348
-#define STB0899_BASE_TP_BUFFER18		0x00000040
-#define STB0899_OFF0_TP_BUFFER19		0xf34c
-#define STB0899_BASE_TP_BUFFER19		0x00000040
-#define STB0899_OFF0_TP_BUFFER20		0xf350
-#define STB0899_BASE_TP_BUFFER20		0x00000040
-#define STB0899_OFF0_TP_BUFFER21		0xf354
-#define STB0899_BASE_TP_BUFFER21		0x00000040
-#define STB0899_OFF0_TP_BUFFER22		0xf358
-#define STB0899_BASE_TP_BUFFER22		0x00000040
-#define STB0899_OFF0_TP_BUFFER23		0xf35c
-#define STB0899_BASE_TP_BUFFER23		0x00000040
-#define STB0899_OFF0_TP_BUFFER24		0xf360
-#define STB0899_BASE_TP_BUFFER24		0x00000040
-#define STB0899_OFF0_TP_BUFFER25		0xf364
-#define STB0899_BASE_TP_BUFFER25		0x00000040
-#define STB0899_OFF0_TP_BUFFER26		0xf368
-#define STB0899_BASE_TP_BUFFER26		0x00000040
-#define STB0899_OFF0_TP_BUFFER27		0xf36c
-#define STB0899_BASE_TP_BUFFER27		0x00000040
-#define STB0899_OFF0_TP_BUFFER28		0xf370
-#define STB0899_BASE_TP_BUFFER28		0x00000040
-#define STB0899_OFF0_TP_BUFFER29		0xf374
-#define STB0899_BASE_TP_BUFFER29		0x00000040
-#define STB0899_OFF0_TP_BUFFER30		0xf378
-#define STB0899_BASE_TP_BUFFER30		0x00000040
-#define STB0899_OFF0_TP_BUFFER31		0xf37c
-#define STB0899_BASE_TP_BUFFER31		0x00000040
-#define STB0899_OFF0_TP_BUFFER32		0xf300
-#define STB0899_BASE_TP_BUFFER32		0x00000060
-#define STB0899_OFF0_TP_BUFFER33		0xf304
-#define STB0899_BASE_TP_BUFFER33		0x00000060
-#define STB0899_OFF0_TP_BUFFER34		0xf308
-#define STB0899_BASE_TP_BUFFER34		0x00000060
-#define STB0899_OFF0_TP_BUFFER35		0xf30c
-#define STB0899_BASE_TP_BUFFER35		0x00000060
-#define STB0899_OFF0_TP_BUFFER36		0xf310
-#define STB0899_BASE_TP_BUFFER36		0x00000060
-#define STB0899_OFF0_TP_BUFFER37		0xf314
-#define STB0899_BASE_TP_BUFFER37		0x00000060
-#define STB0899_OFF0_TP_BUFFER38		0xf318
-#define STB0899_BASE_TP_BUFFER38		0x00000060
-#define STB0899_OFF0_TP_BUFFER39		0xf31c
-#define STB0899_BASE_TP_BUFFER39		0x00000060
-#define STB0899_OFF0_TP_BUFFER40		0xf320
-#define STB0899_BASE_TP_BUFFER40		0x00000060
-#define STB0899_OFF0_TP_BUFFER41		0xf324
-#define STB0899_BASE_TP_BUFFER41		0x00000060
-#define STB0899_OFF0_TP_BUFFER42		0xf328
-#define STB0899_BASE_TP_BUFFER42		0x00000060
-#define STB0899_OFF0_TP_BUFFER43		0xf32c
-#define STB0899_BASE_TP_BUFFER43		0x00000060
-#define STB0899_OFF0_TP_BUFFER44		0xf330
-#define STB0899_BASE_TP_BUFFER44		0x00000060
-#define STB0899_OFF0_TP_BUFFER45		0xf334
-#define STB0899_BASE_TP_BUFFER45		0x00000060
-#define STB0899_OFF0_TP_BUFFER46		0xf338
-#define STB0899_BASE_TP_BUFFER46		0x00000060
-#define STB0899_OFF0_TP_BUFFER47		0xf33c
-#define STB0899_BASE_TP_BUFFER47		0x00000060
-#define STB0899_OFF0_TP_BUFFER48		0xf340
-#define STB0899_BASE_TP_BUFFER48		0x00000060
-#define STB0899_OFF0_TP_BUFFER49		0xf344
-#define STB0899_BASE_TP_BUFFER49		0x00000060
-#define STB0899_OFF0_TP_BUFFER50		0xf348
-#define STB0899_BASE_TP_BUFFER50		0x00000060
-#define STB0899_OFF0_TP_BUFFER51		0xf34c
-#define STB0899_BASE_TP_BUFFER51		0x00000060
-#define STB0899_OFF0_TP_BUFFER52		0xf350
-#define STB0899_BASE_TP_BUFFER52		0x00000060
-#define STB0899_OFF0_TP_BUFFER53		0xf354
-#define STB0899_BASE_TP_BUFFER53		0x00000060
-#define STB0899_OFF0_TP_BUFFER54		0xf358
-#define STB0899_BASE_TP_BUFFER54		0x00000060
-#define STB0899_OFF0_TP_BUFFER55		0xf35c
-#define STB0899_BASE_TP_BUFFER55		0x00000060
-#define STB0899_OFF0_TP_BUFFER56		0xf360
-#define STB0899_BASE_TP_BUFFER56		0x00000060
-#define STB0899_OFF0_TP_BUFFER57		0xf364
-#define STB0899_BASE_TP_BUFFER57		0x00000060
-#define STB0899_OFF0_TP_BUFFER58		0xf368
-#define STB0899_BASE_TP_BUFFER58		0x00000060
-#define STB0899_OFF0_TP_BUFFER59		0xf36c
-#define STB0899_BASE_TP_BUFFER59		0x00000060
-#define STB0899_OFF0_TP_BUFFER60		0xf370
-#define STB0899_BASE_TP_BUFFER60		0x00000060
-#define STB0899_OFF0_TP_BUFFER61		0xf374
-#define STB0899_BASE_TP_BUFFER61		0x00000060
-#define STB0899_OFF0_TP_BUFFER62		0xf378
-#define STB0899_BASE_TP_BUFFER62		0x00000060
-#define STB0899_OFF0_TP_BUFFER63		0xf37c
-#define STB0899_BASE_TP_BUFFER63		0x00000060
-
-#define STB0899_OFF0_RESET_CNTRL		0xf300
-#define STB0899_BASE_RESET_CNTRL		0x00000400
-#define STB0899_DVBS2_RESET			(0x01 << 0)
-#define STB0899_OFFST_DVBS2_RESET		0
-#define STB0899_WIDTH_DVBS2_RESET		1
-
-#define STB0899_OFF0_ACM_ENABLE			0xf304
-#define STB0899_BASE_ACM_ENABLE			0x00000400
-#define STB0899_ACM_ENABLE			1
-
-#define STB0899_OFF0_DESCR_CNTRL		0xf30c
-#define STB0899_BASE_DESCR_CNTRL		0x00000400
-#define STB0899_OFFST_DESCR_CNTRL               0
-#define STB0899_WIDTH_DESCR_CNTRL               16
-
-#define STB0899_OFF0_UWP_CNTRL1			0xf320
-#define STB0899_BASE_UWP_CNTRL1			0x00000400
-#define STB0899_UWP_TH_SOF			(0x7fff << 11)
-#define STB0899_OFFST_UWP_TH_SOF		11
-#define STB0899_WIDTH_UWP_TH_SOF		15
-#define STB0899_UWP_ESN0_QUANT			(0xff << 3)
-#define STB0899_OFFST_UWP_ESN0_QUANT		3
-#define STB0899_WIDTH_UWP_ESN0_QUANT		8
-#define STB0899_UWP_ESN0_AVE			(0x03 << 1)
-#define STB0899_OFFST_UWP_ESN0_AVE		1
-#define STB0899_WIDTH_UWP_ESN0_AVE		2
-#define STB0899_UWP_START			(0x01 << 0)
-#define STB0899_OFFST_UWP_START			0
-#define STB0899_WIDTH_UWP_START			1
-
-#define STB0899_OFF0_UWP_CNTRL2			0xf324
-#define STB0899_BASE_UWP_CNTRL2			0x00000400
-#define STB0899_UWP_MISS_TH			(0xff << 16)
-#define STB0899_OFFST_UWP_MISS_TH		16
-#define STB0899_WIDTH_UWP_MISS_TH		8
-#define STB0899_FE_FINE_TRK			(0xff << 8)
-#define STB0899_OFFST_FE_FINE_TRK		8
-#define STB0899_WIDTH_FE_FINE_TRK		8
-#define STB0899_FE_COARSE_TRK			(0xff << 0)
-#define STB0899_OFFST_FE_COARSE_TRK		0
-#define STB0899_WIDTH_FE_COARSE_TRK		8
-
-#define STB0899_OFF0_UWP_STAT1			0xf328
-#define STB0899_BASE_UWP_STAT1			0x00000400
-#define STB0899_UWP_STATE			(0x03ff << 15)
-#define STB0899_OFFST_UWP_STATE			15
-#define STB0899_WIDTH_UWP_STATE			10
-#define STB0899_UW_MAX_PEAK			(0x7fff << 0)
-#define STB0899_OFFST_UW_MAX_PEAK		0
-#define STB0899_WIDTH_UW_MAX_PEAK		15
-
-#define STB0899_OFF0_UWP_STAT2			0xf32c
-#define STB0899_BASE_UWP_STAT2			0x00000400
-#define STB0899_ESNO_EST			(0x07ffff << 7)
-#define STB0899_OFFST_ESN0_EST			7
-#define STB0899_WIDTH_ESN0_EST			19
-#define STB0899_UWP_DECODE_MOD			(0x7f << 0)
-#define STB0899_OFFST_UWP_DECODE_MOD		0
-#define STB0899_WIDTH_UWP_DECODE_MOD		7
-
-#define STB0899_OFF0_DMD_CORE_ID		0xf334
-#define STB0899_BASE_DMD_CORE_ID		0x00000400
-#define STB0899_CORE_ID				(0xffffffff << 0)
-#define STB0899_OFFST_CORE_ID			0
-#define STB0899_WIDTH_CORE_ID			32
-
-#define STB0899_OFF0_DMD_VERSION_ID		0xf33c
-#define STB0899_BASE_DMD_VERSION_ID		0x00000400
-#define STB0899_VERSION_ID			(0xff << 0)
-#define STB0899_OFFST_VERSION_ID		0
-#define STB0899_WIDTH_VERSION_ID		8
-
-#define STB0899_OFF0_DMD_STAT2			0xf340
-#define STB0899_BASE_DMD_STAT2			0x00000400
-#define STB0899_CSM_LOCK			(0x01 << 1)
-#define STB0899_OFFST_CSM_LOCK			1
-#define STB0899_WIDTH_CSM_LOCK			1
-#define STB0899_UWP_LOCK			(0x01 << 0)
-#define STB0899_OFFST_UWP_LOCK			0
-#define STB0899_WIDTH_UWP_LOCK			1
-
-#define STB0899_OFF0_FREQ_ADJ_SCALE		0xf344
-#define STB0899_BASE_FREQ_ADJ_SCALE		0x00000400
-#define STB0899_FREQ_ADJ_SCALE			(0x0fff << 0)
-#define STB0899_OFFST_FREQ_ADJ_SCALE		0
-#define STB0899_WIDTH_FREQ_ADJ_SCALE		12
-
-#define STB0899_OFF0_UWP_CNTRL3			0xf34c
-#define STB0899_BASE_UWP_CNTRL3			0x00000400
-#define STB0899_UWP_TH_TRACK			(0x7fff << 15)
-#define STB0899_OFFST_UWP_TH_TRACK		15
-#define STB0899_WIDTH_UWP_TH_TRACK		15
-#define STB0899_UWP_TH_ACQ			(0x7fff << 0)
-#define STB0899_OFFST_UWP_TH_ACQ		0
-#define STB0899_WIDTH_UWP_TH_ACQ		15
-
-#define STB0899_OFF0_SYM_CLK_SEL		0xf350
-#define STB0899_BASE_SYM_CLK_SEL		0x00000400
-#define STB0899_SYM_CLK_SEL			(0x03 << 0)
-#define STB0899_OFFST_SYM_CLK_SEL		0
-#define STB0899_WIDTH_SYM_CLK_SEL		2
-
-#define STB0899_OFF0_SOF_SRCH_TO		0xf354
-#define STB0899_BASE_SOF_SRCH_TO		0x00000400
-#define STB0899_SOF_SEARCH_TIMEOUT		(0x3fffff << 0)
-#define STB0899_OFFST_SOF_SEARCH_TIMEOUT	0
-#define STB0899_WIDTH_SOF_SEARCH_TIMEOUT	22
-
-#define STB0899_OFF0_ACQ_CNTRL1			0xf358
-#define STB0899_BASE_ACQ_CNTRL1			0x00000400
-#define STB0899_FE_FINE_ACQ			(0xff << 8)
-#define STB0899_OFFST_FE_FINE_ACQ		8
-#define STB0899_WIDTH_FE_FINE_ACQ		8
-#define STB0899_FE_COARSE_ACQ			(0xff << 0)
-#define STB0899_OFFST_FE_COARSE_ACQ		0
-#define STB0899_WIDTH_FE_COARSE_ACQ		8
-
-#define STB0899_OFF0_ACQ_CNTRL2			0xf35c
-#define STB0899_BASE_ACQ_CNTRL2			0x00000400
-#define STB0899_ZIGZAG				(0x01 << 25)
-#define STB0899_OFFST_ZIGZAG			25
-#define STB0899_WIDTH_ZIGZAG			1
-#define STB0899_NUM_STEPS			(0xff << 17)
-#define STB0899_OFFST_NUM_STEPS			17
-#define STB0899_WIDTH_NUM_STEPS			8
-#define STB0899_FREQ_STEPSIZE			(0x1ffff << 0)
-#define STB0899_OFFST_FREQ_STEPSIZE		0
-#define STB0899_WIDTH_FREQ_STEPSIZE		17
-
-#define STB0899_OFF0_ACQ_CNTRL3			0xf360
-#define STB0899_BASE_ACQ_CNTRL3			0x00000400
-#define STB0899_THRESHOLD_SCL			(0x3f << 23)
-#define STB0899_OFFST_THRESHOLD_SCL		23
-#define STB0899_WIDTH_THRESHOLD_SCL		6
-#define STB0899_UWP_TH_SRCH			(0x7fff << 8)
-#define STB0899_OFFST_UWP_TH_SRCH		8
-#define STB0899_WIDTH_UWP_TH_SRCH		15
-#define STB0899_AUTO_REACQUIRE			(0x01 << 7)
-#define STB0899_OFFST_AUTO_REACQUIRE		7
-#define STB0899_WIDTH_AUTO_REACQUIRE		1
-#define STB0899_TRACK_LOCK_SEL			(0x01 << 6)
-#define STB0899_OFFST_TRACK_LOCK_SEL		6
-#define STB0899_WIDTH_TRACK_LOCK_SEL		1
-#define STB0899_ACQ_SEARCH_MODE			(0x03 << 4)
-#define STB0899_OFFST_ACQ_SEARCH_MODE		4
-#define STB0899_WIDTH_ACQ_SEARCH_MODE		2
-#define STB0899_CONFIRM_FRAMES			(0x0f << 0)
-#define STB0899_OFFST_CONFIRM_FRAMES		0
-#define STB0899_WIDTH_CONFIRM_FRAMES		4
-
-#define STB0899_OFF0_FE_SETTLE			0xf364
-#define STB0899_BASE_FE_SETTLE			0x00000400
-#define STB0899_SETTLING_TIME			(0x3fffff << 0)
-#define STB0899_OFFST_SETTLING_TIME		0
-#define STB0899_WIDTH_SETTLING_TIME		22
-
-#define STB0899_OFF0_AC_DWELL			0xf368
-#define STB0899_BASE_AC_DWELL			0x00000400
-#define STB0899_DWELL_TIME			(0x3fffff << 0)
-#define STB0899_OFFST_DWELL_TIME		0
-#define STB0899_WIDTH_DWELL_TIME		22
-
-#define STB0899_OFF0_ACQUIRE_TRIG		0xf36c
-#define STB0899_BASE_ACQUIRE_TRIG		0x00000400
-#define STB0899_ACQUIRE				(0x01 << 0)
-#define STB0899_OFFST_ACQUIRE			0
-#define STB0899_WIDTH_ACQUIRE			1
-
-#define STB0899_OFF0_LOCK_LOST			0xf370
-#define STB0899_BASE_LOCK_LOST			0x00000400
-#define STB0899_LOCK_LOST			(0x01 << 0)
-#define STB0899_OFFST_LOCK_LOST			0
-#define STB0899_WIDTH_LOCK_LOST			1
-
-#define STB0899_OFF0_ACQ_STAT1			0xf374
-#define STB0899_BASE_ACQ_STAT1			0x00000400
-#define STB0899_STEP_FREQ			(0x1fffff << 11)
-#define STB0899_OFFST_STEP_FREQ			11
-#define STB0899_WIDTH_STEP_FREQ			21
-#define STB0899_ACQ_STATE			(0x07 << 8)
-#define STB0899_OFFST_ACQ_STATE			8
-#define STB0899_WIDTH_ACQ_STATE			3
-#define STB0899_UW_DETECT_COUNT			(0xff << 0)
-#define STB0899_OFFST_UW_DETECT_COUNT		0
-#define STB0899_WIDTH_UW_DETECT_COUNT		8
-
-#define STB0899_OFF0_ACQ_TIMEOUT		0xf378
-#define STB0899_BASE_ACQ_TIMEOUT		0x00000400
-#define STB0899_ACQ_TIMEOUT			(0x3fffff << 0)
-#define STB0899_OFFST_ACQ_TIMEOUT		0
-#define STB0899_WIDTH_ACQ_TIMEOUT		22
-
-#define STB0899_OFF0_ACQ_TIME			0xf37c
-#define STB0899_BASE_ACQ_TIME			0x00000400
-#define STB0899_ACQ_TIME_SYM			(0xffffff << 0)
-#define STB0899_OFFST_ACQ_TIME_SYM		0
-#define STB0899_WIDTH_ACQ_TIME_SYM		24
-
-#define STB0899_OFF0_FINAL_AGC_CNTRL		0xf308
-#define STB0899_BASE_FINAL_AGC_CNTRL		0x00000440
-#define STB0899_FINAL_GAIN_INIT			(0x3fff << 12)
-#define STB0899_OFFST_FINAL_GAIN_INIT		12
-#define STB0899_WIDTH_FINAL_GAIN_INIT		14
-#define STB0899_FINAL_LOOP_GAIN			(0x0f << 8)
-#define STB0899_OFFST_FINAL_LOOP_GAIN		8
-#define STB0899_WIDTH_FINAL_LOOP_GAIN		4
-#define STB0899_FINAL_LD_GAIN_INIT		(0x01 << 7)
-#define STB0899_OFFST_FINAL_LD_GAIN_INIT	7
-#define STB0899_WIDTH_FINAL_LD_GAIN_INIT	1
-#define STB0899_FINAL_AGC_REF			(0x7f << 0)
-#define STB0899_OFFST_FINAL_AGC_REF		0
-#define STB0899_WIDTH_FINAL_AGC_REF		7
-
-#define STB0899_OFF0_FINAL_AGC_GAIN		0xf30c
-#define STB0899_BASE_FINAL_AGC_GAIN		0x00000440
-#define STB0899_FINAL_AGC_GAIN			(0x3fff << 0)
-#define STB0899_OFFST_FINAL_AGC_GAIN		0
-#define STB0899_WIDTH_FINAL_AGC_GAIN		14
-
-#define STB0899_OFF0_EQUALIZER_INIT		0xf310
-#define STB0899_BASE_EQUALIZER_INIT		0x00000440
-#define STB0899_EQ_SRST				(0x01 << 1)
-#define STB0899_OFFST_EQ_SRST			1
-#define STB0899_WIDTH_EQ_SRST			1
-#define STB0899_EQ_INIT				(0x01 << 0)
-#define STB0899_OFFST_EQ_INIT			0
-#define STB0899_WIDTH_EQ_INIT			1
-
-#define STB0899_OFF0_EQ_CNTRL			0xf314
-#define STB0899_BASE_EQ_CNTRL			0x00000440
-#define STB0899_EQ_ADAPT_MODE			(0x01 << 18)
-#define STB0899_OFFST_EQ_ADAPT_MODE		18
-#define STB0899_WIDTH_EQ_ADAPT_MODE		1
-#define STB0899_EQ_DELAY			(0x0f << 14)
-#define STB0899_OFFST_EQ_DELAY			14
-#define STB0899_WIDTH_EQ_DELAY			4
-#define STB0899_EQ_QUANT_LEVEL			(0xff << 6)
-#define STB0899_OFFST_EQ_QUANT_LEVEL		6
-#define STB0899_WIDTH_EQ_QUANT_LEVEL		8
-#define STB0899_EQ_DISABLE_UPDATE		(0x01 << 5)
-#define STB0899_OFFST_EQ_DISABLE_UPDATE		5
-#define STB0899_WIDTH_EQ_DISABLE_UPDATE		1
-#define STB0899_EQ_BYPASS			(0x01 << 4)
-#define STB0899_OFFST_EQ_BYPASS			4
-#define STB0899_WIDTH_EQ_BYPASS			1
-#define STB0899_EQ_SHIFT			(0x0f << 0)
-#define STB0899_OFFST_EQ_SHIFT			0
-#define STB0899_WIDTH_EQ_SHIFT			4
-
-#define STB0899_OFF0_EQ_I_INIT_COEFF_0		0xf320
-#define STB0899_OFF1_EQ_I_INIT_COEFF_1		0xf324
-#define STB0899_OFF2_EQ_I_INIT_COEFF_2		0xf328
-#define STB0899_OFF3_EQ_I_INIT_COEFF_3		0xf32c
-#define STB0899_OFF4_EQ_I_INIT_COEFF_4		0xf330
-#define STB0899_OFF5_EQ_I_INIT_COEFF_5		0xf334
-#define STB0899_OFF6_EQ_I_INIT_COEFF_6		0xf338
-#define STB0899_OFF7_EQ_I_INIT_COEFF_7		0xf33c
-#define STB0899_OFF8_EQ_I_INIT_COEFF_8		0xf340
-#define STB0899_OFF9_EQ_I_INIT_COEFF_9		0xf344
-#define STB0899_OFFa_EQ_I_INIT_COEFF_10		0xf348
-#define STB0899_BASE_EQ_I_INIT_COEFF_N		0x00000440
-#define STB0899_EQ_I_INIT_COEFF_N		(0x0fff << 0)
-#define STB0899_OFFST_EQ_I_INIT_COEFF_N		0
-#define STB0899_WIDTH_EQ_I_INIT_COEFF_N		12
-
-#define STB0899_OFF0_EQ_Q_INIT_COEFF_0		0xf350
-#define STB0899_OFF1_EQ_Q_INIT_COEFF_1		0xf354
-#define STB0899_OFF2_EQ_Q_INIT_COEFF_2		0xf358
-#define STB0899_OFF3_EQ_Q_INIT_COEFF_3		0xf35c
-#define STB0899_OFF4_EQ_Q_INIT_COEFF_4		0xf360
-#define STB0899_OFF5_EQ_Q_INIT_COEFF_5		0xf364
-#define STB0899_OFF6_EQ_Q_INIT_COEFF_6		0xf368
-#define STB0899_OFF7_EQ_Q_INIT_COEFF_7		0xf36c
-#define STB0899_OFF8_EQ_Q_INIT_COEFF_8		0xf370
-#define STB0899_OFF9_EQ_Q_INIT_COEFF_9		0xf374
-#define STB0899_OFFa_EQ_Q_INIT_COEFF_10		0xf378
-#define STB0899_BASE_EQ_Q_INIT_COEFF_N		0x00000440
-#define STB0899_EQ_Q_INIT_COEFF_N		(0x0fff << 0)
-#define STB0899_OFFST_EQ_Q_INIT_COEFF_N		0
-#define STB0899_WIDTH_EQ_Q_INIT_COEFF_N		12
-
-#define STB0899_OFF0_EQ_I_OUT_COEFF_0		0xf300
-#define STB0899_OFF1_EQ_I_OUT_COEFF_1		0xf304
-#define STB0899_OFF2_EQ_I_OUT_COEFF_2		0xf308
-#define STB0899_OFF3_EQ_I_OUT_COEFF_3		0xf30c
-#define STB0899_OFF4_EQ_I_OUT_COEFF_4		0xf310
-#define STB0899_OFF5_EQ_I_OUT_COEFF_5		0xf314
-#define STB0899_OFF6_EQ_I_OUT_COEFF_6		0xf318
-#define STB0899_OFF7_EQ_I_OUT_COEFF_7		0xf31c
-#define STB0899_OFF8_EQ_I_OUT_COEFF_8		0xf320
-#define STB0899_OFF9_EQ_I_OUT_COEFF_9		0xf324
-#define STB0899_OFFa_EQ_I_OUT_COEFF_10		0xf328
-#define STB0899_BASE_EQ_I_OUT_COEFF_N		0x00000460
-#define STB0899_EQ_I_OUT_COEFF_N		(0x0fff << 0)
-#define STB0899_OFFST_EQ_I_OUT_COEFF_N		0
-#define STB0899_WIDTH_EQ_I_OUT_COEFF_N		12
-
-#define STB0899_OFF0_EQ_Q_OUT_COEFF_0		0xf330
-#define STB0899_OFF1_EQ_Q_OUT_COEFF_1		0xf334
-#define STB0899_OFF2_EQ_Q_OUT_COEFF_2		0xf338
-#define STB0899_OFF3_EQ_Q_OUT_COEFF_3		0xf33c
-#define STB0899_OFF4_EQ_Q_OUT_COEFF_4		0xf340
-#define STB0899_OFF5_EQ_Q_OUT_COEFF_5		0xf344
-#define STB0899_OFF6_EQ_Q_OUT_COEFF_6		0xf348
-#define STB0899_OFF7_EQ_Q_OUT_COEFF_7		0xf34c
-#define STB0899_OFF8_EQ_Q_OUT_COEFF_8		0xf350
-#define STB0899_OFF9_EQ_Q_OUT_COEFF_9		0xf354
-#define STB0899_OFFa_EQ_Q_OUT_COEFF_10		0xf358
-#define STB0899_BASE_EQ_Q_OUT_COEFF_N		0x00000460
-#define STB0899_EQ_Q_OUT_COEFF_N		(0x0fff << 0)
-#define STB0899_OFFST_EQ_Q_OUT_COEFF_N		0
-#define STB0899_WIDTH_EQ_Q_OUT_COEFF_N		12
-
-/*	S2 FEC	*/
-#define STB0899_OFF0_BLOCK_LNGTH		0xfa04
-#define STB0899_BASE_BLOCK_LNGTH		0x00000000
-#define STB0899_BLOCK_LENGTH			(0xff << 0)
-#define STB0899_OFFST_BLOCK_LENGTH		0
-#define STB0899_WIDTH_BLOCK_LENGTH		8
-
-#define STB0899_OFF0_ROW_STR			0xfa08
-#define STB0899_BASE_ROW_STR			0x00000000
-#define STB0899_ROW_STRIDE			(0xff << 0)
-#define STB0899_OFFST_ROW_STRIDE		0
-#define STB0899_WIDTH_ROW_STRIDE		8
-
-#define STB0899_OFF0_MAX_ITER			0xfa0c
-#define STB0899_BASE_MAX_ITER			0x00000000
-#define STB0899_MAX_ITERATIONS			(0xff << 0)
-#define STB0899_OFFST_MAX_ITERATIONS		0
-#define STB0899_WIDTH_MAX_ITERATIONS		8
-
-#define STB0899_OFF0_BN_END_ADDR		0xfa10
-#define STB0899_BASE_BN_END_ADDR		0x00000000
-#define STB0899_BN_END_ADDR			(0x0fff << 0)
-#define STB0899_OFFST_BN_END_ADDR		0
-#define STB0899_WIDTH_BN_END_ADDR		12
-
-#define STB0899_OFF0_CN_END_ADDR		0xfa14
-#define STB0899_BASE_CN_END_ADDR		0x00000000
-#define STB0899_CN_END_ADDR			(0x0fff << 0)
-#define STB0899_OFFST_CN_END_ADDR		0
-#define STB0899_WIDTH_CN_END_ADDR		12
-
-#define STB0899_OFF0_INFO_LENGTH		0xfa1c
-#define STB0899_BASE_INFO_LENGTH		0x00000000
-#define STB0899_INFO_LENGTH			(0xff << 0)
-#define STB0899_OFFST_INFO_LENGTH		0
-#define STB0899_WIDTH_INFO_LENGTH		8
-
-#define STB0899_OFF0_BOT_ADDR			0xfa20
-#define STB0899_BASE_BOT_ADDR			0x00000000
-#define STB0899_BOTTOM_BASE_ADDR		(0x03ff << 0)
-#define STB0899_OFFST_BOTTOM_BASE_ADDR		0
-#define STB0899_WIDTH_BOTTOM_BASE_ADDR		10
-
-#define STB0899_OFF0_BCH_BLK_LN			0xfa24
-#define STB0899_BASE_BCH_BLK_LN			0x00000000
-#define STB0899_BCH_BLOCK_LENGTH		(0xffff << 0)
-#define STB0899_OFFST_BCH_BLOCK_LENGTH		0
-#define STB0899_WIDTH_BCH_BLOCK_LENGTH		16
-
-#define STB0899_OFF0_BCH_T			0xfa28
-#define STB0899_BASE_BCH_T			0x00000000
-#define STB0899_BCH_T				(0x0f << 0)
-#define STB0899_OFFST_BCH_T			0
-#define STB0899_WIDTH_BCH_T			4
-
-#define STB0899_OFF0_CNFG_MODE			0xfa00
-#define STB0899_BASE_CNFG_MODE			0x00000800
-#define STB0899_MODCOD				(0x1f << 2)
-#define STB0899_OFFST_MODCOD			2
-#define STB0899_WIDTH_MODCOD			5
-#define STB0899_MODCOD_SEL			(0x01 << 1)
-#define STB0899_OFFST_MODCOD_SEL		1
-#define STB0899_WIDTH_MODCOD_SEL		1
-#define STB0899_CONFIG_MODE			(0x01 << 0)
-#define STB0899_OFFST_CONFIG_MODE		0
-#define STB0899_WIDTH_CONFIG_MODE		1
-
-#define STB0899_OFF0_LDPC_STAT			0xfa04
-#define STB0899_BASE_LDPC_STAT			0x00000800
-#define STB0899_ITERATION			(0xff << 3)
-#define STB0899_OFFST_ITERATION			3
-#define STB0899_WIDTH_ITERATION			8
-#define STB0899_LDPC_DEC_STATE			(0x07 << 0)
-#define STB0899_OFFST_LDPC_DEC_STATE		0
-#define STB0899_WIDTH_LDPC_DEC_STATE		3
-
-#define STB0899_OFF0_ITER_SCALE			0xfa08
-#define STB0899_BASE_ITER_SCALE			0x00000800
-#define STB0899_ITERATION_SCALE			(0xff << 0)
-#define STB0899_OFFST_ITERATION_SCALE		0
-#define STB0899_WIDTH_ITERATION_SCALE		8
-
-#define STB0899_OFF0_INPUT_MODE			0xfa0c
-#define STB0899_BASE_INPUT_MODE			0x00000800
-#define STB0899_SD_BLOCK1_STREAM0		(0x01 << 0)
-#define STB0899_OFFST_SD_BLOCK1_STREAM0		0
-#define STB0899_WIDTH_SD_BLOCK1_STREAM0		1
-
-#define STB0899_OFF0_LDPCDECRST			0xfa10
-#define STB0899_BASE_LDPCDECRST			0x00000800
-#define STB0899_LDPC_DEC_RST			(0x01 << 0)
-#define STB0899_OFFST_LDPC_DEC_RST		0
-#define STB0899_WIDTH_LDPC_DEC_RST		1
-
-#define STB0899_OFF0_CLK_PER_BYTE_RW		0xfa14
-#define STB0899_BASE_CLK_PER_BYTE_RW		0x00000800
-#define STB0899_CLKS_PER_BYTE			(0x0f << 0)
-#define STB0899_OFFST_CLKS_PER_BYTE		0
-#define STB0899_WIDTH_CLKS_PER_BYTE		5
-
-#define STB0899_OFF0_BCH_ERRORS			0xfa18
-#define STB0899_BASE_BCH_ERRORS			0x00000800
-#define STB0899_BCH_ERRORS			(0x0f << 0)
-#define STB0899_OFFST_BCH_ERRORS		0
-#define STB0899_WIDTH_BCH_ERRORS		4
-
-#define STB0899_OFF0_LDPC_ERRORS		0xfa1c
-#define STB0899_BASE_LDPC_ERRORS		0x00000800
-#define STB0899_LDPC_ERRORS			(0xffff << 0)
-#define STB0899_OFFST_LDPC_ERRORS		0
-#define STB0899_WIDTH_LDPC_ERRORS		16
-
-#define STB0899_OFF0_BCH_MODE			0xfa20
-#define STB0899_BASE_BCH_MODE			0x00000800
-#define STB0899_BCH_CORRECT_N			(0x01 << 1)
-#define STB0899_OFFST_BCH_CORRECT_N		1
-#define STB0899_WIDTH_BCH_CORRECT_N		1
-#define STB0899_FULL_BYPASS			(0x01 << 0)
-#define STB0899_OFFST_FULL_BYPASS		0
-#define STB0899_WIDTH_FULL_BYPASS		1
-
-#define STB0899_OFF0_ERR_ACC_PER		0xfa24
-#define STB0899_BASE_ERR_ACC_PER		0x00000800
-#define STB0899_BCH_ERR_ACC_PERIOD		(0x0f << 0)
-#define STB0899_OFFST_BCH_ERR_ACC_PERIOD	0
-#define STB0899_WIDTH_BCH_ERR_ACC_PERIOD	4
-
-#define STB0899_OFF0_BCH_ERR_ACC		0xfa28
-#define STB0899_BASE_BCH_ERR_ACC		0x00000800
-#define STB0899_BCH_ERR_ACCUM			(0xff << 0)
-#define STB0899_OFFST_BCH_ERR_ACCUM		0
-#define STB0899_WIDTH_BCH_ERR_ACCUM		8
-
-#define STB0899_OFF0_FEC_CORE_ID_REG		0xfa2c
-#define STB0899_BASE_FEC_CORE_ID_REG		0x00000800
-#define STB0899_FEC_CORE_ID			(0xffffffff << 0)
-#define STB0899_OFFST_FEC_CORE_ID		0
-#define STB0899_WIDTH_FEC_CORE_ID		32
-
-#define STB0899_OFF0_FEC_VER_ID_REG		0xfa34
-#define STB0899_BASE_FEC_VER_ID_REG		0x00000800
-#define STB0899_FEC_VER_ID			(0xff << 0)
-#define STB0899_OFFST_FEC_VER_ID		0
-#define STB0899_WIDTH_FEC_VER_ID		8
-
-#define STB0899_OFF0_FEC_TP_SEL			0xfa38
-#define STB0899_BASE_FEC_TP_SEL			0x00000800
-
-#define STB0899_OFF0_CSM_CNTRL1			0xf310
-#define STB0899_BASE_CSM_CNTRL1			0x00000400
-#define STB0899_CSM_FORCE_FREQLOCK		(0x01 << 19)
-#define STB0899_OFFST_CSM_FORCE_FREQLOCK	19
-#define STB0899_WIDTH_CSM_FORCE_FREQLOCK	1
-#define STB0899_CSM_FREQ_LOCKSTATE		(0x01 << 18)
-#define STB0899_OFFST_CSM_FREQ_LOCKSTATE	18
-#define STB0899_WIDTH_CSM_FREQ_LOCKSTATE	1
-#define STB0899_CSM_AUTO_PARAM			(0x01 << 17)
-#define STB0899_OFFST_CSM_AUTO_PARAM		17
-#define STB0899_WIDTH_CSM_AUTO_PARAM		1
-#define STB0899_FE_LOOP_SHIFT			(0x07 << 14)
-#define STB0899_OFFST_FE_LOOP_SHIFT		14
-#define STB0899_WIDTH_FE_LOOP_SHIFT		3
-#define STB0899_CSM_AGC_SHIFT			(0x07 << 11)
-#define STB0899_OFFST_CSM_AGC_SHIFT		11
-#define STB0899_WIDTH_CSM_AGC_SHIFT		3
-#define STB0899_CSM_AGC_GAIN			(0x1ff << 2)
-#define STB0899_OFFST_CSM_AGC_GAIN		2
-#define STB0899_WIDTH_CSM_AGC_GAIN		9
-#define STB0899_CSM_TWO_PASS			(0x01 << 1)
-#define STB0899_OFFST_CSM_TWO_PASS		1
-#define STB0899_WIDTH_CSM_TWO_PASS		1
-#define STB0899_CSM_DVT_TABLE			(0x01 << 0)
-#define STB0899_OFFST_CSM_DVT_TABLE		0
-#define STB0899_WIDTH_CSM_DVT_TABLE		1
-
-#define STB0899_OFF0_CSM_CNTRL2			0xf314
-#define STB0899_BASE_CSM_CNTRL2			0x00000400
-#define STB0899_CSM_GAMMA_RHO_ACQ		(0x1ff << 9)
-#define STB0899_OFFST_CSM_GAMMA_RHOACQ		9
-#define STB0899_WIDTH_CSM_GAMMA_RHOACQ		9
-#define STB0899_CSM_GAMMA_ACQ			(0x1ff << 0)
-#define STB0899_OFFST_CSM_GAMMA_ACQ		0
-#define STB0899_WIDTH_CSM_GAMMA_ACQ		9
-
-#define STB0899_OFF0_CSM_CNTRL3			0xf318
-#define STB0899_BASE_CSM_CNTRL3			0x00000400
-#define STB0899_CSM_GAMMA_RHO_TRACK		(0x1ff << 9)
-#define STB0899_OFFST_CSM_GAMMA_RHOTRACK	9
-#define STB0899_WIDTH_CSM_GAMMA_RHOTRACK	9
-#define STB0899_CSM_GAMMA_TRACK			(0x1ff << 0)
-#define STB0899_OFFST_CSM_GAMMA_TRACK		0
-#define STB0899_WIDTH_CSM_GAMMA_TRACK		9
-
-#define STB0899_OFF0_CSM_CNTRL4			0xf31c
-#define STB0899_BASE_CSM_CNTRL4			0x00000400
-#define STB0899_CSM_PHASEDIFF_THRESH		(0x0f << 8)
-#define STB0899_OFFST_CSM_PHASEDIFF_THRESH	8
-#define STB0899_WIDTH_CSM_PHASEDIFF_THRESH	4
-#define STB0899_CSM_LOCKCOUNT_THRESH		(0xff << 0)
-#define STB0899_OFFST_CSM_LOCKCOUNT_THRESH	0
-#define STB0899_WIDTH_CSM_LOCKCOUNT_THRESH	8
-
-/*	Check on chapter 8 page 42	*/
-#define STB0899_ERRCTRL1			0xf574
-#define STB0899_ERRCTRL2			0xf575
-#define STB0899_ERRCTRL3			0xf576
-#define STB0899_ERR_SRC_S1			(0x1f << 3)
-#define STB0899_OFFST_ERR_SRC_S1		3
-#define STB0899_WIDTH_ERR_SRC_S1		5
-#define STB0899_ERR_SRC_S2			(0x0f << 0)
-#define STB0899_OFFST_ERR_SRC_S2		0
-#define STB0899_WIDTH_ERR_SRC_S2		4
-#define STB0899_NOE				(0x07 << 0)
-#define STB0899_OFFST_NOE			0
-#define STB0899_WIDTH_NOE			3
-
-#define STB0899_ECNT1M				0xf524
-#define STB0899_ECNT1L				0xf525
-#define STB0899_ECNT2M				0xf526
-#define STB0899_ECNT2L				0xf527
-#define STB0899_ECNT3M				0xf528
-#define STB0899_ECNT3L				0xf529
-
-#define STB0899_DMONMSK1			0xf57b
-#define STB0899_DMONMSK1_WAIT_1STEP		(1 << 7)
-#define STB0899_DMONMSK1_FREE_14		(1 << 6)
-#define STB0899_DMONMSK1_AVRGVIT_CALC		(1 << 5)
-#define STB0899_DMONMSK1_FREE_12		(1 << 4)
-#define STB0899_DMONMSK1_FREE_11		(1 << 3)
-#define STB0899_DMONMSK1_B0DIV_CALC		(1 << 2)
-#define STB0899_DMONMSK1_KDIVB1_CALC		(1 << 1)
-#define STB0899_DMONMSK1_KDIVB2_CALC		(1 << 0)
-
-#define STB0899_DMONMSK0			0xf57c
-#define STB0899_DMONMSK0_SMOTTH_CALC		(1 << 7)
-#define STB0899_DMONMSK0_FREE_6			(1 << 6)
-#define STB0899_DMONMSK0_SIGPOWER_CALC		(1 << 5)
-#define STB0899_DMONMSK0_QSEUIL_CALC		(1 << 4)
-#define STB0899_DMONMSK0_FREE_3			(1 << 3)
-#define STB0899_DMONMSK0_FREE_2			(1 << 2)
-#define STB0899_DMONMSK0_KVDIVB1_CALC		(1 << 1)
-#define STB0899_DMONMSK0_KVDIVB2_CALC		(1 << 0)
-
-#define STB0899_TSULC				0xf549
-#define STB0899_ULNOSYNCBYTES			(0x01 << 7)
-#define STB0899_OFFST_ULNOSYNCBYTES		7
-#define STB0899_WIDTH_ULNOSYNCBYTES		1
-#define STB0899_ULPARITY_ON			(0x01 << 6)
-#define STB0899_OFFST_ULPARITY_ON		6
-#define STB0899_WIDTH_ULPARITY_ON		1
-#define STB0899_ULSYNCOUTRS			(0x01 << 5)
-#define STB0899_OFFST_ULSYNCOUTRS		5
-#define STB0899_WIDTH_ULSYNCOUTRS		1
-#define STB0899_ULDSS_PACKETS			(0x01 << 0)
-#define STB0899_OFFST_ULDSS_PACKETS		0
-#define STB0899_WIDTH_ULDSS_PACKETS		1
-
-#define STB0899_TSLPL				0xf54b
-#define STB0899_LLDVBS2_MODE			(0x01 << 4)
-#define STB0899_OFFST_LLDVBS2_MODE		4
-#define STB0899_WIDTH_LLDVBS2_MODE		1
-#define STB0899_LLISSYI_ON			(0x01 << 3)
-#define STB0899_OFFST_LLISSYI_ON		3
-#define STB0899_WIDTH_LLISSYI_ON		1
-#define STB0899_LLNPD_ON			(0x01 << 2)
-#define STB0899_OFFST_LLNPD_ON			2
-#define STB0899_WIDTH_LLNPD_ON			1
-#define STB0899_LLCRC8_ON			(0x01 << 1)
-#define STB0899_OFFST_LLCRC8_ON			1
-#define STB0899_WIDTH_LLCRC8_ON			1
-
-#define STB0899_TSCFGH				0xf54c
-#define STB0899_OUTRS_PS			(0x01 << 6)
-#define STB0899_OFFST_OUTRS_PS			6
-#define STB0899_WIDTH_OUTRS_PS			1
-#define STB0899_SYNCBYTE			(0x01 << 5)
-#define STB0899_OFFST_SYNCBYTE			5
-#define STB0899_WIDTH_SYNCBYTE			1
-#define STB0899_PFBIT				(0x01 << 4)
-#define STB0899_OFFST_PFBIT			4
-#define STB0899_WIDTH_PFBIT			1
-#define STB0899_ERR_BIT				(0x01 << 3)
-#define STB0899_OFFST_ERR_BIT			3
-#define STB0899_WIDTH_ERR_BIT			1
-#define STB0899_MPEG				(0x01 << 2)
-#define STB0899_OFFST_MPEG			2
-#define STB0899_WIDTH_MPEG			1
-#define STB0899_CLK_POL				(0x01 << 1)
-#define STB0899_OFFST_CLK_POL			1
-#define STB0899_WIDTH_CLK_POL			1
-#define STB0899_FORCE0				(0x01 << 0)
-#define STB0899_OFFST_FORCE0			0
-#define STB0899_WIDTH_FORCE0			1
-
-#define STB0899_TSCFGM				0xf54d
-#define STB0899_LLPRIORITY			(0x01 << 3)
-#define STB0899_OFFST_LLPRIORIY			3
-#define STB0899_WIDTH_LLPRIORITY		1
-#define STB0899_EN188				(0x01 << 2)
-#define STB0899_OFFST_EN188			2
-#define STB0899_WIDTH_EN188			1
-
-#define STB0899_TSCFGL				0xf54e
-#define STB0899_DEL_ERRPCK			(0x01 << 7)
-#define STB0899_OFFST_DEL_ERRPCK		7
-#define STB0899_WIDTH_DEL_ERRPCK		1
-#define STB0899_ERRFLAGSTD			(0x01 << 5)
-#define STB0899_OFFST_ERRFLAGSTD		5
-#define STB0899_WIDTH_ERRFLAGSTD		1
-#define STB0899_MPEGERR				(0x01 << 4)
-#define STB0899_OFFST_MPEGERR			4
-#define STB0899_WIDTH_MPEGERR			1
-#define STB0899_BCH_CHK				(0x01 << 3)
-#define STB0899_OFFST_BCH_CHK			5
-#define STB0899_WIDTH_BCH_CHK			1
-#define STB0899_CRC8CHK				(0x01 << 2)
-#define STB0899_OFFST_CRC8CHK			2
-#define STB0899_WIDTH_CRC8CHK			1
-#define STB0899_SPEC_INFO			(0x01 << 1)
-#define STB0899_OFFST_SPEC_INFO			1
-#define STB0899_WIDTH_SPEC_INFO			1
-#define STB0899_LOW_PRIO_CLK			(0x01 << 0)
-#define STB0899_OFFST_LOW_PRIO_CLK		0
-#define STB0899_WIDTH_LOW_PRIO_CLK		1
-#define STB0899_ERROR_NORM			(0x00 << 0)
-#define STB0899_OFFST_ERROR_NORM		0
-#define STB0899_WIDTH_ERROR_NORM		0
-
-#define STB0899_TSOUT				0xf54f
-#define STB0899_RSSYNCDEL			0xf550
-#define STB0899_TSINHDELH			0xf551
-#define STB0899_TSINHDELM			0xf552
-#define STB0899_TSINHDELL			0xf553
-#define STB0899_TSLLSTKM			0xf55a
-#define STB0899_TSLLSTKL			0xf55b
-#define STB0899_TSULSTKM			0xf55c
-#define STB0899_TSULSTKL			0xf55d
-#define STB0899_TSSTATUS			0xf561
-
-#define STB0899_PDELCTRL			0xf600
-#define STB0899_INVERT_RES			(0x01 << 7)
-#define STB0899_OFFST_INVERT_RES		7
-#define STB0899_WIDTH_INVERT_RES		1
-#define STB0899_FORCE_ACCEPTED			(0x01 << 6)
-#define STB0899_OFFST_FORCE_ACCEPTED		6
-#define STB0899_WIDTH_FORCE_ACCEPTED		1
-#define STB0899_FILTER_EN			(0x01 << 5)
-#define STB0899_OFFST_FILTER_EN			5
-#define STB0899_WIDTH_FILTER_EN			1
-#define STB0899_LOCKFALL_THRESH			(0x01 << 4)
-#define STB0899_OFFST_LOCKFALL_THRESH		4
-#define STB0899_WIDTH_LOCKFALL_THRESH		1
-#define STB0899_HYST_EN				(0x01 << 3)
-#define STB0899_OFFST_HYST_EN			3
-#define STB0899_WIDTH_HYST_EN			1
-#define STB0899_HYST_SWRST			(0x01 << 2)
-#define STB0899_OFFST_HYST_SWRST		2
-#define STB0899_WIDTH_HYST_SWRST		1
-#define STB0899_ALGO_EN				(0x01 << 1)
-#define STB0899_OFFST_ALGO_EN			1
-#define STB0899_WIDTH_ALGO_EN			1
-#define STB0899_ALGO_SWRST			(0x01 << 0)
-#define STB0899_OFFST_ALGO_SWRST		0
-#define STB0899_WIDTH_ALGO_SWRST		1
-
-#define STB0899_PDELCTRL2			0xf601
-#define STB0899_BBHCTRL1			0xf602
-#define STB0899_BBHCTRL2			0xf603
-#define STB0899_HYSTTHRESH			0xf604
-
-#define STB0899_MATCSTM				0xf605
-#define STB0899_MATCSTL				0xf606
-#define STB0899_UPLCSTM				0xf607
-#define STB0899_UPLCSTL				0xf608
-#define STB0899_DFLCSTM				0xf609
-#define STB0899_DFLCSTL				0xf60a
-#define STB0899_SYNCCST				0xf60b
-#define STB0899_SYNCDCSTM			0xf60c
-#define STB0899_SYNCDCSTL			0xf60d
-#define STB0899_ISI_ENTRY			0xf60e
-#define STB0899_ISI_BIT_EN			0xf60f
-#define STB0899_MATSTRM				0xf610
-#define STB0899_MATSTRL				0xf611
-#define STB0899_UPLSTRM				0xf612
-#define STB0899_UPLSTRL				0xf613
-#define STB0899_DFLSTRM				0xf614
-#define STB0899_DFLSTRL				0xf615
-#define STB0899_SYNCSTR				0xf616
-#define STB0899_SYNCDSTRM			0xf617
-#define STB0899_SYNCDSTRL			0xf618
-
-#define STB0899_CFGPDELSTATUS1			0xf619
-#define STB0899_BADDFL				(0x01 << 6)
-#define STB0899_OFFST_BADDFL			6
-#define STB0899_WIDTH_BADDFL			1
-#define STB0899_CONTINUOUS_STREAM		(0x01 << 5)
-#define STB0899_OFFST_CONTINUOUS_STREAM		5
-#define STB0899_WIDTH_CONTINUOUS_STREAM		1
-#define STB0899_ACCEPTED_STREAM			(0x01 << 4)
-#define STB0899_OFFST_ACCEPTED_STREAM		4
-#define STB0899_WIDTH_ACCEPTED_STREAM		1
-#define STB0899_BCH_ERRFLAG			(0x01 << 3)
-#define STB0899_OFFST_BCH_ERRFLAG		3
-#define STB0899_WIDTH_BCH_ERRFLAG		1
-#define STB0899_CRCRES				(0x01 << 2)
-#define STB0899_OFFST_CRCRES			2
-#define STB0899_WIDTH_CRCRES			1
-#define STB0899_CFGPDELSTATUS_LOCK		(0x01 << 1)
-#define STB0899_OFFST_CFGPDELSTATUS_LOCK	1
-#define STB0899_WIDTH_CFGPDELSTATUS_LOCK	1
-#define STB0899_1STLOCK				(0x01 << 0)
-#define STB0899_OFFST_1STLOCK			0
-#define STB0899_WIDTH_1STLOCK			1
-
-#define STB0899_CFGPDELSTATUS2			0xf61a
-#define STB0899_BBFERRORM			0xf61b
-#define STB0899_BBFERRORL			0xf61c
-#define STB0899_UPKTERRORM			0xf61d
-#define STB0899_UPKTERRORL			0xf61e
-
-#define STB0899_TSTCK				0xff10
-
-#define STB0899_TSTRES				0xff11
-#define STB0899_FRESLDPC			(0x01 << 7)
-#define STB0899_OFFST_FRESLDPC			7
-#define STB0899_WIDTH_FRESLDPC			1
-#define STB0899_FRESRS				(0x01 << 6)
-#define STB0899_OFFST_FRESRS			6
-#define STB0899_WIDTH_FRESRS			1
-#define STB0899_FRESVIT				(0x01 << 5)
-#define STB0899_OFFST_FRESVIT			5
-#define STB0899_WIDTH_FRESVIT			1
-#define STB0899_FRESMAS1_2			(0x01 << 4)
-#define STB0899_OFFST_FRESMAS1_2		4
-#define STB0899_WIDTH_FRESMAS1_2		1
-#define STB0899_FRESACS				(0x01 << 3)
-#define STB0899_OFFST_FRESACS			3
-#define STB0899_WIDTH_FRESACS			1
-#define STB0899_FRESSYM				(0x01 << 2)
-#define STB0899_OFFST_FRESSYM			2
-#define STB0899_WIDTH_FRESSYM			1
-#define STB0899_FRESMAS				(0x01 << 1)
-#define STB0899_OFFST_FRESMAS			1
-#define STB0899_WIDTH_FRESMAS			1
-#define STB0899_FRESINT				(0x01 << 0)
-#define STB0899_OFFST_FRESINIT			0
-#define STB0899_WIDTH_FRESINIT			1
-
-#define STB0899_TSTOUT				0xff12
-#define STB0899_EN_SIGNATURE			(0x01 << 7)
-#define STB0899_OFFST_EN_SIGNATURE		7
-#define STB0899_WIDTH_EN_SIGNATURE		1
-#define STB0899_BCLK_CLK			(0x01 << 6)
-#define STB0899_OFFST_BCLK_CLK			6
-#define STB0899_WIDTH_BCLK_CLK			1
-#define STB0899_SGNL_OUT			(0x01 << 5)
-#define STB0899_OFFST_SGNL_OUT			5
-#define STB0899_WIDTH_SGNL_OUT			1
-#define STB0899_TS				(0x01 << 4)
-#define STB0899_OFFST_TS			4
-#define STB0899_WIDTH_TS			1
-#define STB0899_CTEST				(0x01 << 0)
-#define STB0899_OFFST_CTEST			0
-#define STB0899_WIDTH_CTEST			1
-
-#define STB0899_TSTIN				0xff13
-#define STB0899_TEST_IN				(0x01 << 7)
-#define STB0899_OFFST_TEST_IN			7
-#define STB0899_WIDTH_TEST_IN			1
-#define STB0899_EN_ADC				(0x01 << 6)
-#define STB0899_OFFST_EN_ADC			6
-#define STB0899_WIDTH_ENADC			1
-#define STB0899_SGN_ADC				(0x01 << 5)
-#define STB0899_OFFST_SGN_ADC			5
-#define STB0899_WIDTH_SGN_ADC			1
-#define STB0899_BCLK_IN				(0x01 << 4)
-#define STB0899_OFFST_BCLK_IN			4
-#define STB0899_WIDTH_BCLK_IN			1
-#define STB0899_JETONIN_MODE			(0x01 << 3)
-#define STB0899_OFFST_JETONIN_MODE		3
-#define STB0899_WIDTH_JETONIN_MODE		1
-#define STB0899_BCLK_VALUE			(0x01 << 2)
-#define STB0899_OFFST_BCLK_VALUE		2
-#define STB0899_WIDTH_BCLK_VALUE		1
-#define STB0899_SGNRST_T12			(0x01 << 1)
-#define STB0899_OFFST_SGNRST_T12		1
-#define STB0899_WIDTH_SGNRST_T12		1
-#define STB0899_LOWSP_ENAX			(0x01 << 0)
-#define STB0899_OFFST_LOWSP_ENAX		0
-#define STB0899_WIDTH_LOWSP_ENAX		1
-
-#define STB0899_TSTSYS				0xff14
-#define STB0899_TSTCHIP				0xff15
-#define STB0899_TSTFREE				0xff16
-#define STB0899_TSTI2C				0xff17
-#define STB0899_BITSPEEDM			0xff1c
-#define STB0899_BITSPEEDL			0xff1d
-#define STB0899_TBUSBIT				0xff1e
-#define STB0899_TSTDIS				0xff24
-#define STB0899_TSTDISRX			0xff25
-#define STB0899_TSTJETON			0xff28
-#define STB0899_TSTDCADJ			0xff40
-#define STB0899_TSTAGC1				0xff41
-#define STB0899_TSTAGC1N			0xff42
-#define STB0899_TSTPOLYPH			0xff48
-#define STB0899_TSTR				0xff49
-#define STB0899_TSTAGC2				0xff4a
-#define STB0899_TSTCTL1				0xff4b
-#define STB0899_TSTCTL2				0xff4c
-#define STB0899_TSTCTL3				0xff4d
-#define STB0899_TSTDEMAP			0xff50
-#define STB0899_TSTDEMAP2			0xff51
-#define STB0899_TSTDEMMON			0xff52
-#define STB0899_TSTRATE				0xff53
-#define STB0899_TSTSELOUT			0xff54
-#define STB0899_TSYNC				0xff55
-#define STB0899_TSTERR				0xff56
-#define STB0899_TSTRAM1				0xff58
-#define STB0899_TSTVSELOUT			0xff59
-#define STB0899_TSTFORCEIN			0xff5a
-#define STB0899_TSTRS1				0xff5c
-#define STB0899_TSTRS2				0xff5d
-#define STB0899_TSTRS3				0xff53
-
-#define STB0899_INTBUFSTATUS			0xf200
-#define STB0899_INTBUFCTRL			0xf201
-#define STB0899_PCKLENUL			0xf55e
-#define STB0899_PCKLENLL			0xf55f
-#define STB0899_RSPCKLEN			0xf560
-
-/*	2 registers	*/
-#define STB0899_SYNCDCST			0xf60c
-
-/*	DiSEqC	*/
-#define STB0899_DISCNTRL1			0xf0a0
-#define STB0899_TIMOFF				(0x01 << 7)
-#define STB0899_OFFST_TIMOFF			7
-#define STB0899_WIDTH_TIMOFF			1
-#define STB0899_DISEQCRESET			(0x01 << 6)
-#define STB0899_OFFST_DISEQCRESET		6
-#define STB0899_WIDTH_DISEQCRESET		1
-#define STB0899_TIMCMD				(0x03 << 4)
-#define STB0899_OFFST_TIMCMD			4
-#define STB0899_WIDTH_TIMCMD			2
-#define STB0899_DISPRECHARGE			(0x01 << 2)
-#define STB0899_OFFST_DISPRECHARGE		2
-#define STB0899_WIDTH_DISPRECHARGE		1
-#define STB0899_DISEQCMODE			(0x03 << 0)
-#define STB0899_OFFST_DISEQCMODE		0
-#define STB0899_WIDTH_DISEQCMODE		2
-
-#define STB0899_DISCNTRL2			0xf0a1
-#define STB0899_RECEIVER_ON			(0x01 << 7)
-#define STB0899_OFFST_RECEIVER_ON		7
-#define STB0899_WIDTH_RECEIVER_ON		1
-#define STB0899_IGNO_SHORT_22K			(0x01 << 6)
-#define STB0899_OFFST_IGNO_SHORT_22K		6
-#define STB0899_WIDTH_IGNO_SHORT_22K		1
-#define STB0899_ONECHIP_TRX			(0x01 << 5)
-#define STB0899_OFFST_ONECHIP_TRX		5
-#define STB0899_WIDTH_ONECHIP_TRX		1
-#define STB0899_EXT_ENVELOP			(0x01 << 4)
-#define STB0899_OFFST_EXT_ENVELOP		4
-#define STB0899_WIDTH_EXT_ENVELOP		1
-#define STB0899_PIN_SELECT			(0x03 << 2)
-#define STB0899_OFFST_PIN_SELCT			2
-#define STB0899_WIDTH_PIN_SELCT			2
-#define STB0899_IRQ_RXEND			(0x01 << 1)
-#define STB0899_OFFST_IRQ_RXEND			1
-#define STB0899_WIDTH_IRQ_RXEND			1
-#define STB0899_IRQ_4NBYTES			(0x01 << 0)
-#define STB0899_OFFST_IRQ_4NBYTES		0
-#define STB0899_WIDTH_IRQ_4NBYTES		1
-
-#define STB0899_DISRX_ST0			0xf0a4
-#define STB0899_RXEND				(0x01 << 7)
-#define STB0899_OFFST_RXEND			7
-#define STB0899_WIDTH_RXEND			1
-#define STB0899_RXACTIVE			(0x01 << 6)
-#define STB0899_OFFST_RXACTIVE			6
-#define STB0899_WIDTH_RXACTIVE			1
-#define STB0899_SHORT22K			(0x01 << 5)
-#define STB0899_OFFST_SHORT22K			5
-#define STB0899_WIDTH_SHORT22K			1
-#define STB0899_CONTTONE			(0x01 << 4)
-#define STB0899_OFFST_CONTTONE			4
-#define STB0899_WIDTH_CONTONE			1
-#define STB0899_4BFIFOREDY			(0x01 << 3)
-#define STB0899_OFFST_4BFIFOREDY		3
-#define STB0899_WIDTH_4BFIFOREDY		1
-#define STB0899_FIFOEMPTY			(0x01 << 2)
-#define STB0899_OFFST_FIFOEMPTY			2
-#define STB0899_WIDTH_FIFOEMPTY			1
-#define STB0899_ABORTTRX			(0x01 << 0)
-#define STB0899_OFFST_ABORTTRX			0
-#define STB0899_WIDTH_ABORTTRX			1
-
-#define STB0899_DISRX_ST1			0xf0a5
-#define STB0899_RXFAIL				(0x01 << 7)
-#define STB0899_OFFST_RXFAIL			7
-#define STB0899_WIDTH_RXFAIL			1
-#define STB0899_FIFOPFAIL			(0x01 << 6)
-#define STB0899_OFFST_FIFOPFAIL			6
-#define STB0899_WIDTH_FIFOPFAIL			1
-#define STB0899_RXNONBYTES			(0x01 << 5)
-#define STB0899_OFFST_RXNONBYTES		5
-#define STB0899_WIDTH_RXNONBYTES		1
-#define STB0899_FIFOOVF				(0x01 << 4)
-#define STB0899_OFFST_FIFOOVF			4
-#define STB0899_WIDTH_FIFOOVF			1
-#define STB0899_FIFOBYTENBR			(0x0f << 0)
-#define STB0899_OFFST_FIFOBYTENBR		0
-#define STB0899_WIDTH_FIFOBYTENBR		4
-
-#define STB0899_DISPARITY			0xf0a6
-
-#define STB0899_DISFIFO				0xf0a7
-
-#define STB0899_DISSTATUS			0xf0a8
-#define STB0899_FIFOFULL			(0x01 << 6)
-#define STB0899_OFFST_FIFOFULL			6
-#define STB0899_WIDTH_FIFOFULL			1
-#define STB0899_TXIDLE				(0x01 << 5)
-#define STB0899_OFFST_TXIDLE			5
-#define STB0899_WIDTH_TXIDLE			1
-#define STB0899_GAPBURST			(0x01 << 4)
-#define STB0899_OFFST_GAPBURST			4
-#define STB0899_WIDTH_GAPBURST			1
-#define STB0899_TXFIFOBYTES			(0x0f << 0)
-#define STB0899_OFFST_TXFIFOBYTES		0
-#define STB0899_WIDTH_TXFIFOBYTES		4
-#define STB0899_DISF22				0xf0a9
-
-#define STB0899_DISF22RX			0xf0aa
-
-/*	General Purpose	*/
-#define STB0899_SYSREG				0xf101
-#define STB0899_ACRPRESC			0xf110
-#define STB0899_OFFST_RSVD2			7
-#define STB0899_WIDTH_RSVD2			1
-#define STB0899_OFFST_ACRPRESC			4
-#define STB0899_WIDTH_ACRPRESC			3
-#define STB0899_OFFST_RSVD1			3
-#define STB0899_WIDTH_RSVD1			1
-#define STB0899_OFFST_ACRPRESC2			0
-#define STB0899_WIDTH_ACRPRESC2			3
-
-#define STB0899_ACRDIV1				0xf111
-#define STB0899_ACRDIV2				0xf112
-#define STB0899_DACR1				0xf113
-#define STB0899_DACR2				0xf114
-#define STB0899_OUTCFG				0xf11c
-#define STB0899_MODECFG				0xf11d
-#define STB0899_NCOARSE				0xf1b3
-
-#define STB0899_SYNTCTRL			0xf1b6
-#define STB0899_STANDBY				(0x01 << 7)
-#define STB0899_OFFST_STANDBY			7
-#define STB0899_WIDTH_STANDBY			1
-#define STB0899_BYPASSPLL			(0x01 << 6)
-#define STB0899_OFFST_BYPASSPLL			6
-#define STB0899_WIDTH_BYPASSPLL			1
-#define STB0899_SEL1XRATIO			(0x01 << 5)
-#define STB0899_OFFST_SEL1XRATIO		5
-#define STB0899_WIDTH_SEL1XRATIO		1
-#define STB0899_SELOSCI				(0x01 << 1)
-#define STB0899_OFFST_SELOSCI			1
-#define STB0899_WIDTH_SELOSCI			1
-
-#define STB0899_FILTCTRL			0xf1b7
-#define STB0899_SYSCTRL				0xf1b8
-
-#define STB0899_STOPCLK1			0xf1c2
-#define STB0899_STOP_CKINTBUF108		(0x01 << 7)
-#define STB0899_OFFST_STOP_CKINTBUF108		7
-#define STB0899_WIDTH_STOP_CKINTBUF108		1
-#define STB0899_STOP_CKINTBUF216		(0x01 << 6)
-#define STB0899_OFFST_STOP_CKINTBUF216		6
-#define STB0899_WIDTH_STOP_CKINTBUF216		1
-#define STB0899_STOP_CHK8PSK			(0x01 << 5)
-#define STB0899_OFFST_STOP_CHK8PSK		5
-#define STB0899_WIDTH_STOP_CHK8PSK		1
-#define STB0899_STOP_CKFEC108			(0x01 << 4)
-#define STB0899_OFFST_STOP_CKFEC108		4
-#define STB0899_WIDTH_STOP_CKFEC108		1
-#define STB0899_STOP_CKFEC216			(0x01 << 3)
-#define STB0899_OFFST_STOP_CKFEC216		3
-#define STB0899_WIDTH_STOP_CKFEC216		1
-#define STB0899_STOP_CKCORE216			(0x01 << 2)
-#define STB0899_OFFST_STOP_CKCORE216		2
-#define STB0899_WIDTH_STOP_CKCORE216		1
-#define STB0899_STOP_CKADCI108			(0x01 << 1)
-#define STB0899_OFFST_STOP_CKADCI108		1
-#define STB0899_WIDTH_STOP_CKADCI108		1
-#define STB0899_STOP_INVCKADCI108		(0x01 << 0)
-#define STB0899_OFFST_STOP_INVCKADCI108		0
-#define STB0899_WIDTH_STOP_INVCKADCI108		1
-
-#define STB0899_STOPCLK2			0xf1c3
-#define STB0899_STOP_CKS2DMD108			(0x01 << 2)
-#define STB0899_OFFST_STOP_CKS2DMD108		2
-#define STB0899_WIDTH_STOP_CKS2DMD108		1
-#define STB0899_STOP_CKPKDLIN108		(0x01 << 1)
-#define STB0899_OFFST_STOP_CKPKDLIN108		1
-#define STB0899_WIDTH_STOP_CKPKDLIN108		1
-#define STB0899_STOP_CKPKDLIN216		(0x01 << 0)
-#define STB0899_OFFST_STOP_CKPKDLIN216		0
-#define STB0899_WIDTH_STOP_CKPKDLIN216		1
-
-#define STB0899_TSTTNR1				0xf1e0
-#define STB0899_BYPASS_ADC			(0x01 << 7)
-#define STB0899_OFFST_BYPASS_ADC		7
-#define STB0899_WIDTH_BYPASS_ADC		1
-#define STB0899_INVADCICKOUT			(0x01 << 6)
-#define STB0899_OFFST_INVADCICKOUT		6
-#define STB0899_WIDTH_INVADCICKOUT		1
-#define STB0899_ADCTEST_VOLTAGE			(0x03 << 4)
-#define STB0899_OFFST_ADCTEST_VOLTAGE		4
-#define STB0899_WIDTH_ADCTEST_VOLTAGE		1
-#define STB0899_ADC_RESET			(0x01 << 3)
-#define STB0899_OFFST_ADC_RESET			3
-#define STB0899_WIDTH_ADC_RESET			1
-#define STB0899_TSTTNR1_2			(0x01 << 2)
-#define STB0899_OFFST_TSTTNR1_2			2
-#define STB0899_WIDTH_TSTTNR1_2			1
-#define STB0899_ADCPON				(0x01 << 1)
-#define STB0899_OFFST_ADCPON			1
-#define STB0899_WIDTH_ADCPON			1
-#define STB0899_ADCIN_MODE			(0x01 << 0)
-#define STB0899_OFFST_ADCIN_MODE		0
-#define STB0899_WIDTH_ADCIN_MODE		1
-
-#define STB0899_TSTTNR2				0xf1e1
-#define STB0899_TSTTNR2_7			(0x01 << 7)
-#define STB0899_OFFST_TSTTNR2_7			7
-#define STB0899_WIDTH_TSTTNR2_7			1
-#define STB0899_NOT_DISRX_WIRED			(0x01 << 6)
-#define STB0899_OFFST_NOT_DISRX_WIRED		6
-#define STB0899_WIDTH_NOT_DISRX_WIRED		1
-#define STB0899_DISEQC_DCURRENT			(0x01 << 5)
-#define STB0899_OFFST_DISEQC_DCURRENT		5
-#define STB0899_WIDTH_DISEQC_DCURRENT		1
-#define STB0899_DISEQC_ZCURRENT			(0x01 << 4)
-#define STB0899_OFFST_DISEQC_ZCURRENT		4
-#define STB0899_WIDTH_DISEQC_ZCURRENT		1
-#define STB0899_DISEQC_SINC_SOURCE		(0x03 << 2)
-#define STB0899_OFFST_DISEQC_SINC_SOURCE	2
-#define STB0899_WIDTH_DISEQC_SINC_SOURCE	2
-#define STB0899_SELIQSRC			(0x03 << 0)
-#define STB0899_OFFST_SELIQSRC			0
-#define STB0899_WIDTH_SELIQSRC			2
-
-#define STB0899_TSTTNR3				0xf1e2
-
-#define STB0899_I2CCFG				0xf129
-#define STB0899_I2CCFGRSVD			(0x0f << 4)
-#define STB0899_OFFST_I2CCFGRSVD		4
-#define STB0899_WIDTH_I2CCFGRSVD		4
-#define STB0899_I2CFASTMODE			(0x01 << 3)
-#define STB0899_OFFST_I2CFASTMODE		3
-#define STB0899_WIDTH_I2CFASTMODE		1
-#define STB0899_STATUSWR			(0x01 << 2)
-#define STB0899_OFFST_STATUSWR			2
-#define STB0899_WIDTH_STATUSWR			1
-#define STB0899_I2CADDRINC			(0x03 << 0)
-#define STB0899_OFFST_I2CADDRINC		0
-#define STB0899_WIDTH_I2CADDRINC		2
-
-#define STB0899_I2CRPT				0xf12a
-#define STB0899_I2CTON				(0x01 << 7)
-#define STB0899_OFFST_I2CTON			7
-#define STB0899_WIDTH_I2CTON			1
-#define STB0899_ENARPTLEVEL			(0x01 << 6)
-#define STB0899_OFFST_ENARPTLEVEL		6
-#define STB0899_WIDTH_ENARPTLEVEL		2
-#define STB0899_SCLTDELAY			(0x01 << 3)
-#define STB0899_OFFST_SCLTDELAY			3
-#define STB0899_WIDTH_SCLTDELAY			1
-#define STB0899_STOPENA				(0x01 << 2)
-#define STB0899_OFFST_STOPENA			2
-#define STB0899_WIDTH_STOPENA			1
-#define STB0899_STOPSDAT2SDA			(0x01 << 1)
-#define STB0899_OFFST_STOPSDAT2SDA		1
-#define STB0899_WIDTH_STOPSDAT2SDA		1
-
-#define STB0899_IOPVALUE8			0xf136
-#define STB0899_IOPVALUE7			0xf137
-#define STB0899_IOPVALUE6			0xf138
-#define STB0899_IOPVALUE5			0xf139
-#define STB0899_IOPVALUE4			0xf13a
-#define STB0899_IOPVALUE3			0xf13b
-#define STB0899_IOPVALUE2			0xf13c
-#define STB0899_IOPVALUE1			0xf13d
-#define STB0899_IOPVALUE0			0xf13e
-
-#define STB0899_GPIO00CFG			0xf140
-
-#define STB0899_GPIO01CFG			0xf141
-#define STB0899_GPIO02CFG			0xf142
-#define STB0899_GPIO03CFG			0xf143
-#define STB0899_GPIO04CFG			0xf144
-#define STB0899_GPIO05CFG			0xf145
-#define STB0899_GPIO06CFG			0xf146
-#define STB0899_GPIO07CFG			0xf147
-#define STB0899_GPIO08CFG			0xf148
-#define STB0899_GPIO09CFG			0xf149
-#define STB0899_GPIO10CFG			0xf14a
-#define STB0899_GPIO11CFG			0xf14b
-#define STB0899_GPIO12CFG			0xf14c
-#define STB0899_GPIO13CFG			0xf14d
-#define STB0899_GPIO14CFG			0xf14e
-#define STB0899_GPIO15CFG			0xf14f
-#define STB0899_GPIO16CFG			0xf150
-#define STB0899_GPIO17CFG			0xf151
-#define STB0899_GPIO18CFG			0xf152
-#define STB0899_GPIO19CFG			0xf153
-#define STB0899_GPIO20CFG			0xf154
-
-#define STB0899_SDATCFG				0xf155
-#define STB0899_SCLTCFG				0xf156
-#define STB0899_AGCRFCFG			0xf157
-#define STB0899_GPIO22				0xf158	/* AGCBB2CFG	*/
-#define STB0899_GPIO21				0xf159  /* AGCBB1CFG	*/
-#define STB0899_DIRCLKCFG			0xf15a
-#define STB0899_CLKOUT27CFG			0xf15b
-#define STB0899_STDBYCFG			0xf15c
-#define STB0899_CS0CFG				0xf15d
-#define STB0899_CS1CFG				0xf15e
-#define STB0899_DISEQCOCFG			0xf15f
-
-#define STB0899_GPIO32CFG			0xf160
-#define STB0899_GPIO33CFG			0xf161
-#define STB0899_GPIO34CFG			0xf162
-#define STB0899_GPIO35CFG			0xf163
-#define STB0899_GPIO36CFG			0xf164
-#define STB0899_GPIO37CFG			0xf165
-#define STB0899_GPIO38CFG			0xf166
-#define STB0899_GPIO39CFG			0xf167
-
-#define STB0899_IRQSTATUS_3			0xf120
-#define STB0899_IRQSTATUS_2			0xf121
-#define STB0899_IRQSTATUS_1			0xf122
-#define STB0899_IRQSTATUS_0			0xf123
-
-#define STB0899_IRQMSK_3			0xf124
-#define STB0899_IRQMSK_2			0xf125
-#define STB0899_IRQMSK_1			0xf126
-#define STB0899_IRQMSK_0			0xf127
-
-#define STB0899_IRQCFG				0xf128
-
-#define STB0899_GHOSTREG			0xf000
-
-#define STB0899_S2DEMOD				0xf3fc
-#define STB0899_S2FEC				0xfafc
-
-
-#endif
diff --git a/drivers/media/dvb/frontends/stb6000.c b/drivers/media/dvb/frontends/stb6000.c
deleted file mode 100644
index a0c3c52..0000000
--- a/drivers/media/dvb/frontends/stb6000.c
+++ /dev/null
@@ -1,256 +0,0 @@
-  /*
-     Driver for ST STB6000 DVBS Silicon tuner
-
-     Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
-
-     This program is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published by
-     the Free Software Foundation; either version 2 of the License, or
-     (at your option) any later version.
-
-     This program is distributed in the hope that it will be useful,
-     but WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-     GNU General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with this program; if not, write to the Free Software
-     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-  */
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/dvb/frontend.h>
-#include <asm/types.h>
-
-#include "stb6000.h"
-
-static int debug;
-#define dprintk(args...) \
-	do { \
-		if (debug) \
-			printk(KERN_DEBUG "stb6000: " args); \
-	} while (0)
-
-struct stb6000_priv {
-	/* i2c details */
-	int i2c_address;
-	struct i2c_adapter *i2c;
-	u32 frequency;
-};
-
-static int stb6000_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static int stb6000_sleep(struct dvb_frontend *fe)
-{
-	struct stb6000_priv *priv = fe->tuner_priv;
-	int ret;
-	u8 buf[] = { 10, 0 };
-	struct i2c_msg msg = {
-		.addr = priv->i2c_address,
-		.flags = 0,
-		.buf = buf,
-		.len = 2
-	};
-
-	dprintk("%s:\n", __func__);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	ret = i2c_transfer(priv->i2c, &msg, 1);
-	if (ret != 1)
-		dprintk("%s: i2c error\n", __func__);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	return (ret == 1) ? 0 : ret;
-}
-
-static int stb6000_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct stb6000_priv *priv = fe->tuner_priv;
-	unsigned int n, m;
-	int ret;
-	u32 freq_mhz;
-	int bandwidth;
-	u8 buf[12];
-	struct i2c_msg msg = {
-		.addr = priv->i2c_address,
-		.flags = 0,
-		.buf = buf,
-		.len = 12
-	};
-
-	dprintk("%s:\n", __func__);
-
-	freq_mhz = p->frequency / 1000;
-	bandwidth = p->symbol_rate / 1000000;
-
-	if (bandwidth > 31)
-		bandwidth = 31;
-
-	if ((freq_mhz > 949) && (freq_mhz < 2151)) {
-		buf[0] = 0x01;
-		buf[1] = 0xac;
-		if (freq_mhz < 1950)
-			buf[1] = 0xaa;
-		if (freq_mhz < 1800)
-			buf[1] = 0xa8;
-		if (freq_mhz < 1650)
-			buf[1] = 0xa6;
-		if (freq_mhz < 1530)
-			buf[1] = 0xa5;
-		if (freq_mhz < 1470)
-			buf[1] = 0xa4;
-		if (freq_mhz < 1370)
-			buf[1] = 0xa2;
-		if (freq_mhz < 1300)
-			buf[1] = 0xa1;
-		if (freq_mhz < 1200)
-			buf[1] = 0xa0;
-		if (freq_mhz < 1075)
-			buf[1] = 0xbc;
-		if (freq_mhz < 1000)
-			buf[1] = 0xba;
-		if (freq_mhz < 1075) {
-			n = freq_mhz / 8; /* vco=lo*4 */
-			m = 2;
-		} else {
-			n = freq_mhz / 16; /* vco=lo*2 */
-			m = 1;
-		}
-		buf[2] = n >> 1;
-		buf[3] = (unsigned char)(((n & 1) << 7) |
-					(m * freq_mhz - n * 16) | 0x60);
-		buf[4] = 0x04;
-		buf[5] = 0x0e;
-
-		buf[6] = (unsigned char)(bandwidth);
-
-		buf[7] = 0xd8;
-		buf[8] = 0xd0;
-		buf[9] = 0x50;
-		buf[10] = 0xeb;
-		buf[11] = 0x4f;
-
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-
-		ret = i2c_transfer(priv->i2c, &msg, 1);
-		if (ret != 1)
-			dprintk("%s: i2c error\n", __func__);
-
-		udelay(10);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-
-		buf[0] = 0x07;
-		buf[1] = 0xdf;
-		buf[2] = 0xd0;
-		buf[3] = 0x50;
-		buf[4] = 0xfb;
-		msg.len = 5;
-
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-
-		ret = i2c_transfer(priv->i2c, &msg, 1);
-		if (ret != 1)
-			dprintk("%s: i2c error\n", __func__);
-
-		udelay(10);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-
-		priv->frequency = freq_mhz * 1000;
-
-		return (ret == 1) ? 0 : ret;
-	}
-	return -1;
-}
-
-static int stb6000_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct stb6000_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-	return 0;
-}
-
-static struct dvb_tuner_ops stb6000_tuner_ops = {
-	.info = {
-		.name = "ST STB6000",
-		.frequency_min = 950000,
-		.frequency_max = 2150000
-	},
-	.release = stb6000_release,
-	.sleep = stb6000_sleep,
-	.set_params = stb6000_set_params,
-	.get_frequency = stb6000_get_frequency,
-};
-
-struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr,
-						struct i2c_adapter *i2c)
-{
-	struct stb6000_priv *priv = NULL;
-	u8 b0[] = { 0 };
-	u8 b1[] = { 0, 0 };
-	struct i2c_msg msg[2] = {
-		{
-			.addr = addr,
-			.flags = 0,
-			.buf = b0,
-			.len = 0
-		}, {
-			.addr = addr,
-			.flags = I2C_M_RD,
-			.buf = b1,
-			.len = 2
-		}
-	};
-	int ret;
-
-	dprintk("%s:\n", __func__);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	/* is some i2c device here ? */
-	ret = i2c_transfer(i2c, msg, 2);
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	if (ret != 2)
-		return NULL;
-
-	priv = kzalloc(sizeof(struct stb6000_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	priv->i2c_address = addr;
-	priv->i2c = i2c;
-
-	memcpy(&fe->ops.tuner_ops, &stb6000_tuner_ops,
-				sizeof(struct dvb_tuner_ops));
-
-	fe->tuner_priv = priv;
-
-	return fe;
-}
-EXPORT_SYMBOL(stb6000_attach);
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("DVB STB6000 driver");
-MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stb6000.h b/drivers/media/dvb/frontends/stb6000.h
deleted file mode 100644
index 7be479c..0000000
--- a/drivers/media/dvb/frontends/stb6000.h
+++ /dev/null
@@ -1,51 +0,0 @@
-  /*
-     Driver for ST stb6000 DVBS Silicon tuner
-
-     Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
-
-     This program is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published by
-     the Free Software Foundation; either version 2 of the License, or
-     (at your option) any later version.
-
-     This program is distributed in the hope that it will be useful,
-     but WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-     GNU General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with this program; if not, write to the Free Software
-     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-  */
-
-#ifndef __DVB_STB6000_H__
-#define __DVB_STB6000_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-/**
- * Attach a stb6000 tuner to the supplied frontend structure.
- *
- * @param fe Frontend to attach to.
- * @param addr i2c address of the tuner.
- * @param i2c i2c adapter to use.
- * @return FE pointer on success, NULL on failure.
- */
-#if defined(CONFIG_DVB_STB6000) || (defined(CONFIG_DVB_STB6000_MODULE) \
-							&& defined(MODULE))
-extern struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr,
-					   struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe,
-						  int addr,
-						  struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_STB6000 */
-
-#endif /* __DVB_STB6000_H__ */
diff --git a/drivers/media/dvb/frontends/stb6100.c b/drivers/media/dvb/frontends/stb6100.c
deleted file mode 100644
index 2e93e65..0000000
--- a/drivers/media/dvb/frontends/stb6100.c
+++ /dev/null
@@ -1,611 +0,0 @@
-/*
-	STB6100 Silicon Tuner
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	Copyright (C) ST Microelectronics
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-
-#include "dvb_frontend.h"
-#include "stb6100.h"
-
-static unsigned int verbose;
-module_param(verbose, int, 0644);
-
-
-#define FE_ERROR		0
-#define FE_NOTICE		1
-#define FE_INFO			2
-#define FE_DEBUG		3
-
-#define dprintk(x, y, z, format, arg...) do {						\
-	if (z) {									\
-		if	((x > FE_ERROR) && (x > y))					\
-			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);		\
-		else if	((x > FE_NOTICE) && (x > y))					\
-			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
-		else if ((x > FE_INFO) && (x > y))					\
-			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);		\
-		else if ((x > FE_DEBUG) && (x > y))					\
-			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
-	} else {									\
-		if (x > y)								\
-			printk(format, ##arg);						\
-	}										\
-} while (0)
-
-struct stb6100_lkup {
-	u32 val_low;
-	u32 val_high;
-	u8   reg;
-};
-
-static int stb6100_release(struct dvb_frontend *fe);
-
-static const struct stb6100_lkup lkup[] = {
-	{       0,  950000, 0x0a },
-	{  950000, 1000000, 0x0a },
-	{ 1000000, 1075000, 0x0c },
-	{ 1075000, 1200000, 0x00 },
-	{ 1200000, 1300000, 0x01 },
-	{ 1300000, 1370000, 0x02 },
-	{ 1370000, 1470000, 0x04 },
-	{ 1470000, 1530000, 0x05 },
-	{ 1530000, 1650000, 0x06 },
-	{ 1650000, 1800000, 0x08 },
-	{ 1800000, 1950000, 0x0a },
-	{ 1950000, 2150000, 0x0c },
-	{ 2150000, 9999999, 0x0c },
-	{       0,       0, 0x00 }
-};
-
-/* Register names for easy debugging.	*/
-static const char *stb6100_regnames[] = {
-	[STB6100_LD]		= "LD",
-	[STB6100_VCO]		= "VCO",
-	[STB6100_NI]		= "NI",
-	[STB6100_NF_LSB]	= "NF",
-	[STB6100_K]		= "K",
-	[STB6100_G]		= "G",
-	[STB6100_F]		= "F",
-	[STB6100_DLB]		= "DLB",
-	[STB6100_TEST1]		= "TEST1",
-	[STB6100_FCCK]		= "FCCK",
-	[STB6100_LPEN]		= "LPEN",
-	[STB6100_TEST3]		= "TEST3",
-};
-
-/* Template for normalisation, i.e. setting unused or undocumented
- * bits as required according to the documentation.
- */
-struct stb6100_regmask {
-	u8 mask;
-	u8 set;
-};
-
-static const struct stb6100_regmask stb6100_template[] = {
-	[STB6100_LD]		= { 0xff, 0x00 },
-	[STB6100_VCO]		= { 0xff, 0x00 },
-	[STB6100_NI]		= { 0xff, 0x00 },
-	[STB6100_NF_LSB]	= { 0xff, 0x00 },
-	[STB6100_K]		= { 0xc7, 0x38 },
-	[STB6100_G]		= { 0xef, 0x10 },
-	[STB6100_F]		= { 0x1f, 0xc0 },
-	[STB6100_DLB]		= { 0x38, 0xc4 },
-	[STB6100_TEST1]		= { 0x00, 0x8f },
-	[STB6100_FCCK]		= { 0x40, 0x0d },
-	[STB6100_LPEN]		= { 0xf0, 0x0b },
-	[STB6100_TEST3]		= { 0x00, 0xde },
-};
-
-/*
- * Currently unused. Some boards might need it in the future
- */
-static inline void stb6100_normalise_regs(u8 regs[])
-{
-	int i;
-
-	for (i = 0; i < STB6100_NUMREGS; i++)
-		regs[i] = (regs[i] & stb6100_template[i].mask) | stb6100_template[i].set;
-}
-
-static int stb6100_read_regs(struct stb6100_state *state, u8 regs[])
-{
-	int rc;
-	struct i2c_msg msg = {
-		.addr	= state->config->tuner_address,
-		.flags	= I2C_M_RD,
-		.buf	= regs,
-		.len	= STB6100_NUMREGS
-	};
-
-	rc = i2c_transfer(state->i2c, &msg, 1);
-	if (unlikely(rc != 1)) {
-		dprintk(verbose, FE_ERROR, 1, "Read (0x%x) err, rc=[%d]",
-			state->config->tuner_address, rc);
-
-		return -EREMOTEIO;
-	}
-	if (unlikely(verbose > FE_DEBUG)) {
-		int i;
-
-		dprintk(verbose, FE_DEBUG, 1, "    Read from 0x%02x", state->config->tuner_address);
-		for (i = 0; i < STB6100_NUMREGS; i++)
-			dprintk(verbose, FE_DEBUG, 1, "        %s: 0x%02x", stb6100_regnames[i], regs[i]);
-	}
-	return 0;
-}
-
-static int stb6100_read_reg(struct stb6100_state *state, u8 reg)
-{
-	u8 regs[STB6100_NUMREGS];
-
-	struct i2c_msg msg = {
-		.addr	= state->config->tuner_address + reg,
-		.flags	= I2C_M_RD,
-		.buf	= regs,
-		.len	= 1
-	};
-
-	i2c_transfer(state->i2c, &msg, 1);
-
-	if (unlikely(reg >= STB6100_NUMREGS)) {
-		dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
-		return -EINVAL;
-	}
-	if (unlikely(verbose > FE_DEBUG)) {
-		dprintk(verbose, FE_DEBUG, 1, "    Read from 0x%02x", state->config->tuner_address);
-		dprintk(verbose, FE_DEBUG, 1, "        %s: 0x%02x", stb6100_regnames[reg], regs[0]);
-	}
-
-	return (unsigned int)regs[0];
-}
-
-static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int start, int len)
-{
-	int rc;
-	u8 cmdbuf[len + 1];
-	struct i2c_msg msg = {
-		.addr	= state->config->tuner_address,
-		.flags	= 0,
-		.buf	= cmdbuf,
-		.len	= len + 1
-	};
-
-	if (unlikely(start < 1 || start + len > STB6100_NUMREGS)) {
-		dprintk(verbose, FE_ERROR, 1, "Invalid register range %d:%d",
-			start, len);
-		return -EINVAL;
-	}
-	memcpy(&cmdbuf[1], buf, len);
-	cmdbuf[0] = start;
-
-	if (unlikely(verbose > FE_DEBUG)) {
-		int i;
-
-		dprintk(verbose, FE_DEBUG, 1, "    Write @ 0x%02x: [%d:%d]", state->config->tuner_address, start, len);
-		for (i = 0; i < len; i++)
-			dprintk(verbose, FE_DEBUG, 1, "        %s: 0x%02x", stb6100_regnames[start + i], buf[i]);
-	}
-	rc = i2c_transfer(state->i2c, &msg, 1);
-	if (unlikely(rc != 1)) {
-		dprintk(verbose, FE_ERROR, 1, "(0x%x) write err [%d:%d], rc=[%d]",
-			(unsigned int)state->config->tuner_address, start, len,	rc);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data)
-{
-	if (unlikely(reg >= STB6100_NUMREGS)) {
-		dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
-		return -EREMOTEIO;
-	}
-	data = (data & stb6100_template[reg].mask) | stb6100_template[reg].set;
-	return stb6100_write_reg_range(state, &data, reg, 1);
-}
-
-
-static int stb6100_get_status(struct dvb_frontend *fe, u32 *status)
-{
-	int rc;
-	struct stb6100_state *state = fe->tuner_priv;
-
-	rc = stb6100_read_reg(state, STB6100_LD);
-	if (rc < 0) {
-		dprintk(verbose, FE_ERROR, 1, "%s failed", __func__);
-		return rc;
-	}
-	return (rc & STB6100_LD_LOCK) ? TUNER_STATUS_LOCKED : 0;
-}
-
-static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	int rc;
-	u8 f;
-	struct stb6100_state *state = fe->tuner_priv;
-
-	rc = stb6100_read_reg(state, STB6100_F);
-	if (rc < 0)
-		return rc;
-	f = rc & STB6100_F_F;
-
-	state->status.bandwidth = (f + 5) * 2000;	/* x2 for ZIF	*/
-
-	*bandwidth = state->bandwidth = state->status.bandwidth * 1000;
-	dprintk(verbose, FE_DEBUG, 1, "bandwidth = %u Hz", state->bandwidth);
-	return 0;
-}
-
-static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
-{
-	u32 tmp;
-	int rc;
-	struct stb6100_state *state = fe->tuner_priv;
-
-	dprintk(verbose, FE_DEBUG, 1, "set bandwidth to %u Hz", bandwidth);
-
-	bandwidth /= 2; /* ZIF */
-
-	if (bandwidth >= 36000000)	/* F[4:0] BW/2 max =31+5=36 mhz for F=31	*/
-		tmp = 31;
-	else if (bandwidth <= 5000000)	/* bw/2 min = 5Mhz for F=0			*/
-		tmp = 0;
-	else				/* if 5 < bw/2 < 36				*/
-		tmp = (bandwidth + 500000) / 1000000 - 5;
-
-	/* Turn on LPF bandwidth setting clock control,
-	 * set bandwidth, wait 10ms, turn off.
-	 */
-	rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d | STB6100_FCCK_FCCK);
-	if (rc < 0)
-		return rc;
-	rc = stb6100_write_reg(state, STB6100_F, 0xc0 | tmp);
-	if (rc < 0)
-		return rc;
-
-	msleep(5);  /*  This is dangerous as another (related) thread may start */
-
-	rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d);
-	if (rc < 0)
-		return rc;
-
-	msleep(10);  /*  This is dangerous as another (related) thread may start */
-
-	return 0;
-}
-
-static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	int rc;
-	u32 nint, nfrac, fvco;
-	int psd2, odiv;
-	struct stb6100_state *state = fe->tuner_priv;
-	u8 regs[STB6100_NUMREGS];
-
-	rc = stb6100_read_regs(state, regs);
-	if (rc < 0)
-		return rc;
-
-	odiv = (regs[STB6100_VCO] & STB6100_VCO_ODIV) >> STB6100_VCO_ODIV_SHIFT;
-	psd2 = (regs[STB6100_K] & STB6100_K_PSD2) >> STB6100_K_PSD2_SHIFT;
-	nint = regs[STB6100_NI];
-	nfrac = ((regs[STB6100_K] & STB6100_K_NF_MSB) << 8) | regs[STB6100_NF_LSB];
-	fvco = (nfrac * state->reference >> (9 - psd2)) + (nint * state->reference << psd2);
-	*frequency = state->frequency = fvco >> (odiv + 1);
-
-	dprintk(verbose, FE_DEBUG, 1,
-		"frequency = %u kHz, odiv = %u, psd2 = %u, fxtal = %u kHz, fvco = %u kHz, N(I) = %u, N(F) = %u",
-		state->frequency, odiv, psd2, state->reference,	fvco, nint, nfrac);
-	return 0;
-}
-
-
-static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
-{
-	int rc;
-	const struct stb6100_lkup *ptr;
-	struct stb6100_state *state = fe->tuner_priv;
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-
-	u32 srate = 0, fvco, nint, nfrac;
-	u8 regs[STB6100_NUMREGS];
-	u8 g, psd2, odiv;
-
-	dprintk(verbose, FE_DEBUG, 1, "Version 2010-8-14 13:51");
-
-	if (fe->ops.get_frontend) {
-		dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters");
-		fe->ops.get_frontend(fe);
-	}
-	srate = p->symbol_rate;
-
-	/* Set up tuner cleanly, LPF calibration on */
-	rc = stb6100_write_reg(state, STB6100_FCCK, 0x4d | STB6100_FCCK_FCCK);
-	if (rc < 0)
-		return rc;  /* allow LPF calibration */
-
-	/* PLL Loop disabled, bias on, VCO on, synth on */
-	regs[STB6100_LPEN] = 0xeb;
-	rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]);
-	if (rc < 0)
-		return rc;
-
-	/* Program the registers with their data values */
-
-	/* VCO divide ratio (LO divide ratio, VCO prescaler enable).	*/
-	if (frequency <= 1075000)
-		odiv = 1;
-	else
-		odiv = 0;
-
-	/* VCO enabled, search clock off as per LL3.7, 3.4.1 */
-	regs[STB6100_VCO] = 0xe0 | (odiv << STB6100_VCO_ODIV_SHIFT);
-
-	/* OSM	*/
-	for (ptr = lkup;
-	     (ptr->val_high != 0) && !CHKRANGE(frequency, ptr->val_low, ptr->val_high);
-	     ptr++);
-
-	if (ptr->val_high == 0) {
-		printk(KERN_ERR "%s: frequency out of range: %u kHz\n", __func__, frequency);
-		return -EINVAL;
-	}
-	regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_OSM) | ptr->reg;
-	rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]);
-	if (rc < 0)
-		return rc;
-
-	if ((frequency > 1075000) && (frequency <= 1325000))
-		psd2 = 0;
-	else
-		psd2 = 1;
-	/* F(VCO) = F(LO) * (ODIV == 0 ? 2 : 4)			*/
-	fvco = frequency << (1 + odiv);
-	/* N(I) = floor(f(VCO) / (f(XTAL) * (PSD2 ? 2 : 1)))	*/
-	nint = fvco / (state->reference << psd2);
-	/* N(F) = round(f(VCO) / f(XTAL) * (PSD2 ? 2 : 1) - N(I)) * 2 ^ 9	*/
-	nfrac = DIV_ROUND_CLOSEST((fvco - (nint * state->reference << psd2))
-					 << (9 - psd2), state->reference);
-
-	/* NI */
-	regs[STB6100_NI] = nint;
-	rc = stb6100_write_reg(state, STB6100_NI, regs[STB6100_NI]);
-	if (rc < 0)
-		return rc;
-
-	/* NF */
-	regs[STB6100_NF_LSB] = nfrac;
-	rc = stb6100_write_reg(state, STB6100_NF_LSB, regs[STB6100_NF_LSB]);
-	if (rc < 0)
-		return rc;
-
-	/* K */
-	regs[STB6100_K] = (0x38 & ~STB6100_K_PSD2) | (psd2 << STB6100_K_PSD2_SHIFT);
-	regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_NF_MSB) | ((nfrac >> 8) & STB6100_K_NF_MSB);
-	rc = stb6100_write_reg(state, STB6100_K, regs[STB6100_K]);
-	if (rc < 0)
-		return rc;
-
-	/* G Baseband gain. */
-	if (srate >= 15000000)
-		g = 9;  /*  +4 dB */
-	else if (srate >= 5000000)
-		g = 11; /*  +8 dB */
-	else
-		g = 14; /* +14 dB */
-
-	regs[STB6100_G] = (0x10 & ~STB6100_G_G) | g;
-	regs[STB6100_G] &= ~STB6100_G_GCT; /* mask GCT */
-	regs[STB6100_G] |= (1 << 5); /* 2Vp-p Mode */
-	rc = stb6100_write_reg(state, STB6100_G, regs[STB6100_G]);
-	if (rc < 0)
-		return rc;
-
-	/* F we don't write as it is set up in BW set */
-
-	/* DLB set DC servo loop BW to 160Hz (LLA 3.8 / 2.1) */
-	regs[STB6100_DLB] = 0xcc;
-	rc = stb6100_write_reg(state, STB6100_DLB, regs[STB6100_DLB]);
-	if (rc < 0)
-		return rc;
-
-	dprintk(verbose, FE_DEBUG, 1,
-		"frequency = %u, srate = %u, g = %u, odiv = %u, psd2 = %u, fxtal = %u, osm = %u, fvco = %u, N(I) = %u, N(F) = %u",
-		frequency, srate, (unsigned int)g, (unsigned int)odiv,
-		(unsigned int)psd2, state->reference,
-		ptr->reg, fvco, nint, nfrac);
-
-	/* Set up the test registers */
-	regs[STB6100_TEST1] = 0x8f;
-	rc = stb6100_write_reg(state, STB6100_TEST1, regs[STB6100_TEST1]);
-	if (rc < 0)
-		return rc;
-	regs[STB6100_TEST3] = 0xde;
-	rc = stb6100_write_reg(state, STB6100_TEST3, regs[STB6100_TEST3]);
-	if (rc < 0)
-		return rc;
-
-	/* Bring up tuner according to LLA 3.7 3.4.1, step 2 */
-	regs[STB6100_LPEN] = 0xfb; /* PLL Loop enabled, bias on, VCO on, synth on */
-	rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]);
-	if (rc < 0)
-		return rc;
-
-	msleep(2);
-
-	/* Bring up tuner according to LLA 3.7 3.4.1, step 3 */
-	regs[STB6100_VCO] &= ~STB6100_VCO_OCK;		/* VCO fast search		*/
-	rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]);
-	if (rc < 0)
-		return rc;
-
-	msleep(10);  /*  This is dangerous as another (related) thread may start */ /* wait for LO to lock */
-
-	regs[STB6100_VCO] &= ~STB6100_VCO_OSCH;		/* vco search disabled		*/
-	regs[STB6100_VCO] |= STB6100_VCO_OCK;		/* search clock off		*/
-	rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]);
-	if (rc < 0)
-		return rc;
-
-	rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d);
-	if (rc < 0)
-		return rc;  /* Stop LPF calibration */
-
-	msleep(10);  /*  This is dangerous as another (related) thread may start */
-		     /* wait for stabilisation, (should not be necessary)		*/
-	return 0;
-}
-
-static int stb6100_sleep(struct dvb_frontend *fe)
-{
-	/* TODO: power down	*/
-	return 0;
-}
-
-static int stb6100_init(struct dvb_frontend *fe)
-{
-	struct stb6100_state *state = fe->tuner_priv;
-	struct tuner_state *status = &state->status;
-
-	status->tunerstep	= 125000;
-	status->ifreq		= 0;
-	status->refclock	= 27000000;	/* Hz	*/
-	status->iqsense		= 1;
-	status->bandwidth	= 36000;	/* kHz	*/
-	state->bandwidth	= status->bandwidth * 1000;	/* Hz	*/
-	state->reference	= status->refclock / 1000;	/* kHz	*/
-
-	/* Set default bandwidth. Modified, PN 13-May-10	*/
-	return 0;
-}
-
-static int stb6100_get_state(struct dvb_frontend *fe,
-			     enum tuner_param param,
-			     struct tuner_state *state)
-{
-	switch (param) {
-	case DVBFE_TUNER_FREQUENCY:
-		stb6100_get_frequency(fe, &state->frequency);
-		break;
-	case DVBFE_TUNER_TUNERSTEP:
-		break;
-	case DVBFE_TUNER_IFFREQ:
-		break;
-	case DVBFE_TUNER_BANDWIDTH:
-		stb6100_get_bandwidth(fe, &state->bandwidth);
-		break;
-	case DVBFE_TUNER_REFCLOCK:
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static int stb6100_set_state(struct dvb_frontend *fe,
-			     enum tuner_param param,
-			     struct tuner_state *state)
-{
-	struct stb6100_state *tstate = fe->tuner_priv;
-
-	switch (param) {
-	case DVBFE_TUNER_FREQUENCY:
-		stb6100_set_frequency(fe, state->frequency);
-		tstate->frequency = state->frequency;
-		break;
-	case DVBFE_TUNER_TUNERSTEP:
-		break;
-	case DVBFE_TUNER_IFFREQ:
-		break;
-	case DVBFE_TUNER_BANDWIDTH:
-		stb6100_set_bandwidth(fe, state->bandwidth);
-		tstate->bandwidth = state->bandwidth;
-		break;
-	case DVBFE_TUNER_REFCLOCK:
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static struct dvb_tuner_ops stb6100_ops = {
-	.info = {
-		.name			= "STB6100 Silicon Tuner",
-		.frequency_min		= 950000,
-		.frequency_max		= 2150000,
-		.frequency_step		= 0,
-	},
-
-	.init		= stb6100_init,
-	.sleep          = stb6100_sleep,
-	.get_status	= stb6100_get_status,
-	.get_state	= stb6100_get_state,
-	.set_state	= stb6100_set_state,
-	.release	= stb6100_release
-};
-
-struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
-				    const struct stb6100_config *config,
-				    struct i2c_adapter *i2c)
-{
-	struct stb6100_state *state = NULL;
-
-	state = kzalloc(sizeof (struct stb6100_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	state->config		= config;
-	state->i2c		= i2c;
-	state->frontend		= fe;
-	state->reference	= config->refclock / 1000; /* kHz */
-	fe->tuner_priv		= state;
-	fe->ops.tuner_ops	= stb6100_ops;
-
-	printk("%s: Attaching STB6100 \n", __func__);
-	return fe;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static int stb6100_release(struct dvb_frontend *fe)
-{
-	struct stb6100_state *state = fe->tuner_priv;
-
-	fe->tuner_priv = NULL;
-	kfree(state);
-
-	return 0;
-}
-
-EXPORT_SYMBOL(stb6100_attach);
-MODULE_PARM_DESC(verbose, "Set Verbosity level");
-
-MODULE_AUTHOR("Manu Abraham");
-MODULE_DESCRIPTION("STB6100 Silicon tuner");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stb6100.h b/drivers/media/dvb/frontends/stb6100.h
deleted file mode 100644
index 2ab0966..0000000
--- a/drivers/media/dvb/frontends/stb6100.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
-	STB6100 Silicon Tuner
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	Copyright (C) ST Microelectronics
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __STB_6100_REG_H
-#define __STB_6100_REG_H
-
-#include <linux/dvb/frontend.h>
-#include "dvb_frontend.h"
-
-#define STB6100_LD			0x00
-#define STB6100_LD_LOCK			(1 << 0)
-
-#define STB6100_VCO			0x01
-#define STB6100_VCO_OSCH		(0x01 << 7)
-#define STB6100_VCO_OSCH_SHIFT		7
-#define STB6100_VCO_OCK			(0x03 << 5)
-#define STB6100_VCO_OCK_SHIFT		5
-#define STB6100_VCO_ODIV		(0x01 << 4)
-#define STB6100_VCO_ODIV_SHIFT		4
-#define STB6100_VCO_OSM			(0x0f << 0)
-
-#define STB6100_NI			0x02
-#define STB6100_NF_LSB			0x03
-
-#define STB6100_K			0x04
-#define STB6100_K_PSD2			(0x01 << 2)
-#define STB6100_K_PSD2_SHIFT            2
-#define STB6100_K_NF_MSB		(0x03 << 0)
-
-#define STB6100_G			0x05
-#define STB6100_G_G			(0x0f << 0)
-#define STB6100_G_GCT			(0x07 << 5)
-
-#define STB6100_F			0x06
-#define STB6100_F_F			(0x1f << 0)
-
-#define STB6100_DLB			0x07
-
-#define STB6100_TEST1			0x08
-
-#define STB6100_FCCK			0x09
-#define STB6100_FCCK_FCCK		(0x01 << 6)
-
-#define STB6100_LPEN			0x0a
-#define STB6100_LPEN_LPEN		(0x01 << 4)
-#define STB6100_LPEN_SYNP		(0x01 << 5)
-#define STB6100_LPEN_OSCP		(0x01 << 6)
-#define STB6100_LPEN_BEN		(0x01 << 7)
-
-#define STB6100_TEST3			0x0b
-
-#define STB6100_NUMREGS                 0x0c
-
-
-#define INRANGE(val, x, y)		(((x <= val) && (val <= y)) ||		\
-					 ((y <= val) && (val <= x)) ? 1 : 0)
-
-#define CHKRANGE(val, x, y)		(((val >= x) && (val < y)) ? 1 : 0)
-
-struct stb6100_config {
-	u8	tuner_address;
-	u32	refclock;
-};
-
-struct stb6100_state {
-	struct i2c_adapter *i2c;
-
-	const struct stb6100_config	*config;
-	struct dvb_tuner_ops		ops;
-	struct dvb_frontend		*frontend;
-	struct tuner_state		status;
-
-	u32 frequency;
-	u32 srate;
-	u32 bandwidth;
-	u32 reference;
-};
-
-#if defined(CONFIG_DVB_STB6100) || (defined(CONFIG_DVB_STB6100_MODULE) && defined(MODULE))
-
-extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
-					   const struct stb6100_config *config,
-					   struct i2c_adapter *i2c);
-
-#else
-
-static inline struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
-						  const struct stb6100_config *config,
-						  struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-#endif //CONFIG_DVB_STB6100
-
-#endif
diff --git a/drivers/media/dvb/frontends/stb6100_cfg.h b/drivers/media/dvb/frontends/stb6100_cfg.h
deleted file mode 100644
index 6314d18..0000000
--- a/drivers/media/dvb/frontends/stb6100_cfg.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
-	STB6100 Silicon Tuner
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	Copyright (C) ST Microelectronics
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
-	struct tuner_state	t_state;
-	int err = 0;
-
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
-	if (tuner_ops->get_state) {
-		if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
-			printk("%s: Invalid parameter\n", __func__);
-			return err;
-		}
-		*frequency = t_state.frequency;
-	}
-	return 0;
-}
-
-static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
-{
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
-	struct tuner_state	t_state;
-	int err = 0;
-
-	t_state.frequency = frequency;
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
-	if (tuner_ops->set_state) {
-		if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
-			printk("%s: Invalid parameter\n", __func__);
-			return err;
-		}
-	}
-	return 0;
-}
-
-static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	struct dvb_frontend_ops	*frontend_ops = &fe->ops;
-	struct dvb_tuner_ops	*tuner_ops = &frontend_ops->tuner_ops;
-	struct tuner_state	t_state;
-	int err = 0;
-
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
-	if (tuner_ops->get_state) {
-		if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
-			printk("%s: Invalid parameter\n", __func__);
-			return err;
-		}
-		*bandwidth = t_state.bandwidth;
-	}
-	return 0;
-}
-
-static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
-{
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
-	struct tuner_state	t_state;
-	int err = 0;
-
-	t_state.bandwidth = bandwidth;
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
-	if (tuner_ops->set_state) {
-		if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
-			printk("%s: Invalid parameter\n", __func__);
-			return err;
-		}
-	}
-	return 0;
-}
diff --git a/drivers/media/dvb/frontends/stb6100_proc.h b/drivers/media/dvb/frontends/stb6100_proc.h
deleted file mode 100644
index 112163a..0000000
--- a/drivers/media/dvb/frontends/stb6100_proc.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
-	STB6100 Silicon Tuner wrapper
-	Copyright (C)2009 Igor M. Liplianin (liplianin@me.by)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-static int stb6100_get_freq(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
-	struct tuner_state	state;
-	int err = 0;
-
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
-	if (tuner_ops->get_state) {
-		if (frontend_ops->i2c_gate_ctrl)
-			frontend_ops->i2c_gate_ctrl(fe, 1);
-
-		err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &state);
-		if (err < 0) {
-			printk(KERN_ERR "%s: Invalid parameter\n", __func__);
-			return err;
-		}
-
-		if (frontend_ops->i2c_gate_ctrl)
-			frontend_ops->i2c_gate_ctrl(fe, 0);
-
-		*frequency = state.frequency;
-	}
-
-	return 0;
-}
-
-static int stb6100_set_freq(struct dvb_frontend *fe, u32 frequency)
-{
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
-	struct tuner_state	state;
-	int err = 0;
-
-	state.frequency = frequency;
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
-	if (tuner_ops->set_state) {
-		if (frontend_ops->i2c_gate_ctrl)
-			frontend_ops->i2c_gate_ctrl(fe, 1);
-
-		err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &state);
-		if (err < 0) {
-			printk(KERN_ERR "%s: Invalid parameter\n", __func__);
-			return err;
-		}
-
-		if (frontend_ops->i2c_gate_ctrl)
-			frontend_ops->i2c_gate_ctrl(fe, 0);
-
-	}
-
-	return 0;
-}
-
-static int stb6100_get_bandw(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
-	struct tuner_state	state;
-	int err = 0;
-
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
-	if (tuner_ops->get_state) {
-		if (frontend_ops->i2c_gate_ctrl)
-			frontend_ops->i2c_gate_ctrl(fe, 1);
-
-		err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &state);
-		if (err < 0) {
-			printk(KERN_ERR "%s: Invalid parameter\n", __func__);
-			return err;
-		}
-
-		if (frontend_ops->i2c_gate_ctrl)
-			frontend_ops->i2c_gate_ctrl(fe, 0);
-
-		*bandwidth = state.bandwidth;
-	}
-
-	return 0;
-}
-
-static int stb6100_set_bandw(struct dvb_frontend *fe, u32 bandwidth)
-{
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
-	struct tuner_state	state;
-	int err = 0;
-
-	state.bandwidth = bandwidth;
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
-	if (tuner_ops->set_state) {
-		if (frontend_ops->i2c_gate_ctrl)
-			frontend_ops->i2c_gate_ctrl(fe, 1);
-
-		err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &state);
-		if (err < 0) {
-			printk(KERN_ERR "%s: Invalid parameter\n", __func__);
-			return err;
-		}
-
-		if (frontend_ops->i2c_gate_ctrl)
-			frontend_ops->i2c_gate_ctrl(fe, 0);
-
-	}
-
-	return 0;
-}
diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c
deleted file mode 100644
index 632b251..0000000
--- a/drivers/media/dvb/frontends/stv0288.c
+++ /dev/null
@@ -1,626 +0,0 @@
-/*
-	Driver for ST STV0288 demodulator
-	Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de
-		for Reel Multimedia
-	Copyright (C) 2008 TurboSight.com, Bob Liu <bob@turbosight.com>
-	Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
-		Removed stb6000 specific tuner code and revised some
-		procedures.
-	2010-09-01 Josef Pavlik <josef@pavlik.it>
-		Fixed diseqc_msg, diseqc_burst and set_tone problems
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
-#include <asm/div64.h>
-
-#include "dvb_frontend.h"
-#include "stv0288.h"
-
-struct stv0288_state {
-	struct i2c_adapter *i2c;
-	const struct stv0288_config *config;
-	struct dvb_frontend frontend;
-
-	u8 initialised:1;
-	u32 tuner_frequency;
-	u32 symbol_rate;
-	fe_code_rate_t fec_inner;
-	int errmode;
-};
-
-#define STATUS_BER 0
-#define STATUS_UCBLOCKS 1
-
-static int debug;
-static int debug_legacy_dish_switch;
-#define dprintk(args...) \
-	do { \
-		if (debug) \
-			printk(KERN_DEBUG "stv0288: " args); \
-	} while (0)
-
-
-static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data)
-{
-	int ret;
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = {
-		.addr = state->config->demod_address,
-		.flags = 0,
-		.buf = buf,
-		.len = 2
-	};
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-
-	if (ret != 1)
-		dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
-			"ret == %i)\n", __func__, reg, data, ret);
-
-	return (ret != 1) ? -EREMOTEIO : 0;
-}
-
-static int stv0288_write(struct dvb_frontend *fe, const u8 buf[], int len)
-{
-	struct stv0288_state *state = fe->demodulator_priv;
-
-	if (len != 2)
-		return -EINVAL;
-
-	return stv0288_writeregI(state, buf[0], buf[1]);
-}
-
-static u8 stv0288_readreg(struct stv0288_state *state, u8 reg)
-{
-	int ret;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
-	struct i2c_msg msg[] = {
-		{
-			.addr = state->config->demod_address,
-			.flags = 0,
-			.buf = b0,
-			.len = 1
-		}, {
-			.addr = state->config->demod_address,
-			.flags = I2C_M_RD,
-			.buf = b1,
-			.len = 1
-		}
-	};
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2)
-		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
-				__func__, reg, ret);
-
-	return b1[0];
-}
-
-static int stv0288_set_symbolrate(struct dvb_frontend *fe, u32 srate)
-{
-	struct stv0288_state *state = fe->demodulator_priv;
-	unsigned int temp;
-	unsigned char b[3];
-
-	if ((srate < 1000000) || (srate > 45000000))
-		return -EINVAL;
-
-	stv0288_writeregI(state, 0x22, 0);
-	stv0288_writeregI(state, 0x23, 0);
-	stv0288_writeregI(state, 0x2b, 0xff);
-	stv0288_writeregI(state, 0x2c, 0xf7);
-
-	temp = (unsigned int)srate / 1000;
-
-		temp = temp * 32768;
-		temp = temp / 25;
-		temp = temp / 125;
-		b[0] = (unsigned char)((temp >> 12) & 0xff);
-		b[1] = (unsigned char)((temp >> 4) & 0xff);
-		b[2] = (unsigned char)((temp << 4) & 0xf0);
-		stv0288_writeregI(state, 0x28, 0x80); /* SFRH */
-		stv0288_writeregI(state, 0x29, 0); /* SFRM */
-		stv0288_writeregI(state, 0x2a, 0); /* SFRL */
-
-		stv0288_writeregI(state, 0x28, b[0]);
-		stv0288_writeregI(state, 0x29, b[1]);
-		stv0288_writeregI(state, 0x2a, b[2]);
-		dprintk("stv0288: stv0288_set_symbolrate\n");
-
-	return 0;
-}
-
-static int stv0288_send_diseqc_msg(struct dvb_frontend *fe,
-				    struct dvb_diseqc_master_cmd *m)
-{
-	struct stv0288_state *state = fe->demodulator_priv;
-
-	int i;
-
-	dprintk("%s\n", __func__);
-
-	stv0288_writeregI(state, 0x09, 0);
-	msleep(30);
-	stv0288_writeregI(state, 0x05, 0x12);/* modulated mode, single shot */
-
-	for (i = 0; i < m->msg_len; i++) {
-		if (stv0288_writeregI(state, 0x06, m->msg[i]))
-			return -EREMOTEIO;
-	}
-	msleep(m->msg_len*12);
-	return 0;
-}
-
-static int stv0288_send_diseqc_burst(struct dvb_frontend *fe,
-						fe_sec_mini_cmd_t burst)
-{
-	struct stv0288_state *state = fe->demodulator_priv;
-
-	dprintk("%s\n", __func__);
-
-	if (stv0288_writeregI(state, 0x05, 0x03))/* burst mode, single shot */
-		return -EREMOTEIO;
-
-	if (stv0288_writeregI(state, 0x06, burst == SEC_MINI_A ? 0x00 : 0xff))
-		return -EREMOTEIO;
-
-	msleep(15);
-	if (stv0288_writeregI(state, 0x05, 0x12))
-		return -EREMOTEIO;
-
-	return 0;
-}
-
-static int stv0288_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
-{
-	struct stv0288_state *state = fe->demodulator_priv;
-
-	switch (tone) {
-	case SEC_TONE_ON:
-		if (stv0288_writeregI(state, 0x05, 0x10))/* cont carrier */
-			return -EREMOTEIO;
-	break;
-
-	case SEC_TONE_OFF:
-		if (stv0288_writeregI(state, 0x05, 0x12))/* burst mode off*/
-			return -EREMOTEIO;
-	break;
-
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static u8 stv0288_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x20,
-	0x09, 0x0,
-	0x0a, 0x4,
-	0x0b, 0x0,
-	0x0c, 0x0,
-	0x0d, 0x0,
-	0x0e, 0xd4,
-	0x0f, 0x30,
-	0x11, 0x80,
-	0x12, 0x03,
-	0x13, 0x48,
-	0x14, 0x84,
-	0x15, 0x45,
-	0x16, 0xb7,
-	0x17, 0x9c,
-	0x18, 0x0,
-	0x19, 0xa6,
-	0x1a, 0x88,
-	0x1b, 0x8f,
-	0x1c, 0xf0,
-	0x20, 0x0b,
-	0x21, 0x54,
-	0x22, 0x0,
-	0x23, 0x0,
-	0x2b, 0xff,
-	0x2c, 0xf7,
-	0x30, 0x0,
-	0x31, 0x1e,
-	0x32, 0x14,
-	0x33, 0x0f,
-	0x34, 0x09,
-	0x35, 0x0c,
-	0x36, 0x05,
-	0x37, 0x2f,
-	0x38, 0x16,
-	0x39, 0xbe,
-	0x3a, 0x0,
-	0x3b, 0x13,
-	0x3c, 0x11,
-	0x3d, 0x30,
-	0x40, 0x63,
-	0x41, 0x04,
-	0x42, 0x20,
-	0x43, 0x00,
-	0x44, 0x00,
-	0x45, 0x00,
-	0x46, 0x00,
-	0x47, 0x00,
-	0x4a, 0x00,
-	0x50, 0x10,
-	0x51, 0x38,
-	0x52, 0x21,
-	0x58, 0x54,
-	0x59, 0x86,
-	0x5a, 0x0,
-	0x5b, 0x9b,
-	0x5c, 0x08,
-	0x5d, 0x7f,
-	0x5e, 0x0,
-	0x5f, 0xff,
-	0x70, 0x0,
-	0x71, 0x0,
-	0x72, 0x0,
-	0x74, 0x0,
-	0x75, 0x0,
-	0x76, 0x0,
-	0x81, 0x0,
-	0x82, 0x3f,
-	0x83, 0x3f,
-	0x84, 0x0,
-	0x85, 0x0,
-	0x88, 0x0,
-	0x89, 0x0,
-	0x8a, 0x0,
-	0x8b, 0x0,
-	0x8c, 0x0,
-	0x90, 0x0,
-	0x91, 0x0,
-	0x92, 0x0,
-	0x93, 0x0,
-	0x94, 0x1c,
-	0x97, 0x0,
-	0xa0, 0x48,
-	0xa1, 0x0,
-	0xb0, 0xb8,
-	0xb1, 0x3a,
-	0xb2, 0x10,
-	0xb3, 0x82,
-	0xb4, 0x80,
-	0xb5, 0x82,
-	0xb6, 0x82,
-	0xb7, 0x82,
-	0xb8, 0x20,
-	0xb9, 0x0,
-	0xf0, 0x0,
-	0xf1, 0x0,
-	0xf2, 0xc0,
-	0x51, 0x36,
-	0x52, 0x09,
-	0x53, 0x94,
-	0x54, 0x62,
-	0x55, 0x29,
-	0x56, 0x64,
-	0x57, 0x2b,
-	0xff, 0xff,
-};
-
-static int stv0288_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
-{
-	dprintk("%s: %s\n", __func__,
-		volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
-		volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
-
-	return 0;
-}
-
-static int stv0288_init(struct dvb_frontend *fe)
-{
-	struct stv0288_state *state = fe->demodulator_priv;
-	int i;
-	u8 reg;
-	u8 val;
-
-	dprintk("stv0288: init chip\n");
-	stv0288_writeregI(state, 0x41, 0x04);
-	msleep(50);
-
-	/* we have default inittab */
-	if (state->config->inittab == NULL) {
-		for (i = 0; !(stv0288_inittab[i] == 0xff &&
-				stv0288_inittab[i + 1] == 0xff); i += 2)
-			stv0288_writeregI(state, stv0288_inittab[i],
-					stv0288_inittab[i + 1]);
-	} else {
-		for (i = 0; ; i += 2)  {
-			reg = state->config->inittab[i];
-			val = state->config->inittab[i+1];
-			if (reg == 0xff && val == 0xff)
-				break;
-			stv0288_writeregI(state, reg, val);
-		}
-	}
-	return 0;
-}
-
-static int stv0288_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct stv0288_state *state = fe->demodulator_priv;
-
-	u8 sync = stv0288_readreg(state, 0x24);
-	if (sync == 255)
-		sync = 0;
-
-	dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync);
-
-	*status = 0;
-	if (sync & 0x80)
-		*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
-	if (sync & 0x10)
-		*status |= FE_HAS_VITERBI;
-	if (sync & 0x08) {
-		*status |= FE_HAS_LOCK;
-		dprintk("stv0288 has locked\n");
-	}
-
-	return 0;
-}
-
-static int stv0288_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct stv0288_state *state = fe->demodulator_priv;
-
-	if (state->errmode != STATUS_BER)
-		return 0;
-	*ber = (stv0288_readreg(state, 0x26) << 8) |
-					stv0288_readreg(state, 0x27);
-	dprintk("stv0288_read_ber %d\n", *ber);
-
-	return 0;
-}
-
-
-static int stv0288_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct stv0288_state *state = fe->demodulator_priv;
-
-	s32 signal =  0xffff - ((stv0288_readreg(state, 0x10) << 8));
-
-
-	signal = signal * 5 / 4;
-	*strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal;
-	dprintk("stv0288_read_signal_strength %d\n", *strength);
-
-	return 0;
-}
-static int stv0288_sleep(struct dvb_frontend *fe)
-{
-	struct stv0288_state *state = fe->demodulator_priv;
-
-	stv0288_writeregI(state, 0x41, 0x84);
-	state->initialised = 0;
-
-	return 0;
-}
-static int stv0288_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct stv0288_state *state = fe->demodulator_priv;
-
-	s32 xsnr = 0xffff - ((stv0288_readreg(state, 0x2d) << 8)
-			   | stv0288_readreg(state, 0x2e));
-	xsnr = 3 * (xsnr - 0xa100);
-	*snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
-	dprintk("stv0288_read_snr %d\n", *snr);
-
-	return 0;
-}
-
-static int stv0288_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct stv0288_state *state = fe->demodulator_priv;
-
-	if (state->errmode != STATUS_BER)
-		return 0;
-	*ucblocks = (stv0288_readreg(state, 0x26) << 8) |
-					stv0288_readreg(state, 0x27);
-	dprintk("stv0288_read_ber %d\n", *ucblocks);
-
-	return 0;
-}
-
-static int stv0288_set_property(struct dvb_frontend *fe, struct dtv_property *p)
-{
-	dprintk("%s(..)\n", __func__);
-	return 0;
-}
-
-static int stv0288_set_frontend(struct dvb_frontend *fe)
-{
-	struct stv0288_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-
-	char tm;
-	unsigned char tda[3];
-	u8 reg, time_out = 0;
-
-	dprintk("%s : FE_SET_FRONTEND\n", __func__);
-
-	if (c->delivery_system != SYS_DVBS) {
-			dprintk("%s: unsupported delivery "
-				"system selected (%d)\n",
-				__func__, c->delivery_system);
-			return -EOPNOTSUPP;
-	}
-
-	if (state->config->set_ts_params)
-		state->config->set_ts_params(fe, 0);
-
-	/* only frequency & symbol_rate are used for tuner*/
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	udelay(10);
-	stv0288_set_symbolrate(fe, c->symbol_rate);
-	/* Carrier lock control register */
-	stv0288_writeregI(state, 0x15, 0xc5);
-
-	tda[2] = 0x0; /* CFRL */
-	for (tm = -9; tm < 7;) {
-		/* Viterbi status */
-		reg = stv0288_readreg(state, 0x24);
-		if (reg & 0x8)
-				break;
-		if (reg & 0x80) {
-			time_out++;
-			if (time_out > 10)
-				break;
-			tda[2] += 40;
-			if (tda[2] < 40)
-				tm++;
-		} else {
-			tm++;
-			tda[2] = 0;
-			time_out = 0;
-		}
-		tda[1] = (unsigned char)tm;
-		stv0288_writeregI(state, 0x2b, tda[1]);
-		stv0288_writeregI(state, 0x2c, tda[2]);
-		msleep(30);
-	}
-	state->tuner_frequency = c->frequency;
-	state->fec_inner = FEC_AUTO;
-	state->symbol_rate = c->symbol_rate;
-
-	return 0;
-}
-
-static int stv0288_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct stv0288_state *state = fe->demodulator_priv;
-
-	if (enable)
-		stv0288_writeregI(state, 0x01, 0xb5);
-	else
-		stv0288_writeregI(state, 0x01, 0x35);
-
-	udelay(1);
-
-	return 0;
-}
-
-static void stv0288_release(struct dvb_frontend *fe)
-{
-	struct stv0288_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops stv0288_ops = {
-	.delsys = { SYS_DVBS },
-	.info = {
-		.name			= "ST STV0288 DVB-S",
-		.frequency_min		= 950000,
-		.frequency_max		= 2150000,
-		.frequency_stepsize	= 1000,	 /* kHz for QPSK frontends */
-		.frequency_tolerance	= 0,
-		.symbol_rate_min	= 1000000,
-		.symbol_rate_max	= 45000000,
-		.symbol_rate_tolerance	= 500,	/* ppm */
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
-		      FE_CAN_QPSK |
-		      FE_CAN_FEC_AUTO
-	},
-
-	.release = stv0288_release,
-	.init = stv0288_init,
-	.sleep = stv0288_sleep,
-	.write = stv0288_write,
-	.i2c_gate_ctrl = stv0288_i2c_gate_ctrl,
-	.read_status = stv0288_read_status,
-	.read_ber = stv0288_read_ber,
-	.read_signal_strength = stv0288_read_signal_strength,
-	.read_snr = stv0288_read_snr,
-	.read_ucblocks = stv0288_read_ucblocks,
-	.diseqc_send_master_cmd = stv0288_send_diseqc_msg,
-	.diseqc_send_burst = stv0288_send_diseqc_burst,
-	.set_tone = stv0288_set_tone,
-	.set_voltage = stv0288_set_voltage,
-
-	.set_property = stv0288_set_property,
-	.set_frontend = stv0288_set_frontend,
-};
-
-struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
-				    struct i2c_adapter *i2c)
-{
-	struct stv0288_state *state = NULL;
-	int id;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct stv0288_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->initialised = 0;
-	state->tuner_frequency = 0;
-	state->symbol_rate = 0;
-	state->fec_inner = 0;
-	state->errmode = STATUS_BER;
-
-	stv0288_writeregI(state, 0x41, 0x04);
-	msleep(200);
-	id = stv0288_readreg(state, 0x00);
-	dprintk("stv0288 id %x\n", id);
-
-	/* register 0x00 contains 0x11 for STV0288  */
-	if (id != 0x11)
-		goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &stv0288_ops,
-			sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-
-	return NULL;
-}
-EXPORT_SYMBOL(stv0288_attach);
-
-module_param(debug_legacy_dish_switch, int, 0444);
-MODULE_PARM_DESC(debug_legacy_dish_switch,
-		"Enable timing analysis for Dish Network legacy switches");
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("ST STV0288 DVB Demodulator driver");
-MODULE_AUTHOR("Georg Acher, Bob Liu, Igor liplianin");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/media/dvb/frontends/stv0288.h b/drivers/media/dvb/frontends/stv0288.h
deleted file mode 100644
index f2b53db..0000000
--- a/drivers/media/dvb/frontends/stv0288.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
-	Driver for ST STV0288 demodulator
-
-	Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de
-		for Reel Multimedia
-	Copyright (C) 2008 TurboSight.com, <bob@turbosight.com>
-	Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
-		Removed stb6000 specific tuner code and revised some
-		procedures.
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef STV0288_H
-#define STV0288_H
-
-#include <linux/dvb/frontend.h>
-#include "dvb_frontend.h"
-
-struct stv0288_config {
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	u8* inittab;
-
-	/* minimum delay before retuning */
-	int min_delay_ms;
-
-	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
-};
-
-#if defined(CONFIG_DVB_STV0288) || (defined(CONFIG_DVB_STV0288_MODULE) && \
-							defined(MODULE))
-extern struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
-					   struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
-					   struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_STV0288 */
-
-static inline int stv0288_writereg(struct dvb_frontend *fe, u8 reg, u8 val)
-{
-	int r = 0;
-	u8 buf[] = { reg, val };
-	if (fe->ops.write)
-		r = fe->ops.write(fe, buf, 2);
-	return r;
-}
-
-#endif /* STV0288_H */
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
deleted file mode 100644
index d40f226..0000000
--- a/drivers/media/dvb/frontends/stv0297.c
+++ /dev/null
@@ -1,722 +0,0 @@
-/*
-    Driver for STV0297 demodulator
-
-    Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.net>
-    Copyright (C) 2003-2004 Dennis Noermann <dennis.noermann@noernet.de>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/jiffies.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "stv0297.h"
-
-struct stv0297_state {
-	struct i2c_adapter *i2c;
-	const struct stv0297_config *config;
-	struct dvb_frontend frontend;
-
-	unsigned long last_ber;
-	unsigned long base_freq;
-};
-
-#if 1
-#define dprintk(x...) printk(x)
-#else
-#define dprintk(x...)
-#endif
-
-#define STV0297_CLOCK_KHZ   28900
-
-
-static int stv0297_writereg(struct stv0297_state *state, u8 reg, u8 data)
-{
-	int ret;
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 2 };
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-
-	if (ret != 1)
-		dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
-			"ret == %i)\n", __func__, reg, data, ret);
-
-	return (ret != 1) ? -1 : 0;
-}
-
-static int stv0297_readreg(struct stv0297_state *state, u8 reg)
-{
-	int ret;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
-	struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1},
-				 {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
-			       };
-
-	// this device needs a STOP between the register and data
-	if (state->config->stop_during_read) {
-		if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
-			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret);
-			return -1;
-		}
-		if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
-			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret);
-			return -1;
-		}
-	} else {
-		if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
-			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret);
-			return -1;
-		}
-	}
-
-	return b1[0];
-}
-
-static int stv0297_writereg_mask(struct stv0297_state *state, u8 reg, u8 mask, u8 data)
-{
-	int val;
-
-	val = stv0297_readreg(state, reg);
-	val &= ~mask;
-	val |= (data & mask);
-	stv0297_writereg(state, reg, val);
-
-	return 0;
-}
-
-static int stv0297_readregs(struct stv0297_state *state, u8 reg1, u8 * b, u8 len)
-{
-	int ret;
-	struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf =
-				  &reg1,.len = 1},
-	{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b,.len = len}
-	};
-
-	// this device needs a STOP between the register and data
-	if (state->config->stop_during_read) {
-		if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
-			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret);
-			return -1;
-		}
-		if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
-			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret);
-			return -1;
-		}
-	} else {
-		if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
-			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret);
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-static u32 stv0297_get_symbolrate(struct stv0297_state *state)
-{
-	u64 tmp;
-
-	tmp = stv0297_readreg(state, 0x55);
-	tmp |= stv0297_readreg(state, 0x56) << 8;
-	tmp |= stv0297_readreg(state, 0x57) << 16;
-	tmp |= stv0297_readreg(state, 0x58) << 24;
-
-	tmp *= STV0297_CLOCK_KHZ;
-	tmp >>= 32;
-
-	return (u32) tmp;
-}
-
-static void stv0297_set_symbolrate(struct stv0297_state *state, u32 srate)
-{
-	long tmp;
-
-	tmp = 131072L * srate;	/* 131072 = 2^17  */
-	tmp = tmp / (STV0297_CLOCK_KHZ / 4);	/* 1/4 = 2^-2 */
-	tmp = tmp * 8192L;	/* 8192 = 2^13 */
-
-	stv0297_writereg(state, 0x55, (unsigned char) (tmp & 0xFF));
-	stv0297_writereg(state, 0x56, (unsigned char) (tmp >> 8));
-	stv0297_writereg(state, 0x57, (unsigned char) (tmp >> 16));
-	stv0297_writereg(state, 0x58, (unsigned char) (tmp >> 24));
-}
-
-static void stv0297_set_sweeprate(struct stv0297_state *state, short fshift, long symrate)
-{
-	long tmp;
-
-	tmp = (long) fshift *262144L;	/* 262144 = 2*18 */
-	tmp /= symrate;
-	tmp *= 1024;		/* 1024 = 2*10   */
-
-	// adjust
-	if (tmp >= 0) {
-		tmp += 500000;
-	} else {
-		tmp -= 500000;
-	}
-	tmp /= 1000000;
-
-	stv0297_writereg(state, 0x60, tmp & 0xFF);
-	stv0297_writereg_mask(state, 0x69, 0xF0, (tmp >> 4) & 0xf0);
-}
-
-static void stv0297_set_carrieroffset(struct stv0297_state *state, long offset)
-{
-	long tmp;
-
-	/* symrate is hardcoded to 10000 */
-	tmp = offset * 26844L;	/* (2**28)/10000 */
-	if (tmp < 0)
-		tmp += 0x10000000;
-	tmp &= 0x0FFFFFFF;
-
-	stv0297_writereg(state, 0x66, (unsigned char) (tmp & 0xFF));
-	stv0297_writereg(state, 0x67, (unsigned char) (tmp >> 8));
-	stv0297_writereg(state, 0x68, (unsigned char) (tmp >> 16));
-	stv0297_writereg_mask(state, 0x69, 0x0F, (tmp >> 24) & 0x0f);
-}
-
-/*
-static long stv0297_get_carrieroffset(struct stv0297_state *state)
-{
-	s64 tmp;
-
-	stv0297_writereg(state, 0x6B, 0x00);
-
-	tmp = stv0297_readreg(state, 0x66);
-	tmp |= (stv0297_readreg(state, 0x67) << 8);
-	tmp |= (stv0297_readreg(state, 0x68) << 16);
-	tmp |= (stv0297_readreg(state, 0x69) & 0x0F) << 24;
-
-	tmp *= stv0297_get_symbolrate(state);
-	tmp >>= 28;
-
-	return (s32) tmp;
-}
-*/
-
-static void stv0297_set_initialdemodfreq(struct stv0297_state *state, long freq)
-{
-	s32 tmp;
-
-	if (freq > 10000)
-		freq -= STV0297_CLOCK_KHZ;
-
-	tmp = (STV0297_CLOCK_KHZ * 1000) / (1 << 16);
-	tmp = (freq * 1000) / tmp;
-	if (tmp > 0xffff)
-		tmp = 0xffff;
-
-	stv0297_writereg_mask(state, 0x25, 0x80, 0x80);
-	stv0297_writereg(state, 0x21, tmp >> 8);
-	stv0297_writereg(state, 0x20, tmp);
-}
-
-static int stv0297_set_qam(struct stv0297_state *state, fe_modulation_t modulation)
-{
-	int val = 0;
-
-	switch (modulation) {
-	case QAM_16:
-		val = 0;
-		break;
-
-	case QAM_32:
-		val = 1;
-		break;
-
-	case QAM_64:
-		val = 4;
-		break;
-
-	case QAM_128:
-		val = 2;
-		break;
-
-	case QAM_256:
-		val = 3;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	stv0297_writereg_mask(state, 0x00, 0x70, val << 4);
-
-	return 0;
-}
-
-static int stv0297_set_inversion(struct stv0297_state *state, fe_spectral_inversion_t inversion)
-{
-	int val = 0;
-
-	switch (inversion) {
-	case INVERSION_OFF:
-		val = 0;
-		break;
-
-	case INVERSION_ON:
-		val = 1;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	stv0297_writereg_mask(state, 0x83, 0x08, val << 3);
-
-	return 0;
-}
-
-static int stv0297_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct stv0297_state *state = fe->demodulator_priv;
-
-	if (enable) {
-		stv0297_writereg(state, 0x87, 0x78);
-		stv0297_writereg(state, 0x86, 0xc8);
-	}
-
-	return 0;
-}
-
-static int stv0297_init(struct dvb_frontend *fe)
-{
-	struct stv0297_state *state = fe->demodulator_priv;
-	int i;
-
-	/* load init table */
-	for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2)
-		stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]);
-	msleep(200);
-
-	state->last_ber = 0;
-
-	return 0;
-}
-
-static int stv0297_sleep(struct dvb_frontend *fe)
-{
-	struct stv0297_state *state = fe->demodulator_priv;
-
-	stv0297_writereg_mask(state, 0x80, 1, 1);
-
-	return 0;
-}
-
-static int stv0297_read_status(struct dvb_frontend *fe, fe_status_t * status)
-{
-	struct stv0297_state *state = fe->demodulator_priv;
-
-	u8 sync = stv0297_readreg(state, 0xDF);
-
-	*status = 0;
-	if (sync & 0x80)
-		*status |=
-			FE_HAS_SYNC | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK;
-	return 0;
-}
-
-static int stv0297_read_ber(struct dvb_frontend *fe, u32 * ber)
-{
-	struct stv0297_state *state = fe->demodulator_priv;
-	u8 BER[3];
-
-	stv0297_readregs(state, 0xA0, BER, 3);
-	if (!(BER[0] & 0x80)) {
-		state->last_ber = BER[2] << 8 | BER[1];
-		stv0297_writereg_mask(state, 0xA0, 0x80, 0x80);
-	}
-
-	*ber = state->last_ber;
-
-	return 0;
-}
-
-
-static int stv0297_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
-{
-	struct stv0297_state *state = fe->demodulator_priv;
-	u8 STRENGTH[3];
-	u16 tmp;
-
-	stv0297_readregs(state, 0x41, STRENGTH, 3);
-	tmp = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0];
-	if (STRENGTH[2] & 0x20) {
-		if (tmp < 0x200)
-			tmp = 0;
-		else
-			tmp = tmp - 0x200;
-	} else {
-		if (tmp > 0x1ff)
-			tmp = 0;
-		else
-			tmp = 0x1ff - tmp;
-	}
-	*strength = (tmp << 7) | (tmp >> 2);
-	return 0;
-}
-
-static int stv0297_read_snr(struct dvb_frontend *fe, u16 * snr)
-{
-	struct stv0297_state *state = fe->demodulator_priv;
-	u8 SNR[2];
-
-	stv0297_readregs(state, 0x07, SNR, 2);
-	*snr = SNR[1] << 8 | SNR[0];
-
-	return 0;
-}
-
-static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
-{
-	struct stv0297_state *state = fe->demodulator_priv;
-
-	stv0297_writereg_mask(state, 0xDF, 0x03, 0x03); /* freeze the counters */
-
-	*ucblocks = (stv0297_readreg(state, 0xD5) << 8)
-		| stv0297_readreg(state, 0xD4);
-
-	stv0297_writereg_mask(state, 0xDF, 0x03, 0x02); /* clear the counters */
-	stv0297_writereg_mask(state, 0xDF, 0x03, 0x01); /* re-enable the counters */
-
-	return 0;
-}
-
-static int stv0297_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct stv0297_state *state = fe->demodulator_priv;
-	int u_threshold;
-	int initial_u;
-	int blind_u;
-	int delay;
-	int sweeprate;
-	int carrieroffset;
-	unsigned long timeout;
-	fe_spectral_inversion_t inversion;
-
-	switch (p->modulation) {
-	case QAM_16:
-	case QAM_32:
-	case QAM_64:
-		delay = 100;
-		sweeprate = 1000;
-		break;
-
-	case QAM_128:
-	case QAM_256:
-		delay = 200;
-		sweeprate = 500;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	// determine inversion dependent parameters
-	inversion = p->inversion;
-	if (state->config->invert)
-		inversion = (inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON;
-	carrieroffset = -330;
-	switch (inversion) {
-	case INVERSION_OFF:
-		break;
-
-	case INVERSION_ON:
-		sweeprate = -sweeprate;
-		carrieroffset = -carrieroffset;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	stv0297_init(fe);
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	/* clear software interrupts */
-	stv0297_writereg(state, 0x82, 0x0);
-
-	/* set initial demodulation frequency */
-	stv0297_set_initialdemodfreq(state, 7250);
-
-	/* setup AGC */
-	stv0297_writereg_mask(state, 0x43, 0x10, 0x00);
-	stv0297_writereg(state, 0x41, 0x00);
-	stv0297_writereg_mask(state, 0x42, 0x03, 0x01);
-	stv0297_writereg_mask(state, 0x36, 0x60, 0x00);
-	stv0297_writereg_mask(state, 0x36, 0x18, 0x00);
-	stv0297_writereg_mask(state, 0x71, 0x80, 0x80);
-	stv0297_writereg(state, 0x72, 0x00);
-	stv0297_writereg(state, 0x73, 0x00);
-	stv0297_writereg_mask(state, 0x74, 0x0F, 0x00);
-	stv0297_writereg_mask(state, 0x43, 0x08, 0x00);
-	stv0297_writereg_mask(state, 0x71, 0x80, 0x00);
-
-	/* setup STL */
-	stv0297_writereg_mask(state, 0x5a, 0x20, 0x20);
-	stv0297_writereg_mask(state, 0x5b, 0x02, 0x02);
-	stv0297_writereg_mask(state, 0x5b, 0x02, 0x00);
-	stv0297_writereg_mask(state, 0x5b, 0x01, 0x00);
-	stv0297_writereg_mask(state, 0x5a, 0x40, 0x40);
-
-	/* disable frequency sweep */
-	stv0297_writereg_mask(state, 0x6a, 0x01, 0x00);
-
-	/* reset deinterleaver */
-	stv0297_writereg_mask(state, 0x81, 0x01, 0x01);
-	stv0297_writereg_mask(state, 0x81, 0x01, 0x00);
-
-	/* ??? */
-	stv0297_writereg_mask(state, 0x83, 0x20, 0x20);
-	stv0297_writereg_mask(state, 0x83, 0x20, 0x00);
-
-	/* reset equaliser */
-	u_threshold = stv0297_readreg(state, 0x00) & 0xf;
-	initial_u = stv0297_readreg(state, 0x01) >> 4;
-	blind_u = stv0297_readreg(state, 0x01) & 0xf;
-	stv0297_writereg_mask(state, 0x84, 0x01, 0x01);
-	stv0297_writereg_mask(state, 0x84, 0x01, 0x00);
-	stv0297_writereg_mask(state, 0x00, 0x0f, u_threshold);
-	stv0297_writereg_mask(state, 0x01, 0xf0, initial_u << 4);
-	stv0297_writereg_mask(state, 0x01, 0x0f, blind_u);
-
-	/* data comes from internal A/D */
-	stv0297_writereg_mask(state, 0x87, 0x80, 0x00);
-
-	/* clear phase registers */
-	stv0297_writereg(state, 0x63, 0x00);
-	stv0297_writereg(state, 0x64, 0x00);
-	stv0297_writereg(state, 0x65, 0x00);
-	stv0297_writereg(state, 0x66, 0x00);
-	stv0297_writereg(state, 0x67, 0x00);
-	stv0297_writereg(state, 0x68, 0x00);
-	stv0297_writereg_mask(state, 0x69, 0x0f, 0x00);
-
-	/* set parameters */
-	stv0297_set_qam(state, p->modulation);
-	stv0297_set_symbolrate(state, p->symbol_rate / 1000);
-	stv0297_set_sweeprate(state, sweeprate, p->symbol_rate / 1000);
-	stv0297_set_carrieroffset(state, carrieroffset);
-	stv0297_set_inversion(state, inversion);
-
-	/* kick off lock */
-	/* Disable corner detection for higher QAMs */
-	if (p->modulation == QAM_128 ||
-		p->modulation == QAM_256)
-		stv0297_writereg_mask(state, 0x88, 0x08, 0x00);
-	else
-		stv0297_writereg_mask(state, 0x88, 0x08, 0x08);
-
-	stv0297_writereg_mask(state, 0x5a, 0x20, 0x00);
-	stv0297_writereg_mask(state, 0x6a, 0x01, 0x01);
-	stv0297_writereg_mask(state, 0x43, 0x40, 0x40);
-	stv0297_writereg_mask(state, 0x5b, 0x30, 0x00);
-	stv0297_writereg_mask(state, 0x03, 0x0c, 0x0c);
-	stv0297_writereg_mask(state, 0x03, 0x03, 0x03);
-	stv0297_writereg_mask(state, 0x43, 0x10, 0x10);
-
-	/* wait for WGAGC lock */
-	timeout = jiffies + msecs_to_jiffies(2000);
-	while (time_before(jiffies, timeout)) {
-		msleep(10);
-		if (stv0297_readreg(state, 0x43) & 0x08)
-			break;
-	}
-	if (time_after(jiffies, timeout)) {
-		goto timeout;
-	}
-	msleep(20);
-
-	/* wait for equaliser partial convergence */
-	timeout = jiffies + msecs_to_jiffies(500);
-	while (time_before(jiffies, timeout)) {
-		msleep(10);
-
-		if (stv0297_readreg(state, 0x82) & 0x04) {
-			break;
-		}
-	}
-	if (time_after(jiffies, timeout)) {
-		goto timeout;
-	}
-
-	/* wait for equaliser full convergence */
-	timeout = jiffies + msecs_to_jiffies(delay);
-	while (time_before(jiffies, timeout)) {
-		msleep(10);
-
-		if (stv0297_readreg(state, 0x82) & 0x08) {
-			break;
-		}
-	}
-	if (time_after(jiffies, timeout)) {
-		goto timeout;
-	}
-
-	/* disable sweep */
-	stv0297_writereg_mask(state, 0x6a, 1, 0);
-	stv0297_writereg_mask(state, 0x88, 8, 0);
-
-	/* wait for main lock */
-	timeout = jiffies + msecs_to_jiffies(20);
-	while (time_before(jiffies, timeout)) {
-		msleep(10);
-
-		if (stv0297_readreg(state, 0xDF) & 0x80) {
-			break;
-		}
-	}
-	if (time_after(jiffies, timeout)) {
-		goto timeout;
-	}
-	msleep(100);
-
-	/* is it still locked after that delay? */
-	if (!(stv0297_readreg(state, 0xDF) & 0x80)) {
-		goto timeout;
-	}
-
-	/* success!! */
-	stv0297_writereg_mask(state, 0x5a, 0x40, 0x00);
-	state->base_freq = p->frequency;
-	return 0;
-
-timeout:
-	stv0297_writereg_mask(state, 0x6a, 0x01, 0x00);
-	return 0;
-}
-
-static int stv0297_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct stv0297_state *state = fe->demodulator_priv;
-	int reg_00, reg_83;
-
-	reg_00 = stv0297_readreg(state, 0x00);
-	reg_83 = stv0297_readreg(state, 0x83);
-
-	p->frequency = state->base_freq;
-	p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF;
-	if (state->config->invert)
-		p->inversion = (p->inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON;
-	p->symbol_rate = stv0297_get_symbolrate(state) * 1000;
-	p->fec_inner = FEC_NONE;
-
-	switch ((reg_00 >> 4) & 0x7) {
-	case 0:
-		p->modulation = QAM_16;
-		break;
-	case 1:
-		p->modulation = QAM_32;
-		break;
-	case 2:
-		p->modulation = QAM_128;
-		break;
-	case 3:
-		p->modulation = QAM_256;
-		break;
-	case 4:
-		p->modulation = QAM_64;
-		break;
-	}
-
-	return 0;
-}
-
-static void stv0297_release(struct dvb_frontend *fe)
-{
-	struct stv0297_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops stv0297_ops;
-
-struct dvb_frontend *stv0297_attach(const struct stv0297_config *config,
-				    struct i2c_adapter *i2c)
-{
-	struct stv0297_state *state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct stv0297_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->last_ber = 0;
-	state->base_freq = 0;
-
-	/* check if the demod is there */
-	if ((stv0297_readreg(state, 0x80) & 0x70) != 0x20)
-		goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops stv0297_ops = {
-	.delsys = { SYS_DVBC_ANNEX_A },
-	.info = {
-		 .name = "ST STV0297 DVB-C",
-		 .frequency_min = 47000000,
-		 .frequency_max = 862000000,
-		 .frequency_stepsize = 62500,
-		 .symbol_rate_min = 870000,
-		 .symbol_rate_max = 11700000,
-		 .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
-		 FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO},
-
-	.release = stv0297_release,
-
-	.init = stv0297_init,
-	.sleep = stv0297_sleep,
-	.i2c_gate_ctrl = stv0297_i2c_gate_ctrl,
-
-	.set_frontend = stv0297_set_frontend,
-	.get_frontend = stv0297_get_frontend,
-
-	.read_status = stv0297_read_status,
-	.read_ber = stv0297_read_ber,
-	.read_signal_strength = stv0297_read_signal_strength,
-	.read_snr = stv0297_read_snr,
-	.read_ucblocks = stv0297_read_ucblocks,
-};
-
-MODULE_DESCRIPTION("ST STV0297 DVB-C Demodulator driver");
-MODULE_AUTHOR("Dennis Noermann and Andrew de Quincey");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(stv0297_attach);
diff --git a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb/frontends/stv0297.h
deleted file mode 100644
index 3f8f946..0000000
--- a/drivers/media/dvb/frontends/stv0297.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-    Driver for STV0297 demodulator
-
-    Copyright (C) 2003-2004 Dennis Noermann <dennis.noermann@noernet.de>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef STV0297_H
-#define STV0297_H
-
-#include <linux/dvb/frontend.h>
-#include "dvb_frontend.h"
-
-struct stv0297_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* inittab - array of pairs of values.
-	* First of each pair is the register, second is the value.
-	* List should be terminated with an 0xff, 0xff pair.
-	*/
-	u8* inittab;
-
-	/* does the "inversion" need inverted? */
-	u8 invert:1;
-
-	/* set to 1 if the device requires an i2c STOP during reading */
-	u8 stop_during_read:1;
-};
-
-#if defined(CONFIG_DVB_STV0297) || (defined(CONFIG_DVB_STV0297_MODULE) && defined(MODULE))
-extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
-					   struct i2c_adapter* i2c);
-#else
-static inline struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
-					   struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_STV0297
-
-#endif // STV0297_H
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
deleted file mode 100644
index 057b5f8..0000000
--- a/drivers/media/dvb/frontends/stv0299.c
+++ /dev/null
@@ -1,762 +0,0 @@
-/*
-    Driver for ST STV0299 demodulator
-
-    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
-	<ralph@convergence.de>,
-	<holger@convergence.de>,
-	<js@convergence.de>
-
-
-    Philips SU1278/SH
-
-    Copyright (C) 2002 by Peter Schildmann <peter.schildmann@web.de>
-
-
-    LG TDQF-S001F
-
-    Copyright (C) 2002 Felix Domke <tmbinc@elitedvb.net>
-		     & Andreas Oberritter <obi@linuxtv.org>
-
-
-    Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B
-
-    Copyright (C) 2003 Vadim Catana <skystar@moldova.cc>:
-
-    Support for Philips SU1278 on Technotrend hardware
-
-    Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.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.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
-#include <asm/div64.h>
-
-#include "dvb_frontend.h"
-#include "stv0299.h"
-
-struct stv0299_state {
-	struct i2c_adapter* i2c;
-	const struct stv0299_config* config;
-	struct dvb_frontend frontend;
-
-	u8 initialised:1;
-	u32 tuner_frequency;
-	u32 symbol_rate;
-	fe_code_rate_t fec_inner;
-	int errmode;
-	u32 ucblocks;
-	u8 mcr_reg;
-};
-
-#define STATUS_BER 0
-#define STATUS_UCBLOCKS 1
-
-static int debug;
-static int debug_legacy_dish_switch;
-#define dprintk(args...) \
-	do { \
-		if (debug) printk(KERN_DEBUG "stv0299: " args); \
-	} while (0)
-
-
-static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data)
-{
-	int ret;
-	u8 buf [] = { reg, data };
-	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
-
-	ret = i2c_transfer (state->i2c, &msg, 1);
-
-	if (ret != 1)
-		dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
-			"ret == %i)\n", __func__, reg, data, ret);
-
-	return (ret != 1) ? -EREMOTEIO : 0;
-}
-
-static int stv0299_write(struct dvb_frontend* fe, const u8 buf[], int len)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-
-	if (len != 2)
-		return -EINVAL;
-
-	return stv0299_writeregI(state, buf[0], buf[1]);
-}
-
-static u8 stv0299_readreg (struct stv0299_state* state, u8 reg)
-{
-	int ret;
-	u8 b0 [] = { reg };
-	u8 b1 [] = { 0 };
-	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
-			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-
-	ret = i2c_transfer (state->i2c, msg, 2);
-
-	if (ret != 2)
-		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
-				__func__, reg, ret);
-
-	return b1[0];
-}
-
-static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len)
-{
-	int ret;
-	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = &reg1, .len = 1 },
-			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } };
-
-	ret = i2c_transfer (state->i2c, msg, 2);
-
-	if (ret != 2)
-		dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
-
-	return ret == 2 ? 0 : ret;
-}
-
-static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
-{
-	dprintk ("%s\n", __func__);
-
-	switch (fec) {
-	case FEC_AUTO:
-	{
-		return stv0299_writeregI (state, 0x31, 0x1f);
-	}
-	case FEC_1_2:
-	{
-		return stv0299_writeregI (state, 0x31, 0x01);
-	}
-	case FEC_2_3:
-	{
-		return stv0299_writeregI (state, 0x31, 0x02);
-	}
-	case FEC_3_4:
-	{
-		return stv0299_writeregI (state, 0x31, 0x04);
-	}
-	case FEC_5_6:
-	{
-		return stv0299_writeregI (state, 0x31, 0x08);
-	}
-	case FEC_7_8:
-	{
-		return stv0299_writeregI (state, 0x31, 0x10);
-	}
-	default:
-	{
-		return -EINVAL;
-	}
-    }
-}
-
-static fe_code_rate_t stv0299_get_fec (struct stv0299_state* state)
-{
-	static fe_code_rate_t fec_tab [] = { FEC_2_3, FEC_3_4, FEC_5_6,
-					     FEC_7_8, FEC_1_2 };
-	u8 index;
-
-	dprintk ("%s\n", __func__);
-
-	index = stv0299_readreg (state, 0x1b);
-	index &= 0x7;
-
-	if (index > 4)
-		return FEC_AUTO;
-
-	return fec_tab [index];
-}
-
-static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout)
-{
-	unsigned long start = jiffies;
-
-	dprintk ("%s\n", __func__);
-
-	while (stv0299_readreg(state, 0x0a) & 1) {
-		if (jiffies - start > timeout) {
-			dprintk ("%s: timeout!!\n", __func__);
-			return -ETIMEDOUT;
-		}
-		msleep(10);
-	};
-
-	return 0;
-}
-
-static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout)
-{
-	unsigned long start = jiffies;
-
-	dprintk ("%s\n", __func__);
-
-	while ((stv0299_readreg(state, 0x0a) & 3) != 2 ) {
-		if (jiffies - start > timeout) {
-			dprintk ("%s: timeout!!\n", __func__);
-			return -ETIMEDOUT;
-		}
-		msleep(10);
-	};
-
-	return 0;
-}
-
-static int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-	u64 big = srate;
-	u32 ratio;
-
-	// check rate is within limits
-	if ((srate < 1000000) || (srate > 45000000)) return -EINVAL;
-
-	// calculate value to program
-	big = big << 20;
-	big += (state->config->mclk-1); // round correctly
-	do_div(big, state->config->mclk);
-	ratio = big << 4;
-
-	return state->config->set_symbol_rate(fe, srate, ratio);
-}
-
-static int stv0299_get_symbolrate (struct stv0299_state* state)
-{
-	u32 Mclk = state->config->mclk / 4096L;
-	u32 srate;
-	s32 offset;
-	u8 sfr[3];
-	s8 rtf;
-
-	dprintk ("%s\n", __func__);
-
-	stv0299_readregs (state, 0x1f, sfr, 3);
-	stv0299_readregs (state, 0x1a, (u8 *)&rtf, 1);
-
-	srate = (sfr[0] << 8) | sfr[1];
-	srate *= Mclk;
-	srate /= 16;
-	srate += (sfr[2] >> 4) * Mclk / 256;
-	offset = (s32) rtf * (srate / 4096L);
-	offset /= 128;
-
-	dprintk ("%s : srate = %i\n", __func__, srate);
-	dprintk ("%s : ofset = %i\n", __func__, offset);
-
-	srate += offset;
-
-	srate += 1000;
-	srate /= 2000;
-	srate *= 2000;
-
-	return srate;
-}
-
-static int stv0299_send_diseqc_msg (struct dvb_frontend* fe,
-				    struct dvb_diseqc_master_cmd *m)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-	u8 val;
-	int i;
-
-	dprintk ("%s\n", __func__);
-
-	if (stv0299_wait_diseqc_idle (state, 100) < 0)
-		return -ETIMEDOUT;
-
-	val = stv0299_readreg (state, 0x08);
-
-	if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x6))  /* DiSEqC mode */
-		return -EREMOTEIO;
-
-	for (i=0; i<m->msg_len; i++) {
-		if (stv0299_wait_diseqc_fifo (state, 100) < 0)
-			return -ETIMEDOUT;
-
-		if (stv0299_writeregI (state, 0x09, m->msg[i]))
-			return -EREMOTEIO;
-	}
-
-	if (stv0299_wait_diseqc_idle (state, 100) < 0)
-		return -ETIMEDOUT;
-
-	return 0;
-}
-
-static int stv0299_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-	u8 val;
-
-	dprintk ("%s\n", __func__);
-
-	if (stv0299_wait_diseqc_idle (state, 100) < 0)
-		return -ETIMEDOUT;
-
-	val = stv0299_readreg (state, 0x08);
-
-	if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x2))	/* burst mode */
-		return -EREMOTEIO;
-
-	if (stv0299_writeregI (state, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff))
-		return -EREMOTEIO;
-
-	if (stv0299_wait_diseqc_idle (state, 100) < 0)
-		return -ETIMEDOUT;
-
-	if (stv0299_writeregI (state, 0x08, val))
-		return -EREMOTEIO;
-
-	return 0;
-}
-
-static int stv0299_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-	u8 val;
-
-	if (stv0299_wait_diseqc_idle (state, 100) < 0)
-		return -ETIMEDOUT;
-
-	val = stv0299_readreg (state, 0x08);
-
-	switch (tone) {
-	case SEC_TONE_ON:
-		return stv0299_writeregI (state, 0x08, val | 0x3);
-
-	case SEC_TONE_OFF:
-		return stv0299_writeregI (state, 0x08, (val & ~0x3) | 0x02);
-
-	default:
-		return -EINVAL;
-	}
-}
-
-static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-	u8 reg0x08;
-	u8 reg0x0c;
-
-	dprintk("%s: %s\n", __func__,
-		voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
-		voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
-
-	reg0x08 = stv0299_readreg (state, 0x08);
-	reg0x0c = stv0299_readreg (state, 0x0c);
-
-	/**
-	 *  H/V switching over OP0, OP1 and OP2 are LNB power enable bits
-	 */
-	reg0x0c &= 0x0f;
-	reg0x08 = (reg0x08 & 0x3f) | (state->config->lock_output << 6);
-
-	switch (voltage) {
-	case SEC_VOLTAGE_13:
-		if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0)
-			reg0x0c |= 0x10; /* OP1 off, OP0 on */
-		else
-			reg0x0c |= 0x40; /* OP1 on, OP0 off */
-		break;
-	case SEC_VOLTAGE_18:
-		reg0x0c |= 0x50; /* OP1 on, OP0 on */
-		break;
-	case SEC_VOLTAGE_OFF:
-		/* LNB power off! */
-		reg0x08 = 0x00;
-		reg0x0c = 0x00;
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	if (state->config->op0_off)
-		reg0x0c &= ~0x10;
-
-	stv0299_writeregI(state, 0x08, reg0x08);
-	return stv0299_writeregI(state, 0x0c, reg0x0c);
-}
-
-static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long cmd)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-	u8 reg0x08;
-	u8 reg0x0c;
-	u8 lv_mask = 0x40;
-	u8 last = 1;
-	int i;
-	struct timeval nexttime;
-	struct timeval tv[10];
-
-	reg0x08 = stv0299_readreg (state, 0x08);
-	reg0x0c = stv0299_readreg (state, 0x0c);
-	reg0x0c &= 0x0f;
-	stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6));
-	if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0)
-		lv_mask = 0x10;
-
-	cmd = cmd << 1;
-	if (debug_legacy_dish_switch)
-		printk ("%s switch command: 0x%04lx\n",__func__, cmd);
-
-	do_gettimeofday (&nexttime);
-	if (debug_legacy_dish_switch)
-		memcpy (&tv[0], &nexttime, sizeof (struct timeval));
-	stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */
-
-	dvb_frontend_sleep_until(&nexttime, 32000);
-
-	for (i=0; i<9; i++) {
-		if (debug_legacy_dish_switch)
-			do_gettimeofday (&tv[i+1]);
-		if((cmd & 0x01) != last) {
-			/* set voltage to (last ? 13V : 18V) */
-			stv0299_writeregI (state, 0x0c, reg0x0c | (last ? lv_mask : 0x50));
-			last = (last) ? 0 : 1;
-		}
-
-		cmd = cmd >> 1;
-
-		if (i != 8)
-			dvb_frontend_sleep_until(&nexttime, 8000);
-	}
-	if (debug_legacy_dish_switch) {
-		printk ("%s(%d): switch delay (should be 32k followed by all 8k\n",
-			__func__, fe->dvb->num);
-		for (i = 1; i < 10; i++)
-			printk ("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
-	}
-
-	return 0;
-}
-
-static int stv0299_init (struct dvb_frontend* fe)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-	int i;
-	u8 reg;
-	u8 val;
-
-	dprintk("stv0299: init chip\n");
-
-	stv0299_writeregI(state, 0x02, 0x30 | state->mcr_reg);
-	msleep(50);
-
-	for (i = 0; ; i += 2)  {
-		reg = state->config->inittab[i];
-		val = state->config->inittab[i+1];
-		if (reg == 0xff && val == 0xff)
-			break;
-		if (reg == 0x0c && state->config->op0_off)
-			val &= ~0x10;
-		if (reg == 0x2)
-			state->mcr_reg = val & 0xf;
-		stv0299_writeregI(state, reg, val);
-	}
-
-	return 0;
-}
-
-static int stv0299_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-
-	u8 signal = 0xff - stv0299_readreg (state, 0x18);
-	u8 sync = stv0299_readreg (state, 0x1b);
-
-	dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync);
-	*status = 0;
-
-	if (signal > 10)
-		*status |= FE_HAS_SIGNAL;
-
-	if (sync & 0x80)
-		*status |= FE_HAS_CARRIER;
-
-	if (sync & 0x10)
-		*status |= FE_HAS_VITERBI;
-
-	if (sync & 0x08)
-		*status |= FE_HAS_SYNC;
-
-	if ((sync & 0x98) == 0x98)
-		*status |= FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-
-	if (state->errmode != STATUS_BER)
-		return -ENOSYS;
-
-	*ber = stv0299_readreg(state, 0x1e) | (stv0299_readreg(state, 0x1d) << 8);
-
-	return 0;
-}
-
-static int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-
-	s32 signal =  0xffff - ((stv0299_readreg (state, 0x18) << 8)
-			       | stv0299_readreg (state, 0x19));
-
-	dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __func__,
-		 stv0299_readreg (state, 0x18),
-		 stv0299_readreg (state, 0x19), (int) signal);
-
-	signal = signal * 5 / 4;
-	*strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal;
-
-	return 0;
-}
-
-static int stv0299_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-
-	s32 xsnr = 0xffff - ((stv0299_readreg (state, 0x24) << 8)
-			   | stv0299_readreg (state, 0x25));
-	xsnr = 3 * (xsnr - 0xa100);
-	*snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
-
-	return 0;
-}
-
-static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-
-	if (state->errmode != STATUS_UCBLOCKS)
-		return -ENOSYS;
-
-	state->ucblocks += stv0299_readreg(state, 0x1e);
-	state->ucblocks += (stv0299_readreg(state, 0x1d) << 8);
-	*ucblocks = state->ucblocks;
-
-	return 0;
-}
-
-static int stv0299_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct stv0299_state* state = fe->demodulator_priv;
-	int invval = 0;
-
-	dprintk ("%s : FE_SET_FRONTEND\n", __func__);
-	if (state->config->set_ts_params)
-		state->config->set_ts_params(fe, 0);
-
-	// set the inversion
-	if (p->inversion == INVERSION_OFF) invval = 0;
-	else if (p->inversion == INVERSION_ON) invval = 1;
-	else {
-		printk("stv0299 does not support auto-inversion\n");
-		return -EINVAL;
-	}
-	if (state->config->invert) invval = (~invval) & 1;
-	stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
-
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	stv0299_set_FEC(state, p->fec_inner);
-	stv0299_set_symbolrate(fe, p->symbol_rate);
-	stv0299_writeregI(state, 0x22, 0x00);
-	stv0299_writeregI(state, 0x23, 0x00);
-
-	state->tuner_frequency = p->frequency;
-	state->fec_inner = p->fec_inner;
-	state->symbol_rate = p->symbol_rate;
-
-	return 0;
-}
-
-static int stv0299_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct stv0299_state* state = fe->demodulator_priv;
-	s32 derot_freq;
-	int invval;
-
-	derot_freq = (s32)(s16) ((stv0299_readreg (state, 0x22) << 8)
-				| stv0299_readreg (state, 0x23));
-
-	derot_freq *= (state->config->mclk >> 16);
-	derot_freq += 500;
-	derot_freq /= 1000;
-
-	p->frequency += derot_freq;
-
-	invval = stv0299_readreg (state, 0x0c) & 1;
-	if (state->config->invert) invval = (~invval) & 1;
-	p->inversion = invval ? INVERSION_ON : INVERSION_OFF;
-
-	p->fec_inner = stv0299_get_fec(state);
-	p->symbol_rate = stv0299_get_symbolrate(state);
-
-	return 0;
-}
-
-static int stv0299_sleep(struct dvb_frontend* fe)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-
-	stv0299_writeregI(state, 0x02, 0xb0 | state->mcr_reg);
-	state->initialised = 0;
-
-	return 0;
-}
-
-static int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-
-	if (enable) {
-		stv0299_writeregI(state, 0x05, 0xb5);
-	} else {
-		stv0299_writeregI(state, 0x05, 0x35);
-	}
-	udelay(1);
-	return 0;
-}
-
-static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-
-	fesettings->min_delay_ms = state->config->min_delay_ms;
-	if (p->symbol_rate < 10000000) {
-		fesettings->step_size = p->symbol_rate / 32000;
-		fesettings->max_drift = 5000;
-	} else {
-		fesettings->step_size = p->symbol_rate / 16000;
-		fesettings->max_drift = p->symbol_rate / 2000;
-	}
-	return 0;
-}
-
-static void stv0299_release(struct dvb_frontend* fe)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops stv0299_ops;
-
-struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
-				    struct i2c_adapter* i2c)
-{
-	struct stv0299_state* state = NULL;
-	int id;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct stv0299_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->initialised = 0;
-	state->tuner_frequency = 0;
-	state->symbol_rate = 0;
-	state->fec_inner = 0;
-	state->errmode = STATUS_BER;
-
-	/* check if the demod is there */
-	stv0299_writeregI(state, 0x02, 0x30); /* standby off */
-	msleep(200);
-	id = stv0299_readreg(state, 0x00);
-
-	/* register 0x00 contains 0xa1 for STV0299 and STV0299B */
-	/* register 0x00 might contain 0x80 when returning from standby */
-	if (id != 0xa1 && id != 0x80) goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops stv0299_ops = {
-	.delsys = { SYS_DVBS },
-	.info = {
-		.name			= "ST STV0299 DVB-S",
-		.frequency_min		= 950000,
-		.frequency_max		= 2150000,
-		.frequency_stepsize	= 125,	 /* kHz for QPSK frontends */
-		.frequency_tolerance	= 0,
-		.symbol_rate_min	= 1000000,
-		.symbol_rate_max	= 45000000,
-		.symbol_rate_tolerance	= 500,	/* ppm */
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
-		      FE_CAN_QPSK |
-		      FE_CAN_FEC_AUTO
-	},
-
-	.release = stv0299_release,
-
-	.init = stv0299_init,
-	.sleep = stv0299_sleep,
-	.write = stv0299_write,
-	.i2c_gate_ctrl = stv0299_i2c_gate_ctrl,
-
-	.set_frontend = stv0299_set_frontend,
-	.get_frontend = stv0299_get_frontend,
-	.get_tune_settings = stv0299_get_tune_settings,
-
-	.read_status = stv0299_read_status,
-	.read_ber = stv0299_read_ber,
-	.read_signal_strength = stv0299_read_signal_strength,
-	.read_snr = stv0299_read_snr,
-	.read_ucblocks = stv0299_read_ucblocks,
-
-	.diseqc_send_master_cmd = stv0299_send_diseqc_msg,
-	.diseqc_send_burst = stv0299_send_diseqc_burst,
-	.set_tone = stv0299_set_tone,
-	.set_voltage = stv0299_set_voltage,
-	.dishnetwork_send_legacy_command = stv0299_send_legacy_dish_cmd,
-};
-
-module_param(debug_legacy_dish_switch, int, 0444);
-MODULE_PARM_DESC(debug_legacy_dish_switch, "Enable timing analysis for Dish Network legacy switches");
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver");
-MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
-	      "Andreas Oberritter, Andrew de Quincey, Kenneth Aafly");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(stv0299_attach);
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h
deleted file mode 100644
index ba219b7..0000000
--- a/drivers/media/dvb/frontends/stv0299.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
-    Driver for ST STV0299 demodulator
-
-    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
-	<ralph@convergence.de>,
-	<holger@convergence.de>,
-	<js@convergence.de>
-
-
-    Philips SU1278/SH
-
-    Copyright (C) 2002 by Peter Schildmann <peter.schildmann@web.de>
-
-
-    LG TDQF-S001F
-
-    Copyright (C) 2002 Felix Domke <tmbinc@elitedvb.net>
-		     & Andreas Oberritter <obi@linuxtv.org>
-
-
-    Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B
-
-    Copyright (C) 2003 Vadim Catana <skystar@moldova.cc>:
-
-    Support for Philips SU1278 on Technotrend hardware
-
-    Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.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.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef STV0299_H
-#define STV0299_H
-
-#include <linux/dvb/frontend.h>
-#include "dvb_frontend.h"
-
-#define STV0299_LOCKOUTPUT_0  0
-#define STV0299_LOCKOUTPUT_1  1
-#define STV0299_LOCKOUTPUT_CF 2
-#define STV0299_LOCKOUTPUT_LK 3
-
-#define STV0299_VOLT13_OP0 0
-#define STV0299_VOLT13_OP1 1
-
-struct stv0299_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* inittab - array of pairs of values.
-	 * First of each pair is the register, second is the value.
-	 * List should be terminated with an 0xff, 0xff pair.
-	 */
-	const u8* inittab;
-
-	/* master clock to use */
-	u32 mclk;
-
-	/* does the inversion require inversion? */
-	u8 invert:1;
-
-	/* Skip reinitialisation? */
-	u8 skip_reinit:1;
-
-	/* LOCK OUTPUT setting */
-	u8 lock_output:2;
-
-	/* Is 13v controlled by OP0 or OP1? */
-	u8 volt13_op0_op1:1;
-
-	/* Turn-off OP0? */
-	u8 op0_off:1;
-
-	/* minimum delay before retuning */
-	int min_delay_ms;
-
-	/* Set the symbol rate */
-	int (*set_symbol_rate)(struct dvb_frontend *fe, u32 srate, u32 ratio);
-
-	/* Set device param to start dma */
-	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
-};
-
-#if defined(CONFIG_DVB_STV0299) || (defined(CONFIG_DVB_STV0299_MODULE) && defined(MODULE))
-extern struct dvb_frontend *stv0299_attach(const struct stv0299_config *config,
-					   struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *stv0299_attach(const struct stv0299_config *config,
-					   struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_STV0299
-
-static inline int stv0299_writereg(struct dvb_frontend *fe, u8 reg, u8 val) {
-	int r = 0;
-	u8 buf[] = {reg, val};
-	if (fe->ops.write)
-		r = fe->ops.write(fe, buf, 2);
-	return r;
-}
-
-#endif // STV0299_H
diff --git a/drivers/media/dvb/frontends/stv0367.c b/drivers/media/dvb/frontends/stv0367.c
deleted file mode 100644
index 2a8aaeb..0000000
--- a/drivers/media/dvb/frontends/stv0367.c
+++ /dev/null
@@ -1,3450 +0,0 @@
-/*
- * stv0367.c
- *
- * Driver for ST STV0367 DVB-T & DVB-C demodulator IC.
- *
- * Copyright (C) ST Microelectronics.
- * Copyright (C) 2010,2011 NetUP Inc.
- * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-
-#include "stv0367.h"
-#include "stv0367_regs.h"
-#include "stv0367_priv.h"
-
-static int stvdebug;
-module_param_named(debug, stvdebug, int, 0644);
-
-static int i2cdebug;
-module_param_named(i2c_debug, i2cdebug, int, 0644);
-
-#define dprintk(args...) \
-	do { \
-		if (stvdebug) \
-			printk(KERN_DEBUG args); \
-	} while (0)
-	/* DVB-C */
-
-struct stv0367cab_state {
-	enum stv0367_cab_signal_type	state;
-	u32	mclk;
-	u32	adc_clk;
-	s32	search_range;
-	s32	derot_offset;
-	/* results */
-	int locked;			/* channel found		*/
-	u32 freq_khz;			/* found frequency (in kHz)	*/
-	u32 symbol_rate;		/* found symbol rate (in Bds)	*/
-	enum stv0367cab_mod modulation;	/* modulation			*/
-	fe_spectral_inversion_t	spect_inv; /* Spectrum Inversion	*/
-};
-
-struct stv0367ter_state {
-	/* DVB-T */
-	enum stv0367_ter_signal_type state;
-	enum stv0367_ter_if_iq_mode if_iq_mode;
-	enum stv0367_ter_mode mode;/* mode 2K or 8K */
-	fe_guard_interval_t guard;
-	enum stv0367_ter_hierarchy hierarchy;
-	u32 frequency;
-	fe_spectral_inversion_t  sense; /*  current search spectrum */
-	u8  force; /* force mode/guard */
-	u8  bw; /* channel width 6, 7 or 8 in MHz */
-	u8  pBW; /* channel width used during previous lock */
-	u32 pBER;
-	u32 pPER;
-	u32 ucblocks;
-	s8  echo_pos; /* echo position */
-	u8  first_lock;
-	u8  unlock_counter;
-	u32 agc_val;
-};
-
-struct stv0367_state {
-	struct dvb_frontend fe;
-	struct i2c_adapter *i2c;
-	/* config settings */
-	const struct stv0367_config *config;
-	u8 chip_id;
-	/* DVB-C */
-	struct stv0367cab_state *cab_state;
-	/* DVB-T */
-	struct stv0367ter_state *ter_state;
-};
-
-struct st_register {
-	u16	addr;
-	u8	value;
-};
-
-/* values for STV4100 XTAL=30M int clk=53.125M*/
-static struct st_register def0367ter[STV0367TER_NBREGS] = {
-	{R367TER_ID,		0x60},
-	{R367TER_I2CRPT,	0xa0},
-	/* {R367TER_I2CRPT,	0x22},*/
-	{R367TER_TOPCTRL,	0x00},/* for xc5000; was 0x02 */
-	{R367TER_IOCFG0,	0x40},
-	{R367TER_DAC0R,		0x00},
-	{R367TER_IOCFG1,	0x00},
-	{R367TER_DAC1R,		0x00},
-	{R367TER_IOCFG2,	0x62},
-	{R367TER_SDFR,		0x00},
-	{R367TER_STATUS,	0xf8},
-	{R367TER_AUX_CLK,	0x0a},
-	{R367TER_FREESYS1,	0x00},
-	{R367TER_FREESYS2,	0x00},
-	{R367TER_FREESYS3,	0x00},
-	{R367TER_GPIO_CFG,	0x55},
-	{R367TER_GPIO_CMD,	0x00},
-	{R367TER_AGC2MAX,	0xff},
-	{R367TER_AGC2MIN,	0x00},
-	{R367TER_AGC1MAX,	0xff},
-	{R367TER_AGC1MIN,	0x00},
-	{R367TER_AGCR,		0xbc},
-	{R367TER_AGC2TH,	0x00},
-	{R367TER_AGC12C,	0x00},
-	{R367TER_AGCCTRL1,	0x85},
-	{R367TER_AGCCTRL2,	0x1f},
-	{R367TER_AGC1VAL1,	0x00},
-	{R367TER_AGC1VAL2,	0x00},
-	{R367TER_AGC2VAL1,	0x6f},
-	{R367TER_AGC2VAL2,	0x05},
-	{R367TER_AGC2PGA,	0x00},
-	{R367TER_OVF_RATE1,	0x00},
-	{R367TER_OVF_RATE2,	0x00},
-	{R367TER_GAIN_SRC1,	0xaa},/* for xc5000; was 0x2b */
-	{R367TER_GAIN_SRC2,	0xd6},/* for xc5000; was 0x04 */
-	{R367TER_INC_DEROT1,	0x55},
-	{R367TER_INC_DEROT2,	0x55},
-	{R367TER_PPM_CPAMP_DIR,	0x2c},
-	{R367TER_PPM_CPAMP_INV,	0x00},
-	{R367TER_FREESTFE_1,	0x00},
-	{R367TER_FREESTFE_2,	0x1c},
-	{R367TER_DCOFFSET,	0x00},
-	{R367TER_EN_PROCESS,	0x05},
-	{R367TER_SDI_SMOOTHER,	0x80},
-	{R367TER_FE_LOOP_OPEN,	0x1c},
-	{R367TER_FREQOFF1,	0x00},
-	{R367TER_FREQOFF2,	0x00},
-	{R367TER_FREQOFF3,	0x00},
-	{R367TER_TIMOFF1,	0x00},
-	{R367TER_TIMOFF2,	0x00},
-	{R367TER_EPQ,		0x02},
-	{R367TER_EPQAUTO,	0x01},
-	{R367TER_SYR_UPDATE,	0xf5},
-	{R367TER_CHPFREE,	0x00},
-	{R367TER_PPM_STATE_MAC,	0x23},
-	{R367TER_INR_THRESHOLD,	0xff},
-	{R367TER_EPQ_TPS_ID_CELL, 0xf9},
-	{R367TER_EPQ_CFG,	0x00},
-	{R367TER_EPQ_STATUS,	0x01},
-	{R367TER_AUTORELOCK,	0x81},
-	{R367TER_BER_THR_VMSB,	0x00},
-	{R367TER_BER_THR_MSB,	0x00},
-	{R367TER_BER_THR_LSB,	0x00},
-	{R367TER_CCD,		0x83},
-	{R367TER_SPECTR_CFG,	0x00},
-	{R367TER_CHC_DUMMY,	0x18},
-	{R367TER_INC_CTL,	0x88},
-	{R367TER_INCTHRES_COR1,	0xb4},
-	{R367TER_INCTHRES_COR2,	0x96},
-	{R367TER_INCTHRES_DET1,	0x0e},
-	{R367TER_INCTHRES_DET2,	0x11},
-	{R367TER_IIR_CELLNB,	0x8d},
-	{R367TER_IIRCX_COEFF1_MSB, 0x00},
-	{R367TER_IIRCX_COEFF1_LSB, 0x00},
-	{R367TER_IIRCX_COEFF2_MSB, 0x09},
-	{R367TER_IIRCX_COEFF2_LSB, 0x18},
-	{R367TER_IIRCX_COEFF3_MSB, 0x14},
-	{R367TER_IIRCX_COEFF3_LSB, 0x9c},
-	{R367TER_IIRCX_COEFF4_MSB, 0x00},
-	{R367TER_IIRCX_COEFF4_LSB, 0x00},
-	{R367TER_IIRCX_COEFF5_MSB, 0x36},
-	{R367TER_IIRCX_COEFF5_LSB, 0x42},
-	{R367TER_FEPATH_CFG,	0x00},
-	{R367TER_PMC1_FUNC,	0x65},
-	{R367TER_PMC1_FOR,	0x00},
-	{R367TER_PMC2_FUNC,	0x00},
-	{R367TER_STATUS_ERR_DA,	0xe0},
-	{R367TER_DIG_AGC_R,	0xfe},
-	{R367TER_COMAGC_TARMSB,	0x0b},
-	{R367TER_COM_AGC_TAR_ENMODE, 0x41},
-	{R367TER_COM_AGC_CFG,	0x3e},
-	{R367TER_COM_AGC_GAIN1, 0x39},
-	{R367TER_AUT_AGC_TARGETMSB, 0x0b},
-	{R367TER_LOCK_DET_MSB,	0x01},
-	{R367TER_AGCTAR_LOCK_LSBS, 0x40},
-	{R367TER_AUT_GAIN_EN,	0xf4},
-	{R367TER_AUT_CFG,	0xf0},
-	{R367TER_LOCKN,		0x23},
-	{R367TER_INT_X_3,	0x00},
-	{R367TER_INT_X_2,	0x03},
-	{R367TER_INT_X_1,	0x8d},
-	{R367TER_INT_X_0,	0xa0},
-	{R367TER_MIN_ERRX_MSB,	0x00},
-	{R367TER_COR_CTL,	0x23},
-	{R367TER_COR_STAT,	0xf6},
-	{R367TER_COR_INTEN,	0x00},
-	{R367TER_COR_INTSTAT,	0x3f},
-	{R367TER_COR_MODEGUARD,	0x03},
-	{R367TER_AGC_CTL,	0x08},
-	{R367TER_AGC_MANUAL1,	0x00},
-	{R367TER_AGC_MANUAL2,	0x00},
-	{R367TER_AGC_TARG,	0x16},
-	{R367TER_AGC_GAIN1,	0x53},
-	{R367TER_AGC_GAIN2,	0x1d},
-	{R367TER_RESERVED_1,	0x00},
-	{R367TER_RESERVED_2,	0x00},
-	{R367TER_RESERVED_3,	0x00},
-	{R367TER_CAS_CTL,	0x44},
-	{R367TER_CAS_FREQ,	0xb3},
-	{R367TER_CAS_DAGCGAIN,	0x12},
-	{R367TER_SYR_CTL,	0x04},
-	{R367TER_SYR_STAT,	0x10},
-	{R367TER_SYR_NCO1,	0x00},
-	{R367TER_SYR_NCO2,	0x00},
-	{R367TER_SYR_OFFSET1,	0x00},
-	{R367TER_SYR_OFFSET2,	0x00},
-	{R367TER_FFT_CTL,	0x00},
-	{R367TER_SCR_CTL,	0x70},
-	{R367TER_PPM_CTL1,	0xf8},
-	{R367TER_TRL_CTL,	0x14},/* for xc5000; was 0xac */
-	{R367TER_TRL_NOMRATE1,	0xae},/* for xc5000; was 0x1e */
-	{R367TER_TRL_NOMRATE2,	0x56},/* for xc5000; was 0x58 */
-	{R367TER_TRL_TIME1,	0x1d},
-	{R367TER_TRL_TIME2,	0xfc},
-	{R367TER_CRL_CTL,	0x24},
-	{R367TER_CRL_FREQ1,	0xad},
-	{R367TER_CRL_FREQ2,	0x9d},
-	{R367TER_CRL_FREQ3,	0xff},
-	{R367TER_CHC_CTL,	0x01},
-	{R367TER_CHC_SNR,	0xf0},
-	{R367TER_BDI_CTL,	0x00},
-	{R367TER_DMP_CTL,	0x00},
-	{R367TER_TPS_RCVD1,	0x30},
-	{R367TER_TPS_RCVD2,	0x02},
-	{R367TER_TPS_RCVD3,	0x01},
-	{R367TER_TPS_RCVD4,	0x00},
-	{R367TER_TPS_ID_CELL1,	0x00},
-	{R367TER_TPS_ID_CELL2,	0x00},
-	{R367TER_TPS_RCVD5_SET1, 0x02},
-	{R367TER_TPS_SET2,	0x02},
-	{R367TER_TPS_SET3,	0x01},
-	{R367TER_TPS_CTL,	0x00},
-	{R367TER_CTL_FFTOSNUM,	0x34},
-	{R367TER_TESTSELECT,	0x09},
-	{R367TER_MSC_REV,	0x0a},
-	{R367TER_PIR_CTL,	0x00},
-	{R367TER_SNR_CARRIER1,	0xa1},
-	{R367TER_SNR_CARRIER2,	0x9a},
-	{R367TER_PPM_CPAMP,	0x2c},
-	{R367TER_TSM_AP0,	0x00},
-	{R367TER_TSM_AP1,	0x00},
-	{R367TER_TSM_AP2 ,	0x00},
-	{R367TER_TSM_AP3,	0x00},
-	{R367TER_TSM_AP4,	0x00},
-	{R367TER_TSM_AP5,	0x00},
-	{R367TER_TSM_AP6,	0x00},
-	{R367TER_TSM_AP7,	0x00},
-	{R367TER_TSTRES,	0x00},
-	{R367TER_ANACTRL,	0x0D},/* PLL stoped, restart at init!!! */
-	{R367TER_TSTBUS,	0x00},
-	{R367TER_TSTRATE,	0x00},
-	{R367TER_CONSTMODE,	0x01},
-	{R367TER_CONSTCARR1,	0x00},
-	{R367TER_CONSTCARR2,	0x00},
-	{R367TER_ICONSTEL,	0x0a},
-	{R367TER_QCONSTEL,	0x15},
-	{R367TER_TSTBISTRES0,	0x00},
-	{R367TER_TSTBISTRES1,	0x00},
-	{R367TER_TSTBISTRES2,	0x28},
-	{R367TER_TSTBISTRES3,	0x00},
-	{R367TER_RF_AGC1,	0xff},
-	{R367TER_RF_AGC2,	0x83},
-	{R367TER_ANADIGCTRL,	0x19},
-	{R367TER_PLLMDIV,	0x01},/* for xc5000; was 0x0c */
-	{R367TER_PLLNDIV,	0x06},/* for xc5000; was 0x55 */
-	{R367TER_PLLSETUP,	0x18},
-	{R367TER_DUAL_AD12,	0x0C},/* for xc5000 AGC voltage 1.6V */
-	{R367TER_TSTBIST,	0x00},
-	{R367TER_PAD_COMP_CTRL,	0x00},
-	{R367TER_PAD_COMP_WR,	0x00},
-	{R367TER_PAD_COMP_RD,	0xe0},
-	{R367TER_SYR_TARGET_FFTADJT_MSB, 0x00},
-	{R367TER_SYR_TARGET_FFTADJT_LSB, 0x00},
-	{R367TER_SYR_TARGET_CHCADJT_MSB, 0x00},
-	{R367TER_SYR_TARGET_CHCADJT_LSB, 0x00},
-	{R367TER_SYR_FLAG,	0x00},
-	{R367TER_CRL_TARGET1,	0x00},
-	{R367TER_CRL_TARGET2,	0x00},
-	{R367TER_CRL_TARGET3,	0x00},
-	{R367TER_CRL_TARGET4,	0x00},
-	{R367TER_CRL_FLAG,	0x00},
-	{R367TER_TRL_TARGET1,	0x00},
-	{R367TER_TRL_TARGET2,	0x00},
-	{R367TER_TRL_CHC,	0x00},
-	{R367TER_CHC_SNR_TARG,	0x00},
-	{R367TER_TOP_TRACK,	0x00},
-	{R367TER_TRACKER_FREE1,	0x00},
-	{R367TER_ERROR_CRL1,	0x00},
-	{R367TER_ERROR_CRL2,	0x00},
-	{R367TER_ERROR_CRL3,	0x00},
-	{R367TER_ERROR_CRL4,	0x00},
-	{R367TER_DEC_NCO1,	0x2c},
-	{R367TER_DEC_NCO2,	0x0f},
-	{R367TER_DEC_NCO3,	0x20},
-	{R367TER_SNR,		0xf1},
-	{R367TER_SYR_FFTADJ1,	0x00},
-	{R367TER_SYR_FFTADJ2,	0x00},
-	{R367TER_SYR_CHCADJ1,	0x00},
-	{R367TER_SYR_CHCADJ2,	0x00},
-	{R367TER_SYR_OFF,	0x00},
-	{R367TER_PPM_OFFSET1,	0x00},
-	{R367TER_PPM_OFFSET2,	0x03},
-	{R367TER_TRACKER_FREE2,	0x00},
-	{R367TER_DEBG_LT10,	0x00},
-	{R367TER_DEBG_LT11,	0x00},
-	{R367TER_DEBG_LT12,	0x00},
-	{R367TER_DEBG_LT13,	0x00},
-	{R367TER_DEBG_LT14,	0x00},
-	{R367TER_DEBG_LT15,	0x00},
-	{R367TER_DEBG_LT16,	0x00},
-	{R367TER_DEBG_LT17,	0x00},
-	{R367TER_DEBG_LT18,	0x00},
-	{R367TER_DEBG_LT19,	0x00},
-	{R367TER_DEBG_LT1A,	0x00},
-	{R367TER_DEBG_LT1B,	0x00},
-	{R367TER_DEBG_LT1C,	0x00},
-	{R367TER_DEBG_LT1D,	0x00},
-	{R367TER_DEBG_LT1E,	0x00},
-	{R367TER_DEBG_LT1F,	0x00},
-	{R367TER_RCCFGH,	0x00},
-	{R367TER_RCCFGM,	0x00},
-	{R367TER_RCCFGL,	0x00},
-	{R367TER_RCINSDELH,	0x00},
-	{R367TER_RCINSDELM,	0x00},
-	{R367TER_RCINSDELL,	0x00},
-	{R367TER_RCSTATUS,	0x00},
-	{R367TER_RCSPEED,	0x6f},
-	{R367TER_RCDEBUGM,	0xe7},
-	{R367TER_RCDEBUGL,	0x9b},
-	{R367TER_RCOBSCFG,	0x00},
-	{R367TER_RCOBSM,	0x00},
-	{R367TER_RCOBSL,	0x00},
-	{R367TER_RCFECSPY,	0x00},
-	{R367TER_RCFSPYCFG,	0x00},
-	{R367TER_RCFSPYDATA,	0x00},
-	{R367TER_RCFSPYOUT,	0x00},
-	{R367TER_RCFSTATUS,	0x00},
-	{R367TER_RCFGOODPACK,	0x00},
-	{R367TER_RCFPACKCNT,	0x00},
-	{R367TER_RCFSPYMISC,	0x00},
-	{R367TER_RCFBERCPT4,	0x00},
-	{R367TER_RCFBERCPT3,	0x00},
-	{R367TER_RCFBERCPT2,	0x00},
-	{R367TER_RCFBERCPT1,	0x00},
-	{R367TER_RCFBERCPT0,	0x00},
-	{R367TER_RCFBERERR2,	0x00},
-	{R367TER_RCFBERERR1,	0x00},
-	{R367TER_RCFBERERR0,	0x00},
-	{R367TER_RCFSTATESM,	0x00},
-	{R367TER_RCFSTATESL,	0x00},
-	{R367TER_RCFSPYBER,	0x00},
-	{R367TER_RCFSPYDISTM,	0x00},
-	{R367TER_RCFSPYDISTL,	0x00},
-	{R367TER_RCFSPYOBS7,	0x00},
-	{R367TER_RCFSPYOBS6,	0x00},
-	{R367TER_RCFSPYOBS5,	0x00},
-	{R367TER_RCFSPYOBS4,	0x00},
-	{R367TER_RCFSPYOBS3,	0x00},
-	{R367TER_RCFSPYOBS2,	0x00},
-	{R367TER_RCFSPYOBS1,	0x00},
-	{R367TER_RCFSPYOBS0,	0x00},
-	{R367TER_TSGENERAL,	0x00},
-	{R367TER_RC1SPEED,	0x6f},
-	{R367TER_TSGSTATUS,	0x18},
-	{R367TER_FECM,		0x01},
-	{R367TER_VTH12,		0xff},
-	{R367TER_VTH23,		0xa1},
-	{R367TER_VTH34,		0x64},
-	{R367TER_VTH56,		0x40},
-	{R367TER_VTH67,		0x00},
-	{R367TER_VTH78,		0x2c},
-	{R367TER_VITCURPUN,	0x12},
-	{R367TER_VERROR,	0x01},
-	{R367TER_PRVIT,		0x3f},
-	{R367TER_VAVSRVIT,	0x00},
-	{R367TER_VSTATUSVIT,	0xbd},
-	{R367TER_VTHINUSE,	0xa1},
-	{R367TER_KDIV12,	0x20},
-	{R367TER_KDIV23,	0x40},
-	{R367TER_KDIV34,	0x20},
-	{R367TER_KDIV56,	0x30},
-	{R367TER_KDIV67,	0x00},
-	{R367TER_KDIV78,	0x30},
-	{R367TER_SIGPOWER,	0x54},
-	{R367TER_DEMAPVIT,	0x40},
-	{R367TER_VITSCALE,	0x00},
-	{R367TER_FFEC1PRG,	0x00},
-	{R367TER_FVITCURPUN,	0x12},
-	{R367TER_FVERROR,	0x01},
-	{R367TER_FVSTATUSVIT,	0xbd},
-	{R367TER_DEBUG_LT1,	0x00},
-	{R367TER_DEBUG_LT2,	0x00},
-	{R367TER_DEBUG_LT3,	0x00},
-	{R367TER_TSTSFMET,	0x00},
-	{R367TER_SELOUT,	0x00},
-	{R367TER_TSYNC,		0x00},
-	{R367TER_TSTERR,	0x00},
-	{R367TER_TSFSYNC,	0x00},
-	{R367TER_TSTSFERR,	0x00},
-	{R367TER_TSTTSSF1,	0x01},
-	{R367TER_TSTTSSF2,	0x1f},
-	{R367TER_TSTTSSF3,	0x00},
-	{R367TER_TSTTS1,	0x00},
-	{R367TER_TSTTS2,	0x1f},
-	{R367TER_TSTTS3,	0x01},
-	{R367TER_TSTTS4,	0x00},
-	{R367TER_TSTTSRC,	0x00},
-	{R367TER_TSTTSRS,	0x00},
-	{R367TER_TSSTATEM,	0xb0},
-	{R367TER_TSSTATEL,	0x40},
-	{R367TER_TSCFGH,	0xC0},
-	{R367TER_TSCFGM,	0xc0},/* for xc5000; was 0x00 */
-	{R367TER_TSCFGL,	0x20},
-	{R367TER_TSSYNC,	0x00},
-	{R367TER_TSINSDELH,	0x00},
-	{R367TER_TSINSDELM,	0x00},
-	{R367TER_TSINSDELL,	0x00},
-	{R367TER_TSDIVN,	0x03},
-	{R367TER_TSDIVPM,	0x00},
-	{R367TER_TSDIVPL,	0x00},
-	{R367TER_TSDIVQM,	0x00},
-	{R367TER_TSDIVQL,	0x00},
-	{R367TER_TSDILSTKM,	0x00},
-	{R367TER_TSDILSTKL,	0x00},
-	{R367TER_TSSPEED,	0x40},/* for xc5000; was 0x6f */
-	{R367TER_TSSTATUS,	0x81},
-	{R367TER_TSSTATUS2,	0x6a},
-	{R367TER_TSBITRATEM,	0x0f},
-	{R367TER_TSBITRATEL,	0xc6},
-	{R367TER_TSPACKLENM,	0x00},
-	{R367TER_TSPACKLENL,	0xfc},
-	{R367TER_TSBLOCLENM,	0x0a},
-	{R367TER_TSBLOCLENL,	0x80},
-	{R367TER_TSDLYH,	0x90},
-	{R367TER_TSDLYM,	0x68},
-	{R367TER_TSDLYL,	0x01},
-	{R367TER_TSNPDAV,	0x00},
-	{R367TER_TSBUFSTATH,	0x00},
-	{R367TER_TSBUFSTATM,	0x00},
-	{R367TER_TSBUFSTATL,	0x00},
-	{R367TER_TSDEBUGM,	0xcf},
-	{R367TER_TSDEBUGL,	0x1e},
-	{R367TER_TSDLYSETH,	0x00},
-	{R367TER_TSDLYSETM,	0x68},
-	{R367TER_TSDLYSETL,	0x00},
-	{R367TER_TSOBSCFG,	0x00},
-	{R367TER_TSOBSM,	0x47},
-	{R367TER_TSOBSL,	0x1f},
-	{R367TER_ERRCTRL1,	0x95},
-	{R367TER_ERRCNT1H,	0x80},
-	{R367TER_ERRCNT1M,	0x00},
-	{R367TER_ERRCNT1L,	0x00},
-	{R367TER_ERRCTRL2,	0x95},
-	{R367TER_ERRCNT2H,	0x00},
-	{R367TER_ERRCNT2M,	0x00},
-	{R367TER_ERRCNT2L,	0x00},
-	{R367TER_FECSPY,	0x88},
-	{R367TER_FSPYCFG,	0x2c},
-	{R367TER_FSPYDATA,	0x3a},
-	{R367TER_FSPYOUT,	0x06},
-	{R367TER_FSTATUS,	0x61},
-	{R367TER_FGOODPACK,	0xff},
-	{R367TER_FPACKCNT,	0xff},
-	{R367TER_FSPYMISC,	0x66},
-	{R367TER_FBERCPT4,	0x00},
-	{R367TER_FBERCPT3,	0x00},
-	{R367TER_FBERCPT2,	0x36},
-	{R367TER_FBERCPT1,	0x36},
-	{R367TER_FBERCPT0,	0x14},
-	{R367TER_FBERERR2,	0x00},
-	{R367TER_FBERERR1,	0x03},
-	{R367TER_FBERERR0,	0x28},
-	{R367TER_FSTATESM,	0x00},
-	{R367TER_FSTATESL,	0x02},
-	{R367TER_FSPYBER,	0x00},
-	{R367TER_FSPYDISTM,	0x01},
-	{R367TER_FSPYDISTL,	0x9f},
-	{R367TER_FSPYOBS7,	0xc9},
-	{R367TER_FSPYOBS6,	0x99},
-	{R367TER_FSPYOBS5,	0x08},
-	{R367TER_FSPYOBS4,	0xec},
-	{R367TER_FSPYOBS3,	0x01},
-	{R367TER_FSPYOBS2,	0x0f},
-	{R367TER_FSPYOBS1,	0xf5},
-	{R367TER_FSPYOBS0,	0x08},
-	{R367TER_SFDEMAP,	0x40},
-	{R367TER_SFERROR,	0x00},
-	{R367TER_SFAVSR,	0x30},
-	{R367TER_SFECSTATUS,	0xcc},
-	{R367TER_SFKDIV12,	0x20},
-	{R367TER_SFKDIV23,	0x40},
-	{R367TER_SFKDIV34,	0x20},
-	{R367TER_SFKDIV56,	0x20},
-	{R367TER_SFKDIV67,	0x00},
-	{R367TER_SFKDIV78,	0x20},
-	{R367TER_SFDILSTKM,	0x00},
-	{R367TER_SFDILSTKL,	0x00},
-	{R367TER_SFSTATUS,	0xb5},
-	{R367TER_SFDLYH,	0x90},
-	{R367TER_SFDLYM,	0x60},
-	{R367TER_SFDLYL,	0x01},
-	{R367TER_SFDLYSETH,	0xc0},
-	{R367TER_SFDLYSETM,	0x60},
-	{R367TER_SFDLYSETL,	0x00},
-	{R367TER_SFOBSCFG,	0x00},
-	{R367TER_SFOBSM,	0x47},
-	{R367TER_SFOBSL,	0x05},
-	{R367TER_SFECINFO,	0x40},
-	{R367TER_SFERRCTRL,	0x74},
-	{R367TER_SFERRCNTH,	0x80},
-	{R367TER_SFERRCNTM ,	0x00},
-	{R367TER_SFERRCNTL,	0x00},
-	{R367TER_SYMBRATEM,	0x2f},
-	{R367TER_SYMBRATEL,	0x50},
-	{R367TER_SYMBSTATUS,	0x7f},
-	{R367TER_SYMBCFG,	0x00},
-	{R367TER_SYMBFIFOM,	0xf4},
-	{R367TER_SYMBFIFOL,	0x0d},
-	{R367TER_SYMBOFFSM,	0xf0},
-	{R367TER_SYMBOFFSL,	0x2d},
-	{R367TER_DEBUG_LT4,	0x00},
-	{R367TER_DEBUG_LT5,	0x00},
-	{R367TER_DEBUG_LT6,	0x00},
-	{R367TER_DEBUG_LT7,	0x00},
-	{R367TER_DEBUG_LT8,	0x00},
-	{R367TER_DEBUG_LT9,	0x00},
-};
-
-#define RF_LOOKUP_TABLE_SIZE  31
-#define RF_LOOKUP_TABLE2_SIZE 16
-/* RF Level (for RF AGC->AGC1) Lookup Table, depends on the board and tuner.*/
-s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = {
-	{/*AGC1*/
-		48, 50, 51, 53, 54, 56, 57, 58, 60, 61, 62, 63,
-		64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
-		76, 77, 78, 80, 83, 85, 88,
-	}, {/*RF(dbm)*/
-		22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
-		34, 35, 36, 37, 38, 39, 41, 42, 43, 44, 46, 47,
-		49, 50, 52, 53, 54, 55, 56,
-	}
-};
-/* RF Level (for IF AGC->AGC2) Lookup Table, depends on the board and tuner.*/
-s32 stv0367cab_RF_LookUp2[RF_LOOKUP_TABLE2_SIZE][RF_LOOKUP_TABLE2_SIZE] = {
-	{/*AGC2*/
-		28, 29, 31, 32, 34, 35, 36, 37,
-		38, 39, 40, 41, 42, 43, 44, 45,
-	}, {/*RF(dbm)*/
-		57, 58, 59, 60, 61, 62, 63, 64,
-		65, 66, 67, 68, 69, 70, 71, 72,
-	}
-};
-
-static struct st_register def0367cab[STV0367CAB_NBREGS] = {
-	{R367CAB_ID,		0x60},
-	{R367CAB_I2CRPT,	0xa0},
-	/*{R367CAB_I2CRPT,	0x22},*/
-	{R367CAB_TOPCTRL,	0x10},
-	{R367CAB_IOCFG0,	0x80},
-	{R367CAB_DAC0R,		0x00},
-	{R367CAB_IOCFG1,	0x00},
-	{R367CAB_DAC1R,		0x00},
-	{R367CAB_IOCFG2,	0x00},
-	{R367CAB_SDFR,		0x00},
-	{R367CAB_AUX_CLK,	0x00},
-	{R367CAB_FREESYS1,	0x00},
-	{R367CAB_FREESYS2,	0x00},
-	{R367CAB_FREESYS3,	0x00},
-	{R367CAB_GPIO_CFG,	0x55},
-	{R367CAB_GPIO_CMD,	0x01},
-	{R367CAB_TSTRES,	0x00},
-	{R367CAB_ANACTRL,	0x0d},/* was 0x00 need to check - I.M.L.*/
-	{R367CAB_TSTBUS,	0x00},
-	{R367CAB_RF_AGC1,	0xea},
-	{R367CAB_RF_AGC2,	0x82},
-	{R367CAB_ANADIGCTRL,	0x0b},
-	{R367CAB_PLLMDIV,	0x01},
-	{R367CAB_PLLNDIV,	0x08},
-	{R367CAB_PLLSETUP,	0x18},
-	{R367CAB_DUAL_AD12,	0x0C}, /* for xc5000 AGC voltage 1.6V */
-	{R367CAB_TSTBIST,	0x00},
-	{R367CAB_CTRL_1,	0x00},
-	{R367CAB_CTRL_2,	0x03},
-	{R367CAB_IT_STATUS1,	0x2b},
-	{R367CAB_IT_STATUS2,	0x08},
-	{R367CAB_IT_EN1,	0x00},
-	{R367CAB_IT_EN2,	0x00},
-	{R367CAB_CTRL_STATUS,	0x04},
-	{R367CAB_TEST_CTL,	0x00},
-	{R367CAB_AGC_CTL,	0x73},
-	{R367CAB_AGC_IF_CFG,	0x50},
-	{R367CAB_AGC_RF_CFG,	0x00},
-	{R367CAB_AGC_PWM_CFG,	0x03},
-	{R367CAB_AGC_PWR_REF_L,	0x5a},
-	{R367CAB_AGC_PWR_REF_H,	0x00},
-	{R367CAB_AGC_RF_TH_L,	0xff},
-	{R367CAB_AGC_RF_TH_H,	0x07},
-	{R367CAB_AGC_IF_LTH_L,	0x00},
-	{R367CAB_AGC_IF_LTH_H,	0x08},
-	{R367CAB_AGC_IF_HTH_L,	0xff},
-	{R367CAB_AGC_IF_HTH_H,	0x07},
-	{R367CAB_AGC_PWR_RD_L,	0xa0},
-	{R367CAB_AGC_PWR_RD_M,	0xe9},
-	{R367CAB_AGC_PWR_RD_H,	0x03},
-	{R367CAB_AGC_PWM_IFCMD_L,	0xe4},
-	{R367CAB_AGC_PWM_IFCMD_H,	0x00},
-	{R367CAB_AGC_PWM_RFCMD_L,	0xff},
-	{R367CAB_AGC_PWM_RFCMD_H,	0x07},
-	{R367CAB_IQDEM_CFG,	0x01},
-	{R367CAB_MIX_NCO_LL,	0x22},
-	{R367CAB_MIX_NCO_HL,	0x96},
-	{R367CAB_MIX_NCO_HH,	0x55},
-	{R367CAB_SRC_NCO_LL,	0xff},
-	{R367CAB_SRC_NCO_LH,	0x0c},
-	{R367CAB_SRC_NCO_HL,	0xf5},
-	{R367CAB_SRC_NCO_HH,	0x20},
-	{R367CAB_IQDEM_GAIN_SRC_L,	0x06},
-	{R367CAB_IQDEM_GAIN_SRC_H,	0x01},
-	{R367CAB_IQDEM_DCRM_CFG_LL,	0xfe},
-	{R367CAB_IQDEM_DCRM_CFG_LH,	0xff},
-	{R367CAB_IQDEM_DCRM_CFG_HL,	0x0f},
-	{R367CAB_IQDEM_DCRM_CFG_HH,	0x00},
-	{R367CAB_IQDEM_ADJ_COEFF0,	0x34},
-	{R367CAB_IQDEM_ADJ_COEFF1,	0xae},
-	{R367CAB_IQDEM_ADJ_COEFF2,	0x46},
-	{R367CAB_IQDEM_ADJ_COEFF3,	0x77},
-	{R367CAB_IQDEM_ADJ_COEFF4,	0x96},
-	{R367CAB_IQDEM_ADJ_COEFF5,	0x69},
-	{R367CAB_IQDEM_ADJ_COEFF6,	0xc7},
-	{R367CAB_IQDEM_ADJ_COEFF7,	0x01},
-	{R367CAB_IQDEM_ADJ_EN,	0x04},
-	{R367CAB_IQDEM_ADJ_AGC_REF,	0x94},
-	{R367CAB_ALLPASSFILT1,	0xc9},
-	{R367CAB_ALLPASSFILT2,	0x2d},
-	{R367CAB_ALLPASSFILT3,	0xa3},
-	{R367CAB_ALLPASSFILT4,	0xfb},
-	{R367CAB_ALLPASSFILT5,	0xf6},
-	{R367CAB_ALLPASSFILT6,	0x45},
-	{R367CAB_ALLPASSFILT7,	0x6f},
-	{R367CAB_ALLPASSFILT8,	0x7e},
-	{R367CAB_ALLPASSFILT9,	0x05},
-	{R367CAB_ALLPASSFILT10,	0x0a},
-	{R367CAB_ALLPASSFILT11,	0x51},
-	{R367CAB_TRL_AGC_CFG,	0x20},
-	{R367CAB_TRL_LPF_CFG,	0x28},
-	{R367CAB_TRL_LPF_ACQ_GAIN,	0x44},
-	{R367CAB_TRL_LPF_TRK_GAIN,	0x22},
-	{R367CAB_TRL_LPF_OUT_GAIN,	0x03},
-	{R367CAB_TRL_LOCKDET_LTH,	0x04},
-	{R367CAB_TRL_LOCKDET_HTH,	0x11},
-	{R367CAB_TRL_LOCKDET_TRGVAL,	0x20},
-	{R367CAB_IQ_QAM,	0x01},
-	{R367CAB_FSM_STATE,	0xa0},
-	{R367CAB_FSM_CTL,	0x08},
-	{R367CAB_FSM_STS,	0x0c},
-	{R367CAB_FSM_SNR0_HTH,	0x00},
-	{R367CAB_FSM_SNR1_HTH,	0x00},
-	{R367CAB_FSM_SNR2_HTH,	0x23},/* 0x00 */
-	{R367CAB_FSM_SNR0_LTH,	0x00},
-	{R367CAB_FSM_SNR1_LTH,	0x00},
-	{R367CAB_FSM_EQA1_HTH,	0x00},
-	{R367CAB_FSM_TEMPO,	0x32},
-	{R367CAB_FSM_CONFIG,	0x03},
-	{R367CAB_EQU_I_TESTTAP_L,	0x11},
-	{R367CAB_EQU_I_TESTTAP_M,	0x00},
-	{R367CAB_EQU_I_TESTTAP_H,	0x00},
-	{R367CAB_EQU_TESTAP_CFG,	0x00},
-	{R367CAB_EQU_Q_TESTTAP_L,	0xff},
-	{R367CAB_EQU_Q_TESTTAP_M,	0x00},
-	{R367CAB_EQU_Q_TESTTAP_H,	0x00},
-	{R367CAB_EQU_TAP_CTRL,	0x00},
-	{R367CAB_EQU_CTR_CRL_CONTROL_L,	0x11},
-	{R367CAB_EQU_CTR_CRL_CONTROL_H,	0x05},
-	{R367CAB_EQU_CTR_HIPOW_L,	0x00},
-	{R367CAB_EQU_CTR_HIPOW_H,	0x00},
-	{R367CAB_EQU_I_EQU_LO,	0xef},
-	{R367CAB_EQU_I_EQU_HI,	0x00},
-	{R367CAB_EQU_Q_EQU_LO,	0xee},
-	{R367CAB_EQU_Q_EQU_HI,	0x00},
-	{R367CAB_EQU_MAPPER,	0xc5},
-	{R367CAB_EQU_SWEEP_RATE,	0x80},
-	{R367CAB_EQU_SNR_LO,	0x64},
-	{R367CAB_EQU_SNR_HI,	0x03},
-	{R367CAB_EQU_GAMMA_LO,	0x00},
-	{R367CAB_EQU_GAMMA_HI,	0x00},
-	{R367CAB_EQU_ERR_GAIN,	0x36},
-	{R367CAB_EQU_RADIUS,	0xaa},
-	{R367CAB_EQU_FFE_MAINTAP,	0x00},
-	{R367CAB_EQU_FFE_LEAKAGE,	0x63},
-	{R367CAB_EQU_FFE_MAINTAP_POS,	0xdf},
-	{R367CAB_EQU_GAIN_WIDE,	0x88},
-	{R367CAB_EQU_GAIN_NARROW,	0x41},
-	{R367CAB_EQU_CTR_LPF_GAIN,	0xd1},
-	{R367CAB_EQU_CRL_LPF_GAIN,	0xa7},
-	{R367CAB_EQU_GLOBAL_GAIN,	0x06},
-	{R367CAB_EQU_CRL_LD_SEN,	0x85},
-	{R367CAB_EQU_CRL_LD_VAL,	0xe2},
-	{R367CAB_EQU_CRL_TFR,	0x20},
-	{R367CAB_EQU_CRL_BISTH_LO,	0x00},
-	{R367CAB_EQU_CRL_BISTH_HI,	0x00},
-	{R367CAB_EQU_SWEEP_RANGE_LO,	0x00},
-	{R367CAB_EQU_SWEEP_RANGE_HI,	0x00},
-	{R367CAB_EQU_CRL_LIMITER,	0x40},
-	{R367CAB_EQU_MODULUS_MAP,	0x90},
-	{R367CAB_EQU_PNT_GAIN,	0xa7},
-	{R367CAB_FEC_AC_CTR_0,	0x16},
-	{R367CAB_FEC_AC_CTR_1,	0x0b},
-	{R367CAB_FEC_AC_CTR_2,	0x88},
-	{R367CAB_FEC_AC_CTR_3,	0x02},
-	{R367CAB_FEC_STATUS,	0x12},
-	{R367CAB_RS_COUNTER_0,	0x7d},
-	{R367CAB_RS_COUNTER_1,	0xd0},
-	{R367CAB_RS_COUNTER_2,	0x19},
-	{R367CAB_RS_COUNTER_3,	0x0b},
-	{R367CAB_RS_COUNTER_4,	0xa3},
-	{R367CAB_RS_COUNTER_5,	0x00},
-	{R367CAB_BERT_0,	0x01},
-	{R367CAB_BERT_1,	0x25},
-	{R367CAB_BERT_2,	0x41},
-	{R367CAB_BERT_3,	0x39},
-	{R367CAB_OUTFORMAT_0,	0xc2},
-	{R367CAB_OUTFORMAT_1,	0x22},
-	{R367CAB_SMOOTHER_2,	0x28},
-	{R367CAB_TSMF_CTRL_0,	0x01},
-	{R367CAB_TSMF_CTRL_1,	0xc6},
-	{R367CAB_TSMF_CTRL_3,	0x43},
-	{R367CAB_TS_ON_ID_0,	0x00},
-	{R367CAB_TS_ON_ID_1,	0x00},
-	{R367CAB_TS_ON_ID_2,	0x00},
-	{R367CAB_TS_ON_ID_3,	0x00},
-	{R367CAB_RE_STATUS_0,	0x00},
-	{R367CAB_RE_STATUS_1,	0x00},
-	{R367CAB_RE_STATUS_2,	0x00},
-	{R367CAB_RE_STATUS_3,	0x00},
-	{R367CAB_TS_STATUS_0,	0x00},
-	{R367CAB_TS_STATUS_1,	0x00},
-	{R367CAB_TS_STATUS_2,	0xa0},
-	{R367CAB_TS_STATUS_3,	0x00},
-	{R367CAB_T_O_ID_0,	0x00},
-	{R367CAB_T_O_ID_1,	0x00},
-	{R367CAB_T_O_ID_2,	0x00},
-	{R367CAB_T_O_ID_3,	0x00},
-};
-
-static
-int stv0367_writeregs(struct stv0367_state *state, u16 reg, u8 *data, int len)
-{
-	u8 buf[len + 2];
-	struct i2c_msg msg = {
-		.addr = state->config->demod_address,
-		.flags = 0,
-		.buf = buf,
-		.len = len + 2
-	};
-	int ret;
-
-	buf[0] = MSB(reg);
-	buf[1] = LSB(reg);
-	memcpy(buf + 2, data, len);
-
-	if (i2cdebug)
-		printk(KERN_DEBUG "%s: %02x: %02x\n", __func__, reg, buf[2]);
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-	if (ret != 1)
-		printk(KERN_ERR "%s: i2c write error!\n", __func__);
-
-	return (ret != 1) ? -EREMOTEIO : 0;
-}
-
-static int stv0367_writereg(struct stv0367_state *state, u16 reg, u8 data)
-{
-	return stv0367_writeregs(state, reg, &data, 1);
-}
-
-static u8 stv0367_readreg(struct stv0367_state *state, u16 reg)
-{
-	u8 b0[] = { 0, 0 };
-	u8 b1[] = { 0 };
-	struct i2c_msg msg[] = {
-		{
-			.addr = state->config->demod_address,
-			.flags = 0,
-			.buf = b0,
-			.len = 2
-		}, {
-			.addr = state->config->demod_address,
-			.flags = I2C_M_RD,
-			.buf = b1,
-			.len = 1
-		}
-	};
-	int ret;
-
-	b0[0] = MSB(reg);
-	b0[1] = LSB(reg);
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-	if (ret != 2)
-		printk(KERN_ERR "%s: i2c read error\n", __func__);
-
-	if (i2cdebug)
-		printk(KERN_DEBUG "%s: %02x: %02x\n", __func__, reg, b1[0]);
-
-	return b1[0];
-}
-
-static void extract_mask_pos(u32 label, u8 *mask, u8 *pos)
-{
-	u8 position = 0, i = 0;
-
-	(*mask) = label & 0xff;
-
-	while ((position == 0) && (i < 8)) {
-		position = ((*mask) >> i) & 0x01;
-		i++;
-	}
-
-	(*pos) = (i - 1);
-}
-
-static void stv0367_writebits(struct stv0367_state *state, u32 label, u8 val)
-{
-	u8 reg, mask, pos;
-
-	reg = stv0367_readreg(state, (label >> 16) & 0xffff);
-	extract_mask_pos(label, &mask, &pos);
-
-	val = mask & (val << pos);
-
-	reg = (reg & (~mask)) | val;
-	stv0367_writereg(state, (label >> 16) & 0xffff, reg);
-
-}
-
-static void stv0367_setbits(u8 *reg, u32 label, u8 val)
-{
-	u8 mask, pos;
-
-	extract_mask_pos(label, &mask, &pos);
-
-	val = mask & (val << pos);
-
-	(*reg) = ((*reg) & (~mask)) | val;
-}
-
-static u8 stv0367_readbits(struct stv0367_state *state, u32 label)
-{
-	u8 val = 0xff;
-	u8 mask, pos;
-
-	extract_mask_pos(label, &mask, &pos);
-
-	val = stv0367_readreg(state, label >> 16);
-	val = (val & mask) >> pos;
-
-	return val;
-}
-
-u8 stv0367_getbits(u8 reg, u32 label)
-{
-	u8 mask, pos;
-
-	extract_mask_pos(label, &mask, &pos);
-
-	return (reg & mask) >> pos;
-}
-
-static int stv0367ter_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct stv0367_state *state = fe->demodulator_priv;
-	u8 tmp = stv0367_readreg(state, R367TER_I2CRPT);
-
-	dprintk("%s:\n", __func__);
-
-	if (enable) {
-		stv0367_setbits(&tmp, F367TER_STOP_ENABLE, 0);
-		stv0367_setbits(&tmp, F367TER_I2CT_ON, 1);
-	} else {
-		stv0367_setbits(&tmp, F367TER_STOP_ENABLE, 1);
-		stv0367_setbits(&tmp, F367TER_I2CT_ON, 0);
-	}
-
-	stv0367_writereg(state, R367TER_I2CRPT, tmp);
-
-	return 0;
-}
-
-static u32 stv0367_get_tuner_freq(struct dvb_frontend *fe)
-{
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
-	u32 freq = 0;
-	int err = 0;
-
-	dprintk("%s:\n", __func__);
-
-
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
-	if (tuner_ops->get_frequency) {
-		err = tuner_ops->get_frequency(fe, &freq);
-		if (err < 0) {
-			printk(KERN_ERR "%s: Invalid parameter\n", __func__);
-			return err;
-		}
-
-		dprintk("%s: frequency=%d\n", __func__, freq);
-
-	} else
-		return -1;
-
-	return freq;
-}
-
-static u16 CellsCoeffs_8MHz_367cofdm[3][6][5] = {
-	{
-		{0x10EF, 0xE205, 0x10EF, 0xCE49, 0x6DA7}, /* CELL 1 COEFFS 27M*/
-		{0x2151, 0xc557, 0x2151, 0xc705, 0x6f93}, /* CELL 2 COEFFS */
-		{0x2503, 0xc000, 0x2503, 0xc375, 0x7194}, /* CELL 3 COEFFS */
-		{0x20E9, 0xca94, 0x20e9, 0xc153, 0x7194}, /* CELL 4 COEFFS */
-		{0x06EF, 0xF852, 0x06EF, 0xC057, 0x7207}, /* CELL 5 COEFFS */
-		{0x0000, 0x0ECC, 0x0ECC, 0x0000, 0x3647} /* CELL 6 COEFFS */
-	}, {
-		{0x10A0, 0xE2AF, 0x10A1, 0xCE76, 0x6D6D}, /* CELL 1 COEFFS 25M*/
-		{0x20DC, 0xC676, 0x20D9, 0xC80A, 0x6F29},
-		{0x2532, 0xC000, 0x251D, 0xC391, 0x706F},
-		{0x1F7A, 0xCD2B, 0x2032, 0xC15E, 0x711F},
-		{0x0698, 0xFA5E, 0x0568, 0xC059, 0x7193},
-		{0x0000, 0x0918, 0x149C, 0x0000, 0x3642} /* CELL 6 COEFFS */
-	}, {
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000}
-	}
-};
-
-static u16 CellsCoeffs_7MHz_367cofdm[3][6][5] = {
-	{
-		{0x12CA, 0xDDAF, 0x12CA, 0xCCEB, 0x6FB1}, /* CELL 1 COEFFS 27M*/
-		{0x2329, 0xC000, 0x2329, 0xC6B0, 0x725F}, /* CELL 2 COEFFS */
-		{0x2394, 0xC000, 0x2394, 0xC2C7, 0x7410}, /* CELL 3 COEFFS */
-		{0x251C, 0xC000, 0x251C, 0xC103, 0x74D9}, /* CELL 4 COEFFS */
-		{0x0804, 0xF546, 0x0804, 0xC040, 0x7544}, /* CELL 5 COEFFS */
-		{0x0000, 0x0CD9, 0x0CD9, 0x0000, 0x370A} /* CELL 6 COEFFS */
-	}, {
-		{0x1285, 0xDE47, 0x1285, 0xCD17, 0x6F76}, /*25M*/
-		{0x234C, 0xC000, 0x2348, 0xC6DA, 0x7206},
-		{0x23B4, 0xC000, 0x23AC, 0xC2DB, 0x73B3},
-		{0x253D, 0xC000, 0x25B6, 0xC10B, 0x747F},
-		{0x0721, 0xF79C, 0x065F, 0xC041, 0x74EB},
-		{0x0000, 0x08FA, 0x1162, 0x0000, 0x36FF}
-	}, {
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000}
-	}
-};
-
-static u16 CellsCoeffs_6MHz_367cofdm[3][6][5] = {
-	{
-		{0x1699, 0xD5B8, 0x1699, 0xCBC3, 0x713B}, /* CELL 1 COEFFS 27M*/
-		{0x2245, 0xC000, 0x2245, 0xC568, 0x74D5}, /* CELL 2 COEFFS */
-		{0x227F, 0xC000, 0x227F, 0xC1FC, 0x76C6}, /* CELL 3 COEFFS */
-		{0x235E, 0xC000, 0x235E, 0xC0A7, 0x778A}, /* CELL 4 COEFFS */
-		{0x0ECB, 0xEA0B, 0x0ECB, 0xC027, 0x77DD}, /* CELL 5 COEFFS */
-		{0x0000, 0x0B68, 0x0B68, 0x0000, 0xC89A}, /* CELL 6 COEFFS */
-	}, {
-		{0x1655, 0xD64E, 0x1658, 0xCBEF, 0x70FE}, /*25M*/
-		{0x225E, 0xC000, 0x2256, 0xC589, 0x7489},
-		{0x2293, 0xC000, 0x2295, 0xC209, 0x767E},
-		{0x2377, 0xC000, 0x23AA, 0xC0AB, 0x7746},
-		{0x0DC7, 0xEBC8, 0x0D07, 0xC027, 0x7799},
-		{0x0000, 0x0888, 0x0E9C, 0x0000, 0x3757}
-
-	}, {
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
-		{0x0000, 0x0000, 0x0000, 0x0000, 0x0000}
-	}
-};
-
-static u32 stv0367ter_get_mclk(struct stv0367_state *state, u32 ExtClk_Hz)
-{
-	u32 mclk_Hz = 0; /* master clock frequency (Hz) */
-	u32 m, n, p;
-
-	dprintk("%s:\n", __func__);
-
-	if (stv0367_readbits(state, F367TER_BYPASS_PLLXN) == 0) {
-		n = (u32)stv0367_readbits(state, F367TER_PLL_NDIV);
-		if (n == 0)
-			n = n + 1;
-
-		m = (u32)stv0367_readbits(state, F367TER_PLL_MDIV);
-		if (m == 0)
-			m = m + 1;
-
-		p = (u32)stv0367_readbits(state, F367TER_PLL_PDIV);
-		if (p > 5)
-			p = 5;
-
-		mclk_Hz = ((ExtClk_Hz / 2) * n) / (m * (1 << p));
-
-		dprintk("N=%d M=%d P=%d mclk_Hz=%d ExtClk_Hz=%d\n",
-				n, m, p, mclk_Hz, ExtClk_Hz);
-	} else
-		mclk_Hz = ExtClk_Hz;
-
-	dprintk("%s: mclk_Hz=%d\n", __func__, mclk_Hz);
-
-	return mclk_Hz;
-}
-
-static int stv0367ter_filt_coeff_init(struct stv0367_state *state,
-				u16 CellsCoeffs[3][6][5], u32 DemodXtal)
-{
-	int i, j, k, freq;
-
-	dprintk("%s:\n", __func__);
-
-	freq = stv0367ter_get_mclk(state, DemodXtal);
-
-	if (freq == 53125000)
-		k = 1; /* equivalent to Xtal 25M on 362*/
-	else if (freq == 54000000)
-		k = 0; /* equivalent to Xtal 27M on 362*/
-	else if (freq == 52500000)
-		k = 2; /* equivalent to Xtal 30M on 362*/
-	else
-		return 0;
-
-	for (i = 1; i <= 6; i++) {
-		stv0367_writebits(state, F367TER_IIR_CELL_NB, i - 1);
-
-		for (j = 1; j <= 5; j++) {
-			stv0367_writereg(state,
-				(R367TER_IIRCX_COEFF1_MSB + 2 * (j - 1)),
-				MSB(CellsCoeffs[k][i-1][j-1]));
-			stv0367_writereg(state,
-				(R367TER_IIRCX_COEFF1_LSB + 2 * (j - 1)),
-				LSB(CellsCoeffs[k][i-1][j-1]));
-		}
-	}
-
-	return 1;
-
-}
-
-static void stv0367ter_agc_iir_lock_detect_set(struct stv0367_state *state)
-{
-	dprintk("%s:\n", __func__);
-
-	stv0367_writebits(state, F367TER_LOCK_DETECT_LSB, 0x00);
-
-	/* Lock detect 1 */
-	stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x00);
-	stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x06);
-	stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x04);
-
-	/* Lock detect 2 */
-	stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x01);
-	stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x06);
-	stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x04);
-
-	/* Lock detect 3 */
-	stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x02);
-	stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x01);
-	stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x00);
-
-	/* Lock detect 4 */
-	stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x03);
-	stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x01);
-	stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x00);
-
-}
-
-static int stv0367_iir_filt_init(struct stv0367_state *state, u8 Bandwidth,
-							u32 DemodXtalValue)
-{
-	dprintk("%s:\n", __func__);
-
-	stv0367_writebits(state, F367TER_NRST_IIR, 0);
-
-	switch (Bandwidth) {
-	case 6:
-		if (!stv0367ter_filt_coeff_init(state,
-				CellsCoeffs_6MHz_367cofdm,
-				DemodXtalValue))
-			return 0;
-		break;
-	case 7:
-		if (!stv0367ter_filt_coeff_init(state,
-				CellsCoeffs_7MHz_367cofdm,
-				DemodXtalValue))
-			return 0;
-		break;
-	case 8:
-		if (!stv0367ter_filt_coeff_init(state,
-				CellsCoeffs_8MHz_367cofdm,
-				DemodXtalValue))
-			return 0;
-		break;
-	default:
-		return 0;
-	}
-
-	stv0367_writebits(state, F367TER_NRST_IIR, 1);
-
-	return 1;
-}
-
-static void stv0367ter_agc_iir_rst(struct stv0367_state *state)
-{
-
-	u8 com_n;
-
-	dprintk("%s:\n", __func__);
-
-	com_n = stv0367_readbits(state, F367TER_COM_N);
-
-	stv0367_writebits(state, F367TER_COM_N, 0x07);
-
-	stv0367_writebits(state, F367TER_COM_SOFT_RSTN, 0x00);
-	stv0367_writebits(state, F367TER_COM_AGC_ON, 0x00);
-
-	stv0367_writebits(state, F367TER_COM_SOFT_RSTN, 0x01);
-	stv0367_writebits(state, F367TER_COM_AGC_ON, 0x01);
-
-	stv0367_writebits(state, F367TER_COM_N, com_n);
-
-}
-
-static int stv0367ter_duration(s32 mode, int tempo1, int tempo2, int tempo3)
-{
-	int local_tempo = 0;
-	switch (mode) {
-	case 0:
-		local_tempo = tempo1;
-		break;
-	case 1:
-		local_tempo = tempo2;
-		break ;
-
-	case 2:
-		local_tempo = tempo3;
-		break;
-
-	default:
-		break;
-	}
-	/*	msleep(local_tempo);  */
-	return local_tempo;
-}
-
-static enum
-stv0367_ter_signal_type stv0367ter_check_syr(struct stv0367_state *state)
-{
-	int wd = 100;
-	unsigned short int SYR_var;
-	s32 SYRStatus;
-
-	dprintk("%s:\n", __func__);
-
-	SYR_var = stv0367_readbits(state, F367TER_SYR_LOCK);
-
-	while ((!SYR_var) && (wd > 0)) {
-		usleep_range(2000, 3000);
-		wd -= 2;
-		SYR_var = stv0367_readbits(state, F367TER_SYR_LOCK);
-	}
-
-	if (!SYR_var)
-		SYRStatus = FE_TER_NOSYMBOL;
-	else
-		SYRStatus =  FE_TER_SYMBOLOK;
-
-	dprintk("stv0367ter_check_syr SYRStatus %s\n",
-				SYR_var == 0 ? "No Symbol" : "OK");
-
-	return SYRStatus;
-}
-
-static enum
-stv0367_ter_signal_type stv0367ter_check_cpamp(struct stv0367_state *state,
-								s32 FFTmode)
-{
-
-	s32  CPAMPvalue = 0, CPAMPStatus, CPAMPMin;
-	int wd = 0;
-
-	dprintk("%s:\n", __func__);
-
-	switch (FFTmode) {
-	case 0: /*2k mode*/
-		CPAMPMin = 20;
-		wd = 10;
-		break;
-	case 1: /*8k mode*/
-		CPAMPMin = 80;
-		wd = 55;
-		break;
-	case 2: /*4k mode*/
-		CPAMPMin = 40;
-		wd = 30;
-		break;
-	default:
-		CPAMPMin = 0xffff;  /*drives to NOCPAMP	*/
-		break;
-	}
-
-	dprintk("%s: CPAMPMin=%d wd=%d\n", __func__, CPAMPMin, wd);
-
-	CPAMPvalue = stv0367_readbits(state, F367TER_PPM_CPAMP_DIRECT);
-	while ((CPAMPvalue < CPAMPMin) && (wd > 0)) {
-		usleep_range(1000, 2000);
-		wd -= 1;
-		CPAMPvalue = stv0367_readbits(state, F367TER_PPM_CPAMP_DIRECT);
-		/*dprintk("CPAMPvalue= %d at wd=%d\n",CPAMPvalue,wd); */
-	}
-	dprintk("******last CPAMPvalue= %d at wd=%d\n", CPAMPvalue, wd);
-	if (CPAMPvalue < CPAMPMin) {
-		CPAMPStatus = FE_TER_NOCPAMP;
-		printk(KERN_ERR "CPAMP failed\n");
-	} else {
-		printk(KERN_ERR "CPAMP OK !\n");
-		CPAMPStatus = FE_TER_CPAMPOK;
-	}
-
-	return CPAMPStatus;
-}
-
-enum
-stv0367_ter_signal_type stv0367ter_lock_algo(struct stv0367_state *state)
-{
-	enum stv0367_ter_signal_type ret_flag;
-	short int wd, tempo;
-	u8 try, u_var1 = 0, u_var2 = 0, u_var3 = 0, u_var4 = 0, mode, guard;
-	u8 tmp, tmp2;
-
-	dprintk("%s:\n", __func__);
-
-	if (state == NULL)
-		return FE_TER_SWNOK;
-
-	try = 0;
-	do {
-		ret_flag = FE_TER_LOCKOK;
-
-		stv0367_writebits(state, F367TER_CORE_ACTIVE, 0);
-
-		if (state->config->if_iq_mode != 0)
-			stv0367_writebits(state, F367TER_COM_N, 0x07);
-
-		stv0367_writebits(state, F367TER_GUARD, 3);/* suggest 2k 1/4 */
-		stv0367_writebits(state, F367TER_MODE, 0);
-		stv0367_writebits(state, F367TER_SYR_TR_DIS, 0);
-		usleep_range(5000, 10000);
-
-		stv0367_writebits(state, F367TER_CORE_ACTIVE, 1);
-
-
-		if (stv0367ter_check_syr(state) == FE_TER_NOSYMBOL)
-			return FE_TER_NOSYMBOL;
-		else { /*
-			if chip locked on wrong mode first try,
-			it must lock correctly second try */
-			mode = stv0367_readbits(state, F367TER_SYR_MODE);
-			if (stv0367ter_check_cpamp(state, mode) ==
-							FE_TER_NOCPAMP) {
-				if (try == 0)
-					ret_flag = FE_TER_NOCPAMP;
-
-			}
-		}
-
-		try++;
-	} while ((try < 10) && (ret_flag != FE_TER_LOCKOK));
-
-	tmp  = stv0367_readreg(state, R367TER_SYR_STAT);
-	tmp2 = stv0367_readreg(state, R367TER_STATUS);
-	dprintk("state=%p\n", state);
-	dprintk("LOCK OK! mode=%d SYR_STAT=0x%x R367TER_STATUS=0x%x\n",
-							mode, tmp, tmp2);
-
-	tmp  = stv0367_readreg(state, R367TER_PRVIT);
-	tmp2 = stv0367_readreg(state, R367TER_I2CRPT);
-	dprintk("PRVIT=0x%x I2CRPT=0x%x\n", tmp, tmp2);
-
-	tmp  = stv0367_readreg(state, R367TER_GAIN_SRC1);
-	dprintk("GAIN_SRC1=0x%x\n", tmp);
-
-	if ((mode != 0) && (mode != 1) && (mode != 2))
-		return FE_TER_SWNOK;
-
-	/*guard=stv0367_readbits(state,F367TER_SYR_GUARD); */
-
-	/*suppress EPQ auto for SYR_GARD 1/16 or 1/32
-	and set channel predictor in automatic */
-#if 0
-	switch (guard) {
-
-	case 0:
-	case 1:
-		stv0367_writebits(state, F367TER_AUTO_LE_EN, 0);
-		stv0367_writereg(state, R367TER_CHC_CTL, 0x01);
-		break;
-	case 2:
-	case 3:
-		stv0367_writebits(state, F367TER_AUTO_LE_EN, 1);
-		stv0367_writereg(state, R367TER_CHC_CTL, 0x11);
-		break;
-
-	default:
-		return FE_TER_SWNOK;
-	}
-#endif
-
-	/*reset fec an reedsolo FOR 367 only*/
-	stv0367_writebits(state, F367TER_RST_SFEC, 1);
-	stv0367_writebits(state, F367TER_RST_REEDSOLO, 1);
-	usleep_range(1000, 2000);
-	stv0367_writebits(state, F367TER_RST_SFEC, 0);
-	stv0367_writebits(state, F367TER_RST_REEDSOLO, 0);
-
-	u_var1 = stv0367_readbits(state, F367TER_LK);
-	u_var2 = stv0367_readbits(state, F367TER_PRF);
-	u_var3 = stv0367_readbits(state, F367TER_TPS_LOCK);
-	/*	u_var4=stv0367_readbits(state,F367TER_TSFIFO_LINEOK); */
-
-	wd = stv0367ter_duration(mode, 125, 500, 250);
-	tempo = stv0367ter_duration(mode, 4, 16, 8);
-
-	/*while ( ((!u_var1)||(!u_var2)||(!u_var3)||(!u_var4))  && (wd>=0)) */
-	while (((!u_var1) || (!u_var2) || (!u_var3)) && (wd >= 0)) {
-		usleep_range(1000 * tempo, 1000 * (tempo + 1));
-		wd -= tempo;
-		u_var1 = stv0367_readbits(state, F367TER_LK);
-		u_var2 = stv0367_readbits(state, F367TER_PRF);
-		u_var3 = stv0367_readbits(state, F367TER_TPS_LOCK);
-		/*u_var4=stv0367_readbits(state, F367TER_TSFIFO_LINEOK); */
-	}
-
-	if (!u_var1)
-		return FE_TER_NOLOCK;
-
-
-	if (!u_var2)
-		return FE_TER_NOPRFOUND;
-
-	if (!u_var3)
-		return FE_TER_NOTPS;
-
-	guard = stv0367_readbits(state, F367TER_SYR_GUARD);
-	stv0367_writereg(state, R367TER_CHC_CTL, 0x11);
-	switch (guard) {
-	case 0:
-	case 1:
-		stv0367_writebits(state, F367TER_AUTO_LE_EN, 0);
-		/*stv0367_writereg(state,R367TER_CHC_CTL, 0x1);*/
-		stv0367_writebits(state, F367TER_SYR_FILTER, 0);
-		break;
-	case 2:
-	case 3:
-		stv0367_writebits(state, F367TER_AUTO_LE_EN, 1);
-		/*stv0367_writereg(state,R367TER_CHC_CTL, 0x11);*/
-		stv0367_writebits(state, F367TER_SYR_FILTER, 1);
-		break;
-
-	default:
-		return FE_TER_SWNOK;
-	}
-
-	/* apply Sfec workaround if 8K 64QAM CR!=1/2*/
-	if ((stv0367_readbits(state, F367TER_TPS_CONST) == 2) &&
-			(mode == 1) &&
-			(stv0367_readbits(state, F367TER_TPS_HPCODE) != 0)) {
-		stv0367_writereg(state, R367TER_SFDLYSETH, 0xc0);
-		stv0367_writereg(state, R367TER_SFDLYSETM, 0x60);
-		stv0367_writereg(state, R367TER_SFDLYSETL, 0x0);
-	} else
-		stv0367_writereg(state, R367TER_SFDLYSETH, 0x0);
-
-	wd = stv0367ter_duration(mode, 125, 500, 250);
-	u_var4 = stv0367_readbits(state, F367TER_TSFIFO_LINEOK);
-
-	while ((!u_var4) && (wd >= 0)) {
-		usleep_range(1000 * tempo, 1000 * (tempo + 1));
-		wd -= tempo;
-		u_var4 = stv0367_readbits(state, F367TER_TSFIFO_LINEOK);
-	}
-
-	if (!u_var4)
-		return FE_TER_NOLOCK;
-
-	/* for 367 leave COM_N at 0x7 for IQ_mode*/
-	/*if(ter_state->if_iq_mode!=FE_TER_NORMAL_IF_TUNER) {
-		tempo=0;
-		while ((stv0367_readbits(state,F367TER_COM_USEGAINTRK)!=1) &&
-		(stv0367_readbits(state,F367TER_COM_AGCLOCK)!=1)&&(tempo<100)) {
-			ChipWaitOrAbort(state,1);
-			tempo+=1;
-		}
-
-		stv0367_writebits(state,F367TER_COM_N,0x17);
-	} */
-
-	stv0367_writebits(state, F367TER_SYR_TR_DIS, 1);
-
-	dprintk("FE_TER_LOCKOK !!!\n");
-
-	return	FE_TER_LOCKOK;
-
-}
-
-static void stv0367ter_set_ts_mode(struct stv0367_state *state,
-					enum stv0367_ts_mode PathTS)
-{
-
-	dprintk("%s:\n", __func__);
-
-	if (state == NULL)
-		return;
-
-	stv0367_writebits(state, F367TER_TS_DIS, 0);
-	switch (PathTS) {
-	default:
-		/*for removing warning :default we can assume in parallel mode*/
-	case STV0367_PARALLEL_PUNCT_CLOCK:
-		stv0367_writebits(state, F367TER_TSFIFO_SERIAL, 0);
-		stv0367_writebits(state, F367TER_TSFIFO_DVBCI, 0);
-		break;
-	case STV0367_SERIAL_PUNCT_CLOCK:
-		stv0367_writebits(state, F367TER_TSFIFO_SERIAL, 1);
-		stv0367_writebits(state, F367TER_TSFIFO_DVBCI, 1);
-		break;
-	}
-}
-
-static void stv0367ter_set_clk_pol(struct stv0367_state *state,
-					enum stv0367_clk_pol clock)
-{
-
-	dprintk("%s:\n", __func__);
-
-	if (state == NULL)
-		return;
-
-	switch (clock) {
-	case STV0367_RISINGEDGE_CLOCK:
-		stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 1);
-		break;
-	case STV0367_FALLINGEDGE_CLOCK:
-		stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 0);
-		break;
-		/*case FE_TER_CLOCK_POLARITY_DEFAULT:*/
-	default:
-		stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 0);
-		break;
-	}
-}
-
-#if 0
-static void stv0367ter_core_sw(struct stv0367_state *state)
-{
-
-	dprintk("%s:\n", __func__);
-
-	stv0367_writebits(state, F367TER_CORE_ACTIVE, 0);
-	stv0367_writebits(state, F367TER_CORE_ACTIVE, 1);
-	msleep(350);
-}
-#endif
-static int stv0367ter_standby(struct dvb_frontend *fe, u8 standby_on)
-{
-	struct stv0367_state *state = fe->demodulator_priv;
-
-	dprintk("%s:\n", __func__);
-
-	if (standby_on) {
-		stv0367_writebits(state, F367TER_STDBY, 1);
-		stv0367_writebits(state, F367TER_STDBY_FEC, 1);
-		stv0367_writebits(state, F367TER_STDBY_CORE, 1);
-	} else {
-		stv0367_writebits(state, F367TER_STDBY, 0);
-		stv0367_writebits(state, F367TER_STDBY_FEC, 0);
-		stv0367_writebits(state, F367TER_STDBY_CORE, 0);
-	}
-
-	return 0;
-}
-
-static int stv0367ter_sleep(struct dvb_frontend *fe)
-{
-	return stv0367ter_standby(fe, 1);
-}
-
-int stv0367ter_init(struct dvb_frontend *fe)
-{
-	struct stv0367_state *state = fe->demodulator_priv;
-	struct stv0367ter_state *ter_state = state->ter_state;
-	int i;
-
-	dprintk("%s:\n", __func__);
-
-	ter_state->pBER = 0;
-
-	for (i = 0; i < STV0367TER_NBREGS; i++)
-		stv0367_writereg(state, def0367ter[i].addr,
-					def0367ter[i].value);
-
-	switch (state->config->xtal) {
-		/*set internal freq to 53.125MHz */
-	case 25000000:
-		stv0367_writereg(state, R367TER_PLLMDIV, 0xa);
-		stv0367_writereg(state, R367TER_PLLNDIV, 0x55);
-		stv0367_writereg(state, R367TER_PLLSETUP, 0x18);
-		break;
-	default:
-	case 27000000:
-		dprintk("FE_STV0367TER_SetCLKgen for 27Mhz\n");
-		stv0367_writereg(state, R367TER_PLLMDIV, 0x1);
-		stv0367_writereg(state, R367TER_PLLNDIV, 0x8);
-		stv0367_writereg(state, R367TER_PLLSETUP, 0x18);
-		break;
-	case 30000000:
-		stv0367_writereg(state, R367TER_PLLMDIV, 0xc);
-		stv0367_writereg(state, R367TER_PLLNDIV, 0x55);
-		stv0367_writereg(state, R367TER_PLLSETUP, 0x18);
-		break;
-	}
-
-	stv0367_writereg(state, R367TER_I2CRPT, 0xa0);
-	stv0367_writereg(state, R367TER_ANACTRL, 0x00);
-
-	/*Set TS1 and TS2 to serial or parallel mode */
-	stv0367ter_set_ts_mode(state, state->config->ts_mode);
-	stv0367ter_set_clk_pol(state, state->config->clk_pol);
-
-	state->chip_id = stv0367_readreg(state, R367TER_ID);
-	ter_state->first_lock = 0;
-	ter_state->unlock_counter = 2;
-
-	return 0;
-}
-
-static int stv0367ter_algo(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct stv0367_state *state = fe->demodulator_priv;
-	struct stv0367ter_state *ter_state = state->ter_state;
-	int offset = 0, tempo = 0;
-	u8 u_var;
-	u8 /*constell,*/ counter;
-	s8 step;
-	s32 timing_offset = 0;
-	u32 trl_nomrate = 0, InternalFreq = 0, temp = 0;
-
-	dprintk("%s:\n", __func__);
-
-	ter_state->frequency = p->frequency;
-	ter_state->force = FE_TER_FORCENONE
-			+ stv0367_readbits(state, F367TER_FORCE) * 2;
-	ter_state->if_iq_mode = state->config->if_iq_mode;
-	switch (state->config->if_iq_mode) {
-	case FE_TER_NORMAL_IF_TUNER:  /* Normal IF mode */
-		dprintk("ALGO: FE_TER_NORMAL_IF_TUNER selected\n");
-		stv0367_writebits(state, F367TER_TUNER_BB, 0);
-		stv0367_writebits(state, F367TER_LONGPATH_IF, 0);
-		stv0367_writebits(state, F367TER_DEMUX_SWAP, 0);
-		break;
-	case FE_TER_LONGPATH_IF_TUNER:  /* Long IF mode */
-		dprintk("ALGO: FE_TER_LONGPATH_IF_TUNER selected\n");
-		stv0367_writebits(state, F367TER_TUNER_BB, 0);
-		stv0367_writebits(state, F367TER_LONGPATH_IF, 1);
-		stv0367_writebits(state, F367TER_DEMUX_SWAP, 1);
-		break;
-	case FE_TER_IQ_TUNER:  /* IQ mode */
-		dprintk("ALGO: FE_TER_IQ_TUNER selected\n");
-		stv0367_writebits(state, F367TER_TUNER_BB, 1);
-		stv0367_writebits(state, F367TER_PPM_INVSEL, 0);
-		break;
-	default:
-		printk(KERN_ERR "ALGO: wrong TUNER type selected\n");
-		return -EINVAL;
-	}
-
-	usleep_range(5000, 7000);
-
-	switch (p->inversion) {
-	case INVERSION_AUTO:
-	default:
-		dprintk("%s: inversion AUTO\n", __func__);
-		if (ter_state->if_iq_mode == FE_TER_IQ_TUNER)
-			stv0367_writebits(state, F367TER_IQ_INVERT,
-						ter_state->sense);
-		else
-			stv0367_writebits(state, F367TER_INV_SPECTR,
-						ter_state->sense);
-
-		break;
-	case INVERSION_ON:
-	case INVERSION_OFF:
-		if (ter_state->if_iq_mode == FE_TER_IQ_TUNER)
-			stv0367_writebits(state, F367TER_IQ_INVERT,
-						p->inversion);
-		else
-			stv0367_writebits(state, F367TER_INV_SPECTR,
-						p->inversion);
-
-		break;
-	}
-
-	if ((ter_state->if_iq_mode != FE_TER_NORMAL_IF_TUNER) &&
-				(ter_state->pBW != ter_state->bw)) {
-		stv0367ter_agc_iir_lock_detect_set(state);
-
-		/*set fine agc target to 180 for LPIF or IQ mode*/
-		/* set Q_AGCTarget */
-		stv0367_writebits(state, F367TER_SEL_IQNTAR, 1);
-		stv0367_writebits(state, F367TER_AUT_AGC_TARGET_MSB, 0xB);
-		/*stv0367_writebits(state,AUT_AGC_TARGET_LSB,0x04); */
-
-		/* set Q_AGCTarget */
-		stv0367_writebits(state, F367TER_SEL_IQNTAR, 0);
-		stv0367_writebits(state, F367TER_AUT_AGC_TARGET_MSB, 0xB);
-		/*stv0367_writebits(state,AUT_AGC_TARGET_LSB,0x04); */
-
-		if (!stv0367_iir_filt_init(state, ter_state->bw,
-						state->config->xtal))
-			return -EINVAL;
-		/*set IIR filter once for 6,7 or 8MHz BW*/
-		ter_state->pBW = ter_state->bw;
-
-		stv0367ter_agc_iir_rst(state);
-	}
-
-	if (ter_state->hierarchy == FE_TER_HIER_LOW_PRIO)
-		stv0367_writebits(state, F367TER_BDI_LPSEL, 0x01);
-	else
-		stv0367_writebits(state, F367TER_BDI_LPSEL, 0x00);
-
-	InternalFreq = stv0367ter_get_mclk(state, state->config->xtal) / 1000;
-	temp = (int)
-		((((ter_state->bw * 64 * (1 << 15) * 100)
-						/ (InternalFreq)) * 10) / 7);
-
-	stv0367_writebits(state, F367TER_TRL_NOMRATE_LSB, temp % 2);
-	temp = temp / 2;
-	stv0367_writebits(state, F367TER_TRL_NOMRATE_HI, temp / 256);
-	stv0367_writebits(state, F367TER_TRL_NOMRATE_LO, temp % 256);
-
-	temp = stv0367_readbits(state, F367TER_TRL_NOMRATE_HI) * 512 +
-			stv0367_readbits(state, F367TER_TRL_NOMRATE_LO) * 2 +
-			stv0367_readbits(state, F367TER_TRL_NOMRATE_LSB);
-	temp = (int)(((1 << 17) * ter_state->bw * 1000) / (7 * (InternalFreq)));
-	stv0367_writebits(state, F367TER_GAIN_SRC_HI, temp / 256);
-	stv0367_writebits(state, F367TER_GAIN_SRC_LO, temp % 256);
-	temp = stv0367_readbits(state, F367TER_GAIN_SRC_HI) * 256 +
-			stv0367_readbits(state, F367TER_GAIN_SRC_LO);
-
-	temp = (int)
-		((InternalFreq - state->config->if_khz) * (1 << 16)
-							/ (InternalFreq));
-
-	dprintk("DEROT temp=0x%x\n", temp);
-	stv0367_writebits(state, F367TER_INC_DEROT_HI, temp / 256);
-	stv0367_writebits(state, F367TER_INC_DEROT_LO, temp % 256);
-
-	ter_state->echo_pos = 0;
-	ter_state->ucblocks = 0; /* liplianin */
-	ter_state->pBER = 0; /* liplianin */
-	stv0367_writebits(state, F367TER_LONG_ECHO, ter_state->echo_pos);
-
-	if (stv0367ter_lock_algo(state) != FE_TER_LOCKOK)
-		return 0;
-
-	ter_state->state = FE_TER_LOCKOK;
-
-	ter_state->mode = stv0367_readbits(state, F367TER_SYR_MODE);
-	ter_state->guard = stv0367_readbits(state, F367TER_SYR_GUARD);
-
-	ter_state->first_lock = 1; /* we know sense now :) */
-
-	ter_state->agc_val =
-			(stv0367_readbits(state, F367TER_AGC1_VAL_LO) << 16) +
-			(stv0367_readbits(state, F367TER_AGC1_VAL_HI) << 24) +
-			stv0367_readbits(state, F367TER_AGC2_VAL_LO) +
-			(stv0367_readbits(state, F367TER_AGC2_VAL_HI) << 8);
-
-	/* Carrier offset calculation */
-	stv0367_writebits(state, F367TER_FREEZE, 1);
-	offset = (stv0367_readbits(state, F367TER_CRL_FOFFSET_VHI) << 16) ;
-	offset += (stv0367_readbits(state, F367TER_CRL_FOFFSET_HI) << 8);
-	offset += (stv0367_readbits(state, F367TER_CRL_FOFFSET_LO));
-	stv0367_writebits(state, F367TER_FREEZE, 0);
-	if (offset > 8388607)
-		offset -= 16777216;
-
-	offset = offset * 2 / 16384;
-
-	if (ter_state->mode == FE_TER_MODE_2K)
-		offset = (offset * 4464) / 1000;/*** 1 FFT BIN=4.464khz***/
-	else if (ter_state->mode == FE_TER_MODE_4K)
-		offset = (offset * 223) / 100;/*** 1 FFT BIN=2.23khz***/
-	else  if (ter_state->mode == FE_TER_MODE_8K)
-		offset = (offset * 111) / 100;/*** 1 FFT BIN=1.1khz***/
-
-	if (stv0367_readbits(state, F367TER_PPM_INVSEL) == 1) {
-		if ((stv0367_readbits(state, F367TER_INV_SPECTR) ==
-				(stv0367_readbits(state,
-					F367TER_STATUS_INV_SPECRUM) == 1)))
-			offset = offset * -1;
-	}
-
-	if (ter_state->bw == 6)
-		offset = (offset * 6) / 8;
-	else if (ter_state->bw == 7)
-		offset = (offset * 7) / 8;
-
-	ter_state->frequency += offset;
-
-	tempo = 10;  /* exit even if timing_offset stays null */
-	while ((timing_offset == 0) && (tempo > 0)) {
-		usleep_range(10000, 20000);	/*was 20ms  */
-		/* fine tuning of timing offset if required */
-		timing_offset = stv0367_readbits(state, F367TER_TRL_TOFFSET_LO)
-				+ 256 * stv0367_readbits(state,
-							F367TER_TRL_TOFFSET_HI);
-		if (timing_offset >= 32768)
-			timing_offset -= 65536;
-		trl_nomrate = (512 * stv0367_readbits(state,
-							F367TER_TRL_NOMRATE_HI)
-			+ stv0367_readbits(state, F367TER_TRL_NOMRATE_LO) * 2
-			+ stv0367_readbits(state, F367TER_TRL_NOMRATE_LSB));
-
-		timing_offset = ((signed)(1000000 / trl_nomrate) *
-							timing_offset) / 2048;
-		tempo--;
-	}
-
-	if (timing_offset <= 0) {
-		timing_offset = (timing_offset - 11) / 22;
-		step = -1;
-	} else {
-		timing_offset = (timing_offset + 11) / 22;
-		step = 1;
-	}
-
-	for (counter = 0; counter < abs(timing_offset); counter++) {
-		trl_nomrate += step;
-		stv0367_writebits(state, F367TER_TRL_NOMRATE_LSB,
-						trl_nomrate % 2);
-		stv0367_writebits(state, F367TER_TRL_NOMRATE_LO,
-						trl_nomrate / 2);
-		usleep_range(1000, 2000);
-	}
-
-	usleep_range(5000, 6000);
-	/* unlocks could happen in case of trl centring big step,
-	then a core off/on restarts demod */
-	u_var = stv0367_readbits(state, F367TER_LK);
-
-	if (!u_var) {
-		stv0367_writebits(state, F367TER_CORE_ACTIVE, 0);
-		msleep(20);
-		stv0367_writebits(state, F367TER_CORE_ACTIVE, 1);
-	}
-
-	return 0;
-}
-
-static int stv0367ter_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct stv0367_state *state = fe->demodulator_priv;
-	struct stv0367ter_state *ter_state = state->ter_state;
-
-	/*u8 trials[2]; */
-	s8 num_trials, index;
-	u8 SenseTrials[] = { INVERSION_ON, INVERSION_OFF };
-
-	stv0367ter_init(fe);
-
-	if (fe->ops.tuner_ops.set_params) {
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	switch (p->transmission_mode) {
-	default:
-	case TRANSMISSION_MODE_AUTO:
-	case TRANSMISSION_MODE_2K:
-		ter_state->mode = FE_TER_MODE_2K;
-		break;
-/*	case TRANSMISSION_MODE_4K:
-		pLook.mode = FE_TER_MODE_4K;
-		break;*/
-	case TRANSMISSION_MODE_8K:
-		ter_state->mode = FE_TER_MODE_8K;
-		break;
-	}
-
-	switch (p->guard_interval) {
-	default:
-	case GUARD_INTERVAL_1_32:
-	case GUARD_INTERVAL_1_16:
-	case GUARD_INTERVAL_1_8:
-	case GUARD_INTERVAL_1_4:
-		ter_state->guard = p->guard_interval;
-		break;
-	case GUARD_INTERVAL_AUTO:
-		ter_state->guard = GUARD_INTERVAL_1_32;
-		break;
-	}
-
-	switch (p->bandwidth_hz) {
-	case 6000000:
-		ter_state->bw = FE_TER_CHAN_BW_6M;
-		break;
-	case 7000000:
-		ter_state->bw = FE_TER_CHAN_BW_7M;
-		break;
-	case 8000000:
-	default:
-		ter_state->bw = FE_TER_CHAN_BW_8M;
-	}
-
-	ter_state->hierarchy = FE_TER_HIER_NONE;
-
-	switch (p->inversion) {
-	case INVERSION_OFF:
-	case INVERSION_ON:
-		num_trials = 1;
-		break;
-	default:
-		num_trials = 2;
-		if (ter_state->first_lock)
-			num_trials = 1;
-		break;
-	}
-
-	ter_state->state = FE_TER_NOLOCK;
-	index = 0;
-
-	while (((index) < num_trials) && (ter_state->state != FE_TER_LOCKOK)) {
-		if (!ter_state->first_lock) {
-			if (p->inversion == INVERSION_AUTO)
-				ter_state->sense = SenseTrials[index];
-
-		}
-		stv0367ter_algo(fe);
-
-		if ((ter_state->state == FE_TER_LOCKOK) &&
-				(p->inversion == INVERSION_AUTO) &&
-								(index == 1)) {
-			/* invert spectrum sense */
-			SenseTrials[index] = SenseTrials[0];
-			SenseTrials[(index + 1) % 2] = (SenseTrials[1] + 1) % 2;
-		}
-
-		index++;
-	}
-
-	return 0;
-}
-
-static int stv0367ter_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct stv0367_state *state = fe->demodulator_priv;
-	struct stv0367ter_state *ter_state = state->ter_state;
-	u32 errs = 0;
-
-	/*wait for counting completion*/
-	if (stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 0) {
-		errs =
-			((u32)stv0367_readbits(state, F367TER_ERR_CNT1)
-			* (1 << 16))
-			+ ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_HI)
-			* (1 << 8))
-			+ ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_LO));
-		ter_state->ucblocks = errs;
-	}
-
-	(*ucblocks) = ter_state->ucblocks;
-
-	return 0;
-}
-
-static int stv0367ter_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct stv0367_state *state = fe->demodulator_priv;
-	struct stv0367ter_state *ter_state = state->ter_state;
-
-	int error = 0;
-	enum stv0367_ter_mode mode;
-	int constell = 0,/* snr = 0,*/ Data = 0;
-
-	p->frequency = stv0367_get_tuner_freq(fe);
-	if ((int)p->frequency < 0)
-		p->frequency = -p->frequency;
-
-	constell = stv0367_readbits(state, F367TER_TPS_CONST);
-	if (constell == 0)
-		p->modulation = QPSK;
-	else if (constell == 1)
-		p->modulation = QAM_16;
-	else
-		p->modulation = QAM_64;
-
-	p->inversion = stv0367_readbits(state, F367TER_INV_SPECTR);
-
-	/* Get the Hierarchical mode */
-	Data = stv0367_readbits(state, F367TER_TPS_HIERMODE);
-
-	switch (Data) {
-	case 0:
-		p->hierarchy = HIERARCHY_NONE;
-		break;
-	case 1:
-		p->hierarchy = HIERARCHY_1;
-		break;
-	case 2:
-		p->hierarchy = HIERARCHY_2;
-		break;
-	case 3:
-		p->hierarchy = HIERARCHY_4;
-		break;
-	default:
-		p->hierarchy = HIERARCHY_AUTO;
-		break; /* error */
-	}
-
-	/* Get the FEC Rate */
-	if (ter_state->hierarchy == FE_TER_HIER_LOW_PRIO)
-		Data = stv0367_readbits(state, F367TER_TPS_LPCODE);
-	else
-		Data = stv0367_readbits(state, F367TER_TPS_HPCODE);
-
-	switch (Data) {
-	case 0:
-		p->code_rate_HP = FEC_1_2;
-		break;
-	case 1:
-		p->code_rate_HP = FEC_2_3;
-		break;
-	case 2:
-		p->code_rate_HP = FEC_3_4;
-		break;
-	case 3:
-		p->code_rate_HP = FEC_5_6;
-		break;
-	case 4:
-		p->code_rate_HP = FEC_7_8;
-		break;
-	default:
-		p->code_rate_HP = FEC_AUTO;
-		break; /* error */
-	}
-
-	mode = stv0367_readbits(state, F367TER_SYR_MODE);
-
-	switch (mode) {
-	case FE_TER_MODE_2K:
-		p->transmission_mode = TRANSMISSION_MODE_2K;
-		break;
-/*	case FE_TER_MODE_4K:
-		p->transmission_mode = TRANSMISSION_MODE_4K;
-		break;*/
-	case FE_TER_MODE_8K:
-		p->transmission_mode = TRANSMISSION_MODE_8K;
-		break;
-	default:
-		p->transmission_mode = TRANSMISSION_MODE_AUTO;
-	}
-
-	p->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD);
-
-	return error;
-}
-
-static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct stv0367_state *state = fe->demodulator_priv;
-	u32 snru32 = 0;
-	int cpt = 0;
-	u8 cut = stv0367_readbits(state, F367TER_IDENTIFICATIONREG);
-
-	while (cpt < 10) {
-		usleep_range(2000, 3000);
-		if (cut == 0x50) /*cut 1.0 cut 1.1*/
-			snru32 += stv0367_readbits(state, F367TER_CHCSNR) / 4;
-		else /*cu2.0*/
-			snru32 += 125 * stv0367_readbits(state, F367TER_CHCSNR);
-
-		cpt++;
-	}
-
-	snru32 /= 10;/*average on 10 values*/
-
-	*snr = snru32 / 1000;
-
-	return 0;
-}
-
-#if 0
-static int stv0367ter_status(struct dvb_frontend *fe)
-{
-
-	struct stv0367_state *state = fe->demodulator_priv;
-	struct stv0367ter_state *ter_state = state->ter_state;
-	int locked = FALSE;
-
-	locked = (stv0367_readbits(state, F367TER_LK));
-	if (!locked)
-		ter_state->unlock_counter += 1;
-	else
-		ter_state->unlock_counter = 0;
-
-	if (ter_state->unlock_counter > 2) {
-		if (!stv0367_readbits(state, F367TER_TPS_LOCK) ||
-				(!stv0367_readbits(state, F367TER_LK))) {
-			stv0367_writebits(state, F367TER_CORE_ACTIVE, 0);
-			usleep_range(2000, 3000);
-			stv0367_writebits(state, F367TER_CORE_ACTIVE, 1);
-			msleep(350);
-			locked = (stv0367_readbits(state, F367TER_TPS_LOCK)) &&
-					(stv0367_readbits(state, F367TER_LK));
-		}
-
-	}
-
-	return locked;
-}
-#endif
-static int stv0367ter_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct stv0367_state *state = fe->demodulator_priv;
-
-	dprintk("%s:\n", __func__);
-
-	*status = 0;
-
-	if (stv0367_readbits(state, F367TER_LK)) {
-		*status |= FE_HAS_LOCK;
-		dprintk("%s: stv0367 has locked\n", __func__);
-	}
-
-	return 0;
-}
-
-static int stv0367ter_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct stv0367_state *state = fe->demodulator_priv;
-	struct stv0367ter_state *ter_state = state->ter_state;
-	u32 Errors = 0, tber = 0, temporary = 0;
-	int abc = 0, def = 0;
-
-
-	/*wait for counting completion*/
-	if (stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 0)
-		Errors = ((u32)stv0367_readbits(state, F367TER_SFEC_ERR_CNT)
-			* (1 << 16))
-			+ ((u32)stv0367_readbits(state, F367TER_SFEC_ERR_CNT_HI)
-			* (1 << 8))
-			+ ((u32)stv0367_readbits(state,
-						F367TER_SFEC_ERR_CNT_LO));
-	/*measurement not completed, load previous value*/
-	else {
-		tber = ter_state->pBER;
-		return 0;
-	}
-
-	abc = stv0367_readbits(state, F367TER_SFEC_ERR_SOURCE);
-	def = stv0367_readbits(state, F367TER_SFEC_NUM_EVENT);
-
-	if (Errors == 0) {
-		tber = 0;
-	} else if (abc == 0x7) {
-		if (Errors <= 4) {
-			temporary = (Errors * 1000000000) / (8 * (1 << 14));
-			temporary =  temporary;
-		} else if (Errors <= 42) {
-			temporary = (Errors * 100000000) / (8 * (1 << 14));
-			temporary = temporary * 10;
-		} else if (Errors <= 429) {
-			temporary = (Errors * 10000000) / (8 * (1 << 14));
-			temporary = temporary * 100;
-		} else if (Errors <= 4294) {
-			temporary = (Errors * 1000000) / (8 * (1 << 14));
-			temporary = temporary * 1000;
-		} else if (Errors <= 42949) {
-			temporary = (Errors * 100000) / (8 * (1 << 14));
-			temporary = temporary * 10000;
-		} else if (Errors <= 429496) {
-			temporary = (Errors * 10000) / (8 * (1 << 14));
-			temporary = temporary * 100000;
-		} else { /*if (Errors<4294967) 2^22 max error*/
-			temporary = (Errors * 1000) / (8 * (1 << 14));
-			temporary = temporary * 100000;	/* still to *10 */
-		}
-
-		/* Byte error*/
-		if (def == 2)
-			/*tber=Errors/(8*(1 <<14));*/
-			tber = temporary;
-		else if (def == 3)
-			/*tber=Errors/(8*(1 <<16));*/
-			tber = temporary / 4;
-		else if (def == 4)
-			/*tber=Errors/(8*(1 <<18));*/
-			tber = temporary / 16;
-		else if (def == 5)
-			/*tber=Errors/(8*(1 <<20));*/
-			tber = temporary / 64;
-		else if (def == 6)
-			/*tber=Errors/(8*(1 <<22));*/
-			tber = temporary / 256;
-		else
-			/* should not pass here*/
-			tber = 0;
-
-		if ((Errors < 4294967) && (Errors > 429496))
-			tber *= 10;
-
-	}
-
-	/* save actual value */
-	ter_state->pBER = tber;
-
-	(*ber) = tber;
-
-	return 0;
-}
-#if 0
-static u32 stv0367ter_get_per(struct stv0367_state *state)
-{
-	struct stv0367ter_state *ter_state = state->ter_state;
-	u32 Errors = 0, Per = 0, temporary = 0;
-	int abc = 0, def = 0, cpt = 0;
-
-	while (((stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 1) &&
-			(cpt < 400)) || ((Errors == 0) && (cpt < 400))) {
-		usleep_range(1000, 2000);
-		Errors = ((u32)stv0367_readbits(state, F367TER_ERR_CNT1)
-			* (1 << 16))
-			+ ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_HI)
-			* (1 << 8))
-			+ ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_LO));
-		cpt++;
-	}
-	abc = stv0367_readbits(state, F367TER_ERR_SRC1);
-	def = stv0367_readbits(state, F367TER_NUM_EVT1);
-
-	if (Errors == 0)
-		Per = 0;
-	else if (abc == 0x9) {
-		if (Errors <= 4) {
-			temporary = (Errors * 1000000000) / (8 * (1 << 8));
-			temporary =  temporary;
-		} else if (Errors <= 42) {
-			temporary = (Errors * 100000000) / (8 * (1 << 8));
-			temporary = temporary * 10;
-		} else if (Errors <= 429) {
-			temporary = (Errors * 10000000) / (8 * (1 << 8));
-			temporary = temporary * 100;
-		} else if (Errors <= 4294) {
-			temporary = (Errors * 1000000) / (8 * (1 << 8));
-			temporary = temporary * 1000;
-		} else if (Errors <= 42949) {
-			temporary = (Errors * 100000) / (8 * (1 << 8));
-			temporary = temporary * 10000;
-		} else { /*if(Errors<=429496)  2^16 errors max*/
-			temporary = (Errors * 10000) / (8 * (1 << 8));
-			temporary = temporary * 100000;
-		}
-
-		/* pkt error*/
-		if (def == 2)
-			/*Per=Errors/(1 << 8);*/
-			Per = temporary;
-		else if (def == 3)
-			/*Per=Errors/(1 << 10);*/
-			Per = temporary / 4;
-		else if (def == 4)
-			/*Per=Errors/(1 << 12);*/
-			Per = temporary / 16;
-		else if (def == 5)
-			/*Per=Errors/(1 << 14);*/
-			Per = temporary / 64;
-		else if (def == 6)
-			/*Per=Errors/(1 << 16);*/
-			Per = temporary / 256;
-		else
-			Per = 0;
-
-	}
-	/* save actual value */
-	ter_state->pPER = Per;
-
-	return Per;
-}
-#endif
-static int stv0367_get_tune_settings(struct dvb_frontend *fe,
-					struct dvb_frontend_tune_settings
-					*fe_tune_settings)
-{
-	fe_tune_settings->min_delay_ms = 1000;
-	fe_tune_settings->step_size = 0;
-	fe_tune_settings->max_drift = 0;
-
-	return 0;
-}
-
-static void stv0367_release(struct dvb_frontend *fe)
-{
-	struct stv0367_state *state = fe->demodulator_priv;
-
-	kfree(state->ter_state);
-	kfree(state->cab_state);
-	kfree(state);
-}
-
-static struct dvb_frontend_ops stv0367ter_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name			= "ST STV0367 DVB-T",
-		.frequency_min		= 47000000,
-		.frequency_max		= 862000000,
-		.frequency_stepsize	= 15625,
-		.frequency_tolerance	= 0,
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
-			FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
-			FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
-			FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER |
-			FE_CAN_INVERSION_AUTO |
-			FE_CAN_MUTE_TS
-	},
-	.release = stv0367_release,
-	.init = stv0367ter_init,
-	.sleep = stv0367ter_sleep,
-	.i2c_gate_ctrl = stv0367ter_gate_ctrl,
-	.set_frontend = stv0367ter_set_frontend,
-	.get_frontend = stv0367ter_get_frontend,
-	.get_tune_settings = stv0367_get_tune_settings,
-	.read_status = stv0367ter_read_status,
-	.read_ber = stv0367ter_read_ber,/* too slow */
-/*	.read_signal_strength = stv0367_read_signal_strength,*/
-	.read_snr = stv0367ter_read_snr,
-	.read_ucblocks = stv0367ter_read_ucblocks,
-};
-
-struct dvb_frontend *stv0367ter_attach(const struct stv0367_config *config,
-				   struct i2c_adapter *i2c)
-{
-	struct stv0367_state *state = NULL;
-	struct stv0367ter_state *ter_state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct stv0367_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-	ter_state = kzalloc(sizeof(struct stv0367ter_state), GFP_KERNEL);
-	if (ter_state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->i2c = i2c;
-	state->config = config;
-	state->ter_state = ter_state;
-	state->fe.ops = stv0367ter_ops;
-	state->fe.demodulator_priv = state;
-	state->chip_id = stv0367_readreg(state, 0xf000);
-
-	dprintk("%s: chip_id = 0x%x\n", __func__, state->chip_id);
-
-	/* check if the demod is there */
-	if ((state->chip_id != 0x50) && (state->chip_id != 0x60))
-		goto error;
-
-	return &state->fe;
-
-error:
-	kfree(ter_state);
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(stv0367ter_attach);
-
-static int stv0367cab_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct stv0367_state *state = fe->demodulator_priv;
-
-	dprintk("%s:\n", __func__);
-
-	stv0367_writebits(state, F367CAB_I2CT_ON, (enable > 0) ? 1 : 0);
-
-	return 0;
-}
-
-static u32 stv0367cab_get_mclk(struct dvb_frontend *fe, u32 ExtClk_Hz)
-{
-	struct stv0367_state *state = fe->demodulator_priv;
-	u32 mclk_Hz = 0;/* master clock frequency (Hz) */
-	u32 M, N, P;
-
-
-	if (stv0367_readbits(state, F367CAB_BYPASS_PLLXN) == 0) {
-		N = (u32)stv0367_readbits(state, F367CAB_PLL_NDIV);
-		if (N == 0)
-			N = N + 1;
-
-		M = (u32)stv0367_readbits(state, F367CAB_PLL_MDIV);
-		if (M == 0)
-			M = M + 1;
-
-		P = (u32)stv0367_readbits(state, F367CAB_PLL_PDIV);
-
-		if (P > 5)
-			P = 5;
-
-		mclk_Hz = ((ExtClk_Hz / 2) * N) / (M * (1 << P));
-		dprintk("stv0367cab_get_mclk BYPASS_PLLXN mclk_Hz=%d\n",
-								mclk_Hz);
-	} else
-		mclk_Hz = ExtClk_Hz;
-
-	dprintk("stv0367cab_get_mclk final mclk_Hz=%d\n", mclk_Hz);
-
-	return mclk_Hz;
-}
-
-static u32 stv0367cab_get_adc_freq(struct dvb_frontend *fe, u32 ExtClk_Hz)
-{
-	u32 ADCClk_Hz = ExtClk_Hz;
-
-	ADCClk_Hz = stv0367cab_get_mclk(fe, ExtClk_Hz);
-
-	return ADCClk_Hz;
-}
-
-enum stv0367cab_mod stv0367cab_SetQamSize(struct stv0367_state *state,
-					u32 SymbolRate,
-					enum stv0367cab_mod QAMSize)
-{
-	/* Set QAM size */
-	stv0367_writebits(state, F367CAB_QAM_MODE, QAMSize);
-
-	/* Set Registers settings specific to the QAM size */
-	switch (QAMSize) {
-	case FE_CAB_MOD_QAM4:
-		stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
-		break;
-	case FE_CAB_MOD_QAM16:
-		stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x64);
-		stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
-		stv0367_writereg(state, R367CAB_FSM_STATE, 0x90);
-		stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
-		stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7);
-		stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x95);
-		stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40);
-		stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0x8a);
-		break;
-	case FE_CAB_MOD_QAM32:
-		stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
-		stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x6e);
-		stv0367_writereg(state, R367CAB_FSM_STATE, 0xb0);
-		stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
-		stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xb7);
-		stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x9d);
-		stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x7f);
-		stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7);
-		break;
-	case FE_CAB_MOD_QAM64:
-		stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x82);
-		stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x5a);
-		if (SymbolRate > 45000000) {
-			stv0367_writereg(state, R367CAB_FSM_STATE, 0xb0);
-			stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
-			stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa5);
-		} else if (SymbolRate > 25000000) {
-			stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0);
-			stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
-			stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa6);
-		} else {
-			stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0);
-			stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xd1);
-			stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7);
-		}
-		stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x95);
-		stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40);
-		stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0x99);
-		break;
-	case FE_CAB_MOD_QAM128:
-		stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
-		stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x76);
-		stv0367_writereg(state, R367CAB_FSM_STATE, 0x90);
-		stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xb1);
-		if (SymbolRate > 45000000)
-			stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7);
-		else if (SymbolRate > 25000000)
-			stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa6);
-		else
-			stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0x97);
-
-		stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x8e);
-		stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x7f);
-		stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7);
-		break;
-	case FE_CAB_MOD_QAM256:
-		stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x94);
-		stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x5a);
-		stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0);
-		if (SymbolRate > 45000000)
-			stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
-		else if (SymbolRate > 25000000)
-			stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
-		else
-			stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xd1);
-
-		stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7);
-		stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x85);
-		stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40);
-		stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7);
-		break;
-	case FE_CAB_MOD_QAM512:
-		stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
-		break;
-	case FE_CAB_MOD_QAM1024:
-		stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
-		break;
-	default:
-		break;
-	}
-
-	return QAMSize;
-}
-
-static u32 stv0367cab_set_derot_freq(struct stv0367_state *state,
-					u32 adc_hz, s32 derot_hz)
-{
-	u32 sampled_if = 0;
-	u32 adc_khz;
-
-	adc_khz = adc_hz / 1000;
-
-	dprintk("%s: adc_hz=%d derot_hz=%d\n", __func__, adc_hz, derot_hz);
-
-	if (adc_khz != 0) {
-		if (derot_hz < 1000000)
-			derot_hz = adc_hz / 4; /* ZIF operation */
-		if (derot_hz > adc_hz)
-			derot_hz = derot_hz - adc_hz;
-		sampled_if = (u32)derot_hz / 1000;
-		sampled_if *= 32768;
-		sampled_if /= adc_khz;
-		sampled_if *= 256;
-	}
-
-	if (sampled_if > 8388607)
-		sampled_if = 8388607;
-
-	dprintk("%s: sampled_if=0x%x\n", __func__, sampled_if);
-
-	stv0367_writereg(state, R367CAB_MIX_NCO_LL, sampled_if);
-	stv0367_writereg(state, R367CAB_MIX_NCO_HL, (sampled_if >> 8));
-	stv0367_writebits(state, F367CAB_MIX_NCO_INC_HH, (sampled_if >> 16));
-
-	return derot_hz;
-}
-
-static u32 stv0367cab_get_derot_freq(struct stv0367_state *state, u32 adc_hz)
-{
-	u32 sampled_if;
-
-	sampled_if = stv0367_readbits(state, F367CAB_MIX_NCO_INC_LL) +
-			(stv0367_readbits(state, F367CAB_MIX_NCO_INC_HL) << 8) +
-			(stv0367_readbits(state, F367CAB_MIX_NCO_INC_HH) << 16);
-
-	sampled_if /= 256;
-	sampled_if *= (adc_hz / 1000);
-	sampled_if += 1;
-	sampled_if /= 32768;
-
-	return sampled_if;
-}
-
-static u32 stv0367cab_set_srate(struct stv0367_state *state, u32 adc_hz,
-			u32 mclk_hz, u32 SymbolRate,
-			enum stv0367cab_mod QAMSize)
-{
-	u32 QamSizeCorr = 0;
-	u32 u32_tmp = 0, u32_tmp1 = 0;
-	u32 adp_khz;
-
-	dprintk("%s:\n", __func__);
-
-	/* Set Correction factor of SRC gain */
-	switch (QAMSize) {
-	case FE_CAB_MOD_QAM4:
-		QamSizeCorr = 1110;
-		break;
-	case FE_CAB_MOD_QAM16:
-		QamSizeCorr = 1032;
-		break;
-	case FE_CAB_MOD_QAM32:
-		QamSizeCorr =  954;
-		break;
-	case FE_CAB_MOD_QAM64:
-		QamSizeCorr =  983;
-		break;
-	case FE_CAB_MOD_QAM128:
-		QamSizeCorr =  957;
-		break;
-	case FE_CAB_MOD_QAM256:
-		QamSizeCorr =  948;
-		break;
-	case FE_CAB_MOD_QAM512:
-		QamSizeCorr =    0;
-		break;
-	case FE_CAB_MOD_QAM1024:
-		QamSizeCorr =  944;
-		break;
-	default:
-		break;
-	}
-
-	/* Transfer ratio calculation */
-	if (adc_hz != 0) {
-		u32_tmp = 256 * SymbolRate;
-		u32_tmp = u32_tmp / adc_hz;
-	}
-	stv0367_writereg(state, R367CAB_EQU_CRL_TFR, (u8)u32_tmp);
-
-	/* Symbol rate and SRC gain calculation */
-	adp_khz = (mclk_hz >> 1) / 1000;/* TRL works at half the system clock */
-	if (adp_khz != 0) {
-		u32_tmp = SymbolRate;
-		u32_tmp1 = SymbolRate;
-
-		if (u32_tmp < 2097152) { /* 2097152 = 2^21 */
-			/* Symbol rate calculation */
-			u32_tmp *= 2048; /* 2048 = 2^11 */
-			u32_tmp = u32_tmp / adp_khz;
-			u32_tmp = u32_tmp * 16384; /* 16384 = 2^14 */
-			u32_tmp /= 125 ; /* 125 = 1000/2^3 */
-			u32_tmp = u32_tmp * 8; /* 8 = 2^3 */
-
-			/* SRC Gain Calculation */
-			u32_tmp1 *= 2048; /* *2*2^10 */
-			u32_tmp1 /= 439; /* *2/878 */
-			u32_tmp1 *= 256; /* *2^8 */
-			u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */
-			u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */
-			u32_tmp1 = u32_tmp1 / 10000000;
-
-		} else if (u32_tmp < 4194304) { /* 4194304 = 2**22 */
-			/* Symbol rate calculation */
-			u32_tmp *= 1024 ; /* 1024 = 2**10 */
-			u32_tmp = u32_tmp / adp_khz;
-			u32_tmp = u32_tmp * 16384; /* 16384 = 2**14 */
-			u32_tmp /= 125 ; /* 125 = 1000/2**3 */
-			u32_tmp = u32_tmp * 16; /* 16 = 2**4 */
-
-			/* SRC Gain Calculation */
-			u32_tmp1 *= 1024; /* *2*2^9 */
-			u32_tmp1 /= 439; /* *2/878 */
-			u32_tmp1 *= 256; /* *2^8 */
-			u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz)*/
-			u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */
-			u32_tmp1 = u32_tmp1 / 5000000;
-		} else if (u32_tmp < 8388607) { /* 8388607 = 2**23 */
-			/* Symbol rate calculation */
-			u32_tmp *= 512 ; /* 512 = 2**9 */
-			u32_tmp = u32_tmp / adp_khz;
-			u32_tmp = u32_tmp * 16384; /* 16384 = 2**14 */
-			u32_tmp /= 125 ; /* 125 = 1000/2**3 */
-			u32_tmp = u32_tmp * 32; /* 32 = 2**5 */
-
-			/* SRC Gain Calculation */
-			u32_tmp1 *= 512; /* *2*2^8 */
-			u32_tmp1 /= 439; /* *2/878 */
-			u32_tmp1 *= 256; /* *2^8 */
-			u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */
-			u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */
-			u32_tmp1 = u32_tmp1 / 2500000;
-		} else {
-			/* Symbol rate calculation */
-			u32_tmp *= 256 ; /* 256 = 2**8 */
-			u32_tmp = u32_tmp / adp_khz;
-			u32_tmp = u32_tmp * 16384; /* 16384 = 2**13 */
-			u32_tmp /= 125 ; /* 125 = 1000/2**3 */
-			u32_tmp = u32_tmp * 64; /* 64 = 2**6 */
-
-			/* SRC Gain Calculation */
-			u32_tmp1 *= 256; /* 2*2^7 */
-			u32_tmp1 /= 439; /* *2/878 */
-			u32_tmp1 *= 256; /* *2^8 */
-			u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */
-			u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */
-			u32_tmp1 = u32_tmp1 / 1250000;
-		}
-	}
-#if 0
-	/* Filters' coefficients are calculated and written
-	into registers only if the filters are enabled */
-	if (stv0367_readbits(state, F367CAB_ADJ_EN)) {
-		stv0367cab_SetIirAdjacentcoefficient(state, mclk_hz,
-								SymbolRate);
-		/* AllPass filter must be enabled
-		when the adjacents filter is used */
-		stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 1);
-		stv0367cab_SetAllPasscoefficient(state, mclk_hz, SymbolRate);
-	} else
-		/* AllPass filter must be disabled
-		when the adjacents filter is not used */
-#endif
-	stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 0);
-
-	stv0367_writereg(state, R367CAB_SRC_NCO_LL, u32_tmp);
-	stv0367_writereg(state, R367CAB_SRC_NCO_LH, (u32_tmp >> 8));
-	stv0367_writereg(state, R367CAB_SRC_NCO_HL, (u32_tmp >> 16));
-	stv0367_writereg(state, R367CAB_SRC_NCO_HH, (u32_tmp >> 24));
-
-	stv0367_writereg(state, R367CAB_IQDEM_GAIN_SRC_L, u32_tmp1 & 0x00ff);
-	stv0367_writebits(state, F367CAB_GAIN_SRC_HI, (u32_tmp1 >> 8) & 0x00ff);
-
-	return SymbolRate ;
-}
-
-static u32 stv0367cab_GetSymbolRate(struct stv0367_state *state, u32 mclk_hz)
-{
-	u32 regsym;
-	u32 adp_khz;
-
-	regsym = stv0367_readreg(state, R367CAB_SRC_NCO_LL) +
-		(stv0367_readreg(state, R367CAB_SRC_NCO_LH) << 8) +
-		(stv0367_readreg(state, R367CAB_SRC_NCO_HL) << 16) +
-		(stv0367_readreg(state, R367CAB_SRC_NCO_HH) << 24);
-
-	adp_khz = (mclk_hz >> 1) / 1000;/* TRL works at half the system clock */
-
-	if (regsym < 134217728) {		/* 134217728L = 2**27*/
-		regsym = regsym * 32;		/* 32 = 2**5 */
-		regsym = regsym / 32768;	/* 32768L = 2**15 */
-		regsym = adp_khz * regsym;	/* AdpClk in kHz */
-		regsym = regsym / 128;		/* 128 = 2**7 */
-		regsym *= 125 ;			/* 125 = 1000/2**3 */
-		regsym /= 2048 ;		/* 2048 = 2**11	*/
-	} else if (regsym < 268435456) {	/* 268435456L = 2**28 */
-		regsym = regsym * 16;		/* 16 = 2**4 */
-		regsym = regsym / 32768;	/* 32768L = 2**15 */
-		regsym = adp_khz * regsym;	/* AdpClk in kHz */
-		regsym = regsym / 128;		/* 128 = 2**7 */
-		regsym *= 125 ;			/* 125 = 1000/2**3*/
-		regsym /= 1024 ;		/* 256 = 2**10*/
-	} else if (regsym < 536870912) {	/* 536870912L = 2**29*/
-		regsym = regsym * 8;		/* 8 = 2**3 */
-		regsym = regsym / 32768;	/* 32768L = 2**15 */
-		regsym = adp_khz * regsym;	/* AdpClk in kHz */
-		regsym = regsym / 128;		/* 128 = 2**7 */
-		regsym *= 125 ;			/* 125 = 1000/2**3 */
-		regsym /= 512 ;			/* 128 = 2**9 */
-	} else {
-		regsym = regsym * 4;		/* 4 = 2**2 */
-		regsym = regsym / 32768;	/* 32768L = 2**15 */
-		regsym = adp_khz * regsym;	/* AdpClk in kHz */
-		regsym = regsym / 128;		/* 128 = 2**7 */
-		regsym *= 125 ;			/* 125 = 1000/2**3 */
-		regsym /= 256 ;			/* 64 = 2**8 */
-	}
-
-	return regsym;
-}
-
-static int stv0367cab_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct stv0367_state *state = fe->demodulator_priv;
-
-	dprintk("%s:\n", __func__);
-
-	*status = 0;
-
-	if (stv0367_readbits(state, F367CAB_QAMFEC_LOCK)) {
-		*status |= FE_HAS_LOCK;
-		dprintk("%s: stv0367 has locked\n", __func__);
-	}
-
-	return 0;
-}
-
-static int stv0367cab_standby(struct dvb_frontend *fe, u8 standby_on)
-{
-	struct stv0367_state *state = fe->demodulator_priv;
-
-	dprintk("%s:\n", __func__);
-
-	if (standby_on) {
-		stv0367_writebits(state, F367CAB_BYPASS_PLLXN, 0x03);
-		stv0367_writebits(state, F367CAB_STDBY_PLLXN, 0x01);
-		stv0367_writebits(state, F367CAB_STDBY, 1);
-		stv0367_writebits(state, F367CAB_STDBY_CORE, 1);
-		stv0367_writebits(state, F367CAB_EN_BUFFER_I, 0);
-		stv0367_writebits(state, F367CAB_EN_BUFFER_Q, 0);
-		stv0367_writebits(state, F367CAB_POFFQ, 1);
-		stv0367_writebits(state, F367CAB_POFFI, 1);
-	} else {
-		stv0367_writebits(state, F367CAB_STDBY_PLLXN, 0x00);
-		stv0367_writebits(state, F367CAB_BYPASS_PLLXN, 0x00);
-		stv0367_writebits(state, F367CAB_STDBY, 0);
-		stv0367_writebits(state, F367CAB_STDBY_CORE, 0);
-		stv0367_writebits(state, F367CAB_EN_BUFFER_I, 1);
-		stv0367_writebits(state, F367CAB_EN_BUFFER_Q, 1);
-		stv0367_writebits(state, F367CAB_POFFQ, 0);
-		stv0367_writebits(state, F367CAB_POFFI, 0);
-	}
-
-	return 0;
-}
-
-static int stv0367cab_sleep(struct dvb_frontend *fe)
-{
-	return stv0367cab_standby(fe, 1);
-}
-
-int stv0367cab_init(struct dvb_frontend *fe)
-{
-	struct stv0367_state *state = fe->demodulator_priv;
-	struct stv0367cab_state *cab_state = state->cab_state;
-	int i;
-
-	dprintk("%s:\n", __func__);
-
-	for (i = 0; i < STV0367CAB_NBREGS; i++)
-		stv0367_writereg(state, def0367cab[i].addr,
-						def0367cab[i].value);
-
-	switch (state->config->ts_mode) {
-	case STV0367_DVBCI_CLOCK:
-		dprintk("Setting TSMode = STV0367_DVBCI_CLOCK\n");
-		stv0367_writebits(state, F367CAB_OUTFORMAT, 0x03);
-		break;
-	case STV0367_SERIAL_PUNCT_CLOCK:
-	case STV0367_SERIAL_CONT_CLOCK:
-		stv0367_writebits(state, F367CAB_OUTFORMAT, 0x01);
-		break;
-	case STV0367_PARALLEL_PUNCT_CLOCK:
-	case STV0367_OUTPUTMODE_DEFAULT:
-		stv0367_writebits(state, F367CAB_OUTFORMAT, 0x00);
-		break;
-	}
-
-	switch (state->config->clk_pol) {
-	case STV0367_RISINGEDGE_CLOCK:
-		stv0367_writebits(state, F367CAB_CLK_POLARITY, 0x00);
-		break;
-	case STV0367_FALLINGEDGE_CLOCK:
-	case STV0367_CLOCKPOLARITY_DEFAULT:
-		stv0367_writebits(state, F367CAB_CLK_POLARITY, 0x01);
-		break;
-	}
-
-	stv0367_writebits(state, F367CAB_SYNC_STRIP, 0x00);
-
-	stv0367_writebits(state, F367CAB_CT_NBST, 0x01);
-
-	stv0367_writebits(state, F367CAB_TS_SWAP, 0x01);
-
-	stv0367_writebits(state, F367CAB_FIFO_BYPASS, 0x00);
-
-	stv0367_writereg(state, R367CAB_ANACTRL, 0x00);/*PLL enabled and used */
-
-	cab_state->mclk = stv0367cab_get_mclk(fe, state->config->xtal);
-	cab_state->adc_clk = stv0367cab_get_adc_freq(fe, state->config->xtal);
-
-	return 0;
-}
-static
-enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
-					     struct dtv_frontend_properties *p)
-{
-	struct stv0367cab_state *cab_state = state->cab_state;
-	enum stv0367_cab_signal_type signalType = FE_CAB_NOAGC;
-	u32	QAMFEC_Lock, QAM_Lock, u32_tmp,
-		LockTime, TRLTimeOut, AGCTimeOut, CRLSymbols,
-		CRLTimeOut, EQLTimeOut, DemodTimeOut, FECTimeOut;
-	u8	TrackAGCAccum;
-	s32	tmp;
-
-	dprintk("%s:\n", __func__);
-
-	/* Timeouts calculation */
-	/* A max lock time of 25 ms is allowed for delayed AGC */
-	AGCTimeOut = 25;
-	/* 100000 symbols needed by the TRL as a maximum value */
-	TRLTimeOut = 100000000 / p->symbol_rate;
-	/* CRLSymbols is the needed number of symbols to achieve a lock
-	   within [-4%, +4%] of the symbol rate.
-	   CRL timeout is calculated
-	   for a lock within [-search_range, +search_range].
-	   EQL timeout can be changed depending on
-	   the micro-reflections we want to handle.
-	   A characterization must be performed
-	   with these echoes to get new timeout values.
-	*/
-	switch (p->modulation) {
-	case QAM_16:
-		CRLSymbols = 150000;
-		EQLTimeOut = 100;
-		break;
-	case QAM_32:
-		CRLSymbols = 250000;
-		EQLTimeOut = 100;
-		break;
-	case QAM_64:
-		CRLSymbols = 200000;
-		EQLTimeOut = 100;
-		break;
-	case QAM_128:
-		CRLSymbols = 250000;
-		EQLTimeOut = 100;
-		break;
-	case QAM_256:
-		CRLSymbols = 250000;
-		EQLTimeOut = 100;
-		break;
-	default:
-		CRLSymbols = 200000;
-		EQLTimeOut = 100;
-		break;
-	}
-#if 0
-	if (pIntParams->search_range < 0) {
-		CRLTimeOut = (25 * CRLSymbols *
-				(-pIntParams->search_range / 1000)) /
-					(pIntParams->symbol_rate / 1000);
-	} else
-#endif
-	CRLTimeOut = (25 * CRLSymbols * (cab_state->search_range / 1000)) /
-					(p->symbol_rate / 1000);
-
-	CRLTimeOut = (1000 * CRLTimeOut) / p->symbol_rate;
-	/* Timeouts below 50ms are coerced */
-	if (CRLTimeOut < 50)
-		CRLTimeOut = 50;
-	/* A maximum of 100 TS packets is needed to get FEC lock even in case
-	the spectrum inversion needs to be changed.
-	   This is equal to 20 ms in case of the lowest symbol rate of 0.87Msps
-	*/
-	FECTimeOut = 20;
-	DemodTimeOut = AGCTimeOut + TRLTimeOut + CRLTimeOut + EQLTimeOut;
-
-	dprintk("%s: DemodTimeOut=%d\n", __func__, DemodTimeOut);
-
-	/* Reset the TRL to ensure nothing starts until the
-	   AGC is stable which ensures a better lock time
-	*/
-	stv0367_writereg(state, R367CAB_CTRL_1, 0x04);
-	/* Set AGC accumulation time to minimum and lock threshold to maximum
-	in order to speed up the AGC lock */
-	TrackAGCAccum = stv0367_readbits(state, F367CAB_AGC_ACCUMRSTSEL);
-	stv0367_writebits(state, F367CAB_AGC_ACCUMRSTSEL, 0x0);
-	/* Modulus Mapper is disabled */
-	stv0367_writebits(state, F367CAB_MODULUSMAP_EN, 0);
-	/* Disable the sweep function */
-	stv0367_writebits(state, F367CAB_SWEEP_EN, 0);
-	/* The sweep function is never used, Sweep rate must be set to 0 */
-	/* Set the derotator frequency in Hz */
-	stv0367cab_set_derot_freq(state, cab_state->adc_clk,
-		(1000 * (s32)state->config->if_khz + cab_state->derot_offset));
-	/* Disable the Allpass Filter when the symbol rate is out of range */
-	if ((p->symbol_rate > 10800000) | (p->symbol_rate < 1800000)) {
-		stv0367_writebits(state, F367CAB_ADJ_EN, 0);
-		stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 0);
-	}
-#if 0
-	/* Check if the tuner is locked */
-	tuner_lock = stv0367cab_tuner_get_status(fe);
-	if (tuner_lock == 0)
-		return FE_367CAB_NOTUNER;
-#endif
-	/* Relase the TRL to start demodulator acquisition */
-	/* Wait for QAM lock */
-	LockTime = 0;
-	stv0367_writereg(state, R367CAB_CTRL_1, 0x00);
-	do {
-		QAM_Lock = stv0367_readbits(state, F367CAB_FSM_STATUS);
-		if ((LockTime >= (DemodTimeOut - EQLTimeOut)) &&
-							(QAM_Lock == 0x04))
-			/*
-			 * We don't wait longer, the frequency/phase offset
-			 * must be too big
-			 */
-			LockTime = DemodTimeOut;
-		else if ((LockTime >= (AGCTimeOut + TRLTimeOut)) &&
-							(QAM_Lock == 0x02))
-			/*
-			 * We don't wait longer, either there is no signal or
-			 * it is not the right symbol rate or it is an analog
-			 * carrier
-			 */
-		{
-			LockTime = DemodTimeOut;
-			u32_tmp = stv0367_readbits(state,
-						F367CAB_AGC_PWR_WORD_LO) +
-					(stv0367_readbits(state,
-						F367CAB_AGC_PWR_WORD_ME) << 8) +
-					(stv0367_readbits(state,
-						F367CAB_AGC_PWR_WORD_HI) << 16);
-			if (u32_tmp >= 131072)
-				u32_tmp = 262144 - u32_tmp;
-			u32_tmp = u32_tmp / (1 << (11 - stv0367_readbits(state,
-							F367CAB_AGC_IF_BWSEL)));
-
-			if (u32_tmp < stv0367_readbits(state,
-						F367CAB_AGC_PWRREF_LO) +
-					256 * stv0367_readbits(state,
-						F367CAB_AGC_PWRREF_HI) - 10)
-				QAM_Lock = 0x0f;
-		} else {
-			usleep_range(10000, 20000);
-			LockTime += 10;
-		}
-		dprintk("QAM_Lock=0x%x LockTime=%d\n", QAM_Lock, LockTime);
-		tmp = stv0367_readreg(state, R367CAB_IT_STATUS1);
-
-		dprintk("R367CAB_IT_STATUS1=0x%x\n", tmp);
-
-	} while (((QAM_Lock != 0x0c) && (QAM_Lock != 0x0b)) &&
-						(LockTime < DemodTimeOut));
-
-	dprintk("QAM_Lock=0x%x\n", QAM_Lock);
-
-	tmp = stv0367_readreg(state, R367CAB_IT_STATUS1);
-	dprintk("R367CAB_IT_STATUS1=0x%x\n", tmp);
-	tmp = stv0367_readreg(state, R367CAB_IT_STATUS2);
-	dprintk("R367CAB_IT_STATUS2=0x%x\n", tmp);
-
-	tmp  = stv0367cab_get_derot_freq(state, cab_state->adc_clk);
-	dprintk("stv0367cab_get_derot_freq=0x%x\n", tmp);
-
-	if ((QAM_Lock == 0x0c) || (QAM_Lock == 0x0b)) {
-		/* Wait for FEC lock */
-		LockTime = 0;
-		do {
-			usleep_range(5000, 7000);
-			LockTime += 5;
-			QAMFEC_Lock = stv0367_readbits(state,
-							F367CAB_QAMFEC_LOCK);
-		} while (!QAMFEC_Lock && (LockTime < FECTimeOut));
-	} else
-		QAMFEC_Lock = 0;
-
-	if (QAMFEC_Lock) {
-		signalType = FE_CAB_DATAOK;
-		cab_state->modulation = p->modulation;
-		cab_state->spect_inv = stv0367_readbits(state,
-							F367CAB_QUAD_INV);
-#if 0
-/* not clear for me */
-		if (state->config->if_khz != 0) {
-			if (state->config->if_khz > cab_state->adc_clk / 1000) {
-				cab_state->freq_khz =
-					FE_Cab_TunerGetFrequency(pIntParams->hTuner)
-				- stv0367cab_get_derot_freq(state, cab_state->adc_clk)
-				- cab_state->adc_clk / 1000 + state->config->if_khz;
-			} else {
-				cab_state->freq_khz =
-						FE_Cab_TunerGetFrequency(pIntParams->hTuner)
-						- stv0367cab_get_derot_freq(state, cab_state->adc_clk)
-										+ state->config->if_khz;
-			}
-		} else {
-			cab_state->freq_khz =
-				FE_Cab_TunerGetFrequency(pIntParams->hTuner) +
-				stv0367cab_get_derot_freq(state,
-							cab_state->adc_clk) -
-				cab_state->adc_clk / 4000;
-		}
-#endif
-		cab_state->symbol_rate = stv0367cab_GetSymbolRate(state,
-							cab_state->mclk);
-		cab_state->locked = 1;
-
-		/* stv0367_setbits(state, F367CAB_AGC_ACCUMRSTSEL,7);*/
-	} else {
-		switch (QAM_Lock) {
-		case 1:
-			signalType = FE_CAB_NOAGC;
-			break;
-		case 2:
-			signalType = FE_CAB_NOTIMING;
-			break;
-		case 3:
-			signalType = FE_CAB_TIMINGOK;
-			break;
-		case 4:
-			signalType = FE_CAB_NOCARRIER;
-			break;
-		case 5:
-			signalType = FE_CAB_CARRIEROK;
-			break;
-		case 7:
-			signalType = FE_CAB_NOBLIND;
-			break;
-		case 8:
-			signalType = FE_CAB_BLINDOK;
-			break;
-		case 10:
-			signalType = FE_CAB_NODEMOD;
-			break;
-		case 11:
-			signalType = FE_CAB_DEMODOK;
-			break;
-		case 12:
-			signalType = FE_CAB_DEMODOK;
-			break;
-		case 13:
-			signalType = FE_CAB_NODEMOD;
-			break;
-		case 14:
-			signalType = FE_CAB_NOBLIND;
-			break;
-		case 15:
-			signalType = FE_CAB_NOSIGNAL;
-			break;
-		default:
-			break;
-		}
-
-	}
-
-	/* Set the AGC control values to tracking values */
-	stv0367_writebits(state, F367CAB_AGC_ACCUMRSTSEL, TrackAGCAccum);
-	return signalType;
-}
-
-static int stv0367cab_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct stv0367_state *state = fe->demodulator_priv;
-	struct stv0367cab_state *cab_state = state->cab_state;
-	enum stv0367cab_mod QAMSize = 0;
-
-	dprintk("%s: freq = %d, srate = %d\n", __func__,
-					p->frequency, p->symbol_rate);
-
-	cab_state->derot_offset = 0;
-
-	switch (p->modulation) {
-	case QAM_16:
-		QAMSize = FE_CAB_MOD_QAM16;
-		break;
-	case QAM_32:
-		QAMSize = FE_CAB_MOD_QAM32;
-		break;
-	case QAM_64:
-		QAMSize = FE_CAB_MOD_QAM64;
-		break;
-	case QAM_128:
-		QAMSize = FE_CAB_MOD_QAM128;
-		break;
-	case QAM_256:
-		QAMSize = FE_CAB_MOD_QAM256;
-		break;
-	default:
-		break;
-	}
-
-	stv0367cab_init(fe);
-
-	/* Tuner Frequency Setting */
-	if (fe->ops.tuner_ops.set_params) {
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	stv0367cab_SetQamSize(
-			state,
-			p->symbol_rate,
-			QAMSize);
-
-	stv0367cab_set_srate(state,
-			cab_state->adc_clk,
-			cab_state->mclk,
-			p->symbol_rate,
-			QAMSize);
-	/* Search algorithm launch, [-1.1*RangeOffset, +1.1*RangeOffset] scan */
-	cab_state->state = stv0367cab_algo(state, p);
-	return 0;
-}
-
-static int stv0367cab_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct stv0367_state *state = fe->demodulator_priv;
-	struct stv0367cab_state *cab_state = state->cab_state;
-
-	enum stv0367cab_mod QAMSize;
-
-	dprintk("%s:\n", __func__);
-
-	p->symbol_rate = stv0367cab_GetSymbolRate(state, cab_state->mclk);
-
-	QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE);
-	switch (QAMSize) {
-	case FE_CAB_MOD_QAM16:
-		p->modulation = QAM_16;
-		break;
-	case FE_CAB_MOD_QAM32:
-		p->modulation = QAM_32;
-		break;
-	case FE_CAB_MOD_QAM64:
-		p->modulation = QAM_64;
-		break;
-	case FE_CAB_MOD_QAM128:
-		p->modulation = QAM_128;
-		break;
-	case QAM_256:
-		p->modulation = QAM_256;
-		break;
-	default:
-		break;
-	}
-
-	p->frequency = stv0367_get_tuner_freq(fe);
-
-	dprintk("%s: tuner frequency = %d\n", __func__, p->frequency);
-
-	if (state->config->if_khz == 0) {
-		p->frequency +=
-			(stv0367cab_get_derot_freq(state, cab_state->adc_clk) -
-			cab_state->adc_clk / 4000);
-		return 0;
-	}
-
-	if (state->config->if_khz > cab_state->adc_clk / 1000)
-		p->frequency += (state->config->if_khz
-			- stv0367cab_get_derot_freq(state, cab_state->adc_clk)
-			- cab_state->adc_clk / 1000);
-	else
-		p->frequency += (state->config->if_khz
-			- stv0367cab_get_derot_freq(state, cab_state->adc_clk));
-
-	return 0;
-}
-
-#if 0
-void stv0367cab_GetErrorCount(state, enum stv0367cab_mod QAMSize,
-			u32 symbol_rate, FE_367qam_Monitor *Monitor_results)
-{
-	stv0367cab_OptimiseNByteAndGetBER(state, QAMSize, symbol_rate, Monitor_results);
-	stv0367cab_GetPacketsCount(state, Monitor_results);
-
-	return;
-}
-
-static int stv0367cab_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct stv0367_state *state = fe->demodulator_priv;
-
-	return 0;
-}
-#endif
-static s32 stv0367cab_get_rf_lvl(struct stv0367_state *state)
-{
-	s32 rfLevel = 0;
-	s32 RfAgcPwm = 0, IfAgcPwm = 0;
-	u8 i;
-
-	stv0367_writebits(state, F367CAB_STDBY_ADCGP, 0x0);
-
-	RfAgcPwm =
-		(stv0367_readbits(state, F367CAB_RF_AGC1_LEVEL_LO) & 0x03) +
-		(stv0367_readbits(state, F367CAB_RF_AGC1_LEVEL_HI) << 2);
-	RfAgcPwm = 100 * RfAgcPwm / 1023;
-
-	IfAgcPwm =
-		stv0367_readbits(state, F367CAB_AGC_IF_PWMCMD_LO) +
-		(stv0367_readbits(state, F367CAB_AGC_IF_PWMCMD_HI) << 8);
-	if (IfAgcPwm >= 2048)
-		IfAgcPwm -= 2048;
-	else
-		IfAgcPwm += 2048;
-
-	IfAgcPwm = 100 * IfAgcPwm / 4095;
-
-	/* For DTT75467 on NIM */
-	if (RfAgcPwm < 90  && IfAgcPwm < 28) {
-		for (i = 0; i < RF_LOOKUP_TABLE_SIZE; i++) {
-			if (RfAgcPwm <= stv0367cab_RF_LookUp1[0][i]) {
-				rfLevel = (-1) * stv0367cab_RF_LookUp1[1][i];
-				break;
-			}
-		}
-		if (i == RF_LOOKUP_TABLE_SIZE)
-			rfLevel = -56;
-	} else { /*if IF AGC>10*/
-		for (i = 0; i < RF_LOOKUP_TABLE2_SIZE; i++) {
-			if (IfAgcPwm <= stv0367cab_RF_LookUp2[0][i]) {
-				rfLevel = (-1) * stv0367cab_RF_LookUp2[1][i];
-				break;
-			}
-		}
-		if (i == RF_LOOKUP_TABLE2_SIZE)
-			rfLevel = -72;
-	}
-	return rfLevel;
-}
-
-static int stv0367cab_read_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct stv0367_state *state = fe->demodulator_priv;
-
-	s32 signal =  stv0367cab_get_rf_lvl(state);
-
-	dprintk("%s: signal=%d dBm\n", __func__, signal);
-
-	if (signal <= -72)
-		*strength = 65535;
-	else
-		*strength = (22 + signal) * (-1311);
-
-	dprintk("%s: strength=%d\n", __func__, (*strength));
-
-	return 0;
-}
-
-static int stv0367cab_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct stv0367_state *state = fe->demodulator_priv;
-	u32 noisepercentage;
-	enum stv0367cab_mod QAMSize;
-	u32 regval = 0, temp = 0;
-	int power, i;
-
-	QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE);
-	switch (QAMSize) {
-	case FE_CAB_MOD_QAM4:
-		power = 21904;
-		break;
-	case FE_CAB_MOD_QAM16:
-		power = 20480;
-		break;
-	case FE_CAB_MOD_QAM32:
-		power = 23040;
-		break;
-	case FE_CAB_MOD_QAM64:
-		power = 21504;
-		break;
-	case FE_CAB_MOD_QAM128:
-		power = 23616;
-		break;
-	case FE_CAB_MOD_QAM256:
-		power = 21760;
-		break;
-	case FE_CAB_MOD_QAM512:
-		power = 1;
-		break;
-	case FE_CAB_MOD_QAM1024:
-		power = 21280;
-		break;
-	default:
-		power = 1;
-		break;
-	}
-
-	for (i = 0; i < 10; i++) {
-		regval += (stv0367_readbits(state, F367CAB_SNR_LO)
-			+ 256 * stv0367_readbits(state, F367CAB_SNR_HI));
-	}
-
-	regval /= 10; /*for average over 10 times in for loop above*/
-	if (regval != 0) {
-		temp = power
-			* (1 << (3 + stv0367_readbits(state, F367CAB_SNR_PER)));
-		temp /= regval;
-	}
-
-	/* table values, not needed to calculate logarithms */
-	if (temp >= 5012)
-		noisepercentage = 100;
-	else if (temp >= 3981)
-		noisepercentage = 93;
-	else if (temp >= 3162)
-		noisepercentage = 86;
-	else if (temp >= 2512)
-		noisepercentage = 79;
-	else if (temp >= 1995)
-		noisepercentage = 72;
-	else if (temp >= 1585)
-		noisepercentage = 65;
-	else if (temp >= 1259)
-		noisepercentage = 58;
-	else if (temp >= 1000)
-		noisepercentage = 50;
-	else if (temp >= 794)
-		noisepercentage = 43;
-	else if (temp >= 501)
-		noisepercentage = 36;
-	else if (temp >= 316)
-		noisepercentage = 29;
-	else if (temp >= 200)
-		noisepercentage = 22;
-	else if (temp >= 158)
-		noisepercentage = 14;
-	else if (temp >= 126)
-		noisepercentage = 7;
-	else
-		noisepercentage = 0;
-
-	dprintk("%s: noisepercentage=%d\n", __func__, noisepercentage);
-
-	*snr = (noisepercentage * 65535) / 100;
-
-	return 0;
-}
-
-static int stv0367cab_read_ucblcks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct stv0367_state *state = fe->demodulator_priv;
-	int corrected, tscount;
-
-	*ucblocks = (stv0367_readreg(state, R367CAB_RS_COUNTER_5) << 8)
-			| stv0367_readreg(state, R367CAB_RS_COUNTER_4);
-	corrected = (stv0367_readreg(state, R367CAB_RS_COUNTER_3) << 8)
-			| stv0367_readreg(state, R367CAB_RS_COUNTER_2);
-	tscount = (stv0367_readreg(state, R367CAB_RS_COUNTER_2) << 8)
-			| stv0367_readreg(state, R367CAB_RS_COUNTER_1);
-
-	dprintk("%s: uncorrected blocks=%d corrected blocks=%d tscount=%d\n",
-				__func__, *ucblocks, corrected, tscount);
-
-	return 0;
-};
-
-static struct dvb_frontend_ops stv0367cab_ops = {
-	.delsys = { SYS_DVBC_ANNEX_A },
-	.info = {
-		.name = "ST STV0367 DVB-C",
-		.frequency_min = 47000000,
-		.frequency_max = 862000000,
-		.frequency_stepsize = 62500,
-		.symbol_rate_min = 870000,
-		.symbol_rate_max = 11700000,
-		.caps = 0x400 |/* FE_CAN_QAM_4 */
-			FE_CAN_QAM_16 | FE_CAN_QAM_32  |
-			FE_CAN_QAM_64 | FE_CAN_QAM_128 |
-			FE_CAN_QAM_256 | FE_CAN_FEC_AUTO
-	},
-	.release				= stv0367_release,
-	.init					= stv0367cab_init,
-	.sleep					= stv0367cab_sleep,
-	.i2c_gate_ctrl				= stv0367cab_gate_ctrl,
-	.set_frontend				= stv0367cab_set_frontend,
-	.get_frontend				= stv0367cab_get_frontend,
-	.read_status				= stv0367cab_read_status,
-/*	.read_ber				= stv0367cab_read_ber, */
-	.read_signal_strength			= stv0367cab_read_strength,
-	.read_snr				= stv0367cab_read_snr,
-	.read_ucblocks				= stv0367cab_read_ucblcks,
-	.get_tune_settings			= stv0367_get_tune_settings,
-};
-
-struct dvb_frontend *stv0367cab_attach(const struct stv0367_config *config,
-				   struct i2c_adapter *i2c)
-{
-	struct stv0367_state *state = NULL;
-	struct stv0367cab_state *cab_state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct stv0367_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-	cab_state = kzalloc(sizeof(struct stv0367cab_state), GFP_KERNEL);
-	if (cab_state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->i2c = i2c;
-	state->config = config;
-	cab_state->search_range = 280000;
-	state->cab_state = cab_state;
-	state->fe.ops = stv0367cab_ops;
-	state->fe.demodulator_priv = state;
-	state->chip_id = stv0367_readreg(state, 0xf000);
-
-	dprintk("%s: chip_id = 0x%x\n", __func__, state->chip_id);
-
-	/* check if the demod is there */
-	if ((state->chip_id != 0x50) && (state->chip_id != 0x60))
-		goto error;
-
-	return &state->fe;
-
-error:
-	kfree(cab_state);
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(stv0367cab_attach);
-
-MODULE_PARM_DESC(debug, "Set debug");
-MODULE_PARM_DESC(i2c_debug, "Set i2c debug");
-
-MODULE_AUTHOR("Igor M. Liplianin");
-MODULE_DESCRIPTION("ST STV0367 DVB-C/T demodulator driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stv0367.h b/drivers/media/dvb/frontends/stv0367.h
deleted file mode 100644
index 93cc4a5..0000000
--- a/drivers/media/dvb/frontends/stv0367.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * stv0367.h
- *
- * Driver for ST STV0367 DVB-T & DVB-C demodulator IC.
- *
- * Copyright (C) ST Microelectronics.
- * Copyright (C) 2010,2011 NetUP Inc.
- * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef STV0367_H
-#define STV0367_H
-
-#include <linux/dvb/frontend.h>
-#include "dvb_frontend.h"
-
-struct stv0367_config {
-	u8 demod_address;
-	u32 xtal;
-	u32 if_khz;/*4500*/
-	int if_iq_mode;
-	int ts_mode;
-	int clk_pol;
-};
-
-#if defined(CONFIG_DVB_STV0367) || (defined(CONFIG_DVB_STV0367_MODULE) \
-							&& defined(MODULE))
-extern struct
-dvb_frontend *stv0367ter_attach(const struct stv0367_config *config,
-					struct i2c_adapter *i2c);
-extern struct
-dvb_frontend *stv0367cab_attach(const struct stv0367_config *config,
-					struct i2c_adapter *i2c);
-#else
-static inline struct
-dvb_frontend *stv0367ter_attach(const struct stv0367_config *config,
-					struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-static inline struct
-dvb_frontend *stv0367cab_attach(const struct stv0367_config *config,
-					struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/dvb/frontends/stv0367_priv.h b/drivers/media/dvb/frontends/stv0367_priv.h
deleted file mode 100644
index 995db06..0000000
--- a/drivers/media/dvb/frontends/stv0367_priv.h
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * stv0367_priv.h
- *
- * Driver for ST STV0367 DVB-T & DVB-C demodulator IC.
- *
- * Copyright (C) ST Microelectronics.
- * Copyright (C) 2010,2011 NetUP Inc.
- * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/* Common driver error constants */
-
-#ifndef STV0367_PRIV_H
-#define STV0367_PRIV_H
-
-#ifndef TRUE
-    #define TRUE (1 == 1)
-#endif
-#ifndef FALSE
-    #define FALSE (!TRUE)
-#endif
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-/* MACRO definitions */
-#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X))
-#define MAX(X, Y) ((X) >= (Y) ? (X) : (Y))
-#define MIN(X, Y) ((X) <= (Y) ? (X) : (Y))
-#define INRANGE(X, Y, Z) \
-	((((X) <= (Y)) && ((Y) <= (Z))) || \
-	(((Z) <= (Y)) && ((Y) <= (X))) ? 1 : 0)
-
-#ifndef MAKEWORD
-#define MAKEWORD(X, Y) (((X) << 8) + (Y))
-#endif
-
-#define LSB(X) (((X) & 0xff))
-#define MSB(Y) (((Y) >> 8) & 0xff)
-#define MMSB(Y)(((Y) >> 16) & 0xff)
-
-enum stv0367_ter_signal_type {
-	FE_TER_NOAGC = 0,
-	FE_TER_AGCOK = 5,
-	FE_TER_NOTPS = 6,
-	FE_TER_TPSOK = 7,
-	FE_TER_NOSYMBOL = 8,
-	FE_TER_BAD_CPQ = 9,
-	FE_TER_PRFOUNDOK = 10,
-	FE_TER_NOPRFOUND = 11,
-	FE_TER_LOCKOK = 12,
-	FE_TER_NOLOCK = 13,
-	FE_TER_SYMBOLOK = 15,
-	FE_TER_CPAMPOK = 16,
-	FE_TER_NOCPAMP = 17,
-	FE_TER_SWNOK = 18
-};
-
-enum stv0367_ts_mode {
-	STV0367_OUTPUTMODE_DEFAULT,
-	STV0367_SERIAL_PUNCT_CLOCK,
-	STV0367_SERIAL_CONT_CLOCK,
-	STV0367_PARALLEL_PUNCT_CLOCK,
-	STV0367_DVBCI_CLOCK
-};
-
-enum stv0367_clk_pol {
-	STV0367_CLOCKPOLARITY_DEFAULT,
-	STV0367_RISINGEDGE_CLOCK,
-	STV0367_FALLINGEDGE_CLOCK
-};
-
-enum stv0367_ter_bw {
-	FE_TER_CHAN_BW_6M = 6,
-	FE_TER_CHAN_BW_7M = 7,
-	FE_TER_CHAN_BW_8M = 8
-};
-
-#if 0
-enum FE_TER_Rate_TPS {
-	FE_TER_TPS_1_2 = 0,
-	FE_TER_TPS_2_3 = 1,
-	FE_TER_TPS_3_4 = 2,
-	FE_TER_TPS_5_6 = 3,
-	FE_TER_TPS_7_8 = 4
-};
-#endif
-
-enum stv0367_ter_mode {
-	FE_TER_MODE_2K,
-	FE_TER_MODE_8K,
-	FE_TER_MODE_4K
-};
-#if 0
-enum FE_TER_Hierarchy_Alpha {
-	FE_TER_HIER_ALPHA_NONE,	/* Regular modulation */
-	FE_TER_HIER_ALPHA_1,	/* Hierarchical modulation a = 1*/
-	FE_TER_HIER_ALPHA_2,	/* Hierarchical modulation a = 2*/
-	FE_TER_HIER_ALPHA_4	/* Hierarchical modulation a = 4*/
-};
-#endif
-enum stv0367_ter_hierarchy {
-	FE_TER_HIER_NONE,	/*Hierarchy None*/
-	FE_TER_HIER_LOW_PRIO,	/*Hierarchy : Low Priority*/
-	FE_TER_HIER_HIGH_PRIO,	/*Hierarchy : High Priority*/
-	FE_TER_HIER_PRIO_ANY	/*Hierarchy  :Any*/
-};
-
-#if 0
-enum fe_stv0367_ter_spec {
-	FE_TER_INVERSION_NONE = 0,
-	FE_TER_INVERSION = 1,
-	FE_TER_INVERSION_AUTO = 2,
-	FE_TER_INVERSION_UNK  = 4
-};
-#endif
-
-enum stv0367_ter_if_iq_mode {
-	FE_TER_NORMAL_IF_TUNER = 0,
-	FE_TER_LONGPATH_IF_TUNER = 1,
-	FE_TER_IQ_TUNER = 2
-
-};
-
-#if 0
-enum FE_TER_FECRate {
-	FE_TER_FEC_NONE = 0x00,	/* no FEC rate specified */
-	FE_TER_FEC_ALL = 0xFF,	 /* Logical OR of all FECs */
-	FE_TER_FEC_1_2 = 1,
-	FE_TER_FEC_2_3 = (1 << 1),
-	FE_TER_FEC_3_4 = (1 << 2),
-	FE_TER_FEC_4_5 = (1 << 3),
-	FE_TER_FEC_5_6 = (1 << 4),
-	FE_TER_FEC_6_7 = (1 << 5),
-	FE_TER_FEC_7_8 = (1 << 6),
-	FE_TER_FEC_8_9 = (1 << 7)
-};
-
-enum FE_TER_Rate {
-	FE_TER_FE_1_2 = 0,
-	FE_TER_FE_2_3 = 1,
-	FE_TER_FE_3_4 = 2,
-	FE_TER_FE_5_6 = 3,
-	FE_TER_FE_6_7 = 4,
-	FE_TER_FE_7_8 = 5
-};
-#endif
-
-enum stv0367_ter_force {
-	FE_TER_FORCENONE = 0,
-	FE_TER_FORCE_M_G = 1
-};
-
-enum  stv0367cab_mod {
-	FE_CAB_MOD_QAM4,
-	FE_CAB_MOD_QAM16,
-	FE_CAB_MOD_QAM32,
-	FE_CAB_MOD_QAM64,
-	FE_CAB_MOD_QAM128,
-	FE_CAB_MOD_QAM256,
-	FE_CAB_MOD_QAM512,
-	FE_CAB_MOD_QAM1024
-};
-#if 0
-enum {
-	FE_CAB_FEC_A = 1,	/* J83 Annex A */
-	FE_CAB_FEC_B = (1 << 1),/* J83 Annex B */
-	FE_CAB_FEC_C = (1 << 2)	/* J83 Annex C */
-} FE_CAB_FECType_t;
-#endif
-struct stv0367_cab_signal_info {
-	int locked;
-	u32 frequency; /* kHz */
-	u32 symbol_rate; /* Mbds */
-	enum stv0367cab_mod modulation;
-	fe_spectral_inversion_t spect_inv;
-	s32 Power_dBmx10;	/* Power of the RF signal (dBm x 10) */
-	u32	CN_dBx10;	/* Carrier to noise ratio (dB x 10) */
-	u32	BER;		/* Bit error rate (x 10000000)	*/
-};
-
-enum stv0367_cab_signal_type {
-	FE_CAB_NOTUNER,
-	FE_CAB_NOAGC,
-	FE_CAB_NOSIGNAL,
-	FE_CAB_NOTIMING,
-	FE_CAB_TIMINGOK,
-	FE_CAB_NOCARRIER,
-	FE_CAB_CARRIEROK,
-	FE_CAB_NOBLIND,
-	FE_CAB_BLINDOK,
-	FE_CAB_NODEMOD,
-	FE_CAB_DEMODOK,
-	FE_CAB_DATAOK
-};
-
-#endif
diff --git a/drivers/media/dvb/frontends/stv0367_regs.h b/drivers/media/dvb/frontends/stv0367_regs.h
deleted file mode 100644
index a96fbdc..0000000
--- a/drivers/media/dvb/frontends/stv0367_regs.h
+++ /dev/null
@@ -1,3614 +0,0 @@
-/*
- * stv0367_regs.h
- *
- * Driver for ST STV0367 DVB-T & DVB-C demodulator IC.
- *
- * Copyright (C) ST Microelectronics.
- * Copyright (C) 2010,2011 NetUP Inc.
- * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef STV0367_REGS_H
-#define STV0367_REGS_H
-
-/* ID */
-#define	R367TER_ID	0xf000
-#define	F367TER_IDENTIFICATIONREG	0xf00000ff
-
-/* I2CRPT */
-#define	R367TER_I2CRPT	0xf001
-#define	F367TER_I2CT_ON	0xf0010080
-#define	F367TER_ENARPT_LEVEL	0xf0010070
-#define	F367TER_SCLT_DELAY	0xf0010008
-#define	F367TER_SCLT_NOD	0xf0010004
-#define	F367TER_STOP_ENABLE	0xf0010002
-#define	F367TER_SDAT_NOD	0xf0010001
-
-/* TOPCTRL */
-#define	R367TER_TOPCTRL	0xf002
-#define	F367TER_STDBY	0xf0020080
-#define	F367TER_STDBY_FEC	0xf0020040
-#define	F367TER_STDBY_CORE	0xf0020020
-#define	F367TER_QAM_COFDM	0xf0020010
-#define	F367TER_TS_DIS	0xf0020008
-#define	F367TER_DIR_CLK_216	0xf0020004
-#define	F367TER_TUNER_BB	0xf0020002
-#define	F367TER_DVBT_H	0xf0020001
-
-/* IOCFG0 */
-#define	R367TER_IOCFG0	0xf003
-#define	F367TER_OP0_SD	0xf0030080
-#define	F367TER_OP0_VAL	0xf0030040
-#define	F367TER_OP0_OD	0xf0030020
-#define	F367TER_OP0_INV	0xf0030010
-#define	F367TER_OP0_DACVALUE_HI	0xf003000f
-
-/* DAc0R */
-#define	R367TER_DAC0R	0xf004
-#define	F367TER_OP0_DACVALUE_LO	0xf00400ff
-
-/* IOCFG1 */
-#define	R367TER_IOCFG1	0xf005
-#define	F367TER_IP0	0xf0050040
-#define	F367TER_OP1_OD	0xf0050020
-#define	F367TER_OP1_INV	0xf0050010
-#define	F367TER_OP1_DACVALUE_HI	0xf005000f
-
-/* DAC1R */
-#define	R367TER_DAC1R	0xf006
-#define	F367TER_OP1_DACVALUE_LO	0xf00600ff
-
-/* IOCFG2 */
-#define	R367TER_IOCFG2	0xf007
-#define	F367TER_OP2_LOCK_CONF	0xf00700e0
-#define	F367TER_OP2_OD	0xf0070010
-#define	F367TER_OP2_VAL	0xf0070008
-#define	F367TER_OP1_LOCK_CONF	0xf0070007
-
-/* SDFR */
-#define	R367TER_SDFR	0xf008
-#define	F367TER_OP0_FREQ	0xf00800f0
-#define	F367TER_OP1_FREQ	0xf008000f
-
-/* STATUS */
-#define	R367TER_STATUS	0xf009
-#define	F367TER_TPS_LOCK	0xf0090080
-#define	F367TER_SYR_LOCK	0xf0090040
-#define	F367TER_AGC_LOCK	0xf0090020
-#define	F367TER_PRF	0xf0090010
-#define	F367TER_LK	0xf0090008
-#define	F367TER_PR	0xf0090007
-
-/* AUX_CLK */
-#define	R367TER_AUX_CLK	0xf00a
-#define	F367TER_AUXFEC_CTL	0xf00a00c0
-#define	F367TER_DIS_CKX4	0xf00a0020
-#define	F367TER_CKSEL	0xf00a0018
-#define	F367TER_CKDIV_PROG	0xf00a0006
-#define	F367TER_AUXCLK_ENA	0xf00a0001
-
-/* FREESYS1 */
-#define	R367TER_FREESYS1	0xf00b
-#define	F367TER_FREE_SYS1	0xf00b00ff
-
-/* FREESYS2 */
-#define	R367TER_FREESYS2	0xf00c
-#define	F367TER_FREE_SYS2	0xf00c00ff
-
-/* FREESYS3 */
-#define	R367TER_FREESYS3	0xf00d
-#define	F367TER_FREE_SYS3	0xf00d00ff
-
-/* GPIO_CFG */
-#define	R367TER_GPIO_CFG	0xf00e
-#define	F367TER_GPIO7_NOD	0xf00e0080
-#define	F367TER_GPIO7_CFG	0xf00e0040
-#define	F367TER_GPIO6_NOD	0xf00e0020
-#define	F367TER_GPIO6_CFG	0xf00e0010
-#define	F367TER_GPIO5_NOD	0xf00e0008
-#define	F367TER_GPIO5_CFG	0xf00e0004
-#define	F367TER_GPIO4_NOD	0xf00e0002
-#define	F367TER_GPIO4_CFG	0xf00e0001
-
-/* GPIO_CMD */
-#define	R367TER_GPIO_CMD	0xf00f
-#define	F367TER_GPIO7_VAL	0xf00f0008
-#define	F367TER_GPIO6_VAL	0xf00f0004
-#define	F367TER_GPIO5_VAL	0xf00f0002
-#define	F367TER_GPIO4_VAL	0xf00f0001
-
-/* AGC2MAX */
-#define	R367TER_AGC2MAX	0xf010
-#define	F367TER_AGC2_MAX	0xf01000ff
-
-/* AGC2MIN */
-#define	R367TER_AGC2MIN	0xf011
-#define	F367TER_AGC2_MIN	0xf01100ff
-
-/* AGC1MAX */
-#define	R367TER_AGC1MAX	0xf012
-#define	F367TER_AGC1_MAX	0xf01200ff
-
-/* AGC1MIN */
-#define	R367TER_AGC1MIN	0xf013
-#define	F367TER_AGC1_MIN	0xf01300ff
-
-/* AGCR */
-#define	R367TER_AGCR	0xf014
-#define	F367TER_RATIO_A	0xf01400e0
-#define	F367TER_RATIO_B	0xf0140018
-#define	F367TER_RATIO_C	0xf0140007
-
-/* AGC2TH */
-#define	R367TER_AGC2TH	0xf015
-#define	F367TER_AGC2_THRES	0xf01500ff
-
-/* AGC12c */
-#define	R367TER_AGC12C	0xf016
-#define	F367TER_AGC1_IV	0xf0160080
-#define	F367TER_AGC1_OD	0xf0160040
-#define	F367TER_AGC1_LOAD	0xf0160020
-#define	F367TER_AGC2_IV	0xf0160010
-#define	F367TER_AGC2_OD	0xf0160008
-#define	F367TER_AGC2_LOAD	0xf0160004
-#define	F367TER_AGC12_MODE	0xf0160003
-
-/* AGCCTRL1 */
-#define	R367TER_AGCCTRL1	0xf017
-#define	F367TER_DAGC_ON	0xf0170080
-#define	F367TER_INVERT_AGC12	0xf0170040
-#define	F367TER_AGC1_MODE	0xf0170008
-#define	F367TER_AGC2_MODE	0xf0170007
-
-/* AGCCTRL2 */
-#define	R367TER_AGCCTRL2	0xf018
-#define	F367TER_FRZ2_CTRL	0xf0180060
-#define	F367TER_FRZ1_CTRL	0xf0180018
-#define	F367TER_TIME_CST	0xf0180007
-
-/* AGC1VAL1 */
-#define	R367TER_AGC1VAL1	0xf019
-#define	F367TER_AGC1_VAL_LO	0xf01900ff
-
-/* AGC1VAL2 */
-#define	R367TER_AGC1VAL2	0xf01a
-#define	F367TER_AGC1_VAL_HI	0xf01a000f
-
-/* AGC2VAL1 */
-#define	R367TER_AGC2VAL1	0xf01b
-#define	F367TER_AGC2_VAL_LO	0xf01b00ff
-
-/* AGC2VAL2 */
-#define	R367TER_AGC2VAL2	0xf01c
-#define	F367TER_AGC2_VAL_HI	0xf01c000f
-
-/* AGC2PGA */
-#define	R367TER_AGC2PGA	0xf01d
-#define	F367TER_AGC2_PGA	0xf01d00ff
-
-/* OVF_RATE1 */
-#define	R367TER_OVF_RATE1	0xf01e
-#define	F367TER_OVF_RATE_HI	0xf01e000f
-
-/* OVF_RATE2 */
-#define	R367TER_OVF_RATE2	0xf01f
-#define	F367TER_OVF_RATE_LO	0xf01f00ff
-
-/* GAIN_SRC1 */
-#define	R367TER_GAIN_SRC1	0xf020
-#define	F367TER_INV_SPECTR	0xf0200080
-#define	F367TER_IQ_INVERT	0xf0200040
-#define	F367TER_INR_BYPASS	0xf0200020
-#define	F367TER_STATUS_INV_SPECRUM	0xf0200010
-#define	F367TER_GAIN_SRC_HI	0xf020000f
-
-/* GAIN_SRC2 */
-#define	R367TER_GAIN_SRC2	0xf021
-#define	F367TER_GAIN_SRC_LO	0xf02100ff
-
-/* INC_DEROT1 */
-#define	R367TER_INC_DEROT1	0xf022
-#define	F367TER_INC_DEROT_HI	0xf02200ff
-
-/* INC_DEROT2 */
-#define	R367TER_INC_DEROT2	0xf023
-#define	F367TER_INC_DEROT_LO	0xf02300ff
-
-/* PPM_CPAMP_DIR */
-#define	R367TER_PPM_CPAMP_DIR	0xf024
-#define	F367TER_PPM_CPAMP_DIRECT	0xf02400ff
-
-/* PPM_CPAMP_INV */
-#define	R367TER_PPM_CPAMP_INV	0xf025
-#define	F367TER_PPM_CPAMP_INVER	0xf02500ff
-
-/* FREESTFE_1 */
-#define	R367TER_FREESTFE_1	0xf026
-#define	F367TER_SYMBOL_NUMBER_INC	0xf02600c0
-#define	F367TER_SEL_LSB	0xf0260004
-#define	F367TER_AVERAGE_ON	0xf0260002
-#define	F367TER_DC_ADJ	0xf0260001
-
-/* FREESTFE_2 */
-#define	R367TER_FREESTFE_2	0xf027
-#define	F367TER_SEL_SRCOUT	0xf02700c0
-#define	F367TER_SEL_SYRTHR	0xf027001f
-
-/* DCOFFSET */
-#define	R367TER_DCOFFSET	0xf028
-#define	F367TER_SELECT_I_Q	0xf0280080
-#define	F367TER_DC_OFFSET	0xf028007f
-
-/* EN_PROCESS */
-#define	R367TER_EN_PROCESS	0xf029
-#define	F367TER_FREE	0xf02900f0
-#define	F367TER_ENAB_MANUAL	0xf0290001
-
-/* SDI_SMOOTHER */
-#define	R367TER_SDI_SMOOTHER	0xf02a
-#define	F367TER_DIS_SMOOTH	0xf02a0080
-#define	F367TER_SDI_INC_SMOOTHER	0xf02a007f
-
-/* FE_LOOP_OPEN */
-#define	R367TER_FE_LOOP_OPEN	0xf02b
-#define	F367TER_TRL_LOOP_OP	0xf02b0002
-#define	F367TER_CRL_LOOP_OP	0xf02b0001
-
-/* FREQOFF1 */
-#define	R367TER_FREQOFF1	0xf02c
-#define	F367TER_FREQ_OFFSET_LOOP_OPEN_VHI	0xf02c00ff
-
-/* FREQOFF2 */
-#define	R367TER_FREQOFF2	0xf02d
-#define	F367TER_FREQ_OFFSET_LOOP_OPEN_HI	0xf02d00ff
-
-/* FREQOFF3 */
-#define	R367TER_FREQOFF3	0xf02e
-#define	F367TER_FREQ_OFFSET_LOOP_OPEN_LO	0xf02e00ff
-
-/* TIMOFF1 */
-#define	R367TER_TIMOFF1	0xf02f
-#define	F367TER_TIM_OFFSET_LOOP_OPEN_HI	0xf02f00ff
-
-/* TIMOFF2 */
-#define	R367TER_TIMOFF2	0xf030
-#define	F367TER_TIM_OFFSET_LOOP_OPEN_LO	0xf03000ff
-
-/* EPQ */
-#define	R367TER_EPQ	0xf031
-#define	F367TER_EPQ1	0xf03100ff
-
-/* EPQAUTO */
-#define	R367TER_EPQAUTO	0xf032
-#define	F367TER_EPQ2	0xf03200ff
-
-/* SYR_UPDATE */
-#define	R367TER_SYR_UPDATE	0xf033
-#define	F367TER_SYR_PROTV	0xf0330080
-#define	F367TER_SYR_PROTV_GAIN	0xf0330060
-#define	F367TER_SYR_FILTER	0xf0330010
-#define	F367TER_SYR_TRACK_THRES	0xf033000c
-
-/* CHPFREE */
-#define	R367TER_CHPFREE	0xf034
-#define	F367TER_CHP_FREE	0xf03400ff
-
-/* PPM_STATE_MAC */
-#define	R367TER_PPM_STATE_MAC	0xf035
-#define	F367TER_PPM_STATE_MACHINE_DECODER	0xf035003f
-
-/* INR_THRESHOLD */
-#define	R367TER_INR_THRESHOLD	0xf036
-#define	F367TER_INR_THRESH	0xf03600ff
-
-/* EPQ_TPS_ID_CELL */
-#define	R367TER_EPQ_TPS_ID_CELL	0xf037
-#define	F367TER_ENABLE_LGTH_TO_CF	0xf0370080
-#define	F367TER_DIS_TPS_RSVD	0xf0370040
-#define	F367TER_DIS_BCH	0xf0370020
-#define	F367TER_DIS_ID_CEL	0xf0370010
-#define	F367TER_TPS_ADJUST_SYM	0xf037000f
-
-/* EPQ_CFG */
-#define	R367TER_EPQ_CFG	0xf038
-#define	F367TER_EPQ_RANGE	0xf0380002
-#define	F367TER_EPQ_SOFT	0xf0380001
-
-/* EPQ_STATUS */
-#define	R367TER_EPQ_STATUS	0xf039
-#define	F367TER_SLOPE_INC	0xf03900fc
-#define	F367TER_TPS_FIELD	0xf0390003
-
-/* AUTORELOCK */
-#define	R367TER_AUTORELOCK	0xf03a
-#define	F367TER_BYPASS_BER_TEMPO	0xf03a0080
-#define	F367TER_BER_TEMPO	0xf03a0070
-#define	F367TER_BYPASS_COFDM_TEMPO	0xf03a0008
-#define	F367TER_COFDM_TEMPO	0xf03a0007
-
-/* BER_THR_VMSB */
-#define	R367TER_BER_THR_VMSB	0xf03b
-#define	F367TER_BER_THRESHOLD_HI	0xf03b00ff
-
-/* BER_THR_MSB */
-#define	R367TER_BER_THR_MSB	0xf03c
-#define	F367TER_BER_THRESHOLD_MID	0xf03c00ff
-
-/* BER_THR_LSB */
-#define	R367TER_BER_THR_LSB	0xf03d
-#define	F367TER_BER_THRESHOLD_LO	0xf03d00ff
-
-/* CCD */
-#define	R367TER_CCD	0xf03e
-#define	F367TER_CCD_DETECTED	0xf03e0080
-#define	F367TER_CCD_RESET	0xf03e0040
-#define	F367TER_CCD_THRESHOLD	0xf03e000f
-
-/* SPECTR_CFG */
-#define	R367TER_SPECTR_CFG	0xf03f
-#define	F367TER_SPECT_CFG	0xf03f0003
-
-/* CONSTMU_MSB */
-#define	R367TER_CONSTMU_MSB	0xf040
-#define	F367TER_CONSTMU_FREEZE	0xf0400080
-#define	F367TER_CONSTNU_FORCE_EN	0xf0400040
-#define	F367TER_CONST_MU_MSB	0xf040003f
-
-/* CONSTMU_LSB */
-#define	R367TER_CONSTMU_LSB	0xf041
-#define	F367TER_CONST_MU_LSB	0xf04100ff
-
-/* CONSTMU_MAX_MSB */
-#define	R367TER_CONSTMU_MAX_MSB	0xf042
-#define	F367TER_CONST_MU_MAX_MSB	0xf042003f
-
-/* CONSTMU_MAX_LSB */
-#define	R367TER_CONSTMU_MAX_LSB	0xf043
-#define	F367TER_CONST_MU_MAX_LSB	0xf04300ff
-
-/* ALPHANOISE */
-#define	R367TER_ALPHANOISE	0xf044
-#define	F367TER_USE_ALLFILTER	0xf0440080
-#define	F367TER_INTER_ON	0xf0440040
-#define	F367TER_ALPHA_NOISE	0xf044001f
-
-/* MAXGP_MSB */
-#define	R367TER_MAXGP_MSB	0xf045
-#define	F367TER_MUFILTER_LENGTH	0xf04500f0
-#define	F367TER_MAX_GP_MSB	0xf045000f
-
-/* MAXGP_LSB */
-#define	R367TER_MAXGP_LSB	0xf046
-#define	F367TER_MAX_GP_LSB	0xf04600ff
-
-/* ALPHAMSB */
-#define	R367TER_ALPHAMSB	0xf047
-#define	F367TER_CHC_DATARATE	0xf04700c0
-#define	F367TER_ALPHA_MSB	0xf047003f
-
-/* ALPHALSB */
-#define	R367TER_ALPHALSB	0xf048
-#define	F367TER_ALPHA_LSB	0xf04800ff
-
-/* PILOT_ACCU */
-#define	R367TER_PILOT_ACCU	0xf049
-#define	F367TER_USE_SCAT4ADDAPT	0xf0490080
-#define	F367TER_PILOT_ACC	0xf049001f
-
-/* PILOTMU_ACCU */
-#define	R367TER_PILOTMU_ACCU	0xf04a
-#define	F367TER_DISCARD_BAD_SP	0xf04a0080
-#define	F367TER_DISCARD_BAD_CP	0xf04a0040
-#define	F367TER_PILOT_MU_ACCU	0xf04a001f
-
-/* FILT_CHANNEL_EST */
-#define	R367TER_FILT_CHANNEL_EST	0xf04b
-#define	F367TER_USE_FILT_PILOT	0xf04b0080
-#define	F367TER_FILT_CHANNEL	0xf04b007f
-
-/* ALPHA_NOPISE_FREQ */
-#define	R367TER_ALPHA_NOPISE_FREQ	0xf04c
-#define	F367TER_NOISE_FREQ_FILT	0xf04c0040
-#define	F367TER_ALPHA_NOISE_FREQ	0xf04c003f
-
-/* RATIO_PILOT */
-#define	R367TER_RATIO_PILOT	0xf04d
-#define	F367TER_RATIO_MEAN_SP	0xf04d00f0
-#define	F367TER_RATIO_MEAN_CP	0xf04d000f
-
-/* CHC_CTL */
-#define	R367TER_CHC_CTL	0xf04e
-#define	F367TER_TRACK_EN	0xf04e0080
-#define	F367TER_NOISE_NORM_EN	0xf04e0040
-#define	F367TER_FORCE_CHC_RESET	0xf04e0020
-#define	F367TER_SHORT_TIME	0xf04e0010
-#define	F367TER_FORCE_STATE_EN	0xf04e0008
-#define	F367TER_FORCE_STATE	0xf04e0007
-
-/* EPQ_ADJUST */
-#define	R367TER_EPQ_ADJUST	0xf04f
-#define	F367TER_ADJUST_SCAT_IND	0xf04f00c0
-#define	F367TER_ONE_SYMBOL	0xf04f0010
-#define	F367TER_EPQ_DECAY	0xf04f000e
-#define	F367TER_HOLD_SLOPE	0xf04f0001
-
-/* EPQ_THRES */
-#define	R367TER_EPQ_THRES	0xf050
-#define	F367TER_EPQ_THR	0xf05000ff
-
-/* OMEGA_CTL */
-#define	R367TER_OMEGA_CTL	0xf051
-#define	F367TER_OMEGA_RST	0xf0510080
-#define	F367TER_FREEZE_OMEGA	0xf0510040
-#define	F367TER_OMEGA_SEL	0xf051003f
-
-/* GP_CTL */
-#define	R367TER_GP_CTL	0xf052
-#define	F367TER_CHC_STATE	0xf05200e0
-#define	F367TER_FREEZE_GP	0xf0520010
-#define	F367TER_GP_SEL	0xf052000f
-
-/* MUMSB */
-#define	R367TER_MUMSB	0xf053
-#define	F367TER_MU_MSB	0xf053007f
-
-/* MULSB */
-#define	R367TER_MULSB	0xf054
-#define	F367TER_MU_LSB	0xf05400ff
-
-/* GPMSB */
-#define	R367TER_GPMSB	0xf055
-#define	F367TER_CSI_THRESHOLD	0xf05500e0
-#define	F367TER_GP_MSB	0xf055000f
-
-/* GPLSB */
-#define	R367TER_GPLSB	0xf056
-#define	F367TER_GP_LSB	0xf05600ff
-
-/* OMEGAMSB */
-#define	R367TER_OMEGAMSB	0xf057
-#define	F367TER_OMEGA_MSB	0xf057007f
-
-/* OMEGALSB */
-#define	R367TER_OMEGALSB	0xf058
-#define	F367TER_OMEGA_LSB	0xf05800ff
-
-/* SCAT_NB */
-#define	R367TER_SCAT_NB	0xf059
-#define	F367TER_CHC_TEST	0xf05900f8
-#define	F367TER_SCAT_NUMB	0xf0590003
-
-/* CHC_DUMMY */
-#define	R367TER_CHC_DUMMY	0xf05a
-#define	F367TER_CHC_DUM	0xf05a00ff
-
-/* INC_CTL */
-#define	R367TER_INC_CTL	0xf05b
-#define	F367TER_INC_BYPASS	0xf05b0080
-#define	F367TER_INC_NDEPTH	0xf05b000c
-#define	F367TER_INC_MADEPTH	0xf05b0003
-
-/* INCTHRES_COR1 */
-#define	R367TER_INCTHRES_COR1	0xf05c
-#define	F367TER_INC_THRES_COR1	0xf05c00ff
-
-/* INCTHRES_COR2 */
-#define	R367TER_INCTHRES_COR2	0xf05d
-#define	F367TER_INC_THRES_COR2	0xf05d00ff
-
-/* INCTHRES_DET1 */
-#define	R367TER_INCTHRES_DET1	0xf05e
-#define	F367TER_INC_THRES_DET1	0xf05e003f
-
-/* INCTHRES_DET2 */
-#define	R367TER_INCTHRES_DET2	0xf05f
-#define	F367TER_INC_THRES_DET2	0xf05f003f
-
-/* IIR_CELLNB */
-#define	R367TER_IIR_CELLNB	0xf060
-#define	F367TER_NRST_IIR	0xf0600080
-#define	F367TER_IIR_CELL_NB	0xf0600007
-
-/* IIRCX_COEFF1_MSB */
-#define	R367TER_IIRCX_COEFF1_MSB	0xf061
-#define	F367TER_IIR_CX_COEFF1_MSB	0xf06100ff
-
-/* IIRCX_COEFF1_LSB */
-#define	R367TER_IIRCX_COEFF1_LSB	0xf062
-#define	F367TER_IIR_CX_COEFF1_LSB	0xf06200ff
-
-/* IIRCX_COEFF2_MSB */
-#define	R367TER_IIRCX_COEFF2_MSB	0xf063
-#define	F367TER_IIR_CX_COEFF2_MSB	0xf06300ff
-
-/* IIRCX_COEFF2_LSB */
-#define	R367TER_IIRCX_COEFF2_LSB	0xf064
-#define	F367TER_IIR_CX_COEFF2_LSB	0xf06400ff
-
-/* IIRCX_COEFF3_MSB */
-#define	R367TER_IIRCX_COEFF3_MSB	0xf065
-#define	F367TER_IIR_CX_COEFF3_MSB	0xf06500ff
-
-/* IIRCX_COEFF3_LSB */
-#define	R367TER_IIRCX_COEFF3_LSB	0xf066
-#define	F367TER_IIR_CX_COEFF3_LSB	0xf06600ff
-
-/* IIRCX_COEFF4_MSB */
-#define	R367TER_IIRCX_COEFF4_MSB	0xf067
-#define	F367TER_IIR_CX_COEFF4_MSB	0xf06700ff
-
-/* IIRCX_COEFF4_LSB */
-#define	R367TER_IIRCX_COEFF4_LSB	0xf068
-#define	F367TER_IIR_CX_COEFF4_LSB	0xf06800ff
-
-/* IIRCX_COEFF5_MSB */
-#define	R367TER_IIRCX_COEFF5_MSB	0xf069
-#define	F367TER_IIR_CX_COEFF5_MSB	0xf06900ff
-
-/* IIRCX_COEFF5_LSB */
-#define	R367TER_IIRCX_COEFF5_LSB	0xf06a
-#define	F367TER_IIR_CX_COEFF5_LSB	0xf06a00ff
-
-/* FEPATH_CFG */
-#define	R367TER_FEPATH_CFG	0xf06b
-#define	F367TER_DEMUX_SWAP	0xf06b0004
-#define	F367TER_DIGAGC_SWAP	0xf06b0002
-#define	F367TER_LONGPATH_IF	0xf06b0001
-
-/* PMC1_FUNC */
-#define	R367TER_PMC1_FUNC	0xf06c
-#define	F367TER_SOFT_RSTN	0xf06c0080
-#define	F367TER_PMC1_AVERAGE_TIME	0xf06c0078
-#define	F367TER_PMC1_WAIT_TIME	0xf06c0006
-#define	F367TER_PMC1_2N_SEL	0xf06c0001
-
-/* PMC1_FOR */
-#define	R367TER_PMC1_FOR	0xf06d
-#define	F367TER_PMC1_FORCE	0xf06d0080
-#define	F367TER_PMC1_FORCE_VALUE	0xf06d007c
-
-/* PMC2_FUNC */
-#define	R367TER_PMC2_FUNC	0xf06e
-#define	F367TER_PMC2_SOFT_STN	0xf06e0080
-#define	F367TER_PMC2_ACCU_TIME	0xf06e0070
-#define	F367TER_PMC2_CMDP_MN	0xf06e0008
-#define	F367TER_PMC2_SWAP	0xf06e0004
-
-/* STATUS_ERR_DA */
-#define	R367TER_STATUS_ERR_DA	0xf06f
-#define	F367TER_COM_USEGAINTRK	0xf06f0080
-#define	F367TER_COM_AGCLOCK	0xf06f0040
-#define	F367TER_AUT_AGCLOCK	0xf06f0020
-#define	F367TER_MIN_ERR_X_LSB	0xf06f000f
-
-/* DIG_AGC_R */
-#define	R367TER_DIG_AGC_R	0xf070
-#define	F367TER_COM_SOFT_RSTN	0xf0700080
-#define	F367TER_COM_AGC_ON	0xf0700040
-#define	F367TER_COM_EARLY	0xf0700020
-#define	F367TER_AUT_SOFT_RESETN	0xf0700010
-#define	F367TER_AUT_AGC_ON	0xf0700008
-#define	F367TER_AUT_EARLY	0xf0700004
-#define	F367TER_AUT_ROT_EN	0xf0700002
-#define	F367TER_LOCK_SOFT_RESETN	0xf0700001
-
-/* COMAGC_TARMSB */
-#define	R367TER_COMAGC_TARMSB	0xf071
-#define	F367TER_COM_AGC_TARGET_MSB	0xf07100ff
-
-/* COM_AGC_TAR_ENMODE */
-#define	R367TER_COM_AGC_TAR_ENMODE	0xf072
-#define	F367TER_COM_AGC_TARGET_LSB	0xf07200f0
-#define	F367TER_COM_ENMODE	0xf072000f
-
-/* COM_AGC_CFG */
-#define	R367TER_COM_AGC_CFG	0xf073
-#define	F367TER_COM_N	0xf07300f8
-#define	F367TER_COM_STABMODE	0xf0730006
-#define	F367TER_ERR_SEL	0xf0730001
-
-/* COM_AGC_GAIN1 */
-#define	R367TER_COM_AGC_GAIN1	0xf074
-#define	F367TER_COM_GAIN1aCK	0xf07400f0
-#define	F367TER_COM_GAIN1TRK	0xf074000f
-
-/* AUT_AGC_TARGETMSB */
-#define	R367TER_AUT_AGC_TARGETMSB	0xf075
-#define	F367TER_AUT_AGC_TARGET_MSB	0xf07500ff
-
-/* LOCK_DET_MSB */
-#define	R367TER_LOCK_DET_MSB	0xf076
-#define	F367TER_LOCK_DETECT_MSB	0xf07600ff
-
-/* AGCTAR_LOCK_LSBS */
-#define	R367TER_AGCTAR_LOCK_LSBS	0xf077
-#define	F367TER_AUT_AGC_TARGET_LSB	0xf07700f0
-#define	F367TER_LOCK_DETECT_LSB	0xf077000f
-
-/* AUT_GAIN_EN */
-#define	R367TER_AUT_GAIN_EN	0xf078
-#define	F367TER_AUT_ENMODE	0xf07800f0
-#define	F367TER_AUT_GAIN2	0xf078000f
-
-/* AUT_CFG */
-#define	R367TER_AUT_CFG	0xf079
-#define	F367TER_AUT_N	0xf07900f8
-#define	F367TER_INT_CHOICE	0xf0790006
-#define	F367TER_INT_LOAD	0xf0790001
-
-/* LOCKN */
-#define	R367TER_LOCKN	0xf07a
-#define	F367TER_LOCK_N	0xf07a00f8
-#define	F367TER_SEL_IQNTAR	0xf07a0004
-#define	F367TER_LOCK_DETECT_CHOICE	0xf07a0003
-
-/* INT_X_3 */
-#define	R367TER_INT_X_3	0xf07b
-#define	F367TER_INT_X3	0xf07b00ff
-
-/* INT_X_2 */
-#define	R367TER_INT_X_2	0xf07c
-#define	F367TER_INT_X2	0xf07c00ff
-
-/* INT_X_1 */
-#define	R367TER_INT_X_1	0xf07d
-#define	F367TER_INT_X1	0xf07d00ff
-
-/* INT_X_0 */
-#define	R367TER_INT_X_0	0xf07e
-#define	F367TER_INT_X0	0xf07e00ff
-
-/* MIN_ERRX_MSB */
-#define	R367TER_MIN_ERRX_MSB	0xf07f
-#define	F367TER_MIN_ERR_X_MSB	0xf07f00ff
-
-/* COR_CTL */
-#define	R367TER_COR_CTL	0xf080
-#define	F367TER_CORE_ACTIVE	0xf0800020
-#define	F367TER_HOLD	0xf0800010
-#define	F367TER_CORE_STATE_CTL	0xf080000f
-
-/* COR_STAT */
-#define	R367TER_COR_STAT	0xf081
-#define	F367TER_SCATT_LOCKED	0xf0810080
-#define	F367TER_TPS_LOCKED	0xf0810040
-#define	F367TER_SYR_LOCKED_COR	0xf0810020
-#define	F367TER_AGC_LOCKED_STAT	0xf0810010
-#define	F367TER_CORE_STATE_STAT	0xf081000f
-
-/* COR_INTEN */
-#define	R367TER_COR_INTEN	0xf082
-#define	F367TER_INTEN	0xf0820080
-#define	F367TER_INTEN_SYR	0xf0820020
-#define	F367TER_INTEN_FFT	0xf0820010
-#define	F367TER_INTEN_AGC	0xf0820008
-#define	F367TER_INTEN_TPS1	0xf0820004
-#define	F367TER_INTEN_TPS2	0xf0820002
-#define	F367TER_INTEN_TPS3	0xf0820001
-
-/* COR_INTSTAT */
-#define	R367TER_COR_INTSTAT	0xf083
-#define	F367TER_INTSTAT_SYR	0xf0830020
-#define	F367TER_INTSTAT_FFT	0xf0830010
-#define	F367TER_INTSAT_AGC	0xf0830008
-#define	F367TER_INTSTAT_TPS1	0xf0830004
-#define	F367TER_INTSTAT_TPS2	0xf0830002
-#define	F367TER_INTSTAT_TPS3	0xf0830001
-
-/* COR_MODEGUARD */
-#define	R367TER_COR_MODEGUARD	0xf084
-#define	F367TER_FORCE	0xf0840010
-#define	F367TER_MODE	0xf084000c
-#define	F367TER_GUARD	0xf0840003
-
-/* AGC_CTL */
-#define	R367TER_AGC_CTL	0xf085
-#define	F367TER_AGC_TIMING_FACTOR	0xf08500e0
-#define	F367TER_AGC_LAST	0xf0850010
-#define	F367TER_AGC_GAIN	0xf085000c
-#define	F367TER_AGC_NEG	0xf0850002
-#define	F367TER_AGC_SET	0xf0850001
-
-/* AGC_MANUAL1 */
-#define	R367TER_AGC_MANUAL1	0xf086
-#define	F367TER_AGC_VAL_LO	0xf08600ff
-
-/* AGC_MANUAL2 */
-#define	R367TER_AGC_MANUAL2	0xf087
-#define	F367TER_AGC_VAL_HI	0xf087000f
-
-/* AGC_TARG */
-#define	R367TER_AGC_TARG	0xf088
-#define	F367TER_AGC_TARGET	0xf08800ff
-
-/* AGC_GAIN1 */
-#define	R367TER_AGC_GAIN1	0xf089
-#define	F367TER_AGC_GAIN_LO	0xf08900ff
-
-/* AGC_GAIN2 */
-#define	R367TER_AGC_GAIN2	0xf08a
-#define	F367TER_AGC_LOCKED_GAIN2	0xf08a0010
-#define	F367TER_AGC_GAIN_HI	0xf08a000f
-
-/* RESERVED_1 */
-#define	R367TER_RESERVED_1	0xf08b
-#define	F367TER_RESERVED1	0xf08b00ff
-
-/* RESERVED_2 */
-#define	R367TER_RESERVED_2	0xf08c
-#define	F367TER_RESERVED2	0xf08c00ff
-
-/* RESERVED_3 */
-#define	R367TER_RESERVED_3	0xf08d
-#define	F367TER_RESERVED3	0xf08d00ff
-
-/* CAS_CTL */
-#define	R367TER_CAS_CTL	0xf08e
-#define	F367TER_CCS_ENABLE	0xf08e0080
-#define	F367TER_ACS_DISABLE	0xf08e0040
-#define	F367TER_DAGC_DIS	0xf08e0020
-#define	F367TER_DAGC_GAIN	0xf08e0018
-#define	F367TER_CCSMU	0xf08e0007
-
-/* CAS_FREQ */
-#define	R367TER_CAS_FREQ	0xf08f
-#define	F367TER_CCS_FREQ	0xf08f00ff
-
-/* CAS_DAGCGAIN */
-#define	R367TER_CAS_DAGCGAIN	0xf090
-#define	F367TER_CAS_DAGC_GAIN	0xf09000ff
-
-/* SYR_CTL */
-#define	R367TER_SYR_CTL	0xf091
-#define	F367TER_SICTH_ENABLE	0xf0910080
-#define	F367TER_LONG_ECHO	0xf0910078
-#define	F367TER_AUTO_LE_EN	0xf0910004
-#define	F367TER_SYR_BYPASS	0xf0910002
-#define	F367TER_SYR_TR_DIS	0xf0910001
-
-/* SYR_STAT */
-#define	R367TER_SYR_STAT	0xf092
-#define	F367TER_SYR_LOCKED_STAT	0xf0920010
-#define	F367TER_SYR_MODE	0xf092000c
-#define	F367TER_SYR_GUARD	0xf0920003
-
-/* SYR_NCO1 */
-#define	R367TER_SYR_NCO1	0xf093
-#define	F367TER_SYR_NCO_LO	0xf09300ff
-
-/* SYR_NCO2 */
-#define	R367TER_SYR_NCO2	0xf094
-#define	F367TER_SYR_NCO_HI	0xf094003f
-
-/* SYR_OFFSET1 */
-#define	R367TER_SYR_OFFSET1	0xf095
-#define	F367TER_SYR_OFFSET_LO	0xf09500ff
-
-/* SYR_OFFSET2 */
-#define	R367TER_SYR_OFFSET2	0xf096
-#define	F367TER_SYR_OFFSET_HI	0xf096003f
-
-/* FFT_CTL */
-#define	R367TER_FFT_CTL	0xf097
-#define	F367TER_SHIFT_FFT_TRIG	0xf0970018
-#define	F367TER_FFT_TRIGGER	0xf0970004
-#define	F367TER_FFT_MANUAL	0xf0970002
-#define	F367TER_IFFT_MODE	0xf0970001
-
-/* SCR_CTL */
-#define	R367TER_SCR_CTL	0xf098
-#define	F367TER_SYRADJDECAY	0xf0980070
-#define	F367TER_SCR_CPEDIS	0xf0980002
-#define	F367TER_SCR_DIS	0xf0980001
-
-/* PPM_CTL1 */
-#define	R367TER_PPM_CTL1	0xf099
-#define	F367TER_PPM_MAXFREQ	0xf0990030
-#define	F367TER_PPM_MAXTIM	0xf0990008
-#define	F367TER_PPM_INVSEL	0xf0990004
-#define	F367TER_PPM_SCATDIS	0xf0990002
-#define	F367TER_PPM_BYP	0xf0990001
-
-/* TRL_CTL */
-#define	R367TER_TRL_CTL	0xf09a
-#define	F367TER_TRL_NOMRATE_LSB	0xf09a0080
-#define	F367TER_TRL_GAIN_FACTOR	0xf09a0078
-#define	F367TER_TRL_LOOPGAIN	0xf09a0007
-
-/* TRL_NOMRATE1 */
-#define	R367TER_TRL_NOMRATE1	0xf09b
-#define	F367TER_TRL_NOMRATE_LO	0xf09b00ff
-
-/* TRL_NOMRATE2 */
-#define	R367TER_TRL_NOMRATE2	0xf09c
-#define	F367TER_TRL_NOMRATE_HI	0xf09c00ff
-
-/* TRL_TIME1 */
-#define	R367TER_TRL_TIME1	0xf09d
-#define	F367TER_TRL_TOFFSET_LO	0xf09d00ff
-
-/* TRL_TIME2 */
-#define	R367TER_TRL_TIME2	0xf09e
-#define	F367TER_TRL_TOFFSET_HI	0xf09e00ff
-
-/* CRL_CTL */
-#define	R367TER_CRL_CTL	0xf09f
-#define	F367TER_CRL_DIS	0xf09f0080
-#define	F367TER_CRL_GAIN_FACTOR	0xf09f0078
-#define	F367TER_CRL_LOOPGAIN	0xf09f0007
-
-/* CRL_FREQ1 */
-#define	R367TER_CRL_FREQ1	0xf0a0
-#define	F367TER_CRL_FOFFSET_LO	0xf0a000ff
-
-/* CRL_FREQ2 */
-#define	R367TER_CRL_FREQ2	0xf0a1
-#define	F367TER_CRL_FOFFSET_HI	0xf0a100ff
-
-/* CRL_FREQ3 */
-#define	R367TER_CRL_FREQ3	0xf0a2
-#define	F367TER_CRL_FOFFSET_VHI	0xf0a200ff
-
-/* TPS_SFRAME_CTL */
-#define	R367TER_TPS_SFRAME_CTL	0xf0a3
-#define	F367TER_TPS_SFRAME_SYNC	0xf0a30001
-
-/* CHC_SNR */
-#define	R367TER_CHC_SNR	0xf0a4
-#define	F367TER_CHCSNR	0xf0a400ff
-
-/* BDI_CTL */
-#define	R367TER_BDI_CTL	0xf0a5
-#define	F367TER_BDI_LPSEL	0xf0a50002
-#define	F367TER_BDI_SERIAL	0xf0a50001
-
-/* DMP_CTL */
-#define	R367TER_DMP_CTL	0xf0a6
-#define	F367TER_DMP_SCALING_FACTOR	0xf0a6001e
-#define	F367TER_DMP_SDDIS	0xf0a60001
-
-/* TPS_RCVD1 */
-#define	R367TER_TPS_RCVD1	0xf0a7
-#define	F367TER_TPS_CHANGE	0xf0a70040
-#define	F367TER_BCH_OK	0xf0a70020
-#define	F367TER_TPS_SYNC	0xf0a70010
-#define	F367TER_TPS_FRAME	0xf0a70003
-
-/* TPS_RCVD2 */
-#define	R367TER_TPS_RCVD2	0xf0a8
-#define	F367TER_TPS_HIERMODE	0xf0a80070
-#define	F367TER_TPS_CONST	0xf0a80003
-
-/* TPS_RCVD3 */
-#define	R367TER_TPS_RCVD3	0xf0a9
-#define	F367TER_TPS_LPCODE	0xf0a90070
-#define	F367TER_TPS_HPCODE	0xf0a90007
-
-/* TPS_RCVD4 */
-#define	R367TER_TPS_RCVD4	0xf0aa
-#define	F367TER_TPS_GUARD	0xf0aa0030
-#define	F367TER_TPS_MODE	0xf0aa0003
-
-/* TPS_ID_CELL1 */
-#define	R367TER_TPS_ID_CELL1	0xf0ab
-#define	F367TER_TPS_ID_CELL_LO	0xf0ab00ff
-
-/* TPS_ID_CELL2 */
-#define	R367TER_TPS_ID_CELL2	0xf0ac
-#define	F367TER_TPS_ID_CELL_HI	0xf0ac00ff
-
-/* TPS_RCVD5_SET1 */
-#define	R367TER_TPS_RCVD5_SET1	0xf0ad
-#define	F367TER_TPS_NA	0xf0ad00fC
-#define	F367TER_TPS_SETFRAME	0xf0ad0003
-
-/* TPS_SET2 */
-#define	R367TER_TPS_SET2	0xf0ae
-#define	F367TER_TPS_SETHIERMODE	0xf0ae0070
-#define	F367TER_TPS_SETCONST	0xf0ae0003
-
-/* TPS_SET3 */
-#define	R367TER_TPS_SET3	0xf0af
-#define	F367TER_TPS_SETLPCODE	0xf0af0070
-#define	F367TER_TPS_SETHPCODE	0xf0af0007
-
-/* TPS_CTL */
-#define	R367TER_TPS_CTL	0xf0b0
-#define	F367TER_TPS_IMM	0xf0b00004
-#define	F367TER_TPS_BCHDIS	0xf0b00002
-#define	F367TER_TPS_UPDDIS	0xf0b00001
-
-/* CTL_FFTOSNUM */
-#define	R367TER_CTL_FFTOSNUM	0xf0b1
-#define	F367TER_SYMBOL_NUMBER	0xf0b1007f
-
-/* TESTSELECT */
-#define	R367TER_TESTSELECT	0xf0b2
-#define	F367TER_TEST_SELECT	0xf0b2001f
-
-/* MSC_REV */
-#define	R367TER_MSC_REV	0xf0b3
-#define	F367TER_REV_NUMBER	0xf0b300ff
-
-/* PIR_CTL */
-#define	R367TER_PIR_CTL	0xf0b4
-#define	F367TER_FREEZE	0xf0b40001
-
-/* SNR_CARRIER1 */
-#define	R367TER_SNR_CARRIER1	0xf0b5
-#define	F367TER_SNR_CARRIER_LO	0xf0b500ff
-
-/* SNR_CARRIER2 */
-#define	R367TER_SNR_CARRIER2	0xf0b6
-#define	F367TER_MEAN	0xf0b600c0
-#define	F367TER_SNR_CARRIER_HI	0xf0b6001f
-
-/* PPM_CPAMP */
-#define	R367TER_PPM_CPAMP	0xf0b7
-#define	F367TER_PPM_CPC	0xf0b700ff
-
-/* TSM_AP0 */
-#define	R367TER_TSM_AP0	0xf0b8
-#define	F367TER_ADDRESS_BYTE_0	0xf0b800ff
-
-/* TSM_AP1 */
-#define	R367TER_TSM_AP1	0xf0b9
-#define	F367TER_ADDRESS_BYTE_1	0xf0b900ff
-
-/* TSM_AP2 */
-#define	R367TER_TSM_AP2	0xf0bA
-#define	F367TER_DATA_BYTE_0	0xf0ba00ff
-
-/* TSM_AP3 */
-#define	R367TER_TSM_AP3	0xf0bB
-#define	F367TER_DATA_BYTE_1	0xf0bb00ff
-
-/* TSM_AP4 */
-#define	R367TER_TSM_AP4	0xf0bC
-#define	F367TER_DATA_BYTE_2	0xf0bc00ff
-
-/* TSM_AP5 */
-#define	R367TER_TSM_AP5	0xf0bD
-#define	F367TER_DATA_BYTE_3	0xf0bd00ff
-
-/* TSM_AP6 */
-#define	R367TER_TSM_AP6	0xf0bE
-#define	F367TER_TSM_AP_6	0xf0be00ff
-
-/* TSM_AP7 */
-#define	R367TER_TSM_AP7	0xf0bF
-#define	F367TER_MEM_SELECT_BYTE	0xf0bf00ff
-
-/* TSTRES */
-#define	R367TER_TSTRES	0xf0c0
-#define	F367TER_FRES_DISPLAY	0xf0c00080
-#define	F367TER_FRES_FIFO_AD	0xf0c00020
-#define	F367TER_FRESRS	0xf0c00010
-#define	F367TER_FRESACS	0xf0c00008
-#define	F367TER_FRESFEC	0xf0c00004
-#define	F367TER_FRES_PRIF	0xf0c00002
-#define	F367TER_FRESCORE	0xf0c00001
-
-/* ANACTRL */
-#define	R367TER_ANACTRL	0xf0c1
-#define	F367TER_BYPASS_XTAL	0xf0c10040
-#define	F367TER_BYPASS_PLLXN	0xf0c1000c
-#define	F367TER_DIS_PAD_OSC	0xf0c10002
-#define	F367TER_STDBY_PLLXN	0xf0c10001
-
-/* TSTBUS */
-#define	R367TER_TSTBUS	0xf0c2
-#define	F367TER_TS_BYTE_CLK_INV	0xf0c20080
-#define	F367TER_CFG_IP	0xf0c20070
-#define	F367TER_CFG_TST	0xf0c2000f
-
-/* TSTRATE */
-#define	R367TER_TSTRATE	0xf0c6
-#define	F367TER_FORCEPHA	0xf0c60080
-#define	F367TER_FNEWPHA	0xf0c60010
-#define	F367TER_FROT90	0xf0c60008
-#define	F367TER_FR	0xf0c60007
-
-/* CONSTMODE */
-#define	R367TER_CONSTMODE	0xf0cb
-#define	F367TER_TST_PRIF	0xf0cb00e0
-#define	F367TER_CAR_TYPE	0xf0cb0018
-#define	F367TER_CONST_MODE	0xf0cb0003
-
-/* CONSTCARR1 */
-#define	R367TER_CONSTCARR1	0xf0cc
-#define	F367TER_CONST_CARR_LO	0xf0cc00ff
-
-/* CONSTCARR2 */
-#define	R367TER_CONSTCARR2	0xf0cd
-#define	F367TER_CONST_CARR_HI	0xf0cd001f
-
-/* ICONSTEL */
-#define	R367TER_ICONSTEL	0xf0ce
-#define	F367TER_PICONSTEL	0xf0ce00ff
-
-/* QCONSTEL */
-#define	R367TER_QCONSTEL	0xf0cf
-#define	F367TER_PQCONSTEL	0xf0cf00ff
-
-/* TSTBISTRES0 */
-#define	R367TER_TSTBISTRES0	0xf0d0
-#define	F367TER_BEND_PPM	0xf0d00080
-#define	F367TER_BBAD_PPM	0xf0d00040
-#define	F367TER_BEND_FFTW	0xf0d00020
-#define	F367TER_BBAD_FFTW	0xf0d00010
-#define	F367TER_BEND_FFT_BUF	0xf0d00008
-#define	F367TER_BBAD_FFT_BUF	0xf0d00004
-#define	F367TER_BEND_SYR	0xf0d00002
-#define	F367TER_BBAD_SYR	0xf0d00001
-
-/* TSTBISTRES1 */
-#define	R367TER_TSTBISTRES1	0xf0d1
-#define	F367TER_BEND_CHC_CP	0xf0d10080
-#define	F367TER_BBAD_CHC_CP	0xf0d10040
-#define	F367TER_BEND_CHCI	0xf0d10020
-#define	F367TER_BBAD_CHCI	0xf0d10010
-#define	F367TER_BEND_BDI	0xf0d10008
-#define	F367TER_BBAD_BDI	0xf0d10004
-#define	F367TER_BEND_SDI	0xf0d10002
-#define	F367TER_BBAD_SDI	0xf0d10001
-
-/* TSTBISTRES2 */
-#define	R367TER_TSTBISTRES2	0xf0d2
-#define	F367TER_BEND_CHC_INC	0xf0d20080
-#define	F367TER_BBAD_CHC_INC	0xf0d20040
-#define	F367TER_BEND_CHC_SPP	0xf0d20020
-#define	F367TER_BBAD_CHC_SPP	0xf0d20010
-#define	F367TER_BEND_CHC_CPP	0xf0d20008
-#define	F367TER_BBAD_CHC_CPP	0xf0d20004
-#define	F367TER_BEND_CHC_SP	0xf0d20002
-#define	F367TER_BBAD_CHC_SP	0xf0d20001
-
-/* TSTBISTRES3 */
-#define	R367TER_TSTBISTRES3	0xf0d3
-#define	F367TER_BEND_QAM	0xf0d30080
-#define	F367TER_BBAD_QAM	0xf0d30040
-#define	F367TER_BEND_SFEC_VIT	0xf0d30020
-#define	F367TER_BBAD_SFEC_VIT	0xf0d30010
-#define	F367TER_BEND_SFEC_DLINE	0xf0d30008
-#define	F367TER_BBAD_SFEC_DLINE	0xf0d30004
-#define	F367TER_BEND_SFEC_HW	0xf0d30002
-#define	F367TER_BBAD_SFEC_HW	0xf0d30001
-
-/* RF_AGC1 */
-#define	R367TER_RF_AGC1	0xf0d4
-#define	F367TER_RF_AGC1_LEVEL_HI	0xf0d400ff
-
-/* RF_AGC2 */
-#define	R367TER_RF_AGC2	0xf0d5
-#define	F367TER_REF_ADGP	0xf0d50080
-#define	F367TER_STDBY_ADCGP	0xf0d50020
-#define	F367TER_CHANNEL_SEL	0xf0d5001c
-#define	F367TER_RF_AGC1_LEVEL_LO	0xf0d50003
-
-/* ANADIGCTRL */
-#define	R367TER_ANADIGCTRL	0xf0d7
-#define	F367TER_SEL_CLKDEM	0xf0d70020
-#define	F367TER_EN_BUFFER_Q	0xf0d70010
-#define	F367TER_EN_BUFFER_I	0xf0d70008
-#define	F367TER_ADC_RIS_EGDE	0xf0d70004
-#define	F367TER_SGN_ADC	0xf0d70002
-#define	F367TER_SEL_AD12_SYNC	0xf0d70001
-
-/* PLLMDIV */
-#define	R367TER_PLLMDIV	0xf0d8
-#define	F367TER_PLL_MDIV	0xf0d800ff
-
-/* PLLNDIV */
-#define	R367TER_PLLNDIV	0xf0d9
-#define	F367TER_PLL_NDIV	0xf0d900ff
-
-/* PLLSETUP */
-#define	R367TER_PLLSETUP	0xf0dA
-#define	F367TER_PLL_PDIV	0xf0da0070
-#define	F367TER_PLL_KDIV	0xf0da000f
-
-/* DUAL_AD12 */
-#define	R367TER_DUAL_AD12	0xf0dB
-#define	F367TER_FS20M	0xf0db0020
-#define	F367TER_FS50M	0xf0db0010
-#define	F367TER_INMODe0	0xf0db0008
-#define	F367TER_POFFQ	0xf0db0004
-#define	F367TER_POFFI	0xf0db0002
-#define	F367TER_INMODE1	0xf0db0001
-
-/* TSTBIST */
-#define	R367TER_TSTBIST	0xf0dC
-#define	F367TER_TST_BYP_CLK	0xf0dc0080
-#define	F367TER_TST_GCLKENA_STD	0xf0dc0040
-#define	F367TER_TST_GCLKENA	0xf0dc0020
-#define	F367TER_TST_MEMBIST	0xf0dc001f
-
-/* PAD_COMP_CTRL */
-#define	R367TER_PAD_COMP_CTRL	0xf0dD
-#define	F367TER_COMPTQ	0xf0dd0010
-#define	F367TER_COMPEN	0xf0dd0008
-#define	F367TER_FREEZE2	0xf0dd0004
-#define	F367TER_SLEEP_INHBT	0xf0dd0002
-#define	F367TER_CHIP_SLEEP	0xf0dd0001
-
-/* PAD_COMP_WR */
-#define	R367TER_PAD_COMP_WR	0xf0de
-#define	F367TER_WR_ASRC	0xf0de007f
-
-/* PAD_COMP_RD */
-#define	R367TER_PAD_COMP_RD	0xf0df
-#define	F367TER_COMPOK	0xf0df0080
-#define	F367TER_RD_ASRC	0xf0df007f
-
-/* SYR_TARGET_FFTADJT_MSB */
-#define	R367TER_SYR_TARGET_FFTADJT_MSB	0xf100
-#define	F367TER_SYR_START	0xf1000080
-#define	F367TER_SYR_TARGET_FFTADJ_HI	0xf100000f
-
-/* SYR_TARGET_FFTADJT_LSB */
-#define	R367TER_SYR_TARGET_FFTADJT_LSB	0xf101
-#define	F367TER_SYR_TARGET_FFTADJ_LO	0xf10100ff
-
-/* SYR_TARGET_CHCADJT_MSB */
-#define	R367TER_SYR_TARGET_CHCADJT_MSB	0xf102
-#define	F367TER_SYR_TARGET_CHCADJ_HI	0xf102000f
-
-/* SYR_TARGET_CHCADJT_LSB */
-#define	R367TER_SYR_TARGET_CHCADJT_LSB	0xf103
-#define	F367TER_SYR_TARGET_CHCADJ_LO	0xf10300ff
-
-/* SYR_FLAG */
-#define	R367TER_SYR_FLAG	0xf104
-#define	F367TER_TRIG_FLG1	0xf1040080
-#define	F367TER_TRIG_FLG0	0xf1040040
-#define	F367TER_FFT_FLG1	0xf1040008
-#define	F367TER_FFT_FLG0	0xf1040004
-#define	F367TER_CHC_FLG1	0xf1040002
-#define	F367TER_CHC_FLG0	0xf1040001
-
-/* CRL_TARGET1 */
-#define	R367TER_CRL_TARGET1	0xf105
-#define	F367TER_CRL_START	0xf1050080
-#define	F367TER_CRL_TARGET_VHI	0xf105000f
-
-/* CRL_TARGET2 */
-#define	R367TER_CRL_TARGET2	0xf106
-#define	F367TER_CRL_TARGET_HI	0xf10600ff
-
-/* CRL_TARGET3 */
-#define	R367TER_CRL_TARGET3	0xf107
-#define	F367TER_CRL_TARGET_LO	0xf10700ff
-
-/* CRL_TARGET4 */
-#define	R367TER_CRL_TARGET4	0xf108
-#define	F367TER_CRL_TARGET_VLO	0xf10800ff
-
-/* CRL_FLAG */
-#define	R367TER_CRL_FLAG	0xf109
-#define	F367TER_CRL_FLAG1	0xf1090002
-#define	F367TER_CRL_FLAG0	0xf1090001
-
-/* TRL_TARGET1 */
-#define	R367TER_TRL_TARGET1	0xf10a
-#define	F367TER_TRL_TARGET_HI	0xf10a00ff
-
-/* TRL_TARGET2 */
-#define	R367TER_TRL_TARGET2	0xf10b
-#define	F367TER_TRL_TARGET_LO	0xf10b00ff
-
-/* TRL_CHC */
-#define	R367TER_TRL_CHC	0xf10c
-#define	F367TER_TRL_START	0xf10c0080
-#define	F367TER_CHC_START	0xf10c0040
-#define	F367TER_TRL_FLAG1	0xf10c0002
-#define	F367TER_TRL_FLAG0	0xf10c0001
-
-/* CHC_SNR_TARG */
-#define	R367TER_CHC_SNR_TARG	0xf10d
-#define	F367TER_CHC_SNR_TARGET	0xf10d00ff
-
-/* TOP_TRACK */
-#define	R367TER_TOP_TRACK	0xf10e
-#define	F367TER_TOP_START	0xf10e0080
-#define	F367TER_FIRST_FLAG	0xf10e0070
-#define	F367TER_TOP_FLAG1	0xf10e0008
-#define	F367TER_TOP_FLAG0	0xf10e0004
-#define	F367TER_CHC_FLAG1	0xf10e0002
-#define	F367TER_CHC_FLAG0	0xf10e0001
-
-/* TRACKER_FREE1 */
-#define	R367TER_TRACKER_FREE1	0xf10f
-#define	F367TER_TRACKER_FREE_1	0xf10f00ff
-
-/* ERROR_CRL1 */
-#define	R367TER_ERROR_CRL1	0xf110
-#define	F367TER_ERROR_CRL_VHI	0xf11000ff
-
-/* ERROR_CRL2 */
-#define	R367TER_ERROR_CRL2	0xf111
-#define	F367TER_ERROR_CRL_HI	0xf11100ff
-
-/* ERROR_CRL3 */
-#define	R367TER_ERROR_CRL3	0xf112
-#define	F367TER_ERROR_CRL_LOI	0xf11200ff
-
-/* ERROR_CRL4 */
-#define	R367TER_ERROR_CRL4	0xf113
-#define	F367TER_ERROR_CRL_VLO	0xf11300ff
-
-/* DEC_NCO1 */
-#define	R367TER_DEC_NCO1	0xf114
-#define	F367TER_DEC_NCO_VHI	0xf11400ff
-
-/* DEC_NCO2 */
-#define	R367TER_DEC_NCO2	0xf115
-#define	F367TER_DEC_NCO_HI	0xf11500ff
-
-/* DEC_NCO3 */
-#define	R367TER_DEC_NCO3	0xf116
-#define	F367TER_DEC_NCO_LO	0xf11600ff
-
-/* SNR */
-#define	R367TER_SNR	0xf117
-#define	F367TER_SNRATIO	0xf11700ff
-
-/* SYR_FFTADJ1 */
-#define	R367TER_SYR_FFTADJ1	0xf118
-#define	F367TER_SYR_FFTADJ_HI	0xf11800ff
-
-/* SYR_FFTADJ2 */
-#define	R367TER_SYR_FFTADJ2	0xf119
-#define	F367TER_SYR_FFTADJ_LO	0xf11900ff
-
-/* SYR_CHCADJ1 */
-#define	R367TER_SYR_CHCADJ1	0xf11a
-#define	F367TER_SYR_CHCADJ_HI	0xf11a00ff
-
-/* SYR_CHCADJ2 */
-#define	R367TER_SYR_CHCADJ2	0xf11b
-#define	F367TER_SYR_CHCADJ_LO	0xf11b00ff
-
-/* SYR_OFF */
-#define	R367TER_SYR_OFF	0xf11c
-#define	F367TER_SYR_OFFSET	0xf11c00ff
-
-/* PPM_OFFSET1 */
-#define	R367TER_PPM_OFFSET1	0xf11d
-#define	F367TER_PPM_OFFSET_HI	0xf11d00ff
-
-/* PPM_OFFSET2 */
-#define	R367TER_PPM_OFFSET2	0xf11e
-#define	F367TER_PPM_OFFSET_LO	0xf11e00ff
-
-/* TRACKER_FREE2 */
-#define	R367TER_TRACKER_FREE2	0xf11f
-#define	F367TER_TRACKER_FREE_2	0xf11f00ff
-
-/* DEBG_LT10 */
-#define	R367TER_DEBG_LT10	0xf120
-#define	F367TER_DEBUG_LT10	0xf12000ff
-
-/* DEBG_LT11 */
-#define	R367TER_DEBG_LT11	0xf121
-#define	F367TER_DEBUG_LT11	0xf12100ff
-
-/* DEBG_LT12 */
-#define	R367TER_DEBG_LT12	0xf122
-#define	F367TER_DEBUG_LT12	0xf12200ff
-
-/* DEBG_LT13 */
-#define	R367TER_DEBG_LT13	0xf123
-#define	F367TER_DEBUG_LT13	0xf12300ff
-
-/* DEBG_LT14 */
-#define	R367TER_DEBG_LT14	0xf124
-#define	F367TER_DEBUG_LT14	0xf12400ff
-
-/* DEBG_LT15 */
-#define	R367TER_DEBG_LT15	0xf125
-#define	F367TER_DEBUG_LT15	0xf12500ff
-
-/* DEBG_LT16 */
-#define	R367TER_DEBG_LT16	0xf126
-#define	F367TER_DEBUG_LT16	0xf12600ff
-
-/* DEBG_LT17 */
-#define	R367TER_DEBG_LT17	0xf127
-#define	F367TER_DEBUG_LT17	0xf12700ff
-
-/* DEBG_LT18 */
-#define	R367TER_DEBG_LT18	0xf128
-#define	F367TER_DEBUG_LT18	0xf12800ff
-
-/* DEBG_LT19 */
-#define	R367TER_DEBG_LT19	0xf129
-#define	F367TER_DEBUG_LT19	0xf12900ff
-
-/* DEBG_LT1a */
-#define	R367TER_DEBG_LT1A	0xf12a
-#define	F367TER_DEBUG_LT1A	0xf12a00ff
-
-/* DEBG_LT1b */
-#define	R367TER_DEBG_LT1B	0xf12b
-#define	F367TER_DEBUG_LT1B	0xf12b00ff
-
-/* DEBG_LT1c */
-#define	R367TER_DEBG_LT1C	0xf12c
-#define	F367TER_DEBUG_LT1C	0xf12c00ff
-
-/* DEBG_LT1D */
-#define	R367TER_DEBG_LT1D	0xf12d
-#define	F367TER_DEBUG_LT1D	0xf12d00ff
-
-/* DEBG_LT1E */
-#define	R367TER_DEBG_LT1E	0xf12e
-#define	F367TER_DEBUG_LT1E	0xf12e00ff
-
-/* DEBG_LT1F */
-#define	R367TER_DEBG_LT1F	0xf12f
-#define	F367TER_DEBUG_LT1F	0xf12f00ff
-
-/* RCCFGH */
-#define	R367TER_RCCFGH	0xf200
-#define	F367TER_TSRCFIFO_DVBCI	0xf2000080
-#define	F367TER_TSRCFIFO_SERIAL	0xf2000040
-#define	F367TER_TSRCFIFO_DISABLE	0xf2000020
-#define	F367TER_TSFIFO_2TORC	0xf2000010
-#define	F367TER_TSRCFIFO_HSGNLOUT	0xf2000008
-#define	F367TER_TSRCFIFO_ERRMODE	0xf2000006
-#define	F367TER_RCCFGH_0	0xf2000001
-
-/* RCCFGM */
-#define	R367TER_RCCFGM	0xf201
-#define	F367TER_TSRCFIFO_MANSPEED	0xf20100c0
-#define	F367TER_TSRCFIFO_PERMDATA	0xf2010020
-#define	F367TER_TSRCFIFO_NONEWSGNL	0xf2010010
-#define	F367TER_RCBYTE_OVERSAMPLING	0xf201000e
-#define	F367TER_TSRCFIFO_INVDATA	0xf2010001
-
-/* RCCFGL */
-#define	R367TER_RCCFGL	0xf202
-#define	F367TER_TSRCFIFO_BCLKDEL1cK	0xf20200c0
-#define	F367TER_RCCFGL_5	0xf2020020
-#define	F367TER_TSRCFIFO_DUTY50	0xf2020010
-#define	F367TER_TSRCFIFO_NSGNL2dATA	0xf2020008
-#define	F367TER_TSRCFIFO_DISSERMUX	0xf2020004
-#define	F367TER_RCCFGL_1	0xf2020002
-#define	F367TER_TSRCFIFO_STOPCKDIS	0xf2020001
-
-/* RCINSDELH */
-#define	R367TER_RCINSDELH	0xf203
-#define	F367TER_TSRCDEL_SYNCBYTE	0xf2030080
-#define	F367TER_TSRCDEL_XXHEADER	0xf2030040
-#define	F367TER_TSRCDEL_BBHEADER	0xf2030020
-#define	F367TER_TSRCDEL_DATAFIELD	0xf2030010
-#define	F367TER_TSRCINSDEL_ISCR	0xf2030008
-#define	F367TER_TSRCINSDEL_NPD	0xf2030004
-#define	F367TER_TSRCINSDEL_RSPARITY	0xf2030002
-#define	F367TER_TSRCINSDEL_CRC8	0xf2030001
-
-/* RCINSDELM */
-#define	R367TER_RCINSDELM	0xf204
-#define	F367TER_TSRCINS_BBPADDING	0xf2040080
-#define	F367TER_TSRCINS_BCHFEC	0xf2040040
-#define	F367TER_TSRCINS_LDPCFEC	0xf2040020
-#define	F367TER_TSRCINS_EMODCOD	0xf2040010
-#define	F367TER_TSRCINS_TOKEN	0xf2040008
-#define	F367TER_TSRCINS_XXXERR	0xf2040004
-#define	F367TER_TSRCINS_MATYPE	0xf2040002
-#define	F367TER_TSRCINS_UPL	0xf2040001
-
-/* RCINSDELL */
-#define	R367TER_RCINSDELL	0xf205
-#define	F367TER_TSRCINS_DFL	0xf2050080
-#define	F367TER_TSRCINS_SYNCD	0xf2050040
-#define	F367TER_TSRCINS_BLOCLEN	0xf2050020
-#define	F367TER_TSRCINS_SIGPCOUNT	0xf2050010
-#define	F367TER_TSRCINS_FIFO	0xf2050008
-#define	F367TER_TSRCINS_REALPACK	0xf2050004
-#define	F367TER_TSRCINS_TSCONFIG	0xf2050002
-#define	F367TER_TSRCINS_LATENCY	0xf2050001
-
-/* RCSTATUS */
-#define	R367TER_RCSTATUS	0xf206
-#define	F367TER_TSRCFIFO_LINEOK	0xf2060080
-#define	F367TER_TSRCFIFO_ERROR	0xf2060040
-#define	F367TER_TSRCFIFO_DATA7	0xf2060020
-#define	F367TER_RCSTATUS_4	0xf2060010
-#define	F367TER_TSRCFIFO_DEMODSEL	0xf2060008
-#define	F367TER_TSRC1FIFOSPEED_STORE	0xf2060004
-#define	F367TER_RCSTATUS_1	0xf2060002
-#define	F367TER_TSRCSERIAL_IMPOSSIBLE	0xf2060001
-
-/* RCSPEED */
-#define	R367TER_RCSPEED	0xf207
-#define	F367TER_TSRCFIFO_OUTSPEED	0xf20700ff
-
-/* RCDEBUGM */
-#define	R367TER_RCDEBUGM	0xf208
-#define	F367TER_SD_UNSYNC	0xf2080080
-#define	F367TER_ULFLOCK_DETECTM	0xf2080040
-#define	F367TER_SUL_SELECTOS	0xf2080020
-#define	F367TER_DILUL_NOSCRBLE	0xf2080010
-#define	F367TER_NUL_SCRB	0xf2080008
-#define	F367TER_UL_SCRB	0xf2080004
-#define	F367TER_SCRAULBAD	0xf2080002
-#define	F367TER_SCRAUL_UNSYNC	0xf2080001
-
-/* RCDEBUGL */
-#define	R367TER_RCDEBUGL	0xf209
-#define	F367TER_RS_ERR	0xf2090080
-#define	F367TER_LLFLOCK_DETECTM	0xf2090040
-#define	F367TER_NOT_SUL_SELECTOS	0xf2090020
-#define	F367TER_DILLL_NOSCRBLE	0xf2090010
-#define	F367TER_NLL_SCRB	0xf2090008
-#define	F367TER_LL_SCRB	0xf2090004
-#define	F367TER_SCRALLBAD	0xf2090002
-#define	F367TER_SCRALL_UNSYNC	0xf2090001
-
-/* RCOBSCFG */
-#define	R367TER_RCOBSCFG	0xf20a
-#define	F367TER_TSRCFIFO_OBSCFG	0xf20a00ff
-
-/* RCOBSM */
-#define	R367TER_RCOBSM	0xf20b
-#define	F367TER_TSRCFIFO_OBSDATA_HI	0xf20b00ff
-
-/* RCOBSL */
-#define	R367TER_RCOBSL	0xf20c
-#define	F367TER_TSRCFIFO_OBSDATA_LO	0xf20c00ff
-
-/* RCFECSPY */
-#define	R367TER_RCFECSPY	0xf210
-#define	F367TER_SPYRC_ENABLE	0xf2100080
-#define	F367TER_RCNO_SYNCBYTE	0xf2100040
-#define	F367TER_RCSERIAL_MODE	0xf2100020
-#define	F367TER_RCUNUSUAL_PACKET	0xf2100010
-#define	F367TER_BERRCMETER_DATAMODE	0xf210000c
-#define	F367TER_BERRCMETER_LMODE	0xf2100002
-#define	F367TER_BERRCMETER_RESET	0xf2100001
-
-/* RCFSPYCFG */
-#define	R367TER_RCFSPYCFG	0xf211
-#define	F367TER_FECSPYRC_INPUT	0xf21100c0
-#define	F367TER_RCRST_ON_ERROR	0xf2110020
-#define	F367TER_RCONE_SHOT	0xf2110010
-#define	F367TER_RCI2C_MODE	0xf211000c
-#define	F367TER_SPYRC_HSTERESIS	0xf2110003
-
-/* RCFSPYDATA */
-#define	R367TER_RCFSPYDATA	0xf212
-#define	F367TER_SPYRC_STUFFING	0xf2120080
-#define	F367TER_RCNOERR_PKTJITTER	0xf2120040
-#define	F367TER_SPYRC_CNULLPKT	0xf2120020
-#define	F367TER_SPYRC_OUTDATA_MODE	0xf212001f
-
-/* RCFSPYOUT */
-#define	R367TER_RCFSPYOUT	0xf213
-#define	F367TER_FSPYRC_DIRECT	0xf2130080
-#define	F367TER_RCFSPYOUT_6	0xf2130040
-#define	F367TER_SPYRC_OUTDATA_BUS	0xf2130038
-#define	F367TER_RCSTUFF_MODE	0xf2130007
-
-/* RCFSTATUS */
-#define	R367TER_RCFSTATUS	0xf214
-#define	F367TER_SPYRC_ENDSIM	0xf2140080
-#define	F367TER_RCVALID_SIM	0xf2140040
-#define	F367TER_RCFOUND_SIGNAL	0xf2140020
-#define	F367TER_RCDSS_SYNCBYTE	0xf2140010
-#define	F367TER_RCRESULT_STATE	0xf214000f
-
-/* RCFGOODPACK */
-#define	R367TER_RCFGOODPACK	0xf215
-#define	F367TER_RCGOOD_PACKET	0xf21500ff
-
-/* RCFPACKCNT */
-#define	R367TER_RCFPACKCNT	0xf216
-#define	F367TER_RCPACKET_COUNTER	0xf21600ff
-
-/* RCFSPYMISC */
-#define	R367TER_RCFSPYMISC	0xf217
-#define	F367TER_RCLABEL_COUNTER	0xf21700ff
-
-/* RCFBERCPT4 */
-#define	R367TER_RCFBERCPT4	0xf218
-#define	F367TER_FBERRCMETER_CPT_MMMMSB	0xf21800ff
-
-/* RCFBERCPT3 */
-#define	R367TER_RCFBERCPT3	0xf219
-#define	F367TER_FBERRCMETER_CPT_MMMSB	0xf21900ff
-
-/* RCFBERCPT2 */
-#define	R367TER_RCFBERCPT2	0xf21a
-#define	F367TER_FBERRCMETER_CPT_MMSB	0xf21a00ff
-
-/* RCFBERCPT1 */
-#define	R367TER_RCFBERCPT1	0xf21b
-#define	F367TER_FBERRCMETER_CPT_MSB	0xf21b00ff
-
-/* RCFBERCPT0 */
-#define	R367TER_RCFBERCPT0	0xf21c
-#define	F367TER_FBERRCMETER_CPT_LSB	0xf21c00ff
-
-/* RCFBERERR2 */
-#define	R367TER_RCFBERERR2	0xf21d
-#define	F367TER_FBERRCMETER_ERR_HI	0xf21d00ff
-
-/* RCFBERERR1 */
-#define	R367TER_RCFBERERR1	0xf21e
-#define	F367TER_FBERRCMETER_ERR	0xf21e00ff
-
-/* RCFBERERR0 */
-#define	R367TER_RCFBERERR0	0xf21f
-#define	F367TER_FBERRCMETER_ERR_LO	0xf21f00ff
-
-/* RCFSTATESM */
-#define	R367TER_RCFSTATESM	0xf220
-#define	F367TER_RCRSTATE_F	0xf2200080
-#define	F367TER_RCRSTATE_E	0xf2200040
-#define	F367TER_RCRSTATE_D	0xf2200020
-#define	F367TER_RCRSTATE_C	0xf2200010
-#define	F367TER_RCRSTATE_B	0xf2200008
-#define	F367TER_RCRSTATE_A	0xf2200004
-#define	F367TER_RCRSTATE_9	0xf2200002
-#define	F367TER_RCRSTATE_8	0xf2200001
-
-/* RCFSTATESL */
-#define	R367TER_RCFSTATESL	0xf221
-#define	F367TER_RCRSTATE_7	0xf2210080
-#define	F367TER_RCRSTATE_6	0xf2210040
-#define	F367TER_RCRSTATE_5	0xf2210020
-#define	F367TER_RCRSTATE_4	0xf2210010
-#define	F367TER_RCRSTATE_3	0xf2210008
-#define	F367TER_RCRSTATE_2	0xf2210004
-#define	F367TER_RCRSTATE_1	0xf2210002
-#define	F367TER_RCRSTATE_0	0xf2210001
-
-/* RCFSPYBER */
-#define	R367TER_RCFSPYBER	0xf222
-#define	F367TER_RCFSPYBER_7	0xf2220080
-#define	F367TER_SPYRCOBS_XORREAD	0xf2220040
-#define	F367TER_FSPYRCBER_OBSMODE	0xf2220020
-#define	F367TER_FSPYRCBER_SYNCBYT	0xf2220010
-#define	F367TER_FSPYRCBER_UNSYNC	0xf2220008
-#define	F367TER_FSPYRCBER_CTIME	0xf2220007
-
-/* RCFSPYDISTM */
-#define	R367TER_RCFSPYDISTM	0xf223
-#define	F367TER_RCPKTTIME_DISTANCE_HI	0xf22300ff
-
-/* RCFSPYDISTL */
-#define	R367TER_RCFSPYDISTL	0xf224
-#define	F367TER_RCPKTTIME_DISTANCE_LO	0xf22400ff
-
-/* RCFSPYOBS7 */
-#define	R367TER_RCFSPYOBS7	0xf228
-#define	F367TER_RCSPYOBS_SPYFAIL	0xf2280080
-#define	F367TER_RCSPYOBS_SPYFAIL1	0xf2280040
-#define	F367TER_RCSPYOBS_ERROR	0xf2280020
-#define	F367TER_RCSPYOBS_STROUT	0xf2280010
-#define	F367TER_RCSPYOBS_RESULTSTATE1	0xf228000f
-
-/* RCFSPYOBS6 */
-#define	R367TER_RCFSPYOBS6	0xf229
-#define	F367TER_RCSPYOBS_RESULTSTATe0	0xf22900f0
-#define	F367TER_RCSPYOBS_RESULTSTATEM1	0xf229000f
-
-/* RCFSPYOBS5 */
-#define	R367TER_RCFSPYOBS5	0xf22a
-#define	F367TER_RCSPYOBS_BYTEOFPACKET1	0xf22a00ff
-
-/* RCFSPYOBS4 */
-#define	R367TER_RCFSPYOBS4	0xf22b
-#define	F367TER_RCSPYOBS_BYTEVALUE1	0xf22b00ff
-
-/* RCFSPYOBS3 */
-#define	R367TER_RCFSPYOBS3	0xf22c
-#define	F367TER_RCSPYOBS_DATA1	0xf22c00ff
-
-/* RCFSPYOBS2 */
-#define	R367TER_RCFSPYOBS2	0xf22d
-#define	F367TER_RCSPYOBS_DATa0	0xf22d00ff
-
-/* RCFSPYOBS1 */
-#define	R367TER_RCFSPYOBS1	0xf22e
-#define	F367TER_RCSPYOBS_DATAM1	0xf22e00ff
-
-/* RCFSPYOBS0 */
-#define	R367TER_RCFSPYOBS0	0xf22f
-#define	F367TER_RCSPYOBS_DATAM2	0xf22f00ff
-
-/* TSGENERAL */
-#define	R367TER_TSGENERAL	0xf230
-#define	F367TER_TSGENERAL_7	0xf2300080
-#define	F367TER_TSGENERAL_6	0xf2300040
-#define	F367TER_TSFIFO_BCLK1aLL	0xf2300020
-#define	F367TER_TSGENERAL_4	0xf2300010
-#define	F367TER_MUXSTREAM_OUTMODE	0xf2300008
-#define	F367TER_TSFIFO_PERMPARAL	0xf2300006
-#define	F367TER_RST_REEDSOLO	0xf2300001
-
-/* RC1SPEED */
-#define	R367TER_RC1SPEED	0xf231
-#define	F367TER_TSRCFIFO1_OUTSPEED	0xf23100ff
-
-/* TSGSTATUS */
-#define	R367TER_TSGSTATUS	0xf232
-#define	F367TER_TSGSTATUS_7	0xf2320080
-#define	F367TER_TSGSTATUS_6	0xf2320040
-#define	F367TER_RSMEM_FULL	0xf2320020
-#define	F367TER_RS_MULTCALC	0xf2320010
-#define	F367TER_RSIN_OVERTIME	0xf2320008
-#define	F367TER_TSFIFO3_DEMODSEL	0xf2320004
-#define	F367TER_TSFIFO2_DEMODSEL	0xf2320002
-#define	F367TER_TSFIFO1_DEMODSEL	0xf2320001
-
-
-/* FECM */
-#define	R367TER_FECM	0xf233
-#define	F367TER_DSS_DVB	0xf2330080
-#define	F367TER_DEMOD_BYPASS	0xf2330040
-#define	F367TER_CMP_SLOWMODE	0xf2330020
-#define	F367TER_DSS_SRCH	0xf2330010
-#define	F367TER_FECM_3	0xf2330008
-#define	F367TER_DIFF_MODEVIT	0xf2330004
-#define	F367TER_SYNCVIT	0xf2330002
-#define	F367TER_I2CSYM	0xf2330001
-
-/* VTH12 */
-#define	R367TER_VTH12	0xf234
-#define	F367TER_VTH_12	0xf23400ff
-
-/* VTH23 */
-#define	R367TER_VTH23	0xf235
-#define	F367TER_VTH_23	0xf23500ff
-
-/* VTH34 */
-#define	R367TER_VTH34	0xf236
-#define	F367TER_VTH_34	0xf23600ff
-
-/* VTH56 */
-#define	R367TER_VTH56	0xf237
-#define	F367TER_VTH_56	0xf23700ff
-
-/* VTH67 */
-#define	R367TER_VTH67	0xf238
-#define	F367TER_VTH_67	0xf23800ff
-
-/* VTH78 */
-#define	R367TER_VTH78	0xf239
-#define	F367TER_VTH_78	0xf23900ff
-
-/* VITCURPUN */
-#define	R367TER_VITCURPUN	0xf23a
-#define	F367TER_VIT_MAPPING	0xf23a00e0
-#define	F367TER_VIT_CURPUN	0xf23a001f
-
-/* VERROR */
-#define	R367TER_VERROR	0xf23b
-#define	F367TER_REGERR_VIT	0xf23b00ff
-
-/* PRVIT */
-#define	R367TER_PRVIT	0xf23c
-#define	F367TER_PRVIT_7	0xf23c0080
-#define	F367TER_DIS_VTHLOCK	0xf23c0040
-#define	F367TER_E7_8VIT	0xf23c0020
-#define	F367TER_E6_7VIT	0xf23c0010
-#define	F367TER_E5_6VIT	0xf23c0008
-#define	F367TER_E3_4VIT	0xf23c0004
-#define	F367TER_E2_3VIT	0xf23c0002
-#define	F367TER_E1_2VIT	0xf23c0001
-
-/* VAVSRVIT */
-#define	R367TER_VAVSRVIT	0xf23d
-#define	F367TER_AMVIT	0xf23d0080
-#define	F367TER_FROZENVIT	0xf23d0040
-#define	F367TER_SNVIT	0xf23d0030
-#define	F367TER_TOVVIT	0xf23d000c
-#define	F367TER_HYPVIT	0xf23d0003
-
-/* VSTATUSVIT */
-#define	R367TER_VSTATUSVIT	0xf23e
-#define	F367TER_VITERBI_ON	0xf23e0080
-#define	F367TER_END_LOOPVIT	0xf23e0040
-#define	F367TER_VITERBI_DEPRF	0xf23e0020
-#define	F367TER_PRFVIT	0xf23e0010
-#define	F367TER_LOCKEDVIT	0xf23e0008
-#define	F367TER_VITERBI_DELOCK	0xf23e0004
-#define	F367TER_VIT_DEMODSEL	0xf23e0002
-#define	F367TER_VITERBI_COMPOUT	0xf23e0001
-
-/* VTHINUSE */
-#define	R367TER_VTHINUSE	0xf23f
-#define	F367TER_VIT_INUSE	0xf23f00ff
-
-/* KDIV12 */
-#define	R367TER_KDIV12	0xf240
-#define	F367TER_KDIV12_MANUAL	0xf2400080
-#define	F367TER_K_DIVIDER_12	0xf240007f
-
-/* KDIV23 */
-#define	R367TER_KDIV23	0xf241
-#define	F367TER_KDIV23_MANUAL	0xf2410080
-#define	F367TER_K_DIVIDER_23	0xf241007f
-
-/* KDIV34 */
-#define	R367TER_KDIV34	0xf242
-#define	F367TER_KDIV34_MANUAL	0xf2420080
-#define	F367TER_K_DIVIDER_34	0xf242007f
-
-/* KDIV56 */
-#define	R367TER_KDIV56	0xf243
-#define	F367TER_KDIV56_MANUAL	0xf2430080
-#define	F367TER_K_DIVIDER_56	0xf243007f
-
-/* KDIV67 */
-#define	R367TER_KDIV67	0xf244
-#define	F367TER_KDIV67_MANUAL	0xf2440080
-#define	F367TER_K_DIVIDER_67	0xf244007f
-
-/* KDIV78 */
-#define	R367TER_KDIV78	0xf245
-#define	F367TER_KDIV78_MANUAL	0xf2450080
-#define	F367TER_K_DIVIDER_78	0xf245007f
-
-/* SIGPOWER */
-#define	R367TER_SIGPOWER	0xf246
-#define	F367TER_SIGPOWER_MANUAL	0xf2460080
-#define	F367TER_SIG_POWER	0xf246007f
-
-/* DEMAPVIT */
-#define	R367TER_DEMAPVIT	0xf247
-#define	F367TER_DEMAPVIT_7	0xf2470080
-#define	F367TER_K_DIVIDER_VIT	0xf247007f
-
-/* VITSCALE */
-#define	R367TER_VITSCALE	0xf248
-#define	F367TER_NVTH_NOSRANGE	0xf2480080
-#define	F367TER_VERROR_MAXMODE	0xf2480040
-#define	F367TER_KDIV_MODE	0xf2480030
-#define	F367TER_NSLOWSN_LOCKED	0xf2480008
-#define	F367TER_DELOCK_PRFLOSS	0xf2480004
-#define	F367TER_DIS_RSFLOCK	0xf2480002
-#define	F367TER_VITSCALE_0	0xf2480001
-
-/* FFEC1PRG */
-#define	R367TER_FFEC1PRG	0xf249
-#define	F367TER_FDSS_DVB	0xf2490080
-#define	F367TER_FDSS_SRCH	0xf2490040
-#define	F367TER_FFECPROG_5	0xf2490020
-#define	F367TER_FFECPROG_4	0xf2490010
-#define	F367TER_FFECPROG_3	0xf2490008
-#define	F367TER_FFECPROG_2	0xf2490004
-#define	F367TER_FTS1_DISABLE	0xf2490002
-#define	F367TER_FTS2_DISABLE	0xf2490001
-
-/* FVITCURPUN */
-#define	R367TER_FVITCURPUN	0xf24a
-#define	F367TER_FVIT_MAPPING	0xf24a00e0
-#define	F367TER_FVIT_CURPUN	0xf24a001f
-
-/* FVERROR */
-#define	R367TER_FVERROR	0xf24b
-#define	F367TER_FREGERR_VIT	0xf24b00ff
-
-/* FVSTATUSVIT */
-#define	R367TER_FVSTATUSVIT	0xf24c
-#define	F367TER_FVITERBI_ON	0xf24c0080
-#define	F367TER_F1END_LOOPVIT	0xf24c0040
-#define	F367TER_FVITERBI_DEPRF	0xf24c0020
-#define	F367TER_FPRFVIT	0xf24c0010
-#define	F367TER_FLOCKEDVIT	0xf24c0008
-#define	F367TER_FVITERBI_DELOCK	0xf24c0004
-#define	F367TER_FVIT_DEMODSEL	0xf24c0002
-#define	F367TER_FVITERBI_COMPOUT	0xf24c0001
-
-/* DEBUG_LT1 */
-#define	R367TER_DEBUG_LT1	0xf24d
-#define	F367TER_DBG_LT1	0xf24d00ff
-
-/* DEBUG_LT2 */
-#define	R367TER_DEBUG_LT2	0xf24e
-#define	F367TER_DBG_LT2	0xf24e00ff
-
-/* DEBUG_LT3 */
-#define	R367TER_DEBUG_LT3	0xf24f
-#define	F367TER_DBG_LT3	0xf24f00ff
-
-/*	TSTSFMET */
-#define	R367TER_TSTSFMET	0xf250
-#define F367TER_TSTSFEC_METRIQUES	0xf25000ff
-
-/*	SELOUT */
-#define	R367TER_SELOUT	0xf252
-#define	F367TER_EN_SYNC	0xf2520080
-#define	F367TER_EN_TBUSDEMAP	0xf2520040
-#define	F367TER_SELOUT_5	0xf2520020
-#define	F367TER_SELOUT_4	0xf2520010
-#define	F367TER_TSTSYNCHRO_MODE	0xf2520002
-
-/*	TSYNC */
-#define R367TER_TSYNC	0xf253
-#define F367TER_CURPUN_INCMODE	0xf2530080
-#define F367TER_CERR_TSTMODE	0xf2530040
-#define F367TER_SHIFTSOF_MODE	0xf2530030
-#define F367TER_SLOWPHA_MODE	0xf2530008
-#define F367TER_PXX_BYPALL	0xf2530004
-#define F367TER_FROTA45_FIRST	0xf2530002
-#define F367TER_TST_BCHERROR	0xf2530001
-
-/*	TSTERR */
-#define R367TER_TSTERR	0xf254
-#define F367TER_TST_LONGPKT	0xf2540080
-#define F367TER_TST_ISSYION	0xf2540040
-#define F367TER_TST_NPDON	0xf2540020
-#define F367TER_TSTERR_4	0xf2540010
-#define F367TER_TRACEBACK_MODE	0xf2540008
-#define F367TER_TST_RSPARITY	0xf2540004
-#define F367TER_METRIQUE_MODE	0xf2540003
-
-/*	TSFSYNC */
-#define R367TER_TSFSYNC	0xf255
-#define F367TER_EN_SFECSYNC	0xf2550080
-#define F367TER_EN_SFECDEMAP	0xf2550040
-#define F367TER_SFCERR_TSTMODE	0xf2550020
-#define F367TER_SFECPXX_BYPALL	0xf2550010
-#define F367TER_SFECTSTSYNCHRO_MODE 0xf255000f
-
-/*	TSTSFERR */
-#define R367TER_TSTSFERR	0xf256
-#define F367TER_TSTSTERR_7	0xf2560080
-#define F367TER_TSTSTERR_6	0xf2560040
-#define F367TER_TSTSTERR_5	0xf2560020
-#define F367TER_TSTSTERR_4	0xf2560010
-#define F367TER_SFECTRACEBACK_MODE	0xf2560008
-#define F367TER_SFEC_NCONVPROG	0xf2560004
-#define F367TER_SFECMETRIQUE_MODE	0xf2560003
-
-/*	TSTTSSF1 */
-#define R367TER_TSTTSSF1	0xf258
-#define F367TER_TSTERSSF	0xf2580080
-#define F367TER_TSTTSSFEN	0xf2580040
-#define F367TER_SFEC_OUTMODE	0xf2580030
-#define F367TER_XLSF_NOFTHRESHOLD  0xf2580008
-#define F367TER_TSTTSSF_STACKSEL	0xf2580007
-
-/*	TSTTSSF2 */
-#define R367TER_TSTTSSF2	0xf259
-#define F367TER_DILSF_DBBHEADER	0xf2590080
-#define F367TER_TSTTSSF_DISBUG	0xf2590040
-#define F367TER_TSTTSSF_NOBADSTART	0xf2590020
-#define F367TER_TSTTSSF_SELECT	0xf259001f
-
-/*	TSTTSSF3 */
-#define R367TER_TSTTSSF3	0xf25a
-#define F367TER_TSTTSSF3_7	0xf25a0080
-#define F367TER_TSTTSSF3_6	0xf25a0040
-#define F367TER_TSTTSSF3_5	0xf25a0020
-#define F367TER_TSTTSSF3_4	0xf25a0010
-#define F367TER_TSTTSSF3_3	0xf25a0008
-#define F367TER_TSTTSSF3_2	0xf25a0004
-#define F367TER_TSTTSSF3_1	0xf25a0002
-#define F367TER_DISSF_CLKENABLE	0xf25a0001
-
-/*	TSTTS1 */
-#define R367TER_TSTTS1	0xf25c
-#define F367TER_TSTERS	0xf25c0080
-#define F367TER_TSFIFO_DSSSYNCB	0xf25c0040
-#define F367TER_TSTTS_FSPYBEFRS	0xf25c0020
-#define F367TER_NFORCE_SYNCBYTE	0xf25c0010
-#define F367TER_XL_NOFTHRESHOLD	0xf25c0008
-#define F367TER_TSTTS_FRFORCEPKT	0xf25c0004
-#define F367TER_DESCR_NOTAUTO	0xf25c0002
-#define F367TER_TSTTSEN	0xf25c0001
-
-/*	TSTTS2 */
-#define R367TER_TSTTS2	0xf25d
-#define F367TER_DIL_DBBHEADER	0xf25d0080
-#define F367TER_TSTTS_NOBADXXX	0xf25d0040
-#define F367TER_TSFIFO_DELSPEEDUP	0xf25d0020
-#define F367TER_TSTTS_SELECT	0xf25d001f
-
-/*	TSTTS3 */
-#define R367TER_TSTTS3	0xf25e
-#define F367TER_TSTTS_NOPKTGAIN	0xf25e0080
-#define F367TER_TSTTS_NOPKTENE	0xf25e0040
-#define F367TER_TSTTS_ISOLATION	0xf25e0020
-#define F367TER_TSTTS_DISBUG	0xf25e0010
-#define F367TER_TSTTS_NOBADSTART	0xf25e0008
-#define F367TER_TSTTS_STACKSEL	0xf25e0007
-
-/*	TSTTS4 */
-#define R367TER_TSTTS4	0xf25f
-#define F367TER_TSTTS4_7	0xf25f0080
-#define F367TER_TSTTS4_6	0xf25f0040
-#define F367TER_TSTTS4_5	0xf25f0020
-#define F367TER_TSTTS_DISDSTATE	0xf25f0010
-#define F367TER_TSTTS_FASTNOSYNC	0xf25f0008
-#define F367TER_EXT_FECSPYIN	0xf25f0004
-#define F367TER_TSTTS_NODPZERO	0xf25f0002
-#define F367TER_TSTTS_NODIV3	0xf25f0001
-
-/*	TSTTSRC */
-#define R367TER_TSTTSRC	0xf26c
-#define F367TER_TSTTSRC_7	0xf26c0080
-#define F367TER_TSRCFIFO_DSSSYNCB	0xf26c0040
-#define F367TER_TSRCFIFO_DPUNACTIVE	0xf26c0020
-#define F367TER_TSRCFIFO_DELSPEEDUP	0xf26c0010
-#define F367TER_TSTTSRC_NODIV3	0xf26c0008
-#define F367TER_TSTTSRC_FRFORCEPKT	0xf26c0004
-#define F367TER_SAT25_SDDORIGINE	0xf26c0002
-#define F367TER_TSTTSRC_INACTIVE	0xf26c0001
-
-/*	TSTTSRS */
-#define R367TER_TSTTSRS	0xf26d
-#define F367TER_TSTTSRS_7	0xf26d0080
-#define F367TER_TSTTSRS_6	0xf26d0040
-#define F367TER_TSTTSRS_5	0xf26d0020
-#define F367TER_TSTTSRS_4	0xf26d0010
-#define F367TER_TSTTSRS_3	0xf26d0008
-#define F367TER_TSTTSRS_2	0xf26d0004
-#define F367TER_TSTRS_DISRS2	0xf26d0002
-#define F367TER_TSTRS_DISRS1	0xf26d0001
-
-/* TSSTATEM */
-#define	R367TER_TSSTATEM	0xf270
-#define	F367TER_TSDIL_ON	0xf2700080
-#define	F367TER_TSSKIPRS_ON	0xf2700040
-#define	F367TER_TSRS_ON	0xf2700020
-#define	F367TER_TSDESCRAMB_ON	0xf2700010
-#define	F367TER_TSFRAME_MODE	0xf2700008
-#define	F367TER_TS_DISABLE	0xf2700004
-#define	F367TER_TSACM_MODE	0xf2700002
-#define	F367TER_TSOUT_NOSYNC	0xf2700001
-
-/* TSSTATEL */
-#define	R367TER_TSSTATEL	0xf271
-#define	F367TER_TSNOSYNCBYTE	0xf2710080
-#define	F367TER_TSPARITY_ON	0xf2710040
-#define	F367TER_TSSYNCOUTRS_ON	0xf2710020
-#define	F367TER_TSDVBS2_MODE	0xf2710010
-#define	F367TER_TSISSYI_ON	0xf2710008
-#define	F367TER_TSNPD_ON	0xf2710004
-#define	F367TER_TSCRC8_ON	0xf2710002
-#define	F367TER_TSDSS_PACKET	0xf2710001
-
-/* TSCFGH */
-#define	R367TER_TSCFGH	0xf272
-#define	F367TER_TSFIFO_DVBCI	0xf2720080
-#define	F367TER_TSFIFO_SERIAL	0xf2720040
-#define	F367TER_TSFIFO_TEIUPDATE	0xf2720020
-#define	F367TER_TSFIFO_DUTY50	0xf2720010
-#define	F367TER_TSFIFO_HSGNLOUT	0xf2720008
-#define	F367TER_TSFIFO_ERRMODE	0xf2720006
-#define	F367TER_RST_HWARE	0xf2720001
-
-/* TSCFGM */
-#define	R367TER_TSCFGM	0xf273
-#define	F367TER_TSFIFO_MANSPEED	0xf27300c0
-#define	F367TER_TSFIFO_PERMDATA	0xf2730020
-#define	F367TER_TSFIFO_NONEWSGNL	0xf2730010
-#define	F367TER_TSFIFO_BITSPEED	0xf2730008
-#define	F367TER_NPD_SPECDVBS2	0xf2730004
-#define	F367TER_TSFIFO_STOPCKDIS	0xf2730002
-#define	F367TER_TSFIFO_INVDATA	0xf2730001
-
-/* TSCFGL */
-#define	R367TER_TSCFGL	0xf274
-#define	F367TER_TSFIFO_BCLKDEL1cK	0xf27400c0
-#define	F367TER_BCHERROR_MODE	0xf2740030
-#define	F367TER_TSFIFO_NSGNL2dATA	0xf2740008
-#define	F367TER_TSFIFO_EMBINDVB	0xf2740004
-#define	F367TER_TSFIFO_DPUNACT	0xf2740002
-#define	F367TER_TSFIFO_NPDOFF	0xf2740001
-
-/* TSSYNC */
-#define	R367TER_TSSYNC	0xf275
-#define	F367TER_TSFIFO_PERMUTE	0xf2750080
-#define	F367TER_TSFIFO_FISCR3B	0xf2750060
-#define	F367TER_TSFIFO_SYNCMODE	0xf2750018
-#define	F367TER_TSFIFO_SYNCSEL	0xf2750007
-
-/* TSINSDELH */
-#define	R367TER_TSINSDELH	0xf276
-#define	F367TER_TSDEL_SYNCBYTE	0xf2760080
-#define	F367TER_TSDEL_XXHEADER	0xf2760040
-#define	F367TER_TSDEL_BBHEADER	0xf2760020
-#define	F367TER_TSDEL_DATAFIELD	0xf2760010
-#define	F367TER_TSINSDEL_ISCR	0xf2760008
-#define	F367TER_TSINSDEL_NPD	0xf2760004
-#define	F367TER_TSINSDEL_RSPARITY	0xf2760002
-#define	F367TER_TSINSDEL_CRC8	0xf2760001
-
-/* TSINSDELM */
-#define	R367TER_TSINSDELM	0xf277
-#define	F367TER_TSINS_BBPADDING	0xf2770080
-#define	F367TER_TSINS_BCHFEC	0xf2770040
-#define	F367TER_TSINS_LDPCFEC	0xf2770020
-#define	F367TER_TSINS_EMODCOD	0xf2770010
-#define	F367TER_TSINS_TOKEN	0xf2770008
-#define	F367TER_TSINS_XXXERR	0xf2770004
-#define	F367TER_TSINS_MATYPE	0xf2770002
-#define	F367TER_TSINS_UPL	0xf2770001
-
-/* TSINSDELL */
-#define	R367TER_TSINSDELL	0xf278
-#define	F367TER_TSINS_DFL	0xf2780080
-#define	F367TER_TSINS_SYNCD	0xf2780040
-#define	F367TER_TSINS_BLOCLEN	0xf2780020
-#define	F367TER_TSINS_SIGPCOUNT	0xf2780010
-#define	F367TER_TSINS_FIFO	0xf2780008
-#define	F367TER_TSINS_REALPACK	0xf2780004
-#define	F367TER_TSINS_TSCONFIG	0xf2780002
-#define	F367TER_TSINS_LATENCY	0xf2780001
-
-/* TSDIVN */
-#define	R367TER_TSDIVN	0xf279
-#define	F367TER_TSFIFO_LOWSPEED	0xf2790080
-#define	F367TER_BYTE_OVERSAMPLING	0xf2790070
-#define	F367TER_TSMANUAL_PACKETNBR	0xf279000f
-
-/* TSDIVPM */
-#define	R367TER_TSDIVPM	0xf27a
-#define	F367TER_TSMANUAL_P_HI	0xf27a00ff
-
-/* TSDIVPL */
-#define	R367TER_TSDIVPL	0xf27b
-#define	F367TER_TSMANUAL_P_LO	0xf27b00ff
-
-/* TSDIVQM */
-#define	R367TER_TSDIVQM	0xf27c
-#define	F367TER_TSMANUAL_Q_HI	0xf27c00ff
-
-/* TSDIVQL */
-#define	R367TER_TSDIVQL	0xf27d
-#define	F367TER_TSMANUAL_Q_LO	0xf27d00ff
-
-/* TSDILSTKM */
-#define	R367TER_TSDILSTKM	0xf27e
-#define	F367TER_TSFIFO_DILSTK_HI	0xf27e00ff
-
-/* TSDILSTKL */
-#define	R367TER_TSDILSTKL	0xf27f
-#define	F367TER_TSFIFO_DILSTK_LO	0xf27f00ff
-
-/* TSSPEED */
-#define	R367TER_TSSPEED	0xf280
-#define	F367TER_TSFIFO_OUTSPEED	0xf28000ff
-
-/* TSSTATUS */
-#define	R367TER_TSSTATUS	0xf281
-#define	F367TER_TSFIFO_LINEOK	0xf2810080
-#define	F367TER_TSFIFO_ERROR	0xf2810040
-#define	F367TER_TSFIFO_DATA7	0xf2810020
-#define	F367TER_TSFIFO_NOSYNC	0xf2810010
-#define	F367TER_ISCR_INITIALIZED	0xf2810008
-#define	F367TER_ISCR_UPDATED	0xf2810004
-#define	F367TER_SOFFIFO_UNREGUL	0xf2810002
-#define	F367TER_DIL_READY	0xf2810001
-
-/* TSSTATUS2 */
-#define	R367TER_TSSTATUS2	0xf282
-#define	F367TER_TSFIFO_DEMODSEL	0xf2820080
-#define	F367TER_TSFIFOSPEED_STORE	0xf2820040
-#define	F367TER_DILXX_RESET	0xf2820020
-#define	F367TER_TSSERIAL_IMPOSSIBLE	0xf2820010
-#define	F367TER_TSFIFO_UNDERSPEED	0xf2820008
-#define	F367TER_BITSPEED_EVENT	0xf2820004
-#define	F367TER_UL_SCRAMBDETECT	0xf2820002
-#define	F367TER_ULDTV67_FALSELOCK	0xf2820001
-
-/* TSBITRATEM */
-#define	R367TER_TSBITRATEM	0xf283
-#define	F367TER_TSFIFO_BITRATE_HI	0xf28300ff
-
-/* TSBITRATEL */
-#define	R367TER_TSBITRATEL	0xf284
-#define	F367TER_TSFIFO_BITRATE_LO	0xf28400ff
-
-/* TSPACKLENM */
-#define	R367TER_TSPACKLENM	0xf285
-#define	F367TER_TSFIFO_PACKCPT	0xf28500e0
-#define	F367TER_DIL_RPLEN_HI	0xf285001f
-
-/* TSPACKLENL */
-#define	R367TER_TSPACKLENL	0xf286
-#define	F367TER_DIL_RPLEN_LO	0xf28600ff
-
-/* TSBLOCLENM */
-#define	R367TER_TSBLOCLENM	0xf287
-#define	F367TER_TSFIFO_PFLEN_HI	0xf28700ff
-
-/* TSBLOCLENL */
-#define	R367TER_TSBLOCLENL	0xf288
-#define	F367TER_TSFIFO_PFLEN_LO	0xf28800ff
-
-/* TSDLYH */
-#define	R367TER_TSDLYH	0xf289
-#define	F367TER_SOFFIFO_TSTIMEVALID	0xf2890080
-#define	F367TER_SOFFIFO_SPEEDUP	0xf2890040
-#define	F367TER_SOFFIFO_STOP	0xf2890020
-#define	F367TER_SOFFIFO_REGULATED	0xf2890010
-#define	F367TER_SOFFIFO_REALSBOFF_HI	0xf289000f
-
-/* TSDLYM */
-#define	R367TER_TSDLYM	0xf28a
-#define	F367TER_SOFFIFO_REALSBOFF_MED	0xf28a00ff
-
-/* TSDLYL */
-#define	R367TER_TSDLYL	0xf28b
-#define	F367TER_SOFFIFO_REALSBOFF_LO	0xf28b00ff
-
-/* TSNPDAV */
-#define	R367TER_TSNPDAV	0xf28c
-#define	F367TER_TSNPD_AVERAGE	0xf28c00ff
-
-/* TSBUFSTATH */
-#define	R367TER_TSBUFSTATH	0xf28d
-#define	F367TER_TSISCR_3BYTES	0xf28d0080
-#define	F367TER_TSISCR_NEWDATA	0xf28d0040
-#define	F367TER_TSISCR_BUFSTAT_HI	0xf28d003f
-
-/* TSBUFSTATM */
-#define	R367TER_TSBUFSTATM	0xf28e
-#define	F367TER_TSISCR_BUFSTAT_MED	0xf28e00ff
-
-/* TSBUFSTATL */
-#define	R367TER_TSBUFSTATL	0xf28f
-#define	F367TER_TSISCR_BUFSTAT_LO	0xf28f00ff
-
-/* TSDEBUGM */
-#define	R367TER_TSDEBUGM	0xf290
-#define	F367TER_TSFIFO_ILLPACKET	0xf2900080
-#define	F367TER_DIL_NOSYNC	0xf2900040
-#define	F367TER_DIL_ISCR	0xf2900020
-#define	F367TER_DILOUT_BSYNCB	0xf2900010
-#define	F367TER_TSFIFO_EMPTYPKT	0xf2900008
-#define	F367TER_TSFIFO_EMPTYRD	0xf2900004
-#define	F367TER_SOFFIFO_STOPM	0xf2900002
-#define	F367TER_SOFFIFO_SPEEDUPM	0xf2900001
-
-/* TSDEBUGL */
-#define	R367TER_TSDEBUGL	0xf291
-#define	F367TER_TSFIFO_PACKLENFAIL	0xf2910080
-#define	F367TER_TSFIFO_SYNCBFAIL	0xf2910040
-#define	F367TER_TSFIFO_VITLIBRE	0xf2910020
-#define	F367TER_TSFIFO_BOOSTSPEEDM	0xf2910010
-#define	F367TER_TSFIFO_UNDERSPEEDM	0xf2910008
-#define	F367TER_TSFIFO_ERROR_EVNT	0xf2910004
-#define	F367TER_TSFIFO_FULL	0xf2910002
-#define	F367TER_TSFIFO_OVERFLOWM	0xf2910001
-
-/* TSDLYSETH */
-#define	R367TER_TSDLYSETH	0xf292
-#define	F367TER_SOFFIFO_OFFSET	0xf29200e0
-#define	F367TER_SOFFIFO_SYMBOFFSET_HI	0xf292001f
-
-/* TSDLYSETM */
-#define	R367TER_TSDLYSETM	0xf293
-#define	F367TER_SOFFIFO_SYMBOFFSET_MED	0xf29300ff
-
-/* TSDLYSETL */
-#define	R367TER_TSDLYSETL	0xf294
-#define	F367TER_SOFFIFO_SYMBOFFSET_LO	0xf29400ff
-
-/* TSOBSCFG */
-#define	R367TER_TSOBSCFG	0xf295
-#define	F367TER_TSFIFO_OBSCFG	0xf29500ff
-
-/* TSOBSM */
-#define	R367TER_TSOBSM	0xf296
-#define	F367TER_TSFIFO_OBSDATA_HI	0xf29600ff
-
-/* TSOBSL */
-#define	R367TER_TSOBSL	0xf297
-#define	F367TER_TSFIFO_OBSDATA_LO	0xf29700ff
-
-/* ERRCTRL1 */
-#define	R367TER_ERRCTRL1	0xf298
-#define	F367TER_ERR_SRC1	0xf29800f0
-#define	F367TER_ERRCTRL1_3	0xf2980008
-#define	F367TER_NUM_EVT1	0xf2980007
-
-/* ERRCNT1H */
-#define	R367TER_ERRCNT1H	0xf299
-#define	F367TER_ERRCNT1_OLDVALUE	0xf2990080
-#define	F367TER_ERR_CNT1	0xf299007f
-
-/* ERRCNT1M */
-#define	R367TER_ERRCNT1M	0xf29a
-#define	F367TER_ERR_CNT1_HI	0xf29a00ff
-
-/* ERRCNT1L */
-#define	R367TER_ERRCNT1L	0xf29b
-#define	F367TER_ERR_CNT1_LO	0xf29b00ff
-
-/* ERRCTRL2 */
-#define	R367TER_ERRCTRL2	0xf29c
-#define	F367TER_ERR_SRC2	0xf29c00f0
-#define	F367TER_ERRCTRL2_3	0xf29c0008
-#define	F367TER_NUM_EVT2	0xf29c0007
-
-/* ERRCNT2H */
-#define	R367TER_ERRCNT2H	0xf29d
-#define	F367TER_ERRCNT2_OLDVALUE	0xf29d0080
-#define	F367TER_ERR_CNT2_HI	0xf29d007f
-
-/* ERRCNT2M */
-#define	R367TER_ERRCNT2M	0xf29e
-#define	F367TER_ERR_CNT2_MED	0xf29e00ff
-
-/* ERRCNT2L */
-#define	R367TER_ERRCNT2L	0xf29f
-#define	F367TER_ERR_CNT2_LO	0xf29f00ff
-
-/* FECSPY */
-#define	R367TER_FECSPY	0xf2a0
-#define	F367TER_SPY_ENABLE	0xf2a00080
-#define	F367TER_NO_SYNCBYTE	0xf2a00040
-#define	F367TER_SERIAL_MODE	0xf2a00020
-#define	F367TER_UNUSUAL_PACKET	0xf2a00010
-#define	F367TER_BERMETER_DATAMODE	0xf2a0000c
-#define	F367TER_BERMETER_LMODE	0xf2a00002
-#define	F367TER_BERMETER_RESET	0xf2a00001
-
-/* FSPYCFG */
-#define	R367TER_FSPYCFG	0xf2a1
-#define	F367TER_FECSPY_INPUT	0xf2a100c0
-#define	F367TER_RST_ON_ERROR	0xf2a10020
-#define	F367TER_ONE_SHOT	0xf2a10010
-#define	F367TER_I2C_MOD	0xf2a1000c
-#define	F367TER_SPY_HYSTERESIS	0xf2a10003
-
-/* FSPYDATA */
-#define	R367TER_FSPYDATA	0xf2a2
-#define	F367TER_SPY_STUFFING	0xf2a20080
-#define	F367TER_NOERROR_PKTJITTER	0xf2a20040
-#define	F367TER_SPY_CNULLPKT	0xf2a20020
-#define	F367TER_SPY_OUTDATA_MODE	0xf2a2001f
-
-/* FSPYOUT */
-#define	R367TER_FSPYOUT	0xf2a3
-#define	F367TER_FSPY_DIRECT	0xf2a30080
-#define	F367TER_FSPYOUT_6	0xf2a30040
-#define	F367TER_SPY_OUTDATA_BUS	0xf2a30038
-#define	F367TER_STUFF_MODE	0xf2a30007
-
-/* FSTATUS */
-#define	R367TER_FSTATUS	0xf2a4
-#define	F367TER_SPY_ENDSIM	0xf2a40080
-#define	F367TER_VALID_SIM	0xf2a40040
-#define	F367TER_FOUND_SIGNAL	0xf2a40020
-#define	F367TER_DSS_SYNCBYTE	0xf2a40010
-#define	F367TER_RESULT_STATE	0xf2a4000f
-
-/* FGOODPACK */
-#define	R367TER_FGOODPACK	0xf2a5
-#define	F367TER_FGOOD_PACKET	0xf2a500ff
-
-/* FPACKCNT */
-#define	R367TER_FPACKCNT	0xf2a6
-#define	F367TER_FPACKET_COUNTER	0xf2a600ff
-
-/* FSPYMISC */
-#define	R367TER_FSPYMISC	0xf2a7
-#define	F367TER_FLABEL_COUNTER	0xf2a700ff
-
-/* FBERCPT4 */
-#define	R367TER_FBERCPT4	0xf2a8
-#define	F367TER_FBERMETER_CPT5	0xf2a800ff
-
-/* FBERCPT3 */
-#define	R367TER_FBERCPT3	0xf2a9
-#define	F367TER_FBERMETER_CPT4	0xf2a900ff
-
-/* FBERCPT2 */
-#define	R367TER_FBERCPT2	0xf2aa
-#define	F367TER_FBERMETER_CPT3	0xf2aa00ff
-
-/* FBERCPT1 */
-#define	R367TER_FBERCPT1	0xf2ab
-#define	F367TER_FBERMETER_CPT2	0xf2ab00ff
-
-/* FBERCPT0 */
-#define	R367TER_FBERCPT0	0xf2ac
-#define	F367TER_FBERMETER_CPT1	0xf2ac00ff
-
-/* FBERERR2 */
-#define	R367TER_FBERERR2	0xf2ad
-#define	F367TER_FBERMETER_ERR_HI	0xf2ad00ff
-
-/* FBERERR1 */
-#define	R367TER_FBERERR1	0xf2ae
-#define	F367TER_FBERMETER_ERR_MED	0xf2ae00ff
-
-/* FBERERR0 */
-#define	R367TER_FBERERR0	0xf2af
-#define	F367TER_FBERMETER_ERR_LO	0xf2af00ff
-
-/* FSTATESM */
-#define	R367TER_FSTATESM	0xf2b0
-#define	F367TER_RSTATE_F	0xf2b00080
-#define	F367TER_RSTATE_E	0xf2b00040
-#define	F367TER_RSTATE_D	0xf2b00020
-#define	F367TER_RSTATE_C	0xf2b00010
-#define	F367TER_RSTATE_B	0xf2b00008
-#define	F367TER_RSTATE_A	0xf2b00004
-#define	F367TER_RSTATE_9	0xf2b00002
-#define	F367TER_RSTATE_8	0xf2b00001
-
-/* FSTATESL */
-#define	R367TER_FSTATESL	0xf2b1
-#define	F367TER_RSTATE_7	0xf2b10080
-#define	F367TER_RSTATE_6	0xf2b10040
-#define	F367TER_RSTATE_5	0xf2b10020
-#define	F367TER_RSTATE_4	0xf2b10010
-#define	F367TER_RSTATE_3	0xf2b10008
-#define	F367TER_RSTATE_2	0xf2b10004
-#define	F367TER_RSTATE_1	0xf2b10002
-#define	F367TER_RSTATE_0	0xf2b10001
-
-/* FSPYBER */
-#define	R367TER_FSPYBER	0xf2b2
-#define	F367TER_FSPYBER_7	0xf2b20080
-#define	F367TER_FSPYOBS_XORREAD	0xf2b20040
-#define	F367TER_FSPYBER_OBSMODE	0xf2b20020
-#define	F367TER_FSPYBER_SYNCBYTE	0xf2b20010
-#define	F367TER_FSPYBER_UNSYNC	0xf2b20008
-#define	F367TER_FSPYBER_CTIME	0xf2b20007
-
-/* FSPYDISTM */
-#define	R367TER_FSPYDISTM	0xf2b3
-#define	F367TER_PKTTIME_DISTANCE_HI	0xf2b300ff
-
-/* FSPYDISTL */
-#define	R367TER_FSPYDISTL	0xf2b4
-#define	F367TER_PKTTIME_DISTANCE_LO	0xf2b400ff
-
-/* FSPYOBS7 */
-#define	R367TER_FSPYOBS7	0xf2b8
-#define	F367TER_FSPYOBS_SPYFAIL	0xf2b80080
-#define	F367TER_FSPYOBS_SPYFAIL1	0xf2b80040
-#define	F367TER_FSPYOBS_ERROR	0xf2b80020
-#define	F367TER_FSPYOBS_STROUT	0xf2b80010
-#define	F367TER_FSPYOBS_RESULTSTATE1	0xf2b8000f
-
-/* FSPYOBS6 */
-#define	R367TER_FSPYOBS6	0xf2b9
-#define	F367TER_FSPYOBS_RESULTSTATe0	0xf2b900f0
-#define	F367TER_FSPYOBS_RESULTSTATEM1	0xf2b9000f
-
-/* FSPYOBS5 */
-#define	R367TER_FSPYOBS5	0xf2ba
-#define	F367TER_FSPYOBS_BYTEOFPACKET1	0xf2ba00ff
-
-/* FSPYOBS4 */
-#define	R367TER_FSPYOBS4	0xf2bb
-#define	F367TER_FSPYOBS_BYTEVALUE1	0xf2bb00ff
-
-/* FSPYOBS3 */
-#define	R367TER_FSPYOBS3	0xf2bc
-#define	F367TER_FSPYOBS_DATA1	0xf2bc00ff
-
-/* FSPYOBS2 */
-#define	R367TER_FSPYOBS2	0xf2bd
-#define	F367TER_FSPYOBS_DATa0	0xf2bd00ff
-
-/* FSPYOBS1 */
-#define	R367TER_FSPYOBS1	0xf2be
-#define	F367TER_FSPYOBS_DATAM1	0xf2be00ff
-
-/* FSPYOBS0 */
-#define	R367TER_FSPYOBS0	0xf2bf
-#define	F367TER_FSPYOBS_DATAM2	0xf2bf00ff
-
-/* SFDEMAP */
-#define	R367TER_SFDEMAP	0xf2c0
-#define	F367TER_SFDEMAP_7	0xf2c00080
-#define	F367TER_SFEC_K_DIVIDER_VIT	0xf2c0007f
-
-/* SFERROR */
-#define	R367TER_SFERROR	0xf2c1
-#define	F367TER_SFEC_REGERR_VIT	0xf2c100ff
-
-/* SFAVSR */
-#define	R367TER_SFAVSR	0xf2c2
-#define	F367TER_SFEC_SUMERRORS	0xf2c20080
-#define	F367TER_SERROR_MAXMODE	0xf2c20040
-#define	F367TER_SN_SFEC	0xf2c20030
-#define	F367TER_KDIV_MODE_SFEC	0xf2c2000c
-#define	F367TER_SFAVSR_1	0xf2c20002
-#define	F367TER_SFAVSR_0	0xf2c20001
-
-/* SFECSTATUS */
-#define	R367TER_SFECSTATUS	0xf2c3
-#define	F367TER_SFEC_ON	0xf2c30080
-#define	F367TER_SFSTATUS_6	0xf2c30040
-#define	F367TER_SFSTATUS_5	0xf2c30020
-#define	F367TER_SFSTATUS_4	0xf2c30010
-#define	F367TER_LOCKEDSFEC	0xf2c30008
-#define	F367TER_SFEC_DELOCK	0xf2c30004
-#define	F367TER_SFEC_DEMODSEL1	0xf2c30002
-#define	F367TER_SFEC_OVFON	0xf2c30001
-
-/* SFKDIV12 */
-#define	R367TER_SFKDIV12	0xf2c4
-#define	F367TER_SFECKDIV12_MAN	0xf2c40080
-#define	F367TER_SFEC_K_DIVIDER_12	0xf2c4007f
-
-/* SFKDIV23 */
-#define	R367TER_SFKDIV23	0xf2c5
-#define	F367TER_SFECKDIV23_MAN	0xf2c50080
-#define	F367TER_SFEC_K_DIVIDER_23	0xf2c5007f
-
-/* SFKDIV34 */
-#define	R367TER_SFKDIV34	0xf2c6
-#define	F367TER_SFECKDIV34_MAN	0xf2c60080
-#define	F367TER_SFEC_K_DIVIDER_34	0xf2c6007f
-
-/* SFKDIV56 */
-#define	R367TER_SFKDIV56	0xf2c7
-#define	F367TER_SFECKDIV56_MAN	0xf2c70080
-#define	F367TER_SFEC_K_DIVIDER_56	0xf2c7007f
-
-/* SFKDIV67 */
-#define	R367TER_SFKDIV67	0xf2c8
-#define	F367TER_SFECKDIV67_MAN	0xf2c80080
-#define	F367TER_SFEC_K_DIVIDER_67	0xf2c8007f
-
-/* SFKDIV78 */
-#define	R367TER_SFKDIV78	0xf2c9
-#define	F367TER_SFECKDIV78_MAN	0xf2c90080
-#define	F367TER_SFEC_K_DIVIDER_78	0xf2c9007f
-
-/* SFDILSTKM */
-#define	R367TER_SFDILSTKM	0xf2ca
-#define	F367TER_SFEC_PACKCPT	0xf2ca00e0
-#define	F367TER_SFEC_DILSTK_HI	0xf2ca001f
-
-/* SFDILSTKL */
-#define	R367TER_SFDILSTKL	0xf2cb
-#define	F367TER_SFEC_DILSTK_LO	0xf2cb00ff
-
-/* SFSTATUS */
-#define	R367TER_SFSTATUS	0xf2cc
-#define	F367TER_SFEC_LINEOK	0xf2cc0080
-#define	F367TER_SFEC_ERROR	0xf2cc0040
-#define	F367TER_SFEC_DATA7	0xf2cc0020
-#define	F367TER_SFEC_OVERFLOW	0xf2cc0010
-#define	F367TER_SFEC_DEMODSEL2	0xf2cc0008
-#define	F367TER_SFEC_NOSYNC	0xf2cc0004
-#define	F367TER_SFEC_UNREGULA	0xf2cc0002
-#define	F367TER_SFEC_READY	0xf2cc0001
-
-/* SFDLYH */
-#define	R367TER_SFDLYH	0xf2cd
-#define	F367TER_SFEC_TSTIMEVALID	0xf2cd0080
-#define	F367TER_SFEC_SPEEDUP	0xf2cd0040
-#define	F367TER_SFEC_STOP	0xf2cd0020
-#define	F367TER_SFEC_REGULATED	0xf2cd0010
-#define	F367TER_SFEC_REALSYMBOFFSET	0xf2cd000f
-
-/* SFDLYM */
-#define	R367TER_SFDLYM	0xf2ce
-#define	F367TER_SFEC_REALSYMBOFFSET_HI	0xf2ce00ff
-
-/* SFDLYL */
-#define	R367TER_SFDLYL	0xf2cf
-#define	F367TER_SFEC_REALSYMBOFFSET_LO	0xf2cf00ff
-
-/* SFDLYSETH */
-#define	R367TER_SFDLYSETH	0xf2d0
-#define	F367TER_SFEC_OFFSET	0xf2d000e0
-#define	F367TER_SFECDLYSETH_4	0xf2d00010
-#define	F367TER_RST_SFEC	0xf2d00008
-#define	F367TER_SFECDLYSETH_2	0xf2d00004
-#define	F367TER_SFEC_DISABLE	0xf2d00002
-#define	F367TER_SFEC_UNREGUL	0xf2d00001
-
-/* SFDLYSETM */
-#define	R367TER_SFDLYSETM	0xf2d1
-#define	F367TER_SFECDLYSETM_7	0xf2d10080
-#define	F367TER_SFEC_SYMBOFFSET_HI	0xf2d1007f
-
-/* SFDLYSETL */
-#define	R367TER_SFDLYSETL	0xf2d2
-#define	F367TER_SFEC_SYMBOFFSET_LO	0xf2d200ff
-
-/* SFOBSCFG */
-#define	R367TER_SFOBSCFG	0xf2d3
-#define	F367TER_SFEC_OBSCFG	0xf2d300ff
-
-/* SFOBSM */
-#define	R367TER_SFOBSM	0xf2d4
-#define	F367TER_SFEC_OBSDATA_HI	0xf2d400ff
-
-/* SFOBSL */
-#define	R367TER_SFOBSL	0xf2d5
-#define	F367TER_SFEC_OBSDATA_LO	0xf2d500ff
-
-/* SFECINFO */
-#define	R367TER_SFECINFO	0xf2d6
-#define	F367TER_SFECINFO_7	0xf2d60080
-#define	F367TER_SFEC_SYNCDLSB	0xf2d60070
-#define	F367TER_SFCE_S1cPHASE	0xf2d6000f
-
-/* SFERRCTRL */
-#define	R367TER_SFERRCTRL	0xf2d8
-#define	F367TER_SFEC_ERR_SOURCE	0xf2d800f0
-#define	F367TER_SFERRCTRL_3	0xf2d80008
-#define	F367TER_SFEC_NUM_EVENT	0xf2d80007
-
-/* SFERRCNTH */
-#define	R367TER_SFERRCNTH	0xf2d9
-#define	F367TER_SFERRC_OLDVALUE	0xf2d90080
-#define	F367TER_SFEC_ERR_CNT	0xf2d9007f
-
-/* SFERRCNTM */
-#define	R367TER_SFERRCNTM	0xf2da
-#define	F367TER_SFEC_ERR_CNT_HI	0xf2da00ff
-
-/* SFERRCNTL */
-#define	R367TER_SFERRCNTL	0xf2db
-#define	F367TER_SFEC_ERR_CNT_LO	0xf2db00ff
-
-/* SYMBRATEM */
-#define	R367TER_SYMBRATEM	0xf2e0
-#define	F367TER_DEFGEN_SYMBRATE_HI	0xf2e000ff
-
-/* SYMBRATEL */
-#define	R367TER_SYMBRATEL	0xf2e1
-#define	F367TER_DEFGEN_SYMBRATE_LO	0xf2e100ff
-
-/* SYMBSTATUS */
-#define	R367TER_SYMBSTATUS	0xf2e2
-#define	F367TER_SYMBDLINE2_OFF	0xf2e20080
-#define	F367TER_SDDL_REINIT1	0xf2e20040
-#define	F367TER_SDD_REINIT1	0xf2e20020
-#define	F367TER_TOKENID_ERROR	0xf2e20010
-#define	F367TER_SYMBRATE_OVERFLOW	0xf2e20008
-#define	F367TER_SYMBRATE_UNDERFLOW	0xf2e20004
-#define	F367TER_TOKENID_RSTEVENT	0xf2e20002
-#define	F367TER_TOKENID_RESET1	0xf2e20001
-
-/* SYMBCFG */
-#define	R367TER_SYMBCFG	0xf2e3
-#define	F367TER_SYMBCFG_7	0xf2e30080
-#define	F367TER_SYMBCFG_6	0xf2e30040
-#define	F367TER_SYMBCFG_5	0xf2e30020
-#define	F367TER_SYMBCFG_4	0xf2e30010
-#define	F367TER_SYMRATE_FSPEED	0xf2e3000c
-#define	F367TER_SYMRATE_SSPEED	0xf2e30003
-
-/* SYMBFIFOM */
-#define	R367TER_SYMBFIFOM	0xf2e4
-#define	F367TER_SYMBFIFOM_7	0xf2e40080
-#define	F367TER_SYMBFIFOM_6	0xf2e40040
-#define	F367TER_DEFGEN_SYMFIFO_HI	0xf2e4003f
-
-/* SYMBFIFOL */
-#define	R367TER_SYMBFIFOL	0xf2e5
-#define	F367TER_DEFGEN_SYMFIFO_LO	0xf2e500ff
-
-/* SYMBOFFSM */
-#define	R367TER_SYMBOFFSM	0xf2e6
-#define	F367TER_TOKENID_RESET2	0xf2e60080
-#define	F367TER_SDDL_REINIT2	0xf2e60040
-#define	F367TER_SDD_REINIT2	0xf2e60020
-#define	F367TER_SYMBOFFSM_4	0xf2e60010
-#define	F367TER_SYMBOFFSM_3	0xf2e60008
-#define	F367TER_DEFGEN_SYMBOFFSET_HI	0xf2e60007
-
-/* SYMBOFFSL */
-#define	R367TER_SYMBOFFSL	0xf2e7
-#define	F367TER_DEFGEN_SYMBOFFSET_LO	0xf2e700ff
-
-/* DEBUG_LT4 */
-#define	R367TER_DEBUG_LT4	0xf400
-#define	F367TER_F_DEBUG_LT4	0xf40000ff
-
-/* DEBUG_LT5 */
-#define	R367TER_DEBUG_LT5	0xf401
-#define	F367TER_F_DEBUG_LT5	0xf40100ff
-
-/* DEBUG_LT6 */
-#define	R367TER_DEBUG_LT6	0xf402
-#define	F367TER_F_DEBUG_LT6	0xf40200ff
-
-/* DEBUG_LT7 */
-#define	R367TER_DEBUG_LT7	0xf403
-#define	F367TER_F_DEBUG_LT7	0xf40300ff
-
-/* DEBUG_LT8 */
-#define	R367TER_DEBUG_LT8	0xf404
-#define	F367TER_F_DEBUG_LT8	0xf40400ff
-
-/* DEBUG_LT9 */
-#define	R367TER_DEBUG_LT9	0xf405
-#define	F367TER_F_DEBUG_LT9	0xf40500ff
-
-#define STV0367TER_NBREGS	445
-
-/* ID */
-#define	R367CAB_ID	0xf000
-#define	F367CAB_IDENTIFICATIONREGISTER	0xf00000ff
-
-/* I2CRPT */
-#define	R367CAB_I2CRPT	0xf001
-#define	F367CAB_I2CT_ON	0xf0010080
-#define	F367CAB_ENARPT_LEVEL	0xf0010070
-#define	F367CAB_SCLT_DELAY	0xf0010008
-#define	F367CAB_SCLT_NOD	0xf0010004
-#define	F367CAB_STOP_ENABLE	0xf0010002
-#define	F367CAB_SDAT_NOD	0xf0010001
-
-/* TOPCTRL */
-#define	R367CAB_TOPCTRL	0xf002
-#define	F367CAB_STDBY	0xf0020080
-#define	F367CAB_STDBY_CORE	0xf0020020
-#define	F367CAB_QAM_COFDM	0xf0020010
-#define	F367CAB_TS_DIS	0xf0020008
-#define	F367CAB_DIR_CLK_216	0xf0020004
-
-/* IOCFG0 */
-#define	R367CAB_IOCFG0	0xf003
-#define	F367CAB_OP0_SD	0xf0030080
-#define	F367CAB_OP0_VAL	0xf0030040
-#define	F367CAB_OP0_OD	0xf0030020
-#define	F367CAB_OP0_INV	0xf0030010
-#define	F367CAB_OP0_DACVALUE_HI	0xf003000f
-
-/* DAc0R */
-#define	R367CAB_DAC0R	0xf004
-#define	F367CAB_OP0_DACVALUE_LO	0xf00400ff
-
-/* IOCFG1 */
-#define	R367CAB_IOCFG1	0xf005
-#define	F367CAB_IP0	0xf0050040
-#define	F367CAB_OP1_OD	0xf0050020
-#define	F367CAB_OP1_INV	0xf0050010
-#define	F367CAB_OP1_DACVALUE_HI	0xf005000f
-
-/* DAC1R */
-#define	R367CAB_DAC1R	0xf006
-#define	F367CAB_OP1_DACVALUE_LO	0xf00600ff
-
-/* IOCFG2 */
-#define	R367CAB_IOCFG2	0xf007
-#define	F367CAB_OP2_LOCK_CONF	0xf00700e0
-#define	F367CAB_OP2_OD	0xf0070010
-#define	F367CAB_OP2_VAL	0xf0070008
-#define	F367CAB_OP1_LOCK_CONF	0xf0070007
-
-/* SDFR */
-#define	R367CAB_SDFR	0xf008
-#define	F367CAB_OP0_FREQ	0xf00800f0
-#define	F367CAB_OP1_FREQ	0xf008000f
-
-/* AUX_CLK */
-#define	R367CAB_AUX_CLK	0xf00a
-#define	F367CAB_AUXFEC_CTL	0xf00a00c0
-#define	F367CAB_DIS_CKX4	0xf00a0020
-#define	F367CAB_CKSEL	0xf00a0018
-#define	F367CAB_CKDIV_PROG	0xf00a0006
-#define	F367CAB_AUXCLK_ENA	0xf00a0001
-
-/* FREESYS1 */
-#define	R367CAB_FREESYS1	0xf00b
-#define	F367CAB_FREESYS_1	0xf00b00ff
-
-/* FREESYS2 */
-#define	R367CAB_FREESYS2	0xf00c
-#define	F367CAB_FREESYS_2	0xf00c00ff
-
-/* FREESYS3 */
-#define	R367CAB_FREESYS3	0xf00d
-#define	F367CAB_FREESYS_3	0xf00d00ff
-
-/* GPIO_CFG */
-#define	R367CAB_GPIO_CFG	0xf00e
-#define	F367CAB_GPIO7_OD	0xf00e0080
-#define	F367CAB_GPIO7_CFG	0xf00e0040
-#define	F367CAB_GPIO6_OD	0xf00e0020
-#define	F367CAB_GPIO6_CFG	0xf00e0010
-#define	F367CAB_GPIO5_OD	0xf00e0008
-#define	F367CAB_GPIO5_CFG	0xf00e0004
-#define	F367CAB_GPIO4_OD	0xf00e0002
-#define	F367CAB_GPIO4_CFG	0xf00e0001
-
-/* GPIO_CMD */
-#define	R367CAB_GPIO_CMD	0xf00f
-#define	F367CAB_GPIO7_VAL	0xf00f0008
-#define	F367CAB_GPIO6_VAL	0xf00f0004
-#define	F367CAB_GPIO5_VAL	0xf00f0002
-#define	F367CAB_GPIO4_VAL	0xf00f0001
-
-/* TSTRES */
-#define	R367CAB_TSTRES	0xf0c0
-#define	F367CAB_FRES_DISPLAY	0xf0c00080
-#define	F367CAB_FRES_FIFO_AD	0xf0c00020
-#define	F367CAB_FRESRS	0xf0c00010
-#define	F367CAB_FRESACS	0xf0c00008
-#define	F367CAB_FRESFEC	0xf0c00004
-#define	F367CAB_FRES_PRIF	0xf0c00002
-#define	F367CAB_FRESCORE	0xf0c00001
-
-/* ANACTRL */
-#define	R367CAB_ANACTRL	0xf0c1
-#define	F367CAB_BYPASS_XTAL	0xf0c10040
-#define	F367CAB_BYPASS_PLLXN	0xf0c1000c
-#define	F367CAB_DIS_PAD_OSC	0xf0c10002
-#define	F367CAB_STDBY_PLLXN	0xf0c10001
-
-/* TSTBUS */
-#define	R367CAB_TSTBUS	0xf0c2
-#define	F367CAB_TS_BYTE_CLK_INV	0xf0c20080
-#define	F367CAB_CFG_IP	0xf0c20070
-#define	F367CAB_CFG_TST	0xf0c2000f
-
-/* RF_AGC1 */
-#define	R367CAB_RF_AGC1	0xf0d4
-#define	F367CAB_RF_AGC1_LEVEL_HI	0xf0d400ff
-
-/* RF_AGC2 */
-#define	R367CAB_RF_AGC2	0xf0d5
-#define	F367CAB_REF_ADGP	0xf0d50080
-#define	F367CAB_STDBY_ADCGP	0xf0d50020
-#define	F367CAB_RF_AGC1_LEVEL_LO	0xf0d50003
-
-/* ANADIGCTRL */
-#define	R367CAB_ANADIGCTRL	0xf0d7
-#define	F367CAB_SEL_CLKDEM	0xf0d70020
-#define	F367CAB_EN_BUFFER_Q	0xf0d70010
-#define	F367CAB_EN_BUFFER_I	0xf0d70008
-#define	F367CAB_ADC_RIS_EGDE	0xf0d70004
-#define	F367CAB_SGN_ADC	0xf0d70002
-#define	F367CAB_SEL_AD12_SYNC	0xf0d70001
-
-/* PLLMDIV */
-#define	R367CAB_PLLMDIV	0xf0d8
-#define	F367CAB_PLL_MDIV	0xf0d800ff
-
-/* PLLNDIV */
-#define	R367CAB_PLLNDIV	0xf0d9
-#define	F367CAB_PLL_NDIV	0xf0d900ff
-
-/* PLLSETUP */
-#define	R367CAB_PLLSETUP	0xf0da
-#define	F367CAB_PLL_PDIV	0xf0da0070
-#define	F367CAB_PLL_KDIV	0xf0da000f
-
-/* DUAL_AD12 */
-#define	R367CAB_DUAL_AD12	0xf0db
-#define	F367CAB_FS20M	0xf0db0020
-#define	F367CAB_FS50M	0xf0db0010
-#define	F367CAB_INMODe0	0xf0db0008
-#define	F367CAB_POFFQ	0xf0db0004
-#define	F367CAB_POFFI	0xf0db0002
-#define	F367CAB_INMODE1	0xf0db0001
-
-/* TSTBIST */
-#define	R367CAB_TSTBIST	0xf0dc
-#define	F367CAB_TST_BYP_CLK	0xf0dc0080
-#define	F367CAB_TST_GCLKENA_STD	0xf0dc0040
-#define	F367CAB_TST_GCLKENA	0xf0dc0020
-#define	F367CAB_TST_MEMBIST	0xf0dc001f
-
-/* CTRL_1 */
-#define	R367CAB_CTRL_1	0xf402
-#define	F367CAB_SOFT_RST	0xf4020080
-#define	F367CAB_EQU_RST	0xf4020008
-#define	F367CAB_CRL_RST	0xf4020004
-#define	F367CAB_TRL_RST	0xf4020002
-#define	F367CAB_AGC_RST	0xf4020001
-
-/* CTRL_2 */
-#define	R367CAB_CTRL_2	0xf403
-#define	F367CAB_DEINT_RST	0xf4030008
-#define	F367CAB_RS_RST	0xf4030004
-
-/* IT_STATUS1 */
-#define	R367CAB_IT_STATUS1	0xf408
-#define	F367CAB_SWEEP_OUT	0xf4080080
-#define	F367CAB_FSM_CRL	0xf4080040
-#define	F367CAB_CRL_LOCK	0xf4080020
-#define	F367CAB_MFSM	0xf4080010
-#define	F367CAB_TRL_LOCK	0xf4080008
-#define	F367CAB_TRL_AGC_LIMIT	0xf4080004
-#define	F367CAB_ADJ_AGC_LOCK	0xf4080002
-#define	F367CAB_AGC_QAM_LOCK	0xf4080001
-
-/* IT_STATUS2 */
-#define	R367CAB_IT_STATUS2	0xf409
-#define	F367CAB_TSMF_CNT	0xf4090080
-#define	F367CAB_TSMF_EOF	0xf4090040
-#define	F367CAB_TSMF_RDY	0xf4090020
-#define	F367CAB_FEC_NOCORR	0xf4090010
-#define	F367CAB_SYNCSTATE	0xf4090008
-#define	F367CAB_DEINT_LOCK	0xf4090004
-#define	F367CAB_FADDING_FRZ	0xf4090002
-#define	F367CAB_TAPMON_ALARM	0xf4090001
-
-/* IT_EN1 */
-#define	R367CAB_IT_EN1	0xf40a
-#define	F367CAB_SWEEP_OUTE	0xf40a0080
-#define	F367CAB_FSM_CRLE	0xf40a0040
-#define	F367CAB_CRL_LOCKE	0xf40a0020
-#define	F367CAB_MFSME	0xf40a0010
-#define	F367CAB_TRL_LOCKE	0xf40a0008
-#define	F367CAB_TRL_AGC_LIMITE	0xf40a0004
-#define	F367CAB_ADJ_AGC_LOCKE	0xf40a0002
-#define	F367CAB_AGC_LOCKE	0xf40a0001
-
-/* IT_EN2 */
-#define	R367CAB_IT_EN2	0xf40b
-#define	F367CAB_TSMF_CNTE	0xf40b0080
-#define	F367CAB_TSMF_EOFE	0xf40b0040
-#define	F367CAB_TSMF_RDYE	0xf40b0020
-#define	F367CAB_FEC_NOCORRE	0xf40b0010
-#define	F367CAB_SYNCSTATEE	0xf40b0008
-#define	F367CAB_DEINT_LOCKE	0xf40b0004
-#define	F367CAB_FADDING_FRZE	0xf40b0002
-#define	F367CAB_TAPMON_ALARME	0xf40b0001
-
-/* CTRL_STATUS */
-#define	R367CAB_CTRL_STATUS	0xf40c
-#define	F367CAB_QAMFEC_LOCK	0xf40c0004
-#define	F367CAB_TSMF_LOCK	0xf40c0002
-#define	F367CAB_TSMF_ERROR	0xf40c0001
-
-/* TEST_CTL */
-#define	R367CAB_TEST_CTL	0xf40f
-#define	F367CAB_TST_BLK_SEL	0xf40f0060
-#define	F367CAB_TST_BUS_SEL	0xf40f001f
-
-/* AGC_CTL */
-#define	R367CAB_AGC_CTL	0xf410
-#define	F367CAB_AGC_LCK_TH	0xf41000f0
-#define	F367CAB_AGC_ACCUMRSTSEL	0xf4100007
-
-/* AGC_IF_CFG */
-#define	R367CAB_AGC_IF_CFG	0xf411
-#define	F367CAB_AGC_IF_BWSEL	0xf41100f0
-#define	F367CAB_AGC_IF_FREEZE	0xf4110002
-
-/* AGC_RF_CFG */
-#define	R367CAB_AGC_RF_CFG	0xf412
-#define	F367CAB_AGC_RF_BWSEL	0xf4120070
-#define	F367CAB_AGC_RF_FREEZE	0xf4120002
-
-/* AGC_PWM_CFG */
-#define	R367CAB_AGC_PWM_CFG	0xf413
-#define	F367CAB_AGC_RF_PWM_TST	0xf4130080
-#define	F367CAB_AGC_RF_PWM_INV	0xf4130040
-#define	F367CAB_AGC_IF_PWM_TST	0xf4130008
-#define	F367CAB_AGC_IF_PWM_INV	0xf4130004
-#define	F367CAB_AGC_PWM_CLKDIV	0xf4130003
-
-/* AGC_PWR_REF_L */
-#define	R367CAB_AGC_PWR_REF_L	0xf414
-#define	F367CAB_AGC_PWRREF_LO	0xf41400ff
-
-/* AGC_PWR_REF_H */
-#define	R367CAB_AGC_PWR_REF_H	0xf415
-#define	F367CAB_AGC_PWRREF_HI	0xf4150003
-
-/* AGC_RF_TH_L */
-#define	R367CAB_AGC_RF_TH_L	0xf416
-#define	F367CAB_AGC_RF_TH_LO	0xf41600ff
-
-/* AGC_RF_TH_H */
-#define	R367CAB_AGC_RF_TH_H	0xf417
-#define	F367CAB_AGC_RF_TH_HI	0xf417000f
-
-/* AGC_IF_LTH_L */
-#define	R367CAB_AGC_IF_LTH_L	0xf418
-#define	F367CAB_AGC_IF_THLO_LO	0xf41800ff
-
-/* AGC_IF_LTH_H */
-#define	R367CAB_AGC_IF_LTH_H	0xf419
-#define	F367CAB_AGC_IF_THLO_HI	0xf419000f
-
-/* AGC_IF_HTH_L */
-#define	R367CAB_AGC_IF_HTH_L	0xf41a
-#define	F367CAB_AGC_IF_THHI_LO	0xf41a00ff
-
-/* AGC_IF_HTH_H */
-#define	R367CAB_AGC_IF_HTH_H	0xf41b
-#define	F367CAB_AGC_IF_THHI_HI	0xf41b000f
-
-/* AGC_PWR_RD_L */
-#define	R367CAB_AGC_PWR_RD_L	0xf41c
-#define	F367CAB_AGC_PWR_WORD_LO	0xf41c00ff
-
-/* AGC_PWR_RD_M */
-#define	R367CAB_AGC_PWR_RD_M	0xf41d
-#define	F367CAB_AGC_PWR_WORD_ME	0xf41d00ff
-
-/* AGC_PWR_RD_H */
-#define	R367CAB_AGC_PWR_RD_H	0xf41e
-#define	F367CAB_AGC_PWR_WORD_HI	0xf41e0003
-
-/* AGC_PWM_IFCMD_L */
-#define	R367CAB_AGC_PWM_IFCMD_L	0xf420
-#define	F367CAB_AGC_IF_PWMCMD_LO	0xf42000ff
-
-/* AGC_PWM_IFCMD_H */
-#define	R367CAB_AGC_PWM_IFCMD_H	0xf421
-#define	F367CAB_AGC_IF_PWMCMD_HI	0xf421000f
-
-/* AGC_PWM_RFCMD_L */
-#define	R367CAB_AGC_PWM_RFCMD_L	0xf422
-#define	F367CAB_AGC_RF_PWMCMD_LO	0xf42200ff
-
-/* AGC_PWM_RFCMD_H */
-#define	R367CAB_AGC_PWM_RFCMD_H	0xf423
-#define	F367CAB_AGC_RF_PWMCMD_HI	0xf423000f
-
-/* IQDEM_CFG */
-#define	R367CAB_IQDEM_CFG	0xf424
-#define	F367CAB_IQDEM_CLK_SEL	0xf4240004
-#define	F367CAB_IQDEM_INVIQ	0xf4240002
-#define	F367CAB_IQDEM_A2dTYPE	0xf4240001
-
-/* MIX_NCO_LL */
-#define	R367CAB_MIX_NCO_LL	0xf425
-#define	F367CAB_MIX_NCO_INC_LL	0xf42500ff
-
-/* MIX_NCO_HL */
-#define	R367CAB_MIX_NCO_HL	0xf426
-#define	F367CAB_MIX_NCO_INC_HL	0xf42600ff
-
-/* MIX_NCO_HH */
-#define	R367CAB_MIX_NCO_HH	0xf427
-#define	F367CAB_MIX_NCO_INVCNST	0xf4270080
-#define	F367CAB_MIX_NCO_INC_HH	0xf427007f
-
-/* SRC_NCO_LL */
-#define	R367CAB_SRC_NCO_LL	0xf428
-#define	F367CAB_SRC_NCO_INC_LL	0xf42800ff
-
-/* SRC_NCO_LH */
-#define	R367CAB_SRC_NCO_LH	0xf429
-#define	F367CAB_SRC_NCO_INC_LH	0xf42900ff
-
-/* SRC_NCO_HL */
-#define	R367CAB_SRC_NCO_HL	0xf42a
-#define	F367CAB_SRC_NCO_INC_HL	0xf42a00ff
-
-/* SRC_NCO_HH */
-#define	R367CAB_SRC_NCO_HH	0xf42b
-#define	F367CAB_SRC_NCO_INC_HH	0xf42b007f
-
-/* IQDEM_GAIN_SRC_L */
-#define	R367CAB_IQDEM_GAIN_SRC_L	0xf42c
-#define	F367CAB_GAIN_SRC_LO	0xf42c00ff
-
-/* IQDEM_GAIN_SRC_H */
-#define	R367CAB_IQDEM_GAIN_SRC_H	0xf42d
-#define	F367CAB_GAIN_SRC_HI	0xf42d0003
-
-/* IQDEM_DCRM_CFG_LL */
-#define	R367CAB_IQDEM_DCRM_CFG_LL	0xf430
-#define	F367CAB_DCRM0_DCIN_L	0xf43000ff
-
-/* IQDEM_DCRM_CFG_LH */
-#define	R367CAB_IQDEM_DCRM_CFG_LH	0xf431
-#define	F367CAB_DCRM1_I_DCIN_L	0xf43100fc
-#define	F367CAB_DCRM0_DCIN_H	0xf4310003
-
-/* IQDEM_DCRM_CFG_HL */
-#define	R367CAB_IQDEM_DCRM_CFG_HL	0xf432
-#define	F367CAB_DCRM1_Q_DCIN_L	0xf43200f0
-#define	F367CAB_DCRM1_I_DCIN_H	0xf432000f
-
-/* IQDEM_DCRM_CFG_HH */
-#define	R367CAB_IQDEM_DCRM_CFG_HH	0xf433
-#define	F367CAB_DCRM1_FRZ	0xf4330080
-#define	F367CAB_DCRM0_FRZ	0xf4330040
-#define	F367CAB_DCRM1_Q_DCIN_H	0xf433003f
-
-/* IQDEM_ADJ_COEFf0 */
-#define	R367CAB_IQDEM_ADJ_COEFF0	0xf434
-#define	F367CAB_ADJIIR_COEFF10_L	0xf43400ff
-
-/* IQDEM_ADJ_COEFF1 */
-#define	R367CAB_IQDEM_ADJ_COEFF1	0xf435
-#define	F367CAB_ADJIIR_COEFF11_L	0xf43500fc
-#define	F367CAB_ADJIIR_COEFF10_H	0xf4350003
-
-/* IQDEM_ADJ_COEFF2 */
-#define	R367CAB_IQDEM_ADJ_COEFF2	0xf436
-#define	F367CAB_ADJIIR_COEFF12_L	0xf43600f0
-#define	F367CAB_ADJIIR_COEFF11_H	0xf436000f
-
-/* IQDEM_ADJ_COEFF3 */
-#define	R367CAB_IQDEM_ADJ_COEFF3	0xf437
-#define	F367CAB_ADJIIR_COEFF20_L	0xf43700c0
-#define	F367CAB_ADJIIR_COEFF12_H	0xf437003f
-
-/* IQDEM_ADJ_COEFF4 */
-#define	R367CAB_IQDEM_ADJ_COEFF4	0xf438
-#define	F367CAB_ADJIIR_COEFF20_H	0xf43800ff
-
-/* IQDEM_ADJ_COEFF5 */
-#define	R367CAB_IQDEM_ADJ_COEFF5	0xf439
-#define	F367CAB_ADJIIR_COEFF21_L	0xf43900ff
-
-/* IQDEM_ADJ_COEFF6 */
-#define	R367CAB_IQDEM_ADJ_COEFF6	0xf43a
-#define	F367CAB_ADJIIR_COEFF22_L	0xf43a00fc
-#define	F367CAB_ADJIIR_COEFF21_H	0xf43a0003
-
-/* IQDEM_ADJ_COEFF7 */
-#define	R367CAB_IQDEM_ADJ_COEFF7	0xf43b
-#define	F367CAB_ADJIIR_COEFF22_H	0xf43b000f
-
-/* IQDEM_ADJ_EN */
-#define	R367CAB_IQDEM_ADJ_EN	0xf43c
-#define	F367CAB_ALLPASSFILT_EN	0xf43c0008
-#define	F367CAB_ADJ_AGC_EN	0xf43c0004
-#define	F367CAB_ADJ_COEFF_FRZ	0xf43c0002
-#define	F367CAB_ADJ_EN	0xf43c0001
-
-/* IQDEM_ADJ_AGC_REF */
-#define	R367CAB_IQDEM_ADJ_AGC_REF	0xf43d
-#define	F367CAB_ADJ_AGC_REF	0xf43d00ff
-
-/* ALLPASSFILT1 */
-#define	R367CAB_ALLPASSFILT1	0xf440
-#define	F367CAB_ALLPASSFILT_COEFF1_LO	0xf44000ff
-
-/* ALLPASSFILT2 */
-#define	R367CAB_ALLPASSFILT2	0xf441
-#define	F367CAB_ALLPASSFILT_COEFF1_ME	0xf44100ff
-
-/* ALLPASSFILT3 */
-#define	R367CAB_ALLPASSFILT3	0xf442
-#define	F367CAB_ALLPASSFILT_COEFF2_LO	0xf44200c0
-#define	F367CAB_ALLPASSFILT_COEFF1_HI	0xf442003f
-
-/* ALLPASSFILT4 */
-#define	R367CAB_ALLPASSFILT4	0xf443
-#define	F367CAB_ALLPASSFILT_COEFF2_MEL	0xf44300ff
-
-/* ALLPASSFILT5 */
-#define	R367CAB_ALLPASSFILT5	0xf444
-#define	F367CAB_ALLPASSFILT_COEFF2_MEH	0xf44400ff
-
-/* ALLPASSFILT6 */
-#define	R367CAB_ALLPASSFILT6	0xf445
-#define	F367CAB_ALLPASSFILT_COEFF3_LO	0xf44500f0
-#define	F367CAB_ALLPASSFILT_COEFF2_HI	0xf445000f
-
-/* ALLPASSFILT7 */
-#define	R367CAB_ALLPASSFILT7	0xf446
-#define	F367CAB_ALLPASSFILT_COEFF3_MEL	0xf44600ff
-
-/* ALLPASSFILT8 */
-#define	R367CAB_ALLPASSFILT8	0xf447
-#define	F367CAB_ALLPASSFILT_COEFF3_MEH	0xf44700ff
-
-/* ALLPASSFILT9 */
-#define	R367CAB_ALLPASSFILT9	0xf448
-#define	F367CAB_ALLPASSFILT_COEFF4_LO	0xf44800fc
-#define	F367CAB_ALLPASSFILT_COEFF3_HI	0xf4480003
-
-/* ALLPASSFILT10 */
-#define	R367CAB_ALLPASSFILT10	0xf449
-#define	F367CAB_ALLPASSFILT_COEFF4_ME	0xf44900ff
-
-/* ALLPASSFILT11 */
-#define	R367CAB_ALLPASSFILT11	0xf44a
-#define	F367CAB_ALLPASSFILT_COEFF4_HI	0xf44a00ff
-
-/* TRL_AGC_CFG */
-#define	R367CAB_TRL_AGC_CFG	0xf450
-#define	F367CAB_TRL_AGC_FREEZE	0xf4500080
-#define	F367CAB_TRL_AGC_REF	0xf450007f
-
-/* TRL_LPF_CFG */
-#define	R367CAB_TRL_LPF_CFG	0xf454
-#define	F367CAB_NYQPOINT_INV	0xf4540040
-#define	F367CAB_TRL_SHIFT	0xf4540030
-#define	F367CAB_NYQ_COEFF_SEL	0xf454000c
-#define	F367CAB_TRL_LPF_FREEZE	0xf4540002
-#define	F367CAB_TRL_LPF_CRT	0xf4540001
-
-/* TRL_LPF_ACQ_GAIN */
-#define	R367CAB_TRL_LPF_ACQ_GAIN	0xf455
-#define	F367CAB_TRL_GDIR_ACQ	0xf4550070
-#define	F367CAB_TRL_GINT_ACQ	0xf4550007
-
-/* TRL_LPF_TRK_GAIN */
-#define	R367CAB_TRL_LPF_TRK_GAIN	0xf456
-#define	F367CAB_TRL_GDIR_TRK	0xf4560070
-#define	F367CAB_TRL_GINT_TRK	0xf4560007
-
-/* TRL_LPF_OUT_GAIN */
-#define	R367CAB_TRL_LPF_OUT_GAIN	0xf457
-#define	F367CAB_TRL_GAIN_OUT	0xf4570007
-
-/* TRL_LOCKDET_LTH */
-#define	R367CAB_TRL_LOCKDET_LTH	0xf458
-#define	F367CAB_TRL_LCK_THLO	0xf4580007
-
-/* TRL_LOCKDET_HTH */
-#define	R367CAB_TRL_LOCKDET_HTH	0xf459
-#define	F367CAB_TRL_LCK_THHI	0xf45900ff
-
-/* TRL_LOCKDET_TRGVAL */
-#define	R367CAB_TRL_LOCKDET_TRGVAL	0xf45a
-#define	F367CAB_TRL_LCK_TRG	0xf45a00ff
-
-/* IQ_QAM */
-#define	R367CAB_IQ_QAM	0xf45c
-#define	F367CAB_IQ_INPUT	0xf45c0008
-#define	F367CAB_DETECT_MODE	0xf45c0007
-
-/* FSM_STATE */
-#define	R367CAB_FSM_STATE	0xf460
-#define	F367CAB_CRL_DFE	0xf4600080
-#define	F367CAB_DFE_START	0xf4600040
-#define	F367CAB_CTRLG_START	0xf4600030
-#define	F367CAB_FSM_FORCESTATE	0xf460000f
-
-/* FSM_CTL */
-#define	R367CAB_FSM_CTL	0xf461
-#define	F367CAB_FEC2_EN	0xf4610040
-#define	F367CAB_SIT_EN	0xf4610020
-#define	F367CAB_TRL_AHEAD	0xf4610010
-#define	F367CAB_TRL2_EN	0xf4610008
-#define	F367CAB_FSM_EQA1_EN	0xf4610004
-#define	F367CAB_FSM_BKP_DIS	0xf4610002
-#define	F367CAB_FSM_FORCE_EN	0xf4610001
-
-/* FSM_STS */
-#define	R367CAB_FSM_STS	0xf462
-#define	F367CAB_FSM_STATUS	0xf462000f
-
-/* FSM_SNR0_HTH */
-#define	R367CAB_FSM_SNR0_HTH	0xf463
-#define	F367CAB_SNR0_HTH	0xf46300ff
-
-/* FSM_SNR1_HTH */
-#define	R367CAB_FSM_SNR1_HTH	0xf464
-#define	F367CAB_SNR1_HTH	0xf46400ff
-
-/* FSM_SNR2_HTH */
-#define	R367CAB_FSM_SNR2_HTH	0xf465
-#define	F367CAB_SNR2_HTH	0xf46500ff
-
-/* FSM_SNR0_LTH */
-#define	R367CAB_FSM_SNR0_LTH	0xf466
-#define	F367CAB_SNR0_LTH	0xf46600ff
-
-/* FSM_SNR1_LTH */
-#define	R367CAB_FSM_SNR1_LTH	0xf467
-#define	F367CAB_SNR1_LTH	0xf46700ff
-
-/* FSM_EQA1_HTH */
-#define	R367CAB_FSM_EQA1_HTH	0xf468
-#define	F367CAB_SNR3_HTH_LO	0xf46800f0
-#define	F367CAB_EQA1_HTH	0xf468000f
-
-/* FSM_TEMPO */
-#define	R367CAB_FSM_TEMPO	0xf469
-#define	F367CAB_SIT	0xf46900c0
-#define	F367CAB_WST	0xf4690038
-#define	F367CAB_ELT	0xf4690006
-#define	F367CAB_SNR3_HTH_HI	0xf4690001
-
-/* FSM_CONFIG */
-#define	R367CAB_FSM_CONFIG	0xf46a
-#define	F367CAB_FEC2_DFEOFF	0xf46a0004
-#define	F367CAB_PRIT_STATE	0xf46a0002
-#define	F367CAB_MODMAP_STATE	0xf46a0001
-
-/* EQU_I_TESTTAP_L */
-#define	R367CAB_EQU_I_TESTTAP_L	0xf474
-#define	F367CAB_I_TEST_TAP_L	0xf47400ff
-
-/* EQU_I_TESTTAP_M */
-#define	R367CAB_EQU_I_TESTTAP_M	0xf475
-#define	F367CAB_I_TEST_TAP_M	0xf47500ff
-
-/* EQU_I_TESTTAP_H */
-#define	R367CAB_EQU_I_TESTTAP_H	0xf476
-#define	F367CAB_I_TEST_TAP_H	0xf476001f
-
-/* EQU_TESTAP_CFG */
-#define	R367CAB_EQU_TESTAP_CFG	0xf477
-#define	F367CAB_TEST_FFE_DFE_SEL	0xf4770040
-#define	F367CAB_TEST_TAP_SELECT	0xf477003f
-
-/* EQU_Q_TESTTAP_L */
-#define	R367CAB_EQU_Q_TESTTAP_L	0xf478
-#define	F367CAB_Q_TEST_TAP_L	0xf47800ff
-
-/* EQU_Q_TESTTAP_M */
-#define	R367CAB_EQU_Q_TESTTAP_M	0xf479
-#define	F367CAB_Q_TEST_TAP_M	0xf47900ff
-
-/* EQU_Q_TESTTAP_H */
-#define	R367CAB_EQU_Q_TESTTAP_H	0xf47a
-#define	F367CAB_Q_TEST_TAP_H	0xf47a001f
-
-/* EQU_TAP_CTRL */
-#define	R367CAB_EQU_TAP_CTRL	0xf47b
-#define	F367CAB_MTAP_FRZ	0xf47b0010
-#define	F367CAB_PRE_FREEZE	0xf47b0008
-#define	F367CAB_DFE_TAPMON_EN	0xf47b0004
-#define	F367CAB_FFE_TAPMON_EN	0xf47b0002
-#define	F367CAB_MTAP_ONLY	0xf47b0001
-
-/* EQU_CTR_CRL_CONTROL_L */
-#define	R367CAB_EQU_CTR_CRL_CONTROL_L	0xf47c
-#define	F367CAB_EQU_CTR_CRL_CONTROL_LO	0xf47c00ff
-
-/* EQU_CTR_CRL_CONTROL_H */
-#define	R367CAB_EQU_CTR_CRL_CONTROL_H	0xf47d
-#define	F367CAB_EQU_CTR_CRL_CONTROL_HI	0xf47d00ff
-
-/* EQU_CTR_HIPOW_L */
-#define	R367CAB_EQU_CTR_HIPOW_L	0xf47e
-#define	F367CAB_CTR_HIPOW_L	0xf47e00ff
-
-/* EQU_CTR_HIPOW_H */
-#define	R367CAB_EQU_CTR_HIPOW_H	0xf47f
-#define	F367CAB_CTR_HIPOW_H	0xf47f00ff
-
-/* EQU_I_EQU_LO */
-#define	R367CAB_EQU_I_EQU_LO	0xf480
-#define	F367CAB_EQU_I_EQU_L	0xf48000ff
-
-/* EQU_I_EQU_HI */
-#define	R367CAB_EQU_I_EQU_HI	0xf481
-#define	F367CAB_EQU_I_EQU_H	0xf4810003
-
-/* EQU_Q_EQU_LO */
-#define	R367CAB_EQU_Q_EQU_LO	0xf482
-#define	F367CAB_EQU_Q_EQU_L	0xf48200ff
-
-/* EQU_Q_EQU_HI */
-#define	R367CAB_EQU_Q_EQU_HI	0xf483
-#define	F367CAB_EQU_Q_EQU_H	0xf4830003
-
-/* EQU_MAPPER */
-#define	R367CAB_EQU_MAPPER	0xf484
-#define	F367CAB_QUAD_AUTO	0xf4840080
-#define	F367CAB_QUAD_INV	0xf4840040
-#define	F367CAB_QAM_MODE	0xf4840007
-
-/* EQU_SWEEP_RATE */
-#define	R367CAB_EQU_SWEEP_RATE	0xf485
-#define	F367CAB_SNR_PER	0xf48500c0
-#define	F367CAB_SWEEP_RATE	0xf485003f
-
-/* EQU_SNR_LO */
-#define	R367CAB_EQU_SNR_LO	0xf486
-#define	F367CAB_SNR_LO	0xf48600ff
-
-/* EQU_SNR_HI */
-#define	R367CAB_EQU_SNR_HI	0xf487
-#define	F367CAB_SNR_HI	0xf48700ff
-
-/* EQU_GAMMA_LO */
-#define	R367CAB_EQU_GAMMA_LO	0xf488
-#define	F367CAB_GAMMA_LO	0xf48800ff
-
-/* EQU_GAMMA_HI */
-#define	R367CAB_EQU_GAMMA_HI	0xf489
-#define	F367CAB_GAMMA_ME	0xf48900ff
-
-/* EQU_ERR_GAIN */
-#define	R367CAB_EQU_ERR_GAIN	0xf48a
-#define	F367CAB_EQA1MU	0xf48a0070
-#define	F367CAB_CRL2MU	0xf48a000e
-#define	F367CAB_GAMMA_HI	0xf48a0001
-
-/* EQU_RADIUS */
-#define	R367CAB_EQU_RADIUS	0xf48b
-#define	F367CAB_RADIUS	0xf48b00ff
-
-/* EQU_FFE_MAINTAP */
-#define	R367CAB_EQU_FFE_MAINTAP	0xf48c
-#define	F367CAB_FFE_MAINTAP_INIT	0xf48c00ff
-
-/* EQU_FFE_LEAKAGE */
-#define	R367CAB_EQU_FFE_LEAKAGE	0xf48e
-#define	F367CAB_LEAK_PER	0xf48e00f0
-#define	F367CAB_EQU_OUTSEL	0xf48e0002
-#define	F367CAB_PNT2dFE	0xf48e0001
-
-/* EQU_FFE_MAINTAP_POS */
-#define	R367CAB_EQU_FFE_MAINTAP_POS	0xf48f
-#define	F367CAB_FFE_LEAK_EN	0xf48f0080
-#define	F367CAB_DFE_LEAK_EN	0xf48f0040
-#define	F367CAB_FFE_MAINTAP_POS	0xf48f003f
-
-/* EQU_GAIN_WIDE */
-#define	R367CAB_EQU_GAIN_WIDE	0xf490
-#define	F367CAB_DFE_GAIN_WIDE	0xf49000f0
-#define	F367CAB_FFE_GAIN_WIDE	0xf490000f
-
-/* EQU_GAIN_NARROW */
-#define	R367CAB_EQU_GAIN_NARROW	0xf491
-#define	F367CAB_DFE_GAIN_NARROW	0xf49100f0
-#define	F367CAB_FFE_GAIN_NARROW	0xf491000f
-
-/* EQU_CTR_LPF_GAIN */
-#define	R367CAB_EQU_CTR_LPF_GAIN	0xf492
-#define	F367CAB_CTR_GTO	0xf4920080
-#define	F367CAB_CTR_GDIR	0xf4920070
-#define	F367CAB_SWEEP_EN	0xf4920008
-#define	F367CAB_CTR_GINT	0xf4920007
-
-/* EQU_CRL_LPF_GAIN */
-#define	R367CAB_EQU_CRL_LPF_GAIN	0xf493
-#define	F367CAB_CRL_GTO	0xf4930080
-#define	F367CAB_CRL_GDIR	0xf4930070
-#define	F367CAB_SWEEP_DIR	0xf4930008
-#define	F367CAB_CRL_GINT	0xf4930007
-
-/* EQU_GLOBAL_GAIN */
-#define	R367CAB_EQU_GLOBAL_GAIN	0xf494
-#define	F367CAB_CRL_GAIN	0xf49400f8
-#define	F367CAB_CTR_INC_GAIN	0xf4940004
-#define	F367CAB_CTR_FRAC	0xf4940003
-
-/* EQU_CRL_LD_SEN */
-#define	R367CAB_EQU_CRL_LD_SEN	0xf495
-#define	F367CAB_CTR_BADPOINT_EN	0xf4950080
-#define	F367CAB_CTR_GAIN	0xf4950070
-#define	F367CAB_LIMANEN	0xf4950008
-#define	F367CAB_CRL_LD_SEN	0xf4950007
-
-/* EQU_CRL_LD_VAL */
-#define	R367CAB_EQU_CRL_LD_VAL	0xf496
-#define	F367CAB_CRL_BISTH_LIMIT	0xf4960080
-#define	F367CAB_CARE_EN	0xf4960040
-#define	F367CAB_CRL_LD_PER	0xf4960030
-#define	F367CAB_CRL_LD_WST	0xf496000c
-#define	F367CAB_CRL_LD_TFS	0xf4960003
-
-/* EQU_CRL_TFR */
-#define	R367CAB_EQU_CRL_TFR	0xf497
-#define	F367CAB_CRL_LD_TFR	0xf49700ff
-
-/* EQU_CRL_BISTH_LO */
-#define	R367CAB_EQU_CRL_BISTH_LO	0xf498
-#define	F367CAB_CRL_BISTH_LO	0xf49800ff
-
-/* EQU_CRL_BISTH_HI */
-#define	R367CAB_EQU_CRL_BISTH_HI	0xf499
-#define	F367CAB_CRL_BISTH_HI	0xf49900ff
-
-/* EQU_SWEEP_RANGE_LO */
-#define	R367CAB_EQU_SWEEP_RANGE_LO	0xf49a
-#define	F367CAB_SWEEP_RANGE_LO	0xf49a00ff
-
-/* EQU_SWEEP_RANGE_HI */
-#define	R367CAB_EQU_SWEEP_RANGE_HI	0xf49b
-#define	F367CAB_SWEEP_RANGE_HI	0xf49b00ff
-
-/* EQU_CRL_LIMITER */
-#define	R367CAB_EQU_CRL_LIMITER	0xf49c
-#define	F367CAB_BISECTOR_EN	0xf49c0080
-#define	F367CAB_PHEST128_EN	0xf49c0040
-#define	F367CAB_CRL_LIM	0xf49c003f
-
-/* EQU_MODULUS_MAP */
-#define	R367CAB_EQU_MODULUS_MAP	0xf49d
-#define	F367CAB_PNT_DEPTH	0xf49d00e0
-#define	F367CAB_MODULUS_CMP	0xf49d001f
-
-/* EQU_PNT_GAIN */
-#define	R367CAB_EQU_PNT_GAIN	0xf49e
-#define	F367CAB_PNT_EN	0xf49e0080
-#define	F367CAB_MODULUSMAP_EN	0xf49e0040
-#define	F367CAB_PNT_GAIN	0xf49e003f
-
-/* FEC_AC_CTR_0 */
-#define	R367CAB_FEC_AC_CTR_0	0xf4a8
-#define	F367CAB_BE_BYPASS	0xf4a80020
-#define	F367CAB_REFRESH47	0xf4a80010
-#define	F367CAB_CT_NBST	0xf4a80008
-#define	F367CAB_TEI_ENA	0xf4a80004
-#define	F367CAB_DS_ENA	0xf4a80002
-#define	F367CAB_TSMF_EN	0xf4a80001
-
-/* FEC_AC_CTR_1 */
-#define	R367CAB_FEC_AC_CTR_1	0xf4a9
-#define	F367CAB_DEINT_DEPTH	0xf4a900ff
-
-/* FEC_AC_CTR_2 */
-#define	R367CAB_FEC_AC_CTR_2	0xf4aa
-#define	F367CAB_DEINT_M	0xf4aa00f8
-#define	F367CAB_DIS_UNLOCK	0xf4aa0004
-#define	F367CAB_DESCR_MODE	0xf4aa0003
-
-/* FEC_AC_CTR_3 */
-#define	R367CAB_FEC_AC_CTR_3	0xf4ab
-#define	F367CAB_DI_UNLOCK	0xf4ab0080
-#define	F367CAB_DI_FREEZE	0xf4ab0040
-#define	F367CAB_MISMATCH	0xf4ab0030
-#define	F367CAB_ACQ_MODE	0xf4ab000c
-#define	F367CAB_TRK_MODE	0xf4ab0003
-
-/* FEC_STATUS */
-#define	R367CAB_FEC_STATUS	0xf4ac
-#define	F367CAB_DEINT_SMCNTR	0xf4ac00e0
-#define	F367CAB_DEINT_SYNCSTATE	0xf4ac0018
-#define	F367CAB_DEINT_SYNLOST	0xf4ac0004
-#define	F367CAB_DESCR_SYNCSTATE	0xf4ac0002
-
-/* RS_COUNTER_0 */
-#define	R367CAB_RS_COUNTER_0	0xf4ae
-#define	F367CAB_BK_CT_L	0xf4ae00ff
-
-/* RS_COUNTER_1 */
-#define	R367CAB_RS_COUNTER_1	0xf4af
-#define	F367CAB_BK_CT_H	0xf4af00ff
-
-/* RS_COUNTER_2 */
-#define	R367CAB_RS_COUNTER_2	0xf4b0
-#define	F367CAB_CORR_CT_L	0xf4b000ff
-
-/* RS_COUNTER_3 */
-#define	R367CAB_RS_COUNTER_3	0xf4b1
-#define	F367CAB_CORR_CT_H	0xf4b100ff
-
-/* RS_COUNTER_4 */
-#define	R367CAB_RS_COUNTER_4	0xf4b2
-#define	F367CAB_UNCORR_CT_L	0xf4b200ff
-
-/* RS_COUNTER_5 */
-#define	R367CAB_RS_COUNTER_5	0xf4b3
-#define	F367CAB_UNCORR_CT_H	0xf4b300ff
-
-/* BERT_0 */
-#define	R367CAB_BERT_0	0xf4b4
-#define	F367CAB_RS_NOCORR	0xf4b40004
-#define	F367CAB_CT_HOLD	0xf4b40002
-#define	F367CAB_CT_CLEAR	0xf4b40001
-
-/* BERT_1 */
-#define	R367CAB_BERT_1	0xf4b5
-#define	F367CAB_BERT_ON	0xf4b50020
-#define	F367CAB_BERT_ERR_SRC	0xf4b50010
-#define	F367CAB_BERT_ERR_MODE	0xf4b50008
-#define	F367CAB_BERT_NBYTE	0xf4b50007
-
-/* BERT_2 */
-#define	R367CAB_BERT_2	0xf4b6
-#define	F367CAB_BERT_ERRCOUNT_L	0xf4b600ff
-
-/* BERT_3 */
-#define	R367CAB_BERT_3	0xf4b7
-#define	F367CAB_BERT_ERRCOUNT_H	0xf4b700ff
-
-/* OUTFORMAT_0 */
-#define	R367CAB_OUTFORMAT_0	0xf4b8
-#define	F367CAB_CLK_POLARITY	0xf4b80080
-#define	F367CAB_FEC_TYPE	0xf4b80040
-#define	F367CAB_SYNC_STRIP	0xf4b80008
-#define	F367CAB_TS_SWAP	0xf4b80004
-#define	F367CAB_OUTFORMAT	0xf4b80003
-
-/* OUTFORMAT_1 */
-#define	R367CAB_OUTFORMAT_1	0xf4b9
-#define	F367CAB_CI_DIVRANGE	0xf4b900ff
-
-/* SMOOTHER_2 */
-#define	R367CAB_SMOOTHER_2	0xf4be
-#define	F367CAB_FIFO_BYPASS	0xf4be0020
-
-/* TSMF_CTRL_0 */
-#define	R367CAB_TSMF_CTRL_0	0xf4c0
-#define	F367CAB_TS_NUMBER	0xf4c0001e
-#define	F367CAB_SEL_MODE	0xf4c00001
-
-/* TSMF_CTRL_1 */
-#define	R367CAB_TSMF_CTRL_1	0xf4c1
-#define	F367CAB_CHECK_ERROR_BIT	0xf4c10080
-#define	F367CAB_CHCK_F_SYNC	0xf4c10040
-#define	F367CAB_H_MODE	0xf4c10008
-#define	F367CAB_D_V_MODE	0xf4c10004
-#define	F367CAB_MODE	0xf4c10003
-
-/* TSMF_CTRL_3 */
-#define	R367CAB_TSMF_CTRL_3	0xf4c3
-#define	F367CAB_SYNC_IN_COUNT	0xf4c300f0
-#define	F367CAB_SYNC_OUT_COUNT	0xf4c3000f
-
-/* TS_ON_ID_0 */
-#define	R367CAB_TS_ON_ID_0	0xf4c4
-#define	F367CAB_TS_ID_L	0xf4c400ff
-
-/* TS_ON_ID_1 */
-#define	R367CAB_TS_ON_ID_1	0xf4c5
-#define	F367CAB_TS_ID_H	0xf4c500ff
-
-/* TS_ON_ID_2 */
-#define	R367CAB_TS_ON_ID_2	0xf4c6
-#define	F367CAB_ON_ID_L	0xf4c600ff
-
-/* TS_ON_ID_3 */
-#define	R367CAB_TS_ON_ID_3	0xf4c7
-#define	F367CAB_ON_ID_H	0xf4c700ff
-
-/* RE_STATUS_0 */
-#define	R367CAB_RE_STATUS_0	0xf4c8
-#define	F367CAB_RECEIVE_STATUS_L	0xf4c800ff
-
-/* RE_STATUS_1 */
-#define	R367CAB_RE_STATUS_1	0xf4c9
-#define	F367CAB_RECEIVE_STATUS_LH	0xf4c900ff
-
-/* RE_STATUS_2 */
-#define	R367CAB_RE_STATUS_2	0xf4ca
-#define	F367CAB_RECEIVE_STATUS_HL	0xf4ca00ff
-
-/* RE_STATUS_3 */
-#define	R367CAB_RE_STATUS_3	0xf4cb
-#define	F367CAB_RECEIVE_STATUS_HH	0xf4cb003f
-
-/* TS_STATUS_0 */
-#define	R367CAB_TS_STATUS_0	0xf4cc
-#define	F367CAB_TS_STATUS_L	0xf4cc00ff
-
-/* TS_STATUS_1 */
-#define	R367CAB_TS_STATUS_1	0xf4cd
-#define	F367CAB_TS_STATUS_H	0xf4cd007f
-
-/* TS_STATUS_2 */
-#define	R367CAB_TS_STATUS_2	0xf4ce
-#define	F367CAB_ERROR	0xf4ce0080
-#define	F367CAB_EMERGENCY	0xf4ce0040
-#define	F367CAB_CRE_TS	0xf4ce0030
-#define	F367CAB_VER	0xf4ce000e
-#define	F367CAB_M_LOCK	0xf4ce0001
-
-/* TS_STATUS_3 */
-#define	R367CAB_TS_STATUS_3	0xf4cf
-#define	F367CAB_UPDATE_READY	0xf4cf0080
-#define	F367CAB_END_FRAME_HEADER	0xf4cf0040
-#define	F367CAB_CONTCNT	0xf4cf0020
-#define	F367CAB_TS_IDENTIFIER_SEL	0xf4cf000f
-
-/* T_O_ID_0 */
-#define	R367CAB_T_O_ID_0	0xf4d0
-#define	F367CAB_ON_ID_I_L	0xf4d000ff
-
-/* T_O_ID_1 */
-#define	R367CAB_T_O_ID_1	0xf4d1
-#define	F367CAB_ON_ID_I_H	0xf4d100ff
-
-/* T_O_ID_2 */
-#define	R367CAB_T_O_ID_2	0xf4d2
-#define	F367CAB_TS_ID_I_L	0xf4d200ff
-
-/* T_O_ID_3 */
-#define	R367CAB_T_O_ID_3	0xf4d3
-#define	F367CAB_TS_ID_I_H	0xf4d300ff
-
-#define STV0367CAB_NBREGS	187
-
-#endif
diff --git a/drivers/media/dvb/frontends/stv0900.h b/drivers/media/dvb/frontends/stv0900.h
deleted file mode 100644
index 91c7ee8..0000000
--- a/drivers/media/dvb/frontends/stv0900.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * stv0900.h
- *
- * Driver for ST STV0900 satellite demodulator IC.
- *
- * Copyright (C) ST Microelectronics.
- * Copyright (C) 2009 NetUP Inc.
- * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef STV0900_H
-#define STV0900_H
-
-#include <linux/dvb/frontend.h>
-#include "dvb_frontend.h"
-
-struct stv0900_reg {
-	u16 addr;
-	u8  val;
-};
-
-struct stv0900_config {
-	u8 demod_address;
-	u8 demod_mode;
-	u32 xtal;
-	u8 clkmode;/* 0 for CLKI,  2 for XTALI */
-
-	u8 diseqc_mode;
-
-	u8 path1_mode;
-	u8 path2_mode;
-	struct stv0900_reg *ts_config_regs;
-	u8 tun1_maddress;/* 0, 1, 2, 3 for 0xc0, 0xc2, 0xc4, 0xc6 */
-	u8 tun2_maddress;
-	u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */
-	u8 tun2_adc;
-	u8 tun1_type;/* for now 3 for stb6100 auto, else - software */
-	u8 tun2_type;
-	/* Set device param to start dma */
-	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
-	/* Hook for Lock LED */
-	void (*set_lock_led)(struct dvb_frontend *fe, int offon);
-};
-
-#if defined(CONFIG_DVB_STV0900) || (defined(CONFIG_DVB_STV0900_MODULE) \
-							&& defined(MODULE))
-extern struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
-					struct i2c_adapter *i2c, int demod);
-#else
-static inline struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
-					struct i2c_adapter *i2c, int demod)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif
-
diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c
deleted file mode 100644
index 7f1bada..0000000
--- a/drivers/media/dvb/frontends/stv0900_core.c
+++ /dev/null
@@ -1,1959 +0,0 @@
-/*
- * stv0900_core.c
- *
- * Driver for ST STV0900 satellite demodulator IC.
- *
- * Copyright (C) ST Microelectronics.
- * Copyright (C) 2009 NetUP Inc.
- * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-
-#include "stv0900.h"
-#include "stv0900_reg.h"
-#include "stv0900_priv.h"
-#include "stv0900_init.h"
-
-int stvdebug = 1;
-module_param_named(debug, stvdebug, int, 0644);
-
-/* internal params node */
-struct stv0900_inode {
-	/* pointer for internal params, one for each pair of demods */
-	struct stv0900_internal		*internal;
-	struct stv0900_inode		*next_inode;
-};
-
-/* first internal params */
-static struct stv0900_inode *stv0900_first_inode;
-
-/* find chip by i2c adapter and i2c address */
-static struct stv0900_inode *find_inode(struct i2c_adapter *i2c_adap,
-							u8 i2c_addr)
-{
-	struct stv0900_inode *temp_chip = stv0900_first_inode;
-
-	if (temp_chip != NULL) {
-		/*
-		 Search of the last stv0900 chip or
-		 find it by i2c adapter and i2c address */
-		while ((temp_chip != NULL) &&
-			((temp_chip->internal->i2c_adap != i2c_adap) ||
-			(temp_chip->internal->i2c_addr != i2c_addr)))
-
-			temp_chip = temp_chip->next_inode;
-
-	}
-
-	return temp_chip;
-}
-
-/* deallocating chip */
-static void remove_inode(struct stv0900_internal *internal)
-{
-	struct stv0900_inode *prev_node = stv0900_first_inode;
-	struct stv0900_inode *del_node = find_inode(internal->i2c_adap,
-						internal->i2c_addr);
-
-	if (del_node != NULL) {
-		if (del_node == stv0900_first_inode) {
-			stv0900_first_inode = del_node->next_inode;
-		} else {
-			while (prev_node->next_inode != del_node)
-				prev_node = prev_node->next_inode;
-
-			if (del_node->next_inode == NULL)
-				prev_node->next_inode = NULL;
-			else
-				prev_node->next_inode =
-					prev_node->next_inode->next_inode;
-		}
-
-		kfree(del_node);
-	}
-}
-
-/* allocating new chip */
-static struct stv0900_inode *append_internal(struct stv0900_internal *internal)
-{
-	struct stv0900_inode *new_node = stv0900_first_inode;
-
-	if (new_node == NULL) {
-		new_node = kmalloc(sizeof(struct stv0900_inode), GFP_KERNEL);
-		stv0900_first_inode = new_node;
-	} else {
-		while (new_node->next_inode != NULL)
-			new_node = new_node->next_inode;
-
-		new_node->next_inode = kmalloc(sizeof(struct stv0900_inode),
-								GFP_KERNEL);
-		if (new_node->next_inode != NULL)
-			new_node = new_node->next_inode;
-		else
-			new_node = NULL;
-	}
-
-	if (new_node != NULL) {
-		new_node->internal = internal;
-		new_node->next_inode = NULL;
-	}
-
-	return new_node;
-}
-
-s32 ge2comp(s32 a, s32 width)
-{
-	if (width == 32)
-		return a;
-	else
-		return (a >= (1 << (width - 1))) ? (a - (1 << width)) : a;
-}
-
-void stv0900_write_reg(struct stv0900_internal *intp, u16 reg_addr,
-								u8 reg_data)
-{
-	u8 data[3];
-	int ret;
-	struct i2c_msg i2cmsg = {
-		.addr  = intp->i2c_addr,
-		.flags = 0,
-		.len   = 3,
-		.buf   = data,
-	};
-
-	data[0] = MSB(reg_addr);
-	data[1] = LSB(reg_addr);
-	data[2] = reg_data;
-
-	ret = i2c_transfer(intp->i2c_adap, &i2cmsg, 1);
-	if (ret != 1)
-		dprintk("%s: i2c error %d\n", __func__, ret);
-}
-
-u8 stv0900_read_reg(struct stv0900_internal *intp, u16 reg)
-{
-	int ret;
-	u8 b0[] = { MSB(reg), LSB(reg) };
-	u8 buf = 0;
-	struct i2c_msg msg[] = {
-		{
-			.addr	= intp->i2c_addr,
-			.flags	= 0,
-			.buf = b0,
-			.len = 2,
-		}, {
-			.addr	= intp->i2c_addr,
-			.flags	= I2C_M_RD,
-			.buf = &buf,
-			.len = 1,
-		},
-	};
-
-	ret = i2c_transfer(intp->i2c_adap, msg, 2);
-	if (ret != 2)
-		dprintk("%s: i2c error %d, reg[0x%02x]\n",
-				__func__, ret, reg);
-
-	return buf;
-}
-
-static void extract_mask_pos(u32 label, u8 *mask, u8 *pos)
-{
-	u8 position = 0, i = 0;
-
-	(*mask) = label & 0xff;
-
-	while ((position == 0) && (i < 8)) {
-		position = ((*mask) >> i) & 0x01;
-		i++;
-	}
-
-	(*pos) = (i - 1);
-}
-
-void stv0900_write_bits(struct stv0900_internal *intp, u32 label, u8 val)
-{
-	u8 reg, mask, pos;
-
-	reg = stv0900_read_reg(intp, (label >> 16) & 0xffff);
-	extract_mask_pos(label, &mask, &pos);
-
-	val = mask & (val << pos);
-
-	reg = (reg & (~mask)) | val;
-	stv0900_write_reg(intp, (label >> 16) & 0xffff, reg);
-
-}
-
-u8 stv0900_get_bits(struct stv0900_internal *intp, u32 label)
-{
-	u8 val = 0xff;
-	u8 mask, pos;
-
-	extract_mask_pos(label, &mask, &pos);
-
-	val = stv0900_read_reg(intp, label >> 16);
-	val = (val & mask) >> pos;
-
-	return val;
-}
-
-static enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *intp)
-{
-	s32 i;
-
-	if (intp == NULL)
-		return STV0900_INVALID_HANDLE;
-
-	intp->chip_id = stv0900_read_reg(intp, R0900_MID);
-
-	if (intp->errs != STV0900_NO_ERROR)
-		return intp->errs;
-
-	/*Startup sequence*/
-	stv0900_write_reg(intp, R0900_P1_DMDISTATE, 0x5c);
-	stv0900_write_reg(intp, R0900_P2_DMDISTATE, 0x5c);
-	msleep(3);
-	stv0900_write_reg(intp, R0900_P1_TNRCFG, 0x6c);
-	stv0900_write_reg(intp, R0900_P2_TNRCFG, 0x6f);
-	stv0900_write_reg(intp, R0900_P1_I2CRPT, 0x20);
-	stv0900_write_reg(intp, R0900_P2_I2CRPT, 0x20);
-	stv0900_write_reg(intp, R0900_NCOARSE, 0x13);
-	msleep(3);
-	stv0900_write_reg(intp, R0900_I2CCFG, 0x08);
-
-	switch (intp->clkmode) {
-	case 0:
-	case 2:
-		stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20
-				| intp->clkmode);
-		break;
-	default:
-		/* preserve SELOSCI bit */
-		i = 0x02 & stv0900_read_reg(intp, R0900_SYNTCTRL);
-		stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20 | i);
-		break;
-	}
-
-	msleep(3);
-	for (i = 0; i < 181; i++)
-		stv0900_write_reg(intp, STV0900_InitVal[i][0],
-				STV0900_InitVal[i][1]);
-
-	if (stv0900_read_reg(intp, R0900_MID) >= 0x20) {
-		stv0900_write_reg(intp, R0900_TSGENERAL, 0x0c);
-		for (i = 0; i < 32; i++)
-			stv0900_write_reg(intp, STV0900_Cut20_AddOnVal[i][0],
-					STV0900_Cut20_AddOnVal[i][1]);
-	}
-
-	stv0900_write_reg(intp, R0900_P1_FSPYCFG, 0x6c);
-	stv0900_write_reg(intp, R0900_P2_FSPYCFG, 0x6c);
-
-	stv0900_write_reg(intp, R0900_P1_PDELCTRL2, 0x01);
-	stv0900_write_reg(intp, R0900_P2_PDELCTRL2, 0x21);
-
-	stv0900_write_reg(intp, R0900_P1_PDELCTRL3, 0x20);
-	stv0900_write_reg(intp, R0900_P2_PDELCTRL3, 0x20);
-
-	stv0900_write_reg(intp, R0900_TSTRES0, 0x80);
-	stv0900_write_reg(intp, R0900_TSTRES0, 0x00);
-
-	return STV0900_NO_ERROR;
-}
-
-static u32 stv0900_get_mclk_freq(struct stv0900_internal *intp, u32 ext_clk)
-{
-	u32 mclk = 90000000, div = 0, ad_div = 0;
-
-	div = stv0900_get_bits(intp, F0900_M_DIV);
-	ad_div = ((stv0900_get_bits(intp, F0900_SELX1RATIO) == 1) ? 4 : 6);
-
-	mclk = (div + 1) * ext_clk / ad_div;
-
-	dprintk("%s: Calculated Mclk = %d\n", __func__, mclk);
-
-	return mclk;
-}
-
-static enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *intp, u32 mclk)
-{
-	u32 m_div, clk_sel;
-
-	dprintk("%s: Mclk set to %d, Quartz = %d\n", __func__, mclk,
-			intp->quartz);
-
-	if (intp == NULL)
-		return STV0900_INVALID_HANDLE;
-
-	if (intp->errs)
-		return STV0900_I2C_ERROR;
-
-	clk_sel = ((stv0900_get_bits(intp, F0900_SELX1RATIO) == 1) ? 4 : 6);
-	m_div = ((clk_sel * mclk) / intp->quartz) - 1;
-	stv0900_write_bits(intp, F0900_M_DIV, m_div);
-	intp->mclk = stv0900_get_mclk_freq(intp,
-					intp->quartz);
-
-	/*Set the DiseqC frequency to 22KHz */
-	/*
-		Formula:
-		DiseqC_TX_Freq= MasterClock/(32*F22TX_Reg)
-		DiseqC_RX_Freq= MasterClock/(32*F22RX_Reg)
-	*/
-	m_div = intp->mclk / 704000;
-	stv0900_write_reg(intp, R0900_P1_F22TX, m_div);
-	stv0900_write_reg(intp, R0900_P1_F22RX, m_div);
-
-	stv0900_write_reg(intp, R0900_P2_F22TX, m_div);
-	stv0900_write_reg(intp, R0900_P2_F22RX, m_div);
-
-	if ((intp->errs))
-		return STV0900_I2C_ERROR;
-
-	return STV0900_NO_ERROR;
-}
-
-static u32 stv0900_get_err_count(struct stv0900_internal *intp, int cntr,
-					enum fe_stv0900_demod_num demod)
-{
-	u32 lsb, msb, hsb, err_val;
-
-	switch (cntr) {
-	case 0:
-	default:
-		hsb = stv0900_get_bits(intp, ERR_CNT12);
-		msb = stv0900_get_bits(intp, ERR_CNT11);
-		lsb = stv0900_get_bits(intp, ERR_CNT10);
-		break;
-	case 1:
-		hsb = stv0900_get_bits(intp, ERR_CNT22);
-		msb = stv0900_get_bits(intp, ERR_CNT21);
-		lsb = stv0900_get_bits(intp, ERR_CNT20);
-		break;
-	}
-
-	err_val = (hsb << 16) + (msb << 8) + (lsb);
-
-	return err_val;
-}
-
-static int stv0900_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-
-	stv0900_write_bits(intp, I2CT_ON, enable);
-
-	return 0;
-}
-
-static void stv0900_set_ts_parallel_serial(struct stv0900_internal *intp,
-					enum fe_stv0900_clock_type path1_ts,
-					enum fe_stv0900_clock_type path2_ts)
-{
-
-	dprintk("%s\n", __func__);
-
-	if (intp->chip_id >= 0x20) {
-		switch (path1_ts) {
-		case STV0900_PARALLEL_PUNCT_CLOCK:
-		case STV0900_DVBCI_CLOCK:
-			switch (path2_ts) {
-			case STV0900_SERIAL_PUNCT_CLOCK:
-			case STV0900_SERIAL_CONT_CLOCK:
-			default:
-				stv0900_write_reg(intp, R0900_TSGENERAL,
-							0x00);
-				break;
-			case STV0900_PARALLEL_PUNCT_CLOCK:
-			case STV0900_DVBCI_CLOCK:
-				stv0900_write_reg(intp, R0900_TSGENERAL,
-							0x06);
-				stv0900_write_bits(intp,
-						F0900_P1_TSFIFO_MANSPEED, 3);
-				stv0900_write_bits(intp,
-						F0900_P2_TSFIFO_MANSPEED, 0);
-				stv0900_write_reg(intp,
-						R0900_P1_TSSPEED, 0x14);
-				stv0900_write_reg(intp,
-						R0900_P2_TSSPEED, 0x28);
-				break;
-			}
-			break;
-		case STV0900_SERIAL_PUNCT_CLOCK:
-		case STV0900_SERIAL_CONT_CLOCK:
-		default:
-			switch (path2_ts) {
-			case STV0900_SERIAL_PUNCT_CLOCK:
-			case STV0900_SERIAL_CONT_CLOCK:
-			default:
-				stv0900_write_reg(intp,
-						R0900_TSGENERAL, 0x0C);
-				break;
-			case STV0900_PARALLEL_PUNCT_CLOCK:
-			case STV0900_DVBCI_CLOCK:
-				stv0900_write_reg(intp,
-						R0900_TSGENERAL, 0x0A);
-				dprintk("%s: 0x0a\n", __func__);
-				break;
-			}
-			break;
-		}
-	} else {
-		switch (path1_ts) {
-		case STV0900_PARALLEL_PUNCT_CLOCK:
-		case STV0900_DVBCI_CLOCK:
-			switch (path2_ts) {
-			case STV0900_SERIAL_PUNCT_CLOCK:
-			case STV0900_SERIAL_CONT_CLOCK:
-			default:
-				stv0900_write_reg(intp, R0900_TSGENERAL1X,
-							0x10);
-				break;
-			case STV0900_PARALLEL_PUNCT_CLOCK:
-			case STV0900_DVBCI_CLOCK:
-				stv0900_write_reg(intp, R0900_TSGENERAL1X,
-							0x16);
-				stv0900_write_bits(intp,
-						F0900_P1_TSFIFO_MANSPEED, 3);
-				stv0900_write_bits(intp,
-						F0900_P2_TSFIFO_MANSPEED, 0);
-				stv0900_write_reg(intp, R0900_P1_TSSPEED,
-							0x14);
-				stv0900_write_reg(intp, R0900_P2_TSSPEED,
-							0x28);
-				break;
-			}
-
-			break;
-		case STV0900_SERIAL_PUNCT_CLOCK:
-		case STV0900_SERIAL_CONT_CLOCK:
-		default:
-			switch (path2_ts) {
-			case STV0900_SERIAL_PUNCT_CLOCK:
-			case STV0900_SERIAL_CONT_CLOCK:
-			default:
-				stv0900_write_reg(intp, R0900_TSGENERAL1X,
-							0x14);
-				break;
-			case STV0900_PARALLEL_PUNCT_CLOCK:
-			case STV0900_DVBCI_CLOCK:
-				stv0900_write_reg(intp, R0900_TSGENERAL1X,
-							0x12);
-				dprintk("%s: 0x12\n", __func__);
-				break;
-			}
-
-			break;
-		}
-	}
-
-	switch (path1_ts) {
-	case STV0900_PARALLEL_PUNCT_CLOCK:
-		stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x00);
-		stv0900_write_bits(intp, F0900_P1_TSFIFO_DVBCI, 0x00);
-		break;
-	case STV0900_DVBCI_CLOCK:
-		stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x00);
-		stv0900_write_bits(intp, F0900_P1_TSFIFO_DVBCI, 0x01);
-		break;
-	case STV0900_SERIAL_PUNCT_CLOCK:
-		stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x01);
-		stv0900_write_bits(intp, F0900_P1_TSFIFO_DVBCI, 0x00);
-		break;
-	case STV0900_SERIAL_CONT_CLOCK:
-		stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x01);
-		stv0900_write_bits(intp, F0900_P1_TSFIFO_DVBCI, 0x01);
-		break;
-	default:
-		break;
-	}
-
-	switch (path2_ts) {
-	case STV0900_PARALLEL_PUNCT_CLOCK:
-		stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x00);
-		stv0900_write_bits(intp, F0900_P2_TSFIFO_DVBCI, 0x00);
-		break;
-	case STV0900_DVBCI_CLOCK:
-		stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x00);
-		stv0900_write_bits(intp, F0900_P2_TSFIFO_DVBCI, 0x01);
-		break;
-	case STV0900_SERIAL_PUNCT_CLOCK:
-		stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x01);
-		stv0900_write_bits(intp, F0900_P2_TSFIFO_DVBCI, 0x00);
-		break;
-	case STV0900_SERIAL_CONT_CLOCK:
-		stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x01);
-		stv0900_write_bits(intp, F0900_P2_TSFIFO_DVBCI, 0x01);
-		break;
-	default:
-		break;
-	}
-
-	stv0900_write_bits(intp, F0900_P2_RST_HWARE, 1);
-	stv0900_write_bits(intp, F0900_P2_RST_HWARE, 0);
-	stv0900_write_bits(intp, F0900_P1_RST_HWARE, 1);
-	stv0900_write_bits(intp, F0900_P1_RST_HWARE, 0);
-}
-
-void stv0900_set_tuner(struct dvb_frontend *fe, u32 frequency,
-							u32 bandwidth)
-{
-	struct dvb_frontend_ops *frontend_ops = NULL;
-	struct dvb_tuner_ops *tuner_ops = NULL;
-
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
-
-	if (tuner_ops->set_frequency) {
-		if ((tuner_ops->set_frequency(fe, frequency)) < 0)
-			dprintk("%s: Invalid parameter\n", __func__);
-		else
-			dprintk("%s: Frequency=%d\n", __func__, frequency);
-
-	}
-
-	if (tuner_ops->set_bandwidth) {
-		if ((tuner_ops->set_bandwidth(fe, bandwidth)) < 0)
-			dprintk("%s: Invalid parameter\n", __func__);
-		else
-			dprintk("%s: Bandwidth=%d\n", __func__, bandwidth);
-
-	}
-}
-
-void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
-{
-	struct dvb_frontend_ops *frontend_ops = NULL;
-	struct dvb_tuner_ops *tuner_ops = NULL;
-
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
-
-	if (tuner_ops->set_bandwidth) {
-		if ((tuner_ops->set_bandwidth(fe, bandwidth)) < 0)
-			dprintk("%s: Invalid parameter\n", __func__);
-		else
-			dprintk("%s: Bandwidth=%d\n", __func__, bandwidth);
-
-	}
-}
-
-u32 stv0900_get_freq_auto(struct stv0900_internal *intp, int demod)
-{
-	u32 freq, round;
-	/*	Formulat :
-	Tuner_Frequency(MHz)	= Regs / 64
-	Tuner_granularity(MHz)	= Regs / 2048
-	real_Tuner_Frequency	= Tuner_Frequency(MHz) - Tuner_granularity(MHz)
-	*/
-	freq = (stv0900_get_bits(intp, TUN_RFFREQ2) << 10) +
-		(stv0900_get_bits(intp, TUN_RFFREQ1) << 2) +
-		stv0900_get_bits(intp, TUN_RFFREQ0);
-
-	freq = (freq * 1000) / 64;
-
-	round = (stv0900_get_bits(intp, TUN_RFRESTE1) >> 2) +
-		stv0900_get_bits(intp, TUN_RFRESTE0);
-
-	round = (round * 1000) / 2048;
-
-	return freq + round;
-}
-
-void stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency,
-						u32 Bandwidth, int demod)
-{
-	u32 tunerFrequency;
-	/* Formulat:
-	Tuner_frequency_reg= Frequency(MHz)*64
-	*/
-	tunerFrequency = (Frequency * 64) / 1000;
-
-	stv0900_write_bits(intp, TUN_RFFREQ2, (tunerFrequency >> 10));
-	stv0900_write_bits(intp, TUN_RFFREQ1, (tunerFrequency >> 2) & 0xff);
-	stv0900_write_bits(intp, TUN_RFFREQ0, (tunerFrequency & 0x03));
-	/* Low Pass Filter = BW /2 (MHz)*/
-	stv0900_write_bits(intp, TUN_BW, Bandwidth / 2000000);
-	/* Tuner Write trig */
-	stv0900_write_reg(intp, TNRLD, 1);
-}
-
-static s32 stv0900_get_rf_level(struct stv0900_internal *intp,
-				const struct stv0900_table *lookup,
-				enum fe_stv0900_demod_num demod)
-{
-	s32 agc_gain = 0,
-		imin,
-		imax,
-		i,
-		rf_lvl = 0;
-
-	dprintk("%s\n", __func__);
-
-	if ((lookup == NULL) || (lookup->size <= 0))
-		return 0;
-
-	agc_gain = MAKEWORD(stv0900_get_bits(intp, AGCIQ_VALUE1),
-				stv0900_get_bits(intp, AGCIQ_VALUE0));
-
-	imin = 0;
-	imax = lookup->size - 1;
-	if (INRANGE(lookup->table[imin].regval, agc_gain,
-					lookup->table[imax].regval)) {
-		while ((imax - imin) > 1) {
-			i = (imax + imin) >> 1;
-
-			if (INRANGE(lookup->table[imin].regval,
-					agc_gain,
-					lookup->table[i].regval))
-				imax = i;
-			else
-				imin = i;
-		}
-
-		rf_lvl = (s32)agc_gain - lookup->table[imin].regval;
-		rf_lvl *= (lookup->table[imax].realval -
-				lookup->table[imin].realval);
-		rf_lvl /= (lookup->table[imax].regval -
-				lookup->table[imin].regval);
-		rf_lvl += lookup->table[imin].realval;
-	} else if (agc_gain > lookup->table[0].regval)
-		rf_lvl = 5;
-	else if (agc_gain < lookup->table[lookup->size-1].regval)
-		rf_lvl = -100;
-
-	dprintk("%s: RFLevel = %d\n", __func__, rf_lvl);
-
-	return rf_lvl;
-}
-
-static int stv0900_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *internal = state->internal;
-	s32 rflevel = stv0900_get_rf_level(internal, &stv0900_rf,
-								state->demod);
-
-	rflevel = (rflevel + 100) * (65535 / 70);
-	if (rflevel < 0)
-		rflevel = 0;
-
-	if (rflevel > 65535)
-		rflevel = 65535;
-
-	*strength = rflevel;
-
-	return 0;
-}
-
-static s32 stv0900_carr_get_quality(struct dvb_frontend *fe,
-					const struct stv0900_table *lookup)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-
-	s32	c_n = -100,
-		regval,
-		imin,
-		imax,
-		i,
-		noise_field1,
-		noise_field0;
-
-	dprintk("%s\n", __func__);
-
-	if (stv0900_get_standard(fe, demod) == STV0900_DVBS2_STANDARD) {
-		noise_field1 = NOSPLHT_NORMED1;
-		noise_field0 = NOSPLHT_NORMED0;
-	} else {
-		noise_field1 = NOSDATAT_NORMED1;
-		noise_field0 = NOSDATAT_NORMED0;
-	}
-
-	if (stv0900_get_bits(intp, LOCK_DEFINITIF)) {
-		if ((lookup != NULL) && lookup->size) {
-			regval = 0;
-			msleep(5);
-			for (i = 0; i < 16; i++) {
-				regval += MAKEWORD(stv0900_get_bits(intp,
-								noise_field1),
-						stv0900_get_bits(intp,
-								noise_field0));
-				msleep(1);
-			}
-
-			regval /= 16;
-			imin = 0;
-			imax = lookup->size - 1;
-			if (INRANGE(lookup->table[imin].regval,
-					regval,
-					lookup->table[imax].regval)) {
-				while ((imax - imin) > 1) {
-					i = (imax + imin) >> 1;
-					if (INRANGE(lookup->table[imin].regval,
-						    regval,
-						    lookup->table[i].regval))
-						imax = i;
-					else
-						imin = i;
-				}
-
-				c_n = ((regval - lookup->table[imin].regval)
-						* (lookup->table[imax].realval
-						- lookup->table[imin].realval)
-						/ (lookup->table[imax].regval
-						- lookup->table[imin].regval))
-						+ lookup->table[imin].realval;
-			} else if (regval < lookup->table[imin].regval)
-				c_n = 1000;
-		}
-	}
-
-	return c_n;
-}
-
-static int stv0900_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-	u8 err_val1, err_val0;
-	u32 header_err_val = 0;
-
-	*ucblocks = 0x0;
-	if (stv0900_get_standard(fe, demod) == STV0900_DVBS2_STANDARD) {
-		/* DVB-S2 delineator errors count */
-
-		/* retreiving number for errnous headers */
-		err_val1 = stv0900_read_reg(intp, BBFCRCKO1);
-		err_val0 = stv0900_read_reg(intp, BBFCRCKO0);
-		header_err_val = (err_val1 << 8) | err_val0;
-
-		/* retreiving number for errnous packets */
-		err_val1 = stv0900_read_reg(intp, UPCRCKO1);
-		err_val0 = stv0900_read_reg(intp, UPCRCKO0);
-		*ucblocks = (err_val1 << 8) | err_val0;
-		*ucblocks += header_err_val;
-	}
-
-	return 0;
-}
-
-static int stv0900_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	s32 snrlcl = stv0900_carr_get_quality(fe,
-			(const struct stv0900_table *)&stv0900_s2_cn);
-	snrlcl = (snrlcl + 30) * 384;
-	if (snrlcl < 0)
-		snrlcl = 0;
-
-	if (snrlcl > 65535)
-		snrlcl = 65535;
-
-	*snr = snrlcl;
-
-	return 0;
-}
-
-static u32 stv0900_get_ber(struct stv0900_internal *intp,
-				enum fe_stv0900_demod_num demod)
-{
-	u32 ber = 10000000, i;
-	s32 demod_state;
-
-	demod_state = stv0900_get_bits(intp, HEADER_MODE);
-
-	switch (demod_state) {
-	case STV0900_SEARCH:
-	case STV0900_PLH_DETECTED:
-	default:
-		ber = 10000000;
-		break;
-	case STV0900_DVBS_FOUND:
-		ber = 0;
-		for (i = 0; i < 5; i++) {
-			msleep(5);
-			ber += stv0900_get_err_count(intp, 0, demod);
-		}
-
-		ber /= 5;
-		if (stv0900_get_bits(intp, PRFVIT)) {
-			ber *= 9766;
-			ber = ber >> 13;
-		}
-
-		break;
-	case STV0900_DVBS2_FOUND:
-		ber = 0;
-		for (i = 0; i < 5; i++) {
-			msleep(5);
-			ber += stv0900_get_err_count(intp, 0, demod);
-		}
-
-		ber /= 5;
-		if (stv0900_get_bits(intp, PKTDELIN_LOCK)) {
-			ber *= 9766;
-			ber = ber >> 13;
-		}
-
-		break;
-	}
-
-	return ber;
-}
-
-static int stv0900_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *internal = state->internal;
-
-	*ber = stv0900_get_ber(internal, state->demod);
-
-	return 0;
-}
-
-int stv0900_get_demod_lock(struct stv0900_internal *intp,
-			enum fe_stv0900_demod_num demod, s32 time_out)
-{
-	s32 timer = 0,
-		lock = 0;
-
-	enum fe_stv0900_search_state	dmd_state;
-
-	while ((timer < time_out) && (lock == 0)) {
-		dmd_state = stv0900_get_bits(intp, HEADER_MODE);
-		dprintk("Demod State = %d\n", dmd_state);
-		switch (dmd_state) {
-		case STV0900_SEARCH:
-		case STV0900_PLH_DETECTED:
-		default:
-			lock = 0;
-			break;
-		case STV0900_DVBS2_FOUND:
-		case STV0900_DVBS_FOUND:
-			lock = stv0900_get_bits(intp, LOCK_DEFINITIF);
-			break;
-		}
-
-		if (lock == 0)
-			msleep(10);
-
-		timer += 10;
-	}
-
-	if (lock)
-		dprintk("DEMOD LOCK OK\n");
-	else
-		dprintk("DEMOD LOCK FAIL\n");
-
-	return lock;
-}
-
-void stv0900_stop_all_s2_modcod(struct stv0900_internal *intp,
-				enum fe_stv0900_demod_num demod)
-{
-	s32 regflist,
-	i;
-
-	dprintk("%s\n", __func__);
-
-	regflist = MODCODLST0;
-
-	for (i = 0; i < 16; i++)
-		stv0900_write_reg(intp, regflist + i, 0xff);
-}
-
-void stv0900_activate_s2_modcod(struct stv0900_internal *intp,
-				enum fe_stv0900_demod_num demod)
-{
-	u32 matype,
-		mod_code,
-		fmod,
-		reg_index,
-		field_index;
-
-	dprintk("%s\n", __func__);
-
-	if (intp->chip_id <= 0x11) {
-		msleep(5);
-
-		mod_code = stv0900_read_reg(intp, PLHMODCOD);
-		matype = mod_code & 0x3;
-		mod_code = (mod_code & 0x7f) >> 2;
-
-		reg_index = MODCODLSTF - mod_code / 2;
-		field_index = mod_code % 2;
-
-		switch (matype) {
-		case 0:
-		default:
-			fmod = 14;
-			break;
-		case 1:
-			fmod = 13;
-			break;
-		case 2:
-			fmod = 11;
-			break;
-		case 3:
-			fmod = 7;
-			break;
-		}
-
-		if ((INRANGE(STV0900_QPSK_12, mod_code, STV0900_8PSK_910))
-						&& (matype <= 1)) {
-			if (field_index == 0)
-				stv0900_write_reg(intp, reg_index,
-							0xf0 | fmod);
-			else
-				stv0900_write_reg(intp, reg_index,
-							(fmod << 4) | 0xf);
-		}
-
-	} else if (intp->chip_id >= 0x12) {
-		for (reg_index = 0; reg_index < 7; reg_index++)
-			stv0900_write_reg(intp, MODCODLST0 + reg_index, 0xff);
-
-		stv0900_write_reg(intp, MODCODLSTE, 0xff);
-		stv0900_write_reg(intp, MODCODLSTF, 0xcf);
-		for (reg_index = 0; reg_index < 8; reg_index++)
-			stv0900_write_reg(intp, MODCODLST7 + reg_index, 0xcc);
-
-
-	}
-}
-
-void stv0900_activate_s2_modcod_single(struct stv0900_internal *intp,
-					enum fe_stv0900_demod_num demod)
-{
-	u32 reg_index;
-
-	dprintk("%s\n", __func__);
-
-	stv0900_write_reg(intp, MODCODLST0, 0xff);
-	stv0900_write_reg(intp, MODCODLST1, 0xf0);
-	stv0900_write_reg(intp, MODCODLSTF, 0x0f);
-	for (reg_index = 0; reg_index < 13; reg_index++)
-		stv0900_write_reg(intp, MODCODLST2 + reg_index, 0);
-
-}
-
-static enum dvbfe_algo stv0900_frontend_algo(struct dvb_frontend *fe)
-{
-	return DVBFE_ALGO_CUSTOM;
-}
-
-void stv0900_start_search(struct stv0900_internal *intp,
-				enum fe_stv0900_demod_num demod)
-{
-	u32 freq;
-	s16 freq_s16 ;
-
-	stv0900_write_bits(intp, DEMOD_MODE, 0x1f);
-	if (intp->chip_id == 0x10)
-		stv0900_write_reg(intp, CORRELEXP, 0xaa);
-
-	if (intp->chip_id < 0x20)
-		stv0900_write_reg(intp, CARHDR, 0x55);
-
-	if (intp->chip_id <= 0x20) {
-		if (intp->symbol_rate[0] <= 5000000) {
-			stv0900_write_reg(intp, CARCFG, 0x44);
-			stv0900_write_reg(intp, CFRUP1, 0x0f);
-			stv0900_write_reg(intp, CFRUP0, 0xff);
-			stv0900_write_reg(intp, CFRLOW1, 0xf0);
-			stv0900_write_reg(intp, CFRLOW0, 0x00);
-			stv0900_write_reg(intp, RTCS2, 0x68);
-		} else {
-			stv0900_write_reg(intp, CARCFG, 0xc4);
-			stv0900_write_reg(intp, RTCS2, 0x44);
-		}
-
-	} else { /*cut 3.0 above*/
-		if (intp->symbol_rate[demod] <= 5000000)
-			stv0900_write_reg(intp, RTCS2, 0x68);
-		else
-			stv0900_write_reg(intp, RTCS2, 0x44);
-
-		stv0900_write_reg(intp, CARCFG, 0x46);
-		if (intp->srch_algo[demod] == STV0900_WARM_START) {
-			freq = 1000 << 16;
-			freq /= (intp->mclk / 1000);
-			freq_s16 = (s16)freq;
-		} else {
-			freq = (intp->srch_range[demod] / 2000);
-			if (intp->symbol_rate[demod] <= 5000000)
-				freq += 80;
-			else
-				freq += 600;
-
-			freq = freq << 16;
-			freq /= (intp->mclk / 1000);
-			freq_s16 = (s16)freq;
-		}
-
-		stv0900_write_bits(intp, CFR_UP1, MSB(freq_s16));
-		stv0900_write_bits(intp, CFR_UP0, LSB(freq_s16));
-		freq_s16 *= (-1);
-		stv0900_write_bits(intp, CFR_LOW1, MSB(freq_s16));
-		stv0900_write_bits(intp, CFR_LOW0, LSB(freq_s16));
-	}
-
-	stv0900_write_reg(intp, CFRINIT1, 0);
-	stv0900_write_reg(intp, CFRINIT0, 0);
-
-	if (intp->chip_id >= 0x20) {
-		stv0900_write_reg(intp, EQUALCFG, 0x41);
-		stv0900_write_reg(intp, FFECFG, 0x41);
-
-		if ((intp->srch_standard[demod] == STV0900_SEARCH_DVBS1) ||
-			(intp->srch_standard[demod] == STV0900_SEARCH_DSS) ||
-			(intp->srch_standard[demod] == STV0900_AUTO_SEARCH)) {
-			stv0900_write_reg(intp, VITSCALE,
-								0x82);
-			stv0900_write_reg(intp, VAVSRVIT, 0x0);
-		}
-	}
-
-	stv0900_write_reg(intp, SFRSTEP, 0x00);
-	stv0900_write_reg(intp, TMGTHRISE, 0xe0);
-	stv0900_write_reg(intp, TMGTHFALL, 0xc0);
-	stv0900_write_bits(intp, SCAN_ENABLE, 0);
-	stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
-	stv0900_write_bits(intp, S1S2_SEQUENTIAL, 0);
-	stv0900_write_reg(intp, RTC, 0x88);
-	if (intp->chip_id >= 0x20) {
-		if (intp->symbol_rate[demod] < 2000000) {
-			if (intp->chip_id <= 0x20)
-				stv0900_write_reg(intp, CARFREQ, 0x39);
-			else  /*cut 3.0*/
-				stv0900_write_reg(intp, CARFREQ, 0x89);
-
-			stv0900_write_reg(intp, CARHDR, 0x40);
-		} else if (intp->symbol_rate[demod] < 10000000) {
-			stv0900_write_reg(intp, CARFREQ, 0x4c);
-			stv0900_write_reg(intp, CARHDR, 0x20);
-		} else {
-			stv0900_write_reg(intp, CARFREQ, 0x4b);
-			stv0900_write_reg(intp, CARHDR, 0x20);
-		}
-
-	} else {
-		if (intp->symbol_rate[demod] < 10000000)
-			stv0900_write_reg(intp, CARFREQ, 0xef);
-		else
-			stv0900_write_reg(intp, CARFREQ, 0xed);
-	}
-
-	switch (intp->srch_algo[demod]) {
-	case STV0900_WARM_START:
-		stv0900_write_reg(intp, DMDISTATE, 0x1f);
-		stv0900_write_reg(intp, DMDISTATE, 0x18);
-		break;
-	case STV0900_COLD_START:
-		stv0900_write_reg(intp, DMDISTATE, 0x1f);
-		stv0900_write_reg(intp, DMDISTATE, 0x15);
-		break;
-	default:
-		break;
-	}
-}
-
-u8 stv0900_get_optim_carr_loop(s32 srate, enum fe_stv0900_modcode modcode,
-							s32 pilot, u8 chip_id)
-{
-	u8 aclc_value = 0x29;
-	s32 i;
-	const struct stv0900_car_loop_optim *cls2, *cllqs2, *cllas2;
-
-	dprintk("%s\n", __func__);
-
-	if (chip_id <= 0x12) {
-		cls2 = FE_STV0900_S2CarLoop;
-		cllqs2 = FE_STV0900_S2LowQPCarLoopCut30;
-		cllas2 = FE_STV0900_S2APSKCarLoopCut30;
-	} else if (chip_id == 0x20) {
-		cls2 = FE_STV0900_S2CarLoopCut20;
-		cllqs2 = FE_STV0900_S2LowQPCarLoopCut20;
-		cllas2 = FE_STV0900_S2APSKCarLoopCut20;
-	} else {
-		cls2 = FE_STV0900_S2CarLoopCut30;
-		cllqs2 = FE_STV0900_S2LowQPCarLoopCut30;
-		cllas2 = FE_STV0900_S2APSKCarLoopCut30;
-	}
-
-	if (modcode < STV0900_QPSK_12) {
-		i = 0;
-		while ((i < 3) && (modcode != cllqs2[i].modcode))
-			i++;
-
-		if (i >= 3)
-			i = 2;
-	} else {
-		i = 0;
-		while ((i < 14) && (modcode != cls2[i].modcode))
-			i++;
-
-		if (i >= 14) {
-			i = 0;
-			while ((i < 11) && (modcode != cllas2[i].modcode))
-				i++;
-
-			if (i >= 11)
-				i = 10;
-		}
-	}
-
-	if (modcode <= STV0900_QPSK_25) {
-		if (pilot) {
-			if (srate <= 3000000)
-				aclc_value = cllqs2[i].car_loop_pilots_on_2;
-			else if (srate <= 7000000)
-				aclc_value = cllqs2[i].car_loop_pilots_on_5;
-			else if (srate <= 15000000)
-				aclc_value = cllqs2[i].car_loop_pilots_on_10;
-			else if (srate <= 25000000)
-				aclc_value = cllqs2[i].car_loop_pilots_on_20;
-			else
-				aclc_value = cllqs2[i].car_loop_pilots_on_30;
-		} else {
-			if (srate <= 3000000)
-				aclc_value = cllqs2[i].car_loop_pilots_off_2;
-			else if (srate <= 7000000)
-				aclc_value = cllqs2[i].car_loop_pilots_off_5;
-			else if (srate <= 15000000)
-				aclc_value = cllqs2[i].car_loop_pilots_off_10;
-			else if (srate <= 25000000)
-				aclc_value = cllqs2[i].car_loop_pilots_off_20;
-			else
-				aclc_value = cllqs2[i].car_loop_pilots_off_30;
-		}
-
-	} else if (modcode <= STV0900_8PSK_910) {
-		if (pilot) {
-			if (srate <= 3000000)
-				aclc_value = cls2[i].car_loop_pilots_on_2;
-			else if (srate <= 7000000)
-				aclc_value = cls2[i].car_loop_pilots_on_5;
-			else if (srate <= 15000000)
-				aclc_value = cls2[i].car_loop_pilots_on_10;
-			else if (srate <= 25000000)
-				aclc_value = cls2[i].car_loop_pilots_on_20;
-			else
-				aclc_value = cls2[i].car_loop_pilots_on_30;
-		} else {
-			if (srate <= 3000000)
-				aclc_value = cls2[i].car_loop_pilots_off_2;
-			else if (srate <= 7000000)
-				aclc_value = cls2[i].car_loop_pilots_off_5;
-			else if (srate <= 15000000)
-				aclc_value = cls2[i].car_loop_pilots_off_10;
-			else if (srate <= 25000000)
-				aclc_value = cls2[i].car_loop_pilots_off_20;
-			else
-				aclc_value = cls2[i].car_loop_pilots_off_30;
-		}
-
-	} else {
-		if (srate <= 3000000)
-			aclc_value = cllas2[i].car_loop_pilots_on_2;
-		else if (srate <= 7000000)
-			aclc_value = cllas2[i].car_loop_pilots_on_5;
-		else if (srate <= 15000000)
-			aclc_value = cllas2[i].car_loop_pilots_on_10;
-		else if (srate <= 25000000)
-			aclc_value = cllas2[i].car_loop_pilots_on_20;
-		else
-			aclc_value = cllas2[i].car_loop_pilots_on_30;
-	}
-
-	return aclc_value;
-}
-
-u8 stv0900_get_optim_short_carr_loop(s32 srate,
-				enum fe_stv0900_modulation modulation,
-				u8 chip_id)
-{
-	const struct stv0900_short_frames_car_loop_optim *s2scl;
-	const struct stv0900_short_frames_car_loop_optim_vs_mod *s2sclc30;
-	s32 mod_index = 0;
-	u8 aclc_value = 0x0b;
-
-	dprintk("%s\n", __func__);
-
-	s2scl = FE_STV0900_S2ShortCarLoop;
-	s2sclc30 = FE_STV0900_S2ShortCarLoopCut30;
-
-	switch (modulation) {
-	case STV0900_QPSK:
-	default:
-		mod_index = 0;
-		break;
-	case STV0900_8PSK:
-		mod_index = 1;
-		break;
-	case STV0900_16APSK:
-		mod_index = 2;
-		break;
-	case STV0900_32APSK:
-		mod_index = 3;
-		break;
-	}
-
-	if (chip_id >= 0x30) {
-		if (srate <= 3000000)
-			aclc_value = s2sclc30[mod_index].car_loop_2;
-		else if (srate <= 7000000)
-			aclc_value = s2sclc30[mod_index].car_loop_5;
-		else if (srate <= 15000000)
-			aclc_value = s2sclc30[mod_index].car_loop_10;
-		else if (srate <= 25000000)
-			aclc_value = s2sclc30[mod_index].car_loop_20;
-		else
-			aclc_value = s2sclc30[mod_index].car_loop_30;
-
-	} else if (chip_id >= 0x20) {
-		if (srate <= 3000000)
-			aclc_value = s2scl[mod_index].car_loop_cut20_2;
-		else if (srate <= 7000000)
-			aclc_value = s2scl[mod_index].car_loop_cut20_5;
-		else if (srate <= 15000000)
-			aclc_value = s2scl[mod_index].car_loop_cut20_10;
-		else if (srate <= 25000000)
-			aclc_value = s2scl[mod_index].car_loop_cut20_20;
-		else
-			aclc_value = s2scl[mod_index].car_loop_cut20_30;
-
-	} else {
-		if (srate <= 3000000)
-			aclc_value = s2scl[mod_index].car_loop_cut12_2;
-		else if (srate <= 7000000)
-			aclc_value = s2scl[mod_index].car_loop_cut12_5;
-		else if (srate <= 15000000)
-			aclc_value = s2scl[mod_index].car_loop_cut12_10;
-		else if (srate <= 25000000)
-			aclc_value = s2scl[mod_index].car_loop_cut12_20;
-		else
-			aclc_value = s2scl[mod_index].car_loop_cut12_30;
-
-	}
-
-	return aclc_value;
-}
-
-static
-enum fe_stv0900_error stv0900_st_dvbs2_single(struct stv0900_internal *intp,
-					enum fe_stv0900_demod_mode LDPC_Mode,
-					enum fe_stv0900_demod_num demod)
-{
-	enum fe_stv0900_error error = STV0900_NO_ERROR;
-	s32 reg_ind;
-
-	dprintk("%s\n", __func__);
-
-	switch (LDPC_Mode) {
-	case STV0900_DUAL:
-	default:
-		if ((intp->demod_mode != STV0900_DUAL)
-			|| (stv0900_get_bits(intp, F0900_DDEMOD) != 1)) {
-			stv0900_write_reg(intp, R0900_GENCFG, 0x1d);
-
-			intp->demod_mode = STV0900_DUAL;
-
-			stv0900_write_bits(intp, F0900_FRESFEC, 1);
-			stv0900_write_bits(intp, F0900_FRESFEC, 0);
-
-			for (reg_ind = 0; reg_ind < 7; reg_ind++)
-				stv0900_write_reg(intp,
-						R0900_P1_MODCODLST0 + reg_ind,
-						0xff);
-			for (reg_ind = 0; reg_ind < 8; reg_ind++)
-				stv0900_write_reg(intp,
-						R0900_P1_MODCODLST7 + reg_ind,
-						0xcc);
-
-			stv0900_write_reg(intp, R0900_P1_MODCODLSTE, 0xff);
-			stv0900_write_reg(intp, R0900_P1_MODCODLSTF, 0xcf);
-
-			for (reg_ind = 0; reg_ind < 7; reg_ind++)
-				stv0900_write_reg(intp,
-						R0900_P2_MODCODLST0 + reg_ind,
-						0xff);
-			for (reg_ind = 0; reg_ind < 8; reg_ind++)
-				stv0900_write_reg(intp,
-						R0900_P2_MODCODLST7 + reg_ind,
-						0xcc);
-
-			stv0900_write_reg(intp, R0900_P2_MODCODLSTE, 0xff);
-			stv0900_write_reg(intp, R0900_P2_MODCODLSTF, 0xcf);
-		}
-
-		break;
-	case STV0900_SINGLE:
-		if (demod == STV0900_DEMOD_2) {
-			stv0900_stop_all_s2_modcod(intp, STV0900_DEMOD_1);
-			stv0900_activate_s2_modcod_single(intp,
-							STV0900_DEMOD_2);
-			stv0900_write_reg(intp, R0900_GENCFG, 0x06);
-		} else {
-			stv0900_stop_all_s2_modcod(intp, STV0900_DEMOD_2);
-			stv0900_activate_s2_modcod_single(intp,
-							STV0900_DEMOD_1);
-			stv0900_write_reg(intp, R0900_GENCFG, 0x04);
-		}
-
-		intp->demod_mode = STV0900_SINGLE;
-
-		stv0900_write_bits(intp, F0900_FRESFEC, 1);
-		stv0900_write_bits(intp, F0900_FRESFEC, 0);
-		stv0900_write_bits(intp, F0900_P1_ALGOSWRST, 1);
-		stv0900_write_bits(intp, F0900_P1_ALGOSWRST, 0);
-		stv0900_write_bits(intp, F0900_P2_ALGOSWRST, 1);
-		stv0900_write_bits(intp, F0900_P2_ALGOSWRST, 0);
-		break;
-	}
-
-	return error;
-}
-
-static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
-					struct stv0900_init_params *p_init)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	enum fe_stv0900_error error = STV0900_NO_ERROR;
-	enum fe_stv0900_error demodError = STV0900_NO_ERROR;
-	struct stv0900_internal *intp = NULL;
-	int selosci, i;
-
-	struct stv0900_inode *temp_int = find_inode(state->i2c_adap,
-						state->config->demod_address);
-
-	dprintk("%s\n", __func__);
-
-	if ((temp_int != NULL) && (p_init->demod_mode == STV0900_DUAL)) {
-		state->internal = temp_int->internal;
-		(state->internal->dmds_used)++;
-		dprintk("%s: Find Internal Structure!\n", __func__);
-		return STV0900_NO_ERROR;
-	} else {
-		state->internal = kmalloc(sizeof(struct stv0900_internal),
-								GFP_KERNEL);
-		if (state->internal == NULL)
-			return STV0900_INVALID_HANDLE;
-		temp_int = append_internal(state->internal);
-		if (temp_int == NULL) {
-			kfree(state->internal);
-			state->internal = NULL;
-			return STV0900_INVALID_HANDLE;
-		}
-		state->internal->dmds_used = 1;
-		state->internal->i2c_adap = state->i2c_adap;
-		state->internal->i2c_addr = state->config->demod_address;
-		state->internal->clkmode = state->config->clkmode;
-		state->internal->errs = STV0900_NO_ERROR;
-		dprintk("%s: Create New Internal Structure!\n", __func__);
-	}
-
-	if (state->internal == NULL) {
-		error = STV0900_INVALID_HANDLE;
-		return error;
-	}
-
-	demodError = stv0900_initialize(state->internal);
-	if (demodError == STV0900_NO_ERROR) {
-			error = STV0900_NO_ERROR;
-	} else {
-		if (demodError == STV0900_INVALID_HANDLE)
-			error = STV0900_INVALID_HANDLE;
-		else
-			error = STV0900_I2C_ERROR;
-
-		return error;
-	}
-
-	intp = state->internal;
-
-	intp->demod_mode = p_init->demod_mode;
-	stv0900_st_dvbs2_single(intp, intp->demod_mode,	STV0900_DEMOD_1);
-	intp->chip_id = stv0900_read_reg(intp, R0900_MID);
-	intp->rolloff = p_init->rolloff;
-	intp->quartz = p_init->dmd_ref_clk;
-
-	stv0900_write_bits(intp, F0900_P1_ROLLOFF_CONTROL, p_init->rolloff);
-	stv0900_write_bits(intp, F0900_P2_ROLLOFF_CONTROL, p_init->rolloff);
-
-	intp->ts_config = p_init->ts_config;
-	if (intp->ts_config == NULL)
-		stv0900_set_ts_parallel_serial(intp,
-				p_init->path1_ts_clock,
-				p_init->path2_ts_clock);
-	else {
-		for (i = 0; intp->ts_config[i].addr != 0xffff; i++)
-			stv0900_write_reg(intp,
-					intp->ts_config[i].addr,
-					intp->ts_config[i].val);
-
-		stv0900_write_bits(intp, F0900_P2_RST_HWARE, 1);
-		stv0900_write_bits(intp, F0900_P2_RST_HWARE, 0);
-		stv0900_write_bits(intp, F0900_P1_RST_HWARE, 1);
-		stv0900_write_bits(intp, F0900_P1_RST_HWARE, 0);
-	}
-
-	intp->tuner_type[0] = p_init->tuner1_type;
-	intp->tuner_type[1] = p_init->tuner2_type;
-	/* tuner init */
-	switch (p_init->tuner1_type) {
-	case 3: /*FE_AUTO_STB6100:*/
-		stv0900_write_reg(intp, R0900_P1_TNRCFG, 0x3c);
-		stv0900_write_reg(intp, R0900_P1_TNRCFG2, 0x86);
-		stv0900_write_reg(intp, R0900_P1_TNRCFG3, 0x18);
-		stv0900_write_reg(intp, R0900_P1_TNRXTAL, 27); /* 27MHz */
-		stv0900_write_reg(intp, R0900_P1_TNRSTEPS, 0x05);
-		stv0900_write_reg(intp, R0900_P1_TNRGAIN, 0x17);
-		stv0900_write_reg(intp, R0900_P1_TNRADJ, 0x1f);
-		stv0900_write_reg(intp, R0900_P1_TNRCTL2, 0x0);
-		stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 3);
-		break;
-	/* case FE_SW_TUNER: */
-	default:
-		stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 6);
-		break;
-	}
-
-	stv0900_write_bits(intp, F0900_P1_TUN_MADDRESS, p_init->tun1_maddress);
-	switch (p_init->tuner1_adc) {
-	case 1:
-		stv0900_write_reg(intp, R0900_TSTTNR1, 0x26);
-		break;
-	default:
-		break;
-	}
-
-	stv0900_write_reg(intp, R0900_P1_TNRLD, 1); /* hw tuner */
-
-	/* tuner init */
-	switch (p_init->tuner2_type) {
-	case 3: /*FE_AUTO_STB6100:*/
-		stv0900_write_reg(intp, R0900_P2_TNRCFG, 0x3c);
-		stv0900_write_reg(intp, R0900_P2_TNRCFG2, 0x86);
-		stv0900_write_reg(intp, R0900_P2_TNRCFG3, 0x18);
-		stv0900_write_reg(intp, R0900_P2_TNRXTAL, 27); /* 27MHz */
-		stv0900_write_reg(intp, R0900_P2_TNRSTEPS, 0x05);
-		stv0900_write_reg(intp, R0900_P2_TNRGAIN, 0x17);
-		stv0900_write_reg(intp, R0900_P2_TNRADJ, 0x1f);
-		stv0900_write_reg(intp, R0900_P2_TNRCTL2, 0x0);
-		stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 3);
-		break;
-	/* case FE_SW_TUNER: */
-	default:
-		stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 6);
-		break;
-	}
-
-	stv0900_write_bits(intp, F0900_P2_TUN_MADDRESS, p_init->tun2_maddress);
-	switch (p_init->tuner2_adc) {
-	case 1:
-		stv0900_write_reg(intp, R0900_TSTTNR3, 0x26);
-		break;
-	default:
-		break;
-	}
-
-	stv0900_write_reg(intp, R0900_P2_TNRLD, 1); /* hw tuner */
-
-	stv0900_write_bits(intp, F0900_P1_TUN_IQSWAP, p_init->tun1_iq_inv);
-	stv0900_write_bits(intp, F0900_P2_TUN_IQSWAP, p_init->tun2_iq_inv);
-	stv0900_set_mclk(intp, 135000000);
-	msleep(3);
-
-	switch (intp->clkmode) {
-	case 0:
-	case 2:
-		stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20 | intp->clkmode);
-		break;
-	default:
-		selosci = 0x02 & stv0900_read_reg(intp, R0900_SYNTCTRL);
-		stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20 | selosci);
-		break;
-	}
-	msleep(3);
-
-	intp->mclk = stv0900_get_mclk_freq(intp, intp->quartz);
-	if (intp->errs)
-		error = STV0900_I2C_ERROR;
-
-	return error;
-}
-
-static int stv0900_status(struct stv0900_internal *intp,
-					enum fe_stv0900_demod_num demod)
-{
-	enum fe_stv0900_search_state demod_state;
-	int locked = FALSE;
-	u8 tsbitrate0_val, tsbitrate1_val;
-	s32 bitrate;
-
-	demod_state = stv0900_get_bits(intp, HEADER_MODE);
-	switch (demod_state) {
-	case STV0900_SEARCH:
-	case STV0900_PLH_DETECTED:
-	default:
-		locked = FALSE;
-		break;
-	case STV0900_DVBS2_FOUND:
-		locked = stv0900_get_bits(intp, LOCK_DEFINITIF) &&
-				stv0900_get_bits(intp, PKTDELIN_LOCK) &&
-				stv0900_get_bits(intp, TSFIFO_LINEOK);
-		break;
-	case STV0900_DVBS_FOUND:
-		locked = stv0900_get_bits(intp, LOCK_DEFINITIF) &&
-				stv0900_get_bits(intp, LOCKEDVIT) &&
-				stv0900_get_bits(intp, TSFIFO_LINEOK);
-		break;
-	}
-
-	dprintk("%s: locked = %d\n", __func__, locked);
-
-	if (stvdebug) {
-		/* Print TS bitrate */
-		tsbitrate0_val = stv0900_read_reg(intp, TSBITRATE0);
-		tsbitrate1_val = stv0900_read_reg(intp, TSBITRATE1);
-		/* Formula Bit rate = Mclk * px_tsfifo_bitrate / 16384 */
-		bitrate = (stv0900_get_mclk_freq(intp, intp->quartz)/1000000)
-			* (tsbitrate1_val << 8 | tsbitrate0_val);
-		bitrate /= 16384;
-		dprintk("TS bitrate = %d Mbit/sec \n", bitrate);
-	};
-
-	return locked;
-}
-
-static enum dvbfe_search stv0900_search(struct dvb_frontend *fe)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-
-	struct stv0900_search_params p_search;
-	struct stv0900_signal_info p_result = intp->result[demod];
-
-	enum fe_stv0900_error error = STV0900_NO_ERROR;
-
-	dprintk("%s: ", __func__);
-
-	if (!(INRANGE(100000, c->symbol_rate, 70000000)))
-		return DVBFE_ALGO_SEARCH_FAILED;
-
-	if (state->config->set_ts_params)
-		state->config->set_ts_params(fe, 0);
-
-	p_result.locked = FALSE;
-	p_search.path = demod;
-	p_search.frequency = c->frequency;
-	p_search.symbol_rate = c->symbol_rate;
-	p_search.search_range = 10000000;
-	p_search.fec = STV0900_FEC_UNKNOWN;
-	p_search.standard = STV0900_AUTO_SEARCH;
-	p_search.iq_inversion = STV0900_IQ_AUTO;
-	p_search.search_algo = STV0900_BLIND_SEARCH;
-	/* Speeds up DVB-S searching */
-	if (c->delivery_system == SYS_DVBS)
-		p_search.standard = STV0900_SEARCH_DVBS1;
-
-	intp->srch_standard[demod] = p_search.standard;
-	intp->symbol_rate[demod] = p_search.symbol_rate;
-	intp->srch_range[demod] = p_search.search_range;
-	intp->freq[demod] = p_search.frequency;
-	intp->srch_algo[demod] = p_search.search_algo;
-	intp->srch_iq_inv[demod] = p_search.iq_inversion;
-	intp->fec[demod] = p_search.fec;
-	if ((stv0900_algo(fe) == STV0900_RANGEOK) &&
-				(intp->errs == STV0900_NO_ERROR)) {
-		p_result.locked = intp->result[demod].locked;
-		p_result.standard = intp->result[demod].standard;
-		p_result.frequency = intp->result[demod].frequency;
-		p_result.symbol_rate = intp->result[demod].symbol_rate;
-		p_result.fec = intp->result[demod].fec;
-		p_result.modcode = intp->result[demod].modcode;
-		p_result.pilot = intp->result[demod].pilot;
-		p_result.frame_len = intp->result[demod].frame_len;
-		p_result.spectrum = intp->result[demod].spectrum;
-		p_result.rolloff = intp->result[demod].rolloff;
-		p_result.modulation = intp->result[demod].modulation;
-	} else {
-		p_result.locked = FALSE;
-		switch (intp->err[demod]) {
-		case STV0900_I2C_ERROR:
-			error = STV0900_I2C_ERROR;
-			break;
-		case STV0900_NO_ERROR:
-		default:
-			error = STV0900_SEARCH_FAILED;
-			break;
-		}
-	}
-
-	if ((p_result.locked == TRUE) && (error == STV0900_NO_ERROR)) {
-		dprintk("Search Success\n");
-		return DVBFE_ALGO_SEARCH_SUCCESS;
-	} else {
-		dprintk("Search Fail\n");
-		return DVBFE_ALGO_SEARCH_FAILED;
-	}
-
-}
-
-static int stv0900_read_status(struct dvb_frontend *fe, enum fe_status *status)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-
-	dprintk("%s: ", __func__);
-
-	if ((stv0900_status(state->internal, state->demod)) == TRUE) {
-		dprintk("DEMOD LOCK OK\n");
-		*status = FE_HAS_CARRIER
-			| FE_HAS_VITERBI
-			| FE_HAS_SYNC
-			| FE_HAS_LOCK;
-		if (state->config->set_lock_led)
-			state->config->set_lock_led(fe, 1);
-	} else {
-		*status = 0;
-		if (state->config->set_lock_led)
-			state->config->set_lock_led(fe, 0);
-		dprintk("DEMOD LOCK FAIL\n");
-	}
-
-	return 0;
-}
-
-static int stv0900_stop_ts(struct dvb_frontend *fe, int stop_ts)
-{
-
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-
-	if (stop_ts == TRUE)
-		stv0900_write_bits(intp, RST_HWARE, 1);
-	else
-		stv0900_write_bits(intp, RST_HWARE, 0);
-
-	return 0;
-}
-
-static int stv0900_diseqc_init(struct dvb_frontend *fe)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-
-	stv0900_write_bits(intp, DISTX_MODE, state->config->diseqc_mode);
-	stv0900_write_bits(intp, DISEQC_RESET, 1);
-	stv0900_write_bits(intp, DISEQC_RESET, 0);
-
-	return 0;
-}
-
-static int stv0900_init(struct dvb_frontend *fe)
-{
-	dprintk("%s\n", __func__);
-
-	stv0900_stop_ts(fe, 1);
-	stv0900_diseqc_init(fe);
-
-	return 0;
-}
-
-static int stv0900_diseqc_send(struct stv0900_internal *intp , u8 *data,
-				u32 NbData, enum fe_stv0900_demod_num demod)
-{
-	s32 i = 0;
-
-	stv0900_write_bits(intp, DIS_PRECHARGE, 1);
-	while (i < NbData) {
-		while (stv0900_get_bits(intp, FIFO_FULL))
-			;/* checkpatch complains */
-		stv0900_write_reg(intp, DISTXDATA, data[i]);
-		i++;
-	}
-
-	stv0900_write_bits(intp, DIS_PRECHARGE, 0);
-	i = 0;
-	while ((stv0900_get_bits(intp, TX_IDLE) != 1) && (i < 10)) {
-		msleep(10);
-		i++;
-	}
-
-	return 0;
-}
-
-static int stv0900_send_master_cmd(struct dvb_frontend *fe,
-					struct dvb_diseqc_master_cmd *cmd)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-
-	return stv0900_diseqc_send(state->internal,
-				cmd->msg,
-				cmd->msg_len,
-				state->demod);
-}
-
-static int stv0900_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-	u8 data;
-
-
-	switch (burst) {
-	case SEC_MINI_A:
-		stv0900_write_bits(intp, DISTX_MODE, 3);/* Unmodulated */
-		data = 0x00;
-		stv0900_diseqc_send(intp, &data, 1, state->demod);
-		break;
-	case SEC_MINI_B:
-		stv0900_write_bits(intp, DISTX_MODE, 2);/* Modulated */
-		data = 0xff;
-		stv0900_diseqc_send(intp, &data, 1, state->demod);
-		break;
-	}
-
-	return 0;
-}
-
-static int stv0900_recv_slave_reply(struct dvb_frontend *fe,
-				struct dvb_diseqc_slave_reply *reply)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-	s32 i = 0;
-
-	reply->msg_len = 0;
-
-	while ((stv0900_get_bits(intp, RX_END) != 1) && (i < 10)) {
-		msleep(10);
-		i++;
-	}
-
-	if (stv0900_get_bits(intp, RX_END)) {
-		reply->msg_len = stv0900_get_bits(intp, FIFO_BYTENBR);
-
-		for (i = 0; i < reply->msg_len; i++)
-			reply->msg[i] = stv0900_read_reg(intp, DISRXDATA);
-	}
-
-	return 0;
-}
-
-static int stv0900_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t toneoff)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-
-	dprintk("%s: %s\n", __func__, ((toneoff == 0) ? "On" : "Off"));
-
-	switch (toneoff) {
-	case SEC_TONE_ON:
-		/*Set the DiseqC mode to 22Khz _continues_ tone*/
-		stv0900_write_bits(intp, DISTX_MODE, 0);
-		stv0900_write_bits(intp, DISEQC_RESET, 1);
-		/*release DiseqC reset to enable the 22KHz tone*/
-		stv0900_write_bits(intp, DISEQC_RESET, 0);
-		break;
-	case SEC_TONE_OFF:
-		/*return diseqc mode to config->diseqc_mode.
-		Usually it's without _continues_ tone */
-		stv0900_write_bits(intp, DISTX_MODE,
-				state->config->diseqc_mode);
-		/*maintain the DiseqC reset to disable the 22KHz tone*/
-		stv0900_write_bits(intp, DISEQC_RESET, 1);
-		stv0900_write_bits(intp, DISEQC_RESET, 0);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static void stv0900_release(struct dvb_frontend *fe)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-
-	dprintk("%s\n", __func__);
-
-	if (state->config->set_lock_led)
-		state->config->set_lock_led(fe, 0);
-
-	if ((--(state->internal->dmds_used)) <= 0) {
-
-		dprintk("%s: Actually removing\n", __func__);
-
-		remove_inode(state->internal);
-		kfree(state->internal);
-	}
-
-	kfree(state);
-}
-
-static int stv0900_sleep(struct dvb_frontend *fe)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-
-	dprintk("%s\n", __func__);
-
-	if (state->config->set_lock_led)
-		state->config->set_lock_led(fe, 0);
-
-	return 0;
-}
-
-static int stv0900_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-	struct stv0900_signal_info p_result = intp->result[demod];
-
-	p->frequency = p_result.locked ? p_result.frequency : 0;
-	p->symbol_rate = p_result.locked ? p_result.symbol_rate : 0;
-	return 0;
-}
-
-static struct dvb_frontend_ops stv0900_ops = {
-	.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
-	.info = {
-		.name			= "STV0900 frontend",
-		.frequency_min		= 950000,
-		.frequency_max		= 2150000,
-		.frequency_stepsize	= 125,
-		.frequency_tolerance	= 0,
-		.symbol_rate_min	= 1000000,
-		.symbol_rate_max	= 45000000,
-		.symbol_rate_tolerance	= 500,
-		.caps			= FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
-					  FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
-					  FE_CAN_FEC_7_8 | FE_CAN_QPSK    |
-					  FE_CAN_2G_MODULATION |
-					  FE_CAN_FEC_AUTO
-	},
-	.release			= stv0900_release,
-	.init				= stv0900_init,
-	.get_frontend                   = stv0900_get_frontend,
-	.sleep				= stv0900_sleep,
-	.get_frontend_algo		= stv0900_frontend_algo,
-	.i2c_gate_ctrl			= stv0900_i2c_gate_ctrl,
-	.diseqc_send_master_cmd		= stv0900_send_master_cmd,
-	.diseqc_send_burst		= stv0900_send_burst,
-	.diseqc_recv_slave_reply	= stv0900_recv_slave_reply,
-	.set_tone			= stv0900_set_tone,
-	.search				= stv0900_search,
-	.read_status			= stv0900_read_status,
-	.read_ber			= stv0900_read_ber,
-	.read_signal_strength		= stv0900_read_signal_strength,
-	.read_snr			= stv0900_read_snr,
-	.read_ucblocks                  = stv0900_read_ucblocks,
-};
-
-struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
-					struct i2c_adapter *i2c,
-					int demod)
-{
-	struct stv0900_state *state = NULL;
-	struct stv0900_init_params init_params;
-	enum fe_stv0900_error err_stv0900;
-
-	state = kzalloc(sizeof(struct stv0900_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	state->demod		= demod;
-	state->config		= config;
-	state->i2c_adap		= i2c;
-
-	memcpy(&state->frontend.ops, &stv0900_ops,
-			sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-
-	switch (demod) {
-	case 0:
-	case 1:
-		init_params.dmd_ref_clk  	= config->xtal;
-		init_params.demod_mode		= config->demod_mode;
-		init_params.rolloff		= STV0900_35;
-		init_params.path1_ts_clock	= config->path1_mode;
-		init_params.tun1_maddress	= config->tun1_maddress;
-		init_params.tun1_iq_inv		= STV0900_IQ_NORMAL;
-		init_params.tuner1_adc		= config->tun1_adc;
-		init_params.tuner1_type		= config->tun1_type;
-		init_params.path2_ts_clock	= config->path2_mode;
-		init_params.ts_config		= config->ts_config_regs;
-		init_params.tun2_maddress	= config->tun2_maddress;
-		init_params.tuner2_adc		= config->tun2_adc;
-		init_params.tuner2_type		= config->tun2_type;
-		init_params.tun2_iq_inv		= STV0900_IQ_SWAPPED;
-
-		err_stv0900 = stv0900_init_internal(&state->frontend,
-							&init_params);
-
-		if (err_stv0900)
-			goto error;
-
-		break;
-	default:
-		goto error;
-		break;
-	}
-
-	dprintk("%s: Attaching STV0900 demodulator(%d) \n", __func__, demod);
-	return &state->frontend;
-
-error:
-	dprintk("%s: Failed to attach STV0900 demodulator(%d) \n",
-		__func__, demod);
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(stv0900_attach);
-
-MODULE_PARM_DESC(debug, "Set debug");
-
-MODULE_AUTHOR("Igor M. Liplianin");
-MODULE_DESCRIPTION("ST STV0900 frontend");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stv0900_init.h b/drivers/media/dvb/frontends/stv0900_init.h
deleted file mode 100644
index b684df9..0000000
--- a/drivers/media/dvb/frontends/stv0900_init.h
+++ /dev/null
@@ -1,584 +0,0 @@
-/*
- * stv0900_init.h
- *
- * Driver for ST STV0900 satellite demodulator IC.
- *
- * Copyright (C) ST Microelectronics.
- * Copyright (C) 2009 NetUP Inc.
- * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef STV0900_INIT_H
-#define STV0900_INIT_H
-
-#include "stv0900_priv.h"
-
-/* DVBS2 C/N Look-Up table */
-static const struct stv0900_table stv0900_s2_cn = {
-	55,
-	{
-		{ -30,	13348 }, /*C/N=-3dB*/
-		{ -20,	12640 }, /*C/N=-2dB*/
-		{ -10,	11883 }, /*C/N=-1dB*/
-		{ 0,	11101 }, /*C/N=-0dB*/
-		{ 5,	10718 }, /*C/N=0.5dB*/
-		{ 10,	10339 }, /*C/N=1.0dB*/
-		{ 15,	9947 }, /*C/N=1.5dB*/
-		{ 20,	9552 }, /*C/N=2.0dB*/
-		{ 25,	9183 }, /*C/N=2.5dB*/
-		{ 30,	8799 }, /*C/N=3.0dB*/
-		{ 35,	8422 }, /*C/N=3.5dB*/
-		{ 40,	8062 }, /*C/N=4.0dB*/
-		{ 45,	7707 }, /*C/N=4.5dB*/
-		{ 50,	7353 }, /*C/N=5.0dB*/
-		{ 55,	7025 }, /*C/N=5.5dB*/
-		{ 60,	6684 }, /*C/N=6.0dB*/
-		{ 65,	6331 }, /*C/N=6.5dB*/
-		{ 70,	6036 }, /*C/N=7.0dB*/
-		{ 75,	5727 }, /*C/N=7.5dB*/
-		{ 80,	5437 }, /*C/N=8.0dB*/
-		{ 85,	5164 }, /*C/N=8.5dB*/
-		{ 90,	4902 }, /*C/N=9.0dB*/
-		{ 95,	4653 }, /*C/N=9.5dB*/
-		{ 100,	4408 }, /*C/N=10.0dB*/
-		{ 105,	4187 }, /*C/N=10.5dB*/
-		{ 110,	3961 }, /*C/N=11.0dB*/
-		{ 115,	3751 }, /*C/N=11.5dB*/
-		{ 120,	3558 }, /*C/N=12.0dB*/
-		{ 125,	3368 }, /*C/N=12.5dB*/
-		{ 130,	3191 }, /*C/N=13.0dB*/
-		{ 135,	3017 }, /*C/N=13.5dB*/
-		{ 140,	2862 }, /*C/N=14.0dB*/
-		{ 145,	2710 }, /*C/N=14.5dB*/
-		{ 150,	2565 }, /*C/N=15.0dB*/
-		{ 160,	2300 }, /*C/N=16.0dB*/
-		{ 170,	2058 }, /*C/N=17.0dB*/
-		{ 180,	1849 }, /*C/N=18.0dB*/
-		{ 190,	1663 }, /*C/N=19.0dB*/
-		{ 200,	1495 }, /*C/N=20.0dB*/
-		{ 210,	1349 }, /*C/N=21.0dB*/
-		{ 220,	1222 }, /*C/N=22.0dB*/
-		{ 230,	1110 }, /*C/N=23.0dB*/
-		{ 240,	1011 }, /*C/N=24.0dB*/
-		{ 250,	925 }, /*C/N=25.0dB*/
-		{ 260,	853 }, /*C/N=26.0dB*/
-		{ 270,	789 }, /*C/N=27.0dB*/
-		{ 280,	734 }, /*C/N=28.0dB*/
-		{ 290,	690 }, /*C/N=29.0dB*/
-		{ 300,	650 }, /*C/N=30.0dB*/
-		{ 310,	619 }, /*C/N=31.0dB*/
-		{ 320,	593 }, /*C/N=32.0dB*/
-		{ 330,	571 }, /*C/N=33.0dB*/
-		{ 400,	498 }, /*C/N=40.0dB*/
-		{ 450,	484 }, /*C/N=45.0dB*/
-		{ 500,	481 }  /*C/N=50.0dB*/
-	}
-};
-
-/* RF level C/N Look-Up table */
-static const struct stv0900_table stv0900_rf = {
-	14,
-	{
-		{ -5, 0xCAA1 }, /*-5dBm*/
-		{ -10, 0xC229 }, /*-10dBm*/
-		{ -15, 0xBB08 }, /*-15dBm*/
-		{ -20, 0xB4BC }, /*-20dBm*/
-		{ -25, 0xAD5A }, /*-25dBm*/
-		{ -30, 0xA298 }, /*-30dBm*/
-		{ -35, 0x98A8 }, /*-35dBm*/
-		{ -40, 0x8389 }, /*-40dBm*/
-		{ -45, 0x59BE }, /*-45dBm*/
-		{ -50, 0x3A14 }, /*-50dBm*/
-		{ -55, 0x2D11 }, /*-55dBm*/
-		{ -60, 0x210D }, /*-60dBm*/
-		{ -65, 0xA14F }, /*-65dBm*/
-		{ -70, 0x7AA }	/*-70dBm*/
-	}
-};
-
-struct stv0900_car_loop_optim {
-	enum fe_stv0900_modcode modcode;
-	u8 car_loop_pilots_on_2;
-	u8 car_loop_pilots_off_2;
-	u8 car_loop_pilots_on_5;
-	u8 car_loop_pilots_off_5;
-	u8 car_loop_pilots_on_10;
-	u8 car_loop_pilots_off_10;
-	u8 car_loop_pilots_on_20;
-	u8 car_loop_pilots_off_20;
-	u8 car_loop_pilots_on_30;
-	u8 car_loop_pilots_off_30;
-
-};
-
-struct stv0900_short_frames_car_loop_optim {
-	enum fe_stv0900_modulation modulation;
-	u8 car_loop_cut12_2;    /* Cut 1.2,   SR<=3msps     */
-	u8 car_loop_cut20_2;    /* Cut 2.0,   SR<3msps      */
-	u8 car_loop_cut12_5;    /* Cut 1.2,   3<SR<=7msps   */
-	u8 car_loop_cut20_5;    /* Cut 2.0,   3<SR<=7msps   */
-	u8 car_loop_cut12_10;   /* Cut 1.2,   7<SR<=15msps  */
-	u8 car_loop_cut20_10;   /* Cut 2.0,   7<SR<=15msps  */
-	u8 car_loop_cut12_20;   /* Cut 1.2,   10<SR<=25msps */
-	u8 car_loop_cut20_20;   /* Cut 2.0,   10<SR<=25msps */
-	u8 car_loop_cut12_30;   /* Cut 1.2,   25<SR<=45msps */
-	u8 car_loop_cut20_30;   /* Cut 2.0,   10<SR<=45msps */
-
-};
-
-struct stv0900_short_frames_car_loop_optim_vs_mod {
-	enum fe_stv0900_modulation modulation;
-	u8 car_loop_2;	  /* SR<3msps      */
-	u8 car_loop_5;	  /* 3<SR<=7msps   */
-	u8 car_loop_10;   /* 7<SR<=15msps  */
-	u8 car_loop_20;   /* 10<SR<=25msps */
-	u8 car_loop_30;   /* 10<SR<=45msps */
-};
-
-/* Cut 1.x Tracking carrier loop carrier QPSK 1/2 to 8PSK 9/10 long Frame */
-static const struct stv0900_car_loop_optim FE_STV0900_S2CarLoop[14] = {
-	/*Modcod		2MPon 	2MPoff	5MPon 	5MPoff	10MPon
-				10MPoff	20MPon 	20MPoff	30MPon 	30MPoff */
-	{ STV0900_QPSK_12,	0x1C,	0x0D,	0x1B,	0x2C,	0x3A,
-				0x1C,	0x2A,	0x3B,	0x2A,	0x1B },
-	{ STV0900_QPSK_35,	0x2C,	0x0D,	0x2B,	0x2C,	0x3A,
-				0x0C,	0x3A,	0x2B,	0x2A,	0x0B },
-	{ STV0900_QPSK_23,	0x2C,	0x0D,	0x2B,	0x2C,	0x0B,
-				0x0C,	0x3A,	0x1B,	0x2A,	0x3A },
-	{ STV0900_QPSK_34,	0x3C,	0x0D,	0x3B,	0x1C,	0x0B,
-				0x3B,	0x3A,	0x0B,	0x2A,	0x3A },
-	{ STV0900_QPSK_45,	0x3C,	0x0D,	0x3B,	0x1C,	0x0B,
-				0x3B,	0x3A,	0x0B,	0x2A,	0x3A },
-	{ STV0900_QPSK_56,	0x0D,	0x0D,	0x3B,	0x1C,	0x0B,
-				0x3B,	0x3A,	0x0B,	0x2A,	0x3A },
-	{ STV0900_QPSK_89,	0x0D,	0x0D,	0x3B,	0x1C,	0x1B,
-				0x3B,	0x3A,	0x0B,	0x2A,	0x3A },
-	{ STV0900_QPSK_910,	0x1D,	0x0D,	0x3B,	0x1C,	0x1B,
-				0x3B,	0x3A,	0x0B,	0x2A,	0x3A },
-	{ STV0900_8PSK_35,	0x29,	0x3B,	0x09,	0x2B,	0x38,
-				0x0B,	0x18,	0x1A,	0x08,	0x0A },
-	{ STV0900_8PSK_23,	0x0A,	0x3B,	0x29,	0x2B,	0x19,
-				0x0B,	0x38,	0x1A,	0x18,	0x0A },
-	{ STV0900_8PSK_34,	0x3A,	0x3B,	0x2A,	0x2B,	0x39,
-				0x0B,	0x19,	0x1A,	0x38,	0x0A },
-	{ STV0900_8PSK_56,	0x1B,	0x3B,	0x0B,	0x2B,	0x1A,
-				0x0B,	0x39,	0x1A,	0x19,	0x0A },
-	{ STV0900_8PSK_89,	0x3B,	0x3B,	0x0B,	0x2B,	0x2A,
-				0x0B,	0x39,	0x1A,	0x29,	0x39 },
-	{ STV0900_8PSK_910,	0x3B,	0x3B, 	0x0B,	0x2B, 	0x2A,
-				0x0B,	0x39,	0x1A,	0x29,	0x39 }
-};
-
-
-/* Cut 2.0 Tracking carrier loop carrier QPSK 1/2 to 8PSK 9/10 long Frame */
-static const struct stv0900_car_loop_optim FE_STV0900_S2CarLoopCut20[14] = {
-	/* Modcod		2MPon 	2MPoff	5MPon 	5MPoff	10MPon
-				10MPoff	20MPon 	20MPoff	30MPon 	30MPoff */
-	{ STV0900_QPSK_12,	0x1F,	0x3F,	0x1E,	0x3F,	0x3D,
-				0x1F,	0x3D,	0x3E,	0x3D,	0x1E },
-	{ STV0900_QPSK_35,	0x2F,	0x3F,	0x2E,	0x2F,	0x3D,
-				0x0F,	0x0E,	0x2E,	0x3D,	0x0E },
-	{ STV0900_QPSK_23,	0x2F,	0x3F,	0x2E,	0x2F,	0x0E,
-				0x0F,	0x0E,	0x1E,	0x3D,	0x3D },
-	{ STV0900_QPSK_34,	0x3F,	0x3F,	0x3E,	0x1F,	0x0E,
-				0x3E,	0x0E,	0x1E,	0x3D,	0x3D },
-	{ STV0900_QPSK_45,	0x3F,	0x3F,	0x3E,	0x1F,	0x0E,
-				0x3E,	0x0E,	0x1E,	0x3D,	0x3D },
-	{ STV0900_QPSK_56,	0x3F,	0x3F,	0x3E,	0x1F,	0x0E,
-				0x3E,	0x0E,	0x1E,	0x3D,	0x3D },
-	{ STV0900_QPSK_89,	0x3F,	0x3F,	0x3E,	0x1F,	0x1E,
-				0x3E,	0x0E,	0x1E,	0x3D,	0x3D },
-	{ STV0900_QPSK_910,	0x3F,	0x3F,	0x3E,	0x1F,	0x1E,
-				0x3E,	0x0E,	0x1E,	0x3D,	0x3D },
-	{ STV0900_8PSK_35,	0x3c,	0x0c,	0x1c,	0x3b,	0x0c,
-				0x3b,	0x2b,	0x2b,	0x1b,	0x2b },
-	{ STV0900_8PSK_23,	0x1d,	0x0c,	0x3c,	0x0c,	0x2c,
-				0x3b,	0x0c,	0x2b,	0x2b,	0x2b },
-	{ STV0900_8PSK_34,	0x0e,	0x1c,	0x3d,	0x0c,	0x0d,
-				0x3b,	0x2c,	0x3b,	0x0c,	0x2b },
-	{ STV0900_8PSK_56,	0x2e,	0x3e,	0x1e,	0x2e,	0x2d,
-				0x1e,	0x3c,	0x2d,	0x2c,	0x1d },
-	{ STV0900_8PSK_89,	0x3e,	0x3e,	0x1e,	0x2e,	0x3d,
-				0x1e,	0x0d,	0x2d,	0x3c,	0x1d },
-	{ STV0900_8PSK_910,	0x3e,	0x3e, 	0x1e,	0x2e, 	0x3d,
-				0x1e,	0x1d,	0x2d,	0x0d,	0x1d },
-};
-
-
-
-/* Cut 2.0 Tracking carrier loop carrier 16APSK 2/3 to 32APSK 9/10 long Frame */
-static const struct stv0900_car_loop_optim FE_STV0900_S2APSKCarLoopCut20[11] = {
-	/* Modcod		2MPon 	2MPoff	5MPon 	5MPoff	10MPon
-				10MPoff	20MPon 	20MPoff	30MPon 	30MPoff */
-	{ STV0900_16APSK_23,	0x0C,	0x0C,	0x0C,	0x0C,	0x1D,
-				0x0C,	0x3C,	0x0C,	0x2C,	0x0C },
-	{ STV0900_16APSK_34,	0x0C,	0x0C,	0x0C,	0x0C,	0x0E,
-				0x0C,	0x2D,	0x0C,	0x1D,	0x0C },
-	{ STV0900_16APSK_45,	0x0C,	0x0C,	0x0C,	0x0C,	0x1E,
-				0x0C,	0x3D,	0x0C,	0x2D,	0x0C },
-	{ STV0900_16APSK_56,	0x0C,	0x0C,	0x0C,	0x0C,	0x1E,
-				0x0C,	0x3D,	0x0C,	0x2D,	0x0C },
-	{ STV0900_16APSK_89,	0x0C,	0x0C,	0x0C,	0x0C,	0x2E,
-				0x0C,	0x0E,	0x0C,	0x3D,	0x0C },
-	{ STV0900_16APSK_910,	0x0C,	0x0C,	0x0C,	0x0C,	0x2E,
-				0x0C,	0x0E,	0x0C,	0x3D,	0x0C },
-	{ STV0900_32APSK_34,	0x0C,	0x0C,	0x0C,	0x0C,	0x0C,
-				0x0C,	0x0C,	0x0C,	0x0C,	0x0C },
-	{ STV0900_32APSK_45,	0x0C,	0x0C,	0x0C,	0x0C,	0x0C,
-				0x0C,	0x0C,	0x0C,	0x0C,	0x0C },
-	{ STV0900_32APSK_56,	0x0C,	0x0C,	0x0C,	0x0C,	0x0C,
-				0x0C,	0x0C,	0x0C,	0x0C,	0x0C },
-	{ STV0900_32APSK_89,	0x0C,	0x0C,	0x0C,	0x0C,	0x0C,
-				0x0C,	0x0C,	0x0C,	0x0C,	0x0C },
-	{ STV0900_32APSK_910,	0x0C,	0x0C,	0x0C,	0x0C,	0x0C,
-				0x0C,	0x0C,	0x0C,	0x0C,	0x0C },
-};
-
-
-/* Cut 2.0 Tracking carrier loop carrier QPSK 1/4 to QPSK 2/5 long Frame */
-static const struct stv0900_car_loop_optim FE_STV0900_S2LowQPCarLoopCut20[3] = {
-	/* Modcod		2MPon 	2MPoff	5MPon 	5MPoff	10MPon
-				10MPoff	20MPon 	20MPoff	30MPon 	30MPoff */
-	{ STV0900_QPSK_14,	0x0F,	0x3F,	0x0E,	0x3F,	0x2D,
-				0x2F,	0x2D,	0x1F,	0x3D,	0x3E },
-	{ STV0900_QPSK_13,	0x0F,	0x3F,	0x0E,	0x3F,	0x2D,
-				0x2F,	0x3D,	0x0F,	0x3D,	0x2E },
-	{ STV0900_QPSK_25,	0x1F,	0x3F,	0x1E,	0x3F,	0x3D,
-				0x1F,	0x3D,	0x3E,	0x3D,	0x2E }
-};
-
-
-/* Cut 2.0 Tracking carrier loop carrier  short Frame, cut 1.2 and 2.0 */
-static const
-struct stv0900_short_frames_car_loop_optim FE_STV0900_S2ShortCarLoop[4] = {
-	/*Mod		2Mcut1.2 2Mcut2.0 5Mcut1.2 5Mcut2.0 10Mcut1.2
-			10Mcut2.0 20Mcut1.2 20M_cut2.0 30Mcut1.2 30Mcut2.0*/
-	{ STV0900_QPSK,		0x3C,	0x2F,	0x2B,	0x2E,	0x0B,
-				0x0E,	0x3A,	0x0E,	0x2A,	0x3D },
-	{ STV0900_8PSK,		0x0B,	0x3E,	0x2A,	0x0E,	0x0A,
-				0x2D,	0x19,	0x0D,	0x09,	0x3C },
-	{ STV0900_16APSK,	0x1B,	0x1E,	0x1B,	0x1E,	0x1B,
-				0x1E,	0x3A,	0x3D,	0x2A,	0x2D },
-	{ STV0900_32APSK,	0x1B,	0x1E,	0x1B,	0x1E,	0x1B,
-				0x1E,	0x3A,	0x3D,	0x2A,	0x2D }
-};
-
-static	const struct stv0900_car_loop_optim FE_STV0900_S2CarLoopCut30[14] = {
-	/*Modcod		2MPon 	2MPoff	5MPon 	5MPoff	10MPon
-				10MPoff	20MPon 	20MPoff	30MPon 	30MPoff	*/
-	{ STV0900_QPSK_12,	0x3C,	0x2C,	0x0C,	0x2C,	0x1B,
-				0x2C,	0x1B,	0x1C,	0x0B, 	0x3B },
-	{ STV0900_QPSK_35,	0x0D,	0x0D,	0x0C,	0x0D,	0x1B,
-				0x3C,	0x1B,	0x1C,	0x0B,	0x3B },
-	{ STV0900_QPSK_23,	0x1D,	0x0D,	0x0C,	0x1D,	0x2B,
-				0x3C,	0x1B,	0x1C,	0x0B,	0x3B },
-	{ STV0900_QPSK_34,	0x1D,	0x1D,	0x0C,	0x1D,	0x2B,
-				0x3C,	0x1B,	0x1C,	0x0B,	0x3B },
-	{ STV0900_QPSK_45,	0x2D,	0x1D,	0x1C,	0x1D,	0x2B,
-				0x3C,	0x2B,	0x0C,	0x1B,	0x3B },
-	{ STV0900_QPSK_56,	0x2D,	0x1D,	0x1C,	0x1D,	0x2B,
-				0x3C,	0x2B,	0x0C,	0x1B,	0x3B },
-	{ STV0900_QPSK_89,	0x3D,	0x2D,	0x1C,	0x1D,	0x3B,
-				0x3C,	0x2B,	0x0C,	0x1B,	0x3B },
-	{ STV0900_QPSK_910,	0x3D,	0x2D,	0x1C,	0x1D,	0x3B,
-				0x3C,	0x2B,	0x0C,	0x1B,	0x3B },
-	{ STV0900_8PSK_35,	0x39,	0x19,	0x39,	0x19,	0x19,
-				0x19,	0x19,	0x19,	0x09,	0x19 },
-	{ STV0900_8PSK_23,	0x2A,	0x39,	0x1A,	0x0A,	0x39,
-				0x0A,	0x29,	0x39,	0x29,	0x0A },
-	{ STV0900_8PSK_34,	0x0B,	0x3A,	0x0B,	0x0B,	0x3A,
-				0x1B,	0x1A,	0x0B,	0x1A,	0x3A },
-	{ STV0900_8PSK_56,	0x0C,	0x1B,	0x3B,	0x2B,	0x1B,
-				0x3B,	0x3A,	0x3B,	0x3A,	0x1B },
-	{ STV0900_8PSK_89,	0x2C,	0x2C,	0x2C,	0x1C,	0x2B,
-				0x0C,	0x0B,	0x3B,	0x0B,	0x1B },
-	{ STV0900_8PSK_910,	0x2C,	0x3C,	0x2C,	0x1C,	0x3B,
-				0x1C,	0x0B,	0x3B,	0x0B,	0x1B }
-};
-
-static	const
-struct stv0900_car_loop_optim FE_STV0900_S2APSKCarLoopCut30[11] = {
-	/*Modcod		2MPon 	2MPoff	5MPon 	5MPoff	10MPon
-				10MPoff	20MPon 	20MPoff	30MPon 	30MPoff	*/
-	{ STV0900_16APSK_23,	0x0A,	0x0A,	0x0A,	0x0A,	0x1A,
-				0x0A,	0x3A,	0x0A,	0x2A,	0x0A },
-	{ STV0900_16APSK_34,	0x0A,	0x0A,	0x0A,	0x0A,	0x0B,
-				0x0A,	0x3B,	0x0A,	0x1B,	0x0A },
-	{ STV0900_16APSK_45,	0x0A,	0x0A,	0x0A,	0x0A,	0x1B,
-				0x0A,	0x3B,	0x0A,	0x2B,	0x0A },
-	{ STV0900_16APSK_56,	0x0A,	0x0A,	0x0A,	0x0A,	0x1B,
-				0x0A,	0x3B,	0x0A,	0x2B,	0x0A },
-	{ STV0900_16APSK_89,	0x0A,	0x0A,	0x0A,	0x0A,	0x2B,
-				0x0A,	0x0C,	0x0A,	0x3B,	0x0A },
-	{ STV0900_16APSK_910,	0x0A,	0x0A,	0x0A,	0x0A,	0x2B,
-				0x0A,	0x0C,	0x0A,	0x3B,	0x0A },
-	{ STV0900_32APSK_34,	0x0A,	0x0A,	0x0A,	0x0A,	0x0A,
-				0x0A,	0x0A,	0x0A,	0x0A,	0x0A },
-	{ STV0900_32APSK_45,	0x0A,	0x0A,	0x0A,	0x0A,	0x0A,
-				0x0A,	0x0A,	0x0A,	0x0A,	0x0A },
-	{ STV0900_32APSK_56,	0x0A,	0x0A,	0x0A,	0x0A,	0x0A,
-				0x0A,	0x0A,	0x0A,	0x0A,	0x0A },
-	{ STV0900_32APSK_89,	0x0A,	0x0A,	0x0A,	0x0A,	0x0A,
-				0x0A,	0x0A,	0x0A,	0x0A,	0x0A },
-	{ STV0900_32APSK_910,	0x0A,	0x0A,	0x0A,	0x0A,	0x0A,
-				0x0A,	0x0A,	0x0A,	0x0A,	0x0A }
-};
-
-static	const
-struct stv0900_car_loop_optim FE_STV0900_S2LowQPCarLoopCut30[3] = {
-	/*Modcod		2MPon 	2MPoff	5MPon 	5MPoff	10MPon
-				10MPoff	20MPon 	20MPoff	30MPon 	30MPoff*/
-	{ STV0900_QPSK_14,	0x0C,	0x3C,	0x0B,	0x3C,	0x2A,
-				0x2C,	0x2A,	0x1C,	0x3A,	0x3B },
-	{ STV0900_QPSK_13,	0x0C,	0x3C,	0x0B,	0x3C,	0x2A,
-				0x2C,	0x3A,	0x0C,	0x3A,	0x2B },
-	{ STV0900_QPSK_25,	0x1C,	0x3C,	0x1B,	0x3C,	0x3A,
-				0x1C,	0x3A,	0x3B,	0x3A,	0x2B }
-};
-
-static	const struct stv0900_short_frames_car_loop_optim_vs_mod
-FE_STV0900_S2ShortCarLoopCut30[4] = {
-	/*Mod		2Mcut3.0 5Mcut3.0 10Mcut3.0 20Mcut3.0 30Mcut3.0*/
-	{ STV0900_QPSK,		0x2C,	0x2B,	0x0B,	0x0B,	0x3A },
-	{ STV0900_8PSK,		0x3B,	0x0B,	0x2A,	0x0A,	0x39 },
-	{ STV0900_16APSK,	0x1B,	0x1B,	0x1B,	0x3A,	0x2A },
-	{ STV0900_32APSK,	0x1B,	0x1B,	0x1B,	0x3A,	0x2A },
-
-};
-
-static const u16 STV0900_InitVal[181][2] = {
-	{ R0900_OUTCFG		, 0x00	},
-	{ R0900_AGCRF1CFG	, 0x11	},
-	{ R0900_AGCRF2CFG	, 0x13	},
-	{ R0900_TSGENERAL1X	, 0x14	},
-	{ R0900_TSTTNR2		, 0x21	},
-	{ R0900_TSTTNR4		, 0x21	},
-	{ R0900_P2_DISTXCTL	, 0x22	},
-	{ R0900_P2_F22TX	, 0xc0	},
-	{ R0900_P2_F22RX	, 0xc0	},
-	{ R0900_P2_DISRXCTL	, 0x00	},
-	{ R0900_P2_TNRSTEPS	, 0x87	},
-	{ R0900_P2_TNRGAIN	, 0x09	},
-	{ R0900_P2_DMDCFGMD	, 0xF9	},
-	{ R0900_P2_DEMOD	, 0x08	},
-	{ R0900_P2_DMDCFG3	, 0xc4	},
-	{ R0900_P2_CARFREQ	, 0xed	},
-	{ R0900_P2_TNRCFG2	, 0x02	},
-	{ R0900_P2_TNRCFG3	, 0x02	},
-	{ R0900_P2_LDT		, 0xd0	},
-	{ R0900_P2_LDT2		, 0xb8	},
-	{ R0900_P2_TMGCFG	, 0xd2	},
-	{ R0900_P2_TMGTHRISE	, 0x20	},
-	{ R0900_P2_TMGTHFALL	, 0x00	},
-	{ R0900_P2_FECSPY	, 0x88	},
-	{ R0900_P2_FSPYDATA	, 0x3a	},
-	{ R0900_P2_FBERCPT4	, 0x00	},
-	{ R0900_P2_FSPYBER	, 0x10	},
-	{ R0900_P2_ERRCTRL1	, 0x35	},
-	{ R0900_P2_ERRCTRL2	, 0xc1	},
-	{ R0900_P2_CFRICFG	, 0xf8	},
-	{ R0900_P2_NOSCFG	, 0x1c	},
-	{ R0900_P2_DMDT0M	, 0x20	},
-	{ R0900_P2_CORRELMANT	, 0x70	},
-	{ R0900_P2_CORRELABS	, 0x88	},
-	{ R0900_P2_AGC2O	, 0x5b	},
-	{ R0900_P2_AGC2REF	, 0x38	},
-	{ R0900_P2_CARCFG	, 0xe4	},
-	{ R0900_P2_ACLC		, 0x1A	},
-	{ R0900_P2_BCLC		, 0x09	},
-	{ R0900_P2_CARHDR	, 0x08	},
-	{ R0900_P2_KREFTMG	, 0xc1	},
-	{ R0900_P2_SFRUPRATIO	, 0xf0	},
-	{ R0900_P2_SFRLOWRATIO	, 0x70	},
-	{ R0900_P2_SFRSTEP	, 0x58	},
-	{ R0900_P2_TMGCFG2	, 0x01	},
-	{ R0900_P2_CAR2CFG	, 0x26	},
-	{ R0900_P2_BCLC2S2Q	, 0x86	},
-	{ R0900_P2_BCLC2S28	, 0x86	},
-	{ R0900_P2_SMAPCOEF7	, 0x77	},
-	{ R0900_P2_SMAPCOEF6	, 0x85	},
-	{ R0900_P2_SMAPCOEF5	, 0x77	},
-	{ R0900_P2_TSCFGL	, 0x20	},
-	{ R0900_P2_DMDCFG2	, 0x3b	},
-	{ R0900_P2_MODCODLST0	, 0xff	},
-	{ R0900_P2_MODCODLST1	, 0xff	},
-	{ R0900_P2_MODCODLST2	, 0xff	},
-	{ R0900_P2_MODCODLST3	, 0xff	},
-	{ R0900_P2_MODCODLST4	, 0xff	},
-	{ R0900_P2_MODCODLST5	, 0xff	},
-	{ R0900_P2_MODCODLST6	, 0xff	},
-	{ R0900_P2_MODCODLST7	, 0xcc	},
-	{ R0900_P2_MODCODLST8	, 0xcc	},
-	{ R0900_P2_MODCODLST9	, 0xcc	},
-	{ R0900_P2_MODCODLSTA	, 0xcc	},
-	{ R0900_P2_MODCODLSTB	, 0xcc	},
-	{ R0900_P2_MODCODLSTC	, 0xcc	},
-	{ R0900_P2_MODCODLSTD	, 0xcc	},
-	{ R0900_P2_MODCODLSTE	, 0xcc	},
-	{ R0900_P2_MODCODLSTF	, 0xcf	},
-	{ R0900_P1_DISTXCTL	, 0x22	},
-	{ R0900_P1_F22TX	, 0xc0	},
-	{ R0900_P1_F22RX	, 0xc0	},
-	{ R0900_P1_DISRXCTL	, 0x00	},
-	{ R0900_P1_TNRSTEPS	, 0x87	},
-	{ R0900_P1_TNRGAIN	, 0x09	},
-	{ R0900_P1_DMDCFGMD	, 0xf9	},
-	{ R0900_P1_DEMOD	, 0x08	},
-	{ R0900_P1_DMDCFG3	, 0xc4	},
-	{ R0900_P1_DMDT0M	, 0x20	},
-	{ R0900_P1_CARFREQ	, 0xed	},
-	{ R0900_P1_TNRCFG2	, 0x82	},
-	{ R0900_P1_TNRCFG3	, 0x02	},
-	{ R0900_P1_LDT		, 0xd0	},
-	{ R0900_P1_LDT2		, 0xb8	},
-	{ R0900_P1_TMGCFG	, 0xd2	},
-	{ R0900_P1_TMGTHRISE	, 0x20	},
-	{ R0900_P1_TMGTHFALL	, 0x00	},
-	{ R0900_P1_SFRUPRATIO	, 0xf0	},
-	{ R0900_P1_SFRLOWRATIO	, 0x70	},
-	{ R0900_P1_TSCFGL	, 0x20	},
-	{ R0900_P1_FECSPY	, 0x88	},
-	{ R0900_P1_FSPYDATA	, 0x3a	},
-	{ R0900_P1_FBERCPT4	, 0x00	},
-	{ R0900_P1_FSPYBER	, 0x10	},
-	{ R0900_P1_ERRCTRL1	, 0x35	},
-	{ R0900_P1_ERRCTRL2	, 0xc1	},
-	{ R0900_P1_CFRICFG	, 0xf8	},
-	{ R0900_P1_NOSCFG	, 0x1c	},
-	{ R0900_P1_CORRELMANT	, 0x70	},
-	{ R0900_P1_CORRELABS	, 0x88	},
-	{ R0900_P1_AGC2O	, 0x5b	},
-	{ R0900_P1_AGC2REF	, 0x38	},
-	{ R0900_P1_CARCFG	, 0xe4	},
-	{ R0900_P1_ACLC		, 0x1A	},
-	{ R0900_P1_BCLC		, 0x09	},
-	{ R0900_P1_CARHDR	, 0x08	},
-	{ R0900_P1_KREFTMG	, 0xc1	},
-	{ R0900_P1_SFRSTEP	, 0x58	},
-	{ R0900_P1_TMGCFG2	, 0x01	},
-	{ R0900_P1_CAR2CFG	, 0x26	},
-	{ R0900_P1_BCLC2S2Q	, 0x86	},
-	{ R0900_P1_BCLC2S28	, 0x86	},
-	{ R0900_P1_SMAPCOEF7	, 0x77	},
-	{ R0900_P1_SMAPCOEF6	, 0x85	},
-	{ R0900_P1_SMAPCOEF5	, 0x77	},
-	{ R0900_P1_DMDCFG2	, 0x3b	},
-	{ R0900_P1_MODCODLST0	, 0xff	},
-	{ R0900_P1_MODCODLST1	, 0xff	},
-	{ R0900_P1_MODCODLST2	, 0xff	},
-	{ R0900_P1_MODCODLST3	, 0xff	},
-	{ R0900_P1_MODCODLST4	, 0xff	},
-	{ R0900_P1_MODCODLST5	, 0xff	},
-	{ R0900_P1_MODCODLST6	, 0xff	},
-	{ R0900_P1_MODCODLST7	, 0xcc	},
-	{ R0900_P1_MODCODLST8	, 0xcc	},
-	{ R0900_P1_MODCODLST9	, 0xcc	},
-	{ R0900_P1_MODCODLSTA	, 0xcc	},
-	{ R0900_P1_MODCODLSTB	, 0xcc	},
-	{ R0900_P1_MODCODLSTC	, 0xcc	},
-	{ R0900_P1_MODCODLSTD	, 0xcc	},
-	{ R0900_P1_MODCODLSTE	, 0xcc	},
-	{ R0900_P1_MODCODLSTF	, 0xcf	},
-	{ R0900_GENCFG		, 0x1d	},
-	{ R0900_NBITER_NF4	, 0x37	},
-	{ R0900_NBITER_NF5	, 0x29	},
-	{ R0900_NBITER_NF6	, 0x37	},
-	{ R0900_NBITER_NF7	, 0x33	},
-	{ R0900_NBITER_NF8	, 0x31	},
-	{ R0900_NBITER_NF9	, 0x2f	},
-	{ R0900_NBITER_NF10	, 0x39	},
-	{ R0900_NBITER_NF11	, 0x3a	},
-	{ R0900_NBITER_NF12	, 0x29	},
-	{ R0900_NBITER_NF13	, 0x37	},
-	{ R0900_NBITER_NF14	, 0x33	},
-	{ R0900_NBITER_NF15	, 0x2f	},
-	{ R0900_NBITER_NF16	, 0x39	},
-	{ R0900_NBITER_NF17	, 0x3a	},
-	{ R0900_NBITERNOERR	, 0x04	},
-	{ R0900_GAINLLR_NF4	, 0x0C	},
-	{ R0900_GAINLLR_NF5	, 0x0F	},
-	{ R0900_GAINLLR_NF6	, 0x11	},
-	{ R0900_GAINLLR_NF7	, 0x14	},
-	{ R0900_GAINLLR_NF8	, 0x17	},
-	{ R0900_GAINLLR_NF9	, 0x19	},
-	{ R0900_GAINLLR_NF10	, 0x20	},
-	{ R0900_GAINLLR_NF11	, 0x21	},
-	{ R0900_GAINLLR_NF12	, 0x0D	},
-	{ R0900_GAINLLR_NF13	, 0x0F	},
-	{ R0900_GAINLLR_NF14	, 0x13	},
-	{ R0900_GAINLLR_NF15	, 0x1A	},
-	{ R0900_GAINLLR_NF16	, 0x1F	},
-	{ R0900_GAINLLR_NF17	, 0x21	},
-	{ R0900_RCCFG2		, 0x20	},
-	{ R0900_P1_FECM		, 0x01	}, /*disable DSS modes*/
-	{ R0900_P2_FECM		, 0x01	}, /*disable DSS modes*/
-	{ R0900_P1_PRVIT	, 0x2F	}, /*disable puncture rate 6/7*/
-	{ R0900_P2_PRVIT	, 0x2F	}, /*disable puncture rate 6/7*/
-	{ R0900_STROUT1CFG	, 0x4c	},
-	{ R0900_STROUT2CFG	, 0x4c	},
-	{ R0900_CLKOUT1CFG	, 0x50	},
-	{ R0900_CLKOUT2CFG	, 0x50	},
-	{ R0900_DPN1CFG		, 0x4a	},
-	{ R0900_DPN2CFG		, 0x4a	},
-	{ R0900_DATA71CFG	, 0x52	},
-	{ R0900_DATA72CFG	, 0x52	},
-	{ R0900_P1_TSCFGM	, 0xc0	},
-	{ R0900_P2_TSCFGM	, 0xc0	},
-	{ R0900_P1_TSCFGH	, 0xe0	}, /* DVB-CI timings */
-	{ R0900_P2_TSCFGH	, 0xe0	}, /* DVB-CI timings */
-	{ R0900_P1_TSSPEED	, 0x40	},
-	{ R0900_P2_TSSPEED	, 0x40	},
-};
-
-static const u16 STV0900_Cut20_AddOnVal[32][2] = {
-	{ R0900_P2_DMDCFG3	, 0xe8	},
-	{ R0900_P2_DMDCFG4	, 0x10	},
-	{ R0900_P2_CARFREQ	, 0x38	},
-	{ R0900_P2_CARHDR	, 0x20	},
-	{ R0900_P2_KREFTMG	, 0x5a	},
-	{ R0900_P2_SMAPCOEF7	, 0x06	},
-	{ R0900_P2_SMAPCOEF6	, 0x00	},
-	{ R0900_P2_SMAPCOEF5	, 0x04	},
-	{ R0900_P2_NOSCFG	, 0x0c	},
-	{ R0900_P1_DMDCFG3	, 0xe8	},
-	{ R0900_P1_DMDCFG4	, 0x10	},
-	{ R0900_P1_CARFREQ	, 0x38	},
-	{ R0900_P1_CARHDR	, 0x20	},
-	{ R0900_P1_KREFTMG	, 0x5a	},
-	{ R0900_P1_SMAPCOEF7	, 0x06	},
-	{ R0900_P1_SMAPCOEF6	, 0x00	},
-	{ R0900_P1_SMAPCOEF5	, 0x04	},
-	{ R0900_P1_NOSCFG	, 0x0c	},
-	{ R0900_GAINLLR_NF4	, 0x21	},
-	{ R0900_GAINLLR_NF5	, 0x21	},
-	{ R0900_GAINLLR_NF6	, 0x20	},
-	{ R0900_GAINLLR_NF7	, 0x1F	},
-	{ R0900_GAINLLR_NF8	, 0x1E	},
-	{ R0900_GAINLLR_NF9	, 0x1E	},
-	{ R0900_GAINLLR_NF10	, 0x1D	},
-	{ R0900_GAINLLR_NF11	, 0x1B	},
-	{ R0900_GAINLLR_NF12	, 0x20	},
-	{ R0900_GAINLLR_NF13	, 0x20	},
-	{ R0900_GAINLLR_NF14	, 0x20	},
-	{ R0900_GAINLLR_NF15	, 0x20	},
-	{ R0900_GAINLLR_NF16	, 0x20	},
-	{ R0900_GAINLLR_NF17	, 0x21	}
-
-};
-
-#endif
diff --git a/drivers/media/dvb/frontends/stv0900_priv.h b/drivers/media/dvb/frontends/stv0900_priv.h
deleted file mode 100644
index e0ea74c..0000000
--- a/drivers/media/dvb/frontends/stv0900_priv.h
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- * stv0900_priv.h
- *
- * Driver for ST STV0900 satellite demodulator IC.
- *
- * Copyright (C) ST Microelectronics.
- * Copyright (C) 2009 NetUP Inc.
- * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef STV0900_PRIV_H
-#define STV0900_PRIV_H
-
-#include <linux/i2c.h>
-
-#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X))
-#define INRANGE(X, Y, Z) ((((X) <= (Y)) && ((Y) <= (Z))) \
-		|| (((Z) <= (Y)) && ((Y) <= (X))) ? 1 : 0)
-
-#ifndef MAKEWORD
-#define MAKEWORD(X, Y) (((X) << 8) + (Y))
-#endif
-
-#define LSB(X) (((X) & 0xFF))
-#define MSB(Y) (((Y) >> 8) & 0xFF)
-
-#ifndef TRUE
-#define TRUE (1 == 1)
-#endif
-#ifndef FALSE
-#define FALSE (!TRUE)
-#endif
-
-#define dprintk(args...) \
-	do { \
-		if (stvdebug) \
-			printk(KERN_DEBUG args); \
-	} while (0)
-
-#define STV0900_MAXLOOKUPSIZE 500
-#define STV0900_BLIND_SEARCH_AGC2_TH 700
-#define STV0900_BLIND_SEARCH_AGC2_TH_CUT30 1400
-#define IQPOWER_THRESHOLD  30
-
-/* One point of the lookup table */
-struct stv000_lookpoint {
-	s32 realval;/* real value */
-	s32 regval;/* binary value */
-};
-
-/* Lookup table definition */
-struct stv0900_table{
-	s32 size;/* Size of the lookup table */
-	struct stv000_lookpoint table[STV0900_MAXLOOKUPSIZE];/* Lookup table */
-};
-
-enum fe_stv0900_error {
-	STV0900_NO_ERROR = 0,
-	STV0900_INVALID_HANDLE,
-	STV0900_BAD_PARAMETER,
-	STV0900_I2C_ERROR,
-	STV0900_SEARCH_FAILED,
-};
-
-enum fe_stv0900_clock_type {
-	STV0900_USE_REGISTERS_DEFAULT,
-	STV0900_SERIAL_PUNCT_CLOCK,/*Serial punctured clock */
-	STV0900_SERIAL_CONT_CLOCK,/*Serial continues clock */
-	STV0900_PARALLEL_PUNCT_CLOCK,/*Parallel punctured clock */
-	STV0900_DVBCI_CLOCK/*Parallel continues clock : DVBCI */
-};
-
-enum fe_stv0900_search_state {
-	STV0900_SEARCH = 0,
-	STV0900_PLH_DETECTED,
-	STV0900_DVBS2_FOUND,
-	STV0900_DVBS_FOUND
-
-};
-
-enum fe_stv0900_ldpc_state {
-	STV0900_PATH1_OFF_PATH2_OFF = 0,
-	STV0900_PATH1_ON_PATH2_OFF = 1,
-	STV0900_PATH1_OFF_PATH2_ON = 2,
-	STV0900_PATH1_ON_PATH2_ON = 3
-};
-
-enum fe_stv0900_signal_type {
-	STV0900_NOAGC1 = 0,
-	STV0900_AGC1OK,
-	STV0900_NOTIMING,
-	STV0900_ANALOGCARRIER,
-	STV0900_TIMINGOK,
-	STV0900_NOAGC2,
-	STV0900_AGC2OK,
-	STV0900_NOCARRIER,
-	STV0900_CARRIEROK,
-	STV0900_NODATA,
-	STV0900_DATAOK,
-	STV0900_OUTOFRANGE,
-	STV0900_RANGEOK
-};
-
-enum fe_stv0900_demod_num {
-	STV0900_DEMOD_1,
-	STV0900_DEMOD_2
-};
-
-enum fe_stv0900_tracking_standard {
-	STV0900_DVBS1_STANDARD,/* Found Standard*/
-	STV0900_DVBS2_STANDARD,
-	STV0900_DSS_STANDARD,
-	STV0900_TURBOCODE_STANDARD,
-	STV0900_UNKNOWN_STANDARD
-};
-
-enum fe_stv0900_search_standard {
-	STV0900_AUTO_SEARCH,
-	STV0900_SEARCH_DVBS1,/* Search Standard*/
-	STV0900_SEARCH_DVBS2,
-	STV0900_SEARCH_DSS,
-	STV0900_SEARCH_TURBOCODE
-};
-
-enum fe_stv0900_search_algo {
-	STV0900_BLIND_SEARCH,/* offset freq and SR are Unknown */
-	STV0900_COLD_START,/* only the SR is known */
-	STV0900_WARM_START/* offset freq and SR are known */
-};
-
-enum fe_stv0900_modulation {
-	STV0900_QPSK,
-	STV0900_8PSK,
-	STV0900_16APSK,
-	STV0900_32APSK,
-	STV0900_UNKNOWN
-};
-
-enum fe_stv0900_modcode {
-	STV0900_DUMMY_PLF,
-	STV0900_QPSK_14,
-	STV0900_QPSK_13,
-	STV0900_QPSK_25,
-	STV0900_QPSK_12,
-	STV0900_QPSK_35,
-	STV0900_QPSK_23,
-	STV0900_QPSK_34,
-	STV0900_QPSK_45,
-	STV0900_QPSK_56,
-	STV0900_QPSK_89,
-	STV0900_QPSK_910,
-	STV0900_8PSK_35,
-	STV0900_8PSK_23,
-	STV0900_8PSK_34,
-	STV0900_8PSK_56,
-	STV0900_8PSK_89,
-	STV0900_8PSK_910,
-	STV0900_16APSK_23,
-	STV0900_16APSK_34,
-	STV0900_16APSK_45,
-	STV0900_16APSK_56,
-	STV0900_16APSK_89,
-	STV0900_16APSK_910,
-	STV0900_32APSK_34,
-	STV0900_32APSK_45,
-	STV0900_32APSK_56,
-	STV0900_32APSK_89,
-	STV0900_32APSK_910,
-	STV0900_MODCODE_UNKNOWN
-};
-
-enum fe_stv0900_fec {/*DVBS1, DSS and turbo code puncture rate*/
-	STV0900_FEC_1_2 = 0,
-	STV0900_FEC_2_3,
-	STV0900_FEC_3_4,
-	STV0900_FEC_4_5,/*for turbo code only*/
-	STV0900_FEC_5_6,
-	STV0900_FEC_6_7,/*for DSS only */
-	STV0900_FEC_7_8,
-	STV0900_FEC_8_9,/*for turbo code only*/
-	STV0900_FEC_UNKNOWN
-};
-
-enum fe_stv0900_frame_length {
-	STV0900_LONG_FRAME,
-	STV0900_SHORT_FRAME
-};
-
-enum fe_stv0900_pilot {
-	STV0900_PILOTS_OFF,
-	STV0900_PILOTS_ON
-};
-
-enum fe_stv0900_rolloff {
-	STV0900_35,
-	STV0900_25,
-	STV0900_20
-};
-
-enum fe_stv0900_search_iq {
-	STV0900_IQ_AUTO,
-	STV0900_IQ_AUTO_NORMAL_FIRST,
-	STV0900_IQ_FORCE_NORMAL,
-	STV0900_IQ_FORCE_SWAPPED
-};
-
-enum stv0900_iq_inversion {
-	STV0900_IQ_NORMAL,
-	STV0900_IQ_SWAPPED
-};
-
-enum fe_stv0900_diseqc_mode {
-	STV0900_22KHZ_Continues = 0,
-	STV0900_DISEQC_2_3_PWM = 2,
-	STV0900_DISEQC_3_3_PWM = 3,
-	STV0900_DISEQC_2_3_ENVELOP = 4,
-	STV0900_DISEQC_3_3_ENVELOP = 5
-};
-
-enum fe_stv0900_demod_mode {
-	STV0900_SINGLE = 0,
-	STV0900_DUAL
-};
-
-struct stv0900_init_params{
-	u32	dmd_ref_clk;/* Reference,Input clock for the demod in Hz */
-
-	/* Demodulator Type (single demod or dual demod) */
-	enum fe_stv0900_demod_mode	demod_mode;
-	enum fe_stv0900_rolloff		rolloff;
-	enum fe_stv0900_clock_type	path1_ts_clock;
-
-	u8	tun1_maddress;
-	int	tuner1_adc;
-	int 	tuner1_type;
-
-	/* IQ from the tuner1 to the demod */
-	enum stv0900_iq_inversion	tun1_iq_inv;
-	enum fe_stv0900_clock_type	path2_ts_clock;
-
-	u8	tun2_maddress;
-	int	tuner2_adc;
-	int	tuner2_type;
-
-	/* IQ from the tuner2 to the demod */
-	enum stv0900_iq_inversion	tun2_iq_inv;
-	struct stv0900_reg		*ts_config;
-};
-
-struct stv0900_search_params {
-	enum fe_stv0900_demod_num	path;/* Path Used demod1 or 2 */
-
-	u32	frequency;/* Transponder frequency (in KHz) */
-	u32	symbol_rate;/* Transponder symbol rate  (in bds)*/
-	u32	search_range;/* Range of the search (in Hz) */
-
-	enum fe_stv0900_search_standard	standard;
-	enum fe_stv0900_modulation	modulation;
-	enum fe_stv0900_fec		fec;
-	enum fe_stv0900_modcode		modcode;
-	enum fe_stv0900_search_iq	iq_inversion;
-	enum fe_stv0900_search_algo	search_algo;
-
-};
-
-struct stv0900_signal_info {
-	int	locked;/* Transponder locked */
-	u32	frequency;/* Transponder frequency (in KHz) */
-	u32	symbol_rate;/* Transponder symbol rate  (in Mbds) */
-
-	enum fe_stv0900_tracking_standard	standard;
-	enum fe_stv0900_fec			fec;
-	enum fe_stv0900_modcode			modcode;
-	enum fe_stv0900_modulation		modulation;
-	enum fe_stv0900_pilot			pilot;
-	enum fe_stv0900_frame_length		frame_len;
-	enum stv0900_iq_inversion		spectrum;
-	enum fe_stv0900_rolloff			rolloff;
-
-	s32 Power;/* Power of the RF signal (dBm) */
-	s32 C_N;/* Carrier to noise ratio (dB x10)*/
-	u32 BER;/* Bit error rate (x10^7) */
-
-};
-
-struct stv0900_internal{
-	s32	quartz;
-	s32	mclk;
-	/* manual RollOff for DVBS1/DSS only */
-	enum fe_stv0900_rolloff		rolloff;
-	/* Demodulator use for single demod or for dual demod) */
-	enum fe_stv0900_demod_mode	demod_mode;
-
-	/*Demods */
-	s32	freq[2];
-	s32	bw[2];
-	s32	symbol_rate[2];
-	s32	srch_range[2];
-	/* for software/auto tuner */
-	int	tuner_type[2];
-
-	/* algorithm for search Blind, Cold or Warm*/
-	enum fe_stv0900_search_algo	srch_algo[2];
-	/* search standard: Auto, DVBS1/DSS only or DVBS2 only*/
-	enum fe_stv0900_search_standard	srch_standard[2];
-	/* inversion search : auto, auto norma first, normal or inverted */
-	enum fe_stv0900_search_iq	srch_iq_inv[2];
-	enum fe_stv0900_modcode		modcode[2];
-	enum fe_stv0900_modulation	modulation[2];
-	enum fe_stv0900_fec		fec[2];
-
-	struct stv0900_signal_info	result[2];
-	enum fe_stv0900_error		err[2];
-
-
-	struct i2c_adapter	*i2c_adap;
-	u8			i2c_addr;
-	u8			clkmode;/* 0 for CLKI, 2 for XTALI */
-	u8			chip_id;
-	struct stv0900_reg	*ts_config;
-	enum fe_stv0900_error	errs;
-	int dmds_used;
-};
-
-/* state for each demod */
-struct stv0900_state {
-	/* pointer for internal params, one for each pair of demods */
-	struct stv0900_internal		*internal;
-	struct i2c_adapter		*i2c_adap;
-	const struct stv0900_config	*config;
-	struct dvb_frontend		frontend;
-	int demod;
-};
-
-extern int stvdebug;
-
-extern s32 ge2comp(s32 a, s32 width);
-
-extern void stv0900_write_reg(struct stv0900_internal *i_params,
-				u16 reg_addr, u8 reg_data);
-
-extern u8 stv0900_read_reg(struct stv0900_internal *i_params,
-				u16 reg_addr);
-
-extern void stv0900_write_bits(struct stv0900_internal *i_params,
-				u32 label, u8 val);
-
-extern u8 stv0900_get_bits(struct stv0900_internal *i_params,
-				u32 label);
-
-extern int stv0900_get_demod_lock(struct stv0900_internal *i_params,
-				enum fe_stv0900_demod_num demod, s32 time_out);
-extern int stv0900_check_signal_presence(struct stv0900_internal *i_params,
-				enum fe_stv0900_demod_num demod);
-
-extern enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe);
-
-extern void stv0900_set_tuner(struct dvb_frontend *fe, u32 frequency,
-				u32 bandwidth);
-extern void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth);
-
-extern void stv0900_start_search(struct stv0900_internal *i_params,
-				enum fe_stv0900_demod_num demod);
-
-extern u8 stv0900_get_optim_carr_loop(s32 srate,
-				enum fe_stv0900_modcode modcode,
-				s32 pilot, u8 chip_id);
-
-extern u8 stv0900_get_optim_short_carr_loop(s32 srate,
-				enum fe_stv0900_modulation modulation,
-				u8 chip_id);
-
-extern void stv0900_stop_all_s2_modcod(struct stv0900_internal *i_params,
-				enum fe_stv0900_demod_num demod);
-
-extern void stv0900_activate_s2_modcod(struct stv0900_internal *i_params,
-				enum fe_stv0900_demod_num demod);
-
-extern void stv0900_activate_s2_modcod_single(struct stv0900_internal *i_params,
-				enum fe_stv0900_demod_num demod);
-
-extern enum
-fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe,
-				enum fe_stv0900_demod_num demod);
-
-extern u32
-stv0900_get_freq_auto(struct stv0900_internal *intp, int demod);
-
-extern void
-stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency,
-						u32 Bandwidth, int demod);
-
-#endif
diff --git a/drivers/media/dvb/frontends/stv0900_reg.h b/drivers/media/dvb/frontends/stv0900_reg.h
deleted file mode 100644
index 731afe9..0000000
--- a/drivers/media/dvb/frontends/stv0900_reg.h
+++ /dev/null
@@ -1,3981 +0,0 @@
-/*
- * stv0900_reg.h
- *
- * Driver for ST STV0900 satellite demodulator IC.
- *
- * Copyright (C) ST Microelectronics.
- * Copyright (C) 2009 NetUP Inc.
- * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef STV0900_REG_H
-#define STV0900_REG_H
-
-extern s32 shiftx(s32 x, int demod, s32 shift);
-
-#define REGx(x) shiftx(x, demod, 0x200)
-#define FLDx(x) shiftx(x, demod, 0x2000000)
-
-/*MID*/
-#define R0900_MID 0xf100
-#define F0900_MCHIP_IDENT 0xf10000f0
-#define F0900_MRELEASE 0xf100000f
-
-/*DACR1*/
-#define R0900_DACR1 0xf113
-#define F0900_DAC_MODE 0xf11300e0
-#define F0900_DAC_VALUE1 0xf113000f
-
-/*DACR2*/
-#define R0900_DACR2 0xf114
-#define F0900_DAC_VALUE0 0xf11400ff
-
-/*OUTCFG*/
-#define R0900_OUTCFG 0xf11c
-#define F0900_OUTSERRS1_HZ 0xf11c0040
-#define F0900_OUTSERRS2_HZ 0xf11c0020
-#define F0900_OUTSERRS3_HZ 0xf11c0010
-#define F0900_OUTPARRS3_HZ 0xf11c0008
-
-/*IRQSTATUS3*/
-#define R0900_IRQSTATUS3 0xf120
-#define F0900_SPLL_LOCK 0xf1200020
-#define F0900_SSTREAM_LCK_3 0xf1200010
-#define F0900_SSTREAM_LCK_2 0xf1200008
-#define F0900_SSTREAM_LCK_1 0xf1200004
-#define F0900_SDVBS1_PRF_2 0xf1200002
-#define F0900_SDVBS1_PRF_1 0xf1200001
-
-/*IRQSTATUS2*/
-#define R0900_IRQSTATUS2 0xf121
-#define F0900_SSPY_ENDSIM_3 0xf1210080
-#define F0900_SSPY_ENDSIM_2 0xf1210040
-#define F0900_SSPY_ENDSIM_1 0xf1210020
-#define F0900_SPKTDEL_ERROR_2 0xf1210010
-#define F0900_SPKTDEL_LOCKB_2 0xf1210008
-#define F0900_SPKTDEL_LOCK_2 0xf1210004
-#define F0900_SPKTDEL_ERROR_1 0xf1210002
-#define F0900_SPKTDEL_LOCKB_1 0xf1210001
-
-/*IRQSTATUS1*/
-#define R0900_IRQSTATUS1 0xf122
-#define F0900_SPKTDEL_LOCK_1 0xf1220080
-#define F0900_SDEMOD_LOCKB_2 0xf1220004
-#define F0900_SDEMOD_LOCK_2 0xf1220002
-#define F0900_SDEMOD_IRQ_2 0xf1220001
-
-/*IRQSTATUS0*/
-#define R0900_IRQSTATUS0 0xf123
-#define F0900_SDEMOD_LOCKB_1 0xf1230080
-#define F0900_SDEMOD_LOCK_1 0xf1230040
-#define F0900_SDEMOD_IRQ_1 0xf1230020
-#define F0900_SBCH_ERRFLAG 0xf1230010
-#define F0900_SDISEQC2RX_IRQ 0xf1230008
-#define F0900_SDISEQC2TX_IRQ 0xf1230004
-#define F0900_SDISEQC1RX_IRQ 0xf1230002
-#define F0900_SDISEQC1TX_IRQ 0xf1230001
-
-/*IRQMASK3*/
-#define R0900_IRQMASK3 0xf124
-#define F0900_MPLL_LOCK 0xf1240020
-#define F0900_MSTREAM_LCK_3 0xf1240010
-#define F0900_MSTREAM_LCK_2 0xf1240008
-#define F0900_MSTREAM_LCK_1 0xf1240004
-#define F0900_MDVBS1_PRF_2 0xf1240002
-#define F0900_MDVBS1_PRF_1 0xf1240001
-
-/*IRQMASK2*/
-#define R0900_IRQMASK2 0xf125
-#define F0900_MSPY_ENDSIM_3 0xf1250080
-#define F0900_MSPY_ENDSIM_2 0xf1250040
-#define F0900_MSPY_ENDSIM_1 0xf1250020
-#define F0900_MPKTDEL_ERROR_2 0xf1250010
-#define F0900_MPKTDEL_LOCKB_2 0xf1250008
-#define F0900_MPKTDEL_LOCK_2 0xf1250004
-#define F0900_MPKTDEL_ERROR_1 0xf1250002
-#define F0900_MPKTDEL_LOCKB_1 0xf1250001
-
-/*IRQMASK1*/
-#define R0900_IRQMASK1 0xf126
-#define F0900_MPKTDEL_LOCK_1 0xf1260080
-#define F0900_MEXTPINB2 0xf1260040
-#define F0900_MEXTPIN2 0xf1260020
-#define F0900_MEXTPINB1 0xf1260010
-#define F0900_MEXTPIN1 0xf1260008
-#define F0900_MDEMOD_LOCKB_2 0xf1260004
-#define F0900_MDEMOD_LOCK_2 0xf1260002
-#define F0900_MDEMOD_IRQ_2 0xf1260001
-
-/*IRQMASK0*/
-#define R0900_IRQMASK0 0xf127
-#define F0900_MDEMOD_LOCKB_1 0xf1270080
-#define F0900_MDEMOD_LOCK_1 0xf1270040
-#define F0900_MDEMOD_IRQ_1 0xf1270020
-#define F0900_MBCH_ERRFLAG 0xf1270010
-#define F0900_MDISEQC2RX_IRQ 0xf1270008
-#define F0900_MDISEQC2TX_IRQ 0xf1270004
-#define F0900_MDISEQC1RX_IRQ 0xf1270002
-#define F0900_MDISEQC1TX_IRQ 0xf1270001
-
-/*I2CCFG*/
-#define R0900_I2CCFG 0xf129
-#define F0900_I2C_FASTMODE 0xf1290008
-#define F0900_I2CADDR_INC 0xf1290003
-
-/*P1_I2CRPT*/
-#define R0900_P1_I2CRPT 0xf12a
-#define I2CRPT shiftx(R0900_P1_I2CRPT, demod, -1)
-#define F0900_P1_I2CT_ON 0xf12a0080
-#define I2CT_ON shiftx(F0900_P1_I2CT_ON, demod, -0x10000)
-#define F0900_P1_ENARPT_LEVEL 0xf12a0070
-#define F0900_P1_SCLT_DELAY 0xf12a0008
-#define F0900_P1_STOP_ENABLE 0xf12a0004
-#define F0900_P1_STOP_SDAT2SDA 0xf12a0002
-
-/*P2_I2CRPT*/
-#define R0900_P2_I2CRPT 0xf12b
-#define F0900_P2_I2CT_ON 0xf12b0080
-#define F0900_P2_ENARPT_LEVEL 0xf12b0070
-#define F0900_P2_SCLT_DELAY 0xf12b0008
-#define F0900_P2_STOP_ENABLE 0xf12b0004
-#define F0900_P2_STOP_SDAT2SDA 0xf12b0002
-
-/*IOPVALUE6*/
-#define R0900_IOPVALUE6 0xf138
-#define F0900_VSCL 0xf1380004
-#define F0900_VSDA 0xf1380002
-#define F0900_VDATA3_0 0xf1380001
-
-/*IOPVALUE5*/
-#define R0900_IOPVALUE5 0xf139
-#define F0900_VDATA3_1 0xf1390080
-#define F0900_VDATA3_2 0xf1390040
-#define F0900_VDATA3_3 0xf1390020
-#define F0900_VDATA3_4 0xf1390010
-#define F0900_VDATA3_5 0xf1390008
-#define F0900_VDATA3_6 0xf1390004
-#define F0900_VDATA3_7 0xf1390002
-#define F0900_VCLKOUT3 0xf1390001
-
-/*IOPVALUE4*/
-#define R0900_IOPVALUE4 0xf13a
-#define F0900_VSTROUT3 0xf13a0080
-#define F0900_VDPN3 0xf13a0040
-#define F0900_VERROR3 0xf13a0020
-#define F0900_VDATA2_7 0xf13a0010
-#define F0900_VCLKOUT2 0xf13a0008
-#define F0900_VSTROUT2 0xf13a0004
-#define F0900_VDPN2 0xf13a0002
-#define F0900_VERROR2 0xf13a0001
-
-/*IOPVALUE3*/
-#define R0900_IOPVALUE3 0xf13b
-#define F0900_VDATA1_7 0xf13b0080
-#define F0900_VCLKOUT1 0xf13b0040
-#define F0900_VSTROUT1 0xf13b0020
-#define F0900_VDPN1 0xf13b0010
-#define F0900_VERROR1 0xf13b0008
-#define F0900_VCLKOUT27 0xf13b0004
-#define F0900_VDISEQCOUT2 0xf13b0002
-#define F0900_VSCLT2 0xf13b0001
-
-/*IOPVALUE2*/
-#define R0900_IOPVALUE2 0xf13c
-#define F0900_VSDAT2 0xf13c0080
-#define F0900_VAGCRF2 0xf13c0040
-#define F0900_VDISEQCOUT1 0xf13c0020
-#define F0900_VSCLT1 0xf13c0010
-#define F0900_VSDAT1 0xf13c0008
-#define F0900_VAGCRF1 0xf13c0004
-#define F0900_VDIRCLK 0xf13c0002
-#define F0900_VSTDBY 0xf13c0001
-
-/*IOPVALUE1*/
-#define R0900_IOPVALUE1 0xf13d
-#define F0900_VCS1 0xf13d0080
-#define F0900_VCS0 0xf13d0040
-#define F0900_VGPIO13 0xf13d0020
-#define F0900_VGPIO12 0xf13d0010
-#define F0900_VGPIO11 0xf13d0008
-#define F0900_VGPIO10 0xf13d0004
-#define F0900_VGPIO9 0xf13d0002
-#define F0900_VGPIO8 0xf13d0001
-
-/*IOPVALUE0*/
-#define R0900_IOPVALUE0 0xf13e
-#define F0900_VGPIO7 0xf13e0080
-#define F0900_VGPIO6 0xf13e0040
-#define F0900_VGPIO5 0xf13e0020
-#define F0900_VGPIO4 0xf13e0010
-#define F0900_VGPIO3 0xf13e0008
-#define F0900_VGPIO2 0xf13e0004
-#define F0900_VGPIO1 0xf13e0002
-#define F0900_VCLKI2 0xf13e0001
-
-/*CLKI2CFG*/
-#define R0900_CLKI2CFG 0xf140
-#define F0900_CLKI2_OPD 0xf1400080
-#define F0900_CLKI2_CONFIG 0xf140007e
-#define F0900_CLKI2_XOR 0xf1400001
-
-/*GPIO1CFG*/
-#define R0900_GPIO1CFG 0xf141
-#define F0900_GPIO1_OPD 0xf1410080
-#define F0900_GPIO1_CONFIG 0xf141007e
-#define F0900_GPIO1_XOR 0xf1410001
-
-/*GPIO2CFG*/
-#define R0900_GPIO2CFG 0xf142
-#define F0900_GPIO2_OPD 0xf1420080
-#define F0900_GPIO2_CONFIG 0xf142007e
-#define F0900_GPIO2_XOR 0xf1420001
-
-/*GPIO3CFG*/
-#define R0900_GPIO3CFG 0xf143
-#define F0900_GPIO3_OPD 0xf1430080
-#define F0900_GPIO3_CONFIG 0xf143007e
-#define F0900_GPIO3_XOR 0xf1430001
-
-/*GPIO4CFG*/
-#define R0900_GPIO4CFG 0xf144
-#define F0900_GPIO4_OPD 0xf1440080
-#define F0900_GPIO4_CONFIG 0xf144007e
-#define F0900_GPIO4_XOR 0xf1440001
-
-/*GPIO5CFG*/
-#define R0900_GPIO5CFG 0xf145
-#define F0900_GPIO5_OPD 0xf1450080
-#define F0900_GPIO5_CONFIG 0xf145007e
-#define F0900_GPIO5_XOR 0xf1450001
-
-/*GPIO6CFG*/
-#define R0900_GPIO6CFG 0xf146
-#define F0900_GPIO6_OPD 0xf1460080
-#define F0900_GPIO6_CONFIG 0xf146007e
-#define F0900_GPIO6_XOR 0xf1460001
-
-/*GPIO7CFG*/
-#define R0900_GPIO7CFG 0xf147
-#define F0900_GPIO7_OPD 0xf1470080
-#define F0900_GPIO7_CONFIG 0xf147007e
-#define F0900_GPIO7_XOR 0xf1470001
-
-/*GPIO8CFG*/
-#define R0900_GPIO8CFG 0xf148
-#define F0900_GPIO8_OPD 0xf1480080
-#define F0900_GPIO8_CONFIG 0xf148007e
-#define F0900_GPIO8_XOR 0xf1480001
-
-/*GPIO9CFG*/
-#define R0900_GPIO9CFG 0xf149
-#define F0900_GPIO9_OPD 0xf1490080
-#define F0900_GPIO9_CONFIG 0xf149007e
-#define F0900_GPIO9_XOR 0xf1490001
-
-/*GPIO10CFG*/
-#define R0900_GPIO10CFG 0xf14a
-#define F0900_GPIO10_OPD 0xf14a0080
-#define F0900_GPIO10_CONFIG 0xf14a007e
-#define F0900_GPIO10_XOR 0xf14a0001
-
-/*GPIO11CFG*/
-#define R0900_GPIO11CFG 0xf14b
-#define F0900_GPIO11_OPD 0xf14b0080
-#define F0900_GPIO11_CONFIG 0xf14b007e
-#define F0900_GPIO11_XOR 0xf14b0001
-
-/*GPIO12CFG*/
-#define R0900_GPIO12CFG 0xf14c
-#define F0900_GPIO12_OPD 0xf14c0080
-#define F0900_GPIO12_CONFIG 0xf14c007e
-#define F0900_GPIO12_XOR 0xf14c0001
-
-/*GPIO13CFG*/
-#define R0900_GPIO13CFG 0xf14d
-#define F0900_GPIO13_OPD 0xf14d0080
-#define F0900_GPIO13_CONFIG 0xf14d007e
-#define F0900_GPIO13_XOR 0xf14d0001
-
-/*CS0CFG*/
-#define R0900_CS0CFG 0xf14e
-#define F0900_CS0_OPD 0xf14e0080
-#define F0900_CS0_CONFIG 0xf14e007e
-#define F0900_CS0_XOR 0xf14e0001
-
-/*CS1CFG*/
-#define R0900_CS1CFG 0xf14f
-#define F0900_CS1_OPD 0xf14f0080
-#define F0900_CS1_CONFIG 0xf14f007e
-#define F0900_CS1_XOR 0xf14f0001
-
-/*STDBYCFG*/
-#define R0900_STDBYCFG 0xf150
-#define F0900_STDBY_OPD 0xf1500080
-#define F0900_STDBY_CONFIG 0xf150007e
-#define F0900_STBDY_XOR 0xf1500001
-
-/*DIRCLKCFG*/
-#define R0900_DIRCLKCFG 0xf151
-#define F0900_DIRCLK_OPD 0xf1510080
-#define F0900_DIRCLK_CONFIG 0xf151007e
-#define F0900_DIRCLK_XOR 0xf1510001
-
-/*AGCRF1CFG*/
-#define R0900_AGCRF1CFG 0xf152
-#define F0900_AGCRF1_OPD 0xf1520080
-#define F0900_AGCRF1_CONFIG 0xf152007e
-#define F0900_AGCRF1_XOR 0xf1520001
-
-/*SDAT1CFG*/
-#define R0900_SDAT1CFG 0xf153
-#define F0900_SDAT1_OPD 0xf1530080
-#define F0900_SDAT1_CONFIG 0xf153007e
-#define F0900_SDAT1_XOR 0xf1530001
-
-/*SCLT1CFG*/
-#define R0900_SCLT1CFG 0xf154
-#define F0900_SCLT1_OPD 0xf1540080
-#define F0900_SCLT1_CONFIG 0xf154007e
-#define F0900_SCLT1_XOR 0xf1540001
-
-/*DISEQCO1CFG*/
-#define R0900_DISEQCO1CFG 0xf155
-#define F0900_DISEQCO1_OPD 0xf1550080
-#define F0900_DISEQCO1_CONFIG 0xf155007e
-#define F0900_DISEQC1_XOR 0xf1550001
-
-/*AGCRF2CFG*/
-#define R0900_AGCRF2CFG 0xf156
-#define F0900_AGCRF2_OPD 0xf1560080
-#define F0900_AGCRF2_CONFIG 0xf156007e
-#define F0900_AGCRF2_XOR 0xf1560001
-
-/*SDAT2CFG*/
-#define R0900_SDAT2CFG 0xf157
-#define F0900_SDAT2_OPD 0xf1570080
-#define F0900_SDAT2_CONFIG 0xf157007e
-#define F0900_SDAT2_XOR 0xf1570001
-
-/*SCLT2CFG*/
-#define R0900_SCLT2CFG 0xf158
-#define F0900_SCLT2_OPD 0xf1580080
-#define F0900_SCLT2_CONFIG 0xf158007e
-#define F0900_SCLT2_XOR 0xf1580001
-
-/*DISEQCO2CFG*/
-#define R0900_DISEQCO2CFG 0xf159
-#define F0900_DISEQCO2_OPD 0xf1590080
-#define F0900_DISEQCO2_CONFIG 0xf159007e
-#define F0900_DISEQC2_XOR 0xf1590001
-
-/*CLKOUT27CFG*/
-#define R0900_CLKOUT27CFG 0xf15a
-#define F0900_CLKOUT27_OPD 0xf15a0080
-#define F0900_CLKOUT27_CONFIG 0xf15a007e
-#define F0900_CLKOUT27_XOR 0xf15a0001
-
-/*ERROR1CFG*/
-#define R0900_ERROR1CFG 0xf15b
-#define F0900_ERROR1_OPD 0xf15b0080
-#define F0900_ERROR1_CONFIG 0xf15b007e
-#define F0900_ERROR1_XOR 0xf15b0001
-
-/*DPN1CFG*/
-#define R0900_DPN1CFG 0xf15c
-#define F0900_DPN1_OPD 0xf15c0080
-#define F0900_DPN1_CONFIG 0xf15c007e
-#define F0900_DPN1_XOR 0xf15c0001
-
-/*STROUT1CFG*/
-#define R0900_STROUT1CFG 0xf15d
-#define F0900_STROUT1_OPD 0xf15d0080
-#define F0900_STROUT1_CONFIG 0xf15d007e
-#define F0900_STROUT1_XOR 0xf15d0001
-
-/*CLKOUT1CFG*/
-#define R0900_CLKOUT1CFG 0xf15e
-#define F0900_CLKOUT1_OPD 0xf15e0080
-#define F0900_CLKOUT1_CONFIG 0xf15e007e
-#define F0900_CLKOUT1_XOR 0xf15e0001
-
-/*DATA71CFG*/
-#define R0900_DATA71CFG 0xf15f
-#define F0900_DATA71_OPD 0xf15f0080
-#define F0900_DATA71_CONFIG 0xf15f007e
-#define F0900_DATA71_XOR 0xf15f0001
-
-/*ERROR2CFG*/
-#define R0900_ERROR2CFG 0xf160
-#define F0900_ERROR2_OPD 0xf1600080
-#define F0900_ERROR2_CONFIG 0xf160007e
-#define F0900_ERROR2_XOR 0xf1600001
-
-/*DPN2CFG*/
-#define R0900_DPN2CFG 0xf161
-#define F0900_DPN2_OPD 0xf1610080
-#define F0900_DPN2_CONFIG 0xf161007e
-#define F0900_DPN2_XOR 0xf1610001
-
-/*STROUT2CFG*/
-#define R0900_STROUT2CFG 0xf162
-#define F0900_STROUT2_OPD 0xf1620080
-#define F0900_STROUT2_CONFIG 0xf162007e
-#define F0900_STROUT2_XOR 0xf1620001
-
-/*CLKOUT2CFG*/
-#define R0900_CLKOUT2CFG 0xf163
-#define F0900_CLKOUT2_OPD 0xf1630080
-#define F0900_CLKOUT2_CONFIG 0xf163007e
-#define F0900_CLKOUT2_XOR 0xf1630001
-
-/*DATA72CFG*/
-#define R0900_DATA72CFG 0xf164
-#define F0900_DATA72_OPD 0xf1640080
-#define F0900_DATA72_CONFIG 0xf164007e
-#define F0900_DATA72_XOR 0xf1640001
-
-/*ERROR3CFG*/
-#define R0900_ERROR3CFG 0xf165
-#define F0900_ERROR3_OPD 0xf1650080
-#define F0900_ERROR3_CONFIG 0xf165007e
-#define F0900_ERROR3_XOR 0xf1650001
-
-/*DPN3CFG*/
-#define R0900_DPN3CFG 0xf166
-#define F0900_DPN3_OPD 0xf1660080
-#define F0900_DPN3_CONFIG 0xf166007e
-#define F0900_DPN3_XOR 0xf1660001
-
-/*STROUT3CFG*/
-#define R0900_STROUT3CFG 0xf167
-#define F0900_STROUT3_OPD 0xf1670080
-#define F0900_STROUT3_CONFIG 0xf167007e
-#define F0900_STROUT3_XOR 0xf1670001
-
-/*CLKOUT3CFG*/
-#define R0900_CLKOUT3CFG 0xf168
-#define F0900_CLKOUT3_OPD 0xf1680080
-#define F0900_CLKOUT3_CONFIG 0xf168007e
-#define F0900_CLKOUT3_XOR 0xf1680001
-
-/*DATA73CFG*/
-#define R0900_DATA73CFG 0xf169
-#define F0900_DATA73_OPD 0xf1690080
-#define F0900_DATA73_CONFIG 0xf169007e
-#define F0900_DATA73_XOR 0xf1690001
-
-/*STRSTATUS1*/
-#define R0900_STRSTATUS1 0xf16a
-#define F0900_STRSTATUS_SEL2 0xf16a00f0
-#define F0900_STRSTATUS_SEL1 0xf16a000f
-
-/*STRSTATUS2*/
-#define R0900_STRSTATUS2 0xf16b
-#define F0900_STRSTATUS_SEL4 0xf16b00f0
-#define F0900_STRSTATUS_SEL3 0xf16b000f
-
-/*STRSTATUS3*/
-#define R0900_STRSTATUS3 0xf16c
-#define F0900_STRSTATUS_SEL6 0xf16c00f0
-#define F0900_STRSTATUS_SEL5 0xf16c000f
-
-/*FSKTFC2*/
-#define R0900_FSKTFC2 0xf170
-#define F0900_FSKT_KMOD 0xf17000fc
-#define F0900_FSKT_CAR2 0xf1700003
-
-/*FSKTFC1*/
-#define R0900_FSKTFC1 0xf171
-#define F0900_FSKT_CAR1 0xf17100ff
-
-/*FSKTFC0*/
-#define R0900_FSKTFC0 0xf172
-#define F0900_FSKT_CAR0 0xf17200ff
-
-/*FSKTDELTAF1*/
-#define R0900_FSKTDELTAF1 0xf173
-#define F0900_FSKT_DELTAF1 0xf173000f
-
-/*FSKTDELTAF0*/
-#define R0900_FSKTDELTAF0 0xf174
-#define F0900_FSKT_DELTAF0 0xf17400ff
-
-/*FSKTCTRL*/
-#define R0900_FSKTCTRL 0xf175
-#define F0900_FSKT_EN_SGN 0xf1750040
-#define F0900_FSKT_MOD_SGN 0xf1750020
-#define F0900_FSKT_MOD_EN 0xf175001c
-#define F0900_FSKT_DACMODE 0xf1750003
-
-/*FSKRFC2*/
-#define R0900_FSKRFC2 0xf176
-#define F0900_FSKR_DETSGN 0xf1760040
-#define F0900_FSKR_OUTSGN 0xf1760020
-#define F0900_FSKR_KAGC 0xf176001c
-#define F0900_FSKR_CAR2 0xf1760003
-
-/*FSKRFC1*/
-#define R0900_FSKRFC1 0xf177
-#define F0900_FSKR_CAR1 0xf17700ff
-
-/*FSKRFC0*/
-#define R0900_FSKRFC0 0xf178
-#define F0900_FSKR_CAR0 0xf17800ff
-
-/*FSKRK1*/
-#define R0900_FSKRK1 0xf179
-#define F0900_FSKR_K1_EXP 0xf17900e0
-#define F0900_FSKR_K1_MANT 0xf179001f
-
-/*FSKRK2*/
-#define R0900_FSKRK2 0xf17a
-#define F0900_FSKR_K2_EXP 0xf17a00e0
-#define F0900_FSKR_K2_MANT 0xf17a001f
-
-/*FSKRAGCR*/
-#define R0900_FSKRAGCR 0xf17b
-#define F0900_FSKR_OUTCTL 0xf17b00c0
-#define F0900_FSKR_AGC_REF 0xf17b003f
-
-/*FSKRAGC*/
-#define R0900_FSKRAGC 0xf17c
-#define F0900_FSKR_AGC_ACCU 0xf17c00ff
-
-/*FSKRALPHA*/
-#define R0900_FSKRALPHA 0xf17d
-#define F0900_FSKR_ALPHA_EXP 0xf17d001c
-#define F0900_FSKR_ALPHA_M 0xf17d0003
-
-/*FSKRPLTH1*/
-#define R0900_FSKRPLTH1 0xf17e
-#define F0900_FSKR_BETA 0xf17e00f0
-#define F0900_FSKR_PLL_TRESH1 0xf17e000f
-
-/*FSKRPLTH0*/
-#define R0900_FSKRPLTH0 0xf17f
-#define F0900_FSKR_PLL_TRESH0 0xf17f00ff
-
-/*FSKRDF1*/
-#define R0900_FSKRDF1 0xf180
-#define F0900_FSKR_OUT 0xf1800080
-#define F0900_FSKR_DELTAF1 0xf180001f
-
-/*FSKRDF0*/
-#define R0900_FSKRDF0 0xf181
-#define F0900_FSKR_DELTAF0 0xf18100ff
-
-/*FSKRSTEPP*/
-#define R0900_FSKRSTEPP 0xf182
-#define F0900_FSKR_STEP_PLUS 0xf18200ff
-
-/*FSKRSTEPM*/
-#define R0900_FSKRSTEPM 0xf183
-#define F0900_FSKR_STEP_MINUS 0xf18300ff
-
-/*FSKRDET1*/
-#define R0900_FSKRDET1 0xf184
-#define F0900_FSKR_DETECT 0xf1840080
-#define F0900_FSKR_CARDET_ACCU1 0xf184000f
-
-/*FSKRDET0*/
-#define R0900_FSKRDET0 0xf185
-#define F0900_FSKR_CARDET_ACCU0 0xf18500ff
-
-/*FSKRDTH1*/
-#define R0900_FSKRDTH1 0xf186
-#define F0900_FSKR_CARLOSS_THRESH1 0xf18600f0
-#define F0900_FSKR_CARDET_THRESH1 0xf186000f
-
-/*FSKRDTH0*/
-#define R0900_FSKRDTH0 0xf187
-#define F0900_FSKR_CARDET_THRESH0 0xf18700ff
-
-/*FSKRLOSS*/
-#define R0900_FSKRLOSS 0xf188
-#define F0900_FSKR_CARLOSS_THRESH0 0xf18800ff
-
-/*P2_DISTXCTL*/
-#define R0900_P2_DISTXCTL 0xf190
-#define F0900_P2_TIM_OFF 0xf1900080
-#define F0900_P2_DISEQC_RESET 0xf1900040
-#define F0900_P2_TIM_CMD 0xf1900030
-#define F0900_P2_DIS_PRECHARGE 0xf1900008
-#define F0900_P2_DISTX_MODE 0xf1900007
-
-/*P2_DISRXCTL*/
-#define R0900_P2_DISRXCTL 0xf191
-#define F0900_P2_RECEIVER_ON 0xf1910080
-#define F0900_P2_IGNO_SHORT22K 0xf1910040
-#define F0900_P2_ONECHIP_TRX 0xf1910020
-#define F0900_P2_EXT_ENVELOP 0xf1910010
-#define F0900_P2_PIN_SELECT0 0xf191000c
-#define F0900_P2_IRQ_RXEND 0xf1910002
-#define F0900_P2_IRQ_4NBYTES 0xf1910001
-
-/*P2_DISRX_ST0*/
-#define R0900_P2_DISRX_ST0 0xf194
-#define F0900_P2_RX_END 0xf1940080
-#define F0900_P2_RX_ACTIVE 0xf1940040
-#define F0900_P2_SHORT_22KHZ 0xf1940020
-#define F0900_P2_CONT_TONE 0xf1940010
-#define F0900_P2_FIFO_4BREADY 0xf1940008
-#define F0900_P2_FIFO_EMPTY 0xf1940004
-#define F0900_P2_ABORT_DISRX 0xf1940001
-
-/*P2_DISRX_ST1*/
-#define R0900_P2_DISRX_ST1 0xf195
-#define F0900_P2_RX_FAIL 0xf1950080
-#define F0900_P2_FIFO_PARITYFAIL 0xf1950040
-#define F0900_P2_RX_NONBYTE 0xf1950020
-#define F0900_P2_FIFO_OVERFLOW 0xf1950010
-#define F0900_P2_FIFO_BYTENBR 0xf195000f
-
-/*P2_DISRXDATA*/
-#define R0900_P2_DISRXDATA 0xf196
-#define F0900_P2_DISRX_DATA 0xf19600ff
-
-/*P2_DISTXDATA*/
-#define R0900_P2_DISTXDATA 0xf197
-#define F0900_P2_DISEQC_FIFO 0xf19700ff
-
-/*P2_DISTXSTATUS*/
-#define R0900_P2_DISTXSTATUS 0xf198
-#define F0900_P2_TX_FAIL 0xf1980080
-#define F0900_P2_FIFO_FULL 0xf1980040
-#define F0900_P2_TX_IDLE 0xf1980020
-#define F0900_P2_GAP_BURST 0xf1980010
-#define F0900_P2_TXFIFO_BYTES 0xf198000f
-
-/*P2_F22TX*/
-#define R0900_P2_F22TX 0xf199
-#define F0900_P2_F22_REG 0xf19900ff
-
-/*P2_F22RX*/
-#define R0900_P2_F22RX 0xf19a
-#define F0900_P2_F22RX_REG 0xf19a00ff
-
-/*P2_ACRPRESC*/
-#define R0900_P2_ACRPRESC 0xf19c
-#define F0900_P2_ACR_PRESC 0xf19c0007
-
-/*P2_ACRDIV*/
-#define R0900_P2_ACRDIV 0xf19d
-#define F0900_P2_ACR_DIV 0xf19d00ff
-
-/*P1_DISTXCTL*/
-#define R0900_P1_DISTXCTL 0xf1a0
-#define DISTXCTL shiftx(R0900_P1_DISTXCTL, demod, 0x10)
-#define F0900_P1_TIM_OFF 0xf1a00080
-#define F0900_P1_DISEQC_RESET 0xf1a00040
-#define DISEQC_RESET shiftx(F0900_P1_DISEQC_RESET, demod, 0x100000)
-#define F0900_P1_TIM_CMD 0xf1a00030
-#define F0900_P1_DIS_PRECHARGE 0xf1a00008
-#define DIS_PRECHARGE shiftx(F0900_P1_DIS_PRECHARGE, demod, 0x100000)
-#define F0900_P1_DISTX_MODE 0xf1a00007
-#define DISTX_MODE shiftx(F0900_P1_DISTX_MODE, demod, 0x100000)
-
-/*P1_DISRXCTL*/
-#define R0900_P1_DISRXCTL 0xf1a1
-#define DISRXCTL shiftx(R0900_P1_DISRXCTL, demod, 0x10)
-#define F0900_P1_RECEIVER_ON 0xf1a10080
-#define F0900_P1_IGNO_SHORT22K 0xf1a10040
-#define F0900_P1_ONECHIP_TRX 0xf1a10020
-#define F0900_P1_EXT_ENVELOP 0xf1a10010
-#define F0900_P1_PIN_SELECT0 0xf1a1000c
-#define F0900_P1_IRQ_RXEND 0xf1a10002
-#define F0900_P1_IRQ_4NBYTES 0xf1a10001
-
-/*P1_DISRX_ST0*/
-#define R0900_P1_DISRX_ST0 0xf1a4
-#define DISRX_ST0 shiftx(R0900_P1_DISRX_ST0, demod, 0x10)
-#define F0900_P1_RX_END 0xf1a40080
-#define RX_END shiftx(F0900_P1_RX_END, demod, 0x100000)
-#define F0900_P1_RX_ACTIVE 0xf1a40040
-#define F0900_P1_SHORT_22KHZ 0xf1a40020
-#define F0900_P1_CONT_TONE 0xf1a40010
-#define F0900_P1_FIFO_4BREADY 0xf1a40008
-#define F0900_P1_FIFO_EMPTY 0xf1a40004
-#define F0900_P1_ABORT_DISRX 0xf1a40001
-
-/*P1_DISRX_ST1*/
-#define R0900_P1_DISRX_ST1 0xf1a5
-#define DISRX_ST1 shiftx(R0900_P1_DISRX_ST1, demod, 0x10)
-#define F0900_P1_RX_FAIL 0xf1a50080
-#define F0900_P1_FIFO_PARITYFAIL 0xf1a50040
-#define F0900_P1_RX_NONBYTE 0xf1a50020
-#define F0900_P1_FIFO_OVERFLOW 0xf1a50010
-#define F0900_P1_FIFO_BYTENBR 0xf1a5000f
-#define FIFO_BYTENBR shiftx(F0900_P1_FIFO_BYTENBR, demod, 0x100000)
-
-/*P1_DISRXDATA*/
-#define R0900_P1_DISRXDATA 0xf1a6
-#define DISRXDATA shiftx(R0900_P1_DISRXDATA, demod, 0x10)
-#define F0900_P1_DISRX_DATA 0xf1a600ff
-
-/*P1_DISTXDATA*/
-#define R0900_P1_DISTXDATA 0xf1a7
-#define DISTXDATA shiftx(R0900_P1_DISTXDATA, demod, 0x10)
-#define F0900_P1_DISEQC_FIFO 0xf1a700ff
-
-/*P1_DISTXSTATUS*/
-#define R0900_P1_DISTXSTATUS 0xf1a8
-#define F0900_P1_TX_FAIL 0xf1a80080
-#define F0900_P1_FIFO_FULL 0xf1a80040
-#define FIFO_FULL shiftx(F0900_P1_FIFO_FULL, demod, 0x100000)
-#define F0900_P1_TX_IDLE 0xf1a80020
-#define TX_IDLE shiftx(F0900_P1_TX_IDLE, demod, 0x100000)
-#define F0900_P1_GAP_BURST 0xf1a80010
-#define F0900_P1_TXFIFO_BYTES 0xf1a8000f
-
-/*P1_F22TX*/
-#define R0900_P1_F22TX 0xf1a9
-#define F22TX shiftx(R0900_P1_F22TX, demod, 0x10)
-#define F0900_P1_F22_REG 0xf1a900ff
-
-/*P1_F22RX*/
-#define R0900_P1_F22RX 0xf1aa
-#define F22RX shiftx(R0900_P1_F22RX, demod, 0x10)
-#define F0900_P1_F22RX_REG 0xf1aa00ff
-
-/*P1_ACRPRESC*/
-#define R0900_P1_ACRPRESC 0xf1ac
-#define ACRPRESC shiftx(R0900_P1_ACRPRESC, demod, 0x10)
-#define F0900_P1_ACR_PRESC 0xf1ac0007
-
-/*P1_ACRDIV*/
-#define R0900_P1_ACRDIV 0xf1ad
-#define ACRDIV shiftx(R0900_P1_ACRDIV, demod, 0x10)
-#define F0900_P1_ACR_DIV 0xf1ad00ff
-
-/*NCOARSE*/
-#define R0900_NCOARSE 0xf1b3
-#define F0900_M_DIV 0xf1b300ff
-
-/*SYNTCTRL*/
-#define R0900_SYNTCTRL 0xf1b6
-#define F0900_STANDBY 0xf1b60080
-#define F0900_BYPASSPLLCORE 0xf1b60040
-#define F0900_SELX1RATIO 0xf1b60020
-#define F0900_STOP_PLL 0xf1b60008
-#define F0900_BYPASSPLLFSK 0xf1b60004
-#define F0900_SELOSCI 0xf1b60002
-#define F0900_BYPASSPLLADC 0xf1b60001
-
-/*FILTCTRL*/
-#define R0900_FILTCTRL 0xf1b7
-#define F0900_INV_CLK135 0xf1b70080
-#define F0900_SEL_FSKCKDIV 0xf1b70004
-#define F0900_INV_CLKFSK 0xf1b70002
-#define F0900_BYPASS_APPLI 0xf1b70001
-
-/*PLLSTAT*/
-#define R0900_PLLSTAT 0xf1b8
-#define F0900_PLLLOCK 0xf1b80001
-
-/*STOPCLK1*/
-#define R0900_STOPCLK1 0xf1c2
-#define F0900_STOP_CLKPKDT2 0xf1c20040
-#define F0900_STOP_CLKPKDT1 0xf1c20020
-#define F0900_STOP_CLKFEC 0xf1c20010
-#define F0900_STOP_CLKADCI2 0xf1c20008
-#define F0900_INV_CLKADCI2 0xf1c20004
-#define F0900_STOP_CLKADCI1 0xf1c20002
-#define F0900_INV_CLKADCI1 0xf1c20001
-
-/*STOPCLK2*/
-#define R0900_STOPCLK2 0xf1c3
-#define F0900_STOP_CLKSAMP2 0xf1c30010
-#define F0900_STOP_CLKSAMP1 0xf1c30008
-#define F0900_STOP_CLKVIT2 0xf1c30004
-#define F0900_STOP_CLKVIT1 0xf1c30002
-#define STOP_CLKVIT shiftx(F0900_STOP_CLKVIT1, demod, -2)
-#define F0900_STOP_CLKTS 0xf1c30001
-
-/*TSTTNR0*/
-#define R0900_TSTTNR0 0xf1df
-#define F0900_SEL_FSK 0xf1df0080
-#define F0900_FSK_PON 0xf1df0004
-
-/*TSTTNR1*/
-#define R0900_TSTTNR1 0xf1e0
-#define F0900_ADC1_PON 0xf1e00002
-#define F0900_ADC1_INMODE 0xf1e00001
-
-/*TSTTNR2*/
-#define R0900_TSTTNR2 0xf1e1
-#define F0900_DISEQC1_PON 0xf1e10020
-
-/*TSTTNR3*/
-#define R0900_TSTTNR3 0xf1e2
-#define F0900_ADC2_PON 0xf1e20002
-#define F0900_ADC2_INMODE 0xf1e20001
-
-/*TSTTNR4*/
-#define R0900_TSTTNR4 0xf1e3
-#define F0900_DISEQC2_PON 0xf1e30020
-
-/*P2_IQCONST*/
-#define R0900_P2_IQCONST 0xf200
-#define F0900_P2_CONSTEL_SELECT 0xf2000060
-#define F0900_P2_IQSYMB_SEL 0xf200001f
-
-/*P2_NOSCFG*/
-#define R0900_P2_NOSCFG 0xf201
-#define F0900_P2_DUMMYPL_NOSDATA 0xf2010020
-#define F0900_P2_NOSPLH_BETA 0xf2010018
-#define F0900_P2_NOSDATA_BETA 0xf2010007
-
-/*P2_ISYMB*/
-#define R0900_P2_ISYMB 0xf202
-#define F0900_P2_I_SYMBOL 0xf20201ff
-
-/*P2_QSYMB*/
-#define R0900_P2_QSYMB 0xf203
-#define F0900_P2_Q_SYMBOL 0xf20301ff
-
-/*P2_AGC1CFG*/
-#define R0900_P2_AGC1CFG 0xf204
-#define F0900_P2_DC_FROZEN 0xf2040080
-#define F0900_P2_DC_CORRECT 0xf2040040
-#define F0900_P2_AMM_FROZEN 0xf2040020
-#define F0900_P2_AMM_CORRECT 0xf2040010
-#define F0900_P2_QUAD_FROZEN 0xf2040008
-#define F0900_P2_QUAD_CORRECT 0xf2040004
-
-/*P2_AGC1CN*/
-#define R0900_P2_AGC1CN 0xf206
-#define F0900_P2_AGC1_LOCKED 0xf2060080
-#define F0900_P2_AGC1_MINPOWER 0xf2060010
-#define F0900_P2_AGCOUT_FAST 0xf2060008
-#define F0900_P2_AGCIQ_BETA 0xf2060007
-
-/*P2_AGC1REF*/
-#define R0900_P2_AGC1REF 0xf207
-#define F0900_P2_AGCIQ_REF 0xf20700ff
-
-/*P2_IDCCOMP*/
-#define R0900_P2_IDCCOMP 0xf208
-#define F0900_P2_IAVERAGE_ADJ 0xf20801ff
-
-/*P2_QDCCOMP*/
-#define R0900_P2_QDCCOMP 0xf209
-#define F0900_P2_QAVERAGE_ADJ 0xf20901ff
-
-/*P2_POWERI*/
-#define R0900_P2_POWERI 0xf20a
-#define F0900_P2_POWER_I 0xf20a00ff
-
-/*P2_POWERQ*/
-#define R0900_P2_POWERQ 0xf20b
-#define F0900_P2_POWER_Q 0xf20b00ff
-
-/*P2_AGC1AMM*/
-#define R0900_P2_AGC1AMM 0xf20c
-#define F0900_P2_AMM_VALUE 0xf20c00ff
-
-/*P2_AGC1QUAD*/
-#define R0900_P2_AGC1QUAD 0xf20d
-#define F0900_P2_QUAD_VALUE 0xf20d01ff
-
-/*P2_AGCIQIN1*/
-#define R0900_P2_AGCIQIN1 0xf20e
-#define F0900_P2_AGCIQ_VALUE1 0xf20e00ff
-
-/*P2_AGCIQIN0*/
-#define R0900_P2_AGCIQIN0 0xf20f
-#define F0900_P2_AGCIQ_VALUE0 0xf20f00ff
-
-/*P2_DEMOD*/
-#define R0900_P2_DEMOD 0xf210
-#define F0900_P2_MANUALS2_ROLLOFF 0xf2100080
-#define F0900_P2_SPECINV_CONTROL 0xf2100030
-#define F0900_P2_FORCE_ENASAMP 0xf2100008
-#define F0900_P2_MANUALSX_ROLLOFF 0xf2100004
-#define F0900_P2_ROLLOFF_CONTROL 0xf2100003
-
-/*P2_DMDMODCOD*/
-#define R0900_P2_DMDMODCOD 0xf211
-#define F0900_P2_MANUAL_MODCOD 0xf2110080
-#define F0900_P2_DEMOD_MODCOD 0xf211007c
-#define F0900_P2_DEMOD_TYPE 0xf2110003
-
-/*P2_DSTATUS*/
-#define R0900_P2_DSTATUS 0xf212
-#define F0900_P2_CAR_LOCK 0xf2120080
-#define F0900_P2_TMGLOCK_QUALITY 0xf2120060
-#define F0900_P2_LOCK_DEFINITIF 0xf2120008
-#define F0900_P2_OVADC_DETECT 0xf2120001
-
-/*P2_DSTATUS2*/
-#define R0900_P2_DSTATUS2 0xf213
-#define F0900_P2_DEMOD_DELOCK 0xf2130080
-#define F0900_P2_AGC1_NOSIGNALACK 0xf2130008
-#define F0900_P2_AGC2_OVERFLOW 0xf2130004
-#define F0900_P2_CFR_OVERFLOW 0xf2130002
-#define F0900_P2_GAMMA_OVERUNDER 0xf2130001
-
-/*P2_DMDCFGMD*/
-#define R0900_P2_DMDCFGMD 0xf214
-#define F0900_P2_DVBS2_ENABLE 0xf2140080
-#define F0900_P2_DVBS1_ENABLE 0xf2140040
-#define F0900_P2_SCAN_ENABLE 0xf2140010
-#define F0900_P2_CFR_AUTOSCAN 0xf2140008
-#define F0900_P2_TUN_RNG 0xf2140003
-
-/*P2_DMDCFG2*/
-#define R0900_P2_DMDCFG2 0xf215
-#define F0900_P2_S1S2_SEQUENTIAL 0xf2150040
-#define F0900_P2_INFINITE_RELOCK 0xf2150010
-
-/*P2_DMDISTATE*/
-#define R0900_P2_DMDISTATE 0xf216
-#define F0900_P2_I2C_DEMOD_MODE 0xf216001f
-
-/*P2_DMDT0M*/
-#define R0900_P2_DMDT0M 0xf217
-#define F0900_P2_DMDT0_MIN 0xf21700ff
-
-/*P2_DMDSTATE*/
-#define R0900_P2_DMDSTATE 0xf21b
-#define F0900_P2_HEADER_MODE 0xf21b0060
-
-/*P2_DMDFLYW*/
-#define R0900_P2_DMDFLYW 0xf21c
-#define F0900_P2_I2C_IRQVAL 0xf21c00f0
-#define F0900_P2_FLYWHEEL_CPT 0xf21c000f
-
-/*P2_DSTATUS3*/
-#define R0900_P2_DSTATUS3 0xf21d
-#define F0900_P2_DEMOD_CFGMODE 0xf21d0060
-
-/*P2_DMDCFG3*/
-#define R0900_P2_DMDCFG3 0xf21e
-#define F0900_P2_NOSTOP_FIFOFULL 0xf21e0008
-
-/*P2_DMDCFG4*/
-#define R0900_P2_DMDCFG4 0xf21f
-#define F0900_P2_TUNER_NRELAUNCH 0xf21f0008
-
-/*P2_CORRELMANT*/
-#define R0900_P2_CORRELMANT 0xf220
-#define F0900_P2_CORREL_MANT 0xf22000ff
-
-/*P2_CORRELABS*/
-#define R0900_P2_CORRELABS 0xf221
-#define F0900_P2_CORREL_ABS 0xf22100ff
-
-/*P2_CORRELEXP*/
-#define R0900_P2_CORRELEXP 0xf222
-#define F0900_P2_CORREL_ABSEXP 0xf22200f0
-#define F0900_P2_CORREL_EXP 0xf222000f
-
-/*P2_PLHMODCOD*/
-#define R0900_P2_PLHMODCOD 0xf224
-#define F0900_P2_SPECINV_DEMOD 0xf2240080
-#define F0900_P2_PLH_MODCOD 0xf224007c
-#define F0900_P2_PLH_TYPE 0xf2240003
-
-/*P2_DMDREG*/
-#define R0900_P2_DMDREG 0xf225
-#define F0900_P2_DECIM_PLFRAMES 0xf2250001
-
-/*P2_AGC2O*/
-#define R0900_P2_AGC2O 0xf22c
-#define F0900_P2_AGC2_COEF 0xf22c0007
-
-/*P2_AGC2REF*/
-#define R0900_P2_AGC2REF 0xf22d
-#define F0900_P2_AGC2_REF 0xf22d00ff
-
-/*P2_AGC1ADJ*/
-#define R0900_P2_AGC1ADJ 0xf22e
-#define F0900_P2_AGC1_ADJUSTED 0xf22e007f
-
-/*P2_AGC2I1*/
-#define R0900_P2_AGC2I1 0xf236
-#define F0900_P2_AGC2_INTEGRATOR1 0xf23600ff
-
-/*P2_AGC2I0*/
-#define R0900_P2_AGC2I0 0xf237
-#define F0900_P2_AGC2_INTEGRATOR0 0xf23700ff
-
-/*P2_CARCFG*/
-#define R0900_P2_CARCFG 0xf238
-#define F0900_P2_CFRUPLOW_AUTO 0xf2380080
-#define F0900_P2_CFRUPLOW_TEST 0xf2380040
-#define F0900_P2_ROTAON 0xf2380004
-#define F0900_P2_PH_DET_ALGO 0xf2380003
-
-/*P2_ACLC*/
-#define R0900_P2_ACLC 0xf239
-#define F0900_P2_CAR_ALPHA_MANT 0xf2390030
-#define F0900_P2_CAR_ALPHA_EXP 0xf239000f
-
-/*P2_BCLC*/
-#define R0900_P2_BCLC 0xf23a
-#define F0900_P2_CAR_BETA_MANT 0xf23a0030
-#define F0900_P2_CAR_BETA_EXP 0xf23a000f
-
-/*P2_CARFREQ*/
-#define R0900_P2_CARFREQ 0xf23d
-#define F0900_P2_KC_COARSE_EXP 0xf23d00f0
-#define F0900_P2_BETA_FREQ 0xf23d000f
-
-/*P2_CARHDR*/
-#define R0900_P2_CARHDR 0xf23e
-#define F0900_P2_K_FREQ_HDR 0xf23e00ff
-
-/*P2_LDT*/
-#define R0900_P2_LDT 0xf23f
-#define F0900_P2_CARLOCK_THRES 0xf23f01ff
-
-/*P2_LDT2*/
-#define R0900_P2_LDT2 0xf240
-#define F0900_P2_CARLOCK_THRES2 0xf24001ff
-
-/*P2_CFRICFG*/
-#define R0900_P2_CFRICFG 0xf241
-#define F0900_P2_NEG_CFRSTEP 0xf2410001
-
-/*P2_CFRUP1*/
-#define R0900_P2_CFRUP1 0xf242
-#define F0900_P2_CFR_UP1 0xf24201ff
-
-/*P2_CFRUP0*/
-#define R0900_P2_CFRUP0 0xf243
-#define F0900_P2_CFR_UP0 0xf24300ff
-
-/*P2_CFRLOW1*/
-#define R0900_P2_CFRLOW1 0xf246
-#define F0900_P2_CFR_LOW1 0xf24601ff
-
-/*P2_CFRLOW0*/
-#define R0900_P2_CFRLOW0 0xf247
-#define F0900_P2_CFR_LOW0 0xf24700ff
-
-/*P2_CFRINIT1*/
-#define R0900_P2_CFRINIT1 0xf248
-#define F0900_P2_CFR_INIT1 0xf24801ff
-
-/*P2_CFRINIT0*/
-#define R0900_P2_CFRINIT0 0xf249
-#define F0900_P2_CFR_INIT0 0xf24900ff
-
-/*P2_CFRINC1*/
-#define R0900_P2_CFRINC1 0xf24a
-#define F0900_P2_MANUAL_CFRINC 0xf24a0080
-#define F0900_P2_CFR_INC1 0xf24a003f
-
-/*P2_CFRINC0*/
-#define R0900_P2_CFRINC0 0xf24b
-#define F0900_P2_CFR_INC0 0xf24b00f8
-
-/*P2_CFR2*/
-#define R0900_P2_CFR2 0xf24c
-#define F0900_P2_CAR_FREQ2 0xf24c01ff
-
-/*P2_CFR1*/
-#define R0900_P2_CFR1 0xf24d
-#define F0900_P2_CAR_FREQ1 0xf24d00ff
-
-/*P2_CFR0*/
-#define R0900_P2_CFR0 0xf24e
-#define F0900_P2_CAR_FREQ0 0xf24e00ff
-
-/*P2_LDI*/
-#define R0900_P2_LDI 0xf24f
-#define F0900_P2_LOCK_DET_INTEGR 0xf24f01ff
-
-/*P2_TMGCFG*/
-#define R0900_P2_TMGCFG 0xf250
-#define F0900_P2_TMGLOCK_BETA 0xf25000c0
-#define F0900_P2_DO_TIMING_CORR 0xf2500010
-#define F0900_P2_TMG_MINFREQ 0xf2500003
-
-/*P2_RTC*/
-#define R0900_P2_RTC 0xf251
-#define F0900_P2_TMGALPHA_EXP 0xf25100f0
-#define F0900_P2_TMGBETA_EXP 0xf251000f
-
-/*P2_RTCS2*/
-#define R0900_P2_RTCS2 0xf252
-#define F0900_P2_TMGALPHAS2_EXP 0xf25200f0
-#define F0900_P2_TMGBETAS2_EXP 0xf252000f
-
-/*P2_TMGTHRISE*/
-#define R0900_P2_TMGTHRISE 0xf253
-#define F0900_P2_TMGLOCK_THRISE 0xf25300ff
-
-/*P2_TMGTHFALL*/
-#define R0900_P2_TMGTHFALL 0xf254
-#define F0900_P2_TMGLOCK_THFALL 0xf25400ff
-
-/*P2_SFRUPRATIO*/
-#define R0900_P2_SFRUPRATIO 0xf255
-#define F0900_P2_SFR_UPRATIO 0xf25500ff
-
-/*P2_SFRLOWRATIO*/
-#define R0900_P2_SFRLOWRATIO 0xf256
-#define F0900_P2_SFR_LOWRATIO 0xf25600ff
-
-/*P2_KREFTMG*/
-#define R0900_P2_KREFTMG 0xf258
-#define F0900_P2_KREF_TMG 0xf25800ff
-
-/*P2_SFRSTEP*/
-#define R0900_P2_SFRSTEP 0xf259
-#define F0900_P2_SFR_SCANSTEP 0xf25900f0
-#define F0900_P2_SFR_CENTERSTEP 0xf259000f
-
-/*P2_TMGCFG2*/
-#define R0900_P2_TMGCFG2 0xf25a
-#define F0900_P2_SFRRATIO_FINE 0xf25a0001
-
-/*P2_KREFTMG2*/
-#define R0900_P2_KREFTMG2 0xf25b
-#define F0900_P2_KREF_TMG2 0xf25b00ff
-
-/*P2_SFRINIT1*/
-#define R0900_P2_SFRINIT1 0xf25e
-#define F0900_P2_SFR_INIT1 0xf25e007f
-
-/*P2_SFRINIT0*/
-#define R0900_P2_SFRINIT0 0xf25f
-#define F0900_P2_SFR_INIT0 0xf25f00ff
-
-/*P2_SFRUP1*/
-#define R0900_P2_SFRUP1 0xf260
-#define F0900_P2_AUTO_GUP 0xf2600080
-#define F0900_P2_SYMB_FREQ_UP1 0xf260007f
-
-/*P2_SFRUP0*/
-#define R0900_P2_SFRUP0 0xf261
-#define F0900_P2_SYMB_FREQ_UP0 0xf26100ff
-
-/*P2_SFRLOW1*/
-#define R0900_P2_SFRLOW1 0xf262
-#define F0900_P2_AUTO_GLOW 0xf2620080
-#define F0900_P2_SYMB_FREQ_LOW1 0xf262007f
-
-/*P2_SFRLOW0*/
-#define R0900_P2_SFRLOW0 0xf263
-#define F0900_P2_SYMB_FREQ_LOW0 0xf26300ff
-
-/*P2_SFR3*/
-#define R0900_P2_SFR3 0xf264
-#define F0900_P2_SYMB_FREQ3 0xf26400ff
-
-/*P2_SFR2*/
-#define R0900_P2_SFR2 0xf265
-#define F0900_P2_SYMB_FREQ2 0xf26500ff
-
-/*P2_SFR1*/
-#define R0900_P2_SFR1 0xf266
-#define F0900_P2_SYMB_FREQ1 0xf26600ff
-
-/*P2_SFR0*/
-#define R0900_P2_SFR0 0xf267
-#define F0900_P2_SYMB_FREQ0 0xf26700ff
-
-/*P2_TMGREG2*/
-#define R0900_P2_TMGREG2 0xf268
-#define F0900_P2_TMGREG2 0xf26800ff
-
-/*P2_TMGREG1*/
-#define R0900_P2_TMGREG1 0xf269
-#define F0900_P2_TMGREG1 0xf26900ff
-
-/*P2_TMGREG0*/
-#define R0900_P2_TMGREG0 0xf26a
-#define F0900_P2_TMGREG0 0xf26a00ff
-
-/*P2_TMGLOCK1*/
-#define R0900_P2_TMGLOCK1 0xf26b
-#define F0900_P2_TMGLOCK_LEVEL1 0xf26b01ff
-
-/*P2_TMGLOCK0*/
-#define R0900_P2_TMGLOCK0 0xf26c
-#define F0900_P2_TMGLOCK_LEVEL0 0xf26c00ff
-
-/*P2_TMGOBS*/
-#define R0900_P2_TMGOBS 0xf26d
-#define F0900_P2_ROLLOFF_STATUS 0xf26d00c0
-
-/*P2_EQUALCFG*/
-#define R0900_P2_EQUALCFG 0xf26f
-#define F0900_P2_EQUAL_ON 0xf26f0040
-#define F0900_P2_MU_EQUALDFE 0xf26f0007
-
-/*P2_EQUAI1*/
-#define R0900_P2_EQUAI1 0xf270
-#define F0900_P2_EQUA_ACCI1 0xf27001ff
-
-/*P2_EQUAQ1*/
-#define R0900_P2_EQUAQ1 0xf271
-#define F0900_P2_EQUA_ACCQ1 0xf27101ff
-
-/*P2_EQUAI2*/
-#define R0900_P2_EQUAI2 0xf272
-#define F0900_P2_EQUA_ACCI2 0xf27201ff
-
-/*P2_EQUAQ2*/
-#define R0900_P2_EQUAQ2 0xf273
-#define F0900_P2_EQUA_ACCQ2 0xf27301ff
-
-/*P2_EQUAI3*/
-#define R0900_P2_EQUAI3 0xf274
-#define F0900_P2_EQUA_ACCI3 0xf27401ff
-
-/*P2_EQUAQ3*/
-#define R0900_P2_EQUAQ3 0xf275
-#define F0900_P2_EQUA_ACCQ3 0xf27501ff
-
-/*P2_EQUAI4*/
-#define R0900_P2_EQUAI4 0xf276
-#define F0900_P2_EQUA_ACCI4 0xf27601ff
-
-/*P2_EQUAQ4*/
-#define R0900_P2_EQUAQ4 0xf277
-#define F0900_P2_EQUA_ACCQ4 0xf27701ff
-
-/*P2_EQUAI5*/
-#define R0900_P2_EQUAI5 0xf278
-#define F0900_P2_EQUA_ACCI5 0xf27801ff
-
-/*P2_EQUAQ5*/
-#define R0900_P2_EQUAQ5 0xf279
-#define F0900_P2_EQUA_ACCQ5 0xf27901ff
-
-/*P2_EQUAI6*/
-#define R0900_P2_EQUAI6 0xf27a
-#define F0900_P2_EQUA_ACCI6 0xf27a01ff
-
-/*P2_EQUAQ6*/
-#define R0900_P2_EQUAQ6 0xf27b
-#define F0900_P2_EQUA_ACCQ6 0xf27b01ff
-
-/*P2_EQUAI7*/
-#define R0900_P2_EQUAI7 0xf27c
-#define F0900_P2_EQUA_ACCI7 0xf27c01ff
-
-/*P2_EQUAQ7*/
-#define R0900_P2_EQUAQ7 0xf27d
-#define F0900_P2_EQUA_ACCQ7 0xf27d01ff
-
-/*P2_EQUAI8*/
-#define R0900_P2_EQUAI8 0xf27e
-#define F0900_P2_EQUA_ACCI8 0xf27e01ff
-
-/*P2_EQUAQ8*/
-#define R0900_P2_EQUAQ8 0xf27f
-#define F0900_P2_EQUA_ACCQ8 0xf27f01ff
-
-/*P2_NNOSDATAT1*/
-#define R0900_P2_NNOSDATAT1 0xf280
-#define F0900_P2_NOSDATAT_NORMED1 0xf28000ff
-
-/*P2_NNOSDATAT0*/
-#define R0900_P2_NNOSDATAT0 0xf281
-#define F0900_P2_NOSDATAT_NORMED0 0xf28100ff
-
-/*P2_NNOSDATA1*/
-#define R0900_P2_NNOSDATA1 0xf282
-#define F0900_P2_NOSDATA_NORMED1 0xf28200ff
-
-/*P2_NNOSDATA0*/
-#define R0900_P2_NNOSDATA0 0xf283
-#define F0900_P2_NOSDATA_NORMED0 0xf28300ff
-
-/*P2_NNOSPLHT1*/
-#define R0900_P2_NNOSPLHT1 0xf284
-#define F0900_P2_NOSPLHT_NORMED1 0xf28400ff
-
-/*P2_NNOSPLHT0*/
-#define R0900_P2_NNOSPLHT0 0xf285
-#define F0900_P2_NOSPLHT_NORMED0 0xf28500ff
-
-/*P2_NNOSPLH1*/
-#define R0900_P2_NNOSPLH1 0xf286
-#define F0900_P2_NOSPLH_NORMED1 0xf28600ff
-
-/*P2_NNOSPLH0*/
-#define R0900_P2_NNOSPLH0 0xf287
-#define F0900_P2_NOSPLH_NORMED0 0xf28700ff
-
-/*P2_NOSDATAT1*/
-#define R0900_P2_NOSDATAT1 0xf288
-#define F0900_P2_NOSDATAT_UNNORMED1 0xf28800ff
-
-/*P2_NOSDATAT0*/
-#define R0900_P2_NOSDATAT0 0xf289
-#define F0900_P2_NOSDATAT_UNNORMED0 0xf28900ff
-
-/*P2_NOSDATA1*/
-#define R0900_P2_NOSDATA1 0xf28a
-#define F0900_P2_NOSDATA_UNNORMED1 0xf28a00ff
-
-/*P2_NOSDATA0*/
-#define R0900_P2_NOSDATA0 0xf28b
-#define F0900_P2_NOSDATA_UNNORMED0 0xf28b00ff
-
-/*P2_NOSPLHT1*/
-#define R0900_P2_NOSPLHT1 0xf28c
-#define F0900_P2_NOSPLHT_UNNORMED1 0xf28c00ff
-
-/*P2_NOSPLHT0*/
-#define R0900_P2_NOSPLHT0 0xf28d
-#define F0900_P2_NOSPLHT_UNNORMED0 0xf28d00ff
-
-/*P2_NOSPLH1*/
-#define R0900_P2_NOSPLH1 0xf28e
-#define F0900_P2_NOSPLH_UNNORMED1 0xf28e00ff
-
-/*P2_NOSPLH0*/
-#define R0900_P2_NOSPLH0 0xf28f
-#define F0900_P2_NOSPLH_UNNORMED0 0xf28f00ff
-
-/*P2_CAR2CFG*/
-#define R0900_P2_CAR2CFG 0xf290
-#define F0900_P2_CARRIER3_DISABLE 0xf2900040
-#define F0900_P2_ROTA2ON 0xf2900004
-#define F0900_P2_PH_DET_ALGO2 0xf2900003
-
-/*P2_CFR2CFR1*/
-#define R0900_P2_CFR2CFR1 0xf291
-#define F0900_P2_CFR2TOCFR1_DVBS1 0xf29100c0
-#define F0900_P2_EN_S2CAR2CENTER 0xf2910020
-#define F0900_P2_DIS_BCHERRCFR2 0xf2910010
-#define F0900_P2_CFR2TOCFR1_BETA 0xf2910007
-
-/*P2_CFR22*/
-#define R0900_P2_CFR22 0xf293
-#define F0900_P2_CAR2_FREQ2 0xf29301ff
-
-/*P2_CFR21*/
-#define R0900_P2_CFR21 0xf294
-#define F0900_P2_CAR2_FREQ1 0xf29400ff
-
-/*P2_CFR20*/
-#define R0900_P2_CFR20 0xf295
-#define F0900_P2_CAR2_FREQ0 0xf29500ff
-
-/*P2_ACLC2S2Q*/
-#define R0900_P2_ACLC2S2Q 0xf297
-#define F0900_P2_ENAB_SPSKSYMB 0xf2970080
-#define F0900_P2_CAR2S2_Q_ALPH_M 0xf2970030
-#define F0900_P2_CAR2S2_Q_ALPH_E 0xf297000f
-
-/*P2_ACLC2S28*/
-#define R0900_P2_ACLC2S28 0xf298
-#define F0900_P2_OLDI3Q_MODE 0xf2980080
-#define F0900_P2_CAR2S2_8_ALPH_M 0xf2980030
-#define F0900_P2_CAR2S2_8_ALPH_E 0xf298000f
-
-/*P2_ACLC2S216A*/
-#define R0900_P2_ACLC2S216A 0xf299
-#define F0900_P2_DIS_C3STOPA2 0xf2990080
-#define F0900_P2_CAR2S2_16ADERAT 0xf2990040
-#define F0900_P2_CAR2S2_16A_ALPH_M 0xf2990030
-#define F0900_P2_CAR2S2_16A_ALPH_E 0xf299000f
-
-/*P2_ACLC2S232A*/
-#define R0900_P2_ACLC2S232A 0xf29a
-#define F0900_P2_CAR2S2_32ADERAT 0xf29a0040
-#define F0900_P2_CAR2S2_32A_ALPH_M 0xf29a0030
-#define F0900_P2_CAR2S2_32A_ALPH_E 0xf29a000f
-
-/*P2_BCLC2S2Q*/
-#define R0900_P2_BCLC2S2Q 0xf29c
-#define F0900_P2_CAR2S2_Q_BETA_M 0xf29c0030
-#define F0900_P2_CAR2S2_Q_BETA_E 0xf29c000f
-
-/*P2_BCLC2S28*/
-#define R0900_P2_BCLC2S28 0xf29d
-#define F0900_P2_CAR2S2_8_BETA_M 0xf29d0030
-#define F0900_P2_CAR2S2_8_BETA_E 0xf29d000f
-
-/*P2_BCLC2S216A*/
-#define R0900_P2_BCLC2S216A 0xf29e
-
-/*P2_BCLC2S232A*/
-#define R0900_P2_BCLC2S232A 0xf29f
-
-/*P2_PLROOT2*/
-#define R0900_P2_PLROOT2 0xf2ac
-#define F0900_P2_PLSCRAMB_MODE 0xf2ac000c
-#define F0900_P2_PLSCRAMB_ROOT2 0xf2ac0003
-
-/*P2_PLROOT1*/
-#define R0900_P2_PLROOT1 0xf2ad
-#define F0900_P2_PLSCRAMB_ROOT1 0xf2ad00ff
-
-/*P2_PLROOT0*/
-#define R0900_P2_PLROOT0 0xf2ae
-#define F0900_P2_PLSCRAMB_ROOT0 0xf2ae00ff
-
-/*P2_MODCODLST0*/
-#define R0900_P2_MODCODLST0 0xf2b0
-
-/*P2_MODCODLST1*/
-#define R0900_P2_MODCODLST1 0xf2b1
-#define F0900_P2_DIS_MODCOD29 0xf2b100f0
-#define F0900_P2_DIS_32PSK_9_10 0xf2b1000f
-
-/*P2_MODCODLST2*/
-#define R0900_P2_MODCODLST2 0xf2b2
-#define F0900_P2_DIS_32PSK_8_9 0xf2b200f0
-#define F0900_P2_DIS_32PSK_5_6 0xf2b2000f
-
-/*P2_MODCODLST3*/
-#define R0900_P2_MODCODLST3 0xf2b3
-#define F0900_P2_DIS_32PSK_4_5 0xf2b300f0
-#define F0900_P2_DIS_32PSK_3_4 0xf2b3000f
-
-/*P2_MODCODLST4*/
-#define R0900_P2_MODCODLST4 0xf2b4
-#define F0900_P2_DIS_16PSK_9_10 0xf2b400f0
-#define F0900_P2_DIS_16PSK_8_9 0xf2b4000f
-
-/*P2_MODCODLST5*/
-#define R0900_P2_MODCODLST5 0xf2b5
-#define F0900_P2_DIS_16PSK_5_6 0xf2b500f0
-#define F0900_P2_DIS_16PSK_4_5 0xf2b5000f
-
-/*P2_MODCODLST6*/
-#define R0900_P2_MODCODLST6 0xf2b6
-#define F0900_P2_DIS_16PSK_3_4 0xf2b600f0
-#define F0900_P2_DIS_16PSK_2_3 0xf2b6000f
-
-/*P2_MODCODLST7*/
-#define R0900_P2_MODCODLST7 0xf2b7
-#define F0900_P2_DIS_8P_9_10 0xf2b700f0
-#define F0900_P2_DIS_8P_8_9 0xf2b7000f
-
-/*P2_MODCODLST8*/
-#define R0900_P2_MODCODLST8 0xf2b8
-#define F0900_P2_DIS_8P_5_6 0xf2b800f0
-#define F0900_P2_DIS_8P_3_4 0xf2b8000f
-
-/*P2_MODCODLST9*/
-#define R0900_P2_MODCODLST9 0xf2b9
-#define F0900_P2_DIS_8P_2_3 0xf2b900f0
-#define F0900_P2_DIS_8P_3_5 0xf2b9000f
-
-/*P2_MODCODLSTA*/
-#define R0900_P2_MODCODLSTA 0xf2ba
-#define F0900_P2_DIS_QP_9_10 0xf2ba00f0
-#define F0900_P2_DIS_QP_8_9 0xf2ba000f
-
-/*P2_MODCODLSTB*/
-#define R0900_P2_MODCODLSTB 0xf2bb
-#define F0900_P2_DIS_QP_5_6 0xf2bb00f0
-#define F0900_P2_DIS_QP_4_5 0xf2bb000f
-
-/*P2_MODCODLSTC*/
-#define R0900_P2_MODCODLSTC 0xf2bc
-#define F0900_P2_DIS_QP_3_4 0xf2bc00f0
-#define F0900_P2_DIS_QP_2_3 0xf2bc000f
-
-/*P2_MODCODLSTD*/
-#define R0900_P2_MODCODLSTD 0xf2bd
-#define F0900_P2_DIS_QP_3_5 0xf2bd00f0
-#define F0900_P2_DIS_QP_1_2 0xf2bd000f
-
-/*P2_MODCODLSTE*/
-#define R0900_P2_MODCODLSTE 0xf2be
-#define F0900_P2_DIS_QP_2_5 0xf2be00f0
-#define F0900_P2_DIS_QP_1_3 0xf2be000f
-
-/*P2_MODCODLSTF*/
-#define R0900_P2_MODCODLSTF 0xf2bf
-#define F0900_P2_DIS_QP_1_4 0xf2bf00f0
-
-/*P2_GAUSSR0*/
-#define R0900_P2_GAUSSR0 0xf2c0
-#define F0900_P2_EN_CCIMODE 0xf2c00080
-#define F0900_P2_R0_GAUSSIEN 0xf2c0007f
-
-/*P2_CCIR0*/
-#define R0900_P2_CCIR0 0xf2c1
-#define F0900_P2_CCIDETECT_PLHONLY 0xf2c10080
-#define F0900_P2_R0_CCI 0xf2c1007f
-
-/*P2_CCIQUANT*/
-#define R0900_P2_CCIQUANT 0xf2c2
-#define F0900_P2_CCI_BETA 0xf2c200e0
-#define F0900_P2_CCI_QUANT 0xf2c2001f
-
-/*P2_CCITHRES*/
-#define R0900_P2_CCITHRES 0xf2c3
-#define F0900_P2_CCI_THRESHOLD 0xf2c300ff
-
-/*P2_CCIACC*/
-#define R0900_P2_CCIACC 0xf2c4
-#define F0900_P2_CCI_VALUE 0xf2c400ff
-
-/*P2_DMDRESCFG*/
-#define R0900_P2_DMDRESCFG 0xf2c6
-#define F0900_P2_DMDRES_RESET 0xf2c60080
-#define F0900_P2_DMDRES_STRALL 0xf2c60008
-#define F0900_P2_DMDRES_NEWONLY 0xf2c60004
-#define F0900_P2_DMDRES_NOSTORE 0xf2c60002
-
-/*P2_DMDRESADR*/
-#define R0900_P2_DMDRESADR 0xf2c7
-#define F0900_P2_DMDRES_VALIDCFR 0xf2c70040
-#define F0900_P2_DMDRES_MEMFULL 0xf2c70030
-#define F0900_P2_DMDRES_RESNBR 0xf2c7000f
-
-/*P2_DMDRESDATA7*/
-#define R0900_P2_DMDRESDATA7 0xf2c8
-#define F0900_P2_DMDRES_DATA7 0xf2c800ff
-
-/*P2_DMDRESDATA6*/
-#define R0900_P2_DMDRESDATA6 0xf2c9
-#define F0900_P2_DMDRES_DATA6 0xf2c900ff
-
-/*P2_DMDRESDATA5*/
-#define R0900_P2_DMDRESDATA5 0xf2ca
-#define F0900_P2_DMDRES_DATA5 0xf2ca00ff
-
-/*P2_DMDRESDATA4*/
-#define R0900_P2_DMDRESDATA4 0xf2cb
-#define F0900_P2_DMDRES_DATA4 0xf2cb00ff
-
-/*P2_DMDRESDATA3*/
-#define R0900_P2_DMDRESDATA3 0xf2cc
-#define F0900_P2_DMDRES_DATA3 0xf2cc00ff
-
-/*P2_DMDRESDATA2*/
-#define R0900_P2_DMDRESDATA2 0xf2cd
-#define F0900_P2_DMDRES_DATA2 0xf2cd00ff
-
-/*P2_DMDRESDATA1*/
-#define R0900_P2_DMDRESDATA1 0xf2ce
-#define F0900_P2_DMDRES_DATA1 0xf2ce00ff
-
-/*P2_DMDRESDATA0*/
-#define R0900_P2_DMDRESDATA0 0xf2cf
-#define F0900_P2_DMDRES_DATA0 0xf2cf00ff
-
-/*P2_FFEI1*/
-#define R0900_P2_FFEI1 0xf2d0
-#define F0900_P2_FFE_ACCI1 0xf2d001ff
-
-/*P2_FFEQ1*/
-#define R0900_P2_FFEQ1 0xf2d1
-#define F0900_P2_FFE_ACCQ1 0xf2d101ff
-
-/*P2_FFEI2*/
-#define R0900_P2_FFEI2 0xf2d2
-#define F0900_P2_FFE_ACCI2 0xf2d201ff
-
-/*P2_FFEQ2*/
-#define R0900_P2_FFEQ2 0xf2d3
-#define F0900_P2_FFE_ACCQ2 0xf2d301ff
-
-/*P2_FFEI3*/
-#define R0900_P2_FFEI3 0xf2d4
-#define F0900_P2_FFE_ACCI3 0xf2d401ff
-
-/*P2_FFEQ3*/
-#define R0900_P2_FFEQ3 0xf2d5
-#define F0900_P2_FFE_ACCQ3 0xf2d501ff
-
-/*P2_FFEI4*/
-#define R0900_P2_FFEI4 0xf2d6
-#define F0900_P2_FFE_ACCI4 0xf2d601ff
-
-/*P2_FFEQ4*/
-#define R0900_P2_FFEQ4 0xf2d7
-#define F0900_P2_FFE_ACCQ4 0xf2d701ff
-
-/*P2_FFECFG*/
-#define R0900_P2_FFECFG 0xf2d8
-#define F0900_P2_EQUALFFE_ON 0xf2d80040
-#define F0900_P2_MU_EQUALFFE 0xf2d80007
-
-/*P2_TNRCFG*/
-#define R0900_P2_TNRCFG 0xf2e0
-#define F0900_P2_TUN_ACKFAIL 0xf2e00080
-#define F0900_P2_TUN_TYPE 0xf2e00070
-#define F0900_P2_TUN_SECSTOP 0xf2e00008
-#define F0900_P2_TUN_VCOSRCH 0xf2e00004
-#define F0900_P2_TUN_MADDRESS 0xf2e00003
-
-/*P2_TNRCFG2*/
-#define R0900_P2_TNRCFG2 0xf2e1
-#define F0900_P2_TUN_IQSWAP 0xf2e10080
-#define F0900_P2_DIS_BWCALC 0xf2e10004
-#define F0900_P2_SHORT_WAITSTATES 0xf2e10002
-
-/*P2_TNRXTAL*/
-#define R0900_P2_TNRXTAL 0xf2e4
-#define F0900_P2_TUN_XTALFREQ 0xf2e4001f
-
-/*P2_TNRSTEPS*/
-#define R0900_P2_TNRSTEPS 0xf2e7
-#define F0900_P2_TUNER_BW0P125 0xf2e70080
-#define F0900_P2_BWINC_OFFSET 0xf2e70170
-#define F0900_P2_SOFTSTEP_RNG 0xf2e70008
-#define F0900_P2_TUN_BWOFFSET 0xf2e70007
-
-/*P2_TNRGAIN*/
-#define R0900_P2_TNRGAIN 0xf2e8
-#define F0900_P2_TUN_KDIVEN 0xf2e800c0
-#define F0900_P2_STB6X00_OCK 0xf2e80030
-#define F0900_P2_TUN_GAIN 0xf2e8000f
-
-/*P2_TNRRF1*/
-#define R0900_P2_TNRRF1 0xf2e9
-#define F0900_P2_TUN_RFFREQ2 0xf2e900ff
-
-/*P2_TNRRF0*/
-#define R0900_P2_TNRRF0 0xf2ea
-#define F0900_P2_TUN_RFFREQ1 0xf2ea00ff
-
-/*P2_TNRBW*/
-#define R0900_P2_TNRBW 0xf2eb
-#define F0900_P2_TUN_RFFREQ0 0xf2eb00c0
-#define F0900_P2_TUN_BW 0xf2eb003f
-
-/*P2_TNRADJ*/
-#define R0900_P2_TNRADJ 0xf2ec
-#define F0900_P2_STB61X0_CALTIME 0xf2ec0040
-
-/*P2_TNRCTL2*/
-#define R0900_P2_TNRCTL2 0xf2ed
-#define F0900_P2_STB61X0_RCCKOFF 0xf2ed0080
-#define F0900_P2_STB61X0_ICP_SDOFF 0xf2ed0040
-#define F0900_P2_STB61X0_DCLOOPOFF 0xf2ed0020
-#define F0900_P2_STB61X0_REFOUTSEL 0xf2ed0010
-#define F0900_P2_STB61X0_CALOFF 0xf2ed0008
-#define F0900_P2_STB6XX0_LPT_BEN 0xf2ed0004
-#define F0900_P2_STB6XX0_RX_OSCP 0xf2ed0002
-#define F0900_P2_STB6XX0_SYN 0xf2ed0001
-
-/*P2_TNRCFG3*/
-#define R0900_P2_TNRCFG3 0xf2ee
-#define F0900_P2_TUN_PLLFREQ 0xf2ee001c
-#define F0900_P2_TUN_I2CFREQ_MODE 0xf2ee0003
-
-/*P2_TNRLAUNCH*/
-#define R0900_P2_TNRLAUNCH 0xf2f0
-
-/*P2_TNRLD*/
-#define R0900_P2_TNRLD 0xf2f0
-#define F0900_P2_TUNLD_VCOING 0xf2f00080
-#define F0900_P2_TUN_REG1FAIL 0xf2f00040
-#define F0900_P2_TUN_REG2FAIL 0xf2f00020
-#define F0900_P2_TUN_REG3FAIL 0xf2f00010
-#define F0900_P2_TUN_REG4FAIL 0xf2f00008
-#define F0900_P2_TUN_REG5FAIL 0xf2f00004
-#define F0900_P2_TUN_BWING 0xf2f00002
-#define F0900_P2_TUN_LOCKED 0xf2f00001
-
-/*P2_TNROBSL*/
-#define R0900_P2_TNROBSL 0xf2f6
-#define F0900_P2_TUN_I2CABORTED 0xf2f60080
-#define F0900_P2_TUN_LPEN 0xf2f60040
-#define F0900_P2_TUN_FCCK 0xf2f60020
-#define F0900_P2_TUN_I2CLOCKED 0xf2f60010
-#define F0900_P2_TUN_PROGDONE 0xf2f6000c
-#define F0900_P2_TUN_RFRESTE1 0xf2f60003
-
-/*P2_TNRRESTE*/
-#define R0900_P2_TNRRESTE 0xf2f7
-#define F0900_P2_TUN_RFRESTE0 0xf2f700ff
-
-/*P2_SMAPCOEF7*/
-#define R0900_P2_SMAPCOEF7 0xf300
-#define F0900_P2_DIS_QSCALE 0xf3000080
-#define F0900_P2_SMAPCOEF_Q_LLR12 0xf300017f
-
-/*P2_SMAPCOEF6*/
-#define R0900_P2_SMAPCOEF6 0xf301
-#define F0900_P2_ADJ_8PSKLLR1 0xf3010004
-#define F0900_P2_OLD_8PSKLLR1 0xf3010002
-#define F0900_P2_DIS_AB8PSK 0xf3010001
-
-/*P2_SMAPCOEF5*/
-#define R0900_P2_SMAPCOEF5 0xf302
-#define F0900_P2_DIS_8SCALE 0xf3020080
-#define F0900_P2_SMAPCOEF_8P_LLR23 0xf302017f
-
-/*P2_NCO2MAX1*/
-#define R0900_P2_NCO2MAX1 0xf314
-#define F0900_P2_TETA2_MAXVABS1 0xf31400ff
-
-/*P2_NCO2MAX0*/
-#define R0900_P2_NCO2MAX0 0xf315
-#define F0900_P2_TETA2_MAXVABS0 0xf31500ff
-
-/*P2_NCO2FR1*/
-#define R0900_P2_NCO2FR1 0xf316
-#define F0900_P2_NCO2FINAL_ANGLE1 0xf31600ff
-
-/*P2_NCO2FR0*/
-#define R0900_P2_NCO2FR0 0xf317
-#define F0900_P2_NCO2FINAL_ANGLE0 0xf31700ff
-
-/*P2_CFR2AVRGE1*/
-#define R0900_P2_CFR2AVRGE1 0xf318
-#define F0900_P2_I2C_CFR2AVERAGE1 0xf31800ff
-
-/*P2_CFR2AVRGE0*/
-#define R0900_P2_CFR2AVRGE0 0xf319
-#define F0900_P2_I2C_CFR2AVERAGE0 0xf31900ff
-
-/*P2_DMDPLHSTAT*/
-#define R0900_P2_DMDPLHSTAT 0xf320
-#define F0900_P2_PLH_STATISTIC 0xf32000ff
-
-/*P2_LOCKTIME3*/
-#define R0900_P2_LOCKTIME3 0xf322
-#define F0900_P2_DEMOD_LOCKTIME3 0xf32200ff
-
-/*P2_LOCKTIME2*/
-#define R0900_P2_LOCKTIME2 0xf323
-#define F0900_P2_DEMOD_LOCKTIME2 0xf32300ff
-
-/*P2_LOCKTIME1*/
-#define R0900_P2_LOCKTIME1 0xf324
-#define F0900_P2_DEMOD_LOCKTIME1 0xf32400ff
-
-/*P2_LOCKTIME0*/
-#define R0900_P2_LOCKTIME0 0xf325
-#define F0900_P2_DEMOD_LOCKTIME0 0xf32500ff
-
-/*P2_VITSCALE*/
-#define R0900_P2_VITSCALE 0xf332
-#define F0900_P2_NVTH_NOSRANGE 0xf3320080
-#define F0900_P2_VERROR_MAXMODE 0xf3320040
-#define F0900_P2_NSLOWSN_LOCKED 0xf3320008
-#define F0900_P2_DIS_RSFLOCK 0xf3320002
-
-/*P2_FECM*/
-#define R0900_P2_FECM 0xf333
-#define F0900_P2_DSS_DVB 0xf3330080
-#define F0900_P2_DSS_SRCH 0xf3330010
-#define F0900_P2_SYNCVIT 0xf3330002
-#define F0900_P2_IQINV 0xf3330001
-
-/*P2_VTH12*/
-#define R0900_P2_VTH12 0xf334
-#define F0900_P2_VTH12 0xf33400ff
-
-/*P2_VTH23*/
-#define R0900_P2_VTH23 0xf335
-#define F0900_P2_VTH23 0xf33500ff
-
-/*P2_VTH34*/
-#define R0900_P2_VTH34 0xf336
-#define F0900_P2_VTH34 0xf33600ff
-
-/*P2_VTH56*/
-#define R0900_P2_VTH56 0xf337
-#define F0900_P2_VTH56 0xf33700ff
-
-/*P2_VTH67*/
-#define R0900_P2_VTH67 0xf338
-#define F0900_P2_VTH67 0xf33800ff
-
-/*P2_VTH78*/
-#define R0900_P2_VTH78 0xf339
-#define F0900_P2_VTH78 0xf33900ff
-
-/*P2_VITCURPUN*/
-#define R0900_P2_VITCURPUN 0xf33a
-#define F0900_P2_VIT_CURPUN 0xf33a001f
-
-/*P2_VERROR*/
-#define R0900_P2_VERROR 0xf33b
-#define F0900_P2_REGERR_VIT 0xf33b00ff
-
-/*P2_PRVIT*/
-#define R0900_P2_PRVIT 0xf33c
-#define F0900_P2_DIS_VTHLOCK 0xf33c0040
-#define F0900_P2_E7_8VIT 0xf33c0020
-#define F0900_P2_E6_7VIT 0xf33c0010
-#define F0900_P2_E5_6VIT 0xf33c0008
-#define F0900_P2_E3_4VIT 0xf33c0004
-#define F0900_P2_E2_3VIT 0xf33c0002
-#define F0900_P2_E1_2VIT 0xf33c0001
-
-/*P2_VAVSRVIT*/
-#define R0900_P2_VAVSRVIT 0xf33d
-#define F0900_P2_AMVIT 0xf33d0080
-#define F0900_P2_FROZENVIT 0xf33d0040
-#define F0900_P2_SNVIT 0xf33d0030
-#define F0900_P2_TOVVIT 0xf33d000c
-#define F0900_P2_HYPVIT 0xf33d0003
-
-/*P2_VSTATUSVIT*/
-#define R0900_P2_VSTATUSVIT 0xf33e
-#define F0900_P2_PRFVIT 0xf33e0010
-#define F0900_P2_LOCKEDVIT 0xf33e0008
-
-/*P2_VTHINUSE*/
-#define R0900_P2_VTHINUSE 0xf33f
-#define F0900_P2_VIT_INUSE 0xf33f00ff
-
-/*P2_KDIV12*/
-#define R0900_P2_KDIV12 0xf340
-#define F0900_P2_K_DIVIDER_12 0xf340007f
-
-/*P2_KDIV23*/
-#define R0900_P2_KDIV23 0xf341
-#define F0900_P2_K_DIVIDER_23 0xf341007f
-
-/*P2_KDIV34*/
-#define R0900_P2_KDIV34 0xf342
-#define F0900_P2_K_DIVIDER_34 0xf342007f
-
-/*P2_KDIV56*/
-#define R0900_P2_KDIV56 0xf343
-#define F0900_P2_K_DIVIDER_56 0xf343007f
-
-/*P2_KDIV67*/
-#define R0900_P2_KDIV67 0xf344
-#define F0900_P2_K_DIVIDER_67 0xf344007f
-
-/*P2_KDIV78*/
-#define R0900_P2_KDIV78 0xf345
-#define F0900_P2_K_DIVIDER_78 0xf345007f
-
-/*P2_PDELCTRL1*/
-#define R0900_P2_PDELCTRL1 0xf350
-#define F0900_P2_INV_MISMASK 0xf3500080
-#define F0900_P2_FILTER_EN 0xf3500020
-#define F0900_P2_EN_MIS00 0xf3500002
-#define F0900_P2_ALGOSWRST 0xf3500001
-
-/*P2_PDELCTRL2*/
-#define R0900_P2_PDELCTRL2 0xf351
-#define F0900_P2_RESET_UPKO_COUNT 0xf3510040
-#define F0900_P2_FRAME_MODE 0xf3510002
-#define F0900_P2_NOBCHERRFLG_USE 0xf3510001
-
-/*P2_HYSTTHRESH*/
-#define R0900_P2_HYSTTHRESH 0xf354
-#define F0900_P2_UNLCK_THRESH 0xf35400f0
-#define F0900_P2_DELIN_LCK_THRESH 0xf354000f
-
-/*P2_ISIENTRY*/
-#define R0900_P2_ISIENTRY 0xf35e
-#define F0900_P2_ISI_ENTRY 0xf35e00ff
-
-/*P2_ISIBITENA*/
-#define R0900_P2_ISIBITENA 0xf35f
-#define F0900_P2_ISI_BIT_EN 0xf35f00ff
-
-/*P2_MATSTR1*/
-#define R0900_P2_MATSTR1 0xf360
-#define F0900_P2_MATYPE_CURRENT1 0xf36000ff
-
-/*P2_MATSTR0*/
-#define R0900_P2_MATSTR0 0xf361
-#define F0900_P2_MATYPE_CURRENT0 0xf36100ff
-
-/*P2_UPLSTR1*/
-#define R0900_P2_UPLSTR1 0xf362
-#define F0900_P2_UPL_CURRENT1 0xf36200ff
-
-/*P2_UPLSTR0*/
-#define R0900_P2_UPLSTR0 0xf363
-#define F0900_P2_UPL_CURRENT0 0xf36300ff
-
-/*P2_DFLSTR1*/
-#define R0900_P2_DFLSTR1 0xf364
-#define F0900_P2_DFL_CURRENT1 0xf36400ff
-
-/*P2_DFLSTR0*/
-#define R0900_P2_DFLSTR0 0xf365
-#define F0900_P2_DFL_CURRENT0 0xf36500ff
-
-/*P2_SYNCSTR*/
-#define R0900_P2_SYNCSTR 0xf366
-#define F0900_P2_SYNC_CURRENT 0xf36600ff
-
-/*P2_SYNCDSTR1*/
-#define R0900_P2_SYNCDSTR1 0xf367
-#define F0900_P2_SYNCD_CURRENT1 0xf36700ff
-
-/*P2_SYNCDSTR0*/
-#define R0900_P2_SYNCDSTR0 0xf368
-#define F0900_P2_SYNCD_CURRENT0 0xf36800ff
-
-/*P2_PDELSTATUS1*/
-#define R0900_P2_PDELSTATUS1 0xf369
-#define F0900_P2_PKTDELIN_DELOCK 0xf3690080
-#define F0900_P2_SYNCDUPDFL_BADDFL 0xf3690040
-#define F0900_P2_CONTINUOUS_STREAM 0xf3690020
-#define F0900_P2_UNACCEPTED_STREAM 0xf3690010
-#define F0900_P2_BCH_ERROR_FLAG 0xf3690008
-#define F0900_P2_PKTDELIN_LOCK 0xf3690002
-#define F0900_P2_FIRST_LOCK 0xf3690001
-
-/*P2_PDELSTATUS2*/
-#define R0900_P2_PDELSTATUS2 0xf36a
-#define F0900_P2_FRAME_MODCOD 0xf36a007c
-#define F0900_P2_FRAME_TYPE 0xf36a0003
-
-/*P2_BBFCRCKO1*/
-#define R0900_P2_BBFCRCKO1 0xf36b
-#define F0900_P2_BBHCRC_KOCNT1 0xf36b00ff
-
-/*P2_BBFCRCKO0*/
-#define R0900_P2_BBFCRCKO0 0xf36c
-#define F0900_P2_BBHCRC_KOCNT0 0xf36c00ff
-
-/*P2_UPCRCKO1*/
-#define R0900_P2_UPCRCKO1 0xf36d
-#define F0900_P2_PKTCRC_KOCNT1 0xf36d00ff
-
-/*P2_UPCRCKO0*/
-#define R0900_P2_UPCRCKO0 0xf36e
-#define F0900_P2_PKTCRC_KOCNT0 0xf36e00ff
-
-/*P2_PDELCTRL3*/
-#define R0900_P2_PDELCTRL3 0xf36f
-#define F0900_P2_PKTDEL_CONTFAIL 0xf36f0080
-#define F0900_P2_NOFIFO_BCHERR 0xf36f0020
-
-/*P2_TSSTATEM*/
-#define R0900_P2_TSSTATEM 0xf370
-#define F0900_P2_TSDIL_ON 0xf3700080
-#define F0900_P2_TSRS_ON 0xf3700020
-#define F0900_P2_TSDESCRAMB_ON 0xf3700010
-#define F0900_P2_TSFRAME_MODE 0xf3700008
-#define F0900_P2_TS_DISABLE 0xf3700004
-#define F0900_P2_TSOUT_NOSYNC 0xf3700001
-
-/*P2_TSCFGH*/
-#define R0900_P2_TSCFGH 0xf372
-#define F0900_P2_TSFIFO_DVBCI 0xf3720080
-#define F0900_P2_TSFIFO_SERIAL 0xf3720040
-#define F0900_P2_TSFIFO_TEIUPDATE 0xf3720020
-#define F0900_P2_TSFIFO_DUTY50 0xf3720010
-#define F0900_P2_TSFIFO_HSGNLOUT 0xf3720008
-#define F0900_P2_TSFIFO_ERRMODE 0xf3720006
-#define F0900_P2_RST_HWARE 0xf3720001
-
-/*P2_TSCFGM*/
-#define R0900_P2_TSCFGM 0xf373
-#define F0900_P2_TSFIFO_MANSPEED 0xf37300c0
-#define F0900_P2_TSFIFO_PERMDATA 0xf3730020
-#define F0900_P2_TSFIFO_DPUNACT 0xf3730002
-#define F0900_P2_TSFIFO_INVDATA 0xf3730001
-
-/*P2_TSCFGL*/
-#define R0900_P2_TSCFGL 0xf374
-#define F0900_P2_TSFIFO_BCLKDEL1CK 0xf37400c0
-#define F0900_P2_BCHERROR_MODE 0xf3740030
-#define F0900_P2_TSFIFO_NSGNL2DATA 0xf3740008
-#define F0900_P2_TSFIFO_EMBINDVB 0xf3740004
-#define F0900_P2_TSFIFO_BITSPEED 0xf3740003
-
-/*P2_TSINSDELH*/
-#define R0900_P2_TSINSDELH 0xf376
-#define F0900_P2_TSDEL_SYNCBYTE 0xf3760080
-#define F0900_P2_TSDEL_XXHEADER 0xf3760040
-#define F0900_P2_TSDEL_BBHEADER 0xf3760020
-#define F0900_P2_TSDEL_DATAFIELD 0xf3760010
-#define F0900_P2_TSINSDEL_ISCR 0xf3760008
-#define F0900_P2_TSINSDEL_NPD 0xf3760004
-#define F0900_P2_TSINSDEL_RSPARITY 0xf3760002
-#define F0900_P2_TSINSDEL_CRC8 0xf3760001
-
-/*P2_TSDIVN*/
-#define R0900_P2_TSDIVN 0xf379
-#define F0900_P2_TSFIFO_SPEEDMODE 0xf37900c0
-
-/*P2_TSCFG4*/
-#define R0900_P2_TSCFG4 0xf37a
-#define F0900_P2_TSFIFO_TSSPEEDMODE 0xf37a00c0
-
-/*P2_TSSPEED*/
-#define R0900_P2_TSSPEED 0xf380
-#define F0900_P2_TSFIFO_OUTSPEED 0xf38000ff
-
-/*P2_TSSTATUS*/
-#define R0900_P2_TSSTATUS 0xf381
-#define F0900_P2_TSFIFO_LINEOK 0xf3810080
-#define F0900_P2_TSFIFO_ERROR 0xf3810040
-#define F0900_P2_DIL_READY 0xf3810001
-
-/*P2_TSSTATUS2*/
-#define R0900_P2_TSSTATUS2 0xf382
-#define F0900_P2_TSFIFO_DEMODSEL 0xf3820080
-#define F0900_P2_TSFIFOSPEED_STORE 0xf3820040
-#define F0900_P2_DILXX_RESET 0xf3820020
-#define F0900_P2_TSSERIAL_IMPOS 0xf3820010
-#define F0900_P2_SCRAMBDETECT 0xf3820002
-
-/*P2_TSBITRATE1*/
-#define R0900_P2_TSBITRATE1 0xf383
-#define F0900_P2_TSFIFO_BITRATE1 0xf38300ff
-
-/*P2_TSBITRATE0*/
-#define R0900_P2_TSBITRATE0 0xf384
-#define F0900_P2_TSFIFO_BITRATE0 0xf38400ff
-
-/*P2_ERRCTRL1*/
-#define R0900_P2_ERRCTRL1 0xf398
-#define F0900_P2_ERR_SOURCE1 0xf39800f0
-#define F0900_P2_NUM_EVENT1 0xf3980007
-
-/*P2_ERRCNT12*/
-#define R0900_P2_ERRCNT12 0xf399
-#define F0900_P2_ERRCNT1_OLDVALUE 0xf3990080
-#define F0900_P2_ERR_CNT12 0xf399007f
-
-/*P2_ERRCNT11*/
-#define R0900_P2_ERRCNT11 0xf39a
-#define F0900_P2_ERR_CNT11 0xf39a00ff
-
-/*P2_ERRCNT10*/
-#define R0900_P2_ERRCNT10 0xf39b
-#define F0900_P2_ERR_CNT10 0xf39b00ff
-
-/*P2_ERRCTRL2*/
-#define R0900_P2_ERRCTRL2 0xf39c
-#define F0900_P2_ERR_SOURCE2 0xf39c00f0
-#define F0900_P2_NUM_EVENT2 0xf39c0007
-
-/*P2_ERRCNT22*/
-#define R0900_P2_ERRCNT22 0xf39d
-#define F0900_P2_ERRCNT2_OLDVALUE 0xf39d0080
-#define F0900_P2_ERR_CNT22 0xf39d007f
-
-/*P2_ERRCNT21*/
-#define R0900_P2_ERRCNT21 0xf39e
-#define F0900_P2_ERR_CNT21 0xf39e00ff
-
-/*P2_ERRCNT20*/
-#define R0900_P2_ERRCNT20 0xf39f
-#define F0900_P2_ERR_CNT20 0xf39f00ff
-
-/*P2_FECSPY*/
-#define R0900_P2_FECSPY 0xf3a0
-#define F0900_P2_SPY_ENABLE 0xf3a00080
-#define F0900_P2_NO_SYNCBYTE 0xf3a00040
-#define F0900_P2_SERIAL_MODE 0xf3a00020
-#define F0900_P2_UNUSUAL_PACKET 0xf3a00010
-#define F0900_P2_BERMETER_DATAMODE 0xf3a00008
-#define F0900_P2_BERMETER_LMODE 0xf3a00002
-#define F0900_P2_BERMETER_RESET 0xf3a00001
-
-/*P2_FSPYCFG*/
-#define R0900_P2_FSPYCFG 0xf3a1
-#define F0900_P2_FECSPY_INPUT 0xf3a100c0
-#define F0900_P2_RST_ON_ERROR 0xf3a10020
-#define F0900_P2_ONE_SHOT 0xf3a10010
-#define F0900_P2_I2C_MODE 0xf3a1000c
-#define F0900_P2_SPY_HYSTERESIS 0xf3a10003
-
-/*P2_FSPYDATA*/
-#define R0900_P2_FSPYDATA 0xf3a2
-#define F0900_P2_SPY_STUFFING 0xf3a20080
-#define F0900_P2_SPY_CNULLPKT 0xf3a20020
-#define F0900_P2_SPY_OUTDATA_MODE 0xf3a2001f
-
-/*P2_FSPYOUT*/
-#define R0900_P2_FSPYOUT 0xf3a3
-#define F0900_P2_FSPY_DIRECT 0xf3a30080
-#define F0900_P2_STUFF_MODE 0xf3a30007
-
-/*P2_FSTATUS*/
-#define R0900_P2_FSTATUS 0xf3a4
-#define F0900_P2_SPY_ENDSIM 0xf3a40080
-#define F0900_P2_VALID_SIM 0xf3a40040
-#define F0900_P2_FOUND_SIGNAL 0xf3a40020
-#define F0900_P2_DSS_SYNCBYTE 0xf3a40010
-#define F0900_P2_RESULT_STATE 0xf3a4000f
-
-/*P2_FBERCPT4*/
-#define R0900_P2_FBERCPT4 0xf3a8
-#define F0900_P2_FBERMETER_CPT4 0xf3a800ff
-
-/*P2_FBERCPT3*/
-#define R0900_P2_FBERCPT3 0xf3a9
-#define F0900_P2_FBERMETER_CPT3 0xf3a900ff
-
-/*P2_FBERCPT2*/
-#define R0900_P2_FBERCPT2 0xf3aa
-#define F0900_P2_FBERMETER_CPT2 0xf3aa00ff
-
-/*P2_FBERCPT1*/
-#define R0900_P2_FBERCPT1 0xf3ab
-#define F0900_P2_FBERMETER_CPT1 0xf3ab00ff
-
-/*P2_FBERCPT0*/
-#define R0900_P2_FBERCPT0 0xf3ac
-#define F0900_P2_FBERMETER_CPT0 0xf3ac00ff
-
-/*P2_FBERERR2*/
-#define R0900_P2_FBERERR2 0xf3ad
-#define F0900_P2_FBERMETER_ERR2 0xf3ad00ff
-
-/*P2_FBERERR1*/
-#define R0900_P2_FBERERR1 0xf3ae
-#define F0900_P2_FBERMETER_ERR1 0xf3ae00ff
-
-/*P2_FBERERR0*/
-#define R0900_P2_FBERERR0 0xf3af
-#define F0900_P2_FBERMETER_ERR0 0xf3af00ff
-
-/*P2_FSPYBER*/
-#define R0900_P2_FSPYBER 0xf3b2
-#define F0900_P2_FSPYBER_SYNCBYTE 0xf3b20010
-#define F0900_P2_FSPYBER_UNSYNC 0xf3b20008
-#define F0900_P2_FSPYBER_CTIME 0xf3b20007
-
-/*P1_IQCONST*/
-#define R0900_P1_IQCONST 0xf400
-#define IQCONST REGx(R0900_P1_IQCONST)
-#define F0900_P1_CONSTEL_SELECT 0xf4000060
-#define F0900_P1_IQSYMB_SEL 0xf400001f
-
-/*P1_NOSCFG*/
-#define R0900_P1_NOSCFG 0xf401
-#define NOSCFG REGx(R0900_P1_NOSCFG)
-#define F0900_P1_DUMMYPL_NOSDATA 0xf4010020
-#define F0900_P1_NOSPLH_BETA 0xf4010018
-#define F0900_P1_NOSDATA_BETA 0xf4010007
-
-/*P1_ISYMB*/
-#define R0900_P1_ISYMB 0xf402
-#define ISYMB REGx(R0900_P1_ISYMB)
-#define F0900_P1_I_SYMBOL 0xf40201ff
-
-/*P1_QSYMB*/
-#define R0900_P1_QSYMB 0xf403
-#define QSYMB REGx(R0900_P1_QSYMB)
-#define F0900_P1_Q_SYMBOL 0xf40301ff
-
-/*P1_AGC1CFG*/
-#define R0900_P1_AGC1CFG 0xf404
-#define AGC1CFG REGx(R0900_P1_AGC1CFG)
-#define F0900_P1_DC_FROZEN 0xf4040080
-#define F0900_P1_DC_CORRECT 0xf4040040
-#define F0900_P1_AMM_FROZEN 0xf4040020
-#define F0900_P1_AMM_CORRECT 0xf4040010
-#define F0900_P1_QUAD_FROZEN 0xf4040008
-#define F0900_P1_QUAD_CORRECT 0xf4040004
-
-/*P1_AGC1CN*/
-#define R0900_P1_AGC1CN 0xf406
-#define AGC1CN REGx(R0900_P1_AGC1CN)
-#define F0900_P1_AGC1_LOCKED 0xf4060080
-#define F0900_P1_AGC1_MINPOWER 0xf4060010
-#define F0900_P1_AGCOUT_FAST 0xf4060008
-#define F0900_P1_AGCIQ_BETA 0xf4060007
-
-/*P1_AGC1REF*/
-#define R0900_P1_AGC1REF 0xf407
-#define AGC1REF REGx(R0900_P1_AGC1REF)
-#define F0900_P1_AGCIQ_REF 0xf40700ff
-
-/*P1_IDCCOMP*/
-#define R0900_P1_IDCCOMP 0xf408
-#define IDCCOMP REGx(R0900_P1_IDCCOMP)
-#define F0900_P1_IAVERAGE_ADJ 0xf40801ff
-
-/*P1_QDCCOMP*/
-#define R0900_P1_QDCCOMP 0xf409
-#define QDCCOMP REGx(R0900_P1_QDCCOMP)
-#define F0900_P1_QAVERAGE_ADJ 0xf40901ff
-
-/*P1_POWERI*/
-#define R0900_P1_POWERI 0xf40a
-#define POWERI REGx(R0900_P1_POWERI)
-#define F0900_P1_POWER_I 0xf40a00ff
-#define POWER_I FLDx(F0900_P1_POWER_I)
-
-/*P1_POWERQ*/
-#define R0900_P1_POWERQ 0xf40b
-#define POWERQ REGx(R0900_P1_POWERQ)
-#define F0900_P1_POWER_Q 0xf40b00ff
-#define POWER_Q FLDx(F0900_P1_POWER_Q)
-
-/*P1_AGC1AMM*/
-#define R0900_P1_AGC1AMM 0xf40c
-#define AGC1AMM REGx(R0900_P1_AGC1AMM)
-#define F0900_P1_AMM_VALUE 0xf40c00ff
-
-/*P1_AGC1QUAD*/
-#define R0900_P1_AGC1QUAD 0xf40d
-#define AGC1QUAD REGx(R0900_P1_AGC1QUAD)
-#define F0900_P1_QUAD_VALUE 0xf40d01ff
-
-/*P1_AGCIQIN1*/
-#define R0900_P1_AGCIQIN1 0xf40e
-#define AGCIQIN1 REGx(R0900_P1_AGCIQIN1)
-#define F0900_P1_AGCIQ_VALUE1 0xf40e00ff
-#define AGCIQ_VALUE1 FLDx(F0900_P1_AGCIQ_VALUE1)
-
-/*P1_AGCIQIN0*/
-#define R0900_P1_AGCIQIN0 0xf40f
-#define AGCIQIN0 REGx(R0900_P1_AGCIQIN0)
-#define F0900_P1_AGCIQ_VALUE0 0xf40f00ff
-#define AGCIQ_VALUE0 FLDx(F0900_P1_AGCIQ_VALUE0)
-
-/*P1_DEMOD*/
-#define R0900_P1_DEMOD 0xf410
-#define DEMOD REGx(R0900_P1_DEMOD)
-#define F0900_P1_MANUALS2_ROLLOFF 0xf4100080
-#define MANUALS2_ROLLOFF FLDx(F0900_P1_MANUALS2_ROLLOFF)
-
-#define F0900_P1_SPECINV_CONTROL 0xf4100030
-#define SPECINV_CONTROL FLDx(F0900_P1_SPECINV_CONTROL)
-#define F0900_P1_FORCE_ENASAMP 0xf4100008
-#define F0900_P1_MANUALSX_ROLLOFF 0xf4100004
-#define MANUALSX_ROLLOFF FLDx(F0900_P1_MANUALSX_ROLLOFF)
-#define F0900_P1_ROLLOFF_CONTROL 0xf4100003
-#define ROLLOFF_CONTROL FLDx(F0900_P1_ROLLOFF_CONTROL)
-
-/*P1_DMDMODCOD*/
-#define R0900_P1_DMDMODCOD 0xf411
-#define DMDMODCOD REGx(R0900_P1_DMDMODCOD)
-#define F0900_P1_MANUAL_MODCOD 0xf4110080
-#define F0900_P1_DEMOD_MODCOD 0xf411007c
-#define DEMOD_MODCOD FLDx(F0900_P1_DEMOD_MODCOD)
-#define F0900_P1_DEMOD_TYPE 0xf4110003
-#define DEMOD_TYPE FLDx(F0900_P1_DEMOD_TYPE)
-
-/*P1_DSTATUS*/
-#define R0900_P1_DSTATUS 0xf412
-#define DSTATUS REGx(R0900_P1_DSTATUS)
-#define F0900_P1_CAR_LOCK 0xf4120080
-#define F0900_P1_TMGLOCK_QUALITY 0xf4120060
-#define TMGLOCK_QUALITY FLDx(F0900_P1_TMGLOCK_QUALITY)
-#define F0900_P1_LOCK_DEFINITIF 0xf4120008
-#define LOCK_DEFINITIF FLDx(F0900_P1_LOCK_DEFINITIF)
-#define F0900_P1_OVADC_DETECT 0xf4120001
-
-/*P1_DSTATUS2*/
-#define R0900_P1_DSTATUS2 0xf413
-#define DSTATUS2 REGx(R0900_P1_DSTATUS2)
-#define F0900_P1_DEMOD_DELOCK 0xf4130080
-#define F0900_P1_AGC1_NOSIGNALACK 0xf4130008
-#define F0900_P1_AGC2_OVERFLOW 0xf4130004
-#define F0900_P1_CFR_OVERFLOW 0xf4130002
-#define F0900_P1_GAMMA_OVERUNDER 0xf4130001
-
-/*P1_DMDCFGMD*/
-#define R0900_P1_DMDCFGMD 0xf414
-#define DMDCFGMD REGx(R0900_P1_DMDCFGMD)
-#define F0900_P1_DVBS2_ENABLE 0xf4140080
-#define DVBS2_ENABLE FLDx(F0900_P1_DVBS2_ENABLE)
-#define F0900_P1_DVBS1_ENABLE 0xf4140040
-#define DVBS1_ENABLE FLDx(F0900_P1_DVBS1_ENABLE)
-#define F0900_P1_SCAN_ENABLE 0xf4140010
-#define SCAN_ENABLE FLDx(F0900_P1_SCAN_ENABLE)
-#define F0900_P1_CFR_AUTOSCAN 0xf4140008
-#define CFR_AUTOSCAN FLDx(F0900_P1_CFR_AUTOSCAN)
-#define F0900_P1_TUN_RNG 0xf4140003
-
-/*P1_DMDCFG2*/
-#define R0900_P1_DMDCFG2 0xf415
-#define DMDCFG2 REGx(R0900_P1_DMDCFG2)
-#define F0900_P1_S1S2_SEQUENTIAL 0xf4150040
-#define S1S2_SEQUENTIAL FLDx(F0900_P1_S1S2_SEQUENTIAL)
-#define F0900_P1_INFINITE_RELOCK 0xf4150010
-
-/*P1_DMDISTATE*/
-#define R0900_P1_DMDISTATE 0xf416
-#define DMDISTATE REGx(R0900_P1_DMDISTATE)
-#define F0900_P1_I2C_DEMOD_MODE 0xf416001f
-#define DEMOD_MODE FLDx(F0900_P1_I2C_DEMOD_MODE)
-
-/*P1_DMDT0M*/
-#define R0900_P1_DMDT0M 0xf417
-#define DMDT0M REGx(R0900_P1_DMDT0M)
-#define F0900_P1_DMDT0_MIN 0xf41700ff
-
-/*P1_DMDSTATE*/
-#define R0900_P1_DMDSTATE 0xf41b
-#define DMDSTATE REGx(R0900_P1_DMDSTATE)
-#define F0900_P1_HEADER_MODE 0xf41b0060
-#define HEADER_MODE FLDx(F0900_P1_HEADER_MODE)
-
-/*P1_DMDFLYW*/
-#define R0900_P1_DMDFLYW 0xf41c
-#define DMDFLYW REGx(R0900_P1_DMDFLYW)
-#define F0900_P1_I2C_IRQVAL 0xf41c00f0
-#define F0900_P1_FLYWHEEL_CPT 0xf41c000f
-#define FLYWHEEL_CPT FLDx(F0900_P1_FLYWHEEL_CPT)
-
-/*P1_DSTATUS3*/
-#define R0900_P1_DSTATUS3 0xf41d
-#define DSTATUS3 REGx(R0900_P1_DSTATUS3)
-#define F0900_P1_DEMOD_CFGMODE 0xf41d0060
-
-/*P1_DMDCFG3*/
-#define R0900_P1_DMDCFG3 0xf41e
-#define DMDCFG3 REGx(R0900_P1_DMDCFG3)
-#define F0900_P1_NOSTOP_FIFOFULL 0xf41e0008
-
-/*P1_DMDCFG4*/
-#define R0900_P1_DMDCFG4 0xf41f
-#define DMDCFG4 REGx(R0900_P1_DMDCFG4)
-#define F0900_P1_TUNER_NRELAUNCH 0xf41f0008
-
-/*P1_CORRELMANT*/
-#define R0900_P1_CORRELMANT 0xf420
-#define CORRELMANT REGx(R0900_P1_CORRELMANT)
-#define F0900_P1_CORREL_MANT 0xf42000ff
-
-/*P1_CORRELABS*/
-#define R0900_P1_CORRELABS 0xf421
-#define CORRELABS REGx(R0900_P1_CORRELABS)
-#define F0900_P1_CORREL_ABS 0xf42100ff
-
-/*P1_CORRELEXP*/
-#define R0900_P1_CORRELEXP 0xf422
-#define CORRELEXP REGx(R0900_P1_CORRELEXP)
-#define F0900_P1_CORREL_ABSEXP 0xf42200f0
-#define F0900_P1_CORREL_EXP 0xf422000f
-
-/*P1_PLHMODCOD*/
-#define R0900_P1_PLHMODCOD 0xf424
-#define PLHMODCOD REGx(R0900_P1_PLHMODCOD)
-#define F0900_P1_SPECINV_DEMOD 0xf4240080
-#define SPECINV_DEMOD FLDx(F0900_P1_SPECINV_DEMOD)
-#define F0900_P1_PLH_MODCOD 0xf424007c
-#define F0900_P1_PLH_TYPE 0xf4240003
-
-/*P1_DMDREG*/
-#define R0900_P1_DMDREG 0xf425
-#define DMDREG REGx(R0900_P1_DMDREG)
-#define F0900_P1_DECIM_PLFRAMES 0xf4250001
-
-/*P1_AGC2O*/
-#define R0900_P1_AGC2O 0xf42c
-#define AGC2O REGx(R0900_P1_AGC2O)
-#define F0900_P1_AGC2_COEF 0xf42c0007
-
-/*P1_AGC2REF*/
-#define R0900_P1_AGC2REF 0xf42d
-#define AGC2REF REGx(R0900_P1_AGC2REF)
-#define F0900_P1_AGC2_REF 0xf42d00ff
-
-/*P1_AGC1ADJ*/
-#define R0900_P1_AGC1ADJ 0xf42e
-#define AGC1ADJ REGx(R0900_P1_AGC1ADJ)
-#define F0900_P1_AGC1_ADJUSTED 0xf42e007f
-
-/*P1_AGC2I1*/
-#define R0900_P1_AGC2I1 0xf436
-#define AGC2I1 REGx(R0900_P1_AGC2I1)
-#define F0900_P1_AGC2_INTEGRATOR1 0xf43600ff
-
-/*P1_AGC2I0*/
-#define R0900_P1_AGC2I0 0xf437
-#define AGC2I0 REGx(R0900_P1_AGC2I0)
-#define F0900_P1_AGC2_INTEGRATOR0 0xf43700ff
-
-/*P1_CARCFG*/
-#define R0900_P1_CARCFG 0xf438
-#define CARCFG REGx(R0900_P1_CARCFG)
-#define F0900_P1_CFRUPLOW_AUTO 0xf4380080
-#define F0900_P1_CFRUPLOW_TEST 0xf4380040
-#define F0900_P1_ROTAON 0xf4380004
-#define F0900_P1_PH_DET_ALGO 0xf4380003
-
-/*P1_ACLC*/
-#define R0900_P1_ACLC 0xf439
-#define ACLC REGx(R0900_P1_ACLC)
-#define F0900_P1_CAR_ALPHA_MANT 0xf4390030
-#define F0900_P1_CAR_ALPHA_EXP 0xf439000f
-
-/*P1_BCLC*/
-#define R0900_P1_BCLC 0xf43a
-#define BCLC REGx(R0900_P1_BCLC)
-#define F0900_P1_CAR_BETA_MANT 0xf43a0030
-#define F0900_P1_CAR_BETA_EXP 0xf43a000f
-
-/*P1_CARFREQ*/
-#define R0900_P1_CARFREQ 0xf43d
-#define CARFREQ REGx(R0900_P1_CARFREQ)
-#define F0900_P1_KC_COARSE_EXP 0xf43d00f0
-#define F0900_P1_BETA_FREQ 0xf43d000f
-
-/*P1_CARHDR*/
-#define R0900_P1_CARHDR 0xf43e
-#define CARHDR REGx(R0900_P1_CARHDR)
-#define F0900_P1_K_FREQ_HDR 0xf43e00ff
-
-/*P1_LDT*/
-#define R0900_P1_LDT 0xf43f
-#define LDT REGx(R0900_P1_LDT)
-#define F0900_P1_CARLOCK_THRES 0xf43f01ff
-
-/*P1_LDT2*/
-#define R0900_P1_LDT2 0xf440
-#define LDT2 REGx(R0900_P1_LDT2)
-#define F0900_P1_CARLOCK_THRES2 0xf44001ff
-
-/*P1_CFRICFG*/
-#define R0900_P1_CFRICFG 0xf441
-#define CFRICFG REGx(R0900_P1_CFRICFG)
-#define F0900_P1_NEG_CFRSTEP 0xf4410001
-
-/*P1_CFRUP1*/
-#define R0900_P1_CFRUP1 0xf442
-#define CFRUP1 REGx(R0900_P1_CFRUP1)
-#define F0900_P1_CFR_UP1 0xf44201ff
-#define CFR_UP1 FLDx(F0900_P1_CFR_UP1)
-
-/*P1_CFRUP0*/
-#define R0900_P1_CFRUP0 0xf443
-#define CFRUP0 REGx(R0900_P1_CFRUP0)
-#define F0900_P1_CFR_UP0 0xf44300ff
-#define CFR_UP0 FLDx(F0900_P1_CFR_UP0)
-
-/*P1_CFRLOW1*/
-#define R0900_P1_CFRLOW1 0xf446
-#define CFRLOW1 REGx(R0900_P1_CFRLOW1)
-#define F0900_P1_CFR_LOW1 0xf44601ff
-#define CFR_LOW1 FLDx(F0900_P1_CFR_LOW1)
-
-/*P1_CFRLOW0*/
-#define R0900_P1_CFRLOW0 0xf447
-#define CFRLOW0 REGx(R0900_P1_CFRLOW0)
-#define F0900_P1_CFR_LOW0 0xf44700ff
-#define CFR_LOW0 FLDx(F0900_P1_CFR_LOW0)
-
-/*P1_CFRINIT1*/
-#define R0900_P1_CFRINIT1 0xf448
-#define CFRINIT1 REGx(R0900_P1_CFRINIT1)
-#define F0900_P1_CFR_INIT1 0xf44801ff
-#define CFR_INIT1 FLDx(F0900_P1_CFR_INIT1)
-
-/*P1_CFRINIT0*/
-#define R0900_P1_CFRINIT0 0xf449
-#define CFRINIT0 REGx(R0900_P1_CFRINIT0)
-#define F0900_P1_CFR_INIT0 0xf44900ff
-#define CFR_INIT0 FLDx(F0900_P1_CFR_INIT0)
-
-/*P1_CFRINC1*/
-#define R0900_P1_CFRINC1 0xf44a
-#define CFRINC1 REGx(R0900_P1_CFRINC1)
-#define F0900_P1_MANUAL_CFRINC 0xf44a0080
-#define F0900_P1_CFR_INC1 0xf44a003f
-
-/*P1_CFRINC0*/
-#define R0900_P1_CFRINC0 0xf44b
-#define CFRINC0 REGx(R0900_P1_CFRINC0)
-#define F0900_P1_CFR_INC0 0xf44b00f8
-
-/*P1_CFR2*/
-#define R0900_P1_CFR2 0xf44c
-#define CFR2 REGx(R0900_P1_CFR2)
-#define F0900_P1_CAR_FREQ2 0xf44c01ff
-#define CAR_FREQ2 FLDx(F0900_P1_CAR_FREQ2)
-
-/*P1_CFR1*/
-#define R0900_P1_CFR1 0xf44d
-#define CFR1 REGx(R0900_P1_CFR1)
-#define F0900_P1_CAR_FREQ1 0xf44d00ff
-#define CAR_FREQ1 FLDx(F0900_P1_CAR_FREQ1)
-
-/*P1_CFR0*/
-#define R0900_P1_CFR0 0xf44e
-#define CFR0 REGx(R0900_P1_CFR0)
-#define F0900_P1_CAR_FREQ0 0xf44e00ff
-#define CAR_FREQ0 FLDx(F0900_P1_CAR_FREQ0)
-
-/*P1_LDI*/
-#define R0900_P1_LDI 0xf44f
-#define LDI REGx(R0900_P1_LDI)
-#define F0900_P1_LOCK_DET_INTEGR 0xf44f01ff
-
-/*P1_TMGCFG*/
-#define R0900_P1_TMGCFG 0xf450
-#define TMGCFG REGx(R0900_P1_TMGCFG)
-#define F0900_P1_TMGLOCK_BETA 0xf45000c0
-#define F0900_P1_DO_TIMING_CORR 0xf4500010
-#define F0900_P1_TMG_MINFREQ 0xf4500003
-
-/*P1_RTC*/
-#define R0900_P1_RTC 0xf451
-#define RTC REGx(R0900_P1_RTC)
-#define F0900_P1_TMGALPHA_EXP 0xf45100f0
-#define F0900_P1_TMGBETA_EXP 0xf451000f
-
-/*P1_RTCS2*/
-#define R0900_P1_RTCS2 0xf452
-#define RTCS2 REGx(R0900_P1_RTCS2)
-#define F0900_P1_TMGALPHAS2_EXP 0xf45200f0
-#define F0900_P1_TMGBETAS2_EXP 0xf452000f
-
-/*P1_TMGTHRISE*/
-#define R0900_P1_TMGTHRISE 0xf453
-#define TMGTHRISE REGx(R0900_P1_TMGTHRISE)
-#define F0900_P1_TMGLOCK_THRISE 0xf45300ff
-
-/*P1_TMGTHFALL*/
-#define R0900_P1_TMGTHFALL 0xf454
-#define TMGTHFALL REGx(R0900_P1_TMGTHFALL)
-#define F0900_P1_TMGLOCK_THFALL 0xf45400ff
-
-/*P1_SFRUPRATIO*/
-#define R0900_P1_SFRUPRATIO 0xf455
-#define SFRUPRATIO REGx(R0900_P1_SFRUPRATIO)
-#define F0900_P1_SFR_UPRATIO 0xf45500ff
-
-/*P1_SFRLOWRATIO*/
-#define R0900_P1_SFRLOWRATIO 0xf456
-#define F0900_P1_SFR_LOWRATIO 0xf45600ff
-
-/*P1_KREFTMG*/
-#define R0900_P1_KREFTMG 0xf458
-#define KREFTMG REGx(R0900_P1_KREFTMG)
-#define F0900_P1_KREF_TMG 0xf45800ff
-
-/*P1_SFRSTEP*/
-#define R0900_P1_SFRSTEP 0xf459
-#define SFRSTEP REGx(R0900_P1_SFRSTEP)
-#define F0900_P1_SFR_SCANSTEP 0xf45900f0
-#define F0900_P1_SFR_CENTERSTEP 0xf459000f
-
-/*P1_TMGCFG2*/
-#define R0900_P1_TMGCFG2 0xf45a
-#define TMGCFG2 REGx(R0900_P1_TMGCFG2)
-#define F0900_P1_SFRRATIO_FINE 0xf45a0001
-
-/*P1_KREFTMG2*/
-#define R0900_P1_KREFTMG2 0xf45b
-#define KREFTMG2 REGx(R0900_P1_KREFTMG2)
-#define F0900_P1_KREF_TMG2 0xf45b00ff
-
-/*P1_SFRINIT1*/
-#define R0900_P1_SFRINIT1 0xf45e
-#define SFRINIT1 REGx(R0900_P1_SFRINIT1)
-#define F0900_P1_SFR_INIT1 0xf45e007f
-
-/*P1_SFRINIT0*/
-#define R0900_P1_SFRINIT0 0xf45f
-#define SFRINIT0 REGx(R0900_P1_SFRINIT0)
-#define F0900_P1_SFR_INIT0 0xf45f00ff
-
-/*P1_SFRUP1*/
-#define R0900_P1_SFRUP1 0xf460
-#define SFRUP1 REGx(R0900_P1_SFRUP1)
-#define F0900_P1_AUTO_GUP 0xf4600080
-#define AUTO_GUP FLDx(F0900_P1_AUTO_GUP)
-#define F0900_P1_SYMB_FREQ_UP1 0xf460007f
-
-/*P1_SFRUP0*/
-#define R0900_P1_SFRUP0 0xf461
-#define SFRUP0 REGx(R0900_P1_SFRUP0)
-#define F0900_P1_SYMB_FREQ_UP0 0xf46100ff
-
-/*P1_SFRLOW1*/
-#define R0900_P1_SFRLOW1 0xf462
-#define SFRLOW1 REGx(R0900_P1_SFRLOW1)
-#define F0900_P1_AUTO_GLOW 0xf4620080
-#define AUTO_GLOW FLDx(F0900_P1_AUTO_GLOW)
-#define F0900_P1_SYMB_FREQ_LOW1 0xf462007f
-
-/*P1_SFRLOW0*/
-#define R0900_P1_SFRLOW0 0xf463
-#define SFRLOW0 REGx(R0900_P1_SFRLOW0)
-#define F0900_P1_SYMB_FREQ_LOW0 0xf46300ff
-
-/*P1_SFR3*/
-#define R0900_P1_SFR3 0xf464
-#define SFR3 REGx(R0900_P1_SFR3)
-#define F0900_P1_SYMB_FREQ3 0xf46400ff
-#define SYMB_FREQ3 FLDx(F0900_P1_SYMB_FREQ3)
-
-/*P1_SFR2*/
-#define R0900_P1_SFR2 0xf465
-#define SFR2 REGx(R0900_P1_SFR2)
-#define F0900_P1_SYMB_FREQ2 0xf46500ff
-#define SYMB_FREQ2 FLDx(F0900_P1_SYMB_FREQ2)
-
-/*P1_SFR1*/
-#define R0900_P1_SFR1 0xf466
-#define SFR1 REGx(R0900_P1_SFR1)
-#define F0900_P1_SYMB_FREQ1 0xf46600ff
-#define SYMB_FREQ1 FLDx(F0900_P1_SYMB_FREQ1)
-
-/*P1_SFR0*/
-#define R0900_P1_SFR0 0xf467
-#define SFR0 REGx(R0900_P1_SFR0)
-#define F0900_P1_SYMB_FREQ0 0xf46700ff
-#define SYMB_FREQ0 FLDx(F0900_P1_SYMB_FREQ0)
-
-/*P1_TMGREG2*/
-#define R0900_P1_TMGREG2 0xf468
-#define TMGREG2 REGx(R0900_P1_TMGREG2)
-#define F0900_P1_TMGREG2 0xf46800ff
-
-/*P1_TMGREG1*/
-#define R0900_P1_TMGREG1 0xf469
-#define TMGREG1 REGx(R0900_P1_TMGREG1)
-#define F0900_P1_TMGREG1 0xf46900ff
-
-/*P1_TMGREG0*/
-#define R0900_P1_TMGREG0 0xf46a
-#define TMGREG0 REGx(R0900_P1_TMGREG0)
-#define F0900_P1_TMGREG0 0xf46a00ff
-
-/*P1_TMGLOCK1*/
-#define R0900_P1_TMGLOCK1 0xf46b
-#define TMGLOCK1 REGx(R0900_P1_TMGLOCK1)
-#define F0900_P1_TMGLOCK_LEVEL1 0xf46b01ff
-
-/*P1_TMGLOCK0*/
-#define R0900_P1_TMGLOCK0 0xf46c
-#define TMGLOCK0 REGx(R0900_P1_TMGLOCK0)
-#define F0900_P1_TMGLOCK_LEVEL0 0xf46c00ff
-
-/*P1_TMGOBS*/
-#define R0900_P1_TMGOBS 0xf46d
-#define TMGOBS REGx(R0900_P1_TMGOBS)
-#define F0900_P1_ROLLOFF_STATUS 0xf46d00c0
-#define ROLLOFF_STATUS FLDx(F0900_P1_ROLLOFF_STATUS)
-
-/*P1_EQUALCFG*/
-#define R0900_P1_EQUALCFG 0xf46f
-#define EQUALCFG REGx(R0900_P1_EQUALCFG)
-#define F0900_P1_EQUAL_ON 0xf46f0040
-#define F0900_P1_MU_EQUALDFE 0xf46f0007
-
-/*P1_EQUAI1*/
-#define R0900_P1_EQUAI1 0xf470
-#define EQUAI1 REGx(R0900_P1_EQUAI1)
-#define F0900_P1_EQUA_ACCI1 0xf47001ff
-
-/*P1_EQUAQ1*/
-#define R0900_P1_EQUAQ1 0xf471
-#define EQUAQ1 REGx(R0900_P1_EQUAQ1)
-#define F0900_P1_EQUA_ACCQ1 0xf47101ff
-
-/*P1_EQUAI2*/
-#define R0900_P1_EQUAI2 0xf472
-#define EQUAI2 REGx(R0900_P1_EQUAI2)
-#define F0900_P1_EQUA_ACCI2 0xf47201ff
-
-/*P1_EQUAQ2*/
-#define R0900_P1_EQUAQ2 0xf473
-#define EQUAQ2 REGx(R0900_P1_EQUAQ2)
-#define F0900_P1_EQUA_ACCQ2 0xf47301ff
-
-/*P1_EQUAI3*/
-#define R0900_P1_EQUAI3 0xf474
-#define EQUAI3 REGx(R0900_P1_EQUAI3)
-#define F0900_P1_EQUA_ACCI3 0xf47401ff
-
-/*P1_EQUAQ3*/
-#define R0900_P1_EQUAQ3 0xf475
-#define EQUAQ3 REGx(R0900_P1_EQUAQ3)
-#define F0900_P1_EQUA_ACCQ3 0xf47501ff
-
-/*P1_EQUAI4*/
-#define R0900_P1_EQUAI4 0xf476
-#define EQUAI4 REGx(R0900_P1_EQUAI4)
-#define F0900_P1_EQUA_ACCI4 0xf47601ff
-
-/*P1_EQUAQ4*/
-#define R0900_P1_EQUAQ4 0xf477
-#define EQUAQ4 REGx(R0900_P1_EQUAQ4)
-#define F0900_P1_EQUA_ACCQ4 0xf47701ff
-
-/*P1_EQUAI5*/
-#define R0900_P1_EQUAI5 0xf478
-#define EQUAI5 REGx(R0900_P1_EQUAI5)
-#define F0900_P1_EQUA_ACCI5 0xf47801ff
-
-/*P1_EQUAQ5*/
-#define R0900_P1_EQUAQ5 0xf479
-#define EQUAQ5 REGx(R0900_P1_EQUAQ5)
-#define F0900_P1_EQUA_ACCQ5 0xf47901ff
-
-/*P1_EQUAI6*/
-#define R0900_P1_EQUAI6 0xf47a
-#define EQUAI6 REGx(R0900_P1_EQUAI6)
-#define F0900_P1_EQUA_ACCI6 0xf47a01ff
-
-/*P1_EQUAQ6*/
-#define R0900_P1_EQUAQ6 0xf47b
-#define EQUAQ6 REGx(R0900_P1_EQUAQ6)
-#define F0900_P1_EQUA_ACCQ6 0xf47b01ff
-
-/*P1_EQUAI7*/
-#define R0900_P1_EQUAI7 0xf47c
-#define EQUAI7 REGx(R0900_P1_EQUAI7)
-#define F0900_P1_EQUA_ACCI7 0xf47c01ff
-
-/*P1_EQUAQ7*/
-#define R0900_P1_EQUAQ7 0xf47d
-#define EQUAQ7 REGx(R0900_P1_EQUAQ7)
-#define F0900_P1_EQUA_ACCQ7 0xf47d01ff
-
-/*P1_EQUAI8*/
-#define R0900_P1_EQUAI8 0xf47e
-#define EQUAI8 REGx(R0900_P1_EQUAI8)
-#define F0900_P1_EQUA_ACCI8 0xf47e01ff
-
-/*P1_EQUAQ8*/
-#define R0900_P1_EQUAQ8 0xf47f
-#define EQUAQ8 REGx(R0900_P1_EQUAQ8)
-#define F0900_P1_EQUA_ACCQ8 0xf47f01ff
-
-/*P1_NNOSDATAT1*/
-#define R0900_P1_NNOSDATAT1 0xf480
-#define NNOSDATAT1 REGx(R0900_P1_NNOSDATAT1)
-#define F0900_P1_NOSDATAT_NORMED1 0xf48000ff
-#define NOSDATAT_NORMED1 FLDx(F0900_P1_NOSDATAT_NORMED1)
-
-/*P1_NNOSDATAT0*/
-#define R0900_P1_NNOSDATAT0 0xf481
-#define NNOSDATAT0 REGx(R0900_P1_NNOSDATAT0)
-#define F0900_P1_NOSDATAT_NORMED0 0xf48100ff
-#define NOSDATAT_NORMED0 FLDx(F0900_P1_NOSDATAT_NORMED0)
-
-/*P1_NNOSDATA1*/
-#define R0900_P1_NNOSDATA1 0xf482
-#define NNOSDATA1 REGx(R0900_P1_NNOSDATA1)
-#define F0900_P1_NOSDATA_NORMED1 0xf48200ff
-
-/*P1_NNOSDATA0*/
-#define R0900_P1_NNOSDATA0 0xf483
-#define NNOSDATA0 REGx(R0900_P1_NNOSDATA0)
-#define F0900_P1_NOSDATA_NORMED0 0xf48300ff
-
-/*P1_NNOSPLHT1*/
-#define R0900_P1_NNOSPLHT1 0xf484
-#define NNOSPLHT1 REGx(R0900_P1_NNOSPLHT1)
-#define F0900_P1_NOSPLHT_NORMED1 0xf48400ff
-#define NOSPLHT_NORMED1 FLDx(F0900_P1_NOSPLHT_NORMED1)
-
-/*P1_NNOSPLHT0*/
-#define R0900_P1_NNOSPLHT0 0xf485
-#define NNOSPLHT0 REGx(R0900_P1_NNOSPLHT0)
-#define F0900_P1_NOSPLHT_NORMED0 0xf48500ff
-#define NOSPLHT_NORMED0 FLDx(F0900_P1_NOSPLHT_NORMED0)
-
-/*P1_NNOSPLH1*/
-#define R0900_P1_NNOSPLH1 0xf486
-#define NNOSPLH1 REGx(R0900_P1_NNOSPLH1)
-#define F0900_P1_NOSPLH_NORMED1 0xf48600ff
-
-/*P1_NNOSPLH0*/
-#define R0900_P1_NNOSPLH0 0xf487
-#define NNOSPLH0 REGx(R0900_P1_NNOSPLH0)
-#define F0900_P1_NOSPLH_NORMED0 0xf48700ff
-
-/*P1_NOSDATAT1*/
-#define R0900_P1_NOSDATAT1 0xf488
-#define NOSDATAT1 REGx(R0900_P1_NOSDATAT1)
-#define F0900_P1_NOSDATAT_UNNORMED1 0xf48800ff
-
-/*P1_NOSDATAT0*/
-#define R0900_P1_NOSDATAT0 0xf489
-#define NOSDATAT0 REGx(R0900_P1_NOSDATAT0)
-#define F0900_P1_NOSDATAT_UNNORMED0 0xf48900ff
-
-/*P1_NOSDATA1*/
-#define R0900_P1_NOSDATA1 0xf48a
-#define NOSDATA1 REGx(R0900_P1_NOSDATA1)
-#define F0900_P1_NOSDATA_UNNORMED1 0xf48a00ff
-
-/*P1_NOSDATA0*/
-#define R0900_P1_NOSDATA0 0xf48b
-#define NOSDATA0 REGx(R0900_P1_NOSDATA0)
-#define F0900_P1_NOSDATA_UNNORMED0 0xf48b00ff
-
-/*P1_NOSPLHT1*/
-#define R0900_P1_NOSPLHT1 0xf48c
-#define NOSPLHT1 REGx(R0900_P1_NOSPLHT1)
-#define F0900_P1_NOSPLHT_UNNORMED1 0xf48c00ff
-
-/*P1_NOSPLHT0*/
-#define R0900_P1_NOSPLHT0 0xf48d
-#define NOSPLHT0 REGx(R0900_P1_NOSPLHT0)
-#define F0900_P1_NOSPLHT_UNNORMED0 0xf48d00ff
-
-/*P1_NOSPLH1*/
-#define R0900_P1_NOSPLH1 0xf48e
-#define NOSPLH1 REGx(R0900_P1_NOSPLH1)
-#define F0900_P1_NOSPLH_UNNORMED1 0xf48e00ff
-
-/*P1_NOSPLH0*/
-#define R0900_P1_NOSPLH0 0xf48f
-#define NOSPLH0 REGx(R0900_P1_NOSPLH0)
-#define F0900_P1_NOSPLH_UNNORMED0 0xf48f00ff
-
-/*P1_CAR2CFG*/
-#define R0900_P1_CAR2CFG 0xf490
-#define CAR2CFG REGx(R0900_P1_CAR2CFG)
-#define F0900_P1_CARRIER3_DISABLE 0xf4900040
-#define F0900_P1_ROTA2ON 0xf4900004
-#define F0900_P1_PH_DET_ALGO2 0xf4900003
-
-/*P1_CFR2CFR1*/
-#define R0900_P1_CFR2CFR1 0xf491
-#define CFR2CFR1 REGx(R0900_P1_CFR2CFR1)
-#define F0900_P1_CFR2TOCFR1_DVBS1 0xf49100c0
-#define F0900_P1_EN_S2CAR2CENTER 0xf4910020
-#define F0900_P1_DIS_BCHERRCFR2 0xf4910010
-#define F0900_P1_CFR2TOCFR1_BETA 0xf4910007
-
-/*P1_CFR22*/
-#define R0900_P1_CFR22 0xf493
-#define CFR22 REGx(R0900_P1_CFR22)
-#define F0900_P1_CAR2_FREQ2 0xf49301ff
-
-/*P1_CFR21*/
-#define R0900_P1_CFR21 0xf494
-#define CFR21 REGx(R0900_P1_CFR21)
-#define F0900_P1_CAR2_FREQ1 0xf49400ff
-
-/*P1_CFR20*/
-#define R0900_P1_CFR20 0xf495
-#define CFR20 REGx(R0900_P1_CFR20)
-#define F0900_P1_CAR2_FREQ0 0xf49500ff
-
-/*P1_ACLC2S2Q*/
-#define R0900_P1_ACLC2S2Q 0xf497
-#define ACLC2S2Q REGx(R0900_P1_ACLC2S2Q)
-#define F0900_P1_ENAB_SPSKSYMB 0xf4970080
-#define F0900_P1_CAR2S2_Q_ALPH_M 0xf4970030
-#define F0900_P1_CAR2S2_Q_ALPH_E 0xf497000f
-
-/*P1_ACLC2S28*/
-#define R0900_P1_ACLC2S28 0xf498
-#define ACLC2S28 REGx(R0900_P1_ACLC2S28)
-#define F0900_P1_OLDI3Q_MODE 0xf4980080
-#define F0900_P1_CAR2S2_8_ALPH_M 0xf4980030
-#define F0900_P1_CAR2S2_8_ALPH_E 0xf498000f
-
-/*P1_ACLC2S216A*/
-#define R0900_P1_ACLC2S216A 0xf499
-#define ACLC2S216A REGx(R0900_P1_ACLC2S216A)
-#define F0900_P1_DIS_C3STOPA2 0xf4990080
-#define F0900_P1_CAR2S2_16ADERAT 0xf4990040
-#define F0900_P1_CAR2S2_16A_ALPH_M 0xf4990030
-#define F0900_P1_CAR2S2_16A_ALPH_E 0xf499000f
-
-/*P1_ACLC2S232A*/
-#define R0900_P1_ACLC2S232A 0xf49a
-#define ACLC2S232A REGx(R0900_P1_ACLC2S232A)
-#define F0900_P1_CAR2S2_32ADERAT 0xf49a0040
-#define F0900_P1_CAR2S2_32A_ALPH_M 0xf49a0030
-#define F0900_P1_CAR2S2_32A_ALPH_E 0xf49a000f
-
-/*P1_BCLC2S2Q*/
-#define R0900_P1_BCLC2S2Q 0xf49c
-#define BCLC2S2Q REGx(R0900_P1_BCLC2S2Q)
-#define F0900_P1_CAR2S2_Q_BETA_M 0xf49c0030
-#define F0900_P1_CAR2S2_Q_BETA_E 0xf49c000f
-
-/*P1_BCLC2S28*/
-#define R0900_P1_BCLC2S28 0xf49d
-#define BCLC2S28 REGx(R0900_P1_BCLC2S28)
-#define F0900_P1_CAR2S2_8_BETA_M 0xf49d0030
-#define F0900_P1_CAR2S2_8_BETA_E 0xf49d000f
-
-/*P1_BCLC2S216A*/
-#define R0900_P1_BCLC2S216A 0xf49e
-#define BCLC2S216A REGx(R0900_P1_BCLC2S216A)
-
-/*P1_BCLC2S232A*/
-#define R0900_P1_BCLC2S232A 0xf49f
-#define BCLC2S232A REGx(R0900_P1_BCLC2S232A)
-
-/*P1_PLROOT2*/
-#define R0900_P1_PLROOT2 0xf4ac
-#define PLROOT2 REGx(R0900_P1_PLROOT2)
-#define F0900_P1_PLSCRAMB_MODE 0xf4ac000c
-#define F0900_P1_PLSCRAMB_ROOT2 0xf4ac0003
-
-/*P1_PLROOT1*/
-#define R0900_P1_PLROOT1 0xf4ad
-#define PLROOT1 REGx(R0900_P1_PLROOT1)
-#define F0900_P1_PLSCRAMB_ROOT1 0xf4ad00ff
-
-/*P1_PLROOT0*/
-#define R0900_P1_PLROOT0 0xf4ae
-#define PLROOT0 REGx(R0900_P1_PLROOT0)
-#define F0900_P1_PLSCRAMB_ROOT0 0xf4ae00ff
-
-/*P1_MODCODLST0*/
-#define R0900_P1_MODCODLST0 0xf4b0
-#define MODCODLST0 REGx(R0900_P1_MODCODLST0)
-
-/*P1_MODCODLST1*/
-#define R0900_P1_MODCODLST1 0xf4b1
-#define MODCODLST1 REGx(R0900_P1_MODCODLST1)
-#define F0900_P1_DIS_MODCOD29 0xf4b100f0
-#define F0900_P1_DIS_32PSK_9_10 0xf4b1000f
-
-/*P1_MODCODLST2*/
-#define R0900_P1_MODCODLST2 0xf4b2
-#define MODCODLST2 REGx(R0900_P1_MODCODLST2)
-#define F0900_P1_DIS_32PSK_8_9 0xf4b200f0
-#define F0900_P1_DIS_32PSK_5_6 0xf4b2000f
-
-/*P1_MODCODLST3*/
-#define R0900_P1_MODCODLST3 0xf4b3
-#define MODCODLST3 REGx(R0900_P1_MODCODLST3)
-#define F0900_P1_DIS_32PSK_4_5 0xf4b300f0
-#define F0900_P1_DIS_32PSK_3_4 0xf4b3000f
-
-/*P1_MODCODLST4*/
-#define R0900_P1_MODCODLST4 0xf4b4
-#define MODCODLST4 REGx(R0900_P1_MODCODLST4)
-#define F0900_P1_DIS_16PSK_9_10 0xf4b400f0
-#define F0900_P1_DIS_16PSK_8_9 0xf4b4000f
-
-/*P1_MODCODLST5*/
-#define R0900_P1_MODCODLST5 0xf4b5
-#define MODCODLST5 REGx(R0900_P1_MODCODLST5)
-#define F0900_P1_DIS_16PSK_5_6 0xf4b500f0
-#define F0900_P1_DIS_16PSK_4_5 0xf4b5000f
-
-/*P1_MODCODLST6*/
-#define R0900_P1_MODCODLST6 0xf4b6
-#define MODCODLST6 REGx(R0900_P1_MODCODLST6)
-#define F0900_P1_DIS_16PSK_3_4 0xf4b600f0
-#define F0900_P1_DIS_16PSK_2_3 0xf4b6000f
-
-/*P1_MODCODLST7*/
-#define R0900_P1_MODCODLST7 0xf4b7
-#define MODCODLST7 REGx(R0900_P1_MODCODLST7)
-#define F0900_P1_DIS_8P_9_10 0xf4b700f0
-#define F0900_P1_DIS_8P_8_9 0xf4b7000f
-
-/*P1_MODCODLST8*/
-#define R0900_P1_MODCODLST8 0xf4b8
-#define MODCODLST8 REGx(R0900_P1_MODCODLST8)
-#define F0900_P1_DIS_8P_5_6 0xf4b800f0
-#define F0900_P1_DIS_8P_3_4 0xf4b8000f
-
-/*P1_MODCODLST9*/
-#define R0900_P1_MODCODLST9 0xf4b9
-#define MODCODLST9 REGx(R0900_P1_MODCODLST9)
-#define F0900_P1_DIS_8P_2_3 0xf4b900f0
-#define F0900_P1_DIS_8P_3_5 0xf4b9000f
-
-/*P1_MODCODLSTA*/
-#define R0900_P1_MODCODLSTA 0xf4ba
-#define MODCODLSTA REGx(R0900_P1_MODCODLSTA)
-#define F0900_P1_DIS_QP_9_10 0xf4ba00f0
-#define F0900_P1_DIS_QP_8_9 0xf4ba000f
-
-/*P1_MODCODLSTB*/
-#define R0900_P1_MODCODLSTB 0xf4bb
-#define MODCODLSTB REGx(R0900_P1_MODCODLSTB)
-#define F0900_P1_DIS_QP_5_6 0xf4bb00f0
-#define F0900_P1_DIS_QP_4_5 0xf4bb000f
-
-/*P1_MODCODLSTC*/
-#define R0900_P1_MODCODLSTC 0xf4bc
-#define MODCODLSTC REGx(R0900_P1_MODCODLSTC)
-#define F0900_P1_DIS_QP_3_4 0xf4bc00f0
-#define F0900_P1_DIS_QP_2_3 0xf4bc000f
-
-/*P1_MODCODLSTD*/
-#define R0900_P1_MODCODLSTD 0xf4bd
-#define MODCODLSTD REGx(R0900_P1_MODCODLSTD)
-#define F0900_P1_DIS_QP_3_5 0xf4bd00f0
-#define F0900_P1_DIS_QP_1_2 0xf4bd000f
-
-/*P1_MODCODLSTE*/
-#define R0900_P1_MODCODLSTE 0xf4be
-#define MODCODLSTE REGx(R0900_P1_MODCODLSTE)
-#define F0900_P1_DIS_QP_2_5 0xf4be00f0
-#define F0900_P1_DIS_QP_1_3 0xf4be000f
-
-/*P1_MODCODLSTF*/
-#define R0900_P1_MODCODLSTF 0xf4bf
-#define MODCODLSTF REGx(R0900_P1_MODCODLSTF)
-#define F0900_P1_DIS_QP_1_4 0xf4bf00f0
-
-/*P1_GAUSSR0*/
-#define R0900_P1_GAUSSR0 0xf4c0
-#define GAUSSR0 REGx(R0900_P1_GAUSSR0)
-#define F0900_P1_EN_CCIMODE 0xf4c00080
-#define F0900_P1_R0_GAUSSIEN 0xf4c0007f
-
-/*P1_CCIR0*/
-#define R0900_P1_CCIR0 0xf4c1
-#define CCIR0 REGx(R0900_P1_CCIR0)
-#define F0900_P1_CCIDETECT_PLHONLY 0xf4c10080
-#define F0900_P1_R0_CCI 0xf4c1007f
-
-/*P1_CCIQUANT*/
-#define R0900_P1_CCIQUANT 0xf4c2
-#define CCIQUANT REGx(R0900_P1_CCIQUANT)
-#define F0900_P1_CCI_BETA 0xf4c200e0
-#define F0900_P1_CCI_QUANT 0xf4c2001f
-
-/*P1_CCITHRES*/
-#define R0900_P1_CCITHRES 0xf4c3
-#define CCITHRES REGx(R0900_P1_CCITHRES)
-#define F0900_P1_CCI_THRESHOLD 0xf4c300ff
-
-/*P1_CCIACC*/
-#define R0900_P1_CCIACC 0xf4c4
-#define CCIACC REGx(R0900_P1_CCIACC)
-#define F0900_P1_CCI_VALUE 0xf4c400ff
-
-/*P1_DMDRESCFG*/
-#define R0900_P1_DMDRESCFG 0xf4c6
-#define DMDRESCFG REGx(R0900_P1_DMDRESCFG)
-#define F0900_P1_DMDRES_RESET 0xf4c60080
-#define F0900_P1_DMDRES_STRALL 0xf4c60008
-#define F0900_P1_DMDRES_NEWONLY 0xf4c60004
-#define F0900_P1_DMDRES_NOSTORE 0xf4c60002
-
-/*P1_DMDRESADR*/
-#define R0900_P1_DMDRESADR 0xf4c7
-#define DMDRESADR REGx(R0900_P1_DMDRESADR)
-#define F0900_P1_DMDRES_VALIDCFR 0xf4c70040
-#define F0900_P1_DMDRES_MEMFULL 0xf4c70030
-#define F0900_P1_DMDRES_RESNBR 0xf4c7000f
-
-/*P1_DMDRESDATA7*/
-#define R0900_P1_DMDRESDATA7 0xf4c8
-#define F0900_P1_DMDRES_DATA7 0xf4c800ff
-
-/*P1_DMDRESDATA6*/
-#define R0900_P1_DMDRESDATA6 0xf4c9
-#define F0900_P1_DMDRES_DATA6 0xf4c900ff
-
-/*P1_DMDRESDATA5*/
-#define R0900_P1_DMDRESDATA5 0xf4ca
-#define F0900_P1_DMDRES_DATA5 0xf4ca00ff
-
-/*P1_DMDRESDATA4*/
-#define R0900_P1_DMDRESDATA4 0xf4cb
-#define F0900_P1_DMDRES_DATA4 0xf4cb00ff
-
-/*P1_DMDRESDATA3*/
-#define R0900_P1_DMDRESDATA3 0xf4cc
-#define F0900_P1_DMDRES_DATA3 0xf4cc00ff
-
-/*P1_DMDRESDATA2*/
-#define R0900_P1_DMDRESDATA2 0xf4cd
-#define F0900_P1_DMDRES_DATA2 0xf4cd00ff
-
-/*P1_DMDRESDATA1*/
-#define R0900_P1_DMDRESDATA1 0xf4ce
-#define F0900_P1_DMDRES_DATA1 0xf4ce00ff
-
-/*P1_DMDRESDATA0*/
-#define R0900_P1_DMDRESDATA0 0xf4cf
-#define F0900_P1_DMDRES_DATA0 0xf4cf00ff
-
-/*P1_FFEI1*/
-#define R0900_P1_FFEI1 0xf4d0
-#define FFEI1 REGx(R0900_P1_FFEI1)
-#define F0900_P1_FFE_ACCI1 0xf4d001ff
-
-/*P1_FFEQ1*/
-#define R0900_P1_FFEQ1 0xf4d1
-#define FFEQ1 REGx(R0900_P1_FFEQ1)
-#define F0900_P1_FFE_ACCQ1 0xf4d101ff
-
-/*P1_FFEI2*/
-#define R0900_P1_FFEI2 0xf4d2
-#define FFEI2 REGx(R0900_P1_FFEI2)
-#define F0900_P1_FFE_ACCI2 0xf4d201ff
-
-/*P1_FFEQ2*/
-#define R0900_P1_FFEQ2 0xf4d3
-#define FFEQ2 REGx(R0900_P1_FFEQ2)
-#define F0900_P1_FFE_ACCQ2 0xf4d301ff
-
-/*P1_FFEI3*/
-#define R0900_P1_FFEI3 0xf4d4
-#define FFEI3 REGx(R0900_P1_FFEI3)
-#define F0900_P1_FFE_ACCI3 0xf4d401ff
-
-/*P1_FFEQ3*/
-#define R0900_P1_FFEQ3 0xf4d5
-#define FFEQ3 REGx(R0900_P1_FFEQ3)
-#define F0900_P1_FFE_ACCQ3 0xf4d501ff
-
-/*P1_FFEI4*/
-#define R0900_P1_FFEI4 0xf4d6
-#define FFEI4 REGx(R0900_P1_FFEI4)
-#define F0900_P1_FFE_ACCI4 0xf4d601ff
-
-/*P1_FFEQ4*/
-#define R0900_P1_FFEQ4 0xf4d7
-#define FFEQ4 REGx(R0900_P1_FFEQ4)
-#define F0900_P1_FFE_ACCQ4 0xf4d701ff
-
-/*P1_FFECFG*/
-#define R0900_P1_FFECFG 0xf4d8
-#define FFECFG REGx(R0900_P1_FFECFG)
-#define F0900_P1_EQUALFFE_ON 0xf4d80040
-#define F0900_P1_MU_EQUALFFE 0xf4d80007
-
-/*P1_TNRCFG*/
-#define R0900_P1_TNRCFG 0xf4e0
-#define TNRCFG REGx(R0900_P1_TNRCFG)
-#define F0900_P1_TUN_ACKFAIL 0xf4e00080
-#define F0900_P1_TUN_TYPE 0xf4e00070
-#define F0900_P1_TUN_SECSTOP 0xf4e00008
-#define F0900_P1_TUN_VCOSRCH 0xf4e00004
-#define F0900_P1_TUN_MADDRESS 0xf4e00003
-
-/*P1_TNRCFG2*/
-#define R0900_P1_TNRCFG2 0xf4e1
-#define TNRCFG2 REGx(R0900_P1_TNRCFG2)
-#define F0900_P1_TUN_IQSWAP 0xf4e10080
-#define F0900_P1_DIS_BWCALC 0xf4e10004
-#define F0900_P1_SHORT_WAITSTATES 0xf4e10002
-
-/*P1_TNRXTAL*/
-#define R0900_P1_TNRXTAL 0xf4e4
-#define TNRXTAL REGx(R0900_P1_TNRXTAL)
-#define F0900_P1_TUN_XTALFREQ 0xf4e4001f
-
-/*P1_TNRSTEPS*/
-#define R0900_P1_TNRSTEPS 0xf4e7
-#define TNRSTEPS REGx(R0900_P1_TNRSTEPS)
-#define F0900_P1_TUNER_BW0P125 0xf4e70080
-#define F0900_P1_BWINC_OFFSET 0xf4e70170
-#define F0900_P1_SOFTSTEP_RNG 0xf4e70008
-#define F0900_P1_TUN_BWOFFSET 0xf4e70007
-
-/*P1_TNRGAIN*/
-#define R0900_P1_TNRGAIN 0xf4e8
-#define TNRGAIN REGx(R0900_P1_TNRGAIN)
-#define F0900_P1_TUN_KDIVEN 0xf4e800c0
-#define F0900_P1_STB6X00_OCK 0xf4e80030
-#define F0900_P1_TUN_GAIN 0xf4e8000f
-
-/*P1_TNRRF1*/
-#define R0900_P1_TNRRF1 0xf4e9
-#define TNRRF1 REGx(R0900_P1_TNRRF1)
-#define F0900_P1_TUN_RFFREQ2 0xf4e900ff
-#define TUN_RFFREQ2 FLDx(F0900_P1_TUN_RFFREQ2)
-
-/*P1_TNRRF0*/
-#define R0900_P1_TNRRF0 0xf4ea
-#define TNRRF0 REGx(R0900_P1_TNRRF0)
-#define F0900_P1_TUN_RFFREQ1 0xf4ea00ff
-#define TUN_RFFREQ1 FLDx(F0900_P1_TUN_RFFREQ1)
-
-/*P1_TNRBW*/
-#define R0900_P1_TNRBW 0xf4eb
-#define TNRBW REGx(R0900_P1_TNRBW)
-#define F0900_P1_TUN_RFFREQ0 0xf4eb00c0
-#define TUN_RFFREQ0 FLDx(F0900_P1_TUN_RFFREQ0)
-#define F0900_P1_TUN_BW 0xf4eb003f
-#define TUN_BW FLDx(F0900_P1_TUN_BW)
-
-/*P1_TNRADJ*/
-#define R0900_P1_TNRADJ 0xf4ec
-#define TNRADJ REGx(R0900_P1_TNRADJ)
-#define F0900_P1_STB61X0_CALTIME 0xf4ec0040
-
-/*P1_TNRCTL2*/
-#define R0900_P1_TNRCTL2 0xf4ed
-#define TNRCTL2 REGx(R0900_P1_TNRCTL2)
-#define F0900_P1_STB61X0_RCCKOFF 0xf4ed0080
-#define F0900_P1_STB61X0_ICP_SDOFF 0xf4ed0040
-#define F0900_P1_STB61X0_DCLOOPOFF 0xf4ed0020
-#define F0900_P1_STB61X0_REFOUTSEL 0xf4ed0010
-#define F0900_P1_STB61X0_CALOFF 0xf4ed0008
-#define F0900_P1_STB6XX0_LPT_BEN 0xf4ed0004
-#define F0900_P1_STB6XX0_RX_OSCP 0xf4ed0002
-#define F0900_P1_STB6XX0_SYN 0xf4ed0001
-
-/*P1_TNRCFG3*/
-#define R0900_P1_TNRCFG3 0xf4ee
-#define TNRCFG3 REGx(R0900_P1_TNRCFG3)
-#define F0900_P1_TUN_PLLFREQ 0xf4ee001c
-#define F0900_P1_TUN_I2CFREQ_MODE 0xf4ee0003
-
-/*P1_TNRLAUNCH*/
-#define R0900_P1_TNRLAUNCH 0xf4f0
-#define TNRLAUNCH REGx(R0900_P1_TNRLAUNCH)
-
-/*P1_TNRLD*/
-#define R0900_P1_TNRLD 0xf4f0
-#define TNRLD REGx(R0900_P1_TNRLD)
-#define F0900_P1_TUNLD_VCOING 0xf4f00080
-#define F0900_P1_TUN_REG1FAIL 0xf4f00040
-#define F0900_P1_TUN_REG2FAIL 0xf4f00020
-#define F0900_P1_TUN_REG3FAIL 0xf4f00010
-#define F0900_P1_TUN_REG4FAIL 0xf4f00008
-#define F0900_P1_TUN_REG5FAIL 0xf4f00004
-#define F0900_P1_TUN_BWING 0xf4f00002
-#define F0900_P1_TUN_LOCKED 0xf4f00001
-
-/*P1_TNROBSL*/
-#define R0900_P1_TNROBSL 0xf4f6
-#define TNROBSL REGx(R0900_P1_TNROBSL)
-#define F0900_P1_TUN_I2CABORTED 0xf4f60080
-#define F0900_P1_TUN_LPEN 0xf4f60040
-#define F0900_P1_TUN_FCCK 0xf4f60020
-#define F0900_P1_TUN_I2CLOCKED 0xf4f60010
-#define F0900_P1_TUN_PROGDONE 0xf4f6000c
-#define F0900_P1_TUN_RFRESTE1 0xf4f60003
-#define TUN_RFRESTE1 FLDx(F0900_P1_TUN_RFRESTE1)
-
-/*P1_TNRRESTE*/
-#define R0900_P1_TNRRESTE 0xf4f7
-#define TNRRESTE REGx(R0900_P1_TNRRESTE)
-#define F0900_P1_TUN_RFRESTE0 0xf4f700ff
-#define TUN_RFRESTE0 FLDx(F0900_P1_TUN_RFRESTE0)
-
-/*P1_SMAPCOEF7*/
-#define R0900_P1_SMAPCOEF7 0xf500
-#define SMAPCOEF7 REGx(R0900_P1_SMAPCOEF7)
-#define F0900_P1_DIS_QSCALE 0xf5000080
-#define F0900_P1_SMAPCOEF_Q_LLR12 0xf500017f
-
-/*P1_SMAPCOEF6*/
-#define R0900_P1_SMAPCOEF6 0xf501
-#define SMAPCOEF6 REGx(R0900_P1_SMAPCOEF6)
-#define F0900_P1_ADJ_8PSKLLR1 0xf5010004
-#define F0900_P1_OLD_8PSKLLR1 0xf5010002
-#define F0900_P1_DIS_AB8PSK 0xf5010001
-
-/*P1_SMAPCOEF5*/
-#define R0900_P1_SMAPCOEF5 0xf502
-#define SMAPCOEF5 REGx(R0900_P1_SMAPCOEF5)
-#define F0900_P1_DIS_8SCALE 0xf5020080
-#define F0900_P1_SMAPCOEF_8P_LLR23 0xf502017f
-
-/*P1_NCO2MAX1*/
-#define R0900_P1_NCO2MAX1 0xf514
-#define NCO2MAX1 REGx(R0900_P1_NCO2MAX1)
-#define F0900_P1_TETA2_MAXVABS1 0xf51400ff
-
-/*P1_NCO2MAX0*/
-#define R0900_P1_NCO2MAX0 0xf515
-#define NCO2MAX0 REGx(R0900_P1_NCO2MAX0)
-#define F0900_P1_TETA2_MAXVABS0 0xf51500ff
-
-/*P1_NCO2FR1*/
-#define R0900_P1_NCO2FR1 0xf516
-#define NCO2FR1 REGx(R0900_P1_NCO2FR1)
-#define F0900_P1_NCO2FINAL_ANGLE1 0xf51600ff
-
-/*P1_NCO2FR0*/
-#define R0900_P1_NCO2FR0 0xf517
-#define NCO2FR0 REGx(R0900_P1_NCO2FR0)
-#define F0900_P1_NCO2FINAL_ANGLE0 0xf51700ff
-
-/*P1_CFR2AVRGE1*/
-#define R0900_P1_CFR2AVRGE1 0xf518
-#define CFR2AVRGE1 REGx(R0900_P1_CFR2AVRGE1)
-#define F0900_P1_I2C_CFR2AVERAGE1 0xf51800ff
-
-/*P1_CFR2AVRGE0*/
-#define R0900_P1_CFR2AVRGE0 0xf519
-#define CFR2AVRGE0 REGx(R0900_P1_CFR2AVRGE0)
-#define F0900_P1_I2C_CFR2AVERAGE0 0xf51900ff
-
-/*P1_DMDPLHSTAT*/
-#define R0900_P1_DMDPLHSTAT 0xf520
-#define DMDPLHSTAT REGx(R0900_P1_DMDPLHSTAT)
-#define F0900_P1_PLH_STATISTIC 0xf52000ff
-
-/*P1_LOCKTIME3*/
-#define R0900_P1_LOCKTIME3 0xf522
-#define LOCKTIME3 REGx(R0900_P1_LOCKTIME3)
-#define F0900_P1_DEMOD_LOCKTIME3 0xf52200ff
-
-/*P1_LOCKTIME2*/
-#define R0900_P1_LOCKTIME2 0xf523
-#define LOCKTIME2 REGx(R0900_P1_LOCKTIME2)
-#define F0900_P1_DEMOD_LOCKTIME2 0xf52300ff
-
-/*P1_LOCKTIME1*/
-#define R0900_P1_LOCKTIME1 0xf524
-#define LOCKTIME1 REGx(R0900_P1_LOCKTIME1)
-#define F0900_P1_DEMOD_LOCKTIME1 0xf52400ff
-
-/*P1_LOCKTIME0*/
-#define R0900_P1_LOCKTIME0 0xf525
-#define LOCKTIME0 REGx(R0900_P1_LOCKTIME0)
-#define F0900_P1_DEMOD_LOCKTIME0 0xf52500ff
-
-/*P1_VITSCALE*/
-#define R0900_P1_VITSCALE 0xf532
-#define VITSCALE REGx(R0900_P1_VITSCALE)
-#define F0900_P1_NVTH_NOSRANGE 0xf5320080
-#define F0900_P1_VERROR_MAXMODE 0xf5320040
-#define F0900_P1_NSLOWSN_LOCKED 0xf5320008
-#define F0900_P1_DIS_RSFLOCK 0xf5320002
-
-/*P1_FECM*/
-#define R0900_P1_FECM 0xf533
-#define FECM REGx(R0900_P1_FECM)
-#define F0900_P1_DSS_DVB 0xf5330080
-#define DSS_DVB FLDx(F0900_P1_DSS_DVB)
-#define F0900_P1_DSS_SRCH 0xf5330010
-#define F0900_P1_SYNCVIT 0xf5330002
-#define F0900_P1_IQINV 0xf5330001
-#define IQINV FLDx(F0900_P1_IQINV)
-
-/*P1_VTH12*/
-#define R0900_P1_VTH12 0xf534
-#define VTH12 REGx(R0900_P1_VTH12)
-#define F0900_P1_VTH12 0xf53400ff
-
-/*P1_VTH23*/
-#define R0900_P1_VTH23 0xf535
-#define VTH23 REGx(R0900_P1_VTH23)
-#define F0900_P1_VTH23 0xf53500ff
-
-/*P1_VTH34*/
-#define R0900_P1_VTH34 0xf536
-#define VTH34 REGx(R0900_P1_VTH34)
-#define F0900_P1_VTH34 0xf53600ff
-
-/*P1_VTH56*/
-#define R0900_P1_VTH56 0xf537
-#define VTH56 REGx(R0900_P1_VTH56)
-#define F0900_P1_VTH56 0xf53700ff
-
-/*P1_VTH67*/
-#define R0900_P1_VTH67 0xf538
-#define VTH67 REGx(R0900_P1_VTH67)
-#define F0900_P1_VTH67 0xf53800ff
-
-/*P1_VTH78*/
-#define R0900_P1_VTH78 0xf539
-#define VTH78 REGx(R0900_P1_VTH78)
-#define F0900_P1_VTH78 0xf53900ff
-
-/*P1_VITCURPUN*/
-#define R0900_P1_VITCURPUN 0xf53a
-#define VITCURPUN REGx(R0900_P1_VITCURPUN)
-#define F0900_P1_VIT_CURPUN 0xf53a001f
-#define VIT_CURPUN FLDx(F0900_P1_VIT_CURPUN)
-
-/*P1_VERROR*/
-#define R0900_P1_VERROR 0xf53b
-#define VERROR REGx(R0900_P1_VERROR)
-#define F0900_P1_REGERR_VIT 0xf53b00ff
-
-/*P1_PRVIT*/
-#define R0900_P1_PRVIT 0xf53c
-#define PRVIT REGx(R0900_P1_PRVIT)
-#define F0900_P1_DIS_VTHLOCK 0xf53c0040
-#define F0900_P1_E7_8VIT 0xf53c0020
-#define F0900_P1_E6_7VIT 0xf53c0010
-#define F0900_P1_E5_6VIT 0xf53c0008
-#define F0900_P1_E3_4VIT 0xf53c0004
-#define F0900_P1_E2_3VIT 0xf53c0002
-#define F0900_P1_E1_2VIT 0xf53c0001
-
-/*P1_VAVSRVIT*/
-#define R0900_P1_VAVSRVIT 0xf53d
-#define VAVSRVIT REGx(R0900_P1_VAVSRVIT)
-#define F0900_P1_AMVIT 0xf53d0080
-#define F0900_P1_FROZENVIT 0xf53d0040
-#define F0900_P1_SNVIT 0xf53d0030
-#define F0900_P1_TOVVIT 0xf53d000c
-#define F0900_P1_HYPVIT 0xf53d0003
-
-/*P1_VSTATUSVIT*/
-#define R0900_P1_VSTATUSVIT 0xf53e
-#define VSTATUSVIT REGx(R0900_P1_VSTATUSVIT)
-#define F0900_P1_PRFVIT 0xf53e0010
-#define PRFVIT FLDx(F0900_P1_PRFVIT)
-#define F0900_P1_LOCKEDVIT 0xf53e0008
-#define LOCKEDVIT FLDx(F0900_P1_LOCKEDVIT)
-
-/*P1_VTHINUSE*/
-#define R0900_P1_VTHINUSE 0xf53f
-#define VTHINUSE REGx(R0900_P1_VTHINUSE)
-#define F0900_P1_VIT_INUSE 0xf53f00ff
-
-/*P1_KDIV12*/
-#define R0900_P1_KDIV12 0xf540
-#define KDIV12 REGx(R0900_P1_KDIV12)
-#define F0900_P1_K_DIVIDER_12 0xf540007f
-
-/*P1_KDIV23*/
-#define R0900_P1_KDIV23 0xf541
-#define KDIV23 REGx(R0900_P1_KDIV23)
-#define F0900_P1_K_DIVIDER_23 0xf541007f
-
-/*P1_KDIV34*/
-#define R0900_P1_KDIV34 0xf542
-#define KDIV34 REGx(R0900_P1_KDIV34)
-#define F0900_P1_K_DIVIDER_34 0xf542007f
-
-/*P1_KDIV56*/
-#define R0900_P1_KDIV56 0xf543
-#define KDIV56 REGx(R0900_P1_KDIV56)
-#define F0900_P1_K_DIVIDER_56 0xf543007f
-
-/*P1_KDIV67*/
-#define R0900_P1_KDIV67 0xf544
-#define KDIV67 REGx(R0900_P1_KDIV67)
-#define F0900_P1_K_DIVIDER_67 0xf544007f
-
-/*P1_KDIV78*/
-#define R0900_P1_KDIV78 0xf545
-#define KDIV78 REGx(R0900_P1_KDIV78)
-#define F0900_P1_K_DIVIDER_78 0xf545007f
-
-/*P1_PDELCTRL1*/
-#define R0900_P1_PDELCTRL1 0xf550
-#define PDELCTRL1 REGx(R0900_P1_PDELCTRL1)
-#define F0900_P1_INV_MISMASK 0xf5500080
-#define F0900_P1_FILTER_EN 0xf5500020
-#define F0900_P1_EN_MIS00 0xf5500002
-#define F0900_P1_ALGOSWRST 0xf5500001
-#define ALGOSWRST FLDx(F0900_P1_ALGOSWRST)
-
-/*P1_PDELCTRL2*/
-#define R0900_P1_PDELCTRL2 0xf551
-#define PDELCTRL2 REGx(R0900_P1_PDELCTRL2)
-#define F0900_P1_RESET_UPKO_COUNT 0xf5510040
-#define RESET_UPKO_COUNT FLDx(F0900_P1_RESET_UPKO_COUNT)
-#define F0900_P1_FRAME_MODE 0xf5510002
-#define F0900_P1_NOBCHERRFLG_USE 0xf5510001
-
-/*P1_HYSTTHRESH*/
-#define R0900_P1_HYSTTHRESH 0xf554
-#define HYSTTHRESH REGx(R0900_P1_HYSTTHRESH)
-#define F0900_P1_UNLCK_THRESH 0xf55400f0
-#define F0900_P1_DELIN_LCK_THRESH 0xf554000f
-
-/*P1_ISIENTRY*/
-#define R0900_P1_ISIENTRY 0xf55e
-#define ISIENTRY REGx(R0900_P1_ISIENTRY)
-#define F0900_P1_ISI_ENTRY 0xf55e00ff
-
-/*P1_ISIBITENA*/
-#define R0900_P1_ISIBITENA 0xf55f
-#define ISIBITENA REGx(R0900_P1_ISIBITENA)
-#define F0900_P1_ISI_BIT_EN 0xf55f00ff
-
-/*P1_MATSTR1*/
-#define R0900_P1_MATSTR1 0xf560
-#define MATSTR1 REGx(R0900_P1_MATSTR1)
-#define F0900_P1_MATYPE_CURRENT1 0xf56000ff
-
-/*P1_MATSTR0*/
-#define R0900_P1_MATSTR0 0xf561
-#define MATSTR0 REGx(R0900_P1_MATSTR0)
-#define F0900_P1_MATYPE_CURRENT0 0xf56100ff
-
-/*P1_UPLSTR1*/
-#define R0900_P1_UPLSTR1 0xf562
-#define UPLSTR1 REGx(R0900_P1_UPLSTR1)
-#define F0900_P1_UPL_CURRENT1 0xf56200ff
-
-/*P1_UPLSTR0*/
-#define R0900_P1_UPLSTR0 0xf563
-#define UPLSTR0 REGx(R0900_P1_UPLSTR0)
-#define F0900_P1_UPL_CURRENT0 0xf56300ff
-
-/*P1_DFLSTR1*/
-#define R0900_P1_DFLSTR1 0xf564
-#define DFLSTR1 REGx(R0900_P1_DFLSTR1)
-#define F0900_P1_DFL_CURRENT1 0xf56400ff
-
-/*P1_DFLSTR0*/
-#define R0900_P1_DFLSTR0 0xf565
-#define DFLSTR0 REGx(R0900_P1_DFLSTR0)
-#define F0900_P1_DFL_CURRENT0 0xf56500ff
-
-/*P1_SYNCSTR*/
-#define R0900_P1_SYNCSTR 0xf566
-#define SYNCSTR REGx(R0900_P1_SYNCSTR)
-#define F0900_P1_SYNC_CURRENT 0xf56600ff
-
-/*P1_SYNCDSTR1*/
-#define R0900_P1_SYNCDSTR1 0xf567
-#define SYNCDSTR1 REGx(R0900_P1_SYNCDSTR1)
-#define F0900_P1_SYNCD_CURRENT1 0xf56700ff
-
-/*P1_SYNCDSTR0*/
-#define R0900_P1_SYNCDSTR0 0xf568
-#define SYNCDSTR0 REGx(R0900_P1_SYNCDSTR0)
-#define F0900_P1_SYNCD_CURRENT0 0xf56800ff
-
-/*P1_PDELSTATUS1*/
-#define R0900_P1_PDELSTATUS1 0xf569
-#define F0900_P1_PKTDELIN_DELOCK 0xf5690080
-#define F0900_P1_SYNCDUPDFL_BADDFL 0xf5690040
-#define F0900_P1_CONTINUOUS_STREAM 0xf5690020
-#define F0900_P1_UNACCEPTED_STREAM 0xf5690010
-#define F0900_P1_BCH_ERROR_FLAG 0xf5690008
-#define F0900_P1_PKTDELIN_LOCK 0xf5690002
-#define PKTDELIN_LOCK FLDx(F0900_P1_PKTDELIN_LOCK)
-#define F0900_P1_FIRST_LOCK 0xf5690001
-
-/*P1_PDELSTATUS2*/
-#define R0900_P1_PDELSTATUS2 0xf56a
-#define F0900_P1_FRAME_MODCOD 0xf56a007c
-#define F0900_P1_FRAME_TYPE 0xf56a0003
-
-/*P1_BBFCRCKO1*/
-#define R0900_P1_BBFCRCKO1 0xf56b
-#define BBFCRCKO1 REGx(R0900_P1_BBFCRCKO1)
-#define F0900_P1_BBHCRC_KOCNT1 0xf56b00ff
-
-/*P1_BBFCRCKO0*/
-#define R0900_P1_BBFCRCKO0 0xf56c
-#define BBFCRCKO0 REGx(R0900_P1_BBFCRCKO0)
-#define F0900_P1_BBHCRC_KOCNT0 0xf56c00ff
-
-/*P1_UPCRCKO1*/
-#define R0900_P1_UPCRCKO1 0xf56d
-#define UPCRCKO1 REGx(R0900_P1_UPCRCKO1)
-#define F0900_P1_PKTCRC_KOCNT1 0xf56d00ff
-
-/*P1_UPCRCKO0*/
-#define R0900_P1_UPCRCKO0 0xf56e
-#define UPCRCKO0 REGx(R0900_P1_UPCRCKO0)
-#define F0900_P1_PKTCRC_KOCNT0 0xf56e00ff
-
-/*P1_PDELCTRL3*/
-#define R0900_P1_PDELCTRL3 0xf56f
-#define PDELCTRL3 REGx(R0900_P1_PDELCTRL3)
-#define F0900_P1_PKTDEL_CONTFAIL 0xf56f0080
-#define F0900_P1_NOFIFO_BCHERR 0xf56f0020
-
-/*P1_TSSTATEM*/
-#define R0900_P1_TSSTATEM 0xf570
-#define TSSTATEM REGx(R0900_P1_TSSTATEM)
-#define F0900_P1_TSDIL_ON 0xf5700080
-#define F0900_P1_TSRS_ON 0xf5700020
-#define F0900_P1_TSDESCRAMB_ON 0xf5700010
-#define F0900_P1_TSFRAME_MODE 0xf5700008
-#define F0900_P1_TS_DISABLE 0xf5700004
-#define F0900_P1_TSOUT_NOSYNC 0xf5700001
-
-/*P1_TSCFGH*/
-#define R0900_P1_TSCFGH 0xf572
-#define TSCFGH REGx(R0900_P1_TSCFGH)
-#define F0900_P1_TSFIFO_DVBCI 0xf5720080
-#define F0900_P1_TSFIFO_SERIAL 0xf5720040
-#define F0900_P1_TSFIFO_TEIUPDATE 0xf5720020
-#define F0900_P1_TSFIFO_DUTY50 0xf5720010
-#define F0900_P1_TSFIFO_HSGNLOUT 0xf5720008
-#define F0900_P1_TSFIFO_ERRMODE 0xf5720006
-#define F0900_P1_RST_HWARE 0xf5720001
-#define RST_HWARE FLDx(F0900_P1_RST_HWARE)
-
-/*P1_TSCFGM*/
-#define R0900_P1_TSCFGM 0xf573
-#define TSCFGM REGx(R0900_P1_TSCFGM)
-#define F0900_P1_TSFIFO_MANSPEED 0xf57300c0
-#define F0900_P1_TSFIFO_PERMDATA 0xf5730020
-#define F0900_P1_TSFIFO_DPUNACT 0xf5730002
-#define F0900_P1_TSFIFO_INVDATA 0xf5730001
-
-/*P1_TSCFGL*/
-#define R0900_P1_TSCFGL 0xf574
-#define TSCFGL REGx(R0900_P1_TSCFGL)
-#define F0900_P1_TSFIFO_BCLKDEL1CK 0xf57400c0
-#define F0900_P1_BCHERROR_MODE 0xf5740030
-#define F0900_P1_TSFIFO_NSGNL2DATA 0xf5740008
-#define F0900_P1_TSFIFO_EMBINDVB 0xf5740004
-#define F0900_P1_TSFIFO_BITSPEED 0xf5740003
-
-/*P1_TSINSDELH*/
-#define R0900_P1_TSINSDELH 0xf576
-#define TSINSDELH REGx(R0900_P1_TSINSDELH)
-#define F0900_P1_TSDEL_SYNCBYTE 0xf5760080
-#define F0900_P1_TSDEL_XXHEADER 0xf5760040
-#define F0900_P1_TSDEL_BBHEADER 0xf5760020
-#define F0900_P1_TSDEL_DATAFIELD 0xf5760010
-#define F0900_P1_TSINSDEL_ISCR 0xf5760008
-#define F0900_P1_TSINSDEL_NPD 0xf5760004
-#define F0900_P1_TSINSDEL_RSPARITY 0xf5760002
-#define F0900_P1_TSINSDEL_CRC8 0xf5760001
-
-/*P1_TSDIVN*/
-#define R0900_P1_TSDIVN 0xf579
-#define TSDIVN REGx(R0900_P1_TSDIVN)
-#define F0900_P1_TSFIFO_SPEEDMODE 0xf57900c0
-
-/*P1_TSCFG4*/
-#define R0900_P1_TSCFG4 0xf57a
-#define TSCFG4 REGx(R0900_P1_TSCFG4)
-#define F0900_P1_TSFIFO_TSSPEEDMODE 0xf57a00c0
-
-/*P1_TSSPEED*/
-#define R0900_P1_TSSPEED 0xf580
-#define TSSPEED REGx(R0900_P1_TSSPEED)
-#define F0900_P1_TSFIFO_OUTSPEED 0xf58000ff
-
-/*P1_TSSTATUS*/
-#define R0900_P1_TSSTATUS 0xf581
-#define TSSTATUS REGx(R0900_P1_TSSTATUS)
-#define F0900_P1_TSFIFO_LINEOK 0xf5810080
-#define TSFIFO_LINEOK FLDx(F0900_P1_TSFIFO_LINEOK)
-#define F0900_P1_TSFIFO_ERROR 0xf5810040
-#define F0900_P1_DIL_READY 0xf5810001
-
-/*P1_TSSTATUS2*/
-#define R0900_P1_TSSTATUS2 0xf582
-#define TSSTATUS2 REGx(R0900_P1_TSSTATUS2)
-#define F0900_P1_TSFIFO_DEMODSEL 0xf5820080
-#define F0900_P1_TSFIFOSPEED_STORE 0xf5820040
-#define F0900_P1_DILXX_RESET 0xf5820020
-#define F0900_P1_TSSERIAL_IMPOS 0xf5820010
-#define F0900_P1_SCRAMBDETECT 0xf5820002
-
-/*P1_TSBITRATE1*/
-#define R0900_P1_TSBITRATE1 0xf583
-#define TSBITRATE1 REGx(R0900_P1_TSBITRATE1)
-#define F0900_P1_TSFIFO_BITRATE1 0xf58300ff
-
-/*P1_TSBITRATE0*/
-#define R0900_P1_TSBITRATE0 0xf584
-#define TSBITRATE0 REGx(R0900_P1_TSBITRATE0)
-#define F0900_P1_TSFIFO_BITRATE0 0xf58400ff
-
-/*P1_ERRCTRL1*/
-#define R0900_P1_ERRCTRL1 0xf598
-#define ERRCTRL1 REGx(R0900_P1_ERRCTRL1)
-#define F0900_P1_ERR_SOURCE1 0xf59800f0
-#define F0900_P1_NUM_EVENT1 0xf5980007
-
-/*P1_ERRCNT12*/
-#define R0900_P1_ERRCNT12 0xf599
-#define ERRCNT12 REGx(R0900_P1_ERRCNT12)
-#define F0900_P1_ERRCNT1_OLDVALUE 0xf5990080
-#define F0900_P1_ERR_CNT12 0xf599007f
-#define ERR_CNT12 FLDx(F0900_P1_ERR_CNT12)
-
-/*P1_ERRCNT11*/
-#define R0900_P1_ERRCNT11 0xf59a
-#define ERRCNT11 REGx(R0900_P1_ERRCNT11)
-#define F0900_P1_ERR_CNT11 0xf59a00ff
-#define ERR_CNT11 FLDx(F0900_P1_ERR_CNT11)
-
-/*P1_ERRCNT10*/
-#define R0900_P1_ERRCNT10 0xf59b
-#define ERRCNT10 REGx(R0900_P1_ERRCNT10)
-#define F0900_P1_ERR_CNT10 0xf59b00ff
-#define ERR_CNT10 FLDx(F0900_P1_ERR_CNT10)
-
-/*P1_ERRCTRL2*/
-#define R0900_P1_ERRCTRL2 0xf59c
-#define ERRCTRL2 REGx(R0900_P1_ERRCTRL2)
-#define F0900_P1_ERR_SOURCE2 0xf59c00f0
-#define F0900_P1_NUM_EVENT2 0xf59c0007
-
-/*P1_ERRCNT22*/
-#define R0900_P1_ERRCNT22 0xf59d
-#define ERRCNT22 REGx(R0900_P1_ERRCNT22)
-#define F0900_P1_ERRCNT2_OLDVALUE 0xf59d0080
-#define F0900_P1_ERR_CNT22 0xf59d007f
-#define ERR_CNT22 FLDx(F0900_P1_ERR_CNT22)
-
-/*P1_ERRCNT21*/
-#define R0900_P1_ERRCNT21 0xf59e
-#define ERRCNT21 REGx(R0900_P1_ERRCNT21)
-#define F0900_P1_ERR_CNT21 0xf59e00ff
-#define ERR_CNT21 FLDx(F0900_P1_ERR_CNT21)
-
-/*P1_ERRCNT20*/
-#define R0900_P1_ERRCNT20 0xf59f
-#define ERRCNT20 REGx(R0900_P1_ERRCNT20)
-#define F0900_P1_ERR_CNT20 0xf59f00ff
-#define ERR_CNT20 FLDx(F0900_P1_ERR_CNT20)
-
-/*P1_FECSPY*/
-#define R0900_P1_FECSPY 0xf5a0
-#define FECSPY REGx(R0900_P1_FECSPY)
-#define F0900_P1_SPY_ENABLE 0xf5a00080
-#define F0900_P1_NO_SYNCBYTE 0xf5a00040
-#define F0900_P1_SERIAL_MODE 0xf5a00020
-#define F0900_P1_UNUSUAL_PACKET 0xf5a00010
-#define F0900_P1_BERMETER_DATAMODE 0xf5a00008
-#define F0900_P1_BERMETER_LMODE 0xf5a00002
-#define F0900_P1_BERMETER_RESET 0xf5a00001
-
-/*P1_FSPYCFG*/
-#define R0900_P1_FSPYCFG 0xf5a1
-#define FSPYCFG REGx(R0900_P1_FSPYCFG)
-#define F0900_P1_FECSPY_INPUT 0xf5a100c0
-#define F0900_P1_RST_ON_ERROR 0xf5a10020
-#define F0900_P1_ONE_SHOT 0xf5a10010
-#define F0900_P1_I2C_MODE 0xf5a1000c
-#define F0900_P1_SPY_HYSTERESIS 0xf5a10003
-
-/*P1_FSPYDATA*/
-#define R0900_P1_FSPYDATA 0xf5a2
-#define FSPYDATA REGx(R0900_P1_FSPYDATA)
-#define F0900_P1_SPY_STUFFING 0xf5a20080
-#define F0900_P1_SPY_CNULLPKT 0xf5a20020
-#define F0900_P1_SPY_OUTDATA_MODE 0xf5a2001f
-
-/*P1_FSPYOUT*/
-#define R0900_P1_FSPYOUT 0xf5a3
-#define FSPYOUT REGx(R0900_P1_FSPYOUT)
-#define F0900_P1_FSPY_DIRECT 0xf5a30080
-#define F0900_P1_STUFF_MODE 0xf5a30007
-
-/*P1_FSTATUS*/
-#define R0900_P1_FSTATUS 0xf5a4
-#define FSTATUS REGx(R0900_P1_FSTATUS)
-#define F0900_P1_SPY_ENDSIM 0xf5a40080
-#define F0900_P1_VALID_SIM 0xf5a40040
-#define F0900_P1_FOUND_SIGNAL 0xf5a40020
-#define F0900_P1_DSS_SYNCBYTE 0xf5a40010
-#define F0900_P1_RESULT_STATE 0xf5a4000f
-
-/*P1_FBERCPT4*/
-#define R0900_P1_FBERCPT4 0xf5a8
-#define FBERCPT4 REGx(R0900_P1_FBERCPT4)
-#define F0900_P1_FBERMETER_CPT4 0xf5a800ff
-
-/*P1_FBERCPT3*/
-#define R0900_P1_FBERCPT3 0xf5a9
-#define FBERCPT3 REGx(R0900_P1_FBERCPT3)
-#define F0900_P1_FBERMETER_CPT3 0xf5a900ff
-
-/*P1_FBERCPT2*/
-#define R0900_P1_FBERCPT2 0xf5aa
-#define FBERCPT2 REGx(R0900_P1_FBERCPT2)
-#define F0900_P1_FBERMETER_CPT2 0xf5aa00ff
-
-/*P1_FBERCPT1*/
-#define R0900_P1_FBERCPT1 0xf5ab
-#define FBERCPT1 REGx(R0900_P1_FBERCPT1)
-#define F0900_P1_FBERMETER_CPT1 0xf5ab00ff
-
-/*P1_FBERCPT0*/
-#define R0900_P1_FBERCPT0 0xf5ac
-#define FBERCPT0 REGx(R0900_P1_FBERCPT0)
-#define F0900_P1_FBERMETER_CPT0 0xf5ac00ff
-
-/*P1_FBERERR2*/
-#define R0900_P1_FBERERR2 0xf5ad
-#define FBERERR2 REGx(R0900_P1_FBERERR2)
-#define F0900_P1_FBERMETER_ERR2 0xf5ad00ff
-
-/*P1_FBERERR1*/
-#define R0900_P1_FBERERR1 0xf5ae
-#define FBERERR1 REGx(R0900_P1_FBERERR1)
-#define F0900_P1_FBERMETER_ERR1 0xf5ae00ff
-
-/*P1_FBERERR0*/
-#define R0900_P1_FBERERR0 0xf5af
-#define FBERERR0 REGx(R0900_P1_FBERERR0)
-#define F0900_P1_FBERMETER_ERR0 0xf5af00ff
-
-/*P1_FSPYBER*/
-#define R0900_P1_FSPYBER 0xf5b2
-#define FSPYBER REGx(R0900_P1_FSPYBER)
-#define F0900_P1_FSPYBER_SYNCBYTE 0xf5b20010
-#define F0900_P1_FSPYBER_UNSYNC 0xf5b20008
-#define F0900_P1_FSPYBER_CTIME 0xf5b20007
-
-/*RCCFG2*/
-#define R0900_RCCFG2 0xf600
-
-/*TSGENERAL*/
-#define R0900_TSGENERAL 0xf630
-#define F0900_TSFIFO_DISTS2PAR 0xf6300040
-#define F0900_MUXSTREAM_OUTMODE 0xf6300008
-#define F0900_TSFIFO_PERMPARAL 0xf6300006
-
-/*TSGENERAL1X*/
-#define R0900_TSGENERAL1X 0xf670
-
-/*NBITER_NF4*/
-#define R0900_NBITER_NF4 0xfa03
-#define F0900_NBITER_NF_QP_1_2 0xfa0300ff
-
-/*NBITER_NF5*/
-#define R0900_NBITER_NF5 0xfa04
-#define F0900_NBITER_NF_QP_3_5 0xfa0400ff
-
-/*NBITER_NF6*/
-#define R0900_NBITER_NF6 0xfa05
-#define F0900_NBITER_NF_QP_2_3 0xfa0500ff
-
-/*NBITER_NF7*/
-#define R0900_NBITER_NF7 0xfa06
-#define F0900_NBITER_NF_QP_3_4 0xfa0600ff
-
-/*NBITER_NF8*/
-#define R0900_NBITER_NF8 0xfa07
-#define F0900_NBITER_NF_QP_4_5 0xfa0700ff
-
-/*NBITER_NF9*/
-#define R0900_NBITER_NF9 0xfa08
-#define F0900_NBITER_NF_QP_5_6 0xfa0800ff
-
-/*NBITER_NF10*/
-#define R0900_NBITER_NF10 0xfa09
-#define F0900_NBITER_NF_QP_8_9 0xfa0900ff
-
-/*NBITER_NF11*/
-#define R0900_NBITER_NF11 0xfa0a
-#define F0900_NBITER_NF_QP_9_10 0xfa0a00ff
-
-/*NBITER_NF12*/
-#define R0900_NBITER_NF12 0xfa0b
-#define F0900_NBITER_NF_8P_3_5 0xfa0b00ff
-
-/*NBITER_NF13*/
-#define R0900_NBITER_NF13 0xfa0c
-#define F0900_NBITER_NF_8P_2_3 0xfa0c00ff
-
-/*NBITER_NF14*/
-#define R0900_NBITER_NF14 0xfa0d
-#define F0900_NBITER_NF_8P_3_4 0xfa0d00ff
-
-/*NBITER_NF15*/
-#define R0900_NBITER_NF15 0xfa0e
-#define F0900_NBITER_NF_8P_5_6 0xfa0e00ff
-
-/*NBITER_NF16*/
-#define R0900_NBITER_NF16 0xfa0f
-#define F0900_NBITER_NF_8P_8_9 0xfa0f00ff
-
-/*NBITER_NF17*/
-#define R0900_NBITER_NF17 0xfa10
-#define F0900_NBITER_NF_8P_9_10 0xfa1000ff
-
-/*NBITERNOERR*/
-#define R0900_NBITERNOERR 0xfa3f
-#define F0900_NBITER_STOP_CRIT 0xfa3f000f
-
-/*GAINLLR_NF4*/
-#define R0900_GAINLLR_NF4 0xfa43
-#define F0900_GAINLLR_NF_QP_1_2 0xfa43007f
-
-/*GAINLLR_NF5*/
-#define R0900_GAINLLR_NF5 0xfa44
-#define F0900_GAINLLR_NF_QP_3_5 0xfa44007f
-
-/*GAINLLR_NF6*/
-#define R0900_GAINLLR_NF6 0xfa45
-#define F0900_GAINLLR_NF_QP_2_3 0xfa45007f
-
-/*GAINLLR_NF7*/
-#define R0900_GAINLLR_NF7 0xfa46
-#define F0900_GAINLLR_NF_QP_3_4 0xfa46007f
-
-/*GAINLLR_NF8*/
-#define R0900_GAINLLR_NF8 0xfa47
-#define F0900_GAINLLR_NF_QP_4_5 0xfa47007f
-
-/*GAINLLR_NF9*/
-#define R0900_GAINLLR_NF9 0xfa48
-#define F0900_GAINLLR_NF_QP_5_6 0xfa48007f
-
-/*GAINLLR_NF10*/
-#define R0900_GAINLLR_NF10 0xfa49
-#define F0900_GAINLLR_NF_QP_8_9 0xfa49007f
-
-/*GAINLLR_NF11*/
-#define R0900_GAINLLR_NF11 0xfa4a
-#define F0900_GAINLLR_NF_QP_9_10 0xfa4a007f
-
-/*GAINLLR_NF12*/
-#define R0900_GAINLLR_NF12 0xfa4b
-#define F0900_GAINLLR_NF_8P_3_5 0xfa4b007f
-
-/*GAINLLR_NF13*/
-#define R0900_GAINLLR_NF13 0xfa4c
-#define F0900_GAINLLR_NF_8P_2_3 0xfa4c007f
-
-/*GAINLLR_NF14*/
-#define R0900_GAINLLR_NF14 0xfa4d
-#define F0900_GAINLLR_NF_8P_3_4 0xfa4d007f
-
-/*GAINLLR_NF15*/
-#define R0900_GAINLLR_NF15 0xfa4e
-#define F0900_GAINLLR_NF_8P_5_6 0xfa4e007f
-
-/*GAINLLR_NF16*/
-#define R0900_GAINLLR_NF16 0xfa4f
-#define F0900_GAINLLR_NF_8P_8_9 0xfa4f007f
-
-/*GAINLLR_NF17*/
-#define R0900_GAINLLR_NF17 0xfa50
-#define F0900_GAINLLR_NF_8P_9_10 0xfa50007f
-
-/*CFGEXT*/
-#define R0900_CFGEXT 0xfa80
-#define F0900_STAGMODE 0xfa800080
-#define F0900_BYPBCH 0xfa800040
-#define F0900_BYPLDPC 0xfa800020
-#define F0900_LDPCMODE 0xfa800010
-#define F0900_INVLLRSIGN 0xfa800008
-#define F0900_SHORTMULT 0xfa800004
-#define F0900_EXTERNTX 0xfa800001
-
-/*GENCFG*/
-#define R0900_GENCFG 0xfa86
-#define F0900_BROADCAST 0xfa860010
-#define F0900_PRIORITY 0xfa860002
-#define F0900_DDEMOD 0xfa860001
-
-/*LDPCERR1*/
-#define R0900_LDPCERR1 0xfa96
-#define F0900_LDPC_ERRORS_COUNTER1 0xfa9600ff
-
-/*LDPCERR0*/
-#define R0900_LDPCERR0 0xfa97
-#define F0900_LDPC_ERRORS_COUNTER0 0xfa9700ff
-
-/*BCHERR*/
-#define R0900_BCHERR 0xfa98
-#define F0900_ERRORFLAG 0xfa980010
-#define F0900_BCH_ERRORS_COUNTER 0xfa98000f
-
-/*TSTRES0*/
-#define R0900_TSTRES0 0xff11
-#define F0900_FRESFEC 0xff110080
-
-/*P2_TCTL4*/
-#define R0900_P2_TCTL4 0xff28
-#define F0900_P2_PN4_SELECT 0xff280020
-
-/*P1_TCTL4*/
-#define R0900_P1_TCTL4 0xff48
-#define TCTL4 shiftx(R0900_P1_TCTL4, demod, 0x20)
-#define F0900_P1_PN4_SELECT 0xff480020
-
-/*P2_TSTDISRX*/
-#define R0900_P2_TSTDISRX 0xff65
-#define F0900_P2_PIN_SELECT1 0xff650008
-
-/*P1_TSTDISRX*/
-#define R0900_P1_TSTDISRX 0xff67
-#define TSTDISRX shiftx(R0900_P1_TSTDISRX, demod, 2)
-#define F0900_P1_PIN_SELECT1 0xff670008
-#define PIN_SELECT1 shiftx(F0900_P1_PIN_SELECT1, demod, 0x20000)
-
-#define STV0900_NBREGS 723
-#define STV0900_NBFIELDS 1420
-
-#endif
-
diff --git a/drivers/media/dvb/frontends/stv0900_sw.c b/drivers/media/dvb/frontends/stv0900_sw.c
deleted file mode 100644
index 4af2078..0000000
--- a/drivers/media/dvb/frontends/stv0900_sw.c
+++ /dev/null
@@ -1,2032 +0,0 @@
-/*
- * stv0900_sw.c
- *
- * Driver for ST STV0900 satellite demodulator IC.
- *
- * Copyright (C) ST Microelectronics.
- * Copyright (C) 2009 NetUP Inc.
- * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "stv0900.h"
-#include "stv0900_reg.h"
-#include "stv0900_priv.h"
-
-s32 shiftx(s32 x, int demod, s32 shift)
-{
-	if (demod == 1)
-		return x - shift;
-
-	return x;
-}
-
-int stv0900_check_signal_presence(struct stv0900_internal *intp,
-					enum fe_stv0900_demod_num demod)
-{
-	s32	carr_offset,
-		agc2_integr,
-		max_carrier;
-
-	int no_signal = FALSE;
-
-	carr_offset = (stv0900_read_reg(intp, CFR2) << 8)
-					| stv0900_read_reg(intp, CFR1);
-	carr_offset = ge2comp(carr_offset, 16);
-	agc2_integr = (stv0900_read_reg(intp, AGC2I1) << 8)
-					| stv0900_read_reg(intp, AGC2I0);
-	max_carrier = intp->srch_range[demod] / 1000;
-
-	max_carrier += (max_carrier / 10);
-	max_carrier = 65536 * (max_carrier / 2);
-	max_carrier /= intp->mclk / 1000;
-	if (max_carrier > 0x4000)
-		max_carrier = 0x4000;
-
-	if ((agc2_integr > 0x2000)
-			|| (carr_offset > (2 * max_carrier))
-			|| (carr_offset < (-2 * max_carrier)))
-		no_signal = TRUE;
-
-	return no_signal;
-}
-
-static void stv0900_get_sw_loop_params(struct stv0900_internal *intp,
-				s32 *frequency_inc, s32 *sw_timeout,
-				s32 *steps,
-				enum fe_stv0900_demod_num demod)
-{
-	s32 timeout, freq_inc, max_steps, srate, max_carrier;
-
-	enum fe_stv0900_search_standard	standard;
-
-	srate = intp->symbol_rate[demod];
-	max_carrier = intp->srch_range[demod] / 1000;
-	max_carrier += max_carrier / 10;
-	standard = intp->srch_standard[demod];
-
-	max_carrier = 65536 * (max_carrier / 2);
-	max_carrier /= intp->mclk / 1000;
-
-	if (max_carrier > 0x4000)
-		max_carrier = 0x4000;
-
-	freq_inc = srate;
-	freq_inc /= intp->mclk >> 10;
-	freq_inc = freq_inc << 6;
-
-	switch (standard) {
-	case STV0900_SEARCH_DVBS1:
-	case STV0900_SEARCH_DSS:
-		freq_inc *= 3;
-		timeout = 20;
-		break;
-	case STV0900_SEARCH_DVBS2:
-		freq_inc *= 4;
-		timeout = 25;
-		break;
-	case STV0900_AUTO_SEARCH:
-	default:
-		freq_inc *= 3;
-		timeout = 25;
-		break;
-	}
-
-	freq_inc /= 100;
-
-	if ((freq_inc > max_carrier) || (freq_inc < 0))
-		freq_inc = max_carrier / 2;
-
-	timeout *= 27500;
-
-	if (srate > 0)
-		timeout /= srate / 1000;
-
-	if ((timeout > 100) || (timeout < 0))
-		timeout = 100;
-
-	max_steps = (max_carrier / freq_inc) + 1;
-
-	if ((max_steps > 100) || (max_steps < 0)) {
-		max_steps =  100;
-		freq_inc = max_carrier / max_steps;
-	}
-
-	*frequency_inc = freq_inc;
-	*sw_timeout = timeout;
-	*steps = max_steps;
-
-}
-
-static int stv0900_search_carr_sw_loop(struct stv0900_internal *intp,
-				s32 FreqIncr, s32 Timeout, int zigzag,
-				s32 MaxStep, enum fe_stv0900_demod_num demod)
-{
-	int	no_signal,
-		lock = FALSE;
-	s32	stepCpt,
-		freqOffset,
-		max_carrier;
-
-	max_carrier = intp->srch_range[demod] / 1000;
-	max_carrier += (max_carrier / 10);
-
-	max_carrier = 65536 * (max_carrier / 2);
-	max_carrier /= intp->mclk / 1000;
-
-	if (max_carrier > 0x4000)
-		max_carrier = 0x4000;
-
-	if (zigzag == TRUE)
-		freqOffset = 0;
-	else
-		freqOffset = -max_carrier + FreqIncr;
-
-	stepCpt = 0;
-
-	do {
-		stv0900_write_reg(intp, DMDISTATE, 0x1c);
-		stv0900_write_reg(intp, CFRINIT1, (freqOffset / 256) & 0xff);
-		stv0900_write_reg(intp, CFRINIT0, freqOffset & 0xff);
-		stv0900_write_reg(intp, DMDISTATE, 0x18);
-		stv0900_write_bits(intp, ALGOSWRST, 1);
-
-		if (intp->chip_id == 0x12) {
-			stv0900_write_bits(intp, RST_HWARE, 1);
-			stv0900_write_bits(intp, RST_HWARE, 0);
-		}
-
-		if (zigzag == TRUE) {
-			if (freqOffset >= 0)
-				freqOffset = -freqOffset - 2 * FreqIncr;
-			else
-				freqOffset = -freqOffset;
-		} else
-			freqOffset += + 2 * FreqIncr;
-
-		stepCpt++;
-		lock = stv0900_get_demod_lock(intp, demod, Timeout);
-		no_signal = stv0900_check_signal_presence(intp, demod);
-
-	} while ((lock == FALSE)
-			&& (no_signal == FALSE)
-			&& ((freqOffset - FreqIncr) <  max_carrier)
-			&& ((freqOffset + FreqIncr) > -max_carrier)
-			&& (stepCpt < MaxStep));
-
-	stv0900_write_bits(intp, ALGOSWRST, 0);
-
-	return lock;
-}
-
-static int stv0900_sw_algo(struct stv0900_internal *intp,
-				enum fe_stv0900_demod_num demod)
-{
-	int	lock = FALSE,
-		no_signal,
-		zigzag;
-	s32	s2fw,
-		fqc_inc,
-		sft_stp_tout,
-		trial_cntr,
-		max_steps;
-
-	stv0900_get_sw_loop_params(intp, &fqc_inc, &sft_stp_tout,
-					&max_steps, demod);
-	switch (intp->srch_standard[demod]) {
-	case STV0900_SEARCH_DVBS1:
-	case STV0900_SEARCH_DSS:
-		if (intp->chip_id >= 0x20)
-			stv0900_write_reg(intp, CARFREQ, 0x3b);
-		else
-			stv0900_write_reg(intp, CARFREQ, 0xef);
-
-		stv0900_write_reg(intp, DMDCFGMD, 0x49);
-		zigzag = FALSE;
-		break;
-	case STV0900_SEARCH_DVBS2:
-		if (intp->chip_id >= 0x20)
-			stv0900_write_reg(intp, CORRELABS, 0x79);
-		else
-			stv0900_write_reg(intp, CORRELABS, 0x68);
-
-		stv0900_write_reg(intp, DMDCFGMD, 0x89);
-
-		zigzag = TRUE;
-		break;
-	case STV0900_AUTO_SEARCH:
-	default:
-		if (intp->chip_id >= 0x20) {
-			stv0900_write_reg(intp, CARFREQ, 0x3b);
-			stv0900_write_reg(intp, CORRELABS, 0x79);
-		} else {
-			stv0900_write_reg(intp, CARFREQ, 0xef);
-			stv0900_write_reg(intp, CORRELABS, 0x68);
-		}
-
-		stv0900_write_reg(intp, DMDCFGMD, 0xc9);
-		zigzag = FALSE;
-		break;
-	}
-
-	trial_cntr = 0;
-	do {
-		lock = stv0900_search_carr_sw_loop(intp,
-						fqc_inc,
-						sft_stp_tout,
-						zigzag,
-						max_steps,
-						demod);
-		no_signal = stv0900_check_signal_presence(intp, demod);
-		trial_cntr++;
-		if ((lock == TRUE)
-				|| (no_signal == TRUE)
-				|| (trial_cntr == 2)) {
-
-			if (intp->chip_id >= 0x20) {
-				stv0900_write_reg(intp, CARFREQ, 0x49);
-				stv0900_write_reg(intp, CORRELABS, 0x9e);
-			} else {
-				stv0900_write_reg(intp, CARFREQ, 0xed);
-				stv0900_write_reg(intp, CORRELABS, 0x88);
-			}
-
-			if ((stv0900_get_bits(intp, HEADER_MODE) ==
-						STV0900_DVBS2_FOUND) &&
-							(lock == TRUE)) {
-				msleep(sft_stp_tout);
-				s2fw = stv0900_get_bits(intp, FLYWHEEL_CPT);
-
-				if (s2fw < 0xd) {
-					msleep(sft_stp_tout);
-					s2fw = stv0900_get_bits(intp,
-								FLYWHEEL_CPT);
-				}
-
-				if (s2fw < 0xd) {
-					lock = FALSE;
-
-					if (trial_cntr < 2) {
-						if (intp->chip_id >= 0x20)
-							stv0900_write_reg(intp,
-								CORRELABS,
-								0x79);
-						else
-							stv0900_write_reg(intp,
-								CORRELABS,
-								0x68);
-
-						stv0900_write_reg(intp,
-								DMDCFGMD,
-								0x89);
-					}
-				}
-			}
-		}
-
-	} while ((lock == FALSE)
-		&& (trial_cntr < 2)
-		&& (no_signal == FALSE));
-
-	return lock;
-}
-
-static u32 stv0900_get_symbol_rate(struct stv0900_internal *intp,
-					u32 mclk,
-					enum fe_stv0900_demod_num demod)
-{
-	s32	rem1, rem2, intval1, intval2, srate;
-
-	srate = (stv0900_get_bits(intp, SYMB_FREQ3) << 24) +
-		(stv0900_get_bits(intp, SYMB_FREQ2) << 16) +
-		(stv0900_get_bits(intp, SYMB_FREQ1) << 8) +
-		(stv0900_get_bits(intp, SYMB_FREQ0));
-	dprintk("lock: srate=%d r0=0x%x r1=0x%x r2=0x%x r3=0x%x \n",
-		srate, stv0900_get_bits(intp, SYMB_FREQ0),
-		stv0900_get_bits(intp, SYMB_FREQ1),
-		stv0900_get_bits(intp, SYMB_FREQ2),
-		stv0900_get_bits(intp, SYMB_FREQ3));
-
-	intval1 = (mclk) >> 16;
-	intval2 = (srate) >> 16;
-
-	rem1 = (mclk) % 0x10000;
-	rem2 = (srate) % 0x10000;
-	srate =	(intval1 * intval2) +
-		((intval1 * rem2) >> 16) +
-		((intval2 * rem1) >> 16);
-
-	return srate;
-}
-
-static void stv0900_set_symbol_rate(struct stv0900_internal *intp,
-					u32 mclk, u32 srate,
-					enum fe_stv0900_demod_num demod)
-{
-	u32 symb;
-
-	dprintk("%s: Mclk %d, SR %d, Dmd %d\n", __func__, mclk,
-							srate, demod);
-
-	if (srate > 60000000) {
-		symb = srate << 4;
-		symb /= (mclk >> 12);
-	} else if (srate > 6000000) {
-		symb = srate << 6;
-		symb /= (mclk >> 10);
-	} else {
-		symb = srate << 9;
-		symb /= (mclk >> 7);
-	}
-
-	stv0900_write_reg(intp, SFRINIT1, (symb >> 8) & 0x7f);
-	stv0900_write_reg(intp, SFRINIT1 + 1, (symb & 0xff));
-}
-
-static void stv0900_set_max_symbol_rate(struct stv0900_internal *intp,
-					u32 mclk, u32 srate,
-					enum fe_stv0900_demod_num demod)
-{
-	u32 symb;
-
-	srate = 105 * (srate / 100);
-
-	if (srate > 60000000) {
-		symb = srate << 4;
-		symb /= (mclk >> 12);
-	} else if (srate > 6000000) {
-		symb = srate << 6;
-		symb /= (mclk >> 10);
-	} else {
-		symb = srate << 9;
-		symb /= (mclk >> 7);
-	}
-
-	if (symb < 0x7fff) {
-		stv0900_write_reg(intp, SFRUP1, (symb >> 8) & 0x7f);
-		stv0900_write_reg(intp, SFRUP1 + 1, (symb & 0xff));
-	} else {
-		stv0900_write_reg(intp, SFRUP1, 0x7f);
-		stv0900_write_reg(intp, SFRUP1 + 1, 0xff);
-	}
-}
-
-static void stv0900_set_min_symbol_rate(struct stv0900_internal *intp,
-					u32 mclk, u32 srate,
-					enum fe_stv0900_demod_num demod)
-{
-	u32	symb;
-
-	srate = 95 * (srate / 100);
-	if (srate > 60000000) {
-		symb = srate << 4;
-		symb /= (mclk >> 12);
-
-	} else if (srate > 6000000) {
-		symb = srate << 6;
-		symb /= (mclk >> 10);
-
-	} else {
-		symb = srate << 9;
-		symb /= (mclk >> 7);
-	}
-
-	stv0900_write_reg(intp, SFRLOW1, (symb >> 8) & 0xff);
-	stv0900_write_reg(intp, SFRLOW1 + 1, (symb & 0xff));
-}
-
-static s32 stv0900_get_timing_offst(struct stv0900_internal *intp,
-					u32 srate,
-					enum fe_stv0900_demod_num demod)
-{
-	s32 timingoffset;
-
-
-	timingoffset = (stv0900_read_reg(intp, TMGREG2) << 16) +
-		       (stv0900_read_reg(intp, TMGREG2 + 1) << 8) +
-		       (stv0900_read_reg(intp, TMGREG2 + 2));
-
-	timingoffset = ge2comp(timingoffset, 24);
-
-
-	if (timingoffset == 0)
-		timingoffset = 1;
-
-	timingoffset = ((s32)srate * 10) / ((s32)0x1000000 / timingoffset);
-	timingoffset /= 320;
-
-	return timingoffset;
-}
-
-static void stv0900_set_dvbs2_rolloff(struct stv0900_internal *intp,
-					enum fe_stv0900_demod_num demod)
-{
-	s32 rolloff;
-
-	if (intp->chip_id == 0x10) {
-		stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1);
-		rolloff = stv0900_read_reg(intp, MATSTR1) & 0x03;
-		stv0900_write_bits(intp, ROLLOFF_CONTROL, rolloff);
-	} else if (intp->chip_id <= 0x20)
-		stv0900_write_bits(intp, MANUALSX_ROLLOFF, 0);
-	else /* cut 3.0 */
-		stv0900_write_bits(intp, MANUALS2_ROLLOFF, 0);
-}
-
-static u32 stv0900_carrier_width(u32 srate, enum fe_stv0900_rolloff ro)
-{
-	u32 rolloff;
-
-	switch (ro) {
-	case STV0900_20:
-		rolloff = 20;
-		break;
-	case STV0900_25:
-		rolloff = 25;
-		break;
-	case STV0900_35:
-	default:
-		rolloff = 35;
-		break;
-	}
-
-	return srate  + (srate * rolloff) / 100;
-}
-
-static int stv0900_check_timing_lock(struct stv0900_internal *intp,
-				enum fe_stv0900_demod_num demod)
-{
-	int timingLock = FALSE;
-	s32	i,
-		timingcpt = 0;
-	u8	car_freq,
-		tmg_th_high,
-		tmg_th_low;
-
-	car_freq = stv0900_read_reg(intp, CARFREQ);
-	tmg_th_high = stv0900_read_reg(intp, TMGTHRISE);
-	tmg_th_low = stv0900_read_reg(intp, TMGTHFALL);
-	stv0900_write_reg(intp, TMGTHRISE, 0x20);
-	stv0900_write_reg(intp, TMGTHFALL, 0x0);
-	stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
-	stv0900_write_reg(intp, RTC, 0x80);
-	stv0900_write_reg(intp, RTCS2, 0x40);
-	stv0900_write_reg(intp, CARFREQ, 0x0);
-	stv0900_write_reg(intp, CFRINIT1, 0x0);
-	stv0900_write_reg(intp, CFRINIT0, 0x0);
-	stv0900_write_reg(intp, AGC2REF, 0x65);
-	stv0900_write_reg(intp, DMDISTATE, 0x18);
-	msleep(7);
-
-	for (i = 0; i < 10; i++) {
-		if (stv0900_get_bits(intp, TMGLOCK_QUALITY) >= 2)
-			timingcpt++;
-
-		msleep(1);
-	}
-
-	if (timingcpt >= 3)
-		timingLock = TRUE;
-
-	stv0900_write_reg(intp, AGC2REF, 0x38);
-	stv0900_write_reg(intp, RTC, 0x88);
-	stv0900_write_reg(intp, RTCS2, 0x68);
-	stv0900_write_reg(intp, CARFREQ, car_freq);
-	stv0900_write_reg(intp, TMGTHRISE, tmg_th_high);
-	stv0900_write_reg(intp, TMGTHFALL, tmg_th_low);
-
-	return	timingLock;
-}
-
-static int stv0900_get_demod_cold_lock(struct dvb_frontend *fe,
-					s32 demod_timeout)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-	int	lock = FALSE,
-		d = demod;
-	s32	srate,
-		search_range,
-		locktimeout,
-		currier_step,
-		nb_steps,
-		current_step,
-		direction,
-		tuner_freq,
-		timeout,
-		freq;
-
-	srate = intp->symbol_rate[d];
-	search_range = intp->srch_range[d];
-
-	if (srate >= 10000000)
-		locktimeout = demod_timeout / 3;
-	else
-		locktimeout = demod_timeout / 2;
-
-	lock = stv0900_get_demod_lock(intp, d, locktimeout);
-
-	if (lock != FALSE)
-		return lock;
-
-	if (srate >= 10000000) {
-		if (stv0900_check_timing_lock(intp, d) == TRUE) {
-			stv0900_write_reg(intp, DMDISTATE, 0x1f);
-			stv0900_write_reg(intp, DMDISTATE, 0x15);
-			lock = stv0900_get_demod_lock(intp, d, demod_timeout);
-		} else
-			lock = FALSE;
-
-		return lock;
-	}
-
-	if (intp->chip_id <= 0x20) {
-		if (srate <= 1000000)
-			currier_step = 500;
-		else if (srate <= 4000000)
-			currier_step = 1000;
-		else if (srate <= 7000000)
-			currier_step = 2000;
-		else if (srate <= 10000000)
-			currier_step = 3000;
-		else
-			currier_step = 5000;
-
-		if (srate >= 2000000) {
-			timeout = (demod_timeout / 3);
-			if (timeout > 1000)
-				timeout = 1000;
-		} else
-			timeout = (demod_timeout / 2);
-	} else {
-		/*cut 3.0 */
-		currier_step = srate / 4000;
-		timeout = (demod_timeout * 3) / 4;
-	}
-
-	nb_steps = ((search_range / 1000) / currier_step);
-
-	if ((nb_steps % 2) != 0)
-		nb_steps += 1;
-
-	if (nb_steps <= 0)
-		nb_steps = 2;
-	else if (nb_steps > 12)
-		nb_steps = 12;
-
-	current_step = 1;
-	direction = 1;
-
-	if (intp->chip_id <= 0x20) {
-		tuner_freq = intp->freq[d];
-		intp->bw[d] = stv0900_carrier_width(intp->symbol_rate[d],
-				intp->rolloff) + intp->symbol_rate[d];
-	} else
-		tuner_freq = 0;
-
-	while ((current_step <= nb_steps) && (lock == FALSE)) {
-		if (direction > 0)
-			tuner_freq += (current_step * currier_step);
-		else
-			tuner_freq -= (current_step * currier_step);
-
-		if (intp->chip_id <= 0x20) {
-			if (intp->tuner_type[d] == 3)
-				stv0900_set_tuner_auto(intp, tuner_freq,
-						intp->bw[d], demod);
-			else
-				stv0900_set_tuner(fe, tuner_freq, intp->bw[d]);
-
-			stv0900_write_reg(intp, DMDISTATE, 0x1c);
-			stv0900_write_reg(intp, CFRINIT1, 0);
-			stv0900_write_reg(intp, CFRINIT0, 0);
-			stv0900_write_reg(intp, DMDISTATE, 0x1f);
-			stv0900_write_reg(intp, DMDISTATE, 0x15);
-		} else {
-			stv0900_write_reg(intp, DMDISTATE, 0x1c);
-			freq = (tuner_freq * 65536) / (intp->mclk / 1000);
-			stv0900_write_bits(intp, CFR_INIT1, MSB(freq));
-			stv0900_write_bits(intp, CFR_INIT0, LSB(freq));
-			stv0900_write_reg(intp, DMDISTATE, 0x1f);
-			stv0900_write_reg(intp, DMDISTATE, 0x05);
-		}
-
-		lock = stv0900_get_demod_lock(intp, d, timeout);
-		direction *= -1;
-		current_step++;
-	}
-
-	return	lock;
-}
-
-static void stv0900_get_lock_timeout(s32 *demod_timeout, s32 *fec_timeout,
-					s32 srate,
-					enum fe_stv0900_search_algo algo)
-{
-	switch (algo) {
-	case STV0900_BLIND_SEARCH:
-		if (srate <= 1500000) {
-			(*demod_timeout) = 1500;
-			(*fec_timeout) = 400;
-		} else if (srate <= 5000000) {
-			(*demod_timeout) = 1000;
-			(*fec_timeout) = 300;
-		} else {
-			(*demod_timeout) = 700;
-			(*fec_timeout) = 100;
-		}
-
-		break;
-	case STV0900_COLD_START:
-	case STV0900_WARM_START:
-	default:
-		if (srate <= 1000000) {
-			(*demod_timeout) = 3000;
-			(*fec_timeout) = 1700;
-		} else if (srate <= 2000000) {
-			(*demod_timeout) = 2500;
-			(*fec_timeout) = 1100;
-		} else if (srate <= 5000000) {
-			(*demod_timeout) = 1000;
-			(*fec_timeout) = 550;
-		} else if (srate <= 10000000) {
-			(*demod_timeout) = 700;
-			(*fec_timeout) = 250;
-		} else if (srate <= 20000000) {
-			(*demod_timeout) = 400;
-			(*fec_timeout) = 130;
-		} else {
-			(*demod_timeout) = 300;
-			(*fec_timeout) = 100;
-		}
-
-		break;
-
-	}
-
-	if (algo == STV0900_WARM_START)
-		(*demod_timeout) /= 2;
-}
-
-static void stv0900_set_viterbi_tracq(struct stv0900_internal *intp,
-					enum fe_stv0900_demod_num demod)
-{
-
-	s32 vth_reg = VTH12;
-
-	dprintk("%s\n", __func__);
-
-	stv0900_write_reg(intp, vth_reg++, 0xd0);
-	stv0900_write_reg(intp, vth_reg++, 0x7d);
-	stv0900_write_reg(intp, vth_reg++, 0x53);
-	stv0900_write_reg(intp, vth_reg++, 0x2f);
-	stv0900_write_reg(intp, vth_reg++, 0x24);
-	stv0900_write_reg(intp, vth_reg++, 0x1f);
-}
-
-static void stv0900_set_viterbi_standard(struct stv0900_internal *intp,
-				   enum fe_stv0900_search_standard standard,
-				   enum fe_stv0900_fec fec,
-				   enum fe_stv0900_demod_num demod)
-{
-	dprintk("%s: ViterbiStandard = ", __func__);
-
-	switch (standard) {
-	case STV0900_AUTO_SEARCH:
-		dprintk("Auto\n");
-		stv0900_write_reg(intp, FECM, 0x10);
-		stv0900_write_reg(intp, PRVIT, 0x3f);
-		break;
-	case STV0900_SEARCH_DVBS1:
-		dprintk("DVBS1\n");
-		stv0900_write_reg(intp, FECM, 0x00);
-		switch (fec) {
-		case STV0900_FEC_UNKNOWN:
-		default:
-			stv0900_write_reg(intp, PRVIT, 0x2f);
-			break;
-		case STV0900_FEC_1_2:
-			stv0900_write_reg(intp, PRVIT, 0x01);
-			break;
-		case STV0900_FEC_2_3:
-			stv0900_write_reg(intp, PRVIT, 0x02);
-			break;
-		case STV0900_FEC_3_4:
-			stv0900_write_reg(intp, PRVIT, 0x04);
-			break;
-		case STV0900_FEC_5_6:
-			stv0900_write_reg(intp, PRVIT, 0x08);
-			break;
-		case STV0900_FEC_7_8:
-			stv0900_write_reg(intp, PRVIT, 0x20);
-			break;
-		}
-
-		break;
-	case STV0900_SEARCH_DSS:
-		dprintk("DSS\n");
-		stv0900_write_reg(intp, FECM, 0x80);
-		switch (fec) {
-		case STV0900_FEC_UNKNOWN:
-		default:
-			stv0900_write_reg(intp, PRVIT, 0x13);
-			break;
-		case STV0900_FEC_1_2:
-			stv0900_write_reg(intp, PRVIT, 0x01);
-			break;
-		case STV0900_FEC_2_3:
-			stv0900_write_reg(intp, PRVIT, 0x02);
-			break;
-		case STV0900_FEC_6_7:
-			stv0900_write_reg(intp, PRVIT, 0x10);
-			break;
-		}
-		break;
-	default:
-		break;
-	}
-}
-
-static enum fe_stv0900_fec stv0900_get_vit_fec(struct stv0900_internal *intp,
-						enum fe_stv0900_demod_num demod)
-{
-	enum fe_stv0900_fec prate;
-	s32 rate_fld = stv0900_get_bits(intp, VIT_CURPUN);
-
-	switch (rate_fld) {
-	case 13:
-		prate = STV0900_FEC_1_2;
-		break;
-	case 18:
-		prate = STV0900_FEC_2_3;
-		break;
-	case 21:
-		prate = STV0900_FEC_3_4;
-		break;
-	case 24:
-		prate = STV0900_FEC_5_6;
-		break;
-	case 25:
-		prate = STV0900_FEC_6_7;
-		break;
-	case 26:
-		prate = STV0900_FEC_7_8;
-		break;
-	default:
-		prate = STV0900_FEC_UNKNOWN;
-		break;
-	}
-
-	return prate;
-}
-
-static void stv0900_set_dvbs1_track_car_loop(struct stv0900_internal *intp,
-					enum fe_stv0900_demod_num demod,
-					u32 srate)
-{
-	if (intp->chip_id >= 0x30) {
-		if (srate >= 15000000) {
-			stv0900_write_reg(intp, ACLC, 0x2b);
-			stv0900_write_reg(intp, BCLC, 0x1a);
-		} else if ((srate >= 7000000) && (15000000 > srate)) {
-			stv0900_write_reg(intp, ACLC, 0x0c);
-			stv0900_write_reg(intp, BCLC, 0x1b);
-		} else if (srate < 7000000) {
-			stv0900_write_reg(intp, ACLC, 0x2c);
-			stv0900_write_reg(intp, BCLC, 0x1c);
-		}
-
-	} else { /*cut 2.0 and 1.x*/
-		stv0900_write_reg(intp, ACLC, 0x1a);
-		stv0900_write_reg(intp, BCLC, 0x09);
-	}
-
-}
-
-static void stv0900_track_optimization(struct dvb_frontend *fe)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-
-	s32	srate,
-		pilots,
-		aclc,
-		freq1,
-		freq0,
-		i = 0,
-		timed,
-		timef,
-		blind_tun_sw = 0,
-		modulation;
-
-	enum fe_stv0900_modcode foundModcod;
-
-	dprintk("%s\n", __func__);
-
-	srate = stv0900_get_symbol_rate(intp, intp->mclk, demod);
-	srate += stv0900_get_timing_offst(intp, srate, demod);
-
-	switch (intp->result[demod].standard) {
-	case STV0900_DVBS1_STANDARD:
-	case STV0900_DSS_STANDARD:
-		dprintk("%s: found DVB-S or DSS\n", __func__);
-		if (intp->srch_standard[demod] == STV0900_AUTO_SEARCH) {
-			stv0900_write_bits(intp, DVBS1_ENABLE, 1);
-			stv0900_write_bits(intp, DVBS2_ENABLE, 0);
-		}
-
-		stv0900_write_bits(intp, ROLLOFF_CONTROL, intp->rolloff);
-		stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1);
-
-		if (intp->chip_id < 0x30) {
-			stv0900_write_reg(intp, ERRCTRL1, 0x75);
-			break;
-		}
-
-		if (stv0900_get_vit_fec(intp, demod) == STV0900_FEC_1_2) {
-			stv0900_write_reg(intp, GAUSSR0, 0x98);
-			stv0900_write_reg(intp, CCIR0, 0x18);
-		} else {
-			stv0900_write_reg(intp, GAUSSR0, 0x18);
-			stv0900_write_reg(intp, CCIR0, 0x18);
-		}
-
-		stv0900_write_reg(intp, ERRCTRL1, 0x75);
-		break;
-	case STV0900_DVBS2_STANDARD:
-		dprintk("%s: found DVB-S2\n", __func__);
-		stv0900_write_bits(intp, DVBS1_ENABLE, 0);
-		stv0900_write_bits(intp, DVBS2_ENABLE, 1);
-		stv0900_write_reg(intp, ACLC, 0);
-		stv0900_write_reg(intp, BCLC, 0);
-		if (intp->result[demod].frame_len == STV0900_LONG_FRAME) {
-			foundModcod = stv0900_get_bits(intp, DEMOD_MODCOD);
-			pilots = stv0900_get_bits(intp, DEMOD_TYPE) & 0x01;
-			aclc = stv0900_get_optim_carr_loop(srate,
-							foundModcod,
-							pilots,
-							intp->chip_id);
-			if (foundModcod <= STV0900_QPSK_910)
-				stv0900_write_reg(intp, ACLC2S2Q, aclc);
-			else if (foundModcod <= STV0900_8PSK_910) {
-				stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
-				stv0900_write_reg(intp, ACLC2S28, aclc);
-			}
-
-			if ((intp->demod_mode == STV0900_SINGLE) &&
-					(foundModcod > STV0900_8PSK_910)) {
-				if (foundModcod <= STV0900_16APSK_910) {
-					stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
-					stv0900_write_reg(intp, ACLC2S216A,
-									aclc);
-				} else if (foundModcod <= STV0900_32APSK_910) {
-					stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
-					stv0900_write_reg(intp,	ACLC2S232A,
-									aclc);
-				}
-			}
-
-		} else {
-			modulation = intp->result[demod].modulation;
-			aclc = stv0900_get_optim_short_carr_loop(srate,
-					modulation, intp->chip_id);
-			if (modulation == STV0900_QPSK)
-				stv0900_write_reg(intp, ACLC2S2Q, aclc);
-			else if (modulation == STV0900_8PSK) {
-				stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
-				stv0900_write_reg(intp, ACLC2S28, aclc);
-			} else if (modulation == STV0900_16APSK) {
-				stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
-				stv0900_write_reg(intp, ACLC2S216A, aclc);
-			} else if (modulation == STV0900_32APSK) {
-				stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
-				stv0900_write_reg(intp, ACLC2S232A, aclc);
-			}
-
-		}
-
-		if (intp->chip_id <= 0x11) {
-			if (intp->demod_mode != STV0900_SINGLE)
-				stv0900_activate_s2_modcod(intp, demod);
-
-		}
-
-		stv0900_write_reg(intp, ERRCTRL1, 0x67);
-		break;
-	case STV0900_UNKNOWN_STANDARD:
-	default:
-		dprintk("%s: found unknown standard\n", __func__);
-		stv0900_write_bits(intp, DVBS1_ENABLE, 1);
-		stv0900_write_bits(intp, DVBS2_ENABLE, 1);
-		break;
-	}
-
-	freq1 = stv0900_read_reg(intp, CFR2);
-	freq0 = stv0900_read_reg(intp, CFR1);
-	if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) {
-		stv0900_write_reg(intp, SFRSTEP, 0x00);
-		stv0900_write_bits(intp, SCAN_ENABLE, 0);
-		stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
-		stv0900_write_reg(intp, TMGCFG2, 0xc1);
-		stv0900_set_symbol_rate(intp, intp->mclk, srate, demod);
-		blind_tun_sw = 1;
-		if (intp->result[demod].standard != STV0900_DVBS2_STANDARD)
-			stv0900_set_dvbs1_track_car_loop(intp, demod, srate);
-
-	}
-
-	if (intp->chip_id >= 0x20) {
-		if ((intp->srch_standard[demod] == STV0900_SEARCH_DVBS1) ||
-				(intp->srch_standard[demod] ==
-							STV0900_SEARCH_DSS) ||
-				(intp->srch_standard[demod] ==
-							STV0900_AUTO_SEARCH)) {
-			stv0900_write_reg(intp, VAVSRVIT, 0x0a);
-			stv0900_write_reg(intp, VITSCALE, 0x0);
-		}
-	}
-
-	if (intp->chip_id < 0x20)
-		stv0900_write_reg(intp, CARHDR, 0x08);
-
-	if (intp->chip_id == 0x10)
-		stv0900_write_reg(intp, CORRELEXP, 0x0a);
-
-	stv0900_write_reg(intp, AGC2REF, 0x38);
-
-	if ((intp->chip_id >= 0x20) ||
-			(blind_tun_sw == 1) ||
-			(intp->symbol_rate[demod] < 10000000)) {
-		stv0900_write_reg(intp, CFRINIT1, freq1);
-		stv0900_write_reg(intp, CFRINIT0, freq0);
-		intp->bw[demod] = stv0900_carrier_width(srate,
-					intp->rolloff) + 10000000;
-
-		if ((intp->chip_id >= 0x20) || (blind_tun_sw == 1)) {
-			if (intp->srch_algo[demod] != STV0900_WARM_START) {
-				if (intp->tuner_type[demod] == 3)
-					stv0900_set_tuner_auto(intp,
-							intp->freq[demod],
-							intp->bw[demod],
-							demod);
-				else
-					stv0900_set_bandwidth(fe,
-							intp->bw[demod]);
-			}
-		}
-
-		if ((intp->srch_algo[demod] == STV0900_BLIND_SEARCH) ||
-				(intp->symbol_rate[demod] < 10000000))
-			msleep(50);
-		else
-			msleep(5);
-
-		stv0900_get_lock_timeout(&timed, &timef, srate,
-						STV0900_WARM_START);
-
-		if (stv0900_get_demod_lock(intp, demod, timed / 2) == FALSE) {
-			stv0900_write_reg(intp, DMDISTATE, 0x1f);
-			stv0900_write_reg(intp, CFRINIT1, freq1);
-			stv0900_write_reg(intp, CFRINIT0, freq0);
-			stv0900_write_reg(intp, DMDISTATE, 0x18);
-			i = 0;
-			while ((stv0900_get_demod_lock(intp,
-							demod,
-							timed / 2) == FALSE) &&
-						(i <= 2)) {
-				stv0900_write_reg(intp, DMDISTATE, 0x1f);
-				stv0900_write_reg(intp, CFRINIT1, freq1);
-				stv0900_write_reg(intp, CFRINIT0, freq0);
-				stv0900_write_reg(intp, DMDISTATE, 0x18);
-				i++;
-			}
-		}
-
-	}
-
-	if (intp->chip_id >= 0x20)
-		stv0900_write_reg(intp, CARFREQ, 0x49);
-
-	if ((intp->result[demod].standard == STV0900_DVBS1_STANDARD) ||
-			(intp->result[demod].standard == STV0900_DSS_STANDARD))
-		stv0900_set_viterbi_tracq(intp, demod);
-
-}
-
-static int stv0900_get_fec_lock(struct stv0900_internal *intp,
-				enum fe_stv0900_demod_num demod, s32 time_out)
-{
-	s32 timer = 0, lock = 0;
-
-	enum fe_stv0900_search_state dmd_state;
-
-	dprintk("%s\n", __func__);
-
-	dmd_state = stv0900_get_bits(intp, HEADER_MODE);
-
-	while ((timer < time_out) && (lock == 0)) {
-		switch (dmd_state) {
-		case STV0900_SEARCH:
-		case STV0900_PLH_DETECTED:
-		default:
-			lock = 0;
-			break;
-		case STV0900_DVBS2_FOUND:
-			lock = stv0900_get_bits(intp, PKTDELIN_LOCK);
-			break;
-		case STV0900_DVBS_FOUND:
-			lock = stv0900_get_bits(intp, LOCKEDVIT);
-			break;
-		}
-
-		if (lock == 0) {
-			msleep(10);
-			timer += 10;
-		}
-	}
-
-	if (lock)
-		dprintk("%s: DEMOD FEC LOCK OK\n", __func__);
-	else
-		dprintk("%s: DEMOD FEC LOCK FAIL\n", __func__);
-
-	return lock;
-}
-
-static int stv0900_wait_for_lock(struct stv0900_internal *intp,
-				enum fe_stv0900_demod_num demod,
-				s32 dmd_timeout, s32 fec_timeout)
-{
-
-	s32 timer = 0, lock = 0;
-
-	dprintk("%s\n", __func__);
-
-	lock = stv0900_get_demod_lock(intp, demod, dmd_timeout);
-
-	if (lock)
-		lock = lock && stv0900_get_fec_lock(intp, demod, fec_timeout);
-
-	if (lock) {
-		lock = 0;
-
-		dprintk("%s: Timer = %d, time_out = %d\n",
-				__func__, timer, fec_timeout);
-
-		while ((timer < fec_timeout) && (lock == 0)) {
-			lock = stv0900_get_bits(intp, TSFIFO_LINEOK);
-			msleep(1);
-			timer++;
-		}
-	}
-
-	if (lock)
-		dprintk("%s: DEMOD LOCK OK\n", __func__);
-	else
-		dprintk("%s: DEMOD LOCK FAIL\n", __func__);
-
-	if (lock)
-		return TRUE;
-	else
-		return FALSE;
-}
-
-enum fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe,
-						enum fe_stv0900_demod_num demod)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_tracking_standard fnd_standard;
-
-	int hdr_mode = stv0900_get_bits(intp, HEADER_MODE);
-
-	switch (hdr_mode) {
-	case 2:
-		fnd_standard = STV0900_DVBS2_STANDARD;
-		break;
-	case 3:
-		if (stv0900_get_bits(intp, DSS_DVB) == 1)
-			fnd_standard = STV0900_DSS_STANDARD;
-		else
-			fnd_standard = STV0900_DVBS1_STANDARD;
-
-		break;
-	default:
-		fnd_standard = STV0900_UNKNOWN_STANDARD;
-	}
-
-	dprintk("%s: standard %d\n", __func__, fnd_standard);
-
-	return fnd_standard;
-}
-
-static s32 stv0900_get_carr_freq(struct stv0900_internal *intp, u32 mclk,
-					enum fe_stv0900_demod_num demod)
-{
-	s32	derot,
-		rem1,
-		rem2,
-		intval1,
-		intval2;
-
-	derot = (stv0900_get_bits(intp, CAR_FREQ2) << 16) +
-		(stv0900_get_bits(intp, CAR_FREQ1) << 8) +
-		(stv0900_get_bits(intp, CAR_FREQ0));
-
-	derot = ge2comp(derot, 24);
-	intval1 = mclk >> 12;
-	intval2 = derot >> 12;
-	rem1 = mclk % 0x1000;
-	rem2 = derot % 0x1000;
-	derot = (intval1 * intval2) +
-		((intval1 * rem2) >> 12) +
-		((intval2 * rem1) >> 12);
-
-	return derot;
-}
-
-static u32 stv0900_get_tuner_freq(struct dvb_frontend *fe)
-{
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops *tuner_ops = NULL;
-	u32 freq = 0;
-
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
-
-	if (tuner_ops->get_frequency) {
-		if ((tuner_ops->get_frequency(fe, &freq)) < 0)
-			dprintk("%s: Invalid parameter\n", __func__);
-		else
-			dprintk("%s: Frequency=%d\n", __func__, freq);
-
-	}
-
-	return freq;
-}
-
-static enum
-fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-	enum fe_stv0900_signal_type range = STV0900_OUTOFRANGE;
-	struct stv0900_signal_info *result = &intp->result[demod];
-	s32	offsetFreq,
-		srate_offset;
-	int	i = 0,
-		d = demod;
-
-	u8 timing;
-
-	msleep(5);
-	if (intp->srch_algo[d] == STV0900_BLIND_SEARCH) {
-		timing = stv0900_read_reg(intp, TMGREG2);
-		i = 0;
-		stv0900_write_reg(intp, SFRSTEP, 0x5c);
-
-		while ((i <= 50) && (timing != 0) && (timing != 0xff)) {
-			timing = stv0900_read_reg(intp, TMGREG2);
-			msleep(5);
-			i += 5;
-		}
-	}
-
-	result->standard = stv0900_get_standard(fe, d);
-	if (intp->tuner_type[demod] == 3)
-		result->frequency = stv0900_get_freq_auto(intp, d);
-	else
-		result->frequency = stv0900_get_tuner_freq(fe);
-
-	offsetFreq = stv0900_get_carr_freq(intp, intp->mclk, d) / 1000;
-	result->frequency += offsetFreq;
-	result->symbol_rate = stv0900_get_symbol_rate(intp, intp->mclk, d);
-	srate_offset = stv0900_get_timing_offst(intp, result->symbol_rate, d);
-	result->symbol_rate += srate_offset;
-	result->fec = stv0900_get_vit_fec(intp, d);
-	result->modcode = stv0900_get_bits(intp, DEMOD_MODCOD);
-	result->pilot = stv0900_get_bits(intp, DEMOD_TYPE) & 0x01;
-	result->frame_len = ((u32)stv0900_get_bits(intp, DEMOD_TYPE)) >> 1;
-	result->rolloff = stv0900_get_bits(intp, ROLLOFF_STATUS);
-
-	dprintk("%s: modcode=0x%x \n", __func__, result->modcode);
-
-	switch (result->standard) {
-	case STV0900_DVBS2_STANDARD:
-		result->spectrum = stv0900_get_bits(intp, SPECINV_DEMOD);
-		if (result->modcode <= STV0900_QPSK_910)
-			result->modulation = STV0900_QPSK;
-		else if (result->modcode <= STV0900_8PSK_910)
-			result->modulation = STV0900_8PSK;
-		else if (result->modcode <= STV0900_16APSK_910)
-			result->modulation = STV0900_16APSK;
-		else if (result->modcode <= STV0900_32APSK_910)
-			result->modulation = STV0900_32APSK;
-		else
-			result->modulation = STV0900_UNKNOWN;
-		break;
-	case STV0900_DVBS1_STANDARD:
-	case STV0900_DSS_STANDARD:
-		result->spectrum = stv0900_get_bits(intp, IQINV);
-		result->modulation = STV0900_QPSK;
-		break;
-	default:
-		break;
-	}
-
-	if ((intp->srch_algo[d] == STV0900_BLIND_SEARCH) ||
-				(intp->symbol_rate[d] < 10000000)) {
-		offsetFreq = result->frequency - intp->freq[d];
-		if (intp->tuner_type[demod] == 3)
-			intp->freq[d] = stv0900_get_freq_auto(intp, d);
-		else
-			intp->freq[d] = stv0900_get_tuner_freq(fe);
-
-		if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
-			range = STV0900_RANGEOK;
-		else if (ABS(offsetFreq) <=
-				(stv0900_carrier_width(result->symbol_rate,
-						result->rolloff) / 2000))
-			range = STV0900_RANGEOK;
-
-	} else if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
-		range = STV0900_RANGEOK;
-
-	dprintk("%s: range %d\n", __func__, range);
-
-	return range;
-}
-
-static enum
-fe_stv0900_signal_type stv0900_dvbs1_acq_workaround(struct dvb_frontend *fe)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-	enum fe_stv0900_signal_type signal_type = STV0900_NODATA;
-
-	s32	srate,
-		demod_timeout,
-		fec_timeout,
-		freq1,
-		freq0;
-
-	intp->result[demod].locked = FALSE;
-
-	if (stv0900_get_bits(intp, HEADER_MODE) == STV0900_DVBS_FOUND) {
-		srate = stv0900_get_symbol_rate(intp, intp->mclk, demod);
-		srate += stv0900_get_timing_offst(intp, srate, demod);
-		if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH)
-			stv0900_set_symbol_rate(intp, intp->mclk, srate, demod);
-
-		stv0900_get_lock_timeout(&demod_timeout, &fec_timeout,
-					srate, STV0900_WARM_START);
-		freq1 = stv0900_read_reg(intp, CFR2);
-		freq0 = stv0900_read_reg(intp, CFR1);
-		stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
-		stv0900_write_bits(intp, SPECINV_CONTROL,
-					STV0900_IQ_FORCE_SWAPPED);
-		stv0900_write_reg(intp, DMDISTATE, 0x1c);
-		stv0900_write_reg(intp, CFRINIT1, freq1);
-		stv0900_write_reg(intp, CFRINIT0, freq0);
-		stv0900_write_reg(intp, DMDISTATE, 0x18);
-		if (stv0900_wait_for_lock(intp, demod,
-				demod_timeout, fec_timeout) == TRUE) {
-			intp->result[demod].locked = TRUE;
-			signal_type = stv0900_get_signal_params(fe);
-			stv0900_track_optimization(fe);
-		} else {
-			stv0900_write_bits(intp, SPECINV_CONTROL,
-					STV0900_IQ_FORCE_NORMAL);
-			stv0900_write_reg(intp, DMDISTATE, 0x1c);
-			stv0900_write_reg(intp, CFRINIT1, freq1);
-			stv0900_write_reg(intp, CFRINIT0, freq0);
-			stv0900_write_reg(intp, DMDISTATE, 0x18);
-			if (stv0900_wait_for_lock(intp, demod,
-					demod_timeout, fec_timeout) == TRUE) {
-				intp->result[demod].locked = TRUE;
-				signal_type = stv0900_get_signal_params(fe);
-				stv0900_track_optimization(fe);
-			}
-
-		}
-
-	} else
-		intp->result[demod].locked = FALSE;
-
-	return signal_type;
-}
-
-static u16 stv0900_blind_check_agc2_min_level(struct stv0900_internal *intp,
-					enum fe_stv0900_demod_num demod)
-{
-	u32 minagc2level = 0xffff,
-		agc2level,
-		init_freq, freq_step;
-
-	s32 i, j, nb_steps, direction;
-
-	dprintk("%s\n", __func__);
-
-	stv0900_write_reg(intp, AGC2REF, 0x38);
-	stv0900_write_bits(intp, SCAN_ENABLE, 0);
-	stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
-
-	stv0900_write_bits(intp, AUTO_GUP, 1);
-	stv0900_write_bits(intp, AUTO_GLOW, 1);
-
-	stv0900_write_reg(intp, DMDT0M, 0x0);
-
-	stv0900_set_symbol_rate(intp, intp->mclk, 1000000, demod);
-	nb_steps = -1 + (intp->srch_range[demod] / 1000000);
-	nb_steps /= 2;
-	nb_steps = (2 * nb_steps) + 1;
-
-	if (nb_steps < 0)
-		nb_steps = 1;
-
-	direction = 1;
-
-	freq_step = (1000000 << 8) / (intp->mclk >> 8);
-
-	init_freq = 0;
-
-	for (i = 0; i < nb_steps; i++) {
-		if (direction > 0)
-			init_freq = init_freq + (freq_step * i);
-		else
-			init_freq = init_freq - (freq_step * i);
-
-		direction *= -1;
-		stv0900_write_reg(intp, DMDISTATE, 0x5C);
-		stv0900_write_reg(intp, CFRINIT1, (init_freq >> 8) & 0xff);
-		stv0900_write_reg(intp, CFRINIT0, init_freq  & 0xff);
-		stv0900_write_reg(intp, DMDISTATE, 0x58);
-		msleep(10);
-		agc2level = 0;
-
-		for (j = 0; j < 10; j++)
-			agc2level += (stv0900_read_reg(intp, AGC2I1) << 8)
-					| stv0900_read_reg(intp, AGC2I0);
-
-		agc2level /= 10;
-
-		if (agc2level < minagc2level)
-			minagc2level = agc2level;
-
-	}
-
-	return (u16)minagc2level;
-}
-
-static u32 stv0900_search_srate_coarse(struct dvb_frontend *fe)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-	int timing_lck = FALSE;
-	s32 i, timingcpt = 0,
-		direction = 1,
-		nb_steps,
-		current_step = 0,
-		tuner_freq;
-	u32 agc2_th,
-		coarse_srate = 0,
-		agc2_integr = 0,
-		currier_step = 1200;
-
-	if (intp->chip_id >= 0x30)
-		agc2_th = 0x2e00;
-	else
-		agc2_th = 0x1f00;
-
-	stv0900_write_bits(intp, DEMOD_MODE, 0x1f);
-	stv0900_write_reg(intp, TMGCFG, 0x12);
-	stv0900_write_reg(intp, TMGTHRISE, 0xf0);
-	stv0900_write_reg(intp, TMGTHFALL, 0xe0);
-	stv0900_write_bits(intp, SCAN_ENABLE, 1);
-	stv0900_write_bits(intp, CFR_AUTOSCAN, 1);
-	stv0900_write_reg(intp, SFRUP1, 0x83);
-	stv0900_write_reg(intp, SFRUP0, 0xc0);
-	stv0900_write_reg(intp, SFRLOW1, 0x82);
-	stv0900_write_reg(intp, SFRLOW0, 0xa0);
-	stv0900_write_reg(intp, DMDT0M, 0x0);
-	stv0900_write_reg(intp, AGC2REF, 0x50);
-
-	if (intp->chip_id >= 0x30) {
-		stv0900_write_reg(intp, CARFREQ, 0x99);
-		stv0900_write_reg(intp, SFRSTEP, 0x98);
-	} else if (intp->chip_id >= 0x20) {
-		stv0900_write_reg(intp, CARFREQ, 0x6a);
-		stv0900_write_reg(intp, SFRSTEP, 0x95);
-	} else {
-		stv0900_write_reg(intp, CARFREQ, 0xed);
-		stv0900_write_reg(intp, SFRSTEP, 0x73);
-	}
-
-	if (intp->symbol_rate[demod] <= 2000000)
-		currier_step = 1000;
-	else if (intp->symbol_rate[demod] <= 5000000)
-		currier_step = 2000;
-	else if (intp->symbol_rate[demod] <= 12000000)
-		currier_step = 3000;
-	else
-			currier_step = 5000;
-
-	nb_steps = -1 + ((intp->srch_range[demod] / 1000) / currier_step);
-	nb_steps /= 2;
-	nb_steps = (2 * nb_steps) + 1;
-
-	if (nb_steps < 0)
-		nb_steps = 1;
-	else if (nb_steps > 10) {
-		nb_steps = 11;
-		currier_step = (intp->srch_range[demod] / 1000) / 10;
-	}
-
-	current_step = 0;
-	direction = 1;
-
-	tuner_freq = intp->freq[demod];
-
-	while ((timing_lck == FALSE) && (current_step < nb_steps)) {
-		stv0900_write_reg(intp, DMDISTATE, 0x5f);
-		stv0900_write_bits(intp, DEMOD_MODE, 0);
-
-		msleep(50);
-
-		for (i = 0; i < 10; i++) {
-			if (stv0900_get_bits(intp, TMGLOCK_QUALITY) >= 2)
-				timingcpt++;
-
-			agc2_integr += (stv0900_read_reg(intp, AGC2I1) << 8) |
-					stv0900_read_reg(intp, AGC2I0);
-		}
-
-		agc2_integr /= 10;
-		coarse_srate = stv0900_get_symbol_rate(intp, intp->mclk, demod);
-		current_step++;
-		direction *= -1;
-
-		dprintk("lock: I2C_DEMOD_MODE_FIELD =0. Search started."
-			" tuner freq=%d agc2=0x%x srate_coarse=%d tmg_cpt=%d\n",
-			tuner_freq, agc2_integr, coarse_srate, timingcpt);
-
-		if ((timingcpt >= 5) &&
-				(agc2_integr < agc2_th) &&
-				(coarse_srate < 55000000) &&
-				(coarse_srate > 850000))
-			timing_lck = TRUE;
-		else if (current_step < nb_steps) {
-			if (direction > 0)
-				tuner_freq += (current_step * currier_step);
-			else
-				tuner_freq -= (current_step * currier_step);
-
-			if (intp->tuner_type[demod] == 3)
-				stv0900_set_tuner_auto(intp, tuner_freq,
-						intp->bw[demod], demod);
-			else
-				stv0900_set_tuner(fe, tuner_freq,
-						intp->bw[demod]);
-		}
-	}
-
-	if (timing_lck == FALSE)
-		coarse_srate = 0;
-	else
-		coarse_srate = stv0900_get_symbol_rate(intp, intp->mclk, demod);
-
-	return coarse_srate;
-}
-
-static u32 stv0900_search_srate_fine(struct dvb_frontend *fe)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-	u32	coarse_srate,
-		coarse_freq,
-		symb,
-		symbmax,
-		symbmin,
-		symbcomp;
-
-	coarse_srate = stv0900_get_symbol_rate(intp, intp->mclk, demod);
-
-	if (coarse_srate > 3000000) {
-		symbmax = 13 * (coarse_srate / 10);
-		symbmax = (symbmax / 1000) * 65536;
-		symbmax /= (intp->mclk / 1000);
-
-		symbmin = 10 * (coarse_srate / 13);
-		symbmin = (symbmin / 1000)*65536;
-		symbmin /= (intp->mclk / 1000);
-
-		symb = (coarse_srate / 1000) * 65536;
-		symb /= (intp->mclk / 1000);
-	} else {
-		symbmax = 13 * (coarse_srate / 10);
-		symbmax = (symbmax / 100) * 65536;
-		symbmax /= (intp->mclk / 100);
-
-		symbmin = 10 * (coarse_srate / 14);
-		symbmin = (symbmin / 100) * 65536;
-		symbmin /= (intp->mclk / 100);
-
-		symb = (coarse_srate / 100) * 65536;
-		symb /= (intp->mclk / 100);
-	}
-
-	symbcomp = 13 * (coarse_srate / 10);
-		coarse_freq = (stv0900_read_reg(intp, CFR2) << 8)
-					| stv0900_read_reg(intp, CFR1);
-
-	if (symbcomp < intp->symbol_rate[demod])
-		coarse_srate = 0;
-	else {
-		stv0900_write_reg(intp, DMDISTATE, 0x1f);
-		stv0900_write_reg(intp, TMGCFG2, 0xc1);
-		stv0900_write_reg(intp, TMGTHRISE, 0x20);
-		stv0900_write_reg(intp, TMGTHFALL, 0x00);
-		stv0900_write_reg(intp, TMGCFG, 0xd2);
-		stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
-		stv0900_write_reg(intp, AGC2REF, 0x38);
-
-		if (intp->chip_id >= 0x30)
-			stv0900_write_reg(intp, CARFREQ, 0x79);
-		else if (intp->chip_id >= 0x20)
-			stv0900_write_reg(intp, CARFREQ, 0x49);
-		else
-			stv0900_write_reg(intp, CARFREQ, 0xed);
-
-		stv0900_write_reg(intp, SFRUP1, (symbmax >> 8) & 0x7f);
-		stv0900_write_reg(intp, SFRUP0, (symbmax & 0xff));
-
-		stv0900_write_reg(intp, SFRLOW1, (symbmin >> 8) & 0x7f);
-		stv0900_write_reg(intp, SFRLOW0, (symbmin & 0xff));
-
-		stv0900_write_reg(intp, SFRINIT1, (symb >> 8) & 0xff);
-		stv0900_write_reg(intp, SFRINIT0, (symb & 0xff));
-
-		stv0900_write_reg(intp, DMDT0M, 0x20);
-		stv0900_write_reg(intp, CFRINIT1, (coarse_freq >> 8) & 0xff);
-		stv0900_write_reg(intp, CFRINIT0, coarse_freq  & 0xff);
-		stv0900_write_reg(intp, DMDISTATE, 0x15);
-	}
-
-	return coarse_srate;
-}
-
-static int stv0900_blind_search_algo(struct dvb_frontend *fe)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-	u8	k_ref_tmg,
-		k_ref_tmg_max,
-		k_ref_tmg_min;
-	u32	coarse_srate,
-		agc2_th;
-	int	lock = FALSE,
-		coarse_fail = FALSE;
-	s32	demod_timeout = 500,
-		fec_timeout = 50,
-		fail_cpt,
-		i,
-		agc2_overflow;
-	u16	agc2_int;
-	u8	dstatus2;
-
-	dprintk("%s\n", __func__);
-
-	if (intp->chip_id < 0x20) {
-		k_ref_tmg_max = 233;
-		k_ref_tmg_min = 143;
-	} else {
-		k_ref_tmg_max = 110;
-		k_ref_tmg_min = 10;
-	}
-
-	if (intp->chip_id <= 0x20)
-		agc2_th = STV0900_BLIND_SEARCH_AGC2_TH;
-	else
-		agc2_th = STV0900_BLIND_SEARCH_AGC2_TH_CUT30;
-
-	agc2_int = stv0900_blind_check_agc2_min_level(intp, demod);
-
-	dprintk("%s agc2_int=%d agc2_th=%d \n", __func__, agc2_int, agc2_th);
-	if (agc2_int > agc2_th)
-		return FALSE;
-
-	if (intp->chip_id == 0x10)
-		stv0900_write_reg(intp, CORRELEXP, 0xaa);
-
-	if (intp->chip_id < 0x20)
-		stv0900_write_reg(intp, CARHDR, 0x55);
-	else
-		stv0900_write_reg(intp, CARHDR, 0x20);
-
-	if (intp->chip_id <= 0x20)
-		stv0900_write_reg(intp, CARCFG, 0xc4);
-	else
-		stv0900_write_reg(intp, CARCFG, 0x6);
-
-	stv0900_write_reg(intp, RTCS2, 0x44);
-
-	if (intp->chip_id >= 0x20) {
-		stv0900_write_reg(intp, EQUALCFG, 0x41);
-		stv0900_write_reg(intp, FFECFG, 0x41);
-		stv0900_write_reg(intp, VITSCALE, 0x82);
-		stv0900_write_reg(intp, VAVSRVIT, 0x0);
-	}
-
-	k_ref_tmg = k_ref_tmg_max;
-
-	do {
-		stv0900_write_reg(intp, KREFTMG, k_ref_tmg);
-		if (stv0900_search_srate_coarse(fe) != 0) {
-			coarse_srate = stv0900_search_srate_fine(fe);
-
-			if (coarse_srate != 0) {
-				stv0900_get_lock_timeout(&demod_timeout,
-							&fec_timeout,
-							coarse_srate,
-							STV0900_BLIND_SEARCH);
-				lock = stv0900_get_demod_lock(intp,
-							demod,
-							demod_timeout);
-			} else
-				lock = FALSE;
-		} else {
-			fail_cpt = 0;
-			agc2_overflow = 0;
-
-			for (i = 0; i < 10; i++) {
-				agc2_int = (stv0900_read_reg(intp, AGC2I1) << 8)
-					| stv0900_read_reg(intp, AGC2I0);
-
-				if (agc2_int >= 0xff00)
-					agc2_overflow++;
-
-				dstatus2 = stv0900_read_reg(intp, DSTATUS2);
-
-				if (((dstatus2 & 0x1) == 0x1) &&
-						((dstatus2 >> 7) == 1))
-					fail_cpt++;
-			}
-
-			if ((fail_cpt > 7) || (agc2_overflow > 7))
-				coarse_fail = TRUE;
-
-			lock = FALSE;
-		}
-		k_ref_tmg -= 30;
-	} while ((k_ref_tmg >= k_ref_tmg_min) &&
-				(lock == FALSE) &&
-				(coarse_fail == FALSE));
-
-	return lock;
-}
-
-static void stv0900_set_viterbi_acq(struct stv0900_internal *intp,
-					enum fe_stv0900_demod_num demod)
-{
-	s32 vth_reg = VTH12;
-
-	dprintk("%s\n", __func__);
-
-	stv0900_write_reg(intp, vth_reg++, 0x96);
-	stv0900_write_reg(intp, vth_reg++, 0x64);
-	stv0900_write_reg(intp, vth_reg++, 0x36);
-	stv0900_write_reg(intp, vth_reg++, 0x23);
-	stv0900_write_reg(intp, vth_reg++, 0x1e);
-	stv0900_write_reg(intp, vth_reg++, 0x19);
-}
-
-static void stv0900_set_search_standard(struct stv0900_internal *intp,
-					enum fe_stv0900_demod_num demod)
-{
-
-	dprintk("%s\n", __func__);
-
-	switch (intp->srch_standard[demod]) {
-	case STV0900_SEARCH_DVBS1:
-		dprintk("Search Standard = DVBS1\n");
-		break;
-	case STV0900_SEARCH_DSS:
-		dprintk("Search Standard = DSS\n");
-	case STV0900_SEARCH_DVBS2:
-		break;
-		dprintk("Search Standard = DVBS2\n");
-	case STV0900_AUTO_SEARCH:
-	default:
-		dprintk("Search Standard = AUTO\n");
-		break;
-	}
-
-	switch (intp->srch_standard[demod]) {
-	case STV0900_SEARCH_DVBS1:
-	case STV0900_SEARCH_DSS:
-		stv0900_write_bits(intp, DVBS1_ENABLE, 1);
-		stv0900_write_bits(intp, DVBS2_ENABLE, 0);
-		stv0900_write_bits(intp, STOP_CLKVIT, 0);
-		stv0900_set_dvbs1_track_car_loop(intp,
-						demod,
-						intp->symbol_rate[demod]);
-		stv0900_write_reg(intp, CAR2CFG, 0x22);
-
-		stv0900_set_viterbi_acq(intp, demod);
-		stv0900_set_viterbi_standard(intp,
-					intp->srch_standard[demod],
-					intp->fec[demod], demod);
-
-		break;
-	case STV0900_SEARCH_DVBS2:
-		stv0900_write_bits(intp, DVBS1_ENABLE, 0);
-		stv0900_write_bits(intp, DVBS2_ENABLE, 1);
-		stv0900_write_bits(intp, STOP_CLKVIT, 1);
-		stv0900_write_reg(intp, ACLC, 0x1a);
-		stv0900_write_reg(intp, BCLC, 0x09);
-		if (intp->chip_id <= 0x20) /*cut 1.x and 2.0*/
-			stv0900_write_reg(intp, CAR2CFG, 0x26);
-		else
-			stv0900_write_reg(intp, CAR2CFG, 0x66);
-
-		if (intp->demod_mode != STV0900_SINGLE) {
-			if (intp->chip_id <= 0x11)
-				stv0900_stop_all_s2_modcod(intp, demod);
-			else
-				stv0900_activate_s2_modcod(intp, demod);
-
-		} else
-			stv0900_activate_s2_modcod_single(intp, demod);
-
-		stv0900_set_viterbi_tracq(intp, demod);
-
-		break;
-	case STV0900_AUTO_SEARCH:
-	default:
-		stv0900_write_bits(intp, DVBS1_ENABLE, 1);
-		stv0900_write_bits(intp, DVBS2_ENABLE, 1);
-		stv0900_write_bits(intp, STOP_CLKVIT, 0);
-		stv0900_write_reg(intp, ACLC, 0x1a);
-		stv0900_write_reg(intp, BCLC, 0x09);
-		stv0900_set_dvbs1_track_car_loop(intp,
-						demod,
-						intp->symbol_rate[demod]);
-		if (intp->chip_id <= 0x20) /*cut 1.x and 2.0*/
-			stv0900_write_reg(intp, CAR2CFG, 0x26);
-		else
-			stv0900_write_reg(intp, CAR2CFG, 0x66);
-
-		if (intp->demod_mode != STV0900_SINGLE) {
-			if (intp->chip_id <= 0x11)
-				stv0900_stop_all_s2_modcod(intp, demod);
-			else
-				stv0900_activate_s2_modcod(intp, demod);
-
-		} else
-			stv0900_activate_s2_modcod_single(intp, demod);
-
-		stv0900_set_viterbi_tracq(intp, demod);
-		stv0900_set_viterbi_standard(intp,
-						intp->srch_standard[demod],
-						intp->fec[demod], demod);
-
-		break;
-	}
-}
-
-enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe)
-{
-	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *intp = state->internal;
-	enum fe_stv0900_demod_num demod = state->demod;
-
-	s32 demod_timeout = 500, fec_timeout = 50;
-	s32 aq_power, agc1_power, i;
-
-	int lock = FALSE, low_sr = FALSE;
-
-	enum fe_stv0900_signal_type signal_type = STV0900_NOCARRIER;
-	enum fe_stv0900_search_algo algo;
-	int no_signal = FALSE;
-
-	dprintk("%s\n", __func__);
-
-	algo = intp->srch_algo[demod];
-	stv0900_write_bits(intp, RST_HWARE, 1);
-	stv0900_write_reg(intp, DMDISTATE, 0x5c);
-	if (intp->chip_id >= 0x20) {
-		if (intp->symbol_rate[demod] > 5000000)
-			stv0900_write_reg(intp, CORRELABS, 0x9e);
-		else
-			stv0900_write_reg(intp, CORRELABS, 0x82);
-	} else
-		stv0900_write_reg(intp, CORRELABS, 0x88);
-
-	stv0900_get_lock_timeout(&demod_timeout, &fec_timeout,
-				intp->symbol_rate[demod],
-				intp->srch_algo[demod]);
-
-	if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) {
-		intp->bw[demod] = 2 * 36000000;
-
-		stv0900_write_reg(intp, TMGCFG2, 0xc0);
-		stv0900_write_reg(intp, CORRELMANT, 0x70);
-
-		stv0900_set_symbol_rate(intp, intp->mclk, 1000000, demod);
-	} else {
-		stv0900_write_reg(intp, DMDT0M, 0x20);
-		stv0900_write_reg(intp, TMGCFG, 0xd2);
-
-		if (intp->symbol_rate[demod] < 2000000)
-			stv0900_write_reg(intp, CORRELMANT, 0x63);
-		else
-			stv0900_write_reg(intp, CORRELMANT, 0x70);
-
-		stv0900_write_reg(intp, AGC2REF, 0x38);
-
-		intp->bw[demod] =
-				stv0900_carrier_width(intp->symbol_rate[demod],
-								intp->rolloff);
-		if (intp->chip_id >= 0x20) {
-			stv0900_write_reg(intp, KREFTMG, 0x5a);
-
-			if (intp->srch_algo[demod] == STV0900_COLD_START) {
-				intp->bw[demod] += 10000000;
-				intp->bw[demod] *= 15;
-				intp->bw[demod] /= 10;
-			} else if (intp->srch_algo[demod] == STV0900_WARM_START)
-				intp->bw[demod] += 10000000;
-
-		} else {
-			stv0900_write_reg(intp, KREFTMG, 0xc1);
-			intp->bw[demod] += 10000000;
-			intp->bw[demod] *= 15;
-			intp->bw[demod] /= 10;
-		}
-
-		stv0900_write_reg(intp, TMGCFG2, 0xc1);
-
-		stv0900_set_symbol_rate(intp, intp->mclk,
-					intp->symbol_rate[demod], demod);
-		stv0900_set_max_symbol_rate(intp, intp->mclk,
-					intp->symbol_rate[demod], demod);
-		stv0900_set_min_symbol_rate(intp, intp->mclk,
-					intp->symbol_rate[demod], demod);
-		if (intp->symbol_rate[demod] >= 10000000)
-			low_sr = FALSE;
-		else
-			low_sr = TRUE;
-
-	}
-
-	if (intp->tuner_type[demod] == 3)
-		stv0900_set_tuner_auto(intp, intp->freq[demod],
-				intp->bw[demod], demod);
-	else
-		stv0900_set_tuner(fe, intp->freq[demod], intp->bw[demod]);
-
-	agc1_power = MAKEWORD(stv0900_get_bits(intp, AGCIQ_VALUE1),
-				stv0900_get_bits(intp, AGCIQ_VALUE0));
-
-	aq_power = 0;
-
-	if (agc1_power == 0) {
-		for (i = 0; i < 5; i++)
-			aq_power += (stv0900_get_bits(intp, POWER_I) +
-					stv0900_get_bits(intp, POWER_Q)) / 2;
-
-		aq_power /= 5;
-	}
-
-	if ((agc1_power == 0) && (aq_power < IQPOWER_THRESHOLD)) {
-		intp->result[demod].locked = FALSE;
-		signal_type = STV0900_NOAGC1;
-		dprintk("%s: NO AGC1, POWERI, POWERQ\n", __func__);
-	} else {
-		stv0900_write_bits(intp, SPECINV_CONTROL,
-					intp->srch_iq_inv[demod]);
-		if (intp->chip_id <= 0x20) /*cut 2.0*/
-			stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1);
-		else /*cut 3.0*/
-			stv0900_write_bits(intp, MANUALS2_ROLLOFF, 1);
-
-		stv0900_set_search_standard(intp, demod);
-
-		if (intp->srch_algo[demod] != STV0900_BLIND_SEARCH)
-			stv0900_start_search(intp, demod);
-	}
-
-	if (signal_type == STV0900_NOAGC1)
-		return signal_type;
-
-	if (intp->chip_id == 0x12) {
-		stv0900_write_bits(intp, RST_HWARE, 0);
-		msleep(3);
-		stv0900_write_bits(intp, RST_HWARE, 1);
-		stv0900_write_bits(intp, RST_HWARE, 0);
-	}
-
-	if (algo == STV0900_BLIND_SEARCH)
-		lock = stv0900_blind_search_algo(fe);
-	else if (algo == STV0900_COLD_START)
-		lock = stv0900_get_demod_cold_lock(fe, demod_timeout);
-	else if (algo == STV0900_WARM_START)
-		lock = stv0900_get_demod_lock(intp, demod, demod_timeout);
-
-	if ((lock == FALSE) && (algo == STV0900_COLD_START)) {
-		if (low_sr == FALSE) {
-			if (stv0900_check_timing_lock(intp, demod) == TRUE)
-				lock = stv0900_sw_algo(intp, demod);
-		}
-	}
-
-	if (lock == TRUE)
-		signal_type = stv0900_get_signal_params(fe);
-
-	if ((lock == TRUE) && (signal_type == STV0900_RANGEOK)) {
-		stv0900_track_optimization(fe);
-		if (intp->chip_id <= 0x11) {
-			if ((stv0900_get_standard(fe, 0) ==
-						STV0900_DVBS1_STANDARD) &&
-			   (stv0900_get_standard(fe, 1) ==
-						STV0900_DVBS1_STANDARD)) {
-				msleep(20);
-				stv0900_write_bits(intp, RST_HWARE, 0);
-			} else {
-				stv0900_write_bits(intp, RST_HWARE, 0);
-				msleep(3);
-				stv0900_write_bits(intp, RST_HWARE, 1);
-				stv0900_write_bits(intp, RST_HWARE, 0);
-			}
-
-		} else if (intp->chip_id >= 0x20) {
-			stv0900_write_bits(intp, RST_HWARE, 0);
-			msleep(3);
-			stv0900_write_bits(intp, RST_HWARE, 1);
-			stv0900_write_bits(intp, RST_HWARE, 0);
-		}
-
-		if (stv0900_wait_for_lock(intp, demod,
-					fec_timeout, fec_timeout) == TRUE) {
-			lock = TRUE;
-			intp->result[demod].locked = TRUE;
-			if (intp->result[demod].standard ==
-						STV0900_DVBS2_STANDARD) {
-				stv0900_set_dvbs2_rolloff(intp, demod);
-				stv0900_write_bits(intp, RESET_UPKO_COUNT, 1);
-				stv0900_write_bits(intp, RESET_UPKO_COUNT, 0);
-				stv0900_write_reg(intp, ERRCTRL1, 0x67);
-			} else {
-				stv0900_write_reg(intp, ERRCTRL1, 0x75);
-			}
-
-			stv0900_write_reg(intp, FBERCPT4, 0);
-			stv0900_write_reg(intp, ERRCTRL2, 0xc1);
-		} else {
-			lock = FALSE;
-			signal_type = STV0900_NODATA;
-			no_signal = stv0900_check_signal_presence(intp, demod);
-
-				intp->result[demod].locked = FALSE;
-		}
-	}
-
-	if ((signal_type != STV0900_NODATA) || (no_signal != FALSE))
-		return signal_type;
-
-	if (intp->chip_id > 0x11) {
-		intp->result[demod].locked = FALSE;
-		return signal_type;
-	}
-
-	if ((stv0900_get_bits(intp, HEADER_MODE) == STV0900_DVBS_FOUND) &&
-	   (intp->srch_iq_inv[demod] <= STV0900_IQ_AUTO_NORMAL_FIRST))
-		signal_type = stv0900_dvbs1_acq_workaround(fe);
-
-	return signal_type;
-}
-
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c
deleted file mode 100644
index ea86a56..0000000
--- a/drivers/media/dvb/frontends/stv090x.c
+++ /dev/null
@@ -1,4823 +0,0 @@
-/*
-	STV0900/0903 Multistandard Broadcast Frontend driver
-	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
-
-	Copyright (C) ST Microelectronics
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-
-#include <linux/dvb/frontend.h>
-#include "dvb_frontend.h"
-
-#include "stv6110x.h" /* for demodulator internal modes */
-
-#include "stv090x_reg.h"
-#include "stv090x.h"
-#include "stv090x_priv.h"
-
-static unsigned int verbose;
-module_param(verbose, int, 0644);
-
-/* internal params node */
-struct stv090x_dev {
-	/* pointer for internal params, one for each pair of demods */
-	struct stv090x_internal		*internal;
-	struct stv090x_dev		*next_dev;
-};
-
-/* first internal params */
-static struct stv090x_dev *stv090x_first_dev;
-
-/* find chip by i2c adapter and i2c address */
-static struct stv090x_dev *find_dev(struct i2c_adapter *i2c_adap,
-					u8 i2c_addr)
-{
-	struct stv090x_dev *temp_dev = stv090x_first_dev;
-
-	/*
-	 Search of the last stv0900 chip or
-	 find it by i2c adapter and i2c address */
-	while ((temp_dev != NULL) &&
-		((temp_dev->internal->i2c_adap != i2c_adap) ||
-		(temp_dev->internal->i2c_addr != i2c_addr))) {
-
-		temp_dev = temp_dev->next_dev;
-	}
-
-	return temp_dev;
-}
-
-/* deallocating chip */
-static void remove_dev(struct stv090x_internal *internal)
-{
-	struct stv090x_dev *prev_dev = stv090x_first_dev;
-	struct stv090x_dev *del_dev = find_dev(internal->i2c_adap,
-						internal->i2c_addr);
-
-	if (del_dev != NULL) {
-		if (del_dev == stv090x_first_dev) {
-			stv090x_first_dev = del_dev->next_dev;
-		} else {
-			while (prev_dev->next_dev != del_dev)
-				prev_dev = prev_dev->next_dev;
-
-			prev_dev->next_dev = del_dev->next_dev;
-		}
-
-		kfree(del_dev);
-	}
-}
-
-/* allocating new chip */
-static struct stv090x_dev *append_internal(struct stv090x_internal *internal)
-{
-	struct stv090x_dev *new_dev;
-	struct stv090x_dev *temp_dev;
-
-	new_dev = kmalloc(sizeof(struct stv090x_dev), GFP_KERNEL);
-	if (new_dev != NULL) {
-		new_dev->internal = internal;
-		new_dev->next_dev = NULL;
-
-		/* append to list */
-		if (stv090x_first_dev == NULL) {
-			stv090x_first_dev = new_dev;
-		} else {
-			temp_dev = stv090x_first_dev;
-			while (temp_dev->next_dev != NULL)
-				temp_dev = temp_dev->next_dev;
-
-			temp_dev->next_dev = new_dev;
-		}
-	}
-
-	return new_dev;
-}
-
-
-/* DVBS1 and DSS C/N Lookup table */
-static const struct stv090x_tab stv090x_s1cn_tab[] = {
-	{   0, 8917 }, /*  0.0dB */
-	{   5, 8801 }, /*  0.5dB */
-	{  10, 8667 }, /*  1.0dB */
-	{  15, 8522 }, /*  1.5dB */
-	{  20, 8355 }, /*  2.0dB */
-	{  25, 8175 }, /*  2.5dB */
-	{  30, 7979 }, /*  3.0dB */
-	{  35, 7763 }, /*  3.5dB */
-	{  40, 7530 }, /*  4.0dB */
-	{  45, 7282 }, /*  4.5dB */
-	{  50, 7026 }, /*  5.0dB */
-	{  55, 6781 }, /*  5.5dB */
-	{  60, 6514 }, /*  6.0dB */
-	{  65, 6241 }, /*  6.5dB */
-	{  70, 5965 }, /*  7.0dB */
-	{  75, 5690 }, /*  7.5dB */
-	{  80, 5424 }, /*  8.0dB */
-	{  85, 5161 }, /*  8.5dB */
-	{  90, 4902 }, /*  9.0dB */
-	{  95, 4654 }, /*  9.5dB */
-	{ 100, 4417 }, /* 10.0dB */
-	{ 105, 4186 }, /* 10.5dB */
-	{ 110, 3968 }, /* 11.0dB */
-	{ 115, 3757 }, /* 11.5dB */
-	{ 120, 3558 }, /* 12.0dB */
-	{ 125, 3366 }, /* 12.5dB */
-	{ 130, 3185 }, /* 13.0dB */
-	{ 135, 3012 }, /* 13.5dB */
-	{ 140, 2850 }, /* 14.0dB */
-	{ 145, 2698 }, /* 14.5dB */
-	{ 150, 2550 }, /* 15.0dB */
-	{ 160, 2283 }, /* 16.0dB */
-	{ 170, 2042 }, /* 17.0dB */
-	{ 180, 1827 }, /* 18.0dB */
-	{ 190, 1636 }, /* 19.0dB */
-	{ 200, 1466 }, /* 20.0dB */
-	{ 210, 1315 }, /* 21.0dB */
-	{ 220, 1181 }, /* 22.0dB */
-	{ 230, 1064 }, /* 23.0dB */
-	{ 240,	960 }, /* 24.0dB */
-	{ 250,	869 }, /* 25.0dB */
-	{ 260,	792 }, /* 26.0dB */
-	{ 270,	724 }, /* 27.0dB */
-	{ 280,	665 }, /* 28.0dB */
-	{ 290,	616 }, /* 29.0dB */
-	{ 300,	573 }, /* 30.0dB */
-	{ 310,	537 }, /* 31.0dB */
-	{ 320,	507 }, /* 32.0dB */
-	{ 330,	483 }, /* 33.0dB */
-	{ 400,	398 }, /* 40.0dB */
-	{ 450,	381 }, /* 45.0dB */
-	{ 500,	377 }  /* 50.0dB */
-};
-
-/* DVBS2 C/N Lookup table */
-static const struct stv090x_tab stv090x_s2cn_tab[] = {
-	{ -30, 13348 }, /* -3.0dB */
-	{ -20, 12640 }, /* -2d.0B */
-	{ -10, 11883 }, /* -1.0dB */
-	{   0, 11101 }, /* -0.0dB */
-	{   5, 10718 }, /*  0.5dB */
-	{  10, 10339 }, /*  1.0dB */
-	{  15,  9947 }, /*  1.5dB */
-	{  20,  9552 }, /*  2.0dB */
-	{  25,  9183 }, /*  2.5dB */
-	{  30,  8799 }, /*  3.0dB */
-	{  35,  8422 }, /*  3.5dB */
-	{  40,  8062 }, /*  4.0dB */
-	{  45,  7707 }, /*  4.5dB */
-	{  50,  7353 }, /*  5.0dB */
-	{  55,  7025 }, /*  5.5dB */
-	{  60,  6684 }, /*  6.0dB */
-	{  65,  6331 }, /*  6.5dB */
-	{  70,  6036 }, /*  7.0dB */
-	{  75,  5727 }, /*  7.5dB */
-	{  80,  5437 }, /*  8.0dB */
-	{  85,  5164 }, /*  8.5dB */
-	{  90,  4902 }, /*  9.0dB */
-	{  95,  4653 }, /*  9.5dB */
-	{ 100,  4408 }, /* 10.0dB */
-	{ 105,  4187 }, /* 10.5dB */
-	{ 110,  3961 }, /* 11.0dB */
-	{ 115,  3751 }, /* 11.5dB */
-	{ 120,  3558 }, /* 12.0dB */
-	{ 125,  3368 }, /* 12.5dB */
-	{ 130,  3191 }, /* 13.0dB */
-	{ 135,  3017 }, /* 13.5dB */
-	{ 140,  2862 }, /* 14.0dB */
-	{ 145,  2710 }, /* 14.5dB */
-	{ 150,  2565 }, /* 15.0dB */
-	{ 160,  2300 }, /* 16.0dB */
-	{ 170,  2058 }, /* 17.0dB */
-	{ 180,  1849 }, /* 18.0dB */
-	{ 190,  1663 }, /* 19.0dB */
-	{ 200,  1495 }, /* 20.0dB */
-	{ 210,  1349 }, /* 21.0dB */
-	{ 220,  1222 }, /* 22.0dB */
-	{ 230,  1110 }, /* 23.0dB */
-	{ 240,  1011 }, /* 24.0dB */
-	{ 250,   925 }, /* 25.0dB */
-	{ 260,   853 }, /* 26.0dB */
-	{ 270,   789 }, /* 27.0dB */
-	{ 280,   734 }, /* 28.0dB */
-	{ 290,   690 }, /* 29.0dB */
-	{ 300,   650 }, /* 30.0dB */
-	{ 310,   619 }, /* 31.0dB */
-	{ 320,   593 }, /* 32.0dB */
-	{ 330,   571 }, /* 33.0dB */
-	{ 400,   498 }, /* 40.0dB */
-	{ 450,	 484 }, /* 45.0dB */
-	{ 500,	 481 }	/* 50.0dB */
-};
-
-/* RF level C/N lookup table */
-static const struct stv090x_tab stv090x_rf_tab[] = {
-	{  -5, 0xcaa1 }, /*  -5dBm */
-	{ -10, 0xc229 }, /* -10dBm */
-	{ -15, 0xbb08 }, /* -15dBm */
-	{ -20, 0xb4bc }, /* -20dBm */
-	{ -25, 0xad5a }, /* -25dBm */
-	{ -30, 0xa298 }, /* -30dBm */
-	{ -35, 0x98a8 }, /* -35dBm */
-	{ -40, 0x8389 }, /* -40dBm */
-	{ -45, 0x59be }, /* -45dBm */
-	{ -50, 0x3a14 }, /* -50dBm */
-	{ -55, 0x2d11 }, /* -55dBm */
-	{ -60, 0x210d }, /* -60dBm */
-	{ -65, 0xa14f }, /* -65dBm */
-	{ -70, 0x07aa }	 /* -70dBm */
-};
-
-
-static struct stv090x_reg stv0900_initval[] = {
-
-	{ STV090x_OUTCFG,		0x00 },
-	{ STV090x_MODECFG,		0xff },
-	{ STV090x_AGCRF1CFG,		0x11 },
-	{ STV090x_AGCRF2CFG,		0x13 },
-	{ STV090x_TSGENERAL1X,		0x14 },
-	{ STV090x_TSTTNR2,		0x21 },
-	{ STV090x_TSTTNR4,		0x21 },
-	{ STV090x_P2_DISTXCTL,		0x22 },
-	{ STV090x_P2_F22TX,		0xc0 },
-	{ STV090x_P2_F22RX,		0xc0 },
-	{ STV090x_P2_DISRXCTL,		0x00 },
-	{ STV090x_P2_DMDCFGMD,		0xF9 },
-	{ STV090x_P2_DEMOD,		0x08 },
-	{ STV090x_P2_DMDCFG3,		0xc4 },
-	{ STV090x_P2_CARFREQ,		0xed },
-	{ STV090x_P2_LDT,		0xd0 },
-	{ STV090x_P2_LDT2,		0xb8 },
-	{ STV090x_P2_TMGCFG,		0xd2 },
-	{ STV090x_P2_TMGTHRISE,		0x20 },
-	{ STV090x_P1_TMGCFG,		0xd2 },
-
-	{ STV090x_P2_TMGTHFALL,		0x00 },
-	{ STV090x_P2_FECSPY,		0x88 },
-	{ STV090x_P2_FSPYDATA,		0x3a },
-	{ STV090x_P2_FBERCPT4,		0x00 },
-	{ STV090x_P2_FSPYBER,		0x10 },
-	{ STV090x_P2_ERRCTRL1,		0x35 },
-	{ STV090x_P2_ERRCTRL2,		0xc1 },
-	{ STV090x_P2_CFRICFG,		0xf8 },
-	{ STV090x_P2_NOSCFG,		0x1c },
-	{ STV090x_P2_DMDTOM,		0x20 },
-	{ STV090x_P2_CORRELMANT,	0x70 },
-	{ STV090x_P2_CORRELABS,		0x88 },
-	{ STV090x_P2_AGC2O,		0x5b },
-	{ STV090x_P2_AGC2REF,		0x38 },
-	{ STV090x_P2_CARCFG,		0xe4 },
-	{ STV090x_P2_ACLC,		0x1A },
-	{ STV090x_P2_BCLC,		0x09 },
-	{ STV090x_P2_CARHDR,		0x08 },
-	{ STV090x_P2_KREFTMG,		0xc1 },
-	{ STV090x_P2_SFRUPRATIO,	0xf0 },
-	{ STV090x_P2_SFRLOWRATIO,	0x70 },
-	{ STV090x_P2_SFRSTEP,		0x58 },
-	{ STV090x_P2_TMGCFG2,		0x01 },
-	{ STV090x_P2_CAR2CFG,		0x26 },
-	{ STV090x_P2_BCLC2S2Q,		0x86 },
-	{ STV090x_P2_BCLC2S28,		0x86 },
-	{ STV090x_P2_SMAPCOEF7,		0x77 },
-	{ STV090x_P2_SMAPCOEF6,		0x85 },
-	{ STV090x_P2_SMAPCOEF5,		0x77 },
-	{ STV090x_P2_TSCFGL,		0x20 },
-	{ STV090x_P2_DMDCFG2,		0x3b },
-	{ STV090x_P2_MODCODLST0,	0xff },
-	{ STV090x_P2_MODCODLST1,	0xff },
-	{ STV090x_P2_MODCODLST2,	0xff },
-	{ STV090x_P2_MODCODLST3,	0xff },
-	{ STV090x_P2_MODCODLST4,	0xff },
-	{ STV090x_P2_MODCODLST5,	0xff },
-	{ STV090x_P2_MODCODLST6,	0xff },
-	{ STV090x_P2_MODCODLST7,	0xcc },
-	{ STV090x_P2_MODCODLST8,	0xcc },
-	{ STV090x_P2_MODCODLST9,	0xcc },
-	{ STV090x_P2_MODCODLSTA,	0xcc },
-	{ STV090x_P2_MODCODLSTB,	0xcc },
-	{ STV090x_P2_MODCODLSTC,	0xcc },
-	{ STV090x_P2_MODCODLSTD,	0xcc },
-	{ STV090x_P2_MODCODLSTE,	0xcc },
-	{ STV090x_P2_MODCODLSTF,	0xcf },
-	{ STV090x_P1_DISTXCTL,		0x22 },
-	{ STV090x_P1_F22TX,		0xc0 },
-	{ STV090x_P1_F22RX,		0xc0 },
-	{ STV090x_P1_DISRXCTL,		0x00 },
-	{ STV090x_P1_DMDCFGMD,		0xf9 },
-	{ STV090x_P1_DEMOD,		0x08 },
-	{ STV090x_P1_DMDCFG3,		0xc4 },
-	{ STV090x_P1_DMDTOM,		0x20 },
-	{ STV090x_P1_CARFREQ,		0xed },
-	{ STV090x_P1_LDT,		0xd0 },
-	{ STV090x_P1_LDT2,		0xb8 },
-	{ STV090x_P1_TMGCFG,		0xd2 },
-	{ STV090x_P1_TMGTHRISE,		0x20 },
-	{ STV090x_P1_TMGTHFALL,		0x00 },
-	{ STV090x_P1_SFRUPRATIO,	0xf0 },
-	{ STV090x_P1_SFRLOWRATIO,	0x70 },
-	{ STV090x_P1_TSCFGL,		0x20 },
-	{ STV090x_P1_FECSPY,		0x88 },
-	{ STV090x_P1_FSPYDATA,		0x3a },
-	{ STV090x_P1_FBERCPT4,		0x00 },
-	{ STV090x_P1_FSPYBER,		0x10 },
-	{ STV090x_P1_ERRCTRL1,		0x35 },
-	{ STV090x_P1_ERRCTRL2,		0xc1 },
-	{ STV090x_P1_CFRICFG,		0xf8 },
-	{ STV090x_P1_NOSCFG,		0x1c },
-	{ STV090x_P1_CORRELMANT,	0x70 },
-	{ STV090x_P1_CORRELABS,		0x88 },
-	{ STV090x_P1_AGC2O,		0x5b },
-	{ STV090x_P1_AGC2REF,		0x38 },
-	{ STV090x_P1_CARCFG,		0xe4 },
-	{ STV090x_P1_ACLC,		0x1A },
-	{ STV090x_P1_BCLC,		0x09 },
-	{ STV090x_P1_CARHDR,		0x08 },
-	{ STV090x_P1_KREFTMG,		0xc1 },
-	{ STV090x_P1_SFRSTEP,		0x58 },
-	{ STV090x_P1_TMGCFG2,		0x01 },
-	{ STV090x_P1_CAR2CFG,		0x26 },
-	{ STV090x_P1_BCLC2S2Q,		0x86 },
-	{ STV090x_P1_BCLC2S28,		0x86 },
-	{ STV090x_P1_SMAPCOEF7,		0x77 },
-	{ STV090x_P1_SMAPCOEF6,		0x85 },
-	{ STV090x_P1_SMAPCOEF5,		0x77 },
-	{ STV090x_P1_DMDCFG2,		0x3b },
-	{ STV090x_P1_MODCODLST0,	0xff },
-	{ STV090x_P1_MODCODLST1,	0xff },
-	{ STV090x_P1_MODCODLST2,	0xff },
-	{ STV090x_P1_MODCODLST3,	0xff },
-	{ STV090x_P1_MODCODLST4,	0xff },
-	{ STV090x_P1_MODCODLST5,	0xff },
-	{ STV090x_P1_MODCODLST6,	0xff },
-	{ STV090x_P1_MODCODLST7,	0xcc },
-	{ STV090x_P1_MODCODLST8,	0xcc },
-	{ STV090x_P1_MODCODLST9,	0xcc },
-	{ STV090x_P1_MODCODLSTA,	0xcc },
-	{ STV090x_P1_MODCODLSTB,	0xcc },
-	{ STV090x_P1_MODCODLSTC,	0xcc },
-	{ STV090x_P1_MODCODLSTD,	0xcc },
-	{ STV090x_P1_MODCODLSTE,	0xcc },
-	{ STV090x_P1_MODCODLSTF,	0xcf },
-	{ STV090x_GENCFG,		0x1d },
-	{ STV090x_NBITER_NF4,		0x37 },
-	{ STV090x_NBITER_NF5,		0x29 },
-	{ STV090x_NBITER_NF6,		0x37 },
-	{ STV090x_NBITER_NF7,		0x33 },
-	{ STV090x_NBITER_NF8,		0x31 },
-	{ STV090x_NBITER_NF9,		0x2f },
-	{ STV090x_NBITER_NF10,		0x39 },
-	{ STV090x_NBITER_NF11,		0x3a },
-	{ STV090x_NBITER_NF12,		0x29 },
-	{ STV090x_NBITER_NF13,		0x37 },
-	{ STV090x_NBITER_NF14,		0x33 },
-	{ STV090x_NBITER_NF15,		0x2f },
-	{ STV090x_NBITER_NF16,		0x39 },
-	{ STV090x_NBITER_NF17,		0x3a },
-	{ STV090x_NBITERNOERR,		0x04 },
-	{ STV090x_GAINLLR_NF4,		0x0C },
-	{ STV090x_GAINLLR_NF5,		0x0F },
-	{ STV090x_GAINLLR_NF6,		0x11 },
-	{ STV090x_GAINLLR_NF7,		0x14 },
-	{ STV090x_GAINLLR_NF8,		0x17 },
-	{ STV090x_GAINLLR_NF9,		0x19 },
-	{ STV090x_GAINLLR_NF10,		0x20 },
-	{ STV090x_GAINLLR_NF11,		0x21 },
-	{ STV090x_GAINLLR_NF12,		0x0D },
-	{ STV090x_GAINLLR_NF13,		0x0F },
-	{ STV090x_GAINLLR_NF14,		0x13 },
-	{ STV090x_GAINLLR_NF15,		0x1A },
-	{ STV090x_GAINLLR_NF16,		0x1F },
-	{ STV090x_GAINLLR_NF17,		0x21 },
-	{ STV090x_RCCFGH,		0x20 },
-	{ STV090x_P1_FECM,		0x01 }, /* disable DSS modes */
-	{ STV090x_P2_FECM,		0x01 }, /* disable DSS modes */
-	{ STV090x_P1_PRVIT,		0x2F }, /* disable PR 6/7 */
-	{ STV090x_P2_PRVIT,		0x2F }, /* disable PR 6/7 */
-};
-
-static struct stv090x_reg stv0903_initval[] = {
-	{ STV090x_OUTCFG,		0x00 },
-	{ STV090x_AGCRF1CFG,		0x11 },
-	{ STV090x_STOPCLK1,		0x48 },
-	{ STV090x_STOPCLK2,		0x14 },
-	{ STV090x_TSTTNR1,		0x27 },
-	{ STV090x_TSTTNR2,		0x21 },
-	{ STV090x_P1_DISTXCTL,		0x22 },
-	{ STV090x_P1_F22TX,		0xc0 },
-	{ STV090x_P1_F22RX,		0xc0 },
-	{ STV090x_P1_DISRXCTL,		0x00 },
-	{ STV090x_P1_DMDCFGMD,		0xF9 },
-	{ STV090x_P1_DEMOD,		0x08 },
-	{ STV090x_P1_DMDCFG3,		0xc4 },
-	{ STV090x_P1_CARFREQ,		0xed },
-	{ STV090x_P1_TNRCFG2,		0x82 },
-	{ STV090x_P1_LDT,		0xd0 },
-	{ STV090x_P1_LDT2,		0xb8 },
-	{ STV090x_P1_TMGCFG,		0xd2 },
-	{ STV090x_P1_TMGTHRISE,		0x20 },
-	{ STV090x_P1_TMGTHFALL,		0x00 },
-	{ STV090x_P1_SFRUPRATIO,	0xf0 },
-	{ STV090x_P1_SFRLOWRATIO,	0x70 },
-	{ STV090x_P1_TSCFGL,		0x20 },
-	{ STV090x_P1_FECSPY,		0x88 },
-	{ STV090x_P1_FSPYDATA,		0x3a },
-	{ STV090x_P1_FBERCPT4,		0x00 },
-	{ STV090x_P1_FSPYBER,		0x10 },
-	{ STV090x_P1_ERRCTRL1,		0x35 },
-	{ STV090x_P1_ERRCTRL2,		0xc1 },
-	{ STV090x_P1_CFRICFG,		0xf8 },
-	{ STV090x_P1_NOSCFG,		0x1c },
-	{ STV090x_P1_DMDTOM,		0x20 },
-	{ STV090x_P1_CORRELMANT,	0x70 },
-	{ STV090x_P1_CORRELABS,		0x88 },
-	{ STV090x_P1_AGC2O,		0x5b },
-	{ STV090x_P1_AGC2REF,		0x38 },
-	{ STV090x_P1_CARCFG,		0xe4 },
-	{ STV090x_P1_ACLC,		0x1A },
-	{ STV090x_P1_BCLC,		0x09 },
-	{ STV090x_P1_CARHDR,		0x08 },
-	{ STV090x_P1_KREFTMG,		0xc1 },
-	{ STV090x_P1_SFRSTEP,		0x58 },
-	{ STV090x_P1_TMGCFG2,		0x01 },
-	{ STV090x_P1_CAR2CFG,		0x26 },
-	{ STV090x_P1_BCLC2S2Q,		0x86 },
-	{ STV090x_P1_BCLC2S28,		0x86 },
-	{ STV090x_P1_SMAPCOEF7,		0x77 },
-	{ STV090x_P1_SMAPCOEF6,		0x85 },
-	{ STV090x_P1_SMAPCOEF5,		0x77 },
-	{ STV090x_P1_DMDCFG2,		0x3b },
-	{ STV090x_P1_MODCODLST0,	0xff },
-	{ STV090x_P1_MODCODLST1,	0xff },
-	{ STV090x_P1_MODCODLST2,	0xff },
-	{ STV090x_P1_MODCODLST3,	0xff },
-	{ STV090x_P1_MODCODLST4,	0xff },
-	{ STV090x_P1_MODCODLST5,	0xff },
-	{ STV090x_P1_MODCODLST6,	0xff },
-	{ STV090x_P1_MODCODLST7,	0xcc },
-	{ STV090x_P1_MODCODLST8,	0xcc },
-	{ STV090x_P1_MODCODLST9,	0xcc },
-	{ STV090x_P1_MODCODLSTA,	0xcc },
-	{ STV090x_P1_MODCODLSTB,	0xcc },
-	{ STV090x_P1_MODCODLSTC,	0xcc },
-	{ STV090x_P1_MODCODLSTD,	0xcc },
-	{ STV090x_P1_MODCODLSTE,	0xcc },
-	{ STV090x_P1_MODCODLSTF,	0xcf },
-	{ STV090x_GENCFG,		0x1c },
-	{ STV090x_NBITER_NF4,		0x37 },
-	{ STV090x_NBITER_NF5,		0x29 },
-	{ STV090x_NBITER_NF6,		0x37 },
-	{ STV090x_NBITER_NF7,		0x33 },
-	{ STV090x_NBITER_NF8,		0x31 },
-	{ STV090x_NBITER_NF9,		0x2f },
-	{ STV090x_NBITER_NF10,		0x39 },
-	{ STV090x_NBITER_NF11,		0x3a },
-	{ STV090x_NBITER_NF12,		0x29 },
-	{ STV090x_NBITER_NF13,		0x37 },
-	{ STV090x_NBITER_NF14,		0x33 },
-	{ STV090x_NBITER_NF15,		0x2f },
-	{ STV090x_NBITER_NF16,		0x39 },
-	{ STV090x_NBITER_NF17,		0x3a },
-	{ STV090x_NBITERNOERR,		0x04 },
-	{ STV090x_GAINLLR_NF4,		0x0C },
-	{ STV090x_GAINLLR_NF5,		0x0F },
-	{ STV090x_GAINLLR_NF6,		0x11 },
-	{ STV090x_GAINLLR_NF7,		0x14 },
-	{ STV090x_GAINLLR_NF8,		0x17 },
-	{ STV090x_GAINLLR_NF9,		0x19 },
-	{ STV090x_GAINLLR_NF10,		0x20 },
-	{ STV090x_GAINLLR_NF11,		0x21 },
-	{ STV090x_GAINLLR_NF12,		0x0D },
-	{ STV090x_GAINLLR_NF13,		0x0F },
-	{ STV090x_GAINLLR_NF14,		0x13 },
-	{ STV090x_GAINLLR_NF15,		0x1A },
-	{ STV090x_GAINLLR_NF16,		0x1F },
-	{ STV090x_GAINLLR_NF17,		0x21 },
-	{ STV090x_RCCFGH,		0x20 },
-	{ STV090x_P1_FECM,		0x01 }, /*disable the DSS mode */
-	{ STV090x_P1_PRVIT,		0x2f }  /*disable puncture rate 6/7*/
-};
-
-static struct stv090x_reg stv0900_cut20_val[] = {
-
-	{ STV090x_P2_DMDCFG3,		0xe8 },
-	{ STV090x_P2_DMDCFG4,		0x10 },
-	{ STV090x_P2_CARFREQ,		0x38 },
-	{ STV090x_P2_CARHDR,		0x20 },
-	{ STV090x_P2_KREFTMG,		0x5a },
-	{ STV090x_P2_SMAPCOEF7,		0x06 },
-	{ STV090x_P2_SMAPCOEF6,		0x00 },
-	{ STV090x_P2_SMAPCOEF5,		0x04 },
-	{ STV090x_P2_NOSCFG,		0x0c },
-	{ STV090x_P1_DMDCFG3,		0xe8 },
-	{ STV090x_P1_DMDCFG4,		0x10 },
-	{ STV090x_P1_CARFREQ,		0x38 },
-	{ STV090x_P1_CARHDR,		0x20 },
-	{ STV090x_P1_KREFTMG,		0x5a },
-	{ STV090x_P1_SMAPCOEF7,		0x06 },
-	{ STV090x_P1_SMAPCOEF6,		0x00 },
-	{ STV090x_P1_SMAPCOEF5,		0x04 },
-	{ STV090x_P1_NOSCFG,		0x0c },
-	{ STV090x_GAINLLR_NF4,		0x21 },
-	{ STV090x_GAINLLR_NF5,		0x21 },
-	{ STV090x_GAINLLR_NF6,		0x20 },
-	{ STV090x_GAINLLR_NF7,		0x1F },
-	{ STV090x_GAINLLR_NF8,		0x1E },
-	{ STV090x_GAINLLR_NF9,		0x1E },
-	{ STV090x_GAINLLR_NF10,		0x1D },
-	{ STV090x_GAINLLR_NF11,		0x1B },
-	{ STV090x_GAINLLR_NF12,		0x20 },
-	{ STV090x_GAINLLR_NF13,		0x20 },
-	{ STV090x_GAINLLR_NF14,		0x20 },
-	{ STV090x_GAINLLR_NF15,		0x20 },
-	{ STV090x_GAINLLR_NF16,		0x20 },
-	{ STV090x_GAINLLR_NF17,		0x21 },
-};
-
-static struct stv090x_reg stv0903_cut20_val[] = {
-	{ STV090x_P1_DMDCFG3,		0xe8 },
-	{ STV090x_P1_DMDCFG4,		0x10 },
-	{ STV090x_P1_CARFREQ,		0x38 },
-	{ STV090x_P1_CARHDR,		0x20 },
-	{ STV090x_P1_KREFTMG,		0x5a },
-	{ STV090x_P1_SMAPCOEF7,		0x06 },
-	{ STV090x_P1_SMAPCOEF6,		0x00 },
-	{ STV090x_P1_SMAPCOEF5,		0x04 },
-	{ STV090x_P1_NOSCFG,		0x0c },
-	{ STV090x_GAINLLR_NF4,		0x21 },
-	{ STV090x_GAINLLR_NF5,		0x21 },
-	{ STV090x_GAINLLR_NF6,		0x20 },
-	{ STV090x_GAINLLR_NF7,		0x1F },
-	{ STV090x_GAINLLR_NF8,		0x1E },
-	{ STV090x_GAINLLR_NF9,		0x1E },
-	{ STV090x_GAINLLR_NF10,		0x1D },
-	{ STV090x_GAINLLR_NF11,		0x1B },
-	{ STV090x_GAINLLR_NF12,		0x20 },
-	{ STV090x_GAINLLR_NF13,		0x20 },
-	{ STV090x_GAINLLR_NF14,		0x20 },
-	{ STV090x_GAINLLR_NF15,		0x20 },
-	{ STV090x_GAINLLR_NF16,		0x20 },
-	{ STV090x_GAINLLR_NF17,		0x21 }
-};
-
-/* Cut 2.0 Long Frame Tracking CR loop */
-static struct stv090x_long_frame_crloop stv090x_s2_crl_cut20[] = {
-	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
-	{ STV090x_QPSK_12,  0x1f, 0x3f, 0x1e, 0x3f, 0x3d, 0x1f, 0x3d, 0x3e, 0x3d, 0x1e },
-	{ STV090x_QPSK_35,  0x2f, 0x3f, 0x2e, 0x2f, 0x3d, 0x0f, 0x0e, 0x2e, 0x3d, 0x0e },
-	{ STV090x_QPSK_23,  0x2f, 0x3f, 0x2e, 0x2f, 0x0e, 0x0f, 0x0e, 0x1e, 0x3d, 0x3d },
-	{ STV090x_QPSK_34,  0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
-	{ STV090x_QPSK_45,  0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
-	{ STV090x_QPSK_56,  0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
-	{ STV090x_QPSK_89,  0x3f, 0x3f, 0x3e, 0x1f, 0x1e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
-	{ STV090x_QPSK_910, 0x3f, 0x3f, 0x3e, 0x1f, 0x1e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
-	{ STV090x_8PSK_35,  0x3c, 0x3e, 0x1c, 0x2e, 0x0c, 0x1e, 0x2b, 0x2d, 0x1b, 0x1d },
-	{ STV090x_8PSK_23,  0x1d, 0x3e, 0x3c, 0x2e, 0x2c, 0x1e, 0x0c, 0x2d, 0x2b, 0x1d },
-	{ STV090x_8PSK_34,  0x0e, 0x3e, 0x3d, 0x2e, 0x0d, 0x1e, 0x2c, 0x2d, 0x0c, 0x1d },
-	{ STV090x_8PSK_56,  0x2e, 0x3e, 0x1e, 0x2e, 0x2d, 0x1e, 0x3c, 0x2d, 0x2c, 0x1d },
-	{ STV090x_8PSK_89,  0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x0d, 0x2d, 0x3c, 0x1d },
-	{ STV090x_8PSK_910, 0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x1d, 0x2d, 0x0d, 0x1d }
-};
-
-/* Cut 3.0 Long Frame Tracking CR loop */
-static	struct stv090x_long_frame_crloop stv090x_s2_crl_cut30[] = {
-	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
-	{ STV090x_QPSK_12,  0x3c, 0x2c, 0x0c, 0x2c, 0x1b, 0x2c, 0x1b, 0x1c, 0x0b, 0x3b },
-	{ STV090x_QPSK_35,  0x0d, 0x0d, 0x0c, 0x0d, 0x1b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b },
-	{ STV090x_QPSK_23,  0x1d, 0x0d, 0x0c, 0x1d, 0x2b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b },
-	{ STV090x_QPSK_34,  0x1d, 0x1d, 0x0c, 0x1d, 0x2b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b },
-	{ STV090x_QPSK_45,  0x2d, 0x1d, 0x1c, 0x1d, 0x2b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
-	{ STV090x_QPSK_56,  0x2d, 0x1d, 0x1c, 0x1d, 0x2b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
-	{ STV090x_QPSK_89,  0x3d, 0x2d, 0x1c, 0x1d, 0x3b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
-	{ STV090x_QPSK_910, 0x3d, 0x2d, 0x1c, 0x1d, 0x3b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
-	{ STV090x_8PSK_35,  0x39, 0x29, 0x39, 0x19, 0x19, 0x19, 0x19, 0x19, 0x09, 0x19 },
-	{ STV090x_8PSK_23,  0x2a, 0x39, 0x1a, 0x0a, 0x39, 0x0a, 0x29, 0x39, 0x29, 0x0a },
-	{ STV090x_8PSK_34,  0x2b, 0x3a, 0x1b, 0x1b, 0x3a, 0x1b, 0x1a, 0x0b, 0x1a, 0x3a },
-	{ STV090x_8PSK_56,  0x0c, 0x1b, 0x3b, 0x3b, 0x1b, 0x3b, 0x3a, 0x3b, 0x3a, 0x1b },
-	{ STV090x_8PSK_89,  0x0d, 0x3c, 0x2c, 0x2c, 0x2b, 0x0c, 0x0b, 0x3b, 0x0b, 0x1b },
-	{ STV090x_8PSK_910, 0x0d, 0x0d, 0x2c, 0x3c, 0x3b, 0x1c, 0x0b, 0x3b, 0x0b, 0x1b }
-};
-
-/* Cut 2.0 Long Frame Tracking CR Loop */
-static struct stv090x_long_frame_crloop stv090x_s2_apsk_crl_cut20[] = {
-	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
-	{ STV090x_16APSK_23,  0x0c, 0x0c, 0x0c, 0x0c, 0x1d, 0x0c, 0x3c, 0x0c, 0x2c, 0x0c },
-	{ STV090x_16APSK_34,  0x0c, 0x0c, 0x0c, 0x0c, 0x0e, 0x0c, 0x2d, 0x0c, 0x1d, 0x0c },
-	{ STV090x_16APSK_45,  0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x0c, 0x3d, 0x0c, 0x2d, 0x0c },
-	{ STV090x_16APSK_56,  0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x0c, 0x3d, 0x0c, 0x2d, 0x0c },
-	{ STV090x_16APSK_89,  0x0c, 0x0c, 0x0c, 0x0c, 0x2e, 0x0c, 0x0e, 0x0c, 0x3d, 0x0c },
-	{ STV090x_16APSK_910, 0x0c, 0x0c, 0x0c, 0x0c, 0x2e, 0x0c, 0x0e, 0x0c, 0x3d, 0x0c },
-	{ STV090x_32APSK_34,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
-	{ STV090x_32APSK_45,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
-	{ STV090x_32APSK_56,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
-	{ STV090x_32APSK_89,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
-	{ STV090x_32APSK_910, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }
-};
-
-/* Cut 3.0 Long Frame Tracking CR Loop */
-static struct stv090x_long_frame_crloop	stv090x_s2_apsk_crl_cut30[] = {
-	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
-	{ STV090x_16APSK_23,  0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x0a, 0x3a, 0x0a, 0x2a, 0x0a },
-	{ STV090x_16APSK_34,  0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0a, 0x3b, 0x0a, 0x1b, 0x0a },
-	{ STV090x_16APSK_45,  0x0a, 0x0a, 0x0a, 0x0a, 0x1b, 0x0a, 0x3b, 0x0a, 0x2b, 0x0a },
-	{ STV090x_16APSK_56,  0x0a, 0x0a, 0x0a, 0x0a, 0x1b, 0x0a, 0x3b, 0x0a, 0x2b, 0x0a },
-	{ STV090x_16APSK_89,  0x0a, 0x0a, 0x0a, 0x0a, 0x2b, 0x0a, 0x0c, 0x0a, 0x3b, 0x0a },
-	{ STV090x_16APSK_910, 0x0a, 0x0a, 0x0a, 0x0a, 0x2b, 0x0a, 0x0c, 0x0a, 0x3b, 0x0a },
-	{ STV090x_32APSK_34,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
-	{ STV090x_32APSK_45,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
-	{ STV090x_32APSK_56,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
-	{ STV090x_32APSK_89,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
-	{ STV090x_32APSK_910, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }
-};
-
-static struct stv090x_long_frame_crloop stv090x_s2_lowqpsk_crl_cut20[] = {
-	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
-	{ STV090x_QPSK_14,  0x0f, 0x3f, 0x0e, 0x3f, 0x2d, 0x2f, 0x2d, 0x1f, 0x3d, 0x3e },
-	{ STV090x_QPSK_13,  0x0f, 0x3f, 0x0e, 0x3f, 0x2d, 0x2f, 0x3d, 0x0f, 0x3d, 0x2e },
-	{ STV090x_QPSK_25,  0x1f, 0x3f, 0x1e, 0x3f, 0x3d, 0x1f, 0x3d, 0x3e, 0x3d, 0x2e }
-};
-
-static struct stv090x_long_frame_crloop	stv090x_s2_lowqpsk_crl_cut30[] = {
-	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
-	{ STV090x_QPSK_14,  0x0c, 0x3c, 0x0b, 0x3c, 0x2a, 0x2c, 0x2a, 0x1c, 0x3a, 0x3b },
-	{ STV090x_QPSK_13,  0x0c, 0x3c, 0x0b, 0x3c, 0x2a, 0x2c, 0x3a, 0x0c, 0x3a, 0x2b },
-	{ STV090x_QPSK_25,  0x1c, 0x3c, 0x1b, 0x3c, 0x3a, 0x1c, 0x3a, 0x3b, 0x3a, 0x2b }
-};
-
-/* Cut 2.0 Short Frame Tracking CR Loop */
-static struct stv090x_short_frame_crloop stv090x_s2_short_crl_cut20[] = {
-	/* MODCOD	  2M    5M    10M   20M   30M */
-	{ STV090x_QPSK,   0x2f, 0x2e, 0x0e, 0x0e, 0x3d },
-	{ STV090x_8PSK,   0x3e, 0x0e, 0x2d, 0x0d, 0x3c },
-	{ STV090x_16APSK, 0x1e, 0x1e, 0x1e, 0x3d, 0x2d },
-	{ STV090x_32APSK, 0x1e, 0x1e, 0x1e, 0x3d, 0x2d }
-};
-
-/* Cut 3.0 Short Frame Tracking CR Loop */
-static struct stv090x_short_frame_crloop stv090x_s2_short_crl_cut30[] = {
-	/* MODCOD  	  2M	5M    10M   20M	  30M */
-	{ STV090x_QPSK,   0x2C, 0x2B, 0x0B, 0x0B, 0x3A },
-	{ STV090x_8PSK,   0x3B, 0x0B, 0x2A, 0x0A, 0x39 },
-	{ STV090x_16APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A },
-	{ STV090x_32APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A }
-};
-
-static inline s32 comp2(s32 __x, s32 __width)
-{
-	if (__width == 32)
-		return __x;
-	else
-		return (__x >= (1 << (__width - 1))) ? (__x - (1 << __width)) : __x;
-}
-
-static int stv090x_read_reg(struct stv090x_state *state, unsigned int reg)
-{
-	const struct stv090x_config *config = state->config;
-	int ret;
-
-	u8 b0[] = { reg >> 8, reg & 0xff };
-	u8 buf;
-
-	struct i2c_msg msg[] = {
-		{ .addr	= config->address, .flags	= 0, 		.buf = b0,   .len = 2 },
-		{ .addr	= config->address, .flags	= I2C_M_RD,	.buf = &buf, .len = 1 }
-	};
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-	if (ret != 2) {
-		if (ret != -ERESTARTSYS)
-			dprintk(FE_ERROR, 1,
-				"Read error, Reg=[0x%02x], Status=%d",
-				reg, ret);
-
-		return ret < 0 ? ret : -EREMOTEIO;
-	}
-	if (unlikely(*state->verbose >= FE_DEBUGREG))
-		dprintk(FE_ERROR, 1, "Reg=[0x%02x], data=%02x",
-			reg, buf);
-
-	return (unsigned int) buf;
-}
-
-static int stv090x_write_regs(struct stv090x_state *state, unsigned int reg, u8 *data, u32 count)
-{
-	const struct stv090x_config *config = state->config;
-	int ret;
-	u8 buf[2 + count];
-	struct i2c_msg i2c_msg = { .addr = config->address, .flags = 0, .buf = buf, .len = 2 + count };
-
-	buf[0] = reg >> 8;
-	buf[1] = reg & 0xff;
-	memcpy(&buf[2], data, count);
-
-	if (unlikely(*state->verbose >= FE_DEBUGREG)) {
-		int i;
-
-		printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg);
-		for (i = 0; i < count; i++)
-			printk(" %02x", data[i]);
-		printk("\n");
-	}
-
-	ret = i2c_transfer(state->i2c, &i2c_msg, 1);
-	if (ret != 1) {
-		if (ret != -ERESTARTSYS)
-			dprintk(FE_ERROR, 1, "Reg=[0x%04x], Data=[0x%02x ...], Count=%u, Status=%d",
-				reg, data[0], count, ret);
-		return ret < 0 ? ret : -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static int stv090x_write_reg(struct stv090x_state *state, unsigned int reg, u8 data)
-{
-	return stv090x_write_regs(state, reg, &data, 1);
-}
-
-static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable)
-{
-	u32 reg;
-
-	/*
-	 * NOTE! A lock is used as a FSM to control the state in which
-	 * access is serialized between two tuners on the same demod.
-	 * This has nothing to do with a lock to protect a critical section
-	 * which may in some other cases be confused with protecting I/O
-	 * access to the demodulator gate.
-	 * In case of any error, the lock is unlocked and exit within the
-	 * relevant operations themselves.
-	 */
-	if (enable) {
-		if (state->config->tuner_i2c_lock)
-			state->config->tuner_i2c_lock(&state->frontend, 1);
-		else
-			mutex_lock(&state->internal->tuner_lock);
-	}
-
-	reg = STV090x_READ_DEMOD(state, I2CRPT);
-	if (enable) {
-		dprintk(FE_DEBUG, 1, "Enable Gate");
-		STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 1);
-		if (STV090x_WRITE_DEMOD(state, I2CRPT, reg) < 0)
-			goto err;
-
-	} else {
-		dprintk(FE_DEBUG, 1, "Disable Gate");
-		STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 0);
-		if ((STV090x_WRITE_DEMOD(state, I2CRPT, reg)) < 0)
-			goto err;
-	}
-
-	if (!enable) {
-		if (state->config->tuner_i2c_lock)
-			state->config->tuner_i2c_lock(&state->frontend, 0);
-		else
-			mutex_unlock(&state->internal->tuner_lock);
-	}
-
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	if (state->config->tuner_i2c_lock)
-		state->config->tuner_i2c_lock(&state->frontend, 0);
-	else
-		mutex_unlock(&state->internal->tuner_lock);
-	return -1;
-}
-
-static void stv090x_get_lock_tmg(struct stv090x_state *state)
-{
-	switch (state->algo) {
-	case STV090x_BLIND_SEARCH:
-		dprintk(FE_DEBUG, 1, "Blind Search");
-		if (state->srate <= 1500000) {  /*10Msps< SR <=15Msps*/
-			state->DemodTimeout = 1500;
-			state->FecTimeout = 400;
-		} else if (state->srate <= 5000000) {  /*10Msps< SR <=15Msps*/
-			state->DemodTimeout = 1000;
-			state->FecTimeout = 300;
-		} else {  /*SR >20Msps*/
-			state->DemodTimeout = 700;
-			state->FecTimeout = 100;
-		}
-		break;
-
-	case STV090x_COLD_SEARCH:
-	case STV090x_WARM_SEARCH:
-	default:
-		dprintk(FE_DEBUG, 1, "Normal Search");
-		if (state->srate <= 1000000) {  /*SR <=1Msps*/
-			state->DemodTimeout = 4500;
-			state->FecTimeout = 1700;
-		} else if (state->srate <= 2000000) { /*1Msps < SR <= 2Msps */
-			state->DemodTimeout = 2500;
-			state->FecTimeout = 1100;
-		} else if (state->srate <= 5000000) { /*2Msps < SR <= 5Msps */
-			state->DemodTimeout = 1000;
-			state->FecTimeout = 550;
-		} else if (state->srate <= 10000000) { /*5Msps < SR <= 10Msps */
-			state->DemodTimeout = 700;
-			state->FecTimeout = 250;
-		} else if (state->srate <= 20000000) { /*10Msps < SR <= 20Msps */
-			state->DemodTimeout = 400;
-			state->FecTimeout = 130;
-		} else {   /*SR >20Msps*/
-			state->DemodTimeout = 300;
-			state->FecTimeout = 100;
-		}
-		break;
-	}
-
-	if (state->algo == STV090x_WARM_SEARCH)
-		state->DemodTimeout /= 2;
-}
-
-static int stv090x_set_srate(struct stv090x_state *state, u32 srate)
-{
-	u32 sym;
-
-	if (srate > 60000000) {
-		sym  = (srate << 4); /* SR * 2^16 / master_clk */
-		sym /= (state->internal->mclk >> 12);
-	} else if (srate > 6000000) {
-		sym  = (srate << 6);
-		sym /= (state->internal->mclk >> 10);
-	} else {
-		sym  = (srate << 9);
-		sym /= (state->internal->mclk >> 7);
-	}
-
-	if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0x7f) < 0) /* MSB */
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, SFRINIT0, (sym & 0xff)) < 0) /* LSB */
-		goto err;
-
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_set_max_srate(struct stv090x_state *state, u32 clk, u32 srate)
-{
-	u32 sym;
-
-	srate = 105 * (srate / 100);
-	if (srate > 60000000) {
-		sym  = (srate << 4); /* SR * 2^16 / master_clk */
-		sym /= (state->internal->mclk >> 12);
-	} else if (srate > 6000000) {
-		sym  = (srate << 6);
-		sym /= (state->internal->mclk >> 10);
-	} else {
-		sym  = (srate << 9);
-		sym /= (state->internal->mclk >> 7);
-	}
-
-	if (sym < 0x7fff) {
-		if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0) /* MSB */
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0) /* LSB */
-			goto err;
-	} else {
-		if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x7f) < 0) /* MSB */
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xff) < 0) /* LSB */
-			goto err;
-	}
-
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_set_min_srate(struct stv090x_state *state, u32 clk, u32 srate)
-{
-	u32 sym;
-
-	srate = 95 * (srate / 100);
-	if (srate > 60000000) {
-		sym  = (srate << 4); /* SR * 2^16 / master_clk */
-		sym /= (state->internal->mclk >> 12);
-	} else if (srate > 6000000) {
-		sym  = (srate << 6);
-		sym /= (state->internal->mclk >> 10);
-	} else {
-		sym  = (srate << 9);
-		sym /= (state->internal->mclk >> 7);
-	}
-
-	if (STV090x_WRITE_DEMOD(state, SFRLOW1, ((sym >> 8) & 0x7f)) < 0) /* MSB */
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, SFRLOW0, (sym & 0xff)) < 0) /* LSB */
-		goto err;
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static u32 stv090x_car_width(u32 srate, enum stv090x_rolloff rolloff)
-{
-	u32 ro;
-
-	switch (rolloff) {
-	case STV090x_RO_20:
-		ro = 20;
-		break;
-	case STV090x_RO_25:
-		ro = 25;
-		break;
-	case STV090x_RO_35:
-	default:
-		ro = 35;
-		break;
-	}
-
-	return srate + (srate * ro) / 100;
-}
-
-static int stv090x_set_vit_thacq(struct stv090x_state *state)
-{
-	if (STV090x_WRITE_DEMOD(state, VTH12, 0x96) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, VTH23, 0x64) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, VTH34, 0x36) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, VTH56, 0x23) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, VTH67, 0x1e) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, VTH78, 0x19) < 0)
-		goto err;
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_set_vit_thtracq(struct stv090x_state *state)
-{
-	if (STV090x_WRITE_DEMOD(state, VTH12, 0xd0) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, VTH23, 0x7d) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, VTH34, 0x53) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, VTH56, 0x2f) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, VTH67, 0x24) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, VTH78, 0x1f) < 0)
-		goto err;
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_set_viterbi(struct stv090x_state *state)
-{
-	switch (state->search_mode) {
-	case STV090x_SEARCH_AUTO:
-		if (STV090x_WRITE_DEMOD(state, FECM, 0x10) < 0) /* DVB-S and DVB-S2 */
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, PRVIT, 0x3f) < 0) /* all puncture rate */
-			goto err;
-		break;
-	case STV090x_SEARCH_DVBS1:
-		if (STV090x_WRITE_DEMOD(state, FECM, 0x00) < 0) /* disable DSS */
-			goto err;
-		switch (state->fec) {
-		case STV090x_PR12:
-			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x01) < 0)
-				goto err;
-			break;
-
-		case STV090x_PR23:
-			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x02) < 0)
-				goto err;
-			break;
-
-		case STV090x_PR34:
-			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x04) < 0)
-				goto err;
-			break;
-
-		case STV090x_PR56:
-			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x08) < 0)
-				goto err;
-			break;
-
-		case STV090x_PR78:
-			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x20) < 0)
-				goto err;
-			break;
-
-		default:
-			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x2f) < 0) /* all */
-				goto err;
-			break;
-		}
-		break;
-	case STV090x_SEARCH_DSS:
-		if (STV090x_WRITE_DEMOD(state, FECM, 0x80) < 0)
-			goto err;
-		switch (state->fec) {
-		case STV090x_PR12:
-			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x01) < 0)
-				goto err;
-			break;
-
-		case STV090x_PR23:
-			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x02) < 0)
-				goto err;
-			break;
-
-		case STV090x_PR67:
-			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x10) < 0)
-				goto err;
-			break;
-
-		default:
-			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x13) < 0) /* 1/2, 2/3, 6/7 */
-				goto err;
-			break;
-		}
-		break;
-	default:
-		break;
-	}
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_stop_modcod(struct stv090x_state *state)
-{
-	if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xff) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xff) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xff) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xff) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xff) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xff) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xff) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xff) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xff) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xff) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xff) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xff) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xff) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xff) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xff) < 0)
-		goto err;
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_activate_modcod(struct stv090x_state *state)
-{
-	if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xfc) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xcc) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xcc) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xcc) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xcc) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xcc) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xcc) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xcc) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xcc) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xcc) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xcc) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xcc) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xcc) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xcc) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xcf) < 0)
-		goto err;
-
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_activate_modcod_single(struct stv090x_state *state)
-{
-
-	if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xf0) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0x00) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0x00) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0x00) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0x00) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0x00) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0x00) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0x00) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0x00) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0x00) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0x00) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0x00) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0x00) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0x00) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0x0f) < 0)
-		goto err;
-
-	return 0;
-
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_vitclk_ctl(struct stv090x_state *state, int enable)
-{
-	u32 reg;
-
-	switch (state->demod) {
-	case STV090x_DEMODULATOR_0:
-		mutex_lock(&state->internal->demod_lock);
-		reg = stv090x_read_reg(state, STV090x_STOPCLK2);
-		STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, enable);
-		if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
-			goto err;
-		mutex_unlock(&state->internal->demod_lock);
-		break;
-
-	case STV090x_DEMODULATOR_1:
-		mutex_lock(&state->internal->demod_lock);
-		reg = stv090x_read_reg(state, STV090x_STOPCLK2);
-		STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, enable);
-		if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
-			goto err;
-		mutex_unlock(&state->internal->demod_lock);
-		break;
-
-	default:
-		dprintk(FE_ERROR, 1, "Wrong demodulator!");
-		break;
-	}
-	return 0;
-err:
-	mutex_unlock(&state->internal->demod_lock);
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_dvbs_track_crl(struct stv090x_state *state)
-{
-	if (state->internal->dev_ver >= 0x30) {
-		/* Set ACLC BCLC optimised value vs SR */
-		if (state->srate >= 15000000) {
-			if (STV090x_WRITE_DEMOD(state, ACLC, 0x2b) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, BCLC, 0x1a) < 0)
-				goto err;
-		} else if ((state->srate >= 7000000) && (15000000 > state->srate)) {
-			if (STV090x_WRITE_DEMOD(state, ACLC, 0x0c) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, BCLC, 0x1b) < 0)
-				goto err;
-		} else if (state->srate < 7000000) {
-			if (STV090x_WRITE_DEMOD(state, ACLC, 0x2c) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, BCLC, 0x1c) < 0)
-				goto err;
-		}
-
-	} else {
-		/* Cut 2.0 */
-		if (STV090x_WRITE_DEMOD(state, ACLC, 0x1a) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0)
-			goto err;
-	}
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_delivery_search(struct stv090x_state *state)
-{
-	u32 reg;
-
-	switch (state->search_mode) {
-	case STV090x_SEARCH_DVBS1:
-	case STV090x_SEARCH_DSS:
-		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
-		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
-		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
-		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
-			goto err;
-
-		/* Activate Viterbi decoder in legacy search,
-		 * do not use FRESVIT1, might impact VITERBI2
-		 */
-		if (stv090x_vitclk_ctl(state, 0) < 0)
-			goto err;
-
-		if (stv090x_dvbs_track_crl(state) < 0)
-			goto err;
-
-		if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x22) < 0) /* disable DVB-S2 */
-			goto err;
-
-		if (stv090x_set_vit_thacq(state) < 0)
-			goto err;
-		if (stv090x_set_viterbi(state) < 0)
-			goto err;
-		break;
-
-	case STV090x_SEARCH_DVBS2:
-		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
-		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
-		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
-		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
-			goto err;
-		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
-		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
-		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
-			goto err;
-
-		if (stv090x_vitclk_ctl(state, 1) < 0)
-			goto err;
-
-		if (STV090x_WRITE_DEMOD(state, ACLC, 0x1a) < 0) /* stop DVB-S CR loop */
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0)
-			goto err;
-
-		if (state->internal->dev_ver <= 0x20) {
-			/* enable S2 carrier loop */
-			if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0)
-				goto err;
-		} else {
-			/* > Cut 3: Stop carrier 3 */
-			if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x66) < 0)
-				goto err;
-		}
-
-		if (state->demod_mode != STV090x_SINGLE) {
-			/* Cut 2: enable link during search */
-			if (stv090x_activate_modcod(state) < 0)
-				goto err;
-		} else {
-			/* Single demodulator
-			 * Authorize SHORT and LONG frames,
-			 * QPSK, 8PSK, 16APSK and 32APSK
-			 */
-			if (stv090x_activate_modcod_single(state) < 0)
-				goto err;
-		}
-
-		if (stv090x_set_vit_thtracq(state) < 0)
-			goto err;
-		break;
-
-	case STV090x_SEARCH_AUTO:
-	default:
-		/* enable DVB-S2 and DVB-S2 in Auto MODE */
-		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
-		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
-		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
-		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
-			goto err;
-		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
-		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
-		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
-			goto err;
-
-		if (stv090x_vitclk_ctl(state, 0) < 0)
-			goto err;
-
-		if (stv090x_dvbs_track_crl(state) < 0)
-			goto err;
-
-		if (state->internal->dev_ver <= 0x20) {
-			/* enable S2 carrier loop */
-			if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0)
-				goto err;
-		} else {
-			/* > Cut 3: Stop carrier 3 */
-			if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x66) < 0)
-				goto err;
-		}
-
-		if (state->demod_mode != STV090x_SINGLE) {
-			/* Cut 2: enable link during search */
-			if (stv090x_activate_modcod(state) < 0)
-				goto err;
-		} else {
-			/* Single demodulator
-			 * Authorize SHORT and LONG frames,
-			 * QPSK, 8PSK, 16APSK and 32APSK
-			 */
-			if (stv090x_activate_modcod_single(state) < 0)
-				goto err;
-		}
-
-		if (stv090x_set_vit_thacq(state) < 0)
-			goto err;
-
-		if (stv090x_set_viterbi(state) < 0)
-			goto err;
-		break;
-	}
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_start_search(struct stv090x_state *state)
-{
-	u32 reg, freq_abs;
-	s16 freq;
-
-	/* Reset demodulator */
-	reg = STV090x_READ_DEMOD(state, DMDISTATE);
-	STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f);
-	if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0)
-		goto err;
-
-	if (state->internal->dev_ver <= 0x20) {
-		if (state->srate <= 5000000) {
-			if (STV090x_WRITE_DEMOD(state, CARCFG, 0x44) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, CFRUP1, 0x0f) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, CFRUP0, 0xff) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, CFRLOW1, 0xf0) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, CFRLOW0, 0x00) < 0)
-				goto err;
-
-			/*enlarge the timing bandwidth for Low SR*/
-			if (STV090x_WRITE_DEMOD(state, RTCS2, 0x68) < 0)
-				goto err;
-		} else {
-			/* If the symbol rate is >5 Msps
-			Set The carrier search up and low to auto mode */
-			if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0)
-				goto err;
-			/*reduce the timing bandwidth for high SR*/
-			if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0)
-				goto err;
-		}
-	} else {
-		/* >= Cut 3 */
-		if (state->srate <= 5000000) {
-			/* enlarge the timing bandwidth for Low SR */
-			STV090x_WRITE_DEMOD(state, RTCS2, 0x68);
-		} else {
-			/* reduce timing bandwidth for high SR */
-			STV090x_WRITE_DEMOD(state, RTCS2, 0x44);
-		}
-
-		/* Set CFR min and max to manual mode */
-		STV090x_WRITE_DEMOD(state, CARCFG, 0x46);
-
-		if (state->algo == STV090x_WARM_SEARCH) {
-			/* WARM Start
-			 * CFR min = -1MHz,
-			 * CFR max = +1MHz
-			 */
-			freq_abs  = 1000 << 16;
-			freq_abs /= (state->internal->mclk / 1000);
-			freq      = (s16) freq_abs;
-		} else {
-			/* COLD Start
-			 * CFR min =- (SearchRange / 2 + 600KHz)
-			 * CFR max = +(SearchRange / 2 + 600KHz)
-			 * (600KHz for the tuner step size)
-			 */
-			freq_abs  = (state->search_range / 2000) + 600;
-			freq_abs  = freq_abs << 16;
-			freq_abs /= (state->internal->mclk / 1000);
-			freq      = (s16) freq_abs;
-		}
-
-		if (STV090x_WRITE_DEMOD(state, CFRUP1, MSB(freq)) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, CFRUP0, LSB(freq)) < 0)
-			goto err;
-
-		freq *= -1;
-
-		if (STV090x_WRITE_DEMOD(state, CFRLOW1, MSB(freq)) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, CFRLOW0, LSB(freq)) < 0)
-			goto err;
-
-	}
-
-	if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0) < 0)
-		goto err;
-
-	if (state->internal->dev_ver >= 0x20) {
-		if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0)
-			goto err;
-
-		if ((state->search_mode == STV090x_SEARCH_DVBS1)	||
-			(state->search_mode == STV090x_SEARCH_DSS)	||
-			(state->search_mode == STV090x_SEARCH_AUTO)) {
-
-			if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x00) < 0)
-				goto err;
-		}
-	}
-
-	if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xe0) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xc0) < 0)
-		goto err;
-
-	reg = STV090x_READ_DEMOD(state, DMDCFGMD);
-	STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0);
-	STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0);
-	if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
-		goto err;
-	reg = STV090x_READ_DEMOD(state, DMDCFG2);
-	STV090x_SETFIELD_Px(reg, S1S2_SEQUENTIAL_FIELD, 0x0);
-	if (STV090x_WRITE_DEMOD(state, DMDCFG2, reg) < 0)
-		goto err;
-
-	if (STV090x_WRITE_DEMOD(state, RTC, 0x88) < 0)
-		goto err;
-
-	if (state->internal->dev_ver >= 0x20) {
-		/*Frequency offset detector setting*/
-		if (state->srate < 2000000) {
-			if (state->internal->dev_ver <= 0x20) {
-				/* Cut 2 */
-				if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x39) < 0)
-					goto err;
-			} else {
-				/* Cut 3 */
-				if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x89) < 0)
-					goto err;
-			}
-			if (STV090x_WRITE_DEMOD(state, CARHDR, 0x40) < 0)
-				goto err;
-		} else if (state->srate < 10000000) {
-			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4c) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, CARHDR, 0x20) < 0)
-				goto err;
-		} else {
-			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4b) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, CARHDR, 0x20) < 0)
-				goto err;
-		}
-	} else {
-		if (state->srate < 10000000) {
-			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0xef) < 0)
-				goto err;
-		} else {
-			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0xed) < 0)
-				goto err;
-		}
-	}
-
-	switch (state->algo) {
-	case STV090x_WARM_SEARCH:
-		/* The symbol rate and the exact
-		 * carrier Frequency are known
-		 */
-		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
-			goto err;
-		break;
-
-	case STV090x_COLD_SEARCH:
-		/* The symbol rate is known */
-		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
-			goto err;
-		break;
-
-	default:
-		break;
-	}
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_get_agc2_min_level(struct stv090x_state *state)
-{
-	u32 agc2_min = 0xffff, agc2 = 0, freq_init, freq_step, reg;
-	s32 i, j, steps, dir;
-
-	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
-		goto err;
-	reg = STV090x_READ_DEMOD(state, DMDCFGMD);
-	STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0);
-	STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0);
-	if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
-		goto err;
-
-	if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x83) < 0) /* SR = 65 Msps Max */
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xc0) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x82) < 0) /* SR= 400 ksps Min */
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, SFRLOW0, 0xa0) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0) /* stop acq @ coarse carrier state */
-		goto err;
-	if (stv090x_set_srate(state, 1000000) < 0)
-		goto err;
-
-	steps  = state->search_range / 1000000;
-	if (steps <= 0)
-		steps = 1;
-
-	dir = 1;
-	freq_step = (1000000 * 256) / (state->internal->mclk / 256);
-	freq_init = 0;
-
-	for (i = 0; i < steps; i++) {
-		if (dir > 0)
-			freq_init = freq_init + (freq_step * i);
-		else
-			freq_init = freq_init - (freq_step * i);
-
-		dir *= -1;
-
-		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod RESET */
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, CFRINIT1, (freq_init >> 8) & 0xff) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, CFRINIT0, freq_init & 0xff) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x58) < 0) /* Demod RESET */
-			goto err;
-		msleep(10);
-
-		agc2 = 0;
-		for (j = 0; j < 10; j++) {
-			agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) |
-				STV090x_READ_DEMOD(state, AGC2I0);
-		}
-		agc2 /= 10;
-		if (agc2 < agc2_min)
-			agc2_min = agc2;
-	}
-
-	return agc2_min;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static u32 stv090x_get_srate(struct stv090x_state *state, u32 clk)
-{
-	u8 r3, r2, r1, r0;
-	s32 srate, int_1, int_2, tmp_1, tmp_2;
-
-	r3 = STV090x_READ_DEMOD(state, SFR3);
-	r2 = STV090x_READ_DEMOD(state, SFR2);
-	r1 = STV090x_READ_DEMOD(state, SFR1);
-	r0 = STV090x_READ_DEMOD(state, SFR0);
-
-	srate = ((r3 << 24) | (r2 << 16) | (r1 <<  8) | r0);
-
-	int_1 = clk >> 16;
-	int_2 = srate >> 16;
-
-	tmp_1 = clk % 0x10000;
-	tmp_2 = srate % 0x10000;
-
-	srate = (int_1 * int_2) +
-		((int_1 * tmp_2) >> 16) +
-		((int_2 * tmp_1) >> 16);
-
-	return srate;
-}
-
-static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
-{
-	struct dvb_frontend *fe = &state->frontend;
-
-	int tmg_lock = 0, i;
-	s32 tmg_cpt = 0, dir = 1, steps, cur_step = 0, freq;
-	u32 srate_coarse = 0, agc2 = 0, car_step = 1200, reg;
-	u32 agc2th;
-
-	if (state->internal->dev_ver >= 0x30)
-		agc2th = 0x2e00;
-	else
-		agc2th = 0x1f00;
-
-	reg = STV090x_READ_DEMOD(state, DMDISTATE);
-	STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f); /* Demod RESET */
-	if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, TMGCFG, 0x12) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc0) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xf0) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xe0) < 0)
-		goto err;
-	reg = STV090x_READ_DEMOD(state, DMDCFGMD);
-	STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 1);
-	STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0);
-	if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
-		goto err;
-
-	if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x83) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xc0) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x82) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, SFRLOW0, 0xa0) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x50) < 0)
-		goto err;
-
-	if (state->internal->dev_ver >= 0x30) {
-		if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x99) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x98) < 0)
-			goto err;
-
-	} else if (state->internal->dev_ver >= 0x20) {
-		if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x6a) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x95) < 0)
-			goto err;
-	}
-
-	if (state->srate <= 2000000)
-		car_step = 1000;
-	else if (state->srate <= 5000000)
-		car_step = 2000;
-	else if (state->srate <= 12000000)
-		car_step = 3000;
-	else
-		car_step = 5000;
-
-	steps  = -1 + ((state->search_range / 1000) / car_step);
-	steps /= 2;
-	steps  = (2 * steps) + 1;
-	if (steps < 0)
-		steps = 1;
-	else if (steps > 10) {
-		steps = 11;
-		car_step = (state->search_range / 1000) / 10;
-	}
-	cur_step = 0;
-	dir = 1;
-	freq = state->frequency;
-
-	while ((!tmg_lock) && (cur_step < steps)) {
-		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5f) < 0) /* Demod RESET */
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, SFRINIT1, 0x00) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, SFRINIT0, 0x00) < 0)
-			goto err;
-		/* trigger acquisition */
-		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x40) < 0)
-			goto err;
-		msleep(50);
-		for (i = 0; i < 10; i++) {
-			reg = STV090x_READ_DEMOD(state, DSTATUS);
-			if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2)
-				tmg_cpt++;
-			agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) |
-				STV090x_READ_DEMOD(state, AGC2I0);
-		}
-		agc2 /= 10;
-		srate_coarse = stv090x_get_srate(state, state->internal->mclk);
-		cur_step++;
-		dir *= -1;
-		if ((tmg_cpt >= 5) && (agc2 < agc2th) &&
-		    (srate_coarse < 50000000) && (srate_coarse > 850000))
-			tmg_lock = 1;
-		else if (cur_step < steps) {
-			if (dir > 0)
-				freq += cur_step * car_step;
-			else
-				freq -= cur_step * car_step;
-
-			/* Setup tuner */
-			if (stv090x_i2c_gate_ctrl(state, 1) < 0)
-				goto err;
-
-			if (state->config->tuner_set_frequency) {
-				if (state->config->tuner_set_frequency(fe, freq) < 0)
-					goto err_gateoff;
-			}
-
-			if (state->config->tuner_set_bandwidth) {
-				if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
-					goto err_gateoff;
-			}
-
-			if (stv090x_i2c_gate_ctrl(state, 0) < 0)
-				goto err;
-
-			msleep(50);
-
-			if (stv090x_i2c_gate_ctrl(state, 1) < 0)
-				goto err;
-
-			if (state->config->tuner_get_status) {
-				if (state->config->tuner_get_status(fe, &reg) < 0)
-					goto err_gateoff;
-			}
-
-			if (reg)
-				dprintk(FE_DEBUG, 1, "Tuner phase locked");
-			else
-				dprintk(FE_DEBUG, 1, "Tuner unlocked");
-
-			if (stv090x_i2c_gate_ctrl(state, 0) < 0)
-				goto err;
-
-		}
-	}
-	if (!tmg_lock)
-		srate_coarse = 0;
-	else
-		srate_coarse = stv090x_get_srate(state, state->internal->mclk);
-
-	return srate_coarse;
-
-err_gateoff:
-	stv090x_i2c_gate_ctrl(state, 0);
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static u32 stv090x_srate_srch_fine(struct stv090x_state *state)
-{
-	u32 srate_coarse, freq_coarse, sym, reg;
-
-	srate_coarse = stv090x_get_srate(state, state->internal->mclk);
-	freq_coarse  = STV090x_READ_DEMOD(state, CFR2) << 8;
-	freq_coarse |= STV090x_READ_DEMOD(state, CFR1);
-	sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
-
-	if (sym < state->srate)
-		srate_coarse = 0;
-	else {
-		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) /* Demod RESET */
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0x00) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, TMGCFG, 0xd2) < 0)
-			goto err;
-		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
-		STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00);
-		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
-			goto err;
-
-		if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
-			goto err;
-
-		if (state->internal->dev_ver >= 0x30) {
-			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x79) < 0)
-				goto err;
-		} else if (state->internal->dev_ver >= 0x20) {
-			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
-				goto err;
-		}
-
-		if (srate_coarse > 3000000) {
-			sym  = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
-			sym  = (sym / 1000) * 65536;
-			sym /= (state->internal->mclk / 1000);
-			if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0)
-				goto err;
-			sym  = 10 * (srate_coarse / 13); /* SFRLOW = SFR - 30% */
-			sym  = (sym / 1000) * 65536;
-			sym /= (state->internal->mclk / 1000);
-			if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0)
-				goto err;
-			sym  = (srate_coarse / 1000) * 65536;
-			sym /= (state->internal->mclk / 1000);
-			if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0)
-				goto err;
-		} else {
-			sym  = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
-			sym  = (sym / 100) * 65536;
-			sym /= (state->internal->mclk / 100);
-			if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0)
-				goto err;
-			sym  = 10 * (srate_coarse / 14); /* SFRLOW = SFR - 30% */
-			sym  = (sym / 100) * 65536;
-			sym /= (state->internal->mclk / 100);
-			if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0)
-				goto err;
-			sym  = (srate_coarse / 100) * 65536;
-			sym /= (state->internal->mclk / 100);
-			if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0)
-				goto err;
-		}
-		if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x20) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, CFRINIT1, (freq_coarse >> 8) & 0xff) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, CFRINIT0, freq_coarse & 0xff) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) /* trigger acquisition */
-			goto err;
-	}
-
-	return srate_coarse;
-
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_get_dmdlock(struct stv090x_state *state, s32 timeout)
-{
-	s32 timer = 0, lock = 0;
-	u32 reg;
-	u8 stat;
-
-	while ((timer < timeout) && (!lock)) {
-		reg = STV090x_READ_DEMOD(state, DMDSTATE);
-		stat = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD);
-
-		switch (stat) {
-		case 0: /* searching */
-		case 1: /* first PLH detected */
-		default:
-			dprintk(FE_DEBUG, 1, "Demodulator searching ..");
-			lock = 0;
-			break;
-		case 2: /* DVB-S2 mode */
-		case 3: /* DVB-S1/legacy mode */
-			reg = STV090x_READ_DEMOD(state, DSTATUS);
-			lock = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD);
-			break;
-		}
-
-		if (!lock)
-			msleep(10);
-		else
-			dprintk(FE_DEBUG, 1, "Demodulator acquired LOCK");
-
-		timer += 10;
-	}
-	return lock;
-}
-
-static int stv090x_blind_search(struct stv090x_state *state)
-{
-	u32 agc2, reg, srate_coarse;
-	s32 cpt_fail, agc2_ovflw, i;
-	u8 k_ref, k_max, k_min;
-	int coarse_fail = 0;
-	int lock;
-
-	k_max = 110;
-	k_min = 10;
-
-	agc2 = stv090x_get_agc2_min_level(state);
-
-	if (agc2 > STV090x_SEARCH_AGC2_TH(state->internal->dev_ver)) {
-		lock = 0;
-	} else {
-
-		if (state->internal->dev_ver <= 0x20) {
-			if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0)
-				goto err;
-		} else {
-			/* > Cut 3 */
-			if (STV090x_WRITE_DEMOD(state, CARCFG, 0x06) < 0)
-				goto err;
-		}
-
-		if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0)
-			goto err;
-
-		if (state->internal->dev_ver >= 0x20) {
-			if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x00) < 0) /* set viterbi hysteresis */
-				goto err;
-		}
-
-		k_ref = k_max;
-		do {
-			if (STV090x_WRITE_DEMOD(state, KREFTMG, k_ref) < 0)
-				goto err;
-			if (stv090x_srate_srch_coarse(state) != 0) {
-				srate_coarse = stv090x_srate_srch_fine(state);
-				if (srate_coarse != 0) {
-					stv090x_get_lock_tmg(state);
-					lock = stv090x_get_dmdlock(state,
-							state->DemodTimeout);
-				} else {
-					lock = 0;
-				}
-			} else {
-				cpt_fail = 0;
-				agc2_ovflw = 0;
-				for (i = 0; i < 10; i++) {
-					agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) |
-						STV090x_READ_DEMOD(state, AGC2I0);
-					if (agc2 >= 0xff00)
-						agc2_ovflw++;
-					reg = STV090x_READ_DEMOD(state, DSTATUS2);
-					if ((STV090x_GETFIELD_Px(reg, CFR_OVERFLOW_FIELD) == 0x01) &&
-					    (STV090x_GETFIELD_Px(reg, DEMOD_DELOCK_FIELD) == 0x01))
-
-						cpt_fail++;
-				}
-				if ((cpt_fail > 7) || (agc2_ovflw > 7))
-					coarse_fail = 1;
-
-				lock = 0;
-			}
-			k_ref -= 20;
-		} while ((k_ref >= k_min) && (!lock) && (!coarse_fail));
-	}
-
-	return lock;
-
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_chk_tmg(struct stv090x_state *state)
-{
-	u32 reg;
-	s32 tmg_cpt = 0, i;
-	u8 freq, tmg_thh, tmg_thl;
-	int tmg_lock = 0;
-
-	freq = STV090x_READ_DEMOD(state, CARFREQ);
-	tmg_thh = STV090x_READ_DEMOD(state, TMGTHRISE);
-	tmg_thl = STV090x_READ_DEMOD(state, TMGTHFALL);
-	if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0x00) < 0)
-		goto err;
-
-	reg = STV090x_READ_DEMOD(state, DMDCFGMD);
-	STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00); /* stop carrier offset search */
-	if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, RTC, 0x80) < 0)
-		goto err;
-
-	if (STV090x_WRITE_DEMOD(state, RTCS2, 0x40) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x00) < 0)
-		goto err;
-
-	if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0) /* set car ofset to 0 */
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x65) < 0)
-		goto err;
-
-	if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) /* trigger acquisition */
-		goto err;
-	msleep(10);
-
-	for (i = 0; i < 10; i++) {
-		reg = STV090x_READ_DEMOD(state, DSTATUS);
-		if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2)
-			tmg_cpt++;
-		msleep(1);
-	}
-	if (tmg_cpt >= 3)
-		tmg_lock = 1;
-
-	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, RTC, 0x88) < 0) /* DVB-S1 timing */
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, RTCS2, 0x68) < 0) /* DVB-S2 timing */
-		goto err;
-
-	if (STV090x_WRITE_DEMOD(state, CARFREQ, freq) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, TMGTHRISE, tmg_thh) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, TMGTHFALL, tmg_thl) < 0)
-		goto err;
-
-	return	tmg_lock;
-
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd)
-{
-	struct dvb_frontend *fe = &state->frontend;
-
-	u32 reg;
-	s32 car_step, steps, cur_step, dir, freq, timeout_lock;
-	int lock = 0;
-
-	if (state->srate >= 10000000)
-		timeout_lock = timeout_dmd / 3;
-	else
-		timeout_lock = timeout_dmd / 2;
-
-	lock = stv090x_get_dmdlock(state, timeout_lock); /* cold start wait */
-	if (!lock) {
-		if (state->srate >= 10000000) {
-			if (stv090x_chk_tmg(state)) {
-				if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
-					goto err;
-				if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
-					goto err;
-				lock = stv090x_get_dmdlock(state, timeout_dmd);
-			} else {
-				lock = 0;
-			}
-		} else {
-			if (state->srate <= 4000000)
-				car_step = 1000;
-			else if (state->srate <= 7000000)
-				car_step = 2000;
-			else if (state->srate <= 10000000)
-				car_step = 3000;
-			else
-				car_step = 5000;
-
-			steps  = (state->search_range / 1000) / car_step;
-			steps /= 2;
-			steps  = 2 * (steps + 1);
-			if (steps < 0)
-				steps = 2;
-			else if (steps > 12)
-				steps = 12;
-
-			cur_step = 1;
-			dir = 1;
-
-			if (!lock) {
-				freq = state->frequency;
-				state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + state->srate;
-				while ((cur_step <= steps) && (!lock)) {
-					if (dir > 0)
-						freq += cur_step * car_step;
-					else
-						freq -= cur_step * car_step;
-
-					/* Setup tuner */
-					if (stv090x_i2c_gate_ctrl(state, 1) < 0)
-						goto err;
-
-					if (state->config->tuner_set_frequency) {
-						if (state->config->tuner_set_frequency(fe, freq) < 0)
-							goto err_gateoff;
-					}
-
-					if (state->config->tuner_set_bandwidth) {
-						if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
-							goto err_gateoff;
-					}
-
-					if (stv090x_i2c_gate_ctrl(state, 0) < 0)
-						goto err;
-
-					msleep(50);
-
-					if (stv090x_i2c_gate_ctrl(state, 1) < 0)
-						goto err;
-
-					if (state->config->tuner_get_status) {
-						if (state->config->tuner_get_status(fe, &reg) < 0)
-							goto err_gateoff;
-					}
-
-					if (reg)
-						dprintk(FE_DEBUG, 1, "Tuner phase locked");
-					else
-						dprintk(FE_DEBUG, 1, "Tuner unlocked");
-
-					if (stv090x_i2c_gate_ctrl(state, 0) < 0)
-						goto err;
-
-					STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c);
-					if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0)
-						goto err;
-					if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
-						goto err;
-					if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
-						goto err;
-					if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
-						goto err;
-					lock = stv090x_get_dmdlock(state, (timeout_dmd / 3));
-
-					dir *= -1;
-					cur_step++;
-				}
-			}
-		}
-	}
-
-	return lock;
-
-err_gateoff:
-	stv090x_i2c_gate_ctrl(state, 0);
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_get_loop_params(struct stv090x_state *state, s32 *freq_inc, s32 *timeout_sw, s32 *steps)
-{
-	s32 timeout, inc, steps_max, srate, car_max;
-
-	srate = state->srate;
-	car_max = state->search_range / 1000;
-	car_max += car_max / 10;
-	car_max  = 65536 * (car_max / 2);
-	car_max /= (state->internal->mclk / 1000);
-
-	if (car_max > 0x4000)
-		car_max = 0x4000 ; /* maxcarrier should be<= +-1/4 Mclk */
-
-	inc  = srate;
-	inc /= state->internal->mclk / 1000;
-	inc *= 256;
-	inc *= 256;
-	inc /= 1000;
-
-	switch (state->search_mode) {
-	case STV090x_SEARCH_DVBS1:
-	case STV090x_SEARCH_DSS:
-		inc *= 3; /* freq step = 3% of srate */
-		timeout = 20;
-		break;
-
-	case STV090x_SEARCH_DVBS2:
-		inc *= 4;
-		timeout = 25;
-		break;
-
-	case STV090x_SEARCH_AUTO:
-	default:
-		inc *= 3;
-		timeout = 25;
-		break;
-	}
-	inc /= 100;
-	if ((inc > car_max) || (inc < 0))
-		inc = car_max / 2; /* increment <= 1/8 Mclk */
-
-	timeout *= 27500; /* 27.5 Msps reference */
-	if (srate > 0)
-		timeout /= (srate / 1000);
-
-	if ((timeout > 100) || (timeout < 0))
-		timeout = 100;
-
-	steps_max = (car_max / inc) + 1; /* min steps = 3 */
-	if ((steps_max > 100) || (steps_max < 0)) {
-		steps_max = 100; /* max steps <= 100 */
-		inc = car_max / steps_max;
-	}
-	*freq_inc = inc;
-	*timeout_sw = timeout;
-	*steps = steps_max;
-
-	return 0;
-}
-
-static int stv090x_chk_signal(struct stv090x_state *state)
-{
-	s32 offst_car, agc2, car_max;
-	int no_signal;
-
-	offst_car  = STV090x_READ_DEMOD(state, CFR2) << 8;
-	offst_car |= STV090x_READ_DEMOD(state, CFR1);
-	offst_car = comp2(offst_car, 16);
-
-	agc2  = STV090x_READ_DEMOD(state, AGC2I1) << 8;
-	agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
-	car_max = state->search_range / 1000;
-
-	car_max += (car_max / 10); /* 10% margin */
-	car_max  = (65536 * car_max / 2);
-	car_max /= state->internal->mclk / 1000;
-
-	if (car_max > 0x4000)
-		car_max = 0x4000;
-
-	if ((agc2 > 0x2000) || (offst_car > 2 * car_max) || (offst_car < -2 * car_max)) {
-		no_signal = 1;
-		dprintk(FE_DEBUG, 1, "No Signal");
-	} else {
-		no_signal = 0;
-		dprintk(FE_DEBUG, 1, "Found Signal");
-	}
-
-	return no_signal;
-}
-
-static int stv090x_search_car_loop(struct stv090x_state *state, s32 inc, s32 timeout, int zigzag, s32 steps_max)
-{
-	int no_signal, lock = 0;
-	s32 cpt_step = 0, offst_freq, car_max;
-	u32 reg;
-
-	car_max  = state->search_range / 1000;
-	car_max += (car_max / 10);
-	car_max  = (65536 * car_max / 2);
-	car_max /= (state->internal->mclk / 1000);
-	if (car_max > 0x4000)
-		car_max = 0x4000;
-
-	if (zigzag)
-		offst_freq = 0;
-	else
-		offst_freq = -car_max + inc;
-
-	do {
-		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, CFRINIT1, ((offst_freq / 256) & 0xff)) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, CFRINIT0, offst_freq & 0xff) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
-			goto err;
-
-		reg = STV090x_READ_DEMOD(state, PDELCTRL1);
-		STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x1); /* stop DVB-S2 packet delin */
-		if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
-			goto err;
-
-		if (zigzag) {
-			if (offst_freq >= 0)
-				offst_freq = -offst_freq - 2 * inc;
-			else
-				offst_freq = -offst_freq;
-		} else {
-			offst_freq += 2 * inc;
-		}
-
-		cpt_step++;
-
-		lock = stv090x_get_dmdlock(state, timeout);
-		no_signal = stv090x_chk_signal(state);
-
-	} while ((!lock) &&
-		 (!no_signal) &&
-		  ((offst_freq - inc) < car_max) &&
-		  ((offst_freq + inc) > -car_max) &&
-		  (cpt_step < steps_max));
-
-	reg = STV090x_READ_DEMOD(state, PDELCTRL1);
-	STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0);
-	if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
-			goto err;
-
-	return lock;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_sw_algo(struct stv090x_state *state)
-{
-	int no_signal, zigzag, lock = 0;
-	u32 reg;
-
-	s32 dvbs2_fly_wheel;
-	s32 inc, timeout_step, trials, steps_max;
-
-	/* get params */
-	stv090x_get_loop_params(state, &inc, &timeout_step, &steps_max);
-
-	switch (state->search_mode) {
-	case STV090x_SEARCH_DVBS1:
-	case STV090x_SEARCH_DSS:
-		/* accelerate the frequency detector */
-		if (state->internal->dev_ver >= 0x20) {
-			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3B) < 0)
-				goto err;
-		}
-
-		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x49) < 0)
-			goto err;
-		zigzag = 0;
-		break;
-
-	case STV090x_SEARCH_DVBS2:
-		if (state->internal->dev_ver >= 0x20) {
-			if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
-				goto err;
-		}
-
-		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x89) < 0)
-			goto err;
-		zigzag = 1;
-		break;
-
-	case STV090x_SEARCH_AUTO:
-	default:
-		/* accelerate the frequency detector */
-		if (state->internal->dev_ver >= 0x20) {
-			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3b) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
-				goto err;
-		}
-
-		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0xc9) < 0)
-			goto err;
-		zigzag = 0;
-		break;
-	}
-
-	trials = 0;
-	do {
-		lock = stv090x_search_car_loop(state, inc, timeout_step, zigzag, steps_max);
-		no_signal = stv090x_chk_signal(state);
-		trials++;
-
-		/*run the SW search 2 times maximum*/
-		if (lock || no_signal || (trials == 2)) {
-			/*Check if the demod is not losing lock in DVBS2*/
-			if (state->internal->dev_ver >= 0x20) {
-				if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
-					goto err;
-				if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0)
-					goto err;
-			}
-
-			reg = STV090x_READ_DEMOD(state, DMDSTATE);
-			if ((lock) && (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == STV090x_DVBS2)) {
-				/*Check if the demod is not losing lock in DVBS2*/
-				msleep(timeout_step);
-				reg = STV090x_READ_DEMOD(state, DMDFLYW);
-				dvbs2_fly_wheel = STV090x_GETFIELD_Px(reg, FLYWHEEL_CPT_FIELD);
-				if (dvbs2_fly_wheel < 0xd) {	 /*if correct frames is decrementing */
-					msleep(timeout_step);
-					reg = STV090x_READ_DEMOD(state, DMDFLYW);
-					dvbs2_fly_wheel = STV090x_GETFIELD_Px(reg, FLYWHEEL_CPT_FIELD);
-				}
-				if (dvbs2_fly_wheel < 0xd) {
-					/*FALSE lock, The demod is losing lock */
-					lock = 0;
-					if (trials < 2) {
-						if (state->internal->dev_ver >= 0x20) {
-							if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
-								goto err;
-						}
-
-						if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x89) < 0)
-							goto err;
-					}
-				}
-			}
-		}
-	} while ((!lock) && (trials < 2) && (!no_signal));
-
-	return lock;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static enum stv090x_delsys stv090x_get_std(struct stv090x_state *state)
-{
-	u32 reg;
-	enum stv090x_delsys delsys;
-
-	reg = STV090x_READ_DEMOD(state, DMDSTATE);
-	if (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == 2)
-		delsys = STV090x_DVBS2;
-	else if (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == 3) {
-		reg = STV090x_READ_DEMOD(state, FECM);
-		if (STV090x_GETFIELD_Px(reg, DSS_DVB_FIELD) == 1)
-			delsys = STV090x_DSS;
-		else
-			delsys = STV090x_DVBS1;
-	} else {
-		delsys = STV090x_ERROR;
-	}
-
-	return delsys;
-}
-
-/* in Hz */
-static s32 stv090x_get_car_freq(struct stv090x_state *state, u32 mclk)
-{
-	s32 derot, int_1, int_2, tmp_1, tmp_2;
-
-	derot  = STV090x_READ_DEMOD(state, CFR2) << 16;
-	derot |= STV090x_READ_DEMOD(state, CFR1) <<  8;
-	derot |= STV090x_READ_DEMOD(state, CFR0);
-
-	derot = comp2(derot, 24);
-	int_1 = mclk >> 12;
-	int_2 = derot >> 12;
-
-	/* carrier_frequency = MasterClock * Reg / 2^24 */
-	tmp_1 = mclk % 0x1000;
-	tmp_2 = derot % 0x1000;
-
-	derot = (int_1 * int_2) +
-		((int_1 * tmp_2) >> 12) +
-		((int_2 * tmp_1) >> 12);
-
-	return derot;
-}
-
-static int stv090x_get_viterbi(struct stv090x_state *state)
-{
-	u32 reg, rate;
-
-	reg = STV090x_READ_DEMOD(state, VITCURPUN);
-	rate = STV090x_GETFIELD_Px(reg, VIT_CURPUN_FIELD);
-
-	switch (rate) {
-	case 13:
-		state->fec = STV090x_PR12;
-		break;
-
-	case 18:
-		state->fec = STV090x_PR23;
-		break;
-
-	case 21:
-		state->fec = STV090x_PR34;
-		break;
-
-	case 24:
-		state->fec = STV090x_PR56;
-		break;
-
-	case 25:
-		state->fec = STV090x_PR67;
-		break;
-
-	case 26:
-		state->fec = STV090x_PR78;
-		break;
-
-	default:
-		state->fec = STV090x_PRERR;
-		break;
-	}
-
-	return 0;
-}
-
-static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *state)
-{
-	struct dvb_frontend *fe = &state->frontend;
-
-	u8 tmg;
-	u32 reg;
-	s32 i = 0, offst_freq;
-
-	msleep(5);
-
-	if (state->algo == STV090x_BLIND_SEARCH) {
-		tmg = STV090x_READ_DEMOD(state, TMGREG2);
-		STV090x_WRITE_DEMOD(state, SFRSTEP, 0x5c);
-		while ((i <= 50) && (tmg != 0) && (tmg != 0xff)) {
-			tmg = STV090x_READ_DEMOD(state, TMGREG2);
-			msleep(5);
-			i += 5;
-		}
-	}
-	state->delsys = stv090x_get_std(state);
-
-	if (stv090x_i2c_gate_ctrl(state, 1) < 0)
-		goto err;
-
-	if (state->config->tuner_get_frequency) {
-		if (state->config->tuner_get_frequency(fe, &state->frequency) < 0)
-			goto err_gateoff;
-	}
-
-	if (stv090x_i2c_gate_ctrl(state, 0) < 0)
-		goto err;
-
-	offst_freq = stv090x_get_car_freq(state, state->internal->mclk) / 1000;
-	state->frequency += offst_freq;
-
-	if (stv090x_get_viterbi(state) < 0)
-		goto err;
-
-	reg = STV090x_READ_DEMOD(state, DMDMODCOD);
-	state->modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD);
-	state->pilots = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) & 0x01;
-	state->frame_len = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) >> 1;
-	reg = STV090x_READ_DEMOD(state, TMGOBS);
-	state->rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD);
-	reg = STV090x_READ_DEMOD(state, FECM);
-	state->inversion = STV090x_GETFIELD_Px(reg, IQINV_FIELD);
-
-	if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000)) {
-
-		if (stv090x_i2c_gate_ctrl(state, 1) < 0)
-			goto err;
-
-		if (state->config->tuner_get_frequency) {
-			if (state->config->tuner_get_frequency(fe, &state->frequency) < 0)
-				goto err_gateoff;
-		}
-
-		if (stv090x_i2c_gate_ctrl(state, 0) < 0)
-			goto err;
-
-		if (abs(offst_freq) <= ((state->search_range / 2000) + 500))
-			return STV090x_RANGEOK;
-		else if (abs(offst_freq) <= (stv090x_car_width(state->srate, state->rolloff) / 2000))
-			return STV090x_RANGEOK;
-		else
-			return STV090x_OUTOFRANGE; /* Out of Range */
-	} else {
-		if (abs(offst_freq) <= ((state->search_range / 2000) + 500))
-			return STV090x_RANGEOK;
-		else
-			return STV090x_OUTOFRANGE;
-	}
-
-	return STV090x_OUTOFRANGE;
-
-err_gateoff:
-	stv090x_i2c_gate_ctrl(state, 0);
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static u32 stv090x_get_tmgoffst(struct stv090x_state *state, u32 srate)
-{
-	s32 offst_tmg;
-
-	offst_tmg  = STV090x_READ_DEMOD(state, TMGREG2) << 16;
-	offst_tmg |= STV090x_READ_DEMOD(state, TMGREG1) <<  8;
-	offst_tmg |= STV090x_READ_DEMOD(state, TMGREG0);
-
-	offst_tmg = comp2(offst_tmg, 24); /* 2's complement */
-	if (!offst_tmg)
-		offst_tmg = 1;
-
-	offst_tmg  = ((s32) srate * 10) / ((s32) 0x1000000 / offst_tmg);
-	offst_tmg /= 320;
-
-	return offst_tmg;
-}
-
-static u8 stv090x_optimize_carloop(struct stv090x_state *state, enum stv090x_modcod modcod, s32 pilots)
-{
-	u8 aclc = 0x29;
-	s32 i;
-	struct stv090x_long_frame_crloop *car_loop, *car_loop_qpsk_low, *car_loop_apsk_low;
-
-	if (state->internal->dev_ver == 0x20) {
-		car_loop		= stv090x_s2_crl_cut20;
-		car_loop_qpsk_low	= stv090x_s2_lowqpsk_crl_cut20;
-		car_loop_apsk_low	= stv090x_s2_apsk_crl_cut20;
-	} else {
-		/* >= Cut 3 */
-		car_loop		= stv090x_s2_crl_cut30;
-		car_loop_qpsk_low	= stv090x_s2_lowqpsk_crl_cut30;
-		car_loop_apsk_low	= stv090x_s2_apsk_crl_cut30;
-	}
-
-	if (modcod < STV090x_QPSK_12) {
-		i = 0;
-		while ((i < 3) && (modcod != car_loop_qpsk_low[i].modcod))
-			i++;
-
-		if (i >= 3)
-			i = 2;
-
-	} else {
-		i = 0;
-		while ((i < 14) && (modcod != car_loop[i].modcod))
-			i++;
-
-		if (i >= 14) {
-			i = 0;
-			while ((i < 11) && (modcod != car_loop_apsk_low[i].modcod))
-				i++;
-
-			if (i >= 11)
-				i = 10;
-		}
-	}
-
-	if (modcod <= STV090x_QPSK_25) {
-		if (pilots) {
-			if (state->srate <= 3000000)
-				aclc = car_loop_qpsk_low[i].crl_pilots_on_2;
-			else if (state->srate <= 7000000)
-				aclc = car_loop_qpsk_low[i].crl_pilots_on_5;
-			else if (state->srate <= 15000000)
-				aclc = car_loop_qpsk_low[i].crl_pilots_on_10;
-			else if (state->srate <= 25000000)
-				aclc = car_loop_qpsk_low[i].crl_pilots_on_20;
-			else
-				aclc = car_loop_qpsk_low[i].crl_pilots_on_30;
-		} else {
-			if (state->srate <= 3000000)
-				aclc = car_loop_qpsk_low[i].crl_pilots_off_2;
-			else if (state->srate <= 7000000)
-				aclc = car_loop_qpsk_low[i].crl_pilots_off_5;
-			else if (state->srate <= 15000000)
-				aclc = car_loop_qpsk_low[i].crl_pilots_off_10;
-			else if (state->srate <= 25000000)
-				aclc = car_loop_qpsk_low[i].crl_pilots_off_20;
-			else
-				aclc = car_loop_qpsk_low[i].crl_pilots_off_30;
-		}
-
-	} else if (modcod <= STV090x_8PSK_910) {
-		if (pilots) {
-			if (state->srate <= 3000000)
-				aclc = car_loop[i].crl_pilots_on_2;
-			else if (state->srate <= 7000000)
-				aclc = car_loop[i].crl_pilots_on_5;
-			else if (state->srate <= 15000000)
-				aclc = car_loop[i].crl_pilots_on_10;
-			else if (state->srate <= 25000000)
-				aclc = car_loop[i].crl_pilots_on_20;
-			else
-				aclc = car_loop[i].crl_pilots_on_30;
-		} else {
-			if (state->srate <= 3000000)
-				aclc = car_loop[i].crl_pilots_off_2;
-			else if (state->srate <= 7000000)
-				aclc = car_loop[i].crl_pilots_off_5;
-			else if (state->srate <= 15000000)
-				aclc = car_loop[i].crl_pilots_off_10;
-			else if (state->srate <= 25000000)
-				aclc = car_loop[i].crl_pilots_off_20;
-			else
-				aclc = car_loop[i].crl_pilots_off_30;
-		}
-	} else { /* 16APSK and 32APSK */
-		if (state->srate <= 3000000)
-			aclc = car_loop_apsk_low[i].crl_pilots_on_2;
-		else if (state->srate <= 7000000)
-			aclc = car_loop_apsk_low[i].crl_pilots_on_5;
-		else if (state->srate <= 15000000)
-			aclc = car_loop_apsk_low[i].crl_pilots_on_10;
-		else if (state->srate <= 25000000)
-			aclc = car_loop_apsk_low[i].crl_pilots_on_20;
-		else
-			aclc = car_loop_apsk_low[i].crl_pilots_on_30;
-	}
-
-	return aclc;
-}
-
-static u8 stv090x_optimize_carloop_short(struct stv090x_state *state)
-{
-	struct stv090x_short_frame_crloop *short_crl = NULL;
-	s32 index = 0;
-	u8 aclc = 0x0b;
-
-	switch (state->modulation) {
-	case STV090x_QPSK:
-	default:
-		index = 0;
-		break;
-	case STV090x_8PSK:
-		index = 1;
-		break;
-	case STV090x_16APSK:
-		index = 2;
-		break;
-	case STV090x_32APSK:
-		index = 3;
-		break;
-	}
-
-	if (state->internal->dev_ver >= 0x30) {
-		/* Cut 3.0 and up */
-		short_crl = stv090x_s2_short_crl_cut30;
-	} else {
-		/* Cut 2.0 and up: we don't support cuts older than 2.0 */
-		short_crl = stv090x_s2_short_crl_cut20;
-	}
-
-	if (state->srate <= 3000000)
-		aclc = short_crl[index].crl_2;
-	else if (state->srate <= 7000000)
-		aclc = short_crl[index].crl_5;
-	else if (state->srate <= 15000000)
-		aclc = short_crl[index].crl_10;
-	else if (state->srate <= 25000000)
-		aclc = short_crl[index].crl_20;
-	else
-		aclc = short_crl[index].crl_30;
-
-	return aclc;
-}
-
-static int stv090x_optimize_track(struct stv090x_state *state)
-{
-	struct dvb_frontend *fe = &state->frontend;
-
-	enum stv090x_modcod modcod;
-
-	s32 srate, pilots, aclc, f_1, f_0, i = 0, blind_tune = 0;
-	u32 reg;
-
-	srate  = stv090x_get_srate(state, state->internal->mclk);
-	srate += stv090x_get_tmgoffst(state, srate);
-
-	switch (state->delsys) {
-	case STV090x_DVBS1:
-	case STV090x_DSS:
-		if (state->search_mode == STV090x_SEARCH_AUTO) {
-			reg = STV090x_READ_DEMOD(state, DMDCFGMD);
-			STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
-			STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
-			if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
-				goto err;
-		}
-		reg = STV090x_READ_DEMOD(state, DEMOD);
-		STV090x_SETFIELD_Px(reg, ROLLOFF_CONTROL_FIELD, state->rolloff);
-		STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x01);
-		if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
-			goto err;
-
-		if (state->internal->dev_ver >= 0x30) {
-			if (stv090x_get_viterbi(state) < 0)
-				goto err;
-
-			if (state->fec == STV090x_PR12) {
-				if (STV090x_WRITE_DEMOD(state, GAUSSR0, 0x98) < 0)
-					goto err;
-				if (STV090x_WRITE_DEMOD(state, CCIR0, 0x18) < 0)
-					goto err;
-			} else {
-				if (STV090x_WRITE_DEMOD(state, GAUSSR0, 0x18) < 0)
-					goto err;
-				if (STV090x_WRITE_DEMOD(state, CCIR0, 0x18) < 0)
-					goto err;
-			}
-		}
-
-		if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x75) < 0)
-			goto err;
-		break;
-
-	case STV090x_DVBS2:
-		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
-		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
-		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
-		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
-			goto err;
-		if (state->internal->dev_ver >= 0x30) {
-			if (STV090x_WRITE_DEMOD(state, ACLC, 0) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, BCLC, 0) < 0)
-				goto err;
-		}
-		if (state->frame_len == STV090x_LONG_FRAME) {
-			reg = STV090x_READ_DEMOD(state, DMDMODCOD);
-			modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD);
-			pilots = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) & 0x01;
-			aclc = stv090x_optimize_carloop(state, modcod, pilots);
-			if (modcod <= STV090x_QPSK_910) {
-				STV090x_WRITE_DEMOD(state, ACLC2S2Q, aclc);
-			} else if (modcod <= STV090x_8PSK_910) {
-				if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
-					goto err;
-				if (STV090x_WRITE_DEMOD(state, ACLC2S28, aclc) < 0)
-					goto err;
-			}
-			if ((state->demod_mode == STV090x_SINGLE) && (modcod > STV090x_8PSK_910)) {
-				if (modcod <= STV090x_16APSK_910) {
-					if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
-						goto err;
-					if (STV090x_WRITE_DEMOD(state, ACLC2S216A, aclc) < 0)
-						goto err;
-				} else {
-					if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
-						goto err;
-					if (STV090x_WRITE_DEMOD(state, ACLC2S232A, aclc) < 0)
-						goto err;
-				}
-			}
-		} else {
-			/*Carrier loop setting for short frame*/
-			aclc = stv090x_optimize_carloop_short(state);
-			if (state->modulation == STV090x_QPSK) {
-				if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, aclc) < 0)
-					goto err;
-			} else if (state->modulation == STV090x_8PSK) {
-				if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
-					goto err;
-				if (STV090x_WRITE_DEMOD(state, ACLC2S28, aclc) < 0)
-					goto err;
-			} else if (state->modulation == STV090x_16APSK) {
-				if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
-					goto err;
-				if (STV090x_WRITE_DEMOD(state, ACLC2S216A, aclc) < 0)
-					goto err;
-			} else if (state->modulation == STV090x_32APSK)  {
-				if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
-					goto err;
-				if (STV090x_WRITE_DEMOD(state, ACLC2S232A, aclc) < 0)
-					goto err;
-			}
-		}
-
-		STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67); /* PER */
-		break;
-
-	case STV090x_ERROR:
-	default:
-		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
-		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
-		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
-		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
-			goto err;
-		break;
-	}
-
-	f_1 = STV090x_READ_DEMOD(state, CFR2);
-	f_0 = STV090x_READ_DEMOD(state, CFR1);
-	reg = STV090x_READ_DEMOD(state, TMGOBS);
-
-	if (state->algo == STV090x_BLIND_SEARCH) {
-		STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00);
-		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
-		STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0x00);
-		STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00);
-		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0)
-			goto err;
-
-		if (stv090x_set_srate(state, srate) < 0)
-			goto err;
-		blind_tune = 1;
-
-		if (stv090x_dvbs_track_crl(state) < 0)
-			goto err;
-	}
-
-	if (state->internal->dev_ver >= 0x20) {
-		if ((state->search_mode == STV090x_SEARCH_DVBS1)	||
-		    (state->search_mode == STV090x_SEARCH_DSS)		||
-		    (state->search_mode == STV090x_SEARCH_AUTO)) {
-
-			if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x0a) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x00) < 0)
-				goto err;
-		}
-	}
-
-	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
-		goto err;
-
-	/* AUTO tracking MODE */
-	if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x80) < 0)
-		goto err;
-	/* AUTO tracking MODE */
-	if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x80) < 0)
-		goto err;
-
-	if ((state->internal->dev_ver >= 0x20) || (blind_tune == 1) ||
-	    (state->srate < 10000000)) {
-		/* update initial carrier freq with the found freq offset */
-		if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0)
-			goto err;
-		state->tuner_bw = stv090x_car_width(srate, state->rolloff) + 10000000;
-
-		if ((state->internal->dev_ver >= 0x20) || (blind_tune == 1)) {
-
-			if (state->algo != STV090x_WARM_SEARCH) {
-
-				if (stv090x_i2c_gate_ctrl(state, 1) < 0)
-					goto err;
-
-				if (state->config->tuner_set_bandwidth) {
-					if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
-						goto err_gateoff;
-				}
-
-				if (stv090x_i2c_gate_ctrl(state, 0) < 0)
-					goto err;
-
-			}
-		}
-		if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000))
-			msleep(50); /* blind search: wait 50ms for SR stabilization */
-		else
-			msleep(5);
-
-		stv090x_get_lock_tmg(state);
-
-		if (!(stv090x_get_dmdlock(state, (state->DemodTimeout / 2)))) {
-			if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
-				goto err;
-
-			i = 0;
-
-			while ((!(stv090x_get_dmdlock(state, (state->DemodTimeout / 2)))) && (i <= 2)) {
-
-				if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
-					goto err;
-				if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0)
-					goto err;
-				if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0)
-					goto err;
-				if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
-					goto err;
-				i++;
-			}
-		}
-
-	}
-
-	if (state->internal->dev_ver >= 0x20) {
-		if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
-			goto err;
-	}
-
-	if ((state->delsys == STV090x_DVBS1) || (state->delsys == STV090x_DSS))
-		stv090x_set_vit_thtracq(state);
-
-	return 0;
-
-err_gateoff:
-	stv090x_i2c_gate_ctrl(state, 0);
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_get_feclock(struct stv090x_state *state, s32 timeout)
-{
-	s32 timer = 0, lock = 0, stat;
-	u32 reg;
-
-	while ((timer < timeout) && (!lock)) {
-		reg = STV090x_READ_DEMOD(state, DMDSTATE);
-		stat = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD);
-
-		switch (stat) {
-		case 0: /* searching */
-		case 1: /* first PLH detected */
-		default:
-			lock = 0;
-			break;
-
-		case 2: /* DVB-S2 mode */
-			reg = STV090x_READ_DEMOD(state, PDELSTATUS1);
-			lock = STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD);
-			break;
-
-		case 3: /* DVB-S1/legacy mode */
-			reg = STV090x_READ_DEMOD(state, VSTATUSVIT);
-			lock = STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD);
-			break;
-		}
-		if (!lock) {
-			msleep(10);
-			timer += 10;
-		}
-	}
-	return lock;
-}
-
-static int stv090x_get_lock(struct stv090x_state *state, s32 timeout_dmd, s32 timeout_fec)
-{
-	u32 reg;
-	s32 timer = 0;
-	int lock;
-
-	lock = stv090x_get_dmdlock(state, timeout_dmd);
-	if (lock)
-		lock = stv090x_get_feclock(state, timeout_fec);
-
-	if (lock) {
-		lock = 0;
-
-		while ((timer < timeout_fec) && (!lock)) {
-			reg = STV090x_READ_DEMOD(state, TSSTATUS);
-			lock = STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD);
-			msleep(1);
-			timer++;
-		}
-	}
-
-	return lock;
-}
-
-static int stv090x_set_s2rolloff(struct stv090x_state *state)
-{
-	u32 reg;
-
-	if (state->internal->dev_ver <= 0x20) {
-		/* rolloff to auto mode if DVBS2 */
-		reg = STV090x_READ_DEMOD(state, DEMOD);
-		STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x00);
-		if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
-			goto err;
-	} else {
-		/* DVB-S2 rolloff to auto mode if DVBS2 */
-		reg = STV090x_READ_DEMOD(state, DEMOD);
-		STV090x_SETFIELD_Px(reg, MANUAL_S2ROLLOFF_FIELD, 0x00);
-		if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
-			goto err;
-	}
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-
-static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
-{
-	struct dvb_frontend *fe = &state->frontend;
-	enum stv090x_signal_state signal_state = STV090x_NOCARRIER;
-	u32 reg;
-	s32 agc1_power, power_iq = 0, i;
-	int lock = 0, low_sr = 0;
-
-	reg = STV090x_READ_DEMOD(state, TSCFGH);
-	STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* Stop path 1 stream merger */
-	if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
-		goto err;
-
-	if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod stop */
-		goto err;
-
-	if (state->internal->dev_ver >= 0x20) {
-		if (state->srate > 5000000) {
-			if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0)
-				goto err;
-		} else {
-			if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x82) < 0)
-				goto err;
-		}
-	}
-
-	stv090x_get_lock_tmg(state);
-
-	if (state->algo == STV090x_BLIND_SEARCH) {
-		state->tuner_bw = 2 * 36000000; /* wide bw for unknown srate */
-		if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc0) < 0) /* wider srate scan */
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x70) < 0)
-			goto err;
-		if (stv090x_set_srate(state, 1000000) < 0) /* initial srate = 1Msps */
-			goto err;
-	} else {
-		/* known srate */
-		if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x20) < 0)
-			goto err;
-		if (STV090x_WRITE_DEMOD(state, TMGCFG, 0xd2) < 0)
-			goto err;
-
-		if (state->srate < 2000000) {
-			/* SR < 2MSPS */
-			if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x63) < 0)
-				goto err;
-		} else {
-			/* SR >= 2Msps */
-			if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x70) < 0)
-				goto err;
-		}
-
-		if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
-			goto err;
-
-		if (state->internal->dev_ver >= 0x20) {
-			if (STV090x_WRITE_DEMOD(state, KREFTMG, 0x5a) < 0)
-				goto err;
-			if (state->algo == STV090x_COLD_SEARCH)
-				state->tuner_bw = (15 * (stv090x_car_width(state->srate, state->rolloff) + 10000000)) / 10;
-			else if (state->algo == STV090x_WARM_SEARCH)
-				state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + 10000000;
-		}
-
-		/* if cold start or warm  (Symbolrate is known)
-		 * use a Narrow symbol rate scan range
-		 */
-		if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0) /* narrow srate scan */
-			goto err;
-
-		if (stv090x_set_srate(state, state->srate) < 0)
-			goto err;
-
-		if (stv090x_set_max_srate(state, state->internal->mclk,
-					  state->srate) < 0)
-			goto err;
-		if (stv090x_set_min_srate(state, state->internal->mclk,
-					  state->srate) < 0)
-			goto err;
-
-		if (state->srate >= 10000000)
-			low_sr = 0;
-		else
-			low_sr = 1;
-	}
-
-	/* Setup tuner */
-	if (stv090x_i2c_gate_ctrl(state, 1) < 0)
-		goto err;
-
-	if (state->config->tuner_set_bbgain) {
-		reg = state->config->tuner_bbgain;
-		if (reg == 0)
-			reg = 10; /* default: 10dB */
-		if (state->config->tuner_set_bbgain(fe, reg) < 0)
-			goto err_gateoff;
-	}
-
-	if (state->config->tuner_set_frequency) {
-		if (state->config->tuner_set_frequency(fe, state->frequency) < 0)
-			goto err_gateoff;
-	}
-
-	if (state->config->tuner_set_bandwidth) {
-		if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
-			goto err_gateoff;
-	}
-
-	if (stv090x_i2c_gate_ctrl(state, 0) < 0)
-		goto err;
-
-	msleep(50);
-
-	if (state->config->tuner_get_status) {
-		if (stv090x_i2c_gate_ctrl(state, 1) < 0)
-			goto err;
-		if (state->config->tuner_get_status(fe, &reg) < 0)
-			goto err_gateoff;
-		if (stv090x_i2c_gate_ctrl(state, 0) < 0)
-			goto err;
-
-		if (reg)
-			dprintk(FE_DEBUG, 1, "Tuner phase locked");
-		else {
-			dprintk(FE_DEBUG, 1, "Tuner unlocked");
-			return STV090x_NOCARRIER;
-		}
-	}
-
-	msleep(10);
-	agc1_power = MAKEWORD16(STV090x_READ_DEMOD(state, AGCIQIN1),
-				STV090x_READ_DEMOD(state, AGCIQIN0));
-
-	if (agc1_power == 0) {
-		/* If AGC1 integrator value is 0
-		 * then read POWERI, POWERQ
-		 */
-		for (i = 0; i < 5; i++) {
-			power_iq += (STV090x_READ_DEMOD(state, POWERI) +
-				     STV090x_READ_DEMOD(state, POWERQ)) >> 1;
-		}
-		power_iq /= 5;
-	}
-
-	if ((agc1_power == 0) && (power_iq < STV090x_IQPOWER_THRESHOLD)) {
-		dprintk(FE_ERROR, 1, "No Signal: POWER_IQ=0x%02x", power_iq);
-		lock = 0;
-		signal_state = STV090x_NOAGC1;
-	} else {
-		reg = STV090x_READ_DEMOD(state, DEMOD);
-		STV090x_SETFIELD_Px(reg, SPECINV_CONTROL_FIELD, state->inversion);
-
-		if (state->internal->dev_ver <= 0x20) {
-			/* rolloff to auto mode if DVBS2 */
-			STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 1);
-		} else {
-			/* DVB-S2 rolloff to auto mode if DVBS2 */
-			STV090x_SETFIELD_Px(reg, MANUAL_S2ROLLOFF_FIELD, 1);
-		}
-		if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
-			goto err;
-
-		if (stv090x_delivery_search(state) < 0)
-			goto err;
-
-		if (state->algo != STV090x_BLIND_SEARCH) {
-			if (stv090x_start_search(state) < 0)
-				goto err;
-		}
-	}
-
-	if (signal_state == STV090x_NOAGC1)
-		return signal_state;
-
-	if (state->algo == STV090x_BLIND_SEARCH)
-		lock = stv090x_blind_search(state);
-
-	else if (state->algo == STV090x_COLD_SEARCH)
-		lock = stv090x_get_coldlock(state, state->DemodTimeout);
-
-	else if (state->algo == STV090x_WARM_SEARCH)
-		lock = stv090x_get_dmdlock(state, state->DemodTimeout);
-
-	if ((!lock) && (state->algo == STV090x_COLD_SEARCH)) {
-		if (!low_sr) {
-			if (stv090x_chk_tmg(state))
-				lock = stv090x_sw_algo(state);
-		}
-	}
-
-	if (lock)
-		signal_state = stv090x_get_sig_params(state);
-
-	if ((lock) && (signal_state == STV090x_RANGEOK)) { /* signal within Range */
-		stv090x_optimize_track(state);
-
-		if (state->internal->dev_ver >= 0x20) {
-			/* >= Cut 2.0 :release TS reset after
-			 * demod lock and optimized Tracking
-			 */
-			reg = STV090x_READ_DEMOD(state, TSCFGH);
-			STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0); /* release merger reset */
-			if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
-				goto err;
-
-			msleep(3);
-
-			STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* merger reset */
-			if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
-				goto err;
-
-			STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0); /* release merger reset */
-			if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
-				goto err;
-		}
-
-		lock = stv090x_get_lock(state, state->FecTimeout,
-				state->FecTimeout);
-		if (lock) {
-			if (state->delsys == STV090x_DVBS2) {
-				stv090x_set_s2rolloff(state);
-
-				reg = STV090x_READ_DEMOD(state, PDELCTRL2);
-				STV090x_SETFIELD_Px(reg, RESET_UPKO_COUNT, 1);
-				if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0)
-					goto err;
-				/* Reset DVBS2 packet delinator error counter */
-				reg = STV090x_READ_DEMOD(state, PDELCTRL2);
-				STV090x_SETFIELD_Px(reg, RESET_UPKO_COUNT, 0);
-				if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0)
-					goto err;
-
-				if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67) < 0) /* PER */
-					goto err;
-			} else {
-				if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x75) < 0)
-					goto err;
-			}
-			/* Reset the Total packet counter */
-			if (STV090x_WRITE_DEMOD(state, FBERCPT4, 0x00) < 0)
-				goto err;
-			/* Reset the packet Error counter2 */
-			if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0)
-				goto err;
-		} else {
-			signal_state = STV090x_NODATA;
-			stv090x_chk_signal(state);
-		}
-	}
-	return signal_state;
-
-err_gateoff:
-	stv090x_i2c_gate_ctrl(state, 0);
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static enum dvbfe_search stv090x_search(struct dvb_frontend *fe)
-{
-	struct stv090x_state *state = fe->demodulator_priv;
-	struct dtv_frontend_properties *props = &fe->dtv_property_cache;
-
-	if (props->frequency == 0)
-		return DVBFE_ALGO_SEARCH_INVALID;
-
-	state->delsys = props->delivery_system;
-	state->frequency = props->frequency;
-	state->srate = props->symbol_rate;
-	state->search_mode = STV090x_SEARCH_AUTO;
-	state->algo = STV090x_COLD_SEARCH;
-	state->fec = STV090x_PRERR;
-	if (state->srate > 10000000) {
-		dprintk(FE_DEBUG, 1, "Search range: 10 MHz");
-		state->search_range = 10000000;
-	} else {
-		dprintk(FE_DEBUG, 1, "Search range: 5 MHz");
-		state->search_range = 5000000;
-	}
-
-	if (stv090x_algo(state) == STV090x_RANGEOK) {
-		dprintk(FE_DEBUG, 1, "Search success!");
-		return DVBFE_ALGO_SEARCH_SUCCESS;
-	} else {
-		dprintk(FE_DEBUG, 1, "Search failed!");
-		return DVBFE_ALGO_SEARCH_FAILED;
-	}
-
-	return DVBFE_ALGO_SEARCH_ERROR;
-}
-
-static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
-{
-	struct stv090x_state *state = fe->demodulator_priv;
-	u32 reg, dstatus;
-	u8 search_state;
-
-	*status = 0;
-
-	dstatus = STV090x_READ_DEMOD(state, DSTATUS);
-	if (STV090x_GETFIELD_Px(dstatus, CAR_LOCK_FIELD))
-		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
-
-	reg = STV090x_READ_DEMOD(state, DMDSTATE);
-	search_state = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD);
-
-	switch (search_state) {
-	case 0: /* searching */
-	case 1: /* first PLH detected */
-	default:
-		dprintk(FE_DEBUG, 1, "Status: Unlocked (Searching ..)");
-		break;
-
-	case 2: /* DVB-S2 mode */
-		dprintk(FE_DEBUG, 1, "Delivery system: DVB-S2");
-		if (STV090x_GETFIELD_Px(dstatus, LOCK_DEFINITIF_FIELD)) {
-			reg = STV090x_READ_DEMOD(state, PDELSTATUS1);
-			if (STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD)) {
-				*status |= FE_HAS_VITERBI;
-				reg = STV090x_READ_DEMOD(state, TSSTATUS);
-				if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD))
-					*status |= FE_HAS_SYNC | FE_HAS_LOCK;
-			}
-		}
-		break;
-
-	case 3: /* DVB-S1/legacy mode */
-		dprintk(FE_DEBUG, 1, "Delivery system: DVB-S");
-		if (STV090x_GETFIELD_Px(dstatus, LOCK_DEFINITIF_FIELD)) {
-			reg = STV090x_READ_DEMOD(state, VSTATUSVIT);
-			if (STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD)) {
-				*status |= FE_HAS_VITERBI;
-				reg = STV090x_READ_DEMOD(state, TSSTATUS);
-				if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD))
-					*status |= FE_HAS_SYNC | FE_HAS_LOCK;
-			}
-		}
-		break;
-	}
-
-	return 0;
-}
-
-static int stv090x_read_per(struct dvb_frontend *fe, u32 *per)
-{
-	struct stv090x_state *state = fe->demodulator_priv;
-
-	s32 count_4, count_3, count_2, count_1, count_0, count;
-	u32 reg, h, m, l;
-	enum fe_status status;
-
-	stv090x_read_status(fe, &status);
-	if (!(status & FE_HAS_LOCK)) {
-		*per = 1 << 23; /* Max PER */
-	} else {
-		/* Counter 2 */
-		reg = STV090x_READ_DEMOD(state, ERRCNT22);
-		h = STV090x_GETFIELD_Px(reg, ERR_CNT2_FIELD);
-
-		reg = STV090x_READ_DEMOD(state, ERRCNT21);
-		m = STV090x_GETFIELD_Px(reg, ERR_CNT21_FIELD);
-
-		reg = STV090x_READ_DEMOD(state, ERRCNT20);
-		l = STV090x_GETFIELD_Px(reg, ERR_CNT20_FIELD);
-
-		*per = ((h << 16) | (m << 8) | l);
-
-		count_4 = STV090x_READ_DEMOD(state, FBERCPT4);
-		count_3 = STV090x_READ_DEMOD(state, FBERCPT3);
-		count_2 = STV090x_READ_DEMOD(state, FBERCPT2);
-		count_1 = STV090x_READ_DEMOD(state, FBERCPT1);
-		count_0 = STV090x_READ_DEMOD(state, FBERCPT0);
-
-		if ((!count_4) && (!count_3)) {
-			count  = (count_2 & 0xff) << 16;
-			count |= (count_1 & 0xff) <<  8;
-			count |=  count_0 & 0xff;
-		} else {
-			count = 1 << 24;
-		}
-		if (count == 0)
-			*per = 1;
-	}
-	if (STV090x_WRITE_DEMOD(state, FBERCPT4, 0) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0)
-		goto err;
-
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_table_lookup(const struct stv090x_tab *tab, int max, int val)
-{
-	int res = 0;
-	int min = 0, med;
-
-	if ((val >= tab[min].read && val < tab[max].read) ||
-	    (val >= tab[max].read && val < tab[min].read)) {
-		while ((max - min) > 1) {
-			med = (max + min) / 2;
-			if ((val >= tab[min].read && val < tab[med].read) ||
-			    (val >= tab[med].read && val < tab[min].read))
-				max = med;
-			else
-				min = med;
-		}
-		res = ((val - tab[min].read) *
-		       (tab[max].real - tab[min].real) /
-		       (tab[max].read - tab[min].read)) +
-			tab[min].real;
-	} else {
-		if (tab[min].read < tab[max].read) {
-			if (val < tab[min].read)
-				res = tab[min].real;
-			else if (val >= tab[max].read)
-				res = tab[max].real;
-		} else {
-			if (val >= tab[min].read)
-				res = tab[min].real;
-			else if (val < tab[max].read)
-				res = tab[max].real;
-		}
-	}
-
-	return res;
-}
-
-static int stv090x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct stv090x_state *state = fe->demodulator_priv;
-	u32 reg;
-	s32 agc_0, agc_1, agc;
-	s32 str;
-
-	reg = STV090x_READ_DEMOD(state, AGCIQIN1);
-	agc_1 = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD);
-	reg = STV090x_READ_DEMOD(state, AGCIQIN0);
-	agc_0 = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD);
-	agc = MAKEWORD16(agc_1, agc_0);
-
-	str = stv090x_table_lookup(stv090x_rf_tab,
-		ARRAY_SIZE(stv090x_rf_tab) - 1, agc);
-	if (agc > stv090x_rf_tab[0].read)
-		str = 0;
-	else if (agc < stv090x_rf_tab[ARRAY_SIZE(stv090x_rf_tab) - 1].read)
-		str = -100;
-	*strength = (str + 100) * 0xFFFF / 100;
-
-	return 0;
-}
-
-static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr)
-{
-	struct stv090x_state *state = fe->demodulator_priv;
-	u32 reg_0, reg_1, reg, i;
-	s32 val_0, val_1, val = 0;
-	u8 lock_f;
-	s32 div;
-	u32 last;
-
-	switch (state->delsys) {
-	case STV090x_DVBS2:
-		reg = STV090x_READ_DEMOD(state, DSTATUS);
-		lock_f = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD);
-		if (lock_f) {
-			msleep(5);
-			for (i = 0; i < 16; i++) {
-				reg_1 = STV090x_READ_DEMOD(state, NNOSPLHT1);
-				val_1 = STV090x_GETFIELD_Px(reg_1, NOSPLHT_NORMED_FIELD);
-				reg_0 = STV090x_READ_DEMOD(state, NNOSPLHT0);
-				val_0 = STV090x_GETFIELD_Px(reg_0, NOSPLHT_NORMED_FIELD);
-				val  += MAKEWORD16(val_1, val_0);
-				msleep(1);
-			}
-			val /= 16;
-			last = ARRAY_SIZE(stv090x_s2cn_tab) - 1;
-			div = stv090x_s2cn_tab[0].read -
-			      stv090x_s2cn_tab[last].read;
-			*cnr = 0xFFFF - ((val * 0xFFFF) / div);
-		}
-		break;
-
-	case STV090x_DVBS1:
-	case STV090x_DSS:
-		reg = STV090x_READ_DEMOD(state, DSTATUS);
-		lock_f = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD);
-		if (lock_f) {
-			msleep(5);
-			for (i = 0; i < 16; i++) {
-				reg_1 = STV090x_READ_DEMOD(state, NOSDATAT1);
-				val_1 = STV090x_GETFIELD_Px(reg_1, NOSDATAT_UNNORMED_FIELD);
-				reg_0 = STV090x_READ_DEMOD(state, NOSDATAT0);
-				val_0 = STV090x_GETFIELD_Px(reg_0, NOSDATAT_UNNORMED_FIELD);
-				val  += MAKEWORD16(val_1, val_0);
-				msleep(1);
-			}
-			val /= 16;
-			last = ARRAY_SIZE(stv090x_s1cn_tab) - 1;
-			div = stv090x_s1cn_tab[0].read -
-			      stv090x_s1cn_tab[last].read;
-			*cnr = 0xFFFF - ((val * 0xFFFF) / div);
-		}
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static int stv090x_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
-{
-	struct stv090x_state *state = fe->demodulator_priv;
-	u32 reg;
-
-	reg = STV090x_READ_DEMOD(state, DISTXCTL);
-	switch (tone) {
-	case SEC_TONE_ON:
-		STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 0);
-		STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
-		if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
-			goto err;
-		STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0);
-		if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
-			goto err;
-		break;
-
-	case SEC_TONE_OFF:
-		STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 0);
-		STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
-		if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
-			goto err;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-
-static enum dvbfe_algo stv090x_frontend_algo(struct dvb_frontend *fe)
-{
-	return DVBFE_ALGO_CUSTOM;
-}
-
-static int stv090x_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd)
-{
-	struct stv090x_state *state = fe->demodulator_priv;
-	u32 reg, idle = 0, fifo_full = 1;
-	int i;
-
-	reg = STV090x_READ_DEMOD(state, DISTXCTL);
-
-	STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD,
-		(state->config->diseqc_envelope_mode) ? 4 : 2);
-	STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
-	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
-		goto err;
-	STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0);
-	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
-		goto err;
-
-	STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 1);
-	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
-		goto err;
-
-	for (i = 0; i < cmd->msg_len; i++) {
-
-		while (fifo_full) {
-			reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
-			fifo_full = STV090x_GETFIELD_Px(reg, FIFO_FULL_FIELD);
-		}
-
-		if (STV090x_WRITE_DEMOD(state, DISTXDATA, cmd->msg[i]) < 0)
-			goto err;
-	}
-	reg = STV090x_READ_DEMOD(state, DISTXCTL);
-	STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 0);
-	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
-		goto err;
-
-	i = 0;
-
-	while ((!idle) && (i < 10)) {
-		reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
-		idle = STV090x_GETFIELD_Px(reg, TX_IDLE_FIELD);
-		msleep(10);
-		i++;
-	}
-
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
-{
-	struct stv090x_state *state = fe->demodulator_priv;
-	u32 reg, idle = 0, fifo_full = 1;
-	u8 mode, value;
-	int i;
-
-	reg = STV090x_READ_DEMOD(state, DISTXCTL);
-
-	if (burst == SEC_MINI_A) {
-		mode = (state->config->diseqc_envelope_mode) ? 5 : 3;
-		value = 0x00;
-	} else {
-		mode = (state->config->diseqc_envelope_mode) ? 4 : 2;
-		value = 0xFF;
-	}
-
-	STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, mode);
-	STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
-	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
-		goto err;
-	STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0);
-	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
-		goto err;
-
-	STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 1);
-	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
-		goto err;
-
-	while (fifo_full) {
-		reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
-		fifo_full = STV090x_GETFIELD_Px(reg, FIFO_FULL_FIELD);
-	}
-
-	if (STV090x_WRITE_DEMOD(state, DISTXDATA, value) < 0)
-		goto err;
-
-	reg = STV090x_READ_DEMOD(state, DISTXCTL);
-	STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 0);
-	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
-		goto err;
-
-	i = 0;
-
-	while ((!idle) && (i < 10)) {
-		reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
-		idle = STV090x_GETFIELD_Px(reg, TX_IDLE_FIELD);
-		msleep(10);
-		i++;
-	}
-
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_slave_reply *reply)
-{
-	struct stv090x_state *state = fe->demodulator_priv;
-	u32 reg = 0, i = 0, rx_end = 0;
-
-	while ((rx_end != 1) && (i < 10)) {
-		msleep(10);
-		i++;
-		reg = STV090x_READ_DEMOD(state, DISRX_ST0);
-		rx_end = STV090x_GETFIELD_Px(reg, RX_END_FIELD);
-	}
-
-	if (rx_end) {
-		reply->msg_len = STV090x_GETFIELD_Px(reg, FIFO_BYTENBR_FIELD);
-		for (i = 0; i < reply->msg_len; i++)
-			reply->msg[i] = STV090x_READ_DEMOD(state, DISRXDATA);
-	}
-
-	return 0;
-}
-
-static int stv090x_sleep(struct dvb_frontend *fe)
-{
-	struct stv090x_state *state = fe->demodulator_priv;
-	u32 reg;
-	u8 full_standby = 0;
-
-	if (stv090x_i2c_gate_ctrl(state, 1) < 0)
-		goto err;
-
-	if (state->config->tuner_sleep) {
-		if (state->config->tuner_sleep(fe) < 0)
-			goto err_gateoff;
-	}
-
-	if (stv090x_i2c_gate_ctrl(state, 0) < 0)
-		goto err;
-
-	dprintk(FE_DEBUG, 1, "Set %s(%d) to sleep",
-		state->device == STV0900 ? "STV0900" : "STV0903",
-		state->demod);
-
-	mutex_lock(&state->internal->demod_lock);
-
-	switch (state->demod) {
-	case STV090x_DEMODULATOR_0:
-		/* power off ADC 1 */
-		reg = stv090x_read_reg(state, STV090x_TSTTNR1);
-		STV090x_SETFIELD(reg, ADC1_PON_FIELD, 0);
-		if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
-			goto err;
-		/* power off DiSEqC 1 */
-		reg = stv090x_read_reg(state, STV090x_TSTTNR2);
-		STV090x_SETFIELD(reg, DISEQC1_PON_FIELD, 0);
-		if (stv090x_write_reg(state, STV090x_TSTTNR2, reg) < 0)
-			goto err;
-
-		/* check whether path 2 is already sleeping, that is when
-		   ADC2 is off */
-		reg = stv090x_read_reg(state, STV090x_TSTTNR3);
-		if (STV090x_GETFIELD(reg, ADC2_PON_FIELD) == 0)
-			full_standby = 1;
-
-		/* stop clocks */
-		reg = stv090x_read_reg(state, STV090x_STOPCLK1);
-		/* packet delineator 1 clock */
-		STV090x_SETFIELD(reg, STOP_CLKPKDT1_FIELD, 1);
-		/* ADC 1 clock */
-		STV090x_SETFIELD(reg, STOP_CLKADCI1_FIELD, 1);
-		/* FEC clock is shared between the two paths, only stop it
-		   when full standby is possible */
-		if (full_standby)
-			STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1);
-		if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
-			goto err;
-		reg = stv090x_read_reg(state, STV090x_STOPCLK2);
-		/* sampling 1 clock */
-		STV090x_SETFIELD(reg, STOP_CLKSAMP1_FIELD, 1);
-		/* viterbi 1 clock */
-		STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, 1);
-		/* TS clock is shared between the two paths, only stop it
-		   when full standby is possible */
-		if (full_standby)
-			STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1);
-		if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
-			goto err;
-		break;
-
-	case STV090x_DEMODULATOR_1:
-		/* power off ADC 2 */
-		reg = stv090x_read_reg(state, STV090x_TSTTNR3);
-		STV090x_SETFIELD(reg, ADC2_PON_FIELD, 0);
-		if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0)
-			goto err;
-		/* power off DiSEqC 2 */
-		reg = stv090x_read_reg(state, STV090x_TSTTNR4);
-		STV090x_SETFIELD(reg, DISEQC2_PON_FIELD, 0);
-		if (stv090x_write_reg(state, STV090x_TSTTNR4, reg) < 0)
-			goto err;
-
-		/* check whether path 1 is already sleeping, that is when
-		   ADC1 is off */
-		reg = stv090x_read_reg(state, STV090x_TSTTNR1);
-		if (STV090x_GETFIELD(reg, ADC1_PON_FIELD) == 0)
-			full_standby = 1;
-
-		/* stop clocks */
-		reg = stv090x_read_reg(state, STV090x_STOPCLK1);
-		/* packet delineator 2 clock */
-		STV090x_SETFIELD(reg, STOP_CLKPKDT2_FIELD, 1);
-		/* ADC 2 clock */
-		STV090x_SETFIELD(reg, STOP_CLKADCI2_FIELD, 1);
-		/* FEC clock is shared between the two paths, only stop it
-		   when full standby is possible */
-		if (full_standby)
-			STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1);
-		if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
-			goto err;
-		reg = stv090x_read_reg(state, STV090x_STOPCLK2);
-		/* sampling 2 clock */
-		STV090x_SETFIELD(reg, STOP_CLKSAMP2_FIELD, 1);
-		/* viterbi 2 clock */
-		STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, 1);
-		/* TS clock is shared between the two paths, only stop it
-		   when full standby is possible */
-		if (full_standby)
-			STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1);
-		if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
-			goto err;
-		break;
-
-	default:
-		dprintk(FE_ERROR, 1, "Wrong demodulator!");
-		break;
-	}
-
-	if (full_standby) {
-		/* general power off */
-		reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
-		STV090x_SETFIELD(reg, STANDBY_FIELD, 0x01);
-		if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0)
-			goto err;
-	}
-
-	mutex_unlock(&state->internal->demod_lock);
-	return 0;
-
-err_gateoff:
-	stv090x_i2c_gate_ctrl(state, 0);
-err:
-	mutex_unlock(&state->internal->demod_lock);
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_wakeup(struct dvb_frontend *fe)
-{
-	struct stv090x_state *state = fe->demodulator_priv;
-	u32 reg;
-
-	dprintk(FE_DEBUG, 1, "Wake %s(%d) from standby",
-		state->device == STV0900 ? "STV0900" : "STV0903",
-		state->demod);
-
-	mutex_lock(&state->internal->demod_lock);
-
-	/* general power on */
-	reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
-	STV090x_SETFIELD(reg, STANDBY_FIELD, 0x00);
-	if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0)
-		goto err;
-
-	switch (state->demod) {
-	case STV090x_DEMODULATOR_0:
-		/* power on ADC 1 */
-		reg = stv090x_read_reg(state, STV090x_TSTTNR1);
-		STV090x_SETFIELD(reg, ADC1_PON_FIELD, 1);
-		if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
-			goto err;
-		/* power on DiSEqC 1 */
-		reg = stv090x_read_reg(state, STV090x_TSTTNR2);
-		STV090x_SETFIELD(reg, DISEQC1_PON_FIELD, 1);
-		if (stv090x_write_reg(state, STV090x_TSTTNR2, reg) < 0)
-			goto err;
-
-		/* activate clocks */
-		reg = stv090x_read_reg(state, STV090x_STOPCLK1);
-		/* packet delineator 1 clock */
-		STV090x_SETFIELD(reg, STOP_CLKPKDT1_FIELD, 0);
-		/* ADC 1 clock */
-		STV090x_SETFIELD(reg, STOP_CLKADCI1_FIELD, 0);
-		/* FEC clock */
-		STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 0);
-		if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
-			goto err;
-		reg = stv090x_read_reg(state, STV090x_STOPCLK2);
-		/* sampling 1 clock */
-		STV090x_SETFIELD(reg, STOP_CLKSAMP1_FIELD, 0);
-		/* viterbi 1 clock */
-		STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, 0);
-		/* TS clock */
-		STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 0);
-		if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
-			goto err;
-		break;
-
-	case STV090x_DEMODULATOR_1:
-		/* power on ADC 2 */
-		reg = stv090x_read_reg(state, STV090x_TSTTNR3);
-		STV090x_SETFIELD(reg, ADC2_PON_FIELD, 1);
-		if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0)
-			goto err;
-		/* power on DiSEqC 2 */
-		reg = stv090x_read_reg(state, STV090x_TSTTNR4);
-		STV090x_SETFIELD(reg, DISEQC2_PON_FIELD, 1);
-		if (stv090x_write_reg(state, STV090x_TSTTNR4, reg) < 0)
-			goto err;
-
-		/* activate clocks */
-		reg = stv090x_read_reg(state, STV090x_STOPCLK1);
-		/* packet delineator 2 clock */
-		STV090x_SETFIELD(reg, STOP_CLKPKDT2_FIELD, 0);
-		/* ADC 2 clock */
-		STV090x_SETFIELD(reg, STOP_CLKADCI2_FIELD, 0);
-		/* FEC clock */
-		STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 0);
-		if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
-			goto err;
-		reg = stv090x_read_reg(state, STV090x_STOPCLK2);
-		/* sampling 2 clock */
-		STV090x_SETFIELD(reg, STOP_CLKSAMP2_FIELD, 0);
-		/* viterbi 2 clock */
-		STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, 0);
-		/* TS clock */
-		STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 0);
-		if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
-			goto err;
-		break;
-
-	default:
-		dprintk(FE_ERROR, 1, "Wrong demodulator!");
-		break;
-	}
-
-	mutex_unlock(&state->internal->demod_lock);
-	return 0;
-err:
-	mutex_unlock(&state->internal->demod_lock);
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static void stv090x_release(struct dvb_frontend *fe)
-{
-	struct stv090x_state *state = fe->demodulator_priv;
-
-	state->internal->num_used--;
-	if (state->internal->num_used <= 0) {
-
-		dprintk(FE_ERROR, 1, "Actually removing");
-
-		remove_dev(state->internal);
-		kfree(state->internal);
-	}
-
-	kfree(state);
-}
-
-static int stv090x_ldpc_mode(struct stv090x_state *state, enum stv090x_mode ldpc_mode)
-{
-	u32 reg = 0;
-
-	reg = stv090x_read_reg(state, STV090x_GENCFG);
-
-	switch (ldpc_mode) {
-	case STV090x_DUAL:
-	default:
-		if ((state->demod_mode != STV090x_DUAL) || (STV090x_GETFIELD(reg, DDEMOD_FIELD) != 1)) {
-			/* set LDPC to dual mode */
-			if (stv090x_write_reg(state, STV090x_GENCFG, 0x1d) < 0)
-				goto err;
-
-			state->demod_mode = STV090x_DUAL;
-
-			reg = stv090x_read_reg(state, STV090x_TSTRES0);
-			STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x1);
-			if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
-				goto err;
-			STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x0);
-			if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
-				goto err;
-
-			if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xff) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xff) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xff) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xff) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xff) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xff) < 0)
-				goto err;
-
-			if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xcc) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xcc) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xcc) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xcc) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xcc) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xcc) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xcc) < 0)
-				goto err;
-
-			if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xff) < 0)
-				goto err;
-			if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xcf) < 0)
-				goto err;
-		}
-		break;
-
-	case STV090x_SINGLE:
-		if (stv090x_stop_modcod(state) < 0)
-			goto err;
-		if (stv090x_activate_modcod_single(state) < 0)
-			goto err;
-
-		if (state->demod == STV090x_DEMODULATOR_1) {
-			if (stv090x_write_reg(state, STV090x_GENCFG, 0x06) < 0) /* path 2 */
-				goto err;
-		} else {
-			if (stv090x_write_reg(state, STV090x_GENCFG, 0x04) < 0) /* path 1 */
-				goto err;
-		}
-
-		reg = stv090x_read_reg(state, STV090x_TSTRES0);
-		STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x1);
-		if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
-			goto err;
-		STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x0);
-		if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
-			goto err;
-
-		reg = STV090x_READ_DEMOD(state, PDELCTRL1);
-		STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x01);
-		if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
-			goto err;
-		STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x00);
-		if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
-			goto err;
-		break;
-	}
-
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-/* return (Hz), clk in Hz*/
-static u32 stv090x_get_mclk(struct stv090x_state *state)
-{
-	const struct stv090x_config *config = state->config;
-	u32 div, reg;
-	u8 ratio;
-
-	div = stv090x_read_reg(state, STV090x_NCOARSE);
-	reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
-	ratio = STV090x_GETFIELD(reg, SELX1RATIO_FIELD) ? 4 : 6;
-
-	return (div + 1) * config->xtal / ratio; /* kHz */
-}
-
-static int stv090x_set_mclk(struct stv090x_state *state, u32 mclk, u32 clk)
-{
-	const struct stv090x_config *config = state->config;
-	u32 reg, div, clk_sel;
-
-	reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
-	clk_sel = ((STV090x_GETFIELD(reg, SELX1RATIO_FIELD) == 1) ? 4 : 6);
-
-	div = ((clk_sel * mclk) / config->xtal) - 1;
-
-	reg = stv090x_read_reg(state, STV090x_NCOARSE);
-	STV090x_SETFIELD(reg, M_DIV_FIELD, div);
-	if (stv090x_write_reg(state, STV090x_NCOARSE, reg) < 0)
-		goto err;
-
-	state->internal->mclk = stv090x_get_mclk(state);
-
-	/*Set the DiseqC frequency to 22KHz */
-	div = state->internal->mclk / 704000;
-	if (STV090x_WRITE_DEMOD(state, F22TX, div) < 0)
-		goto err;
-	if (STV090x_WRITE_DEMOD(state, F22RX, div) < 0)
-		goto err;
-
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_set_tspath(struct stv090x_state *state)
-{
-	u32 reg;
-
-	if (state->internal->dev_ver >= 0x20) {
-		switch (state->config->ts1_mode) {
-		case STV090x_TSMODE_PARALLEL_PUNCTURED:
-		case STV090x_TSMODE_DVBCI:
-			switch (state->config->ts2_mode) {
-			case STV090x_TSMODE_SERIAL_PUNCTURED:
-			case STV090x_TSMODE_SERIAL_CONTINUOUS:
-			default:
-				stv090x_write_reg(state, STV090x_TSGENERAL, 0x00);
-				break;
-
-			case STV090x_TSMODE_PARALLEL_PUNCTURED:
-			case STV090x_TSMODE_DVBCI:
-				if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x06) < 0) /* Mux'd stream mode */
-					goto err;
-				reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
-				STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
-				if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
-					goto err;
-				reg = stv090x_read_reg(state, STV090x_P2_TSCFGM);
-				STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
-				if (stv090x_write_reg(state, STV090x_P2_TSCFGM, reg) < 0)
-					goto err;
-				if (stv090x_write_reg(state, STV090x_P1_TSSPEED, 0x14) < 0)
-					goto err;
-				if (stv090x_write_reg(state, STV090x_P2_TSSPEED, 0x28) < 0)
-					goto err;
-				break;
-			}
-			break;
-
-		case STV090x_TSMODE_SERIAL_PUNCTURED:
-		case STV090x_TSMODE_SERIAL_CONTINUOUS:
-		default:
-			switch (state->config->ts2_mode) {
-			case STV090x_TSMODE_SERIAL_PUNCTURED:
-			case STV090x_TSMODE_SERIAL_CONTINUOUS:
-			default:
-				if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0)
-					goto err;
-				break;
-
-			case STV090x_TSMODE_PARALLEL_PUNCTURED:
-			case STV090x_TSMODE_DVBCI:
-				if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0a) < 0)
-					goto err;
-				break;
-			}
-			break;
-		}
-	} else {
-		switch (state->config->ts1_mode) {
-		case STV090x_TSMODE_PARALLEL_PUNCTURED:
-		case STV090x_TSMODE_DVBCI:
-			switch (state->config->ts2_mode) {
-			case STV090x_TSMODE_SERIAL_PUNCTURED:
-			case STV090x_TSMODE_SERIAL_CONTINUOUS:
-			default:
-				stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x10);
-				break;
-
-			case STV090x_TSMODE_PARALLEL_PUNCTURED:
-			case STV090x_TSMODE_DVBCI:
-				stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x16);
-				reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
-				STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
-				if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
-					goto err;
-				reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
-				STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 0);
-				if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
-					goto err;
-				if (stv090x_write_reg(state, STV090x_P1_TSSPEED, 0x14) < 0)
-					goto err;
-				if (stv090x_write_reg(state, STV090x_P2_TSSPEED, 0x28) < 0)
-					goto err;
-				break;
-			}
-			break;
-
-		case STV090x_TSMODE_SERIAL_PUNCTURED:
-		case STV090x_TSMODE_SERIAL_CONTINUOUS:
-		default:
-			switch (state->config->ts2_mode) {
-			case STV090x_TSMODE_SERIAL_PUNCTURED:
-			case STV090x_TSMODE_SERIAL_CONTINUOUS:
-			default:
-				stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x14);
-				break;
-
-			case STV090x_TSMODE_PARALLEL_PUNCTURED:
-			case STV090x_TSMODE_DVBCI:
-				stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x12);
-				break;
-			}
-			break;
-		}
-	}
-
-	switch (state->config->ts1_mode) {
-	case STV090x_TSMODE_PARALLEL_PUNCTURED:
-		reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
-		STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei);
-		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
-		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
-		if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
-			goto err;
-		break;
-
-	case STV090x_TSMODE_DVBCI:
-		reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
-		STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei);
-		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
-		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
-		if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
-			goto err;
-		break;
-
-	case STV090x_TSMODE_SERIAL_PUNCTURED:
-		reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
-		STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei);
-		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
-		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
-		if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
-			goto err;
-		break;
-
-	case STV090x_TSMODE_SERIAL_CONTINUOUS:
-		reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
-		STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei);
-		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
-		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
-		if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
-			goto err;
-		break;
-
-	default:
-		break;
-	}
-
-	switch (state->config->ts2_mode) {
-	case STV090x_TSMODE_PARALLEL_PUNCTURED:
-		reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
-		STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei);
-		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
-		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
-		if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
-			goto err;
-		break;
-
-	case STV090x_TSMODE_DVBCI:
-		reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
-		STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei);
-		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
-		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
-		if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
-			goto err;
-		break;
-
-	case STV090x_TSMODE_SERIAL_PUNCTURED:
-		reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
-		STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei);
-		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
-		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
-		if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
-			goto err;
-		break;
-
-	case STV090x_TSMODE_SERIAL_CONTINUOUS:
-		reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
-		STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei);
-		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
-		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
-		if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
-			goto err;
-		break;
-
-	default:
-		break;
-	}
-
-	if (state->config->ts1_clk > 0) {
-		u32 speed;
-
-		switch (state->config->ts1_mode) {
-		case STV090x_TSMODE_PARALLEL_PUNCTURED:
-		case STV090x_TSMODE_DVBCI:
-		default:
-			speed = state->internal->mclk /
-				(state->config->ts1_clk / 4);
-			if (speed < 0x08)
-				speed = 0x08;
-			if (speed > 0xFF)
-				speed = 0xFF;
-			break;
-		case STV090x_TSMODE_SERIAL_PUNCTURED:
-		case STV090x_TSMODE_SERIAL_CONTINUOUS:
-			speed = state->internal->mclk /
-				(state->config->ts1_clk / 32);
-			if (speed < 0x20)
-				speed = 0x20;
-			if (speed > 0xFF)
-				speed = 0xFF;
-			break;
-		}
-		reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
-		STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
-		if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
-			goto err;
-		if (stv090x_write_reg(state, STV090x_P1_TSSPEED, speed) < 0)
-			goto err;
-	}
-
-	if (state->config->ts2_clk > 0) {
-		u32 speed;
-
-		switch (state->config->ts2_mode) {
-		case STV090x_TSMODE_PARALLEL_PUNCTURED:
-		case STV090x_TSMODE_DVBCI:
-		default:
-			speed = state->internal->mclk /
-				(state->config->ts2_clk / 4);
-			if (speed < 0x08)
-				speed = 0x08;
-			if (speed > 0xFF)
-				speed = 0xFF;
-			break;
-		case STV090x_TSMODE_SERIAL_PUNCTURED:
-		case STV090x_TSMODE_SERIAL_CONTINUOUS:
-			speed = state->internal->mclk /
-				(state->config->ts2_clk / 32);
-			if (speed < 0x20)
-				speed = 0x20;
-			if (speed > 0xFF)
-				speed = 0xFF;
-			break;
-		}
-		reg = stv090x_read_reg(state, STV090x_P2_TSCFGM);
-		STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
-		if (stv090x_write_reg(state, STV090x_P2_TSCFGM, reg) < 0)
-			goto err;
-		if (stv090x_write_reg(state, STV090x_P2_TSSPEED, speed) < 0)
-			goto err;
-	}
-
-	reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
-	STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01);
-	if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
-		goto err;
-	STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00);
-	if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
-		goto err;
-
-	reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
-	STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01);
-	if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
-		goto err;
-	STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00);
-	if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
-		goto err;
-
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_init(struct dvb_frontend *fe)
-{
-	struct stv090x_state *state = fe->demodulator_priv;
-	const struct stv090x_config *config = state->config;
-	u32 reg;
-
-	if (state->internal->mclk == 0) {
-		/* call tuner init to configure the tuner's clock output
-		   divider directly before setting up the master clock of
-		   the stv090x. */
-		if (stv090x_i2c_gate_ctrl(state, 1) < 0)
-			goto err;
-
-		if (config->tuner_init) {
-			if (config->tuner_init(fe) < 0)
-				goto err_gateoff;
-		}
-
-		if (stv090x_i2c_gate_ctrl(state, 0) < 0)
-			goto err;
-
-		stv090x_set_mclk(state, 135000000, config->xtal); /* 135 Mhz */
-		msleep(5);
-		if (stv090x_write_reg(state, STV090x_SYNTCTRL,
-				      0x20 | config->clk_mode) < 0)
-			goto err;
-		stv090x_get_mclk(state);
-	}
-
-	if (stv090x_wakeup(fe) < 0) {
-		dprintk(FE_ERROR, 1, "Error waking device");
-		goto err;
-	}
-
-	if (stv090x_ldpc_mode(state, state->demod_mode) < 0)
-		goto err;
-
-	reg = STV090x_READ_DEMOD(state, TNRCFG2);
-	STV090x_SETFIELD_Px(reg, TUN_IQSWAP_FIELD, state->inversion);
-	if (STV090x_WRITE_DEMOD(state, TNRCFG2, reg) < 0)
-		goto err;
-	reg = STV090x_READ_DEMOD(state, DEMOD);
-	STV090x_SETFIELD_Px(reg, ROLLOFF_CONTROL_FIELD, state->rolloff);
-	if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
-		goto err;
-
-	if (stv090x_i2c_gate_ctrl(state, 1) < 0)
-		goto err;
-
-	if (config->tuner_set_mode) {
-		if (config->tuner_set_mode(fe, TUNER_WAKE) < 0)
-			goto err_gateoff;
-	}
-
-	if (config->tuner_init) {
-		if (config->tuner_init(fe) < 0)
-			goto err_gateoff;
-	}
-
-	if (stv090x_i2c_gate_ctrl(state, 0) < 0)
-		goto err;
-
-	if (stv090x_set_tspath(state) < 0)
-		goto err;
-
-	return 0;
-
-err_gateoff:
-	stv090x_i2c_gate_ctrl(state, 0);
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-static int stv090x_setup(struct dvb_frontend *fe)
-{
-	struct stv090x_state *state = fe->demodulator_priv;
-	const struct stv090x_config *config = state->config;
-	const struct stv090x_reg *stv090x_initval = NULL;
-	const struct stv090x_reg *stv090x_cut20_val = NULL;
-	unsigned long t1_size = 0, t2_size = 0;
-	u32 reg = 0;
-
-	int i;
-
-	if (state->device == STV0900) {
-		dprintk(FE_DEBUG, 1, "Initializing STV0900");
-		stv090x_initval = stv0900_initval;
-		t1_size = ARRAY_SIZE(stv0900_initval);
-		stv090x_cut20_val = stv0900_cut20_val;
-		t2_size = ARRAY_SIZE(stv0900_cut20_val);
-	} else if (state->device == STV0903) {
-		dprintk(FE_DEBUG, 1, "Initializing STV0903");
-		stv090x_initval = stv0903_initval;
-		t1_size = ARRAY_SIZE(stv0903_initval);
-		stv090x_cut20_val = stv0903_cut20_val;
-		t2_size = ARRAY_SIZE(stv0903_cut20_val);
-	}
-
-	/* STV090x init */
-
-	/* Stop Demod */
-	if (stv090x_write_reg(state, STV090x_P1_DMDISTATE, 0x5c) < 0)
-		goto err;
-	if (stv090x_write_reg(state, STV090x_P2_DMDISTATE, 0x5c) < 0)
-		goto err;
-
-	msleep(5);
-
-	/* Set No Tuner Mode */
-	if (stv090x_write_reg(state, STV090x_P1_TNRCFG, 0x6c) < 0)
-		goto err;
-	if (stv090x_write_reg(state, STV090x_P2_TNRCFG, 0x6c) < 0)
-		goto err;
-
-	/* I2C repeater OFF */
-	STV090x_SETFIELD_Px(reg, ENARPT_LEVEL_FIELD, config->repeater_level);
-	if (stv090x_write_reg(state, STV090x_P1_I2CRPT, reg) < 0)
-		goto err;
-	if (stv090x_write_reg(state, STV090x_P2_I2CRPT, reg) < 0)
-		goto err;
-
-	if (stv090x_write_reg(state, STV090x_NCOARSE, 0x13) < 0) /* set PLL divider */
-		goto err;
-	msleep(5);
-	if (stv090x_write_reg(state, STV090x_I2CCFG, 0x08) < 0) /* 1/41 oversampling */
-		goto err;
-	if (stv090x_write_reg(state, STV090x_SYNTCTRL, 0x20 | config->clk_mode) < 0) /* enable PLL */
-		goto err;
-	msleep(5);
-
-	/* write initval */
-	dprintk(FE_DEBUG, 1, "Setting up initial values");
-	for (i = 0; i < t1_size; i++) {
-		if (stv090x_write_reg(state, stv090x_initval[i].addr, stv090x_initval[i].data) < 0)
-			goto err;
-	}
-
-	state->internal->dev_ver = stv090x_read_reg(state, STV090x_MID);
-	if (state->internal->dev_ver >= 0x20) {
-		if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0)
-			goto err;
-
-		/* write cut20_val*/
-		dprintk(FE_DEBUG, 1, "Setting up Cut 2.0 initial values");
-		for (i = 0; i < t2_size; i++) {
-			if (stv090x_write_reg(state, stv090x_cut20_val[i].addr, stv090x_cut20_val[i].data) < 0)
-				goto err;
-		}
-
-	} else if (state->internal->dev_ver < 0x20) {
-		dprintk(FE_ERROR, 1, "ERROR: Unsupported Cut: 0x%02x!",
-			state->internal->dev_ver);
-
-		goto err;
-	} else if (state->internal->dev_ver > 0x30) {
-		/* we shouldn't bail out from here */
-		dprintk(FE_ERROR, 1, "INFO: Cut: 0x%02x probably incomplete support!",
-			state->internal->dev_ver);
-	}
-
-	/* ADC1 range */
-	reg = stv090x_read_reg(state, STV090x_TSTTNR1);
-	STV090x_SETFIELD(reg, ADC1_INMODE_FIELD,
-		(config->adc1_range == STV090x_ADC_1Vpp) ? 0 : 1);
-	if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
-		goto err;
-
-	/* ADC2 range */
-	reg = stv090x_read_reg(state, STV090x_TSTTNR3);
-	STV090x_SETFIELD(reg, ADC2_INMODE_FIELD,
-		(config->adc2_range == STV090x_ADC_1Vpp) ? 0 : 1);
-	if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0)
-		goto err;
-
-	if (stv090x_write_reg(state, STV090x_TSTRES0, 0x80) < 0)
-		goto err;
-	if (stv090x_write_reg(state, STV090x_TSTRES0, 0x00) < 0)
-		goto err;
-
-	return 0;
-err:
-	dprintk(FE_ERROR, 1, "I/O error");
-	return -1;
-}
-
-int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value,
-		u8 xor_value)
-{
-	struct stv090x_state *state = fe->demodulator_priv;
-	u8 reg = 0;
-
-	STV090x_SETFIELD(reg, GPIOx_OPD_FIELD, dir);
-	STV090x_SETFIELD(reg, GPIOx_CONFIG_FIELD, value);
-	STV090x_SETFIELD(reg, GPIOx_XOR_FIELD, xor_value);
-
-	return stv090x_write_reg(state, STV090x_GPIOxCFG(gpio), reg);
-}
-EXPORT_SYMBOL(stv090x_set_gpio);
-
-static struct dvb_frontend_ops stv090x_ops = {
-	.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
-	.info = {
-		.name			= "STV090x Multistandard",
-		.frequency_min		= 950000,
-		.frequency_max 		= 2150000,
-		.frequency_stepsize	= 0,
-		.frequency_tolerance	= 0,
-		.symbol_rate_min 	= 1000000,
-		.symbol_rate_max 	= 45000000,
-		.caps			= FE_CAN_INVERSION_AUTO |
-					  FE_CAN_FEC_AUTO       |
-					  FE_CAN_QPSK           |
-					  FE_CAN_2G_MODULATION
-	},
-
-	.release			= stv090x_release,
-	.init				= stv090x_init,
-
-	.sleep				= stv090x_sleep,
-	.get_frontend_algo		= stv090x_frontend_algo,
-
-	.diseqc_send_master_cmd		= stv090x_send_diseqc_msg,
-	.diseqc_send_burst		= stv090x_send_diseqc_burst,
-	.diseqc_recv_slave_reply	= stv090x_recv_slave_reply,
-	.set_tone			= stv090x_set_tone,
-
-	.search				= stv090x_search,
-	.read_status			= stv090x_read_status,
-	.read_ber			= stv090x_read_per,
-	.read_signal_strength		= stv090x_read_signal_strength,
-	.read_snr			= stv090x_read_cnr,
-};
-
-
-struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
-				    struct i2c_adapter *i2c,
-				    enum stv090x_demodulator demod)
-{
-	struct stv090x_state *state = NULL;
-	struct stv090x_dev *temp_int;
-
-	state = kzalloc(sizeof (struct stv090x_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	state->verbose				= &verbose;
-	state->config				= config;
-	state->i2c				= i2c;
-	state->frontend.ops			= stv090x_ops;
-	state->frontend.demodulator_priv	= state;
-	state->demod				= demod;
-	state->demod_mode 			= config->demod_mode; /* Single or Dual mode */
-	state->device				= config->device;
-	state->rolloff				= STV090x_RO_35; /* default */
-
-	temp_int = find_dev(state->i2c,
-				state->config->address);
-
-	if ((temp_int != NULL) && (state->demod_mode == STV090x_DUAL)) {
-		state->internal = temp_int->internal;
-		state->internal->num_used++;
-		dprintk(FE_INFO, 1, "Found Internal Structure!");
-	} else {
-		state->internal = kmalloc(sizeof(struct stv090x_internal),
-					  GFP_KERNEL);
-		if (!state->internal)
-			goto error;
-		temp_int = append_internal(state->internal);
-		if (!temp_int) {
-			kfree(state->internal);
-			goto error;
-		}
-		state->internal->num_used = 1;
-		state->internal->mclk = 0;
-		state->internal->dev_ver = 0;
-		state->internal->i2c_adap = state->i2c;
-		state->internal->i2c_addr = state->config->address;
-		dprintk(FE_INFO, 1, "Create New Internal Structure!");
-
-		mutex_init(&state->internal->demod_lock);
-		mutex_init(&state->internal->tuner_lock);
-
-		if (stv090x_setup(&state->frontend) < 0) {
-			dprintk(FE_ERROR, 1, "Error setting up device");
-			goto err_remove;
-		}
-	}
-
-	/* workaround for stuck DiSEqC output */
-	if (config->diseqc_envelope_mode)
-		stv090x_send_diseqc_burst(&state->frontend, SEC_MINI_A);
-
-	dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x",
-	       state->device == STV0900 ? "STV0900" : "STV0903",
-	       demod,
-	       state->internal->dev_ver);
-
-	return &state->frontend;
-
-err_remove:
-	remove_dev(state->internal);
-	kfree(state->internal);
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(stv090x_attach);
-MODULE_PARM_DESC(verbose, "Set Verbosity level");
-MODULE_AUTHOR("Manu Abraham");
-MODULE_DESCRIPTION("STV090x Multi-Std Broadcast frontend");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stv090x.h b/drivers/media/dvb/frontends/stv090x.h
deleted file mode 100644
index 29cdc2b..0000000
--- a/drivers/media/dvb/frontends/stv090x.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
-	STV0900/0903 Multistandard Broadcast Frontend driver
-	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
-
-	Copyright (C) ST Microelectronics
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __STV090x_H
-#define __STV090x_H
-
-enum stv090x_demodulator {
-	STV090x_DEMODULATOR_0 = 1,
-	STV090x_DEMODULATOR_1
-};
-
-enum stv090x_device {
-	STV0903	=  0,
-	STV0900,
-};
-
-enum stv090x_mode {
-	STV090x_DUAL = 0,
-	STV090x_SINGLE
-};
-
-enum stv090x_tsmode {
-	STV090x_TSMODE_SERIAL_PUNCTURED	= 1,
-	STV090x_TSMODE_SERIAL_CONTINUOUS,
-	STV090x_TSMODE_PARALLEL_PUNCTURED,
-	STV090x_TSMODE_DVBCI
-};
-
-enum stv090x_clkmode {
-	STV090x_CLK_INT = 0, /* Clk i/p = CLKI */
-	STV090x_CLK_EXT = 2 /* Clk i/p = XTALI */
-};
-
-enum stv090x_i2crpt {
-	STV090x_RPTLEVEL_256	= 0,
-	STV090x_RPTLEVEL_128	= 1,
-	STV090x_RPTLEVEL_64	= 2,
-	STV090x_RPTLEVEL_32	= 3,
-	STV090x_RPTLEVEL_16	= 4,
-	STV090x_RPTLEVEL_8	= 5,
-	STV090x_RPTLEVEL_4	= 6,
-	STV090x_RPTLEVEL_2	= 7,
-};
-
-enum stv090x_adc_range {
-	STV090x_ADC_2Vpp	= 0,
-	STV090x_ADC_1Vpp	= 1
-};
-
-struct stv090x_config {
-	enum stv090x_device	device;
-	enum stv090x_mode	demod_mode;
-	enum stv090x_clkmode	clk_mode;
-
-	u32 xtal; /* default: 8000000 */
-	u8 address; /* default: 0x68 */
-
-	u8 ts1_mode;
-	u8 ts2_mode;
-	u32 ts1_clk;
-	u32 ts2_clk;
-
-	u8 ts1_tei : 1;
-	u8 ts2_tei : 1;
-
-	enum stv090x_i2crpt	repeater_level;
-
-	u8			tuner_bbgain; /* default: 10db */
-	enum stv090x_adc_range	adc1_range; /* default: 2Vpp */
-	enum stv090x_adc_range	adc2_range; /* default: 2Vpp */
-
-	bool diseqc_envelope_mode;
-
-	int (*tuner_init) (struct dvb_frontend *fe);
-	int (*tuner_sleep) (struct dvb_frontend *fe);
-	int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode);
-	int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency);
-	int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency);
-	int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth);
-	int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth);
-	int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain);
-	int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain);
-	int (*tuner_set_refclk)  (struct dvb_frontend *fe, u32 refclk);
-	int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status);
-	void (*tuner_i2c_lock) (struct dvb_frontend *fe, int lock);
-};
-
-#if defined(CONFIG_DVB_STV090x) || (defined(CONFIG_DVB_STV090x_MODULE) && defined(MODULE))
-
-extern struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
-					   struct i2c_adapter *i2c,
-					   enum stv090x_demodulator demod);
-
-/* dir = 0 -> output, dir = 1 -> input/open-drain */
-extern int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio,
-		u8 dir, u8 value, u8 xor_value);
-
-#else
-
-static inline struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
-						  struct i2c_adapter *i2c,
-						  enum stv090x_demodulator demod)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio,
-		u8 opd, u8 value, u8 xor_value)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-#endif /* CONFIG_DVB_STV090x */
-
-#endif /* __STV090x_H */
diff --git a/drivers/media/dvb/frontends/stv090x_priv.h b/drivers/media/dvb/frontends/stv090x_priv.h
deleted file mode 100644
index 5b780c8..0000000
--- a/drivers/media/dvb/frontends/stv090x_priv.h
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
-	STV0900/0903 Multistandard Broadcast Frontend driver
-	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
-
-	Copyright (C) ST Microelectronics
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __STV090x_PRIV_H
-#define __STV090x_PRIV_H
-
-#include "dvb_frontend.h"
-
-#define FE_ERROR				0
-#define FE_NOTICE				1
-#define FE_INFO					2
-#define FE_DEBUG				3
-#define FE_DEBUGREG				4
-
-#define dprintk(__y, __z, format, arg...) do {						\
-	if (__z) {									\
-		if	((verbose > FE_ERROR) && (verbose > __y))			\
-			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);		\
-		else if	((verbose > FE_NOTICE) && (verbose > __y))			\
-			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
-		else if ((verbose > FE_INFO) && (verbose > __y))			\
-			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);		\
-		else if ((verbose > FE_DEBUG) && (verbose > __y))			\
-			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
-	} else {									\
-		if (verbose > __y)							\
-			printk(format, ##arg);						\
-	}										\
-} while (0)
-
-#define STV090x_READ_DEMOD(__state, __reg) ((			\
-	(__state)->demod == STV090x_DEMODULATOR_1)	?	\
-	stv090x_read_reg(__state, STV090x_P2_##__reg) :		\
-	stv090x_read_reg(__state, STV090x_P1_##__reg))
-
-#define STV090x_WRITE_DEMOD(__state, __reg, __data) ((		\
-	(__state)->demod == STV090x_DEMODULATOR_1)	?	\
-	stv090x_write_reg(__state, STV090x_P2_##__reg, __data) :\
-	stv090x_write_reg(__state, STV090x_P1_##__reg, __data))
-
-#define STV090x_ADDR_OFFST(__state, __x) ((			\
-	(__state->demod) == STV090x_DEMODULATOR_1)	?	\
-		STV090x_P1_##__x :				\
-		STV090x_P2_##__x)
-
-
-#define STV090x_SETFIELD(mask, bitf, val)	(mask = (mask & (~(((1 << STV090x_WIDTH_##bitf) - 1) <<\
-							 STV090x_OFFST_##bitf))) | \
-							 (val << STV090x_OFFST_##bitf))
-
-#define STV090x_GETFIELD(val, bitf)		((val >> STV090x_OFFST_##bitf) & ((1 << STV090x_WIDTH_##bitf) - 1))
-
-
-#define STV090x_SETFIELD_Px(mask, bitf, val)	(mask = (mask & (~(((1 << STV090x_WIDTH_Px_##bitf) - 1) <<\
-							 STV090x_OFFST_Px_##bitf))) | \
-							 (val << STV090x_OFFST_Px_##bitf))
-
-#define STV090x_GETFIELD_Px(val, bitf)		((val >> STV090x_OFFST_Px_##bitf) & ((1 << STV090x_WIDTH_Px_##bitf) - 1))
-
-#define MAKEWORD16(__a, __b)			(((__a) << 8) | (__b))
-
-#define MSB(__x)				((__x >> 8) & 0xff)
-#define LSB(__x)				(__x & 0xff)
-
-
-#define STV090x_IQPOWER_THRESHOLD	  30
-#define STV090x_SEARCH_AGC2_TH_CUT20	 700
-#define STV090x_SEARCH_AGC2_TH_CUT30	1400
-
-#define STV090x_SEARCH_AGC2_TH(__ver)	\
-	((__ver <= 0x20) ?		\
-	STV090x_SEARCH_AGC2_TH_CUT20 :	\
-	STV090x_SEARCH_AGC2_TH_CUT30)
-
-enum stv090x_signal_state {
-	STV090x_NOAGC1,
-	STV090x_NOCARRIER,
-	STV090x_NODATA,
-	STV090x_DATAOK,
-	STV090x_RANGEOK,
-	STV090x_OUTOFRANGE
-};
-
-enum stv090x_fec {
-	STV090x_PR12 = 0,
-	STV090x_PR23,
-	STV090x_PR34,
-	STV090x_PR45,
-	STV090x_PR56,
-	STV090x_PR67,
-	STV090x_PR78,
-	STV090x_PR89,
-	STV090x_PR910,
-	STV090x_PRERR
-};
-
-enum stv090x_modulation {
-	STV090x_QPSK,
-	STV090x_8PSK,
-	STV090x_16APSK,
-	STV090x_32APSK,
-	STV090x_UNKNOWN
-};
-
-enum stv090x_frame {
-	STV090x_LONG_FRAME,
-	STV090x_SHORT_FRAME
-};
-
-enum stv090x_pilot {
-	STV090x_PILOTS_OFF,
-	STV090x_PILOTS_ON
-};
-
-enum stv090x_rolloff {
-	STV090x_RO_35,
-	STV090x_RO_25,
-	STV090x_RO_20
-};
-
-enum stv090x_inversion {
-	STV090x_IQ_AUTO,
-	STV090x_IQ_NORMAL,
-	STV090x_IQ_SWAP
-};
-
-enum stv090x_modcod {
-	STV090x_DUMMY_PLF = 0,
-	STV090x_QPSK_14,
-	STV090x_QPSK_13,
-	STV090x_QPSK_25,
-	STV090x_QPSK_12,
-	STV090x_QPSK_35,
-	STV090x_QPSK_23,
-	STV090x_QPSK_34,
-	STV090x_QPSK_45,
-	STV090x_QPSK_56,
-	STV090x_QPSK_89,
-	STV090x_QPSK_910,
-	STV090x_8PSK_35,
-	STV090x_8PSK_23,
-	STV090x_8PSK_34,
-	STV090x_8PSK_56,
-	STV090x_8PSK_89,
-	STV090x_8PSK_910,
-	STV090x_16APSK_23,
-	STV090x_16APSK_34,
-	STV090x_16APSK_45,
-	STV090x_16APSK_56,
-	STV090x_16APSK_89,
-	STV090x_16APSK_910,
-	STV090x_32APSK_34,
-	STV090x_32APSK_45,
-	STV090x_32APSK_56,
-	STV090x_32APSK_89,
-	STV090x_32APSK_910,
-	STV090x_MODCODE_UNKNOWN
-};
-
-enum stv090x_search {
-	STV090x_SEARCH_DSS = 0,
-	STV090x_SEARCH_DVBS1,
-	STV090x_SEARCH_DVBS2,
-	STV090x_SEARCH_AUTO
-};
-
-enum stv090x_algo {
-	STV090x_BLIND_SEARCH,
-	STV090x_COLD_SEARCH,
-	STV090x_WARM_SEARCH
-};
-
-enum stv090x_delsys {
-	STV090x_ERROR = 0,
-	STV090x_DVBS1 = 1,
-	STV090x_DVBS2,
-	STV090x_DSS
-};
-
-struct stv090x_long_frame_crloop {
-	enum stv090x_modcod	modcod;
-
-	u8 crl_pilots_on_2;
-	u8 crl_pilots_off_2;
-	u8 crl_pilots_on_5;
-	u8 crl_pilots_off_5;
-	u8 crl_pilots_on_10;
-	u8 crl_pilots_off_10;
-	u8 crl_pilots_on_20;
-	u8 crl_pilots_off_20;
-	u8 crl_pilots_on_30;
-	u8 crl_pilots_off_30;
-};
-
-struct stv090x_short_frame_crloop {
-	enum stv090x_modulation	modulation;
-
-	u8 crl_2;  /*      SR <   3M */
-	u8 crl_5;  /*  3 < SR <=  7M */
-	u8 crl_10; /*  7 < SR <= 15M */
-	u8 crl_20; /* 10 < SR <= 25M */
-	u8 crl_30; /* 10 < SR <= 45M */
-};
-
-struct stv090x_reg {
-	u16 addr;
-	u8  data;
-};
-
-struct stv090x_tab {
-	s32 real;
-	s32 read;
-};
-
-struct stv090x_internal {
-	struct i2c_adapter 	*i2c_adap;
-	u8			i2c_addr;
-
-	struct mutex		demod_lock; /* Lock access to shared register */
-	struct mutex		tuner_lock; /* Lock access to tuners */
-	s32			mclk; /* Masterclock Divider factor */
-	u32			dev_ver;
-
-	int			num_used;
-};
-
-struct stv090x_state {
-	enum stv090x_device		device;
-	enum stv090x_demodulator	demod;
-	enum stv090x_mode		demod_mode;
-	struct stv090x_internal		*internal;
-
-	struct i2c_adapter		*i2c;
-	const struct stv090x_config	*config;
-	struct dvb_frontend		frontend;
-
-	u32				*verbose; /* Cached module verbosity */
-
-	enum stv090x_delsys		delsys;
-	enum stv090x_fec		fec;
-	enum stv090x_modulation		modulation;
-	enum stv090x_modcod		modcod;
-	enum stv090x_search		search_mode;
-	enum stv090x_frame		frame_len;
-	enum stv090x_pilot		pilots;
-	enum stv090x_rolloff		rolloff;
-	enum stv090x_inversion		inversion;
-	enum stv090x_algo		algo;
-
-	u32				frequency;
-	u32				srate;
-
-	s32				tuner_bw;
-
-	s32				search_range;
-
-	s32				DemodTimeout;
-	s32				FecTimeout;
-};
-
-#endif /* __STV090x_PRIV_H */
diff --git a/drivers/media/dvb/frontends/stv090x_reg.h b/drivers/media/dvb/frontends/stv090x_reg.h
deleted file mode 100644
index 93741ee..0000000
--- a/drivers/media/dvb/frontends/stv090x_reg.h
+++ /dev/null
@@ -1,2371 +0,0 @@
-/*
-	STV0900/0903 Multistandard Broadcast Frontend driver
-	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
-
-	Copyright (C) ST Microelectronics
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __STV090x_REG_H
-#define __STV090x_REG_H
-
-#define STV090x_MID				0xf100
-#define STV090x_OFFST_MCHIP_IDENT_FIELD		4
-#define STV090x_WIDTH_MCHIP_IDENT_FIELD		4
-#define STV090x_OFFST_MRELEASE_FIELD		0
-#define STV090x_WIDTH_MRELEASE_FIELD		4
-
-#define STV090x_DACR1				0xf113
-#define STV090x_OFFST_DACR1_MODE_FIELD		5
-#define STV090x_WIDTH_DACR1_MODE_FIELD		3
-#define STV090x_OFFST_DACR1_VALUE_FIELD		0
-#define STV090x_WIDTH_DACR1_VALUE_FIELD		4
-
-#define STV090x_DACR2				0xf114
-#define STV090x_OFFST_DACR2_VALUE_FIELD		0
-#define STV090x_WIDTH_DACR2_VALUE_FIELD		8
-
-#define STV090x_OUTCFG				0xf11c
-#define STV090x_OFFST_OUTSERRS1_HZ_FIELD	6
-#define STV090x_WIDTH_OUTSERRS1_HZ_FIELD	1
-#define STV090x_OFFST_OUTSERRS2_HZ_FIELD	5
-#define STV090x_WIDTH_OUTSERRS2_HZ_FIELD	1
-#define STV090x_OFFST_OUTSERRS3_HZ_FIELD	4
-#define STV090x_WIDTH_OUTSERRS3_HZ_FIELD	1
-#define STV090x_OFFST_OUTPARRS3_HZ_FIELD	3
-#define STV090x_WIDTH_OUTPARRS3_HZ_FIELD	1
-
-#define STV090x_MODECFG				0xf11d
-
-#define STV090x_IRQSTATUS3			0xf120
-#define STV090x_OFFST_SPLL_LOCK_FIELD		5
-#define STV090x_WIDTH_SPLL_LOCK_FIELD		1
-#define STV090x_OFFST_SSTREAM_LCK_3_FIELD	4
-#define STV090x_WIDTH_SSTREAM_LCK_3_FIELD	1
-#define STV090x_OFFST_SSTREAM_LCK_2_FIELD	3
-#define STV090x_WIDTH_SSTREAM_LCK_2_FIELD	1
-#define STV090x_OFFST_SSTREAM_LCK_1_FIELD	2
-#define STV090x_WIDTH_SSTREAM_LCK_1_FIELD	1
-#define STV090x_OFFST_SDVBS1_PRF_2_FIELD	1
-#define STV090x_WIDTH_SDVBS1_PRF_2_FIELD	1
-#define STV090x_OFFST_SDVBS1_PRF_1_FIELD	0
-#define STV090x_WIDTH_SDVBS1_PRF_1_FIELD	1
-
-#define STV090x_IRQSTATUS2			0xf121
-#define STV090x_OFFST_SSPY_ENDSIM_3_FIELD	7
-#define STV090x_WIDTH_SSPY_ENDSIM_3_FIELD	1
-#define STV090x_OFFST_SSPY_ENDSIM_2_FIELD	6
-#define STV090x_WIDTH_SSPY_ENDSIM_2_FIELD	1
-#define STV090x_OFFST_SSPY_ENDSIM_1_FIELD	5
-#define STV090x_WIDTH_SSPY_ENDSIM_1_FIELD	1
-#define STV090x_OFFST_SPKTDEL_ERROR_2_FIELD	4
-#define STV090x_WIDTH_SPKTDEL_ERROR_2_FIELD	1
-#define STV090x_OFFST_SPKTDEL_LOCKB_2_FIELD	3
-#define STV090x_WIDTH_SPKTDEL_LOCKB_2_FIELD	1
-#define STV090x_OFFST_SPKTDEL_LOCK_2_FIELD	2
-#define STV090x_WIDTH_SPKTDEL_LOCK_2_FIELD	1
-#define STV090x_OFFST_SPKTDEL_ERROR_1_FIELD	1
-#define STV090x_WIDTH_SPKTDEL_ERROR_1_FIELD	1
-#define STV090x_OFFST_SPKTDEL_LOCKB_1_FIELD	0
-#define STV090x_WIDTH_SPKTDEL_LOCKB_1_FIELD	1
-
-#define STV090x_IRQSTATUS1			0xf122
-#define STV090x_OFFST_SPKTDEL_LOCK_1_FIELD	7
-#define STV090x_WIDTH_SPKTDEL_LOCK_1_FIELD	1
-#define STV090x_OFFST_SDEMOD_LOCKB_2_FIELD	2
-#define STV090x_WIDTH_SDEMOD_LOCKB_2_FIELD	1
-#define STV090x_OFFST_SDEMOD_LOCK_2_FIELD	1
-#define STV090x_WIDTH_SDEMOD_LOCK_2_FIELD	1
-#define STV090x_OFFST_SDEMOD_IRQ_2_FIELD	0
-#define STV090x_WIDTH_SDEMOD_IRQ_2_FIELD	1
-
-#define STV090x_IRQSTATUS0			0xf123
-#define STV090x_OFFST_SDEMOD_LOCKB_1_FIELD	7
-#define STV090x_WIDTH_SDEMOD_LOCKB_1_FIELD	1
-#define STV090x_OFFST_SDEMOD_LOCK_1_FIELD	6
-#define STV090x_WIDTH_SDEMOD_LOCK_1_FIELD	1
-#define STV090x_OFFST_SDEMOD_IRQ_1_FIELD	5
-#define STV090x_WIDTH_SDEMOD_IRQ_1_FIELD	1
-#define STV090x_OFFST_SBCH_ERRFLAG_FIELD	4
-#define STV090x_WIDTH_SBCH_ERRFLAG_FIELD	1
-#define STV090x_OFFST_SDISEQC2RX_IRQ_FIELD	3
-#define STV090x_WIDTH_SDISEQC2RX_IRQ_FIELD	1
-#define STV090x_OFFST_SDISEQC2TX_IRQ_FIELD	2
-#define STV090x_WIDTH_SDISEQC2TX_IRQ_FIELD	1
-#define STV090x_OFFST_SDISEQC1RX_IRQ_FIELD	1
-#define STV090x_WIDTH_SDISEQC1RX_IRQ_FIELD	1
-#define STV090x_OFFST_SDISEQC1TX_IRQ_FIELD	0
-#define STV090x_WIDTH_SDISEQC1TX_IRQ_FIELD	1
-
-#define STV090x_IRQMASK3			0xf124
-#define STV090x_OFFST_MPLL_LOCK_FIELD		5
-#define STV090x_WIDTH_MPLL_LOCK_FIELD		1
-#define STV090x_OFFST_MSTREAM_LCK_3_FIELD	4
-#define STV090x_WIDTH_MSTREAM_LCK_3_FIELD	1
-#define STV090x_OFFST_MSTREAM_LCK_2_FIELD	3
-#define STV090x_WIDTH_MSTREAM_LCK_2_FIELD	1
-#define STV090x_OFFST_MSTREAM_LCK_1_FIELD	2
-#define STV090x_WIDTH_MSTREAM_LCK_1_FIELD	1
-#define STV090x_OFFST_MDVBS1_PRF_2_FIELD	1
-#define STV090x_WIDTH_MDVBS1_PRF_2_FIELD	1
-#define STV090x_OFFST_MDVBS1_PRF_1_FIELD	0
-#define STV090x_WIDTH_MDVBS1_PRF_1_FIELD	1
-
-#define STV090x_IRQMASK2			0xf125
-#define STV090x_OFFST_MSPY_ENDSIM_3_FIELD	7
-#define STV090x_WIDTH_MSPY_ENDSIM_3_FIELD	1
-#define STV090x_OFFST_MSPY_ENDSIM_2_FIELD	6
-#define STV090x_WIDTH_MSPY_ENDSIM_2_FIELD	1
-#define STV090x_OFFST_MSPY_ENDSIM_1_FIELD	5
-#define STV090x_WIDTH_MSPY_ENDSIM_1_FIELD	1
-#define STV090x_OFFST_MPKTDEL_ERROR_2_FIELD	4
-#define STV090x_WIDTH_MPKTDEL_ERROR_2_FIELD	1
-#define STV090x_OFFST_MPKTDEL_LOCKB_2_FIELD	3
-#define STV090x_WIDTH_MPKTDEL_LOCKB_2_FIELD	1
-#define STV090x_OFFST_MPKTDEL_LOCK_2_FIELD	2
-#define STV090x_WIDTH_MPKTDEL_LOCK_2_FIELD	1
-#define STV090x_OFFST_MPKTDEL_ERROR_1_FIELD	1
-#define STV090x_WIDTH_MPKTDEL_ERROR_1_FIELD	1
-#define STV090x_OFFST_MPKTDEL_LOCKB_1_FIELD	0
-#define STV090x_WIDTH_MPKTDEL_LOCKB_1_FIELD	1
-
-#define STV090x_IRQMASK1			0xf126
-#define STV090x_OFFST_MPKTDEL_LOCK_1_FIELD	7
-#define STV090x_WIDTH_MPKTDEL_LOCK_1_FIELD	1
-#define STV090x_OFFST_MEXTPINB2_FIELD		6
-#define STV090x_WIDTH_MEXTPINB2_FIELD		1
-#define STV090x_OFFST_MEXTPIN2_FIELD		5
-#define STV090x_WIDTH_MEXTPIN2_FIELD		1
-#define STV090x_OFFST_MEXTPINB1_FIELD		4
-#define STV090x_WIDTH_MEXTPINB1_FIELD		1
-#define STV090x_OFFST_MEXTPIN1_FIELD		3
-#define STV090x_WIDTH_MEXTPIN1_FIELD		1
-#define STV090x_OFFST_MDEMOD_LOCKB_2_FIELD	2
-#define STV090x_WIDTH_MDEMOD_LOCKB_2_FIELD	1
-#define STV090x_OFFST_MDEMOD_LOCK_2_FIELD	1
-#define STV090x_WIDTH_MDEMOD_LOCK_2_FIELD	1
-#define STV090x_OFFST_MDEMOD_IRQ_2_FIELD	0
-#define STV090x_WIDTH_MDEMOD_IRQ_2_FIELD	1
-
-#define STV090x_IRQMASK0			0xf127
-#define STV090x_OFFST_MDEMOD_LOCKB_1_FIELD	7
-#define STV090x_WIDTH_MDEMOD_LOCKB_1_FIELD	1
-#define STV090x_OFFST_MDEMOD_LOCK_1_FIELD	6
-#define STV090x_WIDTH_MDEMOD_LOCK_1_FIELD	1
-#define STV090x_OFFST_MDEMOD_IRQ_1_FIELD	5
-#define STV090x_WIDTH_MDEMOD_IRQ_1_FIELD	1
-#define STV090x_OFFST_MBCH_ERRFLAG_FIELD	4
-#define STV090x_WIDTH_MBCH_ERRFLAG_FIELD	1
-#define STV090x_OFFST_MDISEQC2RX_IRQ_FIELD	3
-#define STV090x_WIDTH_MDISEQC2RX_IRQ_FIELD	1
-#define STV090x_OFFST_MDISEQC2TX_IRQ_FIELD	2
-#define STV090x_WIDTH_MDISEQC2TX_IRQ_FIELD	1
-#define STV090x_OFFST_MDISEQC1RX_IRQ_FIELD	1
-#define STV090x_WIDTH_MDISEQC1RX_IRQ_FIELD	1
-#define STV090x_OFFST_MDISEQC1TX_IRQ_FIELD	0
-#define STV090x_WIDTH_MDISEQC1TX_IRQ_FIELD	1
-
-#define STV090x_I2CCFG				0xf129
-#define STV090x_OFFST_12C_FASTMODE_FIELD	3
-#define STV090x_WIDTH_12C_FASTMODE_FIELD	1
-#define STV090x_OFFST_12CADDR_INC_FIELD		0
-#define STV090x_WIDTH_12CADDR_INC_FIELD		2
-
-#define STV090x_Px_I2CRPT(__x)			(0xf12a + (__x - 1) * 0x1)
-#define STV090x_P1_I2CRPT			STV090x_Px_I2CRPT(1)
-#define STV090x_P2_I2CRPT			STV090x_Px_I2CRPT(2)
-#define STV090x_OFFST_Px_I2CT_ON_FIELD		7
-#define STV090x_WIDTH_Px_I2CT_ON_FIELD		1
-#define STV090x_OFFST_Px_ENARPT_LEVEL_FIELD	4
-#define STV090x_WIDTH_Px_ENARPT_LEVEL_FIELD	3
-#define STV090x_OFFST_Px_SCLT_DELAY_FIELD	3
-#define STV090x_WIDTH_Px_SCLT_DELAY_FIELD	1
-#define STV090x_OFFST_Px_STOP_ENABLE_FIELD	2
-#define STV090x_WIDTH_Px_STOP_ENABLE_FIELD	1
-#define STV090x_OFFST_Px_STOP_SDAT2SDA_FIELD	1
-#define STV090x_WIDTH_Px_STOP_SDAT2SDA_FIELD	1
-
-#define STV090x_CLKI2CFG			0xf140
-#define STV090x_OFFST_CLKI2_OPD_FIELD		7
-#define STV090x_WIDTH_CLKI2_OPD_FIELD		1
-#define STV090x_OFFST_CLKI2_CONFIG_FIELD	1
-#define STV090x_WIDTH_CLKI2_CONFIG_FIELD	6
-#define STV090x_OFFST_CLKI2_XOR_FIELD		0
-#define STV090x_WIDTH_CLKI2_XOR_FIELD		1
-
-#define STV090x_GPIOxCFG(__x)			(0xf141 + (__x - 1))
-#define STV090x_GPIO1CFG			STV090x_GPIOxCFG(1)
-#define STV090x_GPIO2CFG			STV090x_GPIOxCFG(2)
-#define STV090x_GPIO3CFG			STV090x_GPIOxCFG(3)
-#define STV090x_GPIO4CFG			STV090x_GPIOxCFG(4)
-#define STV090x_GPIO5CFG			STV090x_GPIOxCFG(5)
-#define STV090x_GPIO6CFG			STV090x_GPIOxCFG(6)
-#define STV090x_GPIO7CFG			STV090x_GPIOxCFG(7)
-#define STV090x_GPIO8CFG			STV090x_GPIOxCFG(8)
-#define STV090x_GPIO9CFG			STV090x_GPIOxCFG(9)
-#define STV090x_GPIO10CFG			STV090x_GPIOxCFG(10)
-#define STV090x_GPIO11CFG			STV090x_GPIOxCFG(11)
-#define STV090x_GPIO12CFG			STV090x_GPIOxCFG(12)
-#define STV090x_GPIO13CFG			STV090x_GPIOxCFG(13)
-#define STV090x_OFFST_GPIOx_OPD_FIELD		7
-#define STV090x_WIDTH_GPIOx_OPD_FIELD		1
-#define STV090x_OFFST_GPIOx_CONFIG_FIELD	1
-#define STV090x_WIDTH_GPIOx_CONFIG_FIELD	6
-#define STV090x_OFFST_GPIOx_XOR_FIELD		0
-#define STV090x_WIDTH_GPIOx_XOR_FIELD		1
-
-#define STV090x_CSxCFG(__x)			(0xf14e + __x * 0x1)
-#define STV090x_CS0CFG				STV090x_CSxCFG(0)
-#define STV090x_CS1CFG				STV090x_CSxCFG(1)
-#define STV090x_OFFST_CSX_OPD_FIELD		7
-#define STV090x_WIDTH_CSX_OPD_FIELD		1
-#define STV090x_OFFST_CSX_CONFIG_FIELD		1
-#define STV090x_WIDTH_CSX_CONFIG_FIELD		6
-#define STV090x_OFFST_CSX_XOR_FIELD		0
-#define STV090x_WIDTH_CSX_XOR_FIELD		1
-
-
-#define STV090x_STDBYCFG			0xf150
-#define STV090x_OFFST_STDBY_OPD_FIELD		7
-#define STV090x_WIDTH_STDBY_OPD_FIELD		1
-#define STV090x_OFFST_STDBY_CONFIG_FIELD	1
-#define STV090x_WIDTH_STDBY_CONFIG_FIELD	6
-#define STV090x_OFFST_STDBY_XOR_FIELD		0
-#define STV090x_WIDTH_STDBY_XOR_FIELD		1
-
-#define STV090x_DIRCLKCFG			0xf151
-#define STV090x_OFFST_DIRCLK_OPD_FIELD		7
-#define STV090x_WIDTH_DIRCLK_OPD_FIELD		1
-#define STV090x_OFFST_DIRCLK_CONFIG_FIELD	1
-#define STV090x_WIDTH_DIRCLK_CONFIG_FIELD	6
-#define STV090x_OFFST_DIRCLK_XOR_FIELD		0
-#define STV090x_WIDTH_DIRCLK_XOR_FIELD		1
-
-
-#define STV090x_AGCRFxCFG(__x)			(0xf152 + (__x - 1) * 0x4)
-#define STV090x_AGCRF1CFG			STV090x_AGCRFxCFG(1)
-#define STV090x_AGCRF2CFG			STV090x_AGCRFxCFG(2)
-#define STV090x_OFFST_AGCRFx_OPD_FIELD		7
-#define STV090x_WIDTH_AGCRFx_OPD_FIELD		1
-#define STV090x_OFFST_AGCRFx_CONFIG_FIELD	1
-#define STV090x_WIDTH_AGCRFx_CONFIG_FIELD	6
-#define STV090x_OFFST_AGCRFx_XOR_FIELD		0
-#define STV090x_WIDTH_AGCRFx_XOR_FIELD		1
-
-#define STV090x_SDATxCFG(__x)			(0xf153 + (__x - 1) * 0x4)
-#define STV090x_SDAT1CFG			STV090x_SDATxCFG(1)
-#define STV090x_SDAT2CFG			STV090x_SDATxCFG(2)
-#define STV090x_OFFST_SDATx_OPD_FIELD		7
-#define STV090x_WIDTH_SDATx_OPD_FIELD		1
-#define STV090x_OFFST_SDATx_CONFIG_FIELD	1
-#define STV090x_WIDTH_SDATx_CONFIG_FIELD	6
-#define STV090x_OFFST_SDATx_XOR_FIELD		0
-#define STV090x_WIDTH_SDATx_XOR_FIELD		1
-
-#define STV090x_SCLTxCFG(__x)			(0xf154 + (__x - 1) * 0x4)
-#define STV090x_SCLT1CFG			STV090x_SCLTxCFG(1)
-#define STV090x_SCLT2CFG			STV090x_SCLTxCFG(2)
-#define STV090x_OFFST_SCLTx_OPD_FIELD		7
-#define STV090x_WIDTH_SCLTx_OPD_FIELD		1
-#define STV090x_OFFST_SCLTx_CONFIG_FIELD	1
-#define STV090x_WIDTH_SCLTx_CONFIG_FIELD	6
-#define STV090x_OFFST_SCLTx_XOR_FIELD		0
-#define STV090x_WIDTH_SCLTx_XOR_FIELD		1
-
-#define STV090x_DISEQCOxCFG(__x)		(0xf155 + (__x - 1) * 0x4)
-#define STV090x_DISEQCO1CFG			STV090x_DISEQCOxCFG(1)
-#define STV090x_DISEQCO2CFG			STV090x_DISEQCOxCFG(2)
-#define STV090x_OFFST_DISEQCOx_OPD_FIELD	7
-#define STV090x_WIDTH_DISEQCOx_OPD_FIELD	1
-#define STV090x_OFFST_DISEQCOx_CONFIG_FIELD	1
-#define STV090x_WIDTH_DISEQCOx_CONFIG_FIELD	6
-#define STV090x_OFFST_DISEQCOx_XOR_FIELD	0
-#define STV090x_WIDTH_DISEQCOx_XOR_FIELD	1
-
-#define STV090x_CLKOUT27CFG			0xf15a
-#define STV090x_OFFST_CLKOUT27_OPD_FIELD	7
-#define STV090x_WIDTH_CLKOUT27_OPD_FIELD	1
-#define STV090x_OFFST_CLKOUT27_CONFIG_FIELD	1
-#define STV090x_WIDTH_CLKOUT27_CONFIG_FIELD	6
-#define STV090x_OFFST_CLKOUT27_XOR_FIELD	0
-#define STV090x_WIDTH_CLKOUT27_XOR_FIELD	1
-
-#define STV090x_ERRORxCFG(__x)			(0xf15b + (__x - 1) * 0x5)
-#define STV090x_ERROR1CFG			STV090x_ERRORxCFG(1)
-#define STV090x_ERROR2CFG			STV090x_ERRORxCFG(2)
-#define STV090x_ERROR3CFG			STV090x_ERRORxCFG(3)
-#define STV090x_OFFST_ERRORx_OPD_FIELD		7
-#define STV090x_WIDTH_ERRORx_OPD_FIELD		1
-#define STV090x_OFFST_ERRORx_CONFIG_FIELD	1
-#define STV090x_WIDTH_ERRORx_CONFIG_FIELD	6
-#define STV090x_OFFST_ERRORx_XOR_FIELD		0
-#define STV090x_WIDTH_ERRORx_XOR_FIELD		1
-
-#define STV090x_DPNxCFG(__x)			(0xf15c + (__x - 1) * 0x5)
-#define STV090x_DPN1CFG				STV090x_DPNxCFG(1)
-#define STV090x_DPN2CFG				STV090x_DPNxCFG(2)
-#define STV090x_DPN3CFG				STV090x_DPNxCFG(3)
-#define STV090x_OFFST_DPNx_OPD_FIELD		7
-#define STV090x_WIDTH_DPNx_OPD_FIELD		1
-#define STV090x_OFFST_DPNx_CONFIG_FIELD		1
-#define STV090x_WIDTH_DPNx_CONFIG_FIELD		6
-#define STV090x_OFFST_DPNx_XOR_FIELD		0
-#define STV090x_WIDTH_DPNx_XOR_FIELD		1
-
-#define STV090x_STROUTxCFG(__x)			(0xf15d + (__x - 1) * 0x5)
-#define STV090x_STROUT1CFG			STV090x_STROUTxCFG(1)
-#define STV090x_STROUT2CFG			STV090x_STROUTxCFG(2)
-#define STV090x_STROUT3CFG			STV090x_STROUTxCFG(3)
-#define STV090x_OFFST_STROUTx_OPD_FIELD		7
-#define STV090x_WIDTH_STROUTx_OPD_FIELD		1
-#define STV090x_OFFST_STROUTx_CONFIG_FIELD	1
-#define STV090x_WIDTH_STROUTx_CONFIG_FIELD	6
-#define STV090x_OFFST_STROUTx_XOR_FIELD		0
-#define STV090x_WIDTH_STROUTx_XOR_FIELD		1
-
-#define STV090x_CLKOUTxCFG(__x)			(0xf15e + (__x - 1) * 0x5)
-#define STV090x_CLKOUT1CFG			STV090x_CLKOUTxCFG(1)
-#define STV090x_CLKOUT2CFG			STV090x_CLKOUTxCFG(2)
-#define STV090x_CLKOUT3CFG			STV090x_CLKOUTxCFG(3)
-#define STV090x_OFFST_CLKOUTx_OPD_FIELD		7
-#define STV090x_WIDTH_CLKOUTx_OPD_FIELD		1
-#define STV090x_OFFST_CLKOUTx_CONFIG_FIELD	1
-#define STV090x_WIDTH_CLKOUTx_CONFIG_FIELD	6
-#define STV090x_OFFST_CLKOUTx_XOR_FIELD		0
-#define STV090x_WIDTH_CLKOUTx_XOR_FIELD		1
-
-#define STV090x_DATAxCFG(__x)			(0xf15f + (__x - 71) * 0x5)
-#define STV090x_DATA71CFG			STV090x_DATAxCFG(71)
-#define STV090x_DATA72CFG			STV090x_DATAxCFG(72)
-#define STV090x_DATA73CFG			STV090x_DATAxCFG(73)
-#define STV090x_OFFST_DATAx_OPD_FIELD		7
-#define STV090x_WIDTH_DATAx_OPD_FIELD		1
-#define STV090x_OFFST_DATAx_CONFIG_FIELD	1
-#define STV090x_WIDTH_DATAx_CONFIG_FIELD	6
-#define STV090x_OFFST_DATAx_XOR_FIELD		0
-#define STV090x_WIDTH_DATAx_XOR_FIELD		1
-
-#define STV090x_NCOARSE				0xf1b3
-#define STV090x_OFFST_M_DIV_FIELD		0
-#define STV090x_WIDTH_M_DIV_FIELD		8
-
-#define STV090x_SYNTCTRL			0xf1b6
-#define STV090x_OFFST_STANDBY_FIELD		7
-#define STV090x_WIDTH_STANDBY_FIELD		1
-#define STV090x_OFFST_BYPASSPLLCORE_FIELD	6
-#define STV090x_WIDTH_BYPASSPLLCORE_FIELD	1
-#define STV090x_OFFST_SELX1RATIO_FIELD		5
-#define STV090x_WIDTH_SELX1RATIO_FIELD		1
-#define STV090x_OFFST_STOP_PLL_FIELD		3
-#define STV090x_WIDTH_STOP_PLL_FIELD		1
-#define STV090x_OFFST_BYPASSPLLFSK_FIELD	2
-#define STV090x_WIDTH_BYPASSPLLFSK_FIELD	1
-#define STV090x_OFFST_SELOSCI_FIELD		1
-#define STV090x_WIDTH_SELOSCI_FIELD		1
-#define STV090x_OFFST_BYPASSPLLADC_FIELD	0
-#define STV090x_WIDTH_BYPASSPLLADC_FIELD	1
-
-#define STV090x_FILTCTRL			0xf1b7
-#define STV090x_OFFST_INV_CLK135_FIELD		7
-#define STV090x_WIDTH_INV_CLK135_FIELD		1
-#define STV090x_OFFST_SEL_FSKCKDIV_FIELD	2
-#define STV090x_WIDTH_SEL_FSKCKDIV_FIELD	1
-#define STV090x_OFFST_INV_CLKFSK_FIELD		1
-#define STV090x_WIDTH_INV_CLKFSK_FIELD		1
-#define STV090x_OFFST_BYPASS_APPLI_FIELD	0
-#define STV090x_WIDTH_BYPASS_APPLI_FIELD	1
-
-#define STV090x_PLLSTAT				0xf1b8
-#define STV090x_OFFST_PLLLOCK_FIELD		0
-#define STV090x_WIDTH_PLLLOCK_FIELD		1
-
-#define STV090x_STOPCLK1			0xf1c2
-#define STV090x_OFFST_STOP_CLKPKDT2_FIELD	6
-#define STV090x_WIDTH_STOP_CLKPKDT2_FIELD	1
-#define STV090x_OFFST_STOP_CLKPKDT1_FIELD	5
-#define STV090x_WIDTH_STOP_CLKPKDT1_FIELD	1
-#define STV090x_OFFST_STOP_CLKFEC_FIELD		4
-#define STV090x_WIDTH_STOP_CLKFEC_FIELD		1
-#define STV090x_OFFST_STOP_CLKADCI2_FIELD	3
-#define STV090x_WIDTH_STOP_CLKADCI2_FIELD	1
-#define STV090x_OFFST_INV_CLKADCI2_FIELD	2
-#define STV090x_WIDTH_INV_CLKADCI2_FIELD	1
-#define STV090x_OFFST_STOP_CLKADCI1_FIELD	1
-#define STV090x_WIDTH_STOP_CLKADCI1_FIELD	1
-#define STV090x_OFFST_INV_CLKADCI1_FIELD	0
-#define STV090x_WIDTH_INV_CLKADCI1_FIELD	1
-
-#define STV090x_STOPCLK2			0xf1c3
-#define STV090x_OFFST_STOP_CLKSAMP2_FIELD	4
-#define STV090x_WIDTH_STOP_CLKSAMP2_FIELD	1
-#define STV090x_OFFST_STOP_CLKSAMP1_FIELD	3
-#define STV090x_WIDTH_STOP_CLKSAMP1_FIELD	1
-#define STV090x_OFFST_STOP_CLKVIT2_FIELD	2
-#define STV090x_WIDTH_STOP_CLKVIT2_FIELD	1
-#define STV090x_OFFST_STOP_CLKVIT1_FIELD	1
-#define STV090x_WIDTH_STOP_CLKVIT1_FIELD	1
-#define STV090x_OFFST_STOP_CLKTS_FIELD		0
-#define STV090x_WIDTH_STOP_CLKTS_FIELD		1
-
-#define STV090x_TSTTNR0				0xf1df
-#define STV090x_OFFST_SEL_FSK_FIELD		7
-#define STV090x_WIDTH_SEL_FSK_FIELD		1
-#define STV090x_OFFST_FSK_PON_FIELD		2
-#define STV090x_WIDTH_FSK_PON_FIELD		1
-
-#define STV090x_TSTTNR1				0xf1e0
-#define STV090x_OFFST_ADC1_PON_FIELD		1
-#define STV090x_WIDTH_ADC1_PON_FIELD		1
-#define STV090x_OFFST_ADC1_INMODE_FIELD		0
-#define STV090x_WIDTH_ADC1_INMODE_FIELD		1
-
-#define STV090x_TSTTNR2				0xf1e1
-#define STV090x_OFFST_DISEQC1_PON_FIELD		5
-#define STV090x_WIDTH_DISEQC1_PON_FIELD		1
-
-#define STV090x_TSTTNR3				0xf1e2
-#define STV090x_OFFST_ADC2_PON_FIELD		1
-#define STV090x_WIDTH_ADC2_PON_FIELD		1
-#define STV090x_OFFST_ADC2_INMODE_FIELD		0
-#define STV090x_WIDTH_ADC2_INMODE_FIELD		1
-
-#define STV090x_TSTTNR4				0xf1e3
-#define STV090x_OFFST_DISEQC2_PON_FIELD		5
-#define STV090x_WIDTH_DISEQC2_PON_FIELD		1
-
-#define STV090x_FSKTFC2				0xf170
-#define STV090x_OFFST_FSKT_KMOD_FIELD		2
-#define STV090x_WIDTH_FSKT_KMOD_FIELD		6
-#define STV090x_OFFST_FSKT_CAR_FIELD		0
-#define STV090x_WIDTH_FSKT_CAR_FIELD		2
-
-#define STV090x_FSKTFC1				0xf171
-#define STV090x_OFFST_FSKTC1_CAR_FIELD		0
-#define STV090x_WIDTH_FSKTC1_CAR_FIELD		8
-
-#define STV090x_FSKTFC0				0xf172
-#define STV090x_OFFST_FSKTC0_CAR_FIELD		0
-#define STV090x_WIDTH_FSKTC0_CAR_FIELD		8
-
-#define STV090x_FSKTDELTAF1			0xf173
-#define STV090x_OFFST_FSKTF1_DELTAF_FIELD	0
-#define STV090x_WIDTH_FSKTF1_DELTAF_FIELD	4
-
-#define STV090x_FSKTDELTAF0			0xf174
-#define STV090x_OFFST_FSKTF0_DELTAF_FIELD	0
-#define STV090x_WIDTH_FSKTF0_DELTAF_FIELD	8
-
-#define STV090x_FSKTCTRL			0xf175
-#define STV090x_OFFST_FSKT_EN_SGN_FIELD		6
-#define STV090x_WIDTH_FSKT_EN_SGN_FIELD		1
-#define STV090x_OFFST_FSKT_MOD_SGN_FIELD	5
-#define STV090x_WIDTH_FSKT_MOD_SGN_FIELD	1
-#define STV090x_OFFST_FSKT_MOD_EN_FIELD		2
-#define STV090x_WIDTH_FSKT_MOD_EN_FIELD		3
-#define STV090x_OFFST_FSKT_DACMODE_FIELD	0
-#define STV090x_WIDTH_FSKT_DACMODE_FIELD	2
-
-#define STV090x_FSKRFC2				0xf176
-#define STV090x_OFFST_FSKRC2_DETSGN_FIELD	6
-#define STV090x_WIDTH_FSKRC2_DETSGN_FIELD	1
-#define STV090x_OFFST_FSKRC2_OUTSGN_FIELD	5
-#define STV090x_WIDTH_FSKRC2_OUTSGN_FIELD	1
-#define STV090x_OFFST_FSKRC2_KAGC_FIELD		2
-#define STV090x_WIDTH_FSKRC2_KAGC_FIELD		3
-#define STV090x_OFFST_FSKRC2_CAR_FIELD		0
-#define STV090x_WIDTH_FSKRC2_CAR_FIELD		2
-
-#define STV090x_FSKRFC1				0xf177
-#define STV090x_OFFST_FSKRC1_CAR_FIELD		0
-#define STV090x_WIDTH_FSKRC1_CAR_FIELD		8
-
-#define STV090x_FSKRFC0				0xf178
-#define STV090x_OFFST_FSKRC0_CAR_FIELD		0
-#define STV090x_WIDTH_FSKRC0_CAR_FIELD		8
-
-#define STV090x_FSKRK1				0xf179
-#define STV090x_OFFST_FSKR_K1_EXP_FIELD		5
-#define STV090x_WIDTH_FSKR_K1_EXP_FIELD		3
-#define STV090x_OFFST_FSKR_K1_MANT_FIELD	0
-#define STV090x_WIDTH_FSKR_K1_MANT_FIELD	5
-
-#define STV090x_FSKRK2				0xf17a
-#define STV090x_OFFST_FSKR_K2_EXP_FIELD		5
-#define STV090x_WIDTH_FSKR_K2_EXP_FIELD		3
-#define STV090x_OFFST_FSKR_K2_MANT_FIELD	0
-#define STV090x_WIDTH_FSKR_K2_MANT_FIELD	5
-
-#define STV090x_FSKRAGCR			0xf17b
-#define STV090x_OFFST_FSKR_OUTCTL_FIELD		6
-#define STV090x_WIDTH_FSKR_OUTCTL_FIELD		2
-#define STV090x_OFFST_FSKR_AGC_REF_FIELD	0
-#define STV090x_WIDTH_FSKR_AGC_REF_FIELD	6
-
-#define STV090x_FSKRAGC				0xf17c
-#define STV090x_OFFST_FSKR_AGC_ACCU_FIELD	0
-#define STV090x_WIDTH_FSKR_AGC_ACCU_FIELD	8
-
-#define STV090x_FSKRALPHA			0xf17d
-#define STV090x_OFFST_FSKR_ALPHA_EXP_FIELD	2
-#define STV090x_WIDTH_FSKR_ALPHA_EXP_FIELD	3
-#define STV090x_OFFST_FSKR_ALPHA_M_FIELD	0
-#define STV090x_WIDTH_FSKR_ALPHA_M_FIELD	2
-
-#define STV090x_FSKRPLTH1			0xf17e
-#define STV090x_OFFST_FSKR_BETA_FIELD		4
-#define STV090x_WIDTH_FSKR_BETA_FIELD		4
-#define STV090x_OFFST_FSKR_PLL_TRESH1_FIELD	0
-#define STV090x_WIDTH_FSKR_PLL_TRESH1_FIELD	4
-
-#define STV090x_FSKRPLTH0			0xf17f
-#define STV090x_OFFST_FSKR_PLL_TRESH0_FIELD	0
-#define STV090x_WIDTH_FSKR_PLL_TRESH0_FIELD	8
-
-#define STV090x_FSKRDF1				0xf180
-#define STV090x_OFFST_FSKR_DELTAF1_FIELD	0
-#define STV090x_WIDTH_FSKR_DELTAF1_FIELD	5
-
-#define STV090x_FSKRDF0				0xf181
-#define STV090x_OFFST_FSKR_DELTAF0_FIELD	0
-#define STV090x_WIDTH_FSKR_DELTAF0_FIELD	8
-
-#define STV090x_FSKRSTEPP			0xf182
-#define STV090x_OFFST_FSKR_STEP_PLUS_FIELD	0
-#define STV090x_WIDTH_FSKR_STEP_PLUS_FIELD	8
-
-#define STV090x_FSKRSTEPM			0xf183
-#define STV090x_OFFST_FSKR_STEP_MINUS_FIELD	0
-#define STV090x_WIDTH_FSKR_STEP_MINUS_FIELD	8
-
-#define STV090x_FSKRDET1			0xf184
-#define STV090x_OFFST_FSKR_CARDET1_ACCU_FIELD	0
-#define STV090x_WIDTH_FSKR_CARDET1_ACCU_FIELD	4
-
-#define STV090x_FSKRDET0			0xf185
-#define STV090x_OFFST_FSKR_CARDET0_ACCU_FIELD	0
-#define STV090x_WIDTH_FSKR_CARDET0_ACCU_FIELD	8
-
-#define STV090x_FSKRDTH1				0xf186
-#define STV090x_OFFST_FSKR_CARLOSS_THRESH1_FIELD	4
-#define STV090x_WIDTH_FSKR_CARLOSS_THRESH1_FIELD	4
-#define STV090x_OFFST_FSKR_CARDET_THRESH1_FIELD		0
-#define STV090x_WIDTH_FSKR_CARDET_THRESH1_FIELD		4
-
-#define STV090x_FSKRDTH0			0xf187
-#define STV090x_OFFST_FSKR_CARDET_THRESH0_FIELD	0
-#define STV090x_WIDTH_FSKR_CARDET_THRESH0_FIELD	8
-
-#define STV090x_FSKRLOSS			0xf188
-#define STV090x_OFFST_FSKR_CARLOSS_THRESH_FIELD	0
-#define STV090x_WIDTH_FSKR_CARLOSS_THRESH_FIELD	8
-
-#define STV090x_Px_DISTXCTL(__x)		(0xF1A0 - (__x - 1) * 0x10)
-#define STV090x_P1_DISTXCTL			STV090x_Px_DISTXCTL(1)
-#define STV090x_P2_DISTXCTL			STV090x_Px_DISTXCTL(2)
-#define STV090x_OFFST_Px_TIM_OFF_FIELD		7
-#define STV090x_WIDTH_Px_TIM_OFF_FIELD		1
-#define STV090x_OFFST_Px_DISEQC_RESET_FIELD	6
-#define STV090x_WIDTH_Px_DISEQC_RESET_FIELD	1
-#define STV090x_OFFST_Px_TIM_CMD_FIELD		4
-#define STV090x_WIDTH_Px_TIM_CMD_FIELD		2
-#define STV090x_OFFST_Px_DIS_PRECHARGE_FIELD	3
-#define STV090x_WIDTH_Px_DIS_PRECHARGE_FIELD	1
-#define STV090x_OFFST_Px_DISTX_MODE_FIELD	0
-#define STV090x_WIDTH_Px_DISTX_MODE_FIELD	3
-
-#define STV090x_Px_DISRXCTL(__x)		(0xf1a1 - (__x - 1) * 0x10)
-#define STV090x_P1_DISRXCTL			STV090x_Px_DISRXCTL(1)
-#define STV090x_P2_DISRXCTL			STV090x_Px_DISRXCTL(2)
-#define STV090x_OFFST_Px_RECEIVER_ON_FIELD	7
-#define STV090x_WIDTH_Px_RECEIVER_ON_FIELD	1
-#define STV090x_OFFST_Px_IGNO_SHORT22K_FIELD	6
-#define STV090x_WIDTH_Px_IGNO_SHORT22K_FIELD	1
-#define STV090x_OFFST_Px_ONECHIP_TRX_FIELD	5
-#define STV090x_WIDTH_Px_ONECHIP_TRX_FIELD	1
-#define STV090x_OFFST_Px_EXT_ENVELOP_FIELD	4
-#define STV090x_WIDTH_Px_EXT_ENVELOP_FIELD	1
-#define STV090x_OFFST_Px_PIN_SELECT_FIELD	2
-#define STV090x_WIDTH_Px_PIN_SELECT_FIELD	2
-#define STV090x_OFFST_Px_IRQ_RXEND_FIELD	1
-#define STV090x_WIDTH_Px_IRQ_RXEND_FIELD	1
-#define STV090x_OFFST_Px_IRQ_4NBYTES_FIELD	0
-#define STV090x_WIDTH_Px_IRQ_4NBYTES_FIELD	1
-
-#define STV090x_Px_DISRX_ST0(__x)		(0xf1a4 - (__x - 1) * 0x10)
-#define STV090x_P1_DISRX_ST0			STV090x_Px_DISRX_ST0(1)
-#define STV090x_P2_DISRX_ST0			STV090x_Px_DISRX_ST0(2)
-#define STV090x_OFFST_Px_RX_END_FIELD		7
-#define STV090x_WIDTH_Px_RX_END_FIELD		1
-#define STV090x_OFFST_Px_RX_ACTIVE_FIELD	6
-#define STV090x_WIDTH_Px_RX_ACTIVE_FIELD	1
-#define STV090x_OFFST_Px_SHORT_22KHZ_FIELD	5
-#define STV090x_WIDTH_Px_SHORT_22KHZ_FIELD	1
-#define STV090x_OFFST_Px_CONT_TONE_FIELD	4
-#define STV090x_WIDTH_Px_CONT_TONE_FIELD	1
-#define STV090x_OFFST_Px_FIFO_4BREADY_FIELD	3
-#define STV090x_WIDTH_Px_FIFO_4BREADY_FIELD	1
-#define STV090x_OFFST_Px_FIFO_EMPTY_FIELD	2
-#define STV090x_WIDTH_Px_FIFO_EMPTY_FIELD	1
-#define STV090x_OFFST_Px_ABORT_DISRX_FIELD	0
-#define STV090x_WIDTH_Px_ABORT_DISRX_FIELD	1
-
-#define STV090x_Px_DISRX_ST1(__x)		(0xf1a5 - (__x - 1) * 0x10)
-#define STV090x_P1_DISRX_ST1			STV090x_Px_DISRX_ST1(1)
-#define STV090x_P2_DISRX_ST1			STV090x_Px_DISRX_ST1(2)
-#define STV090x_OFFST_Px_RX_FAIL_FIELD		7
-#define STV090x_WIDTH_Px_RX_FAIL_FIELD		1
-#define STV090x_OFFST_Px_FIFO_PARITYFAIL_FIELD	6
-#define STV090x_WIDTH_Px_FIFO_PARITYFAIL_FIELD	1
-#define STV090x_OFFST_Px_RX_NONBYTE_FIELD	5
-#define STV090x_WIDTH_Px_RX_NONBYTE_FIELD	1
-#define STV090x_OFFST_Px_FIFO_OVERFLOW_FIELD	4
-#define STV090x_WIDTH_Px_FIFO_OVERFLOW_FIELD	1
-#define STV090x_OFFST_Px_FIFO_BYTENBR_FIELD	0
-#define STV090x_WIDTH_Px_FIFO_BYTENBR_FIELD	4
-
-#define STV090x_Px_DISRXDATA(__x)		(0xf1a6 - (__x - 1) * 0x10)
-#define STV090x_P1_DISRXDATA			STV090x_Px_DISRXDATA(1)
-#define STV090x_P2_DISRXDATA			STV090x_Px_DISRXDATA(2)
-#define STV090x_OFFST_Px_DISRX_DATA_FIELD	0
-#define STV090x_WIDTH_Px_DISRX_DATA_FIELD	8
-
-#define STV090x_Px_DISTXDATA(__x)		(0xf1a7 - (__x - 1) * 0x10)
-#define STV090x_P1_DISTXDATA			STV090x_Px_DISTXDATA(1)
-#define STV090x_P2_DISTXDATA			STV090x_Px_DISTXDATA(2)
-#define STV090x_OFFST_Px_DISEQC_FIFO_FIELD	0
-#define STV090x_WIDTH_Px_DISEQC_FIFO_FIELD	8
-
-#define STV090x_Px_DISTXSTATUS(__x)		(0xf1a8 - (__x - 1) * 0x10)
-#define STV090x_P1_DISTXSTATUS			STV090x_Px_DISTXSTATUS(1)
-#define STV090x_P2_DISTXSTATUS			STV090x_Px_DISTXSTATUS(2)
-#define STV090x_OFFST_Px_TX_FAIL_FIELD		7
-#define STV090x_WIDTH_Px_TX_FAIL_FIELD		1
-#define STV090x_OFFST_Px_FIFO_FULL_FIELD	6
-#define STV090x_WIDTH_Px_FIFO_FULL_FIELD	1
-#define STV090x_OFFST_Px_TX_IDLE_FIELD		5
-#define STV090x_WIDTH_Px_TX_IDLE_FIELD		1
-#define STV090x_OFFST_Px_GAP_BURST_FIELD	4
-#define STV090x_WIDTH_Px_GAP_BURST_FIELD	1
-#define STV090x_OFFST_Px_TXFIFO_BYTES_FIELD	0
-#define STV090x_WIDTH_Px_TXFIFO_BYTES_FIELD	4
-
-#define STV090x_Px_F22TX(__x)			(0xf1a9 - (__x - 1) * 0x10)
-#define STV090x_P1_F22TX			STV090x_Px_F22TX(1)
-#define STV090x_P2_F22TX			STV090x_Px_F22TX(2)
-#define STV090x_OFFST_Px_F22_REG_FIELD		0
-#define STV090x_WIDTH_Px_F22_REG_FIELD		8
-
-#define STV090x_Px_F22RX(__x)			(0xf1aa - (__x - 1) * 0x10)
-#define STV090x_P1_F22RX			STV090x_Px_F22RX(1)
-#define STV090x_P2_F22RX			STV090x_Px_F22RX(2)
-#define STV090x_OFFST_Px_F22RX_REG_FIELD	0
-#define STV090x_WIDTH_Px_F22RX_REG_FIELD	8
-
-#define STV090x_Px_ACRPRESC(__x)		(0xf1ac - (__x - 1) * 0x10)
-#define STV090x_P1_ACRPRESC			STV090x_Px_ACRPRESC(1)
-#define STV090x_P2_ACRPRESC			STV090x_Px_ACRPRESC(2)
-#define STV090x_OFFST_Px_ACR_PRESC_FIELD	0
-#define STV090x_WIDTH_Px_ACR_PRESC_FIELD	3
-
-#define STV090x_Px_ACRDIV(__x)			(0xf1ad - (__x - 1) * 0x10)
-#define STV090x_P1_ACRDIV			STV090x_Px_ACRDIV(1)
-#define STV090x_P2_ACRDIV			STV090x_Px_ACRDIV(2)
-#define STV090x_OFFST_Px_ACR_DIV_FIELD		0
-#define STV090x_WIDTH_Px_ACR_DIV_FIELD		8
-
-#define STV090x_Px_IQCONST(__x)			(0xF400 - (__x - 1) * 0x200)
-#define STV090x_P1_IQCONST			STV090x_Px_IQCONST(1)
-#define STV090x_P2_IQCONST			STV090x_Px_IQCONST(2)
-#define STV090x_OFFST_Px_CONSTEL_SELECT_FIELD	5
-#define STV090x_WIDTH_Px_CONSTEL_SELECT_FIELD	2
-
-#define STV090x_Px_NOSCFG(__x)			(0xF401 - (__x - 1) * 0x200)
-#define STV090x_P1_NOSCFG			STV090x_Px_NOSCFG(1)
-#define STV090x_P2_NOSCFG			STV090x_Px_NOSCFG(2)
-#define STV090x_OFFST_Px_NOSPLH_BETA_FIELD	3
-#define STV090x_WIDTH_Px_NOSPLH_BETA_FIELD	2
-#define STV090x_OFFST_Px_NOSDATA_BETA_FIELD	0
-#define STV090x_WIDTH_Px_NOSDATA_BETA_FIELD	3
-
-#define STV090x_Px_ISYMB(__x)			(0xF402 - (__x - 1) * 0x200)
-#define STV090x_P1_ISYMB			STV090x_Px_ISYMB(1)
-#define STV090x_P2_ISYMB			STV090x_Px_ISYMB(2)
-#define STV090x_OFFST_Px_I_SYMBOL_FIELD		0
-#define STV090x_WIDTH_Px_I_SYMBOL_FIELD		8
-
-#define STV090x_Px_QSYMB(__x)			(0xF403 - (__x - 1) * 0x200)
-#define STV090x_P1_QSYMB			STV090x_Px_QSYMB(1)
-#define STV090x_P2_QSYMB			STV090x_Px_QSYMB(2)
-#define STV090x_OFFST_Px_Q_SYMBOL_FIELD		0
-#define STV090x_WIDTH_Px_Q_SYMBOL_FIELD		8
-
-#define STV090x_Px_AGC1CFG(__x)			(0xF404 - (__x - 1) * 0x200)
-#define STV090x_P1_AGC1CFG			STV090x_Px_AGC1CFG(1)
-#define STV090x_P2_AGC1CFG			STV090x_Px_AGC1CFG(2)
-#define STV090x_OFFST_Px_DC_FROZEN_FIELD	7
-#define STV090x_WIDTH_Px_DC_FROZEN_FIELD	1
-#define STV090x_OFFST_Px_DC_CORRECT_FIELD	6
-#define STV090x_WIDTH_Px_DC_CORRECT_FIELD	1
-#define STV090x_OFFST_Px_AMM_FROZEN_FIELD	5
-#define STV090x_WIDTH_Px_AMM_FROZEN_FIELD	1
-#define STV090x_OFFST_Px_AMM_CORRECT_FIELD	4
-#define STV090x_WIDTH_Px_AMM_CORRECT_FIELD	1
-#define STV090x_OFFST_Px_QUAD_FROZEN_FIELD	3
-#define STV090x_WIDTH_Px_QUAD_FROZEN_FIELD	1
-#define STV090x_OFFST_Px_QUAD_CORRECT_FIELD	2
-#define STV090x_WIDTH_Px_QUAD_CORRECT_FIELD	1
-
-#define STV090x_Px_AGC1CN(__x)			(0xF406 - (__x - 1) * 0x200)
-#define STV090x_P1_AGC1CN			STV090x_Px_AGC1CN(1)
-#define STV090x_P2_AGC1CN			STV090x_Px_AGC1CN(2)
-#define STV090x_WIDTH_Px_AGC1_LOCKED_FIELD	7
-#define STV090x_OFFST_Px_AGC1_LOCKED_FIELD	1
-#define STV090x_OFFST_Px_AGC1_MINPOWER_FIELD	4
-#define STV090x_WIDTH_Px_AGC1_MINPOWER_FIELD	1
-#define STV090x_OFFST_Px_AGCOUT_FAST_FIELD	3
-#define STV090x_WIDTH_Px_AGCOUT_FAST_FIELD	1
-#define STV090x_OFFST_Px_AGCIQ_BETA_FIELD	0
-#define STV090x_WIDTH_Px_AGCIQ_BETA_FIELD	3
-
-#define STV090x_Px_AGC1REF(__x)			(0xF407 - (__x - 1) * 0x200)
-#define STV090x_P1_AGC1REF			STV090x_Px_AGC1REF(1)
-#define STV090x_P2_AGC1REF			STV090x_Px_AGC1REF(2)
-#define STV090x_OFFST_Px_AGCIQ_REF_FIELD	0
-#define STV090x_WIDTH_Px_AGCIQ_REF_FIELD	8
-
-#define STV090x_Px_IDCCOMP(__x)			(0xF408 - (__x - 1) * 0x200)
-#define STV090x_P1_IDCCOMP			STV090x_Px_IDCCOMP(1)
-#define STV090x_P2_IDCCOMP			STV090x_Px_IDCCOMP(2)
-#define STV090x_OFFST_Px_IAVERAGE_ADJ_FIELD	0
-#define STV090x_WIDTH_Px_IAVERAGE_ADJ_FIELD	8
-
-#define STV090x_Px_QDCCOMP(__x)			(0xF409 - (__x - 1) * 0x200)
-#define STV090x_P1_QDCCOMP			STV090x_Px_QDCCOMP(1)
-#define STV090x_P2_QDCCOMP			STV090x_Px_QDCCOMP(2)
-#define STV090x_OFFST_Px_QAVERAGE_ADJ_FIELD	0
-#define STV090x_WIDTH_Px_QAVERAGE_ADJ_FIELD	8
-
-#define STV090x_Px_POWERI(__x)			(0xF40A - (__x - 1) * 0x200)
-#define STV090x_P1_POWERI			STV090x_Px_POWERI(1)
-#define STV090x_P2_POWERI			STV090x_Px_POWERI(2)
-#define STV090x_OFFST_Px_POWER_I_FIELD		0
-#define STV090x_WIDTH_Px_POWER_I_FIELD		8
-
-#define STV090x_Px_POWERQ(__x)			(0xF40B - (__x - 1) * 0x200)
-#define STV090x_P1_POWERQ			STV090x_Px_POWERQ(1)
-#define STV090x_P2_POWERQ			STV090x_Px_POWERQ(2)
-#define STV090x_OFFST_Px_POWER_Q_FIELD		0
-#define STV090x_WIDTH_Px_POWER_Q_FIELD		8
-
-#define STV090x_Px_AGC1AMM(__x)			(0xF40C - (__x - 1) * 0x200)
-#define STV090x_P1_AGC1AMM			STV090x_Px_AGC1AMM(1)
-#define STV090x_P2_AGC1AMM			STV090x_Px_AGC1AMM(2)
-#define STV090x_OFFST_Px_AMM_VALUE_FIELD	0
-#define STV090x_WIDTH_Px_AMM_VALUE_FIELD	8
-
-#define STV090x_Px_AGC1QUAD(__x)		(0xF40D - (__x - 1) * 0x200)
-#define STV090x_P1_AGC1QUAD			STV090x_Px_AGC1QUAD(1)
-#define STV090x_P2_AGC1QUAD			STV090x_Px_AGC1QUAD(2)
-#define STV090x_OFFST_Px_QUAD_VALUE_FIELD	0
-#define STV090x_WIDTH_Px_QUAD_VALUE_FIELD	8
-
-#define STV090x_Px_AGCIQINy(__x, __y)		(0xF40F - (__x-1) * 0x200 - __y * 0x1)
-#define STV090x_P1_AGCIQIN0			STV090x_Px_AGCIQINy(1, 0)
-#define STV090x_P1_AGCIQIN1			STV090x_Px_AGCIQINy(1, 1)
-#define STV090x_P2_AGCIQIN0			STV090x_Px_AGCIQINy(2, 0)
-#define STV090x_P2_AGCIQIN1			STV090x_Px_AGCIQINy(2, 1)
-#define STV090x_OFFST_Px_AGCIQ_VALUE_FIELD	0
-#define STV090x_WIDTH_Px_AGCIQ_VALUE_FIELD	8
-
-#define STV090x_Px_DEMOD(__x)			(0xF410 - (__x - 1) * 0x200)
-#define STV090x_P1_DEMOD			STV090x_Px_DEMOD(1)
-#define STV090x_P2_DEMOD			STV090x_Px_DEMOD(2)
-#define STV090x_OFFST_Px_MANUAL_S2ROLLOFF_FIELD	7
-#define STV090x_WIDTH_Px_MANUAL_S2ROLLOFF_FIELD	1
-#define STV090x_OFFST_Px_DEMOD_STOP_FIELD	6
-#define STV090x_WIDTH_Px_DEMOD_STOP_FIELD	1
-#define STV090x_OFFST_Px_SPECINV_CONTROL_FIELD	4
-#define STV090x_WIDTH_Px_SPECINV_CONTROL_FIELD	2
-#define STV090x_OFFST_Px_FORCE_ENASAMP_FIELD	3
-#define STV090x_WIDTH_Px_FORCE_ENASAMP_FIELD	1
-#define STV090x_OFFST_Px_MANUAL_SXROLLOFF_FIELD	2
-#define STV090x_WIDTH_Px_MANUAL_SXROLLOFF_FIELD	1
-#define STV090x_OFFST_Px_ROLLOFF_CONTROL_FIELD	0
-#define STV090x_WIDTH_Px_ROLLOFF_CONTROL_FIELD	2
-
-#define STV090x_Px_DMDMODCOD(__x)		(0xF411 - (__x - 1) * 0x200)
-#define STV090x_P1_DMDMODCOD			STV090x_Px_DMDMODCOD(1)
-#define STV090x_P2_DMDMODCOD			STV090x_Px_DMDMODCOD(2)
-#define STV090x_OFFST_Px_MANUAL_MODCOD_FIELD	7
-#define STV090x_WIDTH_Px_MANUAL_MODCOD_FIELD	1
-#define STV090x_OFFST_Px_DEMOD_MODCOD_FIELD	2
-#define STV090x_WIDTH_Px_DEMOD_MODCOD_FIELD	5
-#define STV090x_OFFST_Px_DEMOD_TYPE_FIELD	0
-#define STV090x_WIDTH_Px_DEMOD_TYPE_FIELD	2
-
-#define STV090x_Px_DSTATUS(__x)			(0xF412 - (__x - 1) * 0x200)
-#define STV090x_P1_DSTATUS			STV090x_Px_DSTATUS(1)
-#define STV090x_P2_DSTATUS			STV090x_Px_DSTATUS(2)
-#define STV090x_OFFST_Px_CAR_LOCK_FIELD		7
-#define STV090x_WIDTH_Px_CAR_LOCK_FIELD		1
-#define STV090x_OFFST_Px_TMGLOCK_QUALITY_FIELD	5
-#define STV090x_WIDTH_Px_TMGLOCK_QUALITY_FIELD	2
-#define STV090x_OFFST_Px_LOCK_DEFINITIF_FIELD	3
-#define STV090x_WIDTH_Px_LOCK_DEFINITIF_FIELD	1
-
-#define STV090x_Px_DSTATUS2(__x)		(0xF413 - (__x - 1) * 0x200)
-#define STV090x_P1_DSTATUS2			STV090x_Px_DSTATUS2(1)
-#define STV090x_P2_DSTATUS2			STV090x_Px_DSTATUS2(2)
-#define STV090x_OFFST_Px_DEMOD_DELOCK_FIELD	7
-#define STV090x_WIDTH_Px_DEMOD_DELOCK_FIELD	1
-#define STV090x_OFFST_Px_AGC1_NOSIGNALACK_FIELD	3
-#define STV090x_WIDTH_Px_AGC1_NOSIGNALACK_FIELD	1
-#define STV090x_OFFST_Px_AGC2_OVERFLOW_FIELD	2
-#define STV090x_WIDTH_Px_AGC2_OVERFLOW_FIELD	1
-#define STV090x_OFFST_Px_CFR_OVERFLOW_FIELD	1
-#define STV090x_WIDTH_Px_CFR_OVERFLOW_FIELD	1
-#define STV090x_OFFST_Px_GAMMA_OVERUNDER_FIELD	0
-#define STV090x_WIDTH_Px_GAMMA_OVERUNDER_FIELD	1
-
-#define STV090x_Px_DMDCFGMD(__x)		(0xF414 - (__x - 1) * 0x200)
-#define STV090x_P1_DMDCFGMD			STV090x_Px_DMDCFGMD(1)
-#define STV090x_P2_DMDCFGMD			STV090x_Px_DMDCFGMD(2)
-#define STV090x_OFFST_Px_DVBS2_ENABLE_FIELD	7
-#define STV090x_WIDTH_Px_DVBS2_ENABLE_FIELD	1
-#define STV090x_OFFST_Px_DVBS1_ENABLE_FIELD	6
-#define STV090x_WIDTH_Px_DVBS1_ENABLE_FIELD	1
-#define STV090x_OFFST_Px_SCAN_ENABLE_FIELD	4
-#define STV090x_WIDTH_Px_SCAN_ENABLE_FIELD	1
-#define STV090x_OFFST_Px_CFR_AUTOSCAN_FIELD	3
-#define STV090x_WIDTH_Px_CFR_AUTOSCAN_FIELD	1
-#define STV090x_OFFST_Px_NOFORCE_RELOCK_FIELD	2
-#define STV090x_WIDTH_Px_NOFORCE_RELOCK_FIELD	1
-#define STV090x_OFFST_Px_TUN_RNG_FIELD		0
-#define STV090x_WIDTH_Px_TUN_RNG_FIELD		2
-
-#define STV090x_Px_DMDCFG2(__x)			(0xF415 - (__x - 1) * 0x200)
-#define STV090x_P1_DMDCFG2			STV090x_Px_DMDCFG2(1)
-#define STV090x_P2_DMDCFG2			STV090x_Px_DMDCFG2(2)
-#define STV090x_OFFST_Px_S1S2_SEQUENTIAL_FIELD	6
-#define STV090x_WIDTH_Px_S1S2_SEQUENTIAL_FIELD	1
-
-#define STV090x_Px_DMDISTATE(__x)		(0xF416 - (__x - 1) * 0x200)
-#define STV090x_P1_DMDISTATE			STV090x_Px_DMDISTATE(1)
-#define STV090x_P2_DMDISTATE			STV090x_Px_DMDISTATE(2)
-#define STV090x_OFFST_Px_I2C_DEMOD_MODE_FIELD	0
-#define STV090x_WIDTH_Px_I2C_DEMOD_MODE_FIELD	5
-
-#define STV090x_Px_DMDTOM(__x)			(0xF417 - (__x - 1) * 0x200) /* check */
-#define STV090x_P1_DMDTOM			STV090x_Px_DMDTOM(1)
-#define STV090x_P2_DMDTOM			STV090x_Px_DMDTOM(2)
-
-#define STV090x_Px_DMDSTATE(__x)		(0xF41B - (__x - 1) * 0x200)
-#define STV090x_P1_DMDSTATE			STV090x_Px_DMDSTATE(1)
-#define STV090x_P2_DMDSTATE			STV090x_Px_DMDSTATE(2)
-#define STV090x_OFFST_Px_HEADER_MODE_FIELD	5
-#define STV090x_WIDTH_Px_HEADER_MODE_FIELD	2
-
-#define STV090x_Px_DMDFLYW(__x)			(0xF41C - (__x - 1) * 0x200)
-#define STV090x_P1_DMDFLYW			STV090x_Px_DMDFLYW(1)
-#define STV090x_P2_DMDFLYW			STV090x_Px_DMDFLYW(2)
-#define STV090x_OFFST_Px_I2C_IRQVAL_FIELD	4
-#define STV090x_WIDTH_Px_I2C_IRQVAL_FIELD	4
-#define STV090x_OFFST_Px_FLYWHEEL_CPT_FIELD	0
-#define STV090x_WIDTH_Px_FLYWHEEL_CPT_FIELD	4
-
-#define STV090x_Px_DSTATUS3(__x)		(0xF41D - (__x - 1) * 0x200)
-#define STV090x_P1_DSTATUS3			STV090x_Px_DSTATUS3(1)
-#define STV090x_P2_DSTATUS3			STV090x_Px_DSTATUS3(2)
-#define STV090x_OFFST_Px_DEMOD_CFGMODE_FIELD	5
-#define STV090x_WIDTH_Px_DEMOD_CFGMODE_FIELD	2
-
-#define STV090x_Px_DMDCFG3(__x)			(0xF41E - (__x - 1) * 0x200)
-#define STV090x_P1_DMDCFG3			STV090x_Px_DMDCFG3(1)
-#define STV090x_P2_DMDCFG3			STV090x_Px_DMDCFG3(2)
-#define STV090x_OFFST_Px_NOSTOP_FIFOFULL_FIELD	3
-#define STV090x_WIDTH_Px_NOSTOP_FIFOFULL_FIELD	1
-
-#define STV090x_Px_DMDCFG4(__x)			(0xf41f - (__x - 1) * 0x200)
-#define STV090x_P1_DMDCFG4			STV090x_Px_DMDCFG4(1)
-#define STV090x_P2_DMDCFG4			STV090x_Px_DMDCFG4(2)
-
-#define STV090x_Px_CORRELMANT(__x)		(0xF420 - (__x - 1) * 0x200)
-#define STV090x_P1_CORRELMANT			STV090x_Px_CORRELMANT(1)
-#define STV090x_P2_CORRELMANT			STV090x_Px_CORRELMANT(2)
-#define STV090x_OFFST_Px_CORREL_MANT_FIELD	0
-#define STV090x_WIDTH_Px_CORREL_MANT_FIELD	8
-
-#define STV090x_Px_CORRELABS(__x)		(0xF421 - (__x - 1) * 0x200)
-#define STV090x_P1_CORRELABS			STV090x_Px_CORRELABS(1)
-#define STV090x_P2_CORRELABS			STV090x_Px_CORRELABS(2)
-#define STV090x_OFFST_Px_CORREL_ABS_FIELD	0
-#define STV090x_WIDTH_Px_CORREL_ABS_FIELD	8
-
-#define STV090x_Px_CORRELEXP(__x)		(0xF422 - (__x - 1) * 0x200)
-#define STV090x_P1_CORRELEXP			STV090x_Px_CORRELEXP(1)
-#define STV090x_P2_CORRELEXP			STV090x_Px_CORRELEXP(2)
-#define STV090x_OFFST_Px_CORREL_ABSEXP_FIELD	4
-#define STV090x_WIDTH_Px_CORREL_ABSEXP_FIELD	4
-#define STV090x_OFFST_Px_CORREL_EXP_FIELD	0
-#define STV090x_WIDTH_Px_CORREL_EXP_FIELD	4
-
-#define STV090x_Px_PLHMODCOD(__x)		(0xF424 - (__x - 1) * 0x200)
-#define STV090x_P1_PLHMODCOD			STV090x_Px_PLHMODCOD(1)
-#define STV090x_P2_PLHMODCOD			STV090x_Px_PLHMODCOD(2)
-#define STV090x_OFFST_Px_SPECINV_DEMOD_FIELD	7
-#define STV090x_WIDTH_Px_SPECINV_DEMOD_FIELD	1
-#define STV090x_OFFST_Px_PLH_MODCOD_FIELD	2
-#define STV090x_WIDTH_Px_PLH_MODCOD_FIELD	5
-#define STV090x_OFFST_Px_PLH_TYPE_FIELD		0
-#define STV090x_WIDTH_Px_PLH_TYPE_FIELD		2
-
-#define STV090x_Px_AGCK32(__x)			(0xf42b - (__x - 1) * 0x200)
-#define STV090x_P1_AGCK32			STV090x_Px_AGCK32(1)
-#define STV090x_P2_AGCK32			STV090x_Px_AGCK32(2)
-
-#define STV090x_Px_AGC2O(__x)			(0xF42C - (__x - 1) * 0x200)
-#define STV090x_P1_AGC2O			STV090x_Px_AGC2O(1)
-#define STV090x_P2_AGC2O			STV090x_Px_AGC2O(2)
-
-#define STV090x_Px_AGC2REF(__x)			(0xF42D - (__x - 1) * 0x200)
-#define STV090x_P1_AGC2REF			STV090x_Px_AGC2REF(1)
-#define STV090x_P2_AGC2REF			STV090x_Px_AGC2REF(2)
-#define STV090x_OFFST_Px_AGC2_REF_FIELD		0
-#define STV090x_WIDTH_Px_AGC2_REF_FIELD		8
-
-#define STV090x_Px_AGC1ADJ(__x)			(0xF42E - (__x - 1) * 0x200)
-#define STV090x_P1_AGC1ADJ			STV090x_Px_AGC1ADJ(1)
-#define STV090x_P2_AGC1ADJ			STV090x_Px_AGC1ADJ(2)
-#define STV090x_OFFST_Px_AGC1_ADJUSTED_FIELD	0
-#define STV090x_WIDTH_Px_AGC1_ADJUSTED_FIELD	7
-
-#define STV090x_Px_AGC2Iy(__x, __y)		(0xF437 - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_AGC2I0			STV090x_Px_AGC2Iy(1, 0)
-#define STV090x_P1_AGC2I1			STV090x_Px_AGC2Iy(1, 1)
-#define STV090x_P2_AGC2I0			STV090x_Px_AGC2Iy(2, 0)
-#define STV090x_P2_AGC2I1			STV090x_Px_AGC2Iy(2, 1)
-#define STV090x_OFFST_Px_AGC2_INTEGRATOR_FIELD	0
-#define STV090x_WIDTH_Px_AGC2_INTEGRATOR_FIELD	8
-
-#define STV090x_Px_CARCFG(__x)			(0xF438 - (__x - 1) * 0x200)
-#define STV090x_P1_CARCFG			STV090x_Px_CARCFG(1)
-#define STV090x_P2_CARCFG			STV090x_Px_CARCFG(2)
-#define STV090x_OFFST_Px_EN_CAR2CENTER_FIELD	5
-#define STV090x_WIDTH_Px_EN_CAR2CENTER_FIELD	1
-#define STV090x_OFFST_Px_ROTATON_FIELD		2
-#define STV090x_WIDTH_Px_ROTATON_FIELD		1
-#define STV090x_OFFST_Px_PH_DET_ALGO_FIELD	0
-#define STV090x_WIDTH_Px_PH_DET_ALGO_FIELD	2
-
-#define STV090x_Px_ACLC(__x)			(0xF439 - (__x - 1) * 0x200)
-#define STV090x_P1_ACLC				STV090x_Px_ACLC(1)
-#define STV090x_P2_ACLC				STV090x_Px_ACLC(2)
-#define STV090x_OFFST_Px_CAR_ALPHA_MANT_FIELD	4
-#define STV090x_WIDTH_Px_CAR_ALPHA_MANT_FIELD	2
-#define STV090x_OFFST_Px_CAR_ALPHA_EXP_FIELD	0
-#define STV090x_WIDTH_Px_CAR_ALPHA_EXP_FIELD	4
-
-#define STV090x_Px_BCLC(__x)			(0xF43A - (__x - 1) * 0x200)
-#define STV090x_P1_BCLC				STV090x_Px_BCLC(1)
-#define STV090x_P2_BCLC				STV090x_Px_BCLC(2)
-#define STV090x_OFFST_Px_CAR_BETA_MANT_FIELD	4
-#define STV090x_WIDTH_Px_CAR_BETA_MANT_FIELD	2
-#define STV090x_OFFST_Px_CAR_BETA_EXP_FIELD	0
-#define STV090x_WIDTH_Px_CAR_BETA_EXP_FIELD	4
-
-#define STV090x_Px_CARFREQ(__x)			(0xF43D - (__x - 1) * 0x200)
-#define STV090x_P1_CARFREQ			STV090x_Px_CARFREQ(1)
-#define STV090x_P2_CARFREQ			STV090x_Px_CARFREQ(2)
-#define STV090x_OFFST_Px_KC_COARSE_EXP_FIELD	4
-#define STV090x_WIDTH_Px_KC_COARSE_EXP_FIELD	4
-#define STV090x_OFFST_Px_BETA_FREQ_FIELD	0
-#define STV090x_WIDTH_Px_BETA_FREQ_FIELD	4
-
-#define STV090x_Px_CARHDR(__x)			(0xF43E - (__x - 1) * 0x200)
-#define STV090x_P1_CARHDR			STV090x_Px_CARHDR(1)
-#define STV090x_P2_CARHDR			STV090x_Px_CARHDR(2)
-#define STV090x_OFFST_Px_FREQ_HDR_FIELD		0
-#define STV090x_WIDTH_Px_FREQ_HDR_FIELD		8
-
-#define STV090x_Px_LDT(__x)			(0xF43F - (__x - 1) * 0x200)
-#define STV090x_P1_LDT				STV090x_Px_LDT(1)
-#define STV090x_P2_LDT				STV090x_Px_LDT(2)
-#define STV090x_OFFST_Px_CARLOCK_THRES_FIELD	0
-#define STV090x_WIDTH_Px_CARLOCK_THRES_FIELD	8
-
-#define STV090x_Px_LDT2(__x)			(0xF440 - (__x - 1) * 0x200)
-#define STV090x_P1_LDT2				STV090x_Px_LDT2(1)
-#define STV090x_P2_LDT2				STV090x_Px_LDT2(2)
-#define STV090x_OFFST_Px_CARLOCK_THRES2_FIELD	0
-#define STV090x_WIDTH_Px_CARLOCK_THRES2_FIELD	8
-
-#define STV090x_Px_CFRICFG(__x)			(0xF441 - (__x - 1) * 0x200)
-#define STV090x_P1_CFRICFG			STV090x_Px_CFRICFG(1)
-#define STV090x_P2_CFRICFG			STV090x_Px_CFRICFG(2)
-#define STV090x_OFFST_Px_NEG_CFRSTEP_FIELD	0
-#define STV090x_WIDTH_Px_NEG_CFRSTEP_FIELD	1
-
-#define STV090x_Pn_CFRUPy(__x, __y)		(0xF443 - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_CFRUP0			STV090x_Pn_CFRUPy(1, 0)
-#define STV090x_P1_CFRUP1			STV090x_Pn_CFRUPy(1, 1)
-#define STV090x_P2_CFRUP0			STV090x_Pn_CFRUPy(2, 0)
-#define STV090x_P2_CFRUP1			STV090x_Pn_CFRUPy(2, 1)
-#define STV090x_OFFST_Px_CFR_UP_FIELD		0
-#define STV090x_WIDTH_Px_CFR_UP_FIELD		8
-
-#define STV090x_Pn_CFRLOWy(__x, __y)		(0xF447 - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_CFRLOW0			STV090x_Pn_CFRLOWy(1, 0)
-#define STV090x_P1_CFRLOW1			STV090x_Pn_CFRLOWy(1, 1)
-#define STV090x_P2_CFRLOW0			STV090x_Pn_CFRLOWy(2, 0)
-#define STV090x_P2_CFRLOW1			STV090x_Pn_CFRLOWy(2, 1)
-#define STV090x_OFFST_Px_CFR_LOW_FIELD		0
-#define STV090x_WIDTH_Px_CFR_LOW_FIELD		8
-
-#define STV090x_Pn_CFRINITy(__x, __y)		(0xF449 - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_CFRINIT0			STV090x_Pn_CFRINITy(1, 0)
-#define STV090x_P1_CFRINIT1			STV090x_Pn_CFRINITy(1, 1)
-#define STV090x_P2_CFRINIT0			STV090x_Pn_CFRINITy(2, 0)
-#define STV090x_P2_CFRINIT1			STV090x_Pn_CFRINITy(2, 1)
-#define STV090x_OFFST_Px_CFR_INIT_FIELD		0
-#define STV090x_WIDTH_Px_CFR_INIT_FIELD		8
-
-#define STV090x_Px_CFRINC1(__x)			(0xF44A - (__x - 1) * 0x200)
-#define STV090x_P1_CFRINC1			STV090x_Px_CFRINC1(1)
-#define STV090x_P2_CFRINC1			STV090x_Px_CFRINC1(2)
-#define STV090x_OFFST_Px_CFR_INC1_FIELD		0
-#define STV090x_WIDTH_Px_CFR_INC1_FIELD		7 /* check */
-
-#define STV090x_Px_CFRINC0(__x)			(0xF44B - (__x - 1) * 0x200)
-#define STV090x_P1_CFRINC0			STV090x_Px_CFRINC0(1)
-#define STV090x_P2_CFRINC0			STV090x_Px_CFRINC0(2)
-#define STV090x_OFFST_Px_CFR_INC0_FIELD		4 /* check */
-#define STV090x_WIDTH_Px_CFR_INC0_FIELD		4
-
-#define STV090x_Pn_CFRy(__x, __y)		(0xF44E - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_CFR0				STV090x_Pn_CFRy(1, 0)
-#define STV090x_P1_CFR1				STV090x_Pn_CFRy(1, 1)
-#define STV090x_P1_CFR2				STV090x_Pn_CFRy(1, 2)
-#define STV090x_P2_CFR0				STV090x_Pn_CFRy(2, 0)
-#define STV090x_P2_CFR1				STV090x_Pn_CFRy(2, 1)
-#define STV090x_P2_CFR2				STV090x_Pn_CFRy(2, 2)
-#define STV090x_OFFST_Px_CAR_FREQ_FIELD		0
-#define STV090x_WIDTH_Px_CAR_FREQ_FIELD		8
-
-#define STV090x_Px_LDI(__x)			(0xF44F - (__x - 1) * 0x200)
-#define STV090x_P1_LDI				STV090x_Px_LDI(1)
-#define STV090x_P2_LDI				STV090x_Px_LDI(2)
-#define STV090x_OFFST_Px_LOCK_DET_INTEGR_FIELD	0
-#define STV090x_WIDTH_Px_LOCK_DET_INTEGR_FIELD	8
-
-#define STV090x_Px_TMGCFG(__x)			(0xF450 - (__x - 1) * 0x200)
-#define STV090x_P1_TMGCFG			STV090x_Px_TMGCFG(1)
-#define STV090x_P2_TMGCFG			STV090x_Px_TMGCFG(2)
-#define STV090x_OFFST_Px_TMGLOCK_BETA_FIELD	6
-#define STV090x_WIDTH_Px_TMGLOCK_BETA_FIELD	2
-#define STV090x_OFFST_Px_DO_TIMING_FIELD	4
-#define STV090x_WIDTH_Px_DO_TIMING_FIELD	1
-#define STV090x_OFFST_Px_TMG_MINFREQ_FIELD	0
-#define STV090x_WIDTH_Px_TMG_MINFREQ_FIELD	2
-
-#define STV090x_Px_RTC(__x)			(0xF451 - (__x - 1) * 0x200)
-#define STV090x_P1_RTC				STV090x_Px_RTC(1)
-#define STV090x_P2_RTC				STV090x_Px_RTC(2)
-#define STV090x_OFFST_Px_TMGALPHA_EXP_FIELD	4
-#define STV090x_WIDTH_Px_TMGALPHA_EXP_FIELD	4
-#define STV090x_OFFST_Px_TMGBETA_EXP_FIELD	0
-#define STV090x_WIDTH_Px_TMGBETA_EXP_FIELD	4
-
-#define STV090x_Px_RTCS2(__x)			(0xF452 - (__x - 1) * 0x200)
-#define STV090x_P1_RTCS2			STV090x_Px_RTCS2(1)
-#define STV090x_P2_RTCS2			STV090x_Px_RTCS2(2)
-#define STV090x_OFFST_Px_TMGALPHAS2_EXP_FIELD	4
-#define STV090x_WIDTH_Px_TMGALPHAS2_EXP_FIELD	4
-#define STV090x_OFFST_Px_TMGBETAS2_EXP_FIELD	0
-#define STV090x_WIDTH_Px_TMGBETAS2_EXP_FIELD	4
-
-#define STV090x_Px_TMGTHRISE(__x)		(0xF453 - (__x - 1) * 0x200)
-#define STV090x_P1_TMGTHRISE			STV090x_Px_TMGTHRISE(1)
-#define STV090x_P2_TMGTHRISE			STV090x_Px_TMGTHRISE(2)
-#define STV090x_OFFST_Px_TMGLOCK_THRISE_FIELD	0
-#define STV090x_WIDTH_Px_TMGLOCK_THRISE_FIELD	8
-
-#define STV090x_Px_TMGTHFALL(__x)		(0xF454 - (__x - 1) * 0x200)
-#define STV090x_P1_TMGTHFALL			STV090x_Px_TMGTHFALL(1)
-#define STV090x_P2_TMGTHFALL			STV090x_Px_TMGTHFALL(2)
-#define STV090x_OFFST_Px_TMGLOCK_THFALL_FIELD	0
-#define STV090x_WIDTH_Px_TMGLOCK_THFALL_FIELD	8
-
-#define STV090x_Px_SFRUPRATIO(__x)		(0xF455 - (__x - 1) * 0x200)
-#define STV090x_P1_SFRUPRATIO			STV090x_Px_SFRUPRATIO(1)
-#define STV090x_P2_SFRUPRATIO			STV090x_Px_SFRUPRATIO(2)
-#define STV090x_OFFST_Px_SFR_UPRATIO_FIELD	0
-#define STV090x_WIDTH_Px_SFR_UPRATIO_FIELD	8
-
-#define STV090x_Px_SFRLOWRATIO(__x)		(0xF456 - (__x - 1) * 0x200)
-#define STV090x_P1_SFRLOWRATIO			STV090x_Px_SFRLOWRATIO(1)
-#define STV090x_P2_SFRLOWRATIO			STV090x_Px_SFRLOWRATIO(2)
-#define STV090x_OFFST_Px_SFR_LOWRATIO_FIELD	0
-#define STV090x_WIDTH_Px_SFR_LOWRATIO_FIELD	8
-
-#define STV090x_Px_KREFTMG(__x)			(0xF458 - (__x - 1) * 0x200)
-#define STV090x_P1_KREFTMG			STV090x_Px_KREFTMG(1)
-#define STV090x_P2_KREFTMG			STV090x_Px_KREFTMG(2)
-#define STV090x_OFFST_Px_KREF_TMG_FIELD		0
-#define STV090x_WIDTH_Px_KREF_TMG_FIELD		8
-
-#define STV090x_Px_SFRSTEP(__x)			(0xF459 - (__x - 1) * 0x200)
-#define STV090x_P1_SFRSTEP			STV090x_Px_SFRSTEP(1)
-#define STV090x_P2_SFRSTEP			STV090x_Px_SFRSTEP(2)
-#define STV090x_OFFST_Px_SFR_SCANSTEP_FIELD	4
-#define STV090x_WIDTH_Px_SFR_SCANSTEP_FIELD	4
-#define STV090x_OFFST_Px_SFR_CENTERSTEP_FIELD	0
-#define STV090x_WIDTH_Px_SFR_CENTERSTEP_FIELD	4
-
-#define STV090x_Px_TMGCFG2(__x)			(0xF45A - (__x - 1) * 0x200)
-#define STV090x_P1_TMGCFG2			STV090x_Px_TMGCFG2(1)
-#define STV090x_P2_TMGCFG2			STV090x_Px_TMGCFG2(2)
-#define STV090x_OFFST_Px_SFRRATIO_FINE_FIELD	0
-#define STV090x_WIDTH_Px_SFRRATIO_FINE_FIELD	1
-
-#define STV090x_Px_SFRINIT1(__x)		(0xF45E - (__x - 1) * 0x200)
-#define STV090x_P1_SFRINIT1			STV090x_Px_SFRINIT1(1)
-#define STV090x_P2_SFRINIT1			STV090x_Px_SFRINIT1(2)
-#define STV090x_OFFST_Px_SFR_INIT1_FIELD	0
-#define STV090x_WIDTH_Px_SFR_INIT1_FIELD	7
-
-#define STV090x_Px_SFRINIT0(__x)		(0xF45F - (__x - 1) * 0x200)
-#define STV090x_P1_SFRINIT0			STV090x_Px_SFRINIT0(1)
-#define STV090x_P2_SFRINIT0			STV090x_Px_SFRINIT0(2)
-#define STV090x_OFFST_Px_SFR_INIT0_FIELD	0
-#define STV090x_WIDTH_Px_SFR_INIT0_FIELD	8
-
-#define STV090x_Px_SFRUP1(__x)			(0xF460 - (__x - 1) * 0x200)
-#define STV090x_P1_SFRUP1			STV090x_Px_SFRUP1(1)
-#define STV090x_P2_SFRUP1			STV090x_Px_SFRUP1(2)
-#define STV090x_OFFST_Px_SYMB_FREQ_UP1_FIELD	0
-#define STV090x_WIDTH_Px_SYMB_FREQ_UP1_FIELD	7
-
-#define STV090x_Px_SFRUP0(__x)			(0xF461 - (__x - 1) * 0x200)
-#define STV090x_P1_SFRUP0			STV090x_Px_SFRUP0(1)
-#define STV090x_P2_SFRUP0			STV090x_Px_SFRUP0(2)
-#define STV090x_OFFST_Px_SYMB_FREQ_UP0_FIELD	0
-#define STV090x_WIDTH_Px_SYMB_FREQ_UP0_FIELD	8
-
-#define STV090x_Px_SFRLOW1(__x)			(0xF462 - (__x - 1) * 0x200)
-#define STV090x_P1_SFRLOW1			STV090x_Px_SFRLOW1(1)
-#define STV090x_P2_SFRLOW1			STV090x_Px_SFRLOW1(2)
-#define STV090x_OFFST_Px_SYMB_FREQ_LOW1_FIELD	0
-#define STV090x_WIDTH_Px_SYMB_FREQ_LOW1_FIELD	7
-
-#define STV090x_Px_SFRLOW0(__x)			(0xF463 - (__x - 1) * 0x200)
-#define STV090x_P1_SFRLOW0			STV090x_Px_SFRLOW0(1)
-#define STV090x_P2_SFRLOW0			STV090x_Px_SFRLOW0(2)
-#define STV090x_OFFST_Px_SYMB_FREQ_LOW0_FIELD	0
-#define STV090x_WIDTH_Px_SYMB_FREQ_LOW0_FIELD	8
-
-#define STV090x_Px_SFRy(__x, __y)		(0xF467 - (__x-1) * 0x200 - __y)
-#define STV090x_P1_SFR0				STV090x_Px_SFRy(1, 0)
-#define STV090x_P1_SFR1				STV090x_Px_SFRy(1, 1)
-#define STV090x_P1_SFR2				STV090x_Px_SFRy(1, 2)
-#define STV090x_P1_SFR3				STV090x_Px_SFRy(1, 3)
-#define STV090x_P2_SFR0				STV090x_Px_SFRy(2, 0)
-#define STV090x_P2_SFR1				STV090x_Px_SFRy(2, 1)
-#define STV090x_P2_SFR2				STV090x_Px_SFRy(2, 2)
-#define STV090x_P2_SFR3				STV090x_Px_SFRy(2, 3)
-#define STV090x_OFFST_Px_SYMB_FREQ_FIELD	0
-#define STV090x_WIDTH_Px_SYMB_FREQ_FIELD	8
-
-#define STV090x_Px_TMGREG2(__x)			(0xF468 - (__x - 1) * 0x200)
-#define STV090x_P1_TMGREG2			STV090x_Px_TMGREG2(1)
-#define STV090x_P2_TMGREG2			STV090x_Px_TMGREG2(2)
-#define STV090x_OFFST_Px_TMGREG_FIELD		0
-#define STV090x_WIDTH_Px_TMGREG_FIELD		8
-
-#define STV090x_Px_TMGREG1(__x)			(0xF469 - (__x - 1) * 0x200)
-#define STV090x_P1_TMGREG1			STV090x_Px_TMGREG1(1)
-#define STV090x_P2_TMGREG1			STV090x_Px_TMGREG1(2)
-#define STV090x_OFFST_Px_TMGREG_FIELD		0
-#define STV090x_WIDTH_Px_TMGREG_FIELD		8
-
-#define STV090x_Px_TMGREG0(__x)			(0xF46A - (__x - 1) * 0x200)
-#define STV090x_P1_TMGREG0			STV090x_Px_TMGREG0(1)
-#define STV090x_P2_TMGREG0			STV090x_Px_TMGREG0(2)
-#define STV090x_OFFST_Px_TMGREG_FIELD		0
-#define STV090x_WIDTH_Px_TMGREG_FIELD		8
-
-#define STV090x_Px_TMGLOCKy(__x, __y)		(0xF46C - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_TMGLOCK0			STV090x_Px_TMGLOCKy(1, 0)
-#define STV090x_P1_TMGLOCK1			STV090x_Px_TMGLOCKy(1, 1)
-#define STV090x_P2_TMGLOCK0			STV090x_Px_TMGLOCKy(2, 0)
-#define STV090x_P2_TMGLOCK1			STV090x_Px_TMGLOCKy(2, 1)
-#define STV090x_OFFST_Px_TMGLOCK_LEVEL_FIELD	0
-#define STV090x_WIDTH_Px_TMGLOCK_LEVEL_FIELD	8
-
-#define STV090x_Px_TMGOBS(__x)			(0xF46D - (__x - 1) * 0x200)
-#define STV090x_P1_TMGOBS			STV090x_Px_TMGOBS(1)
-#define STV090x_P2_TMGOBS			STV090x_Px_TMGOBS(2)
-#define STV090x_OFFST_Px_ROLLOFF_STATUS_FIELD	6
-#define STV090x_WIDTH_Px_ROLLOFF_STATUS_FIELD	2
-
-#define STV090x_Px_EQUALCFG(__x)		(0xF46F - (__x - 1) * 0x200)
-#define STV090x_P1_EQUALCFG			STV090x_Px_EQUALCFG(1)
-#define STV090x_P2_EQUALCFG			STV090x_Px_EQUALCFG(2)
-#define STV090x_OFFST_Px_EQUAL_ON_FIELD		6
-#define STV090x_WIDTH_Px_EQUAL_ON_FIELD		1
-#define STV090x_OFFST_Px_MU_EQUALDFE_FIELD	0
-#define STV090x_WIDTH_Px_MU_EQUALDFE_FIELD	3
-
-#define STV090x_Px_EQUAIy(__x, __y)	(0xf470 - (__x-1) * 0x200 + 2 * (__y-1))
-#define STV090x_P1_EQUAI1			STV090x_Px_EQUAIy(1, 1)
-#define STV090x_P1_EQUAI2			STV090x_Px_EQUAIy(1, 2)
-#define STV090x_P1_EQUAI3			STV090x_Px_EQUAIy(1, 3)
-#define STV090x_P1_EQUAI4			STV090x_Px_EQUAIy(1, 4)
-#define STV090x_P1_EQUAI5			STV090x_Px_EQUAIy(1, 5)
-#define STV090x_P1_EQUAI6			STV090x_Px_EQUAIy(1, 6)
-#define STV090x_P1_EQUAI7			STV090x_Px_EQUAIy(1, 7)
-#define STV090x_P1_EQUAI8			STV090x_Px_EQUAIy(1, 8)
-
-#define STV090x_P2_EQUAI1			STV090x_Px_EQUAIy(2, 1)
-#define STV090x_P2_EQUAI2			STV090x_Px_EQUAIy(2, 2)
-#define STV090x_P2_EQUAI3			STV090x_Px_EQUAIy(2, 3)
-#define STV090x_P2_EQUAI4			STV090x_Px_EQUAIy(2, 4)
-#define STV090x_P2_EQUAI5			STV090x_Px_EQUAIy(2, 5)
-#define STV090x_P2_EQUAI6			STV090x_Px_EQUAIy(2, 6)
-#define STV090x_P2_EQUAI7			STV090x_Px_EQUAIy(2, 7)
-#define STV090x_P2_EQUAI8			STV090x_Px_EQUAIy(2, 8)
-#define STV090x_OFFST_Px_EQUA_ACCIy_FIELD	0
-#define STV090x_WIDTH_Px_EQUA_ACCIy_FIELD	8
-
-#define STV090x_Px_EQUAQy(__x, __y)	(0xf471 - (__x-1) * 0x200 + 2 * (__y-1))
-#define STV090x_P1_EQUAQ1			STV090x_Px_EQUAQy(1, 1)
-#define STV090x_P1_EQUAQ2			STV090x_Px_EQUAQy(1, 2)
-#define STV090x_P1_EQUAQ3			STV090x_Px_EQUAQy(1, 3)
-#define STV090x_P1_EQUAQ4			STV090x_Px_EQUAQy(1, 4)
-#define STV090x_P1_EQUAQ5			STV090x_Px_EQUAQy(1, 5)
-#define STV090x_P1_EQUAQ6			STV090x_Px_EQUAQy(1, 6)
-#define STV090x_P1_EQUAQ7			STV090x_Px_EQUAQy(1, 7)
-#define STV090x_P1_EQUAQ8			STV090x_Px_EQUAQy(1, 8)
-
-#define STV090x_P2_EQUAQ1			STV090x_Px_EQUAQy(2, 1)
-#define STV090x_P2_EQUAQ2			STV090x_Px_EQUAQy(2, 2)
-#define STV090x_P2_EQUAQ3			STV090x_Px_EQUAQy(2, 3)
-#define STV090x_P2_EQUAQ4			STV090x_Px_EQUAQy(2, 4)
-#define STV090x_P2_EQUAQ5			STV090x_Px_EQUAQy(2, 5)
-#define STV090x_P2_EQUAQ6			STV090x_Px_EQUAQy(2, 6)
-#define STV090x_P2_EQUAQ7			STV090x_Px_EQUAQy(2, 7)
-#define STV090x_P2_EQUAQ8			STV090x_Px_EQUAQy(2, 8)
-#define STV090x_OFFST_Px_EQUA_ACCQy_FIELD	0
-#define STV090x_WIDTH_Px_EQUA_ACCQy_FIELD	8
-
-#define STV090x_Px_NNOSDATATy(__x, __y)		(0xf481 - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_NNOSDATAT0			STV090x_Px_NNOSDATATy(1, 0)
-#define STV090x_P1_NNOSDATAT1			STV090x_Px_NNOSDATATy(1, 1)
-#define STV090x_P2_NNOSDATAT0			STV090x_Px_NNOSDATATy(2, 0)
-#define STV090x_P2_NNOSDATAT1			STV090x_Px_NNOSDATATy(2, 1)
-#define STV090x_OFFST_Px_NOSDATAT_NORMED_FIELD	0
-#define STV090x_WIDTH_Px_NOSDATAT_NORMED_FIELD	8
-
-#define STV090x_Px_NNOSDATAy(__x, __y)		(0xf483 - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_NNOSDATA0			STV090x_Px_NNOSDATAy(1, 0)
-#define STV090x_P1_NNOSDATA1			STV090x_Px_NNOSDATAy(1, 1)
-#define STV090x_P2_NNOSDATA0			STV090x_Px_NNOSDATAy(2, 0)
-#define STV090x_P2_NNOSDATA1			STV090x_Px_NNOSDATAy(2, 1)
-#define STV090x_OFFST_Px_NOSDATA_NORMED_FIELD	0
-#define STV090x_WIDTH_Px_NOSDATA_NORMED_FIELD	8
-
-#define STV090x_Px_NNOSPLHTy(__x, __y)		(0xf485 - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_NNOSPLHT0			STV090x_Px_NNOSPLHTy(1, 0)
-#define STV090x_P1_NNOSPLHT1			STV090x_Px_NNOSPLHTy(1, 1)
-#define STV090x_P2_NNOSPLHT0			STV090x_Px_NNOSPLHTy(2, 0)
-#define STV090x_P2_NNOSPLHT1			STV090x_Px_NNOSPLHTy(2, 1)
-#define STV090x_OFFST_Px_NOSPLHT_NORMED_FIELD	0
-#define STV090x_WIDTH_Px_NOSPLHT_NORMED_FIELD	8
-
-#define STV090x_Px_NNOSPLHy(__x, __y)		(0xf487 - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_NNOSPLH0			STV090x_Px_NNOSPLHy(1, 0)
-#define STV090x_P1_NNOSPLH1			STV090x_Px_NNOSPLHy(1, 1)
-#define STV090x_P2_NNOSPLH0			STV090x_Px_NNOSPLHy(2, 0)
-#define STV090x_P2_NNOSPLH1			STV090x_Px_NNOSPLHy(2, 1)
-#define STV090x_OFFST_Px_NOSPLH_NORMED_FIELD	0
-#define STV090x_WIDTH_Px_NOSPLH_NORMED_FIELD	8
-
-#define STV090x_Px_NOSDATATy(__x, __y)			(0xf489 - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_NOSDATAT0				STV090x_Px_NOSDATATy(1, 0)
-#define STV090x_P1_NOSDATAT1				STV090x_Px_NOSDATATy(1, 1)
-#define STV090x_P2_NOSDATAT0				STV090x_Px_NOSDATATy(2, 0)
-#define STV090x_P2_NOSDATAT1				STV090x_Px_NOSDATATy(2, 1)
-#define STV090x_OFFST_Px_NOSDATAT_UNNORMED_FIELD	0
-#define STV090x_WIDTH_Px_NOSDATAT_UNNORMED_FIELD	8
-
-#define STV090x_Px_NOSDATAy(__x, __y)		(0xf48b - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_NOSDATA0			STV090x_Px_NOSDATAy(1, 0)
-#define STV090x_P1_NOSDATA1			STV090x_Px_NOSDATAy(1, 1)
-#define STV090x_P2_NOSDATA0			STV090x_Px_NOSDATAy(2, 0)
-#define STV090x_P2_NOSDATA1			STV090x_Px_NOSDATAy(2, 1)
-#define STV090x_OFFST_Px_NOSDATA_UNNORMED_FIELD	0
-#define STV090x_WIDTH_Px_NOSDATA_UNNORMED_FIELD	8
-
-#define STV090x_Px_NOSPLHTy(__x, __y)		(0xf48d - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_NOSPLHT0			STV090x_Px_NOSPLHTy(1, 0)
-#define STV090x_P1_NOSPLHT1			STV090x_Px_NOSPLHTy(1, 1)
-#define STV090x_P2_NOSPLHT0			STV090x_Px_NOSPLHTy(2, 0)
-#define STV090x_P2_NOSPLHT1			STV090x_Px_NOSPLHTy(2, 1)
-#define STV090x_OFFST_Px_NOSPLHT_UNNORMED_FIELD	0
-#define STV090x_WIDTH_Px_NOSPLHT_UNNORMED_FIELD	8
-
-#define STV090x_Px_NOSPLHy(__x, __y)		(0xf48f - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_NOSPLH0			STV090x_Px_NOSPLHy(1, 0)
-#define STV090x_P1_NOSPLH1			STV090x_Px_NOSPLHy(1, 1)
-#define STV090x_P2_NOSPLH0			STV090x_Px_NOSPLHy(2, 0)
-#define STV090x_P2_NOSPLH1			STV090x_Px_NOSPLHy(2, 1)
-#define STV090x_OFFST_Px_NOSPLH_UNNORMED_FIELD	0
-#define STV090x_WIDTH_Px_NOSPLH_UNNORMED_FIELD	8
-
-#define STV090x_Px_CAR2CFG(__x)			(0xf490 - (__x - 1) * 0x200)
-#define STV090x_P1_CAR2CFG			STV090x_Px_CAR2CFG(1)
-#define STV090x_P2_CAR2CFG			STV090x_Px_CAR2CFG(2)
-#define STV090x_OFFST_Px_PN4_SELECT_FIELD	6
-#define STV090x_WIDTH_Px_PN4_SELECT_FIELD	1
-#define STV090x_OFFST_Px_CFR2_STOPDVBS1_FIELD	5
-#define STV090x_WIDTH_Px_CFR2_STOPDVBS1_FIELD	1
-#define STV090x_OFFST_Px_ROTA2ON_FIELD		2
-#define STV090x_WIDTH_Px_ROTA2ON_FIELD		1
-#define STV090x_OFFST_Px_PH_DET_ALGO2_FIELD	0
-#define STV090x_WIDTH_Px_PH_DET_ALGO2_FIELD	2
-
-#define STV090x_Px_ACLC2(__x)			(0xf491 - (__x - 1) * 0x200)
-#define STV090x_P1_ACLC2			STV090x_Px_ACLC2(1)
-#define STV090x_P2_ACLC2			STV090x_Px_ACLC2(2)
-#define STV090x_OFFST_Px_CAR2_ALPHA_MANT_FIELD	4
-#define STV090x_WIDTH_Px_CAR2_ALPHA_MANT_FIELD	2
-#define STV090x_OFFST_Px_CAR2_ALPHA_EXP_FIELD	0
-#define STV090x_WIDTH_Px_CAR2_ALPHA_EXP_FIELD	4
-
-#define STV090x_Px_BCLC2(__x)			(0xf492 - (__x - 1) * 0x200)
-#define STV090x_P1_BCLC2			STV090x_Px_BCLC2(1)
-#define STV090x_P2_BCLC2			STV090x_Px_BCLC2(2)
-#define STV090x_OFFST_Px_CAR2_BETA_MANT_FIELD	4
-#define STV090x_WIDTH_Px_CAR2_BETA_MANT_FIELD	2
-#define STV090x_OFFST_Px_CAR2_BETA_EXP_FIELD	0
-#define STV090x_WIDTH_Px_CAR2_BETA_EXP_FIELD	4
-
-#define STV090x_Px_ACLC2S2Q(__x)		(0xf497 - (__x - 1) * 0x200)
-#define STV090x_P1_ACLC2S2Q			STV090x_Px_ACLC2S2Q(1)
-#define STV090x_P2_ACLC2S2Q			STV090x_Px_ACLC2S2Q(2)
-#define STV090x_OFFST_Px_ENAB_SPSKSYMB_FIELD	7
-#define STV090x_WIDTH_Px_ENAB_SPSKSYMB_FIELD	1
-#define STV090x_OFFST_Px_CAR2S2_Q_ALPH_M_FIELD	4
-#define STV090x_WIDTH_Px_CAR2S2_Q_ALPH_M_FIELD	2
-#define STV090x_OFFST_Px_CAR2S2_Q_ALPH_E_FIELD	0
-#define STV090x_WIDTH_Px_CAR2S2_Q_ALPH_E_FIELD	4
-
-#define STV090x_Px_ACLC2S28(__x)		(0xf498 - (__x - 1) * 0x200)
-#define STV090x_P1_ACLC2S28			STV090x_Px_ACLC2S28(1)
-#define STV090x_P2_ACLC2S28			STV090x_Px_ACLC2S28(2)
-#define STV090x_OFFST_Px_CAR2S2_8_ALPH_M_FIELD	4
-#define STV090x_WIDTH_Px_CAR2S2_8_ALPH_M_FIELD	2
-#define STV090x_OFFST_Px_CAR2S2_8_ALPH_E_FIELD	0
-#define STV090x_WIDTH_Px_CAR2S2_8_ALPH_E_FIELD	4
-
-#define STV090x_Px_ACLC2S216A(__x)		(0xf499 - (__x - 1) * 0x200)
-#define STV090x_P1_ACLC2S216A			STV090x_Px_ACLC2S216A(1)
-#define STV090x_P2_ACLC2S216A			STV090x_Px_ACLC2S216A(2)
-#define STV090x_OFFST_Px_CAR2S2_16A_ALPH_M_FIELD	4
-#define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_M_FIELD	2
-#define STV090x_OFFST_Px_CAR2S2_16A_ALPH_E_FIELD	0
-#define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_E_FIELD	4
-
-#define STV090x_Px_ACLC2S232A(__x)		(0xf49A - (__x - 1) * 0x200)
-#define STV090x_P1_ACLC2S232A			STV090x_Px_ACLC2S232A(1)
-#define STV090x_P2_ACLC2S232A			STV090x_Px_ACLC2S232A(2)
-#define STV090x_OFFST_Px_CAR2S2_32A_ALPH_M_FIELD	4
-#define STV090x_WIDTH_Px_CAR2S2_32A_ALPH_M_FIELD	2
-#define STV090x_OFFST_Px_CAR2S2_32A_ALPH_E_FIELD	0
-#define STV090x_WIDTH_Px_CAR2S2_32A_ALPH_E_FIELD	4
-
-#define STV090x_Px_BCLC2S2Q(__x)		(0xf49c - (__x - 1) * 0x200)
-#define STV090x_P1_BCLC2S2Q			STV090x_Px_BCLC2S2Q(1)
-#define STV090x_P2_BCLC2S2Q			STV090x_Px_BCLC2S2Q(2)
-#define STV090x_OFFST_Px_CAR2S2_Q_BETA_M_FIELD	4
-#define STV090x_WIDTH_Px_CAR2S2_Q_BETA_M_FIELD	2
-#define STV090x_OFFST_Px_CAR2S2_Q_BETA_E_FIELD	0
-#define STV090x_WIDTH_Px_CAR2S2_Q_BETA_E_FIELD	4
-
-#define STV090x_Px_BCLC2S28(__x)		(0xf49d - (__x - 1) * 0x200)
-#define STV090x_P1_BCLC2S28			STV090x_Px_BCLC2S28(1)
-#define STV090x_P2_BCLC2S28			STV090x_Px_BCLC2S28(2)
-#define STV090x_OFFST_Px_CAR2S2_8_BETA_M_FIELD	4
-#define STV090x_WIDTH_Px_CAR2S2_8_BETA_M_FIELD	2
-#define STV090x_OFFST_Px_CAR2S2_8_BETA_E_FIELD	0
-#define STV090x_WIDTH_Px_CAR2S2_8_BETA_E_FIELD	4
-
-#define STV090x_Px_BCLC2S216A(__x)		(0xf49e - (__x - 1) * 0x200)
-#define STV090x_P1_BCLC2S216A			STV090x_Px_BCLC2S216A(1)
-#define STV090x_P2_BCLC2S216A			STV090x_Px_BCLC2S216A(2)
-#define STV090x_OFFST_Px_CAR2S2_16A_BETA_M_FIELD	4
-#define STV090x_WIDTH_Px_CAR2S2_16A_BETA_M_FIELD	2
-#define STV090x_OFFST_Px_CAR2S2_16A_BETA_E_FIELD	0
-#define STV090x_WIDTH_Px_CAR2S2_16A_BETA_E_FIELD	4
-
-#define STV090x_Px_BCLC2S232A(__x)		(0xf49f - (__x - 1) * 0x200)
-#define STV090x_P1_BCLC2S232A			STV090x_Px_BCLC2S232A(1)
-#define STV090x_P2_BCLC2S232A			STV090x_Px_BCLC2S232A(2)
-#define STV090x_OFFST_Px_CAR2S2_32A_BETA_M_FIELD	4
-#define STV090x_WIDTH_Px_CAR2S2_32A_BETA_M_FIELD	2
-#define STV090x_OFFST_Px_CAR2S2_32A_BETA_E_FIELD	0
-#define STV090x_WIDTH_Px_CAR2S2_32A_BETA_E_FIELD	4
-
-#define STV090x_Px_PLROOT2(__x)			(0xf4ac - (__x - 1) * 0x200)
-#define STV090x_P1_PLROOT2			STV090x_Px_PLROOT2(1)
-#define STV090x_P2_PLROOT2			STV090x_Px_PLROOT2(2)
-#define STV090x_OFFST_Px_PLSCRAMB_MODE_FIELD	2
-#define STV090x_WIDTH_Px_PLSCRAMB_MODE_FIELD	2
-#define STV090x_OFFST_Px_PLSCRAMB_ROOT_FIELD	0
-#define STV090x_WIDTH_Px_PLSCRAMB_ROOT_FIELD	2
-
-#define STV090x_Px_PLROOT1(__x)			(0xf4ad - (__x - 1) * 0x200)
-#define STV090x_P1_PLROOT1			STV090x_Px_PLROOT1(1)
-#define STV090x_P2_PLROOT1			STV090x_Px_PLROOT1(2)
-#define STV090x_OFFST_Px_PLSCRAMB_ROOT1_FIELD	0
-#define STV090x_WIDTH_Px_PLSCRAMB_ROOT1_FIELD	8
-
-#define STV090x_Px_PLROOT0(__x)			(0xf4ae - (__x - 1) * 0x200)
-#define STV090x_P1_PLROOT0			STV090x_Px_PLROOT0(1)
-#define STV090x_P2_PLROOT0			STV090x_Px_PLROOT0(2)
-#define STV090x_OFFST_Px_PLSCRAMB_ROOT0_FIELD	0
-#define STV090x_WIDTH_Px_PLSCRAMB_ROOT0_FIELD	8
-
-#define STV090x_Px_MODCODLST0(__x)		(0xf4b0 - (__x - 1) * 0x200) /* check */
-#define STV090x_P1_MODCODLST0			STV090x_Px_MODCODLST0(1)
-#define STV090x_P2_MODCODLST0			STV090x_Px_MODCODLST0(2)
-
-#define STV090x_Px_MODCODLST1(__x)		(0xf4b1 - (__x - 1) * 0x200)
-#define STV090x_P1_MODCODLST1			STV090x_Px_MODCODLST1(1)
-#define STV090x_P2_MODCODLST1			STV090x_Px_MODCODLST1(2)
-#define STV090x_OFFST_Px_DIS_MODCOD29_FIELD	4
-#define STV090x_WIDTH_Px_DIS_MODCOD29_FIELD	4
-#define STV090x_OFFST_Px_DIS_32PSK_9_10_FIELD	0
-#define STV090x_WIDTH_Px_DIS_32PSK_9_10_FIELD	4
-
-#define STV090x_Px_MODCODLST2(__x)		(0xf4b2 - (__x - 1) * 0x200)
-#define STV090x_P1_MODCODLST2			STV090x_Px_MODCODLST2(1)
-#define STV090x_P2_MODCODLST2			STV090x_Px_MODCODLST2(2)
-#define STV090x_OFFST_Px_DIS_32PSK_8_9_FIELD	4
-#define STV090x_WIDTH_Px_DIS_32PSK_8_9_FIELD	4
-#define STV090x_OFFST_Px_DIS_32PSK_5_6_FIELD	0
-#define STV090x_WIDTH_Px_DIS_32PSK_5_6_FIELD	4
-
-#define STV090x_Px_MODCODLST3(__x)		(0xf4b3 - (__x - 1) * 0x200)
-#define STV090x_P1_MODCODLST3			STV090x_Px_MODCODLST3(1)
-#define STV090x_P2_MODCODLST3			STV090x_Px_MODCODLST3(2)
-#define STV090x_OFFST_Px_DIS_32PSK_4_5_FIELD	4
-#define STV090x_WIDTH_Px_DIS_32PSK_4_5_FIELD	4
-#define STV090x_OFFST_Px_DIS_32PSK_3_4_FIELD	0
-#define STV090x_WIDTH_Px_DIS_32PSK_3_4_FIELD	4
-
-#define STV090x_Px_MODCODLST4(__x)		(0xf4b4 - (__x - 1) * 0x200)
-#define STV090x_P1_MODCODLST4			STV090x_Px_MODCODLST4(1)
-#define STV090x_P2_MODCODLST4			STV090x_Px_MODCODLST4(2)
-#define STV090x_OFFST_Px_DIS_16PSK_9_10_FIELD	4
-#define STV090x_WIDTH_Px_DIS_16PSK_9_10_FIELD	4
-#define STV090x_OFFST_Px_DIS_16PSK_8_9_FIELD	0
-#define STV090x_WIDTH_Px_DIS_16PSK_8_9_FIELD	4
-
-#define STV090x_Px_MODCODLST5(__x)		(0xf4b5 - (__x - 1) * 0x200)
-#define STV090x_P1_MODCODLST5			STV090x_Px_MODCODLST5(1)
-#define STV090x_P2_MODCODLST5			STV090x_Px_MODCODLST5(2)
-#define STV090x_OFFST_Px_DIS_16PSK_5_6_FIELD	4
-#define STV090x_WIDTH_Px_DIS_16PSK_5_6_FIELD	4
-#define STV090x_OFFST_Px_DIS_16PSK_4_5_FIELD	0
-#define STV090x_WIDTH_Px_DIS_16PSK_4_5_FIELD	4
-
-#define STV090x_Px_MODCODLST6(__x)		(0xf4b6 - (__x - 1) * 0x200)
-#define STV090x_P1_MODCODLST6			STV090x_Px_MODCODLST6(1)
-#define STV090x_P2_MODCODLST6			STV090x_Px_MODCODLST6(2)
-#define STV090x_OFFST_Px_DIS_16PSK_3_4_FIELD	4
-#define STV090x_WIDTH_Px_DIS_16PSK_3_4_FIELD	4
-#define STV090x_OFFST_Px_DIS_16PSK_2_3_FIELD	0
-#define STV090x_WIDTH_Px_DIS_16PSK_2_3_FIELD	4
-
-#define STV090x_Px_MODCODLST7(__x)		(0xf4b7 - (__x - 1) * 0x200)
-#define STV090x_P1_MODCODLST7			STV090x_Px_MODCODLST7(1)
-#define STV090x_P2_MODCODLST7			STV090x_Px_MODCODLST7(2)
-#define STV090x_OFFST_Px_DIS_8P_9_10_FIELD	4
-#define STV090x_WIDTH_Px_DIS_8P_9_10_FIELD	4
-#define STV090x_OFFST_Px_DIS_8P_8_9_FIELD	0
-#define STV090x_WIDTH_Px_DIS_8P_8_9_FIELD	4
-
-#define STV090x_Px_MODCODLST8(__x)		(0xf4b8 - (__x - 1) * 0x200)
-#define STV090x_P1_MODCODLST8			STV090x_Px_MODCODLST8(1)
-#define STV090x_P2_MODCODLST8			STV090x_Px_MODCODLST8(2)
-#define STV090x_OFFST_Px_DIS_8P_5_6_FIELD	4
-#define STV090x_WIDTH_Px_DIS_8P_5_6_FIELD	4
-#define STV090x_OFFST_Px_DIS_8P_3_4_FIELD	0
-#define STV090x_WIDTH_Px_DIS_8P_3_4_FIELD	4
-
-#define STV090x_Px_MODCODLST9(__x)		(0xf4b9 - (__x - 1) * 0x200)
-#define STV090x_P1_MODCODLST9			STV090x_Px_MODCODLST9(1)
-#define STV090x_P2_MODCODLST9			STV090x_Px_MODCODLST9(2)
-#define STV090x_OFFST_Px_DIS_8P_2_3_FIELD	4
-#define STV090x_WIDTH_Px_DIS_8P_2_3_FIELD	4
-#define STV090x_OFFST_Px_DIS_8P_3_5_FIELD	0
-#define STV090x_WIDTH_Px_DIS_8P_3_5_FIELD	4
-
-#define STV090x_Px_MODCODLSTA(__x)		(0xf4ba - (__x - 1) * 0x200)
-#define STV090x_P1_MODCODLSTA			STV090x_Px_MODCODLSTA(1)
-#define STV090x_P2_MODCODLSTA			STV090x_Px_MODCODLSTA(2)
-#define STV090x_OFFST_Px_DIS_QP_9_10_FIELD	4
-#define STV090x_WIDTH_Px_DIS_QP_9_10_FIELD	4
-#define STV090x_OFFST_Px_DIS_QP_8_9_FIELD	0
-#define STV090x_WIDTH_Px_DIS_QP_8_9_FIELD	4
-
-#define STV090x_Px_MODCODLSTB(__x)		(0xf4bb - (__x - 1) * 0x200)
-#define STV090x_P1_MODCODLSTB			STV090x_Px_MODCODLSTB(1)
-#define STV090x_P2_MODCODLSTB			STV090x_Px_MODCODLSTB(2)
-#define STV090x_OFFST_Px_DIS_QP_5_6_FIELD	4
-#define STV090x_WIDTH_Px_DIS_QP_5_6_FIELD	4
-#define STV090x_OFFST_Px_DIS_QP_4_5_FIELD	0
-#define STV090x_WIDTH_Px_DIS_QP_4_5_FIELD	4
-
-#define STV090x_Px_MODCODLSTC(__x)		(0xf4bc - (__x - 1) * 0x200)
-#define STV090x_P1_MODCODLSTC			STV090x_Px_MODCODLSTC(1)
-#define STV090x_P2_MODCODLSTC			STV090x_Px_MODCODLSTC(2)
-#define STV090x_OFFST_Px_DIS_QP_3_4_FIELD	4
-#define STV090x_WIDTH_Px_DIS_QP_3_4_FIELD	4
-#define STV090x_OFFST_Px_DIS_QP_2_3_FIELD	0
-#define STV090x_WIDTH_Px_DIS_QP_2_3_FIELD	4
-
-#define STV090x_Px_MODCODLSTD(__x)		(0xf4bd - (__x - 1) * 0x200)
-#define STV090x_P1_MODCODLSTD			STV090x_Px_MODCODLSTD(1)
-#define STV090x_P2_MODCODLSTD			STV090x_Px_MODCODLSTD(2)
-#define STV090x_OFFST_Px_DIS_QP_3_5_FIELD	4
-#define STV090x_WIDTH_Px_DIS_QP_3_5_FIELD	4
-#define STV090x_OFFST_Px_DIS_QP_1_2_FIELD	0
-#define STV090x_WIDTH_Px_DIS_QP_1_2_FIELD	4
-
-#define STV090x_Px_MODCODLSTE(__x)		(0xf4be - (__x - 1) * 0x200)
-#define STV090x_P1_MODCODLSTE			STV090x_Px_MODCODLSTE(1)
-#define STV090x_P2_MODCODLSTE			STV090x_Px_MODCODLSTE(2)
-#define STV090x_OFFST_Px_DIS_QP_2_5_FIELD	4
-#define STV090x_WIDTH_Px_DIS_QP_2_5_FIELD	4
-#define STV090x_OFFST_Px_DIS_QP_1_3_FIELD	0
-#define STV090x_WIDTH_Px_DIS_QP_1_3_FIELD	4
-
-#define STV090x_Px_MODCODLSTF(__x)		(0xf4bf - (__x - 1) * 0x200)
-#define STV090x_P1_MODCODLSTF			STV090x_Px_MODCODLSTF(1)
-#define STV090x_P2_MODCODLSTF			STV090x_Px_MODCODLSTF(2)
-#define STV090x_OFFST_Px_DIS_QP_1_4_FIELD	4
-#define STV090x_WIDTH_Px_DIS_QP_1_4_FIELD	4
-
-#define STV090x_Px_GAUSSR0(__x)			(0xf4c0 - (__x - 1) * 0x200)
-#define STV090x_P1_GAUSSR0			STV090x_Px_GAUSSR0(1)
-#define STV090x_P2_GAUSSR0			STV090x_Px_GAUSSR0(2)
-#define STV090x_OFFST_Px_EN_CCIMODE_FIELD	7
-#define STV090x_WIDTH_Px_EN_CCIMODE_FIELD	1
-#define STV090x_OFFST_Px_R0_GAUSSIEN_FIELD	0
-#define STV090x_WIDTH_Px_R0_GAUSSIEN_FIELD	7
-
-#define STV090x_Px_CCIR0(__x)			(0xf4c1 - (__x - 1) * 0x200)
-#define STV090x_P1_CCIR0			STV090x_Px_CCIR0(1)
-#define STV090x_P2_CCIR0			STV090x_Px_CCIR0(2)
-#define STV090x_OFFST_Px_CCIDETECT_PLH_FIELD	7
-#define STV090x_WIDTH_Px_CCIDETECT_PLH_FIELD	1
-#define STV090x_OFFST_Px_R0_CCI_FIELD		0
-#define STV090x_WIDTH_Px_R0_CCI_FIELD		7
-
-#define STV090x_Px_CCIQUANT(__x)		(0xf4c2 - (__x - 1) * 0x200)
-#define STV090x_P1_CCIQUANT			STV090x_Px_CCIQUANT(1)
-#define STV090x_P2_CCIQUANT			STV090x_Px_CCIQUANT(2)
-#define STV090x_OFFST_Px_CCI_BETA_FIELD		5
-#define STV090x_WIDTH_Px_CCI_BETA_FIELD		3
-#define STV090x_OFFST_Px_CCI_QUANT_FIELD	0
-#define STV090x_WIDTH_Px_CCI_QUANT_FIELD	5
-
-#define STV090x_Px_CCITHRESH(__x)		(0xf4c3 - (__x - 1) * 0x200)
-#define STV090x_P1_CCITHRESH			STV090x_Px_CCITHRESH(1)
-#define STV090x_P2_CCITHRESH			STV090x_Px_CCITHRESH(2)
-#define STV090x_OFFST_Px_CCI_THRESHOLD_FIELD	0
-#define STV090x_WIDTH_Px_CCI_THRESHOLD_FIELD	8
-
-#define STV090x_Px_CCIACC(__x)			(0xf4c4 - (__x - 1) * 0x200)
-#define STV090x_P1_CCIACC			STV090x_Px_CCIACC(1)
-#define STV090x_P2_CCIACC			STV090x_Px_CCIACC(2)
-#define STV090x_OFFST_Px_CCI_VALUE_FIELD	0
-#define STV090x_WIDTH_Px_CCI_VALUE_FIELD	8
-
-#define STV090x_Px_DMDRESCFG(__x)		(0xF4C6 - (__x - 1) * 0x200)
-#define STV090x_P1_DMDRESCFG			STV090x_Px_DMDRESCFG(1)
-#define STV090x_P2_DMDRESCFG			STV090x_Px_DMDRESCFG(2)
-#define STV090x_OFFST_Px_DMDRES_RESET_FIELD	7
-#define STV090x_WIDTH_Px_DMDRES_RESET_FIELD	1
-
-#define STV090x_Px_DMDRESADR(__x)		(0xF4C7 - (__x - 1) * 0x200)
-#define STV090x_P1_DMDRESADR			STV090x_Px_DMDRESADR(1)
-#define STV090x_P2_DMDRESADR			STV090x_Px_DMDRESADR(2)
-#define STV090x_OFFST_Px_DMDRES_RESNBR_FIELD	0
-#define STV090x_WIDTH_Px_DMDRES_RESNBR_FIELD	4
-
-#define STV090x_Px_DMDRESDATAy(__x, __y)	(0xF4C8 - (__x - 1) * 0x200 + (7 - __y))
-#define STV090x_P1_DMDRESDATA0			STV090x_Px_DMDRESDATAy(1, 0)
-#define STV090x_P1_DMDRESDATA1			STV090x_Px_DMDRESDATAy(1, 1)
-#define STV090x_P1_DMDRESDATA2			STV090x_Px_DMDRESDATAy(1, 2)
-#define STV090x_P1_DMDRESDATA3			STV090x_Px_DMDRESDATAy(1, 3)
-#define STV090x_P1_DMDRESDATA4			STV090x_Px_DMDRESDATAy(1, 4)
-#define STV090x_P1_DMDRESDATA5			STV090x_Px_DMDRESDATAy(1, 5)
-#define STV090x_P1_DMDRESDATA6			STV090x_Px_DMDRESDATAy(1, 6)
-#define STV090x_P1_DMDRESDATA7			STV090x_Px_DMDRESDATAy(1, 7)
-#define STV090x_P2_DMDRESDATA0			STV090x_Px_DMDRESDATAy(2, 0)
-#define STV090x_P2_DMDRESDATA1			STV090x_Px_DMDRESDATAy(2, 1)
-#define STV090x_P2_DMDRESDATA2			STV090x_Px_DMDRESDATAy(2, 2)
-#define STV090x_P2_DMDRESDATA3			STV090x_Px_DMDRESDATAy(2, 3)
-#define STV090x_P2_DMDRESDATA4			STV090x_Px_DMDRESDATAy(2, 4)
-#define STV090x_P2_DMDRESDATA5			STV090x_Px_DMDRESDATAy(2, 5)
-#define STV090x_P2_DMDRESDATA6			STV090x_Px_DMDRESDATAy(2, 6)
-#define STV090x_P2_DMDRESDATA7			STV090x_Px_DMDRESDATAy(2, 7)
-#define STV090x_OFFST_Px_DMDRES_DATA_FIELD	0
-#define STV090x_WIDTH_Px_DMDRES_DATA_FIELD	8
-
-#define STV090x_Px_FFEIy(__x, __y)		(0xf4d0 - (__x - 1) * 0x200 + 0x2 * (__y - 1))
-#define STV090x_P1_FFEI1			STV090x_Px_FFEIy(1, 1)
-#define STV090x_P1_FFEI2			STV090x_Px_FFEIy(1, 2)
-#define STV090x_P1_FFEI3			STV090x_Px_FFEIy(1, 3)
-#define STV090x_P1_FFEI4			STV090x_Px_FFEIy(1, 4)
-#define STV090x_P2_FFEI1			STV090x_Px_FFEIy(2, 1)
-#define STV090x_P2_FFEI2			STV090x_Px_FFEIy(2, 2)
-#define STV090x_P2_FFEI3			STV090x_Px_FFEIy(2, 3)
-#define STV090x_P2_FFEI4			STV090x_Px_FFEIy(2, 4)
-#define STV090x_OFFST_Px_FFE_ACCIy_FIELD	0
-#define STV090x_WIDTH_Px_FFE_ACCIy_FIELD	8
-
-#define STV090x_Px_FFEQy(__x, __y)		(0xf4d1 - (__x - 1) * 0x200 + 0x2 * (__y - 1))
-#define STV090x_P1_FFEQ1			STV090x_Px_FFEQy(1, 1)
-#define STV090x_P1_FFEQ2			STV090x_Px_FFEQy(1, 2)
-#define STV090x_P1_FFEQ3			STV090x_Px_FFEQy(1, 3)
-#define STV090x_P1_FFEQ4			STV090x_Px_FFEQy(1, 4)
-#define STV090x_P2_FFEQ1			STV090x_Px_FFEQy(2, 1)
-#define STV090x_P2_FFEQ2			STV090x_Px_FFEQy(2, 2)
-#define STV090x_P2_FFEQ3			STV090x_Px_FFEQy(2, 3)
-#define STV090x_P2_FFEQ4			STV090x_Px_FFEQy(2, 4)
-#define STV090x_OFFST_Px_FFE_ACCQy_FIELD	0
-#define STV090x_WIDTH_Px_FFE_ACCQy_FIELD	8
-
-#define STV090x_Px_FFECFG(__x)			(0xf4d8 - (__x - 1) * 0x200)
-#define STV090x_P1_FFECFG			STV090x_Px_FFECFG(1)
-#define STV090x_P2_FFECFG			STV090x_Px_FFECFG(2)
-#define STV090x_OFFST_Px_EQUALFFE_ON_FIELD	6
-#define STV090x_WIDTH_Px_EQUALFFE_ON_FIELD	1
-
-#define STV090x_Px_SMAPCOEF7(__x)		(0xf500 - (__x - 1) * 0x200)
-#define STV090x_P1_SMAPCOEF7			STV090x_Px_SMAPCOEF7(1)
-#define STV090x_P2_SMAPCOEF7			STV090x_Px_SMAPCOEF7(2)
-#define STV090x_OFFST_Px_DIS_QSCALE_FIELD	7
-#define STV090x_WIDTH_Px_DIS_QSCALE_FIELD	1
-#define STV090x_OFFST_Px_SMAPCOEF_Q_LLR12_FIELD	0
-#define STV090x_WIDTH_Px_SMAPCOEF_Q_LLR12_FIELD	7
-
-#define STV090x_Px_SMAPCOEF6(__x)		(0xf501 - (__x - 1) * 0x200)
-#define STV090x_P1_SMAPCOEF6			STV090x_Px_SMAPCOEF6(1)
-#define STV090x_P2_SMAPCOEF6			STV090x_Px_SMAPCOEF6(2)
-#define STV090x_OFFST_Px_ADJ_8PSKLLR1_FIELD	2
-#define STV090x_WIDTH_Px_ADJ_8PSKLLR1_FIELD	1
-#define STV090x_OFFST_Px_OLD_8PSKLLR1_FIELD	1
-#define STV090x_WIDTH_Px_OLD_8PSKLLR1_FIELD	1
-#define STV090x_OFFST_Px_DIS_AB8PSK_FIELD	0
-#define STV090x_WIDTH_Px_DIS_AB8PSK_FIELD	1
-
-#define STV090x_Px_SMAPCOEF5(__x)			(0xf502 - (__x - 1) * 0x200)
-#define STV090x_P1_SMAPCOEF5				STV090x_Px_SMAPCOEF5(1)
-#define STV090x_P2_SMAPCOEF5				STV090x_Px_SMAPCOEF5(2)
-#define STV090x_OFFST_Px_DIS_8SCALE_FIELD		7
-#define STV090x_WIDTH_Px_DIS_8SCALE_FIELD		1
-#define STV090x_OFFST_Px_SMAPCOEF_8P_LLR23_FIELD	0
-#define STV090x_WIDTH_Px_SMAPCOEF_8P_LLR23_FIELD	7
-
-#define STV090x_Px_DMDPLHSTAT(__x)		(0xF520 - (__x - 1) * 0x200)
-#define STV090x_P1_DMDPLHSTAT			STV090x_Px_DMDPLHSTAT(1)
-#define STV090x_P2_DMDPLHSTAT			STV090x_Px_DMDPLHSTAT(2)
-#define STV090x_OFFST_Px_PLH_STATISTIC_FIELD	0
-#define STV090x_WIDTH_Px_PLH_STATISTIC_FIELD	8
-
-#define STV090x_Px_LOCKTIMEy(__x, __y)		(0xF525 - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_LOCKTIME0			STV090x_Px_LOCKTIMEy(1, 0)
-#define STV090x_P1_LOCKTIME1			STV090x_Px_LOCKTIMEy(1, 1)
-#define STV090x_P1_LOCKTIME2			STV090x_Px_LOCKTIMEy(1, 2)
-#define STV090x_P1_LOCKTIME3			STV090x_Px_LOCKTIMEy(1, 3)
-#define STV090x_P2_LOCKTIME0			STV090x_Px_LOCKTIMEy(2, 0)
-#define STV090x_P2_LOCKTIME1			STV090x_Px_LOCKTIMEy(2, 1)
-#define STV090x_P2_LOCKTIME2			STV090x_Px_LOCKTIMEy(2, 2)
-#define STV090x_P2_LOCKTIME3			STV090x_Px_LOCKTIMEy(2, 3)
-#define STV090x_OFFST_Px_DEMOD_LOCKTIME_FIELD	0
-#define STV090x_WIDTH_Px_DEMOD_LOCKTIME_FIELD	8
-
-#define STV090x_Px_TNRCFG(__x)			(0xf4e0 - (__x - 1) * 0x200) /* check */
-#define STV090x_P1_TNRCFG			STV090x_Px_TNRCFG(1)
-#define STV090x_P2_TNRCFG			STV090x_Px_TNRCFG(2)
-
-#define STV090x_Px_TNRCFG2(__x)			(0xf4e1 - (__x - 1) * 0x200)
-#define STV090x_P1_TNRCFG2			STV090x_Px_TNRCFG2(1)
-#define STV090x_P2_TNRCFG2			STV090x_Px_TNRCFG2(2)
-#define STV090x_OFFST_Px_TUN_IQSWAP_FIELD	7
-#define STV090x_WIDTH_Px_TUN_IQSWAP_FIELD	1
-
-#define STV090x_Px_VITSCALE(__x)		(0xf532 - (__x - 1) * 0x200)
-#define STV090x_P1_VITSCALE			STV090x_Px_VITSCALE(1)
-#define STV090x_P2_VITSCALE			STV090x_Px_VITSCALE(2)
-#define STV090x_OFFST_Px_NVTH_NOSRANGE_FIELD	7
-#define STV090x_WIDTH_Px_NVTH_NOSRANGE_FIELD	1
-#define STV090x_OFFST_Px_VERROR_MAXMODE_FIELD	6
-#define STV090x_WIDTH_Px_VERROR_MAXMODE_FIELD	1
-#define STV090x_OFFST_Px_NSLOWSN_LOCKED_FIELD	3
-#define STV090x_WIDTH_Px_NSLOWSN_LOCKED_FIELD	1
-#define STV090x_OFFST_Px_DIS_RSFLOCK_FIELD	1
-#define STV090x_WIDTH_Px_DIS_RSFLOCK_FIELD	1
-
-#define STV090x_Px_FECM(__x)			(0xf533 - (__x - 1) * 0x200)
-#define STV090x_P1_FECM				STV090x_Px_FECM(1)
-#define STV090x_P2_FECM				STV090x_Px_FECM(2)
-#define STV090x_OFFST_Px_DSS_DVB_FIELD		7
-#define STV090x_WIDTH_Px_DSS_DVB_FIELD		1
-#define STV090x_OFFST_Px_DSS_SRCH_FIELD		4
-#define STV090x_WIDTH_Px_DSS_SRCH_FIELD		1
-#define STV090x_OFFST_Px_SYNCVIT_FIELD		1
-#define STV090x_WIDTH_Px_SYNCVIT_FIELD		1
-#define STV090x_OFFST_Px_IQINV_FIELD		0
-#define STV090x_WIDTH_Px_IQINV_FIELD		1
-
-#define STV090x_Px_VTH12(__x)			(0xf534 - (__x - 1) * 0x200)
-#define STV090x_P1_VTH12			STV090x_Px_VTH12(1)
-#define STV090x_P2_VTH12			STV090x_Px_VTH12(2)
-#define STV090x_OFFST_Px_VTH12_FIELD		0
-#define STV090x_WIDTH_Px_VTH12_FIELD		8
-
-#define STV090x_Px_VTH23(__x)			(0xf535 - (__x - 1) * 0x200)
-#define STV090x_P1_VTH23			STV090x_Px_VTH23(1)
-#define STV090x_P2_VTH23			STV090x_Px_VTH23(2)
-#define STV090x_OFFST_Px_VTH23_FIELD		0
-#define STV090x_WIDTH_Px_VTH23_FIELD		8
-
-#define STV090x_Px_VTH34(__x)			(0xf536 - (__x - 1) * 0x200)
-#define STV090x_P1_VTH34			STV090x_Px_VTH34(1)
-#define STV090x_P2_VTH34			STV090x_Px_VTH34(2)
-#define STV090x_OFFST_Px_VTH34_FIELD		0
-#define STV090x_WIDTH_Px_VTH34_FIELD		8
-
-#define STV090x_Px_VTH56(__x)			(0xf537 - (__x - 1) * 0x200)
-#define STV090x_P1_VTH56			STV090x_Px_VTH56(1)
-#define STV090x_P2_VTH56			STV090x_Px_VTH56(2)
-#define STV090x_OFFST_Px_VTH56_FIELD		0
-#define STV090x_WIDTH_Px_VTH56_FIELD		8
-
-#define STV090x_Px_VTH67(__x)			(0xf538 - (__x - 1) * 0x200)
-#define STV090x_P1_VTH67			STV090x_Px_VTH67(1)
-#define STV090x_P2_VTH67			STV090x_Px_VTH67(2)
-#define STV090x_OFFST_Px_VTH67_FIELD		0
-#define STV090x_WIDTH_Px_VTH67_FIELD		8
-
-#define STV090x_Px_VTH78(__x)			(0xf539 - (__x - 1) * 0x200)
-#define STV090x_P1_VTH78			STV090x_Px_VTH78(1)
-#define STV090x_P2_VTH78			STV090x_Px_VTH78(2)
-#define STV090x_OFFST_Px_VTH78_FIELD		0
-#define STV090x_WIDTH_Px_VTH78_FIELD		8
-
-#define STV090x_Px_VITCURPUN(__x)		(0xf53a - (__x - 1) * 0x200)
-#define STV090x_P1_VITCURPUN			STV090x_Px_VITCURPUN(1)
-#define STV090x_P2_VITCURPUN			STV090x_Px_VITCURPUN(2)
-#define STV090x_OFFST_Px_VIT_CURPUN_FIELD	0
-#define STV090x_WIDTH_Px_VIT_CURPUN_FIELD	5
-
-#define STV090x_Px_VERROR(__x)			(0xf53b - (__x - 1) * 0x200)
-#define STV090x_P1_VERROR			STV090x_Px_VERROR(1)
-#define STV090x_P2_VERROR			STV090x_Px_VERROR(2)
-#define STV090x_OFFST_Px_REGERR_VIT_FIELD	0
-#define STV090x_WIDTH_Px_REGERR_VIT_FIELD	8
-
-#define STV090x_Px_PRVIT(__x)			(0xf53c - (__x - 1) * 0x200)
-#define STV090x_P1_PRVIT			STV090x_Px_PRVIT(1)
-#define STV090x_P2_PRVIT			STV090x_Px_PRVIT(2)
-#define STV090x_OFFST_Px_DIS_VTHLOCK_FIELD	6
-#define STV090x_WIDTH_Px_DIS_VTHLOCK_FIELD	1
-#define STV090x_OFFST_Px_E7_8VIT_FIELD		5
-#define STV090x_WIDTH_Px_E7_8VIT_FIELD		1
-#define STV090x_OFFST_Px_E6_7VIT_FIELD		4
-#define STV090x_WIDTH_Px_E6_7VIT_FIELD		1
-#define STV090x_OFFST_Px_E5_6VIT_FIELD		3
-#define STV090x_WIDTH_Px_E5_6VIT_FIELD		1
-#define STV090x_OFFST_Px_E3_4VIT_FIELD		2
-#define STV090x_WIDTH_Px_E3_4VIT_FIELD		1
-#define STV090x_OFFST_Px_E2_3VIT_FIELD		1
-#define STV090x_WIDTH_Px_E2_3VIT_FIELD		1
-#define STV090x_OFFST_Px_E1_2VIT_FIELD		0
-#define STV090x_WIDTH_Px_E1_2VIT_FIELD		1
-
-#define STV090x_Px_VAVSRVIT(__x)		(0xf53d - (__x - 1) * 0x200)
-#define STV090x_P1_VAVSRVIT			STV090x_Px_VAVSRVIT(1)
-#define STV090x_P2_VAVSRVIT			STV090x_Px_VAVSRVIT(2)
-#define STV090x_OFFST_Px_SNVIT_FIELD		4
-#define STV090x_WIDTH_Px_SNVIT_FIELD		2
-#define STV090x_OFFST_Px_TOVVIT_FIELD		2
-#define STV090x_WIDTH_Px_TOVVIT_FIELD		2
-#define STV090x_OFFST_Px_HYPVIT_FIELD		0
-#define STV090x_WIDTH_Px_HYPVIT_FIELD		2
-
-#define STV090x_Px_VSTATUSVIT(__x)		(0xf53e - (__x - 1) * 0x200)
-#define STV090x_P1_VSTATUSVIT			STV090x_Px_VSTATUSVIT(1)
-#define STV090x_P2_VSTATUSVIT			STV090x_Px_VSTATUSVIT(2)
-#define STV090x_OFFST_Px_PRFVIT_FIELD		4
-#define STV090x_WIDTH_Px_PRFVIT_FIELD		1
-#define STV090x_OFFST_Px_LOCKEDVIT_FIELD	3
-#define STV090x_WIDTH_Px_LOCKEDVIT_FIELD	1
-
-#define STV090x_Px_VTHINUSE(__x)		(0xf53f - (__x - 1) * 0x200)
-#define STV090x_P1_VTHINUSE			STV090x_Px_VTHINUSE(1)
-#define STV090x_P2_VTHINUSE			STV090x_Px_VTHINUSE(2)
-#define STV090x_OFFST_Px_VIT_INUSE_FIELD	0
-#define STV090x_WIDTH_Px_VIT_INUSE_FIELD	8
-
-#define STV090x_Px_KDIV12(__x)			(0xf540 - (__x - 1) * 0x200)
-#define STV090x_P1_KDIV12			STV090x_Px_KDIV12(1)
-#define STV090x_P2_KDIV12			STV090x_Px_KDIV12(2)
-#define STV090x_OFFST_Px_K_DIVIDER_12_FIELD	0
-#define STV090x_WIDTH_Px_K_DIVIDER_12_FIELD	7
-
-#define STV090x_Px_KDIV23(__x)			(0xf541 - (__x - 1) * 0x200)
-#define STV090x_P1_KDIV23			STV090x_Px_KDIV23(1)
-#define STV090x_P2_KDIV23			STV090x_Px_KDIV23(2)
-#define STV090x_OFFST_Px_K_DIVIDER_23_FIELD	0
-#define STV090x_WIDTH_Px_K_DIVIDER_23_FIELD	7
-
-#define STV090x_Px_KDIV34(__x)			(0xf542 - (__x - 1) * 0x200)
-#define STV090x_P1_KDIV34			STV090x_Px_KDIV34(1)
-#define STV090x_P2_KDIV34			STV090x_Px_KDIV34(2)
-#define STV090x_OFFST_Px_K_DIVIDER_34_FIELD	0
-#define STV090x_WIDTH_Px_K_DIVIDER_34_FIELD	7
-
-#define STV090x_Px_KDIV56(__x)			(0xf543 - (__x - 1) * 0x200)
-#define STV090x_P1_KDIV56			STV090x_Px_KDIV56(1)
-#define STV090x_P2_KDIV56			STV090x_Px_KDIV56(2)
-#define STV090x_OFFST_Px_K_DIVIDER_56_FIELD	0
-#define STV090x_WIDTH_Px_K_DIVIDER_56_FIELD	7
-
-#define STV090x_Px_KDIV67(__x)			(0xf544 - (__x - 1) * 0x200)
-#define STV090x_P1_KDIV67			STV090x_Px_KDIV67(1)
-#define STV090x_P2_KDIV67			STV090x_Px_KDIV67(2)
-#define STV090x_OFFST_Px_K_DIVIDER_67_FIELD	0
-#define STV090x_WIDTH_Px_K_DIVIDER_67_FIELD	7
-
-#define STV090x_Px_KDIV78(__x)			(0xf545 - (__x - 1) * 0x200)
-#define STV090x_P1_KDIV78			STV090x_Px_KDIV78(1)
-#define STV090x_P2_KDIV78			STV090x_Px_KDIV78(2)
-#define STV090x_OFFST_Px_K_DIVIDER_78_FIELD	0
-#define STV090x_WIDTH_Px_K_DIVIDER_78_FIELD	7
-
-#define STV090x_Px_PDELCTRL1(__x)		(0xf550 - (__x - 1) * 0x200)
-#define STV090x_P1_PDELCTRL1			STV090x_Px_PDELCTRL1(1)
-#define STV090x_P2_PDELCTRL1			STV090x_Px_PDELCTRL1(2)
-#define STV090x_OFFST_Px_INV_MISMASK_FIELD	7
-#define STV090x_WIDTH_Px_INV_MISMASK_FIELD	1
-#define STV090x_OFFST_Px_FILTER_EN_FIELD	5
-#define STV090x_WIDTH_Px_FILTER_EN_FIELD	1
-#define STV090x_OFFST_Px_EN_MIS00_FIELD		1
-#define STV090x_WIDTH_Px_EN_MIS00_FIELD		1
-#define STV090x_OFFST_Px_ALGOSWRST_FIELD	0
-#define STV090x_WIDTH_Px_ALGOSWRST_FIELD	1
-
-#define STV090x_Px_PDELCTRL2(__x)		(0xf551 - (__x - 1) * 0x200)
-#define STV090x_P1_PDELCTRL2			STV090x_Px_PDELCTRL2(1)
-#define STV090x_P2_PDELCTRL2			STV090x_Px_PDELCTRL2(2)
-#define STV090x_OFFST_Px_FORCE_CONTINUOUS	7
-#define STV090x_WIDTH_Px_FORCE_CONTINUOUS	1
-#define STV090x_OFFST_Px_RESET_UPKO_COUNT	6
-#define STV090x_WIDTH_Px_RESET_UPKO_COUNT	1
-#define STV090x_OFFST_Px_USER_PKTDELIN_NB	5
-#define STV090x_WIDTH_Px_USER_PKTDELIN_NB	1
-#define STV090x_OFFST_Px_FORCE_LOCKED		4
-#define STV090x_WIDTH_Px_FORCE_LOCKED		1
-#define STV090x_OFFST_Px_DATA_UNBBSCRAM		3
-#define STV090x_WIDTH_Px_DATA_UNBBSCRAM		1
-#define STV090x_OFFST_Px_FORCE_LONGPACKET	2
-#define STV090x_WIDTH_Px_FORCE_LONGPACKET	1
-#define STV090x_OFFST_Px_FRAME_MODE_FIELD	1
-#define STV090x_WIDTH_Px_FRAME_MODE_FIELD	1
-
-#define STV090x_Px_HYSTTHRESH(__x)		(0xf554 - (__x - 1) * 0x200)
-#define STV090x_P1_HYSTTHRESH			STV090x_Px_HYSTTHRESH(1)
-#define STV090x_P2_HYSTTHRESH			STV090x_Px_HYSTTHRESH(2)
-#define STV090x_OFFST_Px_UNLCK_THRESH_FIELD	4
-#define STV090x_WIDTH_Px_UNLCK_THRESH_FIELD	4
-#define STV090x_OFFST_Px_DELIN_LCK_THRESH_FIELD	0
-#define STV090x_WIDTH_Px_DELIN_LCK_THRESH_FIELD	4
-
-#define STV090x_Px_ISIENTRY(__x)		(0xf55e - (__x - 1) * 0x200)
-#define STV090x_P1_ISIENTRY			STV090x_Px_ISIENTRY(1)
-#define STV090x_P2_ISIENTRY			STV090x_Px_ISIENTRY(2)
-#define STV090x_OFFST_Px_ISI_ENTRY_FIELD	0
-#define STV090x_WIDTH_Px_ISI_ENTRY_FIELD	8
-
-#define STV090x_Px_ISIBITENA(__x)		(0xf55f - (__x - 1) * 0x200)
-#define STV090x_P1_ISIBITENA			STV090x_Px_ISIBITENA(1)
-#define STV090x_P2_ISIBITENA			STV090x_Px_ISIBITENA(2)
-#define STV090x_OFFST_Px_ISI_BIT_EN_FIELD	0
-#define STV090x_WIDTH_Px_ISI_BIT_EN_FIELD	8
-
-#define STV090x_Px_MATSTRy(__x, __y)		(0xf561 - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_MATSTR0			STV090x_Px_MATSTRy(1, 0)
-#define STV090x_P1_MATSTR1			STV090x_Px_MATSTRy(1, 1)
-#define STV090x_P2_MATSTR0			STV090x_Px_MATSTRy(2, 0)
-#define STV090x_P2_MATSTR1			STV090x_Px_MATSTRy(2, 1)
-#define STV090x_OFFST_Px_MATYPE_CURRENT_FIELD	0
-#define STV090x_WIDTH_Px_MATYPE_CURRENT_FIELD	8
-
-#define STV090x_Px_UPLSTRy(__x, __y)		(0xf563 - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_UPLSTR0			STV090x_Px_UPLSTRy(1, 0)
-#define STV090x_P1_UPLSTR1			STV090x_Px_UPLSTRy(1, 1)
-#define STV090x_P2_UPLSTR0			STV090x_Px_UPLSTRy(2, 0)
-#define STV090x_P2_UPLSTR1			STV090x_Px_UPLSTRy(2, 1)
-#define STV090x_OFFST_Px_UPL_CURRENT_FIELD	0
-#define STV090x_WIDTH_Px_UPL_CURRENT_FIELD	8
-
-#define STV090x_Px_DFLSTRy(__x, __y)		(0xf565 - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_DFLSTR0			STV090x_Px_DFLSTRy(1, 0)
-#define STV090x_P1_DFLSTR1			STV090x_Px_DFLSTRy(1, 1)
-#define STV090x_P2_DFLSTR0			STV090x_Px_DFLSTRy(2, 0)
-#define STV090x_P2_DFLSTR1			STV090x_Px_DFLSTRy(2, 1)
-#define STV090x_OFFST_Px_DFL_CURRENT_FIELD	0
-#define STV090x_WIDTH_Px_DFL_CURRENT_FIELD	8
-
-#define STV090x_Px_SYNCSTR(__x)			(0xf566 - (__x - 1) * 0x200)
-#define STV090x_P1_SYNCSTR			STV090x_Px_SYNCSTR(1)
-#define STV090x_P2_SYNCSTR			STV090x_Px_SYNCSTR(2)
-#define STV090x_OFFST_Px_SYNC_CURRENT_FIELD	0
-#define STV090x_WIDTH_Px_SYNC_CURRENT_FIELD	8
-
-#define STV090x_Px_SYNCDSTRy(__x, __y)		(0xf568 - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_SYNCDSTR0			STV090x_Px_SYNCDSTRy(1, 0)
-#define STV090x_P1_SYNCDSTR1			STV090x_Px_SYNCDSTRy(1, 1)
-#define STV090x_P2_SYNCDSTR0			STV090x_Px_SYNCDSTRy(2, 0)
-#define STV090x_P2_SYNCDSTR1			STV090x_Px_SYNCDSTRy(2, 1)
-#define STV090x_OFFST_Px_SYNCD_CURRENT_FIELD	0
-#define STV090x_WIDTH_Px_SYNCD_CURRENT_FIELD	8
-
-#define STV090x_Px_PDELSTATUS1(__x)		(0xf569 - (__x - 1) * 0x200)
-#define STV090x_P1_PDELSTATUS1			STV090x_Px_PDELSTATUS1(1)
-#define STV090x_P2_PDELSTATUS1			STV090x_Px_PDELSTATUS1(2)
-#define STV090x_OFFST_Px_PKTDELIN_LOCK_FIELD	1
-#define STV090x_WIDTH_Px_PKTDELIN_LOCK_FIELD	1
-#define STV090x_OFFST_Px_FIRST_LOCK_FIELD	0
-#define STV090x_WIDTH_Px_FIRST_LOCK_FIELD	1
-
-#define STV090x_Px_PDELSTATUS2(__x)		(0xf56a - (__x - 1) * 0x200)
-#define STV090x_P1_PDELSTATUS2			STV090x_Px_PDELSTATUS2(1)
-#define STV090x_P2_PDELSTATUS2			STV090x_Px_PDELSTATUS2(2)
-#define STV090x_OFFST_Px_FRAME_MODCOD_FIELD	2
-#define STV090x_WIDTH_Px_FRAME_MODCOD_FIELD	5
-#define STV090x_OFFST_Px_FRAME_TYPE_FIELD	0
-#define STV090x_WIDTH_Px_FRAME_TYPE_FIELD	2
-
-#define STV090x_Px_BBFCRCKO1(__x)		(0xf56b - (__x - 1) * 0x200)
-#define STV090x_P1_BBFCRCKO1			STV090x_Px_BBFCRCKO1(1)
-#define STV090x_P2_BBFCRCKO1			STV090x_Px_BBFCRCKO1(2)
-#define STV090x_OFFST_Px_BBHCRC_KOCNT_FIELD	0
-#define STV090x_WIDTH_Px_BBHCRC_KOCNT_FIELD	8
-
-#define STV090x_Px_BBFCRCKO0(__x)		(0xf56c - (__x - 1) * 0x200)
-#define STV090x_P1_BBFCRCKO0			STV090x_Px_BBFCRCKO0(1)
-#define STV090x_P2_BBFCRCKO0			STV090x_Px_BBFCRCKO0(2)
-#define STV090x_OFFST_Px_BBHCRC_KOCNT_FIELD	0
-#define STV090x_WIDTH_Px_BBHCRC_KOCNT_FIELD	8
-
-#define STV090x_Px_UPCRCKO1(__x)		(0xf56d - (__x - 1) * 0x200)
-#define STV090x_P1_UPCRCKO1			STV090x_Px_UPCRCKO1(1)
-#define STV090x_P2_UPCRCKO1			STV090x_Px_UPCRCKO1(2)
-#define STV090x_OFFST_Px_PKTCRC_KOCNT_FIELD	0
-#define STV090x_WIDTH_Px_PKTCRC_KOCNT_FIELD	8
-
-#define STV090x_Px_UPCRCKO0(__x)		(0xf56e - (__x - 1) * 0x200)
-#define STV090x_P1_UPCRCKO0			STV090x_Px_UPCRCKO0(1)
-#define STV090x_P2_UPCRCKO0			STV090x_Px_UPCRCKO0(2)
-#define STV090x_OFFST_Px_PKTCRC_KOCNT_FIELD	0
-#define STV090x_WIDTH_Px_PKTCRC_KOCNT_FIELD	8
-
-#define STV090x_NBITER_NFx(__x)				(0xFA03 + (__x - 4) * 0x1)
-#define STV090x_NBITER_NF4				STV090x_NBITER_NFx(4)
-#define STV090x_NBITER_NF5				STV090x_NBITER_NFx(5)
-#define STV090x_NBITER_NF6				STV090x_NBITER_NFx(6)
-#define STV090x_NBITER_NF7				STV090x_NBITER_NFx(7)
-#define STV090x_NBITER_NF8				STV090x_NBITER_NFx(8)
-#define STV090x_NBITER_NF9				STV090x_NBITER_NFx(9)
-#define STV090x_NBITER_NF10				STV090x_NBITER_NFx(10)
-#define STV090x_NBITER_NF11				STV090x_NBITER_NFx(11)
-#define STV090x_NBITER_NF12				STV090x_NBITER_NFx(12)
-#define STV090x_NBITER_NF13				STV090x_NBITER_NFx(13)
-#define STV090x_NBITER_NF14				STV090x_NBITER_NFx(14)
-#define STV090x_NBITER_NF15				STV090x_NBITER_NFx(15)
-#define STV090x_NBITER_NF16				STV090x_NBITER_NFx(16)
-#define STV090x_NBITER_NF17				STV090x_NBITER_NFx(17)
-
-#define STV090x_NBITERNOERR				0xFA3F
-#define STV090x_OFFST_NBITER_STOP_CRIT_FIELD		0
-#define STV090x_WIDTH_NBITER_STOP_CRIT_FIELD		4
-
-#define STV090x_GAINLLR_NFx(__x)			(0xFA43 + (__x - 4) * 0x1)
-#define STV090x_GAINLLR_NF4				STV090x_GAINLLR_NFx(4)
-#define STV090x_OFFST_GAINLLR_NF_QP_1_2_FIELD		0
-#define STV090x_WIDTH_GAINLLR_NF_QP_1_2_FIELD		7
-
-#define STV090x_GAINLLR_NF5				STV090x_GAINLLR_NFx(5)
-#define STV090x_OFFST_GAINLLR_NF_QP_3_5_FIELD		0
-#define STV090x_WIDTH_GAINLLR_NF_QP_3_5_FIELD		7
-
-#define STV090x_GAINLLR_NF6				STV090x_GAINLLR_NFx(6)
-#define STV090x_OFFST_GAINLLR_NF_QP_2_3_FIELD		0
-#define STV090x_WIDTH_GAINLLR_NF_QP_2_3_FIELD		7
-
-#define STV090x_GAINLLR_NF7				STV090x_GAINLLR_NFx(7)
-#define STV090x_OFFST_GAINLLR_NF_QP_3_4_FIELD		0
-#define STV090x_WIDTH_GAINLLR_NF_QP_3_4_FIELD		7
-
-#define STV090x_GAINLLR_NF8				STV090x_GAINLLR_NFx(8)
-#define STV090x_OFFST_GAINLLR_NF_QP_4_5_FIELD		0
-#define STV090x_WIDTH_GAINLLR_NF_QP_4_5_FIELD		7
-
-#define STV090x_GAINLLR_NF9				STV090x_GAINLLR_NFx(9)
-#define STV090x_OFFST_GAINLLR_NF_QP_5_6_FIELD		0
-#define STV090x_WIDTH_GAINLLR_NF_QP_5_6_FIELD		7
-
-#define STV090x_GAINLLR_NF10				STV090x_GAINLLR_NFx(10)
-#define STV090x_OFFST_GAINLLR_NF_QP_8_9_FIELD		0
-#define STV090x_WIDTH_GAINLLR_NF_QP_8_9_FIELD		7
-
-#define STV090x_GAINLLR_NF11				STV090x_GAINLLR_NFx(11)
-#define STV090x_OFFST_GAINLLR_NF_QP_9_10_FIELD		0
-#define STV090x_WIDTH_GAINLLR_NF_QP_9_10_FIELD		7
-
-#define STV090x_GAINLLR_NF12				STV090x_GAINLLR_NFx(12)
-#define STV090x_OFFST_GAINLLR_NF_8P_3_5_FIELD		0
-#define STV090x_WIDTH_GAINLLR_NF_8P_3_5_FIELD		7
-
-#define STV090x_GAINLLR_NF13				STV090x_GAINLLR_NFx(13)
-#define STV090x_OFFST_GAINLLR_NF_8P_2_3_FIELD		0
-#define STV090x_WIDTH_GAINLLR_NF_8P_2_3_FIELD		7
-
-#define STV090x_GAINLLR_NF14				STV090x_GAINLLR_NFx(14)
-#define STV090x_OFFST_GAINLLR_NF_8P_3_4_FIELD		0
-#define STV090x_WIDTH_GAINLLR_NF_8P_3_4_FIELD		7
-
-#define STV090x_GAINLLR_NF15				STV090x_GAINLLR_NFx(15)
-#define STV090x_OFFST_GAINLLR_NF_8P_5_6_FIELD		0
-#define STV090x_WIDTH_GAINLLR_NF_8P_5_6_FIELD		7
-
-#define STV090x_GAINLLR_NF16				STV090x_GAINLLR_NFx(16)
-#define STV090x_OFFST_GAINLLR_NF_8P_8_9_FIELD		0
-#define STV090x_WIDTH_GAINLLR_NF_8P_8_9_FIELD		7
-
-#define STV090x_GAINLLR_NF17				STV090x_GAINLLR_NFx(17)
-#define STV090x_OFFST_GAINLLR_NF_8P_9_10_FIELD		0
-#define STV090x_WIDTH_GAINLLR_NF_8P_9_10_FIELD		7
-
-#define STV090x_GENCFG					0xFA86
-#define STV090x_OFFST_BROADCAST_FIELD			4
-#define STV090x_WIDTH_BROADCAST_FIELD			1
-#define STV090x_OFFST_PRIORITY_FIELD			1
-#define STV090x_WIDTH_PRIORITY_FIELD			1
-#define STV090x_OFFST_DDEMOD_FIELD			0
-#define STV090x_WIDTH_DDEMOD_FIELD			1
-
-#define STV090x_LDPCERRx(__x)				(0xFA97 - (__x  * 0x1))
-#define STV090x_LDPCERR0				STV090x_LDPCERRx(0)
-#define STV090x_LDPCERR1				STV090x_LDPCERRx(1)
-#define STV090x_OFFST_Px_LDPC_ERRORS_COUNTER_FIELD	0
-#define STV090x_WIDTH_Px_LDPC_ERRORS_COUNTER_FIELD	8
-
-#define STV090x_BCHERR					0xFA98
-#define STV090x_OFFST_Px_ERRORFLAG_FIELD		4
-#define STV090x_WIDTH_Px_ERRORFLAG_FIELD		1
-#define STV090x_OFFST_Px_BCH_ERRORS_COUNTER_FIELD	0
-#define STV090x_WIDTH_Px_BCH_ERRORS_COUNTER_FIELD	4
-
-#define STV090x_Px_TSSTATEM(__x)			(0xF570 - (__x - 1) * 0x200)
-#define STV090x_P1_TSSTATEM				STV090x_Px_TSSTATEM(1)
-#define STV090x_P2_TSSTATEM				STV090x_Px_TSSTATEM(2)
-#define STV090x_OFFST_Px_TSDIL_ON_FIELD			7
-#define STV090x_WIDTH_Px_TSDIL_ON_FIELD			1
-#define STV090x_OFFST_Px_TSRS_ON_FIELD			5
-#define STV090x_WIDTH_Px_TSRS_ON_FIELD			1
-
-#define STV090x_Px_TSCFGH(__x)				(0xF572 - (__x - 1) * 0x200)
-#define STV090x_P1_TSCFGH				STV090x_Px_TSCFGH(1)
-#define STV090x_P2_TSCFGH				STV090x_Px_TSCFGH(2)
-#define STV090x_OFFST_Px_TSFIFO_DVBCI_FIELD		7
-#define STV090x_WIDTH_Px_TSFIFO_DVBCI_FIELD		1
-#define STV090x_OFFST_Px_TSFIFO_SERIAL_FIELD		6
-#define STV090x_WIDTH_Px_TSFIFO_SERIAL_FIELD		1
-#define STV090x_OFFST_Px_TSFIFO_TEIUPDATE_FIELD		5
-#define STV090x_WIDTH_Px_TSFIFO_TEIUPDATE_FIELD		1
-#define STV090x_OFFST_Px_TSFIFO_DUTY50_FIELD		4
-#define STV090x_WIDTH_Px_TSFIFO_DUTY50_FIELD		1
-#define STV090x_OFFST_Px_TSFIFO_HSGNLOUT_FIELD		3
-#define STV090x_WIDTH_Px_TSFIFO_HSGNLOUT_FIELD		1
-#define STV090x_OFFST_Px_TSFIFO_ERRORMODE_FIELD		1
-#define STV090x_WIDTH_Px_TSFIFO_ERRORMODE_FIELD		2
-#define STV090x_OFFST_Px_RST_HWARE_FIELD		0
-#define STV090x_WIDTH_Px_RST_HWARE_FIELD		1
-
-#define STV090x_Px_TSCFGM(__x)				(0xF573 - (__x - 1) * 0x200)
-#define STV090x_P1_TSCFGM				STV090x_Px_TSCFGM(1)
-#define STV090x_P2_TSCFGM				STV090x_Px_TSCFGM(2)
-#define STV090x_OFFST_Px_TSFIFO_MANSPEED_FIELD		6
-#define STV090x_WIDTH_Px_TSFIFO_MANSPEED_FIELD		2
-#define STV090x_OFFST_Px_TSFIFO_PERMDATA_FIELD		5
-#define STV090x_WIDTH_Px_TSFIFO_PERMDATA_FIELD		1
-#define STV090x_OFFST_Px_TSFIFO_INVDATA_FIELD		0
-#define STV090x_WIDTH_Px_TSFIFO_INVDATA_FIELD		1
-
-#define STV090x_Px_TSCFGL(__x)				(0xF574 - (__x - 1) * 0x200)
-#define STV090x_P1_TSCFGL				STV090x_Px_TSCFGL(1)
-#define STV090x_P2_TSCFGL				STV090x_Px_TSCFGL(2)
-#define STV090x_OFFST_Px_TSFIFO_BCLKDEL1CK_FIELD	6
-#define STV090x_WIDTH_Px_TSFIFO_BCLKDEL1CK_FIELD	2
-#define STV090x_OFFST_Px_BCHERROR_MODE_FIELD		4
-#define STV090x_WIDTH_Px_BCHERROR_MODE_FIELD		2
-#define STV090x_OFFST_Px_TSFIFO_NSGNL2DATA_FIELD	3
-#define STV090x_WIDTH_Px_TSFIFO_NSGNL2DATA_FIELD	1
-#define STV090x_OFFST_Px_TSFIFO_EMBINDVB_FIELD		2
-#define STV090x_WIDTH_Px_TSFIFO_EMBINDVB_FIELD		1
-#define STV090x_OFFST_Px_TSFIFO_DPUNACT_FIELD		1
-#define STV090x_WIDTH_Px_TSFIFO_DPUNACT_FIELD		1
-
-#define STV090x_Px_TSINSDELH(__x)			(0xF576 - (__x - 1) * 0x200)
-#define STV090x_P1_TSINSDELH				STV090x_Px_TSINSDELH(1)
-#define STV090x_P2_TSINSDELH				STV090x_Px_TSINSDELH(2)
-#define STV090x_OFFST_Px_TSDEL_SYNCBYTE_FIELD		7
-#define STV090x_WIDTH_Px_TSDEL_SYNCBYTE_FIELD		1
-#define STV090x_OFFST_Px_TSDEL_XXHEADER_FIELD		6
-#define STV090x_WIDTH_Px_TSDEL_XXHEADER_FIELD		1
-
-#define STV090x_Px_TSSPEED(__x)				(0xF580 - (__x - 1) * 0x200)
-#define STV090x_P1_TSSPEED				STV090x_Px_TSSPEED(1)
-#define STV090x_P2_TSSPEED				STV090x_Px_TSSPEED(2)
-#define STV090x_OFFST_Px_TSFIFO_OUTSPEED_FIELD		0
-#define STV090x_WIDTH_Px_TSFIFO_OUTSPEED_FIELD		8
-
-#define STV090x_Px_TSSTATUS(__x)			(0xF581 - (__x - 1) * 0x200)
-#define STV090x_P1_TSSTATUS				STV090x_Px_TSSTATUS(1)
-#define STV090x_P2_TSSTATUS				STV090x_Px_TSSTATUS(2)
-#define STV090x_OFFST_Px_TSFIFO_LINEOK_FIELD		7
-#define STV090x_WIDTH_Px_TSFIFO_LINEOK_FIELD		1
-#define STV090x_OFFST_Px_TSFIFO_ERROR_FIELD		6
-#define STV090x_WIDTH_Px_TSFIFO_ERROR_FIELD		1
-
-#define STV090x_Px_TSSTATUS2(__x)			(0xF582 - (__x - 1) * 0x200)
-#define STV090x_P1_TSSTATUS2				STV090x_Px_TSSTATUS2(1)
-#define STV090x_P2_TSSTATUS2				STV090x_Px_TSSTATUS2(2)
-#define STV090x_OFFST_Px_TSFIFO_DEMODSEL_FIELD		7
-#define STV090x_WIDTH_Px_TSFIFO_DEMODSEL_FIELD		1
-#define STV090x_OFFST_Px_TSFIFOSPEED_STORE_FIELD	6
-#define STV090x_WIDTH_Px_TSFIFOSPEED_STORE_FIELD	1
-#define STV090x_OFFST_Px_DILXX_RESET_FIELD		5
-#define STV090x_WIDTH_Px_DILXX_RESET_FIELD		1
-#define STV090x_OFFST_Px_TSSERIAL_IMPOS_FIELD		4
-#define STV090x_WIDTH_Px_TSSERIAL_IMPOS_FIELD		1
-#define STV090x_OFFST_Px_SCRAMBDETECT_FIELD		1
-#define STV090x_WIDTH_Px_SCRAMBDETECT_FIELD		1
-
-#define STV090x_Px_TSBITRATEy(__x, __y)			(0xF584 - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_TSBITRATE0				STV090x_Px_TSBITRATEy(1, 0)
-#define STV090x_P1_TSBITRATE1				STV090x_Px_TSBITRATEy(1, 1)
-#define STV090x_P2_TSBITRATE0				STV090x_Px_TSBITRATEy(2, 0)
-#define STV090x_P2_TSBITRATE1				STV090x_Px_TSBITRATEy(2, 1)
-#define STV090x_OFFST_Px_TSFIFO_BITRATE_FIELD		0
-#define STV090x_WIDTH_Px_TSFIFO_BITRATE_FIELD		8
-
-#define STV090x_Px_ERRCTRL1(__x)			(0xF598 - (__x - 1) * 0x200)
-#define STV090x_P1_ERRCTRL1				STV090x_Px_ERRCTRL1(1)
-#define STV090x_P2_ERRCTRL1				STV090x_Px_ERRCTRL1(2)
-#define STV090x_OFFST_Px_ERR_SOURCE_FIELD		4
-#define STV090x_WIDTH_Px_ERR_SOURCE_FIELD		4
-#define STV090x_OFFST_Px_NUM_EVENT_FIELD		0
-#define STV090x_WIDTH_Px_NUM_EVENT_FIELD		3
-
-#define STV090x_Px_ERRCNT12(__x)			(0xF599 - (__x - 1) * 0x200)
-#define STV090x_P1_ERRCNT12				STV090x_Px_ERRCNT12(1)
-#define STV090x_P2_ERRCNT12				STV090x_Px_ERRCNT12(2)
-#define STV090x_OFFST_Px_ERRCNT1_OLDVALUE_FIELD		7
-#define STV090x_WIDTH_Px_ERRCNT1_OLDVALUE_FIELD		1
-#define STV090x_OFFST_Px_ERR_CNT12_FIELD		0
-#define STV090x_WIDTH_Px_ERR_CNT12_FIELD		7
-
-#define STV090x_Px_ERRCNT11(__x)			(0xF59A - (__x - 1) * 0x200)
-#define STV090x_P1_ERRCNT11				STV090x_Px_ERRCNT11(1)
-#define STV090x_P2_ERRCNT11				STV090x_Px_ERRCNT11(2)
-#define STV090x_OFFST_Px_ERR_CNT11_FIELD		0
-#define STV090x_WIDTH_Px_ERR_CNT11_FIELD		8
-
-#define STV090x_Px_ERRCNT10(__x)			(0xF59B - (__x - 1) * 0x200)
-#define STV090x_P1_ERRCNT10				STV090x_Px_ERRCNT10(1)
-#define STV090x_P2_ERRCNT10				STV090x_Px_ERRCNT10(2)
-#define STV090x_OFFST_Px_ERR_CNT10_FIELD		0
-#define STV090x_WIDTH_Px_ERR_CNT10_FIELD		8
-
-#define STV090x_Px_ERRCTRL2(__x)			(0xF59C - (__x - 1) * 0x200)
-#define STV090x_P1_ERRCTRL2				STV090x_Px_ERRCTRL2(1)
-#define STV090x_P2_ERRCTRL2				STV090x_Px_ERRCTRL2(2)
-#define STV090x_OFFST_Px_ERR_SOURCE2_FIELD		4
-#define STV090x_WIDTH_Px_ERR_SOURCE2_FIELD		4
-#define STV090x_OFFST_Px_NUM_EVENT2_FIELD		0
-#define STV090x_WIDTH_Px_NUM_EVENT2_FIELD		3
-
-#define STV090x_Px_ERRCNT22(__x)			(0xF59D - (__x - 1) * 0x200)
-#define STV090x_P1_ERRCNT22				STV090x_Px_ERRCNT22(1)
-#define STV090x_P2_ERRCNT22				STV090x_Px_ERRCNT22(2)
-#define STV090x_OFFST_Px_ERRCNT2_OLDVALUE_FIELD		7
-#define STV090x_WIDTH_Px_ERRCNT2_OLDVALUE_FIELD		1
-#define STV090x_OFFST_Px_ERR_CNT2_FIELD			0
-#define STV090x_WIDTH_Px_ERR_CNT2_FIELD			7
-
-#define STV090x_Px_ERRCNT21(__x)			(0xF59E - (__x - 1) * 0x200)
-#define STV090x_P1_ERRCNT21				STV090x_Px_ERRCNT21(1)
-#define STV090x_P2_ERRCNT21				STV090x_Px_ERRCNT21(2)
-#define STV090x_OFFST_Px_ERR_CNT21_FIELD		0
-#define STV090x_WIDTH_Px_ERR_CNT21_FIELD		8
-
-#define STV090x_Px_ERRCNT20(__x)			(0xF59F - (__x - 1) * 0x200)
-#define STV090x_P1_ERRCNT20				STV090x_Px_ERRCNT20(1)
-#define STV090x_P2_ERRCNT20				STV090x_Px_ERRCNT20(2)
-#define STV090x_OFFST_Px_ERR_CNT20_FIELD		0
-#define STV090x_WIDTH_Px_ERR_CNT20_FIELD		8
-
-#define STV090x_Px_FECSPY(__x)				(0xF5A0 - (__x - 1) * 0x200)
-#define STV090x_P1_FECSPY				STV090x_Px_FECSPY(1)
-#define STV090x_P2_FECSPY				STV090x_Px_FECSPY(2)
-#define STV090x_OFFST_Px_SPY_ENABLE_FIELD		7
-#define STV090x_WIDTH_Px_SPY_ENABLE_FIELD		1
-#define STV090x_OFFST_Px_BERMETER_DATAMAODE_FIELD	2
-#define STV090x_WIDTH_Px_BERMETER_DATAMAODE_FIELD	2
-
-#define STV090x_Px_FSPYCFG(__x)				(0xF5A1 - (__x - 1) * 0x200)
-#define STV090x_P1_FSPYCFG				STV090x_Px_FSPYCFG(1)
-#define STV090x_P2_FSPYCFG				STV090x_Px_FSPYCFG(2)
-#define STV090x_OFFST_Px_RST_ON_ERROR_FIELD		5
-#define STV090x_WIDTH_Px_RST_ON_ERROR_FIELD		1
-#define STV090x_OFFST_Px_ONE_SHOT_FIELD			4
-#define STV090x_WIDTH_Px_ONE_SHOT_FIELD			1
-#define STV090x_OFFST_Px_I2C_MODE_FIELD			2
-#define STV090x_WIDTH_Px_I2C_MODE_FIELD			2
-
-#define STV090x_Px_FSPYDATA(__x)			(0xF5A2 - (__x - 1) * 0x200)
-#define STV090x_P1_FSPYDATA				STV090x_Px_FSPYDATA(1)
-#define STV090x_P2_FSPYDATA				STV090x_Px_FSPYDATA(2)
-#define STV090x_OFFST_Px_SPY_STUFFING_FIELD		7
-#define STV090x_WIDTH_Px_SPY_STUFFING_FIELD		1
-#define STV090x_OFFST_Px_SPY_CNULLPKT_FIELD		5
-#define STV090x_WIDTH_Px_SPY_CNULLPKT_FIELD		1
-#define STV090x_OFFST_Px_SPY_OUTDATA_MODE_FIELD		0
-#define STV090x_WIDTH_Px_SPY_OUTDATA_MODE_FIELD		5
-
-#define STV090x_Px_FSPYOUT(__x)				(0xF5A3 - (__x - 1) * 0x200)
-#define STV090x_P1_FSPYOUT				STV090x_Px_FSPYOUT(1)
-#define STV090x_P2_FSPYOUT				STV090x_Px_FSPYOUT(2)
-#define STV090x_OFFST_Px_FSPY_DIRECT_FIELD		7
-#define STV090x_WIDTH_Px_FSPY_DIRECT_FIELD		1
-#define STV090x_OFFST_Px_STUFF_MODE_FIELD		0
-#define STV090x_WIDTH_Px_STUFF_MODE_FIELD		3
-
-#define STV090x_Px_FSTATUS(__x)				(0xF5A4 - (__x - 1) * 0x200)
-#define STV090x_P1_FSTATUS				STV090x_Px_FSTATUS(1)
-#define STV090x_P2_FSTATUS				STV090x_Px_FSTATUS(2)
-#define STV090x_OFFST_Px_SPY_ENDSIM_FIELD		7
-#define STV090x_WIDTH_Px_SPY_ENDSIM_FIELD		1
-#define STV090x_OFFST_Px_VALID_SIM_FIELD		6
-#define STV090x_WIDTH_Px_VALID_SIM_FIELD		1
-#define STV090x_OFFST_Px_FOUND_SIGNAL_FIELD		5
-#define STV090x_WIDTH_Px_FOUND_SIGNAL_FIELD		1
-#define STV090x_OFFST_Px_DSS_SYNCBYTE_FIELD		4
-#define STV090x_WIDTH_Px_DSS_SYNCBYTE_FIELD		1
-#define STV090x_OFFST_Px_RESULT_STATE_FIELD		0
-#define STV090x_WIDTH_Px_RESULT_STATE_FIELD		4
-
-#define STV090x_Px_FBERCPT4(__x)			(0xF5A8 - (__x - 1) * 0x200)
-#define STV090x_P1_FBERCPT4				STV090x_Px_FBERCPT4(1)
-#define STV090x_P2_FBERCPT4				STV090x_Px_FBERCPT4(2)
-#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD		0
-#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD		8
-
-#define STV090x_Px_FBERCPT3(__x)			(0xF5A9 - (__x - 1) * 0x200)
-#define STV090x_P1_FBERCPT3				STV090x_Px_FBERCPT3(1)
-#define STV090x_P2_FBERCPT3				STV090x_Px_FBERCPT3(2)
-#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD		0
-#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD		8
-
-#define STV090x_Px_FBERCPT2(__x)			(0xF5AA - (__x - 1) * 0x200)
-#define STV090x_P1_FBERCPT2				STV090x_Px_FBERCPT2(1)
-#define STV090x_P2_FBERCPT2				STV090x_Px_FBERCPT2(2)
-#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD		0
-#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD		8
-
-#define STV090x_Px_FBERCPT1(__x)			(0xF5AB - (__x - 1) * 0x200)
-#define STV090x_P1_FBERCPT1				STV090x_Px_FBERCPT1(1)
-#define STV090x_P2_FBERCPT1				STV090x_Px_FBERCPT1(2)
-#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD		0
-#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD		8
-
-#define STV090x_Px_FBERCPT0(__x)			(0xF5AC - (__x - 1) * 0x200)
-#define STV090x_P1_FBERCPT0				STV090x_Px_FBERCPT0(1)
-#define STV090x_P2_FBERCPT0				STV090x_Px_FBERCPT0(2)
-#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD		0
-#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD		8
-
-#define STV090x_Px_FBERERRy(__x, __y)			(0xF5AF - (__x - 1) * 0x200 - __y * 0x1)
-#define STV090x_P1_FBERERR0				STV090x_Px_FBERERRy(1, 0)
-#define STV090x_P1_FBERERR1				STV090x_Px_FBERERRy(1, 1)
-#define STV090x_P1_FBERERR2				STV090x_Px_FBERERRy(1, 2)
-#define STV090x_P2_FBERERR0				STV090x_Px_FBERERRy(2, 0)
-#define STV090x_P2_FBERERR1				STV090x_Px_FBERERRy(2, 1)
-#define STV090x_P2_FBERERR2				STV090x_Px_FBERERRy(2, 2)
-#define STV090x_OFFST_Px_FBERMETER_CPT_ERR_FIELD	0
-#define STV090x_WIDTH_Px_FBERMETER_CPT_ERR_FIELD	8
-
-#define STV090x_Px_FSPYBER(__x)				(0xF5B2 - (__x - 1) * 0x200)
-#define STV090x_P1_FSPYBER				STV090x_Px_FSPYBER(1)
-#define STV090x_P2_FSPYBER				STV090x_Px_FSPYBER(2)
-#define STV090x_OFFST_Px_FSPYBER_SYNCBYTE_FIELD		4
-#define STV090x_WIDTH_Px_FSPYBER_SYNCBYTE_FIELD		1
-#define STV090x_OFFST_Px_FSPYBER_UNSYNC_FIELD		3
-#define STV090x_WIDTH_Px_FSPYBER_UNSYNC_FIELD		1
-#define STV090x_OFFST_Px_FSPYBER_CTIME_FIELD		0
-#define STV090x_WIDTH_Px_FSPYBER_CTIME_FIELD		3
-
-#define STV090x_RCCFGH					0xf600
-
-#define STV090x_TSGENERAL				0xF630
-#define STV090x_OFFST_Px_MUXSTREAM_OUT_FIELD		3
-#define STV090x_WIDTH_Px_MUXSTREAM_OUT_FIELD		1
-#define STV090x_OFFST_Px_TSFIFO_PERMPARAL_FIELD		1
-#define STV090x_WIDTH_Px_TSFIFO_PERMPARAL_FIELD		2
-
-#define STV090x_TSGENERAL1X				0xf670
-#define STV090x_CFGEXT					0xfa80
-
-#define STV090x_TSTRES0					0xFF11
-#define STV090x_OFFST_FRESFEC_FIELD			7
-#define STV090x_WIDTH_FRESFEC_FIELD			1
-
-#define STV090x_Px_TSTDISRX(__x)			(0xFF67 - (__x - 1) * 0x2)
-#define STV090x_P1_TSTDISRX				STV090x_Px_TSTDISRX(1)
-#define STV090x_P2_TSTDISRX				STV090x_Px_TSTDISRX(2)
-#define STV090x_OFFST_Px_TSTDISRX_SELECT_FIELD		3
-#define STV090x_WIDTH_Px_TSTDISRX_SELECT_FIELD		1
-
-#endif /* __STV090x_REG_H */
diff --git a/drivers/media/dvb/frontends/stv6110.c b/drivers/media/dvb/frontends/stv6110.c
deleted file mode 100644
index 20b5fa9..0000000
--- a/drivers/media/dvb/frontends/stv6110.c
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * stv6110.c
- *
- * Driver for ST STV6110 satellite tuner IC.
- *
- * Copyright (C) 2009 NetUP Inc.
- * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/dvb/frontend.h>
-
-#include <linux/types.h>
-
-#include "stv6110.h"
-
-static int debug;
-
-struct stv6110_priv {
-	int i2c_address;
-	struct i2c_adapter *i2c;
-
-	u32 mclk;
-	u8 clk_div;
-	u8 gain;
-	u8 regs[8];
-};
-
-#define dprintk(args...) \
-	do { \
-		if (debug) \
-			printk(KERN_DEBUG args); \
-	} while (0)
-
-static s32 abssub(s32 a, s32 b)
-{
-	if (a > b)
-		return a - b;
-	else
-		return b - a;
-};
-
-static int stv6110_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static int stv6110_write_regs(struct dvb_frontend *fe, u8 buf[],
-							int start, int len)
-{
-	struct stv6110_priv *priv = fe->tuner_priv;
-	int rc;
-	u8 cmdbuf[len + 1];
-	struct i2c_msg msg = {
-		.addr	= priv->i2c_address,
-		.flags	= 0,
-		.buf	= cmdbuf,
-		.len	= len + 1
-	};
-
-	dprintk("%s\n", __func__);
-
-	if (start + len > 8)
-		return -EINVAL;
-
-	memcpy(&cmdbuf[1], buf, len);
-	cmdbuf[0] = start;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	rc = i2c_transfer(priv->i2c, &msg, 1);
-	if (rc != 1)
-		dprintk("%s: i2c error\n", __func__);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	return 0;
-}
-
-static int stv6110_read_regs(struct dvb_frontend *fe, u8 regs[],
-							int start, int len)
-{
-	struct stv6110_priv *priv = fe->tuner_priv;
-	int rc;
-	u8 reg[] = { start };
-	struct i2c_msg msg[] = {
-		{
-			.addr	= priv->i2c_address,
-			.flags	= 0,
-			.buf	= reg,
-			.len	= 1,
-		}, {
-			.addr	= priv->i2c_address,
-			.flags	= I2C_M_RD,
-			.buf	= regs,
-			.len	= len,
-		},
-	};
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	rc = i2c_transfer(priv->i2c, msg, 2);
-	if (rc != 2)
-		dprintk("%s: i2c error\n", __func__);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	memcpy(&priv->regs[start], regs, len);
-
-	return 0;
-}
-
-static int stv6110_read_reg(struct dvb_frontend *fe, int start)
-{
-	u8 buf[] = { 0 };
-	stv6110_read_regs(fe, buf, start, 1);
-
-	return buf[0];
-}
-
-static int stv6110_sleep(struct dvb_frontend *fe)
-{
-	u8 reg[] = { 0 };
-	stv6110_write_regs(fe, reg, 0, 1);
-
-	return 0;
-}
-
-static u32 carrier_width(u32 symbol_rate, fe_rolloff_t rolloff)
-{
-	u32 rlf;
-
-	switch (rolloff) {
-	case ROLLOFF_20:
-		rlf = 20;
-		break;
-	case ROLLOFF_25:
-		rlf = 25;
-		break;
-	default:
-		rlf = 35;
-		break;
-	}
-
-	return symbol_rate  + ((symbol_rate * rlf) / 100);
-}
-
-static int stv6110_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
-{
-	struct stv6110_priv *priv = fe->tuner_priv;
-	u8 r8, ret = 0x04;
-	int i;
-
-	if ((bandwidth / 2) > 36000000) /*BW/2 max=31+5=36 mhz for r8=31*/
-		r8 = 31;
-	else if ((bandwidth / 2) < 5000000) /* BW/2 min=5Mhz for F=0 */
-		r8 = 0;
-	else /*if 5 < BW/2 < 36*/
-		r8 = (bandwidth / 2) / 1000000 - 5;
-
-	/* ctrl3, RCCLKOFF = 0 Activate the calibration Clock */
-	/* ctrl3, CF = r8 Set the LPF value */
-	priv->regs[RSTV6110_CTRL3] &= ~((1 << 6) | 0x1f);
-	priv->regs[RSTV6110_CTRL3] |= (r8 & 0x1f);
-	stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL3], RSTV6110_CTRL3, 1);
-	/* stat1, CALRCSTRT = 1 Start LPF auto calibration*/
-	priv->regs[RSTV6110_STAT1] |= 0x02;
-	stv6110_write_regs(fe, &priv->regs[RSTV6110_STAT1], RSTV6110_STAT1, 1);
-
-	i = 0;
-	/* Wait for CALRCSTRT == 0 */
-	while ((i < 10) && (ret != 0)) {
-		ret = ((stv6110_read_reg(fe, RSTV6110_STAT1)) & 0x02);
-		mdelay(1);	/* wait for LPF auto calibration */
-		i++;
-	}
-
-	/* RCCLKOFF = 1 calibration done, desactivate the calibration Clock */
-	priv->regs[RSTV6110_CTRL3] |= (1 << 6);
-	stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL3], RSTV6110_CTRL3, 1);
-	return 0;
-}
-
-static int stv6110_init(struct dvb_frontend *fe)
-{
-	struct stv6110_priv *priv = fe->tuner_priv;
-	u8 buf0[] = { 0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e };
-
-	memcpy(priv->regs, buf0, 8);
-	/* K = (Reference / 1000000) - 16 */
-	priv->regs[RSTV6110_CTRL1] &= ~(0x1f << 3);
-	priv->regs[RSTV6110_CTRL1] |=
-				((((priv->mclk / 1000000) - 16) & 0x1f) << 3);
-
-	/* divisor value for the output clock */
-	priv->regs[RSTV6110_CTRL2] &= ~0xc0;
-	priv->regs[RSTV6110_CTRL2] |= (priv->clk_div << 6);
-
-	stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL1], RSTV6110_CTRL1, 8);
-	msleep(1);
-	stv6110_set_bandwidth(fe, 72000000);
-
-	return 0;
-}
-
-static int stv6110_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct stv6110_priv *priv = fe->tuner_priv;
-	u32 nbsteps, divider, psd2, freq;
-	u8 regs[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-
-	stv6110_read_regs(fe, regs, 0, 8);
-	/*N*/
-	divider = (priv->regs[RSTV6110_TUNING2] & 0x0f) << 8;
-	divider += priv->regs[RSTV6110_TUNING1];
-
-	/*R*/
-	nbsteps  = (priv->regs[RSTV6110_TUNING2] >> 6) & 3;
-	/*p*/
-	psd2  = (priv->regs[RSTV6110_TUNING2] >> 4) & 1;
-
-	freq = divider * (priv->mclk / 1000);
-	freq /= (1 << (nbsteps + psd2));
-	freq /= 4;
-
-	*frequency = freq;
-
-	return 0;
-}
-
-static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency)
-{
-	struct stv6110_priv *priv = fe->tuner_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u8 ret = 0x04;
-	u32 divider, ref, p, presc, i, result_freq, vco_freq;
-	s32 p_calc, p_calc_opt = 1000, r_div, r_div_opt = 0, p_val;
-	s32 srate;
-
-	dprintk("%s, freq=%d kHz, mclk=%d Hz\n", __func__,
-						frequency, priv->mclk);
-
-	/* K = (Reference / 1000000) - 16 */
-	priv->regs[RSTV6110_CTRL1] &= ~(0x1f << 3);
-	priv->regs[RSTV6110_CTRL1] |=
-				((((priv->mclk / 1000000) - 16) & 0x1f) << 3);
-
-	/* BB_GAIN = db/2 */
-	if (fe->ops.set_property && fe->ops.get_property) {
-		srate = c->symbol_rate;
-		dprintk("%s: Get Frontend parameters: srate=%d\n",
-							__func__, srate);
-	} else
-		srate = 15000000;
-
-	priv->regs[RSTV6110_CTRL2] &= ~0x0f;
-	priv->regs[RSTV6110_CTRL2] |= (priv->gain & 0x0f);
-
-	if (frequency <= 1023000) {
-		p = 1;
-		presc = 0;
-	} else if (frequency <= 1300000) {
-		p = 1;
-		presc = 1;
-	} else if (frequency <= 2046000) {
-		p = 0;
-		presc = 0;
-	} else {
-		p = 0;
-		presc = 1;
-	}
-	/* DIV4SEL = p*/
-	priv->regs[RSTV6110_TUNING2] &= ~(1 << 4);
-	priv->regs[RSTV6110_TUNING2] |= (p << 4);
-
-	/* PRESC32ON = presc */
-	priv->regs[RSTV6110_TUNING2] &= ~(1 << 5);
-	priv->regs[RSTV6110_TUNING2] |= (presc << 5);
-
-	p_val = (int)(1 << (p + 1)) * 10;/* P = 2 or P = 4 */
-	for (r_div = 0; r_div <= 3; r_div++) {
-		p_calc = (priv->mclk / 100000);
-		p_calc /= (1 << (r_div + 1));
-		if ((abssub(p_calc, p_val)) < (abssub(p_calc_opt, p_val)))
-			r_div_opt = r_div;
-
-		p_calc_opt = (priv->mclk / 100000);
-		p_calc_opt /= (1 << (r_div_opt + 1));
-	}
-
-	ref = priv->mclk / ((1 << (r_div_opt + 1))  * (1 << (p + 1)));
-	divider = (((frequency * 1000) + (ref >> 1)) / ref);
-
-	/* RDIV = r_div_opt */
-	priv->regs[RSTV6110_TUNING2] &= ~(3 << 6);
-	priv->regs[RSTV6110_TUNING2] |= (((r_div_opt) & 3) << 6);
-
-	/* NDIV_MSB = MSB(divider) */
-	priv->regs[RSTV6110_TUNING2] &= ~0x0f;
-	priv->regs[RSTV6110_TUNING2] |= (((divider) >> 8) & 0x0f);
-
-	/* NDIV_LSB, LSB(divider) */
-	priv->regs[RSTV6110_TUNING1] = (divider & 0xff);
-
-	/* CALVCOSTRT = 1 VCO Auto Calibration */
-	priv->regs[RSTV6110_STAT1] |= 0x04;
-	stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL1],
-						RSTV6110_CTRL1, 8);
-
-	i = 0;
-	/* Wait for CALVCOSTRT == 0 */
-	while ((i < 10) && (ret != 0)) {
-		ret = ((stv6110_read_reg(fe, RSTV6110_STAT1)) & 0x04);
-		msleep(1); /* wait for VCO auto calibration */
-		i++;
-	}
-
-	ret = stv6110_read_reg(fe, RSTV6110_STAT1);
-	stv6110_get_frequency(fe, &result_freq);
-
-	vco_freq = divider * ((priv->mclk / 1000) / ((1 << (r_div_opt + 1))));
-	dprintk("%s, stat1=%x, lo_freq=%d kHz, vco_frec=%d kHz\n", __func__,
-						ret, result_freq, vco_freq);
-
-	return 0;
-}
-
-static int stv6110_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 bandwidth = carrier_width(c->symbol_rate, c->rolloff);
-
-	stv6110_set_frequency(fe, c->frequency);
-	stv6110_set_bandwidth(fe, bandwidth);
-
-	return 0;
-}
-
-static int stv6110_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	struct stv6110_priv *priv = fe->tuner_priv;
-	u8 r8 = 0;
-	u8 regs[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-	stv6110_read_regs(fe, regs, 0, 8);
-
-	/* CF */
-	r8 = priv->regs[RSTV6110_CTRL3] & 0x1f;
-	*bandwidth = (r8 + 5) * 2000000;/* x2 for ZIF tuner BW/2 = F+5 Mhz */
-
-	return 0;
-}
-
-static struct dvb_tuner_ops stv6110_tuner_ops = {
-	.info = {
-		.name = "ST STV6110",
-		.frequency_min = 950000,
-		.frequency_max = 2150000,
-		.frequency_step = 1000,
-	},
-	.init = stv6110_init,
-	.release = stv6110_release,
-	.sleep = stv6110_sleep,
-	.set_params = stv6110_set_params,
-	.get_frequency = stv6110_get_frequency,
-	.set_frequency = stv6110_set_frequency,
-	.get_bandwidth = stv6110_get_bandwidth,
-	.set_bandwidth = stv6110_set_bandwidth,
-
-};
-
-struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
-					const struct stv6110_config *config,
-					struct i2c_adapter *i2c)
-{
-	struct stv6110_priv *priv = NULL;
-	u8 reg0[] = { 0x00, 0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e };
-
-	struct i2c_msg msg[] = {
-		{
-			.addr = config->i2c_address,
-			.flags = 0,
-			.buf = reg0,
-			.len = 9
-		}
-	};
-	int ret;
-
-	/* divisor value for the output clock */
-	reg0[2] &= ~0xc0;
-	reg0[2] |= (config->clk_div << 6);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	ret = i2c_transfer(i2c, msg, 1);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	if (ret != 1)
-		return NULL;
-
-	priv = kzalloc(sizeof(struct stv6110_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	priv->i2c_address = config->i2c_address;
-	priv->i2c = i2c;
-	priv->mclk = config->mclk;
-	priv->clk_div = config->clk_div;
-	priv->gain = config->gain;
-
-	memcpy(&priv->regs, &reg0[1], 8);
-
-	memcpy(&fe->ops.tuner_ops, &stv6110_tuner_ops,
-				sizeof(struct dvb_tuner_ops));
-	fe->tuner_priv = priv;
-	printk(KERN_INFO "STV6110 attached on addr=%x!\n", priv->i2c_address);
-
-	return fe;
-}
-EXPORT_SYMBOL(stv6110_attach);
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("ST STV6110 driver");
-MODULE_AUTHOR("Igor M. Liplianin");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stv6110.h b/drivers/media/dvb/frontends/stv6110.h
deleted file mode 100644
index fe71bba..0000000
--- a/drivers/media/dvb/frontends/stv6110.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * stv6110.h
- *
- * Driver for ST STV6110 satellite tuner IC.
- *
- * Copyright (C) 2009 NetUP Inc.
- * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __DVB_STV6110_H__
-#define __DVB_STV6110_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-/* registers */
-#define RSTV6110_CTRL1		0
-#define RSTV6110_CTRL2		1
-#define RSTV6110_TUNING1	2
-#define RSTV6110_TUNING2	3
-#define RSTV6110_CTRL3		4
-#define RSTV6110_STAT1		5
-#define RSTV6110_STAT2		6
-#define RSTV6110_STAT3		7
-
-struct stv6110_config {
-	u8 i2c_address;
-	u32 mclk;
-	u8 gain;
-	u8 clk_div;	/* divisor value for the output clock */
-};
-
-#if defined(CONFIG_DVB_STV6110) || (defined(CONFIG_DVB_STV6110_MODULE) \
-							&& defined(MODULE))
-extern struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
-					const struct stv6110_config *config,
-					struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
-					const struct stv6110_config *config,
-					struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/dvb/frontends/stv6110x.c b/drivers/media/dvb/frontends/stv6110x.c
deleted file mode 100644
index f36cab1..0000000
--- a/drivers/media/dvb/frontends/stv6110x.c
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
-	STV6110(A) Silicon tuner driver
-
-	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
-
-	Copyright (C) ST Microelectronics
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-
-#include "dvb_frontend.h"
-
-#include "stv6110x_reg.h"
-#include "stv6110x.h"
-#include "stv6110x_priv.h"
-
-static unsigned int verbose;
-module_param(verbose, int, 0644);
-MODULE_PARM_DESC(verbose, "Set Verbosity level");
-
-static int stv6110x_read_reg(struct stv6110x_state *stv6110x, u8 reg, u8 *data)
-{
-	int ret;
-	const struct stv6110x_config *config = stv6110x->config;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
-	struct i2c_msg msg[] = {
-		{ .addr = config->addr, .flags = 0, 	   .buf = b0, .len = 1 },
-		{ .addr = config->addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }
-	};
-
-	ret = i2c_transfer(stv6110x->i2c, msg, 2);
-	if (ret != 2) {
-		dprintk(FE_ERROR, 1, "I/O Error");
-		return -EREMOTEIO;
-	}
-	*data = b1[0];
-
-	return 0;
-}
-
-static int stv6110x_write_regs(struct stv6110x_state *stv6110x, int start, u8 data[], int len)
-{
-	int ret;
-	const struct stv6110x_config *config = stv6110x->config;
-	u8 buf[len + 1];
-	struct i2c_msg msg = {
-		.addr = config->addr,
-		.flags = 0,
-		.buf = buf,
-		.len = len + 1
-	};
-
-	if (start + len > 8)
-		return -EINVAL;
-
-	buf[0] = start;
-	memcpy(&buf[1], data, len);
-
-	ret = i2c_transfer(stv6110x->i2c, &msg, 1);
-	if (ret != 1) {
-		dprintk(FE_ERROR, 1, "I/O Error");
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
-{
-	return stv6110x_write_regs(stv6110x, reg, &data, 1);
-}
-
-static int stv6110x_init(struct dvb_frontend *fe)
-{
-	struct stv6110x_state *stv6110x = fe->tuner_priv;
-	int ret;
-
-	ret = stv6110x_write_regs(stv6110x, 0, stv6110x->regs,
-				  ARRAY_SIZE(stv6110x->regs));
-	if (ret < 0) {
-		dprintk(FE_ERROR, 1, "Initialization failed");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency)
-{
-	struct stv6110x_state *stv6110x = fe->tuner_priv;
-	u32 rDiv, divider;
-	s32 pVal, pCalc, rDivOpt = 0, pCalcOpt = 1000;
-	u8 i;
-
-	STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_K, (REFCLOCK_MHz - 16));
-
-	if (frequency <= 1023000) {
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
-		pVal = 40;
-	} else if (frequency <= 1300000) {
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
-		pVal = 40;
-	} else if (frequency <= 2046000) {
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
-		pVal = 20;
-	} else {
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
-		pVal = 20;
-	}
-
-	for (rDiv = 0; rDiv <= 3; rDiv++) {
-		pCalc = (REFCLOCK_kHz / 100) / R_DIV(rDiv);
-
-		if ((abs((s32)(pCalc - pVal))) < (abs((s32)(pCalcOpt - pVal))))
-			rDivOpt = rDiv;
-
-		pCalcOpt = (REFCLOCK_kHz / 100) / R_DIV(rDivOpt);
-	}
-
-	divider = (frequency * R_DIV(rDivOpt) * pVal) / REFCLOCK_kHz;
-	divider = (divider + 5) / 10;
-
-	STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_R_DIV, rDivOpt);
-	STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_N_DIV_11_8, MSB(divider));
-	STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG0], TNG0_N_DIV_7_0, LSB(divider));
-
-	/* VCO Auto calibration */
-	STV6110x_SETFIELD(stv6110x->regs[STV6110x_STAT1], STAT1_CALVCO_STRT, 1);
-
-	stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x->regs[STV6110x_CTRL1]);
-	stv6110x_write_reg(stv6110x, STV6110x_TNG1, stv6110x->regs[STV6110x_TNG1]);
-	stv6110x_write_reg(stv6110x, STV6110x_TNG0, stv6110x->regs[STV6110x_TNG0]);
-	stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x->regs[STV6110x_STAT1]);
-
-	for (i = 0; i < TRIALS; i++) {
-		stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]);
-		if (!STV6110x_GETFIELD(STAT1_CALVCO_STRT, stv6110x->regs[STV6110x_STAT1]))
-				break;
-		msleep(1);
-	}
-
-	return 0;
-}
-
-static int stv6110x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct stv6110x_state *stv6110x = fe->tuner_priv;
-
-	stv6110x_read_reg(stv6110x, STV6110x_TNG1, &stv6110x->regs[STV6110x_TNG1]);
-	stv6110x_read_reg(stv6110x, STV6110x_TNG0, &stv6110x->regs[STV6110x_TNG0]);
-
-	*frequency = (MAKEWORD16(STV6110x_GETFIELD(TNG1_N_DIV_11_8, stv6110x->regs[STV6110x_TNG1]),
-				 STV6110x_GETFIELD(TNG0_N_DIV_7_0, stv6110x->regs[STV6110x_TNG0]))) * REFCLOCK_kHz;
-
-	*frequency /= (1 << (STV6110x_GETFIELD(TNG1_R_DIV, stv6110x->regs[STV6110x_TNG1]) +
-			     STV6110x_GETFIELD(TNG1_DIV4SEL, stv6110x->regs[STV6110x_TNG1])));
-
-	*frequency >>= 2;
-
-	return 0;
-}
-
-static int stv6110x_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
-{
-	struct stv6110x_state *stv6110x = fe->tuner_priv;
-	u32 halfbw;
-	u8 i;
-
-	halfbw = bandwidth >> 1;
-
-	if (halfbw > 36000000)
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, 31); /* LPF */
-	else if (halfbw < 5000000)
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, 0); /* LPF */
-	else
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, ((halfbw / 1000000) - 5)); /* LPF */
-
-
-	STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x0); /* cal. clk activated */
-	STV6110x_SETFIELD(stv6110x->regs[STV6110x_STAT1], STAT1_CALRC_STRT, 0x1); /* LPF auto cal */
-
-	stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x->regs[STV6110x_CTRL3]);
-	stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x->regs[STV6110x_STAT1]);
-
-	for (i = 0; i < TRIALS; i++) {
-		stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]);
-		if (!STV6110x_GETFIELD(STAT1_CALRC_STRT, stv6110x->regs[STV6110x_STAT1]))
-			break;
-		msleep(1);
-	}
-	STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x1); /* cal. done */
-	stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x->regs[STV6110x_CTRL3]);
-
-	return 0;
-}
-
-static int stv6110x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	struct stv6110x_state *stv6110x = fe->tuner_priv;
-
-	stv6110x_read_reg(stv6110x, STV6110x_CTRL3, &stv6110x->regs[STV6110x_CTRL3]);
-	*bandwidth = (STV6110x_GETFIELD(CTRL3_CF, stv6110x->regs[STV6110x_CTRL3]) + 5) * 2000000;
-
-	return 0;
-}
-
-static int stv6110x_set_refclock(struct dvb_frontend *fe, u32 refclock)
-{
-	struct stv6110x_state *stv6110x = fe->tuner_priv;
-
-	/* setup divider */
-	switch (refclock) {
-	default:
-	case 1:
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
-		break;
-	case 2:
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
-		break;
-	case 4:
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
-		break;
-	case 8:
-	case 0:
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
-		break;
-	}
-	stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x->regs[STV6110x_CTRL2]);
-
-	return 0;
-}
-
-static int stv6110x_get_bbgain(struct dvb_frontend *fe, u32 *gain)
-{
-	struct stv6110x_state *stv6110x = fe->tuner_priv;
-
-	stv6110x_read_reg(stv6110x, STV6110x_CTRL2, &stv6110x->regs[STV6110x_CTRL2]);
-	*gain = 2 * STV6110x_GETFIELD(CTRL2_BBGAIN, stv6110x->regs[STV6110x_CTRL2]);
-
-	return 0;
-}
-
-static int stv6110x_set_bbgain(struct dvb_frontend *fe, u32 gain)
-{
-	struct stv6110x_state *stv6110x = fe->tuner_priv;
-
-	STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_BBGAIN, gain / 2);
-	stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x->regs[STV6110x_CTRL2]);
-
-	return 0;
-}
-
-static int stv6110x_set_mode(struct dvb_frontend *fe, enum tuner_mode mode)
-{
-	struct stv6110x_state *stv6110x = fe->tuner_priv;
-	int ret;
-
-	switch (mode) {
-	case TUNER_SLEEP:
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_SYN, 0);
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_RX, 0);
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_LPT, 0);
-		break;
-
-	case TUNER_WAKE:
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_SYN, 1);
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_RX, 1);
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_LPT, 1);
-		break;
-	}
-
-	ret = stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x->regs[STV6110x_CTRL1]);
-	if (ret < 0) {
-		dprintk(FE_ERROR, 1, "I/O Error");
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int stv6110x_sleep(struct dvb_frontend *fe)
-{
-	if (fe->tuner_priv)
-		return stv6110x_set_mode(fe, TUNER_SLEEP);
-
-	return 0;
-}
-
-static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status)
-{
-	struct stv6110x_state *stv6110x = fe->tuner_priv;
-
-	stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]);
-
-	if (STV6110x_GETFIELD(STAT1_LOCK, stv6110x->regs[STV6110x_STAT1]))
-		*status = TUNER_PHASELOCKED;
-	else
-		*status = 0;
-
-	return 0;
-}
-
-
-static int stv6110x_release(struct dvb_frontend *fe)
-{
-	struct stv6110x_state *stv6110x = fe->tuner_priv;
-
-	fe->tuner_priv = NULL;
-	kfree(stv6110x);
-
-	return 0;
-}
-
-static struct dvb_tuner_ops stv6110x_ops = {
-	.info = {
-		.name		= "STV6110(A) Silicon Tuner",
-		.frequency_min	=  950000,
-		.frequency_max	= 2150000,
-		.frequency_step	= 0,
-	},
-	.release		= stv6110x_release
-};
-
-static struct stv6110x_devctl stv6110x_ctl = {
-	.tuner_init		= stv6110x_init,
-	.tuner_sleep		= stv6110x_sleep,
-	.tuner_set_mode		= stv6110x_set_mode,
-	.tuner_set_frequency	= stv6110x_set_frequency,
-	.tuner_get_frequency	= stv6110x_get_frequency,
-	.tuner_set_bandwidth	= stv6110x_set_bandwidth,
-	.tuner_get_bandwidth	= stv6110x_get_bandwidth,
-	.tuner_set_bbgain	= stv6110x_set_bbgain,
-	.tuner_get_bbgain	= stv6110x_get_bbgain,
-	.tuner_set_refclk	= stv6110x_set_refclock,
-	.tuner_get_status	= stv6110x_get_status,
-};
-
-struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
-					const struct stv6110x_config *config,
-					struct i2c_adapter *i2c)
-{
-	struct stv6110x_state *stv6110x;
-	u8 default_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e};
-
-	stv6110x = kzalloc(sizeof (struct stv6110x_state), GFP_KERNEL);
-	if (!stv6110x)
-		return NULL;
-
-	stv6110x->i2c		= i2c;
-	stv6110x->config	= config;
-	stv6110x->devctl	= &stv6110x_ctl;
-	memcpy(stv6110x->regs, default_regs, 8);
-
-	/* setup divider */
-	switch (stv6110x->config->clk_div) {
-	default:
-	case 1:
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
-		break;
-	case 2:
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
-		break;
-	case 4:
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
-		break;
-	case 8:
-	case 0:
-		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
-		break;
-	}
-
-	fe->tuner_priv		= stv6110x;
-	fe->ops.tuner_ops	= stv6110x_ops;
-
-	printk(KERN_INFO "%s: Attaching STV6110x\n", __func__);
-	return stv6110x->devctl;
-}
-EXPORT_SYMBOL(stv6110x_attach);
-
-MODULE_AUTHOR("Manu Abraham");
-MODULE_DESCRIPTION("STV6110x Silicon tuner");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stv6110x.h b/drivers/media/dvb/frontends/stv6110x.h
deleted file mode 100644
index 47516753..0000000
--- a/drivers/media/dvb/frontends/stv6110x.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
-	STV6110(A) Silicon tuner driver
-
-	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
-
-	Copyright (C) ST Microelectronics
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __STV6110x_H
-#define __STV6110x_H
-
-struct stv6110x_config {
-	u8	addr;
-	u32	refclk;
-	u8	clk_div; /* divisor value for the output clock */
-};
-
-enum tuner_mode {
-	TUNER_SLEEP = 1,
-	TUNER_WAKE,
-};
-
-enum tuner_status {
-	TUNER_PHASELOCKED = 1,
-};
-
-struct stv6110x_devctl {
-	int (*tuner_init) (struct dvb_frontend *fe);
-	int (*tuner_sleep) (struct dvb_frontend *fe);
-	int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode);
-	int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency);
-	int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency);
-	int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth);
-	int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth);
-	int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain);
-	int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain);
-	int (*tuner_set_refclk)  (struct dvb_frontend *fe, u32 refclk);
-	int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status);
-};
-
-
-#if defined(CONFIG_DVB_STV6110x) || (defined(CONFIG_DVB_STV6110x_MODULE) && defined(MODULE))
-
-extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
-					       const struct stv6110x_config *config,
-					       struct i2c_adapter *i2c);
-
-#else
-static inline struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
-						      const struct stv6110x_config *config,
-						      struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-#endif /* CONFIG_DVB_STV6110x */
-
-#endif /* __STV6110x_H */
diff --git a/drivers/media/dvb/frontends/stv6110x_priv.h b/drivers/media/dvb/frontends/stv6110x_priv.h
deleted file mode 100644
index 0ec936a..0000000
--- a/drivers/media/dvb/frontends/stv6110x_priv.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
-	STV6110(A) Silicon tuner driver
-
-	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
-
-	Copyright (C) ST Microelectronics
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __STV6110x_PRIV_H
-#define __STV6110x_PRIV_H
-
-#define FE_ERROR				0
-#define FE_NOTICE				1
-#define FE_INFO					2
-#define FE_DEBUG				3
-#define FE_DEBUGREG				4
-
-#define dprintk(__y, __z, format, arg...) do {						\
-	if (__z) {									\
-		if	((verbose > FE_ERROR) && (verbose > __y))			\
-			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);		\
-		else if	((verbose > FE_NOTICE) && (verbose > __y))			\
-			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
-		else if ((verbose > FE_INFO) && (verbose > __y))			\
-			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);		\
-		else if ((verbose > FE_DEBUG) && (verbose > __y))			\
-			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
-	} else {									\
-		if (verbose > __y)							\
-			printk(format, ##arg);						\
-	}										\
-} while (0)
-
-
-#define STV6110x_SETFIELD(mask, bitf, val)				\
-	(mask = (mask & (~(((1 << STV6110x_WIDTH_##bitf) - 1) <<	\
-				  STV6110x_OFFST_##bitf))) | 		\
-			  (val << STV6110x_OFFST_##bitf))
-
-#define STV6110x_GETFIELD(bitf, val)					\
-	((val >> STV6110x_OFFST_##bitf) & 				\
-	((1 << STV6110x_WIDTH_##bitf) - 1))
-
-#define MAKEWORD16(a, b)			(((a) << 8) | (b))
-
-#define LSB(x)					((x & 0xff))
-#define MSB(y)					((y >> 8) & 0xff)
-
-#define TRIALS					10
-#define R_DIV(__div)				(1 << (__div + 1))
-#define REFCLOCK_kHz				(stv6110x->config->refclk /    1000)
-#define REFCLOCK_MHz				(stv6110x->config->refclk / 1000000)
-
-struct stv6110x_state {
-	struct i2c_adapter		*i2c;
-	const struct stv6110x_config	*config;
-	u8 				regs[8];
-
-	struct stv6110x_devctl		*devctl;
-};
-
-#endif /* __STV6110x_PRIV_H */
diff --git a/drivers/media/dvb/frontends/stv6110x_reg.h b/drivers/media/dvb/frontends/stv6110x_reg.h
deleted file mode 100644
index 93e5c70..0000000
--- a/drivers/media/dvb/frontends/stv6110x_reg.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-	STV6110(A) Silicon tuner driver
-
-	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
-
-	Copyright (C) ST Microelectronics
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __STV6110x_REG_H
-#define __STV6110x_REG_H
-
-#define STV6110x_CTRL1				0x00
-#define STV6110x_OFFST_CTRL1_K			3
-#define STV6110x_WIDTH_CTRL1_K			5
-#define STV6110x_OFFST_CTRL1_LPT		2
-#define STV6110x_WIDTH_CTRL1_LPT		1
-#define STV6110x_OFFST_CTRL1_RX			1
-#define STV6110x_WIDTH_CTRL1_RX			1
-#define STV6110x_OFFST_CTRL1_SYN		0
-#define STV6110x_WIDTH_CTRL1_SYN		1
-
-#define STV6110x_CTRL2				0x01
-#define STV6110x_OFFST_CTRL2_CO_DIV		6
-#define STV6110x_WIDTH_CTRL2_CO_DIV		2
-#define STV6110x_OFFST_CTRL2_RSVD		5
-#define STV6110x_WIDTH_CTRL2_RSVD		1
-#define STV6110x_OFFST_CTRL2_REFOUT_SEL		4
-#define STV6110x_WIDTH_CTRL2_REFOUT_SEL		1
-#define STV6110x_OFFST_CTRL2_BBGAIN		0
-#define STV6110x_WIDTH_CTRL2_BBGAIN		4
-
-#define STV6110x_TNG0				0x02
-#define STV6110x_OFFST_TNG0_N_DIV_7_0		0
-#define STV6110x_WIDTH_TNG0_N_DIV_7_0		8
-
-#define STV6110x_TNG1				0x03
-#define STV6110x_OFFST_TNG1_R_DIV		6
-#define STV6110x_WIDTH_TNG1_R_DIV		2
-#define STV6110x_OFFST_TNG1_PRESC32_ON		5
-#define STV6110x_WIDTH_TNG1_PRESC32_ON		1
-#define STV6110x_OFFST_TNG1_DIV4SEL		4
-#define STV6110x_WIDTH_TNG1_DIV4SEL		1
-#define STV6110x_OFFST_TNG1_N_DIV_11_8		0
-#define STV6110x_WIDTH_TNG1_N_DIV_11_8		4
-
-
-#define STV6110x_CTRL3				0x04
-#define STV6110x_OFFST_CTRL3_DCLOOP_OFF		7
-#define STV6110x_WIDTH_CTRL3_DCLOOP_OFF		1
-#define STV6110x_OFFST_CTRL3_RCCLK_OFF		6
-#define STV6110x_WIDTH_CTRL3_RCCLK_OFF		1
-#define STV6110x_OFFST_CTRL3_ICP		5
-#define STV6110x_WIDTH_CTRL3_ICP		1
-#define STV6110x_OFFST_CTRL3_CF			0
-#define STV6110x_WIDTH_CTRL3_CF			5
-
-#define STV6110x_STAT1				0x05
-#define STV6110x_OFFST_STAT1_CALVCO_STRT	2
-#define STV6110x_WIDTH_STAT1_CALVCO_STRT	1
-#define STV6110x_OFFST_STAT1_CALRC_STRT		1
-#define STV6110x_WIDTH_STAT1_CALRC_STRT		1
-#define STV6110x_OFFST_STAT1_LOCK		0
-#define STV6110x_WIDTH_STAT1_LOCK		1
-
-#define STV6110x_STAT2				0x06
-#define STV6110x_STAT3				0x07
-
-#endif /* __STV6110x_REG_H */
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
deleted file mode 100644
index 1bff7f4..0000000
--- a/drivers/media/dvb/frontends/tda10021.c
+++ /dev/null
@@ -1,528 +0,0 @@
-/*
-    TDA10021  - Single Chip Cable Channel Receiver driver module
-	       used on the Siemens DVB-C cards
-
-    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
-    Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
-		   Support for TDA10021
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "tda1002x.h"
-
-
-struct tda10021_state {
-	struct i2c_adapter* i2c;
-	/* configuration settings */
-	const struct tda1002x_config* config;
-	struct dvb_frontend frontend;
-
-	u8 pwm;
-	u8 reg0;
-};
-
-
-#if 0
-#define dprintk(x...) printk(x)
-#else
-#define dprintk(x...)
-#endif
-
-static int verbose;
-
-#define XIN 57840000UL
-
-#define FIN (XIN >> 4)
-
-static int tda10021_inittab_size = 0x40;
-static u8 tda10021_inittab[0x40]=
-{
-	0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a,
-	0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40,
-	0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff,
-	0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00,
-	0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00,
-	0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58,
-	0x00, 0x00, 0x80, 0x00, 0x80, 0xff, 0x00, 0x00,
-	0x04, 0x2d, 0x2f, 0xff, 0x00, 0x00, 0x00, 0x00,
-};
-
-static int _tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data)
-{
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
-	int ret;
-
-	ret = i2c_transfer (state->i2c, &msg, 1);
-	if (ret != 1)
-		printk("DVB: TDA10021(%d): %s, writereg error "
-			"(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
-			state->frontend.dvb->num, __func__, reg, data, ret);
-
-	msleep(10);
-	return (ret != 1) ? -EREMOTEIO : 0;
-}
-
-static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
-{
-	u8 b0 [] = { reg };
-	u8 b1 [] = { 0 };
-	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
-				  { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-	int ret;
-
-	ret = i2c_transfer (state->i2c, msg, 2);
-	// Don't print an error message if the id is read.
-	if (ret != 2 && reg != 0x1a)
-		printk("DVB: TDA10021: %s: readreg error (ret == %i)\n",
-				__func__, ret);
-	return b1[0];
-}
-
-//get access to tuner
-static int lock_tuner(struct tda10021_state* state)
-{
-	u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] | 0x80 };
-	struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
-
-	if(i2c_transfer(state->i2c, &msg, 1) != 1)
-	{
-		printk("tda10021: lock tuner fails\n");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-//release access from tuner
-static int unlock_tuner(struct tda10021_state* state)
-{
-	u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] & 0x7f };
-	struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
-
-	if(i2c_transfer(state->i2c, &msg_post, 1) != 1)
-	{
-		printk("tda10021: unlock tuner fails\n");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int tda10021_setup_reg0 (struct tda10021_state* state, u8 reg0,
-				fe_spectral_inversion_t inversion)
-{
-	reg0 |= state->reg0 & 0x63;
-
-	if ((INVERSION_ON == inversion) ^ (state->config->invert == 0))
-		reg0 &= ~0x20;
-	else
-		reg0 |= 0x20;
-
-	_tda10021_writereg (state, 0x00, reg0 & 0xfe);
-	_tda10021_writereg (state, 0x00, reg0 | 0x01);
-
-	state->reg0 = reg0;
-	return 0;
-}
-
-static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate)
-{
-	s32 BDR;
-	s32 BDRI;
-	s16 SFIL=0;
-	u16 NDEC = 0;
-	u32 tmp, ratio;
-
-	if (symbolrate > XIN/2)
-		symbolrate = XIN/2;
-	if (symbolrate < 500000)
-		symbolrate = 500000;
-
-	if (symbolrate < XIN/16) NDEC = 1;
-	if (symbolrate < XIN/32) NDEC = 2;
-	if (symbolrate < XIN/64) NDEC = 3;
-
-	if (symbolrate < (u32)(XIN/12.3)) SFIL = 1;
-	if (symbolrate < (u32)(XIN/16))	 SFIL = 0;
-	if (symbolrate < (u32)(XIN/24.6)) SFIL = 1;
-	if (symbolrate < (u32)(XIN/32))	 SFIL = 0;
-	if (symbolrate < (u32)(XIN/49.2)) SFIL = 1;
-	if (symbolrate < (u32)(XIN/64))	 SFIL = 0;
-	if (symbolrate < (u32)(XIN/98.4)) SFIL = 1;
-
-	symbolrate <<= NDEC;
-	ratio = (symbolrate << 4) / FIN;
-	tmp =  ((symbolrate << 4) % FIN) << 8;
-	ratio = (ratio << 8) + tmp / FIN;
-	tmp = (tmp % FIN) << 8;
-	ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, FIN);
-
-	BDR = ratio;
-	BDRI = (((XIN << 5) / symbolrate) + 1) / 2;
-
-	if (BDRI > 0xFF)
-		BDRI = 0xFF;
-
-	SFIL = (SFIL << 4) | tda10021_inittab[0x0E];
-
-	NDEC = (NDEC << 6) | tda10021_inittab[0x03];
-
-	_tda10021_writereg (state, 0x03, NDEC);
-	_tda10021_writereg (state, 0x0a, BDR&0xff);
-	_tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff);
-	_tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f);
-
-	_tda10021_writereg (state, 0x0d, BDRI);
-	_tda10021_writereg (state, 0x0e, SFIL);
-
-	return 0;
-}
-
-static int tda10021_init (struct dvb_frontend *fe)
-{
-	struct tda10021_state* state = fe->demodulator_priv;
-	int i;
-
-	dprintk("DVB: TDA10021(%d): init chip\n", fe->adapter->num);
-
-	//_tda10021_writereg (fe, 0, 0);
-
-	for (i=0; i<tda10021_inittab_size; i++)
-		_tda10021_writereg (state, i, tda10021_inittab[i]);
-
-	_tda10021_writereg (state, 0x34, state->pwm);
-
-	//Comment by markus
-	//0x2A[3-0] == PDIV -> P multiplaying factor (P=PDIV+1)(default 0)
-	//0x2A[4] == BYPPLL -> Power down mode (default 1)
-	//0x2A[5] == LCK -> PLL Lock Flag
-	//0x2A[6] == POLAXIN -> Polarity of the input reference clock (default 0)
-
-	//Activate PLL
-	_tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
-	return 0;
-}
-
-struct qam_params {
-	u8 conf, agcref, lthr, mseth, aref;
-};
-
-static int tda10021_set_parameters(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 delsys  = c->delivery_system;
-	unsigned qam = c->modulation;
-	bool is_annex_c;
-	u32 reg0x3d;
-	struct tda10021_state* state = fe->demodulator_priv;
-	static const struct qam_params qam_params[] = {
-		/* Modulation  Conf  AGCref  LTHR  MSETH  AREF */
-		[QPSK]	   = { 0x14, 0x78,   0x78, 0x8c,  0x96 },
-		[QAM_16]   = { 0x00, 0x8c,   0x87, 0xa2,  0x91 },
-		[QAM_32]   = { 0x04, 0x8c,   0x64, 0x74,  0x96 },
-		[QAM_64]   = { 0x08, 0x6a,   0x46, 0x43,  0x6a },
-		[QAM_128]  = { 0x0c, 0x78,   0x36, 0x34,  0x7e },
-		[QAM_256]  = { 0x10, 0x5c,   0x26, 0x23,  0x6b },
-	};
-
-	switch (delsys) {
-	case SYS_DVBC_ANNEX_A:
-		is_annex_c = false;
-		break;
-	case SYS_DVBC_ANNEX_C:
-		is_annex_c = true;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/*
-	 * gcc optimizes the code bellow the same way as it would code:
-	 *           "if (qam > 5) return -EINVAL;"
-	 * Yet, the code is clearer, as it shows what QAM standards are
-	 * supported by the driver, and avoids the usage of magic numbers on
-	 * it.
-	 */
-	switch (qam) {
-	case QPSK:
-	case QAM_16:
-	case QAM_32:
-	case QAM_64:
-	case QAM_128:
-	case QAM_256:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (c->inversion != INVERSION_ON && c->inversion != INVERSION_OFF)
-		return -EINVAL;
-
-	/*printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->symbol_rate);*/
-
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	tda10021_set_symbolrate(state, c->symbol_rate);
-	_tda10021_writereg(state, 0x34, state->pwm);
-
-	_tda10021_writereg(state, 0x01, qam_params[qam].agcref);
-	_tda10021_writereg(state, 0x05, qam_params[qam].lthr);
-	_tda10021_writereg(state, 0x08, qam_params[qam].mseth);
-	_tda10021_writereg(state, 0x09, qam_params[qam].aref);
-
-	/*
-	 * Bit 0 == 0 means roll-off = 0.15 (Annex A)
-	 *	 == 1 means roll-off = 0.13 (Annex C)
-	 */
-	reg0x3d = tda10021_readreg (state, 0x3d);
-	if (is_annex_c)
-		_tda10021_writereg (state, 0x3d, 0x01 | reg0x3d);
-	else
-		_tda10021_writereg (state, 0x3d, 0xfe & reg0x3d);
-	tda10021_setup_reg0(state, qam_params[qam].conf, c->inversion);
-
-	return 0;
-}
-
-static int tda10021_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct tda10021_state* state = fe->demodulator_priv;
-	int sync;
-
-	*status = 0;
-	//0x11[0] == EQALGO -> Equalizer algorithms state
-	//0x11[1] == CARLOCK -> Carrier locked
-	//0x11[2] == FSYNC -> Frame synchronisation
-	//0x11[3] == FEL -> Front End locked
-	//0x11[6] == NODVB -> DVB Mode Information
-	sync = tda10021_readreg (state, 0x11);
-
-	if (sync & 2)
-		*status |= FE_HAS_SIGNAL|FE_HAS_CARRIER;
-
-	if (sync & 4)
-		*status |= FE_HAS_SYNC|FE_HAS_VITERBI;
-
-	if (sync & 8)
-		*status |= FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int tda10021_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	struct tda10021_state* state = fe->demodulator_priv;
-
-	u32 _ber = tda10021_readreg(state, 0x14) |
-		(tda10021_readreg(state, 0x15) << 8) |
-		((tda10021_readreg(state, 0x16) & 0x0f) << 16);
-	_tda10021_writereg(state, 0x10, (tda10021_readreg(state, 0x10) & ~0xc0)
-					| (tda10021_inittab[0x10] & 0xc0));
-	*ber = 10 * _ber;
-
-	return 0;
-}
-
-static int tda10021_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-{
-	struct tda10021_state* state = fe->demodulator_priv;
-
-	u8 config = tda10021_readreg(state, 0x02);
-	u8 gain = tda10021_readreg(state, 0x17);
-	if (config & 0x02)
-		/* the agc value is inverted */
-		gain = ~gain;
-	*strength = (gain << 8) | gain;
-
-	return 0;
-}
-
-static int tda10021_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct tda10021_state* state = fe->demodulator_priv;
-
-	u8 quality = ~tda10021_readreg(state, 0x18);
-	*snr = (quality << 8) | quality;
-
-	return 0;
-}
-
-static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	struct tda10021_state* state = fe->demodulator_priv;
-
-	*ucblocks = tda10021_readreg (state, 0x13) & 0x7f;
-	if (*ucblocks == 0x7f)
-		*ucblocks = 0xffffffff;
-
-	/* reset uncorrected block counter */
-	_tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf);
-	_tda10021_writereg (state, 0x10, tda10021_inittab[0x10]);
-
-	return 0;
-}
-
-static int tda10021_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct tda10021_state* state = fe->demodulator_priv;
-	int sync;
-	s8 afc = 0;
-
-	sync = tda10021_readreg(state, 0x11);
-	afc = tda10021_readreg(state, 0x19);
-	if (verbose) {
-		/* AFC only valid when carrier has been recovered */
-		printk(sync & 2 ? "DVB: TDA10021(%d): AFC (%d) %dHz\n" :
-				  "DVB: TDA10021(%d): [AFC (%d) %dHz]\n",
-			state->frontend.dvb->num, afc,
-		       -((s32)p->symbol_rate * afc) >> 10);
-	}
-
-	p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF;
-	p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
-
-	p->fec_inner = FEC_NONE;
-	p->frequency = ((p->frequency + 31250) / 62500) * 62500;
-
-	if (sync & 2)
-		p->frequency -= ((s32)p->symbol_rate * afc) >> 10;
-
-	return 0;
-}
-
-static int tda10021_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
-{
-	struct tda10021_state* state = fe->demodulator_priv;
-
-	if (enable) {
-		lock_tuner(state);
-	} else {
-		unlock_tuner(state);
-	}
-	return 0;
-}
-
-static int tda10021_sleep(struct dvb_frontend* fe)
-{
-	struct tda10021_state* state = fe->demodulator_priv;
-
-	_tda10021_writereg (state, 0x1b, 0x02);  /* pdown ADC */
-	_tda10021_writereg (state, 0x00, 0x80);  /* standby */
-
-	return 0;
-}
-
-static void tda10021_release(struct dvb_frontend* fe)
-{
-	struct tda10021_state* state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops tda10021_ops;
-
-struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
-				     struct i2c_adapter* i2c,
-				     u8 pwm)
-{
-	struct tda10021_state* state = NULL;
-	u8 id;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct tda10021_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->pwm = pwm;
-	state->reg0 = tda10021_inittab[0];
-
-	/* check if the demod is there */
-	id = tda10021_readreg(state, 0x1a);
-	if ((id & 0xf0) != 0x70) goto error;
-
-	/* Don't claim TDA10023 */
-	if (id == 0x7d)
-		goto error;
-
-	printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n",
-	       state->config->demod_address, id);
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops tda10021_ops = {
-	.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C },
-	.info = {
-		.name = "Philips TDA10021 DVB-C",
-		.frequency_stepsize = 62500,
-		.frequency_min = 47000000,
-		.frequency_max = 862000000,
-		.symbol_rate_min = (XIN/2)/64,     /* SACLK/64 == (XIN/2)/64 */
-		.symbol_rate_max = (XIN/2)/4,      /* SACLK/4 */
-	#if 0
-		.frequency_tolerance = ???,
-		.symbol_rate_tolerance = ???,  /* ppm */  /* == 8% (spec p. 5) */
-	#endif
-		.caps = 0x400 | //FE_CAN_QAM_4
-			FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
-			FE_CAN_QAM_128 | FE_CAN_QAM_256 |
-			FE_CAN_FEC_AUTO
-	},
-
-	.release = tda10021_release,
-
-	.init = tda10021_init,
-	.sleep = tda10021_sleep,
-	.i2c_gate_ctrl = tda10021_i2c_gate_ctrl,
-
-	.set_frontend = tda10021_set_parameters,
-	.get_frontend = tda10021_get_frontend,
-
-	.read_status = tda10021_read_status,
-	.read_ber = tda10021_read_ber,
-	.read_signal_strength = tda10021_read_signal_strength,
-	.read_snr = tda10021_read_snr,
-	.read_ucblocks = tda10021_read_ucblocks,
-};
-
-module_param(verbose, int, 0644);
-MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
-
-MODULE_DESCRIPTION("Philips TDA10021 DVB-C demodulator driver");
-MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Markus Schulz");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(tda10021_attach);
diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c
deleted file mode 100644
index ca1e0d5..0000000
--- a/drivers/media/dvb/frontends/tda10023.c
+++ /dev/null
@@ -1,610 +0,0 @@
-/*
-    TDA10023  - DVB-C decoder
-    (as used in Philips CU1216-3 NIM and the Reelbox DVB-C tuner card)
-
-    Copyright (C) 2005 Georg Acher, BayCom GmbH (acher at baycom dot de)
-    Copyright (c) 2006 Hartmut Birr (e9hack at gmail dot com)
-
-    Remotely based on tda10021.c
-    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
-    Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
-		   Support for TDA10021
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include <asm/div64.h>
-
-#include "dvb_frontend.h"
-#include "tda1002x.h"
-
-#define REG0_INIT_VAL 0x23
-
-struct tda10023_state {
-	struct i2c_adapter* i2c;
-	/* configuration settings */
-	const struct tda10023_config *config;
-	struct dvb_frontend frontend;
-
-	u8 pwm;
-	u8 reg0;
-
-	/* clock settings */
-	u32 xtal;
-	u8 pll_m;
-	u8 pll_p;
-	u8 pll_n;
-	u32 sysclk;
-};
-
-#define dprintk(x...)
-
-static int verbose;
-
-static u8 tda10023_readreg (struct tda10023_state* state, u8 reg)
-{
-	u8 b0 [] = { reg };
-	u8 b1 [] = { 0 };
-	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
-				  { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-	int ret;
-
-	ret = i2c_transfer (state->i2c, msg, 2);
-	if (ret != 2) {
-		int num = state->frontend.dvb ? state->frontend.dvb->num : -1;
-		printk(KERN_ERR "DVB: TDA10023(%d): %s: readreg error "
-			"(reg == 0x%02x, ret == %i)\n",
-			num, __func__, reg, ret);
-	}
-	return b1[0];
-}
-
-static int tda10023_writereg (struct tda10023_state* state, u8 reg, u8 data)
-{
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
-	int ret;
-
-	ret = i2c_transfer (state->i2c, &msg, 1);
-	if (ret != 1) {
-		int num = state->frontend.dvb ? state->frontend.dvb->num : -1;
-		printk(KERN_ERR "DVB: TDA10023(%d): %s, writereg error "
-			"(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
-			num, __func__, reg, data, ret);
-	}
-	return (ret != 1) ? -EREMOTEIO : 0;
-}
-
-
-static int tda10023_writebit (struct tda10023_state* state, u8 reg, u8 mask,u8 data)
-{
-	if (mask==0xff)
-		return tda10023_writereg(state, reg, data);
-	else {
-		u8 val;
-		val=tda10023_readreg(state,reg);
-		val&=~mask;
-		val|=(data&mask);
-		return tda10023_writereg(state, reg, val);
-	}
-}
-
-static void tda10023_writetab(struct tda10023_state* state, u8* tab)
-{
-	u8 r,m,v;
-	while (1) {
-		r=*tab++;
-		m=*tab++;
-		v=*tab++;
-		if (r==0xff) {
-			if (m==0xff)
-				break;
-			else
-				msleep(m);
-		}
-		else
-			tda10023_writebit(state,r,m,v);
-	}
-}
-
-//get access to tuner
-static int lock_tuner(struct tda10023_state* state)
-{
-	u8 buf[2] = { 0x0f, 0xc0 };
-	struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
-
-	if(i2c_transfer(state->i2c, &msg, 1) != 1)
-	{
-		printk("tda10023: lock tuner fails\n");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-//release access from tuner
-static int unlock_tuner(struct tda10023_state* state)
-{
-	u8 buf[2] = { 0x0f, 0x40 };
-	struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
-
-	if(i2c_transfer(state->i2c, &msg_post, 1) != 1)
-	{
-		printk("tda10023: unlock tuner fails\n");
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int tda10023_setup_reg0 (struct tda10023_state* state, u8 reg0)
-{
-	reg0 |= state->reg0 & 0x63;
-
-	tda10023_writereg (state, 0x00, reg0 & 0xfe);
-	tda10023_writereg (state, 0x00, reg0 | 0x01);
-
-	state->reg0 = reg0;
-	return 0;
-}
-
-static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
-{
-	s32 BDR;
-	s32 BDRI;
-	s16 SFIL=0;
-	u16 NDEC = 0;
-
-	/* avoid floating point operations multiplying syscloc and divider
-	   by 10 */
-	u32 sysclk_x_10 = state->sysclk * 10;
-
-	if (sr < (u32)(sysclk_x_10/984)) {
-		NDEC=3;
-		SFIL=1;
-	} else if (sr < (u32)(sysclk_x_10/640)) {
-		NDEC=3;
-		SFIL=0;
-	} else if (sr < (u32)(sysclk_x_10/492)) {
-		NDEC=2;
-		SFIL=1;
-	} else if (sr < (u32)(sysclk_x_10/320)) {
-		NDEC=2;
-		SFIL=0;
-	} else if (sr < (u32)(sysclk_x_10/246)) {
-		NDEC=1;
-		SFIL=1;
-	} else if (sr < (u32)(sysclk_x_10/160)) {
-		NDEC=1;
-		SFIL=0;
-	} else if (sr < (u32)(sysclk_x_10/123)) {
-		NDEC=0;
-		SFIL=1;
-	}
-
-	BDRI = (state->sysclk)*16;
-	BDRI>>=NDEC;
-	BDRI +=sr/2;
-	BDRI /=sr;
-
-	if (BDRI>255)
-		BDRI=255;
-
-	{
-		u64 BDRX;
-
-		BDRX=1<<(24+NDEC);
-		BDRX*=sr;
-		do_div(BDRX, state->sysclk); 	/* BDRX/=SYSCLK; */
-
-		BDR=(s32)BDRX;
-	}
-	dprintk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",
-		sr, BDR, BDRI, NDEC);
-	tda10023_writebit (state, 0x03, 0xc0, NDEC<<6);
-	tda10023_writereg (state, 0x0a, BDR&255);
-	tda10023_writereg (state, 0x0b, (BDR>>8)&255);
-	tda10023_writereg (state, 0x0c, (BDR>>16)&31);
-	tda10023_writereg (state, 0x0d, BDRI);
-	tda10023_writereg (state, 0x3d, (SFIL<<7));
-	return 0;
-}
-
-static int tda10023_init (struct dvb_frontend *fe)
-{
-	struct tda10023_state* state = fe->demodulator_priv;
-	u8 tda10023_inittab[] = {
-/*        reg  mask val */
-/* 000 */ 0x2a, 0xff, 0x02,  /* PLL3, Bypass, Power Down */
-/* 003 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
-/* 006 */ 0x2a, 0xff, 0x03,  /* PLL3, Bypass, Power Down */
-/* 009 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
-			   /* PLL1 */
-/* 012 */ 0x28, 0xff, (state->pll_m-1),
-			   /* PLL2 */
-/* 015 */ 0x29, 0xff, ((state->pll_p-1)<<6)|(state->pll_n-1),
-			   /* GPR FSAMPLING=1 */
-/* 018 */ 0x00, 0xff, REG0_INIT_VAL,
-/* 021 */ 0x2a, 0xff, 0x08,  /* PLL3 PSACLK=1 */
-/* 024 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
-/* 027 */ 0x1f, 0xff, 0x00,  /* RESET */
-/* 030 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
-/* 033 */ 0xe6, 0x0c, 0x04,  /* RSCFG_IND */
-/* 036 */ 0x10, 0xc0, 0x80,  /* DECDVBCFG1 PBER=1 */
-
-/* 039 */ 0x0e, 0xff, 0x82,  /* GAIN1 */
-/* 042 */ 0x03, 0x08, 0x08,  /* CLKCONF DYN=1 */
-/* 045 */ 0x2e, 0xbf, 0x30,  /* AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1
-				       PPWMTUN=0 PPWMIF=0 */
-/* 048 */ 0x01, 0xff, 0x30,  /* AGCREF */
-/* 051 */ 0x1e, 0x84, 0x84,  /* CONTROL SACLK_ON=1 */
-/* 054 */ 0x1b, 0xff, 0xc8,  /* ADC TWOS=1 */
-/* 057 */ 0x3b, 0xff, 0xff,  /* IFMAX */
-/* 060 */ 0x3c, 0xff, 0x00,  /* IFMIN */
-/* 063 */ 0x34, 0xff, 0x00,  /* PWMREF */
-/* 066 */ 0x35, 0xff, 0xff,  /* TUNMAX */
-/* 069 */ 0x36, 0xff, 0x00,  /* TUNMIN */
-/* 072 */ 0x06, 0xff, 0x7f,  /* EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 */
-/* 075 */ 0x1c, 0x30, 0x30,  /* EQCONF2 STEPALGO=SGNALGO=1 */
-/* 078 */ 0x37, 0xff, 0xf6,  /* DELTAF_LSB */
-/* 081 */ 0x38, 0xff, 0xff,  /* DELTAF_MSB */
-/* 084 */ 0x02, 0xff, 0x93,  /* AGCCONF1  IFS=1 KAGCIF=2 KAGCTUN=3 */
-/* 087 */ 0x2d, 0xff, 0xf6,  /* SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2 */
-/* 090 */ 0x04, 0x10, 0x00,  /* SWRAMP=1 */
-/* 093 */ 0x12, 0xff, TDA10023_OUTPUT_MODE_PARALLEL_B, /*
-				INTP1 POCLKP=1 FEL=1 MFS=0 */
-/* 096 */ 0x2b, 0x01, 0xa1,  /* INTS1 */
-/* 099 */ 0x20, 0xff, 0x04,  /* INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=? */
-/* 102 */ 0x2c, 0xff, 0x0d,  /* INTP/S TRIP=0 TRIS=0 */
-/* 105 */ 0xc4, 0xff, 0x00,
-/* 108 */ 0xc3, 0x30, 0x00,
-/* 111 */ 0xb5, 0xff, 0x19,  /* ERAGC_THD */
-/* 114 */ 0x00, 0x03, 0x01,  /* GPR, CLBS soft reset */
-/* 117 */ 0x00, 0x03, 0x03,  /* GPR, CLBS soft reset */
-/* 120 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
-/* 123 */ 0xff, 0xff, 0xff
-};
-	dprintk("DVB: TDA10023(%d): init chip\n", fe->dvb->num);
-
-	/* override default values if set in config */
-	if (state->config->deltaf) {
-		tda10023_inittab[80] = (state->config->deltaf & 0xff);
-		tda10023_inittab[83] = (state->config->deltaf >> 8);
-	}
-
-	if (state->config->output_mode)
-		tda10023_inittab[95] = state->config->output_mode;
-
-	tda10023_writetab(state, tda10023_inittab);
-
-	return 0;
-}
-
-struct qam_params {
-	u8 qam, lockthr, mseth, aref, agcrefnyq, eragnyq_thd;
-};
-
-static int tda10023_set_parameters(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 delsys  = c->delivery_system;
-	unsigned qam = c->modulation;
-	bool is_annex_c;
-	struct tda10023_state* state = fe->demodulator_priv;
-	static const struct qam_params qam_params[] = {
-		/* Modulation  QAM    LOCKTHR   MSETH   AREF AGCREFNYQ ERAGCNYQ_THD */
-		[QPSK]    = { (5<<2),  0x78,    0x8c,   0x96,   0x78,   0x4c  },
-		[QAM_16]  = { (0<<2),  0x87,    0xa2,   0x91,   0x8c,   0x57  },
-		[QAM_32]  = { (1<<2),  0x64,    0x74,   0x96,   0x8c,   0x57  },
-		[QAM_64]  = { (2<<2),  0x46,    0x43,   0x6a,   0x6a,   0x44  },
-		[QAM_128] = { (3<<2),  0x36,    0x34,   0x7e,   0x78,   0x4c  },
-		[QAM_256] = { (4<<2),  0x26,    0x23,   0x6c,   0x5c,   0x3c  },
-	};
-
-	switch (delsys) {
-	case SYS_DVBC_ANNEX_A:
-		is_annex_c = false;
-		break;
-	case SYS_DVBC_ANNEX_C:
-		is_annex_c = true;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/*
-	 * gcc optimizes the code bellow the same way as it would code:
-	 *		 "if (qam > 5) return -EINVAL;"
-	 * Yet, the code is clearer, as it shows what QAM standards are
-	 * supported by the driver, and avoids the usage of magic numbers on
-	 * it.
-	 */
-	switch (qam) {
-	case QPSK:
-	case QAM_16:
-	case QAM_32:
-	case QAM_64:
-	case QAM_128:
-	case QAM_256:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	tda10023_set_symbolrate(state, c->symbol_rate);
-	tda10023_writereg(state, 0x05, qam_params[qam].lockthr);
-	tda10023_writereg(state, 0x08, qam_params[qam].mseth);
-	tda10023_writereg(state, 0x09, qam_params[qam].aref);
-	tda10023_writereg(state, 0xb4, qam_params[qam].agcrefnyq);
-	tda10023_writereg(state, 0xb6, qam_params[qam].eragnyq_thd);
-#if 0
-	tda10023_writereg(state, 0x04, (c->inversion ? 0x12 : 0x32));
-	tda10023_writebit(state, 0x04, 0x60, (c->inversion ? 0 : 0x20));
-#endif
-	tda10023_writebit(state, 0x04, 0x40, 0x40);
-
-	if (is_annex_c)
-		tda10023_writebit(state, 0x3d, 0xfc, 0x03);
-	else
-		tda10023_writebit(state, 0x3d, 0xfc, 0x02);
-
-	tda10023_setup_reg0(state, qam_params[qam].qam);
-
-	return 0;
-}
-
-static int tda10023_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct tda10023_state* state = fe->demodulator_priv;
-	int sync;
-
-	*status = 0;
-
-	//0x11[1] == CARLOCK -> Carrier locked
-	//0x11[2] == FSYNC -> Frame synchronisation
-	//0x11[3] == FEL -> Front End locked
-	//0x11[6] == NODVB -> DVB Mode Information
-	sync = tda10023_readreg (state, 0x11);
-
-	if (sync & 2)
-		*status |= FE_HAS_SIGNAL|FE_HAS_CARRIER;
-
-	if (sync & 4)
-		*status |= FE_HAS_SYNC|FE_HAS_VITERBI;
-
-	if (sync & 8)
-		*status |= FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int tda10023_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	struct tda10023_state* state = fe->demodulator_priv;
-	u8 a,b,c;
-	a=tda10023_readreg(state, 0x14);
-	b=tda10023_readreg(state, 0x15);
-	c=tda10023_readreg(state, 0x16)&0xf;
-	tda10023_writebit (state, 0x10, 0xc0, 0x00);
-
-	*ber = a | (b<<8)| (c<<16);
-	return 0;
-}
-
-static int tda10023_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-{
-	struct tda10023_state* state = fe->demodulator_priv;
-	u8 ifgain=tda10023_readreg(state, 0x2f);
-
-	u16 gain = ((255-tda10023_readreg(state, 0x17))) + (255-ifgain)/16;
-	// Max raw value is about 0xb0 -> Normalize to >0xf0 after 0x90
-	if (gain>0x90)
-		gain=gain+2*(gain-0x90);
-	if (gain>255)
-		gain=255;
-
-	*strength = (gain<<8)|gain;
-	return 0;
-}
-
-static int tda10023_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct tda10023_state* state = fe->demodulator_priv;
-
-	u8 quality = ~tda10023_readreg(state, 0x18);
-	*snr = (quality << 8) | quality;
-	return 0;
-}
-
-static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	struct tda10023_state* state = fe->demodulator_priv;
-	u8 a,b,c,d;
-	a= tda10023_readreg (state, 0x74);
-	b= tda10023_readreg (state, 0x75);
-	c= tda10023_readreg (state, 0x76);
-	d= tda10023_readreg (state, 0x77);
-	*ucblocks = a | (b<<8)|(c<<16)|(d<<24);
-
-	tda10023_writebit (state, 0x10, 0x20,0x00);
-	tda10023_writebit (state, 0x10, 0x20,0x20);
-	tda10023_writebit (state, 0x13, 0x01, 0x00);
-
-	return 0;
-}
-
-static int tda10023_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct tda10023_state* state = fe->demodulator_priv;
-	int sync,inv;
-	s8 afc = 0;
-
-	sync = tda10023_readreg(state, 0x11);
-	afc = tda10023_readreg(state, 0x19);
-	inv = tda10023_readreg(state, 0x04);
-
-	if (verbose) {
-		/* AFC only valid when carrier has been recovered */
-		printk(sync & 2 ? "DVB: TDA10023(%d): AFC (%d) %dHz\n" :
-				  "DVB: TDA10023(%d): [AFC (%d) %dHz]\n",
-			state->frontend.dvb->num, afc,
-		       -((s32)p->symbol_rate * afc) >> 10);
-	}
-
-	p->inversion = (inv&0x20?0:1);
-	p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
-
-	p->fec_inner = FEC_NONE;
-	p->frequency = ((p->frequency + 31250) / 62500) * 62500;
-
-	if (sync & 2)
-		p->frequency -= ((s32)p->symbol_rate * afc) >> 10;
-
-	return 0;
-}
-
-static int tda10023_sleep(struct dvb_frontend* fe)
-{
-	struct tda10023_state* state = fe->demodulator_priv;
-
-	tda10023_writereg (state, 0x1b, 0x02);  /* pdown ADC */
-	tda10023_writereg (state, 0x00, 0x80);  /* standby */
-
-	return 0;
-}
-
-static int tda10023_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
-{
-	struct tda10023_state* state = fe->demodulator_priv;
-
-	if (enable) {
-		lock_tuner(state);
-	} else {
-		unlock_tuner(state);
-	}
-	return 0;
-}
-
-static void tda10023_release(struct dvb_frontend* fe)
-{
-	struct tda10023_state* state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops tda10023_ops;
-
-struct dvb_frontend *tda10023_attach(const struct tda10023_config *config,
-				     struct i2c_adapter *i2c,
-				     u8 pwm)
-{
-	struct tda10023_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct tda10023_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-
-	/* wakeup if in standby */
-	tda10023_writereg (state, 0x00, 0x33);
-	/* check if the demod is there */
-	if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
-	state->pwm = pwm;
-	state->reg0 = REG0_INIT_VAL;
-	if (state->config->xtal) {
-		state->xtal  = state->config->xtal;
-		state->pll_m = state->config->pll_m;
-		state->pll_p = state->config->pll_p;
-		state->pll_n = state->config->pll_n;
-	} else {
-		/* set default values if not defined in config */
-		state->xtal  = 28920000;
-		state->pll_m = 8;
-		state->pll_p = 4;
-		state->pll_n = 1;
-	}
-
-	/* calc sysclk */
-	state->sysclk = (state->xtal * state->pll_m / \
-			(state->pll_n * state->pll_p));
-
-	state->frontend.ops.info.symbol_rate_min = (state->sysclk/2)/64;
-	state->frontend.ops.info.symbol_rate_max = (state->sysclk/2)/4;
-
-	dprintk("DVB: TDA10023 %s: xtal:%d pll_m:%d pll_p:%d pll_n:%d\n",
-		__func__, state->xtal, state->pll_m, state->pll_p,
-		state->pll_n);
-
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops tda10023_ops = {
-	.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C },
-	.info = {
-		.name = "Philips TDA10023 DVB-C",
-		.frequency_stepsize = 62500,
-		.frequency_min =  47000000,
-		.frequency_max = 862000000,
-		.symbol_rate_min = 0,  /* set in tda10023_attach */
-		.symbol_rate_max = 0,  /* set in tda10023_attach */
-		.caps = 0x400 | //FE_CAN_QAM_4
-			FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
-			FE_CAN_QAM_128 | FE_CAN_QAM_256 |
-			FE_CAN_FEC_AUTO
-	},
-
-	.release = tda10023_release,
-
-	.init = tda10023_init,
-	.sleep = tda10023_sleep,
-	.i2c_gate_ctrl = tda10023_i2c_gate_ctrl,
-
-	.set_frontend = tda10023_set_parameters,
-	.get_frontend = tda10023_get_frontend,
-	.read_status = tda10023_read_status,
-	.read_ber = tda10023_read_ber,
-	.read_signal_strength = tda10023_read_signal_strength,
-	.read_snr = tda10023_read_snr,
-	.read_ucblocks = tda10023_read_ucblocks,
-};
-
-
-MODULE_DESCRIPTION("Philips TDA10023 DVB-C demodulator driver");
-MODULE_AUTHOR("Georg Acher, Hartmut Birr");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(tda10023_attach);
diff --git a/drivers/media/dvb/frontends/tda1002x.h b/drivers/media/dvb/frontends/tda1002x.h
deleted file mode 100644
index 04d1941..0000000
--- a/drivers/media/dvb/frontends/tda1002x.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-    TDA10021/TDA10023  - Single Chip Cable Channel Receiver driver module
-			 used on the the Siemens DVB-C cards
-
-    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
-    Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
-		   Support for TDA10021
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef TDA1002x_H
-#define TDA1002x_H
-
-#include <linux/dvb/frontend.h>
-
-struct tda1002x_config {
-	/* the demodulator's i2c address */
-	u8 demod_address;
-	u8 invert;
-};
-
-enum tda10023_output_mode {
-	TDA10023_OUTPUT_MODE_PARALLEL_A = 0xe0,
-	TDA10023_OUTPUT_MODE_PARALLEL_B = 0xa1,
-	TDA10023_OUTPUT_MODE_PARALLEL_C = 0xa0,
-	TDA10023_OUTPUT_MODE_SERIAL, /* TODO: not implemented */
-};
-
-struct tda10023_config {
-	/* the demodulator's i2c address */
-	u8 demod_address;
-	u8 invert;
-
-	/* clock settings */
-	u32 xtal; /* defaults: 28920000 */
-	u8 pll_m; /* defaults: 8 */
-	u8 pll_p; /* defaults: 4 */
-	u8 pll_n; /* defaults: 1 */
-
-	/* MPEG2 TS output mode */
-	u8 output_mode;
-
-	/* input freq offset + baseband conversion type */
-	u16 deltaf;
-};
-
-#if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE))
-extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
-					    struct i2c_adapter* i2c, u8 pwm);
-#else
-static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
-					    struct i2c_adapter* i2c, u8 pwm)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_TDA10021
-
-#if defined(CONFIG_DVB_TDA10023) || \
-	(defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE))
-extern struct dvb_frontend *tda10023_attach(
-	const struct tda10023_config *config,
-	struct i2c_adapter *i2c, u8 pwm);
-#else
-static inline struct dvb_frontend *tda10023_attach(
-	const struct tda10023_config *config,
-	struct i2c_adapter *i2c, u8 pwm)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_TDA10023
-
-#endif // TDA1002x_H
diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c
deleted file mode 100644
index 71fb632..0000000
--- a/drivers/media/dvb/frontends/tda10048.c
+++ /dev/null
@@ -1,1191 +0,0 @@
-/*
-    NXP TDA10048HN DVB OFDM demodulator driver
-
-    Copyright (C) 2009 Steven Toth <stoth@kernellabs.com>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/math64.h>
-#include <asm/div64.h>
-#include "dvb_frontend.h"
-#include "dvb_math.h"
-#include "tda10048.h"
-
-#define TDA10048_DEFAULT_FIRMWARE "dvb-fe-tda10048-1.0.fw"
-#define TDA10048_DEFAULT_FIRMWARE_SIZE 24878
-
-/* Register name definitions */
-#define TDA10048_IDENTITY          0x00
-#define TDA10048_VERSION           0x01
-#define TDA10048_DSP_CODE_CPT      0x0C
-#define TDA10048_DSP_CODE_IN       0x0E
-#define TDA10048_IN_CONF1          0x10
-#define TDA10048_IN_CONF2          0x11
-#define TDA10048_IN_CONF3          0x12
-#define TDA10048_OUT_CONF1         0x14
-#define TDA10048_OUT_CONF2         0x15
-#define TDA10048_OUT_CONF3         0x16
-#define TDA10048_AUTO              0x18
-#define TDA10048_SYNC_STATUS       0x1A
-#define TDA10048_CONF_C4_1         0x1E
-#define TDA10048_CONF_C4_2         0x1F
-#define TDA10048_CODE_IN_RAM       0x20
-#define TDA10048_CHANNEL_INFO1_R   0x22
-#define TDA10048_CHANNEL_INFO2_R   0x23
-#define TDA10048_CHANNEL_INFO1     0x24
-#define TDA10048_CHANNEL_INFO2     0x25
-#define TDA10048_TIME_ERROR_R      0x26
-#define TDA10048_TIME_ERROR        0x27
-#define TDA10048_FREQ_ERROR_LSB_R  0x28
-#define TDA10048_FREQ_ERROR_MSB_R  0x29
-#define TDA10048_FREQ_ERROR_LSB    0x2A
-#define TDA10048_FREQ_ERROR_MSB    0x2B
-#define TDA10048_IT_SEL            0x30
-#define TDA10048_IT_STAT           0x32
-#define TDA10048_DSP_AD_LSB        0x3C
-#define TDA10048_DSP_AD_MSB        0x3D
-#define TDA10048_DSP_REG_LSB       0x3E
-#define TDA10048_DSP_REG_MSB       0x3F
-#define TDA10048_CONF_TRISTATE1    0x44
-#define TDA10048_CONF_TRISTATE2    0x45
-#define TDA10048_CONF_POLARITY     0x46
-#define TDA10048_GPIO_SP_DS0       0x48
-#define TDA10048_GPIO_SP_DS1       0x49
-#define TDA10048_GPIO_SP_DS2       0x4A
-#define TDA10048_GPIO_SP_DS3       0x4B
-#define TDA10048_GPIO_OUT_SEL      0x4C
-#define TDA10048_GPIO_SELECT       0x4D
-#define TDA10048_IC_MODE           0x4E
-#define TDA10048_CONF_XO           0x50
-#define TDA10048_CONF_PLL1         0x51
-#define TDA10048_CONF_PLL2         0x52
-#define TDA10048_CONF_PLL3         0x53
-#define TDA10048_CONF_ADC          0x54
-#define TDA10048_CONF_ADC_2        0x55
-#define TDA10048_CONF_C1_1         0x60
-#define TDA10048_CONF_C1_3         0x62
-#define TDA10048_AGC_CONF          0x70
-#define TDA10048_AGC_THRESHOLD_LSB 0x72
-#define TDA10048_AGC_THRESHOLD_MSB 0x73
-#define TDA10048_AGC_RENORM        0x74
-#define TDA10048_AGC_GAINS         0x76
-#define TDA10048_AGC_TUN_MIN       0x78
-#define TDA10048_AGC_TUN_MAX       0x79
-#define TDA10048_AGC_IF_MIN        0x7A
-#define TDA10048_AGC_IF_MAX        0x7B
-#define TDA10048_AGC_TUN_LEVEL     0x7E
-#define TDA10048_AGC_IF_LEVEL      0x7F
-#define TDA10048_DIG_AGC_LEVEL     0x81
-#define TDA10048_FREQ_PHY2_LSB     0x86
-#define TDA10048_FREQ_PHY2_MSB     0x87
-#define TDA10048_TIME_INVWREF_LSB  0x88
-#define TDA10048_TIME_INVWREF_MSB  0x89
-#define TDA10048_TIME_WREF_LSB     0x8A
-#define TDA10048_TIME_WREF_MID1    0x8B
-#define TDA10048_TIME_WREF_MID2    0x8C
-#define TDA10048_TIME_WREF_MSB     0x8D
-#define TDA10048_NP_OUT            0xA2
-#define TDA10048_CELL_ID_LSB       0xA4
-#define TDA10048_CELL_ID_MSB       0xA5
-#define TDA10048_EXTTPS_ODD        0xAA
-#define TDA10048_EXTTPS_EVEN       0xAB
-#define TDA10048_TPS_LENGTH        0xAC
-#define TDA10048_FREE_REG_1        0xB2
-#define TDA10048_FREE_REG_2        0xB3
-#define TDA10048_CONF_C3_1         0xC0
-#define TDA10048_CVBER_CTRL        0xC2
-#define TDA10048_CBER_NMAX_LSB     0xC4
-#define TDA10048_CBER_NMAX_MSB     0xC5
-#define TDA10048_CBER_LSB          0xC6
-#define TDA10048_CBER_MSB          0xC7
-#define TDA10048_VBER_LSB          0xC8
-#define TDA10048_VBER_MID          0xC9
-#define TDA10048_VBER_MSB          0xCA
-#define TDA10048_CVBER_LUT         0xCC
-#define TDA10048_UNCOR_CTRL        0xCD
-#define TDA10048_UNCOR_CPT_LSB     0xCE
-#define TDA10048_UNCOR_CPT_MSB     0xCF
-#define TDA10048_SOFT_IT_C3        0xD6
-#define TDA10048_CONF_TS2          0xE0
-#define TDA10048_CONF_TS1          0xE1
-
-static unsigned int debug;
-
-#define dprintk(level, fmt, arg...)\
-	do { if (debug >= level)\
-		printk(KERN_DEBUG "tda10048: " fmt, ## arg);\
-	} while (0)
-
-struct tda10048_state {
-
-	struct i2c_adapter *i2c;
-
-	/* We'll cache and update the attach config settings */
-	struct tda10048_config config;
-	struct dvb_frontend frontend;
-
-	int fwloaded;
-
-	u32 freq_if_hz;
-	u32 xtal_hz;
-	u32 pll_mfactor;
-	u32 pll_nfactor;
-	u32 pll_pfactor;
-	u32 sample_freq;
-
-	u32 bandwidth;
-};
-
-static struct init_tab {
-	u8	reg;
-	u16	data;
-} init_tab[] = {
-	{ TDA10048_CONF_PLL1, 0x08 },
-	{ TDA10048_CONF_ADC_2, 0x00 },
-	{ TDA10048_CONF_C4_1, 0x00 },
-	{ TDA10048_CONF_PLL1, 0x0f },
-	{ TDA10048_CONF_PLL2, 0x0a },
-	{ TDA10048_CONF_PLL3, 0x43 },
-	{ TDA10048_FREQ_PHY2_LSB, 0x02 },
-	{ TDA10048_FREQ_PHY2_MSB, 0x0a },
-	{ TDA10048_TIME_WREF_LSB, 0xbd },
-	{ TDA10048_TIME_WREF_MID1, 0xe4 },
-	{ TDA10048_TIME_WREF_MID2, 0xa8 },
-	{ TDA10048_TIME_WREF_MSB, 0x02 },
-	{ TDA10048_TIME_INVWREF_LSB, 0x04 },
-	{ TDA10048_TIME_INVWREF_MSB, 0x06 },
-	{ TDA10048_CONF_C4_1, 0x00 },
-	{ TDA10048_CONF_C1_1, 0xa8 },
-	{ TDA10048_AGC_CONF, 0x16 },
-	{ TDA10048_CONF_C1_3, 0x0b },
-	{ TDA10048_AGC_TUN_MIN, 0x00 },
-	{ TDA10048_AGC_TUN_MAX, 0xff },
-	{ TDA10048_AGC_IF_MIN, 0x00 },
-	{ TDA10048_AGC_IF_MAX, 0xff },
-	{ TDA10048_AGC_THRESHOLD_MSB, 0x00 },
-	{ TDA10048_AGC_THRESHOLD_LSB, 0x70 },
-	{ TDA10048_CVBER_CTRL, 0x38 },
-	{ TDA10048_AGC_GAINS, 0x12 },
-	{ TDA10048_CONF_XO, 0x00 },
-	{ TDA10048_CONF_TS1, 0x07 },
-	{ TDA10048_IC_MODE, 0x00 },
-	{ TDA10048_CONF_TS2, 0xc0 },
-	{ TDA10048_CONF_TRISTATE1, 0x21 },
-	{ TDA10048_CONF_TRISTATE2, 0x00 },
-	{ TDA10048_CONF_POLARITY, 0x00 },
-	{ TDA10048_CONF_C4_2, 0x04 },
-	{ TDA10048_CONF_ADC, 0x60 },
-	{ TDA10048_CONF_ADC_2, 0x10 },
-	{ TDA10048_CONF_ADC, 0x60 },
-	{ TDA10048_CONF_ADC_2, 0x00 },
-	{ TDA10048_CONF_C1_1, 0xa8 },
-	{ TDA10048_UNCOR_CTRL, 0x00 },
-	{ TDA10048_CONF_C4_2, 0x04 },
-};
-
-static struct pll_tab {
-	u32	clk_freq_khz;
-	u32	if_freq_khz;
-} pll_tab[] = {
-	{ TDA10048_CLK_4000,  TDA10048_IF_36130 },
-	{ TDA10048_CLK_16000, TDA10048_IF_3300 },
-	{ TDA10048_CLK_16000, TDA10048_IF_3500 },
-	{ TDA10048_CLK_16000, TDA10048_IF_3800 },
-	{ TDA10048_CLK_16000, TDA10048_IF_4000 },
-	{ TDA10048_CLK_16000, TDA10048_IF_4300 },
-	{ TDA10048_CLK_16000, TDA10048_IF_4500 },
-	{ TDA10048_CLK_16000, TDA10048_IF_5000 },
-	{ TDA10048_CLK_16000, TDA10048_IF_36130 },
-};
-
-static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
-{
-	struct tda10048_config *config = &state->config;
-	int ret;
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = {
-		.addr = config->demod_address,
-		.flags = 0, .buf = buf, .len = 2 };
-
-	dprintk(2, "%s(reg = 0x%02x, data = 0x%02x)\n", __func__, reg, data);
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-
-	if (ret != 1)
-		printk("%s: writereg error (ret == %i)\n", __func__, ret);
-
-	return (ret != 1) ? -1 : 0;
-}
-
-static u8 tda10048_readreg(struct tda10048_state *state, u8 reg)
-{
-	struct tda10048_config *config = &state->config;
-	int ret;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
-	struct i2c_msg msg[] = {
-		{ .addr = config->demod_address,
-			.flags = 0, .buf = b0, .len = 1 },
-		{ .addr = config->demod_address,
-			.flags = I2C_M_RD, .buf = b1, .len = 1 } };
-
-	dprintk(2, "%s(reg = 0x%02x)\n", __func__, reg);
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2)
-		printk(KERN_ERR "%s: readreg error (ret == %i)\n",
-			__func__, ret);
-
-	return b1[0];
-}
-
-static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg,
-				 const u8 *data, u16 len)
-{
-	struct tda10048_config *config = &state->config;
-	int ret = -EREMOTEIO;
-	struct i2c_msg msg;
-	u8 *buf;
-
-	dprintk(2, "%s(%d, ?, len = %d)\n", __func__, reg, len);
-
-	buf = kmalloc(len + 1, GFP_KERNEL);
-	if (buf == NULL) {
-		ret = -ENOMEM;
-		goto error;
-	}
-
-	*buf = reg;
-	memcpy(buf + 1, data, len);
-
-	msg.addr = config->demod_address;
-	msg.flags = 0;
-	msg.buf = buf;
-	msg.len = len + 1;
-
-	dprintk(2, "%s():  write len = %d\n",
-		__func__, msg.len);
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-	if (ret != 1) {
-		printk(KERN_ERR "%s(): writereg error err %i\n",
-			 __func__, ret);
-		ret = -EREMOTEIO;
-	}
-
-error:
-	kfree(buf);
-
-	return ret;
-}
-
-static int tda10048_set_phy2(struct dvb_frontend *fe, u32 sample_freq_hz,
-			     u32 if_hz)
-{
-	struct tda10048_state *state = fe->demodulator_priv;
-	u64 t;
-
-	dprintk(1, "%s()\n", __func__);
-
-	if (sample_freq_hz == 0)
-		return -EINVAL;
-
-	if (if_hz < (sample_freq_hz / 2)) {
-		/* PHY2 = (if2/fs) * 2^15 */
-		t = if_hz;
-		t *= 10;
-		t *= 32768;
-		do_div(t, sample_freq_hz);
-		t += 5;
-		do_div(t, 10);
-	} else {
-		/* PHY2 = ((IF1-fs)/fs) * 2^15 */
-		t = sample_freq_hz - if_hz;
-		t *= 10;
-		t *= 32768;
-		do_div(t, sample_freq_hz);
-		t += 5;
-		do_div(t, 10);
-		t = ~t + 1;
-	}
-
-	tda10048_writereg(state, TDA10048_FREQ_PHY2_LSB, (u8)t);
-	tda10048_writereg(state, TDA10048_FREQ_PHY2_MSB, (u8)(t >> 8));
-
-	return 0;
-}
-
-static int tda10048_set_wref(struct dvb_frontend *fe, u32 sample_freq_hz,
-			     u32 bw)
-{
-	struct tda10048_state *state = fe->demodulator_priv;
-	u64 t, z;
-
-	dprintk(1, "%s()\n", __func__);
-
-	if (sample_freq_hz == 0)
-		return -EINVAL;
-
-	/* WREF = (B / (7 * fs)) * 2^31 */
-	t = bw * 10;
-	/* avoid warning: this decimal constant is unsigned only in ISO C90 */
-	/* t *= 2147483648 on 32bit platforms */
-	t *= (2048 * 1024);
-	t *= 1024;
-	z = 7 * sample_freq_hz;
-	do_div(t, z);
-	t += 5;
-	do_div(t, 10);
-
-	tda10048_writereg(state, TDA10048_TIME_WREF_LSB, (u8)t);
-	tda10048_writereg(state, TDA10048_TIME_WREF_MID1, (u8)(t >> 8));
-	tda10048_writereg(state, TDA10048_TIME_WREF_MID2, (u8)(t >> 16));
-	tda10048_writereg(state, TDA10048_TIME_WREF_MSB, (u8)(t >> 24));
-
-	return 0;
-}
-
-static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz,
-				u32 bw)
-{
-	struct tda10048_state *state = fe->demodulator_priv;
-	u64 t;
-
-	dprintk(1, "%s()\n", __func__);
-
-	if (sample_freq_hz == 0)
-		return -EINVAL;
-
-	/* INVWREF = ((7 * fs) / B) * 2^5 */
-	t = sample_freq_hz;
-	t *= 7;
-	t *= 32;
-	t *= 10;
-	do_div(t, bw);
-	t += 5;
-	do_div(t, 10);
-
-	tda10048_writereg(state, TDA10048_TIME_INVWREF_LSB, (u8)t);
-	tda10048_writereg(state, TDA10048_TIME_INVWREF_MSB, (u8)(t >> 8));
-
-	return 0;
-}
-
-static int tda10048_set_bandwidth(struct dvb_frontend *fe,
-	u32 bw)
-{
-	struct tda10048_state *state = fe->demodulator_priv;
-	dprintk(1, "%s(bw=%d)\n", __func__, bw);
-
-	/* Bandwidth setting may need to be adjusted */
-	switch (bw) {
-	case 6000000:
-	case 7000000:
-	case 8000000:
-		tda10048_set_wref(fe, state->sample_freq, bw);
-		tda10048_set_invwref(fe, state->sample_freq, bw);
-		break;
-	default:
-		printk(KERN_ERR "%s() invalid bandwidth\n", __func__);
-		return -EINVAL;
-	}
-
-	state->bandwidth = bw;
-
-	return 0;
-}
-
-static int tda10048_set_if(struct dvb_frontend *fe, u32 bw)
-{
-	struct tda10048_state *state = fe->demodulator_priv;
-	struct tda10048_config *config = &state->config;
-	int i;
-	u32 if_freq_khz;
-
-	dprintk(1, "%s(bw = %d)\n", __func__, bw);
-
-	/* based on target bandwidth and clk we calculate pll factors */
-	switch (bw) {
-	case 6000000:
-		if_freq_khz = config->dtv6_if_freq_khz;
-		break;
-	case 7000000:
-		if_freq_khz = config->dtv7_if_freq_khz;
-		break;
-	case 8000000:
-		if_freq_khz = config->dtv8_if_freq_khz;
-		break;
-	default:
-		printk(KERN_ERR "%s() no default\n", __func__);
-		return -EINVAL;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(pll_tab); i++) {
-		if ((pll_tab[i].clk_freq_khz == config->clk_freq_khz) &&
-			(pll_tab[i].if_freq_khz == if_freq_khz)) {
-
-			state->freq_if_hz = pll_tab[i].if_freq_khz * 1000;
-			state->xtal_hz = pll_tab[i].clk_freq_khz * 1000;
-			break;
-		}
-	}
-	if (i == ARRAY_SIZE(pll_tab)) {
-		printk(KERN_ERR "%s() Incorrect attach settings\n",
-			__func__);
-		return -EINVAL;
-	}
-
-	dprintk(1, "- freq_if_hz = %d\n", state->freq_if_hz);
-	dprintk(1, "- xtal_hz = %d\n", state->xtal_hz);
-	dprintk(1, "- pll_mfactor = %d\n", state->pll_mfactor);
-	dprintk(1, "- pll_nfactor = %d\n", state->pll_nfactor);
-	dprintk(1, "- pll_pfactor = %d\n", state->pll_pfactor);
-
-	/* Calculate the sample frequency */
-	state->sample_freq = state->xtal_hz * (state->pll_mfactor + 45);
-	state->sample_freq /= (state->pll_nfactor + 1);
-	state->sample_freq /= (state->pll_pfactor + 4);
-	dprintk(1, "- sample_freq = %d\n", state->sample_freq);
-
-	/* Update the I/F */
-	tda10048_set_phy2(fe, state->sample_freq, state->freq_if_hz);
-
-	return 0;
-}
-
-static int tda10048_firmware_upload(struct dvb_frontend *fe)
-{
-	struct tda10048_state *state = fe->demodulator_priv;
-	struct tda10048_config *config = &state->config;
-	const struct firmware *fw;
-	int ret;
-	int pos = 0;
-	int cnt;
-	u8 wlen = config->fwbulkwritelen;
-
-	if ((wlen != TDA10048_BULKWRITE_200) && (wlen != TDA10048_BULKWRITE_50))
-		wlen = TDA10048_BULKWRITE_200;
-
-	/* request the firmware, this will block and timeout */
-	printk(KERN_INFO "%s: waiting for firmware upload (%s)...\n",
-		__func__,
-		TDA10048_DEFAULT_FIRMWARE);
-
-	ret = request_firmware(&fw, TDA10048_DEFAULT_FIRMWARE,
-		state->i2c->dev.parent);
-	if (ret) {
-		printk(KERN_ERR "%s: Upload failed. (file not found?)\n",
-			__func__);
-		return -EIO;
-	} else {
-		printk(KERN_INFO "%s: firmware read %Zu bytes.\n",
-			__func__,
-			fw->size);
-		ret = 0;
-	}
-
-	if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) {
-		printk(KERN_ERR "%s: firmware incorrect size\n", __func__);
-		ret = -EIO;
-	} else {
-		printk(KERN_INFO "%s: firmware uploading\n", __func__);
-
-		/* Soft reset */
-		tda10048_writereg(state, TDA10048_CONF_TRISTATE1,
-			tda10048_readreg(state, TDA10048_CONF_TRISTATE1)
-				& 0xfe);
-		tda10048_writereg(state, TDA10048_CONF_TRISTATE1,
-			tda10048_readreg(state, TDA10048_CONF_TRISTATE1)
-				| 0x01);
-
-		/* Put the demod into host download mode */
-		tda10048_writereg(state, TDA10048_CONF_C4_1,
-			tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xf9);
-
-		/* Boot the DSP */
-		tda10048_writereg(state, TDA10048_CONF_C4_1,
-			tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x08);
-
-		/* Prepare for download */
-		tda10048_writereg(state, TDA10048_DSP_CODE_CPT, 0);
-
-		/* Download the firmware payload */
-		while (pos < fw->size) {
-
-			if ((fw->size - pos) > wlen)
-				cnt = wlen;
-			else
-				cnt = fw->size - pos;
-
-			tda10048_writeregbulk(state, TDA10048_DSP_CODE_IN,
-				&fw->data[pos], cnt);
-
-			pos += cnt;
-		}
-
-		ret = -EIO;
-		/* Wait up to 250ms for the DSP to boot */
-		for (cnt = 0; cnt < 250 ; cnt += 10) {
-
-			msleep(10);
-
-			if (tda10048_readreg(state, TDA10048_SYNC_STATUS)
-				& 0x40) {
-				ret = 0;
-				break;
-			}
-		}
-	}
-
-	release_firmware(fw);
-
-	if (ret == 0) {
-		printk(KERN_INFO "%s: firmware uploaded\n", __func__);
-		state->fwloaded = 1;
-	} else
-		printk(KERN_ERR "%s: firmware upload failed\n", __func__);
-
-	return ret;
-}
-
-static int tda10048_set_inversion(struct dvb_frontend *fe, int inversion)
-{
-	struct tda10048_state *state = fe->demodulator_priv;
-
-	dprintk(1, "%s(%d)\n", __func__, inversion);
-
-	if (inversion == TDA10048_INVERSION_ON)
-		tda10048_writereg(state, TDA10048_CONF_C1_1,
-			tda10048_readreg(state, TDA10048_CONF_C1_1) | 0x20);
-	else
-		tda10048_writereg(state, TDA10048_CONF_C1_1,
-			tda10048_readreg(state, TDA10048_CONF_C1_1) & 0xdf);
-
-	return 0;
-}
-
-/* Retrieve the demod settings */
-static int tda10048_get_tps(struct tda10048_state *state,
-	struct dtv_frontend_properties *p)
-{
-	u8 val;
-
-	/* Make sure the TPS regs are valid */
-	if (!(tda10048_readreg(state, TDA10048_AUTO) & 0x01))
-		return -EAGAIN;
-
-	val = tda10048_readreg(state, TDA10048_OUT_CONF2);
-	switch ((val & 0x60) >> 5) {
-	case 0:
-		p->modulation = QPSK;
-		break;
-	case 1:
-		p->modulation = QAM_16;
-		break;
-	case 2:
-		p->modulation = QAM_64;
-		break;
-	}
-	switch ((val & 0x18) >> 3) {
-	case 0:
-		p->hierarchy = HIERARCHY_NONE;
-		break;
-	case 1:
-		p->hierarchy = HIERARCHY_1;
-		break;
-	case 2:
-		p->hierarchy = HIERARCHY_2;
-		break;
-	case 3:
-		p->hierarchy = HIERARCHY_4;
-		break;
-	}
-	switch (val & 0x07) {
-	case 0:
-		p->code_rate_HP = FEC_1_2;
-		break;
-	case 1:
-		p->code_rate_HP = FEC_2_3;
-		break;
-	case 2:
-		p->code_rate_HP = FEC_3_4;
-		break;
-	case 3:
-		p->code_rate_HP = FEC_5_6;
-		break;
-	case 4:
-		p->code_rate_HP = FEC_7_8;
-		break;
-	}
-
-	val = tda10048_readreg(state, TDA10048_OUT_CONF3);
-	switch (val & 0x07) {
-	case 0:
-		p->code_rate_LP = FEC_1_2;
-		break;
-	case 1:
-		p->code_rate_LP = FEC_2_3;
-		break;
-	case 2:
-		p->code_rate_LP = FEC_3_4;
-		break;
-	case 3:
-		p->code_rate_LP = FEC_5_6;
-		break;
-	case 4:
-		p->code_rate_LP = FEC_7_8;
-		break;
-	}
-
-	val = tda10048_readreg(state, TDA10048_OUT_CONF1);
-	switch ((val & 0x0c) >> 2) {
-	case 0:
-		p->guard_interval = GUARD_INTERVAL_1_32;
-		break;
-	case 1:
-		p->guard_interval = GUARD_INTERVAL_1_16;
-		break;
-	case 2:
-		p->guard_interval =  GUARD_INTERVAL_1_8;
-		break;
-	case 3:
-		p->guard_interval =  GUARD_INTERVAL_1_4;
-		break;
-	}
-	switch (val & 0x03) {
-	case 0:
-		p->transmission_mode = TRANSMISSION_MODE_2K;
-		break;
-	case 1:
-		p->transmission_mode = TRANSMISSION_MODE_8K;
-		break;
-	}
-
-	return 0;
-}
-
-static int tda10048_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct tda10048_state *state = fe->demodulator_priv;
-	struct tda10048_config *config = &state->config;
-	dprintk(1, "%s(%d)\n", __func__, enable);
-
-	if (config->disable_gate_access)
-		return 0;
-
-	if (enable)
-		return tda10048_writereg(state, TDA10048_CONF_C4_1,
-			tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x02);
-	else
-		return tda10048_writereg(state, TDA10048_CONF_C4_1,
-			tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xfd);
-}
-
-static int tda10048_output_mode(struct dvb_frontend *fe, int serial)
-{
-	struct tda10048_state *state = fe->demodulator_priv;
-	dprintk(1, "%s(%d)\n", __func__, serial);
-
-	/* Ensure pins are out of tri-state */
-	tda10048_writereg(state, TDA10048_CONF_TRISTATE1, 0x21);
-	tda10048_writereg(state, TDA10048_CONF_TRISTATE2, 0x00);
-
-	if (serial) {
-		tda10048_writereg(state, TDA10048_IC_MODE, 0x80 | 0x20);
-		tda10048_writereg(state, TDA10048_CONF_TS2, 0xc0);
-	} else {
-		tda10048_writereg(state, TDA10048_IC_MODE, 0x00);
-		tda10048_writereg(state, TDA10048_CONF_TS2, 0x01);
-	}
-
-	return 0;
-}
-
-/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-/* TODO: Support manual tuning with specific params */
-static int tda10048_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct tda10048_state *state = fe->demodulator_priv;
-
-	dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency);
-
-	/* Update the I/F pll's if the bandwidth changes */
-	if (p->bandwidth_hz != state->bandwidth) {
-		tda10048_set_if(fe, p->bandwidth_hz);
-		tda10048_set_bandwidth(fe, p->bandwidth_hz);
-	}
-
-	if (fe->ops.tuner_ops.set_params) {
-
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-
-		fe->ops.tuner_ops.set_params(fe);
-
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	/* Enable demod TPS auto detection and begin acquisition */
-	tda10048_writereg(state, TDA10048_AUTO, 0x57);
-	/* trigger cber and vber acquisition */
-	tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x3B);
-
-	return 0;
-}
-
-/* Establish sane defaults and load firmware. */
-static int tda10048_init(struct dvb_frontend *fe)
-{
-	struct tda10048_state *state = fe->demodulator_priv;
-	struct tda10048_config *config = &state->config;
-	int ret = 0, i;
-
-	dprintk(1, "%s()\n", __func__);
-
-	/* PLL */
-	init_tab[4].data = (u8)(state->pll_mfactor);
-	init_tab[5].data = (u8)(state->pll_nfactor) | 0x40;
-
-	/* Apply register defaults */
-	for (i = 0; i < ARRAY_SIZE(init_tab); i++)
-		tda10048_writereg(state, init_tab[i].reg, init_tab[i].data);
-
-	if (state->fwloaded == 0)
-		ret = tda10048_firmware_upload(fe);
-
-	/* Set either serial or parallel */
-	tda10048_output_mode(fe, config->output_mode);
-
-	/* Set inversion */
-	tda10048_set_inversion(fe, config->inversion);
-
-	/* Establish default RF values */
-	tda10048_set_if(fe, 8000000);
-	tda10048_set_bandwidth(fe, 8000000);
-
-	/* Ensure we leave the gate closed */
-	tda10048_i2c_gate_ctrl(fe, 0);
-
-	return ret;
-}
-
-static int tda10048_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct tda10048_state *state = fe->demodulator_priv;
-	u8 reg;
-
-	*status = 0;
-
-	reg = tda10048_readreg(state, TDA10048_SYNC_STATUS);
-
-	dprintk(1, "%s() status =0x%02x\n", __func__, reg);
-
-	if (reg & 0x02)
-		*status |= FE_HAS_CARRIER;
-
-	if (reg & 0x04)
-		*status |= FE_HAS_SIGNAL;
-
-	if (reg & 0x08) {
-		*status |= FE_HAS_LOCK;
-		*status |= FE_HAS_VITERBI;
-		*status |= FE_HAS_SYNC;
-	}
-
-	return 0;
-}
-
-static int tda10048_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct tda10048_state *state = fe->demodulator_priv;
-	static u32 cber_current;
-	u32 cber_nmax;
-	u64 cber_tmp;
-
-	dprintk(1, "%s()\n", __func__);
-
-	/* update cber on interrupt */
-	if (tda10048_readreg(state, TDA10048_SOFT_IT_C3) & 0x01) {
-		cber_tmp = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 |
-			tda10048_readreg(state, TDA10048_CBER_LSB);
-		cber_nmax = tda10048_readreg(state, TDA10048_CBER_NMAX_MSB) << 8 |
-			tda10048_readreg(state, TDA10048_CBER_NMAX_LSB);
-		cber_tmp *= 100000000;
-		cber_tmp *= 2;
-		cber_tmp = div_u64(cber_tmp, (cber_nmax * 32) + 1);
-		cber_current = (u32)cber_tmp;
-		/* retrigger cber acquisition */
-		tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x39);
-	}
-	/* actual cber is (*ber)/1e8 */
-	*ber = cber_current;
-
-	return 0;
-}
-
-static int tda10048_read_signal_strength(struct dvb_frontend *fe,
-	u16 *signal_strength)
-{
-	struct tda10048_state *state = fe->demodulator_priv;
-	u8 v;
-
-	dprintk(1, "%s()\n", __func__);
-
-	*signal_strength = 65535;
-
-	v = tda10048_readreg(state, TDA10048_NP_OUT);
-	if (v > 0)
-		*signal_strength -= (v << 8) | v;
-
-	return 0;
-}
-
-/* SNR lookup table */
-static struct snr_tab {
-	u8 val;
-	u8 data;
-} snr_tab[] = {
-	{   0,   0 },
-	{   1, 246 },
-	{   2, 215 },
-	{   3, 198 },
-	{   4, 185 },
-	{   5, 176 },
-	{   6, 168 },
-	{   7, 161 },
-	{   8, 155 },
-	{   9, 150 },
-	{  10, 146 },
-	{  11, 141 },
-	{  12, 138 },
-	{  13, 134 },
-	{  14, 131 },
-	{  15, 128 },
-	{  16, 125 },
-	{  17, 122 },
-	{  18, 120 },
-	{  19, 118 },
-	{  20, 115 },
-	{  21, 113 },
-	{  22, 111 },
-	{  23, 109 },
-	{  24, 107 },
-	{  25, 106 },
-	{  26, 104 },
-	{  27, 102 },
-	{  28, 101 },
-	{  29,  99 },
-	{  30,  98 },
-	{  31,  96 },
-	{  32,  95 },
-	{  33,  94 },
-	{  34,  92 },
-	{  35,  91 },
-	{  36,  90 },
-	{  37,  89 },
-	{  38,  88 },
-	{  39,  86 },
-	{  40,  85 },
-	{  41,  84 },
-	{  42,  83 },
-	{  43,  82 },
-	{  44,  81 },
-	{  45,  80 },
-	{  46,  79 },
-	{  47,  78 },
-	{  48,  77 },
-	{  49,  76 },
-	{  50,  76 },
-	{  51,  75 },
-	{  52,  74 },
-	{  53,  73 },
-	{  54,  72 },
-	{  56,  71 },
-	{  57,  70 },
-	{  58,  69 },
-	{  60,  68 },
-	{  61,  67 },
-	{  63,  66 },
-	{  64,  65 },
-	{  66,  64 },
-	{  67,  63 },
-	{  68,  62 },
-	{  69,  62 },
-	{  70,  61 },
-	{  72,  60 },
-	{  74,  59 },
-	{  75,  58 },
-	{  77,  57 },
-	{  79,  56 },
-	{  81,  55 },
-	{  83,  54 },
-	{  85,  53 },
-	{  87,  52 },
-	{  89,  51 },
-	{  91,  50 },
-	{  93,  49 },
-	{  95,  48 },
-	{  97,  47 },
-	{ 100,  46 },
-	{ 102,  45 },
-	{ 104,  44 },
-	{ 107,  43 },
-	{ 109,  42 },
-	{ 112,  41 },
-	{ 114,  40 },
-	{ 117,  39 },
-	{ 120,  38 },
-	{ 123,  37 },
-	{ 125,  36 },
-	{ 128,  35 },
-	{ 131,  34 },
-	{ 134,  33 },
-	{ 138,  32 },
-	{ 141,  31 },
-	{ 144,  30 },
-	{ 147,  29 },
-	{ 151,  28 },
-	{ 154,  27 },
-	{ 158,  26 },
-	{ 162,  25 },
-	{ 165,  24 },
-	{ 169,  23 },
-	{ 173,  22 },
-	{ 177,  21 },
-	{ 181,  20 },
-	{ 186,  19 },
-	{ 190,  18 },
-	{ 194,  17 },
-	{ 199,  16 },
-	{ 204,  15 },
-	{ 208,  14 },
-	{ 213,  13 },
-	{ 218,  12 },
-	{ 223,  11 },
-	{ 229,  10 },
-	{ 234,   9 },
-	{ 239,   8 },
-	{ 245,   7 },
-	{ 251,   6 },
-	{ 255,   5 },
-};
-
-static int tda10048_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct tda10048_state *state = fe->demodulator_priv;
-	u8 v;
-	int i, ret = -EINVAL;
-
-	dprintk(1, "%s()\n", __func__);
-
-	v = tda10048_readreg(state, TDA10048_NP_OUT);
-	for (i = 0; i < ARRAY_SIZE(snr_tab); i++) {
-		if (v <= snr_tab[i].val) {
-			*snr = snr_tab[i].data;
-			ret = 0;
-			break;
-		}
-	}
-
-	return ret;
-}
-
-static int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct tda10048_state *state = fe->demodulator_priv;
-
-	dprintk(1, "%s()\n", __func__);
-
-	*ucblocks = tda10048_readreg(state, TDA10048_UNCOR_CPT_MSB) << 8 |
-		tda10048_readreg(state, TDA10048_UNCOR_CPT_LSB);
-	/* clear the uncorrected TS packets counter when saturated */
-	if (*ucblocks == 0xFFFF)
-		tda10048_writereg(state, TDA10048_UNCOR_CTRL, 0x80);
-
-	return 0;
-}
-
-static int tda10048_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct tda10048_state *state = fe->demodulator_priv;
-
-	dprintk(1, "%s()\n", __func__);
-
-	p->inversion = tda10048_readreg(state, TDA10048_CONF_C1_1)
-		& 0x20 ? INVERSION_ON : INVERSION_OFF;
-
-	return tda10048_get_tps(state, p);
-}
-
-static int tda10048_get_tune_settings(struct dvb_frontend *fe,
-	struct dvb_frontend_tune_settings *tune)
-{
-	tune->min_delay_ms = 1000;
-	return 0;
-}
-
-static void tda10048_release(struct dvb_frontend *fe)
-{
-	struct tda10048_state *state = fe->demodulator_priv;
-	dprintk(1, "%s()\n", __func__);
-	kfree(state);
-}
-
-static void tda10048_establish_defaults(struct dvb_frontend *fe)
-{
-	struct tda10048_state *state = fe->demodulator_priv;
-	struct tda10048_config *config = &state->config;
-
-	/* Validate/default the config */
-	if (config->dtv6_if_freq_khz == 0) {
-		config->dtv6_if_freq_khz = TDA10048_IF_4300;
-		printk(KERN_WARNING "%s() tda10048_config.dtv6_if_freq_khz "
-			"is not set (defaulting to %d)\n",
-			__func__,
-			config->dtv6_if_freq_khz);
-	}
-
-	if (config->dtv7_if_freq_khz == 0) {
-		config->dtv7_if_freq_khz = TDA10048_IF_4300;
-		printk(KERN_WARNING "%s() tda10048_config.dtv7_if_freq_khz "
-			"is not set (defaulting to %d)\n",
-			__func__,
-			config->dtv7_if_freq_khz);
-	}
-
-	if (config->dtv8_if_freq_khz == 0) {
-		config->dtv8_if_freq_khz = TDA10048_IF_4300;
-		printk(KERN_WARNING "%s() tda10048_config.dtv8_if_freq_khz "
-			"is not set (defaulting to %d)\n",
-			__func__,
-			config->dtv8_if_freq_khz);
-	}
-
-	if (config->clk_freq_khz == 0) {
-		config->clk_freq_khz = TDA10048_CLK_16000;
-		printk(KERN_WARNING "%s() tda10048_config.clk_freq_khz "
-			"is not set (defaulting to %d)\n",
-			__func__,
-			config->clk_freq_khz);
-	}
-}
-
-static struct dvb_frontend_ops tda10048_ops;
-
-struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
-	struct i2c_adapter *i2c)
-{
-	struct tda10048_state *state = NULL;
-
-	dprintk(1, "%s()\n", __func__);
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct tda10048_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* setup the state and clone the config */
-	memcpy(&state->config, config, sizeof(*config));
-	state->i2c = i2c;
-	state->fwloaded = config->no_firmware;
-	state->bandwidth = 8000000;
-
-	/* check if the demod is present */
-	if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048)
-		goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &tda10048_ops,
-		sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-
-	/* set pll */
-	if (config->set_pll) {
-		state->pll_mfactor = config->pll_m;
-		state->pll_nfactor = config->pll_n;
-		state->pll_pfactor = config->pll_p;
-	} else {
-		state->pll_mfactor = 10;
-		state->pll_nfactor = 3;
-		state->pll_pfactor = 0;
-	}
-
-	/* Establish any defaults the the user didn't pass */
-	tda10048_establish_defaults(&state->frontend);
-
-	/* Set the xtal and freq defaults */
-	if (tda10048_set_if(&state->frontend, 8000000) != 0)
-		goto error;
-
-	/* Default bandwidth */
-	if (tda10048_set_bandwidth(&state->frontend, 8000000) != 0)
-		goto error;
-
-	/* Leave the gate closed */
-	tda10048_i2c_gate_ctrl(&state->frontend, 0);
-
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(tda10048_attach);
-
-static struct dvb_frontend_ops tda10048_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name			= "NXP TDA10048HN DVB-T",
-		.frequency_min		= 177000000,
-		.frequency_max		= 858000000,
-		.frequency_stepsize	= 166666,
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-		FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-		FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-		FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
-	},
-
-	.release = tda10048_release,
-	.init = tda10048_init,
-	.i2c_gate_ctrl = tda10048_i2c_gate_ctrl,
-	.set_frontend = tda10048_set_frontend,
-	.get_frontend = tda10048_get_frontend,
-	.get_tune_settings = tda10048_get_tune_settings,
-	.read_status = tda10048_read_status,
-	.read_ber = tda10048_read_ber,
-	.read_signal_strength = tda10048_read_signal_strength,
-	.read_snr = tda10048_read_snr,
-	.read_ucblocks = tda10048_read_ucblocks,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Enable verbose debug messages");
-
-MODULE_DESCRIPTION("NXP TDA10048HN DVB-T Demodulator driver");
-MODULE_AUTHOR("Steven Toth");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda10048.h b/drivers/media/dvb/frontends/tda10048.h
deleted file mode 100644
index fb2ef5a..0000000
--- a/drivers/media/dvb/frontends/tda10048.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
-    NXP TDA10048HN DVB OFDM demodulator driver
-
-    Copyright (C) 2009 Steven Toth <stoth@kernellabs.com>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef TDA10048_H
-#define TDA10048_H
-
-#include <linux/dvb/frontend.h>
-#include <linux/firmware.h>
-
-struct tda10048_config {
-
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* serial/parallel output */
-#define TDA10048_PARALLEL_OUTPUT 0
-#define TDA10048_SERIAL_OUTPUT   1
-	u8 output_mode;
-
-#define TDA10048_BULKWRITE_200	200
-#define TDA10048_BULKWRITE_50	50
-	u8 fwbulkwritelen;
-
-	/* Spectral Inversion */
-#define TDA10048_INVERSION_OFF 0
-#define TDA10048_INVERSION_ON  1
-	u8 inversion;
-
-#define TDA10048_IF_3300  3300
-#define TDA10048_IF_3500  3500
-#define TDA10048_IF_3800  3800
-#define TDA10048_IF_4000  4000
-#define TDA10048_IF_4300  4300
-#define TDA10048_IF_4500  4500
-#define TDA10048_IF_4750  4750
-#define TDA10048_IF_5000  5000
-#define TDA10048_IF_36130 36130
-	u16 dtv6_if_freq_khz;
-	u16 dtv7_if_freq_khz;
-	u16 dtv8_if_freq_khz;
-
-#define TDA10048_CLK_4000  4000
-#define TDA10048_CLK_16000 16000
-	u16 clk_freq_khz;
-
-	/* Disable I2C gate access */
-	u8 disable_gate_access;
-
-	bool no_firmware;
-
-	bool set_pll;
-	u8 pll_m;
-	u8 pll_p;
-	u8 pll_n;
-};
-
-#if defined(CONFIG_DVB_TDA10048) || \
-	(defined(CONFIG_DVB_TDA10048_MODULE) && defined(MODULE))
-extern struct dvb_frontend *tda10048_attach(
-	const struct tda10048_config *config,
-	struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *tda10048_attach(
-	const struct tda10048_config *config,
-	struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_TDA10048 */
-
-#endif /* TDA10048_H */
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
deleted file mode 100644
index 35d72b4..0000000
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ /dev/null
@@ -1,1381 +0,0 @@
-  /*
-     Driver for Philips tda1004xh OFDM Demodulator
-
-     (c) 2003, 2004 Andrew de Quincey & Robert Schlabbach
-
-     This program is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published by
-     the Free Software Foundation; either version 2 of the License, or
-     (at your option) any later version.
-
-     This program is distributed in the hope that it will be useful,
-     but WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-     GNU General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with this program; if not, write to the Free Software
-     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-   */
-/*
- * This driver needs external firmware. Please use the commands
- * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
- * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
- * download/extract them, and then copy them to /usr/lib/hotplug/firmware
- * or /lib/firmware (depending on configuration of firmware hotplug).
- */
-#define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw"
-#define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw"
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/jiffies.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "tda1004x.h"
-
-static int debug;
-#define dprintk(args...) \
-	do { \
-		if (debug) printk(KERN_DEBUG "tda1004x: " args); \
-	} while (0)
-
-#define TDA1004X_CHIPID		 0x00
-#define TDA1004X_AUTO		 0x01
-#define TDA1004X_IN_CONF1	 0x02
-#define TDA1004X_IN_CONF2	 0x03
-#define TDA1004X_OUT_CONF1	 0x04
-#define TDA1004X_OUT_CONF2	 0x05
-#define TDA1004X_STATUS_CD	 0x06
-#define TDA1004X_CONFC4		 0x07
-#define TDA1004X_DSSPARE2	 0x0C
-#define TDA10045H_CODE_IN	 0x0D
-#define TDA10045H_FWPAGE	 0x0E
-#define TDA1004X_SCAN_CPT	 0x10
-#define TDA1004X_DSP_CMD	 0x11
-#define TDA1004X_DSP_ARG	 0x12
-#define TDA1004X_DSP_DATA1	 0x13
-#define TDA1004X_DSP_DATA2	 0x14
-#define TDA1004X_CONFADC1	 0x15
-#define TDA1004X_CONFC1		 0x16
-#define TDA10045H_S_AGC		 0x1a
-#define TDA10046H_AGC_TUN_LEVEL	 0x1a
-#define TDA1004X_SNR		 0x1c
-#define TDA1004X_CONF_TS1	 0x1e
-#define TDA1004X_CONF_TS2	 0x1f
-#define TDA1004X_CBER_RESET	 0x20
-#define TDA1004X_CBER_MSB	 0x21
-#define TDA1004X_CBER_LSB	 0x22
-#define TDA1004X_CVBER_LUT	 0x23
-#define TDA1004X_VBER_MSB	 0x24
-#define TDA1004X_VBER_MID	 0x25
-#define TDA1004X_VBER_LSB	 0x26
-#define TDA1004X_UNCOR		 0x27
-
-#define TDA10045H_CONFPLL_P	 0x2D
-#define TDA10045H_CONFPLL_M_MSB	 0x2E
-#define TDA10045H_CONFPLL_M_LSB	 0x2F
-#define TDA10045H_CONFPLL_N	 0x30
-
-#define TDA10046H_CONFPLL1	 0x2D
-#define TDA10046H_CONFPLL2	 0x2F
-#define TDA10046H_CONFPLL3	 0x30
-#define TDA10046H_TIME_WREF1	 0x31
-#define TDA10046H_TIME_WREF2	 0x32
-#define TDA10046H_TIME_WREF3	 0x33
-#define TDA10046H_TIME_WREF4	 0x34
-#define TDA10046H_TIME_WREF5	 0x35
-
-#define TDA10045H_UNSURW_MSB	 0x31
-#define TDA10045H_UNSURW_LSB	 0x32
-#define TDA10045H_WREF_MSB	 0x33
-#define TDA10045H_WREF_MID	 0x34
-#define TDA10045H_WREF_LSB	 0x35
-#define TDA10045H_MUXOUT	 0x36
-#define TDA1004X_CONFADC2	 0x37
-
-#define TDA10045H_IOFFSET	 0x38
-
-#define TDA10046H_CONF_TRISTATE1 0x3B
-#define TDA10046H_CONF_TRISTATE2 0x3C
-#define TDA10046H_CONF_POLARITY	 0x3D
-#define TDA10046H_FREQ_OFFSET	 0x3E
-#define TDA10046H_GPIO_OUT_SEL	 0x41
-#define TDA10046H_GPIO_SELECT	 0x42
-#define TDA10046H_AGC_CONF	 0x43
-#define TDA10046H_AGC_THR	 0x44
-#define TDA10046H_AGC_RENORM	 0x45
-#define TDA10046H_AGC_GAINS	 0x46
-#define TDA10046H_AGC_TUN_MIN	 0x47
-#define TDA10046H_AGC_TUN_MAX	 0x48
-#define TDA10046H_AGC_IF_MIN	 0x49
-#define TDA10046H_AGC_IF_MAX	 0x4A
-
-#define TDA10046H_FREQ_PHY2_MSB	 0x4D
-#define TDA10046H_FREQ_PHY2_LSB	 0x4E
-
-#define TDA10046H_CVBER_CTRL	 0x4F
-#define TDA10046H_AGC_IF_LEVEL	 0x52
-#define TDA10046H_CODE_CPT	 0x57
-#define TDA10046H_CODE_IN	 0x58
-
-
-static int tda1004x_write_byteI(struct tda1004x_state *state, int reg, int data)
-{
-	int ret;
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
-
-	dprintk("%s: reg=0x%x, data=0x%x\n", __func__, reg, data);
-
-	msg.addr = state->config->demod_address;
-	ret = i2c_transfer(state->i2c, &msg, 1);
-
-	if (ret != 1)
-		dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
-			__func__, reg, data, ret);
-
-	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__,
-		reg, data, ret);
-	return (ret != 1) ? -1 : 0;
-}
-
-static int tda1004x_read_byte(struct tda1004x_state *state, int reg)
-{
-	int ret;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
-	struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 },
-				{ .flags = I2C_M_RD, .buf = b1, .len = 1 }};
-
-	dprintk("%s: reg=0x%x\n", __func__, reg);
-
-	msg[0].addr = state->config->demod_address;
-	msg[1].addr = state->config->demod_address;
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2) {
-		dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg,
-			ret);
-		return -EINVAL;
-	}
-
-	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__,
-		reg, b1[0], ret);
-	return b1[0];
-}
-
-static int tda1004x_write_mask(struct tda1004x_state *state, int reg, int mask, int data)
-{
-	int val;
-	dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __func__, reg,
-		mask, data);
-
-	// read a byte and check
-	val = tda1004x_read_byte(state, reg);
-	if (val < 0)
-		return val;
-
-	// mask if off
-	val = val & ~mask;
-	val |= data & 0xff;
-
-	// write it out again
-	return tda1004x_write_byteI(state, reg, val);
-}
-
-static int tda1004x_write_buf(struct tda1004x_state *state, int reg, unsigned char *buf, int len)
-{
-	int i;
-	int result;
-
-	dprintk("%s: reg=0x%x, len=0x%x\n", __func__, reg, len);
-
-	result = 0;
-	for (i = 0; i < len; i++) {
-		result = tda1004x_write_byteI(state, reg + i, buf[i]);
-		if (result != 0)
-			break;
-	}
-
-	return result;
-}
-
-static int tda1004x_enable_tuner_i2c(struct tda1004x_state *state)
-{
-	int result;
-	dprintk("%s\n", __func__);
-
-	result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2);
-	msleep(20);
-	return result;
-}
-
-static int tda1004x_disable_tuner_i2c(struct tda1004x_state *state)
-{
-	dprintk("%s\n", __func__);
-
-	return tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 0);
-}
-
-static int tda10045h_set_bandwidth(struct tda1004x_state *state,
-				   u32 bandwidth)
-{
-	static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f };
-	static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb };
-	static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 };
-
-	switch (bandwidth) {
-	case 6000000:
-		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz));
-		break;
-
-	case 7000000:
-		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz));
-		break;
-
-	case 8000000:
-		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz));
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	tda1004x_write_byteI(state, TDA10045H_IOFFSET, 0);
-
-	return 0;
-}
-
-static int tda10046h_set_bandwidth(struct tda1004x_state *state,
-				   u32 bandwidth)
-{
-	static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 };
-	static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f };
-	static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d };
-
-	static u8 bandwidth_6mhz_48M[] = { 0x70, 0x02, 0x49, 0x24, 0x92 };
-	static u8 bandwidth_7mhz_48M[] = { 0x60, 0x02, 0xaa, 0xaa, 0xab };
-	static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 };
-	int tda10046_clk53m;
-
-	if ((state->config->if_freq == TDA10046_FREQ_045) ||
-	    (state->config->if_freq == TDA10046_FREQ_052))
-		tda10046_clk53m = 0;
-	else
-		tda10046_clk53m = 1;
-	switch (bandwidth) {
-	case 6000000:
-		if (tda10046_clk53m)
-			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M,
-						  sizeof(bandwidth_6mhz_53M));
-		else
-			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_48M,
-						  sizeof(bandwidth_6mhz_48M));
-		if (state->config->if_freq == TDA10046_FREQ_045) {
-			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a);
-			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xab);
-		}
-		break;
-
-	case 7000000:
-		if (tda10046_clk53m)
-			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M,
-						  sizeof(bandwidth_7mhz_53M));
-		else
-			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_48M,
-						  sizeof(bandwidth_7mhz_48M));
-		if (state->config->if_freq == TDA10046_FREQ_045) {
-			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
-			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
-		}
-		break;
-
-	case 8000000:
-		if (tda10046_clk53m)
-			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M,
-						  sizeof(bandwidth_8mhz_53M));
-		else
-			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_48M,
-						  sizeof(bandwidth_8mhz_48M));
-		if (state->config->if_freq == TDA10046_FREQ_045) {
-			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
-			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x55);
-		}
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int tda1004x_do_upload(struct tda1004x_state *state,
-			      const unsigned char *mem, unsigned int len,
-			      u8 dspCodeCounterReg, u8 dspCodeInReg)
-{
-	u8 buf[65];
-	struct i2c_msg fw_msg = { .flags = 0, .buf = buf, .len = 0 };
-	int tx_size;
-	int pos = 0;
-
-	/* clear code counter */
-	tda1004x_write_byteI(state, dspCodeCounterReg, 0);
-	fw_msg.addr = state->config->demod_address;
-
-	buf[0] = dspCodeInReg;
-	while (pos != len) {
-		// work out how much to send this time
-		tx_size = len - pos;
-		if (tx_size > 0x10)
-			tx_size = 0x10;
-
-		// send the chunk
-		memcpy(buf + 1, mem + pos, tx_size);
-		fw_msg.len = tx_size + 1;
-		if (i2c_transfer(state->i2c, &fw_msg, 1) != 1) {
-			printk(KERN_ERR "tda1004x: Error during firmware upload\n");
-			return -EIO;
-		}
-		pos += tx_size;
-
-		dprintk("%s: fw_pos=0x%x\n", __func__, pos);
-	}
-	// give the DSP a chance to settle 03/10/05 Hac
-	msleep(100);
-
-	return 0;
-}
-
-static int tda1004x_check_upload_ok(struct tda1004x_state *state)
-{
-	u8 data1, data2;
-	unsigned long timeout;
-
-	if (state->demod_type == TDA1004X_DEMOD_TDA10046) {
-		timeout = jiffies + 2 * HZ;
-		while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) {
-			if (time_after(jiffies, timeout)) {
-				printk(KERN_ERR "tda1004x: timeout waiting for DSP ready\n");
-				break;
-			}
-			msleep(1);
-		}
-	} else
-		msleep(100);
-
-	// check upload was OK
-	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP
-	tda1004x_write_byteI(state, TDA1004X_DSP_CMD, 0x67);
-
-	data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1);
-	data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2);
-	if (data1 != 0x67 || data2 < 0x20 || data2 > 0x2e) {
-		printk(KERN_INFO "tda1004x: found firmware revision %x -- invalid\n", data2);
-		return -EIO;
-	}
-	printk(KERN_INFO "tda1004x: found firmware revision %x -- ok\n", data2);
-	return 0;
-}
-
-static int tda10045_fwupload(struct dvb_frontend* fe)
-{
-	struct tda1004x_state* state = fe->demodulator_priv;
-	int ret;
-	const struct firmware *fw;
-
-	/* don't re-upload unless necessary */
-	if (tda1004x_check_upload_ok(state) == 0)
-		return 0;
-
-	/* request the firmware, this will block until someone uploads it */
-	printk(KERN_INFO "tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE);
-	ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
-	if (ret) {
-		printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
-		return ret;
-	}
-
-	/* reset chip */
-	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0);
-	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8);
-	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0);
-	msleep(10);
-
-	/* set parameters */
-	tda10045h_set_bandwidth(state, 8000000);
-
-	ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN);
-	release_firmware(fw);
-	if (ret)
-		return ret;
-	printk(KERN_INFO "tda1004x: firmware upload complete\n");
-
-	/* wait for DSP to initialise */
-	/* DSPREADY doesn't seem to work on the TDA10045H */
-	msleep(100);
-
-	return tda1004x_check_upload_ok(state);
-}
-
-static void tda10046_init_plls(struct dvb_frontend* fe)
-{
-	struct tda1004x_state* state = fe->demodulator_priv;
-	int tda10046_clk53m;
-
-	if ((state->config->if_freq == TDA10046_FREQ_045) ||
-	    (state->config->if_freq == TDA10046_FREQ_052))
-		tda10046_clk53m = 0;
-	else
-		tda10046_clk53m = 1;
-
-	tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
-	if(tda10046_clk53m) {
-		printk(KERN_INFO "tda1004x: setting up plls for 53MHz sampling clock\n");
-		tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x08); // PLL M = 8
-	} else {
-		printk(KERN_INFO "tda1004x: setting up plls for 48MHz sampling clock\n");
-		tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3
-	}
-	if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
-		dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __func__);
-		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
-	} else {
-		dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __func__);
-		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3
-	}
-	if(tda10046_clk53m)
-		tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x67);
-	else
-		tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x72);
-	/* Note clock frequency is handled implicitly */
-	switch (state->config->if_freq) {
-	case TDA10046_FREQ_045:
-		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
-		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
-		break;
-	case TDA10046_FREQ_052:
-		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
-		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xc7);
-		break;
-	case TDA10046_FREQ_3617:
-		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
-		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x59);
-		break;
-	case TDA10046_FREQ_3613:
-		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
-		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f);
-		break;
-	}
-	tda10046h_set_bandwidth(state, 8000000); /* default bandwidth 8 MHz */
-	/* let the PLLs settle */
-	msleep(120);
-}
-
-static int tda10046_fwupload(struct dvb_frontend* fe)
-{
-	struct tda1004x_state* state = fe->demodulator_priv;
-	int ret, confc4;
-	const struct firmware *fw;
-
-	/* reset + wake up chip */
-	if (state->config->xtal_freq == TDA10046_XTAL_4M) {
-		confc4 = 0;
-	} else {
-		dprintk("%s: 16MHz Xtal, reducing I2C speed\n", __func__);
-		confc4 = 0x80;
-	}
-	tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4);
-
-	tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
-	/* set GPIO 1 and 3 */
-	if (state->config->gpio_config != TDA10046_GPTRI) {
-		tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0x33);
-		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, state->config->gpio_config &0x0f);
-	}
-	/* let the clocks recover from sleep */
-	msleep(10);
-
-	/* The PLLs need to be reprogrammed after sleep */
-	tda10046_init_plls(fe);
-	tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0);
-
-	/* don't re-upload unless necessary */
-	if (tda1004x_check_upload_ok(state) == 0)
-		return 0;
-
-	/*
-	   For i2c normal work, we need to slow down the bus speed.
-	   However, the slow down breaks the eeprom firmware load.
-	   So, use normal speed for eeprom booting and then restore the
-	   i2c speed after that. Tested with MSI TV @nyware A/D board,
-	   that comes with firmware version 29 inside their eeprom.
-
-	   It should also be noticed that no other I2C transfer should
-	   be in course while booting from eeprom, otherwise, tda10046
-	   goes into an instable state. So, proper locking are needed
-	   at the i2c bus master.
-	 */
-	printk(KERN_INFO "tda1004x: trying to boot from eeprom\n");
-	tda1004x_write_byteI(state, TDA1004X_CONFC4, 4);
-	msleep(300);
-	tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4);
-
-	/* Checks if eeprom firmware went without troubles */
-	if (tda1004x_check_upload_ok(state) == 0)
-		return 0;
-
-	/* eeprom firmware didn't work. Load one manually. */
-
-	if (state->config->request_firmware != NULL) {
-		/* request the firmware, this will block until someone uploads it */
-		printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
-		ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
-		if (ret) {
-			/* remain compatible to old bug: try to load with tda10045 image name */
-			ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
-			if (ret) {
-				printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
-				return ret;
-			} else {
-				printk(KERN_INFO "tda1004x: please rename the firmware file to %s\n",
-						  TDA10046_DEFAULT_FIRMWARE);
-			}
-		}
-	} else {
-		printk(KERN_ERR "tda1004x: no request function defined, can't upload from file\n");
-		return -EIO;
-	}
-	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
-	ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
-	release_firmware(fw);
-	return tda1004x_check_upload_ok(state);
-}
-
-static int tda1004x_encode_fec(int fec)
-{
-	// convert known FEC values
-	switch (fec) {
-	case FEC_1_2:
-		return 0;
-	case FEC_2_3:
-		return 1;
-	case FEC_3_4:
-		return 2;
-	case FEC_5_6:
-		return 3;
-	case FEC_7_8:
-		return 4;
-	}
-
-	// unsupported
-	return -EINVAL;
-}
-
-static int tda1004x_decode_fec(int tdafec)
-{
-	// convert known FEC values
-	switch (tdafec) {
-	case 0:
-		return FEC_1_2;
-	case 1:
-		return FEC_2_3;
-	case 2:
-		return FEC_3_4;
-	case 3:
-		return FEC_5_6;
-	case 4:
-		return FEC_7_8;
-	}
-
-	// unsupported
-	return -1;
-}
-
-static int tda1004x_write(struct dvb_frontend* fe, const u8 buf[], int len)
-{
-	struct tda1004x_state* state = fe->demodulator_priv;
-
-	if (len != 2)
-		return -EINVAL;
-
-	return tda1004x_write_byteI(state, buf[0], buf[1]);
-}
-
-static int tda10045_init(struct dvb_frontend* fe)
-{
-	struct tda1004x_state* state = fe->demodulator_priv;
-
-	dprintk("%s\n", __func__);
-
-	if (tda10045_fwupload(fe)) {
-		printk("tda1004x: firmware upload failed\n");
-		return -EIO;
-	}
-
-	tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
-
-	// tda setup
-	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
-	tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
-	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0); // set polarity of VAGC signal
-	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0x80); // enable pulse killer
-	tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); // enable auto offset
-	tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0x0); // no frequency offset
-	tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 0); // setup MPEG2 TS interface
-	tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0); // setup MPEG2 TS interface
-	tda1004x_write_mask(state, TDA1004X_VBER_MSB, 0xe0, 0xa0); // 10^6 VBER measurement bits
-	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x10, 0); // VAGC polarity
-	tda1004x_write_byteI(state, TDA1004X_CONFADC1, 0x2e);
-
-	tda1004x_write_mask(state, 0x1f, 0x01, state->config->invert_oclk);
-
-	return 0;
-}
-
-static int tda10046_init(struct dvb_frontend* fe)
-{
-	struct tda1004x_state* state = fe->demodulator_priv;
-	dprintk("%s\n", __func__);
-
-	if (tda10046_fwupload(fe)) {
-		printk("tda1004x: firmware upload failed\n");
-			return -EIO;
-	}
-
-	// tda setup
-	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
-	tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87);    // 100 ppm crystal, select HP stream
-	tda1004x_write_byteI(state, TDA1004X_CONFC1, 0x88);      // enable pulse killer
-
-	switch (state->config->agc_config) {
-	case TDA10046_AGC_DEFAULT:
-		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup
-		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
-		break;
-	case TDA10046_AGC_IFO_AUTO_NEG:
-		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
-		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
-		break;
-	case TDA10046_AGC_IFO_AUTO_POS:
-		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
-		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x00);  // set AGC polarities
-		break;
-	case TDA10046_AGC_TDA827X:
-		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02);   // AGC setup
-		tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70);    // AGC Threshold
-		tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
-		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
-		break;
-	}
-	if (state->config->ts_mode == 0) {
-		tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x40);
-		tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
-	} else {
-		tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x80);
-		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x10,
-							state->config->invert_oclk << 4);
-	}
-	tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
-	tda1004x_write_mask (state, TDA10046H_CONF_TRISTATE1, 0x3e, 0x38); // Turn IF AGC output on
-	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0);	  // }
-	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
-	tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0);	  // }
-	tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff);  // }
-	tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 0x12); // IF gain 2, TUN gain 1
-	tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits
-	tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
-	tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
-	// tda1004x_write_mask(state, 0x50, 0x80, 0x80);         // handle out of guard echoes
-
-	return 0;
-}
-
-static int tda1004x_set_fe(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
-	struct tda1004x_state* state = fe->demodulator_priv;
-	int tmp;
-	int inversion;
-
-	dprintk("%s\n", __func__);
-
-	if (state->demod_type == TDA1004X_DEMOD_TDA10046) {
-		// setup auto offset
-		tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10);
-		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x80, 0);
-		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0);
-
-		// disable agc_conf[2]
-		tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 0);
-	}
-
-	// set frequency
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	// Hardcoded to use auto as much as possible on the TDA10045 as it
-	// is very unreliable if AUTO mode is _not_ used.
-	if (state->demod_type == TDA1004X_DEMOD_TDA10045) {
-		fe_params->code_rate_HP = FEC_AUTO;
-		fe_params->guard_interval = GUARD_INTERVAL_AUTO;
-		fe_params->transmission_mode = TRANSMISSION_MODE_AUTO;
-	}
-
-	// Set standard params.. or put them to auto
-	if ((fe_params->code_rate_HP == FEC_AUTO) ||
-		(fe_params->code_rate_LP == FEC_AUTO) ||
-		(fe_params->modulation == QAM_AUTO) ||
-		(fe_params->hierarchy == HIERARCHY_AUTO)) {
-		tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1);	// enable auto
-		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0);	/* turn off modulation bits */
-		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0);	// turn off hierarchy bits
-		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x3f, 0);	// turn off FEC bits
-	} else {
-		tda1004x_write_mask(state, TDA1004X_AUTO, 1, 0);	// disable auto
-
-		// set HP FEC
-		tmp = tda1004x_encode_fec(fe_params->code_rate_HP);
-		if (tmp < 0)
-			return tmp;
-		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp);
-
-		// set LP FEC
-		tmp = tda1004x_encode_fec(fe_params->code_rate_LP);
-		if (tmp < 0)
-			return tmp;
-		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3);
-
-		/* set modulation */
-		switch (fe_params->modulation) {
-		case QPSK:
-			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0);
-			break;
-
-		case QAM_16:
-			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 1);
-			break;
-
-		case QAM_64:
-			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 2);
-			break;
-
-		default:
-			return -EINVAL;
-		}
-
-		// set hierarchy
-		switch (fe_params->hierarchy) {
-		case HIERARCHY_NONE:
-			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5);
-			break;
-
-		case HIERARCHY_1:
-			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 1 << 5);
-			break;
-
-		case HIERARCHY_2:
-			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 2 << 5);
-			break;
-
-		case HIERARCHY_4:
-			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 3 << 5);
-			break;
-
-		default:
-			return -EINVAL;
-		}
-	}
-
-	// set bandwidth
-	switch (state->demod_type) {
-	case TDA1004X_DEMOD_TDA10045:
-		tda10045h_set_bandwidth(state, fe_params->bandwidth_hz);
-		break;
-
-	case TDA1004X_DEMOD_TDA10046:
-		tda10046h_set_bandwidth(state, fe_params->bandwidth_hz);
-		break;
-	}
-
-	// set inversion
-	inversion = fe_params->inversion;
-	if (state->config->invert)
-		inversion = inversion ? INVERSION_OFF : INVERSION_ON;
-	switch (inversion) {
-	case INVERSION_OFF:
-		tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0);
-		break;
-
-	case INVERSION_ON:
-		tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0x20);
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	// set guard interval
-	switch (fe_params->guard_interval) {
-	case GUARD_INTERVAL_1_32:
-		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
-		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
-		break;
-
-	case GUARD_INTERVAL_1_16:
-		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
-		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 1 << 2);
-		break;
-
-	case GUARD_INTERVAL_1_8:
-		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
-		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 2 << 2);
-		break;
-
-	case GUARD_INTERVAL_1_4:
-		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
-		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 3 << 2);
-		break;
-
-	case GUARD_INTERVAL_AUTO:
-		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 2);
-		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	// set transmission mode
-	switch (fe_params->transmission_mode) {
-	case TRANSMISSION_MODE_2K:
-		tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0);
-		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0 << 4);
-		break;
-
-	case TRANSMISSION_MODE_8K:
-		tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0);
-		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 1 << 4);
-		break;
-
-	case TRANSMISSION_MODE_AUTO:
-		tda1004x_write_mask(state, TDA1004X_AUTO, 4, 4);
-		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0);
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	// start the lock
-	switch (state->demod_type) {
-	case TDA1004X_DEMOD_TDA10045:
-		tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8);
-		tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0);
-		break;
-
-	case TDA1004X_DEMOD_TDA10046:
-		tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40);
-		msleep(1);
-		tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 1);
-		break;
-	}
-
-	msleep(10);
-
-	return 0;
-}
-
-static int tda1004x_get_fe(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
-	struct tda1004x_state* state = fe->demodulator_priv;
-
-	dprintk("%s\n", __func__);
-
-	// inversion status
-	fe_params->inversion = INVERSION_OFF;
-	if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20)
-		fe_params->inversion = INVERSION_ON;
-	if (state->config->invert)
-		fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON;
-
-	// bandwidth
-	switch (state->demod_type) {
-	case TDA1004X_DEMOD_TDA10045:
-		switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) {
-		case 0x14:
-			fe_params->bandwidth_hz = 8000000;
-			break;
-		case 0xdb:
-			fe_params->bandwidth_hz = 7000000;
-			break;
-		case 0x4f:
-			fe_params->bandwidth_hz = 6000000;
-			break;
-		}
-		break;
-	case TDA1004X_DEMOD_TDA10046:
-		switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) {
-		case 0x5c:
-		case 0x54:
-			fe_params->bandwidth_hz = 8000000;
-			break;
-		case 0x6a:
-		case 0x60:
-			fe_params->bandwidth_hz = 7000000;
-			break;
-		case 0x7b:
-		case 0x70:
-			fe_params->bandwidth_hz = 6000000;
-			break;
-		}
-		break;
-	}
-
-	// FEC
-	fe_params->code_rate_HP =
-	    tda1004x_decode_fec(tda1004x_read_byte(state, TDA1004X_OUT_CONF2) & 7);
-	fe_params->code_rate_LP =
-	    tda1004x_decode_fec((tda1004x_read_byte(state, TDA1004X_OUT_CONF2) >> 3) & 7);
-
-	/* modulation */
-	switch (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 3) {
-	case 0:
-		fe_params->modulation = QPSK;
-		break;
-	case 1:
-		fe_params->modulation = QAM_16;
-		break;
-	case 2:
-		fe_params->modulation = QAM_64;
-		break;
-	}
-
-	// transmission mode
-	fe_params->transmission_mode = TRANSMISSION_MODE_2K;
-	if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10)
-		fe_params->transmission_mode = TRANSMISSION_MODE_8K;
-
-	// guard interval
-	switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) {
-	case 0:
-		fe_params->guard_interval = GUARD_INTERVAL_1_32;
-		break;
-	case 1:
-		fe_params->guard_interval = GUARD_INTERVAL_1_16;
-		break;
-	case 2:
-		fe_params->guard_interval = GUARD_INTERVAL_1_8;
-		break;
-	case 3:
-		fe_params->guard_interval = GUARD_INTERVAL_1_4;
-		break;
-	}
-
-	// hierarchy
-	switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) {
-	case 0:
-		fe_params->hierarchy = HIERARCHY_NONE;
-		break;
-	case 1:
-		fe_params->hierarchy = HIERARCHY_1;
-		break;
-	case 2:
-		fe_params->hierarchy = HIERARCHY_2;
-		break;
-	case 3:
-		fe_params->hierarchy = HIERARCHY_4;
-		break;
-	}
-
-	return 0;
-}
-
-static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status)
-{
-	struct tda1004x_state* state = fe->demodulator_priv;
-	int status;
-	int cber;
-	int vber;
-
-	dprintk("%s\n", __func__);
-
-	// read status
-	status = tda1004x_read_byte(state, TDA1004X_STATUS_CD);
-	if (status == -1)
-		return -EIO;
-
-	// decode
-	*fe_status = 0;
-	if (status & 4)
-		*fe_status |= FE_HAS_SIGNAL;
-	if (status & 2)
-		*fe_status |= FE_HAS_CARRIER;
-	if (status & 8)
-		*fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
-
-	// if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi
-	// is getting anything valid
-	if (!(*fe_status & FE_HAS_VITERBI)) {
-		// read the CBER
-		cber = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
-		if (cber == -1)
-			return -EIO;
-		status = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
-		if (status == -1)
-			return -EIO;
-		cber |= (status << 8);
-		// The address 0x20 should be read to cope with a TDA10046 bug
-		tda1004x_read_byte(state, TDA1004X_CBER_RESET);
-
-		if (cber != 65535)
-			*fe_status |= FE_HAS_VITERBI;
-	}
-
-	// if we DO have some valid VITERBI output, but don't already have SYNC
-	// bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid.
-	if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) {
-		// read the VBER
-		vber = tda1004x_read_byte(state, TDA1004X_VBER_LSB);
-		if (vber == -1)
-			return -EIO;
-		status = tda1004x_read_byte(state, TDA1004X_VBER_MID);
-		if (status == -1)
-			return -EIO;
-		vber |= (status << 8);
-		status = tda1004x_read_byte(state, TDA1004X_VBER_MSB);
-		if (status == -1)
-			return -EIO;
-		vber |= (status & 0x0f) << 16;
-		// The CVBER_LUT should be read to cope with TDA10046 hardware bug
-		tda1004x_read_byte(state, TDA1004X_CVBER_LUT);
-
-		// if RS has passed some valid TS packets, then we must be
-		// getting some SYNC bytes
-		if (vber < 16632)
-			*fe_status |= FE_HAS_SYNC;
-	}
-
-	// success
-	dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
-	return 0;
-}
-
-static int tda1004x_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
-{
-	struct tda1004x_state* state = fe->demodulator_priv;
-	int tmp;
-	int reg = 0;
-
-	dprintk("%s\n", __func__);
-
-	// determine the register to use
-	switch (state->demod_type) {
-	case TDA1004X_DEMOD_TDA10045:
-		reg = TDA10045H_S_AGC;
-		break;
-
-	case TDA1004X_DEMOD_TDA10046:
-		reg = TDA10046H_AGC_IF_LEVEL;
-		break;
-	}
-
-	// read it
-	tmp = tda1004x_read_byte(state, reg);
-	if (tmp < 0)
-		return -EIO;
-
-	*signal = (tmp << 8) | tmp;
-	dprintk("%s: signal=0x%x\n", __func__, *signal);
-	return 0;
-}
-
-static int tda1004x_read_snr(struct dvb_frontend* fe, u16 * snr)
-{
-	struct tda1004x_state* state = fe->demodulator_priv;
-	int tmp;
-
-	dprintk("%s\n", __func__);
-
-	// read it
-	tmp = tda1004x_read_byte(state, TDA1004X_SNR);
-	if (tmp < 0)
-		return -EIO;
-	tmp = 255 - tmp;
-
-	*snr = ((tmp << 8) | tmp);
-	dprintk("%s: snr=0x%x\n", __func__, *snr);
-	return 0;
-}
-
-static int tda1004x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	struct tda1004x_state* state = fe->demodulator_priv;
-	int tmp;
-	int tmp2;
-	int counter;
-
-	dprintk("%s\n", __func__);
-
-	// read the UCBLOCKS and reset
-	counter = 0;
-	tmp = tda1004x_read_byte(state, TDA1004X_UNCOR);
-	if (tmp < 0)
-		return -EIO;
-	tmp &= 0x7f;
-	while (counter++ < 5) {
-		tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
-		tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
-		tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
-
-		tmp2 = tda1004x_read_byte(state, TDA1004X_UNCOR);
-		if (tmp2 < 0)
-			return -EIO;
-		tmp2 &= 0x7f;
-		if ((tmp2 < tmp) || (tmp2 == 0))
-			break;
-	}
-
-	if (tmp != 0x7f)
-		*ucblocks = tmp;
-	else
-		*ucblocks = 0xffffffff;
-
-	dprintk("%s: ucblocks=0x%x\n", __func__, *ucblocks);
-	return 0;
-}
-
-static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	struct tda1004x_state* state = fe->demodulator_priv;
-	int tmp;
-
-	dprintk("%s\n", __func__);
-
-	// read it in
-	tmp = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
-	if (tmp < 0)
-		return -EIO;
-	*ber = tmp << 1;
-	tmp = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
-	if (tmp < 0)
-		return -EIO;
-	*ber |= (tmp << 9);
-	// The address 0x20 should be read to cope with a TDA10046 bug
-	tda1004x_read_byte(state, TDA1004X_CBER_RESET);
-
-	dprintk("%s: ber=0x%x\n", __func__, *ber);
-	return 0;
-}
-
-static int tda1004x_sleep(struct dvb_frontend* fe)
-{
-	struct tda1004x_state* state = fe->demodulator_priv;
-	int gpio_conf;
-
-	switch (state->demod_type) {
-	case TDA1004X_DEMOD_TDA10045:
-		tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0x10);
-		break;
-
-	case TDA1004X_DEMOD_TDA10046:
-		/* set outputs to tristate */
-		tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
-		/* invert GPIO 1 and 3 if desired*/
-		gpio_conf = state->config->gpio_config;
-		if (gpio_conf >= TDA10046_GP00_I)
-			tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f,
-							(gpio_conf & 0x0f) ^ 0x0a);
-
-		tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0xc0);
-		tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
-		break;
-	}
-
-	return 0;
-}
-
-static int tda1004x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
-{
-	struct tda1004x_state* state = fe->demodulator_priv;
-
-	if (enable) {
-		return tda1004x_enable_tuner_i2c(state);
-	} else {
-		return tda1004x_disable_tuner_i2c(state);
-	}
-}
-
-static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
-{
-	fesettings->min_delay_ms = 800;
-	/* Drift compensation makes no sense for DVB-T */
-	fesettings->step_size = 0;
-	fesettings->max_drift = 0;
-	return 0;
-}
-
-static void tda1004x_release(struct dvb_frontend* fe)
-{
-	struct tda1004x_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops tda10045_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name = "Philips TDA10045H DVB-T",
-		.frequency_min = 51000000,
-		.frequency_max = 858000000,
-		.frequency_stepsize = 166667,
-		.caps =
-		    FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		    FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-		    FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-		    FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
-	},
-
-	.release = tda1004x_release,
-
-	.init = tda10045_init,
-	.sleep = tda1004x_sleep,
-	.write = tda1004x_write,
-	.i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
-
-	.set_frontend = tda1004x_set_fe,
-	.get_frontend = tda1004x_get_fe,
-	.get_tune_settings = tda1004x_get_tune_settings,
-
-	.read_status = tda1004x_read_status,
-	.read_ber = tda1004x_read_ber,
-	.read_signal_strength = tda1004x_read_signal_strength,
-	.read_snr = tda1004x_read_snr,
-	.read_ucblocks = tda1004x_read_ucblocks,
-};
-
-struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
-				     struct i2c_adapter* i2c)
-{
-	struct tda1004x_state *state;
-	int id;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
-	if (!state) {
-		printk(KERN_ERR "Can't allocate memory for tda10045 state\n");
-		return NULL;
-	}
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->demod_type = TDA1004X_DEMOD_TDA10045;
-
-	/* check if the demod is there */
-	id = tda1004x_read_byte(state, TDA1004X_CHIPID);
-	if (id < 0) {
-		printk(KERN_ERR "tda10045: chip is not answering. Giving up.\n");
-		kfree(state);
-		return NULL;
-	}
-
-	if (id != 0x25) {
-		printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id);
-		kfree(state);
-		return NULL;
-	}
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-}
-
-static struct dvb_frontend_ops tda10046_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name = "Philips TDA10046H DVB-T",
-		.frequency_min = 51000000,
-		.frequency_max = 858000000,
-		.frequency_stepsize = 166667,
-		.caps =
-		    FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		    FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-		    FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-		    FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
-	},
-
-	.release = tda1004x_release,
-
-	.init = tda10046_init,
-	.sleep = tda1004x_sleep,
-	.write = tda1004x_write,
-	.i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
-
-	.set_frontend = tda1004x_set_fe,
-	.get_frontend = tda1004x_get_fe,
-	.get_tune_settings = tda1004x_get_tune_settings,
-
-	.read_status = tda1004x_read_status,
-	.read_ber = tda1004x_read_ber,
-	.read_signal_strength = tda1004x_read_signal_strength,
-	.read_snr = tda1004x_read_snr,
-	.read_ucblocks = tda1004x_read_ucblocks,
-};
-
-struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
-				     struct i2c_adapter* i2c)
-{
-	struct tda1004x_state *state;
-	int id;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
-	if (!state) {
-		printk(KERN_ERR "Can't allocate memory for tda10046 state\n");
-		return NULL;
-	}
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->demod_type = TDA1004X_DEMOD_TDA10046;
-
-	/* check if the demod is there */
-	id = tda1004x_read_byte(state, TDA1004X_CHIPID);
-	if (id < 0) {
-		printk(KERN_ERR "tda10046: chip is not answering. Giving up.\n");
-		kfree(state);
-		return NULL;
-	}
-	if (id != 0x46) {
-		printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id);
-		kfree(state);
-		return NULL;
-	}
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-}
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("Philips TDA10045H & TDA10046H DVB-T Demodulator");
-MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(tda10045_attach);
-EXPORT_SYMBOL(tda10046_attach);
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
deleted file mode 100644
index 4e27ffb..0000000
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ /dev/null
@@ -1,149 +0,0 @@
-  /*
-     Driver for Philips tda1004xh OFDM Frontend
-
-     (c) 2004 Andrew de Quincey
-
-     This program is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published by
-     the Free Software Foundation; either version 2 of the License, or
-     (at your option) any later version.
-
-     This program is distributed in the hope that it will be useful,
-     but WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-     GNU General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with this program; if not, write to the Free Software
-     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-   */
-
-#ifndef TDA1004X_H
-#define TDA1004X_H
-
-#include <linux/dvb/frontend.h>
-#include <linux/firmware.h>
-
-enum tda10046_xtal {
-	TDA10046_XTAL_4M,
-	TDA10046_XTAL_16M,
-};
-
-enum tda10046_agc {
-	TDA10046_AGC_DEFAULT,		/* original configuration */
-	TDA10046_AGC_IFO_AUTO_NEG,	/* IF AGC only, automatic, negtive */
-	TDA10046_AGC_IFO_AUTO_POS,	/* IF AGC only, automatic, positive */
-	TDA10046_AGC_TDA827X,		/* IF AGC only, special setup for tda827x */
-};
-
-/* Many (hybrid) boards use GPIO 1 and 3
-	GPIO1	analog - dvb switch
-	GPIO3	firmware eeprom address switch
-*/
-enum tda10046_gpio {
-	TDA10046_GPTRI  = 0x00,		/* All GPIOs tristate */
-	TDA10046_GP00   = 0x40,		/* GPIO3=0, GPIO1=0 */
-	TDA10046_GP01   = 0x42,		/* GPIO3=0, GPIO1=1 */
-	TDA10046_GP10   = 0x48,		/* GPIO3=1, GPIO1=0 */
-	TDA10046_GP11   = 0x4a,		/* GPIO3=1, GPIO1=1 */
-	TDA10046_GP00_I = 0x80,		/* GPIO3=0, GPIO1=0, invert in sleep mode*/
-	TDA10046_GP01_I = 0x82,		/* GPIO3=0, GPIO1=1, invert in sleep mode */
-	TDA10046_GP10_I = 0x88,		/* GPIO3=1, GPIO1=0, invert in sleep mode */
-	TDA10046_GP11_I = 0x8a,		/* GPIO3=1, GPIO1=1, invert in sleep mode */
-};
-
-enum tda10046_if {
-	TDA10046_FREQ_3617,		/* original config, 36,166 MHZ */
-	TDA10046_FREQ_3613,		/* 36,13 MHZ */
-	TDA10046_FREQ_045,		/* low IF, 4.0, 4.5, or 5.0 MHZ */
-	TDA10046_FREQ_052,		/* low IF, 5.1667 MHZ for tda9889 */
-};
-
-enum tda10046_tsout {
-	TDA10046_TS_PARALLEL  = 0x00,	/* parallel transport stream, default */
-	TDA10046_TS_SERIAL    = 0x01,	/* serial transport stream */
-};
-
-struct tda1004x_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* does the "inversion" need inverted? */
-	u8 invert;
-
-	/* Does the OCLK signal need inverted? */
-	u8 invert_oclk;
-
-	/* parallel or serial transport stream */
-	enum tda10046_tsout ts_mode;
-
-	/* Xtal frequency, 4 or 16MHz*/
-	enum tda10046_xtal xtal_freq;
-
-	/* IF frequency */
-	enum tda10046_if if_freq;
-
-	/* AGC configuration */
-	enum tda10046_agc agc_config;
-
-	/* setting of GPIO1 and 3 */
-	enum tda10046_gpio gpio_config;
-
-	/* slave address and configuration of the tuner */
-	u8 tuner_address;
-	u8 antenna_switch;
-
-	/* if the board uses another I2c Bridge (tda8290), its address */
-	u8 i2c_gate;
-
-	/* request firmware for device */
-	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
-};
-
-enum tda1004x_demod {
-	TDA1004X_DEMOD_TDA10045,
-	TDA1004X_DEMOD_TDA10046,
-};
-
-struct tda1004x_state {
-	struct i2c_adapter* i2c;
-	const struct tda1004x_config* config;
-	struct dvb_frontend frontend;
-
-	/* private demod data */
-	enum tda1004x_demod demod_type;
-};
-
-#if defined(CONFIG_DVB_TDA1004X) || (defined(CONFIG_DVB_TDA1004X_MODULE) && defined(MODULE))
-extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
-					    struct i2c_adapter* i2c);
-
-extern struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
-					    struct i2c_adapter* i2c);
-#else
-static inline struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
-					    struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-static inline struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
-					    struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_TDA1004X
-
-static inline int tda1004x_writereg(struct dvb_frontend *fe, u8 reg, u8 val) {
-	int r = 0;
-	u8 buf[] = {reg, val};
-	if (fe->ops.write)
-		r = fe->ops.write(fe, buf, 2);
-	return r;
-}
-
-#endif // TDA1004X_H
diff --git a/drivers/media/dvb/frontends/tda10071.c b/drivers/media/dvb/frontends/tda10071.c
deleted file mode 100644
index 703c3d0..0000000
--- a/drivers/media/dvb/frontends/tda10071.c
+++ /dev/null
@@ -1,1284 +0,0 @@
-/*
- * NXP TDA10071 + Conexant CX24118A DVB-S/S2 demodulator + tuner driver
- *
- * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "tda10071_priv.h"
-
-static struct dvb_frontend_ops tda10071_ops;
-
-/* write multiple registers */
-static int tda10071_wr_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
-	int len)
-{
-	int ret;
-	u8 buf[len+1];
-	struct i2c_msg msg[1] = {
-		{
-			.addr = priv->cfg.i2c_address,
-			.flags = 0,
-			.len = sizeof(buf),
-			.buf = buf,
-		}
-	};
-
-	buf[0] = reg;
-	memcpy(&buf[1], val, len);
-
-	ret = i2c_transfer(priv->i2c, msg, 1);
-	if (ret == 1) {
-		ret = 0;
-	} else {
-		dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \
-				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-	return ret;
-}
-
-/* read multiple registers */
-static int tda10071_rd_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
-	int len)
-{
-	int ret;
-	u8 buf[len];
-	struct i2c_msg msg[2] = {
-		{
-			.addr = priv->cfg.i2c_address,
-			.flags = 0,
-			.len = 1,
-			.buf = &reg,
-		}, {
-			.addr = priv->cfg.i2c_address,
-			.flags = I2C_M_RD,
-			.len = sizeof(buf),
-			.buf = buf,
-		}
-	};
-
-	ret = i2c_transfer(priv->i2c, msg, 2);
-	if (ret == 2) {
-		memcpy(val, buf, len);
-		ret = 0;
-	} else {
-		dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \
-				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-	return ret;
-}
-
-/* write single register */
-static int tda10071_wr_reg(struct tda10071_priv *priv, u8 reg, u8 val)
-{
-	return tda10071_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-static int tda10071_rd_reg(struct tda10071_priv *priv, u8 reg, u8 *val)
-{
-	return tda10071_rd_regs(priv, reg, val, 1);
-}
-
-/* write single register with mask */
-int tda10071_wr_reg_mask(struct tda10071_priv *priv, u8 reg, u8 val, u8 mask)
-{
-	int ret;
-	u8 tmp;
-
-	/* no need for read if whole reg is written */
-	if (mask != 0xff) {
-		ret = tda10071_rd_regs(priv, reg, &tmp, 1);
-		if (ret)
-			return ret;
-
-		val &= mask;
-		tmp &= ~mask;
-		val |= tmp;
-	}
-
-	return tda10071_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register with mask */
-int tda10071_rd_reg_mask(struct tda10071_priv *priv, u8 reg, u8 *val, u8 mask)
-{
-	int ret, i;
-	u8 tmp;
-
-	ret = tda10071_rd_regs(priv, reg, &tmp, 1);
-	if (ret)
-		return ret;
-
-	tmp &= mask;
-
-	/* find position of the first bit */
-	for (i = 0; i < 8; i++) {
-		if ((mask >> i) & 0x01)
-			break;
-	}
-	*val = tmp >> i;
-
-	return 0;
-}
-
-/* execute firmware command */
-static int tda10071_cmd_execute(struct tda10071_priv *priv,
-	struct tda10071_cmd *cmd)
-{
-	int ret, i;
-	u8 tmp;
-
-	if (!priv->warm) {
-		ret = -EFAULT;
-		goto error;
-	}
-
-	/* write cmd and args for firmware */
-	ret = tda10071_wr_regs(priv, 0x00, cmd->args, cmd->len);
-	if (ret)
-		goto error;
-
-	/* start cmd execution */
-	ret = tda10071_wr_reg(priv, 0x1f, 1);
-	if (ret)
-		goto error;
-
-	/* wait cmd execution terminate */
-	for (i = 1000, tmp = 1; i && tmp; i--) {
-		ret = tda10071_rd_reg(priv, 0x1f, &tmp);
-		if (ret)
-			goto error;
-
-		usleep_range(200, 5000);
-	}
-
-	dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
-
-	if (i == 0) {
-		ret = -ETIMEDOUT;
-		goto error;
-	}
-
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int tda10071_set_tone(struct dvb_frontend *fe,
-	fe_sec_tone_mode_t fe_sec_tone_mode)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	struct tda10071_cmd cmd;
-	int ret;
-	u8 tone;
-
-	if (!priv->warm) {
-		ret = -EFAULT;
-		goto error;
-	}
-
-	dev_dbg(&priv->i2c->dev, "%s: tone_mode=%d\n", __func__,
-			fe_sec_tone_mode);
-
-	switch (fe_sec_tone_mode) {
-	case SEC_TONE_ON:
-		tone = 1;
-		break;
-	case SEC_TONE_OFF:
-		tone = 0;
-		break;
-	default:
-		dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_tone_mode\n",
-				__func__);
-		ret = -EINVAL;
-		goto error;
-	}
-
-	cmd.args[0] = CMD_LNB_PCB_CONFIG;
-	cmd.args[1] = 0;
-	cmd.args[2] = 0x00;
-	cmd.args[3] = 0x00;
-	cmd.args[4] = tone;
-	cmd.len = 5;
-	ret = tda10071_cmd_execute(priv, &cmd);
-	if (ret)
-		goto error;
-
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int tda10071_set_voltage(struct dvb_frontend *fe,
-	fe_sec_voltage_t fe_sec_voltage)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	struct tda10071_cmd cmd;
-	int ret;
-	u8 voltage;
-
-	if (!priv->warm) {
-		ret = -EFAULT;
-		goto error;
-	}
-
-	dev_dbg(&priv->i2c->dev, "%s: voltage=%d\n", __func__, fe_sec_voltage);
-
-	switch (fe_sec_voltage) {
-	case SEC_VOLTAGE_13:
-		voltage = 0;
-		break;
-	case SEC_VOLTAGE_18:
-		voltage = 1;
-		break;
-	case SEC_VOLTAGE_OFF:
-		voltage = 0;
-		break;
-	default:
-		dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_voltage\n",
-				__func__);
-		ret = -EINVAL;
-		goto error;
-	};
-
-	cmd.args[0] = CMD_LNB_SET_DC_LEVEL;
-	cmd.args[1] = 0;
-	cmd.args[2] = voltage;
-	cmd.len = 3;
-	ret = tda10071_cmd_execute(priv, &cmd);
-	if (ret)
-		goto error;
-
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int tda10071_diseqc_send_master_cmd(struct dvb_frontend *fe,
-	struct dvb_diseqc_master_cmd *diseqc_cmd)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	struct tda10071_cmd cmd;
-	int ret, i;
-	u8 tmp;
-
-	if (!priv->warm) {
-		ret = -EFAULT;
-		goto error;
-	}
-
-	dev_dbg(&priv->i2c->dev, "%s: msg_len=%d\n", __func__,
-			diseqc_cmd->msg_len);
-
-	if (diseqc_cmd->msg_len < 3 || diseqc_cmd->msg_len > 6) {
-		ret = -EINVAL;
-		goto error;
-	}
-
-	/* wait LNB TX */
-	for (i = 500, tmp = 0; i && !tmp; i--) {
-		ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x01);
-		if (ret)
-			goto error;
-
-		usleep_range(10000, 20000);
-	}
-
-	dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
-
-	if (i == 0) {
-		ret = -ETIMEDOUT;
-		goto error;
-	}
-
-	ret = tda10071_wr_reg_mask(priv, 0x47, 0x00, 0x01);
-	if (ret)
-		goto error;
-
-	cmd.args[0] = CMD_LNB_SEND_DISEQC;
-	cmd.args[1] = 0;
-	cmd.args[2] = 0;
-	cmd.args[3] = 0;
-	cmd.args[4] = 2;
-	cmd.args[5] = 0;
-	cmd.args[6] = diseqc_cmd->msg_len;
-	memcpy(&cmd.args[7], diseqc_cmd->msg, diseqc_cmd->msg_len);
-	cmd.len = 7 + diseqc_cmd->msg_len;
-	ret = tda10071_cmd_execute(priv, &cmd);
-	if (ret)
-		goto error;
-
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int tda10071_diseqc_recv_slave_reply(struct dvb_frontend *fe,
-	struct dvb_diseqc_slave_reply *reply)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	struct tda10071_cmd cmd;
-	int ret, i;
-	u8 tmp;
-
-	if (!priv->warm) {
-		ret = -EFAULT;
-		goto error;
-	}
-
-	dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
-
-	/* wait LNB RX */
-	for (i = 500, tmp = 0; i && !tmp; i--) {
-		ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x02);
-		if (ret)
-			goto error;
-
-		usleep_range(10000, 20000);
-	}
-
-	dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
-
-	if (i == 0) {
-		ret = -ETIMEDOUT;
-		goto error;
-	}
-
-	/* reply len */
-	ret = tda10071_rd_reg(priv, 0x46, &tmp);
-	if (ret)
-		goto error;
-
-	reply->msg_len = tmp & 0x1f; /* [4:0] */;
-	if (reply->msg_len > sizeof(reply->msg))
-		reply->msg_len = sizeof(reply->msg); /* truncate API max */
-
-	/* read reply */
-	cmd.args[0] = CMD_LNB_UPDATE_REPLY;
-	cmd.args[1] = 0;
-	cmd.len = 2;
-	ret = tda10071_cmd_execute(priv, &cmd);
-	if (ret)
-		goto error;
-
-	ret = tda10071_rd_regs(priv, cmd.len, reply->msg, reply->msg_len);
-	if (ret)
-		goto error;
-
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int tda10071_diseqc_send_burst(struct dvb_frontend *fe,
-	fe_sec_mini_cmd_t fe_sec_mini_cmd)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	struct tda10071_cmd cmd;
-	int ret, i;
-	u8 tmp, burst;
-
-	if (!priv->warm) {
-		ret = -EFAULT;
-		goto error;
-	}
-
-	dev_dbg(&priv->i2c->dev, "%s: fe_sec_mini_cmd=%d\n", __func__,
-			fe_sec_mini_cmd);
-
-	switch (fe_sec_mini_cmd) {
-	case SEC_MINI_A:
-		burst = 0;
-		break;
-	case SEC_MINI_B:
-		burst = 1;
-		break;
-	default:
-		dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_mini_cmd\n",
-				__func__);
-		ret = -EINVAL;
-		goto error;
-	}
-
-	/* wait LNB TX */
-	for (i = 500, tmp = 0; i && !tmp; i--) {
-		ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x01);
-		if (ret)
-			goto error;
-
-		usleep_range(10000, 20000);
-	}
-
-	dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
-
-	if (i == 0) {
-		ret = -ETIMEDOUT;
-		goto error;
-	}
-
-	ret = tda10071_wr_reg_mask(priv, 0x47, 0x00, 0x01);
-	if (ret)
-		goto error;
-
-	cmd.args[0] = CMD_LNB_SEND_TONEBURST;
-	cmd.args[1] = 0;
-	cmd.args[2] = burst;
-	cmd.len = 3;
-	ret = tda10071_cmd_execute(priv, &cmd);
-	if (ret)
-		goto error;
-
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int tda10071_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 tmp;
-
-	*status = 0;
-
-	if (!priv->warm) {
-		ret = 0;
-		goto error;
-	}
-
-	ret = tda10071_rd_reg(priv, 0x39, &tmp);
-	if (ret)
-		goto error;
-
-	if (tmp & 0x01) /* tuner PLL */
-		*status |= FE_HAS_SIGNAL;
-	if (tmp & 0x02) /* demod PLL */
-		*status |= FE_HAS_CARRIER;
-	if (tmp & 0x04) /* viterbi or LDPC*/
-		*status |= FE_HAS_VITERBI;
-	if (tmp & 0x08) /* RS or BCH */
-		*status |= FE_HAS_SYNC | FE_HAS_LOCK;
-
-	priv->fe_status = *status;
-
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int tda10071_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 buf[2];
-
-	if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
-		*snr = 0;
-		ret = 0;
-		goto error;
-	}
-
-	ret = tda10071_rd_regs(priv, 0x3a, buf, 2);
-	if (ret)
-		goto error;
-
-	/* Es/No dBx10 */
-	*snr = buf[0] << 8 | buf[1];
-
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int tda10071_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	struct tda10071_cmd cmd;
-	int ret;
-	u8 tmp;
-
-	if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
-		*strength = 0;
-		ret = 0;
-		goto error;
-	}
-
-	cmd.args[0] = CMD_GET_AGCACC;
-	cmd.args[1] = 0;
-	cmd.len = 2;
-	ret = tda10071_cmd_execute(priv, &cmd);
-	if (ret)
-		goto error;
-
-	/* input power estimate dBm */
-	ret = tda10071_rd_reg(priv, 0x50, &tmp);
-	if (ret)
-		goto error;
-
-	if (tmp < 181)
-		tmp = 181; /* -75 dBm */
-	else if (tmp > 236)
-		tmp = 236; /* -20 dBm */
-
-	/* scale value to 0x0000-0xffff */
-	*strength = (tmp-181) * 0xffff / (236-181);
-
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	struct tda10071_cmd cmd;
-	int ret, i, len;
-	u8 tmp, reg, buf[8];
-
-	if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
-		*ber = priv->ber = 0;
-		ret = 0;
-		goto error;
-	}
-
-	switch (priv->delivery_system) {
-	case SYS_DVBS:
-		reg = 0x4c;
-		len = 8;
-		i = 1;
-		break;
-	case SYS_DVBS2:
-		reg = 0x4d;
-		len = 4;
-		i = 0;
-		break;
-	default:
-		*ber = priv->ber = 0;
-		return 0;
-	}
-
-	ret = tda10071_rd_reg(priv, reg, &tmp);
-	if (ret)
-		goto error;
-
-	if (priv->meas_count[i] == tmp) {
-		dev_dbg(&priv->i2c->dev, "%s: meas not ready=%02x\n", __func__,
-				tmp);
-		*ber = priv->ber;
-		return 0;
-	} else {
-		priv->meas_count[i] = tmp;
-	}
-
-	cmd.args[0] = CMD_BER_UPDATE_COUNTERS;
-	cmd.args[1] = 0;
-	cmd.args[2] = i;
-	cmd.len = 3;
-	ret = tda10071_cmd_execute(priv, &cmd);
-	if (ret)
-		goto error;
-
-	ret = tda10071_rd_regs(priv, cmd.len, buf, len);
-	if (ret)
-		goto error;
-
-	if (priv->delivery_system == SYS_DVBS) {
-		*ber = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-		priv->ucb += (buf[4] << 8) | buf[5];
-	} else {
-		*ber = (buf[0] << 8) | buf[1];
-	}
-	priv->ber = *ber;
-
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int tda10071_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	int ret = 0;
-
-	if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
-		*ucblocks = 0;
-		goto error;
-	}
-
-	/* UCB is updated when BER is read. Assume BER is read anyway. */
-
-	*ucblocks = priv->ucb;
-
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int tda10071_set_frontend(struct dvb_frontend *fe)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	struct tda10071_cmd cmd;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret, i;
-	u8 mode, rolloff, pilot, inversion, div;
-
-	dev_dbg(&priv->i2c->dev, "%s: delivery_system=%d modulation=%d " \
-		"frequency=%d symbol_rate=%d inversion=%d pilot=%d " \
-		"rolloff=%d\n", __func__, c->delivery_system, c->modulation,
-		c->frequency, c->symbol_rate, c->inversion, c->pilot,
-		c->rolloff);
-
-	priv->delivery_system = SYS_UNDEFINED;
-
-	if (!priv->warm) {
-		ret = -EFAULT;
-		goto error;
-	}
-
-	switch (c->inversion) {
-	case INVERSION_OFF:
-		inversion = 1;
-		break;
-	case INVERSION_ON:
-		inversion = 0;
-		break;
-	case INVERSION_AUTO:
-		/* 2 = auto; try first on then off
-		 * 3 = auto; try first off then on */
-		inversion = 3;
-		break;
-	default:
-		dev_dbg(&priv->i2c->dev, "%s: invalid inversion\n", __func__);
-		ret = -EINVAL;
-		goto error;
-	}
-
-	switch (c->delivery_system) {
-	case SYS_DVBS:
-		rolloff = 0;
-		pilot = 2;
-		break;
-	case SYS_DVBS2:
-		switch (c->rolloff) {
-		case ROLLOFF_20:
-			rolloff = 2;
-			break;
-		case ROLLOFF_25:
-			rolloff = 1;
-			break;
-		case ROLLOFF_35:
-			rolloff = 0;
-			break;
-		case ROLLOFF_AUTO:
-		default:
-			dev_dbg(&priv->i2c->dev, "%s: invalid rolloff\n",
-					__func__);
-			ret = -EINVAL;
-			goto error;
-		}
-
-		switch (c->pilot) {
-		case PILOT_OFF:
-			pilot = 0;
-			break;
-		case PILOT_ON:
-			pilot = 1;
-			break;
-		case PILOT_AUTO:
-			pilot = 2;
-			break;
-		default:
-			dev_dbg(&priv->i2c->dev, "%s: invalid pilot\n",
-					__func__);
-			ret = -EINVAL;
-			goto error;
-		}
-		break;
-	default:
-		dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n",
-				__func__);
-		ret = -EINVAL;
-		goto error;
-	}
-
-	for (i = 0, mode = 0xff; i < ARRAY_SIZE(TDA10071_MODCOD); i++) {
-		if (c->delivery_system == TDA10071_MODCOD[i].delivery_system &&
-			c->modulation == TDA10071_MODCOD[i].modulation &&
-			c->fec_inner == TDA10071_MODCOD[i].fec) {
-			mode = TDA10071_MODCOD[i].val;
-			dev_dbg(&priv->i2c->dev, "%s: mode found=%02x\n",
-					__func__, mode);
-			break;
-		}
-	}
-
-	if (mode == 0xff) {
-		dev_dbg(&priv->i2c->dev, "%s: invalid parameter combination\n",
-				__func__);
-		ret = -EINVAL;
-		goto error;
-	}
-
-	if (c->symbol_rate <= 5000000)
-		div = 14;
-	else
-		div = 4;
-
-	ret = tda10071_wr_reg(priv, 0x81, div);
-	if (ret)
-		goto error;
-
-	ret = tda10071_wr_reg(priv, 0xe3, div);
-	if (ret)
-		goto error;
-
-	cmd.args[0] = CMD_CHANGE_CHANNEL;
-	cmd.args[1] = 0;
-	cmd.args[2] = mode;
-	cmd.args[3] = (c->frequency >> 16) & 0xff;
-	cmd.args[4] = (c->frequency >>  8) & 0xff;
-	cmd.args[5] = (c->frequency >>  0) & 0xff;
-	cmd.args[6] = ((c->symbol_rate / 1000) >> 8) & 0xff;
-	cmd.args[7] = ((c->symbol_rate / 1000) >> 0) & 0xff;
-	cmd.args[8] = (tda10071_ops.info.frequency_tolerance >> 8) & 0xff;
-	cmd.args[9] = (tda10071_ops.info.frequency_tolerance >> 0) & 0xff;
-	cmd.args[10] = rolloff;
-	cmd.args[11] = inversion;
-	cmd.args[12] = pilot;
-	cmd.args[13] = 0x00;
-	cmd.args[14] = 0x00;
-	cmd.len = 15;
-	ret = tda10071_cmd_execute(priv, &cmd);
-	if (ret)
-		goto error;
-
-	priv->delivery_system = c->delivery_system;
-
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int tda10071_get_frontend(struct dvb_frontend *fe)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int ret, i;
-	u8 buf[5], tmp;
-
-	if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
-		ret = -EFAULT;
-		goto error;
-	}
-
-	ret = tda10071_rd_regs(priv, 0x30, buf, 5);
-	if (ret)
-		goto error;
-
-	tmp = buf[0] & 0x3f;
-	for (i = 0; i < ARRAY_SIZE(TDA10071_MODCOD); i++) {
-		if (tmp == TDA10071_MODCOD[i].val) {
-			c->modulation = TDA10071_MODCOD[i].modulation;
-			c->fec_inner = TDA10071_MODCOD[i].fec;
-			c->delivery_system = TDA10071_MODCOD[i].delivery_system;
-		}
-	}
-
-	switch ((buf[1] >> 0) & 0x01) {
-	case 0:
-		c->inversion = INVERSION_OFF;
-		break;
-	case 1:
-		c->inversion = INVERSION_ON;
-		break;
-	}
-
-	switch ((buf[1] >> 7) & 0x01) {
-	case 0:
-		c->pilot = PILOT_OFF;
-		break;
-	case 1:
-		c->pilot = PILOT_ON;
-		break;
-	}
-
-	c->frequency = (buf[2] << 16) | (buf[3] << 8) | (buf[4] << 0);
-
-	ret = tda10071_rd_regs(priv, 0x52, buf, 3);
-	if (ret)
-		goto error;
-
-	c->symbol_rate = (buf[0] << 16) | (buf[1] << 8) | (buf[2] << 0);
-
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int tda10071_init(struct dvb_frontend *fe)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	struct tda10071_cmd cmd;
-	int ret, i, len, remaining, fw_size;
-	const struct firmware *fw;
-	u8 *fw_file = TDA10071_DEFAULT_FIRMWARE;
-	u8 tmp, buf[4];
-	struct tda10071_reg_val_mask tab[] = {
-		{ 0xcd, 0x00, 0x07 },
-		{ 0x80, 0x00, 0x02 },
-		{ 0xcd, 0x00, 0xc0 },
-		{ 0xce, 0x00, 0x1b },
-		{ 0x9d, 0x00, 0x01 },
-		{ 0x9d, 0x00, 0x02 },
-		{ 0x9e, 0x00, 0x01 },
-		{ 0x87, 0x00, 0x80 },
-		{ 0xce, 0x00, 0x08 },
-		{ 0xce, 0x00, 0x10 },
-	};
-	struct tda10071_reg_val_mask tab2[] = {
-		{ 0xf1, 0x70, 0xff },
-		{ 0x88, priv->cfg.pll_multiplier, 0x3f },
-		{ 0x89, 0x00, 0x10 },
-		{ 0x89, 0x10, 0x10 },
-		{ 0xc0, 0x01, 0x01 },
-		{ 0xc0, 0x00, 0x01 },
-		{ 0xe0, 0xff, 0xff },
-		{ 0xe0, 0x00, 0xff },
-		{ 0x96, 0x1e, 0x7e },
-		{ 0x8b, 0x08, 0x08 },
-		{ 0x8b, 0x00, 0x08 },
-		{ 0x8f, 0x1a, 0x7e },
-		{ 0x8c, 0x68, 0xff },
-		{ 0x8d, 0x08, 0xff },
-		{ 0x8e, 0x4c, 0xff },
-		{ 0x8f, 0x01, 0x01 },
-		{ 0x8b, 0x04, 0x04 },
-		{ 0x8b, 0x00, 0x04 },
-		{ 0x87, 0x05, 0x07 },
-		{ 0x80, 0x00, 0x20 },
-		{ 0xc8, 0x01, 0xff },
-		{ 0xb4, 0x47, 0xff },
-		{ 0xb5, 0x9c, 0xff },
-		{ 0xb6, 0x7d, 0xff },
-		{ 0xba, 0x00, 0x03 },
-		{ 0xb7, 0x47, 0xff },
-		{ 0xb8, 0x9c, 0xff },
-		{ 0xb9, 0x7d, 0xff },
-		{ 0xba, 0x00, 0x0c },
-		{ 0xc8, 0x00, 0xff },
-		{ 0xcd, 0x00, 0x04 },
-		{ 0xcd, 0x00, 0x20 },
-		{ 0xe8, 0x02, 0xff },
-		{ 0xcf, 0x20, 0xff },
-		{ 0x9b, 0xd7, 0xff },
-		{ 0x9a, 0x01, 0x03 },
-		{ 0xa8, 0x05, 0x0f },
-		{ 0xa8, 0x65, 0xf0 },
-		{ 0xa6, 0xa0, 0xf0 },
-		{ 0x9d, 0x50, 0xfc },
-		{ 0x9e, 0x20, 0xe0 },
-		{ 0xa3, 0x1c, 0x7c },
-		{ 0xd5, 0x03, 0x03 },
-	};
-
-	/* firmware status */
-	ret = tda10071_rd_reg(priv, 0x51, &tmp);
-	if (ret)
-		goto error;
-
-	if (!tmp) {
-		/* warm state - wake up device from sleep */
-		priv->warm = 1;
-
-		for (i = 0; i < ARRAY_SIZE(tab); i++) {
-			ret = tda10071_wr_reg_mask(priv, tab[i].reg,
-				tab[i].val, tab[i].mask);
-			if (ret)
-				goto error;
-		}
-
-		cmd.args[0] = CMD_SET_SLEEP_MODE;
-		cmd.args[1] = 0;
-		cmd.args[2] = 0;
-		cmd.len = 3;
-		ret = tda10071_cmd_execute(priv, &cmd);
-		if (ret)
-			goto error;
-	} else {
-		/* cold state - try to download firmware */
-		priv->warm = 0;
-
-		/* request the firmware, this will block and timeout */
-		ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent);
-		if (ret) {
-			dev_err(&priv->i2c->dev, "%s: did not find the " \
-					"firmware file. (%s) Please see " \
-					"linux/Documentation/dvb/ for more " \
-					"details on firmware-problems. (%d)\n",
-					KBUILD_MODNAME, fw_file, ret);
-			goto error;
-		}
-
-		/* init */
-		for (i = 0; i < ARRAY_SIZE(tab2); i++) {
-			ret = tda10071_wr_reg_mask(priv, tab2[i].reg,
-				tab2[i].val, tab2[i].mask);
-			if (ret)
-				goto error_release_firmware;
-		}
-
-		/*  download firmware */
-		ret = tda10071_wr_reg(priv, 0xe0, 0x7f);
-		if (ret)
-			goto error_release_firmware;
-
-		ret = tda10071_wr_reg(priv, 0xf7, 0x81);
-		if (ret)
-			goto error_release_firmware;
-
-		ret = tda10071_wr_reg(priv, 0xf8, 0x00);
-		if (ret)
-			goto error_release_firmware;
-
-		ret = tda10071_wr_reg(priv, 0xf9, 0x00);
-		if (ret)
-			goto error_release_firmware;
-
-		dev_info(&priv->i2c->dev, "%s: found a '%s' in cold state, " \
-				"will try to load a firmware\n", KBUILD_MODNAME,
-				tda10071_ops.info.name);
-		dev_info(&priv->i2c->dev, "%s: downloading firmware from " \
-				"file '%s'\n", KBUILD_MODNAME, fw_file);
-
-		/* do not download last byte */
-		fw_size = fw->size - 1;
-
-		for (remaining = fw_size; remaining > 0;
-			remaining -= (priv->cfg.i2c_wr_max - 1)) {
-			len = remaining;
-			if (len > (priv->cfg.i2c_wr_max - 1))
-				len = (priv->cfg.i2c_wr_max - 1);
-
-			ret = tda10071_wr_regs(priv, 0xfa,
-				(u8 *) &fw->data[fw_size - remaining], len);
-			if (ret) {
-				dev_err(&priv->i2c->dev, "%s: firmware " \
-						"download failed=%d\n",
-						KBUILD_MODNAME, ret);
-				if (ret)
-					goto error_release_firmware;
-			}
-		}
-		release_firmware(fw);
-
-		ret = tda10071_wr_reg(priv, 0xf7, 0x0c);
-		if (ret)
-			goto error;
-
-		ret = tda10071_wr_reg(priv, 0xe0, 0x00);
-		if (ret)
-			goto error;
-
-		/* wait firmware start */
-		msleep(250);
-
-		/* firmware status */
-		ret = tda10071_rd_reg(priv, 0x51, &tmp);
-		if (ret)
-			goto error;
-
-		if (tmp) {
-			dev_info(&priv->i2c->dev, "%s: firmware did not run\n",
-					KBUILD_MODNAME);
-			ret = -EFAULT;
-			goto error;
-		} else {
-			priv->warm = 1;
-		}
-
-		cmd.args[0] = CMD_GET_FW_VERSION;
-		cmd.len = 1;
-		ret = tda10071_cmd_execute(priv, &cmd);
-		if (ret)
-			goto error;
-
-		ret = tda10071_rd_regs(priv, cmd.len, buf, 4);
-		if (ret)
-			goto error;
-
-		dev_info(&priv->i2c->dev, "%s: firmware version %d.%d.%d.%d\n",
-				KBUILD_MODNAME, buf[0], buf[1], buf[2], buf[3]);
-		dev_info(&priv->i2c->dev, "%s: found a '%s' in warm state\n",
-				KBUILD_MODNAME, tda10071_ops.info.name);
-
-		ret = tda10071_rd_regs(priv, 0x81, buf, 2);
-		if (ret)
-			goto error;
-
-		cmd.args[0] = CMD_DEMOD_INIT;
-		cmd.args[1] = ((priv->cfg.xtal / 1000) >> 8) & 0xff;
-		cmd.args[2] = ((priv->cfg.xtal / 1000) >> 0) & 0xff;
-		cmd.args[3] = buf[0];
-		cmd.args[4] = buf[1];
-		cmd.args[5] = priv->cfg.pll_multiplier;
-		cmd.args[6] = priv->cfg.spec_inv;
-		cmd.args[7] = 0x00;
-		cmd.len = 8;
-		ret = tda10071_cmd_execute(priv, &cmd);
-		if (ret)
-			goto error;
-
-		cmd.args[0] = CMD_TUNER_INIT;
-		cmd.args[1] = 0x00;
-		cmd.args[2] = 0x00;
-		cmd.args[3] = 0x00;
-		cmd.args[4] = 0x00;
-		cmd.args[5] = 0x14;
-		cmd.args[6] = 0x00;
-		cmd.args[7] = 0x03;
-		cmd.args[8] = 0x02;
-		cmd.args[9] = 0x02;
-		cmd.args[10] = 0x00;
-		cmd.args[11] = 0x00;
-		cmd.args[12] = 0x00;
-		cmd.args[13] = 0x00;
-		cmd.args[14] = 0x00;
-		cmd.len = 15;
-		ret = tda10071_cmd_execute(priv, &cmd);
-		if (ret)
-			goto error;
-
-		cmd.args[0] = CMD_MPEG_CONFIG;
-		cmd.args[1] = 0;
-		cmd.args[2] = priv->cfg.ts_mode;
-		cmd.args[3] = 0x00;
-		cmd.args[4] = 0x04;
-		cmd.args[5] = 0x00;
-		cmd.len = 6;
-		ret = tda10071_cmd_execute(priv, &cmd);
-		if (ret)
-			goto error;
-
-		ret = tda10071_wr_reg_mask(priv, 0xf0, 0x01, 0x01);
-		if (ret)
-			goto error;
-
-		cmd.args[0] = CMD_LNB_CONFIG;
-		cmd.args[1] = 0;
-		cmd.args[2] = 150;
-		cmd.args[3] = 3;
-		cmd.args[4] = 22;
-		cmd.args[5] = 1;
-		cmd.args[6] = 1;
-		cmd.args[7] = 30;
-		cmd.args[8] = 30;
-		cmd.args[9] = 30;
-		cmd.args[10] = 30;
-		cmd.len = 11;
-		ret = tda10071_cmd_execute(priv, &cmd);
-		if (ret)
-			goto error;
-
-		cmd.args[0] = CMD_BER_CONTROL;
-		cmd.args[1] = 0;
-		cmd.args[2] = 14;
-		cmd.args[3] = 14;
-		cmd.len = 4;
-		ret = tda10071_cmd_execute(priv, &cmd);
-		if (ret)
-			goto error;
-	}
-
-	return ret;
-error_release_firmware:
-	release_firmware(fw);
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int tda10071_sleep(struct dvb_frontend *fe)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	struct tda10071_cmd cmd;
-	int ret, i;
-	struct tda10071_reg_val_mask tab[] = {
-		{ 0xcd, 0x07, 0x07 },
-		{ 0x80, 0x02, 0x02 },
-		{ 0xcd, 0xc0, 0xc0 },
-		{ 0xce, 0x1b, 0x1b },
-		{ 0x9d, 0x01, 0x01 },
-		{ 0x9d, 0x02, 0x02 },
-		{ 0x9e, 0x01, 0x01 },
-		{ 0x87, 0x80, 0x80 },
-		{ 0xce, 0x08, 0x08 },
-		{ 0xce, 0x10, 0x10 },
-	};
-
-	if (!priv->warm) {
-		ret = -EFAULT;
-		goto error;
-	}
-
-	cmd.args[0] = CMD_SET_SLEEP_MODE;
-	cmd.args[1] = 0;
-	cmd.args[2] = 1;
-	cmd.len = 3;
-	ret = tda10071_cmd_execute(priv, &cmd);
-	if (ret)
-		goto error;
-
-	for (i = 0; i < ARRAY_SIZE(tab); i++) {
-		ret = tda10071_wr_reg_mask(priv, tab[i].reg, tab[i].val,
-			tab[i].mask);
-		if (ret)
-			goto error;
-	}
-
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static int tda10071_get_tune_settings(struct dvb_frontend *fe,
-	struct dvb_frontend_tune_settings *s)
-{
-	s->min_delay_ms = 8000;
-	s->step_size = 0;
-	s->max_drift = 0;
-
-	return 0;
-}
-
-static void tda10071_release(struct dvb_frontend *fe)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	kfree(priv);
-}
-
-struct dvb_frontend *tda10071_attach(const struct tda10071_config *config,
-	struct i2c_adapter *i2c)
-{
-	int ret;
-	struct tda10071_priv *priv = NULL;
-	u8 tmp;
-
-	/* allocate memory for the internal priv */
-	priv = kzalloc(sizeof(struct tda10071_priv), GFP_KERNEL);
-	if (priv == NULL) {
-		ret = -ENOMEM;
-		goto error;
-	}
-
-	/* setup the priv */
-	priv->i2c = i2c;
-	memcpy(&priv->cfg, config, sizeof(struct tda10071_config));
-
-	/* chip ID */
-	ret = tda10071_rd_reg(priv, 0xff, &tmp);
-	if (ret || tmp != 0x0f)
-		goto error;
-
-	/* chip type */
-	ret = tda10071_rd_reg(priv, 0xdd, &tmp);
-	if (ret || tmp != 0x00)
-		goto error;
-
-	/* chip version */
-	ret = tda10071_rd_reg(priv, 0xfe, &tmp);
-	if (ret || tmp != 0x01)
-		goto error;
-
-	/* create dvb_frontend */
-	memcpy(&priv->fe.ops, &tda10071_ops, sizeof(struct dvb_frontend_ops));
-	priv->fe.demodulator_priv = priv;
-
-	return &priv->fe;
-error:
-	dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
-	kfree(priv);
-	return NULL;
-}
-EXPORT_SYMBOL(tda10071_attach);
-
-static struct dvb_frontend_ops tda10071_ops = {
-	.delsys = { SYS_DVBS, SYS_DVBS2 },
-	.info = {
-		.name = "NXP TDA10071",
-		.frequency_min = 950000,
-		.frequency_max = 2150000,
-		.frequency_tolerance = 5000,
-		.symbol_rate_min = 1000000,
-		.symbol_rate_max = 45000000,
-		.caps = FE_CAN_INVERSION_AUTO |
-			FE_CAN_FEC_1_2 |
-			FE_CAN_FEC_2_3 |
-			FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_4_5 |
-			FE_CAN_FEC_5_6 |
-			FE_CAN_FEC_6_7 |
-			FE_CAN_FEC_7_8 |
-			FE_CAN_FEC_8_9 |
-			FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK |
-			FE_CAN_RECOVER |
-			FE_CAN_2G_MODULATION
-	},
-
-	.release = tda10071_release,
-
-	.get_tune_settings = tda10071_get_tune_settings,
-
-	.init = tda10071_init,
-	.sleep = tda10071_sleep,
-
-	.set_frontend = tda10071_set_frontend,
-	.get_frontend = tda10071_get_frontend,
-
-	.read_status = tda10071_read_status,
-	.read_snr = tda10071_read_snr,
-	.read_signal_strength = tda10071_read_signal_strength,
-	.read_ber = tda10071_read_ber,
-	.read_ucblocks = tda10071_read_ucblocks,
-
-	.diseqc_send_master_cmd = tda10071_diseqc_send_master_cmd,
-	.diseqc_recv_slave_reply = tda10071_diseqc_recv_slave_reply,
-	.diseqc_send_burst = tda10071_diseqc_send_burst,
-
-	.set_tone = tda10071_set_tone,
-	.set_voltage = tda10071_set_voltage,
-};
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("NXP TDA10071 DVB-S/S2 demodulator driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda10071.h b/drivers/media/dvb/frontends/tda10071.h
deleted file mode 100644
index 21163c4..0000000
--- a/drivers/media/dvb/frontends/tda10071.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * NXP TDA10071 + Conexant CX24118A DVB-S/S2 demodulator + tuner driver
- *
- * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef TDA10071_H
-#define TDA10071_H
-
-#include <linux/dvb/frontend.h>
-
-struct tda10071_config {
-	/* Demodulator I2C address.
-	 * Default: none, must set
-	 * Values: 0x55,
-	 */
-	u8 i2c_address;
-
-	/* Max bytes I2C provider can write at once.
-	 * Note: Buffer is taken from the stack currently!
-	 * Default: none, must set
-	 * Values:
-	 */
-	u16 i2c_wr_max;
-
-	/* TS output mode.
-	 * Default: TDA10071_TS_SERIAL
-	 * Values:
-	 */
-#define TDA10071_TS_SERIAL        0
-#define TDA10071_TS_PARALLEL      1
-	u8 ts_mode;
-
-	/* Input spectrum inversion.
-	 * Default: 0
-	 * Values: 0, 1
-	 */
-	bool spec_inv;
-
-	/* Xtal frequency Hz
-	 * Default: none, must set
-	 * Values:
-	 */
-	u32 xtal;
-
-	/* PLL multiplier.
-	 * Default: none, must set
-	 * Values:
-	 */
-	u8 pll_multiplier;
-};
-
-
-#if defined(CONFIG_DVB_TDA10071) || \
-	(defined(CONFIG_DVB_TDA10071_MODULE) && defined(MODULE))
-extern struct dvb_frontend *tda10071_attach(
-	const struct tda10071_config *config, struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *tda10071_attach(
-	const struct tda10071_config *config, struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* TDA10071_H */
diff --git a/drivers/media/dvb/frontends/tda10071_priv.h b/drivers/media/dvb/frontends/tda10071_priv.h
deleted file mode 100644
index 0fa85cf..0000000
--- a/drivers/media/dvb/frontends/tda10071_priv.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * NXP TDA10071 + Conexant CX24118A DVB-S/S2 demodulator + tuner driver
- *
- * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef TDA10071_PRIV
-#define TDA10071_PRIV
-
-#include "dvb_frontend.h"
-#include "tda10071.h"
-#include <linux/firmware.h>
-
-struct tda10071_priv {
-	struct i2c_adapter *i2c;
-	struct dvb_frontend fe;
-	struct tda10071_config cfg;
-
-	u8 meas_count[2];
-	u32 ber;
-	u32 ucb;
-	fe_status_t fe_status;
-	fe_delivery_system_t delivery_system;
-	bool warm; /* FW running */
-};
-
-static struct tda10071_modcod {
-	fe_delivery_system_t delivery_system;
-	fe_modulation_t modulation;
-	fe_code_rate_t fec;
-	u8 val;
-} TDA10071_MODCOD[] = {
-	/* NBC-QPSK */
-	{ SYS_DVBS2, QPSK,  FEC_AUTO, 0x00 },
-	{ SYS_DVBS2, QPSK,  FEC_1_2,  0x04 },
-	{ SYS_DVBS2, QPSK,  FEC_3_5,  0x05 },
-	{ SYS_DVBS2, QPSK,  FEC_2_3,  0x06 },
-	{ SYS_DVBS2, QPSK,  FEC_3_4,  0x07 },
-	{ SYS_DVBS2, QPSK,  FEC_4_5,  0x08 },
-	{ SYS_DVBS2, QPSK,  FEC_5_6,  0x09 },
-	{ SYS_DVBS2, QPSK,  FEC_8_9,  0x0a },
-	{ SYS_DVBS2, QPSK,  FEC_9_10, 0x0b },
-	/* 8PSK */
-	{ SYS_DVBS2, PSK_8, FEC_3_5,  0x0c },
-	{ SYS_DVBS2, PSK_8, FEC_2_3,  0x0d },
-	{ SYS_DVBS2, PSK_8, FEC_3_4,  0x0e },
-	{ SYS_DVBS2, PSK_8, FEC_5_6,  0x0f },
-	{ SYS_DVBS2, PSK_8, FEC_8_9,  0x10 },
-	{ SYS_DVBS2, PSK_8, FEC_9_10, 0x11 },
-	/* QPSK */
-	{ SYS_DVBS,  QPSK,  FEC_AUTO, 0x2d },
-	{ SYS_DVBS,  QPSK,  FEC_1_2,  0x2e },
-	{ SYS_DVBS,  QPSK,  FEC_2_3,  0x2f },
-	{ SYS_DVBS,  QPSK,  FEC_3_4,  0x30 },
-	{ SYS_DVBS,  QPSK,  FEC_5_6,  0x31 },
-	{ SYS_DVBS,  QPSK,  FEC_7_8,  0x32 },
-};
-
-struct tda10071_reg_val_mask {
-	u8 reg;
-	u8 val;
-	u8 mask;
-};
-
-/* firmware filename */
-#define TDA10071_DEFAULT_FIRMWARE      "dvb-fe-tda10071.fw"
-
-/* firmware commands */
-#define CMD_DEMOD_INIT          0x10
-#define CMD_CHANGE_CHANNEL      0x11
-#define CMD_MPEG_CONFIG         0x13
-#define CMD_TUNER_INIT          0x15
-#define CMD_GET_AGCACC          0x1a
-
-#define CMD_LNB_CONFIG          0x20
-#define CMD_LNB_SEND_DISEQC     0x21
-#define CMD_LNB_SET_DC_LEVEL    0x22
-#define CMD_LNB_PCB_CONFIG      0x23
-#define CMD_LNB_SEND_TONEBURST  0x24
-#define CMD_LNB_UPDATE_REPLY    0x25
-
-#define CMD_GET_FW_VERSION      0x35
-#define CMD_SET_SLEEP_MODE      0x36
-#define CMD_BER_CONTROL         0x3e
-#define CMD_BER_UPDATE_COUNTERS 0x3f
-
-/* firmare command struct */
-#define TDA10071_ARGLEN      30
-struct tda10071_cmd {
-	u8 args[TDA10071_ARGLEN];
-	u8 len;
-};
-
-
-#endif /* TDA10071_PRIV */
diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c
deleted file mode 100644
index fcfe2e0..0000000
--- a/drivers/media/dvb/frontends/tda10086.c
+++ /dev/null
@@ -1,777 +0,0 @@
-  /*
-     Driver for Philips tda10086 DVBS Demodulator
-
-     (c) 2006 Andrew de Quincey
-
-     This program is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published by
-     the Free Software Foundation; either version 2 of the License, or
-     (at your option) any later version.
-
-     This program is distributed in the hope that it will be useful,
-     but WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-     GNU General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with this program; if not, write to the Free Software
-     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-   */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/jiffies.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "tda10086.h"
-
-#define SACLK 96000000
-
-struct tda10086_state {
-	struct i2c_adapter* i2c;
-	const struct tda10086_config* config;
-	struct dvb_frontend frontend;
-
-	/* private demod data */
-	u32 frequency;
-	u32 symbol_rate;
-	bool has_lock;
-};
-
-static int debug;
-#define dprintk(args...) \
-	do { \
-		if (debug) printk(KERN_DEBUG "tda10086: " args); \
-	} while (0)
-
-static int tda10086_write_byte(struct tda10086_state *state, int reg, int data)
-{
-	int ret;
-	u8 b0[] = { reg, data };
-	struct i2c_msg msg = { .flags = 0, .buf = b0, .len = 2 };
-
-	msg.addr = state->config->demod_address;
-	ret = i2c_transfer(state->i2c, &msg, 1);
-
-	if (ret != 1)
-		dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
-			__func__, reg, data, ret);
-
-	return (ret != 1) ? ret : 0;
-}
-
-static int tda10086_read_byte(struct tda10086_state *state, int reg)
-{
-	int ret;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
-	struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 },
-				{ .flags = I2C_M_RD, .buf = b1, .len = 1 }};
-
-	msg[0].addr = state->config->demod_address;
-	msg[1].addr = state->config->demod_address;
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2) {
-		dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg,
-			ret);
-		return ret;
-	}
-
-	return b1[0];
-}
-
-static int tda10086_write_mask(struct tda10086_state *state, int reg, int mask, int data)
-{
-	int val;
-
-	/* read a byte and check */
-	val = tda10086_read_byte(state, reg);
-	if (val < 0)
-		return val;
-
-	/* mask if off */
-	val = val & ~mask;
-	val |= data & 0xff;
-
-	/* write it out again */
-	return tda10086_write_byte(state, reg, val);
-}
-
-static int tda10086_init(struct dvb_frontend* fe)
-{
-	struct tda10086_state* state = fe->demodulator_priv;
-	u8 t22k_off = 0x80;
-
-	dprintk ("%s\n", __func__);
-
-	if (state->config->diseqc_tone)
-		t22k_off = 0;
-	/* reset */
-	tda10086_write_byte(state, 0x00, 0x00);
-	msleep(10);
-
-	/* misc setup */
-	tda10086_write_byte(state, 0x01, 0x94);
-	tda10086_write_byte(state, 0x02, 0x35); /* NOTE: TT drivers appear to disable CSWP */
-	tda10086_write_byte(state, 0x03, 0xe4);
-	tda10086_write_byte(state, 0x04, 0x43);
-	tda10086_write_byte(state, 0x0c, 0x0c);
-	tda10086_write_byte(state, 0x1b, 0xb0); /* noise threshold */
-	tda10086_write_byte(state, 0x20, 0x89); /* misc */
-	tda10086_write_byte(state, 0x30, 0x04); /* acquisition period length */
-	tda10086_write_byte(state, 0x32, 0x00); /* irq off */
-	tda10086_write_byte(state, 0x31, 0x56); /* setup AFC */
-
-	/* setup PLL (this assumes SACLK = 96MHz) */
-	tda10086_write_byte(state, 0x55, 0x2c); /* misc PLL setup */
-	if (state->config->xtal_freq == TDA10086_XTAL_16M) {
-		tda10086_write_byte(state, 0x3a, 0x0b); /* M=12 */
-		tda10086_write_byte(state, 0x3b, 0x01); /* P=2 */
-	} else {
-		tda10086_write_byte(state, 0x3a, 0x17); /* M=24 */
-		tda10086_write_byte(state, 0x3b, 0x00); /* P=1 */
-	}
-	tda10086_write_mask(state, 0x55, 0x20, 0x00); /* powerup PLL */
-
-	/* setup TS interface */
-	tda10086_write_byte(state, 0x11, 0x81);
-	tda10086_write_byte(state, 0x12, 0x81);
-	tda10086_write_byte(state, 0x19, 0x40); /* parallel mode A + MSBFIRST */
-	tda10086_write_byte(state, 0x56, 0x80); /* powerdown WPLL - unused in the mode we use */
-	tda10086_write_byte(state, 0x57, 0x08); /* bypass WPLL - unused in the mode we use */
-	tda10086_write_byte(state, 0x10, 0x2a);
-
-	/* setup ADC */
-	tda10086_write_byte(state, 0x58, 0x61); /* ADC setup */
-	tda10086_write_mask(state, 0x58, 0x01, 0x00); /* powerup ADC */
-
-	/* setup AGC */
-	tda10086_write_byte(state, 0x05, 0x0B);
-	tda10086_write_byte(state, 0x37, 0x63);
-	tda10086_write_byte(state, 0x3f, 0x0a); /* NOTE: flydvb varies it */
-	tda10086_write_byte(state, 0x40, 0x64);
-	tda10086_write_byte(state, 0x41, 0x4f);
-	tda10086_write_byte(state, 0x42, 0x43);
-
-	/* setup viterbi */
-	tda10086_write_byte(state, 0x1a, 0x11); /* VBER 10^6, DVB, QPSK */
-
-	/* setup carrier recovery */
-	tda10086_write_byte(state, 0x3d, 0x80);
-
-	/* setup SEC */
-	tda10086_write_byte(state, 0x36, t22k_off); /* all SEC off, 22k tone */
-	tda10086_write_byte(state, 0x34, (((1<<19) * (22000/1000)) / (SACLK/1000)));
-	tda10086_write_byte(state, 0x35, (((1<<19) * (22000/1000)) / (SACLK/1000)) >> 8);
-
-	return 0;
-}
-
-static void tda10086_diseqc_wait(struct tda10086_state *state)
-{
-	unsigned long timeout = jiffies + msecs_to_jiffies(200);
-	while (!(tda10086_read_byte(state, 0x50) & 0x01)) {
-		if(time_after(jiffies, timeout)) {
-			printk("%s: diseqc queue not ready, command may be lost.\n", __func__);
-			break;
-		}
-		msleep(10);
-	}
-}
-
-static int tda10086_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
-	struct tda10086_state* state = fe->demodulator_priv;
-	u8 t22k_off = 0x80;
-
-	dprintk ("%s\n", __func__);
-
-	if (state->config->diseqc_tone)
-		t22k_off = 0;
-
-	switch (tone) {
-	case SEC_TONE_OFF:
-		tda10086_write_byte(state, 0x36, t22k_off);
-		break;
-
-	case SEC_TONE_ON:
-		tda10086_write_byte(state, 0x36, 0x01 + t22k_off);
-		break;
-	}
-
-	return 0;
-}
-
-static int tda10086_send_master_cmd (struct dvb_frontend* fe,
-				    struct dvb_diseqc_master_cmd* cmd)
-{
-	struct tda10086_state* state = fe->demodulator_priv;
-	int i;
-	u8 oldval;
-	u8 t22k_off = 0x80;
-
-	dprintk ("%s\n", __func__);
-
-	if (state->config->diseqc_tone)
-		t22k_off = 0;
-
-	if (cmd->msg_len > 6)
-		return -EINVAL;
-	oldval = tda10086_read_byte(state, 0x36);
-
-	for(i=0; i< cmd->msg_len; i++) {
-		tda10086_write_byte(state, 0x48+i, cmd->msg[i]);
-	}
-	tda10086_write_byte(state, 0x36, (0x08 + t22k_off)
-					| ((cmd->msg_len - 1) << 4));
-
-	tda10086_diseqc_wait(state);
-
-	tda10086_write_byte(state, 0x36, oldval);
-
-	return 0;
-}
-
-static int tda10086_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
-{
-	struct tda10086_state* state = fe->demodulator_priv;
-	u8 oldval = tda10086_read_byte(state, 0x36);
-	u8 t22k_off = 0x80;
-
-	dprintk ("%s\n", __func__);
-
-	if (state->config->diseqc_tone)
-		t22k_off = 0;
-
-	switch(minicmd) {
-	case SEC_MINI_A:
-		tda10086_write_byte(state, 0x36, 0x04 + t22k_off);
-		break;
-
-	case SEC_MINI_B:
-		tda10086_write_byte(state, 0x36, 0x06 + t22k_off);
-		break;
-	}
-
-	tda10086_diseqc_wait(state);
-
-	tda10086_write_byte(state, 0x36, oldval);
-
-	return 0;
-}
-
-static int tda10086_set_inversion(struct tda10086_state *state,
-				  struct dtv_frontend_properties *fe_params)
-{
-	u8 invval = 0x80;
-
-	dprintk ("%s %i %i\n", __func__, fe_params->inversion, state->config->invert);
-
-	switch(fe_params->inversion) {
-	case INVERSION_OFF:
-		if (state->config->invert)
-			invval = 0x40;
-		break;
-	case INVERSION_ON:
-		if (!state->config->invert)
-			invval = 0x40;
-		break;
-	case INVERSION_AUTO:
-		invval = 0x00;
-		break;
-	}
-	tda10086_write_mask(state, 0x0c, 0xc0, invval);
-
-	return 0;
-}
-
-static int tda10086_set_symbol_rate(struct tda10086_state *state,
-				    struct dtv_frontend_properties *fe_params)
-{
-	u8 dfn = 0;
-	u8 afs = 0;
-	u8 byp = 0;
-	u8 reg37 = 0x43;
-	u8 reg42 = 0x43;
-	u64 big;
-	u32 tmp;
-	u32 bdr;
-	u32 bdri;
-	u32 symbol_rate = fe_params->symbol_rate;
-
-	dprintk ("%s %i\n", __func__, symbol_rate);
-
-	/* setup the decimation and anti-aliasing filters.. */
-	if (symbol_rate < (u32) (SACLK * 0.0137)) {
-		dfn=4;
-		afs=1;
-	} else if (symbol_rate < (u32) (SACLK * 0.0208)) {
-		dfn=4;
-		afs=0;
-	} else if (symbol_rate < (u32) (SACLK * 0.0270)) {
-		dfn=3;
-		afs=1;
-	} else if (symbol_rate < (u32) (SACLK * 0.0416)) {
-		dfn=3;
-		afs=0;
-	} else if (symbol_rate < (u32) (SACLK * 0.0550)) {
-		dfn=2;
-		afs=1;
-	} else if (symbol_rate < (u32) (SACLK * 0.0833)) {
-		dfn=2;
-		afs=0;
-	} else if (symbol_rate < (u32) (SACLK * 0.1100)) {
-		dfn=1;
-		afs=1;
-	} else if (symbol_rate < (u32) (SACLK * 0.1666)) {
-		dfn=1;
-		afs=0;
-	} else if (symbol_rate < (u32) (SACLK * 0.2200)) {
-		dfn=0;
-		afs=1;
-	} else if (symbol_rate < (u32) (SACLK * 0.3333)) {
-		dfn=0;
-		afs=0;
-	} else {
-		reg37 = 0x63;
-		reg42 = 0x4f;
-		byp=1;
-	}
-
-	/* calculate BDR */
-	big = (1ULL<<21) * ((u64) symbol_rate/1000ULL) * (1ULL<<dfn);
-	big += ((SACLK/1000ULL)-1ULL);
-	do_div(big, (SACLK/1000ULL));
-	bdr = big & 0xfffff;
-
-	/* calculate BDRI */
-	tmp = (1<<dfn)*(symbol_rate/1000);
-	bdri = ((32 * (SACLK/1000)) + (tmp-1)) / tmp;
-
-	tda10086_write_byte(state, 0x21, (afs << 7) | dfn);
-	tda10086_write_mask(state, 0x20, 0x08, byp << 3);
-	tda10086_write_byte(state, 0x06, bdr);
-	tda10086_write_byte(state, 0x07, bdr >> 8);
-	tda10086_write_byte(state, 0x08, bdr >> 16);
-	tda10086_write_byte(state, 0x09, bdri);
-	tda10086_write_byte(state, 0x37, reg37);
-	tda10086_write_byte(state, 0x42, reg42);
-
-	return 0;
-}
-
-static int tda10086_set_fec(struct tda10086_state *state,
-			    struct dtv_frontend_properties *fe_params)
-{
-	u8 fecval;
-
-	dprintk("%s %i\n", __func__, fe_params->fec_inner);
-
-	switch (fe_params->fec_inner) {
-	case FEC_1_2:
-		fecval = 0x00;
-		break;
-	case FEC_2_3:
-		fecval = 0x01;
-		break;
-	case FEC_3_4:
-		fecval = 0x02;
-		break;
-	case FEC_4_5:
-		fecval = 0x03;
-		break;
-	case FEC_5_6:
-		fecval = 0x04;
-		break;
-	case FEC_6_7:
-		fecval = 0x05;
-		break;
-	case FEC_7_8:
-		fecval = 0x06;
-		break;
-	case FEC_8_9:
-		fecval = 0x07;
-		break;
-	case FEC_AUTO:
-		fecval = 0x08;
-		break;
-	default:
-		return -1;
-	}
-	tda10086_write_byte(state, 0x0d, fecval);
-
-	return 0;
-}
-
-static int tda10086_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
-	struct tda10086_state *state = fe->demodulator_priv;
-	int ret;
-	u32 freq = 0;
-	int freqoff;
-
-	dprintk ("%s\n", __func__);
-
-	/* modify parameters for tuning */
-	tda10086_write_byte(state, 0x02, 0x35);
-	state->has_lock = false;
-
-	/* set params */
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-
-		if (fe->ops.tuner_ops.get_frequency)
-			fe->ops.tuner_ops.get_frequency(fe, &freq);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	/* calcluate the frequency offset (in *Hz* not kHz) */
-	freqoff = fe_params->frequency - freq;
-	freqoff = ((1<<16) * freqoff) / (SACLK/1000);
-	tda10086_write_byte(state, 0x3d, 0x80 | ((freqoff >> 8) & 0x7f));
-	tda10086_write_byte(state, 0x3e, freqoff);
-
-	if ((ret = tda10086_set_inversion(state, fe_params)) < 0)
-		return ret;
-	if ((ret = tda10086_set_symbol_rate(state, fe_params)) < 0)
-		return ret;
-	if ((ret = tda10086_set_fec(state, fe_params)) < 0)
-		return ret;
-
-	/* soft reset + disable TS output until lock */
-	tda10086_write_mask(state, 0x10, 0x40, 0x40);
-	tda10086_write_mask(state, 0x00, 0x01, 0x00);
-
-	state->symbol_rate = fe_params->symbol_rate;
-	state->frequency = fe_params->frequency;
-	return 0;
-}
-
-static int tda10086_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
-	struct tda10086_state* state = fe->demodulator_priv;
-	u8 val;
-	int tmp;
-	u64 tmp64;
-
-	dprintk ("%s\n", __func__);
-
-	/* check for invalid symbol rate */
-	if (fe_params->symbol_rate < 500000)
-		return -EINVAL;
-
-	/* calculate the updated frequency (note: we convert from Hz->kHz) */
-	tmp64 = tda10086_read_byte(state, 0x52);
-	tmp64 |= (tda10086_read_byte(state, 0x51) << 8);
-	if (tmp64 & 0x8000)
-		tmp64 |= 0xffffffffffff0000ULL;
-	tmp64 = (tmp64 * (SACLK/1000ULL));
-	do_div(tmp64, (1ULL<<15) * (1ULL<<1));
-	fe_params->frequency = (int) state->frequency + (int) tmp64;
-
-	/* the inversion */
-	val = tda10086_read_byte(state, 0x0c);
-	if (val & 0x80) {
-		switch(val & 0x40) {
-		case 0x00:
-			fe_params->inversion = INVERSION_OFF;
-			if (state->config->invert)
-				fe_params->inversion = INVERSION_ON;
-			break;
-		default:
-			fe_params->inversion = INVERSION_ON;
-			if (state->config->invert)
-				fe_params->inversion = INVERSION_OFF;
-			break;
-		}
-	} else {
-		tda10086_read_byte(state, 0x0f);
-		switch(val & 0x02) {
-		case 0x00:
-			fe_params->inversion = INVERSION_OFF;
-			if (state->config->invert)
-				fe_params->inversion = INVERSION_ON;
-			break;
-		default:
-			fe_params->inversion = INVERSION_ON;
-			if (state->config->invert)
-				fe_params->inversion = INVERSION_OFF;
-			break;
-		}
-	}
-
-	/* calculate the updated symbol rate */
-	tmp = tda10086_read_byte(state, 0x1d);
-	if (tmp & 0x80)
-		tmp |= 0xffffff00;
-	tmp = (tmp * 480 * (1<<1)) / 128;
-	tmp = ((state->symbol_rate/1000) * tmp) / (1000000/1000);
-	fe_params->symbol_rate = state->symbol_rate + tmp;
-
-	/* the FEC */
-	val = (tda10086_read_byte(state, 0x0d) & 0x70) >> 4;
-	switch(val) {
-	case 0x00:
-		fe_params->fec_inner = FEC_1_2;
-		break;
-	case 0x01:
-		fe_params->fec_inner = FEC_2_3;
-		break;
-	case 0x02:
-		fe_params->fec_inner = FEC_3_4;
-		break;
-	case 0x03:
-		fe_params->fec_inner = FEC_4_5;
-		break;
-	case 0x04:
-		fe_params->fec_inner = FEC_5_6;
-		break;
-	case 0x05:
-		fe_params->fec_inner = FEC_6_7;
-		break;
-	case 0x06:
-		fe_params->fec_inner = FEC_7_8;
-		break;
-	case 0x07:
-		fe_params->fec_inner = FEC_8_9;
-		break;
-	}
-
-	return 0;
-}
-
-static int tda10086_read_status(struct dvb_frontend* fe, fe_status_t *fe_status)
-{
-	struct tda10086_state* state = fe->demodulator_priv;
-	u8 val;
-
-	dprintk ("%s\n", __func__);
-
-	val = tda10086_read_byte(state, 0x0e);
-	*fe_status = 0;
-	if (val & 0x01)
-		*fe_status |= FE_HAS_SIGNAL;
-	if (val & 0x02)
-		*fe_status |= FE_HAS_CARRIER;
-	if (val & 0x04)
-		*fe_status |= FE_HAS_VITERBI;
-	if (val & 0x08)
-		*fe_status |= FE_HAS_SYNC;
-	if (val & 0x10) {
-		*fe_status |= FE_HAS_LOCK;
-		if (!state->has_lock) {
-			state->has_lock = true;
-			/* modify parameters for stable reception */
-			tda10086_write_byte(state, 0x02, 0x00);
-		}
-	}
-
-	return 0;
-}
-
-static int tda10086_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
-{
-	struct tda10086_state* state = fe->demodulator_priv;
-	u8 _str;
-
-	dprintk ("%s\n", __func__);
-
-	_str = 0xff - tda10086_read_byte(state, 0x43);
-	*signal = (_str << 8) | _str;
-
-	return 0;
-}
-
-static int tda10086_read_snr(struct dvb_frontend* fe, u16 * snr)
-{
-	struct tda10086_state* state = fe->demodulator_priv;
-	u8 _snr;
-
-	dprintk ("%s\n", __func__);
-
-	_snr = 0xff - tda10086_read_byte(state, 0x1c);
-	*snr = (_snr << 8) | _snr;
-
-	return 0;
-}
-
-static int tda10086_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	struct tda10086_state* state = fe->demodulator_priv;
-
-	dprintk ("%s\n", __func__);
-
-	/* read it */
-	*ucblocks = tda10086_read_byte(state, 0x18) & 0x7f;
-
-	/* reset counter */
-	tda10086_write_byte(state, 0x18, 0x00);
-	tda10086_write_byte(state, 0x18, 0x80);
-
-	return 0;
-}
-
-static int tda10086_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	struct tda10086_state* state = fe->demodulator_priv;
-
-	dprintk ("%s\n", __func__);
-
-	/* read it */
-	*ber = 0;
-	*ber |= tda10086_read_byte(state, 0x15);
-	*ber |= tda10086_read_byte(state, 0x16) << 8;
-	*ber |= (tda10086_read_byte(state, 0x17) & 0xf) << 16;
-
-	return 0;
-}
-
-static int tda10086_sleep(struct dvb_frontend* fe)
-{
-	struct tda10086_state* state = fe->demodulator_priv;
-
-	dprintk ("%s\n", __func__);
-
-	tda10086_write_mask(state, 0x00, 0x08, 0x08);
-
-	return 0;
-}
-
-static int tda10086_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
-{
-	struct tda10086_state* state = fe->demodulator_priv;
-
-	dprintk ("%s\n", __func__);
-
-	if (enable) {
-		tda10086_write_mask(state, 0x00, 0x10, 0x10);
-	} else {
-		tda10086_write_mask(state, 0x00, 0x10, 0x00);
-	}
-
-	return 0;
-}
-
-static int tda10086_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-
-	if (p->symbol_rate > 20000000) {
-		fesettings->min_delay_ms = 50;
-		fesettings->step_size = 2000;
-		fesettings->max_drift = 8000;
-	} else if (p->symbol_rate > 12000000) {
-		fesettings->min_delay_ms = 100;
-		fesettings->step_size = 1500;
-		fesettings->max_drift = 9000;
-	} else if (p->symbol_rate > 8000000) {
-		fesettings->min_delay_ms = 100;
-		fesettings->step_size = 1000;
-		fesettings->max_drift = 8000;
-	} else if (p->symbol_rate > 4000000) {
-		fesettings->min_delay_ms = 100;
-		fesettings->step_size = 500;
-		fesettings->max_drift = 7000;
-	} else if (p->symbol_rate > 2000000) {
-		fesettings->min_delay_ms = 200;
-		fesettings->step_size = p->symbol_rate / 8000;
-		fesettings->max_drift = 14 * fesettings->step_size;
-	} else {
-		fesettings->min_delay_ms = 200;
-		fesettings->step_size =  p->symbol_rate / 8000;
-		fesettings->max_drift = 18 * fesettings->step_size;
-	}
-
-	return 0;
-}
-
-static void tda10086_release(struct dvb_frontend* fe)
-{
-	struct tda10086_state *state = fe->demodulator_priv;
-	tda10086_sleep(fe);
-	kfree(state);
-}
-
-static struct dvb_frontend_ops tda10086_ops = {
-	.delsys = { SYS_DVBS },
-	.info = {
-		.name     = "Philips TDA10086 DVB-S",
-		.frequency_min    = 950000,
-		.frequency_max    = 2150000,
-		.frequency_stepsize = 125,     /* kHz for QPSK frontends */
-		.symbol_rate_min  = 1000000,
-		.symbol_rate_max  = 45000000,
-		.caps = FE_CAN_INVERSION_AUTO |
-			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK
-	},
-
-	.release = tda10086_release,
-
-	.init = tda10086_init,
-	.sleep = tda10086_sleep,
-	.i2c_gate_ctrl = tda10086_i2c_gate_ctrl,
-
-	.set_frontend = tda10086_set_frontend,
-	.get_frontend = tda10086_get_frontend,
-	.get_tune_settings = tda10086_get_tune_settings,
-
-	.read_status = tda10086_read_status,
-	.read_ber = tda10086_read_ber,
-	.read_signal_strength = tda10086_read_signal_strength,
-	.read_snr = tda10086_read_snr,
-	.read_ucblocks = tda10086_read_ucblocks,
-
-	.diseqc_send_master_cmd = tda10086_send_master_cmd,
-	.diseqc_send_burst = tda10086_send_burst,
-	.set_tone = tda10086_set_tone,
-};
-
-struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
-				     struct i2c_adapter* i2c)
-{
-	struct tda10086_state *state;
-
-	dprintk ("%s\n", __func__);
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct tda10086_state), GFP_KERNEL);
-	if (!state)
-		return NULL;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-
-	/* check if the demod is there */
-	if (tda10086_read_byte(state, 0x1e) != 0xe1) {
-		kfree(state);
-		return NULL;
-	}
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &tda10086_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-}
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("Philips TDA10086 DVB-S Demodulator");
-MODULE_AUTHOR("Andrew de Quincey");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(tda10086_attach);
diff --git a/drivers/media/dvb/frontends/tda10086.h b/drivers/media/dvb/frontends/tda10086.h
deleted file mode 100644
index 61148c5..0000000
--- a/drivers/media/dvb/frontends/tda10086.h
+++ /dev/null
@@ -1,61 +0,0 @@
-  /*
-     Driver for Philips tda10086 DVBS Frontend
-
-     (c) 2006 Andrew de Quincey
-
-     This program is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published by
-     the Free Software Foundation; either version 2 of the License, or
-     (at your option) any later version.
-
-     This program is distributed in the hope that it will be useful,
-     but WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-     GNU General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with this program; if not, write to the Free Software
-     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-   */
-
-#ifndef TDA10086_H
-#define TDA10086_H
-
-#include <linux/dvb/frontend.h>
-#include <linux/firmware.h>
-
-enum tda10086_xtal {
-	TDA10086_XTAL_16M,
-	TDA10086_XTAL_4M
-};
-
-struct tda10086_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* does the "inversion" need inverted? */
-	u8 invert;
-
-	/* do we need the diseqc signal with carrier? */
-	u8 diseqc_tone;
-
-	/* frequency of the reference xtal */
-	enum tda10086_xtal xtal_freq;
-};
-
-#if defined(CONFIG_DVB_TDA10086) || (defined(CONFIG_DVB_TDA10086_MODULE) && defined(MODULE))
-extern struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
-					    struct i2c_adapter* i2c);
-#else
-static inline struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
-						   struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_TDA10086 */
-
-#endif /* TDA10086_H */
diff --git a/drivers/media/dvb/frontends/tda18271c2dd.c b/drivers/media/dvb/frontends/tda18271c2dd.c
deleted file mode 100644
index ad7c72e..0000000
--- a/drivers/media/dvb/frontends/tda18271c2dd.c
+++ /dev/null
@@ -1,1246 +0,0 @@
-/*
- * tda18271c2dd: Driver for the TDA18271C2 tuner
- *
- * Copyright (C) 2010 Digital Devices GmbH
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/i2c.h>
-#include <asm/div64.h>
-
-#include "dvb_frontend.h"
-
-struct SStandardParam {
-	s32   m_IFFrequency;
-	u32   m_BandWidth;
-	u8    m_EP3_4_0;
-	u8    m_EB22;
-};
-
-struct SMap {
-	u32   m_Frequency;
-	u8    m_Param;
-};
-
-struct SMapI {
-	u32   m_Frequency;
-	s32    m_Param;
-};
-
-struct SMap2 {
-	u32   m_Frequency;
-	u8    m_Param1;
-	u8    m_Param2;
-};
-
-struct SRFBandMap {
-	u32   m_RF_max;
-	u32   m_RF1_Default;
-	u32   m_RF2_Default;
-	u32   m_RF3_Default;
-};
-
-enum ERegister {
-	ID = 0,
-	TM,
-	PL,
-	EP1, EP2, EP3, EP4, EP5,
-	CPD, CD1, CD2, CD3,
-	MPD, MD1, MD2, MD3,
-	EB1, EB2, EB3, EB4, EB5, EB6, EB7, EB8, EB9, EB10,
-	EB11, EB12, EB13, EB14, EB15, EB16, EB17, EB18, EB19, EB20,
-	EB21, EB22, EB23,
-	NUM_REGS
-};
-
-struct tda_state {
-	struct i2c_adapter *i2c;
-	u8 adr;
-
-	u32   m_Frequency;
-	u32   IF;
-
-	u8    m_IFLevelAnalog;
-	u8    m_IFLevelDigital;
-	u8    m_IFLevelDVBC;
-	u8    m_IFLevelDVBT;
-
-	u8    m_EP4;
-	u8    m_EP3_Standby;
-
-	bool  m_bMaster;
-
-	s32   m_SettlingTime;
-
-	u8    m_Regs[NUM_REGS];
-
-	/* Tracking filter settings for band 0..6 */
-	u32   m_RF1[7];
-	s32   m_RF_A1[7];
-	s32   m_RF_B1[7];
-	u32   m_RF2[7];
-	s32   m_RF_A2[7];
-	s32   m_RF_B2[7];
-	u32   m_RF3[7];
-
-	u8    m_TMValue_RFCal;    /* Calibration temperatur */
-
-	bool  m_bFMInput;         /* true to use Pin 8 for FM Radio */
-
-};
-
-static int PowerScan(struct tda_state *state,
-		     u8 RFBand, u32 RF_in,
-		     u32 *pRF_Out, bool *pbcal);
-
-static int i2c_readn(struct i2c_adapter *adapter, u8 adr, u8 *data, int len)
-{
-	struct i2c_msg msgs[1] = {{.addr = adr,  .flags = I2C_M_RD,
-				   .buf  = data, .len   = len} };
-	return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
-}
-
-static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
-{
-	struct i2c_msg msg = {.addr = adr, .flags = 0,
-			      .buf = data, .len = len};
-
-	if (i2c_transfer(adap, &msg, 1) != 1) {
-		printk(KERN_ERR "tda18271c2dd: i2c write error at addr %i\n", adr);
-		return -1;
-	}
-	return 0;
-}
-
-static int WriteRegs(struct tda_state *state,
-		     u8 SubAddr, u8 *Regs, u16 nRegs)
-{
-	u8 data[nRegs+1];
-
-	data[0] = SubAddr;
-	memcpy(data + 1, Regs, nRegs);
-	return i2c_write(state->i2c, state->adr, data, nRegs+1);
-}
-
-static int WriteReg(struct tda_state *state, u8 SubAddr, u8 Reg)
-{
-	u8 msg[2] = {SubAddr, Reg};
-
-	return i2c_write(state->i2c, state->adr, msg, 2);
-}
-
-static int Read(struct tda_state *state, u8 * Regs)
-{
-	return i2c_readn(state->i2c, state->adr, Regs, 16);
-}
-
-static int ReadExtented(struct tda_state *state, u8 * Regs)
-{
-	return i2c_readn(state->i2c, state->adr, Regs, NUM_REGS);
-}
-
-static int UpdateRegs(struct tda_state *state, u8 RegFrom, u8 RegTo)
-{
-	return WriteRegs(state, RegFrom,
-			 &state->m_Regs[RegFrom], RegTo-RegFrom+1);
-}
-static int UpdateReg(struct tda_state *state, u8 Reg)
-{
-	return WriteReg(state, Reg, state->m_Regs[Reg]);
-}
-
-#include "tda18271c2dd_maps.h"
-
-static void reset(struct tda_state *state)
-{
-	u32   ulIFLevelAnalog = 0;
-	u32   ulIFLevelDigital = 2;
-	u32   ulIFLevelDVBC = 7;
-	u32   ulIFLevelDVBT = 6;
-	u32   ulXTOut = 0;
-	u32   ulStandbyMode = 0x06;    /* Send in stdb, but leave osc on */
-	u32   ulSlave = 0;
-	u32   ulFMInput = 0;
-	u32   ulSettlingTime = 100;
-
-	state->m_Frequency         = 0;
-	state->m_SettlingTime = 100;
-	state->m_IFLevelAnalog = (ulIFLevelAnalog & 0x07) << 2;
-	state->m_IFLevelDigital = (ulIFLevelDigital & 0x07) << 2;
-	state->m_IFLevelDVBC = (ulIFLevelDVBC & 0x07) << 2;
-	state->m_IFLevelDVBT = (ulIFLevelDVBT & 0x07) << 2;
-
-	state->m_EP4 = 0x20;
-	if (ulXTOut != 0)
-		state->m_EP4 |= 0x40;
-
-	state->m_EP3_Standby = ((ulStandbyMode & 0x07) << 5) | 0x0F;
-	state->m_bMaster = (ulSlave == 0);
-
-	state->m_SettlingTime = ulSettlingTime;
-
-	state->m_bFMInput = (ulFMInput == 2);
-}
-
-static bool SearchMap1(struct SMap Map[],
-		       u32 Frequency, u8 *pParam)
-{
-	int i = 0;
-
-	while ((Map[i].m_Frequency != 0) && (Frequency > Map[i].m_Frequency))
-		i += 1;
-	if (Map[i].m_Frequency == 0)
-		return false;
-	*pParam = Map[i].m_Param;
-	return true;
-}
-
-static bool SearchMap2(struct SMapI Map[],
-		       u32 Frequency, s32 *pParam)
-{
-	int i = 0;
-
-	while ((Map[i].m_Frequency != 0) &&
-	       (Frequency > Map[i].m_Frequency))
-		i += 1;
-	if (Map[i].m_Frequency == 0)
-		return false;
-	*pParam = Map[i].m_Param;
-	return true;
-}
-
-static bool SearchMap3(struct SMap2 Map[], u32 Frequency,
-		       u8 *pParam1, u8 *pParam2)
-{
-	int i = 0;
-
-	while ((Map[i].m_Frequency != 0) &&
-	       (Frequency > Map[i].m_Frequency))
-		i += 1;
-	if (Map[i].m_Frequency == 0)
-		return false;
-	*pParam1 = Map[i].m_Param1;
-	*pParam2 = Map[i].m_Param2;
-	return true;
-}
-
-static bool SearchMap4(struct SRFBandMap Map[],
-		       u32 Frequency, u8 *pRFBand)
-{
-	int i = 0;
-
-	while (i < 7 && (Frequency > Map[i].m_RF_max))
-		i += 1;
-	if (i == 7)
-		return false;
-	*pRFBand = i;
-	return true;
-}
-
-static int ThermometerRead(struct tda_state *state, u8 *pTM_Value)
-{
-	int status = 0;
-
-	do {
-		u8 Regs[16];
-		state->m_Regs[TM] |= 0x10;
-		status = UpdateReg(state, TM);
-		if (status < 0)
-			break;
-		status = Read(state, Regs);
-		if (status < 0)
-			break;
-		if (((Regs[TM] & 0x0F) == 0 && (Regs[TM] & 0x20) == 0x20) ||
-		    ((Regs[TM] & 0x0F) == 8 && (Regs[TM] & 0x20) == 0x00)) {
-			state->m_Regs[TM] ^= 0x20;
-			status = UpdateReg(state, TM);
-			if (status < 0)
-				break;
-			msleep(10);
-			status = Read(state, Regs);
-			if (status < 0)
-				break;
-		}
-		*pTM_Value = (Regs[TM] & 0x20)
-				? m_Thermometer_Map_2[Regs[TM] & 0x0F]
-				: m_Thermometer_Map_1[Regs[TM] & 0x0F] ;
-		state->m_Regs[TM] &= ~0x10;        /* Thermometer off */
-		status = UpdateReg(state, TM);
-		if (status < 0)
-			break;
-		state->m_Regs[EP4] &= ~0x03;       /* CAL_mode = 0 ????????? */
-		status = UpdateReg(state, EP4);
-		if (status < 0)
-			break;
-	} while (0);
-
-	return status;
-}
-
-static int StandBy(struct tda_state *state)
-{
-	int status = 0;
-	do {
-		state->m_Regs[EB12] &= ~0x20;  /* PD_AGC1_Det = 0 */
-		status = UpdateReg(state, EB12);
-		if (status < 0)
-			break;
-		state->m_Regs[EB18] &= ~0x83;  /* AGC1_loop_off = 0, AGC1_Gain = 6 dB */
-		status = UpdateReg(state, EB18);
-		if (status < 0)
-			break;
-		state->m_Regs[EB21] |= 0x03; /* AGC2_Gain = -6 dB */
-		state->m_Regs[EP3] = state->m_EP3_Standby;
-		status = UpdateReg(state, EP3);
-		if (status < 0)
-			break;
-		state->m_Regs[EB23] &= ~0x06; /* ForceLP_Fc2_En = 0, LP_Fc[2] = 0 */
-		status = UpdateRegs(state, EB21, EB23);
-		if (status < 0)
-			break;
-	} while (0);
-	return status;
-}
-
-static int CalcMainPLL(struct tda_state *state, u32 freq)
-{
-
-	u8  PostDiv;
-	u8  Div;
-	u64 OscFreq;
-	u32 MainDiv;
-
-	if (!SearchMap3(m_Main_PLL_Map, freq, &PostDiv, &Div))
-		return -EINVAL;
-
-	OscFreq = (u64) freq * (u64) Div;
-	OscFreq *= (u64) 16384;
-	do_div(OscFreq, (u64)16000000);
-	MainDiv = OscFreq;
-
-	state->m_Regs[MPD] = PostDiv & 0x77;
-	state->m_Regs[MD1] = ((MainDiv >> 16) & 0x7F);
-	state->m_Regs[MD2] = ((MainDiv >>  8) & 0xFF);
-	state->m_Regs[MD3] = (MainDiv & 0xFF);
-
-	return UpdateRegs(state, MPD, MD3);
-}
-
-static int CalcCalPLL(struct tda_state *state, u32 freq)
-{
-	u8 PostDiv;
-	u8 Div;
-	u64 OscFreq;
-	u32 CalDiv;
-
-	if (!SearchMap3(m_Cal_PLL_Map, freq, &PostDiv, &Div))
-		return -EINVAL;
-
-	OscFreq = (u64)freq * (u64)Div;
-	/* CalDiv = u32( OscFreq * 16384 / 16000000 ); */
-	OscFreq *= (u64)16384;
-	do_div(OscFreq, (u64)16000000);
-	CalDiv = OscFreq;
-
-	state->m_Regs[CPD] = PostDiv;
-	state->m_Regs[CD1] = ((CalDiv >> 16) & 0xFF);
-	state->m_Regs[CD2] = ((CalDiv >>  8) & 0xFF);
-	state->m_Regs[CD3] = (CalDiv & 0xFF);
-
-	return UpdateRegs(state, CPD, CD3);
-}
-
-static int CalibrateRF(struct tda_state *state,
-		       u8 RFBand, u32 freq, s32 *pCprog)
-{
-	int status = 0;
-	u8 Regs[NUM_REGS];
-	do {
-		u8 BP_Filter = 0;
-		u8 GainTaper = 0;
-		u8 RFC_K = 0;
-		u8 RFC_M = 0;
-
-		state->m_Regs[EP4] &= ~0x03; /* CAL_mode = 0 */
-		status = UpdateReg(state, EP4);
-		if (status < 0)
-			break;
-		state->m_Regs[EB18] |= 0x03;  /* AGC1_Gain = 3 */
-		status = UpdateReg(state, EB18);
-		if (status < 0)
-			break;
-
-		/* Switching off LT (as datasheet says) causes calibration on C1 to fail */
-		/* (Readout of Cprog is allways 255) */
-		if (state->m_Regs[ID] != 0x83)    /* C1: ID == 83, C2: ID == 84 */
-			state->m_Regs[EP3] |= 0x40; /* SM_LT = 1 */
-
-		if (!(SearchMap1(m_BP_Filter_Map, freq, &BP_Filter) &&
-			SearchMap1(m_GainTaper_Map, freq, &GainTaper) &&
-			SearchMap3(m_KM_Map, freq, &RFC_K, &RFC_M)))
-			return -EINVAL;
-
-		state->m_Regs[EP1] = (state->m_Regs[EP1] & ~0x07) | BP_Filter;
-		state->m_Regs[EP2] = (RFBand << 5) | GainTaper;
-
-		state->m_Regs[EB13] = (state->m_Regs[EB13] & ~0x7C) | (RFC_K << 4) | (RFC_M << 2);
-
-		status = UpdateRegs(state, EP1, EP3);
-		if (status < 0)
-			break;
-		status = UpdateReg(state, EB13);
-		if (status < 0)
-			break;
-
-		state->m_Regs[EB4] |= 0x20;    /* LO_ForceSrce = 1 */
-		status = UpdateReg(state, EB4);
-		if (status < 0)
-			break;
-
-		state->m_Regs[EB7] |= 0x20;    /* CAL_ForceSrce = 1 */
-		status = UpdateReg(state, EB7);
-		if (status < 0)
-			break;
-
-		state->m_Regs[EB14] = 0; /* RFC_Cprog = 0 */
-		status = UpdateReg(state, EB14);
-		if (status < 0)
-			break;
-
-		state->m_Regs[EB20] &= ~0x20;  /* ForceLock = 0; */
-		status = UpdateReg(state, EB20);
-		if (status < 0)
-			break;
-
-		state->m_Regs[EP4] |= 0x03;  /* CAL_Mode = 3 */
-		status = UpdateRegs(state, EP4, EP5);
-		if (status < 0)
-			break;
-
-		status = CalcCalPLL(state, freq);
-		if (status < 0)
-			break;
-		status = CalcMainPLL(state, freq + 1000000);
-		if (status < 0)
-			break;
-
-		msleep(5);
-		status = UpdateReg(state, EP2);
-		if (status < 0)
-			break;
-		status = UpdateReg(state, EP1);
-		if (status < 0)
-			break;
-		status = UpdateReg(state, EP2);
-		if (status < 0)
-			break;
-		status = UpdateReg(state, EP1);
-		if (status < 0)
-			break;
-
-		state->m_Regs[EB4] &= ~0x20;    /* LO_ForceSrce = 0 */
-		status = UpdateReg(state, EB4);
-		if (status < 0)
-			break;
-
-		state->m_Regs[EB7] &= ~0x20;    /* CAL_ForceSrce = 0 */
-		status = UpdateReg(state, EB7);
-		if (status < 0)
-			break;
-		msleep(10);
-
-		state->m_Regs[EB20] |= 0x20;  /* ForceLock = 1; */
-		status = UpdateReg(state, EB20);
-		if (status < 0)
-			break;
-		msleep(60);
-
-		state->m_Regs[EP4] &= ~0x03;  /* CAL_Mode = 0 */
-		state->m_Regs[EP3] &= ~0x40; /* SM_LT = 0 */
-		state->m_Regs[EB18] &= ~0x03;  /* AGC1_Gain = 0 */
-		status = UpdateReg(state, EB18);
-		if (status < 0)
-			break;
-		status = UpdateRegs(state, EP3, EP4);
-		if (status < 0)
-			break;
-		status = UpdateReg(state, EP1);
-		if (status < 0)
-			break;
-
-		status = ReadExtented(state, Regs);
-		if (status < 0)
-			break;
-
-		*pCprog = Regs[EB14];
-
-	} while (0);
-	return status;
-}
-
-static int RFTrackingFiltersInit(struct tda_state *state,
-				 u8 RFBand)
-{
-	int status = 0;
-
-	u32   RF1 = m_RF_Band_Map[RFBand].m_RF1_Default;
-	u32   RF2 = m_RF_Band_Map[RFBand].m_RF2_Default;
-	u32   RF3 = m_RF_Band_Map[RFBand].m_RF3_Default;
-	bool    bcal = false;
-
-	s32    Cprog_cal1 = 0;
-	s32    Cprog_table1 = 0;
-	s32    Cprog_cal2 = 0;
-	s32    Cprog_table2 = 0;
-	s32    Cprog_cal3 = 0;
-	s32    Cprog_table3 = 0;
-
-	state->m_RF_A1[RFBand] = 0;
-	state->m_RF_B1[RFBand] = 0;
-	state->m_RF_A2[RFBand] = 0;
-	state->m_RF_B2[RFBand] = 0;
-
-	do {
-		status = PowerScan(state, RFBand, RF1, &RF1, &bcal);
-		if (status < 0)
-			break;
-		if (bcal) {
-			status = CalibrateRF(state, RFBand, RF1, &Cprog_cal1);
-			if (status < 0)
-				break;
-		}
-		SearchMap2(m_RF_Cal_Map, RF1, &Cprog_table1);
-		if (!bcal)
-			Cprog_cal1 = Cprog_table1;
-		state->m_RF_B1[RFBand] = Cprog_cal1 - Cprog_table1;
-		/* state->m_RF_A1[RF_Band] = ???? */
-
-		if (RF2 == 0)
-			break;
-
-		status = PowerScan(state, RFBand, RF2, &RF2, &bcal);
-		if (status < 0)
-			break;
-		if (bcal) {
-			status = CalibrateRF(state, RFBand, RF2, &Cprog_cal2);
-			if (status < 0)
-				break;
-		}
-		SearchMap2(m_RF_Cal_Map, RF2, &Cprog_table2);
-		if (!bcal)
-			Cprog_cal2 = Cprog_table2;
-
-		state->m_RF_A1[RFBand] =
-			(Cprog_cal2 - Cprog_table2 - Cprog_cal1 + Cprog_table1) /
-			((s32)(RF2) - (s32)(RF1));
-
-		if (RF3 == 0)
-			break;
-
-		status = PowerScan(state, RFBand, RF3, &RF3, &bcal);
-		if (status < 0)
-			break;
-		if (bcal) {
-			status = CalibrateRF(state, RFBand, RF3, &Cprog_cal3);
-			if (status < 0)
-				break;
-		}
-		SearchMap2(m_RF_Cal_Map, RF3, &Cprog_table3);
-		if (!bcal)
-			Cprog_cal3 = Cprog_table3;
-		state->m_RF_A2[RFBand] = (Cprog_cal3 - Cprog_table3 - Cprog_cal2 + Cprog_table2) / ((s32)(RF3) - (s32)(RF2));
-		state->m_RF_B2[RFBand] = Cprog_cal2 - Cprog_table2;
-
-	} while (0);
-
-	state->m_RF1[RFBand] = RF1;
-	state->m_RF2[RFBand] = RF2;
-	state->m_RF3[RFBand] = RF3;
-
-#if 0
-	printk(KERN_ERR "tda18271c2dd: %s %d RF1 = %d A1 = %d B1 = %d RF2 = %d A2 = %d B2 = %d RF3 = %d\n", __func__,
-	       RFBand, RF1, state->m_RF_A1[RFBand], state->m_RF_B1[RFBand], RF2,
-	       state->m_RF_A2[RFBand], state->m_RF_B2[RFBand], RF3);
-#endif
-
-	return status;
-}
-
-static int PowerScan(struct tda_state *state,
-		     u8 RFBand, u32 RF_in, u32 *pRF_Out, bool *pbcal)
-{
-	int status = 0;
-	do {
-		u8   Gain_Taper = 0;
-		s32  RFC_Cprog = 0;
-		u8   CID_Target = 0;
-		u8   CountLimit = 0;
-		u32  freq_MainPLL;
-		u8   Regs[NUM_REGS];
-		u8   CID_Gain;
-		s32  Count = 0;
-		int  sign  = 1;
-		bool wait = false;
-
-		if (!(SearchMap2(m_RF_Cal_Map, RF_in, &RFC_Cprog) &&
-		      SearchMap1(m_GainTaper_Map, RF_in, &Gain_Taper) &&
-		      SearchMap3(m_CID_Target_Map, RF_in, &CID_Target, &CountLimit))) {
-
-			printk(KERN_ERR "tda18271c2dd: %s Search map failed\n", __func__);
-			return -EINVAL;
-		}
-
-		state->m_Regs[EP2] = (RFBand << 5) | Gain_Taper;
-		state->m_Regs[EB14] = (RFC_Cprog);
-		status = UpdateReg(state, EP2);
-		if (status < 0)
-			break;
-		status = UpdateReg(state, EB14);
-		if (status < 0)
-			break;
-
-		freq_MainPLL = RF_in + 1000000;
-		status = CalcMainPLL(state, freq_MainPLL);
-		if (status < 0)
-			break;
-		msleep(5);
-		state->m_Regs[EP4] = (state->m_Regs[EP4] & ~0x03) | 1;    /* CAL_mode = 1 */
-		status = UpdateReg(state, EP4);
-		if (status < 0)
-			break;
-		status = UpdateReg(state, EP2);  /* Launch power measurement */
-		if (status < 0)
-			break;
-		status = ReadExtented(state, Regs);
-		if (status < 0)
-			break;
-		CID_Gain = Regs[EB10] & 0x3F;
-		state->m_Regs[ID] = Regs[ID];  /* Chip version, (needed for C1 workarround in CalibrateRF) */
-
-		*pRF_Out = RF_in;
-
-		while (CID_Gain < CID_Target) {
-			freq_MainPLL = RF_in + sign * Count + 1000000;
-			status = CalcMainPLL(state, freq_MainPLL);
-			if (status < 0)
-				break;
-			msleep(wait ? 5 : 1);
-			wait = false;
-			status = UpdateReg(state, EP2);  /* Launch power measurement */
-			if (status < 0)
-				break;
-			status = ReadExtented(state, Regs);
-			if (status < 0)
-				break;
-			CID_Gain = Regs[EB10] & 0x3F;
-			Count += 200000;
-
-			if (Count < CountLimit * 100000)
-				continue;
-			if (sign < 0)
-				break;
-
-			sign = -sign;
-			Count = 200000;
-			wait = true;
-		}
-		status = status;
-		if (status < 0)
-			break;
-		if (CID_Gain >= CID_Target) {
-			*pbcal = true;
-			*pRF_Out = freq_MainPLL - 1000000;
-		} else
-			*pbcal = false;
-	} while (0);
-
-	return status;
-}
-
-static int PowerScanInit(struct tda_state *state)
-{
-	int status = 0;
-	do {
-		state->m_Regs[EP3] = (state->m_Regs[EP3] & ~0x1F) | 0x12;
-		state->m_Regs[EP4] = (state->m_Regs[EP4] & ~0x1F); /* If level = 0, Cal mode = 0 */
-		status = UpdateRegs(state, EP3, EP4);
-		if (status < 0)
-			break;
-		state->m_Regs[EB18] = (state->m_Regs[EB18] & ~0x03); /* AGC 1 Gain = 0 */
-		status = UpdateReg(state, EB18);
-		if (status < 0)
-			break;
-		state->m_Regs[EB21] = (state->m_Regs[EB21] & ~0x03); /* AGC 2 Gain = 0 (Datasheet = 3) */
-		state->m_Regs[EB23] = (state->m_Regs[EB23] | 0x06); /* ForceLP_Fc2_En = 1, LPFc[2] = 1 */
-		status = UpdateRegs(state, EB21, EB23);
-		if (status < 0)
-			break;
-	} while (0);
-	return status;
-}
-
-static int CalcRFFilterCurve(struct tda_state *state)
-{
-	int status = 0;
-	do {
-		msleep(200);      /* Temperature stabilisation */
-		status = PowerScanInit(state);
-		if (status < 0)
-			break;
-		status = RFTrackingFiltersInit(state, 0);
-		if (status < 0)
-			break;
-		status = RFTrackingFiltersInit(state, 1);
-		if (status < 0)
-			break;
-		status = RFTrackingFiltersInit(state, 2);
-		if (status < 0)
-			break;
-		status = RFTrackingFiltersInit(state, 3);
-		if (status < 0)
-			break;
-		status = RFTrackingFiltersInit(state, 4);
-		if (status < 0)
-			break;
-		status = RFTrackingFiltersInit(state, 5);
-		if (status < 0)
-			break;
-		status = RFTrackingFiltersInit(state, 6);
-		if (status < 0)
-			break;
-		status = ThermometerRead(state, &state->m_TMValue_RFCal); /* also switches off Cal mode !!! */
-		if (status < 0)
-			break;
-	} while (0);
-
-	return status;
-}
-
-static int FixedContentsI2CUpdate(struct tda_state *state)
-{
-	static u8 InitRegs[] = {
-		0x08, 0x80, 0xC6,
-		0xDF, 0x16, 0x60, 0x80,
-		0x80, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00,
-		0xFC, 0x01, 0x84, 0x41,
-		0x01, 0x84, 0x40, 0x07,
-		0x00, 0x00, 0x96, 0x3F,
-		0xC1, 0x00, 0x8F, 0x00,
-		0x00, 0x8C, 0x00, 0x20,
-		0xB3, 0x48, 0xB0,
-	};
-	int status = 0;
-	memcpy(&state->m_Regs[TM], InitRegs, EB23 - TM + 1);
-	do {
-		status = UpdateRegs(state, TM, EB23);
-		if (status < 0)
-			break;
-
-		/* AGC1 gain setup */
-		state->m_Regs[EB17] = 0x00;
-		status = UpdateReg(state, EB17);
-		if (status < 0)
-			break;
-		state->m_Regs[EB17] = 0x03;
-		status = UpdateReg(state, EB17);
-		if (status < 0)
-			break;
-		state->m_Regs[EB17] = 0x43;
-		status = UpdateReg(state, EB17);
-		if (status < 0)
-			break;
-		state->m_Regs[EB17] = 0x4C;
-		status = UpdateReg(state, EB17);
-		if (status < 0)
-			break;
-
-		/* IRC Cal Low band */
-		state->m_Regs[EP3] = 0x1F;
-		state->m_Regs[EP4] = 0x66;
-		state->m_Regs[EP5] = 0x81;
-		state->m_Regs[CPD] = 0xCC;
-		state->m_Regs[CD1] = 0x6C;
-		state->m_Regs[CD2] = 0x00;
-		state->m_Regs[CD3] = 0x00;
-		state->m_Regs[MPD] = 0xC5;
-		state->m_Regs[MD1] = 0x77;
-		state->m_Regs[MD2] = 0x08;
-		state->m_Regs[MD3] = 0x00;
-		status = UpdateRegs(state, EP2, MD3); /* diff between sw and datasheet (ep3-md3) */
-		if (status < 0)
-			break;
-
-#if 0
-		state->m_Regs[EB4] = 0x61;          /* missing in sw */
-		status = UpdateReg(state, EB4);
-		if (status < 0)
-			break;
-		msleep(1);
-		state->m_Regs[EB4] = 0x41;
-		status = UpdateReg(state, EB4);
-		if (status < 0)
-			break;
-#endif
-
-		msleep(5);
-		status = UpdateReg(state, EP1);
-		if (status < 0)
-			break;
-		msleep(5);
-
-		state->m_Regs[EP5] = 0x85;
-		state->m_Regs[CPD] = 0xCB;
-		state->m_Regs[CD1] = 0x66;
-		state->m_Regs[CD2] = 0x70;
-		status = UpdateRegs(state, EP3, CD3);
-		if (status < 0)
-			break;
-		msleep(5);
-		status = UpdateReg(state, EP2);
-		if (status < 0)
-			break;
-		msleep(30);
-
-		/* IRC Cal mid band */
-		state->m_Regs[EP5] = 0x82;
-		state->m_Regs[CPD] = 0xA8;
-		state->m_Regs[CD2] = 0x00;
-		state->m_Regs[MPD] = 0xA1; /* Datasheet = 0xA9 */
-		state->m_Regs[MD1] = 0x73;
-		state->m_Regs[MD2] = 0x1A;
-		status = UpdateRegs(state, EP3, MD3);
-		if (status < 0)
-			break;
-
-		msleep(5);
-		status = UpdateReg(state, EP1);
-		if (status < 0)
-			break;
-		msleep(5);
-
-		state->m_Regs[EP5] = 0x86;
-		state->m_Regs[CPD] = 0xA8;
-		state->m_Regs[CD1] = 0x66;
-		state->m_Regs[CD2] = 0xA0;
-		status = UpdateRegs(state, EP3, CD3);
-		if (status < 0)
-			break;
-		msleep(5);
-		status = UpdateReg(state, EP2);
-		if (status < 0)
-			break;
-		msleep(30);
-
-		/* IRC Cal high band */
-		state->m_Regs[EP5] = 0x83;
-		state->m_Regs[CPD] = 0x98;
-		state->m_Regs[CD1] = 0x65;
-		state->m_Regs[CD2] = 0x00;
-		state->m_Regs[MPD] = 0x91;  /* Datasheet = 0x91 */
-		state->m_Regs[MD1] = 0x71;
-		state->m_Regs[MD2] = 0xCD;
-		status = UpdateRegs(state, EP3, MD3);
-		if (status < 0)
-			break;
-		msleep(5);
-		status = UpdateReg(state, EP1);
-		if (status < 0)
-			break;
-		msleep(5);
-		state->m_Regs[EP5] = 0x87;
-		state->m_Regs[CD1] = 0x65;
-		state->m_Regs[CD2] = 0x50;
-		status = UpdateRegs(state, EP3, CD3);
-		if (status < 0)
-			break;
-		msleep(5);
-		status = UpdateReg(state, EP2);
-		if (status < 0)
-			break;
-		msleep(30);
-
-		/* Back to normal */
-		state->m_Regs[EP4] = 0x64;
-		status = UpdateReg(state, EP4);
-		if (status < 0)
-			break;
-		status = UpdateReg(state, EP1);
-		if (status < 0)
-			break;
-
-	} while (0);
-	return status;
-}
-
-static int InitCal(struct tda_state *state)
-{
-	int status = 0;
-
-	do {
-		status = FixedContentsI2CUpdate(state);
-		if (status < 0)
-			break;
-		status = CalcRFFilterCurve(state);
-		if (status < 0)
-			break;
-		status = StandBy(state);
-		if (status < 0)
-			break;
-		/* m_bInitDone = true; */
-	} while (0);
-	return status;
-};
-
-static int RFTrackingFiltersCorrection(struct tda_state *state,
-				       u32 Frequency)
-{
-	int status = 0;
-	s32 Cprog_table;
-	u8 RFBand;
-	u8 dCoverdT;
-
-	if (!SearchMap2(m_RF_Cal_Map, Frequency, &Cprog_table) ||
-	    !SearchMap4(m_RF_Band_Map, Frequency, &RFBand) ||
-	    !SearchMap1(m_RF_Cal_DC_Over_DT_Map, Frequency, &dCoverdT))
-
-		return -EINVAL;
-
-	do {
-		u8 TMValue_Current;
-		u32   RF1 = state->m_RF1[RFBand];
-		u32   RF2 = state->m_RF1[RFBand];
-		u32   RF3 = state->m_RF1[RFBand];
-		s32    RF_A1 = state->m_RF_A1[RFBand];
-		s32    RF_B1 = state->m_RF_B1[RFBand];
-		s32    RF_A2 = state->m_RF_A2[RFBand];
-		s32    RF_B2 = state->m_RF_B2[RFBand];
-		s32 Capprox = 0;
-		int TComp;
-
-		state->m_Regs[EP3] &= ~0xE0;  /* Power up */
-		status = UpdateReg(state, EP3);
-		if (status < 0)
-			break;
-
-		status = ThermometerRead(state, &TMValue_Current);
-		if (status < 0)
-			break;
-
-		if (RF3 == 0 || Frequency < RF2)
-			Capprox = RF_A1 * ((s32)(Frequency) - (s32)(RF1)) + RF_B1 + Cprog_table;
-		else
-			Capprox = RF_A2 * ((s32)(Frequency) - (s32)(RF2)) + RF_B2 + Cprog_table;
-
-		TComp = (int)(dCoverdT) * ((int)(TMValue_Current) - (int)(state->m_TMValue_RFCal))/1000;
-
-		Capprox += TComp;
-
-		if (Capprox < 0)
-			Capprox = 0;
-		else if (Capprox > 255)
-			Capprox = 255;
-
-
-		/* TODO Temperature compensation. There is defenitely a scale factor */
-		/*      missing in the datasheet, so leave it out for now.           */
-		state->m_Regs[EB14] = Capprox;
-
-		status = UpdateReg(state, EB14);
-		if (status < 0)
-			break;
-
-	} while (0);
-	return status;
-}
-
-static int ChannelConfiguration(struct tda_state *state,
-				u32 Frequency, int Standard)
-{
-
-	s32 IntermediateFrequency = m_StandardTable[Standard].m_IFFrequency;
-	int status = 0;
-
-	u8 BP_Filter = 0;
-	u8 RF_Band = 0;
-	u8 GainTaper = 0;
-	u8 IR_Meas = 0;
-
-	state->IF = IntermediateFrequency;
-	/* printk("tda18271c2dd: %s Freq = %d Standard = %d IF = %d\n", __func__, Frequency, Standard, IntermediateFrequency); */
-	/* get values from tables */
-
-	if (!(SearchMap1(m_BP_Filter_Map, Frequency, &BP_Filter) &&
-	       SearchMap1(m_GainTaper_Map, Frequency, &GainTaper) &&
-	       SearchMap1(m_IR_Meas_Map, Frequency, &IR_Meas) &&
-	       SearchMap4(m_RF_Band_Map, Frequency, &RF_Band))) {
-
-		printk(KERN_ERR "tda18271c2dd: %s SearchMap failed\n", __func__);
-		return -EINVAL;
-	}
-
-	do {
-		state->m_Regs[EP3] = (state->m_Regs[EP3] & ~0x1F) | m_StandardTable[Standard].m_EP3_4_0;
-		state->m_Regs[EP3] &= ~0x04;   /* switch RFAGC to high speed mode */
-
-		/* m_EP4 default for XToutOn, CAL_Mode (0) */
-		state->m_Regs[EP4] = state->m_EP4 | ((Standard > HF_AnalogMax) ? state->m_IFLevelDigital : state->m_IFLevelAnalog);
-		/* state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDigital; */
-		if (Standard <= HF_AnalogMax)
-			state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelAnalog;
-		else if (Standard <= HF_ATSC)
-			state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDVBT;
-		else if (Standard <= HF_DVBC)
-			state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDVBC;
-		else
-			state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDigital;
-
-		if ((Standard == HF_FM_Radio) && state->m_bFMInput)
-			state->m_Regs[EP4] |= 80;
-
-		state->m_Regs[MPD] &= ~0x80;
-		if (Standard > HF_AnalogMax)
-			state->m_Regs[MPD] |= 0x80; /* Add IF_notch for digital */
-
-		state->m_Regs[EB22] = m_StandardTable[Standard].m_EB22;
-
-		/* Note: This is missing from flowchart in TDA18271 specification ( 1.5 MHz cutoff for FM ) */
-		if (Standard == HF_FM_Radio)
-			state->m_Regs[EB23] |=  0x06; /* ForceLP_Fc2_En = 1, LPFc[2] = 1 */
-		else
-			state->m_Regs[EB23] &= ~0x06; /* ForceLP_Fc2_En = 0, LPFc[2] = 0 */
-
-		status = UpdateRegs(state, EB22, EB23);
-		if (status < 0)
-			break;
-
-		state->m_Regs[EP1] = (state->m_Regs[EP1] & ~0x07) | 0x40 | BP_Filter;   /* Dis_Power_level = 1, Filter */
-		state->m_Regs[EP5] = (state->m_Regs[EP5] & ~0x07) | IR_Meas;
-		state->m_Regs[EP2] = (RF_Band << 5) | GainTaper;
-
-		state->m_Regs[EB1] = (state->m_Regs[EB1] & ~0x07) |
-			(state->m_bMaster ? 0x04 : 0x00); /* CALVCO_FortLOn = MS */
-		/* AGC1_always_master = 0 */
-		/* AGC_firstn = 0 */
-		status = UpdateReg(state, EB1);
-		if (status < 0)
-			break;
-
-		if (state->m_bMaster) {
-			status = CalcMainPLL(state, Frequency + IntermediateFrequency);
-			if (status < 0)
-				break;
-			status = UpdateRegs(state, TM, EP5);
-			if (status < 0)
-				break;
-			state->m_Regs[EB4] |= 0x20;    /* LO_forceSrce = 1 */
-			status = UpdateReg(state, EB4);
-			if (status < 0)
-				break;
-			msleep(1);
-			state->m_Regs[EB4] &= ~0x20;   /* LO_forceSrce = 0 */
-			status = UpdateReg(state, EB4);
-			if (status < 0)
-				break;
-		} else {
-			u8 PostDiv = 0;
-			u8 Div;
-			status = CalcCalPLL(state, Frequency + IntermediateFrequency);
-			if (status < 0)
-				break;
-
-			SearchMap3(m_Cal_PLL_Map, Frequency + IntermediateFrequency, &PostDiv, &Div);
-			state->m_Regs[MPD] = (state->m_Regs[MPD] & ~0x7F) | (PostDiv & 0x77);
-			status = UpdateReg(state, MPD);
-			if (status < 0)
-				break;
-			status = UpdateRegs(state, TM, EP5);
-			if (status < 0)
-				break;
-
-			state->m_Regs[EB7] |= 0x20;    /* CAL_forceSrce = 1 */
-			status = UpdateReg(state, EB7);
-			if (status < 0)
-				break;
-			msleep(1);
-			state->m_Regs[EB7] &= ~0x20;   /* CAL_forceSrce = 0 */
-			status = UpdateReg(state, EB7);
-			if (status < 0)
-				break;
-		}
-		msleep(20);
-		if (Standard != HF_FM_Radio)
-			state->m_Regs[EP3] |= 0x04;    /* RFAGC to normal mode */
-		status = UpdateReg(state, EP3);
-		if (status < 0)
-			break;
-
-	} while (0);
-	return status;
-}
-
-static int sleep(struct dvb_frontend *fe)
-{
-	struct tda_state *state = fe->tuner_priv;
-
-	StandBy(state);
-	return 0;
-}
-
-static int init(struct dvb_frontend *fe)
-{
-	return 0;
-}
-
-static int release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-
-static int set_params(struct dvb_frontend *fe)
-{
-	struct tda_state *state = fe->tuner_priv;
-	int status = 0;
-	int Standard;
-	u32 bw = fe->dtv_property_cache.bandwidth_hz;
-	u32 delsys  = fe->dtv_property_cache.delivery_system;
-
-	state->m_Frequency = fe->dtv_property_cache.frequency;
-
-	switch (delsys) {
-	case  SYS_DVBT:
-	case  SYS_DVBT2:
-		switch (bw) {
-		case 6000000:
-			Standard = HF_DVBT_6MHZ;
-			break;
-		case 7000000:
-			Standard = HF_DVBT_7MHZ;
-			break;
-		case 8000000:
-			Standard = HF_DVBT_8MHZ;
-			break;
-		default:
-			return -EINVAL;
-		}
-	case SYS_DVBC_ANNEX_A:
-	case SYS_DVBC_ANNEX_C:
-		if (bw <= 6000000)
-			Standard = HF_DVBC_6MHZ;
-		else if (bw <= 7000000)
-			Standard = HF_DVBC_7MHZ;
-		else
-			Standard = HF_DVBC_8MHZ;
-		break;
-	default:
-		return -EINVAL;
-	}
-	do {
-		status = RFTrackingFiltersCorrection(state, state->m_Frequency);
-		if (status < 0)
-			break;
-		status = ChannelConfiguration(state, state->m_Frequency,
-					      Standard);
-		if (status < 0)
-			break;
-
-		msleep(state->m_SettlingTime);  /* Allow AGC's to settle down */
-	} while (0);
-	return status;
-}
-
-#if 0
-static int GetSignalStrength(s32 *pSignalStrength, u32 RFAgc, u32 IFAgc)
-{
-	if (IFAgc < 500) {
-		/* Scale this from 0 to 50000 */
-		*pSignalStrength = IFAgc * 100;
-	} else {
-		/* Scale range 500-1500 to 50000-80000 */
-		*pSignalStrength = 50000 + (IFAgc - 500) * 30;
-	}
-
-	return 0;
-}
-#endif
-
-static int get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct tda_state *state = fe->tuner_priv;
-
-	*frequency = state->IF;
-	return 0;
-}
-
-static int get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	/* struct tda_state *state = fe->tuner_priv; */
-	/* *bandwidth = priv->bandwidth; */
-	return 0;
-}
-
-
-static struct dvb_tuner_ops tuner_ops = {
-	.info = {
-		.name = "NXP TDA18271C2D",
-		.frequency_min  =  47125000,
-		.frequency_max  = 865000000,
-		.frequency_step =     62500
-	},
-	.init              = init,
-	.sleep             = sleep,
-	.set_params        = set_params,
-	.release           = release,
-	.get_if_frequency  = get_if_frequency,
-	.get_bandwidth     = get_bandwidth,
-};
-
-struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe,
-					 struct i2c_adapter *i2c, u8 adr)
-{
-	struct tda_state *state;
-
-	state = kzalloc(sizeof(struct tda_state), GFP_KERNEL);
-	if (!state)
-		return NULL;
-
-	fe->tuner_priv = state;
-	state->adr = adr;
-	state->i2c = i2c;
-	memcpy(&fe->ops.tuner_ops, &tuner_ops, sizeof(struct dvb_tuner_ops));
-	reset(state);
-	InitCal(state);
-
-	return fe;
-}
-EXPORT_SYMBOL_GPL(tda18271c2dd_attach);
-
-MODULE_DESCRIPTION("TDA18271C2 driver");
-MODULE_AUTHOR("DD");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda18271c2dd.h b/drivers/media/dvb/frontends/tda18271c2dd.h
deleted file mode 100644
index 1389c74..0000000
--- a/drivers/media/dvb/frontends/tda18271c2dd.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _TDA18271C2DD_H_
-#define _TDA18271C2DD_H_
-#if defined(CONFIG_DVB_TDA18271C2DD) || (defined(CONFIG_DVB_TDA18271C2DD_MODULE) \
-        && defined(MODULE))
-struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe,
-					 struct i2c_adapter *i2c, u8 adr);
-#else
-static inline struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe,
-					 struct i2c_adapter *i2c, u8 adr)
-{
-        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-        return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/dvb/frontends/tda18271c2dd_maps.h b/drivers/media/dvb/frontends/tda18271c2dd_maps.h
deleted file mode 100644
index b87661b..0000000
--- a/drivers/media/dvb/frontends/tda18271c2dd_maps.h
+++ /dev/null
@@ -1,814 +0,0 @@
-enum HF_S {
-	HF_None = 0, HF_B, HF_DK, HF_G, HF_I, HF_L, HF_L1, HF_MN, HF_FM_Radio,
-	HF_AnalogMax, HF_DVBT_6MHZ, HF_DVBT_7MHZ, HF_DVBT_8MHZ,
-	HF_DVBT, HF_ATSC,  HF_DVBC_6MHZ,  HF_DVBC_7MHZ,
-	HF_DVBC_8MHZ, HF_DVBC
-};
-
-struct SStandardParam m_StandardTable[] = {
-	{       0,        0, 0x00, 0x00 },    /* HF_None */
-	{ 6000000,  7000000, 0x1D, 0x2C },    /* HF_B, */
-	{ 6900000,  8000000, 0x1E, 0x2C },    /* HF_DK, */
-	{ 7100000,  8000000, 0x1E, 0x2C },    /* HF_G, */
-	{ 7250000,  8000000, 0x1E, 0x2C },    /* HF_I, */
-	{ 6900000,  8000000, 0x1E, 0x2C },    /* HF_L, */
-	{ 1250000,  8000000, 0x1E, 0x2C },    /* HF_L1, */
-	{ 5400000,  6000000, 0x1C, 0x2C },    /* HF_MN, */
-	{ 1250000,   500000, 0x18, 0x2C },    /* HF_FM_Radio, */
-	{       0,        0, 0x00, 0x00 },    /* HF_AnalogMax (Unused) */
-	{ 3300000,  6000000, 0x1C, 0x58 },    /* HF_DVBT_6MHZ */
-	{ 3500000,  7000000, 0x1C, 0x37 },    /* HF_DVBT_7MHZ */
-	{ 4000000,  8000000, 0x1D, 0x37 },    /* HF_DVBT_8MHZ */
-	{       0,        0, 0x00, 0x00 },    /* HF_DVBT (Unused) */
-	{ 5000000,  6000000, 0x1C, 0x37 },    /* HF_ATSC  (center = 3.25 MHz) */
-	{ 4000000,  6000000, 0x1D, 0x58 },    /* HF_DVBC_6MHZ (Chicago) */
-	{ 4500000,  7000000, 0x1E, 0x37 },    /* HF_DVBC_7MHZ (not documented by NXP) */
-	{ 5000000,  8000000, 0x1F, 0x37 },    /* HF_DVBC_8MHZ */
-	{       0,        0, 0x00, 0x00 },    /* HF_DVBC (Unused) */
-};
-
-struct SMap  m_BP_Filter_Map[] = {
-	{   62000000,  0x00 },
-	{   84000000,  0x01 },
-	{  100000000,  0x02 },
-	{  140000000,  0x03 },
-	{  170000000,  0x04 },
-	{  180000000,  0x05 },
-	{  865000000,  0x06 },
-	{          0,  0x00 },    /* Table End */
-};
-
-static struct SMapI m_RF_Cal_Map[] = {
-	{   41000000,  0x0F },
-	{   43000000,  0x1C },
-	{   45000000,  0x2F },
-	{   46000000,  0x39 },
-	{   47000000,  0x40 },
-	{   47900000,  0x50 },
-	{   49100000,  0x16 },
-	{   50000000,  0x18 },
-	{   51000000,  0x20 },
-	{   53000000,  0x28 },
-	{   55000000,  0x2B },
-	{   56000000,  0x32 },
-	{   57000000,  0x35 },
-	{   58000000,  0x3E },
-	{   59000000,  0x43 },
-	{   60000000,  0x4E },
-	{   61100000,  0x55 },
-	{   63000000,  0x0F },
-	{   64000000,  0x11 },
-	{   65000000,  0x12 },
-	{   66000000,  0x15 },
-	{   67000000,  0x16 },
-	{   68000000,  0x17 },
-	{   70000000,  0x19 },
-	{   71000000,  0x1C },
-	{   72000000,  0x1D },
-	{   73000000,  0x1F },
-	{   74000000,  0x20 },
-	{   75000000,  0x21 },
-	{   76000000,  0x24 },
-	{   77000000,  0x25 },
-	{   78000000,  0x27 },
-	{   80000000,  0x28 },
-	{   81000000,  0x29 },
-	{   82000000,  0x2D },
-	{   83000000,  0x2E },
-	{   84000000,  0x2F },
-	{   85000000,  0x31 },
-	{   86000000,  0x33 },
-	{   87000000,  0x34 },
-	{   88000000,  0x35 },
-	{   89000000,  0x37 },
-	{   90000000,  0x38 },
-	{   91000000,  0x39 },
-	{   93000000,  0x3C },
-	{   94000000,  0x3E },
-	{   95000000,  0x3F },
-	{   96000000,  0x40 },
-	{   97000000,  0x42 },
-	{   99000000,  0x45 },
-	{  100000000,  0x46 },
-	{  102000000,  0x48 },
-	{  103000000,  0x4A },
-	{  105000000,  0x4D },
-	{  106000000,  0x4E },
-	{  107000000,  0x50 },
-	{  108000000,  0x51 },
-	{  110000000,  0x54 },
-	{  111000000,  0x56 },
-	{  112000000,  0x57 },
-	{  113000000,  0x58 },
-	{  114000000,  0x59 },
-	{  115000000,  0x5C },
-	{  116000000,  0x5D },
-	{  117000000,  0x5F },
-	{  119000000,  0x60 },
-	{  120000000,  0x64 },
-	{  121000000,  0x65 },
-	{  122000000,  0x66 },
-	{  123000000,  0x68 },
-	{  124000000,  0x69 },
-	{  125000000,  0x6C },
-	{  126000000,  0x6D },
-	{  127000000,  0x6E },
-	{  128000000,  0x70 },
-	{  129000000,  0x71 },
-	{  130000000,  0x75 },
-	{  131000000,  0x77 },
-	{  132000000,  0x78 },
-	{  133000000,  0x7B },
-	{  134000000,  0x7E },
-	{  135000000,  0x81 },
-	{  136000000,  0x82 },
-	{  137000000,  0x87 },
-	{  138000000,  0x88 },
-	{  139000000,  0x8D },
-	{  140000000,  0x8E },
-	{  141000000,  0x91 },
-	{  142000000,  0x95 },
-	{  143000000,  0x9A },
-	{  144000000,  0x9D },
-	{  145000000,  0xA1 },
-	{  146000000,  0xA2 },
-	{  147000000,  0xA4 },
-	{  148000000,  0xA9 },
-	{  149000000,  0xAE },
-	{  150000000,  0xB0 },
-	{  151000000,  0xB1 },
-	{  152000000,  0xB7 },
-	{  152600000,  0xBD },
-	{  154000000,  0x20 },
-	{  155000000,  0x22 },
-	{  156000000,  0x24 },
-	{  157000000,  0x25 },
-	{  158000000,  0x27 },
-	{  159000000,  0x29 },
-	{  160000000,  0x2C },
-	{  161000000,  0x2D },
-	{  163000000,  0x2E },
-	{  164000000,  0x2F },
-	{  164700000,  0x30 },
-	{  166000000,  0x11 },
-	{  167000000,  0x12 },
-	{  168000000,  0x13 },
-	{  169000000,  0x14 },
-	{  170000000,  0x15 },
-	{  172000000,  0x16 },
-	{  173000000,  0x17 },
-	{  174000000,  0x18 },
-	{  175000000,  0x1A },
-	{  176000000,  0x1B },
-	{  178000000,  0x1D },
-	{  179000000,  0x1E },
-	{  180000000,  0x1F },
-	{  181000000,  0x20 },
-	{  182000000,  0x21 },
-	{  183000000,  0x22 },
-	{  184000000,  0x24 },
-	{  185000000,  0x25 },
-	{  186000000,  0x26 },
-	{  187000000,  0x27 },
-	{  188000000,  0x29 },
-	{  189000000,  0x2A },
-	{  190000000,  0x2C },
-	{  191000000,  0x2D },
-	{  192000000,  0x2E },
-	{  193000000,  0x2F },
-	{  194000000,  0x30 },
-	{  195000000,  0x33 },
-	{  196000000,  0x35 },
-	{  198000000,  0x36 },
-	{  200000000,  0x38 },
-	{  201000000,  0x3C },
-	{  202000000,  0x3D },
-	{  203500000,  0x3E },
-	{  206000000,  0x0E },
-	{  208000000,  0x0F },
-	{  212000000,  0x10 },
-	{  216000000,  0x11 },
-	{  217000000,  0x12 },
-	{  218000000,  0x13 },
-	{  220000000,  0x14 },
-	{  222000000,  0x15 },
-	{  225000000,  0x16 },
-	{  228000000,  0x17 },
-	{  231000000,  0x18 },
-	{  234000000,  0x19 },
-	{  235000000,  0x1A },
-	{  236000000,  0x1B },
-	{  237000000,  0x1C },
-	{  240000000,  0x1D },
-	{  242000000,  0x1E },
-	{  244000000,  0x1F },
-	{  247000000,  0x20 },
-	{  249000000,  0x21 },
-	{  252000000,  0x22 },
-	{  253000000,  0x23 },
-	{  254000000,  0x24 },
-	{  256000000,  0x25 },
-	{  259000000,  0x26 },
-	{  262000000,  0x27 },
-	{  264000000,  0x28 },
-	{  267000000,  0x29 },
-	{  269000000,  0x2A },
-	{  271000000,  0x2B },
-	{  273000000,  0x2C },
-	{  275000000,  0x2D },
-	{  277000000,  0x2E },
-	{  279000000,  0x2F },
-	{  282000000,  0x30 },
-	{  284000000,  0x31 },
-	{  286000000,  0x32 },
-	{  287000000,  0x33 },
-	{  290000000,  0x34 },
-	{  293000000,  0x35 },
-	{  295000000,  0x36 },
-	{  297000000,  0x37 },
-	{  300000000,  0x38 },
-	{  303000000,  0x39 },
-	{  305000000,  0x3A },
-	{  306000000,  0x3B },
-	{  307000000,  0x3C },
-	{  310000000,  0x3D },
-	{  312000000,  0x3E },
-	{  315000000,  0x3F },
-	{  318000000,  0x40 },
-	{  320000000,  0x41 },
-	{  323000000,  0x42 },
-	{  324000000,  0x43 },
-	{  325000000,  0x44 },
-	{  327000000,  0x45 },
-	{  331000000,  0x46 },
-	{  334000000,  0x47 },
-	{  337000000,  0x48 },
-	{  339000000,  0x49 },
-	{  340000000,  0x4A },
-	{  341000000,  0x4B },
-	{  343000000,  0x4C },
-	{  345000000,  0x4D },
-	{  349000000,  0x4E },
-	{  352000000,  0x4F },
-	{  353000000,  0x50 },
-	{  355000000,  0x51 },
-	{  357000000,  0x52 },
-	{  359000000,  0x53 },
-	{  361000000,  0x54 },
-	{  362000000,  0x55 },
-	{  364000000,  0x56 },
-	{  368000000,  0x57 },
-	{  370000000,  0x58 },
-	{  372000000,  0x59 },
-	{  375000000,  0x5A },
-	{  376000000,  0x5B },
-	{  377000000,  0x5C },
-	{  379000000,  0x5D },
-	{  382000000,  0x5E },
-	{  384000000,  0x5F },
-	{  385000000,  0x60 },
-	{  386000000,  0x61 },
-	{  388000000,  0x62 },
-	{  390000000,  0x63 },
-	{  393000000,  0x64 },
-	{  394000000,  0x65 },
-	{  396000000,  0x66 },
-	{  397000000,  0x67 },
-	{  398000000,  0x68 },
-	{  400000000,  0x69 },
-	{  402000000,  0x6A },
-	{  403000000,  0x6B },
-	{  407000000,  0x6C },
-	{  408000000,  0x6D },
-	{  409000000,  0x6E },
-	{  410000000,  0x6F },
-	{  411000000,  0x70 },
-	{  412000000,  0x71 },
-	{  413000000,  0x72 },
-	{  414000000,  0x73 },
-	{  417000000,  0x74 },
-	{  418000000,  0x75 },
-	{  420000000,  0x76 },
-	{  422000000,  0x77 },
-	{  423000000,  0x78 },
-	{  424000000,  0x79 },
-	{  427000000,  0x7A },
-	{  428000000,  0x7B },
-	{  429000000,  0x7D },
-	{  432000000,  0x7F },
-	{  434000000,  0x80 },
-	{  435000000,  0x81 },
-	{  436000000,  0x83 },
-	{  437000000,  0x84 },
-	{  438000000,  0x85 },
-	{  439000000,  0x86 },
-	{  440000000,  0x87 },
-	{  441000000,  0x88 },
-	{  442000000,  0x89 },
-	{  445000000,  0x8A },
-	{  446000000,  0x8B },
-	{  447000000,  0x8C },
-	{  448000000,  0x8E },
-	{  449000000,  0x8F },
-	{  450000000,  0x90 },
-	{  452000000,  0x91 },
-	{  453000000,  0x93 },
-	{  454000000,  0x94 },
-	{  456000000,  0x96 },
-	{  457800000,  0x98 },
-	{  461000000,  0x11 },
-	{  468000000,  0x12 },
-	{  472000000,  0x13 },
-	{  473000000,  0x14 },
-	{  474000000,  0x15 },
-	{  481000000,  0x16 },
-	{  486000000,  0x17 },
-	{  491000000,  0x18 },
-	{  498000000,  0x19 },
-	{  499000000,  0x1A },
-	{  501000000,  0x1B },
-	{  506000000,  0x1C },
-	{  511000000,  0x1D },
-	{  516000000,  0x1E },
-	{  520000000,  0x1F },
-	{  521000000,  0x20 },
-	{  525000000,  0x21 },
-	{  529000000,  0x22 },
-	{  533000000,  0x23 },
-	{  539000000,  0x24 },
-	{  541000000,  0x25 },
-	{  547000000,  0x26 },
-	{  549000000,  0x27 },
-	{  551000000,  0x28 },
-	{  556000000,  0x29 },
-	{  561000000,  0x2A },
-	{  563000000,  0x2B },
-	{  565000000,  0x2C },
-	{  569000000,  0x2D },
-	{  571000000,  0x2E },
-	{  577000000,  0x2F },
-	{  580000000,  0x30 },
-	{  582000000,  0x31 },
-	{  584000000,  0x32 },
-	{  588000000,  0x33 },
-	{  591000000,  0x34 },
-	{  596000000,  0x35 },
-	{  598000000,  0x36 },
-	{  603000000,  0x37 },
-	{  604000000,  0x38 },
-	{  606000000,  0x39 },
-	{  612000000,  0x3A },
-	{  615000000,  0x3B },
-	{  617000000,  0x3C },
-	{  621000000,  0x3D },
-	{  622000000,  0x3E },
-	{  625000000,  0x3F },
-	{  632000000,  0x40 },
-	{  633000000,  0x41 },
-	{  634000000,  0x42 },
-	{  642000000,  0x43 },
-	{  643000000,  0x44 },
-	{  647000000,  0x45 },
-	{  650000000,  0x46 },
-	{  652000000,  0x47 },
-	{  657000000,  0x48 },
-	{  661000000,  0x49 },
-	{  662000000,  0x4A },
-	{  665000000,  0x4B },
-	{  667000000,  0x4C },
-	{  670000000,  0x4D },
-	{  673000000,  0x4E },
-	{  676000000,  0x4F },
-	{  677000000,  0x50 },
-	{  681000000,  0x51 },
-	{  683000000,  0x52 },
-	{  686000000,  0x53 },
-	{  688000000,  0x54 },
-	{  689000000,  0x55 },
-	{  691000000,  0x56 },
-	{  695000000,  0x57 },
-	{  698000000,  0x58 },
-	{  703000000,  0x59 },
-	{  704000000,  0x5A },
-	{  705000000,  0x5B },
-	{  707000000,  0x5C },
-	{  710000000,  0x5D },
-	{  712000000,  0x5E },
-	{  717000000,  0x5F },
-	{  718000000,  0x60 },
-	{  721000000,  0x61 },
-	{  722000000,  0x62 },
-	{  723000000,  0x63 },
-	{  725000000,  0x64 },
-	{  727000000,  0x65 },
-	{  730000000,  0x66 },
-	{  732000000,  0x67 },
-	{  735000000,  0x68 },
-	{  740000000,  0x69 },
-	{  741000000,  0x6A },
-	{  742000000,  0x6B },
-	{  743000000,  0x6C },
-	{  745000000,  0x6D },
-	{  747000000,  0x6E },
-	{  748000000,  0x6F },
-	{  750000000,  0x70 },
-	{  752000000,  0x71 },
-	{  754000000,  0x72 },
-	{  757000000,  0x73 },
-	{  758000000,  0x74 },
-	{  760000000,  0x75 },
-	{  763000000,  0x76 },
-	{  764000000,  0x77 },
-	{  766000000,  0x78 },
-	{  767000000,  0x79 },
-	{  768000000,  0x7A },
-	{  773000000,  0x7B },
-	{  774000000,  0x7C },
-	{  776000000,  0x7D },
-	{  777000000,  0x7E },
-	{  778000000,  0x7F },
-	{  779000000,  0x80 },
-	{  781000000,  0x81 },
-	{  783000000,  0x82 },
-	{  784000000,  0x83 },
-	{  785000000,  0x84 },
-	{  786000000,  0x85 },
-	{  793000000,  0x86 },
-	{  794000000,  0x87 },
-	{  795000000,  0x88 },
-	{  797000000,  0x89 },
-	{  799000000,  0x8A },
-	{  801000000,  0x8B },
-	{  802000000,  0x8C },
-	{  803000000,  0x8D },
-	{  804000000,  0x8E },
-	{  810000000,  0x90 },
-	{  811000000,  0x91 },
-	{  812000000,  0x92 },
-	{  814000000,  0x93 },
-	{  816000000,  0x94 },
-	{  817000000,  0x96 },
-	{  818000000,  0x97 },
-	{  820000000,  0x98 },
-	{  821000000,  0x99 },
-	{  822000000,  0x9A },
-	{  828000000,  0x9B },
-	{  829000000,  0x9D },
-	{  830000000,  0x9F },
-	{  831000000,  0xA0 },
-	{  833000000,  0xA1 },
-	{  835000000,  0xA2 },
-	{  836000000,  0xA3 },
-	{  837000000,  0xA4 },
-	{  838000000,  0xA6 },
-	{  840000000,  0xA8 },
-	{  842000000,  0xA9 },
-	{  845000000,  0xAA },
-	{  846000000,  0xAB },
-	{  847000000,  0xAD },
-	{  848000000,  0xAE },
-	{  852000000,  0xAF },
-	{  853000000,  0xB0 },
-	{  858000000,  0xB1 },
-	{  860000000,  0xB2 },
-	{  861000000,  0xB3 },
-	{  862000000,  0xB4 },
-	{  863000000,  0xB6 },
-	{  864000000,  0xB8 },
-	{  865000000,  0xB9 },
-	{          0,  0x00 },    /* Table End */
-};
-
-
-static struct SMap2  m_KM_Map[] = {
-	{   47900000,  3, 2 },
-	{   61100000,  3, 1 },
-	{  350000000,  3, 0 },
-	{  720000000,  2, 1 },
-	{  865000000,  3, 3 },
-	{          0,  0x00 },    /* Table End */
-};
-
-static struct SMap2 m_Main_PLL_Map[] = {
-	{  33125000, 0x57, 0xF0 },
-	{  35500000, 0x56, 0xE0 },
-	{  38188000, 0x55, 0xD0 },
-	{  41375000, 0x54, 0xC0 },
-	{  45125000, 0x53, 0xB0 },
-	{  49688000, 0x52, 0xA0 },
-	{  55188000, 0x51, 0x90 },
-	{  62125000, 0x50, 0x80 },
-	{  66250000, 0x47, 0x78 },
-	{  71000000, 0x46, 0x70 },
-	{  76375000, 0x45, 0x68 },
-	{  82750000, 0x44, 0x60 },
-	{  90250000, 0x43, 0x58 },
-	{  99375000, 0x42, 0x50 },
-	{ 110375000, 0x41, 0x48 },
-	{ 124250000, 0x40, 0x40 },
-	{ 132500000, 0x37, 0x3C },
-	{ 142000000, 0x36, 0x38 },
-	{ 152750000, 0x35, 0x34 },
-	{ 165500000, 0x34, 0x30 },
-	{ 180500000, 0x33, 0x2C },
-	{ 198750000, 0x32, 0x28 },
-	{ 220750000, 0x31, 0x24 },
-	{ 248500000, 0x30, 0x20 },
-	{ 265000000, 0x27, 0x1E },
-	{ 284000000, 0x26, 0x1C },
-	{ 305500000, 0x25, 0x1A },
-	{ 331000000, 0x24, 0x18 },
-	{ 361000000, 0x23, 0x16 },
-	{ 397500000, 0x22, 0x14 },
-	{ 441500000, 0x21, 0x12 },
-	{ 497000000, 0x20, 0x10 },
-	{ 530000000, 0x17, 0x0F },
-	{ 568000000, 0x16, 0x0E },
-	{ 611000000, 0x15, 0x0D },
-	{ 662000000, 0x14, 0x0C },
-	{ 722000000, 0x13, 0x0B },
-	{ 795000000, 0x12, 0x0A },
-	{ 883000000, 0x11, 0x09 },
-	{ 994000000, 0x10, 0x08 },
-	{         0, 0x00, 0x00 },    /* Table End */
-};
-
-static struct SMap2 m_Cal_PLL_Map[] = {
-	{  33813000, 0xDD, 0xD0 },
-	{  36625000, 0xDC, 0xC0 },
-	{  39938000, 0xDB, 0xB0 },
-	{  43938000, 0xDA, 0xA0 },
-	{  48813000, 0xD9, 0x90 },
-	{  54938000, 0xD8, 0x80 },
-	{  62813000, 0xD3, 0x70 },
-	{  67625000, 0xCD, 0x68 },
-	{  73250000, 0xCC, 0x60 },
-	{  79875000, 0xCB, 0x58 },
-	{  87875000, 0xCA, 0x50 },
-	{  97625000, 0xC9, 0x48 },
-	{ 109875000, 0xC8, 0x40 },
-	{ 125625000, 0xC3, 0x38 },
-	{ 135250000, 0xBD, 0x34 },
-	{ 146500000, 0xBC, 0x30 },
-	{ 159750000, 0xBB, 0x2C },
-	{ 175750000, 0xBA, 0x28 },
-	{ 195250000, 0xB9, 0x24 },
-	{ 219750000, 0xB8, 0x20 },
-	{ 251250000, 0xB3, 0x1C },
-	{ 270500000, 0xAD, 0x1A },
-	{ 293000000, 0xAC, 0x18 },
-	{ 319500000, 0xAB, 0x16 },
-	{ 351500000, 0xAA, 0x14 },
-	{ 390500000, 0xA9, 0x12 },
-	{ 439500000, 0xA8, 0x10 },
-	{ 502500000, 0xA3, 0x0E },
-	{ 541000000, 0x9D, 0x0D },
-	{ 586000000, 0x9C, 0x0C },
-	{ 639000000, 0x9B, 0x0B },
-	{ 703000000, 0x9A, 0x0A },
-	{ 781000000, 0x99, 0x09 },
-	{ 879000000, 0x98, 0x08 },
-	{         0, 0x00, 0x00 },    /* Table End */
-};
-
-static struct SMap  m_GainTaper_Map[] = {
-	{  45400000, 0x1F },
-	{  45800000, 0x1E },
-	{  46200000, 0x1D },
-	{  46700000, 0x1C },
-	{  47100000, 0x1B },
-	{  47500000, 0x1A },
-	{  47900000, 0x19 },
-	{  49600000, 0x17 },
-	{  51200000, 0x16 },
-	{  52900000, 0x15 },
-	{  54500000, 0x14 },
-	{  56200000, 0x13 },
-	{  57800000, 0x12 },
-	{  59500000, 0x11 },
-	{  61100000, 0x10 },
-	{  67600000, 0x0D },
-	{  74200000, 0x0C },
-	{  80700000, 0x0B },
-	{  87200000, 0x0A },
-	{  93800000, 0x09 },
-	{ 100300000, 0x08 },
-	{ 106900000, 0x07 },
-	{ 113400000, 0x06 },
-	{ 119900000, 0x05 },
-	{ 126500000, 0x04 },
-	{ 133000000, 0x03 },
-	{ 139500000, 0x02 },
-	{ 146100000, 0x01 },
-	{ 152600000, 0x00 },
-	{ 154300000, 0x1F },
-	{ 156100000, 0x1E },
-	{ 157800000, 0x1D },
-	{ 159500000, 0x1C },
-	{ 161200000, 0x1B },
-	{ 163000000, 0x1A },
-	{ 164700000, 0x19 },
-	{ 170200000, 0x17 },
-	{ 175800000, 0x16 },
-	{ 181300000, 0x15 },
-	{ 186900000, 0x14 },
-	{ 192400000, 0x13 },
-	{ 198000000, 0x12 },
-	{ 203500000, 0x11 },
-	{ 216200000, 0x14 },
-	{ 228900000, 0x13 },
-	{ 241600000, 0x12 },
-	{ 254400000, 0x11 },
-	{ 267100000, 0x10 },
-	{ 279800000, 0x0F },
-	{ 292500000, 0x0E },
-	{ 305200000, 0x0D },
-	{ 317900000, 0x0C },
-	{ 330700000, 0x0B },
-	{ 343400000, 0x0A },
-	{ 356100000, 0x09 },
-	{ 368800000, 0x08 },
-	{ 381500000, 0x07 },
-	{ 394200000, 0x06 },
-	{ 406900000, 0x05 },
-	{ 419700000, 0x04 },
-	{ 432400000, 0x03 },
-	{ 445100000, 0x02 },
-	{ 457800000, 0x01 },
-	{ 476300000, 0x19 },
-	{ 494800000, 0x18 },
-	{ 513300000, 0x17 },
-	{ 531800000, 0x16 },
-	{ 550300000, 0x15 },
-	{ 568900000, 0x14 },
-	{ 587400000, 0x13 },
-	{ 605900000, 0x12 },
-	{ 624400000, 0x11 },
-	{ 642900000, 0x10 },
-	{ 661400000, 0x0F },
-	{ 679900000, 0x0E },
-	{ 698400000, 0x0D },
-	{ 716900000, 0x0C },
-	{ 735400000, 0x0B },
-	{ 753900000, 0x0A },
-	{ 772500000, 0x09 },
-	{ 791000000, 0x08 },
-	{ 809500000, 0x07 },
-	{ 828000000, 0x06 },
-	{ 846500000, 0x05 },
-	{ 865000000, 0x04 },
-	{         0, 0x00 },    /* Table End */
-};
-
-static struct SMap m_RF_Cal_DC_Over_DT_Map[] = {
-	{  47900000, 0x00 },
-	{  55000000, 0x00 },
-	{  61100000, 0x0A },
-	{  64000000, 0x0A },
-	{  82000000, 0x14 },
-	{  84000000, 0x19 },
-	{ 119000000, 0x1C },
-	{ 124000000, 0x20 },
-	{ 129000000, 0x2A },
-	{ 134000000, 0x32 },
-	{ 139000000, 0x39 },
-	{ 144000000, 0x3E },
-	{ 149000000, 0x3F },
-	{ 152600000, 0x40 },
-	{ 154000000, 0x40 },
-	{ 164700000, 0x41 },
-	{ 203500000, 0x32 },
-	{ 353000000, 0x19 },
-	{ 356000000, 0x1A },
-	{ 359000000, 0x1B },
-	{ 363000000, 0x1C },
-	{ 366000000, 0x1D },
-	{ 369000000, 0x1E },
-	{ 373000000, 0x1F },
-	{ 376000000, 0x20 },
-	{ 379000000, 0x21 },
-	{ 383000000, 0x22 },
-	{ 386000000, 0x23 },
-	{ 389000000, 0x24 },
-	{ 393000000, 0x25 },
-	{ 396000000, 0x26 },
-	{ 399000000, 0x27 },
-	{ 402000000, 0x28 },
-	{ 404000000, 0x29 },
-	{ 407000000, 0x2A },
-	{ 409000000, 0x2B },
-	{ 412000000, 0x2C },
-	{ 414000000, 0x2D },
-	{ 417000000, 0x2E },
-	{ 419000000, 0x2F },
-	{ 422000000, 0x30 },
-	{ 424000000, 0x31 },
-	{ 427000000, 0x32 },
-	{ 429000000, 0x33 },
-	{ 432000000, 0x34 },
-	{ 434000000, 0x35 },
-	{ 437000000, 0x36 },
-	{ 439000000, 0x37 },
-	{ 442000000, 0x38 },
-	{ 444000000, 0x39 },
-	{ 447000000, 0x3A },
-	{ 449000000, 0x3B },
-	{ 457800000, 0x3C },
-	{ 465000000, 0x0F },
-	{ 477000000, 0x12 },
-	{ 483000000, 0x14 },
-	{ 502000000, 0x19 },
-	{ 508000000, 0x1B },
-	{ 519000000, 0x1C },
-	{ 522000000, 0x1D },
-	{ 524000000, 0x1E },
-	{ 534000000, 0x1F },
-	{ 549000000, 0x20 },
-	{ 554000000, 0x22 },
-	{ 584000000, 0x24 },
-	{ 589000000, 0x26 },
-	{ 658000000, 0x27 },
-	{ 664000000, 0x2C },
-	{ 669000000, 0x2D },
-	{ 699000000, 0x2E },
-	{ 704000000, 0x30 },
-	{ 709000000, 0x31 },
-	{ 714000000, 0x32 },
-	{ 724000000, 0x33 },
-	{ 729000000, 0x36 },
-	{ 739000000, 0x38 },
-	{ 744000000, 0x39 },
-	{ 749000000, 0x3B },
-	{ 754000000, 0x3C },
-	{ 759000000, 0x3D },
-	{ 764000000, 0x3E },
-	{ 769000000, 0x3F },
-	{ 774000000, 0x40 },
-	{ 779000000, 0x41 },
-	{ 784000000, 0x43 },
-	{ 789000000, 0x46 },
-	{ 794000000, 0x48 },
-	{ 799000000, 0x4B },
-	{ 804000000, 0x4F },
-	{ 809000000, 0x54 },
-	{ 814000000, 0x59 },
-	{ 819000000, 0x5D },
-	{ 824000000, 0x61 },
-	{ 829000000, 0x68 },
-	{ 834000000, 0x6E },
-	{ 839000000, 0x75 },
-	{ 844000000, 0x7E },
-	{ 849000000, 0x82 },
-	{ 854000000, 0x84 },
-	{ 859000000, 0x8F },
-	{ 865000000, 0x9A },
-	{         0, 0x00 },    /* Table End */
-};
-
-
-static struct SMap  m_IR_Meas_Map[] = {
-	{ 200000000, 0x05 },
-	{ 400000000, 0x06 },
-	{ 865000000, 0x07 },
-	{         0, 0x00 },    /* Table End */
-};
-
-static struct SMap2 m_CID_Target_Map[] = {
-	{  46000000, 0x04, 18 },
-	{  52200000, 0x0A, 15 },
-	{  70100000, 0x01, 40 },
-	{ 136800000, 0x18, 40 },
-	{ 156700000, 0x18, 40 },
-	{ 186250000, 0x0A, 40 },
-	{ 230000000, 0x0A, 40 },
-	{ 345000000, 0x18, 40 },
-	{ 426000000, 0x0E, 40 },
-	{ 489500000, 0x1E, 40 },
-	{ 697500000, 0x32, 40 },
-	{ 842000000, 0x3A, 40 },
-	{         0, 0x00,  0 },    /* Table End */
-};
-
-static struct SRFBandMap  m_RF_Band_Map[7] = {
-	{   47900000,   46000000,           0,          0},
-	{   61100000,   52200000,           0,          0},
-	{  152600000,   70100000,   136800000,          0},
-	{  164700000,  156700000,           0,          0},
-	{  203500000,  186250000,           0,          0},
-	{  457800000,  230000000,   345000000,  426000000},
-	{  865000000,  489500000,   697500000,  842000000},
-};
-
-u8 m_Thermometer_Map_1[16] = {
-	60, 62, 66, 64,
-	74, 72, 68, 70,
-	90, 88, 84, 86,
-	76, 78, 82, 80,
-};
-
-u8 m_Thermometer_Map_2[16] = {
-	92, 94, 98, 96,
-	106, 104, 100, 102,
-	122, 120, 116, 118,
-	108, 110, 114, 112,
-};
diff --git a/drivers/media/dvb/frontends/tda665x.c b/drivers/media/dvb/frontends/tda665x.c
deleted file mode 100644
index 2c1c759..0000000
--- a/drivers/media/dvb/frontends/tda665x.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
-	TDA665x tuner driver
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "tda665x.h"
-
-struct tda665x_state {
-	struct dvb_frontend		*fe;
-	struct i2c_adapter		*i2c;
-	const struct tda665x_config	*config;
-
-	u32 frequency;
-	u32 bandwidth;
-};
-
-static int tda665x_read(struct tda665x_state *state, u8 *buf)
-{
-	const struct tda665x_config *config = state->config;
-	int err = 0;
-	struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD, .buf = buf, .len = 2 };
-
-	err = i2c_transfer(state->i2c, &msg, 1);
-	if (err != 1)
-		goto exit;
-
-	return err;
-exit:
-	printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
-	return err;
-}
-
-static int tda665x_write(struct tda665x_state *state, u8 *buf, u8 length)
-{
-	const struct tda665x_config *config = state->config;
-	int err = 0;
-	struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = length };
-
-	err = i2c_transfer(state->i2c, &msg, 1);
-	if (err != 1)
-		goto exit;
-
-	return err;
-exit:
-	printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
-	return err;
-}
-
-static int tda665x_get_state(struct dvb_frontend *fe,
-			     enum tuner_param param,
-			     struct tuner_state *tstate)
-{
-	struct tda665x_state *state = fe->tuner_priv;
-	int err = 0;
-
-	switch (param) {
-	case DVBFE_TUNER_FREQUENCY:
-		tstate->frequency = state->frequency;
-		break;
-	case DVBFE_TUNER_BANDWIDTH:
-		break;
-	default:
-		printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param);
-		err = -EINVAL;
-		break;
-	}
-
-	return err;
-}
-
-static int tda665x_get_status(struct dvb_frontend *fe, u32 *status)
-{
-	struct tda665x_state *state = fe->tuner_priv;
-	u8 result = 0;
-	int err = 0;
-
-	*status = 0;
-
-	err = tda665x_read(state, &result);
-	if (err < 0)
-		goto exit;
-
-	if ((result >> 6) & 0x01) {
-		printk(KERN_DEBUG "%s: Tuner Phase Locked\n", __func__);
-		*status = 1;
-	}
-
-	return err;
-exit:
-	printk(KERN_ERR "%s: I/O Error\n", __func__);
-	return err;
-}
-
-static int tda665x_set_state(struct dvb_frontend *fe,
-			     enum tuner_param param,
-			     struct tuner_state *tstate)
-{
-	struct tda665x_state *state = fe->tuner_priv;
-	const struct tda665x_config *config = state->config;
-	u32 frequency, status = 0;
-	u8 buf[4];
-	int err = 0;
-
-	if (param & DVBFE_TUNER_FREQUENCY) {
-
-		frequency = tstate->frequency;
-		if ((frequency < config->frequency_max) || (frequency > config->frequency_min)) {
-			printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n", __func__, frequency);
-			return -EINVAL;
-		}
-
-		frequency += config->frequency_offst;
-		frequency *= config->ref_multiplier;
-		frequency += config->ref_divider >> 1;
-		frequency /= config->ref_divider;
-
-		buf[0] = (u8) ((frequency & 0x7f00) >> 8);
-		buf[1] = (u8) (frequency & 0x00ff) >> 0;
-		buf[2] = 0x80 | 0x40 | 0x02;
-		buf[3] = 0x00;
-
-		/* restore frequency */
-		frequency = tstate->frequency;
-
-		if (frequency < 153000000) {
-			/* VHF-L */
-			buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */
-			if (frequency < 68000000)
-				buf[3] |= 0x40; /* 83uA */
-			if (frequency < 1040000000)
-				buf[3] |= 0x60; /* 122uA */
-			if (frequency < 1250000000)
-				buf[3] |= 0x80; /* 163uA */
-			else
-				buf[3] |= 0xa0; /* 254uA */
-		} else if (frequency < 438000000) {
-			/* VHF-H */
-			buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */
-			if (frequency < 230000000)
-				buf[3] |= 0x40;
-			if (frequency < 300000000)
-				buf[3] |= 0x60;
-			else
-				buf[3] |= 0x80;
-		} else {
-			/* UHF */
-			buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */
-			if (frequency < 470000000)
-				buf[3] |= 0x60;
-			if (frequency < 526000000)
-				buf[3] |= 0x80;
-			else
-				buf[3] |= 0xa0;
-		}
-
-		/* Set params */
-		err = tda665x_write(state, buf, 5);
-		if (err < 0)
-			goto exit;
-
-		/* sleep for some time */
-		printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__);
-		msleep(20);
-		/* check status */
-		err = tda665x_get_status(fe, &status);
-		if (err < 0)
-			goto exit;
-
-		if (status == 1) {
-			printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n", __func__, status);
-			state->frequency = frequency; /* cache successful state */
-		} else {
-			printk(KERN_ERR "%s: No Phase lock: status=%d\n", __func__, status);
-		}
-	} else {
-		printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param);
-		return -EINVAL;
-	}
-
-	return 0;
-exit:
-	printk(KERN_ERR "%s: I/O Error\n", __func__);
-	return err;
-}
-
-static int tda665x_release(struct dvb_frontend *fe)
-{
-	struct tda665x_state *state = fe->tuner_priv;
-
-	fe->tuner_priv = NULL;
-	kfree(state);
-	return 0;
-}
-
-static struct dvb_tuner_ops tda665x_ops = {
-
-	.set_state	= tda665x_set_state,
-	.get_state	= tda665x_get_state,
-	.get_status	= tda665x_get_status,
-	.release	= tda665x_release
-};
-
-struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
-				    const struct tda665x_config *config,
-				    struct i2c_adapter *i2c)
-{
-	struct tda665x_state *state = NULL;
-	struct dvb_tuner_info *info;
-
-	state = kzalloc(sizeof(struct tda665x_state), GFP_KERNEL);
-	if (state == NULL)
-		goto exit;
-
-	state->config		= config;
-	state->i2c		= i2c;
-	state->fe		= fe;
-	fe->tuner_priv		= state;
-	fe->ops.tuner_ops	= tda665x_ops;
-	info			 = &fe->ops.tuner_ops.info;
-
-	memcpy(info->name, config->name, sizeof(config->name));
-	info->frequency_min	= config->frequency_min;
-	info->frequency_max	= config->frequency_max;
-	info->frequency_step	= config->frequency_offst;
-
-	printk(KERN_DEBUG "%s: Attaching TDA665x (%s) tuner\n", __func__, info->name);
-
-	return fe;
-
-exit:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(tda665x_attach);
-
-MODULE_DESCRIPTION("TDA665x driver");
-MODULE_AUTHOR("Manu Abraham");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda665x.h b/drivers/media/dvb/frontends/tda665x.h
deleted file mode 100644
index ec7927a..0000000
--- a/drivers/media/dvb/frontends/tda665x.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
-	TDA665x tuner driver
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TDA665x_H
-#define __TDA665x_H
-
-struct tda665x_config {
-	char name[128];
-
-	u8	addr;
-	u32	frequency_min;
-	u32	frequency_max;
-	u32	frequency_offst;
-	u32	ref_multiplier;
-	u32	ref_divider;
-};
-
-#if defined(CONFIG_DVB_TDA665x) || (defined(CONFIG_DVB_TDA665x_MODULE) && defined(MODULE))
-
-extern struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
-					   const struct tda665x_config *config,
-					   struct i2c_adapter *i2c);
-
-#else
-
-static inline struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
-						  const struct tda665x_config *config,
-						  struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-#endif /* CONFIG_DVB_TDA665x */
-
-#endif /* __TDA665x_H */
diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c
deleted file mode 100644
index 15912c9..0000000
--- a/drivers/media/dvb/frontends/tda8083.c
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
-    Driver for Philips TDA8083 based QPSK Demodulator
-
-    Copyright (C) 2001 Convergence Integrated Media GmbH
-
-    written by Ralph Metzler <ralph@convergence.de>
-
-    adoption to the new DVB frontend API and diagnostic ioctl's
-    by Holger Waechtler <holger@convergence.de>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
-#include "dvb_frontend.h"
-#include "tda8083.h"
-
-
-struct tda8083_state {
-	struct i2c_adapter* i2c;
-	/* configuration settings */
-	const struct tda8083_config* config;
-	struct dvb_frontend frontend;
-};
-
-static int debug;
-#define dprintk(args...) \
-	do { \
-		if (debug) printk(KERN_DEBUG "tda8083: " args); \
-	} while (0)
-
-
-static u8 tda8083_init_tab [] = {
-	0x04, 0x00, 0x4a, 0x79, 0x04, 0x00, 0xff, 0xea,
-	0x48, 0x42, 0x79, 0x60, 0x70, 0x52, 0x9a, 0x10,
-	0x0e, 0x10, 0xf2, 0xa7, 0x93, 0x0b, 0x05, 0xc8,
-	0x9d, 0x00, 0x42, 0x80, 0x00, 0x60, 0x40, 0x00,
-	0x00, 0x75, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00
-};
-
-
-static int tda8083_writereg (struct tda8083_state* state, u8 reg, u8 data)
-{
-	int ret;
-	u8 buf [] = { reg, data };
-	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-
-	if (ret != 1)
-		dprintk ("%s: writereg error (reg %02x, ret == %i)\n",
-			__func__, reg, ret);
-
-	return (ret != 1) ? -1 : 0;
-}
-
-static int tda8083_readregs (struct tda8083_state* state, u8 reg1, u8 *b, u8 len)
-{
-	int ret;
-	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = &reg1, .len = 1 },
-			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } };
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2)
-		dprintk ("%s: readreg error (reg %02x, ret == %i)\n",
-			__func__, reg1, ret);
-
-	return ret == 2 ? 0 : -1;
-}
-
-static inline u8 tda8083_readreg (struct tda8083_state* state, u8 reg)
-{
-	u8 val;
-
-	tda8083_readregs (state, reg, &val, 1);
-
-	return val;
-}
-
-static int tda8083_set_inversion (struct tda8083_state* state, fe_spectral_inversion_t inversion)
-{
-	/*  XXX FIXME: implement other modes than FEC_AUTO */
-	if (inversion == INVERSION_AUTO)
-		return 0;
-
-	return -EINVAL;
-}
-
-static int tda8083_set_fec (struct tda8083_state* state, fe_code_rate_t fec)
-{
-	if (fec == FEC_AUTO)
-		return tda8083_writereg (state, 0x07, 0xff);
-
-	if (fec >= FEC_1_2 && fec <= FEC_8_9)
-		return tda8083_writereg (state, 0x07, 1 << (FEC_8_9 - fec));
-
-	return -EINVAL;
-}
-
-static fe_code_rate_t tda8083_get_fec (struct tda8083_state* state)
-{
-	u8 index;
-	static fe_code_rate_t fec_tab [] = { FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4,
-				       FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8 };
-
-	index = tda8083_readreg(state, 0x0e) & 0x07;
-
-	return fec_tab [index];
-}
-
-static int tda8083_set_symbolrate (struct tda8083_state* state, u32 srate)
-{
-	u32 ratio;
-	u32 tmp;
-	u8 filter;
-
-	if (srate > 32000000)
-		srate = 32000000;
-	if (srate < 500000)
-		srate = 500000;
-
-	filter = 0;
-	if (srate < 24000000)
-		filter = 2;
-	if (srate < 16000000)
-		filter = 3;
-
-	tmp = 31250 << 16;
-	ratio = tmp / srate;
-
-	tmp = (tmp % srate) << 8;
-	ratio = (ratio << 8) + tmp / srate;
-
-	tmp = (tmp % srate) << 8;
-	ratio = (ratio << 8) + tmp / srate;
-
-	dprintk("tda8083: ratio == %08x\n", (unsigned int) ratio);
-
-	tda8083_writereg (state, 0x05, filter);
-	tda8083_writereg (state, 0x02, (ratio >> 16) & 0xff);
-	tda8083_writereg (state, 0x03, (ratio >>  8) & 0xff);
-	tda8083_writereg (state, 0x04, (ratio      ) & 0xff);
-
-	tda8083_writereg (state, 0x00, 0x3c);
-	tda8083_writereg (state, 0x00, 0x04);
-
-	return 1;
-}
-
-static void tda8083_wait_diseqc_fifo (struct tda8083_state* state, int timeout)
-{
-	unsigned long start = jiffies;
-
-	while (jiffies - start < timeout &&
-	       !(tda8083_readreg(state, 0x02) & 0x80))
-	{
-		msleep(50);
-	};
-}
-
-static int tda8083_set_tone (struct tda8083_state* state, fe_sec_tone_mode_t tone)
-{
-	tda8083_writereg (state, 0x26, 0xf1);
-
-	switch (tone) {
-	case SEC_TONE_OFF:
-		return tda8083_writereg (state, 0x29, 0x00);
-	case SEC_TONE_ON:
-		return tda8083_writereg (state, 0x29, 0x80);
-	default:
-		return -EINVAL;
-	};
-}
-
-static int tda8083_set_voltage (struct tda8083_state* state, fe_sec_voltage_t voltage)
-{
-	switch (voltage) {
-	case SEC_VOLTAGE_13:
-		return tda8083_writereg (state, 0x20, 0x00);
-	case SEC_VOLTAGE_18:
-		return tda8083_writereg (state, 0x20, 0x11);
-	default:
-		return -EINVAL;
-	};
-}
-
-static int tda8083_send_diseqc_burst (struct tda8083_state* state, fe_sec_mini_cmd_t burst)
-{
-	switch (burst) {
-	case SEC_MINI_A:
-		tda8083_writereg (state, 0x29, (5 << 2));  /* send burst A */
-		break;
-	case SEC_MINI_B:
-		tda8083_writereg (state, 0x29, (7 << 2));  /* send B */
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	tda8083_wait_diseqc_fifo (state, 100);
-
-	return 0;
-}
-
-static int tda8083_send_diseqc_msg (struct dvb_frontend* fe,
-				    struct dvb_diseqc_master_cmd *m)
-{
-	struct tda8083_state* state = fe->demodulator_priv;
-	int i;
-
-	tda8083_writereg (state, 0x29, (m->msg_len - 3) | (1 << 2)); /* enable */
-
-	for (i=0; i<m->msg_len; i++)
-		tda8083_writereg (state, 0x23 + i, m->msg[i]);
-
-	tda8083_writereg (state, 0x29, (m->msg_len - 3) | (3 << 2)); /* send!! */
-
-	tda8083_wait_diseqc_fifo (state, 100);
-
-	return 0;
-}
-
-static int tda8083_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct tda8083_state* state = fe->demodulator_priv;
-
-	u8 signal = ~tda8083_readreg (state, 0x01);
-	u8 sync = tda8083_readreg (state, 0x02);
-
-	*status = 0;
-
-	if (signal > 10)
-		*status |= FE_HAS_SIGNAL;
-
-	if (sync & 0x01)
-		*status |= FE_HAS_CARRIER;
-
-	if (sync & 0x02)
-		*status |= FE_HAS_VITERBI;
-
-	if (sync & 0x10)
-		*status |= FE_HAS_SYNC;
-
-	if (sync & 0x20) /* frontend can not lock */
-		*status |= FE_TIMEDOUT;
-
-	if ((sync & 0x1f) == 0x1f)
-		*status |= FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int tda8083_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	struct tda8083_state* state = fe->demodulator_priv;
-	int ret;
-	u8 buf[3];
-
-	if ((ret = tda8083_readregs(state, 0x0b, buf, sizeof(buf))))
-		return ret;
-
-	*ber = ((buf[0] & 0x1f) << 16) | (buf[1] << 8) | buf[2];
-
-	return 0;
-}
-
-static int tda8083_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-{
-	struct tda8083_state* state = fe->demodulator_priv;
-
-	u8 signal = ~tda8083_readreg (state, 0x01);
-	*strength = (signal << 8) | signal;
-
-	return 0;
-}
-
-static int tda8083_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct tda8083_state* state = fe->demodulator_priv;
-
-	u8 _snr = tda8083_readreg (state, 0x08);
-	*snr = (_snr << 8) | _snr;
-
-	return 0;
-}
-
-static int tda8083_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	struct tda8083_state* state = fe->demodulator_priv;
-
-	*ucblocks = tda8083_readreg(state, 0x0f);
-	if (*ucblocks == 0xff)
-		*ucblocks = 0xffffffff;
-
-	return 0;
-}
-
-static int tda8083_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct tda8083_state* state = fe->demodulator_priv;
-
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	tda8083_set_inversion (state, p->inversion);
-	tda8083_set_fec(state, p->fec_inner);
-	tda8083_set_symbolrate(state, p->symbol_rate);
-
-	tda8083_writereg (state, 0x00, 0x3c);
-	tda8083_writereg (state, 0x00, 0x04);
-
-	return 0;
-}
-
-static int tda8083_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct tda8083_state* state = fe->demodulator_priv;
-
-	/*  FIXME: get symbolrate & frequency offset...*/
-	/*p->frequency = ???;*/
-	p->inversion = (tda8083_readreg (state, 0x0e) & 0x80) ?
-			INVERSION_ON : INVERSION_OFF;
-	p->fec_inner = tda8083_get_fec(state);
-	/*p->symbol_rate = tda8083_get_symbolrate (state);*/
-
-	return 0;
-}
-
-static int tda8083_sleep(struct dvb_frontend* fe)
-{
-	struct tda8083_state* state = fe->demodulator_priv;
-
-	tda8083_writereg (state, 0x00, 0x02);
-	return 0;
-}
-
-static int tda8083_init(struct dvb_frontend* fe)
-{
-	struct tda8083_state* state = fe->demodulator_priv;
-	int i;
-
-	for (i=0; i<44; i++)
-		tda8083_writereg (state, i, tda8083_init_tab[i]);
-
-	tda8083_writereg (state, 0x00, 0x3c);
-	tda8083_writereg (state, 0x00, 0x04);
-
-	return 0;
-}
-
-static int tda8083_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
-{
-	struct tda8083_state* state = fe->demodulator_priv;
-
-	tda8083_send_diseqc_burst (state, burst);
-	tda8083_writereg (state, 0x00, 0x3c);
-	tda8083_writereg (state, 0x00, 0x04);
-
-	return 0;
-}
-
-static int tda8083_diseqc_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
-	struct tda8083_state* state = fe->demodulator_priv;
-
-	tda8083_set_tone (state, tone);
-	tda8083_writereg (state, 0x00, 0x3c);
-	tda8083_writereg (state, 0x00, 0x04);
-
-	return 0;
-}
-
-static int tda8083_diseqc_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
-	struct tda8083_state* state = fe->demodulator_priv;
-
-	tda8083_set_voltage (state, voltage);
-	tda8083_writereg (state, 0x00, 0x3c);
-	tda8083_writereg (state, 0x00, 0x04);
-
-	return 0;
-}
-
-static void tda8083_release(struct dvb_frontend* fe)
-{
-	struct tda8083_state* state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops tda8083_ops;
-
-struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
-				    struct i2c_adapter* i2c)
-{
-	struct tda8083_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct tda8083_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-
-	/* check if the demod is there */
-	if ((tda8083_readreg(state, 0x00)) != 0x05) goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &tda8083_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops tda8083_ops = {
-	.delsys = { SYS_DVBS },
-	.info = {
-		.name			= "Philips TDA8083 DVB-S",
-		.frequency_min		= 920000,     /* TDA8060 */
-		.frequency_max		= 2200000,    /* TDA8060 */
-		.frequency_stepsize	= 125,   /* kHz for QPSK frontends */
-	/*      .frequency_tolerance	= ???,*/
-		.symbol_rate_min	= 12000000,
-		.symbol_rate_max	= 30000000,
-	/*      .symbol_rate_tolerance	= ???,*/
-		.caps = FE_CAN_INVERSION_AUTO |
-			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
-			FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK | FE_CAN_MUTE_TS
-	},
-
-	.release = tda8083_release,
-
-	.init = tda8083_init,
-	.sleep = tda8083_sleep,
-
-	.set_frontend = tda8083_set_frontend,
-	.get_frontend = tda8083_get_frontend,
-
-	.read_status = tda8083_read_status,
-	.read_signal_strength = tda8083_read_signal_strength,
-	.read_snr = tda8083_read_snr,
-	.read_ber = tda8083_read_ber,
-	.read_ucblocks = tda8083_read_ucblocks,
-
-	.diseqc_send_master_cmd = tda8083_send_diseqc_msg,
-	.diseqc_send_burst = tda8083_diseqc_send_burst,
-	.set_tone = tda8083_diseqc_set_tone,
-	.set_voltage = tda8083_diseqc_set_voltage,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("Philips TDA8083 DVB-S Demodulator");
-MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(tda8083_attach);
diff --git a/drivers/media/dvb/frontends/tda8083.h b/drivers/media/dvb/frontends/tda8083.h
deleted file mode 100644
index 5a03c14..0000000
--- a/drivers/media/dvb/frontends/tda8083.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-    Driver for Grundig 29504-491, a Philips TDA8083 based QPSK Frontend
-
-    Copyright (C) 2001 Convergence Integrated Media GmbH
-
-    written by Ralph Metzler <ralph@convergence.de>
-
-    adoption to the new DVB frontend API and diagnostic ioctl's
-    by Holger Waechtler <holger@convergence.de>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef TDA8083_H
-#define TDA8083_H
-
-#include <linux/dvb/frontend.h>
-
-struct tda8083_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-};
-
-#if defined(CONFIG_DVB_TDA8083) || (defined(CONFIG_DVB_TDA8083_MODULE) && defined(MODULE))
-extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
-					   struct i2c_adapter* i2c);
-#else
-static inline struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
-					   struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_TDA8083
-
-#endif // TDA8083_H
diff --git a/drivers/media/dvb/frontends/tda8261.c b/drivers/media/dvb/frontends/tda8261.c
deleted file mode 100644
index 53c7d8f..0000000
--- a/drivers/media/dvb/frontends/tda8261.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
-	TDA8261 8PSK/QPSK tuner driver
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-#include "tda8261.h"
-
-struct tda8261_state {
-	struct dvb_frontend		*fe;
-	struct i2c_adapter		*i2c;
-	const struct tda8261_config	*config;
-
-	/* state cache */
-	u32 frequency;
-	u32 bandwidth;
-};
-
-static int tda8261_read(struct tda8261_state *state, u8 *buf)
-{
-	const struct tda8261_config *config = state->config;
-	int err = 0;
-	struct i2c_msg msg = { .addr	= config->addr, .flags = I2C_M_RD,.buf = buf,  .len = 1 };
-
-	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1)
-		printk("%s: read error, err=%d\n", __func__, err);
-
-	return err;
-}
-
-static int tda8261_write(struct tda8261_state *state, u8 *buf)
-{
-	const struct tda8261_config *config = state->config;
-	int err = 0;
-	struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = 4 };
-
-	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1)
-		printk("%s: write error, err=%d\n", __func__, err);
-
-	return err;
-}
-
-static int tda8261_get_status(struct dvb_frontend *fe, u32 *status)
-{
-	struct tda8261_state *state = fe->tuner_priv;
-	u8 result = 0;
-	int err = 0;
-
-	*status = 0;
-
-	if ((err = tda8261_read(state, &result)) < 0) {
-		printk("%s: I/O Error\n", __func__);
-		return err;
-	}
-	if ((result >> 6) & 0x01) {
-		printk("%s: Tuner Phase Locked\n", __func__);
-		*status = 1;
-	}
-
-	return err;
-}
-
-static const u32 div_tab[] = { 2000, 1000,  500,  250,  125 }; /* kHz */
-static const u8  ref_div[] = { 0x00, 0x01, 0x02, 0x05, 0x07 };
-
-static int tda8261_get_state(struct dvb_frontend *fe,
-			     enum tuner_param param,
-			     struct tuner_state *tstate)
-{
-	struct tda8261_state *state = fe->tuner_priv;
-	int err = 0;
-
-	switch (param) {
-	case DVBFE_TUNER_FREQUENCY:
-		tstate->frequency = state->frequency;
-		break;
-	case DVBFE_TUNER_BANDWIDTH:
-		tstate->bandwidth = 40000000; /* FIXME! need to calculate Bandwidth */
-		break;
-	default:
-		printk("%s: Unknown parameter (param=%d)\n", __func__, param);
-		err = -EINVAL;
-		break;
-	}
-
-	return err;
-}
-
-static int tda8261_set_state(struct dvb_frontend *fe,
-			     enum tuner_param param,
-			     struct tuner_state *tstate)
-{
-	struct tda8261_state *state = fe->tuner_priv;
-	const struct tda8261_config *config = state->config;
-	u32 frequency, N, status = 0;
-	u8 buf[4];
-	int err = 0;
-
-	if (param & DVBFE_TUNER_FREQUENCY) {
-		/**
-		 * N = Max VCO Frequency / Channel Spacing
-		 * Max VCO Frequency = VCO frequency + (channel spacing - 1)
-		 * (to account for half channel spacing on either side)
-		 */
-		frequency = tstate->frequency;
-		if ((frequency < 950000) || (frequency > 2150000)) {
-			printk("%s: Frequency beyond limits, frequency=%d\n", __func__, frequency);
-			return -EINVAL;
-		}
-		N = (frequency + (div_tab[config->step_size] - 1)) / div_tab[config->step_size];
-		printk("%s: Step size=%d, Divider=%d, PG=0x%02x (%d)\n",
-			__func__, config->step_size, div_tab[config->step_size], N, N);
-
-		buf[0] = (N >> 8) & 0xff;
-		buf[1] = N & 0xff;
-		buf[2] = (0x01 << 7) | ((ref_div[config->step_size] & 0x07) << 1);
-
-		if (frequency < 1450000)
-			buf[3] = 0x00;
-		else if (frequency < 2000000)
-			buf[3] = 0x40;
-		else if (frequency < 2150000)
-			buf[3] = 0x80;
-
-		/* Set params */
-		if ((err = tda8261_write(state, buf)) < 0) {
-			printk("%s: I/O Error\n", __func__);
-			return err;
-		}
-		/* sleep for some time */
-		printk("%s: Waiting to Phase LOCK\n", __func__);
-		msleep(20);
-		/* check status */
-		if ((err = tda8261_get_status(fe, &status)) < 0) {
-			printk("%s: I/O Error\n", __func__);
-			return err;
-		}
-		if (status == 1) {
-			printk("%s: Tuner Phase locked: status=%d\n", __func__, status);
-			state->frequency = frequency; /* cache successful state */
-		} else {
-			printk("%s: No Phase lock: status=%d\n", __func__, status);
-		}
-	} else {
-		printk("%s: Unknown parameter (param=%d)\n", __func__, param);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int tda8261_release(struct dvb_frontend *fe)
-{
-	struct tda8261_state *state = fe->tuner_priv;
-
-	fe->tuner_priv = NULL;
-	kfree(state);
-	return 0;
-}
-
-static struct dvb_tuner_ops tda8261_ops = {
-
-	.info = {
-		.name		= "TDA8261",
-//		.tuner_name	= NULL,
-		.frequency_min	=  950000,
-		.frequency_max	= 2150000,
-		.frequency_step = 0
-	},
-
-	.set_state	= tda8261_set_state,
-	.get_state	= tda8261_get_state,
-	.get_status	= tda8261_get_status,
-	.release	= tda8261_release
-};
-
-struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
-				    const struct tda8261_config *config,
-				    struct i2c_adapter *i2c)
-{
-	struct tda8261_state *state = NULL;
-
-	if ((state = kzalloc(sizeof (struct tda8261_state), GFP_KERNEL)) == NULL)
-		goto exit;
-
-	state->config		= config;
-	state->i2c		= i2c;
-	state->fe		= fe;
-	fe->tuner_priv		= state;
-	fe->ops.tuner_ops	= tda8261_ops;
-
-	fe->ops.tuner_ops.info.frequency_step = div_tab[config->step_size];
-//	fe->ops.tuner_ops.tuner_name	 = &config->buf;
-
-//	printk("%s: Attaching %s TDA8261 8PSK/QPSK tuner\n",
-//		__func__, fe->ops.tuner_ops.tuner_name);
-	printk("%s: Attaching TDA8261 8PSK/QPSK tuner\n", __func__);
-
-	return fe;
-
-exit:
-	kfree(state);
-	return NULL;
-}
-
-EXPORT_SYMBOL(tda8261_attach);
-
-MODULE_AUTHOR("Manu Abraham");
-MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda8261.h b/drivers/media/dvb/frontends/tda8261.h
deleted file mode 100644
index 006e453..0000000
--- a/drivers/media/dvb/frontends/tda8261.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-	TDA8261 8PSK/QPSK tuner driver
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TDA8261_H
-#define __TDA8261_H
-
-enum tda8261_step {
-	TDA8261_STEP_2000 = 0,	/* 2000 kHz */
-	TDA8261_STEP_1000,	/* 1000 kHz */
-	TDA8261_STEP_500,	/*  500 kHz */
-	TDA8261_STEP_250,	/*  250 kHz */
-	TDA8261_STEP_125	/*  125 kHz */
-};
-
-struct tda8261_config {
-//	u8			buf[16];
-	u8			addr;
-	enum tda8261_step	step_size;
-};
-
-#if defined(CONFIG_DVB_TDA8261) || (defined(CONFIG_DVB_TDA8261_MODULE) && defined(MODULE))
-
-extern struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
-					   const struct tda8261_config *config,
-					   struct i2c_adapter *i2c);
-
-#else
-
-static inline struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
-						  const struct tda8261_config *config,
-						  struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-#endif //CONFIG_DVB_TDA8261
-
-#endif// __TDA8261_H
diff --git a/drivers/media/dvb/frontends/tda8261_cfg.h b/drivers/media/dvb/frontends/tda8261_cfg.h
deleted file mode 100644
index 1af1ee4..0000000
--- a/drivers/media/dvb/frontends/tda8261_cfg.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
-	TDA8261 8PSK/QPSK tuner driver
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
-	struct tuner_state	t_state;
-	int err = 0;
-
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
-	if (tuner_ops->get_state) {
-		if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
-			printk("%s: Invalid parameter\n", __func__);
-			return err;
-		}
-		*frequency = t_state.frequency;
-		printk("%s: Frequency=%d\n", __func__, t_state.frequency);
-	}
-	return 0;
-}
-
-static int tda8261_set_frequency(struct dvb_frontend *fe, u32 frequency)
-{
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
-	struct tuner_state	t_state;
-	int err = 0;
-
-	t_state.frequency = frequency;
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
-	if (tuner_ops->set_state) {
-		if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
-			printk("%s: Invalid parameter\n", __func__);
-			return err;
-		}
-	}
-	printk("%s: Frequency=%d\n", __func__, t_state.frequency);
-	return 0;
-}
-
-static int tda8261_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-	struct dvb_frontend_ops	*frontend_ops = &fe->ops;
-	struct dvb_tuner_ops	*tuner_ops = &frontend_ops->tuner_ops;
-	struct tuner_state	t_state;
-	int err = 0;
-
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
-	if (tuner_ops->get_state) {
-		if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
-			printk("%s: Invalid parameter\n", __func__);
-			return err;
-		}
-		*bandwidth = t_state.bandwidth;
-	}
-	printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
-	return 0;
-}
diff --git a/drivers/media/dvb/frontends/tda826x.c b/drivers/media/dvb/frontends/tda826x.c
deleted file mode 100644
index 04bbcc2..0000000
--- a/drivers/media/dvb/frontends/tda826x.c
+++ /dev/null
@@ -1,188 +0,0 @@
-  /*
-     Driver for Philips tda8262/tda8263 DVBS Silicon tuners
-
-     (c) 2006 Andrew de Quincey
-
-     This program is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published by
-     the Free Software Foundation; either version 2 of the License, or
-     (at your option) any later version.
-
-     This program is distributed in the hope that it will be useful,
-     but WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-     GNU General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with this program; if not, write to the Free Software
-     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-  */
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/dvb/frontend.h>
-#include <asm/types.h>
-
-#include "tda826x.h"
-
-static int debug;
-#define dprintk(args...) \
-	do { \
-		if (debug) printk(KERN_DEBUG "tda826x: " args); \
-	} while (0)
-
-struct tda826x_priv {
-	/* i2c details */
-	int i2c_address;
-	struct i2c_adapter *i2c;
-	u8 has_loopthrough:1;
-	u32 frequency;
-};
-
-static int tda826x_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static int tda826x_sleep(struct dvb_frontend *fe)
-{
-	struct tda826x_priv *priv = fe->tuner_priv;
-	int ret;
-	u8 buf [] = { 0x00, 0x8d };
-	struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = buf, .len = 2 };
-
-	dprintk("%s:\n", __func__);
-
-	if (!priv->has_loopthrough)
-		buf[1] = 0xad;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
-		dprintk("%s: i2c error\n", __func__);
-	}
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	return (ret == 1) ? 0 : ret;
-}
-
-static int tda826x_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct tda826x_priv *priv = fe->tuner_priv;
-	int ret;
-	u32 div;
-	u32 ksyms;
-	u32 bandwidth;
-	u8 buf [11];
-	struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = buf, .len = 11 };
-
-	dprintk("%s:\n", __func__);
-
-	div = (p->frequency + (1000-1)) / 1000;
-
-	/* BW = ((1 + RO) * SR/2 + 5) * 1.3      [SR in MSPS, BW in MHz] */
-	/* with R0 = 0.35 and some transformations: */
-	ksyms = p->symbol_rate / 1000;
-	bandwidth = (878 * ksyms + 6500000) / 1000000 + 1;
-	if (bandwidth < 5)
-		bandwidth = 5;
-	else if (bandwidth > 36)
-		bandwidth = 36;
-
-	buf[0] = 0x00; // subaddress
-	buf[1] = 0x09; // powerdown RSSI + the magic value 1
-	if (!priv->has_loopthrough)
-		buf[1] |= 0x20; // power down loopthrough if not needed
-	buf[2] = (1<<5) | 0x0b; // 1Mhz + 0.45 VCO
-	buf[3] = div >> 7;
-	buf[4] = div << 1;
-	buf[5] = ((bandwidth - 5) << 3) | 7; /* baseband cut-off */
-	buf[6] = 0xfe; // baseband gain 9 db + no RF attenuation
-	buf[7] = 0x83; // charge pumps at high, tests off
-	buf[8] = 0x80; // recommended value 4 for AMPVCO + disable ports.
-	buf[9] = 0x1a; // normal caltime + recommended values for SELTH + SELVTL
-	buf[10] = 0xd4; // recommended value 13 for BBIAS + unknown bit set on
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
-		dprintk("%s: i2c error\n", __func__);
-	}
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	priv->frequency = div * 1000;
-
-	return (ret == 1) ? 0 : ret;
-}
-
-static int tda826x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct tda826x_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-	return 0;
-}
-
-static struct dvb_tuner_ops tda826x_tuner_ops = {
-	.info = {
-		.name = "Philips TDA826X",
-		.frequency_min = 950000,
-		.frequency_max = 2175000
-	},
-	.release = tda826x_release,
-	.sleep = tda826x_sleep,
-	.set_params = tda826x_set_params,
-	.get_frequency = tda826x_get_frequency,
-};
-
-struct dvb_frontend *tda826x_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c, int has_loopthrough)
-{
-	struct tda826x_priv *priv = NULL;
-	u8 b1 [] = { 0, 0 };
-	struct i2c_msg msg[2] = {
-		{ .addr = addr, .flags = 0,        .buf = NULL, .len = 0 },
-		{ .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 }
-	};
-	int ret;
-
-	dprintk("%s:\n", __func__);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	ret = i2c_transfer (i2c, msg, 2);
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	if (ret != 2)
-		return NULL;
-	if (!(b1[1] & 0x80))
-		return NULL;
-
-	priv = kzalloc(sizeof(struct tda826x_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	priv->i2c_address = addr;
-	priv->i2c = i2c;
-	priv->has_loopthrough = has_loopthrough;
-
-	memcpy(&fe->ops.tuner_ops, &tda826x_tuner_ops, sizeof(struct dvb_tuner_ops));
-
-	fe->tuner_priv = priv;
-
-	return fe;
-}
-EXPORT_SYMBOL(tda826x_attach);
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("DVB TDA826x driver");
-MODULE_AUTHOR("Andrew de Quincey");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda826x.h b/drivers/media/dvb/frontends/tda826x.h
deleted file mode 100644
index 89e9792..0000000
--- a/drivers/media/dvb/frontends/tda826x.h
+++ /dev/null
@@ -1,53 +0,0 @@
-  /*
-     Driver for Philips tda8262/tda8263 DVBS Silicon tuners
-
-     (c) 2006 Andrew de Quincey
-
-     This program is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published by
-     the Free Software Foundation; either version 2 of the License, or
-     (at your option) any later version.
-
-     This program is distributed in the hope that it will be useful,
-     but WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-     GNU General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with this program; if not, write to the Free Software
-     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-  */
-
-#ifndef __DVB_TDA826X_H__
-#define __DVB_TDA826X_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-/**
- * Attach a tda826x tuner to the supplied frontend structure.
- *
- * @param fe Frontend to attach to.
- * @param addr i2c address of the tuner.
- * @param i2c i2c adapter to use.
- * @param has_loopthrough Set to 1 if the card has a loopthrough RF connector.
- * @return FE pointer on success, NULL on failure.
- */
-#if defined(CONFIG_DVB_TDA826X) || (defined(CONFIG_DVB_TDA826X_MODULE) && defined(MODULE))
-extern struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe, int addr,
-					   struct i2c_adapter *i2c,
-					   int has_loopthrough);
-#else
-static inline struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe,
-						  int addr,
-						  struct i2c_adapter *i2c,
-						  int has_loopthrough)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_TDA826X
-
-#endif // __DVB_TDA826X_H__
diff --git a/drivers/media/dvb/frontends/tdhd1.h b/drivers/media/dvb/frontends/tdhd1.h
deleted file mode 100644
index 1775098..0000000
--- a/drivers/media/dvb/frontends/tdhd1.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * tdhd1.h - ALPS TDHD1-204A tuner support
- *
- * Copyright (C) 2008 Oliver Endriss <o.endriss@gmx.de>
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * The project's page is at http://www.linuxtv.org
- */
-
-#ifndef TDHD1_H
-#define TDHD1_H
-
-#include "tda1004x.h"
-
-static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name);
-
-static struct tda1004x_config alps_tdhd1_204a_config = {
-	.demod_address = 0x8,
-	.invert = 1,
-	.invert_oclk = 0,
-	.xtal_freq = TDA10046_XTAL_4M,
-	.agc_config = TDA10046_AGC_DEFAULT,
-	.if_freq = TDA10046_FREQ_3617,
-	.request_firmware = alps_tdhd1_204_request_firmware
-};
-
-static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct i2c_adapter *i2c = fe->tuner_priv;
-	u8 data[4];
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-	u32 div;
-
-	div = (p->frequency + 36166666) / 166666;
-
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0x85;
-
-	if (p->frequency >= 174000000 && p->frequency <= 230000000)
-		data[3] = 0x02;
-	else if (p->frequency >= 470000000 && p->frequency <= 823000000)
-		data[3] = 0x0C;
-	else if (p->frequency > 823000000 && p->frequency <= 862000000)
-		data[3] = 0x8C;
-	else
-		return -EINVAL;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(i2c, &msg, 1) != 1)
-		return -EIO;
-
-	return 0;
-}
-
-#endif /* TDHD1_H */
diff --git a/drivers/media/dvb/frontends/tua6100.c b/drivers/media/dvb/frontends/tua6100.c
deleted file mode 100644
index 029384d..0000000
--- a/drivers/media/dvb/frontends/tua6100.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/**
- * Driver for Infineon tua6100 pll.
- *
- * (c) 2006 Andrew de Quincey
- *
- * Based on code found in budget-av.c, which has the following:
- * Compiled from various sources by Michael Hunold <michael@mihu.de>
- *
- * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> &
- *                               Andrew de Quincey <adq_dvb@lidskialf.net>
- *
- * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
- *
- * Copyright (C) 1999-2002 Ralph  Metzler
- *                       & Marcus Metzler for convergence integrated media GmbH
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/dvb/frontend.h>
-#include <asm/types.h>
-
-#include "tua6100.h"
-
-struct tua6100_priv {
-	/* i2c details */
-	int i2c_address;
-	struct i2c_adapter *i2c;
-	u32 frequency;
-};
-
-static int tua6100_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static int tua6100_sleep(struct dvb_frontend *fe)
-{
-	struct tua6100_priv *priv = fe->tuner_priv;
-	int ret;
-	u8 reg0[] = { 0x00, 0x00 };
-	struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 };
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
-		printk("%s: i2c error\n", __func__);
-	}
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	return (ret == 1) ? 0 : ret;
-}
-
-static int tua6100_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct tua6100_priv *priv = fe->tuner_priv;
-	u32 div;
-	u32 prediv;
-	u8 reg0[] = { 0x00, 0x00 };
-	u8 reg1[] = { 0x01, 0x00, 0x00, 0x00 };
-	u8 reg2[] = { 0x02, 0x00, 0x00 };
-	struct i2c_msg msg0 = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 };
-	struct i2c_msg msg1 = { .addr = priv->i2c_address, .flags = 0, .buf = reg1, .len = 4 };
-	struct i2c_msg msg2 = { .addr = priv->i2c_address, .flags = 0, .buf = reg2, .len = 3 };
-
-#define _R 4
-#define _P 32
-#define _ri 4000000
-
-	// setup register 0
-	if (c->frequency < 2000000)
-		reg0[1] = 0x03;
-	else
-		reg0[1] = 0x07;
-
-	// setup register 1
-	if (c->frequency < 1630000)
-		reg1[1] = 0x2c;
-	else
-		reg1[1] = 0x0c;
-
-	if (_P == 64)
-		reg1[1] |= 0x40;
-	if (c->frequency >= 1525000)
-		reg1[1] |= 0x80;
-
-	// register 2
-	reg2[1] = (_R >> 8) & 0x03;
-	reg2[2] = _R;
-	if (c->frequency < 1455000)
-		reg2[1] |= 0x1c;
-	else if (c->frequency < 1630000)
-		reg2[1] |= 0x0c;
-	else
-		reg2[1] |= 0x1c;
-
-	/*
-	 * The N divisor ratio (note: c->frequency is in kHz, but we
-	 * need it in Hz)
-	 */
-	prediv = (c->frequency * _R) / (_ri / 1000);
-	div = prediv / _P;
-	reg1[1] |= (div >> 9) & 0x03;
-	reg1[2] = div >> 1;
-	reg1[3] = (div << 7);
-	priv->frequency = ((div * _P) * (_ri / 1000)) / _R;
-
-	// Finally, calculate and store the value for A
-	reg1[3] |= (prediv - (div*_P)) & 0x7f;
-
-#undef _R
-#undef _P
-#undef _ri
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(priv->i2c, &msg0, 1) != 1)
-		return -EIO;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(priv->i2c, &msg2, 1) != 1)
-		return -EIO;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(priv->i2c, &msg1, 1) != 1)
-		return -EIO;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	return 0;
-}
-
-static int tua6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct tua6100_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-	return 0;
-}
-
-static struct dvb_tuner_ops tua6100_tuner_ops = {
-	.info = {
-		.name = "Infineon TUA6100",
-		.frequency_min = 950000,
-		.frequency_max = 2150000,
-		.frequency_step = 1000,
-	},
-	.release = tua6100_release,
-	.sleep = tua6100_sleep,
-	.set_params = tua6100_set_params,
-	.get_frequency = tua6100_get_frequency,
-};
-
-struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c)
-{
-	struct tua6100_priv *priv = NULL;
-	u8 b1 [] = { 0x80 };
-	u8 b2 [] = { 0x00 };
-	struct i2c_msg msg [] = { { .addr = addr, .flags = 0, .buf = b1, .len = 1 },
-				  { .addr = addr, .flags = I2C_M_RD, .buf = b2, .len = 1 } };
-	int ret;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	ret = i2c_transfer (i2c, msg, 2);
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	if (ret != 2)
-		return NULL;
-
-	priv = kzalloc(sizeof(struct tua6100_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	priv->i2c_address = addr;
-	priv->i2c = i2c;
-
-	memcpy(&fe->ops.tuner_ops, &tua6100_tuner_ops, sizeof(struct dvb_tuner_ops));
-	fe->tuner_priv = priv;
-	return fe;
-}
-EXPORT_SYMBOL(tua6100_attach);
-
-MODULE_DESCRIPTION("DVB tua6100 driver");
-MODULE_AUTHOR("Andrew de Quincey");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tua6100.h b/drivers/media/dvb/frontends/tua6100.h
deleted file mode 100644
index f83dbd5..0000000
--- a/drivers/media/dvb/frontends/tua6100.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * Driver for Infineon tua6100 PLL.
- *
- * (c) 2006 Andrew de Quincey
- *
- * Based on code found in budget-av.c, which has the following:
- * Compiled from various sources by Michael Hunold <michael@mihu.de>
- *
- * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> &
- *                               Andrew de Quincey <adq_dvb@lidskialf.net>
- *
- * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
- *
- * Copyright (C) 1999-2002 Ralph  Metzler
- *                       & Marcus Metzler for convergence integrated media GmbH
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __DVB_TUA6100_H__
-#define __DVB_TUA6100_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-#if defined(CONFIG_DVB_TUA6100) || (defined(CONFIG_DVB_TUA6100_MODULE) && defined(MODULE))
-extern struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend* tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_TUA6100
-
-#endif
diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c
deleted file mode 100644
index bb42b56..0000000
--- a/drivers/media/dvb/frontends/ves1820.c
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
-    VES1820  - Single Chip Cable Channel Receiver driver module
-
-    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <asm/div64.h>
-
-#include "dvb_frontend.h"
-#include "ves1820.h"
-
-
-
-struct ves1820_state {
-	struct i2c_adapter* i2c;
-	/* configuration settings */
-	const struct ves1820_config* config;
-	struct dvb_frontend frontend;
-
-	/* private demodulator data */
-	u8 reg0;
-	u8 pwm;
-};
-
-
-static int verbose;
-
-static u8 ves1820_inittab[] = {
-	0x69, 0x6A, 0x93, 0x1A, 0x12, 0x46, 0x26, 0x1A,
-	0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x20,
-	0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
-	0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x40
-};
-
-static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data)
-{
-	u8 buf[] = { 0x00, reg, data };
-	struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 3 };
-	int ret;
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
-
-	if (ret != 1)
-		printk("ves1820: %s(): writereg error (reg == 0x%02x, "
-			"val == 0x%02x, ret == %i)\n", __func__, reg, data, ret);
-
-	return (ret != 1) ? -EREMOTEIO : 0;
-}
-
-static u8 ves1820_readreg(struct ves1820_state *state, u8 reg)
-{
-	u8 b0[] = { 0x00, reg };
-	u8 b1[] = { 0 };
-	struct i2c_msg msg[] = {
-		{.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 2},
-		{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
-	};
-	int ret;
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2)
-		printk("ves1820: %s(): readreg error (reg == 0x%02x, "
-		"ret == %i)\n", __func__, reg, ret);
-
-	return b1[0];
-}
-
-static int ves1820_setup_reg0(struct ves1820_state *state, u8 reg0, fe_spectral_inversion_t inversion)
-{
-	reg0 |= state->reg0 & 0x62;
-
-	if (INVERSION_ON == inversion) {
-		if (!state->config->invert) reg0 |= 0x20;
-		else reg0 &= ~0x20;
-	} else if (INVERSION_OFF == inversion) {
-		if (!state->config->invert) reg0 &= ~0x20;
-		else reg0 |= 0x20;
-	}
-
-	ves1820_writereg(state, 0x00, reg0 & 0xfe);
-	ves1820_writereg(state, 0x00, reg0 | 0x01);
-
-	state->reg0 = reg0;
-
-	return 0;
-}
-
-static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate)
-{
-	s32 BDR;
-	s32 BDRI;
-	s16 SFIL = 0;
-	u16 NDEC = 0;
-	u32 ratio;
-	u32 fin;
-	u32 tmp;
-	u64 fptmp;
-	u64 fpxin;
-
-	if (symbolrate > state->config->xin / 2)
-		symbolrate = state->config->xin / 2;
-
-	if (symbolrate < 500000)
-		symbolrate = 500000;
-
-	if (symbolrate < state->config->xin / 16)
-		NDEC = 1;
-	if (symbolrate < state->config->xin / 32)
-		NDEC = 2;
-	if (symbolrate < state->config->xin / 64)
-		NDEC = 3;
-
-	/* yeuch! */
-	fpxin = state->config->xin * 10;
-	fptmp = fpxin; do_div(fptmp, 123);
-	if (symbolrate < fptmp)
-		SFIL = 1;
-	fptmp = fpxin; do_div(fptmp, 160);
-	if (symbolrate < fptmp)
-		SFIL = 0;
-	fptmp = fpxin; do_div(fptmp, 246);
-	if (symbolrate < fptmp)
-		SFIL = 1;
-	fptmp = fpxin; do_div(fptmp, 320);
-	if (symbolrate < fptmp)
-		SFIL = 0;
-	fptmp = fpxin; do_div(fptmp, 492);
-	if (symbolrate < fptmp)
-		SFIL = 1;
-	fptmp = fpxin; do_div(fptmp, 640);
-	if (symbolrate < fptmp)
-		SFIL = 0;
-	fptmp = fpxin; do_div(fptmp, 984);
-	if (symbolrate < fptmp)
-		SFIL = 1;
-
-	fin = state->config->xin >> 4;
-	symbolrate <<= NDEC;
-	ratio = (symbolrate << 4) / fin;
-	tmp = ((symbolrate << 4) % fin) << 8;
-	ratio = (ratio << 8) + tmp / fin;
-	tmp = (tmp % fin) << 8;
-	ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, fin);
-
-	BDR = ratio;
-	BDRI = (((state->config->xin << 5) / symbolrate) + 1) / 2;
-
-	if (BDRI > 0xFF)
-		BDRI = 0xFF;
-
-	SFIL = (SFIL << 4) | ves1820_inittab[0x0E];
-
-	NDEC = (NDEC << 6) | ves1820_inittab[0x03];
-
-	ves1820_writereg(state, 0x03, NDEC);
-	ves1820_writereg(state, 0x0a, BDR & 0xff);
-	ves1820_writereg(state, 0x0b, (BDR >> 8) & 0xff);
-	ves1820_writereg(state, 0x0c, (BDR >> 16) & 0x3f);
-
-	ves1820_writereg(state, 0x0d, BDRI);
-	ves1820_writereg(state, 0x0e, SFIL);
-
-	return 0;
-}
-
-static int ves1820_init(struct dvb_frontend* fe)
-{
-	struct ves1820_state* state = fe->demodulator_priv;
-	int i;
-
-	ves1820_writereg(state, 0, 0);
-
-	for (i = 0; i < sizeof(ves1820_inittab); i++)
-		ves1820_writereg(state, i, ves1820_inittab[i]);
-	if (state->config->selagc)
-		ves1820_writereg(state, 2, ves1820_inittab[2] | 0x08);
-
-	ves1820_writereg(state, 0x34, state->pwm);
-
-	return 0;
-}
-
-static int ves1820_set_parameters(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct ves1820_state* state = fe->demodulator_priv;
-	static const u8 reg0x00[] = { 0x00, 0x04, 0x08, 0x0c, 0x10 };
-	static const u8 reg0x01[] = { 140, 140, 106, 100, 92 };
-	static const u8 reg0x05[] = { 135, 100, 70, 54, 38 };
-	static const u8 reg0x08[] = { 162, 116, 67, 52, 35 };
-	static const u8 reg0x09[] = { 145, 150, 106, 126, 107 };
-	int real_qam = p->modulation - QAM_16;
-
-	if (real_qam < 0 || real_qam > 4)
-		return -EINVAL;
-
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-
-	ves1820_set_symbolrate(state, p->symbol_rate);
-	ves1820_writereg(state, 0x34, state->pwm);
-
-	ves1820_writereg(state, 0x01, reg0x01[real_qam]);
-	ves1820_writereg(state, 0x05, reg0x05[real_qam]);
-	ves1820_writereg(state, 0x08, reg0x08[real_qam]);
-	ves1820_writereg(state, 0x09, reg0x09[real_qam]);
-
-	ves1820_setup_reg0(state, reg0x00[real_qam], p->inversion);
-	ves1820_writereg(state, 2, ves1820_inittab[2] | (state->config->selagc ? 0x08 : 0));
-	return 0;
-}
-
-static int ves1820_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct ves1820_state* state = fe->demodulator_priv;
-	int sync;
-
-	*status = 0;
-	sync = ves1820_readreg(state, 0x11);
-
-	if (sync & 1)
-		*status |= FE_HAS_SIGNAL;
-
-	if (sync & 2)
-		*status |= FE_HAS_CARRIER;
-
-	if (sync & 2)	/* XXX FIXME! */
-		*status |= FE_HAS_VITERBI;
-
-	if (sync & 4)
-		*status |= FE_HAS_SYNC;
-
-	if (sync & 8)
-		*status |= FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int ves1820_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	struct ves1820_state* state = fe->demodulator_priv;
-
-	u32 _ber = ves1820_readreg(state, 0x14) |
-			(ves1820_readreg(state, 0x15) << 8) |
-			((ves1820_readreg(state, 0x16) & 0x0f) << 16);
-	*ber = 10 * _ber;
-
-	return 0;
-}
-
-static int ves1820_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-{
-	struct ves1820_state* state = fe->demodulator_priv;
-
-	u8 gain = ves1820_readreg(state, 0x17);
-	*strength = (gain << 8) | gain;
-
-	return 0;
-}
-
-static int ves1820_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct ves1820_state* state = fe->demodulator_priv;
-
-	u8 quality = ~ves1820_readreg(state, 0x18);
-	*snr = (quality << 8) | quality;
-
-	return 0;
-}
-
-static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	struct ves1820_state* state = fe->demodulator_priv;
-
-	*ucblocks = ves1820_readreg(state, 0x13) & 0x7f;
-	if (*ucblocks == 0x7f)
-		*ucblocks = 0xffffffff;
-
-	/* reset uncorrected block counter */
-	ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf);
-	ves1820_writereg(state, 0x10, ves1820_inittab[0x10]);
-
-	return 0;
-}
-
-static int ves1820_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct ves1820_state* state = fe->demodulator_priv;
-	int sync;
-	s8 afc = 0;
-
-	sync = ves1820_readreg(state, 0x11);
-	afc = ves1820_readreg(state, 0x19);
-	if (verbose) {
-		/* AFC only valid when carrier has been recovered */
-		printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" :
-			"ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->symbol_rate * afc) >> 10);
-	}
-
-	if (!state->config->invert) {
-		p->inversion = (state->reg0 & 0x20) ? INVERSION_ON : INVERSION_OFF;
-	} else {
-		p->inversion = (!(state->reg0 & 0x20)) ? INVERSION_ON : INVERSION_OFF;
-	}
-
-	p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
-
-	p->fec_inner = FEC_NONE;
-
-	p->frequency = ((p->frequency + 31250) / 62500) * 62500;
-	if (sync & 2)
-		p->frequency -= ((s32) p->symbol_rate * afc) >> 10;
-
-	return 0;
-}
-
-static int ves1820_sleep(struct dvb_frontend* fe)
-{
-	struct ves1820_state* state = fe->demodulator_priv;
-
-	ves1820_writereg(state, 0x1b, 0x02);	/* pdown ADC */
-	ves1820_writereg(state, 0x00, 0x80);	/* standby */
-
-	return 0;
-}
-
-static int ves1820_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
-{
-
-	fesettings->min_delay_ms = 200;
-	fesettings->step_size = 0;
-	fesettings->max_drift = 0;
-	return 0;
-}
-
-static void ves1820_release(struct dvb_frontend* fe)
-{
-	struct ves1820_state* state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops ves1820_ops;
-
-struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
-				    struct i2c_adapter* i2c,
-				    u8 pwm)
-{
-	struct ves1820_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct ves1820_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->reg0 = ves1820_inittab[0];
-	state->config = config;
-	state->i2c = i2c;
-	state->pwm = pwm;
-
-	/* check if the demod is there */
-	if ((ves1820_readreg(state, 0x1a) & 0xf0) != 0x70)
-		goto error;
-
-	if (verbose)
-		printk("ves1820: pwm=0x%02x\n", state->pwm);
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.ops.info.symbol_rate_min = (state->config->xin / 2) / 64;      /* SACLK/64 == (XIN/2)/64 */
-	state->frontend.ops.info.symbol_rate_max = (state->config->xin / 2) / 4;       /* SACLK/4 */
-	state->frontend.demodulator_priv = state;
-
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops ves1820_ops = {
-	.delsys = { SYS_DVBC_ANNEX_A },
-	.info = {
-		.name = "VLSI VES1820 DVB-C",
-		.frequency_stepsize = 62500,
-		.frequency_min = 47000000,
-		.frequency_max = 862000000,
-		.caps = FE_CAN_QAM_16 |
-			FE_CAN_QAM_32 |
-			FE_CAN_QAM_64 |
-			FE_CAN_QAM_128 |
-			FE_CAN_QAM_256 |
-			FE_CAN_FEC_AUTO
-	},
-
-	.release = ves1820_release,
-
-	.init = ves1820_init,
-	.sleep = ves1820_sleep,
-
-	.set_frontend = ves1820_set_parameters,
-	.get_frontend = ves1820_get_frontend,
-	.get_tune_settings = ves1820_get_tune_settings,
-
-	.read_status = ves1820_read_status,
-	.read_ber = ves1820_read_ber,
-	.read_signal_strength = ves1820_read_signal_strength,
-	.read_snr = ves1820_read_snr,
-	.read_ucblocks = ves1820_read_ucblocks,
-};
-
-module_param(verbose, int, 0644);
-MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
-
-MODULE_DESCRIPTION("VLSI VES1820 DVB-C Demodulator driver");
-MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(ves1820_attach);
diff --git a/drivers/media/dvb/frontends/ves1820.h b/drivers/media/dvb/frontends/ves1820.h
deleted file mode 100644
index e902ed6..0000000
--- a/drivers/media/dvb/frontends/ves1820.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-    VES1820  - Single Chip Cable Channel Receiver driver module
-
-    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef VES1820_H
-#define VES1820_H
-
-#include <linux/dvb/frontend.h>
-
-#define VES1820_SELAGC_PWM 0
-#define VES1820_SELAGC_SIGNAMPERR 1
-
-struct ves1820_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* value of XIN to use */
-	u32 xin;
-
-	/* does inversion need inverted? */
-	u8 invert:1;
-
-	/* SELAGC control */
-	u8 selagc:1;
-};
-
-#if defined(CONFIG_DVB_VES1820) || (defined(CONFIG_DVB_VES1820_MODULE) && defined(MODULE))
-extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
-					   struct i2c_adapter* i2c, u8 pwm);
-#else
-static inline struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
-					   struct i2c_adapter* i2c, u8 pwm)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_VES1820
-
-#endif // VES1820_H
diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c
deleted file mode 100644
index 9c17eac..0000000
--- a/drivers/media/dvb/frontends/ves1x93.c
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
-    Driver for VES1893 and VES1993 QPSK Demodulators
-
-    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
-    Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de>
-    Copyright (C) 2002 Dennis Noermann <dennis.noermann@noernet.de>
-    Copyright (C) 2002-2003 Andreas Oberritter <obi@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-
-#include "dvb_frontend.h"
-#include "ves1x93.h"
-
-
-struct ves1x93_state {
-	struct i2c_adapter* i2c;
-	/* configuration settings */
-	const struct ves1x93_config* config;
-	struct dvb_frontend frontend;
-
-	/* previous uncorrected block counter */
-	fe_spectral_inversion_t inversion;
-	u8 *init_1x93_tab;
-	u8 *init_1x93_wtab;
-	u8 tab_size;
-	u8 demod_type;
-	u32 frequency;
-};
-
-static int debug;
-#define dprintk	if (debug) printk
-
-#define DEMOD_VES1893		0
-#define DEMOD_VES1993		1
-
-static u8 init_1893_tab [] = {
-	0x01, 0xa4, 0x35, 0x80, 0x2a, 0x0b, 0x55, 0xc4,
-	0x09, 0x69, 0x00, 0x86, 0x4c, 0x28, 0x7f, 0x00,
-	0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x80, 0x00, 0x21, 0xb0, 0x14, 0x00, 0xdc, 0x00,
-	0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x55, 0x00, 0x00, 0x7f, 0x00
-};
-
-static u8 init_1993_tab [] = {
-	0x00, 0x9c, 0x35, 0x80, 0x6a, 0x09, 0x72, 0x8c,
-	0x09, 0x6b, 0x00, 0x00, 0x4c, 0x08, 0x00, 0x00,
-	0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x80, 0x40, 0x21, 0xb0, 0x00, 0x00, 0x00, 0x10,
-	0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03,
-	0x00, 0x00, 0x0e, 0x80, 0x00
-};
-
-static u8 init_1893_wtab[] =
-{
-	1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
-	0,1,0,0,0,0,0,0, 1,0,1,1,0,0,0,1,
-	1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0,
-	1,1,1,0,1,1
-};
-
-static u8 init_1993_wtab[] =
-{
-	1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
-	0,1,0,0,0,0,0,0, 1,1,1,1,0,0,0,1,
-	1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0,
-	1,1,1,0,1,1,1,1, 1,1,1,1,1
-};
-
-static int ves1x93_writereg (struct ves1x93_state* state, u8 reg, u8 data)
-{
-	u8 buf [] = { 0x00, reg, data };
-	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 };
-	int err;
-
-	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
-		dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
-		return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static u8 ves1x93_readreg (struct ves1x93_state* state, u8 reg)
-{
-	int ret;
-	u8 b0 [] = { 0x00, reg };
-	u8 b1 [] = { 0 };
-	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
-			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-
-	ret = i2c_transfer (state->i2c, msg, 2);
-
-	if (ret != 2) return ret;
-
-	return b1[0];
-}
-
-static int ves1x93_clr_bit (struct ves1x93_state* state)
-{
-	msleep(10);
-	ves1x93_writereg (state, 0, state->init_1x93_tab[0] & 0xfe);
-	ves1x93_writereg (state, 0, state->init_1x93_tab[0]);
-	msleep(50);
-	return 0;
-}
-
-static int ves1x93_set_inversion (struct ves1x93_state* state, fe_spectral_inversion_t inversion)
-{
-	u8 val;
-
-	/*
-	 * inversion on/off are interchanged because i and q seem to
-	 * be swapped on the hardware
-	 */
-
-	switch (inversion) {
-	case INVERSION_OFF:
-		val = 0xc0;
-		break;
-	case INVERSION_ON:
-		val = 0x80;
-		break;
-	case INVERSION_AUTO:
-		val = 0x00;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return ves1x93_writereg (state, 0x0c, (state->init_1x93_tab[0x0c] & 0x3f) | val);
-}
-
-static int ves1x93_set_fec (struct ves1x93_state* state, fe_code_rate_t fec)
-{
-	if (fec == FEC_AUTO)
-		return ves1x93_writereg (state, 0x0d, 0x08);
-	else if (fec < FEC_1_2 || fec > FEC_8_9)
-		return -EINVAL;
-	else
-		return ves1x93_writereg (state, 0x0d, fec - FEC_1_2);
-}
-
-static fe_code_rate_t ves1x93_get_fec (struct ves1x93_state* state)
-{
-	return FEC_1_2 + ((ves1x93_readreg (state, 0x0d) >> 4) & 0x7);
-}
-
-static int ves1x93_set_symbolrate (struct ves1x93_state* state, u32 srate)
-{
-	u32 BDR;
-	u32 ratio;
-	u8  ADCONF, FCONF, FNR, AGCR;
-	u32 BDRI;
-	u32 tmp;
-	u32 FIN;
-
-	dprintk("%s: srate == %d\n", __func__, (unsigned int) srate);
-
-	if (srate > state->config->xin/2)
-		srate = state->config->xin/2;
-
-	if (srate < 500000)
-		srate = 500000;
-
-#define MUL (1UL<<26)
-
-	FIN = (state->config->xin + 6000) >> 4;
-
-	tmp = srate << 6;
-	ratio = tmp / FIN;
-
-	tmp = (tmp % FIN) << 8;
-	ratio = (ratio << 8) + tmp / FIN;
-
-	tmp = (tmp % FIN) << 8;
-	ratio = (ratio << 8) + tmp / FIN;
-
-	FNR = 0xff;
-
-	if (ratio < MUL/3)	     FNR = 0;
-	if (ratio < (MUL*11)/50)     FNR = 1;
-	if (ratio < MUL/6)	     FNR = 2;
-	if (ratio < MUL/9)	     FNR = 3;
-	if (ratio < MUL/12)	     FNR = 4;
-	if (ratio < (MUL*11)/200)    FNR = 5;
-	if (ratio < MUL/24)	     FNR = 6;
-	if (ratio < (MUL*27)/1000)   FNR = 7;
-	if (ratio < MUL/48)	     FNR = 8;
-	if (ratio < (MUL*137)/10000) FNR = 9;
-
-	if (FNR == 0xff) {
-		ADCONF = 0x89;
-		FCONF  = 0x80;
-		FNR	= 0;
-	} else {
-		ADCONF = 0x81;
-		FCONF  = 0x88 | (FNR >> 1) | ((FNR & 0x01) << 5);
-		/*FCONF	 = 0x80 | ((FNR & 0x01) << 5) | (((FNR > 1) & 0x03) << 3) | ((FNR >> 1) & 0x07);*/
-	}
-
-	BDR = (( (ratio << (FNR >> 1)) >> 4) + 1) >> 1;
-	BDRI = ( ((FIN << 8) / ((srate << (FNR >> 1)) >> 2)) + 1) >> 1;
-
-	dprintk("FNR= %d\n", FNR);
-	dprintk("ratio= %08x\n", (unsigned int) ratio);
-	dprintk("BDR= %08x\n", (unsigned int) BDR);
-	dprintk("BDRI= %02x\n", (unsigned int) BDRI);
-
-	if (BDRI > 0xff)
-		BDRI = 0xff;
-
-	ves1x93_writereg (state, 0x06, 0xff & BDR);
-	ves1x93_writereg (state, 0x07, 0xff & (BDR >> 8));
-	ves1x93_writereg (state, 0x08, 0x0f & (BDR >> 16));
-
-	ves1x93_writereg (state, 0x09, BDRI);
-	ves1x93_writereg (state, 0x20, ADCONF);
-	ves1x93_writereg (state, 0x21, FCONF);
-
-	AGCR = state->init_1x93_tab[0x05];
-	if (state->config->invert_pwm)
-		AGCR |= 0x20;
-
-	if (srate < 6000000)
-		AGCR |= 0x80;
-	else
-		AGCR &= ~0x80;
-
-	ves1x93_writereg (state, 0x05, AGCR);
-
-	/* ves1993 hates this, will lose lock */
-	if (state->demod_type != DEMOD_VES1993)
-		ves1x93_clr_bit (state);
-
-	return 0;
-}
-
-static int ves1x93_init (struct dvb_frontend* fe)
-{
-	struct ves1x93_state* state = fe->demodulator_priv;
-	int i;
-	int val;
-
-	dprintk("%s: init chip\n", __func__);
-
-	for (i = 0; i < state->tab_size; i++) {
-		if (state->init_1x93_wtab[i]) {
-			val = state->init_1x93_tab[i];
-
-			if (state->config->invert_pwm && (i == 0x05)) val |= 0x20; /* invert PWM */
-			ves1x93_writereg (state, i, val);
-		}
-	}
-
-	return 0;
-}
-
-static int ves1x93_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
-	struct ves1x93_state* state = fe->demodulator_priv;
-
-	switch (voltage) {
-	case SEC_VOLTAGE_13:
-		return ves1x93_writereg (state, 0x1f, 0x20);
-	case SEC_VOLTAGE_18:
-		return ves1x93_writereg (state, 0x1f, 0x30);
-	case SEC_VOLTAGE_OFF:
-		return ves1x93_writereg (state, 0x1f, 0x00);
-	default:
-		return -EINVAL;
-	}
-}
-
-static int ves1x93_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct ves1x93_state* state = fe->demodulator_priv;
-
-	u8 sync = ves1x93_readreg (state, 0x0e);
-
-	/*
-	 * The ves1893 sometimes returns sync values that make no sense,
-	 * because, e.g., the SIGNAL bit is 0, while some of the higher
-	 * bits are 1 (and how can there be a CARRIER w/o a SIGNAL?).
-	 * Tests showed that the VITERBI and SYNC bits are returned
-	 * reliably, while the SIGNAL and CARRIER bits ar sometimes wrong.
-	 * If such a case occurs, we read the value again, until we get a
-	 * valid value.
-	 */
-	int maxtry = 10; /* just for safety - let's not get stuck here */
-	while ((sync & 0x03) != 0x03 && (sync & 0x0c) && maxtry--) {
-		msleep(10);
-		sync = ves1x93_readreg (state, 0x0e);
-	}
-
-	*status = 0;
-
-	if (sync & 1)
-		*status |= FE_HAS_SIGNAL;
-
-	if (sync & 2)
-		*status |= FE_HAS_CARRIER;
-
-	if (sync & 4)
-		*status |= FE_HAS_VITERBI;
-
-	if (sync & 8)
-		*status |= FE_HAS_SYNC;
-
-	if ((sync & 0x1f) == 0x1f)
-		*status |= FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int ves1x93_read_ber(struct dvb_frontend* fe, u32* ber)
-{
-	struct ves1x93_state* state = fe->demodulator_priv;
-
-	*ber = ves1x93_readreg (state, 0x15);
-	*ber |= (ves1x93_readreg (state, 0x16) << 8);
-	*ber |= ((ves1x93_readreg (state, 0x17) & 0x0F) << 16);
-	*ber *= 10;
-
-	return 0;
-}
-
-static int ves1x93_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-{
-	struct ves1x93_state* state = fe->demodulator_priv;
-
-	u8 signal = ~ves1x93_readreg (state, 0x0b);
-	*strength = (signal << 8) | signal;
-
-	return 0;
-}
-
-static int ves1x93_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct ves1x93_state* state = fe->demodulator_priv;
-
-	u8 _snr = ~ves1x93_readreg (state, 0x1c);
-	*snr = (_snr << 8) | _snr;
-
-	return 0;
-}
-
-static int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	struct ves1x93_state* state = fe->demodulator_priv;
-
-	*ucblocks = ves1x93_readreg (state, 0x18) & 0x7f;
-
-	if (*ucblocks == 0x7f)
-		*ucblocks = 0xffffffff;   /* counter overflow... */
-
-	ves1x93_writereg (state, 0x18, 0x00);  /* reset the counter */
-	ves1x93_writereg (state, 0x18, 0x80);  /* dto. */
-
-	return 0;
-}
-
-static int ves1x93_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct ves1x93_state* state = fe->demodulator_priv;
-
-	if (fe->ops.tuner_ops.set_params) {
-		fe->ops.tuner_ops.set_params(fe);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-	ves1x93_set_inversion (state, p->inversion);
-	ves1x93_set_fec(state, p->fec_inner);
-	ves1x93_set_symbolrate(state, p->symbol_rate);
-	state->inversion = p->inversion;
-	state->frequency = p->frequency;
-
-	return 0;
-}
-
-static int ves1x93_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct ves1x93_state* state = fe->demodulator_priv;
-	int afc;
-
-	afc = ((int)((char)(ves1x93_readreg (state, 0x0a) << 1)))/2;
-	afc = (afc * (int)(p->symbol_rate/1000/8))/16;
-
-	p->frequency = state->frequency - afc;
-
-	/*
-	 * inversion indicator is only valid
-	 * if auto inversion was used
-	 */
-	if (state->inversion == INVERSION_AUTO)
-		p->inversion = (ves1x93_readreg (state, 0x0f) & 2) ?
-				INVERSION_OFF : INVERSION_ON;
-	p->fec_inner = ves1x93_get_fec(state);
-	/*  XXX FIXME: timing offset !! */
-
-	return 0;
-}
-
-static int ves1x93_sleep(struct dvb_frontend* fe)
-{
-	struct ves1x93_state* state = fe->demodulator_priv;
-
-	return ves1x93_writereg (state, 0x00, 0x08);
-}
-
-static void ves1x93_release(struct dvb_frontend* fe)
-{
-	struct ves1x93_state* state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static int ves1x93_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
-{
-	struct ves1x93_state* state = fe->demodulator_priv;
-
-	if (enable) {
-		return ves1x93_writereg(state, 0x00, 0x11);
-	} else {
-		return ves1x93_writereg(state, 0x00, 0x01);
-	}
-}
-
-static struct dvb_frontend_ops ves1x93_ops;
-
-struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
-				    struct i2c_adapter* i2c)
-{
-	struct ves1x93_state* state = NULL;
-	u8 identity;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct ves1x93_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	state->inversion = INVERSION_OFF;
-
-	/* check if the demod is there + identify it */
-	identity = ves1x93_readreg(state, 0x1e);
-	switch (identity) {
-	case 0xdc: /* VES1893A rev1 */
-		printk("ves1x93: Detected ves1893a rev1\n");
-		state->demod_type = DEMOD_VES1893;
-		state->init_1x93_tab = init_1893_tab;
-		state->init_1x93_wtab = init_1893_wtab;
-		state->tab_size = sizeof(init_1893_tab);
-		break;
-
-	case 0xdd: /* VES1893A rev2 */
-		printk("ves1x93: Detected ves1893a rev2\n");
-		state->demod_type = DEMOD_VES1893;
-		state->init_1x93_tab = init_1893_tab;
-		state->init_1x93_wtab = init_1893_wtab;
-		state->tab_size = sizeof(init_1893_tab);
-		break;
-
-	case 0xde: /* VES1993 */
-		printk("ves1x93: Detected ves1993\n");
-		state->demod_type = DEMOD_VES1993;
-		state->init_1x93_tab = init_1993_tab;
-		state->init_1x93_wtab = init_1993_wtab;
-		state->tab_size = sizeof(init_1993_tab);
-		break;
-
-	default:
-		goto error;
-	}
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops ves1x93_ops = {
-	.delsys = { SYS_DVBS },
-	.info = {
-		.name			= "VLSI VES1x93 DVB-S",
-		.frequency_min		= 950000,
-		.frequency_max		= 2150000,
-		.frequency_stepsize	= 125,		 /* kHz for QPSK frontends */
-		.frequency_tolerance	= 29500,
-		.symbol_rate_min	= 1000000,
-		.symbol_rate_max	= 45000000,
-	/*	.symbol_rate_tolerance	=	???,*/
-		.caps = FE_CAN_INVERSION_AUTO |
-			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK
-	},
-
-	.release = ves1x93_release,
-
-	.init = ves1x93_init,
-	.sleep = ves1x93_sleep,
-	.i2c_gate_ctrl = ves1x93_i2c_gate_ctrl,
-
-	.set_frontend = ves1x93_set_frontend,
-	.get_frontend = ves1x93_get_frontend,
-
-	.read_status = ves1x93_read_status,
-	.read_ber = ves1x93_read_ber,
-	.read_signal_strength = ves1x93_read_signal_strength,
-	.read_snr = ves1x93_read_snr,
-	.read_ucblocks = ves1x93_read_ucblocks,
-
-	.set_voltage = ves1x93_set_voltage,
-};
-
-module_param(debug, int, 0644);
-
-MODULE_DESCRIPTION("VLSI VES1x93 DVB-S Demodulator driver");
-MODULE_AUTHOR("Ralph Metzler");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(ves1x93_attach);
diff --git a/drivers/media/dvb/frontends/ves1x93.h b/drivers/media/dvb/frontends/ves1x93.h
deleted file mode 100644
index 8a5a49e..0000000
--- a/drivers/media/dvb/frontends/ves1x93.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-    Driver for VES1893 and VES1993 QPSK Demodulators
-
-    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
-    Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de>
-    Copyright (C) 2002 Dennis Noermann <dennis.noermann@noernet.de>
-    Copyright (C) 2002-2003 Andreas Oberritter <obi@linuxtv.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef VES1X93_H
-#define VES1X93_H
-
-#include <linux/dvb/frontend.h>
-
-struct ves1x93_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* value of XIN to use */
-	u32 xin;
-
-	/* should PWM be inverted? */
-	u8 invert_pwm:1;
-};
-
-#if defined(CONFIG_DVB_VES1X93) || (defined(CONFIG_DVB_VES1X93_MODULE) && defined(MODULE))
-extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
-					   struct i2c_adapter* i2c);
-#else
-static inline struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
-					   struct i2c_adapter* i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif // CONFIG_DVB_VES1X93
-
-#endif // VES1X93_H
diff --git a/drivers/media/dvb/frontends/z0194a.h b/drivers/media/dvb/frontends/z0194a.h
deleted file mode 100644
index 96d86d6..0000000
--- a/drivers/media/dvb/frontends/z0194a.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* z0194a.h Sharp z0194a tuner support
-*
-* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
-*
-*	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, version 2.
-*
-* see Documentation/dvb/README.dvb-usb for more information
-*/
-
-#ifndef Z0194A
-#define Z0194A
-
-static int sharp_z0194a_set_symbol_rate(struct dvb_frontend *fe,
-					 u32 srate, u32 ratio)
-{
-	u8 aclk = 0;
-	u8 bclk = 0;
-
-	if (srate < 1500000) {
-		aclk = 0xb7; bclk = 0x47; }
-	else if (srate < 3000000) {
-		aclk = 0xb7; bclk = 0x4b; }
-	else if (srate < 7000000) {
-		aclk = 0xb7; bclk = 0x4f; }
-	else if (srate < 14000000) {
-		aclk = 0xb7; bclk = 0x53; }
-	else if (srate < 30000000) {
-		aclk = 0xb6; bclk = 0x53; }
-	else if (srate < 45000000) {
-		aclk = 0xb4; bclk = 0x51; }
-
-	stv0299_writereg(fe, 0x13, aclk);
-	stv0299_writereg(fe, 0x14, bclk);
-	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
-	stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
-	stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
-
-	return 0;
-}
-
-static u8 sharp_z0194a_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x30,
-	0x03, 0x00,
-	0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-	0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
-	0x06, 0x40,   /* DAC not used, set to high impendance mode */
-	0x07, 0x00,   /* DAC LSB */
-	0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
-	0x09, 0x00,   /* FIFO */
-	0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
-	0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
-	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
-	0x10, 0x3f,   /* AGC2  0x3d */
-	0x11, 0x84,
-	0x12, 0xb9,
-	0x15, 0xc9,   /* lock detector threshold */
-	0x16, 0x00,
-	0x17, 0x00,
-	0x18, 0x00,
-	0x19, 0x00,
-	0x1a, 0x00,
-	0x1f, 0x50,
-	0x20, 0x00,
-	0x21, 0x00,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x28, 0x00,  /* out imp: normal  out type: parallel FEC mode:0 */
-	0x29, 0x1e,  /* 1/2 threshold */
-	0x2a, 0x14,  /* 2/3 threshold */
-	0x2b, 0x0f,  /* 3/4 threshold */
-	0x2c, 0x09,  /* 5/6 threshold */
-	0x2d, 0x05,  /* 7/8 threshold */
-	0x2e, 0x01,
-	0x31, 0x1f,  /* test all FECs */
-	0x32, 0x19,  /* viterbi and synchro search */
-	0x33, 0xfc,  /* rs control */
-	0x34, 0x93,  /* error control */
-	0x0f, 0x52,
-	0xff, 0xff
-};
-
-#endif
diff --git a/drivers/media/dvb/frontends/zl10036.c b/drivers/media/dvb/frontends/zl10036.c
deleted file mode 100644
index 0903d46..0000000
--- a/drivers/media/dvb/frontends/zl10036.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/**
- * Driver for Zarlink zl10036 DVB-S silicon tuner
- *
- * Copyright (C) 2006 Tino Reichardt
- * Copyright (C) 2007-2009 Matthias Schwarzott <zzam@gentoo.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- **
- * The data sheet for this tuner can be found at:
- *    http://www.mcmilk.de/projects/dvb-card/datasheets/ZL10036.pdf
- *
- * This one is working: (at my Avermedia DVB-S Pro)
- * - zl10036 (40pin, FTA)
- *
- * A driver for zl10038 should be very similar.
- */
-
-#include <linux/module.h>
-#include <linux/dvb/frontend.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-#include "zl10036.h"
-
-static int zl10036_debug;
-#define dprintk(level, args...) \
-	do { if (zl10036_debug & level) printk(KERN_DEBUG "zl10036: " args); \
-	} while (0)
-
-#define deb_info(args...)  dprintk(0x01, args)
-#define deb_i2c(args...)  dprintk(0x02, args)
-
-struct zl10036_state {
-	struct i2c_adapter *i2c;
-	const struct zl10036_config *config;
-	u32 frequency;
-	u8 br, bf;
-};
-
-
-/* This driver assumes the tuner is driven by a 10.111MHz Cristal */
-#define _XTAL 10111
-
-/* Some of the possible dividers:
- *   64, (write 0x05 to reg), freq step size   158kHz
- *   10, (write 0x0a to reg), freq step size 1.011kHz (used here)
- *    5, (write 0x09 to reg), freq step size 2.022kHz
- */
-
-#define _RDIV 10
-#define _RDIV_REG 0x0a
-#define _FR   (_XTAL/_RDIV)
-
-#define STATUS_POR 0x80 /* Power on Reset */
-#define STATUS_FL  0x40 /* Frequency & Phase Lock */
-
-/* read/write for zl10036 and zl10038 */
-
-static int zl10036_read_status_reg(struct zl10036_state *state)
-{
-	u8 status;
-	struct i2c_msg msg[1] = {
-		{ .addr = state->config->tuner_address, .flags = I2C_M_RD,
-		  .buf = &status, .len = sizeof(status) },
-	};
-
-	if (i2c_transfer(state->i2c, msg, 1) != 1) {
-		printk(KERN_ERR "%s: i2c read failed at addr=%02x\n",
-			__func__, state->config->tuner_address);
-		return -EIO;
-	}
-
-	deb_i2c("R(status): %02x  [FL=%d]\n", status,
-		(status & STATUS_FL) ? 1 : 0);
-	if (status & STATUS_POR)
-		deb_info("%s: Power-On-Reset bit enabled - "
-			"need to initialize the tuner\n", __func__);
-
-	return status;
-}
-
-static int zl10036_write(struct zl10036_state *state, u8 buf[], u8 count)
-{
-	struct i2c_msg msg[1] = {
-		{ .addr = state->config->tuner_address, .flags = 0,
-		  .buf = buf, .len = count },
-	};
-	u8 reg = 0;
-	int ret;
-
-	if (zl10036_debug & 0x02) {
-		/* every 8bit-value satisifes this!
-		 * so only check for debug log */
-		if ((buf[0] & 0x80) == 0x00)
-			reg = 2;
-		else if ((buf[0] & 0xc0) == 0x80)
-			reg = 4;
-		else if ((buf[0] & 0xf0) == 0xc0)
-			reg = 6;
-		else if ((buf[0] & 0xf0) == 0xd0)
-			reg = 8;
-		else if ((buf[0] & 0xf0) == 0xe0)
-			reg = 10;
-		else if ((buf[0] & 0xf0) == 0xf0)
-			reg = 12;
-
-		deb_i2c("W(%d):", reg);
-		{
-			int i;
-			for (i = 0; i < count; i++)
-				printk(KERN_CONT " %02x", buf[i]);
-			printk(KERN_CONT "\n");
-		}
-	}
-
-	ret = i2c_transfer(state->i2c, msg, 1);
-	if (ret != 1) {
-		printk(KERN_ERR "%s: i2c error, ret=%d\n", __func__, ret);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int zl10036_release(struct dvb_frontend *fe)
-{
-	struct zl10036_state *state = fe->tuner_priv;
-
-	fe->tuner_priv = NULL;
-	kfree(state);
-
-	return 0;
-}
-
-static int zl10036_sleep(struct dvb_frontend *fe)
-{
-	struct zl10036_state *state = fe->tuner_priv;
-	u8 buf[] = { 0xf0, 0x80 }; /* regs 12/13 */
-	int ret;
-
-	deb_info("%s\n", __func__);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
-
-	ret = zl10036_write(state, buf, sizeof(buf));
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
-
-	return ret;
-}
-
-/**
- * register map of the ZL10036/ZL10038
- *
- * reg[default] content
- *  2[0x00]:   0 | N14 | N13 | N12 | N11 | N10 |  N9 |  N8
- *  3[0x00]:  N7 |  N6 |  N5 |  N4 |  N3 |  N2 |  N1 |  N0
- *  4[0x80]:   1 |   0 | RFG | BA1 | BA0 | BG1 | BG0 | LEN
- *  5[0x00]:  P0 |  C1 |  C0 |  R4 |  R3 |  R2 |  R1 |  R0
- *  6[0xc0]:   1 |   1 |   0 |   0 | RSD |   0 |   0 |   0
- *  7[0x20]:  P1 | BF6 | BF5 | BF4 | BF3 | BF2 | BF1 |   0
- *  8[0xdb]:   1 |   1 |   0 |   1 |   0 |  CC |   1 |   1
- *  9[0x30]: VSD |  V2 |  V1 |  V0 |  S3 |  S2 |  S1 |  S0
- * 10[0xe1]:   1 |   1 |   1 |   0 |   0 | LS2 | LS1 | LS0
- * 11[0xf5]:  WS | WH2 | WH1 | WH0 | WL2 | WL1 | WL0 | WRE
- * 12[0xf0]:   1 |   1 |   1 |   1 |   0 |   0 |   0 |   0
- * 13[0x28]:  PD | BR4 | BR3 | BR2 | BR1 | BR0 | CLR |  TL
- */
-
-static int zl10036_set_frequency(struct zl10036_state *state, u32 frequency)
-{
-	u8 buf[2];
-	u32 div, foffset;
-
-	div = (frequency + _FR/2) / _FR;
-	state->frequency = div * _FR;
-
-	foffset = frequency - state->frequency;
-
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = (div >> 0) & 0xff;
-
-	deb_info("%s: ftodo=%u fpriv=%u ferr=%d div=%u\n", __func__,
-		frequency, state->frequency, foffset, div);
-
-	return zl10036_write(state, buf, sizeof(buf));
-}
-
-static int zl10036_set_bandwidth(struct zl10036_state *state, u32 fbw)
-{
-	/* fbw is measured in kHz */
-	u8 br, bf;
-	int ret;
-	u8 buf_bf[] = {
-		0xc0, 0x00, /*   6/7: rsd=0 bf=0 */
-	};
-	u8 buf_br[] = {
-		0xf0, 0x00, /* 12/13: br=0xa clr=0 tl=0*/
-	};
-	u8 zl10036_rsd_off[] = { 0xc8 }; /* set RSD=1 */
-
-	/* ensure correct values */
-	if (fbw > 35000)
-		fbw = 35000;
-	if (fbw <  8000)
-		fbw =  8000;
-
-#define _BR_MAXIMUM (_XTAL/575) /* _XTAL / 575kHz = 17 */
-
-	/* <= 28,82 MHz */
-	if (fbw <= 28820) {
-		br = _BR_MAXIMUM;
-	} else {
-		/**
-		 *  f(bw)=34,6MHz f(xtal)=10.111MHz
-		 *  br = (10111/34600) * 63 * 1/K = 14;
-		 */
-		br = ((_XTAL * 21 * 1000) / (fbw * 419));
-	}
-
-	/* ensure correct values */
-	if (br < 4)
-		br = 4;
-	if (br > _BR_MAXIMUM)
-		br = _BR_MAXIMUM;
-
-	/*
-	 * k = 1.257
-	 * bf = fbw/_XTAL * br * k - 1 */
-
-	bf = (fbw * br * 1257) / (_XTAL * 1000) - 1;
-
-	/* ensure correct values */
-	if (bf > 62)
-		bf = 62;
-
-	buf_bf[1] = (bf << 1) & 0x7e;
-	buf_br[1] = (br << 2) & 0x7c;
-	deb_info("%s: BW=%d br=%u bf=%u\n", __func__, fbw, br, bf);
-
-	if (br != state->br) {
-		ret = zl10036_write(state, buf_br, sizeof(buf_br));
-		if (ret < 0)
-			return ret;
-	}
-
-	if (bf != state->bf) {
-		ret = zl10036_write(state, buf_bf, sizeof(buf_bf));
-		if (ret < 0)
-			return ret;
-
-		/* time = br/(32* fxtal) */
-		/* minimal sleep time to be calculated
-		 * maximum br is 63 -> max time = 2 /10 MHz = 2e-7 */
-		msleep(1);
-
-		ret = zl10036_write(state, zl10036_rsd_off,
-			sizeof(zl10036_rsd_off));
-		if (ret < 0)
-			return ret;
-	}
-
-	state->br = br;
-	state->bf = bf;
-
-	return 0;
-}
-
-static int zl10036_set_gain_params(struct zl10036_state *state,
-	int c)
-{
-	u8 buf[2];
-	u8 rfg, ba, bg;
-
-	/* default values */
-	rfg = 0; /* enable when using an lna */
-	ba = 1;
-	bg = 1;
-
-	/* reg 4 */
-	buf[0] = 0x80 | ((rfg << 5) & 0x20)
-		| ((ba  << 3) & 0x18) | ((bg  << 1) & 0x06);
-
-	if (!state->config->rf_loop_enable)
-		buf[0] |= 0x01;
-
-	/* P0=0 */
-	buf[1] = _RDIV_REG | ((c << 5) & 0x60);
-
-	deb_info("%s: c=%u rfg=%u ba=%u bg=%u\n", __func__, c, rfg, ba, bg);
-	return zl10036_write(state, buf, sizeof(buf));
-}
-
-static int zl10036_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct zl10036_state *state = fe->tuner_priv;
-	int ret = 0;
-	u32 frequency = p->frequency;
-	u32 fbw;
-	int i;
-	u8 c;
-
-	/* ensure correct values
-	 * maybe redundant as core already checks this */
-	if ((frequency < fe->ops.info.frequency_min)
-	||  (frequency > fe->ops.info.frequency_max))
-		return -EINVAL;
-
-	/**
-	 * alpha = 1.35 for dvb-s
-	 * fBW = (alpha*symbolrate)/(2*0.8)
-	 * 1.35 / (2*0.8) = 27 / 32
-	 */
-	fbw = (27 * p->symbol_rate) / 32;
-
-	/* scale to kHz */
-	fbw /= 1000;
-
-	/* Add safe margin of 3MHz */
-	fbw += 3000;
-
-	/* setting the charge pump - guessed values */
-	if (frequency < 950000)
-		return -EINVAL;
-	else if (frequency < 1250000)
-		c = 0;
-	else if (frequency < 1750000)
-		c = 1;
-	else if (frequency < 2175000)
-		c = 2;
-	else
-		return -EINVAL;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
-
-	ret = zl10036_set_gain_params(state, c);
-	if (ret < 0)
-		goto error;
-
-	ret = zl10036_set_frequency(state, p->frequency);
-	if (ret < 0)
-		goto error;
-
-	ret = zl10036_set_bandwidth(state, fbw);
-	if (ret < 0)
-		goto error;
-
-	/* wait for tuner lock - no idea if this is really needed */
-	for (i = 0; i < 20; i++) {
-		ret = zl10036_read_status_reg(state);
-		if (ret < 0)
-			goto error;
-
-		/* check Frequency & Phase Lock Bit */
-		if (ret & STATUS_FL)
-			break;
-
-		msleep(10);
-	}
-
-error:
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
-
-	return ret;
-}
-
-static int zl10036_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct zl10036_state *state = fe->tuner_priv;
-
-	*frequency = state->frequency;
-
-	return 0;
-}
-
-static int zl10036_init_regs(struct zl10036_state *state)
-{
-	int ret;
-	int i;
-
-	/* could also be one block from reg 2 to 13 and additional 10/11 */
-	u8 zl10036_init_tab[][2] = {
-		{ 0x04, 0x00 },		/*   2/3: div=0x400 - arbitrary value */
-		{ 0x8b, _RDIV_REG },	/*   4/5: rfg=0 ba=1 bg=1 len=? */
-					/*        p0=0 c=0 r=_RDIV_REG */
-		{ 0xc0, 0x20 },		/*   6/7: rsd=0 bf=0x10 */
-		{ 0xd3, 0x40 },		/*   8/9: from datasheet */
-		{ 0xe3, 0x5b },		/* 10/11: lock window level */
-		{ 0xf0, 0x28 },		/* 12/13: br=0xa clr=0 tl=0*/
-		{ 0xe3, 0xf9 },		/* 10/11: unlock window level */
-	};
-
-	/* invalid values to trigger writing */
-	state->br = 0xff;
-	state->bf = 0xff;
-
-	if (!state->config->rf_loop_enable)
-		zl10036_init_tab[1][0] |= 0x01;
-
-	deb_info("%s\n", __func__);
-
-	for (i = 0; i < ARRAY_SIZE(zl10036_init_tab); i++) {
-		ret = zl10036_write(state, zl10036_init_tab[i], 2);
-		if (ret < 0)
-			return ret;
-	}
-
-	return 0;
-}
-
-static int zl10036_init(struct dvb_frontend *fe)
-{
-	struct zl10036_state *state = fe->tuner_priv;
-	int ret = 0;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
-
-	ret = zl10036_read_status_reg(state);
-	if (ret < 0)
-		return ret;
-
-	/* Only init if Power-on-Reset bit is set? */
-	ret = zl10036_init_regs(state);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
-
-	return ret;
-}
-
-static struct dvb_tuner_ops zl10036_tuner_ops = {
-	.info = {
-		.name = "Zarlink ZL10036",
-		.frequency_min = 950000,
-		.frequency_max = 2175000
-	},
-	.init = zl10036_init,
-	.release = zl10036_release,
-	.sleep = zl10036_sleep,
-	.set_params = zl10036_set_params,
-	.get_frequency = zl10036_get_frequency,
-};
-
-struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe,
-				    const struct zl10036_config *config,
-				    struct i2c_adapter *i2c)
-{
-	struct zl10036_state *state;
-	int ret;
-
-	if (!config) {
-		printk(KERN_ERR "%s: no config specified", __func__);
-		return NULL;
-	}
-
-	state = kzalloc(sizeof(struct zl10036_state), GFP_KERNEL);
-	if (!state)
-		return NULL;
-
-	state->config = config;
-	state->i2c = i2c;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
-
-	ret = zl10036_read_status_reg(state);
-	if (ret < 0) {
-		printk(KERN_ERR "%s: No zl10036 found\n", __func__);
-		goto error;
-	}
-
-	ret = zl10036_init_regs(state);
-	if (ret < 0) {
-		printk(KERN_ERR "%s: tuner initialization failed\n",
-			__func__);
-		goto error;
-	}
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
-
-	fe->tuner_priv = state;
-
-	memcpy(&fe->ops.tuner_ops, &zl10036_tuner_ops,
-		sizeof(struct dvb_tuner_ops));
-	printk(KERN_INFO "%s: tuner initialization (%s addr=0x%02x) ok\n",
-		__func__, fe->ops.tuner_ops.info.name, config->tuner_address);
-
-	return fe;
-
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(zl10036_attach);
-
-module_param_named(debug, zl10036_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-MODULE_DESCRIPTION("DVB ZL10036 driver");
-MODULE_AUTHOR("Tino Reichardt");
-MODULE_AUTHOR("Matthias Schwarzott");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/zl10036.h b/drivers/media/dvb/frontends/zl10036.h
deleted file mode 100644
index d84b8f8..0000000
--- a/drivers/media/dvb/frontends/zl10036.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * Driver for Zarlink ZL10036 DVB-S silicon tuner
- *
- * Copyright (C) 2006 Tino Reichardt
- * Copyright (C) 2007-2009 Matthias Schwarzott <zzam@gentoo.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef DVB_ZL10036_H
-#define DVB_ZL10036_H
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-/**
- * Attach a zl10036 tuner to the supplied frontend structure.
- *
- * @param fe Frontend to attach to.
- * @param config zl10036_config structure
- * @return FE pointer on success, NULL on failure.
- */
-
-struct zl10036_config {
-	u8 tuner_address;
-	int rf_loop_enable;
-};
-
-#if defined(CONFIG_DVB_ZL10036) || \
-	(defined(CONFIG_DVB_ZL10036_MODULE) && defined(MODULE))
-extern struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe,
-	const struct zl10036_config *config, struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe,
-	const struct zl10036_config *config, struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
-#endif /* DVB_ZL10036_H */
diff --git a/drivers/media/dvb/frontends/zl10039.c b/drivers/media/dvb/frontends/zl10039.c
deleted file mode 100644
index eff9c5f..0000000
--- a/drivers/media/dvb/frontends/zl10039.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- *  Driver for Zarlink ZL10039 DVB-S tuner
- *
- *  Copyright 2007 Jan D. Louw <jd.louw@mweb.co.za>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/dvb/frontend.h>
-
-#include "dvb_frontend.h"
-#include "zl10039.h"
-
-static int debug;
-
-#define dprintk(args...) \
-	do { \
-		if (debug) \
-			printk(KERN_DEBUG args); \
-	} while (0)
-
-enum zl10039_model_id {
-	ID_ZL10039 = 1
-};
-
-struct zl10039_state {
-	struct i2c_adapter *i2c;
-	u8 i2c_addr;
-	u8 id;
-};
-
-enum zl10039_reg_addr {
-	PLL0 = 0,
-	PLL1,
-	PLL2,
-	PLL3,
-	RFFE,
-	BASE0,
-	BASE1,
-	BASE2,
-	LO0,
-	LO1,
-	LO2,
-	LO3,
-	LO4,
-	LO5,
-	LO6,
-	GENERAL
-};
-
-static int zl10039_read(const struct zl10039_state *state,
-			const enum zl10039_reg_addr reg, u8 *buf,
-			const size_t count)
-{
-	u8 regbuf[] = { reg };
-	struct i2c_msg msg[] = {
-		{/* Write register address */
-			.addr = state->i2c_addr,
-			.flags = 0,
-			.buf = regbuf,
-			.len = 1,
-		}, {/* Read count bytes */
-			.addr = state->i2c_addr,
-			.flags = I2C_M_RD,
-			.buf = buf,
-			.len = count,
-		},
-	};
-
-	dprintk("%s\n", __func__);
-
-	if (i2c_transfer(state->i2c, msg, 2) != 2) {
-		dprintk("%s: i2c read error\n", __func__);
-		return -EREMOTEIO;
-	}
-
-	return 0; /* Success */
-}
-
-static int zl10039_write(struct zl10039_state *state,
-			const enum zl10039_reg_addr reg, const u8 *src,
-			const size_t count)
-{
-	u8 buf[count + 1];
-	struct i2c_msg msg = {
-		.addr = state->i2c_addr,
-		.flags = 0,
-		.buf = buf,
-		.len = count + 1,
-	};
-
-	dprintk("%s\n", __func__);
-	/* Write register address and data in one go */
-	buf[0] = reg;
-	memcpy(&buf[1], src, count);
-	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
-		dprintk("%s: i2c write error\n", __func__);
-		return -EREMOTEIO;
-	}
-
-	return 0; /* Success */
-}
-
-static inline int zl10039_readreg(struct zl10039_state *state,
-				const enum zl10039_reg_addr reg, u8 *val)
-{
-	return zl10039_read(state, reg, val, 1);
-}
-
-static inline int zl10039_writereg(struct zl10039_state *state,
-				const enum zl10039_reg_addr reg,
-				const u8 val)
-{
-	return zl10039_write(state, reg, &val, 1);
-}
-
-static int zl10039_init(struct dvb_frontend *fe)
-{
-	struct zl10039_state *state = fe->tuner_priv;
-	int ret;
-
-	dprintk("%s\n", __func__);
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	/* Reset logic */
-	ret = zl10039_writereg(state, GENERAL, 0x40);
-	if (ret < 0) {
-		dprintk("Note: i2c write error normal when resetting the "
-			"tuner\n");
-	}
-	/* Wake up */
-	ret = zl10039_writereg(state, GENERAL, 0x01);
-	if (ret < 0) {
-		dprintk("Tuner power up failed\n");
-		return ret;
-	}
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	return 0;
-}
-
-static int zl10039_sleep(struct dvb_frontend *fe)
-{
-	struct zl10039_state *state = fe->tuner_priv;
-	int ret;
-
-	dprintk("%s\n", __func__);
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	ret = zl10039_writereg(state, GENERAL, 0x80);
-	if (ret < 0) {
-		dprintk("Tuner sleep failed\n");
-		return ret;
-	}
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	return 0;
-}
-
-static int zl10039_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct zl10039_state *state = fe->tuner_priv;
-	u8 buf[6];
-	u8 bf;
-	u32 fbw;
-	u32 div;
-	int ret;
-
-	dprintk("%s\n", __func__);
-	dprintk("Set frequency = %d, symbol rate = %d\n",
-			c->frequency, c->symbol_rate);
-
-	/* Assumed 10.111 MHz crystal oscillator */
-	/* Cancelled num/den 80 to prevent overflow */
-	div = (c->frequency * 1000) / 126387;
-	fbw = (c->symbol_rate * 27) / 32000;
-	/* Cancelled num/den 10 to prevent overflow */
-	bf = ((fbw * 5088) / 1011100) - 1;
-
-	/*PLL divider*/
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = (div >> 0) & 0xff;
-	/*Reference divider*/
-	/* Select reference ratio of 80 */
-	buf[2] = 0x1D;
-	/*PLL test modes*/
-	buf[3] = 0x40;
-	/*RF Control register*/
-	buf[4] = 0x6E; /* Bypass enable */
-	/*Baseband filter cutoff */
-	buf[5] = bf;
-
-	/* Open i2c gate */
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	/* BR = 10, Enable filter adjustment */
-	ret = zl10039_writereg(state, BASE1, 0x0A);
-	if (ret < 0)
-		goto error;
-	/* Write new config values */
-	ret = zl10039_write(state, PLL0, buf, sizeof(buf));
-	if (ret < 0)
-		goto error;
-	/* BR = 10, Disable filter adjustment */
-	ret = zl10039_writereg(state, BASE1, 0x6A);
-	if (ret < 0)
-		goto error;
-
-	/* Close i2c gate */
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-	return 0;
-error:
-	dprintk("Error setting tuner\n");
-	return ret;
-}
-
-static int zl10039_release(struct dvb_frontend *fe)
-{
-	struct zl10039_state *state = fe->tuner_priv;
-
-	dprintk("%s\n", __func__);
-	kfree(state);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static struct dvb_tuner_ops zl10039_ops = {
-	.release = zl10039_release,
-	.init = zl10039_init,
-	.sleep = zl10039_sleep,
-	.set_params = zl10039_set_params,
-};
-
-struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
-		u8 i2c_addr, struct i2c_adapter *i2c)
-{
-	struct zl10039_state *state = NULL;
-
-	dprintk("%s\n", __func__);
-	state = kmalloc(sizeof(struct zl10039_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	state->i2c = i2c;
-	state->i2c_addr = i2c_addr;
-
-	/* Open i2c gate */
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	/* check if this is a valid tuner */
-	if (zl10039_readreg(state, GENERAL, &state->id) < 0) {
-		/* Close i2c gate */
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-		goto error;
-	}
-	/* Close i2c gate */
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	state->id = state->id & 0x0f;
-	switch (state->id) {
-	case ID_ZL10039:
-		strcpy(fe->ops.tuner_ops.info.name,
-			"Zarlink ZL10039 DVB-S tuner");
-		break;
-	default:
-		dprintk("Chip ID=%x does not match a known type\n", state->id);
-		goto error;
-	}
-
-	memcpy(&fe->ops.tuner_ops, &zl10039_ops, sizeof(struct dvb_tuner_ops));
-	fe->tuner_priv = state;
-	dprintk("Tuner attached @ i2c address 0x%02x\n", i2c_addr);
-	return fe;
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(zl10039_attach);
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-MODULE_DESCRIPTION("Zarlink ZL10039 DVB-S tuner driver");
-MODULE_AUTHOR("Jan D. Louw <jd.louw@mweb.co.za>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/zl10039.h b/drivers/media/dvb/frontends/zl10039.h
deleted file mode 100644
index 5eee7ea..0000000
--- a/drivers/media/dvb/frontends/zl10039.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-    Driver for Zarlink ZL10039 DVB-S tuner
-
-    Copyright (C) 2007 Jan D. Louw <jd.louw@mweb.co.za>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef ZL10039_H
-#define ZL10039_H
-
-#if defined(CONFIG_DVB_ZL10039) || (defined(CONFIG_DVB_ZL10039_MODULE) \
-	    && defined(MODULE))
-struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
-					u8 i2c_addr,
-					struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
-					u8 i2c_addr,
-					struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_ZL10039 */
-
-#endif /* ZL10039_H */
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
deleted file mode 100644
index 82946cd..0000000
--- a/drivers/media/dvb/frontends/zl10353.c
+++ /dev/null
@@ -1,684 +0,0 @@
-/*
- * Driver for Zarlink DVB-T ZL10353 demodulator
- *
- * Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <asm/div64.h>
-
-#include "dvb_frontend.h"
-#include "zl10353_priv.h"
-#include "zl10353.h"
-
-struct zl10353_state {
-	struct i2c_adapter *i2c;
-	struct dvb_frontend frontend;
-
-	struct zl10353_config config;
-
-	u32 bandwidth;
-	u32 ucblocks;
-	u32 frequency;
-};
-
-static int debug;
-#define dprintk(args...) \
-	do { \
-		if (debug) printk(KERN_DEBUG "zl10353: " args); \
-	} while (0)
-
-static int debug_regs;
-
-static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
-{
-	struct zl10353_state *state = fe->demodulator_priv;
-	u8 buf[2] = { reg, val };
-	struct i2c_msg msg = { .addr = state->config.demod_address, .flags = 0,
-			       .buf = buf, .len = 2 };
-	int err = i2c_transfer(state->i2c, &msg, 1);
-	if (err != 1) {
-		printk("zl10353: write to reg %x failed (err = %d)!\n", reg, err);
-		return err;
-	}
-	return 0;
-}
-
-static int zl10353_write(struct dvb_frontend *fe, const u8 ibuf[], int ilen)
-{
-	int err, i;
-	for (i = 0; i < ilen - 1; i++)
-		if ((err = zl10353_single_write(fe, ibuf[0] + i, ibuf[i + 1])))
-			return err;
-
-	return 0;
-}
-
-static int zl10353_read_register(struct zl10353_state *state, u8 reg)
-{
-	int ret;
-	u8 b0[1] = { reg };
-	u8 b1[1] = { 0 };
-	struct i2c_msg msg[2] = { { .addr = state->config.demod_address,
-				    .flags = 0,
-				    .buf = b0, .len = 1 },
-				  { .addr = state->config.demod_address,
-				    .flags = I2C_M_RD,
-				    .buf = b1, .len = 1 } };
-
-	ret = i2c_transfer(state->i2c, msg, 2);
-
-	if (ret != 2) {
-		printk("%s: readreg error (reg=%d, ret==%i)\n",
-		       __func__, reg, ret);
-		return ret;
-	}
-
-	return b1[0];
-}
-
-static void zl10353_dump_regs(struct dvb_frontend *fe)
-{
-	struct zl10353_state *state = fe->demodulator_priv;
-	int ret;
-	u8 reg;
-
-	/* Dump all registers. */
-	for (reg = 0; ; reg++) {
-		if (reg % 16 == 0) {
-			if (reg)
-				printk(KERN_CONT "\n");
-			printk(KERN_DEBUG "%02x:", reg);
-		}
-		ret = zl10353_read_register(state, reg);
-		if (ret >= 0)
-			printk(KERN_CONT " %02x", (u8)ret);
-		else
-			printk(KERN_CONT " --");
-		if (reg == 0xff)
-			break;
-	}
-	printk(KERN_CONT "\n");
-}
-
-static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
-				      u32 bandwidth,
-				      u16 *nominal_rate)
-{
-	struct zl10353_state *state = fe->demodulator_priv;
-	u32 adc_clock = 450560; /* 45.056 MHz */
-	u64 value;
-	u8 bw = bandwidth / 1000000;
-
-	if (state->config.adc_clock)
-		adc_clock = state->config.adc_clock;
-
-	value = (u64)10 * (1 << 23) / 7 * 125;
-	value = (bw * value) + adc_clock / 2;
-	do_div(value, adc_clock);
-	*nominal_rate = value;
-
-	dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
-		__func__, bw, adc_clock, *nominal_rate);
-}
-
-static void zl10353_calc_input_freq(struct dvb_frontend *fe,
-				    u16 *input_freq)
-{
-	struct zl10353_state *state = fe->demodulator_priv;
-	u32 adc_clock = 450560;	/* 45.056  MHz */
-	int if2 = 361667;	/* 36.1667 MHz */
-	int ife;
-	u64 value;
-
-	if (state->config.adc_clock)
-		adc_clock = state->config.adc_clock;
-	if (state->config.if2)
-		if2 = state->config.if2;
-
-	if (adc_clock >= if2 * 2)
-		ife = if2;
-	else {
-		ife = adc_clock - (if2 % adc_clock);
-		if (ife > adc_clock / 2)
-			ife = adc_clock - ife;
-	}
-	value = (u64)65536 * ife + adc_clock / 2;
-	do_div(value, adc_clock);
-	*input_freq = -value;
-
-	dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
-		__func__, if2, ife, adc_clock, -(int)value, *input_freq);
-}
-
-static int zl10353_sleep(struct dvb_frontend *fe)
-{
-	static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 };
-
-	zl10353_write(fe, zl10353_softdown, sizeof(zl10353_softdown));
-	return 0;
-}
-
-static int zl10353_set_parameters(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct zl10353_state *state = fe->demodulator_priv;
-	u16 nominal_rate, input_freq;
-	u8 pllbuf[6] = { 0x67 }, acq_ctl = 0;
-	u16 tps = 0;
-
-	state->frequency = c->frequency;
-
-	zl10353_single_write(fe, RESET, 0x80);
-	udelay(200);
-	zl10353_single_write(fe, 0xEA, 0x01);
-	udelay(200);
-	zl10353_single_write(fe, 0xEA, 0x00);
-
-	zl10353_single_write(fe, AGC_TARGET, 0x28);
-
-	if (c->transmission_mode != TRANSMISSION_MODE_AUTO)
-		acq_ctl |= (1 << 0);
-	if (c->guard_interval != GUARD_INTERVAL_AUTO)
-		acq_ctl |= (1 << 1);
-	zl10353_single_write(fe, ACQ_CTL, acq_ctl);
-
-	switch (c->bandwidth_hz) {
-	case 6000000:
-		/* These are extrapolated from the 7 and 8MHz values */
-		zl10353_single_write(fe, MCLK_RATIO, 0x97);
-		zl10353_single_write(fe, 0x64, 0x34);
-		zl10353_single_write(fe, 0xcc, 0xdd);
-		break;
-	case 7000000:
-		zl10353_single_write(fe, MCLK_RATIO, 0x86);
-		zl10353_single_write(fe, 0x64, 0x35);
-		zl10353_single_write(fe, 0xcc, 0x73);
-		break;
-	default:
-		c->bandwidth_hz = 8000000;
-		/* fall though */
-	case 8000000:
-		zl10353_single_write(fe, MCLK_RATIO, 0x75);
-		zl10353_single_write(fe, 0x64, 0x36);
-		zl10353_single_write(fe, 0xcc, 0x73);
-	}
-
-	zl10353_calc_nominal_rate(fe, c->bandwidth_hz, &nominal_rate);
-	zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate));
-	zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate));
-	state->bandwidth = c->bandwidth_hz;
-
-	zl10353_calc_input_freq(fe, &input_freq);
-	zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq));
-	zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq));
-
-	/* Hint at TPS settings */
-	switch (c->code_rate_HP) {
-	case FEC_2_3:
-		tps |= (1 << 7);
-		break;
-	case FEC_3_4:
-		tps |= (2 << 7);
-		break;
-	case FEC_5_6:
-		tps |= (3 << 7);
-		break;
-	case FEC_7_8:
-		tps |= (4 << 7);
-		break;
-	case FEC_1_2:
-	case FEC_AUTO:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	switch (c->code_rate_LP) {
-	case FEC_2_3:
-		tps |= (1 << 4);
-		break;
-	case FEC_3_4:
-		tps |= (2 << 4);
-		break;
-	case FEC_5_6:
-		tps |= (3 << 4);
-		break;
-	case FEC_7_8:
-		tps |= (4 << 4);
-		break;
-	case FEC_1_2:
-	case FEC_AUTO:
-		break;
-	case FEC_NONE:
-		if (c->hierarchy == HIERARCHY_AUTO ||
-		    c->hierarchy == HIERARCHY_NONE)
-			break;
-	default:
-		return -EINVAL;
-	}
-
-	switch (c->modulation) {
-	case QPSK:
-		break;
-	case QAM_AUTO:
-	case QAM_16:
-		tps |= (1 << 13);
-		break;
-	case QAM_64:
-		tps |= (2 << 13);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	switch (c->transmission_mode) {
-	case TRANSMISSION_MODE_2K:
-	case TRANSMISSION_MODE_AUTO:
-		break;
-	case TRANSMISSION_MODE_8K:
-		tps |= (1 << 0);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	switch (c->guard_interval) {
-	case GUARD_INTERVAL_1_32:
-	case GUARD_INTERVAL_AUTO:
-		break;
-	case GUARD_INTERVAL_1_16:
-		tps |= (1 << 2);
-		break;
-	case GUARD_INTERVAL_1_8:
-		tps |= (2 << 2);
-		break;
-	case GUARD_INTERVAL_1_4:
-		tps |= (3 << 2);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	switch (c->hierarchy) {
-	case HIERARCHY_AUTO:
-	case HIERARCHY_NONE:
-		break;
-	case HIERARCHY_1:
-		tps |= (1 << 10);
-		break;
-	case HIERARCHY_2:
-		tps |= (2 << 10);
-		break;
-	case HIERARCHY_4:
-		tps |= (3 << 10);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	zl10353_single_write(fe, TPS_GIVEN_1, msb(tps));
-	zl10353_single_write(fe, TPS_GIVEN_0, lsb(tps));
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	/*
-	 * If there is no tuner attached to the secondary I2C bus, we call
-	 * set_params to program a potential tuner attached somewhere else.
-	 * Otherwise, we update the PLL registers via calc_regs.
-	 */
-	if (state->config.no_tuner) {
-		if (fe->ops.tuner_ops.set_params) {
-			fe->ops.tuner_ops.set_params(fe);
-			if (fe->ops.i2c_gate_ctrl)
-				fe->ops.i2c_gate_ctrl(fe, 0);
-		}
-	} else if (fe->ops.tuner_ops.calc_regs) {
-		fe->ops.tuner_ops.calc_regs(fe, pllbuf + 1, 5);
-		pllbuf[1] <<= 1;
-		zl10353_write(fe, pllbuf, sizeof(pllbuf));
-	}
-
-	zl10353_single_write(fe, 0x5F, 0x13);
-
-	/* If no attached tuner or invalid PLL registers, just start the FSM. */
-	if (state->config.no_tuner || fe->ops.tuner_ops.calc_regs == NULL)
-		zl10353_single_write(fe, FSM_GO, 0x01);
-	else
-		zl10353_single_write(fe, TUNER_GO, 0x01);
-
-	return 0;
-}
-
-static int zl10353_get_parameters(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct zl10353_state *state = fe->demodulator_priv;
-	int s6, s9;
-	u16 tps;
-	static const u8 tps_fec_to_api[8] = {
-		FEC_1_2,
-		FEC_2_3,
-		FEC_3_4,
-		FEC_5_6,
-		FEC_7_8,
-		FEC_AUTO,
-		FEC_AUTO,
-		FEC_AUTO
-	};
-
-	s6 = zl10353_read_register(state, STATUS_6);
-	s9 = zl10353_read_register(state, STATUS_9);
-	if (s6 < 0 || s9 < 0)
-		return -EREMOTEIO;
-	if ((s6 & (1 << 5)) == 0 || (s9 & (1 << 4)) == 0)
-		return -EINVAL;	/* no FE or TPS lock */
-
-	tps = zl10353_read_register(state, TPS_RECEIVED_1) << 8 |
-	      zl10353_read_register(state, TPS_RECEIVED_0);
-
-	c->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7];
-	c->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7];
-
-	switch ((tps >> 13) & 3) {
-	case 0:
-		c->modulation = QPSK;
-		break;
-	case 1:
-		c->modulation = QAM_16;
-		break;
-	case 2:
-		c->modulation = QAM_64;
-		break;
-	default:
-		c->modulation = QAM_AUTO;
-		break;
-	}
-
-	c->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K :
-					       TRANSMISSION_MODE_2K;
-
-	switch ((tps >> 2) & 3) {
-	case 0:
-		c->guard_interval = GUARD_INTERVAL_1_32;
-		break;
-	case 1:
-		c->guard_interval = GUARD_INTERVAL_1_16;
-		break;
-	case 2:
-		c->guard_interval = GUARD_INTERVAL_1_8;
-		break;
-	case 3:
-		c->guard_interval = GUARD_INTERVAL_1_4;
-		break;
-	default:
-		c->guard_interval = GUARD_INTERVAL_AUTO;
-		break;
-	}
-
-	switch ((tps >> 10) & 7) {
-	case 0:
-		c->hierarchy = HIERARCHY_NONE;
-		break;
-	case 1:
-		c->hierarchy = HIERARCHY_1;
-		break;
-	case 2:
-		c->hierarchy = HIERARCHY_2;
-		break;
-	case 3:
-		c->hierarchy = HIERARCHY_4;
-		break;
-	default:
-		c->hierarchy = HIERARCHY_AUTO;
-		break;
-	}
-
-	c->frequency = state->frequency;
-	c->bandwidth_hz = state->bandwidth;
-	c->inversion = INVERSION_AUTO;
-
-	return 0;
-}
-
-static int zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct zl10353_state *state = fe->demodulator_priv;
-	int s6, s7, s8;
-
-	if ((s6 = zl10353_read_register(state, STATUS_6)) < 0)
-		return -EREMOTEIO;
-	if ((s7 = zl10353_read_register(state, STATUS_7)) < 0)
-		return -EREMOTEIO;
-	if ((s8 = zl10353_read_register(state, STATUS_8)) < 0)
-		return -EREMOTEIO;
-
-	*status = 0;
-	if (s6 & (1 << 2))
-		*status |= FE_HAS_CARRIER;
-	if (s6 & (1 << 1))
-		*status |= FE_HAS_VITERBI;
-	if (s6 & (1 << 5))
-		*status |= FE_HAS_LOCK;
-	if (s7 & (1 << 4))
-		*status |= FE_HAS_SYNC;
-	if (s8 & (1 << 6))
-		*status |= FE_HAS_SIGNAL;
-
-	if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
-	    (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
-		*status &= ~FE_HAS_LOCK;
-
-	return 0;
-}
-
-static int zl10353_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	struct zl10353_state *state = fe->demodulator_priv;
-
-	*ber = zl10353_read_register(state, RS_ERR_CNT_2) << 16 |
-	       zl10353_read_register(state, RS_ERR_CNT_1) << 8 |
-	       zl10353_read_register(state, RS_ERR_CNT_0);
-
-	return 0;
-}
-
-static int zl10353_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct zl10353_state *state = fe->demodulator_priv;
-
-	u16 signal = zl10353_read_register(state, AGC_GAIN_1) << 10 |
-		     zl10353_read_register(state, AGC_GAIN_0) << 2 | 3;
-
-	*strength = ~signal;
-
-	return 0;
-}
-
-static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct zl10353_state *state = fe->demodulator_priv;
-	u8 _snr;
-
-	if (debug_regs)
-		zl10353_dump_regs(fe);
-
-	_snr = zl10353_read_register(state, SNR);
-	*snr = 10 * _snr / 8;
-
-	return 0;
-}
-
-static int zl10353_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	struct zl10353_state *state = fe->demodulator_priv;
-       u32 ubl = 0;
-
-       ubl = zl10353_read_register(state, RS_UBC_1) << 8 |
-	     zl10353_read_register(state, RS_UBC_0);
-
-       state->ucblocks += ubl;
-       *ucblocks = state->ucblocks;
-
-	return 0;
-}
-
-static int zl10353_get_tune_settings(struct dvb_frontend *fe,
-				     struct dvb_frontend_tune_settings
-					 *fe_tune_settings)
-{
-	fe_tune_settings->min_delay_ms = 1000;
-	fe_tune_settings->step_size = 0;
-	fe_tune_settings->max_drift = 0;
-
-	return 0;
-}
-
-static int zl10353_init(struct dvb_frontend *fe)
-{
-	struct zl10353_state *state = fe->demodulator_priv;
-	u8 zl10353_reset_attach[6] = { 0x50, 0x03, 0x64, 0x46, 0x15, 0x0F };
-
-	if (debug_regs)
-		zl10353_dump_regs(fe);
-	if (state->config.parallel_ts)
-		zl10353_reset_attach[2] &= ~0x20;
-	if (state->config.clock_ctl_1)
-		zl10353_reset_attach[3] = state->config.clock_ctl_1;
-	if (state->config.pll_0)
-		zl10353_reset_attach[4] = state->config.pll_0;
-
-	/* Do a "hard" reset if not already done */
-	if (zl10353_read_register(state, 0x50) != zl10353_reset_attach[1] ||
-	    zl10353_read_register(state, 0x51) != zl10353_reset_attach[2]) {
-		zl10353_write(fe, zl10353_reset_attach,
-				   sizeof(zl10353_reset_attach));
-		if (debug_regs)
-			zl10353_dump_regs(fe);
-	}
-
-	return 0;
-}
-
-static int zl10353_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
-{
-	struct zl10353_state *state = fe->demodulator_priv;
-	u8 val = 0x0a;
-
-	if (state->config.disable_i2c_gate_ctrl) {
-		/* No tuner attached to the internal I2C bus */
-		/* If set enable I2C bridge, the main I2C bus stopped hardly */
-		return 0;
-	}
-
-	if (enable)
-		val |= 0x10;
-
-	return zl10353_single_write(fe, 0x62, val);
-}
-
-static void zl10353_release(struct dvb_frontend *fe)
-{
-	struct zl10353_state *state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops zl10353_ops;
-
-struct dvb_frontend *zl10353_attach(const struct zl10353_config *config,
-				    struct i2c_adapter *i2c)
-{
-	struct zl10353_state *state = NULL;
-	int id;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct zl10353_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
-
-	/* setup the state */
-	state->i2c = i2c;
-	memcpy(&state->config, config, sizeof(struct zl10353_config));
-
-	/* check if the demod is there */
-	id = zl10353_read_register(state, CHIP_ID);
-	if ((id != ID_ZL10353) && (id != ID_CE6230) && (id != ID_CE6231))
-		goto error;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &zl10353_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-
-	return &state->frontend;
-error:
-	kfree(state);
-	return NULL;
-}
-
-static struct dvb_frontend_ops zl10353_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name			= "Zarlink ZL10353 DVB-T",
-		.frequency_min		= 174000000,
-		.frequency_max		= 862000000,
-		.frequency_stepsize	= 166667,
-		.frequency_tolerance	= 0,
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
-			FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
-			FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER |
-			FE_CAN_MUTE_TS
-	},
-
-	.release = zl10353_release,
-
-	.init = zl10353_init,
-	.sleep = zl10353_sleep,
-	.i2c_gate_ctrl = zl10353_i2c_gate_ctrl,
-	.write = zl10353_write,
-
-	.set_frontend = zl10353_set_parameters,
-	.get_frontend = zl10353_get_parameters,
-	.get_tune_settings = zl10353_get_tune_settings,
-
-	.read_status = zl10353_read_status,
-	.read_ber = zl10353_read_ber,
-	.read_signal_strength = zl10353_read_signal_strength,
-	.read_snr = zl10353_read_snr,
-	.read_ucblocks = zl10353_read_ucblocks,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-module_param(debug_regs, int, 0644);
-MODULE_PARM_DESC(debug_regs, "Turn on/off frontend register dumps (default:off).");
-
-MODULE_DESCRIPTION("Zarlink ZL10353 DVB-T demodulator driver");
-MODULE_AUTHOR("Chris Pascoe");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(zl10353_attach);
diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
deleted file mode 100644
index 6e3ca9e..0000000
--- a/drivers/media/dvb/frontends/zl10353.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- *  Driver for Zarlink DVB-T ZL10353 demodulator
- *
- *  Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef ZL10353_H
-#define ZL10353_H
-
-#include <linux/dvb/frontend.h>
-
-struct zl10353_config
-{
-	/* demodulator's I2C address */
-	u8 demod_address;
-
-	/* frequencies in units of 0.1kHz */
-	int adc_clock;	/* default: 450560 (45.056  MHz) */
-	int if2;	/* default: 361667 (36.1667 MHz) */
-
-	/* set if no pll is connected to the secondary i2c bus */
-	int no_tuner;
-
-	/* set if parallel ts output is required */
-	int parallel_ts;
-
-	/* set if i2c_gate_ctrl disable is required */
-	u8 disable_i2c_gate_ctrl:1;
-
-	/* clock control registers (0x51-0x54) */
-	u8 clock_ctl_1;  /* default: 0x46 */
-	u8 pll_0;        /* default: 0x15 */
-};
-
-#if defined(CONFIG_DVB_ZL10353) || (defined(CONFIG_DVB_ZL10353_MODULE) && defined(MODULE))
-extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
-					   struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
-					   struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_ZL10353 */
-
-#endif /* ZL10353_H */
diff --git a/drivers/media/dvb/frontends/zl10353_priv.h b/drivers/media/dvb/frontends/zl10353_priv.h
deleted file mode 100644
index e0dd1d3..0000000
--- a/drivers/media/dvb/frontends/zl10353_priv.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- *  Driver for Zarlink DVB-T ZL10353 demodulator
- *
- *  Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _ZL10353_PRIV_
-#define _ZL10353_PRIV_
-
-#define ID_ZL10353	0x14 /* Zarlink ZL10353 */
-#define ID_CE6230	0x18 /* Intel CE6230 */
-#define ID_CE6231	0x19 /* Intel CE6231 */
-
-#define msb(x) (((x) >> 8) & 0xff)
-#define lsb(x) ((x) & 0xff)
-
-enum zl10353_reg_addr {
-	INTERRUPT_0        = 0x00,
-	INTERRUPT_1        = 0x01,
-	INTERRUPT_2        = 0x02,
-	INTERRUPT_3        = 0x03,
-	INTERRUPT_4        = 0x04,
-	INTERRUPT_5        = 0x05,
-	STATUS_6           = 0x06,
-	STATUS_7           = 0x07,
-	STATUS_8           = 0x08,
-	STATUS_9           = 0x09,
-	AGC_GAIN_1         = 0x0A,
-	AGC_GAIN_0         = 0x0B,
-	SNR                = 0x10,
-	RS_ERR_CNT_2       = 0x11,
-	RS_ERR_CNT_1       = 0x12,
-	RS_ERR_CNT_0       = 0x13,
-	RS_UBC_1           = 0x14,
-	RS_UBC_0           = 0x15,
-	TPS_RECEIVED_1     = 0x1D,
-	TPS_RECEIVED_0     = 0x1E,
-	TPS_CURRENT_1      = 0x1F,
-	TPS_CURRENT_0      = 0x20,
-	CLOCK_CTL_0        = 0x51,
-	CLOCK_CTL_1        = 0x52,
-	PLL_0              = 0x53,
-	PLL_1              = 0x54,
-	RESET              = 0x55,
-	AGC_TARGET         = 0x56,
-	MCLK_RATIO         = 0x5C,
-	ACQ_CTL            = 0x5E,
-	TRL_NOMINAL_RATE_1 = 0x65,
-	TRL_NOMINAL_RATE_0 = 0x66,
-	INPUT_FREQ_1       = 0x6C,
-	INPUT_FREQ_0       = 0x6D,
-	TPS_GIVEN_1        = 0x6E,
-	TPS_GIVEN_0        = 0x6F,
-	TUNER_GO           = 0x70,
-	FSM_GO             = 0x71,
-	CHIP_ID            = 0x7F,
-	CHAN_STEP_1        = 0xE4,
-	CHAN_STEP_0        = 0xE5,
-	OFDM_LOCK_TIME     = 0xE7,
-	FEC_LOCK_TIME      = 0xE8,
-	ACQ_DELAY          = 0xE9,
-};
-
-#endif                          /* _ZL10353_PRIV_ */
diff --git a/drivers/media/dvb/mantis/Kconfig b/drivers/media/dvb/mantis/Kconfig
deleted file mode 100644
index a13a505..0000000
--- a/drivers/media/dvb/mantis/Kconfig
+++ /dev/null
@@ -1,38 +0,0 @@
-config MANTIS_CORE
-	tristate "Mantis/Hopper PCI bridge based devices"
-	depends on PCI && I2C && INPUT && RC_CORE
-
-	help
-	  Support for PCI cards based on the Mantis and Hopper PCi bridge.
-
-	  Say Y if you own such a device and want to use it.
-
-config DVB_MANTIS
-	tristate "MANTIS based cards"
-	depends on MANTIS_CORE && DVB_CORE && PCI && I2C
-	select DVB_MB86A16 if !DVB_FE_CUSTOMISE
-	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-	select DVB_STV0299 if !DVB_FE_CUSTOMISE
-	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
-	select DVB_STB0899 if !DVB_FE_CUSTOMISE
-	select DVB_STB6100 if !DVB_FE_CUSTOMISE
-	select DVB_TDA665x if !DVB_FE_CUSTOMISE
-	select DVB_TDA10021 if !DVB_FE_CUSTOMISE
-	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
-	select DVB_PLL
-	help
-	  Support for PCI cards based on the Mantis PCI bridge.
-	  Say Y when you have a Mantis based DVB card and want to use it.
-
-	  If unsure say N.
-
-config DVB_HOPPER
-	tristate "HOPPER based cards"
-	depends on MANTIS_CORE && DVB_CORE && PCI && I2C
-	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-	select DVB_PLL
-	help
-	  Support for PCI cards based on the Hopper  PCI bridge.
-	  Say Y when you have a Hopper based DVB card and want to use it.
-
-	  If unsure say N
diff --git a/drivers/media/dvb/mantis/Makefile b/drivers/media/dvb/mantis/Makefile
deleted file mode 100644
index ec8116d..0000000
--- a/drivers/media/dvb/mantis/Makefile
+++ /dev/null
@@ -1,28 +0,0 @@
-mantis_core-objs :=	mantis_ioc.o	\
-			mantis_uart.o	\
-			mantis_dma.o	\
-			mantis_pci.o	\
-			mantis_i2c.o	\
-			mantis_dvb.o	\
-			mantis_evm.o	\
-			mantis_hif.o	\
-			mantis_ca.o	\
-			mantis_pcmcia.o	\
-			mantis_input.o
-
-mantis-objs	:=	mantis_cards.o	\
-			mantis_vp1033.o	\
-			mantis_vp1034.o	\
-			mantis_vp1041.o	\
-			mantis_vp2033.o	\
-			mantis_vp2040.o	\
-			mantis_vp3030.o
-
-hopper-objs	:=	hopper_cards.o	\
-			hopper_vp3028.o
-
-obj-$(CONFIG_MANTIS_CORE)	+= mantis_core.o
-obj-$(CONFIG_DVB_MANTIS)	+= mantis.o
-obj-$(CONFIG_DVB_HOPPER)	+= hopper.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/mantis/hopper_cards.c b/drivers/media/dvb/mantis/hopper_cards.c
deleted file mode 100644
index cc0251e..0000000
--- a/drivers/media/dvb/mantis/hopper_cards.c
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
-	Hopper PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <asm/irq.h>
-#include <linux/interrupt.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "mantis_common.h"
-#include "hopper_vp3028.h"
-#include "mantis_dma.h"
-#include "mantis_dvb.h"
-#include "mantis_uart.h"
-#include "mantis_ioc.h"
-#include "mantis_pci.h"
-#include "mantis_i2c.h"
-#include "mantis_reg.h"
-
-static unsigned int verbose;
-module_param(verbose, int, 0644);
-MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)");
-
-#define DRIVER_NAME	"Hopper"
-
-static char *label[10] = {
-	"DMA",
-	"IRQ-0",
-	"IRQ-1",
-	"OCERR",
-	"PABRT",
-	"RIPRR",
-	"PPERR",
-	"FTRGT",
-	"RISCI",
-	"RACK"
-};
-
-static int devs;
-
-static irqreturn_t hopper_irq_handler(int irq, void *dev_id)
-{
-	u32 stat = 0, mask = 0;
-	u32 rst_stat = 0, rst_mask = 0;
-
-	struct mantis_pci *mantis;
-	struct mantis_ca *ca;
-
-	mantis = (struct mantis_pci *) dev_id;
-	if (unlikely(mantis == NULL)) {
-		dprintk(MANTIS_ERROR, 1, "Mantis == NULL");
-		return IRQ_NONE;
-	}
-	ca = mantis->mantis_ca;
-
-	stat = mmread(MANTIS_INT_STAT);
-	mask = mmread(MANTIS_INT_MASK);
-	if (!(stat & mask))
-		return IRQ_NONE;
-
-	rst_mask  = MANTIS_GPIF_WRACK  |
-		    MANTIS_GPIF_OTHERR |
-		    MANTIS_SBUF_WSTO   |
-		    MANTIS_GPIF_EXTIRQ;
-
-	rst_stat  = mmread(MANTIS_GPIF_STATUS);
-	rst_stat &= rst_mask;
-	mmwrite(rst_stat, MANTIS_GPIF_STATUS);
-
-	mantis->mantis_int_stat = stat;
-	mantis->mantis_int_mask = mask;
-	dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask);
-	if (stat & MANTIS_INT_RISCEN) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]);
-	}
-	if (stat & MANTIS_INT_IRQ0) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]);
-		mantis->gpif_status = rst_stat;
-		wake_up(&ca->hif_write_wq);
-		schedule_work(&ca->hif_evm_work);
-	}
-	if (stat & MANTIS_INT_IRQ1) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]);
-		schedule_work(&mantis->uart_work);
-	}
-	if (stat & MANTIS_INT_OCERR) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]);
-	}
-	if (stat & MANTIS_INT_PABORT) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]);
-	}
-	if (stat & MANTIS_INT_RIPERR) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]);
-	}
-	if (stat & MANTIS_INT_PPERR) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]);
-	}
-	if (stat & MANTIS_INT_FTRGT) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]);
-	}
-	if (stat & MANTIS_INT_RISCI) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
-		mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
-		tasklet_schedule(&mantis->tasklet);
-	}
-	if (stat & MANTIS_INT_I2CDONE) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
-		wake_up(&mantis->i2c_wq);
-	}
-	mmwrite(stat, MANTIS_INT_STAT);
-	stat &= ~(MANTIS_INT_RISCEN   | MANTIS_INT_I2CDONE |
-		  MANTIS_INT_I2CRACK  | MANTIS_INT_PCMCIA7 |
-		  MANTIS_INT_PCMCIA6  | MANTIS_INT_PCMCIA5 |
-		  MANTIS_INT_PCMCIA4  | MANTIS_INT_PCMCIA3 |
-		  MANTIS_INT_PCMCIA2  | MANTIS_INT_PCMCIA1 |
-		  MANTIS_INT_PCMCIA0  | MANTIS_INT_IRQ1	   |
-		  MANTIS_INT_IRQ0     | MANTIS_INT_OCERR   |
-		  MANTIS_INT_PABORT   | MANTIS_INT_RIPERR  |
-		  MANTIS_INT_PPERR    | MANTIS_INT_FTRGT   |
-		  MANTIS_INT_RISCI);
-
-	if (stat)
-		dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask);
-
-	dprintk(MANTIS_DEBUG, 0, "\n");
-	return IRQ_HANDLED;
-}
-
-static int __devinit hopper_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
-{
-	struct mantis_pci *mantis;
-	struct mantis_hwconfig *config;
-	int err = 0;
-
-	mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL);
-	if (mantis == NULL) {
-		printk(KERN_ERR "%s ERROR: Out of memory\n", __func__);
-		err = -ENOMEM;
-		goto fail0;
-	}
-
-	mantis->num		= devs;
-	mantis->verbose		= verbose;
-	mantis->pdev		= pdev;
-	config			= (struct mantis_hwconfig *) pci_id->driver_data;
-	config->irq_handler	= &hopper_irq_handler;
-	mantis->hwconfig	= config;
-
-	err = mantis_pci_init(mantis);
-	if (err) {
-		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err);
-		goto fail1;
-	}
-
-	err = mantis_stream_control(mantis, STREAM_TO_HIF);
-	if (err < 0) {
-		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err);
-		goto fail1;
-	}
-
-	err = mantis_i2c_init(mantis);
-	if (err < 0) {
-		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err);
-		goto fail2;
-	}
-
-	err = mantis_get_mac(mantis);
-	if (err < 0) {
-		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err);
-		goto fail2;
-	}
-
-	err = mantis_dma_init(mantis);
-	if (err < 0) {
-		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err);
-		goto fail3;
-	}
-
-	err = mantis_dvb_init(mantis);
-	if (err < 0) {
-		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err);
-		goto fail4;
-	}
-	devs++;
-
-	return err;
-
-fail4:
-	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err);
-	mantis_dma_exit(mantis);
-
-fail3:
-	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err);
-	mantis_i2c_exit(mantis);
-
-fail2:
-	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err);
-	mantis_pci_exit(mantis);
-
-fail1:
-	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err);
-	kfree(mantis);
-
-fail0:
-	return err;
-}
-
-static void __devexit hopper_pci_remove(struct pci_dev *pdev)
-{
-	struct mantis_pci *mantis = pci_get_drvdata(pdev);
-
-	if (mantis) {
-		mantis_dvb_exit(mantis);
-		mantis_dma_exit(mantis);
-		mantis_i2c_exit(mantis);
-		mantis_pci_exit(mantis);
-		kfree(mantis);
-	}
-	return;
-
-}
-
-static struct pci_device_id hopper_pci_table[] = {
-	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config),
-	{ }
-};
-
-MODULE_DEVICE_TABLE(pci, hopper_pci_table);
-
-static struct pci_driver hopper_pci_driver = {
-	.name		= DRIVER_NAME,
-	.id_table	= hopper_pci_table,
-	.probe		= hopper_pci_probe,
-	.remove		= hopper_pci_remove,
-};
-
-static int __devinit hopper_init(void)
-{
-	return pci_register_driver(&hopper_pci_driver);
-}
-
-static void __devexit hopper_exit(void)
-{
-	return pci_unregister_driver(&hopper_pci_driver);
-}
-
-module_init(hopper_init);
-module_exit(hopper_exit);
-
-MODULE_DESCRIPTION("HOPPER driver");
-MODULE_AUTHOR("Manu Abraham");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/mantis/hopper_vp3028.c b/drivers/media/dvb/mantis/hopper_vp3028.c
deleted file mode 100644
index 68a29f8..0000000
--- a/drivers/media/dvb/mantis/hopper_vp3028.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
-	Hopper VP-3028 driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "zl10353.h"
-#include "mantis_common.h"
-#include "mantis_ioc.h"
-#include "mantis_dvb.h"
-#include "hopper_vp3028.h"
-
-struct zl10353_config hopper_vp3028_config = {
-	.demod_address	= 0x0f,
-};
-
-#define MANTIS_MODEL_NAME	"VP-3028"
-#define MANTIS_DEV_TYPE		"DVB-T"
-
-static int vp3028_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
-{
-	struct i2c_adapter *adapter	= &mantis->adapter;
-	struct mantis_hwconfig *config	= mantis->hwconfig;
-	int err = 0;
-
-	mantis_gpio_set_bits(mantis, config->reset, 0);
-	msleep(100);
-	err = mantis_frontend_power(mantis, POWER_ON);
-	msleep(100);
-	mantis_gpio_set_bits(mantis, config->reset, 1);
-
-	err = mantis_frontend_power(mantis, POWER_ON);
-	if (err == 0) {
-		msleep(250);
-		dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)");
-		fe = dvb_attach(zl10353_attach, &hopper_vp3028_config, adapter);
-
-		if (!fe)
-			return -1;
-	} else {
-		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
-			adapter->name,
-			err);
-
-		return -EIO;
-	}
-	dprintk(MANTIS_ERROR, 1, "Done!");
-
-	return 0;
-}
-
-struct mantis_hwconfig vp3028_config = {
-	.model_name	= MANTIS_MODEL_NAME,
-	.dev_type	= MANTIS_DEV_TYPE,
-	.ts_size	= MANTIS_TS_188,
-
-	.baud_rate	= MANTIS_BAUD_9600,
-	.parity		= MANTIS_PARITY_NONE,
-	.bytes		= 0,
-
-	.frontend_init	= vp3028_frontend_init,
-	.power		= GPIF_A00,
-	.reset		= GPIF_A03,
-};
diff --git a/drivers/media/dvb/mantis/hopper_vp3028.h b/drivers/media/dvb/mantis/hopper_vp3028.h
deleted file mode 100644
index 5723949..0000000
--- a/drivers/media/dvb/mantis/hopper_vp3028.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-	Hopper VP-3028 driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_VP3028_H
-#define __MANTIS_VP3028_H
-
-#include "mantis_common.h"
-
-#define MANTIS_VP_3028_DVB_T	0x0028
-
-extern struct mantis_hwconfig vp3028_config;
-
-#endif /* __MANTIS_VP3028_H */
diff --git a/drivers/media/dvb/mantis/mantis_ca.c b/drivers/media/dvb/mantis/mantis_ca.c
deleted file mode 100644
index 3d70469..0000000
--- a/drivers/media/dvb/mantis/mantis_ca.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/signal.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "mantis_common.h"
-#include "mantis_link.h"
-#include "mantis_hif.h"
-#include "mantis_reg.h"
-
-#include "mantis_ca.h"
-
-static int mantis_ca_read_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr)
-{
-	struct mantis_ca *ca = en50221->data;
-	struct mantis_pci *mantis = ca->ca_priv;
-
-	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Read", slot);
-
-	if (slot != 0)
-		return -EINVAL;
-
-	return mantis_hif_read_mem(ca, addr);
-}
-
-static int mantis_ca_write_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr, u8 data)
-{
-	struct mantis_ca *ca = en50221->data;
-	struct mantis_pci *mantis = ca->ca_priv;
-
-	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Write", slot);
-
-	if (slot != 0)
-		return -EINVAL;
-
-	return mantis_hif_write_mem(ca, addr, data);
-}
-
-static int mantis_ca_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr)
-{
-	struct mantis_ca *ca = en50221->data;
-	struct mantis_pci *mantis = ca->ca_priv;
-
-	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Read", slot);
-
-	if (slot != 0)
-		return -EINVAL;
-
-	return mantis_hif_read_iom(ca, addr);
-}
-
-static int mantis_ca_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr, u8 data)
-{
-	struct mantis_ca *ca = en50221->data;
-	struct mantis_pci *mantis = ca->ca_priv;
-
-	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Write", slot);
-
-	if (slot != 0)
-		return -EINVAL;
-
-	return mantis_hif_write_iom(ca, addr, data);
-}
-
-static int mantis_ca_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
-{
-	struct mantis_ca *ca = en50221->data;
-	struct mantis_pci *mantis = ca->ca_priv;
-
-	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot RESET", slot);
-	udelay(500); /* Wait.. */
-	mmwrite(0xda, MANTIS_PCMCIA_RESET); /* Leading edge assert */
-	udelay(500);
-	mmwrite(0x00, MANTIS_PCMCIA_RESET); /* Trailing edge deassert */
-	msleep(1000);
-	dvb_ca_en50221_camready_irq(&ca->en50221, 0);
-
-	return 0;
-}
-
-static int mantis_ca_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
-{
-	struct mantis_ca *ca = en50221->data;
-	struct mantis_pci *mantis = ca->ca_priv;
-
-	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot shutdown", slot);
-
-	return 0;
-}
-
-static int mantis_ts_control(struct dvb_ca_en50221 *en50221, int slot)
-{
-	struct mantis_ca *ca = en50221->data;
-	struct mantis_pci *mantis = ca->ca_priv;
-
-	dprintk(MANTIS_DEBUG, 1, "Slot(%d): TS control", slot);
-/*	mantis_set_direction(mantis, 1); */ /* Enable TS through CAM */
-
-	return 0;
-}
-
-static int mantis_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open)
-{
-	struct mantis_ca *ca = en50221->data;
-	struct mantis_pci *mantis = ca->ca_priv;
-
-	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Poll Slot status", slot);
-
-	if (ca->slot_state == MODULE_INSERTED) {
-		dprintk(MANTIS_DEBUG, 1, "CA Module present and ready");
-		return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
-	} else {
-		dprintk(MANTIS_DEBUG, 1, "CA Module not present or not ready");
-	}
-
-	return 0;
-}
-
-int mantis_ca_init(struct mantis_pci *mantis)
-{
-	struct dvb_adapter *dvb_adapter	= &mantis->dvb_adapter;
-	struct mantis_ca *ca;
-	int ca_flags = 0, result;
-
-	dprintk(MANTIS_DEBUG, 1, "Initializing Mantis CA");
-	ca = kzalloc(sizeof(struct mantis_ca), GFP_KERNEL);
-	if (!ca) {
-		dprintk(MANTIS_ERROR, 1, "Out of memory!, exiting ..");
-		result = -ENOMEM;
-		goto err;
-	}
-
-	ca->ca_priv		= mantis;
-	mantis->mantis_ca	= ca;
-	ca_flags		= DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE;
-	/* register CA interface */
-	ca->en50221.owner		= THIS_MODULE;
-	ca->en50221.read_attribute_mem	= mantis_ca_read_attr_mem;
-	ca->en50221.write_attribute_mem	= mantis_ca_write_attr_mem;
-	ca->en50221.read_cam_control	= mantis_ca_read_cam_ctl;
-	ca->en50221.write_cam_control	= mantis_ca_write_cam_ctl;
-	ca->en50221.slot_reset		= mantis_ca_slot_reset;
-	ca->en50221.slot_shutdown	= mantis_ca_slot_shutdown;
-	ca->en50221.slot_ts_enable	= mantis_ts_control;
-	ca->en50221.poll_slot_status	= mantis_slot_status;
-	ca->en50221.data		= ca;
-
-	mutex_init(&ca->ca_lock);
-
-	init_waitqueue_head(&ca->hif_data_wq);
-	init_waitqueue_head(&ca->hif_opdone_wq);
-	init_waitqueue_head(&ca->hif_write_wq);
-
-	dprintk(MANTIS_ERROR, 1, "Registering EN50221 device");
-	result = dvb_ca_en50221_init(dvb_adapter, &ca->en50221, ca_flags, 1);
-	if (result != 0) {
-		dprintk(MANTIS_ERROR, 1, "EN50221: Initialization failed <%d>", result);
-		goto err;
-	}
-	dprintk(MANTIS_ERROR, 1, "Registered EN50221 device");
-	mantis_evmgr_init(ca);
-	return 0;
-err:
-	kfree(ca);
-	return result;
-}
-EXPORT_SYMBOL_GPL(mantis_ca_init);
-
-void mantis_ca_exit(struct mantis_pci *mantis)
-{
-	struct mantis_ca *ca = mantis->mantis_ca;
-
-	dprintk(MANTIS_DEBUG, 1, "Mantis CA exit");
-
-	mantis_evmgr_exit(ca);
-	dprintk(MANTIS_ERROR, 1, "Unregistering EN50221 device");
-	if (ca)
-		dvb_ca_en50221_release(&ca->en50221);
-
-	kfree(ca);
-}
-EXPORT_SYMBOL_GPL(mantis_ca_exit);
diff --git a/drivers/media/dvb/mantis/mantis_ca.h b/drivers/media/dvb/mantis/mantis_ca.h
deleted file mode 100644
index dc63e55..0000000
--- a/drivers/media/dvb/mantis/mantis_ca.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_CA_H
-#define __MANTIS_CA_H
-
-extern int mantis_ca_init(struct mantis_pci *mantis);
-extern void mantis_ca_exit(struct mantis_pci *mantis);
-
-#endif /* __MANTIS_CA_H */
diff --git a/drivers/media/dvb/mantis/mantis_cards.c b/drivers/media/dvb/mantis/mantis_cards.c
deleted file mode 100644
index 095cf3a..0000000
--- a/drivers/media/dvb/mantis/mantis_cards.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <asm/irq.h>
-#include <linux/interrupt.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "mantis_common.h"
-
-#include "mantis_vp1033.h"
-#include "mantis_vp1034.h"
-#include "mantis_vp1041.h"
-#include "mantis_vp2033.h"
-#include "mantis_vp2040.h"
-#include "mantis_vp3030.h"
-
-#include "mantis_dma.h"
-#include "mantis_ca.h"
-#include "mantis_dvb.h"
-#include "mantis_uart.h"
-#include "mantis_ioc.h"
-#include "mantis_pci.h"
-#include "mantis_i2c.h"
-#include "mantis_reg.h"
-
-static unsigned int verbose;
-module_param(verbose, int, 0644);
-MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)");
-
-static int devs;
-
-#define DRIVER_NAME	"Mantis"
-
-static char *label[10] = {
-	"DMA",
-	"IRQ-0",
-	"IRQ-1",
-	"OCERR",
-	"PABRT",
-	"RIPRR",
-	"PPERR",
-	"FTRGT",
-	"RISCI",
-	"RACK"
-};
-
-static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
-{
-	u32 stat = 0, mask = 0;
-	u32 rst_stat = 0, rst_mask = 0;
-
-	struct mantis_pci *mantis;
-	struct mantis_ca *ca;
-
-	mantis = (struct mantis_pci *) dev_id;
-	if (unlikely(mantis == NULL)) {
-		dprintk(MANTIS_ERROR, 1, "Mantis == NULL");
-		return IRQ_NONE;
-	}
-	ca = mantis->mantis_ca;
-
-	stat = mmread(MANTIS_INT_STAT);
-	mask = mmread(MANTIS_INT_MASK);
-	if (!(stat & mask))
-		return IRQ_NONE;
-
-	rst_mask  = MANTIS_GPIF_WRACK  |
-		    MANTIS_GPIF_OTHERR |
-		    MANTIS_SBUF_WSTO   |
-		    MANTIS_GPIF_EXTIRQ;
-
-	rst_stat  = mmread(MANTIS_GPIF_STATUS);
-	rst_stat &= rst_mask;
-	mmwrite(rst_stat, MANTIS_GPIF_STATUS);
-
-	mantis->mantis_int_stat = stat;
-	mantis->mantis_int_mask = mask;
-	dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask);
-	if (stat & MANTIS_INT_RISCEN) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]);
-	}
-	if (stat & MANTIS_INT_IRQ0) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]);
-		mantis->gpif_status = rst_stat;
-		wake_up(&ca->hif_write_wq);
-		schedule_work(&ca->hif_evm_work);
-	}
-	if (stat & MANTIS_INT_IRQ1) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]);
-		schedule_work(&mantis->uart_work);
-	}
-	if (stat & MANTIS_INT_OCERR) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]);
-	}
-	if (stat & MANTIS_INT_PABORT) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]);
-	}
-	if (stat & MANTIS_INT_RIPERR) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]);
-	}
-	if (stat & MANTIS_INT_PPERR) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]);
-	}
-	if (stat & MANTIS_INT_FTRGT) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]);
-	}
-	if (stat & MANTIS_INT_RISCI) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
-		mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
-		tasklet_schedule(&mantis->tasklet);
-	}
-	if (stat & MANTIS_INT_I2CDONE) {
-		dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
-		wake_up(&mantis->i2c_wq);
-	}
-	mmwrite(stat, MANTIS_INT_STAT);
-	stat &= ~(MANTIS_INT_RISCEN   | MANTIS_INT_I2CDONE |
-		  MANTIS_INT_I2CRACK  | MANTIS_INT_PCMCIA7 |
-		  MANTIS_INT_PCMCIA6  | MANTIS_INT_PCMCIA5 |
-		  MANTIS_INT_PCMCIA4  | MANTIS_INT_PCMCIA3 |
-		  MANTIS_INT_PCMCIA2  | MANTIS_INT_PCMCIA1 |
-		  MANTIS_INT_PCMCIA0  | MANTIS_INT_IRQ1	   |
-		  MANTIS_INT_IRQ0     | MANTIS_INT_OCERR   |
-		  MANTIS_INT_PABORT   | MANTIS_INT_RIPERR  |
-		  MANTIS_INT_PPERR    | MANTIS_INT_FTRGT   |
-		  MANTIS_INT_RISCI);
-
-	if (stat)
-		dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask);
-
-	dprintk(MANTIS_DEBUG, 0, "\n");
-	return IRQ_HANDLED;
-}
-
-static int __devinit mantis_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
-{
-	struct mantis_pci *mantis;
-	struct mantis_hwconfig *config;
-	int err = 0;
-
-	mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL);
-	if (mantis == NULL) {
-		printk(KERN_ERR "%s ERROR: Out of memory\n", __func__);
-		err = -ENOMEM;
-		goto fail0;
-	}
-
-	mantis->num		= devs;
-	mantis->verbose		= verbose;
-	mantis->pdev		= pdev;
-	config			= (struct mantis_hwconfig *) pci_id->driver_data;
-	config->irq_handler	= &mantis_irq_handler;
-	mantis->hwconfig	= config;
-
-	err = mantis_pci_init(mantis);
-	if (err) {
-		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err);
-		goto fail1;
-	}
-
-	err = mantis_stream_control(mantis, STREAM_TO_HIF);
-	if (err < 0) {
-		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err);
-		goto fail1;
-	}
-
-	err = mantis_i2c_init(mantis);
-	if (err < 0) {
-		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err);
-		goto fail2;
-	}
-
-	err = mantis_get_mac(mantis);
-	if (err < 0) {
-		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err);
-		goto fail2;
-	}
-
-	err = mantis_dma_init(mantis);
-	if (err < 0) {
-		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err);
-		goto fail3;
-	}
-
-	err = mantis_dvb_init(mantis);
-	if (err < 0) {
-		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err);
-		goto fail4;
-	}
-	err = mantis_uart_init(mantis);
-	if (err < 0) {
-		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART initialization failed <%d>", err);
-		goto fail6;
-	}
-
-	devs++;
-
-	return err;
-
-
-	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART exit! <%d>", err);
-	mantis_uart_exit(mantis);
-
-fail6:
-fail4:
-	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err);
-	mantis_dma_exit(mantis);
-
-fail3:
-	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err);
-	mantis_i2c_exit(mantis);
-
-fail2:
-	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err);
-	mantis_pci_exit(mantis);
-
-fail1:
-	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err);
-	kfree(mantis);
-
-fail0:
-	return err;
-}
-
-static void __devexit mantis_pci_remove(struct pci_dev *pdev)
-{
-	struct mantis_pci *mantis = pci_get_drvdata(pdev);
-
-	if (mantis) {
-
-		mantis_uart_exit(mantis);
-		mantis_dvb_exit(mantis);
-		mantis_dma_exit(mantis);
-		mantis_i2c_exit(mantis);
-		mantis_pci_exit(mantis);
-		kfree(mantis);
-	}
-	return;
-}
-
-static struct pci_device_id mantis_pci_table[] = {
-	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config),
-	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config),
-	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config),
-	MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config),
-	MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config),
-	MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config),
-	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config),
-	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config),
-	MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config),
-	MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2033_config),
-	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config),
-	{ }
-};
-
-MODULE_DEVICE_TABLE(pci, mantis_pci_table);
-
-static struct pci_driver mantis_pci_driver = {
-	.name		= DRIVER_NAME,
-	.id_table	= mantis_pci_table,
-	.probe		= mantis_pci_probe,
-	.remove		= mantis_pci_remove,
-};
-
-static int __devinit mantis_init(void)
-{
-	return pci_register_driver(&mantis_pci_driver);
-}
-
-static void __devexit mantis_exit(void)
-{
-	return pci_unregister_driver(&mantis_pci_driver);
-}
-
-module_init(mantis_init);
-module_exit(mantis_exit);
-
-MODULE_DESCRIPTION("MANTIS driver");
-MODULE_AUTHOR("Manu Abraham");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/mantis/mantis_common.h b/drivers/media/dvb/mantis/mantis_common.h
deleted file mode 100644
index f2410cf..0000000
--- a/drivers/media/dvb/mantis/mantis_common.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_COMMON_H
-#define __MANTIS_COMMON_H
-
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-#include <linux/workqueue.h>
-
-#include "mantis_uart.h"
-
-#include "mantis_link.h"
-
-#define MANTIS_ERROR		0
-#define MANTIS_NOTICE		1
-#define MANTIS_INFO		2
-#define MANTIS_DEBUG		3
-#define MANTIS_TMG		9
-
-#define dprintk(y, z, format, arg...) do {								\
-	if (z) {											\
-		if	((mantis->verbose > MANTIS_ERROR) && (mantis->verbose > y))			\
-			printk(KERN_ERR "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);	\
-		else if	((mantis->verbose > MANTIS_NOTICE) && (mantis->verbose > y))			\
-			printk(KERN_NOTICE "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);	\
-		else if ((mantis->verbose > MANTIS_INFO) && (mantis->verbose > y))			\
-			printk(KERN_INFO "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);	\
-		else if ((mantis->verbose > MANTIS_DEBUG) && (mantis->verbose > y))			\
-			printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);	\
-		else if ((mantis->verbose > MANTIS_TMG) && (mantis->verbose > y))			\
-			printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);	\
-	} else {											\
-		if (mantis->verbose > y)								\
-			printk(format , ##arg);								\
-	}												\
-} while(0)
-
-#define mwrite(dat, addr)	writel((dat), addr)
-#define mread(addr)		readl(addr)
-
-#define mmwrite(dat, addr)	mwrite((dat), (mantis->mmio + (addr)))
-#define mmread(addr)		mread(mantis->mmio + (addr))
-
-#define MANTIS_TS_188		0
-#define MANTIS_TS_204		1
-
-#define TWINHAN_TECHNOLOGIES	0x1822
-#define MANTIS			0x4e35
-
-#define TECHNISAT		0x1ae4
-#define TERRATEC		0x153b
-
-#define MAKE_ENTRY(__subven, __subdev, __configptr) {			\
-		.vendor		= TWINHAN_TECHNOLOGIES,			\
-		.device		= MANTIS,				\
-		.subvendor	= (__subven),				\
-		.subdevice	= (__subdev),				\
-		.driver_data	= (unsigned long) (__configptr)		\
-}
-
-enum mantis_i2c_mode {
-	MANTIS_PAGE_MODE = 0,
-	MANTIS_BYTE_MODE,
-};
-
-struct mantis_pci;
-
-struct mantis_hwconfig {
-	char			*model_name;
-	char			*dev_type;
-	u32			ts_size;
-
-	enum mantis_baud	baud_rate;
-	enum mantis_parity	parity;
-	u32			bytes;
-
-	irqreturn_t (*irq_handler)(int irq, void *dev_id);
-	int (*frontend_init)(struct mantis_pci *mantis, struct dvb_frontend *fe);
-
-	u8			power;
-	u8			reset;
-
-	enum mantis_i2c_mode	i2c_mode;
-};
-
-struct mantis_pci {
-	unsigned int		verbose;
-
-	/*	PCI stuff		*/
-	u16			vendor_id;
-	u16			device_id;
-	u16			subsystem_vendor;
-	u16			subsystem_device;
-
-	u8			latency;
-
-	struct pci_dev		*pdev;
-
-	unsigned long		mantis_addr;
-	void __iomem		*mmio;
-
-	u8			irq;
-	u8			revision;
-
-	unsigned int		num;
-
-	/*	RISC Core		*/
-	u32			busy_block;
-	u32			last_block;
-	u8			*buf_cpu;
-	dma_addr_t		buf_dma;
-	u32			*risc_cpu;
-	dma_addr_t		risc_dma;
-
-	struct tasklet_struct	tasklet;
-
-	struct i2c_adapter	adapter;
-	int			i2c_rc;
-	wait_queue_head_t	i2c_wq;
-	struct mutex		i2c_lock;
-
-	/*	DVB stuff		*/
-	struct dvb_adapter	dvb_adapter;
-	struct dvb_frontend	*fe;
-	struct dvb_demux	demux;
-	struct dmxdev		dmxdev;
-	struct dmx_frontend	fe_hw;
-	struct dmx_frontend	fe_mem;
-	struct dvb_net		dvbnet;
-
-	u8			feeds;
-
-	struct mantis_hwconfig	*hwconfig;
-
-	u32			mantis_int_stat;
-	u32			mantis_int_mask;
-
-	/*	board specific		*/
-	u8			mac_address[8];
-	u32			sub_vendor_id;
-	u32			sub_device_id;
-
-	 /*	A12 A13 A14		*/
-	u32			gpio_status;
-
-	u32			gpif_status;
-
-	struct mantis_ca	*mantis_ca;
-
-	wait_queue_head_t	uart_wq;
-	struct work_struct	uart_work;
-	spinlock_t		uart_lock;
-
-	struct rc_dev		*rc;
-	char			input_name[80];
-	char			input_phys[80];
-};
-
-#define MANTIS_HIF_STATUS	(mantis->gpio_status)
-
-#endif /* __MANTIS_COMMON_H */
diff --git a/drivers/media/dvb/mantis/mantis_core.c b/drivers/media/dvb/mantis/mantis_core.c
deleted file mode 100644
index 22524a8..0000000
--- a/drivers/media/dvb/mantis/mantis_core.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "mantis_common.h"
-#include "mantis_core.h"
-#include "mantis_vp1033.h"
-#include "mantis_vp1034.h"
-#include "mantis_vp1041.h"
-#include "mantis_vp2033.h"
-#include "mantis_vp2040.h"
-#include "mantis_vp3030.h"
-
-static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
-{
-	int err;
-	struct i2c_msg msg[] = {
-		{
-			.addr = 0x50,
-			.flags = 0,
-			.buf = data,
-			.len = 1
-		}, {
-			.addr = 0x50,
-			.flags = I2C_M_RD,
-			.buf = data,
-			.len = length
-		},
-	};
-
-	err = i2c_transfer(&mantis->adapter, msg, 2);
-	if (err < 0) {
-		dprintk(verbose, MANTIS_ERROR, 1,
-			"ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >",
-			err, data[0], data[1]);
-
-		return err;
-	}
-
-	return 0;
-}
-
-static int write_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
-{
-	int err;
-
-	struct i2c_msg msg = {
-		.addr = 0x50,
-		.flags = 0,
-		.buf = data,
-		.len = length
-	};
-
-	err = i2c_transfer(&mantis->adapter, &msg, 1);
-	if (err < 0) {
-		dprintk(verbose, MANTIS_ERROR, 1,
-			"ERROR: i2c write: < err=%i length=0x%02x d0=0x%02x, d1=0x%02x >",
-			err, length, data[0], data[1]);
-
-		return err;
-	}
-
-	return 0;
-}
-
-static int get_mac_address(struct mantis_pci *mantis)
-{
-	int err;
-
-	mantis->mac_address[0] = 0x08;
-	err = read_eeprom_byte(mantis, &mantis->mac_address[0], 6);
-	if (err < 0) {
-		dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error");
-
-		return err;
-	}
-	dprintk(verbose, MANTIS_ERROR, 0,
-		"    MAC Address=[%pM]\n", mantis->mac_address);
-
-	return 0;
-}
-
-#define MANTIS_MODEL_UNKNOWN	"UNKNOWN"
-#define MANTIS_DEV_UNKNOWN	"UNKNOWN"
-
-struct mantis_hwconfig unknown_device = {
-	.model_name	= MANTIS_MODEL_UNKNOWN,
-	.dev_type	= MANTIS_DEV_UNKNOWN,
-};
-
-static void mantis_load_config(struct mantis_pci *mantis)
-{
-	switch (mantis->subsystem_device) {
-	case MANTIS_VP_1033_DVB_S:	/* VP-1033 */
-		mantis->hwconfig = &vp1033_mantis_config;
-		break;
-	case MANTIS_VP_1034_DVB_S:	/* VP-1034 */
-		mantis->hwconfig = &vp1034_mantis_config;
-		break;
-	case MANTIS_VP_1041_DVB_S2:	/* VP-1041 */
-	case TECHNISAT_SKYSTAR_HD2:
-		mantis->hwconfig = &vp1041_mantis_config;
-		break;
-	case MANTIS_VP_2033_DVB_C:	/* VP-2033 */
-		mantis->hwconfig = &vp2033_mantis_config;
-		break;
-	case MANTIS_VP_2040_DVB_C:	/* VP-2040 */
-	case TERRATEC_CINERGY_C_PCI:	/* VP-2040 clone */
-	case TECHNISAT_CABLESTAR_HD2:
-		mantis->hwconfig = &vp2040_mantis_config;
-		break;
-	case MANTIS_VP_3030_DVB_T:	/* VP-3030 */
-		mantis->hwconfig = &vp3030_mantis_config;
-		break;
-	default:
-		mantis->hwconfig = &unknown_device;
-		break;
-	}
-}
-
-int mantis_core_init(struct mantis_pci *mantis)
-{
-	int err = 0;
-
-	mantis_load_config(mantis);
-	dprintk(verbose, MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n",
-		mantis->hwconfig->model_name, mantis->hwconfig->dev_type,
-		mantis->pdev->bus->number, PCI_SLOT(mantis->pdev->devfn), PCI_FUNC(mantis->pdev->devfn));
-	dprintk(verbose, MANTIS_ERROR, 0, "    Mantis Rev %d [%04x:%04x], ",
-		mantis->revision,
-		mantis->subsystem_vendor, mantis->subsystem_device);
-	dprintk(verbose, MANTIS_ERROR, 0,
-		"irq: %d, latency: %d\n    memory: 0x%lx, mmio: 0x%p\n",
-		mantis->pdev->irq, mantis->latency,
-		mantis->mantis_addr, mantis->mantis_mmio);
-
-	err = mantis_i2c_init(mantis);
-	if (err < 0) {
-		dprintk(verbose, MANTIS_ERROR, 1, "Mantis I2C init failed");
-		return err;
-	}
-	err = get_mac_address(mantis);
-	if (err < 0) {
-		dprintk(verbose, MANTIS_ERROR, 1, "get MAC address failed");
-		return err;
-	}
-	err = mantis_dma_init(mantis);
-	if (err < 0) {
-		dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA init failed");
-		return err;
-	}
-	err = mantis_dvb_init(mantis);
-	if (err < 0) {
-		dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB init failed");
-		return err;
-	}
-	err = mantis_uart_init(mantis);
-	if (err < 0) {
-		dprintk(verbose, MANTIS_DEBUG, 1, "Mantis UART init failed");
-		return err;
-	}
-
-	return 0;
-}
-
-int mantis_core_exit(struct mantis_pci *mantis)
-{
-	mantis_dma_stop(mantis);
-	dprintk(verbose, MANTIS_ERROR, 1, "DMA engine stopping");
-
-	mantis_uart_exit(mantis);
-	dprintk(verbose, MANTIS_ERROR, 1, "UART exit failed");
-
-	if (mantis_dma_exit(mantis) < 0)
-		dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed");
-	if (mantis_dvb_exit(mantis) < 0)
-		dprintk(verbose, MANTIS_ERROR, 1, "DVB exit failed");
-	if (mantis_i2c_exit(mantis) < 0)
-		dprintk(verbose, MANTIS_ERROR, 1, "I2C adapter delete.. failed");
-
-	return 0;
-}
-
-/* Turn the given bit on or off. */
-void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
-{
-	u32 cur;
-
-	cur = mmread(MANTIS_GPIF_ADDR);
-	if (value)
-		mantis->gpio_status = cur | (1 << bitpos);
-	else
-		mantis->gpio_status = cur & (~(1 << bitpos));
-
-	mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR);
-	mmwrite(0x00, MANTIS_GPIF_DOUT);
-	udelay(100);
-}
-
-/* direction = 0 , no CI passthrough ; 1 , CI passthrough */
-void mantis_set_direction(struct mantis_pci *mantis, int direction)
-{
-	u32 reg;
-
-	reg = mmread(0x28);
-	dprintk(verbose, MANTIS_DEBUG, 1, "TS direction setup");
-	if (direction == 0x01) {
-		/* to CI */
-		reg |= 0x04;
-		mmwrite(reg, 0x28);
-		reg &= 0xff - 0x04;
-		mmwrite(reg, 0x28);
-	} else {
-		reg &= 0xff - 0x04;
-		mmwrite(reg, 0x28);
-		reg |= 0x04;
-		mmwrite(reg, 0x28);
-	}
-}
diff --git a/drivers/media/dvb/mantis/mantis_core.h b/drivers/media/dvb/mantis/mantis_core.h
deleted file mode 100644
index 833ee42..0000000
--- a/drivers/media/dvb/mantis/mantis_core.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_CORE_H
-#define __MANTIS_CORE_H
-
-#include "mantis_common.h"
-
-
-#define FE_TYPE_SAT	0
-#define FE_TYPE_CAB	1
-#define FE_TYPE_TER	2
-
-#define FE_TYPE_TS204	0
-#define FE_TYPE_TS188	1
-
-
-struct vendorname {
-	u8  *sub_vendor_name;
-	u32 sub_vendor_id;
-};
-
-struct devicetype {
-	u8  *sub_device_name;
-	u32 sub_device_id;
-	u8  device_type;
-	u32 type_flags;
-};
-
-
-extern int mantis_dma_init(struct mantis_pci *mantis);
-extern int mantis_dma_exit(struct mantis_pci *mantis);
-extern void mantis_dma_start(struct mantis_pci *mantis);
-extern void mantis_dma_stop(struct mantis_pci *mantis);
-extern int mantis_i2c_init(struct mantis_pci *mantis);
-extern int mantis_i2c_exit(struct mantis_pci *mantis);
-extern int mantis_core_init(struct mantis_pci *mantis);
-extern int mantis_core_exit(struct mantis_pci *mantis);
-
-#endif /* __MANTIS_CORE_H */
diff --git a/drivers/media/dvb/mantis/mantis_dma.c b/drivers/media/dvb/mantis/mantis_dma.c
deleted file mode 100644
index 566c407..0000000
--- a/drivers/media/dvb/mantis/mantis_dma.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/kernel.h>
-#include <asm/page.h>
-#include <linux/vmalloc.h>
-#include <linux/pci.h>
-
-#include <asm/irq.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "mantis_common.h"
-#include "mantis_reg.h"
-#include "mantis_dma.h"
-
-#define RISC_WRITE		(0x01 << 28)
-#define RISC_JUMP		(0x07 << 28)
-#define RISC_IRQ		(0x01 << 24)
-
-#define RISC_STATUS(status)	((((~status) & 0x0f) << 20) | ((status & 0x0f) << 16))
-#define RISC_FLUSH(risc_pos)		(risc_pos = 0)
-#define RISC_INSTR(risc_pos, opcode)	(mantis->risc_cpu[risc_pos++] = cpu_to_le32(opcode))
-
-#define MANTIS_BUF_SIZE		(64 * 1024)
-#define MANTIS_BLOCK_BYTES      (MANTIS_BUF_SIZE / 4)
-#define MANTIS_DMA_TR_BYTES     (2 * 1024) /* upper limit: 4095 bytes. */
-#define MANTIS_BLOCK_COUNT	(MANTIS_BUF_SIZE / MANTIS_BLOCK_BYTES)
-
-#define MANTIS_DMA_TR_UNITS     (MANTIS_BLOCK_BYTES / MANTIS_DMA_TR_BYTES)
-/* MANTIS_BUF_SIZE / MANTIS_DMA_TR_UNITS must not exceed MANTIS_RISC_SIZE (4k RISC cmd buffer) */
-#define MANTIS_RISC_SIZE	PAGE_SIZE /* RISC program must fit here. */
-
-int mantis_dma_exit(struct mantis_pci *mantis)
-{
-	if (mantis->buf_cpu) {
-		dprintk(MANTIS_ERROR, 1,
-			"DMA=0x%lx cpu=0x%p size=%d",
-			(unsigned long) mantis->buf_dma,
-			 mantis->buf_cpu,
-			 MANTIS_BUF_SIZE);
-
-		pci_free_consistent(mantis->pdev, MANTIS_BUF_SIZE,
-				    mantis->buf_cpu, mantis->buf_dma);
-
-		mantis->buf_cpu = NULL;
-	}
-	if (mantis->risc_cpu) {
-		dprintk(MANTIS_ERROR, 1,
-			"RISC=0x%lx cpu=0x%p size=%lx",
-			(unsigned long) mantis->risc_dma,
-			mantis->risc_cpu,
-			MANTIS_RISC_SIZE);
-
-		pci_free_consistent(mantis->pdev, MANTIS_RISC_SIZE,
-				    mantis->risc_cpu, mantis->risc_dma);
-
-		mantis->risc_cpu = NULL;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(mantis_dma_exit);
-
-static inline int mantis_alloc_buffers(struct mantis_pci *mantis)
-{
-	if (!mantis->buf_cpu) {
-		mantis->buf_cpu = pci_alloc_consistent(mantis->pdev,
-						       MANTIS_BUF_SIZE,
-						       &mantis->buf_dma);
-		if (!mantis->buf_cpu) {
-			dprintk(MANTIS_ERROR, 1,
-				"DMA buffer allocation failed");
-
-			goto err;
-		}
-		dprintk(MANTIS_ERROR, 1,
-			"DMA=0x%lx cpu=0x%p size=%d",
-			(unsigned long) mantis->buf_dma,
-			mantis->buf_cpu, MANTIS_BUF_SIZE);
-	}
-	if (!mantis->risc_cpu) {
-		mantis->risc_cpu = pci_alloc_consistent(mantis->pdev,
-							MANTIS_RISC_SIZE,
-							&mantis->risc_dma);
-
-		if (!mantis->risc_cpu) {
-			dprintk(MANTIS_ERROR, 1,
-				"RISC program allocation failed");
-
-			mantis_dma_exit(mantis);
-
-			goto err;
-		}
-		dprintk(MANTIS_ERROR, 1,
-			"RISC=0x%lx cpu=0x%p size=%lx",
-			(unsigned long) mantis->risc_dma,
-			mantis->risc_cpu, MANTIS_RISC_SIZE);
-	}
-
-	return 0;
-err:
-	dprintk(MANTIS_ERROR, 1, "Out of memory (?) .....");
-	return -ENOMEM;
-}
-
-int mantis_dma_init(struct mantis_pci *mantis)
-{
-	int err = 0;
-
-	dprintk(MANTIS_DEBUG, 1, "Mantis DMA init");
-	if (mantis_alloc_buffers(mantis) < 0) {
-		dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer");
-
-		/* Stop RISC Engine */
-		mmwrite(0, MANTIS_DMA_CTL);
-
-		goto err;
-	}
-
-	return 0;
-err:
-	return err;
-}
-EXPORT_SYMBOL_GPL(mantis_dma_init);
-
-static inline void mantis_risc_program(struct mantis_pci *mantis)
-{
-	u32 buf_pos = 0;
-	u32 line, step;
-	u32 risc_pos;
-
-	dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program");
-	RISC_FLUSH(risc_pos);
-
-	dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u, bytes per DMA tr %u",
-		MANTIS_BLOCK_COUNT, MANTIS_BLOCK_BYTES, MANTIS_DMA_TR_BYTES);
-
-	for (line = 0; line < MANTIS_BLOCK_COUNT; line++) {
-		for (step = 0; step < MANTIS_DMA_TR_UNITS; step++) {
-			dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d], step=[%d]", line, step);
-			if (step == 0) {
-				RISC_INSTR(risc_pos, RISC_WRITE	|
-					   RISC_IRQ	|
-					   RISC_STATUS(line) |
-					   MANTIS_DMA_TR_BYTES);
-			} else {
-				RISC_INSTR(risc_pos, RISC_WRITE | MANTIS_DMA_TR_BYTES);
-			}
-			RISC_INSTR(risc_pos, mantis->buf_dma + buf_pos);
-			buf_pos += MANTIS_DMA_TR_BYTES;
-		  }
-	}
-	RISC_INSTR(risc_pos, RISC_JUMP);
-	RISC_INSTR(risc_pos, mantis->risc_dma);
-}
-
-void mantis_dma_start(struct mantis_pci *mantis)
-{
-	dprintk(MANTIS_DEBUG, 1, "Mantis Start DMA engine");
-
-	mantis_risc_program(mantis);
-	mmwrite(mantis->risc_dma, MANTIS_RISC_START);
-	mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
-
-	mmwrite(0, MANTIS_DMA_CTL);
-	mantis->last_block = mantis->busy_block = 0;
-
-	mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK);
-
-	mmwrite(MANTIS_FIFO_EN | MANTIS_DCAP_EN
-			       | MANTIS_RISC_EN, MANTIS_DMA_CTL);
-
-}
-
-void mantis_dma_stop(struct mantis_pci *mantis)
-{
-	dprintk(MANTIS_DEBUG, 1, "Mantis Stop DMA engine");
-
-	mmwrite((mmread(MANTIS_GPIF_ADDR) & (~(MANTIS_GPIF_HIFRDWRN))), MANTIS_GPIF_ADDR);
-
-	mmwrite((mmread(MANTIS_DMA_CTL) & ~(MANTIS_FIFO_EN |
-					    MANTIS_DCAP_EN |
-					    MANTIS_RISC_EN)), MANTIS_DMA_CTL);
-
-	mmwrite(mmread(MANTIS_INT_STAT), MANTIS_INT_STAT);
-
-	mmwrite(mmread(MANTIS_INT_MASK) & ~(MANTIS_INT_RISCI |
-					    MANTIS_INT_RISCEN), MANTIS_INT_MASK);
-}
-
-
-void mantis_dma_xfer(unsigned long data)
-{
-	struct mantis_pci *mantis = (struct mantis_pci *) data;
-	struct mantis_hwconfig *config = mantis->hwconfig;
-
-	while (mantis->last_block != mantis->busy_block) {
-		dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]",
-			mantis->last_block, mantis->busy_block);
-
-		(config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter)
-		(&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES);
-		mantis->last_block = (mantis->last_block + 1) % MANTIS_BLOCK_COUNT;
-	}
-}
diff --git a/drivers/media/dvb/mantis/mantis_dma.h b/drivers/media/dvb/mantis/mantis_dma.h
deleted file mode 100644
index 6be00fa..0000000
--- a/drivers/media/dvb/mantis/mantis_dma.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_DMA_H
-#define __MANTIS_DMA_H
-
-extern int mantis_dma_init(struct mantis_pci *mantis);
-extern int mantis_dma_exit(struct mantis_pci *mantis);
-extern void mantis_dma_start(struct mantis_pci *mantis);
-extern void mantis_dma_stop(struct mantis_pci *mantis);
-extern void mantis_dma_xfer(unsigned long data);
-
-#endif /* __MANTIS_DMA_H */
diff --git a/drivers/media/dvb/mantis/mantis_dvb.c b/drivers/media/dvb/mantis/mantis_dvb.c
deleted file mode 100644
index e5180e4..0000000
--- a/drivers/media/dvb/mantis/mantis_dvb.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
-	Mantis PCI bridge driver
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/kernel.h>
-#include <linux/bitops.h>
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/i2c.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "mantis_common.h"
-#include "mantis_dma.h"
-#include "mantis_ca.h"
-#include "mantis_ioc.h"
-#include "mantis_dvb.h"
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power)
-{
-	struct mantis_hwconfig *config = mantis->hwconfig;
-
-	switch (power) {
-	case POWER_ON:
-		dprintk(MANTIS_DEBUG, 1, "Power ON");
-		mantis_gpio_set_bits(mantis, config->power, POWER_ON);
-		msleep(100);
-		mantis_gpio_set_bits(mantis, config->power, POWER_ON);
-		msleep(100);
-		break;
-
-	case POWER_OFF:
-		dprintk(MANTIS_DEBUG, 1, "Power OFF");
-		mantis_gpio_set_bits(mantis, config->power, POWER_OFF);
-		msleep(100);
-		break;
-
-	default:
-		dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power);
-		return -1;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(mantis_frontend_power);
-
-void mantis_frontend_soft_reset(struct mantis_pci *mantis)
-{
-	struct mantis_hwconfig *config = mantis->hwconfig;
-
-	dprintk(MANTIS_DEBUG, 1, "Frontend RESET");
-	mantis_gpio_set_bits(mantis, config->reset, 0);
-	msleep(100);
-	mantis_gpio_set_bits(mantis, config->reset, 0);
-	msleep(100);
-	mantis_gpio_set_bits(mantis, config->reset, 1);
-	msleep(100);
-	mantis_gpio_set_bits(mantis, config->reset, 1);
-	msleep(100);
-
-	return;
-}
-EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset);
-
-static int mantis_frontend_shutdown(struct mantis_pci *mantis)
-{
-	int err;
-
-	mantis_frontend_soft_reset(mantis);
-	err = mantis_frontend_power(mantis, POWER_OFF);
-	if (err != 0) {
-		dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err);
-		return 1;
-	}
-
-	return 0;
-}
-
-static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-	struct mantis_pci *mantis = dvbdmx->priv;
-
-	dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed");
-	if (!dvbdmx->dmx.frontend) {
-		dprintk(MANTIS_DEBUG, 1, "no frontend ?");
-		return -EINVAL;
-	}
-
-	mantis->feeds++;
-	dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d",	mantis->feeds);
-
-	if (mantis->feeds == 1)	 {
-		dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma");
-		mantis_dma_start(mantis);
-		tasklet_enable(&mantis->tasklet);
-	}
-
-	return mantis->feeds;
-}
-
-static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-	struct mantis_pci *mantis = dvbdmx->priv;
-
-	dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed");
-	if (!dvbdmx->dmx.frontend) {
-		dprintk(MANTIS_DEBUG, 1, "no frontend ?");
-		return -EINVAL;
-	}
-
-	mantis->feeds--;
-	if (mantis->feeds == 0) {
-		dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma");
-		tasklet_disable(&mantis->tasklet);
-		mantis_dma_stop(mantis);
-	}
-
-	return 0;
-}
-
-int __devinit mantis_dvb_init(struct mantis_pci *mantis)
-{
-	struct mantis_hwconfig *config = mantis->hwconfig;
-	int result = -1;
-
-	dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter");
-
-	result = dvb_register_adapter(&mantis->dvb_adapter,
-				      "Mantis DVB adapter",
-				      THIS_MODULE,
-				      &mantis->pdev->dev,
-				      adapter_nr);
-
-	if (result < 0) {
-
-		dprintk(MANTIS_ERROR, 1, "Error registering adapter");
-		return -ENODEV;
-	}
-
-	mantis->dvb_adapter.priv	= mantis;
-	mantis->demux.dmx.capabilities	= DMX_TS_FILTERING	|
-					 DMX_SECTION_FILTERING	|
-					 DMX_MEMORY_BASED_FILTERING;
-
-	mantis->demux.priv		= mantis;
-	mantis->demux.filternum		= 256;
-	mantis->demux.feednum		= 256;
-	mantis->demux.start_feed	= mantis_dvb_start_feed;
-	mantis->demux.stop_feed		= mantis_dvb_stop_feed;
-	mantis->demux.write_to_decoder	= NULL;
-
-	dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init");
-	result = dvb_dmx_init(&mantis->demux);
-	if (result < 0) {
-		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
-
-		goto err0;
-	}
-
-	mantis->dmxdev.filternum	= 256;
-	mantis->dmxdev.demux		= &mantis->demux.dmx;
-	mantis->dmxdev.capabilities	= 0;
-	dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init");
-
-	result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter);
-	if (result < 0) {
-
-		dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result);
-		goto err1;
-	}
-
-	mantis->fe_hw.source		= DMX_FRONTEND_0;
-	result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw);
-	if (result < 0) {
-
-		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
-		goto err2;
-	}
-
-	mantis->fe_mem.source		= DMX_MEMORY_FE;
-	result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem);
-	if (result < 0) {
-		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
-		goto err3;
-	}
-
-	result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw);
-	if (result < 0) {
-		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
-		goto err4;
-	}
-
-	dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);
-	tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis);
-	tasklet_disable(&mantis->tasklet);
-	if (mantis->hwconfig) {
-		result = config->frontend_init(mantis, mantis->fe);
-		if (result < 0) {
-			dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!");
-			goto err5;
-		} else {
-			if (mantis->fe == NULL) {
-				dprintk(MANTIS_ERROR, 1, "FE <NULL>");
-				goto err5;
-			}
-
-			if (dvb_register_frontend(&mantis->dvb_adapter, mantis->fe)) {
-				dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed");
-
-				if (mantis->fe->ops.release)
-					mantis->fe->ops.release(mantis->fe);
-
-				mantis->fe = NULL;
-				goto err5;
-			}
-		}
-	}
-
-	return 0;
-
-	/* Error conditions ..	*/
-err5:
-	tasklet_kill(&mantis->tasklet);
-	dvb_net_release(&mantis->dvbnet);
-	dvb_unregister_frontend(mantis->fe);
-	dvb_frontend_detach(mantis->fe);
-err4:
-	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
-
-err3:
-	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
-
-err2:
-	dvb_dmxdev_release(&mantis->dmxdev);
-
-err1:
-	dvb_dmx_release(&mantis->demux);
-
-err0:
-	dvb_unregister_adapter(&mantis->dvb_adapter);
-
-	return result;
-}
-EXPORT_SYMBOL_GPL(mantis_dvb_init);
-
-int __devexit mantis_dvb_exit(struct mantis_pci *mantis)
-{
-	int err;
-
-	if (mantis->fe) {
-		/* mantis_ca_exit(mantis); */
-		err = mantis_frontend_shutdown(mantis);
-		if (err != 0)
-			dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err);
-		dvb_unregister_frontend(mantis->fe);
-		dvb_frontend_detach(mantis->fe);
-	}
-
-	tasklet_kill(&mantis->tasklet);
-	dvb_net_release(&mantis->dvbnet);
-
-	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
-	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
-
-	dvb_dmxdev_release(&mantis->dmxdev);
-	dvb_dmx_release(&mantis->demux);
-
-	dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter");
-	dvb_unregister_adapter(&mantis->dvb_adapter);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(mantis_dvb_exit);
diff --git a/drivers/media/dvb/mantis/mantis_dvb.h b/drivers/media/dvb/mantis/mantis_dvb.h
deleted file mode 100644
index 464199d..0000000
--- a/drivers/media/dvb/mantis/mantis_dvb.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_DVB_H
-#define __MANTIS_DVB_H
-
-enum mantis_power {
-	POWER_OFF	= 0,
-	POWER_ON	= 1
-};
-
-extern int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power);
-extern void mantis_frontend_soft_reset(struct mantis_pci *mantis);
-
-extern int mantis_dvb_init(struct mantis_pci *mantis);
-extern int mantis_dvb_exit(struct mantis_pci *mantis);
-
-#endif /* __MANTIS_DVB_H */
diff --git a/drivers/media/dvb/mantis/mantis_evm.c b/drivers/media/dvb/mantis/mantis_evm.c
deleted file mode 100644
index 71ce528..0000000
--- a/drivers/media/dvb/mantis/mantis_evm.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/kernel.h>
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "mantis_common.h"
-#include "mantis_link.h"
-#include "mantis_hif.h"
-#include "mantis_reg.h"
-
-static void mantis_hifevm_work(struct work_struct *work)
-{
-	struct mantis_ca *ca = container_of(work, struct mantis_ca, hif_evm_work);
-	struct mantis_pci *mantis = ca->ca_priv;
-
-	u32 gpif_stat;
-
-	gpif_stat = mmread(MANTIS_GPIF_STATUS);
-
-	if (gpif_stat & MANTIS_GPIF_DETSTAT) {
-		if (gpif_stat & MANTIS_CARD_PLUGIN) {
-			dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Plugin", mantis->num);
-			mmwrite(0xdada0000, MANTIS_CARD_RESET);
-			mantis_event_cam_plugin(ca);
-			dvb_ca_en50221_camchange_irq(&ca->en50221,
-						     0,
-						     DVB_CA_EN50221_CAMCHANGE_INSERTED);
-		}
-	} else {
-		if (gpif_stat & MANTIS_CARD_PLUGOUT) {
-			dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Unplug", mantis->num);
-			mmwrite(0xdada0000, MANTIS_CARD_RESET);
-			mantis_event_cam_unplug(ca);
-			dvb_ca_en50221_camchange_irq(&ca->en50221,
-						     0,
-						     DVB_CA_EN50221_CAMCHANGE_REMOVED);
-		}
-	}
-
-	if (mantis->gpif_status & MANTIS_GPIF_EXTIRQ)
-		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Ext IRQ", mantis->num);
-
-	if (mantis->gpif_status & MANTIS_SBUF_WSTO)
-		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Timeout", mantis->num);
-
-	if (mantis->gpif_status & MANTIS_GPIF_OTHERR)
-		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Alignment Error", mantis->num);
-
-	if (gpif_stat & MANTIS_SBUF_OVFLW)
-		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Overflow", mantis->num);
-
-	if (gpif_stat & MANTIS_GPIF_BRRDY)
-		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Read Ready", mantis->num);
-
-	if (gpif_stat & MANTIS_GPIF_INTSTAT)
-		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): GPIF IRQ", mantis->num);
-
-	if (gpif_stat & MANTIS_SBUF_EMPTY)
-		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Empty", mantis->num);
-
-	if (gpif_stat & MANTIS_SBUF_OPDONE) {
-		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer operation complete", mantis->num);
-		ca->sbuf_status = MANTIS_SBUF_DATA_AVAIL;
-		ca->hif_event = MANTIS_SBUF_OPDONE;
-		wake_up(&ca->hif_opdone_wq);
-	}
-}
-
-int mantis_evmgr_init(struct mantis_ca *ca)
-{
-	struct mantis_pci *mantis = ca->ca_priv;
-
-	dprintk(MANTIS_DEBUG, 1, "Initializing Mantis Host I/F Event manager");
-	INIT_WORK(&ca->hif_evm_work, mantis_hifevm_work);
-	mantis_pcmcia_init(ca);
-	schedule_work(&ca->hif_evm_work);
-	mantis_hif_init(ca);
-	return 0;
-}
-
-void mantis_evmgr_exit(struct mantis_ca *ca)
-{
-	struct mantis_pci *mantis = ca->ca_priv;
-
-	dprintk(MANTIS_DEBUG, 1, "Mantis Host I/F Event manager exiting");
-	flush_work_sync(&ca->hif_evm_work);
-	mantis_hif_exit(ca);
-	mantis_pcmcia_exit(ca);
-}
diff --git a/drivers/media/dvb/mantis/mantis_hif.c b/drivers/media/dvb/mantis/mantis_hif.c
deleted file mode 100644
index 10c68df..0000000
--- a/drivers/media/dvb/mantis/mantis_hif.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-
-#include <linux/interrupt.h>
-#include <asm/io.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "mantis_common.h"
-
-#include "mantis_hif.h"
-#include "mantis_link.h" /* temporary due to physical layer stuff */
-
-#include "mantis_reg.h"
-
-
-static int mantis_hif_sbuf_opdone_wait(struct mantis_ca *ca)
-{
-	struct mantis_pci *mantis = ca->ca_priv;
-	int rc = 0;
-
-	if (wait_event_timeout(ca->hif_opdone_wq,
-			       ca->hif_event & MANTIS_SBUF_OPDONE,
-			       msecs_to_jiffies(500)) == -ERESTARTSYS) {
-
-		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Smart buffer operation timeout !", mantis->num);
-		rc = -EREMOTEIO;
-	}
-	dprintk(MANTIS_DEBUG, 1, "Smart Buffer Operation complete");
-	ca->hif_event &= ~MANTIS_SBUF_OPDONE;
-	return rc;
-}
-
-static int mantis_hif_write_wait(struct mantis_ca *ca)
-{
-	struct mantis_pci *mantis = ca->ca_priv;
-	u32 opdone = 0, timeout = 0;
-	int rc = 0;
-
-	if (wait_event_timeout(ca->hif_write_wq,
-			       mantis->gpif_status & MANTIS_GPIF_WRACK,
-			       msecs_to_jiffies(500)) == -ERESTARTSYS) {
-
-		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write ACK timed out !", mantis->num);
-		rc = -EREMOTEIO;
-	}
-	dprintk(MANTIS_DEBUG, 1, "Write Acknowledged");
-	mantis->gpif_status &= ~MANTIS_GPIF_WRACK;
-	while (!opdone) {
-		opdone = (mmread(MANTIS_GPIF_STATUS) & MANTIS_SBUF_OPDONE);
-		udelay(500);
-		timeout++;
-		if (timeout > 100) {
-			dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write operation timed out!", mantis->num);
-			rc = -ETIMEDOUT;
-			break;
-		}
-	}
-	dprintk(MANTIS_DEBUG, 1, "HIF Write success");
-	return rc;
-}
-
-
-int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr)
-{
-	struct mantis_pci *mantis = ca->ca_priv;
-	u32 hif_addr = 0, data, count = 4;
-
-	dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Read", mantis->num);
-	mutex_lock(&ca->ca_lock);
-	hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
-	hif_addr &= ~MANTIS_GPIF_PCMCIAIOM;
-	hif_addr |=  MANTIS_HIF_STATUS;
-	hif_addr |=  addr;
-
-	mmwrite(hif_addr, MANTIS_GPIF_BRADDR);
-	mmwrite(count, MANTIS_GPIF_BRBYTES);
-	udelay(20);
-	mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
-
-	if (mantis_hif_sbuf_opdone_wait(ca) != 0) {
-		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): GPIF Smart Buffer operation failed", mantis->num);
-		mutex_unlock(&ca->ca_lock);
-		return -EREMOTEIO;
-	}
-	data = mmread(MANTIS_GPIF_DIN);
-	mutex_unlock(&ca->ca_lock);
-	dprintk(MANTIS_DEBUG, 1, "Mem Read: 0x%02x", data);
-	return (data >> 24) & 0xff;
-}
-
-int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data)
-{
-	struct mantis_slot *slot = ca->slot;
-	struct mantis_pci *mantis = ca->ca_priv;
-	u32 hif_addr = 0;
-
-	dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Write", mantis->num);
-	mutex_lock(&ca->ca_lock);
-	hif_addr &= ~MANTIS_GPIF_HIFRDWRN;
-	hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
-	hif_addr &= ~MANTIS_GPIF_PCMCIAIOM;
-	hif_addr |=  MANTIS_HIF_STATUS;
-	hif_addr |=  addr;
-
-	mmwrite(slot->slave_cfg, MANTIS_GPIF_CFGSLA); /* Slot0 alone for now */
-	mmwrite(hif_addr, MANTIS_GPIF_ADDR);
-	mmwrite(data, MANTIS_GPIF_DOUT);
-
-	if (mantis_hif_write_wait(ca) != 0) {
-		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
-		mutex_unlock(&ca->ca_lock);
-		return -EREMOTEIO;
-	}
-	dprintk(MANTIS_DEBUG, 1, "Mem Write: (0x%02x to 0x%02x)", data, addr);
-	mutex_unlock(&ca->ca_lock);
-
-	return 0;
-}
-
-int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr)
-{
-	struct mantis_pci *mantis = ca->ca_priv;
-	u32 data, hif_addr = 0;
-
-	dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Read", mantis->num);
-	mutex_lock(&ca->ca_lock);
-	hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
-	hif_addr |=  MANTIS_GPIF_PCMCIAIOM;
-	hif_addr |=  MANTIS_HIF_STATUS;
-	hif_addr |=  addr;
-
-	mmwrite(hif_addr, MANTIS_GPIF_BRADDR);
-	mmwrite(1, MANTIS_GPIF_BRBYTES);
-	udelay(20);
-	mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
-
-	if (mantis_hif_sbuf_opdone_wait(ca) != 0) {
-		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
-		mutex_unlock(&ca->ca_lock);
-		return -EREMOTEIO;
-	}
-	data = mmread(MANTIS_GPIF_DIN);
-	dprintk(MANTIS_DEBUG, 1, "I/O Read: 0x%02x", data);
-	udelay(50);
-	mutex_unlock(&ca->ca_lock);
-
-	return (u8) data;
-}
-
-int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data)
-{
-	struct mantis_pci *mantis = ca->ca_priv;
-	u32 hif_addr = 0;
-
-	dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Write", mantis->num);
-	mutex_lock(&ca->ca_lock);
-	hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
-	hif_addr &= ~MANTIS_GPIF_HIFRDWRN;
-	hif_addr |=  MANTIS_GPIF_PCMCIAIOM;
-	hif_addr |=  MANTIS_HIF_STATUS;
-	hif_addr |=  addr;
-
-	mmwrite(hif_addr, MANTIS_GPIF_ADDR);
-	mmwrite(data, MANTIS_GPIF_DOUT);
-
-	if (mantis_hif_write_wait(ca) != 0) {
-		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
-		mutex_unlock(&ca->ca_lock);
-		return -EREMOTEIO;
-	}
-	dprintk(MANTIS_DEBUG, 1, "I/O Write: (0x%02x to 0x%02x)", data, addr);
-	mutex_unlock(&ca->ca_lock);
-	udelay(50);
-
-	return 0;
-}
-
-int mantis_hif_init(struct mantis_ca *ca)
-{
-	struct mantis_slot *slot = ca->slot;
-	struct mantis_pci *mantis = ca->ca_priv;
-	u32 irqcfg;
-
-	slot[0].slave_cfg = 0x70773028;
-	dprintk(MANTIS_ERROR, 1, "Adapter(%d) Initializing Mantis Host Interface", mantis->num);
-
-	mutex_lock(&ca->ca_lock);
-	irqcfg = mmread(MANTIS_GPIF_IRQCFG);
-	irqcfg = MANTIS_MASK_BRRDY	|
-		 MANTIS_MASK_WRACK	|
-		 MANTIS_MASK_EXTIRQ	|
-		 MANTIS_MASK_WSTO	|
-		 MANTIS_MASK_OTHERR	|
-		 MANTIS_MASK_OVFLW;
-
-	mmwrite(irqcfg, MANTIS_GPIF_IRQCFG);
-	mutex_unlock(&ca->ca_lock);
-
-	return 0;
-}
-
-void mantis_hif_exit(struct mantis_ca *ca)
-{
-	struct mantis_pci *mantis = ca->ca_priv;
-	u32 irqcfg;
-
-	dprintk(MANTIS_ERROR, 1, "Adapter(%d) Exiting Mantis Host Interface", mantis->num);
-	mutex_lock(&ca->ca_lock);
-	irqcfg = mmread(MANTIS_GPIF_IRQCFG);
-	irqcfg &= ~MANTIS_MASK_BRRDY;
-	mmwrite(irqcfg, MANTIS_GPIF_IRQCFG);
-	mutex_unlock(&ca->ca_lock);
-}
diff --git a/drivers/media/dvb/mantis/mantis_hif.h b/drivers/media/dvb/mantis/mantis_hif.h
deleted file mode 100644
index 9094f9e..0000000
--- a/drivers/media/dvb/mantis/mantis_hif.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_HIF_H
-#define __MANTIS_HIF_H
-
-#define MANTIS_HIF_MEMRD		1
-#define MANTIS_HIF_MEMWR		2
-#define MANTIS_HIF_IOMRD		3
-#define MANTIS_HIF_IOMWR		4
-
-#endif /* __MANTIS_HIF_H */
diff --git a/drivers/media/dvb/mantis/mantis_i2c.c b/drivers/media/dvb/mantis/mantis_i2c.c
deleted file mode 100644
index e779451..0000000
--- a/drivers/media/dvb/mantis/mantis_i2c.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <asm/io.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/i2c.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "mantis_common.h"
-#include "mantis_reg.h"
-#include "mantis_i2c.h"
-
-#define TRIALS			10000
-
-static int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg)
-{
-	u32 rxd, i, stat, trials;
-
-	dprintk(MANTIS_INFO, 0, "        %s:  Address=[0x%02x] <R>[ ",
-		__func__, msg->addr);
-
-	for (i = 0; i < msg->len; i++) {
-		rxd = (msg->addr << 25) | (1 << 24)
-					| MANTIS_I2C_RATE_3
-					| MANTIS_I2C_STOP
-					| MANTIS_I2C_PGMODE;
-
-		if (i == (msg->len - 1))
-			rxd &= ~MANTIS_I2C_STOP;
-
-		mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
-		mmwrite(rxd, MANTIS_I2CDATA_CTL);
-
-		/* wait for xfer completion */
-		for (trials = 0; trials < TRIALS; trials++) {
-			stat = mmread(MANTIS_INT_STAT);
-			if (stat & MANTIS_INT_I2CDONE)
-				break;
-		}
-
-		dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
-
-		/* wait for xfer completion */
-		for (trials = 0; trials < TRIALS; trials++) {
-			stat = mmread(MANTIS_INT_STAT);
-			if (stat & MANTIS_INT_I2CRACK)
-				break;
-		}
-
-		dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
-
-		rxd = mmread(MANTIS_I2CDATA_CTL);
-		msg->buf[i] = (u8)((rxd >> 8) & 0xFF);
-		dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
-	}
-	dprintk(MANTIS_INFO, 0, "]\n");
-
-	return 0;
-}
-
-static int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg)
-{
-	int i;
-	u32 txd = 0, stat, trials;
-
-	dprintk(MANTIS_INFO, 0, "        %s: Address=[0x%02x] <W>[ ",
-		__func__, msg->addr);
-
-	for (i = 0; i < msg->len; i++) {
-		dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
-		txd = (msg->addr << 25) | (msg->buf[i] << 8)
-					| MANTIS_I2C_RATE_3
-					| MANTIS_I2C_STOP
-					| MANTIS_I2C_PGMODE;
-
-		if (i == (msg->len - 1))
-			txd &= ~MANTIS_I2C_STOP;
-
-		mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
-		mmwrite(txd, MANTIS_I2CDATA_CTL);
-
-		/* wait for xfer completion */
-		for (trials = 0; trials < TRIALS; trials++) {
-			stat = mmread(MANTIS_INT_STAT);
-			if (stat & MANTIS_INT_I2CDONE)
-				break;
-		}
-
-		dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
-
-		/* wait for xfer completion */
-		for (trials = 0; trials < TRIALS; trials++) {
-			stat = mmread(MANTIS_INT_STAT);
-			if (stat & MANTIS_INT_I2CRACK)
-				break;
-		}
-
-		dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
-	}
-	dprintk(MANTIS_INFO, 0, "]\n");
-
-	return 0;
-}
-
-static int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
-{
-	int ret = 0, i = 0, trials;
-	u32 stat, data, txd;
-	struct mantis_pci *mantis;
-	struct mantis_hwconfig *config;
-
-	mantis = i2c_get_adapdata(adapter);
-	BUG_ON(!mantis);
-	config = mantis->hwconfig;
-	BUG_ON(!config);
-
-	dprintk(MANTIS_DEBUG, 1, "Messages:%d", num);
-	mutex_lock(&mantis->i2c_lock);
-
-	while (i < num) {
-		/* Byte MODE */
-		if ((config->i2c_mode & MANTIS_BYTE_MODE) &&
-		    ((i + 1) < num)			&&
-		    (msgs[i].len < 2)			&&
-		    (msgs[i + 1].len < 2)		&&
-		    (msgs[i + 1].flags & I2C_M_RD)) {
-
-			dprintk(MANTIS_DEBUG, 0, "        Byte MODE:\n");
-
-			/* Read operation */
-			txd = msgs[i].addr << 25 | (0x1 << 24)
-						 | (msgs[i].buf[0] << 16)
-						 | MANTIS_I2C_RATE_3;
-
-			mmwrite(txd, MANTIS_I2CDATA_CTL);
-			/* wait for xfer completion */
-			for (trials = 0; trials < TRIALS; trials++) {
-				stat = mmread(MANTIS_INT_STAT);
-				if (stat & MANTIS_INT_I2CDONE)
-					break;
-			}
-
-			/* check for xfer completion */
-			if (stat & MANTIS_INT_I2CDONE) {
-				/* check xfer was acknowledged */
-				if (stat & MANTIS_INT_I2CRACK) {
-					data = mmread(MANTIS_I2CDATA_CTL);
-					msgs[i + 1].buf[0] = (data >> 8) & 0xff;
-					dprintk(MANTIS_DEBUG, 0, "        Byte <%d> RXD=0x%02x  [%02x]\n", 0x0, data, msgs[i + 1].buf[0]);
-				} else {
-					/* I/O error */
-					dprintk(MANTIS_ERROR, 1, "        I/O error, LINE:%d", __LINE__);
-					ret = -EIO;
-					break;
-				}
-			} else {
-				/* I/O error */
-				dprintk(MANTIS_ERROR, 1, "        I/O error, LINE:%d", __LINE__);
-				ret = -EIO;
-				break;
-			}
-			i += 2; /* Write/Read operation in one go */
-		}
-
-		if (i < num) {
-			if (msgs[i].flags & I2C_M_RD)
-				ret = mantis_i2c_read(mantis, &msgs[i]);
-			else
-				ret = mantis_i2c_write(mantis, &msgs[i]);
-
-			i++;
-			if (ret < 0)
-				goto bail_out;
-		}
-
-	}
-
-	mutex_unlock(&mantis->i2c_lock);
-
-	return num;
-
-bail_out:
-	mutex_unlock(&mantis->i2c_lock);
-	return ret;
-}
-
-static u32 mantis_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_SMBUS_EMUL;
-}
-
-static struct i2c_algorithm mantis_algo = {
-	.master_xfer		= mantis_i2c_xfer,
-	.functionality		= mantis_i2c_func,
-};
-
-int __devinit mantis_i2c_init(struct mantis_pci *mantis)
-{
-	u32 intstat, intmask;
-	struct i2c_adapter *i2c_adapter = &mantis->adapter;
-	struct pci_dev *pdev		= mantis->pdev;
-
-	init_waitqueue_head(&mantis->i2c_wq);
-	mutex_init(&mantis->i2c_lock);
-	strncpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name));
-	i2c_set_adapdata(i2c_adapter, mantis);
-
-	i2c_adapter->owner	= THIS_MODULE;
-	i2c_adapter->algo	= &mantis_algo;
-	i2c_adapter->algo_data	= NULL;
-	i2c_adapter->timeout	= 500;
-	i2c_adapter->retries	= 3;
-	i2c_adapter->dev.parent	= &pdev->dev;
-
-	mantis->i2c_rc		= i2c_add_adapter(i2c_adapter);
-	if (mantis->i2c_rc < 0)
-		return mantis->i2c_rc;
-
-	dprintk(MANTIS_DEBUG, 1, "Initializing I2C ..");
-
-	intstat = mmread(MANTIS_INT_STAT);
-	intmask = mmread(MANTIS_INT_MASK);
-	mmwrite(intstat, MANTIS_INT_STAT);
-	dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
-	intmask = mmread(MANTIS_INT_MASK);
-	mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(mantis_i2c_init);
-
-int mantis_i2c_exit(struct mantis_pci *mantis)
-{
-	u32 intmask;
-
-	dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
-	intmask = mmread(MANTIS_INT_MASK);
-	mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK);
-
-	dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter");
-	return i2c_del_adapter(&mantis->adapter);
-}
-EXPORT_SYMBOL_GPL(mantis_i2c_exit);
diff --git a/drivers/media/dvb/mantis/mantis_i2c.h b/drivers/media/dvb/mantis/mantis_i2c.h
deleted file mode 100644
index 1342df2..0000000
--- a/drivers/media/dvb/mantis/mantis_i2c.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_I2C_H
-#define __MANTIS_I2C_H
-
-#define I2C_STOP		(1 <<  0)
-#define I2C_READ		(1 <<  1)
-
-extern int mantis_i2c_init(struct mantis_pci *mantis);
-extern int mantis_i2c_exit(struct mantis_pci *mantis);
-
-#endif /* __MANTIS_I2C_H */
diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/dvb/mantis/mantis_input.c
deleted file mode 100644
index db6d54d..0000000
--- a/drivers/media/dvb/mantis/mantis_input.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <media/rc-core.h>
-#include <linux/pci.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "mantis_common.h"
-#include "mantis_reg.h"
-#include "mantis_uart.h"
-
-#define MODULE_NAME "mantis_core"
-#define RC_MAP_MANTIS "rc-mantis"
-
-static struct rc_map_table mantis_ir_table[] = {
-	{ 0x29, KEY_POWER	},
-	{ 0x28, KEY_FAVORITES	},
-	{ 0x30, KEY_TEXT	},
-	{ 0x17, KEY_INFO	}, /* Preview */
-	{ 0x23, KEY_EPG		},
-	{ 0x3b, KEY_F22		}, /* Record List */
-	{ 0x3c, KEY_1		},
-	{ 0x3e, KEY_2		},
-	{ 0x39, KEY_3		},
-	{ 0x36, KEY_4		},
-	{ 0x22, KEY_5		},
-	{ 0x20, KEY_6		},
-	{ 0x32, KEY_7		},
-	{ 0x26, KEY_8		},
-	{ 0x24, KEY_9		},
-	{ 0x2a, KEY_0		},
-
-	{ 0x33, KEY_CANCEL	},
-	{ 0x2c, KEY_BACK	},
-	{ 0x15, KEY_CLEAR	},
-	{ 0x3f, KEY_TAB		},
-	{ 0x10, KEY_ENTER	},
-	{ 0x14, KEY_UP		},
-	{ 0x0d, KEY_RIGHT	},
-	{ 0x0e, KEY_DOWN	},
-	{ 0x11, KEY_LEFT	},
-
-	{ 0x21, KEY_VOLUMEUP	},
-	{ 0x35, KEY_VOLUMEDOWN	},
-	{ 0x3d, KEY_CHANNELDOWN	},
-	{ 0x3a, KEY_CHANNELUP	},
-	{ 0x2e, KEY_RECORD	},
-	{ 0x2b, KEY_PLAY	},
-	{ 0x13, KEY_PAUSE	},
-	{ 0x25, KEY_STOP	},
-
-	{ 0x1f, KEY_REWIND	},
-	{ 0x2d, KEY_FASTFORWARD	},
-	{ 0x1e, KEY_PREVIOUS	}, /* Replay |< */
-	{ 0x1d, KEY_NEXT	}, /* Skip   >| */
-
-	{ 0x0b, KEY_CAMERA	}, /* Capture */
-	{ 0x0f, KEY_LANGUAGE	}, /* SAP */
-	{ 0x18, KEY_MODE	}, /* PIP */
-	{ 0x12, KEY_ZOOM	}, /* Full screen */
-	{ 0x1c, KEY_SUBTITLE	},
-	{ 0x2f, KEY_MUTE	},
-	{ 0x16, KEY_F20		}, /* L/R */
-	{ 0x38, KEY_F21		}, /* Hibernate */
-
-	{ 0x37, KEY_SWITCHVIDEOMODE }, /* A/V */
-	{ 0x31, KEY_AGAIN	}, /* Recall */
-	{ 0x1a, KEY_KPPLUS	}, /* Zoom+ */
-	{ 0x19, KEY_KPMINUS	}, /* Zoom- */
-	{ 0x27, KEY_RED		},
-	{ 0x0C, KEY_GREEN	},
-	{ 0x01, KEY_YELLOW	},
-	{ 0x00, KEY_BLUE	},
-};
-
-static struct rc_map_list ir_mantis_map = {
-	.map = {
-		.scan = mantis_ir_table,
-		.size = ARRAY_SIZE(mantis_ir_table),
-		.rc_type = RC_TYPE_UNKNOWN,
-		.name = RC_MAP_MANTIS,
-	}
-};
-
-int mantis_input_init(struct mantis_pci *mantis)
-{
-	struct rc_dev *dev;
-	int err;
-
-	err = rc_map_register(&ir_mantis_map);
-	if (err)
-		goto out;
-
-	dev = rc_allocate_device();
-	if (!dev) {
-		dprintk(MANTIS_ERROR, 1, "Remote device allocation failed");
-		err = -ENOMEM;
-		goto out_map;
-	}
-
-	sprintf(mantis->input_name, "Mantis %s IR receiver", mantis->hwconfig->model_name);
-	sprintf(mantis->input_phys, "pci-%s/ir0", pci_name(mantis->pdev));
-
-	dev->input_name         = mantis->input_name;
-	dev->input_phys         = mantis->input_phys;
-	dev->input_id.bustype   = BUS_PCI;
-	dev->input_id.vendor    = mantis->vendor_id;
-	dev->input_id.product   = mantis->device_id;
-	dev->input_id.version   = 1;
-	dev->driver_name        = MODULE_NAME;
-	dev->map_name           = RC_MAP_MANTIS;
-	dev->dev.parent         = &mantis->pdev->dev;
-
-	err = rc_register_device(dev);
-	if (err) {
-		dprintk(MANTIS_ERROR, 1, "IR device registration failed, ret = %d", err);
-		goto out_dev;
-	}
-
-	mantis->rc = dev;
-	return 0;
-
-out_dev:
-	rc_free_device(dev);
-out_map:
-	rc_map_unregister(&ir_mantis_map);
-out:
-	return err;
-}
-
-int mantis_exit(struct mantis_pci *mantis)
-{
-	rc_unregister_device(mantis->rc);
-	rc_map_unregister(&ir_mantis_map);
-	return 0;
-}
-
diff --git a/drivers/media/dvb/mantis/mantis_ioc.c b/drivers/media/dvb/mantis/mantis_ioc.c
deleted file mode 100644
index 24fcdc6..0000000
--- a/drivers/media/dvb/mantis/mantis_ioc.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/kernel.h>
-#include <linux/i2c.h>
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "mantis_common.h"
-#include "mantis_reg.h"
-#include "mantis_ioc.h"
-
-static int read_eeprom_bytes(struct mantis_pci *mantis, u8 reg, u8 *data, u8 length)
-{
-	struct i2c_adapter *adapter = &mantis->adapter;
-	int err;
-	u8 buf = reg;
-
-	struct i2c_msg msg[] = {
-		{ .addr = 0x50, .flags = 0, .buf = &buf, .len = 1 },
-		{ .addr = 0x50, .flags = I2C_M_RD, .buf = data, .len = length },
-	};
-
-	err = i2c_transfer(adapter, msg, 2);
-	if (err < 0) {
-		dprintk(MANTIS_ERROR, 1, "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >",
-			err, data[0], data[1]);
-
-		return err;
-	}
-
-	return 0;
-}
-int mantis_get_mac(struct mantis_pci *mantis)
-{
-	int err;
-	u8 mac_addr[6] = {0};
-
-	err = read_eeprom_bytes(mantis, 0x08, mac_addr, 6);
-	if (err < 0) {
-		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis EEPROM read error <%d>", err);
-
-		return err;
-	}
-
-	dprintk(MANTIS_ERROR, 0, "    MAC Address=[%pM]\n", mac_addr);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(mantis_get_mac);
-
-/* Turn the given bit on or off. */
-void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
-{
-	u32 cur;
-
-	dprintk(MANTIS_DEBUG, 1, "Set Bit <%d> to <%d>", bitpos, value);
-	cur = mmread(MANTIS_GPIF_ADDR);
-	if (value)
-		mantis->gpio_status = cur | (1 << bitpos);
-	else
-		mantis->gpio_status = cur & (~(1 << bitpos));
-
-	dprintk(MANTIS_DEBUG, 1, "GPIO Value <%02x>", mantis->gpio_status);
-	mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR);
-	mmwrite(0x00, MANTIS_GPIF_DOUT);
-}
-EXPORT_SYMBOL_GPL(mantis_gpio_set_bits);
-
-int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl)
-{
-	u32 reg;
-
-	reg = mmread(MANTIS_CONTROL);
-	switch (stream_ctl) {
-	case STREAM_TO_HIF:
-		dprintk(MANTIS_DEBUG, 1, "Set stream to HIF");
-		reg &= 0xff - MANTIS_BYPASS;
-		mmwrite(reg, MANTIS_CONTROL);
-		reg |= MANTIS_BYPASS;
-		mmwrite(reg, MANTIS_CONTROL);
-		break;
-
-	case STREAM_TO_CAM:
-		dprintk(MANTIS_DEBUG, 1, "Set stream to CAM");
-		reg |= MANTIS_BYPASS;
-		mmwrite(reg, MANTIS_CONTROL);
-		reg &= 0xff - MANTIS_BYPASS;
-		mmwrite(reg, MANTIS_CONTROL);
-		break;
-	default:
-		dprintk(MANTIS_ERROR, 1, "Unknown MODE <%02x>", stream_ctl);
-		return -1;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(mantis_stream_control);
diff --git a/drivers/media/dvb/mantis/mantis_ioc.h b/drivers/media/dvb/mantis/mantis_ioc.h
deleted file mode 100644
index d56e002..0000000
--- a/drivers/media/dvb/mantis/mantis_ioc.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_IOC_H
-#define __MANTIS_IOC_H
-
-#define GPIF_A00		0x00
-#define GPIF_A01		0x01
-#define GPIF_A02		0x02
-#define GPIF_A03		0x03
-#define GPIF_A04		0x04
-#define GPIF_A05		0x05
-#define GPIF_A06		0x06
-#define GPIF_A07		0x07
-#define GPIF_A08		0x08
-#define GPIF_A09		0x09
-#define GPIF_A10		0x0a
-#define GPIF_A11		0x0b
-
-#define GPIF_A12		0x0c
-#define GPIF_A13		0x0d
-#define GPIF_A14		0x0e
-
-enum mantis_stream_control {
-	STREAM_TO_HIF = 0,
-	STREAM_TO_CAM
-};
-
-extern int mantis_get_mac(struct mantis_pci *mantis);
-extern void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value);
-
-extern int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl);
-
-#endif /* __MANTIS_IOC_H */
diff --git a/drivers/media/dvb/mantis/mantis_link.h b/drivers/media/dvb/mantis/mantis_link.h
deleted file mode 100644
index 2a81477..0000000
--- a/drivers/media/dvb/mantis/mantis_link.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_LINK_H
-#define __MANTIS_LINK_H
-
-#include <linux/mutex.h>
-#include <linux/workqueue.h>
-#include "dvb_ca_en50221.h"
-
-enum mantis_sbuf_status {
-	MANTIS_SBUF_DATA_AVAIL		= 1,
-	MANTIS_SBUF_DATA_EMPTY		= 2,
-	MANTIS_SBUF_DATA_OVFLW		= 3
-};
-
-struct mantis_slot {
-	u32				timeout;
-	u32				slave_cfg;
-	u32				bar;
-};
-
-/* Physical layer */
-enum mantis_slot_state {
-	MODULE_INSERTED			= 3,
-	MODULE_XTRACTED			= 4
-};
-
-struct mantis_ca {
-	struct mantis_slot		slot[4];
-
-	struct work_struct		hif_evm_work;
-
-	u32				hif_event;
-	wait_queue_head_t		hif_opdone_wq;
-	wait_queue_head_t		hif_brrdyw_wq;
-	wait_queue_head_t		hif_data_wq;
-	wait_queue_head_t		hif_write_wq; /* HIF Write op */
-
-	enum mantis_sbuf_status		sbuf_status;
-
-	enum mantis_slot_state		slot_state;
-
-	void				*ca_priv;
-
-	struct dvb_ca_en50221		en50221;
-	struct mutex			ca_lock;
-};
-
-/* CA */
-extern void mantis_event_cam_plugin(struct mantis_ca *ca);
-extern void mantis_event_cam_unplug(struct mantis_ca *ca);
-extern int mantis_pcmcia_init(struct mantis_ca *ca);
-extern void mantis_pcmcia_exit(struct mantis_ca *ca);
-extern int mantis_evmgr_init(struct mantis_ca *ca);
-extern void mantis_evmgr_exit(struct mantis_ca *ca);
-
-/* HIF */
-extern int mantis_hif_init(struct mantis_ca *ca);
-extern void mantis_hif_exit(struct mantis_ca *ca);
-extern int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr);
-extern int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data);
-extern int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr);
-extern int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data);
-
-#endif /* __MANTIS_LINK_H */
diff --git a/drivers/media/dvb/mantis/mantis_pci.c b/drivers/media/dvb/mantis/mantis_pci.c
deleted file mode 100644
index 371558a..0000000
--- a/drivers/media/dvb/mantis/mantis_pci.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <asm/io.h>
-#include <asm/page.h>
-#include <linux/kmod.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/pci.h>
-
-#include <asm/irq.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "mantis_common.h"
-#include "mantis_reg.h"
-#include "mantis_pci.h"
-
-#define DRIVER_NAME		"Mantis Core"
-
-int __devinit mantis_pci_init(struct mantis_pci *mantis)
-{
-	u8 latency;
-	struct mantis_hwconfig *config	= mantis->hwconfig;
-	struct pci_dev *pdev		= mantis->pdev;
-	int err, ret = 0;
-
-	dprintk(MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n",
-		config->model_name,
-		config->dev_type,
-		mantis->pdev->bus->number,
-		PCI_SLOT(mantis->pdev->devfn),
-		PCI_FUNC(mantis->pdev->devfn));
-
-	err = pci_enable_device(pdev);
-	if (err != 0) {
-		ret = -ENODEV;
-		dprintk(MANTIS_ERROR, 1, "ERROR: PCI enable failed <%i>", err);
-		goto fail0;
-	}
-
-	err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-	if (err != 0) {
-		dprintk(MANTIS_ERROR, 1, "ERROR: Unable to obtain 32 bit DMA <%i>", err);
-		ret = -ENOMEM;
-		goto fail1;
-	}
-
-	pci_set_master(pdev);
-
-	if (!request_mem_region(pci_resource_start(pdev, 0),
-				pci_resource_len(pdev, 0),
-				DRIVER_NAME)) {
-
-		dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 Request failed !");
-		ret = -ENODEV;
-		goto fail1;
-	}
-
-	mantis->mmio = ioremap(pci_resource_start(pdev, 0),
-			       pci_resource_len(pdev, 0));
-
-	if (!mantis->mmio) {
-		dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 remap failed !");
-		ret = -ENODEV;
-		goto fail2;
-	}
-
-	pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
-	mantis->latency = latency;
-	mantis->revision = pdev->revision;
-
-	dprintk(MANTIS_ERROR, 0, "    Mantis Rev %d [%04x:%04x], ",
-		mantis->revision,
-		mantis->pdev->subsystem_vendor,
-		mantis->pdev->subsystem_device);
-
-	dprintk(MANTIS_ERROR, 0,
-		"irq: %d, latency: %d\n    memory: 0x%lx, mmio: 0x%p\n",
-		mantis->pdev->irq,
-		mantis->latency,
-		mantis->mantis_addr,
-		mantis->mmio);
-
-	err = request_irq(pdev->irq,
-			  config->irq_handler,
-			  IRQF_SHARED,
-			  DRIVER_NAME,
-			  mantis);
-
-	if (err != 0) {
-
-		dprintk(MANTIS_ERROR, 1, "ERROR: IRQ registration failed ! <%d>", err);
-		ret = -ENODEV;
-		goto fail3;
-	}
-
-	pci_set_drvdata(pdev, mantis);
-	return ret;
-
-	/* Error conditions */
-fail3:
-	dprintk(MANTIS_ERROR, 1, "ERROR: <%d> I/O unmap", ret);
-	if (mantis->mmio)
-		iounmap(mantis->mmio);
-
-fail2:
-	dprintk(MANTIS_ERROR, 1, "ERROR: <%d> releasing regions", ret);
-	release_mem_region(pci_resource_start(pdev, 0),
-			   pci_resource_len(pdev, 0));
-
-fail1:
-	dprintk(MANTIS_ERROR, 1, "ERROR: <%d> disabling device", ret);
-	pci_disable_device(pdev);
-
-fail0:
-	dprintk(MANTIS_ERROR, 1, "ERROR: <%d> exiting", ret);
-	pci_set_drvdata(pdev, NULL);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(mantis_pci_init);
-
-void mantis_pci_exit(struct mantis_pci *mantis)
-{
-	struct pci_dev *pdev = mantis->pdev;
-
-	dprintk(MANTIS_NOTICE, 1, " mem: 0x%p", mantis->mmio);
-	free_irq(pdev->irq, mantis);
-	if (mantis->mmio) {
-		iounmap(mantis->mmio);
-		release_mem_region(pci_resource_start(pdev, 0),
-				   pci_resource_len(pdev, 0));
-	}
-
-	pci_disable_device(pdev);
-	pci_set_drvdata(pdev, NULL);
-}
-EXPORT_SYMBOL_GPL(mantis_pci_exit);
-
-MODULE_DESCRIPTION("Mantis PCI DTV bridge driver");
-MODULE_AUTHOR("Manu Abraham");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/mantis/mantis_pci.h b/drivers/media/dvb/mantis/mantis_pci.h
deleted file mode 100644
index 65f0045..0000000
--- a/drivers/media/dvb/mantis/mantis_pci.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_PCI_H
-#define __MANTIS_PCI_H
-
-extern int mantis_pci_init(struct mantis_pci *mantis);
-extern void mantis_pci_exit(struct mantis_pci *mantis);
-
-#endif /* __MANTIS_PCI_H */
diff --git a/drivers/media/dvb/mantis/mantis_pcmcia.c b/drivers/media/dvb/mantis/mantis_pcmcia.c
deleted file mode 100644
index 2f188c0..0000000
--- a/drivers/media/dvb/mantis/mantis_pcmcia.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/kernel.h>
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "mantis_common.h"
-#include "mantis_link.h" /* temporary due to physical layer stuff */
-#include "mantis_reg.h"
-
-/*
- * If Slot state is already PLUG_IN event and we are called
- * again, definitely it is jitter alone
- */
-void mantis_event_cam_plugin(struct mantis_ca *ca)
-{
-	struct mantis_pci *mantis = ca->ca_priv;
-
-	u32 gpif_irqcfg;
-
-	if (ca->slot_state == MODULE_XTRACTED) {
-		dprintk(MANTIS_DEBUG, 1, "Event: CAM Plugged IN: Adapter(%d) Slot(0)", mantis->num);
-		udelay(50);
-		mmwrite(0xda000000, MANTIS_CARD_RESET);
-		gpif_irqcfg  = mmread(MANTIS_GPIF_IRQCFG);
-		gpif_irqcfg |= MANTIS_MASK_PLUGOUT;
-		gpif_irqcfg &= ~MANTIS_MASK_PLUGIN;
-		mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG);
-		udelay(500);
-		ca->slot_state = MODULE_INSERTED;
-	}
-	udelay(100);
-}
-
-/*
- * If Slot state is already UN_PLUG event and we are called
- * again, definitely it is jitter alone
- */
-void mantis_event_cam_unplug(struct mantis_ca *ca)
-{
-	struct mantis_pci *mantis = ca->ca_priv;
-
-	u32 gpif_irqcfg;
-
-	if (ca->slot_state == MODULE_INSERTED) {
-		dprintk(MANTIS_DEBUG, 1, "Event: CAM Unplugged: Adapter(%d) Slot(0)", mantis->num);
-		udelay(50);
-		mmwrite(0x00da0000, MANTIS_CARD_RESET);
-		gpif_irqcfg  = mmread(MANTIS_GPIF_IRQCFG);
-		gpif_irqcfg |= MANTIS_MASK_PLUGIN;
-		gpif_irqcfg &= ~MANTIS_MASK_PLUGOUT;
-		mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG);
-		udelay(500);
-		ca->slot_state = MODULE_XTRACTED;
-	}
-	udelay(100);
-}
-
-int mantis_pcmcia_init(struct mantis_ca *ca)
-{
-	struct mantis_pci *mantis = ca->ca_priv;
-
-	u32 gpif_stat, card_stat;
-
-	mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_IRQ0, MANTIS_INT_MASK);
-	gpif_stat = mmread(MANTIS_GPIF_STATUS);
-	card_stat = mmread(MANTIS_GPIF_IRQCFG);
-
-	if (gpif_stat & MANTIS_GPIF_DETSTAT) {
-		dprintk(MANTIS_DEBUG, 1, "CAM found on Adapter(%d) Slot(0)", mantis->num);
-		mmwrite(card_stat | MANTIS_MASK_PLUGOUT, MANTIS_GPIF_IRQCFG);
-		ca->slot_state = MODULE_INSERTED;
-		dvb_ca_en50221_camchange_irq(&ca->en50221,
-					     0,
-					     DVB_CA_EN50221_CAMCHANGE_INSERTED);
-	} else {
-		dprintk(MANTIS_DEBUG, 1, "Empty Slot on Adapter(%d) Slot(0)", mantis->num);
-		mmwrite(card_stat | MANTIS_MASK_PLUGIN, MANTIS_GPIF_IRQCFG);
-		ca->slot_state = MODULE_XTRACTED;
-		dvb_ca_en50221_camchange_irq(&ca->en50221,
-					     0,
-					     DVB_CA_EN50221_CAMCHANGE_REMOVED);
-	}
-
-	return 0;
-}
-
-void mantis_pcmcia_exit(struct mantis_ca *ca)
-{
-	struct mantis_pci *mantis = ca->ca_priv;
-
-	mmwrite(mmread(MANTIS_GPIF_STATUS) & (~MANTIS_CARD_PLUGOUT | ~MANTIS_CARD_PLUGIN), MANTIS_GPIF_STATUS);
-	mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ0, MANTIS_INT_MASK);
-}
diff --git a/drivers/media/dvb/mantis/mantis_reg.h b/drivers/media/dvb/mantis/mantis_reg.h
deleted file mode 100644
index 7761f9d..0000000
--- a/drivers/media/dvb/mantis/mantis_reg.h
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_REG_H
-#define __MANTIS_REG_H
-
-/* Interrupts */
-#define MANTIS_INT_STAT			0x00
-#define MANTIS_INT_MASK			0x04
-
-#define MANTIS_INT_RISCSTAT		(0x0f << 28)
-#define MANTIS_INT_RISCEN		(0x01 << 27)
-#define MANTIS_INT_I2CRACK		(0x01 << 26)
-
-/* #define MANTIS_INT_GPIF			(0xff << 12) */
-
-#define MANTIS_INT_PCMCIA7		(0x01 << 19)
-#define MANTIS_INT_PCMCIA6		(0x01 << 18)
-#define MANTIS_INT_PCMCIA5		(0x01 << 17)
-#define MANTIS_INT_PCMCIA4		(0x01 << 16)
-#define MANTIS_INT_PCMCIA3		(0x01 << 15)
-#define MANTIS_INT_PCMCIA2		(0x01 << 14)
-#define MANTIS_INT_PCMCIA1		(0x01 << 13)
-#define MANTIS_INT_PCMCIA0		(0x01 << 12)
-#define MANTIS_INT_IRQ1			(0x01 << 11)
-#define MANTIS_INT_IRQ0			(0x01 << 10)
-#define MANTIS_INT_OCERR		(0x01 <<  8)
-#define MANTIS_INT_PABORT		(0x01 <<  7)
-#define MANTIS_INT_RIPERR		(0x01 <<  6)
-#define MANTIS_INT_PPERR		(0x01 <<  5)
-#define MANTIS_INT_FTRGT		(0x01 <<  3)
-#define MANTIS_INT_RISCI		(0x01 <<  1)
-#define MANTIS_INT_I2CDONE		(0x01 <<  0)
-
-/* DMA */
-#define MANTIS_DMA_CTL			0x08
-#define MANTIS_GPIF_RD			(0xff << 24)
-#define MANTIS_GPIF_WR			(0xff << 16)
-#define MANTIS_CPU_DO			(0x01 << 10)
-#define MANTIS_DRV_DO			(0x01 <<  9)
-#define	MANTIS_I2C_RD			(0x01 <<  7)
-#define MANTIS_I2C_WR			(0x01 <<  6)
-#define MANTIS_DCAP_MODE		(0x01 <<  5)
-#define MANTIS_FIFO_TP_4		(0x00 <<  3)
-#define MANTIS_FIFO_TP_8		(0x01 <<  3)
-#define MANTIS_FIFO_TP_16		(0x02 <<  3)
-#define MANTIS_FIFO_EN			(0x01 <<  2)
-#define MANTIS_DCAP_EN			(0x01 <<  1)
-#define MANTIS_RISC_EN			(0x01 <<  0)
-
-/* DEBUG */
-#define MANTIS_DEBUGREG			0x0c
-#define MANTIS_DATINV			(0x0e <<  7)
-#define MANTIS_TOP_DEBUGSEL		(0x07 <<  4)
-#define MANTIS_PCMCIA_DEBUGSEL		(0x0f <<  0)
-
-#define MANTIS_RISC_START		0x10
-#define MANTIS_RISC_PC			0x14
-
-/* I2C */
-#define MANTIS_I2CDATA_CTL		0x18
-#define MANTIS_I2C_RATE_1		(0x00 <<  6)
-#define MANTIS_I2C_RATE_2		(0x01 <<  6)
-#define MANTIS_I2C_RATE_3		(0x02 <<  6)
-#define MANTIS_I2C_RATE_4		(0x03 <<  6)
-#define MANTIS_I2C_STOP			(0x01 <<  5)
-#define MANTIS_I2C_PGMODE		(0x01 <<  3)
-
-/* DATA */
-#define MANTIS_CMD_DATA_R1		0x20
-#define MANTIS_CMD_DATA_3		(0xff << 24)
-#define MANTIS_CMD_DATA_2		(0xff << 16)
-#define MANTIS_CMD_DATA_1		(0xff <<  8)
-#define MANTIS_CMD_DATA_0		(0xff <<  0)
-
-#define MANTIS_CMD_DATA_R2		0x24
-#define MANTIS_CMD_DATA_7		(0xff << 24)
-#define MANTIS_CMD_DATA_6		(0xff << 16)
-#define MANTIS_CMD_DATA_5		(0xff <<  8)
-#define MANTIS_CMD_DATA_4		(0xff <<  0)
-
-#define MANTIS_CONTROL			0x28
-#define MANTIS_DET			(0x01 <<  7)
-#define MANTIS_DAT_CF_EN		(0x01 <<  6)
-#define MANTIS_ACS			(0x03 <<  4)
-#define MANTIS_VCCEN			(0x01 <<  3)
-#define MANTIS_BYPASS			(0x01 <<  2)
-#define MANTIS_MRST			(0x01 <<  1)
-#define MANTIS_CRST_INT			(0x01 <<  0)
-
-#define MANTIS_GPIF_CFGSLA		0x84
-#define MANTIS_GPIF_WAITSMPL		(0x07 << 28)
-#define MANTIS_GPIF_BYTEADDRSUB		(0x01 << 25)
-#define MANTIS_GPIF_WAITPOL		(0x01 << 24)
-#define MANTIS_GPIF_NCDELAY		(0x07 << 20)
-#define MANTIS_GPIF_RW2CSDELAY		(0x07 << 16)
-#define MANTIS_GPIF_SLFTIMEDMODE	(0x01 << 15)
-#define MANTIS_GPIF_SLFTIMEDDELY	(0x7f <<  8)
-#define MANTIS_GPIF_DEVTYPE		(0x07 <<  4)
-#define MANTIS_GPIF_BIGENDIAN		(0x01 <<  3)
-#define MANTIS_GPIF_FETCHCMD		(0x03 <<  1)
-#define MANTIS_GPIF_HWORDDEV		(0x01 <<  0)
-
-#define MANTIS_GPIF_WSTOPER		0x90
-#define MANTIS_GPIF_WSTOPERWREN3	(0x01 << 31)
-#define MANTIS_GPIF_PARBOOTN		(0x01 << 29)
-#define MANTIS_GPIF_WSTOPERSLID3	(0x1f << 24)
-#define MANTIS_GPIF_WSTOPERWREN2	(0x01 << 23)
-#define MANTIS_GPIF_WSTOPERSLID2	(0x1f << 16)
-#define MANTIS_GPIF_WSTOPERWREN1	(0x01 << 15)
-#define MANTIS_GPIF_WSTOPERSLID1	(0x1f <<  8)
-#define MANTIS_GPIF_WSTOPERWREN0	(0x01 <<  7)
-#define MANTIS_GPIF_WSTOPERSLID0	(0x1f <<  0)
-
-#define MANTIS_GPIF_CS2RW		0x94
-#define MANTIS_GPIF_CS2RWWREN3		(0x01 << 31)
-#define MANTIS_GPIF_CS2RWDELY3		(0x3f << 24)
-#define MANTIS_GPIF_CS2RWWREN2		(0x01 << 23)
-#define MANTIS_GPIF_CS2RWDELY2		(0x3f << 16)
-#define MANTIS_GPIF_CS2RWWREN1		(0x01 << 15)
-#define MANTIS_GPIF_CS2RWDELY1		(0x3f <<  8)
-#define MANTIS_GPIF_CS2RWWREN0		(0x01 <<  7)
-#define MANTIS_GPIF_CS2RWDELY0		(0x3f <<  0)
-
-#define MANTIS_GPIF_IRQCFG		0x98
-#define MANTIS_GPIF_IRQPOL		(0x01 <<  8)
-#define MANTIS_MASK_WRACK		(0x01 <<  7)
-#define MANTIS_MASK_BRRDY		(0x01 <<  6)
-#define MANTIS_MASK_OVFLW		(0x01 <<  5)
-#define MANTIS_MASK_OTHERR		(0x01 <<  4)
-#define MANTIS_MASK_WSTO		(0x01 <<  3)
-#define MANTIS_MASK_EXTIRQ		(0x01 <<  2)
-#define MANTIS_MASK_PLUGIN		(0x01 <<  1)
-#define MANTIS_MASK_PLUGOUT		(0x01 <<  0)
-
-#define MANTIS_GPIF_STATUS		0x9c
-#define MANTIS_SBUF_KILLOP		(0x01 << 15)
-#define MANTIS_SBUF_OPDONE		(0x01 << 14)
-#define MANTIS_SBUF_EMPTY		(0x01 << 13)
-#define MANTIS_GPIF_DETSTAT		(0x01 <<  9)
-#define MANTIS_GPIF_INTSTAT		(0x01 <<  8)
-#define MANTIS_GPIF_WRACK		(0x01 <<  7)
-#define MANTIS_GPIF_BRRDY		(0x01 <<  6)
-#define MANTIS_SBUF_OVFLW		(0x01 <<  5)
-#define MANTIS_GPIF_OTHERR		(0x01 <<  4)
-#define MANTIS_SBUF_WSTO		(0x01 <<  3)
-#define MANTIS_GPIF_EXTIRQ		(0x01 <<  2)
-#define MANTIS_CARD_PLUGIN		(0x01 <<  1)
-#define MANTIS_CARD_PLUGOUT		(0x01 <<  0)
-
-#define MANTIS_GPIF_BRADDR		0xa0
-#define MANTIS_GPIF_PCMCIAREG		(0x01 		<< 27)
-#define MANTIS_GPIF_PCMCIAIOM		(0x01 		<< 26)
-#define MANTIS_GPIF_BR_ADDR		(0xfffffff	<<  0)
-
-#define MANTIS_GPIF_BRBYTES		0xa4
-#define MANTIS_GPIF_BRCNT		(0xfff 		<<  0)
-
-#define MANTIS_PCMCIA_RESET		0xa8
-#define MANTIS_PCMCIA_RSTVAL		(0xff << 0)
-
-#define MANTIS_CARD_RESET		0xac
-
-#define MANTIS_GPIF_ADDR		0xb0
-#define MANTIS_GPIF_HIFRDWRN		(0x01		<< 31)
-#define MANTIS_GPIF_PCMCIAREG		(0x01		<< 27)
-#define MANTIS_GPIF_PCMCIAIOM		(0x01		<< 26)
-#define MANTIS_GPIF_HIFADDR		(0xfffffff	<<  0)
-
-#define MANTIS_GPIF_DOUT		0xb4
-#define MANTIS_GPIF_HIFDOUT		(0xfffffff	<<  0)
-
-#define MANTIS_GPIF_DIN			0xb8
-#define MANTIS_GPIF_HIFDIN		(0xfffffff	<<  0)
-
-#define MANTIS_GPIF_SPARE		0xbc
-#define MANTIS_GPIF_LOGICRD		(0xffff		<< 16)
-#define MANTIS_GPIF_LOGICRW		(0xffff		<<  0)
-
-#endif /* __MANTIS_REG_H */
diff --git a/drivers/media/dvb/mantis/mantis_uart.c b/drivers/media/dvb/mantis/mantis_uart.c
deleted file mode 100644
index 18340da..0000000
--- a/drivers/media/dvb/mantis/mantis_uart.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <asm/io.h>
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "mantis_common.h"
-#include "mantis_reg.h"
-#include "mantis_uart.h"
-
-struct mantis_uart_params {
-	enum mantis_baud	baud_rate;
-	enum mantis_parity	parity;
-};
-
-static struct {
-	char string[7];
-} rates[5] = {
-	{ "9600" },
-	{ "19200" },
-	{ "38400" },
-	{ "57600" },
-	{ "115200" }
-};
-
-static struct {
-	char string[5];
-} parity[3] = {
-	{ "NONE" },
-	{ "ODD" },
-	{ "EVEN" }
-};
-
-#define UART_MAX_BUF			16
-
-int mantis_uart_read(struct mantis_pci *mantis, u8 *data)
-{
-	struct mantis_hwconfig *config = mantis->hwconfig;
-	u32 stat = 0, i;
-
-	/* get data */
-	for (i = 0; i < (config->bytes + 1); i++) {
-
-		stat = mmread(MANTIS_UART_STAT);
-
-		if (stat & MANTIS_UART_RXFIFO_FULL) {
-			dprintk(MANTIS_ERROR, 1, "RX Fifo FULL");
-		}
-		data[i] = mmread(MANTIS_UART_RXD) & 0x3f;
-
-		dprintk(MANTIS_DEBUG, 1, "Reading ... <%02x>", data[i] & 0x3f);
-
-		if (data[i] & (1 << 7)) {
-			dprintk(MANTIS_ERROR, 1, "UART framing error");
-			return -EINVAL;
-		}
-		if (data[i] & (1 << 6)) {
-			dprintk(MANTIS_ERROR, 1, "UART parity error");
-			return -EINVAL;
-		}
-	}
-
-	return 0;
-}
-
-static void mantis_uart_work(struct work_struct *work)
-{
-	struct mantis_pci *mantis = container_of(work, struct mantis_pci, uart_work);
-	struct mantis_hwconfig *config = mantis->hwconfig;
-	u8 buf[16];
-	int i;
-
-	mantis_uart_read(mantis, buf);
-
-	for (i = 0; i < (config->bytes + 1); i++)
-		dprintk(MANTIS_INFO, 1, "UART BUF:%d <%02x> ", i, buf[i]);
-
-	dprintk(MANTIS_DEBUG, 0, "\n");
-}
-
-static int mantis_uart_setup(struct mantis_pci *mantis,
-			     struct mantis_uart_params *params)
-{
-	u32 reg;
-
-	mmwrite((mmread(MANTIS_UART_CTL) | (params->parity & 0x3)), MANTIS_UART_CTL);
-
-	reg = mmread(MANTIS_UART_BAUD);
-
-	switch (params->baud_rate) {
-	case MANTIS_BAUD_9600:
-		reg |= 0xd8;
-		break;
-	case MANTIS_BAUD_19200:
-		reg |= 0x6c;
-		break;
-	case MANTIS_BAUD_38400:
-		reg |= 0x36;
-		break;
-	case MANTIS_BAUD_57600:
-		reg |= 0x23;
-		break;
-	case MANTIS_BAUD_115200:
-		reg |= 0x11;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	mmwrite(reg, MANTIS_UART_BAUD);
-
-	return 0;
-}
-
-int mantis_uart_init(struct mantis_pci *mantis)
-{
-	struct mantis_hwconfig *config = mantis->hwconfig;
-	struct mantis_uart_params params;
-
-	/* default parity: */
-	params.baud_rate = config->baud_rate;
-	params.parity = config->parity;
-	dprintk(MANTIS_INFO, 1, "Initializing UART @ %sbps parity:%s",
-		rates[params.baud_rate].string,
-		parity[params.parity].string);
-
-	init_waitqueue_head(&mantis->uart_wq);
-	spin_lock_init(&mantis->uart_lock);
-
-	INIT_WORK(&mantis->uart_work, mantis_uart_work);
-
-	/* disable interrupt */
-	mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL);
-
-	mantis_uart_setup(mantis, &params);
-
-	/* default 1 byte */
-	mmwrite((mmread(MANTIS_UART_BAUD) | (config->bytes << 8)), MANTIS_UART_BAUD);
-
-	/* flush buffer */
-	mmwrite((mmread(MANTIS_UART_CTL) | MANTIS_UART_RXFLUSH), MANTIS_UART_CTL);
-
-	/* enable interrupt */
-	mmwrite(mmread(MANTIS_INT_MASK) | 0x800, MANTIS_INT_MASK);
-	mmwrite(mmread(MANTIS_UART_CTL) | MANTIS_UART_RXINT, MANTIS_UART_CTL);
-
-	schedule_work(&mantis->uart_work);
-	dprintk(MANTIS_DEBUG, 1, "UART successfully initialized");
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(mantis_uart_init);
-
-void mantis_uart_exit(struct mantis_pci *mantis)
-{
-	/* disable interrupt */
-	mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL);
-	flush_work_sync(&mantis->uart_work);
-}
-EXPORT_SYMBOL_GPL(mantis_uart_exit);
diff --git a/drivers/media/dvb/mantis/mantis_uart.h b/drivers/media/dvb/mantis/mantis_uart.h
deleted file mode 100644
index ffb62a0..0000000
--- a/drivers/media/dvb/mantis/mantis_uart.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-	Mantis PCI bridge driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_UART_H
-#define __MANTIS_UART_H
-
-#define MANTIS_UART_CTL			0xe0
-#define MANTIS_UART_RXINT		(1 << 4)
-#define MANTIS_UART_RXFLUSH		(1 << 2)
-
-#define MANTIS_UART_RXD			0xe8
-#define MANTIS_UART_BAUD		0xec
-
-#define MANTIS_UART_STAT		0xf0
-#define MANTIS_UART_RXFIFO_DATA		(1 << 7)
-#define MANTIS_UART_RXFIFO_EMPTY	(1 << 6)
-#define MANTIS_UART_RXFIFO_FULL		(1 << 3)
-#define MANTIS_UART_FRAME_ERR		(1 << 2)
-#define MANTIS_UART_PARITY_ERR		(1 << 1)
-#define MANTIS_UART_RXTHRESH_INT	(1 << 0)
-
-enum mantis_baud {
-	MANTIS_BAUD_9600	= 0,
-	MANTIS_BAUD_19200,
-	MANTIS_BAUD_38400,
-	MANTIS_BAUD_57600,
-	MANTIS_BAUD_115200
-};
-
-enum mantis_parity {
-	MANTIS_PARITY_NONE	= 0,
-	MANTIS_PARITY_EVEN,
-	MANTIS_PARITY_ODD,
-};
-
-struct mantis_pci;
-
-extern int mantis_uart_init(struct mantis_pci *mantis);
-extern void mantis_uart_exit(struct mantis_pci *mantis);
-
-#endif /* __MANTIS_UART_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp1033.c b/drivers/media/dvb/mantis/mantis_vp1033.c
deleted file mode 100644
index ad013e9..0000000
--- a/drivers/media/dvb/mantis/mantis_vp1033.c
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
-	Mantis VP-1033 driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "stv0299.h"
-#include "mantis_common.h"
-#include "mantis_ioc.h"
-#include "mantis_dvb.h"
-#include "mantis_vp1033.h"
-#include "mantis_reg.h"
-
-u8 lgtdqcs001f_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x30,
-	0x03, 0x00,
-	0x04, 0x2a,
-	0x05, 0x85,
-	0x06, 0x02,
-	0x07, 0x00,
-	0x08, 0x00,
-	0x0c, 0x01,
-	0x0d, 0x81,
-	0x0e, 0x44,
-	0x0f, 0x94,
-	0x10, 0x3c,
-	0x11, 0x84,
-	0x12, 0xb9,
-	0x13, 0xb5,
-	0x14, 0x4f,
-	0x15, 0xc9,
-	0x16, 0x80,
-	0x17, 0x36,
-	0x18, 0xfb,
-	0x19, 0xcf,
-	0x1a, 0xbc,
-	0x1c, 0x2b,
-	0x1d, 0x27,
-	0x1e, 0x00,
-	0x1f, 0x0b,
-	0x20, 0xa1,
-	0x21, 0x60,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x28, 0x00,
-	0x29, 0x28,
-	0x2a, 0x14,
-	0x2b, 0x0f,
-	0x2c, 0x09,
-	0x2d, 0x05,
-	0x31, 0x1f,
-	0x32, 0x19,
-	0x33, 0xfc,
-	0x34, 0x13,
-	0xff, 0xff,
-};
-
-#define MANTIS_MODEL_NAME	"VP-1033"
-#define MANTIS_DEV_TYPE		"DVB-S/DSS"
-
-int lgtdqcs001f_tuner_set(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct mantis_pci *mantis	= fe->dvb->priv;
-	struct i2c_adapter *adapter	= &mantis->adapter;
-
-	u8 buf[4];
-	u32 div;
-
-
-	struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf)};
-
-	div = p->frequency / 250;
-
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] =  div & 0xff;
-	buf[2] =  0x83;
-	buf[3] =  0xc0;
-
-	if (p->frequency < 1531000)
-		buf[3] |= 0x04;
-	else
-		buf[3] &= ~0x04;
-	if (i2c_transfer(adapter, &msg, 1) < 0) {
-		dprintk(MANTIS_ERROR, 1, "Write: I2C Transfer failed");
-		return -EIO;
-	}
-	msleep_interruptible(100);
-
-	return 0;
-}
-
-int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe,
-				u32 srate, u32 ratio)
-{
-	u8 aclk = 0;
-	u8 bclk = 0;
-
-	if (srate < 1500000) {
-		aclk = 0xb7;
-		bclk = 0x47;
-	} else if (srate < 3000000) {
-		aclk = 0xb7;
-		bclk = 0x4b;
-	} else if (srate < 7000000) {
-		aclk = 0xb7;
-		bclk = 0x4f;
-	} else if (srate < 14000000) {
-		aclk = 0xb7;
-		bclk = 0x53;
-	} else if (srate < 30000000) {
-		aclk = 0xb6;
-		bclk = 0x53;
-	} else if (srate < 45000000) {
-		aclk = 0xb4;
-		bclk = 0x51;
-	}
-	stv0299_writereg(fe, 0x13, aclk);
-	stv0299_writereg(fe, 0x14, bclk);
-
-	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
-	stv0299_writereg(fe, 0x20, (ratio >>  8) & 0xff);
-	stv0299_writereg(fe, 0x21,  ratio & 0xf0);
-
-	return 0;
-}
-
-struct stv0299_config lgtdqcs001f_config = {
-	.demod_address		= 0x68,
-	.inittab		= lgtdqcs001f_inittab,
-	.mclk			= 88000000UL,
-	.invert			= 0,
-	.skip_reinit		= 0,
-	.volt13_op0_op1		= STV0299_VOLT13_OP0,
-	.min_delay_ms		= 100,
-	.set_symbol_rate	= lgtdqcs001f_set_symbol_rate,
-};
-
-static int vp1033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
-{
-	struct i2c_adapter *adapter	= &mantis->adapter;
-
-	int err = 0;
-
-	err = mantis_frontend_power(mantis, POWER_ON);
-	if (err == 0) {
-		mantis_frontend_soft_reset(mantis);
-		msleep(250);
-
-		dprintk(MANTIS_ERROR, 1, "Probing for STV0299 (DVB-S)");
-		fe = dvb_attach(stv0299_attach, &lgtdqcs001f_config, adapter);
-
-		if (fe) {
-			fe->ops.tuner_ops.set_params = lgtdqcs001f_tuner_set;
-			dprintk(MANTIS_ERROR, 1, "found STV0299 DVB-S frontend @ 0x%02x",
-				lgtdqcs001f_config.demod_address);
-
-			dprintk(MANTIS_ERROR, 1, "Mantis DVB-S STV0299 frontend attach success");
-		} else {
-			return -1;
-		}
-	} else {
-		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
-			adapter->name,
-			err);
-
-		return -EIO;
-	}
-	mantis->fe = fe;
-	dprintk(MANTIS_ERROR, 1, "Done!");
-
-	return 0;
-}
-
-struct mantis_hwconfig vp1033_config = {
-	.model_name		= MANTIS_MODEL_NAME,
-	.dev_type		= MANTIS_DEV_TYPE,
-	.ts_size		= MANTIS_TS_204,
-
-	.baud_rate		= MANTIS_BAUD_9600,
-	.parity			= MANTIS_PARITY_NONE,
-	.bytes			= 0,
-
-	.frontend_init		= vp1033_frontend_init,
-	.power			= GPIF_A12,
-	.reset			= GPIF_A13,
-};
diff --git a/drivers/media/dvb/mantis/mantis_vp1033.h b/drivers/media/dvb/mantis/mantis_vp1033.h
deleted file mode 100644
index 7daaa1b..0000000
--- a/drivers/media/dvb/mantis/mantis_vp1033.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-	Mantis VP-1033 driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_VP1033_H
-#define __MANTIS_VP1033_H
-
-#include "mantis_common.h"
-
-#define MANTIS_VP_1033_DVB_S	0x0016
-
-extern struct mantis_hwconfig vp1033_config;
-
-#endif /* __MANTIS_VP1033_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp1034.c b/drivers/media/dvb/mantis/mantis_vp1034.c
deleted file mode 100644
index 430ae84..0000000
--- a/drivers/media/dvb/mantis/mantis_vp1034.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
-	Mantis VP-1034 driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "mb86a16.h"
-#include "mantis_common.h"
-#include "mantis_ioc.h"
-#include "mantis_dvb.h"
-#include "mantis_vp1034.h"
-#include "mantis_reg.h"
-
-struct mb86a16_config vp1034_mb86a16_config = {
-	.demod_address	= 0x08,
-	.set_voltage	= vp1034_set_voltage,
-};
-
-#define MANTIS_MODEL_NAME	"VP-1034"
-#define MANTIS_DEV_TYPE		"DVB-S/DSS"
-
-int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
-	struct mantis_pci *mantis = fe->dvb->priv;
-
-	switch (voltage) {
-	case SEC_VOLTAGE_13:
-		dprintk(MANTIS_ERROR, 1, "Polarization=[13V]");
-		mantis_gpio_set_bits(mantis, 13, 1);
-		mantis_gpio_set_bits(mantis, 14, 0);
-		break;
-	case SEC_VOLTAGE_18:
-		dprintk(MANTIS_ERROR, 1, "Polarization=[18V]");
-		mantis_gpio_set_bits(mantis, 13, 1);
-		mantis_gpio_set_bits(mantis, 14, 1);
-		break;
-	case SEC_VOLTAGE_OFF:
-		dprintk(MANTIS_ERROR, 1, "Frontend (dummy) POWERDOWN");
-		break;
-	default:
-		dprintk(MANTIS_ERROR, 1, "Invalid = (%d)", (u32) voltage);
-		return -EINVAL;
-	}
-	mmwrite(0x00, MANTIS_GPIF_DOUT);
-
-	return 0;
-}
-
-static int vp1034_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
-{
-	struct i2c_adapter *adapter	= &mantis->adapter;
-
-	int err = 0;
-
-	err = mantis_frontend_power(mantis, POWER_ON);
-	if (err == 0) {
-		mantis_frontend_soft_reset(mantis);
-		msleep(250);
-
-		dprintk(MANTIS_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)");
-		fe = dvb_attach(mb86a16_attach, &vp1034_mb86a16_config, adapter);
-		if (fe) {
-			dprintk(MANTIS_ERROR, 1,
-			"found MB86A16 DVB-S/DSS frontend @0x%02x",
-			vp1034_mb86a16_config.demod_address);
-
-		} else {
-			return -1;
-		}
-	} else {
-		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
-			adapter->name,
-			err);
-
-		return -EIO;
-	}
-	mantis->fe = fe;
-	dprintk(MANTIS_ERROR, 1, "Done!");
-
-	return 0;
-}
-
-struct mantis_hwconfig vp1034_config = {
-	.model_name	= MANTIS_MODEL_NAME,
-	.dev_type	= MANTIS_DEV_TYPE,
-	.ts_size	= MANTIS_TS_204,
-
-	.baud_rate	= MANTIS_BAUD_9600,
-	.parity		= MANTIS_PARITY_NONE,
-	.bytes		= 0,
-
-	.frontend_init	= vp1034_frontend_init,
-	.power		= GPIF_A12,
-	.reset		= GPIF_A13,
-};
diff --git a/drivers/media/dvb/mantis/mantis_vp1034.h b/drivers/media/dvb/mantis/mantis_vp1034.h
deleted file mode 100644
index 323f38e..0000000
--- a/drivers/media/dvb/mantis/mantis_vp1034.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
-	Mantis VP-1034 driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_VP1034_H
-#define __MANTIS_VP1034_H
-
-#include "dvb_frontend.h"
-#include "mantis_common.h"
-
-
-#define MANTIS_VP_1034_DVB_S	0x0014
-
-extern struct mantis_hwconfig vp1034_config;
-extern int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
-
-#endif /* __MANTIS_VP1034_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp1041.c b/drivers/media/dvb/mantis/mantis_vp1041.c
deleted file mode 100644
index 07aa887..0000000
--- a/drivers/media/dvb/mantis/mantis_vp1041.c
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
-	Mantis VP-1041 driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "mantis_common.h"
-#include "mantis_ioc.h"
-#include "mantis_dvb.h"
-#include "mantis_vp1041.h"
-#include "stb0899_reg.h"
-#include "stb0899_drv.h"
-#include "stb0899_cfg.h"
-#include "stb6100_cfg.h"
-#include "stb6100.h"
-#include "lnbp21.h"
-
-#define MANTIS_MODEL_NAME	"VP-1041"
-#define MANTIS_DEV_TYPE		"DSS/DVB-S/DVB-S2"
-
-static const struct stb0899_s1_reg vp1041_stb0899_s1_init_1[] = {
-
-	/* 0x0000000b, *//* SYSREG */
-	{ STB0899_DEV_ID		, 0x30 },
-	{ STB0899_DISCNTRL1		, 0x32 },
-	{ STB0899_DISCNTRL2     	, 0x80 },
-	{ STB0899_DISRX_ST0     	, 0x04 },
-	{ STB0899_DISRX_ST1     	, 0x00 },
-	{ STB0899_DISPARITY     	, 0x00 },
-	{ STB0899_DISSTATUS		, 0x20 },
-	{ STB0899_DISF22        	, 0x99 },
-	{ STB0899_DISF22RX      	, 0xa8 },
-	/* SYSREG ? */
-	{ STB0899_ACRPRESC      	, 0x11 },
-	{ STB0899_ACRDIV1       	, 0x0a },
-	{ STB0899_ACRDIV2       	, 0x05 },
-	{ STB0899_DACR1         	, 0x00 },
-	{ STB0899_DACR2         	, 0x00 },
-	{ STB0899_OUTCFG        	, 0x00 },
-	{ STB0899_MODECFG       	, 0x00 },
-	{ STB0899_IRQSTATUS_3		, 0xfe },
-	{ STB0899_IRQSTATUS_2		, 0x03 },
-	{ STB0899_IRQSTATUS_1		, 0x7c },
-	{ STB0899_IRQSTATUS_0		, 0xf4 },
-	{ STB0899_IRQMSK_3      	, 0xf3 },
-	{ STB0899_IRQMSK_2      	, 0xfc },
-	{ STB0899_IRQMSK_1      	, 0xff },
-	{ STB0899_IRQMSK_0		, 0xff },
-	{ STB0899_IRQCFG		, 0x00 },
-	{ STB0899_I2CCFG        	, 0x88 },
-	{ STB0899_I2CRPT        	, 0x58 },
-	{ STB0899_IOPVALUE5		, 0x00 },
-	{ STB0899_IOPVALUE4		, 0x33 },
-	{ STB0899_IOPVALUE3		, 0x6d },
-	{ STB0899_IOPVALUE2		, 0x90 },
-	{ STB0899_IOPVALUE1		, 0x60 },
-	{ STB0899_IOPVALUE0		, 0x00 },
-	{ STB0899_GPIO00CFG     	, 0x82 },
-	{ STB0899_GPIO01CFG     	, 0x82 },
-	{ STB0899_GPIO02CFG     	, 0x82 },
-	{ STB0899_GPIO03CFG     	, 0x82 },
-	{ STB0899_GPIO04CFG     	, 0x82 },
-	{ STB0899_GPIO05CFG     	, 0x82 },
-	{ STB0899_GPIO06CFG     	, 0x82 },
-	{ STB0899_GPIO07CFG     	, 0x82 },
-	{ STB0899_GPIO08CFG     	, 0x82 },
-	{ STB0899_GPIO09CFG     	, 0x82 },
-	{ STB0899_GPIO10CFG     	, 0x82 },
-	{ STB0899_GPIO11CFG     	, 0x82 },
-	{ STB0899_GPIO12CFG     	, 0x82 },
-	{ STB0899_GPIO13CFG     	, 0x82 },
-	{ STB0899_GPIO14CFG     	, 0x82 },
-	{ STB0899_GPIO15CFG     	, 0x82 },
-	{ STB0899_GPIO16CFG     	, 0x82 },
-	{ STB0899_GPIO17CFG     	, 0x82 },
-	{ STB0899_GPIO18CFG     	, 0x82 },
-	{ STB0899_GPIO19CFG     	, 0x82 },
-	{ STB0899_GPIO20CFG     	, 0x82 },
-	{ STB0899_SDATCFG       	, 0xb8 },
-	{ STB0899_SCLTCFG       	, 0xba },
-	{ STB0899_AGCRFCFG      	, 0x1c }, /* 0x11 */
-	{ STB0899_GPIO22        	, 0x82 }, /* AGCBB2CFG */
-	{ STB0899_GPIO21        	, 0x91 }, /* AGCBB1CFG */
-	{ STB0899_DIRCLKCFG     	, 0x82 },
-	{ STB0899_CLKOUT27CFG   	, 0x7e },
-	{ STB0899_STDBYCFG      	, 0x82 },
-	{ STB0899_CS0CFG        	, 0x82 },
-	{ STB0899_CS1CFG        	, 0x82 },
-	{ STB0899_DISEQCOCFG    	, 0x20 },
-	{ STB0899_GPIO32CFG		, 0x82 },
-	{ STB0899_GPIO33CFG		, 0x82 },
-	{ STB0899_GPIO34CFG		, 0x82 },
-	{ STB0899_GPIO35CFG		, 0x82 },
-	{ STB0899_GPIO36CFG		, 0x82 },
-	{ STB0899_GPIO37CFG		, 0x82 },
-	{ STB0899_GPIO38CFG		, 0x82 },
-	{ STB0899_GPIO39CFG		, 0x82 },
-	{ STB0899_NCOARSE       	, 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
-	{ STB0899_SYNTCTRL      	, 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
-	{ STB0899_FILTCTRL      	, 0x00 },
-	{ STB0899_SYSCTRL       	, 0x01 },
-	{ STB0899_STOPCLK1      	, 0x20 },
-	{ STB0899_STOPCLK2      	, 0x00 },
-	{ STB0899_INTBUFSTATUS		, 0x00 },
-	{ STB0899_INTBUFCTRL    	, 0x0a },
-	{ 0xffff			, 0xff },
-};
-
-static const struct stb0899_s1_reg vp1041_stb0899_s1_init_3[] = {
-	{ STB0899_DEMOD         	, 0x00 },
-	{ STB0899_RCOMPC        	, 0xc9 },
-	{ STB0899_AGC1CN        	, 0x01 },
-	{ STB0899_AGC1REF       	, 0x10 },
-	{ STB0899_RTC			, 0x23 },
-	{ STB0899_TMGCFG        	, 0x4e },
-	{ STB0899_AGC2REF       	, 0x34 },
-	{ STB0899_TLSR          	, 0x84 },
-	{ STB0899_CFD           	, 0xf7 },
-	{ STB0899_ACLC			, 0x87 },
-	{ STB0899_BCLC          	, 0x94 },
-	{ STB0899_EQON          	, 0x41 },
-	{ STB0899_LDT           	, 0xf1 },
-	{ STB0899_LDT2          	, 0xe3 },
-	{ STB0899_EQUALREF      	, 0xb4 },
-	{ STB0899_TMGRAMP       	, 0x10 },
-	{ STB0899_TMGTHD        	, 0x30 },
-	{ STB0899_IDCCOMP		, 0xfd },
-	{ STB0899_QDCCOMP		, 0xff },
-	{ STB0899_POWERI		, 0x0c },
-	{ STB0899_POWERQ		, 0x0f },
-	{ STB0899_RCOMP			, 0x6c },
-	{ STB0899_AGCIQIN		, 0x80 },
-	{ STB0899_AGC2I1		, 0x06 },
-	{ STB0899_AGC2I2		, 0x00 },
-	{ STB0899_TLIR			, 0x30 },
-	{ STB0899_RTF			, 0x7f },
-	{ STB0899_DSTATUS		, 0x00 },
-	{ STB0899_LDI			, 0xbc },
-	{ STB0899_CFRM			, 0xea },
-	{ STB0899_CFRL			, 0x31 },
-	{ STB0899_NIRM			, 0x2b },
-	{ STB0899_NIRL			, 0x80 },
-	{ STB0899_ISYMB			, 0x1d },
-	{ STB0899_QSYMB			, 0xa6 },
-	{ STB0899_SFRH          	, 0x2f },
-	{ STB0899_SFRM          	, 0x68 },
-	{ STB0899_SFRL          	, 0x40 },
-	{ STB0899_SFRUPH        	, 0x2f },
-	{ STB0899_SFRUPM        	, 0x68 },
-	{ STB0899_SFRUPL        	, 0x40 },
-	{ STB0899_EQUAI1		, 0x02 },
-	{ STB0899_EQUAQ1		, 0xff },
-	{ STB0899_EQUAI2		, 0x04 },
-	{ STB0899_EQUAQ2		, 0x05 },
-	{ STB0899_EQUAI3		, 0x02 },
-	{ STB0899_EQUAQ3		, 0xfd },
-	{ STB0899_EQUAI4		, 0x03 },
-	{ STB0899_EQUAQ4		, 0x07 },
-	{ STB0899_EQUAI5		, 0x08 },
-	{ STB0899_EQUAQ5		, 0xf5 },
-	{ STB0899_DSTATUS2		, 0x00 },
-	{ STB0899_VSTATUS       	, 0x00 },
-	{ STB0899_VERROR		, 0x86 },
-	{ STB0899_IQSWAP		, 0x2a },
-	{ STB0899_ECNT1M		, 0x00 },
-	{ STB0899_ECNT1L		, 0x00 },
-	{ STB0899_ECNT2M		, 0x00 },
-	{ STB0899_ECNT2L		, 0x00 },
-	{ STB0899_ECNT3M		, 0x0a },
-	{ STB0899_ECNT3L		, 0xad },
-	{ STB0899_FECAUTO1      	, 0x06 },
-	{ STB0899_FECM			, 0x01 },
-	{ STB0899_VTH12         	, 0xb0 },
-	{ STB0899_VTH23         	, 0x7a },
-	{ STB0899_VTH34			, 0x58 },
-	{ STB0899_VTH56         	, 0x38 },
-	{ STB0899_VTH67         	, 0x34 },
-	{ STB0899_VTH78         	, 0x24 },
-	{ STB0899_PRVIT         	, 0xff },
-	{ STB0899_VITSYNC       	, 0x19 },
-	{ STB0899_RSULC         	, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
-	{ STB0899_TSULC         	, 0x42 },
-	{ STB0899_RSLLC         	, 0x41 },
-	{ STB0899_TSLPL			, 0x12 },
-	{ STB0899_TSCFGH        	, 0x0c },
-	{ STB0899_TSCFGM        	, 0x00 },
-	{ STB0899_TSCFGL        	, 0x00 },
-	{ STB0899_TSOUT			, 0x69 }, /* 0x0d for CAM */
-	{ STB0899_RSSYNCDEL     	, 0x00 },
-	{ STB0899_TSINHDELH     	, 0x02 },
-	{ STB0899_TSINHDELM		, 0x00 },
-	{ STB0899_TSINHDELL		, 0x00 },
-	{ STB0899_TSLLSTKM		, 0x1b },
-	{ STB0899_TSLLSTKL		, 0xb3 },
-	{ STB0899_TSULSTKM		, 0x00 },
-	{ STB0899_TSULSTKL		, 0x00 },
-	{ STB0899_PCKLENUL		, 0xbc },
-	{ STB0899_PCKLENLL		, 0xcc },
-	{ STB0899_RSPCKLEN		, 0xbd },
-	{ STB0899_TSSTATUS		, 0x90 },
-	{ STB0899_ERRCTRL1      	, 0xb6 },
-	{ STB0899_ERRCTRL2      	, 0x95 },
-	{ STB0899_ERRCTRL3      	, 0x8d },
-	{ STB0899_DMONMSK1		, 0x27 },
-	{ STB0899_DMONMSK0		, 0x03 },
-	{ STB0899_DEMAPVIT      	, 0x5c },
-	{ STB0899_PLPARM		, 0x19 },
-	{ STB0899_PDELCTRL      	, 0x48 },
-	{ STB0899_PDELCTRL2     	, 0x00 },
-	{ STB0899_BBHCTRL1      	, 0x00 },
-	{ STB0899_BBHCTRL2      	, 0x00 },
-	{ STB0899_HYSTTHRESH    	, 0x77 },
-	{ STB0899_MATCSTM		, 0x00 },
-	{ STB0899_MATCSTL		, 0x00 },
-	{ STB0899_UPLCSTM		, 0x00 },
-	{ STB0899_UPLCSTL		, 0x00 },
-	{ STB0899_DFLCSTM		, 0x00 },
-	{ STB0899_DFLCSTL		, 0x00 },
-	{ STB0899_SYNCCST		, 0x00 },
-	{ STB0899_SYNCDCSTM		, 0x00 },
-	{ STB0899_SYNCDCSTL		, 0x00 },
-	{ STB0899_ISI_ENTRY		, 0x00 },
-	{ STB0899_ISI_BIT_EN		, 0x00 },
-	{ STB0899_MATSTRM		, 0xf0 },
-	{ STB0899_MATSTRL		, 0x02 },
-	{ STB0899_UPLSTRM		, 0x45 },
-	{ STB0899_UPLSTRL		, 0x60 },
-	{ STB0899_DFLSTRM		, 0xe3 },
-	{ STB0899_DFLSTRL		, 0x00 },
-	{ STB0899_SYNCSTR		, 0x47 },
-	{ STB0899_SYNCDSTRM		, 0x05 },
-	{ STB0899_SYNCDSTRL		, 0x18 },
-	{ STB0899_CFGPDELSTATUS1	, 0x19 },
-	{ STB0899_CFGPDELSTATUS2	, 0x2b },
-	{ STB0899_BBFERRORM		, 0x00 },
-	{ STB0899_BBFERRORL		, 0x01 },
-	{ STB0899_UPKTERRORM		, 0x00 },
-	{ STB0899_UPKTERRORL		, 0x00 },
-	{ 0xffff			, 0xff },
-};
-
-struct stb0899_config vp1041_stb0899_config = {
-	.init_dev		= vp1041_stb0899_s1_init_1,
-	.init_s2_demod		= stb0899_s2_init_2,
-	.init_s1_demod		= vp1041_stb0899_s1_init_3,
-	.init_s2_fec		= stb0899_s2_init_4,
-	.init_tst		= stb0899_s1_init_5,
-
-	.demod_address 		= 0x68, /*  0xd0 >> 1 */
-
-	.xtal_freq		= 27000000,
-	.inversion		= IQ_SWAP_ON, /* 1 */
-
-	.lo_clk			= 76500000,
-	.hi_clk			= 99000000,
-
-	.esno_ave		= STB0899_DVBS2_ESNO_AVE,
-	.esno_quant		= STB0899_DVBS2_ESNO_QUANT,
-	.avframes_coarse	= STB0899_DVBS2_AVFRAMES_COARSE,
-	.avframes_fine		= STB0899_DVBS2_AVFRAMES_FINE,
-	.miss_threshold		= STB0899_DVBS2_MISS_THRESHOLD,
-	.uwp_threshold_acq	= STB0899_DVBS2_UWP_THRESHOLD_ACQ,
-	.uwp_threshold_track	= STB0899_DVBS2_UWP_THRESHOLD_TRACK,
-	.uwp_threshold_sof	= STB0899_DVBS2_UWP_THRESHOLD_SOF,
-	.sof_search_timeout	= STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
-
-	.btr_nco_bits		= STB0899_DVBS2_BTR_NCO_BITS,
-	.btr_gain_shift_offset	= STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
-	.crl_nco_bits		= STB0899_DVBS2_CRL_NCO_BITS,
-	.ldpc_max_iter		= STB0899_DVBS2_LDPC_MAX_ITER,
-
-	.tuner_get_frequency	= stb6100_get_frequency,
-	.tuner_set_frequency	= stb6100_set_frequency,
-	.tuner_set_bandwidth	= stb6100_set_bandwidth,
-	.tuner_get_bandwidth	= stb6100_get_bandwidth,
-	.tuner_set_rfsiggain	= NULL,
-};
-
-struct stb6100_config vp1041_stb6100_config = {
-	.tuner_address	= 0x60,
-	.refclock	= 27000000,
-};
-
-static int vp1041_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
-{
-	struct i2c_adapter *adapter	= &mantis->adapter;
-
-	int err = 0;
-
-	err = mantis_frontend_power(mantis, POWER_ON);
-	if (err == 0) {
-		mantis_frontend_soft_reset(mantis);
-		msleep(250);
-		mantis->fe = dvb_attach(stb0899_attach, &vp1041_stb0899_config, adapter);
-		if (mantis->fe) {
-			dprintk(MANTIS_ERROR, 1,
-				"found STB0899 DVB-S/DVB-S2 frontend @0x%02x",
-				vp1041_stb0899_config.demod_address);
-
-			if (dvb_attach(stb6100_attach, mantis->fe, &vp1041_stb6100_config, adapter)) {
-				if (!dvb_attach(lnbp21_attach, mantis->fe, adapter, 0, 0))
-					dprintk(MANTIS_ERROR, 1, "No LNBP21 found!");
-			}
-		} else {
-			return -EREMOTEIO;
-		}
-	} else {
-		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
-			adapter->name,
-			err);
-
-		return -EIO;
-	}
-
-
-	dprintk(MANTIS_ERROR, 1, "Done!");
-
-	return 0;
-}
-
-struct mantis_hwconfig vp1041_config = {
-	.model_name	= MANTIS_MODEL_NAME,
-	.dev_type	= MANTIS_DEV_TYPE,
-	.ts_size	= MANTIS_TS_188,
-
-	.baud_rate	= MANTIS_BAUD_9600,
-	.parity		= MANTIS_PARITY_NONE,
-	.bytes		= 0,
-
-	.frontend_init	= vp1041_frontend_init,
-	.power		= GPIF_A12,
-	.reset		= GPIF_A13,
-};
diff --git a/drivers/media/dvb/mantis/mantis_vp1041.h b/drivers/media/dvb/mantis/mantis_vp1041.h
deleted file mode 100644
index 1ae5b3d..0000000
--- a/drivers/media/dvb/mantis/mantis_vp1041.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
-	Mantis VP-1041 driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_VP1041_H
-#define __MANTIS_VP1041_H
-
-#include "mantis_common.h"
-
-#define MANTIS_VP_1041_DVB_S2	0x0031
-#define SKYSTAR_HD2_10		0x0001
-#define SKYSTAR_HD2_20		0x0003
-#define CINERGY_S2_PCI_HD	0x1179
-
-extern struct mantis_hwconfig vp1041_config;
-
-#endif /* __MANTIS_VP1041_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp2033.c b/drivers/media/dvb/mantis/mantis_vp2033.c
deleted file mode 100644
index 1ca6837..0000000
--- a/drivers/media/dvb/mantis/mantis_vp2033.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
-	Mantis VP-2033 driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "tda1002x.h"
-#include "mantis_common.h"
-#include "mantis_ioc.h"
-#include "mantis_dvb.h"
-#include "mantis_vp2033.h"
-
-#define MANTIS_MODEL_NAME	"VP-2033"
-#define MANTIS_DEV_TYPE		"DVB-C"
-
-struct tda1002x_config vp2033_tda1002x_cu1216_config = {
-	.demod_address = 0x18 >> 1,
-	.invert = 1,
-};
-
-struct tda10023_config vp2033_tda10023_cu1216_config = {
-	.demod_address = 0x18 >> 1,
-	.invert = 1,
-};
-
-static u8 read_pwm(struct mantis_pci *mantis)
-{
-	struct i2c_adapter *adapter = &mantis->adapter;
-
-	u8 b = 0xff;
-	u8 pwm;
-	struct i2c_msg msg[] = {
-		{.addr = 0x50, .flags = 0, .buf = &b, .len = 1},
-		{.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1}
-	};
-
-	if ((i2c_transfer(adapter, msg, 2) != 2)
-	    || (pwm == 0xff))
-		pwm = 0x48;
-
-	return pwm;
-}
-
-static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct mantis_pci *mantis = fe->dvb->priv;
-	struct i2c_adapter *adapter = &mantis->adapter;
-
-	u8 buf[6];
-	struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)};
-	int i;
-
-#define CU1216_IF 36125000
-#define TUNER_MUL 62500
-
-	u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
-
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = div & 0xff;
-	buf[2] = 0xce;
-	buf[3] = (p->frequency < 150000000 ? 0x01 :
-		  p->frequency < 445000000 ? 0x02 : 0x04);
-	buf[4] = 0xde;
-	buf[5] = 0x20;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	if (i2c_transfer(adapter, &msg, 1) != 1)
-		return -EIO;
-
-	/* wait for the pll lock */
-	msg.flags = I2C_M_RD;
-	msg.len = 1;
-	for (i = 0; i < 20; i++) {
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-
-		if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40))
-			break;
-
-		msleep(10);
-	}
-
-	/* switch the charge pump to the lower current */
-	msg.flags = 0;
-	msg.len = 2;
-	msg.buf = &buf[2];
-	buf[2] &= ~0x40;
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	if (i2c_transfer(adapter, &msg, 1) != 1)
-		return -EIO;
-
-	return 0;
-}
-
-static int vp2033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
-{
-	struct i2c_adapter *adapter = &mantis->adapter;
-
-	int err = 0;
-
-	err = mantis_frontend_power(mantis, POWER_ON);
-	if (err == 0) {
-		mantis_frontend_soft_reset(mantis);
-		msleep(250);
-
-		dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)");
-		fe = dvb_attach(tda10021_attach, &vp2033_tda1002x_cu1216_config,
-				     adapter,
-				     read_pwm(mantis));
-
-		if (fe) {
-			dprintk(MANTIS_ERROR, 1,
-				"found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x",
-				vp2033_tda1002x_cu1216_config.demod_address);
-		} else {
-			fe = dvb_attach(tda10023_attach, &vp2033_tda10023_cu1216_config,
-					     adapter,
-					     read_pwm(mantis));
-
-			if (fe) {
-				dprintk(MANTIS_ERROR, 1,
-					"found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x",
-					vp2033_tda1002x_cu1216_config.demod_address);
-			}
-		}
-
-		if (fe) {
-			fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set;
-			dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success");
-		} else {
-			return -1;
-		}
-	} else {
-		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
-			adapter->name,
-			err);
-
-		return -EIO;
-	}
-
-	mantis->fe = fe;
-	dprintk(MANTIS_DEBUG, 1, "Done!");
-
-	return 0;
-}
-
-struct mantis_hwconfig vp2033_config = {
-	.model_name	= MANTIS_MODEL_NAME,
-	.dev_type	= MANTIS_DEV_TYPE,
-	.ts_size	= MANTIS_TS_204,
-
-	.baud_rate	= MANTIS_BAUD_9600,
-	.parity		= MANTIS_PARITY_NONE,
-	.bytes		= 0,
-
-	.frontend_init	= vp2033_frontend_init,
-	.power		= GPIF_A12,
-	.reset		= GPIF_A13,
-};
diff --git a/drivers/media/dvb/mantis/mantis_vp2033.h b/drivers/media/dvb/mantis/mantis_vp2033.h
deleted file mode 100644
index c55242b..0000000
--- a/drivers/media/dvb/mantis/mantis_vp2033.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-	Mantis VP-2033 driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_VP2033_H
-#define __MANTIS_VP2033_H
-
-#include "mantis_common.h"
-
-#define MANTIS_VP_2033_DVB_C	0x0008
-
-extern struct mantis_hwconfig vp2033_config;
-
-#endif /* __MANTIS_VP2033_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp2040.c b/drivers/media/dvb/mantis/mantis_vp2040.c
deleted file mode 100644
index d480741..0000000
--- a/drivers/media/dvb/mantis/mantis_vp2040.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
-	Mantis VP-2040 driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "tda1002x.h"
-#include "mantis_common.h"
-#include "mantis_ioc.h"
-#include "mantis_dvb.h"
-#include "mantis_vp2040.h"
-
-#define MANTIS_MODEL_NAME	"VP-2040"
-#define MANTIS_DEV_TYPE		"DVB-C"
-
-struct tda1002x_config vp2040_tda1002x_cu1216_config = {
-	.demod_address	= 0x18 >> 1,
-	.invert		= 1,
-};
-
-struct tda10023_config vp2040_tda10023_cu1216_config = {
-	.demod_address	= 0x18 >> 1,
-	.invert		= 1,
-};
-
-static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct mantis_pci *mantis	= fe->dvb->priv;
-	struct i2c_adapter *adapter	= &mantis->adapter;
-
-	u8 buf[6];
-	struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)};
-	int i;
-
-#define CU1216_IF 36125000
-#define TUNER_MUL 62500
-
-	u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
-
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = div & 0xff;
-	buf[2] = 0xce;
-	buf[3] = (p->frequency < 150000000 ? 0x01 :
-		  p->frequency < 445000000 ? 0x02 : 0x04);
-	buf[4] = 0xde;
-	buf[5] = 0x20;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	if (i2c_transfer(adapter, &msg, 1) != 1)
-		return -EIO;
-
-	/* wait for the pll lock */
-	msg.flags = I2C_M_RD;
-	msg.len = 1;
-	for (i = 0; i < 20; i++) {
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-
-		if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40))
-			break;
-
-		msleep(10);
-	}
-
-	/* switch the charge pump to the lower current */
-	msg.flags = 0;
-	msg.len = 2;
-	msg.buf = &buf[2];
-	buf[2] &= ~0x40;
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	if (i2c_transfer(adapter, &msg, 1) != 1)
-		return -EIO;
-
-	return 0;
-}
-
-static u8 read_pwm(struct mantis_pci *mantis)
-{
-	struct i2c_adapter *adapter = &mantis->adapter;
-
-	u8 b = 0xff;
-	u8 pwm;
-	struct i2c_msg msg[] = {
-		{.addr = 0x50, .flags = 0, .buf = &b, .len = 1},
-		{.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1}
-	};
-
-	if ((i2c_transfer(adapter, msg, 2) != 2)
-	    || (pwm == 0xff))
-		pwm = 0x48;
-
-	return pwm;
-}
-
-static int vp2040_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
-{
-	struct i2c_adapter *adapter = &mantis->adapter;
-
-	int err = 0;
-
-	err = mantis_frontend_power(mantis, POWER_ON);
-	if (err == 0) {
-		mantis_frontend_soft_reset(mantis);
-		msleep(250);
-
-		dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)");
-		fe = dvb_attach(tda10021_attach, &vp2040_tda1002x_cu1216_config,
-				     adapter,
-				     read_pwm(mantis));
-
-		if (fe) {
-			dprintk(MANTIS_ERROR, 1,
-				"found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x",
-				vp2040_tda1002x_cu1216_config.demod_address);
-		} else {
-			fe = dvb_attach(tda10023_attach, &vp2040_tda10023_cu1216_config,
-					     adapter,
-					     read_pwm(mantis));
-
-			if (fe) {
-				dprintk(MANTIS_ERROR, 1,
-					"found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x",
-					vp2040_tda1002x_cu1216_config.demod_address);
-			}
-		}
-
-		if (fe) {
-			fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set;
-			dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success");
-		} else {
-			return -1;
-		}
-	} else {
-		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
-			adapter->name,
-			err);
-
-		return -EIO;
-	}
-	mantis->fe = fe;
-	dprintk(MANTIS_DEBUG, 1, "Done!");
-
-	return 0;
-}
-
-struct mantis_hwconfig vp2040_config = {
-	.model_name	= MANTIS_MODEL_NAME,
-	.dev_type	= MANTIS_DEV_TYPE,
-	.ts_size	= MANTIS_TS_204,
-
-	.baud_rate	= MANTIS_BAUD_9600,
-	.parity		= MANTIS_PARITY_NONE,
-	.bytes		= 0,
-
-	.frontend_init	= vp2040_frontend_init,
-	.power		= GPIF_A12,
-	.reset		= GPIF_A13,
-};
diff --git a/drivers/media/dvb/mantis/mantis_vp2040.h b/drivers/media/dvb/mantis/mantis_vp2040.h
deleted file mode 100644
index d125e21..0000000
--- a/drivers/media/dvb/mantis/mantis_vp2040.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-	Mantis VP-2040 driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_VP2040_H
-#define __MANTIS_VP2040_H
-
-#include "mantis_common.h"
-
-#define MANTIS_VP_2040_DVB_C	0x0043
-#define CINERGY_C		0x1178
-#define CABLESTAR_HD2		0x0002
-
-extern struct mantis_hwconfig vp2040_config;
-
-#endif /* __MANTIS_VP2040_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp3028.c b/drivers/media/dvb/mantis/mantis_vp3028.c
deleted file mode 100644
index 4155c83..0000000
--- a/drivers/media/dvb/mantis/mantis_vp3028.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-	Mantis VP-3028 driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "mantis_common.h"
-#include "mantis_vp3028.h"
-
-struct zl10353_config mantis_vp3028_config = {
-	.demod_address	= 0x0f,
-};
-
-#define MANTIS_MODEL_NAME	"VP-3028"
-#define MANTIS_DEV_TYPE		"DVB-T"
-
-struct mantis_hwconfig vp3028_mantis_config = {
-	.model_name	= MANTIS_MODEL_NAME,
-	.dev_type	= MANTIS_DEV_TYPE,
-	.ts_size	= MANTIS_TS_188,
-	.baud_rate	= MANTIS_BAUD_9600,
-	.parity		= MANTIS_PARITY_NONE,
-	.bytes		= 0,
-};
diff --git a/drivers/media/dvb/mantis/mantis_vp3028.h b/drivers/media/dvb/mantis/mantis_vp3028.h
deleted file mode 100644
index b07be6a..0000000
--- a/drivers/media/dvb/mantis/mantis_vp3028.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
-	Mantis VP-3028 driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_VP3028_H
-#define __MANTIS_VP3028_H
-
-#include "dvb_frontend.h"
-#include "mantis_common.h"
-#include "zl10353.h"
-
-#define MANTIS_VP_3028_DVB_T	0x0028
-
-extern struct zl10353_config mantis_vp3028_config;
-extern struct mantis_hwconfig vp3028_mantis_config;
-
-#endif /* __MANTIS_VP3028_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp3030.c b/drivers/media/dvb/mantis/mantis_vp3030.c
deleted file mode 100644
index c09308cd..0000000
--- a/drivers/media/dvb/mantis/mantis_vp3030.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
-	Mantis VP-3030 driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "zl10353.h"
-#include "tda665x.h"
-#include "mantis_common.h"
-#include "mantis_ioc.h"
-#include "mantis_dvb.h"
-#include "mantis_vp3030.h"
-
-struct zl10353_config mantis_vp3030_config = {
-	.demod_address		= 0x0f,
-};
-
-struct tda665x_config env57h12d5_config = {
-	.name			= "ENV57H12D5 (ET-50DT)",
-	.addr			= 0x60,
-	.frequency_min		=  47000000,
-	.frequency_max		= 862000000,
-	.frequency_offst	=   3616667,
-	.ref_multiplier		= 6, /* 1/6 MHz */
-	.ref_divider		= 100000, /* 1/6 MHz */
-};
-
-#define MANTIS_MODEL_NAME	"VP-3030"
-#define MANTIS_DEV_TYPE		"DVB-T"
-
-
-static int vp3030_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
-{
-	struct i2c_adapter *adapter	= &mantis->adapter;
-	struct mantis_hwconfig *config	= mantis->hwconfig;
-	int err = 0;
-
-	mantis_gpio_set_bits(mantis, config->reset, 0);
-	msleep(100);
-	err = mantis_frontend_power(mantis, POWER_ON);
-	msleep(100);
-	mantis_gpio_set_bits(mantis, config->reset, 1);
-
-	if (err == 0) {
-		msleep(250);
-		dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)");
-		fe = dvb_attach(zl10353_attach, &mantis_vp3030_config, adapter);
-
-		if (!fe)
-			return -1;
-
-		dvb_attach(tda665x_attach, fe, &env57h12d5_config, adapter);
-	} else {
-		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
-			adapter->name,
-			err);
-
-		return -EIO;
-
-	}
-	mantis->fe = fe;
-	dprintk(MANTIS_ERROR, 1, "Done!");
-
-	return 0;
-}
-
-struct mantis_hwconfig vp3030_config = {
-	.model_name	= MANTIS_MODEL_NAME,
-	.dev_type	= MANTIS_DEV_TYPE,
-	.ts_size	= MANTIS_TS_188,
-
-	.baud_rate	= MANTIS_BAUD_9600,
-	.parity		= MANTIS_PARITY_NONE,
-	.bytes		= 0,
-
-	.frontend_init	= vp3030_frontend_init,
-	.power		= GPIF_A12,
-	.reset		= GPIF_A13,
-
-	.i2c_mode	= MANTIS_BYTE_MODE
-};
diff --git a/drivers/media/dvb/mantis/mantis_vp3030.h b/drivers/media/dvb/mantis/mantis_vp3030.h
deleted file mode 100644
index 5f12c42..0000000
--- a/drivers/media/dvb/mantis/mantis_vp3030.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-	Mantis VP-3030 driver
-
-	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_VP3030_H
-#define __MANTIS_VP3030_H
-
-#include "mantis_common.h"
-
-#define MANTIS_VP_3030_DVB_T	0x0024
-
-extern struct mantis_hwconfig vp3030_config;
-
-#endif /* __MANTIS_VP3030_H */
diff --git a/drivers/media/dvb/ngene/Kconfig b/drivers/media/dvb/ngene/Kconfig
deleted file mode 100644
index 64c8470..0000000
--- a/drivers/media/dvb/ngene/Kconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-config DVB_NGENE
-	tristate "Micronas nGene support"
-	depends on DVB_CORE && PCI && I2C
-	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
-	select DVB_STV6110x if !DVB_FE_CUSTOMISE
-	select DVB_STV090x if !DVB_FE_CUSTOMISE
-	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
-	select DVB_DRXK if !DVB_FE_CUSTOMISE
-	select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE
-	---help---
-	  Support for Micronas PCI express cards with nGene bridge.
-
diff --git a/drivers/media/dvb/ngene/Makefile b/drivers/media/dvb/ngene/Makefile
deleted file mode 100644
index 13ebeff..0000000
--- a/drivers/media/dvb/ngene/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Makefile for the nGene device driver
-#
-
-ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o
-
-obj-$(CONFIG_DVB_NGENE) += ngene.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/
-ccflags-y += -Idrivers/media/dvb/frontends/
-ccflags-y += -Idrivers/media/common/tuners/
-
-# For the staging CI driver cxd2099
-ccflags-y += -Idrivers/staging/media/cxd2099/
diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c
deleted file mode 100644
index 72ee8de..0000000
--- a/drivers/media/dvb/ngene/ngene-cards.c
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
- * ngene-cards.c: nGene PCIe bridge driver - card specific info
- *
- * Copyright (C) 2005-2007 Micronas
- *
- * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
- *                         Modifications for new nGene firmware,
- *                         support for EEPROM-copying,
- *                         support for new dual DVB-S2 card prototype
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/pci_ids.h>
-
-#include "ngene.h"
-
-/* demods/tuners */
-#include "stv6110x.h"
-#include "stv090x.h"
-#include "lnbh24.h"
-#include "lgdt330x.h"
-#include "mt2131.h"
-#include "tda18271c2dd.h"
-#include "drxk.h"
-
-
-/****************************************************************************/
-/* Demod/tuner attachment ***************************************************/
-/****************************************************************************/
-
-static int tuner_attach_stv6110(struct ngene_channel *chan)
-{
-	struct i2c_adapter *i2c;
-	struct stv090x_config *feconf = (struct stv090x_config *)
-		chan->dev->card_info->fe_config[chan->number];
-	struct stv6110x_config *tunerconf = (struct stv6110x_config *)
-		chan->dev->card_info->tuner_config[chan->number];
-	struct stv6110x_devctl *ctl;
-
-	/* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
-	if (chan->number < 2)
-		i2c = &chan->dev->channel[0].i2c_adapter;
-	else
-		i2c = &chan->dev->channel[1].i2c_adapter;
-
-	ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c);
-	if (ctl == NULL) {
-		printk(KERN_ERR	DEVICE_NAME ": No STV6110X found!\n");
-		return -ENODEV;
-	}
-
-	feconf->tuner_init          = ctl->tuner_init;
-	feconf->tuner_sleep         = ctl->tuner_sleep;
-	feconf->tuner_set_mode      = ctl->tuner_set_mode;
-	feconf->tuner_set_frequency = ctl->tuner_set_frequency;
-	feconf->tuner_get_frequency = ctl->tuner_get_frequency;
-	feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth;
-	feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth;
-	feconf->tuner_set_bbgain    = ctl->tuner_set_bbgain;
-	feconf->tuner_get_bbgain    = ctl->tuner_get_bbgain;
-	feconf->tuner_set_refclk    = ctl->tuner_set_refclk;
-	feconf->tuner_get_status    = ctl->tuner_get_status;
-
-	return 0;
-}
-
-
-static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	struct ngene_channel *chan = fe->sec_priv;
-	int status;
-
-	if (enable) {
-		down(&chan->dev->pll_mutex);
-		status = chan->gate_ctrl(fe, 1);
-	} else {
-		status = chan->gate_ctrl(fe, 0);
-		up(&chan->dev->pll_mutex);
-	}
-	return status;
-}
-
-static int tuner_attach_tda18271(struct ngene_channel *chan)
-{
-	struct i2c_adapter *i2c;
-	struct dvb_frontend *fe;
-
-	i2c = &chan->dev->channel[0].i2c_adapter;
-	if (chan->fe->ops.i2c_gate_ctrl)
-		chan->fe->ops.i2c_gate_ctrl(chan->fe, 1);
-	fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60);
-	if (chan->fe->ops.i2c_gate_ctrl)
-		chan->fe->ops.i2c_gate_ctrl(chan->fe, 0);
-	if (!fe) {
-		printk(KERN_ERR "No TDA18271 found!\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static int tuner_attach_probe(struct ngene_channel *chan)
-{
-	if (chan->demod_type == 0)
-		return tuner_attach_stv6110(chan);
-	if (chan->demod_type == 1)
-		return tuner_attach_tda18271(chan);
-	return -EINVAL;
-}
-
-static int demod_attach_stv0900(struct ngene_channel *chan)
-{
-	struct i2c_adapter *i2c;
-	struct stv090x_config *feconf = (struct stv090x_config *)
-		chan->dev->card_info->fe_config[chan->number];
-
-	/* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
-	/* Note: Both adapters share the same i2c bus, but the demod     */
-	/*       driver requires that each demod has its own i2c adapter */
-	if (chan->number < 2)
-		i2c = &chan->dev->channel[0].i2c_adapter;
-	else
-		i2c = &chan->dev->channel[1].i2c_adapter;
-
-	chan->fe = dvb_attach(stv090x_attach, feconf, i2c,
-			(chan->number & 1) == 0 ? STV090x_DEMODULATOR_0
-						: STV090x_DEMODULATOR_1);
-	if (chan->fe == NULL) {
-		printk(KERN_ERR	DEVICE_NAME ": No STV0900 found!\n");
-		return -ENODEV;
-	}
-
-	/* store channel info */
-	if (feconf->tuner_i2c_lock)
-		chan->fe->analog_demod_priv = chan;
-
-	if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0,
-			0, chan->dev->card_info->lnb[chan->number])) {
-		printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n");
-		dvb_frontend_detach(chan->fe);
-		chan->fe = NULL;
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock)
-{
-	struct ngene_channel *chan = fe->analog_demod_priv;
-
-	if (lock)
-		down(&chan->dev->pll_mutex);
-	else
-		up(&chan->dev->pll_mutex);
-}
-
-static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
-{
-	struct i2c_msg msgs[1] = {{.addr = adr,  .flags = I2C_M_RD,
-				   .buf  = val,  .len   = 1 } };
-	return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
-}
-
-static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
-			  u16 reg, u8 *val)
-{
-	u8 msg[2] = {reg>>8, reg&0xff};
-	struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
-				   .buf  = msg, .len   = 2},
-				  {.addr = adr, .flags = I2C_M_RD,
-				   .buf  = val, .len   = 1} };
-	return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
-}
-
-static int port_has_stv0900(struct i2c_adapter *i2c, int port)
-{
-	u8 val;
-	if (i2c_read_reg16(i2c, 0x68+port/2, 0xf100, &val) < 0)
-		return 0;
-	return 1;
-}
-
-static int port_has_drxk(struct i2c_adapter *i2c, int port)
-{
-	u8 val;
-
-	if (i2c_read(i2c, 0x29+port, &val) < 0)
-		return 0;
-	return 1;
-}
-
-static int demod_attach_drxk(struct ngene_channel *chan,
-			     struct i2c_adapter *i2c)
-{
-	struct drxk_config config;
-
-	memset(&config, 0, sizeof(config));
-	config.microcode_name = "drxk_a3.mc";
-	config.qam_demod_parameter_count = 4;
-	config.adr = 0x29 + (chan->number ^ 2);
-
-	chan->fe = dvb_attach(drxk_attach, &config, i2c);
-	if (!chan->fe) {
-		printk(KERN_ERR "No DRXK found!\n");
-		return -ENODEV;
-	}
-	chan->fe->sec_priv = chan;
-	chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl;
-	chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
-	return 0;
-}
-
-static int cineS2_probe(struct ngene_channel *chan)
-{
-	struct i2c_adapter *i2c;
-	struct stv090x_config *fe_conf;
-	u8 buf[3];
-	struct i2c_msg i2c_msg = { .flags = 0, .buf = buf };
-	int rc;
-
-	/* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
-	if (chan->number < 2)
-		i2c = &chan->dev->channel[0].i2c_adapter;
-	else
-		i2c = &chan->dev->channel[1].i2c_adapter;
-
-	if (port_has_stv0900(i2c, chan->number)) {
-		chan->demod_type = 0;
-		fe_conf = chan->dev->card_info->fe_config[chan->number];
-		/* demod found, attach it */
-		rc = demod_attach_stv0900(chan);
-		if (rc < 0 || chan->number < 2)
-			return rc;
-
-		/* demod #2: reprogram outputs DPN1 & DPN2 */
-		i2c_msg.addr = fe_conf->address;
-		i2c_msg.len = 3;
-		buf[0] = 0xf1;
-		switch (chan->number) {
-		case 2:
-			buf[1] = 0x5c;
-			buf[2] = 0xc2;
-			break;
-		case 3:
-			buf[1] = 0x61;
-			buf[2] = 0xcc;
-			break;
-		default:
-			return -ENODEV;
-		}
-		rc = i2c_transfer(i2c, &i2c_msg, 1);
-		if (rc != 1) {
-			printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n");
-			return -EIO;
-		}
-	} else if (port_has_drxk(i2c, chan->number^2)) {
-		chan->demod_type = 1;
-		demod_attach_drxk(chan, i2c);
-	} else {
-		printk(KERN_ERR "No demod found on chan %d\n", chan->number);
-		return -ENODEV;
-	}
-	return 0;
-}
-
-
-static struct lgdt330x_config aver_m780 = {
-	.demod_address = 0xb2 >> 1,
-	.demod_chip    = LGDT3303,
-	.serial_mpeg   = 0x00, /* PARALLEL */
-	.clock_polarity_flip = 1,
-};
-
-static struct mt2131_config m780_tunerconfig = {
-	0xc0 >> 1
-};
-
-/* A single func to attach the demo and tuner, rather than
- * use two sep funcs like the current design mandates.
- */
-static int demod_attach_lg330x(struct ngene_channel *chan)
-{
-	chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, &chan->i2c_adapter);
-	if (chan->fe == NULL) {
-		printk(KERN_ERR	DEVICE_NAME ": No LGDT330x found!\n");
-		return -ENODEV;
-	}
-
-	dvb_attach(mt2131_attach, chan->fe, &chan->i2c_adapter,
-		   &m780_tunerconfig, 0);
-
-	return (chan->fe) ? 0 : -ENODEV;
-}
-
-/****************************************************************************/
-/* Switch control (I2C gates, etc.) *****************************************/
-/****************************************************************************/
-
-
-static struct stv090x_config fe_cineS2 = {
-	.device         = STV0900,
-	.demod_mode     = STV090x_DUAL,
-	.clk_mode       = STV090x_CLK_EXT,
-
-	.xtal           = 27000000,
-	.address        = 0x68,
-
-	.ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
-	.ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
-
-	.repeater_level = STV090x_RPTLEVEL_16,
-
-	.adc1_range	= STV090x_ADC_1Vpp,
-	.adc2_range	= STV090x_ADC_1Vpp,
-
-	.diseqc_envelope_mode = true,
-
-	.tuner_i2c_lock = cineS2_tuner_i2c_lock,
-};
-
-static struct stv090x_config fe_cineS2_2 = {
-	.device         = STV0900,
-	.demod_mode     = STV090x_DUAL,
-	.clk_mode       = STV090x_CLK_EXT,
-
-	.xtal           = 27000000,
-	.address        = 0x69,
-
-	.ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
-	.ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
-
-	.repeater_level = STV090x_RPTLEVEL_16,
-
-	.adc1_range	= STV090x_ADC_1Vpp,
-	.adc2_range	= STV090x_ADC_1Vpp,
-
-	.diseqc_envelope_mode = true,
-
-	.tuner_i2c_lock = cineS2_tuner_i2c_lock,
-};
-
-static struct stv6110x_config tuner_cineS2_0 = {
-	.addr	= 0x60,
-	.refclk	= 27000000,
-	.clk_div = 1,
-};
-
-static struct stv6110x_config tuner_cineS2_1 = {
-	.addr	= 0x63,
-	.refclk	= 27000000,
-	.clk_div = 1,
-};
-
-static struct ngene_info ngene_info_cineS2 = {
-	.type		= NGENE_SIDEWINDER,
-	.name		= "Linux4Media cineS2 DVB-S2 Twin Tuner",
-	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN},
-	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900},
-	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110},
-	.fe_config	= {&fe_cineS2, &fe_cineS2},
-	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1},
-	.lnb		= {0x0b, 0x08},
-	.tsf		= {3, 3},
-	.fw_version	= 18,
-	.msi_supported	= true,
-};
-
-static struct ngene_info ngene_info_satixS2 = {
-	.type		= NGENE_SIDEWINDER,
-	.name		= "Mystique SaTiX-S2 Dual",
-	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN},
-	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900},
-	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110},
-	.fe_config	= {&fe_cineS2, &fe_cineS2},
-	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1},
-	.lnb		= {0x0b, 0x08},
-	.tsf		= {3, 3},
-	.fw_version	= 18,
-	.msi_supported	= true,
-};
-
-static struct ngene_info ngene_info_satixS2v2 = {
-	.type		= NGENE_SIDEWINDER,
-	.name		= "Mystique SaTiX-S2 Dual (v2)",
-	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
-			   NGENE_IO_TSOUT},
-	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},
-	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe},
-	.fe_config	= {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
-	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
-	.lnb		= {0x0a, 0x08, 0x0b, 0x09},
-	.tsf		= {3, 3},
-	.fw_version	= 18,
-	.msi_supported	= true,
-};
-
-static struct ngene_info ngene_info_cineS2v5 = {
-	.type		= NGENE_SIDEWINDER,
-	.name		= "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)",
-	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
-			   NGENE_IO_TSOUT},
-	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},
-	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe},
-	.fe_config	= {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
-	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
-	.lnb		= {0x0a, 0x08, 0x0b, 0x09},
-	.tsf		= {3, 3},
-	.fw_version	= 18,
-	.msi_supported	= true,
-};
-
-
-static struct ngene_info ngene_info_duoFlex = {
-	.type           = NGENE_SIDEWINDER,
-	.name           = "Digital Devices DuoFlex PCIe or miniPCIe",
-	.io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
-			   NGENE_IO_TSOUT},
-	.demod_attach   = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe},
-	.tuner_attach   = {tuner_attach_probe, tuner_attach_probe, tuner_attach_probe, tuner_attach_probe},
-	.fe_config      = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
-	.tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
-	.lnb            = {0x0a, 0x08, 0x0b, 0x09},
-	.tsf            = {3, 3},
-	.fw_version     = 18,
-	.msi_supported	= true,
-};
-
-static struct ngene_info ngene_info_m780 = {
-	.type           = NGENE_APP,
-	.name           = "Aver M780 ATSC/QAM-B",
-
-	/* Channel 0 is analog, which is currently unsupported */
-	.io_type        = { NGENE_IO_NONE, NGENE_IO_TSIN },
-	.demod_attach   = { NULL, demod_attach_lg330x },
-
-	/* Ensure these are NULL else the frame will call them (as funcs) */
-	.tuner_attach   = { 0, 0, 0, 0 },
-	.fe_config      = { NULL, &aver_m780 },
-	.avf            = { 0 },
-
-	/* A custom electrical interface config for the demod to bridge */
-	.tsf		= { 4, 4 },
-	.fw_version	= 15,
-};
-
-/****************************************************************************/
-
-
-
-/****************************************************************************/
-/* PCI Subsystem ID *********************************************************/
-/****************************************************************************/
-
-#define NGENE_ID(_subvend, _subdev, _driverdata) { \
-	.vendor = NGENE_VID, .device = NGENE_PID, \
-	.subvendor = _subvend, .subdevice = _subdev, \
-	.driver_data = (unsigned long) &_driverdata }
-
-/****************************************************************************/
-
-static const struct pci_device_id ngene_id_tbl[] __devinitdata = {
-	NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2),
-	NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2),
-	NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2),
-	NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2),
-	NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5),
-	NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlex),
-	NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlex),
-	NGENE_ID(0x1461, 0x062e, ngene_info_m780),
-	{0}
-};
-MODULE_DEVICE_TABLE(pci, ngene_id_tbl);
-
-/****************************************************************************/
-/* Init/Exit ****************************************************************/
-/****************************************************************************/
-
-static pci_ers_result_t ngene_error_detected(struct pci_dev *dev,
-					     enum pci_channel_state state)
-{
-	printk(KERN_ERR DEVICE_NAME ": PCI error\n");
-	if (state == pci_channel_io_perm_failure)
-		return PCI_ERS_RESULT_DISCONNECT;
-	if (state == pci_channel_io_frozen)
-		return PCI_ERS_RESULT_NEED_RESET;
-	return PCI_ERS_RESULT_CAN_RECOVER;
-}
-
-static pci_ers_result_t ngene_link_reset(struct pci_dev *dev)
-{
-	printk(KERN_INFO DEVICE_NAME ": link reset\n");
-	return 0;
-}
-
-static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev)
-{
-	printk(KERN_INFO DEVICE_NAME ": slot reset\n");
-	return 0;
-}
-
-static void ngene_resume(struct pci_dev *dev)
-{
-	printk(KERN_INFO DEVICE_NAME ": resume\n");
-}
-
-static struct pci_error_handlers ngene_errors = {
-	.error_detected = ngene_error_detected,
-	.link_reset = ngene_link_reset,
-	.slot_reset = ngene_slot_reset,
-	.resume = ngene_resume,
-};
-
-static struct pci_driver ngene_pci_driver = {
-	.name        = "ngene",
-	.id_table    = ngene_id_tbl,
-	.probe       = ngene_probe,
-	.remove      = __devexit_p(ngene_remove),
-	.err_handler = &ngene_errors,
-	.shutdown    = ngene_shutdown,
-};
-
-static __init int module_init_ngene(void)
-{
-	printk(KERN_INFO
-	       "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n");
-	return pci_register_driver(&ngene_pci_driver);
-}
-
-static __exit void module_exit_ngene(void)
-{
-	pci_unregister_driver(&ngene_pci_driver);
-}
-
-module_init(module_init_ngene);
-module_exit(module_exit_ngene);
-
-MODULE_DESCRIPTION("nGene");
-MODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c
deleted file mode 100644
index 3985738..0000000
--- a/drivers/media/dvb/ngene/ngene-core.c
+++ /dev/null
@@ -1,1713 +0,0 @@
-/*
- * ngene.c: nGene PCIe bridge driver
- *
- * Copyright (C) 2005-2007 Micronas
- *
- * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
- *                         Modifications for new nGene firmware,
- *                         support for EEPROM-copying,
- *                         support for new dual DVB-S2 card prototype
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/poll.h>
-#include <linux/io.h>
-#include <asm/div64.h>
-#include <linux/pci.h>
-#include <linux/timer.h>
-#include <linux/byteorder/generic.h>
-#include <linux/firmware.h>
-#include <linux/vmalloc.h>
-
-#include "ngene.h"
-
-static int one_adapter;
-module_param(one_adapter, int, 0444);
-MODULE_PARM_DESC(one_adapter, "Use only one adapter.");
-
-static int shutdown_workaround;
-module_param(shutdown_workaround, int, 0644);
-MODULE_PARM_DESC(shutdown_workaround, "Activate workaround for shutdown problem with some chipsets.");
-
-static int debug;
-module_param(debug, int, 0444);
-MODULE_PARM_DESC(debug, "Print debugging information.");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define dprintk	if (debug) printk
-
-#define ngwriteb(dat, adr)         writeb((dat), (char *)(dev->iomem + (adr)))
-#define ngwritel(dat, adr)         writel((dat), (char *)(dev->iomem + (adr)))
-#define ngwriteb(dat, adr)         writeb((dat), (char *)(dev->iomem + (adr)))
-#define ngreadl(adr)               readl(dev->iomem + (adr))
-#define ngreadb(adr)               readb(dev->iomem + (adr))
-#define ngcpyto(adr, src, count)   memcpy_toio((char *) \
-				   (dev->iomem + (adr)), (src), (count))
-#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \
-				   (dev->iomem + (adr)), (count))
-
-/****************************************************************************/
-/* nGene interrupt handler **************************************************/
-/****************************************************************************/
-
-static void event_tasklet(unsigned long data)
-{
-	struct ngene *dev = (struct ngene *)data;
-
-	while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) {
-		struct EVENT_BUFFER Event =
-			dev->EventQueue[dev->EventQueueReadIndex];
-		dev->EventQueueReadIndex =
-			(dev->EventQueueReadIndex + 1) & (EVENT_QUEUE_SIZE - 1);
-
-		if ((Event.UARTStatus & 0x01) && (dev->TxEventNotify))
-			dev->TxEventNotify(dev, Event.TimeStamp);
-		if ((Event.UARTStatus & 0x02) && (dev->RxEventNotify))
-			dev->RxEventNotify(dev, Event.TimeStamp,
-					   Event.RXCharacter);
-	}
-}
-
-static void demux_tasklet(unsigned long data)
-{
-	struct ngene_channel *chan = (struct ngene_channel *)data;
-	struct SBufferHeader *Cur = chan->nextBuffer;
-
-	spin_lock_irq(&chan->state_lock);
-
-	while (Cur->ngeneBuffer.SR.Flags & 0x80) {
-		if (chan->mode & NGENE_IO_TSOUT) {
-			u32 Flags = chan->DataFormatFlags;
-			if (Cur->ngeneBuffer.SR.Flags & 0x20)
-				Flags |= BEF_OVERFLOW;
-			if (chan->pBufferExchange) {
-				if (!chan->pBufferExchange(chan,
-							   Cur->Buffer1,
-							   chan->Capture1Length,
-							   Cur->ngeneBuffer.SR.
-							   Clock, Flags)) {
-					/*
-					   We didn't get data
-					   Clear in service flag to make sure we
-					   get called on next interrupt again.
-					   leave fill/empty (0x80) flag alone
-					   to avoid hardware running out of
-					   buffers during startup, we hold only
-					   in run state ( the source may be late
-					   delivering data )
-					*/
-
-					if (chan->HWState == HWSTATE_RUN) {
-						Cur->ngeneBuffer.SR.Flags &=
-							~0x40;
-						break;
-						/* Stop processing stream */
-					}
-				} else {
-					/* We got a valid buffer,
-					   so switch to run state */
-					chan->HWState = HWSTATE_RUN;
-				}
-			} else {
-				printk(KERN_ERR DEVICE_NAME ": OOPS\n");
-				if (chan->HWState == HWSTATE_RUN) {
-					Cur->ngeneBuffer.SR.Flags &= ~0x40;
-					break;	/* Stop processing stream */
-				}
-			}
-			if (chan->AudioDTOUpdated) {
-				printk(KERN_INFO DEVICE_NAME
-				       ": Update AudioDTO = %d\n",
-				       chan->AudioDTOValue);
-				Cur->ngeneBuffer.SR.DTOUpdate =
-					chan->AudioDTOValue;
-				chan->AudioDTOUpdated = 0;
-			}
-		} else {
-			if (chan->HWState == HWSTATE_RUN) {
-				u32 Flags = chan->DataFormatFlags;
-				IBufferExchange *exch1 = chan->pBufferExchange;
-				IBufferExchange *exch2 = chan->pBufferExchange2;
-				if (Cur->ngeneBuffer.SR.Flags & 0x01)
-					Flags |= BEF_EVEN_FIELD;
-				if (Cur->ngeneBuffer.SR.Flags & 0x20)
-					Flags |= BEF_OVERFLOW;
-				spin_unlock_irq(&chan->state_lock);
-				if (exch1)
-					exch1(chan, Cur->Buffer1,
-						chan->Capture1Length,
-						Cur->ngeneBuffer.SR.Clock,
-						Flags);
-				if (exch2)
-					exch2(chan, Cur->Buffer2,
-						chan->Capture2Length,
-						Cur->ngeneBuffer.SR.Clock,
-						Flags);
-				spin_lock_irq(&chan->state_lock);
-			} else if (chan->HWState != HWSTATE_STOP)
-				chan->HWState = HWSTATE_RUN;
-		}
-		Cur->ngeneBuffer.SR.Flags = 0x00;
-		Cur = Cur->Next;
-	}
-	chan->nextBuffer = Cur;
-
-	spin_unlock_irq(&chan->state_lock);
-}
-
-static irqreturn_t irq_handler(int irq, void *dev_id)
-{
-	struct ngene *dev = (struct ngene *)dev_id;
-	u32 icounts = 0;
-	irqreturn_t rc = IRQ_NONE;
-	u32 i = MAX_STREAM;
-	u8 *tmpCmdDoneByte;
-
-	if (dev->BootFirmware) {
-		icounts = ngreadl(NGENE_INT_COUNTS);
-		if (icounts != dev->icounts) {
-			ngwritel(0, FORCE_NMI);
-			dev->cmd_done = 1;
-			wake_up(&dev->cmd_wq);
-			dev->icounts = icounts;
-			rc = IRQ_HANDLED;
-		}
-		return rc;
-	}
-
-	ngwritel(0, FORCE_NMI);
-
-	spin_lock(&dev->cmd_lock);
-	tmpCmdDoneByte = dev->CmdDoneByte;
-	if (tmpCmdDoneByte &&
-	    (*tmpCmdDoneByte ||
-	    (dev->ngenetohost[0] == 1 && dev->ngenetohost[1] != 0))) {
-		dev->CmdDoneByte = NULL;
-		dev->cmd_done = 1;
-		wake_up(&dev->cmd_wq);
-		rc = IRQ_HANDLED;
-	}
-	spin_unlock(&dev->cmd_lock);
-
-	if (dev->EventBuffer->EventStatus & 0x80) {
-		u8 nextWriteIndex =
-			(dev->EventQueueWriteIndex + 1) &
-			(EVENT_QUEUE_SIZE - 1);
-		if (nextWriteIndex != dev->EventQueueReadIndex) {
-			dev->EventQueue[dev->EventQueueWriteIndex] =
-				*(dev->EventBuffer);
-			dev->EventQueueWriteIndex = nextWriteIndex;
-		} else {
-			printk(KERN_ERR DEVICE_NAME ": event overflow\n");
-			dev->EventQueueOverflowCount += 1;
-			dev->EventQueueOverflowFlag = 1;
-		}
-		dev->EventBuffer->EventStatus &= ~0x80;
-		tasklet_schedule(&dev->event_tasklet);
-		rc = IRQ_HANDLED;
-	}
-
-	while (i > 0) {
-		i--;
-		spin_lock(&dev->channel[i].state_lock);
-		/* if (dev->channel[i].State>=KSSTATE_RUN) { */
-		if (dev->channel[i].nextBuffer) {
-			if ((dev->channel[i].nextBuffer->
-			     ngeneBuffer.SR.Flags & 0xC0) == 0x80) {
-				dev->channel[i].nextBuffer->
-					ngeneBuffer.SR.Flags |= 0x40;
-				tasklet_schedule(
-					&dev->channel[i].demux_tasklet);
-				rc = IRQ_HANDLED;
-			}
-		}
-		spin_unlock(&dev->channel[i].state_lock);
-	}
-
-	/* Request might have been processed by a previous call. */
-	return IRQ_HANDLED;
-}
-
-/****************************************************************************/
-/* nGene command interface **************************************************/
-/****************************************************************************/
-
-static void dump_command_io(struct ngene *dev)
-{
-	u8 buf[8], *b;
-
-	ngcpyfrom(buf, HOST_TO_NGENE, 8);
-	printk(KERN_ERR "host_to_ngene (%04x): %02x %02x %02x %02x %02x %02x %02x %02x\n",
-		HOST_TO_NGENE, buf[0], buf[1], buf[2], buf[3],
-		buf[4], buf[5], buf[6], buf[7]);
-
-	ngcpyfrom(buf, NGENE_TO_HOST, 8);
-	printk(KERN_ERR "ngene_to_host (%04x): %02x %02x %02x %02x %02x %02x %02x %02x\n",
-		NGENE_TO_HOST, buf[0], buf[1], buf[2], buf[3],
-		buf[4], buf[5], buf[6], buf[7]);
-
-	b = dev->hosttongene;
-	printk(KERN_ERR "dev->hosttongene (%p): %02x %02x %02x %02x %02x %02x %02x %02x\n",
-		b, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
-
-	b = dev->ngenetohost;
-	printk(KERN_ERR "dev->ngenetohost (%p): %02x %02x %02x %02x %02x %02x %02x %02x\n",
-		b, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
-}
-
-static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com)
-{
-	int ret;
-	u8 *tmpCmdDoneByte;
-
-	dev->cmd_done = 0;
-
-	if (com->cmd.hdr.Opcode == CMD_FWLOAD_PREPARE) {
-		dev->BootFirmware = 1;
-		dev->icounts = ngreadl(NGENE_INT_COUNTS);
-		ngwritel(0, NGENE_COMMAND);
-		ngwritel(0, NGENE_COMMAND_HI);
-		ngwritel(0, NGENE_STATUS);
-		ngwritel(0, NGENE_STATUS_HI);
-		ngwritel(0, NGENE_EVENT);
-		ngwritel(0, NGENE_EVENT_HI);
-	} else if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) {
-		u64 fwio = dev->PAFWInterfaceBuffer;
-
-		ngwritel(fwio & 0xffffffff, NGENE_COMMAND);
-		ngwritel(fwio >> 32, NGENE_COMMAND_HI);
-		ngwritel((fwio + 256) & 0xffffffff, NGENE_STATUS);
-		ngwritel((fwio + 256) >> 32, NGENE_STATUS_HI);
-		ngwritel((fwio + 512) & 0xffffffff, NGENE_EVENT);
-		ngwritel((fwio + 512) >> 32, NGENE_EVENT_HI);
-	}
-
-	memcpy(dev->FWInterfaceBuffer, com->cmd.raw8, com->in_len + 2);
-
-	if (dev->BootFirmware)
-		ngcpyto(HOST_TO_NGENE, com->cmd.raw8, com->in_len + 2);
-
-	spin_lock_irq(&dev->cmd_lock);
-	tmpCmdDoneByte = dev->ngenetohost + com->out_len;
-	if (!com->out_len)
-		tmpCmdDoneByte++;
-	*tmpCmdDoneByte = 0;
-	dev->ngenetohost[0] = 0;
-	dev->ngenetohost[1] = 0;
-	dev->CmdDoneByte = tmpCmdDoneByte;
-	spin_unlock_irq(&dev->cmd_lock);
-
-	/* Notify 8051. */
-	ngwritel(1, FORCE_INT);
-
-	ret = wait_event_timeout(dev->cmd_wq, dev->cmd_done == 1, 2 * HZ);
-	if (!ret) {
-		/*ngwritel(0, FORCE_NMI);*/
-
-		printk(KERN_ERR DEVICE_NAME
-		       ": Command timeout cmd=%02x prev=%02x\n",
-		       com->cmd.hdr.Opcode, dev->prev_cmd);
-		dump_command_io(dev);
-		return -1;
-	}
-	if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH)
-		dev->BootFirmware = 0;
-
-	dev->prev_cmd = com->cmd.hdr.Opcode;
-
-	if (!com->out_len)
-		return 0;
-
-	memcpy(com->cmd.raw8, dev->ngenetohost, com->out_len);
-
-	return 0;
-}
-
-int ngene_command(struct ngene *dev, struct ngene_command *com)
-{
-	int result;
-
-	down(&dev->cmd_mutex);
-	result = ngene_command_mutex(dev, com);
-	up(&dev->cmd_mutex);
-	return result;
-}
-
-
-static int ngene_command_load_firmware(struct ngene *dev,
-				       u8 *ngene_fw, u32 size)
-{
-#define FIRSTCHUNK (1024)
-	u32 cleft;
-	struct ngene_command com;
-
-	com.cmd.hdr.Opcode = CMD_FWLOAD_PREPARE;
-	com.cmd.hdr.Length = 0;
-	com.in_len = 0;
-	com.out_len = 0;
-
-	ngene_command(dev, &com);
-
-	cleft = (size + 3) & ~3;
-	if (cleft > FIRSTCHUNK) {
-		ngcpyto(PROGRAM_SRAM + FIRSTCHUNK, ngene_fw + FIRSTCHUNK,
-			cleft - FIRSTCHUNK);
-		cleft = FIRSTCHUNK;
-	}
-	ngcpyto(DATA_FIFO_AREA, ngene_fw, cleft);
-
-	memset(&com, 0, sizeof(struct ngene_command));
-	com.cmd.hdr.Opcode = CMD_FWLOAD_FINISH;
-	com.cmd.hdr.Length = 4;
-	com.cmd.FWLoadFinish.Address = DATA_FIFO_AREA;
-	com.cmd.FWLoadFinish.Length = (unsigned short)cleft;
-	com.in_len = 4;
-	com.out_len = 0;
-
-	return ngene_command(dev, &com);
-}
-
-
-static int ngene_command_config_buf(struct ngene *dev, u8 config)
-{
-	struct ngene_command com;
-
-	com.cmd.hdr.Opcode = CMD_CONFIGURE_BUFFER;
-	com.cmd.hdr.Length = 1;
-	com.cmd.ConfigureBuffers.config = config;
-	com.in_len = 1;
-	com.out_len = 0;
-
-	if (ngene_command(dev, &com) < 0)
-		return -EIO;
-	return 0;
-}
-
-static int ngene_command_config_free_buf(struct ngene *dev, u8 *config)
-{
-	struct ngene_command com;
-
-	com.cmd.hdr.Opcode = CMD_CONFIGURE_FREE_BUFFER;
-	com.cmd.hdr.Length = 6;
-	memcpy(&com.cmd.ConfigureBuffers.config, config, 6);
-	com.in_len = 6;
-	com.out_len = 0;
-
-	if (ngene_command(dev, &com) < 0)
-		return -EIO;
-
-	return 0;
-}
-
-int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level)
-{
-	struct ngene_command com;
-
-	com.cmd.hdr.Opcode = CMD_SET_GPIO_PIN;
-	com.cmd.hdr.Length = 1;
-	com.cmd.SetGpioPin.select = select | (level << 7);
-	com.in_len = 1;
-	com.out_len = 0;
-
-	return ngene_command(dev, &com);
-}
-
-
-/*
- 02000640 is sample on rising edge.
- 02000740 is sample on falling edge.
- 02000040 is ignore "valid" signal
-
- 0: FD_CTL1 Bit 7,6 must be 0,1
-    7   disable(fw controlled)
-    6   0-AUX,1-TS
-    5   0-par,1-ser
-    4   0-lsb/1-msb
-    3,2 reserved
-    1,0 0-no sync, 1-use ext. start, 2-use 0x47, 3-both
- 1: FD_CTL2 has 3-valid must be hi, 2-use valid, 1-edge
- 2: FD_STA is read-only. 0-sync
- 3: FD_INSYNC is number of 47s to trigger "in sync".
- 4: FD_OUTSYNC is number of 47s to trigger "out of sync".
- 5: FD_MAXBYTE1 is low-order of bytes per packet.
- 6: FD_MAXBYTE2 is high-order of bytes per packet.
- 7: Top byte is unused.
-*/
-
-/****************************************************************************/
-
-static u8 TSFeatureDecoderSetup[8 * 5] = {
-	0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,
-	0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,	/* DRXH */
-	0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,	/* DRXHser */
-	0x72, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,	/* S2ser */
-	0x40, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* LGDT3303 */
-};
-
-/* Set NGENE I2S Config to 16 bit packed */
-static u8 I2SConfiguration[] = {
-	0x00, 0x10, 0x00, 0x00,
-	0x80, 0x10, 0x00, 0x00,
-};
-
-static u8 SPDIFConfiguration[10] = {
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-/* Set NGENE I2S Config to transport stream compatible mode */
-
-static u8 TS_I2SConfiguration[4] = { 0x3E, 0x18, 0x00, 0x00 };
-
-static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x04, 0x00, 0x00 };
-
-static u8 ITUDecoderSetup[4][16] = {
-	{0x1c, 0x13, 0x01, 0x68, 0x3d, 0x90, 0x14, 0x20,  /* SDTV */
-	 0x00, 0x00, 0x01, 0xb0, 0x9c, 0x00, 0x00, 0x00},
-	{0x9c, 0x03, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00,
-	 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
-	{0x9f, 0x00, 0x23, 0xC0, 0x60, 0x0F, 0x13, 0x00,  /* HDTV 1080i50 */
-	 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
-	{0x9c, 0x01, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00,  /* HDTV 1080i60 */
-	 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
-};
-
-/*
- * 50 48 60 gleich
- * 27p50 9f 00 22 80 42 69 18 ...
- * 27p60 93 00 22 80 82 69 1c ...
- */
-
-/* Maxbyte to 1144 (for raw data) */
-static u8 ITUFeatureDecoderSetup[8] = {
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x00
-};
-
-void FillTSBuffer(void *Buffer, int Length, u32 Flags)
-{
-	u32 *ptr = Buffer;
-
-	memset(Buffer, TS_FILLER, Length);
-	while (Length > 0) {
-		if (Flags & DF_SWAP32)
-			*ptr = 0x471FFF10;
-		else
-			*ptr = 0x10FF1F47;
-		ptr += (188 / 4);
-		Length -= 188;
-	}
-}
-
-
-static void flush_buffers(struct ngene_channel *chan)
-{
-	u8 val;
-
-	do {
-		msleep(1);
-		spin_lock_irq(&chan->state_lock);
-		val = chan->nextBuffer->ngeneBuffer.SR.Flags & 0x80;
-		spin_unlock_irq(&chan->state_lock);
-	} while (val);
-}
-
-static void clear_buffers(struct ngene_channel *chan)
-{
-	struct SBufferHeader *Cur = chan->nextBuffer;
-
-	do {
-		memset(&Cur->ngeneBuffer.SR, 0, sizeof(Cur->ngeneBuffer.SR));
-		if (chan->mode & NGENE_IO_TSOUT)
-			FillTSBuffer(Cur->Buffer1,
-				     chan->Capture1Length,
-				     chan->DataFormatFlags);
-		Cur = Cur->Next;
-	} while (Cur != chan->nextBuffer);
-
-	if (chan->mode & NGENE_IO_TSOUT) {
-		chan->nextBuffer->ngeneBuffer.SR.DTOUpdate =
-			chan->AudioDTOValue;
-		chan->AudioDTOUpdated = 0;
-
-		Cur = chan->TSIdleBuffer.Head;
-
-		do {
-			memset(&Cur->ngeneBuffer.SR, 0,
-			       sizeof(Cur->ngeneBuffer.SR));
-			FillTSBuffer(Cur->Buffer1,
-				     chan->Capture1Length,
-				     chan->DataFormatFlags);
-			Cur = Cur->Next;
-		} while (Cur != chan->TSIdleBuffer.Head);
-	}
-}
-
-static int ngene_command_stream_control(struct ngene *dev, u8 stream,
-					u8 control, u8 mode, u8 flags)
-{
-	struct ngene_channel *chan = &dev->channel[stream];
-	struct ngene_command com;
-	u16 BsUVI = ((stream & 1) ? 0x9400 : 0x9300);
-	u16 BsSDI = ((stream & 1) ? 0x9600 : 0x9500);
-	u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700);
-	u16 BsSDO = 0x9B00;
-
-	down(&dev->stream_mutex);
-	memset(&com, 0, sizeof(com));
-	com.cmd.hdr.Opcode = CMD_CONTROL;
-	com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2;
-	com.cmd.StreamControl.Stream = stream | (control ? 8 : 0);
-	if (chan->mode & NGENE_IO_TSOUT)
-		com.cmd.StreamControl.Stream |= 0x07;
-	com.cmd.StreamControl.Control = control |
-		(flags & SFLAG_ORDER_LUMA_CHROMA);
-	com.cmd.StreamControl.Mode = mode;
-	com.in_len = sizeof(struct FW_STREAM_CONTROL);
-	com.out_len = 0;
-
-	dprintk(KERN_INFO DEVICE_NAME
-		": Stream=%02x, Control=%02x, Mode=%02x\n",
-		com.cmd.StreamControl.Stream, com.cmd.StreamControl.Control,
-		com.cmd.StreamControl.Mode);
-
-	chan->Mode = mode;
-
-	if (!(control & 0x80)) {
-		spin_lock_irq(&chan->state_lock);
-		if (chan->State == KSSTATE_RUN) {
-			chan->State = KSSTATE_ACQUIRE;
-			chan->HWState = HWSTATE_STOP;
-			spin_unlock_irq(&chan->state_lock);
-			if (ngene_command(dev, &com) < 0) {
-				up(&dev->stream_mutex);
-				return -1;
-			}
-			/* clear_buffers(chan); */
-			flush_buffers(chan);
-			up(&dev->stream_mutex);
-			return 0;
-		}
-		spin_unlock_irq(&chan->state_lock);
-		up(&dev->stream_mutex);
-		return 0;
-	}
-
-	if (mode & SMODE_AUDIO_CAPTURE) {
-		com.cmd.StreamControl.CaptureBlockCount =
-			chan->Capture1Length / AUDIO_BLOCK_SIZE;
-		com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead;
-	} else if (mode & SMODE_TRANSPORT_STREAM) {
-		com.cmd.StreamControl.CaptureBlockCount =
-			chan->Capture1Length / TS_BLOCK_SIZE;
-		com.cmd.StreamControl.MaxLinesPerField =
-			chan->Capture1Length / TS_BLOCK_SIZE;
-		com.cmd.StreamControl.Buffer_Address =
-			chan->TSRingBuffer.PAHead;
-		if (chan->mode & NGENE_IO_TSOUT) {
-			com.cmd.StreamControl.BytesPerVBILine =
-				chan->Capture1Length / TS_BLOCK_SIZE;
-			com.cmd.StreamControl.Stream |= 0x07;
-		}
-	} else {
-		com.cmd.StreamControl.BytesPerVideoLine = chan->nBytesPerLine;
-		com.cmd.StreamControl.MaxLinesPerField = chan->nLines;
-		com.cmd.StreamControl.MinLinesPerField = 100;
-		com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead;
-
-		if (mode & SMODE_VBI_CAPTURE) {
-			com.cmd.StreamControl.MaxVBILinesPerField =
-				chan->nVBILines;
-			com.cmd.StreamControl.MinVBILinesPerField = 0;
-			com.cmd.StreamControl.BytesPerVBILine =
-				chan->nBytesPerVBILine;
-		}
-		if (flags & SFLAG_COLORBAR)
-			com.cmd.StreamControl.Stream |= 0x04;
-	}
-
-	spin_lock_irq(&chan->state_lock);
-	if (mode & SMODE_AUDIO_CAPTURE) {
-		chan->nextBuffer = chan->RingBuffer.Head;
-		if (mode & SMODE_AUDIO_SPDIF) {
-			com.cmd.StreamControl.SetupDataLen =
-				sizeof(SPDIFConfiguration);
-			com.cmd.StreamControl.SetupDataAddr = BsSPI;
-			memcpy(com.cmd.StreamControl.SetupData,
-			       SPDIFConfiguration, sizeof(SPDIFConfiguration));
-		} else {
-			com.cmd.StreamControl.SetupDataLen = 4;
-			com.cmd.StreamControl.SetupDataAddr = BsSDI;
-			memcpy(com.cmd.StreamControl.SetupData,
-			       I2SConfiguration +
-			       4 * dev->card_info->i2s[stream], 4);
-		}
-	} else if (mode & SMODE_TRANSPORT_STREAM) {
-		chan->nextBuffer = chan->TSRingBuffer.Head;
-		if (stream >= STREAM_AUDIOIN1) {
-			if (chan->mode & NGENE_IO_TSOUT) {
-				com.cmd.StreamControl.SetupDataLen =
-					sizeof(TS_I2SOutConfiguration);
-				com.cmd.StreamControl.SetupDataAddr = BsSDO;
-				memcpy(com.cmd.StreamControl.SetupData,
-				       TS_I2SOutConfiguration,
-				       sizeof(TS_I2SOutConfiguration));
-			} else {
-				com.cmd.StreamControl.SetupDataLen =
-					sizeof(TS_I2SConfiguration);
-				com.cmd.StreamControl.SetupDataAddr = BsSDI;
-				memcpy(com.cmd.StreamControl.SetupData,
-				       TS_I2SConfiguration,
-				       sizeof(TS_I2SConfiguration));
-			}
-		} else {
-			com.cmd.StreamControl.SetupDataLen = 8;
-			com.cmd.StreamControl.SetupDataAddr = BsUVI + 0x10;
-			memcpy(com.cmd.StreamControl.SetupData,
-			       TSFeatureDecoderSetup +
-			       8 * dev->card_info->tsf[stream], 8);
-		}
-	} else {
-		chan->nextBuffer = chan->RingBuffer.Head;
-		com.cmd.StreamControl.SetupDataLen =
-			16 + sizeof(ITUFeatureDecoderSetup);
-		com.cmd.StreamControl.SetupDataAddr = BsUVI;
-		memcpy(com.cmd.StreamControl.SetupData,
-		       ITUDecoderSetup[chan->itumode], 16);
-		memcpy(com.cmd.StreamControl.SetupData + 16,
-		       ITUFeatureDecoderSetup, sizeof(ITUFeatureDecoderSetup));
-	}
-	clear_buffers(chan);
-	chan->State = KSSTATE_RUN;
-	if (mode & SMODE_TRANSPORT_STREAM)
-		chan->HWState = HWSTATE_RUN;
-	else
-		chan->HWState = HWSTATE_STARTUP;
-	spin_unlock_irq(&chan->state_lock);
-
-	if (ngene_command(dev, &com) < 0) {
-		up(&dev->stream_mutex);
-		return -1;
-	}
-	up(&dev->stream_mutex);
-	return 0;
-}
-
-void set_transfer(struct ngene_channel *chan, int state)
-{
-	u8 control = 0, mode = 0, flags = 0;
-	struct ngene *dev = chan->dev;
-	int ret;
-
-	/*
-	printk(KERN_INFO DEVICE_NAME ": st %d\n", state);
-	msleep(100);
-	*/
-
-	if (state) {
-		if (chan->running) {
-			printk(KERN_INFO DEVICE_NAME ": already running\n");
-			return;
-		}
-	} else {
-		if (!chan->running) {
-			printk(KERN_INFO DEVICE_NAME ": already stopped\n");
-			return;
-		}
-	}
-
-	if (dev->card_info->switch_ctrl)
-		dev->card_info->switch_ctrl(chan, 1, state ^ 1);
-
-	if (state) {
-		spin_lock_irq(&chan->state_lock);
-
-		/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n",
-			  ngreadl(0x9310)); */
-		dvb_ringbuffer_flush(&dev->tsout_rbuf);
-		control = 0x80;
-		if (chan->mode & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
-			chan->Capture1Length = 512 * 188;
-			mode = SMODE_TRANSPORT_STREAM;
-		}
-		if (chan->mode & NGENE_IO_TSOUT) {
-			chan->pBufferExchange = tsout_exchange;
-			/* 0x66666666 = 50MHz *2^33 /250MHz */
-			chan->AudioDTOValue = 0x80000000;
-			chan->AudioDTOUpdated = 1;
-		}
-		if (chan->mode & NGENE_IO_TSIN)
-			chan->pBufferExchange = tsin_exchange;
-		spin_unlock_irq(&chan->state_lock);
-	} else
-		;/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n",
-			   ngreadl(0x9310)); */
-
-	ret = ngene_command_stream_control(dev, chan->number,
-					   control, mode, flags);
-	if (!ret)
-		chan->running = state;
-	else
-		printk(KERN_ERR DEVICE_NAME ": set_transfer %d failed\n",
-		       state);
-	if (!state) {
-		spin_lock_irq(&chan->state_lock);
-		chan->pBufferExchange = NULL;
-		dvb_ringbuffer_flush(&dev->tsout_rbuf);
-		spin_unlock_irq(&chan->state_lock);
-	}
-}
-
-
-/****************************************************************************/
-/* nGene hardware init and release functions ********************************/
-/****************************************************************************/
-
-static void free_ringbuffer(struct ngene *dev, struct SRingBufferDescriptor *rb)
-{
-	struct SBufferHeader *Cur = rb->Head;
-	u32 j;
-
-	if (!Cur)
-		return;
-
-	for (j = 0; j < rb->NumBuffers; j++, Cur = Cur->Next) {
-		if (Cur->Buffer1)
-			pci_free_consistent(dev->pci_dev,
-					    rb->Buffer1Length,
-					    Cur->Buffer1,
-					    Cur->scList1->Address);
-
-		if (Cur->Buffer2)
-			pci_free_consistent(dev->pci_dev,
-					    rb->Buffer2Length,
-					    Cur->Buffer2,
-					    Cur->scList2->Address);
-	}
-
-	if (rb->SCListMem)
-		pci_free_consistent(dev->pci_dev, rb->SCListMemSize,
-				    rb->SCListMem, rb->PASCListMem);
-
-	pci_free_consistent(dev->pci_dev, rb->MemSize, rb->Head, rb->PAHead);
-}
-
-static void free_idlebuffer(struct ngene *dev,
-		     struct SRingBufferDescriptor *rb,
-		     struct SRingBufferDescriptor *tb)
-{
-	int j;
-	struct SBufferHeader *Cur = tb->Head;
-
-	if (!rb->Head)
-		return;
-	free_ringbuffer(dev, rb);
-	for (j = 0; j < tb->NumBuffers; j++, Cur = Cur->Next) {
-		Cur->Buffer2 = NULL;
-		Cur->scList2 = NULL;
-		Cur->ngeneBuffer.Address_of_first_entry_2 = 0;
-		Cur->ngeneBuffer.Number_of_entries_2 = 0;
-	}
-}
-
-static void free_common_buffers(struct ngene *dev)
-{
-	u32 i;
-	struct ngene_channel *chan;
-
-	for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) {
-		chan = &dev->channel[i];
-		free_idlebuffer(dev, &chan->TSIdleBuffer, &chan->TSRingBuffer);
-		free_ringbuffer(dev, &chan->RingBuffer);
-		free_ringbuffer(dev, &chan->TSRingBuffer);
-	}
-
-	if (dev->OverflowBuffer)
-		pci_free_consistent(dev->pci_dev,
-				    OVERFLOW_BUFFER_SIZE,
-				    dev->OverflowBuffer, dev->PAOverflowBuffer);
-
-	if (dev->FWInterfaceBuffer)
-		pci_free_consistent(dev->pci_dev,
-				    4096,
-				    dev->FWInterfaceBuffer,
-				    dev->PAFWInterfaceBuffer);
-}
-
-/****************************************************************************/
-/* Ring buffer handling *****************************************************/
-/****************************************************************************/
-
-static int create_ring_buffer(struct pci_dev *pci_dev,
-		       struct SRingBufferDescriptor *descr, u32 NumBuffers)
-{
-	dma_addr_t tmp;
-	struct SBufferHeader *Head;
-	u32 i;
-	u32 MemSize = SIZEOF_SBufferHeader * NumBuffers;
-	u64 PARingBufferHead;
-	u64 PARingBufferCur;
-	u64 PARingBufferNext;
-	struct SBufferHeader *Cur, *Next;
-
-	descr->Head = NULL;
-	descr->MemSize = 0;
-	descr->PAHead = 0;
-	descr->NumBuffers = 0;
-
-	if (MemSize < 4096)
-		MemSize = 4096;
-
-	Head = pci_alloc_consistent(pci_dev, MemSize, &tmp);
-	PARingBufferHead = tmp;
-
-	if (!Head)
-		return -ENOMEM;
-
-	memset(Head, 0, MemSize);
-
-	PARingBufferCur = PARingBufferHead;
-	Cur = Head;
-
-	for (i = 0; i < NumBuffers - 1; i++) {
-		Next = (struct SBufferHeader *)
-			(((u8 *) Cur) + SIZEOF_SBufferHeader);
-		PARingBufferNext = PARingBufferCur + SIZEOF_SBufferHeader;
-		Cur->Next = Next;
-		Cur->ngeneBuffer.Next = PARingBufferNext;
-		Cur = Next;
-		PARingBufferCur = PARingBufferNext;
-	}
-	/* Last Buffer points back to first one */
-	Cur->Next = Head;
-	Cur->ngeneBuffer.Next = PARingBufferHead;
-
-	descr->Head       = Head;
-	descr->MemSize    = MemSize;
-	descr->PAHead     = PARingBufferHead;
-	descr->NumBuffers = NumBuffers;
-
-	return 0;
-}
-
-static int AllocateRingBuffers(struct pci_dev *pci_dev,
-			       dma_addr_t of,
-			       struct SRingBufferDescriptor *pRingBuffer,
-			       u32 Buffer1Length, u32 Buffer2Length)
-{
-	dma_addr_t tmp;
-	u32 i, j;
-	int status = 0;
-	u32 SCListMemSize = pRingBuffer->NumBuffers
-		* ((Buffer2Length != 0) ? (NUM_SCATTER_GATHER_ENTRIES * 2) :
-		    NUM_SCATTER_GATHER_ENTRIES)
-		* sizeof(struct HW_SCATTER_GATHER_ELEMENT);
-
-	u64 PASCListMem;
-	struct HW_SCATTER_GATHER_ELEMENT *SCListEntry;
-	u64 PASCListEntry;
-	struct SBufferHeader *Cur;
-	void *SCListMem;
-
-	if (SCListMemSize < 4096)
-		SCListMemSize = 4096;
-
-	SCListMem = pci_alloc_consistent(pci_dev, SCListMemSize, &tmp);
-
-	PASCListMem = tmp;
-	if (SCListMem == NULL)
-		return -ENOMEM;
-
-	memset(SCListMem, 0, SCListMemSize);
-
-	pRingBuffer->SCListMem = SCListMem;
-	pRingBuffer->PASCListMem = PASCListMem;
-	pRingBuffer->SCListMemSize = SCListMemSize;
-	pRingBuffer->Buffer1Length = Buffer1Length;
-	pRingBuffer->Buffer2Length = Buffer2Length;
-
-	SCListEntry = SCListMem;
-	PASCListEntry = PASCListMem;
-	Cur = pRingBuffer->Head;
-
-	for (i = 0; i < pRingBuffer->NumBuffers; i += 1, Cur = Cur->Next) {
-		u64 PABuffer;
-
-		void *Buffer = pci_alloc_consistent(pci_dev, Buffer1Length,
-						    &tmp);
-		PABuffer = tmp;
-
-		if (Buffer == NULL)
-			return -ENOMEM;
-
-		Cur->Buffer1 = Buffer;
-
-		SCListEntry->Address = PABuffer;
-		SCListEntry->Length  = Buffer1Length;
-
-		Cur->scList1 = SCListEntry;
-		Cur->ngeneBuffer.Address_of_first_entry_1 = PASCListEntry;
-		Cur->ngeneBuffer.Number_of_entries_1 =
-			NUM_SCATTER_GATHER_ENTRIES;
-
-		SCListEntry += 1;
-		PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT);
-
-#if NUM_SCATTER_GATHER_ENTRIES > 1
-		for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j += 1) {
-			SCListEntry->Address = of;
-			SCListEntry->Length = OVERFLOW_BUFFER_SIZE;
-			SCListEntry += 1;
-			PASCListEntry +=
-				sizeof(struct HW_SCATTER_GATHER_ELEMENT);
-		}
-#endif
-
-		if (!Buffer2Length)
-			continue;
-
-		Buffer = pci_alloc_consistent(pci_dev, Buffer2Length, &tmp);
-		PABuffer = tmp;
-
-		if (Buffer == NULL)
-			return -ENOMEM;
-
-		Cur->Buffer2 = Buffer;
-
-		SCListEntry->Address = PABuffer;
-		SCListEntry->Length  = Buffer2Length;
-
-		Cur->scList2 = SCListEntry;
-		Cur->ngeneBuffer.Address_of_first_entry_2 = PASCListEntry;
-		Cur->ngeneBuffer.Number_of_entries_2 =
-			NUM_SCATTER_GATHER_ENTRIES;
-
-		SCListEntry   += 1;
-		PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT);
-
-#if NUM_SCATTER_GATHER_ENTRIES > 1
-		for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j++) {
-			SCListEntry->Address = of;
-			SCListEntry->Length = OVERFLOW_BUFFER_SIZE;
-			SCListEntry += 1;
-			PASCListEntry +=
-				sizeof(struct HW_SCATTER_GATHER_ELEMENT);
-		}
-#endif
-
-	}
-
-	return status;
-}
-
-static int FillTSIdleBuffer(struct SRingBufferDescriptor *pIdleBuffer,
-			    struct SRingBufferDescriptor *pRingBuffer)
-{
-	int status = 0;
-
-	/* Copy pointer to scatter gather list in TSRingbuffer
-	   structure for buffer 2
-	   Load number of buffer
-	*/
-	u32 n = pRingBuffer->NumBuffers;
-
-	/* Point to first buffer entry */
-	struct SBufferHeader *Cur = pRingBuffer->Head;
-	int i;
-	/* Loop thru all buffer and set Buffer 2 pointers to TSIdlebuffer */
-	for (i = 0; i < n; i++) {
-		Cur->Buffer2 = pIdleBuffer->Head->Buffer1;
-		Cur->scList2 = pIdleBuffer->Head->scList1;
-		Cur->ngeneBuffer.Address_of_first_entry_2 =
-			pIdleBuffer->Head->ngeneBuffer.
-			Address_of_first_entry_1;
-		Cur->ngeneBuffer.Number_of_entries_2 =
-			pIdleBuffer->Head->ngeneBuffer.Number_of_entries_1;
-		Cur = Cur->Next;
-	}
-	return status;
-}
-
-static u32 RingBufferSizes[MAX_STREAM] = {
-	RING_SIZE_VIDEO,
-	RING_SIZE_VIDEO,
-	RING_SIZE_AUDIO,
-	RING_SIZE_AUDIO,
-	RING_SIZE_AUDIO,
-};
-
-static u32 Buffer1Sizes[MAX_STREAM] = {
-	MAX_VIDEO_BUFFER_SIZE,
-	MAX_VIDEO_BUFFER_SIZE,
-	MAX_AUDIO_BUFFER_SIZE,
-	MAX_AUDIO_BUFFER_SIZE,
-	MAX_AUDIO_BUFFER_SIZE
-};
-
-static u32 Buffer2Sizes[MAX_STREAM] = {
-	MAX_VBI_BUFFER_SIZE,
-	MAX_VBI_BUFFER_SIZE,
-	0,
-	0,
-	0
-};
-
-
-static int AllocCommonBuffers(struct ngene *dev)
-{
-	int status = 0, i;
-
-	dev->FWInterfaceBuffer = pci_alloc_consistent(dev->pci_dev, 4096,
-						     &dev->PAFWInterfaceBuffer);
-	if (!dev->FWInterfaceBuffer)
-		return -ENOMEM;
-	dev->hosttongene = dev->FWInterfaceBuffer;
-	dev->ngenetohost = dev->FWInterfaceBuffer + 256;
-	dev->EventBuffer = dev->FWInterfaceBuffer + 512;
-
-	dev->OverflowBuffer = pci_alloc_consistent(dev->pci_dev,
-						   OVERFLOW_BUFFER_SIZE,
-						   &dev->PAOverflowBuffer);
-	if (!dev->OverflowBuffer)
-		return -ENOMEM;
-	memset(dev->OverflowBuffer, 0, OVERFLOW_BUFFER_SIZE);
-
-	for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) {
-		int type = dev->card_info->io_type[i];
-
-		dev->channel[i].State = KSSTATE_STOP;
-
-		if (type & (NGENE_IO_TV | NGENE_IO_HDTV | NGENE_IO_AIN)) {
-			status = create_ring_buffer(dev->pci_dev,
-						    &dev->channel[i].RingBuffer,
-						    RingBufferSizes[i]);
-			if (status < 0)
-				break;
-
-			if (type & (NGENE_IO_TV | NGENE_IO_AIN)) {
-				status = AllocateRingBuffers(dev->pci_dev,
-							     dev->
-							     PAOverflowBuffer,
-							     &dev->channel[i].
-							     RingBuffer,
-							     Buffer1Sizes[i],
-							     Buffer2Sizes[i]);
-				if (status < 0)
-					break;
-			} else if (type & NGENE_IO_HDTV) {
-				status = AllocateRingBuffers(dev->pci_dev,
-							     dev->
-							     PAOverflowBuffer,
-							     &dev->channel[i].
-							     RingBuffer,
-							   MAX_HDTV_BUFFER_SIZE,
-							     0);
-				if (status < 0)
-					break;
-			}
-		}
-
-		if (type & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
-
-			status = create_ring_buffer(dev->pci_dev,
-						    &dev->channel[i].
-						    TSRingBuffer, RING_SIZE_TS);
-			if (status < 0)
-				break;
-
-			status = AllocateRingBuffers(dev->pci_dev,
-						     dev->PAOverflowBuffer,
-						     &dev->channel[i].
-						     TSRingBuffer,
-						     MAX_TS_BUFFER_SIZE, 0);
-			if (status)
-				break;
-		}
-
-		if (type & NGENE_IO_TSOUT) {
-			status = create_ring_buffer(dev->pci_dev,
-						    &dev->channel[i].
-						    TSIdleBuffer, 1);
-			if (status < 0)
-				break;
-			status = AllocateRingBuffers(dev->pci_dev,
-						     dev->PAOverflowBuffer,
-						     &dev->channel[i].
-						     TSIdleBuffer,
-						     MAX_TS_BUFFER_SIZE, 0);
-			if (status)
-				break;
-			FillTSIdleBuffer(&dev->channel[i].TSIdleBuffer,
-					 &dev->channel[i].TSRingBuffer);
-		}
-	}
-	return status;
-}
-
-static void ngene_release_buffers(struct ngene *dev)
-{
-	if (dev->iomem)
-		iounmap(dev->iomem);
-	free_common_buffers(dev);
-	vfree(dev->tsout_buf);
-	vfree(dev->tsin_buf);
-	vfree(dev->ain_buf);
-	vfree(dev->vin_buf);
-	vfree(dev);
-}
-
-static int ngene_get_buffers(struct ngene *dev)
-{
-	if (AllocCommonBuffers(dev))
-		return -ENOMEM;
-	if (dev->card_info->io_type[4] & NGENE_IO_TSOUT) {
-		dev->tsout_buf = vmalloc(TSOUT_BUF_SIZE);
-		if (!dev->tsout_buf)
-			return -ENOMEM;
-		dvb_ringbuffer_init(&dev->tsout_rbuf,
-				    dev->tsout_buf, TSOUT_BUF_SIZE);
-	}
-	if (dev->card_info->io_type[2]&NGENE_IO_TSIN) {
-		dev->tsin_buf = vmalloc(TSIN_BUF_SIZE);
-		if (!dev->tsin_buf)
-			return -ENOMEM;
-		dvb_ringbuffer_init(&dev->tsin_rbuf,
-				    dev->tsin_buf, TSIN_BUF_SIZE);
-	}
-	if (dev->card_info->io_type[2] & NGENE_IO_AIN) {
-		dev->ain_buf = vmalloc(AIN_BUF_SIZE);
-		if (!dev->ain_buf)
-			return -ENOMEM;
-		dvb_ringbuffer_init(&dev->ain_rbuf, dev->ain_buf, AIN_BUF_SIZE);
-	}
-	if (dev->card_info->io_type[0] & NGENE_IO_HDTV) {
-		dev->vin_buf = vmalloc(VIN_BUF_SIZE);
-		if (!dev->vin_buf)
-			return -ENOMEM;
-		dvb_ringbuffer_init(&dev->vin_rbuf, dev->vin_buf, VIN_BUF_SIZE);
-	}
-	dev->iomem = ioremap(pci_resource_start(dev->pci_dev, 0),
-			     pci_resource_len(dev->pci_dev, 0));
-	if (!dev->iomem)
-		return -ENOMEM;
-
-	return 0;
-}
-
-static void ngene_init(struct ngene *dev)
-{
-	int i;
-
-	tasklet_init(&dev->event_tasklet, event_tasklet, (unsigned long)dev);
-
-	memset_io(dev->iomem + 0xc000, 0x00, 0x220);
-	memset_io(dev->iomem + 0xc400, 0x00, 0x100);
-
-	for (i = 0; i < MAX_STREAM; i++) {
-		dev->channel[i].dev = dev;
-		dev->channel[i].number = i;
-	}
-
-	dev->fw_interface_version = 0;
-
-	ngwritel(0, NGENE_INT_ENABLE);
-
-	dev->icounts = ngreadl(NGENE_INT_COUNTS);
-
-	dev->device_version = ngreadl(DEV_VER) & 0x0f;
-	printk(KERN_INFO DEVICE_NAME ": Device version %d\n",
-	       dev->device_version);
-}
-
-static int ngene_load_firm(struct ngene *dev)
-{
-	u32 size;
-	const struct firmware *fw = NULL;
-	u8 *ngene_fw;
-	char *fw_name;
-	int err, version;
-
-	version = dev->card_info->fw_version;
-
-	switch (version) {
-	default:
-	case 15:
-		version = 15;
-		size = 23466;
-		fw_name = "ngene_15.fw";
-		dev->cmd_timeout_workaround = true;
-		break;
-	case 16:
-		size = 23498;
-		fw_name = "ngene_16.fw";
-		dev->cmd_timeout_workaround = true;
-		break;
-	case 17:
-		size = 24446;
-		fw_name = "ngene_17.fw";
-		dev->cmd_timeout_workaround = true;
-		break;
-	case 18:
-		size = 0;
-		fw_name = "ngene_18.fw";
-		break;
-	}
-
-	if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) {
-		printk(KERN_ERR DEVICE_NAME
-			": Could not load firmware file %s.\n", fw_name);
-		printk(KERN_INFO DEVICE_NAME
-			": Copy %s to your hotplug directory!\n", fw_name);
-		return -1;
-	}
-	if (size == 0)
-		size = fw->size;
-	if (size != fw->size) {
-		printk(KERN_ERR DEVICE_NAME
-			": Firmware %s has invalid size!", fw_name);
-		err = -1;
-	} else {
-		printk(KERN_INFO DEVICE_NAME
-			": Loading firmware file %s.\n", fw_name);
-		ngene_fw = (u8 *) fw->data;
-		err = ngene_command_load_firmware(dev, ngene_fw, size);
-	}
-
-	release_firmware(fw);
-
-	return err;
-}
-
-static void ngene_stop(struct ngene *dev)
-{
-	down(&dev->cmd_mutex);
-	i2c_del_adapter(&(dev->channel[0].i2c_adapter));
-	i2c_del_adapter(&(dev->channel[1].i2c_adapter));
-	ngwritel(0, NGENE_INT_ENABLE);
-	ngwritel(0, NGENE_COMMAND);
-	ngwritel(0, NGENE_COMMAND_HI);
-	ngwritel(0, NGENE_STATUS);
-	ngwritel(0, NGENE_STATUS_HI);
-	ngwritel(0, NGENE_EVENT);
-	ngwritel(0, NGENE_EVENT_HI);
-	free_irq(dev->pci_dev->irq, dev);
-#ifdef CONFIG_PCI_MSI
-	if (dev->msi_enabled)
-		pci_disable_msi(dev->pci_dev);
-#endif
-}
-
-static int ngene_buffer_config(struct ngene *dev)
-{
-	int stat;
-
-	if (dev->card_info->fw_version >= 17) {
-		u8 tsin12_config[6]   = { 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 };
-		u8 tsin1234_config[6] = { 0x30, 0x30, 0x00, 0x30, 0x30, 0x00 };
-		u8 tsio1235_config[6] = { 0x30, 0x30, 0x00, 0x28, 0x00, 0x38 };
-		u8 *bconf = tsin12_config;
-
-		if (dev->card_info->io_type[2]&NGENE_IO_TSIN &&
-		    dev->card_info->io_type[3]&NGENE_IO_TSIN) {
-			bconf = tsin1234_config;
-			if (dev->card_info->io_type[4]&NGENE_IO_TSOUT &&
-			    dev->ci.en)
-				bconf = tsio1235_config;
-		}
-		stat = ngene_command_config_free_buf(dev, bconf);
-	} else {
-		int bconf = BUFFER_CONFIG_4422;
-
-		if (dev->card_info->io_type[3] == NGENE_IO_TSIN)
-			bconf = BUFFER_CONFIG_3333;
-		stat = ngene_command_config_buf(dev, bconf);
-	}
-	return stat;
-}
-
-
-static int ngene_start(struct ngene *dev)
-{
-	int stat;
-	int i;
-
-	pci_set_master(dev->pci_dev);
-	ngene_init(dev);
-
-	stat = request_irq(dev->pci_dev->irq, irq_handler,
-			   IRQF_SHARED, "nGene",
-			   (void *)dev);
-	if (stat < 0)
-		return stat;
-
-	init_waitqueue_head(&dev->cmd_wq);
-	init_waitqueue_head(&dev->tx_wq);
-	init_waitqueue_head(&dev->rx_wq);
-	sema_init(&dev->cmd_mutex, 1);
-	sema_init(&dev->stream_mutex, 1);
-	sema_init(&dev->pll_mutex, 1);
-	sema_init(&dev->i2c_switch_mutex, 1);
-	spin_lock_init(&dev->cmd_lock);
-	for (i = 0; i < MAX_STREAM; i++)
-		spin_lock_init(&dev->channel[i].state_lock);
-	ngwritel(1, TIMESTAMPS);
-
-	ngwritel(1, NGENE_INT_ENABLE);
-
-	stat = ngene_load_firm(dev);
-	if (stat < 0)
-		goto fail;
-
-#ifdef CONFIG_PCI_MSI
-	/* enable MSI if kernel and card support it */
-	if (pci_msi_enabled() && dev->card_info->msi_supported) {
-		unsigned long flags;
-
-		ngwritel(0, NGENE_INT_ENABLE);
-		free_irq(dev->pci_dev->irq, dev);
-		stat = pci_enable_msi(dev->pci_dev);
-		if (stat) {
-			printk(KERN_INFO DEVICE_NAME
-				": MSI not available\n");
-			flags = IRQF_SHARED;
-		} else {
-			flags = 0;
-			dev->msi_enabled = true;
-		}
-		stat = request_irq(dev->pci_dev->irq, irq_handler,
-					flags, "nGene", dev);
-		if (stat < 0)
-			goto fail2;
-		ngwritel(1, NGENE_INT_ENABLE);
-	}
-#endif
-
-	stat = ngene_i2c_init(dev, 0);
-	if (stat < 0)
-		goto fail;
-
-	stat = ngene_i2c_init(dev, 1);
-	if (stat < 0)
-		goto fail;
-
-	return 0;
-
-fail:
-	ngwritel(0, NGENE_INT_ENABLE);
-	free_irq(dev->pci_dev->irq, dev);
-#ifdef CONFIG_PCI_MSI
-fail2:
-	if (dev->msi_enabled)
-		pci_disable_msi(dev->pci_dev);
-#endif
-	return stat;
-}
-
-/****************************************************************************/
-/****************************************************************************/
-/****************************************************************************/
-
-static void release_channel(struct ngene_channel *chan)
-{
-	struct dvb_demux *dvbdemux = &chan->demux;
-	struct ngene *dev = chan->dev;
-
-	if (chan->running)
-		set_transfer(chan, 0);
-
-	tasklet_kill(&chan->demux_tasklet);
-
-	if (chan->ci_dev) {
-		dvb_unregister_device(chan->ci_dev);
-		chan->ci_dev = NULL;
-	}
-
-	if (chan->fe2)
-		dvb_unregister_frontend(chan->fe2);
-
-	if (chan->fe) {
-		dvb_unregister_frontend(chan->fe);
-		dvb_frontend_detach(chan->fe);
-		chan->fe = NULL;
-	}
-
-	if (chan->has_demux) {
-		dvb_net_release(&chan->dvbnet);
-		dvbdemux->dmx.close(&dvbdemux->dmx);
-		dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
-					      &chan->hw_frontend);
-		dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
-					      &chan->mem_frontend);
-		dvb_dmxdev_release(&chan->dmxdev);
-		dvb_dmx_release(&chan->demux);
-		chan->has_demux = false;
-	}
-
-	if (chan->has_adapter) {
-		dvb_unregister_adapter(&dev->adapter[chan->number]);
-		chan->has_adapter = false;
-	}
-}
-
-static int init_channel(struct ngene_channel *chan)
-{
-	int ret = 0, nr = chan->number;
-	struct dvb_adapter *adapter = NULL;
-	struct dvb_demux *dvbdemux = &chan->demux;
-	struct ngene *dev = chan->dev;
-	struct ngene_info *ni = dev->card_info;
-	int io = ni->io_type[nr];
-
-	tasklet_init(&chan->demux_tasklet, demux_tasklet, (unsigned long)chan);
-	chan->users = 0;
-	chan->type = io;
-	chan->mode = chan->type;	/* for now only one mode */
-
-	if (io & NGENE_IO_TSIN) {
-		chan->fe = NULL;
-		if (ni->demod_attach[nr]) {
-			ret = ni->demod_attach[nr](chan);
-			if (ret < 0)
-				goto err;
-		}
-		if (chan->fe && ni->tuner_attach[nr]) {
-			ret = ni->tuner_attach[nr](chan);
-			if (ret < 0)
-				goto err;
-		}
-	}
-
-	if (!dev->ci.en && (io & NGENE_IO_TSOUT))
-		return 0;
-
-	if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
-		if (nr >= STREAM_AUDIOIN1)
-			chan->DataFormatFlags = DF_SWAP32;
-
-		if (nr == 0 || !one_adapter || dev->first_adapter == NULL) {
-			adapter = &dev->adapter[nr];
-			ret = dvb_register_adapter(adapter, "nGene",
-						   THIS_MODULE,
-						   &chan->dev->pci_dev->dev,
-						   adapter_nr);
-			if (ret < 0)
-				goto err;
-			if (dev->first_adapter == NULL)
-				dev->first_adapter = adapter;
-			chan->has_adapter = true;
-		} else
-			adapter = dev->first_adapter;
-	}
-
-	if (dev->ci.en && (io & NGENE_IO_TSOUT)) {
-		dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1);
-		set_transfer(chan, 1);
-		chan->dev->channel[2].DataFormatFlags = DF_SWAP32;
-		set_transfer(&chan->dev->channel[2], 1);
-		dvb_register_device(adapter, &chan->ci_dev,
-				    &ngene_dvbdev_ci, (void *) chan,
-				    DVB_DEVICE_SEC);
-		if (!chan->ci_dev)
-			goto err;
-	}
-
-	if (chan->fe) {
-		if (dvb_register_frontend(adapter, chan->fe) < 0)
-			goto err;
-		chan->has_demux = true;
-	}
-	if (chan->fe2) {
-		if (dvb_register_frontend(adapter, chan->fe2) < 0)
-			goto err;
-		chan->fe2->tuner_priv = chan->fe->tuner_priv;
-		memcpy(&chan->fe2->ops.tuner_ops,
-		       &chan->fe->ops.tuner_ops,
-		       sizeof(struct dvb_tuner_ops));
-	}
-
-	if (chan->has_demux) {
-		ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux",
-					      ngene_start_feed,
-					      ngene_stop_feed, chan);
-		ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux,
-						 &chan->hw_frontend,
-						 &chan->mem_frontend, adapter);
-		ret = dvb_net_init(adapter, &chan->dvbnet, &chan->demux.dmx);
-	}
-
-	return ret;
-
-err:
-	if (chan->fe) {
-		dvb_frontend_detach(chan->fe);
-		chan->fe = NULL;
-	}
-	release_channel(chan);
-	return 0;
-}
-
-static int init_channels(struct ngene *dev)
-{
-	int i, j;
-
-	for (i = 0; i < MAX_STREAM; i++) {
-		dev->channel[i].number = i;
-		if (init_channel(&dev->channel[i]) < 0) {
-			for (j = i - 1; j >= 0; j--)
-				release_channel(&dev->channel[j]);
-			return -1;
-		}
-	}
-	return 0;
-}
-
-static struct cxd2099_cfg cxd_cfg = {
-	.bitrate = 62000,
-	.adr = 0x40,
-	.polarity = 0,
-	.clock_mode = 0,
-};
-
-static void cxd_attach(struct ngene *dev)
-{
-	struct ngene_ci *ci = &dev->ci;
-
-	ci->en = cxd2099_attach(&cxd_cfg, dev, &dev->channel[0].i2c_adapter);
-	ci->dev = dev;
-	return;
-}
-
-static void cxd_detach(struct ngene *dev)
-{
-	struct ngene_ci *ci = &dev->ci;
-
-	dvb_ca_en50221_release(ci->en);
-	kfree(ci->en);
-	ci->en = 0;
-}
-
-/***********************************/
-/* workaround for shutdown failure */
-/***********************************/
-
-static void ngene_unlink(struct ngene *dev)
-{
-	struct ngene_command com;
-
-	com.cmd.hdr.Opcode = CMD_MEM_WRITE;
-	com.cmd.hdr.Length = 3;
-	com.cmd.MemoryWrite.address = 0x910c;
-	com.cmd.MemoryWrite.data = 0xff;
-	com.in_len = 3;
-	com.out_len = 1;
-
-	down(&dev->cmd_mutex);
-	ngwritel(0, NGENE_INT_ENABLE);
-	ngene_command_mutex(dev, &com);
-	up(&dev->cmd_mutex);
-}
-
-void ngene_shutdown(struct pci_dev *pdev)
-{
-	struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev);
-
-	if (!dev || !shutdown_workaround)
-		return;
-
-	printk(KERN_INFO DEVICE_NAME ": shutdown workaround...\n");
-	ngene_unlink(dev);
-	pci_disable_device(pdev);
-}
-
-/****************************************************************************/
-/* device probe/remove calls ************************************************/
-/****************************************************************************/
-
-void __devexit ngene_remove(struct pci_dev *pdev)
-{
-	struct ngene *dev = pci_get_drvdata(pdev);
-	int i;
-
-	tasklet_kill(&dev->event_tasklet);
-	for (i = MAX_STREAM - 1; i >= 0; i--)
-		release_channel(&dev->channel[i]);
-	if (dev->ci.en)
-		cxd_detach(dev);
-	ngene_stop(dev);
-	ngene_release_buffers(dev);
-	pci_set_drvdata(pdev, NULL);
-	pci_disable_device(pdev);
-}
-
-int __devinit ngene_probe(struct pci_dev *pci_dev,
-			  const struct pci_device_id *id)
-{
-	struct ngene *dev;
-	int stat = 0;
-
-	if (pci_enable_device(pci_dev) < 0)
-		return -ENODEV;
-
-	dev = vzalloc(sizeof(struct ngene));
-	if (dev == NULL) {
-		stat = -ENOMEM;
-		goto fail0;
-	}
-
-	dev->pci_dev = pci_dev;
-	dev->card_info = (struct ngene_info *)id->driver_data;
-	printk(KERN_INFO DEVICE_NAME ": Found %s\n", dev->card_info->name);
-
-	pci_set_drvdata(pci_dev, dev);
-
-	/* Alloc buffers and start nGene */
-	stat = ngene_get_buffers(dev);
-	if (stat < 0)
-		goto fail1;
-	stat = ngene_start(dev);
-	if (stat < 0)
-		goto fail1;
-
-	cxd_attach(dev);
-
-	stat = ngene_buffer_config(dev);
-	if (stat < 0)
-		goto fail1;
-
-
-	dev->i2c_current_bus = -1;
-
-	/* Register DVB adapters and devices for both channels */
-	if (init_channels(dev) < 0)
-		goto fail2;
-
-	return 0;
-
-fail2:
-	ngene_stop(dev);
-fail1:
-	ngene_release_buffers(dev);
-fail0:
-	pci_disable_device(pci_dev);
-	pci_set_drvdata(pci_dev, NULL);
-	return stat;
-}
diff --git a/drivers/media/dvb/ngene/ngene-dvb.c b/drivers/media/dvb/ngene/ngene-dvb.c
deleted file mode 100644
index fcb16a6..0000000
--- a/drivers/media/dvb/ngene/ngene-dvb.c
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * ngene-dvb.c: nGene PCIe bridge driver - DVB functions
- *
- * Copyright (C) 2005-2007 Micronas
- *
- * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
- *                         Modifications for new nGene firmware,
- *                         support for EEPROM-copying,
- *                         support for new dual DVB-S2 card prototype
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/io.h>
-#include <asm/div64.h>
-#include <linux/pci.h>
-#include <linux/timer.h>
-#include <linux/byteorder/generic.h>
-#include <linux/firmware.h>
-#include <linux/vmalloc.h>
-
-#include "ngene.h"
-
-
-/****************************************************************************/
-/* COMMAND API interface ****************************************************/
-/****************************************************************************/
-
-static ssize_t ts_write(struct file *file, const char *buf,
-			size_t count, loff_t *ppos)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct ngene_channel *chan = dvbdev->priv;
-	struct ngene *dev = chan->dev;
-
-	if (wait_event_interruptible(dev->tsout_rbuf.queue,
-				     dvb_ringbuffer_free
-				     (&dev->tsout_rbuf) >= count) < 0)
-		return 0;
-
-	dvb_ringbuffer_write(&dev->tsout_rbuf, buf, count);
-
-	return count;
-}
-
-static ssize_t ts_read(struct file *file, char *buf,
-		       size_t count, loff_t *ppos)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct ngene_channel *chan = dvbdev->priv;
-	struct ngene *dev = chan->dev;
-	int left, avail;
-
-	left = count;
-	while (left) {
-		if (wait_event_interruptible(
-			    dev->tsin_rbuf.queue,
-			    dvb_ringbuffer_avail(&dev->tsin_rbuf) > 0) < 0)
-			return -EAGAIN;
-		avail = dvb_ringbuffer_avail(&dev->tsin_rbuf);
-		if (avail > left)
-			avail = left;
-		dvb_ringbuffer_read_user(&dev->tsin_rbuf, buf, avail);
-		left -= avail;
-		buf += avail;
-	}
-	return count;
-}
-
-static const struct file_operations ci_fops = {
-	.owner   = THIS_MODULE,
-	.read    = ts_read,
-	.write   = ts_write,
-	.open    = dvb_generic_open,
-	.release = dvb_generic_release,
-};
-
-struct dvb_device ngene_dvbdev_ci = {
-	.priv    = 0,
-	.readers = -1,
-	.writers = -1,
-	.users   = -1,
-	.fops    = &ci_fops,
-};
-
-
-/****************************************************************************/
-/* DVB functions and API interface ******************************************/
-/****************************************************************************/
-
-static void swap_buffer(u32 *p, u32 len)
-{
-	while (len) {
-		*p = swab32(*p);
-		p++;
-		len -= 4;
-	}
-}
-
-/* start of filler packet */
-static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER };
-
-/* #define DEBUG_CI_XFER */
-#ifdef DEBUG_CI_XFER
-static u32 ok;
-static u32 overflow;
-static u32 stripped;
-#endif
-
-void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
-{
-	struct ngene_channel *chan = priv;
-	struct ngene *dev = chan->dev;
-
-
-	if (flags & DF_SWAP32)
-		swap_buffer(buf, len);
-
-	if (dev->ci.en && chan->number == 2) {
-		while (len >= 188) {
-			if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) {
-				if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) {
-					dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188);
-					wake_up(&dev->tsin_rbuf.queue);
-#ifdef DEBUG_CI_XFER
-					ok++;
-#endif
-				}
-#ifdef DEBUG_CI_XFER
-				else
-					overflow++;
-#endif
-			}
-#ifdef DEBUG_CI_XFER
-			else
-				stripped++;
-
-			if (ok % 100 == 0 && overflow)
-				printk(KERN_WARNING "%s: ok %u overflow %u dropped %u\n", __func__, ok, overflow, stripped);
-#endif
-			buf += 188;
-			len -= 188;
-		}
-		return NULL;
-	}
-
-	if (chan->users > 0)
-		dvb_dmx_swfilter(&chan->demux, buf, len);
-
-	return NULL;
-}
-
-void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
-{
-	struct ngene_channel *chan = priv;
-	struct ngene *dev = chan->dev;
-	u32 alen;
-
-	alen = dvb_ringbuffer_avail(&dev->tsout_rbuf);
-	alen -= alen % 188;
-
-	if (alen < len)
-		FillTSBuffer(buf + alen, len - alen, flags);
-	else
-		alen = len;
-	dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen);
-	if (flags & DF_SWAP32)
-		swap_buffer((u32 *)buf, alen);
-	wake_up_interruptible(&dev->tsout_rbuf.queue);
-	return buf;
-}
-
-
-
-int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-	struct ngene_channel *chan = dvbdmx->priv;
-
-	if (chan->users == 0) {
-		if (!chan->dev->cmd_timeout_workaround || !chan->running)
-			set_transfer(chan, 1);
-	}
-
-	return ++chan->users;
-}
-
-int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-	struct ngene_channel *chan = dvbdmx->priv;
-
-	if (--chan->users)
-		return chan->users;
-
-	if (!chan->dev->cmd_timeout_workaround)
-		set_transfer(chan, 0);
-
-	return 0;
-}
-
-int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
-			    int (*start_feed)(struct dvb_demux_feed *),
-			    int (*stop_feed)(struct dvb_demux_feed *),
-			    void *priv)
-{
-	dvbdemux->priv = priv;
-
-	dvbdemux->filternum = 256;
-	dvbdemux->feednum = 256;
-	dvbdemux->start_feed = start_feed;
-	dvbdemux->stop_feed = stop_feed;
-	dvbdemux->write_to_decoder = NULL;
-	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
-				      DMX_SECTION_FILTERING |
-				      DMX_MEMORY_BASED_FILTERING);
-	return dvb_dmx_init(dvbdemux);
-}
-
-int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
-			       struct dvb_demux *dvbdemux,
-			       struct dmx_frontend *hw_frontend,
-			       struct dmx_frontend *mem_frontend,
-			       struct dvb_adapter *dvb_adapter)
-{
-	int ret;
-
-	dmxdev->filternum = 256;
-	dmxdev->demux = &dvbdemux->dmx;
-	dmxdev->capabilities = 0;
-	ret = dvb_dmxdev_init(dmxdev, dvb_adapter);
-	if (ret < 0)
-		return ret;
-
-	hw_frontend->source = DMX_FRONTEND_0;
-	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend);
-	mem_frontend->source = DMX_MEMORY_FE;
-	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend);
-	return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend);
-}
diff --git a/drivers/media/dvb/ngene/ngene-i2c.c b/drivers/media/dvb/ngene/ngene-i2c.c
deleted file mode 100644
index d28554f..0000000
--- a/drivers/media/dvb/ngene/ngene-i2c.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * ngene-i2c.c: nGene PCIe bridge driver i2c functions
- *
- * Copyright (C) 2005-2007 Micronas
- *
- * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
- *                         Modifications for new nGene firmware,
- *                         support for EEPROM-copying,
- *                         support for new dual DVB-S2 card prototype
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-/* FIXME - some of these can probably be removed */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/io.h>
-#include <asm/div64.h>
-#include <linux/pci.h>
-#include <linux/pci_ids.h>
-#include <linux/timer.h>
-#include <linux/byteorder/generic.h>
-#include <linux/firmware.h>
-#include <linux/vmalloc.h>
-
-#include "ngene.h"
-
-/* Firmware command for i2c operations */
-static int ngene_command_i2c_read(struct ngene *dev, u8 adr,
-			   u8 *out, u8 outlen, u8 *in, u8 inlen, int flag)
-{
-	struct ngene_command com;
-
-	com.cmd.hdr.Opcode = CMD_I2C_READ;
-	com.cmd.hdr.Length = outlen + 3;
-	com.cmd.I2CRead.Device = adr << 1;
-	memcpy(com.cmd.I2CRead.Data, out, outlen);
-	com.cmd.I2CRead.Data[outlen] = inlen;
-	com.cmd.I2CRead.Data[outlen + 1] = 0;
-	com.in_len = outlen + 3;
-	com.out_len = inlen + 1;
-
-	if (ngene_command(dev, &com) < 0)
-		return -EIO;
-
-	if ((com.cmd.raw8[0] >> 1) != adr)
-		return -EIO;
-
-	if (flag)
-		memcpy(in, com.cmd.raw8, inlen + 1);
-	else
-		memcpy(in, com.cmd.raw8 + 1, inlen);
-	return 0;
-}
-
-static int ngene_command_i2c_write(struct ngene *dev, u8 adr,
-				   u8 *out, u8 outlen)
-{
-	struct ngene_command com;
-
-
-	com.cmd.hdr.Opcode = CMD_I2C_WRITE;
-	com.cmd.hdr.Length = outlen + 1;
-	com.cmd.I2CRead.Device = adr << 1;
-	memcpy(com.cmd.I2CRead.Data, out, outlen);
-	com.in_len = outlen + 1;
-	com.out_len = 1;
-
-	if (ngene_command(dev, &com) < 0)
-		return -EIO;
-
-	if (com.cmd.raw8[0] == 1)
-		return -EIO;
-
-	return 0;
-}
-
-static void ngene_i2c_set_bus(struct ngene *dev, int bus)
-{
-	if (!(dev->card_info->i2c_access & 2))
-		return;
-	if (dev->i2c_current_bus == bus)
-		return;
-
-	switch (bus) {
-	case 0:
-		ngene_command_gpio_set(dev, 3, 0);
-		ngene_command_gpio_set(dev, 2, 1);
-		break;
-
-	case 1:
-		ngene_command_gpio_set(dev, 2, 0);
-		ngene_command_gpio_set(dev, 3, 1);
-		break;
-	}
-	dev->i2c_current_bus = bus;
-}
-
-static int ngene_i2c_master_xfer(struct i2c_adapter *adapter,
-				 struct i2c_msg msg[], int num)
-{
-	struct ngene_channel *chan =
-		(struct ngene_channel *)i2c_get_adapdata(adapter);
-	struct ngene *dev = chan->dev;
-
-	down(&dev->i2c_switch_mutex);
-	ngene_i2c_set_bus(dev, chan->number);
-
-	if (num == 2 && msg[1].flags & I2C_M_RD && !(msg[0].flags & I2C_M_RD))
-		if (!ngene_command_i2c_read(dev, msg[0].addr,
-					    msg[0].buf, msg[0].len,
-					    msg[1].buf, msg[1].len, 0))
-			goto done;
-
-	if (num == 1 && !(msg[0].flags & I2C_M_RD))
-		if (!ngene_command_i2c_write(dev, msg[0].addr,
-					     msg[0].buf, msg[0].len))
-			goto done;
-	if (num == 1 && (msg[0].flags & I2C_M_RD))
-		if (!ngene_command_i2c_read(dev, msg[0].addr, NULL, 0,
-					    msg[0].buf, msg[0].len, 0))
-			goto done;
-
-	up(&dev->i2c_switch_mutex);
-	return -EIO;
-
-done:
-	up(&dev->i2c_switch_mutex);
-	return num;
-}
-
-
-static u32 ngene_i2c_functionality(struct i2c_adapter *adap)
-{
-	return I2C_FUNC_SMBUS_EMUL;
-}
-
-static struct i2c_algorithm ngene_i2c_algo = {
-	.master_xfer = ngene_i2c_master_xfer,
-	.functionality = ngene_i2c_functionality,
-};
-
-int ngene_i2c_init(struct ngene *dev, int dev_nr)
-{
-	struct i2c_adapter *adap = &(dev->channel[dev_nr].i2c_adapter);
-
-	i2c_set_adapdata(adap, &(dev->channel[dev_nr]));
-
-	strcpy(adap->name, "nGene");
-
-	adap->algo = &ngene_i2c_algo;
-	adap->algo_data = (void *)&(dev->channel[dev_nr]);
-	adap->dev.parent = &dev->pci_dev->dev;
-
-	return i2c_add_adapter(adap);
-}
-
diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h
deleted file mode 100644
index 5443dc0..0000000
--- a/drivers/media/dvb/ngene/ngene.h
+++ /dev/null
@@ -1,921 +0,0 @@
-/*
- * ngene.h: nGene PCIe bridge driver
- *
- * Copyright (C) 2005-2007 Micronas
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#ifndef _NGENE_H_
-#define _NGENE_H_
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <asm/dma.h>
-#include <linux/scatterlist.h>
-
-#include <linux/dvb/frontend.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_ca_en50221.h"
-#include "dvb_frontend.h"
-#include "dvb_ringbuffer.h"
-#include "dvb_net.h"
-#include "cxd2099.h"
-
-#define DEVICE_NAME "ngene"
-
-#define NGENE_VID       0x18c3
-#define NGENE_PID       0x0720
-
-#ifndef VIDEO_CAP_VC1
-#define VIDEO_CAP_AVC   128
-#define VIDEO_CAP_H264  128
-#define VIDEO_CAP_VC1   256
-#define VIDEO_CAP_WMV9  256
-#define VIDEO_CAP_MPEG4 512
-#endif
-
-enum STREAM {
-	STREAM_VIDEOIN1 = 0,        /* ITU656 or TS Input */
-	STREAM_VIDEOIN2,
-	STREAM_AUDIOIN1,            /* I2S or SPI Input */
-	STREAM_AUDIOIN2,
-	STREAM_AUDIOOUT,
-	MAX_STREAM
-};
-
-enum SMODE_BITS {
-	SMODE_AUDIO_SPDIF = 0x20,
-	SMODE_AVSYNC = 0x10,
-	SMODE_TRANSPORT_STREAM = 0x08,
-	SMODE_AUDIO_CAPTURE = 0x04,
-	SMODE_VBI_CAPTURE = 0x02,
-	SMODE_VIDEO_CAPTURE = 0x01
-};
-
-enum STREAM_FLAG_BITS {
-	SFLAG_CHROMA_FORMAT_2COMP  = 0x01, /* Chroma Format : 2's complement */
-	SFLAG_CHROMA_FORMAT_OFFSET = 0x00, /* Chroma Format : Binary offset */
-	SFLAG_ORDER_LUMA_CHROMA    = 0x02, /* Byte order: Y,Cb,Y,Cr */
-	SFLAG_ORDER_CHROMA_LUMA    = 0x00, /* Byte order: Cb,Y,Cr,Y */
-	SFLAG_COLORBAR             = 0x04, /* Select colorbar */
-};
-
-#define PROGRAM_ROM     0x0000
-#define PROGRAM_SRAM    0x1000
-#define PERIPHERALS0    0x8000
-#define PERIPHERALS1    0x9000
-#define SHARED_BUFFER   0xC000
-
-#define HOST_TO_NGENE    (SHARED_BUFFER+0x0000)
-#define NGENE_TO_HOST    (SHARED_BUFFER+0x0100)
-#define NGENE_COMMAND    (SHARED_BUFFER+0x0200)
-#define NGENE_COMMAND_HI (SHARED_BUFFER+0x0204)
-#define NGENE_STATUS     (SHARED_BUFFER+0x0208)
-#define NGENE_STATUS_HI  (SHARED_BUFFER+0x020C)
-#define NGENE_EVENT      (SHARED_BUFFER+0x0210)
-#define NGENE_EVENT_HI   (SHARED_BUFFER+0x0214)
-#define VARIABLES        (SHARED_BUFFER+0x0210)
-
-#define NGENE_INT_COUNTS       (SHARED_BUFFER+0x0260)
-#define NGENE_INT_ENABLE       (SHARED_BUFFER+0x0264)
-#define NGENE_VBI_LINE_COUNT   (SHARED_BUFFER+0x0268)
-
-#define BUFFER_GP_XMIT  (SHARED_BUFFER+0x0800)
-#define BUFFER_GP_RECV  (SHARED_BUFFER+0x0900)
-#define EEPROM_AREA     (SHARED_BUFFER+0x0A00)
-
-#define SG_V_IN_1       (SHARED_BUFFER+0x0A80)
-#define SG_VBI_1        (SHARED_BUFFER+0x0B00)
-#define SG_A_IN_1       (SHARED_BUFFER+0x0B80)
-#define SG_V_IN_2       (SHARED_BUFFER+0x0C00)
-#define SG_VBI_2        (SHARED_BUFFER+0x0C80)
-#define SG_A_IN_2       (SHARED_BUFFER+0x0D00)
-#define SG_V_OUT        (SHARED_BUFFER+0x0D80)
-#define SG_A_OUT2       (SHARED_BUFFER+0x0E00)
-
-#define DATA_A_IN_1     (SHARED_BUFFER+0x0E80)
-#define DATA_A_IN_2     (SHARED_BUFFER+0x0F00)
-#define DATA_A_OUT      (SHARED_BUFFER+0x0F80)
-#define DATA_V_IN_1     (SHARED_BUFFER+0x1000)
-#define DATA_V_IN_2     (SHARED_BUFFER+0x2000)
-#define DATA_V_OUT      (SHARED_BUFFER+0x3000)
-
-#define DATA_FIFO_AREA  (SHARED_BUFFER+0x1000)
-
-#define TIMESTAMPS      0xA000
-#define SCRATCHPAD      0xA080
-#define FORCE_INT       0xA088
-#define FORCE_NMI       0xA090
-#define INT_STATUS      0xA0A0
-
-#define DEV_VER         0x9004
-
-#define FW_DEBUG_DEFAULT (PROGRAM_SRAM+0x00FF)
-
-struct SG_ADDR {
-	u64 start;
-	u64 curr;
-	u16 curr_ptr;
-	u16 elements;
-	u32 pad[3];
-} __attribute__ ((__packed__));
-
-struct SHARED_MEMORY {
-	/* C000 */
-	u32 HostToNgene[64];
-
-	/* C100 */
-	u32 NgeneToHost[64];
-
-	/* C200 */
-	u64 NgeneCommand;
-	u64 NgeneStatus;
-	u64 NgeneEvent;
-
-	/* C210 */
-	u8 pad1[0xc260 - 0xc218];
-
-	/* C260 */
-	u32 IntCounts;
-	u32 IntEnable;
-
-	/* C268 */
-	u8 pad2[0xd000 - 0xc268];
-
-} __attribute__ ((__packed__));
-
-struct BUFFER_STREAM_RESULTS {
-	u32 Clock;           /* Stream time in 100ns units */
-	u16 RemainingLines;  /* Remaining lines in this field.
-				0 for complete field */
-	u8  FieldCount;      /* Video field number */
-	u8  Flags;           /* Bit 7 = Done, Bit 6 = seen, Bit 5 = overflow,
-				Bit 0 = FieldID */
-	u16 BlockCount;      /* Audio block count (unused) */
-	u8  Reserved[2];
-	u32 DTOUpdate;
-} __attribute__ ((__packed__));
-
-struct HW_SCATTER_GATHER_ELEMENT {
-	u64 Address;
-	u32 Length;
-	u32 Reserved;
-} __attribute__ ((__packed__));
-
-struct BUFFER_HEADER {
-	u64    Next;
-	struct BUFFER_STREAM_RESULTS SR;
-
-	u32    Number_of_entries_1;
-	u32    Reserved5;
-	u64    Address_of_first_entry_1;
-
-	u32    Number_of_entries_2;
-	u32    Reserved7;
-	u64    Address_of_first_entry_2;
-} __attribute__ ((__packed__));
-
-struct EVENT_BUFFER {
-	u32    TimeStamp;
-	u8     GPIOStatus;
-	u8     UARTStatus;
-	u8     RXCharacter;
-	u8     EventStatus;
-	u32    Reserved[2];
-} __attribute__ ((__packed__));
-
-/* Firmware commands. */
-
-enum OPCODES {
-	CMD_NOP = 0,
-	CMD_FWLOAD_PREPARE  = 0x01,
-	CMD_FWLOAD_FINISH   = 0x02,
-	CMD_I2C_READ        = 0x03,
-	CMD_I2C_WRITE       = 0x04,
-
-	CMD_I2C_WRITE_NOSTOP = 0x05,
-	CMD_I2C_CONTINUE_WRITE = 0x06,
-	CMD_I2C_CONTINUE_WRITE_NOSTOP = 0x07,
-
-	CMD_DEBUG_OUTPUT    = 0x09,
-
-	CMD_CONTROL         = 0x10,
-	CMD_CONFIGURE_BUFFER = 0x11,
-	CMD_CONFIGURE_FREE_BUFFER = 0x12,
-
-	CMD_SPI_READ        = 0x13,
-	CMD_SPI_WRITE       = 0x14,
-
-	CMD_MEM_READ        = 0x20,
-	CMD_MEM_WRITE	    = 0x21,
-	CMD_SFR_READ	    = 0x22,
-	CMD_SFR_WRITE	    = 0x23,
-	CMD_IRAM_READ	    = 0x24,
-	CMD_IRAM_WRITE	    = 0x25,
-	CMD_SET_GPIO_PIN    = 0x26,
-	CMD_SET_GPIO_INT    = 0x27,
-	CMD_CONFIGURE_UART  = 0x28,
-	CMD_WRITE_UART      = 0x29,
-	MAX_CMD
-};
-
-enum RESPONSES {
-	OK = 0,
-	ERROR = 1
-};
-
-struct FW_HEADER {
-	u8 Opcode;
-	u8 Length;
-} __attribute__ ((__packed__));
-
-struct FW_I2C_WRITE {
-	struct FW_HEADER hdr;
-	u8 Device;
-	u8 Data[250];
-} __attribute__ ((__packed__));
-
-struct FW_I2C_CONTINUE_WRITE {
-	struct FW_HEADER hdr;
-	u8 Data[250];
-} __attribute__ ((__packed__));
-
-struct FW_I2C_READ {
-	struct FW_HEADER hdr;
-	u8 Device;
-	u8 Data[252];    /* followed by two bytes of read data count */
-} __attribute__ ((__packed__));
-
-struct FW_SPI_WRITE {
-	struct FW_HEADER hdr;
-	u8 ModeSelect;
-	u8 Data[250];
-} __attribute__ ((__packed__));
-
-struct FW_SPI_READ {
-	struct FW_HEADER hdr;
-	u8 ModeSelect;
-	u8 Data[252];    /* followed by two bytes of read data count */
-} __attribute__ ((__packed__));
-
-struct FW_FWLOAD_PREPARE {
-	struct FW_HEADER hdr;
-} __attribute__ ((__packed__));
-
-struct FW_FWLOAD_FINISH {
-	struct FW_HEADER hdr;
-	u16 Address;     /* address of final block */
-	u16 Length;
-} __attribute__ ((__packed__));
-
-/*
- * Meaning of FW_STREAM_CONTROL::Mode bits:
- *  Bit 7: Loopback PEXin to PEXout using TVOut channel
- *  Bit 6: AVLOOP
- *  Bit 5: Audio select; 0=I2S, 1=SPDIF
- *  Bit 4: AVSYNC
- *  Bit 3: Enable transport stream
- *  Bit 2: Enable audio capture
- *  Bit 1: Enable ITU-Video VBI capture
- *  Bit 0: Enable ITU-Video capture
- *
- * Meaning of FW_STREAM_CONTROL::Control bits (see UVI1_CTL)
- *  Bit 7: continuous capture
- *  Bit 6: capture one field
- *  Bit 5: capture one frame
- *  Bit 4: unused
- *  Bit 3: starting field; 0=odd, 1=even
- *  Bit 2: sample size; 0=8-bit, 1=10-bit
- *  Bit 1: data format; 0=UYVY, 1=YUY2
- *  Bit 0: resets buffer pointers
-*/
-
-enum FSC_MODE_BITS {
-	SMODE_LOOPBACK          = 0x80,
-	SMODE_AVLOOP            = 0x40,
-	_SMODE_AUDIO_SPDIF      = 0x20,
-	_SMODE_AVSYNC           = 0x10,
-	_SMODE_TRANSPORT_STREAM = 0x08,
-	_SMODE_AUDIO_CAPTURE    = 0x04,
-	_SMODE_VBI_CAPTURE      = 0x02,
-	_SMODE_VIDEO_CAPTURE    = 0x01
-};
-
-
-/* Meaning of FW_STREAM_CONTROL::Stream bits:
- * Bit 3: Audio sample count:  0 = relative, 1 = absolute
- * Bit 2: color bar select; 1=color bars, 0=CV3 decoder
- * Bits 1-0: stream select, UVI1, UVI2, TVOUT
- */
-
-struct FW_STREAM_CONTROL {
-	struct FW_HEADER hdr;
-	u8     Stream;             /* Stream number (UVI1, UVI2, TVOUT) */
-	u8     Control;            /* Value written to UVI1_CTL */
-	u8     Mode;               /* Controls clock source */
-	u8     SetupDataLen;	   /* Length of setup data, MSB=1 write
-				      backwards */
-	u16    CaptureBlockCount;  /* Blocks (a 256 Bytes) to capture per buffer
-				      for TS and Audio */
-	u64    Buffer_Address;	   /* Address of first buffer header */
-	u16    BytesPerVideoLine;
-	u16    MaxLinesPerField;
-	u16    MinLinesPerField;
-	u16    Reserved_1;
-	u16    BytesPerVBILine;
-	u16    MaxVBILinesPerField;
-	u16    MinVBILinesPerField;
-	u16    SetupDataAddr;      /* ngene relative address of setup data */
-	u8     SetupData[32];      /* setup data */
-} __attribute__((__packed__));
-
-#define AUDIO_BLOCK_SIZE    256
-#define TS_BLOCK_SIZE       256
-
-struct FW_MEM_READ {
-	struct FW_HEADER hdr;
-	u16   address;
-} __attribute__ ((__packed__));
-
-struct FW_MEM_WRITE {
-	struct FW_HEADER hdr;
-	u16   address;
-	u8    data;
-} __attribute__ ((__packed__));
-
-struct FW_SFR_IRAM_READ {
-	struct FW_HEADER hdr;
-	u8    address;
-} __attribute__ ((__packed__));
-
-struct FW_SFR_IRAM_WRITE {
-	struct FW_HEADER hdr;
-	u8    address;
-	u8    data;
-} __attribute__ ((__packed__));
-
-struct FW_SET_GPIO_PIN {
-	struct FW_HEADER hdr;
-	u8    select;
-} __attribute__ ((__packed__));
-
-struct FW_SET_GPIO_INT {
-	struct FW_HEADER hdr;
-	u8    select;
-} __attribute__ ((__packed__));
-
-struct FW_SET_DEBUGMODE {
-	struct FW_HEADER hdr;
-	u8   debug_flags;
-} __attribute__ ((__packed__));
-
-struct FW_CONFIGURE_BUFFERS {
-	struct FW_HEADER hdr;
-	u8   config;
-} __attribute__ ((__packed__));
-
-enum _BUFFER_CONFIGS {
-	/* 4k UVI1, 4k UVI2, 2k AUD1, 2k AUD2  (standard usage) */
-	BUFFER_CONFIG_4422 = 0,
-	/* 3k UVI1, 3k UVI2, 3k AUD1, 3k AUD2  (4x TS input usage) */
-	BUFFER_CONFIG_3333 = 1,
-	/* 8k UVI1, 0k UVI2, 2k AUD1, 2k I2SOut  (HDTV decoder usage) */
-	BUFFER_CONFIG_8022 = 2,
-	BUFFER_CONFIG_FW17 = 255, /* Use new FW 17 command */
-};
-
-struct FW_CONFIGURE_FREE_BUFFERS {
-	struct FW_HEADER hdr;
-	u8   UVI1_BufferLength;
-	u8   UVI2_BufferLength;
-	u8   TVO_BufferLength;
-	u8   AUD1_BufferLength;
-	u8   AUD2_BufferLength;
-	u8   TVA_BufferLength;
-} __attribute__ ((__packed__));
-
-struct FW_CONFIGURE_UART {
-	struct FW_HEADER hdr;
-	u8 UartControl;
-} __attribute__ ((__packed__));
-
-enum _UART_CONFIG {
-	_UART_BAUDRATE_19200 = 0,
-	_UART_BAUDRATE_9600  = 1,
-	_UART_BAUDRATE_4800  = 2,
-	_UART_BAUDRATE_2400  = 3,
-	_UART_RX_ENABLE      = 0x40,
-	_UART_TX_ENABLE      = 0x80,
-};
-
-struct FW_WRITE_UART {
-	struct FW_HEADER hdr;
-	u8 Data[252];
-} __attribute__ ((__packed__));
-
-
-struct ngene_command {
-	u32 in_len;
-	u32 out_len;
-	union {
-		u32                              raw[64];
-		u8                               raw8[256];
-		struct FW_HEADER                 hdr;
-		struct FW_I2C_WRITE              I2CWrite;
-		struct FW_I2C_CONTINUE_WRITE     I2CContinueWrite;
-		struct FW_I2C_READ               I2CRead;
-		struct FW_STREAM_CONTROL         StreamControl;
-		struct FW_FWLOAD_PREPARE         FWLoadPrepare;
-		struct FW_FWLOAD_FINISH          FWLoadFinish;
-		struct FW_MEM_READ		 MemoryRead;
-		struct FW_MEM_WRITE		 MemoryWrite;
-		struct FW_SFR_IRAM_READ		 SfrIramRead;
-		struct FW_SFR_IRAM_WRITE         SfrIramWrite;
-		struct FW_SPI_WRITE              SPIWrite;
-		struct FW_SPI_READ               SPIRead;
-		struct FW_SET_GPIO_PIN           SetGpioPin;
-		struct FW_SET_GPIO_INT           SetGpioInt;
-		struct FW_SET_DEBUGMODE          SetDebugMode;
-		struct FW_CONFIGURE_BUFFERS      ConfigureBuffers;
-		struct FW_CONFIGURE_FREE_BUFFERS ConfigureFreeBuffers;
-		struct FW_CONFIGURE_UART         ConfigureUart;
-		struct FW_WRITE_UART             WriteUart;
-	} cmd;
-} __attribute__ ((__packed__));
-
-#define NGENE_INTERFACE_VERSION 0x103
-#define MAX_VIDEO_BUFFER_SIZE   (417792) /* 288*1440 rounded up to next page */
-#define MAX_AUDIO_BUFFER_SIZE     (8192) /* Gives room for about 23msec@48KHz */
-#define MAX_VBI_BUFFER_SIZE      (28672) /* 1144*18 rounded up to next page */
-#define MAX_TS_BUFFER_SIZE       (98304) /* 512*188 rounded up to next page */
-#define MAX_HDTV_BUFFER_SIZE   (2080768) /* 541*1920*2 rounded up to next page
-					    Max: (1920x1080i60) */
-
-#define OVERFLOW_BUFFER_SIZE    (8192)
-
-#define RING_SIZE_VIDEO     4
-#define RING_SIZE_AUDIO     8
-#define RING_SIZE_TS        8
-
-#define NUM_SCATTER_GATHER_ENTRIES  8
-
-#define MAX_DMA_LENGTH (((MAX_VIDEO_BUFFER_SIZE + MAX_VBI_BUFFER_SIZE) * \
-			RING_SIZE_VIDEO * 2) + \
-			(MAX_AUDIO_BUFFER_SIZE * RING_SIZE_AUDIO * 2) + \
-			(MAX_TS_BUFFER_SIZE * RING_SIZE_TS * 4) + \
-			(RING_SIZE_VIDEO * PAGE_SIZE * 2) + \
-			(RING_SIZE_AUDIO * PAGE_SIZE * 2) + \
-			(RING_SIZE_TS    * PAGE_SIZE * 4) + \
-			 8 * PAGE_SIZE + OVERFLOW_BUFFER_SIZE + PAGE_SIZE)
-
-#define EVENT_QUEUE_SIZE    16
-
-/* Gathers the current state of a single channel. */
-
-struct SBufferHeader {
-	struct BUFFER_HEADER   ngeneBuffer; /* Physical descriptor */
-	struct SBufferHeader  *Next;
-	void                  *Buffer1;
-	struct HW_SCATTER_GATHER_ELEMENT *scList1;
-	void                  *Buffer2;
-	struct HW_SCATTER_GATHER_ELEMENT *scList2;
-};
-
-/* Sizeof SBufferHeader aligned to next 64 Bit boundary (hw restriction) */
-#define SIZEOF_SBufferHeader ((sizeof(struct SBufferHeader) + 63) & ~63)
-
-enum HWSTATE {
-	HWSTATE_STOP,
-	HWSTATE_STARTUP,
-	HWSTATE_RUN,
-	HWSTATE_PAUSE,
-};
-
-enum KSSTATE {
-	KSSTATE_STOP,
-	KSSTATE_ACQUIRE,
-	KSSTATE_PAUSE,
-	KSSTATE_RUN,
-};
-
-struct SRingBufferDescriptor {
-	struct SBufferHeader *Head; /* Points to first buffer in ring buffer
-				       structure*/
-	u64   PAHead;         /* Physical address of first buffer */
-	u32   MemSize;        /* Memory size of allocated ring buffers
-				 (needed for freeing) */
-	u32   NumBuffers;     /* Number of buffers in the ring */
-	u32   Buffer1Length;  /* Allocated length of Buffer 1 */
-	u32   Buffer2Length;  /* Allocated length of Buffer 2 */
-	void *SCListMem;      /* Memory to hold scatter gather lists for this
-				 ring */
-	u64   PASCListMem;    /* Physical address  .. */
-	u32   SCListMemSize;  /* Size of this memory */
-};
-
-enum STREAMMODEFLAGS {
-	StreamMode_NONE   = 0, /* Stream not used */
-	StreamMode_ANALOG = 1, /* Analog: Stream 0,1 = Video, 2,3 = Audio */
-	StreamMode_TSIN   = 2, /* Transport stream input (all) */
-	StreamMode_HDTV   = 4, /* HDTV: Maximum 1920x1080p30,1920x1080i60
-				  (only stream 0) */
-	StreamMode_TSOUT  = 8, /* Transport stream output (only stream 3) */
-};
-
-
-enum BufferExchangeFlags {
-	BEF_EVEN_FIELD   = 0x00000001,
-	BEF_CONTINUATION = 0x00000002,
-	BEF_MORE_DATA    = 0x00000004,
-	BEF_OVERFLOW     = 0x00000008,
-	DF_SWAP32        = 0x00010000,
-};
-
-typedef void *(IBufferExchange)(void *, void *, u32, u32, u32);
-
-struct MICI_STREAMINFO {
-	IBufferExchange    *pExchange;
-	IBufferExchange    *pExchangeVBI;     /* Secondary (VBI, ancillary) */
-	u8  Stream;
-	u8  Flags;
-	u8  Mode;
-	u8  Reserved;
-	u16 nLinesVideo;
-	u16 nBytesPerLineVideo;
-	u16 nLinesVBI;
-	u16 nBytesPerLineVBI;
-	u32 CaptureLength;    /* Used for audio and transport stream */
-};
-
-/****************************************************************************/
-/* STRUCTS ******************************************************************/
-/****************************************************************************/
-
-/* sound hardware definition */
-#define MIXER_ADDR_TVTUNER      0
-#define MIXER_ADDR_LAST         0
-
-struct ngene_channel;
-
-/*struct sound chip*/
-
-struct mychip {
-	struct ngene_channel *chan;
-	struct snd_card *card;
-	struct pci_dev *pci;
-	struct snd_pcm_substream *substream;
-	struct snd_pcm *pcm;
-	unsigned long port;
-	int irq;
-	spinlock_t mixer_lock;
-	spinlock_t lock;
-	int mixer_volume[MIXER_ADDR_LAST + 1][2];
-	int capture_source[MIXER_ADDR_LAST + 1][2];
-};
-
-#ifdef NGENE_V4L
-struct ngene_overlay {
-	int                    tvnorm;
-	struct v4l2_rect       w;
-	enum v4l2_field        field;
-	struct v4l2_clip       *clips;
-	int                    nclips;
-	int                    setup_ok;
-};
-
-struct ngene_tvnorm {
-	int   v4l2_id;
-	char  *name;
-	u16   swidth, sheight; /* scaled standard width, height */
-	int   tuner_norm;
-	int   soundstd;
-};
-
-struct ngene_vopen {
-	struct ngene_channel      *ch;
-	enum v4l2_priority         prio;
-	int                        width;
-	int                        height;
-	int                        depth;
-	struct videobuf_queue      vbuf_q;
-	struct videobuf_queue      vbi;
-	int                        fourcc;
-	int                        picxcount;
-	int                        resources;
-	enum v4l2_buf_type         type;
-	const struct ngene_format *fmt;
-
-	const struct ngene_format *ovfmt;
-	struct ngene_overlay       ov;
-};
-#endif
-
-struct ngene_channel {
-	struct device         device;
-	struct i2c_adapter    i2c_adapter;
-
-	struct ngene         *dev;
-	int                   number;
-	int                   type;
-	int                   mode;
-	bool                  has_adapter;
-	bool                  has_demux;
-	int                   demod_type;
-	int (*gate_ctrl)(struct dvb_frontend *, int);
-
-	struct dvb_frontend  *fe;
-	struct dvb_frontend  *fe2;
-	struct dmxdev         dmxdev;
-	struct dvb_demux      demux;
-	struct dvb_net        dvbnet;
-	struct dmx_frontend   hw_frontend;
-	struct dmx_frontend   mem_frontend;
-	int                   users;
-	struct video_device  *v4l_dev;
-	struct dvb_device    *ci_dev;
-	struct tasklet_struct demux_tasklet;
-
-	struct SBufferHeader *nextBuffer;
-	enum KSSTATE          State;
-	enum HWSTATE          HWState;
-	u8                    Stream;
-	u8                    Flags;
-	u8                    Mode;
-	IBufferExchange      *pBufferExchange;
-	IBufferExchange      *pBufferExchange2;
-
-	spinlock_t            state_lock;
-	u16                   nLines;
-	u16                   nBytesPerLine;
-	u16                   nVBILines;
-	u16                   nBytesPerVBILine;
-	u16                   itumode;
-	u32                   Capture1Length;
-	u32                   Capture2Length;
-	struct SRingBufferDescriptor RingBuffer;
-	struct SRingBufferDescriptor TSRingBuffer;
-	struct SRingBufferDescriptor TSIdleBuffer;
-
-	u32                   DataFormatFlags;
-
-	int                   AudioDTOUpdated;
-	u32                   AudioDTOValue;
-
-	int (*set_tone)(struct dvb_frontend *, fe_sec_tone_mode_t);
-	u8 lnbh;
-
-	/* stuff from analog driver */
-
-	int minor;
-	struct mychip        *mychip;
-	struct snd_card      *soundcard;
-	u8                   *evenbuffer;
-	u8                    dma_on;
-	int                   soundstreamon;
-	int                   audiomute;
-	int                   soundbuffisallocated;
-	int                   sndbuffflag;
-	int                   tun_rdy;
-	int                   dec_rdy;
-	int                   tun_dec_rdy;
-	int                   lastbufferflag;
-
-	struct ngene_tvnorm  *tvnorms;
-	int                   tvnorm_num;
-	int                   tvnorm;
-
-#ifdef NGENE_V4L
-	int                   videousers;
-	struct v4l2_prio_state prio;
-	struct ngene_vopen    init;
-	int                   resources;
-	struct v4l2_framebuffer fbuf;
-	struct ngene_buffer  *screen;     /* overlay             */
-	struct list_head      capture;    /* video capture queue */
-	spinlock_t s_lock;
-	struct semaphore reslock;
-#endif
-
-	int running;
-};
-
-
-struct ngene_ci {
-	struct device         device;
-	struct i2c_adapter    i2c_adapter;
-
-	struct ngene         *dev;
-	struct dvb_ca_en50221 *en;
-};
-
-struct ngene;
-
-typedef void (rx_cb_t)(struct ngene *, u32, u8);
-typedef void (tx_cb_t)(struct ngene *, u32);
-
-struct ngene {
-	int                   nr;
-	struct pci_dev       *pci_dev;
-	unsigned char        *iomem;
-
-	/*struct i2c_adapter  i2c_adapter;*/
-
-	u32                   device_version;
-	u32                   fw_interface_version;
-	u32                   icounts;
-	bool                  msi_enabled;
-	bool                  cmd_timeout_workaround;
-
-	u8                   *CmdDoneByte;
-	int                   BootFirmware;
-	void                 *OverflowBuffer;
-	dma_addr_t            PAOverflowBuffer;
-	void                 *FWInterfaceBuffer;
-	dma_addr_t            PAFWInterfaceBuffer;
-	u8                   *ngenetohost;
-	u8                   *hosttongene;
-
-	struct EVENT_BUFFER   EventQueue[EVENT_QUEUE_SIZE];
-	int                   EventQueueOverflowCount;
-	int                   EventQueueOverflowFlag;
-	struct tasklet_struct event_tasklet;
-	struct EVENT_BUFFER  *EventBuffer;
-	int                   EventQueueWriteIndex;
-	int                   EventQueueReadIndex;
-
-	wait_queue_head_t     cmd_wq;
-	int                   cmd_done;
-	struct semaphore      cmd_mutex;
-	struct semaphore      stream_mutex;
-	struct semaphore      pll_mutex;
-	struct semaphore      i2c_switch_mutex;
-	int                   i2c_current_channel;
-	int                   i2c_current_bus;
-	spinlock_t            cmd_lock;
-
-	struct dvb_adapter    adapter[MAX_STREAM];
-	struct dvb_adapter    *first_adapter; /* "one_adapter" modprobe opt */
-	struct ngene_channel  channel[MAX_STREAM];
-
-	struct ngene_info    *card_info;
-
-	tx_cb_t              *TxEventNotify;
-	rx_cb_t              *RxEventNotify;
-	int                   tx_busy;
-	wait_queue_head_t     tx_wq;
-	wait_queue_head_t     rx_wq;
-#define UART_RBUF_LEN 4096
-	u8                    uart_rbuf[UART_RBUF_LEN];
-	int                   uart_rp, uart_wp;
-
-#define TS_FILLER  0x6f
-
-	u8                   *tsout_buf;
-#define TSOUT_BUF_SIZE (512*188*8)
-	struct dvb_ringbuffer tsout_rbuf;
-
-	u8                   *tsin_buf;
-#define TSIN_BUF_SIZE (512*188*8)
-	struct dvb_ringbuffer tsin_rbuf;
-
-	u8                   *ain_buf;
-#define AIN_BUF_SIZE (128*1024)
-	struct dvb_ringbuffer ain_rbuf;
-
-
-	u8                   *vin_buf;
-#define VIN_BUF_SIZE (4*1920*1080)
-	struct dvb_ringbuffer vin_rbuf;
-
-	unsigned long         exp_val;
-	int prev_cmd;
-
-	struct ngene_ci       ci;
-};
-
-struct ngene_info {
-	int   type;
-#define NGENE_APP        0
-#define NGENE_TERRATEC   1
-#define NGENE_SIDEWINDER 2
-#define NGENE_RACER      3
-#define NGENE_VIPER      4
-#define NGENE_PYTHON     5
-#define NGENE_VBOX_V1	 6
-#define NGENE_VBOX_V2	 7
-
-	int   fw_version;
-	bool  msi_supported;
-	char *name;
-
-	int   io_type[MAX_STREAM];
-#define NGENE_IO_NONE    0
-#define NGENE_IO_TV      1
-#define NGENE_IO_HDTV    2
-#define NGENE_IO_TSIN    4
-#define NGENE_IO_TSOUT   8
-#define NGENE_IO_AIN     16
-
-	void *fe_config[4];
-	void *tuner_config[4];
-
-	int (*demod_attach[4])(struct ngene_channel *);
-	int (*tuner_attach[4])(struct ngene_channel *);
-
-	u8    avf[4];
-	u8    msp[4];
-	u8    demoda[4];
-	u8    lnb[4];
-	int   i2c_access;
-	u8    ntsc;
-	u8    tsf[4];
-	u8    i2s[4];
-
-	int (*gate_ctrl)(struct dvb_frontend *, int);
-	int (*switch_ctrl)(struct ngene_channel *, int, int);
-};
-
-#ifdef NGENE_V4L
-struct ngene_format {
-	char *name;
-	int   fourcc;          /* video4linux 2      */
-	int   btformat;        /* BT848_COLOR_FMT_*  */
-	int   format;
-	int   btswap;          /* BT848_COLOR_CTL_*  */
-	int   depth;           /* bit/pixel          */
-	int   flags;
-	int   hshift, vshift;  /* for planar modes   */
-	int   palette;
-};
-
-#define RESOURCE_OVERLAY       1
-#define RESOURCE_VIDEO         2
-#define RESOURCE_VBI           4
-
-struct ngene_buffer {
-	/* common v4l buffer stuff -- must be first */
-	struct videobuf_buffer     vb;
-
-	/* ngene specific */
-	const struct ngene_format *fmt;
-	int                        tvnorm;
-	int                        btformat;
-	int                        btswap;
-};
-#endif
-
-
-/* Provided by ngene-core.c */
-int __devinit ngene_probe(struct pci_dev *pci_dev,
-			  const struct pci_device_id *id);
-void __devexit ngene_remove(struct pci_dev *pdev);
-void ngene_shutdown(struct pci_dev *pdev);
-int ngene_command(struct ngene *dev, struct ngene_command *com);
-int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level);
-void set_transfer(struct ngene_channel *chan, int state);
-void FillTSBuffer(void *Buffer, int Length, u32 Flags);
-
-/* Provided by ngene-i2c.c */
-int ngene_i2c_init(struct ngene *dev, int dev_nr);
-
-/* Provided by ngene-dvb.c */
-extern struct dvb_device ngene_dvbdev_ci;
-void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags);
-void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags);
-int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed);
-int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed);
-int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
-			    int (*start_feed)(struct dvb_demux_feed *),
-			    int (*stop_feed)(struct dvb_demux_feed *),
-			    void *priv);
-int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
-			       struct dvb_demux *dvbdemux,
-			       struct dmx_frontend *hw_frontend,
-			       struct dmx_frontend *mem_frontend,
-			       struct dvb_adapter *dvb_adapter);
-
-#endif
-
-/*  LocalWords:  Endif
- */
diff --git a/drivers/media/dvb/pluto2/Kconfig b/drivers/media/dvb/pluto2/Kconfig
deleted file mode 100644
index 7d8e6e8..0000000
--- a/drivers/media/dvb/pluto2/Kconfig
+++ /dev/null
@@ -1,15 +0,0 @@
-config DVB_PLUTO2
-	tristate "Pluto2 cards"
-	depends on DVB_CORE && PCI && I2C
-	select I2C_ALGOBIT
-	select DVB_TDA1004X
-	help
-	  Support for PCI cards based on the Pluto2 FPGA like the Satelco
-	  Easywatch Mobile Terrestrial DVB-T Receiver.
-
-	  Since these cards have no MPEG decoder onboard, they transmit
-	  only compressed MPEG data over the PCI bus, so you need
-	  an external software decoder to watch TV on your computer.
-
-	  Say Y or M if you own such a device and want to use it.
-
diff --git a/drivers/media/dvb/pluto2/Makefile b/drivers/media/dvb/pluto2/Makefile
deleted file mode 100644
index 7008223..0000000
--- a/drivers/media/dvb/pluto2/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_DVB_PLUTO2) += pluto2.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
deleted file mode 100644
index f148b19..0000000
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ /dev/null
@@ -1,815 +0,0 @@
-/*
- * pluto2.c - Satelco Easywatch Mobile Terrestrial Receiver [DVB-T]
- *
- * Copyright (C) 2005 Andreas Oberritter <obi@linuxtv.org>
- *
- * based on pluto2.c 1.10 - http://instinct-wp8.no-ip.org/pluto/
- * 	by Dany Salman <salmandany@yahoo.fr>
- *	Copyright (c) 2004 TDF
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-
-#include "demux.h"
-#include "dmxdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-#include "dvbdev.h"
-#include "tda1004x.h"
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define DRIVER_NAME		"pluto2"
-
-#define REG_PIDn(n)		((n) << 2)	/* PID n pattern registers */
-#define REG_PCAR		0x0020		/* PC address register */
-#define REG_TSCR		0x0024		/* TS ctrl & status */
-#define REG_MISC		0x0028		/* miscellaneous */
-#define REG_MMAC		0x002c		/* MSB MAC address */
-#define REG_IMAC		0x0030		/* ISB MAC address */
-#define REG_LMAC		0x0034		/* LSB MAC address */
-#define REG_SPID		0x0038		/* SPI data */
-#define REG_SLCS		0x003c		/* serial links ctrl/status */
-
-#define PID0_NOFIL		(0x0001 << 16)
-#define PIDn_ENP		(0x0001 << 15)
-#define PID0_END		(0x0001 << 14)
-#define PID0_AFIL		(0x0001 << 13)
-#define PIDn_PID		(0x1fff <<  0)
-
-#define TSCR_NBPACKETS		(0x00ff << 24)
-#define TSCR_DEM		(0x0001 << 17)
-#define TSCR_DE			(0x0001 << 16)
-#define TSCR_RSTN		(0x0001 << 15)
-#define TSCR_MSKO		(0x0001 << 14)
-#define TSCR_MSKA		(0x0001 << 13)
-#define TSCR_MSKL		(0x0001 << 12)
-#define TSCR_OVR		(0x0001 << 11)
-#define TSCR_AFUL		(0x0001 << 10)
-#define TSCR_LOCK		(0x0001 <<  9)
-#define TSCR_IACK		(0x0001 <<  8)
-#define TSCR_ADEF		(0x007f <<  0)
-
-#define MISC_DVR		(0x0fff <<  4)
-#define MISC_ALED		(0x0001 <<  3)
-#define MISC_FRST		(0x0001 <<  2)
-#define MISC_LED1		(0x0001 <<  1)
-#define MISC_LED0		(0x0001 <<  0)
-
-#define SPID_SPIDR		(0x00ff <<  0)
-
-#define SLCS_SCL		(0x0001 <<  7)
-#define SLCS_SDA		(0x0001 <<  6)
-#define SLCS_CSN		(0x0001 <<  2)
-#define SLCS_OVR		(0x0001 <<  1)
-#define SLCS_SWC		(0x0001 <<  0)
-
-#define TS_DMA_PACKETS		(8)
-#define TS_DMA_BYTES		(188 * TS_DMA_PACKETS)
-
-#define I2C_ADDR_TDA10046	0x10
-#define I2C_ADDR_TUA6034	0xc2
-#define NHWFILTERS		8
-
-struct pluto {
-	/* pci */
-	struct pci_dev *pdev;
-	u8 __iomem *io_mem;
-
-	/* dvb */
-	struct dmx_frontend hw_frontend;
-	struct dmx_frontend mem_frontend;
-	struct dmxdev dmxdev;
-	struct dvb_adapter dvb_adapter;
-	struct dvb_demux demux;
-	struct dvb_frontend *fe;
-	struct dvb_net dvbnet;
-	unsigned int full_ts_users;
-	unsigned int users;
-
-	/* i2c */
-	struct i2c_algo_bit_data i2c_bit;
-	struct i2c_adapter i2c_adap;
-	unsigned int i2cbug;
-
-	/* irq */
-	unsigned int overflow;
-	unsigned int dead;
-
-	/* dma */
-	dma_addr_t dma_addr;
-	u8 dma_buf[TS_DMA_BYTES];
-	u8 dummy[4096];
-};
-
-static inline struct pluto *feed_to_pluto(struct dvb_demux_feed *feed)
-{
-	return container_of(feed->demux, struct pluto, demux);
-}
-
-static inline struct pluto *frontend_to_pluto(struct dvb_frontend *fe)
-{
-	return container_of(fe->dvb, struct pluto, dvb_adapter);
-}
-
-static inline u32 pluto_readreg(struct pluto *pluto, u32 reg)
-{
-	return readl(&pluto->io_mem[reg]);
-}
-
-static inline void pluto_writereg(struct pluto *pluto, u32 reg, u32 val)
-{
-	writel(val, &pluto->io_mem[reg]);
-}
-
-static inline void pluto_rw(struct pluto *pluto, u32 reg, u32 mask, u32 bits)
-{
-	u32 val = readl(&pluto->io_mem[reg]);
-	val &= ~mask;
-	val |= bits;
-	writel(val, &pluto->io_mem[reg]);
-}
-
-static void pluto_write_tscr(struct pluto *pluto, u32 val)
-{
-	/* set the number of packets */
-	val &= ~TSCR_ADEF;
-	val |= TS_DMA_PACKETS / 2;
-
-	pluto_writereg(pluto, REG_TSCR, val);
-}
-
-static void pluto_setsda(void *data, int state)
-{
-	struct pluto *pluto = data;
-
-	if (state)
-		pluto_rw(pluto, REG_SLCS, SLCS_SDA, SLCS_SDA);
-	else
-		pluto_rw(pluto, REG_SLCS, SLCS_SDA, 0);
-}
-
-static void pluto_setscl(void *data, int state)
-{
-	struct pluto *pluto = data;
-
-	if (state)
-		pluto_rw(pluto, REG_SLCS, SLCS_SCL, SLCS_SCL);
-	else
-		pluto_rw(pluto, REG_SLCS, SLCS_SCL, 0);
-
-	/* try to detect i2c_inb() to workaround hardware bug:
-	 * reset SDA to high after SCL has been set to low */
-	if ((state) && (pluto->i2cbug == 0)) {
-		pluto->i2cbug = 1;
-	} else {
-		if ((!state) && (pluto->i2cbug == 1))
-			pluto_setsda(pluto, 1);
-		pluto->i2cbug = 0;
-	}
-}
-
-static int pluto_getsda(void *data)
-{
-	struct pluto *pluto = data;
-
-	return pluto_readreg(pluto, REG_SLCS) & SLCS_SDA;
-}
-
-static int pluto_getscl(void *data)
-{
-	struct pluto *pluto = data;
-
-	return pluto_readreg(pluto, REG_SLCS) & SLCS_SCL;
-}
-
-static void pluto_reset_frontend(struct pluto *pluto, int reenable)
-{
-	u32 val = pluto_readreg(pluto, REG_MISC);
-
-	if (val & MISC_FRST) {
-		val &= ~MISC_FRST;
-		pluto_writereg(pluto, REG_MISC, val);
-	}
-	if (reenable) {
-		val |= MISC_FRST;
-		pluto_writereg(pluto, REG_MISC, val);
-	}
-}
-
-static void pluto_reset_ts(struct pluto *pluto, int reenable)
-{
-	u32 val = pluto_readreg(pluto, REG_TSCR);
-
-	if (val & TSCR_RSTN) {
-		val &= ~TSCR_RSTN;
-		pluto_write_tscr(pluto, val);
-	}
-	if (reenable) {
-		val |= TSCR_RSTN;
-		pluto_write_tscr(pluto, val);
-	}
-}
-
-static void pluto_set_dma_addr(struct pluto *pluto)
-{
-	pluto_writereg(pluto, REG_PCAR, pluto->dma_addr);
-}
-
-static int __devinit pluto_dma_map(struct pluto *pluto)
-{
-	pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf,
-			TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
-
-	return pci_dma_mapping_error(pluto->pdev, pluto->dma_addr);
-}
-
-static void pluto_dma_unmap(struct pluto *pluto)
-{
-	pci_unmap_single(pluto->pdev, pluto->dma_addr,
-			TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
-}
-
-static int pluto_start_feed(struct dvb_demux_feed *f)
-{
-	struct pluto *pluto = feed_to_pluto(f);
-
-	/* enable PID filtering */
-	if (pluto->users++ == 0)
-		pluto_rw(pluto, REG_PIDn(0), PID0_AFIL | PID0_NOFIL, 0);
-
-	if ((f->pid < 0x2000) && (f->index < NHWFILTERS))
-		pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, PIDn_ENP | f->pid);
-	else if (pluto->full_ts_users++ == 0)
-		pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, PID0_NOFIL);
-
-	return 0;
-}
-
-static int pluto_stop_feed(struct dvb_demux_feed *f)
-{
-	struct pluto *pluto = feed_to_pluto(f);
-
-	/* disable PID filtering */
-	if (--pluto->users == 0)
-		pluto_rw(pluto, REG_PIDn(0), PID0_AFIL, PID0_AFIL);
-
-	if ((f->pid < 0x2000) && (f->index < NHWFILTERS))
-		pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, 0x1fff);
-	else if (--pluto->full_ts_users == 0)
-		pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, 0);
-
-	return 0;
-}
-
-static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets)
-{
-	/* synchronize the DMA transfer with the CPU
-	 * first so that we see updated contents. */
-	pci_dma_sync_single_for_cpu(pluto->pdev, pluto->dma_addr,
-			TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
-
-	/* Workaround for broken hardware:
-	 * [1] On startup NBPACKETS seems to contain an uninitialized value,
-	 *     but no packets have been transferred.
-	 * [2] Sometimes (actually very often) NBPACKETS stays at zero
-	 *     although one packet has been transferred.
-	 * [3] Sometimes (actually rarely), the card gets into an erroneous
-	 *     mode where it continuously generates interrupts, claiming it
-	 *     has received nbpackets>TS_DMA_PACKETS packets, but no packet
-	 *     has been transferred. Only a reset seems to solve this
-	 */
-	if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) {
-		unsigned int i = 0;
-		while (pluto->dma_buf[i] == 0x47)
-			i += 188;
-		nbpackets = i / 188;
-		if (i == 0) {
-			pluto_reset_ts(pluto, 1);
-			dev_printk(KERN_DEBUG, &pluto->pdev->dev, "resetting TS because of invalid packet counter\n");
-		}
-	}
-
-	dvb_dmx_swfilter_packets(&pluto->demux, pluto->dma_buf, nbpackets);
-
-	/* clear the dma buffer. this is needed to be able to identify
-	 * new valid ts packets above */
-	memset(pluto->dma_buf, 0, nbpackets * 188);
-
-	/* reset the dma address */
-	pluto_set_dma_addr(pluto);
-
-	/* sync the buffer and give it back to the card */
-	pci_dma_sync_single_for_device(pluto->pdev, pluto->dma_addr,
-			TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
-}
-
-static irqreturn_t pluto_irq(int irq, void *dev_id)
-{
-	struct pluto *pluto = dev_id;
-	u32 tscr;
-
-	/* check whether an interrupt occurred on this device */
-	tscr = pluto_readreg(pluto, REG_TSCR);
-	if (!(tscr & (TSCR_DE | TSCR_OVR)))
-		return IRQ_NONE;
-
-	if (tscr == 0xffffffff) {
-		if (pluto->dead == 0)
-			dev_err(&pluto->pdev->dev, "card has hung or been ejected.\n");
-		/* It's dead Jim */
-		pluto->dead = 1;
-		return IRQ_HANDLED;
-	}
-
-	/* dma end interrupt */
-	if (tscr & TSCR_DE) {
-		pluto_dma_end(pluto, (tscr & TSCR_NBPACKETS) >> 24);
-		/* overflow interrupt */
-		if (tscr & TSCR_OVR)
-			pluto->overflow++;
-		if (pluto->overflow) {
-			dev_err(&pluto->pdev->dev, "overflow irq (%d)\n",
-					pluto->overflow);
-			pluto_reset_ts(pluto, 1);
-			pluto->overflow = 0;
-		}
-	} else if (tscr & TSCR_OVR) {
-		pluto->overflow++;
-	}
-
-	/* ACK the interrupt */
-	pluto_write_tscr(pluto, tscr | TSCR_IACK);
-
-	return IRQ_HANDLED;
-}
-
-static void __devinit pluto_enable_irqs(struct pluto *pluto)
-{
-	u32 val = pluto_readreg(pluto, REG_TSCR);
-
-	/* disable AFUL and LOCK interrupts */
-	val |= (TSCR_MSKA | TSCR_MSKL);
-	/* enable DMA and OVERFLOW interrupts */
-	val &= ~(TSCR_DEM | TSCR_MSKO);
-	/* clear pending interrupts */
-	val |= TSCR_IACK;
-
-	pluto_write_tscr(pluto, val);
-}
-
-static void pluto_disable_irqs(struct pluto *pluto)
-{
-	u32 val = pluto_readreg(pluto, REG_TSCR);
-
-	/* disable all interrupts */
-	val |= (TSCR_DEM | TSCR_MSKO | TSCR_MSKA | TSCR_MSKL);
-	/* clear pending interrupts */
-	val |= TSCR_IACK;
-
-	pluto_write_tscr(pluto, val);
-}
-
-static int __devinit pluto_hw_init(struct pluto *pluto)
-{
-	pluto_reset_frontend(pluto, 1);
-
-	/* set automatic LED control by FPGA */
-	pluto_rw(pluto, REG_MISC, MISC_ALED, MISC_ALED);
-
-	/* set data endianess */
-#ifdef __LITTLE_ENDIAN
-	pluto_rw(pluto, REG_PIDn(0), PID0_END, PID0_END);
-#else
-	pluto_rw(pluto, REG_PIDn(0), PID0_END, 0);
-#endif
-	/* map DMA and set address */
-	pluto_dma_map(pluto);
-	pluto_set_dma_addr(pluto);
-
-	/* enable interrupts */
-	pluto_enable_irqs(pluto);
-
-	/* reset TS logic */
-	pluto_reset_ts(pluto, 1);
-
-	return 0;
-}
-
-static void pluto_hw_exit(struct pluto *pluto)
-{
-	/* disable interrupts */
-	pluto_disable_irqs(pluto);
-
-	pluto_reset_ts(pluto, 0);
-
-	/* LED: disable automatic control, enable yellow, disable green */
-	pluto_rw(pluto, REG_MISC, MISC_ALED | MISC_LED1 | MISC_LED0, MISC_LED1);
-
-	/* unmap DMA */
-	pluto_dma_unmap(pluto);
-
-	pluto_reset_frontend(pluto, 0);
-}
-
-static inline u32 divide(u32 numerator, u32 denominator)
-{
-	if (denominator == 0)
-		return ~0;
-
-	return DIV_ROUND_CLOSEST(numerator, denominator);
-}
-
-/* LG Innotek TDTE-E001P (Infineon TUA6034) */
-static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct pluto *pluto = frontend_to_pluto(fe);
-	struct i2c_msg msg;
-	int ret;
-	u8 buf[4];
-	u32 div;
-
-	// Fref = 166.667 Hz
-	// Fref * 3 = 500.000 Hz
-	// IF = 36166667
-	// IF / Fref = 217
-	//div = divide(p->frequency + 36166667, 166667);
-	div = divide(p->frequency * 3, 500000) + 217;
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = (div >> 0) & 0xff;
-
-	if (p->frequency < 611000000)
-		buf[2] = 0xb4;
-	else if (p->frequency < 811000000)
-		buf[2] = 0xbc;
-	else
-		buf[2] = 0xf4;
-
-	// VHF: 174-230 MHz
-	// center: 350 MHz
-	// UHF: 470-862 MHz
-	if (p->frequency < 350000000)
-		buf[3] = 0x02;
-	else
-		buf[3] = 0x04;
-
-	if (p->bandwidth_hz == 8000000)
-		buf[3] |= 0x08;
-
-	msg.addr = I2C_ADDR_TUA6034 >> 1;
-	msg.flags = 0;
-	msg.buf = buf;
-	msg.len = sizeof(buf);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	ret = i2c_transfer(&pluto->i2c_adap, &msg, 1);
-	if (ret < 0)
-		return ret;
-	else if (ret == 0)
-		return -EREMOTEIO;
-
-	return 0;
-}
-
-static int pluto2_request_firmware(struct dvb_frontend *fe,
-				   const struct firmware **fw, char *name)
-{
-	struct pluto *pluto = frontend_to_pluto(fe);
-
-	return request_firmware(fw, name, &pluto->pdev->dev);
-}
-
-static struct tda1004x_config pluto2_fe_config __devinitdata = {
-	.demod_address = I2C_ADDR_TDA10046 >> 1,
-	.invert = 1,
-	.invert_oclk = 0,
-	.xtal_freq = TDA10046_XTAL_16M,
-	.agc_config = TDA10046_AGC_DEFAULT,
-	.if_freq = TDA10046_FREQ_3617,
-	.request_firmware = pluto2_request_firmware,
-};
-
-static int __devinit frontend_init(struct pluto *pluto)
-{
-	int ret;
-
-	pluto->fe = tda10046_attach(&pluto2_fe_config, &pluto->i2c_adap);
-	if (!pluto->fe) {
-		dev_err(&pluto->pdev->dev, "could not attach frontend\n");
-		return -ENODEV;
-	}
-	pluto->fe->ops.tuner_ops.set_params = lg_tdtpe001p_tuner_set_params;
-
-	ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe);
-	if (ret < 0) {
-		if (pluto->fe->ops.release)
-			pluto->fe->ops.release(pluto->fe);
-		return ret;
-	}
-
-	return 0;
-}
-
-static void __devinit pluto_read_rev(struct pluto *pluto)
-{
-	u32 val = pluto_readreg(pluto, REG_MISC) & MISC_DVR;
-	dev_info(&pluto->pdev->dev, "board revision %d.%d\n",
-			(val >> 12) & 0x0f, (val >> 4) & 0xff);
-}
-
-static void __devinit pluto_read_mac(struct pluto *pluto, u8 *mac)
-{
-	u32 val = pluto_readreg(pluto, REG_MMAC);
-	mac[0] = (val >> 8) & 0xff;
-	mac[1] = (val >> 0) & 0xff;
-
-	val = pluto_readreg(pluto, REG_IMAC);
-	mac[2] = (val >> 8) & 0xff;
-	mac[3] = (val >> 0) & 0xff;
-
-	val = pluto_readreg(pluto, REG_LMAC);
-	mac[4] = (val >> 8) & 0xff;
-	mac[5] = (val >> 0) & 0xff;
-
-	dev_info(&pluto->pdev->dev, "MAC %pM\n", mac);
-}
-
-static int __devinit pluto_read_serial(struct pluto *pluto)
-{
-	struct pci_dev *pdev = pluto->pdev;
-	unsigned int i, j;
-	u8 __iomem *cis;
-
-	cis = pci_iomap(pdev, 1, 0);
-	if (!cis)
-		return -EIO;
-
-	dev_info(&pdev->dev, "S/N ");
-
-	for (i = 0xe0; i < 0x100; i += 4) {
-		u32 val = readl(&cis[i]);
-		for (j = 0; j < 32; j += 8) {
-			if ((val & 0xff) == 0xff)
-				goto out;
-			printk("%c", val & 0xff);
-			val >>= 8;
-		}
-	}
-out:
-	printk("\n");
-	pci_iounmap(pdev, cis);
-
-	return 0;
-}
-
-static int __devinit pluto2_probe(struct pci_dev *pdev,
-				  const struct pci_device_id *ent)
-{
-	struct pluto *pluto;
-	struct dvb_adapter *dvb_adapter;
-	struct dvb_demux *dvbdemux;
-	struct dmx_demux *dmx;
-	int ret = -ENOMEM;
-
-	pluto = kzalloc(sizeof(struct pluto), GFP_KERNEL);
-	if (!pluto)
-		goto out;
-
-	pluto->pdev = pdev;
-
-	ret = pci_enable_device(pdev);
-	if (ret < 0)
-		goto err_kfree;
-
-	/* enable interrupts */
-	pci_write_config_dword(pdev, 0x6c, 0x8000);
-
-	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-	if (ret < 0)
-		goto err_pci_disable_device;
-
-	pci_set_master(pdev);
-
-	ret = pci_request_regions(pdev, DRIVER_NAME);
-	if (ret < 0)
-		goto err_pci_disable_device;
-
-	pluto->io_mem = pci_iomap(pdev, 0, 0x40);
-	if (!pluto->io_mem) {
-		ret = -EIO;
-		goto err_pci_release_regions;
-	}
-
-	pci_set_drvdata(pdev, pluto);
-
-	ret = request_irq(pdev->irq, pluto_irq, IRQF_SHARED, DRIVER_NAME, pluto);
-	if (ret < 0)
-		goto err_pci_iounmap;
-
-	ret = pluto_hw_init(pluto);
-	if (ret < 0)
-		goto err_free_irq;
-
-	/* i2c */
-	i2c_set_adapdata(&pluto->i2c_adap, pluto);
-	strcpy(pluto->i2c_adap.name, DRIVER_NAME);
-	pluto->i2c_adap.owner = THIS_MODULE;
-	pluto->i2c_adap.dev.parent = &pdev->dev;
-	pluto->i2c_adap.algo_data = &pluto->i2c_bit;
-	pluto->i2c_bit.data = pluto;
-	pluto->i2c_bit.setsda = pluto_setsda;
-	pluto->i2c_bit.setscl = pluto_setscl;
-	pluto->i2c_bit.getsda = pluto_getsda;
-	pluto->i2c_bit.getscl = pluto_getscl;
-	pluto->i2c_bit.udelay = 10;
-	pluto->i2c_bit.timeout = 10;
-
-	/* Raise SCL and SDA */
-	pluto_setsda(pluto, 1);
-	pluto_setscl(pluto, 1);
-
-	ret = i2c_bit_add_bus(&pluto->i2c_adap);
-	if (ret < 0)
-		goto err_pluto_hw_exit;
-
-	/* dvb */
-	ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME,
-				   THIS_MODULE, &pdev->dev, adapter_nr);
-	if (ret < 0)
-		goto err_i2c_del_adapter;
-
-	dvb_adapter = &pluto->dvb_adapter;
-
-	pluto_read_rev(pluto);
-	pluto_read_serial(pluto);
-	pluto_read_mac(pluto, dvb_adapter->proposed_mac);
-
-	dvbdemux = &pluto->demux;
-	dvbdemux->filternum = 256;
-	dvbdemux->feednum = 256;
-	dvbdemux->start_feed = pluto_start_feed;
-	dvbdemux->stop_feed = pluto_stop_feed;
-	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
-			DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
-	ret = dvb_dmx_init(dvbdemux);
-	if (ret < 0)
-		goto err_dvb_unregister_adapter;
-
-	dmx = &dvbdemux->dmx;
-
-	pluto->hw_frontend.source = DMX_FRONTEND_0;
-	pluto->mem_frontend.source = DMX_MEMORY_FE;
-	pluto->dmxdev.filternum = NHWFILTERS;
-	pluto->dmxdev.demux = dmx;
-
-	ret = dvb_dmxdev_init(&pluto->dmxdev, dvb_adapter);
-	if (ret < 0)
-		goto err_dvb_dmx_release;
-
-	ret = dmx->add_frontend(dmx, &pluto->hw_frontend);
-	if (ret < 0)
-		goto err_dvb_dmxdev_release;
-
-	ret = dmx->add_frontend(dmx, &pluto->mem_frontend);
-	if (ret < 0)
-		goto err_remove_hw_frontend;
-
-	ret = dmx->connect_frontend(dmx, &pluto->hw_frontend);
-	if (ret < 0)
-		goto err_remove_mem_frontend;
-
-	ret = frontend_init(pluto);
-	if (ret < 0)
-		goto err_disconnect_frontend;
-
-	dvb_net_init(dvb_adapter, &pluto->dvbnet, dmx);
-out:
-	return ret;
-
-err_disconnect_frontend:
-	dmx->disconnect_frontend(dmx);
-err_remove_mem_frontend:
-	dmx->remove_frontend(dmx, &pluto->mem_frontend);
-err_remove_hw_frontend:
-	dmx->remove_frontend(dmx, &pluto->hw_frontend);
-err_dvb_dmxdev_release:
-	dvb_dmxdev_release(&pluto->dmxdev);
-err_dvb_dmx_release:
-	dvb_dmx_release(dvbdemux);
-err_dvb_unregister_adapter:
-	dvb_unregister_adapter(dvb_adapter);
-err_i2c_del_adapter:
-	i2c_del_adapter(&pluto->i2c_adap);
-err_pluto_hw_exit:
-	pluto_hw_exit(pluto);
-err_free_irq:
-	free_irq(pdev->irq, pluto);
-err_pci_iounmap:
-	pci_iounmap(pdev, pluto->io_mem);
-err_pci_release_regions:
-	pci_release_regions(pdev);
-err_pci_disable_device:
-	pci_disable_device(pdev);
-err_kfree:
-	pci_set_drvdata(pdev, NULL);
-	kfree(pluto);
-	goto out;
-}
-
-static void __devexit pluto2_remove(struct pci_dev *pdev)
-{
-	struct pluto *pluto = pci_get_drvdata(pdev);
-	struct dvb_adapter *dvb_adapter = &pluto->dvb_adapter;
-	struct dvb_demux *dvbdemux = &pluto->demux;
-	struct dmx_demux *dmx = &dvbdemux->dmx;
-
-	dmx->close(dmx);
-	dvb_net_release(&pluto->dvbnet);
-	if (pluto->fe)
-		dvb_unregister_frontend(pluto->fe);
-
-	dmx->disconnect_frontend(dmx);
-	dmx->remove_frontend(dmx, &pluto->mem_frontend);
-	dmx->remove_frontend(dmx, &pluto->hw_frontend);
-	dvb_dmxdev_release(&pluto->dmxdev);
-	dvb_dmx_release(dvbdemux);
-	dvb_unregister_adapter(dvb_adapter);
-	i2c_del_adapter(&pluto->i2c_adap);
-	pluto_hw_exit(pluto);
-	free_irq(pdev->irq, pluto);
-	pci_iounmap(pdev, pluto->io_mem);
-	pci_release_regions(pdev);
-	pci_disable_device(pdev);
-	pci_set_drvdata(pdev, NULL);
-	kfree(pluto);
-}
-
-#ifndef PCI_VENDOR_ID_SCM
-#define PCI_VENDOR_ID_SCM	0x0432
-#endif
-#ifndef PCI_DEVICE_ID_PLUTO2
-#define PCI_DEVICE_ID_PLUTO2	0x0001
-#endif
-
-static struct pci_device_id pluto2_id_table[] __devinitdata = {
-	{
-		.vendor = PCI_VENDOR_ID_SCM,
-		.device = PCI_DEVICE_ID_PLUTO2,
-		.subvendor = PCI_ANY_ID,
-		.subdevice = PCI_ANY_ID,
-	}, {
-		/* empty */
-	},
-};
-
-MODULE_DEVICE_TABLE(pci, pluto2_id_table);
-
-static struct pci_driver pluto2_driver = {
-	.name = DRIVER_NAME,
-	.id_table = pluto2_id_table,
-	.probe = pluto2_probe,
-	.remove = __devexit_p(pluto2_remove),
-};
-
-static int __init pluto2_init(void)
-{
-	return pci_register_driver(&pluto2_driver);
-}
-
-static void __exit pluto2_exit(void)
-{
-	pci_unregister_driver(&pluto2_driver);
-}
-
-module_init(pluto2_init);
-module_exit(pluto2_exit);
-
-MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
-MODULE_DESCRIPTION("Pluto2 driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/pt1/Kconfig b/drivers/media/dvb/pt1/Kconfig
deleted file mode 100644
index 24501d5..0000000
--- a/drivers/media/dvb/pt1/Kconfig
+++ /dev/null
@@ -1,12 +0,0 @@
-config DVB_PT1
-	tristate "PT1 cards"
-	depends on DVB_CORE && PCI && I2C
-	help
-	  Support for Earthsoft PT1 PCI cards.
-
-	  Since these cards have no MPEG decoder onboard, they transmit
-	  only compressed MPEG data over the PCI bus, so you need
-	  an external software decoder to watch TV on your computer.
-
-	  Say Y or M if you own such a device and want to use it.
-
diff --git a/drivers/media/dvb/pt1/Makefile b/drivers/media/dvb/pt1/Makefile
deleted file mode 100644
index d80d8e8..0000000
--- a/drivers/media/dvb/pt1/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-earth-pt1-objs := pt1.o va1j5jf8007s.o va1j5jf8007t.o
-
-obj-$(CONFIG_DVB_PT1) += earth-pt1.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/pt1/pt1.c b/drivers/media/dvb/pt1/pt1.c
deleted file mode 100644
index 15b35c4..0000000
--- a/drivers/media/dvb/pt1/pt1.c
+++ /dev/null
@@ -1,1246 +0,0 @@
-/*
- * driver for Earthsoft PT1/PT2
- *
- * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
- *
- * based on pt1dvr - http://pt1dvr.sourceforge.jp/
- * 	by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/pci.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-#include <linux/ratelimit.h>
-
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dmxdev.h"
-#include "dvb_net.h"
-#include "dvb_frontend.h"
-
-#include "va1j5jf8007t.h"
-#include "va1j5jf8007s.h"
-
-#define DRIVER_NAME "earth-pt1"
-
-#define PT1_PAGE_SHIFT 12
-#define PT1_PAGE_SIZE (1 << PT1_PAGE_SHIFT)
-#define PT1_NR_UPACKETS 1024
-#define PT1_NR_BUFS 511
-
-struct pt1_buffer_page {
-	__le32 upackets[PT1_NR_UPACKETS];
-};
-
-struct pt1_table_page {
-	__le32 next_pfn;
-	__le32 buf_pfns[PT1_NR_BUFS];
-};
-
-struct pt1_buffer {
-	struct pt1_buffer_page *page;
-	dma_addr_t addr;
-};
-
-struct pt1_table {
-	struct pt1_table_page *page;
-	dma_addr_t addr;
-	struct pt1_buffer bufs[PT1_NR_BUFS];
-};
-
-#define PT1_NR_ADAPS 4
-
-struct pt1_adapter;
-
-struct pt1 {
-	struct pci_dev *pdev;
-	void __iomem *regs;
-	struct i2c_adapter i2c_adap;
-	int i2c_running;
-	struct pt1_adapter *adaps[PT1_NR_ADAPS];
-	struct pt1_table *tables;
-	struct task_struct *kthread;
-	int table_index;
-	int buf_index;
-
-	struct mutex lock;
-	int power;
-	int reset;
-};
-
-struct pt1_adapter {
-	struct pt1 *pt1;
-	int index;
-
-	u8 *buf;
-	int upacket_count;
-	int packet_count;
-	int st_count;
-
-	struct dvb_adapter adap;
-	struct dvb_demux demux;
-	int users;
-	struct dmxdev dmxdev;
-	struct dvb_frontend *fe;
-	int (*orig_set_voltage)(struct dvb_frontend *fe,
-				fe_sec_voltage_t voltage);
-	int (*orig_sleep)(struct dvb_frontend *fe);
-	int (*orig_init)(struct dvb_frontend *fe);
-
-	fe_sec_voltage_t voltage;
-	int sleep;
-};
-
-#define pt1_printk(level, pt1, format, arg...)	\
-	dev_printk(level, &(pt1)->pdev->dev, format, ##arg)
-
-static void pt1_write_reg(struct pt1 *pt1, int reg, u32 data)
-{
-	writel(data, pt1->regs + reg * 4);
-}
-
-static u32 pt1_read_reg(struct pt1 *pt1, int reg)
-{
-	return readl(pt1->regs + reg * 4);
-}
-
-static int pt1_nr_tables = 8;
-module_param_named(nr_tables, pt1_nr_tables, int, 0);
-
-static void pt1_increment_table_count(struct pt1 *pt1)
-{
-	pt1_write_reg(pt1, 0, 0x00000020);
-}
-
-static void pt1_init_table_count(struct pt1 *pt1)
-{
-	pt1_write_reg(pt1, 0, 0x00000010);
-}
-
-static void pt1_register_tables(struct pt1 *pt1, u32 first_pfn)
-{
-	pt1_write_reg(pt1, 5, first_pfn);
-	pt1_write_reg(pt1, 0, 0x0c000040);
-}
-
-static void pt1_unregister_tables(struct pt1 *pt1)
-{
-	pt1_write_reg(pt1, 0, 0x08080000);
-}
-
-static int pt1_sync(struct pt1 *pt1)
-{
-	int i;
-	for (i = 0; i < 57; i++) {
-		if (pt1_read_reg(pt1, 0) & 0x20000000)
-			return 0;
-		pt1_write_reg(pt1, 0, 0x00000008);
-	}
-	pt1_printk(KERN_ERR, pt1, "could not sync\n");
-	return -EIO;
-}
-
-static u64 pt1_identify(struct pt1 *pt1)
-{
-	int i;
-	u64 id;
-	id = 0;
-	for (i = 0; i < 57; i++) {
-		id |= (u64)(pt1_read_reg(pt1, 0) >> 30 & 1) << i;
-		pt1_write_reg(pt1, 0, 0x00000008);
-	}
-	return id;
-}
-
-static int pt1_unlock(struct pt1 *pt1)
-{
-	int i;
-	pt1_write_reg(pt1, 0, 0x00000008);
-	for (i = 0; i < 3; i++) {
-		if (pt1_read_reg(pt1, 0) & 0x80000000)
-			return 0;
-		schedule_timeout_uninterruptible((HZ + 999) / 1000);
-	}
-	pt1_printk(KERN_ERR, pt1, "could not unlock\n");
-	return -EIO;
-}
-
-static int pt1_reset_pci(struct pt1 *pt1)
-{
-	int i;
-	pt1_write_reg(pt1, 0, 0x01010000);
-	pt1_write_reg(pt1, 0, 0x01000000);
-	for (i = 0; i < 10; i++) {
-		if (pt1_read_reg(pt1, 0) & 0x00000001)
-			return 0;
-		schedule_timeout_uninterruptible((HZ + 999) / 1000);
-	}
-	pt1_printk(KERN_ERR, pt1, "could not reset PCI\n");
-	return -EIO;
-}
-
-static int pt1_reset_ram(struct pt1 *pt1)
-{
-	int i;
-	pt1_write_reg(pt1, 0, 0x02020000);
-	pt1_write_reg(pt1, 0, 0x02000000);
-	for (i = 0; i < 10; i++) {
-		if (pt1_read_reg(pt1, 0) & 0x00000002)
-			return 0;
-		schedule_timeout_uninterruptible((HZ + 999) / 1000);
-	}
-	pt1_printk(KERN_ERR, pt1, "could not reset RAM\n");
-	return -EIO;
-}
-
-static int pt1_do_enable_ram(struct pt1 *pt1)
-{
-	int i, j;
-	u32 status;
-	status = pt1_read_reg(pt1, 0) & 0x00000004;
-	pt1_write_reg(pt1, 0, 0x00000002);
-	for (i = 0; i < 10; i++) {
-		for (j = 0; j < 1024; j++) {
-			if ((pt1_read_reg(pt1, 0) & 0x00000004) != status)
-				return 0;
-		}
-		schedule_timeout_uninterruptible((HZ + 999) / 1000);
-	}
-	pt1_printk(KERN_ERR, pt1, "could not enable RAM\n");
-	return -EIO;
-}
-
-static int pt1_enable_ram(struct pt1 *pt1)
-{
-	int i, ret;
-	int phase;
-	schedule_timeout_uninterruptible((HZ + 999) / 1000);
-	phase = pt1->pdev->device == 0x211a ? 128 : 166;
-	for (i = 0; i < phase; i++) {
-		ret = pt1_do_enable_ram(pt1);
-		if (ret < 0)
-			return ret;
-	}
-	return 0;
-}
-
-static void pt1_disable_ram(struct pt1 *pt1)
-{
-	pt1_write_reg(pt1, 0, 0x0b0b0000);
-}
-
-static void pt1_set_stream(struct pt1 *pt1, int index, int enabled)
-{
-	pt1_write_reg(pt1, 2, 1 << (index + 8) | enabled << index);
-}
-
-static void pt1_init_streams(struct pt1 *pt1)
-{
-	int i;
-	for (i = 0; i < PT1_NR_ADAPS; i++)
-		pt1_set_stream(pt1, i, 0);
-}
-
-static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page)
-{
-	u32 upacket;
-	int i;
-	int index;
-	struct pt1_adapter *adap;
-	int offset;
-	u8 *buf;
-	int sc;
-
-	if (!page->upackets[PT1_NR_UPACKETS - 1])
-		return 0;
-
-	for (i = 0; i < PT1_NR_UPACKETS; i++) {
-		upacket = le32_to_cpu(page->upackets[i]);
-		index = (upacket >> 29) - 1;
-		if (index < 0 || index >=  PT1_NR_ADAPS)
-			continue;
-
-		adap = pt1->adaps[index];
-		if (upacket >> 25 & 1)
-			adap->upacket_count = 0;
-		else if (!adap->upacket_count)
-			continue;
-
-		if (upacket >> 24 & 1)
-			printk_ratelimited(KERN_INFO "earth-pt1: device "
-				"buffer overflowing. table[%d] buf[%d]\n",
-				pt1->table_index, pt1->buf_index);
-		sc = upacket >> 26 & 0x7;
-		if (adap->st_count != -1 && sc != ((adap->st_count + 1) & 0x7))
-			printk_ratelimited(KERN_INFO "earth-pt1: data loss"
-				" in streamID(adapter)[%d]\n", index);
-		adap->st_count = sc;
-
-		buf = adap->buf;
-		offset = adap->packet_count * 188 + adap->upacket_count * 3;
-		buf[offset] = upacket >> 16;
-		buf[offset + 1] = upacket >> 8;
-		if (adap->upacket_count != 62)
-			buf[offset + 2] = upacket;
-
-		if (++adap->upacket_count >= 63) {
-			adap->upacket_count = 0;
-			if (++adap->packet_count >= 21) {
-				dvb_dmx_swfilter_packets(&adap->demux, buf, 21);
-				adap->packet_count = 0;
-			}
-		}
-	}
-
-	page->upackets[PT1_NR_UPACKETS - 1] = 0;
-	return 1;
-}
-
-static int pt1_thread(void *data)
-{
-	struct pt1 *pt1;
-	struct pt1_buffer_page *page;
-
-	pt1 = data;
-	set_freezable();
-
-	while (!kthread_should_stop()) {
-		try_to_freeze();
-
-		page = pt1->tables[pt1->table_index].bufs[pt1->buf_index].page;
-		if (!pt1_filter(pt1, page)) {
-			schedule_timeout_interruptible((HZ + 999) / 1000);
-			continue;
-		}
-
-		if (++pt1->buf_index >= PT1_NR_BUFS) {
-			pt1_increment_table_count(pt1);
-			pt1->buf_index = 0;
-			if (++pt1->table_index >= pt1_nr_tables)
-				pt1->table_index = 0;
-		}
-	}
-
-	return 0;
-}
-
-static void pt1_free_page(struct pt1 *pt1, void *page, dma_addr_t addr)
-{
-	dma_free_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, page, addr);
-}
-
-static void *pt1_alloc_page(struct pt1 *pt1, dma_addr_t *addrp, u32 *pfnp)
-{
-	void *page;
-	dma_addr_t addr;
-
-	page = dma_alloc_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, &addr,
-				  GFP_KERNEL);
-	if (page == NULL)
-		return NULL;
-
-	BUG_ON(addr & (PT1_PAGE_SIZE - 1));
-	BUG_ON(addr >> PT1_PAGE_SHIFT >> 31 >> 1);
-
-	*addrp = addr;
-	*pfnp = addr >> PT1_PAGE_SHIFT;
-	return page;
-}
-
-static void pt1_cleanup_buffer(struct pt1 *pt1, struct pt1_buffer *buf)
-{
-	pt1_free_page(pt1, buf->page, buf->addr);
-}
-
-static int
-pt1_init_buffer(struct pt1 *pt1, struct pt1_buffer *buf,  u32 *pfnp)
-{
-	struct pt1_buffer_page *page;
-	dma_addr_t addr;
-
-	page = pt1_alloc_page(pt1, &addr, pfnp);
-	if (page == NULL)
-		return -ENOMEM;
-
-	page->upackets[PT1_NR_UPACKETS - 1] = 0;
-
-	buf->page = page;
-	buf->addr = addr;
-	return 0;
-}
-
-static void pt1_cleanup_table(struct pt1 *pt1, struct pt1_table *table)
-{
-	int i;
-
-	for (i = 0; i < PT1_NR_BUFS; i++)
-		pt1_cleanup_buffer(pt1, &table->bufs[i]);
-
-	pt1_free_page(pt1, table->page, table->addr);
-}
-
-static int
-pt1_init_table(struct pt1 *pt1, struct pt1_table *table, u32 *pfnp)
-{
-	struct pt1_table_page *page;
-	dma_addr_t addr;
-	int i, ret;
-	u32 buf_pfn;
-
-	page = pt1_alloc_page(pt1, &addr, pfnp);
-	if (page == NULL)
-		return -ENOMEM;
-
-	for (i = 0; i < PT1_NR_BUFS; i++) {
-		ret = pt1_init_buffer(pt1, &table->bufs[i], &buf_pfn);
-		if (ret < 0)
-			goto err;
-
-		page->buf_pfns[i] = cpu_to_le32(buf_pfn);
-	}
-
-	pt1_increment_table_count(pt1);
-	table->page = page;
-	table->addr = addr;
-	return 0;
-
-err:
-	while (i--)
-		pt1_cleanup_buffer(pt1, &table->bufs[i]);
-
-	pt1_free_page(pt1, page, addr);
-	return ret;
-}
-
-static void pt1_cleanup_tables(struct pt1 *pt1)
-{
-	struct pt1_table *tables;
-	int i;
-
-	tables = pt1->tables;
-	pt1_unregister_tables(pt1);
-
-	for (i = 0; i < pt1_nr_tables; i++)
-		pt1_cleanup_table(pt1, &tables[i]);
-
-	vfree(tables);
-}
-
-static int pt1_init_tables(struct pt1 *pt1)
-{
-	struct pt1_table *tables;
-	int i, ret;
-	u32 first_pfn, pfn;
-
-	tables = vmalloc(sizeof(struct pt1_table) * pt1_nr_tables);
-	if (tables == NULL)
-		return -ENOMEM;
-
-	pt1_init_table_count(pt1);
-
-	i = 0;
-	if (pt1_nr_tables) {
-		ret = pt1_init_table(pt1, &tables[0], &first_pfn);
-		if (ret)
-			goto err;
-		i++;
-	}
-
-	while (i < pt1_nr_tables) {
-		ret = pt1_init_table(pt1, &tables[i], &pfn);
-		if (ret)
-			goto err;
-		tables[i - 1].page->next_pfn = cpu_to_le32(pfn);
-		i++;
-	}
-
-	tables[pt1_nr_tables - 1].page->next_pfn = cpu_to_le32(first_pfn);
-
-	pt1_register_tables(pt1, first_pfn);
-	pt1->tables = tables;
-	return 0;
-
-err:
-	while (i--)
-		pt1_cleanup_table(pt1, &tables[i]);
-
-	vfree(tables);
-	return ret;
-}
-
-static int pt1_start_polling(struct pt1 *pt1)
-{
-	int ret = 0;
-
-	mutex_lock(&pt1->lock);
-	if (!pt1->kthread) {
-		pt1->kthread = kthread_run(pt1_thread, pt1, "earth-pt1");
-		if (IS_ERR(pt1->kthread)) {
-			ret = PTR_ERR(pt1->kthread);
-			pt1->kthread = NULL;
-		}
-	}
-	mutex_unlock(&pt1->lock);
-	return ret;
-}
-
-static int pt1_start_feed(struct dvb_demux_feed *feed)
-{
-	struct pt1_adapter *adap;
-	adap = container_of(feed->demux, struct pt1_adapter, demux);
-	if (!adap->users++) {
-		int ret;
-
-		ret = pt1_start_polling(adap->pt1);
-		if (ret)
-			return ret;
-		pt1_set_stream(adap->pt1, adap->index, 1);
-	}
-	return 0;
-}
-
-static void pt1_stop_polling(struct pt1 *pt1)
-{
-	int i, count;
-
-	mutex_lock(&pt1->lock);
-	for (i = 0, count = 0; i < PT1_NR_ADAPS; i++)
-		count += pt1->adaps[i]->users;
-
-	if (count == 0 && pt1->kthread) {
-		kthread_stop(pt1->kthread);
-		pt1->kthread = NULL;
-	}
-	mutex_unlock(&pt1->lock);
-}
-
-static int pt1_stop_feed(struct dvb_demux_feed *feed)
-{
-	struct pt1_adapter *adap;
-	adap = container_of(feed->demux, struct pt1_adapter, demux);
-	if (!--adap->users) {
-		pt1_set_stream(adap->pt1, adap->index, 0);
-		pt1_stop_polling(adap->pt1);
-	}
-	return 0;
-}
-
-static void
-pt1_update_power(struct pt1 *pt1)
-{
-	int bits;
-	int i;
-	struct pt1_adapter *adap;
-	static const int sleep_bits[] = {
-		1 << 4,
-		1 << 6 | 1 << 7,
-		1 << 5,
-		1 << 6 | 1 << 8,
-	};
-
-	bits = pt1->power | !pt1->reset << 3;
-	mutex_lock(&pt1->lock);
-	for (i = 0; i < PT1_NR_ADAPS; i++) {
-		adap = pt1->adaps[i];
-		switch (adap->voltage) {
-		case SEC_VOLTAGE_13: /* actually 11V */
-			bits |= 1 << 1;
-			break;
-		case SEC_VOLTAGE_18: /* actually 15V */
-			bits |= 1 << 1 | 1 << 2;
-			break;
-		default:
-			break;
-		}
-
-		/* XXX: The bits should be changed depending on adap->sleep. */
-		bits |= sleep_bits[i];
-	}
-	pt1_write_reg(pt1, 1, bits);
-	mutex_unlock(&pt1->lock);
-}
-
-static int pt1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
-	struct pt1_adapter *adap;
-
-	adap = container_of(fe->dvb, struct pt1_adapter, adap);
-	adap->voltage = voltage;
-	pt1_update_power(adap->pt1);
-
-	if (adap->orig_set_voltage)
-		return adap->orig_set_voltage(fe, voltage);
-	else
-		return 0;
-}
-
-static int pt1_sleep(struct dvb_frontend *fe)
-{
-	struct pt1_adapter *adap;
-
-	adap = container_of(fe->dvb, struct pt1_adapter, adap);
-	adap->sleep = 1;
-	pt1_update_power(adap->pt1);
-
-	if (adap->orig_sleep)
-		return adap->orig_sleep(fe);
-	else
-		return 0;
-}
-
-static int pt1_wakeup(struct dvb_frontend *fe)
-{
-	struct pt1_adapter *adap;
-
-	adap = container_of(fe->dvb, struct pt1_adapter, adap);
-	adap->sleep = 0;
-	pt1_update_power(adap->pt1);
-	schedule_timeout_uninterruptible((HZ + 999) / 1000);
-
-	if (adap->orig_init)
-		return adap->orig_init(fe);
-	else
-		return 0;
-}
-
-static void pt1_free_adapter(struct pt1_adapter *adap)
-{
-	adap->demux.dmx.close(&adap->demux.dmx);
-	dvb_dmxdev_release(&adap->dmxdev);
-	dvb_dmx_release(&adap->demux);
-	dvb_unregister_adapter(&adap->adap);
-	free_page((unsigned long)adap->buf);
-	kfree(adap);
-}
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static struct pt1_adapter *
-pt1_alloc_adapter(struct pt1 *pt1)
-{
-	struct pt1_adapter *adap;
-	void *buf;
-	struct dvb_adapter *dvb_adap;
-	struct dvb_demux *demux;
-	struct dmxdev *dmxdev;
-	int ret;
-
-	adap = kzalloc(sizeof(struct pt1_adapter), GFP_KERNEL);
-	if (!adap) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	adap->pt1 = pt1;
-
-	adap->voltage = SEC_VOLTAGE_OFF;
-	adap->sleep = 1;
-
-	buf = (u8 *)__get_free_page(GFP_KERNEL);
-	if (!buf) {
-		ret = -ENOMEM;
-		goto err_kfree;
-	}
-
-	adap->buf = buf;
-	adap->upacket_count = 0;
-	adap->packet_count = 0;
-	adap->st_count = -1;
-
-	dvb_adap = &adap->adap;
-	dvb_adap->priv = adap;
-	ret = dvb_register_adapter(dvb_adap, DRIVER_NAME, THIS_MODULE,
-				   &pt1->pdev->dev, adapter_nr);
-	if (ret < 0)
-		goto err_free_page;
-
-	demux = &adap->demux;
-	demux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
-	demux->priv = adap;
-	demux->feednum = 256;
-	demux->filternum = 256;
-	demux->start_feed = pt1_start_feed;
-	demux->stop_feed = pt1_stop_feed;
-	demux->write_to_decoder = NULL;
-	ret = dvb_dmx_init(demux);
-	if (ret < 0)
-		goto err_unregister_adapter;
-
-	dmxdev = &adap->dmxdev;
-	dmxdev->filternum = 256;
-	dmxdev->demux = &demux->dmx;
-	dmxdev->capabilities = 0;
-	ret = dvb_dmxdev_init(dmxdev, dvb_adap);
-	if (ret < 0)
-		goto err_dmx_release;
-
-	return adap;
-
-err_dmx_release:
-	dvb_dmx_release(demux);
-err_unregister_adapter:
-	dvb_unregister_adapter(dvb_adap);
-err_free_page:
-	free_page((unsigned long)buf);
-err_kfree:
-	kfree(adap);
-err:
-	return ERR_PTR(ret);
-}
-
-static void pt1_cleanup_adapters(struct pt1 *pt1)
-{
-	int i;
-	for (i = 0; i < PT1_NR_ADAPS; i++)
-		pt1_free_adapter(pt1->adaps[i]);
-}
-
-static int pt1_init_adapters(struct pt1 *pt1)
-{
-	int i;
-	struct pt1_adapter *adap;
-	int ret;
-
-	for (i = 0; i < PT1_NR_ADAPS; i++) {
-		adap = pt1_alloc_adapter(pt1);
-		if (IS_ERR(adap)) {
-			ret = PTR_ERR(adap);
-			goto err;
-		}
-
-		adap->index = i;
-		pt1->adaps[i] = adap;
-	}
-	return 0;
-
-err:
-	while (i--)
-		pt1_free_adapter(pt1->adaps[i]);
-
-	return ret;
-}
-
-static void pt1_cleanup_frontend(struct pt1_adapter *adap)
-{
-	dvb_unregister_frontend(adap->fe);
-}
-
-static int pt1_init_frontend(struct pt1_adapter *adap, struct dvb_frontend *fe)
-{
-	int ret;
-
-	adap->orig_set_voltage = fe->ops.set_voltage;
-	adap->orig_sleep = fe->ops.sleep;
-	adap->orig_init = fe->ops.init;
-	fe->ops.set_voltage = pt1_set_voltage;
-	fe->ops.sleep = pt1_sleep;
-	fe->ops.init = pt1_wakeup;
-
-	ret = dvb_register_frontend(&adap->adap, fe);
-	if (ret < 0)
-		return ret;
-
-	adap->fe = fe;
-	return 0;
-}
-
-static void pt1_cleanup_frontends(struct pt1 *pt1)
-{
-	int i;
-	for (i = 0; i < PT1_NR_ADAPS; i++)
-		pt1_cleanup_frontend(pt1->adaps[i]);
-}
-
-struct pt1_config {
-	struct va1j5jf8007s_config va1j5jf8007s_config;
-	struct va1j5jf8007t_config va1j5jf8007t_config;
-};
-
-static const struct pt1_config pt1_configs[2] = {
-	{
-		{
-			.demod_address = 0x1b,
-			.frequency = VA1J5JF8007S_20MHZ,
-		},
-		{
-			.demod_address = 0x1a,
-			.frequency = VA1J5JF8007T_20MHZ,
-		},
-	}, {
-		{
-			.demod_address = 0x19,
-			.frequency = VA1J5JF8007S_20MHZ,
-		},
-		{
-			.demod_address = 0x18,
-			.frequency = VA1J5JF8007T_20MHZ,
-		},
-	},
-};
-
-static const struct pt1_config pt2_configs[2] = {
-	{
-		{
-			.demod_address = 0x1b,
-			.frequency = VA1J5JF8007S_25MHZ,
-		},
-		{
-			.demod_address = 0x1a,
-			.frequency = VA1J5JF8007T_25MHZ,
-		},
-	}, {
-		{
-			.demod_address = 0x19,
-			.frequency = VA1J5JF8007S_25MHZ,
-		},
-		{
-			.demod_address = 0x18,
-			.frequency = VA1J5JF8007T_25MHZ,
-		},
-	},
-};
-
-static int pt1_init_frontends(struct pt1 *pt1)
-{
-	int i, j;
-	struct i2c_adapter *i2c_adap;
-	const struct pt1_config *configs, *config;
-	struct dvb_frontend *fe[4];
-	int ret;
-
-	i = 0;
-	j = 0;
-
-	i2c_adap = &pt1->i2c_adap;
-	configs = pt1->pdev->device == 0x211a ? pt1_configs : pt2_configs;
-	do {
-		config = &configs[i / 2];
-
-		fe[i] = va1j5jf8007s_attach(&config->va1j5jf8007s_config,
-					    i2c_adap);
-		if (!fe[i]) {
-			ret = -ENODEV; /* This does not sound nice... */
-			goto err;
-		}
-		i++;
-
-		fe[i] = va1j5jf8007t_attach(&config->va1j5jf8007t_config,
-					    i2c_adap);
-		if (!fe[i]) {
-			ret = -ENODEV;
-			goto err;
-		}
-		i++;
-
-		ret = va1j5jf8007s_prepare(fe[i - 2]);
-		if (ret < 0)
-			goto err;
-
-		ret = va1j5jf8007t_prepare(fe[i - 1]);
-		if (ret < 0)
-			goto err;
-
-	} while (i < 4);
-
-	do {
-		ret = pt1_init_frontend(pt1->adaps[j], fe[j]);
-		if (ret < 0)
-			goto err;
-	} while (++j < 4);
-
-	return 0;
-
-err:
-	while (i-- > j)
-		fe[i]->ops.release(fe[i]);
-
-	while (j--)
-		dvb_unregister_frontend(fe[j]);
-
-	return ret;
-}
-
-static void pt1_i2c_emit(struct pt1 *pt1, int addr, int busy, int read_enable,
-			 int clock, int data, int next_addr)
-{
-	pt1_write_reg(pt1, 4, addr << 18 | busy << 13 | read_enable << 12 |
-		      !clock << 11 | !data << 10 | next_addr);
-}
-
-static void pt1_i2c_write_bit(struct pt1 *pt1, int addr, int *addrp, int data)
-{
-	pt1_i2c_emit(pt1, addr,     1, 0, 0, data, addr + 1);
-	pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, data, addr + 2);
-	pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, data, addr + 3);
-	*addrp = addr + 3;
-}
-
-static void pt1_i2c_read_bit(struct pt1 *pt1, int addr, int *addrp)
-{
-	pt1_i2c_emit(pt1, addr,     1, 0, 0, 1, addr + 1);
-	pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 1, addr + 2);
-	pt1_i2c_emit(pt1, addr + 2, 1, 1, 1, 1, addr + 3);
-	pt1_i2c_emit(pt1, addr + 3, 1, 0, 0, 1, addr + 4);
-	*addrp = addr + 4;
-}
-
-static void pt1_i2c_write_byte(struct pt1 *pt1, int addr, int *addrp, int data)
-{
-	int i;
-	for (i = 0; i < 8; i++)
-		pt1_i2c_write_bit(pt1, addr, &addr, data >> (7 - i) & 1);
-	pt1_i2c_write_bit(pt1, addr, &addr, 1);
-	*addrp = addr;
-}
-
-static void pt1_i2c_read_byte(struct pt1 *pt1, int addr, int *addrp, int last)
-{
-	int i;
-	for (i = 0; i < 8; i++)
-		pt1_i2c_read_bit(pt1, addr, &addr);
-	pt1_i2c_write_bit(pt1, addr, &addr, last);
-	*addrp = addr;
-}
-
-static void pt1_i2c_prepare(struct pt1 *pt1, int addr, int *addrp)
-{
-	pt1_i2c_emit(pt1, addr,     1, 0, 1, 1, addr + 1);
-	pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2);
-	pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, 0, addr + 3);
-	*addrp = addr + 3;
-}
-
-static void
-pt1_i2c_write_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg)
-{
-	int i;
-	pt1_i2c_prepare(pt1, addr, &addr);
-	pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1);
-	for (i = 0; i < msg->len; i++)
-		pt1_i2c_write_byte(pt1, addr, &addr, msg->buf[i]);
-	*addrp = addr;
-}
-
-static void
-pt1_i2c_read_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg)
-{
-	int i;
-	pt1_i2c_prepare(pt1, addr, &addr);
-	pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1 | 1);
-	for (i = 0; i < msg->len; i++)
-		pt1_i2c_read_byte(pt1, addr, &addr, i == msg->len - 1);
-	*addrp = addr;
-}
-
-static int pt1_i2c_end(struct pt1 *pt1, int addr)
-{
-	pt1_i2c_emit(pt1, addr,     1, 0, 0, 0, addr + 1);
-	pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2);
-	pt1_i2c_emit(pt1, addr + 2, 1, 0, 1, 1, 0);
-
-	pt1_write_reg(pt1, 0, 0x00000004);
-	do {
-		if (signal_pending(current))
-			return -EINTR;
-		schedule_timeout_interruptible((HZ + 999) / 1000);
-	} while (pt1_read_reg(pt1, 0) & 0x00000080);
-	return 0;
-}
-
-static void pt1_i2c_begin(struct pt1 *pt1, int *addrp)
-{
-	int addr;
-	addr = 0;
-
-	pt1_i2c_emit(pt1, addr,     0, 0, 1, 1, addr /* itself */);
-	addr = addr + 1;
-
-	if (!pt1->i2c_running) {
-		pt1_i2c_emit(pt1, addr,     1, 0, 1, 1, addr + 1);
-		pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2);
-		addr = addr + 2;
-		pt1->i2c_running = 1;
-	}
-	*addrp = addr;
-}
-
-static int pt1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
-{
-	struct pt1 *pt1;
-	int i;
-	struct i2c_msg *msg, *next_msg;
-	int addr, ret;
-	u16 len;
-	u32 word;
-
-	pt1 = i2c_get_adapdata(adap);
-
-	for (i = 0; i < num; i++) {
-		msg = &msgs[i];
-		if (msg->flags & I2C_M_RD)
-			return -ENOTSUPP;
-
-		if (i + 1 < num)
-			next_msg = &msgs[i + 1];
-		else
-			next_msg = NULL;
-
-		if (next_msg && next_msg->flags & I2C_M_RD) {
-			i++;
-
-			len = next_msg->len;
-			if (len > 4)
-				return -ENOTSUPP;
-
-			pt1_i2c_begin(pt1, &addr);
-			pt1_i2c_write_msg(pt1, addr, &addr, msg);
-			pt1_i2c_read_msg(pt1, addr, &addr, next_msg);
-			ret = pt1_i2c_end(pt1, addr);
-			if (ret < 0)
-				return ret;
-
-			word = pt1_read_reg(pt1, 2);
-			while (len--) {
-				next_msg->buf[len] = word;
-				word >>= 8;
-			}
-		} else {
-			pt1_i2c_begin(pt1, &addr);
-			pt1_i2c_write_msg(pt1, addr, &addr, msg);
-			ret = pt1_i2c_end(pt1, addr);
-			if (ret < 0)
-				return ret;
-		}
-	}
-
-	return num;
-}
-
-static u32 pt1_i2c_func(struct i2c_adapter *adap)
-{
-	return I2C_FUNC_I2C;
-}
-
-static const struct i2c_algorithm pt1_i2c_algo = {
-	.master_xfer = pt1_i2c_xfer,
-	.functionality = pt1_i2c_func,
-};
-
-static void pt1_i2c_wait(struct pt1 *pt1)
-{
-	int i;
-	for (i = 0; i < 128; i++)
-		pt1_i2c_emit(pt1, 0, 0, 0, 1, 1, 0);
-}
-
-static void pt1_i2c_init(struct pt1 *pt1)
-{
-	int i;
-	for (i = 0; i < 1024; i++)
-		pt1_i2c_emit(pt1, i, 0, 0, 1, 1, 0);
-}
-
-static void __devexit pt1_remove(struct pci_dev *pdev)
-{
-	struct pt1 *pt1;
-	void __iomem *regs;
-
-	pt1 = pci_get_drvdata(pdev);
-	regs = pt1->regs;
-
-	if (pt1->kthread)
-		kthread_stop(pt1->kthread);
-	pt1_cleanup_tables(pt1);
-	pt1_cleanup_frontends(pt1);
-	pt1_disable_ram(pt1);
-	pt1->power = 0;
-	pt1->reset = 1;
-	pt1_update_power(pt1);
-	pt1_cleanup_adapters(pt1);
-	i2c_del_adapter(&pt1->i2c_adap);
-	pci_set_drvdata(pdev, NULL);
-	kfree(pt1);
-	pci_iounmap(pdev, regs);
-	pci_release_regions(pdev);
-	pci_disable_device(pdev);
-}
-
-static int __devinit
-pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-	int ret;
-	void __iomem *regs;
-	struct pt1 *pt1;
-	struct i2c_adapter *i2c_adap;
-
-	ret = pci_enable_device(pdev);
-	if (ret < 0)
-		goto err;
-
-	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-	if (ret < 0)
-		goto err_pci_disable_device;
-
-	pci_set_master(pdev);
-
-	ret = pci_request_regions(pdev, DRIVER_NAME);
-	if (ret < 0)
-		goto err_pci_disable_device;
-
-	regs = pci_iomap(pdev, 0, 0);
-	if (!regs) {
-		ret = -EIO;
-		goto err_pci_release_regions;
-	}
-
-	pt1 = kzalloc(sizeof(struct pt1), GFP_KERNEL);
-	if (!pt1) {
-		ret = -ENOMEM;
-		goto err_pci_iounmap;
-	}
-
-	mutex_init(&pt1->lock);
-	pt1->pdev = pdev;
-	pt1->regs = regs;
-	pci_set_drvdata(pdev, pt1);
-
-	ret = pt1_init_adapters(pt1);
-	if (ret < 0)
-		goto err_kfree;
-
-	mutex_init(&pt1->lock);
-
-	pt1->power = 0;
-	pt1->reset = 1;
-	pt1_update_power(pt1);
-
-	i2c_adap = &pt1->i2c_adap;
-	i2c_adap->algo = &pt1_i2c_algo;
-	i2c_adap->algo_data = NULL;
-	i2c_adap->dev.parent = &pdev->dev;
-	strcpy(i2c_adap->name, DRIVER_NAME);
-	i2c_set_adapdata(i2c_adap, pt1);
-	ret = i2c_add_adapter(i2c_adap);
-	if (ret < 0)
-		goto err_pt1_cleanup_adapters;
-
-	pt1_i2c_init(pt1);
-	pt1_i2c_wait(pt1);
-
-	ret = pt1_sync(pt1);
-	if (ret < 0)
-		goto err_i2c_del_adapter;
-
-	pt1_identify(pt1);
-
-	ret = pt1_unlock(pt1);
-	if (ret < 0)
-		goto err_i2c_del_adapter;
-
-	ret = pt1_reset_pci(pt1);
-	if (ret < 0)
-		goto err_i2c_del_adapter;
-
-	ret = pt1_reset_ram(pt1);
-	if (ret < 0)
-		goto err_i2c_del_adapter;
-
-	ret = pt1_enable_ram(pt1);
-	if (ret < 0)
-		goto err_i2c_del_adapter;
-
-	pt1_init_streams(pt1);
-
-	pt1->power = 1;
-	pt1_update_power(pt1);
-	schedule_timeout_uninterruptible((HZ + 49) / 50);
-
-	pt1->reset = 0;
-	pt1_update_power(pt1);
-	schedule_timeout_uninterruptible((HZ + 999) / 1000);
-
-	ret = pt1_init_frontends(pt1);
-	if (ret < 0)
-		goto err_pt1_disable_ram;
-
-	ret = pt1_init_tables(pt1);
-	if (ret < 0)
-		goto err_pt1_cleanup_frontends;
-
-	return 0;
-
-err_pt1_cleanup_frontends:
-	pt1_cleanup_frontends(pt1);
-err_pt1_disable_ram:
-	pt1_disable_ram(pt1);
-	pt1->power = 0;
-	pt1->reset = 1;
-	pt1_update_power(pt1);
-err_i2c_del_adapter:
-	i2c_del_adapter(i2c_adap);
-err_pt1_cleanup_adapters:
-	pt1_cleanup_adapters(pt1);
-err_kfree:
-	pci_set_drvdata(pdev, NULL);
-	kfree(pt1);
-err_pci_iounmap:
-	pci_iounmap(pdev, regs);
-err_pci_release_regions:
-	pci_release_regions(pdev);
-err_pci_disable_device:
-	pci_disable_device(pdev);
-err:
-	return ret;
-
-}
-
-static struct pci_device_id pt1_id_table[] = {
-	{ PCI_DEVICE(0x10ee, 0x211a) },
-	{ PCI_DEVICE(0x10ee, 0x222a) },
-	{ },
-};
-MODULE_DEVICE_TABLE(pci, pt1_id_table);
-
-static struct pci_driver pt1_driver = {
-	.name		= DRIVER_NAME,
-	.probe		= pt1_probe,
-	.remove		= __devexit_p(pt1_remove),
-	.id_table	= pt1_id_table,
-};
-
-
-static int __init pt1_init(void)
-{
-	return pci_register_driver(&pt1_driver);
-}
-
-
-static void __exit pt1_cleanup(void)
-{
-	pci_unregister_driver(&pt1_driver);
-}
-
-module_init(pt1_init);
-module_exit(pt1_cleanup);
-
-MODULE_AUTHOR("Takahito HIRANO <hiranotaka@zng.info>");
-MODULE_DESCRIPTION("Earthsoft PT1/PT2 Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/pt1/va1j5jf8007s.c b/drivers/media/dvb/pt1/va1j5jf8007s.c
deleted file mode 100644
index d980dfb..0000000
--- a/drivers/media/dvb/pt1/va1j5jf8007s.c
+++ /dev/null
@@ -1,735 +0,0 @@
-/*
- * ISDB-S driver for VA1J5JF8007/VA1J5JF8011
- *
- * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
- *
- * based on pt1dvr - http://pt1dvr.sourceforge.jp/
- * 	by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-#include "va1j5jf8007s.h"
-
-enum va1j5jf8007s_tune_state {
-	VA1J5JF8007S_IDLE,
-	VA1J5JF8007S_SET_FREQUENCY_1,
-	VA1J5JF8007S_SET_FREQUENCY_2,
-	VA1J5JF8007S_SET_FREQUENCY_3,
-	VA1J5JF8007S_CHECK_FREQUENCY,
-	VA1J5JF8007S_SET_MODULATION,
-	VA1J5JF8007S_CHECK_MODULATION,
-	VA1J5JF8007S_SET_TS_ID,
-	VA1J5JF8007S_CHECK_TS_ID,
-	VA1J5JF8007S_TRACK,
-};
-
-struct va1j5jf8007s_state {
-	const struct va1j5jf8007s_config *config;
-	struct i2c_adapter *adap;
-	struct dvb_frontend fe;
-	enum va1j5jf8007s_tune_state tune_state;
-};
-
-static int va1j5jf8007s_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct va1j5jf8007s_state *state;
-	u8 addr;
-	int i;
-	u8 write_buf[1], read_buf[1];
-	struct i2c_msg msgs[2];
-	s32 word, x1, x2, x3, x4, x5, y;
-
-	state = fe->demodulator_priv;
-	addr = state->config->demod_address;
-
-	word = 0;
-	for (i = 0; i < 2; i++) {
-		write_buf[0] = 0xbc + i;
-
-		msgs[0].addr = addr;
-		msgs[0].flags = 0;
-		msgs[0].len = sizeof(write_buf);
-		msgs[0].buf = write_buf;
-
-		msgs[1].addr = addr;
-		msgs[1].flags = I2C_M_RD;
-		msgs[1].len = sizeof(read_buf);
-		msgs[1].buf = read_buf;
-
-		if (i2c_transfer(state->adap, msgs, 2) != 2)
-			return -EREMOTEIO;
-
-		word <<= 8;
-		word |= read_buf[0];
-	}
-
-	word -= 3000;
-	if (word < 0)
-		word = 0;
-
-	x1 = int_sqrt(word << 16) * ((15625ll << 21) / 1000000);
-	x2 = (s64)x1 * x1 >> 31;
-	x3 = (s64)x2 * x1 >> 31;
-	x4 = (s64)x2 * x2 >> 31;
-	x5 = (s64)x4 * x1 >> 31;
-
-	y = (58857ll << 23) / 1000;
-	y -= (s64)x1 * ((89565ll << 24) / 1000) >> 30;
-	y += (s64)x2 * ((88977ll << 24) / 1000) >> 28;
-	y -= (s64)x3 * ((50259ll << 25) / 1000) >> 27;
-	y += (s64)x4 * ((14341ll << 27) / 1000) >> 27;
-	y -= (s64)x5 * ((16346ll << 30) / 10000) >> 28;
-
-	*snr = y < 0 ? 0 : y >> 15;
-	return 0;
-}
-
-static int va1j5jf8007s_get_frontend_algo(struct dvb_frontend *fe)
-{
-	return DVBFE_ALGO_HW;
-}
-
-static int
-va1j5jf8007s_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct va1j5jf8007s_state *state;
-
-	state = fe->demodulator_priv;
-
-	switch (state->tune_state) {
-	case VA1J5JF8007S_IDLE:
-	case VA1J5JF8007S_SET_FREQUENCY_1:
-	case VA1J5JF8007S_SET_FREQUENCY_2:
-	case VA1J5JF8007S_SET_FREQUENCY_3:
-	case VA1J5JF8007S_CHECK_FREQUENCY:
-		*status = 0;
-		return 0;
-
-
-	case VA1J5JF8007S_SET_MODULATION:
-	case VA1J5JF8007S_CHECK_MODULATION:
-		*status |= FE_HAS_SIGNAL;
-		return 0;
-
-	case VA1J5JF8007S_SET_TS_ID:
-	case VA1J5JF8007S_CHECK_TS_ID:
-		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
-		return 0;
-
-	case VA1J5JF8007S_TRACK:
-		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
-		return 0;
-	}
-
-	BUG();
-}
-
-struct va1j5jf8007s_cb_map {
-	u32 frequency;
-	u8 cb;
-};
-
-static const struct va1j5jf8007s_cb_map va1j5jf8007s_cb_maps[] = {
-	{  986000, 0xb2 },
-	{ 1072000, 0xd2 },
-	{ 1154000, 0xe2 },
-	{ 1291000, 0x20 },
-	{ 1447000, 0x40 },
-	{ 1615000, 0x60 },
-	{ 1791000, 0x80 },
-	{ 1972000, 0xa0 },
-};
-
-static u8 va1j5jf8007s_lookup_cb(u32 frequency)
-{
-	int i;
-	const struct va1j5jf8007s_cb_map *map;
-
-	for (i = 0; i < ARRAY_SIZE(va1j5jf8007s_cb_maps); i++) {
-		map = &va1j5jf8007s_cb_maps[i];
-		if (frequency < map->frequency)
-			return map->cb;
-	}
-	return 0xc0;
-}
-
-static int va1j5jf8007s_set_frequency_1(struct va1j5jf8007s_state *state)
-{
-	u32 frequency;
-	u16 word;
-	u8 buf[6];
-	struct i2c_msg msg;
-
-	frequency = state->fe.dtv_property_cache.frequency;
-
-	word = (frequency + 500) / 1000;
-	if (frequency < 1072000)
-		word = (word << 1 & ~0x1f) | (word & 0x0f);
-
-	buf[0] = 0xfe;
-	buf[1] = 0xc0;
-	buf[2] = 0x40 | word >> 8;
-	buf[3] = word;
-	buf[4] = 0xe0;
-	buf[5] = va1j5jf8007s_lookup_cb(frequency);
-
-	msg.addr = state->config->demod_address;
-	msg.flags = 0;
-	msg.len = sizeof(buf);
-	msg.buf = buf;
-
-	if (i2c_transfer(state->adap, &msg, 1) != 1)
-		return -EREMOTEIO;
-
-	return 0;
-}
-
-static int va1j5jf8007s_set_frequency_2(struct va1j5jf8007s_state *state)
-{
-	u8 buf[3];
-	struct i2c_msg msg;
-
-	buf[0] = 0xfe;
-	buf[1] = 0xc0;
-	buf[2] = 0xe4;
-
-	msg.addr = state->config->demod_address;
-	msg.flags = 0;
-	msg.len = sizeof(buf);
-	msg.buf = buf;
-
-	if (i2c_transfer(state->adap, &msg, 1) != 1)
-		return -EREMOTEIO;
-
-	return 0;
-}
-
-static int va1j5jf8007s_set_frequency_3(struct va1j5jf8007s_state *state)
-{
-	u32 frequency;
-	u8 buf[4];
-	struct i2c_msg msg;
-
-	frequency = state->fe.dtv_property_cache.frequency;
-
-	buf[0] = 0xfe;
-	buf[1] = 0xc0;
-	buf[2] = 0xf4;
-	buf[3] = va1j5jf8007s_lookup_cb(frequency) | 0x4;
-
-	msg.addr = state->config->demod_address;
-	msg.flags = 0;
-	msg.len = sizeof(buf);
-	msg.buf = buf;
-
-	if (i2c_transfer(state->adap, &msg, 1) != 1)
-		return -EREMOTEIO;
-
-	return 0;
-}
-
-static int
-va1j5jf8007s_check_frequency(struct va1j5jf8007s_state *state, int *lock)
-{
-	u8 addr;
-	u8 write_buf[2], read_buf[1];
-	struct i2c_msg msgs[2];
-
-	addr = state->config->demod_address;
-
-	write_buf[0] = 0xfe;
-	write_buf[1] = 0xc1;
-
-	msgs[0].addr = addr;
-	msgs[0].flags = 0;
-	msgs[0].len = sizeof(write_buf);
-	msgs[0].buf = write_buf;
-
-	msgs[1].addr = addr;
-	msgs[1].flags = I2C_M_RD;
-	msgs[1].len = sizeof(read_buf);
-	msgs[1].buf = read_buf;
-
-	if (i2c_transfer(state->adap, msgs, 2) != 2)
-		return -EREMOTEIO;
-
-	*lock = read_buf[0] & 0x40;
-	return 0;
-}
-
-static int va1j5jf8007s_set_modulation(struct va1j5jf8007s_state *state)
-{
-	u8 buf[2];
-	struct i2c_msg msg;
-
-	buf[0] = 0x03;
-	buf[1] = 0x01;
-
-	msg.addr = state->config->demod_address;
-	msg.flags = 0;
-	msg.len = sizeof(buf);
-	msg.buf = buf;
-
-	if (i2c_transfer(state->adap, &msg, 1) != 1)
-		return -EREMOTEIO;
-
-	return 0;
-}
-
-static int
-va1j5jf8007s_check_modulation(struct va1j5jf8007s_state *state, int *lock)
-{
-	u8 addr;
-	u8 write_buf[1], read_buf[1];
-	struct i2c_msg msgs[2];
-
-	addr = state->config->demod_address;
-
-	write_buf[0] = 0xc3;
-
-	msgs[0].addr = addr;
-	msgs[0].flags = 0;
-	msgs[0].len = sizeof(write_buf);
-	msgs[0].buf = write_buf;
-
-	msgs[1].addr = addr;
-	msgs[1].flags = I2C_M_RD;
-	msgs[1].len = sizeof(read_buf);
-	msgs[1].buf = read_buf;
-
-	if (i2c_transfer(state->adap, msgs, 2) != 2)
-		return -EREMOTEIO;
-
-	*lock = !(read_buf[0] & 0x10);
-	return 0;
-}
-
-static int
-va1j5jf8007s_set_ts_id(struct va1j5jf8007s_state *state)
-{
-	u32 ts_id;
-	u8 buf[3];
-	struct i2c_msg msg;
-
-	ts_id = state->fe.dtv_property_cache.isdbs_ts_id;
-	if (!ts_id)
-		return 0;
-
-	buf[0] = 0x8f;
-	buf[1] = ts_id >> 8;
-	buf[2] = ts_id;
-
-	msg.addr = state->config->demod_address;
-	msg.flags = 0;
-	msg.len = sizeof(buf);
-	msg.buf = buf;
-
-	if (i2c_transfer(state->adap, &msg, 1) != 1)
-		return -EREMOTEIO;
-
-	return 0;
-}
-
-static int
-va1j5jf8007s_check_ts_id(struct va1j5jf8007s_state *state, int *lock)
-{
-	u8 addr;
-	u8 write_buf[1], read_buf[2];
-	struct i2c_msg msgs[2];
-	u32 ts_id;
-
-	ts_id = state->fe.dtv_property_cache.isdbs_ts_id;
-	if (!ts_id) {
-		*lock = 1;
-		return 0;
-	}
-
-	addr = state->config->demod_address;
-
-	write_buf[0] = 0xe6;
-
-	msgs[0].addr = addr;
-	msgs[0].flags = 0;
-	msgs[0].len = sizeof(write_buf);
-	msgs[0].buf = write_buf;
-
-	msgs[1].addr = addr;
-	msgs[1].flags = I2C_M_RD;
-	msgs[1].len = sizeof(read_buf);
-	msgs[1].buf = read_buf;
-
-	if (i2c_transfer(state->adap, msgs, 2) != 2)
-		return -EREMOTEIO;
-
-	*lock = (read_buf[0] << 8 | read_buf[1]) == ts_id;
-	return 0;
-}
-
-static int
-va1j5jf8007s_tune(struct dvb_frontend *fe,
-		  bool re_tune,
-		  unsigned int mode_flags,  unsigned int *delay,
-		  fe_status_t *status)
-{
-	struct va1j5jf8007s_state *state;
-	int ret;
-	int lock = 0;
-
-	state = fe->demodulator_priv;
-
-	if (re_tune)
-		state->tune_state = VA1J5JF8007S_SET_FREQUENCY_1;
-
-	switch (state->tune_state) {
-	case VA1J5JF8007S_IDLE:
-		*delay = 3 * HZ;
-		*status = 0;
-		return 0;
-
-	case VA1J5JF8007S_SET_FREQUENCY_1:
-		ret = va1j5jf8007s_set_frequency_1(state);
-		if (ret < 0)
-			return ret;
-
-		state->tune_state = VA1J5JF8007S_SET_FREQUENCY_2;
-		*delay = 0;
-		*status = 0;
-		return 0;
-
-	case VA1J5JF8007S_SET_FREQUENCY_2:
-		ret = va1j5jf8007s_set_frequency_2(state);
-		if (ret < 0)
-			return ret;
-
-		state->tune_state = VA1J5JF8007S_SET_FREQUENCY_3;
-		*delay = (HZ + 99) / 100;
-		*status = 0;
-		return 0;
-
-	case VA1J5JF8007S_SET_FREQUENCY_3:
-		ret = va1j5jf8007s_set_frequency_3(state);
-		if (ret < 0)
-			return ret;
-
-		state->tune_state = VA1J5JF8007S_CHECK_FREQUENCY;
-		*delay = 0;
-		*status = 0;
-		return 0;
-
-	case VA1J5JF8007S_CHECK_FREQUENCY:
-		ret = va1j5jf8007s_check_frequency(state, &lock);
-		if (ret < 0)
-			return ret;
-
-		if (!lock)  {
-			*delay = (HZ + 999) / 1000;
-			*status = 0;
-			return 0;
-		}
-
-		state->tune_state = VA1J5JF8007S_SET_MODULATION;
-		*delay = 0;
-		*status = FE_HAS_SIGNAL;
-		return 0;
-
-	case VA1J5JF8007S_SET_MODULATION:
-		ret = va1j5jf8007s_set_modulation(state);
-		if (ret < 0)
-			return ret;
-
-		state->tune_state = VA1J5JF8007S_CHECK_MODULATION;
-		*delay = 0;
-		*status = FE_HAS_SIGNAL;
-		return 0;
-
-	case VA1J5JF8007S_CHECK_MODULATION:
-		ret = va1j5jf8007s_check_modulation(state, &lock);
-		if (ret < 0)
-			return ret;
-
-		if (!lock)  {
-			*delay = (HZ + 49) / 50;
-			*status = FE_HAS_SIGNAL;
-			return 0;
-		}
-
-		state->tune_state = VA1J5JF8007S_SET_TS_ID;
-		*delay = 0;
-		*status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
-		return 0;
-
-	case VA1J5JF8007S_SET_TS_ID:
-		ret = va1j5jf8007s_set_ts_id(state);
-		if (ret < 0)
-			return ret;
-
-		state->tune_state = VA1J5JF8007S_CHECK_TS_ID;
-		return 0;
-
-	case VA1J5JF8007S_CHECK_TS_ID:
-		ret = va1j5jf8007s_check_ts_id(state, &lock);
-		if (ret < 0)
-			return ret;
-
-		if (!lock)  {
-			*delay = (HZ + 99) / 100;
-			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
-			return 0;
-		}
-
-		state->tune_state = VA1J5JF8007S_TRACK;
-		/* fall through */
-
-	case VA1J5JF8007S_TRACK:
-		*delay = 3 * HZ;
-		*status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
-		return 0;
-	}
-
-	BUG();
-}
-
-static int va1j5jf8007s_init_frequency(struct va1j5jf8007s_state *state)
-{
-	u8 buf[4];
-	struct i2c_msg msg;
-
-	buf[0] = 0xfe;
-	buf[1] = 0xc0;
-	buf[2] = 0xf0;
-	buf[3] = 0x04;
-
-	msg.addr = state->config->demod_address;
-	msg.flags = 0;
-	msg.len = sizeof(buf);
-	msg.buf = buf;
-
-	if (i2c_transfer(state->adap, &msg, 1) != 1)
-		return -EREMOTEIO;
-
-	return 0;
-}
-
-static int va1j5jf8007s_set_sleep(struct va1j5jf8007s_state *state, int sleep)
-{
-	u8 buf[2];
-	struct i2c_msg msg;
-
-	buf[0] = 0x17;
-	buf[1] = sleep ? 0x01 : 0x00;
-
-	msg.addr = state->config->demod_address;
-	msg.flags = 0;
-	msg.len = sizeof(buf);
-	msg.buf = buf;
-
-	if (i2c_transfer(state->adap, &msg, 1) != 1)
-		return -EREMOTEIO;
-
-	return 0;
-}
-
-static int va1j5jf8007s_sleep(struct dvb_frontend *fe)
-{
-	struct va1j5jf8007s_state *state;
-	int ret;
-
-	state = fe->demodulator_priv;
-
-	ret = va1j5jf8007s_init_frequency(state);
-	if (ret < 0)
-		return ret;
-
-	return va1j5jf8007s_set_sleep(state, 1);
-}
-
-static int va1j5jf8007s_init(struct dvb_frontend *fe)
-{
-	struct va1j5jf8007s_state *state;
-
-	state = fe->demodulator_priv;
-	state->tune_state = VA1J5JF8007S_IDLE;
-
-	return va1j5jf8007s_set_sleep(state, 0);
-}
-
-static void va1j5jf8007s_release(struct dvb_frontend *fe)
-{
-	struct va1j5jf8007s_state *state;
-	state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops va1j5jf8007s_ops = {
-	.delsys = { SYS_ISDBS },
-	.info = {
-		.name = "VA1J5JF8007/VA1J5JF8011 ISDB-S",
-		.frequency_min = 950000,
-		.frequency_max = 2150000,
-		.frequency_stepsize = 1000,
-		.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO |
-			FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
-	},
-
-	.read_snr = va1j5jf8007s_read_snr,
-	.get_frontend_algo = va1j5jf8007s_get_frontend_algo,
-	.read_status = va1j5jf8007s_read_status,
-	.tune = va1j5jf8007s_tune,
-	.sleep = va1j5jf8007s_sleep,
-	.init = va1j5jf8007s_init,
-	.release = va1j5jf8007s_release,
-};
-
-static int va1j5jf8007s_prepare_1(struct va1j5jf8007s_state *state)
-{
-	u8 addr;
-	u8 write_buf[1], read_buf[1];
-	struct i2c_msg msgs[2];
-
-	addr = state->config->demod_address;
-
-	write_buf[0] = 0x07;
-
-	msgs[0].addr = addr;
-	msgs[0].flags = 0;
-	msgs[0].len = sizeof(write_buf);
-	msgs[0].buf = write_buf;
-
-	msgs[1].addr = addr;
-	msgs[1].flags = I2C_M_RD;
-	msgs[1].len = sizeof(read_buf);
-	msgs[1].buf = read_buf;
-
-	if (i2c_transfer(state->adap, msgs, 2) != 2)
-		return -EREMOTEIO;
-
-	if (read_buf[0] != 0x41)
-		return -EIO;
-
-	return 0;
-}
-
-static const u8 va1j5jf8007s_20mhz_prepare_bufs[][2] = {
-	{0x04, 0x02}, {0x0d, 0x55}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01},
-	{0x1c, 0x0a}, {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0},
-	{0x52, 0x89}, {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69},
-	{0x87, 0x04}, {0x8e, 0x02}, {0xa3, 0xf7}, {0xa5, 0xc0},
-};
-
-static const u8 va1j5jf8007s_25mhz_prepare_bufs[][2] = {
-	{0x04, 0x02}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, {0x1c, 0x0a},
-	{0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, {0x52, 0x89},
-	{0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, {0x87, 0x04},
-	{0x8e, 0x26}, {0xa3, 0xf7}, {0xa5, 0xc0},
-};
-
-static int va1j5jf8007s_prepare_2(struct va1j5jf8007s_state *state)
-{
-	const u8 (*bufs)[2];
-	int size;
-	u8 addr;
-	u8 buf[2];
-	struct i2c_msg msg;
-	int i;
-
-	switch (state->config->frequency) {
-	case VA1J5JF8007S_20MHZ:
-		bufs = va1j5jf8007s_20mhz_prepare_bufs;
-		size = ARRAY_SIZE(va1j5jf8007s_20mhz_prepare_bufs);
-		break;
-	case VA1J5JF8007S_25MHZ:
-		bufs = va1j5jf8007s_25mhz_prepare_bufs;
-		size = ARRAY_SIZE(va1j5jf8007s_25mhz_prepare_bufs);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	addr = state->config->demod_address;
-
-	msg.addr = addr;
-	msg.flags = 0;
-	msg.len = 2;
-	msg.buf = buf;
-	for (i = 0; i < size; i++) {
-		memcpy(buf, bufs[i], sizeof(buf));
-		if (i2c_transfer(state->adap, &msg, 1) != 1)
-			return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-/* must be called after va1j5jf8007t_attach */
-int va1j5jf8007s_prepare(struct dvb_frontend *fe)
-{
-	struct va1j5jf8007s_state *state;
-	int ret;
-
-	state = fe->demodulator_priv;
-
-	ret = va1j5jf8007s_prepare_1(state);
-	if (ret < 0)
-		return ret;
-
-	ret = va1j5jf8007s_prepare_2(state);
-	if (ret < 0)
-		return ret;
-
-	return va1j5jf8007s_init_frequency(state);
-}
-
-struct dvb_frontend *
-va1j5jf8007s_attach(const struct va1j5jf8007s_config *config,
-		    struct i2c_adapter *adap)
-{
-	struct va1j5jf8007s_state *state;
-	struct dvb_frontend *fe;
-	u8 buf[2];
-	struct i2c_msg msg;
-
-	state = kzalloc(sizeof(struct va1j5jf8007s_state), GFP_KERNEL);
-	if (!state)
-		return NULL;
-
-	state->config = config;
-	state->adap = adap;
-
-	fe = &state->fe;
-	memcpy(&fe->ops, &va1j5jf8007s_ops, sizeof(struct dvb_frontend_ops));
-	fe->demodulator_priv = state;
-
-	buf[0] = 0x01;
-	buf[1] = 0x80;
-
-	msg.addr = state->config->demod_address;
-	msg.flags = 0;
-	msg.len = sizeof(buf);
-	msg.buf = buf;
-
-	if (i2c_transfer(state->adap, &msg, 1) != 1) {
-		kfree(state);
-		return NULL;
-	}
-
-	return fe;
-}
diff --git a/drivers/media/dvb/pt1/va1j5jf8007s.h b/drivers/media/dvb/pt1/va1j5jf8007s.h
deleted file mode 100644
index b7d6f05..0000000
--- a/drivers/media/dvb/pt1/va1j5jf8007s.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * ISDB-S driver for VA1J5JF8007/VA1J5JF8011
- *
- * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
- *
- * based on pt1dvr - http://pt1dvr.sourceforge.jp/
- * 	by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef VA1J5JF8007S_H
-#define VA1J5JF8007S_H
-
-enum va1j5jf8007s_frequency {
-	VA1J5JF8007S_20MHZ,
-	VA1J5JF8007S_25MHZ,
-};
-
-struct va1j5jf8007s_config {
-	u8 demod_address;
-	enum va1j5jf8007s_frequency frequency;
-};
-
-struct i2c_adapter;
-
-struct dvb_frontend *
-va1j5jf8007s_attach(const struct va1j5jf8007s_config *config,
-		    struct i2c_adapter *adap);
-
-/* must be called after va1j5jf8007t_attach */
-int va1j5jf8007s_prepare(struct dvb_frontend *fe);
-
-#endif
diff --git a/drivers/media/dvb/pt1/va1j5jf8007t.c b/drivers/media/dvb/pt1/va1j5jf8007t.c
deleted file mode 100644
index 2db15159..0000000
--- a/drivers/media/dvb/pt1/va1j5jf8007t.c
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * ISDB-T driver for VA1J5JF8007/VA1J5JF8011
- *
- * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
- *
- * based on pt1dvr - http://pt1dvr.sourceforge.jp/
- * 	by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-#include "dvb_math.h"
-#include "va1j5jf8007t.h"
-
-enum va1j5jf8007t_tune_state {
-	VA1J5JF8007T_IDLE,
-	VA1J5JF8007T_SET_FREQUENCY,
-	VA1J5JF8007T_CHECK_FREQUENCY,
-	VA1J5JF8007T_SET_MODULATION,
-	VA1J5JF8007T_CHECK_MODULATION,
-	VA1J5JF8007T_TRACK,
-	VA1J5JF8007T_ABORT,
-};
-
-struct va1j5jf8007t_state {
-	const struct va1j5jf8007t_config *config;
-	struct i2c_adapter *adap;
-	struct dvb_frontend fe;
-	enum va1j5jf8007t_tune_state tune_state;
-};
-
-static int va1j5jf8007t_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct va1j5jf8007t_state *state;
-	u8 addr;
-	int i;
-	u8 write_buf[1], read_buf[1];
-	struct i2c_msg msgs[2];
-	s32 word, x, y;
-
-	state = fe->demodulator_priv;
-	addr = state->config->demod_address;
-
-	word = 0;
-	for (i = 0; i < 3; i++) {
-		write_buf[0] = 0x8b + i;
-
-		msgs[0].addr = addr;
-		msgs[0].flags = 0;
-		msgs[0].len = sizeof(write_buf);
-		msgs[0].buf = write_buf;
-
-		msgs[1].addr = addr;
-		msgs[1].flags = I2C_M_RD;
-		msgs[1].len = sizeof(read_buf);
-		msgs[1].buf = read_buf;
-
-		if (i2c_transfer(state->adap, msgs, 2) != 2)
-			return -EREMOTEIO;
-
-		word <<= 8;
-		word |= read_buf[0];
-	}
-
-	if (!word)
-		return -EIO;
-
-	x = 10 * (intlog10(0x540000 * 100 / word) - (2 << 24));
-	y = (24ll << 46) / 1000000;
-	y = ((s64)y * x >> 30) - (16ll << 40) / 10000;
-	y = ((s64)y * x >> 29) + (398ll << 35) / 10000;
-	y = ((s64)y * x >> 30) + (5491ll << 29) / 10000;
-	y = ((s64)y * x >> 30) + (30965ll << 23) / 10000;
-	*snr = y >> 15;
-	return 0;
-}
-
-static int va1j5jf8007t_get_frontend_algo(struct dvb_frontend *fe)
-{
-	return DVBFE_ALGO_HW;
-}
-
-static int
-va1j5jf8007t_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct va1j5jf8007t_state *state;
-
-	state = fe->demodulator_priv;
-
-	switch (state->tune_state) {
-	case VA1J5JF8007T_IDLE:
-	case VA1J5JF8007T_SET_FREQUENCY:
-	case VA1J5JF8007T_CHECK_FREQUENCY:
-		*status = 0;
-		return 0;
-
-
-	case VA1J5JF8007T_SET_MODULATION:
-	case VA1J5JF8007T_CHECK_MODULATION:
-	case VA1J5JF8007T_ABORT:
-		*status |= FE_HAS_SIGNAL;
-		return 0;
-
-	case VA1J5JF8007T_TRACK:
-		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
-		return 0;
-	}
-
-	BUG();
-}
-
-struct va1j5jf8007t_cb_map {
-	u32 frequency;
-	u8 cb;
-};
-
-static const struct va1j5jf8007t_cb_map va1j5jf8007t_cb_maps[] = {
-	{  90000000, 0x80 },
-	{ 140000000, 0x81 },
-	{ 170000000, 0xa1 },
-	{ 220000000, 0x62 },
-	{ 330000000, 0xa2 },
-	{ 402000000, 0xe2 },
-	{ 450000000, 0x64 },
-	{ 550000000, 0x84 },
-	{ 600000000, 0xa4 },
-	{ 700000000, 0xc4 },
-};
-
-static u8 va1j5jf8007t_lookup_cb(u32 frequency)
-{
-	int i;
-	const struct va1j5jf8007t_cb_map *map;
-
-	for (i = 0; i < ARRAY_SIZE(va1j5jf8007t_cb_maps); i++) {
-		map = &va1j5jf8007t_cb_maps[i];
-		if (frequency < map->frequency)
-			return map->cb;
-	}
-	return 0xe4;
-}
-
-static int va1j5jf8007t_set_frequency(struct va1j5jf8007t_state *state)
-{
-	u32 frequency;
-	u16 word;
-	u8 buf[6];
-	struct i2c_msg msg;
-
-	frequency = state->fe.dtv_property_cache.frequency;
-
-	word = (frequency + 71428) / 142857 + 399;
-	buf[0] = 0xfe;
-	buf[1] = 0xc2;
-	buf[2] = word >> 8;
-	buf[3] = word;
-	buf[4] = 0x80;
-	buf[5] = va1j5jf8007t_lookup_cb(frequency);
-
-	msg.addr = state->config->demod_address;
-	msg.flags = 0;
-	msg.len = sizeof(buf);
-	msg.buf = buf;
-
-	if (i2c_transfer(state->adap, &msg, 1) != 1)
-		return -EREMOTEIO;
-
-	return 0;
-}
-
-static int
-va1j5jf8007t_check_frequency(struct va1j5jf8007t_state *state, int *lock)
-{
-	u8 addr;
-	u8 write_buf[2], read_buf[1];
-	struct i2c_msg msgs[2];
-
-	addr = state->config->demod_address;
-
-	write_buf[0] = 0xfe;
-	write_buf[1] = 0xc3;
-
-	msgs[0].addr = addr;
-	msgs[0].flags = 0;
-	msgs[0].len = sizeof(write_buf);
-	msgs[0].buf = write_buf;
-
-	msgs[1].addr = addr;
-	msgs[1].flags = I2C_M_RD;
-	msgs[1].len = sizeof(read_buf);
-	msgs[1].buf = read_buf;
-
-	if (i2c_transfer(state->adap, msgs, 2) != 2)
-		return -EREMOTEIO;
-
-	*lock = read_buf[0] & 0x40;
-	return 0;
-}
-
-static int va1j5jf8007t_set_modulation(struct va1j5jf8007t_state *state)
-{
-	u8 buf[2];
-	struct i2c_msg msg;
-
-	buf[0] = 0x01;
-	buf[1] = 0x40;
-
-	msg.addr = state->config->demod_address;
-	msg.flags = 0;
-	msg.len = sizeof(buf);
-	msg.buf = buf;
-
-	if (i2c_transfer(state->adap, &msg, 1) != 1)
-		return -EREMOTEIO;
-
-	return 0;
-}
-
-static int va1j5jf8007t_check_modulation(struct va1j5jf8007t_state *state,
-					 int *lock, int *retry)
-{
-	u8 addr;
-	u8 write_buf[1], read_buf[1];
-	struct i2c_msg msgs[2];
-
-	addr = state->config->demod_address;
-
-	write_buf[0] = 0x80;
-
-	msgs[0].addr = addr;
-	msgs[0].flags = 0;
-	msgs[0].len = sizeof(write_buf);
-	msgs[0].buf = write_buf;
-
-	msgs[1].addr = addr;
-	msgs[1].flags = I2C_M_RD;
-	msgs[1].len = sizeof(read_buf);
-	msgs[1].buf = read_buf;
-
-	if (i2c_transfer(state->adap, msgs, 2) != 2)
-		return -EREMOTEIO;
-
-	*lock = !(read_buf[0] & 0x10);
-	*retry = read_buf[0] & 0x80;
-	return 0;
-}
-
-static int
-va1j5jf8007t_tune(struct dvb_frontend *fe,
-		  bool re_tune,
-		  unsigned int mode_flags,  unsigned int *delay,
-		  fe_status_t *status)
-{
-	struct va1j5jf8007t_state *state;
-	int ret;
-	int lock = 0, retry = 0;
-
-	state = fe->demodulator_priv;
-
-	if (re_tune)
-		state->tune_state = VA1J5JF8007T_SET_FREQUENCY;
-
-	switch (state->tune_state) {
-	case VA1J5JF8007T_IDLE:
-		*delay = 3 * HZ;
-		*status = 0;
-		return 0;
-
-	case VA1J5JF8007T_SET_FREQUENCY:
-		ret = va1j5jf8007t_set_frequency(state);
-		if (ret < 0)
-			return ret;
-
-		state->tune_state = VA1J5JF8007T_CHECK_FREQUENCY;
-		*delay = 0;
-		*status = 0;
-		return 0;
-
-	case VA1J5JF8007T_CHECK_FREQUENCY:
-		ret = va1j5jf8007t_check_frequency(state, &lock);
-		if (ret < 0)
-			return ret;
-
-		if (!lock)  {
-			*delay = (HZ + 999) / 1000;
-			*status = 0;
-			return 0;
-		}
-
-		state->tune_state = VA1J5JF8007T_SET_MODULATION;
-		*delay = 0;
-		*status = FE_HAS_SIGNAL;
-		return 0;
-
-	case VA1J5JF8007T_SET_MODULATION:
-		ret = va1j5jf8007t_set_modulation(state);
-		if (ret < 0)
-			return ret;
-
-		state->tune_state = VA1J5JF8007T_CHECK_MODULATION;
-		*delay = 0;
-		*status = FE_HAS_SIGNAL;
-		return 0;
-
-	case VA1J5JF8007T_CHECK_MODULATION:
-		ret = va1j5jf8007t_check_modulation(state, &lock, &retry);
-		if (ret < 0)
-			return ret;
-
-		if (!lock)  {
-			if (!retry)  {
-				state->tune_state = VA1J5JF8007T_ABORT;
-				*delay = 3 * HZ;
-				*status = FE_HAS_SIGNAL;
-				return 0;
-			}
-			*delay = (HZ + 999) / 1000;
-			*status = FE_HAS_SIGNAL;
-			return 0;
-		}
-
-		state->tune_state = VA1J5JF8007T_TRACK;
-		/* fall through */
-
-	case VA1J5JF8007T_TRACK:
-		*delay = 3 * HZ;
-		*status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
-		return 0;
-
-	case VA1J5JF8007T_ABORT:
-		*delay = 3 * HZ;
-		*status = FE_HAS_SIGNAL;
-		return 0;
-	}
-
-	BUG();
-}
-
-static int va1j5jf8007t_init_frequency(struct va1j5jf8007t_state *state)
-{
-	u8 buf[7];
-	struct i2c_msg msg;
-
-	buf[0] = 0xfe;
-	buf[1] = 0xc2;
-	buf[2] = 0x01;
-	buf[3] = 0x8f;
-	buf[4] = 0xc1;
-	buf[5] = 0x80;
-	buf[6] = 0x80;
-
-	msg.addr = state->config->demod_address;
-	msg.flags = 0;
-	msg.len = sizeof(buf);
-	msg.buf = buf;
-
-	if (i2c_transfer(state->adap, &msg, 1) != 1)
-		return -EREMOTEIO;
-
-	return 0;
-}
-
-static int va1j5jf8007t_set_sleep(struct va1j5jf8007t_state *state, int sleep)
-{
-	u8 buf[2];
-	struct i2c_msg msg;
-
-	buf[0] = 0x03;
-	buf[1] = sleep ? 0x90 : 0x80;
-
-	msg.addr = state->config->demod_address;
-	msg.flags = 0;
-	msg.len = sizeof(buf);
-	msg.buf = buf;
-
-	if (i2c_transfer(state->adap, &msg, 1) != 1)
-		return -EREMOTEIO;
-
-	return 0;
-}
-
-static int va1j5jf8007t_sleep(struct dvb_frontend *fe)
-{
-	struct va1j5jf8007t_state *state;
-	int ret;
-
-	state = fe->demodulator_priv;
-
-	ret = va1j5jf8007t_init_frequency(state);
-	if (ret < 0)
-		return ret;
-
-	return va1j5jf8007t_set_sleep(state, 1);
-}
-
-static int va1j5jf8007t_init(struct dvb_frontend *fe)
-{
-	struct va1j5jf8007t_state *state;
-
-	state = fe->demodulator_priv;
-	state->tune_state = VA1J5JF8007T_IDLE;
-
-	return va1j5jf8007t_set_sleep(state, 0);
-}
-
-static void va1j5jf8007t_release(struct dvb_frontend *fe)
-{
-	struct va1j5jf8007t_state *state;
-	state = fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops va1j5jf8007t_ops = {
-	.delsys = { SYS_ISDBT },
-	.info = {
-		.name = "VA1J5JF8007/VA1J5JF8011 ISDB-T",
-		.frequency_min = 90000000,
-		.frequency_max = 770000000,
-		.frequency_stepsize = 142857,
-		.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO |
-			FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
-	},
-
-	.read_snr = va1j5jf8007t_read_snr,
-	.get_frontend_algo = va1j5jf8007t_get_frontend_algo,
-	.read_status = va1j5jf8007t_read_status,
-	.tune = va1j5jf8007t_tune,
-	.sleep = va1j5jf8007t_sleep,
-	.init = va1j5jf8007t_init,
-	.release = va1j5jf8007t_release,
-};
-
-static const u8 va1j5jf8007t_20mhz_prepare_bufs[][2] = {
-	{0x03, 0x90}, {0x14, 0x8f}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2},
-	{0x22, 0x83}, {0x31, 0x0d}, {0x32, 0xe0}, {0x39, 0xd3}, {0x3a, 0x00},
-	{0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x02}, {0x76, 0x4e}, {0x77, 0x03},
-	{0xef, 0x01}
-};
-
-static const u8 va1j5jf8007t_25mhz_prepare_bufs[][2] = {
-	{0x03, 0x90}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, {0x22, 0x83},
-	{0x3a, 0x00}, {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x0a}, {0x76, 0x4c},
-	{0x77, 0x03}, {0xef, 0x01}
-};
-
-int va1j5jf8007t_prepare(struct dvb_frontend *fe)
-{
-	struct va1j5jf8007t_state *state;
-	const u8 (*bufs)[2];
-	int size;
-	u8 buf[2];
-	struct i2c_msg msg;
-	int i;
-
-	state = fe->demodulator_priv;
-
-	switch (state->config->frequency) {
-	case VA1J5JF8007T_20MHZ:
-		bufs = va1j5jf8007t_20mhz_prepare_bufs;
-		size = ARRAY_SIZE(va1j5jf8007t_20mhz_prepare_bufs);
-		break;
-	case VA1J5JF8007T_25MHZ:
-		bufs = va1j5jf8007t_25mhz_prepare_bufs;
-		size = ARRAY_SIZE(va1j5jf8007t_25mhz_prepare_bufs);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	msg.addr = state->config->demod_address;
-	msg.flags = 0;
-	msg.len = sizeof(buf);
-	msg.buf = buf;
-
-	for (i = 0; i < size; i++) {
-		memcpy(buf, bufs[i], sizeof(buf));
-		if (i2c_transfer(state->adap, &msg, 1) != 1)
-			return -EREMOTEIO;
-	}
-
-	return va1j5jf8007t_init_frequency(state);
-}
-
-struct dvb_frontend *
-va1j5jf8007t_attach(const struct va1j5jf8007t_config *config,
-		    struct i2c_adapter *adap)
-{
-	struct va1j5jf8007t_state *state;
-	struct dvb_frontend *fe;
-	u8 buf[2];
-	struct i2c_msg msg;
-
-	state = kzalloc(sizeof(struct va1j5jf8007t_state), GFP_KERNEL);
-	if (!state)
-		return NULL;
-
-	state->config = config;
-	state->adap = adap;
-
-	fe = &state->fe;
-	memcpy(&fe->ops, &va1j5jf8007t_ops, sizeof(struct dvb_frontend_ops));
-	fe->demodulator_priv = state;
-
-	buf[0] = 0x01;
-	buf[1] = 0x80;
-
-	msg.addr = state->config->demod_address;
-	msg.flags = 0;
-	msg.len = sizeof(buf);
-	msg.buf = buf;
-
-	if (i2c_transfer(state->adap, &msg, 1) != 1) {
-		kfree(state);
-		return NULL;
-	}
-
-	return fe;
-}
diff --git a/drivers/media/dvb/pt1/va1j5jf8007t.h b/drivers/media/dvb/pt1/va1j5jf8007t.h
deleted file mode 100644
index 2903be5..0000000
--- a/drivers/media/dvb/pt1/va1j5jf8007t.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * ISDB-T driver for VA1J5JF8007/VA1J5JF8011
- *
- * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
- *
- * based on pt1dvr - http://pt1dvr.sourceforge.jp/
- * 	by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef VA1J5JF8007T_H
-#define VA1J5JF8007T_H
-
-enum va1j5jf8007t_frequency {
-	VA1J5JF8007T_20MHZ,
-	VA1J5JF8007T_25MHZ,
-};
-
-struct va1j5jf8007t_config {
-	u8 demod_address;
-	enum va1j5jf8007t_frequency frequency;
-};
-
-struct i2c_adapter;
-
-struct dvb_frontend *
-va1j5jf8007t_attach(const struct va1j5jf8007t_config *config,
-		    struct i2c_adapter *adap);
-
-/* must be called after va1j5jf8007s_attach */
-int va1j5jf8007t_prepare(struct dvb_frontend *fe);
-
-#endif
diff --git a/drivers/media/dvb/siano/Kconfig b/drivers/media/dvb/siano/Kconfig
deleted file mode 100644
index bc6456e..0000000
--- a/drivers/media/dvb/siano/Kconfig
+++ /dev/null
@@ -1,34 +0,0 @@
-#
-# Siano Mobile Silicon Digital TV device configuration
-#
-
-config SMS_SIANO_MDTV
-	tristate "Siano SMS1xxx based MDTV receiver"
-	depends on DVB_CORE && RC_CORE && HAS_DMA
-	---help---
-	  Choose Y or M here if you have MDTV receiver with a Siano chipset.
-
-	  To compile this driver as a module, choose M here
-	  (The module will be called smsmdtv).
-
-	  Further documentation on this driver can be found on the WWW
-	  at http://www.siano-ms.com/
-
-if SMS_SIANO_MDTV
-menu "Siano module components"
-
-# Hardware interfaces support
-
-config SMS_USB_DRV
-	tristate "USB interface support"
-	depends on DVB_CORE && USB
-	---help---
-	  Choose if you would like to have Siano's support for USB interface
-
-config SMS_SDIO_DRV
-	tristate "SDIO interface support"
-	depends on DVB_CORE && MMC
-	---help---
-	  Choose if you would like to have Siano's support for SDIO interface
-endmenu
-endif # SMS_SIANO_MDTV
diff --git a/drivers/media/dvb/siano/Makefile b/drivers/media/dvb/siano/Makefile
deleted file mode 100644
index f233b57..0000000
--- a/drivers/media/dvb/siano/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-
-smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o
-
-obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o
-obj-$(CONFIG_SMS_USB_DRV) += smsusb.o
-obj-$(CONFIG_SMS_SDIO_DRV) += smssdio.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core
-
-ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
-
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
deleted file mode 100644
index 680c781..0000000
--- a/drivers/media/dvb/siano/sms-cards.c
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- *  Card-specific functions for the Siano SMS1xxx USB dongle
- *
- *  Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation;
- *
- *  Software distributed under the License is distributed on an "AS IS"
- *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
- *
- *  See the GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "sms-cards.h"
-#include "smsir.h"
-#include <linux/module.h>
-
-static int sms_dbg;
-module_param_named(cards_dbg, sms_dbg, int, 0644);
-MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))");
-
-static struct sms_board sms_boards[] = {
-	[SMS_BOARD_UNKNOWN] = {
-		.name	= "Unknown board",
-	},
-	[SMS1XXX_BOARD_SIANO_STELLAR] = {
-		.name	= "Siano Stellar Digital Receiver",
-		.type	= SMS_STELLAR,
-	},
-	[SMS1XXX_BOARD_SIANO_NOVA_A] = {
-		.name	= "Siano Nova A Digital Receiver",
-		.type	= SMS_NOVA_A0,
-	},
-	[SMS1XXX_BOARD_SIANO_NOVA_B] = {
-		.name	= "Siano Nova B Digital Receiver",
-		.type	= SMS_NOVA_B0,
-	},
-	[SMS1XXX_BOARD_SIANO_VEGA] = {
-		.name	= "Siano Vega Digital Receiver",
-		.type	= SMS_VEGA,
-	},
-	[SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = {
-		.name	= "Hauppauge Catamount",
-		.type	= SMS_STELLAR,
-		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
-	},
-	[SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = {
-		.name	= "Hauppauge Okemo-A",
-		.type	= SMS_NOVA_A0,
-		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
-	},
-	[SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = {
-		.name	= "Hauppauge Okemo-B",
-		.type	= SMS_NOVA_B0,
-		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
-	},
-	[SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
-		.name	= "Hauppauge WinTV MiniStick",
-		.type	= SMS_NOVA_B0,
-		.fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw",
-		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
-		.rc_codes = RC_MAP_HAUPPAUGE,
-		.board_cfg.leds_power = 26,
-		.board_cfg.led0 = 27,
-		.board_cfg.led1 = 28,
-		.board_cfg.ir = 9,
-		.led_power = 26,
-		.led_lo    = 27,
-		.led_hi    = 28,
-	},
-	[SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = {
-		.name	= "Hauppauge WinTV MiniCard",
-		.type	= SMS_NOVA_B0,
-		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
-		.lna_ctrl  = 29,
-		.board_cfg.foreign_lna0_ctrl = 29,
-		.rf_switch = 17,
-		.board_cfg.rf_switch_uhf = 17,
-	},
-	[SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
-		.name	= "Hauppauge WinTV MiniCard",
-		.type	= SMS_NOVA_B0,
-		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
-		.lna_ctrl  = -1,
-	},
-	[SMS1XXX_BOARD_SIANO_NICE] = {
-	/* 11 */
-		.name = "Siano Nice Digital Receiver",
-		.type = SMS_NOVA_B0,
-	},
-	[SMS1XXX_BOARD_SIANO_VENICE] = {
-	/* 12 */
-		.name = "Siano Venice Digital Receiver",
-		.type = SMS_VEGA,
-	},
-};
-
-struct sms_board *sms_get_board(unsigned id)
-{
-	BUG_ON(id >= ARRAY_SIZE(sms_boards));
-
-	return &sms_boards[id];
-}
-EXPORT_SYMBOL_GPL(sms_get_board);
-static inline void sms_gpio_assign_11xx_default_led_config(
-		struct smscore_gpio_config *pGpioConfig) {
-	pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT;
-	pGpioConfig->InputCharacteristics =
-		SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL;
-	pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA;
-	pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS;
-	pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE;
-}
-
-int sms_board_event(struct smscore_device_t *coredev,
-		enum SMS_BOARD_EVENTS gevent) {
-	struct smscore_gpio_config MyGpioConfig;
-
-	sms_gpio_assign_11xx_default_led_config(&MyGpioConfig);
-
-	switch (gevent) {
-	case BOARD_EVENT_POWER_INIT: /* including hotplug */
-		break; /* BOARD_EVENT_BIND */
-
-	case BOARD_EVENT_POWER_SUSPEND:
-		break; /* BOARD_EVENT_POWER_SUSPEND */
-
-	case BOARD_EVENT_POWER_RESUME:
-		break; /* BOARD_EVENT_POWER_RESUME */
-
-	case BOARD_EVENT_BIND:
-		break; /* BOARD_EVENT_BIND */
-
-	case BOARD_EVENT_SCAN_PROG:
-		break; /* BOARD_EVENT_SCAN_PROG */
-	case BOARD_EVENT_SCAN_COMP:
-		break; /* BOARD_EVENT_SCAN_COMP */
-	case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL:
-		break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */
-	case BOARD_EVENT_FE_LOCK:
-		break; /* BOARD_EVENT_FE_LOCK */
-	case BOARD_EVENT_FE_UNLOCK:
-		break; /* BOARD_EVENT_FE_UNLOCK */
-	case BOARD_EVENT_DEMOD_LOCK:
-		break; /* BOARD_EVENT_DEMOD_LOCK */
-	case BOARD_EVENT_DEMOD_UNLOCK:
-		break; /* BOARD_EVENT_DEMOD_UNLOCK */
-	case BOARD_EVENT_RECEPTION_MAX_4:
-		break; /* BOARD_EVENT_RECEPTION_MAX_4 */
-	case BOARD_EVENT_RECEPTION_3:
-		break; /* BOARD_EVENT_RECEPTION_3 */
-	case BOARD_EVENT_RECEPTION_2:
-		break; /* BOARD_EVENT_RECEPTION_2 */
-	case BOARD_EVENT_RECEPTION_1:
-		break; /* BOARD_EVENT_RECEPTION_1 */
-	case BOARD_EVENT_RECEPTION_LOST_0:
-		break; /* BOARD_EVENT_RECEPTION_LOST_0 */
-	case BOARD_EVENT_MULTIPLEX_OK:
-		break; /* BOARD_EVENT_MULTIPLEX_OK */
-	case BOARD_EVENT_MULTIPLEX_ERRORS:
-		break; /* BOARD_EVENT_MULTIPLEX_ERRORS */
-
-	default:
-		sms_err("Unknown SMS board event");
-		break;
-	}
-	return 0;
-}
-EXPORT_SYMBOL_GPL(sms_board_event);
-
-static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
-{
-	int lvl, ret;
-	u32 gpio;
-	struct smscore_config_gpio gpioconfig = {
-		.direction            = SMS_GPIO_DIRECTION_OUTPUT,
-		.pullupdown           = SMS_GPIO_PULLUPDOWN_NONE,
-		.inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,
-		.outputslewrate       = SMS_GPIO_OUTPUTSLEWRATE_FAST,
-		.outputdriving        = SMS_GPIO_OUTPUTDRIVING_4mA,
-	};
-
-	if (pin == 0)
-		return -EINVAL;
-
-	if (pin < 0) {
-		/* inverted gpio */
-		gpio = pin * -1;
-		lvl = enable ? 0 : 1;
-	} else {
-		gpio = pin;
-		lvl = enable ? 1 : 0;
-	}
-
-	ret = smscore_configure_gpio(coredev, gpio, &gpioconfig);
-	if (ret < 0)
-		return ret;
-
-	return smscore_set_gpio(coredev, gpio, lvl);
-}
-
-int sms_board_setup(struct smscore_device_t *coredev)
-{
-	int board_id = smscore_get_board_id(coredev);
-	struct sms_board *board = sms_get_board(board_id);
-
-	switch (board_id) {
-	case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
-		/* turn off all LEDs */
-		sms_set_gpio(coredev, board->led_power, 0);
-		sms_set_gpio(coredev, board->led_hi, 0);
-		sms_set_gpio(coredev, board->led_lo, 0);
-		break;
-	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
-	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
-		/* turn off LNA */
-		sms_set_gpio(coredev, board->lna_ctrl, 0);
-		break;
-	}
-	return 0;
-}
-EXPORT_SYMBOL_GPL(sms_board_setup);
-
-int sms_board_power(struct smscore_device_t *coredev, int onoff)
-{
-	int board_id = smscore_get_board_id(coredev);
-	struct sms_board *board = sms_get_board(board_id);
-
-	switch (board_id) {
-	case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
-		/* power LED */
-		sms_set_gpio(coredev,
-			     board->led_power, onoff ? 1 : 0);
-		break;
-	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
-	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
-		/* LNA */
-		if (!onoff)
-			sms_set_gpio(coredev, board->lna_ctrl, 0);
-		break;
-	}
-	return 0;
-}
-EXPORT_SYMBOL_GPL(sms_board_power);
-
-int sms_board_led_feedback(struct smscore_device_t *coredev, int led)
-{
-	int board_id = smscore_get_board_id(coredev);
-	struct sms_board *board = sms_get_board(board_id);
-
-	/* dont touch GPIO if LEDs are already set */
-	if (smscore_led_state(coredev, -1) == led)
-		return 0;
-
-	switch (board_id) {
-	case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
-		sms_set_gpio(coredev,
-			     board->led_lo, (led & SMS_LED_LO) ? 1 : 0);
-		sms_set_gpio(coredev,
-			     board->led_hi, (led & SMS_LED_HI) ? 1 : 0);
-
-		smscore_led_state(coredev, led);
-		break;
-	}
-	return 0;
-}
-EXPORT_SYMBOL_GPL(sms_board_led_feedback);
-
-int sms_board_lna_control(struct smscore_device_t *coredev, int onoff)
-{
-	int board_id = smscore_get_board_id(coredev);
-	struct sms_board *board = sms_get_board(board_id);
-
-	sms_debug("%s: LNA %s", __func__, onoff ? "enabled" : "disabled");
-
-	switch (board_id) {
-	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
-	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
-		sms_set_gpio(coredev,
-			     board->rf_switch, onoff ? 1 : 0);
-		return sms_set_gpio(coredev,
-				    board->lna_ctrl, onoff ? 1 : 0);
-	}
-	return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(sms_board_lna_control);
-
-int sms_board_load_modules(int id)
-{
-	switch (id) {
-	case SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT:
-	case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A:
-	case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B:
-	case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
-	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
-	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
-		request_module("smsdvb");
-		break;
-	default:
-		/* do nothing */
-		break;
-	}
-	return 0;
-}
-EXPORT_SYMBOL_GPL(sms_board_load_modules);
diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h
deleted file mode 100644
index d8cdf75..0000000
--- a/drivers/media/dvb/siano/sms-cards.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- *  Card-specific functions for the Siano SMS1xxx USB dongle
- *
- *  Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation;
- *
- *  Software distributed under the License is distributed on an "AS IS"
- *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
- *
- *  See the GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __SMS_CARDS_H__
-#define __SMS_CARDS_H__
-
-#include <linux/usb.h>
-#include "smscoreapi.h"
-#include "smsir.h"
-
-#define SMS_BOARD_UNKNOWN 0
-#define SMS1XXX_BOARD_SIANO_STELLAR 1
-#define SMS1XXX_BOARD_SIANO_NOVA_A  2
-#define SMS1XXX_BOARD_SIANO_NOVA_B  3
-#define SMS1XXX_BOARD_SIANO_VEGA    4
-#define SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT 5
-#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6
-#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7
-#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
-#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9
-#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10
-#define SMS1XXX_BOARD_SIANO_NICE	11
-#define SMS1XXX_BOARD_SIANO_VENICE	12
-
-struct sms_board_gpio_cfg {
-	int lna_vhf_exist;
-	int lna_vhf_ctrl;
-	int lna_uhf_exist;
-	int lna_uhf_ctrl;
-	int lna_uhf_d_ctrl;
-	int lna_sband_exist;
-	int lna_sband_ctrl;
-	int lna_sband_d_ctrl;
-	int foreign_lna0_ctrl;
-	int foreign_lna1_ctrl;
-	int foreign_lna2_ctrl;
-	int rf_switch_vhf;
-	int rf_switch_uhf;
-	int rf_switch_sband;
-	int leds_power;
-	int led0;
-	int led1;
-	int led2;
-	int led3;
-	int led4;
-	int ir;
-	int eeprom_wp;
-	int mrc_sense;
-	int mrc_pdn_resetn;
-	int mrc_gp0; /* mrcs spi int */
-	int mrc_gp1;
-	int mrc_gp2;
-	int mrc_gp3;
-	int mrc_gp4;
-	int host_spi_gsp_ts_int;
-};
-
-struct sms_board {
-	enum sms_device_type_st type;
-	char *name, *fw[DEVICE_MODE_MAX];
-	struct sms_board_gpio_cfg board_cfg;
-	char *rc_codes;				/* Name of IR codes table */
-
-	/* gpios */
-	int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
-};
-
-struct sms_board *sms_get_board(unsigned id);
-
-extern struct smscore_device_t *coredev;
-
-enum SMS_BOARD_EVENTS {
-	BOARD_EVENT_POWER_INIT,
-	BOARD_EVENT_POWER_SUSPEND,
-	BOARD_EVENT_POWER_RESUME,
-	BOARD_EVENT_BIND,
-	BOARD_EVENT_SCAN_PROG,
-	BOARD_EVENT_SCAN_COMP,
-	BOARD_EVENT_EMERGENCY_WARNING_SIGNAL,
-	BOARD_EVENT_FE_LOCK,
-	BOARD_EVENT_FE_UNLOCK,
-	BOARD_EVENT_DEMOD_LOCK,
-	BOARD_EVENT_DEMOD_UNLOCK,
-	BOARD_EVENT_RECEPTION_MAX_4,
-	BOARD_EVENT_RECEPTION_3,
-	BOARD_EVENT_RECEPTION_2,
-	BOARD_EVENT_RECEPTION_1,
-	BOARD_EVENT_RECEPTION_LOST_0,
-	BOARD_EVENT_MULTIPLEX_OK,
-	BOARD_EVENT_MULTIPLEX_ERRORS
-};
-
-int sms_board_event(struct smscore_device_t *coredev,
-		enum SMS_BOARD_EVENTS gevent);
-
-int sms_board_setup(struct smscore_device_t *coredev);
-
-#define SMS_LED_OFF 0
-#define SMS_LED_LO  1
-#define SMS_LED_HI  2
-int sms_board_led_feedback(struct smscore_device_t *coredev, int led);
-int sms_board_power(struct smscore_device_t *coredev, int onoff);
-int sms_board_lna_control(struct smscore_device_t *coredev, int onoff);
-
-extern int sms_board_load_modules(int id);
-
-#endif /* __SMS_CARDS_H__ */
diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
deleted file mode 100644
index 9cc5554..0000000
--- a/drivers/media/dvb/siano/smscoreapi.c
+++ /dev/null
@@ -1,1637 +0,0 @@
-/*
- *  Siano core API module
- *
- *  This file contains implementation for the interface to sms core component
- *
- *  author: Uri Shkolnik
- *
- *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation;
- *
- *  Software distributed under the License is distributed on an "AS IS"
- *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
- *
- *  See the GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-#include <linux/firmware.h>
-#include <linux/wait.h>
-#include <asm/byteorder.h>
-
-#include "smscoreapi.h"
-#include "sms-cards.h"
-#include "smsir.h"
-#include "smsendian.h"
-
-static int sms_dbg;
-module_param_named(debug, sms_dbg, int, 0644);
-MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
-
-struct smscore_device_notifyee_t {
-	struct list_head entry;
-	hotplug_t hotplug;
-};
-
-struct smscore_idlist_t {
-	struct list_head entry;
-	int		id;
-	int		data_type;
-};
-
-struct smscore_client_t {
-	struct list_head entry;
-	struct smscore_device_t *coredev;
-	void			*context;
-	struct list_head 	idlist;
-	onresponse_t	onresponse_handler;
-	onremove_t		onremove_handler;
-};
-
-void smscore_set_board_id(struct smscore_device_t *core, int id)
-{
-	core->board_id = id;
-}
-
-int smscore_led_state(struct smscore_device_t *core, int led)
-{
-	if (led >= 0)
-		core->led_state = led;
-	return core->led_state;
-}
-EXPORT_SYMBOL_GPL(smscore_set_board_id);
-
-int smscore_get_board_id(struct smscore_device_t *core)
-{
-	return core->board_id;
-}
-EXPORT_SYMBOL_GPL(smscore_get_board_id);
-
-struct smscore_registry_entry_t {
-	struct list_head entry;
-	char			devpath[32];
-	int				mode;
-	enum sms_device_type_st	type;
-};
-
-static struct list_head g_smscore_notifyees;
-static struct list_head g_smscore_devices;
-static struct mutex g_smscore_deviceslock;
-
-static struct list_head g_smscore_registry;
-static struct mutex g_smscore_registrylock;
-
-static int default_mode = 4;
-
-module_param(default_mode, int, 0644);
-MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
-
-static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
-{
-	struct smscore_registry_entry_t *entry;
-	struct list_head *next;
-
-	kmutex_lock(&g_smscore_registrylock);
-	for (next = g_smscore_registry.next;
-	     next != &g_smscore_registry;
-	     next = next->next) {
-		entry = (struct smscore_registry_entry_t *) next;
-		if (!strcmp(entry->devpath, devpath)) {
-			kmutex_unlock(&g_smscore_registrylock);
-			return entry;
-		}
-	}
-	entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL);
-	if (entry) {
-		entry->mode = default_mode;
-		strcpy(entry->devpath, devpath);
-		list_add(&entry->entry, &g_smscore_registry);
-	} else
-		sms_err("failed to create smscore_registry.");
-	kmutex_unlock(&g_smscore_registrylock);
-	return entry;
-}
-
-int smscore_registry_getmode(char *devpath)
-{
-	struct smscore_registry_entry_t *entry;
-
-	entry = smscore_find_registry(devpath);
-	if (entry)
-		return entry->mode;
-	else
-		sms_err("No registry found.");
-
-	return default_mode;
-}
-EXPORT_SYMBOL_GPL(smscore_registry_getmode);
-
-static enum sms_device_type_st smscore_registry_gettype(char *devpath)
-{
-	struct smscore_registry_entry_t *entry;
-
-	entry = smscore_find_registry(devpath);
-	if (entry)
-		return entry->type;
-	else
-		sms_err("No registry found.");
-
-	return -1;
-}
-
-void smscore_registry_setmode(char *devpath, int mode)
-{
-	struct smscore_registry_entry_t *entry;
-
-	entry = smscore_find_registry(devpath);
-	if (entry)
-		entry->mode = mode;
-	else
-		sms_err("No registry found.");
-}
-
-static void smscore_registry_settype(char *devpath,
-				     enum sms_device_type_st type)
-{
-	struct smscore_registry_entry_t *entry;
-
-	entry = smscore_find_registry(devpath);
-	if (entry)
-		entry->type = type;
-	else
-		sms_err("No registry found.");
-}
-
-
-static void list_add_locked(struct list_head *new, struct list_head *head,
-			    spinlock_t *lock)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(lock, flags);
-
-	list_add(new, head);
-
-	spin_unlock_irqrestore(lock, flags);
-}
-
-/**
- * register a client callback that called when device plugged in/unplugged
- * NOTE: if devices exist callback is called immediately for each device
- *
- * @param hotplug callback
- *
- * @return 0 on success, <0 on error.
- */
-int smscore_register_hotplug(hotplug_t hotplug)
-{
-	struct smscore_device_notifyee_t *notifyee;
-	struct list_head *next, *first;
-	int rc = 0;
-
-	kmutex_lock(&g_smscore_deviceslock);
-
-	notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
-			   GFP_KERNEL);
-	if (notifyee) {
-		/* now notify callback about existing devices */
-		first = &g_smscore_devices;
-		for (next = first->next;
-		     next != first && !rc;
-		     next = next->next) {
-			struct smscore_device_t *coredev =
-				(struct smscore_device_t *) next;
-			rc = hotplug(coredev, coredev->device, 1);
-		}
-
-		if (rc >= 0) {
-			notifyee->hotplug = hotplug;
-			list_add(&notifyee->entry, &g_smscore_notifyees);
-		} else
-			kfree(notifyee);
-	} else
-		rc = -ENOMEM;
-
-	kmutex_unlock(&g_smscore_deviceslock);
-
-	return rc;
-}
-EXPORT_SYMBOL_GPL(smscore_register_hotplug);
-
-/**
- * unregister a client callback that called when device plugged in/unplugged
- *
- * @param hotplug callback
- *
- */
-void smscore_unregister_hotplug(hotplug_t hotplug)
-{
-	struct list_head *next, *first;
-
-	kmutex_lock(&g_smscore_deviceslock);
-
-	first = &g_smscore_notifyees;
-
-	for (next = first->next; next != first;) {
-		struct smscore_device_notifyee_t *notifyee =
-			(struct smscore_device_notifyee_t *) next;
-		next = next->next;
-
-		if (notifyee->hotplug == hotplug) {
-			list_del(&notifyee->entry);
-			kfree(notifyee);
-		}
-	}
-
-	kmutex_unlock(&g_smscore_deviceslock);
-}
-EXPORT_SYMBOL_GPL(smscore_unregister_hotplug);
-
-static void smscore_notify_clients(struct smscore_device_t *coredev)
-{
-	struct smscore_client_t *client;
-
-	/* the client must call smscore_unregister_client from remove handler */
-	while (!list_empty(&coredev->clients)) {
-		client = (struct smscore_client_t *) coredev->clients.next;
-		client->onremove_handler(client->context);
-	}
-}
-
-static int smscore_notify_callbacks(struct smscore_device_t *coredev,
-				    struct device *device, int arrival)
-{
-	struct smscore_device_notifyee_t *elem;
-	int rc = 0;
-
-	/* note: must be called under g_deviceslock */
-
-	list_for_each_entry(elem, &g_smscore_notifyees, entry) {
-		rc = elem->hotplug(coredev, device, arrival);
-		if (rc < 0)
-			break;
-	}
-
-	return rc;
-}
-
-static struct
-smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
-				       dma_addr_t common_buffer_phys)
-{
-	struct smscore_buffer_t *cb =
-		kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
-	if (!cb) {
-		sms_info("kmalloc(...) failed");
-		return NULL;
-	}
-
-	cb->p = buffer;
-	cb->offset_in_common = buffer - (u8 *) common_buffer;
-	cb->phys = common_buffer_phys + cb->offset_in_common;
-
-	return cb;
-}
-
-/**
- * creates coredev object for a device, prepares buffers,
- * creates buffer mappings, notifies registered hotplugs about new device.
- *
- * @param params device pointer to struct with device specific parameters
- *               and handlers
- * @param coredev pointer to a value that receives created coredev object
- *
- * @return 0 on success, <0 on error.
- */
-int smscore_register_device(struct smsdevice_params_t *params,
-			    struct smscore_device_t **coredev)
-{
-	struct smscore_device_t *dev;
-	u8 *buffer;
-
-	dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
-	if (!dev) {
-		sms_info("kzalloc(...) failed");
-		return -ENOMEM;
-	}
-
-	/* init list entry so it could be safe in smscore_unregister_device */
-	INIT_LIST_HEAD(&dev->entry);
-
-	/* init queues */
-	INIT_LIST_HEAD(&dev->clients);
-	INIT_LIST_HEAD(&dev->buffers);
-
-	/* init locks */
-	spin_lock_init(&dev->clientslock);
-	spin_lock_init(&dev->bufferslock);
-
-	/* init completion events */
-	init_completion(&dev->version_ex_done);
-	init_completion(&dev->data_download_done);
-	init_completion(&dev->trigger_done);
-	init_completion(&dev->init_device_done);
-	init_completion(&dev->reload_start_done);
-	init_completion(&dev->resume_done);
-	init_completion(&dev->gpio_configuration_done);
-	init_completion(&dev->gpio_set_level_done);
-	init_completion(&dev->gpio_get_level_done);
-	init_completion(&dev->ir_init_done);
-
-	/* Buffer management */
-	init_waitqueue_head(&dev->buffer_mng_waitq);
-
-	/* alloc common buffer */
-	dev->common_buffer_size = params->buffer_size * params->num_buffers;
-	dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
-						&dev->common_buffer_phys,
-						GFP_KERNEL | GFP_DMA);
-	if (!dev->common_buffer) {
-		smscore_unregister_device(dev);
-		return -ENOMEM;
-	}
-
-	/* prepare dma buffers */
-	for (buffer = dev->common_buffer;
-	     dev->num_buffers < params->num_buffers;
-	     dev->num_buffers++, buffer += params->buffer_size) {
-		struct smscore_buffer_t *cb =
-			smscore_createbuffer(buffer, dev->common_buffer,
-					     dev->common_buffer_phys);
-		if (!cb) {
-			smscore_unregister_device(dev);
-			return -ENOMEM;
-		}
-
-		smscore_putbuffer(dev, cb);
-	}
-
-	sms_info("allocated %d buffers", dev->num_buffers);
-
-	dev->mode = DEVICE_MODE_NONE;
-	dev->context = params->context;
-	dev->device = params->device;
-	dev->setmode_handler = params->setmode_handler;
-	dev->detectmode_handler = params->detectmode_handler;
-	dev->sendrequest_handler = params->sendrequest_handler;
-	dev->preload_handler = params->preload_handler;
-	dev->postload_handler = params->postload_handler;
-
-	dev->device_flags = params->flags;
-	strcpy(dev->devpath, params->devpath);
-
-	smscore_registry_settype(dev->devpath, params->device_type);
-
-	/* add device to devices list */
-	kmutex_lock(&g_smscore_deviceslock);
-	list_add(&dev->entry, &g_smscore_devices);
-	kmutex_unlock(&g_smscore_deviceslock);
-
-	*coredev = dev;
-
-	sms_info("device %p created", dev);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(smscore_register_device);
-
-
-static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
-		void *buffer, size_t size, struct completion *completion) {
-	int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
-	if (rc < 0) {
-		sms_info("sendrequest returned error %d", rc);
-		return rc;
-	}
-
-	return wait_for_completion_timeout(completion,
-			msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ?
-			0 : -ETIME;
-}
-
-/**
- * Starts & enables IR operations
- *
- * @return 0 on success, < 0 on error.
- */
-static int smscore_init_ir(struct smscore_device_t *coredev)
-{
-	int ir_io;
-	int rc;
-	void *buffer;
-
-	coredev->ir.dev = NULL;
-	ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir;
-	if (ir_io) {/* only if IR port exist we use IR sub-module */
-		sms_info("IR loading");
-		rc = sms_ir_init(coredev);
-
-		if	(rc != 0)
-			sms_err("Error initialization DTV IR sub-module");
-		else {
-			buffer = kmalloc(sizeof(struct SmsMsgData_ST2) +
-						SMS_DMA_ALIGNMENT,
-						GFP_KERNEL | GFP_DMA);
-			if (buffer) {
-				struct SmsMsgData_ST2 *msg =
-				(struct SmsMsgData_ST2 *)
-				SMS_ALIGN_ADDRESS(buffer);
-
-				SMS_INIT_MSG(&msg->xMsgHeader,
-						MSG_SMS_START_IR_REQ,
-						sizeof(struct SmsMsgData_ST2));
-				msg->msgData[0] = coredev->ir.controller;
-				msg->msgData[1] = coredev->ir.timeout;
-
-				smsendian_handle_tx_message(
-					(struct SmsMsgHdr_ST2 *)msg);
-				rc = smscore_sendrequest_and_wait(coredev, msg,
-						msg->xMsgHeader. msgLength,
-						&coredev->ir_init_done);
-
-				kfree(buffer);
-			} else
-				sms_err
-				("Sending IR initialization message failed");
-		}
-	} else
-		sms_info("IR port has not been detected");
-
-	return 0;
-}
-
-/**
- * sets initial device mode and notifies client hotplugs that device is ready
- *
- * @param coredev pointer to a coredev object returned by
- * 		  smscore_register_device
- *
- * @return 0 on success, <0 on error.
- */
-int smscore_start_device(struct smscore_device_t *coredev)
-{
-	int rc = smscore_set_device_mode(
-			coredev, smscore_registry_getmode(coredev->devpath));
-	if (rc < 0) {
-		sms_info("set device mode faile , rc %d", rc);
-		return rc;
-	}
-
-	kmutex_lock(&g_smscore_deviceslock);
-
-	rc = smscore_notify_callbacks(coredev, coredev->device, 1);
-	smscore_init_ir(coredev);
-
-	sms_info("device %p started, rc %d", coredev, rc);
-
-	kmutex_unlock(&g_smscore_deviceslock);
-
-	return rc;
-}
-EXPORT_SYMBOL_GPL(smscore_start_device);
-
-
-static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
-					 void *buffer, size_t size)
-{
-	struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
-	struct SmsMsgHdr_ST *msg;
-	u32 mem_address;
-	u8 *payload = firmware->Payload;
-	int rc = 0;
-	firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
-	firmware->Length = le32_to_cpu(firmware->Length);
-
-	mem_address = firmware->StartAddress;
-
-	sms_info("loading FW to addr 0x%x size %d",
-		 mem_address, firmware->Length);
-	if (coredev->preload_handler) {
-		rc = coredev->preload_handler(coredev->context);
-		if (rc < 0)
-			return rc;
-	}
-
-	/* PAGE_SIZE buffer shall be enough and dma aligned */
-	msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
-	if (!msg)
-		return -ENOMEM;
-
-	if (coredev->mode != DEVICE_MODE_NONE) {
-		sms_debug("sending reload command.");
-		SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
-			     sizeof(struct SmsMsgHdr_ST));
-		rc = smscore_sendrequest_and_wait(coredev, msg,
-						  msg->msgLength,
-						  &coredev->reload_start_done);
-		mem_address = *(u32 *) &payload[20];
-	}
-
-	while (size && rc >= 0) {
-		struct SmsDataDownload_ST *DataMsg =
-			(struct SmsDataDownload_ST *) msg;
-		int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
-
-		SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
-			     (u16)(sizeof(struct SmsMsgHdr_ST) +
-				      sizeof(u32) + payload_size));
-
-		DataMsg->MemAddr = mem_address;
-		memcpy(DataMsg->Payload, payload, payload_size);
-
-		if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
-		    (coredev->mode == DEVICE_MODE_NONE))
-			rc = coredev->sendrequest_handler(
-				coredev->context, DataMsg,
-				DataMsg->xMsgHeader.msgLength);
-		else
-			rc = smscore_sendrequest_and_wait(
-				coredev, DataMsg,
-				DataMsg->xMsgHeader.msgLength,
-				&coredev->data_download_done);
-
-		payload += payload_size;
-		size -= payload_size;
-		mem_address += payload_size;
-	}
-
-	if (rc >= 0) {
-		if (coredev->mode == DEVICE_MODE_NONE) {
-			struct SmsMsgData_ST *TriggerMsg =
-				(struct SmsMsgData_ST *) msg;
-
-			SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
-				     sizeof(struct SmsMsgHdr_ST) +
-				     sizeof(u32) * 5);
-
-			TriggerMsg->msgData[0] = firmware->StartAddress;
-						/* Entry point */
-			TriggerMsg->msgData[1] = 5; /* Priority */
-			TriggerMsg->msgData[2] = 0x200; /* Stack size */
-			TriggerMsg->msgData[3] = 0; /* Parameter */
-			TriggerMsg->msgData[4] = 4; /* Task ID */
-
-			if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
-				rc = coredev->sendrequest_handler(
-					coredev->context, TriggerMsg,
-					TriggerMsg->xMsgHeader.msgLength);
-				msleep(100);
-			} else
-				rc = smscore_sendrequest_and_wait(
-					coredev, TriggerMsg,
-					TriggerMsg->xMsgHeader.msgLength,
-					&coredev->trigger_done);
-		} else {
-			SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
-				     sizeof(struct SmsMsgHdr_ST));
-
-			rc = coredev->sendrequest_handler(coredev->context,
-							  msg, msg->msgLength);
-		}
-		msleep(500);
-	}
-
-	sms_debug("rc=%d, postload=%p ", rc,
-		  coredev->postload_handler);
-
-	kfree(msg);
-
-	return ((rc >= 0) && coredev->postload_handler) ?
-		coredev->postload_handler(coredev->context) :
-		rc;
-}
-
-/**
- * loads specified firmware into a buffer and calls device loadfirmware_handler
- *
- * @param coredev pointer to a coredev object returned by
- *                smscore_register_device
- * @param filename null-terminated string specifies firmware file name
- * @param loadfirmware_handler device handler that loads firmware
- *
- * @return 0 on success, <0 on error.
- */
-static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
-					   char *filename,
-					   loadfirmware_t loadfirmware_handler)
-{
-	int rc = -ENOENT;
-	const struct firmware *fw;
-	u8 *fw_buffer;
-
-	if (loadfirmware_handler == NULL && !(coredev->device_flags &
-					      SMS_DEVICE_FAMILY2))
-		return -EINVAL;
-
-	rc = request_firmware(&fw, filename, coredev->device);
-	if (rc < 0) {
-		sms_info("failed to open \"%s\"", filename);
-		return rc;
-	}
-	sms_info("read FW %s, size=%zd", filename, fw->size);
-	fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
-			    GFP_KERNEL | GFP_DMA);
-	if (fw_buffer) {
-		memcpy(fw_buffer, fw->data, fw->size);
-
-		rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
-		      smscore_load_firmware_family2(coredev,
-						    fw_buffer,
-						    fw->size) :
-		      loadfirmware_handler(coredev->context,
-					   fw_buffer, fw->size);
-
-		kfree(fw_buffer);
-	} else {
-		sms_info("failed to allocate firmware buffer");
-		rc = -ENOMEM;
-	}
-
-	release_firmware(fw);
-
-	return rc;
-}
-
-/**
- * notifies all clients registered with the device, notifies hotplugs,
- * frees all buffers and coredev object
- *
- * @param coredev pointer to a coredev object returned by
- *                smscore_register_device
- *
- * @return 0 on success, <0 on error.
- */
-void smscore_unregister_device(struct smscore_device_t *coredev)
-{
-	struct smscore_buffer_t *cb;
-	int num_buffers = 0;
-	int retry = 0;
-
-	kmutex_lock(&g_smscore_deviceslock);
-
-	/* Release input device (IR) resources */
-	sms_ir_exit(coredev);
-
-	smscore_notify_clients(coredev);
-	smscore_notify_callbacks(coredev, NULL, 0);
-
-	/* at this point all buffers should be back
-	 * onresponse must no longer be called */
-
-	while (1) {
-		while (!list_empty(&coredev->buffers)) {
-			cb = (struct smscore_buffer_t *) coredev->buffers.next;
-			list_del(&cb->entry);
-			kfree(cb);
-			num_buffers++;
-		}
-		if (num_buffers == coredev->num_buffers)
-			break;
-		if (++retry > 10) {
-			sms_info("exiting although "
-				 "not all buffers released.");
-			break;
-		}
-
-		sms_info("waiting for %d buffer(s)",
-			 coredev->num_buffers - num_buffers);
-		msleep(100);
-	}
-
-	sms_info("freed %d buffers", num_buffers);
-
-	if (coredev->common_buffer)
-		dma_free_coherent(NULL, coredev->common_buffer_size,
-			coredev->common_buffer, coredev->common_buffer_phys);
-
-	if (coredev->fw_buf != NULL)
-		kfree(coredev->fw_buf);
-
-	list_del(&coredev->entry);
-	kfree(coredev);
-
-	kmutex_unlock(&g_smscore_deviceslock);
-
-	sms_info("device %p destroyed", coredev);
-}
-EXPORT_SYMBOL_GPL(smscore_unregister_device);
-
-static int smscore_detect_mode(struct smscore_device_t *coredev)
-{
-	void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
-			       GFP_KERNEL | GFP_DMA);
-	struct SmsMsgHdr_ST *msg =
-		(struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
-	int rc;
-
-	if (!buffer)
-		return -ENOMEM;
-
-	SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
-		     sizeof(struct SmsMsgHdr_ST));
-
-	rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
-					  &coredev->version_ex_done);
-	if (rc == -ETIME) {
-		sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
-
-		if (wait_for_completion_timeout(&coredev->resume_done,
-						msecs_to_jiffies(5000))) {
-			rc = smscore_sendrequest_and_wait(
-				coredev, msg, msg->msgLength,
-				&coredev->version_ex_done);
-			if (rc < 0)
-				sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
-					"second try, rc %d", rc);
-		} else
-			rc = -ETIME;
-	}
-
-	kfree(buffer);
-
-	return rc;
-}
-
-static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
-	/*Stellar		NOVA A0		Nova B0		VEGA*/
-	/*DVBT*/
-	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
-	/*DVBH*/
-	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
-	/*TDMB*/
-	{"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
-	/*DABIP*/
-	{"none", "none", "none", "none"},
-	/*BDA*/
-	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
-	/*ISDBT*/
-	{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
-	/*ISDBTBDA*/
-	{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
-	/*CMMB*/
-	{"none", "none", "none", "cmmb_vega_12mhz.inp"}
-};
-
-static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
-				    int mode, enum sms_device_type_st type)
-{
-	char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
-	return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
-}
-
-/**
- * calls device handler to change mode of operation
- * NOTE: stellar/usb may disconnect when changing mode
- *
- * @param coredev pointer to a coredev object returned by
- *                smscore_register_device
- * @param mode requested mode of operation
- *
- * @return 0 on success, <0 on error.
- */
-int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
-{
-	void *buffer;
-	int rc = 0;
-	enum sms_device_type_st type;
-
-	sms_debug("set device mode to %d", mode);
-	if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
-		if (mode < DEVICE_MODE_DVBT || mode >= DEVICE_MODE_RAW_TUNER) {
-			sms_err("invalid mode specified %d", mode);
-			return -EINVAL;
-		}
-
-		smscore_registry_setmode(coredev->devpath, mode);
-
-		if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
-			rc = smscore_detect_mode(coredev);
-			if (rc < 0) {
-				sms_err("mode detect failed %d", rc);
-				return rc;
-			}
-		}
-
-		if (coredev->mode == mode) {
-			sms_info("device mode %d already set", mode);
-			return 0;
-		}
-
-		if (!(coredev->modes_supported & (1 << mode))) {
-			char *fw_filename;
-
-			type = smscore_registry_gettype(coredev->devpath);
-			fw_filename = sms_get_fw_name(coredev, mode, type);
-
-			rc = smscore_load_firmware_from_file(coredev,
-							     fw_filename, NULL);
-			if (rc < 0) {
-				sms_warn("error %d loading firmware: %s, "
-					 "trying again with default firmware",
-					 rc, fw_filename);
-
-				/* try again with the default firmware */
-				fw_filename = smscore_fw_lkup[mode][type];
-				rc = smscore_load_firmware_from_file(coredev,
-							     fw_filename, NULL);
-
-				if (rc < 0) {
-					sms_warn("error %d loading "
-						 "firmware: %s", rc,
-						 fw_filename);
-					return rc;
-				}
-			}
-			sms_log("firmware download success: %s", fw_filename);
-		} else
-			sms_info("mode %d supported by running "
-				 "firmware", mode);
-
-		buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
-				 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
-		if (buffer) {
-			struct SmsMsgData_ST *msg =
-				(struct SmsMsgData_ST *)
-					SMS_ALIGN_ADDRESS(buffer);
-
-			SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
-				     sizeof(struct SmsMsgData_ST));
-			msg->msgData[0] = mode;
-
-			rc = smscore_sendrequest_and_wait(
-				coredev, msg, msg->xMsgHeader.msgLength,
-				&coredev->init_device_done);
-
-			kfree(buffer);
-		} else {
-			sms_err("Could not allocate buffer for "
-				"init device message.");
-			rc = -ENOMEM;
-		}
-	} else {
-		if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
-			sms_err("invalid mode specified %d", mode);
-			return -EINVAL;
-		}
-
-		smscore_registry_setmode(coredev->devpath, mode);
-
-		if (coredev->detectmode_handler)
-			coredev->detectmode_handler(coredev->context,
-						    &coredev->mode);
-
-		if (coredev->mode != mode && coredev->setmode_handler)
-			rc = coredev->setmode_handler(coredev->context, mode);
-	}
-
-	if (rc >= 0) {
-		coredev->mode = mode;
-		coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
-	}
-
-	if (rc < 0)
-		sms_err("return error code %d.", rc);
-	return rc;
-}
-
-/**
- * calls device handler to get current mode of operation
- *
- * @param coredev pointer to a coredev object returned by
- *                smscore_register_device
- *
- * @return current mode
- */
-int smscore_get_device_mode(struct smscore_device_t *coredev)
-{
-	return coredev->mode;
-}
-EXPORT_SYMBOL_GPL(smscore_get_device_mode);
-
-/**
- * find client by response id & type within the clients list.
- * return client handle or NULL.
- *
- * @param coredev pointer to a coredev object returned by
- *                smscore_register_device
- * @param data_type client data type (SMS_DONT_CARE for all types)
- * @param id client id (SMS_DONT_CARE for all id)
- *
- */
-static struct
-smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
-				      int data_type, int id)
-{
-	struct list_head *first;
-	struct smscore_client_t *client;
-	unsigned long flags;
-	struct list_head *firstid;
-	struct smscore_idlist_t *client_id;
-
-	spin_lock_irqsave(&coredev->clientslock, flags);
-	first = &coredev->clients;
-	list_for_each_entry(client, first, entry) {
-		firstid = &client->idlist;
-		list_for_each_entry(client_id, firstid, entry) {
-			if ((client_id->id == id) &&
-			    (client_id->data_type == data_type ||
-			    (client_id->data_type == 0)))
-				goto found;
-		}
-	}
-	client = NULL;
-found:
-	spin_unlock_irqrestore(&coredev->clientslock, flags);
-	return client;
-}
-
-/**
- * find client by response id/type, call clients onresponse handler
- * return buffer to pool on error
- *
- * @param coredev pointer to a coredev object returned by
- *                smscore_register_device
- * @param cb pointer to response buffer descriptor
- *
- */
-void smscore_onresponse(struct smscore_device_t *coredev,
-		struct smscore_buffer_t *cb) {
-	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p
-			+ cb->offset);
-	struct smscore_client_t *client;
-	int rc = -EBUSY;
-	static unsigned long last_sample_time; /* = 0; */
-	static int data_total; /* = 0; */
-	unsigned long time_now = jiffies_to_msecs(jiffies);
-
-	if (!last_sample_time)
-		last_sample_time = time_now;
-
-	if (time_now - last_sample_time > 10000) {
-		sms_debug("\ndata rate %d bytes/secs",
-			  (int)((data_total * 1000) /
-				(time_now - last_sample_time)));
-
-		last_sample_time = time_now;
-		data_total = 0;
-	}
-
-	data_total += cb->size;
-	/* Do we need to re-route? */
-	if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) ||
-			(phdr->msgType == MSG_SMS_TRANSMISSION_IND)) {
-		if (coredev->mode == DEVICE_MODE_DVBT_BDA)
-			phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID;
-	}
-
-
-	client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
-
-	/* If no client registered for type & id,
-	 * check for control client where type is not registered */
-	if (client)
-		rc = client->onresponse_handler(client->context, cb);
-
-	if (rc < 0) {
-		switch (phdr->msgType) {
-		case MSG_SMS_GET_VERSION_EX_RES:
-		{
-			struct SmsVersionRes_ST *ver =
-				(struct SmsVersionRes_ST *) phdr;
-			sms_debug("MSG_SMS_GET_VERSION_EX_RES "
-				  "id %d prots 0x%x ver %d.%d",
-				  ver->FirmwareId, ver->SupportedProtocols,
-				  ver->RomVersionMajor, ver->RomVersionMinor);
-
-			coredev->mode = ver->FirmwareId == 255 ?
-				DEVICE_MODE_NONE : ver->FirmwareId;
-			coredev->modes_supported = ver->SupportedProtocols;
-
-			complete(&coredev->version_ex_done);
-			break;
-		}
-		case MSG_SMS_INIT_DEVICE_RES:
-			sms_debug("MSG_SMS_INIT_DEVICE_RES");
-			complete(&coredev->init_device_done);
-			break;
-		case MSG_SW_RELOAD_START_RES:
-			sms_debug("MSG_SW_RELOAD_START_RES");
-			complete(&coredev->reload_start_done);
-			break;
-		case MSG_SMS_DATA_DOWNLOAD_RES:
-			complete(&coredev->data_download_done);
-			break;
-		case MSG_SW_RELOAD_EXEC_RES:
-			sms_debug("MSG_SW_RELOAD_EXEC_RES");
-			break;
-		case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
-			sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
-			complete(&coredev->trigger_done);
-			break;
-		case MSG_SMS_SLEEP_RESUME_COMP_IND:
-			complete(&coredev->resume_done);
-			break;
-		case MSG_SMS_GPIO_CONFIG_EX_RES:
-			sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES");
-			complete(&coredev->gpio_configuration_done);
-			break;
-		case MSG_SMS_GPIO_SET_LEVEL_RES:
-			sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES");
-			complete(&coredev->gpio_set_level_done);
-			break;
-		case MSG_SMS_GPIO_GET_LEVEL_RES:
-		{
-			u32 *msgdata = (u32 *) phdr;
-			coredev->gpio_get_res = msgdata[1];
-			sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d",
-					coredev->gpio_get_res);
-			complete(&coredev->gpio_get_level_done);
-			break;
-		}
-		case MSG_SMS_START_IR_RES:
-			complete(&coredev->ir_init_done);
-			break;
-		case MSG_SMS_IR_SAMPLES_IND:
-			sms_ir_event(coredev,
-				(const char *)
-				((char *)phdr
-				+ sizeof(struct SmsMsgHdr_ST)),
-				(int)phdr->msgLength
-				- sizeof(struct SmsMsgHdr_ST));
-			break;
-
-		default:
-			break;
-		}
-		smscore_putbuffer(coredev, cb);
-	}
-}
-EXPORT_SYMBOL_GPL(smscore_onresponse);
-
-/**
- * return pointer to next free buffer descriptor from core pool
- *
- * @param coredev pointer to a coredev object returned by
- *                smscore_register_device
- *
- * @return pointer to descriptor on success, NULL on error.
- */
-
-struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev)
-{
-	struct smscore_buffer_t *cb = NULL;
-	unsigned long flags;
-
-	spin_lock_irqsave(&coredev->bufferslock, flags);
-	if (!list_empty(&coredev->buffers)) {
-		cb = (struct smscore_buffer_t *) coredev->buffers.next;
-		list_del(&cb->entry);
-	}
-	spin_unlock_irqrestore(&coredev->bufferslock, flags);
-	return cb;
-}
-
-struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
-{
-	struct smscore_buffer_t *cb = NULL;
-
-	wait_event(coredev->buffer_mng_waitq, (cb = get_entry(coredev)));
-
-	return cb;
-}
-EXPORT_SYMBOL_GPL(smscore_getbuffer);
-
-/**
- * return buffer descriptor to a pool
- *
- * @param coredev pointer to a coredev object returned by
- *                smscore_register_device
- * @param cb pointer buffer descriptor
- *
- */
-void smscore_putbuffer(struct smscore_device_t *coredev,
-		struct smscore_buffer_t *cb) {
-	wake_up_interruptible(&coredev->buffer_mng_waitq);
-	list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
-}
-EXPORT_SYMBOL_GPL(smscore_putbuffer);
-
-static int smscore_validate_client(struct smscore_device_t *coredev,
-				   struct smscore_client_t *client,
-				   int data_type, int id)
-{
-	struct smscore_idlist_t *listentry;
-	struct smscore_client_t *registered_client;
-
-	if (!client) {
-		sms_err("bad parameter.");
-		return -EINVAL;
-	}
-	registered_client = smscore_find_client(coredev, data_type, id);
-	if (registered_client == client)
-		return 0;
-
-	if (registered_client) {
-		sms_err("The msg ID already registered to another client.");
-		return -EEXIST;
-	}
-	listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
-	if (!listentry) {
-		sms_err("Can't allocate memory for client id.");
-		return -ENOMEM;
-	}
-	listentry->id = id;
-	listentry->data_type = data_type;
-	list_add_locked(&listentry->entry, &client->idlist,
-			&coredev->clientslock);
-	return 0;
-}
-
-/**
- * creates smsclient object, check that id is taken by another client
- *
- * @param coredev pointer to a coredev object from clients hotplug
- * @param initial_id all messages with this id would be sent to this client
- * @param data_type all messages of this type would be sent to this client
- * @param onresponse_handler client handler that is called to
- *                           process incoming messages
- * @param onremove_handler client handler that is called when device is removed
- * @param context client-specific context
- * @param client pointer to a value that receives created smsclient object
- *
- * @return 0 on success, <0 on error.
- */
-int smscore_register_client(struct smscore_device_t *coredev,
-			    struct smsclient_params_t *params,
-			    struct smscore_client_t **client)
-{
-	struct smscore_client_t *newclient;
-	/* check that no other channel with same parameters exists */
-	if (smscore_find_client(coredev, params->data_type,
-				params->initial_id)) {
-		sms_err("Client already exist.");
-		return -EEXIST;
-	}
-
-	newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
-	if (!newclient) {
-		sms_err("Failed to allocate memory for client.");
-		return -ENOMEM;
-	}
-
-	INIT_LIST_HEAD(&newclient->idlist);
-	newclient->coredev = coredev;
-	newclient->onresponse_handler = params->onresponse_handler;
-	newclient->onremove_handler = params->onremove_handler;
-	newclient->context = params->context;
-	list_add_locked(&newclient->entry, &coredev->clients,
-			&coredev->clientslock);
-	smscore_validate_client(coredev, newclient, params->data_type,
-				params->initial_id);
-	*client = newclient;
-	sms_debug("%p %d %d", params->context, params->data_type,
-		  params->initial_id);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(smscore_register_client);
-
-/**
- * frees smsclient object and all subclients associated with it
- *
- * @param client pointer to smsclient object returned by
- *               smscore_register_client
- *
- */
-void smscore_unregister_client(struct smscore_client_t *client)
-{
-	struct smscore_device_t *coredev = client->coredev;
-	unsigned long flags;
-
-	spin_lock_irqsave(&coredev->clientslock, flags);
-
-
-	while (!list_empty(&client->idlist)) {
-		struct smscore_idlist_t *identry =
-			(struct smscore_idlist_t *) client->idlist.next;
-		list_del(&identry->entry);
-		kfree(identry);
-	}
-
-	sms_info("%p", client->context);
-
-	list_del(&client->entry);
-	kfree(client);
-
-	spin_unlock_irqrestore(&coredev->clientslock, flags);
-}
-EXPORT_SYMBOL_GPL(smscore_unregister_client);
-
-/**
- * verifies that source id is not taken by another client,
- * calls device handler to send requests to the device
- *
- * @param client pointer to smsclient object returned by
- *               smscore_register_client
- * @param buffer pointer to a request buffer
- * @param size size (in bytes) of request buffer
- *
- * @return 0 on success, <0 on error.
- */
-int smsclient_sendrequest(struct smscore_client_t *client,
-			  void *buffer, size_t size)
-{
-	struct smscore_device_t *coredev;
-	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
-	int rc;
-
-	if (client == NULL) {
-		sms_err("Got NULL client");
-		return -EINVAL;
-	}
-
-	coredev = client->coredev;
-
-	/* check that no other channel with same id exists */
-	if (coredev == NULL) {
-		sms_err("Got NULL coredev");
-		return -EINVAL;
-	}
-
-	rc = smscore_validate_client(client->coredev, client, 0,
-				     phdr->msgSrcId);
-	if (rc < 0)
-		return rc;
-
-	return coredev->sendrequest_handler(coredev->context, buffer, size);
-}
-EXPORT_SYMBOL_GPL(smsclient_sendrequest);
-
-
-/* old GPIO managements implementation */
-int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
-			   struct smscore_config_gpio *pinconfig)
-{
-	struct {
-		struct SmsMsgHdr_ST hdr;
-		u32 data[6];
-	} msg;
-
-	if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
-		msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
-		msg.hdr.msgDstId = HIF_TASK;
-		msg.hdr.msgFlags = 0;
-		msg.hdr.msgType  = MSG_SMS_GPIO_CONFIG_EX_REQ;
-		msg.hdr.msgLength = sizeof(msg);
-
-		msg.data[0] = pin;
-		msg.data[1] = pinconfig->pullupdown;
-
-		/* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */
-		msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0;
-
-		switch (pinconfig->outputdriving) {
-		case SMS_GPIO_OUTPUTDRIVING_16mA:
-			msg.data[3] = 7; /* Nova - 16mA */
-			break;
-		case SMS_GPIO_OUTPUTDRIVING_12mA:
-			msg.data[3] = 5; /* Nova - 11mA */
-			break;
-		case SMS_GPIO_OUTPUTDRIVING_8mA:
-			msg.data[3] = 3; /* Nova - 7mA */
-			break;
-		case SMS_GPIO_OUTPUTDRIVING_4mA:
-		default:
-			msg.data[3] = 2; /* Nova - 4mA */
-			break;
-		}
-
-		msg.data[4] = pinconfig->direction;
-		msg.data[5] = 0;
-	} else /* TODO: SMS_DEVICE_FAMILY1 */
-		return -EINVAL;
-
-	return coredev->sendrequest_handler(coredev->context,
-					    &msg, sizeof(msg));
-}
-
-int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
-{
-	struct {
-		struct SmsMsgHdr_ST hdr;
-		u32 data[3];
-	} msg;
-
-	if (pin > MAX_GPIO_PIN_NUMBER)
-		return -EINVAL;
-
-	msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
-	msg.hdr.msgDstId = HIF_TASK;
-	msg.hdr.msgFlags = 0;
-	msg.hdr.msgType  = MSG_SMS_GPIO_SET_LEVEL_REQ;
-	msg.hdr.msgLength = sizeof(msg);
-
-	msg.data[0] = pin;
-	msg.data[1] = level ? 1 : 0;
-	msg.data[2] = 0;
-
-	return coredev->sendrequest_handler(coredev->context,
-					    &msg, sizeof(msg));
-}
-
-/* new GPIO management implementation */
-static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
-		u32 *pGroupNum, u32 *pGroupCfg) {
-
-	*pGroupCfg = 1;
-
-	if (PinNum <= 1)	{
-		*pTranslatedPinNum = 0;
-		*pGroupNum = 9;
-		*pGroupCfg = 2;
-	} else if (PinNum >= 2 && PinNum <= 6) {
-		*pTranslatedPinNum = 2;
-		*pGroupNum = 0;
-		*pGroupCfg = 2;
-	} else if (PinNum >= 7 && PinNum <= 11) {
-		*pTranslatedPinNum = 7;
-		*pGroupNum = 1;
-	} else if (PinNum >= 12 && PinNum <= 15) {
-		*pTranslatedPinNum = 12;
-		*pGroupNum = 2;
-		*pGroupCfg = 3;
-	} else if (PinNum == 16) {
-		*pTranslatedPinNum = 16;
-		*pGroupNum = 23;
-	} else if (PinNum >= 17 && PinNum <= 24) {
-		*pTranslatedPinNum = 17;
-		*pGroupNum = 3;
-	} else if (PinNum == 25) {
-		*pTranslatedPinNum = 25;
-		*pGroupNum = 6;
-	} else if (PinNum >= 26 && PinNum <= 28) {
-		*pTranslatedPinNum = 26;
-		*pGroupNum = 4;
-	} else if (PinNum == 29) {
-		*pTranslatedPinNum = 29;
-		*pGroupNum = 5;
-		*pGroupCfg = 2;
-	} else if (PinNum == 30) {
-		*pTranslatedPinNum = 30;
-		*pGroupNum = 8;
-	} else if (PinNum == 31) {
-		*pTranslatedPinNum = 31;
-		*pGroupNum = 17;
-	} else
-		return -1;
-
-	*pGroupCfg <<= 24;
-
-	return 0;
-}
-
-int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
-		struct smscore_gpio_config *pGpioConfig) {
-
-	u32 totalLen;
-	u32 TranslatedPinNum = 0;
-	u32 GroupNum = 0;
-	u32 ElectricChar;
-	u32 groupCfg;
-	void *buffer;
-	int rc;
-
-	struct SetGpioMsg {
-		struct SmsMsgHdr_ST xMsgHeader;
-		u32 msgData[6];
-	} *pMsg;
-
-
-	if (PinNum > MAX_GPIO_PIN_NUMBER)
-		return -EINVAL;
-
-	if (pGpioConfig == NULL)
-		return -EINVAL;
-
-	totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6);
-
-	buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
-			GFP_KERNEL | GFP_DMA);
-	if (!buffer)
-		return -ENOMEM;
-
-	pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
-
-	pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
-	pMsg->xMsgHeader.msgDstId = HIF_TASK;
-	pMsg->xMsgHeader.msgFlags = 0;
-	pMsg->xMsgHeader.msgLength = (u16) totalLen;
-	pMsg->msgData[0] = PinNum;
-
-	if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
-		pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
-		if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
-				&groupCfg) != 0) {
-			rc = -EINVAL;
-			goto free;
-		}
-
-		pMsg->msgData[1] = TranslatedPinNum;
-		pMsg->msgData[2] = GroupNum;
-		ElectricChar = (pGpioConfig->PullUpDown)
-				| (pGpioConfig->InputCharacteristics << 2)
-				| (pGpioConfig->OutputSlewRate << 3)
-				| (pGpioConfig->OutputDriving << 4);
-		pMsg->msgData[3] = ElectricChar;
-		pMsg->msgData[4] = pGpioConfig->Direction;
-		pMsg->msgData[5] = groupCfg;
-	} else {
-		pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
-		pMsg->msgData[1] = pGpioConfig->PullUpDown;
-		pMsg->msgData[2] = pGpioConfig->OutputSlewRate;
-		pMsg->msgData[3] = pGpioConfig->OutputDriving;
-		pMsg->msgData[4] = pGpioConfig->Direction;
-		pMsg->msgData[5] = 0;
-	}
-
-	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
-	rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
-			&coredev->gpio_configuration_done);
-
-	if (rc != 0) {
-		if (rc == -ETIME)
-			sms_err("smscore_gpio_configure timeout");
-		else
-			sms_err("smscore_gpio_configure error");
-	}
-free:
-	kfree(buffer);
-
-	return rc;
-}
-
-int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
-		u8 NewLevel) {
-
-	u32 totalLen;
-	int rc;
-	void *buffer;
-
-	struct SetGpioMsg {
-		struct SmsMsgHdr_ST xMsgHeader;
-		u32 msgData[3]; /* keep it 3 ! */
-	} *pMsg;
-
-	if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER))
-		return -EINVAL;
-
-	totalLen = sizeof(struct SmsMsgHdr_ST) +
-			(3 * sizeof(u32)); /* keep it 3 ! */
-
-	buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
-			GFP_KERNEL | GFP_DMA);
-	if (!buffer)
-		return -ENOMEM;
-
-	pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
-
-	pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
-	pMsg->xMsgHeader.msgDstId = HIF_TASK;
-	pMsg->xMsgHeader.msgFlags = 0;
-	pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
-	pMsg->xMsgHeader.msgLength = (u16) totalLen;
-	pMsg->msgData[0] = PinNum;
-	pMsg->msgData[1] = NewLevel;
-
-	/* Send message to SMS */
-	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
-	rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
-			&coredev->gpio_set_level_done);
-
-	if (rc != 0) {
-		if (rc == -ETIME)
-			sms_err("smscore_gpio_set_level timeout");
-		else
-			sms_err("smscore_gpio_set_level error");
-	}
-	kfree(buffer);
-
-	return rc;
-}
-
-int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
-		u8 *level) {
-
-	u32 totalLen;
-	int rc;
-	void *buffer;
-
-	struct SetGpioMsg {
-		struct SmsMsgHdr_ST xMsgHeader;
-		u32 msgData[2];
-	} *pMsg;
-
-
-	if (PinNum > MAX_GPIO_PIN_NUMBER)
-		return -EINVAL;
-
-	totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32));
-
-	buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
-			GFP_KERNEL | GFP_DMA);
-	if (!buffer)
-		return -ENOMEM;
-
-	pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
-
-	pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
-	pMsg->xMsgHeader.msgDstId = HIF_TASK;
-	pMsg->xMsgHeader.msgFlags = 0;
-	pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ;
-	pMsg->xMsgHeader.msgLength = (u16) totalLen;
-	pMsg->msgData[0] = PinNum;
-	pMsg->msgData[1] = 0;
-
-	/* Send message to SMS */
-	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
-	rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
-			&coredev->gpio_get_level_done);
-
-	if (rc != 0) {
-		if (rc == -ETIME)
-			sms_err("smscore_gpio_get_level timeout");
-		else
-			sms_err("smscore_gpio_get_level error");
-	}
-	kfree(buffer);
-
-	/* Its a race between other gpio_get_level() and the copy of the single
-	 * global 'coredev->gpio_get_res' to  the function's variable 'level'
-	 */
-	*level = coredev->gpio_get_res;
-
-	return rc;
-}
-
-static int __init smscore_module_init(void)
-{
-	int rc = 0;
-
-	INIT_LIST_HEAD(&g_smscore_notifyees);
-	INIT_LIST_HEAD(&g_smscore_devices);
-	kmutex_init(&g_smscore_deviceslock);
-
-	INIT_LIST_HEAD(&g_smscore_registry);
-	kmutex_init(&g_smscore_registrylock);
-
-	return rc;
-}
-
-static void __exit smscore_module_exit(void)
-{
-	kmutex_lock(&g_smscore_deviceslock);
-	while (!list_empty(&g_smscore_notifyees)) {
-		struct smscore_device_notifyee_t *notifyee =
-			(struct smscore_device_notifyee_t *)
-				g_smscore_notifyees.next;
-
-		list_del(&notifyee->entry);
-		kfree(notifyee);
-	}
-	kmutex_unlock(&g_smscore_deviceslock);
-
-	kmutex_lock(&g_smscore_registrylock);
-	while (!list_empty(&g_smscore_registry)) {
-		struct smscore_registry_entry_t *entry =
-			(struct smscore_registry_entry_t *)
-				g_smscore_registry.next;
-
-		list_del(&entry->entry);
-		kfree(entry);
-	}
-	kmutex_unlock(&g_smscore_registrylock);
-
-	sms_debug("");
-}
-
-module_init(smscore_module_init);
-module_exit(smscore_module_exit);
-
-MODULE_DESCRIPTION("Siano MDTV Core module");
-MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h
deleted file mode 100644
index c592ae0..0000000
--- a/drivers/media/dvb/siano/smscoreapi.h
+++ /dev/null
@@ -1,775 +0,0 @@
-/****************************************************************
-
-Siano Mobile Silicon, Inc.
-MDTV receiver kernel modules.
-Copyright (C) 2006-2008, Uri Shkolnik, Anatoly Greenblat
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 2 of the License, or
-(at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-****************************************************************/
-
-#ifndef __SMS_CORE_API_H__
-#define __SMS_CORE_API_H__
-
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/scatterlist.h>
-#include <linux/types.h>
-#include <linux/mutex.h>
-#include <linux/wait.h>
-#include <linux/timer.h>
-
-#include <asm/page.h>
-
-#include "smsir.h"
-
-#define kmutex_init(_p_) mutex_init(_p_)
-#define kmutex_lock(_p_) mutex_lock(_p_)
-#define kmutex_trylock(_p_) mutex_trylock(_p_)
-#define kmutex_unlock(_p_) mutex_unlock(_p_)
-
-#ifndef min
-#define min(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-
-#define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS			(10000)
-#define SMS_ALLOC_ALIGNMENT				128
-#define SMS_DMA_ALIGNMENT				16
-#define SMS_ALIGN_ADDRESS(addr) \
-	((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1))
-
-#define SMS_DEVICE_FAMILY2				1
-#define SMS_ROM_NO_RESPONSE				2
-#define SMS_DEVICE_NOT_READY				0x8000000
-
-enum sms_device_type_st {
-	SMS_STELLAR = 0,
-	SMS_NOVA_A0,
-	SMS_NOVA_B0,
-	SMS_VEGA,
-	SMS_NUM_OF_DEVICE_TYPES
-};
-
-struct smscore_device_t;
-struct smscore_client_t;
-struct smscore_buffer_t;
-
-typedef int (*hotplug_t)(struct smscore_device_t *coredev,
-			 struct device *device, int arrival);
-
-typedef int (*setmode_t)(void *context, int mode);
-typedef void (*detectmode_t)(void *context, int *mode);
-typedef int (*sendrequest_t)(void *context, void *buffer, size_t size);
-typedef int (*loadfirmware_t)(void *context, void *buffer, size_t size);
-typedef int (*preload_t)(void *context);
-typedef int (*postload_t)(void *context);
-
-typedef int (*onresponse_t)(void *context, struct smscore_buffer_t *cb);
-typedef void (*onremove_t)(void *context);
-
-struct smscore_buffer_t {
-	/* public members, once passed to clients can be changed freely */
-	struct list_head entry;
-	int size;
-	int offset;
-
-	/* private members, read-only for clients */
-	void *p;
-	dma_addr_t phys;
-	unsigned long offset_in_common;
-};
-
-struct smsdevice_params_t {
-	struct device	*device;
-
-	int				buffer_size;
-	int				num_buffers;
-
-	char			devpath[32];
-	unsigned long	flags;
-
-	setmode_t		setmode_handler;
-	detectmode_t	detectmode_handler;
-	sendrequest_t	sendrequest_handler;
-	preload_t		preload_handler;
-	postload_t		postload_handler;
-
-	void			*context;
-	enum sms_device_type_st device_type;
-};
-
-struct smsclient_params_t {
-	int				initial_id;
-	int				data_type;
-	onresponse_t	onresponse_handler;
-	onremove_t		onremove_handler;
-	void			*context;
-};
-
-struct smscore_device_t {
-	struct list_head entry;
-
-	struct list_head clients;
-	struct list_head subclients;
-	spinlock_t clientslock;
-
-	struct list_head buffers;
-	spinlock_t bufferslock;
-	int num_buffers;
-
-	void *common_buffer;
-	int common_buffer_size;
-	dma_addr_t common_buffer_phys;
-
-	void *context;
-	struct device *device;
-
-	char devpath[32];
-	unsigned long device_flags;
-
-	setmode_t setmode_handler;
-	detectmode_t detectmode_handler;
-	sendrequest_t sendrequest_handler;
-	preload_t preload_handler;
-	postload_t postload_handler;
-
-	int mode, modes_supported;
-
-	/* host <--> device messages */
-	struct completion version_ex_done, data_download_done, trigger_done;
-	struct completion init_device_done, reload_start_done, resume_done;
-	struct completion gpio_configuration_done, gpio_set_level_done;
-	struct completion gpio_get_level_done, ir_init_done;
-
-	/* Buffer management */
-	wait_queue_head_t buffer_mng_waitq;
-
-	/* GPIO */
-	int gpio_get_res;
-
-	/* Target hardware board */
-	int board_id;
-
-	/* Firmware */
-	u8 *fw_buf;
-	u32 fw_buf_size;
-
-	/* Infrared (IR) */
-	struct ir_t ir;
-
-	int led_state;
-};
-
-/* GPIO definitions for antenna frequency domain control (SMS8021) */
-#define SMS_ANTENNA_GPIO_0					1
-#define SMS_ANTENNA_GPIO_1					0
-
-#define BW_8_MHZ							0
-#define BW_7_MHZ							1
-#define BW_6_MHZ							2
-#define BW_5_MHZ							3
-#define BW_ISDBT_1SEG						4
-#define BW_ISDBT_3SEG						5
-
-#define MSG_HDR_FLAG_SPLIT_MSG				4
-
-#define MAX_GPIO_PIN_NUMBER					31
-
-#define HIF_TASK							11
-#define SMS_HOST_LIB						150
-#define DVBT_BDA_CONTROL_MSG_ID				201
-
-#define SMS_MAX_PAYLOAD_SIZE				240
-#define SMS_TUNE_TIMEOUT					500
-
-#define MSG_SMS_GPIO_CONFIG_REQ				507
-#define MSG_SMS_GPIO_CONFIG_RES				508
-#define MSG_SMS_GPIO_SET_LEVEL_REQ			509
-#define MSG_SMS_GPIO_SET_LEVEL_RES			510
-#define MSG_SMS_GPIO_GET_LEVEL_REQ			511
-#define MSG_SMS_GPIO_GET_LEVEL_RES			512
-#define MSG_SMS_RF_TUNE_REQ					561
-#define MSG_SMS_RF_TUNE_RES					562
-#define MSG_SMS_INIT_DEVICE_REQ				578
-#define MSG_SMS_INIT_DEVICE_RES				579
-#define MSG_SMS_ADD_PID_FILTER_REQ			601
-#define MSG_SMS_ADD_PID_FILTER_RES			602
-#define MSG_SMS_REMOVE_PID_FILTER_REQ			603
-#define MSG_SMS_REMOVE_PID_FILTER_RES			604
-#define MSG_SMS_DAB_CHANNEL				607
-#define MSG_SMS_GET_PID_FILTER_LIST_REQ			608
-#define MSG_SMS_GET_PID_FILTER_LIST_RES			609
-#define MSG_SMS_GET_STATISTICS_RES			616
-#define MSG_SMS_GET_STATISTICS_REQ			615
-#define MSG_SMS_HO_PER_SLICES_IND			630
-#define MSG_SMS_SET_ANTENNA_CONFIG_REQ			651
-#define MSG_SMS_SET_ANTENNA_CONFIG_RES			652
-#define MSG_SMS_SLEEP_RESUME_COMP_IND			655
-#define MSG_SMS_DATA_DOWNLOAD_REQ			660
-#define MSG_SMS_DATA_DOWNLOAD_RES			661
-#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ		664
-#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES		665
-#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ		666
-#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES		667
-#define MSG_SMS_GET_VERSION_EX_REQ			668
-#define MSG_SMS_GET_VERSION_EX_RES			669
-#define MSG_SMS_SET_CLOCK_OUTPUT_REQ		670
-#define MSG_SMS_I2C_SET_FREQ_REQ			685
-#define MSG_SMS_GENERIC_I2C_REQ				687
-#define MSG_SMS_GENERIC_I2C_RES				688
-#define MSG_SMS_DVBT_BDA_DATA				693
-#define MSG_SW_RELOAD_REQ					697
-#define MSG_SMS_DATA_MSG					699
-#define MSG_SW_RELOAD_START_REQ				702
-#define MSG_SW_RELOAD_START_RES				703
-#define MSG_SW_RELOAD_EXEC_REQ				704
-#define MSG_SW_RELOAD_EXEC_RES				705
-#define MSG_SMS_SPI_INT_LINE_SET_REQ		710
-#define MSG_SMS_GPIO_CONFIG_EX_REQ			712
-#define MSG_SMS_GPIO_CONFIG_EX_RES			713
-#define MSG_SMS_ISDBT_TUNE_REQ				776
-#define MSG_SMS_ISDBT_TUNE_RES				777
-#define MSG_SMS_TRANSMISSION_IND			782
-#define MSG_SMS_START_IR_REQ				800
-#define MSG_SMS_START_IR_RES				801
-#define MSG_SMS_IR_SAMPLES_IND				802
-#define MSG_SMS_SIGNAL_DETECTED_IND			827
-#define MSG_SMS_NO_SIGNAL_IND				828
-
-#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \
-	(ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \
-	(ptr)->msgLength = len; (ptr)->msgFlags = 0; \
-} while (0)
-
-#define SMS_INIT_MSG(ptr, type, len) \
-	SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len)
-
-enum SMS_DVB3_EVENTS {
-	DVB3_EVENT_INIT = 0,
-	DVB3_EVENT_SLEEP,
-	DVB3_EVENT_HOTPLUG,
-	DVB3_EVENT_FE_LOCK,
-	DVB3_EVENT_FE_UNLOCK,
-	DVB3_EVENT_UNC_OK,
-	DVB3_EVENT_UNC_ERR
-};
-
-enum SMS_DEVICE_MODE {
-	DEVICE_MODE_NONE = -1,
-	DEVICE_MODE_DVBT = 0,
-	DEVICE_MODE_DVBH,
-	DEVICE_MODE_DAB_TDMB,
-	DEVICE_MODE_DAB_TDMB_DABIP,
-	DEVICE_MODE_DVBT_BDA,
-	DEVICE_MODE_ISDBT,
-	DEVICE_MODE_ISDBT_BDA,
-	DEVICE_MODE_CMMB,
-	DEVICE_MODE_RAW_TUNER,
-	DEVICE_MODE_MAX,
-};
-
-struct SmsMsgHdr_ST {
-	u16	msgType;
-	u8	msgSrcId;
-	u8	msgDstId;
-	u16	msgLength; /* Length of entire message, including header */
-	u16	msgFlags;
-};
-
-struct SmsMsgData_ST {
-	struct SmsMsgHdr_ST xMsgHeader;
-	u32 msgData[1];
-};
-
-struct SmsMsgData_ST2 {
-	struct SmsMsgHdr_ST xMsgHeader;
-	u32 msgData[2];
-};
-
-struct SmsDataDownload_ST {
-	struct SmsMsgHdr_ST	xMsgHeader;
-	u32			MemAddr;
-	u8			Payload[SMS_MAX_PAYLOAD_SIZE];
-};
-
-struct SmsVersionRes_ST {
-	struct SmsMsgHdr_ST	xMsgHeader;
-
-	u16		ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */
-	u8		Step; /* 0 - Step A */
-	u8		MetalFix; /* 0 - Metal 0 */
-
-	/* FirmwareId 0xFF if ROM, otherwise the
-	 * value indicated by SMSHOSTLIB_DEVICE_MODES_E */
-	u8 FirmwareId;
-	/* SupportedProtocols Bitwise OR combination of
-					     * supported protocols */
-	u8 SupportedProtocols;
-
-	u8		VersionMajor;
-	u8		VersionMinor;
-	u8		VersionPatch;
-	u8		VersionFieldPatch;
-
-	u8		RomVersionMajor;
-	u8		RomVersionMinor;
-	u8		RomVersionPatch;
-	u8		RomVersionFieldPatch;
-
-	u8		TextLabel[34];
-};
-
-struct SmsFirmware_ST {
-	u32			CheckSum;
-	u32			Length;
-	u32			StartAddress;
-	u8			Payload[1];
-};
-
-/* Statistics information returned as response for
- * SmsHostApiGetStatistics_Req */
-struct SMSHOSTLIB_STATISTICS_ST {
-	u32 Reserved;		/* Reserved */
-
-	/* Common parameters */
-	u32 IsRfLocked;		/* 0 - not locked, 1 - locked */
-	u32 IsDemodLocked;	/* 0 - not locked, 1 - locked */
-	u32 IsExternalLNAOn;	/* 0 - external LNA off, 1 - external LNA on */
-
-	/* Reception quality */
-	s32 SNR;		/* dB */
-	u32 BER;		/* Post Viterbi BER [1E-5] */
-	u32 FIB_CRC;		/* CRC errors percentage, valid only for DAB */
-	u32 TS_PER;		/* Transport stream PER,
-	0xFFFFFFFF indicate N/A, valid only for DVB-T/H */
-	u32 MFER;		/* DVB-H frame error rate in percentage,
-	0xFFFFFFFF indicate N/A, valid only for DVB-H */
-	s32 RSSI;		/* dBm */
-	s32 InBandPwr;		/* In band power in dBM */
-	s32 CarrierOffset;	/* Carrier Offset in bin/1024 */
-
-	/* Transmission parameters */
-	u32 Frequency;		/* Frequency in Hz */
-	u32 Bandwidth;		/* Bandwidth in MHz, valid only for DVB-T/H */
-	u32 TransmissionMode;	/* Transmission Mode, for DAB modes 1-4,
-	for DVB-T/H FFT mode carriers in Kilos */
-	u32 ModemState;		/* from SMSHOSTLIB_DVB_MODEM_STATE_ET,
-	valid only for DVB-T/H */
-	u32 GuardInterval;	/* Guard Interval from
-	SMSHOSTLIB_GUARD_INTERVALS_ET, 	valid only for DVB-T/H */
-	u32 CodeRate;		/* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
-	valid only for DVB-T/H */
-	u32 LPCodeRate;		/* Low Priority Code Rate from
-	SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */
-	u32 Hierarchy;		/* Hierarchy from SMSHOSTLIB_HIERARCHY_ET,
-	valid only for DVB-T/H */
-	u32 Constellation;	/* Constellation from
-	SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */
-
-	/* Burst parameters, valid only for DVB-H */
-	u32 BurstSize;		/* Current burst size in bytes,
-	valid only for DVB-H */
-	u32 BurstDuration;	/* Current burst duration in mSec,
-	valid only for DVB-H */
-	u32 BurstCycleTime;	/* Current burst cycle time in mSec,
-	valid only for DVB-H */
-	u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec,
-	as calculated by demodulator, valid only for DVB-H */
-	u32 NumOfRows;		/* Number of rows in MPE table,
-	valid only for DVB-H */
-	u32 NumOfPaddCols;	/* Number of padding columns in MPE table,
-	valid only for DVB-H */
-	u32 NumOfPunctCols;	/* Number of puncturing columns in MPE table,
-	valid only for DVB-H */
-	u32 ErrorTSPackets;	/* Number of erroneous
-	transport-stream packets */
-	u32 TotalTSPackets;	/* Total number of transport-stream packets */
-	u32 NumOfValidMpeTlbs;	/* Number of MPE tables which do not include
-	errors after MPE RS decoding */
-	u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors
-	after MPE RS decoding */
-	u32 NumOfCorrectedMpeTlbs;/* Number of MPE tables which were
-	corrected by MPE RS decoding */
-	/* Common params */
-	u32 BERErrorCount;	/* Number of errornous SYNC bits. */
-	u32 BERBitCount;	/* Total number of SYNC bits. */
-
-	/* Interface information */
-	u32 SmsToHostTxErrors;	/* Total number of transmission errors. */
-
-	/* DAB/T-DMB */
-	u32 PreBER; 		/* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
-
-	/* DVB-H TPS parameters */
-	u32 CellId;		/* TPS Cell ID in bits 15..0, bits 31..16 zero;
-	 if set to 0xFFFFFFFF cell_id not yet recovered */
-	u32 DvbhSrvIndHP;	/* DVB-H service indication info, bit 1 -
-	Time Slicing indicator, bit 0 - MPE-FEC indicator */
-	u32 DvbhSrvIndLP;	/* DVB-H service indication info, bit 1 -
-	Time Slicing indicator, bit 0 - MPE-FEC indicator */
-
-	u32 NumMPEReceived;	/* DVB-H, Num MPE section received */
-
-	u32 ReservedFields[10];	/* Reserved */
-};
-
-struct SmsMsgStatisticsInfo_ST {
-	u32 RequestResult;
-
-	struct SMSHOSTLIB_STATISTICS_ST Stat;
-
-	/* Split the calc of the SNR in DAB */
-	u32 Signal; /* dB */
-	u32 Noise; /* dB */
-
-};
-
-struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST {
-	/* Per-layer information */
-	u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
-		       * 255 means layer does not exist */
-	u32 Constellation; /* Constellation from SMSHOSTLIB_CONSTELLATION_ET,
-			    * 255 means layer does not exist */
-	u32 BER; /* Post Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */
-	u32 BERErrorCount; /* Post Viterbi Error Bits Count */
-	u32 BERBitCount; /* Post Viterbi Total Bits Count */
-	u32 PreBER; /* Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */
-	u32 TS_PER; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */
-	u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */
-	u32 TotalTSPackets; /* Total number of transport-stream packets */
-	u32 TILdepthI; /* Time interleaver depth I parameter,
-			* 255 means layer does not exist */
-	u32 NumberOfSegments; /* Number of segments in layer A,
-			       * 255 means layer does not exist */
-	u32 TMCCErrors; /* TMCC errors */
-};
-
-struct SMSHOSTLIB_STATISTICS_ISDBT_ST {
-	u32 StatisticsType; /* Enumerator identifying the type of the
-				* structure.  Values are the same as
-				* SMSHOSTLIB_DEVICE_MODES_E
-				*
-				* This field MUST always be first in any
-				* statistics structure */
-
-	u32 FullSize; /* Total size of the structure returned by the modem.
-		       * If the size requested by the host is smaller than
-		       * FullSize, the struct will be truncated */
-
-	/* Common parameters */
-	u32 IsRfLocked; /* 0 - not locked, 1 - locked */
-	u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
-	u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
-
-	/* Reception quality */
-	s32  SNR; /* dB */
-	s32  RSSI; /* dBm */
-	s32  InBandPwr; /* In band power in dBM */
-	s32  CarrierOffset; /* Carrier Offset in Hz */
-
-	/* Transmission parameters */
-	u32 Frequency; /* Frequency in Hz */
-	u32 Bandwidth; /* Bandwidth in MHz */
-	u32 TransmissionMode; /* ISDB-T transmission mode */
-	u32 ModemState; /* 0 - Acquisition, 1 - Locked */
-	u32 GuardInterval; /* Guard Interval, 1 divided by value */
-	u32 SystemType; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */
-	u32 PartialReception; /* TRUE - partial reception, FALSE otherwise */
-	u32 NumOfLayers; /* Number of ISDB-T layers in the network */
-
-	/* Per-layer information */
-	/* Layers A, B and C */
-	struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST	LayerInfo[3];
-	/* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */
-
-	/* Interface information */
-	u32 SmsToHostTxErrors; /* Total number of transmission errors. */
-};
-
-struct PID_STATISTICS_DATA_S {
-	struct PID_BURST_S {
-		u32 size;
-		u32 padding_cols;
-		u32 punct_cols;
-		u32 duration;
-		u32 cycle;
-		u32 calc_cycle;
-	} burst;
-
-	u32 tot_tbl_cnt;
-	u32 invalid_tbl_cnt;
-	u32 tot_cor_tbl;
-};
-
-struct PID_DATA_S {
-	u32 pid;
-	u32 num_rows;
-	struct PID_STATISTICS_DATA_S pid_statistics;
-};
-
-#define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1)
-#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth)
-#define CORRECT_STAT_TRANSMISSON_MODE(_stat) \
-	if (_stat.TransmissionMode == 0) \
-		_stat.TransmissionMode = 2; \
-	else if (_stat.TransmissionMode == 1) \
-		_stat.TransmissionMode = 8; \
-		else \
-			_stat.TransmissionMode = 4;
-
-struct TRANSMISSION_STATISTICS_S {
-	u32 Frequency;		/* Frequency in Hz */
-	u32 Bandwidth;		/* Bandwidth in MHz */
-	u32 TransmissionMode;	/* FFT mode carriers in Kilos */
-	u32 GuardInterval;	/* Guard Interval from
-	SMSHOSTLIB_GUARD_INTERVALS_ET */
-	u32 CodeRate;		/* Code Rate from SMSHOSTLIB_CODE_RATE_ET */
-	u32 LPCodeRate;		/* Low Priority Code Rate from
-	SMSHOSTLIB_CODE_RATE_ET */
-	u32 Hierarchy;		/* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */
-	u32 Constellation;	/* Constellation from
-	SMSHOSTLIB_CONSTELLATION_ET */
-
-	/* DVB-H TPS parameters */
-	u32 CellId;		/* TPS Cell ID in bits 15..0, bits 31..16 zero;
-	 if set to 0xFFFFFFFF cell_id not yet recovered */
-	u32 DvbhSrvIndHP;	/* DVB-H service indication info, bit 1 -
-	 Time Slicing indicator, bit 0 - MPE-FEC indicator */
-	u32 DvbhSrvIndLP;	/* DVB-H service indication info, bit 1 -
-	 Time Slicing indicator, bit 0 - MPE-FEC indicator */
-	u32 IsDemodLocked;	/* 0 - not locked, 1 - locked */
-};
-
-struct RECEPTION_STATISTICS_S {
-	u32 IsRfLocked;		/* 0 - not locked, 1 - locked */
-	u32 IsDemodLocked;	/* 0 - not locked, 1 - locked */
-	u32 IsExternalLNAOn;	/* 0 - external LNA off, 1 - external LNA on */
-
-	u32 ModemState;		/* from SMSHOSTLIB_DVB_MODEM_STATE_ET */
-	s32 SNR;		/* dB */
-	u32 BER;		/* Post Viterbi BER [1E-5] */
-	u32 BERErrorCount;	/* Number of erronous SYNC bits. */
-	u32 BERBitCount;	/* Total number of SYNC bits. */
-	u32 TS_PER;		/* Transport stream PER,
-	0xFFFFFFFF indicate N/A */
-	u32 MFER;		/* DVB-H frame error rate in percentage,
-	0xFFFFFFFF indicate N/A, valid only for DVB-H */
-	s32 RSSI;		/* dBm */
-	s32 InBandPwr;		/* In band power in dBM */
-	s32 CarrierOffset;	/* Carrier Offset in bin/1024 */
-	u32 ErrorTSPackets;	/* Number of erroneous
-	transport-stream packets */
-	u32 TotalTSPackets;	/* Total number of transport-stream packets */
-
-	s32 MRC_SNR;		/* dB */
-	s32 MRC_RSSI;		/* dBm */
-	s32 MRC_InBandPwr;	/* In band power in dBM */
-};
-
-
-/* Statistics information returned as response for
- * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */
-struct SMSHOSTLIB_STATISTICS_DVB_S {
-	/* Reception */
-	struct RECEPTION_STATISTICS_S ReceptionData;
-
-	/* Transmission parameters */
-	struct TRANSMISSION_STATISTICS_S TransmissionData;
-
-	/* Burst parameters, valid only for DVB-H */
-#define	SRVM_MAX_PID_FILTERS 8
-	struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS];
-};
-
-struct SRVM_SIGNAL_STATUS_S {
-	u32 result;
-	u32 snr;
-	u32 tsPackets;
-	u32 etsPackets;
-	u32 constellation;
-	u32 hpCode;
-	u32 tpsSrvIndLP;
-	u32 tpsSrvIndHP;
-	u32 cellId;
-	u32 reason;
-
-	s32 inBandPower;
-	u32 requestId;
-};
-
-struct SMSHOSTLIB_I2C_REQ_ST {
-	u32	DeviceAddress; /* I2c device address */
-	u32	WriteCount; /* number of bytes to write */
-	u32	ReadCount; /* number of bytes to read */
-	u8	Data[1];
-};
-
-struct SMSHOSTLIB_I2C_RES_ST {
-	u32	Status; /* non-zero value in case of failure */
-	u32	ReadCount; /* number of bytes read */
-	u8	Data[1];
-};
-
-
-struct smscore_config_gpio {
-#define SMS_GPIO_DIRECTION_INPUT  0
-#define SMS_GPIO_DIRECTION_OUTPUT 1
-	u8 direction;
-
-#define SMS_GPIO_PULLUPDOWN_NONE     0
-#define SMS_GPIO_PULLUPDOWN_PULLDOWN 1
-#define SMS_GPIO_PULLUPDOWN_PULLUP   2
-#define SMS_GPIO_PULLUPDOWN_KEEPER   3
-	u8 pullupdown;
-
-#define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL  0
-#define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1
-	u8 inputcharacteristics;
-
-#define SMS_GPIO_OUTPUTSLEWRATE_FAST 0
-#define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1
-	u8 outputslewrate;
-
-#define SMS_GPIO_OUTPUTDRIVING_4mA  0
-#define SMS_GPIO_OUTPUTDRIVING_8mA  1
-#define SMS_GPIO_OUTPUTDRIVING_12mA 2
-#define SMS_GPIO_OUTPUTDRIVING_16mA 3
-	u8 outputdriving;
-};
-
-struct smscore_gpio_config {
-#define SMS_GPIO_DIRECTION_INPUT  0
-#define SMS_GPIO_DIRECTION_OUTPUT 1
-	u8 Direction;
-
-#define SMS_GPIO_PULL_UP_DOWN_NONE     0
-#define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1
-#define SMS_GPIO_PULL_UP_DOWN_PULLUP   2
-#define SMS_GPIO_PULL_UP_DOWN_KEEPER   3
-	u8 PullUpDown;
-
-#define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL  0
-#define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1
-	u8 InputCharacteristics;
-
-#define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW		1 /* 10xx */
-#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST		0 /* 10xx */
-
-
-#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS	0 /* 11xx */
-#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS	1 /* 11xx */
-#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS	2 /* 11xx */
-#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS	3 /* 11xx */
-	u8 OutputSlewRate;
-
-#define SMS_GPIO_OUTPUT_DRIVING_S_4mA		0 /* 10xx */
-#define SMS_GPIO_OUTPUT_DRIVING_S_8mA		1 /* 10xx */
-#define SMS_GPIO_OUTPUT_DRIVING_S_12mA		2 /* 10xx */
-#define SMS_GPIO_OUTPUT_DRIVING_S_16mA		3 /* 10xx */
-
-#define SMS_GPIO_OUTPUT_DRIVING_1_5mA		0 /* 11xx */
-#define SMS_GPIO_OUTPUT_DRIVING_2_8mA		1 /* 11xx */
-#define SMS_GPIO_OUTPUT_DRIVING_4mA		2 /* 11xx */
-#define SMS_GPIO_OUTPUT_DRIVING_7mA		3 /* 11xx */
-#define SMS_GPIO_OUTPUT_DRIVING_10mA		4 /* 11xx */
-#define SMS_GPIO_OUTPUT_DRIVING_11mA		5 /* 11xx */
-#define SMS_GPIO_OUTPUT_DRIVING_14mA		6 /* 11xx */
-#define SMS_GPIO_OUTPUT_DRIVING_16mA		7 /* 11xx */
-	u8 OutputDriving;
-};
-
-extern void smscore_registry_setmode(char *devpath, int mode);
-extern int smscore_registry_getmode(char *devpath);
-
-extern int smscore_register_hotplug(hotplug_t hotplug);
-extern void smscore_unregister_hotplug(hotplug_t hotplug);
-
-extern int smscore_register_device(struct smsdevice_params_t *params,
-				   struct smscore_device_t **coredev);
-extern void smscore_unregister_device(struct smscore_device_t *coredev);
-
-extern int smscore_start_device(struct smscore_device_t *coredev);
-extern int smscore_load_firmware(struct smscore_device_t *coredev,
-				 char *filename,
-				 loadfirmware_t loadfirmware_handler);
-
-extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode);
-extern int smscore_get_device_mode(struct smscore_device_t *coredev);
-
-extern int smscore_register_client(struct smscore_device_t *coredev,
-				    struct smsclient_params_t *params,
-				    struct smscore_client_t **client);
-extern void smscore_unregister_client(struct smscore_client_t *client);
-
-extern int smsclient_sendrequest(struct smscore_client_t *client,
-				 void *buffer, size_t size);
-extern void smscore_onresponse(struct smscore_device_t *coredev,
-			       struct smscore_buffer_t *cb);
-
-extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev);
-extern int smscore_map_common_buffer(struct smscore_device_t *coredev,
-				      struct vm_area_struct *vma);
-extern int smscore_get_fw_filename(struct smscore_device_t *coredev,
-				   int mode, char *filename);
-extern int smscore_send_fw_file(struct smscore_device_t *coredev,
-				u8 *ufwbuf, int size);
-
-extern
-struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
-extern void smscore_putbuffer(struct smscore_device_t *coredev,
-			      struct smscore_buffer_t *cb);
-
-/* old GPIO management */
-int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
-			   struct smscore_config_gpio *pinconfig);
-int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level);
-
-/* new GPIO management */
-extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
-		struct smscore_gpio_config *pGpioConfig);
-extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
-		u8 NewLevel);
-extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
-		u8 *level);
-
-void smscore_set_board_id(struct smscore_device_t *core, int id);
-int smscore_get_board_id(struct smscore_device_t *core);
-
-int smscore_led_state(struct smscore_device_t *core, int led);
-
-
-/* ------------------------------------------------------------------------ */
-
-#define DBG_INFO 1
-#define DBG_ADV  2
-
-#define sms_printk(kern, fmt, arg...) \
-	printk(kern "%s: " fmt "\n", __func__, ##arg)
-
-#define dprintk(kern, lvl, fmt, arg...) do {\
-	if (sms_dbg & lvl) \
-		sms_printk(kern, fmt, ##arg); } while (0)
-
-#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg)
-#define sms_err(fmt, arg...) \
-	sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg)
-#define sms_warn(fmt, arg...)  sms_printk(KERN_WARNING, fmt, ##arg)
-#define sms_info(fmt, arg...) \
-	dprintk(KERN_INFO, DBG_INFO, fmt, ##arg)
-#define sms_debug(fmt, arg...) \
-	dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg)
-
-
-#endif /* __SMS_CORE_API_H__ */
diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c
deleted file mode 100644
index aa77e54..0000000
--- a/drivers/media/dvb/siano/smsdvb.c
+++ /dev/null
@@ -1,1078 +0,0 @@
-/****************************************************************
-
-Siano Mobile Silicon, Inc.
-MDTV receiver kernel modules.
-Copyright (C) 2006-2008, Uri Shkolnik
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 2 of the License, or
-(at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-****************************************************************/
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-
-#include "smscoreapi.h"
-#include "smsendian.h"
-#include "sms-cards.h"
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-struct smsdvb_client_t {
-	struct list_head entry;
-
-	struct smscore_device_t *coredev;
-	struct smscore_client_t *smsclient;
-
-	struct dvb_adapter      adapter;
-	struct dvb_demux        demux;
-	struct dmxdev           dmxdev;
-	struct dvb_frontend     frontend;
-
-	fe_status_t             fe_status;
-
-	struct completion       tune_done;
-
-	struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
-	int event_fe_state;
-	int event_unc_state;
-};
-
-static struct list_head g_smsdvb_clients;
-static struct mutex g_smsdvb_clientslock;
-
-static int sms_dbg;
-module_param_named(debug, sms_dbg, int, 0644);
-MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
-
-/* Events that may come from DVB v3 adapter */
-static void sms_board_dvb3_event(struct smsdvb_client_t *client,
-		enum SMS_DVB3_EVENTS event) {
-
-	struct smscore_device_t *coredev = client->coredev;
-	switch (event) {
-	case DVB3_EVENT_INIT:
-		sms_debug("DVB3_EVENT_INIT");
-		sms_board_event(coredev, BOARD_EVENT_BIND);
-		break;
-	case DVB3_EVENT_SLEEP:
-		sms_debug("DVB3_EVENT_SLEEP");
-		sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
-		break;
-	case DVB3_EVENT_HOTPLUG:
-		sms_debug("DVB3_EVENT_HOTPLUG");
-		sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
-		break;
-	case DVB3_EVENT_FE_LOCK:
-		if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
-			client->event_fe_state = DVB3_EVENT_FE_LOCK;
-			sms_debug("DVB3_EVENT_FE_LOCK");
-			sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
-		}
-		break;
-	case DVB3_EVENT_FE_UNLOCK:
-		if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
-			client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
-			sms_debug("DVB3_EVENT_FE_UNLOCK");
-			sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
-		}
-		break;
-	case DVB3_EVENT_UNC_OK:
-		if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
-			client->event_unc_state = DVB3_EVENT_UNC_OK;
-			sms_debug("DVB3_EVENT_UNC_OK");
-			sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
-		}
-		break;
-	case DVB3_EVENT_UNC_ERR:
-		if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
-			client->event_unc_state = DVB3_EVENT_UNC_ERR;
-			sms_debug("DVB3_EVENT_UNC_ERR");
-			sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
-		}
-		break;
-
-	default:
-		sms_err("Unknown dvb3 api event");
-		break;
-	}
-}
-
-
-static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
-				   struct SMSHOSTLIB_STATISTICS_ST *p)
-{
-	if (sms_dbg & 2) {
-		printk(KERN_DEBUG "Reserved = %d", p->Reserved);
-		printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
-		printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
-		printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
-		printk(KERN_DEBUG "SNR = %d", p->SNR);
-		printk(KERN_DEBUG "BER = %d", p->BER);
-		printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC);
-		printk(KERN_DEBUG "TS_PER = %d", p->TS_PER);
-		printk(KERN_DEBUG "MFER = %d", p->MFER);
-		printk(KERN_DEBUG "RSSI = %d", p->RSSI);
-		printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
-		printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
-		printk(KERN_DEBUG "Frequency = %d", p->Frequency);
-		printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
-		printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
-		printk(KERN_DEBUG "ModemState = %d", p->ModemState);
-		printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
-		printk(KERN_DEBUG "CodeRate = %d", p->CodeRate);
-		printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate);
-		printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy);
-		printk(KERN_DEBUG "Constellation = %d", p->Constellation);
-		printk(KERN_DEBUG "BurstSize = %d", p->BurstSize);
-		printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration);
-		printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime);
-		printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime);
-		printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows);
-		printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols);
-		printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols);
-		printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets);
-		printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets);
-		printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs);
-		printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs);
-		printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs);
-		printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount);
-		printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount);
-		printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
-		printk(KERN_DEBUG "PreBER = %d", p->PreBER);
-		printk(KERN_DEBUG "CellId = %d", p->CellId);
-		printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP);
-		printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP);
-		printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived);
-	}
-
-	pReceptionData->IsDemodLocked = p->IsDemodLocked;
-
-	pReceptionData->SNR = p->SNR;
-	pReceptionData->BER = p->BER;
-	pReceptionData->BERErrorCount = p->BERErrorCount;
-	pReceptionData->InBandPwr = p->InBandPwr;
-	pReceptionData->ErrorTSPackets = p->ErrorTSPackets;
-};
-
-
-static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
-				    struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
-{
-	int i;
-
-	if (sms_dbg & 2) {
-		printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
-		printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
-		printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
-		printk(KERN_DEBUG "SNR = %d", p->SNR);
-		printk(KERN_DEBUG "RSSI = %d", p->RSSI);
-		printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
-		printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
-		printk(KERN_DEBUG "Frequency = %d", p->Frequency);
-		printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
-		printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
-		printk(KERN_DEBUG "ModemState = %d", p->ModemState);
-		printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
-		printk(KERN_DEBUG "SystemType = %d", p->SystemType);
-		printk(KERN_DEBUG "PartialReception = %d", p->PartialReception);
-		printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers);
-		printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
-
-		for (i = 0; i < 3; i++) {
-			printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate);
-			printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation);
-			printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER);
-			printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount);
-			printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount);
-			printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER);
-			printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER);
-			printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets);
-			printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets);
-			printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI);
-			printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments);
-			printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors);
-		}
-	}
-
-	pReceptionData->IsDemodLocked = p->IsDemodLocked;
-
-	pReceptionData->SNR = p->SNR;
-	pReceptionData->InBandPwr = p->InBandPwr;
-
-	pReceptionData->ErrorTSPackets = 0;
-	pReceptionData->BER = 0;
-	pReceptionData->BERErrorCount = 0;
-	for (i = 0; i < 3; i++) {
-		pReceptionData->BER += p->LayerInfo[i].BER;
-		pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount;
-		pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets;
-	}
-}
-
-static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
-{
-	struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
-	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
-			+ cb->offset);
-	u32 *pMsgData = (u32 *) phdr + 1;
-	/*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
-	bool is_status_update = false;
-
-	smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);
-
-	switch (phdr->msgType) {
-	case MSG_SMS_DVBT_BDA_DATA:
-		dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),
-				 cb->size - sizeof(struct SmsMsgHdr_ST));
-		break;
-
-	case MSG_SMS_RF_TUNE_RES:
-	case MSG_SMS_ISDBT_TUNE_RES:
-		complete(&client->tune_done);
-		break;
-
-	case MSG_SMS_SIGNAL_DETECTED_IND:
-		sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
-		client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;
-		is_status_update = true;
-		break;
-
-	case MSG_SMS_NO_SIGNAL_IND:
-		sms_info("MSG_SMS_NO_SIGNAL_IND");
-		client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;
-		is_status_update = true;
-		break;
-
-	case MSG_SMS_TRANSMISSION_IND: {
-		sms_info("MSG_SMS_TRANSMISSION_IND");
-
-		pMsgData++;
-		memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
-				sizeof(struct TRANSMISSION_STATISTICS_S));
-
-		/* Mo need to correct guard interval
-		 * (as opposed to old statistics message).
-		 */
-		CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);
-		CORRECT_STAT_TRANSMISSON_MODE(
-				client->sms_stat_dvb.TransmissionData);
-		is_status_update = true;
-		break;
-	}
-	case MSG_SMS_HO_PER_SLICES_IND: {
-		struct RECEPTION_STATISTICS_S *pReceptionData =
-				&client->sms_stat_dvb.ReceptionData;
-		struct SRVM_SIGNAL_STATUS_S SignalStatusData;
-
-		/*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
-		pMsgData++;
-		SignalStatusData.result = pMsgData[0];
-		SignalStatusData.snr = pMsgData[1];
-		SignalStatusData.inBandPower = (s32) pMsgData[2];
-		SignalStatusData.tsPackets = pMsgData[3];
-		SignalStatusData.etsPackets = pMsgData[4];
-		SignalStatusData.constellation = pMsgData[5];
-		SignalStatusData.hpCode = pMsgData[6];
-		SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;
-		SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;
-		SignalStatusData.cellId = pMsgData[9] & 0xFFFF;
-		SignalStatusData.reason = pMsgData[10];
-		SignalStatusData.requestId = pMsgData[11];
-		pReceptionData->IsRfLocked = pMsgData[16];
-		pReceptionData->IsDemodLocked = pMsgData[17];
-		pReceptionData->ModemState = pMsgData[12];
-		pReceptionData->SNR = pMsgData[1];
-		pReceptionData->BER = pMsgData[13];
-		pReceptionData->RSSI = pMsgData[14];
-		CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);
-
-		pReceptionData->InBandPwr = (s32) pMsgData[2];
-		pReceptionData->CarrierOffset = (s32) pMsgData[15];
-		pReceptionData->TotalTSPackets = pMsgData[3];
-		pReceptionData->ErrorTSPackets = pMsgData[4];
-
-		/* TS PER */
-		if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
-				> 0) {
-			pReceptionData->TS_PER = (SignalStatusData.etsPackets
-					* 100) / (SignalStatusData.tsPackets
-					+ SignalStatusData.etsPackets);
-		} else {
-			pReceptionData->TS_PER = 0;
-		}
-
-		pReceptionData->BERBitCount = pMsgData[18];
-		pReceptionData->BERErrorCount = pMsgData[19];
-
-		pReceptionData->MRC_SNR = pMsgData[20];
-		pReceptionData->MRC_InBandPwr = pMsgData[21];
-		pReceptionData->MRC_RSSI = pMsgData[22];
-
-		is_status_update = true;
-		break;
-	}
-	case MSG_SMS_GET_STATISTICS_RES: {
-		union {
-			struct SMSHOSTLIB_STATISTICS_ISDBT_ST  isdbt;
-			struct SmsMsgStatisticsInfo_ST         dvb;
-		} *p = (void *) (phdr + 1);
-		struct RECEPTION_STATISTICS_S *pReceptionData =
-				&client->sms_stat_dvb.ReceptionData;
-
-		sms_info("MSG_SMS_GET_STATISTICS_RES");
-
-		is_status_update = true;
-
-		switch (smscore_get_device_mode(client->coredev)) {
-		case DEVICE_MODE_ISDBT:
-		case DEVICE_MODE_ISDBT_BDA:
-			smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt);
-			break;
-		default:
-			smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat);
-		}
-		if (!pReceptionData->IsDemodLocked) {
-			pReceptionData->SNR = 0;
-			pReceptionData->BER = 0;
-			pReceptionData->BERErrorCount = 0;
-			pReceptionData->InBandPwr = 0;
-			pReceptionData->ErrorTSPackets = 0;
-		}
-
-		complete(&client->tune_done);
-		break;
-	}
-	default:
-		sms_info("Unhandled message %d", phdr->msgType);
-
-	}
-	smscore_putbuffer(client->coredev, cb);
-
-	if (is_status_update) {
-		if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {
-			client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER
-				| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
-			sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
-			if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets
-					== 0)
-				sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
-			else
-				sms_board_dvb3_event(client,
-						DVB3_EVENT_UNC_ERR);
-
-		} else {
-			if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
-				client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
-			else
-				client->fe_status = 0;
-			sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
-		}
-	}
-
-	return 0;
-}
-
-static void smsdvb_unregister_client(struct smsdvb_client_t *client)
-{
-	/* must be called under clientslock */
-
-	list_del(&client->entry);
-
-	smscore_unregister_client(client->smsclient);
-	dvb_unregister_frontend(&client->frontend);
-	dvb_dmxdev_release(&client->dmxdev);
-	dvb_dmx_release(&client->demux);
-	dvb_unregister_adapter(&client->adapter);
-	kfree(client);
-}
-
-static void smsdvb_onremove(void *context)
-{
-	kmutex_lock(&g_smsdvb_clientslock);
-
-	smsdvb_unregister_client((struct smsdvb_client_t *) context);
-
-	kmutex_unlock(&g_smsdvb_clientslock);
-}
-
-static int smsdvb_start_feed(struct dvb_demux_feed *feed)
-{
-	struct smsdvb_client_t *client =
-		container_of(feed->demux, struct smsdvb_client_t, demux);
-	struct SmsMsgData_ST PidMsg;
-
-	sms_debug("add pid %d(%x)",
-		  feed->pid, feed->pid);
-
-	PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
-	PidMsg.xMsgHeader.msgDstId = HIF_TASK;
-	PidMsg.xMsgHeader.msgFlags = 0;
-	PidMsg.xMsgHeader.msgType  = MSG_SMS_ADD_PID_FILTER_REQ;
-	PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
-	PidMsg.msgData[0] = feed->pid;
-
-	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
-	return smsclient_sendrequest(client->smsclient,
-				     &PidMsg, sizeof(PidMsg));
-}
-
-static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
-{
-	struct smsdvb_client_t *client =
-		container_of(feed->demux, struct smsdvb_client_t, demux);
-	struct SmsMsgData_ST PidMsg;
-
-	sms_debug("remove pid %d(%x)",
-		  feed->pid, feed->pid);
-
-	PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
-	PidMsg.xMsgHeader.msgDstId = HIF_TASK;
-	PidMsg.xMsgHeader.msgFlags = 0;
-	PidMsg.xMsgHeader.msgType  = MSG_SMS_REMOVE_PID_FILTER_REQ;
-	PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
-	PidMsg.msgData[0] = feed->pid;
-
-	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
-	return smsclient_sendrequest(client->smsclient,
-				     &PidMsg, sizeof(PidMsg));
-}
-
-static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
-					void *buffer, size_t size,
-					struct completion *completion)
-{
-	int rc;
-
-	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
-	rc = smsclient_sendrequest(client->smsclient, buffer, size);
-	if (rc < 0)
-		return rc;
-
-	return wait_for_completion_timeout(completion,
-					   msecs_to_jiffies(2000)) ?
-						0 : -ETIME;
-}
-
-static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
-{
-	int rc;
-	struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
-				    DVBT_BDA_CONTROL_MSG_ID,
-				    HIF_TASK,
-				    sizeof(struct SmsMsgHdr_ST), 0 };
-
-	rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
-					  &client->tune_done);
-
-	return rc;
-}
-
-static inline int led_feedback(struct smsdvb_client_t *client)
-{
-	if (client->fe_status & FE_HAS_LOCK)
-		return sms_board_led_feedback(client->coredev,
-			(client->sms_stat_dvb.ReceptionData.BER
-			== 0) ? SMS_LED_HI : SMS_LED_LO);
-	else
-		return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
-}
-
-static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
-{
-	int rc;
-	struct smsdvb_client_t *client;
-	client = container_of(fe, struct smsdvb_client_t, frontend);
-
-	rc = smsdvb_send_statistics_request(client);
-
-	*stat = client->fe_status;
-
-	led_feedback(client);
-
-	return rc;
-}
-
-static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	int rc;
-	struct smsdvb_client_t *client;
-	client = container_of(fe, struct smsdvb_client_t, frontend);
-
-	rc = smsdvb_send_statistics_request(client);
-
-	*ber = client->sms_stat_dvb.ReceptionData.BER;
-
-	led_feedback(client);
-
-	return rc;
-}
-
-static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	int rc;
-
-	struct smsdvb_client_t *client;
-	client = container_of(fe, struct smsdvb_client_t, frontend);
-
-	rc = smsdvb_send_statistics_request(client);
-
-	if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
-		*strength = 0;
-		else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
-			*strength = 100;
-		else
-			*strength =
-				(client->sms_stat_dvb.ReceptionData.InBandPwr
-				+ 95) * 3 / 2;
-
-	led_feedback(client);
-
-	return rc;
-}
-
-static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	int rc;
-	struct smsdvb_client_t *client;
-	client = container_of(fe, struct smsdvb_client_t, frontend);
-
-	rc = smsdvb_send_statistics_request(client);
-
-	*snr = client->sms_stat_dvb.ReceptionData.SNR;
-
-	led_feedback(client);
-
-	return rc;
-}
-
-static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	int rc;
-	struct smsdvb_client_t *client;
-	client = container_of(fe, struct smsdvb_client_t, frontend);
-
-	rc = smsdvb_send_statistics_request(client);
-
-	*ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
-
-	led_feedback(client);
-
-	return rc;
-}
-
-static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
-				    struct dvb_frontend_tune_settings *tune)
-{
-	sms_debug("");
-
-	tune->min_delay_ms = 400;
-	tune->step_size = 250000;
-	tune->max_drift = 0;
-	return 0;
-}
-
-static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct smsdvb_client_t *client =
-		container_of(fe, struct smsdvb_client_t, frontend);
-
-	struct {
-		struct SmsMsgHdr_ST	Msg;
-		u32		Data[3];
-	} Msg;
-
-	int ret;
-
-	client->fe_status = FE_HAS_SIGNAL;
-	client->event_fe_state = -1;
-	client->event_unc_state = -1;
-	fe->dtv_property_cache.delivery_system = SYS_DVBT;
-
-	Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
-	Msg.Msg.msgDstId = HIF_TASK;
-	Msg.Msg.msgFlags = 0;
-	Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
-	Msg.Msg.msgLength = sizeof(Msg);
-	Msg.Data[0] = c->frequency;
-	Msg.Data[2] = 12000000;
-
-	sms_info("%s: freq %d band %d", __func__, c->frequency,
-		 c->bandwidth_hz);
-
-	switch (c->bandwidth_hz / 1000000) {
-	case 8:
-		Msg.Data[1] = BW_8_MHZ;
-		break;
-	case 7:
-		Msg.Data[1] = BW_7_MHZ;
-		break;
-	case 6:
-		Msg.Data[1] = BW_6_MHZ;
-		break;
-	case 0:
-		return -EOPNOTSUPP;
-	default:
-		return -EINVAL;
-	}
-	/* Disable LNA, if any. An error is returned if no LNA is present */
-	ret = sms_board_lna_control(client->coredev, 0);
-	if (ret == 0) {
-		fe_status_t status;
-
-		/* tune with LNA off at first */
-		ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
-						  &client->tune_done);
-
-		smsdvb_read_status(fe, &status);
-
-		if (status & FE_HAS_LOCK)
-			return ret;
-
-		/* previous tune didn't lock - enable LNA and tune again */
-		sms_board_lna_control(client->coredev, 1);
-	}
-
-	return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
-					   &client->tune_done);
-}
-
-static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct smsdvb_client_t *client =
-		container_of(fe, struct smsdvb_client_t, frontend);
-
-	struct {
-		struct SmsMsgHdr_ST	Msg;
-		u32		Data[4];
-	} Msg;
-
-	fe->dtv_property_cache.delivery_system = SYS_ISDBT;
-
-	Msg.Msg.msgSrcId  = DVBT_BDA_CONTROL_MSG_ID;
-	Msg.Msg.msgDstId  = HIF_TASK;
-	Msg.Msg.msgFlags  = 0;
-	Msg.Msg.msgType   = MSG_SMS_ISDBT_TUNE_REQ;
-	Msg.Msg.msgLength = sizeof(Msg);
-
-	if (c->isdbt_sb_segment_idx == -1)
-		c->isdbt_sb_segment_idx = 0;
-
-	switch (c->isdbt_sb_segment_count) {
-	case 3:
-		Msg.Data[1] = BW_ISDBT_3SEG;
-		break;
-	case 1:
-		Msg.Data[1] = BW_ISDBT_1SEG;
-		break;
-	case 0:	/* AUTO */
-		switch (c->bandwidth_hz / 1000000) {
-		case 8:
-		case 7:
-			c->isdbt_sb_segment_count = 3;
-			Msg.Data[1] = BW_ISDBT_3SEG;
-			break;
-		case 6:
-			c->isdbt_sb_segment_count = 1;
-			Msg.Data[1] = BW_ISDBT_1SEG;
-			break;
-		default: /* Assumes 6 MHZ bw */
-			c->isdbt_sb_segment_count = 1;
-			c->bandwidth_hz = 6000;
-			Msg.Data[1] = BW_ISDBT_1SEG;
-			break;
-		}
-		break;
-	default:
-		sms_info("Segment count %d not supported", c->isdbt_sb_segment_count);
-		return -EINVAL;
-	}
-
-	Msg.Data[0] = c->frequency;
-	Msg.Data[2] = 12000000;
-	Msg.Data[3] = c->isdbt_sb_segment_idx;
-
-	sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,
-		 c->frequency, c->isdbt_sb_segment_count,
-		 c->isdbt_sb_segment_idx);
-
-	return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
-					   &client->tune_done);
-}
-
-static int smsdvb_set_frontend(struct dvb_frontend *fe)
-{
-	struct smsdvb_client_t *client =
-		container_of(fe, struct smsdvb_client_t, frontend);
-	struct smscore_device_t *coredev = client->coredev;
-
-	switch (smscore_get_device_mode(coredev)) {
-	case DEVICE_MODE_DVBT:
-	case DEVICE_MODE_DVBT_BDA:
-		return smsdvb_dvbt_set_frontend(fe);
-	case DEVICE_MODE_ISDBT:
-	case DEVICE_MODE_ISDBT_BDA:
-		return smsdvb_isdbt_set_frontend(fe);
-	default:
-		return -EINVAL;
-	}
-}
-
-static int smsdvb_get_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
-	struct smsdvb_client_t *client =
-		container_of(fe, struct smsdvb_client_t, frontend);
-	struct smscore_device_t *coredev = client->coredev;
-	struct TRANSMISSION_STATISTICS_S *td =
-		&client->sms_stat_dvb.TransmissionData;
-
-	switch (smscore_get_device_mode(coredev)) {
-	case DEVICE_MODE_DVBT:
-	case DEVICE_MODE_DVBT_BDA:
-		fep->frequency = td->Frequency;
-
-		switch (td->Bandwidth) {
-		case 6:
-			fep->bandwidth_hz = 6000000;
-			break;
-		case 7:
-			fep->bandwidth_hz = 7000000;
-			break;
-		case 8:
-			fep->bandwidth_hz = 8000000;
-			break;
-		}
-
-		switch (td->TransmissionMode) {
-		case 2:
-			fep->transmission_mode = TRANSMISSION_MODE_2K;
-			break;
-		case 8:
-			fep->transmission_mode = TRANSMISSION_MODE_8K;
-		}
-
-		switch (td->GuardInterval) {
-		case 0:
-			fep->guard_interval = GUARD_INTERVAL_1_32;
-			break;
-		case 1:
-			fep->guard_interval = GUARD_INTERVAL_1_16;
-			break;
-		case 2:
-			fep->guard_interval = GUARD_INTERVAL_1_8;
-			break;
-		case 3:
-			fep->guard_interval = GUARD_INTERVAL_1_4;
-			break;
-		}
-
-		switch (td->CodeRate) {
-		case 0:
-			fep->code_rate_HP = FEC_1_2;
-			break;
-		case 1:
-			fep->code_rate_HP = FEC_2_3;
-			break;
-		case 2:
-			fep->code_rate_HP = FEC_3_4;
-			break;
-		case 3:
-			fep->code_rate_HP = FEC_5_6;
-			break;
-		case 4:
-			fep->code_rate_HP = FEC_7_8;
-			break;
-		}
-
-		switch (td->LPCodeRate) {
-		case 0:
-			fep->code_rate_LP = FEC_1_2;
-			break;
-		case 1:
-			fep->code_rate_LP = FEC_2_3;
-			break;
-		case 2:
-			fep->code_rate_LP = FEC_3_4;
-			break;
-		case 3:
-			fep->code_rate_LP = FEC_5_6;
-			break;
-		case 4:
-			fep->code_rate_LP = FEC_7_8;
-			break;
-		}
-
-		switch (td->Constellation) {
-		case 0:
-			fep->modulation = QPSK;
-			break;
-		case 1:
-			fep->modulation = QAM_16;
-			break;
-		case 2:
-			fep->modulation = QAM_64;
-			break;
-		}
-
-		switch (td->Hierarchy) {
-		case 0:
-			fep->hierarchy = HIERARCHY_NONE;
-			break;
-		case 1:
-			fep->hierarchy = HIERARCHY_1;
-			break;
-		case 2:
-			fep->hierarchy = HIERARCHY_2;
-			break;
-		case 3:
-			fep->hierarchy = HIERARCHY_4;
-			break;
-		}
-
-		fep->inversion = INVERSION_AUTO;
-		break;
-	case DEVICE_MODE_ISDBT:
-	case DEVICE_MODE_ISDBT_BDA:
-		fep->frequency = td->Frequency;
-		fep->bandwidth_hz = 6000000;
-		/* todo: retrive the other parameters */
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int smsdvb_init(struct dvb_frontend *fe)
-{
-	struct smsdvb_client_t *client =
-		container_of(fe, struct smsdvb_client_t, frontend);
-
-	sms_board_power(client->coredev, 1);
-
-	sms_board_dvb3_event(client, DVB3_EVENT_INIT);
-	return 0;
-}
-
-static int smsdvb_sleep(struct dvb_frontend *fe)
-{
-	struct smsdvb_client_t *client =
-		container_of(fe, struct smsdvb_client_t, frontend);
-
-	sms_board_led_feedback(client->coredev, SMS_LED_OFF);
-	sms_board_power(client->coredev, 0);
-
-	sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
-
-	return 0;
-}
-
-static void smsdvb_release(struct dvb_frontend *fe)
-{
-	/* do nothing */
-}
-
-static struct dvb_frontend_ops smsdvb_fe_ops = {
-	.info = {
-		.name			= "Siano Mobile Digital MDTV Receiver",
-		.frequency_min		= 44250000,
-		.frequency_max		= 867250000,
-		.frequency_stepsize	= 250000,
-		.caps = FE_CAN_INVERSION_AUTO |
-			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
-			FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_RECOVER |
-			FE_CAN_HIERARCHY_AUTO,
-	},
-
-	.release = smsdvb_release,
-
-	.set_frontend = smsdvb_set_frontend,
-	.get_frontend = smsdvb_get_frontend,
-	.get_tune_settings = smsdvb_get_tune_settings,
-
-	.read_status = smsdvb_read_status,
-	.read_ber = smsdvb_read_ber,
-	.read_signal_strength = smsdvb_read_signal_strength,
-	.read_snr = smsdvb_read_snr,
-	.read_ucblocks = smsdvb_read_ucblocks,
-
-	.init = smsdvb_init,
-	.sleep = smsdvb_sleep,
-};
-
-static int smsdvb_hotplug(struct smscore_device_t *coredev,
-			  struct device *device, int arrival)
-{
-	struct smsclient_params_t params;
-	struct smsdvb_client_t *client;
-	int rc;
-
-	/* device removal handled by onremove callback */
-	if (!arrival)
-		return 0;
-	client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
-	if (!client) {
-		sms_err("kmalloc() failed");
-		return -ENOMEM;
-	}
-
-	/* register dvb adapter */
-	rc = dvb_register_adapter(&client->adapter,
-				  sms_get_board(
-					smscore_get_board_id(coredev))->name,
-				  THIS_MODULE, device, adapter_nr);
-	if (rc < 0) {
-		sms_err("dvb_register_adapter() failed %d", rc);
-		goto adapter_error;
-	}
-
-	/* init dvb demux */
-	client->demux.dmx.capabilities = DMX_TS_FILTERING;
-	client->demux.filternum = 32; /* todo: nova ??? */
-	client->demux.feednum = 32;
-	client->demux.start_feed = smsdvb_start_feed;
-	client->demux.stop_feed = smsdvb_stop_feed;
-
-	rc = dvb_dmx_init(&client->demux);
-	if (rc < 0) {
-		sms_err("dvb_dmx_init failed %d", rc);
-		goto dvbdmx_error;
-	}
-
-	/* init dmxdev */
-	client->dmxdev.filternum = 32;
-	client->dmxdev.demux = &client->demux.dmx;
-	client->dmxdev.capabilities = 0;
-
-	rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
-	if (rc < 0) {
-		sms_err("dvb_dmxdev_init failed %d", rc);
-		goto dmxdev_error;
-	}
-
-	/* init and register frontend */
-	memcpy(&client->frontend.ops, &smsdvb_fe_ops,
-	       sizeof(struct dvb_frontend_ops));
-
-	switch (smscore_get_device_mode(coredev)) {
-	case DEVICE_MODE_DVBT:
-	case DEVICE_MODE_DVBT_BDA:
-		client->frontend.ops.delsys[0] = SYS_DVBT;
-		break;
-	case DEVICE_MODE_ISDBT:
-	case DEVICE_MODE_ISDBT_BDA:
-		client->frontend.ops.delsys[0] = SYS_ISDBT;
-		break;
-	}
-
-	rc = dvb_register_frontend(&client->adapter, &client->frontend);
-	if (rc < 0) {
-		sms_err("frontend registration failed %d", rc);
-		goto frontend_error;
-	}
-
-	params.initial_id = 1;
-	params.data_type = MSG_SMS_DVBT_BDA_DATA;
-	params.onresponse_handler = smsdvb_onresponse;
-	params.onremove_handler = smsdvb_onremove;
-	params.context = client;
-
-	rc = smscore_register_client(coredev, &params, &client->smsclient);
-	if (rc < 0) {
-		sms_err("smscore_register_client() failed %d", rc);
-		goto client_error;
-	}
-
-	client->coredev = coredev;
-
-	init_completion(&client->tune_done);
-
-	kmutex_lock(&g_smsdvb_clientslock);
-
-	list_add(&client->entry, &g_smsdvb_clients);
-
-	kmutex_unlock(&g_smsdvb_clientslock);
-
-	client->event_fe_state = -1;
-	client->event_unc_state = -1;
-	sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
-
-	sms_info("success");
-	sms_board_setup(coredev);
-
-	return 0;
-
-client_error:
-	dvb_unregister_frontend(&client->frontend);
-
-frontend_error:
-	dvb_dmxdev_release(&client->dmxdev);
-
-dmxdev_error:
-	dvb_dmx_release(&client->demux);
-
-dvbdmx_error:
-	dvb_unregister_adapter(&client->adapter);
-
-adapter_error:
-	kfree(client);
-	return rc;
-}
-
-static int __init smsdvb_module_init(void)
-{
-	int rc;
-
-	INIT_LIST_HEAD(&g_smsdvb_clients);
-	kmutex_init(&g_smsdvb_clientslock);
-
-	rc = smscore_register_hotplug(smsdvb_hotplug);
-
-	sms_debug("");
-
-	return rc;
-}
-
-static void __exit smsdvb_module_exit(void)
-{
-	smscore_unregister_hotplug(smsdvb_hotplug);
-
-	kmutex_lock(&g_smsdvb_clientslock);
-
-	while (!list_empty(&g_smsdvb_clients))
-	       smsdvb_unregister_client(
-			(struct smsdvb_client_t *) g_smsdvb_clients.next);
-
-	kmutex_unlock(&g_smsdvb_clientslock);
-}
-
-module_init(smsdvb_module_init);
-module_exit(smsdvb_module_exit);
-
-MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
-MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/siano/smsendian.c b/drivers/media/dvb/siano/smsendian.c
deleted file mode 100644
index e2657c2..0000000
--- a/drivers/media/dvb/siano/smsendian.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/****************************************************************
-
- Siano Mobile Silicon, Inc.
- MDTV receiver kernel modules.
- Copyright (C) 2006-2009, Uri Shkolnik
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
- ****************************************************************/
-
-#include <linux/export.h>
-#include <asm/byteorder.h>
-
-#include "smsendian.h"
-#include "smscoreapi.h"
-
-void smsendian_handle_tx_message(void *buffer)
-{
-#ifdef __BIG_ENDIAN
-	struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
-	int i;
-	int msgWords;
-
-	switch (msg->xMsgHeader.msgType) {
-	case MSG_SMS_DATA_DOWNLOAD_REQ:
-	{
-		msg->msgData[0] = le32_to_cpu(msg->msgData[0]);
-		break;
-	}
-
-	default:
-		msgWords = (msg->xMsgHeader.msgLength -
-				sizeof(struct SmsMsgHdr_ST))/4;
-
-		for (i = 0; i < msgWords; i++)
-			msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
-
-		break;
-	}
-#endif /* __BIG_ENDIAN */
-}
-EXPORT_SYMBOL_GPL(smsendian_handle_tx_message);
-
-void smsendian_handle_rx_message(void *buffer)
-{
-#ifdef __BIG_ENDIAN
-	struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
-	int i;
-	int msgWords;
-
-	switch (msg->xMsgHeader.msgType) {
-	case MSG_SMS_GET_VERSION_EX_RES:
-	{
-		struct SmsVersionRes_ST *ver =
-			(struct SmsVersionRes_ST *) msg;
-		ver->ChipModel = le16_to_cpu(ver->ChipModel);
-		break;
-	}
-
-	case MSG_SMS_DVBT_BDA_DATA:
-	case MSG_SMS_DAB_CHANNEL:
-	case MSG_SMS_DATA_MSG:
-	{
-		break;
-	}
-
-	default:
-	{
-		msgWords = (msg->xMsgHeader.msgLength -
-				sizeof(struct SmsMsgHdr_ST))/4;
-
-		for (i = 0; i < msgWords; i++)
-			msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
-
-		break;
-	}
-	}
-#endif /* __BIG_ENDIAN */
-}
-EXPORT_SYMBOL_GPL(smsendian_handle_rx_message);
-
-void smsendian_handle_message_header(void *msg)
-{
-#ifdef __BIG_ENDIAN
-	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg;
-
-	phdr->msgType = le16_to_cpu(phdr->msgType);
-	phdr->msgLength = le16_to_cpu(phdr->msgLength);
-	phdr->msgFlags = le16_to_cpu(phdr->msgFlags);
-#endif /* __BIG_ENDIAN */
-}
-EXPORT_SYMBOL_GPL(smsendian_handle_message_header);
diff --git a/drivers/media/dvb/siano/smsendian.h b/drivers/media/dvb/siano/smsendian.h
deleted file mode 100644
index 1624d6f..0000000
--- a/drivers/media/dvb/siano/smsendian.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/****************************************************************
-
-Siano Mobile Silicon, Inc.
-MDTV receiver kernel modules.
-Copyright (C) 2006-2009, Uri Shkolnik
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 2 of the License, or
-(at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-****************************************************************/
-
-#ifndef __SMS_ENDIAN_H__
-#define __SMS_ENDIAN_H__
-
-#include <asm/byteorder.h>
-
-extern void smsendian_handle_tx_message(void *buffer);
-extern void smsendian_handle_rx_message(void *buffer);
-extern void smsendian_handle_message_header(void *msg);
-
-#endif /* __SMS_ENDIAN_H__ */
-
diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c
deleted file mode 100644
index 37bc5c4..0000000
--- a/drivers/media/dvb/siano/smsir.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/****************************************************************
-
- Siano Mobile Silicon, Inc.
- MDTV receiver kernel modules.
- Copyright (C) 2006-2009, Uri Shkolnik
-
- Copyright (c) 2010 - Mauro Carvalho Chehab
-	- Ported the driver to use rc-core
-	- IR raw event decoding is now done at rc-core
-	- Code almost re-written
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
- ****************************************************************/
-
-
-#include <linux/types.h>
-#include <linux/input.h>
-
-#include "smscoreapi.h"
-#include "smsir.h"
-#include "sms-cards.h"
-
-#define MODULE_NAME "smsmdtv"
-
-void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
-{
-	int i;
-	const s32 *samples = (const void *)buf;
-
-	for (i = 0; i < len >> 2; i++) {
-		DEFINE_IR_RAW_EVENT(ev);
-
-		ev.duration = abs(samples[i]) * 1000; /* Convert to ns */
-		ev.pulse = (samples[i] > 0) ? false : true;
-
-		ir_raw_event_store(coredev->ir.dev, &ev);
-	}
-	ir_raw_event_handle(coredev->ir.dev);
-}
-
-int sms_ir_init(struct smscore_device_t *coredev)
-{
-	int err;
-	int board_id = smscore_get_board_id(coredev);
-	struct rc_dev *dev;
-
-	sms_log("Allocating rc device");
-	dev = rc_allocate_device();
-	if (!dev) {
-		sms_err("Not enough memory");
-		return -ENOMEM;
-	}
-
-	coredev->ir.controller = 0;	/* Todo: vega/nova SPI number */
-	coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
-	sms_log("IR port %d, timeout %d ms",
-			coredev->ir.controller, coredev->ir.timeout);
-
-	snprintf(coredev->ir.name, sizeof(coredev->ir.name),
-		 "SMS IR (%s)", sms_get_board(board_id)->name);
-
-	strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys));
-	strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys));
-
-	dev->input_name = coredev->ir.name;
-	dev->input_phys = coredev->ir.phys;
-	dev->dev.parent = coredev->device;
-
-#if 0
-	/* TODO: properly initialize the parameters bellow */
-	dev->input_id.bustype = BUS_USB;
-	dev->input_id.version = 1;
-	dev->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
-	dev->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
-#endif
-
-	dev->priv = coredev;
-	dev->driver_type = RC_DRIVER_IR_RAW;
-	dev->allowed_protos = RC_TYPE_ALL;
-	dev->map_name = sms_get_board(board_id)->rc_codes;
-	dev->driver_name = MODULE_NAME;
-
-	sms_log("Input device (IR) %s is set for key events", dev->input_name);
-
-	err = rc_register_device(dev);
-	if (err < 0) {
-		sms_err("Failed to register device");
-		rc_free_device(dev);
-		return err;
-	}
-
-	coredev->ir.dev = dev;
-	return 0;
-}
-
-void sms_ir_exit(struct smscore_device_t *coredev)
-{
-	if (coredev->ir.dev)
-		rc_unregister_device(coredev->ir.dev);
-
-	sms_log("");
-}
diff --git a/drivers/media/dvb/siano/smsir.h b/drivers/media/dvb/siano/smsir.h
deleted file mode 100644
index ae92b3a..0000000
--- a/drivers/media/dvb/siano/smsir.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/****************************************************************
-
-Siano Mobile Silicon, Inc.
-MDTV receiver kernel modules.
-Copyright (C) 2006-2009, Uri Shkolnik
-
- Copyright (c) 2010 - Mauro Carvalho Chehab
-	- Ported the driver to use rc-core
-	- IR raw event decoding is now done at rc-core
-	- Code almost re-written
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 2 of the License, or
-(at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-****************************************************************/
-
-#ifndef __SMS_IR_H__
-#define __SMS_IR_H__
-
-#include <linux/input.h>
-#include <media/rc-core.h>
-
-#define IR_DEFAULT_TIMEOUT		100
-
-struct smscore_device_t;
-
-struct ir_t {
-	struct rc_dev *dev;
-	char name[40];
-	char phys[32];
-
-	char *rc_codes;
-	u64 protocol;
-
-	u32 timeout;
-	u32 controller;
-};
-
-int sms_ir_init(struct smscore_device_t *coredev);
-void sms_ir_exit(struct smscore_device_t *coredev);
-void sms_ir_event(struct smscore_device_t *coredev,
-			const char *buf, int len);
-
-#endif /* __SMS_IR_H__ */
-
diff --git a/drivers/media/dvb/siano/smssdio.c b/drivers/media/dvb/siano/smssdio.c
deleted file mode 100644
index d6f3f10..0000000
--- a/drivers/media/dvb/siano/smssdio.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- *  smssdio.c - Siano 1xxx SDIO interface driver
- *
- *  Copyright 2008 Pierre Ossman
- *
- * Based on code by Siano Mobile Silicon, Inc.,
- * Copyright (C) 2006-2008, Uri Shkolnik
- *
- * 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 hardware is a bit odd in that all transfers should be done
- * to/from the SMSSDIO_DATA register, yet the "increase address" bit
- * always needs to be set.
- *
- * Also, buffers from the card are always aligned to 128 byte
- * boundaries.
- */
-
-/*
- * General cleanup notes:
- *
- * - only typedefs should be name *_t
- *
- * - use ERR_PTR and friends for smscore_register_device()
- *
- * - smscore_getbuffer should zero fields
- *
- * Fix stop command
- */
-
-#include <linux/moduleparam.h>
-#include <linux/slab.h>
-#include <linux/firmware.h>
-#include <linux/delay.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio_ids.h>
-#include <linux/module.h>
-
-#include "smscoreapi.h"
-#include "sms-cards.h"
-
-/* Registers */
-
-#define SMSSDIO_DATA		0x00
-#define SMSSDIO_INT		0x04
-#define SMSSDIO_BLOCK_SIZE	128
-
-static const struct sdio_device_id smssdio_ids[] __devinitconst = {
-	{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR),
-	 .driver_data = SMS1XXX_BOARD_SIANO_STELLAR},
-	{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0),
-	 .driver_data = SMS1XXX_BOARD_SIANO_NOVA_A},
-	{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_B0),
-	 .driver_data = SMS1XXX_BOARD_SIANO_NOVA_B},
-	{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VEGA_A0),
-	 .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
-	{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE),
-	 .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
-	{ /* end: all zeroes */ },
-};
-
-MODULE_DEVICE_TABLE(sdio, smssdio_ids);
-
-struct smssdio_device {
-	struct sdio_func *func;
-
-	struct smscore_device_t *coredev;
-
-	struct smscore_buffer_t *split_cb;
-};
-
-/*******************************************************************/
-/* Siano core callbacks                                            */
-/*******************************************************************/
-
-static int smssdio_sendrequest(void *context, void *buffer, size_t size)
-{
-	int ret = 0;
-	struct smssdio_device *smsdev;
-
-	smsdev = context;
-
-	sdio_claim_host(smsdev->func);
-
-	while (size >= smsdev->func->cur_blksize) {
-		ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA,
-					buffer, smsdev->func->cur_blksize);
-		if (ret)
-			goto out;
-
-		buffer += smsdev->func->cur_blksize;
-		size -= smsdev->func->cur_blksize;
-	}
-
-	if (size) {
-		ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA,
-					buffer, size);
-	}
-
-out:
-	sdio_release_host(smsdev->func);
-
-	return ret;
-}
-
-/*******************************************************************/
-/* SDIO callbacks                                                  */
-/*******************************************************************/
-
-static void smssdio_interrupt(struct sdio_func *func)
-{
-	int ret;
-
-	struct smssdio_device *smsdev;
-	struct smscore_buffer_t *cb;
-	struct SmsMsgHdr_ST *hdr;
-	size_t size;
-
-	smsdev = sdio_get_drvdata(func);
-
-	/*
-	 * The interrupt register has no defined meaning. It is just
-	 * a way of turning of the level triggered interrupt.
-	 */
-	(void)sdio_readb(func, SMSSDIO_INT, &ret);
-	if (ret) {
-		sms_err("Unable to read interrupt register!\n");
-		return;
-	}
-
-	if (smsdev->split_cb == NULL) {
-		cb = smscore_getbuffer(smsdev->coredev);
-		if (!cb) {
-			sms_err("Unable to allocate data buffer!\n");
-			return;
-		}
-
-		ret = sdio_memcpy_fromio(smsdev->func,
-					 cb->p,
-					 SMSSDIO_DATA,
-					 SMSSDIO_BLOCK_SIZE);
-		if (ret) {
-			sms_err("Error %d reading initial block!\n", ret);
-			return;
-		}
-
-		hdr = cb->p;
-
-		if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) {
-			smsdev->split_cb = cb;
-			return;
-		}
-
-		if (hdr->msgLength > smsdev->func->cur_blksize)
-			size = hdr->msgLength - smsdev->func->cur_blksize;
-		else
-			size = 0;
-	} else {
-		cb = smsdev->split_cb;
-		hdr = cb->p;
-
-		size = hdr->msgLength - sizeof(struct SmsMsgHdr_ST);
-
-		smsdev->split_cb = NULL;
-	}
-
-	if (size) {
-		void *buffer;
-
-		buffer = cb->p + (hdr->msgLength - size);
-		size = ALIGN(size, SMSSDIO_BLOCK_SIZE);
-
-		BUG_ON(smsdev->func->cur_blksize != SMSSDIO_BLOCK_SIZE);
-
-		/*
-		 * First attempt to transfer all of it in one go...
-		 */
-		ret = sdio_memcpy_fromio(smsdev->func,
-					 buffer,
-					 SMSSDIO_DATA,
-					 size);
-		if (ret && ret != -EINVAL) {
-			smscore_putbuffer(smsdev->coredev, cb);
-			sms_err("Error %d reading data from card!\n", ret);
-			return;
-		}
-
-		/*
-		 * ..then fall back to one block at a time if that is
-		 * not possible...
-		 *
-		 * (we have to do this manually because of the
-		 * problem with the "increase address" bit)
-		 */
-		if (ret == -EINVAL) {
-			while (size) {
-				ret = sdio_memcpy_fromio(smsdev->func,
-						  buffer, SMSSDIO_DATA,
-						  smsdev->func->cur_blksize);
-				if (ret) {
-					smscore_putbuffer(smsdev->coredev, cb);
-					sms_err("Error %d reading "
-						"data from card!\n", ret);
-					return;
-				}
-
-				buffer += smsdev->func->cur_blksize;
-				if (size > smsdev->func->cur_blksize)
-					size -= smsdev->func->cur_blksize;
-				else
-					size = 0;
-			}
-		}
-	}
-
-	cb->size = hdr->msgLength;
-	cb->offset = 0;
-
-	smscore_onresponse(smsdev->coredev, cb);
-}
-
-static int __devinit smssdio_probe(struct sdio_func *func,
-			 const struct sdio_device_id *id)
-{
-	int ret;
-
-	int board_id;
-	struct smssdio_device *smsdev;
-	struct smsdevice_params_t params;
-
-	board_id = id->driver_data;
-
-	smsdev = kzalloc(sizeof(struct smssdio_device), GFP_KERNEL);
-	if (!smsdev)
-		return -ENOMEM;
-
-	smsdev->func = func;
-
-	memset(&params, 0, sizeof(struct smsdevice_params_t));
-
-	params.device = &func->dev;
-	params.buffer_size = 0x5000;	/* ?? */
-	params.num_buffers = 22;	/* ?? */
-	params.context = smsdev;
-
-	snprintf(params.devpath, sizeof(params.devpath),
-		 "sdio\\%s", sdio_func_id(func));
-
-	params.sendrequest_handler = smssdio_sendrequest;
-
-	params.device_type = sms_get_board(board_id)->type;
-
-	if (params.device_type != SMS_STELLAR)
-		params.flags |= SMS_DEVICE_FAMILY2;
-	else {
-		/*
-		 * FIXME: Stellar needs special handling...
-		 */
-		ret = -ENODEV;
-		goto free;
-	}
-
-	ret = smscore_register_device(&params, &smsdev->coredev);
-	if (ret < 0)
-		goto free;
-
-	smscore_set_board_id(smsdev->coredev, board_id);
-
-	sdio_claim_host(func);
-
-	ret = sdio_enable_func(func);
-	if (ret)
-		goto release;
-
-	ret = sdio_set_block_size(func, SMSSDIO_BLOCK_SIZE);
-	if (ret)
-		goto disable;
-
-	ret = sdio_claim_irq(func, smssdio_interrupt);
-	if (ret)
-		goto disable;
-
-	sdio_set_drvdata(func, smsdev);
-
-	sdio_release_host(func);
-
-	ret = smscore_start_device(smsdev->coredev);
-	if (ret < 0)
-		goto reclaim;
-
-	return 0;
-
-reclaim:
-	sdio_claim_host(func);
-	sdio_release_irq(func);
-disable:
-	sdio_disable_func(func);
-release:
-	sdio_release_host(func);
-	smscore_unregister_device(smsdev->coredev);
-free:
-	kfree(smsdev);
-
-	return ret;
-}
-
-static void smssdio_remove(struct sdio_func *func)
-{
-	struct smssdio_device *smsdev;
-
-	smsdev = sdio_get_drvdata(func);
-
-	/* FIXME: racy! */
-	if (smsdev->split_cb)
-		smscore_putbuffer(smsdev->coredev, smsdev->split_cb);
-
-	smscore_unregister_device(smsdev->coredev);
-
-	sdio_claim_host(func);
-	sdio_release_irq(func);
-	sdio_disable_func(func);
-	sdio_release_host(func);
-
-	kfree(smsdev);
-}
-
-static struct sdio_driver smssdio_driver = {
-	.name = "smssdio",
-	.id_table = smssdio_ids,
-	.probe = smssdio_probe,
-	.remove = smssdio_remove,
-};
-
-/*******************************************************************/
-/* Module functions                                                */
-/*******************************************************************/
-
-static int __init smssdio_module_init(void)
-{
-	int ret = 0;
-
-	printk(KERN_INFO "smssdio: Siano SMS1xxx SDIO driver\n");
-	printk(KERN_INFO "smssdio: Copyright Pierre Ossman\n");
-
-	ret = sdio_register_driver(&smssdio_driver);
-
-	return ret;
-}
-
-static void __exit smssdio_module_exit(void)
-{
-	sdio_unregister_driver(&smssdio_driver);
-}
-
-module_init(smssdio_module_init);
-module_exit(smssdio_module_exit);
-
-MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver");
-MODULE_AUTHOR("Pierre Ossman");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
deleted file mode 100644
index 664e460..0000000
--- a/drivers/media/dvb/siano/smsusb.c
+++ /dev/null
@@ -1,568 +0,0 @@
-/****************************************************************
-
-Siano Mobile Silicon, Inc.
-MDTV receiver kernel modules.
-Copyright (C) 2005-2009, Uri Shkolnik, Anatoly Greenblat
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 2 of the License, or
-(at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-****************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/usb.h>
-#include <linux/firmware.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-
-#include "smscoreapi.h"
-#include "sms-cards.h"
-#include "smsendian.h"
-
-static int sms_dbg;
-module_param_named(debug, sms_dbg, int, 0644);
-MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
-
-#define USB1_BUFFER_SIZE		0x1000
-#define USB2_BUFFER_SIZE		0x4000
-
-#define MAX_BUFFERS		50
-#define MAX_URBS		10
-
-struct smsusb_device_t;
-
-struct smsusb_urb_t {
-	struct smscore_buffer_t *cb;
-	struct smsusb_device_t	*dev;
-
-	struct urb urb;
-};
-
-struct smsusb_device_t {
-	struct usb_device *udev;
-	struct smscore_device_t *coredev;
-
-	struct smsusb_urb_t 	surbs[MAX_URBS];
-
-	int		response_alignment;
-	int		buffer_size;
-};
-
-static int smsusb_submit_urb(struct smsusb_device_t *dev,
-			     struct smsusb_urb_t *surb);
-
-static void smsusb_onresponse(struct urb *urb)
-{
-	struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
-	struct smsusb_device_t *dev = surb->dev;
-
-	if (urb->status == -ESHUTDOWN) {
-		sms_err("error, urb status %d (-ESHUTDOWN), %d bytes",
-			urb->status, urb->actual_length);
-		return;
-	}
-
-	if ((urb->actual_length > 0) && (urb->status == 0)) {
-		struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)surb->cb->p;
-
-		smsendian_handle_message_header(phdr);
-		if (urb->actual_length >= phdr->msgLength) {
-			surb->cb->size = phdr->msgLength;
-
-			if (dev->response_alignment &&
-			    (phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG)) {
-
-				surb->cb->offset =
-					dev->response_alignment +
-					((phdr->msgFlags >> 8) & 3);
-
-				/* sanity check */
-				if (((int) phdr->msgLength +
-				     surb->cb->offset) > urb->actual_length) {
-					sms_err("invalid response "
-						"msglen %d offset %d "
-						"size %d",
-						phdr->msgLength,
-						surb->cb->offset,
-						urb->actual_length);
-					goto exit_and_resubmit;
-				}
-
-				/* move buffer pointer and
-				 * copy header to its new location */
-				memcpy((char *) phdr + surb->cb->offset,
-				       phdr, sizeof(struct SmsMsgHdr_ST));
-			} else
-				surb->cb->offset = 0;
-
-			smscore_onresponse(dev->coredev, surb->cb);
-			surb->cb = NULL;
-		} else {
-			sms_err("invalid response "
-				"msglen %d actual %d",
-				phdr->msgLength, urb->actual_length);
-		}
-	} else
-		sms_err("error, urb status %d, %d bytes",
-			urb->status, urb->actual_length);
-
-
-exit_and_resubmit:
-	smsusb_submit_urb(dev, surb);
-}
-
-static int smsusb_submit_urb(struct smsusb_device_t *dev,
-			     struct smsusb_urb_t *surb)
-{
-	if (!surb->cb) {
-		surb->cb = smscore_getbuffer(dev->coredev);
-		if (!surb->cb) {
-			sms_err("smscore_getbuffer(...) returned NULL");
-			return -ENOMEM;
-		}
-	}
-
-	usb_fill_bulk_urb(
-		&surb->urb,
-		dev->udev,
-		usb_rcvbulkpipe(dev->udev, 0x81),
-		surb->cb->p,
-		dev->buffer_size,
-		smsusb_onresponse,
-		surb
-	);
-	surb->urb.transfer_dma = surb->cb->phys;
-	surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	return usb_submit_urb(&surb->urb, GFP_ATOMIC);
-}
-
-static void smsusb_stop_streaming(struct smsusb_device_t *dev)
-{
-	int i;
-
-	for (i = 0; i < MAX_URBS; i++) {
-		usb_kill_urb(&dev->surbs[i].urb);
-
-		if (dev->surbs[i].cb) {
-			smscore_putbuffer(dev->coredev, dev->surbs[i].cb);
-			dev->surbs[i].cb = NULL;
-		}
-	}
-}
-
-static int smsusb_start_streaming(struct smsusb_device_t *dev)
-{
-	int i, rc;
-
-	for (i = 0; i < MAX_URBS; i++) {
-		rc = smsusb_submit_urb(dev, &dev->surbs[i]);
-		if (rc < 0) {
-			sms_err("smsusb_submit_urb(...) failed");
-			smsusb_stop_streaming(dev);
-			break;
-		}
-	}
-
-	return rc;
-}
-
-static int smsusb_sendrequest(void *context, void *buffer, size_t size)
-{
-	struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
-	int dummy;
-
-	smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer);
-	return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
-			    buffer, size, &dummy, 1000);
-}
-
-static char *smsusb1_fw_lkup[] = {
-	"dvbt_stellar_usb.inp",
-	"dvbh_stellar_usb.inp",
-	"tdmb_stellar_usb.inp",
-	"none",
-	"dvbt_bda_stellar_usb.inp",
-};
-
-static inline char *sms_get_fw_name(int mode, int board_id)
-{
-	char **fw = sms_get_board(board_id)->fw;
-	return (fw && fw[mode]) ? fw[mode] : smsusb1_fw_lkup[mode];
-}
-
-static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)
-{
-	const struct firmware *fw;
-	u8 *fw_buffer;
-	int rc, dummy;
-	char *fw_filename;
-
-	if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) {
-		sms_err("invalid firmware id specified %d", id);
-		return -EINVAL;
-	}
-
-	fw_filename = sms_get_fw_name(id, board_id);
-
-	rc = request_firmware(&fw, fw_filename, &udev->dev);
-	if (rc < 0) {
-		sms_warn("failed to open \"%s\" mode %d, "
-			 "trying again with default firmware", fw_filename, id);
-
-		fw_filename = smsusb1_fw_lkup[id];
-		rc = request_firmware(&fw, fw_filename, &udev->dev);
-		if (rc < 0) {
-			sms_warn("failed to open \"%s\" mode %d",
-				 fw_filename, id);
-
-			return rc;
-		}
-	}
-
-	fw_buffer = kmalloc(fw->size, GFP_KERNEL);
-	if (fw_buffer) {
-		memcpy(fw_buffer, fw->data, fw->size);
-
-		rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2),
-				  fw_buffer, fw->size, &dummy, 1000);
-
-		sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc);
-
-		kfree(fw_buffer);
-	} else {
-		sms_err("failed to allocate firmware buffer");
-		rc = -ENOMEM;
-	}
-	sms_info("read FW %s, size=%zd", fw_filename, fw->size);
-
-	release_firmware(fw);
-
-	return rc;
-}
-
-static void smsusb1_detectmode(void *context, int *mode)
-{
-	char *product_string =
-		((struct smsusb_device_t *) context)->udev->product;
-
-	*mode = DEVICE_MODE_NONE;
-
-	if (!product_string) {
-		product_string = "none";
-		sms_err("product string not found");
-	} else if (strstr(product_string, "DVBH"))
-		*mode = 1;
-	else if (strstr(product_string, "BDA"))
-		*mode = 4;
-	else if (strstr(product_string, "DVBT"))
-		*mode = 0;
-	else if (strstr(product_string, "TDMB"))
-		*mode = 2;
-
-	sms_info("%d \"%s\"", *mode, product_string);
-}
-
-static int smsusb1_setmode(void *context, int mode)
-{
-	struct SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK,
-			     sizeof(struct SmsMsgHdr_ST), 0 };
-
-	if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
-		sms_err("invalid firmware id specified %d", mode);
-		return -EINVAL;
-	}
-
-	return smsusb_sendrequest(context, &Msg, sizeof(Msg));
-}
-
-static void smsusb_term_device(struct usb_interface *intf)
-{
-	struct smsusb_device_t *dev = usb_get_intfdata(intf);
-
-	if (dev) {
-		smsusb_stop_streaming(dev);
-
-		/* unregister from smscore */
-		if (dev->coredev)
-			smscore_unregister_device(dev->coredev);
-
-		sms_info("device %p destroyed", dev);
-		kfree(dev);
-	}
-
-	usb_set_intfdata(intf, NULL);
-}
-
-static int smsusb_init_device(struct usb_interface *intf, int board_id)
-{
-	struct smsdevice_params_t params;
-	struct smsusb_device_t *dev;
-	int i, rc;
-
-	/* create device object */
-	dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL);
-	if (!dev) {
-		sms_err("kzalloc(sizeof(struct smsusb_device_t) failed");
-		return -ENOMEM;
-	}
-
-	memset(&params, 0, sizeof(params));
-	usb_set_intfdata(intf, dev);
-	dev->udev = interface_to_usbdev(intf);
-
-	params.device_type = sms_get_board(board_id)->type;
-
-	switch (params.device_type) {
-	case SMS_STELLAR:
-		dev->buffer_size = USB1_BUFFER_SIZE;
-
-		params.setmode_handler = smsusb1_setmode;
-		params.detectmode_handler = smsusb1_detectmode;
-		break;
-	default:
-		sms_err("Unspecified sms device type!");
-		/* fall-thru */
-	case SMS_NOVA_A0:
-	case SMS_NOVA_B0:
-	case SMS_VEGA:
-		dev->buffer_size = USB2_BUFFER_SIZE;
-		dev->response_alignment =
-		    le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) -
-		    sizeof(struct SmsMsgHdr_ST);
-
-		params.flags |= SMS_DEVICE_FAMILY2;
-		break;
-	}
-
-	params.device = &dev->udev->dev;
-	params.buffer_size = dev->buffer_size;
-	params.num_buffers = MAX_BUFFERS;
-	params.sendrequest_handler = smsusb_sendrequest;
-	params.context = dev;
-	usb_make_path(dev->udev, params.devpath, sizeof(params.devpath));
-
-	/* register in smscore */
-	rc = smscore_register_device(&params, &dev->coredev);
-	if (rc < 0) {
-		sms_err("smscore_register_device(...) failed, rc %d", rc);
-		smsusb_term_device(intf);
-		return rc;
-	}
-
-	smscore_set_board_id(dev->coredev, board_id);
-
-	/* initialize urbs */
-	for (i = 0; i < MAX_URBS; i++) {
-		dev->surbs[i].dev = dev;
-		usb_init_urb(&dev->surbs[i].urb);
-	}
-
-	sms_info("smsusb_start_streaming(...).");
-	rc = smsusb_start_streaming(dev);
-	if (rc < 0) {
-		sms_err("smsusb_start_streaming(...) failed");
-		smsusb_term_device(intf);
-		return rc;
-	}
-
-	rc = smscore_start_device(dev->coredev);
-	if (rc < 0) {
-		sms_err("smscore_start_device(...) failed");
-		smsusb_term_device(intf);
-		return rc;
-	}
-
-	sms_info("device %p created", dev);
-
-	return rc;
-}
-
-static int __devinit smsusb_probe(struct usb_interface *intf,
-			const struct usb_device_id *id)
-{
-	struct usb_device *udev = interface_to_usbdev(intf);
-	char devpath[32];
-	int i, rc;
-
-	rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
-	rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
-
-	if (intf->num_altsetting > 0) {
-		rc = usb_set_interface(
-			udev, intf->cur_altsetting->desc.bInterfaceNumber, 0);
-		if (rc < 0) {
-			sms_err("usb_set_interface failed, rc %d", rc);
-			return rc;
-		}
-	}
-
-	sms_info("smsusb_probe %d",
-	       intf->cur_altsetting->desc.bInterfaceNumber);
-	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
-		sms_info("endpoint %d %02x %02x %d", i,
-		       intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
-		       intf->cur_altsetting->endpoint[i].desc.bmAttributes,
-		       intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
-
-	if ((udev->actconfig->desc.bNumInterfaces == 2) &&
-	    (intf->cur_altsetting->desc.bInterfaceNumber == 0)) {
-		sms_err("rom interface 0 is not used");
-		return -ENODEV;
-	}
-
-	if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
-		snprintf(devpath, sizeof(devpath), "usb\\%d-%s",
-			 udev->bus->busnum, udev->devpath);
-		sms_info("stellar device was found.");
-		return smsusb1_load_firmware(
-				udev, smscore_registry_getmode(devpath),
-				id->driver_info);
-	}
-
-	rc = smsusb_init_device(intf, id->driver_info);
-	sms_info("rc %d", rc);
-	sms_board_load_modules(id->driver_info);
-	return rc;
-}
-
-static void smsusb_disconnect(struct usb_interface *intf)
-{
-	smsusb_term_device(intf);
-}
-
-static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
-{
-	struct smsusb_device_t *dev = usb_get_intfdata(intf);
-	printk(KERN_INFO "%s: Entering status %d.\n", __func__, msg.event);
-	smsusb_stop_streaming(dev);
-	return 0;
-}
-
-static int smsusb_resume(struct usb_interface *intf)
-{
-	int rc, i;
-	struct smsusb_device_t *dev = usb_get_intfdata(intf);
-	struct usb_device *udev = interface_to_usbdev(intf);
-
-	printk(KERN_INFO "%s: Entering.\n", __func__);
-	usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
-	usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
-
-	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
-		printk(KERN_INFO "endpoint %d %02x %02x %d\n", i,
-		       intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
-		       intf->cur_altsetting->endpoint[i].desc.bmAttributes,
-		       intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
-
-	if (intf->num_altsetting > 0) {
-		rc = usb_set_interface(udev,
-				       intf->cur_altsetting->desc.
-				       bInterfaceNumber, 0);
-		if (rc < 0) {
-			printk(KERN_INFO "%s usb_set_interface failed, "
-			       "rc %d\n", __func__, rc);
-			return rc;
-		}
-	}
-
-	smsusb_start_streaming(dev);
-	return 0;
-}
-
-static const struct usb_device_id smsusb_id_table[] __devinitconst = {
-	{ USB_DEVICE(0x187f, 0x0010),
-		.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
-	{ USB_DEVICE(0x187f, 0x0100),
-		.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
-	{ USB_DEVICE(0x187f, 0x0200),
-		.driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
-	{ USB_DEVICE(0x187f, 0x0201),
-		.driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
-	{ USB_DEVICE(0x187f, 0x0300),
-		.driver_info = SMS1XXX_BOARD_SIANO_VEGA },
-	{ USB_DEVICE(0x2040, 0x1700),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
-	{ USB_DEVICE(0x2040, 0x1800),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
-	{ USB_DEVICE(0x2040, 0x1801),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
-	{ USB_DEVICE(0x2040, 0x2000),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
-	{ USB_DEVICE(0x2040, 0x2009),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 },
-	{ USB_DEVICE(0x2040, 0x200a),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
-	{ USB_DEVICE(0x2040, 0x2010),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
-	{ USB_DEVICE(0x2040, 0x2011),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
-	{ USB_DEVICE(0x2040, 0x2019),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
-	{ USB_DEVICE(0x2040, 0x5500),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-	{ USB_DEVICE(0x2040, 0x5510),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-	{ USB_DEVICE(0x2040, 0x5520),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-	{ USB_DEVICE(0x2040, 0x5530),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-	{ USB_DEVICE(0x2040, 0x5580),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-	{ USB_DEVICE(0x2040, 0x5590),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-	{ USB_DEVICE(0x187f, 0x0202),
-		.driver_info = SMS1XXX_BOARD_SIANO_NICE },
-	{ USB_DEVICE(0x187f, 0x0301),
-		.driver_info = SMS1XXX_BOARD_SIANO_VENICE },
-	{ USB_DEVICE(0x2040, 0xb900),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-	{ USB_DEVICE(0x2040, 0xb910),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-	{ USB_DEVICE(0x2040, 0xb980),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-	{ USB_DEVICE(0x2040, 0xb990),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-	{ USB_DEVICE(0x2040, 0xc000),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-	{ USB_DEVICE(0x2040, 0xc010),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-	{ USB_DEVICE(0x2040, 0xc080),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-	{ USB_DEVICE(0x2040, 0xc090),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-	{ USB_DEVICE(0x2040, 0xc0a0),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-	{ USB_DEVICE(0x2040, 0xf5a0),
-		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-	{ } /* Terminating entry */
-	};
-
-MODULE_DEVICE_TABLE(usb, smsusb_id_table);
-
-static struct usb_driver smsusb_driver = {
-	.name			= "smsusb",
-	.probe			= smsusb_probe,
-	.disconnect		= smsusb_disconnect,
-	.id_table		= smsusb_id_table,
-
-	.suspend		= smsusb_suspend,
-	.resume			= smsusb_resume,
-};
-
-module_usb_driver(smsusb_driver);
-
-MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle");
-MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
deleted file mode 100644
index 9d83ced..0000000
--- a/drivers/media/dvb/ttpci/Kconfig
+++ /dev/null
@@ -1,159 +0,0 @@
-config TTPCI_EEPROM
-	tristate
-	depends on I2C
-	default n
-
-config DVB_AV7110
-	tristate "AV7110 cards"
-	depends on DVB_CORE && PCI && I2C
-	select TTPCI_EEPROM
-	select VIDEO_SAA7146_VV
-	depends on VIDEO_DEV	# dependencies of VIDEO_SAA7146_VV
-	select DVB_VES1820 if !DVB_FE_CUSTOMISE
-	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
-	select DVB_STV0299 if !DVB_FE_CUSTOMISE
-	select DVB_TDA8083 if !DVB_FE_CUSTOMISE
-	select DVB_SP8870 if !DVB_FE_CUSTOMISE
-	select DVB_STV0297 if !DVB_FE_CUSTOMISE
-	select DVB_L64781 if !DVB_FE_CUSTOMISE
-	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
-	help
-	  Support for SAA7146 and AV7110 based DVB cards as produced
-	  by Fujitsu-Siemens, Technotrend, Hauppauge and others.
-
-	  This driver only supports the fullfeatured cards with
-	  onboard MPEG2 decoder.
-
-	  This driver needs an external firmware. Please use the script
-	  "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to
-	  download/extract it, and then copy it to /usr/lib/hotplug/firmware
-	  or /lib/firmware (depending on configuration of firmware hotplug).
-
-	  Alternatively, you can download the file and use the kernel's
-	  EXTRA_FIRMWARE configuration option to build it into your
-	  kernel image by adding the filename to the EXTRA_FIRMWARE
-	  configuration option string.
-
-	  Say Y if you own such a card and want to use it.
-
-config DVB_AV7110_OSD
-	bool "AV7110 OSD support"
-	depends on DVB_AV7110
-	default y if DVB_AV7110=y || DVB_AV7110=m
-	help
-	  The AV7110 firmware provides some code to generate an OnScreenDisplay
-	  on the video output. This is kind of nonstandard and not guaranteed to
-	  be maintained.
-
-	  Anyway, some popular DVB software like VDR uses this OSD to render
-	  its menus, so say Y if you want to use this software.
-
-	  All other people say N.
-
-config DVB_BUDGET_CORE
-	tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)"
-	depends on DVB_CORE && PCI && I2C
-	select VIDEO_SAA7146
-	select TTPCI_EEPROM
-	help
-	  Support for simple SAA7146 based DVB cards
-	  (so called Budget- or Nova-PCI cards) without onboard
-	  MPEG2 decoder.
-
-config DVB_BUDGET
-	tristate "Budget cards"
-	depends on DVB_BUDGET_CORE && I2C
-	select DVB_STV0299 if !DVB_FE_CUSTOMISE
-	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
-	select DVB_VES1820 if !DVB_FE_CUSTOMISE
-	select DVB_L64781 if !DVB_FE_CUSTOMISE
-	select DVB_TDA8083 if !DVB_FE_CUSTOMISE
-	select DVB_S5H1420 if !DVB_FE_CUSTOMISE
-	select DVB_TDA10086 if !DVB_FE_CUSTOMISE
-	select DVB_TDA826X if !DVB_FE_CUSTOMISE
-	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
-	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
-	select DVB_ISL6423 if !DVB_FE_CUSTOMISE
-	select DVB_STV090x if !DVB_FE_CUSTOMISE
-	select DVB_STV6110x if !DVB_FE_CUSTOMISE
-	help
-	  Support for simple SAA7146 based DVB cards (so called Budget-
-	  or Nova-PCI cards) without onboard MPEG2 decoder, and without
-	  analog inputs or an onboard Common Interface connector.
-
-	  Say Y if you own such a card and want to use it.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called budget.
-
-config DVB_BUDGET_CI
-	tristate "Budget cards with onboard CI connector"
-	depends on DVB_BUDGET_CORE && I2C
-	select DVB_STV0297 if !DVB_FE_CUSTOMISE
-	select DVB_STV0299 if !DVB_FE_CUSTOMISE
-	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
-	select DVB_STB0899 if !DVB_FE_CUSTOMISE
-	select DVB_STB6100 if !DVB_FE_CUSTOMISE
-	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
-	select DVB_STV0288 if !DVB_FE_CUSTOMISE
-	select DVB_STB6000 if !DVB_FE_CUSTOMISE
-	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
-	depends on RC_CORE
-	help
-	  Support for simple SAA7146 based DVB cards
-	  (so called Budget- or Nova-PCI cards) without onboard
-	  MPEG2 decoder, but with onboard Common Interface connector.
-
-	  Note: The Common Interface is not yet supported by this driver
-	  due to lack of information from the vendor.
-
-	  Say Y if you own such a card and want to use it.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called budget-ci.
-
-config DVB_BUDGET_AV
-	tristate "Budget cards with analog video inputs"
-	depends on DVB_BUDGET_CORE && I2C
-	select VIDEO_SAA7146_VV
-	depends on VIDEO_DEV	# dependencies of VIDEO_SAA7146_VV
-	select DVB_PLL if !DVB_FE_CUSTOMISE
-	select DVB_STV0299 if !DVB_FE_CUSTOMISE
-	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
-	select DVB_TDA10021 if !DVB_FE_CUSTOMISE
-	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
-	select DVB_STB0899 if !DVB_FE_CUSTOMISE
-	select DVB_TDA8261 if !DVB_FE_CUSTOMISE
-	select DVB_TUA6100 if !DVB_FE_CUSTOMISE
-	help
-	  Support for simple SAA7146 based DVB cards
-	  (so called Budget- or Nova-PCI cards) without onboard
-	  MPEG2 decoder, but with one or more analog video inputs.
-
-	  Say Y if you own such a card and want to use it.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called budget-av.
-
-config DVB_BUDGET_PATCH
-	tristate "AV7110 cards with Budget Patch"
-	depends on DVB_BUDGET_CORE && I2C
-	depends on DVB_AV7110
-	select DVB_STV0299 if !DVB_FE_CUSTOMISE
-	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
-	select DVB_TDA8083 if !DVB_FE_CUSTOMISE
-	help
-	  Support for Budget Patch (full TS) modification on
-	  SAA7146+AV7110 based cards (DVB-S cards). This
-	  driver doesn't use onboard MPEG2 decoder. The
-	  card is driven in Budget-only mode. Card is
-	  required to have loaded firmware to tune properly.
-	  Firmware can be loaded by insertion and removal of
-	  standard AV7110 driver prior to loading this
-	  driver.
-
-	  Say Y if you own such a card and want to use it.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called budget-patch.
diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile
deleted file mode 100644
index f6e8693..0000000
--- a/drivers/media/dvb/ttpci/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# Makefile for the kernel SAA7146 FULL TS DVB device driver
-# and the AV7110 DVB device driver
-#
-
-dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o
-
-ifdef CONFIG_INPUT_EVDEV
-dvb-ttpci-objs += av7110_ir.o
-endif
-
-obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
-obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o
-obj-$(CONFIG_DVB_BUDGET) += budget.o
-obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o
-obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o
-obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
-obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
-ccflags-y += -Idrivers/media/common/tuners
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
deleted file mode 100644
index 4bd8bd5..0000000
--- a/drivers/media/dvb/ttpci/av7110.c
+++ /dev/null
@@ -1,2939 +0,0 @@
-/*
- * driver for the SAA7146 based AV110 cards (like the Fujitsu-Siemens DVB)
- * av7110.c: initialization and demux stuff
- *
- * Copyright (C) 1999-2002 Ralph  Metzler
- *                       & Marcus Metzler for convergence integrated media GmbH
- *
- * originally based on code by:
- * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org/ 
- */
-
-
-#include <linux/module.h>
-#include <linux/kmod.h>
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/timer.h>
-#include <linux/poll.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/firmware.h>
-#include <linux/crc32.h>
-#include <linux/i2c.h>
-#include <linux/kthread.h>
-#include <linux/slab.h>
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
-
-
-#include <linux/dvb/frontend.h>
-
-#include "dvb_frontend.h"
-
-#include "ttpci-eeprom.h"
-#include "av7110.h"
-#include "av7110_hw.h"
-#include "av7110_av.h"
-#include "av7110_ca.h"
-#include "av7110_ipack.h"
-
-#include "bsbe1.h"
-#include "lnbp21.h"
-#include "bsru6.h"
-
-#define TS_WIDTH  376
-#define TS_HEIGHT 512
-#define TS_BUFLEN (TS_WIDTH*TS_HEIGHT)
-#define TS_MAX_PACKETS (TS_BUFLEN/TS_SIZE)
-
-
-int av7110_debug;
-
-static int vidmode = CVBS_RGB_OUT;
-static int pids_off;
-static int adac = DVB_ADAC_TI;
-static int hw_sections;
-static int rgb_on;
-static int volume = 255;
-static int budgetpatch;
-static int wss_cfg_4_3 = 0x4008;
-static int wss_cfg_16_9 = 0x0007;
-static int tv_standard;
-static int full_ts;
-
-module_param_named(debug, av7110_debug, int, 0644);
-MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)");
-module_param(vidmode, int, 0444);
-MODULE_PARM_DESC(vidmode,"analog video out: 0 off, 1 CVBS+RGB (default), 2 CVBS+YC, 3 YC");
-module_param(pids_off, int, 0444);
-MODULE_PARM_DESC(pids_off,"clear video/audio/PCR PID filters when demux is closed");
-module_param(adac, int, 0444);
-MODULE_PARM_DESC(adac,"audio DAC type: 0 TI, 1 CRYSTAL, 2 MSP (use if autodetection fails)");
-module_param(hw_sections, int, 0444);
-MODULE_PARM_DESC(hw_sections, "0 use software section filter, 1 use hardware");
-module_param(rgb_on, int, 0444);
-MODULE_PARM_DESC(rgb_on, "For Siemens DVB-C cards only: Enable RGB control"
-		" signal on SCART pin 16 to switch SCART video mode from CVBS to RGB");
-module_param(volume, int, 0444);
-MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)");
-module_param(budgetpatch, int, 0444);
-MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)");
-module_param(full_ts, int, 0444);
-MODULE_PARM_DESC(full_ts, "enable code for full-ts hardware modification: 0 disable (default), 1 enable");
-module_param(wss_cfg_4_3, int, 0444);
-MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data");
-module_param(wss_cfg_16_9, int, 0444);
-MODULE_PARM_DESC(wss_cfg_16_9, "WSS 16:9 - default 0x0007 - bit 15: disable, 14: burst mode, 13..0: wss data");
-module_param(tv_standard, int, 0444);
-MODULE_PARM_DESC(tv_standard, "TV standard: 0 PAL (default), 1 NTSC");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static void restart_feeds(struct av7110 *av7110);
-static int budget_start_feed(struct dvb_demux_feed *feed);
-static int budget_stop_feed(struct dvb_demux_feed *feed);
-
-static int av7110_num;
-
-#define FE_FUNC_OVERRIDE(fe_func, av7110_copy, av7110_func) \
-{\
-	if (fe_func != NULL) { \
-		av7110_copy = fe_func; \
-		fe_func = av7110_func; \
-	} \
-}
-
-
-static void init_av7110_av(struct av7110 *av7110)
-{
-	int ret;
-	struct saa7146_dev *dev = av7110->dev;
-
-	/* set internal volume control to maximum */
-	av7110->adac_type = DVB_ADAC_TI;
-	ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
-	if (ret < 0)
-		printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret);
-
-	ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType,
-			    1, (u16) av7110->display_ar);
-	if (ret < 0)
-		printk("dvb-ttpci: unable to set aspect ratio\n");
-	ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
-			    1, av7110->display_panscan);
-	if (ret < 0)
-		printk("dvb-ttpci: unable to set pan scan\n");
-
-	ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 2, wss_cfg_4_3);
-	if (ret < 0)
-		printk("dvb-ttpci: unable to configure 4:3 wss\n");
-	ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 3, wss_cfg_16_9);
-	if (ret < 0)
-		printk("dvb-ttpci: unable to configure 16:9 wss\n");
-
-	ret = av7710_set_video_mode(av7110, vidmode);
-	if (ret < 0)
-		printk("dvb-ttpci:cannot set video mode:%d\n",ret);
-
-	/* handle different card types */
-	/* remaining inits according to card and frontend type */
-	av7110->analog_tuner_flags = 0;
-	av7110->current_input = 0;
-	if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a)
-		av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on
-	if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
-		printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n",
-			av7110->dvb_adapter.num);
-		av7110->adac_type = DVB_ADAC_CRYSTAL;
-		i2c_writereg(av7110, 0x20, 0x01, 0xd2);
-		i2c_writereg(av7110, 0x20, 0x02, 0x49);
-		i2c_writereg(av7110, 0x20, 0x03, 0x00);
-		i2c_writereg(av7110, 0x20, 0x04, 0x00);
-
-		/**
-		 * some special handling for the Siemens DVB-C cards...
-		 */
-	} else if (0 == av7110_init_analog_module(av7110)) {
-		/* done. */
-	}
-	else if (dev->pci->subsystem_vendor == 0x110a) {
-		printk("dvb-ttpci: DVB-C w/o analog module @ card %d detected\n",
-			av7110->dvb_adapter.num);
-		av7110->adac_type = DVB_ADAC_NONE;
-	}
-	else {
-		av7110->adac_type = adac;
-		printk("dvb-ttpci: adac type set to %d @ card %d\n",
-			av7110->adac_type, av7110->dvb_adapter.num);
-	}
-
-	if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP34x0) {
-		// switch DVB SCART on
-		ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);
-		if (ret < 0)
-			printk("dvb-ttpci:cannot switch on SCART(Main):%d\n",ret);
-		ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1);
-		if (ret < 0)
-			printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret);
-		if (rgb_on &&
-		    ((av7110->dev->pci->subsystem_vendor == 0x110a) ||
-		     (av7110->dev->pci->subsystem_vendor == 0x13c2)) &&
-		     (av7110->dev->pci->subsystem_device == 0x0000)) {
-			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16
-			//saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // SCARTpin 8
-		}
-	}
-
-	if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000e)
-		av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, SpdifSwitch, 1, 0); // SPDIF on
-
-	ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
-	if (ret < 0)
-		printk("dvb-ttpci:cannot set volume :%d\n",ret);
-}
-
-static void recover_arm(struct av7110 *av7110)
-{
-	dprintk(4, "%p\n",av7110);
-
-	av7110_bootarm(av7110);
-	msleep(100);
-
-	init_av7110_av(av7110);
-
-	/* card-specific recovery */
-	if (av7110->recover)
-		av7110->recover(av7110);
-
-	restart_feeds(av7110);
-
-#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
-	av7110_check_ir_config(av7110, true);
-#endif
-}
-
-static void av7110_arm_sync(struct av7110 *av7110)
-{
-	if (av7110->arm_thread)
-		kthread_stop(av7110->arm_thread);
-
-	av7110->arm_thread = NULL;
-}
-
-static int arm_thread(void *data)
-{
-	struct av7110 *av7110 = data;
-	u16 newloops = 0;
-	int timeout;
-
-	dprintk(4, "%p\n",av7110);
-
-	for (;;) {
-		timeout = wait_event_interruptible_timeout(av7110->arm_wait,
-			kthread_should_stop(), 5 * HZ);
-
-		if (-ERESTARTSYS == timeout || kthread_should_stop()) {
-			/* got signal or told to quit*/
-			break;
-		}
-
-		if (!av7110->arm_ready)
-			continue;
-
-#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
-		av7110_check_ir_config(av7110, false);
-#endif
-
-		if (mutex_lock_interruptible(&av7110->dcomlock))
-			break;
-		newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
-		mutex_unlock(&av7110->dcomlock);
-
-		if (newloops == av7110->arm_loops || av7110->arm_errors > 3) {
-			printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n",
-			       av7110->dvb_adapter.num);
-
-			recover_arm(av7110);
-
-			if (mutex_lock_interruptible(&av7110->dcomlock))
-				break;
-			newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1;
-			mutex_unlock(&av7110->dcomlock);
-		}
-		av7110->arm_loops = newloops;
-		av7110->arm_errors = 0;
-	}
-
-	return 0;
-}
-
-
-/****************************************************************************
- * IRQ handling
- ****************************************************************************/
-
-static int DvbDmxFilterCallback(u8 *buffer1, size_t buffer1_len,
-				u8 *buffer2, size_t buffer2_len,
-				struct dvb_demux_filter *dvbdmxfilter,
-				enum dmx_success success,
-				struct av7110 *av7110)
-{
-	if (!dvbdmxfilter->feed->demux->dmx.frontend)
-		return 0;
-	if (dvbdmxfilter->feed->demux->dmx.frontend->source == DMX_MEMORY_FE)
-		return 0;
-
-	switch (dvbdmxfilter->type) {
-	case DMX_TYPE_SEC:
-		if ((((buffer1[1] << 8) | buffer1[2]) & 0xfff) + 3 != buffer1_len)
-			return 0;
-		if (dvbdmxfilter->doneq) {
-			struct dmx_section_filter *filter = &dvbdmxfilter->filter;
-			int i;
-			u8 xor, neq = 0;
-
-			for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
-				xor = filter->filter_value[i] ^ buffer1[i];
-				neq |= dvbdmxfilter->maskandnotmode[i] & xor;
-			}
-			if (!neq)
-				return 0;
-		}
-		return dvbdmxfilter->feed->cb.sec(buffer1, buffer1_len,
-						  buffer2, buffer2_len,
-						  &dvbdmxfilter->filter,
-						  DMX_OK);
-	case DMX_TYPE_TS:
-		if (!(dvbdmxfilter->feed->ts_type & TS_PACKET))
-			return 0;
-		if (dvbdmxfilter->feed->ts_type & TS_PAYLOAD_ONLY)
-			return dvbdmxfilter->feed->cb.ts(buffer1, buffer1_len,
-							 buffer2, buffer2_len,
-							 &dvbdmxfilter->feed->feed.ts,
-							 DMX_OK);
-		else
-			av7110_p2t_write(buffer1, buffer1_len,
-					 dvbdmxfilter->feed->pid,
-					 &av7110->p2t_filter[dvbdmxfilter->index]);
-	default:
-		return 0;
-	}
-}
-
-
-//#define DEBUG_TIMING
-static inline void print_time(char *s)
-{
-#ifdef DEBUG_TIMING
-	struct timeval tv;
-	do_gettimeofday(&tv);
-	printk("%s: %d.%d\n", s, (int)tv.tv_sec, (int)tv.tv_usec);
-#endif
-}
-
-#define DEBI_READ 0
-#define DEBI_WRITE 1
-static inline void start_debi_dma(struct av7110 *av7110, int dir,
-				  unsigned long addr, unsigned int len)
-{
-	dprintk(8, "%c %08lx %u\n", dir == DEBI_READ ? 'R' : 'W', addr, len);
-	if (saa7146_wait_for_debi_done(av7110->dev, 0)) {
-		printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__);
-		return;
-	}
-
-	SAA7146_ISR_CLEAR(av7110->dev, MASK_19); /* for good measure */
-	SAA7146_IER_ENABLE(av7110->dev, MASK_19);
-	if (len < 5)
-		len = 5; /* we want a real DEBI DMA */
-	if (dir == DEBI_WRITE)
-		iwdebi(av7110, DEBISWAB, addr, 0, (len + 3) & ~3);
-	else
-		irdebi(av7110, DEBISWAB, addr, 0, len);
-}
-
-static void debiirq(unsigned long cookie)
-{
-	struct av7110 *av7110 = (struct av7110 *)cookie;
-	int type = av7110->debitype;
-	int handle = (type >> 8) & 0x1f;
-	unsigned int xfer = 0;
-
-	print_time("debi");
-	dprintk(4, "type 0x%04x\n", type);
-
-	if (type == -1) {
-		printk("DEBI irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n",
-		       jiffies, saa7146_read(av7110->dev, PSR),
-		       saa7146_read(av7110->dev, SSR));
-		goto debi_done;
-	}
-	av7110->debitype = -1;
-
-	switch (type & 0xff) {
-
-	case DATA_TS_RECORD:
-		dvb_dmx_swfilter_packets(&av7110->demux,
-					 (const u8 *) av7110->debi_virt,
-					 av7110->debilen / 188);
-		xfer = RX_BUFF;
-		break;
-
-	case DATA_PES_RECORD:
-		if (av7110->demux.recording)
-			av7110_record_cb(&av7110->p2t[handle],
-					 (u8 *) av7110->debi_virt,
-					 av7110->debilen);
-		xfer = RX_BUFF;
-		break;
-
-	case DATA_IPMPE:
-	case DATA_FSECTION:
-	case DATA_PIPING:
-		if (av7110->handle2filter[handle])
-			DvbDmxFilterCallback((u8 *)av7110->debi_virt,
-					     av7110->debilen, NULL, 0,
-					     av7110->handle2filter[handle],
-					     DMX_OK, av7110);
-		xfer = RX_BUFF;
-		break;
-
-	case DATA_CI_GET:
-	{
-		u8 *data = av7110->debi_virt;
-
-		if ((data[0] < 2) && data[2] == 0xff) {
-			int flags = 0;
-			if (data[5] > 0)
-				flags |= CA_CI_MODULE_PRESENT;
-			if (data[5] > 5)
-				flags |= CA_CI_MODULE_READY;
-			av7110->ci_slot[data[0]].flags = flags;
-		} else
-			ci_get_data(&av7110->ci_rbuffer,
-				    av7110->debi_virt,
-				    av7110->debilen);
-		xfer = RX_BUFF;
-		break;
-	}
-
-	case DATA_COMMON_INTERFACE:
-		CI_handle(av7110, (u8 *)av7110->debi_virt, av7110->debilen);
-#if 0
-	{
-		int i;
-
-		printk("av7110%d: ", av7110->num);
-		printk("%02x ", *(u8 *)av7110->debi_virt);
-		printk("%02x ", *(1+(u8 *)av7110->debi_virt));
-		for (i = 2; i < av7110->debilen; i++)
-			printk("%02x ", (*(i+(unsigned char *)av7110->debi_virt)));
-		for (i = 2; i < av7110->debilen; i++)
-			printk("%c", chtrans(*(i+(unsigned char *)av7110->debi_virt)));
-
-		printk("\n");
-	}
-#endif
-		xfer = RX_BUFF;
-		break;
-
-	case DATA_DEBUG_MESSAGE:
-		((s8*)av7110->debi_virt)[Reserved_SIZE - 1] = 0;
-		printk("%s\n", (s8 *) av7110->debi_virt);
-		xfer = RX_BUFF;
-		break;
-
-	case DATA_CI_PUT:
-		dprintk(4, "debi DATA_CI_PUT\n");
-	case DATA_MPEG_PLAY:
-		dprintk(4, "debi DATA_MPEG_PLAY\n");
-	case DATA_BMP_LOAD:
-		dprintk(4, "debi DATA_BMP_LOAD\n");
-		xfer = TX_BUFF;
-		break;
-	default:
-		break;
-	}
-debi_done:
-	spin_lock(&av7110->debilock);
-	if (xfer)
-		iwdebi(av7110, DEBINOSWAP, xfer, 0, 2);
-	ARM_ClearMailBox(av7110);
-	spin_unlock(&av7110->debilock);
-}
-
-/* irq from av7110 firmware writing the mailbox register in the DPRAM */
-static void gpioirq(unsigned long cookie)
-{
-	struct av7110 *av7110 = (struct av7110 *)cookie;
-	u32 rxbuf, txbuf;
-	int len;
-
-	if (av7110->debitype != -1)
-		/* we shouldn't get any irq while a debi xfer is running */
-		printk("dvb-ttpci: GPIO0 irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n",
-		       jiffies, saa7146_read(av7110->dev, PSR),
-		       saa7146_read(av7110->dev, SSR));
-
-	if (saa7146_wait_for_debi_done(av7110->dev, 0)) {
-		printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__);
-		BUG(); /* maybe we should try resetting the debi? */
-	}
-
-	spin_lock(&av7110->debilock);
-	ARM_ClearIrq(av7110);
-
-	/* see what the av7110 wants */
-	av7110->debitype = irdebi(av7110, DEBINOSWAP, IRQ_STATE, 0, 2);
-	av7110->debilen  = irdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
-	rxbuf = irdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
-	txbuf = irdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
-	len = (av7110->debilen + 3) & ~3;
-
-	print_time("gpio");
-	dprintk(8, "GPIO0 irq 0x%04x %d\n", av7110->debitype, av7110->debilen);
-
-	switch (av7110->debitype & 0xff) {
-
-	case DATA_TS_PLAY:
-	case DATA_PES_PLAY:
-		break;
-
-	case DATA_MPEG_VIDEO_EVENT:
-	{
-		u32 h_ar;
-		struct video_event event;
-
-		av7110->video_size.w = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_WIDTH, 0, 2);
-		h_ar = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_HEIGHT_AR, 0, 2);
-
-		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
-		iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
-
-		av7110->video_size.h = h_ar & 0xfff;
-
-		event.type = VIDEO_EVENT_SIZE_CHANGED;
-		event.u.size.w = av7110->video_size.w;
-		event.u.size.h = av7110->video_size.h;
-		switch ((h_ar >> 12) & 0xf)
-		{
-		case 3:
-			av7110->video_size.aspect_ratio = VIDEO_FORMAT_16_9;
-			event.u.size.aspect_ratio = VIDEO_FORMAT_16_9;
-			av7110->videostate.video_format = VIDEO_FORMAT_16_9;
-			break;
-		case 4:
-			av7110->video_size.aspect_ratio = VIDEO_FORMAT_221_1;
-			event.u.size.aspect_ratio = VIDEO_FORMAT_221_1;
-			av7110->videostate.video_format = VIDEO_FORMAT_221_1;
-			break;
-		default:
-			av7110->video_size.aspect_ratio = VIDEO_FORMAT_4_3;
-			event.u.size.aspect_ratio = VIDEO_FORMAT_4_3;
-			av7110->videostate.video_format = VIDEO_FORMAT_4_3;
-		}
-
-		dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",
-			av7110->video_size.w, av7110->video_size.h,
-			av7110->video_size.aspect_ratio);
-
-		dvb_video_add_event(av7110, &event);
-		break;
-	}
-
-	case DATA_CI_PUT:
-	{
-		int avail;
-		struct dvb_ringbuffer *cibuf = &av7110->ci_wbuffer;
-
-		avail = dvb_ringbuffer_avail(cibuf);
-		if (avail <= 2) {
-			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
-			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
-			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
-			break;
-		}
-		len = DVB_RINGBUFFER_PEEK(cibuf, 0) << 8;
-		len |= DVB_RINGBUFFER_PEEK(cibuf, 1);
-		if (avail < len + 2) {
-			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
-			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
-			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
-			break;
-		}
-		DVB_RINGBUFFER_SKIP(cibuf, 2);
-
-		dvb_ringbuffer_read(cibuf, av7110->debi_virt, len);
-
-		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
-		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
-		dprintk(8, "DMA: CI\n");
-		start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len);
-		spin_unlock(&av7110->debilock);
-		wake_up(&cibuf->queue);
-		return;
-	}
-
-	case DATA_MPEG_PLAY:
-		if (!av7110->playing) {
-			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
-			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
-			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
-			break;
-		}
-		len = 0;
-		if (av7110->debitype & 0x100) {
-			spin_lock(&av7110->aout.lock);
-			len = av7110_pes_play(av7110->debi_virt, &av7110->aout, 2048);
-			spin_unlock(&av7110->aout.lock);
-		}
-		if (len <= 0 && (av7110->debitype & 0x200)
-		    &&av7110->videostate.play_state != VIDEO_FREEZED) {
-			spin_lock(&av7110->avout.lock);
-			len = av7110_pes_play(av7110->debi_virt, &av7110->avout, 2048);
-			spin_unlock(&av7110->avout.lock);
-		}
-		if (len <= 0) {
-			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
-			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
-			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
-			break;
-		}
-		dprintk(8, "GPIO0 PES_PLAY len=%04x\n", len);
-		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
-		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
-		dprintk(8, "DMA: MPEG_PLAY\n");
-		start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len);
-		spin_unlock(&av7110->debilock);
-		return;
-
-	case DATA_BMP_LOAD:
-		len = av7110->debilen;
-		dprintk(8, "gpio DATA_BMP_LOAD len %d\n", len);
-		if (!len) {
-			av7110->bmp_state = BMP_LOADED;
-			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
-			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
-			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
-			wake_up(&av7110->bmpq);
-			dprintk(8, "gpio DATA_BMP_LOAD done\n");
-			break;
-		}
-		if (len > av7110->bmplen)
-			len = av7110->bmplen;
-		if (len > 2 * 1024)
-			len = 2 * 1024;
-		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
-		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
-		memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len);
-		av7110->bmpp += len;
-		av7110->bmplen -= len;
-		dprintk(8, "gpio DATA_BMP_LOAD DMA len %d\n", len);
-		start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE+txbuf, len);
-		spin_unlock(&av7110->debilock);
-		return;
-
-	case DATA_CI_GET:
-	case DATA_COMMON_INTERFACE:
-	case DATA_FSECTION:
-	case DATA_IPMPE:
-	case DATA_PIPING:
-		if (!len || len > 4 * 1024) {
-			iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
-			break;
-		}
-		/* fall through */
-
-	case DATA_TS_RECORD:
-	case DATA_PES_RECORD:
-		dprintk(8, "DMA: TS_REC etc.\n");
-		start_debi_dma(av7110, DEBI_READ, DPRAM_BASE+rxbuf, len);
-		spin_unlock(&av7110->debilock);
-		return;
-
-	case DATA_DEBUG_MESSAGE:
-		if (!len || len > 0xff) {
-			iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
-			break;
-		}
-		start_debi_dma(av7110, DEBI_READ, Reserved, len);
-		spin_unlock(&av7110->debilock);
-		return;
-
-	case DATA_IRCOMMAND:
-		if (av7110->ir.ir_handler)
-			av7110->ir.ir_handler(av7110,
-				swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4)));
-		iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
-		break;
-
-	default:
-		printk("dvb-ttpci: gpioirq unknown type=%d len=%d\n",
-		       av7110->debitype, av7110->debilen);
-		break;
-	}
-	av7110->debitype = -1;
-	ARM_ClearMailBox(av7110);
-	spin_unlock(&av7110->debilock);
-}
-
-
-#ifdef CONFIG_DVB_AV7110_OSD
-static int dvb_osd_ioctl(struct file *file,
-			 unsigned int cmd, void *parg)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct av7110 *av7110 = dvbdev->priv;
-
-	dprintk(4, "%p\n", av7110);
-
-	if (cmd == OSD_SEND_CMD)
-		return av7110_osd_cmd(av7110, (osd_cmd_t *) parg);
-	if (cmd == OSD_GET_CAPABILITY)
-		return av7110_osd_capability(av7110, (osd_cap_t *) parg);
-
-	return -EINVAL;
-}
-
-
-static const struct file_operations dvb_osd_fops = {
-	.owner		= THIS_MODULE,
-	.unlocked_ioctl	= dvb_generic_ioctl,
-	.open		= dvb_generic_open,
-	.release	= dvb_generic_release,
-	.llseek		= noop_llseek,
-};
-
-static struct dvb_device dvbdev_osd = {
-	.priv		= NULL,
-	.users		= 1,
-	.writers	= 1,
-	.fops		= &dvb_osd_fops,
-	.kernel_ioctl	= dvb_osd_ioctl,
-};
-#endif /* CONFIG_DVB_AV7110_OSD */
-
-
-static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
-			  u16 subpid, u16 pcrpid)
-{
-	u16 aflags = 0;
-
-	dprintk(4, "%p\n", av7110);
-
-	if (vpid == 0x1fff || apid == 0x1fff ||
-	    ttpid == 0x1fff || subpid == 0x1fff || pcrpid == 0x1fff) {
-		vpid = apid = ttpid = subpid = pcrpid = 0;
-		av7110->pids[DMX_PES_VIDEO] = 0;
-		av7110->pids[DMX_PES_AUDIO] = 0;
-		av7110->pids[DMX_PES_TELETEXT] = 0;
-		av7110->pids[DMX_PES_PCR] = 0;
-	}
-
-	if (av7110->audiostate.bypass_mode)
-		aflags |= 0x8000;
-
-	return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 6,
-			     pcrpid, vpid, apid, ttpid, subpid, aflags);
-}
-
-int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
-		u16 subpid, u16 pcrpid)
-{
-	int ret = 0;
-	dprintk(4, "%p\n", av7110);
-
-	if (mutex_lock_interruptible(&av7110->pid_mutex))
-		return -ERESTARTSYS;
-
-	if (!(vpid & 0x8000))
-		av7110->pids[DMX_PES_VIDEO] = vpid;
-	if (!(apid & 0x8000))
-		av7110->pids[DMX_PES_AUDIO] = apid;
-	if (!(ttpid & 0x8000))
-		av7110->pids[DMX_PES_TELETEXT] = ttpid;
-	if (!(pcrpid & 0x8000))
-		av7110->pids[DMX_PES_PCR] = pcrpid;
-
-	av7110->pids[DMX_PES_SUBTITLE] = 0;
-
-	if (av7110->fe_synced) {
-		pcrpid = av7110->pids[DMX_PES_PCR];
-		ret = SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid);
-	}
-
-	mutex_unlock(&av7110->pid_mutex);
-	return ret;
-}
-
-
-/******************************************************************************
- * hardware filter functions
- ******************************************************************************/
-
-static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter)
-{
-	struct dvb_demux_feed *dvbdmxfeed = dvbdmxfilter->feed;
-	struct av7110 *av7110 = dvbdmxfeed->demux->priv;
-	u16 buf[20];
-	int ret, i;
-	u16 handle;
-//	u16 mode = 0x0320;
-	u16 mode = 0xb96a;
-
-	dprintk(4, "%p\n", av7110);
-
-	if (av7110->full_ts)
-		return 0;
-
-	if (dvbdmxfilter->type == DMX_TYPE_SEC) {
-		if (hw_sections) {
-			buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) |
-				dvbdmxfilter->maskandmode[0];
-			for (i = 3; i < 18; i++)
-				buf[i + 4 - 2] =
-					(dvbdmxfilter->filter.filter_value[i] << 8) |
-					dvbdmxfilter->maskandmode[i];
-			mode = 4;
-		}
-	} else if ((dvbdmxfeed->ts_type & TS_PACKET) &&
-		   !(dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)) {
-		av7110_p2t_init(&av7110->p2t_filter[dvbdmxfilter->index], dvbdmxfeed);
-	}
-
-	buf[0] = (COMTYPE_PID_FILTER << 8) + AddPIDFilter;
-	buf[1] = 16;
-	buf[2] = dvbdmxfeed->pid;
-	buf[3] = mode;
-
-	ret = av7110_fw_request(av7110, buf, 20, &handle, 1);
-	if (ret != 0 || handle >= 32) {
-		printk("dvb-ttpci: %s error  buf %04x %04x %04x %04x  "
-				"ret %d  handle %04x\n",
-				__func__, buf[0], buf[1], buf[2], buf[3],
-				ret, handle);
-		dvbdmxfilter->hw_handle = 0xffff;
-		if (!ret)
-			ret = -1;
-		return ret;
-	}
-
-	av7110->handle2filter[handle] = dvbdmxfilter;
-	dvbdmxfilter->hw_handle = handle;
-
-	return ret;
-}
-
-static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
-{
-	struct av7110 *av7110 = dvbdmxfilter->feed->demux->priv;
-	u16 buf[3];
-	u16 answ[2];
-	int ret;
-	u16 handle;
-
-	dprintk(4, "%p\n", av7110);
-
-	if (av7110->full_ts)
-		return 0;
-
-	handle = dvbdmxfilter->hw_handle;
-	if (handle >= 32) {
-		printk("%s tried to stop invalid filter %04x, filter type = %x\n",
-				__func__, handle, dvbdmxfilter->type);
-		return -EINVAL;
-	}
-
-	av7110->handle2filter[handle] = NULL;
-
-	buf[0] = (COMTYPE_PID_FILTER << 8) + DelPIDFilter;
-	buf[1] = 1;
-	buf[2] = handle;
-	ret = av7110_fw_request(av7110, buf, 3, answ, 2);
-	if (ret != 0 || answ[1] != handle) {
-		printk("dvb-ttpci: %s error  cmd %04x %04x %04x  ret %x  "
-				"resp %04x %04x  pid %d\n",
-				__func__, buf[0], buf[1], buf[2], ret,
-				answ[0], answ[1], dvbdmxfilter->feed->pid);
-		if (!ret)
-			ret = -1;
-	}
-	return ret;
-}
-
-
-static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-	struct av7110 *av7110 = dvbdmx->priv;
-	u16 *pid = dvbdmx->pids, npids[5];
-	int i;
-	int ret = 0;
-
-	dprintk(4, "%p\n", av7110);
-
-	npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff;
-	i = dvbdmxfeed->pes_type;
-	npids[i] = (pid[i]&0x8000) ? 0 : pid[i];
-	if ((i == 2) && npids[i] && (dvbdmxfeed->ts_type & TS_PACKET)) {
-		npids[i] = 0;
-		ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
-		if (!ret)
-			ret = StartHWFilter(dvbdmxfeed->filter);
-		return ret;
-	}
-	if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4) {
-		ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
-		if (ret)
-			return ret;
-	}
-
-	if (dvbdmxfeed->pes_type < 2 && npids[0])
-		if (av7110->fe_synced)
-		{
-			ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
-			if (ret)
-				return ret;
-		}
-
-	if ((dvbdmxfeed->ts_type & TS_PACKET) && !av7110->full_ts) {
-		if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000))
-			ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed);
-		if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000))
-			ret = av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed);
-	}
-	return ret;
-}
-
-static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-	struct av7110 *av7110 = dvbdmx->priv;
-	u16 *pid = dvbdmx->pids, npids[5];
-	int i;
-
-	int ret = 0;
-
-	dprintk(4, "%p\n", av7110);
-
-	if (dvbdmxfeed->pes_type <= 1) {
-		ret = av7110_av_stop(av7110, dvbdmxfeed->pes_type ?  RP_VIDEO : RP_AUDIO);
-		if (ret)
-			return ret;
-		if (!av7110->rec_mode)
-			dvbdmx->recording = 0;
-		if (!av7110->playing)
-			dvbdmx->playing = 0;
-	}
-	npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff;
-	i = dvbdmxfeed->pes_type;
-	switch (i) {
-	case 2: //teletext
-		if (dvbdmxfeed->ts_type & TS_PACKET)
-			ret = StopHWFilter(dvbdmxfeed->filter);
-		npids[2] = 0;
-		break;
-	case 0:
-	case 1:
-	case 4:
-		if (!pids_off)
-			return 0;
-		npids[i] = (pid[i]&0x8000) ? 0 : pid[i];
-		break;
-	}
-	if (!ret)
-		ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
-	return ret;
-}
-
-static int av7110_start_feed(struct dvb_demux_feed *feed)
-{
-	struct dvb_demux *demux = feed->demux;
-	struct av7110 *av7110 = demux->priv;
-	int ret = 0;
-
-	dprintk(4, "%p\n", av7110);
-
-	if (!demux->dmx.frontend)
-		return -EINVAL;
-
-	if (!av7110->full_ts && feed->pid > 0x1fff)
-		return -EINVAL;
-
-	if (feed->type == DMX_TYPE_TS) {
-		if ((feed->ts_type & TS_DECODER) &&
-		    (feed->pes_type <= DMX_TS_PES_PCR)) {
-			switch (demux->dmx.frontend->source) {
-			case DMX_MEMORY_FE:
-				if (feed->ts_type & TS_DECODER)
-				       if (feed->pes_type < 2 &&
-					   !(demux->pids[0] & 0x8000) &&
-					   !(demux->pids[1] & 0x8000)) {
-					       dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
-					       dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
-					       ret = av7110_av_start_play(av7110,RP_AV);
-					       if (!ret)
-						       demux->playing = 1;
-					}
-				break;
-			default:
-				ret = dvb_feed_start_pid(feed);
-				break;
-			}
-		} else if ((feed->ts_type & TS_PACKET) &&
-			   (demux->dmx.frontend->source != DMX_MEMORY_FE)) {
-			ret = StartHWFilter(feed->filter);
-		}
-	}
-
-	if (av7110->full_ts) {
-		budget_start_feed(feed);
-		return ret;
-	}
-
-	if (feed->type == DMX_TYPE_SEC) {
-		int i;
-
-		for (i = 0; i < demux->filternum; i++) {
-			if (demux->filter[i].state != DMX_STATE_READY)
-				continue;
-			if (demux->filter[i].type != DMX_TYPE_SEC)
-				continue;
-			if (demux->filter[i].filter.parent != &feed->feed.sec)
-				continue;
-			demux->filter[i].state = DMX_STATE_GO;
-			if (demux->dmx.frontend->source != DMX_MEMORY_FE) {
-				ret = StartHWFilter(&demux->filter[i]);
-				if (ret)
-					break;
-			}
-		}
-	}
-
-	return ret;
-}
-
-
-static int av7110_stop_feed(struct dvb_demux_feed *feed)
-{
-	struct dvb_demux *demux = feed->demux;
-	struct av7110 *av7110 = demux->priv;
-	int i, rc, ret = 0;
-	dprintk(4, "%p\n", av7110);
-
-	if (feed->type == DMX_TYPE_TS) {
-		if (feed->ts_type & TS_DECODER) {
-			if (feed->pes_type >= DMX_TS_PES_OTHER ||
-			    !demux->pesfilter[feed->pes_type])
-				return -EINVAL;
-			demux->pids[feed->pes_type] |= 0x8000;
-			demux->pesfilter[feed->pes_type] = NULL;
-		}
-		if (feed->ts_type & TS_DECODER &&
-		    feed->pes_type < DMX_TS_PES_OTHER) {
-			ret = dvb_feed_stop_pid(feed);
-		} else
-			if ((feed->ts_type & TS_PACKET) &&
-			    (demux->dmx.frontend->source != DMX_MEMORY_FE))
-				ret = StopHWFilter(feed->filter);
-	}
-
-	if (av7110->full_ts) {
-		budget_stop_feed(feed);
-		return ret;
-	}
-
-	if (feed->type == DMX_TYPE_SEC) {
-		for (i = 0; i<demux->filternum; i++) {
-			if (demux->filter[i].state == DMX_STATE_GO &&
-			    demux->filter[i].filter.parent == &feed->feed.sec) {
-				demux->filter[i].state = DMX_STATE_READY;
-				if (demux->dmx.frontend->source != DMX_MEMORY_FE) {
-					rc = StopHWFilter(&demux->filter[i]);
-					if (!ret)
-						ret = rc;
-					/* keep going, stop as many filters as possible */
-				}
-			}
-		}
-	}
-
-	return ret;
-}
-
-
-static void restart_feeds(struct av7110 *av7110)
-{
-	struct dvb_demux *dvbdmx = &av7110->demux;
-	struct dvb_demux_feed *feed;
-	int mode;
-	int feeding;
-	int i, j;
-
-	dprintk(4, "%p\n", av7110);
-
-	mode = av7110->playing;
-	av7110->playing = 0;
-	av7110->rec_mode = 0;
-
-	feeding = av7110->feeding1; /* full_ts mod */
-
-	for (i = 0; i < dvbdmx->feednum; i++) {
-		feed = &dvbdmx->feed[i];
-		if (feed->state == DMX_STATE_GO) {
-			if (feed->type == DMX_TYPE_SEC) {
-				for (j = 0; j < dvbdmx->filternum; j++) {
-					if (dvbdmx->filter[j].type != DMX_TYPE_SEC)
-						continue;
-					if (dvbdmx->filter[j].filter.parent != &feed->feed.sec)
-						continue;
-					if (dvbdmx->filter[j].state == DMX_STATE_GO)
-						dvbdmx->filter[j].state = DMX_STATE_READY;
-				}
-			}
-			av7110_start_feed(feed);
-		}
-	}
-
-	av7110->feeding1 = feeding; /* full_ts mod */
-
-	if (mode)
-		av7110_av_start_play(av7110, mode);
-}
-
-static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
-		       uint64_t *stc, unsigned int *base)
-{
-	int ret;
-	u16 fwstc[4];
-	u16 tag = ((COMTYPE_REQUEST << 8) + ReqSTC);
-	struct dvb_demux *dvbdemux;
-	struct av7110 *av7110;
-
-	/* pointer casting paranoia... */
-	BUG_ON(!demux);
-	dvbdemux = demux->priv;
-	BUG_ON(!dvbdemux);
-	av7110 = dvbdemux->priv;
-
-	dprintk(4, "%p\n", av7110);
-
-	if (num != 0)
-		return -EINVAL;
-
-	ret = av7110_fw_request(av7110, &tag, 0, fwstc, 4);
-	if (ret) {
-		printk(KERN_ERR "%s: av7110_fw_request error\n", __func__);
-		return ret;
-	}
-	dprintk(2, "fwstc = %04hx %04hx %04hx %04hx\n",
-		fwstc[0], fwstc[1], fwstc[2], fwstc[3]);
-
-	*stc =	(((uint64_t) ((fwstc[3] & 0x8000) >> 15)) << 32) |
-		(((uint64_t)  fwstc[1]) << 16) | ((uint64_t) fwstc[0]);
-	*base = 1;
-
-	dprintk(4, "stc = %lu\n", (unsigned long)*stc);
-
-	return 0;
-}
-
-
-/******************************************************************************
- * SEC device file operations
- ******************************************************************************/
-
-
-static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
-	struct av7110* av7110 = fe->dvb->priv;
-
-	switch (tone) {
-	case SEC_TONE_ON:
-		return Set22K(av7110, 1);
-
-	case SEC_TONE_OFF:
-		return Set22K(av7110, 0);
-
-	default:
-		return -EINVAL;
-	}
-}
-
-static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe,
-					 struct dvb_diseqc_master_cmd* cmd)
-{
-	struct av7110* av7110 = fe->dvb->priv;
-
-	return av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1);
-}
-
-static int av7110_diseqc_send_burst(struct dvb_frontend* fe,
-				    fe_sec_mini_cmd_t minicmd)
-{
-	struct av7110* av7110 = fe->dvb->priv;
-
-	return av7110_diseqc_send(av7110, 0, NULL, minicmd);
-}
-
-/* simplified code from budget-core.c */
-static int stop_ts_capture(struct av7110 *budget)
-{
-	dprintk(2, "budget: %p\n", budget);
-
-	if (--budget->feeding1)
-		return budget->feeding1;
-	saa7146_write(budget->dev, MC1, MASK_20);	/* DMA3 off */
-	SAA7146_IER_DISABLE(budget->dev, MASK_10);
-	SAA7146_ISR_CLEAR(budget->dev, MASK_10);
-	return 0;
-}
-
-static int start_ts_capture(struct av7110 *budget)
-{
-	dprintk(2, "budget: %p\n", budget);
-
-	if (budget->feeding1)
-		return ++budget->feeding1;
-	memset(budget->grabbing, 0x00, TS_BUFLEN);
-	budget->ttbp = 0;
-	SAA7146_ISR_CLEAR(budget->dev, MASK_10);  /* VPE */
-	SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */
-	saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */
-	return ++budget->feeding1;
-}
-
-static int budget_start_feed(struct dvb_demux_feed *feed)
-{
-	struct dvb_demux *demux = feed->demux;
-	struct av7110 *budget = demux->priv;
-	int status;
-
-	dprintk(2, "av7110: %p\n", budget);
-
-	spin_lock(&budget->feedlock1);
-	feed->pusi_seen = 0; /* have a clean section start */
-	status = start_ts_capture(budget);
-	spin_unlock(&budget->feedlock1);
-	return status;
-}
-
-static int budget_stop_feed(struct dvb_demux_feed *feed)
-{
-	struct dvb_demux *demux = feed->demux;
-	struct av7110 *budget = demux->priv;
-	int status;
-
-	dprintk(2, "budget: %p\n", budget);
-
-	spin_lock(&budget->feedlock1);
-	status = stop_ts_capture(budget);
-	spin_unlock(&budget->feedlock1);
-	return status;
-}
-
-static void vpeirq(unsigned long cookie)
-{
-	struct av7110 *budget = (struct av7110 *)cookie;
-	u8 *mem = (u8 *) (budget->grabbing);
-	u32 olddma = budget->ttbp;
-	u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
-	struct dvb_demux *demux = budget->full_ts ? &budget->demux : &budget->demux1;
-
-	/* nearest lower position divisible by 188 */
-	newdma -= newdma % 188;
-
-	if (newdma >= TS_BUFLEN)
-		return;
-
-	budget->ttbp = newdma;
-
-	if (!budget->feeding1 || (newdma == olddma))
-		return;
-
-	/* Ensure streamed PCI data is synced to CPU */
-	pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE);
-
-#if 0
-	/* track rps1 activity */
-	printk("vpeirq: %02x Event Counter 1 0x%04x\n",
-	       mem[olddma],
-	       saa7146_read(budget->dev, EC1R) & 0x3fff);
-#endif
-
-	if (newdma > olddma)
-		/* no wraparound, dump olddma..newdma */
-		dvb_dmx_swfilter_packets(demux, mem + olddma, (newdma - olddma) / 188);
-	else {
-		/* wraparound, dump olddma..buflen and 0..newdma */
-		dvb_dmx_swfilter_packets(demux, mem + olddma, (TS_BUFLEN - olddma) / 188);
-		dvb_dmx_swfilter_packets(demux, mem, newdma / 188);
-	}
-}
-
-static int av7110_register(struct av7110 *av7110)
-{
-	int ret, i;
-	struct dvb_demux *dvbdemux = &av7110->demux;
-	struct dvb_demux *dvbdemux1 = &av7110->demux1;
-
-	dprintk(4, "%p\n", av7110);
-
-	if (av7110->registered)
-		return -1;
-
-	av7110->registered = 1;
-
-	dvbdemux->priv = (void *) av7110;
-
-	for (i = 0; i < 32; i++)
-		av7110->handle2filter[i] = NULL;
-
-	dvbdemux->filternum = (av7110->full_ts) ? 256 : 32;
-	dvbdemux->feednum = (av7110->full_ts) ? 256 : 32;
-	dvbdemux->start_feed = av7110_start_feed;
-	dvbdemux->stop_feed = av7110_stop_feed;
-	dvbdemux->write_to_decoder = av7110_write_to_decoder;
-	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING |
-				      DMX_MEMORY_BASED_FILTERING);
-
-	dvb_dmx_init(&av7110->demux);
-	av7110->demux.dmx.get_stc = dvb_get_stc;
-
-	av7110->dmxdev.filternum = (av7110->full_ts) ? 256 : 32;
-	av7110->dmxdev.demux = &dvbdemux->dmx;
-	av7110->dmxdev.capabilities = 0;
-
-	dvb_dmxdev_init(&av7110->dmxdev, &av7110->dvb_adapter);
-
-	av7110->hw_frontend.source = DMX_FRONTEND_0;
-
-	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &av7110->hw_frontend);
-
-	if (ret < 0)
-		return ret;
-
-	av7110->mem_frontend.source = DMX_MEMORY_FE;
-
-	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &av7110->mem_frontend);
-
-	if (ret < 0)
-		return ret;
-
-	ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx,
-					     &av7110->hw_frontend);
-	if (ret < 0)
-		return ret;
-
-	av7110_av_register(av7110);
-	av7110_ca_register(av7110);
-
-#ifdef CONFIG_DVB_AV7110_OSD
-	dvb_register_device(&av7110->dvb_adapter, &av7110->osd_dev,
-			    &dvbdev_osd, av7110, DVB_DEVICE_OSD);
-#endif
-
-	dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx);
-
-	if (budgetpatch) {
-		/* initialize software demux1 without its own frontend
-		 * demux1 hardware is connected to frontend0 of demux0
-		 */
-		dvbdemux1->priv = (void *) av7110;
-
-		dvbdemux1->filternum = 256;
-		dvbdemux1->feednum = 256;
-		dvbdemux1->start_feed = budget_start_feed;
-		dvbdemux1->stop_feed = budget_stop_feed;
-		dvbdemux1->write_to_decoder = NULL;
-
-		dvbdemux1->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING |
-					       DMX_MEMORY_BASED_FILTERING);
-
-		dvb_dmx_init(&av7110->demux1);
-
-		av7110->dmxdev1.filternum = 256;
-		av7110->dmxdev1.demux = &dvbdemux1->dmx;
-		av7110->dmxdev1.capabilities = 0;
-
-		dvb_dmxdev_init(&av7110->dmxdev1, &av7110->dvb_adapter);
-
-		dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net1, &dvbdemux1->dmx);
-		printk("dvb-ttpci: additional demux1 for budget-patch registered\n");
-	}
-	return 0;
-}
-
-
-static void dvb_unregister(struct av7110 *av7110)
-{
-	struct dvb_demux *dvbdemux = &av7110->demux;
-	struct dvb_demux *dvbdemux1 = &av7110->demux1;
-
-	dprintk(4, "%p\n", av7110);
-
-	if (!av7110->registered)
-		return;
-
-	if (budgetpatch) {
-		dvb_net_release(&av7110->dvb_net1);
-		dvbdemux->dmx.close(&dvbdemux1->dmx);
-		dvb_dmxdev_release(&av7110->dmxdev1);
-		dvb_dmx_release(&av7110->demux1);
-	}
-
-	dvb_net_release(&av7110->dvb_net);
-
-	dvbdemux->dmx.close(&dvbdemux->dmx);
-	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->hw_frontend);
-	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->mem_frontend);
-
-	dvb_dmxdev_release(&av7110->dmxdev);
-	dvb_dmx_release(&av7110->demux);
-
-	if (av7110->fe != NULL) {
-		dvb_unregister_frontend(av7110->fe);
-		dvb_frontend_detach(av7110->fe);
-	}
-	dvb_unregister_device(av7110->osd_dev);
-	av7110_av_unregister(av7110);
-	av7110_ca_unregister(av7110);
-}
-
-
-/****************************************************************************
- * I2C client commands
- ****************************************************************************/
-
-int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val)
-{
-	u8 msg[2] = { reg, val };
-	struct i2c_msg msgs;
-
-	msgs.flags = 0;
-	msgs.addr = id / 2;
-	msgs.len = 2;
-	msgs.buf = msg;
-	return i2c_transfer(&av7110->i2c_adap, &msgs, 1);
-}
-
-u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg)
-{
-	u8 mm1[] = {0x00};
-	u8 mm2[] = {0x00};
-	struct i2c_msg msgs[2];
-
-	msgs[0].flags = 0;
-	msgs[1].flags = I2C_M_RD;
-	msgs[0].addr = msgs[1].addr = id / 2;
-	mm1[0] = reg;
-	msgs[0].len = 1; msgs[1].len = 1;
-	msgs[0].buf = mm1; msgs[1].buf = mm2;
-	i2c_transfer(&av7110->i2c_adap, msgs, 2);
-
-	return mm2[0];
-}
-
-/****************************************************************************
- * INITIALIZATION
- ****************************************************************************/
-
-
-static int check_firmware(struct av7110* av7110)
-{
-	u32 crc = 0, len = 0;
-	unsigned char *ptr;
-
-	/* check for firmware magic */
-	ptr = av7110->bin_fw;
-	if (ptr[0] != 'A' || ptr[1] != 'V' ||
-	    ptr[2] != 'F' || ptr[3] != 'W') {
-		printk("dvb-ttpci: this is not an av7110 firmware\n");
-		return -EINVAL;
-	}
-	ptr += 4;
-
-	/* check dpram file */
-	crc = get_unaligned_be32(ptr);
-	ptr += 4;
-	len = get_unaligned_be32(ptr);
-	ptr += 4;
-	if (len >= 512) {
-		printk("dvb-ttpci: dpram file is way too big.\n");
-		return -EINVAL;
-	}
-	if (crc != crc32_le(0, ptr, len)) {
-		printk("dvb-ttpci: crc32 of dpram file does not match.\n");
-		return -EINVAL;
-	}
-	av7110->bin_dpram = ptr;
-	av7110->size_dpram = len;
-	ptr += len;
-
-	/* check root file */
-	crc = get_unaligned_be32(ptr);
-	ptr += 4;
-	len = get_unaligned_be32(ptr);
-	ptr += 4;
-
-	if (len <= 200000 || len >= 300000 ||
-	    len > ((av7110->bin_fw + av7110->size_fw) - ptr)) {
-		printk("dvb-ttpci: root file has strange size (%d). aborting.\n", len);
-		return -EINVAL;
-	}
-	if( crc != crc32_le(0, ptr, len)) {
-		printk("dvb-ttpci: crc32 of root file does not match.\n");
-		return -EINVAL;
-	}
-	av7110->bin_root = ptr;
-	av7110->size_root = len;
-	return 0;
-}
-
-static void put_firmware(struct av7110* av7110)
-{
-	vfree(av7110->bin_fw);
-}
-
-static int get_firmware(struct av7110* av7110)
-{
-	int ret;
-	const struct firmware *fw;
-
-	/* request the av7110 firmware, this will block until someone uploads it */
-	ret = request_firmware(&fw, "dvb-ttpci-01.fw", &av7110->dev->pci->dev);
-	if (ret) {
-		if (ret == -ENOENT) {
-			printk(KERN_ERR "dvb-ttpci: could not load firmware,"
-			       " file not found: dvb-ttpci-01.fw\n");
-			printk(KERN_ERR "dvb-ttpci: usually this should be in "
-			       "/usr/lib/hotplug/firmware or /lib/firmware\n");
-			printk(KERN_ERR "dvb-ttpci: and can be downloaded from"
-			       " http://www.linuxtv.org/download/dvb/firmware/\n");
-		} else
-			printk(KERN_ERR "dvb-ttpci: cannot request firmware"
-			       " (error %i)\n", ret);
-		return -EINVAL;
-	}
-
-	if (fw->size <= 200000) {
-		printk("dvb-ttpci: this firmware is way too small.\n");
-		release_firmware(fw);
-		return -EINVAL;
-	}
-
-	/* check if the firmware is available */
-	av7110->bin_fw = vmalloc(fw->size);
-	if (NULL == av7110->bin_fw) {
-		dprintk(1, "out of memory\n");
-		release_firmware(fw);
-		return -ENOMEM;
-	}
-
-	memcpy(av7110->bin_fw, fw->data, fw->size);
-	av7110->size_fw = fw->size;
-	if ((ret = check_firmware(av7110)))
-		vfree(av7110->bin_fw);
-
-	release_firmware(fw);
-	return ret;
-}
-
-static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct av7110* av7110 = fe->dvb->priv;
-	u8 pwr = 0;
-	u8 buf[4];
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-	u32 div = (p->frequency + 479500) / 125;
-
-	if (p->frequency > 2000000)
-		pwr = 3;
-	else if (p->frequency > 1800000)
-		pwr = 2;
-	else if (p->frequency > 1600000)
-		pwr = 1;
-	else if (p->frequency > 1200000)
-		pwr = 0;
-	else if (p->frequency >= 1100000)
-		pwr = 1;
-	else
-		pwr = 2;
-
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = div & 0xff;
-	buf[2] = ((div & 0x18000) >> 10) | 0x95;
-	buf[3] = (pwr << 6) | 0x30;
-
-	// NOTE: since we're using a prescaler of 2, we set the
-	// divisor frequency to 62.5kHz and divide by 125 above
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-	return 0;
-}
-
-static struct ves1x93_config alps_bsrv2_config = {
-	.demod_address = 0x08,
-	.xin = 90100000UL,
-	.invert_pwm = 0,
-};
-
-static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct av7110* av7110 = fe->dvb->priv;
-	u32 div;
-	u8 data[4];
-	struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	div = (p->frequency + 35937500 + 31250) / 62500;
-
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0x85 | ((div >> 10) & 0x60);
-	data[3] = (p->frequency < 174000000 ? 0x88 : p->frequency < 470000000 ? 0x84 : 0x81);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-	return 0;
-}
-
-static struct ves1820_config alps_tdbe2_config = {
-	.demod_address = 0x09,
-	.xin = 57840000UL,
-	.invert = 1,
-	.selagc = VES1820_SELAGC_SIGNAMPERR,
-};
-
-
-
-
-static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct av7110* av7110 = fe->dvb->priv;
-	u32 div;
-	u8 data[4];
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	div = p->frequency / 125;
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0x8e;
-	data[3] = 0x00;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-	return 0;
-}
-
-static struct tda8083_config grundig_29504_451_config = {
-	.demod_address = 0x68,
-};
-
-
-
-static int philips_cd1516_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct av7110* av7110 = fe->dvb->priv;
-	u32 div;
-	u32 f = p->frequency;
-	u8 data[4];
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	div = (f + 36125000 + 31250) / 62500;
-
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0x8e;
-	data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-	return 0;
-}
-
-static struct ves1820_config philips_cd1516_config = {
-	.demod_address = 0x09,
-	.xin = 57840000UL,
-	.invert = 1,
-	.selagc = VES1820_SELAGC_SIGNAMPERR,
-};
-
-
-
-static int alps_tdlb7_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct av7110* av7110 = fe->dvb->priv;
-	u32 div, pwr;
-	u8 data[4];
-	struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	div = (p->frequency + 36200000) / 166666;
-
-	if (p->frequency <= 782000000)
-		pwr = 1;
-	else
-		pwr = 2;
-
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0x85;
-	data[3] = pwr << 6;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-	return 0;
-}
-
-static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
-{
-#if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE)
-	struct av7110* av7110 = fe->dvb->priv;
-
-	return request_firmware(fw, name, &av7110->dev->pci->dev);
-#else
-	return -EINVAL;
-#endif
-}
-
-static struct sp8870_config alps_tdlb7_config = {
-
-	.demod_address = 0x71,
-	.request_firmware = alps_tdlb7_request_firmware,
-};
-
-
-static u8 nexusca_stv0297_inittab[] = {
-	0x80, 0x01,
-	0x80, 0x00,
-	0x81, 0x01,
-	0x81, 0x00,
-	0x00, 0x09,
-	0x01, 0x69,
-	0x03, 0x00,
-	0x04, 0x00,
-	0x07, 0x00,
-	0x08, 0x00,
-	0x20, 0x00,
-	0x21, 0x40,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x24, 0x40,
-	0x25, 0x88,
-	0x30, 0xff,
-	0x31, 0x00,
-	0x32, 0xff,
-	0x33, 0x00,
-	0x34, 0x50,
-	0x35, 0x7f,
-	0x36, 0x00,
-	0x37, 0x20,
-	0x38, 0x00,
-	0x40, 0x1c,
-	0x41, 0xff,
-	0x42, 0x29,
-	0x43, 0x00,
-	0x44, 0xff,
-	0x45, 0x00,
-	0x46, 0x00,
-	0x49, 0x04,
-	0x4a, 0x00,
-	0x4b, 0x7b,
-	0x52, 0x30,
-	0x55, 0xae,
-	0x56, 0x47,
-	0x57, 0xe1,
-	0x58, 0x3a,
-	0x5a, 0x1e,
-	0x5b, 0x34,
-	0x60, 0x00,
-	0x63, 0x00,
-	0x64, 0x00,
-	0x65, 0x00,
-	0x66, 0x00,
-	0x67, 0x00,
-	0x68, 0x00,
-	0x69, 0x00,
-	0x6a, 0x02,
-	0x6b, 0x00,
-	0x70, 0xff,
-	0x71, 0x00,
-	0x72, 0x00,
-	0x73, 0x00,
-	0x74, 0x0c,
-	0x80, 0x00,
-	0x81, 0x00,
-	0x82, 0x00,
-	0x83, 0x00,
-	0x84, 0x04,
-	0x85, 0x80,
-	0x86, 0x24,
-	0x87, 0x78,
-	0x88, 0x10,
-	0x89, 0x00,
-	0x90, 0x01,
-	0x91, 0x01,
-	0xa0, 0x04,
-	0xa1, 0x00,
-	0xa2, 0x00,
-	0xb0, 0x91,
-	0xb1, 0x0b,
-	0xc0, 0x53,
-	0xc1, 0x70,
-	0xc2, 0x12,
-	0xd0, 0x00,
-	0xd1, 0x00,
-	0xd2, 0x00,
-	0xd3, 0x00,
-	0xd4, 0x00,
-	0xd5, 0x00,
-	0xde, 0x00,
-	0xdf, 0x00,
-	0x61, 0x49,
-	0x62, 0x0b,
-	0x53, 0x08,
-	0x59, 0x08,
-	0xff, 0xff,
-};
-
-static int nexusca_stv0297_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct av7110* av7110 = fe->dvb->priv;
-	u32 div;
-	u8 data[4];
-	struct i2c_msg msg = { .addr = 0x63, .flags = 0, .buf = data, .len = sizeof(data) };
-	struct i2c_msg readmsg = { .addr = 0x63, .flags = I2C_M_RD, .buf = data, .len = 1 };
-	int i;
-
-	div = (p->frequency + 36150000 + 31250) / 62500;
-
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0xce;
-
-	if (p->frequency < 45000000)
-		return -EINVAL;
-	else if (p->frequency < 137000000)
-		data[3] = 0x01;
-	else if (p->frequency < 403000000)
-		data[3] = 0x02;
-	else if (p->frequency < 860000000)
-		data[3] = 0x04;
-	else
-		return -EINVAL;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) {
-		printk("nexusca: pll transfer failed!\n");
-		return -EIO;
-	}
-
-	// wait for PLL lock
-	for(i = 0; i < 20; i++) {
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-		if (i2c_transfer(&av7110->i2c_adap, &readmsg, 1) == 1)
-			if (data[0] & 0x40) break;
-		msleep(10);
-	}
-
-	return 0;
-}
-
-static struct stv0297_config nexusca_stv0297_config = {
-
-	.demod_address = 0x1C,
-	.inittab = nexusca_stv0297_inittab,
-	.invert = 1,
-	.stop_during_read = 1,
-};
-
-
-
-static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct av7110* av7110 = fe->dvb->priv;
-	u32 div;
-	u8 cfg, cpump, band_select;
-	u8 data[4];
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	div = (36125000 + p->frequency) / 166666;
-
-	cfg = 0x88;
-
-	if (p->frequency < 175000000)
-		cpump = 2;
-	else if (p->frequency < 390000000)
-		cpump = 1;
-	else if (p->frequency < 470000000)
-		cpump = 2;
-	else if (p->frequency < 750000000)
-		cpump = 1;
-	else
-		cpump = 3;
-
-	if (p->frequency < 175000000)
-		band_select = 0x0e;
-	else if (p->frequency < 470000000)
-		band_select = 0x05;
-	else
-		band_select = 0x03;
-
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = ((div >> 10) & 0x60) | cfg;
-	data[3] = (cpump << 6) | band_select;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) return -EIO;
-	return 0;
-}
-
-static struct l64781_config grundig_29504_401_config = {
-	.demod_address = 0x55,
-};
-
-
-
-static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
-{
-	int ret = 0;
-	int synced = (status & FE_HAS_LOCK) ? 1 : 0;
-
-	av7110->fe_status = status;
-
-	if (av7110->fe_synced == synced)
-		return 0;
-
-	if (av7110->playing) {
-		av7110->fe_synced = synced;
-		return 0;
-	}
-
-	if (mutex_lock_interruptible(&av7110->pid_mutex))
-		return -ERESTARTSYS;
-
-	if (synced) {
-		ret = SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO],
-			av7110->pids[DMX_PES_AUDIO],
-			av7110->pids[DMX_PES_TELETEXT], 0,
-			av7110->pids[DMX_PES_PCR]);
-		if (!ret)
-			ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
-	} else {
-		ret = SetPIDs(av7110, 0, 0, 0, 0, 0);
-		if (!ret) {
-			ret = av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0);
-			if (!ret)
-				ret = av7110_wait_msgstate(av7110, GPMQBusy);
-		}
-	}
-
-	if (!ret)
-		av7110->fe_synced = synced;
-
-	mutex_unlock(&av7110->pid_mutex);
-	return ret;
-}
-
-static int av7110_fe_set_frontend(struct dvb_frontend *fe)
-{
-	struct av7110* av7110 = fe->dvb->priv;
-
-	int ret = av7110_fe_lock_fix(av7110, 0);
-	if (!ret)
-		ret = av7110->fe_set_frontend(fe);
-
-	return ret;
-}
-
-static int av7110_fe_init(struct dvb_frontend* fe)
-{
-	struct av7110* av7110 = fe->dvb->priv;
-
-	int ret = av7110_fe_lock_fix(av7110, 0);
-	if (!ret)
-		ret = av7110->fe_init(fe);
-	return ret;
-}
-
-static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct av7110* av7110 = fe->dvb->priv;
-
-	/* call the real implementation */
-	int ret = av7110->fe_read_status(fe, status);
-	if (!ret)
-		if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK))
-			ret = av7110_fe_lock_fix(av7110, *status);
-	return ret;
-}
-
-static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe)
-{
-	struct av7110* av7110 = fe->dvb->priv;
-
-	int ret = av7110_fe_lock_fix(av7110, 0);
-	if (!ret)
-		ret = av7110->fe_diseqc_reset_overload(fe);
-	return ret;
-}
-
-static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe,
-					    struct dvb_diseqc_master_cmd* cmd)
-{
-	struct av7110* av7110 = fe->dvb->priv;
-
-	int ret = av7110_fe_lock_fix(av7110, 0);
-	if (!ret) {
-		av7110->saved_master_cmd = *cmd;
-		ret = av7110->fe_diseqc_send_master_cmd(fe, cmd);
-	}
-	return ret;
-}
-
-static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
-{
-	struct av7110* av7110 = fe->dvb->priv;
-
-	int ret = av7110_fe_lock_fix(av7110, 0);
-	if (!ret) {
-		av7110->saved_minicmd = minicmd;
-		ret = av7110->fe_diseqc_send_burst(fe, minicmd);
-	}
-	return ret;
-}
-
-static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
-	struct av7110* av7110 = fe->dvb->priv;
-
-	int ret = av7110_fe_lock_fix(av7110, 0);
-	if (!ret) {
-		av7110->saved_tone = tone;
-		ret = av7110->fe_set_tone(fe, tone);
-	}
-	return ret;
-}
-
-static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
-	struct av7110* av7110 = fe->dvb->priv;
-
-	int ret = av7110_fe_lock_fix(av7110, 0);
-	if (!ret) {
-		av7110->saved_voltage = voltage;
-		ret = av7110->fe_set_voltage(fe, voltage);
-	}
-	return ret;
-}
-
-static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned long cmd)
-{
-	struct av7110* av7110 = fe->dvb->priv;
-
-	int ret = av7110_fe_lock_fix(av7110, 0);
-	if (!ret)
-		ret = av7110->fe_dishnetwork_send_legacy_command(fe, cmd);
-	return ret;
-}
-
-static void dvb_s_recover(struct av7110* av7110)
-{
-	av7110_fe_init(av7110->fe);
-
-	av7110_fe_set_voltage(av7110->fe, av7110->saved_voltage);
-	if (av7110->saved_master_cmd.msg_len) {
-		msleep(20);
-		av7110_fe_diseqc_send_master_cmd(av7110->fe, &av7110->saved_master_cmd);
-	}
-	msleep(20);
-	av7110_fe_diseqc_send_burst(av7110->fe, av7110->saved_minicmd);
-	msleep(20);
-	av7110_fe_set_tone(av7110->fe, av7110->saved_tone);
-
-	av7110_fe_set_frontend(av7110->fe);
-}
-
-static u8 read_pwm(struct av7110* av7110)
-{
-	u8 b = 0xff;
-	u8 pwm;
-	struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
-				 { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
-
-	if ((i2c_transfer(&av7110->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
-		pwm = 0x48;
-
-	return pwm;
-}
-
-static int frontend_init(struct av7110 *av7110)
-{
-	int ret;
-
-	if (av7110->dev->pci->subsystem_vendor == 0x110a) {
-		switch(av7110->dev->pci->subsystem_device) {
-		case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??))
-			av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config,
-						    &av7110->i2c_adap, read_pwm(av7110));
-			if (av7110->fe) {
-				av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
-			}
-			break;
-		}
-
-	} else if (av7110->dev->pci->subsystem_vendor == 0x13c2) {
-		switch(av7110->dev->pci->subsystem_device) {
-		case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X
-		case 0x0003: // Hauppauge/TT WinTV Nexus-S Rev 2.X
-		case 0x1002: // Hauppauge/TT WinTV DVB-S rev1.3SE
-
-			// try the ALPS BSRV2 first of all
-			av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap);
-			if (av7110->fe) {
-				av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
-				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
-				av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
-				av7110->fe->ops.set_tone = av7110_set_tone;
-				av7110->recover = dvb_s_recover;
-				break;
-			}
-
-			// try the ALPS BSRU6 now
-			av7110->fe = dvb_attach(stv0299_attach, &alps_bsru6_config, &av7110->i2c_adap);
-			if (av7110->fe) {
-				av7110->fe->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
-				av7110->fe->tuner_priv = &av7110->i2c_adap;
-
-				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
-				av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
-				av7110->fe->ops.set_tone = av7110_set_tone;
-				av7110->recover = dvb_s_recover;
-				break;
-			}
-
-			// Try the grundig 29504-451
-			av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap);
-			if (av7110->fe) {
-				av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
-				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
-				av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
-				av7110->fe->ops.set_tone = av7110_set_tone;
-				av7110->recover = dvb_s_recover;
-				break;
-			}
-
-			/* Try DVB-C cards */
-			switch(av7110->dev->pci->subsystem_device) {
-			case 0x0000:
-				/* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */
-				av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, &av7110->i2c_adap,
-							read_pwm(av7110));
-				if (av7110->fe) {
-					av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
-				}
-				break;
-			case 0x0003:
-				/* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */
-				av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap,
-							read_pwm(av7110));
-				if (av7110->fe) {
-					av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
-				}
-				break;
-			}
-			break;
-
-		case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X
-			// try ALPS TDLB7 first, then Grundig 29504-401
-			av7110->fe = dvb_attach(sp8870_attach, &alps_tdlb7_config, &av7110->i2c_adap);
-			if (av7110->fe) {
-				av7110->fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params;
-				break;
-			}
-			/* fall-thru */
-
-		case 0x0008: // Hauppauge/TT DVB-T
-			// Grundig 29504-401
-			av7110->fe = dvb_attach(l64781_attach, &grundig_29504_401_config, &av7110->i2c_adap);
-			if (av7110->fe)
-				av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
-			break;
-
-		case 0x0002: // Hauppauge/TT DVB-C premium rev2.X
-
-			av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
-			if (av7110->fe) {
-				av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
-			}
-			break;
-
-		case 0x0004: // Galaxis DVB-S rev1.3
-			/* ALPS BSRV2 */
-			av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap);
-			if (av7110->fe) {
-				av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
-				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
-				av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
-				av7110->fe->ops.set_tone = av7110_set_tone;
-				av7110->recover = dvb_s_recover;
-			}
-			break;
-
-		case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */
-			/* Grundig 29504-451 */
-			av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap);
-			if (av7110->fe) {
-				av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
-				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
-				av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
-				av7110->fe->ops.set_tone = av7110_set_tone;
-				av7110->recover = dvb_s_recover;
-			}
-			break;
-
-		case 0x000A: // Hauppauge/TT Nexus-CA rev1.X
-
-			av7110->fe = dvb_attach(stv0297_attach, &nexusca_stv0297_config, &av7110->i2c_adap);
-			if (av7110->fe) {
-				av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params;
-
-				/* set TDA9819 into DVB mode */
-				saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
-				saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
-
-				/* tuner on this needs a slower i2c bus speed */
-				av7110->dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
-				break;
-			}
-			break;
-
-		case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */
-			/* ALPS BSBE1 */
-			av7110->fe = dvb_attach(stv0299_attach, &alps_bsbe1_config, &av7110->i2c_adap);
-			if (av7110->fe) {
-				av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
-				av7110->fe->tuner_priv = &av7110->i2c_adap;
-
-				if (dvb_attach(lnbp21_attach, av7110->fe, &av7110->i2c_adap, 0, 0) == NULL) {
-					printk("dvb-ttpci: LNBP21 not found!\n");
-					if (av7110->fe->ops.release)
-						av7110->fe->ops.release(av7110->fe);
-					av7110->fe = NULL;
-				} else {
-					av7110->fe->ops.dishnetwork_send_legacy_command = NULL;
-					av7110->recover = dvb_s_recover;
-				}
-			}
-			break;
-		}
-	}
-
-	if (!av7110->fe) {
-		/* FIXME: propagate the failure code from the lower layers */
-		ret = -ENOMEM;
-		printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
-		       av7110->dev->pci->vendor,
-		       av7110->dev->pci->device,
-		       av7110->dev->pci->subsystem_vendor,
-		       av7110->dev->pci->subsystem_device);
-	} else {
-		FE_FUNC_OVERRIDE(av7110->fe->ops.init, av7110->fe_init, av7110_fe_init);
-		FE_FUNC_OVERRIDE(av7110->fe->ops.read_status, av7110->fe_read_status, av7110_fe_read_status);
-		FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload);
-		FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
-		FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
-		FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
-		FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage);
-		FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
-		FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
-
-		ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe);
-		if (ret < 0) {
-			printk("av7110: Frontend registration failed!\n");
-			dvb_frontend_detach(av7110->fe);
-			av7110->fe = NULL;
-		}
-	}
-	return ret;
-}
-
-/* Budgetpatch note:
- * Original hardware design by Roberto Deza:
- * There is a DVB_Wiki at
- * http://www.linuxtv.org/
- *
- * New software triggering design by Emard that works on
- * original Roberto Deza's hardware:
- *
- * rps1 code for budgetpatch will copy internal HS event to GPIO3 pin.
- * GPIO3 is in budget-patch hardware connectd to port B VSYNC
- * HS is an internal event of 7146, accessible with RPS
- * and temporarily raised high every n lines
- * (n in defined in the RPS_THRESH1 counter threshold)
- * I think HS is raised high on the beginning of the n-th line
- * and remains high until this n-th line that triggered
- * it is completely received. When the receiption of n-th line
- * ends, HS is lowered.
- *
- * To transmit data over DMA, 7146 needs changing state at
- * port B VSYNC pin. Any changing of port B VSYNC will
- * cause some DMA data transfer, with more or less packets loss.
- * It depends on the phase and frequency of VSYNC and
- * the way of 7146 is instructed to trigger on port B (defined
- * in DD1_INIT register, 3rd nibble from the right valid
- * numbers are 0-7, see datasheet)
- *
- * The correct triggering can minimize packet loss,
- * dvbtraffic should give this stable bandwidths:
- *   22k transponder = 33814 kbit/s
- * 27.5k transponder = 38045 kbit/s
- * by experiment it is found that the best results
- * (stable bandwidths and almost no packet loss)
- * are obtained using DD1_INIT triggering number 2
- * (Va at rising edge of VS Fa = HS x VS-failing forced toggle)
- * and a VSYNC phase that occurs in the middle of DMA transfer
- * (about byte 188*512=96256 in the DMA window).
- *
- * Phase of HS is still not clear to me how to control,
- * It just happens to be so. It can be seen if one enables
- * RPS_IRQ and print Event Counter 1 in vpeirq(). Every
- * time RPS_INTERRUPT is called, the Event Counter 1 will
- * increment. That's how the 7146 is programmed to do event
- * counting in this budget-patch.c
- * I *think* HPS setting has something to do with the phase
- * of HS but I can't be 100% sure in that.
- *
- * hardware debug note: a working budget card (including budget patch)
- * with vpeirq() interrupt setup in mode "0x90" (every 64K) will
- * generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes
- * and that means 3*25=75 Hz of interrupt freqency, as seen by
- * watch cat /proc/interrupts
- *
- * If this frequency is 3x lower (and data received in the DMA
- * buffer don't start with 0x47, but in the middle of packets,
- * whose lengths appear to be like 188 292 188 104 etc.
- * this means VSYNC line is not connected in the hardware.
- * (check soldering pcb and pins)
- * The same behaviour of missing VSYNC can be duplicated on budget
- * cards, by seting DD1_INIT trigger mode 7 in 3rd nibble.
- */
-static int __devinit av7110_attach(struct saa7146_dev* dev,
-				   struct saa7146_pci_extension_data *pci_ext)
-{
-	const int length = TS_WIDTH * TS_HEIGHT;
-	struct pci_dev *pdev = dev->pci;
-	struct av7110 *av7110;
-	struct task_struct *thread;
-	int ret, count = 0;
-
-	dprintk(4, "dev: %p\n", dev);
-
-	/* Set RPS_IRQ to 1 to track rps1 activity.
-	 * Enabling this won't send any interrupt to PC CPU.
-	 */
-#define RPS_IRQ 0
-
-	if (budgetpatch == 1) {
-		budgetpatch = 0;
-		/* autodetect the presence of budget patch
-		 * this only works if saa7146 has been recently
-		 * reset with with MASK_31 to MC1
-		 *
-		 * will wait for VBI_B event (vertical blank at port B)
-		 * and will reset GPIO3 after VBI_B is detected.
-		 * (GPIO3 should be raised high by CPU to
-		 * test if GPIO3 will generate vertical blank signal
-		 * in budget patch GPIO3 is connected to VSYNC_B
-		 */
-
-		/* RESET SAA7146 */
-		saa7146_write(dev, MC1, MASK_31);
-		/* autodetection success seems to be time-dependend after reset */
-
-		/* Fix VSYNC level */
-		saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
-		/* set vsync_b triggering */
-		saa7146_write(dev, DD1_STREAM_B, 0);
-		/* port B VSYNC at rising edge */
-		saa7146_write(dev, DD1_INIT, 0x00000200);
-		saa7146_write(dev, BRS_CTRL, 0x00000000);  // VBI
-		saa7146_write(dev, MC2,
-			      1 * (MASK_08 | MASK_24)  |   // BRS control
-			      0 * (MASK_09 | MASK_25)  |   // a
-			      1 * (MASK_10 | MASK_26)  |   // b
-			      0 * (MASK_06 | MASK_22)  |   // HPS_CTRL1
-			      0 * (MASK_05 | MASK_21)  |   // HPS_CTRL2
-			      0 * (MASK_01 | MASK_15)      // DEBI
-		);
-
-		/* start writing RPS1 code from beginning */
-		count = 0;
-		/* Disable RPS1 */
-		saa7146_write(dev, MC1, MASK_29);
-		/* RPS1 timeout disable */
-		saa7146_write(dev, RPS_TOV1, 0);
-		WRITE_RPS1(CMD_PAUSE | EVT_VBI_B);
-		WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
-		WRITE_RPS1(GPIO3_MSK);
-		WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
-#if RPS_IRQ
-		/* issue RPS1 interrupt to increment counter */
-		WRITE_RPS1(CMD_INTERRUPT);
-#endif
-		WRITE_RPS1(CMD_STOP);
-		/* Jump to begin of RPS program as safety measure               (p37) */
-		WRITE_RPS1(CMD_JUMP);
-		WRITE_RPS1(dev->d_rps1.dma_handle);
-
-#if RPS_IRQ
-		/* set event counter 1 source as RPS1 interrupt (0x03)          (rE4 p53)
-		 * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
-		 * use 0x15 to track VPE  interrupts - increase by 1 every vpeirq() is called
-		 */
-		saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
-		/* set event counter 1 threshold to maximum allowed value        (rEC p55) */
-		saa7146_write(dev, ECT1R,  0x3fff );
-#endif
-		/* Set RPS1 Address register to point to RPS code               (r108 p42) */
-		saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
-		/* Enable RPS1,                                                 (rFC p33) */
-		saa7146_write(dev, MC1, (MASK_13 | MASK_29 ));
-
-		mdelay(10);
-		/* now send VSYNC_B to rps1 by rising GPIO3 */
-		saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
-		mdelay(10);
-		/* if rps1 responded by lowering the GPIO3,
-		 * then we have budgetpatch hardware
-		 */
-		if ((saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0) {
-			budgetpatch = 1;
-			printk("dvb-ttpci: BUDGET-PATCH DETECTED.\n");
-		}
-		/* Disable RPS1 */
-		saa7146_write(dev, MC1, ( MASK_29 ));
-#if RPS_IRQ
-		printk("dvb-ttpci: Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff );
-#endif
-	}
-
-	/* prepare the av7110 device struct */
-	av7110 = kzalloc(sizeof(struct av7110), GFP_KERNEL);
-	if (!av7110) {
-		dprintk(1, "out of memory\n");
-		return -ENOMEM;
-	}
-
-	av7110->card_name = (char*) pci_ext->ext_priv;
-	av7110->dev = dev;
-	dev->ext_priv = av7110;
-
-	ret = get_firmware(av7110);
-	if (ret < 0)
-		goto err_kfree_0;
-
-	ret = dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name,
-				   THIS_MODULE, &dev->pci->dev, adapter_nr);
-	if (ret < 0)
-		goto err_put_firmware_1;
-
-	/* the Siemens DVB needs this if you want to have the i2c chips
-	   get recognized before the main driver is fully loaded */
-	saa7146_write(dev, GPIO_CTRL, 0x500000);
-
-	strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name));
-
-	saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
-
-	ret = i2c_add_adapter(&av7110->i2c_adap);
-	if (ret < 0)
-		goto err_dvb_unregister_adapter_2;
-
-	ttpci_eeprom_parse_mac(&av7110->i2c_adap,
-			       av7110->dvb_adapter.proposed_mac);
-	ret = -ENOMEM;
-
-	/* full-ts mod? */
-	if (full_ts)
-		av7110->full_ts = true;
-
-	/* check for full-ts flag in eeprom */
-	if (i2c_readreg(av7110, 0xaa, 0) == 0x4f && i2c_readreg(av7110, 0xaa, 1) == 0x45) {
-		u8 flags = i2c_readreg(av7110, 0xaa, 2);
-		if (flags != 0xff && (flags & 0x01))
-			av7110->full_ts = true;
-	}
-
-	if (av7110->full_ts) {
-		printk(KERN_INFO "dvb-ttpci: full-ts mode enabled for saa7146 port B\n");
-		spin_lock_init(&av7110->feedlock1);
-		av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length,
-								 &av7110->pt);
-		if (!av7110->grabbing)
-			goto err_i2c_del_3;
-
-		saa7146_write(dev, DD1_STREAM_B, 0x00000000);
-		saa7146_write(dev, MC2, (MASK_10 | MASK_26));
-
-		saa7146_write(dev, DD1_INIT, 0x00000600);
-		saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
-
-		saa7146_write(dev, BRS_CTRL, 0x60000000);
-		saa7146_write(dev, MC2, MASK_08 | MASK_24);
-
-		/* dma3 */
-		saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000));
-		saa7146_write(dev, BASE_ODD3, 0);
-		saa7146_write(dev, BASE_EVEN3, 0);
-		saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT);
-		saa7146_write(dev, PITCH3, TS_WIDTH);
-		saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90);
-		saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH);
-		saa7146_write(dev, MC2, MASK_04 | MASK_20);
-
-		tasklet_init(&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110);
-
-	} else if (budgetpatch) {
-		spin_lock_init(&av7110->feedlock1);
-		av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length,
-								 &av7110->pt);
-		if (!av7110->grabbing)
-			goto err_i2c_del_3;
-
-		saa7146_write(dev, PCI_BT_V1, 0x1c1f101f);
-		saa7146_write(dev, BCS_CTRL, 0x80400040);
-		/* set dd1 stream a & b */
-		saa7146_write(dev, DD1_STREAM_B, 0x00000000);
-		saa7146_write(dev, DD1_INIT, 0x03000200);
-		saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
-		saa7146_write(dev, BRS_CTRL, 0x60000000);
-		saa7146_write(dev, BASE_ODD3, 0);
-		saa7146_write(dev, BASE_EVEN3, 0);
-		saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT);
-		saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90);
-
-		saa7146_write(dev, PITCH3, TS_WIDTH);
-		saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH);
-
-		/* upload all */
-		saa7146_write(dev, MC2, 0x077c077c);
-		saa7146_write(dev, GPIO_CTRL, 0x000000);
-#if RPS_IRQ
-		/* set event counter 1 source as RPS1 interrupt (0x03)          (rE4 p53)
-		 * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
-		 * use 0x15 to track VPE  interrupts - increase by 1 every vpeirq() is called
-		 */
-		saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
-		/* set event counter 1 threshold to maximum allowed value        (rEC p55) */
-		saa7146_write(dev, ECT1R,  0x3fff );
-#endif
-		/* Setup BUDGETPATCH MAIN RPS1 "program" (p35) */
-		count = 0;
-
-		/* Wait Source Line Counter Threshold                           (p36) */
-		WRITE_RPS1(CMD_PAUSE | EVT_HS);
-		/* Set GPIO3=1                                                  (p42) */
-		WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
-		WRITE_RPS1(GPIO3_MSK);
-		WRITE_RPS1(SAA7146_GPIO_OUTHI<<24);
-#if RPS_IRQ
-		/* issue RPS1 interrupt */
-		WRITE_RPS1(CMD_INTERRUPT);
-#endif
-		/* Wait reset Source Line Counter Threshold                     (p36) */
-		WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS);
-		/* Set GPIO3=0                                                  (p42) */
-		WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
-		WRITE_RPS1(GPIO3_MSK);
-		WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
-#if RPS_IRQ
-		/* issue RPS1 interrupt */
-		WRITE_RPS1(CMD_INTERRUPT);
-#endif
-		/* Jump to begin of RPS program                                 (p37) */
-		WRITE_RPS1(CMD_JUMP);
-		WRITE_RPS1(dev->d_rps1.dma_handle);
-
-		/* Fix VSYNC level */
-		saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
-		/* Set RPS1 Address register to point to RPS code               (r108 p42) */
-		saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
-		/* Set Source Line Counter Threshold, using BRS                 (rCC p43)
-		 * It generates HS event every TS_HEIGHT lines
-		 * this is related to TS_WIDTH set in register
-		 * NUM_LINE_BYTE3. If NUM_LINE_BYTE low 16 bits
-		 * are set to TS_WIDTH bytes (TS_WIDTH=2*188),
-		 * then RPS_THRESH1 should be set to trigger
-		 * every TS_HEIGHT (512) lines.
-		 */
-		saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 );
-
-		/* Enable RPS1                                                  (rFC p33) */
-		saa7146_write(dev, MC1, (MASK_13 | MASK_29));
-
-		/* end of budgetpatch register initialization */
-		tasklet_init (&av7110->vpe_tasklet,  vpeirq,  (unsigned long) av7110);
-	} else {
-		saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
-		saa7146_write(dev, BCS_CTRL, 0x80400040);
-
-		/* set dd1 stream a & b */
-		saa7146_write(dev, DD1_STREAM_B, 0x00000000);
-		saa7146_write(dev, DD1_INIT, 0x03000000);
-		saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
-
-		/* upload all */
-		saa7146_write(dev, MC2, 0x077c077c);
-		saa7146_write(dev, GPIO_CTRL, 0x000000);
-	}
-
-	tasklet_init (&av7110->debi_tasklet, debiirq, (unsigned long) av7110);
-	tasklet_init (&av7110->gpio_tasklet, gpioirq, (unsigned long) av7110);
-
-	mutex_init(&av7110->pid_mutex);
-
-	/* locks for data transfers from/to AV7110 */
-	spin_lock_init(&av7110->debilock);
-	mutex_init(&av7110->dcomlock);
-	av7110->debitype = -1;
-
-	/* default OSD window */
-	av7110->osdwin = 1;
-	mutex_init(&av7110->osd_mutex);
-
-	/* TV standard */
-	av7110->vidmode = tv_standard == 1 ? AV7110_VIDEO_MODE_NTSC
-					   : AV7110_VIDEO_MODE_PAL;
-
-	/* ARM "watchdog" */
-	init_waitqueue_head(&av7110->arm_wait);
-	av7110->arm_thread = NULL;
-
-	/* allocate and init buffers */
-	av7110->debi_virt = pci_alloc_consistent(pdev, 8192, &av7110->debi_bus);
-	if (!av7110->debi_virt)
-		goto err_saa71466_vfree_4;
-
-
-	av7110->iobuf = vmalloc(AVOUTLEN+AOUTLEN+BMPLEN+4*IPACKS);
-	if (!av7110->iobuf)
-		goto err_pci_free_5;
-
-	ret = av7110_av_init(av7110);
-	if (ret < 0)
-		goto err_iobuf_vfree_6;
-
-	/* init BMP buffer */
-	av7110->bmpbuf = av7110->iobuf+AVOUTLEN+AOUTLEN;
-	init_waitqueue_head(&av7110->bmpq);
-
-	ret = av7110_ca_init(av7110);
-	if (ret < 0)
-		goto err_av7110_av_exit_7;
-
-	/* load firmware into AV7110 cards */
-	ret = av7110_bootarm(av7110);
-	if (ret < 0)
-		goto err_av7110_ca_exit_8;
-
-	ret = av7110_firmversion(av7110);
-	if (ret < 0)
-		goto err_stop_arm_9;
-
-	if (FW_VERSION(av7110->arm_app)<0x2501)
-		printk ("dvb-ttpci: Warning, firmware version 0x%04x is too old. "
-			"System might be unstable!\n", FW_VERSION(av7110->arm_app));
-
-	thread = kthread_run(arm_thread, (void *) av7110, "arm_mon");
-	if (IS_ERR(thread)) {
-		ret = PTR_ERR(thread);
-		goto err_stop_arm_9;
-	}
-	av7110->arm_thread = thread;
-
-	/* set initial volume in mixer struct */
-	av7110->mixer.volume_left  = volume;
-	av7110->mixer.volume_right = volume;
-
-	ret = av7110_register(av7110);
-	if (ret < 0)
-		goto err_arm_thread_stop_10;
-
-	init_av7110_av(av7110);
-
-	/* special case DVB-C: these cards have an analog tuner
-	   plus need some special handling, so we have separate
-	   saa7146_ext_vv data for these... */
-	ret = av7110_init_v4l(av7110);
-	if (ret < 0)
-		goto err_av7110_unregister_11;
-
-	av7110->dvb_adapter.priv = av7110;
-	ret = frontend_init(av7110);
-	if (ret < 0)
-		goto err_av7110_exit_v4l_12;
-
-#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
-	av7110_ir_init(av7110);
-#endif
-	printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num);
-	av7110_num++;
-out:
-	return ret;
-
-err_av7110_exit_v4l_12:
-	av7110_exit_v4l(av7110);
-err_av7110_unregister_11:
-	dvb_unregister(av7110);
-err_arm_thread_stop_10:
-	av7110_arm_sync(av7110);
-err_stop_arm_9:
-	/* Nothing to do. Rejoice. */
-err_av7110_ca_exit_8:
-	av7110_ca_exit(av7110);
-err_av7110_av_exit_7:
-	av7110_av_exit(av7110);
-err_iobuf_vfree_6:
-	vfree(av7110->iobuf);
-err_pci_free_5:
-	pci_free_consistent(pdev, 8192, av7110->debi_virt, av7110->debi_bus);
-err_saa71466_vfree_4:
-	if (av7110->grabbing)
-		saa7146_vfree_destroy_pgtable(pdev, av7110->grabbing, &av7110->pt);
-err_i2c_del_3:
-	i2c_del_adapter(&av7110->i2c_adap);
-err_dvb_unregister_adapter_2:
-	dvb_unregister_adapter(&av7110->dvb_adapter);
-err_put_firmware_1:
-	put_firmware(av7110);
-err_kfree_0:
-	kfree(av7110);
-	goto out;
-}
-
-static int __devexit av7110_detach(struct saa7146_dev* saa)
-{
-	struct av7110 *av7110 = saa->ext_priv;
-	dprintk(4, "%p\n", av7110);
-
-#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
-	av7110_ir_exit(av7110);
-#endif
-	if (budgetpatch || av7110->full_ts) {
-		if (budgetpatch) {
-			/* Disable RPS1 */
-			saa7146_write(saa, MC1, MASK_29);
-			/* VSYNC LOW (inactive) */
-			saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
-		}
-		saa7146_write(saa, MC1, MASK_20);	/* DMA3 off */
-		SAA7146_IER_DISABLE(saa, MASK_10);
-		SAA7146_ISR_CLEAR(saa, MASK_10);
-		msleep(50);
-		tasklet_kill(&av7110->vpe_tasklet);
-		saa7146_vfree_destroy_pgtable(saa->pci, av7110->grabbing, &av7110->pt);
-	}
-	av7110_exit_v4l(av7110);
-
-	av7110_arm_sync(av7110);
-
-	tasklet_kill(&av7110->debi_tasklet);
-	tasklet_kill(&av7110->gpio_tasklet);
-
-	dvb_unregister(av7110);
-
-	SAA7146_IER_DISABLE(saa, MASK_19 | MASK_03);
-	SAA7146_ISR_CLEAR(saa, MASK_19 | MASK_03);
-
-	av7110_ca_exit(av7110);
-	av7110_av_exit(av7110);
-
-	vfree(av7110->iobuf);
-	pci_free_consistent(saa->pci, 8192, av7110->debi_virt,
-			    av7110->debi_bus);
-
-	i2c_del_adapter(&av7110->i2c_adap);
-
-	dvb_unregister_adapter (&av7110->dvb_adapter);
-
-	av7110_num--;
-
-	put_firmware(av7110);
-
-	kfree(av7110);
-
-	saa->ext_priv = NULL;
-
-	return 0;
-}
-
-
-static void av7110_irq(struct saa7146_dev* dev, u32 *isr)
-{
-	struct av7110 *av7110 = dev->ext_priv;
-
-	//print_time("av7110_irq");
-
-	/* Note: Don't try to handle the DEBI error irq (MASK_18), in
-	 * intel mode the timeout is asserted all the time...
-	 */
-
-	if (*isr & MASK_19) {
-		//printk("av7110_irq: DEBI\n");
-		/* Note 1: The DEBI irq is level triggered: We must enable it
-		 * only after we started a DMA xfer, and disable it here
-		 * immediately, or it will be signalled all the time while
-		 * DEBI is idle.
-		 * Note 2: You would think that an irq which is masked is
-		 * not signalled by the hardware. Not so for the SAA7146:
-		 * An irq is signalled as long as the corresponding bit
-		 * in the ISR is set, and disabling irqs just prevents the
-		 * hardware from setting the ISR bit. This means a) that we
-		 * must clear the ISR *after* disabling the irq (which is why
-		 * we must do it here even though saa7146_core did it already),
-		 * and b) that if we were to disable an edge triggered irq
-		 * (like the gpio irqs sadly are) temporarily we would likely
-		 * loose some. This sucks :-(
-		 */
-		SAA7146_IER_DISABLE(av7110->dev, MASK_19);
-		SAA7146_ISR_CLEAR(av7110->dev, MASK_19);
-		tasklet_schedule(&av7110->debi_tasklet);
-	}
-
-	if (*isr & MASK_03) {
-		//printk("av7110_irq: GPIO\n");
-		tasklet_schedule(&av7110->gpio_tasklet);
-	}
-
-	if (*isr & MASK_10)
-		tasklet_schedule(&av7110->vpe_tasklet);
-}
-
-
-static struct saa7146_extension av7110_extension_driver;
-
-#define MAKE_AV7110_INFO(x_var,x_name) \
-static struct saa7146_pci_extension_data x_var = { \
-	.ext_priv = x_name, \
-	.ext = &av7110_extension_driver }
-
-MAKE_AV7110_INFO(tts_1_X_fsc,"Technotrend/Hauppauge WinTV DVB-S rev1.X or Fujitsu Siemens DVB-C");
-MAKE_AV7110_INFO(ttt_1_X,    "Technotrend/Hauppauge WinTV DVB-T rev1.X");
-MAKE_AV7110_INFO(ttc_1_X,    "Technotrend/Hauppauge WinTV Nexus-CA rev1.X");
-MAKE_AV7110_INFO(ttc_2_X,    "Technotrend/Hauppauge WinTV DVB-C rev2.X");
-MAKE_AV7110_INFO(tts_2_X,    "Technotrend/Hauppauge WinTV Nexus-S rev2.X");
-MAKE_AV7110_INFO(tts_2_3,    "Technotrend/Hauppauge WinTV Nexus-S rev2.3");
-MAKE_AV7110_INFO(tts_1_3se,  "Technotrend/Hauppauge WinTV DVB-S rev1.3 SE");
-MAKE_AV7110_INFO(ttt,        "Technotrend/Hauppauge DVB-T");
-MAKE_AV7110_INFO(fsc,        "Fujitsu Siemens DVB-C");
-MAKE_AV7110_INFO(fss,        "Fujitsu Siemens DVB-S rev1.6");
-MAKE_AV7110_INFO(gxs_1_3,    "Galaxis DVB-S rev1.3");
-
-static struct pci_device_id pci_tbl[] = {
-	MAKE_EXTENSION_PCI(fsc,         0x110a, 0x0000),
-	MAKE_EXTENSION_PCI(tts_1_X_fsc, 0x13c2, 0x0000),
-	MAKE_EXTENSION_PCI(ttt_1_X,     0x13c2, 0x0001),
-	MAKE_EXTENSION_PCI(ttc_2_X,     0x13c2, 0x0002),
-	MAKE_EXTENSION_PCI(tts_2_X,     0x13c2, 0x0003),
-	MAKE_EXTENSION_PCI(gxs_1_3,     0x13c2, 0x0004),
-	MAKE_EXTENSION_PCI(fss,         0x13c2, 0x0006),
-	MAKE_EXTENSION_PCI(ttt,         0x13c2, 0x0008),
-	MAKE_EXTENSION_PCI(ttc_1_X,     0x13c2, 0x000a),
-	MAKE_EXTENSION_PCI(tts_2_3,     0x13c2, 0x000e),
-	MAKE_EXTENSION_PCI(tts_1_3se,   0x13c2, 0x1002),
-
-/*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1
-/*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v????
-
-	{
-		.vendor    = 0,
-	}
-};
-
-MODULE_DEVICE_TABLE(pci, pci_tbl);
-
-
-static struct saa7146_extension av7110_extension_driver = {
-	.name		= "av7110",
-	.flags		= SAA7146_USE_I2C_IRQ,
-
-	.module		= THIS_MODULE,
-	.pci_tbl	= &pci_tbl[0],
-	.attach		= av7110_attach,
-	.detach		= __devexit_p(av7110_detach),
-
-	.irq_mask	= MASK_19 | MASK_03 | MASK_10,
-	.irq_func	= av7110_irq,
-};
-
-
-static int __init av7110_init(void)
-{
-	int retval;
-	retval = saa7146_register_extension(&av7110_extension_driver);
-	return retval;
-}
-
-
-static void __exit av7110_exit(void)
-{
-	saa7146_unregister_extension(&av7110_extension_driver);
-}
-
-module_init(av7110_init);
-module_exit(av7110_exit);
-
-MODULE_DESCRIPTION("driver for the SAA7146 based AV110 PCI DVB cards by "
-		   "Siemens, Technotrend, Hauppauge");
-MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
deleted file mode 100644
index 88b3b2d..0000000
--- a/drivers/media/dvb/ttpci/av7110.h
+++ /dev/null
@@ -1,314 +0,0 @@
-#ifndef _AV7110_H_
-#define _AV7110_H_
-
-#include <linux/interrupt.h>
-#include <linux/socket.h>
-#include <linux/netdevice.h>
-#include <linux/i2c.h>
-#include <linux/input.h>
-
-#include <linux/dvb/video.h>
-#include <linux/dvb/audio.h>
-#include <linux/dvb/dmx.h>
-#include <linux/dvb/ca.h>
-#include <linux/dvb/osd.h>
-#include <linux/dvb/net.h>
-#include <linux/mutex.h>
-
-#include "dvbdev.h"
-#include "demux.h"
-#include "dvb_demux.h"
-#include "dmxdev.h"
-#include "dvb_filter.h"
-#include "dvb_net.h"
-#include "dvb_ringbuffer.h"
-#include "dvb_frontend.h"
-#include "ves1820.h"
-#include "ves1x93.h"
-#include "stv0299.h"
-#include "tda8083.h"
-#include "sp8870.h"
-#include "stv0297.h"
-#include "l64781.h"
-
-#include <media/saa7146_vv.h>
-
-
-#define ANALOG_TUNER_VES1820 1
-#define ANALOG_TUNER_STV0297 2
-
-extern int av7110_debug;
-
-#define dprintk(level,args...) \
-	    do { if ((av7110_debug & level)) { printk("dvb-ttpci: %s(): ", __func__); printk(args); } } while (0)
-
-#define MAXFILT 32
-
-enum {AV_PES_STREAM, PS_STREAM, TS_STREAM, PES_STREAM};
-
-enum av7110_video_mode {
-	AV7110_VIDEO_MODE_PAL 	= 0,
-	AV7110_VIDEO_MODE_NTSC	= 1
-};
-
-struct av7110_p2t {
-	u8		  pes[TS_SIZE];
-	u8		  counter;
-	long int	  pos;
-	int		  frags;
-	struct dvb_demux_feed *feed;
-};
-
-/* video MPEG decoder events: */
-/* (code copied from dvb_frontend.c, should maybe be factored out...) */
-#define MAX_VIDEO_EVENT 8
-struct dvb_video_events {
-	struct video_event	  events[MAX_VIDEO_EVENT];
-	int			  eventw;
-	int			  eventr;
-	int			  overflow;
-	wait_queue_head_t	  wait_queue;
-	spinlock_t		  lock;
-};
-
-
-struct av7110;
-
-/* infrared remote control */
-struct infrared {
-	u16	key_map[256];
-	struct input_dev	*input_dev;
-	char			input_phys[32];
-	struct timer_list	keyup_timer;
-	struct tasklet_struct	ir_tasklet;
-	void			(*ir_handler)(struct av7110 *av7110, u32 ircom);
-	u32			ir_command;
-	u32			ir_config;
-	u32			device_mask;
-	u8			protocol;
-	u8			inversion;
-	u16			last_key;
-	u16			last_toggle;
-	u8			delay_timer_finished;
-};
-
-
-/* place to store all the necessary device information */
-struct av7110 {
-
-	/* devices */
-
-	struct dvb_device	dvb_dev;
-	struct dvb_net		dvb_net;
-
-	struct video_device	*v4l_dev;
-	struct video_device	*vbi_dev;
-
-	struct saa7146_dev	*dev;
-
-	struct i2c_adapter	i2c_adap;
-
-	char			*card_name;
-
-	/* support for analog module of dvb-c */
-	int			analog_tuner_flags;
-	int			current_input;
-	u32			current_freq;
-
-	struct tasklet_struct	debi_tasklet;
-	struct tasklet_struct	gpio_tasklet;
-
-	int adac_type;	       /* audio DAC type */
-#define DVB_ADAC_TI	  0
-#define DVB_ADAC_CRYSTAL  1
-#define DVB_ADAC_MSP34x0  2
-#define DVB_ADAC_MSP34x5  3
-#define DVB_ADAC_NONE	 -1
-
-
-	/* buffers */
-
-	void		       *iobuf;	 /* memory for all buffers */
-	struct dvb_ringbuffer	avout;   /* buffer for video or A/V mux */
-#define AVOUTLEN (128*1024)
-	struct dvb_ringbuffer	aout;    /* buffer for audio */
-#define AOUTLEN (64*1024)
-	void		       *bmpbuf;
-#define BMPLEN (8*32768+1024)
-
-	/* bitmap buffers and states */
-
-	int			bmpp;
-	int			bmplen;
-	volatile int		bmp_state;
-#define BMP_NONE     0
-#define BMP_LOADING  1
-#define BMP_LOADED   2
-	wait_queue_head_t	bmpq;
-
-
-	/* DEBI and polled command interface */
-
-	spinlock_t		debilock;
-	struct mutex		dcomlock;
-	volatile int		debitype;
-	volatile int		debilen;
-
-
-	/* Recording and playback flags */
-
-	int			rec_mode;
-	int			playing;
-#define RP_NONE  0
-#define RP_VIDEO 1
-#define RP_AUDIO 2
-#define RP_AV	 3
-
-
-	/* OSD */
-
-	int			osdwin;      /* currently active window */
-	u16			osdbpp[8];
-	struct mutex		osd_mutex;
-
-	/* CA */
-
-	ca_slot_info_t		ci_slot[2];
-
-	enum av7110_video_mode	vidmode;
-	struct dmxdev		dmxdev;
-	struct dvb_demux	demux;
-
-	struct dmx_frontend	hw_frontend;
-	struct dmx_frontend	mem_frontend;
-
-	/* for budget mode demux1 */
-	struct dmxdev		dmxdev1;
-	struct dvb_demux	demux1;
-	struct dvb_net		dvb_net1;
-	spinlock_t		feedlock1;
-	int			feeding1;
-	u32			ttbp;
-	unsigned char           *grabbing;
-	struct saa7146_pgtable  pt;
-	struct tasklet_struct   vpe_tasklet;
-	bool			full_ts;
-
-	int			fe_synced;
-	struct mutex		pid_mutex;
-
-	int			video_blank;
-	struct video_status	videostate;
-	u16			display_panscan;
-	int			display_ar;
-	int			trickmode;
-#define TRICK_NONE   0
-#define TRICK_FAST   1
-#define TRICK_SLOW   2
-#define TRICK_FREEZE 3
-	struct audio_status	audiostate;
-
-	struct dvb_demux_filter *handle2filter[32];
-	struct av7110_p2t	 p2t_filter[MAXFILT];
-	struct dvb_filter_pes2ts p2t[2];
-	struct ipack		 ipack[2];
-	u8			*kbuf[2];
-
-	int sinfo;
-	int feeding;
-
-	int arm_errors;
-	int registered;
-
-
-	/* AV711X */
-
-	u32		    arm_fw;
-	u32		    arm_rtsl;
-	u32		    arm_vid;
-	u32		    arm_app;
-	u32		    avtype;
-	int		    arm_ready;
-	struct task_struct *arm_thread;
-	wait_queue_head_t   arm_wait;
-	u16		    arm_loops;
-
-	void		   *debi_virt;
-	dma_addr_t	    debi_bus;
-
-	u16		    pids[DMX_PES_OTHER];
-
-	struct dvb_ringbuffer	 ci_rbuffer;
-	struct dvb_ringbuffer	 ci_wbuffer;
-
-	struct audio_mixer	mixer;
-
-	struct dvb_adapter	 dvb_adapter;
-	struct dvb_device	 *video_dev;
-	struct dvb_device	 *audio_dev;
-	struct dvb_device	 *ca_dev;
-	struct dvb_device	 *osd_dev;
-
-	struct dvb_video_events  video_events;
-	video_size_t		 video_size;
-
-	u16			wssMode;
-	u16			wssData;
-
-	struct infrared		ir;
-
-	/* firmware stuff */
-	unsigned char *bin_fw;
-	unsigned long size_fw;
-
-	unsigned char *bin_dpram;
-	unsigned long size_dpram;
-
-	unsigned char *bin_root;
-	unsigned long size_root;
-
-	struct dvb_frontend* fe;
-	fe_status_t fe_status;
-
-	/* crash recovery */
-	void				(*recover)(struct av7110* av7110);
-	fe_sec_voltage_t		saved_voltage;
-	fe_sec_tone_mode_t		saved_tone;
-	struct dvb_diseqc_master_cmd	saved_master_cmd;
-	fe_sec_mini_cmd_t		saved_minicmd;
-
-	int (*fe_init)(struct dvb_frontend* fe);
-	int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status);
-	int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe);
-	int (*fe_diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
-	int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
-	int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
-	int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
-	int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
-	int (*fe_set_frontend)(struct dvb_frontend *fe);
-};
-
-
-extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
-		       u16 subpid, u16 pcrpid);
-
-extern int av7110_check_ir_config(struct av7110 *av7110, int force);
-extern int av7110_ir_init(struct av7110 *av7110);
-extern void av7110_ir_exit(struct av7110 *av7110);
-
-/* msp3400 i2c subaddresses */
-#define MSP_WR_DEM 0x10
-#define MSP_RD_DEM 0x11
-#define MSP_WR_DSP 0x12
-#define MSP_RD_DSP 0x13
-
-extern int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val);
-extern u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg);
-extern int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val);
-
-
-extern int av7110_init_analog_module(struct av7110 *av7110);
-extern int av7110_init_v4l(struct av7110 *av7110);
-extern int av7110_exit_v4l(struct av7110 *av7110);
-
-#endif /* _AV7110_H_ */
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
deleted file mode 100644
index 952b33d..0000000
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ /dev/null
@@ -1,1626 +0,0 @@
-/*
- * av7110_av.c: audio and video MPEG decoder stuff
- *
- * Copyright (C) 1999-2002 Ralph  Metzler
- *                       & Marcus Metzler for convergence integrated media GmbH
- *
- * originally based on code by:
- * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org/ 
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/fs.h>
-
-#include "av7110.h"
-#include "av7110_hw.h"
-#include "av7110_av.h"
-#include "av7110_ipack.h"
-
-/* MPEG-2 (ISO 13818 / H.222.0) stream types */
-#define PROG_STREAM_MAP  0xBC
-#define PRIVATE_STREAM1  0xBD
-#define PADDING_STREAM	 0xBE
-#define PRIVATE_STREAM2  0xBF
-#define AUDIO_STREAM_S	 0xC0
-#define AUDIO_STREAM_E	 0xDF
-#define VIDEO_STREAM_S	 0xE0
-#define VIDEO_STREAM_E	 0xEF
-#define ECM_STREAM	 0xF0
-#define EMM_STREAM	 0xF1
-#define DSM_CC_STREAM	 0xF2
-#define ISO13522_STREAM  0xF3
-#define PROG_STREAM_DIR  0xFF
-
-#define PTS_DTS_FLAGS	 0xC0
-
-//pts_dts flags
-#define PTS_ONLY	 0x80
-#define PTS_DTS		 0xC0
-#define TS_SIZE		 188
-#define TRANS_ERROR	 0x80
-#define PAY_START	 0x40
-#define TRANS_PRIO	 0x20
-#define PID_MASK_HI	 0x1F
-//flags
-#define TRANS_SCRMBL1	 0x80
-#define TRANS_SCRMBL2	 0x40
-#define ADAPT_FIELD	 0x20
-#define PAYLOAD		 0x10
-#define COUNT_MASK	 0x0F
-
-// adaptation flags
-#define DISCON_IND	 0x80
-#define RAND_ACC_IND	 0x40
-#define ES_PRI_IND	 0x20
-#define PCR_FLAG	 0x10
-#define OPCR_FLAG	 0x08
-#define SPLICE_FLAG	 0x04
-#define TRANS_PRIV	 0x02
-#define ADAP_EXT_FLAG	 0x01
-
-// adaptation extension flags
-#define LTW_FLAG	 0x80
-#define PIECE_RATE	 0x40
-#define SEAM_SPLICE	 0x20
-
-
-static void p_to_t(u8 const *buf, long int length, u16 pid,
-		   u8 *counter, struct dvb_demux_feed *feed);
-static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len);
-
-
-int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len)
-{
-	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) p2t->priv;
-
-	if (!(dvbdmxfeed->ts_type & TS_PACKET))
-		return 0;
-	if (buf[3] == 0xe0)	 // video PES do not have a length in TS
-		buf[4] = buf[5] = 0;
-	if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)
-		return dvbdmxfeed->cb.ts(buf, len, NULL, 0,
-					 &dvbdmxfeed->feed.ts, DMX_OK);
-	else
-		return dvb_filter_pes2ts(p2t, buf, len, 1);
-}
-
-static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data)
-{
-	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv;
-
-	dvbdmxfeed->cb.ts(data, 188, NULL, 0,
-			  &dvbdmxfeed->feed.ts, DMX_OK);
-	return 0;
-}
-
-int av7110_av_start_record(struct av7110 *av7110, int av,
-			   struct dvb_demux_feed *dvbdmxfeed)
-{
-	int ret = 0;
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-
-	dprintk(2, "av7110:%p, , dvb_demux_feed:%p\n", av7110, dvbdmxfeed);
-
-	if (av7110->playing || (av7110->rec_mode & av))
-		return -EBUSY;
-	av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
-	dvbdmx->recording = 1;
-	av7110->rec_mode |= av;
-
-	switch (av7110->rec_mode) {
-	case RP_AUDIO:
-		dvb_filter_pes2ts_init(&av7110->p2t[0],
-				       dvbdmx->pesfilter[0]->pid,
-				       dvb_filter_pes2ts_cb,
-				       (void *) dvbdmx->pesfilter[0]);
-		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
-		break;
-
-	case RP_VIDEO:
-		dvb_filter_pes2ts_init(&av7110->p2t[1],
-				       dvbdmx->pesfilter[1]->pid,
-				       dvb_filter_pes2ts_cb,
-				       (void *) dvbdmx->pesfilter[1]);
-		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
-		break;
-
-	case RP_AV:
-		dvb_filter_pes2ts_init(&av7110->p2t[0],
-				       dvbdmx->pesfilter[0]->pid,
-				       dvb_filter_pes2ts_cb,
-				       (void *) dvbdmx->pesfilter[0]);
-		dvb_filter_pes2ts_init(&av7110->p2t[1],
-				       dvbdmx->pesfilter[1]->pid,
-				       dvb_filter_pes2ts_cb,
-				       (void *) dvbdmx->pesfilter[1]);
-		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0);
-		break;
-	}
-	return ret;
-}
-
-int av7110_av_start_play(struct av7110 *av7110, int av)
-{
-	int ret = 0;
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	if (av7110->rec_mode)
-		return -EBUSY;
-	if (av7110->playing & av)
-		return -EBUSY;
-
-	av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
-
-	if (av7110->playing == RP_NONE) {
-		av7110_ipack_reset(&av7110->ipack[0]);
-		av7110_ipack_reset(&av7110->ipack[1]);
-	}
-
-	av7110->playing |= av;
-	switch (av7110->playing) {
-	case RP_AUDIO:
-		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
-		break;
-	case RP_VIDEO:
-		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
-		av7110->sinfo = 0;
-		break;
-	case RP_AV:
-		av7110->sinfo = 0;
-		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0);
-		break;
-	}
-	return ret;
-}
-
-int av7110_av_stop(struct av7110 *av7110, int av)
-{
-	int ret = 0;
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	if (!(av7110->playing & av) && !(av7110->rec_mode & av))
-		return 0;
-	av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
-	if (av7110->playing) {
-		av7110->playing &= ~av;
-		switch (av7110->playing) {
-		case RP_AUDIO:
-			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
-			break;
-		case RP_VIDEO:
-			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
-			break;
-		case RP_NONE:
-			ret = av7110_set_vidmode(av7110, av7110->vidmode);
-			break;
-		}
-	} else {
-		av7110->rec_mode &= ~av;
-		switch (av7110->rec_mode) {
-		case RP_AUDIO:
-			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
-			break;
-		case RP_VIDEO:
-			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
-			break;
-		case RP_NONE:
-			break;
-		}
-	}
-	return ret;
-}
-
-
-int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen)
-{
-	int len;
-	u32 sync;
-	u16 blen;
-
-	if (!dlen) {
-		wake_up(&buf->queue);
-		return -1;
-	}
-	while (1) {
-		len = dvb_ringbuffer_avail(buf);
-		if (len < 6) {
-			wake_up(&buf->queue);
-			return -1;
-		}
-		sync =  DVB_RINGBUFFER_PEEK(buf, 0) << 24;
-		sync |= DVB_RINGBUFFER_PEEK(buf, 1) << 16;
-		sync |= DVB_RINGBUFFER_PEEK(buf, 2) << 8;
-		sync |= DVB_RINGBUFFER_PEEK(buf, 3);
-
-		if (((sync &~ 0x0f) == 0x000001e0) ||
-		    ((sync &~ 0x1f) == 0x000001c0) ||
-		    (sync == 0x000001bd))
-			break;
-		printk("resync\n");
-		DVB_RINGBUFFER_SKIP(buf, 1);
-	}
-	blen =  DVB_RINGBUFFER_PEEK(buf, 4) << 8;
-	blen |= DVB_RINGBUFFER_PEEK(buf, 5);
-	blen += 6;
-	if (len < blen || blen > dlen) {
-		//printk("buffer empty - avail %d blen %u dlen %d\n", len, blen, dlen);
-		wake_up(&buf->queue);
-		return -1;
-	}
-
-	dvb_ringbuffer_read(buf, dest, (size_t) blen);
-
-	dprintk(2, "pread=0x%08lx, pwrite=0x%08lx\n",
-	       (unsigned long) buf->pread, (unsigned long) buf->pwrite);
-	wake_up(&buf->queue);
-	return blen;
-}
-
-
-int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
-{
-	int err, vol, val, balance = 0;
-
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	av7110->mixer.volume_left = volleft;
-	av7110->mixer.volume_right = volright;
-
-	switch (av7110->adac_type) {
-	case DVB_ADAC_TI:
-		volleft = (volleft * 256) / 1036;
-		volright = (volright * 256) / 1036;
-		if (volleft > 0x3f)
-			volleft = 0x3f;
-		if (volright > 0x3f)
-			volright = 0x3f;
-		if ((err = SendDAC(av7110, 3, 0x80 + volleft)))
-			return err;
-		return SendDAC(av7110, 4, volright);
-
-	case DVB_ADAC_CRYSTAL:
-		volleft = 127 - volleft / 2;
-		volright = 127 - volright / 2;
-		i2c_writereg(av7110, 0x20, 0x03, volleft);
-		i2c_writereg(av7110, 0x20, 0x04, volright);
-		return 0;
-
-	case DVB_ADAC_MSP34x0:
-		vol  = (volleft > volright) ? volleft : volright;
-		val	= (vol * 0x73 / 255) << 8;
-		if (vol > 0)
-		       balance = ((volright - volleft) * 127) / vol;
-		msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8);
-		msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */
-		msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */
-		return 0;
-
-	case DVB_ADAC_MSP34x5:
-		vol = (volleft > volright) ? volleft : volright;
-		val = (vol * 0x73 / 255) << 8;
-		if (vol > 0)
-			balance = ((volright - volleft) * 127) / vol;
-		msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8);
-		msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */
-		return 0;
-	}
-
-	return 0;
-}
-
-int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode)
-{
-	int ret;
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode);
-
-	if (!ret && !av7110->playing) {
-		ret = ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO],
-			   av7110->pids[DMX_PES_AUDIO],
-			   av7110->pids[DMX_PES_TELETEXT],
-			   0, av7110->pids[DMX_PES_PCR]);
-		if (!ret)
-			ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
-	}
-	return ret;
-}
-
-
-static enum av7110_video_mode sw2mode[16] = {
-	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,
-	AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL,
-	AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC,
-	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,
-	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
-	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
-	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
-	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
-};
-
-static int get_video_format(struct av7110 *av7110, u8 *buf, int count)
-{
-	int i;
-	int hsize, vsize;
-	int sw;
-	u8 *p;
-	int ret = 0;
-
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	if (av7110->sinfo)
-		return 0;
-	for (i = 7; i < count - 10; i++) {
-		p = buf + i;
-		if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3)
-			continue;
-		p += 4;
-		hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4);
-		vsize = ((p[1] &0x0F) << 8) | (p[2]);
-		sw = (p[3] & 0x0F);
-		ret = av7110_set_vidmode(av7110, sw2mode[sw]);
-		if (!ret) {
-			dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw);
-			av7110->sinfo = 1;
-		}
-		break;
-	}
-	return ret;
-}
-
-
-/****************************************************************************
- * I/O buffer management and control
- ****************************************************************************/
-
-static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf,
-					 const u8 *buf, unsigned long count)
-{
-	unsigned long todo = count;
-	int free;
-
-	while (todo > 0) {
-		if (dvb_ringbuffer_free(rbuf) < 2048) {
-			if (wait_event_interruptible(rbuf->queue,
-						     (dvb_ringbuffer_free(rbuf) >= 2048)))
-				return count - todo;
-		}
-		free = dvb_ringbuffer_free(rbuf);
-		if (free > todo)
-			free = todo;
-		dvb_ringbuffer_write(rbuf, buf, free);
-		todo -= free;
-		buf += free;
-	}
-
-	return count - todo;
-}
-
-static void play_video_cb(u8 *buf, int count, void *priv)
-{
-	struct av7110 *av7110 = (struct av7110 *) priv;
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	if ((buf[3] & 0xe0) == 0xe0) {
-		get_video_format(av7110, buf, count);
-		aux_ring_buffer_write(&av7110->avout, buf, count);
-	} else
-		aux_ring_buffer_write(&av7110->aout, buf, count);
-}
-
-static void play_audio_cb(u8 *buf, int count, void *priv)
-{
-	struct av7110 *av7110 = (struct av7110 *) priv;
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	aux_ring_buffer_write(&av7110->aout, buf, count);
-}
-
-
-#define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096)
-
-static ssize_t ts_play(struct av7110 *av7110, const char __user *buf,
-		       unsigned long count, int nonblock, int type)
-{
-	struct dvb_ringbuffer *rb;
-	u8 *kb;
-	unsigned long todo = count;
-
-	dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count);
-
-	rb = (type) ? &av7110->avout : &av7110->aout;
-	kb = av7110->kbuf[type];
-
-	if (!kb)
-		return -ENOBUFS;
-
-	if (nonblock && !FREE_COND_TS)
-		return -EWOULDBLOCK;
-
-	while (todo >= TS_SIZE) {
-		if (!FREE_COND_TS) {
-			if (nonblock)
-				return count - todo;
-			if (wait_event_interruptible(rb->queue, FREE_COND_TS))
-				return count - todo;
-		}
-		if (copy_from_user(kb, buf, TS_SIZE))
-			return -EFAULT;
-		write_ts_to_decoder(av7110, type, kb, TS_SIZE);
-		todo -= TS_SIZE;
-		buf += TS_SIZE;
-	}
-
-	return count - todo;
-}
-
-
-#define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
-		   dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
-
-static ssize_t dvb_play(struct av7110 *av7110, const char __user *buf,
-			unsigned long count, int nonblock, int type)
-{
-	unsigned long todo = count, n;
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	if (!av7110->kbuf[type])
-		return -ENOBUFS;
-
-	if (nonblock && !FREE_COND)
-		return -EWOULDBLOCK;
-
-	while (todo > 0) {
-		if (!FREE_COND) {
-			if (nonblock)
-				return count - todo;
-			if (wait_event_interruptible(av7110->avout.queue,
-						     FREE_COND))
-				return count - todo;
-		}
-		n = todo;
-		if (n > IPACKS * 2)
-			n = IPACKS * 2;
-		if (copy_from_user(av7110->kbuf[type], buf, n))
-			return -EFAULT;
-		av7110_ipack_instant_repack(av7110->kbuf[type], n,
-					    &av7110->ipack[type]);
-		todo -= n;
-		buf += n;
-	}
-	return count - todo;
-}
-
-static ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf,
-			unsigned long count, int nonblock, int type)
-{
-	unsigned long todo = count, n;
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	if (!av7110->kbuf[type])
-		return -ENOBUFS;
-
-	if (nonblock && !FREE_COND)
-		return -EWOULDBLOCK;
-
-	while (todo > 0) {
-		if (!FREE_COND) {
-			if (nonblock)
-				return count - todo;
-			if (wait_event_interruptible(av7110->avout.queue,
-						     FREE_COND))
-				return count - todo;
-		}
-		n = todo;
-		if (n > IPACKS * 2)
-			n = IPACKS * 2;
-		av7110_ipack_instant_repack(buf, n, &av7110->ipack[type]);
-		todo -= n;
-		buf += n;
-	}
-	return count - todo;
-}
-
-static ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf,
-			 unsigned long count, int nonblock, int type)
-{
-	unsigned long todo = count, n;
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	if (!av7110->kbuf[type])
-		return -ENOBUFS;
-	if (nonblock && dvb_ringbuffer_free(&av7110->aout) < 20 * 1024)
-		return -EWOULDBLOCK;
-
-	while (todo > 0) {
-		if (dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) {
-			if (nonblock)
-				return count - todo;
-			if (wait_event_interruptible(av7110->aout.queue,
-					(dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)))
-				return count-todo;
-		}
-		n = todo;
-		if (n > IPACKS * 2)
-			n = IPACKS * 2;
-		if (copy_from_user(av7110->kbuf[type], buf, n))
-			return -EFAULT;
-		av7110_ipack_instant_repack(av7110->kbuf[type], n,
-					    &av7110->ipack[type]);
-		todo -= n;
-		buf += n;
-	}
-	return count - todo;
-}
-
-void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed)
-{
-	memset(p->pes, 0, TS_SIZE);
-	p->counter = 0;
-	p->pos = 0;
-	p->frags = 0;
-	if (feed)
-		p->feed = feed;
-}
-
-static void clear_p2t(struct av7110_p2t *p)
-{
-	memset(p->pes, 0, TS_SIZE);
-//	p->counter = 0;
-	p->pos = 0;
-	p->frags = 0;
-}
-
-
-static int find_pes_header(u8 const *buf, long int length, int *frags)
-{
-	int c = 0;
-	int found = 0;
-
-	*frags = 0;
-
-	while (c < length - 3 && !found) {
-		if (buf[c] == 0x00 && buf[c + 1] == 0x00 &&
-		    buf[c + 2] == 0x01) {
-			switch ( buf[c + 3] ) {
-			case PROG_STREAM_MAP:
-			case PRIVATE_STREAM2:
-			case PROG_STREAM_DIR:
-			case ECM_STREAM     :
-			case EMM_STREAM     :
-			case PADDING_STREAM :
-			case DSM_CC_STREAM  :
-			case ISO13522_STREAM:
-			case PRIVATE_STREAM1:
-			case AUDIO_STREAM_S ... AUDIO_STREAM_E:
-			case VIDEO_STREAM_S ... VIDEO_STREAM_E:
-				found = 1;
-				break;
-
-			default:
-				c++;
-				break;
-			}
-		} else
-			c++;
-	}
-	if (c == length - 3 && !found) {
-		if (buf[length - 1] == 0x00)
-			*frags = 1;
-		if (buf[length - 2] == 0x00 &&
-		    buf[length - 1] == 0x00)
-			*frags = 2;
-		if (buf[length - 3] == 0x00 &&
-		    buf[length - 2] == 0x00 &&
-		    buf[length - 1] == 0x01)
-			*frags = 3;
-		return -1;
-	}
-
-	return c;
-}
-
-void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p)
-{
-	int c, c2, l, add;
-	int check, rest;
-
-	c = 0;
-	c2 = 0;
-	if (p->frags){
-		check = 0;
-		switch(p->frags) {
-		case 1:
-			if (buf[c] == 0x00 && buf[c + 1] == 0x01) {
-				check = 1;
-				c += 2;
-			}
-			break;
-		case 2:
-			if (buf[c] == 0x01) {
-				check = 1;
-				c++;
-			}
-			break;
-		case 3:
-			check = 1;
-		}
-		if (check) {
-			switch (buf[c]) {
-			case PROG_STREAM_MAP:
-			case PRIVATE_STREAM2:
-			case PROG_STREAM_DIR:
-			case ECM_STREAM     :
-			case EMM_STREAM     :
-			case PADDING_STREAM :
-			case DSM_CC_STREAM  :
-			case ISO13522_STREAM:
-			case PRIVATE_STREAM1:
-			case AUDIO_STREAM_S ... AUDIO_STREAM_E:
-			case VIDEO_STREAM_S ... VIDEO_STREAM_E:
-				p->pes[0] = 0x00;
-				p->pes[1] = 0x00;
-				p->pes[2] = 0x01;
-				p->pes[3] = buf[c];
-				p->pos = 4;
-				memcpy(p->pes + p->pos, buf + c, (TS_SIZE - 4) - p->pos);
-				c += (TS_SIZE - 4) - p->pos;
-				p_to_t(p->pes, (TS_SIZE - 4), pid, &p->counter, p->feed);
-				clear_p2t(p);
-				break;
-
-			default:
-				c = 0;
-				break;
-			}
-		}
-		p->frags = 0;
-	}
-
-	if (p->pos) {
-		c2 = find_pes_header(buf + c, length - c, &p->frags);
-		if (c2 >= 0 && c2 < (TS_SIZE - 4) - p->pos)
-			l = c2+c;
-		else
-			l = (TS_SIZE - 4) - p->pos;
-		memcpy(p->pes + p->pos, buf, l);
-		c += l;
-		p->pos += l;
-		p_to_t(p->pes, p->pos, pid, &p->counter, p->feed);
-		clear_p2t(p);
-	}
-
-	add = 0;
-	while (c < length) {
-		c2 = find_pes_header(buf + c + add, length - c - add, &p->frags);
-		if (c2 >= 0) {
-			c2 += c + add;
-			if (c2 > c){
-				p_to_t(buf + c, c2 - c, pid, &p->counter, p->feed);
-				c = c2;
-				clear_p2t(p);
-				add = 0;
-			} else
-				add = 1;
-		} else {
-			l = length - c;
-			rest = l % (TS_SIZE - 4);
-			l -= rest;
-			p_to_t(buf + c, l, pid, &p->counter, p->feed);
-			memcpy(p->pes, buf + c + l, rest);
-			p->pos = rest;
-			c = length;
-		}
-	}
-}
-
-
-static int write_ts_header2(u16 pid, u8 *counter, int pes_start, u8 *buf, u8 length)
-{
-	int i;
-	int c = 0;
-	int fill;
-	u8 tshead[4] = { 0x47, 0x00, 0x00, 0x10 };
-
-	fill = (TS_SIZE - 4) - length;
-	if (pes_start)
-		tshead[1] = 0x40;
-	if (fill)
-		tshead[3] = 0x30;
-	tshead[1] |= (u8)((pid & 0x1F00) >> 8);
-	tshead[2] |= (u8)(pid & 0x00FF);
-	tshead[3] |= ((*counter)++ & 0x0F);
-	memcpy(buf, tshead, 4);
-	c += 4;
-
-	if (fill) {
-		buf[4] = fill - 1;
-		c++;
-		if (fill > 1) {
-			buf[5] = 0x00;
-			c++;
-		}
-		for (i = 6; i < fill + 4; i++) {
-			buf[i] = 0xFF;
-			c++;
-		}
-	}
-
-	return c;
-}
-
-
-static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter,
-		   struct dvb_demux_feed *feed)
-{
-	int l, pes_start;
-	u8 obuf[TS_SIZE];
-	long c = 0;
-
-	pes_start = 0;
-	if (length > 3 &&
-	     buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01)
-		switch (buf[3]) {
-			case PROG_STREAM_MAP:
-			case PRIVATE_STREAM2:
-			case PROG_STREAM_DIR:
-			case ECM_STREAM     :
-			case EMM_STREAM     :
-			case PADDING_STREAM :
-			case DSM_CC_STREAM  :
-			case ISO13522_STREAM:
-			case PRIVATE_STREAM1:
-			case AUDIO_STREAM_S ... AUDIO_STREAM_E:
-			case VIDEO_STREAM_S ... VIDEO_STREAM_E:
-				pes_start = 1;
-				break;
-
-			default:
-				break;
-		}
-
-	while (c < length) {
-		memset(obuf, 0, TS_SIZE);
-		if (length - c >= (TS_SIZE - 4)){
-			l = write_ts_header2(pid, counter, pes_start,
-					     obuf, (TS_SIZE - 4));
-			memcpy(obuf + l, buf + c, TS_SIZE - l);
-			c += TS_SIZE - l;
-		} else {
-			l = write_ts_header2(pid, counter, pes_start,
-					     obuf, length - c);
-			memcpy(obuf + l, buf + c, TS_SIZE - l);
-			c = length;
-		}
-		feed->cb.ts(obuf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
-		pes_start = 0;
-	}
-}
-
-
-static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len)
-{
-	struct ipack *ipack = &av7110->ipack[type];
-
-	if (buf[1] & TRANS_ERROR) {
-		av7110_ipack_reset(ipack);
-		return -1;
-	}
-
-	if (!(buf[3] & PAYLOAD))
-		return -1;
-
-	if (buf[1] & PAY_START)
-		av7110_ipack_flush(ipack);
-
-	if (buf[3] & ADAPT_FIELD) {
-		len -= buf[4] + 1;
-		buf += buf[4] + 1;
-		if (!len)
-			return 0;
-	}
-
-	av7110_ipack_instant_repack(buf + 4, len - 4, ipack);
-	return 0;
-}
-
-
-int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len)
-{
-	struct dvb_demux *demux = feed->demux;
-	struct av7110 *av7110 = (struct av7110 *) demux->priv;
-
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE)
-		return 0;
-
-	switch (feed->pes_type) {
-	case 0:
-		if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
-			return -EINVAL;
-		break;
-	case 1:
-		if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY)
-			return -EINVAL;
-		break;
-	default:
-		return -1;
-	}
-
-	return write_ts_to_decoder(av7110, feed->pes_type, buf, len);
-}
-
-
-
-/******************************************************************************
- * Video MPEG decoder events
- ******************************************************************************/
-void dvb_video_add_event(struct av7110 *av7110, struct video_event *event)
-{
-	struct dvb_video_events *events = &av7110->video_events;
-	int wp;
-
-	spin_lock_bh(&events->lock);
-
-	wp = (events->eventw + 1) % MAX_VIDEO_EVENT;
-	if (wp == events->eventr) {
-		events->overflow = 1;
-		events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT;
-	}
-
-	//FIXME: timestamp?
-	memcpy(&events->events[events->eventw], event, sizeof(struct video_event));
-	events->eventw = wp;
-
-	spin_unlock_bh(&events->lock);
-
-	wake_up_interruptible(&events->wait_queue);
-}
-
-
-static int dvb_video_get_event (struct av7110 *av7110, struct video_event *event, int flags)
-{
-	struct dvb_video_events *events = &av7110->video_events;
-
-	if (events->overflow) {
-		events->overflow = 0;
-		return -EOVERFLOW;
-	}
-	if (events->eventw == events->eventr) {
-		int ret;
-
-		if (flags & O_NONBLOCK)
-			return -EWOULDBLOCK;
-
-		ret = wait_event_interruptible(events->wait_queue,
-					       events->eventw != events->eventr);
-		if (ret < 0)
-			return ret;
-	}
-
-	spin_lock_bh(&events->lock);
-
-	memcpy(event, &events->events[events->eventr],
-	       sizeof(struct video_event));
-	events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT;
-
-	spin_unlock_bh(&events->lock);
-
-	return 0;
-}
-
-
-/******************************************************************************
- * DVB device file operations
- ******************************************************************************/
-
-static unsigned int dvb_video_poll(struct file *file, poll_table *wait)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct av7110 *av7110 = dvbdev->priv;
-	unsigned int mask = 0;
-
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	if ((file->f_flags & O_ACCMODE) != O_RDONLY)
-		poll_wait(file, &av7110->avout.queue, wait);
-
-	poll_wait(file, &av7110->video_events.wait_queue, wait);
-
-	if (av7110->video_events.eventw != av7110->video_events.eventr)
-		mask = POLLPRI;
-
-	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
-		if (av7110->playing) {
-			if (FREE_COND)
-				mask |= (POLLOUT | POLLWRNORM);
-			} else /* if not playing: may play if asked for */
-				mask |= (POLLOUT | POLLWRNORM);
-	}
-
-	return mask;
-}
-
-static ssize_t dvb_video_write(struct file *file, const char __user *buf,
-			       size_t count, loff_t *ppos)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct av7110 *av7110 = dvbdev->priv;
-	unsigned char c;
-
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
-		return -EPERM;
-
-	if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY)
-		return -EPERM;
-
-	if (get_user(c, buf))
-		return -EFAULT;
-	if (c == 0x47 && count % TS_SIZE == 0)
-		return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
-	else
-		return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
-}
-
-static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct av7110 *av7110 = dvbdev->priv;
-	unsigned int mask = 0;
-
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	poll_wait(file, &av7110->aout.queue, wait);
-
-	if (av7110->playing) {
-		if (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
-			mask |= (POLLOUT | POLLWRNORM);
-	} else /* if not playing: may play if asked for */
-		mask = (POLLOUT | POLLWRNORM);
-
-	return mask;
-}
-
-static ssize_t dvb_audio_write(struct file *file, const char __user *buf,
-			       size_t count, loff_t *ppos)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct av7110 *av7110 = dvbdev->priv;
-	unsigned char c;
-
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	if (av7110->audiostate.stream_source != AUDIO_SOURCE_MEMORY) {
-		printk(KERN_ERR "not audio source memory\n");
-		return -EPERM;
-	}
-
-	if (get_user(c, buf))
-		return -EFAULT;
-	if (c == 0x47 && count % TS_SIZE == 0)
-		return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
-	else
-		return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
-}
-
-static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 };
-
-#define MIN_IFRAME 400000
-
-static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock)
-{
-	unsigned i, n;
-	int progressive = 0;
-	int match = 0;
-
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	if (!(av7110->playing & RP_VIDEO)) {
-		if (av7110_av_start_play(av7110, RP_VIDEO) < 0)
-			return -EBUSY;
-	}
-
-	/* search in buf for instances of 00 00 01 b5 1? */
-	for (i = 0; i < len; i++) {
-		unsigned char c;
-		if (get_user(c, buf + i))
-			return -EFAULT;
-		if (match == 5) {
-			progressive = c & 0x08;
-			match = 0;
-		}
-		if (c == 0x00) {
-			match = (match == 1 || match == 2) ? 2 : 1;
-			continue;
-		}
-		switch (match++) {
-		case 2: if (c == 0x01)
-				continue;
-			break;
-		case 3: if (c == 0xb5)
-				continue;
-			break;
-		case 4: if ((c & 0xf0) == 0x10)
-				continue;
-			break;
-		}
-		match = 0;
-	}
-
-	/* setting n always > 1, fixes problems when playing stillframes
-	   consisting of I- and P-Frames */
-	n = MIN_IFRAME / len + 1;
-
-	/* FIXME: nonblock? */
-	dvb_play_kernel(av7110, iframe_header, sizeof(iframe_header), 0, 1);
-
-	for (i = 0; i < n; i++)
-		dvb_play(av7110, buf, len, 0, 1);
-
-	av7110_ipack_flush(&av7110->ipack[1]);
-
-	if (progressive)
-		return vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1);
-	else
-		return 0;
-}
-
-
-static int dvb_video_ioctl(struct file *file,
-			   unsigned int cmd, void *parg)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct av7110 *av7110 = dvbdev->priv;
-	unsigned long arg = (unsigned long) parg;
-	int ret = 0;
-
-	dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd);
-
-	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
-		if ( cmd != VIDEO_GET_STATUS && cmd != VIDEO_GET_EVENT &&
-		     cmd != VIDEO_GET_SIZE ) {
-			return -EPERM;
-		}
-	}
-
-	switch (cmd) {
-	case VIDEO_STOP:
-		av7110->videostate.play_state = VIDEO_STOPPED;
-		if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY)
-			ret = av7110_av_stop(av7110, RP_VIDEO);
-		else
-			ret = vidcom(av7110, AV_VIDEO_CMD_STOP,
-			       av7110->videostate.video_blank ? 0 : 1);
-		if (!ret)
-			av7110->trickmode = TRICK_NONE;
-		break;
-
-	case VIDEO_PLAY:
-		av7110->trickmode = TRICK_NONE;
-		if (av7110->videostate.play_state == VIDEO_FREEZED) {
-			av7110->videostate.play_state = VIDEO_PLAYING;
-			ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
-			if (ret)
-				break;
-		}
-		if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) {
-			if (av7110->playing == RP_AV) {
-				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
-				if (ret)
-					break;
-				av7110->playing &= ~RP_VIDEO;
-			}
-			ret = av7110_av_start_play(av7110, RP_VIDEO);
-		}
-		if (!ret)
-			ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
-		if (!ret)
-			av7110->videostate.play_state = VIDEO_PLAYING;
-		break;
-
-	case VIDEO_FREEZE:
-		av7110->videostate.play_state = VIDEO_FREEZED;
-		if (av7110->playing & RP_VIDEO)
-			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0);
-		else
-			ret = vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1);
-		if (!ret)
-			av7110->trickmode = TRICK_FREEZE;
-		break;
-
-	case VIDEO_CONTINUE:
-		if (av7110->playing & RP_VIDEO)
-			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0);
-		if (!ret)
-			ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
-		if (!ret) {
-			av7110->videostate.play_state = VIDEO_PLAYING;
-			av7110->trickmode = TRICK_NONE;
-		}
-		break;
-
-	case VIDEO_SELECT_SOURCE:
-		av7110->videostate.stream_source = (video_stream_source_t) arg;
-		break;
-
-	case VIDEO_SET_BLANK:
-		av7110->videostate.video_blank = (int) arg;
-		break;
-
-	case VIDEO_GET_STATUS:
-		memcpy(parg, &av7110->videostate, sizeof(struct video_status));
-		break;
-
-	case VIDEO_GET_EVENT:
-		ret = dvb_video_get_event(av7110, parg, file->f_flags);
-		break;
-
-	case VIDEO_GET_SIZE:
-		memcpy(parg, &av7110->video_size, sizeof(video_size_t));
-		break;
-
-	case VIDEO_SET_DISPLAY_FORMAT:
-	{
-		video_displayformat_t format = (video_displayformat_t) arg;
-		switch (format) {
-		case VIDEO_PAN_SCAN:
-			av7110->display_panscan = VID_PAN_SCAN_PREF;
-			break;
-		case VIDEO_LETTER_BOX:
-			av7110->display_panscan = VID_VC_AND_PS_PREF;
-			break;
-		case VIDEO_CENTER_CUT_OUT:
-			av7110->display_panscan = VID_CENTRE_CUT_PREF;
-			break;
-		default:
-			ret = -EINVAL;
-		}
-		if (ret < 0)
-			break;
-		av7110->videostate.display_format = format;
-		ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
-				    1, av7110->display_panscan);
-		break;
-	}
-
-	case VIDEO_SET_FORMAT:
-		if (arg > 1) {
-			ret = -EINVAL;
-			break;
-		}
-		av7110->display_ar = arg;
-		ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType,
-				    1, (u16) arg);
-		break;
-
-	case VIDEO_STILLPICTURE:
-	{
-		struct video_still_picture *pic =
-			(struct video_still_picture *) parg;
-		av7110->videostate.stream_source = VIDEO_SOURCE_MEMORY;
-		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
-		ret = play_iframe(av7110, pic->iFrame, pic->size,
-				  file->f_flags & O_NONBLOCK);
-		break;
-	}
-
-	case VIDEO_FAST_FORWARD:
-		//note: arg is ignored by firmware
-		if (av7110->playing & RP_VIDEO)
-			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
-					    __Scan_I, 2, AV_PES, 0);
-		else
-			ret = vidcom(av7110, AV_VIDEO_CMD_FFWD, arg);
-		if (!ret) {
-			av7110->trickmode = TRICK_FAST;
-			av7110->videostate.play_state = VIDEO_PLAYING;
-		}
-		break;
-
-	case VIDEO_SLOWMOTION:
-		if (av7110->playing&RP_VIDEO) {
-			if (av7110->trickmode != TRICK_SLOW)
-				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
-			if (!ret)
-				ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
-		} else {
-			ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
-			if (!ret)
-				ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 0);
-			if (!ret)
-				ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
-		}
-		if (!ret) {
-			av7110->trickmode = TRICK_SLOW;
-			av7110->videostate.play_state = VIDEO_PLAYING;
-		}
-		break;
-
-	case VIDEO_GET_CAPABILITIES:
-		*(int *)parg = VIDEO_CAP_MPEG1 | VIDEO_CAP_MPEG2 |
-			VIDEO_CAP_SYS | VIDEO_CAP_PROG;
-		break;
-
-	case VIDEO_CLEAR_BUFFER:
-		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
-		av7110_ipack_reset(&av7110->ipack[1]);
-		if (av7110->playing == RP_AV) {
-			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
-					    __Play, 2, AV_PES, 0);
-			if (ret)
-				break;
-			if (av7110->trickmode == TRICK_FAST)
-				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
-						    __Scan_I, 2, AV_PES, 0);
-			if (av7110->trickmode == TRICK_SLOW) {
-				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
-						    __Slow, 2, 0, 0);
-				if (!ret)
-					ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
-			}
-			if (av7110->trickmode == TRICK_FREEZE)
-				ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 1);
-		}
-		break;
-
-	case VIDEO_SET_STREAMTYPE:
-		break;
-
-	default:
-		ret = -ENOIOCTLCMD;
-		break;
-	}
-
-	return ret;
-}
-
-static int dvb_audio_ioctl(struct file *file,
-			   unsigned int cmd, void *parg)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct av7110 *av7110 = dvbdev->priv;
-	unsigned long arg = (unsigned long) parg;
-	int ret = 0;
-
-	dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd);
-
-	if (((file->f_flags & O_ACCMODE) == O_RDONLY) &&
-	    (cmd != AUDIO_GET_STATUS))
-		return -EPERM;
-
-	switch (cmd) {
-	case AUDIO_STOP:
-		if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
-			ret = av7110_av_stop(av7110, RP_AUDIO);
-		else
-			ret = audcom(av7110, AUDIO_CMD_MUTE);
-		if (!ret)
-			av7110->audiostate.play_state = AUDIO_STOPPED;
-		break;
-
-	case AUDIO_PLAY:
-		if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
-			ret = av7110_av_start_play(av7110, RP_AUDIO);
-		if (!ret)
-			ret = audcom(av7110, AUDIO_CMD_UNMUTE);
-		if (!ret)
-			av7110->audiostate.play_state = AUDIO_PLAYING;
-		break;
-
-	case AUDIO_PAUSE:
-		ret = audcom(av7110, AUDIO_CMD_MUTE);
-		if (!ret)
-			av7110->audiostate.play_state = AUDIO_PAUSED;
-		break;
-
-	case AUDIO_CONTINUE:
-		if (av7110->audiostate.play_state == AUDIO_PAUSED) {
-			av7110->audiostate.play_state = AUDIO_PLAYING;
-			ret = audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16);
-		}
-		break;
-
-	case AUDIO_SELECT_SOURCE:
-		av7110->audiostate.stream_source = (audio_stream_source_t) arg;
-		break;
-
-	case AUDIO_SET_MUTE:
-	{
-		ret = audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE);
-		if (!ret)
-			av7110->audiostate.mute_state = (int) arg;
-		break;
-	}
-
-	case AUDIO_SET_AV_SYNC:
-		av7110->audiostate.AV_sync_state = (int) arg;
-		ret = audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF);
-		break;
-
-	case AUDIO_SET_BYPASS_MODE:
-		if (FW_VERSION(av7110->arm_app) < 0x2621)
-			ret = -EINVAL;
-		av7110->audiostate.bypass_mode = (int)arg;
-		break;
-
-	case AUDIO_CHANNEL_SELECT:
-		av7110->audiostate.channel_select = (audio_channel_select_t) arg;
-		switch(av7110->audiostate.channel_select) {
-		case AUDIO_STEREO:
-			ret = audcom(av7110, AUDIO_CMD_STEREO);
-			if (!ret) {
-				if (av7110->adac_type == DVB_ADAC_CRYSTAL)
-					i2c_writereg(av7110, 0x20, 0x02, 0x49);
-				else if (av7110->adac_type == DVB_ADAC_MSP34x5)
-					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220);
-			}
-			break;
-		case AUDIO_MONO_LEFT:
-			ret = audcom(av7110, AUDIO_CMD_MONO_L);
-			if (!ret) {
-				if (av7110->adac_type == DVB_ADAC_CRYSTAL)
-					i2c_writereg(av7110, 0x20, 0x02, 0x4a);
-				else if (av7110->adac_type == DVB_ADAC_MSP34x5)
-					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200);
-			}
-			break;
-		case AUDIO_MONO_RIGHT:
-			ret = audcom(av7110, AUDIO_CMD_MONO_R);
-			if (!ret) {
-				if (av7110->adac_type == DVB_ADAC_CRYSTAL)
-					i2c_writereg(av7110, 0x20, 0x02, 0x45);
-				else if (av7110->adac_type == DVB_ADAC_MSP34x5)
-					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210);
-			}
-			break;
-		default:
-			ret = -EINVAL;
-			break;
-		}
-		break;
-
-	case AUDIO_GET_STATUS:
-		memcpy(parg, &av7110->audiostate, sizeof(struct audio_status));
-		break;
-
-	case AUDIO_GET_CAPABILITIES:
-		if (FW_VERSION(av7110->arm_app) < 0x2621)
-			*(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
-		else
-			*(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_DTS | AUDIO_CAP_AC3 |
-						AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
-		break;
-
-	case AUDIO_CLEAR_BUFFER:
-		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
-		av7110_ipack_reset(&av7110->ipack[0]);
-		if (av7110->playing == RP_AV)
-			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
-					    __Play, 2, AV_PES, 0);
-		break;
-
-	case AUDIO_SET_ID:
-		break;
-
-	case AUDIO_SET_MIXER:
-	{
-		struct audio_mixer *amix = (struct audio_mixer *)parg;
-		ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right);
-		break;
-	}
-
-	case AUDIO_SET_STREAMTYPE:
-		break;
-
-	default:
-		ret = -ENOIOCTLCMD;
-	}
-
-	return ret;
-}
-
-
-static int dvb_video_open(struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct av7110 *av7110 = dvbdev->priv;
-	int err;
-
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	if ((err = dvb_generic_open(inode, file)) < 0)
-		return err;
-
-	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
-		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
-		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
-		av7110->video_blank = 1;
-		av7110->audiostate.AV_sync_state = 1;
-		av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX;
-
-		/*  empty event queue */
-		av7110->video_events.eventr = av7110->video_events.eventw = 0;
-	}
-
-	return 0;
-}
-
-static int dvb_video_release(struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct av7110 *av7110 = dvbdev->priv;
-
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
-		av7110_av_stop(av7110, RP_VIDEO);
-	}
-
-	return dvb_generic_release(inode, file);
-}
-
-static int dvb_audio_open(struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct av7110 *av7110 = dvbdev->priv;
-	int err = dvb_generic_open(inode, file);
-
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	if (err < 0)
-		return err;
-	dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
-	av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX;
-	return 0;
-}
-
-static int dvb_audio_release(struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct av7110 *av7110 = dvbdev->priv;
-
-	dprintk(2, "av7110:%p, \n", av7110);
-
-	av7110_av_stop(av7110, RP_AUDIO);
-	return dvb_generic_release(inode, file);
-}
-
-
-
-/******************************************************************************
- * driver registration
- ******************************************************************************/
-
-static const struct file_operations dvb_video_fops = {
-	.owner		= THIS_MODULE,
-	.write		= dvb_video_write,
-	.unlocked_ioctl	= dvb_generic_ioctl,
-	.open		= dvb_video_open,
-	.release	= dvb_video_release,
-	.poll		= dvb_video_poll,
-	.llseek		= noop_llseek,
-};
-
-static struct dvb_device dvbdev_video = {
-	.priv		= NULL,
-	.users		= 6,
-	.readers	= 5,	/* arbitrary */
-	.writers	= 1,
-	.fops		= &dvb_video_fops,
-	.kernel_ioctl	= dvb_video_ioctl,
-};
-
-static const struct file_operations dvb_audio_fops = {
-	.owner		= THIS_MODULE,
-	.write		= dvb_audio_write,
-	.unlocked_ioctl	= dvb_generic_ioctl,
-	.open		= dvb_audio_open,
-	.release	= dvb_audio_release,
-	.poll		= dvb_audio_poll,
-	.llseek		= noop_llseek,
-};
-
-static struct dvb_device dvbdev_audio = {
-	.priv		= NULL,
-	.users		= 1,
-	.writers	= 1,
-	.fops		= &dvb_audio_fops,
-	.kernel_ioctl	= dvb_audio_ioctl,
-};
-
-
-int av7110_av_register(struct av7110 *av7110)
-{
-	av7110->audiostate.AV_sync_state = 0;
-	av7110->audiostate.mute_state = 0;
-	av7110->audiostate.play_state = AUDIO_STOPPED;
-	av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX;
-	av7110->audiostate.channel_select = AUDIO_STEREO;
-	av7110->audiostate.bypass_mode = 0;
-
-	av7110->videostate.video_blank = 0;
-	av7110->videostate.play_state = VIDEO_STOPPED;
-	av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX;
-	av7110->videostate.video_format = VIDEO_FORMAT_4_3;
-	av7110->videostate.display_format = VIDEO_LETTER_BOX;
-	av7110->display_ar = VIDEO_FORMAT_4_3;
-	av7110->display_panscan = VID_VC_AND_PS_PREF;
-
-	init_waitqueue_head(&av7110->video_events.wait_queue);
-	spin_lock_init(&av7110->video_events.lock);
-	av7110->video_events.eventw = av7110->video_events.eventr = 0;
-	av7110->video_events.overflow = 0;
-	memset(&av7110->video_size, 0, sizeof (video_size_t));
-
-	dvb_register_device(&av7110->dvb_adapter, &av7110->video_dev,
-			    &dvbdev_video, av7110, DVB_DEVICE_VIDEO);
-
-	dvb_register_device(&av7110->dvb_adapter, &av7110->audio_dev,
-			    &dvbdev_audio, av7110, DVB_DEVICE_AUDIO);
-
-	return 0;
-}
-
-void av7110_av_unregister(struct av7110 *av7110)
-{
-	dvb_unregister_device(av7110->audio_dev);
-	dvb_unregister_device(av7110->video_dev);
-}
-
-int av7110_av_init(struct av7110 *av7110)
-{
-	void (*play[])(u8 *, int, void *) = { play_audio_cb, play_video_cb };
-	int i, ret;
-
-	for (i = 0; i < 2; i++) {
-		struct ipack *ipack = av7110->ipack + i;
-
-		ret = av7110_ipack_init(ipack, IPACKS, play[i]);
-		if (ret < 0) {
-			if (i)
-				av7110_ipack_free(--ipack);
-			goto out;
-		}
-		ipack->data = av7110;
-	}
-
-	dvb_ringbuffer_init(&av7110->avout, av7110->iobuf, AVOUTLEN);
-	dvb_ringbuffer_init(&av7110->aout, av7110->iobuf + AVOUTLEN, AOUTLEN);
-
-	av7110->kbuf[0] = (u8 *)(av7110->iobuf + AVOUTLEN + AOUTLEN + BMPLEN);
-	av7110->kbuf[1] = av7110->kbuf[0] + 2 * IPACKS;
-out:
-	return ret;
-}
-
-void av7110_av_exit(struct av7110 *av7110)
-{
-	av7110_ipack_free(&av7110->ipack[0]);
-	av7110_ipack_free(&av7110->ipack[1]);
-}
diff --git a/drivers/media/dvb/ttpci/av7110_av.h b/drivers/media/dvb/ttpci/av7110_av.h
deleted file mode 100644
index 5f02ef8..0000000
--- a/drivers/media/dvb/ttpci/av7110_av.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef _AV7110_AV_H_
-#define _AV7110_AV_H_
-
-struct av7110;
-
-extern int av7110_set_vidmode(struct av7110 *av7110,
-			      enum av7110_video_mode mode);
-
-extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len);
-extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen);
-extern int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len);
-
-extern int av7110_set_volume(struct av7110 *av7110, int volleft, int volright);
-extern int av7110_av_stop(struct av7110 *av7110, int av);
-extern int av7110_av_start_record(struct av7110 *av7110, int av,
-			  struct dvb_demux_feed *dvbdmxfeed);
-extern int av7110_av_start_play(struct av7110 *av7110, int av);
-
-extern void dvb_video_add_event(struct av7110 *av7110, struct video_event *event);
-
-extern void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed);
-extern void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p);
-
-extern int av7110_av_register(struct av7110 *av7110);
-extern void av7110_av_unregister(struct av7110 *av7110);
-extern int av7110_av_init(struct av7110 *av7110);
-extern void av7110_av_exit(struct av7110 *av7110);
-
-
-#endif /* _AV7110_AV_H_ */
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
deleted file mode 100644
index 9fc1dd0..0000000
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * av7110_ca.c: CA and CI stuff
- *
- * Copyright (C) 1999-2002 Ralph  Metzler
- *                       & Marcus Metzler for convergence integrated media GmbH
- *
- * originally based on code by:
- * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org/ 
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/timer.h>
-#include <linux/poll.h>
-#include <linux/gfp.h>
-
-#include "av7110.h"
-#include "av7110_hw.h"
-#include "av7110_ca.h"
-
-
-void CI_handle(struct av7110 *av7110, u8 *data, u16 len)
-{
-	dprintk(8, "av7110:%p\n",av7110);
-
-	if (len < 3)
-		return;
-	switch (data[0]) {
-	case CI_MSG_CI_INFO:
-		if (data[2] != 1 && data[2] != 2)
-			break;
-		switch (data[1]) {
-		case 0:
-			av7110->ci_slot[data[2] - 1].flags = 0;
-			break;
-		case 1:
-			av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_PRESENT;
-			break;
-		case 2:
-			av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_READY;
-			break;
-		}
-		break;
-	case CI_SWITCH_PRG_REPLY:
-		//av7110->ci_stat=data[1];
-		break;
-	default:
-		break;
-	}
-}
-
-
-void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len)
-{
-	if (dvb_ringbuffer_free(cibuf) < len + 2)
-		return;
-
-	DVB_RINGBUFFER_WRITE_BYTE(cibuf, len >> 8);
-	DVB_RINGBUFFER_WRITE_BYTE(cibuf, len & 0xff);
-	dvb_ringbuffer_write(cibuf, data, len);
-	wake_up_interruptible(&cibuf->queue);
-}
-
-
-/******************************************************************************
- * CI link layer file ops
- ******************************************************************************/
-
-static int ci_ll_init(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf, int size)
-{
-	struct dvb_ringbuffer *tab[] = { cirbuf, ciwbuf, NULL }, **p;
-	void *data;
-
-	for (p = tab; *p; p++) {
-		data = vmalloc(size);
-		if (!data) {
-			while (p-- != tab) {
-				vfree(p[0]->data);
-				p[0]->data = NULL;
-			}
-			return -ENOMEM;
-		}
-		dvb_ringbuffer_init(*p, data, size);
-	}
-	return 0;
-}
-
-static void ci_ll_flush(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf)
-{
-	dvb_ringbuffer_flush_spinlock_wakeup(cirbuf);
-	dvb_ringbuffer_flush_spinlock_wakeup(ciwbuf);
-}
-
-static void ci_ll_release(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf)
-{
-	vfree(cirbuf->data);
-	cirbuf->data = NULL;
-	vfree(ciwbuf->data);
-	ciwbuf->data = NULL;
-}
-
-static int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file,
-		       int slots, ca_slot_info_t *slot)
-{
-	int i;
-	int len = 0;
-	u8 msg[8] = { 0x00, 0x06, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00 };
-
-	for (i = 0; i < 2; i++) {
-		if (slots & (1 << i))
-			len += 8;
-	}
-
-	if (dvb_ringbuffer_free(cibuf) < len)
-		return -EBUSY;
-
-	for (i = 0; i < 2; i++) {
-		if (slots & (1 << i)) {
-			msg[2] = i;
-			dvb_ringbuffer_write(cibuf, msg, 8);
-			slot[i].flags = 0;
-		}
-	}
-
-	return 0;
-}
-
-static ssize_t ci_ll_write(struct dvb_ringbuffer *cibuf, struct file *file,
-			   const char __user *buf, size_t count, loff_t *ppos)
-{
-	int free;
-	int non_blocking = file->f_flags & O_NONBLOCK;
-	u8 *page = (u8 *)__get_free_page(GFP_USER);
-	int res;
-
-	if (!page)
-		return -ENOMEM;
-
-	res = -EINVAL;
-	if (count > 2048)
-		goto out;
-
-	res = -EFAULT;
-	if (copy_from_user(page, buf, count))
-		goto out;
-
-	free = dvb_ringbuffer_free(cibuf);
-	if (count + 2 > free) {
-		res = -EWOULDBLOCK;
-		if (non_blocking)
-			goto out;
-		res = -ERESTARTSYS;
-		if (wait_event_interruptible(cibuf->queue,
-					     (dvb_ringbuffer_free(cibuf) >= count + 2)))
-			goto out;
-	}
-
-	DVB_RINGBUFFER_WRITE_BYTE(cibuf, count >> 8);
-	DVB_RINGBUFFER_WRITE_BYTE(cibuf, count & 0xff);
-
-	res = dvb_ringbuffer_write(cibuf, page, count);
-out:
-	free_page((unsigned long)page);
-	return res;
-}
-
-static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file,
-			  char __user *buf, size_t count, loff_t *ppos)
-{
-	int avail;
-	int non_blocking = file->f_flags & O_NONBLOCK;
-	ssize_t len;
-
-	if (!cibuf->data || !count)
-		return 0;
-	if (non_blocking && (dvb_ringbuffer_empty(cibuf)))
-		return -EWOULDBLOCK;
-	if (wait_event_interruptible(cibuf->queue,
-				     !dvb_ringbuffer_empty(cibuf)))
-		return -ERESTARTSYS;
-	avail = dvb_ringbuffer_avail(cibuf);
-	if (avail < 4)
-		return 0;
-	len = DVB_RINGBUFFER_PEEK(cibuf, 0) << 8;
-	len |= DVB_RINGBUFFER_PEEK(cibuf, 1);
-	if (avail < len + 2 || count < len)
-		return -EINVAL;
-	DVB_RINGBUFFER_SKIP(cibuf, 2);
-
-	return dvb_ringbuffer_read_user(cibuf, buf, len);
-}
-
-static int dvb_ca_open(struct inode *inode, struct file *file)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct av7110 *av7110 = dvbdev->priv;
-	int err = dvb_generic_open(inode, file);
-
-	dprintk(8, "av7110:%p\n",av7110);
-
-	if (err < 0)
-		return err;
-	ci_ll_flush(&av7110->ci_rbuffer, &av7110->ci_wbuffer);
-	return 0;
-}
-
-static unsigned int dvb_ca_poll (struct file *file, poll_table *wait)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct av7110 *av7110 = dvbdev->priv;
-	struct dvb_ringbuffer *rbuf = &av7110->ci_rbuffer;
-	struct dvb_ringbuffer *wbuf = &av7110->ci_wbuffer;
-	unsigned int mask = 0;
-
-	dprintk(8, "av7110:%p\n",av7110);
-
-	poll_wait(file, &rbuf->queue, wait);
-	poll_wait(file, &wbuf->queue, wait);
-
-	if (!dvb_ringbuffer_empty(rbuf))
-		mask |= (POLLIN | POLLRDNORM);
-
-	if (dvb_ringbuffer_free(wbuf) > 1024)
-		mask |= (POLLOUT | POLLWRNORM);
-
-	return mask;
-}
-
-static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct av7110 *av7110 = dvbdev->priv;
-	unsigned long arg = (unsigned long) parg;
-
-	dprintk(8, "av7110:%p\n",av7110);
-
-	switch (cmd) {
-	case CA_RESET:
-		return ci_ll_reset(&av7110->ci_wbuffer, file, arg, &av7110->ci_slot[0]);
-		break;
-	case CA_GET_CAP:
-	{
-		ca_caps_t cap;
-
-		cap.slot_num = 2;
-		cap.slot_type = (FW_CI_LL_SUPPORT(av7110->arm_app) ?
-				 CA_CI_LINK : CA_CI) | CA_DESCR;
-		cap.descr_num = 16;
-		cap.descr_type = CA_ECD;
-		memcpy(parg, &cap, sizeof(cap));
-		break;
-	}
-
-	case CA_GET_SLOT_INFO:
-	{
-		ca_slot_info_t *info=(ca_slot_info_t *)parg;
-
-		if (info->num < 0 || info->num > 1)
-			return -EINVAL;
-		av7110->ci_slot[info->num].num = info->num;
-		av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
-							CA_CI_LINK : CA_CI;
-		memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t));
-		break;
-	}
-
-	case CA_GET_MSG:
-		break;
-
-	case CA_SEND_MSG:
-		break;
-
-	case CA_GET_DESCR_INFO:
-	{
-		ca_descr_info_t info;
-
-		info.num = 16;
-		info.type = CA_ECD;
-		memcpy(parg, &info, sizeof (info));
-		break;
-	}
-
-	case CA_SET_DESCR:
-	{
-		ca_descr_t *descr = (ca_descr_t*) parg;
-
-		if (descr->index >= 16)
-			return -EINVAL;
-		if (descr->parity > 1)
-			return -EINVAL;
-		av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetDescr, 5,
-			      (descr->index<<8)|descr->parity,
-			      (descr->cw[0]<<8)|descr->cw[1],
-			      (descr->cw[2]<<8)|descr->cw[3],
-			      (descr->cw[4]<<8)|descr->cw[5],
-			      (descr->cw[6]<<8)|descr->cw[7]);
-		break;
-	}
-
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static ssize_t dvb_ca_write(struct file *file, const char __user *buf,
-			    size_t count, loff_t *ppos)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct av7110 *av7110 = dvbdev->priv;
-
-	dprintk(8, "av7110:%p\n",av7110);
-	return ci_ll_write(&av7110->ci_wbuffer, file, buf, count, ppos);
-}
-
-static ssize_t dvb_ca_read(struct file *file, char __user *buf,
-			   size_t count, loff_t *ppos)
-{
-	struct dvb_device *dvbdev = file->private_data;
-	struct av7110 *av7110 = dvbdev->priv;
-
-	dprintk(8, "av7110:%p\n",av7110);
-	return ci_ll_read(&av7110->ci_rbuffer, file, buf, count, ppos);
-}
-
-static const struct file_operations dvb_ca_fops = {
-	.owner		= THIS_MODULE,
-	.read		= dvb_ca_read,
-	.write		= dvb_ca_write,
-	.unlocked_ioctl	= dvb_generic_ioctl,
-	.open		= dvb_ca_open,
-	.release	= dvb_generic_release,
-	.poll		= dvb_ca_poll,
-	.llseek		= default_llseek,
-};
-
-static struct dvb_device dvbdev_ca = {
-	.priv		= NULL,
-	.users		= 1,
-	.writers	= 1,
-	.fops		= &dvb_ca_fops,
-	.kernel_ioctl	= dvb_ca_ioctl,
-};
-
-
-int av7110_ca_register(struct av7110 *av7110)
-{
-	return dvb_register_device(&av7110->dvb_adapter, &av7110->ca_dev,
-				   &dvbdev_ca, av7110, DVB_DEVICE_CA);
-}
-
-void av7110_ca_unregister(struct av7110 *av7110)
-{
-	dvb_unregister_device(av7110->ca_dev);
-}
-
-int av7110_ca_init(struct av7110* av7110)
-{
-	return ci_ll_init(&av7110->ci_rbuffer, &av7110->ci_wbuffer, 8192);
-}
-
-void av7110_ca_exit(struct av7110* av7110)
-{
-	ci_ll_release(&av7110->ci_rbuffer, &av7110->ci_wbuffer);
-}
diff --git a/drivers/media/dvb/ttpci/av7110_ca.h b/drivers/media/dvb/ttpci/av7110_ca.h
deleted file mode 100644
index 70ee855..0000000
--- a/drivers/media/dvb/ttpci/av7110_ca.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _AV7110_CA_H_
-#define _AV7110_CA_H_
-
-struct av7110;
-
-extern void CI_handle(struct av7110 *av7110, u8 *data, u16 len);
-extern void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len);
-
-extern int av7110_ca_register(struct av7110 *av7110);
-extern void av7110_ca_unregister(struct av7110 *av7110);
-extern int av7110_ca_init(struct av7110* av7110);
-extern void av7110_ca_exit(struct av7110* av7110);
-
-#endif /* _AV7110_CA_H_ */
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
deleted file mode 100644
index f1cbfe5..0000000
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ /dev/null
@@ -1,1208 +0,0 @@
-/*
- * av7110_hw.c: av7110 low level hardware access and firmware interface
- *
- * Copyright (C) 1999-2002 Ralph  Metzler
- *                       & Marcus Metzler for convergence integrated media GmbH
- *
- * originally based on code by:
- * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- * the project's page is at http://www.linuxtv.org/ 
- */
-
-/* for debugging ARM communication: */
-//#define COM_DEBUG
-
-#include <stdarg.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/fs.h>
-
-#include "av7110.h"
-#include "av7110_hw.h"
-
-#define _NOHANDSHAKE
-
-/****************************************************************************
- * DEBI functions
- ****************************************************************************/
-
-/* This DEBI code is based on the Stradis driver
-   by Nathan Laredo <laredo@gnu.org> */
-
-int av7110_debiwrite(struct av7110 *av7110, u32 config,
-		     int addr, u32 val, int count)
-{
-	struct saa7146_dev *dev = av7110->dev;
-
-	if (count <= 0 || count > 32764) {
-		printk("%s: invalid count %d\n", __func__, count);
-		return -1;
-	}
-	if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
-		printk("%s: wait_for_debi_done failed\n", __func__);
-		return -1;
-	}
-	saa7146_write(dev, DEBI_CONFIG, config);
-	if (count <= 4)		/* immediate transfer */
-		saa7146_write(dev, DEBI_AD, val);
-	else			/* block transfer */
-		saa7146_write(dev, DEBI_AD, av7110->debi_bus);
-	saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff));
-	saa7146_write(dev, MC2, (2 << 16) | 2);
-	return 0;
-}
-
-u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
-{
-	struct saa7146_dev *dev = av7110->dev;
-	u32 result = 0;
-
-	if (count > 32764 || count <= 0) {
-		printk("%s: invalid count %d\n", __func__, count);
-		return 0;
-	}
-	if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
-		printk("%s: wait_for_debi_done #1 failed\n", __func__);
-		return 0;
-	}
-	saa7146_write(dev, DEBI_AD, av7110->debi_bus);
-	saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
-
-	saa7146_write(dev, DEBI_CONFIG, config);
-	saa7146_write(dev, MC2, (2 << 16) | 2);
-	if (count > 4)
-		return count;
-	if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
-		printk("%s: wait_for_debi_done #2 failed\n", __func__);
-		return 0;
-	}
-
-	result = saa7146_read(dev, DEBI_AD);
-	result &= (0xffffffffUL >> ((4 - count) * 8));
-	return result;
-}
-
-
-
-/* av7110 ARM core boot stuff */
-#if 0
-void av7110_reset_arm(struct av7110 *av7110)
-{
-	saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO);
-
-	/* Disable DEBI and GPIO irq */
-	SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03);
-	SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
-
-	saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI);
-	msleep(30);	/* the firmware needs some time to initialize */
-
-	ARM_ResetMailBox(av7110);
-
-	SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
-	SAA7146_IER_ENABLE(av7110->dev, MASK_03);
-
-	av7110->arm_ready = 1;
-	dprintk(1, "reset ARM\n");
-}
-#endif  /*  0  */
-
-static int waitdebi(struct av7110 *av7110, int adr, int state)
-{
-	int k;
-
-	dprintk(4, "%p\n", av7110);
-
-	for (k = 0; k < 100; k++) {
-		if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state)
-			return 0;
-		udelay(5);
-	}
-	return -ETIMEDOUT;
-}
-
-static int load_dram(struct av7110 *av7110, u32 *data, int len)
-{
-	int i;
-	int blocks, rest;
-	u32 base, bootblock = AV7110_BOOT_BLOCK;
-
-	dprintk(4, "%p\n", av7110);
-
-	blocks = len / AV7110_BOOT_MAX_SIZE;
-	rest = len % AV7110_BOOT_MAX_SIZE;
-	base = DRAM_START_CODE;
-
-	for (i = 0; i < blocks; i++) {
-		if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
-			printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
-			return -ETIMEDOUT;
-		}
-		dprintk(4, "writing DRAM block %d\n", i);
-		mwdebi(av7110, DEBISWAB, bootblock,
-		       ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
-		bootblock ^= 0x1400;
-		iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
-		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
-		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
-		base += AV7110_BOOT_MAX_SIZE;
-	}
-
-	if (rest > 0) {
-		if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
-			printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
-			return -ETIMEDOUT;
-		}
-		if (rest > 4)
-			mwdebi(av7110, DEBISWAB, bootblock,
-			       ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest);
-		else
-			mwdebi(av7110, DEBISWAB, bootblock,
-			       ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
-
-		iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
-		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
-		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
-	}
-	if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
-		printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
-		return -ETIMEDOUT;
-	}
-	iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2);
-	iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
-	if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) {
-		printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
-		return -ETIMEDOUT;
-	}
-	return 0;
-}
-
-
-/* we cannot write av7110 DRAM directly, so load a bootloader into
- * the DPRAM which implements a simple boot protocol */
-int av7110_bootarm(struct av7110 *av7110)
-{
-	const struct firmware *fw;
-	const char *fw_name = "av7110/bootcode.bin";
-	struct saa7146_dev *dev = av7110->dev;
-	u32 ret;
-	int i;
-
-	dprintk(4, "%p\n", av7110);
-
-	av7110->arm_ready = 0;
-
-	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
-
-	/* Disable DEBI and GPIO irq */
-	SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19);
-	SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
-
-	/* enable DEBI */
-	saa7146_write(av7110->dev, MC1, 0x08800880);
-	saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
-	saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
-
-	/* test DEBI */
-	iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
-	/* FIXME: Why does Nexus CA require 2x iwdebi for first init? */
-	iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
-
-	if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) {
-		printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: "
-		       "%08x != %08x (check your BIOS 'Plug&Play OS' settings)\n",
-		       ret, 0x10325476);
-		return -1;
-	}
-	for (i = 0; i < 8192; i += 4)
-		iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4);
-	dprintk(2, "debi test OK\n");
-
-	/* boot */
-	dprintk(1, "load boot code\n");
-	saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO);
-	//saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT);
-	//saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT);
-
-	ret = request_firmware(&fw, fw_name, &dev->pci->dev);
-	if (ret) {
-		printk(KERN_ERR "dvb-ttpci: Failed to load firmware \"%s\"\n",
-			fw_name);
-		return ret;
-	}
-
-	mwdebi(av7110, DEBISWAB, DPRAM_BASE, fw->data, fw->size);
-	release_firmware(fw);
-	iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
-
-	if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
-		printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
-		       "saa7146_wait_for_debi_done() timed out\n");
-		return -ETIMEDOUT;
-	}
-	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
-	mdelay(1);
-
-	dprintk(1, "load dram code\n");
-	if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) {
-		printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
-		       "load_dram() failed\n");
-		return -1;
-	}
-
-	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
-	mdelay(1);
-
-	dprintk(1, "load dpram code\n");
-	mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
-
-	if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
-		printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
-		       "saa7146_wait_for_debi_done() timed out after loading DRAM\n");
-		return -ETIMEDOUT;
-	}
-	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
-	msleep(30);	/* the firmware needs some time to initialize */
-
-	//ARM_ClearIrq(av7110);
-	ARM_ResetMailBox(av7110);
-	SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
-	SAA7146_IER_ENABLE(av7110->dev, MASK_03);
-
-	av7110->arm_errors = 0;
-	av7110->arm_ready = 1;
-	return 0;
-}
-MODULE_FIRMWARE("av7110/bootcode.bin");
-
-/****************************************************************************
- * DEBI command polling
- ****************************************************************************/
-
-int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
-{
-	unsigned long start;
-	u32 stat;
-	int err;
-
-	if (FW_VERSION(av7110->arm_app) <= 0x261c) {
-		/* not supported by old firmware */
-		msleep(50);
-		return 0;
-	}
-
-	/* new firmware */
-	start = jiffies;
-	for (;;) {
-		err = time_after(jiffies, start + ARM_WAIT_FREE);
-		if (mutex_lock_interruptible(&av7110->dcomlock))
-			return -ERESTARTSYS;
-		stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
-		mutex_unlock(&av7110->dcomlock);
-		if ((stat & flags) == 0)
-			break;
-		if (err) {
-			printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
-				__func__, stat & flags);
-			return -ETIMEDOUT;
-		}
-		msleep(1);
-	}
-	return 0;
-}
-
-static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
-{
-	int i;
-	unsigned long start;
-	char *type = NULL;
-	u16 flags[2] = {0, 0};
-	u32 stat;
-	int err;
-
-//	dprintk(4, "%p\n", av7110);
-
-	if (!av7110->arm_ready) {
-		dprintk(1, "arm not ready.\n");
-		return -ENXIO;
-	}
-
-	start = jiffies;
-	while (1) {
-		err = time_after(jiffies, start + ARM_WAIT_FREE);
-		if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
-			break;
-		if (err) {
-			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __func__);
-			av7110->arm_errors++;
-			return -ETIMEDOUT;
-		}
-		msleep(1);
-	}
-
-	if (FW_VERSION(av7110->arm_app) <= 0x261f)
-		wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
-
-#ifndef _NOHANDSHAKE
-	start = jiffies;
-	while (1) {
-		err = time_after(jiffies, start + ARM_WAIT_SHAKE);
-		if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
-			break;
-		if (err) {
-			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __func__);
-			return -ETIMEDOUT;
-		}
-		msleep(1);
-	}
-#endif
-
-	switch ((buf[0] >> 8) & 0xff) {
-	case COMTYPE_PIDFILTER:
-	case COMTYPE_ENCODER:
-	case COMTYPE_REC_PLAY:
-	case COMTYPE_MPEGDECODER:
-		type = "MSG";
-		flags[0] = GPMQOver;
-		flags[1] = GPMQFull;
-		break;
-	case COMTYPE_OSD:
-		type = "OSD";
-		flags[0] = OSDQOver;
-		flags[1] = OSDQFull;
-		break;
-	case COMTYPE_MISC:
-		if (FW_VERSION(av7110->arm_app) >= 0x261d) {
-			type = "MSG";
-			flags[0] = GPMQOver;
-			flags[1] = GPMQBusy;
-		}
-		break;
-	default:
-		break;
-	}
-
-	if (type != NULL) {
-		/* non-immediate COMMAND type */
-		start = jiffies;
-		for (;;) {
-			err = time_after(jiffies, start + ARM_WAIT_FREE);
-			stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
-			if (stat & flags[0]) {
-				printk(KERN_ERR "%s: %s QUEUE overflow\n",
-					__func__, type);
-				return -1;
-			}
-			if ((stat & flags[1]) == 0)
-				break;
-			if (err) {
-				printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
-					__func__, type);
-				av7110->arm_errors++;
-				return -ETIMEDOUT;
-			}
-			msleep(1);
-		}
-	}
-
-	for (i = 2; i < length; i++)
-		wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2);
-
-	if (length)
-		wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2);
-	else
-		wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2);
-
-	wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2);
-
-	if (FW_VERSION(av7110->arm_app) <= 0x261f)
-		wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
-
-#ifdef COM_DEBUG
-	start = jiffies;
-	while (1) {
-		err = time_after(jiffies, start + ARM_WAIT_FREE);
-		if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
-			break;
-		if (err) {
-			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
-			       __func__, (buf[0] >> 8) & 0xff);
-			return -ETIMEDOUT;
-		}
-		msleep(1);
-	}
-
-	stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
-	if (stat & GPMQOver) {
-		printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __func__);
-		return -ENOSPC;
-	}
-	else if (stat & OSDQOver) {
-		printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __func__);
-		return -ENOSPC;
-	}
-#endif
-
-	return 0;
-}
-
-static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
-{
-	int ret;
-
-//	dprintk(4, "%p\n", av7110);
-
-	if (!av7110->arm_ready) {
-		dprintk(1, "arm not ready.\n");
-		return -1;
-	}
-	if (mutex_lock_interruptible(&av7110->dcomlock))
-		return -ERESTARTSYS;
-
-	ret = __av7110_send_fw_cmd(av7110, buf, length);
-	mutex_unlock(&av7110->dcomlock);
-	if (ret && ret!=-ERESTARTSYS)
-		printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
-		       __func__, ret);
-	return ret;
-}
-
-int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
-{
-	va_list args;
-	u16 buf[num + 2];
-	int i, ret;
-
-//	dprintk(4, "%p\n", av7110);
-
-	buf[0] = ((type << 8) | com);
-	buf[1] = num;
-
-	if (num) {
-		va_start(args, num);
-		for (i = 0; i < num; i++)
-			buf[i + 2] = va_arg(args, u32);
-		va_end(args);
-	}
-
-	ret = av7110_send_fw_cmd(av7110, buf, num + 2);
-	if (ret && ret != -ERESTARTSYS)
-		printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
-	return ret;
-}
-
-#if 0
-int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
-{
-	int i, ret;
-	u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom),
-		16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
-	dprintk(4, "%p\n", av7110);
-
-	for(i = 0; i < len && i < 32; i++)
-	{
-		if(i % 2 == 0)
-			cmd[(i / 2) + 2] = (u16)(buf[i]) << 8;
-		else
-			cmd[(i / 2) + 2] |= buf[i];
-	}
-
-	ret = av7110_send_fw_cmd(av7110, cmd, 18);
-	if (ret && ret != -ERESTARTSYS)
-		printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
-	return ret;
-}
-#endif  /*  0  */
-
-int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
-		      int request_buf_len, u16 *reply_buf, int reply_buf_len)
-{
-	int err;
-	s16 i;
-	unsigned long start;
-#ifdef COM_DEBUG
-	u32 stat;
-#endif
-
-	dprintk(4, "%p\n", av7110);
-
-	if (!av7110->arm_ready) {
-		dprintk(1, "arm not ready.\n");
-		return -1;
-	}
-
-	if (mutex_lock_interruptible(&av7110->dcomlock))
-		return -ERESTARTSYS;
-
-	if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
-		mutex_unlock(&av7110->dcomlock);
-		printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
-		return err;
-	}
-
-	start = jiffies;
-	while (1) {
-		err = time_after(jiffies, start + ARM_WAIT_FREE);
-		if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
-			break;
-		if (err) {
-			printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __func__);
-			mutex_unlock(&av7110->dcomlock);
-			return -ETIMEDOUT;
-		}
-#ifdef _NOHANDSHAKE
-		msleep(1);
-#endif
-	}
-
-#ifndef _NOHANDSHAKE
-	start = jiffies;
-	while (1) {
-		err = time_after(jiffies, start + ARM_WAIT_SHAKE);
-		if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
-			break;
-		if (err) {
-			printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __func__);
-			mutex_unlock(&av7110->dcomlock);
-			return -ETIMEDOUT;
-		}
-		msleep(1);
-	}
-#endif
-
-#ifdef COM_DEBUG
-	stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
-	if (stat & GPMQOver) {
-		printk(KERN_ERR "%s: GPMQOver\n", __func__);
-		mutex_unlock(&av7110->dcomlock);
-		return -1;
-	}
-	else if (stat & OSDQOver) {
-		printk(KERN_ERR "%s: OSDQOver\n", __func__);
-		mutex_unlock(&av7110->dcomlock);
-		return -1;
-	}
-#endif
-
-	for (i = 0; i < reply_buf_len; i++)
-		reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
-
-	mutex_unlock(&av7110->dcomlock);
-	return 0;
-}
-
-static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
-{
-	int ret;
-	ret = av7110_fw_request(av7110, &tag, 0, buf, length);
-	if (ret)
-		printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret);
-	return ret;
-}
-
-
-/****************************************************************************
- * Firmware commands
- ****************************************************************************/
-
-/* get version of the firmware ROM, RTSL, video ucode and ARM application  */
-int av7110_firmversion(struct av7110 *av7110)
-{
-	u16 buf[20];
-	u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion);
-
-	dprintk(4, "%p\n", av7110);
-
-	if (av7110_fw_query(av7110, tag, buf, 16)) {
-		printk("dvb-ttpci: failed to boot firmware @ card %d\n",
-		       av7110->dvb_adapter.num);
-		return -EIO;
-	}
-
-	av7110->arm_fw = (buf[0] << 16) + buf[1];
-	av7110->arm_rtsl = (buf[2] << 16) + buf[3];
-	av7110->arm_vid = (buf[4] << 16) + buf[5];
-	av7110->arm_app = (buf[6] << 16) + buf[7];
-	av7110->avtype = (buf[8] << 16) + buf[9];
-
-	printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n",
-	       av7110->dvb_adapter.num, av7110->arm_fw,
-	       av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
-
-	/* print firmware capabilities */
-	if (FW_CI_LL_SUPPORT(av7110->arm_app))
-		printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n",
-		       av7110->dvb_adapter.num);
-	else
-		printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
-		       av7110->dvb_adapter.num);
-
-	return 0;
-}
-
-
-int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
-{
-	int i, ret;
-	u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC),
-			16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
-	dprintk(4, "%p\n", av7110);
-
-	if (len > 10)
-		len = 10;
-
-	buf[1] = len + 2;
-	buf[2] = len;
-
-	if (burst != -1)
-		buf[3] = burst ? 0x01 : 0x00;
-	else
-		buf[3] = 0xffff;
-
-	for (i = 0; i < len; i++)
-		buf[i + 4] = msg[i];
-
-	ret = av7110_send_fw_cmd(av7110, buf, 18);
-	if (ret && ret!=-ERESTARTSYS)
-		printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
-	return ret;
-}
-
-
-#ifdef CONFIG_DVB_AV7110_OSD
-
-static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
-{
-	return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
-}
-
-static inline int SetBlend_(struct av7110 *av7110, u8 windownr,
-		     enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
-{
-	return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4,
-			     windownr, colordepth, index, blending);
-}
-
-static inline int SetColor_(struct av7110 *av7110, u8 windownr,
-		     enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo)
-{
-	return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5,
-			     windownr, colordepth, index, colorhi, colorlo);
-}
-
-static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
-			  u16 colorfg, u16 colorbg)
-{
-	return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4,
-			     windownr, fontsize, colorfg, colorbg);
-}
-
-static int FlushText(struct av7110 *av7110)
-{
-	unsigned long start;
-	int err;
-
-	if (mutex_lock_interruptible(&av7110->dcomlock))
-		return -ERESTARTSYS;
-	start = jiffies;
-	while (1) {
-		err = time_after(jiffies, start + ARM_WAIT_OSD);
-		if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
-			break;
-		if (err) {
-			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
-			       __func__);
-			mutex_unlock(&av7110->dcomlock);
-			return -ETIMEDOUT;
-		}
-		msleep(1);
-	}
-	mutex_unlock(&av7110->dcomlock);
-	return 0;
-}
-
-static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf)
-{
-	int i, ret;
-	unsigned long start;
-	int length = strlen(buf) + 1;
-	u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
-
-	if (mutex_lock_interruptible(&av7110->dcomlock))
-		return -ERESTARTSYS;
-
-	start = jiffies;
-	while (1) {
-		ret = time_after(jiffies, start + ARM_WAIT_OSD);
-		if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
-			break;
-		if (ret) {
-			printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
-			       __func__);
-			mutex_unlock(&av7110->dcomlock);
-			return -ETIMEDOUT;
-		}
-		msleep(1);
-	}
-#ifndef _NOHANDSHAKE
-	start = jiffies;
-	while (1) {
-		ret = time_after(jiffies, start + ARM_WAIT_SHAKE);
-		if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
-			break;
-		if (ret) {
-			printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
-			       __func__);
-			mutex_unlock(&av7110->dcomlock);
-			return -ETIMEDOUT;
-		}
-		msleep(1);
-	}
-#endif
-	for (i = 0; i < length / 2; i++)
-		wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2,
-		      swab16(*(u16 *)(buf + 2 * i)), 2);
-	if (length & 1)
-		wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
-	ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
-	mutex_unlock(&av7110->dcomlock);
-	if (ret && ret!=-ERESTARTSYS)
-		printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
-	return ret;
-}
-
-static inline int DrawLine(struct av7110 *av7110, u8 windownr,
-			   u16 x, u16 y, u16 dx, u16 dy, u16 color)
-{
-	return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6,
-			     windownr, x, y, dx, dy, color);
-}
-
-static inline int DrawBlock(struct av7110 *av7110, u8 windownr,
-			    u16 x, u16 y, u16 dx, u16 dy, u16 color)
-{
-	return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6,
-			     windownr, x, y, dx, dy, color);
-}
-
-static inline int HideWindow(struct av7110 *av7110, u8 windownr)
-{
-	return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr);
-}
-
-static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
-{
-	return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y);
-}
-
-static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
-{
-	return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y);
-}
-
-static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
-{
-	return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr);
-}
-
-static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
-				  osd_raw_window_t disptype,
-				  u16 width, u16 height)
-{
-	return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4,
-			     windownr, disptype, width, height);
-}
-
-
-static enum av7110_osd_palette_type bpp2pal[8] = {
-	Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
-};
-static osd_raw_window_t bpp2bit[8] = {
-	OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
-};
-
-static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
-{
-	int ret = wait_event_timeout(av7110->bmpq,
-				av7110->bmp_state != BMP_LOADING, 10*HZ);
-	if (ret == 0) {
-		printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
-		       ret, av7110->bmp_state);
-		av7110->bmp_state = BMP_NONE;
-		return -ETIMEDOUT;
-	}
-	return 0;
-}
-
-static inline int LoadBitmap(struct av7110 *av7110,
-			     u16 dx, u16 dy, int inc, u8 __user * data)
-{
-	u16 format;
-	int bpp;
-	int i;
-	int d, delta;
-	u8 c;
-	int ret;
-
-	dprintk(4, "%p\n", av7110);
-
-	format = bpp2bit[av7110->osdbpp[av7110->osdwin]];
-
-	av7110->bmp_state = BMP_LOADING;
-	if	(format == OSD_BITMAP8) {
-		bpp=8; delta = 1;
-	} else if (format == OSD_BITMAP4) {
-		bpp=4; delta = 2;
-	} else if (format == OSD_BITMAP2) {
-		bpp=2; delta = 4;
-	} else if (format == OSD_BITMAP1) {
-		bpp=1; delta = 8;
-	} else {
-		av7110->bmp_state = BMP_NONE;
-		return -EINVAL;
-	}
-	av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
-	av7110->bmpp = 0;
-	if (av7110->bmplen > 32768) {
-		av7110->bmp_state = BMP_NONE;
-		return -EINVAL;
-	}
-	for (i = 0; i < dy; i++) {
-		if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
-			av7110->bmp_state = BMP_NONE;
-			return -EINVAL;
-		}
-	}
-	if (format != OSD_BITMAP8) {
-		for (i = 0; i < dx * dy / delta; i++) {
-			c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1];
-			for (d = delta - 2; d >= 0; d--) {
-				c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d]
-				      << ((delta - d - 1) * bpp));
-				((u8 *)av7110->bmpbuf)[1024 + i] = c;
-			}
-		}
-	}
-	av7110->bmplen += 1024;
-	dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
-	ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
-	if (!ret)
-		ret = WaitUntilBmpLoaded(av7110);
-	return ret;
-}
-
-static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y)
-{
-	dprintk(4, "%p\n", av7110);
-
-	return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0);
-}
-
-static inline int ReleaseBitmap(struct av7110 *av7110)
-{
-	dprintk(4, "%p\n", av7110);
-
-	if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
-		return -1;
-	if (av7110->bmp_state == BMP_LOADING)
-		dprintk(1,"ReleaseBitmap called while BMP_LOADING\n");
-	av7110->bmp_state = BMP_NONE;
-	return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
-}
-
-static u32 RGB2YUV(u16 R, u16 G, u16 B)
-{
-	u16 y, u, v;
-	u16 Y, Cr, Cb;
-
-	y = R * 77 + G * 150 + B * 29;	/* Luma=0.299R+0.587G+0.114B 0..65535 */
-	u = 2048 + B * 8 -(y >> 5);	/* Cr 0..4095 */
-	v = 2048 + R * 8 -(y >> 5);	/* Cb 0..4095 */
-
-	Y = y / 256;
-	Cb = u / 16;
-	Cr = v / 16;
-
-	return Cr | (Cb << 16) | (Y << 8);
-}
-
-static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
-{
-	int ret;
-
-	u16 ch, cl;
-	u32 yuv;
-
-	yuv = blend ? RGB2YUV(r,g,b) : 0;
-	cl = (yuv & 0xffff);
-	ch = ((yuv >> 16) & 0xffff);
-	ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
-			color, ch, cl);
-	if (!ret)
-		ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
-				color, ((blend >> 4) & 0x0f));
-	return ret;
-}
-
-static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
-{
-	int i;
-	int length = last - first + 1;
-
-	if (length * 4 > DATA_BUFF3_SIZE)
-		return -EINVAL;
-
-	for (i = 0; i < length; i++) {
-		u32 color, blend, yuv;
-
-		if (get_user(color, colors + i))
-			return -EFAULT;
-		blend = (color & 0xF0000000) >> 4;
-		yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
-				     (color >> 16) & 0xFF) | blend : 0;
-		yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
-		wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
-	}
-	return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
-			    av7110->osdwin,
-			    bpp2pal[av7110->osdbpp[av7110->osdwin]],
-			    first, last);
-}
-
-static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
-		       int x1, int y1, int inc, u8 __user * data)
-{
-	uint w, h, bpp, bpl, size, lpb, bnum, brest;
-	int i;
-	int rc,release_rc;
-
-	w = x1 - x0 + 1;
-	h = y1 - y0 + 1;
-	if (inc <= 0)
-		inc = w;
-	if (w <= 0 || w > 720 || h <= 0 || h > 576)
-		return -EINVAL;
-	bpp = av7110->osdbpp[av7110->osdwin] + 1;
-	bpl = ((w * bpp + 7) & ~7) / 8;
-	size = h * bpl;
-	lpb = (32 * 1024) / bpl;
-	bnum = size / (lpb * bpl);
-	brest = size - bnum * lpb * bpl;
-
-	if (av7110->bmp_state == BMP_LOADING) {
-		/* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */
-		BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e);
-		rc = WaitUntilBmpLoaded(av7110);
-		if (rc)
-			return rc;
-		/* just continue. This should work for all fw versions
-		 * if bnum==1 && !brest && LoadBitmap was successful
-		 */
-	}
-
-	rc = 0;
-	for (i = 0; i < bnum; i++) {
-		rc = LoadBitmap(av7110, w, lpb, inc, data);
-		if (rc)
-			break;
-		rc = BlitBitmap(av7110, x0, y0 + i * lpb);
-		if (rc)
-			break;
-		data += lpb * inc;
-	}
-	if (!rc && brest) {
-		rc = LoadBitmap(av7110, w, brest / bpl, inc, data);
-		if (!rc)
-			rc = BlitBitmap(av7110, x0, y0 + bnum * lpb);
-	}
-	release_rc = ReleaseBitmap(av7110);
-	if (!rc)
-		rc = release_rc;
-	if (rc)
-		dprintk(1,"returns %d\n",rc);
-	return rc;
-}
-
-int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
-{
-	int ret;
-
-	if (mutex_lock_interruptible(&av7110->osd_mutex))
-		return -ERESTARTSYS;
-
-	switch (dc->cmd) {
-	case OSD_Close:
-		ret = DestroyOSDWindow(av7110, av7110->osdwin);
-		break;
-	case OSD_Open:
-		av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
-		ret = CreateOSDWindow(av7110, av7110->osdwin,
-				bpp2bit[av7110->osdbpp[av7110->osdwin]],
-				dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
-		if (ret)
-			break;
-		if (!dc->data) {
-			ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
-			if (ret)
-				break;
-			ret = SetColorBlend(av7110, av7110->osdwin);
-		}
-		break;
-	case OSD_Show:
-		ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0);
-		break;
-	case OSD_Hide:
-		ret = HideWindow(av7110, av7110->osdwin);
-		break;
-	case OSD_Clear:
-		ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
-		break;
-	case OSD_Fill:
-		ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
-		break;
-	case OSD_SetColor:
-		ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
-		break;
-	case OSD_SetPalette:
-		if (FW_VERSION(av7110->arm_app) >= 0x2618)
-			ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
-		else {
-			int i, len = dc->x0-dc->color+1;
-			u8 __user *colors = (u8 __user *)dc->data;
-			u8 r, g = 0, b = 0, blend = 0;
-			ret = 0;
-			for (i = 0; i<len; i++) {
-				if (get_user(r, colors + i * 4) ||
-				    get_user(g, colors + i * 4 + 1) ||
-				    get_user(b, colors + i * 4 + 2) ||
-				    get_user(blend, colors + i * 4 + 3)) {
-					ret = -EFAULT;
-					break;
-				    }
-				ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
-				if (ret)
-					break;
-			}
-		}
-		break;
-	case OSD_SetPixel:
-		ret = DrawLine(av7110, av7110->osdwin,
-			 dc->x0, dc->y0, 0, 0, dc->color);
-		break;
-	case OSD_SetRow:
-		dc->y1 = dc->y0;
-		/* fall through */
-	case OSD_SetBlock:
-		ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
-		break;
-	case OSD_FillRow:
-		ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
-			  dc->x1-dc->x0+1, dc->y1, dc->color);
-		break;
-	case OSD_FillBlock:
-		ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
-			  dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
-		break;
-	case OSD_Line:
-		ret = DrawLine(av7110, av7110->osdwin,
-			 dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
-		break;
-	case OSD_Text:
-	{
-		char textbuf[240];
-
-		if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
-			ret = -EFAULT;
-			break;
-		}
-		textbuf[239] = 0;
-		if (dc->x1 > 3)
-			dc->x1 = 3;
-		ret = SetFont(av7110, av7110->osdwin, dc->x1,
-			(u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
-		if (!ret)
-			ret = FlushText(av7110);
-		if (!ret)
-			ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
-		break;
-	}
-	case OSD_SetWindow:
-		if (dc->x0 < 1 || dc->x0 > 7)
-			ret = -EINVAL;
-		else {
-			av7110->osdwin = dc->x0;
-			ret = 0;
-		}
-		break;
-	case OSD_MoveWindow:
-		ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
-		if (!ret)
-			ret = SetColorBlend(av7110, av7110->osdwin);
-		break;
-	case OSD_OpenRaw:
-		if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
-			ret = -EINVAL;
-			break;
-		}
-		if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR)
-			av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
-		else
-			av7110->osdbpp[av7110->osdwin] = 0;
-		ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
-				dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
-		if (ret)
-			break;
-		if (!dc->data) {
-			ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
-			if (!ret)
-				ret = SetColorBlend(av7110, av7110->osdwin);
-		}
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-
-	mutex_unlock(&av7110->osd_mutex);
-	if (ret==-ERESTARTSYS)
-		dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
-	else if (ret)
-		dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret);
-
-	return ret;
-}
-
-int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
-{
-	switch (cap->cmd) {
-	case OSD_CAP_MEMSIZE:
-		if (FW_4M_SDRAM(av7110->arm_app))
-			cap->val = 1000000;
-		else
-			cap->val = 92000;
-		return 0;
-	default:
-		return -EINVAL;
-	}
-}
-#endif /* CONFIG_DVB_AV7110_OSD */
diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h
deleted file mode 100644
index 1634aba..0000000
--- a/drivers/media/dvb/ttpci/av7110_hw.h
+++ /dev/null
@@ -1,495 +0,0 @@
-#ifndef _AV7110_HW_H_
-#define _AV7110_HW_H_
-
-#include "av7110.h"
-
-/* DEBI transfer mode defs */
-
-#define DEBINOSWAP 0x000e0000
-#define DEBISWAB   0x001e0000
-#define DEBISWAP   0x002e0000
-
-#define ARM_WAIT_FREE  (HZ)
-#define ARM_WAIT_SHAKE (HZ/5)
-#define ARM_WAIT_OSD (HZ)
-
-
-enum av7110_bootstate
-{
-	BOOTSTATE_BUFFER_EMPTY	= 0,
-	BOOTSTATE_BUFFER_FULL	= 1,
-	BOOTSTATE_AV7110_BOOT_COMPLETE	= 2
-};
-
-enum av7110_type_rec_play_format
-{	RP_None,
-	AudioPES,
-	AudioMp2,
-	AudioPCM,
-	VideoPES,
-	AV_PES
-};
-
-enum av7110_osd_palette_type
-{
-	NoPalet =  0,	   /* No palette */
-	Pal1Bit =  2,	   /* 2 colors for 1 Bit Palette    */
-	Pal2Bit =  4,	   /* 4 colors for 2 bit palette    */
-	Pal4Bit =  16,	   /* 16 colors for 4 bit palette   */
-	Pal8Bit =  256	   /* 256 colors for 16 bit palette */
-};
-
-/* switch defines */
-#define SB_GPIO 3
-#define SB_OFF	SAA7146_GPIO_OUTLO  /* SlowBlank off (TV-Mode) */
-#define SB_ON	SAA7146_GPIO_INPUT  /* SlowBlank on  (AV-Mode) */
-#define SB_WIDE SAA7146_GPIO_OUTHI  /* SlowBlank 6V  (16/9-Mode) (not implemented) */
-
-#define FB_GPIO 1
-#define FB_OFF	SAA7146_GPIO_LO     /* FastBlank off (CVBS-Mode) */
-#define FB_ON	SAA7146_GPIO_OUTHI  /* FastBlank on  (RGB-Mode) */
-#define FB_LOOP	SAA7146_GPIO_INPUT  /* FastBlank loop-through (PC graphics ???) */
-
-enum av7110_video_output_mode
-{
-	NO_OUT	     = 0,		/* disable analog output */
-	CVBS_RGB_OUT = 1,
-	CVBS_YC_OUT  = 2,
-	YC_OUT	     = 3
-};
-
-/* firmware internal msg q status: */
-#define GPMQFull	0x0001		/* Main Message Queue Full */
-#define GPMQOver	0x0002		/* Main Message Queue Overflow */
-#define HPQFull		0x0004		/* High Priority Msg Queue Full */
-#define HPQOver		0x0008
-#define OSDQFull	0x0010		/* OSD Queue Full */
-#define OSDQOver	0x0020
-#define GPMQBusy	0x0040		/* Queue not empty, FW >= 261d */
-#define HPQBusy		0x0080
-#define OSDQBusy	0x0100
-
-/* hw section filter flags */
-#define	SECTION_EIT		0x01
-#define	SECTION_SINGLE		0x00
-#define	SECTION_CYCLE		0x02
-#define	SECTION_CONTINUOS	0x04
-#define	SECTION_MODE		0x06
-#define SECTION_IPMPE		0x0C	/* size up to 4k */
-#define SECTION_HIGH_SPEED	0x1C	/* larger buffer */
-#define DATA_PIPING_FLAG	0x20	/* for Data Piping Filter */
-
-#define	PBUFSIZE_NONE 0x0000
-#define	PBUFSIZE_1P   0x0100
-#define	PBUFSIZE_2P   0x0200
-#define	PBUFSIZE_1K   0x0300
-#define	PBUFSIZE_2K   0x0400
-#define	PBUFSIZE_4K   0x0500
-#define	PBUFSIZE_8K   0x0600
-#define PBUFSIZE_16K  0x0700
-#define PBUFSIZE_32K  0x0800
-
-
-/* firmware command codes */
-enum av7110_osd_command {
-	WCreate,
-	WDestroy,
-	WMoveD,
-	WMoveA,
-	WHide,
-	WTop,
-	DBox,
-	DLine,
-	DText,
-	Set_Font,
-	SetColor,
-	SetBlend,
-	SetWBlend,
-	SetCBlend,
-	SetNonBlend,
-	LoadBmp,
-	BlitBmp,
-	ReleaseBmp,
-	SetWTrans,
-	SetWNoTrans,
-	Set_Palette
-};
-
-enum av7110_pid_command {
-	MultiPID,
-	VideoPID,
-	AudioPID,
-	InitFilt,
-	FiltError,
-	NewVersion,
-	CacheError,
-	AddPIDFilter,
-	DelPIDFilter,
-	Scan,
-	SetDescr,
-	SetIR,
-	FlushTSQueue
-};
-
-enum av7110_mpeg_command {
-	SelAudChannels
-};
-
-enum av7110_audio_command {
-	AudioDAC,
-	CabADAC,
-	ON22K,
-	OFF22K,
-	MainSwitch,
-	ADSwitch,
-	SendDiSEqC,
-	SetRegister,
-	SpdifSwitch
-};
-
-enum av7110_request_command {
-	AudioState,
-	AudioBuffState,
-	VideoState1,
-	VideoState2,
-	VideoState3,
-	CrashCounter,
-	ReqVersion,
-	ReqVCXO,
-	ReqRegister,
-	ReqSecFilterError,
-	ReqSTC
-};
-
-enum av7110_encoder_command {
-	SetVidMode,
-	SetTestMode,
-	LoadVidCode,
-	SetMonitorType,
-	SetPanScanType,
-	SetFreezeMode,
-	SetWSSConfig
-};
-
-enum av7110_rec_play_state {
-	__Record,
-	__Stop,
-	__Play,
-	__Pause,
-	__Slow,
-	__FF_IP,
-	__Scan_I,
-	__Continue
-};
-
-enum av7110_fw_cmd_misc {
-	AV7110_FW_VIDEO_ZOOM = 1,
-	AV7110_FW_VIDEO_COMMAND,
-	AV7110_FW_AUDIO_COMMAND
-};
-
-enum av7110_command_type {
-	COMTYPE_NOCOM,
-	COMTYPE_PIDFILTER,
-	COMTYPE_MPEGDECODER,
-	COMTYPE_OSD,
-	COMTYPE_BMP,
-	COMTYPE_ENCODER,
-	COMTYPE_AUDIODAC,
-	COMTYPE_REQUEST,
-	COMTYPE_SYSTEM,
-	COMTYPE_REC_PLAY,
-	COMTYPE_COMMON_IF,
-	COMTYPE_PID_FILTER,
-	COMTYPE_PES,
-	COMTYPE_TS,
-	COMTYPE_VIDEO,
-	COMTYPE_AUDIO,
-	COMTYPE_CI_LL,
-	COMTYPE_MISC = 0x80
-};
-
-#define VID_NONE_PREF		0x00	/* No aspect ration processing preferred */
-#define VID_PAN_SCAN_PREF	0x01	/* Pan and Scan Display preferred */
-#define VID_VERT_COMP_PREF	0x02	/* Vertical compression display preferred */
-#define VID_VC_AND_PS_PREF	0x03	/* PanScan and vertical Compression if allowed */
-#define VID_CENTRE_CUT_PREF	0x05	/* PanScan with zero vector */
-
-/* MPEG video decoder commands */
-#define AV_VIDEO_CMD_STOP	0x000e
-#define AV_VIDEO_CMD_PLAY	0x000d
-#define AV_VIDEO_CMD_FREEZE	0x0102
-#define AV_VIDEO_CMD_FFWD	0x0016
-#define AV_VIDEO_CMD_SLOW	0x0022
-
-/* MPEG audio decoder commands */
-#define AUDIO_CMD_MUTE		0x0001
-#define AUDIO_CMD_UNMUTE	0x0002
-#define AUDIO_CMD_PCM16		0x0010
-#define AUDIO_CMD_STEREO	0x0080
-#define AUDIO_CMD_MONO_L	0x0100
-#define AUDIO_CMD_MONO_R	0x0200
-#define AUDIO_CMD_SYNC_OFF	0x000e
-#define AUDIO_CMD_SYNC_ON	0x000f
-
-/* firmware data interface codes */
-#define DATA_NONE		 0x00
-#define DATA_FSECTION		 0x01
-#define DATA_IPMPE		 0x02
-#define DATA_MPEG_RECORD	 0x03
-#define DATA_DEBUG_MESSAGE	 0x04
-#define DATA_COMMON_INTERFACE	 0x05
-#define DATA_MPEG_PLAY		 0x06
-#define DATA_BMP_LOAD		 0x07
-#define DATA_IRCOMMAND		 0x08
-#define DATA_PIPING		 0x09
-#define DATA_STREAMING		 0x0a
-#define DATA_CI_GET		 0x0b
-#define DATA_CI_PUT		 0x0c
-#define DATA_MPEG_VIDEO_EVENT	 0x0d
-
-#define DATA_PES_RECORD		 0x10
-#define DATA_PES_PLAY		 0x11
-#define DATA_TS_RECORD		 0x12
-#define DATA_TS_PLAY		 0x13
-
-/* ancient CI command codes, only two are actually still used
- * by the link level CI firmware */
-#define CI_CMD_ERROR		 0x00
-#define CI_CMD_ACK		 0x01
-#define CI_CMD_SYSTEM_READY	 0x02
-#define CI_CMD_KEYPRESS		 0x03
-#define CI_CMD_ON_TUNED		 0x04
-#define CI_CMD_ON_SWITCH_PROGRAM 0x05
-#define CI_CMD_SECTION_ARRIVED	 0x06
-#define CI_CMD_SECTION_TIMEOUT	 0x07
-#define CI_CMD_TIME		 0x08
-#define CI_CMD_ENTER_MENU	 0x09
-#define CI_CMD_FAST_PSI		 0x0a
-#define CI_CMD_GET_SLOT_INFO	 0x0b
-
-#define CI_MSG_NONE		 0x00
-#define CI_MSG_CI_INFO		 0x01
-#define CI_MSG_MENU		 0x02
-#define CI_MSG_LIST		 0x03
-#define CI_MSG_TEXT		 0x04
-#define CI_MSG_REQUEST_INPUT	 0x05
-#define CI_MSG_INPUT_COMPLETE	 0x06
-#define CI_MSG_LIST_MORE	 0x07
-#define CI_MSG_MENU_MORE	 0x08
-#define CI_MSG_CLOSE_MMI_IMM	 0x09
-#define CI_MSG_SECTION_REQUEST	 0x0a
-#define CI_MSG_CLOSE_FILTER	 0x0b
-#define CI_PSI_COMPLETE		 0x0c
-#define CI_MODULE_READY		 0x0d
-#define CI_SWITCH_PRG_REPLY	 0x0e
-#define CI_MSG_TEXT_MORE	 0x0f
-
-#define CI_MSG_CA_PMT		 0xe0
-#define CI_MSG_ERROR		 0xf0
-
-
-/* base address of the dual ported RAM which serves as communication
- * area between PCI bus and av7110,
- * as seen by the DEBI bus of the saa7146 */
-#define	DPRAM_BASE 0x4000
-
-/* boot protocol area */
-#define AV7110_BOOT_STATE	(DPRAM_BASE + 0x3F8)
-#define AV7110_BOOT_SIZE	(DPRAM_BASE + 0x3FA)
-#define AV7110_BOOT_BASE	(DPRAM_BASE + 0x3FC)
-#define AV7110_BOOT_BLOCK	(DPRAM_BASE + 0x400)
-#define AV7110_BOOT_MAX_SIZE	0xc00
-
-/* firmware command protocol area */
-#define IRQ_STATE	(DPRAM_BASE + 0x0F4)
-#define IRQ_STATE_EXT	(DPRAM_BASE + 0x0F6)
-#define MSGSTATE	(DPRAM_BASE + 0x0F8)
-#define COMMAND		(DPRAM_BASE + 0x0FC)
-#define COM_BUFF	(DPRAM_BASE + 0x100)
-#define COM_BUFF_SIZE	0x20
-
-/* various data buffers */
-#define BUFF1_BASE	(DPRAM_BASE + 0x120)
-#define BUFF1_SIZE	0xE0
-
-#define DATA_BUFF0_BASE	(DPRAM_BASE + 0x200)
-#define DATA_BUFF0_SIZE	0x0800
-
-#define DATA_BUFF1_BASE	(DATA_BUFF0_BASE+DATA_BUFF0_SIZE)
-#define DATA_BUFF1_SIZE	0x0800
-
-#define DATA_BUFF2_BASE	(DATA_BUFF1_BASE+DATA_BUFF1_SIZE)
-#define DATA_BUFF2_SIZE	0x0800
-
-#define DATA_BUFF3_BASE (DATA_BUFF2_BASE+DATA_BUFF2_SIZE)
-#define DATA_BUFF3_SIZE 0x0400
-
-#define Reserved	(DPRAM_BASE + 0x1E00)
-#define Reserved_SIZE	0x1C0
-
-
-/* firmware status area */
-#define STATUS_BASE	(DPRAM_BASE + 0x1FC0)
-#define STATUS_LOOPS	(STATUS_BASE + 0x08)
-
-#define STATUS_MPEG_WIDTH     (STATUS_BASE + 0x0C)
-/* ((aspect_ratio & 0xf) << 12) | (height & 0xfff) */
-#define STATUS_MPEG_HEIGHT_AR (STATUS_BASE + 0x0E)
-
-/* firmware data protocol area */
-#define RX_TYPE		(DPRAM_BASE + 0x1FE8)
-#define RX_LEN		(DPRAM_BASE + 0x1FEA)
-#define TX_TYPE		(DPRAM_BASE + 0x1FEC)
-#define TX_LEN		(DPRAM_BASE + 0x1FEE)
-
-#define RX_BUFF		(DPRAM_BASE + 0x1FF4)
-#define TX_BUFF		(DPRAM_BASE + 0x1FF6)
-
-#define HANDSHAKE_REG	(DPRAM_BASE + 0x1FF8)
-#define COM_IF_LOCK	(DPRAM_BASE + 0x1FFA)
-
-#define IRQ_RX		(DPRAM_BASE + 0x1FFC)
-#define IRQ_TX		(DPRAM_BASE + 0x1FFE)
-
-/* used by boot protocol to load firmware into av7110 DRAM */
-#define DRAM_START_CODE		0x2e000404
-#define DRAM_MAX_CODE_SIZE	0x00100000
-
-/* saa7146 gpio lines */
-#define RESET_LINE		2
-#define DEBI_DONE_LINE		1
-#define ARM_IRQ_LINE		0
-
-
-
-extern int av7110_bootarm(struct av7110 *av7110);
-extern int av7110_firmversion(struct av7110 *av7110);
-#define FW_CI_LL_SUPPORT(arm_app) ((arm_app) & 0x80000000)
-#define FW_4M_SDRAM(arm_app)      ((arm_app) & 0x40000000)
-#define FW_VERSION(arm_app)	  ((arm_app) & 0x0000FFFF)
-
-extern int av7110_wait_msgstate(struct av7110 *av7110, u16 flags);
-extern int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...);
-extern int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
-			     int request_buf_len, u16 *reply_buf, int reply_buf_len);
-
-
-/* DEBI (saa7146 data extension bus interface) access */
-extern int av7110_debiwrite(struct av7110 *av7110, u32 config,
-			    int addr, u32 val, int count);
-extern u32 av7110_debiread(struct av7110 *av7110, u32 config,
-			   int addr, int count);
-
-
-/* DEBI during interrupt */
-/* single word writes */
-static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count)
-{
-	av7110_debiwrite(av7110, config, addr, val, count);
-}
-
-/* buffer writes */
-static inline void mwdebi(struct av7110 *av7110, u32 config, int addr,
-			  const u8 *val, int count)
-{
-	memcpy(av7110->debi_virt, val, count);
-	av7110_debiwrite(av7110, config, addr, 0, count);
-}
-
-static inline u32 irdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count)
-{
-	u32 res;
-
-	res=av7110_debiread(av7110, config, addr, count);
-	if (count<=4)
-		memcpy(av7110->debi_virt, (char *) &res, count);
-	return res;
-}
-
-/* DEBI outside interrupts, only for count <= 4! */
-static inline void wdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&av7110->debilock, flags);
-	av7110_debiwrite(av7110, config, addr, val, count);
-	spin_unlock_irqrestore(&av7110->debilock, flags);
-}
-
-static inline u32 rdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count)
-{
-	unsigned long flags;
-	u32 res;
-
-	spin_lock_irqsave(&av7110->debilock, flags);
-	res=av7110_debiread(av7110, config, addr, count);
-	spin_unlock_irqrestore(&av7110->debilock, flags);
-	return res;
-}
-
-/* handle mailbox registers of the dual ported RAM */
-static inline void ARM_ResetMailBox(struct av7110 *av7110)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&av7110->debilock, flags);
-	av7110_debiread(av7110, DEBINOSWAP, IRQ_RX, 2);
-	av7110_debiwrite(av7110, DEBINOSWAP, IRQ_RX, 0, 2);
-	spin_unlock_irqrestore(&av7110->debilock, flags);
-}
-
-static inline void ARM_ClearMailBox(struct av7110 *av7110)
-{
-	iwdebi(av7110, DEBINOSWAP, IRQ_RX, 0, 2);
-}
-
-static inline void ARM_ClearIrq(struct av7110 *av7110)
-{
-	irdebi(av7110, DEBINOSWAP, IRQ_RX, 0, 2);
-}
-
-/****************************************************************************
- * Firmware commands
- ****************************************************************************/
-
-static inline int SendDAC(struct av7110 *av7110, u8 addr, u8 data)
-{
-	return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, AudioDAC, 2, addr, data);
-}
-
-static inline int av7710_set_video_mode(struct av7110 *av7110, int mode)
-{
-	return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode);
-}
-
-static inline int vidcom(struct av7110 *av7110, u32 com, u32 arg)
-{
-	return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_VIDEO_COMMAND, 4,
-			     (com>>16), (com&0xffff),
-			     (arg>>16), (arg&0xffff));
-}
-
-static inline int audcom(struct av7110 *av7110, u32 com)
-{
-	return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 2,
-			     (com>>16), (com&0xffff));
-}
-
-static inline int Set22K(struct av7110 *av7110, int state)
-{
-	return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0);
-}
-
-
-extern int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst);
-
-
-#ifdef CONFIG_DVB_AV7110_OSD
-extern int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc);
-extern int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap);
-#endif /* CONFIG_DVB_AV7110_OSD */
-
-
-
-#endif /* _AV7110_HW_H_ */
diff --git a/drivers/media/dvb/ttpci/av7110_ipack.c b/drivers/media/dvb/ttpci/av7110_ipack.c
deleted file mode 100644
index 699ef8b..0000000
--- a/drivers/media/dvb/ttpci/av7110_ipack.c
+++ /dev/null
@@ -1,403 +0,0 @@
-#include "dvb_filter.h"
-#include "av7110_ipack.h"
-#include <linux/string.h>	/* for memcpy() */
-#include <linux/vmalloc.h>
-
-
-void av7110_ipack_reset(struct ipack *p)
-{
-	p->found = 0;
-	p->cid = 0;
-	p->plength = 0;
-	p->flag1 = 0;
-	p->flag2 = 0;
-	p->hlength = 0;
-	p->mpeg = 0;
-	p->check = 0;
-	p->which = 0;
-	p->done = 0;
-	p->count = 0;
-}
-
-
-int av7110_ipack_init(struct ipack *p, int size,
-		      void (*func)(u8 *buf, int size, void *priv))
-{
-	if (!(p->buf = vmalloc(size*sizeof(u8)))) {
-		printk(KERN_WARNING "Couldn't allocate memory for ipack\n");
-		return -ENOMEM;
-	}
-	p->size = size;
-	p->func = func;
-	p->repack_subids = 0;
-	av7110_ipack_reset(p);
-	return 0;
-}
-
-
-void av7110_ipack_free(struct ipack *p)
-{
-	vfree(p->buf);
-}
-
-
-static void send_ipack(struct ipack *p)
-{
-	int off;
-	struct dvb_audio_info ai;
-	int ac3_off = 0;
-	int streamid = 0;
-	int nframes = 0;
-	int f = 0;
-
-	switch (p->mpeg) {
-	case 2:
-		if (p->count < 10)
-			return;
-		p->buf[3] = p->cid;
-		p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8);
-		p->buf[5] = (u8)((p->count - 6) & 0x00ff);
-		if (p->repack_subids && p->cid == PRIVATE_STREAM1) {
-			off = 9 + p->buf[8];
-			streamid = p->buf[off];
-			if ((streamid & 0xf8) == 0x80) {
-				ai.off = 0;
-				ac3_off = ((p->buf[off + 2] << 8)|
-					   p->buf[off + 3]);
-				if (ac3_off < p->count)
-					f = dvb_filter_get_ac3info(p->buf + off + 3 + ac3_off,
-								   p->count - ac3_off, &ai, 0);
-				if (!f) {
-					nframes = (p->count - off - 3 - ac3_off) /
-						ai.framesize + 1;
-					p->buf[off + 2] = (ac3_off >> 8) & 0xff;
-					p->buf[off + 3] = (ac3_off) & 0xff;
-					p->buf[off + 1] = nframes;
-					ac3_off +=  nframes * ai.framesize - p->count;
-				}
-			}
-		}
-		p->func(p->buf, p->count, p->data);
-
-		p->buf[6] = 0x80;
-		p->buf[7] = 0x00;
-		p->buf[8] = 0x00;
-		p->count = 9;
-		if (p->repack_subids && p->cid == PRIVATE_STREAM1
-		    && (streamid & 0xf8) == 0x80) {
-			p->count += 4;
-			p->buf[9] = streamid;
-			p->buf[10] = (ac3_off >> 8) & 0xff;
-			p->buf[11] = (ac3_off) & 0xff;
-			p->buf[12] = 0;
-		}
-		break;
-
-	case 1:
-		if (p->count < 8)
-			return;
-		p->buf[3] = p->cid;
-		p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8);
-		p->buf[5] = (u8)((p->count - 6) & 0x00ff);
-		p->func(p->buf, p->count, p->data);
-
-		p->buf[6] = 0x0f;
-		p->count = 7;
-		break;
-	}
-}
-
-
-void av7110_ipack_flush(struct ipack *p)
-{
-	if (p->plength != MMAX_PLENGTH - 6 || p->found <= 6)
-		return;
-	p->plength = p->found - 6;
-	p->found = 0;
-	send_ipack(p);
-	av7110_ipack_reset(p);
-}
-
-
-static void write_ipack(struct ipack *p, const u8 *data, int count)
-{
-	u8 headr[3] = { 0x00, 0x00, 0x01 };
-
-	if (p->count < 6) {
-		memcpy(p->buf, headr, 3);
-		p->count = 6;
-	}
-
-	if (p->count + count < p->size){
-		memcpy(p->buf+p->count, data, count);
-		p->count += count;
-	} else {
-		int rest = p->size - p->count;
-		memcpy(p->buf+p->count, data, rest);
-		p->count += rest;
-		send_ipack(p);
-		if (count - rest > 0)
-			write_ipack(p, data + rest, count - rest);
-	}
-}
-
-
-int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p)
-{
-	int l;
-	int c = 0;
-
-	while (c < count && (p->mpeg == 0 ||
-			     (p->mpeg == 1 && p->found < 7) ||
-			     (p->mpeg == 2 && p->found < 9))
-	       &&  (p->found < 5 || !p->done)) {
-		switch (p->found) {
-		case 0:
-		case 1:
-			if (buf[c] == 0x00)
-				p->found++;
-			else
-				p->found = 0;
-			c++;
-			break;
-		case 2:
-			if (buf[c] == 0x01)
-				p->found++;
-			else if (buf[c] == 0)
-				p->found = 2;
-			else
-				p->found = 0;
-			c++;
-			break;
-		case 3:
-			p->cid = 0;
-			switch (buf[c]) {
-			case PROG_STREAM_MAP:
-			case PRIVATE_STREAM2:
-			case PROG_STREAM_DIR:
-			case ECM_STREAM     :
-			case EMM_STREAM     :
-			case PADDING_STREAM :
-			case DSM_CC_STREAM  :
-			case ISO13522_STREAM:
-				p->done = 1;
-				/* fall through */
-			case PRIVATE_STREAM1:
-			case VIDEO_STREAM_S ... VIDEO_STREAM_E:
-			case AUDIO_STREAM_S ... AUDIO_STREAM_E:
-				p->found++;
-				p->cid = buf[c];
-				c++;
-				break;
-			default:
-				p->found = 0;
-				break;
-			}
-			break;
-
-		case 4:
-			if (count-c > 1) {
-				p->plen[0] = buf[c];
-				c++;
-				p->plen[1] = buf[c];
-				c++;
-				p->found += 2;
-				p->plength = (p->plen[0] << 8) | p->plen[1];
-			} else {
-				p->plen[0] = buf[c];
-				p->found++;
-				return count;
-			}
-			break;
-		case 5:
-			p->plen[1] = buf[c];
-			c++;
-			p->found++;
-			p->plength = (p->plen[0] << 8) | p->plen[1];
-			break;
-		case 6:
-			if (!p->done) {
-				p->flag1 = buf[c];
-				c++;
-				p->found++;
-				if ((p->flag1 & 0xc0) == 0x80)
-					p->mpeg = 2;
-				else {
-					p->hlength = 0;
-					p->which = 0;
-					p->mpeg = 1;
-					p->flag2 = 0;
-				}
-			}
-			break;
-
-		case 7:
-			if (!p->done && p->mpeg == 2) {
-				p->flag2 = buf[c];
-				c++;
-				p->found++;
-			}
-			break;
-
-		case 8:
-			if (!p->done && p->mpeg == 2) {
-				p->hlength = buf[c];
-				c++;
-				p->found++;
-			}
-			break;
-		}
-	}
-
-	if (c == count)
-		return count;
-
-	if (!p->plength)
-		p->plength = MMAX_PLENGTH - 6;
-
-	if (p->done || ((p->mpeg == 2 && p->found >= 9) ||
-			(p->mpeg == 1 && p->found >= 7))) {
-		switch (p->cid) {
-		case AUDIO_STREAM_S ... AUDIO_STREAM_E:
-		case VIDEO_STREAM_S ... VIDEO_STREAM_E:
-		case PRIVATE_STREAM1:
-			if (p->mpeg == 2 && p->found == 9) {
-				write_ipack(p, &p->flag1, 1);
-				write_ipack(p, &p->flag2, 1);
-				write_ipack(p, &p->hlength, 1);
-			}
-
-			if (p->mpeg == 1 && p->found == 7)
-				write_ipack(p, &p->flag1, 1);
-
-			if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) &&
-			    p->found < 14) {
-				while (c < count && p->found < 14) {
-					p->pts[p->found - 9] = buf[c];
-					write_ipack(p, buf + c, 1);
-					c++;
-					p->found++;
-				}
-				if (c == count)
-					return count;
-			}
-
-			if (p->mpeg == 1 && p->which < 2000) {
-
-				if (p->found == 7) {
-					p->check = p->flag1;
-					p->hlength = 1;
-				}
-
-				while (!p->which && c < count &&
-				       p->check == 0xff){
-					p->check = buf[c];
-					write_ipack(p, buf + c, 1);
-					c++;
-					p->found++;
-					p->hlength++;
-				}
-
-				if (c == count)
-					return count;
-
-				if ((p->check & 0xc0) == 0x40 && !p->which) {
-					p->check = buf[c];
-					write_ipack(p, buf + c, 1);
-					c++;
-					p->found++;
-					p->hlength++;
-
-					p->which = 1;
-					if (c == count)
-						return count;
-					p->check = buf[c];
-					write_ipack(p, buf + c, 1);
-					c++;
-					p->found++;
-					p->hlength++;
-					p->which = 2;
-					if (c == count)
-						return count;
-				}
-
-				if (p->which == 1) {
-					p->check = buf[c];
-					write_ipack(p, buf + c, 1);
-					c++;
-					p->found++;
-					p->hlength++;
-					p->which = 2;
-					if (c == count)
-						return count;
-				}
-
-				if ((p->check & 0x30) && p->check != 0xff) {
-					p->flag2 = (p->check & 0xf0) << 2;
-					p->pts[0] = p->check;
-					p->which = 3;
-				}
-
-				if (c == count)
-					return count;
-				if (p->which > 2){
-					if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY) {
-						while (c < count && p->which < 7) {
-							p->pts[p->which - 2] = buf[c];
-							write_ipack(p, buf + c, 1);
-							c++;
-							p->found++;
-							p->which++;
-							p->hlength++;
-						}
-						if (c == count)
-							return count;
-					} else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS) {
-						while (c < count && p->which < 12) {
-							if (p->which < 7)
-								p->pts[p->which - 2] = buf[c];
-							write_ipack(p, buf + c, 1);
-							c++;
-							p->found++;
-							p->which++;
-							p->hlength++;
-						}
-						if (c == count)
-							return count;
-					}
-					p->which = 2000;
-				}
-
-			}
-
-			while (c < count && p->found < p->plength + 6) {
-				l = count - c;
-				if (l + p->found > p->plength + 6)
-					l = p->plength + 6 - p->found;
-				write_ipack(p, buf + c, l);
-				p->found += l;
-				c += l;
-			}
-			break;
-		}
-
-
-		if (p->done) {
-			if (p->found + count - c < p->plength + 6) {
-				p->found += count - c;
-				c = count;
-			} else {
-				c += p->plength + 6 - p->found;
-				p->found = p->plength + 6;
-			}
-		}
-
-		if (p->plength && p->found == p->plength + 6) {
-			send_ipack(p);
-			av7110_ipack_reset(p);
-			if (c < count)
-				av7110_ipack_instant_repack(buf + c, count - c, p);
-		}
-	}
-	return count;
-}
diff --git a/drivers/media/dvb/ttpci/av7110_ipack.h b/drivers/media/dvb/ttpci/av7110_ipack.h
deleted file mode 100644
index becf94d..0000000
--- a/drivers/media/dvb/ttpci/av7110_ipack.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef _AV7110_IPACK_H_
-#define _AV7110_IPACK_H_
-
-extern int av7110_ipack_init(struct ipack *p, int size,
-			     void (*func)(u8 *buf,  int size, void *priv));
-
-extern void av7110_ipack_reset(struct ipack *p);
-extern int  av7110_ipack_instant_repack(const u8 *buf, int count, struct ipack *p);
-extern void av7110_ipack_free(struct ipack * p);
-extern void av7110_ipack_flush(struct ipack *p);
-
-#endif
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
deleted file mode 100644
index 908f272..0000000
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * Driver for the remote control of SAA7146 based AV7110 cards
- *
- * Copyright (C) 1999-2003 Holger Waechtler <holger@convergence.de>
- * Copyright (C) 2003-2007 Oliver Endriss <o.endriss@gmx.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- */
-
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/kernel.h>
-#include <linux/bitops.h>
-
-#include "av7110.h"
-#include "av7110_hw.h"
-
-
-#define AV_CNT		4
-
-#define IR_RC5		0
-#define IR_RCMM		1
-#define IR_RC5_EXT	2 /* internal only */
-
-#define IR_ALL		0xffffffff
-
-#define UP_TIMEOUT	(HZ*7/25)
-
-
-/* Note: enable ir debugging by or'ing debug with 16 */
-
-static int ir_protocol[AV_CNT] = { IR_RCMM, IR_RCMM, IR_RCMM, IR_RCMM};
-module_param_array(ir_protocol, int, NULL, 0644);
-MODULE_PARM_DESC(ir_protocol, "Infrared protocol: 0 RC5, 1 RCMM (default)");
-
-static int ir_inversion[AV_CNT];
-module_param_array(ir_inversion, int, NULL, 0644);
-MODULE_PARM_DESC(ir_inversion, "Inversion of infrared signal: 0 not inverted (default), 1 inverted");
-
-static uint ir_device_mask[AV_CNT] = { IR_ALL, IR_ALL, IR_ALL, IR_ALL };
-module_param_array(ir_device_mask, uint, NULL, 0644);
-MODULE_PARM_DESC(ir_device_mask, "Bitmask of infrared devices: bit 0..31 = device 0..31 (default: all)");
-
-
-static int av_cnt;
-static struct av7110 *av_list[AV_CNT];
-
-static u16 default_key_map [256] = {
-	KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
-	KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO,
-	KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	KEY_CHANNELUP, KEY_CHANNELDOWN, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, KEY_TEXT, 0, 0, KEY_TV, 0, 0, 0, 0, 0, KEY_SETUP, 0, 0,
-	0, 0, 0, KEY_SUBTITLE, 0, 0, KEY_LANGUAGE, 0,
-	KEY_RADIO, 0, 0, 0, 0, KEY_EXIT, 0, 0,
-	KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_OK, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RED, KEY_GREEN, KEY_YELLOW,
-	KEY_BLUE, 0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_LIST, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, KEY_UP, KEY_UP, KEY_DOWN, KEY_DOWN,
-	0, 0, 0, 0, KEY_EPG, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_VCR
-};
-
-
-/* key-up timer */
-static void av7110_emit_keyup(unsigned long parm)
-{
-	struct infrared *ir = (struct infrared *) parm;
-
-	if (!ir || !test_bit(ir->last_key, ir->input_dev->key))
-		return;
-
-	input_report_key(ir->input_dev, ir->last_key, 0);
-	input_sync(ir->input_dev);
-}
-
-
-/* tasklet */
-static void av7110_emit_key(unsigned long parm)
-{
-	struct infrared *ir = (struct infrared *) parm;
-	u32 ircom = ir->ir_command;
-	u8 data;
-	u8 addr;
-	u16 toggle;
-	u16 keycode;
-
-	/* extract device address and data */
-	switch (ir->protocol) {
-	case IR_RC5: /* RC5: 5 bits device address, 6 bits data */
-		data = ircom & 0x3f;
-		addr = (ircom >> 6) & 0x1f;
-		toggle = ircom & 0x0800;
-		break;
-
-	case IR_RCMM: /* RCMM: ? bits device address, ? bits data */
-		data = ircom & 0xff;
-		addr = (ircom >> 8) & 0x1f;
-		toggle = ircom & 0x8000;
-		break;
-
-	case IR_RC5_EXT: /* extended RC5: 5 bits device address, 7 bits data */
-		data = ircom & 0x3f;
-		addr = (ircom >> 6) & 0x1f;
-		/* invert 7th data bit for backward compatibility with RC5 keymaps */
-		if (!(ircom & 0x1000))
-			data |= 0x40;
-		toggle = ircom & 0x0800;
-		break;
-
-	default:
-		printk("%s invalid protocol %x\n", __func__, ir->protocol);
-		return;
-	}
-
-	input_event(ir->input_dev, EV_MSC, MSC_RAW, (addr << 16) | data);
-	input_event(ir->input_dev, EV_MSC, MSC_SCAN, data);
-
-	keycode = ir->key_map[data];
-
-	dprintk(16, "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n",
-		__func__, ircom, addr, data, keycode);
-
-	/* check device address */
-	if (!(ir->device_mask & (1 << addr)))
-		return;
-
-	if (!keycode) {
-		printk ("%s: code %08x -> addr %i data 0x%02x -> unknown key!\n",
-			__func__, ircom, addr, data);
-		return;
-	}
-
-	if (timer_pending(&ir->keyup_timer)) {
-		del_timer(&ir->keyup_timer);
-		if (ir->last_key != keycode || toggle != ir->last_toggle) {
-			ir->delay_timer_finished = 0;
-			input_event(ir->input_dev, EV_KEY, ir->last_key, 0);
-			input_event(ir->input_dev, EV_KEY, keycode, 1);
-			input_sync(ir->input_dev);
-		} else if (ir->delay_timer_finished) {
-			input_event(ir->input_dev, EV_KEY, keycode, 2);
-			input_sync(ir->input_dev);
-		}
-	} else {
-		ir->delay_timer_finished = 0;
-		input_event(ir->input_dev, EV_KEY, keycode, 1);
-		input_sync(ir->input_dev);
-	}
-
-	ir->last_key = keycode;
-	ir->last_toggle = toggle;
-
-	ir->keyup_timer.expires = jiffies + UP_TIMEOUT;
-	add_timer(&ir->keyup_timer);
-
-}
-
-
-/* register with input layer */
-static void input_register_keys(struct infrared *ir)
-{
-	int i;
-
-	set_bit(EV_KEY, ir->input_dev->evbit);
-	set_bit(EV_REP, ir->input_dev->evbit);
-	set_bit(EV_MSC, ir->input_dev->evbit);
-
-	set_bit(MSC_RAW, ir->input_dev->mscbit);
-	set_bit(MSC_SCAN, ir->input_dev->mscbit);
-
-	memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit));
-
-	for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) {
-		if (ir->key_map[i] > KEY_MAX)
-			ir->key_map[i] = 0;
-		else if (ir->key_map[i] > KEY_RESERVED)
-			set_bit(ir->key_map[i], ir->input_dev->keybit);
-	}
-
-	ir->input_dev->keycode = ir->key_map;
-	ir->input_dev->keycodesize = sizeof(ir->key_map[0]);
-	ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map);
-}
-
-
-/* called by the input driver after rep[REP_DELAY] ms */
-static void input_repeat_key(unsigned long parm)
-{
-	struct infrared *ir = (struct infrared *) parm;
-
-	ir->delay_timer_finished = 1;
-}
-
-
-/* check for configuration changes */
-int av7110_check_ir_config(struct av7110 *av7110, int force)
-{
-	int i;
-	int modified = force;
-	int ret = -ENODEV;
-
-	for (i = 0; i < av_cnt; i++)
-		if (av7110 == av_list[i])
-			break;
-
-	if (i < av_cnt && av7110) {
-		if ((av7110->ir.protocol & 1) != ir_protocol[i] ||
-		    av7110->ir.inversion != ir_inversion[i])
-			modified = true;
-
-		if (modified) {
-			/* protocol */
-			if (ir_protocol[i]) {
-				ir_protocol[i] = 1;
-				av7110->ir.protocol = IR_RCMM;
-				av7110->ir.ir_config = 0x0001;
-			} else if (FW_VERSION(av7110->arm_app) >= 0x2620) {
-				av7110->ir.protocol = IR_RC5_EXT;
-				av7110->ir.ir_config = 0x0002;
-			} else {
-				av7110->ir.protocol = IR_RC5;
-				av7110->ir.ir_config = 0x0000;
-			}
-			/* inversion */
-			if (ir_inversion[i]) {
-				ir_inversion[i] = 1;
-				av7110->ir.ir_config |= 0x8000;
-			}
-			av7110->ir.inversion = ir_inversion[i];
-			/* update ARM */
-			ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1,
-						av7110->ir.ir_config);
-		} else
-			ret = 0;
-
-		/* address */
-		if (av7110->ir.device_mask != ir_device_mask[i])
-			av7110->ir.device_mask = ir_device_mask[i];
-	}
-
-	return ret;
-}
-
-
-/* /proc/av7110_ir interface */
-static ssize_t av7110_ir_proc_write(struct file *file, const char __user *buffer,
-				    size_t count, loff_t *pos)
-{
-	char *page;
-	u32 ir_config;
-	int size = sizeof ir_config + sizeof av_list[0]->ir.key_map;
-	int i;
-
-	if (count < size)
-		return -EINVAL;
-
-	page = vmalloc(size);
-	if (!page)
-		return -ENOMEM;
-
-	if (copy_from_user(page, buffer, size)) {
-		vfree(page);
-		return -EFAULT;
-	}
-
-	memcpy(&ir_config, page, sizeof ir_config);
-
-	for (i = 0; i < av_cnt; i++) {
-		/* keymap */
-		memcpy(av_list[i]->ir.key_map, page + sizeof ir_config,
-			sizeof(av_list[i]->ir.key_map));
-		/* protocol, inversion, address */
-		ir_protocol[i] = ir_config & 0x0001;
-		ir_inversion[i] = ir_config & 0x8000 ? 1 : 0;
-		if (ir_config & 0x4000)
-			ir_device_mask[i] = 1 << ((ir_config >> 16) & 0x1f);
-		else
-			ir_device_mask[i] = IR_ALL;
-		/* update configuration */
-		av7110_check_ir_config(av_list[i], false);
-		input_register_keys(&av_list[i]->ir);
-	}
-	vfree(page);
-	return count;
-}
-
-static const struct file_operations av7110_ir_proc_fops = {
-	.owner		= THIS_MODULE,
-	.write		= av7110_ir_proc_write,
-	.llseek		= noop_llseek,
-};
-
-/* interrupt handler */
-static void ir_handler(struct av7110 *av7110, u32 ircom)
-{
-	dprintk(4, "ir command = %08x\n", ircom);
-	av7110->ir.ir_command = ircom;
-	tasklet_schedule(&av7110->ir.ir_tasklet);
-}
-
-
-int __devinit av7110_ir_init(struct av7110 *av7110)
-{
-	struct input_dev *input_dev;
-	static struct proc_dir_entry *e;
-	int err;
-
-	if (av_cnt >= ARRAY_SIZE(av_list))
-		return -ENOSPC;
-
-	av_list[av_cnt++] = av7110;
-	av7110_check_ir_config(av7110, true);
-
-	init_timer(&av7110->ir.keyup_timer);
-	av7110->ir.keyup_timer.function = av7110_emit_keyup;
-	av7110->ir.keyup_timer.data = (unsigned long) &av7110->ir;
-
-	input_dev = input_allocate_device();
-	if (!input_dev)
-		return -ENOMEM;
-
-	av7110->ir.input_dev = input_dev;
-	snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys),
-		"pci-%s/ir0", pci_name(av7110->dev->pci));
-
-	input_dev->name = "DVB on-card IR receiver";
-
-	input_dev->phys = av7110->ir.input_phys;
-	input_dev->id.bustype = BUS_PCI;
-	input_dev->id.version = 2;
-	if (av7110->dev->pci->subsystem_vendor) {
-		input_dev->id.vendor = av7110->dev->pci->subsystem_vendor;
-		input_dev->id.product = av7110->dev->pci->subsystem_device;
-	} else {
-		input_dev->id.vendor = av7110->dev->pci->vendor;
-		input_dev->id.product = av7110->dev->pci->device;
-	}
-	input_dev->dev.parent = &av7110->dev->pci->dev;
-	/* initial keymap */
-	memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map);
-	input_register_keys(&av7110->ir);
-	err = input_register_device(input_dev);
-	if (err) {
-		input_free_device(input_dev);
-		return err;
-	}
-	input_dev->timer.function = input_repeat_key;
-	input_dev->timer.data = (unsigned long) &av7110->ir;
-
-	if (av_cnt == 1) {
-		e = proc_create("av7110_ir", S_IWUSR, NULL, &av7110_ir_proc_fops);
-		if (e)
-			e->size = 4 + 256 * sizeof(u16);
-	}
-
-	tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir);
-	av7110->ir.ir_handler = ir_handler;
-
-	return 0;
-}
-
-
-void __devexit av7110_ir_exit(struct av7110 *av7110)
-{
-	int i;
-
-	if (av_cnt == 0)
-		return;
-
-	del_timer_sync(&av7110->ir.keyup_timer);
-	av7110->ir.ir_handler = NULL;
-	tasklet_kill(&av7110->ir.ir_tasklet);
-
-	for (i = 0; i < av_cnt; i++)
-		if (av_list[i] == av7110) {
-			av_list[i] = av_list[av_cnt-1];
-			av_list[av_cnt-1] = NULL;
-			break;
-		}
-
-	if (av_cnt == 1)
-		remove_proc_entry("av7110_ir", NULL);
-
-	input_unregister_device(av7110->ir.input_dev);
-
-	av_cnt--;
-}
-
-//MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>, Oliver Endriss <o.endriss@gmx.de>");
-//MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
deleted file mode 100644
index 1b2d151..0000000
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ /dev/null
@@ -1,966 +0,0 @@
-/*
- * av7110_v4l.c: av7110 video4linux interface for DVB and Siemens DVB-C analog module
- *
- * Copyright (C) 1999-2002 Ralph  Metzler
- *                       & Marcus Metzler for convergence integrated media GmbH
- *
- * originally based on code by:
- * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- * the project's page is at http://www.linuxtv.org/ 
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/timer.h>
-#include <linux/poll.h>
-
-#include "av7110.h"
-#include "av7110_hw.h"
-#include "av7110_av.h"
-
-int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val)
-{
-	u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff };
-	struct i2c_msg msgs = { .flags = 0, .len = 5, .buf = msg };
-
-	switch (av7110->adac_type) {
-	case DVB_ADAC_MSP34x0:
-		msgs.addr = 0x40;
-		break;
-	case DVB_ADAC_MSP34x5:
-		msgs.addr = 0x42;
-		break;
-	default:
-		return 0;
-	}
-
-	if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) {
-		dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n",
-		       av7110->dvb_adapter.num, reg, val);
-		return -EIO;
-	}
-	return 0;
-}
-
-static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val)
-{
-	u8 msg1[3] = { dev, reg >> 8, reg & 0xff };
-	u8 msg2[2];
-	struct i2c_msg msgs[2] = {
-		{ .flags = 0	   , .len = 3, .buf = msg1 },
-		{ .flags = I2C_M_RD, .len = 2, .buf = msg2 }
-	};
-
-	switch (av7110->adac_type) {
-	case DVB_ADAC_MSP34x0:
-		msgs[0].addr = 0x40;
-		msgs[1].addr = 0x40;
-		break;
-	case DVB_ADAC_MSP34x5:
-		msgs[0].addr = 0x42;
-		msgs[1].addr = 0x42;
-		break;
-	default:
-		return 0;
-	}
-
-	if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) {
-		dprintk(1, "dvb-ttpci: failed @ card %d, %u\n",
-		       av7110->dvb_adapter.num, reg);
-		return -EIO;
-	}
-	*val = (msg2[0] << 8) | msg2[1];
-	return 0;
-}
-
-static struct v4l2_input inputs[4] = {
-	{
-		.index		= 0,
-		.name		= "DVB",
-		.type		= V4L2_INPUT_TYPE_CAMERA,
-		.audioset	= 1,
-		.tuner		= 0, /* ignored */
-		.std		= V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
-		.status		= 0,
-		.capabilities	= V4L2_IN_CAP_STD,
-	}, {
-		.index		= 1,
-		.name		= "Television",
-		.type		= V4L2_INPUT_TYPE_TUNER,
-		.audioset	= 1,
-		.tuner		= 0,
-		.std		= V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
-		.status		= 0,
-		.capabilities	= V4L2_IN_CAP_STD,
-	}, {
-		.index		= 2,
-		.name		= "Video",
-		.type		= V4L2_INPUT_TYPE_CAMERA,
-		.audioset	= 0,
-		.tuner		= 0,
-		.std		= V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
-		.status		= 0,
-		.capabilities	= V4L2_IN_CAP_STD,
-	}, {
-		.index		= 3,
-		.name		= "Y/C",
-		.type		= V4L2_INPUT_TYPE_CAMERA,
-		.audioset	= 0,
-		.tuner		= 0,
-		.std		= V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
-		.status		= 0,
-		.capabilities	= V4L2_IN_CAP_STD,
-	}
-};
-
-static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
-{
-	struct av7110 *av7110 = dev->ext_priv;
-	u8 buf[] = { 0x00, reg, data };
-	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
-
-	dprintk(4, "dev: %p\n", dev);
-
-	if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
-		return -1;
-	return 0;
-}
-
-static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4])
-{
-	struct av7110 *av7110 = dev->ext_priv;
-	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
-
-	dprintk(4, "dev: %p\n", dev);
-
-	if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
-		return -1;
-	return 0;
-}
-
-static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq)
-{
-	u32 div;
-	u8 config;
-	u8 buf[4];
-
-	dprintk(4, "freq: 0x%08x\n", freq);
-
-	/* magic number: 614. tuning with the frequency given by v4l2
-	   is always off by 614*62.5 = 38375 kHz...*/
-	div = freq + 614;
-
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = div & 0xff;
-	buf[2] = 0x8e;
-
-	if (freq < (u32) (16 * 168.25))
-		config = 0xa0;
-	else if (freq < (u32) (16 * 447.25))
-		config = 0x90;
-	else
-		config = 0x30;
-	config &= ~0x02;
-
-	buf[3] = config;
-
-	return tuner_write(dev, 0x61, buf);
-}
-
-static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq)
-{
-	struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
-	u32 div;
-	u8 data[4];
-
-	div = (freq + 38900000 + 31250) / 62500;
-
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0xce;
-
-	if (freq < 45000000)
-		return -EINVAL;
-	else if (freq < 137000000)
-		data[3] = 0x01;
-	else if (freq < 403000000)
-		data[3] = 0x02;
-	else if (freq < 860000000)
-		data[3] = 0x04;
-	else
-		return -EINVAL;
-
-	if (av7110->fe->ops.i2c_gate_ctrl)
-		av7110->fe->ops.i2c_gate_ctrl(av7110->fe, 1);
-	return tuner_write(dev, 0x63, data);
-}
-
-
-
-static struct saa7146_standard analog_standard[];
-static struct saa7146_standard dvb_standard[];
-static struct saa7146_standard standard[];
-
-static struct v4l2_audio msp3400_v4l2_audio = {
-	.index = 0,
-	.name = "Television",
-	.capability = V4L2_AUDCAP_STEREO
-};
-
-static int av7110_dvb_c_switch(struct saa7146_fh *fh)
-{
-	struct saa7146_dev *dev = fh->dev;
-	struct saa7146_vv *vv = dev->vv_data;
-	struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
-	u16 adswitch;
-	int source, sync, err;
-
-	dprintk(4, "%p\n", av7110);
-
-	if ((vv->video_status & STATUS_OVERLAY) != 0) {
-		vv->ov_suspend = vv->video_fh;
-		err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
-		if (err != 0) {
-			dprintk(2, "suspending video failed\n");
-			vv->ov_suspend = NULL;
-		}
-	}
-
-	if (0 != av7110->current_input) {
-		dprintk(1, "switching to analog TV:\n");
-		adswitch = 1;
-		source = SAA7146_HPS_SOURCE_PORT_B;
-		sync = SAA7146_HPS_SYNC_PORT_B;
-		memcpy(standard, analog_standard, sizeof(struct saa7146_standard) * 2);
-
-		switch (av7110->current_input) {
-		case 1:
-			dprintk(1, "switching SAA7113 to Analog Tuner Input\n");
-			msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source
-			msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source
-			msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source
-			msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono
-			msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone
-			msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume
-
-			if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
-				if (ves1820_writereg(dev, 0x09, 0x0f, 0x60))
-					dprintk(1, "setting band in demodulator failed\n");
-			} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
-				saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9819 pin9(STD)
-				saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9819 pin30(VIF)
-			}
-			if (i2c_writereg(av7110, 0x48, 0x02, 0xd0) != 1)
-				dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
-			break;
-		case 2:
-			dprintk(1, "switching SAA7113 to Video AV CVBS Input\n");
-			if (i2c_writereg(av7110, 0x48, 0x02, 0xd2) != 1)
-				dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
-			break;
-		case 3:
-			dprintk(1, "switching SAA7113 to Video AV Y/C Input\n");
-			if (i2c_writereg(av7110, 0x48, 0x02, 0xd9) != 1)
-				dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
-			break;
-		default:
-			dprintk(1, "switching SAA7113 to Input: AV7110: SAA7113: invalid input\n");
-		}
-	} else {
-		adswitch = 0;
-		source = SAA7146_HPS_SOURCE_PORT_A;
-		sync = SAA7146_HPS_SYNC_PORT_A;
-		memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2);
-		dprintk(1, "switching DVB mode\n");
-		msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source
-		msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source
-		msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source
-		msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono
-		msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
-		msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume
-
-		if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
-			if (ves1820_writereg(dev, 0x09, 0x0f, 0x20))
-				dprintk(1, "setting band in demodulator failed\n");
-		} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
-			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
-			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
-		}
-	}
-
-	/* hmm, this does not do anything!? */
-	if (av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, adswitch))
-		dprintk(1, "ADSwitch error\n");
-
-	saa7146_set_hps_source_and_sync(dev, source, sync);
-
-	if (vv->ov_suspend != NULL) {
-		saa7146_start_preview(vv->ov_suspend);
-		vv->ov_suspend = NULL;
-	}
-
-	return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
-	u16 stereo_det;
-	s8 stereo;
-
-	dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index);
-
-	if (!av7110->analog_tuner_flags || t->index != 0)
-		return -EINVAL;
-
-	memset(t, 0, sizeof(*t));
-	strcpy((char *)t->name, "Television");
-
-	t->type = V4L2_TUNER_ANALOG_TV;
-	t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
-		V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
-	t->rangelow = 772;	/* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
-	t->rangehigh = 13684;	/* 855.25 MHz / 62.5 kHz = 13684 */
-	/* FIXME: add the real signal strength here */
-	t->signal = 0xffff;
-	t->afc = 0;
-
-	/* FIXME: standard / stereo detection is still broken */
-	msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det);
-	dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
-	msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det);
-	dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det);
-	stereo = (s8)(stereo_det >> 8);
-	if (stereo > 0x10) {
-		/* stereo */
-		t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
-		t->audmode = V4L2_TUNER_MODE_STEREO;
-	} else if (stereo < -0x10) {
-		/* bilingual */
-		t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
-		t->audmode = V4L2_TUNER_MODE_LANG1;
-	} else /* mono */
-		t->rxsubchans = V4L2_TUNER_SUB_MONO;
-
-	return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
-	u16 fm_matrix, src;
-	dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index);
-
-	if (!av7110->analog_tuner_flags || av7110->current_input != 1)
-		return -EINVAL;
-
-	switch (t->audmode) {
-	case V4L2_TUNER_MODE_STEREO:
-		dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n");
-		fm_matrix = 0x3001; /* stereo */
-		src = 0x0020;
-		break;
-	case V4L2_TUNER_MODE_LANG1_LANG2:
-		dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n");
-		fm_matrix = 0x3000; /* bilingual */
-		src = 0x0020;
-		break;
-	case V4L2_TUNER_MODE_LANG1:
-		dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n");
-		fm_matrix = 0x3000; /* mono */
-		src = 0x0000;
-		break;
-	case V4L2_TUNER_MODE_LANG2:
-		dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n");
-		fm_matrix = 0x3000; /* mono */
-		src = 0x0010;
-		break;
-	default: /* case V4L2_TUNER_MODE_MONO: */
-		dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n");
-		fm_matrix = 0x3000; /* mono */
-		src = 0x0030;
-		break;
-	}
-	msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix);
-	msp_writereg(av7110, MSP_WR_DSP, 0x0008, src);
-	msp_writereg(av7110, MSP_WR_DSP, 0x0009, src);
-	msp_writereg(av7110, MSP_WR_DSP, 0x000a, src);
-	return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
-
-	dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x\n", f->frequency);
-
-	if (!av7110->analog_tuner_flags || av7110->current_input != 1)
-		return -EINVAL;
-
-	memset(f, 0, sizeof(*f));
-	f->type = V4L2_TUNER_ANALOG_TV;
-	f->frequency =	av7110->current_freq;
-	return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
-
-	dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x\n", f->frequency);
-
-	if (!av7110->analog_tuner_flags || av7110->current_input != 1)
-		return -EINVAL;
-
-	if (V4L2_TUNER_ANALOG_TV != f->type)
-		return -EINVAL;
-
-	msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); /* fast mute */
-	msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0);
-
-	/* tune in desired frequency */
-	if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820)
-		ves1820_set_tv_freq(dev, f->frequency);
-	else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297)
-		stv0297_set_tv_freq(dev, f->frequency);
-	av7110->current_freq = f->frequency;
-
-	msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); /* start stereo detection */
-	msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000);
-	msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); /* loudspeaker + headphone */
-	msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); /* SCART 1 volume */
-	return 0;
-}
-
-static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
-
-	dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
-
-	if (av7110->analog_tuner_flags) {
-		if (i->index >= 4)
-			return -EINVAL;
-	} else {
-		if (i->index != 0)
-			return -EINVAL;
-	}
-
-	memcpy(i, &inputs[i->index], sizeof(struct v4l2_input));
-
-	return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
-
-	*input = av7110->current_input;
-	dprintk(2, "VIDIOC_G_INPUT: %d\n", *input);
-	return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
-
-	dprintk(2, "VIDIOC_S_INPUT: %d\n", input);
-
-	if (!av7110->analog_tuner_flags)
-		return input ? -EINVAL : 0;
-
-	if (input >= 4)
-		return -EINVAL;
-
-	av7110->current_input = input;
-	return av7110_dvb_c_switch(fh);
-}
-
-static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
-{
-	dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
-	if (a->index != 0)
-		return -EINVAL;
-	*a = msp3400_v4l2_audio;
-	return 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
-
-	dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
-	if (a->index != 0)
-		return -EINVAL;
-	if (av7110->current_input >= 2)
-		return -EINVAL;
-	*a = msp3400_v4l2_audio;
-	return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
-
-	dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
-	if (av7110->current_input >= 2)
-		return -EINVAL;
-	return a->index ? -EINVAL : 0;
-}
-
-static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh,
-					struct v4l2_sliced_vbi_cap *cap)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
-
-	dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
-	if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
-		return -EINVAL;
-	if (FW_VERSION(av7110->arm_app) >= 0x2623) {
-		cap->service_set = V4L2_SLICED_WSS_625;
-		cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
-	}
-	return 0;
-}
-
-static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh,
-					struct v4l2_format *f)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
-
-	dprintk(2, "VIDIOC_G_FMT:\n");
-	if (FW_VERSION(av7110->arm_app) < 0x2623)
-		return -EINVAL;
-	memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
-	if (av7110->wssMode) {
-		f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
-		f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
-		f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data);
-	}
-	return 0;
-}
-
-static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh,
-					struct v4l2_format *f)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
-
-	dprintk(2, "VIDIOC_S_FMT\n");
-	if (FW_VERSION(av7110->arm_app) < 0x2623)
-		return -EINVAL;
-	if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
-	    f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
-		memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
-		/* WSS controlled by firmware */
-		av7110->wssMode = 0;
-		av7110->wssData = 0;
-		return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
-				     SetWSSConfig, 1, 0);
-	} else {
-		memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
-		f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
-		f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
-		f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data);
-		/* WSS controlled by userspace */
-		av7110->wssMode = 1;
-		av7110->wssData = 0;
-	}
-	return 0;
-}
-
-static int av7110_vbi_reset(struct file *file)
-{
-	struct saa7146_fh *fh = file->private_data;
-	struct saa7146_dev *dev = fh->dev;
-	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
-
-	dprintk(2, "%s\n", __func__);
-	av7110->wssMode = 0;
-	av7110->wssData = 0;
-	if (FW_VERSION(av7110->arm_app) < 0x2623)
-		return 0;
-	else
-		return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
-}
-
-static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
-{
-	struct saa7146_fh *fh = file->private_data;
-	struct saa7146_dev *dev = fh->dev;
-	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
-	struct v4l2_sliced_vbi_data d;
-	int rc;
-
-	dprintk(2, "%s\n", __func__);
-	if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d)
-		return -EINVAL;
-	if (copy_from_user(&d, data, count))
-		return -EFAULT;
-	if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23)
-		return -EINVAL;
-	if (d.id)
-		av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0];
-	else
-		av7110->wssData = 0x8000;
-	rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 1, av7110->wssData);
-	return (rc < 0) ? rc : count;
-}
-
-/****************************************************************************
- * INITIALIZATION
- ****************************************************************************/
-
-static u8 saa7113_init_regs[] = {
-	0x02, 0xd0,
-	0x03, 0x23,
-	0x04, 0x00,
-	0x05, 0x00,
-	0x06, 0xe9,
-	0x07, 0x0d,
-	0x08, 0x98,
-	0x09, 0x02,
-	0x0a, 0x80,
-	0x0b, 0x40,
-	0x0c, 0x40,
-	0x0d, 0x00,
-	0x0e, 0x01,
-	0x0f, 0x7c,
-	0x10, 0x48,
-	0x11, 0x0c,
-	0x12, 0x8b,
-	0x13, 0x1a,
-	0x14, 0x00,
-	0x15, 0x00,
-	0x16, 0x00,
-	0x17, 0x00,
-	0x18, 0x00,
-	0x19, 0x00,
-	0x1a, 0x00,
-	0x1b, 0x00,
-	0x1c, 0x00,
-	0x1d, 0x00,
-	0x1e, 0x00,
-
-	0x41, 0x77,
-	0x42, 0x77,
-	0x43, 0x77,
-	0x44, 0x77,
-	0x45, 0x77,
-	0x46, 0x77,
-	0x47, 0x77,
-	0x48, 0x77,
-	0x49, 0x77,
-	0x4a, 0x77,
-	0x4b, 0x77,
-	0x4c, 0x77,
-	0x4d, 0x77,
-	0x4e, 0x77,
-	0x4f, 0x77,
-	0x50, 0x77,
-	0x51, 0x77,
-	0x52, 0x77,
-	0x53, 0x77,
-	0x54, 0x77,
-	0x55, 0x77,
-	0x56, 0x77,
-	0x57, 0xff,
-
-	0xff
-};
-
-
-static struct saa7146_ext_vv av7110_vv_data_st;
-static struct saa7146_ext_vv av7110_vv_data_c;
-
-int av7110_init_analog_module(struct av7110 *av7110)
-{
-	u16 version1, version2;
-
-	if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 &&
-	    i2c_writereg(av7110, 0x80, 0x0, 0) == 1) {
-		pr_info("DVB-C analog module @ card %d detected, initializing MSP3400\n",
-			av7110->dvb_adapter.num);
-		av7110->adac_type = DVB_ADAC_MSP34x0;
-	} else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 &&
-		   i2c_writereg(av7110, 0x84, 0x0, 0) == 1) {
-		pr_info("DVB-C analog module @ card %d detected, initializing MSP3415\n",
-			av7110->dvb_adapter.num);
-		av7110->adac_type = DVB_ADAC_MSP34x5;
-	} else
-		return -ENODEV;
-
-	msleep(100); // the probing above resets the msp...
-	msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
-	msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
-	dprintk(1, "dvb-ttpci: @ card %d MSP34xx version 0x%04x 0x%04x\n",
-		av7110->dvb_adapter.num, version1, version2);
-	msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00);
-	msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
-	msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source
-	msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source
-	msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume
-	msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source
-	msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume
-	msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART
-
-	if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) {
-		pr_info("saa7113 not accessible\n");
-	} else {
-		u8 *i = saa7113_init_regs;
-
-		if ((av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) {
-			/* Fujitsu/Siemens DVB-Cable */
-			av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820;
-		} else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x0002)) {
-			/* Hauppauge/TT DVB-C premium */
-			av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820;
-		} else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x000A)) {
-			/* Hauppauge/TT DVB-C premium */
-			av7110->analog_tuner_flags |= ANALOG_TUNER_STV0297;
-		}
-
-		/* setup for DVB by default */
-		if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
-			if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20))
-				dprintk(1, "setting band in demodulator failed\n");
-		} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
-			saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
-			saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
-		}
-
-		/* init the saa7113 */
-		while (*i != 0xff) {
-			if (i2c_writereg(av7110, 0x48, i[0], i[1]) != 1) {
-				dprintk(1, "saa7113 initialization failed @ card %d", av7110->dvb_adapter.num);
-				break;
-			}
-			i += 2;
-		}
-		/* setup msp for analog sound: B/G Dual-FM */
-		msp_writereg(av7110, MSP_WR_DEM, 0x00bb, 0x02d0); // AD_CV
-		msp_writereg(av7110, MSP_WR_DEM, 0x0001,  3); // FIR1
-		msp_writereg(av7110, MSP_WR_DEM, 0x0001, 18); // FIR1
-		msp_writereg(av7110, MSP_WR_DEM, 0x0001, 27); // FIR1
-		msp_writereg(av7110, MSP_WR_DEM, 0x0001, 48); // FIR1
-		msp_writereg(av7110, MSP_WR_DEM, 0x0001, 66); // FIR1
-		msp_writereg(av7110, MSP_WR_DEM, 0x0001, 72); // FIR1
-		msp_writereg(av7110, MSP_WR_DEM, 0x0005,  4); // FIR2
-		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 64); // FIR2
-		msp_writereg(av7110, MSP_WR_DEM, 0x0005,  0); // FIR2
-		msp_writereg(av7110, MSP_WR_DEM, 0x0005,  3); // FIR2
-		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 18); // FIR2
-		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 27); // FIR2
-		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 48); // FIR2
-		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 66); // FIR2
-		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 72); // FIR2
-		msp_writereg(av7110, MSP_WR_DEM, 0x0083, 0xa000); // MODE_REG
-		msp_writereg(av7110, MSP_WR_DEM, 0x0093, 0x00aa); // DCO1_LO 5.74MHz
-		msp_writereg(av7110, MSP_WR_DEM, 0x009b, 0x04fc); // DCO1_HI
-		msp_writereg(av7110, MSP_WR_DEM, 0x00a3, 0x038e); // DCO2_LO 5.5MHz
-		msp_writereg(av7110, MSP_WR_DEM, 0x00ab, 0x04c6); // DCO2_HI
-		msp_writereg(av7110, MSP_WR_DEM, 0x0056, 0); // LOAD_REG 1/2
-	}
-
-	memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2);
-	/* set dd1 stream a & b */
-	saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
-	saa7146_write(av7110->dev, DD1_INIT, 0x03000700);
-	saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
-
-	return 0;
-}
-
-int av7110_init_v4l(struct av7110 *av7110)
-{
-	struct saa7146_dev* dev = av7110->dev;
-	struct saa7146_ext_vv *vv_data;
-	int ret;
-
-	/* special case DVB-C: these cards have an analog tuner
-	   plus need some special handling, so we have separate
-	   saa7146_ext_vv data for these... */
-	if (av7110->analog_tuner_flags)
-		vv_data = &av7110_vv_data_c;
-	else
-		vv_data = &av7110_vv_data_st;
-	ret = saa7146_vv_init(dev, vv_data);
-
-	if (ret) {
-		ERR("cannot init capture device. skipping\n");
-		return -ENODEV;
-	}
-	vv_data->vid_ops.vidioc_enum_input = vidioc_enum_input;
-	vv_data->vid_ops.vidioc_g_input = vidioc_g_input;
-	vv_data->vid_ops.vidioc_s_input = vidioc_s_input;
-	vv_data->vid_ops.vidioc_g_tuner = vidioc_g_tuner;
-	vv_data->vid_ops.vidioc_s_tuner = vidioc_s_tuner;
-	vv_data->vid_ops.vidioc_g_frequency = vidioc_g_frequency;
-	vv_data->vid_ops.vidioc_s_frequency = vidioc_s_frequency;
-	vv_data->vid_ops.vidioc_enumaudio = vidioc_enumaudio;
-	vv_data->vid_ops.vidioc_g_audio = vidioc_g_audio;
-	vv_data->vid_ops.vidioc_s_audio = vidioc_s_audio;
-	vv_data->vid_ops.vidioc_g_fmt_vbi_cap = NULL;
-
-	vv_data->vbi_ops.vidioc_g_tuner = vidioc_g_tuner;
-	vv_data->vbi_ops.vidioc_s_tuner = vidioc_s_tuner;
-	vv_data->vbi_ops.vidioc_g_frequency = vidioc_g_frequency;
-	vv_data->vbi_ops.vidioc_s_frequency = vidioc_s_frequency;
-	vv_data->vbi_ops.vidioc_g_fmt_vbi_cap = NULL;
-	vv_data->vbi_ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap;
-	vv_data->vbi_ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out;
-	vv_data->vbi_ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out;
-
-	if (FW_VERSION(av7110->arm_app) < 0x2623)
-		vv_data->capabilities &= ~V4L2_CAP_SLICED_VBI_OUTPUT;
-
-	if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) {
-		ERR("cannot register capture device. skipping\n");
-		saa7146_vv_release(dev);
-		return -ENODEV;
-	}
-	if (FW_VERSION(av7110->arm_app) >= 0x2623) {
-		if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI))
-			ERR("cannot register vbi v4l2 device. skipping\n");
-	}
-	return 0;
-}
-
-int av7110_exit_v4l(struct av7110 *av7110)
-{
-	struct saa7146_dev* dev = av7110->dev;
-
-	saa7146_unregister_device(&av7110->v4l_dev, av7110->dev);
-	saa7146_unregister_device(&av7110->vbi_dev, av7110->dev);
-
-	saa7146_vv_release(dev);
-
-	return 0;
-}
-
-
-
-/* FIXME: these values are experimental values that look better than the
-   values from the latest "official" driver -- at least for me... (MiHu) */
-static struct saa7146_standard standard[] = {
-	{
-		.name	= "PAL",	.id		= V4L2_STD_PAL_BG,
-		.v_offset	= 0x15,	.v_field	= 288,
-		.h_offset	= 0x48,	.h_pixels	= 708,
-		.v_max_out	= 576,	.h_max_out	= 768,
-	}, {
-		.name	= "NTSC",	.id		= V4L2_STD_NTSC,
-		.v_offset	= 0x10,	.v_field	= 244,
-		.h_offset	= 0x40,	.h_pixels	= 708,
-		.v_max_out	= 480,	.h_max_out	= 640,
-	}
-};
-
-static struct saa7146_standard analog_standard[] = {
-	{
-		.name	= "PAL",	.id		= V4L2_STD_PAL_BG,
-		.v_offset	= 0x1b,	.v_field	= 288,
-		.h_offset	= 0x08,	.h_pixels	= 708,
-		.v_max_out	= 576,	.h_max_out	= 768,
-	}, {
-		.name	= "NTSC",	.id		= V4L2_STD_NTSC,
-		.v_offset	= 0x10,	.v_field	= 244,
-		.h_offset	= 0x40,	.h_pixels	= 708,
-		.v_max_out	= 480,	.h_max_out	= 640,
-	}
-};
-
-static struct saa7146_standard dvb_standard[] = {
-	{
-		.name	= "PAL",	.id		= V4L2_STD_PAL_BG,
-		.v_offset	= 0x14,	.v_field	= 288,
-		.h_offset	= 0x48,	.h_pixels	= 708,
-		.v_max_out	= 576,	.h_max_out	= 768,
-	}, {
-		.name	= "NTSC",	.id		= V4L2_STD_NTSC,
-		.v_offset	= 0x10,	.v_field	= 244,
-		.h_offset	= 0x40,	.h_pixels	= 708,
-		.v_max_out	= 480,	.h_max_out	= 640,
-	}
-};
-
-static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
-{
-	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
-
-	if (std->id & V4L2_STD_PAL) {
-		av7110->vidmode = AV7110_VIDEO_MODE_PAL;
-		av7110_set_vidmode(av7110, av7110->vidmode);
-	}
-	else if (std->id & V4L2_STD_NTSC) {
-		av7110->vidmode = AV7110_VIDEO_MODE_NTSC;
-		av7110_set_vidmode(av7110, av7110->vidmode);
-	}
-	else
-		return -1;
-
-	return 0;
-}
-
-
-static struct saa7146_ext_vv av7110_vv_data_st = {
-	.inputs		= 1,
-	.audios		= 1,
-	.capabilities	= V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO,
-	.flags		= 0,
-
-	.stds		= &standard[0],
-	.num_stds	= ARRAY_SIZE(standard),
-	.std_callback	= &std_callback,
-
-	.vbi_fops.open	= av7110_vbi_reset,
-	.vbi_fops.release = av7110_vbi_reset,
-	.vbi_fops.write	= av7110_vbi_write,
-};
-
-static struct saa7146_ext_vv av7110_vv_data_c = {
-	.inputs		= 1,
-	.audios		= 1,
-	.capabilities	= V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO,
-	.flags		= SAA7146_USE_PORT_B_FOR_VBI,
-
-	.stds		= &standard[0],
-	.num_stds	= ARRAY_SIZE(standard),
-	.std_callback	= &std_callback,
-
-	.vbi_fops.open	= av7110_vbi_reset,
-	.vbi_fops.release = av7110_vbi_reset,
-	.vbi_fops.write	= av7110_vbi_write,
-};
-
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
deleted file mode 100644
index 12ddb53..0000000
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ /dev/null
@@ -1,1640 +0,0 @@
-/*
- * budget-av.c: driver for the SAA7146 based Budget DVB cards
- *              with analog video in
- *
- * Compiled from various sources by Michael Hunold <michael@mihu.de>
- *
- * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> &
- *                               Andrew de Quincey <adq_dvb@lidskialf.net>
- *
- * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
- *
- * Copyright (C) 1999-2002 Ralph  Metzler
- *                       & Marcus Metzler for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org/ 
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include "budget.h"
-#include "stv0299.h"
-#include "stb0899_drv.h"
-#include "stb0899_reg.h"
-#include "stb0899_cfg.h"
-#include "tda8261.h"
-#include "tda8261_cfg.h"
-#include "tda1002x.h"
-#include "tda1004x.h"
-#include "tua6100.h"
-#include "dvb-pll.h"
-#include <media/saa7146_vv.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/input.h>
-#include <linux/spinlock.h>
-
-#include "dvb_ca_en50221.h"
-
-#define DEBICICAM		0x02420000
-
-#define SLOTSTATUS_NONE         1
-#define SLOTSTATUS_PRESENT      2
-#define SLOTSTATUS_RESET        4
-#define SLOTSTATUS_READY        8
-#define SLOTSTATUS_OCCUPIED     (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-struct budget_av {
-	struct budget budget;
-	struct video_device *vd;
-	int cur_input;
-	int has_saa7113;
-	struct tasklet_struct ciintf_irq_tasklet;
-	int slot_status;
-	struct dvb_ca_en50221 ca;
-	u8 reinitialise_demod:1;
-};
-
-static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot);
-
-
-/* GPIO Connections:
- * 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*!
- * 1 - CI memory select 0=>IO memory, 1=>Attribute Memory
- * 2 - CI Card Enable (Active Low)
- * 3 - CI Card Detect
- */
-
-/****************************************************************************
- * INITIALIZATION
- ****************************************************************************/
-
-static u8 i2c_readreg(struct i2c_adapter *i2c, u8 id, u8 reg)
-{
-	u8 mm1[] = { 0x00 };
-	u8 mm2[] = { 0x00 };
-	struct i2c_msg msgs[2];
-
-	msgs[0].flags = 0;
-	msgs[1].flags = I2C_M_RD;
-	msgs[0].addr = msgs[1].addr = id / 2;
-	mm1[0] = reg;
-	msgs[0].len = 1;
-	msgs[1].len = 1;
-	msgs[0].buf = mm1;
-	msgs[1].buf = mm2;
-
-	i2c_transfer(i2c, msgs, 2);
-
-	return mm2[0];
-}
-
-static int i2c_readregs(struct i2c_adapter *i2c, u8 id, u8 reg, u8 * buf, u8 len)
-{
-	u8 mm1[] = { reg };
-	struct i2c_msg msgs[2] = {
-		{.addr = id / 2,.flags = 0,.buf = mm1,.len = 1},
-		{.addr = id / 2,.flags = I2C_M_RD,.buf = buf,.len = len}
-	};
-
-	if (i2c_transfer(i2c, msgs, 2) != 2)
-		return -EIO;
-
-	return 0;
-}
-
-static int i2c_writereg(struct i2c_adapter *i2c, u8 id, u8 reg, u8 val)
-{
-	u8 msg[2] = { reg, val };
-	struct i2c_msg msgs;
-
-	msgs.flags = 0;
-	msgs.addr = id / 2;
-	msgs.len = 2;
-	msgs.buf = msg;
-	return i2c_transfer(i2c, &msgs, 1);
-}
-
-static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
-{
-	struct budget_av *budget_av = (struct budget_av *) ca->data;
-	int result;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
-	udelay(1);
-
-	result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1);
-	if (result == -ETIMEDOUT) {
-		ciintf_slot_shutdown(ca, slot);
-		pr_info("cam ejected 1\n");
-	}
-	return result;
-}
-
-static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
-{
-	struct budget_av *budget_av = (struct budget_av *) ca->data;
-	int result;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
-	udelay(1);
-
-	result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1);
-	if (result == -ETIMEDOUT) {
-		ciintf_slot_shutdown(ca, slot);
-		pr_info("cam ejected 2\n");
-	}
-	return result;
-}
-
-static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
-{
-	struct budget_av *budget_av = (struct budget_av *) ca->data;
-	int result;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
-	udelay(1);
-
-	result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0);
-	if (result == -ETIMEDOUT) {
-		ciintf_slot_shutdown(ca, slot);
-		pr_info("cam ejected 3\n");
-		return -ETIMEDOUT;
-	}
-	return result;
-}
-
-static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
-{
-	struct budget_av *budget_av = (struct budget_av *) ca->data;
-	int result;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
-	udelay(1);
-
-	result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0);
-	if (result == -ETIMEDOUT) {
-		ciintf_slot_shutdown(ca, slot);
-		pr_info("cam ejected 5\n");
-	}
-	return result;
-}
-
-static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
-{
-	struct budget_av *budget_av = (struct budget_av *) ca->data;
-	struct saa7146_dev *saa = budget_av->budget.dev;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	dprintk(1, "ciintf_slot_reset\n");
-	budget_av->slot_status = SLOTSTATUS_RESET;
-
-	saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
-
-	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */
-	msleep(2);
-	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); /* Vcc on */
-	msleep(20); /* 20 ms Vcc settling time */
-
-	saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */
-	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
-	msleep(20);
-
-	/* reinitialise the frontend if necessary */
-	if (budget_av->reinitialise_demod)
-		dvb_frontend_reinitialise(budget_av->budget.dvb_frontend);
-
-	return 0;
-}
-
-static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
-{
-	struct budget_av *budget_av = (struct budget_av *) ca->data;
-	struct saa7146_dev *saa = budget_av->budget.dev;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	dprintk(1, "ciintf_slot_shutdown\n");
-
-	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
-	budget_av->slot_status = SLOTSTATUS_NONE;
-
-	return 0;
-}
-
-static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
-{
-	struct budget_av *budget_av = (struct budget_av *) ca->data;
-	struct saa7146_dev *saa = budget_av->budget.dev;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status);
-
-	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
-
-	return 0;
-}
-
-static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
-{
-	struct budget_av *budget_av = (struct budget_av *) ca->data;
-	struct saa7146_dev *saa = budget_av->budget.dev;
-	int result;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	/* test the card detect line - needs to be done carefully
-	 * since it never goes high for some CAMs on this interface (e.g. topuptv) */
-	if (budget_av->slot_status == SLOTSTATUS_NONE) {
-		saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
-		udelay(1);
-		if (saa7146_read(saa, PSR) & MASK_06) {
-			if (budget_av->slot_status == SLOTSTATUS_NONE) {
-				budget_av->slot_status = SLOTSTATUS_PRESENT;
-				pr_info("cam inserted A\n");
-			}
-		}
-		saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
-	}
-
-	/* We also try and read from IO memory to work round the above detection bug. If
-	 * there is no CAM, we will get a timeout. Only done if there is no cam
-	 * present, since this test actually breaks some cams :(
-	 *
-	 * if the CI interface is not open, we also do the above test since we
-	 * don't care if the cam has problems - we'll be resetting it on open() anyway */
-	if ((budget_av->slot_status == SLOTSTATUS_NONE) || (!open)) {
-		saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
-		result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1);
-		if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) {
-			budget_av->slot_status = SLOTSTATUS_PRESENT;
-			pr_info("cam inserted B\n");
-		} else if (result < 0) {
-			if (budget_av->slot_status != SLOTSTATUS_NONE) {
-				ciintf_slot_shutdown(ca, slot);
-				pr_info("cam ejected 5\n");
-				return 0;
-			}
-		}
-	}
-
-	/* read from attribute memory in reset/ready state to know when the CAM is ready */
-	if (budget_av->slot_status == SLOTSTATUS_RESET) {
-		result = ciintf_read_attribute_mem(ca, slot, 0);
-		if (result == 0x1d) {
-			budget_av->slot_status = SLOTSTATUS_READY;
-		}
-	}
-
-	/* work out correct return code */
-	if (budget_av->slot_status != SLOTSTATUS_NONE) {
-		if (budget_av->slot_status & SLOTSTATUS_READY) {
-			return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
-		}
-		return DVB_CA_EN50221_POLL_CAM_PRESENT;
-	}
-	return 0;
-}
-
-static int ciintf_init(struct budget_av *budget_av)
-{
-	struct saa7146_dev *saa = budget_av->budget.dev;
-	int result;
-
-	memset(&budget_av->ca, 0, sizeof(struct dvb_ca_en50221));
-
-	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
-	saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
-	saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO);
-	saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
-
-	/* Enable DEBI pins */
-	saa7146_write(saa, MC1, MASK_27 | MASK_11);
-
-	/* register CI interface */
-	budget_av->ca.owner = THIS_MODULE;
-	budget_av->ca.read_attribute_mem = ciintf_read_attribute_mem;
-	budget_av->ca.write_attribute_mem = ciintf_write_attribute_mem;
-	budget_av->ca.read_cam_control = ciintf_read_cam_control;
-	budget_av->ca.write_cam_control = ciintf_write_cam_control;
-	budget_av->ca.slot_reset = ciintf_slot_reset;
-	budget_av->ca.slot_shutdown = ciintf_slot_shutdown;
-	budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable;
-	budget_av->ca.poll_slot_status = ciintf_poll_slot_status;
-	budget_av->ca.data = budget_av;
-	budget_av->budget.ci_present = 1;
-	budget_av->slot_status = SLOTSTATUS_NONE;
-
-	if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter,
-					  &budget_av->ca, 0, 1)) != 0) {
-		pr_err("ci initialisation failed\n");
-		goto error;
-	}
-
-	pr_info("ci interface initialised\n");
-	return 0;
-
-error:
-	saa7146_write(saa, MC1, MASK_27);
-	return result;
-}
-
-static void ciintf_deinit(struct budget_av *budget_av)
-{
-	struct saa7146_dev *saa = budget_av->budget.dev;
-
-	saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
-	saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
-	saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
-	saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
-
-	/* release the CA device */
-	dvb_ca_en50221_release(&budget_av->ca);
-
-	/* disable DEBI pins */
-	saa7146_write(saa, MC1, MASK_27);
-}
-
-
-static const u8 saa7113_tab[] = {
-	0x01, 0x08,
-	0x02, 0xc0,
-	0x03, 0x33,
-	0x04, 0x00,
-	0x05, 0x00,
-	0x06, 0xeb,
-	0x07, 0xe0,
-	0x08, 0x28,
-	0x09, 0x00,
-	0x0a, 0x80,
-	0x0b, 0x47,
-	0x0c, 0x40,
-	0x0d, 0x00,
-	0x0e, 0x01,
-	0x0f, 0x44,
-
-	0x10, 0x08,
-	0x11, 0x0c,
-	0x12, 0x7b,
-	0x13, 0x00,
-	0x15, 0x00, 0x16, 0x00, 0x17, 0x00,
-
-	0x57, 0xff,
-	0x40, 0x82, 0x58, 0x00, 0x59, 0x54, 0x5a, 0x07,
-	0x5b, 0x83, 0x5e, 0x00,
-	0xff
-};
-
-static int saa7113_init(struct budget_av *budget_av)
-{
-	struct budget *budget = &budget_av->budget;
-	struct saa7146_dev *saa = budget->dev;
-	const u8 *data = saa7113_tab;
-
-	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI);
-	msleep(200);
-
-	if (i2c_writereg(&budget->i2c_adap, 0x4a, 0x01, 0x08) != 1) {
-		dprintk(1, "saa7113 not found on KNC card\n");
-		return -ENODEV;
-	}
-
-	dprintk(1, "saa7113 detected and initializing\n");
-
-	while (*data != 0xff) {
-		i2c_writereg(&budget->i2c_adap, 0x4a, *data, *(data + 1));
-		data += 2;
-	}
-
-	dprintk(1, "saa7113  status=%02x\n", i2c_readreg(&budget->i2c_adap, 0x4a, 0x1f));
-
-	return 0;
-}
-
-static int saa7113_setinput(struct budget_av *budget_av, int input)
-{
-	struct budget *budget = &budget_av->budget;
-
-	if (1 != budget_av->has_saa7113)
-		return -ENODEV;
-
-	if (input == 1) {
-		i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc7);
-		i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x80);
-	} else if (input == 0) {
-		i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc0);
-		i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x00);
-	} else
-		return -EINVAL;
-
-	budget_av->cur_input = input;
-	return 0;
-}
-
-
-static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
-{
-	u8 aclk = 0;
-	u8 bclk = 0;
-	u8 m1;
-
-	aclk = 0xb5;
-	if (srate < 2000000)
-		bclk = 0x86;
-	else if (srate < 5000000)
-		bclk = 0x89;
-	else if (srate < 15000000)
-		bclk = 0x8f;
-	else if (srate < 45000000)
-		bclk = 0x95;
-
-	m1 = 0x14;
-	if (srate < 4000000)
-		m1 = 0x10;
-
-	stv0299_writereg(fe, 0x13, aclk);
-	stv0299_writereg(fe, 0x14, bclk);
-	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
-	stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
-	stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
-	stv0299_writereg(fe, 0x0f, 0x80 | m1);
-
-	return 0;
-}
-
-static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	u32 div;
-	u8 buf[4];
-	struct budget *budget = (struct budget *) fe->dvb->priv;
-	struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
-
-	if ((c->frequency < 950000) || (c->frequency > 2150000))
-		return -EINVAL;
-
-	div = (c->frequency + (125 - 1)) / 125;	/* round correctly */
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = div & 0xff;
-	buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
-	buf[3] = 0x20;
-
-	if (c->symbol_rate < 4000000)
-		buf[3] |= 1;
-
-	if (c->frequency < 1250000)
-		buf[3] |= 0;
-	else if (c->frequency < 1550000)
-		buf[3] |= 0x40;
-	else if (c->frequency < 2050000)
-		buf[3] |= 0x80;
-	else if (c->frequency < 2150000)
-		buf[3] |= 0xC0;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-	return 0;
-}
-
-static u8 typhoon_cinergy1200s_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x30,
-	0x03, 0x00,
-	0x04, 0x7d,		/* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-	0x05, 0x35,		/* I2CT = 0, SCLT = 1, SDAT = 1 */
-	0x06, 0x40,		/* DAC not used, set to high impendance mode */
-	0x07, 0x00,		/* DAC LSB */
-	0x08, 0x40,		/* DiSEqC off */
-	0x09, 0x00,		/* FIFO */
-	0x0c, 0x51,		/* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
-	0x0d, 0x82,		/* DC offset compensation = ON, beta_agc1 = 2 */
-	0x0e, 0x23,		/* alpha_tmg = 2, beta_tmg = 3 */
-	0x10, 0x3f,		// AGC2  0x3d
-	0x11, 0x84,
-	0x12, 0xb9,
-	0x15, 0xc9,		// lock detector threshold
-	0x16, 0x00,
-	0x17, 0x00,
-	0x18, 0x00,
-	0x19, 0x00,
-	0x1a, 0x00,
-	0x1f, 0x50,
-	0x20, 0x00,
-	0x21, 0x00,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x28, 0x00,		// out imp: normal  out type: parallel FEC mode:0
-	0x29, 0x1e,		// 1/2 threshold
-	0x2a, 0x14,		// 2/3 threshold
-	0x2b, 0x0f,		// 3/4 threshold
-	0x2c, 0x09,		// 5/6 threshold
-	0x2d, 0x05,		// 7/8 threshold
-	0x2e, 0x01,
-	0x31, 0x1f,		// test all FECs
-	0x32, 0x19,		// viterbi and synchro search
-	0x33, 0xfc,		// rs control
-	0x34, 0x93,		// error control
-	0x0f, 0x92,
-	0xff, 0xff
-};
-
-static struct stv0299_config typhoon_config = {
-	.demod_address = 0x68,
-	.inittab = typhoon_cinergy1200s_inittab,
-	.mclk = 88000000UL,
-	.invert = 0,
-	.skip_reinit = 0,
-	.lock_output = STV0299_LOCKOUTPUT_1,
-	.volt13_op0_op1 = STV0299_VOLT13_OP0,
-	.min_delay_ms = 100,
-	.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
-};
-
-
-static struct stv0299_config cinergy_1200s_config = {
-	.demod_address = 0x68,
-	.inittab = typhoon_cinergy1200s_inittab,
-	.mclk = 88000000UL,
-	.invert = 0,
-	.skip_reinit = 0,
-	.lock_output = STV0299_LOCKOUTPUT_0,
-	.volt13_op0_op1 = STV0299_VOLT13_OP0,
-	.min_delay_ms = 100,
-	.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
-};
-
-static struct stv0299_config cinergy_1200s_1894_0010_config = {
-	.demod_address = 0x68,
-	.inittab = typhoon_cinergy1200s_inittab,
-	.mclk = 88000000UL,
-	.invert = 1,
-	.skip_reinit = 0,
-	.lock_output = STV0299_LOCKOUTPUT_1,
-	.volt13_op0_op1 = STV0299_VOLT13_OP0,
-	.min_delay_ms = 100,
-	.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
-};
-
-static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct budget *budget = (struct budget *) fe->dvb->priv;
-	u8 buf[6];
-	struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
-	int i;
-
-#define CU1216_IF 36125000
-#define TUNER_MUL 62500
-
-	u32 div = (c->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
-
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = div & 0xff;
-	buf[2] = 0xce;
-	buf[3] = (c->frequency < 150000000 ? 0x01 :
-		  c->frequency < 445000000 ? 0x02 : 0x04);
-	buf[4] = 0xde;
-	buf[5] = 0x20;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-
-	/* wait for the pll lock */
-	msg.flags = I2C_M_RD;
-	msg.len = 1;
-	for (i = 0; i < 20; i++) {
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-		if (i2c_transfer(&budget->i2c_adap, &msg, 1) == 1 && (buf[0] & 0x40))
-			break;
-		msleep(10);
-	}
-
-	/* switch the charge pump to the lower current */
-	msg.flags = 0;
-	msg.len = 2;
-	msg.buf = &buf[2];
-	buf[2] &= ~0x40;
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-
-	return 0;
-}
-
-static struct tda1002x_config philips_cu1216_config = {
-	.demod_address = 0x0c,
-	.invert = 1,
-};
-
-static struct tda1002x_config philips_cu1216_config_altaddress = {
-	.demod_address = 0x0d,
-	.invert = 0,
-};
-
-static struct tda10023_config philips_cu1216_tda10023_config = {
-	.demod_address = 0x0c,
-	.invert = 1,
-};
-
-static int philips_tu1216_tuner_init(struct dvb_frontend *fe)
-{
-	struct budget *budget = (struct budget *) fe->dvb->priv;
-	static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
-	struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
-
-	// setup PLL configuration
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
-		return -EIO;
-	msleep(1);
-
-	return 0;
-}
-
-static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct budget *budget = (struct budget *) fe->dvb->priv;
-	u8 tuner_buf[4];
-	struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len =
-			sizeof(tuner_buf) };
-	int tuner_frequency = 0;
-	u8 band, cp, filter;
-
-	// determine charge pump
-	tuner_frequency = c->frequency + 36166000;
-	if (tuner_frequency < 87000000)
-		return -EINVAL;
-	else if (tuner_frequency < 130000000)
-		cp = 3;
-	else if (tuner_frequency < 160000000)
-		cp = 5;
-	else if (tuner_frequency < 200000000)
-		cp = 6;
-	else if (tuner_frequency < 290000000)
-		cp = 3;
-	else if (tuner_frequency < 420000000)
-		cp = 5;
-	else if (tuner_frequency < 480000000)
-		cp = 6;
-	else if (tuner_frequency < 620000000)
-		cp = 3;
-	else if (tuner_frequency < 830000000)
-		cp = 5;
-	else if (tuner_frequency < 895000000)
-		cp = 7;
-	else
-		return -EINVAL;
-
-	// determine band
-	if (c->frequency < 49000000)
-		return -EINVAL;
-	else if (c->frequency < 161000000)
-		band = 1;
-	else if (c->frequency < 444000000)
-		band = 2;
-	else if (c->frequency < 861000000)
-		band = 4;
-	else
-		return -EINVAL;
-
-	// setup PLL filter
-	switch (c->bandwidth_hz) {
-	case 6000000:
-		filter = 0;
-		break;
-
-	case 7000000:
-		filter = 0;
-		break;
-
-	case 8000000:
-		filter = 1;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	// calculate divisor
-	// ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
-	tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000;
-
-	// setup tuner buffer
-	tuner_buf[0] = (tuner_frequency >> 8) & 0x7f;
-	tuner_buf[1] = tuner_frequency & 0xff;
-	tuner_buf[2] = 0xca;
-	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
-		return -EIO;
-
-	msleep(1);
-	return 0;
-}
-
-static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
-					   const struct firmware **fw, char *name)
-{
-	struct budget *budget = (struct budget *) fe->dvb->priv;
-
-	return request_firmware(fw, name, &budget->dev->pci->dev);
-}
-
-static struct tda1004x_config philips_tu1216_config = {
-
-	.demod_address = 0x8,
-	.invert = 1,
-	.invert_oclk = 1,
-	.xtal_freq = TDA10046_XTAL_4M,
-	.agc_config = TDA10046_AGC_DEFAULT,
-	.if_freq = TDA10046_FREQ_3617,
-	.request_firmware = philips_tu1216_request_firmware,
-};
-
-static u8 philips_sd1878_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x30,
-	0x03, 0x00,
-	0x04, 0x7d,
-	0x05, 0x35,
-	0x06, 0x40,
-	0x07, 0x00,
-	0x08, 0x43,
-	0x09, 0x02,
-	0x0C, 0x51,
-	0x0D, 0x82,
-	0x0E, 0x23,
-	0x10, 0x3f,
-	0x11, 0x84,
-	0x12, 0xb9,
-	0x15, 0xc9,
-	0x16, 0x19,
-	0x17, 0x8c,
-	0x18, 0x59,
-	0x19, 0xf8,
-	0x1a, 0xfe,
-	0x1c, 0x7f,
-	0x1d, 0x00,
-	0x1e, 0x00,
-	0x1f, 0x50,
-	0x20, 0x00,
-	0x21, 0x00,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x28, 0x00,
-	0x29, 0x28,
-	0x2a, 0x14,
-	0x2b, 0x0f,
-	0x2c, 0x09,
-	0x2d, 0x09,
-	0x31, 0x1f,
-	0x32, 0x19,
-	0x33, 0xfc,
-	0x34, 0x93,
-	0xff, 0xff
-};
-
-static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe,
-		u32 srate, u32 ratio)
-{
-	u8 aclk = 0;
-	u8 bclk = 0;
-	u8 m1;
-
-	aclk = 0xb5;
-	if (srate < 2000000)
-		bclk = 0x86;
-	else if (srate < 5000000)
-		bclk = 0x89;
-	else if (srate < 15000000)
-		bclk = 0x8f;
-	else if (srate < 45000000)
-		bclk = 0x95;
-
-	m1 = 0x14;
-	if (srate < 4000000)
-		m1 = 0x10;
-
-	stv0299_writereg(fe, 0x0e, 0x23);
-	stv0299_writereg(fe, 0x0f, 0x94);
-	stv0299_writereg(fe, 0x10, 0x39);
-	stv0299_writereg(fe, 0x13, aclk);
-	stv0299_writereg(fe, 0x14, bclk);
-	stv0299_writereg(fe, 0x15, 0xc9);
-	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
-	stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
-	stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
-	stv0299_writereg(fe, 0x0f, 0x80 | m1);
-
-	return 0;
-}
-
-static struct stv0299_config philips_sd1878_config = {
-	.demod_address = 0x68,
-     .inittab = philips_sd1878_inittab,
-	.mclk = 88000000UL,
-	.invert = 0,
-	.skip_reinit = 0,
-	.lock_output = STV0299_LOCKOUTPUT_1,
-	.volt13_op0_op1 = STV0299_VOLT13_OP0,
-	.min_delay_ms = 100,
-	.set_symbol_rate = philips_sd1878_ci_set_symbol_rate,
-};
-
-/* KNC1 DVB-S (STB0899) Inittab	*/
-static const struct stb0899_s1_reg knc1_stb0899_s1_init_1[] = {
-
-	{ STB0899_DEV_ID		, 0x81 },
-	{ STB0899_DISCNTRL1		, 0x32 },
-	{ STB0899_DISCNTRL2		, 0x80 },
-	{ STB0899_DISRX_ST0		, 0x04 },
-	{ STB0899_DISRX_ST1		, 0x00 },
-	{ STB0899_DISPARITY		, 0x00 },
-	{ STB0899_DISSTATUS		, 0x20 },
-	{ STB0899_DISF22		, 0x8c },
-	{ STB0899_DISF22RX		, 0x9a },
-	{ STB0899_SYSREG		, 0x0b },
-	{ STB0899_ACRPRESC		, 0x11 },
-	{ STB0899_ACRDIV1		, 0x0a },
-	{ STB0899_ACRDIV2		, 0x05 },
-	{ STB0899_DACR1			, 0x00 },
-	{ STB0899_DACR2			, 0x00 },
-	{ STB0899_OUTCFG		, 0x00 },
-	{ STB0899_MODECFG		, 0x00 },
-	{ STB0899_IRQSTATUS_3		, 0x30 },
-	{ STB0899_IRQSTATUS_2		, 0x00 },
-	{ STB0899_IRQSTATUS_1		, 0x00 },
-	{ STB0899_IRQSTATUS_0		, 0x00 },
-	{ STB0899_IRQMSK_3		, 0xf3 },
-	{ STB0899_IRQMSK_2		, 0xfc },
-	{ STB0899_IRQMSK_1		, 0xff },
-	{ STB0899_IRQMSK_0		, 0xff },
-	{ STB0899_IRQCFG		, 0x00 },
-	{ STB0899_I2CCFG		, 0x88 },
-	{ STB0899_I2CRPT		, 0x58 }, /* Repeater=8, Stop=disabled */
-	{ STB0899_IOPVALUE5		, 0x00 },
-	{ STB0899_IOPVALUE4		, 0x20 },
-	{ STB0899_IOPVALUE3		, 0xc9 },
-	{ STB0899_IOPVALUE2		, 0x90 },
-	{ STB0899_IOPVALUE1		, 0x40 },
-	{ STB0899_IOPVALUE0		, 0x00 },
-	{ STB0899_GPIO00CFG		, 0x82 },
-	{ STB0899_GPIO01CFG		, 0x82 },
-	{ STB0899_GPIO02CFG		, 0x82 },
-	{ STB0899_GPIO03CFG		, 0x82 },
-	{ STB0899_GPIO04CFG		, 0x82 },
-	{ STB0899_GPIO05CFG		, 0x82 },
-	{ STB0899_GPIO06CFG		, 0x82 },
-	{ STB0899_GPIO07CFG		, 0x82 },
-	{ STB0899_GPIO08CFG		, 0x82 },
-	{ STB0899_GPIO09CFG		, 0x82 },
-	{ STB0899_GPIO10CFG		, 0x82 },
-	{ STB0899_GPIO11CFG		, 0x82 },
-	{ STB0899_GPIO12CFG		, 0x82 },
-	{ STB0899_GPIO13CFG		, 0x82 },
-	{ STB0899_GPIO14CFG		, 0x82 },
-	{ STB0899_GPIO15CFG		, 0x82 },
-	{ STB0899_GPIO16CFG		, 0x82 },
-	{ STB0899_GPIO17CFG		, 0x82 },
-	{ STB0899_GPIO18CFG		, 0x82 },
-	{ STB0899_GPIO19CFG		, 0x82 },
-	{ STB0899_GPIO20CFG		, 0x82 },
-	{ STB0899_SDATCFG		, 0xb8 },
-	{ STB0899_SCLTCFG		, 0xba },
-	{ STB0899_AGCRFCFG		, 0x08 }, /* 0x1c */
-	{ STB0899_GPIO22		, 0x82 }, /* AGCBB2CFG */
-	{ STB0899_GPIO21		, 0x91 }, /* AGCBB1CFG */
-	{ STB0899_DIRCLKCFG		, 0x82 },
-	{ STB0899_CLKOUT27CFG		, 0x7e },
-	{ STB0899_STDBYCFG		, 0x82 },
-	{ STB0899_CS0CFG		, 0x82 },
-	{ STB0899_CS1CFG		, 0x82 },
-	{ STB0899_DISEQCOCFG		, 0x20 },
-	{ STB0899_GPIO32CFG		, 0x82 },
-	{ STB0899_GPIO33CFG		, 0x82 },
-	{ STB0899_GPIO34CFG		, 0x82 },
-	{ STB0899_GPIO35CFG		, 0x82 },
-	{ STB0899_GPIO36CFG		, 0x82 },
-	{ STB0899_GPIO37CFG		, 0x82 },
-	{ STB0899_GPIO38CFG		, 0x82 },
-	{ STB0899_GPIO39CFG		, 0x82 },
-	{ STB0899_NCOARSE		, 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
-	{ STB0899_SYNTCTRL		, 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
-	{ STB0899_FILTCTRL		, 0x00 },
-	{ STB0899_SYSCTRL		, 0x00 },
-	{ STB0899_STOPCLK1		, 0x20 },
-	{ STB0899_STOPCLK2		, 0x00 },
-	{ STB0899_INTBUFSTATUS		, 0x00 },
-	{ STB0899_INTBUFCTRL		, 0x0a },
-	{ 0xffff			, 0xff },
-};
-
-static const struct stb0899_s1_reg knc1_stb0899_s1_init_3[] = {
-	{ STB0899_DEMOD			, 0x00 },
-	{ STB0899_RCOMPC		, 0xc9 },
-	{ STB0899_AGC1CN		, 0x41 },
-	{ STB0899_AGC1REF		, 0x08 },
-	{ STB0899_RTC			, 0x7a },
-	{ STB0899_TMGCFG		, 0x4e },
-	{ STB0899_AGC2REF		, 0x33 },
-	{ STB0899_TLSR			, 0x84 },
-	{ STB0899_CFD			, 0xee },
-	{ STB0899_ACLC			, 0x87 },
-	{ STB0899_BCLC			, 0x94 },
-	{ STB0899_EQON			, 0x41 },
-	{ STB0899_LDT			, 0xdd },
-	{ STB0899_LDT2			, 0xc9 },
-	{ STB0899_EQUALREF		, 0xb4 },
-	{ STB0899_TMGRAMP		, 0x10 },
-	{ STB0899_TMGTHD		, 0x30 },
-	{ STB0899_IDCCOMP		, 0xfb },
-	{ STB0899_QDCCOMP		, 0x03 },
-	{ STB0899_POWERI		, 0x3b },
-	{ STB0899_POWERQ		, 0x3d },
-	{ STB0899_RCOMP			, 0x81 },
-	{ STB0899_AGCIQIN		, 0x80 },
-	{ STB0899_AGC2I1		, 0x04 },
-	{ STB0899_AGC2I2		, 0xf5 },
-	{ STB0899_TLIR			, 0x25 },
-	{ STB0899_RTF			, 0x80 },
-	{ STB0899_DSTATUS		, 0x00 },
-	{ STB0899_LDI			, 0xca },
-	{ STB0899_CFRM			, 0xf1 },
-	{ STB0899_CFRL			, 0xf3 },
-	{ STB0899_NIRM			, 0x2a },
-	{ STB0899_NIRL			, 0x05 },
-	{ STB0899_ISYMB			, 0x17 },
-	{ STB0899_QSYMB			, 0xfa },
-	{ STB0899_SFRH			, 0x2f },
-	{ STB0899_SFRM			, 0x68 },
-	{ STB0899_SFRL			, 0x40 },
-	{ STB0899_SFRUPH		, 0x2f },
-	{ STB0899_SFRUPM		, 0x68 },
-	{ STB0899_SFRUPL		, 0x40 },
-	{ STB0899_EQUAI1		, 0xfd },
-	{ STB0899_EQUAQ1		, 0x04 },
-	{ STB0899_EQUAI2		, 0x0f },
-	{ STB0899_EQUAQ2		, 0xff },
-	{ STB0899_EQUAI3		, 0xdf },
-	{ STB0899_EQUAQ3		, 0xfa },
-	{ STB0899_EQUAI4		, 0x37 },
-	{ STB0899_EQUAQ4		, 0x0d },
-	{ STB0899_EQUAI5		, 0xbd },
-	{ STB0899_EQUAQ5		, 0xf7 },
-	{ STB0899_DSTATUS2		, 0x00 },
-	{ STB0899_VSTATUS		, 0x00 },
-	{ STB0899_VERROR		, 0xff },
-	{ STB0899_IQSWAP		, 0x2a },
-	{ STB0899_ECNT1M		, 0x00 },
-	{ STB0899_ECNT1L		, 0x00 },
-	{ STB0899_ECNT2M		, 0x00 },
-	{ STB0899_ECNT2L		, 0x00 },
-	{ STB0899_ECNT3M		, 0x00 },
-	{ STB0899_ECNT3L		, 0x00 },
-	{ STB0899_FECAUTO1		, 0x06 },
-	{ STB0899_FECM			, 0x01 },
-	{ STB0899_VTH12			, 0xf0 },
-	{ STB0899_VTH23			, 0xa0 },
-	{ STB0899_VTH34			, 0x78 },
-	{ STB0899_VTH56			, 0x4e },
-	{ STB0899_VTH67			, 0x48 },
-	{ STB0899_VTH78			, 0x38 },
-	{ STB0899_PRVIT			, 0xff },
-	{ STB0899_VITSYNC		, 0x19 },
-	{ STB0899_RSULC			, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
-	{ STB0899_TSULC			, 0x42 },
-	{ STB0899_RSLLC			, 0x40 },
-	{ STB0899_TSLPL			, 0x12 },
-	{ STB0899_TSCFGH		, 0x0c },
-	{ STB0899_TSCFGM		, 0x00 },
-	{ STB0899_TSCFGL		, 0x0c },
-	{ STB0899_TSOUT			, 0x4d }, /* 0x0d for CAM */
-	{ STB0899_RSSYNCDEL		, 0x00 },
-	{ STB0899_TSINHDELH		, 0x02 },
-	{ STB0899_TSINHDELM		, 0x00 },
-	{ STB0899_TSINHDELL		, 0x00 },
-	{ STB0899_TSLLSTKM		, 0x00 },
-	{ STB0899_TSLLSTKL		, 0x00 },
-	{ STB0899_TSULSTKM		, 0x00 },
-	{ STB0899_TSULSTKL		, 0xab },
-	{ STB0899_PCKLENUL		, 0x00 },
-	{ STB0899_PCKLENLL		, 0xcc },
-	{ STB0899_RSPCKLEN		, 0xcc },
-	{ STB0899_TSSTATUS		, 0x80 },
-	{ STB0899_ERRCTRL1		, 0xb6 },
-	{ STB0899_ERRCTRL2		, 0x96 },
-	{ STB0899_ERRCTRL3		, 0x89 },
-	{ STB0899_DMONMSK1		, 0x27 },
-	{ STB0899_DMONMSK0		, 0x03 },
-	{ STB0899_DEMAPVIT		, 0x5c },
-	{ STB0899_PLPARM		, 0x1f },
-	{ STB0899_PDELCTRL		, 0x48 },
-	{ STB0899_PDELCTRL2		, 0x00 },
-	{ STB0899_BBHCTRL1		, 0x00 },
-	{ STB0899_BBHCTRL2		, 0x00 },
-	{ STB0899_HYSTTHRESH		, 0x77 },
-	{ STB0899_MATCSTM		, 0x00 },
-	{ STB0899_MATCSTL		, 0x00 },
-	{ STB0899_UPLCSTM		, 0x00 },
-	{ STB0899_UPLCSTL		, 0x00 },
-	{ STB0899_DFLCSTM		, 0x00 },
-	{ STB0899_DFLCSTL		, 0x00 },
-	{ STB0899_SYNCCST		, 0x00 },
-	{ STB0899_SYNCDCSTM		, 0x00 },
-	{ STB0899_SYNCDCSTL		, 0x00 },
-	{ STB0899_ISI_ENTRY		, 0x00 },
-	{ STB0899_ISI_BIT_EN		, 0x00 },
-	{ STB0899_MATSTRM		, 0x00 },
-	{ STB0899_MATSTRL		, 0x00 },
-	{ STB0899_UPLSTRM		, 0x00 },
-	{ STB0899_UPLSTRL		, 0x00 },
-	{ STB0899_DFLSTRM		, 0x00 },
-	{ STB0899_DFLSTRL		, 0x00 },
-	{ STB0899_SYNCSTR		, 0x00 },
-	{ STB0899_SYNCDSTRM		, 0x00 },
-	{ STB0899_SYNCDSTRL		, 0x00 },
-	{ STB0899_CFGPDELSTATUS1	, 0x10 },
-	{ STB0899_CFGPDELSTATUS2	, 0x00 },
-	{ STB0899_BBFERRORM		, 0x00 },
-	{ STB0899_BBFERRORL		, 0x00 },
-	{ STB0899_UPKTERRORM		, 0x00 },
-	{ STB0899_UPKTERRORL		, 0x00 },
-	{ 0xffff			, 0xff },
-};
-
-/* STB0899 demodulator config for the KNC1 and clones */
-static struct stb0899_config knc1_dvbs2_config = {
-	.init_dev		= knc1_stb0899_s1_init_1,
-	.init_s2_demod		= stb0899_s2_init_2,
-	.init_s1_demod		= knc1_stb0899_s1_init_3,
-	.init_s2_fec		= stb0899_s2_init_4,
-	.init_tst		= stb0899_s1_init_5,
-
-	.postproc		= NULL,
-
-	.demod_address		= 0x68,
-//	.ts_output_mode		= STB0899_OUT_PARALLEL,	/* types = SERIAL/PARALLEL	*/
-	.block_sync_mode	= STB0899_SYNC_FORCED,	/* DSS, SYNC_FORCED/UNSYNCED	*/
-//	.ts_pfbit_toggle	= STB0899_MPEG_NORMAL,	/* DirecTV, MPEG toggling seq	*/
-
-	.xtal_freq		= 27000000,
-	.inversion		= IQ_SWAP_OFF, /* 1 */
-
-	.lo_clk			= 76500000,
-	.hi_clk			= 90000000,
-
-	.esno_ave		= STB0899_DVBS2_ESNO_AVE,
-	.esno_quant		= STB0899_DVBS2_ESNO_QUANT,
-	.avframes_coarse	= STB0899_DVBS2_AVFRAMES_COARSE,
-	.avframes_fine		= STB0899_DVBS2_AVFRAMES_FINE,
-	.miss_threshold		= STB0899_DVBS2_MISS_THRESHOLD,
-	.uwp_threshold_acq	= STB0899_DVBS2_UWP_THRESHOLD_ACQ,
-	.uwp_threshold_track	= STB0899_DVBS2_UWP_THRESHOLD_TRACK,
-	.uwp_threshold_sof	= STB0899_DVBS2_UWP_THRESHOLD_SOF,
-	.sof_search_timeout	= STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
-
-	.btr_nco_bits		= STB0899_DVBS2_BTR_NCO_BITS,
-	.btr_gain_shift_offset	= STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
-	.crl_nco_bits		= STB0899_DVBS2_CRL_NCO_BITS,
-	.ldpc_max_iter		= STB0899_DVBS2_LDPC_MAX_ITER,
-
-	.tuner_get_frequency	= tda8261_get_frequency,
-	.tuner_set_frequency	= tda8261_set_frequency,
-	.tuner_set_bandwidth	= NULL,
-	.tuner_get_bandwidth	= tda8261_get_bandwidth,
-	.tuner_set_rfsiggain	= NULL
-};
-
-/*
- * SD1878/SHA tuner config
- * 1F, Single I/P, Horizontal mount, High Sensitivity
- */
-static const struct tda8261_config sd1878c_config = {
-//	.name		= "SD1878/SHA",
-	.addr		= 0x60,
-	.step_size	= TDA8261_STEP_1000 /* kHz */
-};
-
-static u8 read_pwm(struct budget_av *budget_av)
-{
-	u8 b = 0xff;
-	u8 pwm;
-	struct i2c_msg msg[] = { {.addr = 0x50,.flags = 0,.buf = &b,.len = 1},
-	{.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1}
-	};
-
-	if ((i2c_transfer(&budget_av->budget.i2c_adap, msg, 2) != 2)
-	    || (pwm == 0xff))
-		pwm = 0x48;
-
-	return pwm;
-}
-
-#define SUBID_DVBS_KNC1			0x0010
-#define SUBID_DVBS_KNC1_PLUS		0x0011
-#define SUBID_DVBS_TYPHOON		0x4f56
-#define SUBID_DVBS_CINERGY1200		0x1154
-#define SUBID_DVBS_CYNERGY1200N 	0x1155
-#define SUBID_DVBS_TV_STAR		0x0014
-#define SUBID_DVBS_TV_STAR_PLUS_X4	0x0015
-#define SUBID_DVBS_TV_STAR_CI		0x0016
-#define SUBID_DVBS2_KNC1		0x0018
-#define SUBID_DVBS2_KNC1_OEM		0x0019
-#define SUBID_DVBS_EASYWATCH_1  	0x001a
-#define SUBID_DVBS_EASYWATCH_2  	0x001b
-#define SUBID_DVBS2_EASYWATCH		0x001d
-#define SUBID_DVBS_EASYWATCH		0x001e
-
-#define SUBID_DVBC_EASYWATCH		0x002a
-#define SUBID_DVBC_EASYWATCH_MK3	0x002c
-#define SUBID_DVBC_KNC1			0x0020
-#define SUBID_DVBC_KNC1_PLUS		0x0021
-#define SUBID_DVBC_KNC1_MK3		0x0022
-#define SUBID_DVBC_KNC1_TDA10024	0x0028
-#define SUBID_DVBC_KNC1_PLUS_MK3	0x0023
-#define SUBID_DVBC_CINERGY1200		0x1156
-#define SUBID_DVBC_CINERGY1200_MK3	0x1176
-
-#define SUBID_DVBT_EASYWATCH		0x003a
-#define SUBID_DVBT_KNC1_PLUS		0x0031
-#define SUBID_DVBT_KNC1			0x0030
-#define SUBID_DVBT_CINERGY1200		0x1157
-
-static void frontend_init(struct budget_av *budget_av)
-{
-	struct saa7146_dev * saa = budget_av->budget.dev;
-	struct dvb_frontend * fe = NULL;
-
-	/* Enable / PowerON Frontend */
-	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
-
-	/* Wait for PowerON */
-	msleep(100);
-
-	/* additional setup necessary for the PLUS cards */
-	switch (saa->pci->subsystem_device) {
-		case SUBID_DVBS_KNC1_PLUS:
-		case SUBID_DVBC_KNC1_PLUS:
-		case SUBID_DVBT_KNC1_PLUS:
-		case SUBID_DVBC_EASYWATCH:
-		case SUBID_DVBC_KNC1_PLUS_MK3:
-		case SUBID_DVBS2_KNC1:
-		case SUBID_DVBS2_KNC1_OEM:
-		case SUBID_DVBS2_EASYWATCH:
-			saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
-			break;
-	}
-
-	switch (saa->pci->subsystem_device) {
-
-	case SUBID_DVBS_KNC1:
-		/*
-		 * maybe that setting is needed for other dvb-s cards as well,
-		 * but so far it has been only confirmed for this type
-		 */
-		budget_av->reinitialise_demod = 1;
-		/* fall through */
-	case SUBID_DVBS_KNC1_PLUS:
-	case SUBID_DVBS_EASYWATCH_1:
-		if (saa->pci->subsystem_vendor == 0x1894) {
-			fe = dvb_attach(stv0299_attach, &cinergy_1200s_1894_0010_config,
-					     &budget_av->budget.i2c_adap);
-			if (fe) {
-				dvb_attach(tua6100_attach, fe, 0x60, &budget_av->budget.i2c_adap);
-			}
-		} else {
-			fe = dvb_attach(stv0299_attach, &typhoon_config,
-					     &budget_av->budget.i2c_adap);
-			if (fe) {
-				fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
-			}
-		}
-		break;
-
-	case SUBID_DVBS_TV_STAR:
-	case SUBID_DVBS_TV_STAR_PLUS_X4:
-	case SUBID_DVBS_TV_STAR_CI:
-	case SUBID_DVBS_CYNERGY1200N:
-	case SUBID_DVBS_EASYWATCH:
-	case SUBID_DVBS_EASYWATCH_2:
-		fe = dvb_attach(stv0299_attach, &philips_sd1878_config,
-				&budget_av->budget.i2c_adap);
-		if (fe) {
-			dvb_attach(dvb_pll_attach, fe, 0x60,
-				   &budget_av->budget.i2c_adap,
-				   DVB_PLL_PHILIPS_SD1878_TDA8261);
-		}
-		break;
-
-	case SUBID_DVBS_TYPHOON:
-		fe = dvb_attach(stv0299_attach, &typhoon_config,
-				    &budget_av->budget.i2c_adap);
-		if (fe) {
-			fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
-		}
-		break;
-	case SUBID_DVBS2_KNC1:
-	case SUBID_DVBS2_KNC1_OEM:
-	case SUBID_DVBS2_EASYWATCH:
-		budget_av->reinitialise_demod = 1;
-		if ((fe = dvb_attach(stb0899_attach, &knc1_dvbs2_config, &budget_av->budget.i2c_adap)))
-			dvb_attach(tda8261_attach, fe, &sd1878c_config, &budget_av->budget.i2c_adap);
-
-		break;
-	case SUBID_DVBS_CINERGY1200:
-		fe = dvb_attach(stv0299_attach, &cinergy_1200s_config,
-				    &budget_av->budget.i2c_adap);
-		if (fe) {
-			fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
-		}
-		break;
-
-	case SUBID_DVBC_KNC1:
-	case SUBID_DVBC_KNC1_PLUS:
-	case SUBID_DVBC_CINERGY1200:
-	case SUBID_DVBC_EASYWATCH:
-		budget_av->reinitialise_demod = 1;
-		budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
-		fe = dvb_attach(tda10021_attach, &philips_cu1216_config,
-				     &budget_av->budget.i2c_adap,
-				     read_pwm(budget_av));
-		if (fe == NULL)
-			fe = dvb_attach(tda10021_attach, &philips_cu1216_config_altaddress,
-					     &budget_av->budget.i2c_adap,
-					     read_pwm(budget_av));
-		if (fe) {
-			fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
-		}
-		break;
-
-	case SUBID_DVBC_EASYWATCH_MK3:
-	case SUBID_DVBC_CINERGY1200_MK3:
-	case SUBID_DVBC_KNC1_MK3:
-	case SUBID_DVBC_KNC1_TDA10024:
-	case SUBID_DVBC_KNC1_PLUS_MK3:
-		budget_av->reinitialise_demod = 1;
-		budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
-		fe = dvb_attach(tda10023_attach,
-			&philips_cu1216_tda10023_config,
-			&budget_av->budget.i2c_adap,
-			read_pwm(budget_av));
-		if (fe) {
-			fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
-		}
-		break;
-
-	case SUBID_DVBT_EASYWATCH:
-	case SUBID_DVBT_KNC1:
-	case SUBID_DVBT_KNC1_PLUS:
-	case SUBID_DVBT_CINERGY1200:
-		budget_av->reinitialise_demod = 1;
-		fe = dvb_attach(tda10046_attach, &philips_tu1216_config,
-				     &budget_av->budget.i2c_adap);
-		if (fe) {
-			fe->ops.tuner_ops.init = philips_tu1216_tuner_init;
-			fe->ops.tuner_ops.set_params = philips_tu1216_tuner_set_params;
-		}
-		break;
-	}
-
-	if (fe == NULL) {
-		pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
-		       saa->pci->vendor,
-		       saa->pci->device,
-		       saa->pci->subsystem_vendor,
-		       saa->pci->subsystem_device);
-		return;
-	}
-
-	budget_av->budget.dvb_frontend = fe;
-
-	if (dvb_register_frontend(&budget_av->budget.dvb_adapter,
-				  budget_av->budget.dvb_frontend)) {
-		pr_err("Frontend registration failed!\n");
-		dvb_frontend_detach(budget_av->budget.dvb_frontend);
-		budget_av->budget.dvb_frontend = NULL;
-	}
-}
-
-
-static void budget_av_irq(struct saa7146_dev *dev, u32 * isr)
-{
-	struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
-
-	dprintk(8, "dev: %p, budget_av: %p\n", dev, budget_av);
-
-	if (*isr & MASK_10)
-		ttpci_budget_irq10_handler(dev, isr);
-}
-
-static int budget_av_detach(struct saa7146_dev *dev)
-{
-	struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
-	int err;
-
-	dprintk(2, "dev: %p\n", dev);
-
-	if (1 == budget_av->has_saa7113) {
-		saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO);
-
-		msleep(200);
-
-		saa7146_unregister_device(&budget_av->vd, dev);
-
-		saa7146_vv_release(dev);
-	}
-
-	if (budget_av->budget.ci_present)
-		ciintf_deinit(budget_av);
-
-	if (budget_av->budget.dvb_frontend != NULL) {
-		dvb_unregister_frontend(budget_av->budget.dvb_frontend);
-		dvb_frontend_detach(budget_av->budget.dvb_frontend);
-	}
-	err = ttpci_budget_deinit(&budget_av->budget);
-
-	kfree(budget_av);
-
-	return err;
-}
-
-#define KNC1_INPUTS 2
-static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
-	{ 0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0,
-		V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-	{ 1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0,
-		V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
-};
-
-static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
-{
-	dprintk(1, "VIDIOC_ENUMINPUT %d\n", i->index);
-	if (i->index >= KNC1_INPUTS)
-		return -EINVAL;
-	memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
-	return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct budget_av *budget_av = (struct budget_av *)dev->ext_priv;
-
-	*i = budget_av->cur_input;
-
-	dprintk(1, "VIDIOC_G_INPUT %d\n", *i);
-	return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
-{
-	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
-	struct budget_av *budget_av = (struct budget_av *)dev->ext_priv;
-
-	dprintk(1, "VIDIOC_S_INPUT %d\n", input);
-	return saa7113_setinput(budget_av, input);
-}
-
-static struct saa7146_ext_vv vv_data;
-
-static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
-{
-	struct budget_av *budget_av;
-	u8 *mac;
-	int err;
-
-	dprintk(2, "dev: %p\n", dev);
-
-	if (!(budget_av = kzalloc(sizeof(struct budget_av), GFP_KERNEL)))
-		return -ENOMEM;
-
-	budget_av->has_saa7113 = 0;
-	budget_av->budget.ci_present = 0;
-
-	dev->ext_priv = budget_av;
-
-	err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE,
-				adapter_nr);
-	if (err) {
-		kfree(budget_av);
-		return err;
-	}
-
-	/* knc1 initialization */
-	saa7146_write(dev, DD1_STREAM_B, 0x04000000);
-	saa7146_write(dev, DD1_INIT, 0x07000600);
-	saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26);
-
-	if (saa7113_init(budget_av) == 0) {
-		budget_av->has_saa7113 = 1;
-
-		if (0 != saa7146_vv_init(dev, &vv_data)) {
-			/* fixme: proper cleanup here */
-			ERR("cannot init vv subsystem\n");
-			return err;
-		}
-		vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
-		vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
-		vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
-
-		if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
-			/* fixme: proper cleanup here */
-			ERR("cannot register capture v4l2 device\n");
-			saa7146_vv_release(dev);
-			return err;
-		}
-
-		/* beware: this modifies dev->vv ... */
-		saa7146_set_hps_source_and_sync(dev, SAA7146_HPS_SOURCE_PORT_A,
-						SAA7146_HPS_SYNC_PORT_A);
-
-		saa7113_setinput(budget_av, 0);
-	}
-
-	/* fixme: find some sane values here... */
-	saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
-
-	mac = budget_av->budget.dvb_adapter.proposed_mac;
-	if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) {
-		pr_err("KNC1-%d: Could not read MAC from KNC1 card\n",
-		       budget_av->budget.dvb_adapter.num);
-		memset(mac, 0, 6);
-	} else {
-		pr_info("KNC1-%d: MAC addr = %pM\n",
-			budget_av->budget.dvb_adapter.num, mac);
-	}
-
-	budget_av->budget.dvb_adapter.priv = budget_av;
-	frontend_init(budget_av);
-	ciintf_init(budget_av);
-
-	ttpci_budget_init_hooks(&budget_av->budget);
-
-	return 0;
-}
-
-static struct saa7146_standard standard[] = {
-	{.name = "PAL",.id = V4L2_STD_PAL,
-	 .v_offset = 0x17,.v_field = 288,
-	 .h_offset = 0x14,.h_pixels = 680,
-	 .v_max_out = 576,.h_max_out = 768 },
-
-	{.name = "NTSC",.id = V4L2_STD_NTSC,
-	 .v_offset = 0x16,.v_field = 240,
-	 .h_offset = 0x06,.h_pixels = 708,
-	 .v_max_out = 480,.h_max_out = 640, },
-};
-
-static struct saa7146_ext_vv vv_data = {
-	.inputs = 2,
-	.capabilities = 0,	// perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113
-	.flags = 0,
-	.stds = &standard[0],
-	.num_stds = ARRAY_SIZE(standard),
-};
-
-static struct saa7146_extension budget_extension;
-
-MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S);
-MAKE_BUDGET_INFO(knc1s2,"KNC1 DVB-S2", BUDGET_KNC1S2);
-MAKE_BUDGET_INFO(sates2,"Satelco EasyWatch DVB-S2", BUDGET_KNC1S2);
-MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);
-MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
-MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
-MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
-MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
-MAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S);
-MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP);
-MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3);
-MAKE_BUDGET_INFO(satewt, "Satelco EasyWatch DVB-T", BUDGET_KNC1T);
-MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
-MAKE_BUDGET_INFO(knc1spx4, "KNC1 DVB-S Plus X4", BUDGET_KNC1SP);
-MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
-MAKE_BUDGET_INFO(knc1cmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3);
-MAKE_BUDGET_INFO(knc1ctda10024, "KNC1 DVB-C TDA10024", BUDGET_KNC1C_TDA10024);
-MAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C Plus MK3", BUDGET_KNC1CP_MK3);
-MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
-MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
-MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
-MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C);
-MAKE_BUDGET_INFO(cin1200cmk3, "Terratec Cinergy 1200 DVB-C MK3", BUDGET_CIN1200C_MK3);
-MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);
-
-static struct pci_device_id pci_tbl[] = {
-	MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56),
-	MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010),
-	MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010),
-	MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),
-	MAKE_EXTENSION_PCI(knc1sp, 0x1894, 0x0011),
-	MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
-	MAKE_EXTENSION_PCI(knc1spx4, 0x1894, 0x0015),
-	MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
-	MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0018),
-	MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0019),
-	MAKE_EXTENSION_PCI(sates2, 0x1894, 0x001d),
-	MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
-	MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
-	MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b),
-	MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a),
-	MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c),
-	MAKE_EXTENSION_PCI(satewt, 0x1894, 0x003a),
-	MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
-	MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
-	MAKE_EXTENSION_PCI(knc1cmk3, 0x1894, 0x0022),
-	MAKE_EXTENSION_PCI(knc1ctda10024, 0x1894, 0x0028),
-	MAKE_EXTENSION_PCI(knc1cpmk3, 0x1894, 0x0023),
-	MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
-	MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031),
-	MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154),
-	MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155),
-	MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156),
-	MAKE_EXTENSION_PCI(cin1200cmk3, 0x153b, 0x1176),
-	MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157),
-	{
-	 .vendor = 0,
-	}
-};
-
-MODULE_DEVICE_TABLE(pci, pci_tbl);
-
-static struct saa7146_extension budget_extension = {
-	.name = "budget_av",
-	.flags = SAA7146_USE_I2C_IRQ,
-
-	.pci_tbl = pci_tbl,
-
-	.module = THIS_MODULE,
-	.attach = budget_av_attach,
-	.detach = budget_av_detach,
-
-	.irq_mask = MASK_10,
-	.irq_func = budget_av_irq,
-};
-
-static int __init budget_av_init(void)
-{
-	return saa7146_register_extension(&budget_extension);
-}
-
-static void __exit budget_av_exit(void)
-{
-	saa7146_unregister_extension(&budget_extension);
-}
-
-module_init(budget_av_init);
-module_exit(budget_av_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others");
-MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
-		   "budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)");
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
deleted file mode 100644
index 98e5241..0000000
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ /dev/null
@@ -1,1591 +0,0 @@
-/*
- * budget-ci.c: driver for the SAA7146 based Budget DVB cards
- *
- * Compiled from various sources by Michael Hunold <michael@mihu.de>
- *
- *     msp430 IR support contributed by Jack Thomasson <jkt@Helius.COM>
- *     partially based on the Siemens DVB driver by Ralph+Marcus Metzler
- *
- * CI interface support (c) 2004 Andrew de Quincey <adq_dvb@lidskialf.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.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org/
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <media/rc-core.h>
-
-#include "budget.h"
-
-#include "dvb_ca_en50221.h"
-#include "stv0299.h"
-#include "stv0297.h"
-#include "tda1004x.h"
-#include "stb0899_drv.h"
-#include "stb0899_reg.h"
-#include "stb0899_cfg.h"
-#include "stb6100.h"
-#include "stb6100_cfg.h"
-#include "lnbp21.h"
-#include "bsbe1.h"
-#include "bsru6.h"
-#include "tda1002x.h"
-#include "tda827x.h"
-#include "bsbe1-d01a.h"
-
-#define MODULE_NAME "budget_ci"
-
-/*
- * Regarding DEBIADDR_IR:
- * Some CI modules hang if random addresses are read.
- * Using address 0x4000 for the IR read means that we
- * use the same address as for CI version, which should
- * be a safe default.
- */
-#define DEBIADDR_IR		0x4000
-#define DEBIADDR_CICONTROL	0x0000
-#define DEBIADDR_CIVERSION	0x4000
-#define DEBIADDR_IO		0x1000
-#define DEBIADDR_ATTR		0x3000
-
-#define CICONTROL_RESET		0x01
-#define CICONTROL_ENABLETS	0x02
-#define CICONTROL_CAMDETECT	0x08
-
-#define DEBICICTL		0x00420000
-#define DEBICICAM		0x02420000
-
-#define SLOTSTATUS_NONE		1
-#define SLOTSTATUS_PRESENT	2
-#define SLOTSTATUS_RESET	4
-#define SLOTSTATUS_READY	8
-#define SLOTSTATUS_OCCUPIED	(SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
-
-/* RC5 device wildcard */
-#define IR_DEVICE_ANY		255
-
-static int rc5_device = -1;
-module_param(rc5_device, int, 0644);
-MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)");
-
-static int ir_debug;
-module_param(ir_debug, int, 0644);
-MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-struct budget_ci_ir {
-	struct rc_dev *dev;
-	struct tasklet_struct msp430_irq_tasklet;
-	char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
-	char phys[32];
-	int rc5_device;
-	u32 ir_key;
-	bool have_command;
-	bool full_rc5;		/* Outputs a full RC5 code */
-};
-
-struct budget_ci {
-	struct budget budget;
-	struct tasklet_struct ciintf_irq_tasklet;
-	int slot_status;
-	int ci_irq;
-	struct dvb_ca_en50221 ca;
-	struct budget_ci_ir ir;
-	u8 tuner_pll_address; /* used for philips_tdm1316l configs */
-};
-
-static void msp430_ir_interrupt(unsigned long data)
-{
-	struct budget_ci *budget_ci = (struct budget_ci *) data;
-	struct rc_dev *dev = budget_ci->ir.dev;
-	u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
-
-	/*
-	 * The msp430 chip can generate two different bytes, command and device
-	 *
-	 * type1: X1CCCCCC, C = command bits (0 - 63)
-	 * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
-	 *
-	 * Each signal from the remote control can generate one or more command
-	 * bytes and one or more device bytes. For the repeated bytes, the
-	 * highest bit (X) is set. The first command byte is always generated
-	 * before the first device byte. Other than that, no specific order
-	 * seems to apply. To make life interesting, bytes can also be lost.
-	 *
-	 * Only when we have a command and device byte, a keypress is
-	 * generated.
-	 */
-
-	if (ir_debug)
-		printk("budget_ci: received byte 0x%02x\n", command);
-
-	/* Remove repeat bit, we use every command */
-	command = command & 0x7f;
-
-	/* Is this a RC5 command byte? */
-	if (command & 0x40) {
-		budget_ci->ir.have_command = true;
-		budget_ci->ir.ir_key = command & 0x3f;
-		return;
-	}
-
-	/* It's a RC5 device byte */
-	if (!budget_ci->ir.have_command)
-		return;
-	budget_ci->ir.have_command = false;
-
-	if (budget_ci->ir.rc5_device != IR_DEVICE_ANY &&
-	    budget_ci->ir.rc5_device != (command & 0x1f))
-		return;
-
-	if (budget_ci->ir.full_rc5) {
-		rc_keydown(dev,
-			   budget_ci->ir.rc5_device <<8 | budget_ci->ir.ir_key,
-			   (command & 0x20) ? 1 : 0);
-		return;
-	}
-
-	/* FIXME: We should generate complete scancodes for all devices */
-	rc_keydown(dev, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0);
-}
-
-static int msp430_ir_init(struct budget_ci *budget_ci)
-{
-	struct saa7146_dev *saa = budget_ci->budget.dev;
-	struct rc_dev *dev;
-	int error;
-
-	dev = rc_allocate_device();
-	if (!dev) {
-		printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
-		return -ENOMEM;
-	}
-
-	snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
-		 "Budget-CI dvb ir receiver %s", saa->name);
-	snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
-		 "pci-%s/ir0", pci_name(saa->pci));
-
-	dev->driver_name = MODULE_NAME;
-	dev->input_name = budget_ci->ir.name;
-	dev->input_phys = budget_ci->ir.phys;
-	dev->input_id.bustype = BUS_PCI;
-	dev->input_id.version = 1;
-	if (saa->pci->subsystem_vendor) {
-		dev->input_id.vendor = saa->pci->subsystem_vendor;
-		dev->input_id.product = saa->pci->subsystem_device;
-	} else {
-		dev->input_id.vendor = saa->pci->vendor;
-		dev->input_id.product = saa->pci->device;
-	}
-	dev->dev.parent = &saa->pci->dev;
-
-	if (rc5_device < 0)
-		budget_ci->ir.rc5_device = IR_DEVICE_ANY;
-	else
-		budget_ci->ir.rc5_device = rc5_device;
-
-	/* Select keymap and address */
-	switch (budget_ci->budget.dev->pci->subsystem_device) {
-	case 0x100c:
-	case 0x100f:
-	case 0x1011:
-	case 0x1012:
-		/* The hauppauge keymap is a superset of these remotes */
-		dev->map_name = RC_MAP_HAUPPAUGE;
-		budget_ci->ir.full_rc5 = true;
-
-		if (rc5_device < 0)
-			budget_ci->ir.rc5_device = 0x1f;
-		break;
-	case 0x1010:
-	case 0x1017:
-	case 0x1019:
-	case 0x101a:
-	case 0x101b:
-		/* for the Technotrend 1500 bundled remote */
-		dev->map_name = RC_MAP_TT_1500;
-		break;
-	default:
-		/* unknown remote */
-		dev->map_name = RC_MAP_BUDGET_CI_OLD;
-		break;
-	}
-	if (!budget_ci->ir.full_rc5)
-		dev->scanmask = 0xff;
-
-	error = rc_register_device(dev);
-	if (error) {
-		printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
-		rc_free_device(dev);
-		return error;
-	}
-
-	budget_ci->ir.dev = dev;
-
-	tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
-		     (unsigned long) budget_ci);
-
-	SAA7146_IER_ENABLE(saa, MASK_06);
-	saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
-
-	return 0;
-}
-
-static void msp430_ir_deinit(struct budget_ci *budget_ci)
-{
-	struct saa7146_dev *saa = budget_ci->budget.dev;
-
-	SAA7146_IER_DISABLE(saa, MASK_06);
-	saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
-	tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
-
-	rc_unregister_device(budget_ci->ir.dev);
-}
-
-static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
-{
-	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
-				     DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
-}
-
-static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
-{
-	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
-				      DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
-}
-
-static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
-{
-	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
-				     DEBIADDR_IO | (address & 3), 1, 1, 0);
-}
-
-static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
-{
-	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
-				      DEBIADDR_IO | (address & 3), 1, value, 1, 0);
-}
-
-static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
-{
-	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
-	struct saa7146_dev *saa = budget_ci->budget.dev;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	if (budget_ci->ci_irq) {
-		// trigger on RISING edge during reset so we know when READY is re-asserted
-		saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
-	}
-	budget_ci->slot_status = SLOTSTATUS_RESET;
-	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
-	msleep(1);
-	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
-			       CICONTROL_RESET, 1, 0);
-
-	saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
-	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
-	return 0;
-}
-
-static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
-{
-	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
-	struct saa7146_dev *saa = budget_ci->budget.dev;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
-	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
-	return 0;
-}
-
-static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
-{
-	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
-	struct saa7146_dev *saa = budget_ci->budget.dev;
-	int tmp;
-
-	if (slot != 0)
-		return -EINVAL;
-
-	saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
-
-	tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
-	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
-			       tmp | CICONTROL_ENABLETS, 1, 0);
-
-	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
-	return 0;
-}
-
-static void ciintf_interrupt(unsigned long data)
-{
-	struct budget_ci *budget_ci = (struct budget_ci *) data;
-	struct saa7146_dev *saa = budget_ci->budget.dev;
-	unsigned int flags;
-
-	// ensure we don't get spurious IRQs during initialisation
-	if (!budget_ci->budget.ci_present)
-		return;
-
-	// read the CAM status
-	flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
-	if (flags & CICONTROL_CAMDETECT) {
-
-		// GPIO should be set to trigger on falling edge if a CAM is present
-		saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
-
-		if (budget_ci->slot_status & SLOTSTATUS_NONE) {
-			// CAM insertion IRQ
-			budget_ci->slot_status = SLOTSTATUS_PRESENT;
-			dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
-						     DVB_CA_EN50221_CAMCHANGE_INSERTED);
-
-		} else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
-			// CAM ready (reset completed)
-			budget_ci->slot_status = SLOTSTATUS_READY;
-			dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
-
-		} else if (budget_ci->slot_status & SLOTSTATUS_READY) {
-			// FR/DA IRQ
-			dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
-		}
-	} else {
-
-		// trigger on rising edge if a CAM is not present - when a CAM is inserted, we
-		// only want to get the IRQ when it sets READY. If we trigger on the falling edge,
-		// the CAM might not actually be ready yet.
-		saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
-
-		// generate a CAM removal IRQ if we haven't already
-		if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
-			// CAM removal IRQ
-			budget_ci->slot_status = SLOTSTATUS_NONE;
-			dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
-						     DVB_CA_EN50221_CAMCHANGE_REMOVED);
-		}
-	}
-}
-
-static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
-{
-	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
-	unsigned int flags;
-
-	// ensure we don't get spurious IRQs during initialisation
-	if (!budget_ci->budget.ci_present)
-		return -EINVAL;
-
-	// read the CAM status
-	flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
-	if (flags & CICONTROL_CAMDETECT) {
-		// mark it as present if it wasn't before
-		if (budget_ci->slot_status & SLOTSTATUS_NONE) {
-			budget_ci->slot_status = SLOTSTATUS_PRESENT;
-		}
-
-		// during a RESET, we check if we can read from IO memory to see when CAM is ready
-		if (budget_ci->slot_status & SLOTSTATUS_RESET) {
-			if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
-				budget_ci->slot_status = SLOTSTATUS_READY;
-			}
-		}
-	} else {
-		budget_ci->slot_status = SLOTSTATUS_NONE;
-	}
-
-	if (budget_ci->slot_status != SLOTSTATUS_NONE) {
-		if (budget_ci->slot_status & SLOTSTATUS_READY) {
-			return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
-		}
-		return DVB_CA_EN50221_POLL_CAM_PRESENT;
-	}
-
-	return 0;
-}
-
-static int ciintf_init(struct budget_ci *budget_ci)
-{
-	struct saa7146_dev *saa = budget_ci->budget.dev;
-	int flags;
-	int result;
-	int ci_version;
-	int ca_flags;
-
-	memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
-
-	// enable DEBI pins
-	saa7146_write(saa, MC1, MASK_27 | MASK_11);
-
-	// test if it is there
-	ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
-	if ((ci_version & 0xa0) != 0xa0) {
-		result = -ENODEV;
-		goto error;
-	}
-
-	// determine whether a CAM is present or not
-	flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
-	budget_ci->slot_status = SLOTSTATUS_NONE;
-	if (flags & CICONTROL_CAMDETECT)
-		budget_ci->slot_status = SLOTSTATUS_PRESENT;
-
-	// version 0xa2 of the CI firmware doesn't generate interrupts
-	if (ci_version == 0xa2) {
-		ca_flags = 0;
-		budget_ci->ci_irq = 0;
-	} else {
-		ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
-				DVB_CA_EN50221_FLAG_IRQ_FR |
-				DVB_CA_EN50221_FLAG_IRQ_DA;
-		budget_ci->ci_irq = 1;
-	}
-
-	// register CI interface
-	budget_ci->ca.owner = THIS_MODULE;
-	budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
-	budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
-	budget_ci->ca.read_cam_control = ciintf_read_cam_control;
-	budget_ci->ca.write_cam_control = ciintf_write_cam_control;
-	budget_ci->ca.slot_reset = ciintf_slot_reset;
-	budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
-	budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
-	budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
-	budget_ci->ca.data = budget_ci;
-	if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
-					  &budget_ci->ca,
-					  ca_flags, 1)) != 0) {
-		printk("budget_ci: CI interface detected, but initialisation failed.\n");
-		goto error;
-	}
-
-	// Setup CI slot IRQ
-	if (budget_ci->ci_irq) {
-		tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
-		if (budget_ci->slot_status != SLOTSTATUS_NONE) {
-			saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
-		} else {
-			saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
-		}
-		SAA7146_IER_ENABLE(saa, MASK_03);
-	}
-
-	// enable interface
-	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
-			       CICONTROL_RESET, 1, 0);
-
-	// success!
-	printk("budget_ci: CI interface initialised\n");
-	budget_ci->budget.ci_present = 1;
-
-	// forge a fake CI IRQ so the CAM state is setup correctly
-	if (budget_ci->ci_irq) {
-		flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
-		if (budget_ci->slot_status != SLOTSTATUS_NONE)
-			flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
-		dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
-	}
-
-	return 0;
-
-error:
-	saa7146_write(saa, MC1, MASK_27);
-	return result;
-}
-
-static void ciintf_deinit(struct budget_ci *budget_ci)
-{
-	struct saa7146_dev *saa = budget_ci->budget.dev;
-
-	// disable CI interrupts
-	if (budget_ci->ci_irq) {
-		SAA7146_IER_DISABLE(saa, MASK_03);
-		saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
-		tasklet_kill(&budget_ci->ciintf_irq_tasklet);
-	}
-
-	// reset interface
-	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
-	msleep(1);
-	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
-			       CICONTROL_RESET, 1, 0);
-
-	// disable TS data stream to CI interface
-	saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
-
-	// release the CA device
-	dvb_ca_en50221_release(&budget_ci->ca);
-
-	// disable DEBI pins
-	saa7146_write(saa, MC1, MASK_27);
-}
-
-static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
-{
-	struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
-
-	dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
-
-	if (*isr & MASK_06)
-		tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
-
-	if (*isr & MASK_10)
-		ttpci_budget_irq10_handler(dev, isr);
-
-	if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
-		tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
-}
-
-static u8 philips_su1278_tt_inittab[] = {
-	0x01, 0x0f,
-	0x02, 0x30,
-	0x03, 0x00,
-	0x04, 0x5b,
-	0x05, 0x85,
-	0x06, 0x02,
-	0x07, 0x00,
-	0x08, 0x02,
-	0x09, 0x00,
-	0x0C, 0x01,
-	0x0D, 0x81,
-	0x0E, 0x44,
-	0x0f, 0x14,
-	0x10, 0x3c,
-	0x11, 0x84,
-	0x12, 0xda,
-	0x13, 0x97,
-	0x14, 0x95,
-	0x15, 0xc9,
-	0x16, 0x19,
-	0x17, 0x8c,
-	0x18, 0x59,
-	0x19, 0xf8,
-	0x1a, 0xfe,
-	0x1c, 0x7f,
-	0x1d, 0x00,
-	0x1e, 0x00,
-	0x1f, 0x50,
-	0x20, 0x00,
-	0x21, 0x00,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x28, 0x00,
-	0x29, 0x28,
-	0x2a, 0x14,
-	0x2b, 0x0f,
-	0x2c, 0x09,
-	0x2d, 0x09,
-	0x31, 0x1f,
-	0x32, 0x19,
-	0x33, 0xfc,
-	0x34, 0x93,
-	0xff, 0xff
-};
-
-static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
-{
-	stv0299_writereg(fe, 0x0e, 0x44);
-	if (srate >= 10000000) {
-		stv0299_writereg(fe, 0x13, 0x97);
-		stv0299_writereg(fe, 0x14, 0x95);
-		stv0299_writereg(fe, 0x15, 0xc9);
-		stv0299_writereg(fe, 0x17, 0x8c);
-		stv0299_writereg(fe, 0x1a, 0xfe);
-		stv0299_writereg(fe, 0x1c, 0x7f);
-		stv0299_writereg(fe, 0x2d, 0x09);
-	} else {
-		stv0299_writereg(fe, 0x13, 0x99);
-		stv0299_writereg(fe, 0x14, 0x8d);
-		stv0299_writereg(fe, 0x15, 0xce);
-		stv0299_writereg(fe, 0x17, 0x43);
-		stv0299_writereg(fe, 0x1a, 0x1d);
-		stv0299_writereg(fe, 0x1c, 0x12);
-		stv0299_writereg(fe, 0x2d, 0x05);
-	}
-	stv0299_writereg(fe, 0x0e, 0x23);
-	stv0299_writereg(fe, 0x0f, 0x94);
-	stv0299_writereg(fe, 0x10, 0x39);
-	stv0299_writereg(fe, 0x15, 0xc9);
-
-	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
-	stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
-	stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
-
-	return 0;
-}
-
-static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
-	u32 div;
-	u8 buf[4];
-	struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
-
-	if ((p->frequency < 950000) || (p->frequency > 2150000))
-		return -EINVAL;
-
-	div = (p->frequency + (500 - 1)) / 500;	/* round correctly */
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = div & 0xff;
-	buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
-	buf[3] = 0x20;
-
-	if (p->symbol_rate < 4000000)
-		buf[3] |= 1;
-
-	if (p->frequency < 1250000)
-		buf[3] |= 0;
-	else if (p->frequency < 1550000)
-		buf[3] |= 0x40;
-	else if (p->frequency < 2050000)
-		buf[3] |= 0x80;
-	else if (p->frequency < 2150000)
-		buf[3] |= 0xC0;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
-		return -EIO;
-	return 0;
-}
-
-static struct stv0299_config philips_su1278_tt_config = {
-
-	.demod_address = 0x68,
-	.inittab = philips_su1278_tt_inittab,
-	.mclk = 64000000UL,
-	.invert = 0,
-	.skip_reinit = 1,
-	.lock_output = STV0299_LOCKOUTPUT_1,
-	.volt13_op0_op1 = STV0299_VOLT13_OP1,
-	.min_delay_ms = 50,
-	.set_symbol_rate = philips_su1278_tt_set_symbol_rate,
-};
-
-
-
-static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
-{
-	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
-	static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
-	static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
-	struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
-			sizeof(td1316_init) };
-
-	// setup PLL configuration
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
-		return -EIO;
-	msleep(1);
-
-	// disable the mc44BC374c (do not check for errors)
-	tuner_msg.addr = 0x65;
-	tuner_msg.buf = disable_mc44BC374c;
-	tuner_msg.len = sizeof(disable_mc44BC374c);
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 1);
-		i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
-	}
-
-	return 0;
-}
-
-static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
-	u8 tuner_buf[4];
-	struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) };
-	int tuner_frequency = 0;
-	u8 band, cp, filter;
-
-	// determine charge pump
-	tuner_frequency = p->frequency + 36130000;
-	if (tuner_frequency < 87000000)
-		return -EINVAL;
-	else if (tuner_frequency < 130000000)
-		cp = 3;
-	else if (tuner_frequency < 160000000)
-		cp = 5;
-	else if (tuner_frequency < 200000000)
-		cp = 6;
-	else if (tuner_frequency < 290000000)
-		cp = 3;
-	else if (tuner_frequency < 420000000)
-		cp = 5;
-	else if (tuner_frequency < 480000000)
-		cp = 6;
-	else if (tuner_frequency < 620000000)
-		cp = 3;
-	else if (tuner_frequency < 830000000)
-		cp = 5;
-	else if (tuner_frequency < 895000000)
-		cp = 7;
-	else
-		return -EINVAL;
-
-	// determine band
-	if (p->frequency < 49000000)
-		return -EINVAL;
-	else if (p->frequency < 159000000)
-		band = 1;
-	else if (p->frequency < 444000000)
-		band = 2;
-	else if (p->frequency < 861000000)
-		band = 4;
-	else
-		return -EINVAL;
-
-	// setup PLL filter and TDA9889
-	switch (p->bandwidth_hz) {
-	case 6000000:
-		tda1004x_writereg(fe, 0x0C, 0x14);
-		filter = 0;
-		break;
-
-	case 7000000:
-		tda1004x_writereg(fe, 0x0C, 0x80);
-		filter = 0;
-		break;
-
-	case 8000000:
-		tda1004x_writereg(fe, 0x0C, 0x14);
-		filter = 1;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	// calculate divisor
-	// ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
-	tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000;
-
-	// setup tuner buffer
-	tuner_buf[0] = tuner_frequency >> 8;
-	tuner_buf[1] = tuner_frequency & 0xff;
-	tuner_buf[2] = 0xca;
-	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
-		return -EIO;
-
-	msleep(1);
-	return 0;
-}
-
-static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
-					     const struct firmware **fw, char *name)
-{
-	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
-
-	return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
-}
-
-static struct tda1004x_config philips_tdm1316l_config = {
-
-	.demod_address = 0x8,
-	.invert = 0,
-	.invert_oclk = 0,
-	.xtal_freq = TDA10046_XTAL_4M,
-	.agc_config = TDA10046_AGC_DEFAULT,
-	.if_freq = TDA10046_FREQ_3617,
-	.request_firmware = philips_tdm1316l_request_firmware,
-};
-
-static struct tda1004x_config philips_tdm1316l_config_invert = {
-
-	.demod_address = 0x8,
-	.invert = 1,
-	.invert_oclk = 0,
-	.xtal_freq = TDA10046_XTAL_4M,
-	.agc_config = TDA10046_AGC_DEFAULT,
-	.if_freq = TDA10046_FREQ_3617,
-	.request_firmware = philips_tdm1316l_request_firmware,
-};
-
-static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
-	u8 tuner_buf[5];
-	struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
-				    .flags = 0,
-				    .buf = tuner_buf,
-				    .len = sizeof(tuner_buf) };
-	int tuner_frequency = 0;
-	u8 band, cp, filter;
-
-	// determine charge pump
-	tuner_frequency = p->frequency + 36125000;
-	if (tuner_frequency < 87000000)
-		return -EINVAL;
-	else if (tuner_frequency < 130000000) {
-		cp = 3;
-		band = 1;
-	} else if (tuner_frequency < 160000000) {
-		cp = 5;
-		band = 1;
-	} else if (tuner_frequency < 200000000) {
-		cp = 6;
-		band = 1;
-	} else if (tuner_frequency < 290000000) {
-		cp = 3;
-		band = 2;
-	} else if (tuner_frequency < 420000000) {
-		cp = 5;
-		band = 2;
-	} else if (tuner_frequency < 480000000) {
-		cp = 6;
-		band = 2;
-	} else if (tuner_frequency < 620000000) {
-		cp = 3;
-		band = 4;
-	} else if (tuner_frequency < 830000000) {
-		cp = 5;
-		band = 4;
-	} else if (tuner_frequency < 895000000) {
-		cp = 7;
-		band = 4;
-	} else
-		return -EINVAL;
-
-	// assume PLL filter should always be 8MHz for the moment.
-	filter = 1;
-
-	// calculate divisor
-	tuner_frequency = (p->frequency + 36125000 + (62500/2)) / 62500;
-
-	// setup tuner buffer
-	tuner_buf[0] = tuner_frequency >> 8;
-	tuner_buf[1] = tuner_frequency & 0xff;
-	tuner_buf[2] = 0xc8;
-	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
-	tuner_buf[4] = 0x80;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
-		return -EIO;
-
-	msleep(50);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
-		return -EIO;
-
-	msleep(1);
-
-	return 0;
-}
-
-static u8 dvbc_philips_tdm1316l_inittab[] = {
-	0x80, 0x01,
-	0x80, 0x00,
-	0x81, 0x01,
-	0x81, 0x00,
-	0x00, 0x09,
-	0x01, 0x69,
-	0x03, 0x00,
-	0x04, 0x00,
-	0x07, 0x00,
-	0x08, 0x00,
-	0x20, 0x00,
-	0x21, 0x40,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x24, 0x40,
-	0x25, 0x88,
-	0x30, 0xff,
-	0x31, 0x00,
-	0x32, 0xff,
-	0x33, 0x00,
-	0x34, 0x50,
-	0x35, 0x7f,
-	0x36, 0x00,
-	0x37, 0x20,
-	0x38, 0x00,
-	0x40, 0x1c,
-	0x41, 0xff,
-	0x42, 0x29,
-	0x43, 0x20,
-	0x44, 0xff,
-	0x45, 0x00,
-	0x46, 0x00,
-	0x49, 0x04,
-	0x4a, 0x00,
-	0x4b, 0x7b,
-	0x52, 0x30,
-	0x55, 0xae,
-	0x56, 0x47,
-	0x57, 0xe1,
-	0x58, 0x3a,
-	0x5a, 0x1e,
-	0x5b, 0x34,
-	0x60, 0x00,
-	0x63, 0x00,
-	0x64, 0x00,
-	0x65, 0x00,
-	0x66, 0x00,
-	0x67, 0x00,
-	0x68, 0x00,
-	0x69, 0x00,
-	0x6a, 0x02,
-	0x6b, 0x00,
-	0x70, 0xff,
-	0x71, 0x00,
-	0x72, 0x00,
-	0x73, 0x00,
-	0x74, 0x0c,
-	0x80, 0x00,
-	0x81, 0x00,
-	0x82, 0x00,
-	0x83, 0x00,
-	0x84, 0x04,
-	0x85, 0x80,
-	0x86, 0x24,
-	0x87, 0x78,
-	0x88, 0x10,
-	0x89, 0x00,
-	0x90, 0x01,
-	0x91, 0x01,
-	0xa0, 0x04,
-	0xa1, 0x00,
-	0xa2, 0x00,
-	0xb0, 0x91,
-	0xb1, 0x0b,
-	0xc0, 0x53,
-	0xc1, 0x70,
-	0xc2, 0x12,
-	0xd0, 0x00,
-	0xd1, 0x00,
-	0xd2, 0x00,
-	0xd3, 0x00,
-	0xd4, 0x00,
-	0xd5, 0x00,
-	0xde, 0x00,
-	0xdf, 0x00,
-	0x61, 0x38,
-	0x62, 0x0a,
-	0x53, 0x13,
-	0x59, 0x08,
-	0xff, 0xff,
-};
-
-static struct stv0297_config dvbc_philips_tdm1316l_config = {
-	.demod_address = 0x1c,
-	.inittab = dvbc_philips_tdm1316l_inittab,
-	.invert = 0,
-	.stop_during_read = 1,
-};
-
-static struct tda10023_config tda10023_config = {
-	.demod_address = 0xc,
-	.invert = 0,
-	.xtal = 16000000,
-	.pll_m = 11,
-	.pll_p = 3,
-	.pll_n = 1,
-	.deltaf = 0xa511,
-};
-
-static struct tda827x_config tda827x_config = {
-	.config = 0,
-};
-
-/* TT S2-3200 DVB-S (STB0899) Inittab */
-static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = {
-
-	{ STB0899_DEV_ID		, 0x81 },
-	{ STB0899_DISCNTRL1		, 0x32 },
-	{ STB0899_DISCNTRL2     	, 0x80 },
-	{ STB0899_DISRX_ST0     	, 0x04 },
-	{ STB0899_DISRX_ST1     	, 0x00 },
-	{ STB0899_DISPARITY     	, 0x00 },
-	{ STB0899_DISSTATUS		, 0x20 },
-	{ STB0899_DISF22        	, 0x8c },
-	{ STB0899_DISF22RX      	, 0x9a },
-	{ STB0899_SYSREG		, 0x0b },
-	{ STB0899_ACRPRESC      	, 0x11 },
-	{ STB0899_ACRDIV1       	, 0x0a },
-	{ STB0899_ACRDIV2       	, 0x05 },
-	{ STB0899_DACR1         	, 0x00 },
-	{ STB0899_DACR2         	, 0x00 },
-	{ STB0899_OUTCFG        	, 0x00 },
-	{ STB0899_MODECFG       	, 0x00 },
-	{ STB0899_IRQSTATUS_3		, 0x30 },
-	{ STB0899_IRQSTATUS_2		, 0x00 },
-	{ STB0899_IRQSTATUS_1		, 0x00 },
-	{ STB0899_IRQSTATUS_0		, 0x00 },
-	{ STB0899_IRQMSK_3      	, 0xf3 },
-	{ STB0899_IRQMSK_2      	, 0xfc },
-	{ STB0899_IRQMSK_1      	, 0xff },
-	{ STB0899_IRQMSK_0		, 0xff },
-	{ STB0899_IRQCFG		, 0x00 },
-	{ STB0899_I2CCFG        	, 0x88 },
-	{ STB0899_I2CRPT        	, 0x48 }, /* 12k Pullup, Repeater=16, Stop=disabled */
-	{ STB0899_IOPVALUE5		, 0x00 },
-	{ STB0899_IOPVALUE4		, 0x20 },
-	{ STB0899_IOPVALUE3		, 0xc9 },
-	{ STB0899_IOPVALUE2		, 0x90 },
-	{ STB0899_IOPVALUE1		, 0x40 },
-	{ STB0899_IOPVALUE0		, 0x00 },
-	{ STB0899_GPIO00CFG     	, 0x82 },
-	{ STB0899_GPIO01CFG     	, 0x82 },
-	{ STB0899_GPIO02CFG     	, 0x82 },
-	{ STB0899_GPIO03CFG     	, 0x82 },
-	{ STB0899_GPIO04CFG     	, 0x82 },
-	{ STB0899_GPIO05CFG     	, 0x82 },
-	{ STB0899_GPIO06CFG     	, 0x82 },
-	{ STB0899_GPIO07CFG     	, 0x82 },
-	{ STB0899_GPIO08CFG     	, 0x82 },
-	{ STB0899_GPIO09CFG     	, 0x82 },
-	{ STB0899_GPIO10CFG     	, 0x82 },
-	{ STB0899_GPIO11CFG     	, 0x82 },
-	{ STB0899_GPIO12CFG     	, 0x82 },
-	{ STB0899_GPIO13CFG     	, 0x82 },
-	{ STB0899_GPIO14CFG     	, 0x82 },
-	{ STB0899_GPIO15CFG     	, 0x82 },
-	{ STB0899_GPIO16CFG     	, 0x82 },
-	{ STB0899_GPIO17CFG     	, 0x82 },
-	{ STB0899_GPIO18CFG     	, 0x82 },
-	{ STB0899_GPIO19CFG     	, 0x82 },
-	{ STB0899_GPIO20CFG     	, 0x82 },
-	{ STB0899_SDATCFG       	, 0xb8 },
-	{ STB0899_SCLTCFG       	, 0xba },
-	{ STB0899_AGCRFCFG      	, 0x1c }, /* 0x11 */
-	{ STB0899_GPIO22        	, 0x82 }, /* AGCBB2CFG */
-	{ STB0899_GPIO21        	, 0x91 }, /* AGCBB1CFG */
-	{ STB0899_DIRCLKCFG     	, 0x82 },
-	{ STB0899_CLKOUT27CFG   	, 0x7e },
-	{ STB0899_STDBYCFG      	, 0x82 },
-	{ STB0899_CS0CFG        	, 0x82 },
-	{ STB0899_CS1CFG        	, 0x82 },
-	{ STB0899_DISEQCOCFG    	, 0x20 },
-	{ STB0899_GPIO32CFG		, 0x82 },
-	{ STB0899_GPIO33CFG		, 0x82 },
-	{ STB0899_GPIO34CFG		, 0x82 },
-	{ STB0899_GPIO35CFG		, 0x82 },
-	{ STB0899_GPIO36CFG		, 0x82 },
-	{ STB0899_GPIO37CFG		, 0x82 },
-	{ STB0899_GPIO38CFG		, 0x82 },
-	{ STB0899_GPIO39CFG		, 0x82 },
-	{ STB0899_NCOARSE       	, 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
-	{ STB0899_SYNTCTRL      	, 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
-	{ STB0899_FILTCTRL      	, 0x00 },
-	{ STB0899_SYSCTRL       	, 0x00 },
-	{ STB0899_STOPCLK1      	, 0x20 },
-	{ STB0899_STOPCLK2      	, 0x00 },
-	{ STB0899_INTBUFSTATUS		, 0x00 },
-	{ STB0899_INTBUFCTRL    	, 0x0a },
-	{ 0xffff			, 0xff },
-};
-
-static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = {
-	{ STB0899_DEMOD         	, 0x00 },
-	{ STB0899_RCOMPC        	, 0xc9 },
-	{ STB0899_AGC1CN        	, 0x41 },
-	{ STB0899_AGC1REF       	, 0x10 },
-	{ STB0899_RTC			, 0x7a },
-	{ STB0899_TMGCFG        	, 0x4e },
-	{ STB0899_AGC2REF       	, 0x34 },
-	{ STB0899_TLSR          	, 0x84 },
-	{ STB0899_CFD           	, 0xc7 },
-	{ STB0899_ACLC			, 0x87 },
-	{ STB0899_BCLC          	, 0x94 },
-	{ STB0899_EQON          	, 0x41 },
-	{ STB0899_LDT           	, 0xdd },
-	{ STB0899_LDT2          	, 0xc9 },
-	{ STB0899_EQUALREF      	, 0xb4 },
-	{ STB0899_TMGRAMP       	, 0x10 },
-	{ STB0899_TMGTHD        	, 0x30 },
-	{ STB0899_IDCCOMP		, 0xfb },
-	{ STB0899_QDCCOMP		, 0x03 },
-	{ STB0899_POWERI		, 0x3b },
-	{ STB0899_POWERQ		, 0x3d },
-	{ STB0899_RCOMP			, 0x81 },
-	{ STB0899_AGCIQIN		, 0x80 },
-	{ STB0899_AGC2I1		, 0x04 },
-	{ STB0899_AGC2I2		, 0xf5 },
-	{ STB0899_TLIR			, 0x25 },
-	{ STB0899_RTF			, 0x80 },
-	{ STB0899_DSTATUS		, 0x00 },
-	{ STB0899_LDI			, 0xca },
-	{ STB0899_CFRM			, 0xf1 },
-	{ STB0899_CFRL			, 0xf3 },
-	{ STB0899_NIRM			, 0x2a },
-	{ STB0899_NIRL			, 0x05 },
-	{ STB0899_ISYMB			, 0x17 },
-	{ STB0899_QSYMB			, 0xfa },
-	{ STB0899_SFRH          	, 0x2f },
-	{ STB0899_SFRM          	, 0x68 },
-	{ STB0899_SFRL          	, 0x40 },
-	{ STB0899_SFRUPH        	, 0x2f },
-	{ STB0899_SFRUPM        	, 0x68 },
-	{ STB0899_SFRUPL        	, 0x40 },
-	{ STB0899_EQUAI1		, 0xfd },
-	{ STB0899_EQUAQ1		, 0x04 },
-	{ STB0899_EQUAI2		, 0x0f },
-	{ STB0899_EQUAQ2		, 0xff },
-	{ STB0899_EQUAI3		, 0xdf },
-	{ STB0899_EQUAQ3		, 0xfa },
-	{ STB0899_EQUAI4		, 0x37 },
-	{ STB0899_EQUAQ4		, 0x0d },
-	{ STB0899_EQUAI5		, 0xbd },
-	{ STB0899_EQUAQ5		, 0xf7 },
-	{ STB0899_DSTATUS2		, 0x00 },
-	{ STB0899_VSTATUS       	, 0x00 },
-	{ STB0899_VERROR		, 0xff },
-	{ STB0899_IQSWAP		, 0x2a },
-	{ STB0899_ECNT1M		, 0x00 },
-	{ STB0899_ECNT1L		, 0x00 },
-	{ STB0899_ECNT2M		, 0x00 },
-	{ STB0899_ECNT2L		, 0x00 },
-	{ STB0899_ECNT3M		, 0x00 },
-	{ STB0899_ECNT3L		, 0x00 },
-	{ STB0899_FECAUTO1      	, 0x06 },
-	{ STB0899_FECM			, 0x01 },
-	{ STB0899_VTH12         	, 0xf0 },
-	{ STB0899_VTH23         	, 0xa0 },
-	{ STB0899_VTH34			, 0x78 },
-	{ STB0899_VTH56         	, 0x4e },
-	{ STB0899_VTH67         	, 0x48 },
-	{ STB0899_VTH78         	, 0x38 },
-	{ STB0899_PRVIT         	, 0xff },
-	{ STB0899_VITSYNC       	, 0x19 },
-	{ STB0899_RSULC         	, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
-	{ STB0899_TSULC         	, 0x42 },
-	{ STB0899_RSLLC         	, 0x40 },
-	{ STB0899_TSLPL			, 0x12 },
-	{ STB0899_TSCFGH        	, 0x0c },
-	{ STB0899_TSCFGM        	, 0x00 },
-	{ STB0899_TSCFGL        	, 0x0c },
-	{ STB0899_TSOUT			, 0x4d }, /* 0x0d for CAM */
-	{ STB0899_RSSYNCDEL     	, 0x00 },
-	{ STB0899_TSINHDELH     	, 0x02 },
-	{ STB0899_TSINHDELM		, 0x00 },
-	{ STB0899_TSINHDELL		, 0x00 },
-	{ STB0899_TSLLSTKM		, 0x00 },
-	{ STB0899_TSLLSTKL		, 0x00 },
-	{ STB0899_TSULSTKM		, 0x00 },
-	{ STB0899_TSULSTKL		, 0xab },
-	{ STB0899_PCKLENUL		, 0x00 },
-	{ STB0899_PCKLENLL		, 0xcc },
-	{ STB0899_RSPCKLEN		, 0xcc },
-	{ STB0899_TSSTATUS		, 0x80 },
-	{ STB0899_ERRCTRL1      	, 0xb6 },
-	{ STB0899_ERRCTRL2      	, 0x96 },
-	{ STB0899_ERRCTRL3      	, 0x89 },
-	{ STB0899_DMONMSK1		, 0x27 },
-	{ STB0899_DMONMSK0		, 0x03 },
-	{ STB0899_DEMAPVIT      	, 0x5c },
-	{ STB0899_PLPARM		, 0x1f },
-	{ STB0899_PDELCTRL      	, 0x48 },
-	{ STB0899_PDELCTRL2     	, 0x00 },
-	{ STB0899_BBHCTRL1      	, 0x00 },
-	{ STB0899_BBHCTRL2      	, 0x00 },
-	{ STB0899_HYSTTHRESH    	, 0x77 },
-	{ STB0899_MATCSTM		, 0x00 },
-	{ STB0899_MATCSTL		, 0x00 },
-	{ STB0899_UPLCSTM		, 0x00 },
-	{ STB0899_UPLCSTL		, 0x00 },
-	{ STB0899_DFLCSTM		, 0x00 },
-	{ STB0899_DFLCSTL		, 0x00 },
-	{ STB0899_SYNCCST		, 0x00 },
-	{ STB0899_SYNCDCSTM		, 0x00 },
-	{ STB0899_SYNCDCSTL		, 0x00 },
-	{ STB0899_ISI_ENTRY		, 0x00 },
-	{ STB0899_ISI_BIT_EN		, 0x00 },
-	{ STB0899_MATSTRM		, 0x00 },
-	{ STB0899_MATSTRL		, 0x00 },
-	{ STB0899_UPLSTRM		, 0x00 },
-	{ STB0899_UPLSTRL		, 0x00 },
-	{ STB0899_DFLSTRM		, 0x00 },
-	{ STB0899_DFLSTRL		, 0x00 },
-	{ STB0899_SYNCSTR		, 0x00 },
-	{ STB0899_SYNCDSTRM		, 0x00 },
-	{ STB0899_SYNCDSTRL		, 0x00 },
-	{ STB0899_CFGPDELSTATUS1	, 0x10 },
-	{ STB0899_CFGPDELSTATUS2	, 0x00 },
-	{ STB0899_BBFERRORM		, 0x00 },
-	{ STB0899_BBFERRORL		, 0x00 },
-	{ STB0899_UPKTERRORM		, 0x00 },
-	{ STB0899_UPKTERRORL		, 0x00 },
-	{ 0xffff			, 0xff },
-};
-
-static struct stb0899_config tt3200_config = {
-	.init_dev		= tt3200_stb0899_s1_init_1,
-	.init_s2_demod		= stb0899_s2_init_2,
-	.init_s1_demod		= tt3200_stb0899_s1_init_3,
-	.init_s2_fec		= stb0899_s2_init_4,
-	.init_tst		= stb0899_s1_init_5,
-
-	.postproc		= NULL,
-
-	.demod_address 		= 0x68,
-
-	.xtal_freq		= 27000000,
-	.inversion		= IQ_SWAP_ON, /* 1 */
-
-	.lo_clk			= 76500000,
-	.hi_clk			= 99000000,
-
-	.esno_ave		= STB0899_DVBS2_ESNO_AVE,
-	.esno_quant		= STB0899_DVBS2_ESNO_QUANT,
-	.avframes_coarse	= STB0899_DVBS2_AVFRAMES_COARSE,
-	.avframes_fine		= STB0899_DVBS2_AVFRAMES_FINE,
-	.miss_threshold		= STB0899_DVBS2_MISS_THRESHOLD,
-	.uwp_threshold_acq	= STB0899_DVBS2_UWP_THRESHOLD_ACQ,
-	.uwp_threshold_track	= STB0899_DVBS2_UWP_THRESHOLD_TRACK,
-	.uwp_threshold_sof	= STB0899_DVBS2_UWP_THRESHOLD_SOF,
-	.sof_search_timeout	= STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
-
-	.btr_nco_bits		= STB0899_DVBS2_BTR_NCO_BITS,
-	.btr_gain_shift_offset	= STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
-	.crl_nco_bits		= STB0899_DVBS2_CRL_NCO_BITS,
-	.ldpc_max_iter		= STB0899_DVBS2_LDPC_MAX_ITER,
-
-	.tuner_get_frequency	= stb6100_get_frequency,
-	.tuner_set_frequency	= stb6100_set_frequency,
-	.tuner_set_bandwidth	= stb6100_set_bandwidth,
-	.tuner_get_bandwidth	= stb6100_get_bandwidth,
-	.tuner_set_rfsiggain	= NULL
-};
-
-static struct stb6100_config tt3200_stb6100_config = {
-	.tuner_address	= 0x60,
-	.refclock	= 27000000,
-};
-
-static void frontend_init(struct budget_ci *budget_ci)
-{
-	switch (budget_ci->budget.dev->pci->subsystem_device) {
-	case 0x100c:		// Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
-		budget_ci->budget.dvb_frontend =
-			dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
-		if (budget_ci->budget.dvb_frontend) {
-			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
-			budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
-			break;
-		}
-		break;
-
-	case 0x100f:		// Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
-		budget_ci->budget.dvb_frontend =
-			dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
-		if (budget_ci->budget.dvb_frontend) {
-			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
-			break;
-		}
-		break;
-
-	case 0x1010:		// TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
-		budget_ci->tuner_pll_address = 0x61;
-		budget_ci->budget.dvb_frontend =
-			dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
-		if (budget_ci->budget.dvb_frontend) {
-			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
-			break;
-		}
-		break;
-
-	case 0x1011:		// Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
-		budget_ci->tuner_pll_address = 0x63;
-		budget_ci->budget.dvb_frontend =
-			dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
-		if (budget_ci->budget.dvb_frontend) {
-			budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
-			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
-			break;
-		}
-		break;
-
-	case 0x1012:		// TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
-		budget_ci->tuner_pll_address = 0x60;
-		budget_ci->budget.dvb_frontend =
-			dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap);
-		if (budget_ci->budget.dvb_frontend) {
-			budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
-			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
-			break;
-		}
-		break;
-
-	case 0x1017:		// TT S-1500 PCI
-		budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
-		if (budget_ci->budget.dvb_frontend) {
-			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
-			budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
-
-			budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
-			if (dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0) == NULL) {
-				printk("%s: No LNBP21 found!\n", __func__);
-				dvb_frontend_detach(budget_ci->budget.dvb_frontend);
-				budget_ci->budget.dvb_frontend = NULL;
-			}
-		}
-		break;
-
-	case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */
-		budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48);
-		if (budget_ci->budget.dvb_frontend) {
-			if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, &tda827x_config) == NULL) {
-				printk(KERN_ERR "%s: No tda827x found!\n", __func__);
-				dvb_frontend_detach(budget_ci->budget.dvb_frontend);
-				budget_ci->budget.dvb_frontend = NULL;
-			}
-		}
-		break;
-
-	case 0x101b: /* TT S-1500B (BSBE1-D01A - STV0288/STB6000/LNBP21) */
-		budget_ci->budget.dvb_frontend = dvb_attach(stv0288_attach, &stv0288_bsbe1_d01a_config, &budget_ci->budget.i2c_adap);
-		if (budget_ci->budget.dvb_frontend) {
-			if (dvb_attach(stb6000_attach, budget_ci->budget.dvb_frontend, 0x63, &budget_ci->budget.i2c_adap)) {
-				if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) {
-					printk(KERN_ERR "%s: No LNBP21 found!\n", __func__);
-					dvb_frontend_detach(budget_ci->budget.dvb_frontend);
-					budget_ci->budget.dvb_frontend = NULL;
-				}
-			} else {
-				printk(KERN_ERR "%s: No STB6000 found!\n", __func__);
-				dvb_frontend_detach(budget_ci->budget.dvb_frontend);
-				budget_ci->budget.dvb_frontend = NULL;
-			}
-		}
-		break;
-
-	case 0x1019:		// TT S2-3200 PCI
-		/*
-		 * NOTE! on some STB0899 versions, the internal PLL takes a longer time
-		 * to settle, aka LOCK. On the older revisions of the chip, we don't see
-		 * this, as a result on the newer chips the entire clock tree, will not
-		 * be stable after a freshly POWER 'ed up situation.
-		 * In this case, we should RESET the STB0899 (Active LOW) and wait for
-		 * PLL stabilization.
-		 *
-		 * On the TT S2 3200 and clones, the STB0899 demodulator's RESETB is
-		 * connected to the SAA7146 GPIO, GPIO2, Pin 142
-		 */
-		/* Reset Demodulator */
-		saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTLO);
-		/* Wait for everything to die */
-		msleep(50);
-		/* Pull it up out of Reset state */
-		saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTHI);
-		/* Wait for PLL to stabilize */
-		msleep(250);
-		/*
-		 * PLL state should be stable now. Ideally, we should check
-		 * for PLL LOCK status. But well, never mind!
-		 */
-		budget_ci->budget.dvb_frontend = dvb_attach(stb0899_attach, &tt3200_config, &budget_ci->budget.i2c_adap);
-		if (budget_ci->budget.dvb_frontend) {
-			if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) {
-				if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) {
-					printk("%s: No LNBP21 found!\n", __func__);
-					dvb_frontend_detach(budget_ci->budget.dvb_frontend);
-					budget_ci->budget.dvb_frontend = NULL;
-				}
-			} else {
-					dvb_frontend_detach(budget_ci->budget.dvb_frontend);
-					budget_ci->budget.dvb_frontend = NULL;
-			}
-		}
-		break;
-
-	}
-
-	if (budget_ci->budget.dvb_frontend == NULL) {
-		printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
-		       budget_ci->budget.dev->pci->vendor,
-		       budget_ci->budget.dev->pci->device,
-		       budget_ci->budget.dev->pci->subsystem_vendor,
-		       budget_ci->budget.dev->pci->subsystem_device);
-	} else {
-		if (dvb_register_frontend
-		    (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
-			printk("budget-ci: Frontend registration failed!\n");
-			dvb_frontend_detach(budget_ci->budget.dvb_frontend);
-			budget_ci->budget.dvb_frontend = NULL;
-		}
-	}
-}
-
-static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
-{
-	struct budget_ci *budget_ci;
-	int err;
-
-	budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL);
-	if (!budget_ci) {
-		err = -ENOMEM;
-		goto out1;
-	}
-
-	dprintk(2, "budget_ci: %p\n", budget_ci);
-
-	dev->ext_priv = budget_ci;
-
-	err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE,
-				adapter_nr);
-	if (err)
-		goto out2;
-
-	err = msp430_ir_init(budget_ci);
-	if (err)
-		goto out3;
-
-	ciintf_init(budget_ci);
-
-	budget_ci->budget.dvb_adapter.priv = budget_ci;
-	frontend_init(budget_ci);
-
-	ttpci_budget_init_hooks(&budget_ci->budget);
-
-	return 0;
-
-out3:
-	ttpci_budget_deinit(&budget_ci->budget);
-out2:
-	kfree(budget_ci);
-out1:
-	return err;
-}
-
-static int budget_ci_detach(struct saa7146_dev *dev)
-{
-	struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
-	struct saa7146_dev *saa = budget_ci->budget.dev;
-	int err;
-
-	if (budget_ci->budget.ci_present)
-		ciintf_deinit(budget_ci);
-	msp430_ir_deinit(budget_ci);
-	if (budget_ci->budget.dvb_frontend) {
-		dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
-		dvb_frontend_detach(budget_ci->budget.dvb_frontend);
-	}
-	err = ttpci_budget_deinit(&budget_ci->budget);
-
-	// disable frontend and CI interface
-	saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
-
-	kfree(budget_ci);
-
-	return err;
-}
-
-static struct saa7146_extension budget_extension;
-
-MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
-MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
-MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T	 PCI", BUDGET_TT);
-MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
-MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
-MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT);
-MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT);
-MAKE_BUDGET_INFO(ttbs1500b, "TT-Budget S-1500B PCI", BUDGET_TT);
-
-static struct pci_device_id pci_tbl[] = {
-	MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
-	MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
-	MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
-	MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
-	MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
-	MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
-	MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a),
-	MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019),
-	MAKE_EXTENSION_PCI(ttbs1500b, 0x13c2, 0x101b),
-	{
-	 .vendor = 0,
-	 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci_tbl);
-
-static struct saa7146_extension budget_extension = {
-	.name = "budget_ci dvb",
-	.flags = SAA7146_USE_I2C_IRQ,
-
-	.module = THIS_MODULE,
-	.pci_tbl = &pci_tbl[0],
-	.attach = budget_ci_attach,
-	.detach = budget_ci_detach,
-
-	.irq_mask = MASK_03 | MASK_06 | MASK_10,
-	.irq_func = budget_ci_irq,
-};
-
-static int __init budget_ci_init(void)
-{
-	return saa7146_register_extension(&budget_extension);
-}
-
-static void __exit budget_ci_exit(void)
-{
-	saa7146_unregister_extension(&budget_extension);
-}
-
-module_init(budget_ci_init);
-module_exit(budget_ci_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
-MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
-		   "budget PCI DVB cards w/ CI-module produced by "
-		   "Siemens, Technotrend, Hauppauge");
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
deleted file mode 100644
index 37d02fe..0000000
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ /dev/null
@@ -1,602 +0,0 @@
-/*
- * budget-core.c: driver for the SAA7146 based Budget DVB cards
- *
- * Compiled from various sources by Michael Hunold <michael@mihu.de>
- *
- * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
- *
- * Copyright (C) 1999-2002 Ralph  Metzler
- *			 & Marcus Metzler for convergence integrated media GmbH
- *
- * 26feb2004 Support for FS Activy Card (Grundig tuner) by
- *	     Michael Dreher <michael@5dot1.de>,
- *	     Oliver Endriss <o.endriss@gmx.de>,
- *	     Andreas 'randy' Weinberger
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org/ 
- */
-
-
-#include "budget.h"
-#include "ttpci-eeprom.h"
-
-#define TS_WIDTH		(2 * TS_SIZE)
-#define TS_WIDTH_ACTIVY		TS_SIZE
-#define TS_WIDTH_DVBC		TS_SIZE
-#define TS_HEIGHT_MASK		0xf00
-#define TS_HEIGHT_MASK_ACTIVY	0xc00
-#define TS_HEIGHT_MASK_DVBC	0xe00
-#define TS_MIN_BUFSIZE_K	188
-#define TS_MAX_BUFSIZE_K	1410
-#define TS_MAX_BUFSIZE_K_ACTIVY	564
-#define TS_MAX_BUFSIZE_K_DVBC	1316
-#define BUFFER_WARNING_WAIT	(30*HZ)
-
-int budget_debug;
-static int dma_buffer_size = TS_MIN_BUFSIZE_K;
-module_param_named(debug, budget_debug, int, 0644);
-module_param_named(bufsize, dma_buffer_size, int, 0444);
-MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off).");
-MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)");
-
-/****************************************************************************
- * TT budget / WinTV Nova
- ****************************************************************************/
-
-static int stop_ts_capture(struct budget *budget)
-{
-	dprintk(2, "budget: %p\n", budget);
-
-	saa7146_write(budget->dev, MC1, MASK_20);	// DMA3 off
-	SAA7146_IER_DISABLE(budget->dev, MASK_10);
-	return 0;
-}
-
-static int start_ts_capture(struct budget *budget)
-{
-	struct saa7146_dev *dev = budget->dev;
-
-	dprintk(2, "budget: %p\n", budget);
-
-	if (!budget->feeding || !budget->fe_synced)
-		return 0;
-
-	saa7146_write(dev, MC1, MASK_20);	// DMA3 off
-
-	memset(budget->grabbing, 0x00, budget->buffer_size);
-
-	saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000));
-
-	budget->ttbp = 0;
-
-	/*
-	 *  Signal path on the Activy:
-	 *
-	 *  tuner -> SAA7146 port A -> SAA7146 BRS -> SAA7146 DMA3 -> memory
-	 *
-	 *  Since the tuner feeds 204 bytes packets into the SAA7146,
-	 *  DMA3 is configured to strip the trailing 16 FEC bytes:
-	 *      Pitch: 188, NumBytes3: 188, NumLines3: 1024
-	 */
-
-	switch(budget->card->type) {
-	case BUDGET_FS_ACTIVY:
-		saa7146_write(dev, DD1_INIT, 0x04000000);
-		saa7146_write(dev, MC2, (MASK_09 | MASK_25));
-		saa7146_write(dev, BRS_CTRL, 0x00000000);
-		break;
-	case BUDGET_PATCH:
-		saa7146_write(dev, DD1_INIT, 0x00000200);
-		saa7146_write(dev, MC2, (MASK_10 | MASK_26));
-		saa7146_write(dev, BRS_CTRL, 0x60000000);
-		break;
-	case BUDGET_CIN1200C_MK3:
-	case BUDGET_KNC1C_MK3:
-	case BUDGET_KNC1C_TDA10024:
-	case BUDGET_KNC1CP_MK3:
-		if (budget->video_port == BUDGET_VIDEO_PORTA) {
-			saa7146_write(dev, DD1_INIT, 0x06000200);
-			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
-			saa7146_write(dev, BRS_CTRL, 0x00000000);
-		} else {
-			saa7146_write(dev, DD1_INIT, 0x00000600);
-			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
-			saa7146_write(dev, BRS_CTRL, 0x60000000);
-		}
-		break;
-	default:
-		if (budget->video_port == BUDGET_VIDEO_PORTA) {
-			saa7146_write(dev, DD1_INIT, 0x06000200);
-			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
-			saa7146_write(dev, BRS_CTRL, 0x00000000);
-		} else {
-			saa7146_write(dev, DD1_INIT, 0x02000600);
-			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
-			saa7146_write(dev, BRS_CTRL, 0x60000000);
-		}
-	}
-
-	saa7146_write(dev, MC2, (MASK_08 | MASK_24));
-	mdelay(10);
-
-	saa7146_write(dev, BASE_ODD3, 0);
-	if (budget->buffer_size > budget->buffer_height * budget->buffer_width) {
-		// using odd/even buffers
-		saa7146_write(dev, BASE_EVEN3, budget->buffer_height * budget->buffer_width);
-	} else {
-		// using a single buffer
-		saa7146_write(dev, BASE_EVEN3, 0);
-	}
-	saa7146_write(dev, PROT_ADDR3, budget->buffer_size);
-	saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90);
-
-	saa7146_write(dev, PITCH3, budget->buffer_width);
-	saa7146_write(dev, NUM_LINE_BYTE3,
-			(budget->buffer_height << 16) | budget->buffer_width);
-
-	saa7146_write(dev, MC2, (MASK_04 | MASK_20));
-
-	SAA7146_ISR_CLEAR(budget->dev, MASK_10);	/* VPE */
-	SAA7146_IER_ENABLE(budget->dev, MASK_10);	/* VPE */
-	saa7146_write(dev, MC1, (MASK_04 | MASK_20));	/* DMA3 on */
-
-	return 0;
-}
-
-static int budget_read_fe_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-	struct budget *budget = (struct budget *) fe->dvb->priv;
-	int synced;
-	int ret;
-
-	if (budget->read_fe_status)
-		ret = budget->read_fe_status(fe, status);
-	else
-		ret = -EINVAL;
-
-	if (!ret) {
-		synced = (*status & FE_HAS_LOCK);
-		if (synced != budget->fe_synced) {
-			budget->fe_synced = synced;
-			spin_lock(&budget->feedlock);
-			if (synced)
-				start_ts_capture(budget);
-			else
-				stop_ts_capture(budget);
-			spin_unlock(&budget->feedlock);
-		}
-	}
-	return ret;
-}
-
-static void vpeirq(unsigned long data)
-{
-	struct budget *budget = (struct budget *) data;
-	u8 *mem = (u8 *) (budget->grabbing);
-	u32 olddma = budget->ttbp;
-	u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
-	u32 count;
-
-	/* Ensure streamed PCI data is synced to CPU */
-	pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE);
-
-	/* nearest lower position divisible by 188 */
-	newdma -= newdma % 188;
-
-	if (newdma >= budget->buffer_size)
-		return;
-
-	budget->ttbp = newdma;
-
-	if (budget->feeding == 0 || newdma == olddma)
-		return;
-
-	if (newdma > olddma) {	/* no wraparound, dump olddma..newdma */
-		count = newdma - olddma;
-		dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188);
-	} else {		/* wraparound, dump olddma..buflen and 0..newdma */
-		count = budget->buffer_size - olddma;
-		dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188);
-		count += newdma;
-		dvb_dmx_swfilter_packets(&budget->demux, mem, newdma / 188);
-	}
-
-	if (count > budget->buffer_warning_threshold)
-		budget->buffer_warnings++;
-
-	if (budget->buffer_warnings && time_after(jiffies, budget->buffer_warning_time)) {
-		printk("%s %s: used %d times >80%% of buffer (%u bytes now)\n",
-			budget->dev->name, __func__, budget->buffer_warnings, count);
-		budget->buffer_warning_time = jiffies + BUFFER_WARNING_WAIT;
-		budget->buffer_warnings = 0;
-	}
-}
-
-
-int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count,
-			  int uselocks, int nobusyloop)
-{
-	struct saa7146_dev *saa = budget->dev;
-	int result = 0;
-	unsigned long flags = 0;
-
-	if (count > 4 || count <= 0)
-		return 0;
-
-	if (uselocks)
-		spin_lock_irqsave(&budget->debilock, flags);
-
-	if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
-		if (uselocks)
-			spin_unlock_irqrestore(&budget->debilock, flags);
-		return result;
-	}
-
-	saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
-	saa7146_write(saa, DEBI_CONFIG, config);
-	saa7146_write(saa, DEBI_PAGE, 0);
-	saa7146_write(saa, MC2, (2 << 16) | 2);
-
-	if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
-		if (uselocks)
-			spin_unlock_irqrestore(&budget->debilock, flags);
-		return result;
-	}
-
-	result = saa7146_read(saa, DEBI_AD);
-	result &= (0xffffffffUL >> ((4 - count) * 8));
-
-	if (uselocks)
-		spin_unlock_irqrestore(&budget->debilock, flags);
-
-	return result;
-}
-
-int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr,
-			   int count, u32 value, int uselocks, int nobusyloop)
-{
-	struct saa7146_dev *saa = budget->dev;
-	unsigned long flags = 0;
-	int result;
-
-	if (count > 4 || count <= 0)
-		return 0;
-
-	if (uselocks)
-		spin_lock_irqsave(&budget->debilock, flags);
-
-	if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
-		if (uselocks)
-			spin_unlock_irqrestore(&budget->debilock, flags);
-		return result;
-	}
-
-	saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x00000 | (addr & 0xffff));
-	saa7146_write(saa, DEBI_CONFIG, config);
-	saa7146_write(saa, DEBI_PAGE, 0);
-	saa7146_write(saa, DEBI_AD, value);
-	saa7146_write(saa, MC2, (2 << 16) | 2);
-
-	if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
-		if (uselocks)
-			spin_unlock_irqrestore(&budget->debilock, flags);
-		return result;
-	}
-
-	if (uselocks)
-		spin_unlock_irqrestore(&budget->debilock, flags);
-	return 0;
-}
-
-
-/****************************************************************************
- * DVB API SECTION
- ****************************************************************************/
-
-static int budget_start_feed(struct dvb_demux_feed *feed)
-{
-	struct dvb_demux *demux = feed->demux;
-	struct budget *budget = (struct budget *) demux->priv;
-	int status = 0;
-
-	dprintk(2, "budget: %p\n", budget);
-
-	if (!demux->dmx.frontend)
-		return -EINVAL;
-
-	spin_lock(&budget->feedlock);
-	feed->pusi_seen = 0; /* have a clean section start */
-	if (budget->feeding++ == 0)
-		status = start_ts_capture(budget);
-	spin_unlock(&budget->feedlock);
-	return status;
-}
-
-static int budget_stop_feed(struct dvb_demux_feed *feed)
-{
-	struct dvb_demux *demux = feed->demux;
-	struct budget *budget = (struct budget *) demux->priv;
-	int status = 0;
-
-	dprintk(2, "budget: %p\n", budget);
-
-	spin_lock(&budget->feedlock);
-	if (--budget->feeding == 0)
-		status = stop_ts_capture(budget);
-	spin_unlock(&budget->feedlock);
-	return status;
-}
-
-static int budget_register(struct budget *budget)
-{
-	struct dvb_demux *dvbdemux = &budget->demux;
-	int ret;
-
-	dprintk(2, "budget: %p\n", budget);
-
-	dvbdemux->priv = (void *) budget;
-
-	dvbdemux->filternum = 256;
-	dvbdemux->feednum = 256;
-	dvbdemux->start_feed = budget_start_feed;
-	dvbdemux->stop_feed = budget_stop_feed;
-	dvbdemux->write_to_decoder = NULL;
-
-	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING |
-				      DMX_MEMORY_BASED_FILTERING);
-
-	dvb_dmx_init(&budget->demux);
-
-	budget->dmxdev.filternum = 256;
-	budget->dmxdev.demux = &dvbdemux->dmx;
-	budget->dmxdev.capabilities = 0;
-
-	dvb_dmxdev_init(&budget->dmxdev, &budget->dvb_adapter);
-
-	budget->hw_frontend.source = DMX_FRONTEND_0;
-
-	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->hw_frontend);
-
-	if (ret < 0)
-		return ret;
-
-	budget->mem_frontend.source = DMX_MEMORY_FE;
-	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->mem_frontend);
-	if (ret < 0)
-		return ret;
-
-	ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &budget->hw_frontend);
-	if (ret < 0)
-		return ret;
-
-	dvb_net_init(&budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx);
-
-	return 0;
-}
-
-static void budget_unregister(struct budget *budget)
-{
-	struct dvb_demux *dvbdemux = &budget->demux;
-
-	dprintk(2, "budget: %p\n", budget);
-
-	dvb_net_release(&budget->dvb_net);
-
-	dvbdemux->dmx.close(&dvbdemux->dmx);
-	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->hw_frontend);
-	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->mem_frontend);
-
-	dvb_dmxdev_release(&budget->dmxdev);
-	dvb_dmx_release(&budget->demux);
-}
-
-int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
-		      struct saa7146_pci_extension_data *info,
-		      struct module *owner, short *adapter_nums)
-{
-	int ret = 0;
-	struct budget_info *bi = info->ext_priv;
-	int max_bufsize;
-	int height_mask;
-
-	memset(budget, 0, sizeof(struct budget));
-
-	dprintk(2, "dev: %p, budget: %p\n", dev, budget);
-
-	budget->card = bi;
-	budget->dev = (struct saa7146_dev *) dev;
-
-	switch(budget->card->type) {
-	case BUDGET_FS_ACTIVY:
-		budget->buffer_width = TS_WIDTH_ACTIVY;
-		max_bufsize = TS_MAX_BUFSIZE_K_ACTIVY;
-		height_mask = TS_HEIGHT_MASK_ACTIVY;
-		break;
-
-	case BUDGET_KNC1C:
-	case BUDGET_KNC1CP:
-	case BUDGET_CIN1200C:
-	case BUDGET_KNC1C_MK3:
-	case BUDGET_KNC1C_TDA10024:
-	case BUDGET_KNC1CP_MK3:
-	case BUDGET_CIN1200C_MK3:
-		budget->buffer_width = TS_WIDTH_DVBC;
-		max_bufsize = TS_MAX_BUFSIZE_K_DVBC;
-		height_mask = TS_HEIGHT_MASK_DVBC;
-		break;
-
-	default:
-		budget->buffer_width = TS_WIDTH;
-		max_bufsize = TS_MAX_BUFSIZE_K;
-		height_mask = TS_HEIGHT_MASK;
-	}
-
-	if (dma_buffer_size < TS_MIN_BUFSIZE_K)
-		dma_buffer_size = TS_MIN_BUFSIZE_K;
-	else if (dma_buffer_size > max_bufsize)
-		dma_buffer_size = max_bufsize;
-
-	budget->buffer_height = dma_buffer_size * 1024 / budget->buffer_width;
-	if (budget->buffer_height > 0xfff) {
-		budget->buffer_height /= 2;
-		budget->buffer_height &= height_mask;
-		budget->buffer_size = 2 * budget->buffer_height * budget->buffer_width;
-	} else {
-		budget->buffer_height &= height_mask;
-		budget->buffer_size = budget->buffer_height * budget->buffer_width;
-	}
-	budget->buffer_warning_threshold = budget->buffer_size * 80/100;
-	budget->buffer_warnings = 0;
-	budget->buffer_warning_time = jiffies;
-
-	dprintk(2, "%s: buffer type = %s, width = %d, height = %d\n",
-		budget->dev->name,
-		budget->buffer_size > budget->buffer_width * budget->buffer_height ? "odd/even" : "single",
-		budget->buffer_width, budget->buffer_height);
-	printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size);
-
-	ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name,
-				   owner, &budget->dev->pci->dev, adapter_nums);
-	if (ret < 0)
-		return ret;
-
-	/* set dd1 stream a & b */
-	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
-	saa7146_write(dev, MC2, (MASK_09 | MASK_25));
-	saa7146_write(dev, MC2, (MASK_10 | MASK_26));
-	saa7146_write(dev, DD1_INIT, 0x02000000);
-	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
-
-	if (bi->type != BUDGET_FS_ACTIVY)
-		budget->video_port = BUDGET_VIDEO_PORTB;
-	else
-		budget->video_port = BUDGET_VIDEO_PORTA;
-	spin_lock_init(&budget->feedlock);
-	spin_lock_init(&budget->debilock);
-
-	/* the Siemens DVB needs this if you want to have the i2c chips
-	   get recognized before the main driver is loaded */
-	if (bi->type != BUDGET_FS_ACTIVY)
-		saa7146_write(dev, GPIO_CTRL, 0x500000);	/* GPIO 3 = 1 */
-
-	strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name));
-
-	saa7146_i2c_adapter_prepare(dev, &budget->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120);
-	strcpy(budget->i2c_adap.name, budget->card->name);
-
-	if (i2c_add_adapter(&budget->i2c_adap) < 0) {
-		ret = -ENOMEM;
-		goto err_dvb_unregister;
-	}
-
-	ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac);
-
-	budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, budget->buffer_size, &budget->pt);
-	if (NULL == budget->grabbing) {
-		ret = -ENOMEM;
-		goto err_del_i2c;
-	}
-
-	saa7146_write(dev, PCI_BT_V1, 0x001c0000);
-	/* upload all */
-	saa7146_write(dev, GPIO_CTRL, 0x000000);
-
-	tasklet_init(&budget->vpe_tasklet, vpeirq, (unsigned long) budget);
-
-	/* frontend power on */
-	if (bi->type != BUDGET_FS_ACTIVY)
-		saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
-
-	if ((ret = budget_register(budget)) == 0)
-		return 0; /* Everything OK */
-
-	/* An error occurred, cleanup resources */
-	saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt);
-
-err_del_i2c:
-	i2c_del_adapter(&budget->i2c_adap);
-
-err_dvb_unregister:
-	dvb_unregister_adapter(&budget->dvb_adapter);
-
-	return ret;
-}
-
-void ttpci_budget_init_hooks(struct budget *budget)
-{
-	if (budget->dvb_frontend && !budget->read_fe_status) {
-		budget->read_fe_status = budget->dvb_frontend->ops.read_status;
-		budget->dvb_frontend->ops.read_status = budget_read_fe_status;
-	}
-}
-
-int ttpci_budget_deinit(struct budget *budget)
-{
-	struct saa7146_dev *dev = budget->dev;
-
-	dprintk(2, "budget: %p\n", budget);
-
-	budget_unregister(budget);
-
-	tasklet_kill(&budget->vpe_tasklet);
-
-	saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt);
-
-	i2c_del_adapter(&budget->i2c_adap);
-
-	dvb_unregister_adapter(&budget->dvb_adapter);
-
-	return 0;
-}
-
-void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr)
-{
-	struct budget *budget = (struct budget *) dev->ext_priv;
-
-	dprintk(8, "dev: %p, budget: %p\n", dev, budget);
-
-	if (*isr & MASK_10)
-		tasklet_schedule(&budget->vpe_tasklet);
-}
-
-void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port)
-{
-	struct budget *budget = (struct budget *) dev->ext_priv;
-
-	spin_lock(&budget->feedlock);
-	budget->video_port = video_port;
-	if (budget->feeding) {
-		stop_ts_capture(budget);
-		start_ts_capture(budget);
-	}
-	spin_unlock(&budget->feedlock);
-}
-
-EXPORT_SYMBOL_GPL(ttpci_budget_debiread);
-EXPORT_SYMBOL_GPL(ttpci_budget_debiwrite);
-EXPORT_SYMBOL_GPL(ttpci_budget_init);
-EXPORT_SYMBOL_GPL(ttpci_budget_init_hooks);
-EXPORT_SYMBOL_GPL(ttpci_budget_deinit);
-EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler);
-EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port);
-EXPORT_SYMBOL_GPL(budget_debug);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
deleted file mode 100644
index 2cb35c2..0000000
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ /dev/null
@@ -1,680 +0,0 @@
-/*
- * budget-patch.c: driver for Budget Patch,
- * hardware modification of DVB-S cards enabling full TS
- *
- * Written by Emard <emard@softhome.net>
- *
- * Original idea by Roberto Deza <rdeza@unav.es>
- *
- * Special thanks to Holger Waechtler, Michael Hunold, Marian Durkovic
- * and Metzlerbros
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org/ 
- */
-
-#include "av7110.h"
-#include "av7110_hw.h"
-#include "budget.h"
-#include "stv0299.h"
-#include "ves1x93.h"
-#include "tda8083.h"
-
-#include "bsru6.h"
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define budget_patch budget
-
-static struct saa7146_extension budget_extension;
-
-MAKE_BUDGET_INFO(ttbp, "TT-Budget/Patch DVB-S 1.x PCI", BUDGET_PATCH);
-//MAKE_BUDGET_INFO(satel,"TT-Budget/Patch SATELCO PCI", BUDGET_TT_HW_DISEQC);
-
-static struct pci_device_id pci_tbl[] = {
-	MAKE_EXTENSION_PCI(ttbp,0x13c2, 0x0000),
-//        MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
-	{
-		.vendor    = 0,
-	}
-};
-
-/* those lines are for budget-patch to be tried
-** on a true budget card and observe the
-** behaviour of VSYNC generated by rps1.
-** this code was shamelessly copy/pasted from budget.c
-*/
-static void gpio_Set22K (struct budget *budget, int state)
-{
-	struct saa7146_dev *dev=budget->dev;
-	dprintk(2, "budget: %p\n", budget);
-	saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO));
-}
-
-/* Diseqc functions only for TT Budget card */
-/* taken from the Skyvision DVB driver by
-   Ralph Metzler <rjkm@metzlerbros.de> */
-
-static void DiseqcSendBit (struct budget *budget, int data)
-{
-	struct saa7146_dev *dev=budget->dev;
-	dprintk(2, "budget: %p\n", budget);
-
-	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
-	udelay(data ? 500 : 1000);
-	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
-	udelay(data ? 1000 : 500);
-}
-
-static void DiseqcSendByte (struct budget *budget, int data)
-{
-	int i, par=1, d;
-
-	dprintk(2, "budget: %p\n", budget);
-
-	for (i=7; i>=0; i--) {
-		d = (data>>i)&1;
-		par ^= d;
-		DiseqcSendBit(budget, d);
-	}
-
-	DiseqcSendBit(budget, par);
-}
-
-static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst)
-{
-	struct saa7146_dev *dev=budget->dev;
-	int i;
-
-	dprintk(2, "budget: %p\n", budget);
-
-	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
-	mdelay(16);
-
-	for (i=0; i<len; i++)
-		DiseqcSendByte(budget, msg[i]);
-
-	mdelay(16);
-
-	if (burst!=-1) {
-		if (burst)
-			DiseqcSendByte(budget, 0xff);
-		else {
-			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
-			mdelay(12);
-			udelay(500);
-			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
-		}
-		msleep(20);
-	}
-
-	return 0;
-}
-
-/* shamelessly copy/pasted from budget.c
-*/
-static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
-	struct budget* budget = (struct budget*) fe->dvb->priv;
-
-	switch (tone) {
-	case SEC_TONE_ON:
-		gpio_Set22K (budget, 1);
-		break;
-
-	case SEC_TONE_OFF:
-		gpio_Set22K (budget, 0);
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
-{
-	struct budget* budget = (struct budget*) fe->dvb->priv;
-
-	SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
-
-	return 0;
-}
-
-static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
-{
-	struct budget* budget = (struct budget*) fe->dvb->priv;
-
-	SendDiSEqCMsg (budget, 0, NULL, minicmd);
-
-	return 0;
-}
-
-static int budget_av7110_send_fw_cmd(struct budget_patch *budget, u16* buf, int length)
-{
-	int i;
-
-	dprintk(2, "budget: %p\n", budget);
-
-	for (i = 2; i < length; i++)
-	{
-		  ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2*i, 2, (u32) buf[i], 0,0);
-		  msleep(5);
-	}
-	if (length)
-		  ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, (u32) buf[1], 0,0);
-	else
-		  ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, 0, 0,0);
-	msleep(5);
-	ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND, 2, (u32) buf[0], 0,0);
-	msleep(5);
-	return 0;
-}
-
-static void av7110_set22k(struct budget_patch *budget, int state)
-{
-	u16 buf[2] = {( COMTYPE_AUDIODAC << 8) | (state ? ON22K : OFF22K), 0};
-
-	dprintk(2, "budget: %p\n", budget);
-	budget_av7110_send_fw_cmd(budget, buf, 2);
-}
-
-static int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg, int burst)
-{
-	int i;
-	u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) | SendDiSEqC),
-		16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
-	dprintk(2, "budget: %p\n", budget);
-
-	if (len>10)
-		len=10;
-
-	buf[1] = len+2;
-	buf[2] = len;
-
-	if (burst != -1)
-		buf[3]=burst ? 0x01 : 0x00;
-	else
-		buf[3]=0xffff;
-
-	for (i=0; i<len; i++)
-		buf[i+4]=msg[i];
-
-	budget_av7110_send_fw_cmd(budget, buf, 18);
-	return 0;
-}
-
-static int budget_patch_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
-	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
-
-	switch (tone) {
-	case SEC_TONE_ON:
-		av7110_set22k (budget, 1);
-		break;
-
-	case SEC_TONE_OFF:
-		av7110_set22k (budget, 0);
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
-{
-	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
-
-	av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0);
-
-	return 0;
-}
-
-static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
-{
-	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
-
-	av7110_send_diseqc_msg (budget, 0, NULL, minicmd);
-
-	return 0;
-}
-
-static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
-	u8 pwr = 0;
-	u8 buf[4];
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-	u32 div = (p->frequency + 479500) / 125;
-
-	if (p->frequency > 2000000)
-		pwr = 3;
-	else if (p->frequency > 1800000)
-		pwr = 2;
-	else if (p->frequency > 1600000)
-		pwr = 1;
-	else if (p->frequency > 1200000)
-		pwr = 0;
-	else if (p->frequency >= 1100000)
-		pwr = 1;
-	else pwr = 2;
-
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = div & 0xff;
-	buf[2] = ((div & 0x18000) >> 10) | 0x95;
-	buf[3] = (pwr << 6) | 0x30;
-
-	// NOTE: since we're using a prescaler of 2, we set the
-	// divisor frequency to 62.5kHz and divide by 125 above
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-	return 0;
-}
-
-static struct ves1x93_config alps_bsrv2_config = {
-	.demod_address = 0x08,
-	.xin = 90100000UL,
-	.invert_pwm = 0,
-};
-
-static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
-	u32 div;
-	u8 data[4];
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	div = p->frequency / 125;
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0x8e;
-	data[3] = 0x00;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-	return 0;
-}
-
-static struct tda8083_config grundig_29504_451_config = {
-	.demod_address = 0x68,
-};
-
-static void frontend_init(struct budget_patch* budget)
-{
-	switch(budget->dev->pci->subsystem_device) {
-	case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X
-	case 0x1013: // SATELCO Multimedia PCI
-
-		// try the ALPS BSRV2 first of all
-		budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap);
-		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
-			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
-			budget->dvb_frontend->ops.diseqc_send_burst = budget_patch_diseqc_send_burst;
-			budget->dvb_frontend->ops.set_tone = budget_patch_set_tone;
-			break;
-		}
-
-		// try the ALPS BSRU6 now
-		budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
-		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
-			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
-
-			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
-			budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
-			budget->dvb_frontend->ops.set_tone = budget_set_tone;
-			break;
-		}
-
-		// Try the grundig 29504-451
-		budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap);
-		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
-			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
-			budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
-			budget->dvb_frontend->ops.set_tone = budget_set_tone;
-			break;
-		}
-		break;
-	}
-
-	if (budget->dvb_frontend == NULL) {
-		printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
-		       budget->dev->pci->vendor,
-		       budget->dev->pci->device,
-		       budget->dev->pci->subsystem_vendor,
-		       budget->dev->pci->subsystem_device);
-	} else {
-		if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
-			printk("budget-av: Frontend registration failed!\n");
-			dvb_frontend_detach(budget->dvb_frontend);
-			budget->dvb_frontend = NULL;
-		}
-	}
-}
-
-/* written by Emard */
-static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
-{
-	struct budget_patch *budget;
-	int err;
-	int count = 0;
-	int detected = 0;
-
-#define PATCH_RESET 0
-#define RPS_IRQ 0
-#define HPS_SETUP 0
-#if PATCH_RESET
-	saa7146_write(dev, MC1, MASK_31);
-	msleep(40);
-#endif
-#if HPS_SETUP
-	// initialize registers. Better to have it like this
-	// than leaving something unconfigured
-	saa7146_write(dev, DD1_STREAM_B, 0);
-	// port B VSYNC at rising edge
-	saa7146_write(dev, DD1_INIT, 0x00000200);  // have this in budget-core too!
-	saa7146_write(dev, BRS_CTRL, 0x00000000);  // VBI
-
-	// debi config
-	// saa7146_write(dev, DEBI_CONFIG, MASK_30|MASK_28|MASK_18);
-
-	// zero all HPS registers
-	saa7146_write(dev, HPS_H_PRESCALE, 0);                  // r68
-	saa7146_write(dev, HPS_H_SCALE, 0);                     // r6c
-	saa7146_write(dev, BCS_CTRL, 0);                        // r70
-	saa7146_write(dev, HPS_V_SCALE, 0);                     // r60
-	saa7146_write(dev, HPS_V_GAIN, 0);                      // r64
-	saa7146_write(dev, CHROMA_KEY_RANGE, 0);                // r74
-	saa7146_write(dev, CLIP_FORMAT_CTRL, 0);                // r78
-	// Set HPS prescaler for port B input
-	saa7146_write(dev, HPS_CTRL, (1<<30) | (0<<29) | (1<<28) | (0<<12) );
-	saa7146_write(dev, MC2,
-	  0 * (MASK_08 | MASK_24)  |   // BRS control
-	  0 * (MASK_09 | MASK_25)  |   // a
-	  0 * (MASK_10 | MASK_26)  |   // b
-	  1 * (MASK_06 | MASK_22)  |   // HPS_CTRL1
-	  1 * (MASK_05 | MASK_21)  |   // HPS_CTRL2
-	  0 * (MASK_01 | MASK_15)      // DEBI
-	   );
-#endif
-	// Disable RPS1 and RPS0
-	saa7146_write(dev, MC1, ( MASK_29 | MASK_28));
-	// RPS1 timeout disable
-	saa7146_write(dev, RPS_TOV1, 0);
-
-	// code for autodetection
-	// will wait for VBI_B event (vertical blank at port B)
-	// and will reset GPIO3 after VBI_B is detected.
-	// (GPIO3 should be raised high by CPU to
-	// test if GPIO3 will generate vertical blank signal
-	// in budget patch GPIO3 is connected to VSYNC_B
-	count = 0;
-#if 0
-	WRITE_RPS1(CMD_UPLOAD |
-	  MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 );
-#endif
-	WRITE_RPS1(CMD_PAUSE | EVT_VBI_B);
-	WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
-	WRITE_RPS1(GPIO3_MSK);
-	WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
-#if RPS_IRQ
-	// issue RPS1 interrupt to increment counter
-	WRITE_RPS1(CMD_INTERRUPT);
-	// at least a NOP is neede between two interrupts
-	WRITE_RPS1(CMD_NOP);
-	// interrupt again
-	WRITE_RPS1(CMD_INTERRUPT);
-#endif
-	WRITE_RPS1(CMD_STOP);
-
-#if RPS_IRQ
-	// set event counter 1 source as RPS1 interrupt (0x03)          (rE4 p53)
-	// use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
-	// use 0x15 to track VPE  interrupts - increase by 1 every vpeirq() is called
-	saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
-	// set event counter 1 threshold to maximum allowed value        (rEC p55)
-	saa7146_write(dev, ECT1R,  0x3fff );
-#endif
-	// Fix VSYNC level
-	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
-	// Set RPS1 Address register to point to RPS code               (r108 p42)
-	saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
-	// Enable RPS1,                                                 (rFC p33)
-	saa7146_write(dev, MC1, (MASK_13 | MASK_29 ));
-
-
-	mdelay(50);
-	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
-	mdelay(150);
-
-
-	if( (saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0)
-		detected = 1;
-
-#if RPS_IRQ
-	printk("Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff );
-#endif
-	// Disable RPS1
-	saa7146_write(dev, MC1, ( MASK_29 ));
-
-	if(detected == 0)
-		printk("budget-patch not detected or saa7146 in non-default state.\n"
-		       "try enabling ressetting of 7146 with MASK_31 in MC1 register\n");
-
-	else
-		printk("BUDGET-PATCH DETECTED.\n");
-
-
-/*      OLD (Original design by Roberto Deza):
-**      This code will setup the SAA7146_RPS1 to generate a square
-**      wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of
-**      TS_WIDTH packets) has been acquired on SAA7146_D1B video port;
-**      then, this GPIO3 output which is connected to the D1B_VSYNC
-**      input, will trigger the acquisition of the alternate field
-**      and so on.
-**      Currently, the TT_budget / WinTV_Nova cards have two ICs
-**      (74HCT4040, LVC74) for the generation of this VSYNC signal,
-**      which seems that can be done perfectly without this :-)).
-*/
-
-/*      New design (By Emard)
-**      this rps1 code will copy internal HS event to GPIO3 pin.
-**      GPIO3 is in budget-patch hardware connected to port B VSYNC
-
-**      HS is an internal event of 7146, accessible with RPS
-**      and temporarily raised high every n lines
-**      (n in defined in the RPS_THRESH1 counter threshold)
-**      I think HS is raised high on the beginning of the n-th line
-**      and remains high until this n-th line that triggered
-**      it is completely received. When the reception of n-th line
-**      ends, HS is lowered.
-
-**      To transmit data over DMA, 7146 needs changing state at
-**      port B VSYNC pin. Any changing of port B VSYNC will
-**      cause some DMA data transfer, with more or less packets loss.
-**      It depends on the phase and frequency of VSYNC and
-**      the way of 7146 is instructed to trigger on port B (defined
-**      in DD1_INIT register, 3rd nibble from the right valid
-**      numbers are 0-7, see datasheet)
-**
-**      The correct triggering can minimize packet loss,
-**      dvbtraffic should give this stable bandwidths:
-**        22k transponder = 33814 kbit/s
-**      27.5k transponder = 38045 kbit/s
-**      by experiment it is found that the best results
-**      (stable bandwidths and almost no packet loss)
-**      are obtained using DD1_INIT triggering number 2
-**      (Va at rising edge of VS Fa = HS x VS-failing forced toggle)
-**      and a VSYNC phase that occurs in the middle of DMA transfer
-**      (about byte 188*512=96256 in the DMA window).
-**
-**      Phase of HS is still not clear to me how to control,
-**      It just happens to be so. It can be seen if one enables
-**      RPS_IRQ and print Event Counter 1 in vpeirq(). Every
-**      time RPS_INTERRUPT is called, the Event Counter 1 will
-**      increment. That's how the 7146 is programmed to do event
-**      counting in this budget-patch.c
-**      I *think* HPS setting has something to do with the phase
-**      of HS but I can't be 100% sure in that.
-
-**      hardware debug note: a working budget card (including budget patch)
-**      with vpeirq() interrupt setup in mode "0x90" (every 64K) will
-**      generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes
-**      and that means 3*25=75 Hz of interrupt frequency, as seen by
-**      watch cat /proc/interrupts
-**
-**      If this frequency is 3x lower (and data received in the DMA
-**      buffer don't start with 0x47, but in the middle of packets,
-**      whose lengths appear to be like 188 292 188 104 etc.
-**      this means VSYNC line is not connected in the hardware.
-**      (check soldering pcb and pins)
-**      The same behaviour of missing VSYNC can be duplicated on budget
-**      cards, by setting DD1_INIT trigger mode 7 in 3rd nibble.
-*/
-
-	// Setup RPS1 "program" (p35)
-	count = 0;
-
-
-	// Wait Source Line Counter Threshold                           (p36)
-	WRITE_RPS1(CMD_PAUSE | EVT_HS);
-	// Set GPIO3=1                                                  (p42)
-	WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
-	WRITE_RPS1(GPIO3_MSK);
-	WRITE_RPS1(SAA7146_GPIO_OUTHI<<24);
-#if RPS_IRQ
-	// issue RPS1 interrupt
-	WRITE_RPS1(CMD_INTERRUPT);
-#endif
-	// Wait reset Source Line Counter Threshold                     (p36)
-	WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS);
-	// Set GPIO3=0                                                  (p42)
-	WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
-	WRITE_RPS1(GPIO3_MSK);
-	WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
-#if RPS_IRQ
-	// issue RPS1 interrupt
-	WRITE_RPS1(CMD_INTERRUPT);
-#endif
-	// Jump to begin of RPS program                                 (p37)
-	WRITE_RPS1(CMD_JUMP);
-	WRITE_RPS1(dev->d_rps1.dma_handle);
-
-	// Fix VSYNC level
-	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
-	// Set RPS1 Address register to point to RPS code               (r108 p42)
-	saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
-
-	if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL)))
-		return -ENOMEM;
-
-	dprintk(2, "budget: %p\n", budget);
-
-	err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr);
-	if (err) {
-		kfree(budget);
-		return err;
-	}
-
-	// Set Source Line Counter Threshold, using BRS                 (rCC p43)
-	// It generates HS event every TS_HEIGHT lines
-	// this is related to TS_WIDTH set in register
-	// NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE
-	// low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188
-	//,then RPS_THRESH1
-	// should be set to trigger every TS_HEIGHT (512) lines.
-	//
-	saa7146_write(dev, RPS_THRESH1, budget->buffer_height | MASK_12 );
-
-	// saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 );
-	// Enable RPS1                                                  (rFC p33)
-	saa7146_write(dev, MC1, (MASK_13 | MASK_29));
-
-
-	dev->ext_priv = budget;
-
-	budget->dvb_adapter.priv = budget;
-	frontend_init(budget);
-
-	ttpci_budget_init_hooks(budget);
-
-	return 0;
-}
-
-static int budget_patch_detach (struct saa7146_dev* dev)
-{
-	struct budget_patch *budget = (struct budget_patch*) dev->ext_priv;
-	int err;
-
-	if (budget->dvb_frontend) {
-		dvb_unregister_frontend(budget->dvb_frontend);
-		dvb_frontend_detach(budget->dvb_frontend);
-	}
-	err = ttpci_budget_deinit (budget);
-
-	kfree (budget);
-
-	return err;
-}
-
-static int __init budget_patch_init(void)
-{
-	return saa7146_register_extension(&budget_extension);
-}
-
-static void __exit budget_patch_exit(void)
-{
-	saa7146_unregister_extension(&budget_extension);
-}
-
-static struct saa7146_extension budget_extension = {
-	.name           = "budget_patch dvb",
-	.flags          = 0,
-
-	.module         = THIS_MODULE,
-	.pci_tbl        = pci_tbl,
-	.attach         = budget_patch_attach,
-	.detach         = budget_patch_detach,
-
-	.irq_mask       = MASK_10,
-	.irq_func       = ttpci_budget_irq10_handler,
-};
-
-module_init(budget_patch_init);
-module_exit(budget_patch_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Emard, Roberto Deza, Holger Waechtler, Michael Hunold, others");
-MODULE_DESCRIPTION("Driver for full TS modified DVB-S SAA7146+AV7110 "
-		   "based so-called Budget Patch cards");
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
deleted file mode 100644
index b21bcce..0000000
--- a/drivers/media/dvb/ttpci/budget.c
+++ /dev/null
@@ -1,811 +0,0 @@
-/*
- * budget.c: driver for the SAA7146 based Budget DVB cards
- *
- * Compiled from various sources by Michael Hunold <michael@mihu.de>
- *
- * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
- *
- * Copyright (C) 1999-2002 Ralph  Metzler
- *                       & Marcus Metzler for convergence integrated media GmbH
- *
- * 26feb2004 Support for FS Activy Card (Grundig tuner) by
- *           Michael Dreher <michael@5dot1.de>,
- *           Oliver Endriss <o.endriss@gmx.de> and
- *           Andreas 'randy' Weinberger
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org/ 
- */
-
-#include "budget.h"
-#include "stv0299.h"
-#include "ves1x93.h"
-#include "ves1820.h"
-#include "l64781.h"
-#include "tda8083.h"
-#include "s5h1420.h"
-#include "tda10086.h"
-#include "tda826x.h"
-#include "lnbp21.h"
-#include "bsru6.h"
-#include "bsbe1.h"
-#include "tdhd1.h"
-#include "stv6110x.h"
-#include "stv090x.h"
-#include "isl6423.h"
-
-static int diseqc_method;
-module_param(diseqc_method, int, 0444);
-MODULE_PARM_DESC(diseqc_method, "Select DiSEqC method for subsystem id 13c2:1003, 0: default, 1: more reliable (for newer revisions only)");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static void Set22K (struct budget *budget, int state)
-{
-	struct saa7146_dev *dev=budget->dev;
-	dprintk(2, "budget: %p\n", budget);
-	saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO));
-}
-
-/* Diseqc functions only for TT Budget card */
-/* taken from the Skyvision DVB driver by
-   Ralph Metzler <rjkm@metzlerbros.de> */
-
-static void DiseqcSendBit (struct budget *budget, int data)
-{
-	struct saa7146_dev *dev=budget->dev;
-	dprintk(2, "budget: %p\n", budget);
-
-	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
-	udelay(data ? 500 : 1000);
-	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
-	udelay(data ? 1000 : 500);
-}
-
-static void DiseqcSendByte (struct budget *budget, int data)
-{
-	int i, par=1, d;
-
-	dprintk(2, "budget: %p\n", budget);
-
-	for (i=7; i>=0; i--) {
-		d = (data>>i)&1;
-		par ^= d;
-		DiseqcSendBit(budget, d);
-	}
-
-	DiseqcSendBit(budget, par);
-}
-
-static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst)
-{
-	struct saa7146_dev *dev=budget->dev;
-	int i;
-
-	dprintk(2, "budget: %p\n", budget);
-
-	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
-	mdelay(16);
-
-	for (i=0; i<len; i++)
-		DiseqcSendByte(budget, msg[i]);
-
-	mdelay(16);
-
-	if (burst!=-1) {
-		if (burst)
-			DiseqcSendByte(budget, 0xff);
-		else {
-			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
-			mdelay(12);
-			udelay(500);
-			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
-		}
-		msleep(20);
-	}
-
-	return 0;
-}
-
-/*
- *   Routines for the Fujitsu Siemens Activy budget card
- *   22 kHz tone and DiSEqC are handled by the frontend.
- *   Voltage must be set here.
- *   GPIO 1: LNBP EN, GPIO 2: LNBP VSEL
- */
-static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
-{
-	struct saa7146_dev *dev=budget->dev;
-
-	dprintk(2, "budget: %p\n", budget);
-
-	switch (voltage) {
-		case SEC_VOLTAGE_13:
-			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
-			saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO);
-			break;
-		case SEC_VOLTAGE_18:
-			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
-			saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
-			break;
-		case SEC_VOLTAGE_OFF:
-			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO);
-			break;
-		default:
-			return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
-	struct budget* budget = (struct budget*) fe->dvb->priv;
-
-	return SetVoltage_Activy (budget, voltage);
-}
-
-static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
-	struct budget* budget = (struct budget*) fe->dvb->priv;
-
-	switch (tone) {
-	case SEC_TONE_ON:
-		Set22K (budget, 1);
-		break;
-
-	case SEC_TONE_OFF:
-		Set22K (budget, 0);
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
-{
-	struct budget* budget = (struct budget*) fe->dvb->priv;
-
-	SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
-
-	return 0;
-}
-
-static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
-{
-	struct budget* budget = (struct budget*) fe->dvb->priv;
-
-	SendDiSEqCMsg (budget, 0, NULL, minicmd);
-
-	return 0;
-}
-
-static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct budget* budget = (struct budget*) fe->dvb->priv;
-	u8 pwr = 0;
-	u8 buf[4];
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-	u32 div = (c->frequency + 479500) / 125;
-
-	if (c->frequency > 2000000)
-		pwr = 3;
-	else if (c->frequency > 1800000)
-		pwr = 2;
-	else if (c->frequency > 1600000)
-		pwr = 1;
-	else if (c->frequency > 1200000)
-		pwr = 0;
-	else if (c->frequency >= 1100000)
-		pwr = 1;
-	else pwr = 2;
-
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = div & 0xff;
-	buf[2] = ((div & 0x18000) >> 10) | 0x95;
-	buf[3] = (pwr << 6) | 0x30;
-
-	// NOTE: since we're using a prescaler of 2, we set the
-	// divisor frequency to 62.5kHz and divide by 125 above
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-	return 0;
-}
-
-static struct ves1x93_config alps_bsrv2_config =
-{
-	.demod_address = 0x08,
-	.xin = 90100000UL,
-	.invert_pwm = 0,
-};
-
-static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct budget* budget = (struct budget*) fe->dvb->priv;
-	u32 div;
-	u8 data[4];
-	struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	div = (c->frequency + 35937500 + 31250) / 62500;
-
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0x85 | ((div >> 10) & 0x60);
-	data[3] = (c->frequency < 174000000 ? 0x88 : c->frequency < 470000000 ? 0x84 : 0x81);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-	return 0;
-}
-
-static struct ves1820_config alps_tdbe2_config = {
-	.demod_address = 0x09,
-	.xin = 57840000UL,
-	.invert = 1,
-	.selagc = VES1820_SELAGC_SIGNAMPERR,
-};
-
-static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct budget *budget = fe->dvb->priv;
-	u8 *tuner_addr = fe->tuner_priv;
-	u32 div;
-	u8 cfg, cpump, band_select;
-	u8 data[4];
-	struct i2c_msg msg = { .flags = 0, .buf = data, .len = sizeof(data) };
-
-	if (tuner_addr)
-		msg.addr = *tuner_addr;
-	else
-		msg.addr = 0x61;
-
-	div = (36125000 + c->frequency) / 166666;
-
-	cfg = 0x88;
-
-	if (c->frequency < 175000000)
-		cpump = 2;
-	else if (c->frequency < 390000000)
-		cpump = 1;
-	else if (c->frequency < 470000000)
-		cpump = 2;
-	else if (c->frequency < 750000000)
-		cpump = 1;
-	else
-		cpump = 3;
-
-	if (c->frequency < 175000000)
-		band_select = 0x0e;
-	else if (c->frequency < 470000000)
-		band_select = 0x05;
-	else
-		band_select = 0x03;
-
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = ((div >> 10) & 0x60) | cfg;
-	data[3] = (cpump << 6) | band_select;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-	return 0;
-}
-
-static struct l64781_config grundig_29504_401_config = {
-	.demod_address = 0x55,
-};
-
-static struct l64781_config grundig_29504_401_config_activy = {
-	.demod_address = 0x54,
-};
-
-static u8 tuner_address_grundig_29504_401_activy = 0x60;
-
-static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct budget* budget = (struct budget*) fe->dvb->priv;
-	u32 div;
-	u8 data[4];
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	div = c->frequency / 125;
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0x8e;
-	data[3] = 0x00;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-	return 0;
-}
-
-static struct tda8083_config grundig_29504_451_config = {
-	.demod_address = 0x68,
-};
-
-static int s5h1420_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	struct budget* budget = (struct budget*) fe->dvb->priv;
-	u32 div;
-	u8 data[4];
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	div = c->frequency / 1000;
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0xc2;
-
-	if (div < 1450)
-		data[3] = 0x00;
-	else if (div < 1850)
-		data[3] = 0x40;
-	else if (div < 2000)
-		data[3] = 0x80;
-	else
-		data[3] = 0xc0;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-
-	return 0;
-}
-
-static struct s5h1420_config s5h1420_config = {
-	.demod_address = 0x53,
-	.invert = 1,
-	.cdclk_polarity = 1,
-};
-
-static struct tda10086_config tda10086_config = {
-	.demod_address = 0x0e,
-	.invert = 0,
-	.diseqc_tone = 1,
-	.xtal_freq = TDA10086_XTAL_16M,
-};
-
-static struct stv0299_config alps_bsru6_config_activy = {
-	.demod_address = 0x68,
-	.inittab = alps_bsru6_inittab,
-	.mclk = 88000000UL,
-	.invert = 1,
-	.op0_off = 1,
-	.min_delay_ms = 100,
-	.set_symbol_rate = alps_bsru6_set_symbol_rate,
-};
-
-static struct stv0299_config alps_bsbe1_config_activy = {
-	.demod_address = 0x68,
-	.inittab = alps_bsbe1_inittab,
-	.mclk = 88000000UL,
-	.invert = 1,
-	.op0_off = 1,
-	.min_delay_ms = 100,
-	.set_symbol_rate = alps_bsbe1_set_symbol_rate,
-};
-
-static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name)
-{
-	struct budget *budget = (struct budget *)fe->dvb->priv;
-
-	return request_firmware(fw, name, &budget->dev->pci->dev);
-}
-
-
-static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg)
-{
-	u8 val;
-	struct i2c_msg msg[] = {
-		{ .addr = adr, .flags = 0, .buf = &reg, .len = 1 },
-		{ .addr = adr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
-	};
-
-	return (i2c_transfer(i2c, msg, 2) != 2) ? -EIO : val;
-}
-
-static u8 read_pwm(struct budget* budget)
-{
-	u8 b = 0xff;
-	u8 pwm;
-	struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
-				 { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
-
-	if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
-		pwm = 0x48;
-
-	return pwm;
-}
-
-static struct stv090x_config tt1600_stv090x_config = {
-	.device			= STV0903,
-	.demod_mode		= STV090x_SINGLE,
-	.clk_mode		= STV090x_CLK_EXT,
-
-	.xtal			= 13500000,
-	.address		= 0x68,
-
-	.ts1_mode		= STV090x_TSMODE_DVBCI,
-	.ts2_mode		= STV090x_TSMODE_SERIAL_CONTINUOUS,
-
-	.repeater_level		= STV090x_RPTLEVEL_16,
-
-	.tuner_init		= NULL,
-	.tuner_sleep		= NULL,
-	.tuner_set_mode		= NULL,
-	.tuner_set_frequency	= NULL,
-	.tuner_get_frequency	= NULL,
-	.tuner_set_bandwidth	= NULL,
-	.tuner_get_bandwidth	= NULL,
-	.tuner_set_bbgain	= NULL,
-	.tuner_get_bbgain	= NULL,
-	.tuner_set_refclk	= NULL,
-	.tuner_get_status	= NULL,
-};
-
-static struct stv6110x_config tt1600_stv6110x_config = {
-	.addr			= 0x60,
-	.refclk			= 27000000,
-	.clk_div		= 2,
-};
-
-static struct isl6423_config tt1600_isl6423_config = {
-	.current_max		= SEC_CURRENT_515m,
-	.curlim			= SEC_CURRENT_LIM_ON,
-	.mod_extern		= 1,
-	.addr			= 0x08,
-};
-
-static void frontend_init(struct budget *budget)
-{
-	(void)alps_bsbe1_config; /* avoid warning */
-
-	switch(budget->dev->pci->subsystem_device) {
-	case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
-	case 0x1013:
-		// try the ALPS BSRV2 first of all
-		budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap);
-		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
-			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
-			budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
-			budget->dvb_frontend->ops.set_tone = budget_set_tone;
-			break;
-		}
-
-		// try the ALPS BSRU6 now
-		budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
-		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
-			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
-			if (budget->dev->pci->subsystem_device == 0x1003 && diseqc_method == 0) {
-				budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
-				budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
-				budget->dvb_frontend->ops.set_tone = budget_set_tone;
-			}
-			break;
-		}
-		break;
-
-	case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
-
-		budget->dvb_frontend = dvb_attach(ves1820_attach, &alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
-		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
-			break;
-		}
-		break;
-
-	case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
-
-		budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config, &budget->i2c_adap);
-		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
-			budget->dvb_frontend->tuner_priv = NULL;
-			break;
-		}
-		break;
-
-	case 0x4f60: /* Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/tsa5059) */
-	{
-		int subtype = i2c_readreg(&budget->i2c_adap, 0x50, 0x67);
-
-		if (subtype < 0)
-			break;
-		/* fixme: find a better way to identify the card */
-		if (subtype < 0x36) {
-			/* assume ALPS BSRU6 */
-			budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config_activy, &budget->i2c_adap);
-			if (budget->dvb_frontend) {
-				printk(KERN_INFO "budget: tuner ALPS BSRU6 detected\n");
-				budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
-				budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
-				budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
-				budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
-				break;
-			}
-		} else {
-			/* assume ALPS BSBE1 */
-			/* reset tuner */
-			saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTLO);
-			msleep(50);
-			saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTHI);
-			msleep(250);
-			budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config_activy, &budget->i2c_adap);
-			if (budget->dvb_frontend) {
-				printk(KERN_INFO "budget: tuner ALPS BSBE1 detected\n");
-				budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
-				budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
-				budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
-				budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
-				break;
-			}
-		}
-		break;
-	}
-
-	case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))
-		budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap);
-		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
-			budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
-			budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
-		}
-		break;
-
-	case 0x5f60: /* Fujitsu Siemens Activy Budget-T PCI rev AL (tda10046/ALPS TDHD1-204A) */
-		budget->dvb_frontend = dvb_attach(tda10046_attach, &alps_tdhd1_204a_config, &budget->i2c_adap);
-		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdhd1_204a_tuner_set_params;
-			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
-		}
-		break;
-
-	case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */
-		budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap);
-		if (budget->dvb_frontend) {
-			budget->dvb_frontend->tuner_priv = &tuner_address_grundig_29504_401_activy;
-			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
-		}
-		break;
-
-	case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
-		budget->dvb_frontend = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap);
-		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params;
-			if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
-				printk("%s: No LNBP21 found!\n", __func__);
-				goto error_out;
-			}
-			break;
-		}
-
-	case 0x1018: // TT Budget-S-1401 (philips tda10086/philips tda8262)
-		// gpio2 is connected to CLB - reset it + leave it high
-		saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
-		msleep(1);
-		saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
-		msleep(1);
-
-		budget->dvb_frontend = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap);
-		if (budget->dvb_frontend) {
-			if (dvb_attach(tda826x_attach, budget->dvb_frontend, 0x60, &budget->i2c_adap, 0) == NULL)
-				printk("%s: No tda826x found!\n", __func__);
-			if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
-				printk("%s: No LNBP21 found!\n", __func__);
-				goto error_out;
-			}
-			break;
-		}
-
-	case 0x101c: { /* TT S2-1600 */
-			struct stv6110x_devctl *ctl;
-			saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
-			msleep(50);
-			saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
-			msleep(250);
-
-			budget->dvb_frontend = dvb_attach(stv090x_attach,
-							  &tt1600_stv090x_config,
-							  &budget->i2c_adap,
-							  STV090x_DEMODULATOR_0);
-
-			if (budget->dvb_frontend) {
-
-				ctl = dvb_attach(stv6110x_attach,
-						 budget->dvb_frontend,
-						 &tt1600_stv6110x_config,
-						 &budget->i2c_adap);
-
-				if (ctl) {
-					tt1600_stv090x_config.tuner_init	  = ctl->tuner_init;
-					tt1600_stv090x_config.tuner_sleep	  = ctl->tuner_sleep;
-					tt1600_stv090x_config.tuner_set_mode	  = ctl->tuner_set_mode;
-					tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
-					tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
-					tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
-					tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
-					tt1600_stv090x_config.tuner_set_bbgain	  = ctl->tuner_set_bbgain;
-					tt1600_stv090x_config.tuner_get_bbgain	  = ctl->tuner_get_bbgain;
-					tt1600_stv090x_config.tuner_set_refclk	  = ctl->tuner_set_refclk;
-					tt1600_stv090x_config.tuner_get_status	  = ctl->tuner_get_status;
-
-					/* call the init function once to initialize
-					   tuner's clock output divider and demod's
-					   master clock */
-					if (budget->dvb_frontend->ops.init)
-						budget->dvb_frontend->ops.init(budget->dvb_frontend);
-
-					if (dvb_attach(isl6423_attach,
-						       budget->dvb_frontend,
-						       &budget->i2c_adap,
-						       &tt1600_isl6423_config) == NULL) {
-						printk(KERN_ERR "%s: No Intersil ISL6423 found!\n", __func__);
-						goto error_out;
-					}
-				} else {
-					printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__);
-					goto error_out;
-				}
-			}
-		}
-		break;
-	}
-
-	if (budget->dvb_frontend == NULL) {
-		printk("budget: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
-		       budget->dev->pci->vendor,
-		       budget->dev->pci->device,
-		       budget->dev->pci->subsystem_vendor,
-		       budget->dev->pci->subsystem_device);
-	} else {
-		if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend))
-			goto error_out;
-	}
-	return;
-
-error_out:
-	printk("budget: Frontend registration failed!\n");
-	dvb_frontend_detach(budget->dvb_frontend);
-	budget->dvb_frontend = NULL;
-	return;
-}
-
-static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
-{
-	struct budget *budget = NULL;
-	int err;
-
-	budget = kmalloc(sizeof(struct budget), GFP_KERNEL);
-	if( NULL == budget ) {
-		return -ENOMEM;
-	}
-
-	dprintk(2, "dev:%p, info:%p, budget:%p\n", dev, info, budget);
-
-	dev->ext_priv = budget;
-
-	err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr);
-	if (err) {
-		printk("==> failed\n");
-		kfree (budget);
-		return err;
-	}
-
-	budget->dvb_adapter.priv = budget;
-	frontend_init(budget);
-
-	ttpci_budget_init_hooks(budget);
-
-	return 0;
-}
-
-static int budget_detach (struct saa7146_dev* dev)
-{
-	struct budget *budget = (struct budget*) dev->ext_priv;
-	int err;
-
-	if (budget->dvb_frontend) {
-		dvb_unregister_frontend(budget->dvb_frontend);
-		dvb_frontend_detach(budget->dvb_frontend);
-	}
-
-	err = ttpci_budget_deinit (budget);
-
-	kfree (budget);
-	dev->ext_priv = NULL;
-
-	return err;
-}
-
-static struct saa7146_extension budget_extension;
-
-MAKE_BUDGET_INFO(ttbs,	"TT-Budget/WinTV-NOVA-S  PCI",	BUDGET_TT);
-MAKE_BUDGET_INFO(ttbc,	"TT-Budget/WinTV-NOVA-C  PCI",	BUDGET_TT);
-MAKE_BUDGET_INFO(ttbt,	"TT-Budget/WinTV-NOVA-T  PCI",	BUDGET_TT);
-MAKE_BUDGET_INFO(satel,	"SATELCO Multimedia PCI",	BUDGET_TT_HW_DISEQC);
-MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT);
-MAKE_BUDGET_INFO(tt1600, "TT-Budget S2-1600 PCI", BUDGET_TT);
-MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
-MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
-MAKE_BUDGET_INFO(fsact,	 "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY);
-MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY);
-
-static struct pci_device_id pci_tbl[] = {
-	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1003),
-	MAKE_EXTENSION_PCI(ttbc,  0x13c2, 0x1004),
-	MAKE_EXTENSION_PCI(ttbt,  0x13c2, 0x1005),
-	MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
-	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1016),
-	MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018),
-	MAKE_EXTENSION_PCI(tt1600, 0x13c2, 0x101c),
-	MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
-	MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
-	MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60),
-	MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61),
-	{
-		.vendor    = 0,
-	}
-};
-
-MODULE_DEVICE_TABLE(pci, pci_tbl);
-
-static struct saa7146_extension budget_extension = {
-	.name		= "budget dvb",
-	.flags		= SAA7146_USE_I2C_IRQ,
-
-	.module		= THIS_MODULE,
-	.pci_tbl	= pci_tbl,
-	.attach		= budget_attach,
-	.detach		= budget_detach,
-
-	.irq_mask	= MASK_10,
-	.irq_func	= ttpci_budget_irq10_handler,
-};
-
-static int __init budget_init(void)
-{
-	return saa7146_register_extension(&budget_extension);
-}
-
-static void __exit budget_exit(void)
-{
-	saa7146_unregister_extension(&budget_extension);
-}
-
-module_init(budget_init);
-module_exit(budget_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others");
-MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
-		   "budget PCI DVB cards by Siemens, Technotrend, Hauppauge");
diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h
deleted file mode 100644
index 3d8a806..0000000
--- a/drivers/media/dvb/ttpci/budget.h
+++ /dev/null
@@ -1,124 +0,0 @@
-
-#ifndef __BUDGET_DVB__
-#define __BUDGET_DVB__
-
-#include "dvb_frontend.h"
-#include "dvbdev.h"
-#include "demux.h"
-#include "dvb_demux.h"
-#include "dmxdev.h"
-#include "dvb_filter.h"
-#include "dvb_net.h"
-
-#include <linux/module.h>
-#include <linux/mutex.h>
-
-#include <media/saa7146.h>
-
-extern int budget_debug;
-
-#ifdef dprintk
-#undef dprintk
-#endif
-
-#define dprintk(level,args...) \
-	    do { if ((budget_debug & level)) { printk("%s: %s(): ", KBUILD_MODNAME, __func__); printk(args); } } while (0)
-
-struct budget_info {
-	char *name;
-	int type;
-};
-
-/* place to store all the necessary device information */
-struct budget {
-
-	/* devices */
-	struct dvb_device dvb_dev;
-	struct dvb_net dvb_net;
-
-	struct saa7146_dev *dev;
-
-	struct i2c_adapter i2c_adap;
-	struct budget_info *card;
-
-	unsigned char *grabbing;
-	struct saa7146_pgtable pt;
-
-	struct tasklet_struct fidb_tasklet;
-	struct tasklet_struct vpe_tasklet;
-
-	struct dmxdev dmxdev;
-	struct dvb_demux demux;
-
-	struct dmx_frontend hw_frontend;
-	struct dmx_frontend mem_frontend;
-
-	int ci_present;
-	int video_port;
-
-	u32 buffer_width;
-	u32 buffer_height;
-	u32 buffer_size;
-	u32 buffer_warning_threshold;
-	u32 buffer_warnings;
-	unsigned long buffer_warning_time;
-
-	u32 ttbp;
-	int feeding;
-
-	spinlock_t feedlock;
-
-	spinlock_t debilock;
-
-	struct dvb_adapter dvb_adapter;
-	struct dvb_frontend *dvb_frontend;
-	int (*read_fe_status)(struct dvb_frontend *fe, fe_status_t *status);
-	int fe_synced;
-
-	void *priv;
-};
-
-#define MAKE_BUDGET_INFO(x_var,x_name,x_type) \
-static struct budget_info x_var ## _info = { \
-	.name=x_name,	\
-	.type=x_type };	\
-static struct saa7146_pci_extension_data x_var = { \
-	.ext_priv = &x_var ## _info, \
-	.ext = &budget_extension };
-
-#define BUDGET_TT		   0
-#define BUDGET_TT_HW_DISEQC	   1
-#define BUDGET_PATCH		   3
-#define BUDGET_FS_ACTIVY	   4
-#define BUDGET_CIN1200S		   5
-#define BUDGET_CIN1200C		   6
-#define BUDGET_CIN1200T		   7
-#define BUDGET_KNC1S		   8
-#define BUDGET_KNC1C		   9
-#define BUDGET_KNC1T		   10
-#define BUDGET_KNC1SP		   11
-#define BUDGET_KNC1CP		   12
-#define BUDGET_KNC1TP		   13
-#define BUDGET_TVSTAR		   14
-#define BUDGET_CIN1200C_MK3	   15
-#define BUDGET_KNC1C_MK3	   16
-#define BUDGET_KNC1CP_MK3	   17
-#define BUDGET_KNC1S2              18
-#define BUDGET_KNC1C_TDA10024	   19
-
-#define BUDGET_VIDEO_PORTA         0
-#define BUDGET_VIDEO_PORTB         1
-
-extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
-			     struct saa7146_pci_extension_data *info,
-			     struct module *owner, short *adapter_nums);
-extern void ttpci_budget_init_hooks(struct budget *budget);
-extern int ttpci_budget_deinit(struct budget *budget);
-extern void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr);
-extern void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port);
-extern int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count,
-				 int uselocks, int nobusyloop);
-extern int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, int count, u32 value,
-				  int uselocks, int nobusyloop);
-
-#endif
diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c
deleted file mode 100644
index 32d4315..0000000
--- a/drivers/media/dvb/ttpci/ttpci-eeprom.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
-    Retrieve encoded MAC address from 24C16 serial 2-wire EEPROM,
-    decode it and store it in the associated adapter struct for
-    use by dvb_net.c
-
-    This card appear to have the 24C16 write protect held to ground,
-    thus permitting normal read/write operation. Theoretically it
-    would be possible to write routines to burn a different (encoded)
-    MAC address into the EEPROM.
-
-    Robert Schlabbach	GMX
-    Michael Glaum	KVH Industries
-    Holger Waechtler	Convergence
-
-    Copyright (C) 2002-2003 Ralph Metzler <rjkm@metzlerbros.de>
-			    Metzler Brothers Systementwicklung GbR
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <asm/errno.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/i2c.h>
-
-#include "ttpci-eeprom.h"
-
-#if 1
-#define dprintk(x...) do { printk(x); } while (0)
-#else
-#define dprintk(x...) do { } while (0)
-#endif
-
-
-static int check_mac_tt(u8 *buf)
-{
-	int i;
-	u16 tmp = 0xffff;
-
-	for (i = 0; i < 8; i++) {
-		tmp  = (tmp << 8) | ((tmp >> 8) ^ buf[i]);
-		tmp ^= (tmp >> 4) & 0x0f;
-		tmp ^= (tmp << 12) ^ ((tmp & 0xff) << 5);
-	}
-	tmp ^= 0xffff;
-	return (((tmp >> 8) ^ buf[8]) | ((tmp & 0xff) ^ buf[9]));
-}
-
-static int getmac_tt(u8 * decodedMAC, u8 * encodedMAC)
-{
-	u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c,
-		       0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6,
-		       0x1d, 0x36, 0x64, 0x78};
-	u8 data[20];
-	int i;
-
-	/* In case there is a sig check failure have the orig contents available */
-	memcpy(data, encodedMAC, 20);
-
-	for (i = 0; i < 20; i++)
-		data[i] ^= xor[i];
-	for (i = 0; i < 10; i++)
-		data[i] = ((data[2 * i + 1] << 8) | data[2 * i])
-			>> ((data[2 * i + 1] >> 6) & 3);
-
-	if (check_mac_tt(data))
-		return -ENODEV;
-
-	decodedMAC[0] = data[2]; decodedMAC[1] = data[1]; decodedMAC[2] = data[0];
-	decodedMAC[3] = data[6]; decodedMAC[4] = data[5]; decodedMAC[5] = data[4];
-	return 0;
-}
-
-int ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC)
-{
-	u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c,
-		       0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6,
-		       0x1d, 0x36, 0x64, 0x78};
-	u8 data[20];
-	int i;
-
-	memcpy(data, encodedMAC, 20);
-
-	for (i = 0; i < 20; i++)
-		data[i] ^= xor[i];
-	for (i = 0; i < 10; i++)
-		data[i] = ((data[2 * i + 1] << 8) | data[2 * i])
-			>> ((data[2 * i + 1] >> 6) & 3);
-
-	if (check_mac_tt(data))
-		return -ENODEV;
-
-	decodedMAC[0] = data[2];
-	decodedMAC[1] = data[1];
-	decodedMAC[2] = data[0];
-	decodedMAC[3] = data[6];
-	decodedMAC[4] = data[5];
-	decodedMAC[5] = data[4];
-	return 0;
-}
-EXPORT_SYMBOL(ttpci_eeprom_decode_mac);
-
-static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC)
-{
-	int ret;
-	u8 b0[] = { 0xcc };
-
-	struct i2c_msg msg[] = {
-		{ .addr = 0x50, .flags = 0, .buf = b0, .len = 1 },
-		{ .addr = 0x50, .flags = I2C_M_RD, .buf = encodedMAC, .len = 20 }
-	};
-
-	/* dprintk("%s\n", __func__); */
-
-	ret = i2c_transfer(adapter, msg, 2);
-
-	if (ret != 2)		/* Assume EEPROM isn't there */
-		return (-ENODEV);
-
-	return 0;
-}
-
-
-int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac)
-{
-	int ret, i;
-	u8 encodedMAC[20];
-	u8 decodedMAC[6];
-
-	ret = ttpci_eeprom_read_encodedMAC(adapter, encodedMAC);
-
-	if (ret != 0) {		/* Will only be -ENODEV */
-		dprintk("Couldn't read from EEPROM: not there?\n");
-		memset(proposed_mac, 0, 6);
-		return ret;
-	}
-
-	ret = getmac_tt(decodedMAC, encodedMAC);
-	if( ret != 0 ) {
-		dprintk("adapter failed MAC signature check\n");
-		dprintk("encoded MAC from EEPROM was " );
-		for(i=0; i<19; i++) {
-			dprintk( "%.2x:", encodedMAC[i]);
-		}
-		dprintk("%.2x\n", encodedMAC[19]);
-		memset(proposed_mac, 0, 6);
-		return ret;
-	}
-
-	memcpy(proposed_mac, decodedMAC, 6);
-	dprintk("adapter has MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
-		decodedMAC[0], decodedMAC[1], decodedMAC[2],
-		decodedMAC[3], decodedMAC[4], decodedMAC[5]);
-	return 0;
-}
-
-EXPORT_SYMBOL(ttpci_eeprom_parse_mac);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others");
-MODULE_DESCRIPTION("Decode dvb_net MAC address from EEPROM of PCI DVB cards "
-		"made by Siemens, Technotrend, Hauppauge");
diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.h b/drivers/media/dvb/ttpci/ttpci-eeprom.h
deleted file mode 100644
index dcc33d5..0000000
--- a/drivers/media/dvb/ttpci/ttpci-eeprom.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-    Retrieve encoded MAC address from ATMEL ttpci_eeprom serial 2-wire EEPROM,
-    decode it and store it in associated adapter net device
-
-    Robert Schlabbach	GMX
-    Michael Glaum	KVH Industries
-    Holger Waechtler	Convergence
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef __TTPCI_EEPROM_H__
-#define __TTPCI_EEPROM_H__
-
-#include <linux/types.h>
-#include <linux/i2c.h>
-
-extern int ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC);
-extern int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *propsed_mac);
-
-#endif
diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig
deleted file mode 100644
index 2663ae3..0000000
--- a/drivers/media/dvb/ttusb-budget/Kconfig
+++ /dev/null
@@ -1,18 +0,0 @@
-config DVB_TTUSB_BUDGET
-	tristate "Technotrend/Hauppauge Nova-USB devices"
-	depends on DVB_CORE && USB && I2C && PCI
-	select DVB_CX22700 if !DVB_FE_CUSTOMISE
-	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
-	select DVB_VES1820 if !DVB_FE_CUSTOMISE
-	select DVB_TDA8083 if !DVB_FE_CUSTOMISE
-	select DVB_STV0299 if !DVB_FE_CUSTOMISE
-	select DVB_STV0297 if !DVB_FE_CUSTOMISE
-	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
-	help
-	  Support for external USB adapters designed by Technotrend and
-	  produced by Hauppauge, shipped under the brand name 'Nova-USB'.
-
-	  These devices don't have a MPEG decoder built in, so you need
-	  an external software decoder to watch TV.
-
-	  Say Y if you own such a device and want to use it.
diff --git a/drivers/media/dvb/ttusb-budget/Makefile b/drivers/media/dvb/ttusb-budget/Makefile
deleted file mode 100644
index 8d6c4ac..0000000
--- a/drivers/media/dvb/ttusb-budget/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
deleted file mode 100644
index 5b682cc..0000000
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ /dev/null
@@ -1,1816 +0,0 @@
-/*
- * TTUSB DVB driver
- *
- * Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
- * Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.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.
- */
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/wait.h>
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-#include <linux/errno.h>
-#include <linux/jiffies.h>
-#include <linux/mutex.h>
-#include <linux/firmware.h>
-
-#include "dvb_frontend.h"
-#include "dmxdev.h"
-#include "dvb_demux.h"
-#include "dvb_net.h"
-#include "ves1820.h"
-#include "cx22700.h"
-#include "tda1004x.h"
-#include "stv0299.h"
-#include "tda8083.h"
-#include "stv0297.h"
-#include "lnbp21.h"
-
-#include <linux/dvb/frontend.h>
-#include <linux/dvb/dmx.h>
-#include <linux/pci.h>
-
-/*
-  TTUSB_HWSECTIONS:
-    the DSP supports filtering in hardware, however, since the "muxstream"
-    is a bit braindead (no matching channel masks or no matching filter mask),
-    we won't support this - yet. it doesn't event support negative filters,
-    so the best way is maybe to keep TTUSB_HWSECTIONS undef'd and just
-    parse TS data. USB bandwidth will be a problem when having large
-    datastreams, especially for dvb-net, but hey, that's not my problem.
-
-  TTUSB_DISEQC, TTUSB_TONE:
-    let the STC do the diseqc/tone stuff. this isn't supported at least with
-    my TTUSB, so let it undef'd unless you want to implement another
-    frontend. never tested.
-
-  debug:
-    define it to > 3 for really hardcore debugging. you probably don't want
-    this unless the device doesn't load at all. > 2 for bandwidth statistics.
-*/
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define dprintk(x...) do { if (debug) printk(KERN_DEBUG x); } while (0)
-
-#define ISO_BUF_COUNT      4
-#define FRAMES_PER_ISO_BUF 4
-#define ISO_FRAME_SIZE     912
-#define TTUSB_MAXCHANNEL   32
-#ifdef TTUSB_HWSECTIONS
-#define TTUSB_MAXFILTER    16	/* ??? */
-#endif
-
-#define TTUSB_REV_2_2	0x22
-#define TTUSB_BUDGET_NAME "ttusb_stc_fw"
-
-/**
- *  since we're casting (struct ttusb*) <-> (struct dvb_demux*) around
- *  the dvb_demux field must be the first in struct!!
- */
-struct ttusb {
-	struct dvb_demux dvb_demux;
-	struct dmxdev dmxdev;
-	struct dvb_net dvbnet;
-
-	/* and one for USB access. */
-	struct mutex semi2c;
-	struct mutex semusb;
-
-	struct dvb_adapter adapter;
-	struct usb_device *dev;
-
-	struct i2c_adapter i2c_adap;
-
-	int disconnecting;
-	int iso_streaming;
-
-	unsigned int bulk_out_pipe;
-	unsigned int bulk_in_pipe;
-	unsigned int isoc_in_pipe;
-
-	void *iso_buffer;
-	dma_addr_t iso_dma_handle;
-
-	struct urb *iso_urb[ISO_BUF_COUNT];
-
-	int running_feed_count;
-	int last_channel;
-	int last_filter;
-
-	u8 c;			/* transaction counter, wraps around...  */
-	fe_sec_tone_mode_t tone;
-	fe_sec_voltage_t voltage;
-
-	int mux_state;		// 0..2 - MuxSyncWord, 3 - nMuxPacks,    4 - muxpack
-	u8 mux_npacks;
-	u8 muxpack[256 + 8];
-	int muxpack_ptr, muxpack_len;
-
-	int insync;
-
-	int cc;			/* MuxCounter - will increment on EVERY MUX PACKET */
-	/* (including stuffing. yes. really.) */
-
-	u8 last_result[32];
-
-	int revision;
-
-	struct dvb_frontend* fe;
-};
-
-/* ugly workaround ... don't know why it's necessary to read */
-/* all result codes. */
-
-static int ttusb_cmd(struct ttusb *ttusb,
-	      const u8 * data, int len, int needresult)
-{
-	int actual_len;
-	int err;
-	int i;
-
-	if (debug >= 3) {
-		printk(KERN_DEBUG ">");
-		for (i = 0; i < len; ++i)
-			printk(KERN_CONT " %02x", data[i]);
-		printk(KERN_CONT "\n");
-	}
-
-	if (mutex_lock_interruptible(&ttusb->semusb) < 0)
-		return -EAGAIN;
-
-	err = usb_bulk_msg(ttusb->dev, ttusb->bulk_out_pipe,
-			   (u8 *) data, len, &actual_len, 1000);
-	if (err != 0) {
-		dprintk("%s: usb_bulk_msg(send) failed, err == %i!\n",
-			__func__, err);
-		mutex_unlock(&ttusb->semusb);
-		return err;
-	}
-	if (actual_len != len) {
-		dprintk("%s: only wrote %d of %d bytes\n", __func__,
-			actual_len, len);
-		mutex_unlock(&ttusb->semusb);
-		return -1;
-	}
-
-	err = usb_bulk_msg(ttusb->dev, ttusb->bulk_in_pipe,
-			   ttusb->last_result, 32, &actual_len, 1000);
-
-	if (err != 0) {
-		printk("%s: failed, receive error %d\n", __func__,
-		       err);
-		mutex_unlock(&ttusb->semusb);
-		return err;
-	}
-
-	if (debug >= 3) {
-		actual_len = ttusb->last_result[3] + 4;
-		printk(KERN_DEBUG "<");
-		for (i = 0; i < actual_len; ++i)
-			printk(KERN_CONT " %02x", ttusb->last_result[i]);
-		printk(KERN_CONT "\n");
-	}
-
-	if (!needresult)
-		mutex_unlock(&ttusb->semusb);
-	return 0;
-}
-
-static int ttusb_result(struct ttusb *ttusb, u8 * data, int len)
-{
-	memcpy(data, ttusb->last_result, len);
-	mutex_unlock(&ttusb->semusb);
-	return 0;
-}
-
-static int ttusb_i2c_msg(struct ttusb *ttusb,
-		  u8 addr, u8 * snd_buf, u8 snd_len, u8 * rcv_buf,
-		  u8 rcv_len)
-{
-	u8 b[0x28];
-	u8 id = ++ttusb->c;
-	int i, err;
-
-	if (snd_len > 0x28 - 7 || rcv_len > 0x20 - 7)
-		return -EINVAL;
-
-	b[0] = 0xaa;
-	b[1] = id;
-	b[2] = 0x31;
-	b[3] = snd_len + 3;
-	b[4] = addr << 1;
-	b[5] = snd_len;
-	b[6] = rcv_len;
-
-	for (i = 0; i < snd_len; i++)
-		b[7 + i] = snd_buf[i];
-
-	err = ttusb_cmd(ttusb, b, snd_len + 7, 1);
-
-	if (err)
-		return -EREMOTEIO;
-
-	err = ttusb_result(ttusb, b, 0x20);
-
-	/* check if the i2c transaction was successful */
-	if ((snd_len != b[5]) || (rcv_len != b[6])) return -EREMOTEIO;
-
-	if (rcv_len > 0) {
-
-		if (err || b[0] != 0x55 || b[1] != id) {
-			dprintk
-			    ("%s: usb_bulk_msg(recv) failed, err == %i, id == %02x, b == ",
-			     __func__, err, id);
-			return -EREMOTEIO;
-		}
-
-		for (i = 0; i < rcv_len; i++)
-			rcv_buf[i] = b[7 + i];
-	}
-
-	return rcv_len;
-}
-
-static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num)
-{
-	struct ttusb *ttusb = i2c_get_adapdata(adapter);
-	int i = 0;
-	int inc;
-
-	if (mutex_lock_interruptible(&ttusb->semi2c) < 0)
-		return -EAGAIN;
-
-	while (i < num) {
-		u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf;
-		int err;
-
-		if (num > i + 1 && (msg[i + 1].flags & I2C_M_RD)) {
-			addr = msg[i].addr;
-			snd_buf = msg[i].buf;
-			snd_len = msg[i].len;
-			rcv_buf = msg[i + 1].buf;
-			rcv_len = msg[i + 1].len;
-			inc = 2;
-		} else {
-			addr = msg[i].addr;
-			snd_buf = msg[i].buf;
-			snd_len = msg[i].len;
-			rcv_buf = NULL;
-			rcv_len = 0;
-			inc = 1;
-		}
-
-		err = ttusb_i2c_msg(ttusb, addr,
-				    snd_buf, snd_len, rcv_buf, rcv_len);
-
-		if (err < rcv_len) {
-			dprintk("%s: i == %i\n", __func__, i);
-			break;
-		}
-
-		i += inc;
-	}
-
-	mutex_unlock(&ttusb->semi2c);
-	return i;
-}
-
-static int ttusb_boot_dsp(struct ttusb *ttusb)
-{
-	const struct firmware *fw;
-	int i, err;
-	u8 b[40];
-
-	err = request_firmware(&fw, "ttusb-budget/dspbootcode.bin",
-			       &ttusb->dev->dev);
-	if (err) {
-		printk(KERN_ERR "ttusb-budget: failed to request firmware\n");
-		return err;
-	}
-
-	/* BootBlock */
-	b[0] = 0xaa;
-	b[2] = 0x13;
-	b[3] = 28;
-
-	/* upload dsp code in 32 byte steps (36 didn't work for me ...) */
-	/* 32 is max packet size, no messages should be splitted. */
-	for (i = 0; i < fw->size; i += 28) {
-		memcpy(&b[4], &fw->data[i], 28);
-
-		b[1] = ++ttusb->c;
-
-		err = ttusb_cmd(ttusb, b, 32, 0);
-		if (err)
-			goto done;
-	}
-
-	/* last block ... */
-	b[1] = ++ttusb->c;
-	b[2] = 0x13;
-	b[3] = 0;
-
-	err = ttusb_cmd(ttusb, b, 4, 0);
-	if (err)
-		goto done;
-
-	/* BootEnd */
-	b[1] = ++ttusb->c;
-	b[2] = 0x14;
-	b[3] = 0;
-
-	err = ttusb_cmd(ttusb, b, 4, 0);
-
-      done:
-	release_firmware(fw);
-	if (err) {
-		dprintk("%s: usb_bulk_msg() failed, return value %i!\n",
-			__func__, err);
-	}
-
-	return err;
-}
-
-static int ttusb_set_channel(struct ttusb *ttusb, int chan_id, int filter_type,
-		      int pid)
-{
-	int err;
-	/* SetChannel */
-	u8 b[] = { 0xaa, ++ttusb->c, 0x22, 4, chan_id, filter_type,
-		(pid >> 8) & 0xff, pid & 0xff
-	};
-
-	err = ttusb_cmd(ttusb, b, sizeof(b), 0);
-	return err;
-}
-
-static int ttusb_del_channel(struct ttusb *ttusb, int channel_id)
-{
-	int err;
-	/* DelChannel */
-	u8 b[] = { 0xaa, ++ttusb->c, 0x23, 1, channel_id };
-
-	err = ttusb_cmd(ttusb, b, sizeof(b), 0);
-	return err;
-}
-
-#ifdef TTUSB_HWSECTIONS
-static int ttusb_set_filter(struct ttusb *ttusb, int filter_id,
-		     int associated_chan, u8 filter[8], u8 mask[8])
-{
-	int err;
-	/* SetFilter */
-	u8 b[] = { 0xaa, 0, 0x24, 0x1a, filter_id, associated_chan,
-		filter[0], filter[1], filter[2], filter[3],
-		filter[4], filter[5], filter[6], filter[7],
-		filter[8], filter[9], filter[10], filter[11],
-		mask[0], mask[1], mask[2], mask[3],
-		mask[4], mask[5], mask[6], mask[7],
-		mask[8], mask[9], mask[10], mask[11]
-	};
-
-	err = ttusb_cmd(ttusb, b, sizeof(b), 0);
-	return err;
-}
-
-static int ttusb_del_filter(struct ttusb *ttusb, int filter_id)
-{
-	int err;
-	/* DelFilter */
-	u8 b[] = { 0xaa, ++ttusb->c, 0x25, 1, filter_id };
-
-	err = ttusb_cmd(ttusb, b, sizeof(b), 0);
-	return err;
-}
-#endif
-
-static int ttusb_init_controller(struct ttusb *ttusb)
-{
-	u8 b0[] = { 0xaa, ++ttusb->c, 0x15, 1, 0 };
-	u8 b1[] = { 0xaa, ++ttusb->c, 0x15, 1, 1 };
-	u8 b2[] = { 0xaa, ++ttusb->c, 0x32, 1, 0 };
-	/* i2c write read: 5 bytes, addr 0x10, 0x02 bytes write, 1 bytes read. */
-	u8 b3[] =
-	    { 0xaa, ++ttusb->c, 0x31, 5, 0x10, 0x02, 0x01, 0x00, 0x1e };
-	u8 b4[] =
-	    { 0x55, ttusb->c, 0x31, 4, 0x10, 0x02, 0x01, 0x00, 0x1e };
-
-	u8 get_version[] = { 0xaa, ++ttusb->c, 0x17, 5, 0, 0, 0, 0, 0 };
-	u8 get_dsp_version[0x20] =
-	    { 0xaa, ++ttusb->c, 0x26, 28, 0, 0, 0, 0, 0 };
-	int err;
-
-	/* reset board */
-	if ((err = ttusb_cmd(ttusb, b0, sizeof(b0), 0)))
-		return err;
-
-	/* reset board (again?) */
-	if ((err = ttusb_cmd(ttusb, b1, sizeof(b1), 0)))
-		return err;
-
-	ttusb_boot_dsp(ttusb);
-
-	/* set i2c bit rate */
-	if ((err = ttusb_cmd(ttusb, b2, sizeof(b2), 0)))
-		return err;
-
-	if ((err = ttusb_cmd(ttusb, b3, sizeof(b3), 1)))
-		return err;
-
-	err = ttusb_result(ttusb, b4, sizeof(b4));
-
-	if ((err = ttusb_cmd(ttusb, get_version, sizeof(get_version), 1)))
-		return err;
-
-	if ((err = ttusb_result(ttusb, get_version, sizeof(get_version))))
-		return err;
-
-	dprintk("%s: stc-version: %c%c%c%c%c\n", __func__,
-		get_version[4], get_version[5], get_version[6],
-		get_version[7], get_version[8]);
-
-	if (memcmp(get_version + 4, "V 0.0", 5) &&
-	    memcmp(get_version + 4, "V 1.1", 5) &&
-	    memcmp(get_version + 4, "V 2.1", 5) &&
-	    memcmp(get_version + 4, "V 2.2", 5)) {
-		printk
-		    ("%s: unknown STC version %c%c%c%c%c, please report!\n",
-		     __func__, get_version[4], get_version[5],
-		     get_version[6], get_version[7], get_version[8]);
-	}
-
-	ttusb->revision = ((get_version[6] - '0') << 4) |
-			   (get_version[8] - '0');
-
-	err =
-	    ttusb_cmd(ttusb, get_dsp_version, sizeof(get_dsp_version), 1);
-	if (err)
-		return err;
-
-	err =
-	    ttusb_result(ttusb, get_dsp_version, sizeof(get_dsp_version));
-	if (err)
-		return err;
-	printk("%s: dsp-version: %c%c%c\n", __func__,
-	       get_dsp_version[4], get_dsp_version[5], get_dsp_version[6]);
-	return 0;
-}
-
-#ifdef TTUSB_DISEQC
-static int ttusb_send_diseqc(struct dvb_frontend* fe,
-			     const struct dvb_diseqc_master_cmd *cmd)
-{
-	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
-	u8 b[12] = { 0xaa, ++ttusb->c, 0x18 };
-
-	int err;
-
-	b[3] = 4 + 2 + cmd->msg_len;
-	b[4] = 0xFF;		/* send diseqc master, not burst */
-	b[5] = cmd->msg_len;
-
-	memcpy(b + 5, cmd->msg, cmd->msg_len);
-
-	/* Diseqc */
-	if ((err = ttusb_cmd(ttusb, b, 4 + b[3], 0))) {
-		dprintk("%s: usb_bulk_msg() failed, return value %i!\n",
-			__func__, err);
-	}
-
-	return err;
-}
-#endif
-
-static int ttusb_update_lnb(struct ttusb *ttusb)
-{
-	u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1,
-		ttusb->voltage == SEC_VOLTAGE_18 ? 0 : 1,
-		ttusb->tone == SEC_TONE_ON ? 1 : 0, 1, 1
-	};
-	int err;
-
-	/* SetLNB */
-	if ((err = ttusb_cmd(ttusb, b, sizeof(b), 0))) {
-		dprintk("%s: usb_bulk_msg() failed, return value %i!\n",
-			__func__, err);
-	}
-
-	return err;
-}
-
-static int ttusb_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
-	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
-
-	ttusb->voltage = voltage;
-	return ttusb_update_lnb(ttusb);
-}
-
-#ifdef TTUSB_TONE
-static int ttusb_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
-	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
-
-	ttusb->tone = tone;
-	return ttusb_update_lnb(ttusb);
-}
-#endif
-
-
-#if 0
-static void ttusb_set_led_freq(struct ttusb *ttusb, u8 freq)
-{
-	u8 b[] = { 0xaa, ++ttusb->c, 0x19, 1, freq };
-	int err, actual_len;
-
-	err = ttusb_cmd(ttusb, b, sizeof(b), 0);
-	if (err) {
-		dprintk("%s: usb_bulk_msg() failed, return value %i!\n",
-			__func__, err);
-	}
-}
-#endif
-
-/*****************************************************************************/
-
-#ifdef TTUSB_HWSECTIONS
-static void ttusb_handle_ts_data(struct ttusb_channel *channel,
-				 const u8 * data, int len);
-static void ttusb_handle_sec_data(struct ttusb_channel *channel,
-				  const u8 * data, int len);
-#endif
-
-static int numpkt, numts, numstuff, numsec, numinvalid;
-static unsigned long lastj;
-
-static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack,
-			   int len)
-{
-	u16 csum = 0, cc;
-	int i;
-	for (i = 0; i < len; i += 2)
-		csum ^= le16_to_cpup((__le16 *) (muxpack + i));
-	if (csum) {
-		printk("%s: muxpack with incorrect checksum, ignoring\n",
-		       __func__);
-		numinvalid++;
-		return;
-	}
-
-	cc = (muxpack[len - 4] << 8) | muxpack[len - 3];
-	cc &= 0x7FFF;
-	if ((cc != ttusb->cc) && (ttusb->cc != -1))
-		printk("%s: cc discontinuity (%d frames missing)\n",
-		       __func__, (cc - ttusb->cc) & 0x7FFF);
-	ttusb->cc = (cc + 1) & 0x7FFF;
-	if (muxpack[0] & 0x80) {
-#ifdef TTUSB_HWSECTIONS
-		/* section data */
-		int pusi = muxpack[0] & 0x40;
-		int channel = muxpack[0] & 0x1F;
-		int payload = muxpack[1];
-		const u8 *data = muxpack + 2;
-		/* check offset flag */
-		if (muxpack[0] & 0x20)
-			data++;
-
-		ttusb_handle_sec_data(ttusb->channel + channel, data,
-				      payload);
-		data += payload;
-
-		if ((!!(ttusb->muxpack[0] & 0x20)) ^
-		    !!(ttusb->muxpack[1] & 1))
-			data++;
-#warning TODO: pusi
-		printk("cc: %04x\n", (data[0] << 8) | data[1]);
-#endif
-		numsec++;
-	} else if (muxpack[0] == 0x47) {
-#ifdef TTUSB_HWSECTIONS
-		/* we have TS data here! */
-		int pid = ((muxpack[1] & 0x0F) << 8) | muxpack[2];
-		int channel;
-		for (channel = 0; channel < TTUSB_MAXCHANNEL; ++channel)
-			if (ttusb->channel[channel].active
-			    && (pid == ttusb->channel[channel].pid))
-				ttusb_handle_ts_data(ttusb->channel +
-						     channel, muxpack,
-						     188);
-#endif
-		numts++;
-		dvb_dmx_swfilter_packets(&ttusb->dvb_demux, muxpack, 1);
-	} else if (muxpack[0] != 0) {
-		numinvalid++;
-		printk("illegal muxpack type %02x\n", muxpack[0]);
-	} else
-		numstuff++;
-}
-
-static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len)
-{
-	int maxwork = 1024;
-	while (len) {
-		if (!(maxwork--)) {
-			printk("%s: too much work\n", __func__);
-			break;
-		}
-
-		switch (ttusb->mux_state) {
-		case 0:
-		case 1:
-		case 2:
-			len--;
-			if (*data++ == 0xAA)
-				++ttusb->mux_state;
-			else {
-				ttusb->mux_state = 0;
-				if (ttusb->insync) {
-					dprintk("%s: %02x\n",
-						__func__, data[-1]);
-					printk(KERN_INFO "%s: lost sync.\n",
-					       __func__);
-					ttusb->insync = 0;
-				}
-			}
-			break;
-		case 3:
-			ttusb->insync = 1;
-			len--;
-			ttusb->mux_npacks = *data++;
-			++ttusb->mux_state;
-			ttusb->muxpack_ptr = 0;
-			/* maximum bytes, until we know the length */
-			ttusb->muxpack_len = 2;
-			break;
-		case 4:
-			{
-				int avail;
-				avail = len;
-				if (avail >
-				    (ttusb->muxpack_len -
-				     ttusb->muxpack_ptr))
-					avail =
-					    ttusb->muxpack_len -
-					    ttusb->muxpack_ptr;
-				memcpy(ttusb->muxpack + ttusb->muxpack_ptr,
-				       data, avail);
-				ttusb->muxpack_ptr += avail;
-				BUG_ON(ttusb->muxpack_ptr > 264);
-				data += avail;
-				len -= avail;
-				/* determine length */
-				if (ttusb->muxpack_ptr == 2) {
-					if (ttusb->muxpack[0] & 0x80) {
-						ttusb->muxpack_len =
-						    ttusb->muxpack[1] + 2;
-						if (ttusb->
-						    muxpack[0] & 0x20)
-							ttusb->
-							    muxpack_len++;
-						if ((!!
-						     (ttusb->
-						      muxpack[0] & 0x20)) ^
-						    !!(ttusb->
-						       muxpack[1] & 1))
-							ttusb->
-							    muxpack_len++;
-						ttusb->muxpack_len += 4;
-					} else if (ttusb->muxpack[0] ==
-						   0x47)
-						ttusb->muxpack_len =
-						    188 + 4;
-					else if (ttusb->muxpack[0] == 0x00)
-						ttusb->muxpack_len =
-						    ttusb->muxpack[1] + 2 +
-						    4;
-					else {
-						dprintk
-						    ("%s: invalid state: first byte is %x\n",
-						     __func__,
-						     ttusb->muxpack[0]);
-						ttusb->mux_state = 0;
-					}
-				}
-
-			/**
-			 * if length is valid and we reached the end:
-			 * goto next muxpack
-			 */
-				if ((ttusb->muxpack_ptr >= 2) &&
-				    (ttusb->muxpack_ptr ==
-				     ttusb->muxpack_len)) {
-					ttusb_process_muxpack(ttusb,
-							      ttusb->
-							      muxpack,
-							      ttusb->
-							      muxpack_ptr);
-					ttusb->muxpack_ptr = 0;
-					/* maximum bytes, until we know the length */
-					ttusb->muxpack_len = 2;
-
-				/**
-				 * no muxpacks left?
-				 * return to search-sync state
-				 */
-					if (!ttusb->mux_npacks--) {
-						ttusb->mux_state = 0;
-						break;
-					}
-				}
-				break;
-			}
-		default:
-			BUG();
-			break;
-		}
-	}
-}
-
-static void ttusb_iso_irq(struct urb *urb)
-{
-	struct ttusb *ttusb = urb->context;
-	struct usb_iso_packet_descriptor *d;
-	u8 *data;
-	int len, i;
-
-	if (!ttusb->iso_streaming)
-		return;
-
-#if 0
-	printk("%s: status %d, errcount == %d, length == %i\n",
-	       __func__,
-	       urb->status, urb->error_count, urb->actual_length);
-#endif
-
-	if (!urb->status) {
-		for (i = 0; i < urb->number_of_packets; ++i) {
-			numpkt++;
-			if (time_after_eq(jiffies, lastj + HZ)) {
-				dprintk("frames/s: %lu (ts: %d, stuff %d, "
-					"sec: %d, invalid: %d, all: %d)\n",
-					numpkt * HZ / (jiffies - lastj),
-					numts, numstuff, numsec, numinvalid,
-					numts + numstuff + numsec + numinvalid);
-				numts = numstuff = numsec = numinvalid = 0;
-				lastj = jiffies;
-				numpkt = 0;
-			}
-			d = &urb->iso_frame_desc[i];
-			data = urb->transfer_buffer + d->offset;
-			len = d->actual_length;
-			d->actual_length = 0;
-			d->status = 0;
-			ttusb_process_frame(ttusb, data, len);
-		}
-	}
-	usb_submit_urb(urb, GFP_ATOMIC);
-}
-
-static void ttusb_free_iso_urbs(struct ttusb *ttusb)
-{
-	int i;
-
-	for (i = 0; i < ISO_BUF_COUNT; i++)
-		if (ttusb->iso_urb[i])
-			usb_free_urb(ttusb->iso_urb[i]);
-
-	pci_free_consistent(NULL,
-			    ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF *
-			    ISO_BUF_COUNT, ttusb->iso_buffer,
-			    ttusb->iso_dma_handle);
-}
-
-static int ttusb_alloc_iso_urbs(struct ttusb *ttusb)
-{
-	int i;
-
-	ttusb->iso_buffer = pci_alloc_consistent(NULL,
-						 ISO_FRAME_SIZE *
-						 FRAMES_PER_ISO_BUF *
-						 ISO_BUF_COUNT,
-						 &ttusb->iso_dma_handle);
-
-	if (!ttusb->iso_buffer) {
-		dprintk("%s: pci_alloc_consistent - not enough memory\n",
-			__func__);
-		return -ENOMEM;
-	}
-
-	memset(ttusb->iso_buffer, 0,
-	       ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF * ISO_BUF_COUNT);
-
-	for (i = 0; i < ISO_BUF_COUNT; i++) {
-		struct urb *urb;
-
-		if (!
-		    (urb =
-		     usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) {
-			ttusb_free_iso_urbs(ttusb);
-			return -ENOMEM;
-		}
-
-		ttusb->iso_urb[i] = urb;
-	}
-
-	return 0;
-}
-
-static void ttusb_stop_iso_xfer(struct ttusb *ttusb)
-{
-	int i;
-
-	for (i = 0; i < ISO_BUF_COUNT; i++)
-		usb_kill_urb(ttusb->iso_urb[i]);
-
-	ttusb->iso_streaming = 0;
-}
-
-static int ttusb_start_iso_xfer(struct ttusb *ttusb)
-{
-	int i, j, err, buffer_offset = 0;
-
-	if (ttusb->iso_streaming) {
-		printk("%s: iso xfer already running!\n", __func__);
-		return 0;
-	}
-
-	ttusb->cc = -1;
-	ttusb->insync = 0;
-	ttusb->mux_state = 0;
-
-	for (i = 0; i < ISO_BUF_COUNT; i++) {
-		int frame_offset = 0;
-		struct urb *urb = ttusb->iso_urb[i];
-
-		urb->dev = ttusb->dev;
-		urb->context = ttusb;
-		urb->complete = ttusb_iso_irq;
-		urb->pipe = ttusb->isoc_in_pipe;
-		urb->transfer_flags = URB_ISO_ASAP;
-		urb->interval = 1;
-		urb->number_of_packets = FRAMES_PER_ISO_BUF;
-		urb->transfer_buffer_length =
-		    ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF;
-		urb->transfer_buffer = ttusb->iso_buffer + buffer_offset;
-		buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF;
-
-		for (j = 0; j < FRAMES_PER_ISO_BUF; j++) {
-			urb->iso_frame_desc[j].offset = frame_offset;
-			urb->iso_frame_desc[j].length = ISO_FRAME_SIZE;
-			frame_offset += ISO_FRAME_SIZE;
-		}
-	}
-
-	for (i = 0; i < ISO_BUF_COUNT; i++) {
-		if ((err = usb_submit_urb(ttusb->iso_urb[i], GFP_ATOMIC))) {
-			ttusb_stop_iso_xfer(ttusb);
-			printk
-			    ("%s: failed urb submission (%i: err = %i)!\n",
-			     __func__, i, err);
-			return err;
-		}
-	}
-
-	ttusb->iso_streaming = 1;
-
-	return 0;
-}
-
-#ifdef TTUSB_HWSECTIONS
-static void ttusb_handle_ts_data(struct dvb_demux_feed *dvbdmxfeed, const u8 * data,
-			  int len)
-{
-	dvbdmxfeed->cb.ts(data, len, 0, 0, &dvbdmxfeed->feed.ts, 0);
-}
-
-static void ttusb_handle_sec_data(struct dvb_demux_feed *dvbdmxfeed, const u8 * data,
-			   int len)
-{
-//      struct dvb_demux_feed *dvbdmxfeed = channel->dvbdmxfeed;
-#error TODO: handle ugly stuff
-//      dvbdmxfeed->cb.sec(data, len, 0, 0, &dvbdmxfeed->feed.sec, 0);
-}
-#endif
-
-static int ttusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux;
-	int feed_type = 1;
-
-	dprintk("ttusb_start_feed\n");
-
-	switch (dvbdmxfeed->type) {
-	case DMX_TYPE_TS:
-		break;
-	case DMX_TYPE_SEC:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (dvbdmxfeed->type == DMX_TYPE_TS) {
-		switch (dvbdmxfeed->pes_type) {
-		case DMX_TS_PES_VIDEO:
-		case DMX_TS_PES_AUDIO:
-		case DMX_TS_PES_TELETEXT:
-		case DMX_TS_PES_PCR:
-		case DMX_TS_PES_OTHER:
-			break;
-		default:
-			return -EINVAL;
-		}
-	}
-
-#ifdef TTUSB_HWSECTIONS
-#error TODO: allocate filters
-	if (dvbdmxfeed->type == DMX_TYPE_TS) {
-		feed_type = 1;
-	} else if (dvbdmxfeed->type == DMX_TYPE_SEC) {
-		feed_type = 2;
-	}
-#endif
-
-	ttusb_set_channel(ttusb, dvbdmxfeed->index, feed_type, dvbdmxfeed->pid);
-
-	if (0 == ttusb->running_feed_count++)
-		ttusb_start_iso_xfer(ttusb);
-
-	return 0;
-}
-
-static int ttusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux;
-
-	ttusb_del_channel(ttusb, dvbdmxfeed->index);
-
-	if (--ttusb->running_feed_count == 0)
-		ttusb_stop_iso_xfer(ttusb);
-
-	return 0;
-}
-
-static int ttusb_setup_interfaces(struct ttusb *ttusb)
-{
-	usb_set_interface(ttusb->dev, 1, 1);
-
-	ttusb->bulk_out_pipe = usb_sndbulkpipe(ttusb->dev, 1);
-	ttusb->bulk_in_pipe = usb_rcvbulkpipe(ttusb->dev, 1);
-	ttusb->isoc_in_pipe = usb_rcvisocpipe(ttusb->dev, 2);
-
-	return 0;
-}
-
-#if 0
-static u8 stc_firmware[8192];
-
-static int stc_open(struct inode *inode, struct file *file)
-{
-	struct ttusb *ttusb = file->private_data;
-	int addr;
-
-	for (addr = 0; addr < 8192; addr += 16) {
-		u8 snd_buf[2] = { addr >> 8, addr & 0xFF };
-		ttusb_i2c_msg(ttusb, 0x50, snd_buf, 2, stc_firmware + addr,
-			      16);
-	}
-
-	return 0;
-}
-
-static ssize_t stc_read(struct file *file, char *buf, size_t count,
-		 loff_t *offset)
-{
-	return simple_read_from_buffer(buf, count, offset, stc_firmware, 8192);
-}
-
-static int stc_release(struct inode *inode, struct file *file)
-{
-	return 0;
-}
-
-static const struct file_operations stc_fops = {
-	.owner = THIS_MODULE,
-	.read = stc_read,
-	.open = stc_open,
-	.release = stc_release,
-};
-#endif
-
-static u32 functionality(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-
-
-static int alps_tdmb7_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
-	u8 data[4];
-	struct i2c_msg msg = {.addr=0x61, .flags=0, .buf=data, .len=sizeof(data) };
-	u32 div;
-
-	div = (p->frequency + 36166667) / 166667;
-
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = ((div >> 10) & 0x60) | 0x85;
-	data[3] = p->frequency < 592000000 ? 0x40 : 0x80;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO;
-	return 0;
-}
-
-static struct cx22700_config alps_tdmb7_config = {
-	.demod_address = 0x43,
-};
-
-
-
-
-
-static int philips_tdm1316l_tuner_init(struct dvb_frontend* fe)
-{
-	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
-	static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
-	static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
-	struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) };
-
-	// setup PLL configuration
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO;
-	msleep(1);
-
-	// disable the mc44BC374c (do not check for errors)
-	tuner_msg.addr = 0x65;
-	tuner_msg.buf = disable_mc44BC374c;
-	tuner_msg.len = sizeof(disable_mc44BC374c);
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
-		i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1);
-	}
-
-	return 0;
-}
-
-static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
-	u8 tuner_buf[4];
-	struct i2c_msg tuner_msg = {.addr=0x60, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) };
-	int tuner_frequency = 0;
-	u8 band, cp, filter;
-
-	// determine charge pump
-	tuner_frequency = p->frequency + 36130000;
-	if (tuner_frequency < 87000000) return -EINVAL;
-	else if (tuner_frequency < 130000000) cp = 3;
-	else if (tuner_frequency < 160000000) cp = 5;
-	else if (tuner_frequency < 200000000) cp = 6;
-	else if (tuner_frequency < 290000000) cp = 3;
-	else if (tuner_frequency < 420000000) cp = 5;
-	else if (tuner_frequency < 480000000) cp = 6;
-	else if (tuner_frequency < 620000000) cp = 3;
-	else if (tuner_frequency < 830000000) cp = 5;
-	else if (tuner_frequency < 895000000) cp = 7;
-	else return -EINVAL;
-
-	// determine band
-	if (p->frequency < 49000000)
-		return -EINVAL;
-	else if (p->frequency < 159000000)
-		band = 1;
-	else if (p->frequency < 444000000)
-		band = 2;
-	else if (p->frequency < 861000000)
-		band = 4;
-	else return -EINVAL;
-
-	// setup PLL filter
-	switch (p->bandwidth_hz) {
-	case 6000000:
-		tda1004x_writereg(fe, 0x0C, 0);
-		filter = 0;
-		break;
-
-	case 7000000:
-		tda1004x_writereg(fe, 0x0C, 0);
-		filter = 0;
-		break;
-
-	case 8000000:
-		tda1004x_writereg(fe, 0x0C, 0xFF);
-		filter = 1;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	// calculate divisor
-	// ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
-	tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000;
-
-	// setup tuner buffer
-	tuner_buf[0] = tuner_frequency >> 8;
-	tuner_buf[1] = tuner_frequency & 0xff;
-	tuner_buf[2] = 0xca;
-	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1)
-		return -EIO;
-
-	msleep(1);
-	return 0;
-}
-
-static int philips_tdm1316l_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
-{
-	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
-
-	return request_firmware(fw, name, &ttusb->dev->dev);
-}
-
-static struct tda1004x_config philips_tdm1316l_config = {
-
-	.demod_address = 0x8,
-	.invert = 1,
-	.invert_oclk = 0,
-	.request_firmware = philips_tdm1316l_request_firmware,
-};
-
-static u8 alps_bsbe1_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x30,
-	0x03, 0x00,
-	0x04, 0x7d,             /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-	0x05, 0x35,             /* I2CT = 0, SCLT = 1, SDAT = 1 */
-	0x06, 0x40,             /* DAC not used, set to high impendance mode */
-	0x07, 0x00,             /* DAC LSB */
-	0x08, 0x40,             /* DiSEqC off, LNB power on OP2/LOCK pin on */
-	0x09, 0x00,             /* FIFO */
-	0x0c, 0x51,             /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
-	0x0d, 0x82,             /* DC offset compensation = ON, beta_agc1 = 2 */
-	0x0e, 0x23,             /* alpha_tmg = 2, beta_tmg = 3 */
-	0x10, 0x3f,             // AGC2  0x3d
-	0x11, 0x84,
-	0x12, 0xb9,
-	0x15, 0xc9,             // lock detector threshold
-	0x16, 0x00,
-	0x17, 0x00,
-	0x18, 0x00,
-	0x19, 0x00,
-	0x1a, 0x00,
-	0x1f, 0x50,
-	0x20, 0x00,
-	0x21, 0x00,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x28, 0x00,             // out imp: normal  out type: parallel FEC mode:0
-	0x29, 0x1e,             // 1/2 threshold
-	0x2a, 0x14,             // 2/3 threshold
-	0x2b, 0x0f,             // 3/4 threshold
-	0x2c, 0x09,             // 5/6 threshold
-	0x2d, 0x05,             // 7/8 threshold
-	0x2e, 0x01,
-	0x31, 0x1f,             // test all FECs
-	0x32, 0x19,             // viterbi and synchro search
-	0x33, 0xfc,             // rs control
-	0x34, 0x93,             // error control
-	0x0f, 0x92,
-	0xff, 0xff
-};
-
-static u8 alps_bsru6_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x30,
-	0x03, 0x00,
-	0x04, 0x7d,		/* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-	0x05, 0x35,		/* I2CT = 0, SCLT = 1, SDAT = 1 */
-	0x06, 0x40,		/* DAC not used, set to high impendance mode */
-	0x07, 0x00,		/* DAC LSB */
-	0x08, 0x40,		/* DiSEqC off, LNB power on OP2/LOCK pin on */
-	0x09, 0x00,		/* FIFO */
-	0x0c, 0x51,		/* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
-	0x0d, 0x82,		/* DC offset compensation = ON, beta_agc1 = 2 */
-	0x0e, 0x23,		/* alpha_tmg = 2, beta_tmg = 3 */
-	0x10, 0x3f,		// AGC2  0x3d
-	0x11, 0x84,
-	0x12, 0xb9,
-	0x15, 0xc9,		// lock detector threshold
-	0x16, 0x00,
-	0x17, 0x00,
-	0x18, 0x00,
-	0x19, 0x00,
-	0x1a, 0x00,
-	0x1f, 0x50,
-	0x20, 0x00,
-	0x21, 0x00,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x28, 0x00,		// out imp: normal  out type: parallel FEC mode:0
-	0x29, 0x1e,		// 1/2 threshold
-	0x2a, 0x14,		// 2/3 threshold
-	0x2b, 0x0f,		// 3/4 threshold
-	0x2c, 0x09,		// 5/6 threshold
-	0x2d, 0x05,		// 7/8 threshold
-	0x2e, 0x01,
-	0x31, 0x1f,		// test all FECs
-	0x32, 0x19,		// viterbi and synchro search
-	0x33, 0xfc,		// rs control
-	0x34, 0x93,		// error control
-	0x0f, 0x52,
-	0xff, 0xff
-};
-
-static int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
-{
-	u8 aclk = 0;
-	u8 bclk = 0;
-
-	if (srate < 1500000) {
-		aclk = 0xb7;
-		bclk = 0x47;
-	} else if (srate < 3000000) {
-		aclk = 0xb7;
-		bclk = 0x4b;
-	} else if (srate < 7000000) {
-		aclk = 0xb7;
-		bclk = 0x4f;
-	} else if (srate < 14000000) {
-		aclk = 0xb7;
-		bclk = 0x53;
-	} else if (srate < 30000000) {
-		aclk = 0xb6;
-		bclk = 0x53;
-	} else if (srate < 45000000) {
-		aclk = 0xb4;
-		bclk = 0x51;
-	}
-
-	stv0299_writereg(fe, 0x13, aclk);
-	stv0299_writereg(fe, 0x14, bclk);
-	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
-	stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
-	stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
-
-	return 0;
-}
-
-static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
-	u8 buf[4];
-	u32 div;
-	struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
-
-	if ((p->frequency < 950000) || (p->frequency > 2150000))
-		return -EINVAL;
-
-	div = (p->frequency + (125 - 1)) / 125;	/* round correctly */
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = div & 0xff;
-	buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
-	buf[3] = 0xC4;
-
-	if (p->frequency > 1530000)
-		buf[3] = 0xC0;
-
-	/* BSBE1 wants XCE bit set */
-	if (ttusb->revision == TTUSB_REV_2_2)
-		buf[3] |= 0x20;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-
-	return 0;
-}
-
-static struct stv0299_config alps_stv0299_config = {
-	.demod_address = 0x68,
-	.inittab = alps_bsru6_inittab,
-	.mclk = 88000000UL,
-	.invert = 1,
-	.skip_reinit = 0,
-	.lock_output = STV0299_LOCKOUTPUT_1,
-	.volt13_op0_op1 = STV0299_VOLT13_OP1,
-	.min_delay_ms = 100,
-	.set_symbol_rate = alps_stv0299_set_symbol_rate,
-};
-
-static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
-	u8 buf[4];
-	u32 div;
-	struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
-
-	div = p->frequency / 125;
-
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = div & 0xff;
-	buf[2] = 0x8e;
-	buf[3] = 0x00;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-
-	return 0;
-}
-
-static struct tda8083_config ttusb_novas_grundig_29504_491_config = {
-
-	.demod_address = 0x68,
-};
-
-static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct ttusb* ttusb = fe->dvb->priv;
-	u32 div;
-	u8 data[4];
-	struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	div = (p->frequency + 35937500 + 31250) / 62500;
-
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0x85 | ((div >> 10) & 0x60);
-	data[3] = (p->frequency < 174000000 ? 0x88 : p->frequency < 470000000 ? 0x84 : 0x81);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer (&ttusb->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-
-	return 0;
-}
-
-
-static struct ves1820_config alps_tdbe2_config = {
-	.demod_address = 0x09,
-	.xin = 57840000UL,
-	.invert = 1,
-	.selagc = VES1820_SELAGC_SIGNAMPERR,
-};
-
-static u8 read_pwm(struct ttusb* ttusb)
-{
-	u8 b = 0xff;
-	u8 pwm;
-	struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
-				{ .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
-
-	if ((i2c_transfer(&ttusb->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
-		pwm = 0x48;
-
-	return pwm;
-}
-
-
-static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct ttusb *ttusb = (struct ttusb *) fe->dvb->priv;
-	u8 tuner_buf[5];
-	struct i2c_msg tuner_msg = {.addr = 0x60,
-				    .flags = 0,
-				    .buf = tuner_buf,
-				    .len = sizeof(tuner_buf) };
-	int tuner_frequency = 0;
-	u8 band, cp, filter;
-
-	// determine charge pump
-	tuner_frequency = p->frequency;
-	if      (tuner_frequency <  87000000) {return -EINVAL;}
-	else if (tuner_frequency < 130000000) {cp = 3; band = 1;}
-	else if (tuner_frequency < 160000000) {cp = 5; band = 1;}
-	else if (tuner_frequency < 200000000) {cp = 6; band = 1;}
-	else if (tuner_frequency < 290000000) {cp = 3; band = 2;}
-	else if (tuner_frequency < 420000000) {cp = 5; band = 2;}
-	else if (tuner_frequency < 480000000) {cp = 6; band = 2;}
-	else if (tuner_frequency < 620000000) {cp = 3; band = 4;}
-	else if (tuner_frequency < 830000000) {cp = 5; band = 4;}
-	else if (tuner_frequency < 895000000) {cp = 7; band = 4;}
-	else {return -EINVAL;}
-
-	// assume PLL filter should always be 8MHz for the moment.
-	filter = 1;
-
-	// calculate divisor
-	// (Finput + Fif)/Fref; Fif = 36125000 Hz, Fref = 62500 Hz
-	tuner_frequency = ((p->frequency + 36125000) / 62500);
-
-	// setup tuner buffer
-	tuner_buf[0] = tuner_frequency >> 8;
-	tuner_buf[1] = tuner_frequency & 0xff;
-	tuner_buf[2] = 0xc8;
-	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
-	tuner_buf[4] = 0x80;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
-		printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 1\n");
-		return -EIO;
-	}
-
-	msleep(50);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
-		printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 2\n");
-		return -EIO;
-	}
-
-	msleep(1);
-
-	return 0;
-}
-
-static u8 dvbc_philips_tdm1316l_inittab[] = {
-	0x80, 0x21,
-	0x80, 0x20,
-	0x81, 0x01,
-	0x81, 0x00,
-	0x00, 0x09,
-	0x01, 0x69,
-	0x03, 0x00,
-	0x04, 0x00,
-	0x07, 0x00,
-	0x08, 0x00,
-	0x20, 0x00,
-	0x21, 0x40,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x24, 0x40,
-	0x25, 0x88,
-	0x30, 0xff,
-	0x31, 0x00,
-	0x32, 0xff,
-	0x33, 0x00,
-	0x34, 0x50,
-	0x35, 0x7f,
-	0x36, 0x00,
-	0x37, 0x20,
-	0x38, 0x00,
-	0x40, 0x1c,
-	0x41, 0xff,
-	0x42, 0x29,
-	0x43, 0x20,
-	0x44, 0xff,
-	0x45, 0x00,
-	0x46, 0x00,
-	0x49, 0x04,
-	0x4a, 0xff,
-	0x4b, 0x7f,
-	0x52, 0x30,
-	0x55, 0xae,
-	0x56, 0x47,
-	0x57, 0xe1,
-	0x58, 0x3a,
-	0x5a, 0x1e,
-	0x5b, 0x34,
-	0x60, 0x00,
-	0x63, 0x00,
-	0x64, 0x00,
-	0x65, 0x00,
-	0x66, 0x00,
-	0x67, 0x00,
-	0x68, 0x00,
-	0x69, 0x00,
-	0x6a, 0x02,
-	0x6b, 0x00,
-	0x70, 0xff,
-	0x71, 0x00,
-	0x72, 0x00,
-	0x73, 0x00,
-	0x74, 0x0c,
-	0x80, 0x00,
-	0x81, 0x00,
-	0x82, 0x00,
-	0x83, 0x00,
-	0x84, 0x04,
-	0x85, 0x80,
-	0x86, 0x24,
-	0x87, 0x78,
-	0x88, 0x00,
-	0x89, 0x00,
-	0x90, 0x01,
-	0x91, 0x01,
-	0xa0, 0x00,
-	0xa1, 0x00,
-	0xa2, 0x00,
-	0xb0, 0x91,
-	0xb1, 0x0b,
-	0xc0, 0x4b,
-	0xc1, 0x00,
-	0xc2, 0x00,
-	0xd0, 0x00,
-	0xd1, 0x00,
-	0xd2, 0x00,
-	0xd3, 0x00,
-	0xd4, 0x00,
-	0xd5, 0x00,
-	0xde, 0x00,
-	0xdf, 0x00,
-	0x61, 0x38,
-	0x62, 0x0a,
-	0x53, 0x13,
-	0x59, 0x08,
-	0x55, 0x00,
-	0x56, 0x40,
-	0x57, 0x08,
-	0x58, 0x3d,
-	0x88, 0x10,
-	0xa0, 0x00,
-	0xa0, 0x00,
-	0xa0, 0x00,
-	0xa0, 0x04,
-	0xff, 0xff,
-};
-
-static struct stv0297_config dvbc_philips_tdm1316l_config = {
-	.demod_address = 0x1c,
-	.inittab = dvbc_philips_tdm1316l_inittab,
-	.invert = 0,
-};
-
-static void frontend_init(struct ttusb* ttusb)
-{
-	switch(le16_to_cpu(ttusb->dev->descriptor.idProduct)) {
-	case 0x1003: // Hauppauge/TT Nova-USB-S budget (stv0299/ALPS BSRU6|BSBE1(tsa5059))
-		// try the stv0299 based first
-		ttusb->fe = dvb_attach(stv0299_attach, &alps_stv0299_config, &ttusb->i2c_adap);
-		if (ttusb->fe != NULL) {
-			ttusb->fe->ops.tuner_ops.set_params = philips_tsa5059_tuner_set_params;
-
-			if(ttusb->revision == TTUSB_REV_2_2) { // ALPS BSBE1
-				alps_stv0299_config.inittab = alps_bsbe1_inittab;
-				dvb_attach(lnbp21_attach, ttusb->fe, &ttusb->i2c_adap, 0, 0);
-			} else { // ALPS BSRU6
-				ttusb->fe->ops.set_voltage = ttusb_set_voltage;
-			}
-			break;
-		}
-
-		// Grundig 29504-491
-		ttusb->fe = dvb_attach(tda8083_attach, &ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap);
-		if (ttusb->fe != NULL) {
-			ttusb->fe->ops.tuner_ops.set_params = ttusb_novas_grundig_29504_491_tuner_set_params;
-			ttusb->fe->ops.set_voltage = ttusb_set_voltage;
-			break;
-		}
-		break;
-
-	case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
-		ttusb->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb));
-		if (ttusb->fe != NULL) {
-			ttusb->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
-			break;
-		}
-
-		ttusb->fe = dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &ttusb->i2c_adap);
-		if (ttusb->fe != NULL) {
-			ttusb->fe->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
-			break;
-		}
-		break;
-
-	case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??))
-		// try the ALPS TDMB7 first
-		ttusb->fe = dvb_attach(cx22700_attach, &alps_tdmb7_config, &ttusb->i2c_adap);
-		if (ttusb->fe != NULL) {
-			ttusb->fe->ops.tuner_ops.set_params = alps_tdmb7_tuner_set_params;
-			break;
-		}
-
-		// Philips td1316
-		ttusb->fe = dvb_attach(tda10046_attach, &philips_tdm1316l_config, &ttusb->i2c_adap);
-		if (ttusb->fe != NULL) {
-			ttusb->fe->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
-			ttusb->fe->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
-			break;
-		}
-		break;
-	}
-
-	if (ttusb->fe == NULL) {
-		printk("dvb-ttusb-budget: A frontend driver was not found for device [%04x:%04x]\n",
-		       le16_to_cpu(ttusb->dev->descriptor.idVendor),
-		       le16_to_cpu(ttusb->dev->descriptor.idProduct));
-	} else {
-		if (dvb_register_frontend(&ttusb->adapter, ttusb->fe)) {
-			printk("dvb-ttusb-budget: Frontend registration failed!\n");
-			dvb_frontend_detach(ttusb->fe);
-			ttusb->fe = NULL;
-		}
-	}
-}
-
-
-
-static struct i2c_algorithm ttusb_dec_algo = {
-	.master_xfer	= master_xfer,
-	.functionality	= functionality,
-};
-
-static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-	struct usb_device *udev;
-	struct ttusb *ttusb;
-	int result;
-
-	dprintk("%s: TTUSB DVB connected\n", __func__);
-
-	udev = interface_to_usbdev(intf);
-
-	if (intf->altsetting->desc.bInterfaceNumber != 1) return -ENODEV;
-
-	if (!(ttusb = kzalloc(sizeof(struct ttusb), GFP_KERNEL)))
-		return -ENOMEM;
-
-	ttusb->dev = udev;
-	ttusb->c = 0;
-	ttusb->mux_state = 0;
-	mutex_init(&ttusb->semi2c);
-
-	mutex_lock(&ttusb->semi2c);
-
-	mutex_init(&ttusb->semusb);
-
-	ttusb_setup_interfaces(ttusb);
-
-	result = ttusb_alloc_iso_urbs(ttusb);
-	if (result < 0) {
-		dprintk("%s: ttusb_alloc_iso_urbs - failed\n", __func__);
-		mutex_unlock(&ttusb->semi2c);
-		kfree(ttusb);
-		return result;
-	}
-
-	if (ttusb_init_controller(ttusb))
-		printk("ttusb_init_controller: error\n");
-
-	mutex_unlock(&ttusb->semi2c);
-
-	result = dvb_register_adapter(&ttusb->adapter,
-				      "Technotrend/Hauppauge Nova-USB",
-				      THIS_MODULE, &udev->dev, adapter_nr);
-	if (result < 0) {
-		ttusb_free_iso_urbs(ttusb);
-		kfree(ttusb);
-		return result;
-	}
-	ttusb->adapter.priv = ttusb;
-
-	/* i2c */
-	memset(&ttusb->i2c_adap, 0, sizeof(struct i2c_adapter));
-	strcpy(ttusb->i2c_adap.name, "TTUSB DEC");
-
-	i2c_set_adapdata(&ttusb->i2c_adap, ttusb);
-
-	ttusb->i2c_adap.algo              = &ttusb_dec_algo;
-	ttusb->i2c_adap.algo_data         = NULL;
-	ttusb->i2c_adap.dev.parent	  = &udev->dev;
-
-	result = i2c_add_adapter(&ttusb->i2c_adap);
-	if (result)
-		goto err_unregister_adapter;
-
-	memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux));
-
-	ttusb->dvb_demux.dmx.capabilities =
-	    DMX_TS_FILTERING | DMX_SECTION_FILTERING;
-	ttusb->dvb_demux.priv = NULL;
-#ifdef TTUSB_HWSECTIONS
-	ttusb->dvb_demux.filternum = TTUSB_MAXFILTER;
-#else
-	ttusb->dvb_demux.filternum = 32;
-#endif
-	ttusb->dvb_demux.feednum = TTUSB_MAXCHANNEL;
-	ttusb->dvb_demux.start_feed = ttusb_start_feed;
-	ttusb->dvb_demux.stop_feed = ttusb_stop_feed;
-	ttusb->dvb_demux.write_to_decoder = NULL;
-
-	result = dvb_dmx_init(&ttusb->dvb_demux);
-	if (result < 0) {
-		printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n", result);
-		result = -ENODEV;
-		goto err_i2c_del_adapter;
-	}
-//FIXME dmxdev (nur WAS?)
-	ttusb->dmxdev.filternum = ttusb->dvb_demux.filternum;
-	ttusb->dmxdev.demux = &ttusb->dvb_demux.dmx;
-	ttusb->dmxdev.capabilities = 0;
-
-	result = dvb_dmxdev_init(&ttusb->dmxdev, &ttusb->adapter);
-	if (result < 0) {
-		printk("ttusb_dvb: dvb_dmxdev_init failed (errno = %d)\n",
-		       result);
-		result = -ENODEV;
-		goto err_release_dmx;
-	}
-
-	if (dvb_net_init(&ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) {
-		printk("ttusb_dvb: dvb_net_init failed!\n");
-		result = -ENODEV;
-		goto err_release_dmxdev;
-	}
-
-	usb_set_intfdata(intf, (void *) ttusb);
-
-	frontend_init(ttusb);
-
-	return 0;
-
-err_release_dmxdev:
-	dvb_dmxdev_release(&ttusb->dmxdev);
-err_release_dmx:
-	dvb_dmx_release(&ttusb->dvb_demux);
-err_i2c_del_adapter:
-	i2c_del_adapter(&ttusb->i2c_adap);
-err_unregister_adapter:
-	dvb_unregister_adapter (&ttusb->adapter);
-	return result;
-}
-
-static void ttusb_disconnect(struct usb_interface *intf)
-{
-	struct ttusb *ttusb = usb_get_intfdata(intf);
-
-	usb_set_intfdata(intf, NULL);
-
-	ttusb->disconnecting = 1;
-
-	ttusb_stop_iso_xfer(ttusb);
-
-	ttusb->dvb_demux.dmx.close(&ttusb->dvb_demux.dmx);
-	dvb_net_release(&ttusb->dvbnet);
-	dvb_dmxdev_release(&ttusb->dmxdev);
-	dvb_dmx_release(&ttusb->dvb_demux);
-	if (ttusb->fe != NULL) {
-		dvb_unregister_frontend(ttusb->fe);
-		dvb_frontend_detach(ttusb->fe);
-	}
-	i2c_del_adapter(&ttusb->i2c_adap);
-	dvb_unregister_adapter(&ttusb->adapter);
-
-	ttusb_free_iso_urbs(ttusb);
-
-	kfree(ttusb);
-
-	dprintk("%s: TTUSB DVB disconnected\n", __func__);
-}
-
-static struct usb_device_id ttusb_table[] = {
-	{USB_DEVICE(0xb48, 0x1003)},
-	{USB_DEVICE(0xb48, 0x1004)},
-	{USB_DEVICE(0xb48, 0x1005)},
-	{}
-};
-
-MODULE_DEVICE_TABLE(usb, ttusb_table);
-
-static struct usb_driver ttusb_driver = {
-      .name		= "ttusb",
-      .probe		= ttusb_probe,
-      .disconnect	= ttusb_disconnect,
-      .id_table		= ttusb_table,
-};
-
-module_usb_driver(ttusb_driver);
-
-MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>");
-MODULE_DESCRIPTION("TTUSB DVB Driver");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("ttusb-budget/dspbootcode.bin");
diff --git a/drivers/media/dvb/ttusb-dec/Kconfig b/drivers/media/dvb/ttusb-dec/Kconfig
deleted file mode 100644
index 290254a..0000000
--- a/drivers/media/dvb/ttusb-dec/Kconfig
+++ /dev/null
@@ -1,21 +0,0 @@
-config DVB_TTUSB_DEC
-	tristate "Technotrend/Hauppauge USB DEC devices"
-	depends on DVB_CORE && USB && INPUT && PCI
-	select CRC32
-	help
-	  Support for external USB adapters designed by Technotrend and
-	  produced by Hauppauge, shipped under the brand name 'DEC2000-t'
-	  and 'DEC3000-s'.
-
-	  Even if these devices have a MPEG decoder built in, they transmit
-	  only compressed MPEG data over the USB bus, so you need
-	  an external software decoder to watch TV on your computer.
-
-	  This driver needs external firmware. Please use the commands
-	  "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2000t",
-	  "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2540t",
-	  "<kerneldir>/Documentation/dvb/get_dvb_firmware dec3000s",
-	  download/extract them, and then copy them to /usr/lib/hotplug/firmware
-	  or /lib/firmware (depending on configuration of firmware hotplug).
-
-	  Say Y if you own such a device and want to use it.
diff --git a/drivers/media/dvb/ttusb-dec/Makefile b/drivers/media/dvb/ttusb-dec/Makefile
deleted file mode 100644
index ed28b53..0000000
--- a/drivers/media/dvb/ttusb-dec/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
deleted file mode 100644
index 504c812..0000000
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ /dev/null
@@ -1,1764 +0,0 @@
-/*
- * TTUSB DEC Driver
- *
- * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.org>
- * IR support by Peter Beutner <p.beutner@gmx.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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-#include <linux/interrupt.h>
-#include <linux/firmware.h>
-#include <linux/crc32.h>
-#include <linux/init.h>
-#include <linux/input.h>
-
-#include <linux/mutex.h>
-
-#include "dmxdev.h"
-#include "dvb_demux.h"
-#include "dvb_filter.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-#include "ttusbdecfe.h"
-
-static int debug;
-static int output_pva;
-static int enable_rc;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-module_param(output_pva, int, 0444);
-MODULE_PARM_DESC(output_pva, "Output PVA from dvr device (default:off)");
-module_param(enable_rc, int, 0644);
-MODULE_PARM_DESC(enable_rc, "Turn on/off IR remote control(default: off)");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define dprintk	if (debug) printk
-
-#define DRIVER_NAME		"TechnoTrend/Hauppauge DEC USB"
-
-#define COMMAND_PIPE		0x03
-#define RESULT_PIPE		0x04
-#define IN_PIPE			0x08
-#define OUT_PIPE		0x07
-#define IRQ_PIPE		0x0A
-
-#define COMMAND_PACKET_SIZE	0x3c
-#define ARM_PACKET_SIZE		0x1000
-#define IRQ_PACKET_SIZE		0x8
-
-#define ISO_BUF_COUNT		0x04
-#define FRAMES_PER_ISO_BUF	0x04
-#define ISO_FRAME_SIZE		0x0380
-
-#define	MAX_PVA_LENGTH		6144
-
-enum ttusb_dec_model {
-	TTUSB_DEC2000T,
-	TTUSB_DEC2540T,
-	TTUSB_DEC3000S
-};
-
-enum ttusb_dec_packet_type {
-	TTUSB_DEC_PACKET_PVA,
-	TTUSB_DEC_PACKET_SECTION,
-	TTUSB_DEC_PACKET_EMPTY
-};
-
-enum ttusb_dec_interface {
-	TTUSB_DEC_INTERFACE_INITIAL,
-	TTUSB_DEC_INTERFACE_IN,
-	TTUSB_DEC_INTERFACE_OUT
-};
-
-struct ttusb_dec {
-	enum ttusb_dec_model		model;
-	char				*model_name;
-	char				*firmware_name;
-	int				can_playback;
-
-	/* DVB bits */
-	struct dvb_adapter		adapter;
-	struct dmxdev			dmxdev;
-	struct dvb_demux		demux;
-	struct dmx_frontend		frontend;
-	struct dvb_net			dvb_net;
-	struct dvb_frontend*		fe;
-
-	u16			pid[DMX_PES_OTHER];
-
-	/* USB bits */
-	struct usb_device		*udev;
-	u8				trans_count;
-	unsigned int			command_pipe;
-	unsigned int			result_pipe;
-	unsigned int			in_pipe;
-	unsigned int			out_pipe;
-	unsigned int			irq_pipe;
-	enum ttusb_dec_interface	interface;
-	struct mutex			usb_mutex;
-
-	void			*irq_buffer;
-	struct urb		*irq_urb;
-	dma_addr_t		irq_dma_handle;
-	void			*iso_buffer;
-	dma_addr_t		iso_dma_handle;
-	struct urb		*iso_urb[ISO_BUF_COUNT];
-	int			iso_stream_count;
-	struct mutex		iso_mutex;
-
-	u8				packet[MAX_PVA_LENGTH + 4];
-	enum ttusb_dec_packet_type	packet_type;
-	int				packet_state;
-	int				packet_length;
-	int				packet_payload_length;
-	u16				next_packet_id;
-
-	int				pva_stream_count;
-	int				filter_stream_count;
-
-	struct dvb_filter_pes2ts	a_pes2ts;
-	struct dvb_filter_pes2ts	v_pes2ts;
-
-	u8			v_pes[16 + MAX_PVA_LENGTH];
-	int			v_pes_length;
-	int			v_pes_postbytes;
-
-	struct list_head	urb_frame_list;
-	struct tasklet_struct	urb_tasklet;
-	spinlock_t		urb_frame_list_lock;
-
-	struct dvb_demux_filter	*audio_filter;
-	struct dvb_demux_filter	*video_filter;
-	struct list_head	filter_info_list;
-	spinlock_t		filter_info_list_lock;
-
-	struct input_dev	*rc_input_dev;
-	char			rc_phys[64];
-
-	int			active; /* Loaded successfully */
-};
-
-struct urb_frame {
-	u8			data[ISO_FRAME_SIZE];
-	int			length;
-	struct list_head	urb_frame_list;
-};
-
-struct filter_info {
-	u8			stream_id;
-	struct dvb_demux_filter	*filter;
-	struct list_head	filter_info_list;
-};
-
-static u16 rc_keys[] = {
-	KEY_POWER,
-	KEY_MUTE,
-	KEY_1,
-	KEY_2,
-	KEY_3,
-	KEY_4,
-	KEY_5,
-	KEY_6,
-	KEY_7,
-	KEY_8,
-	KEY_9,
-	KEY_0,
-	KEY_CHANNELUP,
-	KEY_VOLUMEDOWN,
-	KEY_OK,
-	KEY_VOLUMEUP,
-	KEY_CHANNELDOWN,
-	KEY_PREVIOUS,
-	KEY_ESC,
-	KEY_RED,
-	KEY_GREEN,
-	KEY_YELLOW,
-	KEY_BLUE,
-	KEY_OPTION,
-	KEY_M,
-	KEY_RADIO
-};
-
-static void ttusb_dec_set_model(struct ttusb_dec *dec,
-				enum ttusb_dec_model model);
-
-static void ttusb_dec_handle_irq( struct urb *urb)
-{
-	struct ttusb_dec * dec = urb->context;
-	char *buffer = dec->irq_buffer;
-	int retval;
-
-	switch(urb->status) {
-		case 0: /*success*/
-			break;
-		case -ECONNRESET:
-		case -ENOENT:
-		case -ESHUTDOWN:
-		case -ETIME:
-			/* this urb is dead, cleanup */
-			dprintk("%s:urb shutting down with status: %d\n",
-					__func__, urb->status);
-			return;
-		default:
-			dprintk("%s:nonzero status received: %d\n",
-					__func__,urb->status);
-			goto exit;
-	}
-
-	if( (buffer[0] == 0x1) && (buffer[2] == 0x15) )  {
-		/* IR - Event */
-		/* this is an fact a bit too simple implementation;
-		 * the box also reports a keyrepeat signal
-		 * (with buffer[3] == 0x40) in an intervall of ~100ms.
-		 * But to handle this correctly we had to imlemenent some
-		 * kind of timer which signals a 'key up' event if no
-		 * keyrepeat signal is received for lets say 200ms.
-		 * this should/could be added later ...
-		 * for now lets report each signal as a key down and up*/
-		dprintk("%s:rc signal:%d\n", __func__, buffer[4]);
-		input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 1);
-		input_sync(dec->rc_input_dev);
-		input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 0);
-		input_sync(dec->rc_input_dev);
-	}
-
-exit:	retval = usb_submit_urb(urb, GFP_ATOMIC);
-	if(retval)
-		printk("%s - usb_commit_urb failed with result: %d\n",
-			__func__, retval);
-}
-
-static u16 crc16(u16 crc, const u8 *buf, size_t len)
-{
-	u16 tmp;
-
-	while (len--) {
-		crc ^= *buf++;
-		crc ^= (u8)crc >> 4;
-		tmp = (u8)crc;
-		crc ^= (tmp ^ (tmp << 1)) << 4;
-	}
-	return crc;
-}
-
-static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
-				  int param_length, const u8 params[],
-				  int *result_length, u8 cmd_result[])
-{
-	int result, actual_len, i;
-	u8 *b;
-
-	dprintk("%s\n", __func__);
-
-	b = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL);
-	if (!b)
-		return -ENOMEM;
-
-	if ((result = mutex_lock_interruptible(&dec->usb_mutex))) {
-		kfree(b);
-		printk("%s: Failed to lock usb mutex.\n", __func__);
-		return result;
-	}
-
-	b[0] = 0xaa;
-	b[1] = ++dec->trans_count;
-	b[2] = command;
-	b[3] = param_length;
-
-	if (params)
-		memcpy(&b[4], params, param_length);
-
-	if (debug) {
-		printk("%s: command: ", __func__);
-		for (i = 0; i < param_length + 4; i++)
-			printk("0x%02X ", b[i]);
-		printk("\n");
-	}
-
-	result = usb_bulk_msg(dec->udev, dec->command_pipe, b,
-			      COMMAND_PACKET_SIZE + 4, &actual_len, 1000);
-
-	if (result) {
-		printk("%s: command bulk message failed: error %d\n",
-		       __func__, result);
-		mutex_unlock(&dec->usb_mutex);
-		kfree(b);
-		return result;
-	}
-
-	result = usb_bulk_msg(dec->udev, dec->result_pipe, b,
-			      COMMAND_PACKET_SIZE + 4, &actual_len, 1000);
-
-	if (result) {
-		printk("%s: result bulk message failed: error %d\n",
-		       __func__, result);
-		mutex_unlock(&dec->usb_mutex);
-		kfree(b);
-		return result;
-	} else {
-		if (debug) {
-			printk("%s: result: ", __func__);
-			for (i = 0; i < actual_len; i++)
-				printk("0x%02X ", b[i]);
-			printk("\n");
-		}
-
-		if (result_length)
-			*result_length = b[3];
-		if (cmd_result && b[3] > 0)
-			memcpy(cmd_result, &b[4], b[3]);
-
-		mutex_unlock(&dec->usb_mutex);
-
-		kfree(b);
-		return 0;
-	}
-}
-
-static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode,
-				    unsigned int *model, unsigned int *version)
-{
-	u8 c[COMMAND_PACKET_SIZE];
-	int c_length;
-	int result;
-	__be32 tmp;
-
-	dprintk("%s\n", __func__);
-
-	result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c);
-	if (result)
-		return result;
-
-	if (c_length >= 0x0c) {
-		if (mode != NULL) {
-			memcpy(&tmp, c, 4);
-			*mode = ntohl(tmp);
-		}
-		if (model != NULL) {
-			memcpy(&tmp, &c[4], 4);
-			*model = ntohl(tmp);
-		}
-		if (version != NULL) {
-			memcpy(&tmp, &c[8], 4);
-			*version = ntohl(tmp);
-		}
-		return 0;
-	} else {
-		return -1;
-	}
-}
-
-static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data)
-{
-	struct ttusb_dec *dec = priv;
-
-	dec->audio_filter->feed->cb.ts(data, 188, NULL, 0,
-				       &dec->audio_filter->feed->feed.ts,
-				       DMX_OK);
-
-	return 0;
-}
-
-static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data)
-{
-	struct ttusb_dec *dec = priv;
-
-	dec->video_filter->feed->cb.ts(data, 188, NULL, 0,
-				       &dec->video_filter->feed->feed.ts,
-				       DMX_OK);
-
-	return 0;
-}
-
-static void ttusb_dec_set_pids(struct ttusb_dec *dec)
-{
-	u8 b[] = { 0x00, 0x00, 0x00, 0x00,
-		   0x00, 0x00, 0xff, 0xff,
-		   0xff, 0xff, 0xff, 0xff };
-
-	__be16 pcr = htons(dec->pid[DMX_PES_PCR]);
-	__be16 audio = htons(dec->pid[DMX_PES_AUDIO]);
-	__be16 video = htons(dec->pid[DMX_PES_VIDEO]);
-
-	dprintk("%s\n", __func__);
-
-	memcpy(&b[0], &pcr, 2);
-	memcpy(&b[2], &audio, 2);
-	memcpy(&b[4], &video, 2);
-
-	ttusb_dec_send_command(dec, 0x50, sizeof(b), b, NULL, NULL);
-
-	dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO],
-			       ttusb_dec_audio_pes2ts_cb, dec);
-	dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO],
-			       ttusb_dec_video_pes2ts_cb, dec);
-	dec->v_pes_length = 0;
-	dec->v_pes_postbytes = 0;
-}
-
-static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length)
-{
-	if (length < 8) {
-		printk("%s: packet too short - discarding\n", __func__);
-		return;
-	}
-
-	if (length > 8 + MAX_PVA_LENGTH) {
-		printk("%s: packet too long - discarding\n", __func__);
-		return;
-	}
-
-	switch (pva[2]) {
-
-	case 0x01: {		/* VideoStream */
-		int prebytes = pva[5] & 0x03;
-		int postbytes = (pva[5] & 0x0c) >> 2;
-		__be16 v_pes_payload_length;
-
-		if (output_pva) {
-			dec->video_filter->feed->cb.ts(pva, length, NULL, 0,
-				&dec->video_filter->feed->feed.ts, DMX_OK);
-			return;
-		}
-
-		if (dec->v_pes_postbytes > 0 &&
-		    dec->v_pes_postbytes == prebytes) {
-			memcpy(&dec->v_pes[dec->v_pes_length],
-			       &pva[12], prebytes);
-
-			dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,
-					  dec->v_pes_length + prebytes, 1);
-		}
-
-		if (pva[5] & 0x10) {
-			dec->v_pes[7] = 0x80;
-			dec->v_pes[8] = 0x05;
-
-			dec->v_pes[9] = 0x21 | ((pva[8] & 0xc0) >> 5);
-			dec->v_pes[10] = ((pva[8] & 0x3f) << 2) |
-					 ((pva[9] & 0xc0) >> 6);
-			dec->v_pes[11] = 0x01 |
-					 ((pva[9] & 0x3f) << 2) |
-					 ((pva[10] & 0x80) >> 6);
-			dec->v_pes[12] = ((pva[10] & 0x7f) << 1) |
-					 ((pva[11] & 0xc0) >> 7);
-			dec->v_pes[13] = 0x01 | ((pva[11] & 0x7f) << 1);
-
-			memcpy(&dec->v_pes[14], &pva[12 + prebytes],
-			       length - 12 - prebytes);
-			dec->v_pes_length = 14 + length - 12 - prebytes;
-		} else {
-			dec->v_pes[7] = 0x00;
-			dec->v_pes[8] = 0x00;
-
-			memcpy(&dec->v_pes[9], &pva[8], length - 8);
-			dec->v_pes_length = 9 + length - 8;
-		}
-
-		dec->v_pes_postbytes = postbytes;
-
-		if (dec->v_pes[9 + dec->v_pes[8]] == 0x00 &&
-		    dec->v_pes[10 + dec->v_pes[8]] == 0x00 &&
-		    dec->v_pes[11 + dec->v_pes[8]] == 0x01)
-			dec->v_pes[6] = 0x84;
-		else
-			dec->v_pes[6] = 0x80;
-
-		v_pes_payload_length = htons(dec->v_pes_length - 6 +
-					     postbytes);
-		memcpy(&dec->v_pes[4], &v_pes_payload_length, 2);
-
-		if (postbytes == 0)
-			dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,
-					  dec->v_pes_length, 1);
-
-		break;
-	}
-
-	case 0x02:		/* MainAudioStream */
-		if (output_pva) {
-			dec->audio_filter->feed->cb.ts(pva, length, NULL, 0,
-				&dec->audio_filter->feed->feed.ts, DMX_OK);
-			return;
-		}
-
-		dvb_filter_pes2ts(&dec->a_pes2ts, &pva[8], length - 8,
-				  pva[5] & 0x10);
-		break;
-
-	default:
-		printk("%s: unknown PVA type: %02x.\n", __func__,
-		       pva[2]);
-		break;
-	}
-}
-
-static void ttusb_dec_process_filter(struct ttusb_dec *dec, u8 *packet,
-				     int length)
-{
-	struct list_head *item;
-	struct filter_info *finfo;
-	struct dvb_demux_filter *filter = NULL;
-	unsigned long flags;
-	u8 sid;
-
-	sid = packet[1];
-	spin_lock_irqsave(&dec->filter_info_list_lock, flags);
-	for (item = dec->filter_info_list.next; item != &dec->filter_info_list;
-	     item = item->next) {
-		finfo = list_entry(item, struct filter_info, filter_info_list);
-		if (finfo->stream_id == sid) {
-			filter = finfo->filter;
-			break;
-		}
-	}
-	spin_unlock_irqrestore(&dec->filter_info_list_lock, flags);
-
-	if (filter)
-		filter->feed->cb.sec(&packet[2], length - 2, NULL, 0,
-				     &filter->filter, DMX_OK);
-}
-
-static void ttusb_dec_process_packet(struct ttusb_dec *dec)
-{
-	int i;
-	u16 csum = 0;
-	u16 packet_id;
-
-	if (dec->packet_length % 2) {
-		printk("%s: odd sized packet - discarding\n", __func__);
-		return;
-	}
-
-	for (i = 0; i < dec->packet_length; i += 2)
-		csum ^= ((dec->packet[i] << 8) + dec->packet[i + 1]);
-
-	if (csum) {
-		printk("%s: checksum failed - discarding\n", __func__);
-		return;
-	}
-
-	packet_id = dec->packet[dec->packet_length - 4] << 8;
-	packet_id += dec->packet[dec->packet_length - 3];
-
-	if ((packet_id != dec->next_packet_id) && dec->next_packet_id) {
-		printk("%s: warning: lost packets between %u and %u\n",
-		       __func__, dec->next_packet_id - 1, packet_id);
-	}
-
-	if (packet_id == 0xffff)
-		dec->next_packet_id = 0x8000;
-	else
-		dec->next_packet_id = packet_id + 1;
-
-	switch (dec->packet_type) {
-	case TTUSB_DEC_PACKET_PVA:
-		if (dec->pva_stream_count)
-			ttusb_dec_process_pva(dec, dec->packet,
-					      dec->packet_payload_length);
-		break;
-
-	case TTUSB_DEC_PACKET_SECTION:
-		if (dec->filter_stream_count)
-			ttusb_dec_process_filter(dec, dec->packet,
-						 dec->packet_payload_length);
-		break;
-
-	case TTUSB_DEC_PACKET_EMPTY:
-		break;
-	}
-}
-
-static void swap_bytes(u8 *b, int length)
-{
-	u8 c;
-
-	length -= length % 2;
-	for (; length; b += 2, length -= 2) {
-		c = *b;
-		*b = *(b + 1);
-		*(b + 1) = c;
-	}
-}
-
-static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b,
-					int length)
-{
-	swap_bytes(b, length);
-
-	while (length) {
-		switch (dec->packet_state) {
-
-		case 0:
-		case 1:
-		case 2:
-			if (*b++ == 0xaa)
-				dec->packet_state++;
-			else
-				dec->packet_state = 0;
-
-			length--;
-			break;
-
-		case 3:
-			if (*b == 0x00) {
-				dec->packet_state++;
-				dec->packet_length = 0;
-			} else if (*b != 0xaa) {
-				dec->packet_state = 0;
-			}
-
-			b++;
-			length--;
-			break;
-
-		case 4:
-			dec->packet[dec->packet_length++] = *b++;
-
-			if (dec->packet_length == 2) {
-				if (dec->packet[0] == 'A' &&
-				    dec->packet[1] == 'V') {
-					dec->packet_type =
-						TTUSB_DEC_PACKET_PVA;
-					dec->packet_state++;
-				} else if (dec->packet[0] == 'S') {
-					dec->packet_type =
-						TTUSB_DEC_PACKET_SECTION;
-					dec->packet_state++;
-				} else if (dec->packet[0] == 0x00) {
-					dec->packet_type =
-						TTUSB_DEC_PACKET_EMPTY;
-					dec->packet_payload_length = 2;
-					dec->packet_state = 7;
-				} else {
-					printk("%s: unknown packet type: "
-					       "%02x%02x\n", __func__,
-					       dec->packet[0], dec->packet[1]);
-					dec->packet_state = 0;
-				}
-			}
-
-			length--;
-			break;
-
-		case 5:
-			dec->packet[dec->packet_length++] = *b++;
-
-			if (dec->packet_type == TTUSB_DEC_PACKET_PVA &&
-			    dec->packet_length == 8) {
-				dec->packet_state++;
-				dec->packet_payload_length = 8 +
-					(dec->packet[6] << 8) +
-					dec->packet[7];
-			} else if (dec->packet_type ==
-					TTUSB_DEC_PACKET_SECTION &&
-				   dec->packet_length == 5) {
-				dec->packet_state++;
-				dec->packet_payload_length = 5 +
-					((dec->packet[3] & 0x0f) << 8) +
-					dec->packet[4];
-			}
-
-			length--;
-			break;
-
-		case 6: {
-			int remainder = dec->packet_payload_length -
-					dec->packet_length;
-
-			if (length >= remainder) {
-				memcpy(dec->packet + dec->packet_length,
-				       b, remainder);
-				dec->packet_length += remainder;
-				b += remainder;
-				length -= remainder;
-				dec->packet_state++;
-			} else {
-				memcpy(&dec->packet[dec->packet_length],
-				       b, length);
-				dec->packet_length += length;
-				length = 0;
-			}
-
-			break;
-		}
-
-		case 7: {
-			int tail = 4;
-
-			dec->packet[dec->packet_length++] = *b++;
-
-			if (dec->packet_type == TTUSB_DEC_PACKET_SECTION &&
-			    dec->packet_payload_length % 2)
-				tail++;
-
-			if (dec->packet_length ==
-			    dec->packet_payload_length + tail) {
-				ttusb_dec_process_packet(dec);
-				dec->packet_state = 0;
-			}
-
-			length--;
-			break;
-		}
-
-		default:
-			printk("%s: illegal packet state encountered.\n",
-			       __func__);
-			dec->packet_state = 0;
-		}
-	}
-}
-
-static void ttusb_dec_process_urb_frame_list(unsigned long data)
-{
-	struct ttusb_dec *dec = (struct ttusb_dec *)data;
-	struct list_head *item;
-	struct urb_frame *frame;
-	unsigned long flags;
-
-	while (1) {
-		spin_lock_irqsave(&dec->urb_frame_list_lock, flags);
-		if ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) {
-			frame = list_entry(item, struct urb_frame,
-					   urb_frame_list);
-			list_del(&frame->urb_frame_list);
-		} else {
-			spin_unlock_irqrestore(&dec->urb_frame_list_lock,
-					       flags);
-			return;
-		}
-		spin_unlock_irqrestore(&dec->urb_frame_list_lock, flags);
-
-		ttusb_dec_process_urb_frame(dec, frame->data, frame->length);
-		kfree(frame);
-	}
-}
-
-static void ttusb_dec_process_urb(struct urb *urb)
-{
-	struct ttusb_dec *dec = urb->context;
-
-	if (!urb->status) {
-		int i;
-
-		for (i = 0; i < FRAMES_PER_ISO_BUF; i++) {
-			struct usb_iso_packet_descriptor *d;
-			u8 *b;
-			int length;
-			struct urb_frame *frame;
-
-			d = &urb->iso_frame_desc[i];
-			b = urb->transfer_buffer + d->offset;
-			length = d->actual_length;
-
-			if ((frame = kmalloc(sizeof(struct urb_frame),
-					     GFP_ATOMIC))) {
-				unsigned long flags;
-
-				memcpy(frame->data, b, length);
-				frame->length = length;
-
-				spin_lock_irqsave(&dec->urb_frame_list_lock,
-						     flags);
-				list_add_tail(&frame->urb_frame_list,
-					      &dec->urb_frame_list);
-				spin_unlock_irqrestore(&dec->urb_frame_list_lock,
-						       flags);
-
-				tasklet_schedule(&dec->urb_tasklet);
-			}
-		}
-	} else {
-		 /* -ENOENT is expected when unlinking urbs */
-		if (urb->status != -ENOENT)
-			dprintk("%s: urb error: %d\n", __func__,
-				urb->status);
-	}
-
-	if (dec->iso_stream_count)
-		usb_submit_urb(urb, GFP_ATOMIC);
-}
-
-static void ttusb_dec_setup_urbs(struct ttusb_dec *dec)
-{
-	int i, j, buffer_offset = 0;
-
-	dprintk("%s\n", __func__);
-
-	for (i = 0; i < ISO_BUF_COUNT; i++) {
-		int frame_offset = 0;
-		struct urb *urb = dec->iso_urb[i];
-
-		urb->dev = dec->udev;
-		urb->context = dec;
-		urb->complete = ttusb_dec_process_urb;
-		urb->pipe = dec->in_pipe;
-		urb->transfer_flags = URB_ISO_ASAP;
-		urb->interval = 1;
-		urb->number_of_packets = FRAMES_PER_ISO_BUF;
-		urb->transfer_buffer_length = ISO_FRAME_SIZE *
-					      FRAMES_PER_ISO_BUF;
-		urb->transfer_buffer = dec->iso_buffer + buffer_offset;
-		buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF;
-
-		for (j = 0; j < FRAMES_PER_ISO_BUF; j++) {
-			urb->iso_frame_desc[j].offset = frame_offset;
-			urb->iso_frame_desc[j].length = ISO_FRAME_SIZE;
-			frame_offset += ISO_FRAME_SIZE;
-		}
-	}
-}
-
-static void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec)
-{
-	int i;
-
-	dprintk("%s\n", __func__);
-
-	if (mutex_lock_interruptible(&dec->iso_mutex))
-		return;
-
-	dec->iso_stream_count--;
-
-	if (!dec->iso_stream_count) {
-		for (i = 0; i < ISO_BUF_COUNT; i++)
-			usb_kill_urb(dec->iso_urb[i]);
-	}
-
-	mutex_unlock(&dec->iso_mutex);
-}
-
-/* Setting the interface of the DEC tends to take down the USB communications
- * for a short period, so it's important not to call this function just before
- * trying to talk to it.
- */
-static int ttusb_dec_set_interface(struct ttusb_dec *dec,
-				   enum ttusb_dec_interface interface)
-{
-	int result = 0;
-	u8 b[] = { 0x05 };
-
-	if (interface != dec->interface) {
-		switch (interface) {
-		case TTUSB_DEC_INTERFACE_INITIAL:
-			result = usb_set_interface(dec->udev, 0, 0);
-			break;
-		case TTUSB_DEC_INTERFACE_IN:
-			result = ttusb_dec_send_command(dec, 0x80, sizeof(b),
-							b, NULL, NULL);
-			if (result)
-				return result;
-			result = usb_set_interface(dec->udev, 0, 8);
-			break;
-		case TTUSB_DEC_INTERFACE_OUT:
-			result = usb_set_interface(dec->udev, 0, 1);
-			break;
-		}
-
-		if (result)
-			return result;
-
-		dec->interface = interface;
-	}
-
-	return 0;
-}
-
-static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec)
-{
-	int i, result;
-
-	dprintk("%s\n", __func__);
-
-	if (mutex_lock_interruptible(&dec->iso_mutex))
-		return -EAGAIN;
-
-	if (!dec->iso_stream_count) {
-		ttusb_dec_setup_urbs(dec);
-
-		dec->packet_state = 0;
-		dec->v_pes_postbytes = 0;
-		dec->next_packet_id = 0;
-
-		for (i = 0; i < ISO_BUF_COUNT; i++) {
-			if ((result = usb_submit_urb(dec->iso_urb[i],
-						     GFP_ATOMIC))) {
-				printk("%s: failed urb submission %d: "
-				       "error %d\n", __func__, i, result);
-
-				while (i) {
-					usb_kill_urb(dec->iso_urb[i - 1]);
-					i--;
-				}
-
-				mutex_unlock(&dec->iso_mutex);
-				return result;
-			}
-		}
-	}
-
-	dec->iso_stream_count++;
-
-	mutex_unlock(&dec->iso_mutex);
-
-	return 0;
-}
-
-static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-	struct ttusb_dec *dec = dvbdmx->priv;
-	u8 b0[] = { 0x05 };
-	int result = 0;
-
-	dprintk("%s\n", __func__);
-
-	dprintk("  ts_type:");
-
-	if (dvbdmxfeed->ts_type & TS_DECODER)
-		dprintk(" TS_DECODER");
-
-	if (dvbdmxfeed->ts_type & TS_PACKET)
-		dprintk(" TS_PACKET");
-
-	if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)
-		dprintk(" TS_PAYLOAD_ONLY");
-
-	dprintk("\n");
-
-	switch (dvbdmxfeed->pes_type) {
-
-	case DMX_TS_PES_VIDEO:
-		dprintk("  pes_type: DMX_TS_PES_VIDEO\n");
-		dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid;
-		dec->pid[DMX_PES_VIDEO] = dvbdmxfeed->pid;
-		dec->video_filter = dvbdmxfeed->filter;
-		ttusb_dec_set_pids(dec);
-		break;
-
-	case DMX_TS_PES_AUDIO:
-		dprintk("  pes_type: DMX_TS_PES_AUDIO\n");
-		dec->pid[DMX_PES_AUDIO] = dvbdmxfeed->pid;
-		dec->audio_filter = dvbdmxfeed->filter;
-		ttusb_dec_set_pids(dec);
-		break;
-
-	case DMX_TS_PES_TELETEXT:
-		dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid;
-		dprintk("  pes_type: DMX_TS_PES_TELETEXT(not supported)\n");
-		return -ENOSYS;
-
-	case DMX_TS_PES_PCR:
-		dprintk("  pes_type: DMX_TS_PES_PCR\n");
-		dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid;
-		ttusb_dec_set_pids(dec);
-		break;
-
-	case DMX_TS_PES_OTHER:
-		dprintk("  pes_type: DMX_TS_PES_OTHER(not supported)\n");
-		return -ENOSYS;
-
-	default:
-		dprintk("  pes_type: unknown (%d)\n", dvbdmxfeed->pes_type);
-		return -EINVAL;
-
-	}
-
-	result = ttusb_dec_send_command(dec, 0x80, sizeof(b0), b0, NULL, NULL);
-	if (result)
-		return result;
-
-	dec->pva_stream_count++;
-	return ttusb_dec_start_iso_xfer(dec);
-}
-
-static int ttusb_dec_start_sec_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct ttusb_dec *dec = dvbdmxfeed->demux->priv;
-	u8 b0[] = { 0x00, 0x00, 0x00, 0x01,
-		    0x00, 0x00, 0x00, 0x00,
-		    0x00, 0x00, 0x00, 0x00,
-		    0x00, 0x00, 0x00, 0x00,
-		    0x00, 0xff, 0x00, 0x00,
-		    0x00, 0x00, 0x00, 0x00,
-		    0x00, 0x00, 0x00, 0x00,
-		    0x00 };
-	__be16 pid;
-	u8 c[COMMAND_PACKET_SIZE];
-	int c_length;
-	int result;
-	struct filter_info *finfo;
-	unsigned long flags;
-	u8 x = 1;
-
-	dprintk("%s\n", __func__);
-
-	pid = htons(dvbdmxfeed->pid);
-	memcpy(&b0[0], &pid, 2);
-	memcpy(&b0[4], &x, 1);
-	memcpy(&b0[5], &dvbdmxfeed->filter->filter.filter_value[0], 1);
-
-	result = ttusb_dec_send_command(dec, 0x60, sizeof(b0), b0,
-					&c_length, c);
-
-	if (!result) {
-		if (c_length == 2) {
-			if (!(finfo = kmalloc(sizeof(struct filter_info),
-					      GFP_ATOMIC)))
-				return -ENOMEM;
-
-			finfo->stream_id = c[1];
-			finfo->filter = dvbdmxfeed->filter;
-
-			spin_lock_irqsave(&dec->filter_info_list_lock, flags);
-			list_add_tail(&finfo->filter_info_list,
-				      &dec->filter_info_list);
-			spin_unlock_irqrestore(&dec->filter_info_list_lock,
-					       flags);
-
-			dvbdmxfeed->priv = finfo;
-
-			dec->filter_stream_count++;
-			return ttusb_dec_start_iso_xfer(dec);
-		}
-
-		return -EAGAIN;
-	} else
-		return result;
-}
-
-static int ttusb_dec_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-
-	dprintk("%s\n", __func__);
-
-	if (!dvbdmx->dmx.frontend)
-		return -EINVAL;
-
-	dprintk("  pid: 0x%04X\n", dvbdmxfeed->pid);
-
-	switch (dvbdmxfeed->type) {
-
-	case DMX_TYPE_TS:
-		return ttusb_dec_start_ts_feed(dvbdmxfeed);
-		break;
-
-	case DMX_TYPE_SEC:
-		return ttusb_dec_start_sec_feed(dvbdmxfeed);
-		break;
-
-	default:
-		dprintk("  type: unknown (%d)\n", dvbdmxfeed->type);
-		return -EINVAL;
-
-	}
-}
-
-static int ttusb_dec_stop_ts_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct ttusb_dec *dec = dvbdmxfeed->demux->priv;
-	u8 b0[] = { 0x00 };
-
-	ttusb_dec_send_command(dec, 0x81, sizeof(b0), b0, NULL, NULL);
-
-	dec->pva_stream_count--;
-
-	ttusb_dec_stop_iso_xfer(dec);
-
-	return 0;
-}
-
-static int ttusb_dec_stop_sec_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct ttusb_dec *dec = dvbdmxfeed->demux->priv;
-	u8 b0[] = { 0x00, 0x00 };
-	struct filter_info *finfo = (struct filter_info *)dvbdmxfeed->priv;
-	unsigned long flags;
-
-	b0[1] = finfo->stream_id;
-	spin_lock_irqsave(&dec->filter_info_list_lock, flags);
-	list_del(&finfo->filter_info_list);
-	spin_unlock_irqrestore(&dec->filter_info_list_lock, flags);
-	kfree(finfo);
-	ttusb_dec_send_command(dec, 0x62, sizeof(b0), b0, NULL, NULL);
-
-	dec->filter_stream_count--;
-
-	ttusb_dec_stop_iso_xfer(dec);
-
-	return 0;
-}
-
-static int ttusb_dec_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	dprintk("%s\n", __func__);
-
-	switch (dvbdmxfeed->type) {
-	case DMX_TYPE_TS:
-		return ttusb_dec_stop_ts_feed(dvbdmxfeed);
-		break;
-
-	case DMX_TYPE_SEC:
-		return ttusb_dec_stop_sec_feed(dvbdmxfeed);
-		break;
-	}
-
-	return 0;
-}
-
-static void ttusb_dec_free_iso_urbs(struct ttusb_dec *dec)
-{
-	int i;
-
-	dprintk("%s\n", __func__);
-
-	for (i = 0; i < ISO_BUF_COUNT; i++)
-		usb_free_urb(dec->iso_urb[i]);
-
-	pci_free_consistent(NULL,
-			    ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF *
-					      ISO_BUF_COUNT),
-			    dec->iso_buffer, dec->iso_dma_handle);
-}
-
-static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec)
-{
-	int i;
-
-	dprintk("%s\n", __func__);
-
-	dec->iso_buffer = pci_alloc_consistent(NULL,
-					       ISO_FRAME_SIZE *
-					       (FRAMES_PER_ISO_BUF *
-						ISO_BUF_COUNT),
-					       &dec->iso_dma_handle);
-
-	if (!dec->iso_buffer) {
-		dprintk("%s: pci_alloc_consistent - not enough memory\n",
-			__func__);
-		return -ENOMEM;
-	}
-
-	memset(dec->iso_buffer, 0,
-	       ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT));
-
-	for (i = 0; i < ISO_BUF_COUNT; i++) {
-		struct urb *urb;
-
-		if (!(urb = usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) {
-			ttusb_dec_free_iso_urbs(dec);
-			return -ENOMEM;
-		}
-
-		dec->iso_urb[i] = urb;
-	}
-
-	ttusb_dec_setup_urbs(dec);
-
-	return 0;
-}
-
-static void ttusb_dec_init_tasklet(struct ttusb_dec *dec)
-{
-	spin_lock_init(&dec->urb_frame_list_lock);
-	INIT_LIST_HEAD(&dec->urb_frame_list);
-	tasklet_init(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list,
-		     (unsigned long)dec);
-}
-
-static int ttusb_init_rc( struct ttusb_dec *dec)
-{
-	struct input_dev *input_dev;
-	u8 b[] = { 0x00, 0x01 };
-	int i;
-	int err;
-
-	usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys));
-	strlcat(dec->rc_phys, "/input0", sizeof(dec->rc_phys));
-
-	input_dev = input_allocate_device();
-	if (!input_dev)
-		return -ENOMEM;
-
-	input_dev->name = "ttusb_dec remote control";
-	input_dev->phys = dec->rc_phys;
-	input_dev->evbit[0] = BIT_MASK(EV_KEY);
-	input_dev->keycodesize = sizeof(u16);
-	input_dev->keycodemax = 0x1a;
-	input_dev->keycode = rc_keys;
-
-	for (i = 0; i < ARRAY_SIZE(rc_keys); i++)
-		  set_bit(rc_keys[i], input_dev->keybit);
-
-	err = input_register_device(input_dev);
-	if (err) {
-		input_free_device(input_dev);
-		return err;
-	}
-
-	dec->rc_input_dev = input_dev;
-	if (usb_submit_urb(dec->irq_urb, GFP_KERNEL))
-		printk("%s: usb_submit_urb failed\n",__func__);
-	/* enable irq pipe */
-	ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL);
-
-	return 0;
-}
-
-static void ttusb_dec_init_v_pes(struct ttusb_dec *dec)
-{
-	dprintk("%s\n", __func__);
-
-	dec->v_pes[0] = 0x00;
-	dec->v_pes[1] = 0x00;
-	dec->v_pes[2] = 0x01;
-	dec->v_pes[3] = 0xe0;
-}
-
-static int ttusb_dec_init_usb(struct ttusb_dec *dec)
-{
-	dprintk("%s\n", __func__);
-
-	mutex_init(&dec->usb_mutex);
-	mutex_init(&dec->iso_mutex);
-
-	dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE);
-	dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE);
-	dec->in_pipe = usb_rcvisocpipe(dec->udev, IN_PIPE);
-	dec->out_pipe = usb_sndisocpipe(dec->udev, OUT_PIPE);
-	dec->irq_pipe = usb_rcvintpipe(dec->udev, IRQ_PIPE);
-
-	if(enable_rc) {
-		dec->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
-		if(!dec->irq_urb) {
-			return -ENOMEM;
-		}
-		dec->irq_buffer = usb_alloc_coherent(dec->udev,IRQ_PACKET_SIZE,
-					GFP_ATOMIC, &dec->irq_dma_handle);
-		if(!dec->irq_buffer) {
-			usb_free_urb(dec->irq_urb);
-			return -ENOMEM;
-		}
-		usb_fill_int_urb(dec->irq_urb, dec->udev,dec->irq_pipe,
-				 dec->irq_buffer, IRQ_PACKET_SIZE,
-				 ttusb_dec_handle_irq, dec, 1);
-		dec->irq_urb->transfer_dma = dec->irq_dma_handle;
-		dec->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-	}
-
-	return ttusb_dec_alloc_iso_urbs(dec);
-}
-
-static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
-{
-	int i, j, actual_len, result, size, trans_count;
-	u8 b0[] = { 0x00, 0x00, 0x00, 0x00,
-		    0x00, 0x00, 0x00, 0x00,
-		    0x61, 0x00 };
-	u8 b1[] = { 0x61 };
-	u8 *b;
-	char idstring[21];
-	const u8 *firmware = NULL;
-	size_t firmware_size = 0;
-	u16 firmware_csum = 0;
-	__be16 firmware_csum_ns;
-	__be32 firmware_size_nl;
-	u32 crc32_csum, crc32_check;
-	__be32 tmp;
-	const struct firmware *fw_entry = NULL;
-
-	dprintk("%s\n", __func__);
-
-	if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) {
-		printk(KERN_ERR "%s: Firmware (%s) unavailable.\n",
-		       __func__, dec->firmware_name);
-		return 1;
-	}
-
-	firmware = fw_entry->data;
-	firmware_size = fw_entry->size;
-
-	if (firmware_size < 60) {
-		printk("%s: firmware size too small for DSP code (%zu < 60).\n",
-			__func__, firmware_size);
-		release_firmware(fw_entry);
-		return -1;
-	}
-
-	/* a 32 bit checksum over the first 56 bytes of the DSP Code is stored
-	   at offset 56 of file, so use it to check if the firmware file is
-	   valid. */
-	crc32_csum = crc32(~0L, firmware, 56) ^ ~0L;
-	memcpy(&tmp, &firmware[56], 4);
-	crc32_check = ntohl(tmp);
-	if (crc32_csum != crc32_check) {
-		printk("%s: crc32 check of DSP code failed (calculated "
-		       "0x%08x != 0x%08x in file), file invalid.\n",
-			__func__, crc32_csum, crc32_check);
-		release_firmware(fw_entry);
-		return -1;
-	}
-	memcpy(idstring, &firmware[36], 20);
-	idstring[20] = '\0';
-	printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring);
-
-	firmware_size_nl = htonl(firmware_size);
-	memcpy(b0, &firmware_size_nl, 4);
-	firmware_csum = crc16(~0, firmware, firmware_size) ^ ~0;
-	firmware_csum_ns = htons(firmware_csum);
-	memcpy(&b0[6], &firmware_csum_ns, 2);
-
-	result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL);
-
-	if (result) {
-		release_firmware(fw_entry);
-		return result;
-	}
-
-	trans_count = 0;
-	j = 0;
-
-	b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL);
-	if (b == NULL) {
-		release_firmware(fw_entry);
-		return -ENOMEM;
-	}
-
-	for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) {
-		size = firmware_size - i;
-		if (size > COMMAND_PACKET_SIZE)
-			size = COMMAND_PACKET_SIZE;
-
-		b[j + 0] = 0xaa;
-		b[j + 1] = trans_count++;
-		b[j + 2] = 0xf0;
-		b[j + 3] = size;
-		memcpy(&b[j + 4], &firmware[i], size);
-
-		j += COMMAND_PACKET_SIZE + 4;
-
-		if (j >= ARM_PACKET_SIZE) {
-			result = usb_bulk_msg(dec->udev, dec->command_pipe, b,
-					      ARM_PACKET_SIZE, &actual_len,
-					      100);
-			j = 0;
-		} else if (size < COMMAND_PACKET_SIZE) {
-			result = usb_bulk_msg(dec->udev, dec->command_pipe, b,
-					      j - COMMAND_PACKET_SIZE + size,
-					      &actual_len, 100);
-		}
-	}
-
-	result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL);
-
-	release_firmware(fw_entry);
-	kfree(b);
-
-	return result;
-}
-
-static int ttusb_dec_init_stb(struct ttusb_dec *dec)
-{
-	int result;
-	unsigned int mode = 0, model = 0, version = 0;
-
-	dprintk("%s\n", __func__);
-
-	result = ttusb_dec_get_stb_state(dec, &mode, &model, &version);
-
-	if (!result) {
-		if (!mode) {
-			if (version == 0xABCDEFAB)
-				printk(KERN_INFO "ttusb_dec: no version "
-				       "info in Firmware\n");
-			else
-				printk(KERN_INFO "ttusb_dec: Firmware "
-				       "%x.%02x%c%c\n",
-				       version >> 24, (version >> 16) & 0xff,
-				       (version >> 8) & 0xff, version & 0xff);
-
-			result = ttusb_dec_boot_dsp(dec);
-			if (result)
-				return result;
-			else
-				return 1;
-		} else {
-			/* We can't trust the USB IDs that some firmwares
-			   give the box */
-			switch (model) {
-			case 0x00070001:
-			case 0x00070008:
-			case 0x0007000c:
-				ttusb_dec_set_model(dec, TTUSB_DEC3000S);
-				break;
-			case 0x00070009:
-			case 0x00070013:
-				ttusb_dec_set_model(dec, TTUSB_DEC2000T);
-				break;
-			case 0x00070011:
-				ttusb_dec_set_model(dec, TTUSB_DEC2540T);
-				break;
-			default:
-				printk(KERN_ERR "%s: unknown model returned "
-				       "by firmware (%08x) - please report\n",
-				       __func__, model);
-				return -1;
-				break;
-			}
-
-			if (version >= 0x01770000)
-				dec->can_playback = 1;
-
-			return 0;
-		}
-	}
-	else
-		return result;
-}
-
-static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
-{
-	int result;
-
-	dprintk("%s\n", __func__);
-
-	if ((result = dvb_register_adapter(&dec->adapter,
-					   dec->model_name, THIS_MODULE,
-					   &dec->udev->dev,
-					   adapter_nr)) < 0) {
-		printk("%s: dvb_register_adapter failed: error %d\n",
-		       __func__, result);
-
-		return result;
-	}
-
-	dec->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
-
-	dec->demux.priv = (void *)dec;
-	dec->demux.filternum = 31;
-	dec->demux.feednum = 31;
-	dec->demux.start_feed = ttusb_dec_start_feed;
-	dec->demux.stop_feed = ttusb_dec_stop_feed;
-	dec->demux.write_to_decoder = NULL;
-
-	if ((result = dvb_dmx_init(&dec->demux)) < 0) {
-		printk("%s: dvb_dmx_init failed: error %d\n", __func__,
-		       result);
-
-		dvb_unregister_adapter(&dec->adapter);
-
-		return result;
-	}
-
-	dec->dmxdev.filternum = 32;
-	dec->dmxdev.demux = &dec->demux.dmx;
-	dec->dmxdev.capabilities = 0;
-
-	if ((result = dvb_dmxdev_init(&dec->dmxdev, &dec->adapter)) < 0) {
-		printk("%s: dvb_dmxdev_init failed: error %d\n",
-		       __func__, result);
-
-		dvb_dmx_release(&dec->demux);
-		dvb_unregister_adapter(&dec->adapter);
-
-		return result;
-	}
-
-	dec->frontend.source = DMX_FRONTEND_0;
-
-	if ((result = dec->demux.dmx.add_frontend(&dec->demux.dmx,
-						  &dec->frontend)) < 0) {
-		printk("%s: dvb_dmx_init failed: error %d\n", __func__,
-		       result);
-
-		dvb_dmxdev_release(&dec->dmxdev);
-		dvb_dmx_release(&dec->demux);
-		dvb_unregister_adapter(&dec->adapter);
-
-		return result;
-	}
-
-	if ((result = dec->demux.dmx.connect_frontend(&dec->demux.dmx,
-						      &dec->frontend)) < 0) {
-		printk("%s: dvb_dmx_init failed: error %d\n", __func__,
-		       result);
-
-		dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
-		dvb_dmxdev_release(&dec->dmxdev);
-		dvb_dmx_release(&dec->demux);
-		dvb_unregister_adapter(&dec->adapter);
-
-		return result;
-	}
-
-	dvb_net_init(&dec->adapter, &dec->dvb_net, &dec->demux.dmx);
-
-	return 0;
-}
-
-static void ttusb_dec_exit_dvb(struct ttusb_dec *dec)
-{
-	dprintk("%s\n", __func__);
-
-	dvb_net_release(&dec->dvb_net);
-	dec->demux.dmx.close(&dec->demux.dmx);
-	dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
-	dvb_dmxdev_release(&dec->dmxdev);
-	dvb_dmx_release(&dec->demux);
-	if (dec->fe) {
-		dvb_unregister_frontend(dec->fe);
-		if (dec->fe->ops.release)
-			dec->fe->ops.release(dec->fe);
-	}
-	dvb_unregister_adapter(&dec->adapter);
-}
-
-static void ttusb_dec_exit_rc(struct ttusb_dec *dec)
-{
-
-	dprintk("%s\n", __func__);
-	/* we have to check whether the irq URB is already submitted.
-	  * As the irq is submitted after the interface is changed,
-	  * this is the best method i figured out.
-	  * Any others?*/
-	if (dec->interface == TTUSB_DEC_INTERFACE_IN)
-		usb_kill_urb(dec->irq_urb);
-
-	usb_free_urb(dec->irq_urb);
-
-	usb_free_coherent(dec->udev,IRQ_PACKET_SIZE,
-			  dec->irq_buffer, dec->irq_dma_handle);
-
-	if (dec->rc_input_dev) {
-		input_unregister_device(dec->rc_input_dev);
-		dec->rc_input_dev = NULL;
-	}
-}
-
-
-static void ttusb_dec_exit_usb(struct ttusb_dec *dec)
-{
-	int i;
-
-	dprintk("%s\n", __func__);
-
-	dec->iso_stream_count = 0;
-
-	for (i = 0; i < ISO_BUF_COUNT; i++)
-		usb_kill_urb(dec->iso_urb[i]);
-
-	ttusb_dec_free_iso_urbs(dec);
-}
-
-static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec)
-{
-	struct list_head *item;
-	struct urb_frame *frame;
-
-	tasklet_kill(&dec->urb_tasklet);
-
-	while ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) {
-		frame = list_entry(item, struct urb_frame, urb_frame_list);
-		list_del(&frame->urb_frame_list);
-		kfree(frame);
-	}
-}
-
-static void ttusb_dec_init_filters(struct ttusb_dec *dec)
-{
-	INIT_LIST_HEAD(&dec->filter_info_list);
-	spin_lock_init(&dec->filter_info_list_lock);
-}
-
-static void ttusb_dec_exit_filters(struct ttusb_dec *dec)
-{
-	struct list_head *item;
-	struct filter_info *finfo;
-
-	while ((item = dec->filter_info_list.next) != &dec->filter_info_list) {
-		finfo = list_entry(item, struct filter_info, filter_info_list);
-		list_del(&finfo->filter_info_list);
-		kfree(finfo);
-	}
-}
-
-static int fe_send_command(struct dvb_frontend* fe, const u8 command,
-			   int param_length, const u8 params[],
-			   int *result_length, u8 cmd_result[])
-{
-	struct ttusb_dec* dec = fe->dvb->priv;
-	return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result);
-}
-
-static struct ttusbdecfe_config fe_config = {
-	.send_command = fe_send_command
-};
-
-static int ttusb_dec_probe(struct usb_interface *intf,
-			   const struct usb_device_id *id)
-{
-	struct usb_device *udev;
-	struct ttusb_dec *dec;
-
-	dprintk("%s\n", __func__);
-
-	udev = interface_to_usbdev(intf);
-
-	if (!(dec = kzalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) {
-		printk("%s: couldn't allocate memory.\n", __func__);
-		return -ENOMEM;
-	}
-
-	usb_set_intfdata(intf, (void *)dec);
-
-	switch (id->idProduct) {
-	case 0x1006:
-		ttusb_dec_set_model(dec, TTUSB_DEC3000S);
-		break;
-
-	case 0x1008:
-		ttusb_dec_set_model(dec, TTUSB_DEC2000T);
-		break;
-
-	case 0x1009:
-		ttusb_dec_set_model(dec, TTUSB_DEC2540T);
-		break;
-	}
-
-	dec->udev = udev;
-
-	if (ttusb_dec_init_usb(dec))
-		return 0;
-	if (ttusb_dec_init_stb(dec)) {
-		ttusb_dec_exit_usb(dec);
-		return 0;
-	}
-	ttusb_dec_init_dvb(dec);
-
-	dec->adapter.priv = dec;
-	switch (id->idProduct) {
-	case 0x1006:
-		dec->fe = ttusbdecfe_dvbs_attach(&fe_config);
-		break;
-
-	case 0x1008:
-	case 0x1009:
-		dec->fe = ttusbdecfe_dvbt_attach(&fe_config);
-		break;
-	}
-
-	if (dec->fe == NULL) {
-		printk("dvb-ttusb-dec: A frontend driver was not found for device [%04x:%04x]\n",
-		       le16_to_cpu(dec->udev->descriptor.idVendor),
-		       le16_to_cpu(dec->udev->descriptor.idProduct));
-	} else {
-		if (dvb_register_frontend(&dec->adapter, dec->fe)) {
-			printk("budget-ci: Frontend registration failed!\n");
-			if (dec->fe->ops.release)
-				dec->fe->ops.release(dec->fe);
-			dec->fe = NULL;
-		}
-	}
-
-	ttusb_dec_init_v_pes(dec);
-	ttusb_dec_init_filters(dec);
-	ttusb_dec_init_tasklet(dec);
-
-	dec->active = 1;
-
-	ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN);
-
-	if (enable_rc)
-		ttusb_init_rc(dec);
-
-	return 0;
-}
-
-static void ttusb_dec_disconnect(struct usb_interface *intf)
-{
-	struct ttusb_dec *dec = usb_get_intfdata(intf);
-
-	usb_set_intfdata(intf, NULL);
-
-	dprintk("%s\n", __func__);
-
-	if (dec->active) {
-		ttusb_dec_exit_tasklet(dec);
-		ttusb_dec_exit_filters(dec);
-		if(enable_rc)
-			ttusb_dec_exit_rc(dec);
-		ttusb_dec_exit_usb(dec);
-		ttusb_dec_exit_dvb(dec);
-	}
-
-	kfree(dec);
-}
-
-static void ttusb_dec_set_model(struct ttusb_dec *dec,
-				enum ttusb_dec_model model)
-{
-	dec->model = model;
-
-	switch (model) {
-	case TTUSB_DEC2000T:
-		dec->model_name = "DEC2000-t";
-		dec->firmware_name = "dvb-ttusb-dec-2000t.fw";
-		break;
-
-	case TTUSB_DEC2540T:
-		dec->model_name = "DEC2540-t";
-		dec->firmware_name = "dvb-ttusb-dec-2540t.fw";
-		break;
-
-	case TTUSB_DEC3000S:
-		dec->model_name = "DEC3000-s";
-		dec->firmware_name = "dvb-ttusb-dec-3000s.fw";
-		break;
-	}
-}
-
-static struct usb_device_id ttusb_dec_table[] = {
-	{USB_DEVICE(0x0b48, 0x1006)},	/* DEC3000-s */
-	/*{USB_DEVICE(0x0b48, 0x1007)},	   Unconfirmed */
-	{USB_DEVICE(0x0b48, 0x1008)},	/* DEC2000-t */
-	{USB_DEVICE(0x0b48, 0x1009)},	/* DEC2540-t */
-	{}
-};
-
-static struct usb_driver ttusb_dec_driver = {
-	.name		= "ttusb-dec",
-	.probe		= ttusb_dec_probe,
-	.disconnect	= ttusb_dec_disconnect,
-	.id_table	= ttusb_dec_table,
-};
-
-module_usb_driver(ttusb_dec_driver);
-
-MODULE_AUTHOR("Alex Woods <linux-dvb@giblets.org>");
-MODULE_DESCRIPTION(DRIVER_NAME);
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(usb, ttusb_dec_table);
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
deleted file mode 100644
index 5c45c9d..0000000
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * TTUSB DEC Frontend Driver
- *
- * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include "dvb_frontend.h"
-#include "ttusbdecfe.h"
-
-
-#define LOF_HI			10600000
-#define LOF_LO			9750000
-
-struct ttusbdecfe_state {
-
-	/* configuration settings */
-	const struct ttusbdecfe_config* config;
-
-	struct dvb_frontend frontend;
-
-	u8 hi_band;
-	u8 voltage;
-};
-
-
-static int ttusbdecfe_dvbs_read_status(struct dvb_frontend *fe,
-	fe_status_t *status)
-{
-	*status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
-		FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
-	return 0;
-}
-
-
-static int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe,
-	fe_status_t *status)
-{
-	struct ttusbdecfe_state* state = fe->demodulator_priv;
-	u8 b[] = { 0x00, 0x00, 0x00, 0x00,
-		   0x00, 0x00, 0x00, 0x00 };
-	u8 result[4];
-	int len, ret;
-
-	*status=0;
-
-	ret=state->config->send_command(fe, 0x73, sizeof(b), b, &len, result);
-	if(ret)
-		return ret;
-
-	if(len != 4) {
-		printk(KERN_ERR "%s: unexpected reply\n", __func__);
-		return -EIO;
-	}
-
-	switch(result[3]) {
-		case 1:  /* not tuned yet */
-		case 2:  /* no signal/no lock*/
-			break;
-		case 3:	 /* signal found and locked*/
-			*status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
-			FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
-			break;
-		case 4:
-			*status = FE_TIMEDOUT;
-			break;
-		default:
-			pr_info("%s: returned unknown value: %d\n",
-				__func__, result[3]);
-			return -EIO;
-	}
-
-	return 0;
-}
-
-static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
-	u8 b[] = { 0x00, 0x00, 0x00, 0x03,
-		   0x00, 0x00, 0x00, 0x00,
-		   0x00, 0x00, 0x00, 0x01,
-		   0x00, 0x00, 0x00, 0xff,
-		   0x00, 0x00, 0x00, 0xff };
-
-	__be32 freq = htonl(p->frequency / 1000);
-	memcpy(&b[4], &freq, sizeof (u32));
-	state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL);
-
-	return 0;
-}
-
-static int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe,
-					struct dvb_frontend_tune_settings* fesettings)
-{
-		fesettings->min_delay_ms = 1500;
-		/* Drift compensation makes no sense for DVB-T */
-		fesettings->step_size = 0;
-		fesettings->max_drift = 0;
-		return 0;
-}
-
-static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend *fe)
-{
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
-
-	u8 b[] = { 0x00, 0x00, 0x00, 0x01,
-		   0x00, 0x00, 0x00, 0x00,
-		   0x00, 0x00, 0x00, 0x01,
-		   0x00, 0x00, 0x00, 0x00,
-		   0x00, 0x00, 0x00, 0x00,
-		   0x00, 0x00, 0x00, 0x00,
-		   0x00, 0x00, 0x00, 0x00,
-		   0x00, 0x00, 0x00, 0x00,
-		   0x00, 0x00, 0x00, 0x00,
-		   0x00, 0x00, 0x00, 0x00 };
-	__be32 freq;
-	__be32 sym_rate;
-	__be32 band;
-	__be32 lnb_voltage;
-
-	freq = htonl(p->frequency +
-	       (state->hi_band ? LOF_HI : LOF_LO));
-	memcpy(&b[4], &freq, sizeof(u32));
-	sym_rate = htonl(p->symbol_rate);
-	memcpy(&b[12], &sym_rate, sizeof(u32));
-	band = htonl(state->hi_band ? LOF_HI : LOF_LO);
-	memcpy(&b[24], &band, sizeof(u32));
-	lnb_voltage = htonl(state->voltage);
-	memcpy(&b[28], &lnb_voltage, sizeof(u32));
-
-	state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL);
-
-	return 0;
-}
-
-static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
-{
-	struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
-	u8 b[] = { 0x00, 0xff, 0x00, 0x00,
-		   0x00, 0x00, 0x00, 0x00,
-		   0x00, 0x00 };
-
-	memcpy(&b[4], cmd->msg, cmd->msg_len);
-
-	state->config->send_command(fe, 0x72,
-				    sizeof(b) - (6 - cmd->msg_len), b,
-				    NULL, NULL);
-
-	return 0;
-}
-
-
-static int ttusbdecfe_dvbs_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
-	struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
-
-	state->hi_band = (SEC_TONE_ON == tone);
-
-	return 0;
-}
-
-
-static int ttusbdecfe_dvbs_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
-	struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
-
-	switch (voltage) {
-	case SEC_VOLTAGE_13:
-		state->voltage = 13;
-		break;
-	case SEC_VOLTAGE_18:
-		state->voltage = 18;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static void ttusbdecfe_release(struct dvb_frontend* fe)
-{
-	struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
-	kfree(state);
-}
-
-static struct dvb_frontend_ops ttusbdecfe_dvbt_ops;
-
-struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config)
-{
-	struct ttusbdecfe_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
-	if (state == NULL)
-		return NULL;
-
-	/* setup the state */
-	state->config = config;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-}
-
-static struct dvb_frontend_ops ttusbdecfe_dvbs_ops;
-
-struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config)
-{
-	struct ttusbdecfe_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
-	if (state == NULL)
-		return NULL;
-
-	/* setup the state */
-	state->config = config;
-	state->voltage = 0;
-	state->hi_band = 0;
-
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
-}
-
-static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name			= "TechnoTrend/Hauppauge DEC2000-t Frontend",
-		.frequency_min		= 51000000,
-		.frequency_max		= 858000000,
-		.frequency_stepsize	= 62500,
-		.caps =	FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_HIERARCHY_AUTO,
-	},
-
-	.release = ttusbdecfe_release,
-
-	.set_frontend = ttusbdecfe_dvbt_set_frontend,
-
-	.get_tune_settings = ttusbdecfe_dvbt_get_tune_settings,
-
-	.read_status = ttusbdecfe_dvbt_read_status,
-};
-
-static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = {
-	.delsys = { SYS_DVBS },
-	.info = {
-		.name			= "TechnoTrend/Hauppauge DEC3000-s Frontend",
-		.frequency_min		= 950000,
-		.frequency_max		= 2150000,
-		.frequency_stepsize	= 125,
-		.symbol_rate_min        = 1000000,  /* guessed */
-		.symbol_rate_max        = 45000000, /* guessed */
-		.caps =	FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_QPSK
-	},
-
-	.release = ttusbdecfe_release,
-
-	.set_frontend = ttusbdecfe_dvbs_set_frontend,
-
-	.read_status = ttusbdecfe_dvbs_read_status,
-
-	.diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd,
-	.set_voltage = ttusbdecfe_dvbs_set_voltage,
-	.set_tone = ttusbdecfe_dvbs_set_tone,
-};
-
-MODULE_DESCRIPTION("TTUSB DEC DVB-T/S Demodulator driver");
-MODULE_AUTHOR("Alex Woods/Andrew de Quincey");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(ttusbdecfe_dvbt_attach);
-EXPORT_SYMBOL(ttusbdecfe_dvbs_attach);
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.h b/drivers/media/dvb/ttusb-dec/ttusbdecfe.h
deleted file mode 100644
index 15ccc3d..0000000
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * TTUSB DEC Driver
- *
- * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef TTUSBDECFE_H
-#define TTUSBDECFE_H
-
-#include <linux/dvb/frontend.h>
-
-struct ttusbdecfe_config
-{
-	int (*send_command)(struct dvb_frontend* fe, const u8 command,
-			    int param_length, const u8 params[],
-			    int *result_length, u8 cmd_result[]);
-};
-
-extern struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config);
-
-extern struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config);
-
-#endif // TTUSBDECFE_H
diff --git a/drivers/media/firewire/Kconfig b/drivers/media/firewire/Kconfig
new file mode 100644
index 0000000..f3e9448
--- /dev/null
+++ b/drivers/media/firewire/Kconfig
@@ -0,0 +1,19 @@
+config DVB_FIREDTV
+	tristate "FireDTV and FloppyDTV"
+	depends on DVB_CORE && FIREWIRE
+	help
+	  Support for DVB receivers from Digital Everywhere
+	  which are connected via IEEE 1394 (FireWire).
+
+	  These devices don't have an MPEG decoder built in,
+	  so you need an external software decoder to watch TV.
+
+	  To compile this driver as a module, say M here:
+	  the module will be called firedtv.
+
+if DVB_FIREDTV
+
+config DVB_FIREDTV_INPUT
+	def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m)
+
+endif # DVB_FIREDTV
diff --git a/drivers/media/firewire/Makefile b/drivers/media/firewire/Makefile
new file mode 100644
index 0000000..2394813
--- /dev/null
+++ b/drivers/media/firewire/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_DVB_FIREDTV) += firedtv.o
+
+firedtv-y += firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o firedtv-fw.o
+firedtv-$(CONFIG_DVB_FIREDTV_INPUT)    += firedtv-rc.o
+
+ccflags-y += -Idrivers/media/dvb-core
diff --git a/drivers/media/firewire/firedtv-avc.c b/drivers/media/firewire/firedtv-avc.c
new file mode 100644
index 0000000..d1a1a13
--- /dev/null
+++ b/drivers/media/firewire/firedtv-avc.c
@@ -0,0 +1,1457 @@
+/*
+ * FireDTV driver (formerly known as FireSAT)
+ *
+ * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
+ * Copyright (C) 2008 Ben Backx <ben@bbackx.com>
+ * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
+ *
+ *	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.
+ */
+
+#include <linux/bug.h>
+#include <linux/crc32.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/stringify.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+#include <dvb_frontend.h>
+
+#include "firedtv.h"
+
+#define FCP_COMMAND_REGISTER		0xfffff0000b00ULL
+
+#define AVC_CTYPE_CONTROL		0x0
+#define AVC_CTYPE_STATUS		0x1
+#define AVC_CTYPE_NOTIFY		0x3
+
+#define AVC_RESPONSE_ACCEPTED		0x9
+#define AVC_RESPONSE_STABLE		0xc
+#define AVC_RESPONSE_CHANGED		0xd
+#define AVC_RESPONSE_INTERIM		0xf
+
+#define AVC_SUBUNIT_TYPE_TUNER		(0x05 << 3)
+#define AVC_SUBUNIT_TYPE_UNIT		(0x1f << 3)
+
+#define AVC_OPCODE_VENDOR		0x00
+#define AVC_OPCODE_READ_DESCRIPTOR	0x09
+#define AVC_OPCODE_DSIT			0xc8
+#define AVC_OPCODE_DSD			0xcb
+
+#define DESCRIPTOR_TUNER_STATUS 	0x80
+#define DESCRIPTOR_SUBUNIT_IDENTIFIER	0x00
+
+#define SFE_VENDOR_DE_COMPANYID_0	0x00 /* OUI of Digital Everywhere */
+#define SFE_VENDOR_DE_COMPANYID_1	0x12
+#define SFE_VENDOR_DE_COMPANYID_2	0x87
+
+#define SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL 0x0a
+#define SFE_VENDOR_OPCODE_LNB_CONTROL		0x52
+#define SFE_VENDOR_OPCODE_TUNE_QPSK		0x58 /* for DVB-S */
+
+#define SFE_VENDOR_OPCODE_GET_FIRMWARE_VERSION	0x00
+#define SFE_VENDOR_OPCODE_HOST2CA		0x56
+#define SFE_VENDOR_OPCODE_CA2HOST		0x57
+#define SFE_VENDOR_OPCODE_CISTATUS		0x59
+#define SFE_VENDOR_OPCODE_TUNE_QPSK2		0x60 /* for DVB-S2 */
+
+#define SFE_VENDOR_TAG_CA_RESET			0x00
+#define SFE_VENDOR_TAG_CA_APPLICATION_INFO	0x01
+#define SFE_VENDOR_TAG_CA_PMT			0x02
+#define SFE_VENDOR_TAG_CA_DATE_TIME		0x04
+#define SFE_VENDOR_TAG_CA_MMI			0x05
+#define SFE_VENDOR_TAG_CA_ENTER_MENU		0x07
+
+#define EN50221_LIST_MANAGEMENT_ONLY	0x03
+#define EN50221_TAG_APP_INFO		0x9f8021
+#define EN50221_TAG_CA_INFO		0x9f8031
+
+struct avc_command_frame {
+	u8 ctype;
+	u8 subunit;
+	u8 opcode;
+	u8 operand[509];
+};
+
+struct avc_response_frame {
+	u8 response;
+	u8 subunit;
+	u8 opcode;
+	u8 operand[509];
+};
+
+#define LAST_OPERAND (509 - 1)
+
+static inline void clear_operands(struct avc_command_frame *c, int from, int to)
+{
+	memset(&c->operand[from], 0, to - from + 1);
+}
+
+static void pad_operands(struct avc_command_frame *c, int from)
+{
+	int to = ALIGN(from, 4);
+
+	if (from <= to && to <= LAST_OPERAND)
+		clear_operands(c, from, to);
+}
+
+#define AVC_DEBUG_READ_DESCRIPTOR              0x0001
+#define AVC_DEBUG_DSIT                         0x0002
+#define AVC_DEBUG_DSD                          0x0004
+#define AVC_DEBUG_REGISTER_REMOTE_CONTROL      0x0008
+#define AVC_DEBUG_LNB_CONTROL                  0x0010
+#define AVC_DEBUG_TUNE_QPSK                    0x0020
+#define AVC_DEBUG_TUNE_QPSK2                   0x0040
+#define AVC_DEBUG_HOST2CA                      0x0080
+#define AVC_DEBUG_CA2HOST                      0x0100
+#define AVC_DEBUG_APPLICATION_PMT              0x4000
+#define AVC_DEBUG_FCP_PAYLOADS                 0x8000
+
+static int avc_debug;
+module_param_named(debug, avc_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Verbose logging (none = 0"
+	", FCP subactions"
+	": READ DESCRIPTOR = "		__stringify(AVC_DEBUG_READ_DESCRIPTOR)
+	", DSIT = "			__stringify(AVC_DEBUG_DSIT)
+	", REGISTER_REMOTE_CONTROL = "	__stringify(AVC_DEBUG_REGISTER_REMOTE_CONTROL)
+	", LNB CONTROL = "		__stringify(AVC_DEBUG_LNB_CONTROL)
+	", TUNE QPSK = "		__stringify(AVC_DEBUG_TUNE_QPSK)
+	", TUNE QPSK2 = "		__stringify(AVC_DEBUG_TUNE_QPSK2)
+	", HOST2CA = "			__stringify(AVC_DEBUG_HOST2CA)
+	", CA2HOST = "			__stringify(AVC_DEBUG_CA2HOST)
+	"; Application sent PMT = "	__stringify(AVC_DEBUG_APPLICATION_PMT)
+	", FCP payloads = "		__stringify(AVC_DEBUG_FCP_PAYLOADS)
+	", or a combination, or all = -1)");
+
+/*
+ * This is a workaround since there is no vendor specific command to retrieve
+ * ca_info using AVC. If this parameter is not used, ca_system_id will be
+ * filled with application_manufacturer from ca_app_info.
+ * Digital Everywhere have said that adding ca_info is on their TODO list.
+ */
+static unsigned int num_fake_ca_system_ids;
+static int fake_ca_system_ids[4] = { -1, -1, -1, -1 };
+module_param_array(fake_ca_system_ids, int, &num_fake_ca_system_ids, 0644);
+MODULE_PARM_DESC(fake_ca_system_ids, "If your CAM application manufacturer "
+		 "does not have the same ca_system_id as your CAS, you can "
+		 "override what ca_system_ids are presented to the "
+		 "application by setting this field to an array of ids.");
+
+static const char *debug_fcp_ctype(unsigned int ctype)
+{
+	static const char *ctypes[] = {
+		[0x0] = "CONTROL",		[0x1] = "STATUS",
+		[0x2] = "SPECIFIC INQUIRY",	[0x3] = "NOTIFY",
+		[0x4] = "GENERAL INQUIRY",	[0x8] = "NOT IMPLEMENTED",
+		[0x9] = "ACCEPTED",		[0xa] = "REJECTED",
+		[0xb] = "IN TRANSITION",	[0xc] = "IMPLEMENTED/STABLE",
+		[0xd] = "CHANGED",		[0xf] = "INTERIM",
+	};
+	const char *ret = ctype < ARRAY_SIZE(ctypes) ? ctypes[ctype] : NULL;
+
+	return ret ? ret : "?";
+}
+
+static const char *debug_fcp_opcode(unsigned int opcode,
+				    const u8 *data, int length)
+{
+	switch (opcode) {
+	case AVC_OPCODE_VENDOR:
+		break;
+	case AVC_OPCODE_READ_DESCRIPTOR:
+		return avc_debug & AVC_DEBUG_READ_DESCRIPTOR ?
+				"ReadDescriptor" : NULL;
+	case AVC_OPCODE_DSIT:
+		return avc_debug & AVC_DEBUG_DSIT ?
+				"DirectSelectInfo.Type" : NULL;
+	case AVC_OPCODE_DSD:
+		return avc_debug & AVC_DEBUG_DSD ? "DirectSelectData" : NULL;
+	default:
+		return "Unknown";
+	}
+
+	if (length < 7 ||
+	    data[3] != SFE_VENDOR_DE_COMPANYID_0 ||
+	    data[4] != SFE_VENDOR_DE_COMPANYID_1 ||
+	    data[5] != SFE_VENDOR_DE_COMPANYID_2)
+		return "Vendor/Unknown";
+
+	switch (data[6]) {
+	case SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL:
+		return avc_debug & AVC_DEBUG_REGISTER_REMOTE_CONTROL ?
+				"RegisterRC" : NULL;
+	case SFE_VENDOR_OPCODE_LNB_CONTROL:
+		return avc_debug & AVC_DEBUG_LNB_CONTROL ? "LNBControl" : NULL;
+	case SFE_VENDOR_OPCODE_TUNE_QPSK:
+		return avc_debug & AVC_DEBUG_TUNE_QPSK ? "TuneQPSK" : NULL;
+	case SFE_VENDOR_OPCODE_TUNE_QPSK2:
+		return avc_debug & AVC_DEBUG_TUNE_QPSK2 ? "TuneQPSK2" : NULL;
+	case SFE_VENDOR_OPCODE_HOST2CA:
+		return avc_debug & AVC_DEBUG_HOST2CA ? "Host2CA" : NULL;
+	case SFE_VENDOR_OPCODE_CA2HOST:
+		return avc_debug & AVC_DEBUG_CA2HOST ? "CA2Host" : NULL;
+	}
+	return "Vendor/Unknown";
+}
+
+static void debug_fcp(const u8 *data, int length)
+{
+	unsigned int subunit_type, subunit_id, opcode;
+	const char *op, *prefix;
+
+	prefix       = data[0] > 7 ? "FCP <- " : "FCP -> ";
+	subunit_type = data[1] >> 3;
+	subunit_id   = data[1] & 7;
+	opcode       = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2];
+	op           = debug_fcp_opcode(opcode, data, length);
+
+	if (op) {
+		printk(KERN_INFO "%ssu=%x.%x l=%d: %-8s - %s\n",
+		       prefix, subunit_type, subunit_id, length,
+		       debug_fcp_ctype(data[0]), op);
+		if (avc_debug & AVC_DEBUG_FCP_PAYLOADS)
+			print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_NONE,
+				       16, 1, data, length, false);
+	}
+}
+
+static void debug_pmt(char *msg, int length)
+{
+	printk(KERN_INFO "APP PMT -> l=%d\n", length);
+	print_hex_dump(KERN_INFO, "APP PMT -> ", DUMP_PREFIX_NONE,
+		       16, 1, msg, length, false);
+}
+
+static int avc_write(struct firedtv *fdtv)
+{
+	int err, retry;
+
+	fdtv->avc_reply_received = false;
+
+	for (retry = 0; retry < 6; retry++) {
+		if (unlikely(avc_debug))
+			debug_fcp(fdtv->avc_data, fdtv->avc_data_length);
+
+		err = fdtv_write(fdtv, FCP_COMMAND_REGISTER,
+				 fdtv->avc_data, fdtv->avc_data_length);
+		if (err) {
+			dev_err(fdtv->device, "FCP command write failed\n");
+
+			return err;
+		}
+
+		/*
+		 * AV/C specs say that answers should be sent within 150 ms.
+		 * Time out after 200 ms.
+		 */
+		if (wait_event_timeout(fdtv->avc_wait,
+				       fdtv->avc_reply_received,
+				       msecs_to_jiffies(200)) != 0)
+			return 0;
+	}
+	dev_err(fdtv->device, "FCP response timed out\n");
+
+	return -ETIMEDOUT;
+}
+
+static bool is_register_rc(struct avc_response_frame *r)
+{
+	return r->opcode     == AVC_OPCODE_VENDOR &&
+	       r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
+	       r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
+	       r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 &&
+	       r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
+}
+
+int avc_recv(struct firedtv *fdtv, void *data, size_t length)
+{
+	struct avc_response_frame *r = data;
+
+	if (unlikely(avc_debug))
+		debug_fcp(data, length);
+
+	if (length >= 8 && is_register_rc(r)) {
+		switch (r->response) {
+		case AVC_RESPONSE_CHANGED:
+			fdtv_handle_rc(fdtv, r->operand[4] << 8 | r->operand[5]);
+			schedule_work(&fdtv->remote_ctrl_work);
+			break;
+		case AVC_RESPONSE_INTERIM:
+			if (is_register_rc((void *)fdtv->avc_data))
+				goto wake;
+			break;
+		default:
+			dev_info(fdtv->device,
+				 "remote control result = %d\n", r->response);
+		}
+		return 0;
+	}
+
+	if (fdtv->avc_reply_received) {
+		dev_err(fdtv->device, "out-of-order AVC response, ignored\n");
+		return -EIO;
+	}
+
+	memcpy(fdtv->avc_data, data, length);
+	fdtv->avc_data_length = length;
+wake:
+	fdtv->avc_reply_received = true;
+	wake_up(&fdtv->avc_wait);
+
+	return 0;
+}
+
+static int add_pid_filter(struct firedtv *fdtv, u8 *operand)
+{
+	int i, n, pos = 1;
+
+	for (i = 0, n = 0; i < 16; i++) {
+		if (test_bit(i, &fdtv->channel_active)) {
+			operand[pos++] = 0x13; /* flowfunction relay */
+			operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */
+			operand[pos++] = (fdtv->channel_pid[i] >> 8) & 0x1f;
+			operand[pos++] = fdtv->channel_pid[i] & 0xff;
+			operand[pos++] = 0x00; /* tableID */
+			operand[pos++] = 0x00; /* filter_length */
+			n++;
+		}
+	}
+	operand[0] = n;
+
+	return pos;
+}
+
+/*
+ * tuning command for setting the relative LNB frequency
+ * (not supported by the AVC standard)
+ */
+static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
+			      struct dtv_frontend_properties *p)
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+
+	c->opcode = AVC_OPCODE_VENDOR;
+
+	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+	if (fdtv->type == FIREDTV_DVB_S2)
+		c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK2;
+	else
+		c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK;
+
+	c->operand[4] = (p->frequency >> 24) & 0xff;
+	c->operand[5] = (p->frequency >> 16) & 0xff;
+	c->operand[6] = (p->frequency >> 8) & 0xff;
+	c->operand[7] = p->frequency & 0xff;
+
+	c->operand[8] = ((p->symbol_rate / 1000) >> 8) & 0xff;
+	c->operand[9] = (p->symbol_rate / 1000) & 0xff;
+
+	switch (p->fec_inner) {
+	case FEC_1_2:	c->operand[10] = 0x1; break;
+	case FEC_2_3:	c->operand[10] = 0x2; break;
+	case FEC_3_4:	c->operand[10] = 0x3; break;
+	case FEC_5_6:	c->operand[10] = 0x4; break;
+	case FEC_7_8:	c->operand[10] = 0x5; break;
+	case FEC_4_5:
+	case FEC_8_9:
+	case FEC_AUTO:
+	default:	c->operand[10] = 0x0;
+	}
+
+	if (fdtv->voltage == 0xff)
+		c->operand[11] = 0xff;
+	else if (fdtv->voltage == SEC_VOLTAGE_18) /* polarisation */
+		c->operand[11] = 0;
+	else
+		c->operand[11] = 1;
+
+	if (fdtv->tone == 0xff)
+		c->operand[12] = 0xff;
+	else if (fdtv->tone == SEC_TONE_ON) /* band */
+		c->operand[12] = 1;
+	else
+		c->operand[12] = 0;
+
+	if (fdtv->type == FIREDTV_DVB_S2) {
+		if (fdtv->fe.dtv_property_cache.delivery_system == SYS_DVBS2) {
+			switch (fdtv->fe.dtv_property_cache.modulation) {
+			case QAM_16:		c->operand[13] = 0x1; break;
+			case QPSK:		c->operand[13] = 0x2; break;
+			case PSK_8:		c->operand[13] = 0x3; break;
+			default:		c->operand[13] = 0x2; break;
+			}
+			switch (fdtv->fe.dtv_property_cache.rolloff) {
+			case ROLLOFF_35:	c->operand[14] = 0x2; break;
+			case ROLLOFF_20:	c->operand[14] = 0x0; break;
+			case ROLLOFF_25:	c->operand[14] = 0x1; break;
+			case ROLLOFF_AUTO:
+			default:		c->operand[14] = 0x2; break;
+			/* case ROLLOFF_NONE:	c->operand[14] = 0xff; break; */
+			}
+			switch (fdtv->fe.dtv_property_cache.pilot) {
+			case PILOT_AUTO:	c->operand[15] = 0x0; break;
+			case PILOT_OFF:		c->operand[15] = 0x0; break;
+			case PILOT_ON:		c->operand[15] = 0x1; break;
+			}
+		} else {
+			c->operand[13] = 0x1;  /* auto modulation */
+			c->operand[14] = 0xff; /* disable rolloff */
+			c->operand[15] = 0xff; /* disable pilot */
+		}
+		return 16;
+	} else {
+		return 13;
+	}
+}
+
+static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
+			       struct dtv_frontend_properties *p)
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+
+	c->opcode = AVC_OPCODE_DSD;
+
+	c->operand[0] = 0;    /* source plug */
+	c->operand[1] = 0xd2; /* subfunction replace */
+	c->operand[2] = 0x20; /* system id = DVB */
+	c->operand[3] = 0x00; /* antenna number */
+	c->operand[4] = 0x11; /* system_specific_multiplex selection_length */
+
+	/* multiplex_valid_flags, high byte */
+	c->operand[5] =   0 << 7 /* reserved */
+			| 0 << 6 /* Polarisation */
+			| 0 << 5 /* Orbital_Pos */
+			| 1 << 4 /* Frequency */
+			| 1 << 3 /* Symbol_Rate */
+			| 0 << 2 /* FEC_outer */
+			| (p->fec_inner  != FEC_AUTO ? 1 << 1 : 0)
+			| (p->modulation != QAM_AUTO ? 1 << 0 : 0);
+
+	/* multiplex_valid_flags, low byte */
+	c->operand[6] =   0 << 7 /* NetworkID */
+			| 0 << 0 /* reserved */ ;
+
+	c->operand[7]  = 0x00;
+	c->operand[8]  = 0x00;
+	c->operand[9]  = 0x00;
+	c->operand[10] = 0x00;
+
+	c->operand[11] = (((p->frequency / 4000) >> 16) & 0xff) | (2 << 6);
+	c->operand[12] = ((p->frequency / 4000) >> 8) & 0xff;
+	c->operand[13] = (p->frequency / 4000) & 0xff;
+	c->operand[14] = ((p->symbol_rate / 1000) >> 12) & 0xff;
+	c->operand[15] = ((p->symbol_rate / 1000) >> 4) & 0xff;
+	c->operand[16] = ((p->symbol_rate / 1000) << 4) & 0xf0;
+	c->operand[17] = 0x00;
+
+	switch (p->fec_inner) {
+	case FEC_1_2:	c->operand[18] = 0x1; break;
+	case FEC_2_3:	c->operand[18] = 0x2; break;
+	case FEC_3_4:	c->operand[18] = 0x3; break;
+	case FEC_5_6:	c->operand[18] = 0x4; break;
+	case FEC_7_8:	c->operand[18] = 0x5; break;
+	case FEC_8_9:	c->operand[18] = 0x6; break;
+	case FEC_4_5:	c->operand[18] = 0x8; break;
+	case FEC_AUTO:
+	default:	c->operand[18] = 0x0;
+	}
+
+	switch (p->modulation) {
+	case QAM_16:	c->operand[19] = 0x08; break;
+	case QAM_32:	c->operand[19] = 0x10; break;
+	case QAM_64:	c->operand[19] = 0x18; break;
+	case QAM_128:	c->operand[19] = 0x20; break;
+	case QAM_256:	c->operand[19] = 0x28; break;
+	case QAM_AUTO:
+	default:	c->operand[19] = 0x00;
+	}
+
+	c->operand[20] = 0x00;
+	c->operand[21] = 0x00;
+
+	return 22 + add_pid_filter(fdtv, &c->operand[22]);
+}
+
+static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
+			       struct dtv_frontend_properties *p)
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+
+	c->opcode = AVC_OPCODE_DSD;
+
+	c->operand[0] = 0;    /* source plug */
+	c->operand[1] = 0xd2; /* subfunction replace */
+	c->operand[2] = 0x20; /* system id = DVB */
+	c->operand[3] = 0x00; /* antenna number */
+	c->operand[4] = 0x0c; /* system_specific_multiplex selection_length */
+
+	/* multiplex_valid_flags, high byte */
+	c->operand[5] =
+	      0 << 7 /* reserved */
+	    | 1 << 6 /* CenterFrequency */
+	    | (p->bandwidth_hz != 0        ? 1 << 5 : 0)
+	    | (p->modulation  != QAM_AUTO              ? 1 << 4 : 0)
+	    | (p->hierarchy != HIERARCHY_AUTO ? 1 << 3 : 0)
+	    | (p->code_rate_HP   != FEC_AUTO              ? 1 << 2 : 0)
+	    | (p->code_rate_LP   != FEC_AUTO              ? 1 << 1 : 0)
+	    | (p->guard_interval != GUARD_INTERVAL_AUTO   ? 1 << 0 : 0);
+
+	/* multiplex_valid_flags, low byte */
+	c->operand[6] =
+	      0 << 7 /* NetworkID */
+	    | (p->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0)
+	    | 0 << 5 /* OtherFrequencyFlag */
+	    | 0 << 0 /* reserved */ ;
+
+	c->operand[7]  = 0x0;
+	c->operand[8]  = (p->frequency / 10) >> 24;
+	c->operand[9]  = ((p->frequency / 10) >> 16) & 0xff;
+	c->operand[10] = ((p->frequency / 10) >>  8) & 0xff;
+	c->operand[11] = (p->frequency / 10) & 0xff;
+
+	switch (p->bandwidth_hz) {
+	case 7000000:	c->operand[12] = 0x20; break;
+	case 8000000:
+	case 6000000:	/* not defined by AVC spec */
+	case 0:
+	default:		c->operand[12] = 0x00;
+	}
+
+	switch (p->modulation) {
+	case QAM_16:	c->operand[13] = 1 << 6; break;
+	case QAM_64:	c->operand[13] = 2 << 6; break;
+	case QPSK:
+	default:	c->operand[13] = 0x00;
+	}
+
+	switch (p->hierarchy) {
+	case HIERARCHY_1:	c->operand[13] |= 1 << 3; break;
+	case HIERARCHY_2:	c->operand[13] |= 2 << 3; break;
+	case HIERARCHY_4:	c->operand[13] |= 3 << 3; break;
+	case HIERARCHY_AUTO:
+	case HIERARCHY_NONE:
+	default:		break;
+	}
+
+	switch (p->code_rate_HP) {
+	case FEC_2_3:	c->operand[13] |= 1; break;
+	case FEC_3_4:	c->operand[13] |= 2; break;
+	case FEC_5_6:	c->operand[13] |= 3; break;
+	case FEC_7_8:	c->operand[13] |= 4; break;
+	case FEC_1_2:
+	default:	break;
+	}
+
+	switch (p->code_rate_LP) {
+	case FEC_2_3:	c->operand[14] = 1 << 5; break;
+	case FEC_3_4:	c->operand[14] = 2 << 5; break;
+	case FEC_5_6:	c->operand[14] = 3 << 5; break;
+	case FEC_7_8:	c->operand[14] = 4 << 5; break;
+	case FEC_1_2:
+	default:	c->operand[14] = 0x00; break;
+	}
+
+	switch (p->guard_interval) {
+	case GUARD_INTERVAL_1_16:	c->operand[14] |= 1 << 3; break;
+	case GUARD_INTERVAL_1_8:	c->operand[14] |= 2 << 3; break;
+	case GUARD_INTERVAL_1_4:	c->operand[14] |= 3 << 3; break;
+	case GUARD_INTERVAL_1_32:
+	case GUARD_INTERVAL_AUTO:
+	default:			break;
+	}
+
+	switch (p->transmission_mode) {
+	case TRANSMISSION_MODE_8K:	c->operand[14] |= 1 << 1; break;
+	case TRANSMISSION_MODE_2K:
+	case TRANSMISSION_MODE_AUTO:
+	default:			break;
+	}
+
+	c->operand[15] = 0x00; /* network_ID[0] */
+	c->operand[16] = 0x00; /* network_ID[1] */
+
+	return 17 + add_pid_filter(fdtv, &c->operand[17]);
+}
+
+int avc_tuner_dsd(struct firedtv *fdtv,
+		  struct dtv_frontend_properties *p)
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	int pos, ret;
+
+	mutex_lock(&fdtv->avc_mutex);
+
+	c->ctype   = AVC_CTYPE_CONTROL;
+	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+
+	switch (fdtv->type) {
+	case FIREDTV_DVB_S:
+	case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, p); break;
+	case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, p); break;
+	case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, p); break;
+	default:
+		BUG();
+	}
+	pad_operands(c, pos);
+
+	fdtv->avc_data_length = ALIGN(3 + pos, 4);
+	ret = avc_write(fdtv);
+#if 0
+	/*
+	 * FIXME:
+	 * u8 *status was an out-parameter of avc_tuner_dsd, unused by caller.
+	 * Check for AVC_RESPONSE_ACCEPTED here instead?
+	 */
+	if (status)
+		*status = r->operand[2];
+#endif
+	mutex_unlock(&fdtv->avc_mutex);
+
+	if (ret == 0)
+		msleep(500);
+
+	return ret;
+}
+
+int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[])
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	int ret, pos, k;
+
+	if (pidc > 16 && pidc != 0xff)
+		return -EINVAL;
+
+	mutex_lock(&fdtv->avc_mutex);
+
+	c->ctype   = AVC_CTYPE_CONTROL;
+	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+	c->opcode  = AVC_OPCODE_DSD;
+
+	c->operand[0] = 0;	/* source plug */
+	c->operand[1] = 0xd2;	/* subfunction replace */
+	c->operand[2] = 0x20;	/* system id = DVB */
+	c->operand[3] = 0x00;	/* antenna number */
+	c->operand[4] = 0x00;	/* system_specific_multiplex selection_length */
+	c->operand[5] = pidc;	/* Nr_of_dsd_sel_specs */
+
+	pos = 6;
+	if (pidc != 0xff)
+		for (k = 0; k < pidc; k++) {
+			c->operand[pos++] = 0x13; /* flowfunction relay */
+			c->operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */
+			c->operand[pos++] = (pid[k] >> 8) & 0x1f;
+			c->operand[pos++] = pid[k] & 0xff;
+			c->operand[pos++] = 0x00; /* tableID */
+			c->operand[pos++] = 0x00; /* filter_length */
+		}
+	pad_operands(c, pos);
+
+	fdtv->avc_data_length = ALIGN(3 + pos, 4);
+	ret = avc_write(fdtv);
+
+	/* FIXME: check response code? */
+
+	mutex_unlock(&fdtv->avc_mutex);
+
+	if (ret == 0)
+		msleep(50);
+
+	return ret;
+}
+
+int avc_tuner_get_ts(struct firedtv *fdtv)
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	int ret, sl;
+
+	mutex_lock(&fdtv->avc_mutex);
+
+	c->ctype   = AVC_CTYPE_CONTROL;
+	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+	c->opcode  = AVC_OPCODE_DSIT;
+
+	sl = fdtv->type == FIREDTV_DVB_T ? 0x0c : 0x11;
+
+	c->operand[0] = 0;	/* source plug */
+	c->operand[1] = 0xd2;	/* subfunction replace */
+	c->operand[2] = 0xff;	/* status */
+	c->operand[3] = 0x20;	/* system id = DVB */
+	c->operand[4] = 0x00;	/* antenna number */
+	c->operand[5] = 0x0; 	/* system_specific_search_flags */
+	c->operand[6] = sl;	/* system_specific_multiplex selection_length */
+	/*
+	 * operand[7]: valid_flags[0]
+	 * operand[8]: valid_flags[1]
+	 * operand[7 + sl]: nr_of_dsit_sel_specs (always 0)
+	 */
+	clear_operands(c, 7, 24);
+
+	fdtv->avc_data_length = fdtv->type == FIREDTV_DVB_T ? 24 : 28;
+	ret = avc_write(fdtv);
+
+	/* FIXME: check response code? */
+
+	mutex_unlock(&fdtv->avc_mutex);
+
+	if (ret == 0)
+		msleep(250);
+
+	return ret;
+}
+
+int avc_identify_subunit(struct firedtv *fdtv)
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	struct avc_response_frame *r = (void *)fdtv->avc_data;
+	int ret;
+
+	mutex_lock(&fdtv->avc_mutex);
+
+	c->ctype   = AVC_CTYPE_CONTROL;
+	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+	c->opcode  = AVC_OPCODE_READ_DESCRIPTOR;
+
+	c->operand[0] = DESCRIPTOR_SUBUNIT_IDENTIFIER;
+	c->operand[1] = 0xff;
+	c->operand[2] = 0x00;
+	c->operand[3] = 0x00; /* length highbyte */
+	c->operand[4] = 0x08; /* length lowbyte  */
+	c->operand[5] = 0x00; /* offset highbyte */
+	c->operand[6] = 0x0d; /* offset lowbyte  */
+	clear_operands(c, 7, 8); /* padding */
+
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
+	if (ret < 0)
+		goto out;
+
+	if ((r->response != AVC_RESPONSE_STABLE &&
+	     r->response != AVC_RESPONSE_ACCEPTED) ||
+	    (r->operand[3] << 8) + r->operand[4] != 8) {
+		dev_err(fdtv->device, "cannot read subunit identifier\n");
+		ret = -EINVAL;
+	}
+out:
+	mutex_unlock(&fdtv->avc_mutex);
+
+	return ret;
+}
+
+#define SIZEOF_ANTENNA_INPUT_INFO 22
+
+int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	struct avc_response_frame *r = (void *)fdtv->avc_data;
+	int length, ret;
+
+	mutex_lock(&fdtv->avc_mutex);
+
+	c->ctype   = AVC_CTYPE_CONTROL;
+	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+	c->opcode  = AVC_OPCODE_READ_DESCRIPTOR;
+
+	c->operand[0] = DESCRIPTOR_TUNER_STATUS;
+	c->operand[1] = 0xff;	/* read_result_status */
+	/*
+	 * operand[2]: reserved
+	 * operand[3]: SIZEOF_ANTENNA_INPUT_INFO >> 8
+	 * operand[4]: SIZEOF_ANTENNA_INPUT_INFO & 0xff
+	 */
+	clear_operands(c, 2, 31);
+
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
+	if (ret < 0)
+		goto out;
+
+	if (r->response != AVC_RESPONSE_STABLE &&
+	    r->response != AVC_RESPONSE_ACCEPTED) {
+		dev_err(fdtv->device, "cannot read tuner status\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	length = r->operand[9];
+	if (r->operand[1] != 0x10 || length != SIZEOF_ANTENNA_INPUT_INFO) {
+		dev_err(fdtv->device, "got invalid tuner status\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	stat->active_system		= r->operand[10];
+	stat->searching			= r->operand[11] >> 7 & 1;
+	stat->moving			= r->operand[11] >> 6 & 1;
+	stat->no_rf			= r->operand[11] >> 5 & 1;
+	stat->input			= r->operand[12] >> 7 & 1;
+	stat->selected_antenna		= r->operand[12] & 0x7f;
+	stat->ber			= r->operand[13] << 24 |
+					  r->operand[14] << 16 |
+					  r->operand[15] << 8 |
+					  r->operand[16];
+	stat->signal_strength		= r->operand[17];
+	stat->raster_frequency		= r->operand[18] >> 6 & 2;
+	stat->rf_frequency		= (r->operand[18] & 0x3f) << 16 |
+					  r->operand[19] << 8 |
+					  r->operand[20];
+	stat->man_dep_info_length	= r->operand[21];
+	stat->front_end_error		= r->operand[22] >> 4 & 1;
+	stat->antenna_error		= r->operand[22] >> 3 & 1;
+	stat->front_end_power_status	= r->operand[22] >> 1 & 1;
+	stat->power_supply		= r->operand[22] & 1;
+	stat->carrier_noise_ratio	= r->operand[23] << 8 |
+					  r->operand[24];
+	stat->power_supply_voltage	= r->operand[27];
+	stat->antenna_voltage		= r->operand[28];
+	stat->firewire_bus_voltage	= r->operand[29];
+	stat->ca_mmi			= r->operand[30] & 1;
+	stat->ca_pmt_reply		= r->operand[31] >> 7 & 1;
+	stat->ca_date_time_request	= r->operand[31] >> 6 & 1;
+	stat->ca_application_info	= r->operand[31] >> 5 & 1;
+	stat->ca_module_present_status	= r->operand[31] >> 4 & 1;
+	stat->ca_dvb_flag		= r->operand[31] >> 3 & 1;
+	stat->ca_error_flag		= r->operand[31] >> 2 & 1;
+	stat->ca_initialization_status	= r->operand[31] >> 1 & 1;
+out:
+	mutex_unlock(&fdtv->avc_mutex);
+
+	return ret;
+}
+
+int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
+		    char conttone, char nrdiseq,
+		    struct dvb_diseqc_master_cmd *diseqcmd)
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	struct avc_response_frame *r = (void *)fdtv->avc_data;
+	int pos, j, k, ret;
+
+	mutex_lock(&fdtv->avc_mutex);
+
+	c->ctype   = AVC_CTYPE_CONTROL;
+	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+	c->opcode  = AVC_OPCODE_VENDOR;
+
+	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+	c->operand[3] = SFE_VENDOR_OPCODE_LNB_CONTROL;
+	c->operand[4] = voltage;
+	c->operand[5] = nrdiseq;
+
+	pos = 6;
+	for (j = 0; j < nrdiseq; j++) {
+		c->operand[pos++] = diseqcmd[j].msg_len;
+
+		for (k = 0; k < diseqcmd[j].msg_len; k++)
+			c->operand[pos++] = diseqcmd[j].msg[k];
+	}
+	c->operand[pos++] = burst;
+	c->operand[pos++] = conttone;
+	pad_operands(c, pos);
+
+	fdtv->avc_data_length = ALIGN(3 + pos, 4);
+	ret = avc_write(fdtv);
+	if (ret < 0)
+		goto out;
+
+	if (r->response != AVC_RESPONSE_ACCEPTED) {
+		dev_err(fdtv->device, "LNB control failed\n");
+		ret = -EINVAL;
+	}
+out:
+	mutex_unlock(&fdtv->avc_mutex);
+
+	return ret;
+}
+
+int avc_register_remote_control(struct firedtv *fdtv)
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	int ret;
+
+	mutex_lock(&fdtv->avc_mutex);
+
+	c->ctype   = AVC_CTYPE_NOTIFY;
+	c->subunit = AVC_SUBUNIT_TYPE_UNIT | 7;
+	c->opcode  = AVC_OPCODE_VENDOR;
+
+	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+	c->operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
+	c->operand[4] = 0; /* padding */
+
+	fdtv->avc_data_length = 8;
+	ret = avc_write(fdtv);
+
+	/* FIXME: check response code? */
+
+	mutex_unlock(&fdtv->avc_mutex);
+
+	return ret;
+}
+
+void avc_remote_ctrl_work(struct work_struct *work)
+{
+	struct firedtv *fdtv =
+			container_of(work, struct firedtv, remote_ctrl_work);
+
+	/* Should it be rescheduled in failure cases? */
+	avc_register_remote_control(fdtv);
+}
+
+#if 0 /* FIXME: unused */
+int avc_tuner_host2ca(struct firedtv *fdtv)
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	int ret;
+
+	mutex_lock(&fdtv->avc_mutex);
+
+	c->ctype   = AVC_CTYPE_CONTROL;
+	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+	c->opcode  = AVC_OPCODE_VENDOR;
+
+	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+	c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
+	c->operand[4] = 0; /* slot */
+	c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
+	clear_operands(c, 6, 8);
+
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
+
+	/* FIXME: check response code? */
+
+	mutex_unlock(&fdtv->avc_mutex);
+
+	return ret;
+}
+#endif
+
+static int get_ca_object_pos(struct avc_response_frame *r)
+{
+	int length = 1;
+
+	/* Check length of length field */
+	if (r->operand[7] & 0x80)
+		length = (r->operand[7] & 0x7f) + 1;
+	return length + 7;
+}
+
+static int get_ca_object_length(struct avc_response_frame *r)
+{
+#if 0 /* FIXME: unused */
+	int size = 0;
+	int i;
+
+	if (r->operand[7] & 0x80)
+		for (i = 0; i < (r->operand[7] & 0x7f); i++) {
+			size <<= 8;
+			size += r->operand[8 + i];
+		}
+#endif
+	return r->operand[7];
+}
+
+int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	struct avc_response_frame *r = (void *)fdtv->avc_data;
+	int pos, ret;
+
+	mutex_lock(&fdtv->avc_mutex);
+
+	c->ctype   = AVC_CTYPE_STATUS;
+	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+	c->opcode  = AVC_OPCODE_VENDOR;
+
+	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+	c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
+	c->operand[4] = 0; /* slot */
+	c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
+	clear_operands(c, 6, LAST_OPERAND);
+
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
+	if (ret < 0)
+		goto out;
+
+	/* FIXME: check response code and validate response data */
+
+	pos = get_ca_object_pos(r);
+	app_info[0] = (EN50221_TAG_APP_INFO >> 16) & 0xff;
+	app_info[1] = (EN50221_TAG_APP_INFO >>  8) & 0xff;
+	app_info[2] = (EN50221_TAG_APP_INFO >>  0) & 0xff;
+	app_info[3] = 6 + r->operand[pos + 4];
+	app_info[4] = 0x01;
+	memcpy(&app_info[5], &r->operand[pos], 5 + r->operand[pos + 4]);
+	*len = app_info[3] + 4;
+out:
+	mutex_unlock(&fdtv->avc_mutex);
+
+	return ret;
+}
+
+int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	struct avc_response_frame *r = (void *)fdtv->avc_data;
+	int i, pos, ret;
+
+	mutex_lock(&fdtv->avc_mutex);
+
+	c->ctype   = AVC_CTYPE_STATUS;
+	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+	c->opcode  = AVC_OPCODE_VENDOR;
+
+	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+	c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
+	c->operand[4] = 0; /* slot */
+	c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
+	clear_operands(c, 6, LAST_OPERAND);
+
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
+	if (ret < 0)
+		goto out;
+
+	/* FIXME: check response code and validate response data */
+
+	pos = get_ca_object_pos(r);
+	app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff;
+	app_info[1] = (EN50221_TAG_CA_INFO >>  8) & 0xff;
+	app_info[2] = (EN50221_TAG_CA_INFO >>  0) & 0xff;
+	if (num_fake_ca_system_ids == 0) {
+		app_info[3] = 2;
+		app_info[4] = r->operand[pos + 0];
+		app_info[5] = r->operand[pos + 1];
+	} else {
+		app_info[3] = num_fake_ca_system_ids * 2;
+		for (i = 0; i < num_fake_ca_system_ids; i++) {
+			app_info[4 + i * 2] =
+				(fake_ca_system_ids[i] >> 8) & 0xff;
+			app_info[5 + i * 2] = fake_ca_system_ids[i] & 0xff;
+		}
+	}
+	*len = app_info[3] + 4;
+out:
+	mutex_unlock(&fdtv->avc_mutex);
+
+	return ret;
+}
+
+int avc_ca_reset(struct firedtv *fdtv)
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	int ret;
+
+	mutex_lock(&fdtv->avc_mutex);
+
+	c->ctype   = AVC_CTYPE_CONTROL;
+	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+	c->opcode  = AVC_OPCODE_VENDOR;
+
+	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+	c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
+	c->operand[4] = 0; /* slot */
+	c->operand[5] = SFE_VENDOR_TAG_CA_RESET; /* ca tag */
+	c->operand[6] = 0; /* more/last */
+	c->operand[7] = 1; /* length */
+	c->operand[8] = 0; /* force hardware reset */
+
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
+
+	/* FIXME: check response code? */
+
+	mutex_unlock(&fdtv->avc_mutex);
+
+	return ret;
+}
+
+int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	struct avc_response_frame *r = (void *)fdtv->avc_data;
+	int list_management;
+	int program_info_length;
+	int pmt_cmd_id;
+	int read_pos;
+	int write_pos;
+	int es_info_length;
+	int crc32_csum;
+	int ret;
+
+	if (unlikely(avc_debug & AVC_DEBUG_APPLICATION_PMT))
+		debug_pmt(msg, length);
+
+	mutex_lock(&fdtv->avc_mutex);
+
+	c->ctype   = AVC_CTYPE_CONTROL;
+	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+	c->opcode  = AVC_OPCODE_VENDOR;
+
+	if (msg[0] != EN50221_LIST_MANAGEMENT_ONLY) {
+		dev_info(fdtv->device, "forcing list_management to ONLY\n");
+		msg[0] = EN50221_LIST_MANAGEMENT_ONLY;
+	}
+	/* We take the cmd_id from the programme level only! */
+	list_management = msg[0];
+	program_info_length = ((msg[4] & 0x0f) << 8) + msg[5];
+	if (program_info_length > 0)
+		program_info_length--; /* Remove pmt_cmd_id */
+	pmt_cmd_id = msg[6];
+
+	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+	c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
+	c->operand[4] = 0; /* slot */
+	c->operand[5] = SFE_VENDOR_TAG_CA_PMT; /* ca tag */
+	c->operand[6] = 0; /* more/last */
+	/* Use three bytes for length field in case length > 127 */
+	c->operand[10] = list_management;
+	c->operand[11] = 0x01; /* pmt_cmd=OK_descramble */
+
+	/* TS program map table */
+
+	c->operand[12] = 0x02; /* Table id=2 */
+	c->operand[13] = 0x80; /* Section syntax + length */
+
+	c->operand[15] = msg[1]; /* Program number */
+	c->operand[16] = msg[2];
+	c->operand[17] = msg[3]; /* Version number and current/next */
+	c->operand[18] = 0x00; /* Section number=0 */
+	c->operand[19] = 0x00; /* Last section number=0 */
+	c->operand[20] = 0x1f; /* PCR_PID=1FFF */
+	c->operand[21] = 0xff;
+	c->operand[22] = (program_info_length >> 8); /* Program info length */
+	c->operand[23] = (program_info_length & 0xff);
+
+	/* CA descriptors at programme level */
+	read_pos = 6;
+	write_pos = 24;
+	if (program_info_length > 0) {
+		pmt_cmd_id = msg[read_pos++];
+		if (pmt_cmd_id != 1 && pmt_cmd_id != 4)
+			dev_err(fdtv->device,
+				"invalid pmt_cmd_id %d\n", pmt_cmd_id);
+
+		memcpy(&c->operand[write_pos], &msg[read_pos],
+		       program_info_length);
+		read_pos += program_info_length;
+		write_pos += program_info_length;
+	}
+	while (read_pos < length) {
+		c->operand[write_pos++] = msg[read_pos++];
+		c->operand[write_pos++] = msg[read_pos++];
+		c->operand[write_pos++] = msg[read_pos++];
+		es_info_length =
+			((msg[read_pos] & 0x0f) << 8) + msg[read_pos + 1];
+		read_pos += 2;
+		if (es_info_length > 0)
+			es_info_length--; /* Remove pmt_cmd_id */
+		c->operand[write_pos++] = es_info_length >> 8;
+		c->operand[write_pos++] = es_info_length & 0xff;
+		if (es_info_length > 0) {
+			pmt_cmd_id = msg[read_pos++];
+			if (pmt_cmd_id != 1 && pmt_cmd_id != 4)
+				dev_err(fdtv->device, "invalid pmt_cmd_id %d "
+					"at stream level\n", pmt_cmd_id);
+
+			memcpy(&c->operand[write_pos], &msg[read_pos],
+			       es_info_length);
+			read_pos += es_info_length;
+			write_pos += es_info_length;
+		}
+	}
+	write_pos += 4; /* CRC */
+
+	c->operand[7] = 0x82;
+	c->operand[8] = (write_pos - 10) >> 8;
+	c->operand[9] = (write_pos - 10) & 0xff;
+	c->operand[14] = write_pos - 15;
+
+	crc32_csum = crc32_be(0, &c->operand[10], c->operand[12] - 1);
+	c->operand[write_pos - 4] = (crc32_csum >> 24) & 0xff;
+	c->operand[write_pos - 3] = (crc32_csum >> 16) & 0xff;
+	c->operand[write_pos - 2] = (crc32_csum >>  8) & 0xff;
+	c->operand[write_pos - 1] = (crc32_csum >>  0) & 0xff;
+	pad_operands(c, write_pos);
+
+	fdtv->avc_data_length = ALIGN(3 + write_pos, 4);
+	ret = avc_write(fdtv);
+	if (ret < 0)
+		goto out;
+
+	if (r->response != AVC_RESPONSE_ACCEPTED) {
+		dev_err(fdtv->device,
+			"CA PMT failed with response 0x%x\n", r->response);
+		ret = -EACCES;
+	}
+out:
+	mutex_unlock(&fdtv->avc_mutex);
+
+	return ret;
+}
+
+int avc_ca_get_time_date(struct firedtv *fdtv, int *interval)
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	struct avc_response_frame *r = (void *)fdtv->avc_data;
+	int ret;
+
+	mutex_lock(&fdtv->avc_mutex);
+
+	c->ctype   = AVC_CTYPE_STATUS;
+	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+	c->opcode  = AVC_OPCODE_VENDOR;
+
+	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+	c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
+	c->operand[4] = 0; /* slot */
+	c->operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; /* ca tag */
+	clear_operands(c, 6, LAST_OPERAND);
+
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
+	if (ret < 0)
+		goto out;
+
+	/* FIXME: check response code and validate response data */
+
+	*interval = r->operand[get_ca_object_pos(r)];
+out:
+	mutex_unlock(&fdtv->avc_mutex);
+
+	return ret;
+}
+
+int avc_ca_enter_menu(struct firedtv *fdtv)
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	int ret;
+
+	mutex_lock(&fdtv->avc_mutex);
+
+	c->ctype   = AVC_CTYPE_STATUS;
+	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+	c->opcode  = AVC_OPCODE_VENDOR;
+
+	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+	c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
+	c->operand[4] = 0; /* slot */
+	c->operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU;
+	clear_operands(c, 6, 8);
+
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
+
+	/* FIXME: check response code? */
+
+	mutex_unlock(&fdtv->avc_mutex);
+
+	return ret;
+}
+
+int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
+{
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	struct avc_response_frame *r = (void *)fdtv->avc_data;
+	int ret;
+
+	mutex_lock(&fdtv->avc_mutex);
+
+	c->ctype   = AVC_CTYPE_STATUS;
+	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+	c->opcode  = AVC_OPCODE_VENDOR;
+
+	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+	c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
+	c->operand[4] = 0; /* slot */
+	c->operand[5] = SFE_VENDOR_TAG_CA_MMI;
+	clear_operands(c, 6, LAST_OPERAND);
+
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
+	if (ret < 0)
+		goto out;
+
+	/* FIXME: check response code and validate response data */
+
+	*len = get_ca_object_length(r);
+	memcpy(mmi_object, &r->operand[get_ca_object_pos(r)], *len);
+out:
+	mutex_unlock(&fdtv->avc_mutex);
+
+	return ret;
+}
+
+#define CMP_OUTPUT_PLUG_CONTROL_REG_0	0xfffff0000904ULL
+
+static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data)
+{
+	int ret;
+
+	ret = fdtv_read(fdtv, addr, data);
+	if (ret < 0)
+		dev_err(fdtv->device, "CMP: read I/O error\n");
+
+	return ret;
+}
+
+static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
+{
+	int ret;
+
+	ret = fdtv_lock(fdtv, addr, data);
+	if (ret < 0)
+		dev_err(fdtv->device, "CMP: lock I/O error\n");
+
+	return ret;
+}
+
+static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift)
+{
+	return (be32_to_cpu(opcr) >> shift) & mask;
+}
+
+static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift)
+{
+	*opcr &= ~cpu_to_be32(mask << shift);
+	*opcr |= cpu_to_be32((value & mask) << shift);
+}
+
+#define get_opcr_online(v)		get_opcr((v), 0x1, 31)
+#define get_opcr_p2p_connections(v)	get_opcr((v), 0x3f, 24)
+#define get_opcr_channel(v)		get_opcr((v), 0x3f, 16)
+
+#define set_opcr_p2p_connections(p, v)	set_opcr((p), (v), 0x3f, 24)
+#define set_opcr_channel(p, v)		set_opcr((p), (v), 0x3f, 16)
+#define set_opcr_data_rate(p, v)	set_opcr((p), (v), 0x3, 14)
+#define set_opcr_overhead_id(p, v)	set_opcr((p), (v), 0xf, 10)
+
+int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel)
+{
+	__be32 old_opcr, opcr[2];
+	u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
+	int attempts = 0;
+	int ret;
+
+	ret = cmp_read(fdtv, opcr_address, opcr);
+	if (ret < 0)
+		return ret;
+
+repeat:
+	if (!get_opcr_online(*opcr)) {
+		dev_err(fdtv->device, "CMP: output offline\n");
+		return -EBUSY;
+	}
+
+	old_opcr = *opcr;
+
+	if (get_opcr_p2p_connections(*opcr)) {
+		if (get_opcr_channel(*opcr) != channel) {
+			dev_err(fdtv->device, "CMP: cannot change channel\n");
+			return -EBUSY;
+		}
+		dev_info(fdtv->device, "CMP: overlaying connection\n");
+
+		/* We don't allocate isochronous resources. */
+	} else {
+		set_opcr_channel(opcr, channel);
+		set_opcr_data_rate(opcr, 2); /* S400 */
+
+		/* FIXME: this is for the worst case - optimize */
+		set_opcr_overhead_id(opcr, 0);
+
+		/* FIXME: allocate isochronous channel and bandwidth at IRM */
+	}
+
+	set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) + 1);
+
+	opcr[1] = *opcr;
+	opcr[0] = old_opcr;
+
+	ret = cmp_lock(fdtv, opcr_address, opcr);
+	if (ret < 0)
+		return ret;
+
+	if (old_opcr != *opcr) {
+		/*
+		 * FIXME: if old_opcr.P2P_Connections > 0,
+		 * deallocate isochronous channel and bandwidth at IRM
+		 */
+
+		if (++attempts < 6) /* arbitrary limit */
+			goto repeat;
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel)
+{
+	__be32 old_opcr, opcr[2];
+	u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
+	int attempts = 0;
+
+	if (cmp_read(fdtv, opcr_address, opcr) < 0)
+		return;
+
+repeat:
+	if (!get_opcr_online(*opcr) || !get_opcr_p2p_connections(*opcr) ||
+	    get_opcr_channel(*opcr) != channel) {
+		dev_err(fdtv->device, "CMP: no connection to break\n");
+		return;
+	}
+
+	old_opcr = *opcr;
+	set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) - 1);
+
+	opcr[1] = *opcr;
+	opcr[0] = old_opcr;
+
+	if (cmp_lock(fdtv, opcr_address, opcr) < 0)
+		return;
+
+	if (old_opcr != *opcr) {
+		/*
+		 * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last
+		 * owner, deallocate isochronous channel and bandwidth at IRM
+		 * if (...)
+		 *	fdtv->backend->dealloc_resources(fdtv, channel, bw);
+		 */
+
+		if (++attempts < 6) /* arbitrary limit */
+			goto repeat;
+	}
+}
diff --git a/drivers/media/firewire/firedtv-ci.c b/drivers/media/firewire/firedtv-ci.c
new file mode 100644
index 0000000..e5ebdbf
--- /dev/null
+++ b/drivers/media/firewire/firedtv-ci.c
@@ -0,0 +1,258 @@
+/*
+ * FireDTV driver (formerly known as FireSAT)
+ *
+ * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
+ * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
+ *
+ *	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.
+ */
+
+#include <linux/device.h>
+#include <linux/dvb/ca.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+
+#include <dvbdev.h>
+
+#include "firedtv.h"
+
+#define EN50221_TAG_APP_INFO_ENQUIRY	0x9f8020
+#define EN50221_TAG_CA_INFO_ENQUIRY	0x9f8030
+#define EN50221_TAG_CA_PMT		0x9f8032
+#define EN50221_TAG_ENTER_MENU		0x9f8022
+
+static int fdtv_ca_ready(struct firedtv_tuner_status *stat)
+{
+	return stat->ca_initialization_status	== 1 &&
+	       stat->ca_error_flag		== 0 &&
+	       stat->ca_dvb_flag		== 1 &&
+	       stat->ca_module_present_status	== 1;
+}
+
+static int fdtv_get_ca_flags(struct firedtv_tuner_status *stat)
+{
+	int flags = 0;
+
+	if (stat->ca_module_present_status == 1)
+		flags |= CA_CI_MODULE_PRESENT;
+	if (stat->ca_initialization_status == 1 &&
+	    stat->ca_error_flag            == 0 &&
+	    stat->ca_dvb_flag              == 1)
+		flags |= CA_CI_MODULE_READY;
+	return flags;
+}
+
+static int fdtv_ca_get_caps(void *arg)
+{
+	struct ca_caps *cap = arg;
+
+	cap->slot_num = 1;
+	cap->slot_type = CA_CI;
+	cap->descr_num = 1;
+	cap->descr_type = CA_ECD;
+	return 0;
+}
+
+static int fdtv_ca_get_slot_info(struct firedtv *fdtv, void *arg)
+{
+	struct firedtv_tuner_status stat;
+	struct ca_slot_info *slot = arg;
+	int err;
+
+	err = avc_tuner_status(fdtv, &stat);
+	if (err)
+		return err;
+
+	if (slot->num != 0)
+		return -EACCES;
+
+	slot->type = CA_CI;
+	slot->flags = fdtv_get_ca_flags(&stat);
+	return 0;
+}
+
+static int fdtv_ca_app_info(struct firedtv *fdtv, void *arg)
+{
+	struct ca_msg *reply = arg;
+
+	return avc_ca_app_info(fdtv, reply->msg, &reply->length);
+}
+
+static int fdtv_ca_info(struct firedtv *fdtv, void *arg)
+{
+	struct ca_msg *reply = arg;
+
+	return avc_ca_info(fdtv, reply->msg, &reply->length);
+}
+
+static int fdtv_ca_get_mmi(struct firedtv *fdtv, void *arg)
+{
+	struct ca_msg *reply = arg;
+
+	return avc_ca_get_mmi(fdtv, reply->msg, &reply->length);
+}
+
+static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg)
+{
+	struct firedtv_tuner_status stat;
+	int err;
+
+	switch (fdtv->ca_last_command) {
+	case EN50221_TAG_APP_INFO_ENQUIRY:
+		err = fdtv_ca_app_info(fdtv, arg);
+		break;
+	case EN50221_TAG_CA_INFO_ENQUIRY:
+		err = fdtv_ca_info(fdtv, arg);
+		break;
+	default:
+		err = avc_tuner_status(fdtv, &stat);
+		if (err)
+			break;
+		if (stat.ca_mmi == 1)
+			err = fdtv_ca_get_mmi(fdtv, arg);
+		else {
+			dev_info(fdtv->device, "unhandled CA message 0x%08x\n",
+				 fdtv->ca_last_command);
+			err = -EACCES;
+		}
+	}
+	fdtv->ca_last_command = 0;
+	return err;
+}
+
+static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg)
+{
+	struct ca_msg *msg = arg;
+	int data_pos;
+	int data_length;
+	int i;
+
+	data_pos = 4;
+	if (msg->msg[3] & 0x80) {
+		data_length = 0;
+		for (i = 0; i < (msg->msg[3] & 0x7f); i++)
+			data_length = (data_length << 8) + msg->msg[data_pos++];
+	} else {
+		data_length = msg->msg[3];
+	}
+
+	return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length);
+}
+
+static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg)
+{
+	struct ca_msg *msg = arg;
+	int err;
+
+	/* Do we need a semaphore for this? */
+	fdtv->ca_last_command =
+		(msg->msg[0] << 16) + (msg->msg[1] << 8) + msg->msg[2];
+	switch (fdtv->ca_last_command) {
+	case EN50221_TAG_CA_PMT:
+		err = fdtv_ca_pmt(fdtv, arg);
+		break;
+	case EN50221_TAG_APP_INFO_ENQUIRY:
+		/* handled in ca_get_msg */
+		err = 0;
+		break;
+	case EN50221_TAG_CA_INFO_ENQUIRY:
+		/* handled in ca_get_msg */
+		err = 0;
+		break;
+	case EN50221_TAG_ENTER_MENU:
+		err = avc_ca_enter_menu(fdtv);
+		break;
+	default:
+		dev_err(fdtv->device, "unhandled CA message 0x%08x\n",
+			fdtv->ca_last_command);
+		err = -EACCES;
+	}
+	return err;
+}
+
+static int fdtv_ca_ioctl(struct file *file, unsigned int cmd, void *arg)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct firedtv *fdtv = dvbdev->priv;
+	struct firedtv_tuner_status stat;
+	int err;
+
+	switch (cmd) {
+	case CA_RESET:
+		err = avc_ca_reset(fdtv);
+		break;
+	case CA_GET_CAP:
+		err = fdtv_ca_get_caps(arg);
+		break;
+	case CA_GET_SLOT_INFO:
+		err = fdtv_ca_get_slot_info(fdtv, arg);
+		break;
+	case CA_GET_MSG:
+		err = fdtv_ca_get_msg(fdtv, arg);
+		break;
+	case CA_SEND_MSG:
+		err = fdtv_ca_send_msg(fdtv, arg);
+		break;
+	default:
+		dev_info(fdtv->device, "unhandled CA ioctl %u\n", cmd);
+		err = -EOPNOTSUPP;
+	}
+
+	/* FIXME Is this necessary? */
+	avc_tuner_status(fdtv, &stat);
+
+	return err;
+}
+
+static unsigned int fdtv_ca_io_poll(struct file *file, poll_table *wait)
+{
+	return POLLIN;
+}
+
+static const struct file_operations fdtv_ca_fops = {
+	.owner		= THIS_MODULE,
+	.unlocked_ioctl	= dvb_generic_ioctl,
+	.open		= dvb_generic_open,
+	.release	= dvb_generic_release,
+	.poll		= fdtv_ca_io_poll,
+	.llseek		= noop_llseek,
+};
+
+static struct dvb_device fdtv_ca = {
+	.users		= 1,
+	.readers	= 1,
+	.writers	= 1,
+	.fops		= &fdtv_ca_fops,
+	.kernel_ioctl	= fdtv_ca_ioctl,
+};
+
+int fdtv_ca_register(struct firedtv *fdtv)
+{
+	struct firedtv_tuner_status stat;
+	int err;
+
+	if (avc_tuner_status(fdtv, &stat))
+		return -EINVAL;
+
+	if (!fdtv_ca_ready(&stat))
+		return -EFAULT;
+
+	err = dvb_register_device(&fdtv->adapter, &fdtv->cadev,
+				  &fdtv_ca, fdtv, DVB_DEVICE_CA);
+
+	if (stat.ca_application_info == 0)
+		dev_err(fdtv->device, "CaApplicationInfo is not set\n");
+	if (stat.ca_date_time_request == 1)
+		avc_ca_get_time_date(fdtv, &fdtv->ca_time_interval);
+
+	return err;
+}
+
+void fdtv_ca_release(struct firedtv *fdtv)
+{
+	if (fdtv->cadev)
+		dvb_unregister_device(fdtv->cadev);
+}
diff --git a/drivers/media/firewire/firedtv-dvb.c b/drivers/media/firewire/firedtv-dvb.c
new file mode 100644
index 0000000..eb7496e
--- /dev/null
+++ b/drivers/media/firewire/firedtv-dvb.c
@@ -0,0 +1,248 @@
+/*
+ * FireDTV driver (formerly known as FireSAT)
+ *
+ * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
+ * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
+ *
+ *	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.
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+#include <dmxdev.h>
+#include <dvb_demux.h>
+#include <dvbdev.h>
+#include <dvb_frontend.h>
+
+#include "firedtv.h"
+
+static int alloc_channel(struct firedtv *fdtv)
+{
+	int i;
+
+	for (i = 0; i < 16; i++)
+		if (!__test_and_set_bit(i, &fdtv->channel_active))
+			break;
+	return i;
+}
+
+static void collect_channels(struct firedtv *fdtv, int *pidc, u16 pid[])
+{
+	int i, n;
+
+	for (i = 0, n = 0; i < 16; i++)
+		if (test_bit(i, &fdtv->channel_active))
+			pid[n++] = fdtv->channel_pid[i];
+	*pidc = n;
+}
+
+static inline void dealloc_channel(struct firedtv *fdtv, int i)
+{
+	__clear_bit(i, &fdtv->channel_active);
+}
+
+int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct firedtv *fdtv = dvbdmxfeed->demux->priv;
+	int pidc, c, ret;
+	u16 pids[16];
+
+	switch (dvbdmxfeed->type) {
+	case DMX_TYPE_TS:
+	case DMX_TYPE_SEC:
+		break;
+	default:
+		dev_err(fdtv->device, "can't start dmx feed: invalid type %u\n",
+			dvbdmxfeed->type);
+		return -EINVAL;
+	}
+
+	if (mutex_lock_interruptible(&fdtv->demux_mutex))
+		return -EINTR;
+
+	if (dvbdmxfeed->type == DMX_TYPE_TS) {
+		switch (dvbdmxfeed->pes_type) {
+		case DMX_TS_PES_VIDEO:
+		case DMX_TS_PES_AUDIO:
+		case DMX_TS_PES_TELETEXT:
+		case DMX_TS_PES_PCR:
+		case DMX_TS_PES_OTHER:
+			c = alloc_channel(fdtv);
+			break;
+		default:
+			dev_err(fdtv->device,
+				"can't start dmx feed: invalid pes type %u\n",
+				dvbdmxfeed->pes_type);
+			ret = -EINVAL;
+			goto out;
+		}
+	} else {
+		c = alloc_channel(fdtv);
+	}
+
+	if (c > 15) {
+		dev_err(fdtv->device, "can't start dmx feed: busy\n");
+		ret = -EBUSY;
+		goto out;
+	}
+
+	dvbdmxfeed->priv = (typeof(dvbdmxfeed->priv))(unsigned long)c;
+	fdtv->channel_pid[c] = dvbdmxfeed->pid;
+	collect_channels(fdtv, &pidc, pids);
+
+	if (dvbdmxfeed->pid == 8192) {
+		ret = avc_tuner_get_ts(fdtv);
+		if (ret) {
+			dealloc_channel(fdtv, c);
+			dev_err(fdtv->device, "can't get TS\n");
+			goto out;
+		}
+	} else {
+		ret = avc_tuner_set_pids(fdtv, pidc, pids);
+		if (ret) {
+			dealloc_channel(fdtv, c);
+			dev_err(fdtv->device, "can't set PIDs\n");
+			goto out;
+		}
+	}
+out:
+	mutex_unlock(&fdtv->demux_mutex);
+
+	return ret;
+}
+
+int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *demux = dvbdmxfeed->demux;
+	struct firedtv *fdtv = demux->priv;
+	int pidc, c, ret;
+	u16 pids[16];
+
+	if (dvbdmxfeed->type == DMX_TYPE_TS &&
+	    !((dvbdmxfeed->ts_type & TS_PACKET) &&
+	      (demux->dmx.frontend->source != DMX_MEMORY_FE))) {
+
+		if (dvbdmxfeed->ts_type & TS_DECODER) {
+			if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER ||
+			    !demux->pesfilter[dvbdmxfeed->pes_type])
+				return -EINVAL;
+
+			demux->pids[dvbdmxfeed->pes_type] |= 0x8000;
+			demux->pesfilter[dvbdmxfeed->pes_type] = NULL;
+		}
+
+		if (!(dvbdmxfeed->ts_type & TS_DECODER &&
+		      dvbdmxfeed->pes_type < DMX_TS_PES_OTHER))
+			return 0;
+	}
+
+	if (mutex_lock_interruptible(&fdtv->demux_mutex))
+		return -EINTR;
+
+	c = (unsigned long)dvbdmxfeed->priv;
+	dealloc_channel(fdtv, c);
+	collect_channels(fdtv, &pidc, pids);
+
+	ret = avc_tuner_set_pids(fdtv, pidc, pids);
+
+	mutex_unlock(&fdtv->demux_mutex);
+
+	return ret;
+}
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+int fdtv_dvb_register(struct firedtv *fdtv, const char *name)
+{
+	int err;
+
+	err = dvb_register_adapter(&fdtv->adapter, name,
+				   THIS_MODULE, fdtv->device, adapter_nr);
+	if (err < 0)
+		goto fail_log;
+
+	/*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/
+	fdtv->demux.dmx.capabilities = 0;
+
+	fdtv->demux.priv	= fdtv;
+	fdtv->demux.filternum	= 16;
+	fdtv->demux.feednum	= 16;
+	fdtv->demux.start_feed	= fdtv_start_feed;
+	fdtv->demux.stop_feed	= fdtv_stop_feed;
+	fdtv->demux.write_to_decoder = NULL;
+
+	err = dvb_dmx_init(&fdtv->demux);
+	if (err)
+		goto fail_unreg_adapter;
+
+	fdtv->dmxdev.filternum    = 16;
+	fdtv->dmxdev.demux        = &fdtv->demux.dmx;
+	fdtv->dmxdev.capabilities = 0;
+
+	err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter);
+	if (err)
+		goto fail_dmx_release;
+
+	fdtv->frontend.source = DMX_FRONTEND_0;
+
+	err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, &fdtv->frontend);
+	if (err)
+		goto fail_dmxdev_release;
+
+	err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx,
+					       &fdtv->frontend);
+	if (err)
+		goto fail_rem_frontend;
+
+	err = dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx);
+	if (err)
+		goto fail_disconnect_frontend;
+
+	fdtv_frontend_init(fdtv, name);
+	err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe);
+	if (err)
+		goto fail_net_release;
+
+	err = fdtv_ca_register(fdtv);
+	if (err)
+		dev_info(fdtv->device,
+			 "Conditional Access Module not enabled\n");
+	return 0;
+
+fail_net_release:
+	dvb_net_release(&fdtv->dvbnet);
+fail_disconnect_frontend:
+	fdtv->demux.dmx.close(&fdtv->demux.dmx);
+fail_rem_frontend:
+	fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
+fail_dmxdev_release:
+	dvb_dmxdev_release(&fdtv->dmxdev);
+fail_dmx_release:
+	dvb_dmx_release(&fdtv->demux);
+fail_unreg_adapter:
+	dvb_unregister_adapter(&fdtv->adapter);
+fail_log:
+	dev_err(fdtv->device, "DVB initialization failed\n");
+	return err;
+}
+
+void fdtv_dvb_unregister(struct firedtv *fdtv)
+{
+	fdtv_ca_release(fdtv);
+	dvb_unregister_frontend(&fdtv->fe);
+	dvb_net_release(&fdtv->dvbnet);
+	fdtv->demux.dmx.close(&fdtv->demux.dmx);
+	fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
+	dvb_dmxdev_release(&fdtv->dmxdev);
+	dvb_dmx_release(&fdtv->demux);
+	dvb_unregister_adapter(&fdtv->adapter);
+}
diff --git a/drivers/media/firewire/firedtv-fe.c b/drivers/media/firewire/firedtv-fe.c
new file mode 100644
index 0000000..6fe9793
--- /dev/null
+++ b/drivers/media/firewire/firedtv-fe.c
@@ -0,0 +1,254 @@
+/*
+ * FireDTV driver (formerly known as FireSAT)
+ *
+ * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
+ * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
+ *
+ *	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.
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <dvb_frontend.h>
+
+#include "firedtv.h"
+
+static int fdtv_dvb_init(struct dvb_frontend *fe)
+{
+	struct firedtv *fdtv = fe->sec_priv;
+	int err;
+
+	/* FIXME - allocate free channel at IRM */
+	fdtv->isochannel = fdtv->adapter.num;
+
+	err = cmp_establish_pp_connection(fdtv, fdtv->subunit,
+					  fdtv->isochannel);
+	if (err) {
+		dev_err(fdtv->device,
+			"could not establish point to point connection\n");
+		return err;
+	}
+
+	return fdtv_start_iso(fdtv);
+}
+
+static int fdtv_sleep(struct dvb_frontend *fe)
+{
+	struct firedtv *fdtv = fe->sec_priv;
+
+	fdtv_stop_iso(fdtv);
+	cmp_break_pp_connection(fdtv, fdtv->subunit, fdtv->isochannel);
+	fdtv->isochannel = -1;
+	return 0;
+}
+
+#define LNBCONTROL_DONTCARE 0xff
+
+static int fdtv_diseqc_send_master_cmd(struct dvb_frontend *fe,
+				       struct dvb_diseqc_master_cmd *cmd)
+{
+	struct firedtv *fdtv = fe->sec_priv;
+
+	return avc_lnb_control(fdtv, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE,
+			       LNBCONTROL_DONTCARE, 1, cmd);
+}
+
+static int fdtv_diseqc_send_burst(struct dvb_frontend *fe,
+				  fe_sec_mini_cmd_t minicmd)
+{
+	return 0;
+}
+
+static int fdtv_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct firedtv *fdtv = fe->sec_priv;
+
+	fdtv->tone = tone;
+	return 0;
+}
+
+static int fdtv_set_voltage(struct dvb_frontend *fe,
+			    fe_sec_voltage_t voltage)
+{
+	struct firedtv *fdtv = fe->sec_priv;
+
+	fdtv->voltage = voltage;
+	return 0;
+}
+
+static int fdtv_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct firedtv *fdtv = fe->sec_priv;
+	struct firedtv_tuner_status stat;
+
+	if (avc_tuner_status(fdtv, &stat))
+		return -EINVAL;
+
+	if (stat.no_rf)
+		*status = 0;
+	else
+		*status = FE_HAS_SIGNAL | FE_HAS_VITERBI | FE_HAS_SYNC |
+			  FE_HAS_CARRIER | FE_HAS_LOCK;
+	return 0;
+}
+
+static int fdtv_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct firedtv *fdtv = fe->sec_priv;
+	struct firedtv_tuner_status stat;
+
+	if (avc_tuner_status(fdtv, &stat))
+		return -EINVAL;
+
+	*ber = stat.ber;
+	return 0;
+}
+
+static int fdtv_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct firedtv *fdtv = fe->sec_priv;
+	struct firedtv_tuner_status stat;
+
+	if (avc_tuner_status(fdtv, &stat))
+		return -EINVAL;
+
+	*strength = stat.signal_strength << 8;
+	return 0;
+}
+
+static int fdtv_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct firedtv *fdtv = fe->sec_priv;
+	struct firedtv_tuner_status stat;
+
+	if (avc_tuner_status(fdtv, &stat))
+		return -EINVAL;
+
+	/* C/N[dB] = -10 * log10(snr / 65535) */
+	*snr = stat.carrier_noise_ratio * 257;
+	return 0;
+}
+
+static int fdtv_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	return -EOPNOTSUPP;
+}
+
+static int fdtv_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct firedtv *fdtv = fe->sec_priv;
+
+	return avc_tuner_dsd(fdtv, p);
+}
+
+void fdtv_frontend_init(struct firedtv *fdtv, const char *name)
+{
+	struct dvb_frontend_ops *ops = &fdtv->fe.ops;
+	struct dvb_frontend_info *fi = &ops->info;
+
+	ops->init			= fdtv_dvb_init;
+	ops->sleep			= fdtv_sleep;
+
+	ops->set_frontend		= fdtv_set_frontend;
+
+	ops->read_status		= fdtv_read_status;
+	ops->read_ber			= fdtv_read_ber;
+	ops->read_signal_strength	= fdtv_read_signal_strength;
+	ops->read_snr			= fdtv_read_snr;
+	ops->read_ucblocks		= fdtv_read_uncorrected_blocks;
+
+	ops->diseqc_send_master_cmd 	= fdtv_diseqc_send_master_cmd;
+	ops->diseqc_send_burst		= fdtv_diseqc_send_burst;
+	ops->set_tone			= fdtv_set_tone;
+	ops->set_voltage		= fdtv_set_voltage;
+
+	switch (fdtv->type) {
+	case FIREDTV_DVB_S:
+		ops->delsys[0]		= SYS_DVBS;
+
+		fi->frequency_min	= 950000;
+		fi->frequency_max	= 2150000;
+		fi->frequency_stepsize	= 125;
+		fi->symbol_rate_min	= 1000000;
+		fi->symbol_rate_max	= 40000000;
+
+		fi->caps		= FE_CAN_INVERSION_AUTO |
+					  FE_CAN_FEC_1_2	|
+					  FE_CAN_FEC_2_3	|
+					  FE_CAN_FEC_3_4	|
+					  FE_CAN_FEC_5_6	|
+					  FE_CAN_FEC_7_8	|
+					  FE_CAN_FEC_AUTO	|
+					  FE_CAN_QPSK;
+		break;
+
+	case FIREDTV_DVB_S2:
+		ops->delsys[0]		= SYS_DVBS;
+		ops->delsys[1]		= SYS_DVBS2;
+
+		fi->frequency_min	= 950000;
+		fi->frequency_max	= 2150000;
+		fi->frequency_stepsize	= 125;
+		fi->symbol_rate_min	= 1000000;
+		fi->symbol_rate_max	= 40000000;
+
+		fi->caps		= FE_CAN_INVERSION_AUTO |
+					  FE_CAN_FEC_1_2        |
+					  FE_CAN_FEC_2_3        |
+					  FE_CAN_FEC_3_4        |
+					  FE_CAN_FEC_5_6        |
+					  FE_CAN_FEC_7_8        |
+					  FE_CAN_FEC_AUTO       |
+					  FE_CAN_QPSK           |
+					  FE_CAN_2G_MODULATION;
+		break;
+
+	case FIREDTV_DVB_C:
+		ops->delsys[0]		= SYS_DVBC_ANNEX_A;
+
+		fi->frequency_min	= 47000000;
+		fi->frequency_max	= 866000000;
+		fi->frequency_stepsize	= 62500;
+		fi->symbol_rate_min	= 870000;
+		fi->symbol_rate_max	= 6900000;
+
+		fi->caps 		= FE_CAN_INVERSION_AUTO |
+					  FE_CAN_QAM_16		|
+					  FE_CAN_QAM_32		|
+					  FE_CAN_QAM_64		|
+					  FE_CAN_QAM_128	|
+					  FE_CAN_QAM_256	|
+					  FE_CAN_QAM_AUTO;
+		break;
+
+	case FIREDTV_DVB_T:
+		ops->delsys[0]		= SYS_DVBT;
+
+		fi->frequency_min	= 49000000;
+		fi->frequency_max	= 861000000;
+		fi->frequency_stepsize	= 62500;
+
+		fi->caps 		= FE_CAN_INVERSION_AUTO		|
+					  FE_CAN_FEC_2_3		|
+					  FE_CAN_TRANSMISSION_MODE_AUTO |
+					  FE_CAN_GUARD_INTERVAL_AUTO	|
+					  FE_CAN_HIERARCHY_AUTO;
+		break;
+
+	default:
+		dev_err(fdtv->device, "no frontend for model type %d\n",
+			fdtv->type);
+	}
+	strcpy(fi->name, name);
+
+	fdtv->fe.dvb = &fdtv->adapter;
+	fdtv->fe.sec_priv = fdtv;
+}
diff --git a/drivers/media/firewire/firedtv-fw.c b/drivers/media/firewire/firedtv-fw.c
new file mode 100644
index 0000000..e24ec53
--- /dev/null
+++ b/drivers/media/firewire/firedtv-fw.c
@@ -0,0 +1,429 @@
+/*
+ * FireDTV driver -- firewire I/O backend
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+#include <asm/page.h>
+
+#include <dvb_demux.h>
+
+#include "firedtv.h"
+
+static LIST_HEAD(node_list);
+static DEFINE_SPINLOCK(node_list_lock);
+
+static inline struct fw_device *device_of(struct firedtv *fdtv)
+{
+	return fw_device(fdtv->device->parent);
+}
+
+static int node_req(struct firedtv *fdtv, u64 addr, void *data, size_t len,
+		    int tcode)
+{
+	struct fw_device *device = device_of(fdtv);
+	int rcode, generation = device->generation;
+
+	smp_rmb(); /* node_id vs. generation */
+
+	rcode = fw_run_transaction(device->card, tcode, device->node_id,
+			generation, device->max_speed, addr, data, len);
+
+	return rcode != RCODE_COMPLETE ? -EIO : 0;
+}
+
+int fdtv_lock(struct firedtv *fdtv, u64 addr, void *data)
+{
+	return node_req(fdtv, addr, data, 8, TCODE_LOCK_COMPARE_SWAP);
+}
+
+int fdtv_read(struct firedtv *fdtv, u64 addr, void *data)
+{
+	return node_req(fdtv, addr, data, 4, TCODE_READ_QUADLET_REQUEST);
+}
+
+int fdtv_write(struct firedtv *fdtv, u64 addr, void *data, size_t len)
+{
+	return node_req(fdtv, addr, data, len, TCODE_WRITE_BLOCK_REQUEST);
+}
+
+#define ISO_HEADER_SIZE			4
+#define CIP_HEADER_SIZE			8
+#define MPEG2_TS_HEADER_SIZE		4
+#define MPEG2_TS_SOURCE_PACKET_SIZE	(4 + 188)
+
+#define MAX_PACKET_SIZE		1024  /* 776, rounded up to 2^n */
+#define PACKETS_PER_PAGE	(PAGE_SIZE / MAX_PACKET_SIZE)
+#define N_PACKETS		64    /* buffer size */
+#define N_PAGES			DIV_ROUND_UP(N_PACKETS, PACKETS_PER_PAGE)
+#define IRQ_INTERVAL		16
+
+struct fdtv_ir_context {
+	struct fw_iso_context *context;
+	struct fw_iso_buffer buffer;
+	int interrupt_packet;
+	int current_packet;
+	char *pages[N_PAGES];
+};
+
+static int queue_iso(struct fdtv_ir_context *ctx, int index)
+{
+	struct fw_iso_packet p;
+
+	p.payload_length = MAX_PACKET_SIZE;
+	p.interrupt = !(++ctx->interrupt_packet & (IRQ_INTERVAL - 1));
+	p.skip = 0;
+	p.header_length = ISO_HEADER_SIZE;
+
+	return fw_iso_context_queue(ctx->context, &p, &ctx->buffer,
+				    index * MAX_PACKET_SIZE);
+}
+
+static void handle_iso(struct fw_iso_context *context, u32 cycle,
+		       size_t header_length, void *header, void *data)
+{
+	struct firedtv *fdtv = data;
+	struct fdtv_ir_context *ctx = fdtv->ir_context;
+	__be32 *h, *h_end;
+	int length, err, i = ctx->current_packet;
+	char *p, *p_end;
+
+	for (h = header, h_end = h + header_length / 4; h < h_end; h++) {
+		length = be32_to_cpup(h) >> 16;
+		if (unlikely(length > MAX_PACKET_SIZE)) {
+			dev_err(fdtv->device, "length = %d\n", length);
+			length = MAX_PACKET_SIZE;
+		}
+
+		p = ctx->pages[i / PACKETS_PER_PAGE]
+				+ (i % PACKETS_PER_PAGE) * MAX_PACKET_SIZE;
+		p_end = p + length;
+
+		for (p += CIP_HEADER_SIZE + MPEG2_TS_HEADER_SIZE; p < p_end;
+		     p += MPEG2_TS_SOURCE_PACKET_SIZE)
+			dvb_dmx_swfilter_packets(&fdtv->demux, p, 1);
+
+		err = queue_iso(ctx, i);
+		if (unlikely(err))
+			dev_err(fdtv->device, "requeue failed\n");
+
+		i = (i + 1) & (N_PACKETS - 1);
+	}
+	fw_iso_context_queue_flush(ctx->context);
+	ctx->current_packet = i;
+}
+
+int fdtv_start_iso(struct firedtv *fdtv)
+{
+	struct fdtv_ir_context *ctx;
+	struct fw_device *device = device_of(fdtv);
+	int i, err;
+
+	ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->context = fw_iso_context_create(device->card,
+			FW_ISO_CONTEXT_RECEIVE, fdtv->isochannel,
+			device->max_speed, ISO_HEADER_SIZE, handle_iso, fdtv);
+	if (IS_ERR(ctx->context)) {
+		err = PTR_ERR(ctx->context);
+		goto fail_free;
+	}
+
+	err = fw_iso_buffer_init(&ctx->buffer, device->card,
+				 N_PAGES, DMA_FROM_DEVICE);
+	if (err)
+		goto fail_context_destroy;
+
+	ctx->interrupt_packet = 0;
+	ctx->current_packet = 0;
+
+	for (i = 0; i < N_PAGES; i++)
+		ctx->pages[i] = page_address(ctx->buffer.pages[i]);
+
+	for (i = 0; i < N_PACKETS; i++) {
+		err = queue_iso(ctx, i);
+		if (err)
+			goto fail;
+	}
+
+	err = fw_iso_context_start(ctx->context, -1, 0,
+				   FW_ISO_CONTEXT_MATCH_ALL_TAGS);
+	if (err)
+		goto fail;
+
+	fdtv->ir_context = ctx;
+
+	return 0;
+fail:
+	fw_iso_buffer_destroy(&ctx->buffer, device->card);
+fail_context_destroy:
+	fw_iso_context_destroy(ctx->context);
+fail_free:
+	kfree(ctx);
+
+	return err;
+}
+
+void fdtv_stop_iso(struct firedtv *fdtv)
+{
+	struct fdtv_ir_context *ctx = fdtv->ir_context;
+
+	fw_iso_context_stop(ctx->context);
+	fw_iso_buffer_destroy(&ctx->buffer, device_of(fdtv)->card);
+	fw_iso_context_destroy(ctx->context);
+	kfree(ctx);
+}
+
+static void handle_fcp(struct fw_card *card, struct fw_request *request,
+		       int tcode, int destination, int source, int generation,
+		       unsigned long long offset, void *payload, size_t length,
+		       void *callback_data)
+{
+	struct firedtv *f, *fdtv = NULL;
+	struct fw_device *device;
+	unsigned long flags;
+	int su;
+
+	if (length < 2 || (((u8 *)payload)[0] & 0xf0) != 0)
+		return;
+
+	su = ((u8 *)payload)[1] & 0x7;
+
+	spin_lock_irqsave(&node_list_lock, flags);
+	list_for_each_entry(f, &node_list, list) {
+		device = device_of(f);
+		if (device->generation != generation)
+			continue;
+
+		smp_rmb(); /* node_id vs. generation */
+
+		if (device->card == card &&
+		    device->node_id == source &&
+		    (f->subunit == su || (f->subunit == 0 && su == 0x7))) {
+			fdtv = f;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&node_list_lock, flags);
+
+	if (fdtv)
+		avc_recv(fdtv, payload, length);
+}
+
+static struct fw_address_handler fcp_handler = {
+	.length           = CSR_FCP_END - CSR_FCP_RESPONSE,
+	.address_callback = handle_fcp,
+};
+
+static const struct fw_address_region fcp_region = {
+	.start	= CSR_REGISTER_BASE + CSR_FCP_RESPONSE,
+	.end	= CSR_REGISTER_BASE + CSR_FCP_END,
+};
+
+static const char * const model_names[] = {
+	[FIREDTV_UNKNOWN] = "unknown type",
+	[FIREDTV_DVB_S]   = "FireDTV S/CI",
+	[FIREDTV_DVB_C]   = "FireDTV C/CI",
+	[FIREDTV_DVB_T]   = "FireDTV T/CI",
+	[FIREDTV_DVB_S2]  = "FireDTV S2  ",
+};
+
+/* Adjust the template string if models with longer names appear. */
+#define MAX_MODEL_NAME_LEN sizeof("FireDTV ????")
+
+static int node_probe(struct device *dev)
+{
+	struct firedtv *fdtv;
+	char name[MAX_MODEL_NAME_LEN];
+	int name_len, i, err;
+
+	fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL);
+	if (!fdtv)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, fdtv);
+	fdtv->device		= dev;
+	fdtv->isochannel	= -1;
+	fdtv->voltage		= 0xff;
+	fdtv->tone		= 0xff;
+
+	mutex_init(&fdtv->avc_mutex);
+	init_waitqueue_head(&fdtv->avc_wait);
+	mutex_init(&fdtv->demux_mutex);
+	INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work);
+
+	name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL,
+				 name, sizeof(name));
+	for (i = ARRAY_SIZE(model_names); --i; )
+		if (strlen(model_names[i]) <= name_len &&
+		    strncmp(name, model_names[i], name_len) == 0)
+			break;
+	fdtv->type = i;
+
+	err = fdtv_register_rc(fdtv, dev);
+	if (err)
+		goto fail_free;
+
+	spin_lock_irq(&node_list_lock);
+	list_add_tail(&fdtv->list, &node_list);
+	spin_unlock_irq(&node_list_lock);
+
+	err = avc_identify_subunit(fdtv);
+	if (err)
+		goto fail;
+
+	err = fdtv_dvb_register(fdtv, model_names[fdtv->type]);
+	if (err)
+		goto fail;
+
+	avc_register_remote_control(fdtv);
+
+	return 0;
+fail:
+	spin_lock_irq(&node_list_lock);
+	list_del(&fdtv->list);
+	spin_unlock_irq(&node_list_lock);
+	fdtv_unregister_rc(fdtv);
+fail_free:
+	kfree(fdtv);
+
+	return err;
+}
+
+static int node_remove(struct device *dev)
+{
+	struct firedtv *fdtv = dev_get_drvdata(dev);
+
+	fdtv_dvb_unregister(fdtv);
+
+	spin_lock_irq(&node_list_lock);
+	list_del(&fdtv->list);
+	spin_unlock_irq(&node_list_lock);
+
+	fdtv_unregister_rc(fdtv);
+
+	kfree(fdtv);
+	return 0;
+}
+
+static void node_update(struct fw_unit *unit)
+{
+	struct firedtv *fdtv = dev_get_drvdata(&unit->device);
+
+	if (fdtv->isochannel >= 0)
+		cmp_establish_pp_connection(fdtv, fdtv->subunit,
+					    fdtv->isochannel);
+}
+
+#define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \
+		     IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION)
+
+#define DIGITAL_EVERYWHERE_OUI	0x001287
+#define AVC_UNIT_SPEC_ID_ENTRY	0x00a02d
+#define AVC_SW_VERSION_ENTRY	0x010001
+
+static const struct ieee1394_device_id fdtv_id_table[] = {
+	{
+		/* FloppyDTV S/CI and FloppyDTV S2 */
+		.match_flags	= MATCH_FLAGS,
+		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
+		.model_id	= 0x000024,
+		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
+		.version	= AVC_SW_VERSION_ENTRY,
+	}, {
+		/* FloppyDTV T/CI */
+		.match_flags	= MATCH_FLAGS,
+		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
+		.model_id	= 0x000025,
+		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
+		.version	= AVC_SW_VERSION_ENTRY,
+	}, {
+		/* FloppyDTV C/CI */
+		.match_flags	= MATCH_FLAGS,
+		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
+		.model_id	= 0x000026,
+		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
+		.version	= AVC_SW_VERSION_ENTRY,
+	}, {
+		/* FireDTV S/CI and FloppyDTV S2 */
+		.match_flags	= MATCH_FLAGS,
+		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
+		.model_id	= 0x000034,
+		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
+		.version	= AVC_SW_VERSION_ENTRY,
+	}, {
+		/* FireDTV T/CI */
+		.match_flags	= MATCH_FLAGS,
+		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
+		.model_id	= 0x000035,
+		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
+		.version	= AVC_SW_VERSION_ENTRY,
+	}, {
+		/* FireDTV C/CI */
+		.match_flags	= MATCH_FLAGS,
+		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
+		.model_id	= 0x000036,
+		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
+		.version	= AVC_SW_VERSION_ENTRY,
+	}, {}
+};
+MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table);
+
+static struct fw_driver fdtv_driver = {
+	.driver   = {
+		.owner  = THIS_MODULE,
+		.name   = "firedtv",
+		.bus    = &fw_bus_type,
+		.probe  = node_probe,
+		.remove = node_remove,
+	},
+	.update   = node_update,
+	.id_table = fdtv_id_table,
+};
+
+static int __init fdtv_init(void)
+{
+	int ret;
+
+	ret = fw_core_add_address_handler(&fcp_handler, &fcp_region);
+	if (ret < 0)
+		return ret;
+
+	ret = driver_register(&fdtv_driver.driver);
+	if (ret < 0)
+		fw_core_remove_address_handler(&fcp_handler);
+
+	return ret;
+}
+
+static void __exit fdtv_exit(void)
+{
+	driver_unregister(&fdtv_driver.driver);
+	fw_core_remove_address_handler(&fcp_handler);
+}
+
+module_init(fdtv_init);
+module_exit(fdtv_exit);
+
+MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
+MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
+MODULE_DESCRIPTION("FireDTV DVB Driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("FireDTV DVB");
diff --git a/drivers/media/firewire/firedtv-rc.c b/drivers/media/firewire/firedtv-rc.c
new file mode 100644
index 0000000..f82d4a9
--- /dev/null
+++ b/drivers/media/firewire/firedtv-rc.c
@@ -0,0 +1,196 @@
+/*
+ * FireDTV driver (formerly known as FireSAT)
+ *
+ * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation; either version 2 of
+ *	the License, or (at your option) any later version.
+ */
+
+#include <linux/bitops.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+#include "firedtv.h"
+
+/* fixed table with older keycodes, geared towards MythTV */
+static const u16 oldtable[] = {
+
+	/* code from device: 0x4501...0x451f */
+
+	KEY_ESC,
+	KEY_F9,
+	KEY_1,
+	KEY_2,
+	KEY_3,
+	KEY_4,
+	KEY_5,
+	KEY_6,
+	KEY_7,
+	KEY_8,
+	KEY_9,
+	KEY_I,
+	KEY_0,
+	KEY_ENTER,
+	KEY_RED,
+	KEY_UP,
+	KEY_GREEN,
+	KEY_F10,
+	KEY_SPACE,
+	KEY_F11,
+	KEY_YELLOW,
+	KEY_DOWN,
+	KEY_BLUE,
+	KEY_Z,
+	KEY_P,
+	KEY_PAGEDOWN,
+	KEY_LEFT,
+	KEY_W,
+	KEY_RIGHT,
+	KEY_P,
+	KEY_M,
+
+	/* code from device: 0x4540...0x4542 */
+
+	KEY_R,
+	KEY_V,
+	KEY_C,
+};
+
+/* user-modifiable table for a remote as sold in 2008 */
+static const u16 keytable[] = {
+
+	/* code from device: 0x0300...0x031f */
+
+	[0x00] = KEY_POWER,
+	[0x01] = KEY_SLEEP,
+	[0x02] = KEY_STOP,
+	[0x03] = KEY_OK,
+	[0x04] = KEY_RIGHT,
+	[0x05] = KEY_1,
+	[0x06] = KEY_2,
+	[0x07] = KEY_3,
+	[0x08] = KEY_LEFT,
+	[0x09] = KEY_4,
+	[0x0a] = KEY_5,
+	[0x0b] = KEY_6,
+	[0x0c] = KEY_UP,
+	[0x0d] = KEY_7,
+	[0x0e] = KEY_8,
+	[0x0f] = KEY_9,
+	[0x10] = KEY_DOWN,
+	[0x11] = KEY_TITLE,	/* "OSD" - fixme */
+	[0x12] = KEY_0,
+	[0x13] = KEY_F20,	/* "16:9" - fixme */
+	[0x14] = KEY_SCREEN,	/* "FULL" - fixme */
+	[0x15] = KEY_MUTE,
+	[0x16] = KEY_SUBTITLE,
+	[0x17] = KEY_RECORD,
+	[0x18] = KEY_TEXT,
+	[0x19] = KEY_AUDIO,
+	[0x1a] = KEY_RED,
+	[0x1b] = KEY_PREVIOUS,
+	[0x1c] = KEY_REWIND,
+	[0x1d] = KEY_PLAYPAUSE,
+	[0x1e] = KEY_NEXT,
+	[0x1f] = KEY_VOLUMEUP,
+
+	/* code from device: 0x0340...0x0354 */
+
+	[0x20] = KEY_CHANNELUP,
+	[0x21] = KEY_F21,	/* "4:3" - fixme */
+	[0x22] = KEY_TV,
+	[0x23] = KEY_DVD,
+	[0x24] = KEY_VCR,
+	[0x25] = KEY_AUX,
+	[0x26] = KEY_GREEN,
+	[0x27] = KEY_YELLOW,
+	[0x28] = KEY_BLUE,
+	[0x29] = KEY_CHANNEL,	/* "CH.LIST" */
+	[0x2a] = KEY_VENDOR,	/* "CI" - fixme */
+	[0x2b] = KEY_VOLUMEDOWN,
+	[0x2c] = KEY_CHANNELDOWN,
+	[0x2d] = KEY_LAST,
+	[0x2e] = KEY_INFO,
+	[0x2f] = KEY_FORWARD,
+	[0x30] = KEY_LIST,
+	[0x31] = KEY_FAVORITES,
+	[0x32] = KEY_MENU,
+	[0x33] = KEY_EPG,
+	[0x34] = KEY_EXIT,
+};
+
+int fdtv_register_rc(struct firedtv *fdtv, struct device *dev)
+{
+	struct input_dev *idev;
+	int i, err;
+
+	idev = input_allocate_device();
+	if (!idev)
+		return -ENOMEM;
+
+	fdtv->remote_ctrl_dev = idev;
+	idev->name = "FireDTV remote control";
+	idev->dev.parent = dev;
+	idev->evbit[0] = BIT_MASK(EV_KEY);
+	idev->keycode = kmemdup(keytable, sizeof(keytable), GFP_KERNEL);
+	if (!idev->keycode) {
+		err = -ENOMEM;
+		goto fail;
+	}
+	idev->keycodesize = sizeof(keytable[0]);
+	idev->keycodemax = ARRAY_SIZE(keytable);
+
+	for (i = 0; i < ARRAY_SIZE(keytable); i++)
+		set_bit(keytable[i], idev->keybit);
+
+	err = input_register_device(idev);
+	if (err)
+		goto fail_free_keymap;
+
+	return 0;
+
+fail_free_keymap:
+	kfree(idev->keycode);
+fail:
+	input_free_device(idev);
+	return err;
+}
+
+void fdtv_unregister_rc(struct firedtv *fdtv)
+{
+	cancel_work_sync(&fdtv->remote_ctrl_work);
+	kfree(fdtv->remote_ctrl_dev->keycode);
+	input_unregister_device(fdtv->remote_ctrl_dev);
+}
+
+void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code)
+{
+	struct input_dev *idev = fdtv->remote_ctrl_dev;
+	u16 *keycode = idev->keycode;
+
+	if (code >= 0x0300 && code <= 0x031f)
+		code = keycode[code - 0x0300];
+	else if (code >= 0x0340 && code <= 0x0354)
+		code = keycode[code - 0x0320];
+	else if (code >= 0x4501 && code <= 0x451f)
+		code = oldtable[code - 0x4501];
+	else if (code >= 0x4540 && code <= 0x4542)
+		code = oldtable[code - 0x4521];
+	else {
+		printk(KERN_DEBUG "firedtv: invalid key code 0x%04x "
+		       "from remote control\n", code);
+		return;
+	}
+
+	input_report_key(idev, code, 1);
+	input_sync(idev);
+	input_report_key(idev, code, 0);
+	input_sync(idev);
+}
diff --git a/drivers/media/firewire/firedtv.h b/drivers/media/firewire/firedtv.h
new file mode 100644
index 0000000..4fdcd8c
--- /dev/null
+++ b/drivers/media/firewire/firedtv.h
@@ -0,0 +1,168 @@
+/*
+ * FireDTV driver (formerly known as FireSAT)
+ *
+ * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
+ * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
+ *
+ *	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.
+ */
+
+#ifndef _FIREDTV_H
+#define _FIREDTV_H
+
+#include <linux/dvb/dmx.h>
+#include <linux/dvb/frontend.h>
+#include <linux/list.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/spinlock_types.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+#include <demux.h>
+#include <dmxdev.h>
+#include <dvb_demux.h>
+#include <dvb_frontend.h>
+#include <dvb_net.h>
+#include <dvbdev.h>
+
+struct firedtv_tuner_status {
+	unsigned active_system:8;
+	unsigned searching:1;
+	unsigned moving:1;
+	unsigned no_rf:1;
+	unsigned input:1;
+	unsigned selected_antenna:7;
+	unsigned ber:32;
+	unsigned signal_strength:8;
+	unsigned raster_frequency:2;
+	unsigned rf_frequency:22;
+	unsigned man_dep_info_length:8;
+	unsigned front_end_error:1;
+	unsigned antenna_error:1;
+	unsigned front_end_power_status:1;
+	unsigned power_supply:1;
+	unsigned carrier_noise_ratio:16;
+	unsigned power_supply_voltage:8;
+	unsigned antenna_voltage:8;
+	unsigned firewire_bus_voltage:8;
+	unsigned ca_mmi:1;
+	unsigned ca_pmt_reply:1;
+	unsigned ca_date_time_request:1;
+	unsigned ca_application_info:1;
+	unsigned ca_module_present_status:1;
+	unsigned ca_dvb_flag:1;
+	unsigned ca_error_flag:1;
+	unsigned ca_initialization_status:1;
+};
+
+enum model_type {
+	FIREDTV_UNKNOWN = 0,
+	FIREDTV_DVB_S   = 1,
+	FIREDTV_DVB_C   = 2,
+	FIREDTV_DVB_T   = 3,
+	FIREDTV_DVB_S2  = 4,
+};
+
+struct device;
+struct input_dev;
+struct fdtv_ir_context;
+
+struct firedtv {
+	struct device *device;
+	struct list_head list;
+
+	struct dvb_adapter	adapter;
+	struct dmxdev		dmxdev;
+	struct dvb_demux	demux;
+	struct dmx_frontend	frontend;
+	struct dvb_net		dvbnet;
+	struct dvb_frontend	fe;
+
+	struct dvb_device	*cadev;
+	int			ca_last_command;
+	int			ca_time_interval;
+
+	struct mutex		avc_mutex;
+	wait_queue_head_t	avc_wait;
+	bool			avc_reply_received;
+	struct work_struct	remote_ctrl_work;
+	struct input_dev	*remote_ctrl_dev;
+
+	enum model_type		type;
+	char			subunit;
+	char			isochannel;
+	struct fdtv_ir_context	*ir_context;
+
+	fe_sec_voltage_t	voltage;
+	fe_sec_tone_mode_t	tone;
+
+	struct mutex		demux_mutex;
+	unsigned long		channel_active;
+	u16			channel_pid[16];
+
+	int			avc_data_length;
+	u8			avc_data[512];
+};
+
+/* firedtv-avc.c */
+int avc_recv(struct firedtv *fdtv, void *data, size_t length);
+int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat);
+struct dtv_frontend_properties;
+int avc_tuner_dsd(struct firedtv *fdtv, struct dtv_frontend_properties *params);
+int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]);
+int avc_tuner_get_ts(struct firedtv *fdtv);
+int avc_identify_subunit(struct firedtv *fdtv);
+struct dvb_diseqc_master_cmd;
+int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
+		    char conttone, char nrdiseq,
+		    struct dvb_diseqc_master_cmd *diseqcmd);
+void avc_remote_ctrl_work(struct work_struct *work);
+int avc_register_remote_control(struct firedtv *fdtv);
+int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
+int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
+int avc_ca_reset(struct firedtv *fdtv);
+int avc_ca_pmt(struct firedtv *fdtv, char *app_info, int length);
+int avc_ca_get_time_date(struct firedtv *fdtv, int *interval);
+int avc_ca_enter_menu(struct firedtv *fdtv);
+int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len);
+int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel);
+void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel);
+
+/* firedtv-ci.c */
+int fdtv_ca_register(struct firedtv *fdtv);
+void fdtv_ca_release(struct firedtv *fdtv);
+
+/* firedtv-dvb.c */
+int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed);
+int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed);
+int fdtv_dvb_register(struct firedtv *fdtv, const char *name);
+void fdtv_dvb_unregister(struct firedtv *fdtv);
+
+/* firedtv-fe.c */
+void fdtv_frontend_init(struct firedtv *fdtv, const char *name);
+
+/* firedtv-fw.c */
+int fdtv_lock(struct firedtv *fdtv, u64 addr, void *data);
+int fdtv_read(struct firedtv *fdtv, u64 addr, void *data);
+int fdtv_write(struct firedtv *fdtv, u64 addr, void *data, size_t len);
+int fdtv_start_iso(struct firedtv *fdtv);
+void fdtv_stop_iso(struct firedtv *fdtv);
+
+/* firedtv-rc.c */
+#ifdef CONFIG_DVB_FIREDTV_INPUT
+int fdtv_register_rc(struct firedtv *fdtv, struct device *dev);
+void fdtv_unregister_rc(struct firedtv *fdtv);
+void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code);
+#else
+static inline int fdtv_register_rc(struct firedtv *fdtv,
+				   struct device *dev) { return 0; }
+static inline void fdtv_unregister_rc(struct firedtv *fdtv) {}
+static inline void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code) {}
+#endif
+
+#endif /* _FIREDTV_H */
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
new file mode 100644
index 0000000..7fe4acf
--- /dev/null
+++ b/drivers/media/i2c/Kconfig
@@ -0,0 +1,570 @@
+#
+# Generic video config states
+#
+
+config VIDEO_BTCX
+	depends on PCI
+	tristate
+
+config VIDEO_TVEEPROM
+	tristate
+	depends on I2C
+
+#
+# Multimedia Video device configuration
+#
+
+if VIDEO_V4L2
+
+config VIDEO_HELPER_CHIPS_AUTO
+	bool "Autoselect pertinent encoders/decoders and other helper chips"
+	default y if !EXPERT
+	---help---
+	  Most video cards may require additional modules to encode or
+	  decode audio/video standards. This option will autoselect
+	  all pertinent modules to each selected video module.
+
+	  Unselect this only if you know exactly what you are doing, since
+	  it may break support on some boards.
+
+	  In doubt, say Y.
+
+config VIDEO_IR_I2C
+	tristate "I2C module for IR" if !VIDEO_HELPER_CHIPS_AUTO
+	depends on I2C && RC_CORE
+	default y
+	---help---
+	  Most boards have an IR chip directly connected via GPIO. However,
+	  some video boards have the IR connected via I2C bus.
+
+	  If your board doesn't have an I2C IR chip, you may disable this
+	  option.
+
+	  In doubt, say Y.
+
+#
+# Encoder / Decoder module configuration
+#
+
+menu "Encoders, decoders, sensors and other helper chips"
+	visible if !VIDEO_HELPER_CHIPS_AUTO
+
+comment "Audio decoders, processors and mixers"
+
+config VIDEO_TVAUDIO
+	tristate "Simple audio decoder chips"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for several audio decoder chips found on some bt8xx boards:
+	  Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300,
+		   tea6320, tea6420, tda8425, ta8874z.
+	  Microchip: pic16c54 based design on ProVideo PV951 board.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tvaudio.
+
+config VIDEO_TDA7432
+	tristate "Philips TDA7432 audio processor"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for tda7432 audio decoder chip found on some bt8xx boards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tda7432.
+
+config VIDEO_TDA9840
+	tristate "Philips TDA9840 audio processor"
+	depends on I2C
+	---help---
+	  Support for tda9840 audio decoder chip found on some Zoran boards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tda9840.
+
+config VIDEO_TEA6415C
+	tristate "Philips TEA6415C audio processor"
+	depends on I2C
+	---help---
+	  Support for tea6415c audio decoder chip found on some bt8xx boards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tea6415c.
+
+config VIDEO_TEA6420
+	tristate "Philips TEA6420 audio processor"
+	depends on I2C
+	---help---
+	  Support for tea6420 audio decoder chip found on some bt8xx boards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tea6420.
+
+config VIDEO_MSP3400
+	tristate "Micronas MSP34xx audio decoders"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Micronas MSP34xx series of audio decoders.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called msp3400.
+
+config VIDEO_CS5345
+	tristate "Cirrus Logic CS5345 audio ADC"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Cirrus Logic CS5345 24-bit, 192 kHz
+	  stereo A/D converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cs5345.
+
+config VIDEO_CS53L32A
+	tristate "Cirrus Logic CS53L32A audio ADC"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Cirrus Logic CS53L32A low voltage
+	  stereo A/D converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cs53l32a.
+
+config VIDEO_TLV320AIC23B
+	tristate "Texas Instruments TLV320AIC23B audio codec"
+	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	---help---
+	  Support for the Texas Instruments TLV320AIC23B audio codec.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tlv320aic23b.
+
+config VIDEO_WM8775
+	tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Wolfson Microelectronics WM8775 high
+	  performance stereo A/D Converter with a 4 channel input mixer.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called wm8775.
+
+config VIDEO_WM8739
+	tristate "Wolfson Microelectronics WM8739 stereo audio ADC"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Wolfson Microelectronics WM8739
+	  stereo A/D Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called wm8739.
+
+config VIDEO_VP27SMPX
+	tristate "Panasonic VP27s internal MPX"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the internal MPX of the Panasonic VP27s tuner.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vp27smpx.
+
+comment "RDS decoders"
+
+config VIDEO_SAA6588
+	tristate "SAA6588 Radio Chip RDS decoder support"
+	depends on VIDEO_V4L2 && I2C
+
+	help
+	  Support for this Radio Data System (RDS) decoder. This allows
+	  seeing radio station identification transmitted using this
+	  standard.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa6588.
+
+comment "Video decoders"
+
+config VIDEO_ADV7180
+	tristate "Analog Devices ADV7180 decoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Analog Devices ADV7180 video decoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adv7180.
+
+config VIDEO_ADV7183
+	tristate "Analog Devices ADV7183 decoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  V4l2 subdevice driver for the Analog Devices
+	  ADV7183 video decoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adv7183.
+
+config VIDEO_BT819
+	tristate "BT819A VideoStream decoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for BT819A video decoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bt819.
+
+config VIDEO_BT856
+	tristate "BT856 VideoStream decoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for BT856 video decoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bt856.
+
+config VIDEO_BT866
+	tristate "BT866 VideoStream decoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for BT866 video decoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bt866.
+
+config VIDEO_KS0127
+	tristate "KS0127 video decoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for KS0127 video decoder.
+
+	  This chip is used on AverMedia AVS6EYES Zoran-based MJPEG
+	  cards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ks0127.
+
+config VIDEO_SAA7110
+	tristate "Philips SAA7110 video decoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Philips SAA7110 video decoders.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7110.
+
+config VIDEO_SAA711X
+	tristate "Philips SAA7111/3/4/5 video decoders"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Philips SAA7111/3/4/5 video decoders.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7115.
+
+config VIDEO_SAA7191
+	tristate "Philips SAA7191 video decoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Philips SAA7191 video decoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7191.
+
+config VIDEO_TVP514X
+	tristate "Texas Instruments TVP514x video decoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  This is a Video4Linux2 sensor-level driver for the TI TVP5146/47
+	  decoder. It is currently working with the TI OMAP3 camera
+	  controller.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tvp514x.
+
+config VIDEO_TVP5150
+	tristate "Texas Instruments TVP5150 video decoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Texas Instruments TVP5150 video decoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tvp5150.
+
+config VIDEO_TVP7002
+	tristate "Texas Instruments TVP7002 video decoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Texas Instruments TVP7002 video decoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tvp7002.
+
+config VIDEO_VPX3220
+	tristate "vpx3220a, vpx3216b & vpx3214c video decoders"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for VPX322x video decoders.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vpx3220.
+
+comment "Video and audio decoders"
+
+config VIDEO_SAA717X
+	tristate "Philips SAA7171/3/4 audio/video decoders"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Philips SAA7171/3/4 audio/video decoders.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa717x.
+
+source "drivers/media/i2c/cx25840/Kconfig"
+
+comment "MPEG video encoders"
+
+config VIDEO_CX2341X
+	tristate "Conexant CX2341x MPEG encoders"
+	depends on VIDEO_V4L2 && VIDEO_V4L2_COMMON
+	---help---
+	  Support for the Conexant CX23416 MPEG encoders
+	  and CX23415 MPEG encoder/decoders.
+
+	  This module currently supports the encoding functions only.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx2341x.
+
+comment "Video encoders"
+
+config VIDEO_SAA7127
+	tristate "Philips SAA7127/9 digital video encoders"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Philips SAA7127/9 digital video encoders.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7127.
+
+config VIDEO_SAA7185
+	tristate "Philips SAA7185 video encoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Philips SAA7185 video encoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7185.
+
+config VIDEO_ADV7170
+	tristate "Analog Devices ADV7170 video encoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Analog Devices ADV7170 video encoder driver
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adv7170.
+
+config VIDEO_ADV7175
+	tristate "Analog Devices ADV7175 video encoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Analog Devices ADV7175 video encoder driver
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adv7175.
+
+config VIDEO_ADV7343
+	tristate "ADV7343 video encoder"
+	depends on I2C
+	help
+	  Support for Analog Devices I2C bus based ADV7343 encoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adv7343.
+
+config VIDEO_ADV7393
+	tristate "ADV7393 video encoder"
+	depends on I2C
+	help
+	  Support for Analog Devices I2C bus based ADV7393 encoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adv7393.
+
+config VIDEO_AK881X
+	tristate "AK8813/AK8814 video encoders"
+	depends on I2C
+	help
+	  Video output driver for AKM AK8813 and AK8814 TV encoders
+
+comment "Camera sensor devices"
+
+config VIDEO_APTINA_PLL
+	tristate
+
+config VIDEO_SMIAPP_PLL
+	tristate
+
+config VIDEO_OV7670
+	tristate "OmniVision OV7670 sensor support"
+	depends on I2C && VIDEO_V4L2
+	depends on MEDIA_CAMERA_SUPPORT
+	---help---
+	  This is a Video4Linux2 sensor-level driver for the OmniVision
+	  OV7670 VGA camera.  It currently only works with the M88ALP01
+	  controller.
+
+config VIDEO_VS6624
+	tristate "ST VS6624 sensor support"
+	depends on VIDEO_V4L2 && I2C
+	depends on MEDIA_CAMERA_SUPPORT
+	---help---
+	  This is a Video4Linux2 sensor-level driver for the ST VS6624
+	  camera.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vs6624.
+
+config VIDEO_MT9M032
+	tristate "MT9M032 camera sensor support"
+	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+	depends on MEDIA_CAMERA_SUPPORT
+	select VIDEO_APTINA_PLL
+	---help---
+	  This driver supports MT9M032 camera sensors from Aptina, monochrome
+	  models only.
+
+config VIDEO_MT9P031
+	tristate "Aptina MT9P031 support"
+	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+	depends on MEDIA_CAMERA_SUPPORT
+	select VIDEO_APTINA_PLL
+	---help---
+	  This is a Video4Linux2 sensor-level driver for the Aptina
+	  (Micron) mt9p031 5 Mpixel camera.
+
+config VIDEO_MT9T001
+	tristate "Aptina MT9T001 support"
+	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+	depends on MEDIA_CAMERA_SUPPORT
+	---help---
+	  This is a Video4Linux2 sensor-level driver for the Aptina
+	  (Micron) mt0t001 3 Mpixel camera.
+
+config VIDEO_MT9V011
+	tristate "Micron mt9v011 sensor support"
+	depends on I2C && VIDEO_V4L2
+	depends on MEDIA_CAMERA_SUPPORT
+	---help---
+	  This is a Video4Linux2 sensor-level driver for the Micron
+	  mt0v011 1.3 Mpixel camera.  It currently only works with the
+	  em28xx driver.
+
+config VIDEO_MT9V032
+	tristate "Micron MT9V032 sensor support"
+	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+	depends on MEDIA_CAMERA_SUPPORT
+	---help---
+	  This is a Video4Linux2 sensor-level driver for the Micron
+	  MT9V032 752x480 CMOS sensor.
+
+config VIDEO_TCM825X
+	tristate "TCM825x camera sensor support"
+	depends on I2C && VIDEO_V4L2
+	depends on MEDIA_CAMERA_SUPPORT
+	---help---
+	  This is a driver for the Toshiba TCM825x VGA camera sensor.
+	  It is used for example in Nokia N800.
+
+config VIDEO_SR030PC30
+	tristate "Siliconfile SR030PC30 sensor support"
+	depends on I2C && VIDEO_V4L2
+	depends on MEDIA_CAMERA_SUPPORT
+	---help---
+	  This driver supports SR030PC30 VGA camera from Siliconfile
+
+config VIDEO_NOON010PC30
+	tristate "Siliconfile NOON010PC30 sensor support"
+	depends on I2C && VIDEO_V4L2 && EXPERIMENTAL && VIDEO_V4L2_SUBDEV_API
+	depends on MEDIA_CAMERA_SUPPORT
+	---help---
+	  This driver supports NOON010PC30 CIF camera from Siliconfile
+
+source "drivers/media/i2c/m5mols/Kconfig"
+
+config VIDEO_S5K6AA
+	tristate "Samsung S5K6AAFX sensor support"
+	depends on MEDIA_CAMERA_SUPPORT
+	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+	---help---
+	  This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M
+	  camera sensor with an embedded SoC image signal processor.
+
+source "drivers/media/i2c/smiapp/Kconfig"
+
+comment "Flash devices"
+
+config VIDEO_ADP1653
+	tristate "ADP1653 flash support"
+	depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER
+	depends on MEDIA_CAMERA_SUPPORT
+	---help---
+	  This is a driver for the ADP1653 flash controller. It is used for
+	  example in Nokia N900.
+
+config VIDEO_AS3645A
+	tristate "AS3645A flash driver support"
+	depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER
+	depends on MEDIA_CAMERA_SUPPORT
+	---help---
+	  This is a driver for the AS3645A and LM3555 flash controllers. It has
+	  build in control for flash, torch and indicator LEDs.
+
+comment "Video improvement chips"
+
+config VIDEO_UPD64031A
+	tristate "NEC Electronics uPD64031A Ghost Reduction"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the NEC Electronics uPD64031A Ghost Reduction
+	  video chip. It is most often found in NTSC TV cards made for
+	  Japan and is used to reduce the 'ghosting' effect that can
+	  be present in analog TV broadcasts.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called upd64031a.
+
+config VIDEO_UPD64083
+	tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the NEC Electronics uPD64083 3-Dimensional Y/C
+	  separation video chip. It is used to improve the quality of
+	  the colors of a composite signal.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called upd64083.
+
+comment "Miscelaneous helper chips"
+
+config VIDEO_THS7303
+	tristate "THS7303 Video Amplifier"
+	depends on I2C
+	help
+	  Support for TI THS7303 video amplifier
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ths7303.
+
+config VIDEO_M52790
+	tristate "Mitsubishi M52790 A/V switch"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	 Support for the Mitsubishi M52790 A/V switch.
+
+	 To compile this driver as a module, choose M here: the
+	 module will be called m52790.
+
+if SOC_CAMERA
+	source "drivers/media/i2c/soc_camera/Kconfig"
+endif
+
+endmenu
+endif
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
new file mode 100644
index 0000000..088a460
--- /dev/null
+++ b/drivers/media/i2c/Makefile
@@ -0,0 +1,64 @@
+msp3400-objs	:=	msp3400-driver.o msp3400-kthreads.o
+obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
+
+obj-$(CONFIG_VIDEO_SMIAPP)	+= smiapp/
+obj-$(CONFIG_VIDEO_CX25840) += cx25840/
+obj-$(CONFIG_VIDEO_M5MOLS)	+= m5mols/
+obj-y				+= soc_camera/
+
+obj-$(CONFIG_VIDEO_APTINA_PLL) += aptina-pll.o
+obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
+obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
+obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
+obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
+obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
+obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
+obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o
+obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
+obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o
+obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
+obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
+obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
+obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o
+obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o
+obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o
+obj-$(CONFIG_VIDEO_ADV7183) += adv7183.o
+obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o
+obj-$(CONFIG_VIDEO_ADV7393) += adv7393.o
+obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
+obj-$(CONFIG_VIDEO_VS6624)  += vs6624.o
+obj-$(CONFIG_VIDEO_BT819) += bt819.o
+obj-$(CONFIG_VIDEO_BT856) += bt856.o
+obj-$(CONFIG_VIDEO_BT866) += bt866.o
+obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
+obj-$(CONFIG_VIDEO_THS7303) += ths7303.o
+obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
+obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
+obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o
+obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
+obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+obj-$(CONFIG_VIDEO_M52790) += m52790.o
+obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
+obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
+obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
+obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
+obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
+obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
+obj-$(CONFIG_VIDEO_OV7670) 	+= ov7670.o
+obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
+obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
+obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
+obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o
+obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o
+obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
+obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
+obj-$(CONFIG_VIDEO_SR030PC30)	+= sr030pc30.o
+obj-$(CONFIG_VIDEO_NOON010PC30)	+= noon010pc30.o
+obj-$(CONFIG_VIDEO_S5K6AA)	+= s5k6aa.o
+obj-$(CONFIG_VIDEO_ADP1653)	+= adp1653.o
+obj-$(CONFIG_VIDEO_AS3645A)	+= as3645a.o
+obj-$(CONFIG_VIDEO_SMIAPP_PLL)	+= smiapp-pll.o
+obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
+obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
+obj-$(CONFIG_VIDEO_AK881X)		+= ak881x.o
+obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c
new file mode 100644
index 0000000..18a38b3
--- /dev/null
+++ b/drivers/media/i2c/adp1653.c
@@ -0,0 +1,487 @@
+/*
+ * drivers/media/i2c/adp1653.c
+ *
+ * Copyright (C) 2008--2011 Nokia Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * Contributors:
+ *	Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *	Tuukka Toivonen <tuukkat76@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * TODO:
+ * - fault interrupt handling
+ * - hardware strobe
+ * - power doesn't need to be ON if all lights are off
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <media/adp1653.h>
+#include <media/v4l2-device.h>
+
+#define TIMEOUT_MAX		820000
+#define TIMEOUT_STEP		54600
+#define TIMEOUT_MIN		(TIMEOUT_MAX - ADP1653_REG_CONFIG_TMR_SET_MAX \
+				 * TIMEOUT_STEP)
+#define TIMEOUT_US_TO_CODE(t)	((TIMEOUT_MAX + (TIMEOUT_STEP / 2) - (t)) \
+				 / TIMEOUT_STEP)
+#define TIMEOUT_CODE_TO_US(c)	(TIMEOUT_MAX - (c) * TIMEOUT_STEP)
+
+/* Write values into ADP1653 registers. */
+static int adp1653_update_hw(struct adp1653_flash *flash)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+	u8 out_sel;
+	u8 config = 0;
+	int rval;
+
+	out_sel = ADP1653_INDICATOR_INTENSITY_uA_TO_REG(
+		flash->indicator_intensity->val)
+		<< ADP1653_REG_OUT_SEL_ILED_SHIFT;
+
+	switch (flash->led_mode->val) {
+	case V4L2_FLASH_LED_MODE_NONE:
+		break;
+	case V4L2_FLASH_LED_MODE_FLASH:
+		/* Flash mode, light on with strobe, duration from timer */
+		config = ADP1653_REG_CONFIG_TMR_CFG;
+		config |= TIMEOUT_US_TO_CODE(flash->flash_timeout->val)
+			  << ADP1653_REG_CONFIG_TMR_SET_SHIFT;
+		break;
+	case V4L2_FLASH_LED_MODE_TORCH:
+		/* Torch mode, light immediately on, duration indefinite */
+		out_sel |= ADP1653_FLASH_INTENSITY_mA_TO_REG(
+			flash->torch_intensity->val)
+			<< ADP1653_REG_OUT_SEL_HPLED_SHIFT;
+		break;
+	}
+
+	rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, out_sel);
+	if (rval < 0)
+		return rval;
+
+	rval = i2c_smbus_write_byte_data(client, ADP1653_REG_CONFIG, config);
+	if (rval < 0)
+		return rval;
+
+	return 0;
+}
+
+static int adp1653_get_fault(struct adp1653_flash *flash)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+	int fault;
+	int rval;
+
+	fault = i2c_smbus_read_byte_data(client, ADP1653_REG_FAULT);
+	if (IS_ERR_VALUE(fault))
+		return fault;
+
+	flash->fault |= fault;
+
+	if (!flash->fault)
+		return 0;
+
+	/* Clear faults. */
+	rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, 0);
+	if (IS_ERR_VALUE(rval))
+		return rval;
+
+	flash->led_mode->val = V4L2_FLASH_LED_MODE_NONE;
+
+	rval = adp1653_update_hw(flash);
+	if (IS_ERR_VALUE(rval))
+		return rval;
+
+	return flash->fault;
+}
+
+static int adp1653_strobe(struct adp1653_flash *flash, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+	u8 out_sel = ADP1653_INDICATOR_INTENSITY_uA_TO_REG(
+		flash->indicator_intensity->val)
+		<< ADP1653_REG_OUT_SEL_ILED_SHIFT;
+	int rval;
+
+	if (flash->led_mode->val != V4L2_FLASH_LED_MODE_FLASH)
+		return -EBUSY;
+
+	if (!enable)
+		return i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL,
+						 out_sel);
+
+	out_sel |= ADP1653_FLASH_INTENSITY_mA_TO_REG(
+		flash->flash_intensity->val)
+		<< ADP1653_REG_OUT_SEL_HPLED_SHIFT;
+	rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, out_sel);
+	if (rval)
+		return rval;
+
+	/* Software strobe using i2c */
+	rval = i2c_smbus_write_byte_data(client, ADP1653_REG_SW_STROBE,
+		ADP1653_REG_SW_STROBE_SW_STROBE);
+	if (rval)
+		return rval;
+	return i2c_smbus_write_byte_data(client, ADP1653_REG_SW_STROBE, 0);
+}
+
+/* --------------------------------------------------------------------------
+ * V4L2 controls
+ */
+
+static int adp1653_get_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct adp1653_flash *flash =
+		container_of(ctrl->handler, struct adp1653_flash, ctrls);
+	int rval;
+
+	rval = adp1653_get_fault(flash);
+	if (IS_ERR_VALUE(rval))
+		return rval;
+
+	ctrl->cur.val = 0;
+
+	if (flash->fault & ADP1653_REG_FAULT_FLT_SCP)
+		ctrl->cur.val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
+	if (flash->fault & ADP1653_REG_FAULT_FLT_OT)
+		ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
+	if (flash->fault & ADP1653_REG_FAULT_FLT_TMR)
+		ctrl->cur.val |= V4L2_FLASH_FAULT_TIMEOUT;
+	if (flash->fault & ADP1653_REG_FAULT_FLT_OV)
+		ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
+
+	flash->fault = 0;
+
+	return 0;
+}
+
+static int adp1653_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct adp1653_flash *flash =
+		container_of(ctrl->handler, struct adp1653_flash, ctrls);
+	int rval;
+
+	rval = adp1653_get_fault(flash);
+	if (IS_ERR_VALUE(rval))
+		return rval;
+	if ((rval & (ADP1653_REG_FAULT_FLT_SCP |
+		     ADP1653_REG_FAULT_FLT_OT |
+		     ADP1653_REG_FAULT_FLT_OV)) &&
+	    (ctrl->id == V4L2_CID_FLASH_STROBE ||
+	     ctrl->id == V4L2_CID_FLASH_TORCH_INTENSITY ||
+	     ctrl->id == V4L2_CID_FLASH_LED_MODE))
+		return -EBUSY;
+
+	switch (ctrl->id) {
+	case V4L2_CID_FLASH_STROBE:
+		return adp1653_strobe(flash, 1);
+	case V4L2_CID_FLASH_STROBE_STOP:
+		return adp1653_strobe(flash, 0);
+	}
+
+	return adp1653_update_hw(flash);
+}
+
+static const struct v4l2_ctrl_ops adp1653_ctrl_ops = {
+	.g_volatile_ctrl = adp1653_get_ctrl,
+	.s_ctrl = adp1653_set_ctrl,
+};
+
+static int adp1653_init_controls(struct adp1653_flash *flash)
+{
+	struct v4l2_ctrl *fault;
+
+	v4l2_ctrl_handler_init(&flash->ctrls, 9);
+
+	flash->led_mode =
+		v4l2_ctrl_new_std_menu(&flash->ctrls, &adp1653_ctrl_ops,
+				       V4L2_CID_FLASH_LED_MODE,
+				       V4L2_FLASH_LED_MODE_TORCH, ~0x7, 0);
+	v4l2_ctrl_new_std_menu(&flash->ctrls, &adp1653_ctrl_ops,
+			       V4L2_CID_FLASH_STROBE_SOURCE,
+			       V4L2_FLASH_STROBE_SOURCE_SOFTWARE, ~0x1, 0);
+	v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+			  V4L2_CID_FLASH_STROBE, 0, 0, 0, 0);
+	v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+			  V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0);
+	flash->flash_timeout =
+		v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+				  V4L2_CID_FLASH_TIMEOUT, TIMEOUT_MIN,
+				  flash->platform_data->max_flash_timeout,
+				  TIMEOUT_STEP,
+				  flash->platform_data->max_flash_timeout);
+	flash->flash_intensity =
+		v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+				  V4L2_CID_FLASH_INTENSITY,
+				  ADP1653_FLASH_INTENSITY_MIN,
+				  flash->platform_data->max_flash_intensity,
+				  1, flash->platform_data->max_flash_intensity);
+	flash->torch_intensity =
+		v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+				  V4L2_CID_FLASH_TORCH_INTENSITY,
+				  ADP1653_TORCH_INTENSITY_MIN,
+				  flash->platform_data->max_torch_intensity,
+				  ADP1653_FLASH_INTENSITY_STEP,
+				  flash->platform_data->max_torch_intensity);
+	flash->indicator_intensity =
+		v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+				  V4L2_CID_FLASH_INDICATOR_INTENSITY,
+				  ADP1653_INDICATOR_INTENSITY_MIN,
+				  flash->platform_data->max_indicator_intensity,
+				  ADP1653_INDICATOR_INTENSITY_STEP,
+				  ADP1653_INDICATOR_INTENSITY_MIN);
+	fault = v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+				  V4L2_CID_FLASH_FAULT, 0,
+				  V4L2_FLASH_FAULT_OVER_VOLTAGE
+				  | V4L2_FLASH_FAULT_OVER_TEMPERATURE
+				  | V4L2_FLASH_FAULT_SHORT_CIRCUIT, 0, 0);
+
+	if (flash->ctrls.error)
+		return flash->ctrls.error;
+
+	fault->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+	flash->subdev.ctrl_handler = &flash->ctrls;
+	return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+static int
+adp1653_init_device(struct adp1653_flash *flash)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+	int rval;
+
+	/* Clear FAULT register by writing zero to OUT_SEL */
+	rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, 0);
+	if (rval < 0) {
+		dev_err(&client->dev, "failed writing fault register\n");
+		return -EIO;
+	}
+
+	mutex_lock(flash->ctrls.lock);
+	/* Reset faults before reading new ones. */
+	flash->fault = 0;
+	rval = adp1653_get_fault(flash);
+	mutex_unlock(flash->ctrls.lock);
+	if (rval > 0) {
+		dev_err(&client->dev, "faults detected: 0x%1.1x\n", rval);
+		return -EIO;
+	}
+
+	mutex_lock(flash->ctrls.lock);
+	rval = adp1653_update_hw(flash);
+	mutex_unlock(flash->ctrls.lock);
+	if (rval) {
+		dev_err(&client->dev,
+			"adp1653_update_hw failed at %s\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int
+__adp1653_set_power(struct adp1653_flash *flash, int on)
+{
+	int ret;
+
+	ret = flash->platform_data->power(&flash->subdev, on);
+	if (ret < 0)
+		return ret;
+
+	if (!on)
+		return 0;
+
+	ret = adp1653_init_device(flash);
+	if (ret < 0)
+		flash->platform_data->power(&flash->subdev, 0);
+
+	return ret;
+}
+
+static int
+adp1653_set_power(struct v4l2_subdev *subdev, int on)
+{
+	struct adp1653_flash *flash = to_adp1653_flash(subdev);
+	int ret = 0;
+
+	mutex_lock(&flash->power_lock);
+
+	/* If the power count is modified from 0 to != 0 or from != 0 to 0,
+	 * update the power state.
+	 */
+	if (flash->power_count == !on) {
+		ret = __adp1653_set_power(flash, !!on);
+		if (ret < 0)
+			goto done;
+	}
+
+	/* Update the power count. */
+	flash->power_count += on ? 1 : -1;
+	WARN_ON(flash->power_count < 0);
+
+done:
+	mutex_unlock(&flash->power_lock);
+	return ret;
+}
+
+static int adp1653_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	return adp1653_set_power(sd, 1);
+}
+
+static int adp1653_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	return adp1653_set_power(sd, 0);
+}
+
+static const struct v4l2_subdev_core_ops adp1653_core_ops = {
+	.s_power = adp1653_set_power,
+};
+
+static const struct v4l2_subdev_ops adp1653_ops = {
+	.core = &adp1653_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops adp1653_internal_ops = {
+	.open = adp1653_open,
+	.close = adp1653_close,
+};
+
+/* --------------------------------------------------------------------------
+ * I2C driver
+ */
+#ifdef CONFIG_PM
+
+static int adp1653_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct adp1653_flash *flash = to_adp1653_flash(subdev);
+
+	if (!flash->power_count)
+		return 0;
+
+	return __adp1653_set_power(flash, 0);
+}
+
+static int adp1653_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct adp1653_flash *flash = to_adp1653_flash(subdev);
+
+	if (!flash->power_count)
+		return 0;
+
+	return __adp1653_set_power(flash, 1);
+}
+
+#else
+
+#define adp1653_suspend	NULL
+#define adp1653_resume	NULL
+
+#endif /* CONFIG_PM */
+
+static int adp1653_probe(struct i2c_client *client,
+			 const struct i2c_device_id *devid)
+{
+	struct adp1653_flash *flash;
+	int ret;
+
+	/* we couldn't work without platform data */
+	if (client->dev.platform_data == NULL)
+		return -ENODEV;
+
+	flash = kzalloc(sizeof(*flash), GFP_KERNEL);
+	if (flash == NULL)
+		return -ENOMEM;
+
+	flash->platform_data = client->dev.platform_data;
+
+	mutex_init(&flash->power_lock);
+
+	v4l2_i2c_subdev_init(&flash->subdev, client, &adp1653_ops);
+	flash->subdev.internal_ops = &adp1653_internal_ops;
+	flash->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	ret = adp1653_init_controls(flash);
+	if (ret)
+		goto free_and_quit;
+
+	ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0);
+	if (ret < 0)
+		goto free_and_quit;
+
+	flash->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
+
+	return 0;
+
+free_and_quit:
+	v4l2_ctrl_handler_free(&flash->ctrls);
+	kfree(flash);
+	return ret;
+}
+
+static int __exit adp1653_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct adp1653_flash *flash = to_adp1653_flash(subdev);
+
+	v4l2_device_unregister_subdev(&flash->subdev);
+	v4l2_ctrl_handler_free(&flash->ctrls);
+	media_entity_cleanup(&flash->subdev.entity);
+	kfree(flash);
+	return 0;
+}
+
+static const struct i2c_device_id adp1653_id_table[] = {
+	{ ADP1653_NAME, 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adp1653_id_table);
+
+static struct dev_pm_ops adp1653_pm_ops = {
+	.suspend	= adp1653_suspend,
+	.resume		= adp1653_resume,
+};
+
+static struct i2c_driver adp1653_i2c_driver = {
+	.driver		= {
+		.name	= ADP1653_NAME,
+		.pm	= &adp1653_pm_ops,
+	},
+	.probe		= adp1653_probe,
+	.remove		= __exit_p(adp1653_remove),
+	.id_table	= adp1653_id_table,
+};
+
+module_i2c_driver(adp1653_i2c_driver);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
+MODULE_DESCRIPTION("Analog Devices ADP1653 LED flash driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/adv7170.c b/drivers/media/i2c/adv7170.c
new file mode 100644
index 0000000..6bc01fb
--- /dev/null
+++ b/drivers/media/i2c/adv7170.c
@@ -0,0 +1,410 @@
+/*
+ * adv7170 - adv7170, adv7171 video encoder driver version 0.0.1
+ *
+ * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
+ *
+ * Based on adv7176 driver by:
+ *
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *    - some corrections for Pinnacle Systems Inc. DC10plus card.
+ *
+ * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *    - moved over to linux>=2.4.x i2c protocol (1/1/2003)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
+MODULE_AUTHOR("Maxim Yevtyushkin");
+MODULE_LICENSE("GPL");
+
+
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/* ----------------------------------------------------------------------- */
+
+struct adv7170 {
+	struct v4l2_subdev sd;
+	unsigned char reg[128];
+
+	v4l2_std_id norm;
+	int input;
+};
+
+static inline struct adv7170 *to_adv7170(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct adv7170, sd);
+}
+
+static char *inputs[] = { "pass_through", "play_back" };
+
+static enum v4l2_mbus_pixelcode adv7170_codes[] = {
+	V4L2_MBUS_FMT_UYVY8_2X8,
+	V4L2_MBUS_FMT_UYVY8_1X16,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static inline int adv7170_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct adv7170 *encoder = to_adv7170(sd);
+
+	encoder->reg[reg] = value;
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline int adv7170_read(struct v4l2_subdev *sd, u8 reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int adv7170_write_block(struct v4l2_subdev *sd,
+		     const u8 *data, unsigned int len)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct adv7170 *encoder = to_adv7170(sd);
+	int ret = -1;
+	u8 reg;
+
+	/* the adv7170 has an autoincrement function, use it if
+	 * the adapter understands raw I2C */
+	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		/* do raw I2C, not smbus compatible */
+		u8 block_data[32];
+		int block_len;
+
+		while (len >= 2) {
+			block_len = 0;
+			block_data[block_len++] = reg = data[0];
+			do {
+				block_data[block_len++] =
+				    encoder->reg[reg++] = data[1];
+				len -= 2;
+				data += 2;
+			} while (len >= 2 && data[0] == reg && block_len < 32);
+			ret = i2c_master_send(client, block_data, block_len);
+			if (ret < 0)
+				break;
+		}
+	} else {
+		/* do some slow I2C emulation kind of thing */
+		while (len >= 2) {
+			reg = *data++;
+			ret = adv7170_write(sd, reg, *data++);
+			if (ret < 0)
+				break;
+			len -= 2;
+		}
+	}
+	return ret;
+}
+
+/* ----------------------------------------------------------------------- */
+
+#define TR0MODE     0x4c
+#define TR0RST	    0x80
+
+#define TR1CAPT	    0x00
+#define TR1PLAY	    0x00
+
+static const unsigned char init_NTSC[] = {
+	0x00, 0x10,		/* MR0 */
+	0x01, 0x20,		/* MR1 */
+	0x02, 0x0e,		/* MR2 RTC control: bits 2 and 1 */
+	0x03, 0x80,		/* MR3 */
+	0x04, 0x30,		/* MR4 */
+	0x05, 0x00,		/* Reserved */
+	0x06, 0x00,		/* Reserved */
+	0x07, TR0MODE,		/* TM0 */
+	0x08, TR1CAPT,		/* TM1 */
+	0x09, 0x16,		/* Fsc0 */
+	0x0a, 0x7c,		/* Fsc1 */
+	0x0b, 0xf0,		/* Fsc2 */
+	0x0c, 0x21,		/* Fsc3 */
+	0x0d, 0x00,		/* Subcarrier Phase */
+	0x0e, 0x00,		/* Closed Capt. Ext 0 */
+	0x0f, 0x00,		/* Closed Capt. Ext 1 */
+	0x10, 0x00,		/* Closed Capt. 0 */
+	0x11, 0x00,		/* Closed Capt. 1 */
+	0x12, 0x00,		/* Pedestal Ctl 0 */
+	0x13, 0x00,		/* Pedestal Ctl 1 */
+	0x14, 0x00,		/* Pedestal Ctl 2 */
+	0x15, 0x00,		/* Pedestal Ctl 3 */
+	0x16, 0x00,		/* CGMS_WSS_0 */
+	0x17, 0x00,		/* CGMS_WSS_1 */
+	0x18, 0x00,		/* CGMS_WSS_2 */
+	0x19, 0x00,		/* Teletext Ctl */
+};
+
+static const unsigned char init_PAL[] = {
+	0x00, 0x71,		/* MR0 */
+	0x01, 0x20,		/* MR1 */
+	0x02, 0x0e,		/* MR2 RTC control: bits 2 and 1 */
+	0x03, 0x80,		/* MR3 */
+	0x04, 0x30,		/* MR4 */
+	0x05, 0x00,		/* Reserved */
+	0x06, 0x00,		/* Reserved */
+	0x07, TR0MODE,		/* TM0 */
+	0x08, TR1CAPT,		/* TM1 */
+	0x09, 0xcb,		/* Fsc0 */
+	0x0a, 0x8a,		/* Fsc1 */
+	0x0b, 0x09,		/* Fsc2 */
+	0x0c, 0x2a,		/* Fsc3 */
+	0x0d, 0x00,		/* Subcarrier Phase */
+	0x0e, 0x00,		/* Closed Capt. Ext 0 */
+	0x0f, 0x00,		/* Closed Capt. Ext 1 */
+	0x10, 0x00,		/* Closed Capt. 0 */
+	0x11, 0x00,		/* Closed Capt. 1 */
+	0x12, 0x00,		/* Pedestal Ctl 0 */
+	0x13, 0x00,		/* Pedestal Ctl 1 */
+	0x14, 0x00,		/* Pedestal Ctl 2 */
+	0x15, 0x00,		/* Pedestal Ctl 3 */
+	0x16, 0x00,		/* CGMS_WSS_0 */
+	0x17, 0x00,		/* CGMS_WSS_1 */
+	0x18, 0x00,		/* CGMS_WSS_2 */
+	0x19, 0x00,		/* Teletext Ctl */
+};
+
+
+static int adv7170_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct adv7170 *encoder = to_adv7170(sd);
+
+	v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
+
+	if (std & V4L2_STD_NTSC) {
+		adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC));
+		if (encoder->input == 0)
+			adv7170_write(sd, 0x02, 0x0e);	/* Enable genlock */
+		adv7170_write(sd, 0x07, TR0MODE | TR0RST);
+		adv7170_write(sd, 0x07, TR0MODE);
+	} else if (std & V4L2_STD_PAL) {
+		adv7170_write_block(sd, init_PAL, sizeof(init_PAL));
+		if (encoder->input == 0)
+			adv7170_write(sd, 0x02, 0x0e);	/* Enable genlock */
+		adv7170_write(sd, 0x07, TR0MODE | TR0RST);
+		adv7170_write(sd, 0x07, TR0MODE);
+	} else {
+		v4l2_dbg(1, debug, sd, "illegal norm: %llx\n",
+				(unsigned long long)std);
+		return -EINVAL;
+	}
+	v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std);
+	encoder->norm = std;
+	return 0;
+}
+
+static int adv7170_s_routing(struct v4l2_subdev *sd,
+			     u32 input, u32 output, u32 config)
+{
+	struct adv7170 *encoder = to_adv7170(sd);
+
+	/* RJ: input = 0: input is from decoder
+	   input = 1: input is from ZR36060
+	   input = 2: color bar */
+
+	v4l2_dbg(1, debug, sd, "set input from %s\n",
+			input == 0 ? "decoder" : "ZR36060");
+
+	switch (input) {
+	case 0:
+		adv7170_write(sd, 0x01, 0x20);
+		adv7170_write(sd, 0x08, TR1CAPT);	/* TR1 */
+		adv7170_write(sd, 0x02, 0x0e);	/* Enable genlock */
+		adv7170_write(sd, 0x07, TR0MODE | TR0RST);
+		adv7170_write(sd, 0x07, TR0MODE);
+		/* udelay(10); */
+		break;
+
+	case 1:
+		adv7170_write(sd, 0x01, 0x00);
+		adv7170_write(sd, 0x08, TR1PLAY);	/* TR1 */
+		adv7170_write(sd, 0x02, 0x08);
+		adv7170_write(sd, 0x07, TR0MODE | TR0RST);
+		adv7170_write(sd, 0x07, TR0MODE);
+		/* udelay(10); */
+		break;
+
+	default:
+		v4l2_dbg(1, debug, sd, "illegal input: %d\n", input);
+		return -EINVAL;
+	}
+	v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[input]);
+	encoder->input = input;
+	return 0;
+}
+
+static int adv7170_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+				enum v4l2_mbus_pixelcode *code)
+{
+	if (index >= ARRAY_SIZE(adv7170_codes))
+		return -EINVAL;
+
+	*code = adv7170_codes[index];
+	return 0;
+}
+
+static int adv7170_g_fmt(struct v4l2_subdev *sd,
+				struct v4l2_mbus_framefmt *mf)
+{
+	u8 val = adv7170_read(sd, 0x7);
+
+	if ((val & 0x40) == (1 << 6))
+		mf->code = V4L2_MBUS_FMT_UYVY8_1X16;
+	else
+		mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+
+	mf->colorspace  = V4L2_COLORSPACE_SMPTE170M;
+	mf->width       = 0;
+	mf->height      = 0;
+	mf->field       = V4L2_FIELD_ANY;
+
+	return 0;
+}
+
+static int adv7170_s_fmt(struct v4l2_subdev *sd,
+				struct v4l2_mbus_framefmt *mf)
+{
+	u8 val = adv7170_read(sd, 0x7);
+	int ret;
+
+	switch (mf->code) {
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		val &= ~0x40;
+		break;
+
+	case V4L2_MBUS_FMT_UYVY8_1X16:
+		val |= 0x40;
+		break;
+
+	default:
+		v4l2_dbg(1, debug, sd,
+			"illegal v4l2_mbus_framefmt code: %d\n", mf->code);
+		return -EINVAL;
+	}
+
+	ret = adv7170_write(sd, 0x7, val);
+
+	return ret;
+}
+
+static int adv7170_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7170, 0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops adv7170_core_ops = {
+	.g_chip_ident = adv7170_g_chip_ident,
+};
+
+static const struct v4l2_subdev_video_ops adv7170_video_ops = {
+	.s_std_output = adv7170_s_std_output,
+	.s_routing = adv7170_s_routing,
+	.s_mbus_fmt = adv7170_s_fmt,
+	.g_mbus_fmt = adv7170_g_fmt,
+	.enum_mbus_fmt  = adv7170_enum_fmt,
+};
+
+static const struct v4l2_subdev_ops adv7170_ops = {
+	.core = &adv7170_core_ops,
+	.video = &adv7170_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int adv7170_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct adv7170 *encoder;
+	struct v4l2_subdev *sd;
+	int i;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL);
+	if (encoder == NULL)
+		return -ENOMEM;
+	sd = &encoder->sd;
+	v4l2_i2c_subdev_init(sd, client, &adv7170_ops);
+	encoder->norm = V4L2_STD_NTSC;
+	encoder->input = 0;
+
+	i = adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC));
+	if (i >= 0) {
+		i = adv7170_write(sd, 0x07, TR0MODE | TR0RST);
+		i = adv7170_write(sd, 0x07, TR0MODE);
+		i = adv7170_read(sd, 0x12);
+		v4l2_dbg(1, debug, sd, "revision %d\n", i & 1);
+	}
+	if (i < 0)
+		v4l2_dbg(1, debug, sd, "init error 0x%x\n", i);
+	return 0;
+}
+
+static int adv7170_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_adv7170(sd));
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id adv7170_id[] = {
+	{ "adv7170", 0 },
+	{ "adv7171", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adv7170_id);
+
+static struct i2c_driver adv7170_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "adv7170",
+	},
+	.probe		= adv7170_probe,
+	.remove		= adv7170_remove,
+	.id_table	= adv7170_id,
+};
+
+module_i2c_driver(adv7170_driver);
diff --git a/drivers/media/i2c/adv7175.c b/drivers/media/i2c/adv7175.c
new file mode 100644
index 0000000..c7640fa
--- /dev/null
+++ b/drivers/media/i2c/adv7175.c
@@ -0,0 +1,460 @@
+/*
+ *  adv7175 - adv7175a video encoder driver version 0.0.3
+ *
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *    - some corrections for Pinnacle Systems Inc. DC10plus card.
+ *
+ * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *    - moved over to linux>=2.4.x i2c protocol (9/9/2002)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
+MODULE_AUTHOR("Dave Perks");
+MODULE_LICENSE("GPL");
+
+#define   I2C_ADV7175        0xd4
+#define   I2C_ADV7176        0x54
+
+
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/* ----------------------------------------------------------------------- */
+
+struct adv7175 {
+	struct v4l2_subdev sd;
+	v4l2_std_id norm;
+	int input;
+};
+
+static inline struct adv7175 *to_adv7175(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct adv7175, sd);
+}
+
+static char *inputs[] = { "pass_through", "play_back", "color_bar" };
+
+static enum v4l2_mbus_pixelcode adv7175_codes[] = {
+	V4L2_MBUS_FMT_UYVY8_2X8,
+	V4L2_MBUS_FMT_UYVY8_1X16,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static inline int adv7175_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline int adv7175_read(struct v4l2_subdev *sd, u8 reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int adv7175_write_block(struct v4l2_subdev *sd,
+		     const u8 *data, unsigned int len)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret = -1;
+	u8 reg;
+
+	/* the adv7175 has an autoincrement function, use it if
+	 * the adapter understands raw I2C */
+	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		/* do raw I2C, not smbus compatible */
+		u8 block_data[32];
+		int block_len;
+
+		while (len >= 2) {
+			block_len = 0;
+			block_data[block_len++] = reg = data[0];
+			do {
+				block_data[block_len++] = data[1];
+				reg++;
+				len -= 2;
+				data += 2;
+			} while (len >= 2 && data[0] == reg && block_len < 32);
+			ret = i2c_master_send(client, block_data, block_len);
+			if (ret < 0)
+				break;
+		}
+	} else {
+		/* do some slow I2C emulation kind of thing */
+		while (len >= 2) {
+			reg = *data++;
+			ret = adv7175_write(sd, reg, *data++);
+			if (ret < 0)
+				break;
+			len -= 2;
+		}
+	}
+
+	return ret;
+}
+
+static void set_subcarrier_freq(struct v4l2_subdev *sd, int pass_through)
+{
+	/* for some reason pass_through NTSC needs
+	 * a different sub-carrier freq to remain stable. */
+	if (pass_through)
+		adv7175_write(sd, 0x02, 0x00);
+	else
+		adv7175_write(sd, 0x02, 0x55);
+
+	adv7175_write(sd, 0x03, 0x55);
+	adv7175_write(sd, 0x04, 0x55);
+	adv7175_write(sd, 0x05, 0x25);
+}
+
+/* ----------------------------------------------------------------------- */
+/* Output filter:  S-Video  Composite */
+
+#define MR050       0x11	/* 0x09 */
+#define MR060       0x14	/* 0x0c */
+
+/* ----------------------------------------------------------------------- */
+
+#define TR0MODE     0x46
+#define TR0RST	    0x80
+
+#define TR1CAPT	    0x80
+#define TR1PLAY	    0x00
+
+static const unsigned char init_common[] = {
+
+	0x00, MR050,		/* MR0, PAL enabled */
+	0x01, 0x00,		/* MR1 */
+	0x02, 0x0c,		/* subc. freq. */
+	0x03, 0x8c,		/* subc. freq. */
+	0x04, 0x79,		/* subc. freq. */
+	0x05, 0x26,		/* subc. freq. */
+	0x06, 0x40,		/* subc. phase */
+
+	0x07, TR0MODE,		/* TR0, 16bit */
+	0x08, 0x21,		/*  */
+	0x09, 0x00,		/*  */
+	0x0a, 0x00,		/*  */
+	0x0b, 0x00,		/*  */
+	0x0c, TR1CAPT,		/* TR1 */
+	0x0d, 0x4f,		/* MR2 */
+	0x0e, 0x00,		/*  */
+	0x0f, 0x00,		/*  */
+	0x10, 0x00,		/*  */
+	0x11, 0x00,		/*  */
+};
+
+static const unsigned char init_pal[] = {
+	0x00, MR050,		/* MR0, PAL enabled */
+	0x01, 0x00,		/* MR1 */
+	0x02, 0x0c,		/* subc. freq. */
+	0x03, 0x8c,		/* subc. freq. */
+	0x04, 0x79,		/* subc. freq. */
+	0x05, 0x26,		/* subc. freq. */
+	0x06, 0x40,		/* subc. phase */
+};
+
+static const unsigned char init_ntsc[] = {
+	0x00, MR060,		/* MR0, NTSC enabled */
+	0x01, 0x00,		/* MR1 */
+	0x02, 0x55,		/* subc. freq. */
+	0x03, 0x55,		/* subc. freq. */
+	0x04, 0x55,		/* subc. freq. */
+	0x05, 0x25,		/* subc. freq. */
+	0x06, 0x1a,		/* subc. phase */
+};
+
+static int adv7175_init(struct v4l2_subdev *sd, u32 val)
+{
+	/* This is just for testing!!! */
+	adv7175_write_block(sd, init_common, sizeof(init_common));
+	adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+	adv7175_write(sd, 0x07, TR0MODE);
+	return 0;
+}
+
+static int adv7175_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct adv7175 *encoder = to_adv7175(sd);
+
+	if (std & V4L2_STD_NTSC) {
+		adv7175_write_block(sd, init_ntsc, sizeof(init_ntsc));
+		if (encoder->input == 0)
+			adv7175_write(sd, 0x0d, 0x4f);	/* Enable genlock */
+		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+		adv7175_write(sd, 0x07, TR0MODE);
+	} else if (std & V4L2_STD_PAL) {
+		adv7175_write_block(sd, init_pal, sizeof(init_pal));
+		if (encoder->input == 0)
+			adv7175_write(sd, 0x0d, 0x4f);	/* Enable genlock */
+		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+		adv7175_write(sd, 0x07, TR0MODE);
+	} else if (std & V4L2_STD_SECAM) {
+		/* This is an attempt to convert
+		 * SECAM->PAL (typically it does not work
+		 * due to genlock: when decoder is in SECAM
+		 * and encoder in in PAL the subcarrier can
+		 * not be syncronized with horizontal
+		 * quency) */
+		adv7175_write_block(sd, init_pal, sizeof(init_pal));
+		if (encoder->input == 0)
+			adv7175_write(sd, 0x0d, 0x49);	/* Disable genlock */
+		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+		adv7175_write(sd, 0x07, TR0MODE);
+	} else {
+		v4l2_dbg(1, debug, sd, "illegal norm: %llx\n",
+				(unsigned long long)std);
+		return -EINVAL;
+	}
+	v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std);
+	encoder->norm = std;
+	return 0;
+}
+
+static int adv7175_s_routing(struct v4l2_subdev *sd,
+			     u32 input, u32 output, u32 config)
+{
+	struct adv7175 *encoder = to_adv7175(sd);
+
+	/* RJ: input = 0: input is from decoder
+	   input = 1: input is from ZR36060
+	   input = 2: color bar */
+
+	switch (input) {
+	case 0:
+		adv7175_write(sd, 0x01, 0x00);
+
+		if (encoder->norm & V4L2_STD_NTSC)
+			set_subcarrier_freq(sd, 1);
+
+		adv7175_write(sd, 0x0c, TR1CAPT);	/* TR1 */
+		if (encoder->norm & V4L2_STD_SECAM)
+			adv7175_write(sd, 0x0d, 0x49);	/* Disable genlock */
+		else
+			adv7175_write(sd, 0x0d, 0x4f);	/* Enable genlock */
+		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+		adv7175_write(sd, 0x07, TR0MODE);
+		/*udelay(10);*/
+		break;
+
+	case 1:
+		adv7175_write(sd, 0x01, 0x00);
+
+		if (encoder->norm & V4L2_STD_NTSC)
+			set_subcarrier_freq(sd, 0);
+
+		adv7175_write(sd, 0x0c, TR1PLAY);	/* TR1 */
+		adv7175_write(sd, 0x0d, 0x49);
+		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+		adv7175_write(sd, 0x07, TR0MODE);
+		/* udelay(10); */
+		break;
+
+	case 2:
+		adv7175_write(sd, 0x01, 0x80);
+
+		if (encoder->norm & V4L2_STD_NTSC)
+			set_subcarrier_freq(sd, 0);
+
+		adv7175_write(sd, 0x0d, 0x49);
+		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+		adv7175_write(sd, 0x07, TR0MODE);
+		/* udelay(10); */
+		break;
+
+	default:
+		v4l2_dbg(1, debug, sd, "illegal input: %d\n", input);
+		return -EINVAL;
+	}
+	v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[input]);
+	encoder->input = input;
+	return 0;
+}
+
+static int adv7175_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+				enum v4l2_mbus_pixelcode *code)
+{
+	if (index >= ARRAY_SIZE(adv7175_codes))
+		return -EINVAL;
+
+	*code = adv7175_codes[index];
+	return 0;
+}
+
+static int adv7175_g_fmt(struct v4l2_subdev *sd,
+				struct v4l2_mbus_framefmt *mf)
+{
+	u8 val = adv7175_read(sd, 0x7);
+
+	if ((val & 0x40) == (1 << 6))
+		mf->code = V4L2_MBUS_FMT_UYVY8_1X16;
+	else
+		mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+
+	mf->colorspace  = V4L2_COLORSPACE_SMPTE170M;
+	mf->width       = 0;
+	mf->height      = 0;
+	mf->field       = V4L2_FIELD_ANY;
+
+	return 0;
+}
+
+static int adv7175_s_fmt(struct v4l2_subdev *sd,
+				struct v4l2_mbus_framefmt *mf)
+{
+	u8 val = adv7175_read(sd, 0x7);
+	int ret;
+
+	switch (mf->code) {
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		val &= ~0x40;
+		break;
+
+	case V4L2_MBUS_FMT_UYVY8_1X16:
+		val |= 0x40;
+		break;
+
+	default:
+		v4l2_dbg(1, debug, sd,
+			"illegal v4l2_mbus_framefmt code: %d\n", mf->code);
+		return -EINVAL;
+	}
+
+	ret = adv7175_write(sd, 0x7, val);
+
+	return ret;
+}
+
+static int adv7175_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7175, 0);
+}
+
+static int adv7175_s_power(struct v4l2_subdev *sd, int on)
+{
+	if (on)
+		adv7175_write(sd, 0x01, 0x00);
+	else
+		adv7175_write(sd, 0x01, 0x78);
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops adv7175_core_ops = {
+	.g_chip_ident = adv7175_g_chip_ident,
+	.init = adv7175_init,
+	.s_power = adv7175_s_power,
+};
+
+static const struct v4l2_subdev_video_ops adv7175_video_ops = {
+	.s_std_output = adv7175_s_std_output,
+	.s_routing = adv7175_s_routing,
+	.s_mbus_fmt = adv7175_s_fmt,
+	.g_mbus_fmt = adv7175_g_fmt,
+	.enum_mbus_fmt  = adv7175_enum_fmt,
+};
+
+static const struct v4l2_subdev_ops adv7175_ops = {
+	.core = &adv7175_core_ops,
+	.video = &adv7175_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int adv7175_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int i;
+	struct adv7175 *encoder;
+	struct v4l2_subdev *sd;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	encoder = kzalloc(sizeof(struct adv7175), GFP_KERNEL);
+	if (encoder == NULL)
+		return -ENOMEM;
+	sd = &encoder->sd;
+	v4l2_i2c_subdev_init(sd, client, &adv7175_ops);
+	encoder->norm = V4L2_STD_NTSC;
+	encoder->input = 0;
+
+	i = adv7175_write_block(sd, init_common, sizeof(init_common));
+	if (i >= 0) {
+		i = adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+		i = adv7175_write(sd, 0x07, TR0MODE);
+		i = adv7175_read(sd, 0x12);
+		v4l2_dbg(1, debug, sd, "revision %d\n", i & 1);
+	}
+	if (i < 0)
+		v4l2_dbg(1, debug, sd, "init error 0x%x\n", i);
+	return 0;
+}
+
+static int adv7175_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_adv7175(sd));
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id adv7175_id[] = {
+	{ "adv7175", 0 },
+	{ "adv7176", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adv7175_id);
+
+static struct i2c_driver adv7175_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "adv7175",
+	},
+	.probe		= adv7175_probe,
+	.remove		= adv7175_remove,
+	.id_table	= adv7175_id,
+};
+
+module_i2c_driver(adv7175_driver);
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
new file mode 100644
index 0000000..45ecf8d
--- /dev/null
+++ b/drivers/media/i2c/adv7180.c
@@ -0,0 +1,667 @@
+/*
+ * adv7180.c Analog Devices ADV7180 video decoder driver
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-chip-ident.h>
+#include <linux/mutex.h>
+
+#define ADV7180_INPUT_CONTROL_REG			0x00
+#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM	0x00
+#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10
+#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM	0x20
+#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_M_SECAM	0x30
+#define ADV7180_INPUT_CONTROL_NTSC_J			0x40
+#define ADV7180_INPUT_CONTROL_NTSC_M			0x50
+#define ADV7180_INPUT_CONTROL_PAL60			0x60
+#define ADV7180_INPUT_CONTROL_NTSC_443			0x70
+#define ADV7180_INPUT_CONTROL_PAL_BG			0x80
+#define ADV7180_INPUT_CONTROL_PAL_N			0x90
+#define ADV7180_INPUT_CONTROL_PAL_M			0xa0
+#define ADV7180_INPUT_CONTROL_PAL_M_PED			0xb0
+#define ADV7180_INPUT_CONTROL_PAL_COMB_N		0xc0
+#define ADV7180_INPUT_CONTROL_PAL_COMB_N_PED		0xd0
+#define ADV7180_INPUT_CONTROL_PAL_SECAM			0xe0
+#define ADV7180_INPUT_CONTROL_PAL_SECAM_PED		0xf0
+#define ADV7180_INPUT_CONTROL_INSEL_MASK		0x0f
+
+#define ADV7180_EXTENDED_OUTPUT_CONTROL_REG		0x04
+#define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS		0xC5
+
+#define ADV7180_AUTODETECT_ENABLE_REG			0x07
+#define ADV7180_AUTODETECT_DEFAULT			0x7f
+/* Contrast */
+#define ADV7180_CON_REG		0x08	/*Unsigned */
+#define ADV7180_CON_MIN		0
+#define ADV7180_CON_DEF		128
+#define ADV7180_CON_MAX		255
+/* Brightness*/
+#define ADV7180_BRI_REG		0x0a	/*Signed */
+#define ADV7180_BRI_MIN		-128
+#define ADV7180_BRI_DEF		0
+#define ADV7180_BRI_MAX		127
+/* Hue */
+#define ADV7180_HUE_REG		0x0b	/*Signed, inverted */
+#define ADV7180_HUE_MIN		-127
+#define ADV7180_HUE_DEF		0
+#define ADV7180_HUE_MAX		128
+
+#define ADV7180_ADI_CTRL_REG				0x0e
+#define ADV7180_ADI_CTRL_IRQ_SPACE			0x20
+
+#define ADV7180_PWR_MAN_REG		0x0f
+#define ADV7180_PWR_MAN_ON		0x04
+#define ADV7180_PWR_MAN_OFF		0x24
+#define ADV7180_PWR_MAN_RES		0x80
+
+#define ADV7180_STATUS1_REG				0x10
+#define ADV7180_STATUS1_IN_LOCK		0x01
+#define ADV7180_STATUS1_AUTOD_MASK	0x70
+#define ADV7180_STATUS1_AUTOD_NTSM_M_J	0x00
+#define ADV7180_STATUS1_AUTOD_NTSC_4_43 0x10
+#define ADV7180_STATUS1_AUTOD_PAL_M	0x20
+#define ADV7180_STATUS1_AUTOD_PAL_60	0x30
+#define ADV7180_STATUS1_AUTOD_PAL_B_G	0x40
+#define ADV7180_STATUS1_AUTOD_SECAM	0x50
+#define ADV7180_STATUS1_AUTOD_PAL_COMB	0x60
+#define ADV7180_STATUS1_AUTOD_SECAM_525	0x70
+
+#define ADV7180_IDENT_REG 0x11
+#define ADV7180_ID_7180 0x18
+
+#define ADV7180_ICONF1_ADI		0x40
+#define ADV7180_ICONF1_ACTIVE_LOW	0x01
+#define ADV7180_ICONF1_PSYNC_ONLY	0x10
+#define ADV7180_ICONF1_ACTIVE_TO_CLR	0xC0
+/* Saturation */
+#define ADV7180_SD_SAT_CB_REG	0xe3	/*Unsigned */
+#define ADV7180_SD_SAT_CR_REG	0xe4	/*Unsigned */
+#define ADV7180_SAT_MIN		0
+#define ADV7180_SAT_DEF		128
+#define ADV7180_SAT_MAX		255
+
+#define ADV7180_IRQ1_LOCK	0x01
+#define ADV7180_IRQ1_UNLOCK	0x02
+#define ADV7180_ISR1_ADI	0x42
+#define ADV7180_ICR1_ADI	0x43
+#define ADV7180_IMR1_ADI	0x44
+#define ADV7180_IMR2_ADI	0x48
+#define ADV7180_IRQ3_AD_CHANGE	0x08
+#define ADV7180_ISR3_ADI	0x4A
+#define ADV7180_ICR3_ADI	0x4B
+#define ADV7180_IMR3_ADI	0x4C
+#define ADV7180_IMR4_ADI	0x50
+
+#define ADV7180_NTSC_V_BIT_END_REG	0xE6
+#define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND	0x4F
+
+struct adv7180_state {
+	struct v4l2_ctrl_handler ctrl_hdl;
+	struct v4l2_subdev	sd;
+	struct work_struct	work;
+	struct mutex		mutex; /* mutual excl. when accessing chip */
+	int			irq;
+	v4l2_std_id		curr_norm;
+	bool			autodetect;
+	u8			input;
+};
+#define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler,		\
+					    struct adv7180_state,	\
+					    ctrl_hdl)->sd)
+
+static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
+{
+	switch (status1 & ADV7180_STATUS1_AUTOD_MASK) {
+	case ADV7180_STATUS1_AUTOD_NTSM_M_J:
+		return V4L2_STD_NTSC;
+	case ADV7180_STATUS1_AUTOD_NTSC_4_43:
+		return V4L2_STD_NTSC_443;
+	case ADV7180_STATUS1_AUTOD_PAL_M:
+		return V4L2_STD_PAL_M;
+	case ADV7180_STATUS1_AUTOD_PAL_60:
+		return V4L2_STD_PAL_60;
+	case ADV7180_STATUS1_AUTOD_PAL_B_G:
+		return V4L2_STD_PAL;
+	case ADV7180_STATUS1_AUTOD_SECAM:
+		return V4L2_STD_SECAM;
+	case ADV7180_STATUS1_AUTOD_PAL_COMB:
+		return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N;
+	case ADV7180_STATUS1_AUTOD_SECAM_525:
+		return V4L2_STD_SECAM;
+	default:
+		return V4L2_STD_UNKNOWN;
+	}
+}
+
+static int v4l2_std_to_adv7180(v4l2_std_id std)
+{
+	if (std == V4L2_STD_PAL_60)
+		return ADV7180_INPUT_CONTROL_PAL60;
+	if (std == V4L2_STD_NTSC_443)
+		return ADV7180_INPUT_CONTROL_NTSC_443;
+	if (std == V4L2_STD_PAL_N)
+		return ADV7180_INPUT_CONTROL_PAL_N;
+	if (std == V4L2_STD_PAL_M)
+		return ADV7180_INPUT_CONTROL_PAL_M;
+	if (std == V4L2_STD_PAL_Nc)
+		return ADV7180_INPUT_CONTROL_PAL_COMB_N;
+
+	if (std & V4L2_STD_PAL)
+		return ADV7180_INPUT_CONTROL_PAL_BG;
+	if (std & V4L2_STD_NTSC)
+		return ADV7180_INPUT_CONTROL_NTSC_M;
+	if (std & V4L2_STD_SECAM)
+		return ADV7180_INPUT_CONTROL_PAL_SECAM;
+
+	return -EINVAL;
+}
+
+static u32 adv7180_status_to_v4l2(u8 status1)
+{
+	if (!(status1 & ADV7180_STATUS1_IN_LOCK))
+		return V4L2_IN_ST_NO_SIGNAL;
+
+	return 0;
+}
+
+static int __adv7180_status(struct i2c_client *client, u32 *status,
+			    v4l2_std_id *std)
+{
+	int status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
+
+	if (status1 < 0)
+		return status1;
+
+	if (status)
+		*status = adv7180_status_to_v4l2(status1);
+	if (std)
+		*std = adv7180_std_to_v4l2(status1);
+
+	return 0;
+}
+
+static inline struct adv7180_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct adv7180_state, sd);
+}
+
+static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	struct adv7180_state *state = to_state(sd);
+	int err = mutex_lock_interruptible(&state->mutex);
+	if (err)
+		return err;
+
+	/* when we are interrupt driven we know the state */
+	if (!state->autodetect || state->irq > 0)
+		*std = state->curr_norm;
+	else
+		err = __adv7180_status(v4l2_get_subdevdata(sd), NULL, std);
+
+	mutex_unlock(&state->mutex);
+	return err;
+}
+
+static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
+			     u32 output, u32 config)
+{
+	struct adv7180_state *state = to_state(sd);
+	int ret = mutex_lock_interruptible(&state->mutex);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (ret)
+		return ret;
+
+	/* We cannot discriminate between LQFP and 40-pin LFCSP, so accept
+	 * all inputs and let the card driver take care of validation
+	 */
+	if ((input & ADV7180_INPUT_CONTROL_INSEL_MASK) != input)
+		goto out;
+
+	ret = i2c_smbus_read_byte_data(client, ADV7180_INPUT_CONTROL_REG);
+
+	if (ret < 0)
+		goto out;
+
+	ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK;
+	ret = i2c_smbus_write_byte_data(client,
+					ADV7180_INPUT_CONTROL_REG, ret | input);
+	state->input = input;
+out:
+	mutex_unlock(&state->mutex);
+	return ret;
+}
+
+static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+	struct adv7180_state *state = to_state(sd);
+	int ret = mutex_lock_interruptible(&state->mutex);
+	if (ret)
+		return ret;
+
+	ret = __adv7180_status(v4l2_get_subdevdata(sd), status, NULL);
+	mutex_unlock(&state->mutex);
+	return ret;
+}
+
+static int adv7180_g_chip_ident(struct v4l2_subdev *sd,
+				struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7180, 0);
+}
+
+static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct adv7180_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret = mutex_lock_interruptible(&state->mutex);
+	if (ret)
+		return ret;
+
+	/* all standards -> autodetect */
+	if (std == V4L2_STD_ALL) {
+		ret =
+		    i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
+				ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
+					      | state->input);
+		if (ret < 0)
+			goto out;
+
+		__adv7180_status(client, NULL, &state->curr_norm);
+		state->autodetect = true;
+	} else {
+		ret = v4l2_std_to_adv7180(std);
+		if (ret < 0)
+			goto out;
+
+		ret = i2c_smbus_write_byte_data(client,
+						ADV7180_INPUT_CONTROL_REG,
+						ret | state->input);
+		if (ret < 0)
+			goto out;
+
+		state->curr_norm = std;
+		state->autodetect = false;
+	}
+	ret = 0;
+out:
+	mutex_unlock(&state->mutex);
+	return ret;
+}
+
+static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_adv7180_sd(ctrl);
+	struct adv7180_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret = mutex_lock_interruptible(&state->mutex);
+	int val;
+
+	if (ret)
+		return ret;
+	val = ctrl->val;
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		ret = i2c_smbus_write_byte_data(client, ADV7180_BRI_REG, val);
+		break;
+	case V4L2_CID_HUE:
+		/*Hue is inverted according to HSL chart */
+		ret = i2c_smbus_write_byte_data(client, ADV7180_HUE_REG, -val);
+		break;
+	case V4L2_CID_CONTRAST:
+		ret = i2c_smbus_write_byte_data(client, ADV7180_CON_REG, val);
+		break;
+	case V4L2_CID_SATURATION:
+		/*
+		 *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE
+		 *Let's not confuse the user, everybody understands saturation
+		 */
+		ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CB_REG,
+						val);
+		if (ret < 0)
+			break;
+		ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CR_REG,
+						val);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	mutex_unlock(&state->mutex);
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops adv7180_ctrl_ops = {
+	.s_ctrl = adv7180_s_ctrl,
+};
+
+static int adv7180_init_controls(struct adv7180_state *state)
+{
+	v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
+
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
+			  V4L2_CID_BRIGHTNESS, ADV7180_BRI_MIN,
+			  ADV7180_BRI_MAX, 1, ADV7180_BRI_DEF);
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
+			  V4L2_CID_CONTRAST, ADV7180_CON_MIN,
+			  ADV7180_CON_MAX, 1, ADV7180_CON_DEF);
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
+			  V4L2_CID_SATURATION, ADV7180_SAT_MIN,
+			  ADV7180_SAT_MAX, 1, ADV7180_SAT_DEF);
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
+			  V4L2_CID_HUE, ADV7180_HUE_MIN,
+			  ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF);
+	state->sd.ctrl_handler = &state->ctrl_hdl;
+	if (state->ctrl_hdl.error) {
+		int err = state->ctrl_hdl.error;
+
+		v4l2_ctrl_handler_free(&state->ctrl_hdl);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&state->ctrl_hdl);
+
+	return 0;
+}
+static void adv7180_exit_controls(struct adv7180_state *state)
+{
+	v4l2_ctrl_handler_free(&state->ctrl_hdl);
+}
+
+static const struct v4l2_subdev_video_ops adv7180_video_ops = {
+	.querystd = adv7180_querystd,
+	.g_input_status = adv7180_g_input_status,
+	.s_routing = adv7180_s_routing,
+};
+
+static const struct v4l2_subdev_core_ops adv7180_core_ops = {
+	.g_chip_ident = adv7180_g_chip_ident,
+	.s_std = adv7180_s_std,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+};
+
+static const struct v4l2_subdev_ops adv7180_ops = {
+	.core = &adv7180_core_ops,
+	.video = &adv7180_video_ops,
+};
+
+static void adv7180_work(struct work_struct *work)
+{
+	struct adv7180_state *state = container_of(work, struct adv7180_state,
+						   work);
+	struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
+	u8 isr3;
+
+	mutex_lock(&state->mutex);
+	i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
+				  ADV7180_ADI_CTRL_IRQ_SPACE);
+	isr3 = i2c_smbus_read_byte_data(client, ADV7180_ISR3_ADI);
+	/* clear */
+	i2c_smbus_write_byte_data(client, ADV7180_ICR3_ADI, isr3);
+	i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, 0);
+
+	if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect)
+		__adv7180_status(client, NULL, &state->curr_norm);
+	mutex_unlock(&state->mutex);
+
+	enable_irq(state->irq);
+}
+
+static irqreturn_t adv7180_irq(int irq, void *devid)
+{
+	struct adv7180_state *state = devid;
+
+	schedule_work(&state->work);
+
+	disable_irq_nosync(state->irq);
+
+	return IRQ_HANDLED;
+}
+
+static int init_device(struct i2c_client *client, struct adv7180_state *state)
+{
+	int ret;
+
+	/* Initialize adv7180 */
+	/* Enable autodetection */
+	if (state->autodetect) {
+		ret =
+		    i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
+				ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
+					      | state->input);
+		if (ret < 0)
+			return ret;
+
+		ret =
+		    i2c_smbus_write_byte_data(client,
+					      ADV7180_AUTODETECT_ENABLE_REG,
+					      ADV7180_AUTODETECT_DEFAULT);
+		if (ret < 0)
+			return ret;
+	} else {
+		ret = v4l2_std_to_adv7180(state->curr_norm);
+		if (ret < 0)
+			return ret;
+
+		ret =
+		    i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
+					      ret | state->input);
+		if (ret < 0)
+			return ret;
+
+	}
+	/* ITU-R BT.656-4 compatible */
+	ret = i2c_smbus_write_byte_data(client,
+			ADV7180_EXTENDED_OUTPUT_CONTROL_REG,
+			ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
+	if (ret < 0)
+		return ret;
+
+	/* Manually set V bit end position in NTSC mode */
+	ret = i2c_smbus_write_byte_data(client,
+					ADV7180_NTSC_V_BIT_END_REG,
+					ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
+	if (ret < 0)
+		return ret;
+
+	/* read current norm */
+	__adv7180_status(client, NULL, &state->curr_norm);
+
+	/* register for interrupts */
+	if (state->irq > 0) {
+		ret = request_irq(state->irq, adv7180_irq, 0, KBUILD_MODNAME,
+				  state);
+		if (ret)
+			return ret;
+
+		ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
+						ADV7180_ADI_CTRL_IRQ_SPACE);
+		if (ret < 0)
+			return ret;
+
+		/* config the Interrupt pin to be active low */
+		ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI,
+						ADV7180_ICONF1_ACTIVE_LOW |
+						ADV7180_ICONF1_PSYNC_ONLY);
+		if (ret < 0)
+			return ret;
+
+		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0);
+		if (ret < 0)
+			return ret;
+
+		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0);
+		if (ret < 0)
+			return ret;
+
+		/* enable AD change interrupts interrupts */
+		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI,
+						ADV7180_IRQ3_AD_CHANGE);
+		if (ret < 0)
+			return ret;
+
+		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0);
+		if (ret < 0)
+			return ret;
+
+		ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
+						0);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static __devinit int adv7180_probe(struct i2c_client *client,
+				   const struct i2c_device_id *id)
+{
+	struct adv7180_state *state;
+	struct v4l2_subdev *sd;
+	int ret;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%02x (%s)\n",
+		 client->addr, client->adapter->name);
+
+	state = kzalloc(sizeof(struct adv7180_state), GFP_KERNEL);
+	if (state == NULL) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	state->irq = client->irq;
+	INIT_WORK(&state->work, adv7180_work);
+	mutex_init(&state->mutex);
+	state->autodetect = true;
+	state->input = 0;
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
+
+	ret = adv7180_init_controls(state);
+	if (ret)
+		goto err_unreg_subdev;
+	ret = init_device(client, state);
+	if (ret)
+		goto err_free_ctrl;
+	return 0;
+
+err_free_ctrl:
+	adv7180_exit_controls(state);
+err_unreg_subdev:
+	mutex_destroy(&state->mutex);
+	v4l2_device_unregister_subdev(sd);
+	kfree(state);
+err:
+	printk(KERN_ERR KBUILD_MODNAME ": Failed to probe: %d\n", ret);
+	return ret;
+}
+
+static __devexit int adv7180_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct adv7180_state *state = to_state(sd);
+
+	if (state->irq > 0) {
+		free_irq(client->irq, state);
+		if (cancel_work_sync(&state->work)) {
+			/*
+			 * Work was pending, therefore we need to enable
+			 * IRQ here to balance the disable_irq() done in the
+			 * interrupt handler.
+			 */
+			enable_irq(state->irq);
+		}
+	}
+
+	mutex_destroy(&state->mutex);
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_state(sd));
+	return 0;
+}
+
+static const struct i2c_device_id adv7180_id[] = {
+	{KBUILD_MODNAME, 0},
+	{},
+};
+
+#ifdef CONFIG_PM
+static int adv7180_suspend(struct i2c_client *client, pm_message_t state)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG,
+					ADV7180_PWR_MAN_OFF);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+static int adv7180_resume(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct adv7180_state *state = to_state(sd);
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG,
+					ADV7180_PWR_MAN_ON);
+	if (ret < 0)
+		return ret;
+	ret = init_device(client, state);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+#endif
+
+MODULE_DEVICE_TABLE(i2c, adv7180_id);
+
+static struct i2c_driver adv7180_driver = {
+	.driver = {
+		   .owner = THIS_MODULE,
+		   .name = KBUILD_MODNAME,
+		   },
+	.probe = adv7180_probe,
+	.remove = __devexit_p(adv7180_remove),
+#ifdef CONFIG_PM
+	.suspend = adv7180_suspend,
+	.resume = adv7180_resume,
+#endif
+	.id_table = adv7180_id,
+};
+
+module_i2c_driver(adv7180_driver);
+
+MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver");
+MODULE_AUTHOR("Mocean Laboratories");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c
new file mode 100644
index 0000000..e1d4c89
--- /dev/null
+++ b/drivers/media/i2c/adv7183.c
@@ -0,0 +1,699 @@
+/*
+ * adv7183.c Analog Devices ADV7183 video decoder driver
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/adv7183.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+
+#include "adv7183_regs.h"
+
+struct adv7183 {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+
+	v4l2_std_id std; /* Current set standard */
+	u32 input;
+	u32 output;
+	unsigned reset_pin;
+	unsigned oe_pin;
+	struct v4l2_mbus_framefmt fmt;
+};
+
+/* EXAMPLES USING 27 MHz CLOCK
+ * Mode 1 CVBS Input (Composite Video on AIN5)
+ * All standards are supported through autodetect, 8-bit, 4:2:2, ITU-R BT.656 output on P15 to P8.
+ */
+static const unsigned char adv7183_init_regs[] = {
+	ADV7183_IN_CTRL, 0x04,           /* CVBS input on AIN5 */
+	ADV7183_DIGI_CLAMP_CTRL_1, 0x00, /* Slow down digital clamps */
+	ADV7183_SHAP_FILT_CTRL, 0x41,    /* Set CSFM to SH1 */
+	ADV7183_ADC_CTRL, 0x16,          /* Power down ADC 1 and ADC 2 */
+	ADV7183_CTI_DNR_CTRL_4, 0x04,    /* Set DNR threshold to 4 for flat response */
+	/* ADI recommended programming sequence */
+	ADV7183_ADI_CTRL, 0x80,
+	ADV7183_CTI_DNR_CTRL_4, 0x20,
+	0x52, 0x18,
+	0x58, 0xED,
+	0x77, 0xC5,
+	0x7C, 0x93,
+	0x7D, 0x00,
+	0xD0, 0x48,
+	0xD5, 0xA0,
+	0xD7, 0xEA,
+	ADV7183_SD_SATURATION_CR, 0x3E,
+	ADV7183_PAL_V_END, 0x3E,
+	ADV7183_PAL_F_TOGGLE, 0x0F,
+	ADV7183_ADI_CTRL, 0x00,
+};
+
+static inline struct adv7183 *to_adv7183(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct adv7183, sd);
+}
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct adv7183, hdl)->sd;
+}
+
+static inline int adv7183_read(struct v4l2_subdev *sd, unsigned char reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static inline int adv7183_write(struct v4l2_subdev *sd, unsigned char reg,
+				unsigned char value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int adv7183_writeregs(struct v4l2_subdev *sd,
+		const unsigned char *regs, unsigned int num)
+{
+	unsigned char reg, data;
+	unsigned int cnt = 0;
+
+	if (num & 0x1) {
+		v4l2_err(sd, "invalid regs array\n");
+		return -1;
+	}
+
+	while (cnt < num) {
+		reg = *regs++;
+		data = *regs++;
+		cnt += 2;
+
+		adv7183_write(sd, reg, data);
+	}
+	return 0;
+}
+
+static int adv7183_log_status(struct v4l2_subdev *sd)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+
+	v4l2_info(sd, "adv7183: Input control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_IN_CTRL));
+	v4l2_info(sd, "adv7183: Video selection = 0x%02x\n",
+			adv7183_read(sd, ADV7183_VD_SEL));
+	v4l2_info(sd, "adv7183: Output control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_OUT_CTRL));
+	v4l2_info(sd, "adv7183: Extended output control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_EXT_OUT_CTRL));
+	v4l2_info(sd, "adv7183: Autodetect enable = 0x%02x\n",
+			adv7183_read(sd, ADV7183_AUTO_DET_EN));
+	v4l2_info(sd, "adv7183: Contrast = 0x%02x\n",
+			adv7183_read(sd, ADV7183_CONTRAST));
+	v4l2_info(sd, "adv7183: Brightness = 0x%02x\n",
+			adv7183_read(sd, ADV7183_BRIGHTNESS));
+	v4l2_info(sd, "adv7183: Hue = 0x%02x\n",
+			adv7183_read(sd, ADV7183_HUE));
+	v4l2_info(sd, "adv7183: Default value Y = 0x%02x\n",
+			adv7183_read(sd, ADV7183_DEF_Y));
+	v4l2_info(sd, "adv7183: Default value C = 0x%02x\n",
+			adv7183_read(sd, ADV7183_DEF_C));
+	v4l2_info(sd, "adv7183: ADI control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_ADI_CTRL));
+	v4l2_info(sd, "adv7183: Power Management = 0x%02x\n",
+			adv7183_read(sd, ADV7183_POW_MANAGE));
+	v4l2_info(sd, "adv7183: Status 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
+			adv7183_read(sd, ADV7183_STATUS_1),
+			adv7183_read(sd, ADV7183_STATUS_2),
+			adv7183_read(sd, ADV7183_STATUS_3));
+	v4l2_info(sd, "adv7183: Ident = 0x%02x\n",
+			adv7183_read(sd, ADV7183_IDENT));
+	v4l2_info(sd, "adv7183: Analog clamp control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_ANAL_CLAMP_CTRL));
+	v4l2_info(sd, "adv7183: Digital clamp control 1 = 0x%02x\n",
+			adv7183_read(sd, ADV7183_DIGI_CLAMP_CTRL_1));
+	v4l2_info(sd, "adv7183: Shaping filter control 1 and 2 = 0x%02x 0x%02x\n",
+			adv7183_read(sd, ADV7183_SHAP_FILT_CTRL),
+			adv7183_read(sd, ADV7183_SHAP_FILT_CTRL_2));
+	v4l2_info(sd, "adv7183: Comb filter control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_COMB_FILT_CTRL));
+	v4l2_info(sd, "adv7183: ADI control 2 = 0x%02x\n",
+			adv7183_read(sd, ADV7183_ADI_CTRL_2));
+	v4l2_info(sd, "adv7183: Pixel delay control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_PIX_DELAY_CTRL));
+	v4l2_info(sd, "adv7183: Misc gain control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_MISC_GAIN_CTRL));
+	v4l2_info(sd, "adv7183: AGC mode control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_AGC_MODE_CTRL));
+	v4l2_info(sd, "adv7183: Chroma gain control 1 and 2 = 0x%02x 0x%02x\n",
+			adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_1),
+			adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_2));
+	v4l2_info(sd, "adv7183: Luma gain control 1 and 2 = 0x%02x 0x%02x\n",
+			adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_1),
+			adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_2));
+	v4l2_info(sd, "adv7183: Vsync field control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
+			adv7183_read(sd, ADV7183_VS_FIELD_CTRL_1),
+			adv7183_read(sd, ADV7183_VS_FIELD_CTRL_2),
+			adv7183_read(sd, ADV7183_VS_FIELD_CTRL_3));
+	v4l2_info(sd, "adv7183: Hsync positon control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
+			adv7183_read(sd, ADV7183_HS_POS_CTRL_1),
+			adv7183_read(sd, ADV7183_HS_POS_CTRL_2),
+			adv7183_read(sd, ADV7183_HS_POS_CTRL_3));
+	v4l2_info(sd, "adv7183: Polarity = 0x%02x\n",
+			adv7183_read(sd, ADV7183_POLARITY));
+	v4l2_info(sd, "adv7183: ADC control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_ADC_CTRL));
+	v4l2_info(sd, "adv7183: SD offset Cb and Cr = 0x%02x 0x%02x\n",
+			adv7183_read(sd, ADV7183_SD_OFFSET_CB),
+			adv7183_read(sd, ADV7183_SD_OFFSET_CR));
+	v4l2_info(sd, "adv7183: SD saturation Cb and Cr = 0x%02x 0x%02x\n",
+			adv7183_read(sd, ADV7183_SD_SATURATION_CB),
+			adv7183_read(sd, ADV7183_SD_SATURATION_CR));
+	v4l2_info(sd, "adv7183: Drive strength = 0x%02x\n",
+			adv7183_read(sd, ADV7183_DRIVE_STR));
+	v4l2_ctrl_handler_log_status(&decoder->hdl, sd->name);
+	return 0;
+}
+
+static int adv7183_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+
+	*std = decoder->std;
+	return 0;
+}
+
+static int adv7183_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+	int reg;
+
+	reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF;
+	if (std == V4L2_STD_PAL_60)
+		reg |= 0x60;
+	else if (std == V4L2_STD_NTSC_443)
+		reg |= 0x70;
+	else if (std == V4L2_STD_PAL_N)
+		reg |= 0x90;
+	else if (std == V4L2_STD_PAL_M)
+		reg |= 0xA0;
+	else if (std == V4L2_STD_PAL_Nc)
+		reg |= 0xC0;
+	else if (std & V4L2_STD_PAL)
+		reg |= 0x80;
+	else if (std & V4L2_STD_NTSC)
+		reg |= 0x50;
+	else if (std & V4L2_STD_SECAM)
+		reg |= 0xE0;
+	else
+		return -EINVAL;
+	adv7183_write(sd, ADV7183_IN_CTRL, reg);
+
+	decoder->std = std;
+
+	return 0;
+}
+
+static int adv7183_reset(struct v4l2_subdev *sd, u32 val)
+{
+	int reg;
+
+	reg = adv7183_read(sd, ADV7183_POW_MANAGE) | 0x80;
+	adv7183_write(sd, ADV7183_POW_MANAGE, reg);
+	/* wait 5ms before any further i2c writes are performed */
+	usleep_range(5000, 10000);
+	return 0;
+}
+
+static int adv7183_s_routing(struct v4l2_subdev *sd,
+				u32 input, u32 output, u32 config)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+	int reg;
+
+	if ((input > ADV7183_COMPONENT1) || (output > ADV7183_16BIT_OUT))
+		return -EINVAL;
+
+	if (input != decoder->input) {
+		decoder->input = input;
+		reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF0;
+		switch (input) {
+		case ADV7183_COMPOSITE1:
+			reg |= 0x1;
+			break;
+		case ADV7183_COMPOSITE2:
+			reg |= 0x2;
+			break;
+		case ADV7183_COMPOSITE3:
+			reg |= 0x3;
+			break;
+		case ADV7183_COMPOSITE4:
+			reg |= 0x4;
+			break;
+		case ADV7183_COMPOSITE5:
+			reg |= 0x5;
+			break;
+		case ADV7183_COMPOSITE6:
+			reg |= 0xB;
+			break;
+		case ADV7183_COMPOSITE7:
+			reg |= 0xC;
+			break;
+		case ADV7183_COMPOSITE8:
+			reg |= 0xD;
+			break;
+		case ADV7183_COMPOSITE9:
+			reg |= 0xE;
+			break;
+		case ADV7183_COMPOSITE10:
+			reg |= 0xF;
+			break;
+		case ADV7183_SVIDEO0:
+			reg |= 0x6;
+			break;
+		case ADV7183_SVIDEO1:
+			reg |= 0x7;
+			break;
+		case ADV7183_SVIDEO2:
+			reg |= 0x8;
+			break;
+		case ADV7183_COMPONENT0:
+			reg |= 0x9;
+			break;
+		case ADV7183_COMPONENT1:
+			reg |= 0xA;
+			break;
+		default:
+			break;
+		}
+		adv7183_write(sd, ADV7183_IN_CTRL, reg);
+	}
+
+	if (output != decoder->output) {
+		decoder->output = output;
+		reg = adv7183_read(sd, ADV7183_OUT_CTRL) & 0xC0;
+		switch (output) {
+		case ADV7183_16BIT_OUT:
+			reg |= 0x9;
+			break;
+		default:
+			reg |= 0xC;
+			break;
+		}
+		adv7183_write(sd, ADV7183_OUT_CTRL, reg);
+	}
+
+	return 0;
+}
+
+static int adv7183_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	int val = ctrl->val;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		if (val < 0)
+			val = 127 - val;
+		adv7183_write(sd, ADV7183_BRIGHTNESS, val);
+		break;
+	case V4L2_CID_CONTRAST:
+		adv7183_write(sd, ADV7183_CONTRAST, val);
+		break;
+	case V4L2_CID_SATURATION:
+		adv7183_write(sd, ADV7183_SD_SATURATION_CB, val >> 8);
+		adv7183_write(sd, ADV7183_SD_SATURATION_CR, (val & 0xFF));
+		break;
+	case V4L2_CID_HUE:
+		adv7183_write(sd, ADV7183_SD_OFFSET_CB, val >> 8);
+		adv7183_write(sd, ADV7183_SD_OFFSET_CR, (val & 0xFF));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int adv7183_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+	int reg;
+
+	/* enable autodetection block */
+	reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF;
+	adv7183_write(sd, ADV7183_IN_CTRL, reg);
+
+	/* wait autodetection switch */
+	mdelay(10);
+
+	/* get autodetection result */
+	reg = adv7183_read(sd, ADV7183_STATUS_1);
+	switch ((reg >> 0x4) & 0x7) {
+	case 0:
+		*std = V4L2_STD_NTSC;
+		break;
+	case 1:
+		*std = V4L2_STD_NTSC_443;
+		break;
+	case 2:
+		*std = V4L2_STD_PAL_M;
+		break;
+	case 3:
+		*std = V4L2_STD_PAL_60;
+		break;
+	case 4:
+		*std = V4L2_STD_PAL;
+		break;
+	case 5:
+		*std = V4L2_STD_SECAM;
+		break;
+	case 6:
+		*std = V4L2_STD_PAL_Nc;
+		break;
+	case 7:
+		*std = V4L2_STD_SECAM;
+		break;
+	default:
+		*std = V4L2_STD_UNKNOWN;
+		break;
+	}
+
+	/* after std detection, write back user set std */
+	adv7183_s_std(sd, decoder->std);
+	return 0;
+}
+
+static int adv7183_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+	int reg;
+
+	*status = V4L2_IN_ST_NO_SIGNAL;
+	reg = adv7183_read(sd, ADV7183_STATUS_1);
+	if (reg < 0)
+		return reg;
+	if (reg & 0x1)
+		*status = 0;
+	return 0;
+}
+
+static int adv7183_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+				enum v4l2_mbus_pixelcode *code)
+{
+	if (index > 0)
+		return -EINVAL;
+
+	*code = V4L2_MBUS_FMT_UYVY8_2X8;
+	return 0;
+}
+
+static int adv7183_try_mbus_fmt(struct v4l2_subdev *sd,
+				struct v4l2_mbus_framefmt *fmt)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+
+	fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
+	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	if (decoder->std & V4L2_STD_525_60) {
+		fmt->field = V4L2_FIELD_SEQ_TB;
+		fmt->width = 720;
+		fmt->height = 480;
+	} else {
+		fmt->field = V4L2_FIELD_SEQ_BT;
+		fmt->width = 720;
+		fmt->height = 576;
+	}
+	return 0;
+}
+
+static int adv7183_s_mbus_fmt(struct v4l2_subdev *sd,
+				struct v4l2_mbus_framefmt *fmt)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+
+	adv7183_try_mbus_fmt(sd, fmt);
+	decoder->fmt = *fmt;
+	return 0;
+}
+
+static int adv7183_g_mbus_fmt(struct v4l2_subdev *sd,
+				struct v4l2_mbus_framefmt *fmt)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+
+	*fmt = decoder->fmt;
+	return 0;
+}
+
+static int adv7183_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+
+	if (enable)
+		gpio_direction_output(decoder->oe_pin, 0);
+	else
+		gpio_direction_output(decoder->oe_pin, 1);
+	udelay(1);
+	return 0;
+}
+
+static int adv7183_g_chip_ident(struct v4l2_subdev *sd,
+		struct v4l2_dbg_chip_ident *chip)
+{
+	int rev;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	/* 0x11 for adv7183, 0x13 for adv7183b */
+	rev = adv7183_read(sd, ADV7183_IDENT);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7183, rev);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	reg->val = adv7183_read(sd, reg->reg & 0xff);
+	reg->size = 1;
+	return 0;
+}
+
+static int adv7183_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	adv7183_write(sd, reg->reg & 0xff, reg->val & 0xff);
+	return 0;
+}
+#endif
+
+static const struct v4l2_ctrl_ops adv7183_ctrl_ops = {
+	.s_ctrl = adv7183_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops adv7183_core_ops = {
+	.log_status = adv7183_log_status,
+	.g_std = adv7183_g_std,
+	.s_std = adv7183_s_std,
+	.reset = adv7183_reset,
+	.g_chip_ident = adv7183_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = adv7183_g_register,
+	.s_register = adv7183_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops adv7183_video_ops = {
+	.s_routing = adv7183_s_routing,
+	.querystd = adv7183_querystd,
+	.g_input_status = adv7183_g_input_status,
+	.enum_mbus_fmt = adv7183_enum_mbus_fmt,
+	.try_mbus_fmt = adv7183_try_mbus_fmt,
+	.s_mbus_fmt = adv7183_s_mbus_fmt,
+	.g_mbus_fmt = adv7183_g_mbus_fmt,
+	.s_stream = adv7183_s_stream,
+};
+
+static const struct v4l2_subdev_ops adv7183_ops = {
+	.core = &adv7183_core_ops,
+	.video = &adv7183_video_ops,
+};
+
+static int adv7183_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct adv7183 *decoder;
+	struct v4l2_subdev *sd;
+	struct v4l2_ctrl_handler *hdl;
+	int ret;
+	struct v4l2_mbus_framefmt fmt;
+	const unsigned *pin_array;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%02x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	pin_array = client->dev.platform_data;
+	if (pin_array == NULL)
+		return -EINVAL;
+
+	decoder = kzalloc(sizeof(struct adv7183), GFP_KERNEL);
+	if (decoder == NULL)
+		return -ENOMEM;
+
+	decoder->reset_pin = pin_array[0];
+	decoder->oe_pin = pin_array[1];
+
+	if (gpio_request(decoder->reset_pin, "ADV7183 Reset")) {
+		v4l_err(client, "failed to request GPIO %d\n", decoder->reset_pin);
+		ret = -EBUSY;
+		goto err_free_decoder;
+	}
+
+	if (gpio_request(decoder->oe_pin, "ADV7183 Output Enable")) {
+		v4l_err(client, "failed to request GPIO %d\n", decoder->oe_pin);
+		ret = -EBUSY;
+		goto err_free_reset;
+	}
+
+	sd = &decoder->sd;
+	v4l2_i2c_subdev_init(sd, client, &adv7183_ops);
+
+	hdl = &decoder->hdl;
+	v4l2_ctrl_handler_init(hdl, 4);
+	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
+	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x80);
+	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 0xFFFF, 1, 0x8080);
+	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
+			V4L2_CID_HUE, 0, 0xFFFF, 1, 0x8080);
+	/* hook the control handler into the driver */
+	sd->ctrl_handler = hdl;
+	if (hdl->error) {
+		ret = hdl->error;
+
+		v4l2_ctrl_handler_free(hdl);
+		goto err_free_oe;
+	}
+
+	/* v4l2 doesn't support an autodetect standard, pick PAL as default */
+	decoder->std = V4L2_STD_PAL;
+	decoder->input = ADV7183_COMPOSITE4;
+	decoder->output = ADV7183_8BIT_OUT;
+
+	gpio_direction_output(decoder->oe_pin, 1);
+	/* reset chip */
+	gpio_direction_output(decoder->reset_pin, 0);
+	/* reset pulse width at least 5ms */
+	mdelay(10);
+	gpio_direction_output(decoder->reset_pin, 1);
+	/* wait 5ms before any further i2c writes are performed */
+	mdelay(5);
+
+	adv7183_writeregs(sd, adv7183_init_regs, ARRAY_SIZE(adv7183_init_regs));
+	adv7183_s_std(sd, decoder->std);
+	fmt.width = 720;
+	fmt.height = 576;
+	adv7183_s_mbus_fmt(sd, &fmt);
+
+	/* initialize the hardware to the default control values */
+	ret = v4l2_ctrl_handler_setup(hdl);
+	if (ret) {
+		v4l2_ctrl_handler_free(hdl);
+		goto err_free_oe;
+	}
+
+	return 0;
+err_free_oe:
+	gpio_free(decoder->oe_pin);
+err_free_reset:
+	gpio_free(decoder->reset_pin);
+err_free_decoder:
+	kfree(decoder);
+	return ret;
+}
+
+static int adv7183_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct adv7183 *decoder = to_adv7183(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(sd->ctrl_handler);
+	gpio_free(decoder->oe_pin);
+	gpio_free(decoder->reset_pin);
+	kfree(decoder);
+	return 0;
+}
+
+static const struct i2c_device_id adv7183_id[] = {
+	{"adv7183", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, adv7183_id);
+
+static struct i2c_driver adv7183_driver = {
+	.driver = {
+		.owner  = THIS_MODULE,
+		.name   = "adv7183",
+	},
+	.probe          = adv7183_probe,
+	.remove         = __devexit_p(adv7183_remove),
+	.id_table       = adv7183_id,
+};
+
+static __init int adv7183_init(void)
+{
+	return i2c_add_driver(&adv7183_driver);
+}
+
+static __exit void adv7183_exit(void)
+{
+	i2c_del_driver(&adv7183_driver);
+}
+
+module_init(adv7183_init);
+module_exit(adv7183_exit);
+
+MODULE_DESCRIPTION("Analog Devices ADV7183 video decoder driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/adv7183_regs.h b/drivers/media/i2c/adv7183_regs.h
new file mode 100644
index 0000000..4a5b7d2
--- /dev/null
+++ b/drivers/media/i2c/adv7183_regs.h
@@ -0,0 +1,107 @@
+/*
+ * adv7183 - Analog Devices ADV7183 video decoder registers
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _ADV7183_REGS_H_
+#define _ADV7183_REGS_H_
+
+#define ADV7183_IN_CTRL            0x00 /* Input control */
+#define ADV7183_VD_SEL             0x01 /* Video selection */
+#define ADV7183_OUT_CTRL           0x03 /* Output control */
+#define ADV7183_EXT_OUT_CTRL       0x04 /* Extended output control */
+#define ADV7183_AUTO_DET_EN        0x07 /* Autodetect enable */
+#define ADV7183_CONTRAST           0x08 /* Contrast */
+#define ADV7183_BRIGHTNESS         0x0A /* Brightness */
+#define ADV7183_HUE                0x0B /* Hue */
+#define ADV7183_DEF_Y              0x0C /* Default value Y */
+#define ADV7183_DEF_C              0x0D /* Default value C */
+#define ADV7183_ADI_CTRL           0x0E /* ADI control */
+#define ADV7183_POW_MANAGE         0x0F /* Power Management */
+#define ADV7183_STATUS_1           0x10 /* Status 1 */
+#define ADV7183_IDENT              0x11 /* Ident */
+#define ADV7183_STATUS_2           0x12 /* Status 2 */
+#define ADV7183_STATUS_3           0x13 /* Status 3 */
+#define ADV7183_ANAL_CLAMP_CTRL    0x14 /* Analog clamp control */
+#define ADV7183_DIGI_CLAMP_CTRL_1  0x15 /* Digital clamp control 1 */
+#define ADV7183_SHAP_FILT_CTRL     0x17 /* Shaping filter control */
+#define ADV7183_SHAP_FILT_CTRL_2   0x18 /* Shaping filter control 2 */
+#define ADV7183_COMB_FILT_CTRL     0x19 /* Comb filter control */
+#define ADV7183_ADI_CTRL_2         0x1D /* ADI control 2 */
+#define ADV7183_PIX_DELAY_CTRL     0x27 /* Pixel delay control */
+#define ADV7183_MISC_GAIN_CTRL     0x2B /* Misc gain control */
+#define ADV7183_AGC_MODE_CTRL      0x2C /* AGC mode control */
+#define ADV7183_CHRO_GAIN_CTRL_1   0x2D /* Chroma gain control 1 */
+#define ADV7183_CHRO_GAIN_CTRL_2   0x2E /* Chroma gain control 2 */
+#define ADV7183_LUMA_GAIN_CTRL_1   0x2F /* Luma gain control 1 */
+#define ADV7183_LUMA_GAIN_CTRL_2   0x30 /* Luma gain control 2 */
+#define ADV7183_VS_FIELD_CTRL_1    0x31 /* Vsync field control 1 */
+#define ADV7183_VS_FIELD_CTRL_2    0x32 /* Vsync field control 2 */
+#define ADV7183_VS_FIELD_CTRL_3    0x33 /* Vsync field control 3 */
+#define ADV7183_HS_POS_CTRL_1      0x34 /* Hsync positon control 1 */
+#define ADV7183_HS_POS_CTRL_2      0x35 /* Hsync positon control 2 */
+#define ADV7183_HS_POS_CTRL_3      0x36 /* Hsync positon control 3 */
+#define ADV7183_POLARITY           0x37 /* Polarity */
+#define ADV7183_NTSC_COMB_CTRL     0x38 /* NTSC comb control */
+#define ADV7183_PAL_COMB_CTRL      0x39 /* PAL comb control */
+#define ADV7183_ADC_CTRL           0x3A /* ADC control */
+#define ADV7183_MAN_WIN_CTRL       0x3D /* Manual window control */
+#define ADV7183_RESAMPLE_CTRL      0x41 /* Resample control */
+#define ADV7183_GEMSTAR_CTRL_1     0x48 /* Gemstar ctrl 1 */
+#define ADV7183_GEMSTAR_CTRL_2     0x49 /* Gemstar ctrl 2 */
+#define ADV7183_GEMSTAR_CTRL_3     0x4A /* Gemstar ctrl 3 */
+#define ADV7183_GEMSTAR_CTRL_4     0x4B /* Gemstar ctrl 4 */
+#define ADV7183_GEMSTAR_CTRL_5     0x4C /* Gemstar ctrl 5 */
+#define ADV7183_CTI_DNR_CTRL_1     0x4D /* CTI DNR ctrl 1 */
+#define ADV7183_CTI_DNR_CTRL_2     0x4E /* CTI DNR ctrl 2 */
+#define ADV7183_CTI_DNR_CTRL_4     0x50 /* CTI DNR ctrl 4 */
+#define ADV7183_LOCK_CNT           0x51 /* Lock count */
+#define ADV7183_FREE_LINE_LEN      0x8F /* Free-Run line length 1 */
+#define ADV7183_VBI_INFO           0x90 /* VBI info */
+#define ADV7183_WSS_1              0x91 /* WSS 1 */
+#define ADV7183_WSS_2              0x92 /* WSS 2 */
+#define ADV7183_EDTV_1             0x93 /* EDTV 1 */
+#define ADV7183_EDTV_2             0x94 /* EDTV 2 */
+#define ADV7183_EDTV_3             0x95 /* EDTV 3 */
+#define ADV7183_CGMS_1             0x96 /* CGMS 1 */
+#define ADV7183_CGMS_2             0x97 /* CGMS 2 */
+#define ADV7183_CGMS_3             0x98 /* CGMS 3 */
+#define ADV7183_CCAP_1             0x99 /* CCAP 1 */
+#define ADV7183_CCAP_2             0x9A /* CCAP 2 */
+#define ADV7183_LETTERBOX_1        0x9B /* Letterbox 1 */
+#define ADV7183_LETTERBOX_2        0x9C /* Letterbox 2 */
+#define ADV7183_LETTERBOX_3        0x9D /* Letterbox 3 */
+#define ADV7183_CRC_EN             0xB2 /* CRC enable */
+#define ADV7183_ADC_SWITCH_1       0xC3 /* ADC switch 1 */
+#define ADV7183_ADC_SWITCH_2       0xC4 /* ADC swithc 2 */
+#define ADV7183_LETTERBOX_CTRL_1   0xDC /* Letterbox control 1 */
+#define ADV7183_LETTERBOX_CTRL_2   0xDD /* Letterbox control 2 */
+#define ADV7183_SD_OFFSET_CB       0xE1 /* SD offset Cb */
+#define ADV7183_SD_OFFSET_CR       0xE2 /* SD offset Cr */
+#define ADV7183_SD_SATURATION_CB   0xE3 /* SD saturation Cb */
+#define ADV7183_SD_SATURATION_CR   0xE4 /* SD saturation Cr */
+#define ADV7183_NTSC_V_BEGIN       0xE5 /* NTSC V bit begin */
+#define ADV7183_NTSC_V_END         0xE6 /* NTSC V bit end */
+#define ADV7183_NTSC_F_TOGGLE      0xE7 /* NTSC F bit toggle */
+#define ADV7183_PAL_V_BEGIN        0xE8 /* PAL V bit begin */
+#define ADV7183_PAL_V_END          0xE9 /* PAL V bit end */
+#define ADV7183_PAL_F_TOGGLE       0xEA /* PAL F bit toggle */
+#define ADV7183_DRIVE_STR          0xF4 /* Drive strength */
+#define ADV7183_IF_COMP_CTRL       0xF8 /* IF comp control */
+#define ADV7183_VS_MODE_CTRL       0xF9 /* VS mode control */
+
+#endif
diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c
new file mode 100644
index 0000000..2b5aa67
--- /dev/null
+++ b/drivers/media/i2c/adv7343.c
@@ -0,0 +1,476 @@
+/*
+ * adv7343 - ADV7343 Video Encoder Driver
+ *
+ * The encoder hardware does not support SECAM.
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; 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/init.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <linux/uaccess.h>
+
+#include <media/adv7343.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+#include "adv7343_regs.h"
+
+MODULE_DESCRIPTION("ADV7343 video encoder driver");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+
+struct adv7343_state {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	u8 reg00;
+	u8 reg01;
+	u8 reg02;
+	u8 reg35;
+	u8 reg80;
+	u8 reg82;
+	u32 output;
+	v4l2_std_id std;
+};
+
+static inline struct adv7343_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct adv7343_state, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct adv7343_state, hdl)->sd;
+}
+
+static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static const u8 adv7343_init_reg_val[] = {
+	ADV7343_SOFT_RESET, ADV7343_SOFT_RESET_DEFAULT,
+	ADV7343_POWER_MODE_REG, ADV7343_POWER_MODE_REG_DEFAULT,
+
+	ADV7343_HD_MODE_REG1, ADV7343_HD_MODE_REG1_DEFAULT,
+	ADV7343_HD_MODE_REG2, ADV7343_HD_MODE_REG2_DEFAULT,
+	ADV7343_HD_MODE_REG3, ADV7343_HD_MODE_REG3_DEFAULT,
+	ADV7343_HD_MODE_REG4, ADV7343_HD_MODE_REG4_DEFAULT,
+	ADV7343_HD_MODE_REG5, ADV7343_HD_MODE_REG5_DEFAULT,
+	ADV7343_HD_MODE_REG6, ADV7343_HD_MODE_REG6_DEFAULT,
+	ADV7343_HD_MODE_REG7, ADV7343_HD_MODE_REG7_DEFAULT,
+
+	ADV7343_SD_MODE_REG1, ADV7343_SD_MODE_REG1_DEFAULT,
+	ADV7343_SD_MODE_REG2, ADV7343_SD_MODE_REG2_DEFAULT,
+	ADV7343_SD_MODE_REG3, ADV7343_SD_MODE_REG3_DEFAULT,
+	ADV7343_SD_MODE_REG4, ADV7343_SD_MODE_REG4_DEFAULT,
+	ADV7343_SD_MODE_REG5, ADV7343_SD_MODE_REG5_DEFAULT,
+	ADV7343_SD_MODE_REG6, ADV7343_SD_MODE_REG6_DEFAULT,
+	ADV7343_SD_MODE_REG7, ADV7343_SD_MODE_REG7_DEFAULT,
+	ADV7343_SD_MODE_REG8, ADV7343_SD_MODE_REG8_DEFAULT,
+
+	ADV7343_SD_HUE_REG, ADV7343_SD_HUE_REG_DEFAULT,
+	ADV7343_SD_CGMS_WSS0, ADV7343_SD_CGMS_WSS0_DEFAULT,
+	ADV7343_SD_BRIGHTNESS_WSS, ADV7343_SD_BRIGHTNESS_WSS_DEFAULT,
+};
+
+/*
+ * 			    2^32
+ * FSC(reg) =  FSC (HZ) * --------
+ *			  27000000
+ */
+static const struct adv7343_std_info stdinfo[] = {
+	{
+		/* FSC(Hz) = 3,579,545.45 Hz */
+		SD_STD_NTSC, 569408542, V4L2_STD_NTSC,
+	}, {
+		/* FSC(Hz) = 3,575,611.00 Hz */
+		SD_STD_PAL_M, 568782678, V4L2_STD_PAL_M,
+	}, {
+		/* FSC(Hz) = 3,582,056.00 */
+		SD_STD_PAL_N, 569807903, V4L2_STD_PAL_Nc,
+	}, {
+		/* FSC(Hz) = 4,433,618.75 Hz */
+		SD_STD_PAL_N, 705268427, V4L2_STD_PAL_N,
+	}, {
+		/* FSC(Hz) = 4,433,618.75 Hz */
+		SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL,
+	}, {
+		/* FSC(Hz) = 4,433,618.75 Hz */
+		SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443,
+	}, {
+		/* FSC(Hz) = 4,433,618.75 Hz */
+		SD_STD_PAL_M, 705268427, V4L2_STD_PAL_60,
+	},
+};
+
+static int adv7343_setstd(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct adv7343_state *state = to_state(sd);
+	struct adv7343_std_info *std_info;
+	int num_std;
+	char *fsc_ptr;
+	u8 reg, val;
+	int err = 0;
+	int i = 0;
+
+	std_info = (struct adv7343_std_info *)stdinfo;
+	num_std = ARRAY_SIZE(stdinfo);
+
+	for (i = 0; i < num_std; i++) {
+		if (std_info[i].stdid & std)
+			break;
+	}
+
+	if (i == num_std) {
+		v4l2_dbg(1, debug, sd,
+				"Invalid std or std is not supported: %llx\n",
+						(unsigned long long)std);
+		return -EINVAL;
+	}
+
+	/* Set the standard */
+	val = state->reg80 & (~(SD_STD_MASK));
+	val |= std_info[i].standard_val3;
+	err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val);
+	if (err < 0)
+		goto setstd_exit;
+
+	state->reg80 = val;
+
+	/* Configure the input mode register */
+	val = state->reg01 & (~((u8) INPUT_MODE_MASK));
+	val |= SD_INPUT_MODE;
+	err = adv7343_write(sd, ADV7343_MODE_SELECT_REG, val);
+	if (err < 0)
+		goto setstd_exit;
+
+	state->reg01 = val;
+
+	/* Program the sub carrier frequency registers */
+	fsc_ptr = (unsigned char *)&std_info[i].fsc_val;
+	reg = ADV7343_FSC_REG0;
+	for (i = 0; i < 4; i++, reg++, fsc_ptr++) {
+		err = adv7343_write(sd, reg, *fsc_ptr);
+		if (err < 0)
+			goto setstd_exit;
+	}
+
+	val = state->reg80;
+
+	/* Filter settings */
+	if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443))
+		val &= 0x03;
+	else if (std & ~V4L2_STD_SECAM)
+		val |= 0x04;
+
+	err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val);
+	if (err < 0)
+		goto setstd_exit;
+
+	state->reg80 = val;
+
+setstd_exit:
+	if (err != 0)
+		v4l2_err(sd, "Error setting std, write failed\n");
+
+	return err;
+}
+
+static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type)
+{
+	struct adv7343_state *state = to_state(sd);
+	unsigned char val;
+	int err = 0;
+
+	if (output_type > ADV7343_SVIDEO_ID) {
+		v4l2_dbg(1, debug, sd,
+			"Invalid output type or output type not supported:%d\n",
+								output_type);
+		return -EINVAL;
+	}
+
+	/* Enable Appropriate DAC */
+	val = state->reg00 & 0x03;
+
+	if (output_type == ADV7343_COMPOSITE_ID)
+		val |= ADV7343_COMPOSITE_POWER_VALUE;
+	else if (output_type == ADV7343_COMPONENT_ID)
+		val |= ADV7343_COMPONENT_POWER_VALUE;
+	else
+		val |= ADV7343_SVIDEO_POWER_VALUE;
+
+	err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val);
+	if (err < 0)
+		goto setoutput_exit;
+
+	state->reg00 = val;
+
+	/* Enable YUV output */
+	val = state->reg02 | YUV_OUTPUT_SELECT;
+	err = adv7343_write(sd, ADV7343_MODE_REG0, val);
+	if (err < 0)
+		goto setoutput_exit;
+
+	state->reg02 = val;
+
+	/* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */
+	val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI);
+	err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val);
+	if (err < 0)
+		goto setoutput_exit;
+
+	state->reg82 = val;
+
+	/* configure ED/HD Color DAC Swap and ED/HD RGB Input Enable bit to
+	 * zero */
+	val = state->reg35 & (HD_RGB_INPUT_DI & HD_DAC_SWAP_DI);
+	err = adv7343_write(sd, ADV7343_HD_MODE_REG6, val);
+	if (err < 0)
+		goto setoutput_exit;
+
+	state->reg35 = val;
+
+setoutput_exit:
+	if (err != 0)
+		v4l2_err(sd, "Error setting output, write failed\n");
+
+	return err;
+}
+
+static int adv7343_log_status(struct v4l2_subdev *sd)
+{
+	struct adv7343_state *state = to_state(sd);
+
+	v4l2_info(sd, "Standard: %llx\n", (unsigned long long)state->std);
+	v4l2_info(sd, "Output: %s\n", (state->output == 0) ? "Composite" :
+			((state->output == 1) ? "Component" : "S-Video"));
+	return 0;
+}
+
+static int adv7343_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		return adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS,
+					ctrl->val);
+
+	case V4L2_CID_HUE:
+		return adv7343_write(sd, ADV7343_SD_HUE_REG, ctrl->val);
+
+	case V4L2_CID_GAIN:
+		return adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, ctrl->val);
+	}
+	return -EINVAL;
+}
+
+static int adv7343_g_chip_ident(struct v4l2_subdev *sd,
+				struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0);
+}
+
+static const struct v4l2_ctrl_ops adv7343_ctrl_ops = {
+	.s_ctrl = adv7343_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops adv7343_core_ops = {
+	.log_status = adv7343_log_status,
+	.g_chip_ident = adv7343_g_chip_ident,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+};
+
+static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct adv7343_state *state = to_state(sd);
+	int err = 0;
+
+	if (state->std == std)
+		return 0;
+
+	err = adv7343_setstd(sd, std);
+	if (!err)
+		state->std = std;
+
+	return err;
+}
+
+static int adv7343_s_routing(struct v4l2_subdev *sd,
+		u32 input, u32 output, u32 config)
+{
+	struct adv7343_state *state = to_state(sd);
+	int err = 0;
+
+	if (state->output == output)
+		return 0;
+
+	err = adv7343_setoutput(sd, output);
+	if (!err)
+		state->output = output;
+
+	return err;
+}
+
+static const struct v4l2_subdev_video_ops adv7343_video_ops = {
+	.s_std_output	= adv7343_s_std_output,
+	.s_routing	= adv7343_s_routing,
+};
+
+static const struct v4l2_subdev_ops adv7343_ops = {
+	.core	= &adv7343_core_ops,
+	.video	= &adv7343_video_ops,
+};
+
+static int adv7343_initialize(struct v4l2_subdev *sd)
+{
+	struct adv7343_state *state = to_state(sd);
+	int err = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(adv7343_init_reg_val); i += 2) {
+
+		err = adv7343_write(sd, adv7343_init_reg_val[i],
+					adv7343_init_reg_val[i+1]);
+		if (err) {
+			v4l2_err(sd, "Error initializing\n");
+			return err;
+		}
+	}
+
+	/* Configure for default video standard */
+	err = adv7343_setoutput(sd, state->output);
+	if (err < 0) {
+		v4l2_err(sd, "Error setting output during init\n");
+		return -EINVAL;
+	}
+
+	err = adv7343_setstd(sd, state->std);
+	if (err < 0) {
+		v4l2_err(sd, "Error setting std during init\n");
+		return -EINVAL;
+	}
+
+	return err;
+}
+
+static int adv7343_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	struct adv7343_state *state;
+	int err;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	state = kzalloc(sizeof(struct adv7343_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+
+	state->reg00	= 0x80;
+	state->reg01	= 0x00;
+	state->reg02	= 0x20;
+	state->reg35	= 0x00;
+	state->reg80	= ADV7343_SD_MODE_REG1_DEFAULT;
+	state->reg82	= ADV7343_SD_MODE_REG2_DEFAULT;
+
+	state->output = ADV7343_COMPOSITE_ID;
+	state->std = V4L2_STD_NTSC;
+
+	v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops);
+
+	v4l2_ctrl_handler_init(&state->hdl, 2);
+	v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, ADV7343_BRIGHTNESS_MIN,
+					     ADV7343_BRIGHTNESS_MAX, 1,
+					     ADV7343_BRIGHTNESS_DEF);
+	v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,
+			V4L2_CID_HUE, ADV7343_HUE_MIN,
+				      ADV7343_HUE_MAX, 1,
+				      ADV7343_HUE_DEF);
+	v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,
+			V4L2_CID_GAIN, ADV7343_GAIN_MIN,
+				       ADV7343_GAIN_MAX, 1,
+				       ADV7343_GAIN_DEF);
+	state->sd.ctrl_handler = &state->hdl;
+	if (state->hdl.error) {
+		int err = state->hdl.error;
+
+		v4l2_ctrl_handler_free(&state->hdl);
+		kfree(state);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&state->hdl);
+
+	err = adv7343_initialize(&state->sd);
+	if (err) {
+		v4l2_ctrl_handler_free(&state->hdl);
+		kfree(state);
+	}
+	return err;
+}
+
+static int adv7343_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct adv7343_state *state = to_state(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&state->hdl);
+	kfree(state);
+
+	return 0;
+}
+
+static const struct i2c_device_id adv7343_id[] = {
+	{"adv7343", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, adv7343_id);
+
+static struct i2c_driver adv7343_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "adv7343",
+	},
+	.probe		= adv7343_probe,
+	.remove		= adv7343_remove,
+	.id_table	= adv7343_id,
+};
+
+module_i2c_driver(adv7343_driver);
diff --git a/drivers/media/i2c/adv7343_regs.h b/drivers/media/i2c/adv7343_regs.h
new file mode 100644
index 0000000..4466067
--- /dev/null
+++ b/drivers/media/i2c/adv7343_regs.h
@@ -0,0 +1,181 @@
+/*
+ * ADV7343 encoder related structure and register definitions
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef ADV7343_REG_H
+#define ADV7343_REGS_H
+
+struct adv7343_std_info {
+	u32 standard_val3;
+	u32 fsc_val;
+	v4l2_std_id stdid;
+};
+
+/* Register offset macros */
+#define ADV7343_POWER_MODE_REG		(0x00)
+#define ADV7343_MODE_SELECT_REG		(0x01)
+#define ADV7343_MODE_REG0		(0x02)
+
+#define ADV7343_DAC2_OUTPUT_LEVEL	(0x0b)
+
+#define ADV7343_SOFT_RESET		(0x17)
+
+#define ADV7343_HD_MODE_REG1		(0x30)
+#define ADV7343_HD_MODE_REG2		(0x31)
+#define ADV7343_HD_MODE_REG3		(0x32)
+#define ADV7343_HD_MODE_REG4		(0x33)
+#define ADV7343_HD_MODE_REG5		(0x34)
+#define ADV7343_HD_MODE_REG6		(0x35)
+
+#define ADV7343_HD_MODE_REG7		(0x39)
+
+#define ADV7343_SD_MODE_REG1		(0x80)
+#define ADV7343_SD_MODE_REG2		(0x82)
+#define ADV7343_SD_MODE_REG3		(0x83)
+#define ADV7343_SD_MODE_REG4		(0x84)
+#define ADV7343_SD_MODE_REG5		(0x86)
+#define ADV7343_SD_MODE_REG6		(0x87)
+#define ADV7343_SD_MODE_REG7		(0x88)
+#define ADV7343_SD_MODE_REG8		(0x89)
+
+#define ADV7343_FSC_REG0		(0x8C)
+#define ADV7343_FSC_REG1		(0x8D)
+#define ADV7343_FSC_REG2		(0x8E)
+#define ADV7343_FSC_REG3		(0x8F)
+
+#define ADV7343_SD_CGMS_WSS0		(0x99)
+
+#define ADV7343_SD_HUE_REG		(0xA0)
+#define ADV7343_SD_BRIGHTNESS_WSS	(0xA1)
+
+/* Default values for the registers */
+#define ADV7343_POWER_MODE_REG_DEFAULT		(0x10)
+#define ADV7343_HD_MODE_REG1_DEFAULT		(0x3C)	/* Changed Default
+							   720p EAVSAV code*/
+#define ADV7343_HD_MODE_REG2_DEFAULT		(0x01)	/* Changed Pixel data
+							   valid */
+#define ADV7343_HD_MODE_REG3_DEFAULT		(0x00)	/* Color delay 0 clks */
+#define ADV7343_HD_MODE_REG4_DEFAULT		(0xE8)	/* Changed */
+#define ADV7343_HD_MODE_REG5_DEFAULT		(0x08)
+#define ADV7343_HD_MODE_REG6_DEFAULT		(0x00)
+#define ADV7343_HD_MODE_REG7_DEFAULT		(0x00)
+#define ADV7343_SD_MODE_REG8_DEFAULT		(0x00)
+#define ADV7343_SOFT_RESET_DEFAULT		(0x02)
+#define ADV7343_COMPOSITE_POWER_VALUE		(0x80)
+#define ADV7343_COMPONENT_POWER_VALUE		(0x1C)
+#define ADV7343_SVIDEO_POWER_VALUE		(0x60)
+#define ADV7343_SD_HUE_REG_DEFAULT		(127)
+#define ADV7343_SD_BRIGHTNESS_WSS_DEFAULT	(0x03)
+
+#define ADV7343_SD_CGMS_WSS0_DEFAULT		(0x10)
+
+#define ADV7343_SD_MODE_REG1_DEFAULT		(0x00)
+#define ADV7343_SD_MODE_REG2_DEFAULT		(0xC9)
+#define ADV7343_SD_MODE_REG3_DEFAULT		(0x10)
+#define ADV7343_SD_MODE_REG4_DEFAULT		(0x01)
+#define ADV7343_SD_MODE_REG5_DEFAULT		(0x02)
+#define ADV7343_SD_MODE_REG6_DEFAULT		(0x0C)
+#define ADV7343_SD_MODE_REG7_DEFAULT		(0x04)
+#define ADV7343_SD_MODE_REG8_DEFAULT		(0x00)
+
+/* Bit masks for Mode Select Register */
+#define INPUT_MODE_MASK			(0x70)
+#define SD_INPUT_MODE			(0x00)
+#define HD_720P_INPUT_MODE		(0x10)
+#define HD_1080I_INPUT_MODE		(0x10)
+
+/* Bit masks for Mode Register 0 */
+#define TEST_PATTERN_BLACK_BAR_EN	(0x04)
+#define YUV_OUTPUT_SELECT		(0x20)
+#define RGB_OUTPUT_SELECT		(0xDF)
+
+/* Bit masks for DAC output levels */
+#define DAC_OUTPUT_LEVEL_MASK		(0xFF)
+
+/* Bit masks for soft reset register */
+#define SOFT_RESET			(0x02)
+
+/* Bit masks for HD Mode Register 1 */
+#define OUTPUT_STD_MASK		(0x03)
+#define OUTPUT_STD_SHIFT	(0)
+#define OUTPUT_STD_EIA0_2	(0x00)
+#define OUTPUT_STD_EIA0_1	(0x01)
+#define OUTPUT_STD_FULL		(0x02)
+#define EMBEDDED_SYNC		(0x04)
+#define EXTERNAL_SYNC		(0xFB)
+#define STD_MODE_SHIFT		(3)
+#define STD_MODE_MASK		(0x1F)
+#define STD_MODE_720P		(0x05)
+#define STD_MODE_720P_25	(0x08)
+#define STD_MODE_720P_30	(0x07)
+#define STD_MODE_720P_50	(0x06)
+#define STD_MODE_1080I		(0x0D)
+#define STD_MODE_1080I_25fps	(0x0E)
+#define STD_MODE_1080P_24	(0x12)
+#define STD_MODE_1080P_25	(0x10)
+#define STD_MODE_1080P_30	(0x0F)
+#define STD_MODE_525P		(0x00)
+#define STD_MODE_625P		(0x03)
+
+/* Bit masks for SD Mode Register 1 */
+#define SD_STD_MASK		(0x03)
+#define SD_STD_NTSC		(0x00)
+#define SD_STD_PAL_BDGHI	(0x01)
+#define SD_STD_PAL_M		(0x02)
+#define SD_STD_PAL_N		(0x03)
+#define SD_LUMA_FLTR_MASK	(0x7)
+#define SD_LUMA_FLTR_SHIFT	(0x2)
+#define SD_CHROMA_FLTR_MASK	(0x7)
+#define SD_CHROMA_FLTR_SHIFT	(0x5)
+
+/* Bit masks for SD Mode Register 2 */
+#define SD_PBPR_SSAF_EN		(0x01)
+#define SD_PBPR_SSAF_DI		(0xFE)
+#define SD_DAC_1_DI		(0xFD)
+#define SD_DAC_2_DI		(0xFB)
+#define SD_PEDESTAL_EN		(0x08)
+#define SD_PEDESTAL_DI		(0xF7)
+#define SD_SQUARE_PIXEL_EN	(0x10)
+#define SD_SQUARE_PIXEL_DI	(0xEF)
+#define SD_PIXEL_DATA_VALID	(0x40)
+#define SD_ACTIVE_EDGE_EN	(0x80)
+#define SD_ACTIVE_EDGE_DI	(0x7F)
+
+/* Bit masks for HD Mode Register 6 */
+#define HD_RGB_INPUT_EN		(0x02)
+#define HD_RGB_INPUT_DI		(0xFD)
+#define HD_PBPR_SYNC_EN		(0x04)
+#define HD_PBPR_SYNC_DI		(0xFB)
+#define HD_DAC_SWAP_EN		(0x08)
+#define HD_DAC_SWAP_DI		(0xF7)
+#define HD_GAMMA_CURVE_A	(0xEF)
+#define HD_GAMMA_CURVE_B	(0x10)
+#define HD_GAMMA_EN		(0x20)
+#define HD_GAMMA_DI		(0xDF)
+#define HD_ADPT_FLTR_MODEB	(0x40)
+#define HD_ADPT_FLTR_MODEA	(0xBF)
+#define HD_ADPT_FLTR_EN		(0x80)
+#define HD_ADPT_FLTR_DI		(0x7F)
+
+#define ADV7343_BRIGHTNESS_MAX	(127)
+#define ADV7343_BRIGHTNESS_MIN	(0)
+#define ADV7343_BRIGHTNESS_DEF	(3)
+#define ADV7343_HUE_MAX		(255)
+#define ADV7343_HUE_MIN		(0)
+#define ADV7343_HUE_DEF		(127)
+#define ADV7343_GAIN_MAX	(64)
+#define ADV7343_GAIN_MIN	(-64)
+#define ADV7343_GAIN_DEF	(0)
+
+#endif
diff --git a/drivers/media/i2c/adv7393.c b/drivers/media/i2c/adv7393.c
new file mode 100644
index 0000000..3dc6098
--- /dev/null
+++ b/drivers/media/i2c/adv7393.c
@@ -0,0 +1,487 @@
+/*
+ * adv7393 - ADV7393 Video Encoder Driver
+ *
+ * The encoder hardware does not support SECAM.
+ *
+ * Copyright (C) 2010-2012 ADVANSEE - http://www.advansee.com/
+ * Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
+ *
+ * Based on ADV7343 driver,
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; 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/init.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <linux/uaccess.h>
+
+#include <media/adv7393.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+#include "adv7393_regs.h"
+
+MODULE_DESCRIPTION("ADV7393 video encoder driver");
+MODULE_LICENSE("GPL");
+
+static bool debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+
+struct adv7393_state {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	u8 reg00;
+	u8 reg01;
+	u8 reg02;
+	u8 reg35;
+	u8 reg80;
+	u8 reg82;
+	u32 output;
+	v4l2_std_id std;
+};
+
+static inline struct adv7393_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct adv7393_state, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct adv7393_state, hdl)->sd;
+}
+
+static inline int adv7393_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static const u8 adv7393_init_reg_val[] = {
+	ADV7393_SOFT_RESET, ADV7393_SOFT_RESET_DEFAULT,
+	ADV7393_POWER_MODE_REG, ADV7393_POWER_MODE_REG_DEFAULT,
+
+	ADV7393_HD_MODE_REG1, ADV7393_HD_MODE_REG1_DEFAULT,
+	ADV7393_HD_MODE_REG2, ADV7393_HD_MODE_REG2_DEFAULT,
+	ADV7393_HD_MODE_REG3, ADV7393_HD_MODE_REG3_DEFAULT,
+	ADV7393_HD_MODE_REG4, ADV7393_HD_MODE_REG4_DEFAULT,
+	ADV7393_HD_MODE_REG5, ADV7393_HD_MODE_REG5_DEFAULT,
+	ADV7393_HD_MODE_REG6, ADV7393_HD_MODE_REG6_DEFAULT,
+	ADV7393_HD_MODE_REG7, ADV7393_HD_MODE_REG7_DEFAULT,
+
+	ADV7393_SD_MODE_REG1, ADV7393_SD_MODE_REG1_DEFAULT,
+	ADV7393_SD_MODE_REG2, ADV7393_SD_MODE_REG2_DEFAULT,
+	ADV7393_SD_MODE_REG3, ADV7393_SD_MODE_REG3_DEFAULT,
+	ADV7393_SD_MODE_REG4, ADV7393_SD_MODE_REG4_DEFAULT,
+	ADV7393_SD_MODE_REG5, ADV7393_SD_MODE_REG5_DEFAULT,
+	ADV7393_SD_MODE_REG6, ADV7393_SD_MODE_REG6_DEFAULT,
+	ADV7393_SD_MODE_REG7, ADV7393_SD_MODE_REG7_DEFAULT,
+	ADV7393_SD_MODE_REG8, ADV7393_SD_MODE_REG8_DEFAULT,
+
+	ADV7393_SD_TIMING_REG0, ADV7393_SD_TIMING_REG0_DEFAULT,
+
+	ADV7393_SD_HUE_ADJUST, ADV7393_SD_HUE_ADJUST_DEFAULT,
+	ADV7393_SD_CGMS_WSS0, ADV7393_SD_CGMS_WSS0_DEFAULT,
+	ADV7393_SD_BRIGHTNESS_WSS, ADV7393_SD_BRIGHTNESS_WSS_DEFAULT,
+};
+
+/*
+ * 			    2^32
+ * FSC(reg) =  FSC (HZ) * --------
+ *			  27000000
+ */
+static const struct adv7393_std_info stdinfo[] = {
+	{
+		/* FSC(Hz) = 4,433,618.75 Hz */
+		SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443,
+	}, {
+		/* FSC(Hz) = 3,579,545.45 Hz */
+		SD_STD_NTSC, 569408542, V4L2_STD_NTSC,
+	}, {
+		/* FSC(Hz) = 3,575,611.00 Hz */
+		SD_STD_PAL_M, 568782678, V4L2_STD_PAL_M,
+	}, {
+		/* FSC(Hz) = 3,582,056.00 Hz */
+		SD_STD_PAL_N, 569807903, V4L2_STD_PAL_Nc,
+	}, {
+		/* FSC(Hz) = 4,433,618.75 Hz */
+		SD_STD_PAL_N, 705268427, V4L2_STD_PAL_N,
+	}, {
+		/* FSC(Hz) = 4,433,618.75 Hz */
+		SD_STD_PAL_M, 705268427, V4L2_STD_PAL_60,
+	}, {
+		/* FSC(Hz) = 4,433,618.75 Hz */
+		SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL,
+	},
+};
+
+static int adv7393_setstd(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct adv7393_state *state = to_state(sd);
+	const struct adv7393_std_info *std_info;
+	int num_std;
+	u8 reg;
+	u32 val;
+	int err = 0;
+	int i;
+
+	num_std = ARRAY_SIZE(stdinfo);
+
+	for (i = 0; i < num_std; i++) {
+		if (stdinfo[i].stdid & std)
+			break;
+	}
+
+	if (i == num_std) {
+		v4l2_dbg(1, debug, sd,
+				"Invalid std or std is not supported: %llx\n",
+						(unsigned long long)std);
+		return -EINVAL;
+	}
+
+	std_info = &stdinfo[i];
+
+	/* Set the standard */
+	val = state->reg80 & ~SD_STD_MASK;
+	val |= std_info->standard_val3;
+	err = adv7393_write(sd, ADV7393_SD_MODE_REG1, val);
+	if (err < 0)
+		goto setstd_exit;
+
+	state->reg80 = val;
+
+	/* Configure the input mode register */
+	val = state->reg01 & ~INPUT_MODE_MASK;
+	val |= SD_INPUT_MODE;
+	err = adv7393_write(sd, ADV7393_MODE_SELECT_REG, val);
+	if (err < 0)
+		goto setstd_exit;
+
+	state->reg01 = val;
+
+	/* Program the sub carrier frequency registers */
+	val = std_info->fsc_val;
+	for (reg = ADV7393_FSC_REG0; reg <= ADV7393_FSC_REG3; reg++) {
+		err = adv7393_write(sd, reg, val);
+		if (err < 0)
+			goto setstd_exit;
+		val >>= 8;
+	}
+
+	val = state->reg82;
+
+	/* Pedestal settings */
+	if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443))
+		val |= SD_PEDESTAL_EN;
+	else
+		val &= SD_PEDESTAL_DI;
+
+	err = adv7393_write(sd, ADV7393_SD_MODE_REG2, val);
+	if (err < 0)
+		goto setstd_exit;
+
+	state->reg82 = val;
+
+setstd_exit:
+	if (err != 0)
+		v4l2_err(sd, "Error setting std, write failed\n");
+
+	return err;
+}
+
+static int adv7393_setoutput(struct v4l2_subdev *sd, u32 output_type)
+{
+	struct adv7393_state *state = to_state(sd);
+	u8 val;
+	int err = 0;
+
+	if (output_type > ADV7393_SVIDEO_ID) {
+		v4l2_dbg(1, debug, sd,
+			"Invalid output type or output type not supported:%d\n",
+								output_type);
+		return -EINVAL;
+	}
+
+	/* Enable Appropriate DAC */
+	val = state->reg00 & 0x03;
+
+	if (output_type == ADV7393_COMPOSITE_ID)
+		val |= ADV7393_COMPOSITE_POWER_VALUE;
+	else if (output_type == ADV7393_COMPONENT_ID)
+		val |= ADV7393_COMPONENT_POWER_VALUE;
+	else
+		val |= ADV7393_SVIDEO_POWER_VALUE;
+
+	err = adv7393_write(sd, ADV7393_POWER_MODE_REG, val);
+	if (err < 0)
+		goto setoutput_exit;
+
+	state->reg00 = val;
+
+	/* Enable YUV output */
+	val = state->reg02 | YUV_OUTPUT_SELECT;
+	err = adv7393_write(sd, ADV7393_MODE_REG0, val);
+	if (err < 0)
+		goto setoutput_exit;
+
+	state->reg02 = val;
+
+	/* configure SD DAC Output 1 bit */
+	val = state->reg82;
+	if (output_type == ADV7393_COMPONENT_ID)
+		val &= SD_DAC_OUT1_DI;
+	else
+		val |= SD_DAC_OUT1_EN;
+	err = adv7393_write(sd, ADV7393_SD_MODE_REG2, val);
+	if (err < 0)
+		goto setoutput_exit;
+
+	state->reg82 = val;
+
+	/* configure ED/HD Color DAC Swap bit to zero */
+	val = state->reg35 & HD_DAC_SWAP_DI;
+	err = adv7393_write(sd, ADV7393_HD_MODE_REG6, val);
+	if (err < 0)
+		goto setoutput_exit;
+
+	state->reg35 = val;
+
+setoutput_exit:
+	if (err != 0)
+		v4l2_err(sd, "Error setting output, write failed\n");
+
+	return err;
+}
+
+static int adv7393_log_status(struct v4l2_subdev *sd)
+{
+	struct adv7393_state *state = to_state(sd);
+
+	v4l2_info(sd, "Standard: %llx\n", (unsigned long long)state->std);
+	v4l2_info(sd, "Output: %s\n", (state->output == 0) ? "Composite" :
+			((state->output == 1) ? "Component" : "S-Video"));
+	return 0;
+}
+
+static int adv7393_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		return adv7393_write(sd, ADV7393_SD_BRIGHTNESS_WSS,
+					ctrl->val & SD_BRIGHTNESS_VALUE_MASK);
+
+	case V4L2_CID_HUE:
+		return adv7393_write(sd, ADV7393_SD_HUE_ADJUST,
+					ctrl->val - ADV7393_HUE_MIN);
+
+	case V4L2_CID_GAIN:
+		return adv7393_write(sd, ADV7393_DAC123_OUTPUT_LEVEL,
+					ctrl->val);
+	}
+	return -EINVAL;
+}
+
+static int adv7393_g_chip_ident(struct v4l2_subdev *sd,
+				struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7393, 0);
+}
+
+static const struct v4l2_ctrl_ops adv7393_ctrl_ops = {
+	.s_ctrl = adv7393_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops adv7393_core_ops = {
+	.log_status = adv7393_log_status,
+	.g_chip_ident = adv7393_g_chip_ident,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+};
+
+static int adv7393_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct adv7393_state *state = to_state(sd);
+	int err = 0;
+
+	if (state->std == std)
+		return 0;
+
+	err = adv7393_setstd(sd, std);
+	if (!err)
+		state->std = std;
+
+	return err;
+}
+
+static int adv7393_s_routing(struct v4l2_subdev *sd,
+		u32 input, u32 output, u32 config)
+{
+	struct adv7393_state *state = to_state(sd);
+	int err = 0;
+
+	if (state->output == output)
+		return 0;
+
+	err = adv7393_setoutput(sd, output);
+	if (!err)
+		state->output = output;
+
+	return err;
+}
+
+static const struct v4l2_subdev_video_ops adv7393_video_ops = {
+	.s_std_output	= adv7393_s_std_output,
+	.s_routing	= adv7393_s_routing,
+};
+
+static const struct v4l2_subdev_ops adv7393_ops = {
+	.core	= &adv7393_core_ops,
+	.video	= &adv7393_video_ops,
+};
+
+static int adv7393_initialize(struct v4l2_subdev *sd)
+{
+	struct adv7393_state *state = to_state(sd);
+	int err = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(adv7393_init_reg_val); i += 2) {
+
+		err = adv7393_write(sd, adv7393_init_reg_val[i],
+					adv7393_init_reg_val[i+1]);
+		if (err) {
+			v4l2_err(sd, "Error initializing\n");
+			return err;
+		}
+	}
+
+	/* Configure for default video standard */
+	err = adv7393_setoutput(sd, state->output);
+	if (err < 0) {
+		v4l2_err(sd, "Error setting output during init\n");
+		return -EINVAL;
+	}
+
+	err = adv7393_setstd(sd, state->std);
+	if (err < 0) {
+		v4l2_err(sd, "Error setting std during init\n");
+		return -EINVAL;
+	}
+
+	return err;
+}
+
+static int adv7393_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	struct adv7393_state *state;
+	int err;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	state = kzalloc(sizeof(struct adv7393_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+
+	state->reg00	= ADV7393_POWER_MODE_REG_DEFAULT;
+	state->reg01	= 0x00;
+	state->reg02	= 0x20;
+	state->reg35	= ADV7393_HD_MODE_REG6_DEFAULT;
+	state->reg80	= ADV7393_SD_MODE_REG1_DEFAULT;
+	state->reg82	= ADV7393_SD_MODE_REG2_DEFAULT;
+
+	state->output = ADV7393_COMPOSITE_ID;
+	state->std = V4L2_STD_NTSC;
+
+	v4l2_i2c_subdev_init(&state->sd, client, &adv7393_ops);
+
+	v4l2_ctrl_handler_init(&state->hdl, 3);
+	v4l2_ctrl_new_std(&state->hdl, &adv7393_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, ADV7393_BRIGHTNESS_MIN,
+					     ADV7393_BRIGHTNESS_MAX, 1,
+					     ADV7393_BRIGHTNESS_DEF);
+	v4l2_ctrl_new_std(&state->hdl, &adv7393_ctrl_ops,
+			V4L2_CID_HUE, ADV7393_HUE_MIN,
+				      ADV7393_HUE_MAX, 1,
+				      ADV7393_HUE_DEF);
+	v4l2_ctrl_new_std(&state->hdl, &adv7393_ctrl_ops,
+			V4L2_CID_GAIN, ADV7393_GAIN_MIN,
+				       ADV7393_GAIN_MAX, 1,
+				       ADV7393_GAIN_DEF);
+	state->sd.ctrl_handler = &state->hdl;
+	if (state->hdl.error) {
+		int err = state->hdl.error;
+
+		v4l2_ctrl_handler_free(&state->hdl);
+		kfree(state);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&state->hdl);
+
+	err = adv7393_initialize(&state->sd);
+	if (err) {
+		v4l2_ctrl_handler_free(&state->hdl);
+		kfree(state);
+	}
+	return err;
+}
+
+static int adv7393_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct adv7393_state *state = to_state(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&state->hdl);
+	kfree(state);
+
+	return 0;
+}
+
+static const struct i2c_device_id adv7393_id[] = {
+	{"adv7393", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, adv7393_id);
+
+static struct i2c_driver adv7393_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "adv7393",
+	},
+	.probe		= adv7393_probe,
+	.remove		= adv7393_remove,
+	.id_table	= adv7393_id,
+};
+module_i2c_driver(adv7393_driver);
diff --git a/drivers/media/i2c/adv7393_regs.h b/drivers/media/i2c/adv7393_regs.h
new file mode 100644
index 0000000..7896833
--- /dev/null
+++ b/drivers/media/i2c/adv7393_regs.h
@@ -0,0 +1,188 @@
+/*
+ * ADV7393 encoder related structure and register definitions
+ *
+ * Copyright (C) 2010-2012 ADVANSEE - http://www.advansee.com/
+ * Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
+ *
+ * Based on ADV7343 driver,
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef ADV7393_REGS_H
+#define ADV7393_REGS_H
+
+struct adv7393_std_info {
+	u32 standard_val3;
+	u32 fsc_val;
+	v4l2_std_id stdid;
+};
+
+/* Register offset macros */
+#define ADV7393_POWER_MODE_REG		(0x00)
+#define ADV7393_MODE_SELECT_REG		(0x01)
+#define ADV7393_MODE_REG0		(0x02)
+
+#define ADV7393_DAC123_OUTPUT_LEVEL	(0x0B)
+
+#define ADV7393_SOFT_RESET		(0x17)
+
+#define ADV7393_HD_MODE_REG1		(0x30)
+#define ADV7393_HD_MODE_REG2		(0x31)
+#define ADV7393_HD_MODE_REG3		(0x32)
+#define ADV7393_HD_MODE_REG4		(0x33)
+#define ADV7393_HD_MODE_REG5		(0x34)
+#define ADV7393_HD_MODE_REG6		(0x35)
+
+#define ADV7393_HD_MODE_REG7		(0x39)
+
+#define ADV7393_SD_MODE_REG1		(0x80)
+#define ADV7393_SD_MODE_REG2		(0x82)
+#define ADV7393_SD_MODE_REG3		(0x83)
+#define ADV7393_SD_MODE_REG4		(0x84)
+#define ADV7393_SD_MODE_REG5		(0x86)
+#define ADV7393_SD_MODE_REG6		(0x87)
+#define ADV7393_SD_MODE_REG7		(0x88)
+#define ADV7393_SD_MODE_REG8		(0x89)
+
+#define ADV7393_SD_TIMING_REG0		(0x8A)
+
+#define ADV7393_FSC_REG0		(0x8C)
+#define ADV7393_FSC_REG1		(0x8D)
+#define ADV7393_FSC_REG2		(0x8E)
+#define ADV7393_FSC_REG3		(0x8F)
+
+#define ADV7393_SD_CGMS_WSS0		(0x99)
+
+#define ADV7393_SD_HUE_ADJUST		(0xA0)
+#define ADV7393_SD_BRIGHTNESS_WSS	(0xA1)
+
+/* Default values for the registers */
+#define ADV7393_POWER_MODE_REG_DEFAULT		(0x10)
+#define ADV7393_HD_MODE_REG1_DEFAULT		(0x3C)	/* Changed Default
+							   720p EAV/SAV code*/
+#define ADV7393_HD_MODE_REG2_DEFAULT		(0x01)	/* Changed Pixel data
+							   valid */
+#define ADV7393_HD_MODE_REG3_DEFAULT		(0x00)	/* Color delay 0 clks */
+#define ADV7393_HD_MODE_REG4_DEFAULT		(0xEC)	/* Changed */
+#define ADV7393_HD_MODE_REG5_DEFAULT		(0x08)
+#define ADV7393_HD_MODE_REG6_DEFAULT		(0x00)
+#define ADV7393_HD_MODE_REG7_DEFAULT		(0x00)
+#define ADV7393_SOFT_RESET_DEFAULT		(0x02)
+#define ADV7393_COMPOSITE_POWER_VALUE		(0x10)
+#define ADV7393_COMPONENT_POWER_VALUE		(0x1C)
+#define ADV7393_SVIDEO_POWER_VALUE		(0x0C)
+#define ADV7393_SD_HUE_ADJUST_DEFAULT		(0x80)
+#define ADV7393_SD_BRIGHTNESS_WSS_DEFAULT	(0x00)
+
+#define ADV7393_SD_CGMS_WSS0_DEFAULT		(0x10)
+
+#define ADV7393_SD_MODE_REG1_DEFAULT		(0x10)
+#define ADV7393_SD_MODE_REG2_DEFAULT		(0xC9)
+#define ADV7393_SD_MODE_REG3_DEFAULT		(0x00)
+#define ADV7393_SD_MODE_REG4_DEFAULT		(0x00)
+#define ADV7393_SD_MODE_REG5_DEFAULT		(0x02)
+#define ADV7393_SD_MODE_REG6_DEFAULT		(0x8C)
+#define ADV7393_SD_MODE_REG7_DEFAULT		(0x14)
+#define ADV7393_SD_MODE_REG8_DEFAULT		(0x00)
+
+#define ADV7393_SD_TIMING_REG0_DEFAULT		(0x0C)
+
+/* Bit masks for Mode Select Register */
+#define INPUT_MODE_MASK			(0x70)
+#define SD_INPUT_MODE			(0x00)
+#define HD_720P_INPUT_MODE		(0x10)
+#define HD_1080I_INPUT_MODE		(0x10)
+
+/* Bit masks for Mode Register 0 */
+#define TEST_PATTERN_BLACK_BAR_EN	(0x04)
+#define YUV_OUTPUT_SELECT		(0x20)
+#define RGB_OUTPUT_SELECT		(0xDF)
+
+/* Bit masks for SD brightness/WSS */
+#define SD_BRIGHTNESS_VALUE_MASK	(0x7F)
+#define SD_BLANK_WSS_DATA_MASK		(0x80)
+
+/* Bit masks for soft reset register */
+#define SOFT_RESET			(0x02)
+
+/* Bit masks for HD Mode Register 1 */
+#define OUTPUT_STD_MASK		(0x03)
+#define OUTPUT_STD_SHIFT	(0)
+#define OUTPUT_STD_EIA0_2	(0x00)
+#define OUTPUT_STD_EIA0_1	(0x01)
+#define OUTPUT_STD_FULL		(0x02)
+#define EMBEDDED_SYNC		(0x04)
+#define EXTERNAL_SYNC		(0xFB)
+#define STD_MODE_MASK		(0x1F)
+#define STD_MODE_SHIFT		(3)
+#define STD_MODE_720P		(0x05)
+#define STD_MODE_720P_25	(0x08)
+#define STD_MODE_720P_30	(0x07)
+#define STD_MODE_720P_50	(0x06)
+#define STD_MODE_1080I		(0x0D)
+#define STD_MODE_1080I_25	(0x0E)
+#define STD_MODE_1080P_24	(0x11)
+#define STD_MODE_1080P_25	(0x10)
+#define STD_MODE_1080P_30	(0x0F)
+#define STD_MODE_525P		(0x00)
+#define STD_MODE_625P		(0x03)
+
+/* Bit masks for SD Mode Register 1 */
+#define SD_STD_MASK		(0x03)
+#define SD_STD_NTSC		(0x00)
+#define SD_STD_PAL_BDGHI	(0x01)
+#define SD_STD_PAL_M		(0x02)
+#define SD_STD_PAL_N		(0x03)
+#define SD_LUMA_FLTR_MASK	(0x07)
+#define SD_LUMA_FLTR_SHIFT	(2)
+#define SD_CHROMA_FLTR_MASK	(0x07)
+#define SD_CHROMA_FLTR_SHIFT	(5)
+
+/* Bit masks for SD Mode Register 2 */
+#define SD_PRPB_SSAF_EN		(0x01)
+#define SD_PRPB_SSAF_DI		(0xFE)
+#define SD_DAC_OUT1_EN		(0x02)
+#define SD_DAC_OUT1_DI		(0xFD)
+#define SD_PEDESTAL_EN		(0x08)
+#define SD_PEDESTAL_DI		(0xF7)
+#define SD_SQUARE_PIXEL_EN	(0x10)
+#define SD_SQUARE_PIXEL_DI	(0xEF)
+#define SD_PIXEL_DATA_VALID	(0x40)
+#define SD_ACTIVE_EDGE_EN	(0x80)
+#define SD_ACTIVE_EDGE_DI	(0x7F)
+
+/* Bit masks for HD Mode Register 6 */
+#define HD_PRPB_SYNC_EN		(0x04)
+#define HD_PRPB_SYNC_DI		(0xFB)
+#define HD_DAC_SWAP_EN		(0x08)
+#define HD_DAC_SWAP_DI		(0xF7)
+#define HD_GAMMA_CURVE_A	(0xEF)
+#define HD_GAMMA_CURVE_B	(0x10)
+#define HD_GAMMA_EN		(0x20)
+#define HD_GAMMA_DI		(0xDF)
+#define HD_ADPT_FLTR_MODEA	(0xBF)
+#define HD_ADPT_FLTR_MODEB	(0x40)
+#define HD_ADPT_FLTR_EN		(0x80)
+#define HD_ADPT_FLTR_DI		(0x7F)
+
+#define ADV7393_BRIGHTNESS_MAX	(63)
+#define ADV7393_BRIGHTNESS_MIN	(-64)
+#define ADV7393_BRIGHTNESS_DEF	(0)
+#define ADV7393_HUE_MAX		(127)
+#define ADV7393_HUE_MIN		(-128)
+#define ADV7393_HUE_DEF		(0)
+#define ADV7393_GAIN_MAX	(64)
+#define ADV7393_GAIN_MIN	(-64)
+#define ADV7393_GAIN_DEF	(0)
+
+#endif
diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c
new file mode 100644
index 0000000..ba67465
--- /dev/null
+++ b/drivers/media/i2c/ak881x.c
@@ -0,0 +1,359 @@
+/*
+ * Driver for AK8813 / AK8814 TV-ecoders from Asahi Kasei Microsystems Co., Ltd. (AKM)
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+
+#include <media/ak881x.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+
+#define AK881X_INTERFACE_MODE	0
+#define AK881X_VIDEO_PROCESS1	1
+#define AK881X_VIDEO_PROCESS2	2
+#define AK881X_VIDEO_PROCESS3	3
+#define AK881X_DAC_MODE		5
+#define AK881X_STATUS		0x24
+#define AK881X_DEVICE_ID	0x25
+#define AK881X_DEVICE_REVISION	0x26
+
+struct ak881x {
+	struct v4l2_subdev subdev;
+	struct ak881x_pdata *pdata;
+	unsigned int lines;
+	int id;	/* DEVICE_ID code V4L2_IDENT_AK881X code from v4l2-chip-ident.h */
+	char revision;	/* DEVICE_REVISION content */
+};
+
+static int reg_read(struct i2c_client *client, const u8 reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int reg_write(struct i2c_client *client, const u8 reg,
+		     const u8 data)
+{
+	return i2c_smbus_write_byte_data(client, reg, data);
+}
+
+static int reg_set(struct i2c_client *client, const u8 reg,
+		   const u8 data, u8 mask)
+{
+	int ret = reg_read(client, reg);
+	if (ret < 0)
+		return ret;
+	return reg_write(client, reg, (ret & ~mask) | (data & mask));
+}
+
+static struct ak881x *to_ak881x(const struct i2c_client *client)
+{
+	return container_of(i2c_get_clientdata(client), struct ak881x, subdev);
+}
+
+static int ak881x_g_chip_ident(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_chip_ident *id)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ak881x *ak881x = to_ak881x(client);
+
+	if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+
+	if (id->match.addr != client->addr)
+		return -ENODEV;
+
+	id->ident	= ak881x->id;
+	id->revision	= ak881x->revision;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ak881x_g_register(struct v4l2_subdev *sd,
+			     struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x26)
+		return -EINVAL;
+
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	reg->val = reg_read(client, reg->reg);
+
+	if (reg->val > 0xffff)
+		return -EIO;
+
+	return 0;
+}
+
+static int ak881x_s_register(struct v4l2_subdev *sd,
+			     struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x26)
+		return -EINVAL;
+
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	if (reg_write(client, reg->reg, reg->val) < 0)
+		return -EIO;
+
+	return 0;
+}
+#endif
+
+static int ak881x_try_g_mbus_fmt(struct v4l2_subdev *sd,
+				 struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ak881x *ak881x = to_ak881x(client);
+
+	v4l_bound_align_image(&mf->width, 0, 720, 2,
+			      &mf->height, 0, ak881x->lines, 1, 0);
+	mf->field	= V4L2_FIELD_INTERLACED;
+	mf->code	= V4L2_MBUS_FMT_YUYV8_2X8;
+	mf->colorspace	= V4L2_COLORSPACE_SMPTE170M;
+
+	return 0;
+}
+
+static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd,
+			     struct v4l2_mbus_framefmt *mf)
+{
+	if (mf->field != V4L2_FIELD_INTERLACED ||
+	    mf->code != V4L2_MBUS_FMT_YUYV8_2X8)
+		return -EINVAL;
+
+	return ak881x_try_g_mbus_fmt(sd, mf);
+}
+
+static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
+				enum v4l2_mbus_pixelcode *code)
+{
+	if (index)
+		return -EINVAL;
+
+	*code = V4L2_MBUS_FMT_YUYV8_2X8;
+	return 0;
+}
+
+static int ak881x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ak881x *ak881x = to_ak881x(client);
+
+	a->bounds.left			= 0;
+	a->bounds.top			= 0;
+	a->bounds.width			= 720;
+	a->bounds.height		= ak881x->lines;
+	a->defrect			= a->bounds;
+	a->type				= V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int ak881x_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ak881x *ak881x = to_ak881x(client);
+	u8 vp1;
+
+	if (std == V4L2_STD_NTSC_443) {
+		vp1 = 3;
+		ak881x->lines = 480;
+	} else if (std == V4L2_STD_PAL_M) {
+		vp1 = 5;
+		ak881x->lines = 480;
+	} else if (std == V4L2_STD_PAL_60) {
+		vp1 = 7;
+		ak881x->lines = 480;
+	} else if (std && !(std & ~V4L2_STD_PAL)) {
+		vp1 = 0xf;
+		ak881x->lines = 576;
+	} else if (std && !(std & ~V4L2_STD_NTSC)) {
+		vp1 = 0;
+		ak881x->lines = 480;
+	} else {
+		/* No SECAM or PAL_N/Nc supported */
+		return -EINVAL;
+	}
+
+	reg_set(client, AK881X_VIDEO_PROCESS1, vp1, 0xf);
+
+	return 0;
+}
+
+static int ak881x_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ak881x *ak881x = to_ak881x(client);
+
+	if (enable) {
+		u8 dac;
+		/* For colour-bar testing set bit 6 of AK881X_VIDEO_PROCESS1 */
+		/* Default: composite output */
+		if (ak881x->pdata->flags & AK881X_COMPONENT)
+			dac = 3;
+		else
+			dac = 4;
+		/* Turn on the DAC(s) */
+		reg_write(client, AK881X_DAC_MODE, dac);
+		dev_dbg(&client->dev, "chip status 0x%x\n",
+			reg_read(client, AK881X_STATUS));
+	} else {
+		/* ...and clear bit 6 of AK881X_VIDEO_PROCESS1 here */
+		reg_write(client, AK881X_DAC_MODE, 0);
+		dev_dbg(&client->dev, "chip status 0x%x\n",
+			reg_read(client, AK881X_STATUS));
+	}
+
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops ak881x_subdev_core_ops = {
+	.g_chip_ident	= ak881x_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register	= ak881x_g_register,
+	.s_register	= ak881x_s_register,
+#endif
+};
+
+static struct v4l2_subdev_video_ops ak881x_subdev_video_ops = {
+	.s_mbus_fmt	= ak881x_s_mbus_fmt,
+	.g_mbus_fmt	= ak881x_try_g_mbus_fmt,
+	.try_mbus_fmt	= ak881x_try_g_mbus_fmt,
+	.cropcap	= ak881x_cropcap,
+	.enum_mbus_fmt	= ak881x_enum_mbus_fmt,
+	.s_std_output	= ak881x_s_std_output,
+	.s_stream	= ak881x_s_stream,
+};
+
+static struct v4l2_subdev_ops ak881x_subdev_ops = {
+	.core	= &ak881x_subdev_core_ops,
+	.video	= &ak881x_subdev_video_ops,
+};
+
+static int ak881x_probe(struct i2c_client *client,
+			const struct i2c_device_id *did)
+{
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct ak881x *ak881x;
+	u8 ifmode, data;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		dev_warn(&adapter->dev,
+			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+		return -EIO;
+	}
+
+	ak881x = kzalloc(sizeof(struct ak881x), GFP_KERNEL);
+	if (!ak881x)
+		return -ENOMEM;
+
+	v4l2_i2c_subdev_init(&ak881x->subdev, client, &ak881x_subdev_ops);
+
+	data = reg_read(client, AK881X_DEVICE_ID);
+
+	switch (data) {
+	case 0x13:
+		ak881x->id = V4L2_IDENT_AK8813;
+		break;
+	case 0x14:
+		ak881x->id = V4L2_IDENT_AK8814;
+		break;
+	default:
+		dev_err(&client->dev,
+			"No ak881x chip detected, register read %x\n", data);
+		kfree(ak881x);
+		return -ENODEV;
+	}
+
+	ak881x->revision = reg_read(client, AK881X_DEVICE_REVISION);
+	ak881x->pdata = client->dev.platform_data;
+
+	if (ak881x->pdata) {
+		if (ak881x->pdata->flags & AK881X_FIELD)
+			ifmode = 4;
+		else
+			ifmode = 0;
+
+		switch (ak881x->pdata->flags & AK881X_IF_MODE_MASK) {
+		case AK881X_IF_MODE_BT656:
+			ifmode |= 1;
+			break;
+		case AK881X_IF_MODE_MASTER:
+			ifmode |= 2;
+			break;
+		case AK881X_IF_MODE_SLAVE:
+		default:
+			break;
+		}
+
+		dev_dbg(&client->dev, "IF mode %x\n", ifmode);
+
+		/*
+		 * "Line Blanking No." seems to be the same as the number of
+		 * "black" lines on, e.g., SuperH VOU, whose default value of 20
+		 * "incidentally" matches ak881x' default
+		 */
+		reg_write(client, AK881X_INTERFACE_MODE, ifmode | (20 << 3));
+	}
+
+	/* Hardware default: NTSC-M */
+	ak881x->lines = 480;
+
+	dev_info(&client->dev, "Detected an ak881x chip ID %x, revision %x\n",
+		 data, ak881x->revision);
+
+	return 0;
+}
+
+static int ak881x_remove(struct i2c_client *client)
+{
+	struct ak881x *ak881x = to_ak881x(client);
+
+	v4l2_device_unregister_subdev(&ak881x->subdev);
+	kfree(ak881x);
+
+	return 0;
+}
+
+static const struct i2c_device_id ak881x_id[] = {
+	{ "ak8813", 0 },
+	{ "ak8814", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ak881x_id);
+
+static struct i2c_driver ak881x_i2c_driver = {
+	.driver = {
+		.name = "ak881x",
+	},
+	.probe		= ak881x_probe,
+	.remove		= ak881x_remove,
+	.id_table	= ak881x_id,
+};
+
+module_i2c_driver(ak881x_i2c_driver);
+
+MODULE_DESCRIPTION("TV-output driver for ak8813/ak8814");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/aptina-pll.c b/drivers/media/i2c/aptina-pll.c
new file mode 100644
index 0000000..8153a44
--- /dev/null
+++ b/drivers/media/i2c/aptina-pll.c
@@ -0,0 +1,173 @@
+/*
+ * Aptina Sensor PLL Configuration
+ *
+ * Copyright (C) 2012 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/gcd.h>
+#include <linux/kernel.h>
+#include <linux/lcm.h>
+#include <linux/module.h>
+
+#include "aptina-pll.h"
+
+int aptina_pll_calculate(struct device *dev,
+			 const struct aptina_pll_limits *limits,
+			 struct aptina_pll *pll)
+{
+	unsigned int mf_min;
+	unsigned int mf_max;
+	unsigned int p1_min;
+	unsigned int p1_max;
+	unsigned int p1;
+	unsigned int div;
+
+	dev_dbg(dev, "PLL: ext clock %u pix clock %u\n",
+		pll->ext_clock, pll->pix_clock);
+
+	if (pll->ext_clock < limits->ext_clock_min ||
+	    pll->ext_clock > limits->ext_clock_max) {
+		dev_err(dev, "pll: invalid external clock frequency.\n");
+		return -EINVAL;
+	}
+
+	if (pll->pix_clock == 0 || pll->pix_clock > limits->pix_clock_max) {
+		dev_err(dev, "pll: invalid pixel clock frequency.\n");
+		return -EINVAL;
+	}
+
+	/* Compute the multiplier M and combined N*P1 divisor. */
+	div = gcd(pll->pix_clock, pll->ext_clock);
+	pll->m = pll->pix_clock / div;
+	div = pll->ext_clock / div;
+
+	/* We now have the smallest M and N*P1 values that will result in the
+	 * desired pixel clock frequency, but they might be out of the valid
+	 * range. Compute the factor by which we should multiply them given the
+	 * following constraints:
+	 *
+	 * - minimum/maximum multiplier
+	 * - minimum/maximum multiplier output clock frequency assuming the
+	 *   minimum/maximum N value
+	 * - minimum/maximum combined N*P1 divisor
+	 */
+	mf_min = DIV_ROUND_UP(limits->m_min, pll->m);
+	mf_min = max(mf_min, limits->out_clock_min /
+		     (pll->ext_clock / limits->n_min * pll->m));
+	mf_min = max(mf_min, limits->n_min * limits->p1_min / div);
+	mf_max = limits->m_max / pll->m;
+	mf_max = min(mf_max, limits->out_clock_max /
+		    (pll->ext_clock / limits->n_max * pll->m));
+	mf_max = min(mf_max, DIV_ROUND_UP(limits->n_max * limits->p1_max, div));
+
+	dev_dbg(dev, "pll: mf min %u max %u\n", mf_min, mf_max);
+	if (mf_min > mf_max) {
+		dev_err(dev, "pll: no valid combined N*P1 divisor.\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * We're looking for the highest acceptable P1 value for which a
+	 * multiplier factor MF exists that fulfills the following conditions:
+	 *
+	 * 1. p1 is in the [p1_min, p1_max] range given by the limits and is
+	 *    even
+	 * 2. mf is in the [mf_min, mf_max] range computed above
+	 * 3. div * mf is a multiple of p1, in order to compute
+	 *	n = div * mf / p1
+	 *	m = pll->m * mf
+	 * 4. the internal clock frequency, given by ext_clock / n, is in the
+	 *    [int_clock_min, int_clock_max] range given by the limits
+	 * 5. the output clock frequency, given by ext_clock / n * m, is in the
+	 *    [out_clock_min, out_clock_max] range given by the limits
+	 *
+	 * The first naive approach is to iterate over all p1 values acceptable
+	 * according to (1) and all mf values acceptable according to (2), and
+	 * stop at the first combination that fulfills (3), (4) and (5). This
+	 * has a O(n^2) complexity.
+	 *
+	 * Instead of iterating over all mf values in the [mf_min, mf_max] range
+	 * we can compute the mf increment between two acceptable values
+	 * according to (3) with
+	 *
+	 *	mf_inc = p1 / gcd(div, p1)			(6)
+	 *
+	 * and round the minimum up to the nearest multiple of mf_inc. This will
+	 * restrict the number of mf values to be checked.
+	 *
+	 * Furthermore, conditions (4) and (5) only restrict the range of
+	 * acceptable p1 and mf values by modifying the minimum and maximum
+	 * limits. (5) can be expressed as
+	 *
+	 *	ext_clock / (div * mf / p1) * m * mf >= out_clock_min
+	 *	ext_clock / (div * mf / p1) * m * mf <= out_clock_max
+	 *
+	 * or
+	 *
+	 *	p1 >= out_clock_min * div / (ext_clock * m)	(7)
+	 *	p1 <= out_clock_max * div / (ext_clock * m)
+	 *
+	 * Similarly, (4) can be expressed as
+	 *
+	 *	mf >= ext_clock * p1 / (int_clock_max * div)	(8)
+	 *	mf <= ext_clock * p1 / (int_clock_min * div)
+	 *
+	 * We can thus iterate over the restricted p1 range defined by the
+	 * combination of (1) and (7), and then compute the restricted mf range
+	 * defined by the combination of (2), (6) and (8). If the resulting mf
+	 * range is not empty, any value in the mf range is acceptable. We thus
+	 * select the mf lwoer bound and the corresponding p1 value.
+	 */
+	if (limits->p1_min == 0) {
+		dev_err(dev, "pll: P1 minimum value must be >0.\n");
+		return -EINVAL;
+	}
+
+	p1_min = max(limits->p1_min, DIV_ROUND_UP(limits->out_clock_min * div,
+		     pll->ext_clock * pll->m));
+	p1_max = min(limits->p1_max, limits->out_clock_max * div /
+		     (pll->ext_clock * pll->m));
+
+	for (p1 = p1_max & ~1; p1 >= p1_min; p1 -= 2) {
+		unsigned int mf_inc = p1 / gcd(div, p1);
+		unsigned int mf_high;
+		unsigned int mf_low;
+
+		mf_low = roundup(max(mf_min, DIV_ROUND_UP(pll->ext_clock * p1,
+					limits->int_clock_max * div)), mf_inc);
+		mf_high = min(mf_max, pll->ext_clock * p1 /
+			      (limits->int_clock_min * div));
+
+		if (mf_low > mf_high)
+			continue;
+
+		pll->n = div * mf_low / p1;
+		pll->m *= mf_low;
+		pll->p1 = p1;
+		dev_dbg(dev, "PLL: N %u M %u P1 %u\n", pll->n, pll->m, pll->p1);
+		return 0;
+	}
+
+	dev_err(dev, "pll: no valid N and P1 divisors found.\n");
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(aptina_pll_calculate);
+
+MODULE_DESCRIPTION("Aptina PLL Helpers");
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/aptina-pll.h b/drivers/media/i2c/aptina-pll.h
new file mode 100644
index 0000000..b370e34
--- /dev/null
+++ b/drivers/media/i2c/aptina-pll.h
@@ -0,0 +1,56 @@
+/*
+ * Aptina Sensor PLL Configuration
+ *
+ * Copyright (C) 2012 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __APTINA_PLL_H
+#define __APTINA_PLL_H
+
+struct aptina_pll {
+	unsigned int ext_clock;
+	unsigned int pix_clock;
+
+	unsigned int n;
+	unsigned int m;
+	unsigned int p1;
+};
+
+struct aptina_pll_limits {
+	unsigned int ext_clock_min;
+	unsigned int ext_clock_max;
+	unsigned int int_clock_min;
+	unsigned int int_clock_max;
+	unsigned int out_clock_min;
+	unsigned int out_clock_max;
+	unsigned int pix_clock_max;
+
+	unsigned int n_min;
+	unsigned int n_max;
+	unsigned int m_min;
+	unsigned int m_max;
+	unsigned int p1_min;
+	unsigned int p1_max;
+};
+
+struct device;
+
+int aptina_pll_calculate(struct device *dev,
+			 const struct aptina_pll_limits *limits,
+			 struct aptina_pll *pll);
+
+#endif /* __APTINA_PLL_H */
diff --git a/drivers/media/i2c/as3645a.c b/drivers/media/i2c/as3645a.c
new file mode 100644
index 0000000..3bfdbf9
--- /dev/null
+++ b/drivers/media/i2c/as3645a.c
@@ -0,0 +1,888 @@
+/*
+ * drivers/media/i2c/as3645a.c - AS3645A and LM3555 flash controllers driver
+ *
+ * Copyright (C) 2008-2011 Nokia Corporation
+ * Copyright (c) 2011, Intel Corporation.
+ *
+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * TODO:
+ * - Check hardware FSTROBE control when sensor driver add support for this
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <media/as3645a.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+
+#define AS_TIMER_MS_TO_CODE(t)			(((t) - 100) / 50)
+#define AS_TIMER_CODE_TO_MS(c)			(50 * (c) + 100)
+
+/* Register definitions */
+
+/* Read-only Design info register: Reset state: xxxx 0001 */
+#define AS_DESIGN_INFO_REG			0x00
+#define AS_DESIGN_INFO_FACTORY(x)		(((x) >> 4))
+#define AS_DESIGN_INFO_MODEL(x)			((x) & 0x0f)
+
+/* Read-only Version control register: Reset state: 0000 0000
+ * for first engineering samples
+ */
+#define AS_VERSION_CONTROL_REG			0x01
+#define AS_VERSION_CONTROL_RFU(x)		(((x) >> 4))
+#define AS_VERSION_CONTROL_VERSION(x)		((x) & 0x0f)
+
+/* Read / Write	(Indicator and timer register): Reset state: 0000 1111 */
+#define AS_INDICATOR_AND_TIMER_REG		0x02
+#define AS_INDICATOR_AND_TIMER_TIMEOUT_SHIFT	0
+#define AS_INDICATOR_AND_TIMER_VREF_SHIFT	4
+#define AS_INDICATOR_AND_TIMER_INDICATOR_SHIFT	6
+
+/* Read / Write	(Current set register): Reset state: 0110 1001 */
+#define AS_CURRENT_SET_REG			0x03
+#define AS_CURRENT_ASSIST_LIGHT_SHIFT		0
+#define AS_CURRENT_LED_DET_ON			(1 << 3)
+#define AS_CURRENT_FLASH_CURRENT_SHIFT		4
+
+/* Read / Write	(Control register): Reset state: 1011 0100 */
+#define AS_CONTROL_REG				0x04
+#define AS_CONTROL_MODE_SETTING_SHIFT		0
+#define AS_CONTROL_STROBE_ON			(1 << 2)
+#define AS_CONTROL_OUT_ON			(1 << 3)
+#define AS_CONTROL_EXT_TORCH_ON			(1 << 4)
+#define AS_CONTROL_STROBE_TYPE_EDGE		(0 << 5)
+#define AS_CONTROL_STROBE_TYPE_LEVEL		(1 << 5)
+#define AS_CONTROL_COIL_PEAK_SHIFT		6
+
+/* Read only (D3 is read / write) (Fault and info): Reset state: 0000 x000 */
+#define AS_FAULT_INFO_REG			0x05
+#define AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT	(1 << 1)
+#define AS_FAULT_INFO_INDICATOR_LED		(1 << 2)
+#define AS_FAULT_INFO_LED_AMOUNT		(1 << 3)
+#define AS_FAULT_INFO_TIMEOUT			(1 << 4)
+#define AS_FAULT_INFO_OVER_TEMPERATURE		(1 << 5)
+#define AS_FAULT_INFO_SHORT_CIRCUIT		(1 << 6)
+#define AS_FAULT_INFO_OVER_VOLTAGE		(1 << 7)
+
+/* Boost register */
+#define AS_BOOST_REG				0x0d
+#define AS_BOOST_CURRENT_DISABLE		(0 << 0)
+#define AS_BOOST_CURRENT_ENABLE			(1 << 0)
+
+/* Password register is used to unlock boost register writing */
+#define AS_PASSWORD_REG				0x0f
+#define AS_PASSWORD_UNLOCK_VALUE		0x55
+
+enum as_mode {
+	AS_MODE_EXT_TORCH = 0 << AS_CONTROL_MODE_SETTING_SHIFT,
+	AS_MODE_INDICATOR = 1 << AS_CONTROL_MODE_SETTING_SHIFT,
+	AS_MODE_ASSIST = 2 << AS_CONTROL_MODE_SETTING_SHIFT,
+	AS_MODE_FLASH = 3 << AS_CONTROL_MODE_SETTING_SHIFT,
+};
+
+/*
+ * struct as3645a
+ *
+ * @subdev:		V4L2 subdev
+ * @pdata:		Flash platform data
+ * @power_lock:		Protects power_count
+ * @power_count:	Power reference count
+ * @led_mode:		V4L2 flash LED mode
+ * @timeout:		Flash timeout in microseconds
+ * @flash_current:	Flash current (0=200mA ... 15=500mA). Maximum
+ *			values are 400mA for two LEDs and 500mA for one LED.
+ * @assist_current:	Torch/Assist light current (0=20mA, 1=40mA ... 7=160mA)
+ * @indicator_current:	Indicator LED current (0=0mA, 1=2.5mA ... 4=10mA)
+ * @strobe_source:	Flash strobe source (software or external)
+ */
+struct as3645a {
+	struct v4l2_subdev subdev;
+	const struct as3645a_platform_data *pdata;
+
+	struct mutex power_lock;
+	int power_count;
+
+	/* Controls */
+	struct v4l2_ctrl_handler ctrls;
+
+	enum v4l2_flash_led_mode led_mode;
+	unsigned int timeout;
+	u8 flash_current;
+	u8 assist_current;
+	u8 indicator_current;
+	enum v4l2_flash_strobe_source strobe_source;
+};
+
+#define to_as3645a(sd) container_of(sd, struct as3645a, subdev)
+
+/* Return negative errno else zero on success */
+static int as3645a_write(struct as3645a *flash, u8 addr, u8 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+	int rval;
+
+	rval = i2c_smbus_write_byte_data(client, addr, val);
+
+	dev_dbg(&client->dev, "Write Addr:%02X Val:%02X %s\n", addr, val,
+		rval < 0 ? "fail" : "ok");
+
+	return rval;
+}
+
+/* Return negative errno else a data byte received from the device. */
+static int as3645a_read(struct as3645a *flash, u8 addr)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+	int rval;
+
+	rval = i2c_smbus_read_byte_data(client, addr);
+
+	dev_dbg(&client->dev, "Read Addr:%02X Val:%02X %s\n", addr, rval,
+		rval < 0 ? "fail" : "ok");
+
+	return rval;
+}
+
+/* -----------------------------------------------------------------------------
+ * Hardware configuration and trigger
+ */
+
+/*
+ * as3645a_set_config - Set flash configuration registers
+ * @flash: The flash
+ *
+ * Configure the hardware with flash, assist and indicator currents, as well as
+ * flash timeout.
+ *
+ * Return 0 on success, or a negative error code if an I2C communication error
+ * occurred.
+ */
+static int as3645a_set_config(struct as3645a *flash)
+{
+	int ret;
+	u8 val;
+
+	val = (flash->flash_current << AS_CURRENT_FLASH_CURRENT_SHIFT)
+	    | (flash->assist_current << AS_CURRENT_ASSIST_LIGHT_SHIFT)
+	    | AS_CURRENT_LED_DET_ON;
+
+	ret = as3645a_write(flash, AS_CURRENT_SET_REG, val);
+	if (ret < 0)
+		return ret;
+
+	val = AS_TIMER_MS_TO_CODE(flash->timeout / 1000)
+		    << AS_INDICATOR_AND_TIMER_TIMEOUT_SHIFT;
+
+	val |= (flash->pdata->vref << AS_INDICATOR_AND_TIMER_VREF_SHIFT)
+	    |  ((flash->indicator_current ? flash->indicator_current - 1 : 0)
+		 << AS_INDICATOR_AND_TIMER_INDICATOR_SHIFT);
+
+	return as3645a_write(flash, AS_INDICATOR_AND_TIMER_REG, val);
+}
+
+/*
+ * as3645a_set_control - Set flash control register
+ * @flash: The flash
+ * @mode: Desired output mode
+ * @on: Desired output state
+ *
+ * Configure the hardware with output mode and state.
+ *
+ * Return 0 on success, or a negative error code if an I2C communication error
+ * occurred.
+ */
+static int
+as3645a_set_control(struct as3645a *flash, enum as_mode mode, bool on)
+{
+	u8 reg;
+
+	/* Configure output parameters and operation mode. */
+	reg = (flash->pdata->peak << AS_CONTROL_COIL_PEAK_SHIFT)
+	    | (on ? AS_CONTROL_OUT_ON : 0)
+	    | mode;
+
+	if (flash->led_mode == V4L2_FLASH_LED_MODE_FLASH &&
+	    flash->strobe_source == V4L2_FLASH_STROBE_SOURCE_EXTERNAL) {
+		reg |= AS_CONTROL_STROBE_TYPE_LEVEL
+		    |  AS_CONTROL_STROBE_ON;
+	}
+
+	return as3645a_write(flash, AS_CONTROL_REG, reg);
+}
+
+/*
+ * as3645a_set_output - Configure output and operation mode
+ * @flash: Flash controller
+ * @strobe: Strobe the flash (only valid in flash mode)
+ *
+ * Turn the LEDs output on/off and set the operation mode based on the current
+ * parameters.
+ *
+ * The AS3645A can't control the indicator LED independently of the flash/torch
+ * LED. If the flash controller is in V4L2_FLASH_LED_MODE_NONE mode, set the
+ * chip to indicator mode. Otherwise set it to assist light (torch) or flash
+ * mode.
+ *
+ * In indicator and assist modes, turn the output on/off based on the indicator
+ * and torch currents. In software strobe flash mode, turn the output on/off
+ * based on the strobe parameter.
+ */
+static int as3645a_set_output(struct as3645a *flash, bool strobe)
+{
+	enum as_mode mode;
+	bool on;
+
+	switch (flash->led_mode) {
+	case V4L2_FLASH_LED_MODE_NONE:
+		on = flash->indicator_current != 0;
+		mode = AS_MODE_INDICATOR;
+		break;
+	case V4L2_FLASH_LED_MODE_TORCH:
+		on = true;
+		mode = AS_MODE_ASSIST;
+		break;
+	case V4L2_FLASH_LED_MODE_FLASH:
+		on = strobe;
+		mode = AS_MODE_FLASH;
+		break;
+	default:
+		BUG();
+	}
+
+	/* Configure output parameters and operation mode. */
+	return as3645a_set_control(flash, mode, on);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 controls
+ */
+
+static int as3645a_is_active(struct as3645a *flash)
+{
+	int ret;
+
+	ret = as3645a_read(flash, AS_CONTROL_REG);
+	return ret < 0 ? ret : !!(ret & AS_CONTROL_OUT_ON);
+}
+
+static int as3645a_read_fault(struct as3645a *flash)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+	int rval;
+
+	/* NOTE: reading register clear fault status */
+	rval = as3645a_read(flash, AS_FAULT_INFO_REG);
+	if (rval < 0)
+		return rval;
+
+	if (rval & AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT)
+		dev_dbg(&client->dev, "Inductor Peak limit fault\n");
+
+	if (rval & AS_FAULT_INFO_INDICATOR_LED)
+		dev_dbg(&client->dev, "Indicator LED fault: "
+			"Short circuit or open loop\n");
+
+	dev_dbg(&client->dev, "%u connected LEDs\n",
+		rval & AS_FAULT_INFO_LED_AMOUNT ? 2 : 1);
+
+	if (rval & AS_FAULT_INFO_TIMEOUT)
+		dev_dbg(&client->dev, "Timeout fault\n");
+
+	if (rval & AS_FAULT_INFO_OVER_TEMPERATURE)
+		dev_dbg(&client->dev, "Over temperature fault\n");
+
+	if (rval & AS_FAULT_INFO_SHORT_CIRCUIT)
+		dev_dbg(&client->dev, "Short circuit fault\n");
+
+	if (rval & AS_FAULT_INFO_OVER_VOLTAGE)
+		dev_dbg(&client->dev, "Over voltage fault: "
+			"Indicates missing capacitor or open connection\n");
+
+	return rval;
+}
+
+static int as3645a_get_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct as3645a *flash =
+		container_of(ctrl->handler, struct as3645a, ctrls);
+	struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+	int value;
+
+	switch (ctrl->id) {
+	case V4L2_CID_FLASH_FAULT:
+		value = as3645a_read_fault(flash);
+		if (value < 0)
+			return value;
+
+		ctrl->cur.val = 0;
+		if (value & AS_FAULT_INFO_SHORT_CIRCUIT)
+			ctrl->cur.val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
+		if (value & AS_FAULT_INFO_OVER_TEMPERATURE)
+			ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
+		if (value & AS_FAULT_INFO_TIMEOUT)
+			ctrl->cur.val |= V4L2_FLASH_FAULT_TIMEOUT;
+		if (value & AS_FAULT_INFO_OVER_VOLTAGE)
+			ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
+		if (value & AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT)
+			ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_CURRENT;
+		if (value & AS_FAULT_INFO_INDICATOR_LED)
+			ctrl->cur.val |= V4L2_FLASH_FAULT_INDICATOR;
+		break;
+
+	case V4L2_CID_FLASH_STROBE_STATUS:
+		if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) {
+			ctrl->cur.val = 0;
+			break;
+		}
+
+		value = as3645a_is_active(flash);
+		if (value < 0)
+			return value;
+
+		ctrl->cur.val = value;
+		break;
+	}
+
+	dev_dbg(&client->dev, "G_CTRL %08x:%d\n", ctrl->id, ctrl->cur.val);
+
+	return 0;
+}
+
+static int as3645a_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct as3645a *flash =
+		container_of(ctrl->handler, struct as3645a, ctrls);
+	struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+	int ret;
+
+	dev_dbg(&client->dev, "S_CTRL %08x:%d\n", ctrl->id, ctrl->val);
+
+	/* If a control that doesn't apply to the current mode is modified,
+	 * we store the value and return immediately. The setting will be
+	 * applied when the LED mode is changed. Otherwise we apply the setting
+	 * immediately.
+	 */
+
+	switch (ctrl->id) {
+	case V4L2_CID_FLASH_LED_MODE:
+		if (flash->indicator_current)
+			return -EBUSY;
+
+		ret = as3645a_set_config(flash);
+		if (ret < 0)
+			return ret;
+
+		flash->led_mode = ctrl->val;
+		return as3645a_set_output(flash, false);
+
+	case V4L2_CID_FLASH_STROBE_SOURCE:
+		flash->strobe_source = ctrl->val;
+
+		/* Applies to flash mode only. */
+		if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+			break;
+
+		return as3645a_set_output(flash, false);
+
+	case V4L2_CID_FLASH_STROBE:
+		if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+			return -EBUSY;
+
+		return as3645a_set_output(flash, true);
+
+	case V4L2_CID_FLASH_STROBE_STOP:
+		if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+			return -EBUSY;
+
+		return as3645a_set_output(flash, false);
+
+	case V4L2_CID_FLASH_TIMEOUT:
+		flash->timeout = ctrl->val;
+
+		/* Applies to flash mode only. */
+		if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+			break;
+
+		return as3645a_set_config(flash);
+
+	case V4L2_CID_FLASH_INTENSITY:
+		flash->flash_current = (ctrl->val - AS3645A_FLASH_INTENSITY_MIN)
+				     / AS3645A_FLASH_INTENSITY_STEP;
+
+		/* Applies to flash mode only. */
+		if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+			break;
+
+		return as3645a_set_config(flash);
+
+	case V4L2_CID_FLASH_TORCH_INTENSITY:
+		flash->assist_current =
+			(ctrl->val - AS3645A_TORCH_INTENSITY_MIN)
+			/ AS3645A_TORCH_INTENSITY_STEP;
+
+		/* Applies to torch mode only. */
+		if (flash->led_mode != V4L2_FLASH_LED_MODE_TORCH)
+			break;
+
+		return as3645a_set_config(flash);
+
+	case V4L2_CID_FLASH_INDICATOR_INTENSITY:
+		if (flash->led_mode != V4L2_FLASH_LED_MODE_NONE)
+			return -EBUSY;
+
+		flash->indicator_current =
+			(ctrl->val - AS3645A_INDICATOR_INTENSITY_MIN)
+			/ AS3645A_INDICATOR_INTENSITY_STEP;
+
+		ret = as3645a_set_config(flash);
+		if (ret < 0)
+			return ret;
+
+		if ((ctrl->val == 0) == (ctrl->cur.val == 0))
+			break;
+
+		return as3645a_set_output(flash, false);
+	}
+
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops as3645a_ctrl_ops = {
+	.g_volatile_ctrl = as3645a_get_ctrl,
+	.s_ctrl = as3645a_set_ctrl,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+/* Put device into know state. */
+static int as3645a_setup(struct as3645a *flash)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+	int ret;
+
+	/* clear errors */
+	ret = as3645a_read(flash, AS_FAULT_INFO_REG);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(&client->dev, "Fault info: %02x\n", ret);
+
+	ret = as3645a_set_config(flash);
+	if (ret < 0)
+		return ret;
+
+	ret = as3645a_set_output(flash, false);
+	if (ret < 0)
+		return ret;
+
+	/* read status */
+	ret = as3645a_read_fault(flash);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(&client->dev, "AS_INDICATOR_AND_TIMER_REG: %02x\n",
+		as3645a_read(flash, AS_INDICATOR_AND_TIMER_REG));
+	dev_dbg(&client->dev, "AS_CURRENT_SET_REG: %02x\n",
+		as3645a_read(flash, AS_CURRENT_SET_REG));
+	dev_dbg(&client->dev, "AS_CONTROL_REG: %02x\n",
+		as3645a_read(flash, AS_CONTROL_REG));
+
+	return ret & ~AS_FAULT_INFO_LED_AMOUNT ? -EIO : 0;
+}
+
+static int __as3645a_set_power(struct as3645a *flash, int on)
+{
+	int ret;
+
+	if (!on)
+		as3645a_set_control(flash, AS_MODE_EXT_TORCH, false);
+
+	if (flash->pdata->set_power) {
+		ret = flash->pdata->set_power(&flash->subdev, on);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (!on)
+		return 0;
+
+	ret = as3645a_setup(flash);
+	if (ret < 0) {
+		if (flash->pdata->set_power)
+			flash->pdata->set_power(&flash->subdev, 0);
+	}
+
+	return ret;
+}
+
+static int as3645a_set_power(struct v4l2_subdev *sd, int on)
+{
+	struct as3645a *flash = to_as3645a(sd);
+	int ret = 0;
+
+	mutex_lock(&flash->power_lock);
+
+	if (flash->power_count == !on) {
+		ret = __as3645a_set_power(flash, !!on);
+		if (ret < 0)
+			goto done;
+	}
+
+	flash->power_count += on ? 1 : -1;
+	WARN_ON(flash->power_count < 0);
+
+done:
+	mutex_unlock(&flash->power_lock);
+	return ret;
+}
+
+static int as3645a_registered(struct v4l2_subdev *sd)
+{
+	struct as3645a *flash = to_as3645a(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int rval, man, model, rfu, version;
+	const char *vendor;
+
+	/* Power up the flash driver and read manufacturer ID, model ID, RFU
+	 * and version.
+	 */
+	rval = as3645a_set_power(&flash->subdev, 1);
+	if (rval < 0)
+		return rval;
+
+	rval = as3645a_read(flash, AS_DESIGN_INFO_REG);
+	if (rval < 0)
+		goto power_off;
+
+	man = AS_DESIGN_INFO_FACTORY(rval);
+	model = AS_DESIGN_INFO_MODEL(rval);
+
+	rval = as3645a_read(flash, AS_VERSION_CONTROL_REG);
+	if (rval < 0)
+		goto power_off;
+
+	rfu = AS_VERSION_CONTROL_RFU(rval);
+	version = AS_VERSION_CONTROL_VERSION(rval);
+
+	/* Verify the chip model and version. */
+	if (model != 0x01 || rfu != 0x00) {
+		dev_err(&client->dev, "AS3645A not detected "
+			"(model %d rfu %d)\n", model, rfu);
+		rval = -ENODEV;
+		goto power_off;
+	}
+
+	switch (man) {
+	case 1:
+		vendor = "AMS, Austria Micro Systems";
+		break;
+	case 2:
+		vendor = "ADI, Analog Devices Inc.";
+		break;
+	case 3:
+		vendor = "NSC, National Semiconductor";
+		break;
+	case 4:
+		vendor = "NXP";
+		break;
+	case 5:
+		vendor = "TI, Texas Instrument";
+		break;
+	default:
+		vendor = "Unknown";
+	}
+
+	dev_info(&client->dev, "Chip vendor: %s (%d) Version: %d\n", vendor,
+		 man, version);
+
+	rval = as3645a_write(flash, AS_PASSWORD_REG, AS_PASSWORD_UNLOCK_VALUE);
+	if (rval < 0)
+		goto power_off;
+
+	rval = as3645a_write(flash, AS_BOOST_REG, AS_BOOST_CURRENT_DISABLE);
+	if (rval < 0)
+		goto power_off;
+
+	/* Setup default values. This makes sure that the chip is in a known
+	 * state, in case the power rail can't be controlled.
+	 */
+	rval = as3645a_setup(flash);
+
+power_off:
+	as3645a_set_power(&flash->subdev, 0);
+
+	return rval;
+}
+
+static int as3645a_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	return as3645a_set_power(sd, 1);
+}
+
+static int as3645a_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	return as3645a_set_power(sd, 0);
+}
+
+static const struct v4l2_subdev_core_ops as3645a_core_ops = {
+	.s_power		= as3645a_set_power,
+};
+
+static const struct v4l2_subdev_ops as3645a_ops = {
+	.core = &as3645a_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops as3645a_internal_ops = {
+	.registered = as3645a_registered,
+	.open = as3645a_open,
+	.close = as3645a_close,
+};
+
+/* -----------------------------------------------------------------------------
+ *  I2C driver
+ */
+#ifdef CONFIG_PM
+
+static int as3645a_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct as3645a *flash = to_as3645a(subdev);
+	int rval;
+
+	if (flash->power_count == 0)
+		return 0;
+
+	rval = __as3645a_set_power(flash, 0);
+
+	dev_dbg(&client->dev, "Suspend %s\n", rval < 0 ? "failed" : "ok");
+
+	return rval;
+}
+
+static int as3645a_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct as3645a *flash = to_as3645a(subdev);
+	int rval;
+
+	if (flash->power_count == 0)
+		return 0;
+
+	rval = __as3645a_set_power(flash, 1);
+
+	dev_dbg(&client->dev, "Resume %s\n", rval < 0 ? "fail" : "ok");
+
+	return rval;
+}
+
+#else
+
+#define as3645a_suspend	NULL
+#define as3645a_resume	NULL
+
+#endif /* CONFIG_PM */
+
+/*
+ * as3645a_init_controls - Create controls
+ * @flash: The flash
+ *
+ * The number of LEDs reported in platform data is used to compute default
+ * limits. Parameters passed through platform data can override those limits.
+ */
+static int __devinit as3645a_init_controls(struct as3645a *flash)
+{
+	const struct as3645a_platform_data *pdata = flash->pdata;
+	struct v4l2_ctrl *ctrl;
+	int maximum;
+
+	v4l2_ctrl_handler_init(&flash->ctrls, 10);
+
+	/* V4L2_CID_FLASH_LED_MODE */
+	v4l2_ctrl_new_std_menu(&flash->ctrls, &as3645a_ctrl_ops,
+			       V4L2_CID_FLASH_LED_MODE, 2, ~7,
+			       V4L2_FLASH_LED_MODE_NONE);
+
+	/* V4L2_CID_FLASH_STROBE_SOURCE */
+	v4l2_ctrl_new_std_menu(&flash->ctrls, &as3645a_ctrl_ops,
+			       V4L2_CID_FLASH_STROBE_SOURCE,
+			       pdata->ext_strobe ? 1 : 0,
+			       pdata->ext_strobe ? ~3 : ~1,
+			       V4L2_FLASH_STROBE_SOURCE_SOFTWARE);
+
+	flash->strobe_source = V4L2_FLASH_STROBE_SOURCE_SOFTWARE;
+
+	/* V4L2_CID_FLASH_STROBE */
+	v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+			  V4L2_CID_FLASH_STROBE, 0, 0, 0, 0);
+
+	/* V4L2_CID_FLASH_STROBE_STOP */
+	v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+			  V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0);
+
+	/* V4L2_CID_FLASH_STROBE_STATUS */
+	ctrl = v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+				 V4L2_CID_FLASH_STROBE_STATUS, 0, 1, 1, 1);
+	if (ctrl != NULL)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+	/* V4L2_CID_FLASH_TIMEOUT */
+	maximum = pdata->timeout_max;
+
+	v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+			  V4L2_CID_FLASH_TIMEOUT, AS3645A_FLASH_TIMEOUT_MIN,
+			  maximum, AS3645A_FLASH_TIMEOUT_STEP, maximum);
+
+	flash->timeout = maximum;
+
+	/* V4L2_CID_FLASH_INTENSITY */
+	maximum = pdata->flash_max_current;
+
+	v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+			  V4L2_CID_FLASH_INTENSITY, AS3645A_FLASH_INTENSITY_MIN,
+			  maximum, AS3645A_FLASH_INTENSITY_STEP, maximum);
+
+	flash->flash_current = (maximum - AS3645A_FLASH_INTENSITY_MIN)
+			     / AS3645A_FLASH_INTENSITY_STEP;
+
+	/* V4L2_CID_FLASH_TORCH_INTENSITY */
+	maximum = pdata->torch_max_current;
+
+	v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+			  V4L2_CID_FLASH_TORCH_INTENSITY,
+			  AS3645A_TORCH_INTENSITY_MIN, maximum,
+			  AS3645A_TORCH_INTENSITY_STEP,
+			  AS3645A_TORCH_INTENSITY_MIN);
+
+	flash->assist_current = 0;
+
+	/* V4L2_CID_FLASH_INDICATOR_INTENSITY */
+	v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+			  V4L2_CID_FLASH_INDICATOR_INTENSITY,
+			  AS3645A_INDICATOR_INTENSITY_MIN,
+			  AS3645A_INDICATOR_INTENSITY_MAX,
+			  AS3645A_INDICATOR_INTENSITY_STEP,
+			  AS3645A_INDICATOR_INTENSITY_MIN);
+
+	flash->indicator_current = 0;
+
+	/* V4L2_CID_FLASH_FAULT */
+	ctrl = v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+				 V4L2_CID_FLASH_FAULT, 0,
+				 V4L2_FLASH_FAULT_OVER_VOLTAGE |
+				 V4L2_FLASH_FAULT_TIMEOUT |
+				 V4L2_FLASH_FAULT_OVER_TEMPERATURE |
+				 V4L2_FLASH_FAULT_SHORT_CIRCUIT, 0, 0);
+	if (ctrl != NULL)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+	flash->subdev.ctrl_handler = &flash->ctrls;
+
+	return flash->ctrls.error;
+}
+
+static int __devinit as3645a_probe(struct i2c_client *client,
+				   const struct i2c_device_id *devid)
+{
+	struct as3645a *flash;
+	int ret;
+
+	if (client->dev.platform_data == NULL)
+		return -ENODEV;
+
+	flash = kzalloc(sizeof(*flash), GFP_KERNEL);
+	if (flash == NULL)
+		return -ENOMEM;
+
+	flash->pdata = client->dev.platform_data;
+
+	v4l2_i2c_subdev_init(&flash->subdev, client, &as3645a_ops);
+	flash->subdev.internal_ops = &as3645a_internal_ops;
+	flash->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	ret = as3645a_init_controls(flash);
+	if (ret < 0)
+		goto done;
+
+	ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0);
+	if (ret < 0)
+		goto done;
+
+	flash->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
+
+	mutex_init(&flash->power_lock);
+
+	flash->led_mode = V4L2_FLASH_LED_MODE_NONE;
+
+done:
+	if (ret < 0) {
+		v4l2_ctrl_handler_free(&flash->ctrls);
+		kfree(flash);
+	}
+
+	return ret;
+}
+
+static int __devexit as3645a_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct as3645a *flash = to_as3645a(subdev);
+
+	v4l2_device_unregister_subdev(subdev);
+	v4l2_ctrl_handler_free(&flash->ctrls);
+	media_entity_cleanup(&flash->subdev.entity);
+	mutex_destroy(&flash->power_lock);
+	kfree(flash);
+
+	return 0;
+}
+
+static const struct i2c_device_id as3645a_id_table[] = {
+	{ AS3645A_NAME, 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, as3645a_id_table);
+
+static const struct dev_pm_ops as3645a_pm_ops = {
+	.suspend = as3645a_suspend,
+	.resume = as3645a_resume,
+};
+
+static struct i2c_driver as3645a_i2c_driver = {
+	.driver	= {
+		.name = AS3645A_NAME,
+		.pm   = &as3645a_pm_ops,
+	},
+	.probe	= as3645a_probe,
+	.remove	= __devexit_p(as3645a_remove),
+	.id_table = as3645a_id_table,
+};
+
+module_i2c_driver(as3645a_i2c_driver);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("LED flash driver for AS3645A, LM3555 and their clones");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/bt819.c b/drivers/media/i2c/bt819.c
new file mode 100644
index 0000000..377bf05
--- /dev/null
+++ b/drivers/media/i2c/bt819.c
@@ -0,0 +1,517 @@
+/*
+ *  bt819 - BT819A VideoStream Decoder (Rockwell Part)
+ *
+ * Copyright (C) 1999 Mike Bernson <mike@mlb.org>
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ *
+ * Modifications for LML33/DC10plus unified driver
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *    - moved over to linux>=2.4.x i2c protocol (9/9/2002)
+ *
+ * This code was modify/ported from the saa7111 driver written
+ * by Dave Perks.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+#include <media/bt819.h>
+
+MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
+MODULE_AUTHOR("Mike Bernson & Dave Perks");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+
+/* ----------------------------------------------------------------------- */
+
+struct bt819 {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	unsigned char reg[32];
+
+	v4l2_std_id norm;
+	int ident;
+	int input;
+	int enable;
+};
+
+static inline struct bt819 *to_bt819(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct bt819, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct bt819, hdl)->sd;
+}
+
+struct timing {
+	int hactive;
+	int hdelay;
+	int vactive;
+	int vdelay;
+	int hscale;
+	int vscale;
+};
+
+/* for values, see the bt819 datasheet */
+static struct timing timing_data[] = {
+	{864 - 24, 20, 625 - 2, 1, 0x0504, 0x0000},
+	{858 - 24, 20, 525 - 2, 1, 0x00f8, 0x0000},
+};
+
+/* ----------------------------------------------------------------------- */
+
+static inline int bt819_write(struct bt819 *decoder, u8 reg, u8 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd);
+
+	decoder->reg[reg] = value;
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline int bt819_setbit(struct bt819 *decoder, u8 reg, u8 bit, u8 value)
+{
+	return bt819_write(decoder, reg,
+		(decoder->reg[reg] & ~(1 << bit)) | (value ? (1 << bit) : 0));
+}
+
+static int bt819_write_block(struct bt819 *decoder, const u8 *data, unsigned int len)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd);
+	int ret = -1;
+	u8 reg;
+
+	/* the bt819 has an autoincrement function, use it if
+	 * the adapter understands raw I2C */
+	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		/* do raw I2C, not smbus compatible */
+		u8 block_data[32];
+		int block_len;
+
+		while (len >= 2) {
+			block_len = 0;
+			block_data[block_len++] = reg = data[0];
+			do {
+				block_data[block_len++] =
+				    decoder->reg[reg++] = data[1];
+				len -= 2;
+				data += 2;
+			} while (len >= 2 && data[0] == reg && block_len < 32);
+			ret = i2c_master_send(client, block_data, block_len);
+			if (ret < 0)
+				break;
+		}
+	} else {
+		/* do some slow I2C emulation kind of thing */
+		while (len >= 2) {
+			reg = *data++;
+			ret = bt819_write(decoder, reg, *data++);
+			if (ret < 0)
+				break;
+			len -= 2;
+		}
+	}
+
+	return ret;
+}
+
+static inline int bt819_read(struct bt819 *decoder, u8 reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd);
+
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int bt819_init(struct v4l2_subdev *sd)
+{
+	static unsigned char init[] = {
+		/*0x1f, 0x00,*/     /* Reset */
+		0x01, 0x59,	/* 0x01 input format */
+		0x02, 0x00,	/* 0x02 temporal decimation */
+		0x03, 0x12,	/* 0x03 Cropping msb */
+		0x04, 0x16,	/* 0x04 Vertical Delay, lsb */
+		0x05, 0xe0,	/* 0x05 Vertical Active lsb */
+		0x06, 0x80,	/* 0x06 Horizontal Delay lsb */
+		0x07, 0xd0,	/* 0x07 Horizontal Active lsb */
+		0x08, 0x00,	/* 0x08 Horizontal Scaling msb */
+		0x09, 0xf8,	/* 0x09 Horizontal Scaling lsb */
+		0x0a, 0x00,	/* 0x0a Brightness control */
+		0x0b, 0x30,	/* 0x0b Miscellaneous control */
+		0x0c, 0xd8,	/* 0x0c Luma Gain lsb */
+		0x0d, 0xfe,	/* 0x0d Chroma Gain (U) lsb */
+		0x0e, 0xb4,	/* 0x0e Chroma Gain (V) msb */
+		0x0f, 0x00,	/* 0x0f Hue control */
+		0x12, 0x04,	/* 0x12 Output Format */
+		0x13, 0x20,	/* 0x13 Vertial Scaling msb 0x00
+					   chroma comb OFF, line drop scaling, interlace scaling
+					   BUG? Why does turning the chroma comb on fuck up color?
+					   Bug in the bt819 stepping on my board?
+					*/
+		0x14, 0x00,	/* 0x14 Vertial Scaling lsb */
+		0x16, 0x07,	/* 0x16 Video Timing Polarity
+					   ACTIVE=active low
+					   FIELD: high=odd,
+					   vreset=active high,
+					   hreset=active high */
+		0x18, 0x68,	/* 0x18 AGC Delay */
+		0x19, 0x5d,	/* 0x19 Burst Gate Delay */
+		0x1a, 0x80,	/* 0x1a ADC Interface */
+	};
+
+	struct bt819 *decoder = to_bt819(sd);
+	struct timing *timing = &timing_data[(decoder->norm & V4L2_STD_525_60) ? 1 : 0];
+
+	init[0x03 * 2 - 1] =
+	    (((timing->vdelay >> 8) & 0x03) << 6) |
+	    (((timing->vactive >> 8) & 0x03) << 4) |
+	    (((timing->hdelay >> 8) & 0x03) << 2) |
+	    ((timing->hactive >> 8) & 0x03);
+	init[0x04 * 2 - 1] = timing->vdelay & 0xff;
+	init[0x05 * 2 - 1] = timing->vactive & 0xff;
+	init[0x06 * 2 - 1] = timing->hdelay & 0xff;
+	init[0x07 * 2 - 1] = timing->hactive & 0xff;
+	init[0x08 * 2 - 1] = timing->hscale >> 8;
+	init[0x09 * 2 - 1] = timing->hscale & 0xff;
+	/* 0x15 in array is address 0x19 */
+	init[0x15 * 2 - 1] = (decoder->norm & V4L2_STD_625_50) ? 115 : 93;	/* Chroma burst delay */
+	/* reset */
+	bt819_write(decoder, 0x1f, 0x00);
+	mdelay(1);
+
+	/* init */
+	return bt819_write_block(decoder, init, sizeof(init));
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int bt819_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
+{
+	struct bt819 *decoder = to_bt819(sd);
+	int status = bt819_read(decoder, 0x00);
+	int res = V4L2_IN_ST_NO_SIGNAL;
+	v4l2_std_id std;
+
+	if ((status & 0x80))
+		res = 0;
+
+	if ((status & 0x10))
+		std = V4L2_STD_PAL;
+	else
+		std = V4L2_STD_NTSC;
+	if (pstd)
+		*pstd = std;
+	if (pstatus)
+		*pstatus = res;
+
+	v4l2_dbg(1, debug, sd, "get status %x\n", status);
+	return 0;
+}
+
+static int bt819_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	return bt819_status(sd, NULL, std);
+}
+
+static int bt819_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+	return bt819_status(sd, status, NULL);
+}
+
+static int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct bt819 *decoder = to_bt819(sd);
+	struct timing *timing = NULL;
+
+	v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
+
+	if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL)
+		v4l2_err(sd, "no notify found!\n");
+
+	if (std & V4L2_STD_NTSC) {
+		v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL);
+		bt819_setbit(decoder, 0x01, 0, 1);
+		bt819_setbit(decoder, 0x01, 1, 0);
+		bt819_setbit(decoder, 0x01, 5, 0);
+		bt819_write(decoder, 0x18, 0x68);
+		bt819_write(decoder, 0x19, 0x5d);
+		/* bt819_setbit(decoder, 0x1a,  5, 1); */
+		timing = &timing_data[1];
+	} else if (std & V4L2_STD_PAL) {
+		v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL);
+		bt819_setbit(decoder, 0x01, 0, 1);
+		bt819_setbit(decoder, 0x01, 1, 1);
+		bt819_setbit(decoder, 0x01, 5, 1);
+		bt819_write(decoder, 0x18, 0x7f);
+		bt819_write(decoder, 0x19, 0x72);
+		/* bt819_setbit(decoder, 0x1a,  5, 0); */
+		timing = &timing_data[0];
+	} else {
+		v4l2_dbg(1, debug, sd, "unsupported norm %llx\n",
+				(unsigned long long)std);
+		return -EINVAL;
+	}
+	bt819_write(decoder, 0x03,
+			(((timing->vdelay >> 8) & 0x03) << 6) |
+			(((timing->vactive >> 8) & 0x03) << 4) |
+			(((timing->hdelay >> 8) & 0x03) << 2) |
+			((timing->hactive >> 8) & 0x03));
+	bt819_write(decoder, 0x04, timing->vdelay & 0xff);
+	bt819_write(decoder, 0x05, timing->vactive & 0xff);
+	bt819_write(decoder, 0x06, timing->hdelay & 0xff);
+	bt819_write(decoder, 0x07, timing->hactive & 0xff);
+	bt819_write(decoder, 0x08, (timing->hscale >> 8) & 0xff);
+	bt819_write(decoder, 0x09, timing->hscale & 0xff);
+	decoder->norm = std;
+	v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, NULL);
+	return 0;
+}
+
+static int bt819_s_routing(struct v4l2_subdev *sd,
+			   u32 input, u32 output, u32 config)
+{
+	struct bt819 *decoder = to_bt819(sd);
+
+	v4l2_dbg(1, debug, sd, "set input %x\n", input);
+
+	if (input > 7)
+		return -EINVAL;
+
+	if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL)
+		v4l2_err(sd, "no notify found!\n");
+
+	if (decoder->input != input) {
+		v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL);
+		decoder->input = input;
+		/* select mode */
+		if (decoder->input == 0) {
+			bt819_setbit(decoder, 0x0b, 6, 0);
+			bt819_setbit(decoder, 0x1a, 1, 1);
+		} else {
+			bt819_setbit(decoder, 0x0b, 6, 1);
+			bt819_setbit(decoder, 0x1a, 1, 0);
+		}
+		v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, NULL);
+	}
+	return 0;
+}
+
+static int bt819_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct bt819 *decoder = to_bt819(sd);
+
+	v4l2_dbg(1, debug, sd, "enable output %x\n", enable);
+
+	if (decoder->enable != enable) {
+		decoder->enable = enable;
+		bt819_setbit(decoder, 0x16, 7, !enable);
+	}
+	return 0;
+}
+
+static int bt819_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct bt819 *decoder = to_bt819(sd);
+	int temp;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		bt819_write(decoder, 0x0a, ctrl->val);
+		break;
+
+	case V4L2_CID_CONTRAST:
+		bt819_write(decoder, 0x0c, ctrl->val & 0xff);
+		bt819_setbit(decoder, 0x0b, 2, ((ctrl->val >> 8) & 0x01));
+		break;
+
+	case V4L2_CID_SATURATION:
+		bt819_write(decoder, 0x0d, (ctrl->val >> 7) & 0xff);
+		bt819_setbit(decoder, 0x0b, 1, ((ctrl->val >> 15) & 0x01));
+
+		/* Ratio between U gain and V gain must stay the same as
+		   the ratio between the default U and V gain values. */
+		temp = (ctrl->val * 180) / 254;
+		bt819_write(decoder, 0x0e, (temp >> 7) & 0xff);
+		bt819_setbit(decoder, 0x0b, 0, (temp >> 15) & 0x01);
+		break;
+
+	case V4L2_CID_HUE:
+		bt819_write(decoder, 0x0f, ctrl->val);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int bt819_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct bt819 *decoder = to_bt819(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_ctrl_ops bt819_ctrl_ops = {
+	.s_ctrl = bt819_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops bt819_core_ops = {
+	.g_chip_ident = bt819_g_chip_ident,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+	.s_std = bt819_s_std,
+};
+
+static const struct v4l2_subdev_video_ops bt819_video_ops = {
+	.s_routing = bt819_s_routing,
+	.s_stream = bt819_s_stream,
+	.querystd = bt819_querystd,
+	.g_input_status = bt819_g_input_status,
+};
+
+static const struct v4l2_subdev_ops bt819_ops = {
+	.core = &bt819_core_ops,
+	.video = &bt819_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int bt819_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int i, ver;
+	struct bt819 *decoder;
+	struct v4l2_subdev *sd;
+	const char *name;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	decoder = kzalloc(sizeof(struct bt819), GFP_KERNEL);
+	if (decoder == NULL)
+		return -ENOMEM;
+	sd = &decoder->sd;
+	v4l2_i2c_subdev_init(sd, client, &bt819_ops);
+
+	ver = bt819_read(decoder, 0x17);
+	switch (ver & 0xf0) {
+	case 0x70:
+		name = "bt819a";
+		decoder->ident = V4L2_IDENT_BT819A;
+		break;
+	case 0x60:
+		name = "bt817a";
+		decoder->ident = V4L2_IDENT_BT817A;
+		break;
+	case 0x20:
+		name = "bt815a";
+		decoder->ident = V4L2_IDENT_BT815A;
+		break;
+	default:
+		v4l2_dbg(1, debug, sd,
+			"unknown chip version 0x%02x\n", ver);
+		return -ENODEV;
+	}
+
+	v4l_info(client, "%s found @ 0x%x (%s)\n", name,
+			client->addr << 1, client->adapter->name);
+
+	decoder->norm = V4L2_STD_NTSC;
+	decoder->input = 0;
+	decoder->enable = 1;
+
+	i = bt819_init(sd);
+	if (i < 0)
+		v4l2_dbg(1, debug, sd, "init status %d\n", i);
+
+	v4l2_ctrl_handler_init(&decoder->hdl, 4);
+	v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
+	v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 511, 1, 0xd8);
+	v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 511, 1, 0xfe);
+	v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
+			V4L2_CID_HUE, -128, 127, 1, 0);
+	sd->ctrl_handler = &decoder->hdl;
+	if (decoder->hdl.error) {
+		int err = decoder->hdl.error;
+
+		v4l2_ctrl_handler_free(&decoder->hdl);
+		kfree(decoder);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&decoder->hdl);
+	return 0;
+}
+
+static int bt819_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct bt819 *decoder = to_bt819(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&decoder->hdl);
+	kfree(decoder);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id bt819_id[] = {
+	{ "bt819a", 0 },
+	{ "bt817a", 0 },
+	{ "bt815a", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, bt819_id);
+
+static struct i2c_driver bt819_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "bt819",
+	},
+	.probe		= bt819_probe,
+	.remove		= bt819_remove,
+	.id_table	= bt819_id,
+};
+
+module_i2c_driver(bt819_driver);
diff --git a/drivers/media/i2c/bt856.c b/drivers/media/i2c/bt856.c
new file mode 100644
index 0000000..7e5bd36
--- /dev/null
+++ b/drivers/media/i2c/bt856.c
@@ -0,0 +1,273 @@
+/*
+ * bt856 - BT856A Digital Video Encoder (Rockwell Part)
+ *
+ * Copyright (C) 1999 Mike Bernson <mike@mlb.org>
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ *
+ * Modifications for LML33/DC10plus unified driver
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * This code was modify/ported from the saa7111 driver written
+ * by Dave Perks.
+ *
+ * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *   - moved over to linux>=2.4.x i2c protocol (9/9/2002)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
+MODULE_AUTHOR("Mike Bernson & Dave Perks");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+
+/* ----------------------------------------------------------------------- */
+
+#define BT856_REG_OFFSET	0xDA
+#define BT856_NR_REG		6
+
+struct bt856 {
+	struct v4l2_subdev sd;
+	unsigned char reg[BT856_NR_REG];
+
+	v4l2_std_id norm;
+};
+
+static inline struct bt856 *to_bt856(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct bt856, sd);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static inline int bt856_write(struct bt856 *encoder, u8 reg, u8 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd);
+
+	encoder->reg[reg - BT856_REG_OFFSET] = value;
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline int bt856_setbit(struct bt856 *encoder, u8 reg, u8 bit, u8 value)
+{
+	return bt856_write(encoder, reg,
+		(encoder->reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) |
+				(value ? (1 << bit) : 0));
+}
+
+static void bt856_dump(struct bt856 *encoder)
+{
+	int i;
+
+	v4l2_info(&encoder->sd, "register dump:\n");
+	for (i = 0; i < BT856_NR_REG; i += 2)
+		printk(KERN_CONT " %02x", encoder->reg[i]);
+	printk(KERN_CONT "\n");
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int bt856_init(struct v4l2_subdev *sd, u32 arg)
+{
+	struct bt856 *encoder = to_bt856(sd);
+
+	/* This is just for testing!!! */
+	v4l2_dbg(1, debug, sd, "init\n");
+	bt856_write(encoder, 0xdc, 0x18);
+	bt856_write(encoder, 0xda, 0);
+	bt856_write(encoder, 0xde, 0);
+
+	bt856_setbit(encoder, 0xdc, 3, 1);
+	/*bt856_setbit(encoder, 0xdc, 6, 0);*/
+	bt856_setbit(encoder, 0xdc, 4, 1);
+
+	if (encoder->norm & V4L2_STD_NTSC)
+		bt856_setbit(encoder, 0xdc, 2, 0);
+	else
+		bt856_setbit(encoder, 0xdc, 2, 1);
+
+	bt856_setbit(encoder, 0xdc, 1, 1);
+	bt856_setbit(encoder, 0xde, 4, 0);
+	bt856_setbit(encoder, 0xde, 3, 1);
+	if (debug != 0)
+		bt856_dump(encoder);
+	return 0;
+}
+
+static int bt856_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct bt856 *encoder = to_bt856(sd);
+
+	v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
+
+	if (std & V4L2_STD_NTSC) {
+		bt856_setbit(encoder, 0xdc, 2, 0);
+	} else if (std & V4L2_STD_PAL) {
+		bt856_setbit(encoder, 0xdc, 2, 1);
+		bt856_setbit(encoder, 0xda, 0, 0);
+		/*bt856_setbit(encoder, 0xda, 0, 1);*/
+	} else {
+		return -EINVAL;
+	}
+	encoder->norm = std;
+	if (debug != 0)
+		bt856_dump(encoder);
+	return 0;
+}
+
+static int bt856_s_routing(struct v4l2_subdev *sd,
+			   u32 input, u32 output, u32 config)
+{
+	struct bt856 *encoder = to_bt856(sd);
+
+	v4l2_dbg(1, debug, sd, "set input %d\n", input);
+
+	/* We only have video bus.
+	 * input= 0: input is from bt819
+	 * input= 1: input is from ZR36060 */
+	switch (input) {
+	case 0:
+		bt856_setbit(encoder, 0xde, 4, 0);
+		bt856_setbit(encoder, 0xde, 3, 1);
+		bt856_setbit(encoder, 0xdc, 3, 1);
+		bt856_setbit(encoder, 0xdc, 6, 0);
+		break;
+	case 1:
+		bt856_setbit(encoder, 0xde, 4, 0);
+		bt856_setbit(encoder, 0xde, 3, 1);
+		bt856_setbit(encoder, 0xdc, 3, 1);
+		bt856_setbit(encoder, 0xdc, 6, 1);
+		break;
+	case 2:	/* Color bar */
+		bt856_setbit(encoder, 0xdc, 3, 0);
+		bt856_setbit(encoder, 0xde, 4, 1);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (debug != 0)
+		bt856_dump(encoder);
+	return 0;
+}
+
+static int bt856_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT856, 0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops bt856_core_ops = {
+	.g_chip_ident = bt856_g_chip_ident,
+	.init = bt856_init,
+};
+
+static const struct v4l2_subdev_video_ops bt856_video_ops = {
+	.s_std_output = bt856_s_std_output,
+	.s_routing = bt856_s_routing,
+};
+
+static const struct v4l2_subdev_ops bt856_ops = {
+	.core = &bt856_core_ops,
+	.video = &bt856_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int bt856_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct bt856 *encoder;
+	struct v4l2_subdev *sd;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	encoder = kzalloc(sizeof(struct bt856), GFP_KERNEL);
+	if (encoder == NULL)
+		return -ENOMEM;
+	sd = &encoder->sd;
+	v4l2_i2c_subdev_init(sd, client, &bt856_ops);
+	encoder->norm = V4L2_STD_NTSC;
+
+	bt856_write(encoder, 0xdc, 0x18);
+	bt856_write(encoder, 0xda, 0);
+	bt856_write(encoder, 0xde, 0);
+
+	bt856_setbit(encoder, 0xdc, 3, 1);
+	/*bt856_setbit(encoder, 0xdc, 6, 0);*/
+	bt856_setbit(encoder, 0xdc, 4, 1);
+
+	if (encoder->norm & V4L2_STD_NTSC)
+		bt856_setbit(encoder, 0xdc, 2, 0);
+	else
+		bt856_setbit(encoder, 0xdc, 2, 1);
+
+	bt856_setbit(encoder, 0xdc, 1, 1);
+	bt856_setbit(encoder, 0xde, 4, 0);
+	bt856_setbit(encoder, 0xde, 3, 1);
+
+	if (debug != 0)
+		bt856_dump(encoder);
+	return 0;
+}
+
+static int bt856_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_bt856(sd));
+	return 0;
+}
+
+static const struct i2c_device_id bt856_id[] = {
+	{ "bt856", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, bt856_id);
+
+static struct i2c_driver bt856_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "bt856",
+	},
+	.probe		= bt856_probe,
+	.remove		= bt856_remove,
+	.id_table	= bt856_id,
+};
+
+module_i2c_driver(bt856_driver);
diff --git a/drivers/media/i2c/bt866.c b/drivers/media/i2c/bt866.c
new file mode 100644
index 0000000..905320b
--- /dev/null
+++ b/drivers/media/i2c/bt866.c
@@ -0,0 +1,243 @@
+/*
+    bt866 - BT866 Digital Video Encoder (Rockwell Part)
+
+    Copyright (C) 1999 Mike Bernson <mike@mlb.org>
+    Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+    Modifications for LML33/DC10plus unified driver
+    Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+
+    This code was modify/ported from the saa7111 driver written
+    by Dave Perks.
+
+    This code was adapted for the bt866 by Christer Weinigel and ported
+    to 2.6 by Martin Samuelsson.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
+MODULE_AUTHOR("Mike Bernson & Dave Perks");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+
+/* ----------------------------------------------------------------------- */
+
+struct bt866 {
+	struct v4l2_subdev sd;
+	u8 reg[256];
+};
+
+static inline struct bt866 *to_bt866(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct bt866, sd);
+}
+
+static int bt866_write(struct bt866 *encoder, u8 subaddr, u8 data)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd);
+	u8 buffer[2];
+	int err;
+
+	buffer[0] = subaddr;
+	buffer[1] = data;
+
+	encoder->reg[subaddr] = data;
+
+	v4l_dbg(1, debug, client, "write 0x%02x = 0x%02x\n", subaddr, data);
+
+	for (err = 0; err < 3;) {
+		if (i2c_master_send(client, buffer, 2) == 2)
+			break;
+		err++;
+		v4l_warn(client, "error #%d writing to 0x%02x\n",
+				err, subaddr);
+		schedule_timeout_interruptible(msecs_to_jiffies(100));
+	}
+	if (err == 3) {
+		v4l_warn(client, "giving up\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int bt866_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
+
+	/* Only PAL supported by this driver at the moment! */
+	if (!(std & V4L2_STD_NTSC))
+		return -EINVAL;
+	return 0;
+}
+
+static int bt866_s_routing(struct v4l2_subdev *sd,
+			   u32 input, u32 output, u32 config)
+{
+	static const __u8 init[] = {
+		0xc8, 0xcc, /* CRSCALE */
+		0xca, 0x91, /* CBSCALE */
+		0xcc, 0x24, /* YC16 | OSDNUM */
+		0xda, 0x00, /*  */
+		0xdc, 0x24, /* SETMODE | PAL */
+		0xde, 0x02, /* EACTIVE */
+
+		/* overlay colors */
+		0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */
+		0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */
+		0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */
+		0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */
+		0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */
+		0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */
+		0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */
+		0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */
+
+		0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */
+		0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */
+		0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */
+		0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */
+		0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */
+		0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */
+		0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */
+		0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */
+	};
+	struct bt866 *encoder = to_bt866(sd);
+	u8 val;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
+		bt866_write(encoder, init[i], init[i+1]);
+
+	val = encoder->reg[0xdc];
+
+	if (input == 0)
+		val |= 0x40; /* CBSWAP */
+	else
+		val &= ~0x40; /* !CBSWAP */
+
+	bt866_write(encoder, 0xdc, val);
+
+	val = encoder->reg[0xcc];
+	if (input == 2)
+		val |= 0x01; /* OSDBAR */
+	else
+		val &= ~0x01; /* !OSDBAR */
+	bt866_write(encoder, 0xcc, val);
+
+	v4l2_dbg(1, debug, sd, "set input %d\n", input);
+
+	switch (input) {
+	case 0:
+	case 1:
+	case 2:
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+#if 0
+/* Code to setup square pixels, might be of some use in the future,
+   but is currently unused. */
+	val = encoder->reg[0xdc];
+	if (*iarg)
+		val |= 1; /* SQUARE */
+	else
+		val &= ~1; /* !SQUARE */
+	bt866_write(client, 0xdc, val);
+#endif
+
+static int bt866_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT866, 0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops bt866_core_ops = {
+	.g_chip_ident = bt866_g_chip_ident,
+};
+
+static const struct v4l2_subdev_video_ops bt866_video_ops = {
+	.s_std_output = bt866_s_std_output,
+	.s_routing = bt866_s_routing,
+};
+
+static const struct v4l2_subdev_ops bt866_ops = {
+	.core = &bt866_core_ops,
+	.video = &bt866_video_ops,
+};
+
+static int bt866_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct bt866 *encoder;
+	struct v4l2_subdev *sd;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
+	if (encoder == NULL)
+		return -ENOMEM;
+	sd = &encoder->sd;
+	v4l2_i2c_subdev_init(sd, client, &bt866_ops);
+	return 0;
+}
+
+static int bt866_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_bt866(sd));
+	return 0;
+}
+
+static const struct i2c_device_id bt866_id[] = {
+	{ "bt866", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, bt866_id);
+
+static struct i2c_driver bt866_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "bt866",
+	},
+	.probe		= bt866_probe,
+	.remove		= bt866_remove,
+	.id_table	= bt866_id,
+};
+
+module_i2c_driver(bt866_driver);
diff --git a/drivers/media/i2c/btcx-risc.c b/drivers/media/i2c/btcx-risc.c
new file mode 100644
index 0000000..ac1b268
--- /dev/null
+++ b/drivers/media/i2c/btcx-risc.c
@@ -0,0 +1,260 @@
+/*
+
+    btcx-risc.c
+
+    bt848/bt878/cx2388x risc code generator.
+
+    (c) 2000-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include "btcx-risc.h"
+
+MODULE_DESCRIPTION("some code shared by bttv and cx88xx drivers");
+MODULE_AUTHOR("Gerd Knorr");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"debug messages, default is 0 (no)");
+
+/* ---------------------------------------------------------- */
+/* allocate/free risc memory                                  */
+
+static int memcnt;
+
+void btcx_riscmem_free(struct pci_dev *pci,
+		       struct btcx_riscmem *risc)
+{
+	if (NULL == risc->cpu)
+		return;
+	if (debug) {
+		memcnt--;
+		printk("btcx: riscmem free [%d] dma=%lx\n",
+		       memcnt, (unsigned long)risc->dma);
+	}
+	pci_free_consistent(pci, risc->size, risc->cpu, risc->dma);
+	memset(risc,0,sizeof(*risc));
+}
+
+int btcx_riscmem_alloc(struct pci_dev *pci,
+		       struct btcx_riscmem *risc,
+		       unsigned int size)
+{
+	__le32 *cpu;
+	dma_addr_t dma = 0;
+
+	if (NULL != risc->cpu && risc->size < size)
+		btcx_riscmem_free(pci,risc);
+	if (NULL == risc->cpu) {
+		cpu = pci_alloc_consistent(pci, size, &dma);
+		if (NULL == cpu)
+			return -ENOMEM;
+		risc->cpu  = cpu;
+		risc->dma  = dma;
+		risc->size = size;
+		if (debug) {
+			memcnt++;
+			printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n",
+			       memcnt, (unsigned long)dma, cpu, size);
+		}
+	}
+	memset(risc->cpu,0,risc->size);
+	return 0;
+}
+
+/* ---------------------------------------------------------- */
+/* screen overlay helpers                                     */
+
+int
+btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
+		  struct v4l2_clip *clips, unsigned int n)
+{
+	if (win->left < 0) {
+		/* left */
+		clips[n].c.left = 0;
+		clips[n].c.top = 0;
+		clips[n].c.width  = -win->left;
+		clips[n].c.height = win->height;
+		n++;
+	}
+	if (win->left + win->width > swidth) {
+		/* right */
+		clips[n].c.left   = swidth - win->left;
+		clips[n].c.top    = 0;
+		clips[n].c.width  = win->width - clips[n].c.left;
+		clips[n].c.height = win->height;
+		n++;
+	}
+	if (win->top < 0) {
+		/* top */
+		clips[n].c.left = 0;
+		clips[n].c.top = 0;
+		clips[n].c.width  = win->width;
+		clips[n].c.height = -win->top;
+		n++;
+	}
+	if (win->top + win->height > sheight) {
+		/* bottom */
+		clips[n].c.left = 0;
+		clips[n].c.top = sheight - win->top;
+		clips[n].c.width  = win->width;
+		clips[n].c.height = win->height - clips[n].c.top;
+		n++;
+	}
+	return n;
+}
+
+int
+btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int mask)
+{
+	s32 nx,nw,dx;
+	unsigned int i;
+
+	/* fixup window */
+	nx = (win->left + mask) & ~mask;
+	nw = (win->width) & ~mask;
+	if (nx + nw > win->left + win->width)
+		nw -= mask+1;
+	dx = nx - win->left;
+	win->left  = nx;
+	win->width = nw;
+	if (debug)
+		printk(KERN_DEBUG "btcx: window align %dx%d+%d+%d [dx=%d]\n",
+		       win->width, win->height, win->left, win->top, dx);
+
+	/* fixup clips */
+	for (i = 0; i < n; i++) {
+		nx = (clips[i].c.left-dx) & ~mask;
+		nw = (clips[i].c.width) & ~mask;
+		if (nx + nw < clips[i].c.left-dx + clips[i].c.width)
+			nw += mask+1;
+		clips[i].c.left  = nx;
+		clips[i].c.width = nw;
+		if (debug)
+			printk(KERN_DEBUG "btcx:   clip align %dx%d+%d+%d\n",
+			       clips[i].c.width, clips[i].c.height,
+			       clips[i].c.left, clips[i].c.top);
+	}
+	return 0;
+}
+
+void
+btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips)
+{
+	struct v4l2_clip swap;
+	int i,j,n;
+
+	if (nclips < 2)
+		return;
+	for (i = nclips-2; i >= 0; i--) {
+		for (n = 0, j = 0; j <= i; j++) {
+			if (clips[j].c.left > clips[j+1].c.left) {
+				swap = clips[j];
+				clips[j] = clips[j+1];
+				clips[j+1] = swap;
+				n++;
+			}
+		}
+		if (0 == n)
+			break;
+	}
+}
+
+void
+btcx_calc_skips(int line, int width, int *maxy,
+		struct btcx_skiplist *skips, unsigned int *nskips,
+		const struct v4l2_clip *clips, unsigned int nclips)
+{
+	unsigned int clip,skip;
+	int end, maxline;
+
+	skip=0;
+	maxline = 9999;
+	for (clip = 0; clip < nclips; clip++) {
+
+		/* sanity checks */
+		if (clips[clip].c.left + clips[clip].c.width <= 0)
+			continue;
+		if (clips[clip].c.left > (signed)width)
+			break;
+
+		/* vertical range */
+		if (line > clips[clip].c.top+clips[clip].c.height-1)
+			continue;
+		if (line < clips[clip].c.top) {
+			if (maxline > clips[clip].c.top-1)
+				maxline = clips[clip].c.top-1;
+			continue;
+		}
+		if (maxline > clips[clip].c.top+clips[clip].c.height-1)
+			maxline = clips[clip].c.top+clips[clip].c.height-1;
+
+		/* horizontal range */
+		if (0 == skip || clips[clip].c.left > skips[skip-1].end) {
+			/* new one */
+			skips[skip].start = clips[clip].c.left;
+			if (skips[skip].start < 0)
+				skips[skip].start = 0;
+			skips[skip].end = clips[clip].c.left + clips[clip].c.width;
+			if (skips[skip].end > width)
+				skips[skip].end = width;
+			skip++;
+		} else {
+			/* overlaps -- expand last one */
+			end = clips[clip].c.left + clips[clip].c.width;
+			if (skips[skip-1].end < end)
+				skips[skip-1].end = end;
+			if (skips[skip-1].end > width)
+				skips[skip-1].end = width;
+		}
+	}
+	*nskips = skip;
+	*maxy = maxline;
+
+	if (debug) {
+		printk(KERN_DEBUG "btcx: skips line %d-%d:",line,maxline);
+		for (skip = 0; skip < *nskips; skip++) {
+			printk(" %d-%d",skips[skip].start,skips[skip].end);
+		}
+		printk("\n");
+	}
+}
+
+/* ---------------------------------------------------------- */
+
+EXPORT_SYMBOL(btcx_riscmem_alloc);
+EXPORT_SYMBOL(btcx_riscmem_free);
+
+EXPORT_SYMBOL(btcx_screen_clips);
+EXPORT_SYMBOL(btcx_align);
+EXPORT_SYMBOL(btcx_sort_clips);
+EXPORT_SYMBOL(btcx_calc_skips);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/i2c/btcx-risc.h b/drivers/media/i2c/btcx-risc.h
new file mode 100644
index 0000000..f8bc6e8
--- /dev/null
+++ b/drivers/media/i2c/btcx-risc.h
@@ -0,0 +1,34 @@
+/*
+ */
+struct btcx_riscmem {
+	unsigned int   size;
+	__le32         *cpu;
+	__le32         *jmp;
+	dma_addr_t     dma;
+};
+
+struct btcx_skiplist {
+	int start;
+	int end;
+};
+
+int  btcx_riscmem_alloc(struct pci_dev *pci,
+			struct btcx_riscmem *risc,
+			unsigned int size);
+void btcx_riscmem_free(struct pci_dev *pci,
+		       struct btcx_riscmem *risc);
+
+int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
+		      struct v4l2_clip *clips, unsigned int n);
+int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips,
+	       unsigned int n, int mask);
+void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips);
+void btcx_calc_skips(int line, int width, int *maxy,
+		     struct btcx_skiplist *skips, unsigned int *nskips,
+		     const struct v4l2_clip *clips, unsigned int nclips);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/i2c/cs5345.c b/drivers/media/i2c/cs5345.c
new file mode 100644
index 0000000..c8581e2
--- /dev/null
+++ b/drivers/media/i2c/cs5345.c
@@ -0,0 +1,252 @@
+/*
+ * cs5345 Cirrus Logic 24-bit, 192 kHz Stereo Audio ADC
+ * Copyright (C) 2007 Hans Verkuil
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static bool debug;
+
+module_param(debug, bool, 0644);
+
+MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On");
+
+struct cs5345_state {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+};
+
+static inline struct cs5345_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct cs5345_state, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct cs5345_state, hdl)->sd;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static inline int cs5345_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline int cs5345_read(struct v4l2_subdev *sd, u8 reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int cs5345_s_routing(struct v4l2_subdev *sd,
+			    u32 input, u32 output, u32 config)
+{
+	if ((input & 0xf) > 6) {
+		v4l2_err(sd, "Invalid input %d.\n", input);
+		return -EINVAL;
+	}
+	cs5345_write(sd, 0x09, input & 0xf);
+	cs5345_write(sd, 0x05, input & 0xf0);
+	return 0;
+}
+
+static int cs5345_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		cs5345_write(sd, 0x04, ctrl->val ? 0x80 : 0);
+		return 0;
+	case V4L2_CID_AUDIO_VOLUME:
+		cs5345_write(sd, 0x07, ((u8)ctrl->val) & 0x3f);
+		cs5345_write(sd, 0x08, ((u8)ctrl->val) & 0x3f);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int cs5345_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	reg->size = 1;
+	reg->val = cs5345_read(sd, reg->reg & 0x1f);
+	return 0;
+}
+
+static int cs5345_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	cs5345_write(sd, reg->reg & 0x1f, reg->val & 0xff);
+	return 0;
+}
+#endif
+
+static int cs5345_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_CS5345, 0);
+}
+
+static int cs5345_log_status(struct v4l2_subdev *sd)
+{
+	u8 v = cs5345_read(sd, 0x09) & 7;
+	u8 m = cs5345_read(sd, 0x04);
+	int vol = cs5345_read(sd, 0x08) & 0x3f;
+
+	v4l2_info(sd, "Input:  %d%s\n", v,
+			(m & 0x80) ? " (muted)" : "");
+	if (vol >= 32)
+		vol = vol - 64;
+	v4l2_info(sd, "Volume: %d dB\n", vol);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_ctrl_ops cs5345_ctrl_ops = {
+	.s_ctrl = cs5345_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops cs5345_core_ops = {
+	.log_status = cs5345_log_status,
+	.g_chip_ident = cs5345_g_chip_ident,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = cs5345_g_register,
+	.s_register = cs5345_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_audio_ops cs5345_audio_ops = {
+	.s_routing = cs5345_s_routing,
+};
+
+static const struct v4l2_subdev_ops cs5345_ops = {
+	.core = &cs5345_core_ops,
+	.audio = &cs5345_audio_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int cs5345_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct cs5345_state *state;
+	struct v4l2_subdev *sd;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	state = kzalloc(sizeof(struct cs5345_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &cs5345_ops);
+
+	v4l2_ctrl_handler_init(&state->hdl, 2);
+	v4l2_ctrl_new_std(&state->hdl, &cs5345_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&state->hdl, &cs5345_ctrl_ops,
+			V4L2_CID_AUDIO_VOLUME, -24, 24, 1, 0);
+	sd->ctrl_handler = &state->hdl;
+	if (state->hdl.error) {
+		int err = state->hdl.error;
+
+		v4l2_ctrl_handler_free(&state->hdl);
+		kfree(state);
+		return err;
+	}
+	/* set volume/mute */
+	v4l2_ctrl_handler_setup(&state->hdl);
+
+	cs5345_write(sd, 0x02, 0x00);
+	cs5345_write(sd, 0x04, 0x01);
+	cs5345_write(sd, 0x09, 0x01);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int cs5345_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct cs5345_state *state = to_state(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&state->hdl);
+	kfree(state);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id cs5345_id[] = {
+	{ "cs5345", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, cs5345_id);
+
+static struct i2c_driver cs5345_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "cs5345",
+	},
+	.probe		= cs5345_probe,
+	.remove		= cs5345_remove,
+	.id_table	= cs5345_id,
+};
+
+module_i2c_driver(cs5345_driver);
diff --git a/drivers/media/i2c/cs53l32a.c b/drivers/media/i2c/cs53l32a.c
new file mode 100644
index 0000000..b293912
--- /dev/null
+++ b/drivers/media/i2c/cs53l32a.c
@@ -0,0 +1,251 @@
+/*
+ * cs53l32a (Adaptec AVC-2010 and AVC-2410) i2c ivtv driver.
+ * Copyright (C) 2005  Martin Vaughan
+ *
+ * Audio source switching for Adaptec AVC-2410 added by Trev Jackson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
+MODULE_AUTHOR("Martin Vaughan");
+MODULE_LICENSE("GPL");
+
+static bool debug;
+
+module_param(debug, bool, 0644);
+
+MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On");
+
+
+struct cs53l32a_state {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+};
+
+static inline struct cs53l32a_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct cs53l32a_state, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct cs53l32a_state, hdl)->sd;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int cs53l32a_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int cs53l32a_read(struct v4l2_subdev *sd, u8 reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int cs53l32a_s_routing(struct v4l2_subdev *sd,
+			      u32 input, u32 output, u32 config)
+{
+	/* There are 2 physical inputs, but the second input can be
+	   placed in two modes, the first mode bypasses the PGA (gain),
+	   the second goes through the PGA. Hence there are three
+	   possible inputs to choose from. */
+	if (input > 2) {
+		v4l2_err(sd, "Invalid input %d.\n", input);
+		return -EINVAL;
+	}
+	cs53l32a_write(sd, 0x01, 0x01 + (input << 4));
+	return 0;
+}
+
+static int cs53l32a_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		cs53l32a_write(sd, 0x03, ctrl->val ? 0xf0 : 0x30);
+		return 0;
+	case V4L2_CID_AUDIO_VOLUME:
+		cs53l32a_write(sd, 0x04, (u8)ctrl->val);
+		cs53l32a_write(sd, 0x05, (u8)ctrl->val);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int cs53l32a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client,
+			chip, V4L2_IDENT_CS53l32A, 0);
+}
+
+static int cs53l32a_log_status(struct v4l2_subdev *sd)
+{
+	struct cs53l32a_state *state = to_state(sd);
+	u8 v = cs53l32a_read(sd, 0x01);
+
+	v4l2_info(sd, "Input:  %d\n", (v >> 4) & 3);
+	v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_ctrl_ops cs53l32a_ctrl_ops = {
+	.s_ctrl = cs53l32a_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops cs53l32a_core_ops = {
+	.log_status = cs53l32a_log_status,
+	.g_chip_ident = cs53l32a_g_chip_ident,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+};
+
+static const struct v4l2_subdev_audio_ops cs53l32a_audio_ops = {
+	.s_routing = cs53l32a_s_routing,
+};
+
+static const struct v4l2_subdev_ops cs53l32a_ops = {
+	.core = &cs53l32a_core_ops,
+	.audio = &cs53l32a_audio_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static int cs53l32a_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct cs53l32a_state *state;
+	struct v4l2_subdev *sd;
+	int i;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	if (!id)
+		strlcpy(client->name, "cs53l32a", sizeof(client->name));
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	state = kzalloc(sizeof(struct cs53l32a_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &cs53l32a_ops);
+
+	for (i = 1; i <= 7; i++) {
+		u8 v = cs53l32a_read(sd, i);
+
+		v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v);
+	}
+
+	v4l2_ctrl_handler_init(&state->hdl, 2);
+	v4l2_ctrl_new_std(&state->hdl, &cs53l32a_ctrl_ops,
+			V4L2_CID_AUDIO_VOLUME, -96, 12, 1, 0);
+	v4l2_ctrl_new_std(&state->hdl, &cs53l32a_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+	sd->ctrl_handler = &state->hdl;
+	if (state->hdl.error) {
+		int err = state->hdl.error;
+
+		v4l2_ctrl_handler_free(&state->hdl);
+		kfree(state);
+		return err;
+	}
+
+	/* Set cs53l32a internal register for Adaptec 2010/2410 setup */
+
+	cs53l32a_write(sd, 0x01, 0x21);
+	cs53l32a_write(sd, 0x02, 0x29);
+	cs53l32a_write(sd, 0x03, 0x30);
+	cs53l32a_write(sd, 0x04, 0x00);
+	cs53l32a_write(sd, 0x05, 0x00);
+	cs53l32a_write(sd, 0x06, 0x00);
+	cs53l32a_write(sd, 0x07, 0x00);
+
+	/* Display results, should be 0x21,0x29,0x30,0x00,0x00,0x00,0x00 */
+
+	for (i = 1; i <= 7; i++) {
+		u8 v = cs53l32a_read(sd, i);
+
+		v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v);
+	}
+	return 0;
+}
+
+static int cs53l32a_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct cs53l32a_state *state = to_state(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&state->hdl);
+	kfree(state);
+	return 0;
+}
+
+static const struct i2c_device_id cs53l32a_id[] = {
+	{ "cs53l32a", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, cs53l32a_id);
+
+static struct i2c_driver cs53l32a_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "cs53l32a",
+	},
+	.probe		= cs53l32a_probe,
+	.remove		= cs53l32a_remove,
+	.id_table	= cs53l32a_id,
+};
+
+module_i2c_driver(cs53l32a_driver);
diff --git a/drivers/media/i2c/cx2341x.c b/drivers/media/i2c/cx2341x.c
new file mode 100644
index 0000000..103ef6b
--- /dev/null
+++ b/drivers/media/i2c/cx2341x.c
@@ -0,0 +1,1726 @@
+/*
+ * cx2341x - generic code for cx23415/6/8 based devices
+ *
+ * Copyright (C) 2006 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/tuner.h>
+#include <media/cx2341x.h>
+#include <media/v4l2-common.h>
+
+MODULE_DESCRIPTION("cx23415/6/8 driver");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/********************** COMMON CODE *********************/
+
+/* definitions for audio properties bits 29-28 */
+#define CX2341X_AUDIO_ENCODING_METHOD_MPEG	0
+#define CX2341X_AUDIO_ENCODING_METHOD_AC3	1
+#define CX2341X_AUDIO_ENCODING_METHOD_LPCM	2
+
+static const char *cx2341x_get_name(u32 id)
+{
+	switch (id) {
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+		return "Spatial Filter Mode";
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+		return "Spatial Filter";
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+		return "Spatial Luma Filter Type";
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+		return "Spatial Chroma Filter Type";
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+		return "Temporal Filter Mode";
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+		return "Temporal Filter";
+	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+		return "Median Filter Type";
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+		return "Median Luma Filter Maximum";
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+		return "Median Luma Filter Minimum";
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+		return "Median Chroma Filter Maximum";
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+		return "Median Chroma Filter Minimum";
+	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+		return "Insert Navigation Packets";
+	}
+	return NULL;
+}
+
+static const char **cx2341x_get_menu(u32 id)
+{
+	static const char *cx2341x_video_spatial_filter_mode_menu[] = {
+		"Manual",
+		"Auto",
+		NULL
+	};
+
+	static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
+		"Off",
+		"1D Horizontal",
+		"1D Vertical",
+		"2D H/V Separable",
+		"2D Symmetric non-separable",
+		NULL
+	};
+
+	static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
+		"Off",
+		"1D Horizontal",
+		NULL
+	};
+
+	static const char *cx2341x_video_temporal_filter_mode_menu[] = {
+		"Manual",
+		"Auto",
+		NULL
+	};
+
+	static const char *cx2341x_video_median_filter_type_menu[] = {
+		"Off",
+		"Horizontal",
+		"Vertical",
+		"Horizontal/Vertical",
+		"Diagonal",
+		NULL
+	};
+
+	switch (id) {
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+		return cx2341x_video_spatial_filter_mode_menu;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+		return cx2341x_video_luma_spatial_filter_type_menu;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+		return cx2341x_video_chroma_spatial_filter_type_menu;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+		return cx2341x_video_temporal_filter_mode_menu;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+		return cx2341x_video_median_filter_type_menu;
+	}
+	return NULL;
+}
+
+static void cx2341x_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
+		    s32 *min, s32 *max, s32 *step, s32 *def, u32 *flags)
+{
+	*name = cx2341x_get_name(id);
+	*flags = 0;
+
+	switch (id) {
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+		*type = V4L2_CTRL_TYPE_MENU;
+		*min = 0;
+		*step = 0;
+		break;
+	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+		*type = V4L2_CTRL_TYPE_BOOLEAN;
+		*min = 0;
+		*max = *step = 1;
+		break;
+	default:
+		*type = V4L2_CTRL_TYPE_INTEGER;
+		break;
+	}
+	switch (id) {
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+		*flags |= V4L2_CTRL_FLAG_UPDATE;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+		*flags |= V4L2_CTRL_FLAG_SLIDER;
+		break;
+	case V4L2_CID_MPEG_VIDEO_ENCODING:
+		*flags |= V4L2_CTRL_FLAG_READ_ONLY;
+		break;
+	}
+}
+
+
+/********************** OLD CODE *********************/
+
+/* Must be sorted from low to high control ID! */
+const u32 cx2341x_mpeg_ctrls[] = {
+	V4L2_CID_MPEG_CLASS,
+	V4L2_CID_MPEG_STREAM_TYPE,
+	V4L2_CID_MPEG_STREAM_VBI_FMT,
+	V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+	V4L2_CID_MPEG_AUDIO_ENCODING,
+	V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+	V4L2_CID_MPEG_AUDIO_MODE,
+	V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
+	V4L2_CID_MPEG_AUDIO_EMPHASIS,
+	V4L2_CID_MPEG_AUDIO_CRC,
+	V4L2_CID_MPEG_AUDIO_MUTE,
+	V4L2_CID_MPEG_AUDIO_AC3_BITRATE,
+	V4L2_CID_MPEG_VIDEO_ENCODING,
+	V4L2_CID_MPEG_VIDEO_ASPECT,
+	V4L2_CID_MPEG_VIDEO_B_FRAMES,
+	V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+	V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+	V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+	V4L2_CID_MPEG_VIDEO_BITRATE,
+	V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+	V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
+	V4L2_CID_MPEG_VIDEO_MUTE,
+	V4L2_CID_MPEG_VIDEO_MUTE_YUV,
+	V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
+	V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
+	V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
+	V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
+	V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
+	V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
+	V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
+	V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
+	V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
+	V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
+	V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
+	V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS,
+	0
+};
+EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
+
+static const struct cx2341x_mpeg_params default_params = {
+	/* misc */
+	.capabilities = 0,
+	.port = CX2341X_PORT_MEMORY,
+	.width = 720,
+	.height = 480,
+	.is_50hz = 0,
+
+	/* stream */
+	.stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+	.stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE,
+	.stream_insert_nav_packets = 0,
+
+	/* audio */
+	.audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+	.audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+	.audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
+	.audio_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_224K,
+	.audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
+	.audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+	.audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+	.audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
+	.audio_mute = 0,
+
+	/* video */
+	.video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
+	.video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
+	.video_b_frames = 2,
+	.video_gop_size = 12,
+	.video_gop_closure = 1,
+	.video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+	.video_bitrate = 6000000,
+	.video_bitrate_peak = 8000000,
+	.video_temporal_decimation = 0,
+	.video_mute = 0,
+	.video_mute_yuv = 0x008080,  /* YCbCr value for black */
+
+	/* encoding filters */
+	.video_spatial_filter_mode =
+		V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+	.video_spatial_filter = 0,
+	.video_luma_spatial_filter_type =
+		V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
+	.video_chroma_spatial_filter_type =
+		V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+	.video_temporal_filter_mode =
+		V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+	.video_temporal_filter = 8,
+	.video_median_filter_type =
+		V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+	.video_luma_median_filter_top = 255,
+	.video_luma_median_filter_bottom = 0,
+	.video_chroma_median_filter_top = 255,
+	.video_chroma_median_filter_bottom = 0,
+};
+/* Map the control ID to the correct field in the cx2341x_mpeg_params
+   struct. Return -EINVAL if the ID is unknown, else return 0. */
+static int cx2341x_get_ctrl(const struct cx2341x_mpeg_params *params,
+		struct v4l2_ext_control *ctrl)
+{
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+		ctrl->value = params->audio_sampling_freq;
+		break;
+	case V4L2_CID_MPEG_AUDIO_ENCODING:
+		ctrl->value = params->audio_encoding;
+		break;
+	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+		ctrl->value = params->audio_l2_bitrate;
+		break;
+	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+		ctrl->value = params->audio_ac3_bitrate;
+		break;
+	case V4L2_CID_MPEG_AUDIO_MODE:
+		ctrl->value = params->audio_mode;
+		break;
+	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+		ctrl->value = params->audio_mode_extension;
+		break;
+	case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+		ctrl->value = params->audio_emphasis;
+		break;
+	case V4L2_CID_MPEG_AUDIO_CRC:
+		ctrl->value = params->audio_crc;
+		break;
+	case V4L2_CID_MPEG_AUDIO_MUTE:
+		ctrl->value = params->audio_mute;
+		break;
+	case V4L2_CID_MPEG_VIDEO_ENCODING:
+		ctrl->value = params->video_encoding;
+		break;
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		ctrl->value = params->video_aspect;
+		break;
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+		ctrl->value = params->video_b_frames;
+		break;
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+		ctrl->value = params->video_gop_size;
+		break;
+	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+		ctrl->value = params->video_gop_closure;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		ctrl->value = params->video_bitrate_mode;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		ctrl->value = params->video_bitrate;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+		ctrl->value = params->video_bitrate_peak;
+		break;
+	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+		ctrl->value = params->video_temporal_decimation;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MUTE:
+		ctrl->value = params->video_mute;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
+		ctrl->value = params->video_mute_yuv;
+		break;
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		ctrl->value = params->stream_type;
+		break;
+	case V4L2_CID_MPEG_STREAM_VBI_FMT:
+		ctrl->value = params->stream_vbi_fmt;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+		ctrl->value = params->video_spatial_filter_mode;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+		ctrl->value = params->video_spatial_filter;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+		ctrl->value = params->video_luma_spatial_filter_type;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+		ctrl->value = params->video_chroma_spatial_filter_type;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+		ctrl->value = params->video_temporal_filter_mode;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+		ctrl->value = params->video_temporal_filter;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+		ctrl->value = params->video_median_filter_type;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+		ctrl->value = params->video_luma_median_filter_top;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+		ctrl->value = params->video_luma_median_filter_bottom;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+		ctrl->value = params->video_chroma_median_filter_top;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+		ctrl->value = params->video_chroma_median_filter_bottom;
+		break;
+	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+		ctrl->value = params->stream_insert_nav_packets;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* Map the control ID to the correct field in the cx2341x_mpeg_params
+   struct. Return -EINVAL if the ID is unknown, else return 0. */
+static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
+		struct v4l2_ext_control *ctrl)
+{
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+		if (busy)
+			return -EBUSY;
+		params->audio_sampling_freq = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_AUDIO_ENCODING:
+		if (busy)
+			return -EBUSY;
+		if (params->capabilities & CX2341X_CAP_HAS_AC3)
+			if (ctrl->value != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
+			    ctrl->value != V4L2_MPEG_AUDIO_ENCODING_AC3)
+				return -ERANGE;
+		params->audio_encoding = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+		if (busy)
+			return -EBUSY;
+		params->audio_l2_bitrate = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+		if (busy)
+			return -EBUSY;
+		if (!(params->capabilities & CX2341X_CAP_HAS_AC3))
+			return -EINVAL;
+		params->audio_ac3_bitrate = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_AUDIO_MODE:
+		params->audio_mode = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+		params->audio_mode_extension = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+		params->audio_emphasis = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_AUDIO_CRC:
+		params->audio_crc = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_AUDIO_MUTE:
+		params->audio_mute = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		params->video_aspect = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
+		int b = ctrl->value + 1;
+		int gop = params->video_gop_size;
+		params->video_b_frames = ctrl->value;
+		params->video_gop_size = b * ((gop + b - 1) / b);
+		/* Max GOP size = 34 */
+		while (params->video_gop_size > 34)
+			params->video_gop_size -= b;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE: {
+		int b = params->video_b_frames + 1;
+		int gop = ctrl->value;
+		params->video_gop_size = b * ((gop + b - 1) / b);
+		/* Max GOP size = 34 */
+		while (params->video_gop_size > 34)
+			params->video_gop_size -= b;
+		ctrl->value = params->video_gop_size;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+		params->video_gop_closure = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		if (busy)
+			return -EBUSY;
+		/* MPEG-1 only allows CBR */
+		if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
+		    ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+			return -EINVAL;
+		params->video_bitrate_mode = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		if (busy)
+			return -EBUSY;
+		params->video_bitrate = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+		if (busy)
+			return -EBUSY;
+		params->video_bitrate_peak = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+		params->video_temporal_decimation = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MUTE:
+		params->video_mute = (ctrl->value != 0);
+		break;
+	case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
+		params->video_mute_yuv = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		if (busy)
+			return -EBUSY;
+		params->stream_type = ctrl->value;
+		params->video_encoding =
+		    (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
+		     params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
+			V4L2_MPEG_VIDEO_ENCODING_MPEG_1 :
+			V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+		if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+			/* MPEG-1 implies CBR */
+			params->video_bitrate_mode =
+				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+		break;
+	case V4L2_CID_MPEG_STREAM_VBI_FMT:
+		params->stream_vbi_fmt = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+		params->video_spatial_filter_mode = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+		params->video_spatial_filter = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+		params->video_luma_spatial_filter_type = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+		params->video_chroma_spatial_filter_type = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+		params->video_temporal_filter_mode = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+		params->video_temporal_filter = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+		params->video_median_filter_type = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+		params->video_luma_median_filter_top = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+		params->video_luma_median_filter_bottom = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+		params->video_chroma_median_filter_top = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+		params->video_chroma_median_filter_bottom = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+		params->stream_insert_nav_packets = ctrl->value;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl,
+				   s32 min, s32 max, s32 step, s32 def)
+{
+	const char *name;
+
+	switch (qctrl->id) {
+	/* MPEG controls */
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+		cx2341x_ctrl_fill(qctrl->id, &name, &qctrl->type,
+				&min, &max, &step, &def, &qctrl->flags);
+		qctrl->minimum = min;
+		qctrl->maximum = max;
+		qctrl->step = step;
+		qctrl->default_value = def;
+		qctrl->reserved[0] = qctrl->reserved[1] = 0;
+		strlcpy(qctrl->name, name, sizeof(qctrl->name));
+		return 0;
+
+	default:
+		return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
+	}
+}
+
+int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
+		       struct v4l2_queryctrl *qctrl)
+{
+	int err;
+
+	switch (qctrl->id) {
+	case V4L2_CID_MPEG_CLASS:
+		return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+				V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1,
+				V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+
+	case V4L2_CID_MPEG_STREAM_VBI_FMT:
+		if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI)
+			return v4l2_ctrl_query_fill(qctrl,
+					V4L2_MPEG_STREAM_VBI_FMT_NONE,
+					V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1,
+					V4L2_MPEG_STREAM_VBI_FMT_NONE);
+		return cx2341x_ctrl_query_fill(qctrl,
+				V4L2_MPEG_STREAM_VBI_FMT_NONE,
+				V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
+				default_params.stream_vbi_fmt);
+
+	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100,
+				V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1,
+				V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+
+	case V4L2_CID_MPEG_AUDIO_ENCODING:
+		if (params->capabilities & CX2341X_CAP_HAS_AC3) {
+			/*
+			 * The state of L2 & AC3 bitrate controls can change
+			 * when this control changes, but v4l2_ctrl_query_fill()
+			 * already sets V4L2_CTRL_FLAG_UPDATE for
+			 * V4L2_CID_MPEG_AUDIO_ENCODING, so we don't here.
+			 */
+			return v4l2_ctrl_query_fill(qctrl,
+					V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+					V4L2_MPEG_AUDIO_ENCODING_AC3, 1,
+					default_params.audio_encoding);
+		}
+
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+				V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
+				default_params.audio_encoding);
+
+	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+		err = v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_L2_BITRATE_192K,
+				V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+				default_params.audio_l2_bitrate);
+		if (err)
+			return err;
+		if (params->capabilities & CX2341X_CAP_HAS_AC3 &&
+		    params->audio_encoding != V4L2_MPEG_AUDIO_ENCODING_LAYER_2)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return 0;
+
+	case V4L2_CID_MPEG_AUDIO_MODE:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_MODE_STEREO,
+				V4L2_MPEG_AUDIO_MODE_MONO, 1,
+				V4L2_MPEG_AUDIO_MODE_STEREO);
+
+	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+		err = v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+				V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1,
+				V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4);
+		if (err == 0 &&
+		    params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return err;
+
+	case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+				V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1,
+				V4L2_MPEG_AUDIO_EMPHASIS_NONE);
+
+	case V4L2_CID_MPEG_AUDIO_CRC:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_CRC_NONE,
+				V4L2_MPEG_AUDIO_CRC_CRC16, 1,
+				V4L2_MPEG_AUDIO_CRC_NONE);
+
+	case V4L2_CID_MPEG_AUDIO_MUTE:
+		return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+
+	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+		err = v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_AC3_BITRATE_48K,
+				V4L2_MPEG_AUDIO_AC3_BITRATE_448K, 1,
+				default_params.audio_ac3_bitrate);
+		if (err)
+			return err;
+		if (params->capabilities & CX2341X_CAP_HAS_AC3) {
+			if (params->audio_encoding !=
+						   V4L2_MPEG_AUDIO_ENCODING_AC3)
+				qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		} else
+			qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+		return 0;
+
+	case V4L2_CID_MPEG_VIDEO_ENCODING:
+		/* this setting is read-only for the cx2341x since the
+		   V4L2_CID_MPEG_STREAM_TYPE really determines the
+		   MPEG-1/2 setting */
+		err = v4l2_ctrl_query_fill(qctrl,
+					   V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
+					   V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
+					   V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+		if (err == 0)
+			qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+		return err;
+
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_VIDEO_ASPECT_1x1,
+				V4L2_MPEG_VIDEO_ASPECT_221x100, 1,
+				V4L2_MPEG_VIDEO_ASPECT_4x3);
+
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+		return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2);
+
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+		return v4l2_ctrl_query_fill(qctrl, 1, 34, 1,
+				params->is_50hz ? 12 : 15);
+
+	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+		return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
+
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		err = v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
+				V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+		if (err == 0 &&
+		    params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return err;
+
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
+
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+		err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
+		if (err == 0 &&
+		    params->video_bitrate_mode ==
+				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return err;
+
+	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+		return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+
+	case V4L2_CID_MPEG_VIDEO_MUTE:
+		return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+
+	case V4L2_CID_MPEG_VIDEO_MUTE_YUV:  /* Init YUV (really YCbCr) to black */
+		return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080);
+
+	/* CX23415/6 specific */
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+		return cx2341x_ctrl_query_fill(qctrl,
+			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
+			default_params.video_spatial_filter_mode);
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+		cx2341x_ctrl_query_fill(qctrl, 0, 15, 1,
+				default_params.video_spatial_filter);
+		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+		if (params->video_spatial_filter_mode ==
+			    V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return 0;
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+		cx2341x_ctrl_query_fill(qctrl,
+			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
+			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE,
+			1,
+			default_params.video_luma_spatial_filter_type);
+		if (params->video_spatial_filter_mode ==
+			    V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return 0;
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+		cx2341x_ctrl_query_fill(qctrl,
+		    V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
+		    V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+		    1,
+		    default_params.video_chroma_spatial_filter_type);
+		if (params->video_spatial_filter_mode ==
+			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return 0;
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+		return cx2341x_ctrl_query_fill(qctrl,
+			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
+			default_params.video_temporal_filter_mode);
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+		cx2341x_ctrl_query_fill(qctrl, 0, 31, 1,
+				default_params.video_temporal_filter);
+		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+		if (params->video_temporal_filter_mode ==
+			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return 0;
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+		return cx2341x_ctrl_query_fill(qctrl,
+			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
+			default_params.video_median_filter_type);
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1,
+				default_params.video_luma_median_filter_top);
+		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+		if (params->video_median_filter_type ==
+				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return 0;
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1,
+				default_params.video_luma_median_filter_bottom);
+		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+		if (params->video_median_filter_type ==
+				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return 0;
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1,
+				default_params.video_chroma_median_filter_top);
+		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+		if (params->video_median_filter_type ==
+				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return 0;
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1,
+			default_params.video_chroma_median_filter_bottom);
+		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+		if (params->video_median_filter_type ==
+				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return 0;
+
+	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+		return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1,
+				default_params.stream_insert_nav_packets);
+
+	default:
+		return -EINVAL;
+
+	}
+}
+EXPORT_SYMBOL(cx2341x_ctrl_query);
+
+const char * const *cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
+{
+	static const char * const mpeg_stream_type_without_ts[] = {
+		"MPEG-2 Program Stream",
+		"",
+		"MPEG-1 System Stream",
+		"MPEG-2 DVD-compatible Stream",
+		"MPEG-1 VCD-compatible Stream",
+		"MPEG-2 SVCD-compatible Stream",
+		NULL
+	};
+
+	static const char *mpeg_stream_type_with_ts[] = {
+		"MPEG-2 Program Stream",
+		"MPEG-2 Transport Stream",
+		"MPEG-1 System Stream",
+		"MPEG-2 DVD-compatible Stream",
+		"MPEG-1 VCD-compatible Stream",
+		"MPEG-2 SVCD-compatible Stream",
+		NULL
+	};
+
+	static const char *mpeg_audio_encoding_l2_ac3[] = {
+		"",
+		"MPEG-1/2 Layer II",
+		"",
+		"",
+		"AC-3",
+		NULL
+	};
+
+	switch (id) {
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		return (p->capabilities & CX2341X_CAP_HAS_TS) ?
+			mpeg_stream_type_with_ts : mpeg_stream_type_without_ts;
+	case V4L2_CID_MPEG_AUDIO_ENCODING:
+		return (p->capabilities & CX2341X_CAP_HAS_AC3) ?
+			mpeg_audio_encoding_l2_ac3 : v4l2_ctrl_get_menu(id);
+	case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+	case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+		return NULL;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+		return cx2341x_get_menu(id);
+	default:
+		return v4l2_ctrl_get_menu(id);
+	}
+}
+EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
+
+static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
+{
+	params->audio_properties =
+		(params->audio_sampling_freq << 0) |
+		(params->audio_mode << 8) |
+		(params->audio_mode_extension << 10) |
+		(((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17)
+		  ? 3 : params->audio_emphasis) << 12) |
+		(params->audio_crc << 14);
+
+	if ((params->capabilities & CX2341X_CAP_HAS_AC3) &&
+	    params->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) {
+		params->audio_properties |=
+			/* Not sure if this MPEG Layer II setting is required */
+			((3 - V4L2_MPEG_AUDIO_ENCODING_LAYER_2) << 2) |
+			(params->audio_ac3_bitrate << 4) |
+			(CX2341X_AUDIO_ENCODING_METHOD_AC3 << 28);
+	} else {
+		/* Assuming MPEG Layer II */
+		params->audio_properties |=
+			((3 - params->audio_encoding) << 2) |
+			((1 + params->audio_l2_bitrate) << 4);
+	}
+}
+
+int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
+		  struct v4l2_ext_controls *ctrls, unsigned int cmd)
+{
+	int err = 0;
+	int i;
+
+	if (cmd == VIDIOC_G_EXT_CTRLS) {
+		for (i = 0; i < ctrls->count; i++) {
+			struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+			err = cx2341x_get_ctrl(params, ctrl);
+			if (err) {
+				ctrls->error_idx = i;
+				break;
+			}
+		}
+		return err;
+	}
+	for (i = 0; i < ctrls->count; i++) {
+		struct v4l2_ext_control *ctrl = ctrls->controls + i;
+		struct v4l2_queryctrl qctrl;
+		const char * const *menu_items = NULL;
+
+		qctrl.id = ctrl->id;
+		err = cx2341x_ctrl_query(params, &qctrl);
+		if (err)
+			break;
+		if (qctrl.type == V4L2_CTRL_TYPE_MENU)
+			menu_items = cx2341x_ctrl_get_menu(params, qctrl.id);
+		err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
+		if (err)
+			break;
+		err = cx2341x_set_ctrl(params, busy, ctrl);
+		if (err)
+			break;
+	}
+	if (err == 0 &&
+	    params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+	    params->video_bitrate_peak < params->video_bitrate) {
+		err = -ERANGE;
+		ctrls->error_idx = ctrls->count;
+	}
+	if (err)
+		ctrls->error_idx = i;
+	else
+		cx2341x_calc_audio_properties(params);
+	return err;
+}
+EXPORT_SYMBOL(cx2341x_ext_ctrls);
+
+void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
+{
+	*p = default_params;
+	cx2341x_calc_audio_properties(p);
+}
+EXPORT_SYMBOL(cx2341x_fill_defaults);
+
+static int cx2341x_api(void *priv, cx2341x_mbox_func func,
+		       u32 cmd, int args, ...)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	va_list vargs;
+	int i;
+
+	va_start(vargs, args);
+
+	for (i = 0; i < args; i++)
+		data[i] = va_arg(vargs, int);
+	va_end(vargs);
+	return func(priv, cmd, args, 0, data);
+}
+
+#define NEQ(field) (old->field != new->field)
+
+int cx2341x_update(void *priv, cx2341x_mbox_func func,
+		   const struct cx2341x_mpeg_params *old,
+		   const struct cx2341x_mpeg_params *new)
+{
+	static int mpeg_stream_type[] = {
+		0,	/* MPEG-2 PS */
+		1,	/* MPEG-2 TS */
+		2,	/* MPEG-1 SS */
+		14,	/* DVD */
+		11,	/* VCD */
+		12,	/* SVCD */
+	};
+
+	int err = 0;
+	int force = (old == NULL);
+	u16 temporal = new->video_temporal_filter;
+
+	cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
+
+	if (force || NEQ(is_50hz)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1,
+				  new->is_50hz);
+		if (err) return err;
+	}
+
+	if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) {
+		u16 w = new->width;
+		u16 h = new->height;
+
+		if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
+			w /= 2;
+			h /= 2;
+		}
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2,
+				  h, w);
+		if (err) return err;
+	}
+	if (force || NEQ(stream_type)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1,
+				  mpeg_stream_type[new->stream_type]);
+		if (err) return err;
+	}
+	if (force || NEQ(video_aspect)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1,
+				  1 + new->video_aspect);
+		if (err) return err;
+	}
+	if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
+				new->video_gop_size, new->video_b_frames + 1);
+		if (err) return err;
+	}
+	if (force || NEQ(video_gop_closure)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1,
+				  new->video_gop_closure);
+		if (err) return err;
+	}
+	if (force || NEQ(audio_properties)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES,
+				  1, new->audio_properties);
+		if (err) return err;
+	}
+	if (force || NEQ(audio_mute)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1,
+				  new->audio_mute);
+		if (err) return err;
+	}
+	if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) ||
+						NEQ(video_bitrate_peak)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
+				new->video_bitrate_mode, new->video_bitrate,
+				new->video_bitrate_peak / 400, 0, 0);
+		if (err) return err;
+	}
+	if (force || NEQ(video_spatial_filter_mode) ||
+		     NEQ(video_temporal_filter_mode) ||
+		     NEQ(video_median_filter_type)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE,
+				  2, new->video_spatial_filter_mode |
+					(new->video_temporal_filter_mode << 1),
+				new->video_median_filter_type);
+		if (err) return err;
+	}
+	if (force || NEQ(video_luma_median_filter_bottom) ||
+		     NEQ(video_luma_median_filter_top) ||
+		     NEQ(video_chroma_median_filter_bottom) ||
+		     NEQ(video_chroma_median_filter_top)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
+				new->video_luma_median_filter_bottom,
+				new->video_luma_median_filter_top,
+				new->video_chroma_median_filter_bottom,
+				new->video_chroma_median_filter_top);
+		if (err) return err;
+	}
+	if (force || NEQ(video_luma_spatial_filter_type) ||
+		     NEQ(video_chroma_spatial_filter_type)) {
+		err = cx2341x_api(priv, func,
+				  CX2341X_ENC_SET_SPATIAL_FILTER_TYPE,
+				  2, new->video_luma_spatial_filter_type,
+				  new->video_chroma_spatial_filter_type);
+		if (err) return err;
+	}
+	if (force || NEQ(video_spatial_filter) ||
+		     old->video_temporal_filter != temporal) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS,
+				  2, new->video_spatial_filter, temporal);
+		if (err) return err;
+	}
+	if (force || NEQ(video_temporal_decimation)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE,
+				  1, new->video_temporal_decimation);
+		if (err) return err;
+	}
+	if (force || NEQ(video_mute) ||
+		(new->video_mute && NEQ(video_mute_yuv))) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1,
+				new->video_mute | (new->video_mute_yuv << 8));
+		if (err) return err;
+	}
+	if (force || NEQ(stream_insert_nav_packets)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2,
+				7, new->stream_insert_nav_packets);
+		if (err) return err;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(cx2341x_update);
+
+static const char *cx2341x_menu_item(const struct cx2341x_mpeg_params *p, u32 id)
+{
+	const char * const *menu = cx2341x_ctrl_get_menu(p, id);
+	struct v4l2_ext_control ctrl;
+
+	if (menu == NULL)
+		goto invalid;
+	ctrl.id = id;
+	if (cx2341x_get_ctrl(p, &ctrl))
+		goto invalid;
+	while (ctrl.value-- && *menu) menu++;
+	if (*menu == NULL)
+		goto invalid;
+	return *menu;
+
+invalid:
+	return "<invalid>";
+}
+
+void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix)
+{
+	int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+
+	/* Stream */
+	printk(KERN_INFO "%s: Stream: %s",
+		prefix,
+		cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
+	if (p->stream_insert_nav_packets)
+		printk(" (with navigation packets)");
+	printk("\n");
+	printk(KERN_INFO "%s: VBI Format: %s\n",
+		prefix,
+		cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT));
+
+	/* Video */
+	printk(KERN_INFO "%s: Video:  %dx%d, %d fps%s\n",
+		prefix,
+		p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
+		p->is_50hz ? 25 : 30,
+		(p->video_mute) ? " (muted)" : "");
+	printk(KERN_INFO "%s: Video:  %s, %s, %s, %d",
+		prefix,
+		cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
+		cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
+		cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
+		p->video_bitrate);
+	if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
+		printk(", Peak %d", p->video_bitrate_peak);
+	printk("\n");
+	printk(KERN_INFO
+		"%s: Video:  GOP Size %d, %d B-Frames, %sGOP Closure\n",
+		prefix,
+		p->video_gop_size, p->video_b_frames,
+		p->video_gop_closure ? "" : "No ");
+	if (p->video_temporal_decimation)
+		printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
+			prefix, p->video_temporal_decimation);
+
+	/* Audio */
+	printk(KERN_INFO "%s: Audio:  %s, %s, %s, %s%s",
+		prefix,
+		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
+		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
+		cx2341x_menu_item(p,
+			   p->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3
+					      ? V4L2_CID_MPEG_AUDIO_AC3_BITRATE
+					      : V4L2_CID_MPEG_AUDIO_L2_BITRATE),
+		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
+		p->audio_mute ? " (muted)" : "");
+	if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
+		printk(", %s", cx2341x_menu_item(p,
+				V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
+	printk(", %s, %s\n",
+		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
+		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
+
+	/* Encoding filters */
+	printk(KERN_INFO "%s: Spatial Filter:  %s, Luma %s, Chroma %s, %d\n",
+		prefix,
+		cx2341x_menu_item(p,
+		    V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
+		cx2341x_menu_item(p,
+		    V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
+		cx2341x_menu_item(p,
+		    V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
+		p->video_spatial_filter);
+
+	printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
+		prefix,
+		cx2341x_menu_item(p,
+			V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
+		p->video_temporal_filter);
+	printk(KERN_INFO
+		"%s: Median Filter:   %s, Luma [%d, %d], Chroma [%d, %d]\n",
+		prefix,
+		cx2341x_menu_item(p,
+			V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
+		p->video_luma_median_filter_bottom,
+		p->video_luma_median_filter_top,
+		p->video_chroma_median_filter_bottom,
+		p->video_chroma_median_filter_top);
+}
+EXPORT_SYMBOL(cx2341x_log_status);
+
+
+
+/********************** NEW CODE *********************/
+
+static inline struct cx2341x_handler *to_cxhdl(struct v4l2_ctrl *ctrl)
+{
+	return container_of(ctrl->handler, struct cx2341x_handler, hdl);
+}
+
+static int cx2341x_hdl_api(struct cx2341x_handler *hdl,
+		       u32 cmd, int args, ...)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	va_list vargs;
+	int i;
+
+	va_start(vargs, args);
+
+	for (i = 0; i < args; i++)
+		data[i] = va_arg(vargs, int);
+	va_end(vargs);
+	return hdl->func(hdl->priv, cmd, args, 0, data);
+}
+
+/* ctrl->handler->lock is held, so it is safe to access cur.val */
+static inline int cx2341x_neq(struct v4l2_ctrl *ctrl)
+{
+	return ctrl && ctrl->val != ctrl->cur.val;
+}
+
+static int cx2341x_try_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct cx2341x_handler *hdl = to_cxhdl(ctrl);
+	s32 val = ctrl->val;
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
+		/* video gop cluster */
+		int b = val + 1;
+		int gop = hdl->video_gop_size->val;
+
+		gop = b * ((gop + b - 1) / b);
+
+		/* Max GOP size = 34 */
+		while (gop > 34)
+			gop -= b;
+		hdl->video_gop_size->val = gop;
+		break;
+	}
+
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		/* stream type cluster */
+		hdl->video_encoding->val =
+		    (hdl->stream_type->val == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
+		     hdl->stream_type->val == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
+			V4L2_MPEG_VIDEO_ENCODING_MPEG_1 :
+			V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+		if (hdl->video_encoding->val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+			/* MPEG-1 implies CBR */
+			hdl->video_bitrate_mode->val =
+				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+		/* peak bitrate shall be >= normal bitrate */
+		if (hdl->video_bitrate_mode->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+		    hdl->video_bitrate_peak->val < hdl->video_bitrate->val)
+			hdl->video_bitrate_peak->val = hdl->video_bitrate->val;
+		break;
+	}
+	return 0;
+}
+
+static int cx2341x_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	static const int mpeg_stream_type[] = {
+		0,	/* MPEG-2 PS */
+		1,	/* MPEG-2 TS */
+		2,	/* MPEG-1 SS */
+		14,	/* DVD */
+		11,	/* VCD */
+		12,	/* SVCD */
+	};
+	struct cx2341x_handler *hdl = to_cxhdl(ctrl);
+	s32 val = ctrl->val;
+	u32 props;
+	int err;
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_STREAM_VBI_FMT:
+		if (hdl->ops && hdl->ops->s_stream_vbi_fmt)
+			return hdl->ops->s_stream_vbi_fmt(hdl, val);
+		return 0;
+
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		return cx2341x_hdl_api(hdl,
+			CX2341X_ENC_SET_ASPECT_RATIO, 1, val + 1);
+
+	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+		return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_GOP_CLOSURE, 1, val);
+
+	case V4L2_CID_MPEG_AUDIO_MUTE:
+		return cx2341x_hdl_api(hdl, CX2341X_ENC_MUTE_AUDIO, 1, val);
+
+	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+		return cx2341x_hdl_api(hdl,
+			CX2341X_ENC_SET_FRAME_DROP_RATE, 1, val);
+
+	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+		return cx2341x_hdl_api(hdl, CX2341X_ENC_MISC, 2, 7, val);
+
+	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+		/* audio properties cluster */
+		props = (hdl->audio_sampling_freq->val << 0) |
+			(hdl->audio_mode->val << 8) |
+			(hdl->audio_mode_extension->val << 10) |
+			(hdl->audio_crc->val << 14);
+		if (hdl->audio_emphasis->val == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17)
+			props |= 3 << 12;
+		else
+			props |= hdl->audio_emphasis->val << 12;
+
+		if (hdl->audio_encoding->val == V4L2_MPEG_AUDIO_ENCODING_AC3) {
+			props |=
+#if 1
+				/* Not sure if this MPEG Layer II setting is required */
+				((3 - V4L2_MPEG_AUDIO_ENCODING_LAYER_2) << 2) |
+#endif
+				(hdl->audio_ac3_bitrate->val << 4) |
+				(CX2341X_AUDIO_ENCODING_METHOD_AC3 << 28);
+		} else {
+			/* Assuming MPEG Layer II */
+			props |=
+				((3 - hdl->audio_encoding->val) << 2) |
+				((1 + hdl->audio_l2_bitrate->val) << 4);
+		}
+		err = cx2341x_hdl_api(hdl,
+				CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, props);
+		if (err)
+			return err;
+
+		hdl->audio_properties = props;
+		if (hdl->audio_ac3_bitrate) {
+			int is_ac3 = hdl->audio_encoding->val ==
+						V4L2_MPEG_AUDIO_ENCODING_AC3;
+
+			v4l2_ctrl_activate(hdl->audio_ac3_bitrate, is_ac3);
+			v4l2_ctrl_activate(hdl->audio_l2_bitrate, !is_ac3);
+		}
+		v4l2_ctrl_activate(hdl->audio_mode_extension,
+			hdl->audio_mode->val == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO);
+		if (cx2341x_neq(hdl->audio_sampling_freq) &&
+		    hdl->ops && hdl->ops->s_audio_sampling_freq)
+			return hdl->ops->s_audio_sampling_freq(hdl, hdl->audio_sampling_freq->val);
+		if (cx2341x_neq(hdl->audio_mode) &&
+		    hdl->ops && hdl->ops->s_audio_mode)
+			return hdl->ops->s_audio_mode(hdl, hdl->audio_mode->val);
+		return 0;
+
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+		/* video gop cluster */
+		return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
+				hdl->video_gop_size->val,
+				hdl->video_b_frames->val + 1);
+
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		/* stream type cluster */
+		err = cx2341x_hdl_api(hdl,
+			CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[val]);
+		if (err)
+			return err;
+
+		err = cx2341x_hdl_api(hdl, CX2341X_ENC_SET_BIT_RATE, 5,
+				hdl->video_bitrate_mode->val,
+				hdl->video_bitrate->val,
+				hdl->video_bitrate_peak->val / 400, 0, 0);
+		if (err)
+			return err;
+
+		v4l2_ctrl_activate(hdl->video_bitrate_mode,
+			hdl->video_encoding->val != V4L2_MPEG_VIDEO_ENCODING_MPEG_1);
+		v4l2_ctrl_activate(hdl->video_bitrate_peak,
+			hdl->video_bitrate_mode->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
+		if (cx2341x_neq(hdl->video_encoding) &&
+		    hdl->ops && hdl->ops->s_video_encoding)
+			return hdl->ops->s_video_encoding(hdl, hdl->video_encoding->val);
+		return 0;
+
+	case V4L2_CID_MPEG_VIDEO_MUTE:
+		/* video mute cluster */
+		return cx2341x_hdl_api(hdl, CX2341X_ENC_MUTE_VIDEO, 1,
+				hdl->video_mute->val |
+					(hdl->video_mute_yuv->val << 8));
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: {
+		int active_filter;
+
+		/* video filter mode */
+		err = cx2341x_hdl_api(hdl, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
+				hdl->video_spatial_filter_mode->val |
+					(hdl->video_temporal_filter_mode->val << 1),
+				hdl->video_median_filter_type->val);
+		if (err)
+			return err;
+
+		active_filter = hdl->video_spatial_filter_mode->val !=
+				V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO;
+		v4l2_ctrl_activate(hdl->video_spatial_filter, active_filter);
+		v4l2_ctrl_activate(hdl->video_luma_spatial_filter_type, active_filter);
+		v4l2_ctrl_activate(hdl->video_chroma_spatial_filter_type, active_filter);
+		active_filter = hdl->video_temporal_filter_mode->val !=
+				V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO;
+		v4l2_ctrl_activate(hdl->video_temporal_filter, active_filter);
+		active_filter = hdl->video_median_filter_type->val !=
+				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF;
+		v4l2_ctrl_activate(hdl->video_luma_median_filter_bottom, active_filter);
+		v4l2_ctrl_activate(hdl->video_luma_median_filter_top, active_filter);
+		v4l2_ctrl_activate(hdl->video_chroma_median_filter_bottom, active_filter);
+		v4l2_ctrl_activate(hdl->video_chroma_median_filter_top, active_filter);
+		return 0;
+	}
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+		/* video filter type cluster */
+		return cx2341x_hdl_api(hdl,
+				CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
+				hdl->video_luma_spatial_filter_type->val,
+				hdl->video_chroma_spatial_filter_type->val);
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+		/* video filter cluster */
+		return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
+				hdl->video_spatial_filter->val,
+				hdl->video_temporal_filter->val);
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+		/* video median cluster */
+		return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_CORING_LEVELS, 4,
+				hdl->video_luma_median_filter_bottom->val,
+				hdl->video_luma_median_filter_top->val,
+				hdl->video_chroma_median_filter_bottom->val,
+				hdl->video_chroma_median_filter_top->val);
+	}
+	return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops cx2341x_ops = {
+	.try_ctrl = cx2341x_try_ctrl,
+	.s_ctrl = cx2341x_s_ctrl,
+};
+
+static struct v4l2_ctrl *cx2341x_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
+			u32 id, s32 min, s32 max, s32 step, s32 def)
+{
+	struct v4l2_ctrl_config cfg;
+
+	cx2341x_ctrl_fill(id, &cfg.name, &cfg.type, &min, &max, &step, &def, &cfg.flags);
+	cfg.ops = &cx2341x_ops;
+	cfg.id = id;
+	cfg.min = min;
+	cfg.max = max;
+	cfg.def = def;
+	if (cfg.type == V4L2_CTRL_TYPE_MENU) {
+		cfg.step = 0;
+		cfg.menu_skip_mask = step;
+		cfg.qmenu = cx2341x_get_menu(id);
+	} else {
+		cfg.step = step;
+		cfg.menu_skip_mask = 0;
+	}
+	return v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+}
+
+static struct v4l2_ctrl *cx2341x_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
+			u32 id, s32 min, s32 max, s32 step, s32 def)
+{
+	return v4l2_ctrl_new_std(hdl, &cx2341x_ops, id, min, max, step, def);
+}
+
+static struct v4l2_ctrl *cx2341x_ctrl_new_menu(struct v4l2_ctrl_handler *hdl,
+			u32 id, s32 max, s32 mask, s32 def)
+{
+	return v4l2_ctrl_new_std_menu(hdl, &cx2341x_ops, id, max, mask, def);
+}
+
+int cx2341x_handler_init(struct cx2341x_handler *cxhdl,
+			 unsigned nr_of_controls_hint)
+{
+	struct v4l2_ctrl_handler *hdl = &cxhdl->hdl;
+	u32 caps = cxhdl->capabilities;
+	int has_sliced_vbi = caps & CX2341X_CAP_HAS_SLICED_VBI;
+	int has_ac3 = caps & CX2341X_CAP_HAS_AC3;
+	int has_ts = caps & CX2341X_CAP_HAS_TS;
+
+	cxhdl->width = 720;
+	cxhdl->height = 480;
+
+	v4l2_ctrl_handler_init(hdl, nr_of_controls_hint);
+
+	/* Add controls in ascending control ID order for fastest
+	   insertion time. */
+	cxhdl->stream_type = cx2341x_ctrl_new_menu(hdl,
+			V4L2_CID_MPEG_STREAM_TYPE,
+			V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, has_ts ? 0 : 2,
+			V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+	cxhdl->stream_vbi_fmt = cx2341x_ctrl_new_menu(hdl,
+			V4L2_CID_MPEG_STREAM_VBI_FMT,
+			V4L2_MPEG_STREAM_VBI_FMT_IVTV, has_sliced_vbi ? 0 : 2,
+			V4L2_MPEG_STREAM_VBI_FMT_NONE);
+	cxhdl->audio_sampling_freq = cx2341x_ctrl_new_menu(hdl,
+			V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+			V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 0,
+			V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+	cxhdl->audio_encoding = cx2341x_ctrl_new_menu(hdl,
+			V4L2_CID_MPEG_AUDIO_ENCODING,
+			V4L2_MPEG_AUDIO_ENCODING_AC3, has_ac3 ? ~0x12 : ~0x2,
+			V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+	cxhdl->audio_l2_bitrate = cx2341x_ctrl_new_menu(hdl,
+			V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+			V4L2_MPEG_AUDIO_L2_BITRATE_384K, 0x1ff,
+			V4L2_MPEG_AUDIO_L2_BITRATE_224K);
+	cxhdl->audio_mode = cx2341x_ctrl_new_menu(hdl,
+			V4L2_CID_MPEG_AUDIO_MODE,
+			V4L2_MPEG_AUDIO_MODE_MONO, 0,
+			V4L2_MPEG_AUDIO_MODE_STEREO);
+	cxhdl->audio_mode_extension = cx2341x_ctrl_new_menu(hdl,
+			V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
+			V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 0,
+			V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4);
+	cxhdl->audio_emphasis = cx2341x_ctrl_new_menu(hdl,
+			V4L2_CID_MPEG_AUDIO_EMPHASIS,
+			V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 0,
+			V4L2_MPEG_AUDIO_EMPHASIS_NONE);
+	cxhdl->audio_crc = cx2341x_ctrl_new_menu(hdl,
+			V4L2_CID_MPEG_AUDIO_CRC,
+			V4L2_MPEG_AUDIO_CRC_CRC16, 0,
+			V4L2_MPEG_AUDIO_CRC_NONE);
+
+	cx2341x_ctrl_new_std(hdl, V4L2_CID_MPEG_AUDIO_MUTE, 0, 1, 1, 0);
+	if (has_ac3)
+		cxhdl->audio_ac3_bitrate = cx2341x_ctrl_new_menu(hdl,
+				V4L2_CID_MPEG_AUDIO_AC3_BITRATE,
+				V4L2_MPEG_AUDIO_AC3_BITRATE_448K, 0x03,
+				V4L2_MPEG_AUDIO_AC3_BITRATE_224K);
+	cxhdl->video_encoding = cx2341x_ctrl_new_menu(hdl,
+			V4L2_CID_MPEG_VIDEO_ENCODING,
+			V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 0,
+			V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+	cx2341x_ctrl_new_menu(hdl,
+			V4L2_CID_MPEG_VIDEO_ASPECT,
+			V4L2_MPEG_VIDEO_ASPECT_221x100, 0,
+			V4L2_MPEG_VIDEO_ASPECT_4x3);
+	cxhdl->video_b_frames = cx2341x_ctrl_new_std(hdl,
+			V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 33, 1, 2);
+	cxhdl->video_gop_size = cx2341x_ctrl_new_std(hdl,
+			V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+			1, 34, 1, cxhdl->is_50hz ? 12 : 15);
+	cx2341x_ctrl_new_std(hdl, V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, 0, 1, 1, 1);
+	cxhdl->video_bitrate_mode = cx2341x_ctrl_new_menu(hdl,
+			V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+			V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
+			V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+	cxhdl->video_bitrate = cx2341x_ctrl_new_std(hdl,
+			V4L2_CID_MPEG_VIDEO_BITRATE,
+			0, 27000000, 1, 6000000);
+	cxhdl->video_bitrate_peak = cx2341x_ctrl_new_std(hdl,
+			V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+			0, 27000000, 1, 8000000);
+	cx2341x_ctrl_new_std(hdl,
+			V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, 0, 255, 1, 0);
+	cxhdl->video_mute = cx2341x_ctrl_new_std(hdl,
+			V4L2_CID_MPEG_VIDEO_MUTE, 0, 1, 1, 0);
+	cxhdl->video_mute_yuv = cx2341x_ctrl_new_std(hdl,
+			V4L2_CID_MPEG_VIDEO_MUTE_YUV, 0, 0xffffff, 1, 0x008080);
+
+	/* CX23415/6 specific */
+	cxhdl->video_spatial_filter_mode = cx2341x_ctrl_new_custom(hdl,
+			V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
+			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 0,
+			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
+	cxhdl->video_spatial_filter = cx2341x_ctrl_new_custom(hdl,
+			V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
+			0, 15, 1, 0);
+	cxhdl->video_luma_spatial_filter_type = cx2341x_ctrl_new_custom(hdl,
+			V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
+			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
+			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE,
+			0,
+			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR);
+	cxhdl->video_chroma_spatial_filter_type = cx2341x_ctrl_new_custom(hdl,
+			V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
+			V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
+			V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+			0,
+			V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR);
+	cxhdl->video_temporal_filter_mode = cx2341x_ctrl_new_custom(hdl,
+			V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
+			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO,
+			0,
+			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
+	cxhdl->video_temporal_filter = cx2341x_ctrl_new_custom(hdl,
+			V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
+			0, 31, 1, 8);
+	cxhdl->video_median_filter_type = cx2341x_ctrl_new_custom(hdl,
+			V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
+			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG,
+			0,
+			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
+	cxhdl->video_luma_median_filter_bottom = cx2341x_ctrl_new_custom(hdl,
+			V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
+			0, 255, 1, 0);
+	cxhdl->video_luma_median_filter_top = cx2341x_ctrl_new_custom(hdl,
+			V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
+			0, 255, 1, 255);
+	cxhdl->video_chroma_median_filter_bottom = cx2341x_ctrl_new_custom(hdl,
+			V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
+			0, 255, 1, 0);
+	cxhdl->video_chroma_median_filter_top = cx2341x_ctrl_new_custom(hdl,
+			V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
+			0, 255, 1, 255);
+	cx2341x_ctrl_new_custom(hdl, V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS,
+			0, 1, 1, 0);
+
+	if (hdl->error) {
+		int err = hdl->error;
+
+		v4l2_ctrl_handler_free(hdl);
+		return err;
+	}
+
+	v4l2_ctrl_cluster(8, &cxhdl->audio_sampling_freq);
+	v4l2_ctrl_cluster(2, &cxhdl->video_b_frames);
+	v4l2_ctrl_cluster(5, &cxhdl->stream_type);
+	v4l2_ctrl_cluster(2, &cxhdl->video_mute);
+	v4l2_ctrl_cluster(3, &cxhdl->video_spatial_filter_mode);
+	v4l2_ctrl_cluster(2, &cxhdl->video_luma_spatial_filter_type);
+	v4l2_ctrl_cluster(2, &cxhdl->video_spatial_filter);
+	v4l2_ctrl_cluster(4, &cxhdl->video_luma_median_filter_top);
+
+	return 0;
+}
+EXPORT_SYMBOL(cx2341x_handler_init);
+
+void cx2341x_handler_set_50hz(struct cx2341x_handler *cxhdl, int is_50hz)
+{
+	cxhdl->is_50hz = is_50hz;
+	cxhdl->video_gop_size->default_value = cxhdl->is_50hz ? 12 : 15;
+}
+EXPORT_SYMBOL(cx2341x_handler_set_50hz);
+
+int cx2341x_handler_setup(struct cx2341x_handler *cxhdl)
+{
+	int h = cxhdl->height;
+	int w = cxhdl->width;
+	int err;
+
+	err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_OUTPUT_PORT, 2, cxhdl->port, 0);
+	if (err)
+		return err;
+	err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_FRAME_RATE, 1, cxhdl->is_50hz);
+	if (err)
+		return err;
+
+	if (v4l2_ctrl_g_ctrl(cxhdl->video_encoding) == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
+		w /= 2;
+		h /= 2;
+	}
+	err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
+	if (err)
+		return err;
+	return v4l2_ctrl_handler_setup(&cxhdl->hdl);
+}
+EXPORT_SYMBOL(cx2341x_handler_setup);
+
+void cx2341x_handler_set_busy(struct cx2341x_handler *cxhdl, int busy)
+{
+	v4l2_ctrl_grab(cxhdl->audio_sampling_freq, busy);
+	v4l2_ctrl_grab(cxhdl->audio_encoding, busy);
+	v4l2_ctrl_grab(cxhdl->audio_l2_bitrate, busy);
+	v4l2_ctrl_grab(cxhdl->audio_ac3_bitrate, busy);
+	v4l2_ctrl_grab(cxhdl->stream_vbi_fmt, busy);
+	v4l2_ctrl_grab(cxhdl->stream_type, busy);
+	v4l2_ctrl_grab(cxhdl->video_bitrate_mode, busy);
+	v4l2_ctrl_grab(cxhdl->video_bitrate, busy);
+	v4l2_ctrl_grab(cxhdl->video_bitrate_peak, busy);
+}
+EXPORT_SYMBOL(cx2341x_handler_set_busy);
diff --git a/drivers/media/i2c/cx25840/Kconfig b/drivers/media/i2c/cx25840/Kconfig
new file mode 100644
index 0000000..451133a
--- /dev/null
+++ b/drivers/media/i2c/cx25840/Kconfig
@@ -0,0 +1,8 @@
+config VIDEO_CX25840
+	tristate "Conexant CX2584x audio/video decoders"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Conexant CX2584x audio/video decoders.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx25840
diff --git a/drivers/media/i2c/cx25840/Makefile b/drivers/media/i2c/cx25840/Makefile
new file mode 100644
index 0000000..898eb13
--- /dev/null
+++ b/drivers/media/i2c/cx25840/Makefile
@@ -0,0 +1,6 @@
+cx25840-objs    := cx25840-core.o cx25840-audio.o cx25840-firmware.o \
+		   cx25840-vbi.o cx25840-ir.o
+
+obj-$(CONFIG_VIDEO_CX25840) += cx25840.o
+
+ccflags-y += -Idrivers/media/i2c
diff --git a/drivers/media/i2c/cx25840/cx25840-audio.c b/drivers/media/i2c/cx25840/cx25840-audio.c
new file mode 100644
index 0000000..34b96c7
--- /dev/null
+++ b/drivers/media/i2c/cx25840/cx25840-audio.c
@@ -0,0 +1,571 @@
+/* cx25840 audio functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <media/v4l2-common.h>
+#include <media/cx25840.h>
+
+#include "cx25840-core.h"
+
+/*
+ * Note: The PLL and SRC parameters are based on a reference frequency that
+ * would ideally be:
+ *
+ * NTSC Color subcarrier freq * 8 = 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
+ *
+ * However, it's not the exact reference frequency that matters, only that the
+ * firmware and modules that comprise the driver for a particular board all
+ * use the same value (close to the ideal value).
+ *
+ * Comments below will note which reference frequency is assumed for various
+ * parameters.  They will usually be one of
+ *
+ *	ref_freq = 28.636360 MHz
+ *		or
+ *	ref_freq = 28.636363 MHz
+ */
+
+static int cx25840_set_audclk_freq(struct i2c_client *client, u32 freq)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+
+	if (state->aud_input != CX25840_AUDIO_SERIAL) {
+		switch (freq) {
+		case 32000:
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x06, AUX PLL Post Divider = 0x10
+			 */
+			cx25840_write4(client, 0x108, 0x1006040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x1bb39ee
+			 * 28636363 * 0x6.dd9cf70/0x10 = 32000 * 384
+			 * 196.6 MHz pre-postdivide
+			 * FIXME < 200 MHz is out of specified valid range
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x01bb39ee);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x50);
+
+			if (is_cx2583x(state))
+				break;
+
+			/* src3/4/6_ctl */
+			/* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */
+			cx25840_write4(client, 0x900, 0x0801f77f);
+			cx25840_write4(client, 0x904, 0x0801f77f);
+			cx25840_write4(client, 0x90c, 0x0801f77f);
+			break;
+
+		case 44100:
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x10
+			 */
+			cx25840_write4(client, 0x108, 0x1009040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x0ec6bd6
+			 * 28636363 * 0x9.7635eb0/0x10 = 44100 * 384
+			 * 271 MHz pre-postdivide
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x00ec6bd6);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x50);
+
+			if (is_cx2583x(state))
+				break;
+
+			/* src3/4/6_ctl */
+			/* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */
+			cx25840_write4(client, 0x900, 0x08016d59);
+			cx25840_write4(client, 0x904, 0x08016d59);
+			cx25840_write4(client, 0x90c, 0x08016d59);
+			break;
+
+		case 48000:
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x10
+			 */
+			cx25840_write4(client, 0x108, 0x100a040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x098d6e5
+			 * 28636363 * 0xa.4c6b728/0x10 = 48000 * 384
+			 * 295 MHz pre-postdivide
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x0098d6e5);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x50);
+
+			if (is_cx2583x(state))
+				break;
+
+			/* src3/4/6_ctl */
+			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
+			cx25840_write4(client, 0x900, 0x08014faa);
+			cx25840_write4(client, 0x904, 0x08014faa);
+			cx25840_write4(client, 0x90c, 0x08014faa);
+			break;
+		}
+	} else {
+		switch (freq) {
+		case 32000:
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x08, AUX PLL Post Divider = 0x1e
+			 */
+			cx25840_write4(client, 0x108, 0x1e08040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x12a0869
+			 * 28636363 * 0x8.9504348/0x1e = 32000 * 256
+			 * 246 MHz pre-postdivide
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x012a0869);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x14 = 256/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x54);
+
+			if (is_cx2583x(state))
+				break;
+
+			/* src1_ctl */
+			/* 0x1.0000 = 32000/32000 */
+			cx25840_write4(client, 0x8f8, 0x08010000);
+
+			/* src3/4/6_ctl */
+			/* 0x2.0000 = 2 * (32000/32000) */
+			cx25840_write4(client, 0x900, 0x08020000);
+			cx25840_write4(client, 0x904, 0x08020000);
+			cx25840_write4(client, 0x90c, 0x08020000);
+			break;
+
+		case 44100:
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x18
+			 */
+			cx25840_write4(client, 0x108, 0x1809040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x0ec6bd6
+			 * 28636363 * 0x9.7635eb0/0x18 = 44100 * 256
+			 * 271 MHz pre-postdivide
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x00ec6bd6);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x50);
+
+			if (is_cx2583x(state))
+				break;
+
+			/* src1_ctl */
+			/* 0x1.60cd = 44100/32000 */
+			cx25840_write4(client, 0x8f8, 0x080160cd);
+
+			/* src3/4/6_ctl */
+			/* 0x1.7385 = 2 * (32000/44100) */
+			cx25840_write4(client, 0x900, 0x08017385);
+			cx25840_write4(client, 0x904, 0x08017385);
+			cx25840_write4(client, 0x90c, 0x08017385);
+			break;
+
+		case 48000:
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x18
+			 */
+			cx25840_write4(client, 0x108, 0x180a040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x098d6e5
+			 * 28636363 * 0xa.4c6b728/0x18 = 48000 * 256
+			 * 295 MHz pre-postdivide
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x0098d6e5);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x50);
+
+			if (is_cx2583x(state))
+				break;
+
+			/* src1_ctl */
+			/* 0x1.8000 = 48000/32000 */
+			cx25840_write4(client, 0x8f8, 0x08018000);
+
+			/* src3/4/6_ctl */
+			/* 0x1.5555 = 2 * (32000/48000) */
+			cx25840_write4(client, 0x900, 0x08015555);
+			cx25840_write4(client, 0x904, 0x08015555);
+			cx25840_write4(client, 0x90c, 0x08015555);
+			break;
+		}
+	}
+
+	state->audclk_freq = freq;
+
+	return 0;
+}
+
+static inline int cx25836_set_audclk_freq(struct i2c_client *client, u32 freq)
+{
+	return cx25840_set_audclk_freq(client, freq);
+}
+
+static int cx23885_set_audclk_freq(struct i2c_client *client, u32 freq)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+
+	if (state->aud_input != CX25840_AUDIO_SERIAL) {
+		switch (freq) {
+		case 32000:
+		case 44100:
+		case 48000:
+			/* We don't have register values
+			 * so avoid destroying registers. */
+			/* FIXME return -EINVAL; */
+			break;
+		}
+	} else {
+		switch (freq) {
+		case 32000:
+		case 44100:
+			/* We don't have register values
+			 * so avoid destroying registers. */
+			/* FIXME return -EINVAL; */
+			break;
+
+		case 48000:
+			/* src1_ctl */
+			/* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
+			cx25840_write4(client, 0x8f8, 0x0801867c);
+
+			/* src3/4/6_ctl */
+			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
+			cx25840_write4(client, 0x900, 0x08014faa);
+			cx25840_write4(client, 0x904, 0x08014faa);
+			cx25840_write4(client, 0x90c, 0x08014faa);
+			break;
+		}
+	}
+
+	state->audclk_freq = freq;
+
+	return 0;
+}
+
+static int cx231xx_set_audclk_freq(struct i2c_client *client, u32 freq)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+
+	if (state->aud_input != CX25840_AUDIO_SERIAL) {
+		switch (freq) {
+		case 32000:
+			/* src3/4/6_ctl */
+			/* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */
+			cx25840_write4(client, 0x900, 0x0801f77f);
+			cx25840_write4(client, 0x904, 0x0801f77f);
+			cx25840_write4(client, 0x90c, 0x0801f77f);
+			break;
+
+		case 44100:
+			/* src3/4/6_ctl */
+			/* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */
+			cx25840_write4(client, 0x900, 0x08016d59);
+			cx25840_write4(client, 0x904, 0x08016d59);
+			cx25840_write4(client, 0x90c, 0x08016d59);
+			break;
+
+		case 48000:
+			/* src3/4/6_ctl */
+			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
+			cx25840_write4(client, 0x900, 0x08014faa);
+			cx25840_write4(client, 0x904, 0x08014faa);
+			cx25840_write4(client, 0x90c, 0x08014faa);
+			break;
+		}
+	} else {
+		switch (freq) {
+		/* FIXME These cases make different assumptions about audclk */
+		case 32000:
+			/* src1_ctl */
+			/* 0x1.0000 = 32000/32000 */
+			cx25840_write4(client, 0x8f8, 0x08010000);
+
+			/* src3/4/6_ctl */
+			/* 0x2.0000 = 2 * (32000/32000) */
+			cx25840_write4(client, 0x900, 0x08020000);
+			cx25840_write4(client, 0x904, 0x08020000);
+			cx25840_write4(client, 0x90c, 0x08020000);
+			break;
+
+		case 44100:
+			/* src1_ctl */
+			/* 0x1.60cd = 44100/32000 */
+			cx25840_write4(client, 0x8f8, 0x080160cd);
+
+			/* src3/4/6_ctl */
+			/* 0x1.7385 = 2 * (32000/44100) */
+			cx25840_write4(client, 0x900, 0x08017385);
+			cx25840_write4(client, 0x904, 0x08017385);
+			cx25840_write4(client, 0x90c, 0x08017385);
+			break;
+
+		case 48000:
+			/* src1_ctl */
+			/* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
+			cx25840_write4(client, 0x8f8, 0x0801867c);
+
+			/* src3/4/6_ctl */
+			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
+			cx25840_write4(client, 0x900, 0x08014faa);
+			cx25840_write4(client, 0x904, 0x08014faa);
+			cx25840_write4(client, 0x90c, 0x08014faa);
+			break;
+		}
+	}
+
+	state->audclk_freq = freq;
+
+	return 0;
+}
+
+static int set_audclk_freq(struct i2c_client *client, u32 freq)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+
+	if (freq != 32000 && freq != 44100 && freq != 48000)
+		return -EINVAL;
+
+	if (is_cx231xx(state))
+		return cx231xx_set_audclk_freq(client, freq);
+
+	if (is_cx2388x(state))
+		return cx23885_set_audclk_freq(client, freq);
+
+	if (is_cx2583x(state))
+		return cx25836_set_audclk_freq(client, freq);
+
+	return cx25840_set_audclk_freq(client, freq);
+}
+
+void cx25840_audio_set_path(struct i2c_client *client)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+
+	if (!is_cx2583x(state)) {
+		/* assert soft reset */
+		cx25840_and_or(client, 0x810, ~0x1, 0x01);
+
+		/* stop microcontroller */
+		cx25840_and_or(client, 0x803, ~0x10, 0);
+
+		/* Mute everything to prevent the PFFT! */
+		cx25840_write(client, 0x8d3, 0x1f);
+
+		if (state->aud_input == CX25840_AUDIO_SERIAL) {
+			/* Set Path1 to Serial Audio Input */
+			cx25840_write4(client, 0x8d0, 0x01011012);
+
+			/* The microcontroller should not be started for the
+			 * non-tuner inputs: autodetection is specific for
+			 * TV audio. */
+		} else {
+			/* Set Path1 to Analog Demod Main Channel */
+			cx25840_write4(client, 0x8d0, 0x1f063870);
+		}
+	}
+
+	set_audclk_freq(client, state->audclk_freq);
+
+	if (!is_cx2583x(state)) {
+		if (state->aud_input != CX25840_AUDIO_SERIAL) {
+			/* When the microcontroller detects the
+			 * audio format, it will unmute the lines */
+			cx25840_and_or(client, 0x803, ~0x10, 0x10);
+		}
+
+		/* deassert soft reset */
+		cx25840_and_or(client, 0x810, ~0x1, 0x00);
+
+		/* Ensure the controller is running when we exit */
+		if (is_cx2388x(state) || is_cx231xx(state))
+			cx25840_and_or(client, 0x803, ~0x10, 0x10);
+	}
+}
+
+static void set_volume(struct i2c_client *client, int volume)
+{
+	int vol;
+
+	/* Convert the volume to msp3400 values (0-127) */
+	vol = volume >> 9;
+
+	/* now scale it up to cx25840 values
+	 * -114dB to -96dB maps to 0
+	 * this should be 19, but in my testing that was 4dB too loud */
+	if (vol <= 23) {
+		vol = 0;
+	} else {
+		vol -= 23;
+	}
+
+	/* PATH1_VOLUME */
+	cx25840_write(client, 0x8d4, 228 - (vol * 2));
+}
+
+static void set_balance(struct i2c_client *client, int balance)
+{
+	int bal = balance >> 8;
+	if (bal > 0x80) {
+		/* PATH1_BAL_LEFT */
+		cx25840_and_or(client, 0x8d5, 0x7f, 0x80);
+		/* PATH1_BAL_LEVEL */
+		cx25840_and_or(client, 0x8d5, ~0x7f, bal & 0x7f);
+	} else {
+		/* PATH1_BAL_LEFT */
+		cx25840_and_or(client, 0x8d5, 0x7f, 0x00);
+		/* PATH1_BAL_LEVEL */
+		cx25840_and_or(client, 0x8d5, ~0x7f, 0x80 - bal);
+	}
+}
+
+int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct cx25840_state *state = to_state(sd);
+	int retval;
+
+	if (!is_cx2583x(state))
+		cx25840_and_or(client, 0x810, ~0x1, 1);
+	if (state->aud_input != CX25840_AUDIO_SERIAL) {
+		cx25840_and_or(client, 0x803, ~0x10, 0);
+		cx25840_write(client, 0x8d3, 0x1f);
+	}
+	retval = set_audclk_freq(client, freq);
+	if (state->aud_input != CX25840_AUDIO_SERIAL)
+		cx25840_and_or(client, 0x803, ~0x10, 0x10);
+	if (!is_cx2583x(state))
+		cx25840_and_or(client, 0x810, ~0x1, 0);
+	return retval;
+}
+
+static int cx25840_audio_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct cx25840_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		if (state->mute->val)
+			set_volume(client, 0);
+		else
+			set_volume(client, state->volume->val);
+		break;
+	case V4L2_CID_AUDIO_BASS:
+		/* PATH1_EQ_BASS_VOL */
+		cx25840_and_or(client, 0x8d9, ~0x3f,
+					48 - (ctrl->val * 48 / 0xffff));
+		break;
+	case V4L2_CID_AUDIO_TREBLE:
+		/* PATH1_EQ_TREBLE_VOL */
+		cx25840_and_or(client, 0x8db, ~0x3f,
+					48 - (ctrl->val * 48 / 0xffff));
+		break;
+	case V4L2_CID_AUDIO_BALANCE:
+		set_balance(client, ctrl->val);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+const struct v4l2_ctrl_ops cx25840_audio_ctrl_ops = {
+	.s_ctrl = cx25840_audio_s_ctrl,
+};
diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
new file mode 100644
index 0000000..d8eac3e
--- /dev/null
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
@@ -0,0 +1,5340 @@
+/* cx25840 - Conexant CX25840 audio/video decoder driver
+ *
+ * Copyright (C) 2004 Ulf Eklund
+ *
+ * Based on the saa7115 driver and on the first version of Chris Kennedy's
+ * cx25840 driver.
+ *
+ * Changes by Tyler Trafford <tatrafford@comcast.net>
+ *    - cleanup/rewrite for V4L2 API (2005)
+ *
+ * VBI support by Hans Verkuil <hverkuil@xs4all.nl>.
+ *
+ * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca>
+ * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>.
+ *
+ * CX23885 support by Steven Toth <stoth@linuxtv.org>.
+ *
+ * CX2388[578] IRQ handling, IO Pin mux configuration and other small fixes are
+ * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net>
+ *
+ * CX23888 DIF support for the HVR1850
+ * Copyright (C) 2011 Steven Toth <stoth@kernellabs.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/math64.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/cx25840.h>
+
+#include "cx25840-core.h"
+
+MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver");
+MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford");
+MODULE_LICENSE("GPL");
+
+#define CX25840_VID_INT_STAT_REG 0x410
+#define CX25840_VID_INT_STAT_BITS 0x0000ffff
+#define CX25840_VID_INT_MASK_BITS 0xffff0000
+#define CX25840_VID_INT_MASK_SHFT 16
+#define CX25840_VID_INT_MASK_REG 0x412
+
+#define CX23885_AUD_MC_INT_MASK_REG 0x80c
+#define CX23885_AUD_MC_INT_STAT_BITS 0xffff0000
+#define CX23885_AUD_MC_INT_CTRL_BITS 0x0000ffff
+#define CX23885_AUD_MC_INT_STAT_SHFT 16
+
+#define CX25840_AUD_INT_CTRL_REG 0x812
+#define CX25840_AUD_INT_STAT_REG 0x813
+
+#define CX23885_PIN_CTRL_IRQ_REG 0x123
+#define CX23885_PIN_CTRL_IRQ_IR_STAT  0x40
+#define CX23885_PIN_CTRL_IRQ_AUD_STAT 0x20
+#define CX23885_PIN_CTRL_IRQ_VID_STAT 0x10
+
+#define CX25840_IR_STATS_REG	0x210
+#define CX25840_IR_IRQEN_REG	0x214
+
+static int cx25840_debug;
+
+module_param_named(debug,cx25840_debug, int, 0644);
+
+MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]");
+
+
+/* ----------------------------------------------------------------------- */
+static void cx23888_std_setup(struct i2c_client *client);
+
+int cx25840_write(struct i2c_client *client, u16 addr, u8 value)
+{
+	u8 buffer[3];
+	buffer[0] = addr >> 8;
+	buffer[1] = addr & 0xff;
+	buffer[2] = value;
+	return i2c_master_send(client, buffer, 3);
+}
+
+int cx25840_write4(struct i2c_client *client, u16 addr, u32 value)
+{
+	u8 buffer[6];
+	buffer[0] = addr >> 8;
+	buffer[1] = addr & 0xff;
+	buffer[2] = value & 0xff;
+	buffer[3] = (value >> 8) & 0xff;
+	buffer[4] = (value >> 16) & 0xff;
+	buffer[5] = value >> 24;
+	return i2c_master_send(client, buffer, 6);
+}
+
+u8 cx25840_read(struct i2c_client * client, u16 addr)
+{
+	struct i2c_msg msgs[2];
+	u8 tx_buf[2], rx_buf[1];
+
+	/* Write register address */
+	tx_buf[0] = addr >> 8;
+	tx_buf[1] = addr & 0xff;
+	msgs[0].addr = client->addr;
+	msgs[0].flags = 0;
+	msgs[0].len = 2;
+	msgs[0].buf = (char *) tx_buf;
+
+	/* Read data from register */
+	msgs[1].addr = client->addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = 1;
+	msgs[1].buf = (char *) rx_buf;
+
+	if (i2c_transfer(client->adapter, msgs, 2) < 2)
+		return 0;
+
+	return rx_buf[0];
+}
+
+u32 cx25840_read4(struct i2c_client * client, u16 addr)
+{
+	struct i2c_msg msgs[2];
+	u8 tx_buf[2], rx_buf[4];
+
+	/* Write register address */
+	tx_buf[0] = addr >> 8;
+	tx_buf[1] = addr & 0xff;
+	msgs[0].addr = client->addr;
+	msgs[0].flags = 0;
+	msgs[0].len = 2;
+	msgs[0].buf = (char *) tx_buf;
+
+	/* Read data from registers */
+	msgs[1].addr = client->addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = 4;
+	msgs[1].buf = (char *) rx_buf;
+
+	if (i2c_transfer(client->adapter, msgs, 2) < 2)
+		return 0;
+
+	return (rx_buf[3] << 24) | (rx_buf[2] << 16) | (rx_buf[1] << 8) |
+		rx_buf[0];
+}
+
+int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,
+		   u8 or_value)
+{
+	return cx25840_write(client, addr,
+			     (cx25840_read(client, addr) & and_mask) |
+			     or_value);
+}
+
+int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask,
+		    u32 or_value)
+{
+	return cx25840_write4(client, addr,
+			      (cx25840_read4(client, addr) & and_mask) |
+			      or_value);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
+						enum cx25840_audio_input aud_input);
+
+/* ----------------------------------------------------------------------- */
+
+static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n,
+				      struct v4l2_subdev_io_pin_config *p)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int i;
+	u32 pin_ctrl;
+	u8 gpio_oe, gpio_data, strength;
+
+	pin_ctrl = cx25840_read4(client, 0x120);
+	gpio_oe = cx25840_read(client, 0x160);
+	gpio_data = cx25840_read(client, 0x164);
+
+	for (i = 0; i < n; i++) {
+		strength = p[i].strength;
+		if (strength > CX25840_PIN_DRIVE_FAST)
+			strength = CX25840_PIN_DRIVE_FAST;
+
+		switch (p[i].pin) {
+		case CX23885_PIN_IRQ_N_GPIO16:
+			if (p[i].function != CX23885_PAD_IRQ_N) {
+				/* GPIO16 */
+				pin_ctrl &= ~(0x1 << 25);
+			} else {
+				/* IRQ_N */
+				if (p[i].flags &
+					(V4L2_SUBDEV_IO_PIN_DISABLE |
+					 V4L2_SUBDEV_IO_PIN_INPUT)) {
+					pin_ctrl &= ~(0x1 << 25);
+				} else {
+					pin_ctrl |= (0x1 << 25);
+				}
+				if (p[i].flags &
+					V4L2_SUBDEV_IO_PIN_ACTIVE_LOW) {
+					pin_ctrl &= ~(0x1 << 24);
+				} else {
+					pin_ctrl |= (0x1 << 24);
+				}
+			}
+			break;
+		case CX23885_PIN_IR_RX_GPIO19:
+			if (p[i].function != CX23885_PAD_GPIO19) {
+				/* IR_RX */
+				gpio_oe |= (0x1 << 0);
+				pin_ctrl &= ~(0x3 << 18);
+				pin_ctrl |= (strength << 18);
+			} else {
+				/* GPIO19 */
+				gpio_oe &= ~(0x1 << 0);
+				if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) {
+					gpio_data &= ~(0x1 << 0);
+					gpio_data |= ((p[i].value & 0x1) << 0);
+				}
+				pin_ctrl &= ~(0x3 << 12);
+				pin_ctrl |= (strength << 12);
+			}
+			break;
+		case CX23885_PIN_IR_TX_GPIO20:
+			if (p[i].function != CX23885_PAD_GPIO20) {
+				/* IR_TX */
+				gpio_oe |= (0x1 << 1);
+				if (p[i].flags & V4L2_SUBDEV_IO_PIN_DISABLE)
+					pin_ctrl &= ~(0x1 << 10);
+				else
+					pin_ctrl |= (0x1 << 10);
+				pin_ctrl &= ~(0x3 << 18);
+				pin_ctrl |= (strength << 18);
+			} else {
+				/* GPIO20 */
+				gpio_oe &= ~(0x1 << 1);
+				if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) {
+					gpio_data &= ~(0x1 << 1);
+					gpio_data |= ((p[i].value & 0x1) << 1);
+				}
+				pin_ctrl &= ~(0x3 << 12);
+				pin_ctrl |= (strength << 12);
+			}
+			break;
+		case CX23885_PIN_I2S_SDAT_GPIO21:
+			if (p[i].function != CX23885_PAD_GPIO21) {
+				/* I2S_SDAT */
+				/* TODO: Input or Output config */
+				gpio_oe |= (0x1 << 2);
+				pin_ctrl &= ~(0x3 << 22);
+				pin_ctrl |= (strength << 22);
+			} else {
+				/* GPIO21 */
+				gpio_oe &= ~(0x1 << 2);
+				if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) {
+					gpio_data &= ~(0x1 << 2);
+					gpio_data |= ((p[i].value & 0x1) << 2);
+				}
+				pin_ctrl &= ~(0x3 << 12);
+				pin_ctrl |= (strength << 12);
+			}
+			break;
+		case CX23885_PIN_I2S_WCLK_GPIO22:
+			if (p[i].function != CX23885_PAD_GPIO22) {
+				/* I2S_WCLK */
+				/* TODO: Input or Output config */
+				gpio_oe |= (0x1 << 3);
+				pin_ctrl &= ~(0x3 << 22);
+				pin_ctrl |= (strength << 22);
+			} else {
+				/* GPIO22 */
+				gpio_oe &= ~(0x1 << 3);
+				if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) {
+					gpio_data &= ~(0x1 << 3);
+					gpio_data |= ((p[i].value & 0x1) << 3);
+				}
+				pin_ctrl &= ~(0x3 << 12);
+				pin_ctrl |= (strength << 12);
+			}
+			break;
+		case CX23885_PIN_I2S_BCLK_GPIO23:
+			if (p[i].function != CX23885_PAD_GPIO23) {
+				/* I2S_BCLK */
+				/* TODO: Input or Output config */
+				gpio_oe |= (0x1 << 4);
+				pin_ctrl &= ~(0x3 << 22);
+				pin_ctrl |= (strength << 22);
+			} else {
+				/* GPIO23 */
+				gpio_oe &= ~(0x1 << 4);
+				if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) {
+					gpio_data &= ~(0x1 << 4);
+					gpio_data |= ((p[i].value & 0x1) << 4);
+				}
+				pin_ctrl &= ~(0x3 << 12);
+				pin_ctrl |= (strength << 12);
+			}
+			break;
+		}
+	}
+
+	cx25840_write(client, 0x164, gpio_data);
+	cx25840_write(client, 0x160, gpio_oe);
+	cx25840_write4(client, 0x120, pin_ctrl);
+	return 0;
+}
+
+static int common_s_io_pin_config(struct v4l2_subdev *sd, size_t n,
+				      struct v4l2_subdev_io_pin_config *pincfg)
+{
+	struct cx25840_state *state = to_state(sd);
+
+	if (is_cx2388x(state))
+		return cx23885_s_io_pin_config(sd, n, pincfg);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void init_dll1(struct i2c_client *client)
+{
+	/* This is the Hauppauge sequence used to
+	 * initialize the Delay Lock Loop 1 (ADC DLL). */
+	cx25840_write(client, 0x159, 0x23);
+	cx25840_write(client, 0x15a, 0x87);
+	cx25840_write(client, 0x15b, 0x06);
+	udelay(10);
+	cx25840_write(client, 0x159, 0xe1);
+	udelay(10);
+	cx25840_write(client, 0x15a, 0x86);
+	cx25840_write(client, 0x159, 0xe0);
+	cx25840_write(client, 0x159, 0xe1);
+	cx25840_write(client, 0x15b, 0x10);
+}
+
+static void init_dll2(struct i2c_client *client)
+{
+	/* This is the Hauppauge sequence used to
+	 * initialize the Delay Lock Loop 2 (ADC DLL). */
+	cx25840_write(client, 0x15d, 0xe3);
+	cx25840_write(client, 0x15e, 0x86);
+	cx25840_write(client, 0x15f, 0x06);
+	udelay(10);
+	cx25840_write(client, 0x15d, 0xe1);
+	cx25840_write(client, 0x15d, 0xe0);
+	cx25840_write(client, 0x15d, 0xe1);
+}
+
+static void cx25836_initialize(struct i2c_client *client)
+{
+	/* reset configuration is described on page 3-77 of the CX25836 datasheet */
+	/* 2. */
+	cx25840_and_or(client, 0x000, ~0x01, 0x01);
+	cx25840_and_or(client, 0x000, ~0x01, 0x00);
+	/* 3a. */
+	cx25840_and_or(client, 0x15a, ~0x70, 0x00);
+	/* 3b. */
+	cx25840_and_or(client, 0x15b, ~0x1e, 0x06);
+	/* 3c. */
+	cx25840_and_or(client, 0x159, ~0x02, 0x02);
+	/* 3d. */
+	udelay(10);
+	/* 3e. */
+	cx25840_and_or(client, 0x159, ~0x02, 0x00);
+	/* 3f. */
+	cx25840_and_or(client, 0x159, ~0xc0, 0xc0);
+	/* 3g. */
+	cx25840_and_or(client, 0x159, ~0x01, 0x00);
+	cx25840_and_or(client, 0x159, ~0x01, 0x01);
+	/* 3h. */
+	cx25840_and_or(client, 0x15b, ~0x1e, 0x10);
+}
+
+static void cx25840_work_handler(struct work_struct *work)
+{
+	struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work);
+	cx25840_loadfw(state->c);
+	wake_up(&state->fw_wait);
+}
+
+static void cx25840_initialize(struct i2c_client *client)
+{
+	DEFINE_WAIT(wait);
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+	struct workqueue_struct *q;
+
+	/* datasheet startup in numbered steps, refer to page 3-77 */
+	/* 2. */
+	cx25840_and_or(client, 0x803, ~0x10, 0x00);
+	/* The default of this register should be 4, but I get 0 instead.
+	 * Set this register to 4 manually. */
+	cx25840_write(client, 0x000, 0x04);
+	/* 3. */
+	init_dll1(client);
+	init_dll2(client);
+	cx25840_write(client, 0x136, 0x0a);
+	/* 4. */
+	cx25840_write(client, 0x13c, 0x01);
+	cx25840_write(client, 0x13c, 0x00);
+	/* 5. */
+	/* Do the firmware load in a work handler to prevent.
+	   Otherwise the kernel is blocked waiting for the
+	   bit-banging i2c interface to finish uploading the
+	   firmware. */
+	INIT_WORK(&state->fw_work, cx25840_work_handler);
+	init_waitqueue_head(&state->fw_wait);
+	q = create_singlethread_workqueue("cx25840_fw");
+	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+	queue_work(q, &state->fw_work);
+	schedule();
+	finish_wait(&state->fw_wait, &wait);
+	destroy_workqueue(q);
+
+	/* 6. */
+	cx25840_write(client, 0x115, 0x8c);
+	cx25840_write(client, 0x116, 0x07);
+	cx25840_write(client, 0x118, 0x02);
+	/* 7. */
+	cx25840_write(client, 0x4a5, 0x80);
+	cx25840_write(client, 0x4a5, 0x00);
+	cx25840_write(client, 0x402, 0x00);
+	/* 8. */
+	cx25840_and_or(client, 0x401, ~0x18, 0);
+	cx25840_and_or(client, 0x4a2, ~0x10, 0x10);
+	/* steps 8c and 8d are done in change_input() */
+	/* 10. */
+	cx25840_write(client, 0x8d3, 0x1f);
+	cx25840_write(client, 0x8e3, 0x03);
+
+	cx25840_std_setup(client);
+
+	/* trial and error says these are needed to get audio */
+	cx25840_write(client, 0x914, 0xa0);
+	cx25840_write(client, 0x918, 0xa0);
+	cx25840_write(client, 0x919, 0x01);
+
+	/* stereo preferred */
+	cx25840_write(client, 0x809, 0x04);
+	/* AC97 shift */
+	cx25840_write(client, 0x8cf, 0x0f);
+
+	/* (re)set input */
+	set_input(client, state->vid_input, state->aud_input);
+
+	/* start microcontroller */
+	cx25840_and_or(client, 0x803, ~0x10, 0x10);
+}
+
+static void cx23885_initialize(struct i2c_client *client)
+{
+	DEFINE_WAIT(wait);
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+	struct workqueue_struct *q;
+
+	/*
+	 * Come out of digital power down
+	 * The CX23888, at least, needs this, otherwise registers aside from
+	 * 0x0-0x2 can't be read or written.
+	 */
+	cx25840_write(client, 0x000, 0);
+
+	/* Internal Reset */
+	cx25840_and_or(client, 0x102, ~0x01, 0x01);
+	cx25840_and_or(client, 0x102, ~0x01, 0x00);
+
+	/* Stop microcontroller */
+	cx25840_and_or(client, 0x803, ~0x10, 0x00);
+
+	/* DIF in reset? */
+	cx25840_write(client, 0x398, 0);
+
+	/*
+	 * Trust the default xtal, no division
+	 * '885: 28.636363... MHz
+	 * '887: 25.000000 MHz
+	 * '888: 50.000000 MHz
+	 */
+	cx25840_write(client, 0x2, 0x76);
+
+	/* Power up all the PLL's and DLL */
+	cx25840_write(client, 0x1, 0x40);
+
+	/* Sys PLL */
+	switch (state->id) {
+	case V4L2_IDENT_CX23888_AV:
+		/*
+		 * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz
+		 * 572.73 MHz before post divide
+		 */
+		/* HVR1850 or 50MHz xtal */
+		cx25840_write(client, 0x2, 0x71);
+		cx25840_write4(client, 0x11c, 0x01d1744c);
+		cx25840_write4(client, 0x118, 0x00000416);
+		cx25840_write4(client, 0x404, 0x0010253e);
+		cx25840_write4(client, 0x42c, 0x42600000);
+		cx25840_write4(client, 0x44c, 0x161f1000);
+		break;
+	case V4L2_IDENT_CX23887_AV:
+		/*
+		 * 25.0 MHz * (0x16 + 0x1d1744c/0x2000000)/4 = 5 * 28.636363 MHz
+		 * 572.73 MHz before post divide
+		 */
+		cx25840_write4(client, 0x11c, 0x01d1744c);
+		cx25840_write4(client, 0x118, 0x00000416);
+		break;
+	case V4L2_IDENT_CX23885_AV:
+	default:
+		/*
+		 * 28.636363 MHz * (0x14 + 0x0/0x2000000)/4 = 5 * 28.636363 MHz
+		 * 572.73 MHz before post divide
+		 */
+		cx25840_write4(client, 0x11c, 0x00000000);
+		cx25840_write4(client, 0x118, 0x00000414);
+		break;
+	}
+
+	/* Disable DIF bypass */
+	cx25840_write4(client, 0x33c, 0x00000001);
+
+	/* DIF Src phase inc */
+	cx25840_write4(client, 0x340, 0x0df7df83);
+
+	/*
+	 * Vid PLL
+	 * Setup for a BT.656 pixel clock of 13.5 Mpixels/second
+	 *
+	 * 28.636363 MHz * (0xf + 0x02be2c9/0x2000000)/4 = 8 * 13.5 MHz
+	 * 432.0 MHz before post divide
+	 */
+
+	/* HVR1850 */
+	switch (state->id) {
+	case V4L2_IDENT_CX23888_AV:
+		/* 888/HVR1250 specific */
+		cx25840_write4(client, 0x10c, 0x13333333);
+		cx25840_write4(client, 0x108, 0x00000515);
+		break;
+	default:
+		cx25840_write4(client, 0x10c, 0x002be2c9);
+		cx25840_write4(client, 0x108, 0x0000040f);
+	}
+
+	/* Luma */
+	cx25840_write4(client, 0x414, 0x00107d12);
+
+	/* Chroma */
+	cx25840_write4(client, 0x420, 0x3d008282);
+
+	/*
+	 * Aux PLL
+	 * Initial setup for audio sample clock:
+	 * 48 ksps, 16 bits/sample, x160 multiplier = 122.88 MHz
+	 * Initial I2S output/master clock(?):
+	 * 48 ksps, 16 bits/sample, x16 multiplier = 12.288 MHz
+	 */
+	switch (state->id) {
+	case V4L2_IDENT_CX23888_AV:
+		/*
+		 * 50.0 MHz * (0x7 + 0x0bedfa4/0x2000000)/3 = 122.88 MHz
+		 * 368.64 MHz before post divide
+		 * 122.88 MHz / 0xa = 12.288 MHz
+		 */
+		/* HVR1850  or 50MHz xtal */
+		cx25840_write4(client, 0x114, 0x017dbf48);
+		cx25840_write4(client, 0x110, 0x000a030e);
+		break;
+	case V4L2_IDENT_CX23887_AV:
+		/*
+		 * 25.0 MHz * (0xe + 0x17dbf48/0x2000000)/3 = 122.88 MHz
+		 * 368.64 MHz before post divide
+		 * 122.88 MHz / 0xa = 12.288 MHz
+		 */
+		cx25840_write4(client, 0x114, 0x017dbf48);
+		cx25840_write4(client, 0x110, 0x000a030e);
+		break;
+	case V4L2_IDENT_CX23885_AV:
+	default:
+		/*
+		 * 28.636363 MHz * (0xc + 0x1bf0c9e/0x2000000)/3 = 122.88 MHz
+		 * 368.64 MHz before post divide
+		 * 122.88 MHz / 0xa = 12.288 MHz
+		 */
+		cx25840_write4(client, 0x114, 0x01bf0c9e);
+		cx25840_write4(client, 0x110, 0x000a030c);
+		break;
+	};
+
+	/* ADC2 input select */
+	cx25840_write(client, 0x102, 0x10);
+
+	/* VIN1 & VIN5 */
+	cx25840_write(client, 0x103, 0x11);
+
+	/* Enable format auto detect */
+	cx25840_write(client, 0x400, 0);
+	/* Fast subchroma lock */
+	/* White crush, Chroma AGC & Chroma Killer enabled */
+	cx25840_write(client, 0x401, 0xe8);
+
+	/* Select AFE clock pad output source */
+	cx25840_write(client, 0x144, 0x05);
+
+	/* Drive GPIO2 direction and values for HVR1700
+	 * where an onboard mux selects the output of demodulator
+	 * vs the 417. Failure to set this results in no DTV.
+	 * It's safe to set this across all Hauppauge boards
+	 * currently, regardless of the board type.
+	 */
+	cx25840_write(client, 0x160, 0x1d);
+	cx25840_write(client, 0x164, 0x00);
+
+	/* Do the firmware load in a work handler to prevent.
+	   Otherwise the kernel is blocked waiting for the
+	   bit-banging i2c interface to finish uploading the
+	   firmware. */
+	INIT_WORK(&state->fw_work, cx25840_work_handler);
+	init_waitqueue_head(&state->fw_wait);
+	q = create_singlethread_workqueue("cx25840_fw");
+	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+	queue_work(q, &state->fw_work);
+	schedule();
+	finish_wait(&state->fw_wait, &wait);
+	destroy_workqueue(q);
+
+	/* Call the cx23888 specific std setup func, we no longer rely on
+	 * the generic cx24840 func.
+	 */
+	if (is_cx23888(state))
+		cx23888_std_setup(client);
+	else
+		cx25840_std_setup(client);
+
+	/* (re)set input */
+	set_input(client, state->vid_input, state->aud_input);
+
+	/* start microcontroller */
+	cx25840_and_or(client, 0x803, ~0x10, 0x10);
+
+	/* Disable and clear video interrupts - we don't use them */
+	cx25840_write4(client, CX25840_VID_INT_STAT_REG, 0xffffffff);
+
+	/* Disable and clear audio interrupts - we don't use them */
+	cx25840_write(client, CX25840_AUD_INT_CTRL_REG, 0xff);
+	cx25840_write(client, CX25840_AUD_INT_STAT_REG, 0xff);
+
+	/* CC raw enable */
+	/*  - VIP 1.1 control codes - 10bit, blue field enable.
+	 *  - enable raw data during vertical blanking.
+	 *  - enable ancillary Data insertion for 656 or VIP.
+	 */
+	cx25840_write4(client, 0x404, 0x0010253e);
+
+	/* CC on  - Undocumented Register */
+	cx25840_write(client, 0x42f, 0x66);
+
+	/* HVR-1250 / HVR1850 DIF related */
+	/* Power everything up */
+	cx25840_write4(client, 0x130, 0x0);
+
+	/* Undocumented */
+	cx25840_write4(client, 0x478, 0x6628021F);
+
+	/* AFE_CLK_OUT_CTRL - Select the clock output source as output */
+	cx25840_write4(client, 0x144, 0x5);
+
+	/* I2C_OUT_CTL - I2S output configuration as
+	 * Master, Sony, Left justified, left sample on WS=1
+	 */
+	cx25840_write4(client, 0x918, 0x1a0);
+
+	/* AFE_DIAG_CTRL1 */
+	cx25840_write4(client, 0x134, 0x000a1800);
+
+	/* AFE_DIAG_CTRL3 - Inverted Polarity for Audio and Video */
+	cx25840_write4(client, 0x13c, 0x00310000);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void cx231xx_initialize(struct i2c_client *client)
+{
+	DEFINE_WAIT(wait);
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+	struct workqueue_struct *q;
+
+	/* Internal Reset */
+	cx25840_and_or(client, 0x102, ~0x01, 0x01);
+	cx25840_and_or(client, 0x102, ~0x01, 0x00);
+
+	/* Stop microcontroller */
+	cx25840_and_or(client, 0x803, ~0x10, 0x00);
+
+	/* DIF in reset? */
+	cx25840_write(client, 0x398, 0);
+
+	/* Trust the default xtal, no division */
+	/* This changes for the cx23888 products */
+	cx25840_write(client, 0x2, 0x76);
+
+	/* Bring down the regulator for AUX clk */
+	cx25840_write(client, 0x1, 0x40);
+
+	/* Disable DIF bypass */
+	cx25840_write4(client, 0x33c, 0x00000001);
+
+	/* DIF Src phase inc */
+	cx25840_write4(client, 0x340, 0x0df7df83);
+
+	/* Luma */
+	cx25840_write4(client, 0x414, 0x00107d12);
+
+	/* Chroma */
+	cx25840_write4(client, 0x420, 0x3d008282);
+
+	/* ADC2 input select */
+	cx25840_write(client, 0x102, 0x10);
+
+	/* VIN1 & VIN5 */
+	cx25840_write(client, 0x103, 0x11);
+
+	/* Enable format auto detect */
+	cx25840_write(client, 0x400, 0);
+	/* Fast subchroma lock */
+	/* White crush, Chroma AGC & Chroma Killer enabled */
+	cx25840_write(client, 0x401, 0xe8);
+
+	/* Do the firmware load in a work handler to prevent.
+	   Otherwise the kernel is blocked waiting for the
+	   bit-banging i2c interface to finish uploading the
+	   firmware. */
+	INIT_WORK(&state->fw_work, cx25840_work_handler);
+	init_waitqueue_head(&state->fw_wait);
+	q = create_singlethread_workqueue("cx25840_fw");
+	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+	queue_work(q, &state->fw_work);
+	schedule();
+	finish_wait(&state->fw_wait, &wait);
+	destroy_workqueue(q);
+
+	cx25840_std_setup(client);
+
+	/* (re)set input */
+	set_input(client, state->vid_input, state->aud_input);
+
+	/* start microcontroller */
+	cx25840_and_or(client, 0x803, ~0x10, 0x10);
+
+	/* CC raw enable */
+	cx25840_write(client, 0x404, 0x0b);
+
+	/* CC on */
+	cx25840_write(client, 0x42f, 0x66);
+	cx25840_write4(client, 0x474, 0x1e1e601a);
+}
+
+/* ----------------------------------------------------------------------- */
+
+void cx25840_std_setup(struct i2c_client *client)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+	v4l2_std_id std = state->std;
+	int hblank, hactive, burst, vblank, vactive, sc;
+	int vblank656, src_decimation;
+	int luma_lpf, uv_lpf, comb;
+	u32 pll_int, pll_frac, pll_post;
+
+	/* datasheet startup, step 8d */
+	if (std & ~V4L2_STD_NTSC)
+		cx25840_write(client, 0x49f, 0x11);
+	else
+		cx25840_write(client, 0x49f, 0x14);
+
+	if (std & V4L2_STD_625_50) {
+		hblank = 132;
+		hactive = 720;
+		burst = 93;
+		vblank = 36;
+		vactive = 580;
+		vblank656 = 40;
+		src_decimation = 0x21f;
+		luma_lpf = 2;
+
+		if (std & V4L2_STD_SECAM) {
+			uv_lpf = 0;
+			comb = 0;
+			sc = 0x0a425f;
+		} else if (std == V4L2_STD_PAL_Nc) {
+			uv_lpf = 1;
+			comb = 0x20;
+			sc = 556453;
+		} else {
+			uv_lpf = 1;
+			comb = 0x20;
+			sc = 688739;
+		}
+	} else {
+		hactive = 720;
+		hblank = 122;
+		vactive = 487;
+		luma_lpf = 1;
+		uv_lpf = 1;
+
+		src_decimation = 0x21f;
+		if (std == V4L2_STD_PAL_60) {
+			vblank = 26;
+			vblank656 = 26;
+			burst = 0x5b;
+			luma_lpf = 2;
+			comb = 0x20;
+			sc = 688739;
+		} else if (std == V4L2_STD_PAL_M) {
+			vblank = 20;
+			vblank656 = 24;
+			burst = 0x61;
+			comb = 0x20;
+			sc = 555452;
+		} else {
+			vblank = 26;
+			vblank656 = 26;
+			burst = 0x5b;
+			comb = 0x66;
+			sc = 556063;
+		}
+	}
+
+	/* DEBUG: Displays configured PLL frequency */
+	if (!is_cx231xx(state)) {
+		pll_int = cx25840_read(client, 0x108);
+		pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff;
+		pll_post = cx25840_read(client, 0x109);
+		v4l_dbg(1, cx25840_debug, client,
+			"PLL regs = int: %u, frac: %u, post: %u\n",
+			pll_int, pll_frac, pll_post);
+
+		if (pll_post) {
+			int fin, fsc;
+			int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L;
+
+			pll /= pll_post;
+			v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n",
+					pll / 1000000, pll % 1000000);
+			v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n",
+					pll / 8000000, (pll / 8) % 1000000);
+
+			fin = ((u64)src_decimation * pll) >> 12;
+			v4l_dbg(1, cx25840_debug, client,
+					"ADC Sampling freq = %d.%06d MHz\n",
+					fin / 1000000, fin % 1000000);
+
+			fsc = (((u64)sc) * pll) >> 24L;
+			v4l_dbg(1, cx25840_debug, client,
+					"Chroma sub-carrier freq = %d.%06d MHz\n",
+					fsc / 1000000, fsc % 1000000);
+
+			v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
+				"vblank %i, vactive %i, vblank656 %i, src_dec %i, "
+				"burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, "
+				"sc 0x%06x\n",
+				hblank, hactive, vblank, vactive, vblank656,
+				src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
+		}
+	}
+
+	/* Sets horizontal blanking delay and active lines */
+	cx25840_write(client, 0x470, hblank);
+	cx25840_write(client, 0x471,
+			0xff & (((hblank >> 8) & 0x3) | (hactive << 4)));
+	cx25840_write(client, 0x472, hactive >> 4);
+
+	/* Sets burst gate delay */
+	cx25840_write(client, 0x473, burst);
+
+	/* Sets vertical blanking delay and active duration */
+	cx25840_write(client, 0x474, vblank);
+	cx25840_write(client, 0x475,
+			0xff & (((vblank >> 8) & 0x3) | (vactive << 4)));
+	cx25840_write(client, 0x476, vactive >> 4);
+	cx25840_write(client, 0x477, vblank656);
+
+	/* Sets src decimation rate */
+	cx25840_write(client, 0x478, 0xff & src_decimation);
+	cx25840_write(client, 0x479, 0xff & (src_decimation >> 8));
+
+	/* Sets Luma and UV Low pass filters */
+	cx25840_write(client, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
+
+	/* Enables comb filters */
+	cx25840_write(client, 0x47b, comb);
+
+	/* Sets SC Step*/
+	cx25840_write(client, 0x47c, sc);
+	cx25840_write(client, 0x47d, 0xff & sc >> 8);
+	cx25840_write(client, 0x47e, 0xff & sc >> 16);
+
+	/* Sets VBI parameters */
+	if (std & V4L2_STD_625_50) {
+		cx25840_write(client, 0x47f, 0x01);
+		state->vbi_line_offset = 5;
+	} else {
+		cx25840_write(client, 0x47f, 0x00);
+		state->vbi_line_offset = 8;
+	}
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void input_change(struct i2c_client *client)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+	v4l2_std_id std = state->std;
+
+	/* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */
+	if (std & V4L2_STD_SECAM) {
+		cx25840_write(client, 0x402, 0);
+	}
+	else {
+		cx25840_write(client, 0x402, 0x04);
+		cx25840_write(client, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
+	}
+	cx25840_and_or(client, 0x401, ~0x60, 0);
+	cx25840_and_or(client, 0x401, ~0x60, 0x60);
+
+	/* Don't write into audio registers on cx2583x chips */
+	if (is_cx2583x(state))
+		return;
+
+	cx25840_and_or(client, 0x810, ~0x01, 1);
+
+	if (state->radio) {
+		cx25840_write(client, 0x808, 0xf9);
+		cx25840_write(client, 0x80b, 0x00);
+	}
+	else if (std & V4L2_STD_525_60) {
+		/* Certain Hauppauge PVR150 models have a hardware bug
+		   that causes audio to drop out. For these models the
+		   audio standard must be set explicitly.
+		   To be precise: it affects cards with tuner models
+		   85, 99 and 112 (model numbers from tveeprom). */
+		int hw_fix = state->pvr150_workaround;
+
+		if (std == V4L2_STD_NTSC_M_JP) {
+			/* Japan uses EIAJ audio standard */
+			cx25840_write(client, 0x808, hw_fix ? 0x2f : 0xf7);
+		} else if (std == V4L2_STD_NTSC_M_KR) {
+			/* South Korea uses A2 audio standard */
+			cx25840_write(client, 0x808, hw_fix ? 0x3f : 0xf8);
+		} else {
+			/* Others use the BTSC audio standard */
+			cx25840_write(client, 0x808, hw_fix ? 0x1f : 0xf6);
+		}
+		cx25840_write(client, 0x80b, 0x00);
+	} else if (std & V4L2_STD_PAL) {
+		/* Autodetect audio standard and audio system */
+		cx25840_write(client, 0x808, 0xff);
+		/* Since system PAL-L is pretty much non-existent and
+		   not used by any public broadcast network, force
+		   6.5 MHz carrier to be interpreted as System DK,
+		   this avoids DK audio detection instability */
+	       cx25840_write(client, 0x80b, 0x00);
+	} else if (std & V4L2_STD_SECAM) {
+		/* Autodetect audio standard and audio system */
+		cx25840_write(client, 0x808, 0xff);
+		/* If only one of SECAM-DK / SECAM-L is required, then force
+		  6.5MHz carrier, else autodetect it */
+		if ((std & V4L2_STD_SECAM_DK) &&
+		    !(std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) {
+			/* 6.5 MHz carrier to be interpreted as System DK */
+			cx25840_write(client, 0x80b, 0x00);
+	       } else if (!(std & V4L2_STD_SECAM_DK) &&
+			  (std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) {
+			/* 6.5 MHz carrier to be interpreted as System L */
+			cx25840_write(client, 0x80b, 0x08);
+	       } else {
+			/* 6.5 MHz carrier to be autodetected */
+			cx25840_write(client, 0x80b, 0x10);
+	       }
+	}
+
+	cx25840_and_or(client, 0x810, ~0x01, 0);
+}
+
+static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
+						enum cx25840_audio_input aud_input)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+	u8 is_composite = (vid_input >= CX25840_COMPOSITE1 &&
+			   vid_input <= CX25840_COMPOSITE8);
+	u8 is_component = (vid_input & CX25840_COMPONENT_ON) ==
+			CX25840_COMPONENT_ON;
+	u8 is_dif = (vid_input & CX25840_DIF_ON) ==
+			CX25840_DIF_ON;
+	u8 is_svideo = (vid_input & CX25840_SVIDEO_ON) ==
+			CX25840_SVIDEO_ON;
+	int luma = vid_input & 0xf0;
+	int chroma = vid_input & 0xf00;
+	u8 reg;
+	u32 val;
+
+	v4l_dbg(1, cx25840_debug, client,
+		"decoder set video input %d, audio input %d\n",
+		vid_input, aud_input);
+
+	if (vid_input >= CX25840_VIN1_CH1) {
+		v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n",
+			vid_input);
+		reg = vid_input & 0xff;
+		is_composite = !is_component &&
+			((vid_input & CX25840_SVIDEO_ON) != CX25840_SVIDEO_ON);
+
+		v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n",
+			reg, is_composite);
+	} else if (is_composite) {
+		reg = 0xf0 + (vid_input - CX25840_COMPOSITE1);
+	} else {
+		if ((vid_input & ~0xff0) ||
+		    luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA8 ||
+		    chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) {
+			v4l_err(client, "0x%04x is not a valid video input!\n",
+				vid_input);
+			return -EINVAL;
+		}
+		reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4);
+		if (chroma >= CX25840_SVIDEO_CHROMA7) {
+			reg &= 0x3f;
+			reg |= (chroma - CX25840_SVIDEO_CHROMA7) >> 2;
+		} else {
+			reg &= 0xcf;
+			reg |= (chroma - CX25840_SVIDEO_CHROMA4) >> 4;
+		}
+	}
+
+	/* The caller has previously prepared the correct routing
+	 * configuration in reg (for the cx23885) so we have no
+	 * need to attempt to flip bits for earlier av decoders.
+	 */
+	if (!is_cx2388x(state) && !is_cx231xx(state)) {
+		switch (aud_input) {
+		case CX25840_AUDIO_SERIAL:
+			/* do nothing, use serial audio input */
+			break;
+		case CX25840_AUDIO4: reg &= ~0x30; break;
+		case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
+		case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
+		case CX25840_AUDIO7: reg &= ~0xc0; break;
+		case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
+
+		default:
+			v4l_err(client, "0x%04x is not a valid audio input!\n",
+				aud_input);
+			return -EINVAL;
+		}
+	}
+
+	cx25840_write(client, 0x103, reg);
+
+	/* Set INPUT_MODE to Composite, S-Video or Component */
+	if (is_component)
+		cx25840_and_or(client, 0x401, ~0x6, 0x6);
+	else
+		cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
+
+	if (is_cx2388x(state)) {
+
+		/* Enable or disable the DIF for tuner use */
+		if (is_dif) {
+			cx25840_and_or(client, 0x102, ~0x80, 0x80);
+
+			/* Set of defaults for NTSC and PAL */
+			cx25840_write4(client, 0x31c, 0xc2262600);
+			cx25840_write4(client, 0x320, 0xc2262600);
+
+			/* 18271 IF - Nobody else yet uses a different
+			 * tuner with the DIF, so these are reasonable
+			 * assumptions (HVR1250 and HVR1850 specific).
+			 */
+			cx25840_write4(client, 0x318, 0xda262600);
+			cx25840_write4(client, 0x33c, 0x2a24c800);
+			cx25840_write4(client, 0x104, 0x0704dd00);
+		} else {
+			cx25840_write4(client, 0x300, 0x015c28f5);
+
+			cx25840_and_or(client, 0x102, ~0x80, 0);
+			cx25840_write4(client, 0x340, 0xdf7df83);
+			cx25840_write4(client, 0x104, 0x0704dd80);
+			cx25840_write4(client, 0x314, 0x22400600);
+			cx25840_write4(client, 0x318, 0x40002600);
+			cx25840_write4(client, 0x324, 0x40002600);
+			cx25840_write4(client, 0x32c, 0x0250e620);
+			cx25840_write4(client, 0x39c, 0x01FF0B00);
+
+			cx25840_write4(client, 0x410, 0xffff0dbf);
+			cx25840_write4(client, 0x414, 0x00137d03);
+
+			/* on the 887, 0x418 is HSCALE_CTRL, on the 888 it is 
+			   CHROMA_CTRL */
+			if (is_cx23888(state))
+				cx25840_write4(client, 0x418, 0x01008080);
+			else
+				cx25840_write4(client, 0x418, 0x01000000);
+
+			cx25840_write4(client, 0x41c, 0x00000000);
+
+			/* on the 887, 0x420 is CHROMA_CTRL, on the 888 it is 
+			   CRUSH_CTRL */
+			if (is_cx23888(state))
+				cx25840_write4(client, 0x420, 0x001c3e0f);
+			else
+				cx25840_write4(client, 0x420, 0x001c8282);
+
+			cx25840_write4(client, 0x42c, 0x42600000);
+			cx25840_write4(client, 0x430, 0x0000039b);
+			cx25840_write4(client, 0x438, 0x00000000);
+
+			cx25840_write4(client, 0x440, 0xF8E3E824);
+			cx25840_write4(client, 0x444, 0x401040dc);
+			cx25840_write4(client, 0x448, 0xcd3f02a0);
+			cx25840_write4(client, 0x44c, 0x161f1000);
+			cx25840_write4(client, 0x450, 0x00000802);
+
+			cx25840_write4(client, 0x91c, 0x01000000);
+			cx25840_write4(client, 0x8e0, 0x03063870);
+			cx25840_write4(client, 0x8d4, 0x7FFF0024);
+			cx25840_write4(client, 0x8d0, 0x00063073);
+
+			cx25840_write4(client, 0x8c8, 0x00010000);
+			cx25840_write4(client, 0x8cc, 0x00080023);
+
+			/* DIF BYPASS */
+			cx25840_write4(client, 0x33c, 0x2a04c800);
+		}
+
+		/* Reset the DIF */
+		cx25840_write4(client, 0x398, 0);
+	}
+
+	if (!is_cx2388x(state) && !is_cx231xx(state)) {
+		/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
+		cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
+		/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */
+		if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
+			cx25840_and_or(client, 0x102, ~0x4, 4);
+		else
+			cx25840_and_or(client, 0x102, ~0x4, 0);
+	} else {
+		/* Set DUAL_MODE_ADC2 to 1 if component*/
+		cx25840_and_or(client, 0x102, ~0x4, is_component ? 0x4 : 0x0);
+		if (is_composite) {
+			/* ADC2 input select channel 2 */
+			cx25840_and_or(client, 0x102, ~0x2, 0);
+		} else if (!is_component) {
+			/* S-Video */
+			if (chroma >= CX25840_SVIDEO_CHROMA7) {
+				/* ADC2 input select channel 3 */
+				cx25840_and_or(client, 0x102, ~0x2, 2);
+			} else {
+				/* ADC2 input select channel 2 */
+				cx25840_and_or(client, 0x102, ~0x2, 0);
+			}
+		}
+
+		/* cx23885 / SVIDEO */
+		if (is_cx2388x(state) && is_svideo) {
+#define AFE_CTRL  (0x104)
+#define MODE_CTRL (0x400)
+			cx25840_and_or(client, 0x102, ~0x2, 0x2);
+
+			val = cx25840_read4(client, MODE_CTRL);
+			val &= 0xFFFFF9FF;
+
+			/* YC */
+			val |= 0x00000200;
+			val &= ~0x2000;
+			cx25840_write4(client, MODE_CTRL, val);
+
+			val = cx25840_read4(client, AFE_CTRL);
+
+			/* Chroma in select */
+			val |= 0x00001000;
+			val &= 0xfffffe7f;
+			/* Clear VGA_SEL_CH2 and VGA_SEL_CH3 (bits 7 and 8).
+			 * This sets them to use video rather than audio.
+			 * Only one of the two will be in use.
+			 */
+			cx25840_write4(client, AFE_CTRL, val);
+		} else
+			cx25840_and_or(client, 0x102, ~0x2, 0);
+	}
+
+	state->vid_input = vid_input;
+	state->aud_input = aud_input;
+	cx25840_audio_set_path(client);
+	input_change(client);
+
+	if (is_cx2388x(state)) {
+		/* Audio channel 1 src : Parallel 1 */
+		cx25840_write(client, 0x124, 0x03);
+
+		/* Select AFE clock pad output source */
+		cx25840_write(client, 0x144, 0x05);
+
+		/* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */
+		cx25840_write(client, 0x914, 0xa0);
+
+		/* I2S_OUT_CTL:
+		 * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1
+		 * I2S_OUT_MASTER_MODE = Master
+		 */
+		cx25840_write(client, 0x918, 0xa0);
+		cx25840_write(client, 0x919, 0x01);
+	} else if (is_cx231xx(state)) {
+		/* Audio channel 1 src : Parallel 1 */
+		cx25840_write(client, 0x124, 0x03);
+
+		/* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */
+		cx25840_write(client, 0x914, 0xa0);
+
+		/* I2S_OUT_CTL:
+		 * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1
+		 * I2S_OUT_MASTER_MODE = Master
+		 */
+		cx25840_write(client, 0x918, 0xa0);
+		cx25840_write(client, 0x919, 0x01);
+	}
+
+	if (is_cx2388x(state) && ((aud_input == CX25840_AUDIO7) ||
+		(aud_input == CX25840_AUDIO6))) {
+		/* Configure audio from LR1 or LR2 input */
+		cx25840_write4(client, 0x910, 0);
+		cx25840_write4(client, 0x8d0, 0x63073);
+	} else
+	if (is_cx2388x(state) && (aud_input == CX25840_AUDIO8)) {
+		/* Configure audio from tuner/sif input */
+		cx25840_write4(client, 0x910, 0x12b000c9);
+		cx25840_write4(client, 0x8d0, 0x1f063870);
+	}
+
+	if (is_cx23888(state)) {
+		/* HVR1850 */
+		/* AUD_IO_CTRL - I2S Input, Parallel1*/
+		/*  - Channel 1 src - Parallel1 (Merlin out) */
+		/*  - Channel 2 src - Parallel2 (Merlin out) */
+		/*  - Channel 3 src - Parallel3 (Merlin AC97 out) */
+		/*  - I2S source and dir - Merlin, output */
+		cx25840_write4(client, 0x124, 0x100);
+
+		if (!is_dif) {
+			/* Stop microcontroller if we don't need it
+			 * to avoid audio popping on svideo/composite use.
+			 */
+			cx25840_and_or(client, 0x803, ~0x10, 0x00);
+		}
+	}
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_v4lstd(struct i2c_client *client)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+	u8 fmt = 0; 	/* zero is autodetect */
+	u8 pal_m = 0;
+
+	/* First tests should be against specific std */
+	if (state->std == V4L2_STD_NTSC_M_JP) {
+		fmt = 0x2;
+	} else if (state->std == V4L2_STD_NTSC_443) {
+		fmt = 0x3;
+	} else if (state->std == V4L2_STD_PAL_M) {
+		pal_m = 1;
+		fmt = 0x5;
+	} else if (state->std == V4L2_STD_PAL_N) {
+		fmt = 0x6;
+	} else if (state->std == V4L2_STD_PAL_Nc) {
+		fmt = 0x7;
+	} else if (state->std == V4L2_STD_PAL_60) {
+		fmt = 0x8;
+	} else {
+		/* Then, test against generic ones */
+		if (state->std & V4L2_STD_NTSC)
+			fmt = 0x1;
+		else if (state->std & V4L2_STD_PAL)
+			fmt = 0x4;
+		else if (state->std & V4L2_STD_SECAM)
+			fmt = 0xc;
+	}
+
+	v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n",fmt);
+
+	/* Follow step 9 of section 3.16 in the cx25840 datasheet.
+	   Without this PAL may display a vertical ghosting effect.
+	   This happens for example with the Yuan MPC622. */
+	if (fmt >= 4 && fmt < 8) {
+		/* Set format to NTSC-M */
+		cx25840_and_or(client, 0x400, ~0xf, 1);
+		/* Turn off LCOMB */
+		cx25840_and_or(client, 0x47b, ~6, 0);
+	}
+	cx25840_and_or(client, 0x400, ~0xf, fmt);
+	cx25840_and_or(client, 0x403, ~0x3, pal_m);
+	if (is_cx23888(state))
+		cx23888_std_setup(client);
+	else
+		cx25840_std_setup(client);
+	if (!is_cx2583x(state))
+		input_change(client);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int cx25840_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct cx25840_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		cx25840_write(client, 0x414, ctrl->val - 128);
+		break;
+
+	case V4L2_CID_CONTRAST:
+		cx25840_write(client, 0x415, ctrl->val << 1);
+		break;
+
+	case V4L2_CID_SATURATION:
+		if (is_cx23888(state)) {
+			cx25840_write(client, 0x418, ctrl->val << 1);
+			cx25840_write(client, 0x419, ctrl->val << 1);
+		} else {
+			cx25840_write(client, 0x420, ctrl->val << 1);
+			cx25840_write(client, 0x421, ctrl->val << 1);
+		}
+		break;
+
+	case V4L2_CID_HUE:
+		if (is_cx23888(state))
+			cx25840_write(client, 0x41a, ctrl->val);
+		else
+			cx25840_write(client, 0x422, ctrl->val);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int cx25840_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
+{
+	struct cx25840_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
+	int is_50Hz = !(state->std & V4L2_STD_525_60);
+
+	if (fmt->code != V4L2_MBUS_FMT_FIXED)
+		return -EINVAL;
+
+	fmt->field = V4L2_FIELD_INTERLACED;
+	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+	if (is_cx23888(state)) {
+		Vsrc = (cx25840_read(client, 0x42a) & 0x3f) << 4;
+		Vsrc |= (cx25840_read(client, 0x429) & 0xf0) >> 4;
+	} else {
+		Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4;
+		Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4;
+	}
+
+	if (is_cx23888(state)) {
+		Hsrc = (cx25840_read(client, 0x426) & 0x3f) << 4;
+		Hsrc |= (cx25840_read(client, 0x425) & 0xf0) >> 4;
+	} else {
+		Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4;
+		Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4;
+	}
+
+	Vlines = fmt->height + (is_50Hz ? 4 : 7);
+
+	if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) ||
+			(Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
+		v4l_err(client, "%dx%d is not a valid size!\n",
+				fmt->width, fmt->height);
+		return -ERANGE;
+	}
+
+	HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20);
+	VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
+	VSC &= 0x1fff;
+
+	if (fmt->width >= 385)
+		filter = 0;
+	else if (fmt->width > 192)
+		filter = 1;
+	else if (fmt->width > 96)
+		filter = 2;
+	else
+		filter = 3;
+
+	v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale  %ux%u\n",
+			fmt->width, fmt->height, HSC, VSC);
+
+	/* HSCALE=HSC */
+	cx25840_write(client, 0x418, HSC & 0xff);
+	cx25840_write(client, 0x419, (HSC >> 8) & 0xff);
+	cx25840_write(client, 0x41a, HSC >> 16);
+	/* VSCALE=VSC */
+	cx25840_write(client, 0x41c, VSC & 0xff);
+	cx25840_write(client, 0x41d, VSC >> 8);
+	/* VS_INTRLACE=1 VFILT=filter */
+	cx25840_write(client, 0x41e, 0x8 | filter);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void log_video_status(struct i2c_client *client)
+{
+	static const char *const fmt_strs[] = {
+		"0x0",
+		"NTSC-M", "NTSC-J", "NTSC-4.43",
+		"PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
+		"0x9", "0xA", "0xB",
+		"SECAM",
+		"0xD", "0xE", "0xF"
+	};
+
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+	u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
+	u8 gen_stat1 = cx25840_read(client, 0x40d);
+	u8 gen_stat2 = cx25840_read(client, 0x40e);
+	int vid_input = state->vid_input;
+
+	v4l_info(client, "Video signal:              %spresent\n",
+		    (gen_stat2 & 0x20) ? "" : "not ");
+	v4l_info(client, "Detected format:           %s\n",
+		    fmt_strs[gen_stat1 & 0xf]);
+
+	v4l_info(client, "Specified standard:        %s\n",
+		    vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
+
+	if (vid_input >= CX25840_COMPOSITE1 &&
+	    vid_input <= CX25840_COMPOSITE8) {
+		v4l_info(client, "Specified video input:     Composite %d\n",
+			vid_input - CX25840_COMPOSITE1 + 1);
+	} else {
+		v4l_info(client, "Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",
+			(vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
+	}
+
+	v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void log_audio_status(struct i2c_client *client)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+	u8 download_ctl = cx25840_read(client, 0x803);
+	u8 mod_det_stat0 = cx25840_read(client, 0x804);
+	u8 mod_det_stat1 = cx25840_read(client, 0x805);
+	u8 audio_config = cx25840_read(client, 0x808);
+	u8 pref_mode = cx25840_read(client, 0x809);
+	u8 afc0 = cx25840_read(client, 0x80b);
+	u8 mute_ctl = cx25840_read(client, 0x8d3);
+	int aud_input = state->aud_input;
+	char *p;
+
+	switch (mod_det_stat0) {
+	case 0x00: p = "mono"; break;
+	case 0x01: p = "stereo"; break;
+	case 0x02: p = "dual"; break;
+	case 0x04: p = "tri"; break;
+	case 0x10: p = "mono with SAP"; break;
+	case 0x11: p = "stereo with SAP"; break;
+	case 0x12: p = "dual with SAP"; break;
+	case 0x14: p = "tri with SAP"; break;
+	case 0xfe: p = "forced mode"; break;
+	default: p = "not defined";
+	}
+	v4l_info(client, "Detected audio mode:       %s\n", p);
+
+	switch (mod_det_stat1) {
+	case 0x00: p = "not defined"; break;
+	case 0x01: p = "EIAJ"; break;
+	case 0x02: p = "A2-M"; break;
+	case 0x03: p = "A2-BG"; break;
+	case 0x04: p = "A2-DK1"; break;
+	case 0x05: p = "A2-DK2"; break;
+	case 0x06: p = "A2-DK3"; break;
+	case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
+	case 0x08: p = "AM-L"; break;
+	case 0x09: p = "NICAM-BG"; break;
+	case 0x0a: p = "NICAM-DK"; break;
+	case 0x0b: p = "NICAM-I"; break;
+	case 0x0c: p = "NICAM-L"; break;
+	case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
+	case 0x0e: p = "IF FM Radio"; break;
+	case 0x0f: p = "BTSC"; break;
+	case 0x10: p = "high-deviation FM"; break;
+	case 0x11: p = "very high-deviation FM"; break;
+	case 0xfd: p = "unknown audio standard"; break;
+	case 0xfe: p = "forced audio standard"; break;
+	case 0xff: p = "no detected audio standard"; break;
+	default: p = "not defined";
+	}
+	v4l_info(client, "Detected audio standard:   %s\n", p);
+	v4l_info(client, "Audio microcontroller:     %s\n",
+		    (download_ctl & 0x10) ?
+				((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
+
+	switch (audio_config >> 4) {
+	case 0x00: p = "undefined"; break;
+	case 0x01: p = "BTSC"; break;
+	case 0x02: p = "EIAJ"; break;
+	case 0x03: p = "A2-M"; break;
+	case 0x04: p = "A2-BG"; break;
+	case 0x05: p = "A2-DK1"; break;
+	case 0x06: p = "A2-DK2"; break;
+	case 0x07: p = "A2-DK3"; break;
+	case 0x08: p = "A1 (6.0 MHz FM Mono)"; break;
+	case 0x09: p = "AM-L"; break;
+	case 0x0a: p = "NICAM-BG"; break;
+	case 0x0b: p = "NICAM-DK"; break;
+	case 0x0c: p = "NICAM-I"; break;
+	case 0x0d: p = "NICAM-L"; break;
+	case 0x0e: p = "FM radio"; break;
+	case 0x0f: p = "automatic detection"; break;
+	default: p = "undefined";
+	}
+	v4l_info(client, "Configured audio standard: %s\n", p);
+
+	if ((audio_config >> 4) < 0xF) {
+		switch (audio_config & 0xF) {
+		case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break;
+		case 0x01: p = "MONO2 (LANGUAGE B)"; break;
+		case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
+		case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
+		case 0x04: p = "STEREO"; break;
+		case 0x05: p = "DUAL1 (AB)"; break;
+		case 0x06: p = "DUAL2 (AC) (FM)"; break;
+		case 0x07: p = "DUAL3 (BC) (FM)"; break;
+		case 0x08: p = "DUAL4 (AC) (AM)"; break;
+		case 0x09: p = "DUAL5 (BC) (AM)"; break;
+		case 0x0a: p = "SAP"; break;
+		default: p = "undefined";
+		}
+		v4l_info(client, "Configured audio mode:     %s\n", p);
+	} else {
+		switch (audio_config & 0xF) {
+		case 0x00: p = "BG"; break;
+		case 0x01: p = "DK1"; break;
+		case 0x02: p = "DK2"; break;
+		case 0x03: p = "DK3"; break;
+		case 0x04: p = "I"; break;
+		case 0x05: p = "L"; break;
+		case 0x06: p = "BTSC"; break;
+		case 0x07: p = "EIAJ"; break;
+		case 0x08: p = "A2-M"; break;
+		case 0x09: p = "FM Radio"; break;
+		case 0x0f: p = "automatic standard and mode detection"; break;
+		default: p = "undefined";
+		}
+		v4l_info(client, "Configured audio system:   %s\n", p);
+	}
+
+	if (aud_input) {
+		v4l_info(client, "Specified audio input:     Tuner (In%d)\n", aud_input);
+	} else {
+		v4l_info(client, "Specified audio input:     External\n");
+	}
+
+	switch (pref_mode & 0xf) {
+	case 0: p = "mono/language A"; break;
+	case 1: p = "language B"; break;
+	case 2: p = "language C"; break;
+	case 3: p = "analog fallback"; break;
+	case 4: p = "stereo"; break;
+	case 5: p = "language AC"; break;
+	case 6: p = "language BC"; break;
+	case 7: p = "language AB"; break;
+	default: p = "undefined";
+	}
+	v4l_info(client, "Preferred audio mode:      %s\n", p);
+
+	if ((audio_config & 0xf) == 0xf) {
+		switch ((afc0 >> 3) & 0x3) {
+		case 0: p = "system DK"; break;
+		case 1: p = "system L"; break;
+		case 2: p = "autodetect"; break;
+		default: p = "undefined";
+		}
+		v4l_info(client, "Selected 65 MHz format:    %s\n", p);
+
+		switch (afc0 & 0x7) {
+		case 0: p = "chroma"; break;
+		case 1: p = "BTSC"; break;
+		case 2: p = "EIAJ"; break;
+		case 3: p = "A2-M"; break;
+		case 4: p = "autodetect"; break;
+		default: p = "undefined";
+		}
+		v4l_info(client, "Selected 45 MHz format:    %s\n", p);
+	}
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* This load_fw operation must be called to load the driver's firmware.
+   Without this the audio standard detection will fail and you will
+   only get mono.
+
+   Since loading the firmware is often problematic when the driver is
+   compiled into the kernel I recommend postponing calling this function
+   until the first open of the video device. Another reason for
+   postponing it is that loading this firmware takes a long time (seconds)
+   due to the slow i2c bus speed. So it will speed up the boot process if
+   you can avoid loading the fw as long as the video device isn't used.  */
+static int cx25840_load_fw(struct v4l2_subdev *sd)
+{
+	struct cx25840_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!state->is_initialized) {
+		/* initialize and load firmware */
+		state->is_initialized = 1;
+		if (is_cx2583x(state))
+			cx25836_initialize(client);
+		else if (is_cx2388x(state))
+			cx23885_initialize(client);
+		else if (is_cx231xx(state))
+			cx231xx_initialize(client);
+		else
+			cx25840_initialize(client);
+	}
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	reg->size = 1;
+	reg->val = cx25840_read(client, reg->reg & 0x0fff);
+	return 0;
+}
+
+static int cx25840_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
+	return 0;
+}
+#endif
+
+static int cx25840_s_audio_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct cx25840_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 v;
+
+	if (is_cx2583x(state) || is_cx2388x(state) || is_cx231xx(state))
+		return 0;
+
+	v4l_dbg(1, cx25840_debug, client, "%s audio output\n",
+			enable ? "enable" : "disable");
+
+	if (enable) {
+		v = cx25840_read(client, 0x115) | 0x80;
+		cx25840_write(client, 0x115, v);
+		v = cx25840_read(client, 0x116) | 0x03;
+		cx25840_write(client, 0x116, v);
+	} else {
+		v = cx25840_read(client, 0x115) & ~(0x80);
+		cx25840_write(client, 0x115, v);
+		v = cx25840_read(client, 0x116) & ~(0x03);
+		cx25840_write(client, 0x116, v);
+	}
+	return 0;
+}
+
+static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct cx25840_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 v;
+
+	v4l_dbg(1, cx25840_debug, client, "%s video output\n",
+			enable ? "enable" : "disable");
+	if (enable) {
+		if (is_cx2388x(state) || is_cx231xx(state)) {
+			v = cx25840_read(client, 0x421) | 0x0b;
+			cx25840_write(client, 0x421, v);
+		} else {
+			v = cx25840_read(client, 0x115) | 0x0c;
+			cx25840_write(client, 0x115, v);
+			v = cx25840_read(client, 0x116) | 0x04;
+			cx25840_write(client, 0x116, v);
+		}
+	} else {
+		if (is_cx2388x(state) || is_cx231xx(state)) {
+			v = cx25840_read(client, 0x421) & ~(0x0b);
+			cx25840_write(client, 0x421, v);
+		} else {
+			v = cx25840_read(client, 0x115) & ~(0x0c);
+			cx25840_write(client, 0x115, v);
+			v = cx25840_read(client, 0x116) & ~(0x04);
+			cx25840_write(client, 0x116, v);
+		}
+	}
+	return 0;
+}
+
+/* Query the current detected video format */
+static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	v4l2_std_id stds[] = {
+		/* 0000 */ V4L2_STD_UNKNOWN,
+
+		/* 0001 */ V4L2_STD_NTSC_M,
+		/* 0010 */ V4L2_STD_NTSC_M_JP,
+		/* 0011 */ V4L2_STD_NTSC_443,
+		/* 0100 */ V4L2_STD_PAL,
+		/* 0101 */ V4L2_STD_PAL_M,
+		/* 0110 */ V4L2_STD_PAL_N,
+		/* 0111 */ V4L2_STD_PAL_Nc,
+		/* 1000 */ V4L2_STD_PAL_60,
+
+		/* 1001 */ V4L2_STD_UNKNOWN,
+		/* 1010 */ V4L2_STD_UNKNOWN,
+		/* 1001 */ V4L2_STD_UNKNOWN,
+		/* 1010 */ V4L2_STD_UNKNOWN,
+		/* 1011 */ V4L2_STD_UNKNOWN,
+		/* 1110 */ V4L2_STD_UNKNOWN,
+		/* 1111 */ V4L2_STD_UNKNOWN
+	};
+
+	u32 fmt = (cx25840_read4(client, 0x40c) >> 8) & 0xf;
+	*std = stds[ fmt ];
+
+	v4l_dbg(1, cx25840_debug, client, "g_std fmt = %x, v4l2_std_id = 0x%x\n",
+		fmt, (unsigned int)stds[ fmt ]);
+
+	return 0;
+}
+
+static int cx25840_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	/* A limited function that checks for signal status and returns
+	 * the state.
+	 */
+
+	/* Check for status of Horizontal lock (SRC lock isn't reliable) */
+	if ((cx25840_read4(client, 0x40c) & 0x00010000) == 0)
+		*status |= V4L2_IN_ST_NO_SIGNAL;
+
+	return 0;
+}
+
+static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct cx25840_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (state->radio == 0 && state->std == std)
+		return 0;
+	state->radio = 0;
+	state->std = std;
+	return set_v4lstd(client);
+}
+
+static int cx25840_s_radio(struct v4l2_subdev *sd)
+{
+	struct cx25840_state *state = to_state(sd);
+
+	state->radio = 1;
+	return 0;
+}
+
+static int cx25840_s_video_routing(struct v4l2_subdev *sd,
+				   u32 input, u32 output, u32 config)
+{
+	struct cx25840_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (is_cx23888(state))
+		cx23888_std_setup(client);
+
+	return set_input(client, input, state->aud_input);
+}
+
+static int cx25840_s_audio_routing(struct v4l2_subdev *sd,
+				   u32 input, u32 output, u32 config)
+{
+	struct cx25840_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (is_cx23888(state))
+		cx23888_std_setup(client);
+	return set_input(client, state->vid_input, input);
+}
+
+static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	input_change(client);
+	return 0;
+}
+
+static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct cx25840_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 vpres = cx25840_read(client, 0x40e) & 0x20;
+	u8 mode;
+	int val = 0;
+
+	if (state->radio)
+		return 0;
+
+	vt->signal = vpres ? 0xffff : 0x0;
+	if (is_cx2583x(state))
+		return 0;
+
+	vt->capability |=
+		V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+		V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+
+	mode = cx25840_read(client, 0x804);
+
+	/* get rxsubchans and audmode */
+	if ((mode & 0xf) == 1)
+		val |= V4L2_TUNER_SUB_STEREO;
+	else
+		val |= V4L2_TUNER_SUB_MONO;
+
+	if (mode == 2 || mode == 4)
+		val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+
+	if (mode & 0x10)
+		val |= V4L2_TUNER_SUB_SAP;
+
+	vt->rxsubchans = val;
+	vt->audmode = state->audmode;
+	return 0;
+}
+
+static int cx25840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct cx25840_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (state->radio || is_cx2583x(state))
+		return 0;
+
+	switch (vt->audmode) {
+		case V4L2_TUNER_MODE_MONO:
+			/* mono      -> mono
+			   stereo    -> mono
+			   bilingual -> lang1 */
+			cx25840_and_or(client, 0x809, ~0xf, 0x00);
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+		case V4L2_TUNER_MODE_LANG1:
+			/* mono      -> mono
+			   stereo    -> stereo
+			   bilingual -> lang1 */
+			cx25840_and_or(client, 0x809, ~0xf, 0x04);
+			break;
+		case V4L2_TUNER_MODE_LANG1_LANG2:
+			/* mono      -> mono
+			   stereo    -> stereo
+			   bilingual -> lang1/lang2 */
+			cx25840_and_or(client, 0x809, ~0xf, 0x07);
+			break;
+		case V4L2_TUNER_MODE_LANG2:
+			/* mono      -> mono
+			   stereo    -> stereo
+			   bilingual -> lang2 */
+			cx25840_and_or(client, 0x809, ~0xf, 0x01);
+			break;
+		default:
+			return -EINVAL;
+	}
+	state->audmode = vt->audmode;
+	return 0;
+}
+
+static int cx25840_reset(struct v4l2_subdev *sd, u32 val)
+{
+	struct cx25840_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (is_cx2583x(state))
+		cx25836_initialize(client);
+	else if (is_cx2388x(state))
+		cx23885_initialize(client);
+	else if (is_cx231xx(state))
+		cx231xx_initialize(client);
+	else
+		cx25840_initialize(client);
+	return 0;
+}
+
+static int cx25840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct cx25840_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev);
+}
+
+static int cx25840_log_status(struct v4l2_subdev *sd)
+{
+	struct cx25840_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	log_video_status(client);
+	if (!is_cx2583x(state))
+		log_audio_status(client);
+	cx25840_ir_log_status(sd);
+	v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
+	return 0;
+}
+
+static int cx23885_irq_handler(struct v4l2_subdev *sd, u32 status,
+			       bool *handled)
+{
+	struct cx25840_state *state = to_state(sd);
+	struct i2c_client *c = v4l2_get_subdevdata(sd);
+	u8 irq_stat, aud_stat, aud_en, ir_stat, ir_en;
+	u32 vid_stat, aud_mc_stat;
+	bool block_handled;
+	int ret = 0;
+
+	irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG);
+	v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (entry): %s %s %s\n",
+		irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : "  ",
+		irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : "   ",
+		irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : "   ");
+
+	if ((is_cx23885(state) || is_cx23887(state))) {
+		ir_stat = cx25840_read(c, CX25840_IR_STATS_REG);
+		ir_en = cx25840_read(c, CX25840_IR_IRQEN_REG);
+		v4l_dbg(2, cx25840_debug, c,
+			"AV Core ir IRQ status: %#04x disables: %#04x\n",
+			ir_stat, ir_en);
+		if (irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT) {
+			block_handled = false;
+			ret = cx25840_ir_irq_handler(sd,
+						     status, &block_handled);
+			if (block_handled)
+				*handled = true;
+		}
+	}
+
+	aud_stat = cx25840_read(c, CX25840_AUD_INT_STAT_REG);
+	aud_en = cx25840_read(c, CX25840_AUD_INT_CTRL_REG);
+	v4l_dbg(2, cx25840_debug, c,
+		"AV Core audio IRQ status: %#04x disables: %#04x\n",
+		aud_stat, aud_en);
+	aud_mc_stat = cx25840_read4(c, CX23885_AUD_MC_INT_MASK_REG);
+	v4l_dbg(2, cx25840_debug, c,
+		"AV Core audio MC IRQ status: %#06x enables: %#06x\n",
+		aud_mc_stat >> CX23885_AUD_MC_INT_STAT_SHFT,
+		aud_mc_stat & CX23885_AUD_MC_INT_CTRL_BITS);
+	if (irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT) {
+		if (aud_stat) {
+			cx25840_write(c, CX25840_AUD_INT_STAT_REG, aud_stat);
+			*handled = true;
+		}
+	}
+
+	vid_stat = cx25840_read4(c, CX25840_VID_INT_STAT_REG);
+	v4l_dbg(2, cx25840_debug, c,
+		"AV Core video IRQ status: %#06x disables: %#06x\n",
+		vid_stat & CX25840_VID_INT_STAT_BITS,
+		vid_stat >> CX25840_VID_INT_MASK_SHFT);
+	if (irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT) {
+		if (vid_stat & CX25840_VID_INT_STAT_BITS) {
+			cx25840_write4(c, CX25840_VID_INT_STAT_REG, vid_stat);
+			*handled = true;
+		}
+	}
+
+	irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG);
+	v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (exit): %s %s %s\n",
+		irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : "  ",
+		irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : "   ",
+		irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : "   ");
+
+	return ret;
+}
+
+static int cx25840_irq_handler(struct v4l2_subdev *sd, u32 status,
+			       bool *handled)
+{
+	struct cx25840_state *state = to_state(sd);
+
+	*handled = false;
+
+	/* Only support the CX2388[578] AV Core for now */
+	if (is_cx2388x(state))
+		return cx23885_irq_handler(sd, status, handled);
+
+	return -ENODEV;
+}
+
+/* ----------------------------------------------------------------------- */
+
+#define DIF_PLL_FREQ_WORD	(0x300)
+#define DIF_BPF_COEFF01		(0x348)
+#define DIF_BPF_COEFF23		(0x34c)
+#define DIF_BPF_COEFF45		(0x350)
+#define DIF_BPF_COEFF67		(0x354)
+#define DIF_BPF_COEFF89		(0x358)
+#define DIF_BPF_COEFF1011	(0x35c)
+#define DIF_BPF_COEFF1213	(0x360)
+#define DIF_BPF_COEFF1415	(0x364)
+#define DIF_BPF_COEFF1617	(0x368)
+#define DIF_BPF_COEFF1819	(0x36c)
+#define DIF_BPF_COEFF2021	(0x370)
+#define DIF_BPF_COEFF2223	(0x374)
+#define DIF_BPF_COEFF2425	(0x378)
+#define DIF_BPF_COEFF2627	(0x37c)
+#define DIF_BPF_COEFF2829	(0x380)
+#define DIF_BPF_COEFF3031	(0x384)
+#define DIF_BPF_COEFF3233	(0x388)
+#define DIF_BPF_COEFF3435	(0x38c)
+#define DIF_BPF_COEFF36		(0x390)
+
+void cx23885_dif_setup(struct i2c_client *client, u32 ifHz)
+{
+	u64 pll_freq;
+	u32 pll_freq_word;
+
+	v4l_dbg(1, cx25840_debug, client, "%s(%d)\n", __func__, ifHz);
+
+	/* Assuming TV */
+	/* Calculate the PLL frequency word based on the adjusted ifHz */
+        pll_freq = div_u64((u64)ifHz * 268435456, 50000000);
+        pll_freq_word = (u32)pll_freq;
+
+        cx25840_write4(client, DIF_PLL_FREQ_WORD,  pll_freq_word);
+
+	/* Round down to the nearest 100KHz */
+	ifHz = (ifHz / 100000) * 100000;
+
+	if (ifHz < 3000000)
+		ifHz = 3000000;
+
+	if (ifHz > 16000000)
+		ifHz = 16000000;
+
+	v4l_dbg(1, cx25840_debug, client, "%s(%d) again\n", __func__, ifHz);
+
+	switch (ifHz) {
+	case 3000000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00080012);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0024);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x001bfff8);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffb4ff50);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed8fe68);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe24fe34);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfebaffc7);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d031f);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x04f0065d);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x07010688);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x04c901d6);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe00f9d3);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f342);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf235f337);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf64efb22);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0105070f);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x0c460fce);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 3100000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00070012);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00220032);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00370026);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xfff0ff91);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff0efe7c);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01fdcc);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe0afedb);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440224);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x0434060c);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0738074e);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x06090361);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xff99fb39);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef3b6);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21af2a5);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf573fa33);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0034067d);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x0bfb0fb9);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 3200000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000000);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0004000e);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00200038);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x004c004f);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x002fffdf);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff5cfeb6);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0dfd92);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd7ffe03);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36010a);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x03410575);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x072607d2);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x071804d5);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0134fcb7);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff451);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf223f22e);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4a7f94b);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xff6405e8);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x0bae0fa4);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 3300000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00000008);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x001a0036);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0056006d);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00670030);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xffbdff10);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe46fd8d);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd25fd4f);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35ffe0);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x0224049f);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c9080e);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x07ef0627);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c9fe45);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f513);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf250f1d2);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3ecf869);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe930552);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x0b5f0f8f);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 3400000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd0001);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x000f002c);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0054007d);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x0093007c);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x0024ff82);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea6fdbb);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd03fcca);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51feb9);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x00eb0392);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x06270802);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x08880750);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x044dffdb);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf5f8);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a0f193);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf342f78f);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc404b9);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x0b0e0f78);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 3500000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff9);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0002001b);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0046007d);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00ad00ba);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00870000);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xff26fe1a);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd1bfc7e);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fda4);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xffa5025c);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x054507ad);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x08dd0847);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b80172);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef6ff);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf313f170);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2abf6bd);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6041f);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x0abc0f61);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 3600000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff3);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfff50006);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x002f006c);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00b200e3);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00dc007e);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xffb9fea0);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd6bfc71);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fcb1);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe65010b);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x042d0713);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x08ec0906);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x07020302);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff823);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3a7f16a);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf228f5f5);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xfc2a0384);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x0a670f4a);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 3700000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7ffef);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe9fff1);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0010004d);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00a100f2);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x011a00f0);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x0053ff44);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdedfca2);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fbef);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd39ffae);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x02ea0638);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x08b50987);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x08230483);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f960);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf45bf180);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1b8f537);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xfb6102e7);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x0a110f32);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 3800000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9ffee);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffdd);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xfff00024);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x007c00e5);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x013a014a);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x00e6fff8);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe98fd0f);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fb67);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc32fe54);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x01880525);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x083909c7);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x091505ee);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7fab3);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf52df1b4);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf15df484);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xfa9b0249);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x09ba0f19);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 3900000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000000);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbfff0);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffcf);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1fff6);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x004800be);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x01390184);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x016300ac);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xff5efdb1);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fb23);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb5cfd0d);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x001703e4);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x077b09c4);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x09d2073c);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251fc18);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf61cf203);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf118f3dc);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf9d801aa);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x09600eff);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 4000000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffefff4);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffc8);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffca);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x000b0082);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x01170198);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01c10152);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x0030fe7b);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fb24);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfac3fbe9);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfea5027f);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x0683097f);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a560867);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2fd89);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf723f26f);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0e8f341);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf919010a);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x09060ee5);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 4100000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0002fffb);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe8ffca);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffa4);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffcd0036);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d70184);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f601dc);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x00ffff60);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb6d);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa6efaf5);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd410103);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x055708f9);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a9e0969);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543ff02);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf842f2f5);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0cef2b2);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf85e006b);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x08aa0ecb);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 4200000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00050003);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfff3ffd3);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaff8b);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff95ffe5);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x0080014a);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fe023f);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x01ba0050);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fbf8);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa62fa3b);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbf9ff7e);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x04010836);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aa90a3d);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f007f);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf975f395);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0cbf231);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf7a9ffcb);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x084c0eaf);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 4300000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000a);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0000ffe4);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ff81);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff6aff96);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x001c00f0);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01d70271);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x0254013b);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fcbd);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa9ff9c5);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfadbfdfe);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x028c073b);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a750adf);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e101fa);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xfab8f44e);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0ddf1be);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf6f9ff2b);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x07ed0e94);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 4400000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0009000f);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x000efff8);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ff87);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff52ff54);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xffb5007e);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01860270);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c00210);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fdb2);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb22f997);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9f2fc90);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x0102060f);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a050b4c);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902036e);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xfc0af51e);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf106f15a);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf64efe8b);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x078d0e77);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 4500000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00080012);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0019000e);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff9e);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff4fff25);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff560000);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x0112023b);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f702c0);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfec8);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbe5f9b3);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf947fb41);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xff7004b9);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x095a0b81);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a0004d8);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xfd65f603);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf144f104);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf5aafdec);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x072b0e5a);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 4600000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00060012);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00200022);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ffc1);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff61ff10);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff09ff82);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x008601d7);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f50340);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fff0);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcddfa19);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8e2fa1e);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfde30343);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x08790b7f);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50631);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xfec7f6fc);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf198f0bd);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf50dfd4e);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x06c90e3d);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 4700000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0003000f);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00220030);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ffed);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff87ff15);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed6ff10);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xffed014c);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b90386);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110119);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfdfefac4);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8c6f92f);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc6701b7);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x07670b44);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0776);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x002df807);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf200f086);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf477fcb1);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x06650e1e);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 4800000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0009);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0038);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x003f001b);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffbcff36);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec2feb6);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xff5600a5);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x0248038d);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00232);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xff39fbab);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8f4f87f);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb060020);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x062a0ad2);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf908a3);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0192f922);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf27df05e);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf3e8fc14);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x06000e00);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 4900000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc0002);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00160037);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00510046);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xfff9ff6d);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed0fe7c);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfecefff0);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x01aa0356);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413032b);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x007ffcc5);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf96cf812);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9cefe87);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x04c90a2c);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c4309b4);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x02f3fa4a);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf30ef046);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf361fb7a);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x059b0de0);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 5000000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffa);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x000a002d);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00570067);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x0037ffb5);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfefffe68);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe62ff3d);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x00ec02e3);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x043503f6);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x01befe05);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa27f7ee);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8c6fcf8);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x034c0954);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5c0aa4);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x044cfb7e);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3b1f03f);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf2e2fae1);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x05340dc0);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 5100000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff4);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfffd001e);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0051007b);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x006e0006);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff48fe7c);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe1bfe9a);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x001d023e);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130488);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x02e6ff5b);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb1ef812);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7f7fb7f);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x01bc084e);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c430b72);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x059afcba);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf467f046);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf26cfa4a);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x04cd0da0);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 5200000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8ffef);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfff00009);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x003f007f);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00980056);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xffa5feb6);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe00fe15);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xff4b0170);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b004d7);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x03e800b9);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc48f87f);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf768fa23);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0022071f);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf90c1b);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x06dafdfd);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf52df05e);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf1fef9b5);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x04640d7f);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 5300000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9ffee);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe6fff3);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00250072);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00af009c);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x000cff10);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe13fdb8);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe870089);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x031104e1);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x04b8020f);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd98f92f);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf71df8f0);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe8805ce);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0c9c);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0808ff44);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf603f086);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf19af922);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x03fb0d5e);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 5400000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcffef);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffe0);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00050056);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00b000d1);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x0071ff82);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe53fd8c);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfddfff99);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104a3);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x054a034d);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xff01fa1e);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf717f7ed);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfcf50461);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50cf4);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0921008d);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf6e7f0bd);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf13ff891);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x03920d3b);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 5500000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffffff3);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffd1);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5002f);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x009c00ed);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00cb0000);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfebafd94);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd61feb0);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d0422);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x05970464);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0074fb41);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf759f721);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfb7502de);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000d21);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a2201d4);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf7d9f104);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0edf804);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x03280d19);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 5600000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0003fffa);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe3ffc9);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffc90002);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x007500ef);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x010e007e);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xff3dfdcf);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd16fddd);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440365);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x059b0548);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x01e3fc90);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7dff691);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa0f014d);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x09020d23);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b0a0318);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf8d7f15a);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0a5f779);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x02bd0cf6);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 5700000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00060001);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffecffc9);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ffd4);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x004000d5);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x013600f0);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xffd3fe39);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd04fd31);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xff360277);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x055605ef);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x033efdfe);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8a5f642);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf8cbffb6);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e10cfb);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0bd50456);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf9dff1be);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf067f6f2);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x02520cd2);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 5800000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00080009);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfff8ffd2);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaffac);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x000200a3);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x013c014a);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x006dfec9);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd2bfcb7);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe350165);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x04cb0651);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0477ff7e);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9a5f635);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7b1fe20);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0ca8);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c81058b);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xfaf0f231);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf033f66d);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x01e60cae);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 5900000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0009000e);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0005ffe1);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffacff90);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffc5005f);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x01210184);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x00fcff72);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd8afc77);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51003f);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x04020669);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x05830103);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfad7f66b);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6c8fc93);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430c2b);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d0d06b5);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xfc08f2b2);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf00af5ec);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x017b0c89);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 6000000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00070012);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0012fff5);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaff82);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff8e000f);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e80198);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01750028);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe18fc75);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99ff15);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x03050636);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0656027f);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc32f6e2);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf614fb17);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20b87);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d7707d2);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xfd26f341);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xefeaf56f);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x010f0c64);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 6100000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00050012);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x001c000b);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1ff84);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff66ffbe);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00960184);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01cd00da);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfeccfcb2);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fdf9);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x01e005bc);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x06e703e4);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfdabf798);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf599f9b3);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x02510abd);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dbf08df);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xfe48f3dc);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xefd5f4f6);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x00a20c3e);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 6200000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0002000f);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0021001f);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0ff97);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff50ff74);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x0034014a);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fa0179);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xff97fd2a);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fcfa);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x00a304fe);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x07310525);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xff37f886);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55cf86e);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c709d0);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de209db);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xff6df484);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xefcbf481);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0x00360c18);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 6300000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffe000a);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0021002f);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0010ffb8);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff50ff3b);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xffcc00f0);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fa01fa);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x0069fdd4);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fc26);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xff5d0407);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x07310638);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x00c9f9a8);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55cf74e);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xff3908c3);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de20ac3);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0093f537);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xefcbf410);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xffca0bf2);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 6400000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffb0003);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x001c0037);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x002fffe2);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff66ff17);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff6a007e);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01cd0251);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x0134fea5);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fb8b);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe2002e0);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x06e70713);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x0255faf5);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf599f658);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaf0799);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dbf0b96);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x01b8f5f5);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xefd5f3a3);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xff5e0bca);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 6500000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffb);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00120037);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00460010);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff8eff0f);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff180000);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01750276);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x01e8ff8d);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fb31);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcfb0198);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x065607ad);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x03cefc64);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf614f592);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2e0656);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d770c52);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x02daf6bd);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xefeaf33b);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xfef10ba3);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 6600000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7fff5);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0005002f);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0054003c);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffc5ff22);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedfff82);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x00fc0267);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x0276007e);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb1c);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbfe003e);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x05830802);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x0529fdec);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6c8f4fe);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabd04ff);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d0d0cf6);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x03f8f78f);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf00af2d7);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xfe850b7b);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 6700000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff0);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfff80020);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00560060);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x0002ff4e);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec4ff10);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x006d0225);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02d50166);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb4e);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb35fee1);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0477080e);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x065bff82);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7b1f4a0);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf9610397);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c810d80);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0510f869);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf033f278);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xfe1a0b52);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 6800000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffaffee);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffec000c);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0078);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x0040ff8e);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecafeb6);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xffd301b6);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fc0235);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fbc5);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaaafd90);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x033e07d2);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x075b011b);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf8cbf47a);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81f0224);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0bd50def);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0621f94b);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf067f21e);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xfdae0b29);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 6900000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffdffef);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe3fff6);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0037007f);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x0075ffdc);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef2fe7c);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xff3d0122);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02ea02dd);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fc79);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa65fc5d);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x01e3074e);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x082102ad);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa0ff48c);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fe00a9);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b0a0e43);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0729fa33);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0a5f1c9);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xfd430b00);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 7000000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0001fff3);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffe2);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x001b0076);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x009c002d);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff35fe68);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfeba0076);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x029f0352);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfd60);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa69fb53);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x00740688);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x08a7042d);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfb75f4d6);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600ff2d);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a220e7a);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0827fb22);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0edf17a);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xfcd80ad6);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 7100000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0004fff9);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffd2);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xfffb005e);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00b0007a);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff8ffe7c);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe53ffc1);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x0221038c);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fe6e);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfab6fa80);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xff010587);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x08e90590);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfcf5f556);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bfdb3);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x09210e95);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0919fc15);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf13ff12f);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xfc6e0aab);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 7200000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00070000);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe6ffc9);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffdb0039);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00af00b8);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfff4feb6);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe13ff10);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x01790388);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311ff92);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb48f9ed);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd980453);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x08e306cd);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe88f60a);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482fc40);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x08080e93);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x09fdfd0c);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf19af0ea);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xfc050a81);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 7300000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00080008);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfff0ffc9);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1000d);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x009800e2);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x005bff10);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe00fe74);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x00b50345);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b000bc);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc18f9a1);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc4802f9);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x089807dc);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0022f6f0);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407fada);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x06da0e74);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ad3fe06);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf1fef0ab);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xfb9c0a55);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 7400000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000e);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfffdffd0);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffafffdf);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x006e00f2);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00b8ff82);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe1bfdf8);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xffe302c8);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x041301dc);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd1af99e);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb1e0183);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x080908b5);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x01bcf801);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdf985);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x059a0e38);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b99ff03);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf26cf071);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xfb330a2a);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 7500000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00070011);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x000affdf);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffa9ffb5);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x003700e6);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x01010000);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe62fda8);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xff140219);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x043502e1);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe42f9e6);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa270000);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x073a0953);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x034cf939);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3a4f845);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x044c0de1);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c4f0000);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf2e2f03c);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xfacc09fe);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 7600000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00040012);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0016fff3);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffafff95);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xfff900c0);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x0130007e);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfecefd89);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe560146);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x041303bc);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xff81fa76);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf96cfe7d);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x063209b1);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x04c9fa93);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdf71e);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x02f30d6e);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cf200fd);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf361f00e);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xfa6509d1);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 7700000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00010010);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0008);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1ff84);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffbc0084);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x013e00f0);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xff56fd9f);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdb8005c);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00460);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x00c7fb45);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8f4fd07);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x04fa09ce);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x062afc07);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407f614);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x01920ce0);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d8301fa);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf3e8efe5);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xfa0009a4);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 7800000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd000b);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0022001d);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffdbff82);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff870039);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x012a014a);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xffedfde7);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd47ff6b);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x031104c6);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x0202fc4c);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8c6fbad);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x039909a7);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0767fd8e);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482f52b);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x002d0c39);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e0002f4);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf477efc2);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf99b0977);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 7900000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa0004);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0020002d);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xfffbff91);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff61ffe8);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f70184);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x0086fe5c);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd0bfe85);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104e5);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x0323fd7d);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8e2fa79);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x021d093f);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0879ff22);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bf465);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xfec70b79);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e6803eb);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf50defa5);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf937094a);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 8000000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fffd);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00190036);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x001bffaf);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff4fff99);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00aa0198);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x0112fef3);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd09fdb9);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d04be);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x041bfecc);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf947f978);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x00900897);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x095a00b9);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f3c5);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xfd650aa3);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ebc04de);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf5aaef8e);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf8d5091c);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 8100000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7fff6);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x000e0038);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0037ffd7);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff52ff56);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x004b0184);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x0186ffa1);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd40fd16);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440452);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x04de0029);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9f2f8b2);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfefe07b5);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a05024d);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef34d);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xfc0a09b8);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0efa05cd);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf64eef7d);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf87308ed);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 8200000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff0);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00000031);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0005);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff6aff27);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xffe4014a);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01d70057);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdacfca6);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3603a7);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x05610184);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfadbf82e);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd74069f);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a7503d6);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff2ff);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xfab808b9);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f2306b5);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf6f9ef72);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf81308bf);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 8300000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbffee);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfff30022);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00560032);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff95ff10);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff8000f0);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fe0106);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe46fc71);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3502c7);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x059e02ce);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbf9f7f2);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfbff055b);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aa9054c);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f2db);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf97507aa);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f350797);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf7a9ef6d);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf7b40890);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 8400000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffeffee);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe8000f);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00540058);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffcdff14);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff29007e);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f6019e);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xff01fc7c);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd5101bf);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x059203f6);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd41f7fe);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfaa903f3);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a9e06a9);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf2e2);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf842068b);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f320871);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf85eef6e);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf7560860);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 8500000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0002fff2);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1fff9);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00460073);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x000bff34);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfee90000);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01c10215);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xffd0fcc5);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99009d);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x053d04f1);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfea5f853);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf97d0270);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a5607e4);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef314);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf723055f);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f180943);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf919ef75);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf6fa0830);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 8600000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0005fff8);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffe4);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x002f007f);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x0048ff6b);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec7ff82);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x0163025f);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x00a2fd47);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17ff73);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x04a405b2);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0017f8ed);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf88500dc);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x09d208f9);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff370);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf61c0429);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ee80a0b);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xf9d8ef82);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf6a00800);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 8700000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0007ffff);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffd4);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0010007a);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x007cffb2);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec6ff10);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x00e60277);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x0168fdf9);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fe50);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x03ce0631);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0188f9c8);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7c7ff43);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x091509e3);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f3f6);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf52d02ea);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ea30ac9);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xfa9bef95);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf64607d0);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 8800000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00090007);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe9ffca);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xfff00065);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00a10003);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfee6feb6);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x0053025b);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x0213fed0);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fd46);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x02c70668);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x02eafadb);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf74bfdae);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x08230a9c);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7f4a3);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf45b01a6);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e480b7c);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xfb61efae);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf5ef079f);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 8900000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000d);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfff5ffc8);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffd10043);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00b20053);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff24fe7c);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xffb9020c);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x0295ffbb);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fc64);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x019b0654);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x042dfc1c);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf714fc2a);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x07020b21);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251f575);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3a7005e);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0dd80c24);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xfc2aefcd);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf599076e);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 9000000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00060011);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0002ffcf);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffba0018);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00ad009a);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff79fe68);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xff260192);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02e500ab);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fbb6);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x005b05f7);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0545fd81);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf723fabf);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b80b70);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2f669);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf313ff15);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d550cbf);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6eff2);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf544073d);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 9100000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00030012);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x000fffdd);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffea);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x009300cf);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xffdcfe7c);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea600f7);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fd0190);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb46);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xff150554);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0627fefd);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf778f978);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x044d0b87);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543f77d);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a0fdcf);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cbe0d4e);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc4f01d);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4f2070b);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 9200000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00000010);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x001afff0);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaffbf);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x006700ed);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x0043feb6);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe460047);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02db0258);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb1b);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfddc0473);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c90082);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf811f85e);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c90b66);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x069ff8ad);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf250fc8d);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c140dcf);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe93f04d);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4a106d9);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 9300000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc000c);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00200006);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ff9c);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x002f00ef);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00a4ff10);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0dff92);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x028102f7);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb37);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcbf035e);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x07260202);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8e8f778);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x01340b0d);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1f9f4);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf223fb51);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b590e42);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xff64f083);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf45206a7);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 9400000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff90005);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0022001a);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ff86);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xfff000d7);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f2ff82);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01fee5);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x01f60362);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb99);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbcc0222);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x07380370);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9f7f6cc);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xff990a7e);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902fb50);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21afa1f);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0a8d0ea6);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0034f0bf);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4050675);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 9500000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fffe);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x001e002b);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff81);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffb400a5);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x01280000);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe24fe50);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x01460390);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfc3a);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb1000ce);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x070104bf);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb37f65f);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe0009bc);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a00fcbb);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf235f8f8);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x09b20efc);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0105f101);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf3ba0642);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 9600000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff7);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00150036);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ff8c);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff810061);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x013d007e);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe71fddf);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x007c0380);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fd13);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa94ff70);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x068005e2);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc9bf633);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfc7308ca);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad5fe30);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf274f7e0);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x08c90f43);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x01d4f147);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf371060f);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 9700000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fff1);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00090038);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ffa7);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff5e0012);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x013200f0);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfee3fd9b);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xffaa0331);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fe15);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa60fe18);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x05bd06d1);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe1bf64a);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfafa07ae);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7effab);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2d5f6d7);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x07d30f7a);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x02a3f194);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf32905dc);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 9800000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcffee);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfffb0032);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x003fffcd);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff4effc1);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x0106014a);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xff6efd8a);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfedd02aa);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0ff34);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa74fcd7);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x04bf0781);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xffaaf6a3);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf99e066b);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf90128);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf359f5e1);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x06d20fa2);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0370f1e5);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2e405a8);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 9900000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xffffffee);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffef0024);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0051fffa);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff54ff77);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00be0184);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x0006fdad);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe2701f3);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413005e);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfad1fbba);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x039007ee);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x013bf73d);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf868050a);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c4302a1);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3fdf4fe);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x05c70fba);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x043bf23c);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2a10575);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 10000000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0003fff1);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe50011);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00570027);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff70ff3c);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00620198);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x009efe01);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd95011a);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x04350183);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb71fad0);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x023c0812);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x02c3f811);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf75e0390);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5c0411);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf4c1f432);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x04b30fc1);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0503f297);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2610541);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 10100000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0006fff7);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffdffffc);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00510050);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff9dff18);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfffc0184);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x0128fe80);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd32002e);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130292);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc4dfa21);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x00d107ee);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x0435f91c);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6850205);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c430573);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf5a1f37d);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x03990fba);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x05c7f2f8);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf222050d);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 10200000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffe);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffdfffe7);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x003f006e);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffd6ff0f);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff96014a);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x0197ff1f);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd05ff3e);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0037c);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd59f9b7);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xff5d0781);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x0585fa56);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5e4006f);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf906c4);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf69df2e0);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x02790fa2);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0688f35d);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1e604d8);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 10300000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00090005);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe4ffd6);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0025007e);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x0014ff20);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff3c00f0);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e1ffd0);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd12fe5c);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110433);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe88f996);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfdf106d1);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x06aafbb7);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf57efed8);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e07ff);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf7b0f25e);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x01560f7a);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0745f3c7);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1ac04a4);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 10400000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000c);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffedffcb);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0005007d);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x0050ff4c);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef6007e);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01ff0086);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd58fd97);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104ad);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xffcaf9c0);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc9905e2);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x079afd35);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf555fd46);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50920);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf8d9f1f6);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x00310f43);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x07fdf435);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf174046f);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 10500000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00050011);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfffaffc8);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5006b);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x0082ff8c);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecc0000);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f00130);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdd2fcfc);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d04e3);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x010efa32);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb6404bf);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x084efec5);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf569fbc2);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000a23);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xfa15f1ab);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xff0b0efc);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x08b0f4a7);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf13f043a);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 10600000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00020012);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0007ffcd);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9004c);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00a4ffd9);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec3ff82);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01b401c1);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe76fc97);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x004404d2);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x0245fae8);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa5f0370);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x08c1005f);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5bcfa52);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x09020b04);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xfb60f17b);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xfde70ea6);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x095df51e);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf10c0405);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 10700000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0011);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0014ffdb);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffb40023);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00b2002a);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedbff10);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x0150022d);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xff38fc6f);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36047b);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x035efbda);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9940202);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x08ee01f5);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf649f8fe);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e10bc2);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xfcb6f169);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xfcc60e42);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0a04f599);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0db03d0);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 10800000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffb000d);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x001dffed);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffaafff5);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00aa0077);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff13feb6);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x00ce026b);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x000afc85);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3503e3);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x044cfcfb);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf90c0082);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x08d5037f);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf710f7cc);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0c59);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xfe16f173);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xfbaa0dcf);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0aa5f617);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0ad039b);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 10900000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff90006);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00210003);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffc8);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x008e00b6);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff63fe7c);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x003a0275);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x00dafcda);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd510313);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x0501fe40);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8cbfefd);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x087604f0);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf80af6c2);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430cc8);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xff7af19a);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xfa940d4e);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0b3ff699);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0810365);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 11000000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8ffff);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00210018);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffa3);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x006000e1);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xffc4fe68);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xffa0024b);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x019afd66);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc990216);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x0575ff99);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8d4fd81);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x07d40640);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf932f5e6);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20d0d);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x00dff1de);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf9860cbf);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0bd1f71e);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf058032f);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 11100000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff8);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x001b0029);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1ff8a);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x002600f2);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x002cfe7c);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xff0f01f0);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x023bfe20);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc1700fa);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x05a200f7);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf927fc1c);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x06f40765);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa82f53b);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x02510d27);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0243f23d);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf8810c24);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0c5cf7a7);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf03102fa);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 11200000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff2);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00110035);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0ff81);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffe700e7);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x008ffeb6);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe94016d);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b0fefb);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3ffd1);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x05850249);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9c1fadb);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x05de0858);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfbf2f4c4);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c70d17);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x03a0f2b8);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf7870b7c);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0cdff833);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf00d02c4);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 11300000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffdffee);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00040038);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0010ff88);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffac00c2);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e2ff10);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe3900cb);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f1ffe9);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3feaa);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x05210381);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa9cf9c8);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x04990912);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfd7af484);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xff390cdb);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x04f4f34d);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf69a0ac9);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0d5af8c1);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xefec028e);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 11400000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0000ffee);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfff60033);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x002fff9f);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff7b0087);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x011eff82);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe080018);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f900d8);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fd96);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x04790490);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbadf8ed);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x032f098e);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xff10f47d);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaf0c75);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x063cf3fc);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf5ba0a0b);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0dccf952);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xefcd0258);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 11500000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0004fff1);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffea0026);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0046ffc3);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff5a003c);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x013b0000);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe04ff63);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c801b8);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fca6);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x0397056a);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfcecf853);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x01ad09c9);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x00acf4ad);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2e0be7);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0773f4c2);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4e90943);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e35f9e6);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xefb10221);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 11600000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0007fff6);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe20014);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0054ffee);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff4effeb);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x0137007e);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2efebb);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x0260027a);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fbe6);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x02870605);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfe4af7fe);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x001d09c1);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0243f515);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabd0b32);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0897f59e);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4280871);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e95fa7c);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef9701eb);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 11700000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffd);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffff);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0056001d);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff57ff9c);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x011300f0);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe82fe2e);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x01ca0310);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb62);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x0155065a);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xffbaf7f2);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe8c0977);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x03cef5b2);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf9610a58);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x09a5f68f);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3790797);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0eebfb14);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef8001b5);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 11800000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00080004);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffe9);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0047);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff75ff58);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d1014a);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfef9fdc8);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x0111036f);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb21);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x00120665);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x012df82e);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd0708ec);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0542f682);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81f095c);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a9af792);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2db06b5);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f38fbad);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef6c017e);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 11900000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0007000b);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe7ffd8);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00370068);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffa4ff28);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00790184);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xff87fd91);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x00430392);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb26);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfece0626);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0294f8b2);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb990825);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0698f77f);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fe0842);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b73f8a7);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf25105cd);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f7bfc48);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef5a0148);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 12000000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00050010);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfff2ffcc);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x001b007b);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffdfff10);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00140198);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x0020fd8e);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xff710375);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfb73);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd9a059f);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x03e0f978);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfa4e0726);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x07c8f8a7);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600070c);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c2ff9c9);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1db04de);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fb4fce5);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef4b0111);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 12100000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00010012);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffffffc8);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xfffb007e);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x001dff14);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xffad0184);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x00b7fdbe);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfea9031b);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fc01);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc8504d6);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0504fa79);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf93005f6);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x08caf9f2);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52b05c0);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0ccbfaf9);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf17903eb);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fe3fd83);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3f00db);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 12200000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffe0011);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x000cffcc);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffdb0071);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x0058ff32);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff4f014a);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x013cfe1f);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdfb028a);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fcc9);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb9d03d6);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x05f4fbad);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf848049d);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0999fb5b);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf4820461);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d46fc32);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf12d02f4);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x1007fe21);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3600a4);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 12300000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa000e);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0017ffd9);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffc10055);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x0088ff68);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff0400f0);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01a6fea7);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd7501cc);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0fdc0);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaef02a8);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x06a7fd07);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf79d0326);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a31fcda);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf40702f3);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d9ffd72);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0f601fa);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x1021fec0);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2f006d);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 12400000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80007);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x001fffeb);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffaf002d);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00a8ffb0);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed3007e);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e9ff4c);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd2000ee);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413fed8);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa82015c);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0715fe7d);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7340198);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a8dfe69);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bd017c);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dd5feb8);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0d500fd);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x1031ff60);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2b0037);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 12500000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff70000);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00220000);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffa90000);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00b30000);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec20000);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x02000000);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd030000);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x04350000);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa5e0000);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x073b0000);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7110000);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aac0000);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3a40000);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de70000);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0c90000);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x10360000);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef290000);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 12600000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff9);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x001f0015);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffafffd3);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00a80050);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed3ff82);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e900b4);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd20ff12);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130128);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa82fea4);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x07150183);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf734fe68);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a8d0197);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdfe84);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dd50148);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0d5ff03);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x103100a0);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2bffc9);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 12700000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff2);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00170027);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1ffab);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00880098);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff04ff10);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01a60159);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd75fe34);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00240);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaeffd58);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x06a702f9);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf79dfcda);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a310326);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407fd0d);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d9f028e);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0f6fe06);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x10210140);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2fff93);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 12800000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffeffef);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x000c0034);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffdbff8f);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x005800ce);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff4ffeb6);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x013c01e1);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdfbfd76);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110337);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb9dfc2a);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x05f40453);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf848fb63);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x099904a5);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482fb9f);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d4603ce);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf12dfd0c);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x100701df);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef36ff5c);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 12900000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0001ffee);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffff0038);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xfffbff82);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x001d00ec);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xffadfe7c);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x00b70242);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfea9fce5);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x024103ff);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc85fb2a);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x05040587);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf930fa0a);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x08ca060e);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bfa40);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0ccb0507);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf179fc15);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fe3027d);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3fff25);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 13000000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0005fff0);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfff20034);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x001bff85);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffdf00f0);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x0014fe68);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x00200272);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xff71fc8b);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d048d);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd9afa61);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x03e00688);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfa4ef8da);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x07c80759);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f8f4);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c2f0637);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1dbfb22);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fb4031b);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef4bfeef);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 13100000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0007fff5);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe70028);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0037ff98);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffa400d8);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x0079fe7c);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xff87026f);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x0043fc6e);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x004404da);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfecef9da);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0294074e);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb99f7db);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x06980881);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef7be);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b730759);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf251fa33);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f7b03b8);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef5afeb8);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 13200000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffc);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe00017);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x004cffb9);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff7500a8);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d1feb6);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfef90238);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x0111fc91);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3604df);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x0012f99b);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x012d07d2);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd07f714);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0542097e);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff6a4);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a9a086e);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2dbf94b);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f380453);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef6cfe82);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 13300000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00080003);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffde0001);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0056ffe3);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff570064);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x0113ff10);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe8201d2);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x01cafcf0);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35049e);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x0155f9a6);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xffba080e);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe8cf689);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x03ce0a4e);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f5a8);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x09a50971);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf379f869);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0eeb04ec);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef80fe4b);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 13400000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0007000a);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe2ffec);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00540012);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff4e0015);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x0137ff82);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2e0145);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x0260fd86);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51041a);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x0287f9fb);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfe4a0802);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x001df63f);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x02430aeb);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf4ce);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x08970a62);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf428f78f);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e950584);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xef97fe15);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 13500000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0004000f);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffeaffda);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0046003d);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff5affc4);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x013b0000);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe04009d);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c8fe48);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99035a);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x0397fa96);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfcec07ad);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x01adf637);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x00ac0b53);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef419);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x07730b3e);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4e9f6bd);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e35061a);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xefb1fddf);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 13600000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00000012);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfff6ffcd);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x002f0061);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff7bff79);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x011e007e);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe08ffe8);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f9ff28);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17026a);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x0479fb70);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbad0713);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x032ff672);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xff100b83);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff38b);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x063c0c04);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf5baf5f5);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0dcc06ae);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xefcdfda8);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 13700000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd0012);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0004ffc8);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00100078);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffacff3e);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e200f0);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe39ff35);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f10017);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd30156);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x0521fc7f);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa9c0638);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x0499f6ee);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfd7a0b7c);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f325);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x04f40cb3);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf69af537);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0d5a073f);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xefecfd72);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 13800000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0001fffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa000e);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0011ffcb);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0007f);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffe7ff19);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x008f014a);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe94fe93);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b00105);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3002f);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x0585fdb7);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9c10525);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x05def7a8);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfbf20b3c);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7f2e9);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x03a00d48);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf787f484);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0cdf07cd);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf00dfd3c);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 13900000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80008);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x001bffd7);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffd10076);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x0026ff0e);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x002c0184);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xff0ffe10);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x023b01e0);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17ff06);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x05a2ff09);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf92703e4);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x06f4f89b);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa820ac5);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251f2d9);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x02430dc3);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf881f3dc);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0c5c0859);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf031fd06);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 14000000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80001);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0021ffe8);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffba005d);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x0060ff1f);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xffc40198);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xffa0fdb5);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x019a029a);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fdea);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x05750067);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8d4027f);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x07d4f9c0);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf9320a1a);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2f2f3);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0x00df0e22);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xf986f341);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0bd108e2);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf058fcd1);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 14100000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffa);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0021fffd);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffac0038);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x008eff4a);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff630184);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x003afd8b);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x00da0326);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fced);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x050101c0);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8cb0103);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x0876fb10);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf80a093e);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543f338);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xff7a0e66);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xfa94f2b2);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0b3f0967);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf081fc9b);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 14200000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbfff3);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x001d0013);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffaa000b);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00aaff89);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff13014a);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x00cefd95);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x000a037b);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fc1d);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x044c0305);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf90cff7e);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x08d5fc81);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7100834);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x069ff3a7);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xfe160e8d);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xfbaaf231);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0aa509e9);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0adfc65);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 14300000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xffffffef);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00140025);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ffdd);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00b2ffd6);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedb00f0);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x0150fdd3);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xff380391);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb85);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x035e0426);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xf994fdfe);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x08eefe0b);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6490702);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1f43e);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xfcb60e97);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xfcc6f1be);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x0a040a67);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0dbfc30);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 14400000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0002ffee);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00070033);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ffb4);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00a40027);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec3007e);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01b4fe3f);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe760369);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb2e);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x02450518);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa5ffc90);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x08c1ffa1);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5bc05ae);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902f4fc);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xfb600e85);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xfde7f15a);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x095d0ae2);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf10cfbfb);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 14500000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0005ffef);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfffa0038);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff95);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00820074);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecc0000);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f0fed0);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdd20304);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfb1d);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x010e05ce);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb64fb41);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x084e013b);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf569043e);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a00f5dd);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xfa150e55);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0xff0bf104);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x08b00b59);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf13ffbc6);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 14600000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fff4);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffed0035);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ff83);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x005000b4);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef6ff82);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01ffff7a);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd580269);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fb53);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xffca0640);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc99fa1e);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x079a02cb);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55502ba);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad5f6e0);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf8d90e0a);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0031f0bd);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x07fd0bcb);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf174fb91);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 14700000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0009fffb);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe4002a);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ff82);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x001400e0);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff3cff10);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e10030);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd1201a4);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fbcd);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe88066a);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xfdf1f92f);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x06aa0449);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf57e0128);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7ef801);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf7b00da2);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0156f086);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x07450c39);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1acfb5c);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 14800000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00080002);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffdf0019);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x003fff92);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffd600f1);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff96feb6);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x019700e1);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd0500c2);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0fc84);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd590649);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0xff5df87f);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x058505aa);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5e4ff91);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf9f93c);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf69d0d20);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0279f05e);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x06880ca3);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1e6fb28);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 14900000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x00060009);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffdf0004);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0051ffb0);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff9d00e8);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xfffcfe7c);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x01280180);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd32ffd2);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413fd6e);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc4d05df);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x00d1f812);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x043506e4);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf685fdfb);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c43fa8d);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf5a10c83);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0399f046);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x05c70d08);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf222faf3);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 15000000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0003000f);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffe5ffef);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x0057ffd9);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff7000c4);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x0062fe68);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x009e01ff);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd95fee6);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0435fe7d);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb710530);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x023cf7ee);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x02c307ef);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf75efc70);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5cfbef);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf4c10bce);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x04b3f03f);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x05030d69);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf261fabf);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 15100000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0012);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xffefffdc);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00510006);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff540089);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00befe7c);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0x00060253);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe27fe0d);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413ffa2);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfad10446);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0390f812);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0x013b08c3);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf868faf6);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c43fd5f);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3fd0b02);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x05c7f046);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x043b0dc4);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2a1fa8b);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 15200000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0001fffe);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc0012);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0xfffbffce);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x003f0033);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff4e003f);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x0106feb6);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xff6e0276);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xfeddfd56);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b000cc);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa740329);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x04bff87f);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xffaa095d);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xf99ef995);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf9fed8);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3590a1f);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x06d2f05e);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x03700e1b);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2e4fa58);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 15300000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9000f);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0009ffc8);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00250059);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff5effee);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x0132ff10);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfee30265);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0xffaafccf);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x031101eb);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa6001e8);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x05bdf92f);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe1b09b6);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfafaf852);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0055);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2d50929);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x07d3f086);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x02a30e6c);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf329fa24);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 15400000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80009);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0015ffca);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0x00050074);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xff81ff9f);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x013dff82);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe710221);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x007cfc80);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x024102ed);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa940090);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0680fa1e);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc9b09cd);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfc73f736);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad501d0);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2740820);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x08c9f0bd);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x01d40eb9);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf371f9f1);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 15500000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80002);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x001effd5);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5007f);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xffb4ff5b);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x01280000);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2401b0);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x0146fc70);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d03c6);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb10ff32);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0701fb41);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb3709a1);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe00f644);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000345);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2350708);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x09b2f104);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x01050eff);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf3baf9be);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 15600000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffb);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0022ffe6);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9007a);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0xfff0ff29);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f2007e);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01011b);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x01f6fc9e);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440467);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbccfdde);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0738fc90);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9f70934);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0xff99f582);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x090204b0);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21a05e1);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0a8df15a);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0x00340f41);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf405f98b);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 15700000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcfff4);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x0020fffa);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffb40064);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x002fff11);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x00a400f0);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0d006e);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x0281fd09);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3604c9);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcbffca2);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0726fdfe);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8e80888);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x0134f4f3);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1060c);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf22304af);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b59f1be);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xff640f7d);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf452f959);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 15800000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0000fff0);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x001a0010);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffaa0041);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x0067ff13);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0x0043014a);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe46ffb9);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02dbfda8);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3504e5);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xfddcfb8d);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c9ff7e);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf81107a2);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c9f49a);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0753);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2500373);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c14f231);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe930fb3);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4a1f927);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 15900000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0002);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0003ffee);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x000f0023);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffac0016);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x0093ff31);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xffdc0184);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea6ff09);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fdfe70);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd5104ba);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0xff15faac);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x06270103);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7780688);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x044df479);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430883);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a00231);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cbef2b2);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc40fe3);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4f2f8f5);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+
+	case 16000000:
+		cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001);
+		cx25840_write4(client, DIF_BPF_COEFF23, 0x0006ffef);
+		cx25840_write4(client, DIF_BPF_COEFF45, 0x00020031);
+		cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffe8);
+		cx25840_write4(client, DIF_BPF_COEFF89, 0x00adff66);
+		cx25840_write4(client, DIF_BPF_COEFF1011, 0xff790198);
+		cx25840_write4(client, DIF_BPF_COEFF1213, 0xff26fe6e);
+		cx25840_write4(client, DIF_BPF_COEFF1415, 0x02e5ff55);
+		cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99044a);
+		cx25840_write4(client, DIF_BPF_COEFF1819, 0x005bfa09);
+		cx25840_write4(client, DIF_BPF_COEFF2021, 0x0545027f);
+		cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7230541);
+		cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b8f490);
+		cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20997);
+		cx25840_write4(client, DIF_BPF_COEFF2829, 0xf31300eb);
+		cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d55f341);
+		cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6100e);
+		cx25840_write4(client, DIF_BPF_COEFF3435, 0xf544f8c3);
+		cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+		break;
+	}
+}
+
+static void cx23888_std_setup(struct i2c_client *client)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+	v4l2_std_id std = state->std;
+	u32 ifHz;
+
+	cx25840_write4(client, 0x478, 0x6628021F);
+	cx25840_write4(client, 0x400, 0x0);
+	cx25840_write4(client, 0x4b4, 0x20524030);
+	cx25840_write4(client, 0x47c, 0x010a8263);
+
+	if (std & V4L2_STD_NTSC) {
+		v4l_dbg(1, cx25840_debug, client, "%s() Selecting NTSC",
+			__func__);
+
+		/* Horiz / vert timing */
+		cx25840_write4(client, 0x428, 0x1e1e601a);
+		cx25840_write4(client, 0x424, 0x5b2d007a);
+
+		/* DIF NTSC */
+		cx25840_write4(client, 0x304, 0x6503bc0c);
+		cx25840_write4(client, 0x308, 0xbd038c85);
+		cx25840_write4(client, 0x30c, 0x1db4640a);
+		cx25840_write4(client, 0x310, 0x00008800);
+		cx25840_write4(client, 0x314, 0x44400400);
+		cx25840_write4(client, 0x32c, 0x0c800800);
+		cx25840_write4(client, 0x330, 0x27000100);
+		cx25840_write4(client, 0x334, 0x1f296e1f);
+		cx25840_write4(client, 0x338, 0x009f50c1);
+		cx25840_write4(client, 0x340, 0x1befbf06);
+		cx25840_write4(client, 0x344, 0x000035e8);
+
+		/* DIF I/F */
+		ifHz = 5400000;
+
+	} else {
+		v4l_dbg(1, cx25840_debug, client, "%s() Selecting PAL-BG",
+			__func__);
+
+		/* Horiz / vert timing */
+		cx25840_write4(client, 0x428, 0x28244024);
+		cx25840_write4(client, 0x424, 0x5d2d0084);
+
+		/* DIF */
+		cx25840_write4(client, 0x304, 0x6503bc0c);
+		cx25840_write4(client, 0x308, 0xbd038c85);
+		cx25840_write4(client, 0x30c, 0x1db4640a);
+		cx25840_write4(client, 0x310, 0x00008800);
+		cx25840_write4(client, 0x314, 0x44400600);
+		cx25840_write4(client, 0x32c, 0x0c800800);
+		cx25840_write4(client, 0x330, 0x27000100);
+		cx25840_write4(client, 0x334, 0x213530ec);
+		cx25840_write4(client, 0x338, 0x00a65ba8);
+		cx25840_write4(client, 0x340, 0x1befbf06);
+		cx25840_write4(client, 0x344, 0x000035e8);
+
+		/* DIF I/F */
+		ifHz = 6000000;
+	}
+
+	cx23885_dif_setup(client, ifHz);
+
+	/* Explicitly ensure the inputs are reconfigured after
+	 * a standard change.
+	 */
+	set_input(client, state->vid_input, state->aud_input);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_ctrl_ops cx25840_ctrl_ops = {
+	.s_ctrl = cx25840_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops cx25840_core_ops = {
+	.log_status = cx25840_log_status,
+	.g_chip_ident = cx25840_g_chip_ident,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+	.s_std = cx25840_s_std,
+	.g_std = cx25840_g_std,
+	.reset = cx25840_reset,
+	.load_fw = cx25840_load_fw,
+	.s_io_pin_config = common_s_io_pin_config,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = cx25840_g_register,
+	.s_register = cx25840_s_register,
+#endif
+	.interrupt_service_routine = cx25840_irq_handler,
+};
+
+static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = {
+	.s_frequency = cx25840_s_frequency,
+	.s_radio = cx25840_s_radio,
+	.g_tuner = cx25840_g_tuner,
+	.s_tuner = cx25840_s_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops cx25840_audio_ops = {
+	.s_clock_freq = cx25840_s_clock_freq,
+	.s_routing = cx25840_s_audio_routing,
+	.s_stream = cx25840_s_audio_stream,
+};
+
+static const struct v4l2_subdev_video_ops cx25840_video_ops = {
+	.s_routing = cx25840_s_video_routing,
+	.s_mbus_fmt = cx25840_s_mbus_fmt,
+	.s_stream = cx25840_s_stream,
+	.g_input_status = cx25840_g_input_status,
+};
+
+static const struct v4l2_subdev_vbi_ops cx25840_vbi_ops = {
+	.decode_vbi_line = cx25840_decode_vbi_line,
+	.s_raw_fmt = cx25840_s_raw_fmt,
+	.s_sliced_fmt = cx25840_s_sliced_fmt,
+	.g_sliced_fmt = cx25840_g_sliced_fmt,
+};
+
+static const struct v4l2_subdev_ops cx25840_ops = {
+	.core = &cx25840_core_ops,
+	.tuner = &cx25840_tuner_ops,
+	.audio = &cx25840_audio_ops,
+	.video = &cx25840_video_ops,
+	.vbi = &cx25840_vbi_ops,
+	.ir = &cx25840_ir_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static u32 get_cx2388x_ident(struct i2c_client *client)
+{
+	u32 ret;
+
+	/* Come out of digital power down */
+	cx25840_write(client, 0x000, 0);
+
+	/* Detecting whether the part is cx23885/7/8 is more
+	 * difficult than it needs to be. No ID register. Instead we
+	 * probe certain registers indicated in the datasheets to look
+	 * for specific defaults that differ between the silicon designs. */
+
+	/* It's either 885/7 if the IR Tx Clk Divider register exists */
+	if (cx25840_read4(client, 0x204) & 0xffff) {
+		/* CX23885 returns bogus repetitive byte values for the DIF,
+		 * which doesn't exist for it. (Ex. 8a8a8a8a or 31313131) */
+		ret = cx25840_read4(client, 0x300);
+		if (((ret & 0xffff0000) >> 16) == (ret & 0xffff)) {
+			/* No DIF */
+			ret = V4L2_IDENT_CX23885_AV;
+		} else {
+			/* CX23887 has a broken DIF, but the registers
+			 * appear valid (but unused), good enough to detect. */
+			ret = V4L2_IDENT_CX23887_AV;
+		}
+	} else if (cx25840_read4(client, 0x300) & 0x0fffffff) {
+		/* DIF PLL Freq Word reg exists; chip must be a CX23888 */
+		ret = V4L2_IDENT_CX23888_AV;
+	} else {
+		v4l_err(client, "Unable to detect h/w, assuming cx23887\n");
+		ret = V4L2_IDENT_CX23887_AV;
+	}
+
+	/* Back into digital power down */
+	cx25840_write(client, 0x000, 2);
+	return ret;
+}
+
+static int cx25840_probe(struct i2c_client *client,
+			 const struct i2c_device_id *did)
+{
+	struct cx25840_state *state;
+	struct v4l2_subdev *sd;
+	int default_volume;
+	u32 id = V4L2_IDENT_NONE;
+	u16 device_id;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1);
+
+	device_id = cx25840_read(client, 0x101) << 8;
+	device_id |= cx25840_read(client, 0x100);
+	v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id);
+
+	/* The high byte of the device ID should be
+	 * 0x83 for the cx2583x and 0x84 for the cx2584x */
+	if ((device_id & 0xff00) == 0x8300) {
+		id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
+	} else if ((device_id & 0xff00) == 0x8400) {
+		id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
+	} else if (device_id == 0x0000) {
+		id = get_cx2388x_ident(client);
+	} else if ((device_id & 0xfff0) == 0x5A30) {
+		/* The CX23100 (0x5A3C = 23100) doesn't have an A/V decoder */
+		id = V4L2_IDENT_CX2310X_AV;
+	} else if ((device_id & 0xff) == (device_id >> 8)) {
+		v4l_err(client,
+			"likely a confused/unresponsive cx2388[578] A/V decoder"
+			" found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+		v4l_err(client, "A method to reset it from the cx25840 driver"
+			" software is not known at this time\n");
+		return -ENODEV;
+	} else {
+		v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
+		return -ENODEV;
+	}
+
+	state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &cx25840_ops);
+
+	switch (id) {
+	case V4L2_IDENT_CX23885_AV:
+		v4l_info(client, "cx23885 A/V decoder found @ 0x%x (%s)\n",
+			 client->addr << 1, client->adapter->name);
+		break;
+	case V4L2_IDENT_CX23887_AV:
+		v4l_info(client, "cx23887 A/V decoder found @ 0x%x (%s)\n",
+			 client->addr << 1, client->adapter->name);
+		break;
+	case V4L2_IDENT_CX23888_AV:
+		v4l_info(client, "cx23888 A/V decoder found @ 0x%x (%s)\n",
+			 client->addr << 1, client->adapter->name);
+		break;
+	case V4L2_IDENT_CX2310X_AV:
+		v4l_info(client, "cx%d A/V decoder found @ 0x%x (%s)\n",
+			 device_id, client->addr << 1, client->adapter->name);
+		break;
+	case V4L2_IDENT_CX25840:
+	case V4L2_IDENT_CX25841:
+	case V4L2_IDENT_CX25842:
+	case V4L2_IDENT_CX25843:
+		/* Note: revision '(device_id & 0x0f) == 2' was never built. The
+		   marking skips from 0x1 == 22 to 0x3 == 23. */
+		v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
+			 (device_id & 0xfff0) >> 4,
+			 (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1
+						: (device_id & 0x0f),
+			 client->addr << 1, client->adapter->name);
+		break;
+	case V4L2_IDENT_CX25836:
+	case V4L2_IDENT_CX25837:
+	default:
+		v4l_info(client, "cx25%3x-%x found @ 0x%x (%s)\n",
+			 (device_id & 0xfff0) >> 4, device_id & 0x0f,
+			 client->addr << 1, client->adapter->name);
+		break;
+	}
+
+	state->c = client;
+	state->vid_input = CX25840_COMPOSITE7;
+	state->aud_input = CX25840_AUDIO8;
+	state->audclk_freq = 48000;
+	state->audmode = V4L2_TUNER_MODE_LANG1;
+	state->vbi_line_offset = 8;
+	state->id = id;
+	state->rev = device_id;
+	v4l2_ctrl_handler_init(&state->hdl, 9);
+	v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 127, 1, 64);
+	v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 127, 1, 64);
+	v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
+			V4L2_CID_HUE, -128, 127, 1, 0);
+	if (!is_cx2583x(state)) {
+		default_volume = cx25840_read(client, 0x8d4);
+		/*
+		 * Enforce the legacy PVR-350/MSP3400 to PVR-150/CX25843 volume
+		 * scale mapping limits to avoid -ERANGE errors when
+		 * initializing the volume control
+		 */
+		if (default_volume > 228) {
+			/* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */
+			default_volume = 228;
+			cx25840_write(client, 0x8d4, 228);
+		}
+		else if (default_volume < 20) {
+			/* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */
+			default_volume = 20;
+			cx25840_write(client, 0x8d4, 20);
+		}
+		default_volume = (((228 - default_volume) >> 1) + 23) << 9;
+
+		state->volume = v4l2_ctrl_new_std(&state->hdl,
+			&cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME,
+			0, 65535, 65535 / 100, default_volume);
+		state->mute = v4l2_ctrl_new_std(&state->hdl,
+			&cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE,
+			0, 1, 1, 0);
+		v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops,
+			V4L2_CID_AUDIO_BALANCE,
+			0, 65535, 65535 / 100, 32768);
+		v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops,
+			V4L2_CID_AUDIO_BASS,
+			0, 65535, 65535 / 100, 32768);
+		v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops,
+			V4L2_CID_AUDIO_TREBLE,
+			0, 65535, 65535 / 100, 32768);
+	}
+	sd->ctrl_handler = &state->hdl;
+	if (state->hdl.error) {
+		int err = state->hdl.error;
+
+		v4l2_ctrl_handler_free(&state->hdl);
+		kfree(state);
+		return err;
+	}
+	if (!is_cx2583x(state))
+		v4l2_ctrl_cluster(2, &state->volume);
+	v4l2_ctrl_handler_setup(&state->hdl);
+
+	if (client->dev.platform_data) {
+		struct cx25840_platform_data *pdata = client->dev.platform_data;
+
+		state->pvr150_workaround = pdata->pvr150_workaround;
+	}
+
+	cx25840_ir_probe(sd);
+	return 0;
+}
+
+static int cx25840_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct cx25840_state *state = to_state(sd);
+
+	cx25840_ir_remove(sd);
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&state->hdl);
+	kfree(state);
+	return 0;
+}
+
+static const struct i2c_device_id cx25840_id[] = {
+	{ "cx25840", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, cx25840_id);
+
+static struct i2c_driver cx25840_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "cx25840",
+	},
+	.probe		= cx25840_probe,
+	.remove		= cx25840_remove,
+	.id_table	= cx25840_id,
+};
+
+module_i2c_driver(cx25840_driver);
diff --git a/drivers/media/i2c/cx25840/cx25840-core.h b/drivers/media/i2c/cx25840/cx25840-core.h
new file mode 100644
index 0000000..bd4ada2
--- /dev/null
+++ b/drivers/media/i2c/cx25840/cx25840-core.h
@@ -0,0 +1,137 @@
+/* cx25840 internal API header
+ *
+ * Copyright (C) 2003-2004 Chris Kennedy
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _CX25840_CORE_H_
+#define _CX25840_CORE_H_
+
+
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+#include <linux/i2c.h>
+
+struct cx25840_ir_state;
+
+struct cx25840_state {
+	struct i2c_client *c;
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	struct {
+		/* volume cluster */
+		struct v4l2_ctrl *volume;
+		struct v4l2_ctrl *mute;
+	};
+	int pvr150_workaround;
+	int radio;
+	v4l2_std_id std;
+	enum cx25840_video_input vid_input;
+	enum cx25840_audio_input aud_input;
+	u32 audclk_freq;
+	int audmode;
+	int vbi_line_offset;
+	u32 id;
+	u32 rev;
+	int is_initialized;
+	wait_queue_head_t fw_wait;    /* wake up when the fw load is finished */
+	struct work_struct fw_work;   /* work entry for fw load */
+	struct cx25840_ir_state *ir_state;
+};
+
+static inline struct cx25840_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct cx25840_state, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct cx25840_state, hdl)->sd;
+}
+
+static inline bool is_cx2583x(struct cx25840_state *state)
+{
+	return state->id == V4L2_IDENT_CX25836 ||
+	       state->id == V4L2_IDENT_CX25837;
+}
+
+static inline bool is_cx231xx(struct cx25840_state *state)
+{
+	return state->id == V4L2_IDENT_CX2310X_AV;
+}
+
+static inline bool is_cx2388x(struct cx25840_state *state)
+{
+	return state->id == V4L2_IDENT_CX23885_AV ||
+	       state->id == V4L2_IDENT_CX23887_AV ||
+	       state->id == V4L2_IDENT_CX23888_AV;
+}
+
+static inline bool is_cx23885(struct cx25840_state *state)
+{
+	return state->id == V4L2_IDENT_CX23885_AV;
+}
+
+static inline bool is_cx23887(struct cx25840_state *state)
+{
+	return state->id == V4L2_IDENT_CX23887_AV;
+}
+
+static inline bool is_cx23888(struct cx25840_state *state)
+{
+	return state->id == V4L2_IDENT_CX23888_AV;
+}
+
+/* ----------------------------------------------------------------------- */
+/* cx25850-core.c 							   */
+int cx25840_write(struct i2c_client *client, u16 addr, u8 value);
+int cx25840_write4(struct i2c_client *client, u16 addr, u32 value);
+u8 cx25840_read(struct i2c_client *client, u16 addr);
+u32 cx25840_read4(struct i2c_client *client, u16 addr);
+int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value);
+int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask,
+		    u32 or_value);
+void cx25840_std_setup(struct i2c_client *client);
+
+/* ----------------------------------------------------------------------- */
+/* cx25850-firmware.c                                                      */
+int cx25840_loadfw(struct i2c_client *client);
+
+/* ----------------------------------------------------------------------- */
+/* cx25850-audio.c                                                         */
+void cx25840_audio_set_path(struct i2c_client *client);
+int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
+
+extern const struct v4l2_ctrl_ops cx25840_audio_ctrl_ops;
+
+/* ----------------------------------------------------------------------- */
+/* cx25850-vbi.c                                                           */
+int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt);
+int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt);
+int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt);
+int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi);
+
+/* ----------------------------------------------------------------------- */
+/* cx25850-ir.c                                                            */
+extern const struct v4l2_subdev_ir_ops cx25840_ir_ops;
+int cx25840_ir_log_status(struct v4l2_subdev *sd);
+int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled);
+int cx25840_ir_probe(struct v4l2_subdev *sd);
+int cx25840_ir_remove(struct v4l2_subdev *sd);
+
+#endif
diff --git a/drivers/media/i2c/cx25840/cx25840-firmware.c b/drivers/media/i2c/cx25840/cx25840-firmware.c
new file mode 100644
index 0000000..b3169f9
--- /dev/null
+++ b/drivers/media/i2c/cx25840/cx25840-firmware.c
@@ -0,0 +1,175 @@
+/* cx25840 firmware functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <media/v4l2-common.h>
+#include <media/cx25840.h>
+
+#include "cx25840-core.h"
+
+/*
+ * Mike Isely <isely@pobox.com> - The FWSEND parameter controls the
+ * size of the firmware chunks sent down the I2C bus to the chip.
+ * Previously this had been set to 1024 but unfortunately some I2C
+ * implementations can't transfer data in such big gulps.
+ * Specifically, the pvrusb2 driver has a hard limit of around 60
+ * bytes, due to the encapsulation there of I2C traffic into USB
+ * messages.  So we have to significantly reduce this parameter.
+ */
+#define FWSEND 48
+
+#define FWDEV(x) &((x)->dev)
+
+static char *firmware = "";
+
+module_param(firmware, charp, 0444);
+
+MODULE_PARM_DESC(firmware, "Firmware image to load");
+
+static void start_fw_load(struct i2c_client *client)
+{
+	/* DL_ADDR_LB=0 DL_ADDR_HB=0 */
+	cx25840_write(client, 0x800, 0x00);
+	cx25840_write(client, 0x801, 0x00);
+	// DL_MAP=3 DL_AUTO_INC=0 DL_ENABLE=1
+	cx25840_write(client, 0x803, 0x0b);
+	/* AUTO_INC_DIS=1 */
+	cx25840_write(client, 0x000, 0x20);
+}
+
+static void end_fw_load(struct i2c_client *client)
+{
+	/* AUTO_INC_DIS=0 */
+	cx25840_write(client, 0x000, 0x00);
+	/* DL_ENABLE=0 */
+	cx25840_write(client, 0x803, 0x03);
+}
+
+#define CX2388x_FIRMWARE "v4l-cx23885-avcore-01.fw"
+#define CX231xx_FIRMWARE "v4l-cx231xx-avcore-01.fw"
+#define CX25840_FIRMWARE "v4l-cx25840.fw"
+
+static const char *get_fw_name(struct i2c_client *client)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+
+	if (firmware[0])
+		return firmware;
+	if (is_cx2388x(state))
+		return CX2388x_FIRMWARE;
+	if (is_cx231xx(state))
+		return CX231xx_FIRMWARE;
+	return CX25840_FIRMWARE;
+}
+
+static int check_fw_load(struct i2c_client *client, int size)
+{
+	/* DL_ADDR_HB DL_ADDR_LB */
+	int s = cx25840_read(client, 0x801) << 8;
+	s |= cx25840_read(client, 0x800);
+
+	if (size != s) {
+		v4l_err(client, "firmware %s load failed\n",
+				get_fw_name(client));
+		return -EINVAL;
+	}
+
+	v4l_info(client, "loaded %s firmware (%d bytes)\n",
+			get_fw_name(client), size);
+	return 0;
+}
+
+static int fw_write(struct i2c_client *client, const u8 *data, int size)
+{
+	if (i2c_master_send(client, data, size) < size) {
+		v4l_err(client, "firmware load i2c failure\n");
+		return -ENOSYS;
+	}
+
+	return 0;
+}
+
+int cx25840_loadfw(struct i2c_client *client)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+	const struct firmware *fw = NULL;
+	u8 buffer[FWSEND];
+	const u8 *ptr;
+	const char *fwname = get_fw_name(client);
+	int size, retval;
+	int MAX_BUF_SIZE = FWSEND;
+	u32 gpio_oe = 0, gpio_da = 0;
+
+	if (is_cx2388x(state)) {
+		/* Preserve the GPIO OE and output bits */
+		gpio_oe = cx25840_read(client, 0x160);
+		gpio_da = cx25840_read(client, 0x164);
+	}
+
+	if (is_cx231xx(state) && MAX_BUF_SIZE > 16) {
+		v4l_err(client, " Firmware download size changed to 16 bytes max length\n");
+		MAX_BUF_SIZE = 16;  /* cx231xx cannot accept more than 16 bytes at a time */
+	}
+
+	if (request_firmware(&fw, fwname, FWDEV(client)) != 0) {
+		v4l_err(client, "unable to open firmware %s\n", fwname);
+		return -EINVAL;
+	}
+
+	start_fw_load(client);
+
+	buffer[0] = 0x08;
+	buffer[1] = 0x02;
+
+	size = fw->size;
+	ptr = fw->data;
+	while (size > 0) {
+		int len = min(MAX_BUF_SIZE - 2, size);
+
+		memcpy(buffer + 2, ptr, len);
+
+		retval = fw_write(client, buffer, len + 2);
+
+		if (retval < 0) {
+			release_firmware(fw);
+			return retval;
+		}
+
+		size -= len;
+		ptr += len;
+	}
+
+	end_fw_load(client);
+
+	size = fw->size;
+	release_firmware(fw);
+
+	if (is_cx2388x(state)) {
+		/* Restore GPIO configuration after f/w load */
+		cx25840_write(client, 0x160, gpio_oe);
+		cx25840_write(client, 0x164, gpio_da);
+	}
+
+	return check_fw_load(client, size);
+}
+
+MODULE_FIRMWARE(CX2388x_FIRMWARE);
+MODULE_FIRMWARE(CX231xx_FIRMWARE);
+MODULE_FIRMWARE(CX25840_FIRMWARE);
+
diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c
new file mode 100644
index 0000000..38ce76e
--- /dev/null
+++ b/drivers/media/i2c/cx25840/cx25840-ir.c
@@ -0,0 +1,1281 @@
+/*
+ *  Driver for the Conexant CX2584x Audio/Video decoder chip and related cores
+ *
+ *  Integrated Consumer Infrared Controller
+ *
+ *  Copyright (C) 2010  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/kfifo.h>
+#include <linux/module.h>
+#include <media/cx25840.h>
+#include <media/rc-core.h>
+
+#include "cx25840-core.h"
+
+static unsigned int ir_debug;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug, "enable integrated IR debug messages");
+
+#define CX25840_IR_REG_BASE 	0x200
+
+#define CX25840_IR_CNTRL_REG	0x200
+#define CNTRL_WIN_3_3	0x00000000
+#define CNTRL_WIN_4_3	0x00000001
+#define CNTRL_WIN_3_4	0x00000002
+#define CNTRL_WIN_4_4	0x00000003
+#define CNTRL_WIN	0x00000003
+#define CNTRL_EDG_NONE	0x00000000
+#define CNTRL_EDG_FALL	0x00000004
+#define CNTRL_EDG_RISE	0x00000008
+#define CNTRL_EDG_BOTH	0x0000000C
+#define CNTRL_EDG	0x0000000C
+#define CNTRL_DMD	0x00000010
+#define CNTRL_MOD	0x00000020
+#define CNTRL_RFE	0x00000040
+#define CNTRL_TFE	0x00000080
+#define CNTRL_RXE	0x00000100
+#define CNTRL_TXE	0x00000200
+#define CNTRL_RIC	0x00000400
+#define CNTRL_TIC	0x00000800
+#define CNTRL_CPL	0x00001000
+#define CNTRL_LBM	0x00002000
+#define CNTRL_R		0x00004000
+
+#define CX25840_IR_TXCLK_REG	0x204
+#define TXCLK_TCD	0x0000FFFF
+
+#define CX25840_IR_RXCLK_REG	0x208
+#define RXCLK_RCD	0x0000FFFF
+
+#define CX25840_IR_CDUTY_REG	0x20C
+#define CDUTY_CDC	0x0000000F
+
+#define CX25840_IR_STATS_REG	0x210
+#define STATS_RTO	0x00000001
+#define STATS_ROR	0x00000002
+#define STATS_RBY	0x00000004
+#define STATS_TBY	0x00000008
+#define STATS_RSR	0x00000010
+#define STATS_TSR	0x00000020
+
+#define CX25840_IR_IRQEN_REG	0x214
+#define IRQEN_RTE	0x00000001
+#define IRQEN_ROE	0x00000002
+#define IRQEN_RSE	0x00000010
+#define IRQEN_TSE	0x00000020
+#define IRQEN_MSK	0x00000033
+
+#define CX25840_IR_FILTR_REG	0x218
+#define FILTR_LPF	0x0000FFFF
+
+#define CX25840_IR_FIFO_REG	0x23C
+#define FIFO_RXTX	0x0000FFFF
+#define FIFO_RXTX_LVL	0x00010000
+#define FIFO_RXTX_RTO	0x0001FFFF
+#define FIFO_RX_NDV	0x00020000
+#define FIFO_RX_DEPTH	8
+#define FIFO_TX_DEPTH	8
+
+#define CX25840_VIDCLK_FREQ	108000000 /* 108 MHz, BT.656 */
+#define CX25840_IR_REFCLK_FREQ	(CX25840_VIDCLK_FREQ / 2)
+
+/*
+ * We use this union internally for convenience, but callers to tx_write
+ * and rx_read will be expecting records of type struct ir_raw_event.
+ * Always ensure the size of this union is dictated by struct ir_raw_event.
+ */
+union cx25840_ir_fifo_rec {
+	u32 hw_fifo_data;
+	struct ir_raw_event ir_core_data;
+};
+
+#define CX25840_IR_RX_KFIFO_SIZE    (256 * sizeof(union cx25840_ir_fifo_rec))
+#define CX25840_IR_TX_KFIFO_SIZE    (256 * sizeof(union cx25840_ir_fifo_rec))
+
+struct cx25840_ir_state {
+	struct i2c_client *c;
+
+	struct v4l2_subdev_ir_parameters rx_params;
+	struct mutex rx_params_lock; /* protects Rx parameter settings cache */
+	atomic_t rxclk_divider;
+	atomic_t rx_invert;
+
+	struct kfifo rx_kfifo;
+	spinlock_t rx_kfifo_lock; /* protect Rx data kfifo */
+
+	struct v4l2_subdev_ir_parameters tx_params;
+	struct mutex tx_params_lock; /* protects Tx parameter settings cache */
+	atomic_t txclk_divider;
+};
+
+static inline struct cx25840_ir_state *to_ir_state(struct v4l2_subdev *sd)
+{
+	struct cx25840_state *state = to_state(sd);
+	return state ? state->ir_state : NULL;
+}
+
+
+/*
+ * Rx and Tx Clock Divider register computations
+ *
+ * Note the largest clock divider value of 0xffff corresponds to:
+ * 	(0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns
+ * which fits in 21 bits, so we'll use unsigned int for time arguments.
+ */
+static inline u16 count_to_clock_divider(unsigned int d)
+{
+	if (d > RXCLK_RCD + 1)
+		d = RXCLK_RCD;
+	else if (d < 2)
+		d = 1;
+	else
+		d--;
+	return (u16) d;
+}
+
+static inline u16 ns_to_clock_divider(unsigned int ns)
+{
+	return count_to_clock_divider(
+		DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000));
+}
+
+static inline unsigned int clock_divider_to_ns(unsigned int divider)
+{
+	/* Period of the Rx or Tx clock in ns */
+	return DIV_ROUND_CLOSEST((divider + 1) * 1000,
+				 CX25840_IR_REFCLK_FREQ / 1000000);
+}
+
+static inline u16 carrier_freq_to_clock_divider(unsigned int freq)
+{
+	return count_to_clock_divider(
+			  DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, freq * 16));
+}
+
+static inline unsigned int clock_divider_to_carrier_freq(unsigned int divider)
+{
+	return DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, (divider + 1) * 16);
+}
+
+static inline u16 freq_to_clock_divider(unsigned int freq,
+					unsigned int rollovers)
+{
+	return count_to_clock_divider(
+		   DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, freq * rollovers));
+}
+
+static inline unsigned int clock_divider_to_freq(unsigned int divider,
+						 unsigned int rollovers)
+{
+	return DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ,
+				 (divider + 1) * rollovers);
+}
+
+/*
+ * Low Pass Filter register calculations
+ *
+ * Note the largest count value of 0xffff corresponds to:
+ * 	0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns
+ * which fits in 21 bits, so we'll use unsigned int for time arguments.
+ */
+static inline u16 count_to_lpf_count(unsigned int d)
+{
+	if (d > FILTR_LPF)
+		d = FILTR_LPF;
+	else if (d < 4)
+		d = 0;
+	return (u16) d;
+}
+
+static inline u16 ns_to_lpf_count(unsigned int ns)
+{
+	return count_to_lpf_count(
+		DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000));
+}
+
+static inline unsigned int lpf_count_to_ns(unsigned int count)
+{
+	/* Duration of the Low Pass Filter rejection window in ns */
+	return DIV_ROUND_CLOSEST(count * 1000,
+				 CX25840_IR_REFCLK_FREQ / 1000000);
+}
+
+static inline unsigned int lpf_count_to_us(unsigned int count)
+{
+	/* Duration of the Low Pass Filter rejection window in us */
+	return DIV_ROUND_CLOSEST(count, CX25840_IR_REFCLK_FREQ / 1000000);
+}
+
+/*
+ * FIFO register pulse width count compuations
+ */
+static u32 clock_divider_to_resolution(u16 divider)
+{
+	/*
+	 * Resolution is the duration of 1 tick of the readable portion of
+	 * of the pulse width counter as read from the FIFO.  The two lsb's are
+	 * not readable, hence the << 2.  This function returns ns.
+	 */
+	return DIV_ROUND_CLOSEST((1 << 2)  * ((u32) divider + 1) * 1000,
+				 CX25840_IR_REFCLK_FREQ / 1000000);
+}
+
+static u64 pulse_width_count_to_ns(u16 count, u16 divider)
+{
+	u64 n;
+	u32 rem;
+
+	/*
+	 * The 2 lsb's of the pulse width timer count are not readable, hence
+	 * the (count << 2) | 0x3
+	 */
+	n = (((u64) count << 2) | 0x3) * (divider + 1) * 1000; /* millicycles */
+	rem = do_div(n, CX25840_IR_REFCLK_FREQ / 1000000);     /* / MHz => ns */
+	if (rem >= CX25840_IR_REFCLK_FREQ / 1000000 / 2)
+		n++;
+	return n;
+}
+
+#if 0
+/* Keep as we will need this for Transmit functionality */
+static u16 ns_to_pulse_width_count(u32 ns, u16 divider)
+{
+	u64 n;
+	u32 d;
+	u32 rem;
+
+	/*
+	 * The 2 lsb's of the pulse width timer count are not accessible, hence
+	 * the (1 << 2)
+	 */
+	n = ((u64) ns) * CX25840_IR_REFCLK_FREQ / 1000000; /* millicycles */
+	d = (1 << 2) * ((u32) divider + 1) * 1000; /* millicycles/count */
+	rem = do_div(n, d);
+	if (rem >= d / 2)
+		n++;
+
+	if (n > FIFO_RXTX)
+		n = FIFO_RXTX;
+	else if (n == 0)
+		n = 1;
+	return (u16) n;
+}
+
+#endif
+static unsigned int pulse_width_count_to_us(u16 count, u16 divider)
+{
+	u64 n;
+	u32 rem;
+
+	/*
+	 * The 2 lsb's of the pulse width timer count are not readable, hence
+	 * the (count << 2) | 0x3
+	 */
+	n = (((u64) count << 2) | 0x3) * (divider + 1);    /* cycles      */
+	rem = do_div(n, CX25840_IR_REFCLK_FREQ / 1000000); /* / MHz => us */
+	if (rem >= CX25840_IR_REFCLK_FREQ / 1000000 / 2)
+		n++;
+	return (unsigned int) n;
+}
+
+/*
+ * Pulse Clocks computations: Combined Pulse Width Count & Rx Clock Counts
+ *
+ * The total pulse clock count is an 18 bit pulse width timer count as the most
+ * significant part and (up to) 16 bit clock divider count as a modulus.
+ * When the Rx clock divider ticks down to 0, it increments the 18 bit pulse
+ * width timer count's least significant bit.
+ */
+static u64 ns_to_pulse_clocks(u32 ns)
+{
+	u64 clocks;
+	u32 rem;
+	clocks = CX25840_IR_REFCLK_FREQ / 1000000 * (u64) ns; /* millicycles  */
+	rem = do_div(clocks, 1000);                         /* /1000 = cycles */
+	if (rem >= 1000 / 2)
+		clocks++;
+	return clocks;
+}
+
+static u16 pulse_clocks_to_clock_divider(u64 count)
+{
+	do_div(count, (FIFO_RXTX << 2) | 0x3);
+
+	/* net result needs to be rounded down and decremented by 1 */
+	if (count > RXCLK_RCD + 1)
+		count = RXCLK_RCD;
+	else if (count < 2)
+		count = 1;
+	else
+		count--;
+	return (u16) count;
+}
+
+/*
+ * IR Control Register helpers
+ */
+enum tx_fifo_watermark {
+	TX_FIFO_HALF_EMPTY = 0,
+	TX_FIFO_EMPTY      = CNTRL_TIC,
+};
+
+enum rx_fifo_watermark {
+	RX_FIFO_HALF_FULL = 0,
+	RX_FIFO_NOT_EMPTY = CNTRL_RIC,
+};
+
+static inline void control_tx_irq_watermark(struct i2c_client *c,
+					    enum tx_fifo_watermark level)
+{
+	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_TIC, level);
+}
+
+static inline void control_rx_irq_watermark(struct i2c_client *c,
+					    enum rx_fifo_watermark level)
+{
+	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_RIC, level);
+}
+
+static inline void control_tx_enable(struct i2c_client *c, bool enable)
+{
+	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~(CNTRL_TXE | CNTRL_TFE),
+			enable ? (CNTRL_TXE | CNTRL_TFE) : 0);
+}
+
+static inline void control_rx_enable(struct i2c_client *c, bool enable)
+{
+	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~(CNTRL_RXE | CNTRL_RFE),
+			enable ? (CNTRL_RXE | CNTRL_RFE) : 0);
+}
+
+static inline void control_tx_modulation_enable(struct i2c_client *c,
+						bool enable)
+{
+	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_MOD,
+			enable ? CNTRL_MOD : 0);
+}
+
+static inline void control_rx_demodulation_enable(struct i2c_client *c,
+						  bool enable)
+{
+	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_DMD,
+			enable ? CNTRL_DMD : 0);
+}
+
+static inline void control_rx_s_edge_detection(struct i2c_client *c,
+					       u32 edge_types)
+{
+	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_EDG_BOTH,
+			edge_types & CNTRL_EDG_BOTH);
+}
+
+static void control_rx_s_carrier_window(struct i2c_client *c,
+					unsigned int carrier,
+					unsigned int *carrier_range_low,
+					unsigned int *carrier_range_high)
+{
+	u32 v;
+	unsigned int c16 = carrier * 16;
+
+	if (*carrier_range_low < DIV_ROUND_CLOSEST(c16, 16 + 3)) {
+		v = CNTRL_WIN_3_4;
+		*carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 4);
+	} else {
+		v = CNTRL_WIN_3_3;
+		*carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 3);
+	}
+
+	if (*carrier_range_high > DIV_ROUND_CLOSEST(c16, 16 - 3)) {
+		v |= CNTRL_WIN_4_3;
+		*carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 4);
+	} else {
+		v |= CNTRL_WIN_3_3;
+		*carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 3);
+	}
+	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_WIN, v);
+}
+
+static inline void control_tx_polarity_invert(struct i2c_client *c,
+					      bool invert)
+{
+	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_CPL,
+			invert ? CNTRL_CPL : 0);
+}
+
+/*
+ * IR Rx & Tx Clock Register helpers
+ */
+static unsigned int txclk_tx_s_carrier(struct i2c_client *c,
+				       unsigned int freq,
+				       u16 *divider)
+{
+	*divider = carrier_freq_to_clock_divider(freq);
+	cx25840_write4(c, CX25840_IR_TXCLK_REG, *divider);
+	return clock_divider_to_carrier_freq(*divider);
+}
+
+static unsigned int rxclk_rx_s_carrier(struct i2c_client *c,
+				       unsigned int freq,
+				       u16 *divider)
+{
+	*divider = carrier_freq_to_clock_divider(freq);
+	cx25840_write4(c, CX25840_IR_RXCLK_REG, *divider);
+	return clock_divider_to_carrier_freq(*divider);
+}
+
+static u32 txclk_tx_s_max_pulse_width(struct i2c_client *c, u32 ns,
+				      u16 *divider)
+{
+	u64 pulse_clocks;
+
+	if (ns > IR_MAX_DURATION)
+		ns = IR_MAX_DURATION;
+	pulse_clocks = ns_to_pulse_clocks(ns);
+	*divider = pulse_clocks_to_clock_divider(pulse_clocks);
+	cx25840_write4(c, CX25840_IR_TXCLK_REG, *divider);
+	return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider);
+}
+
+static u32 rxclk_rx_s_max_pulse_width(struct i2c_client *c, u32 ns,
+				      u16 *divider)
+{
+	u64 pulse_clocks;
+
+	if (ns > IR_MAX_DURATION)
+		ns = IR_MAX_DURATION;
+	pulse_clocks = ns_to_pulse_clocks(ns);
+	*divider = pulse_clocks_to_clock_divider(pulse_clocks);
+	cx25840_write4(c, CX25840_IR_RXCLK_REG, *divider);
+	return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider);
+}
+
+/*
+ * IR Tx Carrier Duty Cycle register helpers
+ */
+static unsigned int cduty_tx_s_duty_cycle(struct i2c_client *c,
+					  unsigned int duty_cycle)
+{
+	u32 n;
+	n = DIV_ROUND_CLOSEST(duty_cycle * 100, 625); /* 16ths of 100% */
+	if (n != 0)
+		n--;
+	if (n > 15)
+		n = 15;
+	cx25840_write4(c, CX25840_IR_CDUTY_REG, n);
+	return DIV_ROUND_CLOSEST((n + 1) * 100, 16);
+}
+
+/*
+ * IR Filter Register helpers
+ */
+static u32 filter_rx_s_min_width(struct i2c_client *c, u32 min_width_ns)
+{
+	u32 count = ns_to_lpf_count(min_width_ns);
+	cx25840_write4(c, CX25840_IR_FILTR_REG, count);
+	return lpf_count_to_ns(count);
+}
+
+/*
+ * IR IRQ Enable Register helpers
+ */
+static inline void irqenable_rx(struct v4l2_subdev *sd, u32 mask)
+{
+	struct cx25840_state *state = to_state(sd);
+
+	if (is_cx23885(state) || is_cx23887(state))
+		mask ^= IRQEN_MSK;
+	mask &= (IRQEN_RTE | IRQEN_ROE | IRQEN_RSE);
+	cx25840_and_or4(state->c, CX25840_IR_IRQEN_REG,
+			~(IRQEN_RTE | IRQEN_ROE | IRQEN_RSE), mask);
+}
+
+static inline void irqenable_tx(struct v4l2_subdev *sd, u32 mask)
+{
+	struct cx25840_state *state = to_state(sd);
+
+	if (is_cx23885(state) || is_cx23887(state))
+		mask ^= IRQEN_MSK;
+	mask &= IRQEN_TSE;
+	cx25840_and_or4(state->c, CX25840_IR_IRQEN_REG, ~IRQEN_TSE, mask);
+}
+
+/*
+ * V4L2 Subdevice IR Ops
+ */
+int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled)
+{
+	struct cx25840_state *state = to_state(sd);
+	struct cx25840_ir_state *ir_state = to_ir_state(sd);
+	struct i2c_client *c = NULL;
+	unsigned long flags;
+
+	union cx25840_ir_fifo_rec rx_data[FIFO_RX_DEPTH];
+	unsigned int i, j, k;
+	u32 events, v;
+	int tsr, rsr, rto, ror, tse, rse, rte, roe, kror;
+	u32 cntrl, irqen, stats;
+
+	*handled = false;
+	if (ir_state == NULL)
+		return -ENODEV;
+
+	c = ir_state->c;
+
+	/* Only support the IR controller for the CX2388[57] AV Core for now */
+	if (!(is_cx23885(state) || is_cx23887(state)))
+		return -ENODEV;
+
+	cntrl = cx25840_read4(c, CX25840_IR_CNTRL_REG);
+	irqen = cx25840_read4(c, CX25840_IR_IRQEN_REG);
+	if (is_cx23885(state) || is_cx23887(state))
+		irqen ^= IRQEN_MSK;
+	stats = cx25840_read4(c, CX25840_IR_STATS_REG);
+
+	tsr = stats & STATS_TSR; /* Tx FIFO Service Request */
+	rsr = stats & STATS_RSR; /* Rx FIFO Service Request */
+	rto = stats & STATS_RTO; /* Rx Pulse Width Timer Time Out */
+	ror = stats & STATS_ROR; /* Rx FIFO Over Run */
+
+	tse = irqen & IRQEN_TSE; /* Tx FIFO Service Request IRQ Enable */
+	rse = irqen & IRQEN_RSE; /* Rx FIFO Service Reuqest IRQ Enable */
+	rte = irqen & IRQEN_RTE; /* Rx Pulse Width Timer Time Out IRQ Enable */
+	roe = irqen & IRQEN_ROE; /* Rx FIFO Over Run IRQ Enable */
+
+	v4l2_dbg(2, ir_debug, sd, "IR IRQ Status:  %s %s %s %s %s %s\n",
+		 tsr ? "tsr" : "   ", rsr ? "rsr" : "   ",
+		 rto ? "rto" : "   ", ror ? "ror" : "   ",
+		 stats & STATS_TBY ? "tby" : "   ",
+		 stats & STATS_RBY ? "rby" : "   ");
+
+	v4l2_dbg(2, ir_debug, sd, "IR IRQ Enables: %s %s %s %s\n",
+		 tse ? "tse" : "   ", rse ? "rse" : "   ",
+		 rte ? "rte" : "   ", roe ? "roe" : "   ");
+
+	/*
+	 * Transmitter interrupt service
+	 */
+	if (tse && tsr) {
+		/*
+		 * TODO:
+		 * Check the watermark threshold setting
+		 * Pull FIFO_TX_DEPTH or FIFO_TX_DEPTH/2 entries from tx_kfifo
+		 * Push the data to the hardware FIFO.
+		 * If there was nothing more to send in the tx_kfifo, disable
+		 *	the TSR IRQ and notify the v4l2_device.
+		 * If there was something in the tx_kfifo, check the tx_kfifo
+		 *      level and notify the v4l2_device, if it is low.
+		 */
+		/* For now, inhibit TSR interrupt until Tx is implemented */
+		irqenable_tx(sd, 0);
+		events = V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ;
+		v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_TX_NOTIFY, &events);
+		*handled = true;
+	}
+
+	/*
+	 * Receiver interrupt service
+	 */
+	kror = 0;
+	if ((rse && rsr) || (rte && rto)) {
+		/*
+		 * Receive data on RSR to clear the STATS_RSR.
+		 * Receive data on RTO, since we may not have yet hit the RSR
+		 * watermark when we receive the RTO.
+		 */
+		for (i = 0, v = FIFO_RX_NDV;
+		     (v & FIFO_RX_NDV) && !kror; i = 0) {
+			for (j = 0;
+			     (v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) {
+				v = cx25840_read4(c, CX25840_IR_FIFO_REG);
+				rx_data[i].hw_fifo_data = v & ~FIFO_RX_NDV;
+				i++;
+			}
+			if (i == 0)
+				break;
+			j = i * sizeof(union cx25840_ir_fifo_rec);
+			k = kfifo_in_locked(&ir_state->rx_kfifo,
+					    (unsigned char *) rx_data, j,
+					    &ir_state->rx_kfifo_lock);
+			if (k != j)
+				kror++; /* rx_kfifo over run */
+		}
+		*handled = true;
+	}
+
+	events = 0;
+	v = 0;
+	if (kror) {
+		events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN;
+		v4l2_err(sd, "IR receiver software FIFO overrun\n");
+	}
+	if (roe && ror) {
+		/*
+		 * The RX FIFO Enable (CNTRL_RFE) must be toggled to clear
+		 * the Rx FIFO Over Run status (STATS_ROR)
+		 */
+		v |= CNTRL_RFE;
+		events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN;
+		v4l2_err(sd, "IR receiver hardware FIFO overrun\n");
+	}
+	if (rte && rto) {
+		/*
+		 * The IR Receiver Enable (CNTRL_RXE) must be toggled to clear
+		 * the Rx Pulse Width Timer Time Out (STATS_RTO)
+		 */
+		v |= CNTRL_RXE;
+		events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED;
+	}
+	if (v) {
+		/* Clear STATS_ROR & STATS_RTO as needed by reseting hardware */
+		cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl & ~v);
+		cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl);
+		*handled = true;
+	}
+	spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags);
+	if (kfifo_len(&ir_state->rx_kfifo) >= CX25840_IR_RX_KFIFO_SIZE / 2)
+		events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ;
+	spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags);
+
+	if (events)
+		v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events);
+	return 0;
+}
+
+/* Receiver */
+static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
+			      ssize_t *num)
+{
+	struct cx25840_ir_state *ir_state = to_ir_state(sd);
+	bool invert;
+	u16 divider;
+	unsigned int i, n;
+	union cx25840_ir_fifo_rec *p;
+	unsigned u, v, w;
+
+	if (ir_state == NULL)
+		return -ENODEV;
+
+	invert = (bool) atomic_read(&ir_state->rx_invert);
+	divider = (u16) atomic_read(&ir_state->rxclk_divider);
+
+	n = count / sizeof(union cx25840_ir_fifo_rec)
+		* sizeof(union cx25840_ir_fifo_rec);
+	if (n == 0) {
+		*num = 0;
+		return 0;
+	}
+
+	n = kfifo_out_locked(&ir_state->rx_kfifo, buf, n,
+			     &ir_state->rx_kfifo_lock);
+
+	n /= sizeof(union cx25840_ir_fifo_rec);
+	*num = n * sizeof(union cx25840_ir_fifo_rec);
+
+	for (p = (union cx25840_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) {
+
+		if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
+			/* Assume RTO was because of no IR light input */
+			u = 0;
+			w = 1;
+		} else {
+			u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
+			if (invert)
+				u = u ? 0 : 1;
+			w = 0;
+		}
+
+		v = (unsigned) pulse_width_count_to_ns(
+				  (u16) (p->hw_fifo_data & FIFO_RXTX), divider);
+		if (v > IR_MAX_DURATION)
+			v = IR_MAX_DURATION;
+
+		init_ir_raw_event(&p->ir_core_data);
+		p->ir_core_data.pulse = u;
+		p->ir_core_data.duration = v;
+		p->ir_core_data.timeout = w;
+
+		v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns  %s  %s\n",
+			 v, u ? "mark" : "space", w ? "(timed out)" : "");
+		if (w)
+			v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n");
+	}
+	return 0;
+}
+
+static int cx25840_ir_rx_g_parameters(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_ir_parameters *p)
+{
+	struct cx25840_ir_state *ir_state = to_ir_state(sd);
+
+	if (ir_state == NULL)
+		return -ENODEV;
+
+	mutex_lock(&ir_state->rx_params_lock);
+	memcpy(p, &ir_state->rx_params,
+				      sizeof(struct v4l2_subdev_ir_parameters));
+	mutex_unlock(&ir_state->rx_params_lock);
+	return 0;
+}
+
+static int cx25840_ir_rx_shutdown(struct v4l2_subdev *sd)
+{
+	struct cx25840_ir_state *ir_state = to_ir_state(sd);
+	struct i2c_client *c;
+
+	if (ir_state == NULL)
+		return -ENODEV;
+
+	c = ir_state->c;
+	mutex_lock(&ir_state->rx_params_lock);
+
+	/* Disable or slow down all IR Rx circuits and counters */
+	irqenable_rx(sd, 0);
+	control_rx_enable(c, false);
+	control_rx_demodulation_enable(c, false);
+	control_rx_s_edge_detection(c, CNTRL_EDG_NONE);
+	filter_rx_s_min_width(c, 0);
+	cx25840_write4(c, CX25840_IR_RXCLK_REG, RXCLK_RCD);
+
+	ir_state->rx_params.shutdown = true;
+
+	mutex_unlock(&ir_state->rx_params_lock);
+	return 0;
+}
+
+static int cx25840_ir_rx_s_parameters(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_ir_parameters *p)
+{
+	struct cx25840_ir_state *ir_state = to_ir_state(sd);
+	struct i2c_client *c;
+	struct v4l2_subdev_ir_parameters *o;
+	u16 rxclk_divider;
+
+	if (ir_state == NULL)
+		return -ENODEV;
+
+	if (p->shutdown)
+		return cx25840_ir_rx_shutdown(sd);
+
+	if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH)
+		return -ENOSYS;
+
+	c = ir_state->c;
+	o = &ir_state->rx_params;
+
+	mutex_lock(&ir_state->rx_params_lock);
+
+	o->shutdown = p->shutdown;
+
+	p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
+	o->mode = p->mode;
+
+	p->bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec);
+	o->bytes_per_data_element = p->bytes_per_data_element;
+
+	/* Before we tweak the hardware, we have to disable the receiver */
+	irqenable_rx(sd, 0);
+	control_rx_enable(c, false);
+
+	control_rx_demodulation_enable(c, p->modulation);
+	o->modulation = p->modulation;
+
+	if (p->modulation) {
+		p->carrier_freq = rxclk_rx_s_carrier(c, p->carrier_freq,
+						     &rxclk_divider);
+
+		o->carrier_freq = p->carrier_freq;
+
+		p->duty_cycle = 50;
+		o->duty_cycle = p->duty_cycle;
+
+		control_rx_s_carrier_window(c, p->carrier_freq,
+					    &p->carrier_range_lower,
+					    &p->carrier_range_upper);
+		o->carrier_range_lower = p->carrier_range_lower;
+		o->carrier_range_upper = p->carrier_range_upper;
+
+		p->max_pulse_width =
+			(u32) pulse_width_count_to_ns(FIFO_RXTX, rxclk_divider);
+	} else {
+		p->max_pulse_width =
+			    rxclk_rx_s_max_pulse_width(c, p->max_pulse_width,
+						       &rxclk_divider);
+	}
+	o->max_pulse_width = p->max_pulse_width;
+	atomic_set(&ir_state->rxclk_divider, rxclk_divider);
+
+	p->noise_filter_min_width =
+			    filter_rx_s_min_width(c, p->noise_filter_min_width);
+	o->noise_filter_min_width = p->noise_filter_min_width;
+
+	p->resolution = clock_divider_to_resolution(rxclk_divider);
+	o->resolution = p->resolution;
+
+	/* FIXME - make this dependent on resolution for better performance */
+	control_rx_irq_watermark(c, RX_FIFO_HALF_FULL);
+
+	control_rx_s_edge_detection(c, CNTRL_EDG_BOTH);
+
+	o->invert_level = p->invert_level;
+	atomic_set(&ir_state->rx_invert, p->invert_level);
+
+	o->interrupt_enable = p->interrupt_enable;
+	o->enable = p->enable;
+	if (p->enable) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags);
+		kfifo_reset(&ir_state->rx_kfifo);
+		spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags);
+		if (p->interrupt_enable)
+			irqenable_rx(sd, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE);
+		control_rx_enable(c, p->enable);
+	}
+
+	mutex_unlock(&ir_state->rx_params_lock);
+	return 0;
+}
+
+/* Transmitter */
+static int cx25840_ir_tx_write(struct v4l2_subdev *sd, u8 *buf, size_t count,
+			       ssize_t *num)
+{
+	struct cx25840_ir_state *ir_state = to_ir_state(sd);
+
+	if (ir_state == NULL)
+		return -ENODEV;
+
+#if 0
+	/*
+	 * FIXME - the code below is an incomplete and untested sketch of what
+	 * may need to be done.  The critical part is to get 4 (or 8) pulses
+	 * from the tx_kfifo, or converted from ns to the proper units from the
+	 * input, and push them off to the hardware Tx FIFO right away, if the
+	 * HW TX fifo needs service.  The rest can be pushed to the tx_kfifo in
+	 * a less critical timeframe.  Also watch out for overruning the
+	 * tx_kfifo - don't let it happen and let the caller know not all his
+	 * pulses were written.
+	 */
+	u32 *ns_pulse = (u32 *) buf;
+	unsigned int n;
+	u32 fifo_pulse[FIFO_TX_DEPTH];
+	u32 mark;
+
+	/* Compute how much we can fit in the tx kfifo */
+	n = CX25840_IR_TX_KFIFO_SIZE - kfifo_len(ir_state->tx_kfifo);
+	n = min(n, (unsigned int) count);
+	n /= sizeof(u32);
+
+	/* FIXME - turn on Tx Fifo service interrupt
+	 * check hardware fifo level, and other stuff
+	 */
+	for (i = 0; i < n; ) {
+		for (j = 0; j < FIFO_TX_DEPTH / 2 && i < n; j++) {
+			mark = ns_pulse[i] & LEVEL_MASK;
+			fifo_pulse[j] = ns_to_pulse_width_count(
+					 ns_pulse[i] &
+					       ~LEVEL_MASK,
+					 ir_state->txclk_divider);
+			if (mark)
+				fifo_pulse[j] &= FIFO_RXTX_LVL;
+			i++;
+		}
+		kfifo_put(ir_state->tx_kfifo, (u8 *) fifo_pulse,
+							       j * sizeof(u32));
+	}
+	*num = n * sizeof(u32);
+#else
+	/* For now enable the Tx FIFO Service interrupt & pretend we did work */
+	irqenable_tx(sd, IRQEN_TSE);
+	*num = count;
+#endif
+	return 0;
+}
+
+static int cx25840_ir_tx_g_parameters(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_ir_parameters *p)
+{
+	struct cx25840_ir_state *ir_state = to_ir_state(sd);
+
+	if (ir_state == NULL)
+		return -ENODEV;
+
+	mutex_lock(&ir_state->tx_params_lock);
+	memcpy(p, &ir_state->tx_params,
+				      sizeof(struct v4l2_subdev_ir_parameters));
+	mutex_unlock(&ir_state->tx_params_lock);
+	return 0;
+}
+
+static int cx25840_ir_tx_shutdown(struct v4l2_subdev *sd)
+{
+	struct cx25840_ir_state *ir_state = to_ir_state(sd);
+	struct i2c_client *c;
+
+	if (ir_state == NULL)
+		return -ENODEV;
+
+	c = ir_state->c;
+	mutex_lock(&ir_state->tx_params_lock);
+
+	/* Disable or slow down all IR Tx circuits and counters */
+	irqenable_tx(sd, 0);
+	control_tx_enable(c, false);
+	control_tx_modulation_enable(c, false);
+	cx25840_write4(c, CX25840_IR_TXCLK_REG, TXCLK_TCD);
+
+	ir_state->tx_params.shutdown = true;
+
+	mutex_unlock(&ir_state->tx_params_lock);
+	return 0;
+}
+
+static int cx25840_ir_tx_s_parameters(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_ir_parameters *p)
+{
+	struct cx25840_ir_state *ir_state = to_ir_state(sd);
+	struct i2c_client *c;
+	struct v4l2_subdev_ir_parameters *o;
+	u16 txclk_divider;
+
+	if (ir_state == NULL)
+		return -ENODEV;
+
+	if (p->shutdown)
+		return cx25840_ir_tx_shutdown(sd);
+
+	if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH)
+		return -ENOSYS;
+
+	c = ir_state->c;
+	o = &ir_state->tx_params;
+	mutex_lock(&ir_state->tx_params_lock);
+
+	o->shutdown = p->shutdown;
+
+	p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
+	o->mode = p->mode;
+
+	p->bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec);
+	o->bytes_per_data_element = p->bytes_per_data_element;
+
+	/* Before we tweak the hardware, we have to disable the transmitter */
+	irqenable_tx(sd, 0);
+	control_tx_enable(c, false);
+
+	control_tx_modulation_enable(c, p->modulation);
+	o->modulation = p->modulation;
+
+	if (p->modulation) {
+		p->carrier_freq = txclk_tx_s_carrier(c, p->carrier_freq,
+						     &txclk_divider);
+		o->carrier_freq = p->carrier_freq;
+
+		p->duty_cycle = cduty_tx_s_duty_cycle(c, p->duty_cycle);
+		o->duty_cycle = p->duty_cycle;
+
+		p->max_pulse_width =
+			(u32) pulse_width_count_to_ns(FIFO_RXTX, txclk_divider);
+	} else {
+		p->max_pulse_width =
+			    txclk_tx_s_max_pulse_width(c, p->max_pulse_width,
+						       &txclk_divider);
+	}
+	o->max_pulse_width = p->max_pulse_width;
+	atomic_set(&ir_state->txclk_divider, txclk_divider);
+
+	p->resolution = clock_divider_to_resolution(txclk_divider);
+	o->resolution = p->resolution;
+
+	/* FIXME - make this dependent on resolution for better performance */
+	control_tx_irq_watermark(c, TX_FIFO_HALF_EMPTY);
+
+	control_tx_polarity_invert(c, p->invert_carrier_sense);
+	o->invert_carrier_sense = p->invert_carrier_sense;
+
+	/*
+	 * FIXME: we don't have hardware help for IO pin level inversion
+	 * here like we have on the CX23888.
+	 * Act on this with some mix of logical inversion of data levels,
+	 * carrier polarity, and carrier duty cycle.
+	 */
+	o->invert_level = p->invert_level;
+
+	o->interrupt_enable = p->interrupt_enable;
+	o->enable = p->enable;
+	if (p->enable) {
+		/* reset tx_fifo here */
+		if (p->interrupt_enable)
+			irqenable_tx(sd, IRQEN_TSE);
+		control_tx_enable(c, p->enable);
+	}
+
+	mutex_unlock(&ir_state->tx_params_lock);
+	return 0;
+}
+
+
+/*
+ * V4L2 Subdevice Core Ops support
+ */
+int cx25840_ir_log_status(struct v4l2_subdev *sd)
+{
+	struct cx25840_state *state = to_state(sd);
+	struct i2c_client *c = state->c;
+	char *s;
+	int i, j;
+	u32 cntrl, txclk, rxclk, cduty, stats, irqen, filtr;
+
+	/* The CX23888 chip doesn't have an IR controller on the A/V core */
+	if (is_cx23888(state))
+		return 0;
+
+	cntrl = cx25840_read4(c, CX25840_IR_CNTRL_REG);
+	txclk = cx25840_read4(c, CX25840_IR_TXCLK_REG) & TXCLK_TCD;
+	rxclk = cx25840_read4(c, CX25840_IR_RXCLK_REG) & RXCLK_RCD;
+	cduty = cx25840_read4(c, CX25840_IR_CDUTY_REG) & CDUTY_CDC;
+	stats = cx25840_read4(c, CX25840_IR_STATS_REG);
+	irqen = cx25840_read4(c, CX25840_IR_IRQEN_REG);
+	if (is_cx23885(state) || is_cx23887(state))
+		irqen ^= IRQEN_MSK;
+	filtr = cx25840_read4(c, CX25840_IR_FILTR_REG) & FILTR_LPF;
+
+	v4l2_info(sd, "IR Receiver:\n");
+	v4l2_info(sd, "\tEnabled:                           %s\n",
+		  cntrl & CNTRL_RXE ? "yes" : "no");
+	v4l2_info(sd, "\tDemodulation from a carrier:       %s\n",
+		  cntrl & CNTRL_DMD ? "enabled" : "disabled");
+	v4l2_info(sd, "\tFIFO:                              %s\n",
+		  cntrl & CNTRL_RFE ? "enabled" : "disabled");
+	switch (cntrl & CNTRL_EDG) {
+	case CNTRL_EDG_NONE:
+		s = "disabled";
+		break;
+	case CNTRL_EDG_FALL:
+		s = "falling edge";
+		break;
+	case CNTRL_EDG_RISE:
+		s = "rising edge";
+		break;
+	case CNTRL_EDG_BOTH:
+		s = "rising & falling edges";
+		break;
+	default:
+		s = "??? edge";
+		break;
+	}
+	v4l2_info(sd, "\tPulse timers' start/stop trigger:  %s\n", s);
+	v4l2_info(sd, "\tFIFO data on pulse timer overflow: %s\n",
+		  cntrl & CNTRL_R ? "not loaded" : "overflow marker");
+	v4l2_info(sd, "\tFIFO interrupt watermark:          %s\n",
+		  cntrl & CNTRL_RIC ? "not empty" : "half full or greater");
+	v4l2_info(sd, "\tLoopback mode:                     %s\n",
+		  cntrl & CNTRL_LBM ? "loopback active" : "normal receive");
+	if (cntrl & CNTRL_DMD) {
+		v4l2_info(sd, "\tExpected carrier (16 clocks):      %u Hz\n",
+			  clock_divider_to_carrier_freq(rxclk));
+		switch (cntrl & CNTRL_WIN) {
+		case CNTRL_WIN_3_3:
+			i = 3;
+			j = 3;
+			break;
+		case CNTRL_WIN_4_3:
+			i = 4;
+			j = 3;
+			break;
+		case CNTRL_WIN_3_4:
+			i = 3;
+			j = 4;
+			break;
+		case CNTRL_WIN_4_4:
+			i = 4;
+			j = 4;
+			break;
+		default:
+			i = 0;
+			j = 0;
+			break;
+		}
+		v4l2_info(sd, "\tNext carrier edge window:          16 clocks "
+			  "-%1d/+%1d, %u to %u Hz\n", i, j,
+			  clock_divider_to_freq(rxclk, 16 + j),
+			  clock_divider_to_freq(rxclk, 16 - i));
+	}
+	v4l2_info(sd, "\tMax measurable pulse width:        %u us, %llu ns\n",
+		  pulse_width_count_to_us(FIFO_RXTX, rxclk),
+		  pulse_width_count_to_ns(FIFO_RXTX, rxclk));
+	v4l2_info(sd, "\tLow pass filter:                   %s\n",
+		  filtr ? "enabled" : "disabled");
+	if (filtr)
+		v4l2_info(sd, "\tMin acceptable pulse width (LPF):  %u us, "
+			  "%u ns\n",
+			  lpf_count_to_us(filtr),
+			  lpf_count_to_ns(filtr));
+	v4l2_info(sd, "\tPulse width timer timed-out:       %s\n",
+		  stats & STATS_RTO ? "yes" : "no");
+	v4l2_info(sd, "\tPulse width timer time-out intr:   %s\n",
+		  irqen & IRQEN_RTE ? "enabled" : "disabled");
+	v4l2_info(sd, "\tFIFO overrun:                      %s\n",
+		  stats & STATS_ROR ? "yes" : "no");
+	v4l2_info(sd, "\tFIFO overrun interrupt:            %s\n",
+		  irqen & IRQEN_ROE ? "enabled" : "disabled");
+	v4l2_info(sd, "\tBusy:                              %s\n",
+		  stats & STATS_RBY ? "yes" : "no");
+	v4l2_info(sd, "\tFIFO service requested:            %s\n",
+		  stats & STATS_RSR ? "yes" : "no");
+	v4l2_info(sd, "\tFIFO service request interrupt:    %s\n",
+		  irqen & IRQEN_RSE ? "enabled" : "disabled");
+
+	v4l2_info(sd, "IR Transmitter:\n");
+	v4l2_info(sd, "\tEnabled:                           %s\n",
+		  cntrl & CNTRL_TXE ? "yes" : "no");
+	v4l2_info(sd, "\tModulation onto a carrier:         %s\n",
+		  cntrl & CNTRL_MOD ? "enabled" : "disabled");
+	v4l2_info(sd, "\tFIFO:                              %s\n",
+		  cntrl & CNTRL_TFE ? "enabled" : "disabled");
+	v4l2_info(sd, "\tFIFO interrupt watermark:          %s\n",
+		  cntrl & CNTRL_TIC ? "not empty" : "half full or less");
+	v4l2_info(sd, "\tCarrier polarity:                  %s\n",
+		  cntrl & CNTRL_CPL ? "space:burst mark:noburst"
+				    : "space:noburst mark:burst");
+	if (cntrl & CNTRL_MOD) {
+		v4l2_info(sd, "\tCarrier (16 clocks):               %u Hz\n",
+			  clock_divider_to_carrier_freq(txclk));
+		v4l2_info(sd, "\tCarrier duty cycle:                %2u/16\n",
+			  cduty + 1);
+	}
+	v4l2_info(sd, "\tMax pulse width:                   %u us, %llu ns\n",
+		  pulse_width_count_to_us(FIFO_RXTX, txclk),
+		  pulse_width_count_to_ns(FIFO_RXTX, txclk));
+	v4l2_info(sd, "\tBusy:                              %s\n",
+		  stats & STATS_TBY ? "yes" : "no");
+	v4l2_info(sd, "\tFIFO service requested:            %s\n",
+		  stats & STATS_TSR ? "yes" : "no");
+	v4l2_info(sd, "\tFIFO service request interrupt:    %s\n",
+		  irqen & IRQEN_TSE ? "enabled" : "disabled");
+
+	return 0;
+}
+
+
+const struct v4l2_subdev_ir_ops cx25840_ir_ops = {
+	.rx_read = cx25840_ir_rx_read,
+	.rx_g_parameters = cx25840_ir_rx_g_parameters,
+	.rx_s_parameters = cx25840_ir_rx_s_parameters,
+
+	.tx_write = cx25840_ir_tx_write,
+	.tx_g_parameters = cx25840_ir_tx_g_parameters,
+	.tx_s_parameters = cx25840_ir_tx_s_parameters,
+};
+
+
+static const struct v4l2_subdev_ir_parameters default_rx_params = {
+	.bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec),
+	.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
+
+	.enable = false,
+	.interrupt_enable = false,
+	.shutdown = true,
+
+	.modulation = true,
+	.carrier_freq = 36000, /* 36 kHz - RC-5, and RC-6 carrier */
+
+	/* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */
+	/* RC-6: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */
+	.noise_filter_min_width = 333333, /* ns */
+	.carrier_range_lower = 35000,
+	.carrier_range_upper = 37000,
+	.invert_level = false,
+};
+
+static const struct v4l2_subdev_ir_parameters default_tx_params = {
+	.bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec),
+	.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
+
+	.enable = false,
+	.interrupt_enable = false,
+	.shutdown = true,
+
+	.modulation = true,
+	.carrier_freq = 36000, /* 36 kHz - RC-5 carrier */
+	.duty_cycle = 25,      /* 25 %   - RC-5 carrier */
+	.invert_level = false,
+	.invert_carrier_sense = false,
+};
+
+int cx25840_ir_probe(struct v4l2_subdev *sd)
+{
+	struct cx25840_state *state = to_state(sd);
+	struct cx25840_ir_state *ir_state;
+	struct v4l2_subdev_ir_parameters default_params;
+
+	/* Only init the IR controller for the CX2388[57] AV Core for now */
+	if (!(is_cx23885(state) || is_cx23887(state)))
+		return 0;
+
+	ir_state = kzalloc(sizeof(struct cx25840_ir_state), GFP_KERNEL);
+	if (ir_state == NULL)
+		return -ENOMEM;
+
+	spin_lock_init(&ir_state->rx_kfifo_lock);
+	if (kfifo_alloc(&ir_state->rx_kfifo,
+			CX25840_IR_RX_KFIFO_SIZE, GFP_KERNEL)) {
+		kfree(ir_state);
+		return -ENOMEM;
+	}
+
+	ir_state->c = state->c;
+	state->ir_state = ir_state;
+
+	/* Ensure no interrupts arrive yet */
+	if (is_cx23885(state) || is_cx23887(state))
+		cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, IRQEN_MSK);
+	else
+		cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, 0);
+
+	mutex_init(&ir_state->rx_params_lock);
+	memcpy(&default_params, &default_rx_params,
+		       sizeof(struct v4l2_subdev_ir_parameters));
+	v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params);
+
+	mutex_init(&ir_state->tx_params_lock);
+	memcpy(&default_params, &default_tx_params,
+		       sizeof(struct v4l2_subdev_ir_parameters));
+	v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params);
+
+	return 0;
+}
+
+int cx25840_ir_remove(struct v4l2_subdev *sd)
+{
+	struct cx25840_state *state = to_state(sd);
+	struct cx25840_ir_state *ir_state = to_ir_state(sd);
+
+	if (ir_state == NULL)
+		return -ENODEV;
+
+	cx25840_ir_rx_shutdown(sd);
+	cx25840_ir_tx_shutdown(sd);
+
+	kfifo_free(&ir_state->rx_kfifo);
+	kfree(ir_state);
+	state->ir_state = NULL;
+	return 0;
+}
diff --git a/drivers/media/i2c/cx25840/cx25840-vbi.c b/drivers/media/i2c/cx25840/cx25840-vbi.c
new file mode 100644
index 0000000..64a4004
--- /dev/null
+++ b/drivers/media/i2c/cx25840/cx25840-vbi.c
@@ -0,0 +1,256 @@
+/* cx25840 VBI functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <media/v4l2-common.h>
+#include <media/cx25840.h>
+
+#include "cx25840-core.h"
+
+static int odd_parity(u8 c)
+{
+	c ^= (c >> 4);
+	c ^= (c >> 2);
+	c ^= (c >> 1);
+
+	return c & 1;
+}
+
+static int decode_vps(u8 * dst, u8 * p)
+{
+	static const u8 biphase_tbl[] = {
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+		0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+		0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+		0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+		0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+		0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+		0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+		0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
+		0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
+		0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
+		0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
+		0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+		0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+		0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+		0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+		0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
+		0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
+		0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
+		0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
+		0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+		0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+		0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+		0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+		0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+		0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+	};
+
+	u8 c, err = 0;
+	int i;
+
+	for (i = 0; i < 2 * 13; i += 2) {
+		err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
+		c = (biphase_tbl[p[i + 1]] & 0xf) |
+		    ((biphase_tbl[p[i]] & 0xf) << 4);
+		dst[i / 2] = c;
+	}
+
+	return err & 0xf0;
+}
+
+int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct cx25840_state *state = to_state(sd);
+	static const u16 lcr2vbi[] = {
+		0, V4L2_SLICED_TELETEXT_B, 0,	/* 1 */
+		0, V4L2_SLICED_WSS_625, 0,	/* 4 */
+		V4L2_SLICED_CAPTION_525,	/* 6 */
+		0, 0, V4L2_SLICED_VPS, 0, 0,	/* 9 */
+		0, 0, 0, 0
+	};
+	int is_pal = !(state->std & V4L2_STD_525_60);
+	int i;
+
+	memset(svbi, 0, sizeof(*svbi));
+	/* we're done if raw VBI is active */
+	if ((cx25840_read(client, 0x404) & 0x10) == 0)
+		return 0;
+
+	if (is_pal) {
+		for (i = 7; i <= 23; i++) {
+			u8 v = cx25840_read(client, 0x424 + i - 7);
+
+			svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+			svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+			svbi->service_set |= svbi->service_lines[0][i] |
+					     svbi->service_lines[1][i];
+		}
+	} else {
+		for (i = 10; i <= 21; i++) {
+			u8 v = cx25840_read(client, 0x424 + i - 10);
+
+			svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+			svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+			svbi->service_set |= svbi->service_lines[0][i] |
+					     svbi->service_lines[1][i];
+		}
+	}
+	return 0;
+}
+
+int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct cx25840_state *state = to_state(sd);
+	int is_pal = !(state->std & V4L2_STD_525_60);
+	int vbi_offset = is_pal ? 1 : 0;
+
+	/* Setup standard */
+	cx25840_std_setup(client);
+
+	/* VBI Offset */
+	cx25840_write(client, 0x47f, vbi_offset);
+	cx25840_write(client, 0x404, 0x2e);
+	return 0;
+}
+
+int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct cx25840_state *state = to_state(sd);
+	int is_pal = !(state->std & V4L2_STD_525_60);
+	int vbi_offset = is_pal ? 1 : 0;
+	int i, x;
+	u8 lcr[24];
+
+	for (x = 0; x <= 23; x++)
+		lcr[x] = 0x00;
+
+	/* Setup standard */
+	cx25840_std_setup(client);
+
+	/* Sliced VBI */
+	cx25840_write(client, 0x404, 0x32);	/* Ancillary data */
+	cx25840_write(client, 0x406, 0x13);
+	cx25840_write(client, 0x47f, vbi_offset);
+
+	if (is_pal) {
+		for (i = 0; i <= 6; i++)
+			svbi->service_lines[0][i] =
+				svbi->service_lines[1][i] = 0;
+	} else {
+		for (i = 0; i <= 9; i++)
+			svbi->service_lines[0][i] =
+				svbi->service_lines[1][i] = 0;
+
+		for (i = 22; i <= 23; i++)
+			svbi->service_lines[0][i] =
+				svbi->service_lines[1][i] = 0;
+	}
+
+	for (i = 7; i <= 23; i++) {
+		for (x = 0; x <= 1; x++) {
+			switch (svbi->service_lines[1-x][i]) {
+			case V4L2_SLICED_TELETEXT_B:
+				lcr[i] |= 1 << (4 * x);
+				break;
+			case V4L2_SLICED_WSS_625:
+				lcr[i] |= 4 << (4 * x);
+				break;
+			case V4L2_SLICED_CAPTION_525:
+				lcr[i] |= 6 << (4 * x);
+				break;
+			case V4L2_SLICED_VPS:
+				lcr[i] |= 9 << (4 * x);
+				break;
+			}
+		}
+	}
+
+	if (is_pal) {
+		for (x = 1, i = 0x424; i <= 0x434; i++, x++)
+			cx25840_write(client, i, lcr[6 + x]);
+	} else {
+		for (x = 1, i = 0x424; i <= 0x430; i++, x++)
+			cx25840_write(client, i, lcr[9 + x]);
+		for (i = 0x431; i <= 0x434; i++)
+			cx25840_write(client, i, 0);
+	}
+
+	cx25840_write(client, 0x43c, 0x16);
+	cx25840_write(client, 0x474, is_pal ? 0x2a : 0x22);
+	return 0;
+}
+
+int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi)
+{
+	struct cx25840_state *state = to_state(sd);
+	u8 *p = vbi->p;
+	int id1, id2, l, err = 0;
+
+	if (p[0] || p[1] != 0xff || p[2] != 0xff ||
+			(p[3] != 0x55 && p[3] != 0x91)) {
+		vbi->line = vbi->type = 0;
+		return 0;
+	}
+
+	p += 4;
+	id1 = p[-1];
+	id2 = p[0] & 0xf;
+	l = p[2] & 0x3f;
+	l += state->vbi_line_offset;
+	p += 4;
+
+	switch (id2) {
+	case 1:
+		id2 = V4L2_SLICED_TELETEXT_B;
+		break;
+	case 4:
+		id2 = V4L2_SLICED_WSS_625;
+		break;
+	case 6:
+		id2 = V4L2_SLICED_CAPTION_525;
+		err = !odd_parity(p[0]) || !odd_parity(p[1]);
+		break;
+	case 9:
+		id2 = V4L2_SLICED_VPS;
+		if (decode_vps(p, p) != 0)
+			err = 1;
+		break;
+	default:
+		id2 = 0;
+		err = 1;
+		break;
+	}
+
+	vbi->type = err ? 0 : id2;
+	vbi->line = err ? 0 : l;
+	vbi->is_second_field = err ? 0 : (id1 == 0x55);
+	vbi->p = p;
+	return 0;
+}
diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
new file mode 100644
index 0000000..04f192a
--- /dev/null
+++ b/drivers/media/i2c/ir-kbd-i2c.c
@@ -0,0 +1,489 @@
+/*
+ *
+ * keyboard input driver for i2c IR remote controls
+ *
+ * Copyright (c) 2000-2003 Gerd Knorr <kraxel@bytesex.org>
+ * modified for PixelView (BT878P+W/FM) by
+ *      Michal Kochanowicz <mkochano@pld.org.pl>
+ *      Christoph Bartelmus <lirc@bartelmus.de>
+ * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by
+ *      Ulrich Mueller <ulrich.mueller42@web.de>
+ * modified for em2820 based USB TV tuners by
+ *      Markus Rechberger <mrechberger@gmail.com>
+ * modified for DViCO Fusion HDTV 5 RT GOLD by
+ *      Chaogui Zhang <czhang1974@gmail.com>
+ * modified for MSI TV@nywhere Plus by
+ *      Henry Wong <henry@stuffedcow.net>
+ *      Mark Schultz <n9xmj@yahoo.com>
+ *      Brian Rogers <brian_rogers@comcast.net>
+ * modified for AVerMedia Cardbus by
+ *      Oldrich Jedlicka <oldium.pro@seznam.cz>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+
+#include <media/rc-core.h>
+#include <media/ir-kbd-i2c.h>
+
+/* ----------------------------------------------------------------------- */
+/* insmod parameters                                                       */
+
+static int debug;
+module_param(debug, int, 0644);    /* debug level (0,1,2) */
+
+
+#define MODULE_NAME "ir-kbd-i2c"
+#define dprintk(level, fmt, arg...)	if (debug >= level) \
+	printk(KERN_DEBUG MODULE_NAME ": " fmt , ## arg)
+
+/* ----------------------------------------------------------------------- */
+
+static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
+			       int size, int offset)
+{
+	unsigned char buf[6];
+	int start, range, toggle, dev, code, ircode;
+
+	/* poll IR chip */
+	if (size != i2c_master_recv(ir->c, buf, size))
+		return -EIO;
+
+	/* split rc5 data block ... */
+	start  = (buf[offset] >> 7) &    1;
+	range  = (buf[offset] >> 6) &    1;
+	toggle = (buf[offset] >> 5) &    1;
+	dev    =  buf[offset]       & 0x1f;
+	code   = (buf[offset+1] >> 2) & 0x3f;
+
+	/* rc5 has two start bits
+	 * the first bit must be one
+	 * the second bit defines the command range (1 = 0-63, 0 = 64 - 127)
+	 */
+	if (!start)
+		/* no key pressed */
+		return 0;
+	/*
+	 * Hauppauge remotes (black/silver) always use
+	 * specific device ids. If we do not filter the
+	 * device ids then messages destined for devices
+	 * such as TVs (id=0) will get through causing
+	 * mis-fired events.
+	 *
+	 * We also filter out invalid key presses which
+	 * produce annoying debug log entries.
+	 */
+	ircode= (start << 12) | (toggle << 11) | (dev << 6) | code;
+	if ((ircode & 0x1fff)==0x1fff)
+		/* invalid key press */
+		return 0;
+
+	if (!range)
+		code += 64;
+
+	dprintk(1,"ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n",
+		start, range, toggle, dev, code);
+
+	/* return key */
+	*ir_key = (dev << 8) | code;
+	*ir_raw = ircode;
+	return 1;
+}
+
+static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	return get_key_haup_common (ir, ir_key, ir_raw, 3, 0);
+}
+
+static int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	int ret;
+	unsigned char buf[1] = { 0 };
+
+	/*
+	 * This is the same apparent "are you ready?" poll command observed
+	 * watching Windows driver traffic and implemented in lirc_zilog. With
+	 * this added, we get far saner remote behavior with z8 chips on usb
+	 * connected devices, even with the default polling interval of 100ms.
+	 */
+	ret = i2c_master_send(ir->c, buf, 1);
+	if (ret != 1)
+		return (ret < 0) ? ret : -EINVAL;
+
+	return get_key_haup_common (ir, ir_key, ir_raw, 6, 3);
+}
+
+static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char b;
+
+	/* poll IR chip */
+	if (1 != i2c_master_recv(ir->c, &b, 1)) {
+		dprintk(1,"read error\n");
+		return -EIO;
+	}
+	*ir_key = b;
+	*ir_raw = b;
+	return 1;
+}
+
+static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char buf[4];
+
+	/* poll IR chip */
+	if (4 != i2c_master_recv(ir->c, buf, 4)) {
+		dprintk(1,"read error\n");
+		return -EIO;
+	}
+
+	if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0)
+		dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __func__,
+			buf[0], buf[1], buf[2], buf[3]);
+
+	/* no key pressed or signal from other ir remote */
+	if(buf[0] != 0x1 ||  buf[1] != 0xfe)
+		return 0;
+
+	*ir_key = buf[2];
+	*ir_raw = (buf[2] << 8) | buf[3];
+
+	return 1;
+}
+
+static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char b;
+
+	/* poll IR chip */
+	if (1 != i2c_master_recv(ir->c, &b, 1)) {
+		dprintk(1,"read error\n");
+		return -EIO;
+	}
+
+	/* it seems that 0xFE indicates that a button is still hold
+	   down, while 0xff indicates that no button is hold
+	   down. 0xfe sequences are sometimes interrupted by 0xFF */
+
+	dprintk(2,"key %02x\n", b);
+
+	if (b == 0xff)
+		return 0;
+
+	if (b == 0xfe)
+		/* keep old data */
+		return 1;
+
+	*ir_key = b;
+	*ir_raw = b;
+	return 1;
+}
+
+static int get_key_avermedia_cardbus(struct IR_i2c *ir,
+				     u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char subaddr, key, keygroup;
+	struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0,
+				   .buf = &subaddr, .len = 1},
+				 { .addr = ir->c->addr, .flags = I2C_M_RD,
+				  .buf = &key, .len = 1} };
+	subaddr = 0x0d;
+	if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
+		dprintk(1, "read error\n");
+		return -EIO;
+	}
+
+	if (key == 0xff)
+		return 0;
+
+	subaddr = 0x0b;
+	msg[1].buf = &keygroup;
+	if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
+		dprintk(1, "read error\n");
+		return -EIO;
+	}
+
+	if (keygroup == 0xff)
+		return 0;
+
+	dprintk(1, "read key 0x%02x/0x%02x\n", key, keygroup);
+	if (keygroup < 2 || keygroup > 3) {
+		/* Only a warning */
+		dprintk(1, "warning: invalid key group 0x%02x for key 0x%02x\n",
+								keygroup, key);
+	}
+	key |= (keygroup & 1) << 6;
+
+	*ir_key = key;
+	*ir_raw = key;
+	return 1;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int ir_key_poll(struct IR_i2c *ir)
+{
+	static u32 ir_key, ir_raw;
+	int rc;
+
+	dprintk(3, "%s\n", __func__);
+	rc = ir->get_key(ir, &ir_key, &ir_raw);
+	if (rc < 0) {
+		dprintk(2,"error\n");
+		return rc;
+	}
+
+	if (rc) {
+		dprintk(1, "%s: keycode = 0x%04x\n", __func__, ir_key);
+		rc_keydown(ir->rc, ir_key, 0);
+	}
+	return 0;
+}
+
+static void ir_work(struct work_struct *work)
+{
+	int rc;
+	struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work);
+
+	rc = ir_key_poll(ir);
+	if (rc == -ENODEV) {
+		rc_unregister_device(ir->rc);
+		ir->rc = NULL;
+		return;
+	}
+
+	schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling_interval));
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	char *ir_codes = NULL;
+	const char *name = NULL;
+	u64 rc_type = RC_TYPE_UNKNOWN;
+	struct IR_i2c *ir;
+	struct rc_dev *rc = NULL;
+	struct i2c_adapter *adap = client->adapter;
+	unsigned short addr = client->addr;
+	int err;
+
+	ir = kzalloc(sizeof(struct IR_i2c), GFP_KERNEL);
+	if (!ir)
+		return -ENOMEM;
+
+	ir->c = client;
+	ir->polling_interval = DEFAULT_POLLING_INTERVAL;
+	i2c_set_clientdata(client, ir);
+
+	switch(addr) {
+	case 0x64:
+		name        = "Pixelview";
+		ir->get_key = get_key_pixelview;
+		rc_type     = RC_TYPE_OTHER;
+		ir_codes    = RC_MAP_EMPTY;
+		break;
+	case 0x18:
+	case 0x1f:
+	case 0x1a:
+		name        = "Hauppauge";
+		ir->get_key = get_key_haup;
+		rc_type     = RC_TYPE_RC5;
+		ir_codes    = RC_MAP_HAUPPAUGE;
+		break;
+	case 0x30:
+		name        = "KNC One";
+		ir->get_key = get_key_knc1;
+		rc_type     = RC_TYPE_OTHER;
+		ir_codes    = RC_MAP_EMPTY;
+		break;
+	case 0x6b:
+		name        = "FusionHDTV";
+		ir->get_key = get_key_fusionhdtv;
+		rc_type     = RC_TYPE_RC5;
+		ir_codes    = RC_MAP_FUSIONHDTV_MCE;
+		break;
+	case 0x40:
+		name        = "AVerMedia Cardbus remote";
+		ir->get_key = get_key_avermedia_cardbus;
+		rc_type     = RC_TYPE_OTHER;
+		ir_codes    = RC_MAP_AVERMEDIA_CARDBUS;
+		break;
+	case 0x71:
+		name        = "Hauppauge/Zilog Z8";
+		ir->get_key = get_key_haup_xvr;
+		rc_type     = RC_TYPE_RC5;
+		ir_codes    = RC_MAP_HAUPPAUGE;
+		break;
+	}
+
+	/* Let the caller override settings */
+	if (client->dev.platform_data) {
+		const struct IR_i2c_init_data *init_data =
+						client->dev.platform_data;
+
+		ir_codes = init_data->ir_codes;
+		rc = init_data->rc_dev;
+
+		name = init_data->name;
+		if (init_data->type)
+			rc_type = init_data->type;
+
+		if (init_data->polling_interval)
+			ir->polling_interval = init_data->polling_interval;
+
+		switch (init_data->internal_get_key_func) {
+		case IR_KBD_GET_KEY_CUSTOM:
+			/* The bridge driver provided us its own function */
+			ir->get_key = init_data->get_key;
+			break;
+		case IR_KBD_GET_KEY_PIXELVIEW:
+			ir->get_key = get_key_pixelview;
+			break;
+		case IR_KBD_GET_KEY_HAUP:
+			ir->get_key = get_key_haup;
+			break;
+		case IR_KBD_GET_KEY_KNC1:
+			ir->get_key = get_key_knc1;
+			break;
+		case IR_KBD_GET_KEY_FUSIONHDTV:
+			ir->get_key = get_key_fusionhdtv;
+			break;
+		case IR_KBD_GET_KEY_HAUP_XVR:
+			ir->get_key = get_key_haup_xvr;
+			break;
+		case IR_KBD_GET_KEY_AVERMEDIA_CARDBUS:
+			ir->get_key = get_key_avermedia_cardbus;
+			break;
+		}
+	}
+
+	if (!rc) {
+		/*
+		 * If platform_data doesn't specify rc_dev, initilize it
+		 * internally
+		 */
+		rc = rc_allocate_device();
+		if (!rc) {
+			err = -ENOMEM;
+			goto err_out_free;
+		}
+	}
+	ir->rc = rc;
+
+	/* Make sure we are all setup before going on */
+	if (!name || !ir->get_key || !rc_type || !ir_codes) {
+		dprintk(1, ": Unsupported device at address 0x%02x\n",
+			addr);
+		err = -ENODEV;
+		goto err_out_free;
+	}
+
+	/* Sets name */
+	snprintf(ir->name, sizeof(ir->name), "i2c IR (%s)", name);
+	ir->ir_codes = ir_codes;
+
+	snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0",
+		 dev_name(&adap->dev),
+		 dev_name(&client->dev));
+
+	/*
+	 * Initialize input_dev fields
+	 * It doesn't make sense to allow overriding them via platform_data
+	 */
+	rc->input_id.bustype = BUS_I2C;
+	rc->input_phys       = ir->phys;
+	rc->input_name	     = ir->name;
+
+	/*
+	 * Initialize the other fields of rc_dev
+	 */
+	rc->map_name       = ir->ir_codes;
+	rc->allowed_protos = rc_type;
+	if (!rc->driver_name)
+		rc->driver_name = MODULE_NAME;
+
+	err = rc_register_device(rc);
+	if (err)
+		goto err_out_free;
+
+	printk(MODULE_NAME ": %s detected at %s [%s]\n",
+	       ir->name, ir->phys, adap->name);
+
+	/* start polling via eventd */
+	INIT_DELAYED_WORK(&ir->work, ir_work);
+	schedule_delayed_work(&ir->work, 0);
+
+	return 0;
+
+ err_out_free:
+	/* Only frees rc if it were allocated internally */
+	rc_free_device(rc);
+	kfree(ir);
+	return err;
+}
+
+static int ir_remove(struct i2c_client *client)
+{
+	struct IR_i2c *ir = i2c_get_clientdata(client);
+
+	/* kill outstanding polls */
+	cancel_delayed_work_sync(&ir->work);
+
+	/* unregister device */
+	if (ir->rc)
+		rc_unregister_device(ir->rc);
+
+	/* free memory */
+	kfree(ir);
+	return 0;
+}
+
+static const struct i2c_device_id ir_kbd_id[] = {
+	/* Generic entry for any IR receiver */
+	{ "ir_video", 0 },
+	/* IR device specific entries should be added here */
+	{ "ir_rx_z8f0811_haup", 0 },
+	{ "ir_rx_z8f0811_hdpvr", 0 },
+	{ }
+};
+
+static struct i2c_driver ir_kbd_driver = {
+	.driver = {
+		.name   = "ir-kbd-i2c",
+	},
+	.probe          = ir_probe,
+	.remove         = ir_remove,
+	.id_table       = ir_kbd_id,
+};
+
+module_i2c_driver(ir_kbd_driver);
+
+/* ----------------------------------------------------------------------- */
+
+MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller");
+MODULE_DESCRIPTION("input driver for i2c IR remote controls");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/ks0127.c b/drivers/media/i2c/ks0127.c
new file mode 100644
index 0000000..ee7ca2d
--- /dev/null
+++ b/drivers/media/i2c/ks0127.c
@@ -0,0 +1,724 @@
+/*
+ * Video Capture Driver (Video for Linux 1/2)
+ * for the Matrox Marvel G200,G400 and Rainbow Runner-G series
+ *
+ * This module is an interface to the KS0127 video decoder chip.
+ *
+ * Copyright (C) 1999  Ryan Drake <stiletto@mediaone.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ *****************************************************************************
+ *
+ * Modified and extended by
+ *	Mike Bernson <mike@mlb.org>
+ *	Gerard v.d. Horst
+ *	Leon van Stuivenberg <l.vanstuivenberg@chello.nl>
+ *	Gernot Ziegler <gz@lysator.liu.se>
+ *
+ * Version History:
+ * V1.0 Ryan Drake	   Initial version by Ryan Drake
+ * V1.1 Gerard v.d. Horst  Added some debugoutput, reset the video-standard
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include "ks0127.h"
+
+MODULE_DESCRIPTION("KS0127 video decoder driver");
+MODULE_AUTHOR("Ryan Drake");
+MODULE_LICENSE("GPL");
+
+/* Addresses */
+#define I2C_KS0127_ADDON   0xD8
+#define I2C_KS0127_ONBOARD 0xDA
+
+
+/* ks0127 control registers */
+#define KS_STAT     0x00
+#define KS_CMDA     0x01
+#define KS_CMDB     0x02
+#define KS_CMDC     0x03
+#define KS_CMDD     0x04
+#define KS_HAVB     0x05
+#define KS_HAVE     0x06
+#define KS_HS1B     0x07
+#define KS_HS1E     0x08
+#define KS_HS2B     0x09
+#define KS_HS2E     0x0a
+#define KS_AGC      0x0b
+#define KS_HXTRA    0x0c
+#define KS_CDEM     0x0d
+#define KS_PORTAB   0x0e
+#define KS_LUMA     0x0f
+#define KS_CON      0x10
+#define KS_BRT      0x11
+#define KS_CHROMA   0x12
+#define KS_CHROMB   0x13
+#define KS_DEMOD    0x14
+#define KS_SAT      0x15
+#define KS_HUE      0x16
+#define KS_VERTIA   0x17
+#define KS_VERTIB   0x18
+#define KS_VERTIC   0x19
+#define KS_HSCLL    0x1a
+#define KS_HSCLH    0x1b
+#define KS_VSCLL    0x1c
+#define KS_VSCLH    0x1d
+#define KS_OFMTA    0x1e
+#define KS_OFMTB    0x1f
+#define KS_VBICTL   0x20
+#define KS_CCDAT2   0x21
+#define KS_CCDAT1   0x22
+#define KS_VBIL30   0x23
+#define KS_VBIL74   0x24
+#define KS_VBIL118  0x25
+#define KS_VBIL1512 0x26
+#define KS_TTFRAM   0x27
+#define KS_TESTA    0x28
+#define KS_UVOFFH   0x29
+#define KS_UVOFFL   0x2a
+#define KS_UGAIN    0x2b
+#define KS_VGAIN    0x2c
+#define KS_VAVB     0x2d
+#define KS_VAVE     0x2e
+#define KS_CTRACK   0x2f
+#define KS_POLCTL   0x30
+#define KS_REFCOD   0x31
+#define KS_INVALY   0x32
+#define KS_INVALU   0x33
+#define KS_INVALV   0x34
+#define KS_UNUSEY   0x35
+#define KS_UNUSEU   0x36
+#define KS_UNUSEV   0x37
+#define KS_USRSAV   0x38
+#define KS_USREAV   0x39
+#define KS_SHS1A    0x3a
+#define KS_SHS1B    0x3b
+#define KS_SHS1C    0x3c
+#define KS_CMDE     0x3d
+#define KS_VSDEL    0x3e
+#define KS_CMDF     0x3f
+#define KS_GAMMA0   0x40
+#define KS_GAMMA1   0x41
+#define KS_GAMMA2   0x42
+#define KS_GAMMA3   0x43
+#define KS_GAMMA4   0x44
+#define KS_GAMMA5   0x45
+#define KS_GAMMA6   0x46
+#define KS_GAMMA7   0x47
+#define KS_GAMMA8   0x48
+#define KS_GAMMA9   0x49
+#define KS_GAMMA10  0x4a
+#define KS_GAMMA11  0x4b
+#define KS_GAMMA12  0x4c
+#define KS_GAMMA13  0x4d
+#define KS_GAMMA14  0x4e
+#define KS_GAMMA15  0x4f
+#define KS_GAMMA16  0x50
+#define KS_GAMMA17  0x51
+#define KS_GAMMA18  0x52
+#define KS_GAMMA19  0x53
+#define KS_GAMMA20  0x54
+#define KS_GAMMA21  0x55
+#define KS_GAMMA22  0x56
+#define KS_GAMMA23  0x57
+#define KS_GAMMA24  0x58
+#define KS_GAMMA25  0x59
+#define KS_GAMMA26  0x5a
+#define KS_GAMMA27  0x5b
+#define KS_GAMMA28  0x5c
+#define KS_GAMMA29  0x5d
+#define KS_GAMMA30  0x5e
+#define KS_GAMMA31  0x5f
+#define KS_GAMMAD0  0x60
+#define KS_GAMMAD1  0x61
+#define KS_GAMMAD2  0x62
+#define KS_GAMMAD3  0x63
+#define KS_GAMMAD4  0x64
+#define KS_GAMMAD5  0x65
+#define KS_GAMMAD6  0x66
+#define KS_GAMMAD7  0x67
+#define KS_GAMMAD8  0x68
+#define KS_GAMMAD9  0x69
+#define KS_GAMMAD10 0x6a
+#define KS_GAMMAD11 0x6b
+#define KS_GAMMAD12 0x6c
+#define KS_GAMMAD13 0x6d
+#define KS_GAMMAD14 0x6e
+#define KS_GAMMAD15 0x6f
+#define KS_GAMMAD16 0x70
+#define KS_GAMMAD17 0x71
+#define KS_GAMMAD18 0x72
+#define KS_GAMMAD19 0x73
+#define KS_GAMMAD20 0x74
+#define KS_GAMMAD21 0x75
+#define KS_GAMMAD22 0x76
+#define KS_GAMMAD23 0x77
+#define KS_GAMMAD24 0x78
+#define KS_GAMMAD25 0x79
+#define KS_GAMMAD26 0x7a
+#define KS_GAMMAD27 0x7b
+#define KS_GAMMAD28 0x7c
+#define KS_GAMMAD29 0x7d
+#define KS_GAMMAD30 0x7e
+#define KS_GAMMAD31 0x7f
+
+
+/****************************************************************************
+* mga_dev : represents one ks0127 chip.
+****************************************************************************/
+
+struct adjust {
+	int	contrast;
+	int	bright;
+	int	hue;
+	int	ugain;
+	int	vgain;
+};
+
+struct ks0127 {
+	struct v4l2_subdev sd;
+	v4l2_std_id	norm;
+	int		ident;
+	u8 		regs[256];
+};
+
+static inline struct ks0127 *to_ks0127(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct ks0127, sd);
+}
+
+
+static int debug; /* insmod parameter */
+
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug output");
+
+static u8 reg_defaults[64];
+
+static void init_reg_defaults(void)
+{
+	static int initialized;
+	u8 *table = reg_defaults;
+
+	if (initialized)
+		return;
+	initialized = 1;
+
+	table[KS_CMDA]     = 0x2c;  /* VSE=0, CCIR 601, autodetect standard */
+	table[KS_CMDB]     = 0x12;  /* VALIGN=0, AGC control and input */
+	table[KS_CMDC]     = 0x00;  /* Test options */
+	/* clock & input select, write 1 to PORTA */
+	table[KS_CMDD]     = 0x01;
+	table[KS_HAVB]     = 0x00;  /* HAV Start Control */
+	table[KS_HAVE]     = 0x00;  /* HAV End Control */
+	table[KS_HS1B]     = 0x10;  /* HS1 Start Control */
+	table[KS_HS1E]     = 0x00;  /* HS1 End Control */
+	table[KS_HS2B]     = 0x00;  /* HS2 Start Control */
+	table[KS_HS2E]     = 0x00;  /* HS2 End Control */
+	table[KS_AGC]      = 0x53;  /* Manual setting for AGC */
+	table[KS_HXTRA]    = 0x00;  /* Extra Bits for HAV and HS1/2 */
+	table[KS_CDEM]     = 0x00;  /* Chroma Demodulation Control */
+	table[KS_PORTAB]   = 0x0f;  /* port B is input, port A output GPPORT */
+	table[KS_LUMA]     = 0x01;  /* Luma control */
+	table[KS_CON]      = 0x00;  /* Contrast Control */
+	table[KS_BRT]      = 0x00;  /* Brightness Control */
+	table[KS_CHROMA]   = 0x2a;  /* Chroma control A */
+	table[KS_CHROMB]   = 0x90;  /* Chroma control B */
+	table[KS_DEMOD]    = 0x00;  /* Chroma Demodulation Control & Status */
+	table[KS_SAT]      = 0x00;  /* Color Saturation Control*/
+	table[KS_HUE]      = 0x00;  /* Hue Control */
+	table[KS_VERTIA]   = 0x00;  /* Vertical Processing Control A */
+	/* Vertical Processing Control B, luma 1 line delayed */
+	table[KS_VERTIB]   = 0x12;
+	table[KS_VERTIC]   = 0x0b;  /* Vertical Processing Control C */
+	table[KS_HSCLL]    = 0x00;  /* Horizontal Scaling Ratio Low */
+	table[KS_HSCLH]    = 0x00;  /* Horizontal Scaling Ratio High */
+	table[KS_VSCLL]    = 0x00;  /* Vertical Scaling Ratio Low */
+	table[KS_VSCLH]    = 0x00;  /* Vertical Scaling Ratio High */
+	/* 16 bit YCbCr 4:2:2 output; I can't make the bt866 like 8 bit /Sam */
+	table[KS_OFMTA]    = 0x30;
+	table[KS_OFMTB]    = 0x00;  /* Output Control B */
+	/* VBI Decoder Control; 4bit fmt: avoid Y overflow */
+	table[KS_VBICTL]   = 0x5d;
+	table[KS_CCDAT2]   = 0x00;  /* Read Only register */
+	table[KS_CCDAT1]   = 0x00;  /* Read Only register */
+	table[KS_VBIL30]   = 0xa8;  /* VBI data decoding options */
+	table[KS_VBIL74]   = 0xaa;  /* VBI data decoding options */
+	table[KS_VBIL118]  = 0x2a;  /* VBI data decoding options */
+	table[KS_VBIL1512] = 0x00;  /* VBI data decoding options */
+	table[KS_TTFRAM]   = 0x00;  /* Teletext frame alignment pattern */
+	table[KS_TESTA]    = 0x00;  /* test register, shouldn't be written */
+	table[KS_UVOFFH]   = 0x00;  /* UV Offset Adjustment High */
+	table[KS_UVOFFL]   = 0x00;  /* UV Offset Adjustment Low */
+	table[KS_UGAIN]    = 0x00;  /* U Component Gain Adjustment */
+	table[KS_VGAIN]    = 0x00;  /* V Component Gain Adjustment */
+	table[KS_VAVB]     = 0x07;  /* VAV Begin */
+	table[KS_VAVE]     = 0x00;  /* VAV End */
+	table[KS_CTRACK]   = 0x00;  /* Chroma Tracking Control */
+	table[KS_POLCTL]   = 0x41;  /* Timing Signal Polarity Control */
+	table[KS_REFCOD]   = 0x80;  /* Reference Code Insertion Control */
+	table[KS_INVALY]   = 0x10;  /* Invalid Y Code */
+	table[KS_INVALU]   = 0x80;  /* Invalid U Code */
+	table[KS_INVALV]   = 0x80;  /* Invalid V Code */
+	table[KS_UNUSEY]   = 0x10;  /* Unused Y Code */
+	table[KS_UNUSEU]   = 0x80;  /* Unused U Code */
+	table[KS_UNUSEV]   = 0x80;  /* Unused V Code */
+	table[KS_USRSAV]   = 0x00;  /* reserved */
+	table[KS_USREAV]   = 0x00;  /* reserved */
+	table[KS_SHS1A]    = 0x00;  /* User Defined SHS1 A */
+	/* User Defined SHS1 B, ALT656=1 on 0127B */
+	table[KS_SHS1B]    = 0x80;
+	table[KS_SHS1C]    = 0x00;  /* User Defined SHS1 C */
+	table[KS_CMDE]     = 0x00;  /* Command Register E */
+	table[KS_VSDEL]    = 0x00;  /* VS Delay Control */
+	/* Command Register F, update -immediately- */
+	/* (there might come no vsync)*/
+	table[KS_CMDF]     = 0x02;
+}
+
+
+/* We need to manually read because of a bug in the KS0127 chip.
+ *
+ * An explanation from kayork@mail.utexas.edu:
+ *
+ * During I2C reads, the KS0127 only samples for a stop condition
+ * during the place where the acknowledge bit should be. Any standard
+ * I2C implementation (correctly) throws in another clock transition
+ * at the 9th bit, and the KS0127 will not recognize the stop condition
+ * and will continue to clock out data.
+ *
+ * So we have to do the read ourself.  Big deal.
+ *	   workaround in i2c-algo-bit
+ */
+
+
+static u8 ks0127_read(struct v4l2_subdev *sd, u8 reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	char val = 0;
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, sizeof(reg), &reg },
+		{ client->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val }
+	};
+	int ret;
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret != ARRAY_SIZE(msgs))
+		v4l2_dbg(1, debug, sd, "read error\n");
+
+	return val;
+}
+
+
+static void ks0127_write(struct v4l2_subdev *sd, u8 reg, u8 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ks0127 *ks = to_ks0127(sd);
+	char msg[] = { reg, val };
+
+	if (i2c_master_send(client, msg, sizeof(msg)) != sizeof(msg))
+		v4l2_dbg(1, debug, sd, "write error\n");
+
+	ks->regs[reg] = val;
+}
+
+
+/* generic bit-twiddling */
+static void ks0127_and_or(struct v4l2_subdev *sd, u8 reg, u8 and_v, u8 or_v)
+{
+	struct ks0127 *ks = to_ks0127(sd);
+
+	u8 val = ks->regs[reg];
+	val = (val & and_v) | or_v;
+	ks0127_write(sd, reg, val);
+}
+
+
+
+/****************************************************************************
+* ks0127 private api
+****************************************************************************/
+static void ks0127_init(struct v4l2_subdev *sd)
+{
+	struct ks0127 *ks = to_ks0127(sd);
+	u8 *table = reg_defaults;
+	int i;
+
+	ks->ident = V4L2_IDENT_KS0127;
+
+	v4l2_dbg(1, debug, sd, "reset\n");
+	msleep(1);
+
+	/* initialize all registers to known values */
+	/* (except STAT, 0x21, 0x22, TEST and 0x38,0x39) */
+
+	for (i = 1; i < 33; i++)
+		ks0127_write(sd, i, table[i]);
+
+	for (i = 35; i < 40; i++)
+		ks0127_write(sd, i, table[i]);
+
+	for (i = 41; i < 56; i++)
+		ks0127_write(sd, i, table[i]);
+
+	for (i = 58; i < 64; i++)
+		ks0127_write(sd, i, table[i]);
+
+
+	if ((ks0127_read(sd, KS_STAT) & 0x80) == 0) {
+		ks->ident = V4L2_IDENT_KS0122S;
+		v4l2_dbg(1, debug, sd, "ks0122s found\n");
+		return;
+	}
+
+	switch (ks0127_read(sd, KS_CMDE) & 0x0f) {
+	case 0:
+		v4l2_dbg(1, debug, sd, "ks0127 found\n");
+		break;
+
+	case 9:
+		ks->ident = V4L2_IDENT_KS0127B;
+		v4l2_dbg(1, debug, sd, "ks0127B Revision A found\n");
+		break;
+
+	default:
+		v4l2_dbg(1, debug, sd, "unknown revision\n");
+		break;
+	}
+}
+
+static int ks0127_s_routing(struct v4l2_subdev *sd,
+			    u32 input, u32 output, u32 config)
+{
+	struct ks0127 *ks = to_ks0127(sd);
+
+	switch (input) {
+	case KS_INPUT_COMPOSITE_1:
+	case KS_INPUT_COMPOSITE_2:
+	case KS_INPUT_COMPOSITE_3:
+	case KS_INPUT_COMPOSITE_4:
+	case KS_INPUT_COMPOSITE_5:
+	case KS_INPUT_COMPOSITE_6:
+		v4l2_dbg(1, debug, sd,
+			"s_routing %d: Composite\n", input);
+		/* autodetect 50/60 Hz */
+		ks0127_and_or(sd, KS_CMDA,   0xfc, 0x00);
+		/* VSE=0 */
+		ks0127_and_or(sd, KS_CMDA,   ~0x40, 0x00);
+		/* set input line */
+		ks0127_and_or(sd, KS_CMDB,   0xb0, input);
+		/* non-freerunning mode */
+		ks0127_and_or(sd, KS_CMDC,   0x70, 0x0a);
+		/* analog input */
+		ks0127_and_or(sd, KS_CMDD,   0x03, 0x00);
+		/* enable chroma demodulation */
+		ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x00);
+		/* chroma trap, HYBWR=1 */
+		ks0127_and_or(sd, KS_LUMA,   0x00,
+			       (reg_defaults[KS_LUMA])|0x0c);
+		/* scaler fullbw, luma comb off */
+		ks0127_and_or(sd, KS_VERTIA, 0x08, 0x81);
+		/* manual chroma comb .25 .5 .25 */
+		ks0127_and_or(sd, KS_VERTIC, 0x0f, 0x90);
+
+		/* chroma path delay */
+		ks0127_and_or(sd, KS_CHROMB, 0x0f, 0x90);
+
+		ks0127_write(sd, KS_UGAIN, reg_defaults[KS_UGAIN]);
+		ks0127_write(sd, KS_VGAIN, reg_defaults[KS_VGAIN]);
+		ks0127_write(sd, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+		ks0127_write(sd, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+		break;
+
+	case KS_INPUT_SVIDEO_1:
+	case KS_INPUT_SVIDEO_2:
+	case KS_INPUT_SVIDEO_3:
+		v4l2_dbg(1, debug, sd,
+			"s_routing %d: S-Video\n", input);
+		/* autodetect 50/60 Hz */
+		ks0127_and_or(sd, KS_CMDA,   0xfc, 0x00);
+		/* VSE=0 */
+		ks0127_and_or(sd, KS_CMDA,   ~0x40, 0x00);
+		/* set input line */
+		ks0127_and_or(sd, KS_CMDB,   0xb0, input);
+		/* non-freerunning mode */
+		ks0127_and_or(sd, KS_CMDC,   0x70, 0x0a);
+		/* analog input */
+		ks0127_and_or(sd, KS_CMDD,   0x03, 0x00);
+		/* enable chroma demodulation */
+		ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x00);
+		ks0127_and_or(sd, KS_LUMA, 0x00,
+			       reg_defaults[KS_LUMA]);
+		/* disable luma comb */
+		ks0127_and_or(sd, KS_VERTIA, 0x08,
+			       (reg_defaults[KS_VERTIA]&0xf0)|0x01);
+		ks0127_and_or(sd, KS_VERTIC, 0x0f,
+			       reg_defaults[KS_VERTIC]&0xf0);
+
+		ks0127_and_or(sd, KS_CHROMB, 0x0f,
+			       reg_defaults[KS_CHROMB]&0xf0);
+
+		ks0127_write(sd, KS_UGAIN, reg_defaults[KS_UGAIN]);
+		ks0127_write(sd, KS_VGAIN, reg_defaults[KS_VGAIN]);
+		ks0127_write(sd, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+		ks0127_write(sd, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+		break;
+
+	case KS_INPUT_YUV656:
+		v4l2_dbg(1, debug, sd, "s_routing 15: YUV656\n");
+		if (ks->norm & V4L2_STD_525_60)
+			/* force 60 Hz */
+			ks0127_and_or(sd, KS_CMDA,   0xfc, 0x03);
+		else
+			/* force 50 Hz */
+			ks0127_and_or(sd, KS_CMDA,   0xfc, 0x02);
+
+		ks0127_and_or(sd, KS_CMDA,   0xff, 0x40); /* VSE=1 */
+		/* set input line and VALIGN */
+		ks0127_and_or(sd, KS_CMDB,   0xb0, (input | 0x40));
+		/* freerunning mode, */
+		/* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0  VMEM=1*/
+		ks0127_and_or(sd, KS_CMDC,   0x70, 0x87);
+		/* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */
+		ks0127_and_or(sd, KS_CMDD,   0x03, 0x08);
+		/* disable chroma demodulation */
+		ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x30);
+		/* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */
+		ks0127_and_or(sd, KS_LUMA,   0x00, 0x71);
+		ks0127_and_or(sd, KS_VERTIC, 0x0f,
+			       reg_defaults[KS_VERTIC]&0xf0);
+
+		/* scaler fullbw, luma comb off */
+		ks0127_and_or(sd, KS_VERTIA, 0x08, 0x81);
+
+		ks0127_and_or(sd, KS_CHROMB, 0x0f,
+			       reg_defaults[KS_CHROMB]&0xf0);
+
+		ks0127_and_or(sd, KS_CON, 0x00, 0x00);
+		ks0127_and_or(sd, KS_BRT, 0x00, 32);	/* spec: 34 */
+			/* spec: 229 (e5) */
+		ks0127_and_or(sd, KS_SAT, 0x00, 0xe8);
+		ks0127_and_or(sd, KS_HUE, 0x00, 0);
+
+		ks0127_and_or(sd, KS_UGAIN, 0x00, 238);
+		ks0127_and_or(sd, KS_VGAIN, 0x00, 0x00);
+
+		/*UOFF:0x30, VOFF:0x30, TSTCGN=1 */
+		ks0127_and_or(sd, KS_UVOFFH, 0x00, 0x4f);
+		ks0127_and_or(sd, KS_UVOFFL, 0x00, 0x00);
+		break;
+
+	default:
+		v4l2_dbg(1, debug, sd,
+			"s_routing: Unknown input %d\n", input);
+		break;
+	}
+
+	/* hack: CDMLPF sometimes spontaneously switches on; */
+	/* force back off */
+	ks0127_write(sd, KS_DEMOD, reg_defaults[KS_DEMOD]);
+	return 0;
+}
+
+static int ks0127_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct ks0127 *ks = to_ks0127(sd);
+
+	/* Set to automatic SECAM/Fsc mode */
+	ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x00);
+
+	ks->norm = std;
+	if (std & V4L2_STD_NTSC) {
+		v4l2_dbg(1, debug, sd,
+			"s_std: NTSC_M\n");
+		ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x20);
+	} else if (std & V4L2_STD_PAL_N) {
+		v4l2_dbg(1, debug, sd,
+			"s_std: NTSC_N (fixme)\n");
+		ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x40);
+	} else if (std & V4L2_STD_PAL) {
+		v4l2_dbg(1, debug, sd,
+			"s_std: PAL_N\n");
+		ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x20);
+	} else if (std & V4L2_STD_PAL_M) {
+		v4l2_dbg(1, debug, sd,
+			"s_std: PAL_M (fixme)\n");
+		ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x40);
+	} else if (std & V4L2_STD_SECAM) {
+		v4l2_dbg(1, debug, sd,
+			"s_std: SECAM\n");
+
+		/* set to secam autodetection */
+		ks0127_and_or(sd, KS_CHROMA, 0xdf, 0x20);
+		ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x00);
+		schedule_timeout_interruptible(HZ/10+1);
+
+		/* did it autodetect? */
+		if (!(ks0127_read(sd, KS_DEMOD) & 0x40))
+			/* force to secam mode */
+			ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x0f);
+	} else {
+		v4l2_dbg(1, debug, sd, "s_std: Unknown norm %llx\n",
+			       (unsigned long long)std);
+	}
+	return 0;
+}
+
+static int ks0127_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	v4l2_dbg(1, debug, sd, "s_stream(%d)\n", enable);
+	if (enable) {
+		/* All output pins on */
+		ks0127_and_or(sd, KS_OFMTA, 0xcf, 0x30);
+		/* Obey the OEN pin */
+		ks0127_and_or(sd, KS_CDEM, 0x7f, 0x00);
+	} else {
+		/* Video output pins off */
+		ks0127_and_or(sd, KS_OFMTA, 0xcf, 0x00);
+		/* Ignore the OEN pin */
+		ks0127_and_or(sd, KS_CDEM, 0x7f, 0x80);
+	}
+	return 0;
+}
+
+static int ks0127_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
+{
+	int stat = V4L2_IN_ST_NO_SIGNAL;
+	u8 status;
+	v4l2_std_id std = V4L2_STD_ALL;
+
+	status = ks0127_read(sd, KS_STAT);
+	if (!(status & 0x20))		 /* NOVID not set */
+		stat = 0;
+	if (!(status & 0x01))		      /* CLOCK set */
+		stat |= V4L2_IN_ST_NO_COLOR;
+	if ((status & 0x08))		   /* PALDET set */
+		std = V4L2_STD_PAL;
+	else
+		std = V4L2_STD_NTSC;
+	if (pstd)
+		*pstd = std;
+	if (pstatus)
+		*pstatus = stat;
+	return 0;
+}
+
+static int ks0127_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	v4l2_dbg(1, debug, sd, "querystd\n");
+	return ks0127_status(sd, NULL, std);
+}
+
+static int ks0127_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+	v4l2_dbg(1, debug, sd, "g_input_status\n");
+	return ks0127_status(sd, status, NULL);
+}
+
+static int ks0127_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ks0127 *ks = to_ks0127(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, ks->ident, 0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops ks0127_core_ops = {
+	.g_chip_ident = ks0127_g_chip_ident,
+	.s_std = ks0127_s_std,
+};
+
+static const struct v4l2_subdev_video_ops ks0127_video_ops = {
+	.s_routing = ks0127_s_routing,
+	.s_stream = ks0127_s_stream,
+	.querystd = ks0127_querystd,
+	.g_input_status = ks0127_g_input_status,
+};
+
+static const struct v4l2_subdev_ops ks0127_ops = {
+	.core = &ks0127_core_ops,
+	.video = &ks0127_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+
+static int ks0127_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct ks0127 *ks;
+	struct v4l2_subdev *sd;
+
+	v4l_info(client, "%s chip found @ 0x%x (%s)\n",
+		client->addr == (I2C_KS0127_ADDON >> 1) ? "addon" : "on-board",
+		client->addr << 1, client->adapter->name);
+
+	ks = kzalloc(sizeof(*ks), GFP_KERNEL);
+	if (ks == NULL)
+		return -ENOMEM;
+	sd = &ks->sd;
+	v4l2_i2c_subdev_init(sd, client, &ks0127_ops);
+
+	/* power up */
+	init_reg_defaults();
+	ks0127_write(sd, KS_CMDA, 0x2c);
+	mdelay(10);
+
+	/* reset the device */
+	ks0127_init(sd);
+	return 0;
+}
+
+static int ks0127_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	ks0127_write(sd, KS_OFMTA, 0x20); /* tristate */
+	ks0127_write(sd, KS_CMDA, 0x2c | 0x80); /* power down */
+	kfree(to_ks0127(sd));
+	return 0;
+}
+
+static const struct i2c_device_id ks0127_id[] = {
+	{ "ks0127", 0 },
+	{ "ks0127b", 0 },
+	{ "ks0122s", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ks0127_id);
+
+static struct i2c_driver ks0127_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "ks0127",
+	},
+	.probe		= ks0127_probe,
+	.remove		= ks0127_remove,
+	.id_table	= ks0127_id,
+};
+
+module_i2c_driver(ks0127_driver);
diff --git a/drivers/media/i2c/ks0127.h b/drivers/media/i2c/ks0127.h
new file mode 100644
index 0000000..cb8abd5
--- /dev/null
+++ b/drivers/media/i2c/ks0127.h
@@ -0,0 +1,51 @@
+/*
+ * Video Capture Driver ( Video for Linux 1/2 )
+ * for the Matrox Marvel G200,G400 and Rainbow Runner-G series
+ *
+ * This module is an interface to the KS0127 video decoder chip.
+ *
+ * Copyright (C) 1999  Ryan Drake <stiletto@mediaone.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef KS0127_H
+#define KS0127_H
+
+/* input channels */
+#define KS_INPUT_COMPOSITE_1    0
+#define KS_INPUT_COMPOSITE_2    1
+#define KS_INPUT_COMPOSITE_3    2
+#define KS_INPUT_COMPOSITE_4    4
+#define KS_INPUT_COMPOSITE_5    5
+#define KS_INPUT_COMPOSITE_6    6
+
+#define KS_INPUT_SVIDEO_1       8
+#define KS_INPUT_SVIDEO_2       9
+#define KS_INPUT_SVIDEO_3       10
+
+#define KS_INPUT_YUV656		15
+#define KS_INPUT_COUNT          10
+
+/* output channels */
+#define KS_OUTPUT_YUV656E       0
+#define KS_OUTPUT_EXV           1
+
+/* video standards */
+#define KS_STD_NTSC_N           112       /* 50 Hz NTSC */
+#define KS_STD_PAL_M            113       /* 60 Hz PAL  */
+
+#endif /* KS0127_H */
+
diff --git a/drivers/media/i2c/m52790.c b/drivers/media/i2c/m52790.c
new file mode 100644
index 0000000..0991576
--- /dev/null
+++ b/drivers/media/i2c/m52790.c
@@ -0,0 +1,216 @@
+/*
+ * m52790 i2c ivtv driver.
+ * Copyright (C) 2007  Hans Verkuil
+ *
+ * A/V source switching Mitsubishi M52790SP/FP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/m52790.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+
+struct m52790_state {
+	struct v4l2_subdev sd;
+	u16 input;
+	u16 output;
+};
+
+static inline struct m52790_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct m52790_state, sd);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int m52790_write(struct v4l2_subdev *sd)
+{
+	struct m52790_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	u8 sw1 = (state->input | state->output) & 0xff;
+	u8 sw2 = (state->input | state->output) >> 8;
+
+	return i2c_smbus_write_byte_data(client, sw1, sw2);
+}
+
+/* Note: audio and video are linked and cannot be switched separately.
+   So audio and video routing commands are identical for this chip.
+   In theory the video amplifier and audio modes could be handled
+   separately for the output, but that seems to be overkill right now.
+   The same holds for implementing an audio mute control, this is now
+   part of the audio output routing. The normal case is that another
+   chip takes care of the actual muting so making it part of the
+   output routing seems to be the right thing to do for now. */
+static int m52790_s_routing(struct v4l2_subdev *sd,
+			    u32 input, u32 output, u32 config)
+{
+	struct m52790_state *state = to_state(sd);
+
+	state->input = input;
+	state->output = output;
+	m52790_write(sd);
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int m52790_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct m52790_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (reg->reg != 0)
+		return -EINVAL;
+	reg->size = 1;
+	reg->val = state->input | state->output;
+	return 0;
+}
+
+static int m52790_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct m52790_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (reg->reg != 0)
+		return -EINVAL;
+	state->input = reg->val & 0x0303;
+	state->output = reg->val & ~0x0303;
+	m52790_write(sd);
+	return 0;
+}
+#endif
+
+static int m52790_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_M52790, 0);
+}
+
+static int m52790_log_status(struct v4l2_subdev *sd)
+{
+	struct m52790_state *state = to_state(sd);
+
+	v4l2_info(sd, "Switch 1: %02x\n",
+			(state->input | state->output) & 0xff);
+	v4l2_info(sd, "Switch 2: %02x\n",
+			(state->input | state->output) >> 8);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops m52790_core_ops = {
+	.log_status = m52790_log_status,
+	.g_chip_ident = m52790_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = m52790_g_register,
+	.s_register = m52790_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_audio_ops m52790_audio_ops = {
+	.s_routing = m52790_s_routing,
+};
+
+static const struct v4l2_subdev_video_ops m52790_video_ops = {
+	.s_routing = m52790_s_routing,
+};
+
+static const struct v4l2_subdev_ops m52790_ops = {
+	.core = &m52790_core_ops,
+	.audio = &m52790_audio_ops,
+	.video = &m52790_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+static int m52790_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct m52790_state *state;
+	struct v4l2_subdev *sd;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	state = kzalloc(sizeof(struct m52790_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &m52790_ops);
+	state->input = M52790_IN_TUNER;
+	state->output = M52790_OUT_STEREO;
+	m52790_write(sd);
+	return 0;
+}
+
+static int m52790_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_state(sd));
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id m52790_id[] = {
+	{ "m52790", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, m52790_id);
+
+static struct i2c_driver m52790_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "m52790",
+	},
+	.probe		= m52790_probe,
+	.remove		= m52790_remove,
+	.id_table	= m52790_id,
+};
+
+module_i2c_driver(m52790_driver);
diff --git a/drivers/media/i2c/m5mols/Kconfig b/drivers/media/i2c/m5mols/Kconfig
new file mode 100644
index 0000000..dc8c250
--- /dev/null
+++ b/drivers/media/i2c/m5mols/Kconfig
@@ -0,0 +1,6 @@
+config VIDEO_M5MOLS
+	tristate "Fujitsu M-5MOLS 8MP sensor support"
+	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+	depends on MEDIA_CAMERA_SUPPORT
+	---help---
+	  This driver supports Fujitsu M-5MOLS camera sensor with ISP
diff --git a/drivers/media/i2c/m5mols/Makefile b/drivers/media/i2c/m5mols/Makefile
new file mode 100644
index 0000000..0a44e02
--- /dev/null
+++ b/drivers/media/i2c/m5mols/Makefile
@@ -0,0 +1,3 @@
+m5mols-objs	:= m5mols_core.o m5mols_controls.o m5mols_capture.o
+
+obj-$(CONFIG_VIDEO_M5MOLS)		+= m5mols.o
diff --git a/drivers/media/i2c/m5mols/m5mols.h b/drivers/media/i2c/m5mols/m5mols.h
new file mode 100644
index 0000000..bb58991
--- /dev/null
+++ b/drivers/media/i2c/m5mols/m5mols.h
@@ -0,0 +1,334 @@
+/*
+ * Header for M-5MOLS 8M Pixel camera sensor with ISP
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Author: HeungJun Kim <riverful.kim@samsung.com>
+ *
+ * Copyright (C) 2009 Samsung Electronics Co., Ltd.
+ * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef M5MOLS_H
+#define M5MOLS_H
+
+#include <media/v4l2-subdev.h>
+#include "m5mols_reg.h"
+
+extern int m5mols_debug;
+
+enum m5mols_restype {
+	M5MOLS_RESTYPE_MONITOR,
+	M5MOLS_RESTYPE_CAPTURE,
+	M5MOLS_RESTYPE_MAX,
+};
+
+/**
+ * struct m5mols_resolution - structure for the resolution
+ * @type: resolution type according to the pixel code
+ * @width: width of the resolution
+ * @height: height of the resolution
+ * @reg: resolution preset register value
+ */
+struct m5mols_resolution {
+	u8 reg;
+	enum m5mols_restype type;
+	u16 width;
+	u16 height;
+};
+
+/**
+ * struct m5mols_exif - structure for the EXIF information of M-5MOLS
+ * @exposure_time: exposure time register value
+ * @shutter_speed: speed of the shutter register value
+ * @aperture: aperture register value
+ * @exposure_bias: it calls also EV bias
+ * @iso_speed: ISO register value
+ * @flash: status register value of the flash
+ * @sdr: status register value of the Subject Distance Range
+ * @qval: not written exact meaning in document
+ */
+struct m5mols_exif {
+	u32 exposure_time;
+	u32 shutter_speed;
+	u32 aperture;
+	u32 brightness;
+	u32 exposure_bias;
+	u16 iso_speed;
+	u16 flash;
+	u16 sdr;
+	u16 qval;
+};
+
+/**
+ * struct m5mols_capture - Structure for the capture capability
+ * @exif: EXIF information
+ * @main: size in bytes of the main image
+ * @thumb: size in bytes of the thumb image, if it was accompanied
+ * @total: total size in bytes of the produced image
+ */
+struct m5mols_capture {
+	struct m5mols_exif exif;
+	u32 main;
+	u32 thumb;
+	u32 total;
+};
+
+/**
+ * struct m5mols_scenemode - structure for the scenemode capability
+ * @metering: metering light register value
+ * @ev_bias: EV bias register value
+ * @wb_mode: mode which means the WhiteBalance is Auto or Manual
+ * @wb_preset: whitebalance preset register value in the Manual mode
+ * @chroma_en: register value whether the Chroma capability is enabled or not
+ * @chroma_lvl: chroma's level register value
+ * @edge_en: register value Whether the Edge capability is enabled or not
+ * @edge_lvl: edge's level register value
+ * @af_range: Auto Focus's range
+ * @fd_mode: Face Detection mode
+ * @mcc: Multi-axis Color Conversion which means emotion color
+ * @light: status of the Light
+ * @flash: status of the Flash
+ * @tone: Tone color which means Contrast
+ * @iso: ISO register value
+ * @capt_mode: Mode of the Image Stabilization while the camera capturing
+ * @wdr: Wide Dynamic Range register value
+ *
+ * The each value according to each scenemode is recommended in the documents.
+ */
+struct m5mols_scenemode {
+	u8 metering;
+	u8 ev_bias;
+	u8 wb_mode;
+	u8 wb_preset;
+	u8 chroma_en;
+	u8 chroma_lvl;
+	u8 edge_en;
+	u8 edge_lvl;
+	u8 af_range;
+	u8 fd_mode;
+	u8 mcc;
+	u8 light;
+	u8 flash;
+	u8 tone;
+	u8 iso;
+	u8 capt_mode;
+	u8 wdr;
+};
+
+/**
+ * struct m5mols_version - firmware version information
+ * @customer:	customer information
+ * @project:	version of project information according to customer
+ * @fw:		firmware revision
+ * @hw:		hardware revision
+ * @param:	version of the parameter
+ * @awb:	Auto WhiteBalance algorithm version
+ * @str:	information about manufacturer and packaging vendor
+ * @af:		Auto Focus version
+ *
+ * The register offset starts the customer version at 0x0, and it ends
+ * the awb version at 0x09. The customer, project information occupies 1 bytes
+ * each. And also the fw, hw, param, awb each requires 2 bytes. The str is
+ * unique string associated with firmware's version. It includes information
+ * about manufacturer and the vendor of the sensor's packaging. The least
+ * significant 2 bytes of the string indicate packaging manufacturer.
+ */
+#define VERSION_STRING_SIZE	22
+struct m5mols_version {
+	u8	customer;
+	u8	project;
+	u16	fw;
+	u16	hw;
+	u16	param;
+	u16	awb;
+	u8	str[VERSION_STRING_SIZE];
+	u8	af;
+};
+
+/**
+ * struct m5mols_info - M-5MOLS driver data structure
+ * @pdata: platform data
+ * @sd: v4l-subdev instance
+ * @pad: media pad
+ * @ffmt: current fmt according to resolution type
+ * @res_type: current resolution type
+ * @irq_waitq: waitqueue for the capture
+ * @irq_done: set to 1 in the interrupt handler
+ * @handle: control handler
+ * @auto_exposure: auto/manual exposure control
+ * @exposure_bias: exposure compensation control
+ * @exposure: manual exposure control
+ * @metering: exposure metering control
+ * @auto_iso: auto/manual ISO sensitivity control
+ * @iso: manual ISO sensitivity control
+ * @auto_wb: auto white balance control
+ * @lock_3a: 3A lock control
+ * @colorfx: color effect control
+ * @saturation: saturation control
+ * @zoom: zoom control
+ * @wdr: wide dynamic range control
+ * @stabilization: image stabilization control
+ * @jpeg_quality: JPEG compression quality control
+ * @ver: information of the version
+ * @cap: the capture mode attributes
+ * @isp_ready: 1 when the ISP controller has completed booting
+ * @power: current sensor's power status
+ * @ctrl_sync: 1 when the control handler state is restored in H/W
+ * @resolution:	register value for current resolution
+ * @mode: register value for current operation mode
+ * @set_power: optional power callback to the board code
+ */
+struct m5mols_info {
+	const struct m5mols_platform_data *pdata;
+	struct v4l2_subdev sd;
+	struct media_pad pad;
+	struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX];
+	int res_type;
+
+	wait_queue_head_t irq_waitq;
+	atomic_t irq_done;
+
+	struct v4l2_ctrl_handler handle;
+	struct {
+		/* exposure/exposure bias/auto exposure cluster */
+		struct v4l2_ctrl *auto_exposure;
+		struct v4l2_ctrl *exposure_bias;
+		struct v4l2_ctrl *exposure;
+		struct v4l2_ctrl *metering;
+	};
+	struct {
+		/* iso/auto iso cluster */
+		struct v4l2_ctrl *auto_iso;
+		struct v4l2_ctrl *iso;
+	};
+	struct v4l2_ctrl *auto_wb;
+
+	struct v4l2_ctrl *lock_3a;
+	struct v4l2_ctrl *colorfx;
+	struct v4l2_ctrl *saturation;
+	struct v4l2_ctrl *zoom;
+	struct v4l2_ctrl *wdr;
+	struct v4l2_ctrl *stabilization;
+	struct v4l2_ctrl *jpeg_quality;
+
+	struct m5mols_version ver;
+	struct m5mols_capture cap;
+
+	unsigned int isp_ready:1;
+	unsigned int power:1;
+	unsigned int ctrl_sync:1;
+
+	u8 resolution;
+	u8 mode;
+
+	int (*set_power)(struct device *dev, int on);
+};
+
+#define is_available_af(__info)	(__info->ver.af)
+#define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code)
+#define is_manufacturer(__info, __manufacturer)	\
+				(__info->ver.str[0] == __manufacturer[0] && \
+				 __info->ver.str[1] == __manufacturer[1])
+/*
+ * I2C operation of the M-5MOLS
+ *
+ * The I2C read operation of the M-5MOLS requires 2 messages. The first
+ * message sends the information about the command, command category, and total
+ * message size. The second message is used to retrieve the data specifed in
+ * the first message
+ *
+ *   1st message                                2nd message
+ *   +-------+---+----------+-----+-------+     +------+------+------+------+
+ *   | size1 | R | category | cmd | size2 |     | d[0] | d[1] | d[2] | d[3] |
+ *   +-------+---+----------+-----+-------+     +------+------+------+------+
+ *   - size1: message data size(5 in this case)
+ *   - size2: desired buffer size of the 2nd message
+ *   - d[0..3]: according to size2
+ *
+ * The I2C write operation needs just one message. The message includes
+ * category, command, total size, and desired data.
+ *
+ *   1st message
+ *   +-------+---+----------+-----+------+------+------+------+
+ *   | size1 | W | category | cmd | d[0] | d[1] | d[2] | d[3] |
+ *   +-------+---+----------+-----+------+------+------+------+
+ *   - d[0..3]: according to size1
+ */
+int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg_comb, u8 *val);
+int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg_comb, u16 *val);
+int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg_comb, u32 *val);
+int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val);
+
+int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask,
+		     int timeout);
+
+/* Mask value for busy waiting until M-5MOLS I2C interface is initialized */
+#define M5MOLS_I2C_RDY_WAIT_FL		(1 << 16)
+/* ISP state transition timeout, in ms */
+#define M5MOLS_MODE_CHANGE_TIMEOUT	200
+#define M5MOLS_BUSY_WAIT_DEF_TIMEOUT	250
+
+/*
+ * Mode operation of the M-5MOLS
+ *
+ * Changing the mode of the M-5MOLS is needed right executing order.
+ * There are three modes(PARAMETER, MONITOR, CAPTURE) which can be changed
+ * by user. There are various categories associated with each mode.
+ *
+ * +============================================================+
+ * | mode	| category					|
+ * +============================================================+
+ * | FLASH	| FLASH(only after Stand-by or Power-on)	|
+ * | SYSTEM	| SYSTEM(only after sensor arm-booting)		|
+ * | PARAMETER	| PARAMETER					|
+ * | MONITOR	| MONITOR(preview), Auto Focus, Face Detection	|
+ * | CAPTURE	| Single CAPTURE, Preview(recording)		|
+ * +============================================================+
+ *
+ * The available executing order between each modes are as follows:
+ *   PARAMETER <---> MONITOR <---> CAPTURE
+ */
+int m5mols_set_mode(struct m5mols_info *info, u8 mode);
+
+int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg);
+int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout);
+int m5mols_restore_controls(struct m5mols_info *info);
+int m5mols_start_capture(struct m5mols_info *info);
+int m5mols_do_scenemode(struct m5mols_info *info, u8 mode);
+int m5mols_lock_3a(struct m5mols_info *info, bool lock);
+int m5mols_set_ctrl(struct v4l2_ctrl *ctrl);
+int m5mols_init_controls(struct v4l2_subdev *sd);
+
+/* The firmware function */
+int m5mols_update_fw(struct v4l2_subdev *sd,
+		     int (*set_power)(struct m5mols_info *, bool));
+
+static inline struct m5mols_info *to_m5mols(struct v4l2_subdev *subdev)
+{
+	return container_of(subdev, struct m5mols_info, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	struct m5mols_info *info = container_of(ctrl->handler,
+						struct m5mols_info, handle);
+	return &info->sd;
+}
+
+static inline void m5mols_set_ctrl_mode(struct v4l2_ctrl *ctrl,
+					unsigned int mode)
+{
+	ctrl->priv = (void *)mode;
+}
+
+static inline unsigned int m5mols_get_ctrl_mode(struct v4l2_ctrl *ctrl)
+{
+	return (unsigned int)ctrl->priv;
+}
+
+#endif	/* M5MOLS_H */
diff --git a/drivers/media/i2c/m5mols/m5mols_capture.c b/drivers/media/i2c/m5mols/m5mols_capture.c
new file mode 100644
index 0000000..cb243bd
--- /dev/null
+++ b/drivers/media/i2c/m5mols/m5mols_capture.c
@@ -0,0 +1,155 @@
+
+/*
+ * The Capture code for Fujitsu M-5MOLS ISP
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Author: HeungJun Kim <riverful.kim@samsung.com>
+ *
+ * Copyright (C) 2009 Samsung Electronics Co., Ltd.
+ * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/m5mols.h>
+#include <media/s5p_fimc.h>
+
+#include "m5mols.h"
+#include "m5mols_reg.h"
+
+/**
+ * m5mols_read_rational - I2C read of a rational number
+ *
+ * Read numerator and denominator from registers @addr_num and @addr_den
+ * respectively and return the division result in @val.
+ */
+static int m5mols_read_rational(struct v4l2_subdev *sd, u32 addr_num,
+				u32 addr_den, u32 *val)
+{
+	u32 num, den;
+
+	int ret = m5mols_read_u32(sd, addr_num, &num);
+	if (!ret)
+		ret = m5mols_read_u32(sd, addr_den, &den);
+	if (ret)
+		return ret;
+	*val = den == 0 ? 0 : num / den;
+	return ret;
+}
+
+/**
+ * m5mols_capture_info - Gather captured image information
+ *
+ * For now it gathers only EXIF information and file size.
+ */
+static int m5mols_capture_info(struct m5mols_info *info)
+{
+	struct m5mols_exif *exif = &info->cap.exif;
+	struct v4l2_subdev *sd = &info->sd;
+	int ret;
+
+	ret = m5mols_read_rational(sd, EXIF_INFO_EXPTIME_NU,
+				   EXIF_INFO_EXPTIME_DE, &exif->exposure_time);
+	if (ret)
+		return ret;
+	ret = m5mols_read_rational(sd, EXIF_INFO_TV_NU, EXIF_INFO_TV_DE,
+				   &exif->shutter_speed);
+	if (ret)
+		return ret;
+	ret = m5mols_read_rational(sd, EXIF_INFO_AV_NU, EXIF_INFO_AV_DE,
+				   &exif->aperture);
+	if (ret)
+		return ret;
+	ret = m5mols_read_rational(sd, EXIF_INFO_BV_NU, EXIF_INFO_BV_DE,
+				   &exif->brightness);
+	if (ret)
+		return ret;
+	ret = m5mols_read_rational(sd, EXIF_INFO_EBV_NU, EXIF_INFO_EBV_DE,
+				   &exif->exposure_bias);
+	if (ret)
+		return ret;
+
+	ret = m5mols_read_u16(sd, EXIF_INFO_ISO, &exif->iso_speed);
+	if (!ret)
+		ret = m5mols_read_u16(sd, EXIF_INFO_FLASH, &exif->flash);
+	if (!ret)
+		ret = m5mols_read_u16(sd, EXIF_INFO_SDR, &exif->sdr);
+	if (!ret)
+		ret = m5mols_read_u16(sd, EXIF_INFO_QVAL, &exif->qval);
+	if (ret)
+		return ret;
+
+	if (!ret)
+		ret = m5mols_read_u32(sd, CAPC_IMAGE_SIZE, &info->cap.main);
+	if (!ret)
+		ret = m5mols_read_u32(sd, CAPC_THUMB_SIZE, &info->cap.thumb);
+	if (!ret)
+		info->cap.total = info->cap.main + info->cap.thumb;
+
+	return ret;
+}
+
+int m5mols_start_capture(struct m5mols_info *info)
+{
+	struct v4l2_subdev *sd = &info->sd;
+	int ret;
+
+	/*
+	 * Synchronize the controls, set the capture frame resolution and color
+	 * format. The frame capture is initiated during switching from Monitor
+	 * to Capture mode.
+	 */
+	ret = m5mols_set_mode(info, REG_MONITOR);
+	if (!ret)
+		ret = m5mols_restore_controls(info);
+	if (!ret)
+		ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG);
+	if (!ret)
+		ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, info->resolution);
+	if (!ret)
+		ret = m5mols_set_mode(info, REG_CAPTURE);
+	if (!ret)
+		/* Wait until a frame is captured to ISP internal memory */
+		ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000);
+	if (ret)
+		return ret;
+
+	/*
+	 * Initiate the captured data transfer to a MIPI-CSI receiver.
+	 */
+	ret = m5mols_write(sd, CAPC_SEL_FRAME, 1);
+	if (!ret)
+		ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN);
+	if (!ret) {
+		bool captured = false;
+		unsigned int size;
+
+		/* Wait for the capture completion interrupt */
+		ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000);
+		if (!ret) {
+			captured = true;
+			ret = m5mols_capture_info(info);
+		}
+		size = captured ? info->cap.main : 0;
+		v4l2_dbg(1, m5mols_debug, sd, "%s: size: %d, thumb.: %d B\n",
+			 __func__, size, info->cap.thumb);
+
+		v4l2_subdev_notify(sd, S5P_FIMC_TX_END_NOTIFY, &size);
+	}
+
+	return ret;
+}
diff --git a/drivers/media/i2c/m5mols/m5mols_controls.c b/drivers/media/i2c/m5mols/m5mols_controls.c
new file mode 100644
index 0000000..fdbc205
--- /dev/null
+++ b/drivers/media/i2c/m5mols/m5mols_controls.c
@@ -0,0 +1,628 @@
+/*
+ * Controls for M-5MOLS 8M Pixel camera sensor with ISP
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Author: HeungJun Kim <riverful.kim@samsung.com>
+ *
+ * Copyright (C) 2009 Samsung Electronics Co., Ltd.
+ * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+
+#include "m5mols.h"
+#include "m5mols_reg.h"
+
+static struct m5mols_scenemode m5mols_default_scenemode[] = {
+	[REG_SCENE_NORMAL] = {
+		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+		REG_AF_NORMAL, REG_FD_OFF,
+		REG_MCC_NORMAL, REG_LIGHT_OFF, REG_FLASH_OFF,
+		5, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+	},
+	[REG_SCENE_PORTRAIT] = {
+		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+		REG_CHROMA_ON, 3, REG_EDGE_ON, 4,
+		REG_AF_NORMAL, BIT_FD_EN | BIT_FD_DRAW_FACE_FRAME,
+		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+	},
+	[REG_SCENE_LANDSCAPE] = {
+		REG_AE_ALL, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+		REG_CHROMA_ON, 4, REG_EDGE_ON, 6,
+		REG_AF_NORMAL, REG_FD_OFF,
+		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+	},
+	[REG_SCENE_SPORTS] = {
+		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+		REG_AF_NORMAL, REG_FD_OFF,
+		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+	},
+	[REG_SCENE_PARTY_INDOOR] = {
+		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+		REG_CHROMA_ON, 4, REG_EDGE_ON, 5,
+		REG_AF_NORMAL, REG_FD_OFF,
+		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+		6, REG_ISO_200, REG_CAP_NONE, REG_WDR_OFF,
+	},
+	[REG_SCENE_BEACH_SNOW] = {
+		REG_AE_CENTER, REG_AE_INDEX_10_POS, REG_AWB_AUTO, 0,
+		REG_CHROMA_ON, 4, REG_EDGE_ON, 5,
+		REG_AF_NORMAL, REG_FD_OFF,
+		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+		6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF,
+	},
+	[REG_SCENE_SUNSET] = {
+		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET,
+		REG_AWB_DAYLIGHT,
+		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+		REG_AF_NORMAL, REG_FD_OFF,
+		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+	},
+	[REG_SCENE_DAWN_DUSK] = {
+		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET,
+		REG_AWB_FLUORESCENT_1,
+		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+		REG_AF_NORMAL, REG_FD_OFF,
+		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+	},
+	[REG_SCENE_FALL] = {
+		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+		REG_CHROMA_ON, 5, REG_EDGE_ON, 5,
+		REG_AF_NORMAL, REG_FD_OFF,
+		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+	},
+	[REG_SCENE_NIGHT] = {
+		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+		REG_AF_NORMAL, REG_FD_OFF,
+		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+	},
+	[REG_SCENE_AGAINST_LIGHT] = {
+		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+		REG_AF_NORMAL, REG_FD_OFF,
+		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+	},
+	[REG_SCENE_FIRE] = {
+		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+		REG_AF_NORMAL, REG_FD_OFF,
+		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+		6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF,
+	},
+	[REG_SCENE_TEXT] = {
+		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+		REG_CHROMA_ON, 3, REG_EDGE_ON, 7,
+		REG_AF_MACRO, REG_FD_OFF,
+		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+		6, REG_ISO_AUTO, REG_CAP_ANTI_SHAKE, REG_WDR_ON,
+	},
+	[REG_SCENE_CANDLE] = {
+		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+		REG_AF_NORMAL, REG_FD_OFF,
+		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+	},
+};
+
+/**
+ * m5mols_do_scenemode() - Change current scenemode
+ * @mode:	Desired mode of the scenemode
+ *
+ * WARNING: The execution order is important. Do not change the order.
+ */
+int m5mols_do_scenemode(struct m5mols_info *info, u8 mode)
+{
+	struct v4l2_subdev *sd = &info->sd;
+	struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode];
+	int ret;
+
+	if (mode > REG_SCENE_CANDLE)
+		return -EINVAL;
+
+	ret = v4l2_ctrl_s_ctrl(info->lock_3a, 0);
+	if (!ret)
+		ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode);
+	if (!ret)
+		ret = m5mols_write(sd, AE_EV_PRESET_CAPTURE, mode);
+	if (!ret)
+		ret = m5mols_write(sd, AE_MODE, scenemode.metering);
+	if (!ret)
+		ret = m5mols_write(sd, AE_INDEX, scenemode.ev_bias);
+	if (!ret)
+		ret = m5mols_write(sd, AWB_MODE, scenemode.wb_mode);
+	if (!ret)
+		ret = m5mols_write(sd, AWB_MANUAL, scenemode.wb_preset);
+	if (!ret)
+		ret = m5mols_write(sd, MON_CHROMA_EN, scenemode.chroma_en);
+	if (!ret)
+		ret = m5mols_write(sd, MON_CHROMA_LVL, scenemode.chroma_lvl);
+	if (!ret)
+		ret = m5mols_write(sd, MON_EDGE_EN, scenemode.edge_en);
+	if (!ret)
+		ret = m5mols_write(sd, MON_EDGE_LVL, scenemode.edge_lvl);
+	if (!ret && is_available_af(info))
+		ret = m5mols_write(sd, AF_MODE, scenemode.af_range);
+	if (!ret && is_available_af(info))
+		ret = m5mols_write(sd, FD_CTL, scenemode.fd_mode);
+	if (!ret)
+		ret = m5mols_write(sd, MON_TONE_CTL, scenemode.tone);
+	if (!ret)
+		ret = m5mols_write(sd, AE_ISO, scenemode.iso);
+	if (!ret)
+		ret = m5mols_set_mode(info, REG_CAPTURE);
+	if (!ret)
+		ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr);
+	if (!ret)
+		ret = m5mols_write(sd, CAPP_MCC_MODE, scenemode.mcc);
+	if (!ret)
+		ret = m5mols_write(sd, CAPP_LIGHT_CTRL, scenemode.light);
+	if (!ret)
+		ret = m5mols_write(sd, CAPP_FLASH_CTRL, scenemode.flash);
+	if (!ret)
+		ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode);
+	if (!ret)
+		ret = m5mols_set_mode(info, REG_MONITOR);
+
+	return ret;
+}
+
+static int m5mols_3a_lock(struct m5mols_info *info, struct v4l2_ctrl *ctrl)
+{
+	bool af_lock = ctrl->val & V4L2_LOCK_FOCUS;
+	int ret = 0;
+
+	if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_EXPOSURE) {
+		bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE;
+
+		ret = m5mols_write(&info->sd, AE_LOCK, ae_lock ?
+				   REG_AE_LOCK : REG_AE_UNLOCK);
+		if (ret)
+			return ret;
+	}
+
+	if (((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_WHITE_BALANCE)
+	    && info->auto_wb->val) {
+		bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE;
+
+		ret = m5mols_write(&info->sd, AWB_LOCK, awb_lock ?
+				   REG_AWB_LOCK : REG_AWB_UNLOCK);
+		if (ret)
+			return ret;
+	}
+
+	if (!info->ver.af || !af_lock)
+		return ret;
+
+	if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS)
+		ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP);
+
+	return ret;
+}
+
+static int m5mols_set_metering_mode(struct m5mols_info *info, int mode)
+{
+	unsigned int metering;
+
+	switch (mode) {
+	case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED:
+		metering = REG_AE_CENTER;
+		break;
+	case V4L2_EXPOSURE_METERING_SPOT:
+		metering = REG_AE_SPOT;
+		break;
+	default:
+		metering = REG_AE_ALL;
+		break;
+	}
+
+	return m5mols_write(&info->sd, AE_MODE, metering);
+}
+
+static int m5mols_set_exposure(struct m5mols_info *info, int exposure)
+{
+	struct v4l2_subdev *sd = &info->sd;
+	int ret = 0;
+
+	if (exposure == V4L2_EXPOSURE_AUTO) {
+		/* Unlock auto exposure */
+		info->lock_3a->val &= ~V4L2_LOCK_EXPOSURE;
+		m5mols_3a_lock(info, info->lock_3a);
+
+		ret = m5mols_set_metering_mode(info, info->metering->val);
+		if (ret < 0)
+			return ret;
+
+		v4l2_dbg(1, m5mols_debug, sd,
+			 "%s: exposure bias: %#x, metering: %#x\n",
+			 __func__, info->exposure_bias->val,
+			 info->metering->val);
+
+		return m5mols_write(sd, AE_INDEX, info->exposure_bias->val);
+	}
+
+	if (exposure == V4L2_EXPOSURE_MANUAL) {
+		ret = m5mols_write(sd, AE_MODE, REG_AE_OFF);
+		if (ret == 0)
+			ret = m5mols_write(sd, AE_MAN_GAIN_MON,
+					   info->exposure->val);
+		if (ret == 0)
+			ret = m5mols_write(sd, AE_MAN_GAIN_CAP,
+					   info->exposure->val);
+
+		v4l2_dbg(1, m5mols_debug, sd, "%s: exposure: %#x\n",
+			 __func__, info->exposure->val);
+	}
+
+	return ret;
+}
+
+static int m5mols_set_white_balance(struct m5mols_info *info, int val)
+{
+	static const unsigned short wb[][2] = {
+		{ V4L2_WHITE_BALANCE_INCANDESCENT,  REG_AWB_INCANDESCENT },
+		{ V4L2_WHITE_BALANCE_FLUORESCENT,   REG_AWB_FLUORESCENT_1 },
+		{ V4L2_WHITE_BALANCE_FLUORESCENT_H, REG_AWB_FLUORESCENT_2 },
+		{ V4L2_WHITE_BALANCE_HORIZON,       REG_AWB_HORIZON },
+		{ V4L2_WHITE_BALANCE_DAYLIGHT,      REG_AWB_DAYLIGHT },
+		{ V4L2_WHITE_BALANCE_FLASH,         REG_AWB_LEDLIGHT },
+		{ V4L2_WHITE_BALANCE_CLOUDY,        REG_AWB_CLOUDY },
+		{ V4L2_WHITE_BALANCE_SHADE,         REG_AWB_SHADE },
+		{ V4L2_WHITE_BALANCE_AUTO,          REG_AWB_AUTO },
+	};
+	int i;
+	struct v4l2_subdev *sd = &info->sd;
+	int ret = -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(wb); i++) {
+		int awb;
+		if (wb[i][0] != val)
+			continue;
+
+		v4l2_dbg(1, m5mols_debug, sd,
+			 "Setting white balance to: %#x\n", wb[i][0]);
+
+		awb = wb[i][0] == V4L2_WHITE_BALANCE_AUTO;
+		ret = m5mols_write(sd, AWB_MODE, awb ? REG_AWB_AUTO :
+						 REG_AWB_PRESET);
+		if (ret < 0)
+			return ret;
+
+		if (!awb)
+			ret = m5mols_write(sd, AWB_MANUAL, wb[i][1]);
+	}
+
+	return ret;
+}
+
+static int m5mols_set_saturation(struct m5mols_info *info, int val)
+{
+	int ret = m5mols_write(&info->sd, MON_CHROMA_LVL, val);
+	if (ret < 0)
+		return ret;
+
+	return m5mols_write(&info->sd, MON_CHROMA_EN, REG_CHROMA_ON);
+}
+
+static int m5mols_set_color_effect(struct m5mols_info *info, int val)
+{
+	unsigned int m_effect = REG_COLOR_EFFECT_OFF;
+	unsigned int p_effect = REG_EFFECT_OFF;
+	unsigned int cfix_r = 0, cfix_b = 0;
+	struct v4l2_subdev *sd = &info->sd;
+	int ret = 0;
+
+	switch (val) {
+	case V4L2_COLORFX_BW:
+		m_effect = REG_COLOR_EFFECT_ON;
+		break;
+	case V4L2_COLORFX_NEGATIVE:
+		p_effect = REG_EFFECT_NEGA;
+		break;
+	case V4L2_COLORFX_EMBOSS:
+		p_effect = REG_EFFECT_EMBOSS;
+		break;
+	case V4L2_COLORFX_SEPIA:
+		m_effect = REG_COLOR_EFFECT_ON;
+		cfix_r = REG_CFIXR_SEPIA;
+		cfix_b = REG_CFIXB_SEPIA;
+		break;
+	}
+
+	ret = m5mols_write(sd, PARM_EFFECT, p_effect);
+	if (!ret)
+		ret = m5mols_write(sd, MON_EFFECT, m_effect);
+
+	if (ret == 0 && m_effect == REG_COLOR_EFFECT_ON) {
+		ret = m5mols_write(sd, MON_CFIXR, cfix_r);
+		if (!ret)
+			ret = m5mols_write(sd, MON_CFIXB, cfix_b);
+	}
+
+	v4l2_dbg(1, m5mols_debug, sd,
+		 "p_effect: %#x, m_effect: %#x, r: %#x, b: %#x (%d)\n",
+		 p_effect, m_effect, cfix_r, cfix_b, ret);
+
+	return ret;
+}
+
+static int m5mols_set_iso(struct m5mols_info *info, int auto_iso)
+{
+	u32 iso = auto_iso ? 0 : info->iso->val + 1;
+
+	return m5mols_write(&info->sd, AE_ISO, iso);
+}
+
+static int m5mols_set_wdr(struct m5mols_info *info, int wdr)
+{
+	int ret;
+
+	ret = m5mols_write(&info->sd, MON_TONE_CTL, wdr ? 9 : 5);
+	if (ret < 0)
+		return ret;
+
+	ret = m5mols_set_mode(info, REG_CAPTURE);
+	if (ret < 0)
+		return ret;
+
+	return m5mols_write(&info->sd, CAPP_WDR_EN, wdr);
+}
+
+static int m5mols_set_stabilization(struct m5mols_info *info, int val)
+{
+	struct v4l2_subdev *sd = &info->sd;
+	unsigned int evp = val ? 0xe : 0x0;
+	int ret;
+
+	ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, evp);
+	if (ret < 0)
+		return ret;
+
+	return m5mols_write(sd, AE_EV_PRESET_CAPTURE, evp);
+}
+
+static int m5mols_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct m5mols_info *info = to_m5mols(sd);
+	int ret = 0;
+	u8 status;
+
+	v4l2_dbg(1, m5mols_debug, sd, "%s: ctrl: %s (%d)\n",
+		 __func__, ctrl->name, info->isp_ready);
+
+	if (!info->isp_ready)
+		return -EBUSY;
+
+	switch (ctrl->id) {
+	case V4L2_CID_ISO_SENSITIVITY_AUTO:
+		ret = m5mols_read_u8(sd, AE_ISO, &status);
+		if (ret == 0)
+			ctrl->val = !status;
+		if (status != REG_ISO_AUTO)
+			info->iso->val = status - 1;
+		break;
+
+	case V4L2_CID_3A_LOCK:
+		ctrl->val &= ~0x7;
+
+		ret = m5mols_read_u8(sd, AE_LOCK, &status);
+		if (ret)
+			return ret;
+		if (status)
+			info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
+
+		ret = m5mols_read_u8(sd, AWB_LOCK, &status);
+		if (ret)
+			return ret;
+		if (status)
+			info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
+
+		ret = m5mols_read_u8(sd, AF_EXECUTE, &status);
+		if (!status)
+			info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
+		break;
+	}
+
+	return ret;
+}
+
+static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	unsigned int ctrl_mode = m5mols_get_ctrl_mode(ctrl);
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct m5mols_info *info = to_m5mols(sd);
+	int last_mode = info->mode;
+	int ret = 0;
+
+	/*
+	 * If needed, defer restoring the controls until
+	 * the device is fully initialized.
+	 */
+	if (!info->isp_ready) {
+		info->ctrl_sync = 0;
+		return 0;
+	}
+
+	v4l2_dbg(1, m5mols_debug, sd, "%s: %s, val: %d, priv: %#x\n",
+		 __func__, ctrl->name, ctrl->val, (int)ctrl->priv);
+
+	if (ctrl_mode && ctrl_mode != info->mode) {
+		ret = m5mols_set_mode(info, ctrl_mode);
+		if (ret < 0)
+			return ret;
+	}
+
+	switch (ctrl->id) {
+	case V4L2_CID_3A_LOCK:
+		ret = m5mols_3a_lock(info, ctrl);
+		break;
+
+	case V4L2_CID_ZOOM_ABSOLUTE:
+		ret = m5mols_write(sd, MON_ZOOM, ctrl->val);
+		break;
+
+	case V4L2_CID_EXPOSURE_AUTO:
+		ret = m5mols_set_exposure(info, ctrl->val);
+		break;
+
+	case V4L2_CID_ISO_SENSITIVITY:
+		ret = m5mols_set_iso(info, ctrl->val);
+		break;
+
+	case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+		ret = m5mols_set_white_balance(info, ctrl->val);
+		break;
+
+	case V4L2_CID_SATURATION:
+		ret = m5mols_set_saturation(info, ctrl->val);
+		break;
+
+	case V4L2_CID_COLORFX:
+		ret = m5mols_set_color_effect(info, ctrl->val);
+		break;
+
+	case V4L2_CID_WIDE_DYNAMIC_RANGE:
+		ret = m5mols_set_wdr(info, ctrl->val);
+		break;
+
+	case V4L2_CID_IMAGE_STABILIZATION:
+		ret = m5mols_set_stabilization(info, ctrl->val);
+		break;
+
+	case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+		ret = m5mols_write(sd, CAPP_JPEG_RATIO, ctrl->val);
+		break;
+	}
+
+	if (ret == 0 && info->mode != last_mode)
+		ret = m5mols_set_mode(info, last_mode);
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
+	.g_volatile_ctrl	= m5mols_g_volatile_ctrl,
+	.s_ctrl			= m5mols_s_ctrl,
+};
+
+/* Supported manual ISO values */
+static const s64 iso_qmenu[] = {
+	/* AE_ISO: 0x01...0x07 (ISO: 50...3200) */
+	50000, 100000, 200000, 400000, 800000, 1600000, 3200000
+};
+
+/* Supported Exposure Bias values, -2.0EV...+2.0EV */
+static const s64 ev_bias_qmenu[] = {
+	/* AE_INDEX: 0x00...0x08 */
+	-2000, -1500, -1000, -500, 0, 500, 1000, 1500, 2000
+};
+
+int m5mols_init_controls(struct v4l2_subdev *sd)
+{
+	struct m5mols_info *info = to_m5mols(sd);
+	u16 exposure_max;
+	u16 zoom_step;
+	int ret;
+
+	/* Determine the firmware dependant control range and step values */
+	ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &exposure_max);
+	if (ret < 0)
+		return ret;
+
+	zoom_step = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1;
+	v4l2_ctrl_handler_init(&info->handle, 20);
+
+	info->auto_wb = v4l2_ctrl_new_std_menu(&info->handle,
+			&m5mols_ctrl_ops, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
+			9, ~0x3fe, V4L2_WHITE_BALANCE_AUTO);
+
+	/* Exposure control cluster */
+	info->auto_exposure = v4l2_ctrl_new_std_menu(&info->handle,
+			&m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
+			1, ~0x03, V4L2_EXPOSURE_AUTO);
+
+	info->exposure = v4l2_ctrl_new_std(&info->handle,
+			&m5mols_ctrl_ops, V4L2_CID_EXPOSURE,
+			0, exposure_max, 1, exposure_max / 2);
+
+	info->exposure_bias = v4l2_ctrl_new_int_menu(&info->handle,
+			&m5mols_ctrl_ops, V4L2_CID_AUTO_EXPOSURE_BIAS,
+			ARRAY_SIZE(ev_bias_qmenu) - 1,
+			ARRAY_SIZE(ev_bias_qmenu)/2 - 1,
+			ev_bias_qmenu);
+
+	info->metering = v4l2_ctrl_new_std_menu(&info->handle,
+			&m5mols_ctrl_ops, V4L2_CID_EXPOSURE_METERING,
+			2, ~0x7, V4L2_EXPOSURE_METERING_AVERAGE);
+
+	/* ISO control cluster */
+	info->auto_iso = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_ISO_SENSITIVITY_AUTO, 1, ~0x03, 1);
+
+	info->iso = v4l2_ctrl_new_int_menu(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1,
+			ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu);
+
+	info->saturation = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_SATURATION, 1, 5, 1, 3);
+
+	info->zoom = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_ZOOM_ABSOLUTE, 1, 70, zoom_step, 1);
+
+	info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_COLORFX, 4, 0, V4L2_COLORFX_NONE);
+
+	info->wdr = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_WIDE_DYNAMIC_RANGE, 0, 1, 1, 0);
+
+	info->stabilization = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_IMAGE_STABILIZATION, 0, 1, 1, 0);
+
+	info->jpeg_quality = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 80);
+
+	info->lock_3a = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+			V4L2_CID_3A_LOCK, 0, 0x7, 0, 0);
+
+	if (info->handle.error) {
+		int ret = info->handle.error;
+		v4l2_err(sd, "Failed to initialize controls: %d\n", ret);
+		v4l2_ctrl_handler_free(&info->handle);
+		return ret;
+	}
+
+	v4l2_ctrl_auto_cluster(4, &info->auto_exposure, 1, false);
+	info->auto_iso->flags |= V4L2_CTRL_FLAG_VOLATILE |
+				V4L2_CTRL_FLAG_UPDATE;
+	v4l2_ctrl_auto_cluster(2, &info->auto_iso, 0, false);
+
+	info->lock_3a->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+	m5mols_set_ctrl_mode(info->auto_exposure, REG_PARAMETER);
+	m5mols_set_ctrl_mode(info->auto_wb, REG_PARAMETER);
+	m5mols_set_ctrl_mode(info->colorfx, REG_MONITOR);
+
+	sd->ctrl_handler = &info->handle;
+
+	return 0;
+}
diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c
new file mode 100644
index 0000000..ac7d28b
--- /dev/null
+++ b/drivers/media/i2c/m5mols/m5mols_core.c
@@ -0,0 +1,990 @@
+/*
+ * Driver for M-5MOLS 8M Pixel camera sensor with ISP
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Author: HeungJun Kim <riverful.kim@samsung.com>
+ *
+ * Copyright (C) 2009 Samsung Electronics Co., Ltd.
+ * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/m5mols.h>
+
+#include "m5mols.h"
+#include "m5mols_reg.h"
+
+int m5mols_debug;
+module_param(m5mols_debug, int, 0644);
+
+#define MODULE_NAME		"M5MOLS"
+#define M5MOLS_I2C_CHECK_RETRY	500
+
+/* The regulator consumer names for external voltage regulators */
+static struct regulator_bulk_data supplies[] = {
+	{
+		.supply = "core",	/* ARM core power, 1.2V */
+	}, {
+		.supply	= "dig_18",	/* digital power 1, 1.8V */
+	}, {
+		.supply	= "d_sensor",	/* sensor power 1, 1.8V */
+	}, {
+		.supply	= "dig_28",	/* digital power 2, 2.8V */
+	}, {
+		.supply	= "a_sensor",	/* analog power */
+	}, {
+		.supply	= "dig_12",	/* digital power 3, 1.2V */
+	},
+};
+
+static struct v4l2_mbus_framefmt m5mols_default_ffmt[M5MOLS_RESTYPE_MAX] = {
+	[M5MOLS_RESTYPE_MONITOR] = {
+		.width		= 1920,
+		.height		= 1080,
+		.code		= V4L2_MBUS_FMT_VYUY8_2X8,
+		.field		= V4L2_FIELD_NONE,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+	},
+	[M5MOLS_RESTYPE_CAPTURE] = {
+		.width		= 1920,
+		.height		= 1080,
+		.code		= V4L2_MBUS_FMT_JPEG_1X8,
+		.field		= V4L2_FIELD_NONE,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+	},
+};
+#define SIZE_DEFAULT_FFMT	ARRAY_SIZE(m5mols_default_ffmt)
+
+static const struct m5mols_resolution m5mols_reg_res[] = {
+	{ 0x01, M5MOLS_RESTYPE_MONITOR, 128, 96 },	/* SUB-QCIF */
+	{ 0x03, M5MOLS_RESTYPE_MONITOR, 160, 120 },	/* QQVGA */
+	{ 0x05, M5MOLS_RESTYPE_MONITOR, 176, 144 },	/* QCIF */
+	{ 0x06, M5MOLS_RESTYPE_MONITOR, 176, 176 },
+	{ 0x08, M5MOLS_RESTYPE_MONITOR, 240, 320 },	/* QVGA */
+	{ 0x09, M5MOLS_RESTYPE_MONITOR, 320, 240 },	/* QVGA */
+	{ 0x0c, M5MOLS_RESTYPE_MONITOR, 240, 400 },	/* WQVGA */
+	{ 0x0d, M5MOLS_RESTYPE_MONITOR, 400, 240 },	/* WQVGA */
+	{ 0x0e, M5MOLS_RESTYPE_MONITOR, 352, 288 },	/* CIF */
+	{ 0x13, M5MOLS_RESTYPE_MONITOR, 480, 360 },
+	{ 0x15, M5MOLS_RESTYPE_MONITOR, 640, 360 },	/* qHD */
+	{ 0x17, M5MOLS_RESTYPE_MONITOR, 640, 480 },	/* VGA */
+	{ 0x18, M5MOLS_RESTYPE_MONITOR, 720, 480 },
+	{ 0x1a, M5MOLS_RESTYPE_MONITOR, 800, 480 },	/* WVGA */
+	{ 0x1f, M5MOLS_RESTYPE_MONITOR, 800, 600 },	/* SVGA */
+	{ 0x21, M5MOLS_RESTYPE_MONITOR, 1280, 720 },	/* HD */
+	{ 0x25, M5MOLS_RESTYPE_MONITOR, 1920, 1080 },	/* 1080p */
+	{ 0x29, M5MOLS_RESTYPE_MONITOR, 3264, 2448 },	/* 2.63fps 8M */
+	{ 0x39, M5MOLS_RESTYPE_MONITOR, 800, 602 },	/* AHS_MON debug */
+
+	{ 0x02, M5MOLS_RESTYPE_CAPTURE, 320, 240 },	/* QVGA */
+	{ 0x04, M5MOLS_RESTYPE_CAPTURE, 400, 240 },	/* WQVGA */
+	{ 0x07, M5MOLS_RESTYPE_CAPTURE, 480, 360 },
+	{ 0x08, M5MOLS_RESTYPE_CAPTURE, 640, 360 },	/* qHD */
+	{ 0x09, M5MOLS_RESTYPE_CAPTURE, 640, 480 },	/* VGA */
+	{ 0x0a, M5MOLS_RESTYPE_CAPTURE, 800, 480 },	/* WVGA */
+	{ 0x10, M5MOLS_RESTYPE_CAPTURE, 1280, 720 },	/* HD */
+	{ 0x14, M5MOLS_RESTYPE_CAPTURE, 1280, 960 },	/* 1M */
+	{ 0x17, M5MOLS_RESTYPE_CAPTURE, 1600, 1200 },	/* 2M */
+	{ 0x19, M5MOLS_RESTYPE_CAPTURE, 1920, 1080 },	/* Full-HD */
+	{ 0x1a, M5MOLS_RESTYPE_CAPTURE, 2048, 1152 },	/* 3Mega */
+	{ 0x1b, M5MOLS_RESTYPE_CAPTURE, 2048, 1536 },
+	{ 0x1c, M5MOLS_RESTYPE_CAPTURE, 2560, 1440 },	/* 4Mega */
+	{ 0x1d, M5MOLS_RESTYPE_CAPTURE, 2560, 1536 },
+	{ 0x1f, M5MOLS_RESTYPE_CAPTURE, 2560, 1920 },	/* 5Mega */
+	{ 0x21, M5MOLS_RESTYPE_CAPTURE, 3264, 1836 },	/* 6Mega */
+	{ 0x22, M5MOLS_RESTYPE_CAPTURE, 3264, 1960 },
+	{ 0x25, M5MOLS_RESTYPE_CAPTURE, 3264, 2448 },	/* 8Mega */
+};
+
+/**
+ * m5mols_swap_byte - an byte array to integer conversion function
+ * @size: size in bytes of I2C packet defined in the M-5MOLS datasheet
+ *
+ * Convert I2C data byte array with performing any required byte
+ * reordering to assure proper values for each data type, regardless
+ * of the architecture endianness.
+ */
+static u32 m5mols_swap_byte(u8 *data, u8 length)
+{
+	if (length == 1)
+		return *data;
+	else if (length == 2)
+		return be16_to_cpu(*((u16 *)data));
+	else
+		return be32_to_cpu(*((u32 *)data));
+}
+
+/**
+ * m5mols_read -  I2C read function
+ * @reg: combination of size, category and command for the I2C packet
+ * @size: desired size of I2C packet
+ * @val: read value
+ *
+ * Returns 0 on success, or else negative errno.
+ */
+static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct m5mols_info *info = to_m5mols(sd);
+	u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1];
+	u8 category = I2C_CATEGORY(reg);
+	u8 cmd = I2C_COMMAND(reg);
+	struct i2c_msg msg[2];
+	u8 wbuf[5];
+	int ret;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	msg[0].addr = client->addr;
+	msg[0].flags = 0;
+	msg[0].len = 5;
+	msg[0].buf = wbuf;
+	wbuf[0] = 5;
+	wbuf[1] = M5MOLS_BYTE_READ;
+	wbuf[2] = category;
+	wbuf[3] = cmd;
+	wbuf[4] = size;
+
+	msg[1].addr = client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = size + 1;
+	msg[1].buf = rbuf;
+
+	/* minimum stabilization time */
+	usleep_range(200, 200);
+
+	ret = i2c_transfer(client->adapter, msg, 2);
+
+	if (ret == 2) {
+		*val = m5mols_swap_byte(&rbuf[1], size);
+		return 0;
+	}
+
+	if (info->isp_ready)
+		v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n",
+			 size, category, cmd, ret);
+
+	return ret < 0 ? ret : -EIO;
+}
+
+int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg, u8 *val)
+{
+	u32 val_32;
+	int ret;
+
+	if (I2C_SIZE(reg) != 1) {
+		v4l2_err(sd, "Wrong data size\n");
+		return -EINVAL;
+	}
+
+	ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32);
+	if (ret)
+		return ret;
+
+	*val = (u8)val_32;
+	return ret;
+}
+
+int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg, u16 *val)
+{
+	u32 val_32;
+	int ret;
+
+	if (I2C_SIZE(reg) != 2) {
+		v4l2_err(sd, "Wrong data size\n");
+		return -EINVAL;
+	}
+
+	ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32);
+	if (ret)
+		return ret;
+
+	*val = (u16)val_32;
+	return ret;
+}
+
+int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg, u32 *val)
+{
+	if (I2C_SIZE(reg) != 4) {
+		v4l2_err(sd, "Wrong data size\n");
+		return -EINVAL;
+	}
+
+	return m5mols_read(sd, I2C_SIZE(reg), reg, val);
+}
+
+/**
+ * m5mols_write - I2C command write function
+ * @reg: combination of size, category and command for the I2C packet
+ * @val: value to write
+ *
+ * Returns 0 on success, or else negative errno.
+ */
+int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct m5mols_info *info = to_m5mols(sd);
+	u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4];
+	u8 category = I2C_CATEGORY(reg);
+	u8 cmd = I2C_COMMAND(reg);
+	u8 size	= I2C_SIZE(reg);
+	u32 *buf = (u32 *)&wbuf[4];
+	struct i2c_msg msg[1];
+	int ret;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	if (size != 1 && size != 2 && size != 4) {
+		v4l2_err(sd, "Wrong data size\n");
+		return -EINVAL;
+	}
+
+	msg->addr = client->addr;
+	msg->flags = 0;
+	msg->len = (u16)size + 4;
+	msg->buf = wbuf;
+	wbuf[0] = size + 4;
+	wbuf[1] = M5MOLS_BYTE_WRITE;
+	wbuf[2] = category;
+	wbuf[3] = cmd;
+
+	*buf = m5mols_swap_byte((u8 *)&val, size);
+
+	usleep_range(200, 200);
+
+	ret = i2c_transfer(client->adapter, msg, 1);
+	if (ret == 1)
+		return 0;
+
+	if (info->isp_ready)
+		v4l2_err(sd, "write failed: cat:%02x cmd:%02x ret:%d\n",
+			 category, cmd, ret);
+
+	return ret < 0 ? ret : -EIO;
+}
+
+/**
+ * m5mols_busy_wait - Busy waiting with I2C register polling
+ * @reg: the I2C_REG() address of an 8-bit status register to check
+ * @value: expected status register value
+ * @mask: bit mask for the read status register value
+ * @timeout: timeout in miliseconds, or -1 for default timeout
+ *
+ * The @reg register value is ORed with @mask before comparing with @value.
+ *
+ * Return: 0 if the requested condition became true within less than
+ *         @timeout ms, or else negative errno.
+ */
+int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask,
+		     int timeout)
+{
+	int ms = timeout < 0 ? M5MOLS_BUSY_WAIT_DEF_TIMEOUT : timeout;
+	unsigned long end = jiffies + msecs_to_jiffies(ms);
+	u8 status;
+
+	do {
+		int ret = m5mols_read_u8(sd, reg, &status);
+
+		if (ret < 0 && !(mask & M5MOLS_I2C_RDY_WAIT_FL))
+			return ret;
+		if (!ret && (status & mask & 0xff) == (value & 0xff))
+			return 0;
+		usleep_range(100, 250);
+	} while (ms > 0 && time_is_after_jiffies(end));
+
+	return -EBUSY;
+}
+
+/**
+ * m5mols_enable_interrupt - Clear interrupt pending bits and unmask interrupts
+ *
+ * Before writing desired interrupt value the INT_FACTOR register should
+ * be read to clear pending interrupts.
+ */
+int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg)
+{
+	struct m5mols_info *info = to_m5mols(sd);
+	u8 mask = is_available_af(info) ? REG_INT_AF : 0;
+	u8 dummy;
+	int ret;
+
+	ret = m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &dummy);
+	if (!ret)
+		ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask);
+	return ret;
+}
+
+int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 irq_mask, u32 timeout)
+{
+	struct m5mols_info *info = to_m5mols(sd);
+
+	int ret = wait_event_interruptible_timeout(info->irq_waitq,
+				atomic_add_unless(&info->irq_done, -1, 0),
+				msecs_to_jiffies(timeout));
+	if (ret <= 0)
+		return ret ? ret : -ETIMEDOUT;
+
+	return m5mols_busy_wait(sd, SYSTEM_INT_FACTOR, irq_mask,
+				M5MOLS_I2C_RDY_WAIT_FL | irq_mask, -1);
+}
+
+/**
+ * m5mols_reg_mode - Write the mode and check busy status
+ *
+ * It always accompanies a little delay changing the M-5MOLS mode, so it is
+ * needed checking current busy status to guarantee right mode.
+ */
+static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode)
+{
+	int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode);
+	if (ret < 0)
+		return ret;
+	return m5mols_busy_wait(sd, SYSTEM_SYSMODE, mode, 0xff,
+				M5MOLS_MODE_CHANGE_TIMEOUT);
+}
+
+/**
+ * m5mols_set_mode - set the M-5MOLS controller mode
+ * @mode: the required operation mode
+ *
+ * The commands of M-5MOLS are grouped into specific modes. Each functionality
+ * can be guaranteed only when the sensor is operating in mode which a command
+ * belongs to.
+ */
+int m5mols_set_mode(struct m5mols_info *info, u8 mode)
+{
+	struct v4l2_subdev *sd = &info->sd;
+	int ret = -EINVAL;
+	u8 reg;
+
+	if (mode < REG_PARAMETER || mode > REG_CAPTURE)
+		return ret;
+
+	ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, &reg);
+	if (ret || reg == mode)
+		return ret;
+
+	switch (reg) {
+	case REG_PARAMETER:
+		ret = m5mols_reg_mode(sd, REG_MONITOR);
+		if (mode == REG_MONITOR)
+			break;
+		if (!ret)
+			ret = m5mols_reg_mode(sd, REG_CAPTURE);
+		break;
+
+	case REG_MONITOR:
+		if (mode == REG_PARAMETER) {
+			ret = m5mols_reg_mode(sd, REG_PARAMETER);
+			break;
+		}
+
+		ret = m5mols_reg_mode(sd, REG_CAPTURE);
+		break;
+
+	case REG_CAPTURE:
+		ret = m5mols_reg_mode(sd, REG_MONITOR);
+		if (mode == REG_MONITOR)
+			break;
+		if (!ret)
+			ret = m5mols_reg_mode(sd, REG_PARAMETER);
+		break;
+
+	default:
+		v4l2_warn(sd, "Wrong mode: %d\n", mode);
+	}
+
+	if (!ret)
+		info->mode = mode;
+
+	return ret;
+}
+
+/**
+ * m5mols_get_version - retrieve full revisions information of M-5MOLS
+ *
+ * The version information includes revisions of hardware and firmware,
+ * AutoFocus alghorithm version and the version string.
+ */
+static int m5mols_get_version(struct v4l2_subdev *sd)
+{
+	struct m5mols_info *info = to_m5mols(sd);
+	struct m5mols_version *ver = &info->ver;
+	u8 *str = ver->str;
+	int i;
+	int ret;
+
+	ret = m5mols_read_u8(sd, SYSTEM_VER_CUSTOMER, &ver->customer);
+	if (!ret)
+		ret = m5mols_read_u8(sd, SYSTEM_VER_PROJECT, &ver->project);
+	if (!ret)
+		ret = m5mols_read_u16(sd, SYSTEM_VER_FIRMWARE, &ver->fw);
+	if (!ret)
+		ret = m5mols_read_u16(sd, SYSTEM_VER_HARDWARE, &ver->hw);
+	if (!ret)
+		ret = m5mols_read_u16(sd, SYSTEM_VER_PARAMETER, &ver->param);
+	if (!ret)
+		ret = m5mols_read_u16(sd, SYSTEM_VER_AWB, &ver->awb);
+	if (!ret)
+		ret = m5mols_read_u8(sd, AF_VERSION, &ver->af);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < VERSION_STRING_SIZE; i++) {
+		ret = m5mols_read_u8(sd, SYSTEM_VER_STRING, &str[i]);
+		if (ret)
+			return ret;
+	}
+
+	ver->fw = be16_to_cpu(ver->fw);
+	ver->hw = be16_to_cpu(ver->hw);
+	ver->param = be16_to_cpu(ver->param);
+	ver->awb = be16_to_cpu(ver->awb);
+
+	v4l2_info(sd, "Manufacturer\t[%s]\n",
+			is_manufacturer(info, REG_SAMSUNG_ELECTRO) ?
+			"Samsung Electro-Machanics" :
+			is_manufacturer(info, REG_SAMSUNG_OPTICS) ?
+			"Samsung Fiber-Optics" :
+			is_manufacturer(info, REG_SAMSUNG_TECHWIN) ?
+			"Samsung Techwin" : "None");
+	v4l2_info(sd, "Customer/Project\t[0x%02x/0x%02x]\n",
+			info->ver.customer, info->ver.project);
+
+	if (!is_available_af(info))
+		v4l2_info(sd, "No support Auto Focus on this firmware\n");
+
+	return ret;
+}
+
+/**
+ * __find_restype - Lookup M-5MOLS resolution type according to pixel code
+ * @code: pixel code
+ */
+static enum m5mols_restype __find_restype(enum v4l2_mbus_pixelcode code)
+{
+	enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR;
+
+	do {
+		if (code == m5mols_default_ffmt[type].code)
+			return type;
+	} while (type++ != SIZE_DEFAULT_FFMT);
+
+	return 0;
+}
+
+/**
+ * __find_resolution - Lookup preset and type of M-5MOLS's resolution
+ * @mf: pixel format to find/negotiate the resolution preset for
+ * @type: M-5MOLS resolution type
+ * @resolution:	M-5MOLS resolution preset register value
+ *
+ * Find nearest resolution matching resolution preset and adjust mf
+ * to supported values.
+ */
+static int __find_resolution(struct v4l2_subdev *sd,
+			     struct v4l2_mbus_framefmt *mf,
+			     enum m5mols_restype *type,
+			     u32 *resolution)
+{
+	const struct m5mols_resolution *fsize = &m5mols_reg_res[0];
+	const struct m5mols_resolution *match = NULL;
+	enum m5mols_restype stype = __find_restype(mf->code);
+	int i = ARRAY_SIZE(m5mols_reg_res);
+	unsigned int min_err = ~0;
+
+	while (i--) {
+		int err;
+		if (stype == fsize->type) {
+			err = abs(fsize->width - mf->width)
+				+ abs(fsize->height - mf->height);
+
+			if (err < min_err) {
+				min_err = err;
+				match = fsize;
+			}
+		}
+		fsize++;
+	}
+	if (match) {
+		mf->width  = match->width;
+		mf->height = match->height;
+		*resolution = match->reg;
+		*type = stype;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info,
+				struct v4l2_subdev_fh *fh,
+				enum v4l2_subdev_format_whence which,
+				enum m5mols_restype type)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL;
+
+	return &info->ffmt[type];
+}
+
+static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			  struct v4l2_subdev_format *fmt)
+{
+	struct m5mols_info *info = to_m5mols(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	format = __find_format(info, fh, fmt->which, info->res_type);
+	if (!format)
+		return -EINVAL;
+
+	fmt->format = *format;
+	return 0;
+}
+
+static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			  struct v4l2_subdev_format *fmt)
+{
+	struct m5mols_info *info = to_m5mols(sd);
+	struct v4l2_mbus_framefmt *format = &fmt->format;
+	struct v4l2_mbus_framefmt *sfmt;
+	enum m5mols_restype type;
+	u32 resolution = 0;
+	int ret;
+
+	ret = __find_resolution(sd, format, &type, &resolution);
+	if (ret < 0)
+		return ret;
+
+	sfmt = __find_format(info, fh, fmt->which, type);
+	if (!sfmt)
+		return 0;
+
+
+	format->code = m5mols_default_ffmt[type].code;
+	format->colorspace = V4L2_COLORSPACE_JPEG;
+	format->field = V4L2_FIELD_NONE;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		*sfmt = *format;
+		info->resolution = resolution;
+		info->res_type = type;
+	}
+
+	return 0;
+}
+
+static int m5mols_enum_mbus_code(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (!code || code->index >= SIZE_DEFAULT_FFMT)
+		return -EINVAL;
+
+	code->code = m5mols_default_ffmt[code->index].code;
+
+	return 0;
+}
+
+static struct v4l2_subdev_pad_ops m5mols_pad_ops = {
+	.enum_mbus_code	= m5mols_enum_mbus_code,
+	.get_fmt	= m5mols_get_fmt,
+	.set_fmt	= m5mols_set_fmt,
+};
+
+/**
+ * m5mols_restore_controls - Apply current control values to the registers
+ *
+ * m5mols_do_scenemode() handles all parameters for which there is yet no
+ * individual control. It should be replaced at some point by setting each
+ * control individually, in required register set up order.
+ */
+int m5mols_restore_controls(struct m5mols_info *info)
+{
+	int ret;
+
+	if (info->ctrl_sync)
+		return 0;
+
+	ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL);
+	if (ret)
+		return ret;
+
+	ret = v4l2_ctrl_handler_setup(&info->handle);
+	info->ctrl_sync = !ret;
+
+	return ret;
+}
+
+/**
+ * m5mols_start_monitor - Start the monitor mode
+ *
+ * Before applying the controls setup the resolution and frame rate
+ * in PARAMETER mode, and then switch over to MONITOR mode.
+ */
+static int m5mols_start_monitor(struct m5mols_info *info)
+{
+	struct v4l2_subdev *sd = &info->sd;
+	int ret;
+
+	ret = m5mols_set_mode(info, REG_PARAMETER);
+	if (!ret)
+		ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution);
+	if (!ret)
+		ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30);
+	if (!ret)
+		ret = m5mols_set_mode(info, REG_MONITOR);
+	if (!ret)
+		ret = m5mols_restore_controls(info);
+
+	return ret;
+}
+
+static int m5mols_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct m5mols_info *info = to_m5mols(sd);
+	u32 code = info->ffmt[info->res_type].code;
+
+	if (enable) {
+		int ret = -EINVAL;
+
+		if (is_code(code, M5MOLS_RESTYPE_MONITOR))
+			ret = m5mols_start_monitor(info);
+		if (is_code(code, M5MOLS_RESTYPE_CAPTURE))
+			ret = m5mols_start_capture(info);
+
+		return ret;
+	}
+
+	return m5mols_set_mode(info, REG_PARAMETER);
+}
+
+static const struct v4l2_subdev_video_ops m5mols_video_ops = {
+	.s_stream	= m5mols_s_stream,
+};
+
+static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
+{
+	struct v4l2_subdev *sd = &info->sd;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	const struct m5mols_platform_data *pdata = info->pdata;
+	int ret;
+
+	if (info->power == enable)
+		return 0;
+
+	if (enable) {
+		if (info->set_power) {
+			ret = info->set_power(&client->dev, 1);
+			if (ret)
+				return ret;
+		}
+
+		ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
+		if (ret) {
+			info->set_power(&client->dev, 0);
+			return ret;
+		}
+
+		gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity);
+		info->power = 1;
+
+		return ret;
+	}
+
+	ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
+	if (ret)
+		return ret;
+
+	if (info->set_power)
+		info->set_power(&client->dev, 0);
+
+	gpio_set_value(pdata->gpio_reset, pdata->reset_polarity);
+
+	info->isp_ready = 0;
+	info->power = 0;
+
+	return ret;
+}
+
+/* m5mols_update_fw - optional firmware update routine */
+int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd,
+		int (*set_power)(struct m5mols_info *, bool))
+{
+	return 0;
+}
+
+/**
+ * m5mols_fw_start - M-5MOLS internal ARM controller initialization
+ *
+ * Execute the M-5MOLS internal ARM controller initialization sequence.
+ * This function should be called after the supply voltage has been
+ * applied and before any requests to the device are made.
+ */
+static int m5mols_fw_start(struct v4l2_subdev *sd)
+{
+	struct m5mols_info *info = to_m5mols(sd);
+	int ret;
+
+	atomic_set(&info->irq_done, 0);
+	/* Wait until I2C slave is initialized in Flash Writer mode */
+	ret = m5mols_busy_wait(sd, FLASH_CAM_START, REG_IN_FLASH_MODE,
+			       M5MOLS_I2C_RDY_WAIT_FL | 0xff, -1);
+	if (!ret)
+		ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT);
+	if (!ret)
+		ret = m5mols_wait_interrupt(sd, REG_INT_MODE, 2000);
+	if (ret < 0)
+		return ret;
+
+	info->isp_ready = 1;
+
+	ret = m5mols_get_version(sd);
+	if (!ret)
+		ret = m5mols_update_fw(sd, m5mols_sensor_power);
+	if (ret)
+		return ret;
+
+	v4l2_dbg(1, m5mols_debug, sd, "Success ARM Booting\n");
+
+	ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI);
+	if (!ret)
+		ret = m5mols_enable_interrupt(sd,
+				REG_INT_AF | REG_INT_CAPTURE);
+
+	return ret;
+}
+
+/**
+ * m5mols_s_power - Main sensor power control function
+ *
+ * To prevent breaking the lens when the sensor is powered off the Soft-Landing
+ * algorithm is called where available. The Soft-Landing algorithm availability
+ * dependends on the firmware provider.
+ */
+static int m5mols_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct m5mols_info *info = to_m5mols(sd);
+	int ret;
+
+	if (on) {
+		ret = m5mols_sensor_power(info, true);
+		if (!ret)
+			ret = m5mols_fw_start(sd);
+		return ret;
+	}
+
+	if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) {
+		ret = m5mols_set_mode(info, REG_MONITOR);
+		if (!ret)
+			ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP);
+		if (!ret)
+			ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF);
+		if (!ret)
+			ret = m5mols_busy_wait(sd, SYSTEM_STATUS, REG_AF_IDLE,
+					       0xff, -1);
+		if (ret < 0)
+			v4l2_warn(sd, "Soft landing lens failed\n");
+	}
+
+	ret = m5mols_sensor_power(info, false);
+	info->ctrl_sync = 0;
+
+	return ret;
+}
+
+static int m5mols_log_status(struct v4l2_subdev *sd)
+{
+	struct m5mols_info *info = to_m5mols(sd);
+
+	v4l2_ctrl_handler_log_status(&info->handle, sd->name);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_core_ops m5mols_core_ops = {
+	.s_power	= m5mols_s_power,
+	.g_ctrl		= v4l2_subdev_g_ctrl,
+	.s_ctrl		= v4l2_subdev_s_ctrl,
+	.queryctrl	= v4l2_subdev_queryctrl,
+	.querymenu	= v4l2_subdev_querymenu,
+	.g_ext_ctrls	= v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls	= v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls	= v4l2_subdev_s_ext_ctrls,
+	.log_status	= m5mols_log_status,
+};
+
+/*
+ * V4L2 subdev internal operations
+ */
+static int m5mols_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
+
+	*format = m5mols_default_ffmt[0];
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops m5mols_subdev_internal_ops = {
+	.open		= m5mols_open,
+};
+
+static const struct v4l2_subdev_ops m5mols_ops = {
+	.core		= &m5mols_core_ops,
+	.pad		= &m5mols_pad_ops,
+	.video		= &m5mols_video_ops,
+};
+
+static irqreturn_t m5mols_irq_handler(int irq, void *data)
+{
+	struct m5mols_info *info = to_m5mols(data);
+
+	atomic_set(&info->irq_done, 1);
+	wake_up_interruptible(&info->irq_waitq);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit m5mols_probe(struct i2c_client *client,
+				  const struct i2c_device_id *id)
+{
+	const struct m5mols_platform_data *pdata = client->dev.platform_data;
+	struct m5mols_info *info;
+	struct v4l2_subdev *sd;
+	int ret;
+
+	if (pdata == NULL) {
+		dev_err(&client->dev, "No platform data\n");
+		return -EINVAL;
+	}
+
+	if (!gpio_is_valid(pdata->gpio_reset)) {
+		dev_err(&client->dev, "No valid RESET GPIO specified\n");
+		return -EINVAL;
+	}
+
+	if (!client->irq) {
+		dev_err(&client->dev, "Interrupt not assigned\n");
+		return -EINVAL;
+	}
+
+	info = kzalloc(sizeof(struct m5mols_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->pdata = pdata;
+	info->set_power	= pdata->set_power;
+
+	ret = gpio_request(pdata->gpio_reset, "M5MOLS_NRST");
+	if (ret) {
+		dev_err(&client->dev, "Failed to request gpio: %d\n", ret);
+		goto out_free;
+	}
+	gpio_direction_output(pdata->gpio_reset, pdata->reset_polarity);
+
+	ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies);
+	if (ret) {
+		dev_err(&client->dev, "Failed to get regulators: %d\n", ret);
+		goto out_gpio;
+	}
+
+	sd = &info->sd;
+	v4l2_i2c_subdev_init(sd, client, &m5mols_ops);
+	strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	sd->internal_ops = &m5mols_subdev_internal_ops;
+	info->pad.flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_init(&sd->entity, 1, &info->pad, 0);
+	if (ret < 0)
+		goto out_reg;
+	sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+
+	init_waitqueue_head(&info->irq_waitq);
+	ret = request_irq(client->irq, m5mols_irq_handler,
+			  IRQF_TRIGGER_RISING, MODULE_NAME, sd);
+	if (ret) {
+		dev_err(&client->dev, "Interrupt request failed: %d\n", ret);
+		goto out_me;
+	}
+	info->res_type = M5MOLS_RESTYPE_MONITOR;
+	info->ffmt[0] = m5mols_default_ffmt[0];
+	info->ffmt[1] =	m5mols_default_ffmt[1];
+
+	ret = m5mols_sensor_power(info, true);
+	if (ret)
+		goto out_me;
+
+	ret = m5mols_fw_start(sd);
+	if (!ret)
+		ret = m5mols_init_controls(sd);
+
+	m5mols_sensor_power(info, false);
+	if (!ret)
+		return 0;
+out_me:
+	media_entity_cleanup(&sd->entity);
+out_reg:
+	regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
+out_gpio:
+	gpio_free(pdata->gpio_reset);
+out_free:
+	kfree(info);
+	return ret;
+}
+
+static int __devexit m5mols_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct m5mols_info *info = to_m5mols(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(sd->ctrl_handler);
+	free_irq(client->irq, sd);
+
+	regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
+	gpio_free(info->pdata->gpio_reset);
+	media_entity_cleanup(&sd->entity);
+	kfree(info);
+	return 0;
+}
+
+static const struct i2c_device_id m5mols_id[] = {
+	{ MODULE_NAME, 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, m5mols_id);
+
+static struct i2c_driver m5mols_i2c_driver = {
+	.driver = {
+		.name	= MODULE_NAME,
+	},
+	.probe		= m5mols_probe,
+	.remove		= __devexit_p(m5mols_remove),
+	.id_table	= m5mols_id,
+};
+
+module_i2c_driver(m5mols_i2c_driver);
+
+MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
+MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>");
+MODULE_DESCRIPTION("Fujitsu M-5MOLS 8M Pixel camera driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/m5mols/m5mols_reg.h b/drivers/media/i2c/m5mols/m5mols_reg.h
new file mode 100644
index 0000000..14d4be7
--- /dev/null
+++ b/drivers/media/i2c/m5mols/m5mols_reg.h
@@ -0,0 +1,362 @@
+/*
+ * Register map for M-5MOLS 8M Pixel camera sensor with ISP
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Author: HeungJun Kim <riverful.kim@samsung.com>
+ *
+ * Copyright (C) 2009 Samsung Electronics Co., Ltd.
+ * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef M5MOLS_REG_H
+#define M5MOLS_REG_H
+
+#define M5MOLS_I2C_MAX_SIZE	4
+#define M5MOLS_BYTE_READ	0x01
+#define M5MOLS_BYTE_WRITE	0x02
+
+#define I2C_CATEGORY(__cat)		((__cat >> 16) & 0xff)
+#define I2C_COMMAND(__comm)		((__comm >> 8) & 0xff)
+#define I2C_SIZE(__reg_s)		((__reg_s) & 0xff)
+#define I2C_REG(__cat, __cmd, __reg_s)	((__cat << 16) | (__cmd << 8) | __reg_s)
+
+/*
+ * Category section register
+ *
+ * The category means set including relevant command of M-5MOLS.
+ */
+#define CAT_SYSTEM		0x00
+#define CAT_PARAM		0x01
+#define CAT_MONITOR		0x02
+#define CAT_AE			0x03
+#define CAT_WB			0x06
+#define CAT_EXIF		0x07
+#define CAT_FD			0x09
+#define CAT_LENS		0x0a
+#define CAT_CAPT_PARM		0x0b
+#define CAT_CAPT_CTRL		0x0c
+#define CAT_FLASH		0x0f	/* related to FW, revisions, booting */
+
+/*
+ * Category 0 - SYSTEM mode
+ *
+ * The SYSTEM mode in the M-5MOLS means area available to handle with the whole
+ * & all-round system of sensor. It deals with version/interrupt/setting mode &
+ * even sensor's status. Especially, the M-5MOLS sensor with ISP varies by
+ * packaging & manufacturer, even the customer and project code. And the
+ * function details may vary among them. The version information helps to
+ * determine what methods shall be used in the driver.
+ *
+ * There is many registers between customer version address and awb one. For
+ * more specific contents, see definition if file m5mols.h.
+ */
+#define SYSTEM_VER_CUSTOMER	I2C_REG(CAT_SYSTEM, 0x00, 1)
+#define SYSTEM_VER_PROJECT	I2C_REG(CAT_SYSTEM, 0x01, 1)
+#define SYSTEM_VER_FIRMWARE	I2C_REG(CAT_SYSTEM, 0x02, 2)
+#define SYSTEM_VER_HARDWARE	I2C_REG(CAT_SYSTEM, 0x04, 2)
+#define SYSTEM_VER_PARAMETER	I2C_REG(CAT_SYSTEM, 0x06, 2)
+#define SYSTEM_VER_AWB		I2C_REG(CAT_SYSTEM, 0x08, 2)
+
+#define SYSTEM_SYSMODE		I2C_REG(CAT_SYSTEM, 0x0b, 1)
+#define REG_SYSINIT		0x00	/* SYSTEM mode */
+#define REG_PARAMETER		0x01	/* PARAMETER mode */
+#define REG_MONITOR		0x02	/* MONITOR mode */
+#define REG_CAPTURE		0x03	/* CAPTURE mode */
+
+#define SYSTEM_CMD(__cmd)	I2C_REG(CAT_SYSTEM, cmd, 1)
+#define SYSTEM_VER_STRING	I2C_REG(CAT_SYSTEM, 0x0a, 1)
+#define REG_SAMSUNG_ELECTRO	"SE"	/* Samsung Electro-Mechanics */
+#define REG_SAMSUNG_OPTICS	"OP"	/* Samsung Fiber-Optics */
+#define REG_SAMSUNG_TECHWIN	"TB"	/* Samsung Techwin */
+/* SYSTEM mode status */
+#define SYSTEM_STATUS	I2C_REG(CAT_SYSTEM, 0x0c, 1)
+
+/* Interrupt pending register */
+#define SYSTEM_INT_FACTOR	I2C_REG(CAT_SYSTEM, 0x10, 1)
+/* interrupt enable register */
+#define SYSTEM_INT_ENABLE	I2C_REG(CAT_SYSTEM, 0x11, 1)
+#define REG_INT_MODE		(1 << 0)
+#define REG_INT_AF		(1 << 1)
+#define REG_INT_ZOOM		(1 << 2)
+#define REG_INT_CAPTURE		(1 << 3)
+#define REG_INT_FRAMESYNC	(1 << 4)
+#define REG_INT_FD		(1 << 5)
+#define REG_INT_LENS_INIT	(1 << 6)
+#define REG_INT_SOUND		(1 << 7)
+#define REG_INT_MASK		0x0f
+
+/*
+ * category 1 - PARAMETER mode
+ *
+ * This category supports function of camera features of M-5MOLS. It means we
+ * can handle with preview(MONITOR) resolution size/frame per second/interface
+ * between the sensor and the Application Processor/even the image effect.
+ */
+
+/* Resolution in the MONITOR mode */
+#define PARM_MON_SIZE		I2C_REG(CAT_PARAM, 0x01, 1)
+
+/* Frame rate */
+#define PARM_MON_FPS		I2C_REG(CAT_PARAM, 0x02, 1)
+#define REG_FPS_30		0x02
+
+/* Video bus between the sensor and a host processor */
+#define PARM_INTERFACE		I2C_REG(CAT_PARAM, 0x00, 1)
+#define REG_INTERFACE_MIPI	0x02
+
+/* Image effects */
+#define PARM_EFFECT		I2C_REG(CAT_PARAM, 0x0b, 1)
+#define REG_EFFECT_OFF		0x00
+#define REG_EFFECT_NEGA		0x01
+#define REG_EFFECT_EMBOSS	0x06
+#define REG_EFFECT_OUTLINE	0x07
+#define REG_EFFECT_WATERCOLOR	0x08
+
+/*
+ * Category 2 - MONITOR mode
+ *
+ * The MONITOR mode is same as preview mode as we said. The M-5MOLS has another
+ * mode named "Preview", but this preview mode is used at the case specific
+ * vider-recording mode. This mmode supports only YUYV format. On the other
+ * hand, the JPEG & RAW formats is supports by CAPTURE mode. And, there are
+ * another options like zoom/color effect(different with effect in PARAMETER
+ * mode)/anti hand shaking algorithm.
+ */
+
+/* Target digital zoom position */
+#define MON_ZOOM		I2C_REG(CAT_MONITOR, 0x01, 1)
+
+/* CR value for color effect */
+#define MON_CFIXR		I2C_REG(CAT_MONITOR, 0x0a, 1)
+/* CB value for color effect */
+#define MON_CFIXB		I2C_REG(CAT_MONITOR, 0x09, 1)
+#define REG_CFIXB_SEPIA		0xd8
+#define REG_CFIXR_SEPIA		0x18
+
+#define MON_EFFECT		I2C_REG(CAT_MONITOR, 0x0b, 1)
+#define REG_COLOR_EFFECT_OFF	0x00
+#define REG_COLOR_EFFECT_ON	0x01
+
+/* Chroma enable */
+#define MON_CHROMA_EN		I2C_REG(CAT_MONITOR, 0x10, 1)
+/* Chroma level */
+#define MON_CHROMA_LVL		I2C_REG(CAT_MONITOR, 0x0f, 1)
+#define REG_CHROMA_OFF		0x00
+#define REG_CHROMA_ON		0x01
+
+/* Sharpness on/off */
+#define MON_EDGE_EN		I2C_REG(CAT_MONITOR, 0x12, 1)
+/* Sharpness level */
+#define MON_EDGE_LVL		I2C_REG(CAT_MONITOR, 0x11, 1)
+#define REG_EDGE_OFF		0x00
+#define REG_EDGE_ON		0x01
+
+/* Set color tone (contrast) */
+#define MON_TONE_CTL		I2C_REG(CAT_MONITOR, 0x25, 1)
+
+/*
+ * Category 3 - Auto Exposure
+ *
+ * The M-5MOLS exposure capbility is detailed as which is similar to digital
+ * camera. This category supports AE locking/various AE mode(range of exposure)
+ * /ISO/flickering/EV bias/shutter/meteoring, and anything else. And the
+ * maximum/minimum exposure gain value depending on M-5MOLS firmware, may be
+ * different. So, this category also provide getting the max/min values. And,
+ * each MONITOR and CAPTURE mode has each gain/shutter/max exposure values.
+ */
+
+/* Auto Exposure locking */
+#define AE_LOCK			I2C_REG(CAT_AE, 0x00, 1)
+#define REG_AE_UNLOCK		0x00
+#define REG_AE_LOCK		0x01
+
+/* Auto Exposure algorithm mode */
+#define AE_MODE			I2C_REG(CAT_AE, 0x01, 1)
+#define REG_AE_OFF		0x00	/* AE off */
+#define REG_AE_ALL		0x01	/* calc AE in all block integral */
+#define REG_AE_CENTER		0x03	/* calc AE in center weighted */
+#define REG_AE_SPOT		0x06	/* calc AE in specific spot */
+
+#define AE_ISO			I2C_REG(CAT_AE, 0x05, 1)
+#define REG_ISO_AUTO		0x00
+#define REG_ISO_50		0x01
+#define REG_ISO_100		0x02
+#define REG_ISO_200		0x03
+#define REG_ISO_400		0x04
+#define REG_ISO_800		0x05
+
+/* EV (scenemode) preset for MONITOR */
+#define AE_EV_PRESET_MONITOR	I2C_REG(CAT_AE, 0x0a, 1)
+/* EV (scenemode) preset for CAPTURE */
+#define AE_EV_PRESET_CAPTURE	I2C_REG(CAT_AE, 0x0b, 1)
+#define REG_SCENE_NORMAL	0x00
+#define REG_SCENE_PORTRAIT	0x01
+#define REG_SCENE_LANDSCAPE	0x02
+#define REG_SCENE_SPORTS	0x03
+#define REG_SCENE_PARTY_INDOOR	0x04
+#define REG_SCENE_BEACH_SNOW	0x05
+#define REG_SCENE_SUNSET	0x06
+#define REG_SCENE_DAWN_DUSK	0x07
+#define REG_SCENE_FALL		0x08
+#define REG_SCENE_NIGHT		0x09
+#define REG_SCENE_AGAINST_LIGHT	0x0a
+#define REG_SCENE_FIRE		0x0b
+#define REG_SCENE_TEXT		0x0c
+#define REG_SCENE_CANDLE	0x0d
+
+/* Manual gain in MONITOR mode */
+#define AE_MAN_GAIN_MON		I2C_REG(CAT_AE, 0x12, 2)
+/* Maximum gain in MONITOR mode */
+#define AE_MAX_GAIN_MON		I2C_REG(CAT_AE, 0x1a, 2)
+/* Manual gain in CAPTURE mode */
+#define AE_MAN_GAIN_CAP		I2C_REG(CAT_AE, 0x26, 2)
+
+#define AE_INDEX		I2C_REG(CAT_AE, 0x38, 1)
+#define REG_AE_INDEX_20_NEG	0x00
+#define REG_AE_INDEX_15_NEG	0x01
+#define REG_AE_INDEX_10_NEG	0x02
+#define REG_AE_INDEX_05_NEG	0x03
+#define REG_AE_INDEX_00		0x04
+#define REG_AE_INDEX_05_POS	0x05
+#define REG_AE_INDEX_10_POS	0x06
+#define REG_AE_INDEX_15_POS	0x07
+#define REG_AE_INDEX_20_POS	0x08
+
+/*
+ * Category 6 - White Balance
+ */
+
+/* Auto Whitebalance locking */
+#define AWB_LOCK		I2C_REG(CAT_WB, 0x00, 1)
+#define REG_AWB_UNLOCK		0x00
+#define REG_AWB_LOCK		0x01
+
+#define AWB_MODE		I2C_REG(CAT_WB, 0x02, 1)
+#define REG_AWB_AUTO		0x01	/* AWB off */
+#define REG_AWB_PRESET		0x02	/* AWB preset */
+
+/* Manual WB (preset) */
+#define AWB_MANUAL		I2C_REG(CAT_WB, 0x03, 1)
+#define REG_AWB_INCANDESCENT	0x01
+#define REG_AWB_FLUORESCENT_1	0x02
+#define REG_AWB_FLUORESCENT_2	0x03
+#define REG_AWB_DAYLIGHT	0x04
+#define REG_AWB_CLOUDY		0x05
+#define REG_AWB_SHADE		0x06
+#define REG_AWB_HORIZON		0x07
+#define REG_AWB_LEDLIGHT	0x09
+
+/*
+ * Category 7 - EXIF information
+ */
+#define EXIF_INFO_EXPTIME_NU	I2C_REG(CAT_EXIF, 0x00, 4)
+#define EXIF_INFO_EXPTIME_DE	I2C_REG(CAT_EXIF, 0x04, 4)
+#define EXIF_INFO_TV_NU		I2C_REG(CAT_EXIF, 0x08, 4)
+#define EXIF_INFO_TV_DE		I2C_REG(CAT_EXIF, 0x0c, 4)
+#define EXIF_INFO_AV_NU		I2C_REG(CAT_EXIF, 0x10, 4)
+#define EXIF_INFO_AV_DE		I2C_REG(CAT_EXIF, 0x14, 4)
+#define EXIF_INFO_BV_NU		I2C_REG(CAT_EXIF, 0x18, 4)
+#define EXIF_INFO_BV_DE		I2C_REG(CAT_EXIF, 0x1c, 4)
+#define EXIF_INFO_EBV_NU	I2C_REG(CAT_EXIF, 0x20, 4)
+#define EXIF_INFO_EBV_DE	I2C_REG(CAT_EXIF, 0x24, 4)
+#define EXIF_INFO_ISO		I2C_REG(CAT_EXIF, 0x28, 2)
+#define EXIF_INFO_FLASH		I2C_REG(CAT_EXIF, 0x2a, 2)
+#define EXIF_INFO_SDR		I2C_REG(CAT_EXIF, 0x2c, 2)
+#define EXIF_INFO_QVAL		I2C_REG(CAT_EXIF, 0x2e, 2)
+
+/*
+ * Category 9 - Face Detection
+ */
+#define FD_CTL			I2C_REG(CAT_FD, 0x00, 1)
+#define BIT_FD_EN		0
+#define BIT_FD_DRAW_FACE_FRAME	4
+#define BIT_FD_DRAW_SMILE_LVL	6
+#define REG_FD(shift)		(1 << shift)
+#define REG_FD_OFF		0x0
+
+/*
+ * Category A - Lens Parameter
+ */
+#define AF_MODE			I2C_REG(CAT_LENS, 0x01, 1)
+#define REG_AF_NORMAL		0x00	/* Normal AF, one time */
+#define REG_AF_MACRO		0x01	/* Macro AF, one time */
+#define REG_AF_POWEROFF		0x07
+
+#define AF_EXECUTE		I2C_REG(CAT_LENS, 0x02, 1)
+#define REG_AF_STOP		0x00
+#define REG_AF_EXE_AUTO		0x01
+#define REG_AF_EXE_CAF		0x02
+
+#define AF_STATUS		I2C_REG(CAT_LENS, 0x03, 1)
+#define REG_AF_FAIL		0x00
+#define REG_AF_SUCCESS		0x02
+#define REG_AF_IDLE		0x04
+#define REG_AF_BUSY		0x05
+
+#define AF_VERSION		I2C_REG(CAT_LENS, 0x0a, 1)
+
+/*
+ * Category B - CAPTURE Parameter
+ */
+#define CAPP_YUVOUT_MAIN	I2C_REG(CAT_CAPT_PARM, 0x00, 1)
+#define REG_YUV422		0x00
+#define REG_BAYER10		0x05
+#define REG_BAYER8		0x06
+#define REG_JPEG		0x10
+
+#define CAPP_MAIN_IMAGE_SIZE	I2C_REG(CAT_CAPT_PARM, 0x01, 1)
+#define CAPP_JPEG_RATIO		I2C_REG(CAT_CAPT_PARM, 0x17, 1)
+
+#define CAPP_MCC_MODE		I2C_REG(CAT_CAPT_PARM, 0x1d, 1)
+#define REG_MCC_OFF		0x00
+#define REG_MCC_NORMAL		0x01
+
+#define CAPP_WDR_EN		I2C_REG(CAT_CAPT_PARM, 0x2c, 1)
+#define REG_WDR_OFF		0x00
+#define REG_WDR_ON		0x01
+#define REG_WDR_AUTO		0x02
+
+#define CAPP_LIGHT_CTRL		I2C_REG(CAT_CAPT_PARM, 0x40, 1)
+#define REG_LIGHT_OFF		0x00
+#define REG_LIGHT_ON		0x01
+#define REG_LIGHT_AUTO		0x02
+
+#define CAPP_FLASH_CTRL		I2C_REG(CAT_CAPT_PARM, 0x41, 1)
+#define REG_FLASH_OFF		0x00
+#define REG_FLASH_ON		0x01
+#define REG_FLASH_AUTO		0x02
+
+/*
+ * Category C - CAPTURE Control
+ */
+#define CAPC_MODE		I2C_REG(CAT_CAPT_CTRL, 0x00, 1)
+#define REG_CAP_NONE		0x00
+#define REG_CAP_ANTI_SHAKE	0x02
+
+/* Select single- or multi-shot capture */
+#define CAPC_SEL_FRAME		I2C_REG(CAT_CAPT_CTRL, 0x06, 1)
+
+#define CAPC_START		I2C_REG(CAT_CAPT_CTRL, 0x09, 1)
+#define REG_CAP_START_MAIN	0x01
+#define REG_CAP_START_THUMB	0x03
+
+#define CAPC_IMAGE_SIZE		I2C_REG(CAT_CAPT_CTRL, 0x0d, 4)
+#define CAPC_THUMB_SIZE		I2C_REG(CAT_CAPT_CTRL, 0x11, 4)
+
+/*
+ * Category F - Flash
+ *
+ * This mode provides functions about internal flash stuff and system startup.
+ */
+
+/* Starts internal ARM core booting after power-up */
+#define FLASH_CAM_START		I2C_REG(CAT_FLASH, 0x12, 1)
+#define REG_START_ARM_BOOT	0x01	/* write value */
+#define REG_IN_FLASH_MODE	0x00	/* read value */
+
+#endif	/* M5MOLS_REG_H */
diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c
new file mode 100644
index 0000000..aeb22be
--- /dev/null
+++ b/drivers/media/i2c/msp3400-driver.c
@@ -0,0 +1,899 @@
+/*
+ * Programming the mspx4xx sound processor family
+ *
+ * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org>
+ *
+ * what works and what doesn't:
+ *
+ *  AM-Mono
+ *      Support for Hauppauge cards added (decoding handled by tuner) added by
+ *      Frederic Crozat <fcrozat@mail.dotcom.fr>
+ *
+ *  FM-Mono
+ *      should work. The stereo modes are backward compatible to FM-mono,
+ *      therefore FM-Mono should be allways available.
+ *
+ *  FM-Stereo (B/G, used in germany)
+ *      should work, with autodetect
+ *
+ *  FM-Stereo (satellite)
+ *      should work, no autodetect (i.e. default is mono, but you can
+ *      switch to stereo -- untested)
+ *
+ *  NICAM (B/G, L , used in UK, Scandinavia, Spain and France)
+ *      should work, with autodetect. Support for NICAM was added by
+ *      Pekka Pietikainen <pp@netppl.fi>
+ *
+ * TODO:
+ *   - better SAT support
+ *
+ * 980623  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *         using soundcore instead of OSS
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/msp3400.h>
+#include <media/tvaudio.h>
+#include "msp3400-driver.h"
+
+/* ---------------------------------------------------------------------- */
+
+MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
+MODULE_AUTHOR("Gerd Knorr");
+MODULE_LICENSE("GPL");
+
+/* module parameters */
+static int opmode   = OPMODE_AUTO;
+int msp_debug;		 /* msp_debug output */
+bool msp_once;		 /* no continuous stereo monitoring */
+bool msp_amsound;	 /* hard-wire AM sound at 6.5 Hz (france),
+			    the autoscan seems work well only with FM... */
+int msp_standard = 1;    /* Override auto detect of audio msp_standard,
+			    if needed. */
+bool msp_dolby;
+
+int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual
+					(msp34xxg only) 0x00a0-0x03c0 */
+
+/* read-only */
+module_param(opmode,           int, 0444);
+
+/* read-write */
+module_param_named(once, msp_once,                      bool, 0644);
+module_param_named(debug, msp_debug,                    int,  0644);
+module_param_named(stereo_threshold, msp_stereo_thresh, int,  0644);
+module_param_named(standard, msp_standard,              int,  0644);
+module_param_named(amsound, msp_amsound,                bool, 0644);
+module_param_named(dolby, msp_dolby,                    bool, 0644);
+
+MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect");
+MODULE_PARM_DESC(once, "No continuous stereo monitoring");
+MODULE_PARM_DESC(debug, "Enable debug messages [0-3]");
+MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo");
+MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect");
+MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan");
+MODULE_PARM_DESC(dolby, "Activates Dolby processing");
+
+/* ---------------------------------------------------------------------- */
+
+/* control subaddress */
+#define I2C_MSP_CONTROL 0x00
+/* demodulator unit subaddress */
+#define I2C_MSP_DEM     0x10
+/* DSP unit subaddress */
+#define I2C_MSP_DSP     0x12
+
+
+/* ----------------------------------------------------------------------- */
+/* functions for talking to the MSP3400C Sound processor                   */
+
+int msp_reset(struct i2c_client *client)
+{
+	/* reset and read revision code */
+	static u8 reset_off[3] = { I2C_MSP_CONTROL, 0x80, 0x00 };
+	static u8 reset_on[3]  = { I2C_MSP_CONTROL, 0x00, 0x00 };
+	static u8 write[3]     = { I2C_MSP_DSP + 1, 0x00, 0x1e };
+	u8 read[2];
+	struct i2c_msg reset[2] = {
+		{ client->addr, I2C_M_IGNORE_NAK, 3, reset_off },
+		{ client->addr, I2C_M_IGNORE_NAK, 3, reset_on  },
+	};
+	struct i2c_msg test[2] = {
+		{ client->addr, 0,        3, write },
+		{ client->addr, I2C_M_RD, 2, read  },
+	};
+
+	v4l_dbg(3, msp_debug, client, "msp_reset\n");
+	if (i2c_transfer(client->adapter, &reset[0], 1) != 1 ||
+	    i2c_transfer(client->adapter, &reset[1], 1) != 1 ||
+	    i2c_transfer(client->adapter, test, 2) != 2) {
+		v4l_err(client, "chip reset failed\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int msp_read(struct i2c_client *client, int dev, int addr)
+{
+	int err, retval;
+	u8 write[3];
+	u8 read[2];
+	struct i2c_msg msgs[2] = {
+		{ client->addr, 0,        3, write },
+		{ client->addr, I2C_M_RD, 2, read  }
+	};
+
+	write[0] = dev + 1;
+	write[1] = addr >> 8;
+	write[2] = addr & 0xff;
+
+	for (err = 0; err < 3; err++) {
+		if (i2c_transfer(client->adapter, msgs, 2) == 2)
+			break;
+		v4l_warn(client, "I/O error #%d (read 0x%02x/0x%02x)\n", err,
+		       dev, addr);
+		schedule_timeout_interruptible(msecs_to_jiffies(10));
+	}
+	if (err == 3) {
+		v4l_warn(client, "resetting chip, sound will go off.\n");
+		msp_reset(client);
+		return -1;
+	}
+	retval = read[0] << 8 | read[1];
+	v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n",
+			dev, addr, retval);
+	return retval;
+}
+
+int msp_read_dem(struct i2c_client *client, int addr)
+{
+	return msp_read(client, I2C_MSP_DEM, addr);
+}
+
+int msp_read_dsp(struct i2c_client *client, int addr)
+{
+	return msp_read(client, I2C_MSP_DSP, addr);
+}
+
+static int msp_write(struct i2c_client *client, int dev, int addr, int val)
+{
+	int err;
+	u8 buffer[5];
+
+	buffer[0] = dev;
+	buffer[1] = addr >> 8;
+	buffer[2] = addr &  0xff;
+	buffer[3] = val  >> 8;
+	buffer[4] = val  &  0xff;
+
+	v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n",
+			dev, addr, val);
+	for (err = 0; err < 3; err++) {
+		if (i2c_master_send(client, buffer, 5) == 5)
+			break;
+		v4l_warn(client, "I/O error #%d (write 0x%02x/0x%02x)\n", err,
+		       dev, addr);
+		schedule_timeout_interruptible(msecs_to_jiffies(10));
+	}
+	if (err == 3) {
+		v4l_warn(client, "resetting chip, sound will go off.\n");
+		msp_reset(client);
+		return -1;
+	}
+	return 0;
+}
+
+int msp_write_dem(struct i2c_client *client, int addr, int val)
+{
+	return msp_write(client, I2C_MSP_DEM, addr, val);
+}
+
+int msp_write_dsp(struct i2c_client *client, int addr, int val)
+{
+	return msp_write(client, I2C_MSP_DSP, addr, val);
+}
+
+/* ----------------------------------------------------------------------- *
+ * bits  9  8  5 - SCART DSP input Select:
+ *       0  0  0 - SCART 1 to DSP input (reset position)
+ *       0  1  0 - MONO to DSP input
+ *       1  0  0 - SCART 2 to DSP input
+ *       1  1  1 - Mute DSP input
+ *
+ * bits 11 10  6 - SCART 1 Output Select:
+ *       0  0  0 - undefined (reset position)
+ *       0  1  0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS)
+ *       1  0  0 - MONO input to SCART 1 Output
+ *       1  1  0 - SCART 1 DA to SCART 1 Output
+ *       0  0  1 - SCART 2 DA to SCART 1 Output
+ *       0  1  1 - SCART 1 Input to SCART 1 Output
+ *       1  1  1 - Mute SCART 1 Output
+ *
+ * bits 13 12  7 - SCART 2 Output Select (for devices with 2 Output SCART):
+ *       0  0  0 - SCART 1 DA to SCART 2 Output (reset position)
+ *       0  1  0 - SCART 1 Input to SCART 2 Output
+ *       1  0  0 - MONO input to SCART 2 Output
+ *       0  0  1 - SCART 2 DA to SCART 2 Output
+ *       0  1  1 - SCART 2 Input to SCART 2 Output
+ *       1  1  0 - Mute SCART 2 Output
+ *
+ * Bits 4 to 0 should be zero.
+ * ----------------------------------------------------------------------- */
+
+static int scarts[3][9] = {
+	/* MASK   IN1     IN2     IN3     IN4     IN1_DA  IN2_DA  MONO    MUTE   */
+	/* SCART DSP Input select */
+	{ 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1,     -1,     0x0100, 0x0320 },
+	/* SCART1 Output select */
+	{ 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 },
+	/* SCART2 Output select */
+	{ 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 },
+};
+
+static char *scart_names[] = {
+	"in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute"
+};
+
+void msp_set_scart(struct i2c_client *client, int in, int out)
+{
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+
+	state->in_scart = in;
+
+	if (in >= 0 && in <= 7 && out >= 0 && out <= 2) {
+		if (-1 == scarts[out][in + 1])
+			return;
+
+		state->acb &= ~scarts[out][0];
+		state->acb |=  scarts[out][in + 1];
+	} else
+		state->acb = 0xf60; /* Mute Input and SCART 1 Output */
+
+	v4l_dbg(1, msp_debug, client, "scart switch: %s => %d (ACB=0x%04x)\n",
+					scart_names[in], out, state->acb);
+	msp_write_dsp(client, 0x13, state->acb);
+
+	/* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */
+	if (state->has_i2s_conf)
+		msp_write_dem(client, 0x40, state->i2s_mode);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static void msp_wake_thread(struct i2c_client *client)
+{
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+
+	if (NULL == state->kthread)
+		return;
+	state->watch_stereo = 0;
+	state->restart = 1;
+	wake_up_interruptible(&state->wq);
+}
+
+int msp_sleep(struct msp_state *state, int timeout)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	add_wait_queue(&state->wq, &wait);
+	if (!kthread_should_stop()) {
+		if (timeout < 0) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+		} else {
+			schedule_timeout_interruptible
+						(msecs_to_jiffies(timeout));
+		}
+	}
+
+	remove_wait_queue(&state->wq, &wait);
+	try_to_freeze();
+	return state->restart;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int msp_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct msp_state *state = ctrl_to_state(ctrl);
+	struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
+	int val = ctrl->val;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME: {
+		/* audio volume cluster */
+		int reallymuted = state->muted->val | state->scan_in_progress;
+
+		if (!reallymuted)
+			val = (val * 0x7f / 65535) << 8;
+
+		v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n",
+				state->muted->val ? "on" : "off",
+				state->scan_in_progress ? "yes" : "no",
+				state->volume->val);
+
+		msp_write_dsp(client, 0x0000, val);
+		msp_write_dsp(client, 0x0007, reallymuted ? 0x1 : (val | 0x1));
+		if (state->has_scart2_out_volume)
+			msp_write_dsp(client, 0x0040, reallymuted ? 0x1 : (val | 0x1));
+		if (state->has_headphones)
+			msp_write_dsp(client, 0x0006, val);
+		break;
+	}
+
+	case V4L2_CID_AUDIO_BASS:
+		val = ((val - 32768) * 0x60 / 65535) << 8;
+		msp_write_dsp(client, 0x0002, val);
+		if (state->has_headphones)
+			msp_write_dsp(client, 0x0031, val);
+		break;
+
+	case V4L2_CID_AUDIO_TREBLE:
+		val = ((val - 32768) * 0x60 / 65535) << 8;
+		msp_write_dsp(client, 0x0003, val);
+		if (state->has_headphones)
+			msp_write_dsp(client, 0x0032, val);
+		break;
+
+	case V4L2_CID_AUDIO_LOUDNESS:
+		val = val ? ((5 * 4) << 8) : 0;
+		msp_write_dsp(client, 0x0004, val);
+		if (state->has_headphones)
+			msp_write_dsp(client, 0x0033, val);
+		break;
+
+	case V4L2_CID_AUDIO_BALANCE:
+		val = (u8)((val / 256) - 128);
+		msp_write_dsp(client, 0x0001, val << 8);
+		if (state->has_headphones)
+			msp_write_dsp(client, 0x0030, val << 8);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+void msp_update_volume(struct msp_state *state)
+{
+	/* Force an update of the volume/mute cluster */
+	v4l2_ctrl_lock(state->volume);
+	state->volume->val = state->volume->cur.val;
+	state->muted->val = state->muted->cur.val;
+	msp_s_ctrl(state->volume);
+	v4l2_ctrl_unlock(state->volume);
+}
+
+/* --- v4l2 ioctls --- */
+static int msp_s_radio(struct v4l2_subdev *sd)
+{
+	struct msp_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (state->radio)
+		return 0;
+	state->radio = 1;
+	v4l_dbg(1, msp_debug, client, "switching to radio mode\n");
+	state->watch_stereo = 0;
+	switch (state->opmode) {
+	case OPMODE_MANUAL:
+		/* set msp3400 to FM radio mode */
+		msp3400c_set_mode(client, MSP_MODE_FM_RADIO);
+		msp3400c_set_carrier(client, MSP_CARRIER(10.7),
+				MSP_CARRIER(10.7));
+		msp_update_volume(state);
+		break;
+	case OPMODE_AUTODETECT:
+	case OPMODE_AUTOSELECT:
+		/* the thread will do for us */
+		msp_wake_thread(client);
+		break;
+	}
+	return 0;
+}
+
+static int msp_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	/* new channel -- kick audio carrier scan */
+	msp_wake_thread(client);
+	return 0;
+}
+
+static int msp_querystd(struct v4l2_subdev *sd, v4l2_std_id *id)
+{
+	struct msp_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	*id &= state->detected_std;
+
+	v4l_dbg(2, msp_debug, client,
+		"detected standard: %s(0x%08Lx)\n",
+		msp_standard_std_name(state->std), state->detected_std);
+
+	return 0;
+}
+
+static int msp_s_std(struct v4l2_subdev *sd, v4l2_std_id id)
+{
+	struct msp_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int update = state->radio || state->v4l2_std != id;
+
+	state->v4l2_std = id;
+	state->radio = 0;
+	if (update)
+		msp_wake_thread(client);
+	return 0;
+}
+
+static int msp_s_routing(struct v4l2_subdev *sd,
+			 u32 input, u32 output, u32 config)
+{
+	struct msp_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int tuner = (input >> 3) & 1;
+	int sc_in = input & 0x7;
+	int sc1_out = output & 0xf;
+	int sc2_out = (output >> 4) & 0xf;
+	u16 val, reg;
+	int i;
+	int extern_input = 1;
+
+	if (state->route_in == input && state->route_out == output)
+		return 0;
+	state->route_in = input;
+	state->route_out = output;
+	/* check if the tuner input is used */
+	for (i = 0; i < 5; i++) {
+		if (((input >> (4 + i * 4)) & 0xf) == 0)
+			extern_input = 0;
+	}
+	state->mode = extern_input ? MSP_MODE_EXTERN : MSP_MODE_AM_DETECT;
+	state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+	msp_set_scart(client, sc_in, 0);
+	msp_set_scart(client, sc1_out, 1);
+	msp_set_scart(client, sc2_out, 2);
+	msp_set_audmode(client);
+	reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb;
+	val = msp_read_dem(client, reg);
+	msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8));
+	/* wake thread when a new input is chosen */
+	msp_wake_thread(client);
+	return 0;
+}
+
+static int msp_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct msp_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (vt->type != V4L2_TUNER_ANALOG_TV)
+		return 0;
+	if (!state->radio) {
+		if (state->opmode == OPMODE_AUTOSELECT)
+			msp_detect_stereo(client);
+		vt->rxsubchans = state->rxsubchans;
+	}
+	vt->audmode = state->audmode;
+	vt->capability |= V4L2_TUNER_CAP_STEREO |
+		V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+	return 0;
+}
+
+static int msp_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct msp_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (state->radio)  /* TODO: add mono/stereo support for radio */
+		return 0;
+	if (state->audmode == vt->audmode)
+		return 0;
+	state->audmode = vt->audmode;
+	/* only set audmode */
+	msp_set_audmode(client);
+	return 0;
+}
+
+static int msp_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq)
+{
+	struct msp_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", freq);
+
+	switch (freq) {
+		case 1024000:
+			state->i2s_mode = 0;
+			break;
+		case 2048000:
+			state->i2s_mode = 1;
+			break;
+		default:
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int msp_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct msp_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, state->ident,
+			(state->rev1 << 16) | state->rev2);
+}
+
+static int msp_log_status(struct v4l2_subdev *sd)
+{
+	struct msp_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	const char *p;
+	char prefix[V4L2_SUBDEV_NAME_SIZE + 20];
+
+	if (state->opmode == OPMODE_AUTOSELECT)
+		msp_detect_stereo(client);
+	v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n",
+			client->name, state->rev1, state->rev2);
+	snprintf(prefix, sizeof(prefix), "%s: Audio:    ", sd->name);
+	v4l2_ctrl_handler_log_status(&state->hdl, prefix);
+	switch (state->mode) {
+		case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break;
+		case MSP_MODE_FM_RADIO: p = "FM Radio"; break;
+		case MSP_MODE_FM_TERRA: p = "Terrestrial FM-mono/stereo"; break;
+		case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break;
+		case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break;
+		case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break;
+		case MSP_MODE_AM_NICAM: p = "NICAM/AM (L)"; break;
+		case MSP_MODE_BTSC: p = "BTSC"; break;
+		case MSP_MODE_EXTERN: p = "External input"; break;
+		default: p = "unknown"; break;
+	}
+	if (state->mode == MSP_MODE_EXTERN) {
+		v4l_info(client, "Mode:     %s\n", p);
+	} else if (state->opmode == OPMODE_MANUAL) {
+		v4l_info(client, "Mode:     %s (%s%s)\n", p,
+				(state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
+				(state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
+	} else {
+		if (state->opmode == OPMODE_AUTODETECT)
+			v4l_info(client, "Mode:     %s\n", p);
+		v4l_info(client, "Standard: %s (%s%s)\n",
+				msp_standard_std_name(state->std),
+				(state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
+				(state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
+	}
+	v4l_info(client, "Audmode:  0x%04x\n", state->audmode);
+	v4l_info(client, "Routing:  0x%08x (input) 0x%08x (output)\n",
+			state->route_in, state->route_out);
+	v4l_info(client, "ACB:      0x%04x\n", state->acb);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int msp_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	v4l_dbg(1, msp_debug, client, "suspend\n");
+	msp_reset(client);
+	return 0;
+}
+
+static int msp_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	v4l_dbg(1, msp_debug, client, "resume\n");
+	msp_wake_thread(client);
+	return 0;
+}
+#endif
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_ctrl_ops msp_ctrl_ops = {
+	.s_ctrl = msp_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops msp_core_ops = {
+	.log_status = msp_log_status,
+	.g_chip_ident = msp_g_chip_ident,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+	.s_std = msp_s_std,
+};
+
+static const struct v4l2_subdev_video_ops msp_video_ops = {
+	.querystd = msp_querystd,
+};
+
+static const struct v4l2_subdev_tuner_ops msp_tuner_ops = {
+	.s_frequency = msp_s_frequency,
+	.g_tuner = msp_g_tuner,
+	.s_tuner = msp_s_tuner,
+	.s_radio = msp_s_radio,
+};
+
+static const struct v4l2_subdev_audio_ops msp_audio_ops = {
+	.s_routing = msp_s_routing,
+	.s_i2s_clock_freq = msp_s_i2s_clock_freq,
+};
+
+static const struct v4l2_subdev_ops msp_ops = {
+	.core = &msp_core_ops,
+	.video = &msp_video_ops,
+	.tuner = &msp_tuner_ops,
+	.audio = &msp_audio_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct msp_state *state;
+	struct v4l2_subdev *sd;
+	struct v4l2_ctrl_handler *hdl;
+	int (*thread_func)(void *data) = NULL;
+	int msp_hard;
+	int msp_family;
+	int msp_revision;
+	int msp_product, msp_prod_hi, msp_prod_lo;
+	int msp_rom;
+
+	if (!id)
+		strlcpy(client->name, "msp3400", sizeof(client->name));
+
+	if (msp_reset(client) == -1) {
+		v4l_dbg(1, msp_debug, client, "msp3400 not found\n");
+		return -ENODEV;
+	}
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &msp_ops);
+
+	state->v4l2_std = V4L2_STD_NTSC;
+	state->detected_std = V4L2_STD_ALL;
+	state->audmode = V4L2_TUNER_MODE_STEREO;
+	state->input = -1;
+	state->i2s_mode = 0;
+	init_waitqueue_head(&state->wq);
+	/* These are the reset input/output positions */
+	state->route_in = MSP_INPUT_DEFAULT;
+	state->route_out = MSP_OUTPUT_DEFAULT;
+
+	state->rev1 = msp_read_dsp(client, 0x1e);
+	if (state->rev1 != -1)
+		state->rev2 = msp_read_dsp(client, 0x1f);
+	v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n",
+			state->rev1, state->rev2);
+	if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) {
+		v4l_dbg(1, msp_debug, client,
+				"not an msp3400 (cannot read chip version)\n");
+		kfree(state);
+		return -ENODEV;
+	}
+
+	msp_family = ((state->rev1 >> 4) & 0x0f) + 3;
+	msp_product = (state->rev2 >> 8) & 0xff;
+	msp_prod_hi = msp_product / 10;
+	msp_prod_lo = msp_product % 10;
+	msp_revision = (state->rev1 & 0x0f) + '@';
+	msp_hard = ((state->rev1 >> 8) & 0xff) + '@';
+	msp_rom = state->rev2 & 0x1f;
+	/* Rev B=2, C=3, D=4, G=7 */
+	state->ident = msp_family * 10000 + 4000 + msp_product * 10 +
+			msp_revision - '@';
+
+	/* Has NICAM support: all mspx41x and mspx45x products have NICAM */
+	state->has_nicam =
+		msp_prod_hi == 1 || msp_prod_hi == 5;
+	/* Has radio support: was added with revision G */
+	state->has_radio =
+		msp_revision >= 'G';
+	/* Has headphones output: not for stripped down products */
+	state->has_headphones =
+		msp_prod_lo < 5;
+	/* Has scart2 input: not in stripped down products of the '3' family */
+	state->has_scart2 =
+		msp_family >= 4 || msp_prod_lo < 7;
+	/* Has scart3 input: not in stripped down products of the '3' family */
+	state->has_scart3 =
+		msp_family >= 4 || msp_prod_lo < 5;
+	/* Has scart4 input: not in pre D revisions, not in stripped D revs */
+	state->has_scart4 =
+		msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5);
+	/* Has scart2 output: not in stripped down products of
+	 * the '3' family */
+	state->has_scart2_out =
+		msp_family >= 4 || msp_prod_lo < 5;
+	/* Has scart2 a volume control? Not in pre-D revisions. */
+	state->has_scart2_out_volume =
+		msp_revision > 'C' && state->has_scart2_out;
+	/* Has a configurable i2s out? */
+	state->has_i2s_conf =
+		msp_revision >= 'G' && msp_prod_lo < 7;
+	/* Has subwoofer output: not in pre-D revs and not in stripped down
+	 * products */
+	state->has_subwoofer =
+		msp_revision >= 'D' && msp_prod_lo < 5;
+	/* Has soundprocessing (bass/treble/balance/loudness/equalizer):
+	 *  not in stripped down products */
+	state->has_sound_processing =
+		msp_prod_lo < 7;
+	/* Has Virtual Dolby Surround: only in msp34x1 */
+	state->has_virtual_dolby_surround =
+		msp_revision == 'G' && msp_prod_lo == 1;
+	/* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */
+	state->has_dolby_pro_logic =
+		msp_revision == 'G' && msp_prod_lo == 2;
+	/* The msp343xG supports BTSC only and cannot do Automatic Standard
+	 * Detection. */
+	state->force_btsc =
+		msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3;
+
+	state->opmode = opmode;
+	if (state->opmode == OPMODE_AUTO) {
+		/* MSP revision G and up have both autodetect and autoselect */
+		if (msp_revision >= 'G')
+			state->opmode = OPMODE_AUTOSELECT;
+		/* MSP revision D and up have autodetect */
+		else if (msp_revision >= 'D')
+			state->opmode = OPMODE_AUTODETECT;
+		else
+			state->opmode = OPMODE_MANUAL;
+	}
+
+	hdl = &state->hdl;
+	v4l2_ctrl_handler_init(hdl, 6);
+	if (state->has_sound_processing) {
+		v4l2_ctrl_new_std(hdl, &msp_ctrl_ops,
+			V4L2_CID_AUDIO_BASS, 0, 65535, 65535 / 100, 32768);
+		v4l2_ctrl_new_std(hdl, &msp_ctrl_ops,
+			V4L2_CID_AUDIO_TREBLE, 0, 65535, 65535 / 100, 32768);
+		v4l2_ctrl_new_std(hdl, &msp_ctrl_ops,
+			V4L2_CID_AUDIO_LOUDNESS, 0, 1, 1, 0);
+	}
+	state->volume = v4l2_ctrl_new_std(hdl, &msp_ctrl_ops,
+			V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 58880);
+	v4l2_ctrl_new_std(hdl, &msp_ctrl_ops,
+			V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768);
+	state->muted = v4l2_ctrl_new_std(hdl, &msp_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+	sd->ctrl_handler = hdl;
+	if (hdl->error) {
+		int err = hdl->error;
+
+		v4l2_ctrl_handler_free(hdl);
+		kfree(state);
+		return err;
+	}
+
+	v4l2_ctrl_cluster(2, &state->volume);
+	v4l2_ctrl_handler_setup(hdl);
+
+	/* hello world :-) */
+	v4l_info(client, "MSP%d4%02d%c-%c%d found @ 0x%x (%s)\n",
+			msp_family, msp_product,
+			msp_revision, msp_hard, msp_rom,
+			client->addr << 1, client->adapter->name);
+	v4l_info(client, "%s ", client->name);
+	if (state->has_nicam && state->has_radio)
+		printk(KERN_CONT "supports nicam and radio, ");
+	else if (state->has_nicam)
+		printk(KERN_CONT "supports nicam, ");
+	else if (state->has_radio)
+		printk(KERN_CONT "supports radio, ");
+	printk(KERN_CONT "mode is ");
+
+	/* version-specific initialization */
+	switch (state->opmode) {
+	case OPMODE_MANUAL:
+		printk(KERN_CONT "manual");
+		thread_func = msp3400c_thread;
+		break;
+	case OPMODE_AUTODETECT:
+		printk(KERN_CONT "autodetect");
+		thread_func = msp3410d_thread;
+		break;
+	case OPMODE_AUTOSELECT:
+		printk(KERN_CONT "autodetect and autoselect");
+		thread_func = msp34xxg_thread;
+		break;
+	}
+	printk(KERN_CONT "\n");
+
+	/* startup control thread if needed */
+	if (thread_func) {
+		state->kthread = kthread_run(thread_func, client, "msp34xx");
+
+		if (IS_ERR(state->kthread))
+			v4l_warn(client, "kernel_thread() failed\n");
+		msp_wake_thread(client);
+	}
+	return 0;
+}
+
+static int msp_remove(struct i2c_client *client)
+{
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+
+	v4l2_device_unregister_subdev(&state->sd);
+	/* shutdown control thread */
+	if (state->kthread) {
+		state->restart = 1;
+		kthread_stop(state->kthread);
+	}
+	msp_reset(client);
+
+	v4l2_ctrl_handler_free(&state->hdl);
+	kfree(state);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct dev_pm_ops msp3400_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(msp_suspend, msp_resume)
+};
+
+static const struct i2c_device_id msp_id[] = {
+	{ "msp3400", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, msp_id);
+
+static struct i2c_driver msp_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "msp3400",
+		.pm	= &msp3400_pm_ops,
+	},
+	.probe		= msp_probe,
+	.remove		= msp_remove,
+	.id_table	= msp_id,
+};
+
+module_i2c_driver(msp_driver);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/i2c/msp3400-driver.h b/drivers/media/i2c/msp3400-driver.h
new file mode 100644
index 0000000..fbe5e07
--- /dev/null
+++ b/drivers/media/i2c/msp3400-driver.h
@@ -0,0 +1,137 @@
+/*
+ */
+
+#ifndef MSP3400_DRIVER_H
+#define MSP3400_DRIVER_H
+
+#include <media/msp3400.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+/* ---------------------------------------------------------------------- */
+
+/* This macro is allowed for *constants* only, gcc must calculate it
+   at compile time.  Remember -- no floats in kernel mode */
+#define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24)))
+
+#define MSP_MODE_AM_DETECT   0
+#define MSP_MODE_FM_RADIO    2
+#define MSP_MODE_FM_TERRA    3
+#define MSP_MODE_FM_SAT      4
+#define MSP_MODE_FM_NICAM1   5
+#define MSP_MODE_FM_NICAM2   6
+#define MSP_MODE_AM_NICAM    7
+#define MSP_MODE_BTSC        8
+#define MSP_MODE_EXTERN      9
+
+#define SCART_IN1     0
+#define SCART_IN2     1
+#define SCART_IN3     2
+#define SCART_IN4     3
+#define SCART_IN1_DA  4
+#define SCART_IN2_DA  5
+#define SCART_MONO    6
+#define SCART_MUTE    7
+
+#define SCART_DSP_IN  0
+#define SCART1_OUT    1
+#define SCART2_OUT    2
+
+#define OPMODE_AUTO       -1
+#define OPMODE_MANUAL      0
+#define OPMODE_AUTODETECT  1   /* use autodetect (>= msp3410 only) */
+#define OPMODE_AUTOSELECT  2   /* use autodetect & autoselect (>= msp34xxG)   */
+
+/* module parameters */
+extern int msp_debug;
+extern bool msp_once;
+extern bool msp_amsound;
+extern int msp_standard;
+extern bool msp_dolby;
+extern int msp_stereo_thresh;
+
+struct msp_state {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	int rev1, rev2;
+	int ident;
+	u8 has_nicam;
+	u8 has_radio;
+	u8 has_headphones;
+	u8 has_ntsc_jp_d_k3;
+	u8 has_scart2;
+	u8 has_scart3;
+	u8 has_scart4;
+	u8 has_scart2_out;
+	u8 has_scart2_out_volume;
+	u8 has_i2s_conf;
+	u8 has_subwoofer;
+	u8 has_sound_processing;
+	u8 has_virtual_dolby_surround;
+	u8 has_dolby_pro_logic;
+	u8 force_btsc;
+
+	int radio;
+	int opmode;
+	int std;
+	int mode;
+	v4l2_std_id v4l2_std, detected_std;
+	int nicam_on;
+	int acb;
+	int in_scart;
+	int i2s_mode;
+	int main, second;	/* sound carrier */
+	int input;
+	u32 route_in;
+	u32 route_out;
+
+	/* v4l2 */
+	int audmode;
+	int rxsubchans;
+
+	struct {
+		/* volume cluster */
+		struct v4l2_ctrl *volume;
+		struct v4l2_ctrl *muted;
+	};
+
+	int scan_in_progress;
+
+	/* thread */
+	struct task_struct   *kthread;
+	wait_queue_head_t    wq;
+	unsigned int         restart:1;
+	unsigned int         watch_stereo:1;
+};
+
+static inline struct msp_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct msp_state, sd);
+}
+
+static inline struct msp_state *ctrl_to_state(struct v4l2_ctrl *ctrl)
+{
+	return container_of(ctrl->handler, struct msp_state, hdl);
+}
+
+/* msp3400-driver.c */
+int msp_write_dem(struct i2c_client *client, int addr, int val);
+int msp_write_dsp(struct i2c_client *client, int addr, int val);
+int msp_read_dem(struct i2c_client *client, int addr);
+int msp_read_dsp(struct i2c_client *client, int addr);
+int msp_reset(struct i2c_client *client);
+void msp_set_scart(struct i2c_client *client, int in, int out);
+void msp_update_volume(struct msp_state *state);
+int msp_sleep(struct msp_state *state, int timeout);
+
+/* msp3400-kthreads.c */
+const char *msp_standard_std_name(int std);
+void msp_set_audmode(struct i2c_client *client);
+int msp_detect_stereo(struct i2c_client *client);
+int msp3400c_thread(void *data);
+int msp3410d_thread(void *data);
+int msp34xxg_thread(void *data);
+void msp3400c_set_mode(struct i2c_client *client, int mode);
+void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2);
+
+#endif /* MSP3400_DRIVER_H */
diff --git a/drivers/media/i2c/msp3400-kthreads.c b/drivers/media/i2c/msp3400-kthreads.c
new file mode 100644
index 0000000..f8b5171
--- /dev/null
+++ b/drivers/media/i2c/msp3400-kthreads.c
@@ -0,0 +1,1165 @@
+/*
+ * Programming the mspx4xx sound processor family
+ *
+ * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/freezer.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/msp3400.h>
+#include <linux/kthread.h>
+#include <linux/suspend.h>
+#include "msp3400-driver.h"
+
+/* this one uses the automatic sound standard detection of newer msp34xx
+   chip versions */
+static struct {
+	int retval;
+	int main, second;
+	char *name;
+	v4l2_std_id std;
+} msp_stdlist[] = {
+	{ 0x0000, 0, 0, "could not detect sound standard", V4L2_STD_ALL },
+	{ 0x0001, 0, 0, "autodetect start", V4L2_STD_ALL },
+	{ 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72),
+	  "4.5/4.72  M Dual FM-Stereo", V4L2_STD_MN },
+	{ 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875),
+	  "5.5/5.74  B/G Dual FM-Stereo", V4L2_STD_BG },
+	{ 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125),
+	  "6.5/6.25  D/K1 Dual FM-Stereo", V4L2_STD_DK },
+	{ 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875),
+	  "6.5/6.74  D/K2 Dual FM-Stereo", V4L2_STD_DK },
+	{ 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+	  "6.5  D/K FM-Mono (HDEV3)", V4L2_STD_DK },
+	{ 0x0007, MSP_CARRIER(6.5), MSP_CARRIER(5.7421875),
+	  "6.5/5.74  D/K3 Dual FM-Stereo", V4L2_STD_DK },
+	{ 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85),
+	  "5.5/5.85  B/G NICAM FM", V4L2_STD_BG },
+	{ 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85),
+	  "6.5/5.85  L NICAM AM", V4L2_STD_L },
+	{ 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55),
+	  "6.0/6.55  I NICAM FM", V4L2_STD_PAL_I },
+	{ 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85),
+	  "6.5/5.85  D/K NICAM FM", V4L2_STD_DK },
+	{ 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85),
+	  "6.5/5.85  D/K NICAM FM (HDEV2)", V4L2_STD_DK },
+	{ 0x000d, MSP_CARRIER(6.5), MSP_CARRIER(5.85),
+	  "6.5/5.85  D/K NICAM FM (HDEV3)", V4L2_STD_DK },
+	{ 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5),
+	  "4.5  M BTSC-Stereo", V4L2_STD_MTS },
+	{ 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5),
+	  "4.5  M BTSC-Mono + SAP", V4L2_STD_MTS },
+	{ 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5),
+	  "4.5  M EIA-J Japan Stereo", V4L2_STD_NTSC_M_JP },
+	{ 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7),
+	  "10.7  FM-Stereo Radio", V4L2_STD_ALL },
+	{ 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+	  "6.5  SAT-Mono", V4L2_STD_ALL },
+	{ 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20),
+	  "7.02/7.20  SAT-Stereo", V4L2_STD_ALL },
+	{ 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2),
+	  "7.2  SAT ADR", V4L2_STD_ALL },
+	{     -1, 0, 0, NULL, 0 }, /* EOF */
+};
+
+static struct msp3400c_init_data_dem {
+	int fir1[6];
+	int fir2[6];
+	int cdo1;
+	int cdo2;
+	int ad_cv;
+	int mode_reg;
+	int dsp_src;
+	int dsp_matrix;
+} msp3400c_init_data[] = {
+	{	/* AM (for carrier detect / msp3400) */
+		{75, 19, 36, 35, 39, 40},
+		{75, 19, 36, 35, 39, 40},
+		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+		0x00d0, 0x0500, 0x0020, 0x3000
+	}, {	/* AM (for carrier detect / msp3410) */
+		{-1, -1, -8, 2, 59, 126},
+		{-1, -1, -8, 2, 59, 126},
+		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+		0x00d0, 0x0100, 0x0020, 0x3000
+	}, {	/* FM Radio */
+		{-8, -8, 4, 6, 78, 107},
+		{-8, -8, 4, 6, 78, 107},
+		MSP_CARRIER(10.7), MSP_CARRIER(10.7),
+		0x00d0, 0x0480, 0x0020, 0x3000
+	}, {	/* Terrestrial FM-mono + FM-stereo */
+		{3, 18, 27, 48, 66, 72},
+		{3, 18, 27, 48, 66, 72},
+		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+		0x00d0, 0x0480, 0x0030, 0x3000
+	}, {	/* Sat FM-mono */
+		{ 1, 9, 14, 24, 33, 37},
+		{ 3, 18, 27, 48, 66, 72},
+		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+		0x00c6, 0x0480, 0x0000, 0x3000
+	}, {	/* NICAM/FM --  B/G (5.5/5.85), D/K (6.5/5.85) */
+		{-2, -8, -10, 10, 50, 86},
+		{3, 18, 27, 48, 66, 72},
+		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+		0x00d0, 0x0040, 0x0120, 0x3000
+	}, {	/* NICAM/FM -- I (6.0/6.552) */
+		{2, 4, -6, -4, 40, 94},
+		{3, 18, 27, 48, 66, 72},
+		MSP_CARRIER(6.0), MSP_CARRIER(6.0),
+		0x00d0, 0x0040, 0x0120, 0x3000
+	}, {	/* NICAM/AM -- L (6.5/5.85) */
+		{-2, -8, -10, 10, 50, 86},
+		{-4, -12, -9, 23, 79, 126},
+		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+		0x00c6, 0x0140, 0x0120, 0x7c00
+	},
+};
+
+struct msp3400c_carrier_detect {
+	int   cdo;
+	char *name;
+};
+
+static struct msp3400c_carrier_detect msp3400c_carrier_detect_main[] = {
+	/* main carrier */
+	{ MSP_CARRIER(4.5),        "4.5   NTSC"                   },
+	{ MSP_CARRIER(5.5),        "5.5   PAL B/G"                },
+	{ MSP_CARRIER(6.0),        "6.0   PAL I"                  },
+	{ MSP_CARRIER(6.5),        "6.5   PAL D/K + SAT + SECAM"  }
+};
+
+static struct msp3400c_carrier_detect msp3400c_carrier_detect_55[] = {
+	/* PAL B/G */
+	{ MSP_CARRIER(5.7421875),  "5.742 PAL B/G FM-stereo"     },
+	{ MSP_CARRIER(5.85),       "5.85  PAL B/G NICAM"         }
+};
+
+static struct msp3400c_carrier_detect msp3400c_carrier_detect_65[] = {
+	/* PAL SAT / SECAM */
+	{ MSP_CARRIER(5.85),       "5.85  PAL D/K + SECAM NICAM" },
+	{ MSP_CARRIER(6.2578125),  "6.25  PAL D/K1 FM-stereo" },
+	{ MSP_CARRIER(6.7421875),  "6.74  PAL D/K2 FM-stereo" },
+	{ MSP_CARRIER(7.02),       "7.02  PAL SAT FM-stereo s/b" },
+	{ MSP_CARRIER(7.20),       "7.20  PAL SAT FM-stereo s"   },
+	{ MSP_CARRIER(7.38),       "7.38  PAL SAT FM-stereo b"   },
+};
+
+/* ------------------------------------------------------------------------ */
+
+const char *msp_standard_std_name(int std)
+{
+	int i;
+
+	for (i = 0; msp_stdlist[i].name != NULL; i++)
+		if (msp_stdlist[i].retval == std)
+			return msp_stdlist[i].name;
+	return "unknown";
+}
+
+static v4l2_std_id msp_standard_std(int std)
+{
+	int i;
+
+	for (i = 0; msp_stdlist[i].name != NULL; i++)
+		if (msp_stdlist[i].retval == std)
+			return msp_stdlist[i].std;
+	return V4L2_STD_ALL;
+}
+
+static void msp_set_source(struct i2c_client *client, u16 src)
+{
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+
+	if (msp_dolby) {
+		msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */
+		msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */
+	} else {
+		msp_write_dsp(client, 0x0008, src);
+		msp_write_dsp(client, 0x0009, src);
+	}
+	msp_write_dsp(client, 0x000a, src);
+	msp_write_dsp(client, 0x000b, src);
+	msp_write_dsp(client, 0x000c, src);
+	if (state->has_scart2_out)
+		msp_write_dsp(client, 0x0041, src);
+}
+
+void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2)
+{
+	msp_write_dem(client, 0x0093, cdo1 & 0xfff);
+	msp_write_dem(client, 0x009b, cdo1 >> 12);
+	msp_write_dem(client, 0x00a3, cdo2 & 0xfff);
+	msp_write_dem(client, 0x00ab, cdo2 >> 12);
+	msp_write_dem(client, 0x0056, 0); /* LOAD_REG_1/2 */
+}
+
+void msp3400c_set_mode(struct i2c_client *client, int mode)
+{
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+	struct msp3400c_init_data_dem *data = &msp3400c_init_data[mode];
+	int tuner = (state->route_in >> 3) & 1;
+	int i;
+
+	v4l_dbg(1, msp_debug, client, "set_mode: %d\n", mode);
+	state->mode = mode;
+	state->rxsubchans = V4L2_TUNER_SUB_MONO;
+
+	msp_write_dem(client, 0x00bb, data->ad_cv | (tuner ? 0x100 : 0));
+
+	for (i = 5; i >= 0; i--)               /* fir 1 */
+		msp_write_dem(client, 0x0001, data->fir1[i]);
+
+	msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */
+	msp_write_dem(client, 0x0005, 0x0040);
+	msp_write_dem(client, 0x0005, 0x0000);
+	for (i = 5; i >= 0; i--)
+		msp_write_dem(client, 0x0005, data->fir2[i]);
+
+	msp_write_dem(client, 0x0083, data->mode_reg);
+
+	msp3400c_set_carrier(client, data->cdo1, data->cdo2);
+
+	msp_set_source(client, data->dsp_src);
+	/* set prescales */
+
+	/* volume prescale for SCART (AM mono input) */
+	msp_write_dsp(client, 0x000d, 0x1900);
+	msp_write_dsp(client, 0x000e, data->dsp_matrix);
+	if (state->has_nicam) /* nicam prescale */
+		msp_write_dsp(client, 0x0010, 0x5a00);
+}
+
+/* Set audio mode. Note that the pre-'G' models do not support BTSC+SAP,
+   nor do they support stereo BTSC. */
+static void msp3400c_set_audmode(struct i2c_client *client)
+{
+	static char *strmode[] = {
+		"mono", "stereo", "lang2", "lang1", "lang1+lang2"
+	};
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+	char *modestr = (state->audmode >= 0 && state->audmode < 5) ?
+		strmode[state->audmode] : "unknown";
+	int src = 0;	/* channel source: FM/AM, nicam or SCART */
+	int audmode = state->audmode;
+
+	if (state->opmode == OPMODE_AUTOSELECT) {
+		/* this method would break everything, let's make sure
+		 * it's never called
+		 */
+		v4l_dbg(1, msp_debug, client,
+			"set_audmode called with mode=%d instead of set_source (ignored)\n",
+			state->audmode);
+		return;
+	}
+
+	/* Note: for the C and D revs no NTSC stereo + SAP is possible as
+	   the hardware does not support SAP. So the rxsubchans combination
+	   of STEREO | LANG2 does not occur. */
+
+	if (state->mode != MSP_MODE_EXTERN) {
+		/* switch to mono if only mono is available */
+		if (state->rxsubchans == V4L2_TUNER_SUB_MONO)
+			audmode = V4L2_TUNER_MODE_MONO;
+		/* if bilingual */
+		else if (state->rxsubchans & V4L2_TUNER_SUB_LANG2) {
+			/* and mono or stereo, then fallback to lang1 */
+			if (audmode == V4L2_TUNER_MODE_MONO ||
+			    audmode == V4L2_TUNER_MODE_STEREO)
+				audmode = V4L2_TUNER_MODE_LANG1;
+		}
+		/* if stereo, and audmode is not mono, then switch to stereo */
+		else if (audmode != V4L2_TUNER_MODE_MONO)
+			audmode = V4L2_TUNER_MODE_STEREO;
+	}
+
+	/* switch demodulator */
+	switch (state->mode) {
+	case MSP_MODE_FM_TERRA:
+		v4l_dbg(1, msp_debug, client, "FM set_audmode: %s\n", modestr);
+		switch (audmode) {
+		case V4L2_TUNER_MODE_STEREO:
+			msp_write_dsp(client, 0x000e, 0x3001);
+			break;
+		case V4L2_TUNER_MODE_MONO:
+		case V4L2_TUNER_MODE_LANG1:
+		case V4L2_TUNER_MODE_LANG2:
+		case V4L2_TUNER_MODE_LANG1_LANG2:
+			msp_write_dsp(client, 0x000e, 0x3000);
+			break;
+		}
+		break;
+	case MSP_MODE_FM_SAT:
+		v4l_dbg(1, msp_debug, client, "SAT set_audmode: %s\n", modestr);
+		switch (audmode) {
+		case V4L2_TUNER_MODE_MONO:
+			msp3400c_set_carrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+		case V4L2_TUNER_MODE_LANG1_LANG2:
+			msp3400c_set_carrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
+			break;
+		case V4L2_TUNER_MODE_LANG1:
+			msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+			break;
+		case V4L2_TUNER_MODE_LANG2:
+			msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+			break;
+		}
+		break;
+	case MSP_MODE_FM_NICAM1:
+	case MSP_MODE_FM_NICAM2:
+	case MSP_MODE_AM_NICAM:
+		v4l_dbg(1, msp_debug, client,
+			"NICAM set_audmode: %s\n", modestr);
+		if (state->nicam_on)
+			src = 0x0100;  /* NICAM */
+		break;
+	case MSP_MODE_BTSC:
+		v4l_dbg(1, msp_debug, client,
+			"BTSC set_audmode: %s\n", modestr);
+		break;
+	case MSP_MODE_EXTERN:
+		v4l_dbg(1, msp_debug, client,
+			"extern set_audmode: %s\n", modestr);
+		src = 0x0200;  /* SCART */
+		break;
+	case MSP_MODE_FM_RADIO:
+		v4l_dbg(1, msp_debug, client,
+			"FM-Radio set_audmode: %s\n", modestr);
+		break;
+	default:
+		v4l_dbg(1, msp_debug, client, "mono set_audmode\n");
+		return;
+	}
+
+	/* switch audio */
+	v4l_dbg(1, msp_debug, client, "set audmode %d\n", audmode);
+	switch (audmode) {
+	case V4L2_TUNER_MODE_STEREO:
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+		src |= 0x0020;
+		break;
+	case V4L2_TUNER_MODE_MONO:
+		if (state->mode == MSP_MODE_AM_NICAM) {
+			v4l_dbg(1, msp_debug, client, "switching to AM mono\n");
+			/* AM mono decoding is handled by tuner, not MSP chip */
+			/* SCART switching control register */
+			msp_set_scart(client, SCART_MONO, 0);
+			src = 0x0200;
+			break;
+		}
+		if (state->rxsubchans & V4L2_TUNER_SUB_STEREO)
+			src = 0x0030;
+		break;
+	case V4L2_TUNER_MODE_LANG1:
+		break;
+	case V4L2_TUNER_MODE_LANG2:
+		src |= 0x0010;
+		break;
+	}
+	v4l_dbg(1, msp_debug, client,
+		"set_audmode final source/matrix = 0x%x\n", src);
+
+	msp_set_source(client, src);
+}
+
+static void msp3400c_print_mode(struct i2c_client *client)
+{
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+
+	if (state->main == state->second)
+		v4l_dbg(1, msp_debug, client,
+			"mono sound carrier: %d.%03d MHz\n",
+			state->main / 910000, (state->main / 910) % 1000);
+	else
+		v4l_dbg(1, msp_debug, client,
+			"main sound carrier: %d.%03d MHz\n",
+			state->main / 910000, (state->main / 910) % 1000);
+	if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2)
+		v4l_dbg(1, msp_debug, client,
+			"NICAM/FM carrier  : %d.%03d MHz\n",
+			state->second / 910000, (state->second/910) % 1000);
+	if (state->mode == MSP_MODE_AM_NICAM)
+		v4l_dbg(1, msp_debug, client,
+			"NICAM/AM carrier  : %d.%03d MHz\n",
+			state->second / 910000, (state->second / 910) % 1000);
+	if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) {
+		v4l_dbg(1, msp_debug, client,
+			"FM-stereo carrier : %d.%03d MHz\n",
+			state->second / 910000, (state->second / 910) % 1000);
+	}
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int msp3400c_detect_stereo(struct i2c_client *client)
+{
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+	int val;
+	int rxsubchans = state->rxsubchans;
+	int newnicam = state->nicam_on;
+	int update = 0;
+
+	switch (state->mode) {
+	case MSP_MODE_FM_TERRA:
+		val = msp_read_dsp(client, 0x18);
+		if (val > 32767)
+			val -= 65536;
+		v4l_dbg(2, msp_debug, client,
+			"stereo detect register: %d\n", val);
+		if (val > 8192) {
+			rxsubchans = V4L2_TUNER_SUB_STEREO;
+		} else if (val < -4096) {
+			rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+		} else {
+			rxsubchans = V4L2_TUNER_SUB_MONO;
+		}
+		newnicam = 0;
+		break;
+	case MSP_MODE_FM_NICAM1:
+	case MSP_MODE_FM_NICAM2:
+	case MSP_MODE_AM_NICAM:
+		val = msp_read_dem(client, 0x23);
+		v4l_dbg(2, msp_debug, client, "nicam sync=%d, mode=%d\n",
+			val & 1, (val & 0x1e) >> 1);
+
+		if (val & 1) {
+			/* nicam synced */
+			switch ((val & 0x1e) >> 1)  {
+			case 0:
+			case 8:
+				rxsubchans = V4L2_TUNER_SUB_STEREO;
+				break;
+			case 1:
+			case 9:
+				rxsubchans = V4L2_TUNER_SUB_MONO;
+				break;
+			case 2:
+			case 10:
+				rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+				break;
+			default:
+				rxsubchans = V4L2_TUNER_SUB_MONO;
+				break;
+			}
+			newnicam = 1;
+		} else {
+			newnicam = 0;
+			rxsubchans = V4L2_TUNER_SUB_MONO;
+		}
+		break;
+	}
+	if (rxsubchans != state->rxsubchans) {
+		update = 1;
+		v4l_dbg(1, msp_debug, client,
+			"watch: rxsubchans %02x => %02x\n",
+			state->rxsubchans, rxsubchans);
+		state->rxsubchans = rxsubchans;
+	}
+	if (newnicam != state->nicam_on) {
+		update = 1;
+		v4l_dbg(1, msp_debug, client, "watch: nicam %d => %d\n",
+			state->nicam_on, newnicam);
+		state->nicam_on = newnicam;
+	}
+	return update;
+}
+
+/*
+ * A kernel thread for msp3400 control -- we don't want to block the
+ * in the ioctl while doing the sound carrier & stereo detect
+ */
+/* stereo/multilang monitoring */
+static void watch_stereo(struct i2c_client *client)
+{
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+
+	if (msp_detect_stereo(client))
+		msp_set_audmode(client);
+
+	if (msp_once)
+		state->watch_stereo = 0;
+}
+
+int msp3400c_thread(void *data)
+{
+	struct i2c_client *client = data;
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+	struct msp3400c_carrier_detect *cd;
+	int count, max1, max2, val1, val2, val, i;
+
+	v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n");
+	state->detected_std = V4L2_STD_ALL;
+	set_freezable();
+	for (;;) {
+		v4l_dbg(2, msp_debug, client, "msp3400 thread: sleep\n");
+		msp_sleep(state, -1);
+		v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n");
+
+restart:
+		v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
+		state->restart = 0;
+		if (kthread_should_stop())
+			break;
+
+		if (state->radio || MSP_MODE_EXTERN == state->mode) {
+			/* no carrier scan, just unmute */
+			v4l_dbg(1, msp_debug, client,
+				"thread: no carrier scan\n");
+			state->scan_in_progress = 0;
+			msp_update_volume(state);
+			continue;
+		}
+
+		/* mute audio */
+		state->scan_in_progress = 1;
+		msp_update_volume(state);
+
+		msp3400c_set_mode(client, MSP_MODE_AM_DETECT);
+		val1 = val2 = 0;
+		max1 = max2 = -1;
+		state->watch_stereo = 0;
+		state->nicam_on = 0;
+
+		/* wait for tuner to settle down after a channel change */
+		if (msp_sleep(state, 200))
+			goto restart;
+
+		/* carrier detect pass #1 -- main carrier */
+		cd = msp3400c_carrier_detect_main;
+		count = ARRAY_SIZE(msp3400c_carrier_detect_main);
+
+		if (msp_amsound && (state->v4l2_std & V4L2_STD_SECAM)) {
+			/* autodetect doesn't work well with AM ... */
+			max1 = 3;
+			count = 0;
+			v4l_dbg(1, msp_debug, client, "AM sound override\n");
+		}
+
+		for (i = 0; i < count; i++) {
+			msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo);
+			if (msp_sleep(state, 100))
+				goto restart;
+			val = msp_read_dsp(client, 0x1b);
+			if (val > 32767)
+				val -= 65536;
+			if (val1 < val)
+				val1 = val, max1 = i;
+			v4l_dbg(1, msp_debug, client,
+				"carrier1 val: %5d / %s\n", val, cd[i].name);
+		}
+
+		/* carrier detect pass #2 -- second (stereo) carrier */
+		switch (max1) {
+		case 1: /* 5.5 */
+			cd = msp3400c_carrier_detect_55;
+			count = ARRAY_SIZE(msp3400c_carrier_detect_55);
+			break;
+		case 3: /* 6.5 */
+			cd = msp3400c_carrier_detect_65;
+			count = ARRAY_SIZE(msp3400c_carrier_detect_65);
+			break;
+		case 0: /* 4.5 */
+		case 2: /* 6.0 */
+		default:
+			cd = NULL;
+			count = 0;
+			break;
+		}
+
+		if (msp_amsound && (state->v4l2_std & V4L2_STD_SECAM)) {
+			/* autodetect doesn't work well with AM ... */
+			cd = NULL;
+			count = 0;
+			max2 = 0;
+		}
+		for (i = 0; i < count; i++) {
+			msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo);
+			if (msp_sleep(state, 100))
+				goto restart;
+			val = msp_read_dsp(client, 0x1b);
+			if (val > 32767)
+				val -= 65536;
+			if (val2 < val)
+				val2 = val, max2 = i;
+			v4l_dbg(1, msp_debug, client,
+				"carrier2 val: %5d / %s\n", val, cd[i].name);
+		}
+
+		/* program the msp3400 according to the results */
+		state->main = msp3400c_carrier_detect_main[max1].cdo;
+		switch (max1) {
+		case 1: /* 5.5 */
+			state->detected_std = V4L2_STD_BG | V4L2_STD_PAL_H;
+			if (max2 == 0) {
+				/* B/G FM-stereo */
+				state->second = msp3400c_carrier_detect_55[max2].cdo;
+				msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
+				state->watch_stereo = 1;
+			} else if (max2 == 1 && state->has_nicam) {
+				/* B/G NICAM */
+				state->second = msp3400c_carrier_detect_55[max2].cdo;
+				msp3400c_set_mode(client, MSP_MODE_FM_NICAM1);
+				state->nicam_on = 1;
+				state->watch_stereo = 1;
+			} else {
+				goto no_second;
+			}
+			break;
+		case 2: /* 6.0 */
+			/* PAL I NICAM */
+			state->detected_std = V4L2_STD_PAL_I;
+			state->second = MSP_CARRIER(6.552);
+			msp3400c_set_mode(client, MSP_MODE_FM_NICAM2);
+			state->nicam_on = 1;
+			state->watch_stereo = 1;
+			break;
+		case 3: /* 6.5 */
+			if (max2 == 1 || max2 == 2) {
+				/* D/K FM-stereo */
+				state->second = msp3400c_carrier_detect_65[max2].cdo;
+				msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
+				state->watch_stereo = 1;
+				state->detected_std = V4L2_STD_DK;
+			} else if (max2 == 0 && (state->v4l2_std & V4L2_STD_SECAM)) {
+				/* L NICAM or AM-mono */
+				state->second = msp3400c_carrier_detect_65[max2].cdo;
+				msp3400c_set_mode(client, MSP_MODE_AM_NICAM);
+				state->watch_stereo = 1;
+				state->detected_std = V4L2_STD_L;
+			} else if (max2 == 0 && state->has_nicam) {
+				/* D/K NICAM */
+				state->second = msp3400c_carrier_detect_65[max2].cdo;
+				msp3400c_set_mode(client, MSP_MODE_FM_NICAM1);
+				state->nicam_on = 1;
+				state->watch_stereo = 1;
+				state->detected_std = V4L2_STD_DK;
+			} else {
+				goto no_second;
+			}
+			break;
+		case 0: /* 4.5 */
+			state->detected_std = V4L2_STD_MN;
+		default:
+no_second:
+			state->second = msp3400c_carrier_detect_main[max1].cdo;
+			msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
+			break;
+		}
+		msp3400c_set_carrier(client, state->second, state->main);
+
+		/* unmute */
+		state->scan_in_progress = 0;
+		msp3400c_set_audmode(client);
+		msp_update_volume(state);
+
+		if (msp_debug)
+			msp3400c_print_mode(client);
+
+		/* monitor tv audio mode, the first time don't wait
+		   so long to get a quick stereo/bilingual result */
+		count = 3;
+		while (state->watch_stereo) {
+			if (msp_sleep(state, count ? 1000 : 5000))
+				goto restart;
+			if (count)
+				count--;
+			watch_stereo(client);
+		}
+	}
+	v4l_dbg(1, msp_debug, client, "thread: exit\n");
+	return 0;
+}
+
+
+int msp3410d_thread(void *data)
+{
+	struct i2c_client *client = data;
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+	int val, i, std, count;
+
+	v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n");
+	state->detected_std = V4L2_STD_ALL;
+	set_freezable();
+	for (;;) {
+		v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n");
+		msp_sleep(state, -1);
+		v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n");
+
+restart:
+		v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
+		state->restart = 0;
+		if (kthread_should_stop())
+			break;
+
+		if (state->mode == MSP_MODE_EXTERN) {
+			/* no carrier scan needed, just unmute */
+			v4l_dbg(1, msp_debug, client,
+				"thread: no carrier scan\n");
+			state->scan_in_progress = 0;
+			msp_update_volume(state);
+			continue;
+		}
+
+		/* mute audio */
+		state->scan_in_progress = 1;
+		msp_update_volume(state);
+
+		/* start autodetect. Note: autodetect is not supported for
+		   NTSC-M and radio, hence we force the standard in those
+		   cases. */
+		if (state->radio)
+			std = 0x40;
+		else
+			std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1;
+		state->watch_stereo = 0;
+		state->nicam_on = 0;
+
+		/* wait for tuner to settle down after a channel change */
+		if (msp_sleep(state, 200))
+			goto restart;
+
+		if (msp_debug)
+			v4l_dbg(2, msp_debug, client,
+				"setting standard: %s (0x%04x)\n",
+				msp_standard_std_name(std), std);
+
+		if (std != 1) {
+			/* programmed some specific mode */
+			val = std;
+		} else {
+			/* triggered autodetect */
+			msp_write_dem(client, 0x20, std);
+			for (;;) {
+				if (msp_sleep(state, 100))
+					goto restart;
+
+				/* check results */
+				val = msp_read_dem(client, 0x7e);
+				if (val < 0x07ff)
+					break;
+				v4l_dbg(2, msp_debug, client,
+					"detection still in progress\n");
+			}
+		}
+		for (i = 0; msp_stdlist[i].name != NULL; i++)
+			if (msp_stdlist[i].retval == val)
+				break;
+		v4l_dbg(1, msp_debug, client, "current standard: %s (0x%04x)\n",
+			msp_standard_std_name(val), val);
+		state->main   = msp_stdlist[i].main;
+		state->second = msp_stdlist[i].second;
+		state->std = val;
+		state->rxsubchans = V4L2_TUNER_SUB_MONO;
+
+		if (msp_amsound && !state->radio &&
+		    (state->v4l2_std & V4L2_STD_SECAM) && (val != 0x0009)) {
+			/* autodetection has failed, let backup */
+			v4l_dbg(1, msp_debug, client, "autodetection failed,"
+				" switching to backup standard: %s (0x%04x)\n",
+				msp_stdlist[8].name ?
+					msp_stdlist[8].name : "unknown", val);
+			state->std = val = 0x0009;
+			msp_write_dem(client, 0x20, val);
+		} else {
+			state->detected_std = msp_standard_std(state->std);
+		}
+
+		/* set stereo */
+		switch (val) {
+		case 0x0008: /* B/G NICAM */
+		case 0x000a: /* I NICAM */
+		case 0x000b: /* D/K NICAM */
+			if (val == 0x000a)
+				state->mode = MSP_MODE_FM_NICAM2;
+			else
+				state->mode = MSP_MODE_FM_NICAM1;
+			/* just turn on stereo */
+			state->nicam_on = 1;
+			state->watch_stereo = 1;
+			break;
+		case 0x0009:
+			state->mode = MSP_MODE_AM_NICAM;
+			state->nicam_on = 1;
+			state->watch_stereo = 1;
+			break;
+		case 0x0020: /* BTSC */
+			/* The pre-'G' models only have BTSC-mono */
+			state->mode = MSP_MODE_BTSC;
+			break;
+		case 0x0040: /* FM radio */
+			state->mode = MSP_MODE_FM_RADIO;
+			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+			/* not needed in theory if we have radio, but
+			   short programming enables carrier mute */
+			msp3400c_set_mode(client, MSP_MODE_FM_RADIO);
+			msp3400c_set_carrier(client, MSP_CARRIER(10.7),
+					    MSP_CARRIER(10.7));
+			break;
+		case 0x0002:
+		case 0x0003:
+		case 0x0004:
+		case 0x0005:
+			state->mode = MSP_MODE_FM_TERRA;
+			state->watch_stereo = 1;
+			break;
+		}
+
+		/* set various prescales */
+		msp_write_dsp(client, 0x0d, 0x1900); /* scart */
+		msp_write_dsp(client, 0x0e, 0x3000); /* FM */
+		if (state->has_nicam)
+			msp_write_dsp(client, 0x10, 0x5a00); /* nicam */
+
+		if (state->has_i2s_conf)
+			msp_write_dem(client, 0x40, state->i2s_mode);
+
+		/* unmute */
+		msp3400c_set_audmode(client);
+		state->scan_in_progress = 0;
+		msp_update_volume(state);
+
+		/* monitor tv audio mode, the first time don't wait
+		   so long to get a quick stereo/bilingual result */
+		count = 3;
+		while (state->watch_stereo) {
+			if (msp_sleep(state, count ? 1000 : 5000))
+				goto restart;
+			if (count)
+				count--;
+			watch_stereo(client);
+		}
+	}
+	v4l_dbg(1, msp_debug, client, "thread: exit\n");
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* msp34xxG + (autoselect no-thread)
+ * this one uses both automatic standard detection and automatic sound
+ * select which are available in the newer G versions
+ * struct msp: only norm, acb and source are really used in this mode
+ */
+
+static int msp34xxg_modus(struct i2c_client *client)
+{
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+
+	if (state->radio) {
+		v4l_dbg(1, msp_debug, client, "selected radio modus\n");
+		return 0x0001;
+	}
+	if (state->v4l2_std == V4L2_STD_NTSC_M_JP) {
+		v4l_dbg(1, msp_debug, client, "selected M (EIA-J) modus\n");
+		return 0x4001;
+	}
+	if (state->v4l2_std == V4L2_STD_NTSC_M_KR) {
+		v4l_dbg(1, msp_debug, client, "selected M (A2) modus\n");
+		return 0x0001;
+	}
+	if (state->v4l2_std == V4L2_STD_SECAM_L) {
+		v4l_dbg(1, msp_debug, client, "selected SECAM-L modus\n");
+		return 0x6001;
+	}
+	if (state->v4l2_std & V4L2_STD_MN) {
+		v4l_dbg(1, msp_debug, client, "selected M (BTSC) modus\n");
+		return 0x2001;
+	}
+	return 0x7001;
+}
+
+static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in)
+ {
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+	int source, matrix;
+
+	switch (state->audmode) {
+	case V4L2_TUNER_MODE_MONO:
+		source = 0; /* mono only */
+		matrix = 0x30;
+		break;
+	case V4L2_TUNER_MODE_LANG2:
+		source = 4; /* stereo or B */
+		matrix = 0x10;
+		break;
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+		source = 1; /* stereo or A|B */
+		matrix = 0x20;
+		break;
+	case V4L2_TUNER_MODE_LANG1:
+		source = 3; /* stereo or A */
+		matrix = 0x00;
+		break;
+	case V4L2_TUNER_MODE_STEREO:
+	default:
+		source = 3; /* stereo or A */
+		matrix = 0x20;
+		break;
+	}
+
+	if (in == MSP_DSP_IN_TUNER)
+		source = (source << 8) | 0x20;
+	/* the msp34x2g puts the MAIN_AVC, MAIN and AUX sources in 12, 13, 14
+	   instead of 11, 12, 13. So we add one for that msp version. */
+	else if (in >= MSP_DSP_IN_MAIN_AVC && state->has_dolby_pro_logic)
+		source = ((in + 1) << 8) | matrix;
+	else
+		source = (in << 8) | matrix;
+
+	v4l_dbg(1, msp_debug, client,
+		"set source to %d (0x%x) for output %02x\n", in, source, reg);
+	msp_write_dsp(client, reg, source);
+}
+
+static void msp34xxg_set_sources(struct i2c_client *client)
+{
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+	u32 in = state->route_in;
+
+	msp34xxg_set_source(client, 0x0008, (in >> 4) & 0xf);
+	/* quasi-peak detector is set to same input as the loudspeaker (MAIN) */
+	msp34xxg_set_source(client, 0x000c, (in >> 4) & 0xf);
+	msp34xxg_set_source(client, 0x0009, (in >> 8) & 0xf);
+	msp34xxg_set_source(client, 0x000a, (in >> 12) & 0xf);
+	if (state->has_scart2_out)
+		msp34xxg_set_source(client, 0x0041, (in >> 16) & 0xf);
+	msp34xxg_set_source(client, 0x000b, (in >> 20) & 0xf);
+}
+
+/* (re-)initialize the msp34xxg */
+static void msp34xxg_reset(struct i2c_client *client)
+{
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+	int tuner = (state->route_in >> 3) & 1;
+	int modus;
+
+	/* initialize std to 1 (autodetect) to signal that no standard is
+	   selected yet. */
+	state->std = 1;
+
+	msp_reset(client);
+
+	if (state->has_i2s_conf)
+		msp_write_dem(client, 0x40, state->i2s_mode);
+
+	/* step-by-step initialisation, as described in the manual */
+	modus = msp34xxg_modus(client);
+	modus |= tuner ? 0x100 : 0;
+	msp_write_dem(client, 0x30, modus);
+
+	/* write the dsps that may have an influence on
+	   standard/audio autodetection right now */
+	msp34xxg_set_sources(client);
+
+	msp_write_dsp(client, 0x0d, 0x1900); /* scart */
+	msp_write_dsp(client, 0x0e, 0x3000); /* FM */
+	if (state->has_nicam)
+		msp_write_dsp(client, 0x10, 0x5a00); /* nicam */
+
+	/* set identification threshold. Personally, I
+	 * I set it to a higher value than the default
+	 * of 0x190 to ignore noisy stereo signals.
+	 * this needs tuning. (recommended range 0x00a0-0x03c0)
+	 * 0x7f0 = forced mono mode
+	 *
+	 * a2 threshold for stereo/bilingual.
+	 * Note: this register is part of the Manual/Compatibility mode.
+	 * It is supported by all 'G'-family chips.
+	 */
+	msp_write_dem(client, 0x22, msp_stereo_thresh);
+}
+
+int msp34xxg_thread(void *data)
+{
+	struct i2c_client *client = data;
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+	int val, i;
+
+	v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n");
+	state->detected_std = V4L2_STD_ALL;
+	set_freezable();
+	for (;;) {
+		v4l_dbg(2, msp_debug, client, "msp34xxg thread: sleep\n");
+		msp_sleep(state, -1);
+		v4l_dbg(2, msp_debug, client, "msp34xxg thread: wakeup\n");
+
+restart:
+		v4l_dbg(1, msp_debug, client, "thread: restart scan\n");
+		state->restart = 0;
+		if (kthread_should_stop())
+			break;
+
+		if (state->mode == MSP_MODE_EXTERN) {
+			/* no carrier scan needed, just unmute */
+			v4l_dbg(1, msp_debug, client,
+				"thread: no carrier scan\n");
+			state->scan_in_progress = 0;
+			msp_update_volume(state);
+			continue;
+		}
+
+		/* setup the chip*/
+		msp34xxg_reset(client);
+		state->std = state->radio ? 0x40 :
+			(state->force_btsc && msp_standard == 1) ? 32 : msp_standard;
+		msp_write_dem(client, 0x20, state->std);
+		/* start autodetect */
+		if (state->std != 1)
+			goto unmute;
+
+		/* watch autodetect */
+		v4l_dbg(1, msp_debug, client,
+			"started autodetect, waiting for result\n");
+		for (i = 0; i < 10; i++) {
+			if (msp_sleep(state, 100))
+				goto restart;
+
+			/* check results */
+			val = msp_read_dem(client, 0x7e);
+			if (val < 0x07ff) {
+				state->std = val;
+				break;
+			}
+			v4l_dbg(2, msp_debug, client,
+				"detection still in progress\n");
+		}
+		if (state->std == 1) {
+			v4l_dbg(1, msp_debug, client,
+				"detection still in progress after 10 tries. giving up.\n");
+			continue;
+		}
+
+unmute:
+		v4l_dbg(1, msp_debug, client,
+			"detected standard: %s (0x%04x)\n",
+			msp_standard_std_name(state->std), state->std);
+		state->detected_std = msp_standard_std(state->std);
+
+		if (state->std == 9) {
+			/* AM NICAM mode */
+			msp_write_dsp(client, 0x0e, 0x7c00);
+		}
+
+		/* unmute: dispatch sound to scart output, set scart volume */
+		msp_update_volume(state);
+
+		/* restore ACB */
+		if (msp_write_dsp(client, 0x13, state->acb))
+			return -1;
+
+		/* the periodic stereo/SAP check is only relevant for
+		   the 0x20 standard (BTSC) */
+		if (state->std != 0x20)
+			continue;
+
+		state->watch_stereo = 1;
+
+		/* monitor tv audio mode, the first time don't wait
+		   in order to get a quick stereo/SAP update */
+		watch_stereo(client);
+		while (state->watch_stereo) {
+			watch_stereo(client);
+			if (msp_sleep(state, 5000))
+				goto restart;
+		}
+	}
+	v4l_dbg(1, msp_debug, client, "thread: exit\n");
+	return 0;
+}
+
+static int msp34xxg_detect_stereo(struct i2c_client *client)
+{
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+	int status = msp_read_dem(client, 0x0200);
+	int is_bilingual = status & 0x100;
+	int is_stereo = status & 0x40;
+	int oldrx = state->rxsubchans;
+
+	if (state->mode == MSP_MODE_EXTERN)
+		return 0;
+
+	state->rxsubchans = 0;
+	if (is_stereo)
+		state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+	else
+		state->rxsubchans = V4L2_TUNER_SUB_MONO;
+	if (is_bilingual) {
+		if (state->std == 0x20)
+			state->rxsubchans |= V4L2_TUNER_SUB_SAP;
+		else
+			state->rxsubchans =
+				V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+	}
+	v4l_dbg(1, msp_debug, client,
+		"status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
+		status, is_stereo, is_bilingual, state->rxsubchans);
+	return (oldrx != state->rxsubchans);
+}
+
+static void msp34xxg_set_audmode(struct i2c_client *client)
+{
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+
+	if (state->std == 0x20) {
+	       if ((state->rxsubchans & V4L2_TUNER_SUB_SAP) &&
+		   (state->audmode == V4L2_TUNER_MODE_LANG1_LANG2 ||
+		    state->audmode == V4L2_TUNER_MODE_LANG2)) {
+			msp_write_dem(client, 0x20, 0x21);
+	       } else {
+			msp_write_dem(client, 0x20, 0x20);
+	       }
+	}
+
+	msp34xxg_set_sources(client);
+}
+
+void msp_set_audmode(struct i2c_client *client)
+{
+	struct msp_state *state = to_state(i2c_get_clientdata(client));
+
+	switch (state->opmode) {
+	case OPMODE_MANUAL:
+	case OPMODE_AUTODETECT:
+		msp3400c_set_audmode(client);
+		break;
+	case OPMODE_AUTOSELECT:
+		msp34xxg_set_audmode(client);
+		break;
+	}
+}
+
+int msp_detect_stereo(struct i2c_client *client)
+{
+	struct msp_state *state  = to_state(i2c_get_clientdata(client));
+
+	switch (state->opmode) {
+	case OPMODE_MANUAL:
+	case OPMODE_AUTODETECT:
+		return msp3400c_detect_stereo(client);
+	case OPMODE_AUTOSELECT:
+		return msp34xxg_detect_stereo(client);
+	}
+	return 0;
+}
+
diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c
new file mode 100644
index 0000000..445359c
--- /dev/null
+++ b/drivers/media/i2c/mt9m032.c
@@ -0,0 +1,878 @@
+/*
+ * Driver for MT9M032 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2010-2011 Lund Engineering
+ * Contact: Gil Lund <gwlund@lundeng.com>
+ * Author: Martin Hostettler <martin@neutronstar.dyndns.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/media-entity.h>
+#include <media/mt9m032.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "aptina-pll.h"
+
+/*
+ * width and height include active boundary and black parts
+ *
+ * column    0-  15 active boundary
+ * column   16-1455 image
+ * column 1456-1471 active boundary
+ * column 1472-1599 black
+ *
+ * row       0-  51 black
+ * row      53-  59 active boundary
+ * row      60-1139 image
+ * row    1140-1147 active boundary
+ * row    1148-1151 black
+ */
+
+#define MT9M032_PIXEL_ARRAY_WIDTH			1600
+#define MT9M032_PIXEL_ARRAY_HEIGHT			1152
+
+#define MT9M032_CHIP_VERSION				0x00
+#define		MT9M032_CHIP_VERSION_VALUE		0x1402
+#define MT9M032_ROW_START				0x01
+#define		MT9M032_ROW_START_MIN			0
+#define		MT9M032_ROW_START_MAX			1152
+#define		MT9M032_ROW_START_DEF			60
+#define MT9M032_COLUMN_START				0x02
+#define		MT9M032_COLUMN_START_MIN		0
+#define		MT9M032_COLUMN_START_MAX		1600
+#define		MT9M032_COLUMN_START_DEF		16
+#define MT9M032_ROW_SIZE				0x03
+#define		MT9M032_ROW_SIZE_MIN			32
+#define		MT9M032_ROW_SIZE_MAX			1152
+#define		MT9M032_ROW_SIZE_DEF			1080
+#define MT9M032_COLUMN_SIZE				0x04
+#define		MT9M032_COLUMN_SIZE_MIN			32
+#define		MT9M032_COLUMN_SIZE_MAX			1600
+#define		MT9M032_COLUMN_SIZE_DEF			1440
+#define MT9M032_HBLANK					0x05
+#define MT9M032_VBLANK					0x06
+#define		MT9M032_VBLANK_MAX			0x7ff
+#define MT9M032_SHUTTER_WIDTH_HIGH			0x08
+#define MT9M032_SHUTTER_WIDTH_LOW			0x09
+#define		MT9M032_SHUTTER_WIDTH_MIN		1
+#define		MT9M032_SHUTTER_WIDTH_MAX		1048575
+#define		MT9M032_SHUTTER_WIDTH_DEF		1943
+#define MT9M032_PIX_CLK_CTRL				0x0a
+#define		MT9M032_PIX_CLK_CTRL_INV_PIXCLK		0x8000
+#define MT9M032_RESTART					0x0b
+#define MT9M032_RESET					0x0d
+#define MT9M032_PLL_CONFIG1				0x11
+#define		MT9M032_PLL_CONFIG1_OUTDIV_MASK		0x3f
+#define		MT9M032_PLL_CONFIG1_MUL_SHIFT		8
+#define MT9M032_READ_MODE1				0x1e
+#define MT9M032_READ_MODE2				0x20
+#define		MT9M032_READ_MODE2_VFLIP_SHIFT		15
+#define		MT9M032_READ_MODE2_HFLIP_SHIFT		14
+#define		MT9M032_READ_MODE2_ROW_BLC		0x40
+#define MT9M032_GAIN_GREEN1				0x2b
+#define MT9M032_GAIN_BLUE				0x2c
+#define MT9M032_GAIN_RED				0x2d
+#define MT9M032_GAIN_GREEN2				0x2e
+
+/* write only */
+#define MT9M032_GAIN_ALL				0x35
+#define		MT9M032_GAIN_DIGITAL_MASK		0x7f
+#define		MT9M032_GAIN_DIGITAL_SHIFT		8
+#define		MT9M032_GAIN_AMUL_SHIFT			6
+#define		MT9M032_GAIN_ANALOG_MASK		0x3f
+#define MT9M032_FORMATTER1				0x9e
+#define MT9M032_FORMATTER2				0x9f
+#define		MT9M032_FORMATTER2_DOUT_EN		0x1000
+#define		MT9M032_FORMATTER2_PIXCLK_EN		0x2000
+
+/*
+ * The available MT9M032 datasheet is missing documentation for register 0x10
+ * MT9P031 seems to be close enough, so use constants from that datasheet for
+ * now.
+ * But keep the name MT9P031 to remind us, that this isn't really confirmed
+ * for this sensor.
+ */
+#define MT9P031_PLL_CONTROL				0x10
+#define		MT9P031_PLL_CONTROL_PWROFF		0x0050
+#define		MT9P031_PLL_CONTROL_PWRON		0x0051
+#define		MT9P031_PLL_CONTROL_USEPLL		0x0052
+#define MT9P031_PLL_CONFIG2				0x11
+#define		MT9P031_PLL_CONFIG2_P1_DIV_MASK		0x1f
+
+struct mt9m032 {
+	struct v4l2_subdev subdev;
+	struct media_pad pad;
+	struct mt9m032_platform_data *pdata;
+
+	unsigned int pix_clock;
+
+	struct v4l2_ctrl_handler ctrls;
+	struct {
+		struct v4l2_ctrl *hflip;
+		struct v4l2_ctrl *vflip;
+	};
+
+	struct mutex lock; /* Protects streaming, format, interval and crop */
+
+	bool streaming;
+
+	struct v4l2_mbus_framefmt format;
+	struct v4l2_rect crop;
+	struct v4l2_fract frame_interval;
+};
+
+#define to_mt9m032(sd)	container_of(sd, struct mt9m032, subdev)
+#define to_dev(sensor) \
+	(&((struct i2c_client *)v4l2_get_subdevdata(&(sensor)->subdev))->dev)
+
+static int mt9m032_read(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_word_swapped(client, reg);
+}
+
+static int mt9m032_write(struct i2c_client *client, u8 reg, const u16 data)
+{
+	return i2c_smbus_write_word_swapped(client, reg, data);
+}
+
+static u32 mt9m032_row_time(struct mt9m032 *sensor, unsigned int width)
+{
+	unsigned int effective_width;
+	u32 ns;
+
+	effective_width = width + 716; /* empirical value */
+	ns = div_u64(1000000000ULL * effective_width, sensor->pix_clock);
+	dev_dbg(to_dev(sensor),	"MT9M032 line time: %u ns\n", ns);
+	return ns;
+}
+
+static int mt9m032_update_timing(struct mt9m032 *sensor,
+				 struct v4l2_fract *interval)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+	struct v4l2_rect *crop = &sensor->crop;
+	unsigned int min_vblank;
+	unsigned int vblank;
+	u32 row_time;
+
+	if (!interval)
+		interval = &sensor->frame_interval;
+
+	row_time = mt9m032_row_time(sensor, crop->width);
+
+	vblank = div_u64(1000000000ULL * interval->numerator,
+			 (u64)row_time * interval->denominator)
+	       - crop->height;
+
+	if (vblank > MT9M032_VBLANK_MAX) {
+		/* hardware limits to 11 bit values */
+		interval->denominator = 1000;
+		interval->numerator =
+			div_u64((crop->height + MT9M032_VBLANK_MAX) *
+				(u64)row_time * interval->denominator,
+				1000000000ULL);
+		vblank = div_u64(1000000000ULL * interval->numerator,
+				 (u64)row_time * interval->denominator)
+		       - crop->height;
+	}
+	/* enforce minimal 1.6ms blanking time. */
+	min_vblank = 1600000 / row_time;
+	vblank = clamp_t(unsigned int, vblank, min_vblank, MT9M032_VBLANK_MAX);
+
+	return mt9m032_write(client, MT9M032_VBLANK, vblank);
+}
+
+static int mt9m032_update_geom_timing(struct mt9m032 *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+	int ret;
+
+	ret = mt9m032_write(client, MT9M032_COLUMN_SIZE,
+			    sensor->crop.width - 1);
+	if (!ret)
+		ret = mt9m032_write(client, MT9M032_ROW_SIZE,
+				    sensor->crop.height - 1);
+	if (!ret)
+		ret = mt9m032_write(client, MT9M032_COLUMN_START,
+				    sensor->crop.left);
+	if (!ret)
+		ret = mt9m032_write(client, MT9M032_ROW_START,
+				    sensor->crop.top);
+	if (!ret)
+		ret = mt9m032_update_timing(sensor, NULL);
+	return ret;
+}
+
+static int update_formatter2(struct mt9m032 *sensor, bool streaming)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+	u16 reg_val =   MT9M032_FORMATTER2_DOUT_EN
+		      | 0x0070;  /* parts reserved! */
+				 /* possibly for changing to 14-bit mode */
+
+	if (streaming)
+		reg_val |= MT9M032_FORMATTER2_PIXCLK_EN;   /* pixclock enable */
+
+	return mt9m032_write(client, MT9M032_FORMATTER2, reg_val);
+}
+
+static int mt9m032_setup_pll(struct mt9m032 *sensor)
+{
+	static const struct aptina_pll_limits limits = {
+		.ext_clock_min = 8000000,
+		.ext_clock_max = 16500000,
+		.int_clock_min = 2000000,
+		.int_clock_max = 24000000,
+		.out_clock_min = 322000000,
+		.out_clock_max = 693000000,
+		.pix_clock_max = 99000000,
+		.n_min = 1,
+		.n_max = 64,
+		.m_min = 16,
+		.m_max = 255,
+		.p1_min = 1,
+		.p1_max = 128,
+	};
+
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+	struct mt9m032_platform_data *pdata = sensor->pdata;
+	struct aptina_pll pll;
+	int ret;
+
+	pll.ext_clock = pdata->ext_clock;
+	pll.pix_clock = pdata->pix_clock;
+
+	ret = aptina_pll_calculate(&client->dev, &limits, &pll);
+	if (ret < 0)
+		return ret;
+
+	sensor->pix_clock = pdata->pix_clock;
+
+	ret = mt9m032_write(client, MT9M032_PLL_CONFIG1,
+			    (pll.m << MT9M032_PLL_CONFIG1_MUL_SHIFT)
+			    | (pll.p1 - 1));
+	if (!ret)
+		ret = mt9m032_write(client, MT9P031_PLL_CONFIG2, pll.n - 1);
+	if (!ret)
+		ret = mt9m032_write(client, MT9P031_PLL_CONTROL,
+				    MT9P031_PLL_CONTROL_PWRON |
+				    MT9P031_PLL_CONTROL_USEPLL);
+	if (!ret)		/* more reserved, Continuous, Master Mode */
+		ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8006);
+	if (!ret)		/* Set 14-bit mode, select 7 divider */
+		ret = mt9m032_write(client, MT9M032_FORMATTER1, 0x111e);
+
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Subdev pad operations
+ */
+
+static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->index != 0)
+		return -EINVAL;
+
+	code->code = V4L2_MBUS_FMT_Y8_1X8;
+	return 0;
+}
+
+static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev,
+				   struct v4l2_subdev_fh *fh,
+				   struct v4l2_subdev_frame_size_enum *fse)
+{
+	if (fse->index != 0 || fse->code != V4L2_MBUS_FMT_Y8_1X8)
+		return -EINVAL;
+
+	fse->min_width = MT9M032_COLUMN_SIZE_DEF;
+	fse->max_width = MT9M032_COLUMN_SIZE_DEF;
+	fse->min_height = MT9M032_ROW_SIZE_DEF;
+	fse->max_height = MT9M032_ROW_SIZE_DEF;
+
+	return 0;
+}
+
+/**
+ * __mt9m032_get_pad_crop() - get crop rect
+ * @sensor: pointer to the sensor struct
+ * @fh: file handle for getting the try crop rect from
+ * @which: select try or active crop rect
+ *
+ * Returns a pointer the current active or fh relative try crop rect
+ */
+static struct v4l2_rect *
+__mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh,
+		       enum v4l2_subdev_format_whence which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_crop(fh, 0);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &sensor->crop;
+	default:
+		return NULL;
+	}
+}
+
+/**
+ * __mt9m032_get_pad_format() - get format
+ * @sensor: pointer to the sensor struct
+ * @fh: file handle for getting the try format from
+ * @which: select try or active format
+ *
+ * Returns a pointer the current active or fh relative try format
+ */
+static struct v4l2_mbus_framefmt *
+__mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh,
+			 enum v4l2_subdev_format_whence which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_format(fh, 0);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &sensor->format;
+	default:
+		return NULL;
+	}
+}
+
+static int mt9m032_get_pad_format(struct v4l2_subdev *subdev,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_format *fmt)
+{
+	struct mt9m032 *sensor = to_mt9m032(subdev);
+
+	mutex_lock(&sensor->lock);
+	fmt->format = *__mt9m032_get_pad_format(sensor, fh, fmt->which);
+	mutex_unlock(&sensor->lock);
+
+	return 0;
+}
+
+static int mt9m032_set_pad_format(struct v4l2_subdev *subdev,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_format *fmt)
+{
+	struct mt9m032 *sensor = to_mt9m032(subdev);
+	int ret;
+
+	mutex_lock(&sensor->lock);
+
+	if (sensor->streaming && fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		ret = -EBUSY;
+		goto done;
+	}
+
+	/* Scaling is not supported, the format is thus fixed. */
+	fmt->format = *__mt9m032_get_pad_format(sensor, fh, fmt->which);
+	ret = 0;
+
+done:
+	mutex_unlock(&sensor->lock);
+	return ret;
+}
+
+static int mt9m032_get_pad_crop(struct v4l2_subdev *subdev,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_crop *crop)
+{
+	struct mt9m032 *sensor = to_mt9m032(subdev);
+
+	mutex_lock(&sensor->lock);
+	crop->rect = *__mt9m032_get_pad_crop(sensor, fh, crop->which);
+	mutex_unlock(&sensor->lock);
+
+	return 0;
+}
+
+static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_crop *crop)
+{
+	struct mt9m032 *sensor = to_mt9m032(subdev);
+	struct v4l2_mbus_framefmt *format;
+	struct v4l2_rect *__crop;
+	struct v4l2_rect rect;
+	int ret = 0;
+
+	mutex_lock(&sensor->lock);
+
+	if (sensor->streaming && crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		ret = -EBUSY;
+		goto done;
+	}
+
+	/* Clamp the crop rectangle boundaries and align them to a multiple of 2
+	 * pixels to ensure a GRBG Bayer pattern.
+	 */
+	rect.left = clamp(ALIGN(crop->rect.left, 2), MT9M032_COLUMN_START_MIN,
+			  MT9M032_COLUMN_START_MAX);
+	rect.top = clamp(ALIGN(crop->rect.top, 2), MT9M032_ROW_START_MIN,
+			 MT9M032_ROW_START_MAX);
+	rect.width = clamp(ALIGN(crop->rect.width, 2), MT9M032_COLUMN_SIZE_MIN,
+			   MT9M032_COLUMN_SIZE_MAX);
+	rect.height = clamp(ALIGN(crop->rect.height, 2), MT9M032_ROW_SIZE_MIN,
+			    MT9M032_ROW_SIZE_MAX);
+
+	rect.width = min(rect.width, MT9M032_PIXEL_ARRAY_WIDTH - rect.left);
+	rect.height = min(rect.height, MT9M032_PIXEL_ARRAY_HEIGHT - rect.top);
+
+	__crop = __mt9m032_get_pad_crop(sensor, fh, crop->which);
+
+	if (rect.width != __crop->width || rect.height != __crop->height) {
+		/* Reset the output image size if the crop rectangle size has
+		 * been modified.
+		 */
+		format = __mt9m032_get_pad_format(sensor, fh, crop->which);
+		format->width = rect.width;
+		format->height = rect.height;
+	}
+
+	*__crop = rect;
+	crop->rect = rect;
+
+	if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		ret = mt9m032_update_geom_timing(sensor);
+
+done:
+	mutex_unlock(&sensor->lock);
+	return ret;
+}
+
+static int mt9m032_get_frame_interval(struct v4l2_subdev *subdev,
+				      struct v4l2_subdev_frame_interval *fi)
+{
+	struct mt9m032 *sensor = to_mt9m032(subdev);
+
+	mutex_lock(&sensor->lock);
+	memset(fi, 0, sizeof(*fi));
+	fi->interval = sensor->frame_interval;
+	mutex_unlock(&sensor->lock);
+
+	return 0;
+}
+
+static int mt9m032_set_frame_interval(struct v4l2_subdev *subdev,
+				      struct v4l2_subdev_frame_interval *fi)
+{
+	struct mt9m032 *sensor = to_mt9m032(subdev);
+	int ret;
+
+	mutex_lock(&sensor->lock);
+
+	if (sensor->streaming) {
+		ret = -EBUSY;
+		goto done;
+	}
+
+	/* Avoid divisions by 0. */
+	if (fi->interval.denominator == 0)
+		fi->interval.denominator = 1;
+
+	ret = mt9m032_update_timing(sensor, &fi->interval);
+	if (!ret)
+		sensor->frame_interval = fi->interval;
+
+done:
+	mutex_unlock(&sensor->lock);
+	return ret;
+}
+
+static int mt9m032_s_stream(struct v4l2_subdev *subdev, int streaming)
+{
+	struct mt9m032 *sensor = to_mt9m032(subdev);
+	int ret;
+
+	mutex_lock(&sensor->lock);
+	ret = update_formatter2(sensor, streaming);
+	if (!ret)
+		sensor->streaming = streaming;
+	mutex_unlock(&sensor->lock);
+
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9m032_g_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct mt9m032 *sensor = to_mt9m032(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+	int val;
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+		return -EINVAL;
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	val = mt9m032_read(client, reg->reg);
+	if (val < 0)
+		return -EIO;
+
+	reg->size = 2;
+	reg->val = val;
+
+	return 0;
+}
+
+static int mt9m032_s_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct mt9m032 *sensor = to_mt9m032(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+		return -EINVAL;
+
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	return mt9m032_write(client, reg->reg, reg->val);
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev control operations
+ */
+
+static int update_read_mode2(struct mt9m032 *sensor, bool vflip, bool hflip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+	int reg_val = (vflip << MT9M032_READ_MODE2_VFLIP_SHIFT)
+		    | (hflip << MT9M032_READ_MODE2_HFLIP_SHIFT)
+		    | MT9M032_READ_MODE2_ROW_BLC
+		    | 0x0007;
+
+	return mt9m032_write(client, MT9M032_READ_MODE2, reg_val);
+}
+
+static int mt9m032_set_gain(struct mt9m032 *sensor, s32 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+	int digital_gain_val;	/* in 1/8th (0..127) */
+	int analog_mul;		/* 0 or 1 */
+	int analog_gain_val;	/* in 1/16th. (0..63) */
+	u16 reg_val;
+
+	digital_gain_val = 51; /* from setup example */
+
+	if (val < 63) {
+		analog_mul = 0;
+		analog_gain_val = val;
+	} else {
+		analog_mul = 1;
+		analog_gain_val = val / 2;
+	}
+
+	/* a_gain = (1 + analog_mul) + (analog_gain_val + 1) / 16 */
+	/* overall_gain = a_gain * (1 + digital_gain_val / 8) */
+
+	reg_val = ((digital_gain_val & MT9M032_GAIN_DIGITAL_MASK)
+		   << MT9M032_GAIN_DIGITAL_SHIFT)
+		| ((analog_mul & 1) << MT9M032_GAIN_AMUL_SHIFT)
+		| (analog_gain_val & MT9M032_GAIN_ANALOG_MASK);
+
+	return mt9m032_write(client, MT9M032_GAIN_ALL, reg_val);
+}
+
+static int mt9m032_try_ctrl(struct v4l2_ctrl *ctrl)
+{
+	if (ctrl->id == V4L2_CID_GAIN && ctrl->val >= 63) {
+		/* round because of multiplier used for values >= 63 */
+		ctrl->val &= ~1;
+	}
+
+	return 0;
+}
+
+static int mt9m032_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mt9m032 *sensor =
+		container_of(ctrl->handler, struct mt9m032, ctrls);
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+	int ret;
+
+	switch (ctrl->id) {
+	case V4L2_CID_GAIN:
+		return mt9m032_set_gain(sensor, ctrl->val);
+
+	case V4L2_CID_HFLIP:
+	/* case V4L2_CID_VFLIP: -- In the same cluster */
+		return update_read_mode2(sensor, sensor->vflip->val,
+					 sensor->hflip->val);
+
+	case V4L2_CID_EXPOSURE:
+		ret = mt9m032_write(client, MT9M032_SHUTTER_WIDTH_HIGH,
+				    (ctrl->val >> 16) & 0xffff);
+		if (ret < 0)
+			return ret;
+
+		return mt9m032_write(client, MT9M032_SHUTTER_WIDTH_LOW,
+				     ctrl->val & 0xffff);
+	}
+
+	return 0;
+}
+
+static struct v4l2_ctrl_ops mt9m032_ctrl_ops = {
+	.s_ctrl = mt9m032_set_ctrl,
+	.try_ctrl = mt9m032_try_ctrl,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops mt9m032_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = mt9m032_g_register,
+	.s_register = mt9m032_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops mt9m032_video_ops = {
+	.s_stream = mt9m032_s_stream,
+	.g_frame_interval = mt9m032_get_frame_interval,
+	.s_frame_interval = mt9m032_set_frame_interval,
+};
+
+static const struct v4l2_subdev_pad_ops mt9m032_pad_ops = {
+	.enum_mbus_code = mt9m032_enum_mbus_code,
+	.enum_frame_size = mt9m032_enum_frame_size,
+	.get_fmt = mt9m032_get_pad_format,
+	.set_fmt = mt9m032_set_pad_format,
+	.set_crop = mt9m032_set_pad_crop,
+	.get_crop = mt9m032_get_pad_crop,
+};
+
+static const struct v4l2_subdev_ops mt9m032_ops = {
+	.core = &mt9m032_core_ops,
+	.video = &mt9m032_video_ops,
+	.pad = &mt9m032_pad_ops,
+};
+
+/* -----------------------------------------------------------------------------
+ * Driver initialization and probing
+ */
+
+static int mt9m032_probe(struct i2c_client *client,
+			 const struct i2c_device_id *devid)
+{
+	struct mt9m032_platform_data *pdata = client->dev.platform_data;
+	struct i2c_adapter *adapter = client->adapter;
+	struct mt9m032 *sensor;
+	int chip_version;
+	int ret;
+
+	if (pdata == NULL) {
+		dev_err(&client->dev, "No platform data\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_warn(&client->dev,
+			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+		return -EIO;
+	}
+
+	if (!client->dev.platform_data)
+		return -ENODEV;
+
+	sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
+	if (sensor == NULL)
+		return -ENOMEM;
+
+	mutex_init(&sensor->lock);
+
+	sensor->pdata = pdata;
+
+	v4l2_i2c_subdev_init(&sensor->subdev, client, &mt9m032_ops);
+	sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	chip_version = mt9m032_read(client, MT9M032_CHIP_VERSION);
+	if (chip_version != MT9M032_CHIP_VERSION_VALUE) {
+		dev_err(&client->dev, "MT9M032 not detected, wrong version "
+			"0x%04x\n", chip_version);
+		ret = -ENODEV;
+		goto error_sensor;
+	}
+
+	dev_info(&client->dev, "MT9M032 detected at address 0x%02x\n",
+		 client->addr);
+
+	sensor->frame_interval.numerator = 1;
+	sensor->frame_interval.denominator = 30;
+
+	sensor->crop.left = MT9M032_COLUMN_START_DEF;
+	sensor->crop.top = MT9M032_ROW_START_DEF;
+	sensor->crop.width = MT9M032_COLUMN_SIZE_DEF;
+	sensor->crop.height = MT9M032_ROW_SIZE_DEF;
+
+	sensor->format.width = sensor->crop.width;
+	sensor->format.height = sensor->crop.height;
+	sensor->format.code = V4L2_MBUS_FMT_Y8_1X8;
+	sensor->format.field = V4L2_FIELD_NONE;
+	sensor->format.colorspace = V4L2_COLORSPACE_SRGB;
+
+	v4l2_ctrl_handler_init(&sensor->ctrls, 5);
+
+	v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
+			  V4L2_CID_GAIN, 0, 127, 1, 64);
+
+	sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls,
+					  &mt9m032_ctrl_ops,
+					  V4L2_CID_HFLIP, 0, 1, 1, 0);
+	sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls,
+					  &mt9m032_ctrl_ops,
+					  V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+	v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
+			  V4L2_CID_EXPOSURE, MT9M032_SHUTTER_WIDTH_MIN,
+			  MT9M032_SHUTTER_WIDTH_MAX, 1,
+			  MT9M032_SHUTTER_WIDTH_DEF);
+	v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
+			  V4L2_CID_PIXEL_RATE, pdata->pix_clock,
+			  pdata->pix_clock, 1, pdata->pix_clock);
+
+	if (sensor->ctrls.error) {
+		ret = sensor->ctrls.error;
+		dev_err(&client->dev, "control initialization error %d\n", ret);
+		goto error_ctrl;
+	}
+
+	v4l2_ctrl_cluster(2, &sensor->hflip);
+
+	sensor->subdev.ctrl_handler = &sensor->ctrls;
+	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_init(&sensor->subdev.entity, 1, &sensor->pad, 0);
+	if (ret < 0)
+		goto error_ctrl;
+
+	ret = mt9m032_write(client, MT9M032_RESET, 1);	/* reset on */
+	if (ret < 0)
+		goto error_entity;
+	mt9m032_write(client, MT9M032_RESET, 0);	/* reset off */
+	if (ret < 0)
+		goto error_entity;
+
+	ret = mt9m032_setup_pll(sensor);
+	if (ret < 0)
+		goto error_entity;
+	usleep_range(10000, 11000);
+
+	ret = v4l2_ctrl_handler_setup(&sensor->ctrls);
+	if (ret < 0)
+		goto error_entity;
+
+	/* SIZE */
+	ret = mt9m032_update_geom_timing(sensor);
+	if (ret < 0)
+		goto error_entity;
+
+	ret = mt9m032_write(client, 0x41, 0x0000);	/* reserved !!! */
+	if (ret < 0)
+		goto error_entity;
+	ret = mt9m032_write(client, 0x42, 0x0003);	/* reserved !!! */
+	if (ret < 0)
+		goto error_entity;
+	ret = mt9m032_write(client, 0x43, 0x0003);	/* reserved !!! */
+	if (ret < 0)
+		goto error_entity;
+	ret = mt9m032_write(client, 0x7f, 0x0000);	/* reserved !!! */
+	if (ret < 0)
+		goto error_entity;
+	if (sensor->pdata->invert_pixclock) {
+		ret = mt9m032_write(client, MT9M032_PIX_CLK_CTRL,
+				    MT9M032_PIX_CLK_CTRL_INV_PIXCLK);
+		if (ret < 0)
+			goto error_entity;
+	}
+
+	ret = mt9m032_write(client, MT9M032_RESTART, 1); /* Restart on */
+	if (ret < 0)
+		goto error_entity;
+	msleep(100);
+	ret = mt9m032_write(client, MT9M032_RESTART, 0); /* Restart off */
+	if (ret < 0)
+		goto error_entity;
+	msleep(100);
+	ret = update_formatter2(sensor, false);
+	if (ret < 0)
+		goto error_entity;
+
+	return ret;
+
+error_entity:
+	media_entity_cleanup(&sensor->subdev.entity);
+error_ctrl:
+	v4l2_ctrl_handler_free(&sensor->ctrls);
+error_sensor:
+	mutex_destroy(&sensor->lock);
+	kfree(sensor);
+	return ret;
+}
+
+static int mt9m032_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct mt9m032 *sensor = to_mt9m032(subdev);
+
+	v4l2_device_unregister_subdev(subdev);
+	v4l2_ctrl_handler_free(&sensor->ctrls);
+	media_entity_cleanup(&subdev->entity);
+	mutex_destroy(&sensor->lock);
+	kfree(sensor);
+	return 0;
+}
+
+static const struct i2c_device_id mt9m032_id_table[] = {
+	{ MT9M032_NAME, 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, mt9m032_id_table);
+
+static struct i2c_driver mt9m032_i2c_driver = {
+	.driver = {
+		.name = MT9M032_NAME,
+	},
+	.probe = mt9m032_probe,
+	.remove = mt9m032_remove,
+	.id_table = mt9m032_id_table,
+};
+
+module_i2c_driver(mt9m032_i2c_driver);
+
+MODULE_AUTHOR("Martin Hostettler <martin@neutronstar.dyndns.org>");
+MODULE_DESCRIPTION("MT9M032 camera sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
new file mode 100644
index 0000000..3be537e
--- /dev/null
+++ b/drivers/media/i2c/mt9p031.c
@@ -0,0 +1,1071 @@
+/*
+ * Driver for MT9P031 CMOS Image Sensor from Aptina
+ *
+ * Copyright (C) 2011, Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Copyright (C) 2011, Javier Martin <javier.martin@vista-silicon.com>
+ * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * Based on the MT9V032 driver and Bastian Hecht's code.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/mt9p031.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "aptina-pll.h"
+
+#define MT9P031_PIXEL_ARRAY_WIDTH			2752
+#define MT9P031_PIXEL_ARRAY_HEIGHT			2004
+
+#define MT9P031_CHIP_VERSION				0x00
+#define		MT9P031_CHIP_VERSION_VALUE		0x1801
+#define MT9P031_ROW_START				0x01
+#define		MT9P031_ROW_START_MIN			0
+#define		MT9P031_ROW_START_MAX			2004
+#define		MT9P031_ROW_START_DEF			54
+#define MT9P031_COLUMN_START				0x02
+#define		MT9P031_COLUMN_START_MIN		0
+#define		MT9P031_COLUMN_START_MAX		2750
+#define		MT9P031_COLUMN_START_DEF		16
+#define MT9P031_WINDOW_HEIGHT				0x03
+#define		MT9P031_WINDOW_HEIGHT_MIN		2
+#define		MT9P031_WINDOW_HEIGHT_MAX		2006
+#define		MT9P031_WINDOW_HEIGHT_DEF		1944
+#define MT9P031_WINDOW_WIDTH				0x04
+#define		MT9P031_WINDOW_WIDTH_MIN		2
+#define		MT9P031_WINDOW_WIDTH_MAX		2752
+#define		MT9P031_WINDOW_WIDTH_DEF		2592
+#define MT9P031_HORIZONTAL_BLANK			0x05
+#define		MT9P031_HORIZONTAL_BLANK_MIN		0
+#define		MT9P031_HORIZONTAL_BLANK_MAX		4095
+#define MT9P031_VERTICAL_BLANK				0x06
+#define		MT9P031_VERTICAL_BLANK_MIN		0
+#define		MT9P031_VERTICAL_BLANK_MAX		4095
+#define		MT9P031_VERTICAL_BLANK_DEF		25
+#define MT9P031_OUTPUT_CONTROL				0x07
+#define		MT9P031_OUTPUT_CONTROL_CEN		2
+#define		MT9P031_OUTPUT_CONTROL_SYN		1
+#define		MT9P031_OUTPUT_CONTROL_DEF		0x1f82
+#define MT9P031_SHUTTER_WIDTH_UPPER			0x08
+#define MT9P031_SHUTTER_WIDTH_LOWER			0x09
+#define		MT9P031_SHUTTER_WIDTH_MIN		1
+#define		MT9P031_SHUTTER_WIDTH_MAX		1048575
+#define		MT9P031_SHUTTER_WIDTH_DEF		1943
+#define	MT9P031_PLL_CONTROL				0x10
+#define		MT9P031_PLL_CONTROL_PWROFF		0x0050
+#define		MT9P031_PLL_CONTROL_PWRON		0x0051
+#define		MT9P031_PLL_CONTROL_USEPLL		0x0052
+#define	MT9P031_PLL_CONFIG_1				0x11
+#define	MT9P031_PLL_CONFIG_2				0x12
+#define MT9P031_PIXEL_CLOCK_CONTROL			0x0a
+#define MT9P031_FRAME_RESTART				0x0b
+#define MT9P031_SHUTTER_DELAY				0x0c
+#define MT9P031_RST					0x0d
+#define		MT9P031_RST_ENABLE			1
+#define		MT9P031_RST_DISABLE			0
+#define MT9P031_READ_MODE_1				0x1e
+#define MT9P031_READ_MODE_2				0x20
+#define		MT9P031_READ_MODE_2_ROW_MIR		(1 << 15)
+#define		MT9P031_READ_MODE_2_COL_MIR		(1 << 14)
+#define		MT9P031_READ_MODE_2_ROW_BLC		(1 << 6)
+#define MT9P031_ROW_ADDRESS_MODE			0x22
+#define MT9P031_COLUMN_ADDRESS_MODE			0x23
+#define MT9P031_GLOBAL_GAIN				0x35
+#define		MT9P031_GLOBAL_GAIN_MIN			8
+#define		MT9P031_GLOBAL_GAIN_MAX			1024
+#define		MT9P031_GLOBAL_GAIN_DEF			8
+#define		MT9P031_GLOBAL_GAIN_MULT		(1 << 6)
+#define MT9P031_ROW_BLACK_TARGET			0x49
+#define MT9P031_ROW_BLACK_DEF_OFFSET			0x4b
+#define MT9P031_GREEN1_OFFSET				0x60
+#define MT9P031_GREEN2_OFFSET				0x61
+#define MT9P031_BLACK_LEVEL_CALIBRATION			0x62
+#define		MT9P031_BLC_MANUAL_BLC			(1 << 0)
+#define MT9P031_RED_OFFSET				0x63
+#define MT9P031_BLUE_OFFSET				0x64
+#define MT9P031_TEST_PATTERN				0xa0
+#define		MT9P031_TEST_PATTERN_SHIFT		3
+#define		MT9P031_TEST_PATTERN_ENABLE		(1 << 0)
+#define		MT9P031_TEST_PATTERN_DISABLE		(0 << 0)
+#define MT9P031_TEST_PATTERN_GREEN			0xa1
+#define MT9P031_TEST_PATTERN_RED			0xa2
+#define MT9P031_TEST_PATTERN_BLUE			0xa3
+
+enum mt9p031_model {
+	MT9P031_MODEL_COLOR,
+	MT9P031_MODEL_MONOCHROME,
+};
+
+struct mt9p031 {
+	struct v4l2_subdev subdev;
+	struct media_pad pad;
+	struct v4l2_rect crop;  /* Sensor window */
+	struct v4l2_mbus_framefmt format;
+	struct mt9p031_platform_data *pdata;
+	struct mutex power_lock; /* lock to protect power_count */
+	int power_count;
+
+	enum mt9p031_model model;
+	struct aptina_pll pll;
+	int reset;
+
+	struct v4l2_ctrl_handler ctrls;
+	struct v4l2_ctrl *blc_auto;
+	struct v4l2_ctrl *blc_offset;
+
+	/* Registers cache */
+	u16 output_control;
+	u16 mode2;
+};
+
+static struct mt9p031 *to_mt9p031(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct mt9p031, subdev);
+}
+
+static int mt9p031_read(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_word_swapped(client, reg);
+}
+
+static int mt9p031_write(struct i2c_client *client, u8 reg, u16 data)
+{
+	return i2c_smbus_write_word_swapped(client, reg, data);
+}
+
+static int mt9p031_set_output_control(struct mt9p031 *mt9p031, u16 clear,
+				      u16 set)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+	u16 value = (mt9p031->output_control & ~clear) | set;
+	int ret;
+
+	ret = mt9p031_write(client, MT9P031_OUTPUT_CONTROL, value);
+	if (ret < 0)
+		return ret;
+
+	mt9p031->output_control = value;
+	return 0;
+}
+
+static int mt9p031_set_mode2(struct mt9p031 *mt9p031, u16 clear, u16 set)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+	u16 value = (mt9p031->mode2 & ~clear) | set;
+	int ret;
+
+	ret = mt9p031_write(client, MT9P031_READ_MODE_2, value);
+	if (ret < 0)
+		return ret;
+
+	mt9p031->mode2 = value;
+	return 0;
+}
+
+static int mt9p031_reset(struct mt9p031 *mt9p031)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+	int ret;
+
+	/* Disable chip output, synchronous option update */
+	ret = mt9p031_write(client, MT9P031_RST, MT9P031_RST_ENABLE);
+	if (ret < 0)
+		return ret;
+	ret = mt9p031_write(client, MT9P031_RST, MT9P031_RST_DISABLE);
+	if (ret < 0)
+		return ret;
+
+	return mt9p031_set_output_control(mt9p031, MT9P031_OUTPUT_CONTROL_CEN,
+					  0);
+}
+
+static int mt9p031_pll_setup(struct mt9p031 *mt9p031)
+{
+	static const struct aptina_pll_limits limits = {
+		.ext_clock_min = 6000000,
+		.ext_clock_max = 27000000,
+		.int_clock_min = 2000000,
+		.int_clock_max = 13500000,
+		.out_clock_min = 180000000,
+		.out_clock_max = 360000000,
+		.pix_clock_max = 96000000,
+		.n_min = 1,
+		.n_max = 64,
+		.m_min = 16,
+		.m_max = 255,
+		.p1_min = 1,
+		.p1_max = 128,
+	};
+
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+	struct mt9p031_platform_data *pdata = mt9p031->pdata;
+
+	mt9p031->pll.ext_clock = pdata->ext_freq;
+	mt9p031->pll.pix_clock = pdata->target_freq;
+
+	return aptina_pll_calculate(&client->dev, &limits, &mt9p031->pll);
+}
+
+static int mt9p031_pll_enable(struct mt9p031 *mt9p031)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+	int ret;
+
+	ret = mt9p031_write(client, MT9P031_PLL_CONTROL,
+			    MT9P031_PLL_CONTROL_PWRON);
+	if (ret < 0)
+		return ret;
+
+	ret = mt9p031_write(client, MT9P031_PLL_CONFIG_1,
+			    (mt9p031->pll.m << 8) | (mt9p031->pll.n - 1));
+	if (ret < 0)
+		return ret;
+
+	ret = mt9p031_write(client, MT9P031_PLL_CONFIG_2, mt9p031->pll.p1 - 1);
+	if (ret < 0)
+		return ret;
+
+	usleep_range(1000, 2000);
+	ret = mt9p031_write(client, MT9P031_PLL_CONTROL,
+			    MT9P031_PLL_CONTROL_PWRON |
+			    MT9P031_PLL_CONTROL_USEPLL);
+	return ret;
+}
+
+static inline int mt9p031_pll_disable(struct mt9p031 *mt9p031)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+
+	return mt9p031_write(client, MT9P031_PLL_CONTROL,
+			     MT9P031_PLL_CONTROL_PWROFF);
+}
+
+static int mt9p031_power_on(struct mt9p031 *mt9p031)
+{
+	/* Ensure RESET_BAR is low */
+	if (mt9p031->reset != -1) {
+		gpio_set_value(mt9p031->reset, 0);
+		usleep_range(1000, 2000);
+	}
+
+	/* Emable clock */
+	if (mt9p031->pdata->set_xclk)
+		mt9p031->pdata->set_xclk(&mt9p031->subdev,
+					 mt9p031->pdata->ext_freq);
+
+	/* Now RESET_BAR must be high */
+	if (mt9p031->reset != -1) {
+		gpio_set_value(mt9p031->reset, 1);
+		usleep_range(1000, 2000);
+	}
+
+	return 0;
+}
+
+static void mt9p031_power_off(struct mt9p031 *mt9p031)
+{
+	if (mt9p031->reset != -1) {
+		gpio_set_value(mt9p031->reset, 0);
+		usleep_range(1000, 2000);
+	}
+
+	if (mt9p031->pdata->set_xclk)
+		mt9p031->pdata->set_xclk(&mt9p031->subdev, 0);
+}
+
+static int __mt9p031_set_power(struct mt9p031 *mt9p031, bool on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+	int ret;
+
+	if (!on) {
+		mt9p031_power_off(mt9p031);
+		return 0;
+	}
+
+	ret = mt9p031_power_on(mt9p031);
+	if (ret < 0)
+		return ret;
+
+	ret = mt9p031_reset(mt9p031);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to reset the camera\n");
+		return ret;
+	}
+
+	return v4l2_ctrl_handler_setup(&mt9p031->ctrls);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev video operations
+ */
+
+static int mt9p031_set_params(struct mt9p031 *mt9p031)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+	struct v4l2_mbus_framefmt *format = &mt9p031->format;
+	const struct v4l2_rect *crop = &mt9p031->crop;
+	unsigned int hblank;
+	unsigned int vblank;
+	unsigned int xskip;
+	unsigned int yskip;
+	unsigned int xbin;
+	unsigned int ybin;
+	int ret;
+
+	/* Windows position and size.
+	 *
+	 * TODO: Make sure the start coordinates and window size match the
+	 * skipping, binning and mirroring (see description of registers 2 and 4
+	 * in table 13, and Binning section on page 41).
+	 */
+	ret = mt9p031_write(client, MT9P031_COLUMN_START, crop->left);
+	if (ret < 0)
+		return ret;
+	ret = mt9p031_write(client, MT9P031_ROW_START, crop->top);
+	if (ret < 0)
+		return ret;
+	ret = mt9p031_write(client, MT9P031_WINDOW_WIDTH, crop->width - 1);
+	if (ret < 0)
+		return ret;
+	ret = mt9p031_write(client, MT9P031_WINDOW_HEIGHT, crop->height - 1);
+	if (ret < 0)
+		return ret;
+
+	/* Row and column binning and skipping. Use the maximum binning value
+	 * compatible with the skipping settings.
+	 */
+	xskip = DIV_ROUND_CLOSEST(crop->width, format->width);
+	yskip = DIV_ROUND_CLOSEST(crop->height, format->height);
+	xbin = 1 << (ffs(xskip) - 1);
+	ybin = 1 << (ffs(yskip) - 1);
+
+	ret = mt9p031_write(client, MT9P031_COLUMN_ADDRESS_MODE,
+			    ((xbin - 1) << 4) | (xskip - 1));
+	if (ret < 0)
+		return ret;
+	ret = mt9p031_write(client, MT9P031_ROW_ADDRESS_MODE,
+			    ((ybin - 1) << 4) | (yskip - 1));
+	if (ret < 0)
+		return ret;
+
+	/* Blanking - use minimum value for horizontal blanking and default
+	 * value for vertical blanking.
+	 */
+	hblank = 346 * ybin + 64 + (80 >> max_t(unsigned int, xbin, 3));
+	vblank = MT9P031_VERTICAL_BLANK_DEF;
+
+	ret = mt9p031_write(client, MT9P031_HORIZONTAL_BLANK, hblank);
+	if (ret < 0)
+		return ret;
+	ret = mt9p031_write(client, MT9P031_VERTICAL_BLANK, vblank);
+	if (ret < 0)
+		return ret;
+
+	return ret;
+}
+
+static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+	int ret;
+
+	if (!enable) {
+		/* Stop sensor readout */
+		ret = mt9p031_set_output_control(mt9p031,
+						 MT9P031_OUTPUT_CONTROL_CEN, 0);
+		if (ret < 0)
+			return ret;
+
+		return mt9p031_pll_disable(mt9p031);
+	}
+
+	ret = mt9p031_set_params(mt9p031);
+	if (ret < 0)
+		return ret;
+
+	/* Switch to master "normal" mode */
+	ret = mt9p031_set_output_control(mt9p031, 0,
+					 MT9P031_OUTPUT_CONTROL_CEN);
+	if (ret < 0)
+		return ret;
+
+	return mt9p031_pll_enable(mt9p031);
+}
+
+static int mt9p031_enum_mbus_code(struct v4l2_subdev *subdev,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+
+	if (code->pad || code->index)
+		return -EINVAL;
+
+	code->code = mt9p031->format.code;
+	return 0;
+}
+
+static int mt9p031_enum_frame_size(struct v4l2_subdev *subdev,
+				   struct v4l2_subdev_fh *fh,
+				   struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+
+	if (fse->index >= 8 || fse->code != mt9p031->format.code)
+		return -EINVAL;
+
+	fse->min_width = MT9P031_WINDOW_WIDTH_DEF
+		       / min_t(unsigned int, 7, fse->index + 1);
+	fse->max_width = fse->min_width;
+	fse->min_height = MT9P031_WINDOW_HEIGHT_DEF / (fse->index + 1);
+	fse->max_height = fse->min_height;
+
+	return 0;
+}
+
+static struct v4l2_mbus_framefmt *
+__mt9p031_get_pad_format(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh,
+			 unsigned int pad, u32 which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_format(fh, pad);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &mt9p031->format;
+	default:
+		return NULL;
+	}
+}
+
+static struct v4l2_rect *
+__mt9p031_get_pad_crop(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh,
+		     unsigned int pad, u32 which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_crop(fh, pad);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &mt9p031->crop;
+	default:
+		return NULL;
+	}
+}
+
+static int mt9p031_get_format(struct v4l2_subdev *subdev,
+			      struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_format *fmt)
+{
+	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+
+	fmt->format = *__mt9p031_get_pad_format(mt9p031, fh, fmt->pad,
+						fmt->which);
+	return 0;
+}
+
+static int mt9p031_set_format(struct v4l2_subdev *subdev,
+			      struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_format *format)
+{
+	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+	struct v4l2_mbus_framefmt *__format;
+	struct v4l2_rect *__crop;
+	unsigned int width;
+	unsigned int height;
+	unsigned int hratio;
+	unsigned int vratio;
+
+	__crop = __mt9p031_get_pad_crop(mt9p031, fh, format->pad,
+					format->which);
+
+	/* Clamp the width and height to avoid dividing by zero. */
+	width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
+			max(__crop->width / 7, MT9P031_WINDOW_WIDTH_MIN),
+			__crop->width);
+	height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
+			max(__crop->height / 8, MT9P031_WINDOW_HEIGHT_MIN),
+			__crop->height);
+
+	hratio = DIV_ROUND_CLOSEST(__crop->width, width);
+	vratio = DIV_ROUND_CLOSEST(__crop->height, height);
+
+	__format = __mt9p031_get_pad_format(mt9p031, fh, format->pad,
+					    format->which);
+	__format->width = __crop->width / hratio;
+	__format->height = __crop->height / vratio;
+
+	format->format = *__format;
+
+	return 0;
+}
+
+static int mt9p031_get_crop(struct v4l2_subdev *subdev,
+			    struct v4l2_subdev_fh *fh,
+			    struct v4l2_subdev_crop *crop)
+{
+	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+
+	crop->rect = *__mt9p031_get_pad_crop(mt9p031, fh, crop->pad,
+					     crop->which);
+	return 0;
+}
+
+static int mt9p031_set_crop(struct v4l2_subdev *subdev,
+			    struct v4l2_subdev_fh *fh,
+			    struct v4l2_subdev_crop *crop)
+{
+	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+	struct v4l2_mbus_framefmt *__format;
+	struct v4l2_rect *__crop;
+	struct v4l2_rect rect;
+
+	/* Clamp the crop rectangle boundaries and align them to a multiple of 2
+	 * pixels to ensure a GRBG Bayer pattern.
+	 */
+	rect.left = clamp(ALIGN(crop->rect.left, 2), MT9P031_COLUMN_START_MIN,
+			  MT9P031_COLUMN_START_MAX);
+	rect.top = clamp(ALIGN(crop->rect.top, 2), MT9P031_ROW_START_MIN,
+			 MT9P031_ROW_START_MAX);
+	rect.width = clamp(ALIGN(crop->rect.width, 2),
+			   MT9P031_WINDOW_WIDTH_MIN,
+			   MT9P031_WINDOW_WIDTH_MAX);
+	rect.height = clamp(ALIGN(crop->rect.height, 2),
+			    MT9P031_WINDOW_HEIGHT_MIN,
+			    MT9P031_WINDOW_HEIGHT_MAX);
+
+	rect.width = min(rect.width, MT9P031_PIXEL_ARRAY_WIDTH - rect.left);
+	rect.height = min(rect.height, MT9P031_PIXEL_ARRAY_HEIGHT - rect.top);
+
+	__crop = __mt9p031_get_pad_crop(mt9p031, fh, crop->pad, crop->which);
+
+	if (rect.width != __crop->width || rect.height != __crop->height) {
+		/* Reset the output image size if the crop rectangle size has
+		 * been modified.
+		 */
+		__format = __mt9p031_get_pad_format(mt9p031, fh, crop->pad,
+						    crop->which);
+		__format->width = rect.width;
+		__format->height = rect.height;
+	}
+
+	*__crop = rect;
+	crop->rect = rect;
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev control operations
+ */
+
+#define V4L2_CID_TEST_PATTERN		(V4L2_CID_USER_BASE | 0x1001)
+#define V4L2_CID_BLC_AUTO		(V4L2_CID_USER_BASE | 0x1002)
+#define V4L2_CID_BLC_TARGET_LEVEL	(V4L2_CID_USER_BASE | 0x1003)
+#define V4L2_CID_BLC_ANALOG_OFFSET	(V4L2_CID_USER_BASE | 0x1004)
+#define V4L2_CID_BLC_DIGITAL_OFFSET	(V4L2_CID_USER_BASE | 0x1005)
+
+static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mt9p031 *mt9p031 =
+			container_of(ctrl->handler, struct mt9p031, ctrls);
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+	u16 data;
+	int ret;
+
+	switch (ctrl->id) {
+	case V4L2_CID_EXPOSURE:
+		ret = mt9p031_write(client, MT9P031_SHUTTER_WIDTH_UPPER,
+				    (ctrl->val >> 16) & 0xffff);
+		if (ret < 0)
+			return ret;
+
+		return mt9p031_write(client, MT9P031_SHUTTER_WIDTH_LOWER,
+				     ctrl->val & 0xffff);
+
+	case V4L2_CID_GAIN:
+		/* Gain is controlled by 2 analog stages and a digital stage.
+		 * Valid values for the 3 stages are
+		 *
+		 * Stage                Min     Max     Step
+		 * ------------------------------------------
+		 * First analog stage   x1      x2      1
+		 * Second analog stage  x1      x4      0.125
+		 * Digital stage        x1      x16     0.125
+		 *
+		 * To minimize noise, the gain stages should be used in the
+		 * second analog stage, first analog stage, digital stage order.
+		 * Gain from a previous stage should be pushed to its maximum
+		 * value before the next stage is used.
+		 */
+		if (ctrl->val <= 32) {
+			data = ctrl->val;
+		} else if (ctrl->val <= 64) {
+			ctrl->val &= ~1;
+			data = (1 << 6) | (ctrl->val >> 1);
+		} else {
+			ctrl->val &= ~7;
+			data = ((ctrl->val - 64) << 5) | (1 << 6) | 32;
+		}
+
+		return mt9p031_write(client, MT9P031_GLOBAL_GAIN, data);
+
+	case V4L2_CID_HFLIP:
+		if (ctrl->val)
+			return mt9p031_set_mode2(mt9p031,
+					0, MT9P031_READ_MODE_2_COL_MIR);
+		else
+			return mt9p031_set_mode2(mt9p031,
+					MT9P031_READ_MODE_2_COL_MIR, 0);
+
+	case V4L2_CID_VFLIP:
+		if (ctrl->val)
+			return mt9p031_set_mode2(mt9p031,
+					0, MT9P031_READ_MODE_2_ROW_MIR);
+		else
+			return mt9p031_set_mode2(mt9p031,
+					MT9P031_READ_MODE_2_ROW_MIR, 0);
+
+	case V4L2_CID_TEST_PATTERN:
+		if (!ctrl->val) {
+			/* Restore the black level compensation settings. */
+			if (mt9p031->blc_auto->cur.val != 0) {
+				ret = mt9p031_s_ctrl(mt9p031->blc_auto);
+				if (ret < 0)
+					return ret;
+			}
+			if (mt9p031->blc_offset->cur.val != 0) {
+				ret = mt9p031_s_ctrl(mt9p031->blc_offset);
+				if (ret < 0)
+					return ret;
+			}
+			return mt9p031_write(client, MT9P031_TEST_PATTERN,
+					     MT9P031_TEST_PATTERN_DISABLE);
+		}
+
+		ret = mt9p031_write(client, MT9P031_TEST_PATTERN_GREEN, 0x05a0);
+		if (ret < 0)
+			return ret;
+		ret = mt9p031_write(client, MT9P031_TEST_PATTERN_RED, 0x0a50);
+		if (ret < 0)
+			return ret;
+		ret = mt9p031_write(client, MT9P031_TEST_PATTERN_BLUE, 0x0aa0);
+		if (ret < 0)
+			return ret;
+
+		/* Disable digital black level compensation when using a test
+		 * pattern.
+		 */
+		ret = mt9p031_set_mode2(mt9p031, MT9P031_READ_MODE_2_ROW_BLC,
+					0);
+		if (ret < 0)
+			return ret;
+
+		ret = mt9p031_write(client, MT9P031_ROW_BLACK_DEF_OFFSET, 0);
+		if (ret < 0)
+			return ret;
+
+		return mt9p031_write(client, MT9P031_TEST_PATTERN,
+				((ctrl->val - 1) << MT9P031_TEST_PATTERN_SHIFT)
+				| MT9P031_TEST_PATTERN_ENABLE);
+
+	case V4L2_CID_BLC_AUTO:
+		ret = mt9p031_set_mode2(mt9p031,
+				ctrl->val ? 0 : MT9P031_READ_MODE_2_ROW_BLC,
+				ctrl->val ? MT9P031_READ_MODE_2_ROW_BLC : 0);
+		if (ret < 0)
+			return ret;
+
+		return mt9p031_write(client, MT9P031_BLACK_LEVEL_CALIBRATION,
+				     ctrl->val ? 0 : MT9P031_BLC_MANUAL_BLC);
+
+	case V4L2_CID_BLC_TARGET_LEVEL:
+		return mt9p031_write(client, MT9P031_ROW_BLACK_TARGET,
+				     ctrl->val);
+
+	case V4L2_CID_BLC_ANALOG_OFFSET:
+		data = ctrl->val & ((1 << 9) - 1);
+
+		ret = mt9p031_write(client, MT9P031_GREEN1_OFFSET, data);
+		if (ret < 0)
+			return ret;
+		ret = mt9p031_write(client, MT9P031_GREEN2_OFFSET, data);
+		if (ret < 0)
+			return ret;
+		ret = mt9p031_write(client, MT9P031_RED_OFFSET, data);
+		if (ret < 0)
+			return ret;
+		return mt9p031_write(client, MT9P031_BLUE_OFFSET, data);
+
+	case V4L2_CID_BLC_DIGITAL_OFFSET:
+		return mt9p031_write(client, MT9P031_ROW_BLACK_DEF_OFFSET,
+				     ctrl->val & ((1 << 12) - 1));
+	}
+
+	return 0;
+}
+
+static struct v4l2_ctrl_ops mt9p031_ctrl_ops = {
+	.s_ctrl = mt9p031_s_ctrl,
+};
+
+static const char * const mt9p031_test_pattern_menu[] = {
+	"Disabled",
+	"Color Field",
+	"Horizontal Gradient",
+	"Vertical Gradient",
+	"Diagonal Gradient",
+	"Classic Test Pattern",
+	"Walking 1s",
+	"Monochrome Horizontal Bars",
+	"Monochrome Vertical Bars",
+	"Vertical Color Bars",
+};
+
+static const struct v4l2_ctrl_config mt9p031_ctrls[] = {
+	{
+		.ops		= &mt9p031_ctrl_ops,
+		.id		= V4L2_CID_TEST_PATTERN,
+		.type		= V4L2_CTRL_TYPE_MENU,
+		.name		= "Test Pattern",
+		.min		= 0,
+		.max		= ARRAY_SIZE(mt9p031_test_pattern_menu) - 1,
+		.step		= 0,
+		.def		= 0,
+		.flags		= 0,
+		.menu_skip_mask	= 0,
+		.qmenu		= mt9p031_test_pattern_menu,
+	}, {
+		.ops		= &mt9p031_ctrl_ops,
+		.id		= V4L2_CID_BLC_AUTO,
+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
+		.name		= "BLC, Auto",
+		.min		= 0,
+		.max		= 1,
+		.step		= 1,
+		.def		= 1,
+		.flags		= 0,
+	}, {
+		.ops		= &mt9p031_ctrl_ops,
+		.id		= V4L2_CID_BLC_TARGET_LEVEL,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "BLC Target Level",
+		.min		= 0,
+		.max		= 4095,
+		.step		= 1,
+		.def		= 168,
+		.flags		= 0,
+	}, {
+		.ops		= &mt9p031_ctrl_ops,
+		.id		= V4L2_CID_BLC_ANALOG_OFFSET,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "BLC Analog Offset",
+		.min		= -255,
+		.max		= 255,
+		.step		= 1,
+		.def		= 32,
+		.flags		= 0,
+	}, {
+		.ops		= &mt9p031_ctrl_ops,
+		.id		= V4L2_CID_BLC_DIGITAL_OFFSET,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "BLC Digital Offset",
+		.min		= -2048,
+		.max		= 2047,
+		.step		= 1,
+		.def		= 40,
+		.flags		= 0,
+	}
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+static int mt9p031_set_power(struct v4l2_subdev *subdev, int on)
+{
+	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+	int ret = 0;
+
+	mutex_lock(&mt9p031->power_lock);
+
+	/* If the power count is modified from 0 to != 0 or from != 0 to 0,
+	 * update the power state.
+	 */
+	if (mt9p031->power_count == !on) {
+		ret = __mt9p031_set_power(mt9p031, !!on);
+		if (ret < 0)
+			goto out;
+	}
+
+	/* Update the power count. */
+	mt9p031->power_count += on ? 1 : -1;
+	WARN_ON(mt9p031->power_count < 0);
+
+out:
+	mutex_unlock(&mt9p031->power_lock);
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev internal operations
+ */
+
+static int mt9p031_registered(struct v4l2_subdev *subdev)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+	s32 data;
+	int ret;
+
+	ret = mt9p031_power_on(mt9p031);
+	if (ret < 0) {
+		dev_err(&client->dev, "MT9P031 power up failed\n");
+		return ret;
+	}
+
+	/* Read out the chip version register */
+	data = mt9p031_read(client, MT9P031_CHIP_VERSION);
+	if (data != MT9P031_CHIP_VERSION_VALUE) {
+		dev_err(&client->dev, "MT9P031 not detected, wrong version "
+			"0x%04x\n", data);
+		return -ENODEV;
+	}
+
+	mt9p031_power_off(mt9p031);
+
+	dev_info(&client->dev, "MT9P031 detected at address 0x%02x\n",
+		 client->addr);
+
+	return ret;
+}
+
+static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+	struct v4l2_mbus_framefmt *format;
+	struct v4l2_rect *crop;
+
+	crop = v4l2_subdev_get_try_crop(fh, 0);
+	crop->left = MT9P031_COLUMN_START_DEF;
+	crop->top = MT9P031_ROW_START_DEF;
+	crop->width = MT9P031_WINDOW_WIDTH_DEF;
+	crop->height = MT9P031_WINDOW_HEIGHT_DEF;
+
+	format = v4l2_subdev_get_try_format(fh, 0);
+
+	if (mt9p031->model == MT9P031_MODEL_MONOCHROME)
+		format->code = V4L2_MBUS_FMT_Y12_1X12;
+	else
+		format->code = V4L2_MBUS_FMT_SGRBG12_1X12;
+
+	format->width = MT9P031_WINDOW_WIDTH_DEF;
+	format->height = MT9P031_WINDOW_HEIGHT_DEF;
+	format->field = V4L2_FIELD_NONE;
+	format->colorspace = V4L2_COLORSPACE_SRGB;
+
+	return mt9p031_set_power(subdev, 1);
+}
+
+static int mt9p031_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+	return mt9p031_set_power(subdev, 0);
+}
+
+static struct v4l2_subdev_core_ops mt9p031_subdev_core_ops = {
+	.s_power        = mt9p031_set_power,
+};
+
+static struct v4l2_subdev_video_ops mt9p031_subdev_video_ops = {
+	.s_stream       = mt9p031_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = {
+	.enum_mbus_code = mt9p031_enum_mbus_code,
+	.enum_frame_size = mt9p031_enum_frame_size,
+	.get_fmt = mt9p031_get_format,
+	.set_fmt = mt9p031_set_format,
+	.get_crop = mt9p031_get_crop,
+	.set_crop = mt9p031_set_crop,
+};
+
+static struct v4l2_subdev_ops mt9p031_subdev_ops = {
+	.core   = &mt9p031_subdev_core_ops,
+	.video  = &mt9p031_subdev_video_ops,
+	.pad    = &mt9p031_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops mt9p031_subdev_internal_ops = {
+	.registered = mt9p031_registered,
+	.open = mt9p031_open,
+	.close = mt9p031_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * Driver initialization and probing
+ */
+
+static int mt9p031_probe(struct i2c_client *client,
+			 const struct i2c_device_id *did)
+{
+	struct mt9p031_platform_data *pdata = client->dev.platform_data;
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct mt9p031 *mt9p031;
+	unsigned int i;
+	int ret;
+
+	if (pdata == NULL) {
+		dev_err(&client->dev, "No platform data\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_warn(&client->dev,
+			"I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+		return -EIO;
+	}
+
+	mt9p031 = kzalloc(sizeof(*mt9p031), GFP_KERNEL);
+	if (mt9p031 == NULL)
+		return -ENOMEM;
+
+	mt9p031->pdata = pdata;
+	mt9p031->output_control	= MT9P031_OUTPUT_CONTROL_DEF;
+	mt9p031->mode2 = MT9P031_READ_MODE_2_ROW_BLC;
+	mt9p031->model = did->driver_data;
+	mt9p031->reset = -1;
+
+	v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 5);
+
+	v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
+			  V4L2_CID_EXPOSURE, MT9P031_SHUTTER_WIDTH_MIN,
+			  MT9P031_SHUTTER_WIDTH_MAX, 1,
+			  MT9P031_SHUTTER_WIDTH_DEF);
+	v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
+			  V4L2_CID_GAIN, MT9P031_GLOBAL_GAIN_MIN,
+			  MT9P031_GLOBAL_GAIN_MAX, 1, MT9P031_GLOBAL_GAIN_DEF);
+	v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
+			  V4L2_CID_HFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
+			  V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
+			  V4L2_CID_PIXEL_RATE, pdata->target_freq,
+			  pdata->target_freq, 1, pdata->target_freq);
+
+	for (i = 0; i < ARRAY_SIZE(mt9p031_ctrls); ++i)
+		v4l2_ctrl_new_custom(&mt9p031->ctrls, &mt9p031_ctrls[i], NULL);
+
+	mt9p031->subdev.ctrl_handler = &mt9p031->ctrls;
+
+	if (mt9p031->ctrls.error) {
+		printk(KERN_INFO "%s: control initialization error %d\n",
+		       __func__, mt9p031->ctrls.error);
+		ret = mt9p031->ctrls.error;
+		goto done;
+	}
+
+	mt9p031->blc_auto = v4l2_ctrl_find(&mt9p031->ctrls, V4L2_CID_BLC_AUTO);
+	mt9p031->blc_offset = v4l2_ctrl_find(&mt9p031->ctrls,
+					     V4L2_CID_BLC_DIGITAL_OFFSET);
+
+	mutex_init(&mt9p031->power_lock);
+	v4l2_i2c_subdev_init(&mt9p031->subdev, client, &mt9p031_subdev_ops);
+	mt9p031->subdev.internal_ops = &mt9p031_subdev_internal_ops;
+
+	mt9p031->pad.flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_init(&mt9p031->subdev.entity, 1, &mt9p031->pad, 0);
+	if (ret < 0)
+		goto done;
+
+	mt9p031->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	mt9p031->crop.width = MT9P031_WINDOW_WIDTH_DEF;
+	mt9p031->crop.height = MT9P031_WINDOW_HEIGHT_DEF;
+	mt9p031->crop.left = MT9P031_COLUMN_START_DEF;
+	mt9p031->crop.top = MT9P031_ROW_START_DEF;
+
+	if (mt9p031->model == MT9P031_MODEL_MONOCHROME)
+		mt9p031->format.code = V4L2_MBUS_FMT_Y12_1X12;
+	else
+		mt9p031->format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
+
+	mt9p031->format.width = MT9P031_WINDOW_WIDTH_DEF;
+	mt9p031->format.height = MT9P031_WINDOW_HEIGHT_DEF;
+	mt9p031->format.field = V4L2_FIELD_NONE;
+	mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB;
+
+	if (pdata->reset != -1) {
+		ret = gpio_request_one(pdata->reset, GPIOF_OUT_INIT_LOW,
+				       "mt9p031_rst");
+		if (ret < 0)
+			goto done;
+
+		mt9p031->reset = pdata->reset;
+	}
+
+	ret = mt9p031_pll_setup(mt9p031);
+
+done:
+	if (ret < 0) {
+		if (mt9p031->reset != -1)
+			gpio_free(mt9p031->reset);
+
+		v4l2_ctrl_handler_free(&mt9p031->ctrls);
+		media_entity_cleanup(&mt9p031->subdev.entity);
+		kfree(mt9p031);
+	}
+
+	return ret;
+}
+
+static int mt9p031_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+
+	v4l2_ctrl_handler_free(&mt9p031->ctrls);
+	v4l2_device_unregister_subdev(subdev);
+	media_entity_cleanup(&subdev->entity);
+	if (mt9p031->reset != -1)
+		gpio_free(mt9p031->reset);
+	kfree(mt9p031);
+
+	return 0;
+}
+
+static const struct i2c_device_id mt9p031_id[] = {
+	{ "mt9p031", MT9P031_MODEL_COLOR },
+	{ "mt9p031m", MT9P031_MODEL_MONOCHROME },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mt9p031_id);
+
+static struct i2c_driver mt9p031_i2c_driver = {
+	.driver = {
+		.name = "mt9p031",
+	},
+	.probe          = mt9p031_probe,
+	.remove         = mt9p031_remove,
+	.id_table       = mt9p031_id,
+};
+
+module_i2c_driver(mt9p031_i2c_driver);
+
+MODULE_DESCRIPTION("Aptina MT9P031 Camera driver");
+MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c
new file mode 100644
index 0000000..6d343ad
--- /dev/null
+++ b/drivers/media/i2c/mt9t001.c
@@ -0,0 +1,833 @@
+/*
+ * Driver for MT9T001 CMOS Image Sensor from Aptina (Micron)
+ *
+ * Copyright (C) 2010-2011, Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * Based on the MT9M001 driver,
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/log2.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/mt9t001.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#define MT9T001_PIXEL_ARRAY_HEIGHT			1568
+#define MT9T001_PIXEL_ARRAY_WIDTH			2112
+
+#define MT9T001_CHIP_VERSION				0x00
+#define		MT9T001_CHIP_ID				0x1621
+#define MT9T001_ROW_START				0x01
+#define		MT9T001_ROW_START_MIN			0
+#define		MT9T001_ROW_START_DEF			20
+#define		MT9T001_ROW_START_MAX			1534
+#define MT9T001_COLUMN_START				0x02
+#define		MT9T001_COLUMN_START_MIN		0
+#define		MT9T001_COLUMN_START_DEF		32
+#define		MT9T001_COLUMN_START_MAX		2046
+#define MT9T001_WINDOW_HEIGHT				0x03
+#define		MT9T001_WINDOW_HEIGHT_MIN		1
+#define		MT9T001_WINDOW_HEIGHT_DEF		1535
+#define		MT9T001_WINDOW_HEIGHT_MAX		1567
+#define MT9T001_WINDOW_WIDTH				0x04
+#define		MT9T001_WINDOW_WIDTH_MIN		1
+#define		MT9T001_WINDOW_WIDTH_DEF		2047
+#define		MT9T001_WINDOW_WIDTH_MAX		2111
+#define MT9T001_HORIZONTAL_BLANKING			0x05
+#define		MT9T001_HORIZONTAL_BLANKING_MIN		21
+#define		MT9T001_HORIZONTAL_BLANKING_MAX		1023
+#define MT9T001_VERTICAL_BLANKING			0x06
+#define		MT9T001_VERTICAL_BLANKING_MIN		3
+#define		MT9T001_VERTICAL_BLANKING_MAX		1023
+#define MT9T001_OUTPUT_CONTROL				0x07
+#define		MT9T001_OUTPUT_CONTROL_SYNC		(1 << 0)
+#define		MT9T001_OUTPUT_CONTROL_CHIP_ENABLE	(1 << 1)
+#define		MT9T001_OUTPUT_CONTROL_TEST_DATA	(1 << 6)
+#define MT9T001_SHUTTER_WIDTH_HIGH			0x08
+#define MT9T001_SHUTTER_WIDTH_LOW			0x09
+#define		MT9T001_SHUTTER_WIDTH_MIN		1
+#define		MT9T001_SHUTTER_WIDTH_DEF		1561
+#define		MT9T001_SHUTTER_WIDTH_MAX		(1024 * 1024)
+#define MT9T001_PIXEL_CLOCK				0x0a
+#define		MT9T001_PIXEL_CLOCK_INVERT		(1 << 15)
+#define		MT9T001_PIXEL_CLOCK_SHIFT_MASK		(7 << 8)
+#define		MT9T001_PIXEL_CLOCK_SHIFT_SHIFT		8
+#define		MT9T001_PIXEL_CLOCK_DIVIDE_MASK		(0x7f << 0)
+#define MT9T001_FRAME_RESTART				0x0b
+#define MT9T001_SHUTTER_DELAY				0x0c
+#define		MT9T001_SHUTTER_DELAY_MAX		2047
+#define MT9T001_RESET					0x0d
+#define MT9T001_READ_MODE1				0x1e
+#define		MT9T001_READ_MODE_SNAPSHOT		(1 << 8)
+#define		MT9T001_READ_MODE_STROBE_ENABLE		(1 << 9)
+#define		MT9T001_READ_MODE_STROBE_WIDTH		(1 << 10)
+#define		MT9T001_READ_MODE_STROBE_OVERRIDE	(1 << 11)
+#define MT9T001_READ_MODE2				0x20
+#define		MT9T001_READ_MODE_BAD_FRAMES		(1 << 0)
+#define		MT9T001_READ_MODE_LINE_VALID_CONTINUOUS	(1 << 9)
+#define		MT9T001_READ_MODE_LINE_VALID_FRAME	(1 << 10)
+#define MT9T001_READ_MODE3				0x21
+#define		MT9T001_READ_MODE_GLOBAL_RESET		(1 << 0)
+#define		MT9T001_READ_MODE_GHST_CTL		(1 << 1)
+#define MT9T001_ROW_ADDRESS_MODE			0x22
+#define		MT9T001_ROW_SKIP_MASK			(7 << 0)
+#define		MT9T001_ROW_BIN_MASK			(3 << 3)
+#define		MT9T001_ROW_BIN_SHIFT			3
+#define MT9T001_COLUMN_ADDRESS_MODE			0x23
+#define		MT9T001_COLUMN_SKIP_MASK		(7 << 0)
+#define		MT9T001_COLUMN_BIN_MASK			(3 << 3)
+#define		MT9T001_COLUMN_BIN_SHIFT		3
+#define MT9T001_GREEN1_GAIN				0x2b
+#define MT9T001_BLUE_GAIN				0x2c
+#define MT9T001_RED_GAIN				0x2d
+#define MT9T001_GREEN2_GAIN				0x2e
+#define MT9T001_TEST_DATA				0x32
+#define MT9T001_GLOBAL_GAIN				0x35
+#define		MT9T001_GLOBAL_GAIN_MIN			8
+#define		MT9T001_GLOBAL_GAIN_MAX			1024
+#define MT9T001_BLACK_LEVEL				0x49
+#define MT9T001_ROW_BLACK_DEFAULT_OFFSET		0x4b
+#define MT9T001_BLC_DELTA_THRESHOLDS			0x5d
+#define MT9T001_CAL_THRESHOLDS				0x5f
+#define MT9T001_GREEN1_OFFSET				0x60
+#define MT9T001_GREEN2_OFFSET				0x61
+#define MT9T001_BLACK_LEVEL_CALIBRATION			0x62
+#define		MT9T001_BLACK_LEVEL_OVERRIDE		(1 << 0)
+#define		MT9T001_BLACK_LEVEL_DISABLE_OFFSET	(1 << 1)
+#define		MT9T001_BLACK_LEVEL_RECALCULATE		(1 << 12)
+#define		MT9T001_BLACK_LEVEL_LOCK_RED_BLUE	(1 << 13)
+#define		MT9T001_BLACK_LEVEL_LOCK_GREEN		(1 << 14)
+#define MT9T001_RED_OFFSET				0x63
+#define MT9T001_BLUE_OFFSET				0x64
+
+struct mt9t001 {
+	struct v4l2_subdev subdev;
+	struct media_pad pad;
+
+	struct v4l2_mbus_framefmt format;
+	struct v4l2_rect crop;
+
+	struct v4l2_ctrl_handler ctrls;
+	struct v4l2_ctrl *gains[4];
+
+	u16 output_control;
+	u16 black_level;
+};
+
+static inline struct mt9t001 *to_mt9t001(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct mt9t001, subdev);
+}
+
+static int mt9t001_read(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_word_swapped(client, reg);
+}
+
+static int mt9t001_write(struct i2c_client *client, u8 reg, u16 data)
+{
+	return i2c_smbus_write_word_swapped(client, reg, data);
+}
+
+static int mt9t001_set_output_control(struct mt9t001 *mt9t001, u16 clear,
+				      u16 set)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev);
+	u16 value = (mt9t001->output_control & ~clear) | set;
+	int ret;
+
+	if (value == mt9t001->output_control)
+		return 0;
+
+	ret = mt9t001_write(client, MT9T001_OUTPUT_CONTROL, value);
+	if (ret < 0)
+		return ret;
+
+	mt9t001->output_control = value;
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev video operations
+ */
+
+static struct v4l2_mbus_framefmt *
+__mt9t001_get_pad_format(struct mt9t001 *mt9t001, struct v4l2_subdev_fh *fh,
+			 unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_format(fh, pad);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &mt9t001->format;
+	default:
+		return NULL;
+	}
+}
+
+static struct v4l2_rect *
+__mt9t001_get_pad_crop(struct mt9t001 *mt9t001, struct v4l2_subdev_fh *fh,
+		       unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_crop(fh, pad);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &mt9t001->crop;
+	default:
+		return NULL;
+	}
+}
+
+static int mt9t001_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+	const u16 mode = MT9T001_OUTPUT_CONTROL_CHIP_ENABLE;
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct mt9t001 *mt9t001 = to_mt9t001(subdev);
+	struct v4l2_mbus_framefmt *format = &mt9t001->format;
+	struct v4l2_rect *crop = &mt9t001->crop;
+	unsigned int hratio;
+	unsigned int vratio;
+	int ret;
+
+	if (!enable)
+		return mt9t001_set_output_control(mt9t001, mode, 0);
+
+	/* Configure the window size and row/column bin */
+	hratio = DIV_ROUND_CLOSEST(crop->width, format->width);
+	vratio = DIV_ROUND_CLOSEST(crop->height, format->height);
+
+	ret = mt9t001_write(client, MT9T001_ROW_ADDRESS_MODE, hratio - 1);
+	if (ret < 0)
+		return ret;
+
+	ret = mt9t001_write(client, MT9T001_COLUMN_ADDRESS_MODE, vratio - 1);
+	if (ret < 0)
+		return ret;
+
+	ret = mt9t001_write(client, MT9T001_COLUMN_START, crop->left);
+	if (ret < 0)
+		return ret;
+
+	ret = mt9t001_write(client, MT9T001_ROW_START, crop->top);
+	if (ret < 0)
+		return ret;
+
+	ret = mt9t001_write(client, MT9T001_WINDOW_WIDTH, crop->width - 1);
+	if (ret < 0)
+		return ret;
+
+	ret = mt9t001_write(client, MT9T001_WINDOW_HEIGHT, crop->height - 1);
+	if (ret < 0)
+		return ret;
+
+	/* Switch to master "normal" mode */
+	return mt9t001_set_output_control(mt9t001, 0, mode);
+}
+
+static int mt9t001_enum_mbus_code(struct v4l2_subdev *subdev,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->index > 0)
+		return -EINVAL;
+
+	code->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+	return 0;
+}
+
+static int mt9t001_enum_frame_size(struct v4l2_subdev *subdev,
+				   struct v4l2_subdev_fh *fh,
+				   struct v4l2_subdev_frame_size_enum *fse)
+{
+	if (fse->index >= 8 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10)
+		return -EINVAL;
+
+	fse->min_width = (MT9T001_WINDOW_WIDTH_DEF + 1) / fse->index;
+	fse->max_width = fse->min_width;
+	fse->min_height = (MT9T001_WINDOW_HEIGHT_DEF + 1) / fse->index;
+	fse->max_height = fse->min_height;
+
+	return 0;
+}
+
+static int mt9t001_get_format(struct v4l2_subdev *subdev,
+			      struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_format *format)
+{
+	struct mt9t001 *mt9t001 = to_mt9t001(subdev);
+
+	format->format = *__mt9t001_get_pad_format(mt9t001, fh, format->pad,
+						   format->which);
+	return 0;
+}
+
+static int mt9t001_set_format(struct v4l2_subdev *subdev,
+			      struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_format *format)
+{
+	struct mt9t001 *mt9t001 = to_mt9t001(subdev);
+	struct v4l2_mbus_framefmt *__format;
+	struct v4l2_rect *__crop;
+	unsigned int width;
+	unsigned int height;
+	unsigned int hratio;
+	unsigned int vratio;
+
+	__crop = __mt9t001_get_pad_crop(mt9t001, fh, format->pad,
+					format->which);
+
+	/* Clamp the width and height to avoid dividing by zero. */
+	width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
+			max(__crop->width / 8, MT9T001_WINDOW_HEIGHT_MIN + 1),
+			__crop->width);
+	height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
+			 max(__crop->height / 8, MT9T001_WINDOW_HEIGHT_MIN + 1),
+			 __crop->height);
+
+	hratio = DIV_ROUND_CLOSEST(__crop->width, width);
+	vratio = DIV_ROUND_CLOSEST(__crop->height, height);
+
+	__format = __mt9t001_get_pad_format(mt9t001, fh, format->pad,
+					    format->which);
+	__format->width = __crop->width / hratio;
+	__format->height = __crop->height / vratio;
+
+	format->format = *__format;
+
+	return 0;
+}
+
+static int mt9t001_get_crop(struct v4l2_subdev *subdev,
+			    struct v4l2_subdev_fh *fh,
+			    struct v4l2_subdev_crop *crop)
+{
+	struct mt9t001 *mt9t001 = to_mt9t001(subdev);
+
+	crop->rect = *__mt9t001_get_pad_crop(mt9t001, fh, crop->pad,
+					     crop->which);
+	return 0;
+}
+
+static int mt9t001_set_crop(struct v4l2_subdev *subdev,
+			    struct v4l2_subdev_fh *fh,
+			    struct v4l2_subdev_crop *crop)
+{
+	struct mt9t001 *mt9t001 = to_mt9t001(subdev);
+	struct v4l2_mbus_framefmt *__format;
+	struct v4l2_rect *__crop;
+	struct v4l2_rect rect;
+
+	/* Clamp the crop rectangle boundaries and align them to a multiple of 2
+	 * pixels.
+	 */
+	rect.left = clamp(ALIGN(crop->rect.left, 2),
+			  MT9T001_COLUMN_START_MIN,
+			  MT9T001_COLUMN_START_MAX);
+	rect.top = clamp(ALIGN(crop->rect.top, 2),
+			 MT9T001_ROW_START_MIN,
+			 MT9T001_ROW_START_MAX);
+	rect.width = clamp(ALIGN(crop->rect.width, 2),
+			   MT9T001_WINDOW_WIDTH_MIN + 1,
+			   MT9T001_WINDOW_WIDTH_MAX + 1);
+	rect.height = clamp(ALIGN(crop->rect.height, 2),
+			    MT9T001_WINDOW_HEIGHT_MIN + 1,
+			    MT9T001_WINDOW_HEIGHT_MAX + 1);
+
+	rect.width = min(rect.width, MT9T001_PIXEL_ARRAY_WIDTH - rect.left);
+	rect.height = min(rect.height, MT9T001_PIXEL_ARRAY_HEIGHT - rect.top);
+
+	__crop = __mt9t001_get_pad_crop(mt9t001, fh, crop->pad, crop->which);
+
+	if (rect.width != __crop->width || rect.height != __crop->height) {
+		/* Reset the output image size if the crop rectangle size has
+		 * been modified.
+		 */
+		__format = __mt9t001_get_pad_format(mt9t001, fh, crop->pad,
+						    crop->which);
+		__format->width = rect.width;
+		__format->height = rect.height;
+	}
+
+	*__crop = rect;
+	crop->rect = rect;
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev control operations
+ */
+
+#define V4L2_CID_TEST_PATTERN		(V4L2_CID_USER_BASE | 0x1001)
+#define V4L2_CID_BLACK_LEVEL_AUTO	(V4L2_CID_USER_BASE | 0x1002)
+#define V4L2_CID_BLACK_LEVEL_OFFSET	(V4L2_CID_USER_BASE | 0x1003)
+#define V4L2_CID_BLACK_LEVEL_CALIBRATE	(V4L2_CID_USER_BASE | 0x1004)
+
+#define V4L2_CID_GAIN_RED		(V4L2_CTRL_CLASS_CAMERA | 0x1001)
+#define V4L2_CID_GAIN_GREEN_RED		(V4L2_CTRL_CLASS_CAMERA | 0x1002)
+#define V4L2_CID_GAIN_GREEN_BLUE	(V4L2_CTRL_CLASS_CAMERA | 0x1003)
+#define V4L2_CID_GAIN_BLUE		(V4L2_CTRL_CLASS_CAMERA | 0x1004)
+
+static u16 mt9t001_gain_value(s32 *gain)
+{
+	/* Gain is controlled by 2 analog stages and a digital stage. Valid
+	 * values for the 3 stages are
+	 *
+	 * Stage		Min	Max	Step
+	 * ------------------------------------------
+	 * First analog stage	x1	x2	1
+	 * Second analog stage	x1	x4	0.125
+	 * Digital stage	x1	x16	0.125
+	 *
+	 * To minimize noise, the gain stages should be used in the second
+	 * analog stage, first analog stage, digital stage order. Gain from a
+	 * previous stage should be pushed to its maximum value before the next
+	 * stage is used.
+	 */
+	if (*gain <= 32)
+		return *gain;
+
+	if (*gain <= 64) {
+		*gain &= ~1;
+		return (1 << 6) | (*gain >> 1);
+	}
+
+	*gain &= ~7;
+	return ((*gain - 64) << 5) | (1 << 6) | 32;
+}
+
+static int mt9t001_ctrl_freeze(struct mt9t001 *mt9t001, bool freeze)
+{
+	return mt9t001_set_output_control(mt9t001,
+		freeze ? 0 : MT9T001_OUTPUT_CONTROL_SYNC,
+		freeze ? MT9T001_OUTPUT_CONTROL_SYNC : 0);
+}
+
+static int mt9t001_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	static const u8 gains[4] = {
+		MT9T001_RED_GAIN, MT9T001_GREEN1_GAIN,
+		MT9T001_GREEN2_GAIN, MT9T001_BLUE_GAIN
+	};
+
+	struct mt9t001 *mt9t001 =
+			container_of(ctrl->handler, struct mt9t001, ctrls);
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev);
+	unsigned int count;
+	unsigned int i;
+	u16 value;
+	int ret;
+
+	switch (ctrl->id) {
+	case V4L2_CID_GAIN_RED:
+	case V4L2_CID_GAIN_GREEN_RED:
+	case V4L2_CID_GAIN_GREEN_BLUE:
+	case V4L2_CID_GAIN_BLUE:
+
+		/* Disable control updates if more than one control has changed
+		 * in the cluster.
+		 */
+		for (i = 0, count = 0; i < 4; ++i) {
+			struct v4l2_ctrl *gain = mt9t001->gains[i];
+
+			if (gain->val != gain->cur.val)
+				count++;
+		}
+
+		if (count > 1) {
+			ret = mt9t001_ctrl_freeze(mt9t001, true);
+			if (ret < 0)
+				return ret;
+		}
+
+		/* Update the gain controls. */
+		for (i = 0; i < 4; ++i) {
+			struct v4l2_ctrl *gain = mt9t001->gains[i];
+
+			if (gain->val == gain->cur.val)
+				continue;
+
+			value = mt9t001_gain_value(&gain->val);
+			ret = mt9t001_write(client, gains[i], value);
+			if (ret < 0) {
+				mt9t001_ctrl_freeze(mt9t001, false);
+				return ret;
+			}
+		}
+
+		/* Enable control updates. */
+		if (count > 1) {
+			ret = mt9t001_ctrl_freeze(mt9t001, false);
+			if (ret < 0)
+				return ret;
+		}
+
+		break;
+
+	case V4L2_CID_EXPOSURE:
+		ret = mt9t001_write(client, MT9T001_SHUTTER_WIDTH_LOW,
+				    ctrl->val & 0xffff);
+		if (ret < 0)
+			return ret;
+
+		return mt9t001_write(client, MT9T001_SHUTTER_WIDTH_HIGH,
+				     ctrl->val >> 16);
+
+	case V4L2_CID_TEST_PATTERN:
+		ret = mt9t001_set_output_control(mt9t001,
+			ctrl->val ? 0 : MT9T001_OUTPUT_CONTROL_TEST_DATA,
+			ctrl->val ? MT9T001_OUTPUT_CONTROL_TEST_DATA : 0);
+		if (ret < 0)
+			return ret;
+
+		return mt9t001_write(client, MT9T001_TEST_DATA, ctrl->val << 2);
+
+	case V4L2_CID_BLACK_LEVEL_AUTO:
+		value = ctrl->val ? 0 : MT9T001_BLACK_LEVEL_OVERRIDE;
+		ret = mt9t001_write(client, MT9T001_BLACK_LEVEL_CALIBRATION,
+				    value);
+		if (ret < 0)
+			return ret;
+
+		mt9t001->black_level = value;
+		break;
+
+	case V4L2_CID_BLACK_LEVEL_OFFSET:
+		ret = mt9t001_write(client, MT9T001_GREEN1_OFFSET, ctrl->val);
+		if (ret < 0)
+			return ret;
+
+		ret = mt9t001_write(client, MT9T001_GREEN2_OFFSET, ctrl->val);
+		if (ret < 0)
+			return ret;
+
+		ret = mt9t001_write(client, MT9T001_RED_OFFSET, ctrl->val);
+		if (ret < 0)
+			return ret;
+
+		return mt9t001_write(client, MT9T001_BLUE_OFFSET, ctrl->val);
+
+	case V4L2_CID_BLACK_LEVEL_CALIBRATE:
+		return mt9t001_write(client, MT9T001_BLACK_LEVEL_CALIBRATION,
+				     MT9T001_BLACK_LEVEL_RECALCULATE |
+				     mt9t001->black_level);
+	}
+
+	return 0;
+}
+
+static struct v4l2_ctrl_ops mt9t001_ctrl_ops = {
+	.s_ctrl = mt9t001_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config mt9t001_ctrls[] = {
+	{
+		.ops		= &mt9t001_ctrl_ops,
+		.id		= V4L2_CID_TEST_PATTERN,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Test pattern",
+		.min		= 0,
+		.max		= 1023,
+		.step		= 1,
+		.def		= 0,
+		.flags		= 0,
+	}, {
+		.ops		= &mt9t001_ctrl_ops,
+		.id		= V4L2_CID_BLACK_LEVEL_AUTO,
+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
+		.name		= "Black Level, Auto",
+		.min		= 0,
+		.max		= 1,
+		.step		= 1,
+		.def		= 1,
+		.flags		= 0,
+	}, {
+		.ops		= &mt9t001_ctrl_ops,
+		.id		= V4L2_CID_BLACK_LEVEL_OFFSET,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Black Level, Offset",
+		.min		= -256,
+		.max		= 255,
+		.step		= 1,
+		.def		= 32,
+		.flags		= 0,
+	}, {
+		.ops		= &mt9t001_ctrl_ops,
+		.id		= V4L2_CID_BLACK_LEVEL_CALIBRATE,
+		.type		= V4L2_CTRL_TYPE_BUTTON,
+		.name		= "Black Level, Calibrate",
+		.min		= 0,
+		.max		= 0,
+		.step		= 0,
+		.def		= 0,
+		.flags		= V4L2_CTRL_FLAG_WRITE_ONLY,
+	},
+};
+
+static const struct v4l2_ctrl_config mt9t001_gains[] = {
+	{
+		.ops		= &mt9t001_ctrl_ops,
+		.id		= V4L2_CID_GAIN_RED,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Gain, Red",
+		.min		= MT9T001_GLOBAL_GAIN_MIN,
+		.max		= MT9T001_GLOBAL_GAIN_MAX,
+		.step		= 1,
+		.def		= MT9T001_GLOBAL_GAIN_MIN,
+		.flags		= 0,
+	}, {
+		.ops		= &mt9t001_ctrl_ops,
+		.id		= V4L2_CID_GAIN_GREEN_RED,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Gain, Green (R)",
+		.min		= MT9T001_GLOBAL_GAIN_MIN,
+		.max		= MT9T001_GLOBAL_GAIN_MAX,
+		.step		= 1,
+		.def		= MT9T001_GLOBAL_GAIN_MIN,
+		.flags		= 0,
+	}, {
+		.ops		= &mt9t001_ctrl_ops,
+		.id		= V4L2_CID_GAIN_GREEN_BLUE,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Gain, Green (B)",
+		.min		= MT9T001_GLOBAL_GAIN_MIN,
+		.max		= MT9T001_GLOBAL_GAIN_MAX,
+		.step		= 1,
+		.def		= MT9T001_GLOBAL_GAIN_MIN,
+		.flags		= 0,
+	}, {
+		.ops		= &mt9t001_ctrl_ops,
+		.id		= V4L2_CID_GAIN_BLUE,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Gain, Blue",
+		.min		= MT9T001_GLOBAL_GAIN_MIN,
+		.max		= MT9T001_GLOBAL_GAIN_MAX,
+		.step		= 1,
+		.def		= MT9T001_GLOBAL_GAIN_MIN,
+		.flags		= 0,
+	},
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev internal operations
+ */
+
+static int mt9t001_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+	struct v4l2_mbus_framefmt *format;
+	struct v4l2_rect *crop;
+
+	crop = v4l2_subdev_get_try_crop(fh, 0);
+	crop->left = MT9T001_COLUMN_START_DEF;
+	crop->top = MT9T001_ROW_START_DEF;
+	crop->width = MT9T001_WINDOW_WIDTH_DEF + 1;
+	crop->height = MT9T001_WINDOW_HEIGHT_DEF + 1;
+
+	format = v4l2_subdev_get_try_format(fh, 0);
+	format->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+	format->width = MT9T001_WINDOW_WIDTH_DEF + 1;
+	format->height = MT9T001_WINDOW_HEIGHT_DEF + 1;
+	format->field = V4L2_FIELD_NONE;
+	format->colorspace = V4L2_COLORSPACE_SRGB;
+
+	return 0;
+}
+
+static struct v4l2_subdev_video_ops mt9t001_subdev_video_ops = {
+	.s_stream = mt9t001_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops mt9t001_subdev_pad_ops = {
+	.enum_mbus_code = mt9t001_enum_mbus_code,
+	.enum_frame_size = mt9t001_enum_frame_size,
+	.get_fmt = mt9t001_get_format,
+	.set_fmt = mt9t001_set_format,
+	.get_crop = mt9t001_get_crop,
+	.set_crop = mt9t001_set_crop,
+};
+
+static struct v4l2_subdev_ops mt9t001_subdev_ops = {
+	.video = &mt9t001_subdev_video_ops,
+	.pad = &mt9t001_subdev_pad_ops,
+};
+
+static struct v4l2_subdev_internal_ops mt9t001_subdev_internal_ops = {
+	.open = mt9t001_open,
+};
+
+static int mt9t001_video_probe(struct i2c_client *client)
+{
+	struct mt9t001_platform_data *pdata = client->dev.platform_data;
+	s32 data;
+	int ret;
+
+	dev_info(&client->dev, "Probing MT9T001 at address 0x%02x\n",
+		 client->addr);
+
+	/* Reset the chip and stop data read out */
+	ret = mt9t001_write(client, MT9T001_RESET, 1);
+	if (ret < 0)
+		return ret;
+
+	ret = mt9t001_write(client, MT9T001_RESET, 0);
+	if (ret < 0)
+		return ret;
+
+	ret  = mt9t001_write(client, MT9T001_OUTPUT_CONTROL, 0);
+	if (ret < 0)
+		return ret;
+
+	/* Configure the pixel clock polarity */
+	if (pdata->clk_pol) {
+		ret  = mt9t001_write(client, MT9T001_PIXEL_CLOCK,
+				     MT9T001_PIXEL_CLOCK_INVERT);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* Read and check the sensor version */
+	data = mt9t001_read(client, MT9T001_CHIP_VERSION);
+	if (data != MT9T001_CHIP_ID) {
+		dev_err(&client->dev, "MT9T001 not detected, wrong version "
+			"0x%04x\n", data);
+		return -ENODEV;
+	}
+
+	dev_info(&client->dev, "MT9T001 detected at address 0x%02x\n",
+		 client->addr);
+
+	return ret;
+}
+
+static int mt9t001_probe(struct i2c_client *client,
+			 const struct i2c_device_id *did)
+{
+	struct mt9t001_platform_data *pdata = client->dev.platform_data;
+	struct mt9t001 *mt9t001;
+	unsigned int i;
+	int ret;
+
+	if (pdata == NULL) {
+		dev_err(&client->dev, "No platform data\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_warn(&client->adapter->dev,
+			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+		return -EIO;
+	}
+
+	ret = mt9t001_video_probe(client);
+	if (ret < 0)
+		return ret;
+
+	mt9t001 = kzalloc(sizeof(*mt9t001), GFP_KERNEL);
+	if (!mt9t001)
+		return -ENOMEM;
+
+	v4l2_ctrl_handler_init(&mt9t001->ctrls, ARRAY_SIZE(mt9t001_ctrls) +
+						ARRAY_SIZE(mt9t001_gains) + 3);
+
+	v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops,
+			  V4L2_CID_EXPOSURE, MT9T001_SHUTTER_WIDTH_MIN,
+			  MT9T001_SHUTTER_WIDTH_MAX, 1,
+			  MT9T001_SHUTTER_WIDTH_DEF);
+	v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops,
+			  V4L2_CID_BLACK_LEVEL, 1, 1, 1, 1);
+	v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops,
+			  V4L2_CID_PIXEL_RATE, pdata->ext_clk, pdata->ext_clk,
+			  1, pdata->ext_clk);
+
+	for (i = 0; i < ARRAY_SIZE(mt9t001_ctrls); ++i)
+		v4l2_ctrl_new_custom(&mt9t001->ctrls, &mt9t001_ctrls[i], NULL);
+
+	for (i = 0; i < ARRAY_SIZE(mt9t001_gains); ++i)
+		mt9t001->gains[i] = v4l2_ctrl_new_custom(&mt9t001->ctrls,
+			&mt9t001_gains[i], NULL);
+
+	v4l2_ctrl_cluster(ARRAY_SIZE(mt9t001_gains), mt9t001->gains);
+
+	mt9t001->subdev.ctrl_handler = &mt9t001->ctrls;
+
+	if (mt9t001->ctrls.error) {
+		printk(KERN_INFO "%s: control initialization error %d\n",
+		       __func__, mt9t001->ctrls.error);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	mt9t001->crop.left = MT9T001_COLUMN_START_DEF;
+	mt9t001->crop.top = MT9T001_ROW_START_DEF;
+	mt9t001->crop.width = MT9T001_WINDOW_WIDTH_DEF + 1;
+	mt9t001->crop.height = MT9T001_WINDOW_HEIGHT_DEF + 1;
+
+	mt9t001->format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+	mt9t001->format.width = MT9T001_WINDOW_WIDTH_DEF + 1;
+	mt9t001->format.height = MT9T001_WINDOW_HEIGHT_DEF + 1;
+	mt9t001->format.field = V4L2_FIELD_NONE;
+	mt9t001->format.colorspace = V4L2_COLORSPACE_SRGB;
+
+	v4l2_i2c_subdev_init(&mt9t001->subdev, client, &mt9t001_subdev_ops);
+	mt9t001->subdev.internal_ops = &mt9t001_subdev_internal_ops;
+	mt9t001->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	mt9t001->pad.flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_init(&mt9t001->subdev.entity, 1, &mt9t001->pad, 0);
+
+done:
+	if (ret < 0) {
+		v4l2_ctrl_handler_free(&mt9t001->ctrls);
+		media_entity_cleanup(&mt9t001->subdev.entity);
+		kfree(mt9t001);
+	}
+
+	return ret;
+}
+
+static int mt9t001_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct mt9t001 *mt9t001 = to_mt9t001(subdev);
+
+	v4l2_ctrl_handler_free(&mt9t001->ctrls);
+	v4l2_device_unregister_subdev(subdev);
+	media_entity_cleanup(&subdev->entity);
+	kfree(mt9t001);
+	return 0;
+}
+
+static const struct i2c_device_id mt9t001_id[] = {
+	{ "mt9t001", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mt9t001_id);
+
+static struct i2c_driver mt9t001_driver = {
+	.driver = {
+		.name = "mt9t001",
+	},
+	.probe		= mt9t001_probe,
+	.remove		= mt9t001_remove,
+	.id_table	= mt9t001_id,
+};
+
+module_i2c_driver(mt9t001_driver);
+
+MODULE_DESCRIPTION("Aptina (Micron) MT9T001 Camera driver");
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c
new file mode 100644
index 0000000..6bf01ad
--- /dev/null
+++ b/drivers/media/i2c/mt9v011.c
@@ -0,0 +1,712 @@
+/*
+ * mt9v011 -Micron 1/4-Inch VGA Digital Image Sensor
+ *
+ * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com)
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <asm/div64.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/mt9v011.h>
+
+MODULE_DESCRIPTION("Micron mt9v011 sensor driver");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+#define R00_MT9V011_CHIP_VERSION	0x00
+#define R01_MT9V011_ROWSTART		0x01
+#define R02_MT9V011_COLSTART		0x02
+#define R03_MT9V011_HEIGHT		0x03
+#define R04_MT9V011_WIDTH		0x04
+#define R05_MT9V011_HBLANK		0x05
+#define R06_MT9V011_VBLANK		0x06
+#define R07_MT9V011_OUT_CTRL		0x07
+#define R09_MT9V011_SHUTTER_WIDTH	0x09
+#define R0A_MT9V011_CLK_SPEED		0x0a
+#define R0B_MT9V011_RESTART		0x0b
+#define R0C_MT9V011_SHUTTER_DELAY	0x0c
+#define R0D_MT9V011_RESET		0x0d
+#define R1E_MT9V011_DIGITAL_ZOOM	0x1e
+#define R20_MT9V011_READ_MODE		0x20
+#define R2B_MT9V011_GREEN_1_GAIN	0x2b
+#define R2C_MT9V011_BLUE_GAIN		0x2c
+#define R2D_MT9V011_RED_GAIN		0x2d
+#define R2E_MT9V011_GREEN_2_GAIN	0x2e
+#define R35_MT9V011_GLOBAL_GAIN		0x35
+#define RF1_MT9V011_CHIP_ENABLE		0xf1
+
+#define MT9V011_VERSION			0x8232
+#define MT9V011_REV_B_VERSION		0x8243
+
+/* supported controls */
+static struct v4l2_queryctrl mt9v011_qctrl[] = {
+	{
+		.id = V4L2_CID_GAIN,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Gain",
+		.minimum = 0,
+		.maximum = (1 << 12) - 1 - 0x0020,
+		.step = 1,
+		.default_value = 0x0020,
+		.flags = 0,
+	}, {
+		.id = V4L2_CID_EXPOSURE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Exposure",
+		.minimum = 0,
+		.maximum = 2047,
+		.step = 1,
+		.default_value = 0x01fc,
+		.flags = 0,
+	}, {
+		.id = V4L2_CID_RED_BALANCE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Red Balance",
+		.minimum = -1 << 9,
+		.maximum = (1 << 9) - 1,
+		.step = 1,
+		.default_value = 0,
+		.flags = 0,
+	}, {
+		.id = V4L2_CID_BLUE_BALANCE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Blue Balance",
+		.minimum = -1 << 9,
+		.maximum = (1 << 9) - 1,
+		.step = 1,
+		.default_value = 0,
+		.flags = 0,
+	}, {
+		.id      = V4L2_CID_HFLIP,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Mirror",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+		.default_value = 0,
+		.flags = 0,
+	}, {
+		.id      = V4L2_CID_VFLIP,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Vflip",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+		.default_value = 0,
+		.flags = 0,
+	}, {
+	}
+};
+
+struct mt9v011 {
+	struct v4l2_subdev sd;
+	unsigned width, height;
+	unsigned xtal;
+	unsigned hflip:1;
+	unsigned vflip:1;
+
+	u16 global_gain, exposure;
+	s16 red_bal, blue_bal;
+};
+
+static inline struct mt9v011 *to_mt9v011(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct mt9v011, sd);
+}
+
+static int mt9v011_read(struct v4l2_subdev *sd, unsigned char addr)
+{
+	struct i2c_client *c = v4l2_get_subdevdata(sd);
+	__be16 buffer;
+	int rc, val;
+
+	rc = i2c_master_send(c, &addr, 1);
+	if (rc != 1)
+		v4l2_dbg(0, debug, sd,
+			 "i2c i/o error: rc == %d (should be 1)\n", rc);
+
+	msleep(10);
+
+	rc = i2c_master_recv(c, (char *)&buffer, 2);
+	if (rc != 2)
+		v4l2_dbg(0, debug, sd,
+			 "i2c i/o error: rc == %d (should be 2)\n", rc);
+
+	val = be16_to_cpu(buffer);
+
+	v4l2_dbg(2, debug, sd, "mt9v011: read 0x%02x = 0x%04x\n", addr, val);
+
+	return val;
+}
+
+static void mt9v011_write(struct v4l2_subdev *sd, unsigned char addr,
+				 u16 value)
+{
+	struct i2c_client *c = v4l2_get_subdevdata(sd);
+	unsigned char buffer[3];
+	int rc;
+
+	buffer[0] = addr;
+	buffer[1] = value >> 8;
+	buffer[2] = value & 0xff;
+
+	v4l2_dbg(2, debug, sd,
+		 "mt9v011: writing 0x%02x 0x%04x\n", buffer[0], value);
+	rc = i2c_master_send(c, buffer, 3);
+	if (rc != 3)
+		v4l2_dbg(0, debug, sd,
+			 "i2c i/o error: rc == %d (should be 3)\n", rc);
+}
+
+
+struct i2c_reg_value {
+	unsigned char reg;
+	u16           value;
+};
+
+/*
+ * Values used at the original driver
+ * Some values are marked as Reserved at the datasheet
+ */
+static const struct i2c_reg_value mt9v011_init_default[] = {
+		{ R0D_MT9V011_RESET, 0x0001 },
+		{ R0D_MT9V011_RESET, 0x0000 },
+
+		{ R0C_MT9V011_SHUTTER_DELAY, 0x0000 },
+		{ R09_MT9V011_SHUTTER_WIDTH, 0x1fc },
+
+		{ R0A_MT9V011_CLK_SPEED, 0x0000 },
+		{ R1E_MT9V011_DIGITAL_ZOOM,  0x0000 },
+
+		{ R07_MT9V011_OUT_CTRL, 0x0002 },	/* chip enable */
+};
+
+
+static u16 calc_mt9v011_gain(s16 lineargain)
+{
+
+	u16 digitalgain = 0;
+	u16 analogmult = 0;
+	u16 analoginit = 0;
+
+	if (lineargain < 0)
+		lineargain = 0;
+
+	/* recommended minimum */
+	lineargain += 0x0020;
+
+	if (lineargain > 2047)
+		lineargain = 2047;
+
+	if (lineargain > 1023) {
+		digitalgain = 3;
+		analogmult = 3;
+		analoginit = lineargain / 16;
+	} else if (lineargain > 511) {
+		digitalgain = 1;
+		analogmult = 3;
+		analoginit = lineargain / 8;
+	} else if (lineargain > 255) {
+		analogmult = 3;
+		analoginit = lineargain / 4;
+	} else if (lineargain > 127) {
+		analogmult = 1;
+		analoginit = lineargain / 2;
+	} else
+		analoginit = lineargain;
+
+	return analoginit + (analogmult << 7) + (digitalgain << 9);
+
+}
+
+static void set_balance(struct v4l2_subdev *sd)
+{
+	struct mt9v011 *core = to_mt9v011(sd);
+	u16 green_gain, blue_gain, red_gain;
+	u16 exposure;
+	s16 bal;
+
+	exposure = core->exposure;
+
+	green_gain = calc_mt9v011_gain(core->global_gain);
+
+	bal = core->global_gain;
+	bal += (core->blue_bal * core->global_gain / (1 << 7));
+	blue_gain = calc_mt9v011_gain(bal);
+
+	bal = core->global_gain;
+	bal += (core->red_bal * core->global_gain / (1 << 7));
+	red_gain = calc_mt9v011_gain(bal);
+
+	mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green_gain);
+	mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN, green_gain);
+	mt9v011_write(sd, R2C_MT9V011_BLUE_GAIN, blue_gain);
+	mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain);
+	mt9v011_write(sd, R09_MT9V011_SHUTTER_WIDTH, exposure);
+}
+
+static void calc_fps(struct v4l2_subdev *sd, u32 *numerator, u32 *denominator)
+{
+	struct mt9v011 *core = to_mt9v011(sd);
+	unsigned height, width, hblank, vblank, speed;
+	unsigned row_time, t_time;
+	u64 frames_per_ms;
+	unsigned tmp;
+
+	height = mt9v011_read(sd, R03_MT9V011_HEIGHT);
+	width = mt9v011_read(sd, R04_MT9V011_WIDTH);
+	hblank = mt9v011_read(sd, R05_MT9V011_HBLANK);
+	vblank = mt9v011_read(sd, R06_MT9V011_VBLANK);
+	speed = mt9v011_read(sd, R0A_MT9V011_CLK_SPEED);
+
+	row_time = (width + 113 + hblank) * (speed + 2);
+	t_time = row_time * (height + vblank + 1);
+
+	frames_per_ms = core->xtal * 1000l;
+	do_div(frames_per_ms, t_time);
+	tmp = frames_per_ms;
+
+	v4l2_dbg(1, debug, sd, "Programmed to %u.%03u fps (%d pixel clcks)\n",
+		tmp / 1000, tmp % 1000, t_time);
+
+	if (numerator && denominator) {
+		*numerator = 1000;
+		*denominator = (u32)frames_per_ms;
+	}
+}
+
+static u16 calc_speed(struct v4l2_subdev *sd, u32 numerator, u32 denominator)
+{
+	struct mt9v011 *core = to_mt9v011(sd);
+	unsigned height, width, hblank, vblank;
+	unsigned row_time, line_time;
+	u64 t_time, speed;
+
+	/* Avoid bogus calculus */
+	if (!numerator || !denominator)
+		return 0;
+
+	height = mt9v011_read(sd, R03_MT9V011_HEIGHT);
+	width = mt9v011_read(sd, R04_MT9V011_WIDTH);
+	hblank = mt9v011_read(sd, R05_MT9V011_HBLANK);
+	vblank = mt9v011_read(sd, R06_MT9V011_VBLANK);
+
+	row_time = width + 113 + hblank;
+	line_time = height + vblank + 1;
+
+	t_time = core->xtal * ((u64)numerator);
+	/* round to the closest value */
+	t_time += denominator / 2;
+	do_div(t_time, denominator);
+
+	speed = t_time;
+	do_div(speed, row_time * line_time);
+
+	/* Avoid having a negative value for speed */
+	if (speed < 2)
+		speed = 0;
+	else
+		speed -= 2;
+
+	/* Avoid speed overflow */
+	if (speed > 15)
+		return 15;
+
+	return (u16)speed;
+}
+
+static void set_res(struct v4l2_subdev *sd)
+{
+	struct mt9v011 *core = to_mt9v011(sd);
+	unsigned vstart, hstart;
+
+	/*
+	 * The mt9v011 doesn't have scaling. So, in order to select the desired
+	 * resolution, we're cropping at the middle of the sensor.
+	 * hblank and vblank should be adjusted, in order to warrant that
+	 * we'll preserve the line timings for 30 fps, no matter what resolution
+	 * is selected.
+	 * NOTE: datasheet says that width (and height) should be filled with
+	 * width-1. However, this doesn't work, since one pixel per line will
+	 * be missing.
+	 */
+
+	hstart = 20 + (640 - core->width) / 2;
+	mt9v011_write(sd, R02_MT9V011_COLSTART, hstart);
+	mt9v011_write(sd, R04_MT9V011_WIDTH, core->width);
+	mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core->width);
+
+	vstart = 8 + (480 - core->height) / 2;
+	mt9v011_write(sd, R01_MT9V011_ROWSTART, vstart);
+	mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height);
+	mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height);
+
+	calc_fps(sd, NULL, NULL);
+};
+
+static void set_read_mode(struct v4l2_subdev *sd)
+{
+	struct mt9v011 *core = to_mt9v011(sd);
+	unsigned mode = 0x1000;
+
+	if (core->hflip)
+		mode |= 0x4000;
+
+	if (core->vflip)
+		mode |= 0x8000;
+
+	mt9v011_write(sd, R20_MT9V011_READ_MODE, mode);
+}
+
+static int mt9v011_reset(struct v4l2_subdev *sd, u32 val)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mt9v011_init_default); i++)
+		mt9v011_write(sd, mt9v011_init_default[i].reg,
+			       mt9v011_init_default[i].value);
+
+	set_balance(sd);
+	set_res(sd);
+	set_read_mode(sd);
+
+	return 0;
+};
+
+static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	struct mt9v011 *core = to_mt9v011(sd);
+
+	v4l2_dbg(1, debug, sd, "g_ctrl called\n");
+
+	switch (ctrl->id) {
+	case V4L2_CID_GAIN:
+		ctrl->value = core->global_gain;
+		return 0;
+	case V4L2_CID_EXPOSURE:
+		ctrl->value = core->exposure;
+		return 0;
+	case V4L2_CID_RED_BALANCE:
+		ctrl->value = core->red_bal;
+		return 0;
+	case V4L2_CID_BLUE_BALANCE:
+		ctrl->value = core->blue_bal;
+		return 0;
+	case V4L2_CID_HFLIP:
+		ctrl->value = core->hflip ? 1 : 0;
+		return 0;
+	case V4L2_CID_VFLIP:
+		ctrl->value = core->vflip ? 1 : 0;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int mt9v011_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+	int i;
+
+	v4l2_dbg(1, debug, sd, "queryctrl called\n");
+
+	for (i = 0; i < ARRAY_SIZE(mt9v011_qctrl); i++)
+		if (qc->id && qc->id == mt9v011_qctrl[i].id) {
+			memcpy(qc, &(mt9v011_qctrl[i]),
+			       sizeof(*qc));
+			return 0;
+		}
+
+	return -EINVAL;
+}
+
+
+static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	struct mt9v011 *core = to_mt9v011(sd);
+	u8 i, n;
+	n = ARRAY_SIZE(mt9v011_qctrl);
+
+	for (i = 0; i < n; i++) {
+		if (ctrl->id != mt9v011_qctrl[i].id)
+			continue;
+		if (ctrl->value < mt9v011_qctrl[i].minimum ||
+		    ctrl->value > mt9v011_qctrl[i].maximum)
+			return -ERANGE;
+		v4l2_dbg(1, debug, sd, "s_ctrl: id=%d, value=%d\n",
+					ctrl->id, ctrl->value);
+		break;
+	}
+
+	switch (ctrl->id) {
+	case V4L2_CID_GAIN:
+		core->global_gain = ctrl->value;
+		break;
+	case V4L2_CID_EXPOSURE:
+		core->exposure = ctrl->value;
+		break;
+	case V4L2_CID_RED_BALANCE:
+		core->red_bal = ctrl->value;
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		core->blue_bal = ctrl->value;
+		break;
+	case V4L2_CID_HFLIP:
+		core->hflip = ctrl->value;
+		set_read_mode(sd);
+		return 0;
+	case V4L2_CID_VFLIP:
+		core->vflip = ctrl->value;
+		set_read_mode(sd);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+
+	set_balance(sd);
+
+	return 0;
+}
+
+static int mt9v011_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+					enum v4l2_mbus_pixelcode *code)
+{
+	if (index > 0)
+		return -EINVAL;
+
+	*code = V4L2_MBUS_FMT_SGRBG8_1X8;
+	return 0;
+}
+
+static int mt9v011_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
+{
+	if (fmt->code != V4L2_MBUS_FMT_SGRBG8_1X8)
+		return -EINVAL;
+
+	v4l_bound_align_image(&fmt->width, 48, 639, 1,
+			      &fmt->height, 32, 480, 1, 0);
+	fmt->field = V4L2_FIELD_NONE;
+	fmt->colorspace = V4L2_COLORSPACE_SRGB;
+
+	return 0;
+}
+
+static int mt9v011_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+	struct v4l2_captureparm *cp = &parms->parm.capture;
+
+	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	memset(cp, 0, sizeof(struct v4l2_captureparm));
+	cp->capability = V4L2_CAP_TIMEPERFRAME;
+	calc_fps(sd,
+		 &cp->timeperframe.numerator,
+		 &cp->timeperframe.denominator);
+
+	return 0;
+}
+
+static int mt9v011_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+	struct v4l2_captureparm *cp = &parms->parm.capture;
+	struct v4l2_fract *tpf = &cp->timeperframe;
+	u16 speed;
+
+	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (cp->extendedmode != 0)
+		return -EINVAL;
+
+	speed = calc_speed(sd, tpf->numerator, tpf->denominator);
+
+	mt9v011_write(sd, R0A_MT9V011_CLK_SPEED, speed);
+	v4l2_dbg(1, debug, sd, "Setting speed to %d\n", speed);
+
+	/* Recalculate and update fps info */
+	calc_fps(sd, &tpf->numerator, &tpf->denominator);
+
+	return 0;
+}
+
+static int mt9v011_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
+{
+	struct mt9v011 *core = to_mt9v011(sd);
+	int rc;
+
+	rc = mt9v011_try_mbus_fmt(sd, fmt);
+	if (rc < 0)
+		return -EINVAL;
+
+	core->width = fmt->width;
+	core->height = fmt->height;
+
+	set_res(sd);
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9v011_g_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	reg->val = mt9v011_read(sd, reg->reg & 0xff);
+	reg->size = 2;
+
+	return 0;
+}
+
+static int mt9v011_s_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	mt9v011_write(sd, reg->reg & 0xff, reg->val & 0xffff);
+
+	return 0;
+}
+#endif
+
+static int mt9v011_g_chip_ident(struct v4l2_subdev *sd,
+				struct v4l2_dbg_chip_ident *chip)
+{
+	u16 version;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_MT9V011,
+					  version);
+}
+
+static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
+	.queryctrl = mt9v011_queryctrl,
+	.g_ctrl = mt9v011_g_ctrl,
+	.s_ctrl = mt9v011_s_ctrl,
+	.reset = mt9v011_reset,
+	.g_chip_ident = mt9v011_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = mt9v011_g_register,
+	.s_register = mt9v011_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops mt9v011_video_ops = {
+	.enum_mbus_fmt = mt9v011_enum_mbus_fmt,
+	.try_mbus_fmt = mt9v011_try_mbus_fmt,
+	.s_mbus_fmt = mt9v011_s_mbus_fmt,
+	.g_parm = mt9v011_g_parm,
+	.s_parm = mt9v011_s_parm,
+};
+
+static const struct v4l2_subdev_ops mt9v011_ops = {
+	.core  = &mt9v011_core_ops,
+	.video = &mt9v011_video_ops,
+};
+
+
+/****************************************************************************
+			I2C Client & Driver
+ ****************************************************************************/
+
+static int mt9v011_probe(struct i2c_client *c,
+			 const struct i2c_device_id *id)
+{
+	u16 version;
+	struct mt9v011 *core;
+	struct v4l2_subdev *sd;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(c->adapter,
+	     I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+		return -EIO;
+
+	core = kzalloc(sizeof(struct mt9v011), GFP_KERNEL);
+	if (!core)
+		return -ENOMEM;
+
+	sd = &core->sd;
+	v4l2_i2c_subdev_init(sd, c, &mt9v011_ops);
+
+	/* Check if the sensor is really a MT9V011 */
+	version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION);
+	if ((version != MT9V011_VERSION) &&
+	    (version != MT9V011_REV_B_VERSION)) {
+		v4l2_info(sd, "*** unknown micron chip detected (0x%04x).\n",
+			  version);
+		kfree(core);
+		return -EINVAL;
+	}
+
+	core->global_gain = 0x0024;
+	core->exposure = 0x01fc;
+	core->width  = 640;
+	core->height = 480;
+	core->xtal = 27000000;	/* Hz */
+
+	if (c->dev.platform_data) {
+		struct mt9v011_platform_data *pdata = c->dev.platform_data;
+
+		core->xtal = pdata->xtal;
+		v4l2_dbg(1, debug, sd, "xtal set to %d.%03d MHz\n",
+			core->xtal / 1000000, (core->xtal / 1000) % 1000);
+	}
+
+	v4l_info(c, "chip found @ 0x%02x (%s - chip version 0x%04x)\n",
+		 c->addr << 1, c->adapter->name, version);
+
+	return 0;
+}
+
+static int mt9v011_remove(struct i2c_client *c)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(c);
+
+	v4l2_dbg(1, debug, sd,
+		"mt9v011.c: removing mt9v011 adapter on address 0x%x\n",
+		c->addr << 1);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_mt9v011(sd));
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id mt9v011_id[] = {
+	{ "mt9v011", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mt9v011_id);
+
+static struct i2c_driver mt9v011_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "mt9v011",
+	},
+	.probe		= mt9v011_probe,
+	.remove		= mt9v011_remove,
+	.id_table	= mt9v011_id,
+};
+
+module_i2c_driver(mt9v011_driver);
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
new file mode 100644
index 0000000..4ba4884
--- /dev/null
+++ b/drivers/media/i2c/mt9v032.c
@@ -0,0 +1,763 @@
+/*
+ * Driver for MT9V032 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2010, Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * Based on the MT9M001 driver,
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/module.h>
+
+#include <media/mt9v032.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#define MT9V032_PIXEL_ARRAY_HEIGHT			492
+#define MT9V032_PIXEL_ARRAY_WIDTH			782
+
+#define MT9V032_CHIP_VERSION				0x00
+#define		MT9V032_CHIP_ID_REV1			0x1311
+#define		MT9V032_CHIP_ID_REV3			0x1313
+#define MT9V032_COLUMN_START				0x01
+#define		MT9V032_COLUMN_START_MIN		1
+#define		MT9V032_COLUMN_START_DEF		1
+#define		MT9V032_COLUMN_START_MAX		752
+#define MT9V032_ROW_START				0x02
+#define		MT9V032_ROW_START_MIN			4
+#define		MT9V032_ROW_START_DEF			5
+#define		MT9V032_ROW_START_MAX			482
+#define MT9V032_WINDOW_HEIGHT				0x03
+#define		MT9V032_WINDOW_HEIGHT_MIN		1
+#define		MT9V032_WINDOW_HEIGHT_DEF		480
+#define		MT9V032_WINDOW_HEIGHT_MAX		480
+#define MT9V032_WINDOW_WIDTH				0x04
+#define		MT9V032_WINDOW_WIDTH_MIN		1
+#define		MT9V032_WINDOW_WIDTH_DEF		752
+#define		MT9V032_WINDOW_WIDTH_MAX		752
+#define MT9V032_HORIZONTAL_BLANKING			0x05
+#define		MT9V032_HORIZONTAL_BLANKING_MIN		43
+#define		MT9V032_HORIZONTAL_BLANKING_MAX		1023
+#define MT9V032_VERTICAL_BLANKING			0x06
+#define		MT9V032_VERTICAL_BLANKING_MIN		4
+#define		MT9V032_VERTICAL_BLANKING_MAX		3000
+#define MT9V032_CHIP_CONTROL				0x07
+#define		MT9V032_CHIP_CONTROL_MASTER_MODE	(1 << 3)
+#define		MT9V032_CHIP_CONTROL_DOUT_ENABLE	(1 << 7)
+#define		MT9V032_CHIP_CONTROL_SEQUENTIAL		(1 << 8)
+#define MT9V032_SHUTTER_WIDTH1				0x08
+#define MT9V032_SHUTTER_WIDTH2				0x09
+#define MT9V032_SHUTTER_WIDTH_CONTROL			0x0a
+#define MT9V032_TOTAL_SHUTTER_WIDTH			0x0b
+#define		MT9V032_TOTAL_SHUTTER_WIDTH_MIN		1
+#define		MT9V032_TOTAL_SHUTTER_WIDTH_DEF		480
+#define		MT9V032_TOTAL_SHUTTER_WIDTH_MAX		32767
+#define MT9V032_RESET					0x0c
+#define MT9V032_READ_MODE				0x0d
+#define		MT9V032_READ_MODE_ROW_BIN_MASK		(3 << 0)
+#define		MT9V032_READ_MODE_ROW_BIN_SHIFT		0
+#define		MT9V032_READ_MODE_COLUMN_BIN_MASK	(3 << 2)
+#define		MT9V032_READ_MODE_COLUMN_BIN_SHIFT	2
+#define		MT9V032_READ_MODE_ROW_FLIP		(1 << 4)
+#define		MT9V032_READ_MODE_COLUMN_FLIP		(1 << 5)
+#define		MT9V032_READ_MODE_DARK_COLUMNS		(1 << 6)
+#define		MT9V032_READ_MODE_DARK_ROWS		(1 << 7)
+#define MT9V032_PIXEL_OPERATION_MODE			0x0f
+#define		MT9V032_PIXEL_OPERATION_MODE_COLOR	(1 << 2)
+#define		MT9V032_PIXEL_OPERATION_MODE_HDR	(1 << 6)
+#define MT9V032_ANALOG_GAIN				0x35
+#define		MT9V032_ANALOG_GAIN_MIN			16
+#define		MT9V032_ANALOG_GAIN_DEF			16
+#define		MT9V032_ANALOG_GAIN_MAX			64
+#define MT9V032_MAX_ANALOG_GAIN				0x36
+#define		MT9V032_MAX_ANALOG_GAIN_MAX		127
+#define MT9V032_FRAME_DARK_AVERAGE			0x42
+#define MT9V032_DARK_AVG_THRESH				0x46
+#define		MT9V032_DARK_AVG_LOW_THRESH_MASK	(255 << 0)
+#define		MT9V032_DARK_AVG_LOW_THRESH_SHIFT	0
+#define		MT9V032_DARK_AVG_HIGH_THRESH_MASK	(255 << 8)
+#define		MT9V032_DARK_AVG_HIGH_THRESH_SHIFT	8
+#define MT9V032_ROW_NOISE_CORR_CONTROL			0x70
+#define		MT9V032_ROW_NOISE_CORR_ENABLE		(1 << 5)
+#define		MT9V032_ROW_NOISE_CORR_USE_BLK_AVG	(1 << 7)
+#define MT9V032_PIXEL_CLOCK				0x74
+#define		MT9V032_PIXEL_CLOCK_INV_LINE		(1 << 0)
+#define		MT9V032_PIXEL_CLOCK_INV_FRAME		(1 << 1)
+#define		MT9V032_PIXEL_CLOCK_XOR_LINE		(1 << 2)
+#define		MT9V032_PIXEL_CLOCK_CONT_LINE		(1 << 3)
+#define		MT9V032_PIXEL_CLOCK_INV_PXL_CLK		(1 << 4)
+#define MT9V032_TEST_PATTERN				0x7f
+#define		MT9V032_TEST_PATTERN_DATA_MASK		(1023 << 0)
+#define		MT9V032_TEST_PATTERN_DATA_SHIFT		0
+#define		MT9V032_TEST_PATTERN_USE_DATA		(1 << 10)
+#define		MT9V032_TEST_PATTERN_GRAY_MASK		(3 << 11)
+#define		MT9V032_TEST_PATTERN_GRAY_NONE		(0 << 11)
+#define		MT9V032_TEST_PATTERN_GRAY_VERTICAL	(1 << 11)
+#define		MT9V032_TEST_PATTERN_GRAY_HORIZONTAL	(2 << 11)
+#define		MT9V032_TEST_PATTERN_GRAY_DIAGONAL	(3 << 11)
+#define		MT9V032_TEST_PATTERN_ENABLE		(1 << 13)
+#define		MT9V032_TEST_PATTERN_FLIP		(1 << 14)
+#define MT9V032_AEC_AGC_ENABLE				0xaf
+#define		MT9V032_AEC_ENABLE			(1 << 0)
+#define		MT9V032_AGC_ENABLE			(1 << 1)
+#define MT9V032_THERMAL_INFO				0xc1
+
+struct mt9v032 {
+	struct v4l2_subdev subdev;
+	struct media_pad pad;
+
+	struct v4l2_mbus_framefmt format;
+	struct v4l2_rect crop;
+
+	struct v4l2_ctrl_handler ctrls;
+
+	struct mutex power_lock;
+	int power_count;
+
+	struct mt9v032_platform_data *pdata;
+	u16 chip_control;
+	u16 aec_agc;
+};
+
+static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct mt9v032, subdev);
+}
+
+static int mt9v032_read(struct i2c_client *client, const u8 reg)
+{
+	s32 data = i2c_smbus_read_word_swapped(client, reg);
+	dev_dbg(&client->dev, "%s: read 0x%04x from 0x%02x\n", __func__,
+		data, reg);
+	return data;
+}
+
+static int mt9v032_write(struct i2c_client *client, const u8 reg,
+			 const u16 data)
+{
+	dev_dbg(&client->dev, "%s: writing 0x%04x to 0x%02x\n", __func__,
+		data, reg);
+	return i2c_smbus_write_word_swapped(client, reg, data);
+}
+
+static int mt9v032_set_chip_control(struct mt9v032 *mt9v032, u16 clear, u16 set)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+	u16 value = (mt9v032->chip_control & ~clear) | set;
+	int ret;
+
+	ret = mt9v032_write(client, MT9V032_CHIP_CONTROL, value);
+	if (ret < 0)
+		return ret;
+
+	mt9v032->chip_control = value;
+	return 0;
+}
+
+static int
+mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+	u16 value = mt9v032->aec_agc;
+	int ret;
+
+	if (enable)
+		value |= which;
+	else
+		value &= ~which;
+
+	ret = mt9v032_write(client, MT9V032_AEC_AGC_ENABLE, value);
+	if (ret < 0)
+		return ret;
+
+	mt9v032->aec_agc = value;
+	return 0;
+}
+
+static int mt9v032_power_on(struct mt9v032 *mt9v032)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+	int ret;
+
+	if (mt9v032->pdata->set_clock) {
+		mt9v032->pdata->set_clock(&mt9v032->subdev, 25000000);
+		udelay(1);
+	}
+
+	/* Reset the chip and stop data read out */
+	ret = mt9v032_write(client, MT9V032_RESET, 1);
+	if (ret < 0)
+		return ret;
+
+	ret = mt9v032_write(client, MT9V032_RESET, 0);
+	if (ret < 0)
+		return ret;
+
+	return mt9v032_write(client, MT9V032_CHIP_CONTROL, 0);
+}
+
+static void mt9v032_power_off(struct mt9v032 *mt9v032)
+{
+	if (mt9v032->pdata->set_clock)
+		mt9v032->pdata->set_clock(&mt9v032->subdev, 0);
+}
+
+static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+	int ret;
+
+	if (!on) {
+		mt9v032_power_off(mt9v032);
+		return 0;
+	}
+
+	ret = mt9v032_power_on(mt9v032);
+	if (ret < 0)
+		return ret;
+
+	/* Configure the pixel clock polarity */
+	if (mt9v032->pdata && mt9v032->pdata->clk_pol) {
+		ret = mt9v032_write(client, MT9V032_PIXEL_CLOCK,
+				MT9V032_PIXEL_CLOCK_INV_PXL_CLK);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* Disable the noise correction algorithm and restore the controls. */
+	ret = mt9v032_write(client, MT9V032_ROW_NOISE_CORR_CONTROL, 0);
+	if (ret < 0)
+		return ret;
+
+	return v4l2_ctrl_handler_setup(&mt9v032->ctrls);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev video operations
+ */
+
+static struct v4l2_mbus_framefmt *
+__mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
+			 unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_format(fh, pad);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &mt9v032->format;
+	default:
+		return NULL;
+	}
+}
+
+static struct v4l2_rect *
+__mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
+		       unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_crop(fh, pad);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &mt9v032->crop;
+	default:
+		return NULL;
+	}
+}
+
+static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+	const u16 mode = MT9V032_CHIP_CONTROL_MASTER_MODE
+		       | MT9V032_CHIP_CONTROL_DOUT_ENABLE
+		       | MT9V032_CHIP_CONTROL_SEQUENTIAL;
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+	struct v4l2_mbus_framefmt *format = &mt9v032->format;
+	struct v4l2_rect *crop = &mt9v032->crop;
+	unsigned int hratio;
+	unsigned int vratio;
+	int ret;
+
+	if (!enable)
+		return mt9v032_set_chip_control(mt9v032, mode, 0);
+
+	/* Configure the window size and row/column bin */
+	hratio = DIV_ROUND_CLOSEST(crop->width, format->width);
+	vratio = DIV_ROUND_CLOSEST(crop->height, format->height);
+
+	ret = mt9v032_write(client, MT9V032_READ_MODE,
+		    (hratio - 1) << MT9V032_READ_MODE_ROW_BIN_SHIFT |
+		    (vratio - 1) << MT9V032_READ_MODE_COLUMN_BIN_SHIFT);
+	if (ret < 0)
+		return ret;
+
+	ret = mt9v032_write(client, MT9V032_COLUMN_START, crop->left);
+	if (ret < 0)
+		return ret;
+
+	ret = mt9v032_write(client, MT9V032_ROW_START, crop->top);
+	if (ret < 0)
+		return ret;
+
+	ret = mt9v032_write(client, MT9V032_WINDOW_WIDTH, crop->width);
+	if (ret < 0)
+		return ret;
+
+	ret = mt9v032_write(client, MT9V032_WINDOW_HEIGHT, crop->height);
+	if (ret < 0)
+		return ret;
+
+	ret = mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING,
+			    max(43, 660 - crop->width));
+	if (ret < 0)
+		return ret;
+
+	/* Switch to master "normal" mode */
+	return mt9v032_set_chip_control(mt9v032, 0, mode);
+}
+
+static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->index > 0)
+		return -EINVAL;
+
+	code->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+	return 0;
+}
+
+static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
+				   struct v4l2_subdev_fh *fh,
+				   struct v4l2_subdev_frame_size_enum *fse)
+{
+	if (fse->index >= 8 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10)
+		return -EINVAL;
+
+	fse->min_width = MT9V032_WINDOW_WIDTH_DEF / fse->index;
+	fse->max_width = fse->min_width;
+	fse->min_height = MT9V032_WINDOW_HEIGHT_DEF / fse->index;
+	fse->max_height = fse->min_height;
+
+	return 0;
+}
+
+static int mt9v032_get_format(struct v4l2_subdev *subdev,
+			      struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_format *format)
+{
+	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+
+	format->format = *__mt9v032_get_pad_format(mt9v032, fh, format->pad,
+						   format->which);
+	return 0;
+}
+
+static int mt9v032_set_format(struct v4l2_subdev *subdev,
+			      struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_format *format)
+{
+	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+	struct v4l2_mbus_framefmt *__format;
+	struct v4l2_rect *__crop;
+	unsigned int width;
+	unsigned int height;
+	unsigned int hratio;
+	unsigned int vratio;
+
+	__crop = __mt9v032_get_pad_crop(mt9v032, fh, format->pad,
+					format->which);
+
+	/* Clamp the width and height to avoid dividing by zero. */
+	width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
+			max(__crop->width / 8, MT9V032_WINDOW_WIDTH_MIN),
+			__crop->width);
+	height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
+			 max(__crop->height / 8, MT9V032_WINDOW_HEIGHT_MIN),
+			 __crop->height);
+
+	hratio = DIV_ROUND_CLOSEST(__crop->width, width);
+	vratio = DIV_ROUND_CLOSEST(__crop->height, height);
+
+	__format = __mt9v032_get_pad_format(mt9v032, fh, format->pad,
+					    format->which);
+	__format->width = __crop->width / hratio;
+	__format->height = __crop->height / vratio;
+
+	format->format = *__format;
+
+	return 0;
+}
+
+static int mt9v032_get_crop(struct v4l2_subdev *subdev,
+			    struct v4l2_subdev_fh *fh,
+			    struct v4l2_subdev_crop *crop)
+{
+	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+
+	crop->rect = *__mt9v032_get_pad_crop(mt9v032, fh, crop->pad,
+					     crop->which);
+	return 0;
+}
+
+static int mt9v032_set_crop(struct v4l2_subdev *subdev,
+			    struct v4l2_subdev_fh *fh,
+			    struct v4l2_subdev_crop *crop)
+{
+	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+	struct v4l2_mbus_framefmt *__format;
+	struct v4l2_rect *__crop;
+	struct v4l2_rect rect;
+
+	/* Clamp the crop rectangle boundaries and align them to a non multiple
+	 * of 2 pixels to ensure a GRBG Bayer pattern.
+	 */
+	rect.left = clamp(ALIGN(crop->rect.left + 1, 2) - 1,
+			  MT9V032_COLUMN_START_MIN,
+			  MT9V032_COLUMN_START_MAX);
+	rect.top = clamp(ALIGN(crop->rect.top + 1, 2) - 1,
+			 MT9V032_ROW_START_MIN,
+			 MT9V032_ROW_START_MAX);
+	rect.width = clamp(ALIGN(crop->rect.width, 2),
+			   MT9V032_WINDOW_WIDTH_MIN,
+			   MT9V032_WINDOW_WIDTH_MAX);
+	rect.height = clamp(ALIGN(crop->rect.height, 2),
+			    MT9V032_WINDOW_HEIGHT_MIN,
+			    MT9V032_WINDOW_HEIGHT_MAX);
+
+	rect.width = min(rect.width, MT9V032_PIXEL_ARRAY_WIDTH - rect.left);
+	rect.height = min(rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
+
+	__crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which);
+
+	if (rect.width != __crop->width || rect.height != __crop->height) {
+		/* Reset the output image size if the crop rectangle size has
+		 * been modified.
+		 */
+		__format = __mt9v032_get_pad_format(mt9v032, fh, crop->pad,
+						    crop->which);
+		__format->width = rect.width;
+		__format->height = rect.height;
+	}
+
+	*__crop = rect;
+	crop->rect = rect;
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev control operations
+ */
+
+#define V4L2_CID_TEST_PATTERN		(V4L2_CID_USER_BASE | 0x1001)
+
+static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mt9v032 *mt9v032 =
+			container_of(ctrl->handler, struct mt9v032, ctrls);
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+	u16 data;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTOGAIN:
+		return mt9v032_update_aec_agc(mt9v032, MT9V032_AGC_ENABLE,
+					      ctrl->val);
+
+	case V4L2_CID_GAIN:
+		return mt9v032_write(client, MT9V032_ANALOG_GAIN, ctrl->val);
+
+	case V4L2_CID_EXPOSURE_AUTO:
+		return mt9v032_update_aec_agc(mt9v032, MT9V032_AEC_ENABLE,
+					      !ctrl->val);
+
+	case V4L2_CID_EXPOSURE:
+		return mt9v032_write(client, MT9V032_TOTAL_SHUTTER_WIDTH,
+				     ctrl->val);
+
+	case V4L2_CID_TEST_PATTERN:
+		switch (ctrl->val) {
+		case 0:
+			data = 0;
+			break;
+		case 1:
+			data = MT9V032_TEST_PATTERN_GRAY_VERTICAL
+			     | MT9V032_TEST_PATTERN_ENABLE;
+			break;
+		case 2:
+			data = MT9V032_TEST_PATTERN_GRAY_HORIZONTAL
+			     | MT9V032_TEST_PATTERN_ENABLE;
+			break;
+		case 3:
+			data = MT9V032_TEST_PATTERN_GRAY_DIAGONAL
+			     | MT9V032_TEST_PATTERN_ENABLE;
+			break;
+		default:
+			data = (ctrl->val << MT9V032_TEST_PATTERN_DATA_SHIFT)
+			     | MT9V032_TEST_PATTERN_USE_DATA
+			     | MT9V032_TEST_PATTERN_ENABLE
+			     | MT9V032_TEST_PATTERN_FLIP;
+			break;
+		}
+
+		return mt9v032_write(client, MT9V032_TEST_PATTERN, data);
+	}
+
+	return 0;
+}
+
+static struct v4l2_ctrl_ops mt9v032_ctrl_ops = {
+	.s_ctrl = mt9v032_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config mt9v032_ctrls[] = {
+	{
+		.ops		= &mt9v032_ctrl_ops,
+		.id		= V4L2_CID_TEST_PATTERN,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Test pattern",
+		.min		= 0,
+		.max		= 1023,
+		.step		= 1,
+		.def		= 0,
+		.flags		= 0,
+	}
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+static int mt9v032_set_power(struct v4l2_subdev *subdev, int on)
+{
+	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+	int ret = 0;
+
+	mutex_lock(&mt9v032->power_lock);
+
+	/* If the power count is modified from 0 to != 0 or from != 0 to 0,
+	 * update the power state.
+	 */
+	if (mt9v032->power_count == !on) {
+		ret = __mt9v032_set_power(mt9v032, !!on);
+		if (ret < 0)
+			goto done;
+	}
+
+	/* Update the power count. */
+	mt9v032->power_count += on ? 1 : -1;
+	WARN_ON(mt9v032->power_count < 0);
+
+done:
+	mutex_unlock(&mt9v032->power_lock);
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev internal operations
+ */
+
+static int mt9v032_registered(struct v4l2_subdev *subdev)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+	s32 data;
+	int ret;
+
+	dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n",
+			client->addr);
+
+	ret = mt9v032_power_on(mt9v032);
+	if (ret < 0) {
+		dev_err(&client->dev, "MT9V032 power up failed\n");
+		return ret;
+	}
+
+	/* Read and check the sensor version */
+	data = mt9v032_read(client, MT9V032_CHIP_VERSION);
+	if (data != MT9V032_CHIP_ID_REV1 && data != MT9V032_CHIP_ID_REV3) {
+		dev_err(&client->dev, "MT9V032 not detected, wrong version "
+				"0x%04x\n", data);
+		return -ENODEV;
+	}
+
+	mt9v032_power_off(mt9v032);
+
+	dev_info(&client->dev, "MT9V032 detected at address 0x%02x\n",
+			client->addr);
+
+	return ret;
+}
+
+static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+	struct v4l2_mbus_framefmt *format;
+	struct v4l2_rect *crop;
+
+	crop = v4l2_subdev_get_try_crop(fh, 0);
+	crop->left = MT9V032_COLUMN_START_DEF;
+	crop->top = MT9V032_ROW_START_DEF;
+	crop->width = MT9V032_WINDOW_WIDTH_DEF;
+	crop->height = MT9V032_WINDOW_HEIGHT_DEF;
+
+	format = v4l2_subdev_get_try_format(fh, 0);
+	format->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+	format->width = MT9V032_WINDOW_WIDTH_DEF;
+	format->height = MT9V032_WINDOW_HEIGHT_DEF;
+	format->field = V4L2_FIELD_NONE;
+	format->colorspace = V4L2_COLORSPACE_SRGB;
+
+	return mt9v032_set_power(subdev, 1);
+}
+
+static int mt9v032_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+	return mt9v032_set_power(subdev, 0);
+}
+
+static struct v4l2_subdev_core_ops mt9v032_subdev_core_ops = {
+	.s_power	= mt9v032_set_power,
+};
+
+static struct v4l2_subdev_video_ops mt9v032_subdev_video_ops = {
+	.s_stream	= mt9v032_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops mt9v032_subdev_pad_ops = {
+	.enum_mbus_code = mt9v032_enum_mbus_code,
+	.enum_frame_size = mt9v032_enum_frame_size,
+	.get_fmt = mt9v032_get_format,
+	.set_fmt = mt9v032_set_format,
+	.get_crop = mt9v032_get_crop,
+	.set_crop = mt9v032_set_crop,
+};
+
+static struct v4l2_subdev_ops mt9v032_subdev_ops = {
+	.core	= &mt9v032_subdev_core_ops,
+	.video	= &mt9v032_subdev_video_ops,
+	.pad	= &mt9v032_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops mt9v032_subdev_internal_ops = {
+	.registered = mt9v032_registered,
+	.open = mt9v032_open,
+	.close = mt9v032_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * Driver initialization and probing
+ */
+
+static int mt9v032_probe(struct i2c_client *client,
+		const struct i2c_device_id *did)
+{
+	struct mt9v032 *mt9v032;
+	unsigned int i;
+	int ret;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_warn(&client->adapter->dev,
+			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+		return -EIO;
+	}
+
+	mt9v032 = kzalloc(sizeof(*mt9v032), GFP_KERNEL);
+	if (!mt9v032)
+		return -ENOMEM;
+
+	mutex_init(&mt9v032->power_lock);
+	mt9v032->pdata = client->dev.platform_data;
+
+	v4l2_ctrl_handler_init(&mt9v032->ctrls, ARRAY_SIZE(mt9v032_ctrls) + 4);
+
+	v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+			  V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+	v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+			  V4L2_CID_GAIN, MT9V032_ANALOG_GAIN_MIN,
+			  MT9V032_ANALOG_GAIN_MAX, 1, MT9V032_ANALOG_GAIN_DEF);
+	v4l2_ctrl_new_std_menu(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+			       V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0,
+			       V4L2_EXPOSURE_AUTO);
+	v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+			  V4L2_CID_EXPOSURE, MT9V032_TOTAL_SHUTTER_WIDTH_MIN,
+			  MT9V032_TOTAL_SHUTTER_WIDTH_MAX, 1,
+			  MT9V032_TOTAL_SHUTTER_WIDTH_DEF);
+
+	for (i = 0; i < ARRAY_SIZE(mt9v032_ctrls); ++i)
+		v4l2_ctrl_new_custom(&mt9v032->ctrls, &mt9v032_ctrls[i], NULL);
+
+	mt9v032->subdev.ctrl_handler = &mt9v032->ctrls;
+
+	if (mt9v032->ctrls.error)
+		printk(KERN_INFO "%s: control initialization error %d\n",
+		       __func__, mt9v032->ctrls.error);
+
+	mt9v032->crop.left = MT9V032_COLUMN_START_DEF;
+	mt9v032->crop.top = MT9V032_ROW_START_DEF;
+	mt9v032->crop.width = MT9V032_WINDOW_WIDTH_DEF;
+	mt9v032->crop.height = MT9V032_WINDOW_HEIGHT_DEF;
+
+	mt9v032->format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+	mt9v032->format.width = MT9V032_WINDOW_WIDTH_DEF;
+	mt9v032->format.height = MT9V032_WINDOW_HEIGHT_DEF;
+	mt9v032->format.field = V4L2_FIELD_NONE;
+	mt9v032->format.colorspace = V4L2_COLORSPACE_SRGB;
+
+	mt9v032->aec_agc = MT9V032_AEC_ENABLE | MT9V032_AGC_ENABLE;
+
+	v4l2_i2c_subdev_init(&mt9v032->subdev, client, &mt9v032_subdev_ops);
+	mt9v032->subdev.internal_ops = &mt9v032_subdev_internal_ops;
+	mt9v032->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	mt9v032->pad.flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_init(&mt9v032->subdev.entity, 1, &mt9v032->pad, 0);
+	if (ret < 0)
+		kfree(mt9v032);
+
+	return ret;
+}
+
+static int mt9v032_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+
+	v4l2_device_unregister_subdev(subdev);
+	media_entity_cleanup(&subdev->entity);
+	kfree(mt9v032);
+	return 0;
+}
+
+static const struct i2c_device_id mt9v032_id[] = {
+	{ "mt9v032", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mt9v032_id);
+
+static struct i2c_driver mt9v032_driver = {
+	.driver = {
+		.name = "mt9v032",
+	},
+	.probe		= mt9v032_probe,
+	.remove		= mt9v032_remove,
+	.id_table	= mt9v032_id,
+};
+
+module_i2c_driver(mt9v032_driver);
+
+MODULE_DESCRIPTION("Aptina MT9V032 Camera driver");
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/noon010pc30.c b/drivers/media/i2c/noon010pc30.c
new file mode 100644
index 0000000..440c129
--- /dev/null
+++ b/drivers/media/i2c/noon010pc30.c
@@ -0,0 +1,851 @@
+/*
+ * Driver for SiliconFile NOON010PC30 CIF (1/11") Image Sensor with ISP
+ *
+ * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd.
+ * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * Initial register configuration based on a driver authored by
+ * HeungJun Kim <riverful.kim@samsung.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <media/noon010pc30.h>
+#include <media/v4l2-chip-ident.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable module debug trace. Set to 1 to enable.");
+
+#define MODULE_NAME		"NOON010PC30"
+
+/*
+ * Register offsets within a page
+ * b15..b8 - page id, b7..b0 - register address
+ */
+#define POWER_CTRL_REG		0x0001
+#define PAGEMODE_REG		0x03
+#define DEVICE_ID_REG		0x0004
+#define NOON010PC30_ID		0x86
+#define VDO_CTL_REG(n)		(0x0010 + (n))
+#define SYNC_CTL_REG		0x0012
+/* Window size and position */
+#define WIN_ROWH_REG		0x0013
+#define WIN_ROWL_REG		0x0014
+#define WIN_COLH_REG		0x0015
+#define WIN_COLL_REG		0x0016
+#define WIN_HEIGHTH_REG		0x0017
+#define WIN_HEIGHTL_REG		0x0018
+#define WIN_WIDTHH_REG		0x0019
+#define WIN_WIDTHL_REG		0x001A
+#define HBLANKH_REG		0x001B
+#define HBLANKL_REG		0x001C
+#define VSYNCH_REG		0x001D
+#define VSYNCL_REG		0x001E
+/* VSYNC control */
+#define VS_CTL_REG(n)		(0x00A1 + (n))
+/* page 1 */
+#define ISP_CTL_REG(n)		(0x0110 + (n))
+#define YOFS_REG		0x0119
+#define DARK_YOFS_REG		0x011A
+#define SAT_CTL_REG		0x0120
+#define BSAT_REG		0x0121
+#define RSAT_REG		0x0122
+/* Color correction */
+#define CMC_CTL_REG		0x0130
+#define CMC_OFSGH_REG		0x0133
+#define CMC_OFSGL_REG		0x0135
+#define CMC_SIGN_REG		0x0136
+#define CMC_GOFS_REG		0x0137
+#define CMC_COEF_REG(n)		(0x0138 + (n))
+#define CMC_OFS_REG(n)		(0x0141 + (n))
+/* Gamma correction */
+#define GMA_CTL_REG		0x0160
+#define GMA_COEF_REG(n)		(0x0161 + (n))
+/* Lens Shading */
+#define LENS_CTRL_REG		0x01D0
+#define LENS_XCEN_REG		0x01D1
+#define LENS_YCEN_REG		0x01D2
+#define LENS_RC_REG		0x01D3
+#define LENS_GC_REG		0x01D4
+#define LENS_BC_REG		0x01D5
+#define L_AGON_REG		0x01D6
+#define L_AGOFF_REG		0x01D7
+/* Page 3 - Auto Exposure */
+#define AE_CTL_REG(n)		(0x0310 + (n))
+#define AE_CTL9_REG		0x032C
+#define AE_CTL10_REG		0x032D
+#define AE_YLVL_REG		0x031C
+#define AE_YTH_REG(n)		(0x031D + (n))
+#define AE_WGT_REG		0x0326
+#define EXP_TIMEH_REG		0x0333
+#define EXP_TIMEM_REG		0x0334
+#define EXP_TIMEL_REG		0x0335
+#define EXP_MMINH_REG		0x0336
+#define EXP_MMINL_REG		0x0337
+#define EXP_MMAXH_REG		0x0338
+#define EXP_MMAXM_REG		0x0339
+#define EXP_MMAXL_REG		0x033A
+/* Page 4 - Auto White Balance */
+#define AWB_CTL_REG(n)		(0x0410 + (n))
+#define AWB_ENABE		0x80
+#define AWB_WGHT_REG		0x0419
+#define BGAIN_PAR_REG(n)	(0x044F + (n))
+/* Manual white balance, when AWB_CTL2[0]=1 */
+#define MWB_RGAIN_REG		0x0466
+#define MWB_BGAIN_REG		0x0467
+
+/* The token to mark an array end */
+#define REG_TERM		0xFFFF
+
+struct noon010_format {
+	enum v4l2_mbus_pixelcode code;
+	enum v4l2_colorspace colorspace;
+	u16 ispctl1_reg;
+};
+
+struct noon010_frmsize {
+	u16 width;
+	u16 height;
+	int vid_ctl1;
+};
+
+static const char * const noon010_supply_name[] = {
+	"vdd_core", "vddio", "vdda"
+};
+
+#define NOON010_NUM_SUPPLIES ARRAY_SIZE(noon010_supply_name)
+
+struct noon010_info {
+	struct v4l2_subdev sd;
+	struct media_pad pad;
+	struct v4l2_ctrl_handler hdl;
+	struct regulator_bulk_data supply[NOON010_NUM_SUPPLIES];
+	u32 gpio_nreset;
+	u32 gpio_nstby;
+
+	/* Protects the struct members below */
+	struct mutex lock;
+
+	const struct noon010_format *curr_fmt;
+	const struct noon010_frmsize *curr_win;
+	unsigned int apply_new_cfg:1;
+	unsigned int streaming:1;
+	unsigned int hflip:1;
+	unsigned int vflip:1;
+	unsigned int power:1;
+	u8 i2c_reg_page;
+};
+
+struct i2c_regval {
+	u16 addr;
+	u16 val;
+};
+
+/* Supported resolutions. */
+static const struct noon010_frmsize noon010_sizes[] = {
+	{
+		.width		= 352,
+		.height		= 288,
+		.vid_ctl1	= 0,
+	}, {
+		.width		= 176,
+		.height		= 144,
+		.vid_ctl1	= 0x10,
+	}, {
+		.width		= 88,
+		.height		= 72,
+		.vid_ctl1	= 0x20,
+	},
+};
+
+/* Supported pixel formats. */
+static const struct noon010_format noon010_formats[] = {
+	{
+		.code		= V4L2_MBUS_FMT_YUYV8_2X8,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.ispctl1_reg	= 0x03,
+	}, {
+		.code		= V4L2_MBUS_FMT_YVYU8_2X8,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.ispctl1_reg	= 0x02,
+	}, {
+		.code		= V4L2_MBUS_FMT_VYUY8_2X8,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.ispctl1_reg	= 0,
+	}, {
+		.code		= V4L2_MBUS_FMT_UYVY8_2X8,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.ispctl1_reg	= 0x01,
+	}, {
+		.code		= V4L2_MBUS_FMT_RGB565_2X8_BE,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.ispctl1_reg	= 0x40,
+	},
+};
+
+static const struct i2c_regval noon010_base_regs[] = {
+	{ WIN_COLL_REG,		0x06 },	{ HBLANKL_REG,		0x7C },
+	/* Color corection and saturation */
+	{ ISP_CTL_REG(0),	0x30 }, { ISP_CTL_REG(2),	0x30 },
+	{ YOFS_REG,		0x80 }, { DARK_YOFS_REG,	0x04 },
+	{ SAT_CTL_REG,		0x1F }, { BSAT_REG,		0x90 },
+	{ CMC_CTL_REG,		0x0F }, { CMC_OFSGH_REG,	0x3C },
+	{ CMC_OFSGL_REG,	0x2C }, { CMC_SIGN_REG,		0x3F },
+	{ CMC_COEF_REG(0),	0x79 }, { CMC_OFS_REG(0),	0x00 },
+	{ CMC_COEF_REG(1),	0x39 }, { CMC_OFS_REG(1),	0x00 },
+	{ CMC_COEF_REG(2),	0x00 }, { CMC_OFS_REG(2),	0x00 },
+	{ CMC_COEF_REG(3),	0x11 }, { CMC_OFS_REG(3),	0x8B },
+	{ CMC_COEF_REG(4),	0x65 }, { CMC_OFS_REG(4),	0x07 },
+	{ CMC_COEF_REG(5),	0x14 }, { CMC_OFS_REG(5),	0x04 },
+	{ CMC_COEF_REG(6),	0x01 }, { CMC_OFS_REG(6),	0x9C },
+	{ CMC_COEF_REG(7),	0x33 }, { CMC_OFS_REG(7),	0x89 },
+	{ CMC_COEF_REG(8),	0x74 }, { CMC_OFS_REG(8),	0x25 },
+	/* Automatic white balance */
+	{ AWB_CTL_REG(0),	0x78 }, { AWB_CTL_REG(1),	0x2E },
+	{ AWB_CTL_REG(2),	0x20 }, { AWB_CTL_REG(3),	0x85 },
+	/* Auto exposure */
+	{ AE_CTL_REG(0),	0xDC }, { AE_CTL_REG(1),	0x81 },
+	{ AE_CTL_REG(2),	0x30 }, { AE_CTL_REG(3),	0xA5 },
+	{ AE_CTL_REG(4),	0x40 }, { AE_CTL_REG(5),	0x51 },
+	{ AE_CTL_REG(6),	0x33 }, { AE_CTL_REG(7),	0x7E },
+	{ AE_CTL9_REG,		0x00 }, { AE_CTL10_REG,		0x02 },
+	{ AE_YLVL_REG,		0x44 },	{ AE_YTH_REG(0),	0x34 },
+	{ AE_YTH_REG(1),	0x30 },	{ AE_WGT_REG,		0xD5 },
+	/* Lens shading compensation */
+	{ LENS_CTRL_REG,	0x01 }, { LENS_XCEN_REG,	0x80 },
+	{ LENS_YCEN_REG,	0x70 }, { LENS_RC_REG,		0x53 },
+	{ LENS_GC_REG,		0x40 }, { LENS_BC_REG,		0x3E },
+	{ REG_TERM,		0 },
+};
+
+static inline struct noon010_info *to_noon010(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct noon010_info, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct noon010_info, hdl)->sd;
+}
+
+static inline int set_i2c_page(struct noon010_info *info,
+			       struct i2c_client *client, unsigned int reg)
+{
+	u32 page = reg >> 8 & 0xFF;
+	int ret = 0;
+
+	if (info->i2c_reg_page != page && (reg & 0xFF) != 0x03) {
+		ret = i2c_smbus_write_byte_data(client, PAGEMODE_REG, page);
+		if (!ret)
+			info->i2c_reg_page = page;
+	}
+	return ret;
+}
+
+static int cam_i2c_read(struct v4l2_subdev *sd, u32 reg_addr)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct noon010_info *info = to_noon010(sd);
+	int ret = set_i2c_page(info, client, reg_addr);
+
+	if (ret)
+		return ret;
+	return i2c_smbus_read_byte_data(client, reg_addr & 0xFF);
+}
+
+static int cam_i2c_write(struct v4l2_subdev *sd, u32 reg_addr, u32 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct noon010_info *info = to_noon010(sd);
+	int ret = set_i2c_page(info, client, reg_addr);
+
+	if (ret)
+		return ret;
+	return i2c_smbus_write_byte_data(client, reg_addr & 0xFF, val);
+}
+
+static inline int noon010_bulk_write_reg(struct v4l2_subdev *sd,
+					 const struct i2c_regval *msg)
+{
+	while (msg->addr != REG_TERM) {
+		int ret = cam_i2c_write(sd, msg->addr, msg->val);
+
+		if (ret)
+			return ret;
+		msg++;
+	}
+	return 0;
+}
+
+/* Device reset and sleep mode control */
+static int noon010_power_ctrl(struct v4l2_subdev *sd, bool reset, bool sleep)
+{
+	struct noon010_info *info = to_noon010(sd);
+	u8 reg = sleep ? 0xF1 : 0xF0;
+	int ret = 0;
+
+	if (reset) {
+		ret = cam_i2c_write(sd, POWER_CTRL_REG, reg | 0x02);
+		udelay(20);
+	}
+	if (!ret) {
+		ret = cam_i2c_write(sd, POWER_CTRL_REG, reg);
+		if (reset && !ret)
+			info->i2c_reg_page = -1;
+	}
+	return ret;
+}
+
+/* Automatic white balance control */
+static int noon010_enable_autowhitebalance(struct v4l2_subdev *sd, int on)
+{
+	int ret;
+
+	ret = cam_i2c_write(sd, AWB_CTL_REG(1), on ? 0x2E : 0x2F);
+	if (!ret)
+		ret = cam_i2c_write(sd, AWB_CTL_REG(0), on ? 0xFB : 0x7B);
+	return ret;
+}
+
+/* Called with struct noon010_info.lock mutex held */
+static int noon010_set_flip(struct v4l2_subdev *sd, int hflip, int vflip)
+{
+	struct noon010_info *info = to_noon010(sd);
+	int reg, ret;
+
+	reg = cam_i2c_read(sd, VDO_CTL_REG(1));
+	if (reg < 0)
+		return reg;
+
+	reg &= 0x7C;
+	if (hflip)
+		reg |= 0x01;
+	if (vflip)
+		reg |= 0x02;
+
+	ret = cam_i2c_write(sd, VDO_CTL_REG(1), reg | 0x80);
+	if (!ret) {
+		info->hflip = hflip;
+		info->vflip = vflip;
+	}
+	return ret;
+}
+
+/* Configure resolution and color format */
+static int noon010_set_params(struct v4l2_subdev *sd)
+{
+	struct noon010_info *info = to_noon010(sd);
+
+	int ret = cam_i2c_write(sd, VDO_CTL_REG(0),
+				info->curr_win->vid_ctl1);
+	if (ret)
+		return ret;
+	return cam_i2c_write(sd, ISP_CTL_REG(0),
+			     info->curr_fmt->ispctl1_reg);
+}
+
+/* Find nearest matching image pixel size. */
+static int noon010_try_frame_size(struct v4l2_mbus_framefmt *mf,
+				  const struct noon010_frmsize **size)
+{
+	unsigned int min_err = ~0;
+	int i = ARRAY_SIZE(noon010_sizes);
+	const struct noon010_frmsize *fsize = &noon010_sizes[0],
+		*match = NULL;
+
+	while (i--) {
+		int err = abs(fsize->width - mf->width)
+				+ abs(fsize->height - mf->height);
+
+		if (err < min_err) {
+			min_err = err;
+			match = fsize;
+		}
+		fsize++;
+	}
+	if (match) {
+		mf->width  = match->width;
+		mf->height = match->height;
+		if (size)
+			*size = match;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+/* Called with info.lock mutex held */
+static int power_enable(struct noon010_info *info)
+{
+	int ret;
+
+	if (info->power) {
+		v4l2_info(&info->sd, "%s: sensor is already on\n", __func__);
+		return 0;
+	}
+
+	if (gpio_is_valid(info->gpio_nstby))
+		gpio_set_value(info->gpio_nstby, 0);
+
+	if (gpio_is_valid(info->gpio_nreset))
+		gpio_set_value(info->gpio_nreset, 0);
+
+	ret = regulator_bulk_enable(NOON010_NUM_SUPPLIES, info->supply);
+	if (ret)
+		return ret;
+
+	if (gpio_is_valid(info->gpio_nreset)) {
+		msleep(50);
+		gpio_set_value(info->gpio_nreset, 1);
+	}
+	if (gpio_is_valid(info->gpio_nstby)) {
+		udelay(1000);
+		gpio_set_value(info->gpio_nstby, 1);
+	}
+	if (gpio_is_valid(info->gpio_nreset)) {
+		udelay(1000);
+		gpio_set_value(info->gpio_nreset, 0);
+		msleep(100);
+		gpio_set_value(info->gpio_nreset, 1);
+		msleep(20);
+	}
+	info->power = 1;
+
+	v4l2_dbg(1, debug, &info->sd,  "%s: sensor is on\n", __func__);
+	return 0;
+}
+
+/* Called with info.lock mutex held */
+static int power_disable(struct noon010_info *info)
+{
+	int ret;
+
+	if (!info->power) {
+		v4l2_info(&info->sd, "%s: sensor is already off\n", __func__);
+		return 0;
+	}
+
+	ret = regulator_bulk_disable(NOON010_NUM_SUPPLIES, info->supply);
+	if (ret)
+		return ret;
+
+	if (gpio_is_valid(info->gpio_nstby))
+		gpio_set_value(info->gpio_nstby, 0);
+
+	if (gpio_is_valid(info->gpio_nreset))
+		gpio_set_value(info->gpio_nreset, 0);
+
+	info->power = 0;
+
+	v4l2_dbg(1, debug, &info->sd,  "%s: sensor is off\n", __func__);
+
+	return 0;
+}
+
+static int noon010_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct noon010_info *info = to_noon010(sd);
+	int ret = 0;
+
+	v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n",
+		 __func__, ctrl->id, ctrl->val);
+
+	mutex_lock(&info->lock);
+	/*
+	 * If the device is not powered up by the host driver do
+	 * not apply any controls to H/W at this time. Instead
+	 * the controls will be restored right after power-up.
+	 */
+	if (!info->power)
+		goto unlock;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		ret = noon010_enable_autowhitebalance(sd, ctrl->val);
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		ret = cam_i2c_write(sd, MWB_BGAIN_REG, ctrl->val);
+		break;
+	case V4L2_CID_RED_BALANCE:
+		ret =  cam_i2c_write(sd, MWB_RGAIN_REG, ctrl->val);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+unlock:
+	mutex_unlock(&info->lock);
+	return ret;
+}
+
+static int noon010_enum_mbus_code(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->index >= ARRAY_SIZE(noon010_formats))
+		return -EINVAL;
+
+	code->code = noon010_formats[code->index].code;
+	return 0;
+}
+
+static int noon010_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			   struct v4l2_subdev_format *fmt)
+{
+	struct noon010_info *info = to_noon010(sd);
+	struct v4l2_mbus_framefmt *mf;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		if (fh) {
+			mf = v4l2_subdev_get_try_format(fh, 0);
+			fmt->format = *mf;
+		}
+		return 0;
+	}
+	mf = &fmt->format;
+
+	mutex_lock(&info->lock);
+	mf->width = info->curr_win->width;
+	mf->height = info->curr_win->height;
+	mf->code = info->curr_fmt->code;
+	mf->colorspace = info->curr_fmt->colorspace;
+	mf->field = V4L2_FIELD_NONE;
+
+	mutex_unlock(&info->lock);
+	return 0;
+}
+
+/* Return nearest media bus frame format. */
+static const struct noon010_format *noon010_try_fmt(struct v4l2_subdev *sd,
+					    struct v4l2_mbus_framefmt *mf)
+{
+	int i = ARRAY_SIZE(noon010_formats);
+
+	while (--i)
+		if (mf->code == noon010_formats[i].code)
+			break;
+	mf->code = noon010_formats[i].code;
+
+	return &noon010_formats[i];
+}
+
+static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			   struct v4l2_subdev_format *fmt)
+{
+	struct noon010_info *info = to_noon010(sd);
+	const struct noon010_frmsize *size = NULL;
+	const struct noon010_format *nf;
+	struct v4l2_mbus_framefmt *mf;
+	int ret = 0;
+
+	nf = noon010_try_fmt(sd, &fmt->format);
+	noon010_try_frame_size(&fmt->format, &size);
+	fmt->format.colorspace = V4L2_COLORSPACE_JPEG;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		if (fh) {
+			mf = v4l2_subdev_get_try_format(fh, 0);
+			*mf = fmt->format;
+		}
+		return 0;
+	}
+	mutex_lock(&info->lock);
+	if (!info->streaming) {
+		info->apply_new_cfg = 1;
+		info->curr_fmt = nf;
+		info->curr_win = size;
+	} else {
+		ret = -EBUSY;
+	}
+	mutex_unlock(&info->lock);
+	return ret;
+}
+
+/* Called with struct noon010_info.lock mutex held */
+static int noon010_base_config(struct v4l2_subdev *sd)
+{
+	int ret = noon010_bulk_write_reg(sd, noon010_base_regs);
+	if (!ret)
+		ret = noon010_set_params(sd);
+	if (!ret)
+		ret = noon010_set_flip(sd, 1, 0);
+
+	return ret;
+}
+
+static int noon010_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct noon010_info *info = to_noon010(sd);
+	int ret;
+
+	mutex_lock(&info->lock);
+	if (on) {
+		ret = power_enable(info);
+		if (!ret)
+			ret = noon010_base_config(sd);
+	} else {
+		noon010_power_ctrl(sd, false, true);
+		ret = power_disable(info);
+	}
+	mutex_unlock(&info->lock);
+
+	/* Restore the controls state */
+	if (!ret && on)
+		ret = v4l2_ctrl_handler_setup(&info->hdl);
+
+	return ret;
+}
+
+static int noon010_s_stream(struct v4l2_subdev *sd, int on)
+{
+	struct noon010_info *info = to_noon010(sd);
+	int ret = 0;
+
+	mutex_lock(&info->lock);
+	if (!info->streaming != !on) {
+		ret = noon010_power_ctrl(sd, false, !on);
+		if (!ret)
+			info->streaming = on;
+	}
+	if (!ret && on && info->apply_new_cfg) {
+		ret = noon010_set_params(sd);
+		if (!ret)
+			info->apply_new_cfg = 0;
+	}
+	mutex_unlock(&info->lock);
+	return ret;
+}
+
+static int noon010_log_status(struct v4l2_subdev *sd)
+{
+	struct noon010_info *info = to_noon010(sd);
+
+	v4l2_ctrl_handler_log_status(&info->hdl, sd->name);
+	return 0;
+}
+
+static int noon010_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(fh, 0);
+
+	mf->width = noon010_sizes[0].width;
+	mf->height = noon010_sizes[0].height;
+	mf->code = noon010_formats[0].code;
+	mf->colorspace = V4L2_COLORSPACE_JPEG;
+	mf->field = V4L2_FIELD_NONE;
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops noon010_subdev_internal_ops = {
+	.open = noon010_open,
+};
+
+static const struct v4l2_ctrl_ops noon010_ctrl_ops = {
+	.s_ctrl = noon010_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops noon010_core_ops = {
+	.s_power	= noon010_s_power,
+	.g_ctrl		= v4l2_subdev_g_ctrl,
+	.s_ctrl		= v4l2_subdev_s_ctrl,
+	.queryctrl	= v4l2_subdev_queryctrl,
+	.querymenu	= v4l2_subdev_querymenu,
+	.g_ext_ctrls	= v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls	= v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls	= v4l2_subdev_s_ext_ctrls,
+	.log_status	= noon010_log_status,
+};
+
+static struct v4l2_subdev_pad_ops noon010_pad_ops = {
+	.enum_mbus_code	= noon010_enum_mbus_code,
+	.get_fmt	= noon010_get_fmt,
+	.set_fmt	= noon010_set_fmt,
+};
+
+static struct v4l2_subdev_video_ops noon010_video_ops = {
+	.s_stream	= noon010_s_stream,
+};
+
+static const struct v4l2_subdev_ops noon010_ops = {
+	.core	= &noon010_core_ops,
+	.pad	= &noon010_pad_ops,
+	.video	= &noon010_video_ops,
+};
+
+/* Return 0 if NOON010PC30L sensor type was detected or -ENODEV otherwise. */
+static int noon010_detect(struct i2c_client *client, struct noon010_info *info)
+{
+	int ret;
+
+	ret = power_enable(info);
+	if (ret)
+		return ret;
+
+	ret = i2c_smbus_read_byte_data(client, DEVICE_ID_REG);
+	if (ret < 0)
+		dev_err(&client->dev, "I2C read failed: 0x%X\n", ret);
+
+	power_disable(info);
+
+	return ret == NOON010PC30_ID ? 0 : -ENODEV;
+}
+
+static int noon010_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct noon010_info *info;
+	struct v4l2_subdev *sd;
+	const struct noon010pc30_platform_data *pdata
+		= client->dev.platform_data;
+	int ret;
+	int i;
+
+	if (!pdata) {
+		dev_err(&client->dev, "No platform data!\n");
+		return -EIO;
+	}
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	mutex_init(&info->lock);
+	sd = &info->sd;
+	v4l2_i2c_subdev_init(sd, client, &noon010_ops);
+	strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
+
+	sd->internal_ops = &noon010_subdev_internal_ops;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	v4l2_ctrl_handler_init(&info->hdl, 3);
+
+	v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops,
+			  V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
+	v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops,
+			  V4L2_CID_RED_BALANCE, 0, 127, 1, 64);
+	v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops,
+			  V4L2_CID_BLUE_BALANCE, 0, 127, 1, 64);
+
+	sd->ctrl_handler = &info->hdl;
+
+	ret = info->hdl.error;
+	if (ret)
+		goto np_err;
+
+	info->i2c_reg_page	= -1;
+	info->gpio_nreset	= -EINVAL;
+	info->gpio_nstby	= -EINVAL;
+	info->curr_fmt		= &noon010_formats[0];
+	info->curr_win		= &noon010_sizes[0];
+
+	if (gpio_is_valid(pdata->gpio_nreset)) {
+		ret = gpio_request(pdata->gpio_nreset, "NOON010PC30 NRST");
+		if (ret) {
+			dev_err(&client->dev, "GPIO request error: %d\n", ret);
+			goto np_err;
+		}
+		info->gpio_nreset = pdata->gpio_nreset;
+		gpio_direction_output(info->gpio_nreset, 0);
+		gpio_export(info->gpio_nreset, 0);
+	}
+
+	if (gpio_is_valid(pdata->gpio_nstby)) {
+		ret = gpio_request(pdata->gpio_nstby, "NOON010PC30 NSTBY");
+		if (ret) {
+			dev_err(&client->dev, "GPIO request error: %d\n", ret);
+			goto np_gpio_err;
+		}
+		info->gpio_nstby = pdata->gpio_nstby;
+		gpio_direction_output(info->gpio_nstby, 0);
+		gpio_export(info->gpio_nstby, 0);
+	}
+
+	for (i = 0; i < NOON010_NUM_SUPPLIES; i++)
+		info->supply[i].supply = noon010_supply_name[i];
+
+	ret = regulator_bulk_get(&client->dev, NOON010_NUM_SUPPLIES,
+				 info->supply);
+	if (ret)
+		goto np_reg_err;
+
+	info->pad.flags = MEDIA_PAD_FL_SOURCE;
+	sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+	ret = media_entity_init(&sd->entity, 1, &info->pad, 0);
+	if (ret < 0)
+		goto np_me_err;
+
+	ret = noon010_detect(client, info);
+	if (!ret)
+		return 0;
+
+np_me_err:
+	regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply);
+np_reg_err:
+	if (gpio_is_valid(info->gpio_nstby))
+		gpio_free(info->gpio_nstby);
+np_gpio_err:
+	if (gpio_is_valid(info->gpio_nreset))
+		gpio_free(info->gpio_nreset);
+np_err:
+	v4l2_ctrl_handler_free(&info->hdl);
+	v4l2_device_unregister_subdev(sd);
+	kfree(info);
+	return ret;
+}
+
+static int noon010_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct noon010_info *info = to_noon010(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&info->hdl);
+
+	regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply);
+
+	if (gpio_is_valid(info->gpio_nreset))
+		gpio_free(info->gpio_nreset);
+
+	if (gpio_is_valid(info->gpio_nstby))
+		gpio_free(info->gpio_nstby);
+
+	media_entity_cleanup(&sd->entity);
+	kfree(info);
+	return 0;
+}
+
+static const struct i2c_device_id noon010_id[] = {
+	{ MODULE_NAME, 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, noon010_id);
+
+
+static struct i2c_driver noon010_i2c_driver = {
+	.driver = {
+		.name = MODULE_NAME
+	},
+	.probe		= noon010_probe,
+	.remove		= noon010_remove,
+	.id_table	= noon010_id,
+};
+
+module_i2c_driver(noon010_i2c_driver);
+
+MODULE_DESCRIPTION("Siliconfile NOON010PC30 camera driver");
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
new file mode 100644
index 0000000..e7c82b2
--- /dev/null
+++ b/drivers/media/i2c/ov7670.c
@@ -0,0 +1,1586 @@
+/*
+ * A V4L2 driver for OmniVision OV7670 cameras.
+ *
+ * Copyright 2006 One Laptop Per Child Association, Inc.  Written
+ * by Jonathan Corbet with substantial inspiration from Mark
+ * McClelland's ovcamchip code.
+ *
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-mediabus.h>
+#include <media/ov7670.h>
+
+MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
+MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
+MODULE_LICENSE("GPL");
+
+static bool debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/*
+ * Basic window sizes.  These probably belong somewhere more globally
+ * useful.
+ */
+#define VGA_WIDTH	640
+#define VGA_HEIGHT	480
+#define QVGA_WIDTH	320
+#define QVGA_HEIGHT	240
+#define CIF_WIDTH	352
+#define CIF_HEIGHT	288
+#define QCIF_WIDTH	176
+#define	QCIF_HEIGHT	144
+
+/*
+ * The 7670 sits on i2c with ID 0x42
+ */
+#define OV7670_I2C_ADDR 0x42
+
+/* Registers */
+#define REG_GAIN	0x00	/* Gain lower 8 bits (rest in vref) */
+#define REG_BLUE	0x01	/* blue gain */
+#define REG_RED		0x02	/* red gain */
+#define REG_VREF	0x03	/* Pieces of GAIN, VSTART, VSTOP */
+#define REG_COM1	0x04	/* Control 1 */
+#define  COM1_CCIR656	  0x40  /* CCIR656 enable */
+#define REG_BAVE	0x05	/* U/B Average level */
+#define REG_GbAVE	0x06	/* Y/Gb Average level */
+#define REG_AECHH	0x07	/* AEC MS 5 bits */
+#define REG_RAVE	0x08	/* V/R Average level */
+#define REG_COM2	0x09	/* Control 2 */
+#define  COM2_SSLEEP	  0x10	/* Soft sleep mode */
+#define REG_PID		0x0a	/* Product ID MSB */
+#define REG_VER		0x0b	/* Product ID LSB */
+#define REG_COM3	0x0c	/* Control 3 */
+#define  COM3_SWAP	  0x40	  /* Byte swap */
+#define  COM3_SCALEEN	  0x08	  /* Enable scaling */
+#define  COM3_DCWEN	  0x04	  /* Enable downsamp/crop/window */
+#define REG_COM4	0x0d	/* Control 4 */
+#define REG_COM5	0x0e	/* All "reserved" */
+#define REG_COM6	0x0f	/* Control 6 */
+#define REG_AECH	0x10	/* More bits of AEC value */
+#define REG_CLKRC	0x11	/* Clocl control */
+#define   CLK_EXT	  0x40	  /* Use external clock directly */
+#define   CLK_SCALE	  0x3f	  /* Mask for internal clock scale */
+#define REG_COM7	0x12	/* Control 7 */
+#define   COM7_RESET	  0x80	  /* Register reset */
+#define   COM7_FMT_MASK	  0x38
+#define   COM7_FMT_VGA	  0x00
+#define	  COM7_FMT_CIF	  0x20	  /* CIF format */
+#define   COM7_FMT_QVGA	  0x10	  /* QVGA format */
+#define   COM7_FMT_QCIF	  0x08	  /* QCIF format */
+#define	  COM7_RGB	  0x04	  /* bits 0 and 2 - RGB format */
+#define	  COM7_YUV	  0x00	  /* YUV */
+#define	  COM7_BAYER	  0x01	  /* Bayer format */
+#define	  COM7_PBAYER	  0x05	  /* "Processed bayer" */
+#define REG_COM8	0x13	/* Control 8 */
+#define   COM8_FASTAEC	  0x80	  /* Enable fast AGC/AEC */
+#define   COM8_AECSTEP	  0x40	  /* Unlimited AEC step size */
+#define   COM8_BFILT	  0x20	  /* Band filter enable */
+#define   COM8_AGC	  0x04	  /* Auto gain enable */
+#define   COM8_AWB	  0x02	  /* White balance enable */
+#define   COM8_AEC	  0x01	  /* Auto exposure enable */
+#define REG_COM9	0x14	/* Control 9  - gain ceiling */
+#define REG_COM10	0x15	/* Control 10 */
+#define   COM10_HSYNC	  0x40	  /* HSYNC instead of HREF */
+#define   COM10_PCLK_HB	  0x20	  /* Suppress PCLK on horiz blank */
+#define   COM10_HREF_REV  0x08	  /* Reverse HREF */
+#define   COM10_VS_LEAD	  0x04	  /* VSYNC on clock leading edge */
+#define   COM10_VS_NEG	  0x02	  /* VSYNC negative */
+#define   COM10_HS_NEG	  0x01	  /* HSYNC negative */
+#define REG_HSTART	0x17	/* Horiz start high bits */
+#define REG_HSTOP	0x18	/* Horiz stop high bits */
+#define REG_VSTART	0x19	/* Vert start high bits */
+#define REG_VSTOP	0x1a	/* Vert stop high bits */
+#define REG_PSHFT	0x1b	/* Pixel delay after HREF */
+#define REG_MIDH	0x1c	/* Manuf. ID high */
+#define REG_MIDL	0x1d	/* Manuf. ID low */
+#define REG_MVFP	0x1e	/* Mirror / vflip */
+#define   MVFP_MIRROR	  0x20	  /* Mirror image */
+#define   MVFP_FLIP	  0x10	  /* Vertical flip */
+
+#define REG_AEW		0x24	/* AGC upper limit */
+#define REG_AEB		0x25	/* AGC lower limit */
+#define REG_VPT		0x26	/* AGC/AEC fast mode op region */
+#define REG_HSYST	0x30	/* HSYNC rising edge delay */
+#define REG_HSYEN	0x31	/* HSYNC falling edge delay */
+#define REG_HREF	0x32	/* HREF pieces */
+#define REG_TSLB	0x3a	/* lots of stuff */
+#define   TSLB_YLAST	  0x04	  /* UYVY or VYUY - see com13 */
+#define REG_COM11	0x3b	/* Control 11 */
+#define   COM11_NIGHT	  0x80	  /* NIght mode enable */
+#define   COM11_NMFR	  0x60	  /* Two bit NM frame rate */
+#define   COM11_HZAUTO	  0x10	  /* Auto detect 50/60 Hz */
+#define	  COM11_50HZ	  0x08	  /* Manual 50Hz select */
+#define   COM11_EXP	  0x02
+#define REG_COM12	0x3c	/* Control 12 */
+#define   COM12_HREF	  0x80	  /* HREF always */
+#define REG_COM13	0x3d	/* Control 13 */
+#define   COM13_GAMMA	  0x80	  /* Gamma enable */
+#define	  COM13_UVSAT	  0x40	  /* UV saturation auto adjustment */
+#define   COM13_UVSWAP	  0x01	  /* V before U - w/TSLB */
+#define REG_COM14	0x3e	/* Control 14 */
+#define   COM14_DCWEN	  0x10	  /* DCW/PCLK-scale enable */
+#define REG_EDGE	0x3f	/* Edge enhancement factor */
+#define REG_COM15	0x40	/* Control 15 */
+#define   COM15_R10F0	  0x00	  /* Data range 10 to F0 */
+#define	  COM15_R01FE	  0x80	  /*            01 to FE */
+#define   COM15_R00FF	  0xc0	  /*            00 to FF */
+#define   COM15_RGB565	  0x10	  /* RGB565 output */
+#define   COM15_RGB555	  0x30	  /* RGB555 output */
+#define REG_COM16	0x41	/* Control 16 */
+#define   COM16_AWBGAIN   0x08	  /* AWB gain enable */
+#define REG_COM17	0x42	/* Control 17 */
+#define   COM17_AECWIN	  0xc0	  /* AEC window - must match COM4 */
+#define   COM17_CBAR	  0x08	  /* DSP Color bar */
+
+/*
+ * This matrix defines how the colors are generated, must be
+ * tweaked to adjust hue and saturation.
+ *
+ * Order: v-red, v-green, v-blue, u-red, u-green, u-blue
+ *
+ * They are nine-bit signed quantities, with the sign bit
+ * stored in 0x58.  Sign for v-red is bit 0, and up from there.
+ */
+#define	REG_CMATRIX_BASE 0x4f
+#define   CMATRIX_LEN 6
+#define REG_CMATRIX_SIGN 0x58
+
+
+#define REG_BRIGHT	0x55	/* Brightness */
+#define REG_CONTRAS	0x56	/* Contrast control */
+
+#define REG_GFIX	0x69	/* Fix gain control */
+
+#define REG_REG76	0x76	/* OV's name */
+#define   R76_BLKPCOR	  0x80	  /* Black pixel correction enable */
+#define   R76_WHTPCOR	  0x40	  /* White pixel correction enable */
+
+#define REG_RGB444	0x8c	/* RGB 444 control */
+#define   R444_ENABLE	  0x02	  /* Turn on RGB444, overrides 5x5 */
+#define   R444_RGBX	  0x01	  /* Empty nibble at end */
+
+#define REG_HAECC1	0x9f	/* Hist AEC/AGC control 1 */
+#define REG_HAECC2	0xa0	/* Hist AEC/AGC control 2 */
+
+#define REG_BD50MAX	0xa5	/* 50hz banding step limit */
+#define REG_HAECC3	0xa6	/* Hist AEC/AGC control 3 */
+#define REG_HAECC4	0xa7	/* Hist AEC/AGC control 4 */
+#define REG_HAECC5	0xa8	/* Hist AEC/AGC control 5 */
+#define REG_HAECC6	0xa9	/* Hist AEC/AGC control 6 */
+#define REG_HAECC7	0xaa	/* Hist AEC/AGC control 7 */
+#define REG_BD60MAX	0xab	/* 60hz banding step limit */
+
+
+/*
+ * Information we maintain about a known sensor.
+ */
+struct ov7670_format_struct;  /* coming later */
+struct ov7670_info {
+	struct v4l2_subdev sd;
+	struct ov7670_format_struct *fmt;  /* Current format */
+	unsigned char sat;		/* Saturation value */
+	int hue;			/* Hue value */
+	int min_width;			/* Filter out smaller sizes */
+	int min_height;			/* Filter out smaller sizes */
+	int clock_speed;		/* External clock speed (MHz) */
+	u8 clkrc;			/* Clock divider value */
+	bool use_smbus;			/* Use smbus I/O instead of I2C */
+};
+
+static inline struct ov7670_info *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct ov7670_info, sd);
+}
+
+
+
+/*
+ * The default register settings, as obtained from OmniVision.  There
+ * is really no making sense of most of these - lots of "reserved" values
+ * and such.
+ *
+ * These settings give VGA YUYV.
+ */
+
+struct regval_list {
+	unsigned char reg_num;
+	unsigned char value;
+};
+
+static struct regval_list ov7670_default_regs[] = {
+	{ REG_COM7, COM7_RESET },
+/*
+ * Clock scale: 3 = 15fps
+ *              2 = 20fps
+ *              1 = 30fps
+ */
+	{ REG_CLKRC, 0x1 },	/* OV: clock scale (30 fps) */
+	{ REG_TSLB,  0x04 },	/* OV */
+	{ REG_COM7, 0 },	/* VGA */
+	/*
+	 * Set the hardware window.  These values from OV don't entirely
+	 * make sense - hstop is less than hstart.  But they work...
+	 */
+	{ REG_HSTART, 0x13 },	{ REG_HSTOP, 0x01 },
+	{ REG_HREF, 0xb6 },	{ REG_VSTART, 0x02 },
+	{ REG_VSTOP, 0x7a },	{ REG_VREF, 0x0a },
+
+	{ REG_COM3, 0 },	{ REG_COM14, 0 },
+	/* Mystery scaling numbers */
+	{ 0x70, 0x3a },		{ 0x71, 0x35 },
+	{ 0x72, 0x11 },		{ 0x73, 0xf0 },
+	{ 0xa2, 0x02 },		{ REG_COM10, 0x0 },
+
+	/* Gamma curve values */
+	{ 0x7a, 0x20 },		{ 0x7b, 0x10 },
+	{ 0x7c, 0x1e },		{ 0x7d, 0x35 },
+	{ 0x7e, 0x5a },		{ 0x7f, 0x69 },
+	{ 0x80, 0x76 },		{ 0x81, 0x80 },
+	{ 0x82, 0x88 },		{ 0x83, 0x8f },
+	{ 0x84, 0x96 },		{ 0x85, 0xa3 },
+	{ 0x86, 0xaf },		{ 0x87, 0xc4 },
+	{ 0x88, 0xd7 },		{ 0x89, 0xe8 },
+
+	/* AGC and AEC parameters.  Note we start by disabling those features,
+	   then turn them only after tweaking the values. */
+	{ REG_COM8, COM8_FASTAEC | COM8_AECSTEP | COM8_BFILT },
+	{ REG_GAIN, 0 },	{ REG_AECH, 0 },
+	{ REG_COM4, 0x40 }, /* magic reserved bit */
+	{ REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
+	{ REG_BD50MAX, 0x05 },	{ REG_BD60MAX, 0x07 },
+	{ REG_AEW, 0x95 },	{ REG_AEB, 0x33 },
+	{ REG_VPT, 0xe3 },	{ REG_HAECC1, 0x78 },
+	{ REG_HAECC2, 0x68 },	{ 0xa1, 0x03 }, /* magic */
+	{ REG_HAECC3, 0xd8 },	{ REG_HAECC4, 0xd8 },
+	{ REG_HAECC5, 0xf0 },	{ REG_HAECC6, 0x90 },
+	{ REG_HAECC7, 0x94 },
+	{ REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC },
+
+	/* Almost all of these are magic "reserved" values.  */
+	{ REG_COM5, 0x61 },	{ REG_COM6, 0x4b },
+	{ 0x16, 0x02 },		{ REG_MVFP, 0x07 },
+	{ 0x21, 0x02 },		{ 0x22, 0x91 },
+	{ 0x29, 0x07 },		{ 0x33, 0x0b },
+	{ 0x35, 0x0b },		{ 0x37, 0x1d },
+	{ 0x38, 0x71 },		{ 0x39, 0x2a },
+	{ REG_COM12, 0x78 },	{ 0x4d, 0x40 },
+	{ 0x4e, 0x20 },		{ REG_GFIX, 0 },
+	{ 0x6b, 0x4a },		{ 0x74, 0x10 },
+	{ 0x8d, 0x4f },		{ 0x8e, 0 },
+	{ 0x8f, 0 },		{ 0x90, 0 },
+	{ 0x91, 0 },		{ 0x96, 0 },
+	{ 0x9a, 0 },		{ 0xb0, 0x84 },
+	{ 0xb1, 0x0c },		{ 0xb2, 0x0e },
+	{ 0xb3, 0x82 },		{ 0xb8, 0x0a },
+
+	/* More reserved magic, some of which tweaks white balance */
+	{ 0x43, 0x0a },		{ 0x44, 0xf0 },
+	{ 0x45, 0x34 },		{ 0x46, 0x58 },
+	{ 0x47, 0x28 },		{ 0x48, 0x3a },
+	{ 0x59, 0x88 },		{ 0x5a, 0x88 },
+	{ 0x5b, 0x44 },		{ 0x5c, 0x67 },
+	{ 0x5d, 0x49 },		{ 0x5e, 0x0e },
+	{ 0x6c, 0x0a },		{ 0x6d, 0x55 },
+	{ 0x6e, 0x11 },		{ 0x6f, 0x9f }, /* "9e for advance AWB" */
+	{ 0x6a, 0x40 },		{ REG_BLUE, 0x40 },
+	{ REG_RED, 0x60 },
+	{ REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC|COM8_AWB },
+
+	/* Matrix coefficients */
+	{ 0x4f, 0x80 },		{ 0x50, 0x80 },
+	{ 0x51, 0 },		{ 0x52, 0x22 },
+	{ 0x53, 0x5e },		{ 0x54, 0x80 },
+	{ 0x58, 0x9e },
+
+	{ REG_COM16, COM16_AWBGAIN },	{ REG_EDGE, 0 },
+	{ 0x75, 0x05 },		{ 0x76, 0xe1 },
+	{ 0x4c, 0 },		{ 0x77, 0x01 },
+	{ REG_COM13, 0xc3 },	{ 0x4b, 0x09 },
+	{ 0xc9, 0x60 },		{ REG_COM16, 0x38 },
+	{ 0x56, 0x40 },
+
+	{ 0x34, 0x11 },		{ REG_COM11, COM11_EXP|COM11_HZAUTO },
+	{ 0xa4, 0x88 },		{ 0x96, 0 },
+	{ 0x97, 0x30 },		{ 0x98, 0x20 },
+	{ 0x99, 0x30 },		{ 0x9a, 0x84 },
+	{ 0x9b, 0x29 },		{ 0x9c, 0x03 },
+	{ 0x9d, 0x4c },		{ 0x9e, 0x3f },
+	{ 0x78, 0x04 },
+
+	/* Extra-weird stuff.  Some sort of multiplexor register */
+	{ 0x79, 0x01 },		{ 0xc8, 0xf0 },
+	{ 0x79, 0x0f },		{ 0xc8, 0x00 },
+	{ 0x79, 0x10 },		{ 0xc8, 0x7e },
+	{ 0x79, 0x0a },		{ 0xc8, 0x80 },
+	{ 0x79, 0x0b },		{ 0xc8, 0x01 },
+	{ 0x79, 0x0c },		{ 0xc8, 0x0f },
+	{ 0x79, 0x0d },		{ 0xc8, 0x20 },
+	{ 0x79, 0x09 },		{ 0xc8, 0x80 },
+	{ 0x79, 0x02 },		{ 0xc8, 0xc0 },
+	{ 0x79, 0x03 },		{ 0xc8, 0x40 },
+	{ 0x79, 0x05 },		{ 0xc8, 0x30 },
+	{ 0x79, 0x26 },
+
+	{ 0xff, 0xff },	/* END MARKER */
+};
+
+
+/*
+ * Here we'll try to encapsulate the changes for just the output
+ * video format.
+ *
+ * RGB656 and YUV422 come from OV; RGB444 is homebrewed.
+ *
+ * IMPORTANT RULE: the first entry must be for COM7, see ov7670_s_fmt for why.
+ */
+
+
+static struct regval_list ov7670_fmt_yuv422[] = {
+	{ REG_COM7, 0x0 },  /* Selects YUV mode */
+	{ REG_RGB444, 0 },	/* No RGB444 please */
+	{ REG_COM1, 0 },	/* CCIR601 */
+	{ REG_COM15, COM15_R00FF },
+	{ REG_COM9, 0x18 }, /* 4x gain ceiling; 0x8 is reserved bit */
+	{ 0x4f, 0x80 }, 	/* "matrix coefficient 1" */
+	{ 0x50, 0x80 }, 	/* "matrix coefficient 2" */
+	{ 0x51, 0    },		/* vb */
+	{ 0x52, 0x22 }, 	/* "matrix coefficient 4" */
+	{ 0x53, 0x5e }, 	/* "matrix coefficient 5" */
+	{ 0x54, 0x80 }, 	/* "matrix coefficient 6" */
+	{ REG_COM13, COM13_GAMMA|COM13_UVSAT },
+	{ 0xff, 0xff },
+};
+
+static struct regval_list ov7670_fmt_rgb565[] = {
+	{ REG_COM7, COM7_RGB },	/* Selects RGB mode */
+	{ REG_RGB444, 0 },	/* No RGB444 please */
+	{ REG_COM1, 0x0 },	/* CCIR601 */
+	{ REG_COM15, COM15_RGB565 },
+	{ REG_COM9, 0x38 }, 	/* 16x gain ceiling; 0x8 is reserved bit */
+	{ 0x4f, 0xb3 }, 	/* "matrix coefficient 1" */
+	{ 0x50, 0xb3 }, 	/* "matrix coefficient 2" */
+	{ 0x51, 0    },		/* vb */
+	{ 0x52, 0x3d }, 	/* "matrix coefficient 4" */
+	{ 0x53, 0xa7 }, 	/* "matrix coefficient 5" */
+	{ 0x54, 0xe4 }, 	/* "matrix coefficient 6" */
+	{ REG_COM13, COM13_GAMMA|COM13_UVSAT },
+	{ 0xff, 0xff },
+};
+
+static struct regval_list ov7670_fmt_rgb444[] = {
+	{ REG_COM7, COM7_RGB },	/* Selects RGB mode */
+	{ REG_RGB444, R444_ENABLE },	/* Enable xxxxrrrr ggggbbbb */
+	{ REG_COM1, 0x0 },	/* CCIR601 */
+	{ REG_COM15, COM15_R01FE|COM15_RGB565 }, /* Data range needed? */
+	{ REG_COM9, 0x38 }, 	/* 16x gain ceiling; 0x8 is reserved bit */
+	{ 0x4f, 0xb3 }, 	/* "matrix coefficient 1" */
+	{ 0x50, 0xb3 }, 	/* "matrix coefficient 2" */
+	{ 0x51, 0    },		/* vb */
+	{ 0x52, 0x3d }, 	/* "matrix coefficient 4" */
+	{ 0x53, 0xa7 }, 	/* "matrix coefficient 5" */
+	{ 0x54, 0xe4 }, 	/* "matrix coefficient 6" */
+	{ REG_COM13, COM13_GAMMA|COM13_UVSAT|0x2 },  /* Magic rsvd bit */
+	{ 0xff, 0xff },
+};
+
+static struct regval_list ov7670_fmt_raw[] = {
+	{ REG_COM7, COM7_BAYER },
+	{ REG_COM13, 0x08 }, /* No gamma, magic rsvd bit */
+	{ REG_COM16, 0x3d }, /* Edge enhancement, denoise */
+	{ REG_REG76, 0xe1 }, /* Pix correction, magic rsvd */
+	{ 0xff, 0xff },
+};
+
+
+
+/*
+ * Low-level register I/O.
+ *
+ * Note that there are two versions of these.  On the XO 1, the
+ * i2c controller only does SMBUS, so that's what we use.  The
+ * ov7670 is not really an SMBUS device, though, so the communication
+ * is not always entirely reliable.
+ */
+static int ov7670_read_smbus(struct v4l2_subdev *sd, unsigned char reg,
+		unsigned char *value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, reg);
+	if (ret >= 0) {
+		*value = (unsigned char)ret;
+		ret = 0;
+	}
+	return ret;
+}
+
+
+static int ov7670_write_smbus(struct v4l2_subdev *sd, unsigned char reg,
+		unsigned char value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret = i2c_smbus_write_byte_data(client, reg, value);
+
+	if (reg == REG_COM7 && (value & COM7_RESET))
+		msleep(5);  /* Wait for reset to run */
+	return ret;
+}
+
+/*
+ * On most platforms, we'd rather do straight i2c I/O.
+ */
+static int ov7670_read_i2c(struct v4l2_subdev *sd, unsigned char reg,
+		unsigned char *value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 data = reg;
+	struct i2c_msg msg;
+	int ret;
+
+	/*
+	 * Send out the register address...
+	 */
+	msg.addr = client->addr;
+	msg.flags = 0;
+	msg.len = 1;
+	msg.buf = &data;
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret < 0) {
+		printk(KERN_ERR "Error %d on register write\n", ret);
+		return ret;
+	}
+	/*
+	 * ...then read back the result.
+	 */
+	msg.flags = I2C_M_RD;
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret >= 0) {
+		*value = data;
+		ret = 0;
+	}
+	return ret;
+}
+
+
+static int ov7670_write_i2c(struct v4l2_subdev *sd, unsigned char reg,
+		unsigned char value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct i2c_msg msg;
+	unsigned char data[2] = { reg, value };
+	int ret;
+
+	msg.addr = client->addr;
+	msg.flags = 0;
+	msg.len = 2;
+	msg.buf = data;
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret > 0)
+		ret = 0;
+	if (reg == REG_COM7 && (value & COM7_RESET))
+		msleep(5);  /* Wait for reset to run */
+	return ret;
+}
+
+static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg,
+		unsigned char *value)
+{
+	struct ov7670_info *info = to_state(sd);
+	if (info->use_smbus)
+		return ov7670_read_smbus(sd, reg, value);
+	else
+		return ov7670_read_i2c(sd, reg, value);
+}
+
+static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg,
+		unsigned char value)
+{
+	struct ov7670_info *info = to_state(sd);
+	if (info->use_smbus)
+		return ov7670_write_smbus(sd, reg, value);
+	else
+		return ov7670_write_i2c(sd, reg, value);
+}
+
+/*
+ * Write a list of register settings; ff/ff stops the process.
+ */
+static int ov7670_write_array(struct v4l2_subdev *sd, struct regval_list *vals)
+{
+	while (vals->reg_num != 0xff || vals->value != 0xff) {
+		int ret = ov7670_write(sd, vals->reg_num, vals->value);
+		if (ret < 0)
+			return ret;
+		vals++;
+	}
+	return 0;
+}
+
+
+/*
+ * Stuff that knows about the sensor.
+ */
+static int ov7670_reset(struct v4l2_subdev *sd, u32 val)
+{
+	ov7670_write(sd, REG_COM7, COM7_RESET);
+	msleep(1);
+	return 0;
+}
+
+
+static int ov7670_init(struct v4l2_subdev *sd, u32 val)
+{
+	return ov7670_write_array(sd, ov7670_default_regs);
+}
+
+
+
+static int ov7670_detect(struct v4l2_subdev *sd)
+{
+	unsigned char v;
+	int ret;
+
+	ret = ov7670_init(sd, 0);
+	if (ret < 0)
+		return ret;
+	ret = ov7670_read(sd, REG_MIDH, &v);
+	if (ret < 0)
+		return ret;
+	if (v != 0x7f) /* OV manuf. id. */
+		return -ENODEV;
+	ret = ov7670_read(sd, REG_MIDL, &v);
+	if (ret < 0)
+		return ret;
+	if (v != 0xa2)
+		return -ENODEV;
+	/*
+	 * OK, we know we have an OmniVision chip...but which one?
+	 */
+	ret = ov7670_read(sd, REG_PID, &v);
+	if (ret < 0)
+		return ret;
+	if (v != 0x76)  /* PID + VER = 0x76 / 0x73 */
+		return -ENODEV;
+	ret = ov7670_read(sd, REG_VER, &v);
+	if (ret < 0)
+		return ret;
+	if (v != 0x73)  /* PID + VER = 0x76 / 0x73 */
+		return -ENODEV;
+	return 0;
+}
+
+
+/*
+ * Store information about the video data format.  The color matrix
+ * is deeply tied into the format, so keep the relevant values here.
+ * The magic matrix numbers come from OmniVision.
+ */
+static struct ov7670_format_struct {
+	enum v4l2_mbus_pixelcode mbus_code;
+	enum v4l2_colorspace colorspace;
+	struct regval_list *regs;
+	int cmatrix[CMATRIX_LEN];
+} ov7670_formats[] = {
+	{
+		.mbus_code	= V4L2_MBUS_FMT_YUYV8_2X8,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.regs 		= ov7670_fmt_yuv422,
+		.cmatrix	= { 128, -128, 0, -34, -94, 128 },
+	},
+	{
+		.mbus_code	= V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
+		.regs		= ov7670_fmt_rgb444,
+		.cmatrix	= { 179, -179, 0, -61, -176, 228 },
+	},
+	{
+		.mbus_code	= V4L2_MBUS_FMT_RGB565_2X8_LE,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
+		.regs		= ov7670_fmt_rgb565,
+		.cmatrix	= { 179, -179, 0, -61, -176, 228 },
+	},
+	{
+		.mbus_code	= V4L2_MBUS_FMT_SBGGR8_1X8,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
+		.regs 		= ov7670_fmt_raw,
+		.cmatrix	= { 0, 0, 0, 0, 0, 0 },
+	},
+};
+#define N_OV7670_FMTS ARRAY_SIZE(ov7670_formats)
+
+
+/*
+ * Then there is the issue of window sizes.  Try to capture the info here.
+ */
+
+/*
+ * QCIF mode is done (by OV) in a very strange way - it actually looks like
+ * VGA with weird scaling options - they do *not* use the canned QCIF mode
+ * which is allegedly provided by the sensor.  So here's the weird register
+ * settings.
+ */
+static struct regval_list ov7670_qcif_regs[] = {
+	{ REG_COM3, COM3_SCALEEN|COM3_DCWEN },
+	{ REG_COM3, COM3_DCWEN },
+	{ REG_COM14, COM14_DCWEN | 0x01},
+	{ 0x73, 0xf1 },
+	{ 0xa2, 0x52 },
+	{ 0x7b, 0x1c },
+	{ 0x7c, 0x28 },
+	{ 0x7d, 0x3c },
+	{ 0x7f, 0x69 },
+	{ REG_COM9, 0x38 },
+	{ 0xa1, 0x0b },
+	{ 0x74, 0x19 },
+	{ 0x9a, 0x80 },
+	{ 0x43, 0x14 },
+	{ REG_COM13, 0xc0 },
+	{ 0xff, 0xff },
+};
+
+static struct ov7670_win_size {
+	int	width;
+	int	height;
+	unsigned char com7_bit;
+	int	hstart;		/* Start/stop values for the camera.  Note */
+	int	hstop;		/* that they do not always make complete */
+	int	vstart;		/* sense to humans, but evidently the sensor */
+	int	vstop;		/* will do the right thing... */
+	struct regval_list *regs; /* Regs to tweak */
+/* h/vref stuff */
+} ov7670_win_sizes[] = {
+	/* VGA */
+	{
+		.width		= VGA_WIDTH,
+		.height		= VGA_HEIGHT,
+		.com7_bit	= COM7_FMT_VGA,
+		.hstart		= 158,		/* These values from */
+		.hstop		=  14,		/* Omnivision */
+		.vstart		=  10,
+		.vstop		= 490,
+		.regs 		= NULL,
+	},
+	/* CIF */
+	{
+		.width		= CIF_WIDTH,
+		.height		= CIF_HEIGHT,
+		.com7_bit	= COM7_FMT_CIF,
+		.hstart		= 170,		/* Empirically determined */
+		.hstop		=  90,
+		.vstart		=  14,
+		.vstop		= 494,
+		.regs 		= NULL,
+	},
+	/* QVGA */
+	{
+		.width		= QVGA_WIDTH,
+		.height		= QVGA_HEIGHT,
+		.com7_bit	= COM7_FMT_QVGA,
+		.hstart		= 168,		/* Empirically determined */
+		.hstop		=  24,
+		.vstart		=  12,
+		.vstop		= 492,
+		.regs 		= NULL,
+	},
+	/* QCIF */
+	{
+		.width		= QCIF_WIDTH,
+		.height		= QCIF_HEIGHT,
+		.com7_bit	= COM7_FMT_VGA, /* see comment above */
+		.hstart		= 456,		/* Empirically determined */
+		.hstop		=  24,
+		.vstart		=  14,
+		.vstop		= 494,
+		.regs 		= ov7670_qcif_regs,
+	},
+};
+
+#define N_WIN_SIZES (ARRAY_SIZE(ov7670_win_sizes))
+
+
+/*
+ * Store a set of start/stop values into the camera.
+ */
+static int ov7670_set_hw(struct v4l2_subdev *sd, int hstart, int hstop,
+		int vstart, int vstop)
+{
+	int ret;
+	unsigned char v;
+/*
+ * Horizontal: 11 bits, top 8 live in hstart and hstop.  Bottom 3 of
+ * hstart are in href[2:0], bottom 3 of hstop in href[5:3].  There is
+ * a mystery "edge offset" value in the top two bits of href.
+ */
+	ret =  ov7670_write(sd, REG_HSTART, (hstart >> 3) & 0xff);
+	ret += ov7670_write(sd, REG_HSTOP, (hstop >> 3) & 0xff);
+	ret += ov7670_read(sd, REG_HREF, &v);
+	v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7);
+	msleep(10);
+	ret += ov7670_write(sd, REG_HREF, v);
+/*
+ * Vertical: similar arrangement, but only 10 bits.
+ */
+	ret += ov7670_write(sd, REG_VSTART, (vstart >> 2) & 0xff);
+	ret += ov7670_write(sd, REG_VSTOP, (vstop >> 2) & 0xff);
+	ret += ov7670_read(sd, REG_VREF, &v);
+	v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3);
+	msleep(10);
+	ret += ov7670_write(sd, REG_VREF, v);
+	return ret;
+}
+
+
+static int ov7670_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+					enum v4l2_mbus_pixelcode *code)
+{
+	if (index >= N_OV7670_FMTS)
+		return -EINVAL;
+
+	*code = ov7670_formats[index].mbus_code;
+	return 0;
+}
+
+static int ov7670_try_fmt_internal(struct v4l2_subdev *sd,
+		struct v4l2_mbus_framefmt *fmt,
+		struct ov7670_format_struct **ret_fmt,
+		struct ov7670_win_size **ret_wsize)
+{
+	int index;
+	struct ov7670_win_size *wsize;
+
+	for (index = 0; index < N_OV7670_FMTS; index++)
+		if (ov7670_formats[index].mbus_code == fmt->code)
+			break;
+	if (index >= N_OV7670_FMTS) {
+		/* default to first format */
+		index = 0;
+		fmt->code = ov7670_formats[0].mbus_code;
+	}
+	if (ret_fmt != NULL)
+		*ret_fmt = ov7670_formats + index;
+	/*
+	 * Fields: the OV devices claim to be progressive.
+	 */
+	fmt->field = V4L2_FIELD_NONE;
+	/*
+	 * Round requested image size down to the nearest
+	 * we support, but not below the smallest.
+	 */
+	for (wsize = ov7670_win_sizes; wsize < ov7670_win_sizes + N_WIN_SIZES;
+	     wsize++)
+		if (fmt->width >= wsize->width && fmt->height >= wsize->height)
+			break;
+	if (wsize >= ov7670_win_sizes + N_WIN_SIZES)
+		wsize--;   /* Take the smallest one */
+	if (ret_wsize != NULL)
+		*ret_wsize = wsize;
+	/*
+	 * Note the size we'll actually handle.
+	 */
+	fmt->width = wsize->width;
+	fmt->height = wsize->height;
+	fmt->colorspace = ov7670_formats[index].colorspace;
+	return 0;
+}
+
+static int ov7670_try_mbus_fmt(struct v4l2_subdev *sd,
+			    struct v4l2_mbus_framefmt *fmt)
+{
+	return ov7670_try_fmt_internal(sd, fmt, NULL, NULL);
+}
+
+/*
+ * Set a format.
+ */
+static int ov7670_s_mbus_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_mbus_framefmt *fmt)
+{
+	struct ov7670_format_struct *ovfmt;
+	struct ov7670_win_size *wsize;
+	struct ov7670_info *info = to_state(sd);
+	unsigned char com7;
+	int ret;
+
+	ret = ov7670_try_fmt_internal(sd, fmt, &ovfmt, &wsize);
+
+	if (ret)
+		return ret;
+	/*
+	 * COM7 is a pain in the ass, it doesn't like to be read then
+	 * quickly written afterward.  But we have everything we need
+	 * to set it absolutely here, as long as the format-specific
+	 * register sets list it first.
+	 */
+	com7 = ovfmt->regs[0].value;
+	com7 |= wsize->com7_bit;
+	ov7670_write(sd, REG_COM7, com7);
+	/*
+	 * Now write the rest of the array.  Also store start/stops
+	 */
+	ov7670_write_array(sd, ovfmt->regs + 1);
+	ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart,
+			wsize->vstop);
+	ret = 0;
+	if (wsize->regs)
+		ret = ov7670_write_array(sd, wsize->regs);
+	info->fmt = ovfmt;
+
+	/*
+	 * If we're running RGB565, we must rewrite clkrc after setting
+	 * the other parameters or the image looks poor.  If we're *not*
+	 * doing RGB565, we must not rewrite clkrc or the image looks
+	 * *really* poor.
+	 *
+	 * (Update) Now that we retain clkrc state, we should be able
+	 * to write it unconditionally, and that will make the frame
+	 * rate persistent too.
+	 */
+	if (ret == 0)
+		ret = ov7670_write(sd, REG_CLKRC, info->clkrc);
+	return 0;
+}
+
+/*
+ * Implement G/S_PARM.  There is a "high quality" mode we could try
+ * to do someday; for now, we just do the frame rate tweak.
+ */
+static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+	struct v4l2_captureparm *cp = &parms->parm.capture;
+	struct ov7670_info *info = to_state(sd);
+
+	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	memset(cp, 0, sizeof(struct v4l2_captureparm));
+	cp->capability = V4L2_CAP_TIMEPERFRAME;
+	cp->timeperframe.numerator = 1;
+	cp->timeperframe.denominator = info->clock_speed;
+	if ((info->clkrc & CLK_EXT) == 0 && (info->clkrc & CLK_SCALE) > 1)
+		cp->timeperframe.denominator /= (info->clkrc & CLK_SCALE);
+	return 0;
+}
+
+static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+	struct v4l2_captureparm *cp = &parms->parm.capture;
+	struct v4l2_fract *tpf = &cp->timeperframe;
+	struct ov7670_info *info = to_state(sd);
+	int div;
+
+	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (cp->extendedmode != 0)
+		return -EINVAL;
+
+	if (tpf->numerator == 0 || tpf->denominator == 0)
+		div = 1;  /* Reset to full rate */
+	else
+		div = (tpf->numerator * info->clock_speed) / tpf->denominator;
+	if (div == 0)
+		div = 1;
+	else if (div > CLK_SCALE)
+		div = CLK_SCALE;
+	info->clkrc = (info->clkrc & 0x80) | div;
+	tpf->numerator = 1;
+	tpf->denominator = info->clock_speed / div;
+	return ov7670_write(sd, REG_CLKRC, info->clkrc);
+}
+
+
+/*
+ * Frame intervals.  Since frame rates are controlled with the clock
+ * divider, we can only do 30/n for integer n values.  So no continuous
+ * or stepwise options.  Here we just pick a handful of logical values.
+ */
+
+static int ov7670_frame_rates[] = { 30, 15, 10, 5, 1 };
+
+static int ov7670_enum_frameintervals(struct v4l2_subdev *sd,
+		struct v4l2_frmivalenum *interval)
+{
+	if (interval->index >= ARRAY_SIZE(ov7670_frame_rates))
+		return -EINVAL;
+	interval->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+	interval->discrete.numerator = 1;
+	interval->discrete.denominator = ov7670_frame_rates[interval->index];
+	return 0;
+}
+
+/*
+ * Frame size enumeration
+ */
+static int ov7670_enum_framesizes(struct v4l2_subdev *sd,
+		struct v4l2_frmsizeenum *fsize)
+{
+	struct ov7670_info *info = to_state(sd);
+	int i;
+	int num_valid = -1;
+	__u32 index = fsize->index;
+
+	/*
+	 * If a minimum width/height was requested, filter out the capture
+	 * windows that fall outside that.
+	 */
+	for (i = 0; i < N_WIN_SIZES; i++) {
+		struct ov7670_win_size *win = &ov7670_win_sizes[index];
+		if (info->min_width && win->width < info->min_width)
+			continue;
+		if (info->min_height && win->height < info->min_height)
+			continue;
+		if (index == ++num_valid) {
+			fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+			fsize->discrete.width = win->width;
+			fsize->discrete.height = win->height;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+/*
+ * Code for dealing with controls.
+ */
+
+static int ov7670_store_cmatrix(struct v4l2_subdev *sd,
+		int matrix[CMATRIX_LEN])
+{
+	int i, ret;
+	unsigned char signbits = 0;
+
+	/*
+	 * Weird crap seems to exist in the upper part of
+	 * the sign bits register, so let's preserve it.
+	 */
+	ret = ov7670_read(sd, REG_CMATRIX_SIGN, &signbits);
+	signbits &= 0xc0;
+
+	for (i = 0; i < CMATRIX_LEN; i++) {
+		unsigned char raw;
+
+		if (matrix[i] < 0) {
+			signbits |= (1 << i);
+			if (matrix[i] < -255)
+				raw = 0xff;
+			else
+				raw = (-1 * matrix[i]) & 0xff;
+		}
+		else {
+			if (matrix[i] > 255)
+				raw = 0xff;
+			else
+				raw = matrix[i] & 0xff;
+		}
+		ret += ov7670_write(sd, REG_CMATRIX_BASE + i, raw);
+	}
+	ret += ov7670_write(sd, REG_CMATRIX_SIGN, signbits);
+	return ret;
+}
+
+
+/*
+ * Hue also requires messing with the color matrix.  It also requires
+ * trig functions, which tend not to be well supported in the kernel.
+ * So here is a simple table of sine values, 0-90 degrees, in steps
+ * of five degrees.  Values are multiplied by 1000.
+ *
+ * The following naive approximate trig functions require an argument
+ * carefully limited to -180 <= theta <= 180.
+ */
+#define SIN_STEP 5
+static const int ov7670_sin_table[] = {
+	   0,	 87,   173,   258,   342,   422,
+	 499,	573,   642,   707,   766,   819,
+	 866,	906,   939,   965,   984,   996,
+	1000
+};
+
+static int ov7670_sine(int theta)
+{
+	int chs = 1;
+	int sine;
+
+	if (theta < 0) {
+		theta = -theta;
+		chs = -1;
+	}
+	if (theta <= 90)
+		sine = ov7670_sin_table[theta/SIN_STEP];
+	else {
+		theta -= 90;
+		sine = 1000 - ov7670_sin_table[theta/SIN_STEP];
+	}
+	return sine*chs;
+}
+
+static int ov7670_cosine(int theta)
+{
+	theta = 90 - theta;
+	if (theta > 180)
+		theta -= 360;
+	else if (theta < -180)
+		theta += 360;
+	return ov7670_sine(theta);
+}
+
+
+
+
+static void ov7670_calc_cmatrix(struct ov7670_info *info,
+		int matrix[CMATRIX_LEN])
+{
+	int i;
+	/*
+	 * Apply the current saturation setting first.
+	 */
+	for (i = 0; i < CMATRIX_LEN; i++)
+		matrix[i] = (info->fmt->cmatrix[i]*info->sat) >> 7;
+	/*
+	 * Then, if need be, rotate the hue value.
+	 */
+	if (info->hue != 0) {
+		int sinth, costh, tmpmatrix[CMATRIX_LEN];
+
+		memcpy(tmpmatrix, matrix, CMATRIX_LEN*sizeof(int));
+		sinth = ov7670_sine(info->hue);
+		costh = ov7670_cosine(info->hue);
+
+		matrix[0] = (matrix[3]*sinth + matrix[0]*costh)/1000;
+		matrix[1] = (matrix[4]*sinth + matrix[1]*costh)/1000;
+		matrix[2] = (matrix[5]*sinth + matrix[2]*costh)/1000;
+		matrix[3] = (matrix[3]*costh - matrix[0]*sinth)/1000;
+		matrix[4] = (matrix[4]*costh - matrix[1]*sinth)/1000;
+		matrix[5] = (matrix[5]*costh - matrix[2]*sinth)/1000;
+	}
+}
+
+
+
+static int ov7670_s_sat(struct v4l2_subdev *sd, int value)
+{
+	struct ov7670_info *info = to_state(sd);
+	int matrix[CMATRIX_LEN];
+	int ret;
+
+	info->sat = value;
+	ov7670_calc_cmatrix(info, matrix);
+	ret = ov7670_store_cmatrix(sd, matrix);
+	return ret;
+}
+
+static int ov7670_g_sat(struct v4l2_subdev *sd, __s32 *value)
+{
+	struct ov7670_info *info = to_state(sd);
+
+	*value = info->sat;
+	return 0;
+}
+
+static int ov7670_s_hue(struct v4l2_subdev *sd, int value)
+{
+	struct ov7670_info *info = to_state(sd);
+	int matrix[CMATRIX_LEN];
+	int ret;
+
+	if (value < -180 || value > 180)
+		return -EINVAL;
+	info->hue = value;
+	ov7670_calc_cmatrix(info, matrix);
+	ret = ov7670_store_cmatrix(sd, matrix);
+	return ret;
+}
+
+
+static int ov7670_g_hue(struct v4l2_subdev *sd, __s32 *value)
+{
+	struct ov7670_info *info = to_state(sd);
+
+	*value = info->hue;
+	return 0;
+}
+
+
+/*
+ * Some weird registers seem to store values in a sign/magnitude format!
+ */
+static unsigned char ov7670_sm_to_abs(unsigned char v)
+{
+	if ((v & 0x80) == 0)
+		return v + 128;
+	return 128 - (v & 0x7f);
+}
+
+
+static unsigned char ov7670_abs_to_sm(unsigned char v)
+{
+	if (v > 127)
+		return v & 0x7f;
+	return (128 - v) | 0x80;
+}
+
+static int ov7670_s_brightness(struct v4l2_subdev *sd, int value)
+{
+	unsigned char com8 = 0, v;
+	int ret;
+
+	ov7670_read(sd, REG_COM8, &com8);
+	com8 &= ~COM8_AEC;
+	ov7670_write(sd, REG_COM8, com8);
+	v = ov7670_abs_to_sm(value);
+	ret = ov7670_write(sd, REG_BRIGHT, v);
+	return ret;
+}
+
+static int ov7670_g_brightness(struct v4l2_subdev *sd, __s32 *value)
+{
+	unsigned char v = 0;
+	int ret = ov7670_read(sd, REG_BRIGHT, &v);
+
+	*value = ov7670_sm_to_abs(v);
+	return ret;
+}
+
+static int ov7670_s_contrast(struct v4l2_subdev *sd, int value)
+{
+	return ov7670_write(sd, REG_CONTRAS, (unsigned char) value);
+}
+
+static int ov7670_g_contrast(struct v4l2_subdev *sd, __s32 *value)
+{
+	unsigned char v = 0;
+	int ret = ov7670_read(sd, REG_CONTRAS, &v);
+
+	*value = v;
+	return ret;
+}
+
+static int ov7670_g_hflip(struct v4l2_subdev *sd, __s32 *value)
+{
+	int ret;
+	unsigned char v = 0;
+
+	ret = ov7670_read(sd, REG_MVFP, &v);
+	*value = (v & MVFP_MIRROR) == MVFP_MIRROR;
+	return ret;
+}
+
+
+static int ov7670_s_hflip(struct v4l2_subdev *sd, int value)
+{
+	unsigned char v = 0;
+	int ret;
+
+	ret = ov7670_read(sd, REG_MVFP, &v);
+	if (value)
+		v |= MVFP_MIRROR;
+	else
+		v &= ~MVFP_MIRROR;
+	msleep(10);  /* FIXME */
+	ret += ov7670_write(sd, REG_MVFP, v);
+	return ret;
+}
+
+
+
+static int ov7670_g_vflip(struct v4l2_subdev *sd, __s32 *value)
+{
+	int ret;
+	unsigned char v = 0;
+
+	ret = ov7670_read(sd, REG_MVFP, &v);
+	*value = (v & MVFP_FLIP) == MVFP_FLIP;
+	return ret;
+}
+
+
+static int ov7670_s_vflip(struct v4l2_subdev *sd, int value)
+{
+	unsigned char v = 0;
+	int ret;
+
+	ret = ov7670_read(sd, REG_MVFP, &v);
+	if (value)
+		v |= MVFP_FLIP;
+	else
+		v &= ~MVFP_FLIP;
+	msleep(10);  /* FIXME */
+	ret += ov7670_write(sd, REG_MVFP, v);
+	return ret;
+}
+
+/*
+ * GAIN is split between REG_GAIN and REG_VREF[7:6].  If one believes
+ * the data sheet, the VREF parts should be the most significant, but
+ * experience shows otherwise.  There seems to be little value in
+ * messing with the VREF bits, so we leave them alone.
+ */
+static int ov7670_g_gain(struct v4l2_subdev *sd, __s32 *value)
+{
+	int ret;
+	unsigned char gain;
+
+	ret = ov7670_read(sd, REG_GAIN, &gain);
+	*value = gain;
+	return ret;
+}
+
+static int ov7670_s_gain(struct v4l2_subdev *sd, int value)
+{
+	int ret;
+	unsigned char com8;
+
+	ret = ov7670_write(sd, REG_GAIN, value & 0xff);
+	/* Have to turn off AGC as well */
+	if (ret == 0) {
+		ret = ov7670_read(sd, REG_COM8, &com8);
+		ret = ov7670_write(sd, REG_COM8, com8 & ~COM8_AGC);
+	}
+	return ret;
+}
+
+/*
+ * Tweak autogain.
+ */
+static int ov7670_g_autogain(struct v4l2_subdev *sd, __s32 *value)
+{
+	int ret;
+	unsigned char com8;
+
+	ret = ov7670_read(sd, REG_COM8, &com8);
+	*value = (com8 & COM8_AGC) != 0;
+	return ret;
+}
+
+static int ov7670_s_autogain(struct v4l2_subdev *sd, int value)
+{
+	int ret;
+	unsigned char com8;
+
+	ret = ov7670_read(sd, REG_COM8, &com8);
+	if (ret == 0) {
+		if (value)
+			com8 |= COM8_AGC;
+		else
+			com8 &= ~COM8_AGC;
+		ret = ov7670_write(sd, REG_COM8, com8);
+	}
+	return ret;
+}
+
+/*
+ * Exposure is spread all over the place: top 6 bits in AECHH, middle
+ * 8 in AECH, and two stashed in COM1 just for the hell of it.
+ */
+static int ov7670_g_exp(struct v4l2_subdev *sd, __s32 *value)
+{
+	int ret;
+	unsigned char com1, aech, aechh;
+
+	ret = ov7670_read(sd, REG_COM1, &com1) +
+		ov7670_read(sd, REG_AECH, &aech) +
+		ov7670_read(sd, REG_AECHH, &aechh);
+	*value = ((aechh & 0x3f) << 10) | (aech << 2) | (com1 & 0x03);
+	return ret;
+}
+
+static int ov7670_s_exp(struct v4l2_subdev *sd, int value)
+{
+	int ret;
+	unsigned char com1, com8, aech, aechh;
+
+	ret = ov7670_read(sd, REG_COM1, &com1) +
+		ov7670_read(sd, REG_COM8, &com8);
+		ov7670_read(sd, REG_AECHH, &aechh);
+	if (ret)
+		return ret;
+
+	com1 = (com1 & 0xfc) | (value & 0x03);
+	aech = (value >> 2) & 0xff;
+	aechh = (aechh & 0xc0) | ((value >> 10) & 0x3f);
+	ret = ov7670_write(sd, REG_COM1, com1) +
+		ov7670_write(sd, REG_AECH, aech) +
+		ov7670_write(sd, REG_AECHH, aechh);
+	/* Have to turn off AEC as well */
+	if (ret == 0)
+		ret = ov7670_write(sd, REG_COM8, com8 & ~COM8_AEC);
+	return ret;
+}
+
+/*
+ * Tweak autoexposure.
+ */
+static int ov7670_g_autoexp(struct v4l2_subdev *sd, __s32 *value)
+{
+	int ret;
+	unsigned char com8;
+	enum v4l2_exposure_auto_type *atype = (enum v4l2_exposure_auto_type *) value;
+
+	ret = ov7670_read(sd, REG_COM8, &com8);
+	if (com8 & COM8_AEC)
+		*atype = V4L2_EXPOSURE_AUTO;
+	else
+		*atype = V4L2_EXPOSURE_MANUAL;
+	return ret;
+}
+
+static int ov7670_s_autoexp(struct v4l2_subdev *sd,
+		enum v4l2_exposure_auto_type value)
+{
+	int ret;
+	unsigned char com8;
+
+	ret = ov7670_read(sd, REG_COM8, &com8);
+	if (ret == 0) {
+		if (value == V4L2_EXPOSURE_AUTO)
+			com8 |= COM8_AEC;
+		else
+			com8 &= ~COM8_AEC;
+		ret = ov7670_write(sd, REG_COM8, com8);
+	}
+	return ret;
+}
+
+
+
+static int ov7670_queryctrl(struct v4l2_subdev *sd,
+		struct v4l2_queryctrl *qc)
+{
+	/* Fill in min, max, step and default value for these controls. */
+	switch (qc->id) {
+	case V4L2_CID_BRIGHTNESS:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
+	case V4L2_CID_CONTRAST:
+		return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
+	case V4L2_CID_VFLIP:
+	case V4L2_CID_HFLIP:
+		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+	case V4L2_CID_SATURATION:
+		return v4l2_ctrl_query_fill(qc, 0, 256, 1, 128);
+	case V4L2_CID_HUE:
+		return v4l2_ctrl_query_fill(qc, -180, 180, 5, 0);
+	case V4L2_CID_GAIN:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
+	case V4L2_CID_AUTOGAIN:
+		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+	case V4L2_CID_EXPOSURE:
+		return v4l2_ctrl_query_fill(qc, 0, 65535, 1, 500);
+	case V4L2_CID_EXPOSURE_AUTO:
+		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+	}
+	return -EINVAL;
+}
+
+static int ov7670_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		return ov7670_g_brightness(sd, &ctrl->value);
+	case V4L2_CID_CONTRAST:
+		return ov7670_g_contrast(sd, &ctrl->value);
+	case V4L2_CID_SATURATION:
+		return ov7670_g_sat(sd, &ctrl->value);
+	case V4L2_CID_HUE:
+		return ov7670_g_hue(sd, &ctrl->value);
+	case V4L2_CID_VFLIP:
+		return ov7670_g_vflip(sd, &ctrl->value);
+	case V4L2_CID_HFLIP:
+		return ov7670_g_hflip(sd, &ctrl->value);
+	case V4L2_CID_GAIN:
+		return ov7670_g_gain(sd, &ctrl->value);
+	case V4L2_CID_AUTOGAIN:
+		return ov7670_g_autogain(sd, &ctrl->value);
+	case V4L2_CID_EXPOSURE:
+		return ov7670_g_exp(sd, &ctrl->value);
+	case V4L2_CID_EXPOSURE_AUTO:
+		return ov7670_g_autoexp(sd, &ctrl->value);
+	}
+	return -EINVAL;
+}
+
+static int ov7670_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		return ov7670_s_brightness(sd, ctrl->value);
+	case V4L2_CID_CONTRAST:
+		return ov7670_s_contrast(sd, ctrl->value);
+	case V4L2_CID_SATURATION:
+		return ov7670_s_sat(sd, ctrl->value);
+	case V4L2_CID_HUE:
+		return ov7670_s_hue(sd, ctrl->value);
+	case V4L2_CID_VFLIP:
+		return ov7670_s_vflip(sd, ctrl->value);
+	case V4L2_CID_HFLIP:
+		return ov7670_s_hflip(sd, ctrl->value);
+	case V4L2_CID_GAIN:
+		return ov7670_s_gain(sd, ctrl->value);
+	case V4L2_CID_AUTOGAIN:
+		return ov7670_s_autogain(sd, ctrl->value);
+	case V4L2_CID_EXPOSURE:
+		return ov7670_s_exp(sd, ctrl->value);
+	case V4L2_CID_EXPOSURE_AUTO:
+		return ov7670_s_autoexp(sd,
+				(enum v4l2_exposure_auto_type) ctrl->value);
+	}
+	return -EINVAL;
+}
+
+static int ov7670_g_chip_ident(struct v4l2_subdev *sd,
+		struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV7670, 0);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov7670_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	unsigned char val = 0;
+	int ret;
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	ret = ov7670_read(sd, reg->reg & 0xff, &val);
+	reg->val = val;
+	reg->size = 1;
+	return ret;
+}
+
+static int ov7670_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	ov7670_write(sd, reg->reg & 0xff, reg->val & 0xff);
+	return 0;
+}
+#endif
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops ov7670_core_ops = {
+	.g_chip_ident = ov7670_g_chip_ident,
+	.g_ctrl = ov7670_g_ctrl,
+	.s_ctrl = ov7670_s_ctrl,
+	.queryctrl = ov7670_queryctrl,
+	.reset = ov7670_reset,
+	.init = ov7670_init,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = ov7670_g_register,
+	.s_register = ov7670_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops ov7670_video_ops = {
+	.enum_mbus_fmt = ov7670_enum_mbus_fmt,
+	.try_mbus_fmt = ov7670_try_mbus_fmt,
+	.s_mbus_fmt = ov7670_s_mbus_fmt,
+	.s_parm = ov7670_s_parm,
+	.g_parm = ov7670_g_parm,
+	.enum_frameintervals = ov7670_enum_frameintervals,
+	.enum_framesizes = ov7670_enum_framesizes,
+};
+
+static const struct v4l2_subdev_ops ov7670_ops = {
+	.core = &ov7670_core_ops,
+	.video = &ov7670_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int ov7670_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct v4l2_subdev *sd;
+	struct ov7670_info *info;
+	int ret;
+
+	info = kzalloc(sizeof(struct ov7670_info), GFP_KERNEL);
+	if (info == NULL)
+		return -ENOMEM;
+	sd = &info->sd;
+	v4l2_i2c_subdev_init(sd, client, &ov7670_ops);
+
+	info->clock_speed = 30; /* default: a guess */
+	if (client->dev.platform_data) {
+		struct ov7670_config *config = client->dev.platform_data;
+
+		/*
+		 * Must apply configuration before initializing device, because it
+		 * selects I/O method.
+		 */
+		info->min_width = config->min_width;
+		info->min_height = config->min_height;
+		info->use_smbus = config->use_smbus;
+
+		if (config->clock_speed)
+			info->clock_speed = config->clock_speed;
+	}
+
+	/* Make sure it's an ov7670 */
+	ret = ov7670_detect(sd);
+	if (ret) {
+		v4l_dbg(1, debug, client,
+			"chip found @ 0x%x (%s) is not an ov7670 chip.\n",
+			client->addr << 1, client->adapter->name);
+		kfree(info);
+		return ret;
+	}
+	v4l_info(client, "chip found @ 0x%02x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	info->fmt = &ov7670_formats[0];
+	info->sat = 128;	/* Review this */
+	info->clkrc = info->clock_speed / 30;
+	return 0;
+}
+
+
+static int ov7670_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_state(sd));
+	return 0;
+}
+
+static const struct i2c_device_id ov7670_id[] = {
+	{ "ov7670", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ov7670_id);
+
+static struct i2c_driver ov7670_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "ov7670",
+	},
+	.probe		= ov7670_probe,
+	.remove		= ov7670_remove,
+	.id_table	= ov7670_id,
+};
+
+module_i2c_driver(ov7670_driver);
diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c
new file mode 100644
index 0000000..045ca7f
--- /dev/null
+++ b/drivers/media/i2c/s5k6aa.c
@@ -0,0 +1,1667 @@
+/*
+ * Driver for Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor
+ * with embedded SoC ISP.
+ *
+ * Copyright (C) 2011, Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * Based on a driver authored by Dongsoo Nathaniel Kim.
+ * Copyright (C) 2009, Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/media.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-mediabus.h>
+#include <media/s5k6aa.h>
+
+static int debug;
+module_param(debug, int, 0644);
+
+#define DRIVER_NAME			"S5K6AA"
+
+/* The token to indicate array termination */
+#define S5K6AA_TERM			0xffff
+#define S5K6AA_OUT_WIDTH_DEF		640
+#define S5K6AA_OUT_HEIGHT_DEF		480
+#define S5K6AA_WIN_WIDTH_MAX		1280
+#define S5K6AA_WIN_HEIGHT_MAX		1024
+#define S5K6AA_WIN_WIDTH_MIN		8
+#define S5K6AA_WIN_HEIGHT_MIN		8
+
+/*
+ * H/W register Interface (0xD0000000 - 0xD0000FFF)
+ */
+#define AHB_MSB_ADDR_PTR		0xfcfc
+#define GEN_REG_OFFSH			0xd000
+#define REG_CMDWR_ADDRH			0x0028
+#define REG_CMDWR_ADDRL			0x002a
+#define REG_CMDRD_ADDRH			0x002c
+#define REG_CMDRD_ADDRL			0x002e
+#define REG_CMDBUF0_ADDR		0x0f12
+#define REG_CMDBUF1_ADDR		0x0f10
+
+/*
+ * Host S/W Register interface (0x70000000 - 0x70002000)
+ * The value of the two most significant address bytes is 0x7000,
+ * (HOST_SWIF_OFFS_H). The register addresses below specify 2 LSBs.
+ */
+#define HOST_SWIF_OFFSH			0x7000
+
+/* Initialization parameters */
+/* Master clock frequency in KHz */
+#define REG_I_INCLK_FREQ_L		0x01b8
+#define REG_I_INCLK_FREQ_H		0x01ba
+#define  MIN_MCLK_FREQ_KHZ		6000U
+#define  MAX_MCLK_FREQ_KHZ		27000U
+#define REG_I_USE_NPVI_CLOCKS		0x01c6
+#define REG_I_USE_NMIPI_CLOCKS		0x01c8
+
+/* Clock configurations, n = 0..2. REG_I_* frequency unit is 4 kHz. */
+#define REG_I_OPCLK_4KHZ(n)		((n) * 6 + 0x01cc)
+#define REG_I_MIN_OUTRATE_4KHZ(n)	((n) * 6 + 0x01ce)
+#define REG_I_MAX_OUTRATE_4KHZ(n)	((n) * 6 + 0x01d0)
+#define  SYS_PLL_OUT_FREQ		(48000000 / 4000)
+#define  PCLK_FREQ_MIN			(24000000 / 4000)
+#define  PCLK_FREQ_MAX			(48000000 / 4000)
+#define REG_I_INIT_PARAMS_UPDATED	0x01e0
+#define REG_I_ERROR_INFO		0x01e2
+
+/* General purpose parameters */
+#define REG_USER_BRIGHTNESS		0x01e4
+#define REG_USER_CONTRAST		0x01e6
+#define REG_USER_SATURATION		0x01e8
+#define REG_USER_SHARPBLUR		0x01ea
+
+#define REG_G_SPEC_EFFECTS		0x01ee
+#define REG_G_ENABLE_PREV		0x01f0
+#define REG_G_ENABLE_PREV_CHG		0x01f2
+#define REG_G_NEW_CFG_SYNC		0x01f8
+#define REG_G_PREVZOOM_IN_WIDTH		0x020a
+#define REG_G_PREVZOOM_IN_HEIGHT	0x020c
+#define REG_G_PREVZOOM_IN_XOFFS		0x020e
+#define REG_G_PREVZOOM_IN_YOFFS		0x0210
+#define REG_G_INPUTS_CHANGE_REQ		0x021a
+#define REG_G_ACTIVE_PREV_CFG		0x021c
+#define REG_G_PREV_CFG_CHG		0x021e
+#define REG_G_PREV_OPEN_AFTER_CH	0x0220
+#define REG_G_PREV_CFG_ERROR		0x0222
+
+/* Preview control section. n = 0...4. */
+#define PREG(n, x)			((n) * 0x26 + x)
+#define REG_P_OUT_WIDTH(n)		PREG(n, 0x0242)
+#define REG_P_OUT_HEIGHT(n)		PREG(n, 0x0244)
+#define REG_P_FMT(n)			PREG(n, 0x0246)
+#define REG_P_MAX_OUT_RATE(n)		PREG(n, 0x0248)
+#define REG_P_MIN_OUT_RATE(n)		PREG(n, 0x024a)
+#define REG_P_PVI_MASK(n)		PREG(n, 0x024c)
+#define REG_P_CLK_INDEX(n)		PREG(n, 0x024e)
+#define REG_P_FR_RATE_TYPE(n)		PREG(n, 0x0250)
+#define  FR_RATE_DYNAMIC		0
+#define  FR_RATE_FIXED			1
+#define  FR_RATE_FIXED_ACCURATE		2
+#define REG_P_FR_RATE_Q_TYPE(n)		PREG(n, 0x0252)
+#define  FR_RATE_Q_BEST_FRRATE		1 /* Binning enabled */
+#define  FR_RATE_Q_BEST_QUALITY		2 /* Binning disabled */
+/* Frame period in 0.1 ms units */
+#define REG_P_MAX_FR_TIME(n)		PREG(n, 0x0254)
+#define REG_P_MIN_FR_TIME(n)		PREG(n, 0x0256)
+/* Conversion to REG_P_[MAX/MIN]_FR_TIME value; __t: time in us */
+#define  US_TO_FR_TIME(__t)		((__t) / 100)
+#define  S5K6AA_MIN_FR_TIME		33300  /* us */
+#define  S5K6AA_MAX_FR_TIME		650000 /* us */
+#define  S5K6AA_MAX_HIGHRES_FR_TIME	666    /* x100 us */
+/* The below 5 registers are for "device correction" values */
+#define REG_P_COLORTEMP(n)		PREG(n, 0x025e)
+#define REG_P_PREV_MIRROR(n)		PREG(n, 0x0262)
+
+/* Extended image property controls */
+/* Exposure time in 10 us units */
+#define REG_SF_USR_EXPOSURE_L		0x03c6
+#define REG_SF_USR_EXPOSURE_H		0x03c8
+#define REG_SF_USR_EXPOSURE_CHG		0x03ca
+#define REG_SF_USR_TOT_GAIN		0x03cc
+#define REG_SF_USR_TOT_GAIN_CHG		0x03ce
+#define REG_SF_RGAIN			0x03d0
+#define REG_SF_RGAIN_CHG		0x03d2
+#define REG_SF_GGAIN			0x03d4
+#define REG_SF_GGAIN_CHG		0x03d6
+#define REG_SF_BGAIN			0x03d8
+#define REG_SF_BGAIN_CHG		0x03da
+#define REG_SF_FLICKER_QUANT		0x03dc
+#define REG_SF_FLICKER_QUANT_CHG	0x03de
+
+/* Output interface (parallel/MIPI) setup */
+#define REG_OIF_EN_MIPI_LANES		0x03fa
+#define REG_OIF_EN_PACKETS		0x03fc
+#define REG_OIF_CFG_CHG			0x03fe
+
+/* Auto-algorithms enable mask */
+#define REG_DBG_AUTOALG_EN		0x0400
+#define  AALG_ALL_EN_MASK		(1 << 0)
+#define  AALG_AE_EN_MASK		(1 << 1)
+#define  AALG_DIVLEI_EN_MASK		(1 << 2)
+#define  AALG_WB_EN_MASK		(1 << 3)
+#define  AALG_FLICKER_EN_MASK		(1 << 5)
+#define  AALG_FIT_EN_MASK		(1 << 6)
+#define  AALG_WRHW_EN_MASK		(1 << 7)
+
+/* Firmware revision information */
+#define REG_FW_APIVER			0x012e
+#define  S5K6AAFX_FW_APIVER		0x0001
+#define REG_FW_REVISION			0x0130
+
+/* For now we use only one user configuration register set */
+#define S5K6AA_MAX_PRESETS		1
+
+static const char * const s5k6aa_supply_names[] = {
+	"vdd_core",	/* Digital core supply 1.5V (1.4V to 1.6V) */
+	"vdda",		/* Analog power supply 2.8V (2.6V to 3.0V) */
+	"vdd_reg",	/* Regulator input power 1.8V (1.7V to 1.9V)
+			   or 2.8V (2.6V to 3.0) */
+	"vddio",	/* I/O supply 1.8V (1.65V to 1.95V)
+			   or 2.8V (2.5V to 3.1V) */
+};
+#define S5K6AA_NUM_SUPPLIES ARRAY_SIZE(s5k6aa_supply_names)
+
+enum s5k6aa_gpio_id {
+	STBY,
+	RST,
+	GPIO_NUM,
+};
+
+struct s5k6aa_regval {
+	u16 addr;
+	u16 val;
+};
+
+struct s5k6aa_pixfmt {
+	enum v4l2_mbus_pixelcode code;
+	u32 colorspace;
+	/* REG_P_FMT(x) register value */
+	u16 reg_p_fmt;
+};
+
+struct s5k6aa_preset {
+	/* output pixel format and resolution */
+	struct v4l2_mbus_framefmt mbus_fmt;
+	u8 clk_id;
+	u8 index;
+};
+
+struct s5k6aa_ctrls {
+	struct v4l2_ctrl_handler handler;
+	/* Auto / manual white balance cluster */
+	struct v4l2_ctrl *awb;
+	struct v4l2_ctrl *gain_red;
+	struct v4l2_ctrl *gain_blue;
+	struct v4l2_ctrl *gain_green;
+	/* Mirror cluster */
+	struct v4l2_ctrl *hflip;
+	struct v4l2_ctrl *vflip;
+	/* Auto exposure / manual exposure and gain cluster */
+	struct v4l2_ctrl *auto_exp;
+	struct v4l2_ctrl *exposure;
+	struct v4l2_ctrl *gain;
+};
+
+struct s5k6aa_interval {
+	u16 reg_fr_time;
+	struct v4l2_fract interval;
+	/* Maximum rectangle for the interval */
+	struct v4l2_frmsize_discrete size;
+};
+
+struct s5k6aa {
+	struct v4l2_subdev sd;
+	struct media_pad pad;
+
+	enum v4l2_mbus_type bus_type;
+	u8 mipi_lanes;
+
+	int (*s_power)(int enable);
+	struct regulator_bulk_data supplies[S5K6AA_NUM_SUPPLIES];
+	struct s5k6aa_gpio gpio[GPIO_NUM];
+
+	/* external master clock frequency */
+	unsigned long mclk_frequency;
+	/* ISP internal master clock frequency */
+	u16 clk_fop;
+	/* output pixel clock frequency range */
+	u16 pclk_fmin;
+	u16 pclk_fmax;
+
+	unsigned int inv_hflip:1;
+	unsigned int inv_vflip:1;
+
+	/* protects the struct members below */
+	struct mutex lock;
+
+	/* sensor matrix scan window */
+	struct v4l2_rect ccd_rect;
+
+	struct s5k6aa_ctrls ctrls;
+	struct s5k6aa_preset presets[S5K6AA_MAX_PRESETS];
+	struct s5k6aa_preset *preset;
+	const struct s5k6aa_interval *fiv;
+
+	unsigned int streaming:1;
+	unsigned int apply_cfg:1;
+	unsigned int apply_crop:1;
+	unsigned int power;
+};
+
+static struct s5k6aa_regval s5k6aa_analog_config[] = {
+	/* Analog settings */
+	{ 0x112a, 0x0000 }, { 0x1132, 0x0000 },
+	{ 0x113e, 0x0000 }, { 0x115c, 0x0000 },
+	{ 0x1164, 0x0000 }, { 0x1174, 0x0000 },
+	{ 0x1178, 0x0000 }, { 0x077a, 0x0000 },
+	{ 0x077c, 0x0000 }, { 0x077e, 0x0000 },
+	{ 0x0780, 0x0000 }, { 0x0782, 0x0000 },
+	{ 0x0784, 0x0000 }, { 0x0786, 0x0000 },
+	{ 0x0788, 0x0000 }, { 0x07a2, 0x0000 },
+	{ 0x07a4, 0x0000 }, { 0x07a6, 0x0000 },
+	{ 0x07a8, 0x0000 }, { 0x07b6, 0x0000 },
+	{ 0x07b8, 0x0002 }, { 0x07ba, 0x0004 },
+	{ 0x07bc, 0x0004 }, { 0x07be, 0x0005 },
+	{ 0x07c0, 0x0005 }, { S5K6AA_TERM, 0 },
+};
+
+/* TODO: Add RGB888 and Bayer format */
+static const struct s5k6aa_pixfmt s5k6aa_formats[] = {
+	{ V4L2_MBUS_FMT_YUYV8_2X8,	V4L2_COLORSPACE_JPEG,	5 },
+	/* range 16-240 */
+	{ V4L2_MBUS_FMT_YUYV8_2X8,	V4L2_COLORSPACE_REC709,	6 },
+	{ V4L2_MBUS_FMT_RGB565_2X8_BE,	V4L2_COLORSPACE_JPEG,	0 },
+};
+
+static const struct s5k6aa_interval s5k6aa_intervals[] = {
+	{ 1000, {10000, 1000000}, {1280, 1024} }, /* 10 fps */
+	{ 666,  {15000, 1000000}, {1280, 1024} }, /* 15 fps */
+	{ 500,  {20000, 1000000}, {1280, 720} },  /* 20 fps */
+	{ 400,  {25000, 1000000}, {640, 480} },   /* 25 fps */
+	{ 333,  {33300, 1000000}, {640, 480} },   /* 30 fps */
+};
+
+#define S5K6AA_INTERVAL_DEF_INDEX 1 /* 15 fps */
+
+static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct s5k6aa, ctrls.handler)->sd;
+}
+
+static inline struct s5k6aa *to_s5k6aa(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct s5k6aa, sd);
+}
+
+/* Set initial values for all preview presets */
+static void s5k6aa_presets_data_init(struct s5k6aa *s5k6aa)
+{
+	struct s5k6aa_preset *preset = &s5k6aa->presets[0];
+	int i;
+
+	for (i = 0; i < S5K6AA_MAX_PRESETS; i++) {
+		preset->mbus_fmt.width	= S5K6AA_OUT_WIDTH_DEF;
+		preset->mbus_fmt.height	= S5K6AA_OUT_HEIGHT_DEF;
+		preset->mbus_fmt.code	= s5k6aa_formats[0].code;
+		preset->index		= i;
+		preset->clk_id		= 0;
+		preset++;
+	}
+
+	s5k6aa->fiv = &s5k6aa_intervals[S5K6AA_INTERVAL_DEF_INDEX];
+	s5k6aa->preset = &s5k6aa->presets[0];
+}
+
+static int s5k6aa_i2c_read(struct i2c_client *client, u16 addr, u16 *val)
+{
+	u8 wbuf[2] = {addr >> 8, addr & 0xFF};
+	struct i2c_msg msg[2];
+	u8 rbuf[2];
+	int ret;
+
+	msg[0].addr = client->addr;
+	msg[0].flags = 0;
+	msg[0].len = 2;
+	msg[0].buf = wbuf;
+
+	msg[1].addr = client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = 2;
+	msg[1].buf = rbuf;
+
+	ret = i2c_transfer(client->adapter, msg, 2);
+	*val = be16_to_cpu(*((u16 *)rbuf));
+
+	v4l2_dbg(3, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val);
+
+	return ret == 2 ? 0 : ret;
+}
+
+static int s5k6aa_i2c_write(struct i2c_client *client, u16 addr, u16 val)
+{
+	u8 buf[4] = {addr >> 8, addr & 0xFF, val >> 8, val & 0xFF};
+
+	int ret = i2c_master_send(client, buf, 4);
+	v4l2_dbg(3, debug, client, "i2c_write: 0x%04X : 0x%04x\n", addr, val);
+
+	return ret == 4 ? 0 : ret;
+}
+
+/* The command register write, assumes Command_Wr_addH = 0x7000. */
+static int s5k6aa_write(struct i2c_client *c, u16 addr, u16 val)
+{
+	int ret = s5k6aa_i2c_write(c, REG_CMDWR_ADDRL, addr);
+	if (ret)
+		return ret;
+	return s5k6aa_i2c_write(c, REG_CMDBUF0_ADDR, val);
+}
+
+/* The command register read, assumes Command_Rd_addH = 0x7000. */
+static int s5k6aa_read(struct i2c_client *client, u16 addr, u16 *val)
+{
+	int ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRL, addr);
+	if (ret)
+		return ret;
+	return s5k6aa_i2c_read(client, REG_CMDBUF0_ADDR, val);
+}
+
+static int s5k6aa_write_array(struct v4l2_subdev *sd,
+			      const struct s5k6aa_regval *msg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u16 addr_incr = 0;
+	int ret = 0;
+
+	while (msg->addr != S5K6AA_TERM) {
+		if (addr_incr != 2)
+			ret = s5k6aa_i2c_write(client, REG_CMDWR_ADDRL,
+					       msg->addr);
+		if (ret)
+			break;
+		ret = s5k6aa_i2c_write(client, REG_CMDBUF0_ADDR, msg->val);
+		if (ret)
+			break;
+		/* Assume that msg->addr is always less than 0xfffc */
+		addr_incr = (msg + 1)->addr - msg->addr;
+		msg++;
+	}
+
+	return ret;
+}
+
+/* Configure the AHB high address bytes for GTG registers access */
+static int s5k6aa_set_ahb_address(struct i2c_client *client)
+{
+	int ret = s5k6aa_i2c_write(client, AHB_MSB_ADDR_PTR, GEN_REG_OFFSH);
+	if (ret)
+		return ret;
+	ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRH, HOST_SWIF_OFFSH);
+	if (ret)
+		return ret;
+	return s5k6aa_i2c_write(client, REG_CMDWR_ADDRH, HOST_SWIF_OFFSH);
+}
+
+/**
+ * s5k6aa_configure_pixel_clock - apply ISP main clock/PLL configuration
+ *
+ * Configure the internal ISP PLL for the required output frequency.
+ * Locking: called with s5k6aa.lock mutex held.
+ */
+static int s5k6aa_configure_pixel_clocks(struct s5k6aa *s5k6aa)
+{
+	struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
+	unsigned long fmclk = s5k6aa->mclk_frequency / 1000;
+	u16 status;
+	int ret;
+
+	if (WARN(fmclk < MIN_MCLK_FREQ_KHZ || fmclk > MAX_MCLK_FREQ_KHZ,
+		 "Invalid clock frequency: %ld\n", fmclk))
+		return -EINVAL;
+
+	s5k6aa->pclk_fmin = PCLK_FREQ_MIN;
+	s5k6aa->pclk_fmax = PCLK_FREQ_MAX;
+	s5k6aa->clk_fop = SYS_PLL_OUT_FREQ;
+
+	/* External input clock frequency in kHz */
+	ret = s5k6aa_write(c, REG_I_INCLK_FREQ_H, fmclk >> 16);
+	if (!ret)
+		ret = s5k6aa_write(c, REG_I_INCLK_FREQ_L, fmclk & 0xFFFF);
+	if (!ret)
+		ret = s5k6aa_write(c, REG_I_USE_NPVI_CLOCKS, 1);
+	/* Internal PLL frequency */
+	if (!ret)
+		ret = s5k6aa_write(c, REG_I_OPCLK_4KHZ(0), s5k6aa->clk_fop);
+	if (!ret)
+		ret = s5k6aa_write(c, REG_I_MIN_OUTRATE_4KHZ(0),
+				   s5k6aa->pclk_fmin);
+	if (!ret)
+		ret = s5k6aa_write(c, REG_I_MAX_OUTRATE_4KHZ(0),
+				   s5k6aa->pclk_fmax);
+	if (!ret)
+		ret = s5k6aa_write(c, REG_I_INIT_PARAMS_UPDATED, 1);
+	if (!ret)
+		ret = s5k6aa_read(c, REG_I_ERROR_INFO, &status);
+
+	return ret ? ret : (status ? -EINVAL : 0);
+}
+
+/* Set horizontal and vertical image flipping */
+static int s5k6aa_set_mirror(struct s5k6aa *s5k6aa, int horiz_flip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+	int index = s5k6aa->preset->index;
+
+	unsigned int vflip = s5k6aa->ctrls.vflip->val ^ s5k6aa->inv_vflip;
+	unsigned int flip = (horiz_flip ^ s5k6aa->inv_hflip) | (vflip << 1);
+
+	return s5k6aa_write(client, REG_P_PREV_MIRROR(index), flip);
+}
+
+/* Configure auto/manual white balance and R/G/B gains */
+static int s5k6aa_set_awb(struct s5k6aa *s5k6aa, int awb)
+{
+	struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
+	struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls;
+	u16 reg;
+
+	int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, &reg);
+
+	if (!ret && !awb) {
+		ret = s5k6aa_write(c, REG_SF_RGAIN, ctrls->gain_red->val);
+		if (!ret)
+			ret = s5k6aa_write(c, REG_SF_RGAIN_CHG, 1);
+		if (ret)
+			return ret;
+
+		ret = s5k6aa_write(c, REG_SF_GGAIN, ctrls->gain_green->val);
+		if (!ret)
+			ret = s5k6aa_write(c, REG_SF_GGAIN_CHG, 1);
+		if (ret)
+			return ret;
+
+		ret = s5k6aa_write(c, REG_SF_BGAIN, ctrls->gain_blue->val);
+		if (!ret)
+			ret = s5k6aa_write(c, REG_SF_BGAIN_CHG, 1);
+	}
+	if (!ret) {
+		reg = awb ? reg | AALG_WB_EN_MASK : reg & ~AALG_WB_EN_MASK;
+		ret = s5k6aa_write(c, REG_DBG_AUTOALG_EN, reg);
+	}
+
+	return ret;
+}
+
+/* Program FW with exposure time, 'exposure' in us units */
+static int s5k6aa_set_user_exposure(struct i2c_client *client, int exposure)
+{
+	unsigned int time = exposure / 10;
+
+	int ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_L, time & 0xffff);
+	if (!ret)
+		ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_H, time >> 16);
+	if (ret)
+		return ret;
+	return s5k6aa_write(client, REG_SF_USR_EXPOSURE_CHG, 1);
+}
+
+static int s5k6aa_set_user_gain(struct i2c_client *client, int gain)
+{
+	int ret = s5k6aa_write(client, REG_SF_USR_TOT_GAIN, gain);
+	if (ret)
+		return ret;
+	return s5k6aa_write(client, REG_SF_USR_TOT_GAIN_CHG, 1);
+}
+
+/* Set auto/manual exposure and total gain */
+static int s5k6aa_set_auto_exposure(struct s5k6aa *s5k6aa, int value)
+{
+	struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
+	unsigned int exp_time = s5k6aa->ctrls.exposure->val;
+	u16 auto_alg;
+
+	int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, &auto_alg);
+	if (ret)
+		return ret;
+
+	v4l2_dbg(1, debug, c, "man_exp: %d, auto_exp: %d, a_alg: 0x%x\n",
+		 exp_time, value, auto_alg);
+
+	if (value == V4L2_EXPOSURE_AUTO) {
+		auto_alg |= AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK;
+	} else {
+		ret = s5k6aa_set_user_exposure(c, exp_time);
+		if (ret)
+			return ret;
+		ret = s5k6aa_set_user_gain(c, s5k6aa->ctrls.gain->val);
+		if (ret)
+			return ret;
+		auto_alg &= ~(AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK);
+	}
+
+	return s5k6aa_write(c, REG_DBG_AUTOALG_EN, auto_alg);
+}
+
+static int s5k6aa_set_anti_flicker(struct s5k6aa *s5k6aa, int value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+	u16 auto_alg;
+	int ret;
+
+	ret = s5k6aa_read(client, REG_DBG_AUTOALG_EN, &auto_alg);
+	if (ret)
+		return ret;
+
+	if (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) {
+		auto_alg |= AALG_FLICKER_EN_MASK;
+	} else {
+		auto_alg &= ~AALG_FLICKER_EN_MASK;
+		/* The V4L2_CID_LINE_FREQUENCY control values match
+		 * the register values */
+		ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT, value);
+		if (ret)
+			return ret;
+		ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT_CHG, 1);
+		if (ret)
+			return ret;
+	}
+
+	return s5k6aa_write(client, REG_DBG_AUTOALG_EN, auto_alg);
+}
+
+static int s5k6aa_set_colorfx(struct s5k6aa *s5k6aa, int val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+	static const struct v4l2_control colorfx[] = {
+		{ V4L2_COLORFX_NONE,	 0 },
+		{ V4L2_COLORFX_BW,	 1 },
+		{ V4L2_COLORFX_NEGATIVE, 2 },
+		{ V4L2_COLORFX_SEPIA,	 3 },
+		{ V4L2_COLORFX_SKY_BLUE, 4 },
+		{ V4L2_COLORFX_SKETCH,	 5 },
+	};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(colorfx); i++) {
+		if (colorfx[i].id == val)
+			return s5k6aa_write(client, REG_G_SPEC_EFFECTS,
+					    colorfx[i].value);
+	}
+	return -EINVAL;
+}
+
+static int s5k6aa_preview_config_status(struct i2c_client *client)
+{
+	u16 error = 0;
+	int ret = s5k6aa_read(client, REG_G_PREV_CFG_ERROR, &error);
+
+	v4l2_dbg(1, debug, client, "error: 0x%x (%d)\n", error, ret);
+	return ret ? ret : (error ? -EINVAL : 0);
+}
+
+static int s5k6aa_get_pixfmt_index(struct s5k6aa *s5k6aa,
+				   struct v4l2_mbus_framefmt *mf)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(s5k6aa_formats); i++)
+		if (mf->colorspace == s5k6aa_formats[i].colorspace &&
+		    mf->code == s5k6aa_formats[i].code)
+			return i;
+	return 0;
+}
+
+static int s5k6aa_set_output_framefmt(struct s5k6aa *s5k6aa,
+				      struct s5k6aa_preset *preset)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+	int fmt_index = s5k6aa_get_pixfmt_index(s5k6aa, &preset->mbus_fmt);
+	int ret;
+
+	ret = s5k6aa_write(client, REG_P_OUT_WIDTH(preset->index),
+			   preset->mbus_fmt.width);
+	if (!ret)
+		ret = s5k6aa_write(client, REG_P_OUT_HEIGHT(preset->index),
+				   preset->mbus_fmt.height);
+	if (!ret)
+		ret = s5k6aa_write(client, REG_P_FMT(preset->index),
+				   s5k6aa_formats[fmt_index].reg_p_fmt);
+	return ret;
+}
+
+static int s5k6aa_set_input_params(struct s5k6aa *s5k6aa)
+{
+	struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
+	struct v4l2_rect *r = &s5k6aa->ccd_rect;
+	int ret;
+
+	ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_WIDTH, r->width);
+	if (!ret)
+		ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_HEIGHT, r->height);
+	if (!ret)
+		ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_XOFFS, r->left);
+	if (!ret)
+		ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_YOFFS, r->top);
+	if (!ret)
+		ret = s5k6aa_write(c, REG_G_INPUTS_CHANGE_REQ, 1);
+	if (!ret)
+		s5k6aa->apply_crop = 0;
+
+	return ret;
+}
+
+/**
+ * s5k6aa_configure_video_bus - configure the video output interface
+ * @bus_type: video bus type: parallel or MIPI-CSI
+ * @nlanes: number of MIPI lanes to be used (MIPI-CSI only)
+ *
+ * Note: Only parallel bus operation has been tested.
+ */
+static int s5k6aa_configure_video_bus(struct s5k6aa *s5k6aa,
+				      enum v4l2_mbus_type bus_type, int nlanes)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+	u16 cfg = 0;
+	int ret;
+
+	/*
+	 * TODO: The sensor is supposed to support BT.601 and BT.656
+	 * but there is nothing indicating how to switch between both
+	 * in the datasheet. For now default BT.601 interface is assumed.
+	 */
+	if (bus_type == V4L2_MBUS_CSI2)
+		cfg = nlanes;
+	else if (bus_type != V4L2_MBUS_PARALLEL)
+		return -EINVAL;
+
+	ret = s5k6aa_write(client, REG_OIF_EN_MIPI_LANES, cfg);
+	if (ret)
+		return ret;
+	return s5k6aa_write(client, REG_OIF_CFG_CHG, 1);
+}
+
+/* This function should be called when switching to new user configuration set*/
+static int s5k6aa_new_config_sync(struct i2c_client *client, int timeout,
+				  int cid)
+{
+	unsigned long end = jiffies + msecs_to_jiffies(timeout);
+	u16 reg = 1;
+	int ret;
+
+	ret = s5k6aa_write(client, REG_G_ACTIVE_PREV_CFG, cid);
+	if (!ret)
+		ret = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
+	if (!ret)
+		ret = s5k6aa_write(client, REG_G_NEW_CFG_SYNC, 1);
+	if (timeout == 0)
+		return ret;
+
+	while (ret >= 0 && time_is_after_jiffies(end)) {
+		ret = s5k6aa_read(client, REG_G_NEW_CFG_SYNC, &reg);
+		if (!reg)
+			return 0;
+		usleep_range(1000, 5000);
+	}
+	return ret ? ret : -ETIMEDOUT;
+}
+
+/**
+ * s5k6aa_set_prev_config - write user preview register set
+ *
+ * Configure output resolution and color fromat, pixel clock
+ * frequency range, device frame rate type and frame period range.
+ */
+static int s5k6aa_set_prev_config(struct s5k6aa *s5k6aa,
+				  struct s5k6aa_preset *preset)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+	int idx = preset->index;
+	u16 frame_rate_q;
+	int ret;
+
+	if (s5k6aa->fiv->reg_fr_time >= S5K6AA_MAX_HIGHRES_FR_TIME)
+		frame_rate_q = FR_RATE_Q_BEST_FRRATE;
+	else
+		frame_rate_q = FR_RATE_Q_BEST_QUALITY;
+
+	ret = s5k6aa_set_output_framefmt(s5k6aa, preset);
+	if (!ret)
+		ret = s5k6aa_write(client, REG_P_MAX_OUT_RATE(idx),
+				   s5k6aa->pclk_fmax);
+	if (!ret)
+		ret = s5k6aa_write(client, REG_P_MIN_OUT_RATE(idx),
+				   s5k6aa->pclk_fmin);
+	if (!ret)
+		ret = s5k6aa_write(client, REG_P_CLK_INDEX(idx),
+				   preset->clk_id);
+	if (!ret)
+		ret = s5k6aa_write(client, REG_P_FR_RATE_TYPE(idx),
+				   FR_RATE_DYNAMIC);
+	if (!ret)
+		ret = s5k6aa_write(client, REG_P_FR_RATE_Q_TYPE(idx),
+				   frame_rate_q);
+	if (!ret)
+		ret = s5k6aa_write(client, REG_P_MAX_FR_TIME(idx),
+				   s5k6aa->fiv->reg_fr_time + 33);
+	if (!ret)
+		ret = s5k6aa_write(client, REG_P_MIN_FR_TIME(idx),
+				   s5k6aa->fiv->reg_fr_time - 33);
+	if (!ret)
+		ret = s5k6aa_new_config_sync(client, 250, idx);
+	if (!ret)
+		ret = s5k6aa_preview_config_status(client);
+	if (!ret)
+		s5k6aa->apply_cfg = 0;
+
+	v4l2_dbg(1, debug, client, "Frame interval: %d +/- 3.3ms. (%d)\n",
+		 s5k6aa->fiv->reg_fr_time, ret);
+	return ret;
+}
+
+/**
+ * s5k6aa_initialize_isp - basic ISP MCU initialization
+ *
+ * Configure AHB addresses for registers read/write; configure PLLs for
+ * required output pixel clock. The ISP power supply needs to be already
+ * enabled, with an optional H/W reset.
+ * Locking: called with s5k6aa.lock mutex held.
+ */
+static int s5k6aa_initialize_isp(struct v4l2_subdev *sd)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+	int ret;
+
+	s5k6aa->apply_crop = 1;
+	s5k6aa->apply_cfg = 1;
+	msleep(100);
+
+	ret = s5k6aa_set_ahb_address(client);
+	if (ret)
+		return ret;
+	ret = s5k6aa_configure_video_bus(s5k6aa, s5k6aa->bus_type,
+					 s5k6aa->mipi_lanes);
+	if (ret)
+		return ret;
+	ret = s5k6aa_write_array(sd, s5k6aa_analog_config);
+	if (ret)
+		return ret;
+	msleep(20);
+
+	return s5k6aa_configure_pixel_clocks(s5k6aa);
+}
+
+static int s5k6aa_gpio_set_value(struct s5k6aa *priv, int id, u32 val)
+{
+	if (!gpio_is_valid(priv->gpio[id].gpio))
+		return 0;
+	gpio_set_value(priv->gpio[id].gpio, !!val);
+	return 1;
+}
+
+static int s5k6aa_gpio_assert(struct s5k6aa *priv, int id)
+{
+	return s5k6aa_gpio_set_value(priv, id, priv->gpio[id].level);
+}
+
+static int s5k6aa_gpio_deassert(struct s5k6aa *priv, int id)
+{
+	return s5k6aa_gpio_set_value(priv, id, !priv->gpio[id].level);
+}
+
+static int __s5k6aa_power_on(struct s5k6aa *s5k6aa)
+{
+	int ret;
+
+	ret = regulator_bulk_enable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
+	if (ret)
+		return ret;
+	if (s5k6aa_gpio_deassert(s5k6aa, STBY))
+		usleep_range(150, 200);
+
+	if (s5k6aa->s_power)
+		ret = s5k6aa->s_power(1);
+	usleep_range(4000, 4000);
+
+	if (s5k6aa_gpio_deassert(s5k6aa, RST))
+		msleep(20);
+
+	return ret;
+}
+
+static int __s5k6aa_power_off(struct s5k6aa *s5k6aa)
+{
+	int ret;
+
+	if (s5k6aa_gpio_assert(s5k6aa, RST))
+		usleep_range(100, 150);
+
+	if (s5k6aa->s_power) {
+		ret = s5k6aa->s_power(0);
+		if (ret)
+			return ret;
+	}
+	if (s5k6aa_gpio_assert(s5k6aa, STBY))
+		usleep_range(50, 100);
+	s5k6aa->streaming = 0;
+
+	return regulator_bulk_disable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
+}
+
+/*
+ * V4L2 subdev core and video operations
+ */
+static int s5k6aa_set_power(struct v4l2_subdev *sd, int on)
+{
+	struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+	int ret = 0;
+
+	mutex_lock(&s5k6aa->lock);
+
+	if (!on == s5k6aa->power) {
+		if (on) {
+			ret = __s5k6aa_power_on(s5k6aa);
+			if (!ret)
+				ret = s5k6aa_initialize_isp(sd);
+		} else {
+			ret = __s5k6aa_power_off(s5k6aa);
+		}
+
+		if (!ret)
+			s5k6aa->power += on ? 1 : -1;
+	}
+
+	mutex_unlock(&s5k6aa->lock);
+
+	if (!on || ret || s5k6aa->power != 1)
+		return ret;
+
+	return v4l2_ctrl_handler_setup(sd->ctrl_handler);
+}
+
+static int __s5k6aa_stream(struct s5k6aa *s5k6aa, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+	int ret = 0;
+
+	ret = s5k6aa_write(client, REG_G_ENABLE_PREV, enable);
+	if (!ret)
+		ret = s5k6aa_write(client, REG_G_ENABLE_PREV_CHG, 1);
+	if (!ret)
+		s5k6aa->streaming = enable;
+
+	return ret;
+}
+
+static int s5k6aa_s_stream(struct v4l2_subdev *sd, int on)
+{
+	struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+	int ret = 0;
+
+	mutex_lock(&s5k6aa->lock);
+
+	if (s5k6aa->streaming == !on) {
+		if (!ret && s5k6aa->apply_cfg)
+			ret = s5k6aa_set_prev_config(s5k6aa, s5k6aa->preset);
+		if (s5k6aa->apply_crop)
+			ret = s5k6aa_set_input_params(s5k6aa);
+		if (!ret)
+			ret = __s5k6aa_stream(s5k6aa, !!on);
+	}
+	mutex_unlock(&s5k6aa->lock);
+
+	return ret;
+}
+
+static int s5k6aa_g_frame_interval(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_frame_interval *fi)
+{
+	struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+
+	mutex_lock(&s5k6aa->lock);
+	fi->interval = s5k6aa->fiv->interval;
+	mutex_unlock(&s5k6aa->lock);
+
+	return 0;
+}
+
+static int __s5k6aa_set_frame_interval(struct s5k6aa *s5k6aa,
+				       struct v4l2_subdev_frame_interval *fi)
+{
+	struct v4l2_mbus_framefmt *mbus_fmt = &s5k6aa->preset->mbus_fmt;
+	const struct s5k6aa_interval *fiv = &s5k6aa_intervals[0];
+	unsigned int err, min_err = UINT_MAX;
+	unsigned int i, fr_time;
+
+	if (fi->interval.denominator == 0)
+		return -EINVAL;
+
+	fr_time = fi->interval.numerator * 10000 / fi->interval.denominator;
+
+	for (i = 0; i < ARRAY_SIZE(s5k6aa_intervals); i++) {
+		const struct s5k6aa_interval *iv = &s5k6aa_intervals[i];
+
+		if (mbus_fmt->width > iv->size.width ||
+		    mbus_fmt->height > iv->size.height)
+			continue;
+
+		err = abs(iv->reg_fr_time - fr_time);
+		if (err < min_err) {
+			fiv = iv;
+			min_err = err;
+		}
+	}
+	s5k6aa->fiv = fiv;
+
+	v4l2_dbg(1, debug, &s5k6aa->sd, "Changed frame interval to %d us\n",
+		 fiv->reg_fr_time * 100);
+	return 0;
+}
+
+static int s5k6aa_s_frame_interval(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_frame_interval *fi)
+{
+	struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+	int ret;
+
+	v4l2_dbg(1, debug, sd, "Setting %d/%d frame interval\n",
+		 fi->interval.numerator, fi->interval.denominator);
+
+	mutex_lock(&s5k6aa->lock);
+	ret = __s5k6aa_set_frame_interval(s5k6aa, fi);
+	s5k6aa->apply_cfg = 1;
+
+	mutex_unlock(&s5k6aa->lock);
+	return ret;
+}
+
+/*
+ * V4L2 subdev pad level and video operations
+ */
+static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd,
+			      struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_frame_interval_enum *fie)
+{
+	struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+	const struct s5k6aa_interval *fi;
+	int ret = 0;
+
+	if (fie->index > ARRAY_SIZE(s5k6aa_intervals))
+		return -EINVAL;
+
+	v4l_bound_align_image(&fie->width, S5K6AA_WIN_WIDTH_MIN,
+			      S5K6AA_WIN_WIDTH_MAX, 1,
+			      &fie->height, S5K6AA_WIN_HEIGHT_MIN,
+			      S5K6AA_WIN_HEIGHT_MAX, 1, 0);
+
+	mutex_lock(&s5k6aa->lock);
+	fi = &s5k6aa_intervals[fie->index];
+	if (fie->width > fi->size.width || fie->height > fi->size.height)
+		ret = -EINVAL;
+	else
+		fie->interval = fi->interval;
+	mutex_unlock(&s5k6aa->lock);
+
+	return ret;
+}
+
+static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->index >= ARRAY_SIZE(s5k6aa_formats))
+		return -EINVAL;
+
+	code->code = s5k6aa_formats[code->index].code;
+	return 0;
+}
+
+static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_frame_size_enum *fse)
+{
+	int i = ARRAY_SIZE(s5k6aa_formats);
+
+	if (fse->index > 0)
+		return -EINVAL;
+
+	while (--i)
+		if (fse->code == s5k6aa_formats[i].code)
+			break;
+
+	fse->code = s5k6aa_formats[i].code;
+	fse->min_width  = S5K6AA_WIN_WIDTH_MIN;
+	fse->max_width  = S5K6AA_WIN_WIDTH_MAX;
+	fse->max_height = S5K6AA_WIN_HEIGHT_MIN;
+	fse->min_height = S5K6AA_WIN_HEIGHT_MAX;
+
+	return 0;
+}
+
+static struct v4l2_rect *
+__s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa, struct v4l2_subdev_fh *fh,
+		       enum v4l2_subdev_format_whence which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		return &s5k6aa->ccd_rect;
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_crop(fh, 0);
+
+	return NULL;
+}
+
+static void s5k6aa_try_format(struct s5k6aa *s5k6aa,
+			      struct v4l2_mbus_framefmt *mf)
+{
+	unsigned int index;
+
+	v4l_bound_align_image(&mf->width, S5K6AA_WIN_WIDTH_MIN,
+			      S5K6AA_WIN_WIDTH_MAX, 1,
+			      &mf->height, S5K6AA_WIN_HEIGHT_MIN,
+			      S5K6AA_WIN_HEIGHT_MAX, 1, 0);
+
+	if (mf->colorspace != V4L2_COLORSPACE_JPEG &&
+	    mf->colorspace != V4L2_COLORSPACE_REC709)
+		mf->colorspace = V4L2_COLORSPACE_JPEG;
+
+	index = s5k6aa_get_pixfmt_index(s5k6aa, mf);
+
+	mf->colorspace	= s5k6aa_formats[index].colorspace;
+	mf->code	= s5k6aa_formats[index].code;
+	mf->field	= V4L2_FIELD_NONE;
+}
+
+static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			  struct v4l2_subdev_format *fmt)
+{
+	struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+	struct v4l2_mbus_framefmt *mf;
+
+	memset(fmt->reserved, 0, sizeof(fmt->reserved));
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		mf = v4l2_subdev_get_try_format(fh, 0);
+		fmt->format = *mf;
+		return 0;
+	}
+
+	mutex_lock(&s5k6aa->lock);
+	fmt->format = s5k6aa->preset->mbus_fmt;
+	mutex_unlock(&s5k6aa->lock);
+
+	return 0;
+}
+
+static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			  struct v4l2_subdev_format *fmt)
+{
+	struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+	struct s5k6aa_preset *preset = s5k6aa->preset;
+	struct v4l2_mbus_framefmt *mf;
+	struct v4l2_rect *crop;
+	int ret = 0;
+
+	mutex_lock(&s5k6aa->lock);
+	s5k6aa_try_format(s5k6aa, &fmt->format);
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+		crop = v4l2_subdev_get_try_crop(fh, 0);
+	} else {
+		if (s5k6aa->streaming) {
+			ret = -EBUSY;
+		} else {
+			mf = &preset->mbus_fmt;
+			crop = &s5k6aa->ccd_rect;
+			s5k6aa->apply_cfg = 1;
+		}
+	}
+
+	if (ret == 0) {
+		struct v4l2_subdev_frame_interval fiv = {
+			.interval = {0, 1}
+		};
+
+		*mf = fmt->format;
+		/*
+		 * Make sure the crop window is valid, i.e. its size is
+		 * greater than the output window, as the ISP supports
+		 * only down-scaling.
+		 */
+		crop->width = clamp_t(unsigned int, crop->width, mf->width,
+				      S5K6AA_WIN_WIDTH_MAX);
+		crop->height = clamp_t(unsigned int, crop->height, mf->height,
+				       S5K6AA_WIN_HEIGHT_MAX);
+		crop->left = clamp_t(unsigned int, crop->left, 0,
+				     S5K6AA_WIN_WIDTH_MAX - crop->width);
+		crop->top  = clamp_t(unsigned int, crop->top, 0,
+				     S5K6AA_WIN_HEIGHT_MAX - crop->height);
+
+		/* Reset to minimum possible frame interval */
+		ret = __s5k6aa_set_frame_interval(s5k6aa, &fiv);
+	}
+	mutex_unlock(&s5k6aa->lock);
+
+	return ret;
+}
+
+static int s5k6aa_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			   struct v4l2_subdev_crop *crop)
+{
+	struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+	struct v4l2_rect *rect;
+
+	memset(crop->reserved, 0, sizeof(crop->reserved));
+	mutex_lock(&s5k6aa->lock);
+
+	rect = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which);
+	if (rect)
+		crop->rect = *rect;
+
+	mutex_unlock(&s5k6aa->lock);
+
+	v4l2_dbg(1, debug, sd, "Current crop rectangle: (%d,%d)/%dx%d\n",
+		 rect->left, rect->top, rect->width, rect->height);
+
+	return 0;
+}
+
+static int s5k6aa_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			   struct v4l2_subdev_crop *crop)
+{
+	struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+	struct v4l2_mbus_framefmt *mf;
+	unsigned int max_x, max_y;
+	struct v4l2_rect *crop_r;
+
+	mutex_lock(&s5k6aa->lock);
+	crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which);
+
+	if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		mf = &s5k6aa->preset->mbus_fmt;
+		s5k6aa->apply_crop = 1;
+	} else {
+		mf = v4l2_subdev_get_try_format(fh, 0);
+	}
+	v4l_bound_align_image(&crop->rect.width, mf->width,
+			      S5K6AA_WIN_WIDTH_MAX, 1,
+			      &crop->rect.height, mf->height,
+			      S5K6AA_WIN_HEIGHT_MAX, 1, 0);
+
+	max_x = (S5K6AA_WIN_WIDTH_MAX - crop->rect.width) & ~1;
+	max_y = (S5K6AA_WIN_HEIGHT_MAX - crop->rect.height) & ~1;
+
+	crop->rect.left = clamp_t(unsigned int, crop->rect.left, 0, max_x);
+	crop->rect.top  = clamp_t(unsigned int, crop->rect.top, 0, max_y);
+
+	*crop_r = crop->rect;
+
+	mutex_unlock(&s5k6aa->lock);
+
+	v4l2_dbg(1, debug, sd, "Set crop rectangle: (%d,%d)/%dx%d\n",
+		 crop_r->left, crop_r->top, crop_r->width, crop_r->height);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_pad_ops s5k6aa_pad_ops = {
+	.enum_mbus_code		= s5k6aa_enum_mbus_code,
+	.enum_frame_size	= s5k6aa_enum_frame_size,
+	.enum_frame_interval	= s5k6aa_enum_frame_interval,
+	.get_fmt		= s5k6aa_get_fmt,
+	.set_fmt		= s5k6aa_set_fmt,
+	.get_crop		= s5k6aa_get_crop,
+	.set_crop		= s5k6aa_set_crop,
+};
+
+static const struct v4l2_subdev_video_ops s5k6aa_video_ops = {
+	.g_frame_interval	= s5k6aa_g_frame_interval,
+	.s_frame_interval	= s5k6aa_s_frame_interval,
+	.s_stream		= s5k6aa_s_stream,
+};
+
+/*
+ * V4L2 subdev controls
+ */
+
+static int s5k6aa_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+	int idx, err = 0;
+
+	v4l2_dbg(1, debug, sd, "ctrl: 0x%x, value: %d\n", ctrl->id, ctrl->val);
+
+	mutex_lock(&s5k6aa->lock);
+	/*
+	 * If the device is not powered up by the host driver do
+	 * not apply any controls to H/W at this time. Instead
+	 * the controls will be restored right after power-up.
+	 */
+	if (s5k6aa->power == 0)
+		goto unlock;
+	idx = s5k6aa->preset->index;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		err = s5k6aa_set_awb(s5k6aa, ctrl->val);
+		break;
+
+	case V4L2_CID_BRIGHTNESS:
+		err = s5k6aa_write(client, REG_USER_BRIGHTNESS, ctrl->val);
+		break;
+
+	case V4L2_CID_COLORFX:
+		err = s5k6aa_set_colorfx(s5k6aa, ctrl->val);
+		break;
+
+	case V4L2_CID_CONTRAST:
+		err = s5k6aa_write(client, REG_USER_CONTRAST, ctrl->val);
+		break;
+
+	case V4L2_CID_EXPOSURE_AUTO:
+		err = s5k6aa_set_auto_exposure(s5k6aa, ctrl->val);
+		break;
+
+	case V4L2_CID_HFLIP:
+		err = s5k6aa_set_mirror(s5k6aa, ctrl->val);
+		if (err)
+			break;
+		err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
+		break;
+
+	case V4L2_CID_POWER_LINE_FREQUENCY:
+		err = s5k6aa_set_anti_flicker(s5k6aa, ctrl->val);
+		break;
+
+	case V4L2_CID_SATURATION:
+		err = s5k6aa_write(client, REG_USER_SATURATION, ctrl->val);
+		break;
+
+	case V4L2_CID_SHARPNESS:
+		err = s5k6aa_write(client, REG_USER_SHARPBLUR, ctrl->val);
+		break;
+
+	case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
+		err = s5k6aa_write(client, REG_P_COLORTEMP(idx), ctrl->val);
+		if (err)
+			break;
+		err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
+		break;
+	}
+unlock:
+	mutex_unlock(&s5k6aa->lock);
+	return err;
+}
+
+static const struct v4l2_ctrl_ops s5k6aa_ctrl_ops = {
+	.s_ctrl	= s5k6aa_s_ctrl,
+};
+
+static int s5k6aa_log_status(struct v4l2_subdev *sd)
+{
+	v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
+	return 0;
+}
+
+#define V4L2_CID_RED_GAIN	(V4L2_CTRL_CLASS_CAMERA | 0x1001)
+#define V4L2_CID_GREEN_GAIN	(V4L2_CTRL_CLASS_CAMERA | 0x1002)
+#define V4L2_CID_BLUE_GAIN	(V4L2_CTRL_CLASS_CAMERA | 0x1003)
+
+static const struct v4l2_ctrl_config s5k6aa_ctrls[] = {
+	{
+		.ops	= &s5k6aa_ctrl_ops,
+		.id	= V4L2_CID_RED_GAIN,
+		.type	= V4L2_CTRL_TYPE_INTEGER,
+		.name	= "Gain, Red",
+		.min	= 0,
+		.max	= 256,
+		.def	= 127,
+		.step	= 1,
+	}, {
+		.ops	= &s5k6aa_ctrl_ops,
+		.id	= V4L2_CID_GREEN_GAIN,
+		.type	= V4L2_CTRL_TYPE_INTEGER,
+		.name	= "Gain, Green",
+		.min	= 0,
+		.max	= 256,
+		.def	= 127,
+		.step	= 1,
+	}, {
+		.ops	= &s5k6aa_ctrl_ops,
+		.id	= V4L2_CID_BLUE_GAIN,
+		.type	= V4L2_CTRL_TYPE_INTEGER,
+		.name	= "Gain, Blue",
+		.min	= 0,
+		.max	= 256,
+		.def	= 127,
+		.step	= 1,
+	},
+};
+
+static int s5k6aa_initialize_ctrls(struct s5k6aa *s5k6aa)
+{
+	const struct v4l2_ctrl_ops *ops = &s5k6aa_ctrl_ops;
+	struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls;
+	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+
+	int ret = v4l2_ctrl_handler_init(hdl, 16);
+	if (ret)
+		return ret;
+	/* Auto white balance cluster */
+	ctrls->awb = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE,
+				       0, 1, 1, 1);
+	ctrls->gain_red = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[0], NULL);
+	ctrls->gain_green = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[1], NULL);
+	ctrls->gain_blue = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[2], NULL);
+	v4l2_ctrl_auto_cluster(4, &ctrls->awb, 0, false);
+
+	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
+	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_cluster(2, &ctrls->hflip);
+
+	ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
+				V4L2_CID_EXPOSURE_AUTO,
+				V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO);
+	/* Exposure time: x 1 us */
+	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
+					    0, 6000000U, 1, 100000U);
+	/* Total gain: 256 <=> 1x */
+	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
+					0, 256, 1, 256);
+	v4l2_ctrl_auto_cluster(3, &ctrls->auto_exp, 0, false);
+
+	v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_POWER_LINE_FREQUENCY,
+			       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
+			       V4L2_CID_POWER_LINE_FREQUENCY_AUTO);
+
+	v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_COLORFX,
+			       V4L2_COLORFX_SKY_BLUE, ~0x6f, V4L2_COLORFX_NONE);
+
+	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+			  0, 256, 1, 0);
+
+	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0);
+	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -127, 127, 1, 0);
+	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0);
+	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -127, 127, 1, 0);
+
+	if (hdl->error) {
+		ret = hdl->error;
+		v4l2_ctrl_handler_free(hdl);
+		return ret;
+	}
+
+	s5k6aa->sd.ctrl_handler = hdl;
+	return 0;
+}
+
+/*
+ * V4L2 subdev internal operations
+ */
+static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
+	struct v4l2_rect *crop = v4l2_subdev_get_try_crop(fh, 0);
+
+	format->colorspace = s5k6aa_formats[0].colorspace;
+	format->code = s5k6aa_formats[0].code;
+	format->width = S5K6AA_OUT_WIDTH_DEF;
+	format->height = S5K6AA_OUT_HEIGHT_DEF;
+	format->field = V4L2_FIELD_NONE;
+
+	crop->width = S5K6AA_WIN_WIDTH_MAX;
+	crop->height = S5K6AA_WIN_HEIGHT_MAX;
+	crop->left = 0;
+	crop->top = 0;
+
+	return 0;
+}
+
+static int s5k6aa_check_fw_revision(struct s5k6aa *s5k6aa)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+	u16 api_ver = 0, fw_rev = 0;
+
+	int ret = s5k6aa_set_ahb_address(client);
+
+	if (!ret)
+		ret = s5k6aa_read(client, REG_FW_APIVER, &api_ver);
+	if (!ret)
+		ret = s5k6aa_read(client, REG_FW_REVISION, &fw_rev);
+	if (ret) {
+		v4l2_err(&s5k6aa->sd, "FW revision check failed!\n");
+		return ret;
+	}
+
+	v4l2_info(&s5k6aa->sd, "FW API ver.: 0x%X, FW rev.: 0x%X\n",
+		  api_ver, fw_rev);
+
+	return api_ver == S5K6AAFX_FW_APIVER ? 0 : -ENODEV;
+}
+
+static int s5k6aa_registered(struct v4l2_subdev *sd)
+{
+	struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+	int ret;
+
+	mutex_lock(&s5k6aa->lock);
+	ret = __s5k6aa_power_on(s5k6aa);
+	if (!ret) {
+		msleep(100);
+		ret = s5k6aa_check_fw_revision(s5k6aa);
+		__s5k6aa_power_off(s5k6aa);
+	}
+	mutex_unlock(&s5k6aa->lock);
+
+	return ret;
+}
+
+static const struct v4l2_subdev_internal_ops s5k6aa_subdev_internal_ops = {
+	.registered = s5k6aa_registered,
+	.open = s5k6aa_open,
+};
+
+static const struct v4l2_subdev_core_ops s5k6aa_core_ops = {
+	.s_power = s5k6aa_set_power,
+	.log_status = s5k6aa_log_status,
+};
+
+static const struct v4l2_subdev_ops s5k6aa_subdev_ops = {
+	.core = &s5k6aa_core_ops,
+	.pad = &s5k6aa_pad_ops,
+	.video = &s5k6aa_video_ops,
+};
+
+/*
+ * GPIO setup
+ */
+static int s5k6aa_configure_gpio(int nr, int val, const char *name)
+{
+	unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+	int ret;
+
+	if (!gpio_is_valid(nr))
+		return 0;
+	ret = gpio_request_one(nr, flags, name);
+	if (!ret)
+		gpio_export(nr, 0);
+	return ret;
+}
+
+static void s5k6aa_free_gpios(struct s5k6aa *s5k6aa)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(s5k6aa->gpio); i++) {
+		if (!gpio_is_valid(s5k6aa->gpio[i].gpio))
+			continue;
+		gpio_free(s5k6aa->gpio[i].gpio);
+		s5k6aa->gpio[i].gpio = -EINVAL;
+	}
+}
+
+static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa,
+				  const struct s5k6aa_platform_data *pdata)
+{
+	const struct s5k6aa_gpio *gpio = &pdata->gpio_stby;
+	int ret;
+
+	s5k6aa->gpio[STBY].gpio = -EINVAL;
+	s5k6aa->gpio[RST].gpio  = -EINVAL;
+
+	ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_STBY");
+	if (ret) {
+		s5k6aa_free_gpios(s5k6aa);
+		return ret;
+	}
+	s5k6aa->gpio[STBY] = *gpio;
+	if (gpio_is_valid(gpio->gpio))
+		gpio_set_value(gpio->gpio, 0);
+
+	gpio = &pdata->gpio_reset;
+	ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_RST");
+	if (ret) {
+		s5k6aa_free_gpios(s5k6aa);
+		return ret;
+	}
+	s5k6aa->gpio[RST] = *gpio;
+	if (gpio_is_valid(gpio->gpio))
+		gpio_set_value(gpio->gpio, 0);
+
+	return 0;
+}
+
+static int s5k6aa_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	const struct s5k6aa_platform_data *pdata = client->dev.platform_data;
+	struct v4l2_subdev *sd;
+	struct s5k6aa *s5k6aa;
+	int i, ret;
+
+	if (pdata == NULL) {
+		dev_err(&client->dev, "Platform data not specified\n");
+		return -EINVAL;
+	}
+
+	if (pdata->mclk_frequency == 0) {
+		dev_err(&client->dev, "MCLK frequency not specified\n");
+		return -EINVAL;
+	}
+
+	s5k6aa = devm_kzalloc(&client->dev, sizeof(*s5k6aa), GFP_KERNEL);
+	if (!s5k6aa)
+		return -ENOMEM;
+
+	mutex_init(&s5k6aa->lock);
+
+	s5k6aa->mclk_frequency = pdata->mclk_frequency;
+	s5k6aa->bus_type = pdata->bus_type;
+	s5k6aa->mipi_lanes = pdata->nlanes;
+	s5k6aa->s_power	= pdata->set_power;
+	s5k6aa->inv_hflip = pdata->horiz_flip;
+	s5k6aa->inv_vflip = pdata->vert_flip;
+
+	sd = &s5k6aa->sd;
+	v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops);
+	strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name));
+
+	sd->internal_ops = &s5k6aa_subdev_internal_ops;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	s5k6aa->pad.flags = MEDIA_PAD_FL_SOURCE;
+	sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+	ret = media_entity_init(&sd->entity, 1, &s5k6aa->pad, 0);
+	if (ret)
+		return ret;
+
+	ret = s5k6aa_configure_gpios(s5k6aa, pdata);
+	if (ret)
+		goto out_err2;
+
+	for (i = 0; i < S5K6AA_NUM_SUPPLIES; i++)
+		s5k6aa->supplies[i].supply = s5k6aa_supply_names[i];
+
+	ret = regulator_bulk_get(&client->dev, S5K6AA_NUM_SUPPLIES,
+				 s5k6aa->supplies);
+	if (ret) {
+		dev_err(&client->dev, "Failed to get regulators\n");
+		goto out_err3;
+	}
+
+	ret = s5k6aa_initialize_ctrls(s5k6aa);
+	if (ret)
+		goto out_err4;
+
+	s5k6aa_presets_data_init(s5k6aa);
+
+	s5k6aa->ccd_rect.width = S5K6AA_WIN_WIDTH_MAX;
+	s5k6aa->ccd_rect.height	= S5K6AA_WIN_HEIGHT_MAX;
+	s5k6aa->ccd_rect.left = 0;
+	s5k6aa->ccd_rect.top = 0;
+
+	return 0;
+
+out_err4:
+	regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
+out_err3:
+	s5k6aa_free_gpios(s5k6aa);
+out_err2:
+	media_entity_cleanup(&s5k6aa->sd.entity);
+	return ret;
+}
+
+static int s5k6aa_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(sd->ctrl_handler);
+	media_entity_cleanup(&sd->entity);
+	regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
+	s5k6aa_free_gpios(s5k6aa);
+
+	return 0;
+}
+
+static const struct i2c_device_id s5k6aa_id[] = {
+	{ DRIVER_NAME, 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, s5k6aa_id);
+
+
+static struct i2c_driver s5k6aa_i2c_driver = {
+	.driver = {
+		.name = DRIVER_NAME
+	},
+	.probe		= s5k6aa_probe,
+	.remove		= s5k6aa_remove,
+	.id_table	= s5k6aa_id,
+};
+
+module_i2c_driver(s5k6aa_i2c_driver);
+
+MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver");
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/saa6588.c b/drivers/media/i2c/saa6588.c
new file mode 100644
index 0000000..0caac50
--- /dev/null
+++ b/drivers/media/i2c/saa6588.c
@@ -0,0 +1,542 @@
+/*
+    Driver for SAA6588 RDS decoder
+
+    (c) 2005 Hans J. Koch
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/wait.h>
+#include <asm/uaccess.h>
+
+#include <media/saa6588.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+
+/* insmod options */
+static unsigned int debug;
+static unsigned int xtal;
+static unsigned int mmbs;
+static unsigned int plvl;
+static unsigned int bufblocks = 100;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+module_param(xtal, int, 0);
+MODULE_PARM_DESC(xtal, "select oscillator frequency (0..3), default 0");
+module_param(mmbs, int, 0);
+MODULE_PARM_DESC(mmbs, "enable MMBS mode: 0=off (default), 1=on");
+module_param(plvl, int, 0);
+MODULE_PARM_DESC(plvl, "select pause level (0..3), default 0");
+module_param(bufblocks, int, 0);
+MODULE_PARM_DESC(bufblocks, "number of buffered blocks, default 100");
+
+MODULE_DESCRIPTION("v4l2 driver module for SAA6588 RDS decoder");
+MODULE_AUTHOR("Hans J. Koch <koch@hjk-az.de>");
+
+MODULE_LICENSE("GPL");
+
+/* ---------------------------------------------------------------------- */
+
+#define UNSET       (-1U)
+#define PREFIX      "saa6588: "
+#define dprintk     if (debug) printk
+
+struct saa6588 {
+	struct v4l2_subdev sd;
+	struct delayed_work work;
+	spinlock_t lock;
+	unsigned char *buffer;
+	unsigned int buf_size;
+	unsigned int rd_index;
+	unsigned int wr_index;
+	unsigned int block_count;
+	unsigned char last_blocknum;
+	wait_queue_head_t read_queue;
+	int data_available_for_read;
+	u8 sync;
+};
+
+static inline struct saa6588 *to_saa6588(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct saa6588, sd);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * SAA6588 defines
+ */
+
+/* Initialization and mode control byte (0w) */
+
+/* bit 0+1 (DAC0/DAC1) */
+#define cModeStandard           0x00
+#define cModeFastPI             0x01
+#define cModeReducedRequest     0x02
+#define cModeInvalid            0x03
+
+/* bit 2 (RBDS) */
+#define cProcessingModeRDS      0x00
+#define cProcessingModeRBDS     0x04
+
+/* bit 3+4 (SYM0/SYM1) */
+#define cErrCorrectionNone      0x00
+#define cErrCorrection2Bits     0x08
+#define cErrCorrection5Bits     0x10
+#define cErrCorrectionNoneRBDS  0x18
+
+/* bit 5 (NWSY) */
+#define cSyncNormal             0x00
+#define cSyncRestart            0x20
+
+/* bit 6 (TSQD) */
+#define cSigQualityDetectOFF    0x00
+#define cSigQualityDetectON     0x40
+
+/* bit 7 (SQCM) */
+#define cSigQualityTriggered    0x00
+#define cSigQualityContinous    0x80
+
+/* Pause level and flywheel control byte (1w) */
+
+/* bits 0..5 (FEB0..FEB5) */
+#define cFlywheelMaxBlocksMask  0x3F
+#define cFlywheelDefault        0x20
+
+/* bits 6+7 (PL0/PL1) */
+#define cPauseLevel_11mV	0x00
+#define cPauseLevel_17mV        0x40
+#define cPauseLevel_27mV        0x80
+#define cPauseLevel_43mV        0xC0
+
+/* Pause time/oscillator frequency/quality detector control byte (1w) */
+
+/* bits 0..4 (SQS0..SQS4) */
+#define cQualityDetectSensMask  0x1F
+#define cQualityDetectDefault   0x0F
+
+/* bit 5 (SOSC) */
+#define cSelectOscFreqOFF	0x00
+#define cSelectOscFreqON	0x20
+
+/* bit 6+7 (PTF0/PTF1) */
+#define cOscFreq_4332kHz	0x00
+#define cOscFreq_8664kHz	0x40
+#define cOscFreq_12996kHz	0x80
+#define cOscFreq_17328kHz	0xC0
+
+/* ---------------------------------------------------------------------- */
+
+static int block_to_user_buf(struct saa6588 *s, unsigned char __user *user_buf)
+{
+	int i;
+
+	if (s->rd_index == s->wr_index) {
+		if (debug > 2)
+			dprintk(PREFIX "Read: buffer empty.\n");
+		return 0;
+	}
+
+	if (debug > 2) {
+		dprintk(PREFIX "Read: ");
+		for (i = s->rd_index; i < s->rd_index + 3; i++)
+			dprintk("0x%02x ", s->buffer[i]);
+	}
+
+	if (copy_to_user(user_buf, &s->buffer[s->rd_index], 3))
+		return -EFAULT;
+
+	s->rd_index += 3;
+	if (s->rd_index >= s->buf_size)
+		s->rd_index = 0;
+	s->block_count--;
+
+	if (debug > 2)
+		dprintk("%d blocks total.\n", s->block_count);
+
+	return 1;
+}
+
+static void read_from_buf(struct saa6588 *s, struct saa6588_command *a)
+{
+	unsigned long flags;
+
+	unsigned char __user *buf_ptr = a->buffer;
+	unsigned int i;
+	unsigned int rd_blocks;
+
+	a->result = 0;
+	if (!a->buffer)
+		return;
+
+	while (!s->data_available_for_read) {
+		int ret = wait_event_interruptible(s->read_queue,
+					     s->data_available_for_read);
+		if (ret == -ERESTARTSYS) {
+			a->result = -EINTR;
+			return;
+		}
+	}
+
+	spin_lock_irqsave(&s->lock, flags);
+	rd_blocks = a->block_count;
+	if (rd_blocks > s->block_count)
+		rd_blocks = s->block_count;
+
+	if (!rd_blocks) {
+		spin_unlock_irqrestore(&s->lock, flags);
+		return;
+	}
+
+	for (i = 0; i < rd_blocks; i++) {
+		if (block_to_user_buf(s, buf_ptr)) {
+			buf_ptr += 3;
+			a->result++;
+		} else
+			break;
+	}
+	a->result *= 3;
+	s->data_available_for_read = (s->block_count > 0);
+	spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static void block_to_buf(struct saa6588 *s, unsigned char *blockbuf)
+{
+	unsigned int i;
+
+	if (debug > 3)
+		dprintk(PREFIX "New block: ");
+
+	for (i = 0; i < 3; ++i) {
+		if (debug > 3)
+			dprintk("0x%02x ", blockbuf[i]);
+		s->buffer[s->wr_index] = blockbuf[i];
+		s->wr_index++;
+	}
+
+	if (s->wr_index >= s->buf_size)
+		s->wr_index = 0;
+
+	if (s->wr_index == s->rd_index) {
+		s->rd_index += 3;
+		if (s->rd_index >= s->buf_size)
+			s->rd_index = 0;
+	} else
+		s->block_count++;
+
+	if (debug > 3)
+		dprintk("%d blocks total.\n", s->block_count);
+}
+
+static void saa6588_i2c_poll(struct saa6588 *s)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&s->sd);
+	unsigned long flags;
+	unsigned char tmpbuf[6];
+	unsigned char blocknum;
+	unsigned char tmp;
+
+	/* Although we only need 3 bytes, we have to read at least 6.
+	   SAA6588 returns garbage otherwise. */
+	if (6 != i2c_master_recv(client, &tmpbuf[0], 6)) {
+		if (debug > 1)
+			dprintk(PREFIX "read error!\n");
+		return;
+	}
+
+	s->sync = tmpbuf[0] & 0x10;
+	if (!s->sync)
+		return;
+	blocknum = tmpbuf[0] >> 5;
+	if (blocknum == s->last_blocknum) {
+		if (debug > 3)
+			dprintk("Saw block %d again.\n", blocknum);
+		return;
+	}
+
+	s->last_blocknum = blocknum;
+
+	/*
+	   Byte order according to v4l2 specification:
+
+	   Byte 0: Least Significant Byte of RDS Block
+	   Byte 1: Most Significant Byte of RDS Block
+	   Byte 2 Bit 7: Error bit. Indicates that an uncorrectable error
+	   occurred during reception of this block.
+	   Bit 6: Corrected bit. Indicates that an error was
+	   corrected for this data block.
+	   Bits 5-3: Same as bits 0-2.
+	   Bits 2-0: Block number.
+
+	   SAA6588 byte order is Status-MSB-LSB, so we have to swap the
+	   first and the last of the 3 bytes block.
+	 */
+
+	tmp = tmpbuf[2];
+	tmpbuf[2] = tmpbuf[0];
+	tmpbuf[0] = tmp;
+
+	/* Map 'Invalid block E' to 'Invalid Block' */
+	if (blocknum == 6)
+		blocknum = V4L2_RDS_BLOCK_INVALID;
+	/* And if are not in mmbs mode, then 'Block E' is also mapped
+	   to 'Invalid Block'. As far as I can tell MMBS is discontinued,
+	   and if there is ever a need to support E blocks, then please
+	   contact the linux-media mailinglist. */
+	else if (!mmbs && blocknum == 5)
+		blocknum = V4L2_RDS_BLOCK_INVALID;
+	tmp = blocknum;
+	tmp |= blocknum << 3;	/* Received offset == Offset Name (OK ?) */
+	if ((tmpbuf[2] & 0x03) == 0x03)
+		tmp |= V4L2_RDS_BLOCK_ERROR;	 /* uncorrectable error */
+	else if ((tmpbuf[2] & 0x03) != 0x00)
+		tmp |= V4L2_RDS_BLOCK_CORRECTED; /* corrected error */
+	tmpbuf[2] = tmp;	/* Is this enough ? Should we also check other bits ? */
+
+	spin_lock_irqsave(&s->lock, flags);
+	block_to_buf(s, tmpbuf);
+	spin_unlock_irqrestore(&s->lock, flags);
+	s->data_available_for_read = 1;
+	wake_up_interruptible(&s->read_queue);
+}
+
+static void saa6588_work(struct work_struct *work)
+{
+	struct saa6588 *s = container_of(work, struct saa6588, work.work);
+
+	saa6588_i2c_poll(s);
+	schedule_delayed_work(&s->work, msecs_to_jiffies(20));
+}
+
+static void saa6588_configure(struct saa6588 *s)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&s->sd);
+	unsigned char buf[3];
+	int rc;
+
+	buf[0] = cSyncRestart;
+	if (mmbs)
+		buf[0] |= cProcessingModeRBDS;
+
+	buf[1] = cFlywheelDefault;
+	switch (plvl) {
+	case 0:
+		buf[1] |= cPauseLevel_11mV;
+		break;
+	case 1:
+		buf[1] |= cPauseLevel_17mV;
+		break;
+	case 2:
+		buf[1] |= cPauseLevel_27mV;
+		break;
+	case 3:
+		buf[1] |= cPauseLevel_43mV;
+		break;
+	default:		/* nothing */
+		break;
+	}
+
+	buf[2] = cQualityDetectDefault | cSelectOscFreqON;
+
+	switch (xtal) {
+	case 0:
+		buf[2] |= cOscFreq_4332kHz;
+		break;
+	case 1:
+		buf[2] |= cOscFreq_8664kHz;
+		break;
+	case 2:
+		buf[2] |= cOscFreq_12996kHz;
+		break;
+	case 3:
+		buf[2] |= cOscFreq_17328kHz;
+		break;
+	default:		/* nothing */
+		break;
+	}
+
+	dprintk(PREFIX "writing: 0w=0x%02x 1w=0x%02x 2w=0x%02x\n",
+		buf[0], buf[1], buf[2]);
+
+	rc = i2c_master_send(client, buf, 3);
+	if (rc != 3)
+		printk(PREFIX "i2c i/o error: rc == %d (should be 3)\n", rc);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+	struct saa6588 *s = to_saa6588(sd);
+	struct saa6588_command *a = arg;
+
+	switch (cmd) {
+		/* --- open() for /dev/radio --- */
+	case SAA6588_CMD_OPEN:
+		a->result = 0;	/* return error if chip doesn't work ??? */
+		break;
+		/* --- close() for /dev/radio --- */
+	case SAA6588_CMD_CLOSE:
+		s->data_available_for_read = 1;
+		wake_up_interruptible(&s->read_queue);
+		a->result = 0;
+		break;
+		/* --- read() for /dev/radio --- */
+	case SAA6588_CMD_READ:
+		read_from_buf(s, a);
+		break;
+		/* --- poll() for /dev/radio --- */
+	case SAA6588_CMD_POLL:
+		a->result = 0;
+		if (s->data_available_for_read) {
+			a->result |= POLLIN | POLLRDNORM;
+		}
+		poll_wait(a->instance, &s->read_queue, a->event_list);
+		break;
+
+	default:
+		/* nothing */
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static int saa6588_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct saa6588 *s = to_saa6588(sd);
+
+	vt->capability |= V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO;
+	if (s->sync)
+		vt->rxsubchans |= V4L2_TUNER_SUB_RDS;
+	return 0;
+}
+
+static int saa6588_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct saa6588 *s = to_saa6588(sd);
+
+	saa6588_configure(s);
+	return 0;
+}
+
+static int saa6588_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA6588, 0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops saa6588_core_ops = {
+	.g_chip_ident = saa6588_g_chip_ident,
+	.ioctl = saa6588_ioctl,
+};
+
+static const struct v4l2_subdev_tuner_ops saa6588_tuner_ops = {
+	.g_tuner = saa6588_g_tuner,
+	.s_tuner = saa6588_s_tuner,
+};
+
+static const struct v4l2_subdev_ops saa6588_ops = {
+	.core = &saa6588_core_ops,
+	.tuner = &saa6588_tuner_ops,
+};
+
+/* ---------------------------------------------------------------------- */
+
+static int saa6588_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct saa6588 *s;
+	struct v4l2_subdev *sd;
+
+	v4l_info(client, "saa6588 found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	s = kzalloc(sizeof(*s), GFP_KERNEL);
+	if (s == NULL)
+		return -ENOMEM;
+
+	s->buf_size = bufblocks * 3;
+
+	s->buffer = kmalloc(s->buf_size, GFP_KERNEL);
+	if (s->buffer == NULL) {
+		kfree(s);
+		return -ENOMEM;
+	}
+	sd = &s->sd;
+	v4l2_i2c_subdev_init(sd, client, &saa6588_ops);
+	spin_lock_init(&s->lock);
+	s->block_count = 0;
+	s->wr_index = 0;
+	s->rd_index = 0;
+	s->last_blocknum = 0xff;
+	init_waitqueue_head(&s->read_queue);
+	s->data_available_for_read = 0;
+
+	saa6588_configure(s);
+
+	/* start polling via eventd */
+	INIT_DELAYED_WORK(&s->work, saa6588_work);
+	schedule_delayed_work(&s->work, 0);
+	return 0;
+}
+
+static int saa6588_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct saa6588 *s = to_saa6588(sd);
+
+	v4l2_device_unregister_subdev(sd);
+
+	cancel_delayed_work_sync(&s->work);
+
+	kfree(s->buffer);
+	kfree(s);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id saa6588_id[] = {
+	{ "saa6588", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, saa6588_id);
+
+static struct i2c_driver saa6588_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "saa6588",
+	},
+	.probe		= saa6588_probe,
+	.remove		= saa6588_remove,
+	.id_table	= saa6588_id,
+};
+
+module_i2c_driver(saa6588_driver);
diff --git a/drivers/media/i2c/saa7110.c b/drivers/media/i2c/saa7110.c
new file mode 100644
index 0000000..51cd4c8
--- /dev/null
+++ b/drivers/media/i2c/saa7110.c
@@ -0,0 +1,494 @@
+/*
+ * saa7110 - Philips SAA7110(A) video decoder driver
+ *
+ * Copyright (C) 1998 Pauline Middelink <middelin@polyware.nl>
+ *
+ * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *    - some corrections for Pinnacle Systems Inc. DC10plus card.
+ *
+ * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *    - moved over to linux>=2.4.x i2c protocol (1/1/2003)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
+MODULE_AUTHOR("Pauline Middelink");
+MODULE_LICENSE("GPL");
+
+
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define SAA7110_MAX_INPUT	9	/* 6 CVBS, 3 SVHS */
+#define SAA7110_MAX_OUTPUT	1	/* 1 YUV */
+
+#define SAA7110_NR_REG		0x35
+
+struct saa7110 {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	u8 reg[SAA7110_NR_REG];
+
+	v4l2_std_id norm;
+	int input;
+	int enable;
+
+	wait_queue_head_t wq;
+};
+
+static inline struct saa7110 *to_saa7110(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct saa7110, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct saa7110, hdl)->sd;
+}
+
+/* ----------------------------------------------------------------------- */
+/* I2C support functions						   */
+/* ----------------------------------------------------------------------- */
+
+static int saa7110_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct saa7110 *decoder = to_saa7110(sd);
+
+	decoder->reg[reg] = value;
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int saa7110_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct saa7110 *decoder = to_saa7110(sd);
+	int ret = -1;
+	u8 reg = *data;		/* first register to write to */
+
+	/* Sanity check */
+	if (reg + (len - 1) > SAA7110_NR_REG)
+		return ret;
+
+	/* the saa7110 has an autoincrement function, use it if
+	 * the adapter understands raw I2C */
+	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		ret = i2c_master_send(client, data, len);
+
+		/* Cache the written data */
+		memcpy(decoder->reg + reg, data + 1, len - 1);
+	} else {
+		for (++data, --len; len; len--) {
+			ret = saa7110_write(sd, reg++, *data++);
+			if (ret < 0)
+				break;
+		}
+	}
+
+	return ret;
+}
+
+static inline int saa7110_read(struct v4l2_subdev *sd)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_read_byte(client);
+}
+
+/* ----------------------------------------------------------------------- */
+/* SAA7110 functions							   */
+/* ----------------------------------------------------------------------- */
+
+#define FRESP_06H_COMPST 0x03	/*0x13*/
+#define FRESP_06H_SVIDEO 0x83	/*0xC0*/
+
+
+static int saa7110_selmux(struct v4l2_subdev *sd, int chan)
+{
+	static const unsigned char modes[9][8] = {
+		/* mode 0 */
+		{FRESP_06H_COMPST, 0xD9, 0x17, 0x40, 0x03,
+			      0x44, 0x75, 0x16},
+		/* mode 1 */
+		{FRESP_06H_COMPST, 0xD8, 0x17, 0x40, 0x03,
+			      0x44, 0x75, 0x16},
+		/* mode 2 */
+		{FRESP_06H_COMPST, 0xBA, 0x07, 0x91, 0x03,
+			      0x60, 0xB5, 0x05},
+		/* mode 3 */
+		{FRESP_06H_COMPST, 0xB8, 0x07, 0x91, 0x03,
+			      0x60, 0xB5, 0x05},
+		/* mode 4 */
+		{FRESP_06H_COMPST, 0x7C, 0x07, 0xD2, 0x83,
+			      0x60, 0xB5, 0x03},
+		/* mode 5 */
+		{FRESP_06H_COMPST, 0x78, 0x07, 0xD2, 0x83,
+			      0x60, 0xB5, 0x03},
+		/* mode 6 */
+		{FRESP_06H_SVIDEO, 0x59, 0x17, 0x42, 0xA3,
+			      0x44, 0x75, 0x12},
+		/* mode 7 */
+		{FRESP_06H_SVIDEO, 0x9A, 0x17, 0xB1, 0x13,
+			      0x60, 0xB5, 0x14},
+		/* mode 8 */
+		{FRESP_06H_SVIDEO, 0x3C, 0x27, 0xC1, 0x23,
+			      0x44, 0x75, 0x21}
+	};
+	struct saa7110 *decoder = to_saa7110(sd);
+	const unsigned char *ptr = modes[chan];
+
+	saa7110_write(sd, 0x06, ptr[0]);	/* Luminance control    */
+	saa7110_write(sd, 0x20, ptr[1]);	/* Analog Control #1    */
+	saa7110_write(sd, 0x21, ptr[2]);	/* Analog Control #2    */
+	saa7110_write(sd, 0x22, ptr[3]);	/* Mixer Control #1     */
+	saa7110_write(sd, 0x2C, ptr[4]);	/* Mixer Control #2     */
+	saa7110_write(sd, 0x30, ptr[5]);	/* ADCs gain control    */
+	saa7110_write(sd, 0x31, ptr[6]);	/* Mixer Control #3     */
+	saa7110_write(sd, 0x21, ptr[7]);	/* Analog Control #2    */
+	decoder->input = chan;
+
+	return 0;
+}
+
+static const unsigned char initseq[1 + SAA7110_NR_REG] = {
+	0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF2, 0x03, 0x00,
+	/* 0x08 */ 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x86, 0x18, 0x90,
+	/* 0x10 */ 0x00, 0x59, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA,
+	/* 0x18 */ 0xF2, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* 0x20 */ 0xD9, 0x16, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F,
+	/* 0x28 */ 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x03, 0x0C,
+	/* 0x30 */ 0x44, 0x71, 0x02, 0x8C, 0x02
+};
+
+static v4l2_std_id determine_norm(struct v4l2_subdev *sd)
+{
+	DEFINE_WAIT(wait);
+	struct saa7110 *decoder = to_saa7110(sd);
+	int status;
+
+	/* mode changed, start automatic detection */
+	saa7110_write_block(sd, initseq, sizeof(initseq));
+	saa7110_selmux(sd, decoder->input);
+	prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
+	schedule_timeout(msecs_to_jiffies(250));
+	finish_wait(&decoder->wq, &wait);
+	status = saa7110_read(sd);
+	if (status & 0x40) {
+		v4l2_dbg(1, debug, sd, "status=0x%02x (no signal)\n", status);
+		return decoder->norm;	/* no change*/
+	}
+	if ((status & 3) == 0) {
+		saa7110_write(sd, 0x06, 0x83);
+		if (status & 0x20) {
+			v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC/no color)\n", status);
+			/*saa7110_write(sd,0x2E,0x81);*/
+			return V4L2_STD_NTSC;
+		}
+		v4l2_dbg(1, debug, sd, "status=0x%02x (PAL/no color)\n", status);
+		/*saa7110_write(sd,0x2E,0x9A);*/
+		return V4L2_STD_PAL;
+	}
+	/*saa7110_write(sd,0x06,0x03);*/
+	if (status & 0x20) {	/* 60Hz */
+		v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC)\n", status);
+		saa7110_write(sd, 0x0D, 0x86);
+		saa7110_write(sd, 0x0F, 0x50);
+		saa7110_write(sd, 0x11, 0x2C);
+		/*saa7110_write(sd,0x2E,0x81);*/
+		return V4L2_STD_NTSC;
+	}
+
+	/* 50Hz -> PAL/SECAM */
+	saa7110_write(sd, 0x0D, 0x86);
+	saa7110_write(sd, 0x0F, 0x10);
+	saa7110_write(sd, 0x11, 0x59);
+	/*saa7110_write(sd,0x2E,0x9A);*/
+
+	prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
+	schedule_timeout(msecs_to_jiffies(250));
+	finish_wait(&decoder->wq, &wait);
+
+	status = saa7110_read(sd);
+	if ((status & 0x03) == 0x01) {
+		v4l2_dbg(1, debug, sd, "status=0x%02x (SECAM)\n", status);
+		saa7110_write(sd, 0x0D, 0x87);
+		return V4L2_STD_SECAM;
+	}
+	v4l2_dbg(1, debug, sd, "status=0x%02x (PAL)\n", status);
+	return V4L2_STD_PAL;
+}
+
+static int saa7110_g_input_status(struct v4l2_subdev *sd, u32 *pstatus)
+{
+	struct saa7110 *decoder = to_saa7110(sd);
+	int res = V4L2_IN_ST_NO_SIGNAL;
+	int status = saa7110_read(sd);
+
+	v4l2_dbg(1, debug, sd, "status=0x%02x norm=%llx\n",
+		       status, (unsigned long long)decoder->norm);
+	if (!(status & 0x40))
+		res = 0;
+	if (!(status & 0x03))
+		res |= V4L2_IN_ST_NO_COLOR;
+
+	*pstatus = res;
+	return 0;
+}
+
+static int saa7110_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	*(v4l2_std_id *)std = determine_norm(sd);
+	return 0;
+}
+
+static int saa7110_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct saa7110 *decoder = to_saa7110(sd);
+
+	if (decoder->norm != std) {
+		decoder->norm = std;
+		/*saa7110_write(sd, 0x06, 0x03);*/
+		if (std & V4L2_STD_NTSC) {
+			saa7110_write(sd, 0x0D, 0x86);
+			saa7110_write(sd, 0x0F, 0x50);
+			saa7110_write(sd, 0x11, 0x2C);
+			/*saa7110_write(sd, 0x2E, 0x81);*/
+			v4l2_dbg(1, debug, sd, "switched to NTSC\n");
+		} else if (std & V4L2_STD_PAL) {
+			saa7110_write(sd, 0x0D, 0x86);
+			saa7110_write(sd, 0x0F, 0x10);
+			saa7110_write(sd, 0x11, 0x59);
+			/*saa7110_write(sd, 0x2E, 0x9A);*/
+			v4l2_dbg(1, debug, sd, "switched to PAL\n");
+		} else if (std & V4L2_STD_SECAM) {
+			saa7110_write(sd, 0x0D, 0x87);
+			saa7110_write(sd, 0x0F, 0x10);
+			saa7110_write(sd, 0x11, 0x59);
+			/*saa7110_write(sd, 0x2E, 0x9A);*/
+			v4l2_dbg(1, debug, sd, "switched to SECAM\n");
+		} else {
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static int saa7110_s_routing(struct v4l2_subdev *sd,
+			     u32 input, u32 output, u32 config)
+{
+	struct saa7110 *decoder = to_saa7110(sd);
+
+	if (input >= SAA7110_MAX_INPUT) {
+		v4l2_dbg(1, debug, sd, "input=%d not available\n", input);
+		return -EINVAL;
+	}
+	if (decoder->input != input) {
+		saa7110_selmux(sd, input);
+		v4l2_dbg(1, debug, sd, "switched to input=%d\n", input);
+	}
+	return 0;
+}
+
+static int saa7110_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct saa7110 *decoder = to_saa7110(sd);
+
+	if (decoder->enable != enable) {
+		decoder->enable = enable;
+		saa7110_write(sd, 0x0E, enable ? 0x18 : 0x80);
+		v4l2_dbg(1, debug, sd, "YUV %s\n", enable ? "on" : "off");
+	}
+	return 0;
+}
+
+static int saa7110_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		saa7110_write(sd, 0x19, ctrl->val);
+		break;
+	case V4L2_CID_CONTRAST:
+		saa7110_write(sd, 0x13, ctrl->val);
+		break;
+	case V4L2_CID_SATURATION:
+		saa7110_write(sd, 0x12, ctrl->val);
+		break;
+	case V4L2_CID_HUE:
+		saa7110_write(sd, 0x07, ctrl->val);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int saa7110_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7110, 0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_ctrl_ops saa7110_ctrl_ops = {
+	.s_ctrl = saa7110_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops saa7110_core_ops = {
+	.g_chip_ident = saa7110_g_chip_ident,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+	.s_std = saa7110_s_std,
+};
+
+static const struct v4l2_subdev_video_ops saa7110_video_ops = {
+	.s_routing = saa7110_s_routing,
+	.s_stream = saa7110_s_stream,
+	.querystd = saa7110_querystd,
+	.g_input_status = saa7110_g_input_status,
+};
+
+static const struct v4l2_subdev_ops saa7110_ops = {
+	.core = &saa7110_core_ops,
+	.video = &saa7110_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7110_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct saa7110 *decoder;
+	struct v4l2_subdev *sd;
+	int rv;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter,
+		I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+		return -ENODEV;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL);
+	if (!decoder)
+		return -ENOMEM;
+	sd = &decoder->sd;
+	v4l2_i2c_subdev_init(sd, client, &saa7110_ops);
+	decoder->norm = V4L2_STD_PAL;
+	decoder->input = 0;
+	decoder->enable = 1;
+	v4l2_ctrl_handler_init(&decoder->hdl, 2);
+	v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
+		V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
+		V4L2_CID_CONTRAST, 0, 127, 1, 64);
+	v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
+		V4L2_CID_SATURATION, 0, 127, 1, 64);
+	v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
+		V4L2_CID_HUE, -128, 127, 1, 0);
+	sd->ctrl_handler = &decoder->hdl;
+	if (decoder->hdl.error) {
+		int err = decoder->hdl.error;
+
+		v4l2_ctrl_handler_free(&decoder->hdl);
+		kfree(decoder);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&decoder->hdl);
+
+	init_waitqueue_head(&decoder->wq);
+
+	rv = saa7110_write_block(sd, initseq, sizeof(initseq));
+	if (rv < 0) {
+		v4l2_dbg(1, debug, sd, "init status %d\n", rv);
+	} else {
+		int ver, status;
+		saa7110_write(sd, 0x21, 0x10);
+		saa7110_write(sd, 0x0e, 0x18);
+		saa7110_write(sd, 0x0D, 0x04);
+		ver = saa7110_read(sd);
+		saa7110_write(sd, 0x0D, 0x06);
+		/*mdelay(150);*/
+		status = saa7110_read(sd);
+		v4l2_dbg(1, debug, sd, "version %x, status=0x%02x\n",
+			       ver, status);
+		saa7110_write(sd, 0x0D, 0x86);
+		saa7110_write(sd, 0x0F, 0x10);
+		saa7110_write(sd, 0x11, 0x59);
+		/*saa7110_write(sd, 0x2E, 0x9A);*/
+	}
+
+	/*saa7110_selmux(sd,0);*/
+	/*determine_norm(sd);*/
+	/* setup and implicit mode 0 select has been performed */
+
+	return 0;
+}
+
+static int saa7110_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct saa7110 *decoder = to_saa7110(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&decoder->hdl);
+	kfree(decoder);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id saa7110_id[] = {
+	{ "saa7110", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, saa7110_id);
+
+static struct i2c_driver saa7110_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "saa7110",
+	},
+	.probe		= saa7110_probe,
+	.remove		= saa7110_remove,
+	.id_table	= saa7110_id,
+};
+
+module_i2c_driver(saa7110_driver);
diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c
new file mode 100644
index 0000000..2107336
--- /dev/null
+++ b/drivers/media/i2c/saa7115.c
@@ -0,0 +1,1727 @@
+/* saa711x - Philips SAA711x video decoder driver
+ * This driver can work with saa7111, saa7111a, saa7113, saa7114,
+ *			     saa7115 and saa7118.
+ *
+ * Based on saa7114 driver by Maxim Yevtyushkin, which is based on
+ * the saa7111 driver by Dave Perks.
+ *
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
+ *
+ * Slight changes for video timing and attachment output by
+ * Wolfgang Scherr <scherr@net4you.net>
+ *
+ * Moved over to the linux >= 2.4.x i2c protocol (1/1/2003)
+ * by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * Added saa7115 support by Kevin Thayer <nufan_wfk at yahoo.com>
+ * (2/17/2003)
+ *
+ * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Copyright (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *	SAA7111, SAA7113 and SAA7118 support
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "saa711x_regs.h"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/saa7115.h>
+#include <asm/div64.h>
+
+#define VRES_60HZ	(480+16)
+
+MODULE_DESCRIPTION("Philips SAA7111/SAA7113/SAA7114/SAA7115/SAA7118 video decoder driver");
+MODULE_AUTHOR(  "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
+		"Hans Verkuil, Mauro Carvalho Chehab");
+MODULE_LICENSE("GPL");
+
+static bool debug;
+module_param(debug, bool, 0644);
+
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+
+struct saa711x_state {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+
+	struct {
+		/* chroma gain control cluster */
+		struct v4l2_ctrl *agc;
+		struct v4l2_ctrl *gain;
+	};
+
+	v4l2_std_id std;
+	int input;
+	int output;
+	int enable;
+	int radio;
+	int width;
+	int height;
+	u32 ident;
+	u32 audclk_freq;
+	u32 crystal_freq;
+	u8 ucgc;
+	u8 cgcdiv;
+	u8 apll;
+};
+
+static inline struct saa711x_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct saa711x_state, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct saa711x_state, hdl)->sd;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static inline int saa711x_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/* Sanity routine to check if a register is present */
+static int saa711x_has_reg(const int id, const u8 reg)
+{
+	if (id == V4L2_IDENT_SAA7111)
+		return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
+		       (reg < 0x13 || reg > 0x19) && reg != 0x1d && reg != 0x1e;
+	if (id == V4L2_IDENT_SAA7111A)
+		return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
+		       reg != 0x14 && reg != 0x18 && reg != 0x19 &&
+		       reg != 0x1d && reg != 0x1e;
+
+	/* common for saa7113/4/5/8 */
+	if (unlikely((reg >= 0x3b && reg <= 0x3f) || reg == 0x5c || reg == 0x5f ||
+	    reg == 0xa3 || reg == 0xa7 || reg == 0xab || reg == 0xaf || (reg >= 0xb5 && reg <= 0xb7) ||
+	    reg == 0xd3 || reg == 0xd7 || reg == 0xdb || reg == 0xdf || (reg >= 0xe5 && reg <= 0xe7) ||
+	    reg == 0x82 || (reg >= 0x89 && reg <= 0x8e)))
+		return 0;
+
+	switch (id) {
+	case V4L2_IDENT_SAA7113:
+		return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && (reg < 0x20 || reg > 0x3f) &&
+		       reg != 0x5d && reg < 0x63;
+	case V4L2_IDENT_SAA7114:
+		return (reg < 0x1a || reg > 0x1e) && (reg < 0x20 || reg > 0x2f) &&
+		       (reg < 0x63 || reg > 0x7f) && reg != 0x33 && reg != 0x37 &&
+		       reg != 0x81 && reg < 0xf0;
+	case V4L2_IDENT_SAA7115:
+		return (reg < 0x20 || reg > 0x2f) && reg != 0x65 && (reg < 0xfc || reg > 0xfe);
+	case V4L2_IDENT_SAA7118:
+		return (reg < 0x1a || reg > 0x1d) && (reg < 0x20 || reg > 0x22) &&
+		       (reg < 0x26 || reg > 0x28) && reg != 0x33 && reg != 0x37 &&
+		       (reg < 0x63 || reg > 0x7f) && reg != 0x81 && reg < 0xf0;
+	}
+	return 1;
+}
+
+static int saa711x_writeregs(struct v4l2_subdev *sd, const unsigned char *regs)
+{
+	struct saa711x_state *state = to_state(sd);
+	unsigned char reg, data;
+
+	while (*regs != 0x00) {
+		reg = *(regs++);
+		data = *(regs++);
+
+		/* According with datasheets, reserved regs should be
+		   filled with 0 - seems better not to touch on they */
+		if (saa711x_has_reg(state->ident, reg)) {
+			if (saa711x_write(sd, reg, data) < 0)
+				return -1;
+		} else {
+			v4l2_dbg(1, debug, sd, "tried to access reserved reg 0x%02x\n", reg);
+		}
+	}
+	return 0;
+}
+
+static inline int saa711x_read(struct v4l2_subdev *sd, u8 reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* SAA7111 initialization table */
+static const unsigned char saa7111_init[] = {
+	R_01_INC_DELAY, 0x00,		/* reserved */
+
+	/*front end */
+	R_02_INPUT_CNTL_1, 0xd0,	/* FUSE=3, GUDL=2, MODE=0 */
+	R_03_INPUT_CNTL_2, 0x23,	/* HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0,
+					 * GAFIX=0, GAI1=256, GAI2=256 */
+	R_04_INPUT_CNTL_3, 0x00,	/* GAI1=256 */
+	R_05_INPUT_CNTL_4, 0x00,	/* GAI2=256 */
+
+	/* decoder */
+	R_06_H_SYNC_START, 0xf3,	/* HSB at  13(50Hz) /  17(60Hz)
+					 * pixels after end of last line */
+	R_07_H_SYNC_STOP, 0xe8,		/* HSS seems to be needed to
+					 * work with NTSC, too */
+	R_08_SYNC_CNTL, 0xc8,		/* AUFD=1, FSEL=1, EXFIL=0,
+					 * VTRC=1, HPLL=0, VNOI=0 */
+	R_09_LUMA_CNTL, 0x01,		/* BYPS=0, PREF=0, BPSS=0,
+					 * VBLB=0, UPTCV=0, APER=1 */
+	R_0A_LUMA_BRIGHT_CNTL, 0x80,
+	R_0B_LUMA_CONTRAST_CNTL, 0x47,	/* 0b - CONT=1.109 */
+	R_0C_CHROMA_SAT_CNTL, 0x40,
+	R_0D_CHROMA_HUE_CNTL, 0x00,
+	R_0E_CHROMA_CNTL_1, 0x01,	/* 0e - CDTO=0, CSTD=0, DCCF=0,
+					 * FCTC=0, CHBW=1 */
+	R_0F_CHROMA_GAIN_CNTL, 0x00,	/* reserved */
+	R_10_CHROMA_CNTL_2, 0x48,	/* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
+	R_11_MODE_DELAY_CNTL, 0x1c,	/* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1,
+					 * OEYC=1, OEHV=1, VIPB=0, COLO=0 */
+	R_12_RT_SIGNAL_CNTL, 0x00,	/* 12 - output control 2 */
+	R_13_RT_X_PORT_OUT_CNTL, 0x00,	/* 13 - output control 3 */
+	R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
+	R_15_VGATE_START_FID_CHG, 0x00,
+	R_16_VGATE_STOP, 0x00,
+	R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
+
+	0x00, 0x00
+};
+
+/* SAA7113 init codes */
+static const unsigned char saa7113_init[] = {
+	R_01_INC_DELAY, 0x08,
+	R_02_INPUT_CNTL_1, 0xc2,
+	R_03_INPUT_CNTL_2, 0x30,
+	R_04_INPUT_CNTL_3, 0x00,
+	R_05_INPUT_CNTL_4, 0x00,
+	R_06_H_SYNC_START, 0x89,
+	R_07_H_SYNC_STOP, 0x0d,
+	R_08_SYNC_CNTL, 0x88,
+	R_09_LUMA_CNTL, 0x01,
+	R_0A_LUMA_BRIGHT_CNTL, 0x80,
+	R_0B_LUMA_CONTRAST_CNTL, 0x47,
+	R_0C_CHROMA_SAT_CNTL, 0x40,
+	R_0D_CHROMA_HUE_CNTL, 0x00,
+	R_0E_CHROMA_CNTL_1, 0x01,
+	R_0F_CHROMA_GAIN_CNTL, 0x2a,
+	R_10_CHROMA_CNTL_2, 0x08,
+	R_11_MODE_DELAY_CNTL, 0x0c,
+	R_12_RT_SIGNAL_CNTL, 0x07,
+	R_13_RT_X_PORT_OUT_CNTL, 0x00,
+	R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
+	R_15_VGATE_START_FID_CHG, 0x00,
+	R_16_VGATE_STOP, 0x00,
+	R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
+
+	0x00, 0x00
+};
+
+/* If a value differs from the Hauppauge driver values, then the comment starts with
+   'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
+   Hauppauge driver sets. */
+
+/* SAA7114 and SAA7115 initialization table */
+static const unsigned char saa7115_init_auto_input[] = {
+		/* Front-End Part */
+	R_01_INC_DELAY, 0x48,			/* white peak control disabled */
+	R_03_INPUT_CNTL_2, 0x20,		/* was 0x30. 0x20: long vertical blanking */
+	R_04_INPUT_CNTL_3, 0x90,		/* analog gain set to 0 */
+	R_05_INPUT_CNTL_4, 0x90,		/* analog gain set to 0 */
+		/* Decoder Part */
+	R_06_H_SYNC_START, 0xeb,		/* horiz sync begin = -21 */
+	R_07_H_SYNC_STOP, 0xe0,			/* horiz sync stop = -17 */
+	R_09_LUMA_CNTL, 0x53,			/* 0x53, was 0x56 for 60hz. luminance control */
+	R_0A_LUMA_BRIGHT_CNTL, 0x80,		/* was 0x88. decoder brightness, 0x80 is itu standard */
+	R_0B_LUMA_CONTRAST_CNTL, 0x44,		/* was 0x48. decoder contrast, 0x44 is itu standard */
+	R_0C_CHROMA_SAT_CNTL, 0x40,		/* was 0x47. decoder saturation, 0x40 is itu standard */
+	R_0D_CHROMA_HUE_CNTL, 0x00,
+	R_0F_CHROMA_GAIN_CNTL, 0x00,		/* use automatic gain  */
+	R_10_CHROMA_CNTL_2, 0x06,		/* chroma: active adaptive combfilter */
+	R_11_MODE_DELAY_CNTL, 0x00,
+	R_12_RT_SIGNAL_CNTL, 0x9d,		/* RTS0 output control: VGATE */
+	R_13_RT_X_PORT_OUT_CNTL, 0x80,		/* ITU656 standard mode, RTCO output enable RTCE */
+	R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
+	R_18_RAW_DATA_GAIN_CNTL, 0x40,		/* gain 0x00 = nominal */
+	R_19_RAW_DATA_OFF_CNTL, 0x80,
+	R_1A_COLOR_KILL_LVL_CNTL, 0x77,		/* recommended value */
+	R_1B_MISC_TVVCRDET, 0x42,		/* recommended value */
+	R_1C_ENHAN_COMB_CTRL1, 0xa9,		/* recommended value */
+	R_1D_ENHAN_COMB_CTRL2, 0x01,		/* recommended value */
+
+
+	R_80_GLOBAL_CNTL_1, 0x0,		/* No tasks enabled at init */
+
+		/* Power Device Control */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,	/* reset device */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,	/* set device programmed, all in operational mode */
+	0x00, 0x00
+};
+
+/* Used to reset saa7113, saa7114 and saa7115 */
+static const unsigned char saa7115_cfg_reset_scaler[] = {
+	R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00,	/* disable I-port output */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,		/* reset scaler */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,		/* activate scaler */
+	R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,	/* enable I-port output */
+	0x00, 0x00
+};
+
+/* ============== SAA7715 VIDEO templates =============  */
+
+static const unsigned char saa7115_cfg_60hz_video[] = {
+	R_80_GLOBAL_CNTL_1, 0x00,			/* reset tasks */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,		/* reset scaler */
+
+	R_15_VGATE_START_FID_CHG, 0x03,
+	R_16_VGATE_STOP, 0x11,
+	R_17_MISC_VGATE_CONF_AND_MSB, 0x9c,
+
+	R_08_SYNC_CNTL, 0x68,			/* 0xBO: auto detection, 0x68 = NTSC */
+	R_0E_CHROMA_CNTL_1, 0x07,		/* video autodetection is on */
+
+	R_5A_V_OFF_FOR_SLICER, 0x06,		/* standard 60hz value for ITU656 line counting */
+
+	/* Task A */
+	R_90_A_TASK_HANDLING_CNTL, 0x80,
+	R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
+	R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
+	R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
+
+	/* hoffset low (input), 0x0002 is minimum */
+	R_94_A_HORIZ_INPUT_WINDOW_START, 0x01,
+	R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
+
+	/* hsize low (input), 0x02d0 = 720 */
+	R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
+	R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
+
+	R_98_A_VERT_INPUT_WINDOW_START, 0x05,
+	R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
+
+	R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x0c,
+	R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
+
+	R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
+	R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05,
+
+	R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x0c,
+	R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,
+
+	/* Task B */
+	R_C0_B_TASK_HANDLING_CNTL, 0x00,
+	R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
+	R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
+	R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
+
+	/* 0x0002 is minimum */
+	R_C4_B_HORIZ_INPUT_WINDOW_START, 0x02,
+	R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
+
+	/* 0x02d0 = 720 */
+	R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
+	R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
+
+	/* vwindow start 0x12 = 18 */
+	R_C8_B_VERT_INPUT_WINDOW_START, 0x12,
+	R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
+
+	/* vwindow length 0xf8 = 248 */
+	R_CA_B_VERT_INPUT_WINDOW_LENGTH, VRES_60HZ>>1,
+	R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, VRES_60HZ>>9,
+
+	/* hwindow 0x02d0 = 720 */
+	R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
+	R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
+
+	R_F0_LFCO_PER_LINE, 0xad,		/* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
+	R_F1_P_I_PARAM_SELECT, 0x05,		/* low bit with 0xF0 */
+	R_F5_PULSGEN_LINE_LENGTH, 0xad,
+	R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
+
+	0x00, 0x00
+};
+
+static const unsigned char saa7115_cfg_50hz_video[] = {
+	R_80_GLOBAL_CNTL_1, 0x00,
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,	/* reset scaler */
+
+	R_15_VGATE_START_FID_CHG, 0x37,		/* VGATE start */
+	R_16_VGATE_STOP, 0x16,
+	R_17_MISC_VGATE_CONF_AND_MSB, 0x99,
+
+	R_08_SYNC_CNTL, 0x28,			/* 0x28 = PAL */
+	R_0E_CHROMA_CNTL_1, 0x07,
+
+	R_5A_V_OFF_FOR_SLICER, 0x03,		/* standard 50hz value */
+
+	/* Task A */
+	R_90_A_TASK_HANDLING_CNTL, 0x81,
+	R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
+	R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
+	R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
+
+	/* This is weird: the datasheet says that you should use 2 as the minimum value, */
+	/* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
+	/* hoffset low (input), 0x0002 is minimum */
+	R_94_A_HORIZ_INPUT_WINDOW_START, 0x00,
+	R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
+
+	/* hsize low (input), 0x02d0 = 720 */
+	R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
+	R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
+
+	R_98_A_VERT_INPUT_WINDOW_START, 0x03,
+	R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
+
+	/* vsize 0x12 = 18 */
+	R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x12,
+	R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
+
+	/* hsize 0x05a0 = 1440 */
+	R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
+	R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05,	/* hsize hi (output) */
+	R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x12,		/* vsize low (output), 0x12 = 18 */
+	R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,	/* vsize hi (output) */
+
+	/* Task B */
+	R_C0_B_TASK_HANDLING_CNTL, 0x00,
+	R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
+	R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
+	R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
+
+	/* This is weird: the datasheet says that you should use 2 as the minimum value, */
+	/* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
+	/* hoffset low (input), 0x0002 is minimum. See comment above. */
+	R_C4_B_HORIZ_INPUT_WINDOW_START, 0x00,
+	R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
+
+	/* hsize 0x02d0 = 720 */
+	R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
+	R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
+
+	/* voffset 0x16 = 22 */
+	R_C8_B_VERT_INPUT_WINDOW_START, 0x16,
+	R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
+
+	/* vsize 0x0120 = 288 */
+	R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0x20,
+	R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x01,
+
+	/* hsize 0x02d0 = 720 */
+	R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
+	R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
+
+	R_F0_LFCO_PER_LINE, 0xb0,		/* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
+	R_F1_P_I_PARAM_SELECT, 0x05,		/* low bit with 0xF0, (was 0x05) */
+	R_F5_PULSGEN_LINE_LENGTH, 0xb0,
+	R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
+
+	0x00, 0x00
+};
+
+/* ============== SAA7715 VIDEO templates (end) =======  */
+
+static const unsigned char saa7115_cfg_vbi_on[] = {
+	R_80_GLOBAL_CNTL_1, 0x00,			/* reset tasks */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,		/* reset scaler */
+	R_80_GLOBAL_CNTL_1, 0x30,			/* Activate both tasks */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,		/* activate scaler */
+	R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,	/* Enable I-port output */
+
+	0x00, 0x00
+};
+
+static const unsigned char saa7115_cfg_vbi_off[] = {
+	R_80_GLOBAL_CNTL_1, 0x00,			/* reset tasks */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,		/* reset scaler */
+	R_80_GLOBAL_CNTL_1, 0x20,			/* Activate only task "B" */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,		/* activate scaler */
+	R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,	/* Enable I-port output */
+
+	0x00, 0x00
+};
+
+
+static const unsigned char saa7115_init_misc[] = {
+	R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01,
+	R_83_X_PORT_I_O_ENA_AND_OUT_CLK, 0x01,
+	R_84_I_PORT_SIGNAL_DEF, 0x20,
+	R_85_I_PORT_SIGNAL_POLAR, 0x21,
+	R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT, 0xc5,
+	R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,
+
+	/* Task A */
+	R_A0_A_HORIZ_PRESCALING, 0x01,
+	R_A1_A_ACCUMULATION_LENGTH, 0x00,
+	R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
+
+	/* Configure controls at nominal value*/
+	R_A4_A_LUMA_BRIGHTNESS_CNTL, 0x80,
+	R_A5_A_LUMA_CONTRAST_CNTL, 0x40,
+	R_A6_A_CHROMA_SATURATION_CNTL, 0x40,
+
+	/* note: 2 x zoom ensures that VBI lines have same length as video lines. */
+	R_A8_A_HORIZ_LUMA_SCALING_INC, 0x00,
+	R_A9_A_HORIZ_LUMA_SCALING_INC_MSB, 0x02,
+
+	R_AA_A_HORIZ_LUMA_PHASE_OFF, 0x00,
+
+	/* must be horiz lum scaling / 2 */
+	R_AC_A_HORIZ_CHROMA_SCALING_INC, 0x00,
+	R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB, 0x01,
+
+	/* must be offset luma / 2 */
+	R_AE_A_HORIZ_CHROMA_PHASE_OFF, 0x00,
+
+	R_B0_A_VERT_LUMA_SCALING_INC, 0x00,
+	R_B1_A_VERT_LUMA_SCALING_INC_MSB, 0x04,
+
+	R_B2_A_VERT_CHROMA_SCALING_INC, 0x00,
+	R_B3_A_VERT_CHROMA_SCALING_INC_MSB, 0x04,
+
+	R_B4_A_VERT_SCALING_MODE_CNTL, 0x01,
+
+	R_B8_A_VERT_CHROMA_PHASE_OFF_00, 0x00,
+	R_B9_A_VERT_CHROMA_PHASE_OFF_01, 0x00,
+	R_BA_A_VERT_CHROMA_PHASE_OFF_10, 0x00,
+	R_BB_A_VERT_CHROMA_PHASE_OFF_11, 0x00,
+
+	R_BC_A_VERT_LUMA_PHASE_OFF_00, 0x00,
+	R_BD_A_VERT_LUMA_PHASE_OFF_01, 0x00,
+	R_BE_A_VERT_LUMA_PHASE_OFF_10, 0x00,
+	R_BF_A_VERT_LUMA_PHASE_OFF_11, 0x00,
+
+	/* Task B */
+	R_D0_B_HORIZ_PRESCALING, 0x01,
+	R_D1_B_ACCUMULATION_LENGTH, 0x00,
+	R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
+
+	/* Configure controls at nominal value*/
+	R_D4_B_LUMA_BRIGHTNESS_CNTL, 0x80,
+	R_D5_B_LUMA_CONTRAST_CNTL, 0x40,
+	R_D6_B_CHROMA_SATURATION_CNTL, 0x40,
+
+	/* hor lum scaling 0x0400 = 1 */
+	R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00,
+	R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
+
+	R_DA_B_HORIZ_LUMA_PHASE_OFF, 0x00,
+
+	/* must be hor lum scaling / 2 */
+	R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
+	R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
+
+	/* must be offset luma / 2 */
+	R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA, 0x00,
+
+	R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
+	R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
+
+	R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
+	R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
+
+	R_E4_B_VERT_SCALING_MODE_CNTL, 0x01,
+
+	R_E8_B_VERT_CHROMA_PHASE_OFF_00, 0x00,
+	R_E9_B_VERT_CHROMA_PHASE_OFF_01, 0x00,
+	R_EA_B_VERT_CHROMA_PHASE_OFF_10, 0x00,
+	R_EB_B_VERT_CHROMA_PHASE_OFF_11, 0x00,
+
+	R_EC_B_VERT_LUMA_PHASE_OFF_00, 0x00,
+	R_ED_B_VERT_LUMA_PHASE_OFF_01, 0x00,
+	R_EE_B_VERT_LUMA_PHASE_OFF_10, 0x00,
+	R_EF_B_VERT_LUMA_PHASE_OFF_11, 0x00,
+
+	R_F2_NOMINAL_PLL2_DTO, 0x50,		/* crystal clock = 24.576 MHz, target = 27MHz */
+	R_F3_PLL_INCREMENT, 0x46,
+	R_F4_PLL2_STATUS, 0x00,
+	R_F7_PULSE_A_POS_MSB, 0x4b,		/* not the recommended settings! */
+	R_F8_PULSE_B_POS, 0x00,
+	R_F9_PULSE_B_POS_MSB, 0x4b,
+	R_FA_PULSE_C_POS, 0x00,
+	R_FB_PULSE_C_POS_MSB, 0x4b,
+
+	/* PLL2 lock detection settings: 71 lines 50% phase error */
+	R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES, 0x88,
+
+	/* Turn off VBI */
+	R_40_SLICER_CNTL_1, 0x20,             /* No framing code errors allowed. */
+	R_41_LCR_BASE, 0xff,
+	R_41_LCR_BASE+1, 0xff,
+	R_41_LCR_BASE+2, 0xff,
+	R_41_LCR_BASE+3, 0xff,
+	R_41_LCR_BASE+4, 0xff,
+	R_41_LCR_BASE+5, 0xff,
+	R_41_LCR_BASE+6, 0xff,
+	R_41_LCR_BASE+7, 0xff,
+	R_41_LCR_BASE+8, 0xff,
+	R_41_LCR_BASE+9, 0xff,
+	R_41_LCR_BASE+10, 0xff,
+	R_41_LCR_BASE+11, 0xff,
+	R_41_LCR_BASE+12, 0xff,
+	R_41_LCR_BASE+13, 0xff,
+	R_41_LCR_BASE+14, 0xff,
+	R_41_LCR_BASE+15, 0xff,
+	R_41_LCR_BASE+16, 0xff,
+	R_41_LCR_BASE+17, 0xff,
+	R_41_LCR_BASE+18, 0xff,
+	R_41_LCR_BASE+19, 0xff,
+	R_41_LCR_BASE+20, 0xff,
+	R_41_LCR_BASE+21, 0xff,
+	R_41_LCR_BASE+22, 0xff,
+	R_58_PROGRAM_FRAMING_CODE, 0x40,
+	R_59_H_OFF_FOR_SLICER, 0x47,
+	R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF, 0x83,
+	R_5D_DID, 0xbd,
+	R_5E_SDID, 0x35,
+
+	R_02_INPUT_CNTL_1, 0xc4, /* input tuner -> input 4, amplifier active */
+
+	R_80_GLOBAL_CNTL_1, 0x20,		/* enable task B */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,
+	0x00, 0x00
+};
+
+static int saa711x_odd_parity(u8 c)
+{
+	c ^= (c >> 4);
+	c ^= (c >> 2);
+	c ^= (c >> 1);
+
+	return c & 1;
+}
+
+static int saa711x_decode_vps(u8 *dst, u8 *p)
+{
+	static const u8 biphase_tbl[] = {
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+		0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+		0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+		0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+		0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+		0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+		0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+		0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
+		0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
+		0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
+		0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
+		0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+		0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+		0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+		0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+		0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
+		0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
+		0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
+		0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
+		0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+		0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+		0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+		0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+		0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+		0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+	};
+	int i;
+	u8 c, err = 0;
+
+	for (i = 0; i < 2 * 13; i += 2) {
+		err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
+		c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4);
+		dst[i / 2] = c;
+	}
+	return err & 0xf0;
+}
+
+static int saa711x_decode_wss(u8 *p)
+{
+	static const int wss_bits[8] = {
+		0, 0, 0, 1, 0, 1, 1, 1
+	};
+	unsigned char parity;
+	int wss = 0;
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		int b1 = wss_bits[p[i] & 7];
+		int b2 = wss_bits[(p[i] >> 3) & 7];
+
+		if (b1 == b2)
+			return -1;
+		wss |= b2 << i;
+	}
+	parity = wss & 15;
+	parity ^= parity >> 2;
+	parity ^= parity >> 1;
+
+	if (!(parity & 1))
+		return -1;
+
+	return wss;
+}
+
+static int saa711x_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
+{
+	struct saa711x_state *state = to_state(sd);
+	u32 acpf;
+	u32 acni;
+	u32 hz;
+	u64 f;
+	u8 acc = 0; 	/* reg 0x3a, audio clock control */
+
+	/* Checks for chips that don't have audio clock (saa7111, saa7113) */
+	if (!saa711x_has_reg(state->ident, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
+		return 0;
+
+	v4l2_dbg(1, debug, sd, "set audio clock freq: %d\n", freq);
+
+	/* sanity check */
+	if (freq < 32000 || freq > 48000)
+		return -EINVAL;
+
+	/* hz is the refresh rate times 100 */
+	hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
+	/* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
+	acpf = (25600 * freq) / hz;
+	/* acni = (256 * freq * 2^23) / crystal_frequency =
+		  (freq * 2^(8+23)) / crystal_frequency =
+		  (freq << 31) / crystal_frequency */
+	f = freq;
+	f = f << 31;
+	do_div(f, state->crystal_freq);
+	acni = f;
+	if (state->ucgc) {
+		acpf = acpf * state->cgcdiv / 16;
+		acni = acni * state->cgcdiv / 16;
+		acc = 0x80;
+		if (state->cgcdiv == 3)
+			acc |= 0x40;
+	}
+	if (state->apll)
+		acc |= 0x08;
+
+	saa711x_write(sd, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
+	saa711x_write(sd, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
+	saa711x_write(sd, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
+
+	saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
+	saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
+							(acpf >> 8) & 0xff);
+	saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
+							(acpf >> 16) & 0x03);
+
+	saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
+	saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
+	saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
+	state->audclk_freq = freq;
+	return 0;
+}
+
+static int saa711x_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct saa711x_state *state = to_state(sd);
+
+	switch (ctrl->id) {
+	case V4L2_CID_CHROMA_AGC:
+		/* chroma gain cluster */
+		if (state->agc->val)
+			state->gain->val =
+				saa711x_read(sd, R_0F_CHROMA_GAIN_CNTL) & 0x7f;
+		break;
+	}
+	return 0;
+}
+
+static int saa711x_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct saa711x_state *state = to_state(sd);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		saa711x_write(sd, R_0A_LUMA_BRIGHT_CNTL, ctrl->val);
+		break;
+
+	case V4L2_CID_CONTRAST:
+		saa711x_write(sd, R_0B_LUMA_CONTRAST_CNTL, ctrl->val);
+		break;
+
+	case V4L2_CID_SATURATION:
+		saa711x_write(sd, R_0C_CHROMA_SAT_CNTL, ctrl->val);
+		break;
+
+	case V4L2_CID_HUE:
+		saa711x_write(sd, R_0D_CHROMA_HUE_CNTL, ctrl->val);
+		break;
+
+	case V4L2_CID_CHROMA_AGC:
+		/* chroma gain cluster */
+		if (state->agc->val)
+			saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, state->gain->val);
+		else
+			saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, state->gain->val | 0x80);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int saa711x_set_size(struct v4l2_subdev *sd, int width, int height)
+{
+	struct saa711x_state *state = to_state(sd);
+	int HPSC, HFSC;
+	int VSCY;
+	int res;
+	int is_50hz = state->std & V4L2_STD_625_50;
+	int Vsrc = is_50hz ? 576 : 480;
+
+	v4l2_dbg(1, debug, sd, "decoder set size to %ix%i\n", width, height);
+
+	/* FIXME need better bounds checking here */
+	if ((width < 1) || (width > 1440))
+		return -EINVAL;
+	if ((height < 1) || (height > Vsrc))
+		return -EINVAL;
+
+	if (!saa711x_has_reg(state->ident, R_D0_B_HORIZ_PRESCALING)) {
+		/* Decoder only supports 720 columns and 480 or 576 lines */
+		if (width != 720)
+			return -EINVAL;
+		if (height != Vsrc)
+			return -EINVAL;
+	}
+
+	state->width = width;
+	state->height = height;
+
+	if (!saa711x_has_reg(state->ident, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH))
+		return 0;
+
+	/* probably have a valid size, let's set it */
+	/* Set output width/height */
+	/* width */
+
+	saa711x_write(sd, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
+					(u8) (width & 0xff));
+	saa711x_write(sd, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
+					(u8) ((width >> 8) & 0xff));
+
+	/* Vertical Scaling uses height/2 */
+	res = height / 2;
+
+	/* On 60Hz, it is using a higher Vertical Output Size */
+	if (!is_50hz)
+		res += (VRES_60HZ - 480) >> 1;
+
+		/* height */
+	saa711x_write(sd, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
+					(u8) (res & 0xff));
+	saa711x_write(sd, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
+					(u8) ((res >> 8) & 0xff));
+
+	/* Scaling settings */
+	/* Hprescaler is floor(inres/outres) */
+	HPSC = (int)(720 / width);
+	/* 0 is not allowed (div. by zero) */
+	HPSC = HPSC ? HPSC : 1;
+	HFSC = (int)((1024 * 720) / (HPSC * width));
+	/* FIXME hardcodes to "Task B"
+	 * write H prescaler integer */
+	saa711x_write(sd, R_D0_B_HORIZ_PRESCALING,
+				(u8) (HPSC & 0x3f));
+
+	v4l2_dbg(1, debug, sd, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
+	/* write H fine-scaling (luminance) */
+	saa711x_write(sd, R_D8_B_HORIZ_LUMA_SCALING_INC,
+				(u8) (HFSC & 0xff));
+	saa711x_write(sd, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
+				(u8) ((HFSC >> 8) & 0xff));
+	/* write H fine-scaling (chrominance)
+	 * must be lum/2, so i'll just bitshift :) */
+	saa711x_write(sd, R_DC_B_HORIZ_CHROMA_SCALING,
+				(u8) ((HFSC >> 1) & 0xff));
+	saa711x_write(sd, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
+				(u8) ((HFSC >> 9) & 0xff));
+
+	VSCY = (int)((1024 * Vsrc) / height);
+	v4l2_dbg(1, debug, sd, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
+
+	/* Correct Contrast and Luminance */
+	saa711x_write(sd, R_D5_B_LUMA_CONTRAST_CNTL,
+					(u8) (64 * 1024 / VSCY));
+	saa711x_write(sd, R_D6_B_CHROMA_SATURATION_CNTL,
+					(u8) (64 * 1024 / VSCY));
+
+		/* write V fine-scaling (luminance) */
+	saa711x_write(sd, R_E0_B_VERT_LUMA_SCALING_INC,
+					(u8) (VSCY & 0xff));
+	saa711x_write(sd, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
+					(u8) ((VSCY >> 8) & 0xff));
+		/* write V fine-scaling (chrominance) */
+	saa711x_write(sd, R_E2_B_VERT_CHROMA_SCALING_INC,
+					(u8) (VSCY & 0xff));
+	saa711x_write(sd, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
+					(u8) ((VSCY >> 8) & 0xff));
+
+	saa711x_writeregs(sd, saa7115_cfg_reset_scaler);
+
+	/* Activates task "B" */
+	saa711x_write(sd, R_80_GLOBAL_CNTL_1,
+				saa711x_read(sd, R_80_GLOBAL_CNTL_1) | 0x20);
+
+	return 0;
+}
+
+static void saa711x_set_v4lstd(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct saa711x_state *state = to_state(sd);
+
+	/* Prevent unnecessary standard changes. During a standard
+	   change the I-Port is temporarily disabled. Any devices
+	   reading from that port can get confused.
+	   Note that s_std is also used to switch from
+	   radio to TV mode, so if a s_std is broadcast to
+	   all I2C devices then you do not want to have an unwanted
+	   side-effect here. */
+	if (std == state->std)
+		return;
+
+	state->std = std;
+
+	// This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
+	if (std & V4L2_STD_525_60) {
+		v4l2_dbg(1, debug, sd, "decoder set standard 60 Hz\n");
+		saa711x_writeregs(sd, saa7115_cfg_60hz_video);
+		saa711x_set_size(sd, 720, 480);
+	} else {
+		v4l2_dbg(1, debug, sd, "decoder set standard 50 Hz\n");
+		saa711x_writeregs(sd, saa7115_cfg_50hz_video);
+		saa711x_set_size(sd, 720, 576);
+	}
+
+	/* Register 0E - Bits D6-D4 on NO-AUTO mode
+		(SAA7111 and SAA7113 doesn't have auto mode)
+	    50 Hz / 625 lines           60 Hz / 525 lines
+	000 PAL BGDHI (4.43Mhz)         NTSC M (3.58MHz)
+	001 NTSC 4.43 (50 Hz)           PAL 4.43 (60 Hz)
+	010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz)
+	011 NTSC N (3.58MHz)            PAL M (3.58MHz)
+	100 reserved                    NTSC-Japan (3.58MHz)
+	*/
+	if (state->ident <= V4L2_IDENT_SAA7113) {
+		u8 reg = saa711x_read(sd, R_0E_CHROMA_CNTL_1) & 0x8f;
+
+		if (std == V4L2_STD_PAL_M) {
+			reg |= 0x30;
+		} else if (std == V4L2_STD_PAL_Nc) {
+			reg |= 0x20;
+		} else if (std == V4L2_STD_PAL_60) {
+			reg |= 0x10;
+		} else if (std == V4L2_STD_NTSC_M_JP) {
+			reg |= 0x40;
+		} else if (std & V4L2_STD_SECAM) {
+			reg |= 0x50;
+		}
+		saa711x_write(sd, R_0E_CHROMA_CNTL_1, reg);
+	} else {
+		/* restart task B if needed */
+		int taskb = saa711x_read(sd, R_80_GLOBAL_CNTL_1) & 0x10;
+
+		if (taskb && state->ident == V4L2_IDENT_SAA7114) {
+			saa711x_writeregs(sd, saa7115_cfg_vbi_on);
+		}
+
+		/* switch audio mode too! */
+		saa711x_s_clock_freq(sd, state->audclk_freq);
+	}
+}
+
+/* setup the sliced VBI lcr registers according to the sliced VBI format */
+static void saa711x_set_lcr(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt)
+{
+	struct saa711x_state *state = to_state(sd);
+	int is_50hz = (state->std & V4L2_STD_625_50);
+	u8 lcr[24];
+	int i, x;
+
+#if 1
+	/* saa7113/7114/7118 VBI support are experimental */
+	if (!saa711x_has_reg(state->ident, R_41_LCR_BASE))
+		return;
+
+#else
+	/* SAA7113 and SAA7118 also should support VBI - Need testing */
+	if (state->ident != V4L2_IDENT_SAA7115)
+		return;
+#endif
+
+	for (i = 0; i <= 23; i++)
+		lcr[i] = 0xff;
+
+	if (fmt == NULL) {
+		/* raw VBI */
+		if (is_50hz)
+			for (i = 6; i <= 23; i++)
+				lcr[i] = 0xdd;
+		else
+			for (i = 10; i <= 21; i++)
+				lcr[i] = 0xdd;
+	} else {
+		/* sliced VBI */
+		/* first clear lines that cannot be captured */
+		if (is_50hz) {
+			for (i = 0; i <= 5; i++)
+				fmt->service_lines[0][i] =
+					fmt->service_lines[1][i] = 0;
+		}
+		else {
+			for (i = 0; i <= 9; i++)
+				fmt->service_lines[0][i] =
+					fmt->service_lines[1][i] = 0;
+			for (i = 22; i <= 23; i++)
+				fmt->service_lines[0][i] =
+					fmt->service_lines[1][i] = 0;
+		}
+
+		/* Now set the lcr values according to the specified service */
+		for (i = 6; i <= 23; i++) {
+			lcr[i] = 0;
+			for (x = 0; x <= 1; x++) {
+				switch (fmt->service_lines[1-x][i]) {
+					case 0:
+						lcr[i] |= 0xf << (4 * x);
+						break;
+					case V4L2_SLICED_TELETEXT_B:
+						lcr[i] |= 1 << (4 * x);
+						break;
+					case V4L2_SLICED_CAPTION_525:
+						lcr[i] |= 4 << (4 * x);
+						break;
+					case V4L2_SLICED_WSS_625:
+						lcr[i] |= 5 << (4 * x);
+						break;
+					case V4L2_SLICED_VPS:
+						lcr[i] |= 7 << (4 * x);
+						break;
+				}
+			}
+		}
+	}
+
+	/* write the lcr registers */
+	for (i = 2; i <= 23; i++) {
+		saa711x_write(sd, i - 2 + R_41_LCR_BASE, lcr[i]);
+	}
+
+	/* enable/disable raw VBI capturing */
+	saa711x_writeregs(sd, fmt == NULL ?
+				saa7115_cfg_vbi_on :
+				saa7115_cfg_vbi_off);
+}
+
+static int saa711x_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *sliced)
+{
+	static u16 lcr2vbi[] = {
+		0, V4L2_SLICED_TELETEXT_B, 0,	/* 1 */
+		0, V4L2_SLICED_CAPTION_525,	/* 4 */
+		V4L2_SLICED_WSS_625, 0,		/* 5 */
+		V4L2_SLICED_VPS, 0, 0, 0, 0,	/* 7 */
+		0, 0, 0, 0
+	};
+	int i;
+
+	memset(sliced, 0, sizeof(*sliced));
+	/* done if using raw VBI */
+	if (saa711x_read(sd, R_80_GLOBAL_CNTL_1) & 0x10)
+		return 0;
+	for (i = 2; i <= 23; i++) {
+		u8 v = saa711x_read(sd, i - 2 + R_41_LCR_BASE);
+
+		sliced->service_lines[0][i] = lcr2vbi[v >> 4];
+		sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
+		sliced->service_set |=
+			sliced->service_lines[0][i] | sliced->service_lines[1][i];
+	}
+	return 0;
+}
+
+static int saa711x_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
+{
+	saa711x_set_lcr(sd, NULL);
+	return 0;
+}
+
+static int saa711x_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt)
+{
+	saa711x_set_lcr(sd, fmt);
+	return 0;
+}
+
+static int saa711x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
+{
+	if (fmt->code != V4L2_MBUS_FMT_FIXED)
+		return -EINVAL;
+	fmt->field = V4L2_FIELD_INTERLACED;
+	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	return saa711x_set_size(sd, fmt->width, fmt->height);
+}
+
+/* Decode the sliced VBI data stream as created by the saa7115.
+   The format is described in the saa7115 datasheet in Tables 25 and 26
+   and in Figure 33.
+   The current implementation uses SAV/EAV codes and not the ancillary data
+   headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV
+   code. */
+static int saa711x_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi)
+{
+	struct saa711x_state *state = to_state(sd);
+	static const char vbi_no_data_pattern[] = {
+		0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
+	};
+	u8 *p = vbi->p;
+	u32 wss;
+	int id1, id2;   /* the ID1 and ID2 bytes from the internal header */
+
+	vbi->type = 0;  /* mark result as a failure */
+	id1 = p[2];
+	id2 = p[3];
+	/* Note: the field bit is inverted for 60 Hz video */
+	if (state->std & V4L2_STD_525_60)
+		id1 ^= 0x40;
+
+	/* Skip internal header, p now points to the start of the payload */
+	p += 4;
+	vbi->p = p;
+
+	/* calculate field and line number of the VBI packet (1-23) */
+	vbi->is_second_field = ((id1 & 0x40) != 0);
+	vbi->line = (id1 & 0x3f) << 3;
+	vbi->line |= (id2 & 0x70) >> 4;
+
+	/* Obtain data type */
+	id2 &= 0xf;
+
+	/* If the VBI slicer does not detect any signal it will fill up
+	   the payload buffer with 0xa0 bytes. */
+	if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
+		return 0;
+
+	/* decode payloads */
+	switch (id2) {
+	case 1:
+		vbi->type = V4L2_SLICED_TELETEXT_B;
+		break;
+	case 4:
+		if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1]))
+			return 0;
+		vbi->type = V4L2_SLICED_CAPTION_525;
+		break;
+	case 5:
+		wss = saa711x_decode_wss(p);
+		if (wss == -1)
+			return 0;
+		p[0] = wss & 0xff;
+		p[1] = wss >> 8;
+		vbi->type = V4L2_SLICED_WSS_625;
+		break;
+	case 7:
+		if (saa711x_decode_vps(p, p) != 0)
+			return 0;
+		vbi->type = V4L2_SLICED_VPS;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+/* ============ SAA7115 AUDIO settings (end) ============= */
+
+static int saa711x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct saa711x_state *state = to_state(sd);
+	int status;
+
+	if (state->radio)
+		return 0;
+	status = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
+
+	v4l2_dbg(1, debug, sd, "status: 0x%02x\n", status);
+	vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
+	return 0;
+}
+
+static int saa711x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct saa711x_state *state = to_state(sd);
+
+	state->radio = 0;
+	saa711x_set_v4lstd(sd, std);
+	return 0;
+}
+
+static int saa711x_s_radio(struct v4l2_subdev *sd)
+{
+	struct saa711x_state *state = to_state(sd);
+
+	state->radio = 1;
+	return 0;
+}
+
+static int saa711x_s_routing(struct v4l2_subdev *sd,
+			     u32 input, u32 output, u32 config)
+{
+	struct saa711x_state *state = to_state(sd);
+	u8 mask = (state->ident <= V4L2_IDENT_SAA7111A) ? 0xf8 : 0xf0;
+
+	v4l2_dbg(1, debug, sd, "decoder set input %d output %d\n",
+		input, output);
+
+	/* saa7111/3 does not have these inputs */
+	if (state->ident <= V4L2_IDENT_SAA7113 &&
+	    (input == SAA7115_COMPOSITE4 ||
+	     input == SAA7115_COMPOSITE5)) {
+		return -EINVAL;
+	}
+	if (input > SAA7115_SVIDEO3)
+		return -EINVAL;
+	if (state->input == input && state->output == output)
+		return 0;
+	v4l2_dbg(1, debug, sd, "now setting %s input %s output\n",
+		(input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite",
+		(output == SAA7115_IPORT_ON) ? "iport on" : "iport off");
+	state->input = input;
+
+	/* saa7111 has slightly different input numbering */
+	if (state->ident <= V4L2_IDENT_SAA7111A) {
+		if (input >= SAA7115_COMPOSITE4)
+			input -= 2;
+		/* saa7111 specific */
+		saa711x_write(sd, R_10_CHROMA_CNTL_2,
+				(saa711x_read(sd, R_10_CHROMA_CNTL_2) & 0x3f) |
+				((output & 0xc0) ^ 0x40));
+		saa711x_write(sd, R_13_RT_X_PORT_OUT_CNTL,
+				(saa711x_read(sd, R_13_RT_X_PORT_OUT_CNTL) & 0xf0) |
+				((output & 2) ? 0x0a : 0));
+	}
+
+	/* select mode */
+	saa711x_write(sd, R_02_INPUT_CNTL_1,
+		      (saa711x_read(sd, R_02_INPUT_CNTL_1) & mask) |
+		       input);
+
+	/* bypass chrominance trap for S-Video modes */
+	saa711x_write(sd, R_09_LUMA_CNTL,
+			(saa711x_read(sd, R_09_LUMA_CNTL) & 0x7f) |
+			(state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
+
+	state->output = output;
+	if (state->ident == V4L2_IDENT_SAA7114 ||
+			state->ident == V4L2_IDENT_SAA7115) {
+		saa711x_write(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK,
+				(saa711x_read(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
+				(state->output & 0x01));
+	}
+	return 0;
+}
+
+static int saa711x_s_gpio(struct v4l2_subdev *sd, u32 val)
+{
+	struct saa711x_state *state = to_state(sd);
+
+	if (state->ident > V4L2_IDENT_SAA7111A)
+		return -EINVAL;
+	saa711x_write(sd, 0x11, (saa711x_read(sd, 0x11) & 0x7f) |
+		(val ? 0x80 : 0));
+	return 0;
+}
+
+static int saa711x_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct saa711x_state *state = to_state(sd);
+
+	v4l2_dbg(1, debug, sd, "%s output\n",
+			enable ? "enable" : "disable");
+
+	if (state->enable == enable)
+		return 0;
+	state->enable = enable;
+	if (!saa711x_has_reg(state->ident, R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED))
+		return 0;
+	saa711x_write(sd, R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, state->enable);
+	return 0;
+}
+
+static int saa711x_s_crystal_freq(struct v4l2_subdev *sd, u32 freq, u32 flags)
+{
+	struct saa711x_state *state = to_state(sd);
+
+	if (freq != SAA7115_FREQ_32_11_MHZ && freq != SAA7115_FREQ_24_576_MHZ)
+		return -EINVAL;
+	state->crystal_freq = freq;
+	state->cgcdiv = (flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
+	state->ucgc = (flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
+	state->apll = (flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
+	saa711x_s_clock_freq(sd, state->audclk_freq);
+	return 0;
+}
+
+static int saa711x_reset(struct v4l2_subdev *sd, u32 val)
+{
+	v4l2_dbg(1, debug, sd, "decoder RESET\n");
+	saa711x_writeregs(sd, saa7115_cfg_reset_scaler);
+	return 0;
+}
+
+static int saa711x_g_vbi_data(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_data *data)
+{
+	/* Note: the internal field ID is inverted for NTSC,
+	   so data->field 0 maps to the saa7115 even field,
+	   whereas for PAL it maps to the saa7115 odd field. */
+	switch (data->id) {
+	case V4L2_SLICED_WSS_625:
+		if (saa711x_read(sd, 0x6b) & 0xc0)
+			return -EIO;
+		data->data[0] = saa711x_read(sd, 0x6c);
+		data->data[1] = saa711x_read(sd, 0x6d);
+		return 0;
+	case V4L2_SLICED_CAPTION_525:
+		if (data->field == 0) {
+			/* CC */
+			if (saa711x_read(sd, 0x66) & 0x30)
+				return -EIO;
+			data->data[0] = saa711x_read(sd, 0x69);
+			data->data[1] = saa711x_read(sd, 0x6a);
+			return 0;
+		}
+		/* XDS */
+		if (saa711x_read(sd, 0x66) & 0xc0)
+			return -EIO;
+		data->data[0] = saa711x_read(sd, 0x67);
+		data->data[1] = saa711x_read(sd, 0x68);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	struct saa711x_state *state = to_state(sd);
+	int reg1f, reg1e;
+
+	/*
+	 * The V4L2 core already initializes std with all supported
+	 * Standards. All driver needs to do is to mask it, to remove
+	 * standards that don't apply from the mask
+	 */
+
+	reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
+	v4l2_dbg(1, debug, sd, "Status byte 2 (0x1f)=0x%02x\n", reg1f);
+
+	/* horizontal/vertical not locked */
+	if (reg1f & 0x40)
+		goto ret;
+
+	if (reg1f & 0x20)
+		*std &= V4L2_STD_525_60;
+	else
+		*std &= V4L2_STD_625_50;
+
+	if (state->ident != V4L2_IDENT_SAA7115)
+		goto ret;
+
+	reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
+
+	switch (reg1e & 0x03) {
+	case 1:
+		*std &= V4L2_STD_NTSC;
+		break;
+	case 2:
+		/*
+		 * V4L2_STD_PAL just cover the european PAL standards.
+		 * This is wrong, as the device could also be using an
+		 * other PAL standard.
+		 */
+		*std &= V4L2_STD_PAL   | V4L2_STD_PAL_N  | V4L2_STD_PAL_Nc |
+			V4L2_STD_PAL_M | V4L2_STD_PAL_60;
+		break;
+	case 3:
+		*std &= V4L2_STD_SECAM;
+		break;
+	default:
+		/* Can't detect anything */
+		break;
+	}
+
+	v4l2_dbg(1, debug, sd, "Status byte 1 (0x1e)=0x%02x\n", reg1e);
+
+ret:
+	v4l2_dbg(1, debug, sd, "detected std mask = %08Lx\n", *std);
+
+	return 0;
+}
+
+static int saa711x_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+	struct saa711x_state *state = to_state(sd);
+	int reg1e = 0x80;
+	int reg1f;
+
+	*status = V4L2_IN_ST_NO_SIGNAL;
+	if (state->ident == V4L2_IDENT_SAA7115)
+		reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
+	reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
+	if ((reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80)
+		*status = 0;
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int saa711x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	reg->val = saa711x_read(sd, reg->reg & 0xff);
+	reg->size = 1;
+	return 0;
+}
+
+static int saa711x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	saa711x_write(sd, reg->reg & 0xff, reg->val & 0xff);
+	return 0;
+}
+#endif
+
+static int saa711x_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct saa711x_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, state->ident, 0);
+}
+
+static int saa711x_log_status(struct v4l2_subdev *sd)
+{
+	struct saa711x_state *state = to_state(sd);
+	int reg1e, reg1f;
+	int signalOk;
+	int vcr;
+
+	v4l2_info(sd, "Audio frequency: %d Hz\n", state->audclk_freq);
+	if (state->ident != V4L2_IDENT_SAA7115) {
+		/* status for the saa7114 */
+		reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
+		signalOk = (reg1f & 0xc1) == 0x81;
+		v4l2_info(sd, "Video signal:    %s\n", signalOk ? "ok" : "bad");
+		v4l2_info(sd, "Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
+		return 0;
+	}
+
+	/* status for the saa7115 */
+	reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
+	reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
+
+	signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
+	vcr = !(reg1f & 0x10);
+
+	if (state->input >= 6)
+		v4l2_info(sd, "Input:           S-Video %d\n", state->input - 6);
+	else
+		v4l2_info(sd, "Input:           Composite %d\n", state->input);
+	v4l2_info(sd, "Video signal:    %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
+	v4l2_info(sd, "Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
+
+	switch (reg1e & 0x03) {
+	case 1:
+		v4l2_info(sd, "Detected format: NTSC\n");
+		break;
+	case 2:
+		v4l2_info(sd, "Detected format: PAL\n");
+		break;
+	case 3:
+		v4l2_info(sd, "Detected format: SECAM\n");
+		break;
+	default:
+		v4l2_info(sd, "Detected format: BW/No color\n");
+		break;
+	}
+	v4l2_info(sd, "Width, Height:   %d, %d\n", state->width, state->height);
+	v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_ctrl_ops saa711x_ctrl_ops = {
+	.s_ctrl = saa711x_s_ctrl,
+	.g_volatile_ctrl = saa711x_g_volatile_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops saa711x_core_ops = {
+	.log_status = saa711x_log_status,
+	.g_chip_ident = saa711x_g_chip_ident,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+	.s_std = saa711x_s_std,
+	.reset = saa711x_reset,
+	.s_gpio = saa711x_s_gpio,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = saa711x_g_register,
+	.s_register = saa711x_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops saa711x_tuner_ops = {
+	.s_radio = saa711x_s_radio,
+	.g_tuner = saa711x_g_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops saa711x_audio_ops = {
+	.s_clock_freq = saa711x_s_clock_freq,
+};
+
+static const struct v4l2_subdev_video_ops saa711x_video_ops = {
+	.s_routing = saa711x_s_routing,
+	.s_crystal_freq = saa711x_s_crystal_freq,
+	.s_mbus_fmt = saa711x_s_mbus_fmt,
+	.s_stream = saa711x_s_stream,
+	.querystd = saa711x_querystd,
+	.g_input_status = saa711x_g_input_status,
+};
+
+static const struct v4l2_subdev_vbi_ops saa711x_vbi_ops = {
+	.g_vbi_data = saa711x_g_vbi_data,
+	.decode_vbi_line = saa711x_decode_vbi_line,
+	.g_sliced_fmt = saa711x_g_sliced_fmt,
+	.s_sliced_fmt = saa711x_s_sliced_fmt,
+	.s_raw_fmt = saa711x_s_raw_fmt,
+};
+
+static const struct v4l2_subdev_ops saa711x_ops = {
+	.core = &saa711x_core_ops,
+	.tuner = &saa711x_tuner_ops,
+	.audio = &saa711x_audio_ops,
+	.video = &saa711x_video_ops,
+	.vbi = &saa711x_vbi_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int saa711x_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct saa711x_state *state;
+	struct v4l2_subdev *sd;
+	struct v4l2_ctrl_handler *hdl;
+	int i;
+	char name[17];
+	char chip_id;
+	int autodetect = !id || id->driver_data == 1;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	for (i = 0; i < 0x0f; i++) {
+		i2c_smbus_write_byte_data(client, 0, i);
+		name[i] = (i2c_smbus_read_byte_data(client, 0) & 0x0f) + '0';
+		if (name[i] > '9')
+			name[i] += 'a' - '9' - 1;
+	}
+	name[i] = '\0';
+
+	chip_id = name[5];
+
+	/* Check whether this chip is part of the saa711x series */
+	if (memcmp(name + 1, "f711", 4)) {
+		v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n",
+			client->addr << 1, name);
+		return -ENODEV;
+	}
+
+	/* Safety check */
+	if (!autodetect && id->name[6] != chip_id) {
+		v4l_warn(client, "found saa711%c while %s was expected\n",
+			 chip_id, id->name);
+	}
+	snprintf(client->name, sizeof(client->name), "saa711%c", chip_id);
+	v4l_info(client, "saa711%c found (%s) @ 0x%x (%s)\n", chip_id, name,
+		 client->addr << 1, client->adapter->name);
+
+	state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &saa711x_ops);
+
+	hdl = &state->hdl;
+	v4l2_ctrl_handler_init(hdl, 6);
+	/* add in ascending ID order */
+	v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 127, 1, 64);
+	v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 127, 1, 64);
+	v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
+			V4L2_CID_HUE, -128, 127, 1, 0);
+	state->agc = v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
+			V4L2_CID_CHROMA_AGC, 0, 1, 1, 1);
+	state->gain = v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
+			V4L2_CID_CHROMA_GAIN, 0, 127, 1, 40);
+	sd->ctrl_handler = hdl;
+	if (hdl->error) {
+		int err = hdl->error;
+
+		v4l2_ctrl_handler_free(hdl);
+		kfree(state);
+		return err;
+	}
+	v4l2_ctrl_auto_cluster(2, &state->agc, 0, true);
+
+	state->input = -1;
+	state->output = SAA7115_IPORT_ON;
+	state->enable = 1;
+	state->radio = 0;
+	switch (chip_id) {
+	case '1':
+		state->ident = V4L2_IDENT_SAA7111;
+		if (saa711x_read(sd, R_00_CHIP_VERSION) & 0xf0) {
+			v4l_info(client, "saa7111a variant found\n");
+			state->ident = V4L2_IDENT_SAA7111A;
+		}
+		break;
+	case '3':
+		state->ident = V4L2_IDENT_SAA7113;
+		break;
+	case '4':
+		state->ident = V4L2_IDENT_SAA7114;
+		break;
+	case '5':
+		state->ident = V4L2_IDENT_SAA7115;
+		break;
+	case '8':
+		state->ident = V4L2_IDENT_SAA7118;
+		break;
+	default:
+		state->ident = V4L2_IDENT_SAA7111;
+		v4l2_info(sd, "WARNING: Chip is not known - Falling back to saa7111\n");
+		break;
+	}
+
+	state->audclk_freq = 48000;
+
+	v4l2_dbg(1, debug, sd, "writing init values\n");
+
+	/* init to 60hz/48khz */
+	state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
+	switch (state->ident) {
+	case V4L2_IDENT_SAA7111:
+	case V4L2_IDENT_SAA7111A:
+		saa711x_writeregs(sd, saa7111_init);
+		break;
+	case V4L2_IDENT_SAA7113:
+		saa711x_writeregs(sd, saa7113_init);
+		break;
+	default:
+		state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
+		saa711x_writeregs(sd, saa7115_init_auto_input);
+	}
+	if (state->ident > V4L2_IDENT_SAA7111A)
+		saa711x_writeregs(sd, saa7115_init_misc);
+	saa711x_set_v4lstd(sd, V4L2_STD_NTSC);
+	v4l2_ctrl_handler_setup(hdl);
+
+	v4l2_dbg(1, debug, sd, "status: (1E) 0x%02x, (1F) 0x%02x\n",
+		saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC),
+		saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC));
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa711x_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(sd->ctrl_handler);
+	kfree(to_state(sd));
+	return 0;
+}
+
+static const struct i2c_device_id saa711x_id[] = {
+	{ "saa7115_auto", 1 }, /* autodetect */
+	{ "saa7111", 0 },
+	{ "saa7113", 0 },
+	{ "saa7114", 0 },
+	{ "saa7115", 0 },
+	{ "saa7118", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, saa711x_id);
+
+static struct i2c_driver saa711x_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "saa7115",
+	},
+	.probe		= saa711x_probe,
+	.remove		= saa711x_remove,
+	.id_table	= saa711x_id,
+};
+
+module_i2c_driver(saa711x_driver);
diff --git a/drivers/media/i2c/saa711x_regs.h b/drivers/media/i2c/saa711x_regs.h
new file mode 100644
index 0000000..4e5f2eb
--- /dev/null
+++ b/drivers/media/i2c/saa711x_regs.h
@@ -0,0 +1,549 @@
+/* saa711x - Philips SAA711x video decoder register specifications
+ *
+ * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * 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.
+ */
+
+#define R_00_CHIP_VERSION                             0x00
+/* Video Decoder */
+	/* Video Decoder - Frontend part */
+#define R_01_INC_DELAY                                0x01
+#define R_02_INPUT_CNTL_1                             0x02
+#define R_03_INPUT_CNTL_2                             0x03
+#define R_04_INPUT_CNTL_3                             0x04
+#define R_05_INPUT_CNTL_4                             0x05
+	/* Video Decoder - Decoder part */
+#define R_06_H_SYNC_START                             0x06
+#define R_07_H_SYNC_STOP                              0x07
+#define R_08_SYNC_CNTL                                0x08
+#define R_09_LUMA_CNTL                                0x09
+#define R_0A_LUMA_BRIGHT_CNTL                         0x0a
+#define R_0B_LUMA_CONTRAST_CNTL                       0x0b
+#define R_0C_CHROMA_SAT_CNTL                          0x0c
+#define R_0D_CHROMA_HUE_CNTL                          0x0d
+#define R_0E_CHROMA_CNTL_1                            0x0e
+#define R_0F_CHROMA_GAIN_CNTL                         0x0f
+#define R_10_CHROMA_CNTL_2                            0x10
+#define R_11_MODE_DELAY_CNTL                          0x11
+#define R_12_RT_SIGNAL_CNTL                           0x12
+#define R_13_RT_X_PORT_OUT_CNTL                       0x13
+#define R_14_ANAL_ADC_COMPAT_CNTL                     0x14
+#define R_15_VGATE_START_FID_CHG                      0x15
+#define R_16_VGATE_STOP                               0x16
+#define R_17_MISC_VGATE_CONF_AND_MSB                  0x17
+#define R_18_RAW_DATA_GAIN_CNTL                       0x18
+#define R_19_RAW_DATA_OFF_CNTL                        0x19
+#define R_1A_COLOR_KILL_LVL_CNTL                      0x1a
+#define R_1B_MISC_TVVCRDET                            0x1b
+#define R_1C_ENHAN_COMB_CTRL1                         0x1c
+#define R_1D_ENHAN_COMB_CTRL2                         0x1d
+#define R_1E_STATUS_BYTE_1_VD_DEC                     0x1e
+#define R_1F_STATUS_BYTE_2_VD_DEC                     0x1f
+
+/* Component processing and interrupt masking part */
+#define R_23_INPUT_CNTL_5                             0x23
+#define R_24_INPUT_CNTL_6                             0x24
+#define R_25_INPUT_CNTL_7                             0x25
+#define R_29_COMP_DELAY                               0x29
+#define R_2A_COMP_BRIGHT_CNTL                         0x2a
+#define R_2B_COMP_CONTRAST_CNTL                       0x2b
+#define R_2C_COMP_SAT_CNTL                            0x2c
+#define R_2D_INTERRUPT_MASK_1                         0x2d
+#define R_2E_INTERRUPT_MASK_2                         0x2e
+#define R_2F_INTERRUPT_MASK_3                         0x2f
+
+/* Audio clock generator part */
+#define R_30_AUD_MAST_CLK_CYCLES_PER_FIELD            0x30
+#define R_34_AUD_MAST_CLK_NOMINAL_INC                 0x34
+#define R_38_CLK_RATIO_AMXCLK_TO_ASCLK                0x38
+#define R_39_CLK_RATIO_ASCLK_TO_ALRCLK                0x39
+#define R_3A_AUD_CLK_GEN_BASIC_SETUP                  0x3a
+
+/* General purpose VBI data slicer part */
+#define R_40_SLICER_CNTL_1                            0x40
+#define R_41_LCR_BASE                                 0x41
+#define R_58_PROGRAM_FRAMING_CODE                     0x58
+#define R_59_H_OFF_FOR_SLICER                         0x59
+#define R_5A_V_OFF_FOR_SLICER                         0x5a
+#define R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF          0x5b
+#define R_5D_DID                                      0x5d
+#define R_5E_SDID                                     0x5e
+#define R_60_SLICER_STATUS_BYTE_0                     0x60
+#define R_61_SLICER_STATUS_BYTE_1                     0x61
+#define R_62_SLICER_STATUS_BYTE_2                     0x62
+
+/* X port, I port and the scaler part */
+	/* Task independent global settings */
+#define R_80_GLOBAL_CNTL_1                            0x80
+#define R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F    0x81
+#define R_83_X_PORT_I_O_ENA_AND_OUT_CLK               0x83
+#define R_84_I_PORT_SIGNAL_DEF                        0x84
+#define R_85_I_PORT_SIGNAL_POLAR                      0x85
+#define R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT          0x86
+#define R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED         0x87
+#define R_88_POWER_SAVE_ADC_PORT_CNTL                 0x88
+#define R_8F_STATUS_INFO_SCALER                       0x8f
+	/* Task A definition */
+		/* Basic settings and acquisition window definition */
+#define R_90_A_TASK_HANDLING_CNTL                     0x90
+#define R_91_A_X_PORT_FORMATS_AND_CONF                0x91
+#define R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL          0x92
+#define R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF         0x93
+#define R_94_A_HORIZ_INPUT_WINDOW_START               0x94
+#define R_95_A_HORIZ_INPUT_WINDOW_START_MSB           0x95
+#define R_96_A_HORIZ_INPUT_WINDOW_LENGTH              0x96
+#define R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB          0x97
+#define R_98_A_VERT_INPUT_WINDOW_START                0x98
+#define R_99_A_VERT_INPUT_WINDOW_START_MSB            0x99
+#define R_9A_A_VERT_INPUT_WINDOW_LENGTH               0x9a
+#define R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB           0x9b
+#define R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH             0x9c
+#define R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB         0x9d
+#define R_9E_A_VERT_OUTPUT_WINDOW_LENGTH              0x9e
+#define R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB          0x9f
+		/* FIR filtering and prescaling */
+#define R_A0_A_HORIZ_PRESCALING                       0xa0
+#define R_A1_A_ACCUMULATION_LENGTH                    0xa1
+#define R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER    0xa2
+#define R_A4_A_LUMA_BRIGHTNESS_CNTL                   0xa4
+#define R_A5_A_LUMA_CONTRAST_CNTL                     0xa5
+#define R_A6_A_CHROMA_SATURATION_CNTL                 0xa6
+		/* Horizontal phase scaling */
+#define R_A8_A_HORIZ_LUMA_SCALING_INC                 0xa8
+#define R_A9_A_HORIZ_LUMA_SCALING_INC_MSB             0xa9
+#define R_AA_A_HORIZ_LUMA_PHASE_OFF                   0xaa
+#define R_AC_A_HORIZ_CHROMA_SCALING_INC               0xac
+#define R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB           0xad
+#define R_AE_A_HORIZ_CHROMA_PHASE_OFF                 0xae
+#define R_AF_A_HORIZ_CHROMA_PHASE_OFF_MSB             0xaf
+		/* Vertical scaling */
+#define R_B0_A_VERT_LUMA_SCALING_INC                  0xb0
+#define R_B1_A_VERT_LUMA_SCALING_INC_MSB              0xb1
+#define R_B2_A_VERT_CHROMA_SCALING_INC                0xb2
+#define R_B3_A_VERT_CHROMA_SCALING_INC_MSB            0xb3
+#define R_B4_A_VERT_SCALING_MODE_CNTL                 0xb4
+#define R_B8_A_VERT_CHROMA_PHASE_OFF_00               0xb8
+#define R_B9_A_VERT_CHROMA_PHASE_OFF_01               0xb9
+#define R_BA_A_VERT_CHROMA_PHASE_OFF_10               0xba
+#define R_BB_A_VERT_CHROMA_PHASE_OFF_11               0xbb
+#define R_BC_A_VERT_LUMA_PHASE_OFF_00                 0xbc
+#define R_BD_A_VERT_LUMA_PHASE_OFF_01                 0xbd
+#define R_BE_A_VERT_LUMA_PHASE_OFF_10                 0xbe
+#define R_BF_A_VERT_LUMA_PHASE_OFF_11                 0xbf
+	/* Task B definition */
+		/* Basic settings and acquisition window definition */
+#define R_C0_B_TASK_HANDLING_CNTL                     0xc0
+#define R_C1_B_X_PORT_FORMATS_AND_CONF                0xc1
+#define R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION      0xc2
+#define R_C3_B_I_PORT_FORMATS_AND_CONF                0xc3
+#define R_C4_B_HORIZ_INPUT_WINDOW_START               0xc4
+#define R_C5_B_HORIZ_INPUT_WINDOW_START_MSB           0xc5
+#define R_C6_B_HORIZ_INPUT_WINDOW_LENGTH              0xc6
+#define R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB          0xc7
+#define R_C8_B_VERT_INPUT_WINDOW_START                0xc8
+#define R_C9_B_VERT_INPUT_WINDOW_START_MSB            0xc9
+#define R_CA_B_VERT_INPUT_WINDOW_LENGTH               0xca
+#define R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB           0xcb
+#define R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH             0xcc
+#define R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB         0xcd
+#define R_CE_B_VERT_OUTPUT_WINDOW_LENGTH              0xce
+#define R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB          0xcf
+		/* FIR filtering and prescaling */
+#define R_D0_B_HORIZ_PRESCALING                       0xd0
+#define R_D1_B_ACCUMULATION_LENGTH                    0xd1
+#define R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER    0xd2
+#define R_D4_B_LUMA_BRIGHTNESS_CNTL                   0xd4
+#define R_D5_B_LUMA_CONTRAST_CNTL                     0xd5
+#define R_D6_B_CHROMA_SATURATION_CNTL                 0xd6
+		/* Horizontal phase scaling */
+#define R_D8_B_HORIZ_LUMA_SCALING_INC                 0xd8
+#define R_D9_B_HORIZ_LUMA_SCALING_INC_MSB             0xd9
+#define R_DA_B_HORIZ_LUMA_PHASE_OFF                   0xda
+#define R_DC_B_HORIZ_CHROMA_SCALING                   0xdc
+#define R_DD_B_HORIZ_CHROMA_SCALING_MSB               0xdd
+#define R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA              0xde
+		/* Vertical scaling */
+#define R_E0_B_VERT_LUMA_SCALING_INC                  0xe0
+#define R_E1_B_VERT_LUMA_SCALING_INC_MSB              0xe1
+#define R_E2_B_VERT_CHROMA_SCALING_INC                0xe2
+#define R_E3_B_VERT_CHROMA_SCALING_INC_MSB            0xe3
+#define R_E4_B_VERT_SCALING_MODE_CNTL                 0xe4
+#define R_E8_B_VERT_CHROMA_PHASE_OFF_00               0xe8
+#define R_E9_B_VERT_CHROMA_PHASE_OFF_01               0xe9
+#define R_EA_B_VERT_CHROMA_PHASE_OFF_10               0xea
+#define R_EB_B_VERT_CHROMA_PHASE_OFF_11               0xeb
+#define R_EC_B_VERT_LUMA_PHASE_OFF_00                 0xec
+#define R_ED_B_VERT_LUMA_PHASE_OFF_01                 0xed
+#define R_EE_B_VERT_LUMA_PHASE_OFF_10                 0xee
+#define R_EF_B_VERT_LUMA_PHASE_OFF_11                 0xef
+
+/* second PLL (PLL2) and Pulsegenerator Programming */
+#define R_F0_LFCO_PER_LINE                            0xf0
+#define R_F1_P_I_PARAM_SELECT                         0xf1
+#define R_F2_NOMINAL_PLL2_DTO                         0xf2
+#define R_F3_PLL_INCREMENT                            0xf3
+#define R_F4_PLL2_STATUS                              0xf4
+#define R_F5_PULSGEN_LINE_LENGTH                      0xf5
+#define R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG      0xf6
+#define R_F7_PULSE_A_POS_MSB                          0xf7
+#define R_F8_PULSE_B_POS                              0xf8
+#define R_F9_PULSE_B_POS_MSB                          0xf9
+#define R_FA_PULSE_C_POS                              0xfa
+#define R_FB_PULSE_C_POS_MSB                          0xfb
+#define R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES     0xff
+
+#if 0
+/* Those structs will be used in the future for debug purposes */
+struct saa711x_reg_descr {
+	u8 reg;
+	int count;
+	char *name;
+};
+
+struct saa711x_reg_descr saa711x_regs[] = {
+	/* REG COUNT NAME */
+	{R_00_CHIP_VERSION,1,
+	 "Chip version"},
+
+	/* Video Decoder: R_01_INC_DELAY to R_1F_STATUS_BYTE_2_VD_DEC */
+
+	/* Video Decoder - Frontend part: R_01_INC_DELAY to R_05_INPUT_CNTL_4 */
+	{R_01_INC_DELAY,1,
+	 "Increment delay"},
+	{R_02_INPUT_CNTL_1,1,
+	 "Analog input control 1"},
+	{R_03_INPUT_CNTL_2,1,
+	 "Analog input control 2"},
+	{R_04_INPUT_CNTL_3,1,
+	 "Analog input control 3"},
+	{R_05_INPUT_CNTL_4,1,
+	 "Analog input control 4"},
+
+	/* Video Decoder - Decoder part: R_06_H_SYNC_START to R_1F_STATUS_BYTE_2_VD_DEC */
+	{R_06_H_SYNC_START,1,
+	 "Horizontal sync start"},
+	{R_07_H_SYNC_STOP,1,
+	 "Horizontal sync stop"},
+	{R_08_SYNC_CNTL,1,
+	 "Sync control"},
+	{R_09_LUMA_CNTL,1,
+	 "Luminance control"},
+	{R_0A_LUMA_BRIGHT_CNTL,1,
+	 "Luminance brightness control"},
+	{R_0B_LUMA_CONTRAST_CNTL,1,
+	 "Luminance contrast control"},
+	{R_0C_CHROMA_SAT_CNTL,1,
+	 "Chrominance saturation control"},
+	{R_0D_CHROMA_HUE_CNTL,1,
+	 "Chrominance hue control"},
+	{R_0E_CHROMA_CNTL_1,1,
+	 "Chrominance control 1"},
+	{R_0F_CHROMA_GAIN_CNTL,1,
+	 "Chrominance gain control"},
+	{R_10_CHROMA_CNTL_2,1,
+	 "Chrominance control 2"},
+	{R_11_MODE_DELAY_CNTL,1,
+	 "Mode/delay control"},
+	{R_12_RT_SIGNAL_CNTL,1,
+	 "RT signal control"},
+	{R_13_RT_X_PORT_OUT_CNTL,1,
+	 "RT/X port output control"},
+	{R_14_ANAL_ADC_COMPAT_CNTL,1,
+	 "Analog/ADC/compatibility control"},
+	{R_15_VGATE_START_FID_CHG,  1,
+	 "VGATE start FID change"},
+	{R_16_VGATE_STOP,1,
+	 "VGATE stop"},
+	{R_17_MISC_VGATE_CONF_AND_MSB,  1,
+	 "Miscellaneous VGATE configuration and MSBs"},
+	{R_18_RAW_DATA_GAIN_CNTL,1,
+	 "Raw data gain control",},
+	{R_19_RAW_DATA_OFF_CNTL,1,
+	 "Raw data offset control",},
+	{R_1A_COLOR_KILL_LVL_CNTL,1,
+	 "Color Killer Level Control"},
+	{ R_1B_MISC_TVVCRDET, 1,
+	  "MISC /TVVCRDET"},
+	{ R_1C_ENHAN_COMB_CTRL1, 1,
+	 "Enhanced comb ctrl1"},
+	{ R_1D_ENHAN_COMB_CTRL2, 1,
+	 "Enhanced comb ctrl1"},
+	{R_1E_STATUS_BYTE_1_VD_DEC,1,
+	 "Status byte 1 video decoder"},
+	{R_1F_STATUS_BYTE_2_VD_DEC,1,
+	 "Status byte 2 video decoder"},
+
+	/* Component processing and interrupt masking part:  0x20h to R_2F_INTERRUPT_MASK_3 */
+	/* 0x20 to 0x22 - Reserved */
+	{R_23_INPUT_CNTL_5,1,
+	 "Analog input control 5"},
+	{R_24_INPUT_CNTL_6,1,
+	 "Analog input control 6"},
+	{R_25_INPUT_CNTL_7,1,
+	 "Analog input control 7"},
+	/* 0x26 to 0x28 - Reserved */
+	{R_29_COMP_DELAY,1,
+	 "Component delay"},
+	{R_2A_COMP_BRIGHT_CNTL,1,
+	 "Component brightness control"},
+	{R_2B_COMP_CONTRAST_CNTL,1,
+	 "Component contrast control"},
+	{R_2C_COMP_SAT_CNTL,1,
+	 "Component saturation control"},
+	{R_2D_INTERRUPT_MASK_1,1,
+	 "Interrupt mask 1"},
+	{R_2E_INTERRUPT_MASK_2,1,
+	 "Interrupt mask 2"},
+	{R_2F_INTERRUPT_MASK_3,1,
+	 "Interrupt mask 3"},
+
+	/* Audio clock generator part: R_30_AUD_MAST_CLK_CYCLES_PER_FIELD to 0x3f */
+	{R_30_AUD_MAST_CLK_CYCLES_PER_FIELD,3,
+	 "Audio master clock cycles per field"},
+	/* 0x33 - Reserved */
+	{R_34_AUD_MAST_CLK_NOMINAL_INC,3,
+	 "Audio master clock nominal increment"},
+	/* 0x37 - Reserved */
+	{R_38_CLK_RATIO_AMXCLK_TO_ASCLK,1,
+	 "Clock ratio AMXCLK to ASCLK"},
+	{R_39_CLK_RATIO_ASCLK_TO_ALRCLK,1,
+	 "Clock ratio ASCLK to ALRCLK"},
+	{R_3A_AUD_CLK_GEN_BASIC_SETUP,1,
+	 "Audio clock generator basic setup"},
+	/* 0x3b-0x3f - Reserved */
+
+	/* General purpose VBI data slicer part: R_40_SLICER_CNTL_1 to 0x7f */
+	{R_40_SLICER_CNTL_1,1,
+	 "Slicer control 1"},
+	{R_41_LCR,23,
+	 "R_41_LCR"},
+	{R_58_PROGRAM_FRAMING_CODE,1,
+	 "Programmable framing code"},
+	{R_59_H_OFF_FOR_SLICER,1,
+	 "Horizontal offset for slicer"},
+	{R_5A_V_OFF_FOR_SLICER,1,
+	 "Vertical offset for slicer"},
+	{R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF,1,
+	 "Field offset and MSBs for horizontal and vertical offset"},
+	{R_5D_DID,1,
+	 "Header and data identification (R_5D_DID)"},
+	{R_5E_SDID,1,
+	 "Sliced data identification (R_5E_SDID) code"},
+	{R_60_SLICER_STATUS_BYTE_0,1,
+	 "Slicer status byte 0"},
+	{R_61_SLICER_STATUS_BYTE_1,1,
+	 "Slicer status byte 1"},
+	{R_62_SLICER_STATUS_BYTE_2,1,
+	 "Slicer status byte 2"},
+	/* 0x63-0x7f - Reserved */
+
+	/* X port, I port and the scaler part: R_80_GLOBAL_CNTL_1 to R_EF_B_VERT_LUMA_PHASE_OFF_11 */
+	/* Task independent global settings: R_80_GLOBAL_CNTL_1 to R_8F_STATUS_INFO_SCALER */
+	{R_80_GLOBAL_CNTL_1,1,
+	 "Global control 1"},
+	{R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F,1,
+	 "Vertical sync and Field ID source selection, retimed V and F signals"},
+	/* 0x82 - Reserved */
+	{R_83_X_PORT_I_O_ENA_AND_OUT_CLK,1,
+	 "X port I/O enable and output clock"},
+	{R_84_I_PORT_SIGNAL_DEF,1,
+	 "I port signal definitions"},
+	{R_85_I_PORT_SIGNAL_POLAR,1,
+	 "I port signal polarities"},
+	{R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT,1,
+	 "I port FIFO flag control and arbitration"},
+	{R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,  1,
+	 "I port I/O enable output clock and gated"},
+	{R_88_POWER_SAVE_ADC_PORT_CNTL,1,
+	 "Power save/ADC port control"},
+	/* 089-0x8e - Reserved */
+	{R_8F_STATUS_INFO_SCALER,1,
+	 "Status information scaler part"},
+
+	/* Task A definition: R_90_A_TASK_HANDLING_CNTL to R_BF_A_VERT_LUMA_PHASE_OFF_11 */
+	/* Task A: Basic settings and acquisition window definition */
+	{R_90_A_TASK_HANDLING_CNTL,1,
+	 "Task A: Task handling control"},
+	{R_91_A_X_PORT_FORMATS_AND_CONF,1,
+	 "Task A: X port formats and configuration"},
+	{R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL,1,
+	 "Task A: X port input reference signal definition"},
+	{R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF,1,
+	 "Task A: I port output formats and configuration"},
+	{R_94_A_HORIZ_INPUT_WINDOW_START,2,
+	 "Task A: Horizontal input window start"},
+	{R_96_A_HORIZ_INPUT_WINDOW_LENGTH,2,
+	 "Task A: Horizontal input window length"},
+	{R_98_A_VERT_INPUT_WINDOW_START,2,
+	 "Task A: Vertical input window start"},
+	{R_9A_A_VERT_INPUT_WINDOW_LENGTH,2,
+	 "Task A: Vertical input window length"},
+	{R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH,2,
+	 "Task A: Horizontal output window length"},
+	{R_9E_A_VERT_OUTPUT_WINDOW_LENGTH,2,
+	 "Task A: Vertical output window length"},
+
+	/* Task A: FIR filtering and prescaling */
+	{R_A0_A_HORIZ_PRESCALING,1,
+	 "Task A: Horizontal prescaling"},
+	{R_A1_A_ACCUMULATION_LENGTH,1,
+	 "Task A: Accumulation length"},
+	{R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER,1,
+	 "Task A: Prescaler DC gain and FIR prefilter"},
+	/* 0xa3 - Reserved */
+	{R_A4_A_LUMA_BRIGHTNESS_CNTL,1,
+	 "Task A: Luminance brightness control"},
+	{R_A5_A_LUMA_CONTRAST_CNTL,1,
+	 "Task A: Luminance contrast control"},
+	{R_A6_A_CHROMA_SATURATION_CNTL,1,
+	 "Task A: Chrominance saturation control"},
+	/* 0xa7 - Reserved */
+
+	/* Task A: Horizontal phase scaling */
+	{R_A8_A_HORIZ_LUMA_SCALING_INC,2,
+	 "Task A: Horizontal luminance scaling increment"},
+	{R_AA_A_HORIZ_LUMA_PHASE_OFF,1,
+	 "Task A: Horizontal luminance phase offset"},
+	/* 0xab - Reserved */
+	{R_AC_A_HORIZ_CHROMA_SCALING_INC,2,
+	 "Task A: Horizontal chrominance scaling increment"},
+	{R_AE_A_HORIZ_CHROMA_PHASE_OFF,1,
+	 "Task A: Horizontal chrominance phase offset"},
+	/* 0xaf - Reserved */
+
+	/* Task A: Vertical scaling */
+	{R_B0_A_VERT_LUMA_SCALING_INC,2,
+	 "Task A: Vertical luminance scaling increment"},
+	{R_B2_A_VERT_CHROMA_SCALING_INC,2,
+	 "Task A: Vertical chrominance scaling increment"},
+	{R_B4_A_VERT_SCALING_MODE_CNTL,1,
+	 "Task A: Vertical scaling mode control"},
+	/* 0xb5-0xb7 - Reserved */
+	{R_B8_A_VERT_CHROMA_PHASE_OFF_00,1,
+	 "Task A: Vertical chrominance phase offset '00'"},
+	{R_B9_A_VERT_CHROMA_PHASE_OFF_01,1,
+	 "Task A: Vertical chrominance phase offset '01'"},
+	{R_BA_A_VERT_CHROMA_PHASE_OFF_10,1,
+	 "Task A: Vertical chrominance phase offset '10'"},
+	{R_BB_A_VERT_CHROMA_PHASE_OFF_11,1,
+	 "Task A: Vertical chrominance phase offset '11'"},
+	{R_BC_A_VERT_LUMA_PHASE_OFF_00,1,
+	 "Task A: Vertical luminance phase offset '00'"},
+	{R_BD_A_VERT_LUMA_PHASE_OFF_01,1,
+	 "Task A: Vertical luminance phase offset '01'"},
+	{R_BE_A_VERT_LUMA_PHASE_OFF_10,1,
+	 "Task A: Vertical luminance phase offset '10'"},
+	{R_BF_A_VERT_LUMA_PHASE_OFF_11,1,
+	 "Task A: Vertical luminance phase offset '11'"},
+
+	/* Task B definition: R_C0_B_TASK_HANDLING_CNTL to R_EF_B_VERT_LUMA_PHASE_OFF_11 */
+	/* Task B: Basic settings and acquisition window definition */
+	{R_C0_B_TASK_HANDLING_CNTL,1,
+	 "Task B: Task handling control"},
+	{R_C1_B_X_PORT_FORMATS_AND_CONF,1,
+	 "Task B: X port formats and configuration"},
+	{R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION,1,
+	 "Task B: Input reference signal definition"},
+	{R_C3_B_I_PORT_FORMATS_AND_CONF,1,
+	 "Task B: I port formats and configuration"},
+	{R_C4_B_HORIZ_INPUT_WINDOW_START,2,
+	 "Task B: Horizontal input window start"},
+	{R_C6_B_HORIZ_INPUT_WINDOW_LENGTH,2,
+	 "Task B: Horizontal input window length"},
+	{R_C8_B_VERT_INPUT_WINDOW_START,2,
+	 "Task B: Vertical input window start"},
+	{R_CA_B_VERT_INPUT_WINDOW_LENGTH,2,
+	 "Task B: Vertical input window length"},
+	{R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,2,
+	 "Task B: Horizontal output window length"},
+	{R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,2,
+	 "Task B: Vertical output window length"},
+
+	/* Task B: FIR filtering and prescaling */
+	{R_D0_B_HORIZ_PRESCALING,1,
+	 "Task B: Horizontal prescaling"},
+	{R_D1_B_ACCUMULATION_LENGTH,1,
+	 "Task B: Accumulation length"},
+	{R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER,1,
+	 "Task B: Prescaler DC gain and FIR prefilter"},
+	/* 0xd3 - Reserved */
+	{R_D4_B_LUMA_BRIGHTNESS_CNTL,1,
+	 "Task B: Luminance brightness control"},
+	{R_D5_B_LUMA_CONTRAST_CNTL,1,
+	 "Task B: Luminance contrast control"},
+	{R_D6_B_CHROMA_SATURATION_CNTL,1,
+	 "Task B: Chrominance saturation control"},
+	/* 0xd7 - Reserved */
+
+	/* Task B: Horizontal phase scaling */
+	{R_D8_B_HORIZ_LUMA_SCALING_INC,2,
+	 "Task B: Horizontal luminance scaling increment"},
+	{R_DA_B_HORIZ_LUMA_PHASE_OFF,1,
+	 "Task B: Horizontal luminance phase offset"},
+	/* 0xdb - Reserved */
+	{R_DC_B_HORIZ_CHROMA_SCALING,2,
+	 "Task B: Horizontal chrominance scaling"},
+	{R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA,1,
+	 "Task B: Horizontal Phase Offset Chroma"},
+	/* 0xdf - Reserved */
+
+	/* Task B: Vertical scaling */
+	{R_E0_B_VERT_LUMA_SCALING_INC,2,
+	 "Task B: Vertical luminance scaling increment"},
+	{R_E2_B_VERT_CHROMA_SCALING_INC,2,
+	 "Task B: Vertical chrominance scaling increment"},
+	{R_E4_B_VERT_SCALING_MODE_CNTL,1,
+	 "Task B: Vertical scaling mode control"},
+	/* 0xe5-0xe7 - Reserved */
+	{R_E8_B_VERT_CHROMA_PHASE_OFF_00,1,
+	 "Task B: Vertical chrominance phase offset '00'"},
+	{R_E9_B_VERT_CHROMA_PHASE_OFF_01,1,
+	 "Task B: Vertical chrominance phase offset '01'"},
+	{R_EA_B_VERT_CHROMA_PHASE_OFF_10,1,
+	 "Task B: Vertical chrominance phase offset '10'"},
+	{R_EB_B_VERT_CHROMA_PHASE_OFF_11,1,
+	 "Task B: Vertical chrominance phase offset '11'"},
+	{R_EC_B_VERT_LUMA_PHASE_OFF_00,1,
+	 "Task B: Vertical luminance phase offset '00'"},
+	{R_ED_B_VERT_LUMA_PHASE_OFF_01,1,
+	 "Task B: Vertical luminance phase offset '01'"},
+	{R_EE_B_VERT_LUMA_PHASE_OFF_10,1,
+	 "Task B: Vertical luminance phase offset '10'"},
+	{R_EF_B_VERT_LUMA_PHASE_OFF_11,1,
+	 "Task B: Vertical luminance phase offset '11'"},
+
+	/* second PLL (PLL2) and Pulsegenerator Programming */
+	{ R_F0_LFCO_PER_LINE, 1,
+	  "LFCO's per line"},
+	{ R_F1_P_I_PARAM_SELECT,1,
+	  "P-/I- Param. Select., PLL Mode, PLL H-Src., LFCO's per line"},
+	{ R_F2_NOMINAL_PLL2_DTO,1,
+	 "Nominal PLL2 DTO"},
+	{R_F3_PLL_INCREMENT,1,
+	 "PLL2 Increment"},
+	{R_F4_PLL2_STATUS,1,
+	 "PLL2 Status"},
+	{R_F5_PULSGEN_LINE_LENGTH,1,
+	 "Pulsgen. line length"},
+	{R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG,1,
+	 "Pulse A Position, Pulsgen Resync., Pulsgen. H-Src., Pulsgen. line length"},
+	{R_F7_PULSE_A_POS_MSB,1,
+	 "Pulse A Position"},
+	{R_F8_PULSE_B_POS,2,
+	 "Pulse B Position"},
+	{R_FA_PULSE_C_POS,2,
+	 "Pulse C Position"},
+	/* 0xfc to 0xfe - Reserved */
+	{R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES,1,
+	 "S_PLL max. phase, error threshold, PLL2 no. of lines, threshold"},
+};
+#endif
diff --git a/drivers/media/i2c/saa7127.c b/drivers/media/i2c/saa7127.c
new file mode 100644
index 0000000..8ecb656
--- /dev/null
+++ b/drivers/media/i2c/saa7127.c
@@ -0,0 +1,852 @@
+/*
+ * saa7127 - Philips SAA7127/SAA7129 video encoder driver
+ *
+ * Copyright (C) 2003 Roy Bulter <rbulter@hetnet.nl>
+ *
+ * Based on SAA7126 video encoder driver by Gillem & Andreas Oberritter
+ *
+ * Copyright (C) 2000-2001 Gillem <htoa@gmx.net>
+ * Copyright (C) 2002 Andreas Oberritter <obi@saftware.de>
+ *
+ * Based on Stadis 4:2:2 MPEG-2 Decoder Driver by Nathan Laredo
+ *
+ * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org>
+ *
+ * This driver is designed for the Hauppauge 250/350 Linux driver
+ * from the ivtv Project
+ *
+ * Copyright (C) 2003 Kevin Thayer <nufan_wfk@yahoo.com>
+ *
+ * Dual output support:
+ * Copyright (C) 2004 Eric Varsanyi
+ *
+ * NTSC Tuning and 7.5 IRE Setup
+ * Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+ *
+ * VBI additions & cleanup:
+ * Copyright (C) 2004, 2005 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Note: the saa7126 is identical to the saa7127, and the saa7128 is
+ * identical to the saa7129, except that the saa7126 and saa7128 have
+ * macrovision anti-taping support. This driver will almost certainly
+ * work fine for those chips, except of course for the missing anti-taping
+ * support.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/saa7127.h>
+
+static int debug;
+static int test_image;
+
+MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver");
+MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
+MODULE_LICENSE("GPL");
+module_param(debug, int, 0644);
+module_param(test_image, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (0-2)");
+MODULE_PARM_DESC(test_image, "test_image (0-1)");
+
+
+/*
+ * SAA7127 registers
+ */
+
+#define SAA7127_REG_STATUS                           0x00
+#define SAA7127_REG_WIDESCREEN_CONFIG                0x26
+#define SAA7127_REG_WIDESCREEN_ENABLE                0x27
+#define SAA7127_REG_BURST_START                      0x28
+#define SAA7127_REG_BURST_END                        0x29
+#define SAA7127_REG_COPYGEN_0                        0x2a
+#define SAA7127_REG_COPYGEN_1                        0x2b
+#define SAA7127_REG_COPYGEN_2                        0x2c
+#define SAA7127_REG_OUTPUT_PORT_CONTROL              0x2d
+#define SAA7127_REG_GAIN_LUMINANCE_RGB               0x38
+#define SAA7127_REG_GAIN_COLORDIFF_RGB               0x39
+#define SAA7127_REG_INPUT_PORT_CONTROL_1             0x3a
+#define SAA7129_REG_FADE_KEY_COL2		     0x4f
+#define SAA7127_REG_CHROMA_PHASE                     0x5a
+#define SAA7127_REG_GAINU                            0x5b
+#define SAA7127_REG_GAINV                            0x5c
+#define SAA7127_REG_BLACK_LEVEL                      0x5d
+#define SAA7127_REG_BLANKING_LEVEL                   0x5e
+#define SAA7127_REG_VBI_BLANKING                     0x5f
+#define SAA7127_REG_DAC_CONTROL                      0x61
+#define SAA7127_REG_BURST_AMP                        0x62
+#define SAA7127_REG_SUBC3                            0x63
+#define SAA7127_REG_SUBC2                            0x64
+#define SAA7127_REG_SUBC1                            0x65
+#define SAA7127_REG_SUBC0                            0x66
+#define SAA7127_REG_LINE_21_ODD_0                    0x67
+#define SAA7127_REG_LINE_21_ODD_1                    0x68
+#define SAA7127_REG_LINE_21_EVEN_0                   0x69
+#define SAA7127_REG_LINE_21_EVEN_1                   0x6a
+#define SAA7127_REG_RCV_PORT_CONTROL                 0x6b
+#define SAA7127_REG_VTRIG                            0x6c
+#define SAA7127_REG_HTRIG_HI                         0x6d
+#define SAA7127_REG_MULTI                            0x6e
+#define SAA7127_REG_CLOSED_CAPTION                   0x6f
+#define SAA7127_REG_RCV2_OUTPUT_START                0x70
+#define SAA7127_REG_RCV2_OUTPUT_END                  0x71
+#define SAA7127_REG_RCV2_OUTPUT_MSBS                 0x72
+#define SAA7127_REG_TTX_REQUEST_H_START              0x73
+#define SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH       0x74
+#define SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT        0x75
+#define SAA7127_REG_TTX_ODD_REQ_VERT_START           0x76
+#define SAA7127_REG_TTX_ODD_REQ_VERT_END             0x77
+#define SAA7127_REG_TTX_EVEN_REQ_VERT_START          0x78
+#define SAA7127_REG_TTX_EVEN_REQ_VERT_END            0x79
+#define SAA7127_REG_FIRST_ACTIVE                     0x7a
+#define SAA7127_REG_LAST_ACTIVE                      0x7b
+#define SAA7127_REG_MSB_VERTICAL                     0x7c
+#define SAA7127_REG_DISABLE_TTX_LINE_LO_0            0x7e
+#define SAA7127_REG_DISABLE_TTX_LINE_LO_1            0x7f
+
+/*
+ **********************************************************************
+ *
+ *  Arrays with configuration parameters for the SAA7127
+ *
+ **********************************************************************
+ */
+
+struct i2c_reg_value {
+	unsigned char reg;
+	unsigned char value;
+};
+
+static const struct i2c_reg_value saa7129_init_config_extra[] = {
+	{ SAA7127_REG_OUTPUT_PORT_CONTROL, 		0x38 },
+	{ SAA7127_REG_VTRIG, 				0xfa },
+	{ 0, 0 }
+};
+
+static const struct i2c_reg_value saa7127_init_config_common[] = {
+	{ SAA7127_REG_WIDESCREEN_CONFIG, 		0x0d },
+	{ SAA7127_REG_WIDESCREEN_ENABLE, 		0x00 },
+	{ SAA7127_REG_COPYGEN_0, 			0x77 },
+	{ SAA7127_REG_COPYGEN_1, 			0x41 },
+	{ SAA7127_REG_COPYGEN_2, 			0x00 },	/* Macrovision enable/disable */
+	{ SAA7127_REG_OUTPUT_PORT_CONTROL, 		0xbf },
+	{ SAA7127_REG_GAIN_LUMINANCE_RGB, 		0x00 },
+	{ SAA7127_REG_GAIN_COLORDIFF_RGB, 		0x00 },
+	{ SAA7127_REG_INPUT_PORT_CONTROL_1, 		0x80 },	/* for color bars */
+	{ SAA7127_REG_LINE_21_ODD_0, 			0x77 },
+	{ SAA7127_REG_LINE_21_ODD_1, 			0x41 },
+	{ SAA7127_REG_LINE_21_EVEN_0, 			0x88 },
+	{ SAA7127_REG_LINE_21_EVEN_1, 			0x41 },
+	{ SAA7127_REG_RCV_PORT_CONTROL, 		0x12 },
+	{ SAA7127_REG_VTRIG, 				0xf9 },
+	{ SAA7127_REG_HTRIG_HI, 			0x00 },
+	{ SAA7127_REG_RCV2_OUTPUT_START, 		0x41 },
+	{ SAA7127_REG_RCV2_OUTPUT_END, 			0xc3 },
+	{ SAA7127_REG_RCV2_OUTPUT_MSBS, 		0x00 },
+	{ SAA7127_REG_TTX_REQUEST_H_START, 		0x3e },
+	{ SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH, 	0xb8 },
+	{ SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT,  	0x03 },
+	{ SAA7127_REG_TTX_ODD_REQ_VERT_START, 		0x15 },
+	{ SAA7127_REG_TTX_ODD_REQ_VERT_END, 		0x16 },
+	{ SAA7127_REG_TTX_EVEN_REQ_VERT_START, 		0x15 },
+	{ SAA7127_REG_TTX_EVEN_REQ_VERT_END, 		0x16 },
+	{ SAA7127_REG_FIRST_ACTIVE, 			0x1a },
+	{ SAA7127_REG_LAST_ACTIVE, 			0x01 },
+	{ SAA7127_REG_MSB_VERTICAL, 			0xc0 },
+	{ SAA7127_REG_DISABLE_TTX_LINE_LO_0, 		0x00 },
+	{ SAA7127_REG_DISABLE_TTX_LINE_LO_1, 		0x00 },
+	{ 0, 0 }
+};
+
+#define SAA7127_60HZ_DAC_CONTROL 0x15
+static const struct i2c_reg_value saa7127_init_config_60hz[] = {
+	{ SAA7127_REG_BURST_START, 			0x19 },
+	/* BURST_END is also used as a chip ID in saa7127_probe */
+	{ SAA7127_REG_BURST_END, 			0x1d },
+	{ SAA7127_REG_CHROMA_PHASE, 			0xa3 },
+	{ SAA7127_REG_GAINU, 				0x98 },
+	{ SAA7127_REG_GAINV, 				0xd3 },
+	{ SAA7127_REG_BLACK_LEVEL, 			0x39 },
+	{ SAA7127_REG_BLANKING_LEVEL, 			0x2e },
+	{ SAA7127_REG_VBI_BLANKING, 			0x2e },
+	{ SAA7127_REG_DAC_CONTROL, 			0x15 },
+	{ SAA7127_REG_BURST_AMP, 			0x4d },
+	{ SAA7127_REG_SUBC3, 				0x1f },
+	{ SAA7127_REG_SUBC2, 				0x7c },
+	{ SAA7127_REG_SUBC1, 				0xf0 },
+	{ SAA7127_REG_SUBC0, 				0x21 },
+	{ SAA7127_REG_MULTI, 				0x90 },
+	{ SAA7127_REG_CLOSED_CAPTION, 			0x11 },
+	{ 0, 0 }
+};
+
+#define SAA7127_50HZ_PAL_DAC_CONTROL 0x02
+static struct i2c_reg_value saa7127_init_config_50hz_pal[] = {
+	{ SAA7127_REG_BURST_START, 			0x21 },
+	/* BURST_END is also used as a chip ID in saa7127_probe */
+	{ SAA7127_REG_BURST_END, 			0x1d },
+	{ SAA7127_REG_CHROMA_PHASE, 			0x3f },
+	{ SAA7127_REG_GAINU, 				0x7d },
+	{ SAA7127_REG_GAINV, 				0xaf },
+	{ SAA7127_REG_BLACK_LEVEL, 			0x33 },
+	{ SAA7127_REG_BLANKING_LEVEL, 			0x35 },
+	{ SAA7127_REG_VBI_BLANKING, 			0x35 },
+	{ SAA7127_REG_DAC_CONTROL, 			0x02 },
+	{ SAA7127_REG_BURST_AMP, 			0x2f },
+	{ SAA7127_REG_SUBC3, 				0xcb },
+	{ SAA7127_REG_SUBC2, 				0x8a },
+	{ SAA7127_REG_SUBC1, 				0x09 },
+	{ SAA7127_REG_SUBC0, 				0x2a },
+	{ SAA7127_REG_MULTI, 				0xa0 },
+	{ SAA7127_REG_CLOSED_CAPTION, 			0x00 },
+	{ 0, 0 }
+};
+
+#define SAA7127_50HZ_SECAM_DAC_CONTROL 0x08
+static struct i2c_reg_value saa7127_init_config_50hz_secam[] = {
+	{ SAA7127_REG_BURST_START, 			0x21 },
+	/* BURST_END is also used as a chip ID in saa7127_probe */
+	{ SAA7127_REG_BURST_END, 			0x1d },
+	{ SAA7127_REG_CHROMA_PHASE, 			0x3f },
+	{ SAA7127_REG_GAINU, 				0x6a },
+	{ SAA7127_REG_GAINV, 				0x81 },
+	{ SAA7127_REG_BLACK_LEVEL, 			0x33 },
+	{ SAA7127_REG_BLANKING_LEVEL, 			0x35 },
+	{ SAA7127_REG_VBI_BLANKING, 			0x35 },
+	{ SAA7127_REG_DAC_CONTROL, 			0x08 },
+	{ SAA7127_REG_BURST_AMP, 			0x2f },
+	{ SAA7127_REG_SUBC3, 				0xb2 },
+	{ SAA7127_REG_SUBC2, 				0x3b },
+	{ SAA7127_REG_SUBC1, 				0xa3 },
+	{ SAA7127_REG_SUBC0, 				0x28 },
+	{ SAA7127_REG_MULTI, 				0x90 },
+	{ SAA7127_REG_CLOSED_CAPTION, 			0x00 },
+	{ 0, 0 }
+};
+
+/*
+ **********************************************************************
+ *
+ *  Encoder Struct, holds the configuration state of the encoder
+ *
+ **********************************************************************
+ */
+
+struct saa7127_state {
+	struct v4l2_subdev sd;
+	v4l2_std_id std;
+	u32 ident;
+	enum saa7127_input_type input_type;
+	enum saa7127_output_type output_type;
+	int video_enable;
+	int wss_enable;
+	u16 wss_mode;
+	int cc_enable;
+	u16 cc_data;
+	int xds_enable;
+	u16 xds_data;
+	int vps_enable;
+	u8 vps_data[5];
+	u8 reg_2d;
+	u8 reg_3a;
+	u8 reg_3a_cb;   /* colorbar bit */
+	u8 reg_61;
+};
+
+static inline struct saa7127_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct saa7127_state, sd);
+}
+
+static const char * const output_strs[] =
+{
+	"S-Video + Composite",
+	"Composite",
+	"S-Video",
+	"RGB",
+	"YUV C",
+	"YUV V"
+};
+
+static const char * const wss_strs[] = {
+	"invalid",
+	"letterbox 14:9 center",
+	"letterbox 14:9 top",
+	"invalid",
+	"letterbox 16:9 top",
+	"invalid",
+	"invalid",
+	"16:9 full format anamorphic",
+	"4:3 full format",
+	"invalid",
+	"invalid",
+	"letterbox 16:9 center",
+	"invalid",
+	"letterbox >16:9 center",
+	"14:9 full format center",
+	"invalid",
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_read(struct v4l2_subdev *sd, u8 reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_write(struct v4l2_subdev *sd, u8 reg, u8 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		if (i2c_smbus_write_byte_data(client, reg, val) == 0)
+			return 0;
+	}
+	v4l2_err(sd, "I2C Write Problem\n");
+	return -1;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_write_inittab(struct v4l2_subdev *sd,
+				 const struct i2c_reg_value *regs)
+{
+	while (regs->reg != 0) {
+		saa7127_write(sd, regs->reg, regs->value);
+		regs++;
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_vps(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
+{
+	struct saa7127_state *state = to_state(sd);
+	int enable = (data->line != 0);
+
+	if (enable && (data->field != 0 || data->line != 16))
+		return -EINVAL;
+	if (state->vps_enable != enable) {
+		v4l2_dbg(1, debug, sd, "Turn VPS Signal %s\n", enable ? "on" : "off");
+		saa7127_write(sd, 0x54, enable << 7);
+		state->vps_enable = enable;
+	}
+	if (!enable)
+		return 0;
+
+	state->vps_data[0] = data->data[2];
+	state->vps_data[1] = data->data[8];
+	state->vps_data[2] = data->data[9];
+	state->vps_data[3] = data->data[10];
+	state->vps_data[4] = data->data[11];
+	v4l2_dbg(1, debug, sd, "Set VPS data %*ph\n", 5, state->vps_data);
+	saa7127_write(sd, 0x55, state->vps_data[0]);
+	saa7127_write(sd, 0x56, state->vps_data[1]);
+	saa7127_write(sd, 0x57, state->vps_data[2]);
+	saa7127_write(sd, 0x58, state->vps_data[3]);
+	saa7127_write(sd, 0x59, state->vps_data[4]);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_cc(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
+{
+	struct saa7127_state *state = to_state(sd);
+	u16 cc = data->data[1] << 8 | data->data[0];
+	int enable = (data->line != 0);
+
+	if (enable && (data->field != 0 || data->line != 21))
+		return -EINVAL;
+	if (state->cc_enable != enable) {
+		v4l2_dbg(1, debug, sd,
+			"Turn CC %s\n", enable ? "on" : "off");
+		saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION,
+			(state->xds_enable << 7) | (enable << 6) | 0x11);
+		state->cc_enable = enable;
+	}
+	if (!enable)
+		return 0;
+
+	v4l2_dbg(2, debug, sd, "CC data: %04x\n", cc);
+	saa7127_write(sd, SAA7127_REG_LINE_21_ODD_0, cc & 0xff);
+	saa7127_write(sd, SAA7127_REG_LINE_21_ODD_1, cc >> 8);
+	state->cc_data = cc;
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_xds(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
+{
+	struct saa7127_state *state = to_state(sd);
+	u16 xds = data->data[1] << 8 | data->data[0];
+	int enable = (data->line != 0);
+
+	if (enable && (data->field != 1 || data->line != 21))
+		return -EINVAL;
+	if (state->xds_enable != enable) {
+		v4l2_dbg(1, debug, sd, "Turn XDS %s\n", enable ? "on" : "off");
+		saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION,
+				(enable << 7) | (state->cc_enable << 6) | 0x11);
+		state->xds_enable = enable;
+	}
+	if (!enable)
+		return 0;
+
+	v4l2_dbg(2, debug, sd, "XDS data: %04x\n", xds);
+	saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff);
+	saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_1, xds >> 8);
+	state->xds_data = xds;
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_wss(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
+{
+	struct saa7127_state *state = to_state(sd);
+	int enable = (data->line != 0);
+
+	if (enable && (data->field != 0 || data->line != 23))
+		return -EINVAL;
+	if (state->wss_enable != enable) {
+		v4l2_dbg(1, debug, sd, "Turn WSS %s\n", enable ? "on" : "off");
+		saa7127_write(sd, 0x27, enable << 7);
+		state->wss_enable = enable;
+	}
+	if (!enable)
+		return 0;
+
+	saa7127_write(sd, 0x26, data->data[0]);
+	saa7127_write(sd, 0x27, 0x80 | (data->data[1] & 0x3f));
+	v4l2_dbg(1, debug, sd,
+		"WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
+	state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_video_enable(struct v4l2_subdev *sd, int enable)
+{
+	struct saa7127_state *state = to_state(sd);
+
+	if (enable) {
+		v4l2_dbg(1, debug, sd, "Enable Video Output\n");
+		saa7127_write(sd, 0x2d, state->reg_2d);
+		saa7127_write(sd, 0x61, state->reg_61);
+	} else {
+		v4l2_dbg(1, debug, sd, "Disable Video Output\n");
+		saa7127_write(sd, 0x2d, (state->reg_2d & 0xf0));
+		saa7127_write(sd, 0x61, (state->reg_61 | 0xc0));
+	}
+	state->video_enable = enable;
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct saa7127_state *state = to_state(sd);
+	const struct i2c_reg_value *inittab;
+
+	if (std & V4L2_STD_525_60) {
+		v4l2_dbg(1, debug, sd, "Selecting 60 Hz video Standard\n");
+		inittab = saa7127_init_config_60hz;
+		state->reg_61 = SAA7127_60HZ_DAC_CONTROL;
+
+	} else if (state->ident == V4L2_IDENT_SAA7129 &&
+		   (std & V4L2_STD_SECAM) &&
+		   !(std & (V4L2_STD_625_50 & ~V4L2_STD_SECAM))) {
+
+		/* If and only if SECAM, with a SAA712[89] */
+		v4l2_dbg(1, debug, sd,
+			 "Selecting 50 Hz SECAM video Standard\n");
+		inittab = saa7127_init_config_50hz_secam;
+		state->reg_61 = SAA7127_50HZ_SECAM_DAC_CONTROL;
+
+	} else {
+		v4l2_dbg(1, debug, sd, "Selecting 50 Hz PAL video Standard\n");
+		inittab = saa7127_init_config_50hz_pal;
+		state->reg_61 = SAA7127_50HZ_PAL_DAC_CONTROL;
+	}
+
+	/* Write Table */
+	saa7127_write_inittab(sd, inittab);
+	state->std = std;
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_output_type(struct v4l2_subdev *sd, int output)
+{
+	struct saa7127_state *state = to_state(sd);
+
+	switch (output) {
+	case SAA7127_OUTPUT_TYPE_RGB:
+		state->reg_2d = 0x0f;	/* RGB + CVBS (for sync) */
+		state->reg_3a = 0x13;	/* by default switch YUV to RGB-matrix on */
+		break;
+
+	case SAA7127_OUTPUT_TYPE_COMPOSITE:
+		if (state->ident == V4L2_IDENT_SAA7129)
+			state->reg_2d = 0x20;	/* CVBS only */
+		else
+			state->reg_2d = 0x08;	/* 00001000 CVBS only, RGB DAC's off (high impedance mode) */
+		state->reg_3a = 0x13;	/* by default switch YUV to RGB-matrix on */
+		break;
+
+	case SAA7127_OUTPUT_TYPE_SVIDEO:
+		if (state->ident == V4L2_IDENT_SAA7129)
+			state->reg_2d = 0x18;	/* Y + C */
+		else
+			state->reg_2d = 0xff;   /*11111111  croma -> R, luma -> CVBS + G + B */
+		state->reg_3a = 0x13;	/* by default switch YUV to RGB-matrix on */
+		break;
+
+	case SAA7127_OUTPUT_TYPE_YUV_V:
+		state->reg_2d = 0x4f;	/* reg 2D = 01001111, all DAC's on, RGB + VBS */
+		state->reg_3a = 0x0b;	/* reg 3A = 00001011, bypass RGB-matrix */
+		break;
+
+	case SAA7127_OUTPUT_TYPE_YUV_C:
+		state->reg_2d = 0x0f;	/* reg 2D = 00001111, all DAC's on, RGB + CVBS */
+		state->reg_3a = 0x0b;	/* reg 3A = 00001011, bypass RGB-matrix */
+		break;
+
+	case SAA7127_OUTPUT_TYPE_BOTH:
+		if (state->ident == V4L2_IDENT_SAA7129)
+			state->reg_2d = 0x38;
+		else
+			state->reg_2d = 0xbf;
+		state->reg_3a = 0x13;	/* by default switch YUV to RGB-matrix on */
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	v4l2_dbg(1, debug, sd,
+		"Selecting %s output type\n", output_strs[output]);
+
+	/* Configure Encoder */
+	saa7127_write(sd, 0x2d, state->reg_2d);
+	saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb);
+	state->output_type = output;
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_input_type(struct v4l2_subdev *sd, int input)
+{
+	struct saa7127_state *state = to_state(sd);
+
+	switch (input) {
+	case SAA7127_INPUT_TYPE_NORMAL:	/* avia */
+		v4l2_dbg(1, debug, sd, "Selecting Normal Encoder Input\n");
+		state->reg_3a_cb = 0;
+		break;
+
+	case SAA7127_INPUT_TYPE_TEST_IMAGE:	/* color bar */
+		v4l2_dbg(1, debug, sd, "Selecting Color Bar generator\n");
+		state->reg_3a_cb = 0x80;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb);
+	state->input_type = input;
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct saa7127_state *state = to_state(sd);
+
+	if (state->std == std)
+		return 0;
+	return saa7127_set_std(sd, std);
+}
+
+static int saa7127_s_routing(struct v4l2_subdev *sd,
+			     u32 input, u32 output, u32 config)
+{
+	struct saa7127_state *state = to_state(sd);
+	int rc = 0;
+
+	if (state->input_type != input)
+		rc = saa7127_set_input_type(sd, input);
+	if (rc == 0 && state->output_type != output)
+		rc = saa7127_set_output_type(sd, output);
+	return rc;
+}
+
+static int saa7127_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct saa7127_state *state = to_state(sd);
+
+	if (state->video_enable == enable)
+		return 0;
+	return saa7127_set_video_enable(sd, enable);
+}
+
+static int saa7127_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt)
+{
+	struct saa7127_state *state = to_state(sd);
+
+	memset(fmt, 0, sizeof(*fmt));
+	if (state->vps_enable)
+		fmt->service_lines[0][16] = V4L2_SLICED_VPS;
+	if (state->wss_enable)
+		fmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
+	if (state->cc_enable) {
+		fmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+		fmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+	}
+	fmt->service_set =
+		(state->vps_enable ? V4L2_SLICED_VPS : 0) |
+		(state->wss_enable ? V4L2_SLICED_WSS_625 : 0) |
+		(state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0);
+	return 0;
+}
+
+static int saa7127_s_vbi_data(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
+{
+	switch (data->id) {
+	case V4L2_SLICED_WSS_625:
+		return saa7127_set_wss(sd, data);
+	case V4L2_SLICED_VPS:
+		return saa7127_set_vps(sd, data);
+	case V4L2_SLICED_CAPTION_525:
+		if (data->field == 0)
+			return saa7127_set_cc(sd, data);
+		return saa7127_set_xds(sd, data);
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int saa7127_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	reg->val = saa7127_read(sd, reg->reg & 0xff);
+	reg->size = 1;
+	return 0;
+}
+
+static int saa7127_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	saa7127_write(sd, reg->reg & 0xff, reg->val & 0xff);
+	return 0;
+}
+#endif
+
+static int saa7127_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct saa7127_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, state->ident, 0);
+}
+
+static int saa7127_log_status(struct v4l2_subdev *sd)
+{
+	struct saa7127_state *state = to_state(sd);
+
+	v4l2_info(sd, "Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
+	v4l2_info(sd, "Input:    %s\n", state->input_type ?  "color bars" : "normal");
+	v4l2_info(sd, "Output:   %s\n", state->video_enable ?
+			output_strs[state->output_type] : "disabled");
+	v4l2_info(sd, "WSS:      %s\n", state->wss_enable ?
+			wss_strs[state->wss_mode] : "disabled");
+	v4l2_info(sd, "VPS:      %s\n", state->vps_enable ? "enabled" : "disabled");
+	v4l2_info(sd, "CC:       %s\n", state->cc_enable ? "enabled" : "disabled");
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops saa7127_core_ops = {
+	.log_status = saa7127_log_status,
+	.g_chip_ident = saa7127_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = saa7127_g_register,
+	.s_register = saa7127_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops saa7127_video_ops = {
+	.s_std_output = saa7127_s_std_output,
+	.s_routing = saa7127_s_routing,
+	.s_stream = saa7127_s_stream,
+};
+
+static const struct v4l2_subdev_vbi_ops saa7127_vbi_ops = {
+	.s_vbi_data = saa7127_s_vbi_data,
+	.g_sliced_fmt = saa7127_g_sliced_fmt,
+};
+
+static const struct v4l2_subdev_ops saa7127_ops = {
+	.core = &saa7127_core_ops,
+	.video = &saa7127_video_ops,
+	.vbi = &saa7127_vbi_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct saa7127_state *state;
+	struct v4l2_subdev *sd;
+	struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 };  /* set to disabled */
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n",
+			client->addr << 1);
+
+	state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &saa7127_ops);
+
+	/* First test register 0: Bits 5-7 are a version ID (should be 0),
+	   and bit 2 should also be 0.
+	   This is rather general, so the second test is more specific and
+	   looks at the 'ending point of burst in clock cycles' which is
+	   0x1d after a reset and not expected to ever change. */
+	if ((saa7127_read(sd, 0) & 0xe4) != 0 ||
+			(saa7127_read(sd, 0x29) & 0x3f) != 0x1d) {
+		v4l2_dbg(1, debug, sd, "saa7127 not found\n");
+		kfree(state);
+		return -ENODEV;
+	}
+
+	if (id->driver_data) {	/* Chip type is already known */
+		state->ident = id->driver_data;
+	} else {		/* Needs detection */
+		int read_result;
+
+		/* Detect if it's an saa7129 */
+		read_result = saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2);
+		saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2, 0xaa);
+		if (saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
+			saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2,
+					read_result);
+			state->ident = V4L2_IDENT_SAA7129;
+			strlcpy(client->name, "saa7129", I2C_NAME_SIZE);
+		} else {
+			state->ident = V4L2_IDENT_SAA7127;
+			strlcpy(client->name, "saa7127", I2C_NAME_SIZE);
+		}
+	}
+
+	v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
+			client->addr << 1, client->adapter->name);
+
+	v4l2_dbg(1, debug, sd, "Configuring encoder\n");
+	saa7127_write_inittab(sd, saa7127_init_config_common);
+	saa7127_set_std(sd, V4L2_STD_NTSC);
+	saa7127_set_output_type(sd, SAA7127_OUTPUT_TYPE_BOTH);
+	saa7127_set_vps(sd, &vbi);
+	saa7127_set_wss(sd, &vbi);
+	saa7127_set_cc(sd, &vbi);
+	saa7127_set_xds(sd, &vbi);
+	if (test_image == 1)
+		/* The Encoder has an internal Colorbar generator */
+		/* This can be used for debugging */
+		saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_TEST_IMAGE);
+	else
+		saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_NORMAL);
+	saa7127_set_video_enable(sd, 1);
+
+	if (state->ident == V4L2_IDENT_SAA7129)
+		saa7127_write_inittab(sd, saa7129_init_config_extra);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	/* Turn off TV output */
+	saa7127_set_video_enable(sd, 0);
+	kfree(to_state(sd));
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_device_id saa7127_id[] = {
+	{ "saa7127_auto", 0 },	/* auto-detection */
+	{ "saa7126", V4L2_IDENT_SAA7127 },
+	{ "saa7127", V4L2_IDENT_SAA7127 },
+	{ "saa7128", V4L2_IDENT_SAA7129 },
+	{ "saa7129", V4L2_IDENT_SAA7129 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, saa7127_id);
+
+static struct i2c_driver saa7127_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "saa7127",
+	},
+	.probe		= saa7127_probe,
+	.remove		= saa7127_remove,
+	.id_table	= saa7127_id,
+};
+
+module_i2c_driver(saa7127_driver);
diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c
new file mode 100644
index 0000000..1e84466
--- /dev/null
+++ b/drivers/media/i2c/saa717x.c
@@ -0,0 +1,1378 @@
+/*
+ * saa717x - Philips SAA717xHL video decoder driver
+ *
+ * Based on the saa7115 driver
+ *
+ * Changes by Ohta Kyuma <alpha292@bremen.or.jp>
+ *    - Apply to SAA717x,NEC uPD64031,uPD64083. (1/31/2004)
+ *
+ * Changes by T.Adachi (tadachi@tadachi-net.com)
+ *    - support audio, video scaler etc, and checked the initialize sequence.
+ *
+ * Cleaned up by Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Note: this is a reversed engineered driver based on captures from
+ * the I2C bus under Windows. This chip is very similar to the saa7134,
+ * though. Unfortunately, this driver is currently only working for NTSC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver");
+MODULE_AUTHOR("K. Ohta, T. Adachi, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+struct saa717x_state {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	v4l2_std_id std;
+	int input;
+	int enable;
+	int radio;
+	int playback;
+	int audio;
+	int tuner_audio_mode;
+	int audio_main_mute;
+	int audio_main_vol_r;
+	int audio_main_vol_l;
+	u16 audio_main_bass;
+	u16 audio_main_treble;
+	u16 audio_main_volume;
+	u16 audio_main_balance;
+	int audio_input;
+};
+
+static inline struct saa717x_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct saa717x_state, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct saa717x_state, hdl)->sd;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* for audio mode */
+#define TUNER_AUDIO_MONO   	0  /* LL */
+#define TUNER_AUDIO_STEREO 	1  /* LR */
+#define TUNER_AUDIO_LANG1  	2  /* LL */
+#define TUNER_AUDIO_LANG2  	3  /* RR */
+
+#define SAA717X_NTSC_WIDTH   	(704)
+#define SAA717X_NTSC_HEIGHT  	(480)
+
+/* ----------------------------------------------------------------------- */
+
+static int saa717x_write(struct v4l2_subdev *sd, u32 reg, u32 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct i2c_adapter *adap = client->adapter;
+	int fw_addr = reg == 0x454 || (reg >= 0x464 && reg <= 0x478) || reg == 0x480 || reg == 0x488;
+	unsigned char mm1[6];
+	struct i2c_msg msg;
+
+	msg.flags = 0;
+	msg.addr = client->addr;
+	mm1[0] = (reg >> 8) & 0xff;
+	mm1[1] = reg & 0xff;
+
+	if (fw_addr) {
+		mm1[4] = (value >> 16) & 0xff;
+		mm1[3] = (value >> 8) & 0xff;
+		mm1[2] = value & 0xff;
+	} else {
+		mm1[2] = value & 0xff;
+	}
+	msg.len = fw_addr ? 5 : 3; /* Long Registers have *only* three bytes! */
+	msg.buf = mm1;
+	v4l2_dbg(2, debug, sd, "wrote:  reg 0x%03x=%08x\n", reg, value);
+	return i2c_transfer(adap, &msg, 1) == 1;
+}
+
+static void saa717x_write_regs(struct v4l2_subdev *sd, u32 *data)
+{
+	while (data[0] || data[1]) {
+		saa717x_write(sd, data[0], data[1]);
+		data += 2;
+	}
+}
+
+static u32 saa717x_read(struct v4l2_subdev *sd, u32 reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct i2c_adapter *adap = client->adapter;
+	int fw_addr = (reg >= 0x404 && reg <= 0x4b8) || reg == 0x528;
+	unsigned char mm1[2];
+	unsigned char mm2[4] = { 0, 0, 0, 0 };
+	struct i2c_msg msgs[2];
+	u32 value;
+
+	msgs[0].flags = 0;
+	msgs[1].flags = I2C_M_RD;
+	msgs[0].addr = msgs[1].addr = client->addr;
+	mm1[0] = (reg >> 8) & 0xff;
+	mm1[1] = reg & 0xff;
+	msgs[0].len = 2;
+	msgs[0].buf = mm1;
+	msgs[1].len = fw_addr ? 3 : 1; /* Multibyte Registers contains *only* 3 bytes */
+	msgs[1].buf = mm2;
+	i2c_transfer(adap, msgs, 2);
+
+	if (fw_addr)
+		value = (mm2[2] & 0xff)  | ((mm2[1] & 0xff) >> 8) | ((mm2[0] & 0xff) >> 16);
+	else
+		value = mm2[0] & 0xff;
+
+	v4l2_dbg(2, debug, sd, "read:  reg 0x%03x=0x%08x\n", reg, value);
+	return value;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static u32 reg_init_initialize[] =
+{
+	/* from linux driver */
+	0x101, 0x008, /* Increment delay */
+
+	0x103, 0x000, /* Analog input control 2 */
+	0x104, 0x090, /* Analog input control 3 */
+	0x105, 0x090, /* Analog input control 4 */
+	0x106, 0x0eb, /* Horizontal sync start */
+	0x107, 0x0e0, /* Horizontal sync stop */
+	0x109, 0x055, /* Luminance control */
+
+	0x10f, 0x02a, /* Chroma gain control */
+	0x110, 0x000, /* Chroma control 2 */
+
+	0x114, 0x045, /* analog/ADC */
+
+	0x118, 0x040, /* RAW data gain */
+	0x119, 0x080, /* RAW data offset */
+
+	0x044, 0x000, /* VBI horizontal input window start (L) TASK A */
+	0x045, 0x000, /* VBI horizontal input window start (H) TASK A */
+	0x046, 0x0cf, /* VBI horizontal input window stop (L) TASK A */
+	0x047, 0x002, /* VBI horizontal input window stop (H) TASK A */
+
+	0x049, 0x000, /* VBI vertical input window start (H) TASK A */
+
+	0x04c, 0x0d0, /* VBI horizontal output length (L) TASK A */
+	0x04d, 0x002, /* VBI horizontal output length (H) TASK A */
+
+	0x064, 0x080, /* Lumina brightness TASK A */
+	0x065, 0x040, /* Luminance contrast TASK A */
+	0x066, 0x040, /* Chroma saturation TASK A */
+	/* 067H: Reserved */
+	0x068, 0x000, /* VBI horizontal scaling increment (L) TASK A */
+	0x069, 0x004, /* VBI horizontal scaling increment (H) TASK A */
+	0x06a, 0x000, /* VBI phase offset TASK A */
+
+	0x06e, 0x000, /* Horizontal phase offset Luma TASK A */
+	0x06f, 0x000, /* Horizontal phase offset Chroma TASK A */
+
+	0x072, 0x000, /* Vertical filter mode TASK A */
+
+	0x084, 0x000, /* VBI horizontal input window start (L) TAKS B */
+	0x085, 0x000, /* VBI horizontal input window start (H) TAKS B */
+	0x086, 0x0cf, /* VBI horizontal input window stop (L) TAKS B */
+	0x087, 0x002, /* VBI horizontal input window stop (H) TAKS B */
+
+	0x089, 0x000, /* VBI vertical input window start (H) TAKS B */
+
+	0x08c, 0x0d0, /* VBI horizontal output length (L) TASK B */
+	0x08d, 0x002, /* VBI horizontal output length (H) TASK B */
+
+	0x0a4, 0x080, /* Lumina brightness TASK B */
+	0x0a5, 0x040, /* Luminance contrast TASK B */
+	0x0a6, 0x040, /* Chroma saturation TASK B */
+	/* 0A7H reserved */
+	0x0a8, 0x000, /* VBI horizontal scaling increment (L) TASK B */
+	0x0a9, 0x004, /* VBI horizontal scaling increment (H) TASK B */
+	0x0aa, 0x000, /* VBI phase offset TASK B */
+
+	0x0ae, 0x000, /* Horizontal phase offset Luma TASK B */
+	0x0af, 0x000, /*Horizontal phase offset Chroma TASK B */
+
+	0x0b2, 0x000, /* Vertical filter mode TASK B */
+
+	0x00c, 0x000, /* Start point GREEN path */
+	0x00d, 0x000, /* Start point BLUE path */
+	0x00e, 0x000, /* Start point RED path */
+
+	0x010, 0x010, /* GREEN path gamma curve --- */
+	0x011, 0x020,
+	0x012, 0x030,
+	0x013, 0x040,
+	0x014, 0x050,
+	0x015, 0x060,
+	0x016, 0x070,
+	0x017, 0x080,
+	0x018, 0x090,
+	0x019, 0x0a0,
+	0x01a, 0x0b0,
+	0x01b, 0x0c0,
+	0x01c, 0x0d0,
+	0x01d, 0x0e0,
+	0x01e, 0x0f0,
+	0x01f, 0x0ff, /* --- GREEN path gamma curve */
+
+	0x020, 0x010, /* BLUE path gamma curve --- */
+	0x021, 0x020,
+	0x022, 0x030,
+	0x023, 0x040,
+	0x024, 0x050,
+	0x025, 0x060,
+	0x026, 0x070,
+	0x027, 0x080,
+	0x028, 0x090,
+	0x029, 0x0a0,
+	0x02a, 0x0b0,
+	0x02b, 0x0c0,
+	0x02c, 0x0d0,
+	0x02d, 0x0e0,
+	0x02e, 0x0f0,
+	0x02f, 0x0ff, /* --- BLUE path gamma curve */
+
+	0x030, 0x010, /* RED path gamma curve --- */
+	0x031, 0x020,
+	0x032, 0x030,
+	0x033, 0x040,
+	0x034, 0x050,
+	0x035, 0x060,
+	0x036, 0x070,
+	0x037, 0x080,
+	0x038, 0x090,
+	0x039, 0x0a0,
+	0x03a, 0x0b0,
+	0x03b, 0x0c0,
+	0x03c, 0x0d0,
+	0x03d, 0x0e0,
+	0x03e, 0x0f0,
+	0x03f, 0x0ff, /* --- RED path gamma curve */
+
+	0x109, 0x085, /* Luminance control  */
+
+	/**** from app start ****/
+	0x584, 0x000, /* AGC gain control */
+	0x585, 0x000, /* Program count */
+	0x586, 0x003, /* Status reset */
+	0x588, 0x0ff, /* Number of audio samples (L) */
+	0x589, 0x00f, /* Number of audio samples (M) */
+	0x58a, 0x000, /* Number of audio samples (H) */
+	0x58b, 0x000, /* Audio select */
+	0x58c, 0x010, /* Audio channel assign1 */
+	0x58d, 0x032, /* Audio channel assign2 */
+	0x58e, 0x054, /* Audio channel assign3 */
+	0x58f, 0x023, /* Audio format */
+	0x590, 0x000, /* SIF control */
+
+	0x595, 0x000, /* ?? */
+	0x596, 0x000, /* ?? */
+	0x597, 0x000, /* ?? */
+
+	0x464, 0x00, /* Digital input crossbar1 */
+
+	0x46c, 0xbbbb10, /* Digital output selection1-3 */
+	0x470, 0x101010, /* Digital output selection4-6 */
+
+	0x478, 0x00, /* Sound feature control */
+
+	0x474, 0x18, /* Softmute control */
+
+	0x454, 0x0425b9, /* Sound Easy programming(reset) */
+	0x454, 0x042539, /* Sound Easy programming(reset) */
+
+
+	/**** common setting( of DVD play, including scaler commands) ****/
+	0x042, 0x003, /* Data path configuration for VBI (TASK A) */
+
+	0x082, 0x003, /* Data path configuration for VBI (TASK B) */
+
+	0x108, 0x0f8, /* Sync control */
+	0x2a9, 0x0fd, /* ??? */
+	0x102, 0x089, /* select video input "mode 9" */
+	0x111, 0x000, /* Mode/delay control */
+
+	0x10e, 0x00a, /* Chroma control 1 */
+
+	0x594, 0x002, /* SIF, analog I/O select */
+
+	0x454, 0x0425b9, /* Sound  */
+	0x454, 0x042539,
+
+	0x111, 0x000,
+	0x10e, 0x00a,
+	0x464, 0x000,
+	0x300, 0x000,
+	0x301, 0x006,
+	0x302, 0x000,
+	0x303, 0x006,
+	0x308, 0x040,
+	0x309, 0x000,
+	0x30a, 0x000,
+	0x30b, 0x000,
+	0x000, 0x002,
+	0x001, 0x000,
+	0x002, 0x000,
+	0x003, 0x000,
+	0x004, 0x033,
+	0x040, 0x01d,
+	0x041, 0x001,
+	0x042, 0x004,
+	0x043, 0x000,
+	0x080, 0x01e,
+	0x081, 0x001,
+	0x082, 0x004,
+	0x083, 0x000,
+	0x190, 0x018,
+	0x115, 0x000,
+	0x116, 0x012,
+	0x117, 0x018,
+	0x04a, 0x011,
+	0x08a, 0x011,
+	0x04b, 0x000,
+	0x08b, 0x000,
+	0x048, 0x000,
+	0x088, 0x000,
+	0x04e, 0x012,
+	0x08e, 0x012,
+	0x058, 0x012,
+	0x098, 0x012,
+	0x059, 0x000,
+	0x099, 0x000,
+	0x05a, 0x003,
+	0x09a, 0x003,
+	0x05b, 0x001,
+	0x09b, 0x001,
+	0x054, 0x008,
+	0x094, 0x008,
+	0x055, 0x000,
+	0x095, 0x000,
+	0x056, 0x0c7,
+	0x096, 0x0c7,
+	0x057, 0x002,
+	0x097, 0x002,
+	0x0ff, 0x0ff,
+	0x060, 0x001,
+	0x0a0, 0x001,
+	0x061, 0x000,
+	0x0a1, 0x000,
+	0x062, 0x000,
+	0x0a2, 0x000,
+	0x063, 0x000,
+	0x0a3, 0x000,
+	0x070, 0x000,
+	0x0b0, 0x000,
+	0x071, 0x004,
+	0x0b1, 0x004,
+	0x06c, 0x0e9,
+	0x0ac, 0x0e9,
+	0x06d, 0x003,
+	0x0ad, 0x003,
+	0x05c, 0x0d0,
+	0x09c, 0x0d0,
+	0x05d, 0x002,
+	0x09d, 0x002,
+	0x05e, 0x0f2,
+	0x09e, 0x0f2,
+	0x05f, 0x000,
+	0x09f, 0x000,
+	0x074, 0x000,
+	0x0b4, 0x000,
+	0x075, 0x000,
+	0x0b5, 0x000,
+	0x076, 0x000,
+	0x0b6, 0x000,
+	0x077, 0x000,
+	0x0b7, 0x000,
+	0x195, 0x008,
+	0x0ff, 0x0ff,
+	0x108, 0x0f8,
+	0x111, 0x000,
+	0x10e, 0x00a,
+	0x2a9, 0x0fd,
+	0x464, 0x001,
+	0x454, 0x042135,
+	0x598, 0x0e7,
+	0x599, 0x07d,
+	0x59a, 0x018,
+	0x59c, 0x066,
+	0x59d, 0x090,
+	0x59e, 0x001,
+	0x584, 0x000,
+	0x585, 0x000,
+	0x586, 0x003,
+	0x588, 0x0ff,
+	0x589, 0x00f,
+	0x58a, 0x000,
+	0x58b, 0x000,
+	0x58c, 0x010,
+	0x58d, 0x032,
+	0x58e, 0x054,
+	0x58f, 0x023,
+	0x590, 0x000,
+	0x595, 0x000,
+	0x596, 0x000,
+	0x597, 0x000,
+	0x464, 0x000,
+	0x46c, 0xbbbb10,
+	0x470, 0x101010,
+
+
+	0x478, 0x000,
+	0x474, 0x018,
+	0x454, 0x042135,
+	0x598, 0x0e7,
+	0x599, 0x07d,
+	0x59a, 0x018,
+	0x59c, 0x066,
+	0x59d, 0x090,
+	0x59e, 0x001,
+	0x584, 0x000,
+	0x585, 0x000,
+	0x586, 0x003,
+	0x588, 0x0ff,
+	0x589, 0x00f,
+	0x58a, 0x000,
+	0x58b, 0x000,
+	0x58c, 0x010,
+	0x58d, 0x032,
+	0x58e, 0x054,
+	0x58f, 0x023,
+	0x590, 0x000,
+	0x595, 0x000,
+	0x596, 0x000,
+	0x597, 0x000,
+	0x464, 0x000,
+	0x46c, 0xbbbb10,
+	0x470, 0x101010,
+
+	0x478, 0x000,
+	0x474, 0x018,
+	0x454, 0x042135,
+	0x598, 0x0e7,
+	0x599, 0x07d,
+	0x59a, 0x018,
+	0x59c, 0x066,
+	0x59d, 0x090,
+	0x59e, 0x001,
+	0x584, 0x000,
+	0x585, 0x000,
+	0x586, 0x003,
+	0x588, 0x0ff,
+	0x589, 0x00f,
+	0x58a, 0x000,
+	0x58b, 0x000,
+	0x58c, 0x010,
+	0x58d, 0x032,
+	0x58e, 0x054,
+	0x58f, 0x023,
+	0x590, 0x000,
+	0x595, 0x000,
+	0x596, 0x000,
+	0x597, 0x000,
+	0x464, 0x000,
+	0x46c, 0xbbbb10,
+	0x470, 0x101010,
+	0x478, 0x000,
+	0x474, 0x018,
+	0x454, 0x042135,
+	0x193, 0x000,
+	0x300, 0x000,
+	0x301, 0x006,
+	0x302, 0x000,
+	0x303, 0x006,
+	0x308, 0x040,
+	0x309, 0x000,
+	0x30a, 0x000,
+	0x30b, 0x000,
+	0x000, 0x002,
+	0x001, 0x000,
+	0x002, 0x000,
+	0x003, 0x000,
+	0x004, 0x033,
+	0x040, 0x01d,
+	0x041, 0x001,
+	0x042, 0x004,
+	0x043, 0x000,
+	0x080, 0x01e,
+	0x081, 0x001,
+	0x082, 0x004,
+	0x083, 0x000,
+	0x190, 0x018,
+	0x115, 0x000,
+	0x116, 0x012,
+	0x117, 0x018,
+	0x04a, 0x011,
+	0x08a, 0x011,
+	0x04b, 0x000,
+	0x08b, 0x000,
+	0x048, 0x000,
+	0x088, 0x000,
+	0x04e, 0x012,
+	0x08e, 0x012,
+	0x058, 0x012,
+	0x098, 0x012,
+	0x059, 0x000,
+	0x099, 0x000,
+	0x05a, 0x003,
+	0x09a, 0x003,
+	0x05b, 0x001,
+	0x09b, 0x001,
+	0x054, 0x008,
+	0x094, 0x008,
+	0x055, 0x000,
+	0x095, 0x000,
+	0x056, 0x0c7,
+	0x096, 0x0c7,
+	0x057, 0x002,
+	0x097, 0x002,
+	0x060, 0x001,
+	0x0a0, 0x001,
+	0x061, 0x000,
+	0x0a1, 0x000,
+	0x062, 0x000,
+	0x0a2, 0x000,
+	0x063, 0x000,
+	0x0a3, 0x000,
+	0x070, 0x000,
+	0x0b0, 0x000,
+	0x071, 0x004,
+	0x0b1, 0x004,
+	0x06c, 0x0e9,
+	0x0ac, 0x0e9,
+	0x06d, 0x003,
+	0x0ad, 0x003,
+	0x05c, 0x0d0,
+	0x09c, 0x0d0,
+	0x05d, 0x002,
+	0x09d, 0x002,
+	0x05e, 0x0f2,
+	0x09e, 0x0f2,
+	0x05f, 0x000,
+	0x09f, 0x000,
+	0x074, 0x000,
+	0x0b4, 0x000,
+	0x075, 0x000,
+	0x0b5, 0x000,
+	0x076, 0x000,
+	0x0b6, 0x000,
+	0x077, 0x000,
+	0x0b7, 0x000,
+	0x195, 0x008,
+	0x598, 0x0e7,
+	0x599, 0x07d,
+	0x59a, 0x018,
+	0x59c, 0x066,
+	0x59d, 0x090,
+	0x59e, 0x001,
+	0x584, 0x000,
+	0x585, 0x000,
+	0x586, 0x003,
+	0x588, 0x0ff,
+	0x589, 0x00f,
+	0x58a, 0x000,
+	0x58b, 0x000,
+	0x58c, 0x010,
+	0x58d, 0x032,
+	0x58e, 0x054,
+	0x58f, 0x023,
+	0x590, 0x000,
+	0x595, 0x000,
+	0x596, 0x000,
+	0x597, 0x000,
+	0x464, 0x000,
+	0x46c, 0xbbbb10,
+	0x470, 0x101010,
+	0x478, 0x000,
+	0x474, 0x018,
+	0x454, 0x042135,
+	0x193, 0x0a6,
+	0x108, 0x0f8,
+	0x042, 0x003,
+	0x082, 0x003,
+	0x454, 0x0425b9,
+	0x454, 0x042539,
+	0x193, 0x000,
+	0x193, 0x0a6,
+	0x464, 0x000,
+
+	0, 0
+};
+
+/* Tuner */
+static u32 reg_init_tuner_input[] = {
+	0x108, 0x0f8, /* Sync control */
+	0x111, 0x000, /* Mode/delay control */
+	0x10e, 0x00a, /* Chroma control 1 */
+	0, 0
+};
+
+/* Composite */
+static u32 reg_init_composite_input[] = {
+	0x108, 0x0e8, /* Sync control */
+	0x111, 0x000, /* Mode/delay control */
+	0x10e, 0x04a, /* Chroma control 1 */
+	0, 0
+};
+
+/* S-Video */
+static u32 reg_init_svideo_input[] = {
+	0x108, 0x0e8, /* Sync control */
+	0x111, 0x000, /* Mode/delay control */
+	0x10e, 0x04a, /* Chroma control 1 */
+	0, 0
+};
+
+static u32 reg_set_audio_template[4][2] =
+{
+	{ /* for MONO
+		tadachi 6/29 DMA audio output select?
+		Register 0x46c
+		7-4: DMA2, 3-0: DMA1 ch. DMA4, DMA3 DMA2, DMA1
+		0: MAIN left,  1: MAIN right
+		2: AUX1 left,  3: AUX1 right
+		4: AUX2 left,  5: AUX2 right
+		6: DPL left,   7: DPL  right
+		8: DPL center, 9: DPL surround
+		A: monitor output, B: digital sense */
+		0xbbbb00,
+
+		/* tadachi 6/29 DAC and I2S output select?
+		   Register 0x470
+		   7-4:DAC right ch. 3-0:DAC left ch.
+		   I2S1 right,left  I2S2 right,left */
+		0x00,
+	},
+	{ /* for STEREO */
+		0xbbbb10, 0x101010,
+	},
+	{ /* for LANG1 */
+		0xbbbb00, 0x00,
+	},
+	{ /* for LANG2/SAP */
+		0xbbbb11, 0x111111,
+	}
+};
+
+
+/* Get detected audio flags (from saa7134 driver) */
+static void get_inf_dev_status(struct v4l2_subdev *sd,
+		int *dual_flag, int *stereo_flag)
+{
+	u32 reg_data3;
+
+	static char *stdres[0x20] = {
+		[0x00] = "no standard detected",
+		[0x01] = "B/G (in progress)",
+		[0x02] = "D/K (in progress)",
+		[0x03] = "M (in progress)",
+
+		[0x04] = "B/G A2",
+		[0x05] = "B/G NICAM",
+		[0x06] = "D/K A2 (1)",
+		[0x07] = "D/K A2 (2)",
+		[0x08] = "D/K A2 (3)",
+		[0x09] = "D/K NICAM",
+		[0x0a] = "L NICAM",
+		[0x0b] = "I NICAM",
+
+		[0x0c] = "M Korea",
+		[0x0d] = "M BTSC ",
+		[0x0e] = "M EIAJ",
+
+		[0x0f] = "FM radio / IF 10.7 / 50 deemp",
+		[0x10] = "FM radio / IF 10.7 / 75 deemp",
+		[0x11] = "FM radio / IF sel / 50 deemp",
+		[0x12] = "FM radio / IF sel / 75 deemp",
+
+		[0x13 ... 0x1e] = "unknown",
+		[0x1f] = "??? [in progress]",
+	};
+
+
+	*dual_flag = *stereo_flag = 0;
+
+	/* (demdec status: 0x528) */
+
+	/* read current status */
+	reg_data3 = saa717x_read(sd, 0x0528);
+
+	v4l2_dbg(1, debug, sd, "tvaudio thread status: 0x%x [%s%s%s]\n",
+		reg_data3, stdres[reg_data3 & 0x1f],
+		(reg_data3 & 0x000020) ? ",stereo" : "",
+		(reg_data3 & 0x000040) ? ",dual"   : "");
+	v4l2_dbg(1, debug, sd, "detailed status: "
+		"%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
+		(reg_data3 & 0x000080) ? " A2/EIAJ pilot tone "     : "",
+		(reg_data3 & 0x000100) ? " A2/EIAJ dual "           : "",
+		(reg_data3 & 0x000200) ? " A2/EIAJ stereo "         : "",
+		(reg_data3 & 0x000400) ? " A2/EIAJ noise mute "     : "",
+
+		(reg_data3 & 0x000800) ? " BTSC/FM radio pilot "    : "",
+		(reg_data3 & 0x001000) ? " SAP carrier "            : "",
+		(reg_data3 & 0x002000) ? " BTSC stereo noise mute " : "",
+		(reg_data3 & 0x004000) ? " SAP noise mute "         : "",
+		(reg_data3 & 0x008000) ? " VDSP "                   : "",
+
+		(reg_data3 & 0x010000) ? " NICST "                  : "",
+		(reg_data3 & 0x020000) ? " NICDU "                  : "",
+		(reg_data3 & 0x040000) ? " NICAM muted "            : "",
+		(reg_data3 & 0x080000) ? " NICAM reserve sound "    : "",
+
+		(reg_data3 & 0x100000) ? " init done "              : "");
+
+	if (reg_data3 & 0x000220) {
+		v4l2_dbg(1, debug, sd, "ST!!!\n");
+		*stereo_flag = 1;
+	}
+
+	if (reg_data3 & 0x000140) {
+		v4l2_dbg(1, debug, sd, "DUAL!!!\n");
+		*dual_flag = 1;
+	}
+}
+
+/* regs write to set audio mode */
+static void set_audio_mode(struct v4l2_subdev *sd, int audio_mode)
+{
+	v4l2_dbg(1, debug, sd, "writing registers to set audio mode by set %d\n",
+			audio_mode);
+
+	saa717x_write(sd, 0x46c, reg_set_audio_template[audio_mode][0]);
+	saa717x_write(sd, 0x470, reg_set_audio_template[audio_mode][1]);
+}
+
+/* write regs to set audio volume, bass and treble */
+static int set_audio_regs(struct v4l2_subdev *sd,
+		struct saa717x_state *decoder)
+{
+	u8 mute = 0xac; /* -84 dB */
+	u32 val;
+	unsigned int work_l, work_r;
+
+	/* set SIF analog I/O select */
+	saa717x_write(sd, 0x0594, decoder->audio_input);
+	v4l2_dbg(1, debug, sd, "set audio input %d\n",
+			decoder->audio_input);
+
+	/* normalize ( 65535 to 0 -> 24 to -40 (not -84)) */
+	work_l = (min(65536 - decoder->audio_main_balance, 32768) * decoder->audio_main_volume) / 32768;
+	work_r = (min(decoder->audio_main_balance, (u16)32768) * decoder->audio_main_volume) / 32768;
+	decoder->audio_main_vol_l = (long)work_l * (24 - (-40)) / 65535 - 40;
+	decoder->audio_main_vol_r = (long)work_r * (24 - (-40)) / 65535 - 40;
+
+	/* set main volume */
+	/* main volume L[7-0],R[7-0],0x00  24=24dB,-83dB, -84(mute) */
+	/*    def:0dB->6dB(MPG600GR) */
+	/* if mute is on, set mute */
+	if (decoder->audio_main_mute) {
+		val = mute | (mute << 8);
+	} else {
+		val = (u8)decoder->audio_main_vol_l |
+			((u8)decoder->audio_main_vol_r << 8);
+	}
+
+	saa717x_write(sd, 0x480, val);
+
+	/* set bass and treble */
+	val = decoder->audio_main_bass & 0x1f;
+	val |= (decoder->audio_main_treble & 0x1f) << 5;
+	saa717x_write(sd, 0x488, val);
+	return 0;
+}
+
+/********** scaling staff ***********/
+static void set_h_prescale(struct v4l2_subdev *sd,
+		int task, int prescale)
+{
+	static const struct {
+		int xpsc;
+		int xacl;
+		int xc2_1;
+		int xdcg;
+		int vpfy;
+	} vals[] = {
+		/* XPSC XACL XC2_1 XDCG VPFY */
+		{    1,   0,    0,    0,   0 },
+		{    2,   2,    1,    2,   2 },
+		{    3,   4,    1,    3,   2 },
+		{    4,   8,    1,    4,   2 },
+		{    5,   8,    1,    4,   2 },
+		{    6,   8,    1,    4,   3 },
+		{    7,   8,    1,    4,   3 },
+		{    8,  15,    0,    4,   3 },
+		{    9,  15,    0,    4,   3 },
+		{   10,  16,    1,    5,   3 },
+	};
+	static const int count = ARRAY_SIZE(vals);
+	int i, task_shift;
+
+	task_shift = task * 0x40;
+	for (i = 0; i < count; i++)
+		if (vals[i].xpsc == prescale)
+			break;
+	if (i == count)
+		return;
+
+	/* horizonal prescaling */
+	saa717x_write(sd, 0x60 + task_shift, vals[i].xpsc);
+	/* accumulation length */
+	saa717x_write(sd, 0x61 + task_shift, vals[i].xacl);
+	/* level control */
+	saa717x_write(sd, 0x62 + task_shift,
+			(vals[i].xc2_1 << 3) | vals[i].xdcg);
+	/*FIR prefilter control */
+	saa717x_write(sd, 0x63 + task_shift,
+			(vals[i].vpfy << 2) | vals[i].vpfy);
+}
+
+/********** scaling staff ***********/
+static void set_v_scale(struct v4l2_subdev *sd, int task, int yscale)
+{
+	int task_shift;
+
+	task_shift = task * 0x40;
+	/* Vertical scaling ratio (LOW) */
+	saa717x_write(sd, 0x70 + task_shift, yscale & 0xff);
+	/* Vertical scaling ratio (HI) */
+	saa717x_write(sd, 0x71 + task_shift, yscale >> 8);
+}
+
+static int saa717x_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct saa717x_state *state = to_state(sd);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		saa717x_write(sd, 0x10a, ctrl->val);
+		return 0;
+
+	case V4L2_CID_CONTRAST:
+		saa717x_write(sd, 0x10b, ctrl->val);
+		return 0;
+
+	case V4L2_CID_SATURATION:
+		saa717x_write(sd, 0x10c, ctrl->val);
+		return 0;
+
+	case V4L2_CID_HUE:
+		saa717x_write(sd, 0x10d, ctrl->val);
+		return 0;
+
+	case V4L2_CID_AUDIO_MUTE:
+		state->audio_main_mute = ctrl->val;
+		break;
+
+	case V4L2_CID_AUDIO_VOLUME:
+		state->audio_main_volume = ctrl->val;
+		break;
+
+	case V4L2_CID_AUDIO_BALANCE:
+		state->audio_main_balance = ctrl->val;
+		break;
+
+	case V4L2_CID_AUDIO_TREBLE:
+		state->audio_main_treble = ctrl->val;
+		break;
+
+	case V4L2_CID_AUDIO_BASS:
+		state->audio_main_bass = ctrl->val;
+		break;
+
+	default:
+		return 0;
+	}
+	set_audio_regs(sd, state);
+	return 0;
+}
+
+static int saa717x_s_video_routing(struct v4l2_subdev *sd,
+				   u32 input, u32 output, u32 config)
+{
+	struct saa717x_state *decoder = to_state(sd);
+	int is_tuner = input & 0x80;  /* tuner input flag */
+
+	input &= 0x7f;
+
+	v4l2_dbg(1, debug, sd, "decoder set input (%d)\n", input);
+	/* inputs from 0-9 are available*/
+	/* saa717x have mode0-mode9 but mode5 is reserved. */
+	if (input > 9 || input == 5)
+		return -EINVAL;
+
+	if (decoder->input != input) {
+		int input_line = input;
+
+		decoder->input = input_line;
+		v4l2_dbg(1, debug, sd,  "now setting %s input %d\n",
+				input_line >= 6 ? "S-Video" : "Composite",
+				input_line);
+
+		/* select mode */
+		saa717x_write(sd, 0x102,
+				(saa717x_read(sd, 0x102) & 0xf0) |
+				input_line);
+
+		/* bypass chrominance trap for modes 6..9 */
+		saa717x_write(sd, 0x109,
+				(saa717x_read(sd, 0x109) & 0x7f) |
+				(input_line < 6 ? 0x0 : 0x80));
+
+		/* change audio_mode */
+		if (is_tuner) {
+			/* tuner */
+			set_audio_mode(sd, decoder->tuner_audio_mode);
+		} else {
+			/* Force to STEREO mode if Composite or
+			 * S-Video were chosen */
+			set_audio_mode(sd, TUNER_AUDIO_STEREO);
+		}
+		/* change initialize procedure (Composite/S-Video) */
+		if (is_tuner)
+			saa717x_write_regs(sd, reg_init_tuner_input);
+		else if (input_line >= 6)
+			saa717x_write_regs(sd, reg_init_svideo_input);
+		else
+			saa717x_write_regs(sd, reg_init_composite_input);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	reg->val = saa717x_read(sd, reg->reg);
+	reg->size = 1;
+	return 0;
+}
+
+static int saa717x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u16 addr = reg->reg & 0xffff;
+	u8 val = reg->val & 0xff;
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	saa717x_write(sd, addr, val);
+	return 0;
+}
+#endif
+
+static int saa717x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
+{
+	int prescale, h_scale, v_scale;
+
+	v4l2_dbg(1, debug, sd, "decoder set size\n");
+
+	if (fmt->code != V4L2_MBUS_FMT_FIXED)
+		return -EINVAL;
+
+	/* FIXME need better bounds checking here */
+	if (fmt->width < 1 || fmt->width > 1440)
+		return -EINVAL;
+	if (fmt->height < 1 || fmt->height > 960)
+		return -EINVAL;
+
+	fmt->field = V4L2_FIELD_INTERLACED;
+	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+	/* scaling setting */
+	/* NTSC and interlace only */
+	prescale = SAA717X_NTSC_WIDTH / fmt->width;
+	if (prescale == 0)
+		prescale = 1;
+	h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / fmt->width;
+	/* interlace */
+	v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / fmt->height;
+
+	/* Horizontal prescaling etc */
+	set_h_prescale(sd, 0, prescale);
+	set_h_prescale(sd, 1, prescale);
+
+	/* Horizontal scaling increment */
+	/* TASK A */
+	saa717x_write(sd, 0x6C, (u8)(h_scale & 0xFF));
+	saa717x_write(sd, 0x6D, (u8)((h_scale >> 8) & 0xFF));
+	/* TASK B */
+	saa717x_write(sd, 0xAC, (u8)(h_scale & 0xFF));
+	saa717x_write(sd, 0xAD, (u8)((h_scale >> 8) & 0xFF));
+
+	/* Vertical prescaling etc */
+	set_v_scale(sd, 0, v_scale);
+	set_v_scale(sd, 1, v_scale);
+
+	/* set video output size */
+	/* video number of pixels at output */
+	/* TASK A */
+	saa717x_write(sd, 0x5C, (u8)(fmt->width & 0xFF));
+	saa717x_write(sd, 0x5D, (u8)((fmt->width >> 8) & 0xFF));
+	/* TASK B */
+	saa717x_write(sd, 0x9C, (u8)(fmt->width & 0xFF));
+	saa717x_write(sd, 0x9D, (u8)((fmt->width >> 8) & 0xFF));
+
+	/* video number of lines at output */
+	/* TASK A */
+	saa717x_write(sd, 0x5E, (u8)(fmt->height & 0xFF));
+	saa717x_write(sd, 0x5F, (u8)((fmt->height >> 8) & 0xFF));
+	/* TASK B */
+	saa717x_write(sd, 0x9E, (u8)(fmt->height & 0xFF));
+	saa717x_write(sd, 0x9F, (u8)((fmt->height >> 8) & 0xFF));
+	return 0;
+}
+
+static int saa717x_s_radio(struct v4l2_subdev *sd)
+{
+	struct saa717x_state *decoder = to_state(sd);
+
+	decoder->radio = 1;
+	return 0;
+}
+
+static int saa717x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct saa717x_state *decoder = to_state(sd);
+
+	v4l2_dbg(1, debug, sd, "decoder set norm ");
+	v4l2_dbg(1, debug, sd, "(not yet implementd)\n");
+
+	decoder->radio = 0;
+	decoder->std = std;
+	return 0;
+}
+
+static int saa717x_s_audio_routing(struct v4l2_subdev *sd,
+				   u32 input, u32 output, u32 config)
+{
+	struct saa717x_state *decoder = to_state(sd);
+
+	if (input < 3) { /* FIXME! --tadachi */
+		decoder->audio_input = input;
+		v4l2_dbg(1, debug, sd,
+				"set decoder audio input to %d\n",
+				decoder->audio_input);
+		set_audio_regs(sd, decoder);
+		return 0;
+	}
+	return -ERANGE;
+}
+
+static int saa717x_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct saa717x_state *decoder = to_state(sd);
+
+	v4l2_dbg(1, debug, sd, "decoder %s output\n",
+			enable ? "enable" : "disable");
+	decoder->enable = enable;
+	saa717x_write(sd, 0x193, enable ? 0xa6 : 0x26);
+	return 0;
+}
+
+/* change audio mode */
+static int saa717x_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct saa717x_state *decoder = to_state(sd);
+	int audio_mode;
+	char *mes[4] = {
+		"MONO", "STEREO", "LANG1", "LANG2/SAP"
+	};
+
+	audio_mode = TUNER_AUDIO_STEREO;
+
+	switch (vt->audmode) {
+		case V4L2_TUNER_MODE_MONO:
+			audio_mode = TUNER_AUDIO_MONO;
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+			audio_mode = TUNER_AUDIO_STEREO;
+			break;
+		case V4L2_TUNER_MODE_LANG2:
+			audio_mode = TUNER_AUDIO_LANG2;
+			break;
+		case V4L2_TUNER_MODE_LANG1:
+			audio_mode = TUNER_AUDIO_LANG1;
+			break;
+	}
+
+	v4l2_dbg(1, debug, sd, "change audio mode to %s\n",
+			mes[audio_mode]);
+	decoder->tuner_audio_mode = audio_mode;
+	/* The registers are not changed here. */
+	/* See DECODER_ENABLE_OUTPUT section. */
+	set_audio_mode(sd, decoder->tuner_audio_mode);
+	return 0;
+}
+
+static int saa717x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct saa717x_state *decoder = to_state(sd);
+	int dual_f, stereo_f;
+
+	if (decoder->radio)
+		return 0;
+	get_inf_dev_status(sd, &dual_f, &stereo_f);
+
+	v4l2_dbg(1, debug, sd, "DETECT==st:%d dual:%d\n",
+			stereo_f, dual_f);
+
+	/* mono */
+	if ((dual_f == 0) && (stereo_f == 0)) {
+		vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+		v4l2_dbg(1, debug, sd, "DETECT==MONO\n");
+	}
+
+	/* stereo */
+	if (stereo_f == 1) {
+		if (vt->audmode == V4L2_TUNER_MODE_STEREO ||
+				vt->audmode == V4L2_TUNER_MODE_LANG1) {
+			vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
+			v4l2_dbg(1, debug, sd, "DETECT==ST(ST)\n");
+		} else {
+			vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+			v4l2_dbg(1, debug, sd, "DETECT==ST(MONO)\n");
+		}
+	}
+
+	/* dual */
+	if (dual_f == 1) {
+		if (vt->audmode == V4L2_TUNER_MODE_LANG2) {
+			vt->rxsubchans = V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_MONO;
+			v4l2_dbg(1, debug, sd, "DETECT==DUAL1\n");
+		} else {
+			vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_MONO;
+			v4l2_dbg(1, debug, sd, "DETECT==DUAL2\n");
+		}
+	}
+	return 0;
+}
+
+static int saa717x_log_status(struct v4l2_subdev *sd)
+{
+	struct saa717x_state *state = to_state(sd);
+
+	v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_ctrl_ops saa717x_ctrl_ops = {
+	.s_ctrl = saa717x_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops saa717x_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = saa717x_g_register,
+	.s_register = saa717x_s_register,
+#endif
+	.s_std = saa717x_s_std,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+	.log_status = saa717x_log_status,
+};
+
+static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = {
+	.g_tuner = saa717x_g_tuner,
+	.s_tuner = saa717x_s_tuner,
+	.s_radio = saa717x_s_radio,
+};
+
+static const struct v4l2_subdev_video_ops saa717x_video_ops = {
+	.s_routing = saa717x_s_video_routing,
+	.s_mbus_fmt = saa717x_s_mbus_fmt,
+	.s_stream = saa717x_s_stream,
+};
+
+static const struct v4l2_subdev_audio_ops saa717x_audio_ops = {
+	.s_routing = saa717x_s_audio_routing,
+};
+
+static const struct v4l2_subdev_ops saa717x_ops = {
+	.core = &saa717x_core_ops,
+	.tuner = &saa717x_tuner_ops,
+	.audio = &saa717x_audio_ops,
+	.video = &saa717x_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+
+/* i2c implementation */
+
+/* ----------------------------------------------------------------------- */
+static int saa717x_probe(struct i2c_client *client,
+			 const struct i2c_device_id *did)
+{
+	struct saa717x_state *decoder;
+	struct v4l2_ctrl_handler *hdl;
+	struct v4l2_subdev *sd;
+	u8 id = 0;
+	char *p = "";
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	decoder = kzalloc(sizeof(struct saa717x_state), GFP_KERNEL);
+	if (decoder == NULL)
+		return -ENOMEM;
+
+	sd = &decoder->sd;
+	v4l2_i2c_subdev_init(sd, client, &saa717x_ops);
+
+	if (saa717x_write(sd, 0x5a4, 0xfe) &&
+			saa717x_write(sd, 0x5a5, 0x0f) &&
+			saa717x_write(sd, 0x5a6, 0x00) &&
+			saa717x_write(sd, 0x5a7, 0x01))
+		id = saa717x_read(sd, 0x5a0);
+	if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
+		v4l2_dbg(1, debug, sd, "saa717x not found (id=%02x)\n", id);
+		kfree(decoder);
+		return -ENODEV;
+	}
+	if (id == 0xc2)
+		p = "saa7173";
+	else if (id == 0x32)
+		p = "saa7174A";
+	else if (id == 0x6c)
+		p = "saa7174HL";
+	else
+		p = "saa7171";
+	v4l2_info(sd, "%s found @ 0x%x (%s)\n", p,
+			client->addr << 1, client->adapter->name);
+
+	hdl = &decoder->hdl;
+	v4l2_ctrl_handler_init(hdl, 9);
+	/* add in ascending ID order */
+	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 255, 1, 68);
+	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 255, 1, 64);
+	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+			V4L2_CID_HUE, -128, 127, 1, 0);
+	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+			V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 42000);
+	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+			V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768);
+	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+			V4L2_CID_AUDIO_BASS, -16, 15, 1, 0);
+	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+			V4L2_CID_AUDIO_TREBLE, -16, 15, 1, 0);
+	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+	sd->ctrl_handler = hdl;
+	if (hdl->error) {
+		int err = hdl->error;
+
+		v4l2_ctrl_handler_free(hdl);
+		kfree(decoder);
+		return err;
+	}
+
+	decoder->std = V4L2_STD_NTSC;
+	decoder->input = -1;
+	decoder->enable = 1;
+
+	/* FIXME!! */
+	decoder->playback = 0;	/* initially capture mode used */
+	decoder->audio = 1; /* DECODER_AUDIO_48_KHZ */
+
+	decoder->audio_input = 2; /* FIXME!! */
+
+	decoder->tuner_audio_mode = TUNER_AUDIO_STEREO;
+	/* set volume, bass and treble */
+	decoder->audio_main_vol_l = 6;
+	decoder->audio_main_vol_r = 6;
+
+	v4l2_dbg(1, debug, sd, "writing init values\n");
+
+	/* FIXME!! */
+	saa717x_write_regs(sd, reg_init_initialize);
+
+	v4l2_ctrl_handler_setup(hdl);
+
+	set_current_state(TASK_INTERRUPTIBLE);
+	schedule_timeout(2*HZ);
+	return 0;
+}
+
+static int saa717x_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(sd->ctrl_handler);
+	kfree(to_state(sd));
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id saa717x_id[] = {
+	{ "saa717x", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, saa717x_id);
+
+static struct i2c_driver saa717x_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "saa717x",
+	},
+	.probe		= saa717x_probe,
+	.remove		= saa717x_remove,
+	.id_table	= saa717x_id,
+};
+
+module_i2c_driver(saa717x_driver);
diff --git a/drivers/media/i2c/saa7185.c b/drivers/media/i2c/saa7185.c
new file mode 100644
index 0000000..2c6b65c
--- /dev/null
+++ b/drivers/media/i2c/saa7185.c
@@ -0,0 +1,377 @@
+/*
+ * saa7185 - Philips SAA7185B video encoder driver version 0.0.3
+ *
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ *
+ * Slight changes for video timing and attachment output by
+ * Wolfgang Scherr <scherr@net4you.net>
+ *
+ * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *    - moved over to linux>=2.4.x i2c protocol (1/1/2003)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
+MODULE_AUTHOR("Dave Perks");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+
+/* ----------------------------------------------------------------------- */
+
+struct saa7185 {
+	struct v4l2_subdev sd;
+	unsigned char reg[128];
+
+	v4l2_std_id norm;
+};
+
+static inline struct saa7185 *to_saa7185(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct saa7185, sd);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static inline int saa7185_read(struct v4l2_subdev *sd)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_read_byte(client);
+}
+
+static int saa7185_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct saa7185 *encoder = to_saa7185(sd);
+
+	v4l2_dbg(1, debug, sd, "%02x set to %02x\n", reg, value);
+	encoder->reg[reg] = value;
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int saa7185_write_block(struct v4l2_subdev *sd,
+		const u8 *data, unsigned int len)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct saa7185 *encoder = to_saa7185(sd);
+	int ret = -1;
+	u8 reg;
+
+	/* the adv7175 has an autoincrement function, use it if
+	 * the adapter understands raw I2C */
+	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		/* do raw I2C, not smbus compatible */
+		u8 block_data[32];
+		int block_len;
+
+		while (len >= 2) {
+			block_len = 0;
+			block_data[block_len++] = reg = data[0];
+			do {
+				block_data[block_len++] =
+				    encoder->reg[reg++] = data[1];
+				len -= 2;
+				data += 2;
+			} while (len >= 2 && data[0] == reg && block_len < 32);
+			ret = i2c_master_send(client, block_data, block_len);
+			if (ret < 0)
+				break;
+		}
+	} else {
+		/* do some slow I2C emulation kind of thing */
+		while (len >= 2) {
+			reg = *data++;
+			ret = saa7185_write(sd, reg, *data++);
+			if (ret < 0)
+				break;
+			len -= 2;
+		}
+	}
+
+	return ret;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const unsigned char init_common[] = {
+	0x3a, 0x0f,		/* CBENB=0, V656=0, VY2C=1,
+				 * YUV2C=1, MY2C=1, MUV2C=1 */
+
+	0x42, 0x6b,		/* OVLY0=107 */
+	0x43, 0x00,		/* OVLU0=0     white */
+	0x44, 0x00,		/* OVLV0=0   */
+	0x45, 0x22,		/* OVLY1=34  */
+	0x46, 0xac,		/* OVLU1=172   yellow */
+	0x47, 0x0e,		/* OVLV1=14  */
+	0x48, 0x03,		/* OVLY2=3   */
+	0x49, 0x1d,		/* OVLU2=29    cyan */
+	0x4a, 0xac,		/* OVLV2=172 */
+	0x4b, 0xf0,		/* OVLY3=240 */
+	0x4c, 0xc8,		/* OVLU3=200   green */
+	0x4d, 0xb9,		/* OVLV3=185 */
+	0x4e, 0xd4,		/* OVLY4=212 */
+	0x4f, 0x38,		/* OVLU4=56    magenta */
+	0x50, 0x47,		/* OVLV4=71  */
+	0x51, 0xc1,		/* OVLY5=193 */
+	0x52, 0xe3,		/* OVLU5=227   red */
+	0x53, 0x54,		/* OVLV5=84  */
+	0x54, 0xa3,		/* OVLY6=163 */
+	0x55, 0x54,		/* OVLU6=84    blue */
+	0x56, 0xf2,		/* OVLV6=242 */
+	0x57, 0x90,		/* OVLY7=144 */
+	0x58, 0x00,		/* OVLU7=0     black */
+	0x59, 0x00,		/* OVLV7=0   */
+
+	0x5a, 0x00,		/* CHPS=0    */
+	0x5b, 0x76,		/* GAINU=118 */
+	0x5c, 0xa5,		/* GAINV=165 */
+	0x5d, 0x3c,		/* BLCKL=60  */
+	0x5e, 0x3a,		/* BLNNL=58  */
+	0x5f, 0x3a,		/* CCRS=0, BLNVB=58 */
+	0x60, 0x00,		/* NULL      */
+
+	/* 0x61 - 0x66 set according to norm */
+
+	0x67, 0x00,		/* 0 : caption 1st byte odd  field */
+	0x68, 0x00,		/* 0 : caption 2nd byte odd  field */
+	0x69, 0x00,		/* 0 : caption 1st byte even field */
+	0x6a, 0x00,		/* 0 : caption 2nd byte even field */
+
+	0x6b, 0x91,		/* MODIN=2, PCREF=0, SCCLN=17 */
+	0x6c, 0x20,		/* SRCV1=0, TRCV2=1, ORCV1=0, PRCV1=0,
+				 * CBLF=0, ORCV2=0, PRCV2=0 */
+	0x6d, 0x00,		/* SRCM1=0, CCEN=0 */
+
+	0x6e, 0x0e,		/* HTRIG=0x005, approx. centered, at
+				 * least for PAL */
+	0x6f, 0x00,		/* HTRIG upper bits */
+	0x70, 0x20,		/* PHRES=0, SBLN=1, VTRIG=0 */
+
+	/* The following should not be needed */
+
+	0x71, 0x15,		/* BMRQ=0x115 */
+	0x72, 0x90,		/* EMRQ=0x690 */
+	0x73, 0x61,		/* EMRQ=0x690, BMRQ=0x115 */
+	0x74, 0x00,		/* NULL       */
+	0x75, 0x00,		/* NULL       */
+	0x76, 0x00,		/* NULL       */
+	0x77, 0x15,		/* BRCV=0x115 */
+	0x78, 0x90,		/* ERCV=0x690 */
+	0x79, 0x61,		/* ERCV=0x690, BRCV=0x115 */
+
+	/* Field length controls */
+
+	0x7a, 0x70,		/* FLC=0 */
+
+	/* The following should not be needed if SBLN = 1 */
+
+	0x7b, 0x16,		/* FAL=22 */
+	0x7c, 0x35,		/* LAL=244 */
+	0x7d, 0x20,		/* LAL=244, FAL=22 */
+};
+
+static const unsigned char init_pal[] = {
+	0x61, 0x1e,		/* FISE=0, PAL=1, SCBW=1, RTCE=1,
+				 * YGS=1, INPI=0, DOWN=0 */
+	0x62, 0xc8,		/* DECTYP=1, BSTA=72 */
+	0x63, 0xcb,		/* FSC0 */
+	0x64, 0x8a,		/* FSC1 */
+	0x65, 0x09,		/* FSC2 */
+	0x66, 0x2a,		/* FSC3 */
+};
+
+static const unsigned char init_ntsc[] = {
+	0x61, 0x1d,		/* FISE=1, PAL=0, SCBW=1, RTCE=1,
+				 * YGS=1, INPI=0, DOWN=0 */
+	0x62, 0xe6,		/* DECTYP=1, BSTA=102 */
+	0x63, 0x1f,		/* FSC0 */
+	0x64, 0x7c,		/* FSC1 */
+	0x65, 0xf0,		/* FSC2 */
+	0x66, 0x21,		/* FSC3 */
+};
+
+
+static int saa7185_init(struct v4l2_subdev *sd, u32 val)
+{
+	struct saa7185 *encoder = to_saa7185(sd);
+
+	saa7185_write_block(sd, init_common, sizeof(init_common));
+	if (encoder->norm & V4L2_STD_NTSC)
+		saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc));
+	else
+		saa7185_write_block(sd, init_pal, sizeof(init_pal));
+	return 0;
+}
+
+static int saa7185_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct saa7185 *encoder = to_saa7185(sd);
+
+	if (std & V4L2_STD_NTSC)
+		saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc));
+	else if (std & V4L2_STD_PAL)
+		saa7185_write_block(sd, init_pal, sizeof(init_pal));
+	else
+		return -EINVAL;
+	encoder->norm = std;
+	return 0;
+}
+
+static int saa7185_s_routing(struct v4l2_subdev *sd,
+			     u32 input, u32 output, u32 config)
+{
+	struct saa7185 *encoder = to_saa7185(sd);
+
+	/* RJ: input = 0: input is from SA7111
+	 input = 1: input is from ZR36060 */
+
+	switch (input) {
+	case 0:
+		/* turn off colorbar */
+		saa7185_write(sd, 0x3a, 0x0f);
+		/* Switch RTCE to 1 */
+		saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08);
+		saa7185_write(sd, 0x6e, 0x01);
+		break;
+
+	case 1:
+		/* turn off colorbar */
+		saa7185_write(sd, 0x3a, 0x0f);
+		/* Switch RTCE to 0 */
+		saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x00);
+		/* SW: a slight sync problem... */
+		saa7185_write(sd, 0x6e, 0x00);
+		break;
+
+	case 2:
+		/* turn on colorbar */
+		saa7185_write(sd, 0x3a, 0x8f);
+		/* Switch RTCE to 0 */
+		saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08);
+		/* SW: a slight sync problem... */
+		saa7185_write(sd, 0x6e, 0x01);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int saa7185_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7185, 0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops saa7185_core_ops = {
+	.g_chip_ident = saa7185_g_chip_ident,
+	.init = saa7185_init,
+};
+
+static const struct v4l2_subdev_video_ops saa7185_video_ops = {
+	.s_std_output = saa7185_s_std_output,
+	.s_routing = saa7185_s_routing,
+};
+
+static const struct v4l2_subdev_ops saa7185_ops = {
+	.core = &saa7185_core_ops,
+	.video = &saa7185_video_ops,
+};
+
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7185_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int i;
+	struct saa7185 *encoder;
+	struct v4l2_subdev *sd;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	encoder = kzalloc(sizeof(struct saa7185), GFP_KERNEL);
+	if (encoder == NULL)
+		return -ENOMEM;
+	encoder->norm = V4L2_STD_NTSC;
+	sd = &encoder->sd;
+	v4l2_i2c_subdev_init(sd, client, &saa7185_ops);
+
+	i = saa7185_write_block(sd, init_common, sizeof(init_common));
+	if (i >= 0)
+		i = saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc));
+	if (i < 0)
+		v4l2_dbg(1, debug, sd, "init error %d\n", i);
+	else
+		v4l2_dbg(1, debug, sd, "revision 0x%x\n",
+				saa7185_read(sd) >> 5);
+	return 0;
+}
+
+static int saa7185_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct saa7185 *encoder = to_saa7185(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	/* SW: output off is active */
+	saa7185_write(sd, 0x61, (encoder->reg[0x61]) | 0x40);
+	kfree(encoder);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id saa7185_id[] = {
+	{ "saa7185", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, saa7185_id);
+
+static struct i2c_driver saa7185_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "saa7185",
+	},
+	.probe		= saa7185_probe,
+	.remove		= saa7185_remove,
+	.id_table	= saa7185_id,
+};
+
+module_i2c_driver(saa7185_driver);
diff --git a/drivers/media/i2c/saa7191.c b/drivers/media/i2c/saa7191.c
new file mode 100644
index 0000000..d7d1670
--- /dev/null
+++ b/drivers/media/i2c/saa7191.c
@@ -0,0 +1,659 @@
+/*
+ *  saa7191.c - Philips SAA7191 video decoder driver
+ *
+ *  Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ *  Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "saa7191.h"
+
+#define SAA7191_MODULE_VERSION	"0.0.5"
+
+MODULE_DESCRIPTION("Philips SAA7191 video decoder driver");
+MODULE_VERSION(SAA7191_MODULE_VERSION);
+MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
+MODULE_LICENSE("GPL");
+
+
+// #define SAA7191_DEBUG
+
+#ifdef SAA7191_DEBUG
+#define dprintk(x...) printk("SAA7191: " x);
+#else
+#define dprintk(x...)
+#endif
+
+#define SAA7191_SYNC_COUNT	30
+#define SAA7191_SYNC_DELAY	100	/* milliseconds */
+
+struct saa7191 {
+	struct v4l2_subdev sd;
+
+	/* the register values are stored here as the actual
+	 * I2C-registers are write-only */
+	u8 reg[25];
+
+	int input;
+	v4l2_std_id norm;
+};
+
+static inline struct saa7191 *to_saa7191(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct saa7191, sd);
+}
+
+static const u8 initseq[] = {
+	0,	/* Subaddress */
+
+	0x50,	/* (0x50) SAA7191_REG_IDEL */
+
+	/* 50 Hz signal timing */
+	0x30,	/* (0x30) SAA7191_REG_HSYB */
+	0x00,	/* (0x00) SAA7191_REG_HSYS */
+	0xe8,	/* (0xe8) SAA7191_REG_HCLB */
+	0xb6,	/* (0xb6) SAA7191_REG_HCLS */
+	0xf4,	/* (0xf4) SAA7191_REG_HPHI */
+
+	/* control */
+	SAA7191_LUMA_APER_1,	/* (0x01) SAA7191_REG_LUMA - CVBS mode */
+	0x00,	/* (0x00) SAA7191_REG_HUEC */
+	0xf8,	/* (0xf8) SAA7191_REG_CKTQ */
+	0xf8,	/* (0xf8) SAA7191_REG_CKTS */
+	0x90,	/* (0x90) SAA7191_REG_PLSE */
+	0x90,	/* (0x90) SAA7191_REG_SESE */
+	0x00,	/* (0x00) SAA7191_REG_GAIN */
+	SAA7191_STDC_NFEN | SAA7191_STDC_HRMV,	/* (0x0c) SAA7191_REG_STDC
+						 * - not SECAM,
+						 * slow time constant */
+	SAA7191_IOCK_OEDC | SAA7191_IOCK_OEHS | SAA7191_IOCK_OEVS
+	| SAA7191_IOCK_OEDY,	/* (0x78) SAA7191_REG_IOCK
+				 * - chroma from CVBS, GPSW1 & 2 off */
+	SAA7191_CTL3_AUFD | SAA7191_CTL3_SCEN | SAA7191_CTL3_OFTS
+	| SAA7191_CTL3_YDEL0,	/* (0x99) SAA7191_REG_CTL3
+				 * - automatic field detection */
+	0x00,	/* (0x00) SAA7191_REG_CTL4 */
+	0x2c,	/* (0x2c) SAA7191_REG_CHCV - PAL nominal value */
+	0x00,	/* unused */
+	0x00,	/* unused */
+
+	/* 60 Hz signal timing */
+	0x34,	/* (0x34) SAA7191_REG_HS6B */
+	0x0a,	/* (0x0a) SAA7191_REG_HS6S */
+	0xf4,	/* (0xf4) SAA7191_REG_HC6B */
+	0xce,	/* (0xce) SAA7191_REG_HC6S */
+	0xf4,	/* (0xf4) SAA7191_REG_HP6I */
+};
+
+/* SAA7191 register handling */
+
+static u8 saa7191_read_reg(struct v4l2_subdev *sd, u8 reg)
+{
+	return to_saa7191(sd)->reg[reg];
+}
+
+static int saa7191_read_status(struct v4l2_subdev *sd, u8 *value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+
+	ret = i2c_master_recv(client, value, 1);
+	if (ret < 0) {
+		printk(KERN_ERR "SAA7191: saa7191_read_status(): read failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+
+static int saa7191_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	to_saa7191(sd)->reg[reg] = value;
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/* the first byte of data must be the first subaddress number (register) */
+static int saa7191_write_block(struct v4l2_subdev *sd,
+			       u8 length, const u8 *data)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct saa7191 *decoder = to_saa7191(sd);
+	int i;
+	int ret;
+
+	for (i = 0; i < (length - 1); i++) {
+		decoder->reg[data[0] + i] = data[i + 1];
+	}
+
+	ret = i2c_master_send(client, data, length);
+	if (ret < 0) {
+		printk(KERN_ERR "SAA7191: saa7191_write_block(): "
+		       "write failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+/* Helper functions */
+
+static int saa7191_s_routing(struct v4l2_subdev *sd,
+			     u32 input, u32 output, u32 config)
+{
+	struct saa7191 *decoder = to_saa7191(sd);
+	u8 luma = saa7191_read_reg(sd, SAA7191_REG_LUMA);
+	u8 iock = saa7191_read_reg(sd, SAA7191_REG_IOCK);
+	int err;
+
+	switch (input) {
+	case SAA7191_INPUT_COMPOSITE: /* Set Composite input */
+		iock &= ~(SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW1
+			  | SAA7191_IOCK_GPSW2);
+		/* Chrominance trap active */
+		luma &= ~SAA7191_LUMA_BYPS;
+		break;
+	case SAA7191_INPUT_SVIDEO: /* Set S-Video input */
+		iock |= SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW2;
+		/* Chrominance trap bypassed */
+		luma |= SAA7191_LUMA_BYPS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	err = saa7191_write_reg(sd, SAA7191_REG_LUMA, luma);
+	if (err)
+		return -EIO;
+	err = saa7191_write_reg(sd, SAA7191_REG_IOCK, iock);
+	if (err)
+		return -EIO;
+
+	decoder->input = input;
+
+	return 0;
+}
+
+static int saa7191_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+	struct saa7191 *decoder = to_saa7191(sd);
+	u8 stdc = saa7191_read_reg(sd, SAA7191_REG_STDC);
+	u8 ctl3 = saa7191_read_reg(sd, SAA7191_REG_CTL3);
+	u8 chcv = saa7191_read_reg(sd, SAA7191_REG_CHCV);
+	int err;
+
+	if (norm & V4L2_STD_PAL) {
+		stdc &= ~SAA7191_STDC_SECS;
+		ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
+		chcv = SAA7191_CHCV_PAL;
+	} else if (norm & V4L2_STD_NTSC) {
+		stdc &= ~SAA7191_STDC_SECS;
+		ctl3 &= ~SAA7191_CTL3_AUFD;
+		ctl3 |= SAA7191_CTL3_FSEL;
+		chcv = SAA7191_CHCV_NTSC;
+	} else if (norm & V4L2_STD_SECAM) {
+		stdc |= SAA7191_STDC_SECS;
+		ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
+		chcv = SAA7191_CHCV_PAL;
+	} else {
+		return -EINVAL;
+	}
+
+	err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
+	if (err)
+		return -EIO;
+	err = saa7191_write_reg(sd, SAA7191_REG_STDC, stdc);
+	if (err)
+		return -EIO;
+	err = saa7191_write_reg(sd, SAA7191_REG_CHCV, chcv);
+	if (err)
+		return -EIO;
+
+	decoder->norm = norm;
+
+	dprintk("ctl3: %02x stdc: %02x chcv: %02x\n", ctl3,
+		stdc, chcv);
+	dprintk("norm: %llx\n", norm);
+
+	return 0;
+}
+
+static int saa7191_wait_for_signal(struct v4l2_subdev *sd, u8 *status)
+{
+	int i = 0;
+
+	dprintk("Checking for signal...\n");
+
+	for (i = 0; i < SAA7191_SYNC_COUNT; i++) {
+		if (saa7191_read_status(sd, status))
+			return -EIO;
+
+		if (((*status) & SAA7191_STATUS_HLCK) == 0) {
+			dprintk("Signal found\n");
+			return 0;
+		}
+
+		msleep(SAA7191_SYNC_DELAY);
+	}
+
+	dprintk("No signal\n");
+
+	return -EBUSY;
+}
+
+static int saa7191_querystd(struct v4l2_subdev *sd, v4l2_std_id *norm)
+{
+	struct saa7191 *decoder = to_saa7191(sd);
+	u8 stdc = saa7191_read_reg(sd, SAA7191_REG_STDC);
+	u8 ctl3 = saa7191_read_reg(sd, SAA7191_REG_CTL3);
+	u8 status;
+	v4l2_std_id old_norm = decoder->norm;
+	int err = 0;
+
+	dprintk("SAA7191 extended signal auto-detection...\n");
+
+	*norm = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
+	stdc &= ~SAA7191_STDC_SECS;
+	ctl3 &= ~(SAA7191_CTL3_FSEL);
+
+	err = saa7191_write_reg(sd, SAA7191_REG_STDC, stdc);
+	if (err) {
+		err = -EIO;
+		goto out;
+	}
+	err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
+	if (err) {
+		err = -EIO;
+		goto out;
+	}
+
+	ctl3 |= SAA7191_CTL3_AUFD;
+	err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
+	if (err) {
+		err = -EIO;
+		goto out;
+	}
+
+	msleep(SAA7191_SYNC_DELAY);
+
+	err = saa7191_wait_for_signal(sd, &status);
+	if (err)
+		goto out;
+
+	if (status & SAA7191_STATUS_FIDT) {
+		/* 60Hz signal -> NTSC */
+		dprintk("60Hz signal: NTSC\n");
+		*norm = V4L2_STD_NTSC;
+		return 0;
+	}
+
+	/* 50Hz signal */
+	dprintk("50Hz signal: Trying PAL...\n");
+
+	/* try PAL first */
+	err = saa7191_s_std(sd, V4L2_STD_PAL);
+	if (err)
+		goto out;
+
+	msleep(SAA7191_SYNC_DELAY);
+
+	err = saa7191_wait_for_signal(sd, &status);
+	if (err)
+		goto out;
+
+	/* not 50Hz ? */
+	if (status & SAA7191_STATUS_FIDT) {
+		dprintk("No 50Hz signal\n");
+		saa7191_s_std(sd, old_norm);
+		return -EAGAIN;
+	}
+
+	if (status & SAA7191_STATUS_CODE) {
+		dprintk("PAL\n");
+		*norm = V4L2_STD_PAL;
+		return saa7191_s_std(sd, old_norm);
+	}
+
+	dprintk("No color detected with PAL - Trying SECAM...\n");
+
+	/* no color detected ? -> try SECAM */
+	err = saa7191_s_std(sd, V4L2_STD_SECAM);
+	if (err)
+		goto out;
+
+	msleep(SAA7191_SYNC_DELAY);
+
+	err = saa7191_wait_for_signal(sd, &status);
+	if (err)
+		goto out;
+
+	/* not 50Hz ? */
+	if (status & SAA7191_STATUS_FIDT) {
+		dprintk("No 50Hz signal\n");
+		err = -EAGAIN;
+		goto out;
+	}
+
+	if (status & SAA7191_STATUS_CODE) {
+		/* Color detected -> SECAM */
+		dprintk("SECAM\n");
+		*norm = V4L2_STD_SECAM;
+		return saa7191_s_std(sd, old_norm);
+	}
+
+	dprintk("No color detected with SECAM - Going back to PAL.\n");
+
+out:
+	return saa7191_s_std(sd, old_norm);
+}
+
+static int saa7191_autodetect_norm(struct v4l2_subdev *sd)
+{
+	u8 status;
+
+	dprintk("SAA7191 signal auto-detection...\n");
+
+	dprintk("Reading status...\n");
+
+	if (saa7191_read_status(sd, &status))
+		return -EIO;
+
+	dprintk("Checking for signal...\n");
+
+	/* no signal ? */
+	if (status & SAA7191_STATUS_HLCK) {
+		dprintk("No signal\n");
+		return -EBUSY;
+	}
+
+	dprintk("Signal found\n");
+
+	if (status & SAA7191_STATUS_FIDT) {
+		/* 60hz signal -> NTSC */
+		dprintk("NTSC\n");
+		return saa7191_s_std(sd, V4L2_STD_NTSC);
+	} else {
+		/* 50hz signal -> PAL */
+		dprintk("PAL\n");
+		return saa7191_s_std(sd, V4L2_STD_PAL);
+	}
+}
+
+static int saa7191_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	u8 reg;
+	int ret = 0;
+
+	switch (ctrl->id) {
+	case SAA7191_CONTROL_BANDPASS:
+	case SAA7191_CONTROL_BANDPASS_WEIGHT:
+	case SAA7191_CONTROL_CORING:
+		reg = saa7191_read_reg(sd, SAA7191_REG_LUMA);
+		switch (ctrl->id) {
+		case SAA7191_CONTROL_BANDPASS:
+			ctrl->value = ((s32)reg & SAA7191_LUMA_BPSS_MASK)
+				>> SAA7191_LUMA_BPSS_SHIFT;
+			break;
+		case SAA7191_CONTROL_BANDPASS_WEIGHT:
+			ctrl->value = ((s32)reg & SAA7191_LUMA_APER_MASK)
+				>> SAA7191_LUMA_APER_SHIFT;
+			break;
+		case SAA7191_CONTROL_CORING:
+			ctrl->value = ((s32)reg & SAA7191_LUMA_CORI_MASK)
+				>> SAA7191_LUMA_CORI_SHIFT;
+			break;
+		}
+		break;
+	case SAA7191_CONTROL_FORCE_COLOUR:
+	case SAA7191_CONTROL_CHROMA_GAIN:
+		reg = saa7191_read_reg(sd, SAA7191_REG_GAIN);
+		if (ctrl->id == SAA7191_CONTROL_FORCE_COLOUR)
+			ctrl->value = ((s32)reg & SAA7191_GAIN_COLO) ? 1 : 0;
+		else
+			ctrl->value = ((s32)reg & SAA7191_GAIN_LFIS_MASK)
+				>> SAA7191_GAIN_LFIS_SHIFT;
+		break;
+	case V4L2_CID_HUE:
+		reg = saa7191_read_reg(sd, SAA7191_REG_HUEC);
+		if (reg < 0x80)
+			reg += 0x80;
+		else
+			reg -= 0x80;
+		ctrl->value = (s32)reg;
+		break;
+	case SAA7191_CONTROL_VTRC:
+		reg = saa7191_read_reg(sd, SAA7191_REG_STDC);
+		ctrl->value = ((s32)reg & SAA7191_STDC_VTRC) ? 1 : 0;
+		break;
+	case SAA7191_CONTROL_LUMA_DELAY:
+		reg = saa7191_read_reg(sd, SAA7191_REG_CTL3);
+		ctrl->value = ((s32)reg & SAA7191_CTL3_YDEL_MASK)
+			>> SAA7191_CTL3_YDEL_SHIFT;
+		if (ctrl->value >= 4)
+			ctrl->value -= 8;
+		break;
+	case SAA7191_CONTROL_VNR:
+		reg = saa7191_read_reg(sd, SAA7191_REG_CTL4);
+		ctrl->value = ((s32)reg & SAA7191_CTL4_VNOI_MASK)
+			>> SAA7191_CTL4_VNOI_SHIFT;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int saa7191_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	u8 reg;
+	int ret = 0;
+
+	switch (ctrl->id) {
+	case SAA7191_CONTROL_BANDPASS:
+	case SAA7191_CONTROL_BANDPASS_WEIGHT:
+	case SAA7191_CONTROL_CORING:
+		reg = saa7191_read_reg(sd, SAA7191_REG_LUMA);
+		switch (ctrl->id) {
+		case SAA7191_CONTROL_BANDPASS:
+			reg &= ~SAA7191_LUMA_BPSS_MASK;
+			reg |= (ctrl->value << SAA7191_LUMA_BPSS_SHIFT)
+				& SAA7191_LUMA_BPSS_MASK;
+			break;
+		case SAA7191_CONTROL_BANDPASS_WEIGHT:
+			reg &= ~SAA7191_LUMA_APER_MASK;
+			reg |= (ctrl->value << SAA7191_LUMA_APER_SHIFT)
+				& SAA7191_LUMA_APER_MASK;
+			break;
+		case SAA7191_CONTROL_CORING:
+			reg &= ~SAA7191_LUMA_CORI_MASK;
+			reg |= (ctrl->value << SAA7191_LUMA_CORI_SHIFT)
+				& SAA7191_LUMA_CORI_MASK;
+			break;
+		}
+		ret = saa7191_write_reg(sd, SAA7191_REG_LUMA, reg);
+		break;
+	case SAA7191_CONTROL_FORCE_COLOUR:
+	case SAA7191_CONTROL_CHROMA_GAIN:
+		reg = saa7191_read_reg(sd, SAA7191_REG_GAIN);
+		if (ctrl->id == SAA7191_CONTROL_FORCE_COLOUR) {
+			if (ctrl->value)
+				reg |= SAA7191_GAIN_COLO;
+			else
+				reg &= ~SAA7191_GAIN_COLO;
+		} else {
+			reg &= ~SAA7191_GAIN_LFIS_MASK;
+			reg |= (ctrl->value << SAA7191_GAIN_LFIS_SHIFT)
+				& SAA7191_GAIN_LFIS_MASK;
+		}
+		ret = saa7191_write_reg(sd, SAA7191_REG_GAIN, reg);
+		break;
+	case V4L2_CID_HUE:
+		reg = ctrl->value & 0xff;
+		if (reg < 0x80)
+			reg += 0x80;
+		else
+			reg -= 0x80;
+		ret = saa7191_write_reg(sd, SAA7191_REG_HUEC, reg);
+		break;
+	case SAA7191_CONTROL_VTRC:
+		reg = saa7191_read_reg(sd, SAA7191_REG_STDC);
+		if (ctrl->value)
+			reg |= SAA7191_STDC_VTRC;
+		else
+			reg &= ~SAA7191_STDC_VTRC;
+		ret = saa7191_write_reg(sd, SAA7191_REG_STDC, reg);
+		break;
+	case SAA7191_CONTROL_LUMA_DELAY: {
+		s32 value = ctrl->value;
+		if (value < 0)
+			value += 8;
+		reg = saa7191_read_reg(sd, SAA7191_REG_CTL3);
+		reg &= ~SAA7191_CTL3_YDEL_MASK;
+		reg |= (value << SAA7191_CTL3_YDEL_SHIFT)
+			& SAA7191_CTL3_YDEL_MASK;
+		ret = saa7191_write_reg(sd, SAA7191_REG_CTL3, reg);
+		break;
+	}
+	case SAA7191_CONTROL_VNR:
+		reg = saa7191_read_reg(sd, SAA7191_REG_CTL4);
+		reg &= ~SAA7191_CTL4_VNOI_MASK;
+		reg |= (ctrl->value << SAA7191_CTL4_VNOI_SHIFT)
+			& SAA7191_CTL4_VNOI_MASK;
+		ret = saa7191_write_reg(sd, SAA7191_REG_CTL4, reg);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/* I2C-interface */
+
+static int saa7191_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+	u8 status_reg;
+	int res = V4L2_IN_ST_NO_SIGNAL;
+
+	if (saa7191_read_status(sd, &status_reg))
+		return -EIO;
+	if ((status_reg & SAA7191_STATUS_HLCK) == 0)
+		res = 0;
+	if (!(status_reg & SAA7191_STATUS_CODE))
+		res |= V4L2_IN_ST_NO_COLOR;
+	*status = res;
+	return 0;
+}
+
+
+static int saa7191_g_chip_ident(struct v4l2_subdev *sd,
+		struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7191, 0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops saa7191_core_ops = {
+	.g_chip_ident = saa7191_g_chip_ident,
+	.g_ctrl = saa7191_g_ctrl,
+	.s_ctrl = saa7191_s_ctrl,
+	.s_std = saa7191_s_std,
+};
+
+static const struct v4l2_subdev_video_ops saa7191_video_ops = {
+	.s_routing = saa7191_s_routing,
+	.querystd = saa7191_querystd,
+	.g_input_status = saa7191_g_input_status,
+};
+
+static const struct v4l2_subdev_ops saa7191_ops = {
+	.core = &saa7191_core_ops,
+	.video = &saa7191_video_ops,
+};
+
+static int saa7191_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	int err = 0;
+	struct saa7191 *decoder;
+	struct v4l2_subdev *sd;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
+	if (!decoder)
+		return -ENOMEM;
+
+	sd = &decoder->sd;
+	v4l2_i2c_subdev_init(sd, client, &saa7191_ops);
+
+	err = saa7191_write_block(sd, sizeof(initseq), initseq);
+	if (err) {
+		printk(KERN_ERR "SAA7191 initialization failed\n");
+		kfree(decoder);
+		return err;
+	}
+
+	printk(KERN_INFO "SAA7191 initialized\n");
+
+	decoder->input = SAA7191_INPUT_COMPOSITE;
+	decoder->norm = V4L2_STD_PAL;
+
+	err = saa7191_autodetect_norm(sd);
+	if (err && (err != -EBUSY))
+		printk(KERN_ERR "SAA7191: Signal auto-detection failed\n");
+
+	return 0;
+}
+
+static int saa7191_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_saa7191(sd));
+	return 0;
+}
+
+static const struct i2c_device_id saa7191_id[] = {
+	{ "saa7191", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, saa7191_id);
+
+static struct i2c_driver saa7191_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "saa7191",
+	},
+	.probe		= saa7191_probe,
+	.remove		= saa7191_remove,
+	.id_table	= saa7191_id,
+};
+
+module_i2c_driver(saa7191_driver);
diff --git a/drivers/media/i2c/saa7191.h b/drivers/media/i2c/saa7191.h
new file mode 100644
index 0000000..803c74d
--- /dev/null
+++ b/drivers/media/i2c/saa7191.h
@@ -0,0 +1,245 @@
+/*
+ *  saa7191.h - Philips SAA7191 video decoder driver
+ *
+ *  Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ *  Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#ifndef _SAA7191_H_
+#define _SAA7191_H_
+
+/* Philips SAA7191 DMSD I2C bus address */
+#define SAA7191_ADDR		0x8a
+
+/* Register subaddresses. */
+#define SAA7191_REG_IDEL	0x00
+#define SAA7191_REG_HSYB	0x01
+#define SAA7191_REG_HSYS	0x02
+#define SAA7191_REG_HCLB	0x03
+#define SAA7191_REG_HCLS	0x04
+#define SAA7191_REG_HPHI	0x05
+#define SAA7191_REG_LUMA	0x06
+#define SAA7191_REG_HUEC	0x07
+#define SAA7191_REG_CKTQ	0x08 /* bits 3-7 */
+#define SAA7191_REG_CKTS	0x09 /* bits 3-7 */
+#define SAA7191_REG_PLSE	0x0a
+#define SAA7191_REG_SESE	0x0b
+#define SAA7191_REG_GAIN	0x0c
+#define SAA7191_REG_STDC	0x0d
+#define SAA7191_REG_IOCK	0x0e
+#define SAA7191_REG_CTL3	0x0f
+#define SAA7191_REG_CTL4	0x10
+#define SAA7191_REG_CHCV	0x11
+#define SAA7191_REG_HS6B	0x14
+#define SAA7191_REG_HS6S	0x15
+#define SAA7191_REG_HC6B	0x16
+#define SAA7191_REG_HC6S	0x17
+#define SAA7191_REG_HP6I	0x18
+#define SAA7191_REG_STATUS	0xff	/* not really a subaddress */
+
+/* Status Register definitions */
+#define SAA7191_STATUS_CODE	0x01	/* color detected flag */
+#define SAA7191_STATUS_FIDT	0x20	/* signal type 50/60 Hz */
+#define SAA7191_STATUS_HLCK	0x40	/* PLL unlocked(1)/locked(0) */
+#define SAA7191_STATUS_STTC	0x80	/* tv/vtr time constant */
+
+/* Luminance Control Register definitions */
+/* input mode select bit:
+ * 0=CVBS (chrominance trap active), 1=S-Video (trap bypassed) */
+#define SAA7191_LUMA_BYPS	0x80
+/* pre-filter (only when chrominance trap is active) */
+#define SAA7191_LUMA_PREF	0x40
+/* aperture bandpass to select different characteristics with maximums
+ * (bits 4-5) */
+#define SAA7191_LUMA_BPSS_MASK	0x30
+#define SAA7191_LUMA_BPSS_SHIFT	4
+#define SAA7191_LUMA_BPSS_3	0x30
+#define SAA7191_LUMA_BPSS_2	0x20
+#define SAA7191_LUMA_BPSS_1	0x10
+#define SAA7191_LUMA_BPSS_0	0x00
+/* coring range for high frequency components according to 8-bit luminance
+ * (bits 2-3)
+ * 0=coring off, n= (+-)n LSB */
+#define SAA7191_LUMA_CORI_MASK	0x0c
+#define SAA7191_LUMA_CORI_SHIFT	2
+#define SAA7191_LUMA_CORI_3	0x0c
+#define SAA7191_LUMA_CORI_2	0x08
+#define SAA7191_LUMA_CORI_1	0x04
+#define SAA7191_LUMA_CORI_0	0x00
+/* aperture bandpass filter weights high frequency components of luminance
+ * signal (bits 0-1)
+ * 0=factor 0, 1=0.25, 2=0.5, 3=1 */
+#define SAA7191_LUMA_APER_MASK	0x03
+#define SAA7191_LUMA_APER_SHIFT	0
+#define SAA7191_LUMA_APER_3	0x03
+#define SAA7191_LUMA_APER_2	0x02
+#define SAA7191_LUMA_APER_1	0x01
+#define SAA7191_LUMA_APER_0	0x00
+
+/* Chrominance Gain Control Settings Register definitions */
+/* colour on: 0=automatic colour-killer enabled, 1=forced colour on */
+#define SAA7191_GAIN_COLO	0x80
+/* chrominance gain control (AGC filter)
+ * 0=loop filter time constant slow, 1=medium, 2=fast, 3=actual gain */
+#define SAA7191_GAIN_LFIS_MASK	0x60
+#define SAA7191_GAIN_LFIS_SHIFT	5
+#define SAA7191_GAIN_LFIS_3	0x60
+#define SAA7191_GAIN_LFIS_2	0x40
+#define SAA7191_GAIN_LFIS_1	0x20
+#define SAA7191_GAIN_LFIS_0	0x00
+
+/* Standard/Mode Control Register definitions */
+/* tv/vtr mode bit: 0=TV mode (slow time constant),
+ * 1=VTR mode (fast time constant) */
+#define SAA7191_STDC_VTRC	0x80
+/* SAA7191B-specific functions enable (RTCO, ODD and GPSW0 outputs)
+ * 0=outputs set to high-impedance (circuit equals SAA7191), 1=enabled */
+#define SAA7191_STDC_NFEN	0x08
+/* HREF generation: 0=like SAA7191, 1=HREF is 8xLLC2 clocks earlier */
+#define SAA7191_STDC_HRMV	0x04
+/* general purpose switch 0
+ * (not used with VINO afaik) */
+#define SAA7191_STDC_GPSW0	0x02
+/* SECAM mode bit: 0=other standards, 1=SECAM */
+#define SAA7191_STDC_SECS	0x01
+
+/* I/O and Clock Control Register definitions */
+/* horizontal clock PLL: 0=PLL closed,
+ * 1=PLL circuit open and horizontal freq fixed */
+#define SAA7191_IOCK_HPLL	0x80
+/* colour-difference output enable (outputs UV0-UV7) */
+#define SAA7191_IOCK_OEDC	0x40
+/* H-sync output enable */
+#define SAA7191_IOCK_OEHS	0x20
+/* V-sync output enable */
+#define SAA7191_IOCK_OEVS	0x10
+/* luminance output enable (outputs Y0-Y7) */
+#define SAA7191_IOCK_OEDY	0x08
+/* S-VHS bit (chrominance from CVBS or from chrominance input):
+ * 0=controlled by BYPS-bit, 1=from chrominance input */
+#define SAA7191_IOCK_CHRS	0x04
+/* general purpose switch 2
+ * VINO-specific: 0=used with CVBS, 1=used with S-Video */
+#define SAA7191_IOCK_GPSW2	0x02
+/* general purpose switch 1 */
+/* VINO-specific: 0=always, 1=not used!*/
+#define SAA7191_IOCK_GPSW1	0x01
+
+/* Miscellaneous Control #1 Register definitions */
+/* automatic field detection (50/60Hz standard) */
+#define SAA7191_CTL3_AUFD	0x80
+/* field select: (if AUFD=0)
+ * 0=50Hz (625 lines), 1=60Hz (525 lines) */
+#define SAA7191_CTL3_FSEL	0x40
+/* SECAM cross-colour reduction enable */
+#define SAA7191_CTL3_SXCR	0x20
+/* sync and clamping pulse enable (HCL and HSY outputs) */
+#define SAA7191_CTL3_SCEN	0x10
+/* output format: 0=4:1:1, 1=4:2:2 (4:2:2 for VINO) */
+#define SAA7191_CTL3_OFTS	0x08
+/* luminance delay compensation
+ * 0=0*2/LLC,  1=+1*2/LLC, 2=+2*2/LLC, 3=+3*2/LLC,
+ * 4=-4*2/LLC, 5=-3*2/LLC, 6=-2*2/LLC, 7=-1*2/LLC
+ * step size = 2/LLC = 67.8ns for 50Hz, 81.5ns for 60Hz */
+#define SAA7191_CTL3_YDEL_MASK	0x07
+#define SAA7191_CTL3_YDEL_SHIFT	0
+#define SAA7191_CTL3_YDEL2	0x04
+#define SAA7191_CTL3_YDEL1	0x02
+#define SAA7191_CTL3_YDEL0	0x01
+
+/* Miscellaneous Control #2 Register definitions */
+/* select HREF position
+ * 0=normal, HREF is matched to YUV output port,
+ * 1=HREF is matched to CVBS input port */
+#define SAA7191_CTL4_HRFS	0x04
+/* vertical noise reduction
+ * 0=normal, 1=searching window, 2=auto-deflection, 3=reduction bypassed */
+#define SAA7191_CTL4_VNOI_MASK	0x03
+#define SAA7191_CTL4_VNOI_SHIFT	0
+#define SAA7191_CTL4_VNOI_3	0x03
+#define SAA7191_CTL4_VNOI_2	0x02
+#define SAA7191_CTL4_VNOI_1	0x01
+#define SAA7191_CTL4_VNOI_0	0x00
+
+/* Chrominance Gain Control Register definitions
+ * - for QAM-modulated input signals, effects output amplitude
+ * (SECAM gain fixed)
+ * (nominal values for UV CCIR level) */
+#define SAA7191_CHCV_NTSC	0x2c
+#define SAA7191_CHCV_PAL	0x59
+
+/* Driver interface definitions */
+#define SAA7191_INPUT_COMPOSITE	0
+#define SAA7191_INPUT_SVIDEO	1
+
+#define SAA7191_NORM_PAL	1
+#define SAA7191_NORM_NTSC	2
+#define SAA7191_NORM_SECAM	3
+
+struct saa7191_status {
+	/* 0=no signal, 1=signal detected */
+	int signal;
+	/* 0=50hz (pal) signal, 1=60hz (ntsc) signal */
+	int signal_60hz;
+	/* 0=no color detected, 1=color detected */
+	int color;
+
+	/* current SAA7191_INPUT_ */
+	int input;
+	/* current SAA7191_NORM_ */
+	int norm;
+};
+
+#define SAA7191_BANDPASS_MIN		0x00
+#define SAA7191_BANDPASS_MAX		0x03
+#define SAA7191_BANDPASS_DEFAULT	0x00
+
+#define SAA7191_BANDPASS_WEIGHT_MIN	0x00
+#define SAA7191_BANDPASS_WEIGHT_MAX	0x03
+#define SAA7191_BANDPASS_WEIGHT_DEFAULT	0x01
+
+#define SAA7191_CORING_MIN		0x00
+#define SAA7191_CORING_MAX		0x03
+#define SAA7191_CORING_DEFAULT		0x00
+
+#define SAA7191_HUE_MIN			0x00
+#define SAA7191_HUE_MAX			0xff
+#define SAA7191_HUE_DEFAULT		0x80
+
+#define SAA7191_VTRC_MIN		0x00
+#define SAA7191_VTRC_MAX		0x01
+#define SAA7191_VTRC_DEFAULT		0x00
+
+#define SAA7191_FORCE_COLOUR_MIN	0x00
+#define SAA7191_FORCE_COLOUR_MAX	0x01
+#define SAA7191_FORCE_COLOUR_DEFAULT	0x00
+
+#define SAA7191_CHROMA_GAIN_MIN		0x00
+#define SAA7191_CHROMA_GAIN_MAX		0x03
+#define SAA7191_CHROMA_GAIN_DEFAULT	0x00
+
+#define SAA7191_LUMA_DELAY_MIN		-0x04
+#define SAA7191_LUMA_DELAY_MAX		0x03
+#define SAA7191_LUMA_DELAY_DEFAULT	0x01
+
+#define SAA7191_VNR_MIN			0x00
+#define SAA7191_VNR_MAX			0x03
+#define SAA7191_VNR_DEFAULT		0x00
+
+#define SAA7191_CONTROL_BANDPASS	(V4L2_CID_PRIVATE_BASE + 0)
+#define SAA7191_CONTROL_BANDPASS_WEIGHT	(V4L2_CID_PRIVATE_BASE + 1)
+#define SAA7191_CONTROL_CORING		(V4L2_CID_PRIVATE_BASE + 2)
+#define SAA7191_CONTROL_FORCE_COLOUR	(V4L2_CID_PRIVATE_BASE + 3)
+#define SAA7191_CONTROL_CHROMA_GAIN	(V4L2_CID_PRIVATE_BASE + 4)
+#define SAA7191_CONTROL_VTRC		(V4L2_CID_PRIVATE_BASE + 5)
+#define SAA7191_CONTROL_LUMA_DELAY	(V4L2_CID_PRIVATE_BASE + 6)
+#define SAA7191_CONTROL_VNR		(V4L2_CID_PRIVATE_BASE + 7)
+
+#define	DECODER_SAA7191_GET_STATUS	_IOR('d', 195, struct saa7191_status)
+#define	DECODER_SAA7191_SET_NORM	_IOW('d', 196, int)
+
+#endif
diff --git a/drivers/media/i2c/smiapp-pll.c b/drivers/media/i2c/smiapp-pll.c
new file mode 100644
index 0000000..a577614
--- /dev/null
+++ b/drivers/media/i2c/smiapp-pll.c
@@ -0,0 +1,418 @@
+/*
+ * drivers/media/i2c/smiapp-pll.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/gcd.h>
+#include <linux/lcm.h>
+#include <linux/module.h>
+
+#include "smiapp-pll.h"
+
+/* Return an even number or one. */
+static inline uint32_t clk_div_even(uint32_t a)
+{
+	return max_t(uint32_t, 1, a & ~1);
+}
+
+/* Return an even number or one. */
+static inline uint32_t clk_div_even_up(uint32_t a)
+{
+	if (a == 1)
+		return 1;
+	return (a + 1) & ~1;
+}
+
+static inline uint32_t is_one_or_even(uint32_t a)
+{
+	if (a == 1)
+		return 1;
+	if (a & 1)
+		return 0;
+
+	return 1;
+}
+
+static int bounds_check(struct device *dev, uint32_t val,
+			uint32_t min, uint32_t max, char *str)
+{
+	if (val >= min && val <= max)
+		return 0;
+
+	dev_warn(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max);
+
+	return -EINVAL;
+}
+
+static void print_pll(struct device *dev, struct smiapp_pll *pll)
+{
+	dev_dbg(dev, "pre_pll_clk_div\t%d\n",  pll->pre_pll_clk_div);
+	dev_dbg(dev, "pll_multiplier \t%d\n",  pll->pll_multiplier);
+	if (pll->flags != SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
+		dev_dbg(dev, "op_sys_clk_div \t%d\n", pll->op_sys_clk_div);
+		dev_dbg(dev, "op_pix_clk_div \t%d\n", pll->op_pix_clk_div);
+	}
+	dev_dbg(dev, "vt_sys_clk_div \t%d\n",  pll->vt_sys_clk_div);
+	dev_dbg(dev, "vt_pix_clk_div \t%d\n",  pll->vt_pix_clk_div);
+
+	dev_dbg(dev, "ext_clk_freq_hz \t%d\n", pll->ext_clk_freq_hz);
+	dev_dbg(dev, "pll_ip_clk_freq_hz \t%d\n", pll->pll_ip_clk_freq_hz);
+	dev_dbg(dev, "pll_op_clk_freq_hz \t%d\n", pll->pll_op_clk_freq_hz);
+	if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
+		dev_dbg(dev, "op_sys_clk_freq_hz \t%d\n",
+			pll->op_sys_clk_freq_hz);
+		dev_dbg(dev, "op_pix_clk_freq_hz \t%d\n",
+			pll->op_pix_clk_freq_hz);
+	}
+	dev_dbg(dev, "vt_sys_clk_freq_hz \t%d\n", pll->vt_sys_clk_freq_hz);
+	dev_dbg(dev, "vt_pix_clk_freq_hz \t%d\n", pll->vt_pix_clk_freq_hz);
+}
+
+int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits,
+			 struct smiapp_pll *pll)
+{
+	uint32_t sys_div;
+	uint32_t best_pix_div = INT_MAX >> 1;
+	uint32_t vt_op_binning_div;
+	uint32_t lane_op_clock_ratio;
+	uint32_t mul, div;
+	uint32_t more_mul_min, more_mul_max;
+	uint32_t more_mul_factor;
+	uint32_t min_vt_div, max_vt_div, vt_div;
+	uint32_t min_sys_div, max_sys_div;
+	unsigned int i;
+	int rval;
+
+	if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE)
+		lane_op_clock_ratio = pll->lanes;
+	else
+		lane_op_clock_ratio = 1;
+	dev_dbg(dev, "lane_op_clock_ratio: %d\n", lane_op_clock_ratio);
+
+	dev_dbg(dev, "binning: %dx%d\n", pll->binning_horizontal,
+		pll->binning_vertical);
+
+	/* CSI transfers 2 bits per clock per lane; thus times 2 */
+	pll->pll_op_clk_freq_hz = pll->link_freq * 2
+		* (pll->lanes / lane_op_clock_ratio);
+
+	/* Figure out limits for pre-pll divider based on extclk */
+	dev_dbg(dev, "min / max pre_pll_clk_div: %d / %d\n",
+		limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
+	limits->max_pre_pll_clk_div =
+		min_t(uint16_t, limits->max_pre_pll_clk_div,
+		      clk_div_even(pll->ext_clk_freq_hz /
+				   limits->min_pll_ip_freq_hz));
+	limits->min_pre_pll_clk_div =
+		max_t(uint16_t, limits->min_pre_pll_clk_div,
+		      clk_div_even_up(
+			      DIV_ROUND_UP(pll->ext_clk_freq_hz,
+					   limits->max_pll_ip_freq_hz)));
+	dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %d / %d\n",
+		limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
+
+	i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz);
+	mul = div_u64(pll->pll_op_clk_freq_hz, i);
+	div = pll->ext_clk_freq_hz / i;
+	dev_dbg(dev, "mul %d / div %d\n", mul, div);
+
+	limits->min_pre_pll_clk_div =
+		max_t(uint16_t, limits->min_pre_pll_clk_div,
+		      clk_div_even_up(
+			      DIV_ROUND_UP(mul * pll->ext_clk_freq_hz,
+					   limits->max_pll_op_freq_hz)));
+	dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %d / %d\n",
+		limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
+
+	if (limits->min_pre_pll_clk_div > limits->max_pre_pll_clk_div) {
+		dev_err(dev, "unable to compute pre_pll divisor\n");
+		return -EINVAL;
+	}
+
+	pll->pre_pll_clk_div = limits->min_pre_pll_clk_div;
+
+	/*
+	 * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be
+	 * too high.
+	 */
+	dev_dbg(dev, "pre_pll_clk_div %d\n", pll->pre_pll_clk_div);
+
+	/* Don't go above max pll multiplier. */
+	more_mul_max = limits->max_pll_multiplier / mul;
+	dev_dbg(dev, "more_mul_max: max_pll_multiplier check: %d\n",
+		more_mul_max);
+	/* Don't go above max pll op frequency. */
+	more_mul_max =
+		min_t(int,
+		      more_mul_max,
+		      limits->max_pll_op_freq_hz
+		      / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul));
+	dev_dbg(dev, "more_mul_max: max_pll_op_freq_hz check: %d\n",
+		more_mul_max);
+	/* Don't go above the division capability of op sys clock divider. */
+	more_mul_max = min(more_mul_max,
+			   limits->max_op_sys_clk_div * pll->pre_pll_clk_div
+			   / div);
+	dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %d\n",
+		more_mul_max);
+	/* Ensure we won't go above min_pll_multiplier. */
+	more_mul_max = min(more_mul_max,
+			   DIV_ROUND_UP(limits->max_pll_multiplier, mul));
+	dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %d\n",
+		more_mul_max);
+
+	/* Ensure we won't go below min_pll_op_freq_hz. */
+	more_mul_min = DIV_ROUND_UP(limits->min_pll_op_freq_hz,
+				    pll->ext_clk_freq_hz / pll->pre_pll_clk_div
+				    * mul);
+	dev_dbg(dev, "more_mul_min: min_pll_op_freq_hz check: %d\n",
+		more_mul_min);
+	/* Ensure we won't go below min_pll_multiplier. */
+	more_mul_min = max(more_mul_min,
+			   DIV_ROUND_UP(limits->min_pll_multiplier, mul));
+	dev_dbg(dev, "more_mul_min: min_pll_multiplier check: %d\n",
+		more_mul_min);
+
+	if (more_mul_min > more_mul_max) {
+		dev_warn(dev,
+			 "unable to compute more_mul_min and more_mul_max");
+		return -EINVAL;
+	}
+
+	more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div;
+	dev_dbg(dev, "more_mul_factor: %d\n", more_mul_factor);
+	more_mul_factor = lcm(more_mul_factor, limits->min_op_sys_clk_div);
+	dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n",
+		more_mul_factor);
+	i = roundup(more_mul_min, more_mul_factor);
+	if (!is_one_or_even(i))
+		i <<= 1;
+
+	dev_dbg(dev, "final more_mul: %d\n", i);
+	if (i > more_mul_max) {
+		dev_warn(dev, "final more_mul is bad, max %d", more_mul_max);
+		return -EINVAL;
+	}
+
+	pll->pll_multiplier = mul * i;
+	pll->op_sys_clk_div = div * i / pll->pre_pll_clk_div;
+	dev_dbg(dev, "op_sys_clk_div: %d\n", pll->op_sys_clk_div);
+
+	pll->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz
+		/ pll->pre_pll_clk_div;
+
+	pll->pll_op_clk_freq_hz = pll->pll_ip_clk_freq_hz
+		* pll->pll_multiplier;
+
+	/* Derive pll_op_clk_freq_hz. */
+	pll->op_sys_clk_freq_hz =
+		pll->pll_op_clk_freq_hz / pll->op_sys_clk_div;
+
+	pll->op_pix_clk_div = pll->bits_per_pixel;
+	dev_dbg(dev, "op_pix_clk_div: %d\n", pll->op_pix_clk_div);
+
+	pll->op_pix_clk_freq_hz =
+		pll->op_sys_clk_freq_hz / pll->op_pix_clk_div;
+
+	/*
+	 * Some sensors perform analogue binning and some do this
+	 * digitally. The ones doing this digitally can be roughly be
+	 * found out using this formula. The ones doing this digitally
+	 * should run at higher clock rate, so smaller divisor is used
+	 * on video timing side.
+	 */
+	if (limits->min_line_length_pck_bin > limits->min_line_length_pck
+	    / pll->binning_horizontal)
+		vt_op_binning_div = pll->binning_horizontal;
+	else
+		vt_op_binning_div = 1;
+	dev_dbg(dev, "vt_op_binning_div: %d\n", vt_op_binning_div);
+
+	/*
+	 * Profile 2 supports vt_pix_clk_div E [4, 10]
+	 *
+	 * Horizontal binning can be used as a base for difference in
+	 * divisors. One must make sure that horizontal blanking is
+	 * enough to accommodate the CSI-2 sync codes.
+	 *
+	 * Take scaling factor into account as well.
+	 *
+	 * Find absolute limits for the factor of vt divider.
+	 */
+	dev_dbg(dev, "scale_m: %d\n", pll->scale_m);
+	min_vt_div = DIV_ROUND_UP(pll->op_pix_clk_div * pll->op_sys_clk_div
+				  * pll->scale_n,
+				  lane_op_clock_ratio * vt_op_binning_div
+				  * pll->scale_m);
+
+	/* Find smallest and biggest allowed vt divisor. */
+	dev_dbg(dev, "min_vt_div: %d\n", min_vt_div);
+	min_vt_div = max(min_vt_div,
+			 DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
+				      limits->max_vt_pix_clk_freq_hz));
+	dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %d\n",
+		min_vt_div);
+	min_vt_div = max_t(uint32_t, min_vt_div,
+			   limits->min_vt_pix_clk_div
+			   * limits->min_vt_sys_clk_div);
+	dev_dbg(dev, "min_vt_div: min_vt_clk_div: %d\n", min_vt_div);
+
+	max_vt_div = limits->max_vt_sys_clk_div * limits->max_vt_pix_clk_div;
+	dev_dbg(dev, "max_vt_div: %d\n", max_vt_div);
+	max_vt_div = min(max_vt_div,
+			 DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
+				      limits->min_vt_pix_clk_freq_hz));
+	dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %d\n",
+		max_vt_div);
+
+	/*
+	 * Find limitsits for sys_clk_div. Not all values are possible
+	 * with all values of pix_clk_div.
+	 */
+	min_sys_div = limits->min_vt_sys_clk_div;
+	dev_dbg(dev, "min_sys_div: %d\n", min_sys_div);
+	min_sys_div = max(min_sys_div,
+			  DIV_ROUND_UP(min_vt_div,
+				       limits->max_vt_pix_clk_div));
+	dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %d\n", min_sys_div);
+	min_sys_div = max(min_sys_div,
+			  pll->pll_op_clk_freq_hz
+			  / limits->max_vt_sys_clk_freq_hz);
+	dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %d\n", min_sys_div);
+	min_sys_div = clk_div_even_up(min_sys_div);
+	dev_dbg(dev, "min_sys_div: one or even: %d\n", min_sys_div);
+
+	max_sys_div = limits->max_vt_sys_clk_div;
+	dev_dbg(dev, "max_sys_div: %d\n", max_sys_div);
+	max_sys_div = min(max_sys_div,
+			  DIV_ROUND_UP(max_vt_div,
+				       limits->min_vt_pix_clk_div));
+	dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %d\n", max_sys_div);
+	max_sys_div = min(max_sys_div,
+			  DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
+				       limits->min_vt_pix_clk_freq_hz));
+	dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %d\n", max_sys_div);
+
+	/*
+	 * Find pix_div such that a legal pix_div * sys_div results
+	 * into a value which is not smaller than div, the desired
+	 * divisor.
+	 */
+	for (vt_div = min_vt_div; vt_div <= max_vt_div;
+	     vt_div += 2 - (vt_div & 1)) {
+		for (sys_div = min_sys_div;
+		     sys_div <= max_sys_div;
+		     sys_div += 2 - (sys_div & 1)) {
+			int pix_div = DIV_ROUND_UP(vt_div, sys_div);
+
+			if (pix_div < limits->min_vt_pix_clk_div
+			    || pix_div > limits->max_vt_pix_clk_div) {
+				dev_dbg(dev,
+					"pix_div %d too small or too big (%d--%d)\n",
+					pix_div,
+					limits->min_vt_pix_clk_div,
+					limits->max_vt_pix_clk_div);
+				continue;
+			}
+
+			/* Check if this one is better. */
+			if (pix_div * sys_div
+			    <= roundup(min_vt_div, best_pix_div))
+				best_pix_div = pix_div;
+		}
+		if (best_pix_div < INT_MAX >> 1)
+			break;
+	}
+
+	pll->vt_sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div);
+	pll->vt_pix_clk_div = best_pix_div;
+
+	pll->vt_sys_clk_freq_hz =
+		pll->pll_op_clk_freq_hz / pll->vt_sys_clk_div;
+	pll->vt_pix_clk_freq_hz =
+		pll->vt_sys_clk_freq_hz / pll->vt_pix_clk_div;
+
+	pll->pixel_rate_csi =
+		pll->op_pix_clk_freq_hz * lane_op_clock_ratio;
+
+	print_pll(dev, pll);
+
+	rval = bounds_check(dev, pll->pre_pll_clk_div,
+			    limits->min_pre_pll_clk_div,
+			    limits->max_pre_pll_clk_div, "pre_pll_clk_div");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->pll_ip_clk_freq_hz,
+			limits->min_pll_ip_freq_hz, limits->max_pll_ip_freq_hz,
+			"pll_ip_clk_freq_hz");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->pll_multiplier,
+			limits->min_pll_multiplier, limits->max_pll_multiplier,
+			"pll_multiplier");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->pll_op_clk_freq_hz,
+			limits->min_pll_op_freq_hz, limits->max_pll_op_freq_hz,
+			"pll_op_clk_freq_hz");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->op_sys_clk_div,
+			limits->min_op_sys_clk_div, limits->max_op_sys_clk_div,
+			"op_sys_clk_div");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->op_pix_clk_div,
+			limits->min_op_pix_clk_div, limits->max_op_pix_clk_div,
+			"op_pix_clk_div");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->op_sys_clk_freq_hz,
+			limits->min_op_sys_clk_freq_hz,
+			limits->max_op_sys_clk_freq_hz,
+			"op_sys_clk_freq_hz");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->op_pix_clk_freq_hz,
+			limits->min_op_pix_clk_freq_hz,
+			limits->max_op_pix_clk_freq_hz,
+			"op_pix_clk_freq_hz");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->vt_sys_clk_freq_hz,
+			limits->min_vt_sys_clk_freq_hz,
+			limits->max_vt_sys_clk_freq_hz,
+			"vt_sys_clk_freq_hz");
+	if (!rval)
+		rval = bounds_check(
+			dev, pll->vt_pix_clk_freq_hz,
+			limits->min_vt_pix_clk_freq_hz,
+			limits->max_vt_pix_clk_freq_hz,
+			"vt_pix_clk_freq_hz");
+
+	return rval;
+}
+EXPORT_SYMBOL_GPL(smiapp_pll_calculate);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>");
+MODULE_DESCRIPTION("Generic SMIA/SMIA++ PLL calculator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/smiapp-pll.h b/drivers/media/i2c/smiapp-pll.h
new file mode 100644
index 0000000..cb2d2db
--- /dev/null
+++ b/drivers/media/i2c/smiapp-pll.h
@@ -0,0 +1,103 @@
+/*
+ * drivers/media/i2c/smiapp-pll.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SMIAPP_PLL_H
+#define SMIAPP_PLL_H
+
+#include <linux/device.h>
+
+struct smiapp_pll {
+	uint8_t lanes;
+	uint8_t binning_horizontal;
+	uint8_t binning_vertical;
+	uint8_t scale_m;
+	uint8_t scale_n;
+	uint8_t bits_per_pixel;
+	uint16_t flags;
+	uint32_t link_freq;
+
+	uint16_t pre_pll_clk_div;
+	uint16_t pll_multiplier;
+	uint16_t op_sys_clk_div;
+	uint16_t op_pix_clk_div;
+	uint16_t vt_sys_clk_div;
+	uint16_t vt_pix_clk_div;
+
+	uint32_t ext_clk_freq_hz;
+	uint32_t pll_ip_clk_freq_hz;
+	uint32_t pll_op_clk_freq_hz;
+	uint32_t op_sys_clk_freq_hz;
+	uint32_t op_pix_clk_freq_hz;
+	uint32_t vt_sys_clk_freq_hz;
+	uint32_t vt_pix_clk_freq_hz;
+
+	uint32_t pixel_rate_csi;
+};
+
+struct smiapp_pll_limits {
+	/* Strict PLL limits */
+	uint32_t min_ext_clk_freq_hz;
+	uint32_t max_ext_clk_freq_hz;
+	uint16_t min_pre_pll_clk_div;
+	uint16_t max_pre_pll_clk_div;
+	uint32_t min_pll_ip_freq_hz;
+	uint32_t max_pll_ip_freq_hz;
+	uint16_t min_pll_multiplier;
+	uint16_t max_pll_multiplier;
+	uint32_t min_pll_op_freq_hz;
+	uint32_t max_pll_op_freq_hz;
+
+	uint16_t min_vt_sys_clk_div;
+	uint16_t max_vt_sys_clk_div;
+	uint32_t min_vt_sys_clk_freq_hz;
+	uint32_t max_vt_sys_clk_freq_hz;
+	uint16_t min_vt_pix_clk_div;
+	uint16_t max_vt_pix_clk_div;
+	uint32_t min_vt_pix_clk_freq_hz;
+	uint32_t max_vt_pix_clk_freq_hz;
+
+	uint16_t min_op_sys_clk_div;
+	uint16_t max_op_sys_clk_div;
+	uint32_t min_op_sys_clk_freq_hz;
+	uint32_t max_op_sys_clk_freq_hz;
+	uint16_t min_op_pix_clk_div;
+	uint16_t max_op_pix_clk_div;
+	uint32_t min_op_pix_clk_freq_hz;
+	uint32_t max_op_pix_clk_freq_hz;
+
+	/* Other relevant limits */
+	uint32_t min_line_length_pck_bin;
+	uint32_t min_line_length_pck;
+};
+
+/* op pix clock is for all lanes in total normally */
+#define SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE			(1 << 0)
+#define SMIAPP_PLL_FLAG_NO_OP_CLOCKS				(1 << 1)
+
+struct device;
+
+int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits,
+			 struct smiapp_pll *pll);
+
+#endif /* SMIAPP_PLL_H */
diff --git a/drivers/media/i2c/smiapp/Kconfig b/drivers/media/i2c/smiapp/Kconfig
new file mode 100644
index 0000000..3149cda
--- /dev/null
+++ b/drivers/media/i2c/smiapp/Kconfig
@@ -0,0 +1,7 @@
+config VIDEO_SMIAPP
+	tristate "SMIA++/SMIA sensor support"
+	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAVE_CLK
+	depends on MEDIA_CAMERA_SUPPORT
+	select VIDEO_SMIAPP_PLL
+	---help---
+	  This is a generic driver for SMIA++/SMIA camera modules.
diff --git a/drivers/media/i2c/smiapp/Makefile b/drivers/media/i2c/smiapp/Makefile
new file mode 100644
index 0000000..f45a003
--- /dev/null
+++ b/drivers/media/i2c/smiapp/Makefile
@@ -0,0 +1,5 @@
+smiapp-objs			+= smiapp-core.o smiapp-regs.o \
+				   smiapp-quirk.o smiapp-limits.o
+obj-$(CONFIG_VIDEO_SMIAPP)	+= smiapp.o
+
+ccflags-y += -Idrivers/media/i2c
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
new file mode 100644
index 0000000..1cf914d
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -0,0 +1,2895 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp-core.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2010--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * Based on smiapp driver by Vimarsh Zutshi
+ * Based on jt8ev1.c by Vimarsh Zutshi
+ * Based on smia-sensor.c by Tuukka Toivonen <tuukkat76@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-device.h>
+
+#include "smiapp.h"
+
+#define SMIAPP_ALIGN_DIM(dim, flags)	\
+	((flags) & V4L2_SEL_FLAG_GE	\
+	 ? ALIGN((dim), 2)		\
+	 : (dim) & ~1)
+
+/*
+ * smiapp_module_idents - supported camera modules
+ */
+static const struct smiapp_module_ident smiapp_module_idents[] = {
+	SMIAPP_IDENT_L(0x01, 0x022b, -1, "vs6555"),
+	SMIAPP_IDENT_L(0x01, 0x022e, -1, "vw6558"),
+	SMIAPP_IDENT_L(0x07, 0x7698, -1, "ovm7698"),
+	SMIAPP_IDENT_L(0x0b, 0x4242, -1, "smiapp-003"),
+	SMIAPP_IDENT_L(0x0c, 0x208a, -1, "tcm8330md"),
+	SMIAPP_IDENT_LQ(0x0c, 0x2134, -1, "tcm8500md", &smiapp_tcm8500md_quirk),
+	SMIAPP_IDENT_L(0x0c, 0x213e, -1, "et8en2"),
+	SMIAPP_IDENT_L(0x0c, 0x2184, -1, "tcm8580md"),
+	SMIAPP_IDENT_LQ(0x0c, 0x560f, -1, "jt8ew9", &smiapp_jt8ew9_quirk),
+	SMIAPP_IDENT_LQ(0x10, 0x4141, -1, "jt8ev1", &smiapp_jt8ev1_quirk),
+	SMIAPP_IDENT_LQ(0x10, 0x4241, -1, "imx125es", &smiapp_imx125es_quirk),
+};
+
+/*
+ *
+ * Dynamic Capability Identification
+ *
+ */
+
+static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	u32 fmt_model_type, fmt_model_subtype, ncol_desc, nrow_desc;
+	unsigned int i;
+	int rval;
+	int line_count = 0;
+	int embedded_start = -1, embedded_end = -1;
+	int image_start = 0;
+
+	rval = smiapp_read(sensor, SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE,
+			   &fmt_model_type);
+	if (rval)
+		return rval;
+
+	rval = smiapp_read(sensor, SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE,
+			   &fmt_model_subtype);
+	if (rval)
+		return rval;
+
+	ncol_desc = (fmt_model_subtype
+		     & SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK)
+		>> SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT;
+	nrow_desc = fmt_model_subtype
+		& SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK;
+
+	dev_dbg(&client->dev, "format_model_type %s\n",
+		fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE
+		? "2 byte" :
+		fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE
+		? "4 byte" : "is simply bad");
+
+	for (i = 0; i < ncol_desc + nrow_desc; i++) {
+		u32 desc;
+		u32 pixelcode;
+		u32 pixels;
+		char *which;
+		char *what;
+
+		if (fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE) {
+			rval = smiapp_read(
+				sensor,
+				SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(i),
+				&desc);
+			if (rval)
+				return rval;
+
+			pixelcode =
+				(desc
+				 & SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK)
+				>> SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT;
+			pixels = desc & SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK;
+		} else if (fmt_model_type
+			   == SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE) {
+			rval = smiapp_read(
+				sensor,
+				SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(i),
+				&desc);
+			if (rval)
+				return rval;
+
+			pixelcode =
+				(desc
+				 & SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK)
+				>> SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT;
+			pixels = desc & SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK;
+		} else {
+			dev_dbg(&client->dev,
+				"invalid frame format model type %d\n",
+				fmt_model_type);
+			return -EINVAL;
+		}
+
+		if (i < ncol_desc)
+			which = "columns";
+		else
+			which = "rows";
+
+		switch (pixelcode) {
+		case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED:
+			what = "embedded";
+			break;
+		case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY:
+			what = "dummy";
+			break;
+		case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK:
+			what = "black";
+			break;
+		case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK:
+			what = "dark";
+			break;
+		case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE:
+			what = "visible";
+			break;
+		default:
+			what = "invalid";
+			dev_dbg(&client->dev, "pixelcode %d\n", pixelcode);
+			break;
+		}
+
+		dev_dbg(&client->dev, "%s pixels: %d %s\n",
+			what, pixels, which);
+
+		if (i < ncol_desc)
+			continue;
+
+		/* Handle row descriptors */
+		if (pixelcode
+		    == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED) {
+			embedded_start = line_count;
+		} else {
+			if (pixelcode == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE
+			    || pixels >= sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES] / 2)
+				image_start = line_count;
+			if (embedded_start != -1 && embedded_end == -1)
+				embedded_end = line_count;
+		}
+		line_count += pixels;
+	}
+
+	if (embedded_start == -1 || embedded_end == -1) {
+		embedded_start = 0;
+		embedded_end = 0;
+	}
+
+	dev_dbg(&client->dev, "embedded data from lines %d to %d\n",
+		embedded_start, embedded_end);
+	dev_dbg(&client->dev, "image data starts at line %d\n", image_start);
+
+	return 0;
+}
+
+static int smiapp_pll_configure(struct smiapp_sensor *sensor)
+{
+	struct smiapp_pll *pll = &sensor->pll;
+	int rval;
+
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_VT_PIX_CLK_DIV, pll->vt_pix_clk_div);
+	if (rval < 0)
+		return rval;
+
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_VT_SYS_CLK_DIV, pll->vt_sys_clk_div);
+	if (rval < 0)
+		return rval;
+
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_PRE_PLL_CLK_DIV, pll->pre_pll_clk_div);
+	if (rval < 0)
+		return rval;
+
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_PLL_MULTIPLIER, pll->pll_multiplier);
+	if (rval < 0)
+		return rval;
+
+	/* Lane op clock ratio does not apply here. */
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS,
+		DIV_ROUND_UP(pll->op_sys_clk_freq_hz, 1000000 / 256 / 256));
+	if (rval < 0 || sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
+		return rval;
+
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_OP_PIX_CLK_DIV, pll->op_pix_clk_div);
+	if (rval < 0)
+		return rval;
+
+	return smiapp_write(
+		sensor, SMIAPP_REG_U16_OP_SYS_CLK_DIV, pll->op_sys_clk_div);
+}
+
+static int smiapp_pll_update(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	struct smiapp_pll_limits lim = {
+		.min_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV],
+		.max_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV],
+		.min_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ],
+		.max_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ],
+		.min_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MIN_PLL_MULTIPLIER],
+		.max_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MAX_PLL_MULTIPLIER],
+		.min_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ],
+		.max_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ],
+
+		.min_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV],
+		.max_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV],
+		.min_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV],
+		.max_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV],
+		.min_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ],
+		.max_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ],
+		.min_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ],
+		.max_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ],
+
+		.min_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV],
+		.max_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV],
+		.min_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV],
+		.max_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV],
+		.min_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ],
+		.max_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ],
+		.min_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ],
+		.max_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ],
+
+		.min_line_length_pck_bin = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN],
+		.min_line_length_pck = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK],
+	};
+	struct smiapp_pll *pll = &sensor->pll;
+	int rval;
+
+	memset(&sensor->pll, 0, sizeof(sensor->pll));
+
+	pll->lanes = sensor->platform_data->lanes;
+	pll->ext_clk_freq_hz = sensor->platform_data->ext_clk;
+
+	if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) {
+		/*
+		 * Fill in operational clock divisors limits from the
+		 * video timing ones. On profile 0 sensors the
+		 * requirements regarding them are essentially the
+		 * same as on VT ones.
+		 */
+		lim.min_op_sys_clk_div = lim.min_vt_sys_clk_div;
+		lim.max_op_sys_clk_div = lim.max_vt_sys_clk_div;
+		lim.min_op_pix_clk_div = lim.min_vt_pix_clk_div;
+		lim.max_op_pix_clk_div = lim.max_vt_pix_clk_div;
+		lim.min_op_sys_clk_freq_hz = lim.min_vt_sys_clk_freq_hz;
+		lim.max_op_sys_clk_freq_hz = lim.max_vt_sys_clk_freq_hz;
+		lim.min_op_pix_clk_freq_hz = lim.min_vt_pix_clk_freq_hz;
+		lim.max_op_pix_clk_freq_hz = lim.max_vt_pix_clk_freq_hz;
+		/* Profile 0 sensors have no separate OP clock branch. */
+		pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS;
+	}
+
+	if (smiapp_needs_quirk(sensor,
+			       SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE))
+		pll->flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE;
+
+	pll->binning_horizontal = sensor->binning_horizontal;
+	pll->binning_vertical = sensor->binning_vertical;
+	pll->link_freq =
+		sensor->link_freq->qmenu_int[sensor->link_freq->val];
+	pll->scale_m = sensor->scale_m;
+	pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+	pll->bits_per_pixel = sensor->csi_format->compressed;
+
+	rval = smiapp_pll_calculate(&client->dev, &lim, pll);
+	if (rval < 0)
+		return rval;
+
+	sensor->pixel_rate_parray->cur.val64 = pll->vt_pix_clk_freq_hz;
+	sensor->pixel_rate_csi->cur.val64 = pll->pixel_rate_csi;
+
+	return 0;
+}
+
+
+/*
+ *
+ * V4L2 Controls handling
+ *
+ */
+
+static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor)
+{
+	struct v4l2_ctrl *ctrl = sensor->exposure;
+	int max;
+
+	max = sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
+		+ sensor->vblank->val
+		- sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN];
+
+	ctrl->maximum = max;
+	if (ctrl->default_value > max)
+		ctrl->default_value = max;
+	if (ctrl->val > max)
+		ctrl->val = max;
+	if (ctrl->cur.val > max)
+		ctrl->cur.val = max;
+}
+
+/*
+ * Order matters.
+ *
+ * 1. Bits-per-pixel, descending.
+ * 2. Bits-per-pixel compressed, descending.
+ * 3. Pixel order, same as in pixel_order_str. Formats for all four pixel
+ *    orders must be defined.
+ */
+static const struct smiapp_csi_data_format smiapp_csi_data_formats[] = {
+	{ V4L2_MBUS_FMT_SGRBG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GRBG, },
+	{ V4L2_MBUS_FMT_SRGGB12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_RGGB, },
+	{ V4L2_MBUS_FMT_SBGGR12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_BGGR, },
+	{ V4L2_MBUS_FMT_SGBRG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GBRG, },
+	{ V4L2_MBUS_FMT_SGRBG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GRBG, },
+	{ V4L2_MBUS_FMT_SRGGB10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_RGGB, },
+	{ V4L2_MBUS_FMT_SBGGR10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_BGGR, },
+	{ V4L2_MBUS_FMT_SGBRG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GBRG, },
+	{ V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GRBG, },
+	{ V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_RGGB, },
+	{ V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_BGGR, },
+	{ V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GBRG, },
+	{ V4L2_MBUS_FMT_SGRBG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GRBG, },
+	{ V4L2_MBUS_FMT_SRGGB8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_RGGB, },
+	{ V4L2_MBUS_FMT_SBGGR8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_BGGR, },
+	{ V4L2_MBUS_FMT_SGBRG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GBRG, },
+};
+
+const char *pixel_order_str[] = { "GRBG", "RGGB", "BGGR", "GBRG" };
+
+#define to_csi_format_idx(fmt) (((unsigned long)(fmt)			\
+				 - (unsigned long)smiapp_csi_data_formats) \
+				/ sizeof(*smiapp_csi_data_formats))
+
+static u32 smiapp_pixel_order(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int flip = 0;
+
+	if (sensor->hflip) {
+		if (sensor->hflip->val)
+			flip |= SMIAPP_IMAGE_ORIENTATION_HFLIP;
+
+		if (sensor->vflip->val)
+			flip |= SMIAPP_IMAGE_ORIENTATION_VFLIP;
+	}
+
+	flip ^= sensor->hvflip_inv_mask;
+
+	dev_dbg(&client->dev, "flip %d\n", flip);
+	return sensor->default_pixel_order ^ flip;
+}
+
+static void smiapp_update_mbus_formats(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	unsigned int csi_format_idx =
+		to_csi_format_idx(sensor->csi_format) & ~3;
+	unsigned int internal_csi_format_idx =
+		to_csi_format_idx(sensor->internal_csi_format) & ~3;
+	unsigned int pixel_order = smiapp_pixel_order(sensor);
+
+	sensor->mbus_frame_fmts =
+		sensor->default_mbus_frame_fmts << pixel_order;
+	sensor->csi_format =
+		&smiapp_csi_data_formats[csi_format_idx + pixel_order];
+	sensor->internal_csi_format =
+		&smiapp_csi_data_formats[internal_csi_format_idx
+					 + pixel_order];
+
+	BUG_ON(max(internal_csi_format_idx, csi_format_idx) + pixel_order
+	       >= ARRAY_SIZE(smiapp_csi_data_formats));
+	BUG_ON(min(internal_csi_format_idx, csi_format_idx) < 0);
+
+	dev_dbg(&client->dev, "new pixel order %s\n",
+		pixel_order_str[pixel_order]);
+}
+
+static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct smiapp_sensor *sensor =
+		container_of(ctrl->handler, struct smiapp_subdev, ctrl_handler)
+			->sensor;
+	u32 orient = 0;
+	int exposure;
+	int rval;
+
+	switch (ctrl->id) {
+	case V4L2_CID_ANALOGUE_GAIN:
+		return smiapp_write(
+			sensor,
+			SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL, ctrl->val);
+
+	case V4L2_CID_EXPOSURE:
+		return smiapp_write(
+			sensor,
+			SMIAPP_REG_U16_COARSE_INTEGRATION_TIME, ctrl->val);
+
+	case V4L2_CID_HFLIP:
+	case V4L2_CID_VFLIP:
+		if (sensor->streaming)
+			return -EBUSY;
+
+		if (sensor->hflip->val)
+			orient |= SMIAPP_IMAGE_ORIENTATION_HFLIP;
+
+		if (sensor->vflip->val)
+			orient |= SMIAPP_IMAGE_ORIENTATION_VFLIP;
+
+		orient ^= sensor->hvflip_inv_mask;
+		rval = smiapp_write(sensor,
+				    SMIAPP_REG_U8_IMAGE_ORIENTATION,
+				    orient);
+		if (rval < 0)
+			return rval;
+
+		smiapp_update_mbus_formats(sensor);
+
+		return 0;
+
+	case V4L2_CID_VBLANK:
+		exposure = sensor->exposure->val;
+
+		__smiapp_update_exposure_limits(sensor);
+
+		if (exposure > sensor->exposure->maximum) {
+			sensor->exposure->val =
+				sensor->exposure->maximum;
+			rval = smiapp_set_ctrl(
+				sensor->exposure);
+			if (rval < 0)
+				return rval;
+		}
+
+		return smiapp_write(
+			sensor, SMIAPP_REG_U16_FRAME_LENGTH_LINES,
+			sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
+			+ ctrl->val);
+
+	case V4L2_CID_HBLANK:
+		return smiapp_write(
+			sensor, SMIAPP_REG_U16_LINE_LENGTH_PCK,
+			sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width
+			+ ctrl->val);
+
+	case V4L2_CID_LINK_FREQ:
+		if (sensor->streaming)
+			return -EBUSY;
+
+		return smiapp_pll_update(sensor);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct v4l2_ctrl_ops smiapp_ctrl_ops = {
+	.s_ctrl = smiapp_set_ctrl,
+};
+
+static int smiapp_init_controls(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	unsigned int max;
+	int rval;
+
+	rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 7);
+	if (rval)
+		return rval;
+	sensor->pixel_array->ctrl_handler.lock = &sensor->mutex;
+
+	sensor->analog_gain = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_ANALOGUE_GAIN,
+		sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN],
+		sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX],
+		max(sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP], 1U),
+		sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN]);
+
+	/* Exposure limits will be updated soon, use just something here. */
+	sensor->exposure = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_EXPOSURE, 0, 0, 1, 0);
+
+	sensor->hflip = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_HFLIP, 0, 1, 1, 0);
+	sensor->vflip = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+	sensor->vblank = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_VBLANK, 0, 1, 1, 0);
+
+	if (sensor->vblank)
+		sensor->vblank->flags |= V4L2_CTRL_FLAG_UPDATE;
+
+	sensor->hblank = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_HBLANK, 0, 1, 1, 0);
+
+	if (sensor->hblank)
+		sensor->hblank->flags |= V4L2_CTRL_FLAG_UPDATE;
+
+	sensor->pixel_rate_parray = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
+
+	if (sensor->pixel_array->ctrl_handler.error) {
+		dev_err(&client->dev,
+			"pixel array controls initialization failed (%d)\n",
+			sensor->pixel_array->ctrl_handler.error);
+		rval = sensor->pixel_array->ctrl_handler.error;
+		goto error;
+	}
+
+	sensor->pixel_array->sd.ctrl_handler =
+		&sensor->pixel_array->ctrl_handler;
+
+	v4l2_ctrl_cluster(2, &sensor->hflip);
+
+	rval = v4l2_ctrl_handler_init(&sensor->src->ctrl_handler, 0);
+	if (rval)
+		goto error;
+	sensor->src->ctrl_handler.lock = &sensor->mutex;
+
+	for (max = 0; sensor->platform_data->op_sys_clock[max + 1]; max++);
+
+	sensor->link_freq = v4l2_ctrl_new_int_menu(
+		&sensor->src->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_LINK_FREQ, max, 0,
+		sensor->platform_data->op_sys_clock);
+
+	sensor->pixel_rate_csi = v4l2_ctrl_new_std(
+		&sensor->src->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
+
+	if (sensor->src->ctrl_handler.error) {
+		dev_err(&client->dev,
+			"src controls initialization failed (%d)\n",
+			sensor->src->ctrl_handler.error);
+		rval = sensor->src->ctrl_handler.error;
+		goto error;
+	}
+
+	sensor->src->sd.ctrl_handler =
+		&sensor->src->ctrl_handler;
+
+	return 0;
+
+error:
+	v4l2_ctrl_handler_free(&sensor->pixel_array->ctrl_handler);
+	v4l2_ctrl_handler_free(&sensor->src->ctrl_handler);
+
+	return rval;
+}
+
+static void smiapp_free_controls(struct smiapp_sensor *sensor)
+{
+	unsigned int i;
+
+	for (i = 0; i < sensor->ssds_used; i++)
+		v4l2_ctrl_handler_free(&sensor->ssds[i].ctrl_handler);
+}
+
+static int smiapp_get_limits(struct smiapp_sensor *sensor, int const *limit,
+			     unsigned int n)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	unsigned int i;
+	u32 val;
+	int rval;
+
+	for (i = 0; i < n; i++) {
+		rval = smiapp_read(
+			sensor, smiapp_reg_limits[limit[i]].addr, &val);
+		if (rval)
+			return rval;
+		sensor->limits[limit[i]] = val;
+		dev_dbg(&client->dev, "0x%8.8x \"%s\" = %d, 0x%x\n",
+			smiapp_reg_limits[limit[i]].addr,
+			smiapp_reg_limits[limit[i]].what, val, val);
+	}
+
+	return 0;
+}
+
+static int smiapp_get_all_limits(struct smiapp_sensor *sensor)
+{
+	unsigned int i;
+	int rval;
+
+	for (i = 0; i < SMIAPP_LIMIT_LAST; i++) {
+		rval = smiapp_get_limits(sensor, &i, 1);
+		if (rval < 0)
+			return rval;
+	}
+
+	if (sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] == 0)
+		smiapp_replace_limit(sensor, SMIAPP_LIMIT_SCALER_N_MIN, 16);
+
+	return 0;
+}
+
+static int smiapp_get_limits_binning(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	static u32 const limits[] = {
+		SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN,
+		SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN,
+		SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN,
+		SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN,
+		SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN,
+		SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN_BIN,
+		SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN,
+	};
+	static u32 const limits_replace[] = {
+		SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES,
+		SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES,
+		SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK,
+		SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK,
+		SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK,
+		SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN,
+		SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN,
+	};
+	unsigned int i;
+	int rval;
+
+	if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY] ==
+	    SMIAPP_BINNING_CAPABILITY_NO) {
+		for (i = 0; i < ARRAY_SIZE(limits); i++)
+			sensor->limits[limits[i]] =
+				sensor->limits[limits_replace[i]];
+
+		return 0;
+	}
+
+	rval = smiapp_get_limits(sensor, limits, ARRAY_SIZE(limits));
+	if (rval < 0)
+		return rval;
+
+	/*
+	 * Sanity check whether the binning limits are valid. If not,
+	 * use the non-binning ones.
+	 */
+	if (sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN]
+	    && sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN]
+	    && sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN])
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(limits); i++) {
+		dev_dbg(&client->dev,
+			"replace limit 0x%8.8x \"%s\" = %d, 0x%x\n",
+			smiapp_reg_limits[limits[i]].addr,
+			smiapp_reg_limits[limits[i]].what,
+			sensor->limits[limits_replace[i]],
+			sensor->limits[limits_replace[i]]);
+		sensor->limits[limits[i]] =
+			sensor->limits[limits_replace[i]];
+	}
+
+	return 0;
+}
+
+static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	unsigned int type, n;
+	unsigned int i, pixel_order;
+	int rval;
+
+	rval = smiapp_read(
+		sensor, SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE, &type);
+	if (rval)
+		return rval;
+
+	dev_dbg(&client->dev, "data_format_model_type %d\n", type);
+
+	rval = smiapp_read(sensor, SMIAPP_REG_U8_PIXEL_ORDER,
+			   &pixel_order);
+	if (rval)
+		return rval;
+
+	if (pixel_order >= ARRAY_SIZE(pixel_order_str)) {
+		dev_dbg(&client->dev, "bad pixel order %d\n", pixel_order);
+		return -EINVAL;
+	}
+
+	dev_dbg(&client->dev, "pixel order %d (%s)\n", pixel_order,
+		pixel_order_str[pixel_order]);
+
+	switch (type) {
+	case SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL:
+		n = SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N;
+		break;
+	case SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED:
+		n = SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	sensor->default_pixel_order = pixel_order;
+	sensor->mbus_frame_fmts = 0;
+
+	for (i = 0; i < n; i++) {
+		unsigned int fmt, j;
+
+		rval = smiapp_read(
+			sensor,
+			SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(i), &fmt);
+		if (rval)
+			return rval;
+
+		dev_dbg(&client->dev, "bpp %d, compressed %d\n",
+			fmt >> 8, (u8)fmt);
+
+		for (j = 0; j < ARRAY_SIZE(smiapp_csi_data_formats); j++) {
+			const struct smiapp_csi_data_format *f =
+				&smiapp_csi_data_formats[j];
+
+			if (f->pixel_order != SMIAPP_PIXEL_ORDER_GRBG)
+				continue;
+
+			if (f->width != fmt >> 8 || f->compressed != (u8)fmt)
+				continue;
+
+			dev_dbg(&client->dev, "jolly good! %d\n", j);
+
+			sensor->default_mbus_frame_fmts |= 1 << j;
+			if (!sensor->csi_format) {
+				sensor->csi_format = f;
+				sensor->internal_csi_format = f;
+			}
+		}
+	}
+
+	if (!sensor->csi_format) {
+		dev_err(&client->dev, "no supported mbus code found\n");
+		return -EINVAL;
+	}
+
+	smiapp_update_mbus_formats(sensor);
+
+	return 0;
+}
+
+static void smiapp_update_blanking(struct smiapp_sensor *sensor)
+{
+	struct v4l2_ctrl *vblank = sensor->vblank;
+	struct v4l2_ctrl *hblank = sensor->hblank;
+
+	vblank->minimum =
+		max_t(int,
+		      sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES],
+		      sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] -
+		      sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height);
+	vblank->maximum =
+		sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] -
+		sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height;
+
+	vblank->val = clamp_t(int, vblank->val,
+			      vblank->minimum, vblank->maximum);
+	vblank->default_value = vblank->minimum;
+	vblank->val = vblank->val;
+	vblank->cur.val = vblank->val;
+
+	hblank->minimum =
+		max_t(int,
+		      sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] -
+		      sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width,
+		      sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]);
+	hblank->maximum =
+		sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] -
+		sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width;
+
+	hblank->val = clamp_t(int, hblank->val,
+			      hblank->minimum, hblank->maximum);
+	hblank->default_value = hblank->minimum;
+	hblank->val = hblank->val;
+	hblank->cur.val = hblank->val;
+
+	__smiapp_update_exposure_limits(sensor);
+}
+
+static int smiapp_update_mode(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	unsigned int binning_mode;
+	int rval;
+
+	dev_dbg(&client->dev, "frame size: %dx%d\n",
+		sensor->src->crop[SMIAPP_PAD_SRC].width,
+		sensor->src->crop[SMIAPP_PAD_SRC].height);
+	dev_dbg(&client->dev, "csi format width: %d\n",
+		sensor->csi_format->width);
+
+	/* Binning has to be set up here; it affects limits */
+	if (sensor->binning_horizontal == 1 &&
+	    sensor->binning_vertical == 1) {
+		binning_mode = 0;
+	} else {
+		u8 binning_type =
+			(sensor->binning_horizontal << 4)
+			| sensor->binning_vertical;
+
+		rval = smiapp_write(
+			sensor, SMIAPP_REG_U8_BINNING_TYPE, binning_type);
+		if (rval < 0)
+			return rval;
+
+		binning_mode = 1;
+	}
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_BINNING_MODE, binning_mode);
+	if (rval < 0)
+		return rval;
+
+	/* Get updated limits due to binning */
+	rval = smiapp_get_limits_binning(sensor);
+	if (rval < 0)
+		return rval;
+
+	rval = smiapp_pll_update(sensor);
+	if (rval < 0)
+		return rval;
+
+	/* Output from pixel array, including blanking */
+	smiapp_update_blanking(sensor);
+
+	dev_dbg(&client->dev, "vblank\t\t%d\n", sensor->vblank->val);
+	dev_dbg(&client->dev, "hblank\t\t%d\n", sensor->hblank->val);
+
+	dev_dbg(&client->dev, "real timeperframe\t100/%d\n",
+		sensor->pll.vt_pix_clk_freq_hz /
+		((sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width
+		  + sensor->hblank->val) *
+		 (sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
+		  + sensor->vblank->val) / 100));
+
+	return 0;
+}
+
+/*
+ *
+ * SMIA++ NVM handling
+ *
+ */
+static int smiapp_read_nvm(struct smiapp_sensor *sensor,
+			   unsigned char *nvm)
+{
+	u32 i, s, p, np, v;
+	int rval = 0, rval2;
+
+	np = sensor->nvm_size / SMIAPP_NVM_PAGE_SIZE;
+	for (p = 0; p < np; p++) {
+		rval = smiapp_write(
+			sensor,
+			SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT, p);
+		if (rval)
+			goto out;
+
+		rval = smiapp_write(sensor,
+				    SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL,
+				    SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN |
+				    SMIAPP_DATA_TRANSFER_IF_1_CTRL_RD_EN);
+		if (rval)
+			goto out;
+
+		for (i = 0; i < 1000; i++) {
+			rval = smiapp_read(
+				sensor,
+				SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, &s);
+
+			if (rval)
+				goto out;
+
+			if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY)
+				break;
+
+			if (--i == 0) {
+				rval = -ETIMEDOUT;
+				goto out;
+			}
+
+		}
+
+		for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) {
+			rval = smiapp_read(
+				sensor,
+				SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 + i,
+				&v);
+			if (rval)
+				goto out;
+
+			*nvm++ = v;
+		}
+	}
+
+out:
+	rval2 = smiapp_write(sensor, SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL, 0);
+	if (rval < 0)
+		return rval;
+	else
+		return rval2;
+}
+
+/*
+ *
+ * SMIA++ CCI address control
+ *
+ */
+static int smiapp_change_cci_addr(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int rval;
+	u32 val;
+
+	client->addr = sensor->platform_data->i2c_addr_dfl;
+
+	rval = smiapp_write(sensor,
+			    SMIAPP_REG_U8_CCI_ADDRESS_CONTROL,
+			    sensor->platform_data->i2c_addr_alt << 1);
+	if (rval)
+		return rval;
+
+	client->addr = sensor->platform_data->i2c_addr_alt;
+
+	/* verify addr change went ok */
+	rval = smiapp_read(sensor, SMIAPP_REG_U8_CCI_ADDRESS_CONTROL, &val);
+	if (rval)
+		return rval;
+
+	if (val != sensor->platform_data->i2c_addr_alt << 1)
+		return -ENODEV;
+
+	return 0;
+}
+
+/*
+ *
+ * SMIA++ Mode Control
+ *
+ */
+static int smiapp_setup_flash_strobe(struct smiapp_sensor *sensor)
+{
+	struct smiapp_flash_strobe_parms *strobe_setup;
+	unsigned int ext_freq = sensor->platform_data->ext_clk;
+	u32 tmp;
+	u32 strobe_adjustment;
+	u32 strobe_width_high_rs;
+	int rval;
+
+	strobe_setup = sensor->platform_data->strobe_setup;
+
+	/*
+	 * How to calculate registers related to strobe length. Please
+	 * do not change, or if you do at least know what you're
+	 * doing. :-)
+	 *
+	 * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> 2010-10-25
+	 *
+	 * flash_strobe_length [us] / 10^6 = (tFlash_strobe_width_ctrl
+	 *	/ EXTCLK freq [Hz]) * flash_strobe_adjustment
+	 *
+	 * tFlash_strobe_width_ctrl E N, [1 - 0xffff]
+	 * flash_strobe_adjustment E N, [1 - 0xff]
+	 *
+	 * The formula above is written as below to keep it on one
+	 * line:
+	 *
+	 * l / 10^6 = w / e * a
+	 *
+	 * Let's mark w * a by x:
+	 *
+	 * x = w * a
+	 *
+	 * Thus, we get:
+	 *
+	 * x = l * e / 10^6
+	 *
+	 * The strobe width must be at least as long as requested,
+	 * thus rounding upwards is needed.
+	 *
+	 * x = (l * e + 10^6 - 1) / 10^6
+	 * -----------------------------
+	 *
+	 * Maximum possible accuracy is wanted at all times. Thus keep
+	 * a as small as possible.
+	 *
+	 * Calculate a, assuming maximum w, with rounding upwards:
+	 *
+	 * a = (x + (2^16 - 1) - 1) / (2^16 - 1)
+	 * -------------------------------------
+	 *
+	 * Thus, we also get w, with that a, with rounding upwards:
+	 *
+	 * w = (x + a - 1) / a
+	 * -------------------
+	 *
+	 * To get limits:
+	 *
+	 * x E [1, (2^16 - 1) * (2^8 - 1)]
+	 *
+	 * Substituting maximum x to the original formula (with rounding),
+	 * the maximum l is thus
+	 *
+	 * (2^16 - 1) * (2^8 - 1) * 10^6 = l * e + 10^6 - 1
+	 *
+	 * l = (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / e
+	 * --------------------------------------------------
+	 *
+	 * flash_strobe_length must be clamped between 1 and
+	 * (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / EXTCLK freq.
+	 *
+	 * Then,
+	 *
+	 * flash_strobe_adjustment = ((flash_strobe_length *
+	 *	EXTCLK freq + 10^6 - 1) / 10^6 + (2^16 - 1) - 1) / (2^16 - 1)
+	 *
+	 * tFlash_strobe_width_ctrl = ((flash_strobe_length *
+	 *	EXTCLK freq + 10^6 - 1) / 10^6 +
+	 *	flash_strobe_adjustment - 1) / flash_strobe_adjustment
+	 */
+	tmp = div_u64(1000000ULL * ((1 << 16) - 1) * ((1 << 8) - 1) -
+		      1000000 + 1, ext_freq);
+	strobe_setup->strobe_width_high_us =
+		clamp_t(u32, strobe_setup->strobe_width_high_us, 1, tmp);
+
+	tmp = div_u64(((u64)strobe_setup->strobe_width_high_us * (u64)ext_freq +
+			1000000 - 1), 1000000ULL);
+	strobe_adjustment = (tmp + (1 << 16) - 1 - 1) / ((1 << 16) - 1);
+	strobe_width_high_rs = (tmp + strobe_adjustment - 1) /
+				strobe_adjustment;
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_MODE_RS,
+			    strobe_setup->mode);
+	if (rval < 0)
+		goto out;
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT,
+			    strobe_adjustment);
+	if (rval < 0)
+		goto out;
+
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL,
+		strobe_width_high_rs);
+	if (rval < 0)
+		goto out;
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL,
+			    strobe_setup->strobe_delay);
+	if (rval < 0)
+		goto out;
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U16_FLASH_STROBE_START_POINT,
+			    strobe_setup->stobe_start_point);
+	if (rval < 0)
+		goto out;
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_TRIGGER_RS,
+			    strobe_setup->trigger);
+
+out:
+	sensor->platform_data->strobe_setup->trigger = 0;
+
+	return rval;
+}
+
+/* -----------------------------------------------------------------------------
+ * Power management
+ */
+
+static int smiapp_power_on(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	unsigned int sleep;
+	int rval;
+
+	rval = regulator_enable(sensor->vana);
+	if (rval) {
+		dev_err(&client->dev, "failed to enable vana regulator\n");
+		return rval;
+	}
+	usleep_range(1000, 1000);
+
+	if (sensor->platform_data->set_xclk)
+		rval = sensor->platform_data->set_xclk(
+			&sensor->src->sd, sensor->platform_data->ext_clk);
+	else
+		rval = clk_enable(sensor->ext_clk);
+	if (rval < 0) {
+		dev_dbg(&client->dev, "failed to set xclk\n");
+		goto out_xclk_fail;
+	}
+	usleep_range(1000, 1000);
+
+	if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+		gpio_set_value(sensor->platform_data->xshutdown, 1);
+
+	sleep = SMIAPP_RESET_DELAY(sensor->platform_data->ext_clk);
+	usleep_range(sleep, sleep);
+
+	/*
+	 * Failures to respond to the address change command have been noticed.
+	 * Those failures seem to be caused by the sensor requiring a longer
+	 * boot time than advertised. An additional 10ms delay seems to work
+	 * around the issue, but the SMIA++ I2C write retry hack makes the delay
+	 * unnecessary. The failures need to be investigated to find a proper
+	 * fix, and a delay will likely need to be added here if the I2C write
+	 * retry hack is reverted before the root cause of the boot time issue
+	 * is found.
+	 */
+
+	if (sensor->platform_data->i2c_addr_alt) {
+		rval = smiapp_change_cci_addr(sensor);
+		if (rval) {
+			dev_err(&client->dev, "cci address change error\n");
+			goto out_cci_addr_fail;
+		}
+	}
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_SOFTWARE_RESET,
+			    SMIAPP_SOFTWARE_RESET);
+	if (rval < 0) {
+		dev_err(&client->dev, "software reset failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	if (sensor->platform_data->i2c_addr_alt) {
+		rval = smiapp_change_cci_addr(sensor);
+		if (rval) {
+			dev_err(&client->dev, "cci address change error\n");
+			goto out_cci_addr_fail;
+		}
+	}
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U16_COMPRESSION_MODE,
+			    SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR);
+	if (rval) {
+		dev_err(&client->dev, "compression mode set failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ,
+		sensor->platform_data->ext_clk / (1000000 / (1 << 8)));
+	if (rval) {
+		dev_err(&client->dev, "extclk frequency set failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_LANE_MODE,
+			    sensor->platform_data->lanes - 1);
+	if (rval) {
+		dev_err(&client->dev, "csi lane mode set failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_FAST_STANDBY_CTRL,
+			    SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE);
+	if (rval) {
+		dev_err(&client->dev, "fast standby set failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_SIGNALLING_MODE,
+			    sensor->platform_data->csi_signalling_mode);
+	if (rval) {
+		dev_err(&client->dev, "csi signalling mode set failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	/* DPHY control done by sensor based on requested link rate */
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_DPHY_CTRL,
+			    SMIAPP_DPHY_CTRL_UI);
+	if (rval < 0)
+		return rval;
+
+	rval = smiapp_call_quirk(sensor, post_poweron);
+	if (rval) {
+		dev_err(&client->dev, "post_poweron quirks failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	/* Are we still initialising...? If yes, return here. */
+	if (!sensor->pixel_array)
+		return 0;
+
+	rval = v4l2_ctrl_handler_setup(
+		&sensor->pixel_array->ctrl_handler);
+	if (rval)
+		goto out_cci_addr_fail;
+
+	rval = v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler);
+	if (rval)
+		goto out_cci_addr_fail;
+
+	mutex_lock(&sensor->mutex);
+	rval = smiapp_update_mode(sensor);
+	mutex_unlock(&sensor->mutex);
+	if (rval < 0)
+		goto out_cci_addr_fail;
+
+	return 0;
+
+out_cci_addr_fail:
+	if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+		gpio_set_value(sensor->platform_data->xshutdown, 0);
+	if (sensor->platform_data->set_xclk)
+		sensor->platform_data->set_xclk(&sensor->src->sd, 0);
+	else
+		clk_disable(sensor->ext_clk);
+
+out_xclk_fail:
+	regulator_disable(sensor->vana);
+	return rval;
+}
+
+static void smiapp_power_off(struct smiapp_sensor *sensor)
+{
+	/*
+	 * Currently power/clock to lens are enable/disabled separately
+	 * but they are essentially the same signals. So if the sensor is
+	 * powered off while the lens is powered on the sensor does not
+	 * really see a power off and next time the cci address change
+	 * will fail. So do a soft reset explicitly here.
+	 */
+	if (sensor->platform_data->i2c_addr_alt)
+		smiapp_write(sensor,
+			     SMIAPP_REG_U8_SOFTWARE_RESET,
+			     SMIAPP_SOFTWARE_RESET);
+
+	if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+		gpio_set_value(sensor->platform_data->xshutdown, 0);
+	if (sensor->platform_data->set_xclk)
+		sensor->platform_data->set_xclk(&sensor->src->sd, 0);
+	else
+		clk_disable(sensor->ext_clk);
+	usleep_range(5000, 5000);
+	regulator_disable(sensor->vana);
+	sensor->streaming = 0;
+}
+
+static int smiapp_set_power(struct v4l2_subdev *subdev, int on)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int ret = 0;
+
+	mutex_lock(&sensor->power_mutex);
+
+	/*
+	 * If the power count is modified from 0 to != 0 or from != 0
+	 * to 0, update the power state.
+	 */
+	if (!sensor->power_count == !on)
+		goto out;
+
+	if (on) {
+		/* Power on and perform initialisation. */
+		ret = smiapp_power_on(sensor);
+		if (ret < 0)
+			goto out;
+	} else {
+		smiapp_power_off(sensor);
+	}
+
+	/* Update the power count. */
+	sensor->power_count += on ? 1 : -1;
+	WARN_ON(sensor->power_count < 0);
+
+out:
+	mutex_unlock(&sensor->power_mutex);
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Video stream management
+ */
+
+static int smiapp_start_streaming(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int rval;
+
+	mutex_lock(&sensor->mutex);
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U16_CSI_DATA_FORMAT,
+			    (sensor->csi_format->width << 8) |
+			    sensor->csi_format->compressed);
+	if (rval)
+		goto out;
+
+	rval = smiapp_pll_configure(sensor);
+	if (rval)
+		goto out;
+
+	/* Analog crop start coordinates */
+	rval = smiapp_write(sensor, SMIAPP_REG_U16_X_ADDR_START,
+			    sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left);
+	if (rval < 0)
+		goto out;
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U16_Y_ADDR_START,
+			    sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top);
+	if (rval < 0)
+		goto out;
+
+	/* Analog crop end coordinates */
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_X_ADDR_END,
+		sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left
+		+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width - 1);
+	if (rval < 0)
+		goto out;
+
+	rval = smiapp_write(
+		sensor, SMIAPP_REG_U16_Y_ADDR_END,
+		sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top
+		+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height - 1);
+	if (rval < 0)
+		goto out;
+
+	/*
+	 * Output from pixel array, including blanking, is set using
+	 * controls below. No need to set here.
+	 */
+
+	/* Digital crop */
+	if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+	    == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
+		rval = smiapp_write(
+			sensor, SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET,
+			sensor->scaler->crop[SMIAPP_PAD_SINK].left);
+		if (rval < 0)
+			goto out;
+
+		rval = smiapp_write(
+			sensor, SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET,
+			sensor->scaler->crop[SMIAPP_PAD_SINK].top);
+		if (rval < 0)
+			goto out;
+
+		rval = smiapp_write(
+			sensor, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH,
+			sensor->scaler->crop[SMIAPP_PAD_SINK].width);
+		if (rval < 0)
+			goto out;
+
+		rval = smiapp_write(
+			sensor, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT,
+			sensor->scaler->crop[SMIAPP_PAD_SINK].height);
+		if (rval < 0)
+			goto out;
+	}
+
+	/* Scaling */
+	if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+	    != SMIAPP_SCALING_CAPABILITY_NONE) {
+		rval = smiapp_write(sensor, SMIAPP_REG_U16_SCALING_MODE,
+				    sensor->scaling_mode);
+		if (rval < 0)
+			goto out;
+
+		rval = smiapp_write(sensor, SMIAPP_REG_U16_SCALE_M,
+				    sensor->scale_m);
+		if (rval < 0)
+			goto out;
+	}
+
+	/* Output size from sensor */
+	rval = smiapp_write(sensor, SMIAPP_REG_U16_X_OUTPUT_SIZE,
+			    sensor->src->crop[SMIAPP_PAD_SRC].width);
+	if (rval < 0)
+		goto out;
+	rval = smiapp_write(sensor, SMIAPP_REG_U16_Y_OUTPUT_SIZE,
+			    sensor->src->crop[SMIAPP_PAD_SRC].height);
+	if (rval < 0)
+		goto out;
+
+	if ((sensor->flash_capability &
+	     (SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE |
+	      SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) &&
+	    sensor->platform_data->strobe_setup != NULL &&
+	    sensor->platform_data->strobe_setup->trigger != 0) {
+		rval = smiapp_setup_flash_strobe(sensor);
+		if (rval)
+			goto out;
+	}
+
+	rval = smiapp_call_quirk(sensor, pre_streamon);
+	if (rval) {
+		dev_err(&client->dev, "pre_streamon quirks failed\n");
+		goto out;
+	}
+
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_MODE_SELECT,
+			    SMIAPP_MODE_SELECT_STREAMING);
+
+out:
+	mutex_unlock(&sensor->mutex);
+
+	return rval;
+}
+
+static int smiapp_stop_streaming(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int rval;
+
+	mutex_lock(&sensor->mutex);
+	rval = smiapp_write(sensor, SMIAPP_REG_U8_MODE_SELECT,
+			    SMIAPP_MODE_SELECT_SOFTWARE_STANDBY);
+	if (rval)
+		goto out;
+
+	rval = smiapp_call_quirk(sensor, post_streamoff);
+	if (rval)
+		dev_err(&client->dev, "post_streamoff quirks failed\n");
+
+out:
+	mutex_unlock(&sensor->mutex);
+	return rval;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev video operations
+ */
+
+static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int rval;
+
+	if (sensor->streaming == enable)
+		return 0;
+
+	if (enable) {
+		sensor->streaming = 1;
+		rval = smiapp_start_streaming(sensor);
+		if (rval < 0)
+			sensor->streaming = 0;
+	} else {
+		rval = smiapp_stop_streaming(sensor);
+		sensor->streaming = 0;
+	}
+
+	return rval;
+}
+
+static int smiapp_enum_mbus_code(struct v4l2_subdev *subdev,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	unsigned int i;
+	int idx = -1;
+	int rval = -EINVAL;
+
+	mutex_lock(&sensor->mutex);
+
+	dev_err(&client->dev, "subdev %s, pad %d, index %d\n",
+		subdev->name, code->pad, code->index);
+
+	if (subdev != &sensor->src->sd || code->pad != SMIAPP_PAD_SRC) {
+		if (code->index)
+			goto out;
+
+		code->code = sensor->internal_csi_format->code;
+		rval = 0;
+		goto out;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
+		if (sensor->mbus_frame_fmts & (1 << i))
+			idx++;
+
+		if (idx == code->index) {
+			code->code = smiapp_csi_data_formats[i].code;
+			dev_err(&client->dev, "found index %d, i %d, code %x\n",
+				code->index, i, code->code);
+			rval = 0;
+			break;
+		}
+	}
+
+out:
+	mutex_unlock(&sensor->mutex);
+
+	return rval;
+}
+
+static u32 __smiapp_get_mbus_code(struct v4l2_subdev *subdev,
+				  unsigned int pad)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+
+	if (subdev == &sensor->src->sd && pad == SMIAPP_PAD_SRC)
+		return sensor->csi_format->code;
+	else
+		return sensor->internal_csi_format->code;
+}
+
+static int __smiapp_get_format(struct v4l2_subdev *subdev,
+			       struct v4l2_subdev_fh *fh,
+			       struct v4l2_subdev_format *fmt)
+{
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad);
+	} else {
+		struct v4l2_rect *r;
+
+		if (fmt->pad == ssd->source_pad)
+			r = &ssd->crop[ssd->source_pad];
+		else
+			r = &ssd->sink_fmt;
+
+		fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad);
+		fmt->format.width = r->width;
+		fmt->format.height = r->height;
+	}
+
+	return 0;
+}
+
+static int smiapp_get_format(struct v4l2_subdev *subdev,
+			     struct v4l2_subdev_fh *fh,
+			     struct v4l2_subdev_format *fmt)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int rval;
+
+	mutex_lock(&sensor->mutex);
+	rval = __smiapp_get_format(subdev, fh, fmt);
+	mutex_unlock(&sensor->mutex);
+
+	return rval;
+}
+
+static void smiapp_get_crop_compose(struct v4l2_subdev *subdev,
+				    struct v4l2_subdev_fh *fh,
+				    struct v4l2_rect **crops,
+				    struct v4l2_rect **comps, int which)
+{
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	unsigned int i;
+
+	if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		if (crops)
+			for (i = 0; i < subdev->entity.num_pads; i++)
+				crops[i] = &ssd->crop[i];
+		if (comps)
+			*comps = &ssd->compose;
+	} else {
+		if (crops) {
+			for (i = 0; i < subdev->entity.num_pads; i++) {
+				crops[i] = v4l2_subdev_get_try_crop(fh, i);
+				BUG_ON(!crops[i]);
+			}
+		}
+		if (comps) {
+			*comps = v4l2_subdev_get_try_compose(fh,
+							     SMIAPP_PAD_SINK);
+			BUG_ON(!*comps);
+		}
+	}
+}
+
+/* Changes require propagation only on sink pad. */
+static void smiapp_propagate(struct v4l2_subdev *subdev,
+			     struct v4l2_subdev_fh *fh, int which,
+			     int target)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	struct v4l2_rect *comp, *crops[SMIAPP_PADS];
+
+	smiapp_get_crop_compose(subdev, fh, crops, &comp, which);
+
+	switch (target) {
+	case V4L2_SEL_TGT_CROP:
+		comp->width = crops[SMIAPP_PAD_SINK]->width;
+		comp->height = crops[SMIAPP_PAD_SINK]->height;
+		if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+			if (ssd == sensor->scaler) {
+				sensor->scale_m =
+					sensor->limits[
+						SMIAPP_LIMIT_SCALER_N_MIN];
+				sensor->scaling_mode =
+					SMIAPP_SCALING_MODE_NONE;
+			} else if (ssd == sensor->binner) {
+				sensor->binning_horizontal = 1;
+				sensor->binning_vertical = 1;
+			}
+		}
+		/* Fall through */
+	case V4L2_SEL_TGT_COMPOSE:
+		*crops[SMIAPP_PAD_SRC] = *comp;
+		break;
+	default:
+		BUG();
+	}
+}
+
+static const struct smiapp_csi_data_format
+*smiapp_validate_csi_data_format(struct smiapp_sensor *sensor, u32 code)
+{
+	const struct smiapp_csi_data_format *csi_format = sensor->csi_format;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
+		if (sensor->mbus_frame_fmts & (1 << i)
+		    && smiapp_csi_data_formats[i].code == code)
+			return &smiapp_csi_data_formats[i];
+	}
+
+	return csi_format;
+}
+
+static int smiapp_set_format(struct v4l2_subdev *subdev,
+			     struct v4l2_subdev_fh *fh,
+			     struct v4l2_subdev_format *fmt)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	struct v4l2_rect *crops[SMIAPP_PADS];
+
+	mutex_lock(&sensor->mutex);
+
+	/*
+	 * Media bus code is changeable on src subdev's source pad. On
+	 * other source pads we just get format here.
+	 */
+	if (fmt->pad == ssd->source_pad) {
+		u32 code = fmt->format.code;
+		int rval = __smiapp_get_format(subdev, fh, fmt);
+
+		if (!rval && subdev == &sensor->src->sd) {
+			const struct smiapp_csi_data_format *csi_format =
+				smiapp_validate_csi_data_format(sensor, code);
+			if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+				sensor->csi_format = csi_format;
+			fmt->format.code = csi_format->code;
+		}
+
+		mutex_unlock(&sensor->mutex);
+		return rval;
+	}
+
+	/* Sink pad. Width and height are changeable here. */
+	fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad);
+	fmt->format.width &= ~1;
+	fmt->format.height &= ~1;
+
+	fmt->format.width =
+		clamp(fmt->format.width,
+		      sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
+		      sensor->limits[SMIAPP_LIMIT_MAX_X_OUTPUT_SIZE]);
+	fmt->format.height =
+		clamp(fmt->format.height,
+		      sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
+		      sensor->limits[SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE]);
+
+	smiapp_get_crop_compose(subdev, fh, crops, NULL, fmt->which);
+
+	crops[ssd->sink_pad]->left = 0;
+	crops[ssd->sink_pad]->top = 0;
+	crops[ssd->sink_pad]->width = fmt->format.width;
+	crops[ssd->sink_pad]->height = fmt->format.height;
+	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		ssd->sink_fmt = *crops[ssd->sink_pad];
+	smiapp_propagate(subdev, fh, fmt->which,
+			 V4L2_SEL_TGT_CROP);
+
+	mutex_unlock(&sensor->mutex);
+
+	return 0;
+}
+
+/*
+ * Calculate goodness of scaled image size compared to expected image
+ * size and flags provided.
+ */
+#define SCALING_GOODNESS		100000
+#define SCALING_GOODNESS_EXTREME	100000000
+static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w,
+			    int h, int ask_h, u32 flags)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	int val = 0;
+
+	w &= ~1;
+	ask_w &= ~1;
+	h &= ~1;
+	ask_h &= ~1;
+
+	if (flags & V4L2_SEL_FLAG_GE) {
+		if (w < ask_w)
+			val -= SCALING_GOODNESS;
+		if (h < ask_h)
+			val -= SCALING_GOODNESS;
+	}
+
+	if (flags & V4L2_SEL_FLAG_LE) {
+		if (w > ask_w)
+			val -= SCALING_GOODNESS;
+		if (h > ask_h)
+			val -= SCALING_GOODNESS;
+	}
+
+	val -= abs(w - ask_w);
+	val -= abs(h - ask_h);
+
+	if (w < sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE])
+		val -= SCALING_GOODNESS_EXTREME;
+
+	dev_dbg(&client->dev, "w %d ask_w %d h %d ask_h %d goodness %d\n",
+		w, ask_h, h, ask_h, val);
+
+	return val;
+}
+
+static void smiapp_set_compose_binner(struct v4l2_subdev *subdev,
+				      struct v4l2_subdev_fh *fh,
+				      struct v4l2_subdev_selection *sel,
+				      struct v4l2_rect **crops,
+				      struct v4l2_rect *comp)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	unsigned int i;
+	unsigned int binh = 1, binv = 1;
+	unsigned int best = scaling_goodness(
+		subdev,
+		crops[SMIAPP_PAD_SINK]->width, sel->r.width,
+		crops[SMIAPP_PAD_SINK]->height, sel->r.height, sel->flags);
+
+	for (i = 0; i < sensor->nbinning_subtypes; i++) {
+		int this = scaling_goodness(
+			subdev,
+			crops[SMIAPP_PAD_SINK]->width
+			/ sensor->binning_subtypes[i].horizontal,
+			sel->r.width,
+			crops[SMIAPP_PAD_SINK]->height
+			/ sensor->binning_subtypes[i].vertical,
+			sel->r.height, sel->flags);
+
+		if (this > best) {
+			binh = sensor->binning_subtypes[i].horizontal;
+			binv = sensor->binning_subtypes[i].vertical;
+			best = this;
+		}
+	}
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		sensor->binning_vertical = binv;
+		sensor->binning_horizontal = binh;
+	}
+
+	sel->r.width = (crops[SMIAPP_PAD_SINK]->width / binh) & ~1;
+	sel->r.height = (crops[SMIAPP_PAD_SINK]->height / binv) & ~1;
+}
+
+/*
+ * Calculate best scaling ratio and mode for given output resolution.
+ *
+ * Try all of these: horizontal ratio, vertical ratio and smallest
+ * size possible (horizontally).
+ *
+ * Also try whether horizontal scaler or full scaler gives a better
+ * result.
+ */
+static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev,
+				      struct v4l2_subdev_fh *fh,
+				      struct v4l2_subdev_selection *sel,
+				      struct v4l2_rect **crops,
+				      struct v4l2_rect *comp)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	u32 min, max, a, b, max_m;
+	u32 scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+	int mode = SMIAPP_SCALING_MODE_HORIZONTAL;
+	u32 try[4];
+	u32 ntry = 0;
+	unsigned int i;
+	int best = INT_MIN;
+
+	sel->r.width = min_t(unsigned int, sel->r.width,
+			     crops[SMIAPP_PAD_SINK]->width);
+	sel->r.height = min_t(unsigned int, sel->r.height,
+			      crops[SMIAPP_PAD_SINK]->height);
+
+	a = crops[SMIAPP_PAD_SINK]->width
+		* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.width;
+	b = crops[SMIAPP_PAD_SINK]->height
+		* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.height;
+	max_m = crops[SMIAPP_PAD_SINK]->width
+		* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]
+		/ sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE];
+
+	a = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
+		max(a, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
+	b = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
+		max(b, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
+	max_m = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
+		    max(max_m, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
+
+	dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m);
+
+	min = min(max_m, min(a, b));
+	max = min(max_m, max(a, b));
+
+	try[ntry] = min;
+	ntry++;
+	if (min != max) {
+		try[ntry] = max;
+		ntry++;
+	}
+	if (max != max_m) {
+		try[ntry] = min + 1;
+		ntry++;
+		if (min != max) {
+			try[ntry] = max + 1;
+			ntry++;
+		}
+	}
+
+	for (i = 0; i < ntry; i++) {
+		int this = scaling_goodness(
+			subdev,
+			crops[SMIAPP_PAD_SINK]->width
+			/ try[i]
+			* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+			sel->r.width,
+			crops[SMIAPP_PAD_SINK]->height,
+			sel->r.height,
+			sel->flags);
+
+		dev_dbg(&client->dev, "trying factor %d (%d)\n", try[i], i);
+
+		if (this > best) {
+			scale_m = try[i];
+			mode = SMIAPP_SCALING_MODE_HORIZONTAL;
+			best = this;
+		}
+
+		if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+		    == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
+			continue;
+
+		this = scaling_goodness(
+			subdev, crops[SMIAPP_PAD_SINK]->width
+			/ try[i]
+			* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+			sel->r.width,
+			crops[SMIAPP_PAD_SINK]->height
+			/ try[i]
+			* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+			sel->r.height,
+			sel->flags);
+
+		if (this > best) {
+			scale_m = try[i];
+			mode = SMIAPP_SCALING_MODE_BOTH;
+			best = this;
+		}
+	}
+
+	sel->r.width =
+		(crops[SMIAPP_PAD_SINK]->width
+		 / scale_m
+		 * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]) & ~1;
+	if (mode == SMIAPP_SCALING_MODE_BOTH)
+		sel->r.height =
+			(crops[SMIAPP_PAD_SINK]->height
+			 / scale_m
+			 * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN])
+			& ~1;
+	else
+		sel->r.height = crops[SMIAPP_PAD_SINK]->height;
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		sensor->scale_m = scale_m;
+		sensor->scaling_mode = mode;
+	}
+}
+/* We're only called on source pads. This function sets scaling. */
+static int smiapp_set_compose(struct v4l2_subdev *subdev,
+			      struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_selection *sel)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	struct v4l2_rect *comp, *crops[SMIAPP_PADS];
+
+	smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which);
+
+	sel->r.top = 0;
+	sel->r.left = 0;
+
+	if (ssd == sensor->binner)
+		smiapp_set_compose_binner(subdev, fh, sel, crops, comp);
+	else
+		smiapp_set_compose_scaler(subdev, fh, sel, crops, comp);
+
+	*comp = sel->r;
+	smiapp_propagate(subdev, fh, sel->which,
+			 V4L2_SEL_TGT_COMPOSE);
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		return smiapp_update_mode(sensor);
+
+	return 0;
+}
+
+static int __smiapp_sel_supported(struct v4l2_subdev *subdev,
+				  struct v4l2_subdev_selection *sel)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+
+	/* We only implement crop in three places. */
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		if (ssd == sensor->pixel_array
+		    && sel->pad == SMIAPP_PA_PAD_SRC)
+			return 0;
+		if (ssd == sensor->src
+		    && sel->pad == SMIAPP_PAD_SRC)
+			return 0;
+		if (ssd == sensor->scaler
+		    && sel->pad == SMIAPP_PAD_SINK
+		    && sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+		    == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP)
+			return 0;
+		return -EINVAL;
+	case V4L2_SEL_TGT_COMPOSE:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		if (sel->pad == ssd->source_pad)
+			return -EINVAL;
+		if (ssd == sensor->binner)
+			return 0;
+		if (ssd == sensor->scaler
+		    && sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+		    != SMIAPP_SCALING_CAPABILITY_NONE)
+			return 0;
+		/* Fall through */
+	default:
+		return -EINVAL;
+	}
+}
+
+static int smiapp_set_crop(struct v4l2_subdev *subdev,
+			   struct v4l2_subdev_fh *fh,
+			   struct v4l2_subdev_selection *sel)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	struct v4l2_rect *src_size, *crops[SMIAPP_PADS];
+	struct v4l2_rect _r;
+
+	smiapp_get_crop_compose(subdev, fh, crops, NULL, sel->which);
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		if (sel->pad == ssd->sink_pad)
+			src_size = &ssd->sink_fmt;
+		else
+			src_size = &ssd->compose;
+	} else {
+		if (sel->pad == ssd->sink_pad) {
+			_r.left = 0;
+			_r.top = 0;
+			_r.width = v4l2_subdev_get_try_format(fh, sel->pad)
+				->width;
+			_r.height = v4l2_subdev_get_try_format(fh, sel->pad)
+				->height;
+			src_size = &_r;
+		} else {
+			src_size =
+				v4l2_subdev_get_try_compose(
+					fh, ssd->sink_pad);
+		}
+	}
+
+	if (ssd == sensor->src && sel->pad == SMIAPP_PAD_SRC) {
+		sel->r.left = 0;
+		sel->r.top = 0;
+	}
+
+	sel->r.width = min(sel->r.width, src_size->width);
+	sel->r.height = min(sel->r.height, src_size->height);
+
+	sel->r.left = min(sel->r.left, src_size->width - sel->r.width);
+	sel->r.top = min(sel->r.top, src_size->height - sel->r.height);
+
+	*crops[sel->pad] = sel->r;
+
+	if (ssd != sensor->pixel_array && sel->pad == SMIAPP_PAD_SINK)
+		smiapp_propagate(subdev, fh, sel->which,
+				 V4L2_SEL_TGT_CROP);
+
+	return 0;
+}
+
+static int __smiapp_get_selection(struct v4l2_subdev *subdev,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_selection *sel)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	struct v4l2_rect *comp, *crops[SMIAPP_PADS];
+	struct v4l2_rect sink_fmt;
+	int ret;
+
+	ret = __smiapp_sel_supported(subdev, sel);
+	if (ret)
+		return ret;
+
+	smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which);
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		sink_fmt = ssd->sink_fmt;
+	} else {
+		struct v4l2_mbus_framefmt *fmt =
+			v4l2_subdev_get_try_format(fh, ssd->sink_pad);
+
+		sink_fmt.left = 0;
+		sink_fmt.top = 0;
+		sink_fmt.width = fmt->width;
+		sink_fmt.height = fmt->height;
+	}
+
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		if (ssd == sensor->pixel_array) {
+			sel->r.width =
+				sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
+			sel->r.height =
+				sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
+		} else if (sel->pad == ssd->sink_pad) {
+			sel->r = sink_fmt;
+		} else {
+			sel->r = *comp;
+		}
+		break;
+	case V4L2_SEL_TGT_CROP:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		sel->r = *crops[sel->pad];
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+		sel->r = *comp;
+		break;
+	}
+
+	return 0;
+}
+
+static int smiapp_get_selection(struct v4l2_subdev *subdev,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_selection *sel)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int rval;
+
+	mutex_lock(&sensor->mutex);
+	rval = __smiapp_get_selection(subdev, fh, sel);
+	mutex_unlock(&sensor->mutex);
+
+	return rval;
+}
+static int smiapp_set_selection(struct v4l2_subdev *subdev,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_selection *sel)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int ret;
+
+	ret = __smiapp_sel_supported(subdev, sel);
+	if (ret)
+		return ret;
+
+	mutex_lock(&sensor->mutex);
+
+	sel->r.left = max(0, sel->r.left & ~1);
+	sel->r.top = max(0, sel->r.top & ~1);
+	sel->r.width = max(0, SMIAPP_ALIGN_DIM(sel->r.width, sel->flags));
+	sel->r.height = max(0, SMIAPP_ALIGN_DIM(sel->r.height, sel->flags));
+
+	sel->r.width = max_t(unsigned int,
+			     sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
+			     sel->r.width);
+	sel->r.height = max_t(unsigned int,
+			      sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
+			      sel->r.height);
+
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP:
+		ret = smiapp_set_crop(subdev, fh, sel);
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+		ret = smiapp_set_compose(subdev, fh, sel);
+		break;
+	default:
+		BUG();
+	}
+
+	mutex_unlock(&sensor->mutex);
+	return ret;
+}
+
+static int smiapp_get_skip_frames(struct v4l2_subdev *subdev, u32 *frames)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+
+	*frames = sensor->frame_skip;
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * sysfs attributes
+ */
+
+static ssize_t
+smiapp_sysfs_nvm_read(struct device *dev, struct device_attribute *attr,
+		      char *buf)
+{
+	struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev));
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	unsigned int nbytes;
+
+	if (!sensor->dev_init_done)
+		return -EBUSY;
+
+	if (!sensor->nvm_size) {
+		/* NVM not read yet - read it now */
+		sensor->nvm_size = sensor->platform_data->nvm_size;
+		if (smiapp_set_power(subdev, 1) < 0)
+			return -ENODEV;
+		if (smiapp_read_nvm(sensor, sensor->nvm)) {
+			dev_err(&client->dev, "nvm read failed\n");
+			return -ENODEV;
+		}
+		smiapp_set_power(subdev, 0);
+	}
+	/*
+	 * NVM is still way below a PAGE_SIZE, so we can safely
+	 * assume this for now.
+	 */
+	nbytes = min_t(unsigned int, sensor->nvm_size, PAGE_SIZE);
+	memcpy(buf, sensor->nvm, nbytes);
+
+	return nbytes;
+}
+static DEVICE_ATTR(nvm, S_IRUGO, smiapp_sysfs_nvm_read, NULL);
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+static int smiapp_identify_module(struct v4l2_subdev *subdev)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct smiapp_module_info *minfo = &sensor->minfo;
+	unsigned int i;
+	int rval = 0;
+
+	minfo->name = SMIAPP_NAME;
+
+	/* Module info */
+	rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_MANUFACTURER_ID,
+				 &minfo->manufacturer_id);
+	if (!rval)
+		rval = smiapp_read_8only(sensor, SMIAPP_REG_U16_MODEL_ID,
+					 &minfo->model_id);
+	if (!rval)
+		rval = smiapp_read_8only(sensor,
+					 SMIAPP_REG_U8_REVISION_NUMBER_MAJOR,
+					 &minfo->revision_number_major);
+	if (!rval)
+		rval = smiapp_read_8only(sensor,
+					 SMIAPP_REG_U8_REVISION_NUMBER_MINOR,
+					 &minfo->revision_number_minor);
+	if (!rval)
+		rval = smiapp_read_8only(sensor,
+					 SMIAPP_REG_U8_MODULE_DATE_YEAR,
+					 &minfo->module_year);
+	if (!rval)
+		rval = smiapp_read_8only(sensor,
+					 SMIAPP_REG_U8_MODULE_DATE_MONTH,
+					 &minfo->module_month);
+	if (!rval)
+		rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_MODULE_DATE_DAY,
+					 &minfo->module_day);
+
+	/* Sensor info */
+	if (!rval)
+		rval = smiapp_read_8only(sensor,
+					 SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID,
+					 &minfo->sensor_manufacturer_id);
+	if (!rval)
+		rval = smiapp_read_8only(sensor,
+					 SMIAPP_REG_U16_SENSOR_MODEL_ID,
+					 &minfo->sensor_model_id);
+	if (!rval)
+		rval = smiapp_read_8only(sensor,
+					 SMIAPP_REG_U8_SENSOR_REVISION_NUMBER,
+					 &minfo->sensor_revision_number);
+	if (!rval)
+		rval = smiapp_read_8only(sensor,
+					 SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION,
+					 &minfo->sensor_firmware_version);
+
+	/* SMIA */
+	if (!rval)
+		rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_SMIA_VERSION,
+					 &minfo->smia_version);
+	if (!rval)
+		rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_SMIAPP_VERSION,
+					 &minfo->smiapp_version);
+
+	if (rval) {
+		dev_err(&client->dev, "sensor detection failed\n");
+		return -ENODEV;
+	}
+
+	dev_dbg(&client->dev, "module 0x%2.2x-0x%4.4x\n",
+		minfo->manufacturer_id, minfo->model_id);
+
+	dev_dbg(&client->dev,
+		"module revision 0x%2.2x-0x%2.2x date %2.2d-%2.2d-%2.2d\n",
+		minfo->revision_number_major, minfo->revision_number_minor,
+		minfo->module_year, minfo->module_month, minfo->module_day);
+
+	dev_dbg(&client->dev, "sensor 0x%2.2x-0x%4.4x\n",
+		minfo->sensor_manufacturer_id, minfo->sensor_model_id);
+
+	dev_dbg(&client->dev,
+		"sensor revision 0x%2.2x firmware version 0x%2.2x\n",
+		minfo->sensor_revision_number, minfo->sensor_firmware_version);
+
+	dev_dbg(&client->dev, "smia version %2.2d smiapp version %2.2d\n",
+		minfo->smia_version, minfo->smiapp_version);
+
+	/*
+	 * Some modules have bad data in the lvalues below. Hope the
+	 * rvalues have better stuff. The lvalues are module
+	 * parameters whereas the rvalues are sensor parameters.
+	 */
+	if (!minfo->manufacturer_id && !minfo->model_id) {
+		minfo->manufacturer_id = minfo->sensor_manufacturer_id;
+		minfo->model_id = minfo->sensor_model_id;
+		minfo->revision_number_major = minfo->sensor_revision_number;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(smiapp_module_idents); i++) {
+		if (smiapp_module_idents[i].manufacturer_id
+		    != minfo->manufacturer_id)
+			continue;
+		if (smiapp_module_idents[i].model_id != minfo->model_id)
+			continue;
+		if (smiapp_module_idents[i].flags
+		    & SMIAPP_MODULE_IDENT_FLAG_REV_LE) {
+			if (smiapp_module_idents[i].revision_number_major
+			    < minfo->revision_number_major)
+				continue;
+		} else {
+			if (smiapp_module_idents[i].revision_number_major
+			    != minfo->revision_number_major)
+				continue;
+		}
+
+		minfo->name = smiapp_module_idents[i].name;
+		minfo->quirk = smiapp_module_idents[i].quirk;
+		break;
+	}
+
+	if (i >= ARRAY_SIZE(smiapp_module_idents))
+		dev_warn(&client->dev,
+			 "no quirks for this module; let's hope it's fully compliant\n");
+
+	dev_dbg(&client->dev, "the sensor is called %s, ident %2.2x%4.4x%2.2x\n",
+		minfo->name, minfo->manufacturer_id, minfo->model_id,
+		minfo->revision_number_major);
+
+	strlcpy(subdev->name, sensor->minfo.name, sizeof(subdev->name));
+
+	return 0;
+}
+
+static const struct v4l2_subdev_ops smiapp_ops;
+static const struct v4l2_subdev_internal_ops smiapp_internal_ops;
+static const struct media_entity_operations smiapp_entity_ops;
+
+static int smiapp_registered(struct v4l2_subdev *subdev)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct smiapp_subdev *last = NULL;
+	u32 tmp;
+	unsigned int i;
+	int rval;
+
+	sensor->vana = regulator_get(&client->dev, "VANA");
+	if (IS_ERR(sensor->vana)) {
+		dev_err(&client->dev, "could not get regulator for vana\n");
+		return -ENODEV;
+	}
+
+	if (!sensor->platform_data->set_xclk) {
+		sensor->ext_clk = clk_get(&client->dev,
+					  sensor->platform_data->ext_clk_name);
+		if (IS_ERR(sensor->ext_clk)) {
+			dev_err(&client->dev, "could not get clock %s\n",
+				sensor->platform_data->ext_clk_name);
+			rval = -ENODEV;
+			goto out_clk_get;
+		}
+
+		rval = clk_set_rate(sensor->ext_clk,
+				    sensor->platform_data->ext_clk);
+		if (rval < 0) {
+			dev_err(&client->dev,
+				"unable to set clock %s freq to %u\n",
+				sensor->platform_data->ext_clk_name,
+				sensor->platform_data->ext_clk);
+			rval = -ENODEV;
+			goto out_clk_set_rate;
+		}
+	}
+
+	if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) {
+		if (gpio_request_one(sensor->platform_data->xshutdown, 0,
+				     "SMIA++ xshutdown") != 0) {
+			dev_err(&client->dev,
+				"unable to acquire reset gpio %d\n",
+				sensor->platform_data->xshutdown);
+			rval = -ENODEV;
+			goto out_clk_set_rate;
+		}
+	}
+
+	rval = smiapp_power_on(sensor);
+	if (rval) {
+		rval = -ENODEV;
+		goto out_smiapp_power_on;
+	}
+
+	rval = smiapp_identify_module(subdev);
+	if (rval) {
+		rval = -ENODEV;
+		goto out_power_off;
+	}
+
+	rval = smiapp_get_all_limits(sensor);
+	if (rval) {
+		rval = -ENODEV;
+		goto out_power_off;
+	}
+
+	/*
+	 * Handle Sensor Module orientation on the board.
+	 *
+	 * The application of H-FLIP and V-FLIP on the sensor is modified by
+	 * the sensor orientation on the board.
+	 *
+	 * For SMIAPP_BOARD_SENSOR_ORIENT_180 the default behaviour is to set
+	 * both H-FLIP and V-FLIP for normal operation which also implies
+	 * that a set/unset operation for user space HFLIP and VFLIP v4l2
+	 * controls will need to be internally inverted.
+	 *
+	 * Rotation also changes the bayer pattern.
+	 */
+	if (sensor->platform_data->module_board_orient ==
+	    SMIAPP_MODULE_BOARD_ORIENT_180)
+		sensor->hvflip_inv_mask = SMIAPP_IMAGE_ORIENTATION_HFLIP |
+					  SMIAPP_IMAGE_ORIENTATION_VFLIP;
+
+	rval = smiapp_get_mbus_formats(sensor);
+	if (rval) {
+		rval = -ENODEV;
+		goto out_power_off;
+	}
+
+	if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY]) {
+		u32 val;
+
+		rval = smiapp_read(sensor,
+				   SMIAPP_REG_U8_BINNING_SUBTYPES, &val);
+		if (rval < 0) {
+			rval = -ENODEV;
+			goto out_power_off;
+		}
+		sensor->nbinning_subtypes = min_t(u8, val,
+						  SMIAPP_BINNING_SUBTYPES);
+
+		for (i = 0; i < sensor->nbinning_subtypes; i++) {
+			rval = smiapp_read(
+				sensor, SMIAPP_REG_U8_BINNING_TYPE_n(i), &val);
+			if (rval < 0) {
+				rval = -ENODEV;
+				goto out_power_off;
+			}
+			sensor->binning_subtypes[i] =
+				*(struct smiapp_binning_subtype *)&val;
+
+			dev_dbg(&client->dev, "binning %xx%x\n",
+				sensor->binning_subtypes[i].horizontal,
+				sensor->binning_subtypes[i].vertical);
+		}
+	}
+	sensor->binning_horizontal = 1;
+	sensor->binning_vertical = 1;
+
+	/* SMIA++ NVM initialization - it will be read from the sensor
+	 * when it is first requested by userspace.
+	 */
+	if (sensor->minfo.smiapp_version && sensor->platform_data->nvm_size) {
+		sensor->nvm = kzalloc(sensor->platform_data->nvm_size,
+				      GFP_KERNEL);
+		if (sensor->nvm == NULL) {
+			dev_err(&client->dev, "nvm buf allocation failed\n");
+			rval = -ENOMEM;
+			goto out_power_off;
+		}
+
+		if (device_create_file(&client->dev, &dev_attr_nvm) != 0) {
+			dev_err(&client->dev, "sysfs nvm entry failed\n");
+			rval = -EBUSY;
+			goto out_power_off;
+		}
+	}
+
+	rval = smiapp_call_quirk(sensor, limits);
+	if (rval) {
+		dev_err(&client->dev, "limits quirks failed\n");
+		goto out_nvm_release;
+	}
+
+	/* We consider this as profile 0 sensor if any of these are zero. */
+	if (!sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV] ||
+	    !sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV] ||
+	    !sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV] ||
+	    !sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV]) {
+		sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0;
+	} else if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+		   != SMIAPP_SCALING_CAPABILITY_NONE) {
+		if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+		    == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
+			sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1;
+		else
+			sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2;
+		sensor->scaler = &sensor->ssds[sensor->ssds_used];
+		sensor->ssds_used++;
+	} else if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+		   == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
+		sensor->scaler = &sensor->ssds[sensor->ssds_used];
+		sensor->ssds_used++;
+	}
+	sensor->binner = &sensor->ssds[sensor->ssds_used];
+	sensor->ssds_used++;
+	sensor->pixel_array = &sensor->ssds[sensor->ssds_used];
+	sensor->ssds_used++;
+
+	sensor->scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+
+	for (i = 0; i < SMIAPP_SUBDEVS; i++) {
+		struct {
+			struct smiapp_subdev *ssd;
+			char *name;
+		} const __this[] = {
+			{ sensor->scaler, "scaler", },
+			{ sensor->binner, "binner", },
+			{ sensor->pixel_array, "pixel array", },
+		}, *_this = &__this[i];
+		struct smiapp_subdev *this = _this->ssd;
+
+		if (!this)
+			continue;
+
+		if (this != sensor->src)
+			v4l2_subdev_init(&this->sd, &smiapp_ops);
+
+		this->sensor = sensor;
+
+		if (this == sensor->pixel_array) {
+			this->npads = 1;
+		} else {
+			this->npads = 2;
+			this->source_pad = 1;
+		}
+
+		snprintf(this->sd.name,
+			 sizeof(this->sd.name), "%s %s",
+			 sensor->minfo.name, _this->name);
+
+		this->sink_fmt.width =
+			sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
+		this->sink_fmt.height =
+			sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
+		this->compose.width = this->sink_fmt.width;
+		this->compose.height = this->sink_fmt.height;
+		this->crop[this->source_pad] = this->compose;
+		this->pads[this->source_pad].flags = MEDIA_PAD_FL_SOURCE;
+		if (this != sensor->pixel_array) {
+			this->crop[this->sink_pad] = this->compose;
+			this->pads[this->sink_pad].flags = MEDIA_PAD_FL_SINK;
+		}
+
+		this->sd.entity.ops = &smiapp_entity_ops;
+
+		if (last == NULL) {
+			last = this;
+			continue;
+		}
+
+		this->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+		this->sd.internal_ops = &smiapp_internal_ops;
+		this->sd.owner = NULL;
+		v4l2_set_subdevdata(&this->sd, client);
+
+		rval = media_entity_init(&this->sd.entity,
+					 this->npads, this->pads, 0);
+		if (rval) {
+			dev_err(&client->dev,
+				"media_entity_init failed\n");
+			goto out_nvm_release;
+		}
+
+		rval = media_entity_create_link(&this->sd.entity,
+						this->source_pad,
+						&last->sd.entity,
+						last->sink_pad,
+						MEDIA_LNK_FL_ENABLED |
+						MEDIA_LNK_FL_IMMUTABLE);
+		if (rval) {
+			dev_err(&client->dev,
+				"media_entity_create_link failed\n");
+			goto out_nvm_release;
+		}
+
+		rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev,
+						   &this->sd);
+		if (rval) {
+			dev_err(&client->dev,
+				"v4l2_device_register_subdev failed\n");
+			goto out_nvm_release;
+		}
+
+		last = this;
+	}
+
+	dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile);
+
+	sensor->pixel_array->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+
+	/* final steps */
+	smiapp_read_frame_fmt(sensor);
+	rval = smiapp_init_controls(sensor);
+	if (rval < 0)
+		goto out_nvm_release;
+
+	rval = smiapp_update_mode(sensor);
+	if (rval) {
+		dev_err(&client->dev, "update mode failed\n");
+		goto out_nvm_release;
+	}
+
+	sensor->streaming = false;
+	sensor->dev_init_done = true;
+
+	/* check flash capability */
+	rval = smiapp_read(sensor, SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, &tmp);
+	sensor->flash_capability = tmp;
+	if (rval)
+		goto out_nvm_release;
+
+	smiapp_power_off(sensor);
+
+	return 0;
+
+out_nvm_release:
+	device_remove_file(&client->dev, &dev_attr_nvm);
+
+out_power_off:
+	kfree(sensor->nvm);
+	sensor->nvm = NULL;
+	smiapp_power_off(sensor);
+
+out_smiapp_power_on:
+	if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+		gpio_free(sensor->platform_data->xshutdown);
+
+out_clk_set_rate:
+	clk_put(sensor->ext_clk);
+	sensor->ext_clk = NULL;
+
+out_clk_get:
+	regulator_put(sensor->vana);
+	sensor->vana = NULL;
+	return rval;
+}
+
+static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct smiapp_subdev *ssd = to_smiapp_subdev(sd);
+	struct smiapp_sensor *sensor = ssd->sensor;
+	u32 mbus_code =
+		smiapp_csi_data_formats[smiapp_pixel_order(sensor)].code;
+	unsigned int i;
+
+	mutex_lock(&sensor->mutex);
+
+	for (i = 0; i < ssd->npads; i++) {
+		struct v4l2_mbus_framefmt *try_fmt =
+			v4l2_subdev_get_try_format(fh, i);
+		struct v4l2_rect *try_crop = v4l2_subdev_get_try_crop(fh, i);
+		struct v4l2_rect *try_comp;
+
+		try_fmt->width = sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
+		try_fmt->height = sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
+		try_fmt->code = mbus_code;
+
+		try_crop->top = 0;
+		try_crop->left = 0;
+		try_crop->width = try_fmt->width;
+		try_crop->height = try_fmt->height;
+
+		if (ssd != sensor->pixel_array)
+			continue;
+
+		try_comp = v4l2_subdev_get_try_compose(fh, i);
+		*try_comp = *try_crop;
+	}
+
+	mutex_unlock(&sensor->mutex);
+
+	return smiapp_set_power(sd, 1);
+}
+
+static int smiapp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	return smiapp_set_power(sd, 0);
+}
+
+static const struct v4l2_subdev_video_ops smiapp_video_ops = {
+	.s_stream = smiapp_set_stream,
+};
+
+static const struct v4l2_subdev_core_ops smiapp_core_ops = {
+	.s_power = smiapp_set_power,
+};
+
+static const struct v4l2_subdev_pad_ops smiapp_pad_ops = {
+	.enum_mbus_code = smiapp_enum_mbus_code,
+	.get_fmt = smiapp_get_format,
+	.set_fmt = smiapp_set_format,
+	.get_selection = smiapp_get_selection,
+	.set_selection = smiapp_set_selection,
+};
+
+static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = {
+	.g_skip_frames = smiapp_get_skip_frames,
+};
+
+static const struct v4l2_subdev_ops smiapp_ops = {
+	.core = &smiapp_core_ops,
+	.video = &smiapp_video_ops,
+	.pad = &smiapp_pad_ops,
+	.sensor = &smiapp_sensor_ops,
+};
+
+static const struct media_entity_operations smiapp_entity_ops = {
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_internal_ops smiapp_internal_src_ops = {
+	.registered = smiapp_registered,
+	.open = smiapp_open,
+	.close = smiapp_close,
+};
+
+static const struct v4l2_subdev_internal_ops smiapp_internal_ops = {
+	.open = smiapp_open,
+	.close = smiapp_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * I2C Driver
+ */
+
+#ifdef CONFIG_PM
+
+static int smiapp_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	bool streaming;
+
+	BUG_ON(mutex_is_locked(&sensor->mutex));
+
+	if (sensor->power_count == 0)
+		return 0;
+
+	if (sensor->streaming)
+		smiapp_stop_streaming(sensor);
+
+	streaming = sensor->streaming;
+
+	smiapp_power_off(sensor);
+
+	/* save state for resume */
+	sensor->streaming = streaming;
+
+	return 0;
+}
+
+static int smiapp_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int rval;
+
+	if (sensor->power_count == 0)
+		return 0;
+
+	rval = smiapp_power_on(sensor);
+	if (rval)
+		return rval;
+
+	if (sensor->streaming)
+		rval = smiapp_start_streaming(sensor);
+
+	return rval;
+}
+
+#else
+
+#define smiapp_suspend	NULL
+#define smiapp_resume	NULL
+
+#endif /* CONFIG_PM */
+
+static int smiapp_probe(struct i2c_client *client,
+			const struct i2c_device_id *devid)
+{
+	struct smiapp_sensor *sensor;
+	int rval;
+
+	if (client->dev.platform_data == NULL)
+		return -ENODEV;
+
+	sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
+	if (sensor == NULL)
+		return -ENOMEM;
+
+	sensor->platform_data = client->dev.platform_data;
+	mutex_init(&sensor->mutex);
+	mutex_init(&sensor->power_mutex);
+	sensor->src = &sensor->ssds[sensor->ssds_used];
+
+	v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops);
+	sensor->src->sd.internal_ops = &smiapp_internal_src_ops;
+	sensor->src->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	sensor->src->sensor = sensor;
+
+	sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE;
+	rval = media_entity_init(&sensor->src->sd.entity, 2,
+				 sensor->src->pads, 0);
+	if (rval < 0)
+		kfree(sensor);
+
+	return rval;
+}
+
+static int __exit smiapp_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	unsigned int i;
+
+	if (sensor->power_count) {
+		if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+			gpio_set_value(sensor->platform_data->xshutdown, 0);
+		if (sensor->platform_data->set_xclk)
+			sensor->platform_data->set_xclk(&sensor->src->sd, 0);
+		else
+			clk_disable(sensor->ext_clk);
+		sensor->power_count = 0;
+	}
+
+	if (sensor->nvm) {
+		device_remove_file(&client->dev, &dev_attr_nvm);
+		kfree(sensor->nvm);
+	}
+
+	for (i = 0; i < sensor->ssds_used; i++) {
+		media_entity_cleanup(&sensor->ssds[i].sd.entity);
+		v4l2_device_unregister_subdev(&sensor->ssds[i].sd);
+	}
+	smiapp_free_controls(sensor);
+	if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+		gpio_free(sensor->platform_data->xshutdown);
+	if (sensor->ext_clk)
+		clk_put(sensor->ext_clk);
+	if (sensor->vana)
+		regulator_put(sensor->vana);
+
+	kfree(sensor);
+
+	return 0;
+}
+
+static const struct i2c_device_id smiapp_id_table[] = {
+	{ SMIAPP_NAME, 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, smiapp_id_table);
+
+static const struct dev_pm_ops smiapp_pm_ops = {
+	.suspend	= smiapp_suspend,
+	.resume		= smiapp_resume,
+};
+
+static struct i2c_driver smiapp_i2c_driver = {
+	.driver	= {
+		.name = SMIAPP_NAME,
+		.pm = &smiapp_pm_ops,
+	},
+	.probe	= smiapp_probe,
+	.remove	= __exit_p(smiapp_remove),
+	.id_table = smiapp_id_table,
+};
+
+module_i2c_driver(smiapp_i2c_driver);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>");
+MODULE_DESCRIPTION("Generic SMIA/SMIA++ camera module driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/smiapp/smiapp-limits.c b/drivers/media/i2c/smiapp/smiapp-limits.c
new file mode 100644
index 0000000..fb2f81a
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp-limits.c
@@ -0,0 +1,132 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp-limits.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "smiapp.h"
+
+struct smiapp_reg_limits smiapp_reg_limits[] = {
+	{ SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY, "analogue_gain_capability" }, /* 0 */
+	{ SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN, "analogue_gain_code_min" },
+	{ SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX, "analogue_gain_code_max" },
+	{ SMIAPP_REG_U8_THS_ZERO_MIN, "ths_zero_min" },
+	{ SMIAPP_REG_U8_TCLK_TRAIL_MIN, "tclk_trail_min" },
+	{ SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY, "integration_time_capability" }, /* 5 */
+	{ SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN, "coarse_integration_time_min" },
+	{ SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN, "coarse_integration_time_max_margin" },
+	{ SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN, "fine_integration_time_min" },
+	{ SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN, "fine_integration_time_max_margin" },
+	{ SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY, "digital_gain_capability" }, /* 10 */
+	{ SMIAPP_REG_U16_DIGITAL_GAIN_MIN, "digital_gain_min" },
+	{ SMIAPP_REG_U16_DIGITAL_GAIN_MAX, "digital_gain_max" },
+	{ SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ, "min_ext_clk_freq_hz" },
+	{ SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ, "max_ext_clk_freq_hz" },
+	{ SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV, "min_pre_pll_clk_div" }, /* 15 */
+	{ SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV, "max_pre_pll_clk_div" },
+	{ SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ, "min_pll_ip_freq_hz" },
+	{ SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ, "max_pll_ip_freq_hz" },
+	{ SMIAPP_REG_U16_MIN_PLL_MULTIPLIER, "min_pll_multiplier" },
+	{ SMIAPP_REG_U16_MAX_PLL_MULTIPLIER, "max_pll_multiplier" }, /* 20 */
+	{ SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ, "min_pll_op_freq_hz" },
+	{ SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ, "max_pll_op_freq_hz" },
+	{ SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV, "min_vt_sys_clk_div" },
+	{ SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV, "max_vt_sys_clk_div" },
+	{ SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ, "min_vt_sys_clk_freq_hz" }, /* 25 */
+	{ SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ, "max_vt_sys_clk_freq_hz" },
+	{ SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ, "min_vt_pix_clk_freq_hz" },
+	{ SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ, "max_vt_pix_clk_freq_hz" },
+	{ SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV, "min_vt_pix_clk_div" },
+	{ SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV, "max_vt_pix_clk_div" }, /* 30 */
+	{ SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES, "min_frame_length_lines" },
+	{ SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES, "max_frame_length_lines" },
+	{ SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK, "min_line_length_pck" },
+	{ SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK, "max_line_length_pck" },
+	{ SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK, "min_line_blanking_pck" }, /* 35 */
+	{ SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES, "min_frame_blanking_lines" },
+	{ SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE, "min_line_length_pck_step_size" },
+	{ SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV, "min_op_sys_clk_div" },
+	{ SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV, "max_op_sys_clk_div" },
+	{ SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ, "min_op_sys_clk_freq_hz" }, /* 40 */
+	{ SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ, "max_op_sys_clk_freq_hz" },
+	{ SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV, "min_op_pix_clk_div" },
+	{ SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV, "max_op_pix_clk_div" },
+	{ SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ, "min_op_pix_clk_freq_hz" },
+	{ SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ, "max_op_pix_clk_freq_hz" }, /* 45 */
+	{ SMIAPP_REG_U16_X_ADDR_MIN, "x_addr_min" },
+	{ SMIAPP_REG_U16_Y_ADDR_MIN, "y_addr_min" },
+	{ SMIAPP_REG_U16_X_ADDR_MAX, "x_addr_max" },
+	{ SMIAPP_REG_U16_Y_ADDR_MAX, "y_addr_max" },
+	{ SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE, "min_x_output_size" }, /* 50 */
+	{ SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE, "min_y_output_size" },
+	{ SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE, "max_x_output_size" },
+	{ SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE, "max_y_output_size" },
+	{ SMIAPP_REG_U16_MIN_EVEN_INC, "min_even_inc" },
+	{ SMIAPP_REG_U16_MAX_EVEN_INC, "max_even_inc" }, /* 55 */
+	{ SMIAPP_REG_U16_MIN_ODD_INC, "min_odd_inc" },
+	{ SMIAPP_REG_U16_MAX_ODD_INC, "max_odd_inc" },
+	{ SMIAPP_REG_U16_SCALING_CAPABILITY, "scaling_capability" },
+	{ SMIAPP_REG_U16_SCALER_M_MIN, "scaler_m_min" },
+	{ SMIAPP_REG_U16_SCALER_M_MAX, "scaler_m_max" }, /* 60 */
+	{ SMIAPP_REG_U16_SCALER_N_MIN, "scaler_n_min" },
+	{ SMIAPP_REG_U16_SCALER_N_MAX, "scaler_n_max" },
+	{ SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY, "spatial_sampling_capability" },
+	{ SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY, "digital_crop_capability" },
+	{ SMIAPP_REG_U16_COMPRESSION_CAPABILITY, "compression_capability" }, /* 65 */
+	{ SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY, "fifo_support_capability" },
+	{ SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY, "dphy_ctrl_capability" },
+	{ SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY, "csi_lane_mode_capability" },
+	{ SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY, "csi_signalling_mode_capability" },
+	{ SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY, "fast_standby_capability" }, /* 70 */
+	{ SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY, "cci_address_control_capability" },
+	{ SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS, "max_per_lane_bitrate_1_lane_mode_mbps" },
+	{ SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS, "max_per_lane_bitrate_2_lane_mode_mbps" },
+	{ SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS, "max_per_lane_bitrate_3_lane_mode_mbps" },
+	{ SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS, "max_per_lane_bitrate_4_lane_mode_mbps" }, /* 75 */
+	{ SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY, "temp_sensor_capability" },
+	{ SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN, "min_frame_length_lines_bin" },
+	{ SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN, "max_frame_length_lines_bin" },
+	{ SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN, "min_line_length_pck_bin" },
+	{ SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN, "max_line_length_pck_bin" }, /* 80 */
+	{ SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN, "min_line_blanking_pck_bin" },
+	{ SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN, "fine_integration_time_min_bin" },
+	{ SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN, "fine_integration_time_max_margin_bin" },
+	{ SMIAPP_REG_U8_BINNING_CAPABILITY, "binning_capability" },
+	{ SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY, "binning_weighting_capability" }, /* 85 */
+	{ SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY, "data_transfer_if_capability" },
+	{ SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY, "shading_correction_capability" },
+	{ SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY, "green_imbalance_capability" },
+	{ SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY, "black_level_capability" },
+	{ SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY, "module_specific_correction_capability" }, /* 90 */
+	{ SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY, "defect_correction_capability" },
+	{ SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2, "defect_correction_capability_2" },
+	{ SMIAPP_REG_U8_EDOF_CAPABILITY, "edof_capability" },
+	{ SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY, "colour_feedback_capability" },
+	{ SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY, "estimation_mode_capability" }, /* 95 */
+	{ SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY, "estimation_zone_capability" },
+	{ SMIAPP_REG_U16_CAPABILITY_TRDY_MIN, "capability_trdy_min" },
+	{ SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, "flash_mode_capability" },
+	{ SMIAPP_REG_U8_ACTUATOR_CAPABILITY, "actuator_capability" },
+	{ SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1, "bracketing_lut_capability_1" }, /* 100 */
+	{ SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2, "bracketing_lut_capability_2" },
+	{ SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP, "analogue_gain_code_step" },
+	{ 0, NULL },
+};
diff --git a/drivers/media/i2c/smiapp/smiapp-limits.h b/drivers/media/i2c/smiapp/smiapp-limits.h
new file mode 100644
index 0000000..9ae765e
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp-limits.h
@@ -0,0 +1,128 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp-limits.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CAPABILITY			0
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN			1
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX			2
+#define SMIAPP_LIMIT_THS_ZERO_MIN				3
+#define SMIAPP_LIMIT_TCLK_TRAIL_MIN				4
+#define SMIAPP_LIMIT_INTEGRATION_TIME_CAPABILITY		5
+#define SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MIN		6
+#define SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN		7
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN			8
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN		9
+#define SMIAPP_LIMIT_DIGITAL_GAIN_CAPABILITY			10
+#define SMIAPP_LIMIT_DIGITAL_GAIN_MIN				11
+#define SMIAPP_LIMIT_DIGITAL_GAIN_MAX				12
+#define SMIAPP_LIMIT_MIN_EXT_CLK_FREQ_HZ			13
+#define SMIAPP_LIMIT_MAX_EXT_CLK_FREQ_HZ			14
+#define SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV			15
+#define SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV			16
+#define SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ				17
+#define SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ				18
+#define SMIAPP_LIMIT_MIN_PLL_MULTIPLIER				19
+#define SMIAPP_LIMIT_MAX_PLL_MULTIPLIER				20
+#define SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ				21
+#define SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ				22
+#define SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV				23
+#define SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV				24
+#define SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ			25
+#define SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ			26
+#define SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ			27
+#define SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ			28
+#define SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV				29
+#define SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV				30
+#define SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES			31
+#define SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES			32
+#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK			33
+#define SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK			34
+#define SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK			35
+#define SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES			36
+#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_STEP_SIZE		37
+#define SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV				38
+#define SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV				39
+#define SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ			40
+#define SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ			41
+#define SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV				42
+#define SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV				43
+#define SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ			44
+#define SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ			45
+#define SMIAPP_LIMIT_X_ADDR_MIN					46
+#define SMIAPP_LIMIT_Y_ADDR_MIN					47
+#define SMIAPP_LIMIT_X_ADDR_MAX					48
+#define SMIAPP_LIMIT_Y_ADDR_MAX					49
+#define SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE				50
+#define SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE				51
+#define SMIAPP_LIMIT_MAX_X_OUTPUT_SIZE				52
+#define SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE				53
+#define SMIAPP_LIMIT_MIN_EVEN_INC				54
+#define SMIAPP_LIMIT_MAX_EVEN_INC				55
+#define SMIAPP_LIMIT_MIN_ODD_INC				56
+#define SMIAPP_LIMIT_MAX_ODD_INC				57
+#define SMIAPP_LIMIT_SCALING_CAPABILITY				58
+#define SMIAPP_LIMIT_SCALER_M_MIN				59
+#define SMIAPP_LIMIT_SCALER_M_MAX				60
+#define SMIAPP_LIMIT_SCALER_N_MIN				61
+#define SMIAPP_LIMIT_SCALER_N_MAX				62
+#define SMIAPP_LIMIT_SPATIAL_SAMPLING_CAPABILITY		63
+#define SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY			64
+#define SMIAPP_LIMIT_COMPRESSION_CAPABILITY			65
+#define SMIAPP_LIMIT_FIFO_SUPPORT_CAPABILITY			66
+#define SMIAPP_LIMIT_DPHY_CTRL_CAPABILITY			67
+#define SMIAPP_LIMIT_CSI_LANE_MODE_CAPABILITY			68
+#define SMIAPP_LIMIT_CSI_SIGNALLING_MODE_CAPABILITY		69
+#define SMIAPP_LIMIT_FAST_STANDBY_CAPABILITY			70
+#define SMIAPP_LIMIT_CCI_ADDRESS_CONTROL_CAPABILITY		71
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS	72
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS	73
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS	74
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS	75
+#define SMIAPP_LIMIT_TEMP_SENSOR_CAPABILITY			76
+#define SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN			77
+#define SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN			78
+#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN			79
+#define SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN			80
+#define SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN			81
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN_BIN		82
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN	83
+#define SMIAPP_LIMIT_BINNING_CAPABILITY				84
+#define SMIAPP_LIMIT_BINNING_WEIGHTING_CAPABILITY		85
+#define SMIAPP_LIMIT_DATA_TRANSFER_IF_CAPABILITY		86
+#define SMIAPP_LIMIT_SHADING_CORRECTION_CAPABILITY		87
+#define SMIAPP_LIMIT_GREEN_IMBALANCE_CAPABILITY			88
+#define SMIAPP_LIMIT_BLACK_LEVEL_CAPABILITY			89
+#define SMIAPP_LIMIT_MODULE_SPECIFIC_CORRECTION_CAPABILITY	90
+#define SMIAPP_LIMIT_DEFECT_CORRECTION_CAPABILITY		91
+#define SMIAPP_LIMIT_DEFECT_CORRECTION_CAPABILITY_2		92
+#define SMIAPP_LIMIT_EDOF_CAPABILITY				93
+#define SMIAPP_LIMIT_COLOUR_FEEDBACK_CAPABILITY			94
+#define SMIAPP_LIMIT_ESTIMATION_MODE_CAPABILITY			95
+#define SMIAPP_LIMIT_ESTIMATION_ZONE_CAPABILITY			96
+#define SMIAPP_LIMIT_CAPABILITY_TRDY_MIN			97
+#define SMIAPP_LIMIT_FLASH_MODE_CAPABILITY			98
+#define SMIAPP_LIMIT_ACTUATOR_CAPABILITY			99
+#define SMIAPP_LIMIT_BRACKETING_LUT_CAPABILITY_1		100
+#define SMIAPP_LIMIT_BRACKETING_LUT_CAPABILITY_2		101
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP			102
+#define SMIAPP_LIMIT_LAST					103
diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c
new file mode 100644
index 0000000..cf04812
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp-quirk.c
@@ -0,0 +1,306 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp-quirk.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/delay.h>
+
+#include "smiapp.h"
+
+static int smiapp_write_8(struct smiapp_sensor *sensor, u16 reg, u8 val)
+{
+	return smiapp_write(sensor, (SMIA_REG_8BIT << 16) | reg, val);
+}
+
+static int smiapp_write_8s(struct smiapp_sensor *sensor,
+			   struct smiapp_reg_8 *regs, int len)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int rval;
+
+	for (; len > 0; len--, regs++) {
+		rval = smiapp_write_8(sensor, regs->reg, regs->val);
+		if (rval < 0) {
+			dev_err(&client->dev,
+				"error %d writing reg 0x%4.4x, val 0x%2.2x",
+				rval, regs->reg, regs->val);
+			return rval;
+		}
+	}
+
+	return 0;
+}
+
+void smiapp_replace_limit(struct smiapp_sensor *sensor,
+			  u32 limit, u32 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+
+	dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" = %d, 0x%x\n",
+		smiapp_reg_limits[limit].addr,
+		smiapp_reg_limits[limit].what, val, val);
+	sensor->limits[limit] = val;
+}
+
+int smiapp_replace_limit_at(struct smiapp_sensor *sensor,
+			    u32 reg, u32 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int i;
+
+	for (i = 0; smiapp_reg_limits[i].addr; i++) {
+		if ((smiapp_reg_limits[i].addr & 0xffff) != reg)
+			continue;
+
+		smiapp_replace_limit(sensor, i, val);
+
+		return 0;
+	}
+
+	dev_dbg(&client->dev, "quirk: bad register 0x%4.4x\n", reg);
+
+	return -EINVAL;
+}
+
+bool smiapp_quirk_reg(struct smiapp_sensor *sensor,
+		      u32 reg, u32 *val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	const struct smia_reg *sreg;
+
+	if (!sensor->minfo.quirk)
+		return false;
+
+	sreg = sensor->minfo.quirk->regs;
+
+	if (!sreg)
+		return false;
+
+	while (sreg->type) {
+		u16 type = reg >> 16;
+		u16 reg16 = reg;
+
+		if (sreg->type != type || sreg->reg != reg16) {
+			sreg++;
+			continue;
+		}
+
+		switch ((u8)type) {
+		case SMIA_REG_8BIT:
+			dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%2.2x\n",
+				reg, sreg->val);
+			break;
+		case SMIA_REG_16BIT:
+			dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%4.4x\n",
+				reg, sreg->val);
+			break;
+		case SMIA_REG_32BIT:
+			dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%8.8x\n",
+				reg, sreg->val);
+			break;
+		}
+
+		*val = sreg->val;
+
+		return true;
+	}
+
+	return false;
+}
+
+static int jt8ew9_limits(struct smiapp_sensor *sensor)
+{
+	if (sensor->minfo.revision_number_major < 0x03)
+		sensor->frame_skip = 1;
+
+	/* Below 24 gain doesn't have effect at all, */
+	/* but ~59 is needed for full dynamic range */
+	smiapp_replace_limit(sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN, 59);
+	smiapp_replace_limit(
+		sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX, 6000);
+
+	return 0;
+}
+
+static int jt8ew9_post_poweron(struct smiapp_sensor *sensor)
+{
+	struct smiapp_reg_8 regs[] = {
+		{ 0x30a3, 0xd8 }, /* Output port control : LVDS ports only */
+		{ 0x30ae, 0x00 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */
+		{ 0x30af, 0xd0 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */
+		{ 0x322d, 0x04 }, /* Adjusting Processing Image Size to Scaler Toshiba Recommendation Setting */
+		{ 0x3255, 0x0f }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
+		{ 0x3256, 0x15 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
+		{ 0x3258, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */
+		{ 0x3259, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */
+		{ 0x325f, 0x7c }, /* Analog Gain Control Toshiba Recommendation Setting */
+		{ 0x3302, 0x06 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+		{ 0x3304, 0x00 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+		{ 0x3307, 0x22 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+		{ 0x3308, 0x8d }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+		{ 0x331e, 0x0f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x3320, 0x30 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x3321, 0x11 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x3322, 0x98 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x3323, 0x64 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x3325, 0x83 }, /* Read Out Timing Control Toshiba Recommendation Setting */
+		{ 0x3330, 0x18 }, /* Read Out Timing Control Toshiba Recommendation Setting */
+		{ 0x333c, 0x01 }, /* Read Out Timing Control Toshiba Recommendation Setting */
+		{ 0x3345, 0x2f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x33de, 0x38 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
+		/* Taken from v03. No idea what the rest are. */
+		{ 0x32e0, 0x05 },
+		{ 0x32e1, 0x05 },
+		{ 0x32e2, 0x04 },
+		{ 0x32e5, 0x04 },
+		{ 0x32e6, 0x04 },
+
+	};
+
+	return smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
+}
+
+const struct smiapp_quirk smiapp_jt8ew9_quirk = {
+	.limits = jt8ew9_limits,
+	.post_poweron = jt8ew9_post_poweron,
+};
+
+static int imx125es_post_poweron(struct smiapp_sensor *sensor)
+{
+	/* Taken from v02. No idea what the other two are. */
+	struct smiapp_reg_8 regs[] = {
+		/*
+		 * 0x3302: clk during frame blanking:
+		 * 0x00 - HS mode, 0x01 - LP11
+		 */
+		{ 0x3302, 0x01 },
+		{ 0x302d, 0x00 },
+		{ 0x3b08, 0x8c },
+	};
+
+	return smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
+}
+
+const struct smiapp_quirk smiapp_imx125es_quirk = {
+	.post_poweron = imx125es_post_poweron,
+};
+
+static int jt8ev1_limits(struct smiapp_sensor *sensor)
+{
+	smiapp_replace_limit(sensor, SMIAPP_LIMIT_X_ADDR_MAX, 4271);
+	smiapp_replace_limit(sensor,
+			     SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN, 184);
+
+	return 0;
+}
+
+static int jt8ev1_post_poweron(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int rval;
+
+	struct smiapp_reg_8 regs[] = {
+		{ 0x3031, 0xcd }, /* For digital binning (EQ_MONI) */
+		{ 0x30a3, 0xd0 }, /* FLASH STROBE enable */
+		{ 0x3237, 0x00 }, /* For control of pulse timing for ADC */
+		{ 0x3238, 0x43 },
+		{ 0x3301, 0x06 }, /* For analog bias for sensor */
+		{ 0x3302, 0x06 },
+		{ 0x3304, 0x00 },
+		{ 0x3305, 0x88 },
+		{ 0x332a, 0x14 },
+		{ 0x332c, 0x6b },
+		{ 0x3336, 0x01 },
+		{ 0x333f, 0x1f },
+		{ 0x3355, 0x00 },
+		{ 0x3356, 0x20 },
+		{ 0x33bf, 0x20 }, /* Adjust the FBC speed */
+		{ 0x33c9, 0x20 },
+		{ 0x33ce, 0x30 }, /* Adjust the parameter for logic function */
+		{ 0x33cf, 0xec }, /* For Black sun */
+		{ 0x3328, 0x80 }, /* Ugh. No idea what's this. */
+	};
+
+	struct smiapp_reg_8 regs_96[] = {
+		{ 0x30ae, 0x00 }, /* For control of ADC clock */
+		{ 0x30af, 0xd0 },
+		{ 0x30b0, 0x01 },
+	};
+
+	rval = smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
+	if (rval < 0)
+		return rval;
+
+	switch (sensor->platform_data->ext_clk) {
+	case 9600000:
+		return smiapp_write_8s(sensor, regs_96,
+				       ARRAY_SIZE(regs_96));
+	default:
+		dev_warn(&client->dev, "no MSRs for %d Hz ext_clk\n",
+			 sensor->platform_data->ext_clk);
+		return 0;
+	}
+}
+
+static int jt8ev1_pre_streamon(struct smiapp_sensor *sensor)
+{
+	return smiapp_write_8(sensor, 0x3328, 0x00);
+}
+
+static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor)
+{
+	int rval;
+
+	/* Workaround: allows fast standby to work properly */
+	rval = smiapp_write_8(sensor, 0x3205, 0x04);
+	if (rval < 0)
+		return rval;
+
+	/* Wait for 1 ms + one line => 2 ms is likely enough */
+	usleep_range(2000, 2000);
+
+	/* Restore it */
+	rval = smiapp_write_8(sensor, 0x3205, 0x00);
+	if (rval < 0)
+		return rval;
+
+	return smiapp_write_8(sensor, 0x3328, 0x80);
+}
+
+const struct smiapp_quirk smiapp_jt8ev1_quirk = {
+	.limits = jt8ev1_limits,
+	.post_poweron = jt8ev1_post_poweron,
+	.pre_streamon = jt8ev1_pre_streamon,
+	.post_streamoff = jt8ev1_post_streamoff,
+	.flags = SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE,
+};
+
+static int tcm8500md_limits(struct smiapp_sensor *sensor)
+{
+	smiapp_replace_limit(sensor, SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ, 2700000);
+
+	return 0;
+}
+
+const struct smiapp_quirk smiapp_tcm8500md_quirk = {
+	.limits = tcm8500md_limits,
+};
diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.h b/drivers/media/i2c/smiapp/smiapp-quirk.h
new file mode 100644
index 0000000..86fd3e8
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp-quirk.h
@@ -0,0 +1,83 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp-quirk.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __SMIAPP_QUIRK__
+#define __SMIAPP_QUIRK__
+
+struct smiapp_sensor;
+
+/**
+ * struct smiapp_quirk - quirks for sensors that deviate from SMIA++ standard
+ *
+ * @limits: Replace sensor->limits with values which can't be read from
+ *	    sensor registers. Called the first time the sensor is powered up.
+ * @post_poweron: Called always after the sensor has been fully powered on.
+ * @pre_streamon: Called just before streaming is enabled.
+ * @post_streamon: Called right after stopping streaming.
+ */
+struct smiapp_quirk {
+	int (*limits)(struct smiapp_sensor *sensor);
+	int (*post_poweron)(struct smiapp_sensor *sensor);
+	int (*pre_streamon)(struct smiapp_sensor *sensor);
+	int (*post_streamoff)(struct smiapp_sensor *sensor);
+	const struct smia_reg *regs;
+	unsigned long flags;
+};
+
+/* op pix clock is for all lanes in total normally */
+#define SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE			(1 << 0)
+#define SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY			(1 << 1)
+
+struct smiapp_reg_8 {
+	u16 reg;
+	u8 val;
+};
+
+void smiapp_replace_limit(struct smiapp_sensor *sensor,
+			  u32 limit, u32 val);
+bool smiapp_quirk_reg(struct smiapp_sensor *sensor,
+		      u32 reg, u32 *val);
+
+#define SMIAPP_MK_QUIRK_REG(_reg, _val) \
+	{				\
+		.type = (_reg >> 16),	\
+		.reg = (u16)_reg,	\
+		.val = _val,		\
+	}
+
+#define smiapp_call_quirk(_sensor, _quirk, ...)				\
+	(_sensor->minfo.quirk &&					\
+	 _sensor->minfo.quirk->_quirk ?					\
+	 _sensor->minfo.quirk->_quirk(_sensor, ##__VA_ARGS__) : 0)
+
+#define smiapp_needs_quirk(_sensor, _quirk)		\
+	(_sensor->minfo.quirk ?				\
+	 _sensor->minfo.quirk->flags & _quirk : 0)
+
+extern const struct smiapp_quirk smiapp_jt8ev1_quirk;
+extern const struct smiapp_quirk smiapp_imx125es_quirk;
+extern const struct smiapp_quirk smiapp_jt8ew9_quirk;
+extern const struct smiapp_quirk smiapp_tcm8500md_quirk;
+
+#endif /* __SMIAPP_QUIRK__ */
diff --git a/drivers/media/i2c/smiapp/smiapp-reg-defs.h b/drivers/media/i2c/smiapp/smiapp-reg-defs.h
new file mode 100644
index 0000000..defa7c5
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp-reg-defs.h
@@ -0,0 +1,503 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp-reg-defs.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#define SMIAPP_REG_MK_U8(r) ((SMIA_REG_8BIT << 16) | (r))
+#define SMIAPP_REG_MK_U16(r) ((SMIA_REG_16BIT << 16) | (r))
+#define SMIAPP_REG_MK_U32(r) ((SMIA_REG_32BIT << 16) | (r))
+
+#define SMIAPP_REG_MK_F32(r) (SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | (r))
+
+#define SMIAPP_REG_U16_MODEL_ID					SMIAPP_REG_MK_U16(0x0000)
+#define SMIAPP_REG_U8_REVISION_NUMBER_MAJOR			SMIAPP_REG_MK_U8(0x0002)
+#define SMIAPP_REG_U8_MANUFACTURER_ID				SMIAPP_REG_MK_U8(0x0003)
+#define SMIAPP_REG_U8_SMIA_VERSION				SMIAPP_REG_MK_U8(0x0004)
+#define SMIAPP_REG_U8_FRAME_COUNT				SMIAPP_REG_MK_U8(0x0005)
+#define SMIAPP_REG_U8_PIXEL_ORDER				SMIAPP_REG_MK_U8(0x0006)
+#define SMIAPP_REG_U16_DATA_PEDESTAL				SMIAPP_REG_MK_U16(0x0008)
+#define SMIAPP_REG_U8_PIXEL_DEPTH				SMIAPP_REG_MK_U8(0x000c)
+#define SMIAPP_REG_U8_REVISION_NUMBER_MINOR			SMIAPP_REG_MK_U8(0x0010)
+#define SMIAPP_REG_U8_SMIAPP_VERSION				SMIAPP_REG_MK_U8(0x0011)
+#define SMIAPP_REG_U8_MODULE_DATE_YEAR				SMIAPP_REG_MK_U8(0x0012)
+#define SMIAPP_REG_U8_MODULE_DATE_MONTH				SMIAPP_REG_MK_U8(0x0013)
+#define SMIAPP_REG_U8_MODULE_DATE_DAY				SMIAPP_REG_MK_U8(0x0014)
+#define SMIAPP_REG_U8_MODULE_DATE_PHASE				SMIAPP_REG_MK_U8(0x0015)
+#define SMIAPP_REG_U16_SENSOR_MODEL_ID				SMIAPP_REG_MK_U16(0x0016)
+#define SMIAPP_REG_U8_SENSOR_REVISION_NUMBER			SMIAPP_REG_MK_U8(0x0018)
+#define SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID			SMIAPP_REG_MK_U8(0x0019)
+#define SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION			SMIAPP_REG_MK_U8(0x001a)
+#define SMIAPP_REG_U32_SERIAL_NUMBER				SMIAPP_REG_MK_U32(0x001c)
+#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE			SMIAPP_REG_MK_U8(0x0040)
+#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE		SMIAPP_REG_MK_U8(0x0041)
+#define SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(n)		SMIAPP_REG_MK_U16(0x0042 + ((n) << 1)) /* 0 <= n <= 14 */
+#define SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(n)		SMIAPP_REG_MK_U32(0x0060 + ((n) << 2)) /* 0 <= n <= 7 */
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY			SMIAPP_REG_MK_U16(0x0080)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN			SMIAPP_REG_MK_U16(0x0084)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX			SMIAPP_REG_MK_U16(0x0086)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP			SMIAPP_REG_MK_U16(0x0088)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_TYPE			SMIAPP_REG_MK_U16(0x008a)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_M0				SMIAPP_REG_MK_U16(0x008c)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_C0				SMIAPP_REG_MK_U16(0x008e)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_M1				SMIAPP_REG_MK_U16(0x0090)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_C1				SMIAPP_REG_MK_U16(0x0092)
+#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE			SMIAPP_REG_MK_U8(0x00c0)
+#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_SUBTYPE			SMIAPP_REG_MK_U8(0x00c1)
+#define SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(n)		SMIAPP_REG_MK_U16(0x00c2 + ((n) << 1))
+#define SMIAPP_REG_U8_MODE_SELECT				SMIAPP_REG_MK_U8(0x0100)
+#define SMIAPP_REG_U8_IMAGE_ORIENTATION				SMIAPP_REG_MK_U8(0x0101)
+#define SMIAPP_REG_U8_SOFTWARE_RESET				SMIAPP_REG_MK_U8(0x0103)
+#define SMIAPP_REG_U8_GROUPED_PARAMETER_HOLD			SMIAPP_REG_MK_U8(0x0104)
+#define SMIAPP_REG_U8_MASK_CORRUPTED_FRAMES			SMIAPP_REG_MK_U8(0x0105)
+#define SMIAPP_REG_U8_FAST_STANDBY_CTRL				SMIAPP_REG_MK_U8(0x0106)
+#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL			SMIAPP_REG_MK_U8(0x0107)
+#define SMIAPP_REG_U8_2ND_CCI_IF_CONTROL			SMIAPP_REG_MK_U8(0x0108)
+#define SMIAPP_REG_U8_2ND_CCI_ADDRESS_CONTROL			SMIAPP_REG_MK_U8(0x0109)
+#define SMIAPP_REG_U8_CSI_CHANNEL_IDENTIFIER			SMIAPP_REG_MK_U8(0x0110)
+#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE			SMIAPP_REG_MK_U8(0x0111)
+#define SMIAPP_REG_U16_CSI_DATA_FORMAT				SMIAPP_REG_MK_U16(0x0112)
+#define SMIAPP_REG_U8_CSI_LANE_MODE				SMIAPP_REG_MK_U8(0x0114)
+#define SMIAPP_REG_U8_CSI2_10_TO_8_DT				SMIAPP_REG_MK_U8(0x0115)
+#define SMIAPP_REG_U8_CSI2_10_TO_7_DT				SMIAPP_REG_MK_U8(0x0116)
+#define SMIAPP_REG_U8_CSI2_10_TO_6_DT				SMIAPP_REG_MK_U8(0x0117)
+#define SMIAPP_REG_U8_CSI2_12_TO_8_DT				SMIAPP_REG_MK_U8(0x0118)
+#define SMIAPP_REG_U8_CSI2_12_TO_7_DT				SMIAPP_REG_MK_U8(0x0119)
+#define SMIAPP_REG_U8_CSI2_12_TO_6_DT				SMIAPP_REG_MK_U8(0x011a)
+#define SMIAPP_REG_U8_CSI2_14_TO_10_DT				SMIAPP_REG_MK_U8(0x011b)
+#define SMIAPP_REG_U8_CSI2_14_TO_8_DT				SMIAPP_REG_MK_U8(0x011c)
+#define SMIAPP_REG_U8_CSI2_16_TO_10_DT				SMIAPP_REG_MK_U8(0x011d)
+#define SMIAPP_REG_U8_CSI2_16_TO_8_DT				SMIAPP_REG_MK_U8(0x011e)
+#define SMIAPP_REG_U8_GAIN_MODE					SMIAPP_REG_MK_U8(0x0120)
+#define SMIAPP_REG_U16_VANA_VOLTAGE				SMIAPP_REG_MK_U16(0x0130)
+#define SMIAPP_REG_U16_VDIG_VOLTAGE				SMIAPP_REG_MK_U16(0x0132)
+#define SMIAPP_REG_U16_VIO_VOLTAGE				SMIAPP_REG_MK_U16(0x0134)
+#define SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ			SMIAPP_REG_MK_U16(0x0136)
+#define SMIAPP_REG_U8_TEMP_SENSOR_CONTROL			SMIAPP_REG_MK_U8(0x0138)
+#define SMIAPP_REG_U8_TEMP_SENSOR_MODE				SMIAPP_REG_MK_U8(0x0139)
+#define SMIAPP_REG_U8_TEMP_SENSOR_OUTPUT			SMIAPP_REG_MK_U8(0x013a)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME			SMIAPP_REG_MK_U16(0x0200)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME			SMIAPP_REG_MK_U16(0x0202)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL		SMIAPP_REG_MK_U16(0x0204)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENR		SMIAPP_REG_MK_U16(0x0206)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_RED			SMIAPP_REG_MK_U16(0x0208)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_BLUE			SMIAPP_REG_MK_U16(0x020a)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENB		SMIAPP_REG_MK_U16(0x020c)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENR			SMIAPP_REG_MK_U16(0x020e)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_RED				SMIAPP_REG_MK_U16(0x0210)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_BLUE			SMIAPP_REG_MK_U16(0x0212)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENB			SMIAPP_REG_MK_U16(0x0214)
+#define SMIAPP_REG_U16_VT_PIX_CLK_DIV				SMIAPP_REG_MK_U16(0x0300)
+#define SMIAPP_REG_U16_VT_SYS_CLK_DIV				SMIAPP_REG_MK_U16(0x0302)
+#define SMIAPP_REG_U16_PRE_PLL_CLK_DIV				SMIAPP_REG_MK_U16(0x0304)
+#define SMIAPP_REG_U16_PLL_MULTIPLIER				SMIAPP_REG_MK_U16(0x0306)
+#define SMIAPP_REG_U16_OP_PIX_CLK_DIV				SMIAPP_REG_MK_U16(0x0308)
+#define SMIAPP_REG_U16_OP_SYS_CLK_DIV				SMIAPP_REG_MK_U16(0x030a)
+#define SMIAPP_REG_U16_FRAME_LENGTH_LINES			SMIAPP_REG_MK_U16(0x0340)
+#define SMIAPP_REG_U16_LINE_LENGTH_PCK				SMIAPP_REG_MK_U16(0x0342)
+#define SMIAPP_REG_U16_X_ADDR_START				SMIAPP_REG_MK_U16(0x0344)
+#define SMIAPP_REG_U16_Y_ADDR_START				SMIAPP_REG_MK_U16(0x0346)
+#define SMIAPP_REG_U16_X_ADDR_END				SMIAPP_REG_MK_U16(0x0348)
+#define SMIAPP_REG_U16_Y_ADDR_END				SMIAPP_REG_MK_U16(0x034a)
+#define SMIAPP_REG_U16_X_OUTPUT_SIZE				SMIAPP_REG_MK_U16(0x034c)
+#define SMIAPP_REG_U16_Y_OUTPUT_SIZE				SMIAPP_REG_MK_U16(0x034e)
+#define SMIAPP_REG_U16_X_EVEN_INC				SMIAPP_REG_MK_U16(0x0380)
+#define SMIAPP_REG_U16_X_ODD_INC				SMIAPP_REG_MK_U16(0x0382)
+#define SMIAPP_REG_U16_Y_EVEN_INC				SMIAPP_REG_MK_U16(0x0384)
+#define SMIAPP_REG_U16_Y_ODD_INC				SMIAPP_REG_MK_U16(0x0386)
+#define SMIAPP_REG_U16_SCALING_MODE				SMIAPP_REG_MK_U16(0x0400)
+#define SMIAPP_REG_U16_SPATIAL_SAMPLING				SMIAPP_REG_MK_U16(0x0402)
+#define SMIAPP_REG_U16_SCALE_M					SMIAPP_REG_MK_U16(0x0404)
+#define SMIAPP_REG_U16_SCALE_N					SMIAPP_REG_MK_U16(0x0406)
+#define SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET			SMIAPP_REG_MK_U16(0x0408)
+#define SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET			SMIAPP_REG_MK_U16(0x040a)
+#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH			SMIAPP_REG_MK_U16(0x040c)
+#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT		SMIAPP_REG_MK_U16(0x040e)
+#define SMIAPP_REG_U16_COMPRESSION_MODE				SMIAPP_REG_MK_U16(0x0500)
+#define SMIAPP_REG_U16_TEST_PATTERN_MODE			SMIAPP_REG_MK_U16(0x0600)
+#define SMIAPP_REG_U16_TEST_DATA_RED				SMIAPP_REG_MK_U16(0x0602)
+#define SMIAPP_REG_U16_TEST_DATA_GREENR				SMIAPP_REG_MK_U16(0x0604)
+#define SMIAPP_REG_U16_TEST_DATA_BLUE				SMIAPP_REG_MK_U16(0x0606)
+#define SMIAPP_REG_U16_TEST_DATA_GREENB				SMIAPP_REG_MK_U16(0x0608)
+#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_WIDTH			SMIAPP_REG_MK_U16(0x060a)
+#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_POSITION		SMIAPP_REG_MK_U16(0x060c)
+#define SMIAPP_REG_U16_VERTICAL_CURSOR_WIDTH			SMIAPP_REG_MK_U16(0x060e)
+#define SMIAPP_REG_U16_VERTICAL_CURSOR_POSITION			SMIAPP_REG_MK_U16(0x0610)
+#define SMIAPP_REG_U16_FIFO_WATER_MARK_PIXELS			SMIAPP_REG_MK_U16(0x0700)
+#define SMIAPP_REG_U8_TCLK_POST					SMIAPP_REG_MK_U8(0x0800)
+#define SMIAPP_REG_U8_THS_PREPARE				SMIAPP_REG_MK_U8(0x0801)
+#define SMIAPP_REG_U8_THS_ZERO_MIN				SMIAPP_REG_MK_U8(0x0802)
+#define SMIAPP_REG_U8_THS_TRAIL					SMIAPP_REG_MK_U8(0x0803)
+#define SMIAPP_REG_U8_TCLK_TRAIL_MIN				SMIAPP_REG_MK_U8(0x0804)
+#define SMIAPP_REG_U8_TCLK_PREPARE				SMIAPP_REG_MK_U8(0x0805)
+#define SMIAPP_REG_U8_TCLK_ZERO					SMIAPP_REG_MK_U8(0x0806)
+#define SMIAPP_REG_U8_TLPX					SMIAPP_REG_MK_U8(0x0807)
+#define SMIAPP_REG_U8_DPHY_CTRL					SMIAPP_REG_MK_U8(0x0808)
+#define SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS		SMIAPP_REG_MK_U32(0x0820)
+#define SMIAPP_REG_U8_BINNING_MODE				SMIAPP_REG_MK_U8(0x0900)
+#define SMIAPP_REG_U8_BINNING_TYPE				SMIAPP_REG_MK_U8(0x0901)
+#define SMIAPP_REG_U8_BINNING_WEIGHTING				SMIAPP_REG_MK_U8(0x0902)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL			SMIAPP_REG_MK_U8(0x0a00)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS			SMIAPP_REG_MK_U8(0x0a01)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT		SMIAPP_REG_MK_U8(0x0a02)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0			SMIAPP_REG_MK_U8(0x0a04)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_1			SMIAPP_REG_MK_U8(0x0a05)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_2			SMIAPP_REG_MK_U8(0x0a06)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_3			SMIAPP_REG_MK_U8(0x0a07)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_4			SMIAPP_REG_MK_U8(0x0a08)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_5			SMIAPP_REG_MK_U8(0x0a09)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_12		SMIAPP_REG_MK_U8(0x0a10)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_13		SMIAPP_REG_MK_U8(0x0a11)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_14		SMIAPP_REG_MK_U8(0x0a12)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_15		SMIAPP_REG_MK_U8(0x0a13)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_16		SMIAPP_REG_MK_U8(0x0a14)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_17		SMIAPP_REG_MK_U8(0x0a15)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_18		SMIAPP_REG_MK_U8(0x0a16)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_19		SMIAPP_REG_MK_U8(0x0a17)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_20		SMIAPP_REG_MK_U8(0x0a18)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_21		SMIAPP_REG_MK_U8(0x0a19)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_22		SMIAPP_REG_MK_U8(0x0a1a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_23		SMIAPP_REG_MK_U8(0x0a1b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_24		SMIAPP_REG_MK_U8(0x0a1c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_25		SMIAPP_REG_MK_U8(0x0a1d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_26		SMIAPP_REG_MK_U8(0x0a1e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_27		SMIAPP_REG_MK_U8(0x0a1f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_28		SMIAPP_REG_MK_U8(0x0a20)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_29		SMIAPP_REG_MK_U8(0x0a21)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_30		SMIAPP_REG_MK_U8(0x0a22)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_31		SMIAPP_REG_MK_U8(0x0a23)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_32		SMIAPP_REG_MK_U8(0x0a24)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_33		SMIAPP_REG_MK_U8(0x0a25)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_34		SMIAPP_REG_MK_U8(0x0a26)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_35		SMIAPP_REG_MK_U8(0x0a27)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_36		SMIAPP_REG_MK_U8(0x0a28)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_37		SMIAPP_REG_MK_U8(0x0a29)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_38		SMIAPP_REG_MK_U8(0x0a2a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_39		SMIAPP_REG_MK_U8(0x0a2b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_40		SMIAPP_REG_MK_U8(0x0a2c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_41		SMIAPP_REG_MK_U8(0x0a2d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_42		SMIAPP_REG_MK_U8(0x0a2e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_43		SMIAPP_REG_MK_U8(0x0a2f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_44		SMIAPP_REG_MK_U8(0x0a30)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_45		SMIAPP_REG_MK_U8(0x0a31)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_46		SMIAPP_REG_MK_U8(0x0a32)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_47		SMIAPP_REG_MK_U8(0x0a33)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_48		SMIAPP_REG_MK_U8(0x0a34)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_49		SMIAPP_REG_MK_U8(0x0a35)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_50		SMIAPP_REG_MK_U8(0x0a36)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_51		SMIAPP_REG_MK_U8(0x0a37)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_52		SMIAPP_REG_MK_U8(0x0a38)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_53		SMIAPP_REG_MK_U8(0x0a39)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_54		SMIAPP_REG_MK_U8(0x0a3a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_55		SMIAPP_REG_MK_U8(0x0a3b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_56		SMIAPP_REG_MK_U8(0x0a3c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_57		SMIAPP_REG_MK_U8(0x0a3d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_58		SMIAPP_REG_MK_U8(0x0a3e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_59		SMIAPP_REG_MK_U8(0x0a3f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_60		SMIAPP_REG_MK_U8(0x0a40)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_61		SMIAPP_REG_MK_U8(0x0a41)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_62		SMIAPP_REG_MK_U8(0x0a42)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_63		SMIAPP_REG_MK_U8(0x0a43)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_CTRL			SMIAPP_REG_MK_U8(0x0a44)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_STATUS			SMIAPP_REG_MK_U8(0x0a45)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_PAGE_SELECT		SMIAPP_REG_MK_U8(0x0a46)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_0			SMIAPP_REG_MK_U8(0x0a48)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_1			SMIAPP_REG_MK_U8(0x0a49)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_2			SMIAPP_REG_MK_U8(0x0a4a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_3			SMIAPP_REG_MK_U8(0x0a4b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_4			SMIAPP_REG_MK_U8(0x0a4c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_5			SMIAPP_REG_MK_U8(0x0a4d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_6			SMIAPP_REG_MK_U8(0x0a4e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_7			SMIAPP_REG_MK_U8(0x0a4f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_8			SMIAPP_REG_MK_U8(0x0a50)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_9			SMIAPP_REG_MK_U8(0x0a51)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_10		SMIAPP_REG_MK_U8(0x0a52)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_11		SMIAPP_REG_MK_U8(0x0a53)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_12		SMIAPP_REG_MK_U8(0x0a54)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_13		SMIAPP_REG_MK_U8(0x0a55)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_14		SMIAPP_REG_MK_U8(0x0a56)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_15		SMIAPP_REG_MK_U8(0x0a57)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_16		SMIAPP_REG_MK_U8(0x0a58)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_17		SMIAPP_REG_MK_U8(0x0a59)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_18		SMIAPP_REG_MK_U8(0x0a5a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_19		SMIAPP_REG_MK_U8(0x0a5b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_20		SMIAPP_REG_MK_U8(0x0a5c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_21		SMIAPP_REG_MK_U8(0x0a5d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_22		SMIAPP_REG_MK_U8(0x0a5e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_23		SMIAPP_REG_MK_U8(0x0a5f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_24		SMIAPP_REG_MK_U8(0x0a60)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_25		SMIAPP_REG_MK_U8(0x0a61)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_26		SMIAPP_REG_MK_U8(0x0a62)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_27		SMIAPP_REG_MK_U8(0x0a63)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_28		SMIAPP_REG_MK_U8(0x0a64)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_29		SMIAPP_REG_MK_U8(0x0a65)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_30		SMIAPP_REG_MK_U8(0x0a66)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_31		SMIAPP_REG_MK_U8(0x0a67)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_32		SMIAPP_REG_MK_U8(0x0a68)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_33		SMIAPP_REG_MK_U8(0x0a69)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_34		SMIAPP_REG_MK_U8(0x0a6a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_35		SMIAPP_REG_MK_U8(0x0a6b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_36		SMIAPP_REG_MK_U8(0x0a6c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_37		SMIAPP_REG_MK_U8(0x0a6d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_38		SMIAPP_REG_MK_U8(0x0a6e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_39		SMIAPP_REG_MK_U8(0x0a6f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_40		SMIAPP_REG_MK_U8(0x0a70)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_41		SMIAPP_REG_MK_U8(0x0a71)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_42		SMIAPP_REG_MK_U8(0x0a72)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_43		SMIAPP_REG_MK_U8(0x0a73)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_44		SMIAPP_REG_MK_U8(0x0a74)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_45		SMIAPP_REG_MK_U8(0x0a75)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_46		SMIAPP_REG_MK_U8(0x0a76)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_47		SMIAPP_REG_MK_U8(0x0a77)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_48		SMIAPP_REG_MK_U8(0x0a78)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_49		SMIAPP_REG_MK_U8(0x0a79)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_50		SMIAPP_REG_MK_U8(0x0a7a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_51		SMIAPP_REG_MK_U8(0x0a7b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_52		SMIAPP_REG_MK_U8(0x0a7c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_53		SMIAPP_REG_MK_U8(0x0a7d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_54		SMIAPP_REG_MK_U8(0x0a7e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_55		SMIAPP_REG_MK_U8(0x0a7f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_56		SMIAPP_REG_MK_U8(0x0a80)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_57		SMIAPP_REG_MK_U8(0x0a81)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_58		SMIAPP_REG_MK_U8(0x0a82)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_59		SMIAPP_REG_MK_U8(0x0a83)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_60		SMIAPP_REG_MK_U8(0x0a84)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_61		SMIAPP_REG_MK_U8(0x0a85)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_62		SMIAPP_REG_MK_U8(0x0a86)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_63		SMIAPP_REG_MK_U8(0x0a87)
+#define SMIAPP_REG_U8_SHADING_CORRECTION_ENABLE			SMIAPP_REG_MK_U8(0x0b00)
+#define SMIAPP_REG_U8_LUMINANCE_CORRECTION_LEVEL		SMIAPP_REG_MK_U8(0x0b01)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_ENABLE		SMIAPP_REG_MK_U8(0x0b02)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_WEIGHT		SMIAPP_REG_MK_U8(0x0b03)
+#define SMIAPP_REG_U8_BLACK_LEVEL_CORRECTION_ENABLE		SMIAPP_REG_MK_U8(0x0b04)
+#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ENABLE		SMIAPP_REG_MK_U8(0x0b05)
+#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_ENABLE		SMIAPP_REG_MK_U8(0x0b06)
+#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_WEIGHT		SMIAPP_REG_MK_U8(0x0b07)
+#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_ENABLE		SMIAPP_REG_MK_U8(0x0b08)
+#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_WEIGHT		SMIAPP_REG_MK_U8(0x0b09)
+#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_ENABLE		SMIAPP_REG_MK_U8(0x0b0a)
+#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_WEIGHT		SMIAPP_REG_MK_U8(0x0b0b)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_ENABLE		SMIAPP_REG_MK_U8(0x0b0c)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_WEIGHT		SMIAPP_REG_MK_U8(0x0b0d)
+#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ENABLE		SMIAPP_REG_MK_U8(0x0b0e)
+#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ADJUST		SMIAPP_REG_MK_U8(0x0b0f)
+#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ADJUST		SMIAPP_REG_MK_U8(0x0b10)
+#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ENABLE	SMIAPP_REG_MK_U8(0x0b11)
+#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ADJUST	SMIAPP_REG_MK_U8(0x0b12)
+#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ENABLE	SMIAPP_REG_MK_U8(0x0b13)
+#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ADJUST	SMIAPP_REG_MK_U8(0x0b14)
+#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ENABLE	SMIAPP_REG_MK_U8(0x0b15)
+#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ADJUST	SMIAPP_REG_MK_U8(0x0b16)
+#define SMIAPP_REG_U8_EDOF_MODE					SMIAPP_REG_MK_U8(0x0b80)
+#define SMIAPP_REG_U8_SHARPNESS					SMIAPP_REG_MK_U8(0x0b83)
+#define SMIAPP_REG_U8_DENOISING					SMIAPP_REG_MK_U8(0x0b84)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC				SMIAPP_REG_MK_U8(0x0b85)
+#define SMIAPP_REG_U16_DEPTH_OF_FIELD				SMIAPP_REG_MK_U16(0x0b86)
+#define SMIAPP_REG_U16_FOCUS_DISTANCE				SMIAPP_REG_MK_U16(0x0b88)
+#define SMIAPP_REG_U8_ESTIMATION_MODE_CTRL			SMIAPP_REG_MK_U8(0x0b8a)
+#define SMIAPP_REG_U16_COLOUR_TEMPERATURE			SMIAPP_REG_MK_U16(0x0b8c)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENR			SMIAPP_REG_MK_U16(0x0b8e)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_RED			SMIAPP_REG_MK_U16(0x0b90)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_BLUE			SMIAPP_REG_MK_U16(0x0b92)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENB			SMIAPP_REG_MK_U16(0x0b94)
+#define SMIAPP_REG_U8_ESTIMATION_ZONE_MODE			SMIAPP_REG_MK_U8(0x0bc0)
+#define SMIAPP_REG_U16_FIXED_ZONE_WEIGHTING			SMIAPP_REG_MK_U16(0x0bc2)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_X_START			SMIAPP_REG_MK_U16(0x0bc4)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_Y_START			SMIAPP_REG_MK_U16(0x0bc6)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_WIDTH			SMIAPP_REG_MK_U16(0x0bc8)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_HEIGHT			SMIAPP_REG_MK_U16(0x0bca)
+#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL1			SMIAPP_REG_MK_U8(0x0c00)
+#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL2			SMIAPP_REG_MK_U8(0x0c01)
+#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_1		SMIAPP_REG_MK_U8(0x0c02)
+#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_2		SMIAPP_REG_MK_U8(0x0c03)
+#define SMIAPP_REG_U16_TRDY_CTRL				SMIAPP_REG_MK_U16(0x0c04)
+#define SMIAPP_REG_U16_TRDOUT_CTRL				SMIAPP_REG_MK_U16(0x0c06)
+#define SMIAPP_REG_U16_TSHUTTER_STROBE_DELAY_CTRL		SMIAPP_REG_MK_U16(0x0c08)
+#define SMIAPP_REG_U16_TSHUTTER_STROBE_WIDTH_CTRL		SMIAPP_REG_MK_U16(0x0c0a)
+#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_CTRL			SMIAPP_REG_MK_U16(0x0c0c)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_CTRL		SMIAPP_REG_MK_U16(0x0c0e)
+#define SMIAPP_REG_U16_TGRST_INTERVAL_CTRL			SMIAPP_REG_MK_U16(0x0c10)
+#define SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT			SMIAPP_REG_MK_U8(0x0c12)
+#define SMIAPP_REG_U16_FLASH_STROBE_START_POINT			SMIAPP_REG_MK_U16(0x0c14)
+#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL		SMIAPP_REG_MK_U16(0x0c16)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL		SMIAPP_REG_MK_U16(0x0c18)
+#define SMIAPP_REG_U8_FLASH_MODE_RS				SMIAPP_REG_MK_U8(0x0c1a)
+#define SMIAPP_REG_U8_FLASH_TRIGGER_RS				SMIAPP_REG_MK_U8(0x0c1b)
+#define SMIAPP_REG_U8_FLASH_STATUS				SMIAPP_REG_MK_U8(0x0c1c)
+#define SMIAPP_REG_U8_SA_STROBE_MODE				SMIAPP_REG_MK_U8(0x0c1d)
+#define SMIAPP_REG_U16_SA_STROBE_START_POINT			SMIAPP_REG_MK_U16(0x0c1e)
+#define SMIAPP_REG_U16_TSA_STROBE_DELAY_CTRL			SMIAPP_REG_MK_U16(0x0c20)
+#define SMIAPP_REG_U16_TSA_STROBE_WIDTH_CTRL			SMIAPP_REG_MK_U16(0x0c22)
+#define SMIAPP_REG_U8_SA_STROBE_TRIGGER				SMIAPP_REG_MK_U8(0x0c24)
+#define SMIAPP_REG_U8_SPECIAL_ACTUATOR_STATUS			SMIAPP_REG_MK_U8(0x0c25)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_RS_CTRL	SMIAPP_REG_MK_U16(0x0c26)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_RS_CTRL		SMIAPP_REG_MK_U16(0x0c28)
+#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_RS_CTRL		SMIAPP_REG_MK_U8(0x0c2a)
+#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_CTRL			SMIAPP_REG_MK_U8(0x0c2b)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_CTRL		SMIAPP_REG_MK_U16(0x0c2c)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_CTRL		SMIAPP_REG_MK_U16(0x0c2e)
+#define SMIAPP_REG_U8_LOW_LEVEL_CTRL				SMIAPP_REG_MK_U8(0x0c80)
+#define SMIAPP_REG_U16_MAIN_TRIGGER_REF_POINT			SMIAPP_REG_MK_U16(0x0c82)
+#define SMIAPP_REG_U16_MAIN_TRIGGER_T3				SMIAPP_REG_MK_U16(0x0c84)
+#define SMIAPP_REG_U8_MAIN_TRIGGER_COUNT			SMIAPP_REG_MK_U8(0x0c86)
+#define SMIAPP_REG_U16_PHASE1_TRIGGER_T3			SMIAPP_REG_MK_U16(0x0c88)
+#define SMIAPP_REG_U8_PHASE1_TRIGGER_COUNT			SMIAPP_REG_MK_U8(0x0c8a)
+#define SMIAPP_REG_U16_PHASE2_TRIGGER_T3			SMIAPP_REG_MK_U16(0x0c8c)
+#define SMIAPP_REG_U8_PHASE2_TRIGGER_COUNT			SMIAPP_REG_MK_U8(0x0c8e)
+#define SMIAPP_REG_U8_MECH_SHUTTER_CTRL				SMIAPP_REG_MK_U8(0x0d00)
+#define SMIAPP_REG_U8_OPERATION_MODE				SMIAPP_REG_MK_U8(0x0d01)
+#define SMIAPP_REG_U8_ACT_STATE1				SMIAPP_REG_MK_U8(0x0d02)
+#define SMIAPP_REG_U8_ACT_STATE2				SMIAPP_REG_MK_U8(0x0d03)
+#define SMIAPP_REG_U16_FOCUS_CHANGE				SMIAPP_REG_MK_U16(0x0d80)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_CONTROL			SMIAPP_REG_MK_U16(0x0d82)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE1		SMIAPP_REG_MK_U16(0x0d84)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE2		SMIAPP_REG_MK_U16(0x0d86)
+#define SMIAPP_REG_U8_STROBE_COUNT_PHASE1			SMIAPP_REG_MK_U8(0x0d88)
+#define SMIAPP_REG_U8_STROBE_COUNT_PHASE2			SMIAPP_REG_MK_U8(0x0d89)
+#define SMIAPP_REG_U8_POSITION					SMIAPP_REG_MK_U8(0x0d8a)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CONTROL			SMIAPP_REG_MK_U8(0x0e00)
+#define SMIAPP_REG_U8_BRACKETING_LUT_MODE			SMIAPP_REG_MK_U8(0x0e01)
+#define SMIAPP_REG_U8_BRACKETING_LUT_ENTRY_CONTROL		SMIAPP_REG_MK_U8(0x0e02)
+#define SMIAPP_REG_U8_LUT_PARAMETERS_START			SMIAPP_REG_MK_U8(0x0e10)
+#define SMIAPP_REG_U8_LUT_PARAMETERS_END			SMIAPP_REG_MK_U8(0x0eff)
+#define SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY		SMIAPP_REG_MK_U16(0x1000)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN		SMIAPP_REG_MK_U16(0x1004)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN	SMIAPP_REG_MK_U16(0x1006)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN		SMIAPP_REG_MK_U16(0x1008)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN		SMIAPP_REG_MK_U16(0x100a)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY			SMIAPP_REG_MK_U16(0x1080)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_MIN				SMIAPP_REG_MK_U16(0x1084)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_MAX				SMIAPP_REG_MK_U16(0x1086)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_STEP_SIZE			SMIAPP_REG_MK_U16(0x1088)
+#define SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1100)
+#define SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1104)
+#define SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV			SMIAPP_REG_MK_U16(0x1108)
+#define SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV			SMIAPP_REG_MK_U16(0x110a)
+#define SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ			SMIAPP_REG_MK_F32(0x110c)
+#define SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ			SMIAPP_REG_MK_F32(0x1110)
+#define SMIAPP_REG_U16_MIN_PLL_MULTIPLIER			SMIAPP_REG_MK_U16(0x1114)
+#define SMIAPP_REG_U16_MAX_PLL_MULTIPLIER			SMIAPP_REG_MK_U16(0x1116)
+#define SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ			SMIAPP_REG_MK_F32(0x1118)
+#define SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ			SMIAPP_REG_MK_F32(0x111c)
+#define SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV			SMIAPP_REG_MK_U16(0x1120)
+#define SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV			SMIAPP_REG_MK_U16(0x1122)
+#define SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1124)
+#define SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1128)
+#define SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x112c)
+#define SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1130)
+#define SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV			SMIAPP_REG_MK_U16(0x1134)
+#define SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV			SMIAPP_REG_MK_U16(0x1136)
+#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES			SMIAPP_REG_MK_U16(0x1140)
+#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES			SMIAPP_REG_MK_U16(0x1142)
+#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK			SMIAPP_REG_MK_U16(0x1144)
+#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK			SMIAPP_REG_MK_U16(0x1146)
+#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK			SMIAPP_REG_MK_U16(0x1148)
+#define SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES			SMIAPP_REG_MK_U16(0x114a)
+#define SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE		SMIAPP_REG_MK_U8(0x114c)
+#define SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV			SMIAPP_REG_MK_U16(0x1160)
+#define SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV			SMIAPP_REG_MK_U16(0x1162)
+#define SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1164)
+#define SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1168)
+#define SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV			SMIAPP_REG_MK_U16(0x116c)
+#define SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV			SMIAPP_REG_MK_U16(0x116e)
+#define SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1170)
+#define SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ			SMIAPP_REG_MK_F32(0x1174)
+#define SMIAPP_REG_U16_X_ADDR_MIN				SMIAPP_REG_MK_U16(0x1180)
+#define SMIAPP_REG_U16_Y_ADDR_MIN				SMIAPP_REG_MK_U16(0x1182)
+#define SMIAPP_REG_U16_X_ADDR_MAX				SMIAPP_REG_MK_U16(0x1184)
+#define SMIAPP_REG_U16_Y_ADDR_MAX				SMIAPP_REG_MK_U16(0x1186)
+#define SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE			SMIAPP_REG_MK_U16(0x1188)
+#define SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE			SMIAPP_REG_MK_U16(0x118a)
+#define SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE			SMIAPP_REG_MK_U16(0x118c)
+#define SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE			SMIAPP_REG_MK_U16(0x118e)
+#define SMIAPP_REG_U16_MIN_EVEN_INC				SMIAPP_REG_MK_U16(0x11c0)
+#define SMIAPP_REG_U16_MAX_EVEN_INC				SMIAPP_REG_MK_U16(0x11c2)
+#define SMIAPP_REG_U16_MIN_ODD_INC				SMIAPP_REG_MK_U16(0x11c4)
+#define SMIAPP_REG_U16_MAX_ODD_INC				SMIAPP_REG_MK_U16(0x11c6)
+#define SMIAPP_REG_U16_SCALING_CAPABILITY			SMIAPP_REG_MK_U16(0x1200)
+#define SMIAPP_REG_U16_SCALER_M_MIN				SMIAPP_REG_MK_U16(0x1204)
+#define SMIAPP_REG_U16_SCALER_M_MAX				SMIAPP_REG_MK_U16(0x1206)
+#define SMIAPP_REG_U16_SCALER_N_MIN				SMIAPP_REG_MK_U16(0x1208)
+#define SMIAPP_REG_U16_SCALER_N_MAX				SMIAPP_REG_MK_U16(0x120a)
+#define SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY		SMIAPP_REG_MK_U16(0x120c)
+#define SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY			SMIAPP_REG_MK_U8(0x120e)
+#define SMIAPP_REG_U16_COMPRESSION_CAPABILITY			SMIAPP_REG_MK_U16(0x1300)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINRED			SMIAPP_REG_MK_U16(0x1400)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINRED		SMIAPP_REG_MK_U16(0x1402)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINRED			SMIAPP_REG_MK_U16(0x1404)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINGREEN		SMIAPP_REG_MK_U16(0x1406)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINGREEN		SMIAPP_REG_MK_U16(0x1408)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINGREEN		SMIAPP_REG_MK_U16(0x140a)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINBLUE			SMIAPP_REG_MK_U16(0x140c)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINBLUE		SMIAPP_REG_MK_U16(0x140e)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINBLUE		SMIAPP_REG_MK_U16(0x1410)
+#define SMIAPP_REG_U16_FIFO_SIZE_PIXELS				SMIAPP_REG_MK_U16(0x1500)
+#define SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY			SMIAPP_REG_MK_U8(0x1502)
+#define SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY			SMIAPP_REG_MK_U8(0x1600)
+#define SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY			SMIAPP_REG_MK_U8(0x1601)
+#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY		SMIAPP_REG_MK_U8(0x1602)
+#define SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY			SMIAPP_REG_MK_U8(0x1603)
+#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY		SMIAPP_REG_MK_U8(0x1604)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS	SMIAPP_REG_MK_U32(0x1608)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS	SMIAPP_REG_MK_U32(0x160c)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS	SMIAPP_REG_MK_U32(0x1610)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS	SMIAPP_REG_MK_U32(0x1614)
+#define SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY			SMIAPP_REG_MK_U8(0x1618)
+#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN		SMIAPP_REG_MK_U16(0x1700)
+#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN		SMIAPP_REG_MK_U16(0x1702)
+#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN			SMIAPP_REG_MK_U16(0x1704)
+#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN			SMIAPP_REG_MK_U16(0x1706)
+#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN		SMIAPP_REG_MK_U16(0x1708)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN		SMIAPP_REG_MK_U16(0x170a)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN	SMIAPP_REG_MK_U16(0x170c)
+#define SMIAPP_REG_U8_BINNING_CAPABILITY			SMIAPP_REG_MK_U8(0x1710)
+#define SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY		SMIAPP_REG_MK_U8(0x1711)
+#define SMIAPP_REG_U8_BINNING_SUBTYPES				SMIAPP_REG_MK_U8(0x1712)
+#define SMIAPP_REG_U8_BINNING_TYPE_n(n)				SMIAPP_REG_MK_U8(0x1713 + (n)) /* 1 <= n <= 237 */
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY		SMIAPP_REG_MK_U8(0x1800)
+#define SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY		SMIAPP_REG_MK_U8(0x1900)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY		SMIAPP_REG_MK_U8(0x1901)
+#define SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY			SMIAPP_REG_MK_U8(0x1902)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY	SMIAPP_REG_MK_U8(0x1903)
+#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY		SMIAPP_REG_MK_U16(0x1904)
+#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2		SMIAPP_REG_MK_U16(0x1906)
+#define SMIAPP_REG_U8_EDOF_CAPABILITY				SMIAPP_REG_MK_U8(0x1980)
+#define SMIAPP_REG_U8_ESTIMATION_FRAMES				SMIAPP_REG_MK_U8(0x1981)
+#define SMIAPP_REG_U8_SUPPORTS_SHARPNESS_ADJ			SMIAPP_REG_MK_U8(0x1982)
+#define SMIAPP_REG_U8_SUPPORTS_DENOISING_ADJ			SMIAPP_REG_MK_U8(0x1983)
+#define SMIAPP_REG_U8_SUPPORTS_MODULE_SPECIFIC_ADJ		SMIAPP_REG_MK_U8(0x1984)
+#define SMIAPP_REG_U8_SUPPORTS_DEPTH_OF_FIELD_ADJ		SMIAPP_REG_MK_U8(0x1985)
+#define SMIAPP_REG_U8_SUPPORTS_FOCUS_DISTANCE_ADJ		SMIAPP_REG_MK_U8(0x1986)
+#define SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY		SMIAPP_REG_MK_U8(0x1987)
+#define SMIAPP_REG_U8_EDOF_SUPPORT_AB_NXM			SMIAPP_REG_MK_U8(0x1988)
+#define SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY		SMIAPP_REG_MK_U8(0x19c0)
+#define SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY		SMIAPP_REG_MK_U8(0x19c1)
+#define SMIAPP_REG_U16_EST_DEPTH_OF_FIELD			SMIAPP_REG_MK_U16(0x19c2)
+#define SMIAPP_REG_U16_EST_FOCUS_DISTANCE			SMIAPP_REG_MK_U16(0x19c4)
+#define SMIAPP_REG_U16_CAPABILITY_TRDY_MIN			SMIAPP_REG_MK_U16(0x1a00)
+#define SMIAPP_REG_U8_FLASH_MODE_CAPABILITY			SMIAPP_REG_MK_U8(0x1a02)
+#define SMIAPP_REG_U16_MECH_SHUT_AND_ACT_START_ADDR		SMIAPP_REG_MK_U16(0x1b02)
+#define SMIAPP_REG_U8_ACTUATOR_CAPABILITY			SMIAPP_REG_MK_U8(0x1b04)
+#define SMIAPP_REG_U16_ACTUATOR_TYPE				SMIAPP_REG_MK_U16(0x1b40)
+#define SMIAPP_REG_U8_AF_DEVICE_ADDRESS				SMIAPP_REG_MK_U8(0x1b42)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_ADDRESS			SMIAPP_REG_MK_U16(0x1b44)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1		SMIAPP_REG_MK_U8(0x1c00)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2		SMIAPP_REG_MK_U8(0x1c01)
+#define SMIAPP_REG_U8_BRACKETING_LUT_SIZE			SMIAPP_REG_MK_U8(0x1c02)
diff --git a/drivers/media/i2c/smiapp/smiapp-reg.h b/drivers/media/i2c/smiapp/smiapp-reg.h
new file mode 100644
index 0000000..54568ca
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp-reg.h
@@ -0,0 +1,122 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp-reg.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __SMIAPP_REG_H_
+#define __SMIAPP_REG_H_
+
+#include "smiapp-reg-defs.h"
+
+/* Bits for above register */
+#define SMIAPP_IMAGE_ORIENTATION_HFLIP		(1 << 0)
+#define SMIAPP_IMAGE_ORIENTATION_VFLIP		(1 << 1)
+
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN		(1 << 0)
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_RD_EN		(0 << 1)
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_WR_EN		(1 << 1)
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_ERR_CLEAR	(1 << 2)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY	(1 << 0)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_WR_READY	(1 << 1)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EDATA		(1 << 2)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EUSAGE		(1 << 3)
+
+#define SMIAPP_SOFTWARE_RESET				(1 << 0)
+
+#define SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE	(1 << 0)
+#define SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE	(1 << 1)
+
+#define SMIAPP_DPHY_CTRL_AUTOMATIC			0
+/* DPHY control based on REQUESTED_LINK_BIT_RATE_MBPS */
+#define SMIAPP_DPHY_CTRL_UI				1
+#define SMIAPP_DPHY_CTRL_REGISTER			2
+
+#define SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR	1
+#define SMIAPP_COMPRESSION_MODE_ADVANCED_PREDICTOR	2
+
+#define SMIAPP_MODE_SELECT_SOFTWARE_STANDBY		0
+#define SMIAPP_MODE_SELECT_STREAMING			1
+
+#define SMIAPP_SCALING_MODE_NONE			0
+#define SMIAPP_SCALING_MODE_HORIZONTAL			1
+#define SMIAPP_SCALING_MODE_BOTH			2
+
+#define SMIAPP_SCALING_CAPABILITY_NONE			0
+#define SMIAPP_SCALING_CAPABILITY_HORIZONTAL		1
+#define SMIAPP_SCALING_CAPABILITY_BOTH			2 /* horizontal/both */
+
+/* digital crop right before scaler */
+#define SMIAPP_DIGITAL_CROP_CAPABILITY_NONE		0
+#define SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP	1
+
+#define SMIAPP_BINNING_CAPABILITY_NO			0
+#define SMIAPP_BINNING_CAPABILITY_YES			1
+
+/* Maximum number of binning subtypes */
+#define SMIAPP_BINNING_SUBTYPES				253
+
+#define SMIAPP_PIXEL_ORDER_GRBG				0
+#define SMIAPP_PIXEL_ORDER_RGGB				1
+#define SMIAPP_PIXEL_ORDER_BGGR				2
+#define SMIAPP_PIXEL_ORDER_GBRG				3
+
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL		1
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED		2
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N		8
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N	16
+
+#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE		0x01
+#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE		0x02
+#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK	0x0f
+#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK	0xf0
+#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT	4
+
+#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK	0xf000
+#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT	12
+#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK		0x0fff
+
+#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK	0xf0000000
+#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT	28
+#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK		0x0000ffff
+
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED	1
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY	2
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK	3
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK		4
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE	5
+
+#define SMIAPP_FAST_STANDBY_CTRL_COMPLETE_FRAMES	0
+#define SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE		1
+
+/* Scaling N factor */
+#define SMIAPP_SCALE_N					16
+
+/* Image statistics registers */
+/* Registers 0x2000 to 0x2fff are reserved for future
+ * use for statistics features.
+ */
+
+/* Manufacturer Specific Registers: 0x3000 to 0x3fff
+ * The manufacturer specifies these as a black box.
+ */
+
+#endif /* __SMIAPP_REG_H_ */
diff --git a/drivers/media/i2c/smiapp/smiapp-regs.c b/drivers/media/i2c/smiapp/smiapp-regs.c
new file mode 100644
index 0000000..70e0d8d
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp-regs.c
@@ -0,0 +1,273 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp-regs.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+
+#include "smiapp.h"
+#include "smiapp-regs.h"
+
+static uint32_t float_to_u32_mul_1000000(struct i2c_client *client,
+					 uint32_t phloat)
+{
+	int32_t exp;
+	uint64_t man;
+
+	if (phloat >= 0x80000000) {
+		dev_err(&client->dev, "this is a negative number\n");
+		return 0;
+	}
+
+	if (phloat == 0x7f800000)
+		return ~0; /* Inf. */
+
+	if ((phloat & 0x7f800000) == 0x7f800000) {
+		dev_err(&client->dev, "NaN or other special number\n");
+		return 0;
+	}
+
+	/* Valid cases begin here */
+	if (phloat == 0)
+		return 0; /* Valid zero */
+
+	if (phloat > 0x4f800000)
+		return ~0; /* larger than 4294967295 */
+
+	/*
+	 * Unbias exponent (note how phloat is now guaranteed to
+	 * have 0 in the high bit)
+	 */
+	exp = ((int32_t)phloat >> 23) - 127;
+
+	/* Extract mantissa, add missing '1' bit and it's in MHz */
+	man = ((phloat & 0x7fffff) | 0x800000) * 1000000ULL;
+
+	if (exp < 0)
+		man >>= -exp;
+	else
+		man <<= exp;
+
+	man >>= 23; /* Remove mantissa bias */
+
+	return man & 0xffffffff;
+}
+
+
+/*
+ * Read a 8/16/32-bit i2c register.  The value is returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int ____smiapp_read(struct smiapp_sensor *sensor, u16 reg,
+			   u16 len, u32 *val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	struct i2c_msg msg;
+	unsigned char data[4];
+	u16 offset = reg;
+	int r;
+
+	msg.addr = client->addr;
+	msg.flags = 0;
+	msg.len = 2;
+	msg.buf = data;
+
+	/* high byte goes out first */
+	data[0] = (u8) (offset >> 8);
+	data[1] = (u8) offset;
+	r = i2c_transfer(client->adapter, &msg, 1);
+	if (r != 1) {
+		if (r >= 0)
+			r = -EBUSY;
+		goto err;
+	}
+
+	msg.len = len;
+	msg.flags = I2C_M_RD;
+	r = i2c_transfer(client->adapter, &msg, 1);
+	if (r != 1) {
+		if (r >= 0)
+			r = -EBUSY;
+		goto err;
+	}
+
+	*val = 0;
+	/* high byte comes first */
+	switch (len) {
+	case SMIA_REG_32BIT:
+		*val = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) +
+			data[3];
+		break;
+	case SMIA_REG_16BIT:
+		*val = (data[0] << 8) + data[1];
+		break;
+	case SMIA_REG_8BIT:
+		*val = data[0];
+		break;
+	default:
+		BUG();
+	}
+
+	return 0;
+
+err:
+	dev_err(&client->dev, "read from offset 0x%x error %d\n", offset, r);
+
+	return r;
+}
+
+/* Read a register using 8-bit access only. */
+static int ____smiapp_read_8only(struct smiapp_sensor *sensor, u16 reg,
+				 u16 len, u32 *val)
+{
+	unsigned int i;
+	int rval;
+
+	*val = 0;
+
+	for (i = 0; i < len; i++) {
+		u32 val8;
+
+		rval = ____smiapp_read(sensor, reg + i, 1, &val8);
+		if (rval < 0)
+			return rval;
+		*val |= val8 << ((len - i - 1) << 3);
+	}
+
+	return 0;
+}
+
+/*
+ * Read a 8/16/32-bit i2c register.  The value is returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int __smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val,
+			 bool only8)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	unsigned int len = (u8)(reg >> 16);
+	int rval;
+
+	if (len != SMIA_REG_8BIT && len != SMIA_REG_16BIT
+	    && len != SMIA_REG_32BIT)
+		return -EINVAL;
+
+	if (smiapp_quirk_reg(sensor, reg, val))
+		goto found_quirk;
+
+	if (len == SMIA_REG_8BIT && !only8)
+		rval = ____smiapp_read(sensor, (u16)reg, len, val);
+	else
+		rval = ____smiapp_read_8only(sensor, (u16)reg, len, val);
+	if (rval < 0)
+		return rval;
+
+found_quirk:
+	if (reg & SMIA_REG_FLAG_FLOAT)
+		*val = float_to_u32_mul_1000000(client, *val);
+
+	return 0;
+}
+
+int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val)
+{
+	return __smiapp_read(
+		sensor, reg, val,
+		smiapp_needs_quirk(sensor,
+				   SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY));
+}
+
+int smiapp_read_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val)
+{
+	return __smiapp_read(sensor, reg, val, true);
+}
+
+/*
+ * Write to a 8/16-bit register.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	struct i2c_msg msg;
+	unsigned char data[6];
+	unsigned int retries;
+	unsigned int flags = reg >> 24;
+	unsigned int len = (u8)(reg >> 16);
+	u16 offset = reg;
+	int r;
+
+	if ((len != SMIA_REG_8BIT && len != SMIA_REG_16BIT &&
+	     len != SMIA_REG_32BIT) || flags)
+		return -EINVAL;
+
+	msg.addr = client->addr;
+	msg.flags = 0; /* Write */
+	msg.len = 2 + len;
+	msg.buf = data;
+
+	/* high byte goes out first */
+	data[0] = (u8) (reg >> 8);
+	data[1] = (u8) (reg & 0xff);
+
+	switch (len) {
+	case SMIA_REG_8BIT:
+		data[2] = val;
+		break;
+	case SMIA_REG_16BIT:
+		data[2] = val >> 8;
+		data[3] = val;
+		break;
+	case SMIA_REG_32BIT:
+		data[2] = val >> 24;
+		data[3] = val >> 16;
+		data[4] = val >> 8;
+		data[5] = val;
+		break;
+	default:
+		BUG();
+	}
+
+	for (retries = 0; retries < 5; retries++) {
+		/*
+		 * Due to unknown reason sensor stops responding. This
+		 * loop is a temporaty solution until the root cause
+		 * is found.
+		 */
+		r = i2c_transfer(client->adapter, &msg, 1);
+		if (r == 1) {
+			if (retries)
+				dev_err(&client->dev,
+					"sensor i2c stall encountered. "
+					"retries: %d\n", retries);
+			return 0;
+		}
+
+		usleep_range(2000, 2000);
+	}
+
+	dev_err(&client->dev,
+		"wrote 0x%x to offset 0x%x error %d\n", val, offset, r);
+
+	return r;
+}
diff --git a/drivers/media/i2c/smiapp/smiapp-regs.h b/drivers/media/i2c/smiapp/smiapp-regs.h
new file mode 100644
index 0000000..7f9013b
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp-regs.h
@@ -0,0 +1,49 @@
+/*
+ * include/media/smiapp/smiapp-regs.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SMIAPP_REGS_H
+#define SMIAPP_REGS_H
+
+#include <linux/i2c.h>
+#include <linux/types.h>
+
+/* Use upper 8 bits of the type field for flags */
+#define SMIA_REG_FLAG_FLOAT		(1 << 24)
+
+#define SMIA_REG_8BIT			1
+#define SMIA_REG_16BIT			2
+#define SMIA_REG_32BIT			4
+struct smia_reg {
+	u16 type;
+	u16 reg;			/* 16-bit offset */
+	u32 val;			/* 8/16/32-bit value */
+};
+
+struct smiapp_sensor;
+
+int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val);
+int smiapp_read_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val);
+int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val);
+
+#endif
diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h
new file mode 100644
index 0000000..4182a69
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp.h
@@ -0,0 +1,252 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2010--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __SMIAPP_PRIV_H_
+#define __SMIAPP_PRIV_H_
+
+#include <linux/mutex.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+#include <media/smiapp.h>
+
+#include "smiapp-pll.h"
+#include "smiapp-reg.h"
+#include "smiapp-regs.h"
+#include "smiapp-quirk.h"
+
+/*
+ * Standard SMIA++ constants
+ */
+#define SMIA_VERSION_1			10
+#define SMIAPP_VERSION_0_8		8 /* Draft 0.8 */
+#define SMIAPP_VERSION_0_9		9 /* Draft 0.9 */
+#define SMIAPP_VERSION_1		10
+
+#define SMIAPP_PROFILE_0		0
+#define SMIAPP_PROFILE_1		1
+#define SMIAPP_PROFILE_2		2
+
+#define SMIAPP_NVM_PAGE_SIZE		64	/* bytes */
+
+#define SMIAPP_RESET_DELAY_CLOCKS	2400
+#define SMIAPP_RESET_DELAY(clk)				\
+	(1000 +	(SMIAPP_RESET_DELAY_CLOCKS * 1000	\
+		 + (clk) / 1000 - 1) / ((clk) / 1000))
+
+#include "smiapp-limits.h"
+
+struct smiapp_quirk;
+
+#define SMIAPP_MODULE_IDENT_FLAG_REV_LE		(1 << 0)
+
+struct smiapp_module_ident {
+	u8 manufacturer_id;
+	u16 model_id;
+	u8 revision_number_major;
+
+	u8 flags;
+
+	char *name;
+	const struct smiapp_quirk *quirk;
+};
+
+struct smiapp_module_info {
+	u32 manufacturer_id;
+	u32 model_id;
+	u32 revision_number_major;
+	u32 revision_number_minor;
+
+	u32 module_year;
+	u32 module_month;
+	u32 module_day;
+
+	u32 sensor_manufacturer_id;
+	u32 sensor_model_id;
+	u32 sensor_revision_number;
+	u32 sensor_firmware_version;
+
+	u32 smia_version;
+	u32 smiapp_version;
+
+	u32 smiapp_profile;
+
+	char *name;
+	const struct smiapp_quirk *quirk;
+};
+
+#define SMIAPP_IDENT_FQ(manufacturer, model, rev, fl, _name, _quirk)	\
+	{ .manufacturer_id = manufacturer,				\
+	  .model_id = model,						\
+	  .revision_number_major = rev,					\
+	  .flags = fl,							\
+	  .name = _name,						\
+	  .quirk = _quirk, }
+
+#define SMIAPP_IDENT_LQ(manufacturer, model, rev, _name, _quirk)	\
+	{ .manufacturer_id = manufacturer,				\
+	  .model_id = model,						\
+	  .revision_number_major = rev,					\
+	  .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE,			\
+	  .name = _name,						\
+	  .quirk = _quirk, }
+
+#define SMIAPP_IDENT_L(manufacturer, model, rev, _name)			\
+	{ .manufacturer_id = manufacturer,				\
+	  .model_id = model,						\
+	  .revision_number_major = rev,					\
+	  .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE,			\
+	  .name = _name, }
+
+#define SMIAPP_IDENT_Q(manufacturer, model, rev, _name, _quirk)		\
+	{ .manufacturer_id = manufacturer,				\
+	  .model_id = model,						\
+	  .revision_number_major = rev,					\
+	  .flags = 0,							\
+	  .name = _name,						\
+	  .quirk = _quirk, }
+
+#define SMIAPP_IDENT(manufacturer, model, rev, _name)			\
+	{ .manufacturer_id = manufacturer,				\
+	  .model_id = model,						\
+	  .revision_number_major = rev,					\
+	  .flags = 0,							\
+	  .name = _name, }
+
+struct smiapp_reg_limits {
+	u32 addr;
+	char *what;
+};
+
+extern struct smiapp_reg_limits smiapp_reg_limits[];
+
+struct smiapp_csi_data_format {
+	u32 code;
+	u8 width;
+	u8 compressed;
+	u8 pixel_order;
+};
+
+#define SMIAPP_SUBDEVS			3
+
+#define SMIAPP_PA_PAD_SRC		0
+#define SMIAPP_PAD_SINK			0
+#define SMIAPP_PAD_SRC			1
+#define SMIAPP_PADS			2
+
+struct smiapp_binning_subtype {
+	u8 horizontal:4;
+	u8 vertical:4;
+} __packed;
+
+struct smiapp_subdev {
+	struct v4l2_subdev sd;
+	struct media_pad pads[2];
+	struct v4l2_rect sink_fmt;
+	struct v4l2_rect crop[2];
+	struct v4l2_rect compose; /* compose on sink */
+	unsigned short sink_pad;
+	unsigned short source_pad;
+	int npads;
+	struct smiapp_sensor *sensor;
+	struct v4l2_ctrl_handler ctrl_handler;
+};
+
+/*
+ * struct smiapp_sensor - Main device structure
+ */
+struct smiapp_sensor {
+	/*
+	 * "mutex" is used to serialise access to all fields here
+	 * except v4l2_ctrls at the end of the struct. "mutex" is also
+	 * used to serialise access to file handle specific
+	 * information. The exception to this rule is the power_mutex
+	 * below.
+	 */
+	struct mutex mutex;
+	/*
+	 * power_mutex is used to serialise power management related
+	 * activities. Acquiring "mutex" at that time isn't necessary
+	 * since there are no other users anyway.
+	 */
+	struct mutex power_mutex;
+	struct smiapp_subdev ssds[SMIAPP_SUBDEVS];
+	u32 ssds_used;
+	struct smiapp_subdev *src;
+	struct smiapp_subdev *binner;
+	struct smiapp_subdev *scaler;
+	struct smiapp_subdev *pixel_array;
+	struct smiapp_platform_data *platform_data;
+	struct regulator *vana;
+	struct clk *ext_clk;
+	u32 limits[SMIAPP_LIMIT_LAST];
+	u8 nbinning_subtypes;
+	struct smiapp_binning_subtype binning_subtypes[SMIAPP_BINNING_SUBTYPES];
+	u32 mbus_frame_fmts;
+	const struct smiapp_csi_data_format *csi_format;
+	const struct smiapp_csi_data_format *internal_csi_format;
+	u32 default_mbus_frame_fmts;
+	int default_pixel_order;
+
+	u8 binning_horizontal;
+	u8 binning_vertical;
+
+	u8 scale_m;
+	u8 scaling_mode;
+
+	u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */
+	u8 flash_capability;
+	u8 frame_skip;
+
+	int power_count;
+
+	bool streaming;
+	bool dev_init_done;
+
+	u8 *nvm;		/* nvm memory buffer */
+	unsigned int nvm_size;	/* bytes */
+
+	struct smiapp_module_info minfo;
+
+	struct smiapp_pll pll;
+
+	/* Pixel array controls */
+	struct v4l2_ctrl *analog_gain;
+	struct v4l2_ctrl *exposure;
+	struct v4l2_ctrl *hflip;
+	struct v4l2_ctrl *vflip;
+	struct v4l2_ctrl *vblank;
+	struct v4l2_ctrl *hblank;
+	struct v4l2_ctrl *pixel_rate_parray;
+	/* src controls */
+	struct v4l2_ctrl *link_freq;
+	struct v4l2_ctrl *pixel_rate_csi;
+};
+
+#define to_smiapp_subdev(_sd)				\
+	container_of(_sd, struct smiapp_subdev, sd)
+
+#define to_smiapp_sensor(_sd)	\
+	(to_smiapp_subdev(_sd)->sensor)
+
+#endif /* __SMIAPP_PRIV_H_ */
diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig
new file mode 100644
index 0000000..6dff2b7
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/Kconfig
@@ -0,0 +1,89 @@
+comment "soc_camera sensor drivers"
+
+config SOC_CAMERA_IMX074
+	tristate "imx074 support"
+	depends on SOC_CAMERA && I2C
+	help
+	  This driver supports IMX074 cameras from Sony
+
+config SOC_CAMERA_MT9M001
+	tristate "mt9m001 support"
+	depends on SOC_CAMERA && I2C
+	select GPIO_PCA953X if MT9M001_PCA9536_SWITCH
+	help
+	  This driver supports MT9M001 cameras from Micron, monochrome
+	  and colour models.
+
+config SOC_CAMERA_MT9M111
+	tristate "mt9m111, mt9m112 and mt9m131 support"
+	depends on SOC_CAMERA && I2C
+	help
+	  This driver supports MT9M111, MT9M112 and MT9M131 cameras from
+	  Micron/Aptina
+
+config SOC_CAMERA_MT9T031
+	tristate "mt9t031 support"
+	depends on SOC_CAMERA && I2C
+	help
+	  This driver supports MT9T031 cameras from Micron.
+
+config SOC_CAMERA_MT9T112
+	tristate "mt9t112 support"
+	depends on SOC_CAMERA && I2C
+	help
+	  This driver supports MT9T112 cameras from Aptina.
+
+config SOC_CAMERA_MT9V022
+	tristate "mt9v022 and mt9v024 support"
+	depends on SOC_CAMERA && I2C
+	select GPIO_PCA953X if MT9V022_PCA9536_SWITCH
+	help
+	  This driver supports MT9V022 cameras from Micron
+
+config SOC_CAMERA_OV2640
+	tristate "ov2640 camera support"
+	depends on SOC_CAMERA && I2C
+	help
+	  This is a ov2640 camera driver
+
+config SOC_CAMERA_OV5642
+	tristate "ov5642 camera support"
+	depends on SOC_CAMERA && I2C
+	help
+	  This is a V4L2 camera driver for the OmniVision OV5642 sensor
+
+config SOC_CAMERA_OV6650
+	tristate "ov6650 sensor support"
+	depends on SOC_CAMERA && I2C
+	---help---
+	  This is a V4L2 SoC camera driver for the OmniVision OV6650 sensor
+
+config SOC_CAMERA_OV772X
+	tristate "ov772x camera support"
+	depends on SOC_CAMERA && I2C
+	help
+	  This is a ov772x camera driver
+
+config SOC_CAMERA_OV9640
+	tristate "ov9640 camera support"
+	depends on SOC_CAMERA && I2C
+	help
+	  This is a ov9640 camera driver
+
+config SOC_CAMERA_OV9740
+	tristate "ov9740 camera support"
+	depends on SOC_CAMERA && I2C
+	help
+	  This is a ov9740 camera driver
+
+config SOC_CAMERA_RJ54N1
+	tristate "rj54n1cb0c support"
+	depends on SOC_CAMERA && I2C
+	help
+	  This is a rj54n1cb0c video driver
+
+config SOC_CAMERA_TW9910
+	tristate "tw9910 support"
+	depends on SOC_CAMERA && I2C
+	help
+	  This is a tw9910 video driver
diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile
new file mode 100644
index 0000000..d0421fe
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/Makefile
@@ -0,0 +1,14 @@
+obj-$(CONFIG_SOC_CAMERA_IMX074)		+= imx074.o
+obj-$(CONFIG_SOC_CAMERA_MT9M001)	+= mt9m001.o
+obj-$(CONFIG_SOC_CAMERA_MT9M111)	+= mt9m111.o
+obj-$(CONFIG_SOC_CAMERA_MT9T031)	+= mt9t031.o
+obj-$(CONFIG_SOC_CAMERA_MT9T112)	+= mt9t112.o
+obj-$(CONFIG_SOC_CAMERA_MT9V022)	+= mt9v022.o
+obj-$(CONFIG_SOC_CAMERA_OV2640)		+= ov2640.o
+obj-$(CONFIG_SOC_CAMERA_OV5642)		+= ov5642.o
+obj-$(CONFIG_SOC_CAMERA_OV6650)		+= ov6650.o
+obj-$(CONFIG_SOC_CAMERA_OV772X)		+= ov772x.o
+obj-$(CONFIG_SOC_CAMERA_OV9640)		+= ov9640.o
+obj-$(CONFIG_SOC_CAMERA_OV9740)		+= ov9740.o
+obj-$(CONFIG_SOC_CAMERA_RJ54N1)		+= rj54n1cb0c.o
+obj-$(CONFIG_SOC_CAMERA_TW9910)		+= tw9910.o
diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/media/i2c/soc_camera/imx074.c
new file mode 100644
index 0000000..f8534ee
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/imx074.c
@@ -0,0 +1,495 @@
+/*
+ * Driver for IMX074 CMOS Image Sensor from Sony
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * Partially inspired by the IMX074 driver from the Android / MSM tree
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-chip-ident.h>
+
+/* IMX074 registers */
+
+#define MODE_SELECT			0x0100
+#define IMAGE_ORIENTATION		0x0101
+#define GROUPED_PARAMETER_HOLD		0x0104
+
+/* Integration Time */
+#define COARSE_INTEGRATION_TIME_HI	0x0202
+#define COARSE_INTEGRATION_TIME_LO	0x0203
+/* Gain */
+#define ANALOGUE_GAIN_CODE_GLOBAL_HI	0x0204
+#define ANALOGUE_GAIN_CODE_GLOBAL_LO	0x0205
+
+/* PLL registers */
+#define PRE_PLL_CLK_DIV			0x0305
+#define PLL_MULTIPLIER			0x0307
+#define PLSTATIM			0x302b
+#define VNDMY_ABLMGSHLMT		0x300a
+#define Y_OPBADDR_START_DI		0x3014
+/* mode setting */
+#define FRAME_LENGTH_LINES_HI		0x0340
+#define FRAME_LENGTH_LINES_LO		0x0341
+#define LINE_LENGTH_PCK_HI		0x0342
+#define LINE_LENGTH_PCK_LO		0x0343
+#define YADDR_START			0x0347
+#define YADDR_END			0x034b
+#define X_OUTPUT_SIZE_MSB		0x034c
+#define X_OUTPUT_SIZE_LSB		0x034d
+#define Y_OUTPUT_SIZE_MSB		0x034e
+#define Y_OUTPUT_SIZE_LSB		0x034f
+#define X_EVEN_INC			0x0381
+#define X_ODD_INC			0x0383
+#define Y_EVEN_INC			0x0385
+#define Y_ODD_INC			0x0387
+
+#define HMODEADD			0x3001
+#define VMODEADD			0x3016
+#define VAPPLINE_START			0x3069
+#define VAPPLINE_END			0x306b
+#define SHUTTER				0x3086
+#define HADDAVE				0x30e8
+#define LANESEL				0x3301
+
+/* IMX074 supported geometry */
+#define IMX074_WIDTH			1052
+#define IMX074_HEIGHT			780
+
+/* IMX074 has only one fixed colorspace per pixelcode */
+struct imx074_datafmt {
+	enum v4l2_mbus_pixelcode	code;
+	enum v4l2_colorspace		colorspace;
+};
+
+struct imx074 {
+	struct v4l2_subdev		subdev;
+	const struct imx074_datafmt	*fmt;
+};
+
+static const struct imx074_datafmt imx074_colour_fmts[] = {
+	{V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
+};
+
+static struct imx074 *to_imx074(const struct i2c_client *client)
+{
+	return container_of(i2c_get_clientdata(client), struct imx074, subdev);
+}
+
+/* Find a data format by a pixel code in an array */
+static const struct imx074_datafmt *imx074_find_datafmt(enum v4l2_mbus_pixelcode code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(imx074_colour_fmts); i++)
+		if (imx074_colour_fmts[i].code == code)
+			return imx074_colour_fmts + i;
+
+	return NULL;
+}
+
+static int reg_write(struct i2c_client *client, const u16 addr, const u8 data)
+{
+	struct i2c_adapter *adap = client->adapter;
+	struct i2c_msg msg;
+	unsigned char tx[3];
+	int ret;
+
+	msg.addr = client->addr;
+	msg.buf = tx;
+	msg.len = 3;
+	msg.flags = 0;
+
+	tx[0] = addr >> 8;
+	tx[1] = addr & 0xff;
+	tx[2] = data;
+
+	ret = i2c_transfer(adap, &msg, 1);
+
+	mdelay(2);
+
+	return ret == 1 ? 0 : -EIO;
+}
+
+static int reg_read(struct i2c_client *client, const u16 addr)
+{
+	u8 buf[2] = {addr >> 8, addr & 0xff};
+	int ret;
+	struct i2c_msg msgs[] = {
+		{
+			.addr  = client->addr,
+			.flags = 0,
+			.len   = 2,
+			.buf   = buf,
+		}, {
+			.addr  = client->addr,
+			.flags = I2C_M_RD,
+			.len   = 2,
+			.buf   = buf,
+		},
+	};
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret < 0) {
+		dev_warn(&client->dev, "Reading register %x from %x failed\n",
+			 addr, client->addr);
+		return ret;
+	}
+
+	return buf[0] & 0xff; /* no sign-extension */
+}
+
+static int imx074_try_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_mbus_framefmt *mf)
+{
+	const struct imx074_datafmt *fmt = imx074_find_datafmt(mf->code);
+
+	dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
+
+	if (!fmt) {
+		mf->code	= imx074_colour_fmts[0].code;
+		mf->colorspace	= imx074_colour_fmts[0].colorspace;
+	}
+
+	mf->width	= IMX074_WIDTH;
+	mf->height	= IMX074_HEIGHT;
+	mf->field	= V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static int imx074_s_fmt(struct v4l2_subdev *sd,
+			struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct imx074 *priv = to_imx074(client);
+
+	dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
+
+	/* MIPI CSI could have changed the format, double-check */
+	if (!imx074_find_datafmt(mf->code))
+		return -EINVAL;
+
+	imx074_try_fmt(sd, mf);
+
+	priv->fmt = imx074_find_datafmt(mf->code);
+
+	return 0;
+}
+
+static int imx074_g_fmt(struct v4l2_subdev *sd,
+			struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct imx074 *priv = to_imx074(client);
+
+	const struct imx074_datafmt *fmt = priv->fmt;
+
+	mf->code	= fmt->code;
+	mf->colorspace	= fmt->colorspace;
+	mf->width	= IMX074_WIDTH;
+	mf->height	= IMX074_HEIGHT;
+	mf->field	= V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static int imx074_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct v4l2_rect *rect = &a->c;
+
+	a->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	rect->top	= 0;
+	rect->left	= 0;
+	rect->width	= IMX074_WIDTH;
+	rect->height	= IMX074_HEIGHT;
+
+	return 0;
+}
+
+static int imx074_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	a->bounds.left			= 0;
+	a->bounds.top			= 0;
+	a->bounds.width			= IMX074_WIDTH;
+	a->bounds.height		= IMX074_HEIGHT;
+	a->defrect			= a->bounds;
+	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int imx074_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			   enum v4l2_mbus_pixelcode *code)
+{
+	if ((unsigned int)index >= ARRAY_SIZE(imx074_colour_fmts))
+		return -EINVAL;
+
+	*code = imx074_colour_fmts[index].code;
+	return 0;
+}
+
+static int imx074_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	/* MODE_SELECT: stream or standby */
+	return reg_write(client, MODE_SELECT, !!enable);
+}
+
+static int imx074_g_chip_ident(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_chip_ident *id)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+
+	if (id->match.addr != client->addr)
+		return -ENODEV;
+
+	id->ident	= V4L2_IDENT_IMX074;
+	id->revision	= 0;
+
+	return 0;
+}
+
+static int imx074_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	return soc_camera_set_power(&client->dev, icl, on);
+}
+
+static int imx074_g_mbus_config(struct v4l2_subdev *sd,
+				struct v4l2_mbus_config *cfg)
+{
+	cfg->type = V4L2_MBUS_CSI2;
+	cfg->flags = V4L2_MBUS_CSI2_2_LANE |
+		V4L2_MBUS_CSI2_CHANNEL_0 |
+		V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+
+	return 0;
+}
+
+static struct v4l2_subdev_video_ops imx074_subdev_video_ops = {
+	.s_stream	= imx074_s_stream,
+	.s_mbus_fmt	= imx074_s_fmt,
+	.g_mbus_fmt	= imx074_g_fmt,
+	.try_mbus_fmt	= imx074_try_fmt,
+	.enum_mbus_fmt	= imx074_enum_fmt,
+	.g_crop		= imx074_g_crop,
+	.cropcap	= imx074_cropcap,
+	.g_mbus_config	= imx074_g_mbus_config,
+};
+
+static struct v4l2_subdev_core_ops imx074_subdev_core_ops = {
+	.g_chip_ident	= imx074_g_chip_ident,
+	.s_power	= imx074_s_power,
+};
+
+static struct v4l2_subdev_ops imx074_subdev_ops = {
+	.core	= &imx074_subdev_core_ops,
+	.video	= &imx074_subdev_video_ops,
+};
+
+static int imx074_video_probe(struct i2c_client *client)
+{
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	int ret;
+	u16 id;
+
+	ret = imx074_s_power(subdev, 1);
+	if (ret < 0)
+		return ret;
+
+	/* Read sensor Model ID */
+	ret = reg_read(client, 0);
+	if (ret < 0)
+		goto done;
+
+	id = ret << 8;
+
+	ret = reg_read(client, 1);
+	if (ret < 0)
+		goto done;
+
+	id |= ret;
+
+	dev_info(&client->dev, "Chip ID 0x%04x detected\n", id);
+
+	if (id != 0x74) {
+		ret = -ENODEV;
+		goto done;
+	}
+
+	/* PLL Setting EXTCLK=24MHz, 22.5times */
+	reg_write(client, PLL_MULTIPLIER, 0x2D);
+	reg_write(client, PRE_PLL_CLK_DIV, 0x02);
+	reg_write(client, PLSTATIM, 0x4B);
+
+	/* 2-lane mode */
+	reg_write(client, 0x3024, 0x00);
+
+	reg_write(client, IMAGE_ORIENTATION, 0x00);
+
+	/* select RAW mode:
+	 * 0x08+0x08 = top 8 bits
+	 * 0x0a+0x08 = compressed 8-bits
+	 * 0x0a+0x0a = 10 bits
+	 */
+	reg_write(client, 0x0112, 0x08);
+	reg_write(client, 0x0113, 0x08);
+
+	/* Base setting for High frame mode */
+	reg_write(client, VNDMY_ABLMGSHLMT, 0x80);
+	reg_write(client, Y_OPBADDR_START_DI, 0x08);
+	reg_write(client, 0x3015, 0x37);
+	reg_write(client, 0x301C, 0x01);
+	reg_write(client, 0x302C, 0x05);
+	reg_write(client, 0x3031, 0x26);
+	reg_write(client, 0x3041, 0x60);
+	reg_write(client, 0x3051, 0x24);
+	reg_write(client, 0x3053, 0x34);
+	reg_write(client, 0x3057, 0xC0);
+	reg_write(client, 0x305C, 0x09);
+	reg_write(client, 0x305D, 0x07);
+	reg_write(client, 0x3060, 0x30);
+	reg_write(client, 0x3065, 0x00);
+	reg_write(client, 0x30AA, 0x08);
+	reg_write(client, 0x30AB, 0x1C);
+	reg_write(client, 0x30B0, 0x32);
+	reg_write(client, 0x30B2, 0x83);
+	reg_write(client, 0x30D3, 0x04);
+	reg_write(client, 0x3106, 0x78);
+	reg_write(client, 0x310C, 0x82);
+	reg_write(client, 0x3304, 0x05);
+	reg_write(client, 0x3305, 0x04);
+	reg_write(client, 0x3306, 0x11);
+	reg_write(client, 0x3307, 0x02);
+	reg_write(client, 0x3308, 0x0C);
+	reg_write(client, 0x3309, 0x06);
+	reg_write(client, 0x330A, 0x08);
+	reg_write(client, 0x330B, 0x04);
+	reg_write(client, 0x330C, 0x08);
+	reg_write(client, 0x330D, 0x06);
+	reg_write(client, 0x330E, 0x01);
+	reg_write(client, 0x3381, 0x00);
+
+	/* V : 1/2V-addition (1,3), H : 1/2H-averaging (1,3) -> Full HD */
+	/* 1608 = 1560 + 48 (black lines) */
+	reg_write(client, FRAME_LENGTH_LINES_HI, 0x06);
+	reg_write(client, FRAME_LENGTH_LINES_LO, 0x48);
+	reg_write(client, YADDR_START, 0x00);
+	reg_write(client, YADDR_END, 0x2F);
+	/* 0x838 == 2104 */
+	reg_write(client, X_OUTPUT_SIZE_MSB, 0x08);
+	reg_write(client, X_OUTPUT_SIZE_LSB, 0x38);
+	/* 0x618 == 1560 */
+	reg_write(client, Y_OUTPUT_SIZE_MSB, 0x06);
+	reg_write(client, Y_OUTPUT_SIZE_LSB, 0x18);
+	reg_write(client, X_EVEN_INC, 0x01);
+	reg_write(client, X_ODD_INC, 0x03);
+	reg_write(client, Y_EVEN_INC, 0x01);
+	reg_write(client, Y_ODD_INC, 0x03);
+	reg_write(client, HMODEADD, 0x00);
+	reg_write(client, VMODEADD, 0x16);
+	reg_write(client, VAPPLINE_START, 0x24);
+	reg_write(client, VAPPLINE_END, 0x53);
+	reg_write(client, SHUTTER, 0x00);
+	reg_write(client, HADDAVE, 0x80);
+
+	reg_write(client, LANESEL, 0x00);
+
+	reg_write(client, GROUPED_PARAMETER_HOLD, 0x00);	/* off */
+
+	ret = 0;
+
+done:
+	imx074_s_power(subdev, 0);
+	return ret;
+}
+
+static int imx074_probe(struct i2c_client *client,
+			const struct i2c_device_id *did)
+{
+	struct imx074 *priv;
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	int ret;
+
+	if (!icl) {
+		dev_err(&client->dev, "IMX074: missing platform data!\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		dev_warn(&adapter->dev,
+			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
+		return -EIO;
+	}
+
+	priv = kzalloc(sizeof(struct imx074), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops);
+
+	priv->fmt	= &imx074_colour_fmts[0];
+
+	ret = imx074_video_probe(client);
+	if (ret < 0) {
+		kfree(priv);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int imx074_remove(struct i2c_client *client)
+{
+	struct imx074 *priv = to_imx074(client);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	if (icl->free_bus)
+		icl->free_bus(icl);
+	kfree(priv);
+
+	return 0;
+}
+
+static const struct i2c_device_id imx074_id[] = {
+	{ "imx074", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, imx074_id);
+
+static struct i2c_driver imx074_i2c_driver = {
+	.driver = {
+		.name = "imx074",
+	},
+	.probe		= imx074_probe,
+	.remove		= imx074_remove,
+	.id_table	= imx074_id,
+};
+
+module_i2c_driver(imx074_i2c_driver);
+
+MODULE_DESCRIPTION("Sony IMX074 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c
new file mode 100644
index 0000000..d85be41
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/mt9m001.c
@@ -0,0 +1,757 @@
+/*
+ * Driver for MT9M001 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+/*
+ * mt9m001 i2c address 0x5d
+ * The platform has to define struct i2c_board_info objects and link to them
+ * from struct soc_camera_link
+ */
+
+/* mt9m001 selected register addresses */
+#define MT9M001_CHIP_VERSION		0x00
+#define MT9M001_ROW_START		0x01
+#define MT9M001_COLUMN_START		0x02
+#define MT9M001_WINDOW_HEIGHT		0x03
+#define MT9M001_WINDOW_WIDTH		0x04
+#define MT9M001_HORIZONTAL_BLANKING	0x05
+#define MT9M001_VERTICAL_BLANKING	0x06
+#define MT9M001_OUTPUT_CONTROL		0x07
+#define MT9M001_SHUTTER_WIDTH		0x09
+#define MT9M001_FRAME_RESTART		0x0b
+#define MT9M001_SHUTTER_DELAY		0x0c
+#define MT9M001_RESET			0x0d
+#define MT9M001_READ_OPTIONS1		0x1e
+#define MT9M001_READ_OPTIONS2		0x20
+#define MT9M001_GLOBAL_GAIN		0x35
+#define MT9M001_CHIP_ENABLE		0xF1
+
+#define MT9M001_MAX_WIDTH		1280
+#define MT9M001_MAX_HEIGHT		1024
+#define MT9M001_MIN_WIDTH		48
+#define MT9M001_MIN_HEIGHT		32
+#define MT9M001_COLUMN_SKIP		20
+#define MT9M001_ROW_SKIP		12
+
+/* MT9M001 has only one fixed colorspace per pixelcode */
+struct mt9m001_datafmt {
+	enum v4l2_mbus_pixelcode	code;
+	enum v4l2_colorspace		colorspace;
+};
+
+/* Find a data format by a pixel code in an array */
+static const struct mt9m001_datafmt *mt9m001_find_datafmt(
+	enum v4l2_mbus_pixelcode code, const struct mt9m001_datafmt *fmt,
+	int n)
+{
+	int i;
+	for (i = 0; i < n; i++)
+		if (fmt[i].code == code)
+			return fmt + i;
+
+	return NULL;
+}
+
+static const struct mt9m001_datafmt mt9m001_colour_fmts[] = {
+	/*
+	 * Order important: first natively supported,
+	 * second supported with a GPIO extender
+	 */
+	{V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
+	{V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
+};
+
+static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = {
+	/* Order important - see above */
+	{V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
+	{V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
+};
+
+struct mt9m001 {
+	struct v4l2_subdev subdev;
+	struct v4l2_ctrl_handler hdl;
+	struct {
+		/* exposure/auto-exposure cluster */
+		struct v4l2_ctrl *autoexposure;
+		struct v4l2_ctrl *exposure;
+	};
+	struct v4l2_rect rect;	/* Sensor window */
+	const struct mt9m001_datafmt *fmt;
+	const struct mt9m001_datafmt *fmts;
+	int num_fmts;
+	int model;	/* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
+	unsigned int total_h;
+	unsigned short y_skip_top;	/* Lines to skip at the top */
+};
+
+static struct mt9m001 *to_mt9m001(const struct i2c_client *client)
+{
+	return container_of(i2c_get_clientdata(client), struct mt9m001, subdev);
+}
+
+static int reg_read(struct i2c_client *client, const u8 reg)
+{
+	return i2c_smbus_read_word_swapped(client, reg);
+}
+
+static int reg_write(struct i2c_client *client, const u8 reg,
+		     const u16 data)
+{
+	return i2c_smbus_write_word_swapped(client, reg, data);
+}
+
+static int reg_set(struct i2c_client *client, const u8 reg,
+		   const u16 data)
+{
+	int ret;
+
+	ret = reg_read(client, reg);
+	if (ret < 0)
+		return ret;
+	return reg_write(client, reg, ret | data);
+}
+
+static int reg_clear(struct i2c_client *client, const u8 reg,
+		     const u16 data)
+{
+	int ret;
+
+	ret = reg_read(client, reg);
+	if (ret < 0)
+		return ret;
+	return reg_write(client, reg, ret & ~data);
+}
+
+static int mt9m001_init(struct i2c_client *client)
+{
+	int ret;
+
+	dev_dbg(&client->dev, "%s\n", __func__);
+
+	/*
+	 * We don't know, whether platform provides reset, issue a soft reset
+	 * too. This returns all registers to their default values.
+	 */
+	ret = reg_write(client, MT9M001_RESET, 1);
+	if (!ret)
+		ret = reg_write(client, MT9M001_RESET, 0);
+
+	/* Disable chip, synchronous option update */
+	if (!ret)
+		ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0);
+
+	return ret;
+}
+
+static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	/* Switch to master "normal" mode or stop sensor readout */
+	if (reg_write(client, MT9M001_OUTPUT_CONTROL, enable ? 2 : 0) < 0)
+		return -EIO;
+	return 0;
+}
+
+static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9m001 *mt9m001 = to_mt9m001(client);
+	struct v4l2_rect rect = a->c;
+	int ret;
+	const u16 hblank = 9, vblank = 25;
+
+	if (mt9m001->fmts == mt9m001_colour_fmts)
+		/*
+		 * Bayer format - even number of rows for simplicity,
+		 * but let the user play with the top row.
+		 */
+		rect.height = ALIGN(rect.height, 2);
+
+	/* Datasheet requirement: see register description */
+	rect.width = ALIGN(rect.width, 2);
+	rect.left = ALIGN(rect.left, 2);
+
+	soc_camera_limit_side(&rect.left, &rect.width,
+		     MT9M001_COLUMN_SKIP, MT9M001_MIN_WIDTH, MT9M001_MAX_WIDTH);
+
+	soc_camera_limit_side(&rect.top, &rect.height,
+		     MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT);
+
+	mt9m001->total_h = rect.height + mt9m001->y_skip_top + vblank;
+
+	/* Blanking and start values - default... */
+	ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank);
+	if (!ret)
+		ret = reg_write(client, MT9M001_VERTICAL_BLANKING, vblank);
+
+	/*
+	 * The caller provides a supported format, as verified per
+	 * call to .try_mbus_fmt()
+	 */
+	if (!ret)
+		ret = reg_write(client, MT9M001_COLUMN_START, rect.left);
+	if (!ret)
+		ret = reg_write(client, MT9M001_ROW_START, rect.top);
+	if (!ret)
+		ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect.width - 1);
+	if (!ret)
+		ret = reg_write(client, MT9M001_WINDOW_HEIGHT,
+				rect.height + mt9m001->y_skip_top - 1);
+	if (!ret && v4l2_ctrl_g_ctrl(mt9m001->autoexposure) == V4L2_EXPOSURE_AUTO)
+		ret = reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h);
+
+	if (!ret)
+		mt9m001->rect = rect;
+
+	return ret;
+}
+
+static int mt9m001_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9m001 *mt9m001 = to_mt9m001(client);
+
+	a->c	= mt9m001->rect;
+	a->type	= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	a->bounds.left			= MT9M001_COLUMN_SKIP;
+	a->bounds.top			= MT9M001_ROW_SKIP;
+	a->bounds.width			= MT9M001_MAX_WIDTH;
+	a->bounds.height		= MT9M001_MAX_HEIGHT;
+	a->defrect			= a->bounds;
+	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int mt9m001_g_fmt(struct v4l2_subdev *sd,
+			 struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9m001 *mt9m001 = to_mt9m001(client);
+
+	mf->width	= mt9m001->rect.width;
+	mf->height	= mt9m001->rect.height;
+	mf->code	= mt9m001->fmt->code;
+	mf->colorspace	= mt9m001->fmt->colorspace;
+	mf->field	= V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static int mt9m001_s_fmt(struct v4l2_subdev *sd,
+			 struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9m001 *mt9m001 = to_mt9m001(client);
+	struct v4l2_crop a = {
+		.c = {
+			.left	= mt9m001->rect.left,
+			.top	= mt9m001->rect.top,
+			.width	= mf->width,
+			.height	= mf->height,
+		},
+	};
+	int ret;
+
+	/* No support for scaling so far, just crop. TODO: use skipping */
+	ret = mt9m001_s_crop(sd, &a);
+	if (!ret) {
+		mf->width	= mt9m001->rect.width;
+		mf->height	= mt9m001->rect.height;
+		mt9m001->fmt	= mt9m001_find_datafmt(mf->code,
+					mt9m001->fmts, mt9m001->num_fmts);
+		mf->colorspace	= mt9m001->fmt->colorspace;
+	}
+
+	return ret;
+}
+
+static int mt9m001_try_fmt(struct v4l2_subdev *sd,
+			   struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9m001 *mt9m001 = to_mt9m001(client);
+	const struct mt9m001_datafmt *fmt;
+
+	v4l_bound_align_image(&mf->width, MT9M001_MIN_WIDTH,
+		MT9M001_MAX_WIDTH, 1,
+		&mf->height, MT9M001_MIN_HEIGHT + mt9m001->y_skip_top,
+		MT9M001_MAX_HEIGHT + mt9m001->y_skip_top, 0, 0);
+
+	if (mt9m001->fmts == mt9m001_colour_fmts)
+		mf->height = ALIGN(mf->height - 1, 2);
+
+	fmt = mt9m001_find_datafmt(mf->code, mt9m001->fmts,
+				   mt9m001->num_fmts);
+	if (!fmt) {
+		fmt = mt9m001->fmt;
+		mf->code = fmt->code;
+	}
+
+	mf->colorspace	= fmt->colorspace;
+
+	return 0;
+}
+
+static int mt9m001_g_chip_ident(struct v4l2_subdev *sd,
+				struct v4l2_dbg_chip_ident *id)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9m001 *mt9m001 = to_mt9m001(client);
+
+	if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+
+	if (id->match.addr != client->addr)
+		return -ENODEV;
+
+	id->ident	= mt9m001->model;
+	id->revision	= 0;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9m001_g_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+		return -EINVAL;
+
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	reg->size = 2;
+	reg->val = reg_read(client, reg->reg);
+
+	if (reg->val > 0xffff)
+		return -EIO;
+
+	return 0;
+}
+
+static int mt9m001_s_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+		return -EINVAL;
+
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	if (reg_write(client, reg->reg, reg->val) < 0)
+		return -EIO;
+
+	return 0;
+}
+#endif
+
+static int mt9m001_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	return soc_camera_set_power(&client->dev, icl, on);
+}
+
+static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mt9m001 *mt9m001 = container_of(ctrl->handler,
+					       struct mt9m001, hdl);
+	s32 min, max;
+
+	switch (ctrl->id) {
+	case V4L2_CID_EXPOSURE_AUTO:
+		min = mt9m001->exposure->minimum;
+		max = mt9m001->exposure->maximum;
+		mt9m001->exposure->val =
+			(524 + (mt9m001->total_h - 1) * (max - min)) / 1048 + min;
+		break;
+	}
+	return 0;
+}
+
+static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mt9m001 *mt9m001 = container_of(ctrl->handler,
+					       struct mt9m001, hdl);
+	struct v4l2_subdev *sd = &mt9m001->subdev;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct v4l2_ctrl *exp = mt9m001->exposure;
+	int data;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		if (ctrl->val)
+			data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000);
+		else
+			data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000);
+		if (data < 0)
+			return -EIO;
+		return 0;
+
+	case V4L2_CID_GAIN:
+		/* See Datasheet Table 7, Gain settings. */
+		if (ctrl->val <= ctrl->default_value) {
+			/* Pack it into 0..1 step 0.125, register values 0..8 */
+			unsigned long range = ctrl->default_value - ctrl->minimum;
+			data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range;
+
+			dev_dbg(&client->dev, "Setting gain %d\n", data);
+			data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
+			if (data < 0)
+				return -EIO;
+		} else {
+			/* Pack it into 1.125..15 variable step, register values 9..67 */
+			/* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
+			unsigned long range = ctrl->maximum - ctrl->default_value - 1;
+			unsigned long gain = ((ctrl->val - ctrl->default_value - 1) *
+					       111 + range / 2) / range + 9;
+
+			if (gain <= 32)
+				data = gain;
+			else if (gain <= 64)
+				data = ((gain - 32) * 16 + 16) / 32 + 80;
+			else
+				data = ((gain - 64) * 7 + 28) / 56 + 96;
+
+			dev_dbg(&client->dev, "Setting gain from %d to %d\n",
+				 reg_read(client, MT9M001_GLOBAL_GAIN), data);
+			data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
+			if (data < 0)
+				return -EIO;
+		}
+		return 0;
+
+	case V4L2_CID_EXPOSURE_AUTO:
+		if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
+			unsigned long range = exp->maximum - exp->minimum;
+			unsigned long shutter = ((exp->val - exp->minimum) * 1048 +
+						 range / 2) / range + 1;
+
+			dev_dbg(&client->dev,
+				"Setting shutter width from %d to %lu\n",
+				reg_read(client, MT9M001_SHUTTER_WIDTH), shutter);
+			if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0)
+				return -EIO;
+		} else {
+			const u16 vblank = 25;
+
+			mt9m001->total_h = mt9m001->rect.height +
+				mt9m001->y_skip_top + vblank;
+			if (reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h) < 0)
+				return -EIO;
+		}
+		return 0;
+	}
+	return -EINVAL;
+}
+
+/*
+ * Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one
+ */
+static int mt9m001_video_probe(struct soc_camera_link *icl,
+			       struct i2c_client *client)
+{
+	struct mt9m001 *mt9m001 = to_mt9m001(client);
+	s32 data;
+	unsigned long flags;
+	int ret;
+
+	ret = mt9m001_s_power(&mt9m001->subdev, 1);
+	if (ret < 0)
+		return ret;
+
+	/* Enable the chip */
+	data = reg_write(client, MT9M001_CHIP_ENABLE, 1);
+	dev_dbg(&client->dev, "write: %d\n", data);
+
+	/* Read out the chip version register */
+	data = reg_read(client, MT9M001_CHIP_VERSION);
+
+	/* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
+	switch (data) {
+	case 0x8411:
+	case 0x8421:
+		mt9m001->model = V4L2_IDENT_MT9M001C12ST;
+		mt9m001->fmts = mt9m001_colour_fmts;
+		break;
+	case 0x8431:
+		mt9m001->model = V4L2_IDENT_MT9M001C12STM;
+		mt9m001->fmts = mt9m001_monochrome_fmts;
+		break;
+	default:
+		dev_err(&client->dev,
+			"No MT9M001 chip detected, register read %x\n", data);
+		ret = -ENODEV;
+		goto done;
+	}
+
+	mt9m001->num_fmts = 0;
+
+	/*
+	 * This is a 10bit sensor, so by default we only allow 10bit.
+	 * The platform may support different bus widths due to
+	 * different routing of the data lines.
+	 */
+	if (icl->query_bus_param)
+		flags = icl->query_bus_param(icl);
+	else
+		flags = SOCAM_DATAWIDTH_10;
+
+	if (flags & SOCAM_DATAWIDTH_10)
+		mt9m001->num_fmts++;
+	else
+		mt9m001->fmts++;
+
+	if (flags & SOCAM_DATAWIDTH_8)
+		mt9m001->num_fmts++;
+
+	mt9m001->fmt = &mt9m001->fmts[0];
+
+	dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
+		 data == 0x8431 ? "C12STM" : "C12ST");
+
+	ret = mt9m001_init(client);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to initialise the camera\n");
+		goto done;
+	}
+
+	/* mt9m001_init() has reset the chip, returning registers to defaults */
+	ret = v4l2_ctrl_handler_setup(&mt9m001->hdl);
+
+done:
+	mt9m001_s_power(&mt9m001->subdev, 0);
+	return ret;
+}
+
+static void mt9m001_video_remove(struct soc_camera_link *icl)
+{
+	if (icl->free_bus)
+		icl->free_bus(icl);
+}
+
+static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9m001 *mt9m001 = to_mt9m001(client);
+
+	*lines = mt9m001->y_skip_top;
+
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops mt9m001_ctrl_ops = {
+	.g_volatile_ctrl = mt9m001_g_volatile_ctrl,
+	.s_ctrl = mt9m001_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
+	.g_chip_ident	= mt9m001_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register	= mt9m001_g_register,
+	.s_register	= mt9m001_s_register,
+#endif
+	.s_power	= mt9m001_s_power,
+};
+
+static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			    enum v4l2_mbus_pixelcode *code)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9m001 *mt9m001 = to_mt9m001(client);
+
+	if (index >= mt9m001->num_fmts)
+		return -EINVAL;
+
+	*code = mt9m001->fmts[index].code;
+	return 0;
+}
+
+static int mt9m001_g_mbus_config(struct v4l2_subdev *sd,
+				struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	/* MT9M001 has all capture_format parameters fixed */
+	cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING |
+		V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
+		V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_MASTER;
+	cfg->type = V4L2_MBUS_PARALLEL;
+	cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+	return 0;
+}
+
+static int mt9m001_s_mbus_config(struct v4l2_subdev *sd,
+				const struct v4l2_mbus_config *cfg)
+{
+	const struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	struct mt9m001 *mt9m001 = to_mt9m001(client);
+	unsigned int bps = soc_mbus_get_fmtdesc(mt9m001->fmt->code)->bits_per_sample;
+
+	if (icl->set_bus_param)
+		return icl->set_bus_param(icl, 1 << (bps - 1));
+
+	/*
+	 * Without board specific bus width settings we only support the
+	 * sensors native bus width
+	 */
+	return bps == 10 ? 0 : -EINVAL;
+}
+
+static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = {
+	.s_stream	= mt9m001_s_stream,
+	.s_mbus_fmt	= mt9m001_s_fmt,
+	.g_mbus_fmt	= mt9m001_g_fmt,
+	.try_mbus_fmt	= mt9m001_try_fmt,
+	.s_crop		= mt9m001_s_crop,
+	.g_crop		= mt9m001_g_crop,
+	.cropcap	= mt9m001_cropcap,
+	.enum_mbus_fmt	= mt9m001_enum_fmt,
+	.g_mbus_config	= mt9m001_g_mbus_config,
+	.s_mbus_config	= mt9m001_s_mbus_config,
+};
+
+static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = {
+	.g_skip_top_lines	= mt9m001_g_skip_top_lines,
+};
+
+static struct v4l2_subdev_ops mt9m001_subdev_ops = {
+	.core	= &mt9m001_subdev_core_ops,
+	.video	= &mt9m001_subdev_video_ops,
+	.sensor	= &mt9m001_subdev_sensor_ops,
+};
+
+static int mt9m001_probe(struct i2c_client *client,
+			 const struct i2c_device_id *did)
+{
+	struct mt9m001 *mt9m001;
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	int ret;
+
+	if (!icl) {
+		dev_err(&client->dev, "MT9M001 driver needs platform data\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_warn(&adapter->dev,
+			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+		return -EIO;
+	}
+
+	mt9m001 = kzalloc(sizeof(struct mt9m001), GFP_KERNEL);
+	if (!mt9m001)
+		return -ENOMEM;
+
+	v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops);
+	v4l2_ctrl_handler_init(&mt9m001->hdl, 4);
+	v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
+			V4L2_CID_GAIN, 0, 127, 1, 64);
+	mt9m001->exposure = v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
+			V4L2_CID_EXPOSURE, 1, 255, 1, 255);
+	/*
+	 * Simulated autoexposure. If enabled, we calculate shutter width
+	 * ourselves in the driver based on vertical blanking and frame width
+	 */
+	mt9m001->autoexposure = v4l2_ctrl_new_std_menu(&mt9m001->hdl,
+			&mt9m001_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
+			V4L2_EXPOSURE_AUTO);
+	mt9m001->subdev.ctrl_handler = &mt9m001->hdl;
+	if (mt9m001->hdl.error) {
+		int err = mt9m001->hdl.error;
+
+		kfree(mt9m001);
+		return err;
+	}
+	v4l2_ctrl_auto_cluster(2, &mt9m001->autoexposure,
+					V4L2_EXPOSURE_MANUAL, true);
+
+	/* Second stage probe - when a capture adapter is there */
+	mt9m001->y_skip_top	= 0;
+	mt9m001->rect.left	= MT9M001_COLUMN_SKIP;
+	mt9m001->rect.top	= MT9M001_ROW_SKIP;
+	mt9m001->rect.width	= MT9M001_MAX_WIDTH;
+	mt9m001->rect.height	= MT9M001_MAX_HEIGHT;
+
+	ret = mt9m001_video_probe(icl, client);
+	if (ret) {
+		v4l2_ctrl_handler_free(&mt9m001->hdl);
+		kfree(mt9m001);
+	}
+
+	return ret;
+}
+
+static int mt9m001_remove(struct i2c_client *client)
+{
+	struct mt9m001 *mt9m001 = to_mt9m001(client);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	v4l2_device_unregister_subdev(&mt9m001->subdev);
+	v4l2_ctrl_handler_free(&mt9m001->hdl);
+	mt9m001_video_remove(icl);
+	kfree(mt9m001);
+
+	return 0;
+}
+
+static const struct i2c_device_id mt9m001_id[] = {
+	{ "mt9m001", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mt9m001_id);
+
+static struct i2c_driver mt9m001_i2c_driver = {
+	.driver = {
+		.name = "mt9m001",
+	},
+	.probe		= mt9m001_probe,
+	.remove		= mt9m001_remove,
+	.id_table	= mt9m001_id,
+};
+
+module_i2c_driver(mt9m001_i2c_driver);
+
+MODULE_DESCRIPTION("Micron MT9M001 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c
new file mode 100644
index 0000000..938c5c3
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/mt9m111.c
@@ -0,0 +1,1046 @@
+/*
+ * Driver for MT9M111/MT9M112/MT9M131 CMOS Image Sensor from Micron/Aptina
+ *
+ * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/module.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-chip-ident.h>
+
+/*
+ * MT9M111, MT9M112 and MT9M131:
+ * i2c address is 0x48 or 0x5d (depending on SADDR pin)
+ * The platform has to define i2c_board_info and call i2c_register_board_info()
+ */
+
+/*
+ * Sensor core register addresses (0x000..0x0ff)
+ */
+#define MT9M111_CHIP_VERSION		0x000
+#define MT9M111_ROW_START		0x001
+#define MT9M111_COLUMN_START		0x002
+#define MT9M111_WINDOW_HEIGHT		0x003
+#define MT9M111_WINDOW_WIDTH		0x004
+#define MT9M111_HORIZONTAL_BLANKING_B	0x005
+#define MT9M111_VERTICAL_BLANKING_B	0x006
+#define MT9M111_HORIZONTAL_BLANKING_A	0x007
+#define MT9M111_VERTICAL_BLANKING_A	0x008
+#define MT9M111_SHUTTER_WIDTH		0x009
+#define MT9M111_ROW_SPEED		0x00a
+#define MT9M111_EXTRA_DELAY		0x00b
+#define MT9M111_SHUTTER_DELAY		0x00c
+#define MT9M111_RESET			0x00d
+#define MT9M111_READ_MODE_B		0x020
+#define MT9M111_READ_MODE_A		0x021
+#define MT9M111_FLASH_CONTROL		0x023
+#define MT9M111_GREEN1_GAIN		0x02b
+#define MT9M111_BLUE_GAIN		0x02c
+#define MT9M111_RED_GAIN		0x02d
+#define MT9M111_GREEN2_GAIN		0x02e
+#define MT9M111_GLOBAL_GAIN		0x02f
+#define MT9M111_CONTEXT_CONTROL		0x0c8
+#define MT9M111_PAGE_MAP		0x0f0
+#define MT9M111_BYTE_WISE_ADDR		0x0f1
+
+#define MT9M111_RESET_SYNC_CHANGES	(1 << 15)
+#define MT9M111_RESET_RESTART_BAD_FRAME	(1 << 9)
+#define MT9M111_RESET_SHOW_BAD_FRAMES	(1 << 8)
+#define MT9M111_RESET_RESET_SOC		(1 << 5)
+#define MT9M111_RESET_OUTPUT_DISABLE	(1 << 4)
+#define MT9M111_RESET_CHIP_ENABLE	(1 << 3)
+#define MT9M111_RESET_ANALOG_STANDBY	(1 << 2)
+#define MT9M111_RESET_RESTART_FRAME	(1 << 1)
+#define MT9M111_RESET_RESET_MODE	(1 << 0)
+
+#define MT9M111_RM_FULL_POWER_RD	(0 << 10)
+#define MT9M111_RM_LOW_POWER_RD		(1 << 10)
+#define MT9M111_RM_COL_SKIP_4X		(1 << 5)
+#define MT9M111_RM_ROW_SKIP_4X		(1 << 4)
+#define MT9M111_RM_COL_SKIP_2X		(1 << 3)
+#define MT9M111_RM_ROW_SKIP_2X		(1 << 2)
+#define MT9M111_RMB_MIRROR_COLS		(1 << 1)
+#define MT9M111_RMB_MIRROR_ROWS		(1 << 0)
+#define MT9M111_CTXT_CTRL_RESTART	(1 << 15)
+#define MT9M111_CTXT_CTRL_DEFECTCOR_B	(1 << 12)
+#define MT9M111_CTXT_CTRL_RESIZE_B	(1 << 10)
+#define MT9M111_CTXT_CTRL_CTRL2_B	(1 << 9)
+#define MT9M111_CTXT_CTRL_GAMMA_B	(1 << 8)
+#define MT9M111_CTXT_CTRL_XENON_EN	(1 << 7)
+#define MT9M111_CTXT_CTRL_READ_MODE_B	(1 << 3)
+#define MT9M111_CTXT_CTRL_LED_FLASH_EN	(1 << 2)
+#define MT9M111_CTXT_CTRL_VBLANK_SEL_B	(1 << 1)
+#define MT9M111_CTXT_CTRL_HBLANK_SEL_B	(1 << 0)
+
+/*
+ * Colorpipe register addresses (0x100..0x1ff)
+ */
+#define MT9M111_OPER_MODE_CTRL		0x106
+#define MT9M111_OUTPUT_FORMAT_CTRL	0x108
+#define MT9M111_REDUCER_XZOOM_B		0x1a0
+#define MT9M111_REDUCER_XSIZE_B		0x1a1
+#define MT9M111_REDUCER_YZOOM_B		0x1a3
+#define MT9M111_REDUCER_YSIZE_B		0x1a4
+#define MT9M111_REDUCER_XZOOM_A		0x1a6
+#define MT9M111_REDUCER_XSIZE_A		0x1a7
+#define MT9M111_REDUCER_YZOOM_A		0x1a9
+#define MT9M111_REDUCER_YSIZE_A		0x1aa
+
+#define MT9M111_OUTPUT_FORMAT_CTRL2_A	0x13a
+#define MT9M111_OUTPUT_FORMAT_CTRL2_B	0x19b
+
+#define MT9M111_OPMODE_AUTOEXPO_EN	(1 << 14)
+#define MT9M111_OPMODE_AUTOWHITEBAL_EN	(1 << 1)
+#define MT9M111_OUTFMT_FLIP_BAYER_COL	(1 << 9)
+#define MT9M111_OUTFMT_FLIP_BAYER_ROW	(1 << 8)
+#define MT9M111_OUTFMT_PROCESSED_BAYER	(1 << 14)
+#define MT9M111_OUTFMT_BYPASS_IFP	(1 << 10)
+#define MT9M111_OUTFMT_INV_PIX_CLOCK	(1 << 9)
+#define MT9M111_OUTFMT_RGB		(1 << 8)
+#define MT9M111_OUTFMT_RGB565		(0 << 6)
+#define MT9M111_OUTFMT_RGB555		(1 << 6)
+#define MT9M111_OUTFMT_RGB444x		(2 << 6)
+#define MT9M111_OUTFMT_RGBx444		(3 << 6)
+#define MT9M111_OUTFMT_TST_RAMP_OFF	(0 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_COL	(1 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_ROW	(2 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_FRAME	(3 << 4)
+#define MT9M111_OUTFMT_SHIFT_3_UP	(1 << 3)
+#define MT9M111_OUTFMT_AVG_CHROMA	(1 << 2)
+#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN	(1 << 1)
+#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B	(1 << 0)
+
+/*
+ * Camera control register addresses (0x200..0x2ff not implemented)
+ */
+
+#define reg_read(reg) mt9m111_reg_read(client, MT9M111_##reg)
+#define reg_write(reg, val) mt9m111_reg_write(client, MT9M111_##reg, (val))
+#define reg_set(reg, val) mt9m111_reg_set(client, MT9M111_##reg, (val))
+#define reg_clear(reg, val) mt9m111_reg_clear(client, MT9M111_##reg, (val))
+#define reg_mask(reg, val, mask) mt9m111_reg_mask(client, MT9M111_##reg, \
+		(val), (mask))
+
+#define MT9M111_MIN_DARK_ROWS	8
+#define MT9M111_MIN_DARK_COLS	26
+#define MT9M111_MAX_HEIGHT	1024
+#define MT9M111_MAX_WIDTH	1280
+
+struct mt9m111_context {
+	u16 read_mode;
+	u16 blanking_h;
+	u16 blanking_v;
+	u16 reducer_xzoom;
+	u16 reducer_yzoom;
+	u16 reducer_xsize;
+	u16 reducer_ysize;
+	u16 output_fmt_ctrl2;
+	u16 control;
+};
+
+static struct mt9m111_context context_a = {
+	.read_mode		= MT9M111_READ_MODE_A,
+	.blanking_h		= MT9M111_HORIZONTAL_BLANKING_A,
+	.blanking_v		= MT9M111_VERTICAL_BLANKING_A,
+	.reducer_xzoom		= MT9M111_REDUCER_XZOOM_A,
+	.reducer_yzoom		= MT9M111_REDUCER_YZOOM_A,
+	.reducer_xsize		= MT9M111_REDUCER_XSIZE_A,
+	.reducer_ysize		= MT9M111_REDUCER_YSIZE_A,
+	.output_fmt_ctrl2	= MT9M111_OUTPUT_FORMAT_CTRL2_A,
+	.control		= MT9M111_CTXT_CTRL_RESTART,
+};
+
+static struct mt9m111_context context_b = {
+	.read_mode		= MT9M111_READ_MODE_B,
+	.blanking_h		= MT9M111_HORIZONTAL_BLANKING_B,
+	.blanking_v		= MT9M111_VERTICAL_BLANKING_B,
+	.reducer_xzoom		= MT9M111_REDUCER_XZOOM_B,
+	.reducer_yzoom		= MT9M111_REDUCER_YZOOM_B,
+	.reducer_xsize		= MT9M111_REDUCER_XSIZE_B,
+	.reducer_ysize		= MT9M111_REDUCER_YSIZE_B,
+	.output_fmt_ctrl2	= MT9M111_OUTPUT_FORMAT_CTRL2_B,
+	.control		= MT9M111_CTXT_CTRL_RESTART |
+		MT9M111_CTXT_CTRL_DEFECTCOR_B | MT9M111_CTXT_CTRL_RESIZE_B |
+		MT9M111_CTXT_CTRL_CTRL2_B | MT9M111_CTXT_CTRL_GAMMA_B |
+		MT9M111_CTXT_CTRL_READ_MODE_B | MT9M111_CTXT_CTRL_VBLANK_SEL_B |
+		MT9M111_CTXT_CTRL_HBLANK_SEL_B,
+};
+
+/* MT9M111 has only one fixed colorspace per pixelcode */
+struct mt9m111_datafmt {
+	enum v4l2_mbus_pixelcode	code;
+	enum v4l2_colorspace		colorspace;
+};
+
+static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
+	{V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+	{V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
+	{V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
+	{V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG},
+	{V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
+	{V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB},
+	{V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
+	{V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
+	{V4L2_MBUS_FMT_BGR565_2X8_LE, V4L2_COLORSPACE_SRGB},
+	{V4L2_MBUS_FMT_BGR565_2X8_BE, V4L2_COLORSPACE_SRGB},
+	{V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
+	{V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
+};
+
+struct mt9m111 {
+	struct v4l2_subdev subdev;
+	struct v4l2_ctrl_handler hdl;
+	struct v4l2_ctrl *gain;
+	int model;	/* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code
+			 * from v4l2-chip-ident.h */
+	struct mt9m111_context *ctx;
+	struct v4l2_rect rect;	/* cropping rectangle */
+	int width;		/* output */
+	int height;		/* sizes */
+	struct mutex power_lock; /* lock to protect power_count */
+	int power_count;
+	const struct mt9m111_datafmt *fmt;
+	int lastpage;	/* PageMap cache value */
+};
+
+/* Find a data format by a pixel code */
+static const struct mt9m111_datafmt *mt9m111_find_datafmt(struct mt9m111 *mt9m111,
+						enum v4l2_mbus_pixelcode code)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(mt9m111_colour_fmts); i++)
+		if (mt9m111_colour_fmts[i].code == code)
+			return mt9m111_colour_fmts + i;
+
+	return mt9m111->fmt;
+}
+
+static struct mt9m111 *to_mt9m111(const struct i2c_client *client)
+{
+	return container_of(i2c_get_clientdata(client), struct mt9m111, subdev);
+}
+
+static int reg_page_map_set(struct i2c_client *client, const u16 reg)
+{
+	int ret;
+	u16 page;
+	struct mt9m111 *mt9m111 = to_mt9m111(client);
+
+	page = (reg >> 8);
+	if (page == mt9m111->lastpage)
+		return 0;
+	if (page > 2)
+		return -EINVAL;
+
+	ret = i2c_smbus_write_word_swapped(client, MT9M111_PAGE_MAP, page);
+	if (!ret)
+		mt9m111->lastpage = page;
+	return ret;
+}
+
+static int mt9m111_reg_read(struct i2c_client *client, const u16 reg)
+{
+	int ret;
+
+	ret = reg_page_map_set(client, reg);
+	if (!ret)
+		ret = i2c_smbus_read_word_swapped(client, reg & 0xff);
+
+	dev_dbg(&client->dev, "read  reg.%03x -> %04x\n", reg, ret);
+	return ret;
+}
+
+static int mt9m111_reg_write(struct i2c_client *client, const u16 reg,
+			     const u16 data)
+{
+	int ret;
+
+	ret = reg_page_map_set(client, reg);
+	if (!ret)
+		ret = i2c_smbus_write_word_swapped(client, reg & 0xff, data);
+	dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret);
+	return ret;
+}
+
+static int mt9m111_reg_set(struct i2c_client *client, const u16 reg,
+			   const u16 data)
+{
+	int ret;
+
+	ret = mt9m111_reg_read(client, reg);
+	if (ret >= 0)
+		ret = mt9m111_reg_write(client, reg, ret | data);
+	return ret;
+}
+
+static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg,
+			     const u16 data)
+{
+	int ret;
+
+	ret = mt9m111_reg_read(client, reg);
+	if (ret >= 0)
+		ret = mt9m111_reg_write(client, reg, ret & ~data);
+	return ret;
+}
+
+static int mt9m111_reg_mask(struct i2c_client *client, const u16 reg,
+			    const u16 data, const u16 mask)
+{
+	int ret;
+
+	ret = mt9m111_reg_read(client, reg);
+	if (ret >= 0)
+		ret = mt9m111_reg_write(client, reg, (ret & ~mask) | data);
+	return ret;
+}
+
+static int mt9m111_set_context(struct mt9m111 *mt9m111,
+			       struct mt9m111_context *ctx)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+	return reg_write(CONTEXT_CONTROL, ctx->control);
+}
+
+static int mt9m111_setup_rect_ctx(struct mt9m111 *mt9m111,
+			struct mt9m111_context *ctx, struct v4l2_rect *rect,
+			unsigned int width, unsigned int height)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+	int ret = mt9m111_reg_write(client, ctx->reducer_xzoom, rect->width);
+	if (!ret)
+		ret = mt9m111_reg_write(client, ctx->reducer_yzoom, rect->height);
+	if (!ret)
+		ret = mt9m111_reg_write(client, ctx->reducer_xsize, width);
+	if (!ret)
+		ret = mt9m111_reg_write(client, ctx->reducer_ysize, height);
+	return ret;
+}
+
+static int mt9m111_setup_geometry(struct mt9m111 *mt9m111, struct v4l2_rect *rect,
+			int width, int height, enum v4l2_mbus_pixelcode code)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+	int ret;
+
+	ret = reg_write(COLUMN_START, rect->left);
+	if (!ret)
+		ret = reg_write(ROW_START, rect->top);
+
+	if (!ret)
+		ret = reg_write(WINDOW_WIDTH, rect->width);
+	if (!ret)
+		ret = reg_write(WINDOW_HEIGHT, rect->height);
+
+	if (code != V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
+		/* IFP in use, down-scaling possible */
+		if (!ret)
+			ret = mt9m111_setup_rect_ctx(mt9m111, &context_b,
+						     rect, width, height);
+		if (!ret)
+			ret = mt9m111_setup_rect_ctx(mt9m111, &context_a,
+						     rect, width, height);
+	}
+
+	dev_dbg(&client->dev, "%s(%x): %ux%u@%u:%u -> %ux%u = %d\n",
+		__func__, code, rect->width, rect->height, rect->left, rect->top,
+		width, height, ret);
+
+	return ret;
+}
+
+static int mt9m111_enable(struct mt9m111 *mt9m111)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+	return reg_write(RESET, MT9M111_RESET_CHIP_ENABLE);
+}
+
+static int mt9m111_reset(struct mt9m111 *mt9m111)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+	int ret;
+
+	ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
+	if (!ret)
+		ret = reg_set(RESET, MT9M111_RESET_RESET_SOC);
+	if (!ret)
+		ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE
+				| MT9M111_RESET_RESET_SOC);
+
+	return ret;
+}
+
+static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct v4l2_rect rect = a->c;
+	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+	int width, height;
+	int ret;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
+	    mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
+		/* Bayer format - even size lengths */
+		rect.width	= ALIGN(rect.width, 2);
+		rect.height	= ALIGN(rect.height, 2);
+		/* Let the user play with the starting pixel */
+	}
+
+	/* FIXME: the datasheet doesn't specify minimum sizes */
+	soc_camera_limit_side(&rect.left, &rect.width,
+		     MT9M111_MIN_DARK_COLS, 2, MT9M111_MAX_WIDTH);
+
+	soc_camera_limit_side(&rect.top, &rect.height,
+		     MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT);
+
+	width = min(mt9m111->width, rect.width);
+	height = min(mt9m111->height, rect.height);
+
+	ret = mt9m111_setup_geometry(mt9m111, &rect, width, height, mt9m111->fmt->code);
+	if (!ret) {
+		mt9m111->rect = rect;
+		mt9m111->width = width;
+		mt9m111->height = height;
+	}
+
+	return ret;
+}
+
+static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+
+	a->c	= mt9m111->rect;
+	a->type	= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	a->bounds.left			= MT9M111_MIN_DARK_COLS;
+	a->bounds.top			= MT9M111_MIN_DARK_ROWS;
+	a->bounds.width			= MT9M111_MAX_WIDTH;
+	a->bounds.height		= MT9M111_MAX_HEIGHT;
+	a->defrect			= a->bounds;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int mt9m111_g_fmt(struct v4l2_subdev *sd,
+			 struct v4l2_mbus_framefmt *mf)
+{
+	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+
+	mf->width	= mt9m111->width;
+	mf->height	= mt9m111->height;
+	mf->code	= mt9m111->fmt->code;
+	mf->colorspace	= mt9m111->fmt->colorspace;
+	mf->field	= V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111,
+			      enum v4l2_mbus_pixelcode code)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+	u16 data_outfmt2, mask_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
+		MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB |
+		MT9M111_OUTFMT_RGB565 | MT9M111_OUTFMT_RGB555 |
+		MT9M111_OUTFMT_RGB444x | MT9M111_OUTFMT_RGBx444 |
+		MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
+		MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
+	int ret;
+
+	switch (code) {
+	case V4L2_MBUS_FMT_SBGGR8_1X8:
+		data_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
+			MT9M111_OUTFMT_RGB;
+		break;
+	case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE:
+		data_outfmt2 = MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB;
+		break;
+	case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+		data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555 |
+			MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
+		break;
+	case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+		data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555;
+		break;
+	case V4L2_MBUS_FMT_RGB565_2X8_LE:
+		data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
+			MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
+		break;
+	case V4L2_MBUS_FMT_RGB565_2X8_BE:
+		data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565;
+		break;
+	case V4L2_MBUS_FMT_BGR565_2X8_BE:
+		data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
+			MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
+		break;
+	case V4L2_MBUS_FMT_BGR565_2X8_LE:
+		data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
+			MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
+			MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
+		break;
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		data_outfmt2 = 0;
+		break;
+	case V4L2_MBUS_FMT_VYUY8_2X8:
+		data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
+		break;
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+		data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
+		break;
+	case V4L2_MBUS_FMT_YVYU8_2X8:
+		data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
+			MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
+		break;
+	default:
+		dev_err(&client->dev, "Pixel format not handled: %x\n", code);
+		return -EINVAL;
+	}
+
+	ret = mt9m111_reg_mask(client, context_a.output_fmt_ctrl2,
+			       data_outfmt2, mask_outfmt2);
+	if (!ret)
+		ret = mt9m111_reg_mask(client, context_b.output_fmt_ctrl2,
+				       data_outfmt2, mask_outfmt2);
+
+	return ret;
+}
+
+static int mt9m111_try_fmt(struct v4l2_subdev *sd,
+			   struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+	const struct mt9m111_datafmt *fmt;
+	struct v4l2_rect *rect = &mt9m111->rect;
+	bool bayer;
+
+	fmt = mt9m111_find_datafmt(mt9m111, mf->code);
+
+	bayer = fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
+		fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE;
+
+	/*
+	 * With Bayer format enforce even side lengths, but let the user play
+	 * with the starting pixel
+	 */
+	if (bayer) {
+		rect->width = ALIGN(rect->width, 2);
+		rect->height = ALIGN(rect->height, 2);
+	}
+
+	if (fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
+		/* IFP bypass mode, no scaling */
+		mf->width = rect->width;
+		mf->height = rect->height;
+	} else {
+		/* No upscaling */
+		if (mf->width > rect->width)
+			mf->width = rect->width;
+		if (mf->height > rect->height)
+			mf->height = rect->height;
+	}
+
+	dev_dbg(&client->dev, "%s(): %ux%u, code=%x\n", __func__,
+		mf->width, mf->height, fmt->code);
+
+	mf->code = fmt->code;
+	mf->colorspace = fmt->colorspace;
+
+	return 0;
+}
+
+static int mt9m111_s_fmt(struct v4l2_subdev *sd,
+			 struct v4l2_mbus_framefmt *mf)
+{
+	const struct mt9m111_datafmt *fmt;
+	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+	struct v4l2_rect *rect = &mt9m111->rect;
+	int ret;
+
+	mt9m111_try_fmt(sd, mf);
+	fmt = mt9m111_find_datafmt(mt9m111, mf->code);
+	/* try_fmt() guarantees fmt != NULL && fmt->code == mf->code */
+
+	ret = mt9m111_setup_geometry(mt9m111, rect, mf->width, mf->height, mf->code);
+	if (!ret)
+		ret = mt9m111_set_pixfmt(mt9m111, mf->code);
+	if (!ret) {
+		mt9m111->width	= mf->width;
+		mt9m111->height	= mf->height;
+		mt9m111->fmt	= fmt;
+	}
+
+	return ret;
+}
+
+static int mt9m111_g_chip_ident(struct v4l2_subdev *sd,
+				struct v4l2_dbg_chip_ident *id)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+
+	if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+
+	if (id->match.addr != client->addr)
+		return -ENODEV;
+
+	id->ident	= mt9m111->model;
+	id->revision	= 0;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9m111_g_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int val;
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+		return -EINVAL;
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	val = mt9m111_reg_read(client, reg->reg);
+	reg->size = 2;
+	reg->val = (u64)val;
+
+	if (reg->val > 0xffff)
+		return -EIO;
+
+	return 0;
+}
+
+static int mt9m111_s_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+		return -EINVAL;
+
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	if (mt9m111_reg_write(client, reg->reg, reg->val) < 0)
+		return -EIO;
+
+	return 0;
+}
+#endif
+
+static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+	int ret;
+
+	if (flip)
+		ret = mt9m111_reg_set(client, mt9m111->ctx->read_mode, mask);
+	else
+		ret = mt9m111_reg_clear(client, mt9m111->ctx->read_mode, mask);
+
+	return ret;
+}
+
+static int mt9m111_get_global_gain(struct mt9m111 *mt9m111)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+	int data;
+
+	data = reg_read(GLOBAL_GAIN);
+	if (data >= 0)
+		return (data & 0x2f) * (1 << ((data >> 10) & 1)) *
+			(1 << ((data >> 9) & 1));
+	return data;
+}
+
+static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+	u16 val;
+
+	if (gain > 63 * 2 * 2)
+		return -EINVAL;
+
+	if ((gain >= 64 * 2) && (gain < 63 * 2 * 2))
+		val = (1 << 10) | (1 << 9) | (gain / 4);
+	else if ((gain >= 64) && (gain < 64 * 2))
+		val = (1 << 9) | (gain / 2);
+	else
+		val = gain;
+
+	return reg_write(GLOBAL_GAIN, val);
+}
+
+static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+
+	if (on)
+		return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
+	return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
+}
+
+static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+
+	if (on)
+		return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
+	return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
+}
+
+static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mt9m111 *mt9m111 = container_of(ctrl->handler,
+					       struct mt9m111, hdl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		return mt9m111_set_flip(mt9m111, ctrl->val,
+					MT9M111_RMB_MIRROR_ROWS);
+	case V4L2_CID_HFLIP:
+		return mt9m111_set_flip(mt9m111, ctrl->val,
+					MT9M111_RMB_MIRROR_COLS);
+	case V4L2_CID_GAIN:
+		return mt9m111_set_global_gain(mt9m111, ctrl->val);
+	case V4L2_CID_EXPOSURE_AUTO:
+		return mt9m111_set_autoexposure(mt9m111, ctrl->val);
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		return mt9m111_set_autowhitebalance(mt9m111, ctrl->val);
+	}
+
+	return -EINVAL;
+}
+
+static int mt9m111_suspend(struct mt9m111 *mt9m111)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+	int ret;
+
+	v4l2_ctrl_s_ctrl(mt9m111->gain, mt9m111_get_global_gain(mt9m111));
+
+	ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
+	if (!ret)
+		ret = reg_set(RESET, MT9M111_RESET_RESET_SOC |
+			      MT9M111_RESET_OUTPUT_DISABLE |
+			      MT9M111_RESET_ANALOG_STANDBY);
+	if (!ret)
+		ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE);
+
+	return ret;
+}
+
+static void mt9m111_restore_state(struct mt9m111 *mt9m111)
+{
+	mt9m111_set_context(mt9m111, mt9m111->ctx);
+	mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code);
+	mt9m111_setup_geometry(mt9m111, &mt9m111->rect,
+			mt9m111->width, mt9m111->height, mt9m111->fmt->code);
+	v4l2_ctrl_handler_setup(&mt9m111->hdl);
+}
+
+static int mt9m111_resume(struct mt9m111 *mt9m111)
+{
+	int ret = mt9m111_enable(mt9m111);
+	if (!ret)
+		ret = mt9m111_reset(mt9m111);
+	if (!ret)
+		mt9m111_restore_state(mt9m111);
+
+	return ret;
+}
+
+static int mt9m111_init(struct mt9m111 *mt9m111)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+	int ret;
+
+	/* Default HIGHPOWER context */
+	mt9m111->ctx = &context_b;
+	ret = mt9m111_enable(mt9m111);
+	if (!ret)
+		ret = mt9m111_reset(mt9m111);
+	if (!ret)
+		ret = mt9m111_set_context(mt9m111, mt9m111->ctx);
+	if (ret)
+		dev_err(&client->dev, "mt9m111 init failed: %d\n", ret);
+	return ret;
+}
+
+static int mt9m111_power_on(struct mt9m111 *mt9m111)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	int ret;
+
+	ret = soc_camera_power_on(&client->dev, icl);
+	if (ret < 0)
+		return ret;
+
+	ret = mt9m111_resume(mt9m111);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret);
+		soc_camera_power_off(&client->dev, icl);
+	}
+
+	return ret;
+}
+
+static void mt9m111_power_off(struct mt9m111 *mt9m111)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	mt9m111_suspend(mt9m111);
+	soc_camera_power_off(&client->dev, icl);
+}
+
+static int mt9m111_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+	int ret = 0;
+
+	mutex_lock(&mt9m111->power_lock);
+
+	/*
+	 * If the power count is modified from 0 to != 0 or from != 0 to 0,
+	 * update the power state.
+	 */
+	if (mt9m111->power_count == !on) {
+		if (on)
+			ret = mt9m111_power_on(mt9m111);
+		else
+			mt9m111_power_off(mt9m111);
+	}
+
+	if (!ret) {
+		/* Update the power count. */
+		mt9m111->power_count += on ? 1 : -1;
+		WARN_ON(mt9m111->power_count < 0);
+	}
+
+	mutex_unlock(&mt9m111->power_lock);
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
+	.s_ctrl = mt9m111_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
+	.g_chip_ident	= mt9m111_g_chip_ident,
+	.s_power	= mt9m111_s_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register	= mt9m111_g_register,
+	.s_register	= mt9m111_s_register,
+#endif
+};
+
+static int mt9m111_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			    enum v4l2_mbus_pixelcode *code)
+{
+	if (index >= ARRAY_SIZE(mt9m111_colour_fmts))
+		return -EINVAL;
+
+	*code = mt9m111_colour_fmts[index].code;
+	return 0;
+}
+
+static int mt9m111_g_mbus_config(struct v4l2_subdev *sd,
+				struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
+		V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
+		V4L2_MBUS_DATA_ACTIVE_HIGH;
+	cfg->type = V4L2_MBUS_PARALLEL;
+	cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+	return 0;
+}
+
+static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
+	.s_mbus_fmt	= mt9m111_s_fmt,
+	.g_mbus_fmt	= mt9m111_g_fmt,
+	.try_mbus_fmt	= mt9m111_try_fmt,
+	.s_crop		= mt9m111_s_crop,
+	.g_crop		= mt9m111_g_crop,
+	.cropcap	= mt9m111_cropcap,
+	.enum_mbus_fmt	= mt9m111_enum_fmt,
+	.g_mbus_config	= mt9m111_g_mbus_config,
+};
+
+static struct v4l2_subdev_ops mt9m111_subdev_ops = {
+	.core	= &mt9m111_subdev_core_ops,
+	.video	= &mt9m111_subdev_video_ops,
+};
+
+/*
+ * Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one
+ */
+static int mt9m111_video_probe(struct i2c_client *client)
+{
+	struct mt9m111 *mt9m111 = to_mt9m111(client);
+	s32 data;
+	int ret;
+
+	ret = mt9m111_s_power(&mt9m111->subdev, 1);
+	if (ret < 0)
+		return ret;
+
+	data = reg_read(CHIP_VERSION);
+
+	switch (data) {
+	case 0x143a: /* MT9M111 or MT9M131 */
+		mt9m111->model = V4L2_IDENT_MT9M111;
+		dev_info(&client->dev,
+			"Detected a MT9M111/MT9M131 chip ID %x\n", data);
+		break;
+	case 0x148c: /* MT9M112 */
+		mt9m111->model = V4L2_IDENT_MT9M112;
+		dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data);
+		break;
+	default:
+		dev_err(&client->dev,
+			"No MT9M111/MT9M112/MT9M131 chip detected register read %x\n",
+			data);
+		ret = -ENODEV;
+		goto done;
+	}
+
+	ret = mt9m111_init(mt9m111);
+	if (ret)
+		goto done;
+
+	ret = v4l2_ctrl_handler_setup(&mt9m111->hdl);
+
+done:
+	mt9m111_s_power(&mt9m111->subdev, 0);
+	return ret;
+}
+
+static int mt9m111_probe(struct i2c_client *client,
+			 const struct i2c_device_id *did)
+{
+	struct mt9m111 *mt9m111;
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	int ret;
+
+	if (!icl) {
+		dev_err(&client->dev, "mt9m111: driver needs platform data\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_warn(&adapter->dev,
+			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+		return -EIO;
+	}
+
+	mt9m111 = kzalloc(sizeof(struct mt9m111), GFP_KERNEL);
+	if (!mt9m111)
+		return -ENOMEM;
+
+	v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops);
+	v4l2_ctrl_handler_init(&mt9m111->hdl, 5);
+	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
+			V4L2_CID_HFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
+			V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
+	mt9m111->gain = v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
+			V4L2_CID_GAIN, 0, 63 * 2 * 2, 1, 32);
+	v4l2_ctrl_new_std_menu(&mt9m111->hdl,
+			&mt9m111_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
+			V4L2_EXPOSURE_AUTO);
+	mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
+	if (mt9m111->hdl.error) {
+		int err = mt9m111->hdl.error;
+
+		kfree(mt9m111);
+		return err;
+	}
+
+	/* Second stage probe - when a capture adapter is there */
+	mt9m111->rect.left	= MT9M111_MIN_DARK_COLS;
+	mt9m111->rect.top	= MT9M111_MIN_DARK_ROWS;
+	mt9m111->rect.width	= MT9M111_MAX_WIDTH;
+	mt9m111->rect.height	= MT9M111_MAX_HEIGHT;
+	mt9m111->fmt		= &mt9m111_colour_fmts[0];
+	mt9m111->lastpage	= -1;
+	mutex_init(&mt9m111->power_lock);
+
+	ret = mt9m111_video_probe(client);
+	if (ret) {
+		v4l2_ctrl_handler_free(&mt9m111->hdl);
+		kfree(mt9m111);
+	}
+
+	return ret;
+}
+
+static int mt9m111_remove(struct i2c_client *client)
+{
+	struct mt9m111 *mt9m111 = to_mt9m111(client);
+
+	v4l2_device_unregister_subdev(&mt9m111->subdev);
+	v4l2_ctrl_handler_free(&mt9m111->hdl);
+	kfree(mt9m111);
+
+	return 0;
+}
+
+static const struct i2c_device_id mt9m111_id[] = {
+	{ "mt9m111", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mt9m111_id);
+
+static struct i2c_driver mt9m111_i2c_driver = {
+	.driver = {
+		.name = "mt9m111",
+	},
+	.probe		= mt9m111_probe,
+	.remove		= mt9m111_remove,
+	.id_table	= mt9m111_id,
+};
+
+module_i2c_driver(mt9m111_i2c_driver);
+
+MODULE_DESCRIPTION("Micron/Aptina MT9M111/MT9M112/MT9M131 Camera driver");
+MODULE_AUTHOR("Robert Jarzmik");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c
new file mode 100644
index 0000000..d74607a
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/mt9t031.c
@@ -0,0 +1,857 @@
+/*
+ * Driver for MT9T031 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski, DENX Software Engineering <lg@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ctrls.h>
+
+/*
+ * ATTENTION: this driver still cannot be used outside of the soc-camera
+ * framework because of its PM implementation, using the video_device node.
+ * If hardware becomes available for testing, alternative PM approaches shall
+ * be considered and tested.
+ */
+
+/*
+ * mt9t031 i2c address 0x5d
+ * The platform has to define i2c_board_info and link to it from
+ * struct soc_camera_link
+ */
+
+/* mt9t031 selected register addresses */
+#define MT9T031_CHIP_VERSION		0x00
+#define MT9T031_ROW_START		0x01
+#define MT9T031_COLUMN_START		0x02
+#define MT9T031_WINDOW_HEIGHT		0x03
+#define MT9T031_WINDOW_WIDTH		0x04
+#define MT9T031_HORIZONTAL_BLANKING	0x05
+#define MT9T031_VERTICAL_BLANKING	0x06
+#define MT9T031_OUTPUT_CONTROL		0x07
+#define MT9T031_SHUTTER_WIDTH_UPPER	0x08
+#define MT9T031_SHUTTER_WIDTH		0x09
+#define MT9T031_PIXEL_CLOCK_CONTROL	0x0a
+#define MT9T031_FRAME_RESTART		0x0b
+#define MT9T031_SHUTTER_DELAY		0x0c
+#define MT9T031_RESET			0x0d
+#define MT9T031_READ_MODE_1		0x1e
+#define MT9T031_READ_MODE_2		0x20
+#define MT9T031_READ_MODE_3		0x21
+#define MT9T031_ROW_ADDRESS_MODE	0x22
+#define MT9T031_COLUMN_ADDRESS_MODE	0x23
+#define MT9T031_GLOBAL_GAIN		0x35
+#define MT9T031_CHIP_ENABLE		0xF8
+
+#define MT9T031_MAX_HEIGHT		1536
+#define MT9T031_MAX_WIDTH		2048
+#define MT9T031_MIN_HEIGHT		2
+#define MT9T031_MIN_WIDTH		18
+#define MT9T031_HORIZONTAL_BLANK	142
+#define MT9T031_VERTICAL_BLANK		25
+#define MT9T031_COLUMN_SKIP		32
+#define MT9T031_ROW_SKIP		20
+
+struct mt9t031 {
+	struct v4l2_subdev subdev;
+	struct v4l2_ctrl_handler hdl;
+	struct {
+		/* exposure/auto-exposure cluster */
+		struct v4l2_ctrl *autoexposure;
+		struct v4l2_ctrl *exposure;
+	};
+	struct v4l2_rect rect;	/* Sensor window */
+	int model;	/* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */
+	u16 xskip;
+	u16 yskip;
+	unsigned int total_h;
+	unsigned short y_skip_top;	/* Lines to skip at the top */
+};
+
+static struct mt9t031 *to_mt9t031(const struct i2c_client *client)
+{
+	return container_of(i2c_get_clientdata(client), struct mt9t031, subdev);
+}
+
+static int reg_read(struct i2c_client *client, const u8 reg)
+{
+	return i2c_smbus_read_word_swapped(client, reg);
+}
+
+static int reg_write(struct i2c_client *client, const u8 reg,
+		     const u16 data)
+{
+	return i2c_smbus_write_word_swapped(client, reg, data);
+}
+
+static int reg_set(struct i2c_client *client, const u8 reg,
+		   const u16 data)
+{
+	int ret;
+
+	ret = reg_read(client, reg);
+	if (ret < 0)
+		return ret;
+	return reg_write(client, reg, ret | data);
+}
+
+static int reg_clear(struct i2c_client *client, const u8 reg,
+		     const u16 data)
+{
+	int ret;
+
+	ret = reg_read(client, reg);
+	if (ret < 0)
+		return ret;
+	return reg_write(client, reg, ret & ~data);
+}
+
+static int set_shutter(struct i2c_client *client, const u32 data)
+{
+	int ret;
+
+	ret = reg_write(client, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16);
+
+	if (ret >= 0)
+		ret = reg_write(client, MT9T031_SHUTTER_WIDTH, data & 0xffff);
+
+	return ret;
+}
+
+static int get_shutter(struct i2c_client *client, u32 *data)
+{
+	int ret;
+
+	ret = reg_read(client, MT9T031_SHUTTER_WIDTH_UPPER);
+	*data = ret << 16;
+
+	if (ret >= 0)
+		ret = reg_read(client, MT9T031_SHUTTER_WIDTH);
+	*data |= ret & 0xffff;
+
+	return ret < 0 ? ret : 0;
+}
+
+static int mt9t031_idle(struct i2c_client *client)
+{
+	int ret;
+
+	/* Disable chip output, synchronous option update */
+	ret = reg_write(client, MT9T031_RESET, 1);
+	if (ret >= 0)
+		ret = reg_write(client, MT9T031_RESET, 0);
+	if (ret >= 0)
+		ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
+
+	return ret >= 0 ? 0 : -EIO;
+}
+
+static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+
+	if (enable)
+		/* Switch to master "normal" mode */
+		ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 2);
+	else
+		/* Stop sensor readout */
+		ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
+
+	if (ret < 0)
+		return -EIO;
+
+	return 0;
+}
+
+/* target must be _even_ */
+static u16 mt9t031_skip(s32 *source, s32 target, s32 max)
+{
+	unsigned int skip;
+
+	if (*source < target + target / 2) {
+		*source = target;
+		return 1;
+	}
+
+	skip = min(max, *source + target / 2) / target;
+	if (skip > 8)
+		skip = 8;
+	*source = target * skip;
+
+	return skip;
+}
+
+/* rect is the sensor rectangle, the caller guarantees parameter validity */
+static int mt9t031_set_params(struct i2c_client *client,
+			      struct v4l2_rect *rect, u16 xskip, u16 yskip)
+{
+	struct mt9t031 *mt9t031 = to_mt9t031(client);
+	int ret;
+	u16 xbin, ybin;
+	const u16 hblank = MT9T031_HORIZONTAL_BLANK,
+		vblank = MT9T031_VERTICAL_BLANK;
+
+	xbin = min(xskip, (u16)3);
+	ybin = min(yskip, (u16)3);
+
+	/*
+	 * Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper.
+	 * There is always a valid suitably aligned value. The worst case is
+	 * xbin = 3, width = 2048. Then we will start at 36, the last read out
+	 * pixel will be 2083, which is < 2085 - first black pixel.
+	 *
+	 * MT9T031 datasheet imposes window left border alignment, depending on
+	 * the selected xskip. Failing to conform to this requirement produces
+	 * dark horizontal stripes in the image. However, even obeying to this
+	 * requirement doesn't eliminate the stripes in all configurations. They
+	 * appear "locally reproducibly," but can differ between tests under
+	 * different lighting conditions.
+	 */
+	switch (xbin) {
+	case 1:
+		rect->left &= ~1;
+		break;
+	case 2:
+		rect->left &= ~3;
+		break;
+	case 3:
+		rect->left = rect->left > roundup(MT9T031_COLUMN_SKIP, 6) ?
+			(rect->left / 6) * 6 : roundup(MT9T031_COLUMN_SKIP, 6);
+	}
+
+	rect->top &= ~1;
+
+	dev_dbg(&client->dev, "skip %u:%u, rect %ux%u@%u:%u\n",
+		xskip, yskip, rect->width, rect->height, rect->left, rect->top);
+
+	/* Disable register update, reconfigure atomically */
+	ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 1);
+	if (ret < 0)
+		return ret;
+
+	/* Blanking and start values - default... */
+	ret = reg_write(client, MT9T031_HORIZONTAL_BLANKING, hblank);
+	if (ret >= 0)
+		ret = reg_write(client, MT9T031_VERTICAL_BLANKING, vblank);
+
+	if (yskip != mt9t031->yskip || xskip != mt9t031->xskip) {
+		/* Binning, skipping */
+		if (ret >= 0)
+			ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE,
+					((xbin - 1) << 4) | (xskip - 1));
+		if (ret >= 0)
+			ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE,
+					((ybin - 1) << 4) | (yskip - 1));
+	}
+	dev_dbg(&client->dev, "new physical left %u, top %u\n",
+		rect->left, rect->top);
+
+	/*
+	 * The caller provides a supported format, as guaranteed by
+	 * .try_mbus_fmt(), soc_camera_s_crop() and soc_camera_cropcap()
+	 */
+	if (ret >= 0)
+		ret = reg_write(client, MT9T031_COLUMN_START, rect->left);
+	if (ret >= 0)
+		ret = reg_write(client, MT9T031_ROW_START, rect->top);
+	if (ret >= 0)
+		ret = reg_write(client, MT9T031_WINDOW_WIDTH, rect->width - 1);
+	if (ret >= 0)
+		ret = reg_write(client, MT9T031_WINDOW_HEIGHT,
+				rect->height + mt9t031->y_skip_top - 1);
+	if (ret >= 0 && v4l2_ctrl_g_ctrl(mt9t031->autoexposure) == V4L2_EXPOSURE_AUTO) {
+		mt9t031->total_h = rect->height + mt9t031->y_skip_top + vblank;
+
+		ret = set_shutter(client, mt9t031->total_h);
+	}
+
+	/* Re-enable register update, commit all changes */
+	if (ret >= 0)
+		ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1);
+
+	if (ret >= 0) {
+		mt9t031->rect = *rect;
+		mt9t031->xskip = xskip;
+		mt9t031->yskip = yskip;
+	}
+
+	return ret < 0 ? ret : 0;
+}
+
+static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct v4l2_rect rect = a->c;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9t031 *mt9t031 = to_mt9t031(client);
+
+	rect.width = ALIGN(rect.width, 2);
+	rect.height = ALIGN(rect.height, 2);
+
+	soc_camera_limit_side(&rect.left, &rect.width,
+		     MT9T031_COLUMN_SKIP, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH);
+
+	soc_camera_limit_side(&rect.top, &rect.height,
+		     MT9T031_ROW_SKIP, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT);
+
+	return mt9t031_set_params(client, &rect, mt9t031->xskip, mt9t031->yskip);
+}
+
+static int mt9t031_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9t031 *mt9t031 = to_mt9t031(client);
+
+	a->c	= mt9t031->rect;
+	a->type	= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	a->bounds.left			= MT9T031_COLUMN_SKIP;
+	a->bounds.top			= MT9T031_ROW_SKIP;
+	a->bounds.width			= MT9T031_MAX_WIDTH;
+	a->bounds.height		= MT9T031_MAX_HEIGHT;
+	a->defrect			= a->bounds;
+	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int mt9t031_g_fmt(struct v4l2_subdev *sd,
+			 struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9t031 *mt9t031 = to_mt9t031(client);
+
+	mf->width	= mt9t031->rect.width / mt9t031->xskip;
+	mf->height	= mt9t031->rect.height / mt9t031->yskip;
+	mf->code	= V4L2_MBUS_FMT_SBGGR10_1X10;
+	mf->colorspace	= V4L2_COLORSPACE_SRGB;
+	mf->field	= V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static int mt9t031_s_fmt(struct v4l2_subdev *sd,
+			 struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9t031 *mt9t031 = to_mt9t031(client);
+	u16 xskip, yskip;
+	struct v4l2_rect rect = mt9t031->rect;
+
+	/*
+	 * try_fmt has put width and height within limits.
+	 * S_FMT: use binning and skipping for scaling
+	 */
+	xskip = mt9t031_skip(&rect.width, mf->width, MT9T031_MAX_WIDTH);
+	yskip = mt9t031_skip(&rect.height, mf->height, MT9T031_MAX_HEIGHT);
+
+	mf->code	= V4L2_MBUS_FMT_SBGGR10_1X10;
+	mf->colorspace	= V4L2_COLORSPACE_SRGB;
+
+	/* mt9t031_set_params() doesn't change width and height */
+	return mt9t031_set_params(client, &rect, xskip, yskip);
+}
+
+/*
+ * If a user window larger than sensor window is requested, we'll increase the
+ * sensor window.
+ */
+static int mt9t031_try_fmt(struct v4l2_subdev *sd,
+			   struct v4l2_mbus_framefmt *mf)
+{
+	v4l_bound_align_image(
+		&mf->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1,
+		&mf->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0);
+
+	mf->code	= V4L2_MBUS_FMT_SBGGR10_1X10;
+	mf->colorspace	= V4L2_COLORSPACE_SRGB;
+
+	return 0;
+}
+
+static int mt9t031_g_chip_ident(struct v4l2_subdev *sd,
+				struct v4l2_dbg_chip_ident *id)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9t031 *mt9t031 = to_mt9t031(client);
+
+	if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+
+	if (id->match.addr != client->addr)
+		return -ENODEV;
+
+	id->ident	= mt9t031->model;
+	id->revision	= 0;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9t031_g_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+		return -EINVAL;
+
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	reg->val = reg_read(client, reg->reg);
+
+	if (reg->val > 0xffff)
+		return -EIO;
+
+	return 0;
+}
+
+static int mt9t031_s_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+		return -EINVAL;
+
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	if (reg_write(client, reg->reg, reg->val) < 0)
+		return -EIO;
+
+	return 0;
+}
+#endif
+
+static int mt9t031_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mt9t031 *mt9t031 = container_of(ctrl->handler,
+					       struct mt9t031, hdl);
+	const u32 shutter_max = MT9T031_MAX_HEIGHT + MT9T031_VERTICAL_BLANK;
+	s32 min, max;
+
+	switch (ctrl->id) {
+	case V4L2_CID_EXPOSURE_AUTO:
+		min = mt9t031->exposure->minimum;
+		max = mt9t031->exposure->maximum;
+		mt9t031->exposure->val =
+			(shutter_max / 2 + (mt9t031->total_h - 1) * (max - min))
+				/ shutter_max + min;
+		break;
+	}
+	return 0;
+}
+
+static int mt9t031_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mt9t031 *mt9t031 = container_of(ctrl->handler,
+					       struct mt9t031, hdl);
+	struct v4l2_subdev *sd = &mt9t031->subdev;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct v4l2_ctrl *exp = mt9t031->exposure;
+	int data;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		if (ctrl->val)
+			data = reg_set(client, MT9T031_READ_MODE_2, 0x8000);
+		else
+			data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000);
+		if (data < 0)
+			return -EIO;
+		return 0;
+	case V4L2_CID_HFLIP:
+		if (ctrl->val)
+			data = reg_set(client, MT9T031_READ_MODE_2, 0x4000);
+		else
+			data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000);
+		if (data < 0)
+			return -EIO;
+		return 0;
+	case V4L2_CID_GAIN:
+		/* See Datasheet Table 7, Gain settings. */
+		if (ctrl->val <= ctrl->default_value) {
+			/* Pack it into 0..1 step 0.125, register values 0..8 */
+			unsigned long range = ctrl->default_value - ctrl->minimum;
+			data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range;
+
+			dev_dbg(&client->dev, "Setting gain %d\n", data);
+			data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
+			if (data < 0)
+				return -EIO;
+		} else {
+			/* Pack it into 1.125..128 variable step, register values 9..0x7860 */
+			/* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
+			unsigned long range = ctrl->maximum - ctrl->default_value - 1;
+			/* calculated gain: map 65..127 to 9..1024 step 0.125 */
+			unsigned long gain = ((ctrl->val - ctrl->default_value - 1) *
+					       1015 + range / 2) / range + 9;
+
+			if (gain <= 32)		/* calculated gain 9..32 -> 9..32 */
+				data = gain;
+			else if (gain <= 64)	/* calculated gain 33..64 -> 0x51..0x60 */
+				data = ((gain - 32) * 16 + 16) / 32 + 80;
+			else
+				/* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */
+				data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60;
+
+			dev_dbg(&client->dev, "Set gain from 0x%x to 0x%x\n",
+				reg_read(client, MT9T031_GLOBAL_GAIN), data);
+			data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
+			if (data < 0)
+				return -EIO;
+		}
+		return 0;
+
+	case V4L2_CID_EXPOSURE_AUTO:
+		if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
+			unsigned int range = exp->maximum - exp->minimum;
+			unsigned int shutter = ((exp->val - exp->minimum) * 1048 +
+						 range / 2) / range + 1;
+			u32 old;
+
+			get_shutter(client, &old);
+			dev_dbg(&client->dev, "Set shutter from %u to %u\n",
+				old, shutter);
+			if (set_shutter(client, shutter) < 0)
+				return -EIO;
+		} else {
+			const u16 vblank = MT9T031_VERTICAL_BLANK;
+			mt9t031->total_h = mt9t031->rect.height +
+				mt9t031->y_skip_top + vblank;
+
+			if (set_shutter(client, mt9t031->total_h) < 0)
+				return -EIO;
+		}
+		return 0;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * Power Management:
+ * This function does nothing for now but must be present for pm to work
+ */
+static int mt9t031_runtime_suspend(struct device *dev)
+{
+	return 0;
+}
+
+/*
+ * Power Management:
+ * COLUMN_ADDRESS_MODE and ROW_ADDRESS_MODE are not rewritten if unchanged
+ * they are however changed at reset if the platform hook is present
+ * thus we rewrite them with the values stored by the driver
+ */
+static int mt9t031_runtime_resume(struct device *dev)
+{
+	struct video_device *vdev = to_video_device(dev);
+	struct v4l2_subdev *sd = soc_camera_vdev_to_subdev(vdev);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9t031 *mt9t031 = to_mt9t031(client);
+
+	int ret;
+	u16 xbin, ybin;
+
+	xbin = min(mt9t031->xskip, (u16)3);
+	ybin = min(mt9t031->yskip, (u16)3);
+
+	ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE,
+		((xbin - 1) << 4) | (mt9t031->xskip - 1));
+	if (ret < 0)
+		return ret;
+
+	ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE,
+		((ybin - 1) << 4) | (mt9t031->yskip - 1));
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct dev_pm_ops mt9t031_dev_pm_ops = {
+	.runtime_suspend	= mt9t031_runtime_suspend,
+	.runtime_resume		= mt9t031_runtime_resume,
+};
+
+static struct device_type mt9t031_dev_type = {
+	.name	= "MT9T031",
+	.pm	= &mt9t031_dev_pm_ops,
+};
+
+static int mt9t031_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	struct video_device *vdev = soc_camera_i2c_to_vdev(client);
+	int ret;
+
+	if (on) {
+		ret = soc_camera_power_on(&client->dev, icl);
+		if (ret < 0)
+			return ret;
+		vdev->dev.type = &mt9t031_dev_type;
+	} else {
+		vdev->dev.type = NULL;
+		soc_camera_power_off(&client->dev, icl);
+	}
+
+	return 0;
+}
+
+/*
+ * Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one
+ */
+static int mt9t031_video_probe(struct i2c_client *client)
+{
+	struct mt9t031 *mt9t031 = to_mt9t031(client);
+	s32 data;
+	int ret;
+
+	ret = mt9t031_s_power(&mt9t031->subdev, 1);
+	if (ret < 0)
+		return ret;
+
+	ret = mt9t031_idle(client);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to initialise the camera\n");
+		goto done;
+	}
+
+	/* Read out the chip version register */
+	data = reg_read(client, MT9T031_CHIP_VERSION);
+
+	switch (data) {
+	case 0x1621:
+		mt9t031->model = V4L2_IDENT_MT9T031;
+		break;
+	default:
+		dev_err(&client->dev,
+			"No MT9T031 chip detected, register read %x\n", data);
+		ret = -ENODEV;
+		goto done;
+	}
+
+	dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data);
+
+	ret = v4l2_ctrl_handler_setup(&mt9t031->hdl);
+
+done:
+	mt9t031_s_power(&mt9t031->subdev, 0);
+
+	return ret;
+}
+
+static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9t031 *mt9t031 = to_mt9t031(client);
+
+	*lines = mt9t031->y_skip_top;
+
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = {
+	.g_volatile_ctrl = mt9t031_g_volatile_ctrl,
+	.s_ctrl = mt9t031_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = {
+	.g_chip_ident	= mt9t031_g_chip_ident,
+	.s_power	= mt9t031_s_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register	= mt9t031_g_register,
+	.s_register	= mt9t031_s_register,
+#endif
+};
+
+static int mt9t031_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			    enum v4l2_mbus_pixelcode *code)
+{
+	if (index)
+		return -EINVAL;
+
+	*code = V4L2_MBUS_FMT_SBGGR10_1X10;
+	return 0;
+}
+
+static int mt9t031_g_mbus_config(struct v4l2_subdev *sd,
+				struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
+		V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+		V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH;
+	cfg->type = V4L2_MBUS_PARALLEL;
+	cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+	return 0;
+}
+
+static int mt9t031_s_mbus_config(struct v4l2_subdev *sd,
+				const struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	if (soc_camera_apply_board_flags(icl, cfg) &
+	    V4L2_MBUS_PCLK_SAMPLE_FALLING)
+		return reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+	else
+		return reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+}
+
+static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = {
+	.s_stream	= mt9t031_s_stream,
+	.s_mbus_fmt	= mt9t031_s_fmt,
+	.g_mbus_fmt	= mt9t031_g_fmt,
+	.try_mbus_fmt	= mt9t031_try_fmt,
+	.s_crop		= mt9t031_s_crop,
+	.g_crop		= mt9t031_g_crop,
+	.cropcap	= mt9t031_cropcap,
+	.enum_mbus_fmt	= mt9t031_enum_fmt,
+	.g_mbus_config	= mt9t031_g_mbus_config,
+	.s_mbus_config	= mt9t031_s_mbus_config,
+};
+
+static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = {
+	.g_skip_top_lines	= mt9t031_g_skip_top_lines,
+};
+
+static struct v4l2_subdev_ops mt9t031_subdev_ops = {
+	.core	= &mt9t031_subdev_core_ops,
+	.video	= &mt9t031_subdev_video_ops,
+	.sensor	= &mt9t031_subdev_sensor_ops,
+};
+
+static int mt9t031_probe(struct i2c_client *client,
+			 const struct i2c_device_id *did)
+{
+	struct mt9t031 *mt9t031;
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	int ret;
+
+	if (!icl) {
+		dev_err(&client->dev, "MT9T031 driver needs platform data\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_warn(&adapter->dev,
+			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+		return -EIO;
+	}
+
+	mt9t031 = kzalloc(sizeof(struct mt9t031), GFP_KERNEL);
+	if (!mt9t031)
+		return -ENOMEM;
+
+	v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops);
+	v4l2_ctrl_handler_init(&mt9t031->hdl, 5);
+	v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
+			V4L2_CID_HFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
+			V4L2_CID_GAIN, 0, 127, 1, 64);
+
+	/*
+	 * Simulated autoexposure. If enabled, we calculate shutter width
+	 * ourselves in the driver based on vertical blanking and frame width
+	 */
+	mt9t031->autoexposure = v4l2_ctrl_new_std_menu(&mt9t031->hdl,
+			&mt9t031_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
+			V4L2_EXPOSURE_AUTO);
+	mt9t031->exposure = v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
+			V4L2_CID_EXPOSURE, 1, 255, 1, 255);
+
+	mt9t031->subdev.ctrl_handler = &mt9t031->hdl;
+	if (mt9t031->hdl.error) {
+		int err = mt9t031->hdl.error;
+
+		kfree(mt9t031);
+		return err;
+	}
+	v4l2_ctrl_auto_cluster(2, &mt9t031->autoexposure,
+				V4L2_EXPOSURE_MANUAL, true);
+
+	mt9t031->y_skip_top	= 0;
+	mt9t031->rect.left	= MT9T031_COLUMN_SKIP;
+	mt9t031->rect.top	= MT9T031_ROW_SKIP;
+	mt9t031->rect.width	= MT9T031_MAX_WIDTH;
+	mt9t031->rect.height	= MT9T031_MAX_HEIGHT;
+
+	mt9t031->xskip = 1;
+	mt9t031->yskip = 1;
+
+	ret = mt9t031_video_probe(client);
+	if (ret) {
+		v4l2_ctrl_handler_free(&mt9t031->hdl);
+		kfree(mt9t031);
+	}
+
+	return ret;
+}
+
+static int mt9t031_remove(struct i2c_client *client)
+{
+	struct mt9t031 *mt9t031 = to_mt9t031(client);
+
+	v4l2_device_unregister_subdev(&mt9t031->subdev);
+	v4l2_ctrl_handler_free(&mt9t031->hdl);
+	kfree(mt9t031);
+
+	return 0;
+}
+
+static const struct i2c_device_id mt9t031_id[] = {
+	{ "mt9t031", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mt9t031_id);
+
+static struct i2c_driver mt9t031_i2c_driver = {
+	.driver = {
+		.name = "mt9t031",
+	},
+	.probe		= mt9t031_probe,
+	.remove		= mt9t031_remove,
+	.id_table	= mt9t031_id,
+};
+
+module_i2c_driver(mt9t031_i2c_driver);
+
+MODULE_DESCRIPTION("Micron MT9T031 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c
new file mode 100644
index 0000000..9ba428e
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/mt9t112.c
@@ -0,0 +1,1142 @@
+/*
+ * mt9t112 Camera Driver
+ *
+ * Copyright (C) 2009 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov772x driver, mt9m111 driver,
+ *
+ * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/mt9t112.h>
+#include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-common.h>
+
+/* you can check PLL/clock info */
+/* #define EXT_CLOCK 24000000 */
+
+/************************************************************************
+			macro
+************************************************************************/
+/*
+ * frame size
+ */
+#define MAX_WIDTH   2048
+#define MAX_HEIGHT  1536
+
+#define VGA_WIDTH   640
+#define VGA_HEIGHT  480
+
+/*
+ * macro of read/write
+ */
+#define ECHECKER(ret, x)		\
+	do {				\
+		(ret) = (x);		\
+		if ((ret) < 0)		\
+			return (ret);	\
+	} while (0)
+
+#define mt9t112_reg_write(ret, client, a, b) \
+	ECHECKER(ret, __mt9t112_reg_write(client, a, b))
+#define mt9t112_mcu_write(ret, client, a, b) \
+	ECHECKER(ret, __mt9t112_mcu_write(client, a, b))
+
+#define mt9t112_reg_mask_set(ret, client, a, b, c) \
+	ECHECKER(ret, __mt9t112_reg_mask_set(client, a, b, c))
+#define mt9t112_mcu_mask_set(ret, client, a, b, c) \
+	ECHECKER(ret, __mt9t112_mcu_mask_set(client, a, b, c))
+
+#define mt9t112_reg_read(ret, client, a) \
+	ECHECKER(ret, __mt9t112_reg_read(client, a))
+
+/*
+ * Logical address
+ */
+#define _VAR(id, offset, base)	(base | (id & 0x1f) << 10 | (offset & 0x3ff))
+#define VAR(id, offset)  _VAR(id, offset, 0x0000)
+#define VAR8(id, offset) _VAR(id, offset, 0x8000)
+
+/************************************************************************
+			struct
+************************************************************************/
+struct mt9t112_format {
+	enum v4l2_mbus_pixelcode code;
+	enum v4l2_colorspace colorspace;
+	u16 fmt;
+	u16 order;
+};
+
+struct mt9t112_priv {
+	struct v4l2_subdev		 subdev;
+	struct mt9t112_camera_info	*info;
+	struct i2c_client		*client;
+	struct v4l2_rect		 frame;
+	const struct mt9t112_format	*format;
+	int				 model;
+	u32				 flags;
+/* for flags */
+#define INIT_DONE	(1 << 0)
+#define PCLK_RISING	(1 << 1)
+};
+
+/************************************************************************
+			supported format
+************************************************************************/
+
+static const struct mt9t112_format mt9t112_cfmts[] = {
+	{
+		.code		= V4L2_MBUS_FMT_UYVY8_2X8,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.fmt		= 1,
+		.order		= 0,
+	}, {
+		.code		= V4L2_MBUS_FMT_VYUY8_2X8,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.fmt		= 1,
+		.order		= 1,
+	}, {
+		.code		= V4L2_MBUS_FMT_YUYV8_2X8,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.fmt		= 1,
+		.order		= 2,
+	}, {
+		.code		= V4L2_MBUS_FMT_YVYU8_2X8,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.fmt		= 1,
+		.order		= 3,
+	}, {
+		.code		= V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
+		.fmt		= 8,
+		.order		= 2,
+	}, {
+		.code		= V4L2_MBUS_FMT_RGB565_2X8_LE,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
+		.fmt		= 4,
+		.order		= 2,
+	},
+};
+
+/************************************************************************
+			general function
+************************************************************************/
+static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client)
+{
+	return container_of(i2c_get_clientdata(client),
+			    struct mt9t112_priv,
+			    subdev);
+}
+
+static int __mt9t112_reg_read(const struct i2c_client *client, u16 command)
+{
+	struct i2c_msg msg[2];
+	u8 buf[2];
+	int ret;
+
+	command = swab16(command);
+
+	msg[0].addr  = client->addr;
+	msg[0].flags = 0;
+	msg[0].len   = 2;
+	msg[0].buf   = (u8 *)&command;
+
+	msg[1].addr  = client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len   = 2;
+	msg[1].buf   = buf;
+
+	/*
+	 * if return value of this function is < 0,
+	 * it mean error.
+	 * else, under 16bit is valid data.
+	 */
+	ret = i2c_transfer(client->adapter, msg, 2);
+	if (ret < 0)
+		return ret;
+
+	memcpy(&ret, buf, 2);
+	return swab16(ret);
+}
+
+static int __mt9t112_reg_write(const struct i2c_client *client,
+			       u16 command, u16 data)
+{
+	struct i2c_msg msg;
+	u8 buf[4];
+	int ret;
+
+	command = swab16(command);
+	data = swab16(data);
+
+	memcpy(buf + 0, &command, 2);
+	memcpy(buf + 2, &data,    2);
+
+	msg.addr  = client->addr;
+	msg.flags = 0;
+	msg.len   = 4;
+	msg.buf   = buf;
+
+	/*
+	 * i2c_transfer return message length,
+	 * but this function should return 0 if correct case
+	 */
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret >= 0)
+		ret = 0;
+
+	return ret;
+}
+
+static int __mt9t112_reg_mask_set(const struct i2c_client *client,
+				  u16  command,
+				  u16  mask,
+				  u16  set)
+{
+	int val = __mt9t112_reg_read(client, command);
+	if (val < 0)
+		return val;
+
+	val &= ~mask;
+	val |= set & mask;
+
+	return __mt9t112_reg_write(client, command, val);
+}
+
+/* mcu access */
+static int __mt9t112_mcu_read(const struct i2c_client *client, u16 command)
+{
+	int ret;
+
+	ret = __mt9t112_reg_write(client, 0x098E, command);
+	if (ret < 0)
+		return ret;
+
+	return __mt9t112_reg_read(client, 0x0990);
+}
+
+static int __mt9t112_mcu_write(const struct i2c_client *client,
+			       u16 command, u16 data)
+{
+	int ret;
+
+	ret = __mt9t112_reg_write(client, 0x098E, command);
+	if (ret < 0)
+		return ret;
+
+	return __mt9t112_reg_write(client, 0x0990, data);
+}
+
+static int __mt9t112_mcu_mask_set(const struct i2c_client *client,
+				  u16  command,
+				  u16  mask,
+				  u16  set)
+{
+	int val = __mt9t112_mcu_read(client, command);
+	if (val < 0)
+		return val;
+
+	val &= ~mask;
+	val |= set & mask;
+
+	return __mt9t112_mcu_write(client, command, val);
+}
+
+static int mt9t112_reset(const struct i2c_client *client)
+{
+	int ret;
+
+	mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0001);
+	msleep(1);
+	mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0000);
+
+	return ret;
+}
+
+#ifndef EXT_CLOCK
+#define CLOCK_INFO(a, b)
+#else
+#define CLOCK_INFO(a, b) mt9t112_clock_info(a, b)
+static int mt9t112_clock_info(const struct i2c_client *client, u32 ext)
+{
+	int m, n, p1, p2, p3, p4, p5, p6, p7;
+	u32 vco, clk;
+	char *enable;
+
+	ext /= 1000; /* kbyte order */
+
+	mt9t112_reg_read(n, client, 0x0012);
+	p1 = n & 0x000f;
+	n = n >> 4;
+	p2 = n & 0x000f;
+	n = n >> 4;
+	p3 = n & 0x000f;
+
+	mt9t112_reg_read(n, client, 0x002a);
+	p4 = n & 0x000f;
+	n = n >> 4;
+	p5 = n & 0x000f;
+	n = n >> 4;
+	p6 = n & 0x000f;
+
+	mt9t112_reg_read(n, client, 0x002c);
+	p7 = n & 0x000f;
+
+	mt9t112_reg_read(n, client, 0x0010);
+	m = n & 0x00ff;
+	n = (n >> 8) & 0x003f;
+
+	enable = ((6000 > ext) || (54000 < ext)) ? "X" : "";
+	dev_dbg(&client->dev, "EXTCLK          : %10u K %s\n", ext, enable);
+
+	vco = 2 * m * ext / (n+1);
+	enable = ((384000 > vco) || (768000 < vco)) ? "X" : "";
+	dev_dbg(&client->dev, "VCO             : %10u K %s\n", vco, enable);
+
+	clk = vco / (p1+1) / (p2+1);
+	enable = (96000 < clk) ? "X" : "";
+	dev_dbg(&client->dev, "PIXCLK          : %10u K %s\n", clk, enable);
+
+	clk = vco / (p3+1);
+	enable = (768000 < clk) ? "X" : "";
+	dev_dbg(&client->dev, "MIPICLK         : %10u K %s\n", clk, enable);
+
+	clk = vco / (p6+1);
+	enable = (96000 < clk) ? "X" : "";
+	dev_dbg(&client->dev, "MCU CLK         : %10u K %s\n", clk, enable);
+
+	clk = vco / (p5+1);
+	enable = (54000 < clk) ? "X" : "";
+	dev_dbg(&client->dev, "SOC CLK         : %10u K %s\n", clk, enable);
+
+	clk = vco / (p4+1);
+	enable = (70000 < clk) ? "X" : "";
+	dev_dbg(&client->dev, "Sensor CLK      : %10u K %s\n", clk, enable);
+
+	clk = vco / (p7+1);
+	dev_dbg(&client->dev, "External sensor : %10u K\n", clk);
+
+	clk = ext / (n+1);
+	enable = ((2000 > clk) || (24000 < clk)) ? "X" : "";
+	dev_dbg(&client->dev, "PFD             : %10u K %s\n", clk, enable);
+
+	return 0;
+}
+#endif
+
+static void mt9t112_frame_check(u32 *width, u32 *height, u32 *left, u32 *top)
+{
+	soc_camera_limit_side(left, width, 0, 0, MAX_WIDTH);
+	soc_camera_limit_side(top, height, 0, 0, MAX_HEIGHT);
+}
+
+static int mt9t112_set_a_frame_size(const struct i2c_client *client,
+				   u16 width,
+				   u16 height)
+{
+	int ret;
+	u16 wstart = (MAX_WIDTH - width) / 2;
+	u16 hstart = (MAX_HEIGHT - height) / 2;
+
+	/* (Context A) Image Width/Height */
+	mt9t112_mcu_write(ret, client, VAR(26, 0), width);
+	mt9t112_mcu_write(ret, client, VAR(26, 2), height);
+
+	/* (Context A) Output Width/Height */
+	mt9t112_mcu_write(ret, client, VAR(18, 43), 8 + width);
+	mt9t112_mcu_write(ret, client, VAR(18, 45), 8 + height);
+
+	/* (Context A) Start Row/Column */
+	mt9t112_mcu_write(ret, client, VAR(18, 2), 4 + hstart);
+	mt9t112_mcu_write(ret, client, VAR(18, 4), 4 + wstart);
+
+	/* (Context A) End Row/Column */
+	mt9t112_mcu_write(ret, client, VAR(18, 6), 11 + height + hstart);
+	mt9t112_mcu_write(ret, client, VAR(18, 8), 11 + width  + wstart);
+
+	mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06);
+
+	return ret;
+}
+
+static int mt9t112_set_pll_dividers(const struct i2c_client *client,
+				    u8 m, u8 n,
+				    u8 p1, u8 p2, u8 p3,
+				    u8 p4, u8 p5, u8 p6,
+				    u8 p7)
+{
+	int ret;
+	u16 val;
+
+	/* N/M */
+	val = (n << 8) |
+	      (m << 0);
+	mt9t112_reg_mask_set(ret, client, 0x0010, 0x3fff, val);
+
+	/* P1/P2/P3 */
+	val = ((p3 & 0x0F) << 8) |
+	      ((p2 & 0x0F) << 4) |
+	      ((p1 & 0x0F) << 0);
+	mt9t112_reg_mask_set(ret, client, 0x0012, 0x0fff, val);
+
+	/* P4/P5/P6 */
+	val = (0x7         << 12) |
+	      ((p6 & 0x0F) <<  8) |
+	      ((p5 & 0x0F) <<  4) |
+	      ((p4 & 0x0F) <<  0);
+	mt9t112_reg_mask_set(ret, client, 0x002A, 0x7fff, val);
+
+	/* P7 */
+	val = (0x1         << 12) |
+	      ((p7 & 0x0F) <<  0);
+	mt9t112_reg_mask_set(ret, client, 0x002C, 0x100f, val);
+
+	return ret;
+}
+
+static int mt9t112_init_pll(const struct i2c_client *client)
+{
+	struct mt9t112_priv *priv = to_mt9t112(client);
+	int data, i, ret;
+
+	mt9t112_reg_mask_set(ret, client, 0x0014, 0x003, 0x0001);
+
+	/* PLL control: BYPASS PLL = 8517 */
+	mt9t112_reg_write(ret, client, 0x0014, 0x2145);
+
+	/* Replace these registers when new timing parameters are generated */
+	mt9t112_set_pll_dividers(client,
+				 priv->info->divider.m,
+				 priv->info->divider.n,
+				 priv->info->divider.p1,
+				 priv->info->divider.p2,
+				 priv->info->divider.p3,
+				 priv->info->divider.p4,
+				 priv->info->divider.p5,
+				 priv->info->divider.p6,
+				 priv->info->divider.p7);
+
+	/*
+	 * TEST_BYPASS  on
+	 * PLL_ENABLE   on
+	 * SEL_LOCK_DET on
+	 * TEST_BYPASS  off
+	 */
+	mt9t112_reg_write(ret, client, 0x0014, 0x2525);
+	mt9t112_reg_write(ret, client, 0x0014, 0x2527);
+	mt9t112_reg_write(ret, client, 0x0014, 0x3427);
+	mt9t112_reg_write(ret, client, 0x0014, 0x3027);
+
+	mdelay(10);
+
+	/*
+	 * PLL_BYPASS off
+	 * Reference clock count
+	 * I2C Master Clock Divider
+	 */
+	mt9t112_reg_write(ret, client, 0x0014, 0x3046);
+	mt9t112_reg_write(ret, client, 0x0016, 0x0400); /* JPEG initialization workaround */
+	mt9t112_reg_write(ret, client, 0x0022, 0x0190);
+	mt9t112_reg_write(ret, client, 0x3B84, 0x0212);
+
+	/* External sensor clock is PLL bypass */
+	mt9t112_reg_write(ret, client, 0x002E, 0x0500);
+
+	mt9t112_reg_mask_set(ret, client, 0x0018, 0x0002, 0x0002);
+	mt9t112_reg_mask_set(ret, client, 0x3B82, 0x0004, 0x0004);
+
+	/* MCU disabled */
+	mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0x0004);
+
+	/* out of standby */
+	mt9t112_reg_mask_set(ret, client, 0x0018, 0x0001, 0);
+
+	mdelay(50);
+
+	/*
+	 * Standby Workaround
+	 * Disable Secondary I2C Pads
+	 */
+	mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+	mdelay(1);
+	mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+	mdelay(1);
+	mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+	mdelay(1);
+	mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+	mdelay(1);
+	mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+	mdelay(1);
+	mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+	mdelay(1);
+
+	/* poll to verify out of standby. Must Poll this bit */
+	for (i = 0; i < 100; i++) {
+		mt9t112_reg_read(data, client, 0x0018);
+		if (!(0x4000 & data))
+			break;
+
+		mdelay(10);
+	}
+
+	return ret;
+}
+
+static int mt9t112_init_setting(const struct i2c_client *client)
+{
+
+	int ret;
+
+	/* Adaptive Output Clock (A) */
+	mt9t112_mcu_mask_set(ret, client, VAR(26, 160), 0x0040, 0x0000);
+
+	/* Read Mode (A) */
+	mt9t112_mcu_write(ret, client, VAR(18, 12), 0x0024);
+
+	/* Fine Correction (A) */
+	mt9t112_mcu_write(ret, client, VAR(18, 15), 0x00CC);
+
+	/* Fine IT Min (A) */
+	mt9t112_mcu_write(ret, client, VAR(18, 17), 0x01f1);
+
+	/* Fine IT Max Margin (A) */
+	mt9t112_mcu_write(ret, client, VAR(18, 19), 0x00fF);
+
+	/* Base Frame Lines (A) */
+	mt9t112_mcu_write(ret, client, VAR(18, 29), 0x032D);
+
+	/* Min Line Length (A) */
+	mt9t112_mcu_write(ret, client, VAR(18, 31), 0x073a);
+
+	/* Line Length (A) */
+	mt9t112_mcu_write(ret, client, VAR(18, 37), 0x07d0);
+
+	/* Adaptive Output Clock (B) */
+	mt9t112_mcu_mask_set(ret, client, VAR(27, 160), 0x0040, 0x0000);
+
+	/* Row Start (B) */
+	mt9t112_mcu_write(ret, client, VAR(18, 74), 0x004);
+
+	/* Column Start (B) */
+	mt9t112_mcu_write(ret, client, VAR(18, 76), 0x004);
+
+	/* Row End (B) */
+	mt9t112_mcu_write(ret, client, VAR(18, 78), 0x60B);
+
+	/* Column End (B) */
+	mt9t112_mcu_write(ret, client, VAR(18, 80), 0x80B);
+
+	/* Fine Correction (B) */
+	mt9t112_mcu_write(ret, client, VAR(18, 87), 0x008C);
+
+	/* Fine IT Min (B) */
+	mt9t112_mcu_write(ret, client, VAR(18, 89), 0x01F1);
+
+	/* Fine IT Max Margin (B) */
+	mt9t112_mcu_write(ret, client, VAR(18, 91), 0x00FF);
+
+	/* Base Frame Lines (B) */
+	mt9t112_mcu_write(ret, client, VAR(18, 101), 0x0668);
+
+	/* Min Line Length (B) */
+	mt9t112_mcu_write(ret, client, VAR(18, 103), 0x0AF0);
+
+	/* Line Length (B) */
+	mt9t112_mcu_write(ret, client, VAR(18, 109), 0x0AF0);
+
+	/*
+	 * Flicker Dectection registers
+	 * This section should be replaced whenever new Timing file is generated
+	 * All the following registers need to be replaced
+	 * Following registers are generated from Register Wizard but user can
+	 * modify them. For detail see auto flicker detection tuning
+	 */
+
+	/* FD_FDPERIOD_SELECT */
+	mt9t112_mcu_write(ret, client, VAR8(8, 5), 0x01);
+
+	/* PRI_B_CONFIG_FD_ALGO_RUN */
+	mt9t112_mcu_write(ret, client, VAR(27, 17), 0x0003);
+
+	/* PRI_A_CONFIG_FD_ALGO_RUN */
+	mt9t112_mcu_write(ret, client, VAR(26, 17), 0x0003);
+
+	/*
+	 * AFD range detection tuning registers
+	 */
+
+	/* search_f1_50 */
+	mt9t112_mcu_write(ret, client, VAR8(18, 165), 0x25);
+
+	/* search_f2_50 */
+	mt9t112_mcu_write(ret, client, VAR8(18, 166), 0x28);
+
+	/* search_f1_60 */
+	mt9t112_mcu_write(ret, client, VAR8(18, 167), 0x2C);
+
+	/* search_f2_60 */
+	mt9t112_mcu_write(ret, client, VAR8(18, 168), 0x2F);
+
+	/* period_50Hz (A) */
+	mt9t112_mcu_write(ret, client, VAR8(18, 68), 0xBA);
+
+	/* secret register by aptina */
+	/* period_50Hz (A MSB) */
+	mt9t112_mcu_write(ret, client, VAR8(18, 303), 0x00);
+
+	/* period_60Hz (A) */
+	mt9t112_mcu_write(ret, client, VAR8(18, 69), 0x9B);
+
+	/* secret register by aptina */
+	/* period_60Hz (A MSB) */
+	mt9t112_mcu_write(ret, client, VAR8(18, 301), 0x00);
+
+	/* period_50Hz (B) */
+	mt9t112_mcu_write(ret, client, VAR8(18, 140), 0x82);
+
+	/* secret register by aptina */
+	/* period_50Hz (B) MSB */
+	mt9t112_mcu_write(ret, client, VAR8(18, 304), 0x00);
+
+	/* period_60Hz (B) */
+	mt9t112_mcu_write(ret, client, VAR8(18, 141), 0x6D);
+
+	/* secret register by aptina */
+	/* period_60Hz (B) MSB */
+	mt9t112_mcu_write(ret, client, VAR8(18, 302), 0x00);
+
+	/* FD Mode */
+	mt9t112_mcu_write(ret, client, VAR8(8, 2), 0x10);
+
+	/* Stat_min */
+	mt9t112_mcu_write(ret, client, VAR8(8, 9), 0x02);
+
+	/* Stat_max */
+	mt9t112_mcu_write(ret, client, VAR8(8, 10), 0x03);
+
+	/* Min_amplitude */
+	mt9t112_mcu_write(ret, client, VAR8(8, 12), 0x0A);
+
+	/* RX FIFO Watermark (A) */
+	mt9t112_mcu_write(ret, client, VAR(18, 70), 0x0014);
+
+	/* RX FIFO Watermark (B) */
+	mt9t112_mcu_write(ret, client, VAR(18, 142), 0x0014);
+
+	/* MCLK: 16MHz
+	 * PCLK: 73MHz
+	 * CorePixCLK: 36.5 MHz
+	 */
+	mt9t112_mcu_write(ret, client, VAR8(18, 0x0044), 133);
+	mt9t112_mcu_write(ret, client, VAR8(18, 0x0045), 110);
+	mt9t112_mcu_write(ret, client, VAR8(18, 0x008c), 130);
+	mt9t112_mcu_write(ret, client, VAR8(18, 0x008d), 108);
+
+	mt9t112_mcu_write(ret, client, VAR8(18, 0x00A5), 27);
+	mt9t112_mcu_write(ret, client, VAR8(18, 0x00a6), 30);
+	mt9t112_mcu_write(ret, client, VAR8(18, 0x00a7), 32);
+	mt9t112_mcu_write(ret, client, VAR8(18, 0x00a8), 35);
+
+	return ret;
+}
+
+static int mt9t112_auto_focus_setting(const struct i2c_client *client)
+{
+	int ret;
+
+	mt9t112_mcu_write(ret, client, VAR(12, 13),	0x000F);
+	mt9t112_mcu_write(ret, client, VAR(12, 23),	0x0F0F);
+	mt9t112_mcu_write(ret, client, VAR8(1, 0),	0x06);
+
+	mt9t112_reg_write(ret, client, 0x0614, 0x0000);
+
+	mt9t112_mcu_write(ret, client, VAR8(1, 0),	0x05);
+	mt9t112_mcu_write(ret, client, VAR8(12, 2),	0x02);
+	mt9t112_mcu_write(ret, client, VAR(12, 3),	0x0002);
+	mt9t112_mcu_write(ret, client, VAR(17, 3),	0x8001);
+	mt9t112_mcu_write(ret, client, VAR(17, 11),	0x0025);
+	mt9t112_mcu_write(ret, client, VAR(17, 13),	0x0193);
+	mt9t112_mcu_write(ret, client, VAR8(17, 33),	0x18);
+	mt9t112_mcu_write(ret, client, VAR8(1, 0),	0x05);
+
+	return ret;
+}
+
+static int mt9t112_auto_focus_trigger(const struct i2c_client *client)
+{
+	int ret;
+
+	mt9t112_mcu_write(ret, client, VAR8(12, 25), 0x01);
+
+	return ret;
+}
+
+static int mt9t112_init_camera(const struct i2c_client *client)
+{
+	int ret;
+
+	ECHECKER(ret, mt9t112_reset(client));
+
+	ECHECKER(ret, mt9t112_init_pll(client));
+
+	ECHECKER(ret, mt9t112_init_setting(client));
+
+	ECHECKER(ret, mt9t112_auto_focus_setting(client));
+
+	mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0);
+
+	/* Analog setting B */
+	mt9t112_reg_write(ret, client, 0x3084, 0x2409);
+	mt9t112_reg_write(ret, client, 0x3092, 0x0A49);
+	mt9t112_reg_write(ret, client, 0x3094, 0x4949);
+	mt9t112_reg_write(ret, client, 0x3096, 0x4950);
+
+	/*
+	 * Disable adaptive clock
+	 * PRI_A_CONFIG_JPEG_OB_TX_CONTROL_VAR
+	 * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR
+	 */
+	mt9t112_mcu_write(ret, client, VAR(26, 160), 0x0A2E);
+	mt9t112_mcu_write(ret, client, VAR(27, 160), 0x0A2E);
+
+	/* Configure STatus in Status_before_length Format and enable header */
+	/* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */
+	mt9t112_mcu_write(ret, client, VAR(27, 144), 0x0CB4);
+
+	/* Enable JPEG in context B */
+	/* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */
+	mt9t112_mcu_write(ret, client, VAR8(27, 142), 0x01);
+
+	/* Disable Dac_TXLO */
+	mt9t112_reg_write(ret, client, 0x316C, 0x350F);
+
+	/* Set max slew rates */
+	mt9t112_reg_write(ret, client, 0x1E, 0x777);
+
+	return ret;
+}
+
+/************************************************************************
+			v4l2_subdev_core_ops
+************************************************************************/
+static int mt9t112_g_chip_ident(struct v4l2_subdev *sd,
+				struct v4l2_dbg_chip_ident *id)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9t112_priv *priv = to_mt9t112(client);
+
+	id->ident    = priv->model;
+	id->revision = 0;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9t112_g_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int                ret;
+
+	reg->size = 2;
+	mt9t112_reg_read(ret, client, reg->reg);
+
+	reg->val = (__u64)ret;
+
+	return 0;
+}
+
+static int mt9t112_s_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+
+	mt9t112_reg_write(ret, client, reg->reg, reg->val);
+
+	return ret;
+}
+#endif
+
+static int mt9t112_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	return soc_camera_set_power(&client->dev, icl, on);
+}
+
+static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = {
+	.g_chip_ident	= mt9t112_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register	= mt9t112_g_register,
+	.s_register	= mt9t112_s_register,
+#endif
+	.s_power	= mt9t112_s_power,
+};
+
+
+/************************************************************************
+			v4l2_subdev_video_ops
+************************************************************************/
+static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9t112_priv *priv = to_mt9t112(client);
+	int ret = 0;
+
+	if (!enable) {
+		/* FIXME
+		 *
+		 * If user selected large output size,
+		 * and used it long time,
+		 * mt9t112 camera will be very warm.
+		 *
+		 * But current driver can not stop mt9t112 camera.
+		 * So, set small size here to solve this problem.
+		 */
+		mt9t112_set_a_frame_size(client, VGA_WIDTH, VGA_HEIGHT);
+		return ret;
+	}
+
+	if (!(priv->flags & INIT_DONE)) {
+		u16 param = PCLK_RISING & priv->flags ? 0x0001 : 0x0000;
+
+		ECHECKER(ret, mt9t112_init_camera(client));
+
+		/* Invert PCLK (Data sampled on falling edge of pixclk) */
+		mt9t112_reg_write(ret, client, 0x3C20, param);
+
+		mdelay(5);
+
+		priv->flags |= INIT_DONE;
+	}
+
+	mt9t112_mcu_write(ret, client, VAR(26, 7), priv->format->fmt);
+	mt9t112_mcu_write(ret, client, VAR(26, 9), priv->format->order);
+	mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06);
+
+	mt9t112_set_a_frame_size(client,
+				 priv->frame.width,
+				 priv->frame.height);
+
+	ECHECKER(ret, mt9t112_auto_focus_trigger(client));
+
+	dev_dbg(&client->dev, "format : %d\n", priv->format->code);
+	dev_dbg(&client->dev, "size   : %d x %d\n",
+		priv->frame.width,
+		priv->frame.height);
+
+	CLOCK_INFO(client, EXT_CLOCK);
+
+	return ret;
+}
+
+static int mt9t112_set_params(struct mt9t112_priv *priv,
+			      const struct v4l2_rect *rect,
+			      enum v4l2_mbus_pixelcode code)
+{
+	int i;
+
+	/*
+	 * get color format
+	 */
+	for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++)
+		if (mt9t112_cfmts[i].code == code)
+			break;
+
+	if (i == ARRAY_SIZE(mt9t112_cfmts))
+		return -EINVAL;
+
+	priv->frame  = *rect;
+
+	/*
+	 * frame size check
+	 */
+	mt9t112_frame_check(&priv->frame.width, &priv->frame.height,
+			    &priv->frame.left, &priv->frame.top);
+
+	priv->format = mt9t112_cfmts + i;
+
+	return 0;
+}
+
+static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	a->bounds.left			= 0;
+	a->bounds.top			= 0;
+	a->bounds.width			= MAX_WIDTH;
+	a->bounds.height		= MAX_HEIGHT;
+	a->defrect.left			= 0;
+	a->defrect.top			= 0;
+	a->defrect.width		= VGA_WIDTH;
+	a->defrect.height		= VGA_HEIGHT;
+	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9t112_priv *priv = to_mt9t112(client);
+
+	a->c	= priv->frame;
+	a->type	= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9t112_priv *priv = to_mt9t112(client);
+	struct v4l2_rect *rect = &a->c;
+
+	return mt9t112_set_params(priv, rect, priv->format->code);
+}
+
+static int mt9t112_g_fmt(struct v4l2_subdev *sd,
+			 struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9t112_priv *priv = to_mt9t112(client);
+
+	mf->width	= priv->frame.width;
+	mf->height	= priv->frame.height;
+	mf->colorspace	= priv->format->colorspace;
+	mf->code	= priv->format->code;
+	mf->field	= V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static int mt9t112_s_fmt(struct v4l2_subdev *sd,
+			 struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9t112_priv *priv = to_mt9t112(client);
+	struct v4l2_rect rect = {
+		.width = mf->width,
+		.height = mf->height,
+		.left = priv->frame.left,
+		.top = priv->frame.top,
+	};
+	int ret;
+
+	ret = mt9t112_set_params(priv, &rect, mf->code);
+
+	if (!ret)
+		mf->colorspace = priv->format->colorspace;
+
+	return ret;
+}
+
+static int mt9t112_try_fmt(struct v4l2_subdev *sd,
+			   struct v4l2_mbus_framefmt *mf)
+{
+	unsigned int top, left;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++)
+		if (mt9t112_cfmts[i].code == mf->code)
+			break;
+
+	if (i == ARRAY_SIZE(mt9t112_cfmts)) {
+		mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+		mf->colorspace = V4L2_COLORSPACE_JPEG;
+	} else {
+		mf->colorspace	= mt9t112_cfmts[i].colorspace;
+	}
+
+	mt9t112_frame_check(&mf->width, &mf->height, &left, &top);
+
+	mf->field = V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			   enum v4l2_mbus_pixelcode *code)
+{
+	if (index >= ARRAY_SIZE(mt9t112_cfmts))
+		return -EINVAL;
+
+	*code = mt9t112_cfmts[index].code;
+
+	return 0;
+}
+
+static int mt9t112_g_mbus_config(struct v4l2_subdev *sd,
+				 struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
+		V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH |
+		V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING;
+	cfg->type = V4L2_MBUS_PARALLEL;
+	cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+	return 0;
+}
+
+static int mt9t112_s_mbus_config(struct v4l2_subdev *sd,
+				 const struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	struct mt9t112_priv *priv = to_mt9t112(client);
+
+	if (soc_camera_apply_board_flags(icl, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING)
+		priv->flags |= PCLK_RISING;
+
+	return 0;
+}
+
+static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = {
+	.s_stream	= mt9t112_s_stream,
+	.g_mbus_fmt	= mt9t112_g_fmt,
+	.s_mbus_fmt	= mt9t112_s_fmt,
+	.try_mbus_fmt	= mt9t112_try_fmt,
+	.cropcap	= mt9t112_cropcap,
+	.g_crop		= mt9t112_g_crop,
+	.s_crop		= mt9t112_s_crop,
+	.enum_mbus_fmt	= mt9t112_enum_fmt,
+	.g_mbus_config	= mt9t112_g_mbus_config,
+	.s_mbus_config	= mt9t112_s_mbus_config,
+};
+
+/************************************************************************
+			i2c driver
+************************************************************************/
+static struct v4l2_subdev_ops mt9t112_subdev_ops = {
+	.core	= &mt9t112_subdev_core_ops,
+	.video	= &mt9t112_subdev_video_ops,
+};
+
+static int mt9t112_camera_probe(struct i2c_client *client)
+{
+	struct mt9t112_priv *priv = to_mt9t112(client);
+	const char          *devname;
+	int                  chipid;
+	int		     ret;
+
+	ret = mt9t112_s_power(&priv->subdev, 1);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * check and show chip ID
+	 */
+	mt9t112_reg_read(chipid, client, 0x0000);
+
+	switch (chipid) {
+	case 0x2680:
+		devname = "mt9t111";
+		priv->model = V4L2_IDENT_MT9T111;
+		break;
+	case 0x2682:
+		devname = "mt9t112";
+		priv->model = V4L2_IDENT_MT9T112;
+		break;
+	default:
+		dev_err(&client->dev, "Product ID error %04x\n", chipid);
+		ret = -ENODEV;
+		goto done;
+	}
+
+	dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid);
+
+done:
+	mt9t112_s_power(&priv->subdev, 0);
+	return ret;
+}
+
+static int mt9t112_probe(struct i2c_client *client,
+			 const struct i2c_device_id *did)
+{
+	struct mt9t112_priv *priv;
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	struct v4l2_rect rect = {
+		.width = VGA_WIDTH,
+		.height = VGA_HEIGHT,
+		.left = (MAX_WIDTH - VGA_WIDTH) / 2,
+		.top = (MAX_HEIGHT - VGA_HEIGHT) / 2,
+	};
+	int ret;
+
+	if (!icl || !icl->priv) {
+		dev_err(&client->dev, "mt9t112: missing platform data!\n");
+		return -EINVAL;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->info = icl->priv;
+
+	v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops);
+
+	ret = mt9t112_camera_probe(client);
+	if (ret) {
+		kfree(priv);
+		return ret;
+	}
+
+	/* Cannot fail: using the default supported pixel code */
+	mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8);
+
+	return ret;
+}
+
+static int mt9t112_remove(struct i2c_client *client)
+{
+	struct mt9t112_priv *priv = to_mt9t112(client);
+
+	kfree(priv);
+	return 0;
+}
+
+static const struct i2c_device_id mt9t112_id[] = {
+	{ "mt9t112", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mt9t112_id);
+
+static struct i2c_driver mt9t112_i2c_driver = {
+	.driver = {
+		.name = "mt9t112",
+	},
+	.probe    = mt9t112_probe,
+	.remove   = mt9t112_remove,
+	.id_table = mt9t112_id,
+};
+
+module_i2c_driver(mt9t112_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for mt9t112");
+MODULE_AUTHOR("Kuninori Morimoto");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c
new file mode 100644
index 0000000..350d0d8
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/mt9v022.c
@@ -0,0 +1,919 @@
+/*
+ * Driver for MT9V022 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+/*
+ * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
+ * The platform has to define struct i2c_board_info objects and link to them
+ * from struct soc_camera_link
+ */
+
+static char *sensor_type;
+module_param(sensor_type, charp, S_IRUGO);
+MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
+
+/* mt9v022 selected register addresses */
+#define MT9V022_CHIP_VERSION		0x00
+#define MT9V022_COLUMN_START		0x01
+#define MT9V022_ROW_START		0x02
+#define MT9V022_WINDOW_HEIGHT		0x03
+#define MT9V022_WINDOW_WIDTH		0x04
+#define MT9V022_HORIZONTAL_BLANKING	0x05
+#define MT9V022_VERTICAL_BLANKING	0x06
+#define MT9V022_CHIP_CONTROL		0x07
+#define MT9V022_SHUTTER_WIDTH1		0x08
+#define MT9V022_SHUTTER_WIDTH2		0x09
+#define MT9V022_SHUTTER_WIDTH_CTRL	0x0a
+#define MT9V022_TOTAL_SHUTTER_WIDTH	0x0b
+#define MT9V022_RESET			0x0c
+#define MT9V022_READ_MODE		0x0d
+#define MT9V022_MONITOR_MODE		0x0e
+#define MT9V022_PIXEL_OPERATION_MODE	0x0f
+#define MT9V022_LED_OUT_CONTROL		0x1b
+#define MT9V022_ADC_MODE_CONTROL	0x1c
+#define MT9V022_ANALOG_GAIN		0x35
+#define MT9V022_BLACK_LEVEL_CALIB_CTRL	0x47
+#define MT9V022_PIXCLK_FV_LV		0x74
+#define MT9V022_DIGITAL_TEST_PATTERN	0x7f
+#define MT9V022_AEC_AGC_ENABLE		0xAF
+#define MT9V022_MAX_TOTAL_SHUTTER_WIDTH	0xBD
+
+/* mt9v024 partial list register addresses changes with respect to mt9v022 */
+#define MT9V024_PIXCLK_FV_LV		0x72
+#define MT9V024_MAX_TOTAL_SHUTTER_WIDTH	0xAD
+
+/* Progressive scan, master, defaults */
+#define MT9V022_CHIP_CONTROL_DEFAULT	0x188
+
+#define MT9V022_MAX_WIDTH		752
+#define MT9V022_MAX_HEIGHT		480
+#define MT9V022_MIN_WIDTH		48
+#define MT9V022_MIN_HEIGHT		32
+#define MT9V022_COLUMN_SKIP		1
+#define MT9V022_ROW_SKIP		4
+
+#define is_mt9v024(id) (id == 0x1324)
+
+/* MT9V022 has only one fixed colorspace per pixelcode */
+struct mt9v022_datafmt {
+	enum v4l2_mbus_pixelcode	code;
+	enum v4l2_colorspace		colorspace;
+};
+
+/* Find a data format by a pixel code in an array */
+static const struct mt9v022_datafmt *mt9v022_find_datafmt(
+	enum v4l2_mbus_pixelcode code, const struct mt9v022_datafmt *fmt,
+	int n)
+{
+	int i;
+	for (i = 0; i < n; i++)
+		if (fmt[i].code == code)
+			return fmt + i;
+
+	return NULL;
+}
+
+static const struct mt9v022_datafmt mt9v022_colour_fmts[] = {
+	/*
+	 * Order important: first natively supported,
+	 * second supported with a GPIO extender
+	 */
+	{V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
+	{V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
+};
+
+static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = {
+	/* Order important - see above */
+	{V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
+	{V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
+};
+
+/* only registers with different addresses on different mt9v02x sensors */
+struct mt9v02x_register {
+	u8	max_total_shutter_width;
+	u8	pixclk_fv_lv;
+};
+
+static const struct mt9v02x_register mt9v022_register = {
+	.max_total_shutter_width	= MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
+	.pixclk_fv_lv			= MT9V022_PIXCLK_FV_LV,
+};
+
+static const struct mt9v02x_register mt9v024_register = {
+	.max_total_shutter_width	= MT9V024_MAX_TOTAL_SHUTTER_WIDTH,
+	.pixclk_fv_lv			= MT9V024_PIXCLK_FV_LV,
+};
+
+struct mt9v022 {
+	struct v4l2_subdev subdev;
+	struct v4l2_ctrl_handler hdl;
+	struct {
+		/* exposure/auto-exposure cluster */
+		struct v4l2_ctrl *autoexposure;
+		struct v4l2_ctrl *exposure;
+	};
+	struct {
+		/* gain/auto-gain cluster */
+		struct v4l2_ctrl *autogain;
+		struct v4l2_ctrl *gain;
+	};
+	struct v4l2_rect rect;	/* Sensor window */
+	const struct mt9v022_datafmt *fmt;
+	const struct mt9v022_datafmt *fmts;
+	const struct mt9v02x_register *reg;
+	int num_fmts;
+	int model;	/* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
+	u16 chip_control;
+	unsigned short y_skip_top;	/* Lines to skip at the top */
+};
+
+static struct mt9v022 *to_mt9v022(const struct i2c_client *client)
+{
+	return container_of(i2c_get_clientdata(client), struct mt9v022, subdev);
+}
+
+static int reg_read(struct i2c_client *client, const u8 reg)
+{
+	return i2c_smbus_read_word_swapped(client, reg);
+}
+
+static int reg_write(struct i2c_client *client, const u8 reg,
+		     const u16 data)
+{
+	return i2c_smbus_write_word_swapped(client, reg, data);
+}
+
+static int reg_set(struct i2c_client *client, const u8 reg,
+		   const u16 data)
+{
+	int ret;
+
+	ret = reg_read(client, reg);
+	if (ret < 0)
+		return ret;
+	return reg_write(client, reg, ret | data);
+}
+
+static int reg_clear(struct i2c_client *client, const u8 reg,
+		     const u16 data)
+{
+	int ret;
+
+	ret = reg_read(client, reg);
+	if (ret < 0)
+		return ret;
+	return reg_write(client, reg, ret & ~data);
+}
+
+static int mt9v022_init(struct i2c_client *client)
+{
+	struct mt9v022 *mt9v022 = to_mt9v022(client);
+	int ret;
+
+	/*
+	 * Almost the default mode: master, parallel, simultaneous, and an
+	 * undocumented bit 0x200, which is present in table 7, but not in 8,
+	 * plus snapshot mode to disable scan for now
+	 */
+	mt9v022->chip_control |= 0x10;
+	ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
+	if (!ret)
+		ret = reg_write(client, MT9V022_READ_MODE, 0x300);
+
+	/* All defaults */
+	if (!ret)
+		/* AEC, AGC on */
+		ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3);
+	if (!ret)
+		ret = reg_write(client, MT9V022_ANALOG_GAIN, 16);
+	if (!ret)
+		ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480);
+	if (!ret)
+		ret = reg_write(client, mt9v022->reg->max_total_shutter_width, 480);
+	if (!ret)
+		/* default - auto */
+		ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1);
+	if (!ret)
+		ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0);
+	if (!ret)
+		return v4l2_ctrl_handler_setup(&mt9v022->hdl);
+
+	return ret;
+}
+
+static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+	if (enable)
+		/* Switch to master "normal" mode */
+		mt9v022->chip_control &= ~0x10;
+	else
+		/* Switch to snapshot mode */
+		mt9v022->chip_control |= 0x10;
+
+	if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0)
+		return -EIO;
+	return 0;
+}
+
+static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9v022 *mt9v022 = to_mt9v022(client);
+	struct v4l2_rect rect = a->c;
+	int ret;
+
+	/* Bayer format - even size lengths */
+	if (mt9v022->fmts == mt9v022_colour_fmts) {
+		rect.width	= ALIGN(rect.width, 2);
+		rect.height	= ALIGN(rect.height, 2);
+		/* Let the user play with the starting pixel */
+	}
+
+	soc_camera_limit_side(&rect.left, &rect.width,
+		     MT9V022_COLUMN_SKIP, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH);
+
+	soc_camera_limit_side(&rect.top, &rect.height,
+		     MT9V022_ROW_SKIP, MT9V022_MIN_HEIGHT, MT9V022_MAX_HEIGHT);
+
+	/* Like in example app. Contradicts the datasheet though */
+	ret = reg_read(client, MT9V022_AEC_AGC_ENABLE);
+	if (ret >= 0) {
+		if (ret & 1) /* Autoexposure */
+			ret = reg_write(client, mt9v022->reg->max_total_shutter_width,
+					rect.height + mt9v022->y_skip_top + 43);
+		else
+			ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
+					rect.height + mt9v022->y_skip_top + 43);
+	}
+	/* Setup frame format: defaults apart from width and height */
+	if (!ret)
+		ret = reg_write(client, MT9V022_COLUMN_START, rect.left);
+	if (!ret)
+		ret = reg_write(client, MT9V022_ROW_START, rect.top);
+	if (!ret)
+		/*
+		 * Default 94, Phytec driver says:
+		 * "width + horizontal blank >= 660"
+		 */
+		ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING,
+				rect.width > 660 - 43 ? 43 :
+				660 - rect.width);
+	if (!ret)
+		ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45);
+	if (!ret)
+		ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width);
+	if (!ret)
+		ret = reg_write(client, MT9V022_WINDOW_HEIGHT,
+				rect.height + mt9v022->y_skip_top);
+
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(&client->dev, "Frame %dx%d pixel\n", rect.width, rect.height);
+
+	mt9v022->rect = rect;
+
+	return 0;
+}
+
+static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+	a->c	= mt9v022->rect;
+	a->type	= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	a->bounds.left			= MT9V022_COLUMN_SKIP;
+	a->bounds.top			= MT9V022_ROW_SKIP;
+	a->bounds.width			= MT9V022_MAX_WIDTH;
+	a->bounds.height		= MT9V022_MAX_HEIGHT;
+	a->defrect			= a->bounds;
+	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int mt9v022_g_fmt(struct v4l2_subdev *sd,
+			 struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+	mf->width	= mt9v022->rect.width;
+	mf->height	= mt9v022->rect.height;
+	mf->code	= mt9v022->fmt->code;
+	mf->colorspace	= mt9v022->fmt->colorspace;
+	mf->field	= V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static int mt9v022_s_fmt(struct v4l2_subdev *sd,
+			 struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9v022 *mt9v022 = to_mt9v022(client);
+	struct v4l2_crop a = {
+		.c = {
+			.left	= mt9v022->rect.left,
+			.top	= mt9v022->rect.top,
+			.width	= mf->width,
+			.height	= mf->height,
+		},
+	};
+	int ret;
+
+	/*
+	 * The caller provides a supported format, as verified per call to
+	 * .try_mbus_fmt(), datawidth is from our supported format list
+	 */
+	switch (mf->code) {
+	case V4L2_MBUS_FMT_Y8_1X8:
+	case V4L2_MBUS_FMT_Y10_1X10:
+		if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
+			return -EINVAL;
+		break;
+	case V4L2_MBUS_FMT_SBGGR8_1X8:
+	case V4L2_MBUS_FMT_SBGGR10_1X10:
+		if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* No support for scaling on this camera, just crop. */
+	ret = mt9v022_s_crop(sd, &a);
+	if (!ret) {
+		mf->width	= mt9v022->rect.width;
+		mf->height	= mt9v022->rect.height;
+		mt9v022->fmt	= mt9v022_find_datafmt(mf->code,
+					mt9v022->fmts, mt9v022->num_fmts);
+		mf->colorspace	= mt9v022->fmt->colorspace;
+	}
+
+	return ret;
+}
+
+static int mt9v022_try_fmt(struct v4l2_subdev *sd,
+			   struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9v022 *mt9v022 = to_mt9v022(client);
+	const struct mt9v022_datafmt *fmt;
+	int align = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
+		mf->code == V4L2_MBUS_FMT_SBGGR10_1X10;
+
+	v4l_bound_align_image(&mf->width, MT9V022_MIN_WIDTH,
+		MT9V022_MAX_WIDTH, align,
+		&mf->height, MT9V022_MIN_HEIGHT + mt9v022->y_skip_top,
+		MT9V022_MAX_HEIGHT + mt9v022->y_skip_top, align, 0);
+
+	fmt = mt9v022_find_datafmt(mf->code, mt9v022->fmts,
+				   mt9v022->num_fmts);
+	if (!fmt) {
+		fmt = mt9v022->fmt;
+		mf->code = fmt->code;
+	}
+
+	mf->colorspace	= fmt->colorspace;
+
+	return 0;
+}
+
+static int mt9v022_g_chip_ident(struct v4l2_subdev *sd,
+				struct v4l2_dbg_chip_ident *id)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+	if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+
+	if (id->match.addr != client->addr)
+		return -ENODEV;
+
+	id->ident	= mt9v022->model;
+	id->revision	= 0;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9v022_g_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+		return -EINVAL;
+
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	reg->size = 2;
+	reg->val = reg_read(client, reg->reg);
+
+	if (reg->val > 0xffff)
+		return -EIO;
+
+	return 0;
+}
+
+static int mt9v022_s_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+		return -EINVAL;
+
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	if (reg_write(client, reg->reg, reg->val) < 0)
+		return -EIO;
+
+	return 0;
+}
+#endif
+
+static int mt9v022_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	return soc_camera_set_power(&client->dev, icl, on);
+}
+
+static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mt9v022 *mt9v022 = container_of(ctrl->handler,
+					       struct mt9v022, hdl);
+	struct v4l2_subdev *sd = &mt9v022->subdev;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct v4l2_ctrl *gain = mt9v022->gain;
+	struct v4l2_ctrl *exp = mt9v022->exposure;
+	unsigned long range;
+	int data;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTOGAIN:
+		data = reg_read(client, MT9V022_ANALOG_GAIN);
+		if (data < 0)
+			return -EIO;
+
+		range = gain->maximum - gain->minimum;
+		gain->val = ((data - 16) * range + 24) / 48 + gain->minimum;
+		return 0;
+	case V4L2_CID_EXPOSURE_AUTO:
+		data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH);
+		if (data < 0)
+			return -EIO;
+
+		range = exp->maximum - exp->minimum;
+		exp->val = ((data - 1) * range + 239) / 479 + exp->minimum;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mt9v022 *mt9v022 = container_of(ctrl->handler,
+					       struct mt9v022, hdl);
+	struct v4l2_subdev *sd = &mt9v022->subdev;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int data;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		if (ctrl->val)
+			data = reg_set(client, MT9V022_READ_MODE, 0x10);
+		else
+			data = reg_clear(client, MT9V022_READ_MODE, 0x10);
+		if (data < 0)
+			return -EIO;
+		return 0;
+	case V4L2_CID_HFLIP:
+		if (ctrl->val)
+			data = reg_set(client, MT9V022_READ_MODE, 0x20);
+		else
+			data = reg_clear(client, MT9V022_READ_MODE, 0x20);
+		if (data < 0)
+			return -EIO;
+		return 0;
+	case V4L2_CID_AUTOGAIN:
+		if (ctrl->val) {
+			if (reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
+				return -EIO;
+		} else {
+			struct v4l2_ctrl *gain = mt9v022->gain;
+			/* mt9v022 has minimum == default */
+			unsigned long range = gain->maximum - gain->minimum;
+			/* Valid values 16 to 64, 32 to 64 must be even. */
+			unsigned long gain_val = ((gain->val - gain->minimum) *
+					      48 + range / 2) / range + 16;
+
+			if (gain_val >= 32)
+				gain_val &= ~1;
+
+			/*
+			 * The user wants to set gain manually, hope, she
+			 * knows, what she's doing... Switch AGC off.
+			 */
+			if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
+				return -EIO;
+
+			dev_dbg(&client->dev, "Setting gain from %d to %lu\n",
+				reg_read(client, MT9V022_ANALOG_GAIN), gain_val);
+			if (reg_write(client, MT9V022_ANALOG_GAIN, gain_val) < 0)
+				return -EIO;
+		}
+		return 0;
+	case V4L2_CID_EXPOSURE_AUTO:
+		if (ctrl->val == V4L2_EXPOSURE_AUTO) {
+			data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1);
+		} else {
+			struct v4l2_ctrl *exp = mt9v022->exposure;
+			unsigned long range = exp->maximum - exp->minimum;
+			unsigned long shutter = ((exp->val - exp->minimum) *
+					479 + range / 2) / range + 1;
+
+			/*
+			 * The user wants to set shutter width manually, hope,
+			 * she knows, what she's doing... Switch AEC off.
+			 */
+			data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1);
+			if (data < 0)
+				return -EIO;
+			dev_dbg(&client->dev, "Shutter width from %d to %lu\n",
+					reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH),
+					shutter);
+			if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
+						shutter) < 0)
+				return -EIO;
+		}
+		return 0;
+	}
+	return -EINVAL;
+}
+
+/*
+ * Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one
+ */
+static int mt9v022_video_probe(struct i2c_client *client)
+{
+	struct mt9v022 *mt9v022 = to_mt9v022(client);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	s32 data;
+	int ret;
+	unsigned long flags;
+
+	ret = mt9v022_s_power(&mt9v022->subdev, 1);
+	if (ret < 0)
+		return ret;
+
+	/* Read out the chip version register */
+	data = reg_read(client, MT9V022_CHIP_VERSION);
+
+	/* must be 0x1311, 0x1313 or 0x1324 */
+	if (data != 0x1311 && data != 0x1313 && data != 0x1324) {
+		ret = -ENODEV;
+		dev_info(&client->dev, "No MT9V022 found, ID register 0x%x\n",
+			 data);
+		goto ei2c;
+	}
+
+	mt9v022->reg = is_mt9v024(data) ? &mt9v024_register :
+			&mt9v022_register;
+
+	/* Soft reset */
+	ret = reg_write(client, MT9V022_RESET, 1);
+	if (ret < 0)
+		goto ei2c;
+	/* 15 clock cycles */
+	udelay(200);
+	if (reg_read(client, MT9V022_RESET)) {
+		dev_err(&client->dev, "Resetting MT9V022 failed!\n");
+		if (ret > 0)
+			ret = -EIO;
+		goto ei2c;
+	}
+
+	/* Set monochrome or colour sensor type */
+	if (sensor_type && (!strcmp("colour", sensor_type) ||
+			    !strcmp("color", sensor_type))) {
+		ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
+		mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
+		mt9v022->fmts = mt9v022_colour_fmts;
+	} else {
+		ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11);
+		mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
+		mt9v022->fmts = mt9v022_monochrome_fmts;
+	}
+
+	if (ret < 0)
+		goto ei2c;
+
+	mt9v022->num_fmts = 0;
+
+	/*
+	 * This is a 10bit sensor, so by default we only allow 10bit.
+	 * The platform may support different bus widths due to
+	 * different routing of the data lines.
+	 */
+	if (icl->query_bus_param)
+		flags = icl->query_bus_param(icl);
+	else
+		flags = SOCAM_DATAWIDTH_10;
+
+	if (flags & SOCAM_DATAWIDTH_10)
+		mt9v022->num_fmts++;
+	else
+		mt9v022->fmts++;
+
+	if (flags & SOCAM_DATAWIDTH_8)
+		mt9v022->num_fmts++;
+
+	mt9v022->fmt = &mt9v022->fmts[0];
+
+	dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
+		 data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ?
+		 "monochrome" : "colour");
+
+	ret = mt9v022_init(client);
+	if (ret < 0)
+		dev_err(&client->dev, "Failed to initialise the camera\n");
+
+ei2c:
+	mt9v022_s_power(&mt9v022->subdev, 0);
+	return ret;
+}
+
+static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+	*lines = mt9v022->y_skip_top;
+
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = {
+	.g_volatile_ctrl = mt9v022_g_volatile_ctrl,
+	.s_ctrl = mt9v022_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
+	.g_chip_ident	= mt9v022_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register	= mt9v022_g_register,
+	.s_register	= mt9v022_s_register,
+#endif
+	.s_power	= mt9v022_s_power,
+};
+
+static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			    enum v4l2_mbus_pixelcode *code)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+	if (index >= mt9v022->num_fmts)
+		return -EINVAL;
+
+	*code = mt9v022->fmts[index].code;
+	return 0;
+}
+
+static int mt9v022_g_mbus_config(struct v4l2_subdev *sd,
+				struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE |
+		V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
+		V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
+		V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
+		V4L2_MBUS_DATA_ACTIVE_HIGH;
+	cfg->type = V4L2_MBUS_PARALLEL;
+	cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+	return 0;
+}
+
+static int mt9v022_s_mbus_config(struct v4l2_subdev *sd,
+				 const struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	struct mt9v022 *mt9v022 = to_mt9v022(client);
+	unsigned long flags = soc_camera_apply_board_flags(icl, cfg);
+	unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample;
+	int ret;
+	u16 pixclk = 0;
+
+	if (icl->set_bus_param) {
+		ret = icl->set_bus_param(icl, 1 << (bps - 1));
+		if (ret)
+			return ret;
+	} else if (bps != 10) {
+		/*
+		 * Without board specific bus width settings we only support the
+		 * sensors native bus width
+		 */
+		return -EINVAL;
+	}
+
+	if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+		pixclk |= 0x10;
+
+	if (!(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH))
+		pixclk |= 0x1;
+
+	if (!(flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH))
+		pixclk |= 0x2;
+
+	ret = reg_write(client, mt9v022->reg->pixclk_fv_lv, pixclk);
+	if (ret < 0)
+		return ret;
+
+	if (!(flags & V4L2_MBUS_MASTER))
+		mt9v022->chip_control &= ~0x8;
+
+	ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
+		pixclk, mt9v022->chip_control);
+
+	return 0;
+}
+
+static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
+	.s_stream	= mt9v022_s_stream,
+	.s_mbus_fmt	= mt9v022_s_fmt,
+	.g_mbus_fmt	= mt9v022_g_fmt,
+	.try_mbus_fmt	= mt9v022_try_fmt,
+	.s_crop		= mt9v022_s_crop,
+	.g_crop		= mt9v022_g_crop,
+	.cropcap	= mt9v022_cropcap,
+	.enum_mbus_fmt	= mt9v022_enum_fmt,
+	.g_mbus_config	= mt9v022_g_mbus_config,
+	.s_mbus_config	= mt9v022_s_mbus_config,
+};
+
+static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = {
+	.g_skip_top_lines	= mt9v022_g_skip_top_lines,
+};
+
+static struct v4l2_subdev_ops mt9v022_subdev_ops = {
+	.core	= &mt9v022_subdev_core_ops,
+	.video	= &mt9v022_subdev_video_ops,
+	.sensor	= &mt9v022_subdev_sensor_ops,
+};
+
+static int mt9v022_probe(struct i2c_client *client,
+			 const struct i2c_device_id *did)
+{
+	struct mt9v022 *mt9v022;
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	int ret;
+
+	if (!icl) {
+		dev_err(&client->dev, "MT9V022 driver needs platform data\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_warn(&adapter->dev,
+			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+		return -EIO;
+	}
+
+	mt9v022 = kzalloc(sizeof(struct mt9v022), GFP_KERNEL);
+	if (!mt9v022)
+		return -ENOMEM;
+
+	v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops);
+	v4l2_ctrl_handler_init(&mt9v022->hdl, 6);
+	v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
+			V4L2_CID_HFLIP, 0, 1, 1, 0);
+	mt9v022->autogain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
+			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+	mt9v022->gain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
+			V4L2_CID_GAIN, 0, 127, 1, 64);
+
+	/*
+	 * Simulated autoexposure. If enabled, we calculate shutter width
+	 * ourselves in the driver based on vertical blanking and frame width
+	 */
+	mt9v022->autoexposure = v4l2_ctrl_new_std_menu(&mt9v022->hdl,
+			&mt9v022_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
+			V4L2_EXPOSURE_AUTO);
+	mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
+			V4L2_CID_EXPOSURE, 1, 255, 1, 255);
+
+	mt9v022->subdev.ctrl_handler = &mt9v022->hdl;
+	if (mt9v022->hdl.error) {
+		int err = mt9v022->hdl.error;
+
+		kfree(mt9v022);
+		return err;
+	}
+	v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure,
+				V4L2_EXPOSURE_MANUAL, true);
+	v4l2_ctrl_auto_cluster(2, &mt9v022->autogain, 0, true);
+
+	mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
+
+	/*
+	 * MT9V022 _really_ corrupts the first read out line.
+	 * TODO: verify on i.MX31
+	 */
+	mt9v022->y_skip_top	= 1;
+	mt9v022->rect.left	= MT9V022_COLUMN_SKIP;
+	mt9v022->rect.top	= MT9V022_ROW_SKIP;
+	mt9v022->rect.width	= MT9V022_MAX_WIDTH;
+	mt9v022->rect.height	= MT9V022_MAX_HEIGHT;
+
+	ret = mt9v022_video_probe(client);
+	if (ret) {
+		v4l2_ctrl_handler_free(&mt9v022->hdl);
+		kfree(mt9v022);
+	}
+
+	return ret;
+}
+
+static int mt9v022_remove(struct i2c_client *client)
+{
+	struct mt9v022 *mt9v022 = to_mt9v022(client);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	v4l2_device_unregister_subdev(&mt9v022->subdev);
+	if (icl->free_bus)
+		icl->free_bus(icl);
+	v4l2_ctrl_handler_free(&mt9v022->hdl);
+	kfree(mt9v022);
+
+	return 0;
+}
+static const struct i2c_device_id mt9v022_id[] = {
+	{ "mt9v022", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mt9v022_id);
+
+static struct i2c_driver mt9v022_i2c_driver = {
+	.driver = {
+		.name = "mt9v022",
+	},
+	.probe		= mt9v022_probe,
+	.remove		= mt9v022_remove,
+	.id_table	= mt9v022_id,
+};
+
+module_i2c_driver(mt9v022_i2c_driver);
+
+MODULE_DESCRIPTION("Micron MT9V022 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c
new file mode 100644
index 0000000..78ac574
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov2640.c
@@ -0,0 +1,1122 @@
+/*
+ * ov2640 Camera Driver
+ *
+ * Copyright (C) 2010 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ *
+ * Based on ov772x, ov9640 drivers and previous non merged implementations.
+ *
+ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2006, OmniVision
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ctrls.h>
+
+#define VAL_SET(x, mask, rshift, lshift)  \
+		((((x) >> rshift) & mask) << lshift)
+/*
+ * DSP registers
+ * register offset for BANK_SEL == BANK_SEL_DSP
+ */
+#define R_BYPASS    0x05 /* Bypass DSP */
+#define   R_BYPASS_DSP_BYPAS    0x01 /* Bypass DSP, sensor out directly */
+#define   R_BYPASS_USE_DSP      0x00 /* Use the internal DSP */
+#define QS          0x44 /* Quantization Scale Factor */
+#define CTRLI       0x50
+#define   CTRLI_LP_DP           0x80
+#define   CTRLI_ROUND           0x40
+#define   CTRLI_V_DIV_SET(x)    VAL_SET(x, 0x3, 0, 3)
+#define   CTRLI_H_DIV_SET(x)    VAL_SET(x, 0x3, 0, 0)
+#define HSIZE       0x51 /* H_SIZE[7:0] (real/4) */
+#define   HSIZE_SET(x)          VAL_SET(x, 0xFF, 2, 0)
+#define VSIZE       0x52 /* V_SIZE[7:0] (real/4) */
+#define   VSIZE_SET(x)          VAL_SET(x, 0xFF, 2, 0)
+#define XOFFL       0x53 /* OFFSET_X[7:0] */
+#define   XOFFL_SET(x)          VAL_SET(x, 0xFF, 0, 0)
+#define YOFFL       0x54 /* OFFSET_Y[7:0] */
+#define   YOFFL_SET(x)          VAL_SET(x, 0xFF, 0, 0)
+#define VHYX        0x55 /* Offset and size completion */
+#define   VHYX_VSIZE_SET(x)     VAL_SET(x, 0x1, (8+2), 7)
+#define   VHYX_HSIZE_SET(x)     VAL_SET(x, 0x1, (8+2), 3)
+#define   VHYX_YOFF_SET(x)      VAL_SET(x, 0x3, 8, 4)
+#define   VHYX_XOFF_SET(x)      VAL_SET(x, 0x3, 8, 0)
+#define DPRP        0x56
+#define TEST        0x57 /* Horizontal size completion */
+#define   TEST_HSIZE_SET(x)     VAL_SET(x, 0x1, (9+2), 7)
+#define ZMOW        0x5A /* Zoom: Out Width  OUTW[7:0] (real/4) */
+#define   ZMOW_OUTW_SET(x)      VAL_SET(x, 0xFF, 2, 0)
+#define ZMOH        0x5B /* Zoom: Out Height OUTH[7:0] (real/4) */
+#define   ZMOH_OUTH_SET(x)      VAL_SET(x, 0xFF, 2, 0)
+#define ZMHH        0x5C /* Zoom: Speed and H&W completion */
+#define   ZMHH_ZSPEED_SET(x)    VAL_SET(x, 0x0F, 0, 4)
+#define   ZMHH_OUTH_SET(x)      VAL_SET(x, 0x1, (8+2), 2)
+#define   ZMHH_OUTW_SET(x)      VAL_SET(x, 0x3, (8+2), 0)
+#define BPADDR      0x7C /* SDE Indirect Register Access: Address */
+#define BPDATA      0x7D /* SDE Indirect Register Access: Data */
+#define CTRL2       0x86 /* DSP Module enable 2 */
+#define   CTRL2_DCW_EN          0x20
+#define   CTRL2_SDE_EN          0x10
+#define   CTRL2_UV_ADJ_EN       0x08
+#define   CTRL2_UV_AVG_EN       0x04
+#define   CTRL2_CMX_EN          0x01
+#define CTRL3       0x87 /* DSP Module enable 3 */
+#define   CTRL3_BPC_EN          0x80
+#define   CTRL3_WPC_EN          0x40
+#define SIZEL       0x8C /* Image Size Completion */
+#define   SIZEL_HSIZE8_11_SET(x) VAL_SET(x, 0x1, 11, 6)
+#define   SIZEL_HSIZE8_SET(x)    VAL_SET(x, 0x7, 0, 3)
+#define   SIZEL_VSIZE8_SET(x)    VAL_SET(x, 0x7, 0, 0)
+#define HSIZE8      0xC0 /* Image Horizontal Size HSIZE[10:3] */
+#define   HSIZE8_SET(x)         VAL_SET(x, 0xFF, 3, 0)
+#define VSIZE8      0xC1 /* Image Vertical Size VSIZE[10:3] */
+#define   VSIZE8_SET(x)         VAL_SET(x, 0xFF, 3, 0)
+#define CTRL0       0xC2 /* DSP Module enable 0 */
+#define   CTRL0_AEC_EN       0x80
+#define   CTRL0_AEC_SEL      0x40
+#define   CTRL0_STAT_SEL     0x20
+#define   CTRL0_VFIRST       0x10
+#define   CTRL0_YUV422       0x08
+#define   CTRL0_YUV_EN       0x04
+#define   CTRL0_RGB_EN       0x02
+#define   CTRL0_RAW_EN       0x01
+#define CTRL1       0xC3 /* DSP Module enable 1 */
+#define   CTRL1_CIP          0x80
+#define   CTRL1_DMY          0x40
+#define   CTRL1_RAW_GMA      0x20
+#define   CTRL1_DG           0x10
+#define   CTRL1_AWB          0x08
+#define   CTRL1_AWB_GAIN     0x04
+#define   CTRL1_LENC         0x02
+#define   CTRL1_PRE          0x01
+#define R_DVP_SP    0xD3 /* DVP output speed control */
+#define   R_DVP_SP_AUTO_MODE 0x80
+#define   R_DVP_SP_DVP_MASK  0x3F /* DVP PCLK = sysclk (48)/[6:0] (YUV0);
+				   *          = sysclk (48)/(2*[6:0]) (RAW);*/
+#define IMAGE_MODE  0xDA /* Image Output Format Select */
+#define   IMAGE_MODE_Y8_DVP_EN   0x40
+#define   IMAGE_MODE_JPEG_EN     0x10
+#define   IMAGE_MODE_YUV422      0x00
+#define   IMAGE_MODE_RAW10       0x04 /* (DVP) */
+#define   IMAGE_MODE_RGB565      0x08
+#define   IMAGE_MODE_HREF_VSYNC  0x02 /* HREF timing select in DVP JPEG output
+				       * mode (0 for HREF is same as sensor) */
+#define   IMAGE_MODE_LBYTE_FIRST 0x01 /* Byte swap enable for DVP
+				       *    1: Low byte first UYVY (C2[4] =0)
+				       *        VYUY (C2[4] =1)
+				       *    0: High byte first YUYV (C2[4]=0)
+				       *        YVYU (C2[4] = 1) */
+#define RESET       0xE0 /* Reset */
+#define   RESET_MICROC       0x40
+#define   RESET_SCCB         0x20
+#define   RESET_JPEG         0x10
+#define   RESET_DVP          0x04
+#define   RESET_IPU          0x02
+#define   RESET_CIF          0x01
+#define REGED       0xED /* Register ED */
+#define   REGED_CLK_OUT_DIS  0x10
+#define MS_SP       0xF0 /* SCCB Master Speed */
+#define SS_ID       0xF7 /* SCCB Slave ID */
+#define SS_CTRL     0xF8 /* SCCB Slave Control */
+#define   SS_CTRL_ADD_AUTO_INC  0x20
+#define   SS_CTRL_EN            0x08
+#define   SS_CTRL_DELAY_CLK     0x04
+#define   SS_CTRL_ACC_EN        0x02
+#define   SS_CTRL_SEN_PASS_THR  0x01
+#define MC_BIST     0xF9 /* Microcontroller misc register */
+#define   MC_BIST_RESET           0x80 /* Microcontroller Reset */
+#define   MC_BIST_BOOT_ROM_SEL    0x40
+#define   MC_BIST_12KB_SEL        0x20
+#define   MC_BIST_12KB_MASK       0x30
+#define   MC_BIST_512KB_SEL       0x08
+#define   MC_BIST_512KB_MASK      0x0C
+#define   MC_BIST_BUSY_BIT_R      0x02
+#define   MC_BIST_MC_RES_ONE_SH_W 0x02
+#define   MC_BIST_LAUNCH          0x01
+#define BANK_SEL    0xFF /* Register Bank Select */
+#define   BANK_SEL_DSP     0x00
+#define   BANK_SEL_SENS    0x01
+
+/*
+ * Sensor registers
+ * register offset for BANK_SEL == BANK_SEL_SENS
+ */
+#define GAIN        0x00 /* AGC - Gain control gain setting */
+#define COM1        0x03 /* Common control 1 */
+#define   COM1_1_DUMMY_FR          0x40
+#define   COM1_3_DUMMY_FR          0x80
+#define   COM1_7_DUMMY_FR          0xC0
+#define   COM1_VWIN_LSB_UXGA       0x0F
+#define   COM1_VWIN_LSB_SVGA       0x0A
+#define   COM1_VWIN_LSB_CIF        0x06
+#define REG04       0x04 /* Register 04 */
+#define   REG04_DEF             0x20 /* Always set */
+#define   REG04_HFLIP_IMG       0x80 /* Horizontal mirror image ON/OFF */
+#define   REG04_VFLIP_IMG       0x40 /* Vertical flip image ON/OFF */
+#define   REG04_VREF_EN         0x10
+#define   REG04_HREF_EN         0x08
+#define   REG04_AEC_SET(x)      VAL_SET(x, 0x3, 0, 0)
+#define REG08       0x08 /* Frame Exposure One-pin Control Pre-charge Row Num */
+#define COM2        0x09 /* Common control 2 */
+#define   COM2_SOFT_SLEEP_MODE  0x10 /* Soft sleep mode */
+				     /* Output drive capability */
+#define   COM2_OCAP_Nx_SET(N)   (((N) - 1) & 0x03) /* N = [1x .. 4x] */
+#define PID         0x0A /* Product ID Number MSB */
+#define VER         0x0B /* Product ID Number LSB */
+#define COM3        0x0C /* Common control 3 */
+#define   COM3_BAND_50H        0x04 /* 0 For Banding at 60H */
+#define   COM3_BAND_AUTO       0x02 /* Auto Banding */
+#define   COM3_SING_FR_SNAPSH  0x01 /* 0 For enable live video output after the
+				     * snapshot sequence*/
+#define AEC         0x10 /* AEC[9:2] Exposure Value */
+#define CLKRC       0x11 /* Internal clock */
+#define   CLKRC_EN             0x80
+#define   CLKRC_DIV_SET(x)     (((x) - 1) & 0x1F) /* CLK = XVCLK/(x) */
+#define COM7        0x12 /* Common control 7 */
+#define   COM7_SRST            0x80 /* Initiates system reset. All registers are
+				     * set to factory default values after which
+				     * the chip resumes normal operation */
+#define   COM7_RES_UXGA        0x00 /* Resolution selectors for UXGA */
+#define   COM7_RES_SVGA        0x40 /* SVGA */
+#define   COM7_RES_CIF         0x20 /* CIF */
+#define   COM7_ZOOM_EN         0x04 /* Enable Zoom mode */
+#define   COM7_COLOR_BAR_TEST  0x02 /* Enable Color Bar Test Pattern */
+#define COM8        0x13 /* Common control 8 */
+#define   COM8_DEF             0xC0 /* Banding filter ON/OFF */
+#define   COM8_BNDF_EN         0x20 /* Banding filter ON/OFF */
+#define   COM8_AGC_EN          0x04 /* AGC Auto/Manual control selection */
+#define   COM8_AEC_EN          0x01 /* Auto/Manual Exposure control */
+#define COM9        0x14 /* Common control 9
+			  * Automatic gain ceiling - maximum AGC value [7:5]*/
+#define   COM9_AGC_GAIN_2x     0x00 /* 000 :   2x */
+#define   COM9_AGC_GAIN_4x     0x20 /* 001 :   4x */
+#define   COM9_AGC_GAIN_8x     0x40 /* 010 :   8x */
+#define   COM9_AGC_GAIN_16x    0x60 /* 011 :  16x */
+#define   COM9_AGC_GAIN_32x    0x80 /* 100 :  32x */
+#define   COM9_AGC_GAIN_64x    0xA0 /* 101 :  64x */
+#define   COM9_AGC_GAIN_128x   0xC0 /* 110 : 128x */
+#define COM10       0x15 /* Common control 10 */
+#define   COM10_PCLK_HREF      0x20 /* PCLK output qualified by HREF */
+#define   COM10_PCLK_RISE      0x10 /* Data is updated at the rising edge of
+				     * PCLK (user can latch data at the next
+				     * falling edge of PCLK).
+				     * 0 otherwise. */
+#define   COM10_HREF_INV       0x08 /* Invert HREF polarity:
+				     * HREF negative for valid data*/
+#define   COM10_VSINC_INV      0x02 /* Invert VSYNC polarity */
+#define HSTART      0x17 /* Horizontal Window start MSB 8 bit */
+#define HEND        0x18 /* Horizontal Window end MSB 8 bit */
+#define VSTART      0x19 /* Vertical Window start MSB 8 bit */
+#define VEND        0x1A /* Vertical Window end MSB 8 bit */
+#define MIDH        0x1C /* Manufacturer ID byte - high */
+#define MIDL        0x1D /* Manufacturer ID byte - low  */
+#define AEW         0x24 /* AGC/AEC - Stable operating region (upper limit) */
+#define AEB         0x25 /* AGC/AEC - Stable operating region (lower limit) */
+#define VV          0x26 /* AGC/AEC Fast mode operating region */
+#define   VV_HIGH_TH_SET(x)      VAL_SET(x, 0xF, 0, 4)
+#define   VV_LOW_TH_SET(x)       VAL_SET(x, 0xF, 0, 0)
+#define REG2A       0x2A /* Dummy pixel insert MSB */
+#define FRARL       0x2B /* Dummy pixel insert LSB */
+#define ADDVFL      0x2D /* LSB of insert dummy lines in Vertical direction */
+#define ADDVFH      0x2E /* MSB of insert dummy lines in Vertical direction */
+#define YAVG        0x2F /* Y/G Channel Average value */
+#define REG32       0x32 /* Common Control 32 */
+#define   REG32_PCLK_DIV_2    0x80 /* PCLK freq divided by 2 */
+#define   REG32_PCLK_DIV_4    0xC0 /* PCLK freq divided by 4 */
+#define ARCOM2      0x34 /* Zoom: Horizontal start point */
+#define REG45       0x45 /* Register 45 */
+#define FLL         0x46 /* Frame Length Adjustment LSBs */
+#define FLH         0x47 /* Frame Length Adjustment MSBs */
+#define COM19       0x48 /* Zoom: Vertical start point */
+#define ZOOMS       0x49 /* Zoom: Vertical start point */
+#define COM22       0x4B /* Flash light control */
+#define COM25       0x4E /* For Banding operations */
+#define BD50        0x4F /* 50Hz Banding AEC 8 LSBs */
+#define BD60        0x50 /* 60Hz Banding AEC 8 LSBs */
+#define REG5D       0x5D /* AVGsel[7:0],   16-zone average weight option */
+#define REG5E       0x5E /* AVGsel[15:8],  16-zone average weight option */
+#define REG5F       0x5F /* AVGsel[23:16], 16-zone average weight option */
+#define REG60       0x60 /* AVGsel[31:24], 16-zone average weight option */
+#define HISTO_LOW   0x61 /* Histogram Algorithm Low Level */
+#define HISTO_HIGH  0x62 /* Histogram Algorithm High Level */
+
+/*
+ * ID
+ */
+#define MANUFACTURER_ID	0x7FA2
+#define PID_OV2640	0x2642
+#define VERSION(pid, ver) ((pid << 8) | (ver & 0xFF))
+
+/*
+ * Struct
+ */
+struct regval_list {
+	u8 reg_num;
+	u8 value;
+};
+
+/* Supported resolutions */
+enum ov2640_width {
+	W_QCIF	= 176,
+	W_QVGA	= 320,
+	W_CIF	= 352,
+	W_VGA	= 640,
+	W_SVGA	= 800,
+	W_XGA	= 1024,
+	W_SXGA	= 1280,
+	W_UXGA	= 1600,
+};
+
+enum ov2640_height {
+	H_QCIF	= 144,
+	H_QVGA	= 240,
+	H_CIF	= 288,
+	H_VGA	= 480,
+	H_SVGA	= 600,
+	H_XGA	= 768,
+	H_SXGA	= 1024,
+	H_UXGA	= 1200,
+};
+
+struct ov2640_win_size {
+	char				*name;
+	enum ov2640_width		width;
+	enum ov2640_height		height;
+	const struct regval_list	*regs;
+};
+
+
+struct ov2640_priv {
+	struct v4l2_subdev		subdev;
+	struct v4l2_ctrl_handler	hdl;
+	enum v4l2_mbus_pixelcode	cfmt_code;
+	const struct ov2640_win_size	*win;
+	int				model;
+};
+
+/*
+ * Registers settings
+ */
+
+#define ENDMARKER { 0xff, 0xff }
+
+static const struct regval_list ov2640_init_regs[] = {
+	{ BANK_SEL, BANK_SEL_DSP },
+	{ 0x2c,   0xff },
+	{ 0x2e,   0xdf },
+	{ BANK_SEL, BANK_SEL_SENS },
+	{ 0x3c,   0x32 },
+	{ CLKRC, CLKRC_DIV_SET(1) },
+	{ COM2, COM2_OCAP_Nx_SET(3) },
+	{ REG04, REG04_DEF | REG04_HREF_EN },
+	{ COM8,  COM8_DEF | COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN },
+	{ COM9, COM9_AGC_GAIN_8x | 0x08},
+	{ 0x2c,   0x0c },
+	{ 0x33,   0x78 },
+	{ 0x3a,   0x33 },
+	{ 0x3b,   0xfb },
+	{ 0x3e,   0x00 },
+	{ 0x43,   0x11 },
+	{ 0x16,   0x10 },
+	{ 0x39,   0x02 },
+	{ 0x35,   0x88 },
+	{ 0x22,   0x0a },
+	{ 0x37,   0x40 },
+	{ 0x23,   0x00 },
+	{ ARCOM2, 0xa0 },
+	{ 0x06,   0x02 },
+	{ 0x06,   0x88 },
+	{ 0x07,   0xc0 },
+	{ 0x0d,   0xb7 },
+	{ 0x0e,   0x01 },
+	{ 0x4c,   0x00 },
+	{ 0x4a,   0x81 },
+	{ 0x21,   0x99 },
+	{ AEW,    0x40 },
+	{ AEB,    0x38 },
+	{ VV,     VV_HIGH_TH_SET(0x08) | VV_LOW_TH_SET(0x02) },
+	{ 0x5c,   0x00 },
+	{ 0x63,   0x00 },
+	{ FLL,    0x22 },
+	{ COM3,   0x38 | COM3_BAND_AUTO },
+	{ REG5D,  0x55 },
+	{ REG5E,  0x7d },
+	{ REG5F,  0x7d },
+	{ REG60,  0x55 },
+	{ HISTO_LOW,   0x70 },
+	{ HISTO_HIGH,  0x80 },
+	{ 0x7c,   0x05 },
+	{ 0x20,   0x80 },
+	{ 0x28,   0x30 },
+	{ 0x6c,   0x00 },
+	{ 0x6d,   0x80 },
+	{ 0x6e,   0x00 },
+	{ 0x70,   0x02 },
+	{ 0x71,   0x94 },
+	{ 0x73,   0xc1 },
+	{ 0x3d,   0x34 },
+	{ COM7, COM7_RES_UXGA | COM7_ZOOM_EN },
+	{ 0x5a,   0x57 },
+	{ BD50,   0xbb },
+	{ BD60,   0x9c },
+	{ BANK_SEL, BANK_SEL_DSP },
+	{ 0xe5,   0x7f },
+	{ MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL },
+	{ 0x41,   0x24 },
+	{ RESET, RESET_JPEG | RESET_DVP },
+	{ 0x76,   0xff },
+	{ 0x33,   0xa0 },
+	{ 0x42,   0x20 },
+	{ 0x43,   0x18 },
+	{ 0x4c,   0x00 },
+	{ CTRL3, CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10 },
+	{ 0x88,   0x3f },
+	{ 0xd7,   0x03 },
+	{ 0xd9,   0x10 },
+	{ R_DVP_SP , R_DVP_SP_AUTO_MODE | 0x2 },
+	{ 0xc8,   0x08 },
+	{ 0xc9,   0x80 },
+	{ BPADDR, 0x00 },
+	{ BPDATA, 0x00 },
+	{ BPADDR, 0x03 },
+	{ BPDATA, 0x48 },
+	{ BPDATA, 0x48 },
+	{ BPADDR, 0x08 },
+	{ BPDATA, 0x20 },
+	{ BPDATA, 0x10 },
+	{ BPDATA, 0x0e },
+	{ 0x90,   0x00 },
+	{ 0x91,   0x0e },
+	{ 0x91,   0x1a },
+	{ 0x91,   0x31 },
+	{ 0x91,   0x5a },
+	{ 0x91,   0x69 },
+	{ 0x91,   0x75 },
+	{ 0x91,   0x7e },
+	{ 0x91,   0x88 },
+	{ 0x91,   0x8f },
+	{ 0x91,   0x96 },
+	{ 0x91,   0xa3 },
+	{ 0x91,   0xaf },
+	{ 0x91,   0xc4 },
+	{ 0x91,   0xd7 },
+	{ 0x91,   0xe8 },
+	{ 0x91,   0x20 },
+	{ 0x92,   0x00 },
+	{ 0x93,   0x06 },
+	{ 0x93,   0xe3 },
+	{ 0x93,   0x03 },
+	{ 0x93,   0x03 },
+	{ 0x93,   0x00 },
+	{ 0x93,   0x02 },
+	{ 0x93,   0x00 },
+	{ 0x93,   0x00 },
+	{ 0x93,   0x00 },
+	{ 0x93,   0x00 },
+	{ 0x93,   0x00 },
+	{ 0x93,   0x00 },
+	{ 0x93,   0x00 },
+	{ 0x96,   0x00 },
+	{ 0x97,   0x08 },
+	{ 0x97,   0x19 },
+	{ 0x97,   0x02 },
+	{ 0x97,   0x0c },
+	{ 0x97,   0x24 },
+	{ 0x97,   0x30 },
+	{ 0x97,   0x28 },
+	{ 0x97,   0x26 },
+	{ 0x97,   0x02 },
+	{ 0x97,   0x98 },
+	{ 0x97,   0x80 },
+	{ 0x97,   0x00 },
+	{ 0x97,   0x00 },
+	{ 0xa4,   0x00 },
+	{ 0xa8,   0x00 },
+	{ 0xc5,   0x11 },
+	{ 0xc6,   0x51 },
+	{ 0xbf,   0x80 },
+	{ 0xc7,   0x10 },
+	{ 0xb6,   0x66 },
+	{ 0xb8,   0xA5 },
+	{ 0xb7,   0x64 },
+	{ 0xb9,   0x7C },
+	{ 0xb3,   0xaf },
+	{ 0xb4,   0x97 },
+	{ 0xb5,   0xFF },
+	{ 0xb0,   0xC5 },
+	{ 0xb1,   0x94 },
+	{ 0xb2,   0x0f },
+	{ 0xc4,   0x5c },
+	{ 0xa6,   0x00 },
+	{ 0xa7,   0x20 },
+	{ 0xa7,   0xd8 },
+	{ 0xa7,   0x1b },
+	{ 0xa7,   0x31 },
+	{ 0xa7,   0x00 },
+	{ 0xa7,   0x18 },
+	{ 0xa7,   0x20 },
+	{ 0xa7,   0xd8 },
+	{ 0xa7,   0x19 },
+	{ 0xa7,   0x31 },
+	{ 0xa7,   0x00 },
+	{ 0xa7,   0x18 },
+	{ 0xa7,   0x20 },
+	{ 0xa7,   0xd8 },
+	{ 0xa7,   0x19 },
+	{ 0xa7,   0x31 },
+	{ 0xa7,   0x00 },
+	{ 0xa7,   0x18 },
+	{ 0x7f,   0x00 },
+	{ 0xe5,   0x1f },
+	{ 0xe1,   0x77 },
+	{ 0xdd,   0x7f },
+	{ CTRL0,  CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN },
+	ENDMARKER,
+};
+
+/*
+ * Register settings for window size
+ * The preamble, setup the internal DSP to input an UXGA (1600x1200) image.
+ * Then the different zooming configurations will setup the output image size.
+ */
+static const struct regval_list ov2640_size_change_preamble_regs[] = {
+	{ BANK_SEL, BANK_SEL_DSP },
+	{ RESET, RESET_DVP },
+	{ HSIZE8, HSIZE8_SET(W_UXGA) },
+	{ VSIZE8, VSIZE8_SET(H_UXGA) },
+	{ CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN |
+		 CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN },
+	{ HSIZE, HSIZE_SET(W_UXGA) },
+	{ VSIZE, VSIZE_SET(H_UXGA) },
+	{ XOFFL, XOFFL_SET(0) },
+	{ YOFFL, YOFFL_SET(0) },
+	{ VHYX, VHYX_HSIZE_SET(W_UXGA) | VHYX_VSIZE_SET(H_UXGA) |
+		VHYX_XOFF_SET(0) | VHYX_YOFF_SET(0)},
+	{ TEST, TEST_HSIZE_SET(W_UXGA) },
+	ENDMARKER,
+};
+
+#define PER_SIZE_REG_SEQ(x, y, v_div, h_div, pclk_div)	\
+	{ CTRLI, CTRLI_LP_DP | CTRLI_V_DIV_SET(v_div) |	\
+		 CTRLI_H_DIV_SET(h_div)},		\
+	{ ZMOW, ZMOW_OUTW_SET(x) },			\
+	{ ZMOH, ZMOH_OUTH_SET(y) },			\
+	{ ZMHH, ZMHH_OUTW_SET(x) | ZMHH_OUTH_SET(y) },	\
+	{ R_DVP_SP, pclk_div },				\
+	{ RESET, 0x00}
+
+static const struct regval_list ov2640_qcif_regs[] = {
+	PER_SIZE_REG_SEQ(W_QCIF, H_QCIF, 3, 3, 4),
+	ENDMARKER,
+};
+
+static const struct regval_list ov2640_qvga_regs[] = {
+	PER_SIZE_REG_SEQ(W_QVGA, H_QVGA, 2, 2, 4),
+	ENDMARKER,
+};
+
+static const struct regval_list ov2640_cif_regs[] = {
+	PER_SIZE_REG_SEQ(W_CIF, H_CIF, 2, 2, 8),
+	ENDMARKER,
+};
+
+static const struct regval_list ov2640_vga_regs[] = {
+	PER_SIZE_REG_SEQ(W_VGA, H_VGA, 0, 0, 2),
+	ENDMARKER,
+};
+
+static const struct regval_list ov2640_svga_regs[] = {
+	PER_SIZE_REG_SEQ(W_SVGA, H_SVGA, 1, 1, 2),
+	ENDMARKER,
+};
+
+static const struct regval_list ov2640_xga_regs[] = {
+	PER_SIZE_REG_SEQ(W_XGA, H_XGA, 0, 0, 2),
+	{ CTRLI,    0x00},
+	ENDMARKER,
+};
+
+static const struct regval_list ov2640_sxga_regs[] = {
+	PER_SIZE_REG_SEQ(W_SXGA, H_SXGA, 0, 0, 2),
+	{ CTRLI,    0x00},
+	{ R_DVP_SP, 2 | R_DVP_SP_AUTO_MODE },
+	ENDMARKER,
+};
+
+static const struct regval_list ov2640_uxga_regs[] = {
+	PER_SIZE_REG_SEQ(W_UXGA, H_UXGA, 0, 0, 0),
+	{ CTRLI,    0x00},
+	{ R_DVP_SP, 0 | R_DVP_SP_AUTO_MODE },
+	ENDMARKER,
+};
+
+#define OV2640_SIZE(n, w, h, r) \
+	{.name = n, .width = w , .height = h, .regs = r }
+
+static const struct ov2640_win_size ov2640_supported_win_sizes[] = {
+	OV2640_SIZE("QCIF", W_QCIF, H_QCIF, ov2640_qcif_regs),
+	OV2640_SIZE("QVGA", W_QVGA, H_QVGA, ov2640_qvga_regs),
+	OV2640_SIZE("CIF", W_CIF, H_CIF, ov2640_cif_regs),
+	OV2640_SIZE("VGA", W_VGA, H_VGA, ov2640_vga_regs),
+	OV2640_SIZE("SVGA", W_SVGA, H_SVGA, ov2640_svga_regs),
+	OV2640_SIZE("XGA", W_XGA, H_XGA, ov2640_xga_regs),
+	OV2640_SIZE("SXGA", W_SXGA, H_SXGA, ov2640_sxga_regs),
+	OV2640_SIZE("UXGA", W_UXGA, H_UXGA, ov2640_uxga_regs),
+};
+
+/*
+ * Register settings for pixel formats
+ */
+static const struct regval_list ov2640_format_change_preamble_regs[] = {
+	{ BANK_SEL, BANK_SEL_DSP },
+	{ R_BYPASS, R_BYPASS_USE_DSP },
+	ENDMARKER,
+};
+
+static const struct regval_list ov2640_yuv422_regs[] = {
+	{ IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_YUV422 },
+	{ 0xD7, 0x01 },
+	{ 0x33, 0xa0 },
+	{ 0xe1, 0x67 },
+	{ RESET,  0x00 },
+	{ R_BYPASS, R_BYPASS_USE_DSP },
+	ENDMARKER,
+};
+
+static const struct regval_list ov2640_rgb565_regs[] = {
+	{ IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_RGB565 },
+	{ 0xd7, 0x03 },
+	{ RESET,  0x00 },
+	{ R_BYPASS, R_BYPASS_USE_DSP },
+	ENDMARKER,
+};
+
+static enum v4l2_mbus_pixelcode ov2640_codes[] = {
+	V4L2_MBUS_FMT_UYVY8_2X8,
+	V4L2_MBUS_FMT_RGB565_2X8_LE,
+};
+
+/*
+ * General functions
+ */
+static struct ov2640_priv *to_ov2640(const struct i2c_client *client)
+{
+	return container_of(i2c_get_clientdata(client), struct ov2640_priv,
+			    subdev);
+}
+
+static int ov2640_write_array(struct i2c_client *client,
+			      const struct regval_list *vals)
+{
+	int ret;
+
+	while ((vals->reg_num != 0xff) || (vals->value != 0xff)) {
+		ret = i2c_smbus_write_byte_data(client,
+						vals->reg_num, vals->value);
+		dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x",
+			 vals->reg_num, vals->value);
+
+		if (ret < 0)
+			return ret;
+		vals++;
+	}
+	return 0;
+}
+
+static int ov2640_mask_set(struct i2c_client *client,
+			   u8  reg, u8  mask, u8  set)
+{
+	s32 val = i2c_smbus_read_byte_data(client, reg);
+	if (val < 0)
+		return val;
+
+	val &= ~mask;
+	val |= set & mask;
+
+	dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val);
+
+	return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int ov2640_reset(struct i2c_client *client)
+{
+	int ret;
+	const struct regval_list reset_seq[] = {
+		{BANK_SEL, BANK_SEL_SENS},
+		{COM7, COM7_SRST},
+		ENDMARKER,
+	};
+
+	ret = ov2640_write_array(client, reset_seq);
+	if (ret)
+		goto err;
+
+	msleep(5);
+err:
+	dev_dbg(&client->dev, "%s: (ret %d)", __func__, ret);
+	return ret;
+}
+
+/*
+ * soc_camera_ops functions
+ */
+static int ov2640_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	return 0;
+}
+
+static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd =
+		&container_of(ctrl->handler, struct ov2640_priv, hdl)->subdev;
+	struct i2c_client  *client = v4l2_get_subdevdata(sd);
+	u8 val;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		val = ctrl->val ? REG04_VFLIP_IMG : 0x00;
+		return ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val);
+	case V4L2_CID_HFLIP:
+		val = ctrl->val ? REG04_HFLIP_IMG : 0x00;
+		return ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val);
+	}
+
+	return -EINVAL;
+}
+
+static int ov2640_g_chip_ident(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_chip_ident *id)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov2640_priv *priv = to_ov2640(client);
+
+	id->ident    = priv->model;
+	id->revision = 0;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov2640_g_register(struct v4l2_subdev *sd,
+			     struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+
+	reg->size = 1;
+	if (reg->reg > 0xff)
+		return -EINVAL;
+
+	ret = i2c_smbus_read_byte_data(client, reg->reg);
+	if (ret < 0)
+		return ret;
+
+	reg->val = ret;
+
+	return 0;
+}
+
+static int ov2640_s_register(struct v4l2_subdev *sd,
+			     struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->reg > 0xff ||
+	    reg->val > 0xff)
+		return -EINVAL;
+
+	return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov2640_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	return soc_camera_set_power(&client->dev, icl, on);
+}
+
+/* Select the nearest higher resolution for capture */
+static const struct ov2640_win_size *ov2640_select_win(u32 *width, u32 *height)
+{
+	int i, default_size = ARRAY_SIZE(ov2640_supported_win_sizes) - 1;
+
+	for (i = 0; i < ARRAY_SIZE(ov2640_supported_win_sizes); i++) {
+		if (ov2640_supported_win_sizes[i].width  >= *width &&
+		    ov2640_supported_win_sizes[i].height >= *height) {
+			*width = ov2640_supported_win_sizes[i].width;
+			*height = ov2640_supported_win_sizes[i].height;
+			return &ov2640_supported_win_sizes[i];
+		}
+	}
+
+	*width = ov2640_supported_win_sizes[default_size].width;
+	*height = ov2640_supported_win_sizes[default_size].height;
+	return &ov2640_supported_win_sizes[default_size];
+}
+
+static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height,
+			     enum v4l2_mbus_pixelcode code)
+{
+	struct ov2640_priv       *priv = to_ov2640(client);
+	const struct regval_list *selected_cfmt_regs;
+	int ret;
+
+	/* select win */
+	priv->win = ov2640_select_win(width, height);
+
+	/* select format */
+	priv->cfmt_code = 0;
+	switch (code) {
+	case V4L2_MBUS_FMT_RGB565_2X8_LE:
+		dev_dbg(&client->dev, "%s: Selected cfmt RGB565", __func__);
+		selected_cfmt_regs = ov2640_rgb565_regs;
+		break;
+	default:
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		dev_dbg(&client->dev, "%s: Selected cfmt YUV422", __func__);
+		selected_cfmt_regs = ov2640_yuv422_regs;
+	}
+
+	/* reset hardware */
+	ov2640_reset(client);
+
+	/* initialize the sensor with default data */
+	dev_dbg(&client->dev, "%s: Init default", __func__);
+	ret = ov2640_write_array(client, ov2640_init_regs);
+	if (ret < 0)
+		goto err;
+
+	/* select preamble */
+	dev_dbg(&client->dev, "%s: Set size to %s", __func__, priv->win->name);
+	ret = ov2640_write_array(client, ov2640_size_change_preamble_regs);
+	if (ret < 0)
+		goto err;
+
+	/* set size win */
+	ret = ov2640_write_array(client, priv->win->regs);
+	if (ret < 0)
+		goto err;
+
+	/* cfmt preamble */
+	dev_dbg(&client->dev, "%s: Set cfmt", __func__);
+	ret = ov2640_write_array(client, ov2640_format_change_preamble_regs);
+	if (ret < 0)
+		goto err;
+
+	/* set cfmt */
+	ret = ov2640_write_array(client, selected_cfmt_regs);
+	if (ret < 0)
+		goto err;
+
+	priv->cfmt_code = code;
+	*width = priv->win->width;
+	*height = priv->win->height;
+
+	return 0;
+
+err:
+	dev_err(&client->dev, "%s: Error %d", __func__, ret);
+	ov2640_reset(client);
+	priv->win = NULL;
+
+	return ret;
+}
+
+static int ov2640_g_fmt(struct v4l2_subdev *sd,
+			struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client  *client = v4l2_get_subdevdata(sd);
+	struct ov2640_priv *priv = to_ov2640(client);
+
+	if (!priv->win) {
+		u32 width = W_SVGA, height = H_SVGA;
+		priv->win = ov2640_select_win(&width, &height);
+		priv->cfmt_code = V4L2_MBUS_FMT_UYVY8_2X8;
+	}
+
+	mf->width	= priv->win->width;
+	mf->height	= priv->win->height;
+	mf->code	= priv->cfmt_code;
+
+	switch (mf->code) {
+	case V4L2_MBUS_FMT_RGB565_2X8_LE:
+		mf->colorspace = V4L2_COLORSPACE_SRGB;
+		break;
+	default:
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		mf->colorspace = V4L2_COLORSPACE_JPEG;
+	}
+	mf->field	= V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static int ov2640_s_fmt(struct v4l2_subdev *sd,
+			struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+
+
+	switch (mf->code) {
+	case V4L2_MBUS_FMT_RGB565_2X8_LE:
+		mf->colorspace = V4L2_COLORSPACE_SRGB;
+		break;
+	default:
+		mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		mf->colorspace = V4L2_COLORSPACE_JPEG;
+	}
+
+	ret = ov2640_set_params(client, &mf->width, &mf->height, mf->code);
+
+	return ret;
+}
+
+static int ov2640_try_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_mbus_framefmt *mf)
+{
+	const struct ov2640_win_size *win;
+
+	/*
+	 * select suitable win
+	 */
+	win = ov2640_select_win(&mf->width, &mf->height);
+
+	mf->field	= V4L2_FIELD_NONE;
+
+	switch (mf->code) {
+	case V4L2_MBUS_FMT_RGB565_2X8_LE:
+		mf->colorspace = V4L2_COLORSPACE_SRGB;
+		break;
+	default:
+		mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		mf->colorspace = V4L2_COLORSPACE_JPEG;
+	}
+
+	return 0;
+}
+
+static int ov2640_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			   enum v4l2_mbus_pixelcode *code)
+{
+	if (index >= ARRAY_SIZE(ov2640_codes))
+		return -EINVAL;
+
+	*code = ov2640_codes[index];
+	return 0;
+}
+
+static int ov2640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	a->c.left	= 0;
+	a->c.top	= 0;
+	a->c.width	= W_UXGA;
+	a->c.height	= H_UXGA;
+	a->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int ov2640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	a->bounds.left			= 0;
+	a->bounds.top			= 0;
+	a->bounds.width			= W_UXGA;
+	a->bounds.height		= H_UXGA;
+	a->defrect			= a->bounds;
+	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int ov2640_video_probe(struct i2c_client *client)
+{
+	struct ov2640_priv *priv = to_ov2640(client);
+	u8 pid, ver, midh, midl;
+	const char *devname;
+	int ret;
+
+	ret = ov2640_s_power(&priv->subdev, 1);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * check and show product ID and manufacturer ID
+	 */
+	i2c_smbus_write_byte_data(client, BANK_SEL, BANK_SEL_SENS);
+	pid  = i2c_smbus_read_byte_data(client, PID);
+	ver  = i2c_smbus_read_byte_data(client, VER);
+	midh = i2c_smbus_read_byte_data(client, MIDH);
+	midl = i2c_smbus_read_byte_data(client, MIDL);
+
+	switch (VERSION(pid, ver)) {
+	case PID_OV2640:
+		devname     = "ov2640";
+		priv->model = V4L2_IDENT_OV2640;
+		break;
+	default:
+		dev_err(&client->dev,
+			"Product ID error %x:%x\n", pid, ver);
+		ret = -ENODEV;
+		goto done;
+	}
+
+	dev_info(&client->dev,
+		 "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
+		 devname, pid, ver, midh, midl);
+
+	ret = v4l2_ctrl_handler_setup(&priv->hdl);
+
+done:
+	ov2640_s_power(&priv->subdev, 0);
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops ov2640_ctrl_ops = {
+	.s_ctrl = ov2640_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = {
+	.g_chip_ident	= ov2640_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register	= ov2640_g_register,
+	.s_register	= ov2640_s_register,
+#endif
+	.s_power	= ov2640_s_power,
+};
+
+static int ov2640_g_mbus_config(struct v4l2_subdev *sd,
+				struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
+		V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+		V4L2_MBUS_DATA_ACTIVE_HIGH;
+	cfg->type = V4L2_MBUS_PARALLEL;
+	cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+	return 0;
+}
+
+static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = {
+	.s_stream	= ov2640_s_stream,
+	.g_mbus_fmt	= ov2640_g_fmt,
+	.s_mbus_fmt	= ov2640_s_fmt,
+	.try_mbus_fmt	= ov2640_try_fmt,
+	.cropcap	= ov2640_cropcap,
+	.g_crop		= ov2640_g_crop,
+	.enum_mbus_fmt	= ov2640_enum_fmt,
+	.g_mbus_config	= ov2640_g_mbus_config,
+};
+
+static struct v4l2_subdev_ops ov2640_subdev_ops = {
+	.core	= &ov2640_subdev_core_ops,
+	.video	= &ov2640_subdev_video_ops,
+};
+
+/*
+ * i2c_driver functions
+ */
+static int ov2640_probe(struct i2c_client *client,
+			const struct i2c_device_id *did)
+{
+	struct ov2640_priv	*priv;
+	struct soc_camera_link	*icl = soc_camera_i2c_to_link(client);
+	struct i2c_adapter	*adapter = to_i2c_adapter(client->dev.parent);
+	int			ret;
+
+	if (!icl) {
+		dev_err(&adapter->dev,
+			"OV2640: Missing platform_data for driver\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		dev_err(&adapter->dev,
+			"OV2640: I2C-Adapter doesn't support SMBUS\n");
+		return -EIO;
+	}
+
+	priv = kzalloc(sizeof(struct ov2640_priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&adapter->dev,
+			"Failed to allocate memory for private data!\n");
+		return -ENOMEM;
+	}
+
+	v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops);
+	v4l2_ctrl_handler_init(&priv->hdl, 2);
+	v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
+			V4L2_CID_HFLIP, 0, 1, 1, 0);
+	priv->subdev.ctrl_handler = &priv->hdl;
+	if (priv->hdl.error) {
+		int err = priv->hdl.error;
+
+		kfree(priv);
+		return err;
+	}
+
+	ret = ov2640_video_probe(client);
+	if (ret) {
+		v4l2_ctrl_handler_free(&priv->hdl);
+		kfree(priv);
+	} else {
+		dev_info(&adapter->dev, "OV2640 Probed\n");
+	}
+
+	return ret;
+}
+
+static int ov2640_remove(struct i2c_client *client)
+{
+	struct ov2640_priv       *priv = to_ov2640(client);
+
+	v4l2_device_unregister_subdev(&priv->subdev);
+	v4l2_ctrl_handler_free(&priv->hdl);
+	kfree(priv);
+	return 0;
+}
+
+static const struct i2c_device_id ov2640_id[] = {
+	{ "ov2640", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ov2640_id);
+
+static struct i2c_driver ov2640_i2c_driver = {
+	.driver = {
+		.name = "ov2640",
+	},
+	.probe    = ov2640_probe,
+	.remove   = ov2640_remove,
+	.id_table = ov2640_id,
+};
+
+module_i2c_driver(ov2640_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 2640 sensor");
+MODULE_AUTHOR("Alberto Panizzo");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c
new file mode 100644
index 0000000..d886c0b
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov5642.c
@@ -0,0 +1,1088 @@
+/*
+ * Driver for OV5642 CMOS Image Sensor from Omnivision
+ *
+ * Copyright (C) 2011, Bastian Hecht <hechtb@gmail.com>
+ *
+ * Based on Sony IMX074 Camera Driver
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * Based on Omnivision OV7670 Camera Driver
+ * Copyright (C) 2006-7 Jonathan Corbet <corbet@lwn.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
+
+/* OV5642 registers */
+#define REG_CHIP_ID_HIGH		0x300a
+#define REG_CHIP_ID_LOW			0x300b
+
+#define REG_WINDOW_START_X_HIGH		0x3800
+#define REG_WINDOW_START_X_LOW		0x3801
+#define REG_WINDOW_START_Y_HIGH		0x3802
+#define REG_WINDOW_START_Y_LOW		0x3803
+#define REG_WINDOW_WIDTH_HIGH		0x3804
+#define REG_WINDOW_WIDTH_LOW		0x3805
+#define REG_WINDOW_HEIGHT_HIGH		0x3806
+#define REG_WINDOW_HEIGHT_LOW		0x3807
+#define REG_OUT_WIDTH_HIGH		0x3808
+#define REG_OUT_WIDTH_LOW		0x3809
+#define REG_OUT_HEIGHT_HIGH		0x380a
+#define REG_OUT_HEIGHT_LOW		0x380b
+#define REG_OUT_TOTAL_WIDTH_HIGH	0x380c
+#define REG_OUT_TOTAL_WIDTH_LOW		0x380d
+#define REG_OUT_TOTAL_HEIGHT_HIGH	0x380e
+#define REG_OUT_TOTAL_HEIGHT_LOW	0x380f
+#define REG_OUTPUT_FORMAT		0x4300
+#define REG_ISP_CTRL_01			0x5001
+#define REG_AVG_WINDOW_END_X_HIGH	0x5682
+#define REG_AVG_WINDOW_END_X_LOW	0x5683
+#define REG_AVG_WINDOW_END_Y_HIGH	0x5686
+#define REG_AVG_WINDOW_END_Y_LOW	0x5687
+
+/* active pixel array size */
+#define OV5642_SENSOR_SIZE_X	2592
+#define OV5642_SENSOR_SIZE_Y	1944
+
+/*
+ * About OV5642 resolution, cropping and binning:
+ * This sensor supports it all, at least in the feature description.
+ * Unfortunately, no combination of appropriate registers settings could make
+ * the chip work the intended way. As it works with predefined register lists,
+ * some undocumented registers are presumably changed there to achieve their
+ * goals.
+ * This driver currently only works for resolutions up to 720 lines with a
+ * 1:1 scale. Hopefully these restrictions will be removed in the future.
+ */
+#define OV5642_MAX_WIDTH	OV5642_SENSOR_SIZE_X
+#define OV5642_MAX_HEIGHT	720
+
+/* default sizes */
+#define OV5642_DEFAULT_WIDTH	1280
+#define OV5642_DEFAULT_HEIGHT	OV5642_MAX_HEIGHT
+
+/* minimum extra blanking */
+#define BLANKING_EXTRA_WIDTH		500
+#define BLANKING_EXTRA_HEIGHT		20
+
+/*
+ * the sensor's autoexposure is buggy when setting total_height low.
+ * It tries to expose longer than 1 frame period without taking care of it
+ * and this leads to weird output. So we set 1000 lines as minimum.
+ */
+#define BLANKING_MIN_HEIGHT		1000
+
+struct regval_list {
+	u16 reg_num;
+	u8 value;
+};
+
+static struct regval_list ov5642_default_regs_init[] = {
+	{ 0x3103, 0x93 },
+	{ 0x3008, 0x82 },
+	{ 0x3017, 0x7f },
+	{ 0x3018, 0xfc },
+	{ 0x3810, 0xc2 },
+	{ 0x3615, 0xf0 },
+	{ 0x3000, 0x0  },
+	{ 0x3001, 0x0  },
+	{ 0x3002, 0x0  },
+	{ 0x3003, 0x0  },
+	{ 0x3004, 0xff },
+	{ 0x3030, 0x2b },
+	{ 0x3011, 0x8  },
+	{ 0x3010, 0x10 },
+	{ 0x3604, 0x60 },
+	{ 0x3622, 0x60 },
+	{ 0x3621, 0x9  },
+	{ 0x3709, 0x0  },
+	{ 0x4000, 0x21 },
+	{ 0x401d, 0x22 },
+	{ 0x3600, 0x54 },
+	{ 0x3605, 0x4  },
+	{ 0x3606, 0x3f },
+	{ 0x3c01, 0x80 },
+	{ 0x300d, 0x22 },
+	{ 0x3623, 0x22 },
+	{ 0x5000, 0x4f },
+	{ 0x5020, 0x4  },
+	{ 0x5181, 0x79 },
+	{ 0x5182, 0x0  },
+	{ 0x5185, 0x22 },
+	{ 0x5197, 0x1  },
+	{ 0x5500, 0xa  },
+	{ 0x5504, 0x0  },
+	{ 0x5505, 0x7f },
+	{ 0x5080, 0x8  },
+	{ 0x300e, 0x18 },
+	{ 0x4610, 0x0  },
+	{ 0x471d, 0x5  },
+	{ 0x4708, 0x6  },
+	{ 0x370c, 0xa0 },
+	{ 0x5687, 0x94 },
+	{ 0x501f, 0x0  },
+	{ 0x5000, 0x4f },
+	{ 0x5001, 0xcf },
+	{ 0x4300, 0x30 },
+	{ 0x4300, 0x30 },
+	{ 0x460b, 0x35 },
+	{ 0x471d, 0x0  },
+	{ 0x3002, 0xc  },
+	{ 0x3002, 0x0  },
+	{ 0x4713, 0x3  },
+	{ 0x471c, 0x50 },
+	{ 0x4721, 0x2  },
+	{ 0x4402, 0x90 },
+	{ 0x460c, 0x22 },
+	{ 0x3815, 0x44 },
+	{ 0x3503, 0x7  },
+	{ 0x3501, 0x73 },
+	{ 0x3502, 0x80 },
+	{ 0x350b, 0x0  },
+	{ 0x3818, 0xc8 },
+	{ 0x3824, 0x11 },
+	{ 0x3a00, 0x78 },
+	{ 0x3a1a, 0x4  },
+	{ 0x3a13, 0x30 },
+	{ 0x3a18, 0x0  },
+	{ 0x3a19, 0x7c },
+	{ 0x3a08, 0x12 },
+	{ 0x3a09, 0xc0 },
+	{ 0x3a0a, 0xf  },
+	{ 0x3a0b, 0xa0 },
+	{ 0x350c, 0x7  },
+	{ 0x350d, 0xd0 },
+	{ 0x3a0d, 0x8  },
+	{ 0x3a0e, 0x6  },
+	{ 0x3500, 0x0  },
+	{ 0x3501, 0x0  },
+	{ 0x3502, 0x0  },
+	{ 0x350a, 0x0  },
+	{ 0x350b, 0x0  },
+	{ 0x3503, 0x0  },
+	{ 0x3a0f, 0x3c },
+	{ 0x3a10, 0x32 },
+	{ 0x3a1b, 0x3c },
+	{ 0x3a1e, 0x32 },
+	{ 0x3a11, 0x80 },
+	{ 0x3a1f, 0x20 },
+	{ 0x3030, 0x2b },
+	{ 0x3a02, 0x0  },
+	{ 0x3a03, 0x7d },
+	{ 0x3a04, 0x0  },
+	{ 0x3a14, 0x0  },
+	{ 0x3a15, 0x7d },
+	{ 0x3a16, 0x0  },
+	{ 0x3a00, 0x78 },
+	{ 0x3a08, 0x9  },
+	{ 0x3a09, 0x60 },
+	{ 0x3a0a, 0x7  },
+	{ 0x3a0b, 0xd0 },
+	{ 0x3a0d, 0x10 },
+	{ 0x3a0e, 0xd  },
+	{ 0x4407, 0x4  },
+	{ 0x5193, 0x70 },
+	{ 0x589b, 0x0  },
+	{ 0x589a, 0xc0 },
+	{ 0x401e, 0x20 },
+	{ 0x4001, 0x42 },
+	{ 0x401c, 0x6  },
+	{ 0x3825, 0xac },
+	{ 0x3827, 0xc  },
+	{ 0x528a, 0x1  },
+	{ 0x528b, 0x4  },
+	{ 0x528c, 0x8  },
+	{ 0x528d, 0x10 },
+	{ 0x528e, 0x20 },
+	{ 0x528f, 0x28 },
+	{ 0x5290, 0x30 },
+	{ 0x5292, 0x0  },
+	{ 0x5293, 0x1  },
+	{ 0x5294, 0x0  },
+	{ 0x5295, 0x4  },
+	{ 0x5296, 0x0  },
+	{ 0x5297, 0x8  },
+	{ 0x5298, 0x0  },
+	{ 0x5299, 0x10 },
+	{ 0x529a, 0x0  },
+	{ 0x529b, 0x20 },
+	{ 0x529c, 0x0  },
+	{ 0x529d, 0x28 },
+	{ 0x529e, 0x0  },
+	{ 0x529f, 0x30 },
+	{ 0x5282, 0x0  },
+	{ 0x5300, 0x0  },
+	{ 0x5301, 0x20 },
+	{ 0x5302, 0x0  },
+	{ 0x5303, 0x7c },
+	{ 0x530c, 0x0  },
+	{ 0x530d, 0xc  },
+	{ 0x530e, 0x20 },
+	{ 0x530f, 0x80 },
+	{ 0x5310, 0x20 },
+	{ 0x5311, 0x80 },
+	{ 0x5308, 0x20 },
+	{ 0x5309, 0x40 },
+	{ 0x5304, 0x0  },
+	{ 0x5305, 0x30 },
+	{ 0x5306, 0x0  },
+	{ 0x5307, 0x80 },
+	{ 0x5314, 0x8  },
+	{ 0x5315, 0x20 },
+	{ 0x5319, 0x30 },
+	{ 0x5316, 0x10 },
+	{ 0x5317, 0x0  },
+	{ 0x5318, 0x2  },
+	{ 0x5380, 0x1  },
+	{ 0x5381, 0x0  },
+	{ 0x5382, 0x0  },
+	{ 0x5383, 0x4e },
+	{ 0x5384, 0x0  },
+	{ 0x5385, 0xf  },
+	{ 0x5386, 0x0  },
+	{ 0x5387, 0x0  },
+	{ 0x5388, 0x1  },
+	{ 0x5389, 0x15 },
+	{ 0x538a, 0x0  },
+	{ 0x538b, 0x31 },
+	{ 0x538c, 0x0  },
+	{ 0x538d, 0x0  },
+	{ 0x538e, 0x0  },
+	{ 0x538f, 0xf  },
+	{ 0x5390, 0x0  },
+	{ 0x5391, 0xab },
+	{ 0x5392, 0x0  },
+	{ 0x5393, 0xa2 },
+	{ 0x5394, 0x8  },
+	{ 0x5480, 0x14 },
+	{ 0x5481, 0x21 },
+	{ 0x5482, 0x36 },
+	{ 0x5483, 0x57 },
+	{ 0x5484, 0x65 },
+	{ 0x5485, 0x71 },
+	{ 0x5486, 0x7d },
+	{ 0x5487, 0x87 },
+	{ 0x5488, 0x91 },
+	{ 0x5489, 0x9a },
+	{ 0x548a, 0xaa },
+	{ 0x548b, 0xb8 },
+	{ 0x548c, 0xcd },
+	{ 0x548d, 0xdd },
+	{ 0x548e, 0xea },
+	{ 0x548f, 0x1d },
+	{ 0x5490, 0x5  },
+	{ 0x5491, 0x0  },
+	{ 0x5492, 0x4  },
+	{ 0x5493, 0x20 },
+	{ 0x5494, 0x3  },
+	{ 0x5495, 0x60 },
+	{ 0x5496, 0x2  },
+	{ 0x5497, 0xb8 },
+	{ 0x5498, 0x2  },
+	{ 0x5499, 0x86 },
+	{ 0x549a, 0x2  },
+	{ 0x549b, 0x5b },
+	{ 0x549c, 0x2  },
+	{ 0x549d, 0x3b },
+	{ 0x549e, 0x2  },
+	{ 0x549f, 0x1c },
+	{ 0x54a0, 0x2  },
+	{ 0x54a1, 0x4  },
+	{ 0x54a2, 0x1  },
+	{ 0x54a3, 0xed },
+	{ 0x54a4, 0x1  },
+	{ 0x54a5, 0xc5 },
+	{ 0x54a6, 0x1  },
+	{ 0x54a7, 0xa5 },
+	{ 0x54a8, 0x1  },
+	{ 0x54a9, 0x6c },
+	{ 0x54aa, 0x1  },
+	{ 0x54ab, 0x41 },
+	{ 0x54ac, 0x1  },
+	{ 0x54ad, 0x20 },
+	{ 0x54ae, 0x0  },
+	{ 0x54af, 0x16 },
+	{ 0x54b0, 0x1  },
+	{ 0x54b1, 0x20 },
+	{ 0x54b2, 0x0  },
+	{ 0x54b3, 0x10 },
+	{ 0x54b4, 0x0  },
+	{ 0x54b5, 0xf0 },
+	{ 0x54b6, 0x0  },
+	{ 0x54b7, 0xdf },
+	{ 0x5402, 0x3f },
+	{ 0x5403, 0x0  },
+	{ 0x3406, 0x0  },
+	{ 0x5180, 0xff },
+	{ 0x5181, 0x52 },
+	{ 0x5182, 0x11 },
+	{ 0x5183, 0x14 },
+	{ 0x5184, 0x25 },
+	{ 0x5185, 0x24 },
+	{ 0x5186, 0x6  },
+	{ 0x5187, 0x8  },
+	{ 0x5188, 0x8  },
+	{ 0x5189, 0x7c },
+	{ 0x518a, 0x60 },
+	{ 0x518b, 0xb2 },
+	{ 0x518c, 0xb2 },
+	{ 0x518d, 0x44 },
+	{ 0x518e, 0x3d },
+	{ 0x518f, 0x58 },
+	{ 0x5190, 0x46 },
+	{ 0x5191, 0xf8 },
+	{ 0x5192, 0x4  },
+	{ 0x5193, 0x70 },
+	{ 0x5194, 0xf0 },
+	{ 0x5195, 0xf0 },
+	{ 0x5196, 0x3  },
+	{ 0x5197, 0x1  },
+	{ 0x5198, 0x4  },
+	{ 0x5199, 0x12 },
+	{ 0x519a, 0x4  },
+	{ 0x519b, 0x0  },
+	{ 0x519c, 0x6  },
+	{ 0x519d, 0x82 },
+	{ 0x519e, 0x0  },
+	{ 0x5025, 0x80 },
+	{ 0x3a0f, 0x38 },
+	{ 0x3a10, 0x30 },
+	{ 0x3a1b, 0x3a },
+	{ 0x3a1e, 0x2e },
+	{ 0x3a11, 0x60 },
+	{ 0x3a1f, 0x10 },
+	{ 0x5688, 0xa6 },
+	{ 0x5689, 0x6a },
+	{ 0x568a, 0xea },
+	{ 0x568b, 0xae },
+	{ 0x568c, 0xa6 },
+	{ 0x568d, 0x6a },
+	{ 0x568e, 0x62 },
+	{ 0x568f, 0x26 },
+	{ 0x5583, 0x40 },
+	{ 0x5584, 0x40 },
+	{ 0x5580, 0x2  },
+	{ 0x5000, 0xcf },
+	{ 0x5800, 0x27 },
+	{ 0x5801, 0x19 },
+	{ 0x5802, 0x12 },
+	{ 0x5803, 0xf  },
+	{ 0x5804, 0x10 },
+	{ 0x5805, 0x15 },
+	{ 0x5806, 0x1e },
+	{ 0x5807, 0x2f },
+	{ 0x5808, 0x15 },
+	{ 0x5809, 0xd  },
+	{ 0x580a, 0xa  },
+	{ 0x580b, 0x9  },
+	{ 0x580c, 0xa  },
+	{ 0x580d, 0xc  },
+	{ 0x580e, 0x12 },
+	{ 0x580f, 0x19 },
+	{ 0x5810, 0xb  },
+	{ 0x5811, 0x7  },
+	{ 0x5812, 0x4  },
+	{ 0x5813, 0x3  },
+	{ 0x5814, 0x3  },
+	{ 0x5815, 0x6  },
+	{ 0x5816, 0xa  },
+	{ 0x5817, 0xf  },
+	{ 0x5818, 0xa  },
+	{ 0x5819, 0x5  },
+	{ 0x581a, 0x1  },
+	{ 0x581b, 0x0  },
+	{ 0x581c, 0x0  },
+	{ 0x581d, 0x3  },
+	{ 0x581e, 0x8  },
+	{ 0x581f, 0xc  },
+	{ 0x5820, 0xa  },
+	{ 0x5821, 0x5  },
+	{ 0x5822, 0x1  },
+	{ 0x5823, 0x0  },
+	{ 0x5824, 0x0  },
+	{ 0x5825, 0x3  },
+	{ 0x5826, 0x8  },
+	{ 0x5827, 0xc  },
+	{ 0x5828, 0xe  },
+	{ 0x5829, 0x8  },
+	{ 0x582a, 0x6  },
+	{ 0x582b, 0x4  },
+	{ 0x582c, 0x5  },
+	{ 0x582d, 0x7  },
+	{ 0x582e, 0xb  },
+	{ 0x582f, 0x12 },
+	{ 0x5830, 0x18 },
+	{ 0x5831, 0x10 },
+	{ 0x5832, 0xc  },
+	{ 0x5833, 0xa  },
+	{ 0x5834, 0xb  },
+	{ 0x5835, 0xe  },
+	{ 0x5836, 0x15 },
+	{ 0x5837, 0x19 },
+	{ 0x5838, 0x32 },
+	{ 0x5839, 0x1f },
+	{ 0x583a, 0x18 },
+	{ 0x583b, 0x16 },
+	{ 0x583c, 0x17 },
+	{ 0x583d, 0x1e },
+	{ 0x583e, 0x26 },
+	{ 0x583f, 0x53 },
+	{ 0x5840, 0x10 },
+	{ 0x5841, 0xf  },
+	{ 0x5842, 0xd  },
+	{ 0x5843, 0xc  },
+	{ 0x5844, 0xe  },
+	{ 0x5845, 0x9  },
+	{ 0x5846, 0x11 },
+	{ 0x5847, 0x10 },
+	{ 0x5848, 0x10 },
+	{ 0x5849, 0x10 },
+	{ 0x584a, 0x10 },
+	{ 0x584b, 0xe  },
+	{ 0x584c, 0x10 },
+	{ 0x584d, 0x10 },
+	{ 0x584e, 0x11 },
+	{ 0x584f, 0x10 },
+	{ 0x5850, 0xf  },
+	{ 0x5851, 0xc  },
+	{ 0x5852, 0xf  },
+	{ 0x5853, 0x10 },
+	{ 0x5854, 0x10 },
+	{ 0x5855, 0xf  },
+	{ 0x5856, 0xe  },
+	{ 0x5857, 0xb  },
+	{ 0x5858, 0x10 },
+	{ 0x5859, 0xd  },
+	{ 0x585a, 0xd  },
+	{ 0x585b, 0xc  },
+	{ 0x585c, 0xc  },
+	{ 0x585d, 0xc  },
+	{ 0x585e, 0xb  },
+	{ 0x585f, 0xc  },
+	{ 0x5860, 0xc  },
+	{ 0x5861, 0xc  },
+	{ 0x5862, 0xd  },
+	{ 0x5863, 0x8  },
+	{ 0x5864, 0x11 },
+	{ 0x5865, 0x18 },
+	{ 0x5866, 0x18 },
+	{ 0x5867, 0x19 },
+	{ 0x5868, 0x17 },
+	{ 0x5869, 0x19 },
+	{ 0x586a, 0x16 },
+	{ 0x586b, 0x13 },
+	{ 0x586c, 0x13 },
+	{ 0x586d, 0x12 },
+	{ 0x586e, 0x13 },
+	{ 0x586f, 0x16 },
+	{ 0x5870, 0x14 },
+	{ 0x5871, 0x12 },
+	{ 0x5872, 0x10 },
+	{ 0x5873, 0x11 },
+	{ 0x5874, 0x11 },
+	{ 0x5875, 0x16 },
+	{ 0x5876, 0x14 },
+	{ 0x5877, 0x11 },
+	{ 0x5878, 0x10 },
+	{ 0x5879, 0xf  },
+	{ 0x587a, 0x10 },
+	{ 0x587b, 0x14 },
+	{ 0x587c, 0x13 },
+	{ 0x587d, 0x12 },
+	{ 0x587e, 0x11 },
+	{ 0x587f, 0x11 },
+	{ 0x5880, 0x12 },
+	{ 0x5881, 0x15 },
+	{ 0x5882, 0x14 },
+	{ 0x5883, 0x15 },
+	{ 0x5884, 0x15 },
+	{ 0x5885, 0x15 },
+	{ 0x5886, 0x13 },
+	{ 0x5887, 0x17 },
+	{ 0x3710, 0x10 },
+	{ 0x3632, 0x51 },
+	{ 0x3702, 0x10 },
+	{ 0x3703, 0xb2 },
+	{ 0x3704, 0x18 },
+	{ 0x370b, 0x40 },
+	{ 0x370d, 0x3  },
+	{ 0x3631, 0x1  },
+	{ 0x3632, 0x52 },
+	{ 0x3606, 0x24 },
+	{ 0x3620, 0x96 },
+	{ 0x5785, 0x7  },
+	{ 0x3a13, 0x30 },
+	{ 0x3600, 0x52 },
+	{ 0x3604, 0x48 },
+	{ 0x3606, 0x1b },
+	{ 0x370d, 0xb  },
+	{ 0x370f, 0xc0 },
+	{ 0x3709, 0x1  },
+	{ 0x3823, 0x0  },
+	{ 0x5007, 0x0  },
+	{ 0x5009, 0x0  },
+	{ 0x5011, 0x0  },
+	{ 0x5013, 0x0  },
+	{ 0x519e, 0x0  },
+	{ 0x5086, 0x0  },
+	{ 0x5087, 0x0  },
+	{ 0x5088, 0x0  },
+	{ 0x5089, 0x0  },
+	{ 0x302b, 0x0  },
+	{ 0x3503, 0x7  },
+	{ 0x3011, 0x8  },
+	{ 0x350c, 0x2  },
+	{ 0x350d, 0xe4 },
+	{ 0x3621, 0xc9 },
+	{ 0x370a, 0x81 },
+	{ 0xffff, 0xff },
+};
+
+static struct regval_list ov5642_default_regs_finalise[] = {
+	{ 0x3810, 0xc2 },
+	{ 0x3818, 0xc9 },
+	{ 0x381c, 0x10 },
+	{ 0x381d, 0xa0 },
+	{ 0x381e, 0x5  },
+	{ 0x381f, 0xb0 },
+	{ 0x3820, 0x0  },
+	{ 0x3821, 0x0  },
+	{ 0x3824, 0x11 },
+	{ 0x3a08, 0x1b },
+	{ 0x3a09, 0xc0 },
+	{ 0x3a0a, 0x17 },
+	{ 0x3a0b, 0x20 },
+	{ 0x3a0d, 0x2  },
+	{ 0x3a0e, 0x1  },
+	{ 0x401c, 0x4  },
+	{ 0x5682, 0x5  },
+	{ 0x5683, 0x0  },
+	{ 0x5686, 0x2  },
+	{ 0x5687, 0xcc },
+	{ 0x5001, 0x4f },
+	{ 0x589b, 0x6  },
+	{ 0x589a, 0xc5 },
+	{ 0x3503, 0x0  },
+	{ 0x460c, 0x20 },
+	{ 0x460b, 0x37 },
+	{ 0x471c, 0xd0 },
+	{ 0x471d, 0x5  },
+	{ 0x3815, 0x1  },
+	{ 0x3818, 0xc1 },
+	{ 0x501f, 0x0  },
+	{ 0x5002, 0xe0 },
+	{ 0x4300, 0x32 }, /* UYVY */
+	{ 0x3002, 0x1c },
+	{ 0x4800, 0x14 },
+	{ 0x4801, 0xf  },
+	{ 0x3007, 0x3b },
+	{ 0x300e, 0x4  },
+	{ 0x4803, 0x50 },
+	{ 0x3815, 0x1  },
+	{ 0x4713, 0x2  },
+	{ 0x4842, 0x1  },
+	{ 0x300f, 0xe  },
+	{ 0x3003, 0x3  },
+	{ 0x3003, 0x1  },
+	{ 0xffff, 0xff },
+};
+
+struct ov5642_datafmt {
+	enum v4l2_mbus_pixelcode	code;
+	enum v4l2_colorspace		colorspace;
+};
+
+struct ov5642 {
+	struct v4l2_subdev		subdev;
+	const struct ov5642_datafmt	*fmt;
+	struct v4l2_rect                crop_rect;
+
+	/* blanking information */
+	int total_width;
+	int total_height;
+};
+
+static const struct ov5642_datafmt ov5642_colour_fmts[] = {
+	{V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
+};
+
+static struct ov5642 *to_ov5642(const struct i2c_client *client)
+{
+	return container_of(i2c_get_clientdata(client), struct ov5642, subdev);
+}
+
+/* Find a data format by a pixel code in an array */
+static const struct ov5642_datafmt
+			*ov5642_find_datafmt(enum v4l2_mbus_pixelcode code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ov5642_colour_fmts); i++)
+		if (ov5642_colour_fmts[i].code == code)
+			return ov5642_colour_fmts + i;
+
+	return NULL;
+}
+
+static int reg_read(struct i2c_client *client, u16 reg, u8 *val)
+{
+	int ret;
+	/* We have 16-bit i2c addresses - care for endianess */
+	unsigned char data[2] = { reg >> 8, reg & 0xff };
+
+	ret = i2c_master_send(client, data, 2);
+	if (ret < 2) {
+		dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
+			__func__, reg);
+		return ret < 0 ? ret : -EIO;
+	}
+
+	ret = i2c_master_recv(client, val, 1);
+	if (ret < 1) {
+		dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
+				__func__, reg);
+		return ret < 0 ? ret : -EIO;
+	}
+	return 0;
+}
+
+static int reg_write(struct i2c_client *client, u16 reg, u8 val)
+{
+	int ret;
+	unsigned char data[3] = { reg >> 8, reg & 0xff, val };
+
+	ret = i2c_master_send(client, data, 3);
+	if (ret < 3) {
+		dev_err(&client->dev, "%s: i2c write error, reg: %x\n",
+			__func__, reg);
+		return ret < 0 ? ret : -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ * convenience function to write 16 bit register values that are split up
+ * into two consecutive high and low parts
+ */
+static int reg_write16(struct i2c_client *client, u16 reg, u16 val16)
+{
+	int ret;
+
+	ret = reg_write(client, reg, val16 >> 8);
+	if (ret)
+		return ret;
+	return reg_write(client, reg + 1, val16 & 0x00ff);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+	u8 val;
+
+	if (reg->reg & ~0xffff)
+		return -EINVAL;
+
+	reg->size = 1;
+
+	ret = reg_read(client, reg->reg, &val);
+	if (!ret)
+		reg->val = (__u64)val;
+
+	return ret;
+}
+
+static int ov5642_set_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->reg & ~0xffff || reg->val & ~0xff)
+		return -EINVAL;
+
+	return reg_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov5642_write_array(struct i2c_client *client,
+				struct regval_list *vals)
+{
+	while (vals->reg_num != 0xffff || vals->value != 0xff) {
+		int ret = reg_write(client, vals->reg_num, vals->value);
+		if (ret < 0)
+			return ret;
+		vals++;
+	}
+	dev_dbg(&client->dev, "Register list loaded\n");
+	return 0;
+}
+
+static int ov5642_set_resolution(struct v4l2_subdev *sd)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5642 *priv = to_ov5642(client);
+	int width = priv->crop_rect.width;
+	int height = priv->crop_rect.height;
+	int total_width = priv->total_width;
+	int total_height = priv->total_height;
+	int start_x = (OV5642_SENSOR_SIZE_X - width) / 2;
+	int start_y = (OV5642_SENSOR_SIZE_Y - height) / 2;
+	int ret;
+
+	/*
+	 * This should set the starting point for cropping.
+	 * Doesn't work so far.
+	 */
+	ret = reg_write16(client, REG_WINDOW_START_X_HIGH, start_x);
+	if (!ret)
+		ret = reg_write16(client, REG_WINDOW_START_Y_HIGH, start_y);
+	if (!ret) {
+		priv->crop_rect.left = start_x;
+		priv->crop_rect.top = start_y;
+	}
+
+	if (!ret)
+		ret = reg_write16(client, REG_WINDOW_WIDTH_HIGH, width);
+	if (!ret)
+		ret = reg_write16(client, REG_WINDOW_HEIGHT_HIGH, height);
+	if (ret)
+		return ret;
+	priv->crop_rect.width = width;
+	priv->crop_rect.height = height;
+
+	/* Set the output window size. Only 1:1 scale is supported so far. */
+	ret = reg_write16(client, REG_OUT_WIDTH_HIGH, width);
+	if (!ret)
+		ret = reg_write16(client, REG_OUT_HEIGHT_HIGH, height);
+
+	/* Total width = output size + blanking */
+	if (!ret)
+		ret = reg_write16(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width);
+	if (!ret)
+		ret = reg_write16(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height);
+
+	/* Sets the window for AWB calculations */
+	if (!ret)
+		ret = reg_write16(client, REG_AVG_WINDOW_END_X_HIGH, width);
+	if (!ret)
+		ret = reg_write16(client, REG_AVG_WINDOW_END_Y_HIGH, height);
+
+	return ret;
+}
+
+static int ov5642_try_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5642 *priv = to_ov5642(client);
+	const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code);
+
+	mf->width = priv->crop_rect.width;
+	mf->height = priv->crop_rect.height;
+
+	if (!fmt) {
+		mf->code	= ov5642_colour_fmts[0].code;
+		mf->colorspace	= ov5642_colour_fmts[0].colorspace;
+	}
+
+	mf->field	= V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static int ov5642_s_fmt(struct v4l2_subdev *sd,
+			struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5642 *priv = to_ov5642(client);
+
+	/* MIPI CSI could have changed the format, double-check */
+	if (!ov5642_find_datafmt(mf->code))
+		return -EINVAL;
+
+	ov5642_try_fmt(sd, mf);
+	priv->fmt = ov5642_find_datafmt(mf->code);
+
+	return 0;
+}
+
+static int ov5642_g_fmt(struct v4l2_subdev *sd,
+			struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5642 *priv = to_ov5642(client);
+
+	const struct ov5642_datafmt *fmt = priv->fmt;
+
+	mf->code	= fmt->code;
+	mf->colorspace	= fmt->colorspace;
+	mf->width	= priv->crop_rect.width;
+	mf->height	= priv->crop_rect.height;
+	mf->field	= V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static int ov5642_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			   enum v4l2_mbus_pixelcode *code)
+{
+	if (index >= ARRAY_SIZE(ov5642_colour_fmts))
+		return -EINVAL;
+
+	*code = ov5642_colour_fmts[index].code;
+	return 0;
+}
+
+static int ov5642_g_chip_ident(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_chip_ident *id)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+
+	if (id->match.addr != client->addr)
+		return -ENODEV;
+
+	id->ident	= V4L2_IDENT_OV5642;
+	id->revision	= 0;
+
+	return 0;
+}
+
+static int ov5642_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5642 *priv = to_ov5642(client);
+	struct v4l2_rect *rect = &a->c;
+	int ret;
+
+	v4l_bound_align_image(&rect->width, 48, OV5642_MAX_WIDTH, 1,
+			      &rect->height, 32, OV5642_MAX_HEIGHT, 1, 0);
+
+	priv->crop_rect.width	= rect->width;
+	priv->crop_rect.height	= rect->height;
+	priv->total_width	= rect->width + BLANKING_EXTRA_WIDTH;
+	priv->total_height	= max_t(int, rect->height +
+							BLANKING_EXTRA_HEIGHT,
+							BLANKING_MIN_HEIGHT);
+	priv->crop_rect.width		= rect->width;
+	priv->crop_rect.height		= rect->height;
+
+	ret = ov5642_write_array(client, ov5642_default_regs_init);
+	if (!ret)
+		ret = ov5642_set_resolution(sd);
+	if (!ret)
+		ret = ov5642_write_array(client, ov5642_default_regs_finalise);
+
+	return ret;
+}
+
+static int ov5642_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5642 *priv = to_ov5642(client);
+	struct v4l2_rect *rect = &a->c;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	*rect = priv->crop_rect;
+
+	return 0;
+}
+
+static int ov5642_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	a->bounds.left			= 0;
+	a->bounds.top			= 0;
+	a->bounds.width			= OV5642_MAX_WIDTH;
+	a->bounds.height		= OV5642_MAX_HEIGHT;
+	a->defrect			= a->bounds;
+	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int ov5642_g_mbus_config(struct v4l2_subdev *sd,
+				struct v4l2_mbus_config *cfg)
+{
+	cfg->type = V4L2_MBUS_CSI2;
+	cfg->flags = V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
+					V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+
+	return 0;
+}
+
+static int ov5642_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	int ret;
+
+	if (!on)
+		return soc_camera_power_off(&client->dev, icl);
+
+	ret = soc_camera_power_on(&client->dev, icl);
+	if (ret < 0)
+		return ret;
+
+	ret = ov5642_write_array(client, ov5642_default_regs_init);
+	if (!ret)
+		ret = ov5642_set_resolution(sd);
+	if (!ret)
+		ret = ov5642_write_array(client, ov5642_default_regs_finalise);
+
+	return ret;
+}
+
+static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = {
+	.s_mbus_fmt	= ov5642_s_fmt,
+	.g_mbus_fmt	= ov5642_g_fmt,
+	.try_mbus_fmt	= ov5642_try_fmt,
+	.enum_mbus_fmt	= ov5642_enum_fmt,
+	.s_crop		= ov5642_s_crop,
+	.g_crop		= ov5642_g_crop,
+	.cropcap	= ov5642_cropcap,
+	.g_mbus_config	= ov5642_g_mbus_config,
+};
+
+static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = {
+	.s_power	= ov5642_s_power,
+	.g_chip_ident	= ov5642_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register	= ov5642_get_register,
+	.s_register	= ov5642_set_register,
+#endif
+};
+
+static struct v4l2_subdev_ops ov5642_subdev_ops = {
+	.core	= &ov5642_subdev_core_ops,
+	.video	= &ov5642_subdev_video_ops,
+};
+
+static int ov5642_video_probe(struct i2c_client *client)
+{
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	int ret;
+	u8 id_high, id_low;
+	u16 id;
+
+	ret = ov5642_s_power(subdev, 1);
+	if (ret < 0)
+		return ret;
+
+	/* Read sensor Model ID */
+	ret = reg_read(client, REG_CHIP_ID_HIGH, &id_high);
+	if (ret < 0)
+		goto done;
+
+	id = id_high << 8;
+
+	ret = reg_read(client, REG_CHIP_ID_LOW, &id_low);
+	if (ret < 0)
+		goto done;
+
+	id |= id_low;
+
+	dev_info(&client->dev, "Chip ID 0x%04x detected\n", id);
+
+	if (id != 0x5642) {
+		ret = -ENODEV;
+		goto done;
+	}
+
+	ret = 0;
+
+done:
+	ov5642_s_power(subdev, 0);
+	return ret;
+}
+
+static int ov5642_probe(struct i2c_client *client,
+			const struct i2c_device_id *did)
+{
+	struct ov5642 *priv;
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	int ret;
+
+	if (!icl) {
+		dev_err(&client->dev, "OV5642: missing platform data!\n");
+		return -EINVAL;
+	}
+
+	priv = kzalloc(sizeof(struct ov5642), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops);
+
+	priv->fmt		= &ov5642_colour_fmts[0];
+
+	priv->crop_rect.width	= OV5642_DEFAULT_WIDTH;
+	priv->crop_rect.height	= OV5642_DEFAULT_HEIGHT;
+	priv->crop_rect.left	= (OV5642_MAX_WIDTH - OV5642_DEFAULT_WIDTH) / 2;
+	priv->crop_rect.top	= (OV5642_MAX_HEIGHT - OV5642_DEFAULT_HEIGHT) / 2;
+	priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH;
+	priv->total_height = BLANKING_MIN_HEIGHT;
+
+	ret = ov5642_video_probe(client);
+	if (ret < 0)
+		goto error;
+
+	return 0;
+
+error:
+	kfree(priv);
+	return ret;
+}
+
+static int ov5642_remove(struct i2c_client *client)
+{
+	struct ov5642 *priv = to_ov5642(client);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	if (icl->free_bus)
+		icl->free_bus(icl);
+	kfree(priv);
+
+	return 0;
+}
+
+static const struct i2c_device_id ov5642_id[] = {
+	{ "ov5642", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ov5642_id);
+
+static struct i2c_driver ov5642_i2c_driver = {
+	.driver = {
+		.name = "ov5642",
+	},
+	.probe		= ov5642_probe,
+	.remove		= ov5642_remove,
+	.id_table	= ov5642_id,
+};
+
+module_i2c_driver(ov5642_i2c_driver);
+
+MODULE_DESCRIPTION("Omnivision OV5642 Camera driver");
+MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c
new file mode 100644
index 0000000..65b031f
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov6650.c
@@ -0,0 +1,1069 @@
+/*
+ * V4L2 SoC Camera driver for OmniVision OV6650 Camera Sensor
+ *
+ * Copyright (C) 2010 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
+ *
+ * Based on OmniVision OV96xx Camera Driver
+ * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on ov772x camera driver:
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov7670 and soc_camera_platform driver,
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * Hardware specific bits initialy based on former work by Matt Callow
+ * drivers/media/video/omap/sensor_ov6650.c
+ * Copyright (C) 2006 Matt Callow
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/module.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+/* Register definitions */
+#define REG_GAIN		0x00	/* range 00 - 3F */
+#define REG_BLUE		0x01
+#define REG_RED			0x02
+#define REG_SAT			0x03	/* [7:4] saturation [0:3] reserved */
+#define REG_HUE			0x04	/* [7:6] rsrvd [5] hue en [4:0] hue */
+
+#define REG_BRT			0x06
+
+#define REG_PIDH		0x0a
+#define REG_PIDL		0x0b
+
+#define REG_AECH		0x10
+#define REG_CLKRC		0x11	/* Data Format and Internal Clock */
+					/* [7:6] Input system clock (MHz)*/
+					/*   00=8, 01=12, 10=16, 11=24 */
+					/* [5:0]: Internal Clock Pre-Scaler */
+#define REG_COMA		0x12	/* [7] Reset */
+#define REG_COMB		0x13
+#define REG_COMC		0x14
+#define REG_COMD		0x15
+#define REG_COML		0x16
+#define REG_HSTRT		0x17
+#define REG_HSTOP		0x18
+#define REG_VSTRT		0x19
+#define REG_VSTOP		0x1a
+#define REG_PSHFT		0x1b
+#define REG_MIDH		0x1c
+#define REG_MIDL		0x1d
+#define REG_HSYNS		0x1e
+#define REG_HSYNE		0x1f
+#define REG_COME		0x20
+#define REG_YOFF		0x21
+#define REG_UOFF		0x22
+#define REG_VOFF		0x23
+#define REG_AEW			0x24
+#define REG_AEB			0x25
+#define REG_COMF		0x26
+#define REG_COMG		0x27
+#define REG_COMH		0x28
+#define REG_COMI		0x29
+
+#define REG_FRARL		0x2b
+#define REG_COMJ		0x2c
+#define REG_COMK		0x2d
+#define REG_AVGY		0x2e
+#define REG_REF0		0x2f
+#define REG_REF1		0x30
+#define REG_REF2		0x31
+#define REG_FRAJH		0x32
+#define REG_FRAJL		0x33
+#define REG_FACT		0x34
+#define REG_L1AEC		0x35
+#define REG_AVGU		0x36
+#define REG_AVGV		0x37
+
+#define REG_SPCB		0x60
+#define REG_SPCC		0x61
+#define REG_GAM1		0x62
+#define REG_GAM2		0x63
+#define REG_GAM3		0x64
+#define REG_SPCD		0x65
+
+#define REG_SPCE		0x68
+#define REG_ADCL		0x69
+
+#define REG_RMCO		0x6c
+#define REG_GMCO		0x6d
+#define REG_BMCO		0x6e
+
+
+/* Register bits, values, etc. */
+#define OV6650_PIDH		0x66	/* high byte of product ID number */
+#define OV6650_PIDL		0x50	/* low byte of product ID number */
+#define OV6650_MIDH		0x7F	/* high byte of mfg ID */
+#define OV6650_MIDL		0xA2	/* low byte of mfg ID */
+
+#define DEF_GAIN		0x00
+#define DEF_BLUE		0x80
+#define DEF_RED			0x80
+
+#define SAT_SHIFT		4
+#define SAT_MASK		(0xf << SAT_SHIFT)
+#define SET_SAT(x)		(((x) << SAT_SHIFT) & SAT_MASK)
+
+#define HUE_EN			BIT(5)
+#define HUE_MASK		0x1f
+#define DEF_HUE			0x10
+#define SET_HUE(x)		(HUE_EN | ((x) & HUE_MASK))
+
+#define DEF_AECH		0x4D
+
+#define CLKRC_6MHz		0x00
+#define CLKRC_12MHz		0x40
+#define CLKRC_16MHz		0x80
+#define CLKRC_24MHz		0xc0
+#define CLKRC_DIV_MASK		0x3f
+#define GET_CLKRC_DIV(x)	(((x) & CLKRC_DIV_MASK) + 1)
+
+#define COMA_RESET		BIT(7)
+#define COMA_QCIF		BIT(5)
+#define COMA_RAW_RGB		BIT(4)
+#define COMA_RGB		BIT(3)
+#define COMA_BW			BIT(2)
+#define COMA_WORD_SWAP		BIT(1)
+#define COMA_BYTE_SWAP		BIT(0)
+#define DEF_COMA		0x00
+
+#define COMB_FLIP_V		BIT(7)
+#define COMB_FLIP_H		BIT(5)
+#define COMB_BAND_FILTER	BIT(4)
+#define COMB_AWB		BIT(2)
+#define COMB_AGC		BIT(1)
+#define COMB_AEC		BIT(0)
+#define DEF_COMB		0x5f
+
+#define COML_ONE_CHANNEL	BIT(7)
+
+#define DEF_HSTRT		0x24
+#define DEF_HSTOP		0xd4
+#define DEF_VSTRT		0x04
+#define DEF_VSTOP		0x94
+
+#define COMF_HREF_LOW		BIT(4)
+
+#define COMJ_PCLK_RISING	BIT(4)
+#define COMJ_VSYNC_HIGH		BIT(0)
+
+/* supported resolutions */
+#define W_QCIF			(DEF_HSTOP - DEF_HSTRT)
+#define W_CIF			(W_QCIF << 1)
+#define H_QCIF			(DEF_VSTOP - DEF_VSTRT)
+#define H_CIF			(H_QCIF << 1)
+
+#define FRAME_RATE_MAX		30
+
+
+struct ov6650_reg {
+	u8	reg;
+	u8	val;
+};
+
+struct ov6650 {
+	struct v4l2_subdev	subdev;
+	struct v4l2_ctrl_handler hdl;
+	struct {
+		/* exposure/autoexposure cluster */
+		struct v4l2_ctrl *autoexposure;
+		struct v4l2_ctrl *exposure;
+	};
+	struct {
+		/* gain/autogain cluster */
+		struct v4l2_ctrl *autogain;
+		struct v4l2_ctrl *gain;
+	};
+	struct {
+		/* blue/red/autowhitebalance cluster */
+		struct v4l2_ctrl *autowb;
+		struct v4l2_ctrl *blue;
+		struct v4l2_ctrl *red;
+	};
+	bool			half_scale;	/* scale down output by 2 */
+	struct v4l2_rect	rect;		/* sensor cropping window */
+	unsigned long		pclk_limit;	/* from host */
+	unsigned long		pclk_max;	/* from resolution and format */
+	struct v4l2_fract	tpf;		/* as requested with s_parm */
+	enum v4l2_mbus_pixelcode code;
+	enum v4l2_colorspace	colorspace;
+};
+
+
+static enum v4l2_mbus_pixelcode ov6650_codes[] = {
+	V4L2_MBUS_FMT_YUYV8_2X8,
+	V4L2_MBUS_FMT_UYVY8_2X8,
+	V4L2_MBUS_FMT_YVYU8_2X8,
+	V4L2_MBUS_FMT_VYUY8_2X8,
+	V4L2_MBUS_FMT_SBGGR8_1X8,
+	V4L2_MBUS_FMT_Y8_1X8,
+};
+
+/* read a register */
+static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val)
+{
+	int ret;
+	u8 data = reg;
+	struct i2c_msg msg = {
+		.addr	= client->addr,
+		.flags	= 0,
+		.len	= 1,
+		.buf	= &data,
+	};
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret < 0)
+		goto err;
+
+	msg.flags = I2C_M_RD;
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret < 0)
+		goto err;
+
+	*val = data;
+	return 0;
+
+err:
+	dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg);
+	return ret;
+}
+
+/* write a register */
+static int ov6650_reg_write(struct i2c_client *client, u8 reg, u8 val)
+{
+	int ret;
+	unsigned char data[2] = { reg, val };
+	struct i2c_msg msg = {
+		.addr	= client->addr,
+		.flags	= 0,
+		.len	= 2,
+		.buf	= data,
+	};
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	udelay(100);
+
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg);
+		return ret;
+	}
+	return 0;
+}
+
+
+/* Read a register, alter its bits, write it back */
+static int ov6650_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 mask)
+{
+	u8 val;
+	int ret;
+
+	ret = ov6650_reg_read(client, reg, &val);
+	if (ret) {
+		dev_err(&client->dev,
+			"[Read]-Modify-Write of register 0x%02x failed!\n",
+			reg);
+		return ret;
+	}
+
+	val &= ~mask;
+	val |= set;
+
+	ret = ov6650_reg_write(client, reg, val);
+	if (ret)
+		dev_err(&client->dev,
+			"Read-Modify-[Write] of register 0x%02x failed!\n",
+			reg);
+
+	return ret;
+}
+
+static struct ov6650 *to_ov6650(const struct i2c_client *client)
+{
+	return container_of(i2c_get_clientdata(client), struct ov6650, subdev);
+}
+
+/* Start/Stop streaming from the device */
+static int ov6650_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	return 0;
+}
+
+/* Get status of additional camera capabilities */
+static int ov6550_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl);
+	struct v4l2_subdev *sd = &priv->subdev;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	uint8_t reg, reg2;
+	int ret;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTOGAIN:
+		ret = ov6650_reg_read(client, REG_GAIN, &reg);
+		if (!ret)
+			priv->gain->val = reg;
+		return ret;
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		ret = ov6650_reg_read(client, REG_BLUE, &reg);
+		if (!ret)
+			ret = ov6650_reg_read(client, REG_RED, &reg2);
+		if (!ret) {
+			priv->blue->val = reg;
+			priv->red->val = reg2;
+		}
+		return ret;
+	case V4L2_CID_EXPOSURE_AUTO:
+		ret = ov6650_reg_read(client, REG_AECH, &reg);
+		if (!ret)
+			priv->exposure->val = reg;
+		return ret;
+	}
+	return -EINVAL;
+}
+
+/* Set status of additional camera capabilities */
+static int ov6550_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl);
+	struct v4l2_subdev *sd = &priv->subdev;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTOGAIN:
+		ret = ov6650_reg_rmw(client, REG_COMB,
+				ctrl->val ? COMB_AGC : 0, COMB_AGC);
+		if (!ret && !ctrl->val)
+			ret = ov6650_reg_write(client, REG_GAIN, priv->gain->val);
+		return ret;
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		ret = ov6650_reg_rmw(client, REG_COMB,
+				ctrl->val ? COMB_AWB : 0, COMB_AWB);
+		if (!ret && !ctrl->val) {
+			ret = ov6650_reg_write(client, REG_BLUE, priv->blue->val);
+			if (!ret)
+				ret = ov6650_reg_write(client, REG_RED,
+							priv->red->val);
+		}
+		return ret;
+	case V4L2_CID_SATURATION:
+		return ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->val),
+				SAT_MASK);
+	case V4L2_CID_HUE:
+		return ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->val),
+				HUE_MASK);
+	case V4L2_CID_BRIGHTNESS:
+		return ov6650_reg_write(client, REG_BRT, ctrl->val);
+	case V4L2_CID_EXPOSURE_AUTO:
+		ret = ov6650_reg_rmw(client, REG_COMB, ctrl->val ==
+				V4L2_EXPOSURE_AUTO ? COMB_AEC : 0, COMB_AEC);
+		if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL)
+			ret = ov6650_reg_write(client, REG_AECH,
+						priv->exposure->val);
+		return ret;
+	case V4L2_CID_GAMMA:
+		return ov6650_reg_write(client, REG_GAM1, ctrl->val);
+	case V4L2_CID_VFLIP:
+		return ov6650_reg_rmw(client, REG_COMB,
+				ctrl->val ? COMB_FLIP_V : 0, COMB_FLIP_V);
+	case V4L2_CID_HFLIP:
+		return ov6650_reg_rmw(client, REG_COMB,
+				ctrl->val ? COMB_FLIP_H : 0, COMB_FLIP_H);
+	}
+
+	return -EINVAL;
+}
+
+/* Get chip identification */
+static int ov6650_g_chip_ident(struct v4l2_subdev *sd,
+				struct v4l2_dbg_chip_ident *id)
+{
+	id->ident	= V4L2_IDENT_OV6650;
+	id->revision	= 0;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov6650_get_register(struct v4l2_subdev *sd,
+				struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+	u8 val;
+
+	if (reg->reg & ~0xff)
+		return -EINVAL;
+
+	reg->size = 1;
+
+	ret = ov6650_reg_read(client, reg->reg, &val);
+	if (!ret)
+		reg->val = (__u64)val;
+
+	return ret;
+}
+
+static int ov6650_set_register(struct v4l2_subdev *sd,
+				struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->reg & ~0xff || reg->val & ~0xff)
+		return -EINVAL;
+
+	return ov6650_reg_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov6650_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	return soc_camera_set_power(&client->dev, icl, on);
+}
+
+static int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov6650 *priv = to_ov6650(client);
+
+	a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->c = priv->rect;
+
+	return 0;
+}
+
+static int ov6650_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov6650 *priv = to_ov6650(client);
+	struct v4l2_rect *rect = &a->c;
+	int ret;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	rect->left   = ALIGN(rect->left,   2);
+	rect->width  = ALIGN(rect->width,  2);
+	rect->top    = ALIGN(rect->top,    2);
+	rect->height = ALIGN(rect->height, 2);
+	soc_camera_limit_side(&rect->left, &rect->width,
+			DEF_HSTRT << 1, 2, W_CIF);
+	soc_camera_limit_side(&rect->top, &rect->height,
+			DEF_VSTRT << 1, 2, H_CIF);
+
+	ret = ov6650_reg_write(client, REG_HSTRT, rect->left >> 1);
+	if (!ret) {
+		priv->rect.left = rect->left;
+		ret = ov6650_reg_write(client, REG_HSTOP,
+				(rect->left + rect->width) >> 1);
+	}
+	if (!ret) {
+		priv->rect.width = rect->width;
+		ret = ov6650_reg_write(client, REG_VSTRT, rect->top >> 1);
+	}
+	if (!ret) {
+		priv->rect.top = rect->top;
+		ret = ov6650_reg_write(client, REG_VSTOP,
+				(rect->top + rect->height) >> 1);
+	}
+	if (!ret)
+		priv->rect.height = rect->height;
+
+	return ret;
+}
+
+static int ov6650_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	a->bounds.left			= DEF_HSTRT << 1;
+	a->bounds.top			= DEF_VSTRT << 1;
+	a->bounds.width			= W_CIF;
+	a->bounds.height		= H_CIF;
+	a->defrect			= a->bounds;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int ov6650_g_fmt(struct v4l2_subdev *sd,
+			 struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov6650 *priv = to_ov6650(client);
+
+	mf->width	= priv->rect.width >> priv->half_scale;
+	mf->height	= priv->rect.height >> priv->half_scale;
+	mf->code	= priv->code;
+	mf->colorspace	= priv->colorspace;
+	mf->field	= V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static bool is_unscaled_ok(int width, int height, struct v4l2_rect *rect)
+{
+	return width > rect->width >> 1 || height > rect->height >> 1;
+}
+
+static u8 to_clkrc(struct v4l2_fract *timeperframe,
+		unsigned long pclk_limit, unsigned long pclk_max)
+{
+	unsigned long pclk;
+
+	if (timeperframe->numerator && timeperframe->denominator)
+		pclk = pclk_max * timeperframe->denominator /
+				(FRAME_RATE_MAX * timeperframe->numerator);
+	else
+		pclk = pclk_max;
+
+	if (pclk_limit && pclk_limit < pclk)
+		pclk = pclk_limit;
+
+	return (pclk_max - 1) / pclk;
+}
+
+/* set the format we will capture in */
+static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd);
+	struct soc_camera_sense *sense = icd->sense;
+	struct ov6650 *priv = to_ov6650(client);
+	bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect);
+	struct v4l2_crop a = {
+		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+		.c = {
+			.left	= priv->rect.left + (priv->rect.width >> 1) -
+					(mf->width >> (1 - half_scale)),
+			.top	= priv->rect.top + (priv->rect.height >> 1) -
+					(mf->height >> (1 - half_scale)),
+			.width	= mf->width << half_scale,
+			.height	= mf->height << half_scale,
+		},
+	};
+	enum v4l2_mbus_pixelcode code = mf->code;
+	unsigned long mclk, pclk;
+	u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask, clkrc;
+	int ret;
+
+	/* select color matrix configuration for given color encoding */
+	switch (code) {
+	case V4L2_MBUS_FMT_Y8_1X8:
+		dev_dbg(&client->dev, "pixel format GREY8_1X8\n");
+		coma_mask |= COMA_RGB | COMA_WORD_SWAP | COMA_BYTE_SWAP;
+		coma_set |= COMA_BW;
+		break;
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+		dev_dbg(&client->dev, "pixel format YUYV8_2X8_LE\n");
+		coma_mask |= COMA_RGB | COMA_BW | COMA_BYTE_SWAP;
+		coma_set |= COMA_WORD_SWAP;
+		break;
+	case V4L2_MBUS_FMT_YVYU8_2X8:
+		dev_dbg(&client->dev, "pixel format YVYU8_2X8_LE (untested)\n");
+		coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP |
+				COMA_BYTE_SWAP;
+		break;
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		dev_dbg(&client->dev, "pixel format YUYV8_2X8_BE\n");
+		if (half_scale) {
+			coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP;
+			coma_set |= COMA_BYTE_SWAP;
+		} else {
+			coma_mask |= COMA_RGB | COMA_BW;
+			coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP;
+		}
+		break;
+	case V4L2_MBUS_FMT_VYUY8_2X8:
+		dev_dbg(&client->dev, "pixel format YVYU8_2X8_BE (untested)\n");
+		if (half_scale) {
+			coma_mask |= COMA_RGB | COMA_BW;
+			coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP;
+		} else {
+			coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP;
+			coma_set |= COMA_BYTE_SWAP;
+		}
+		break;
+	case V4L2_MBUS_FMT_SBGGR8_1X8:
+		dev_dbg(&client->dev, "pixel format SBGGR8_1X8 (untested)\n");
+		coma_mask |= COMA_BW | COMA_BYTE_SWAP | COMA_WORD_SWAP;
+		coma_set |= COMA_RAW_RGB | COMA_RGB;
+		break;
+	default:
+		dev_err(&client->dev, "Pixel format not handled: 0x%x\n", code);
+		return -EINVAL;
+	}
+	priv->code = code;
+
+	if (code == V4L2_MBUS_FMT_Y8_1X8 ||
+			code == V4L2_MBUS_FMT_SBGGR8_1X8) {
+		coml_mask = COML_ONE_CHANNEL;
+		coml_set = 0;
+		priv->pclk_max = 4000000;
+	} else {
+		coml_mask = 0;
+		coml_set = COML_ONE_CHANNEL;
+		priv->pclk_max = 8000000;
+	}
+
+	if (code == V4L2_MBUS_FMT_SBGGR8_1X8)
+		priv->colorspace = V4L2_COLORSPACE_SRGB;
+	else if (code != 0)
+		priv->colorspace = V4L2_COLORSPACE_JPEG;
+
+	if (half_scale) {
+		dev_dbg(&client->dev, "max resolution: QCIF\n");
+		coma_set |= COMA_QCIF;
+		priv->pclk_max /= 2;
+	} else {
+		dev_dbg(&client->dev, "max resolution: CIF\n");
+		coma_mask |= COMA_QCIF;
+	}
+	priv->half_scale = half_scale;
+
+	if (sense) {
+		if (sense->master_clock == 8000000) {
+			dev_dbg(&client->dev, "8MHz input clock\n");
+			clkrc = CLKRC_6MHz;
+		} else if (sense->master_clock == 12000000) {
+			dev_dbg(&client->dev, "12MHz input clock\n");
+			clkrc = CLKRC_12MHz;
+		} else if (sense->master_clock == 16000000) {
+			dev_dbg(&client->dev, "16MHz input clock\n");
+			clkrc = CLKRC_16MHz;
+		} else if (sense->master_clock == 24000000) {
+			dev_dbg(&client->dev, "24MHz input clock\n");
+			clkrc = CLKRC_24MHz;
+		} else {
+			dev_err(&client->dev,
+				"unsupported input clock, check platform data\n");
+			return -EINVAL;
+		}
+		mclk = sense->master_clock;
+		priv->pclk_limit = sense->pixel_clock_max;
+	} else {
+		clkrc = CLKRC_24MHz;
+		mclk = 24000000;
+		priv->pclk_limit = 0;
+		dev_dbg(&client->dev, "using default 24MHz input clock\n");
+	}
+
+	clkrc |= to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max);
+
+	pclk = priv->pclk_max / GET_CLKRC_DIV(clkrc);
+	dev_dbg(&client->dev, "pixel clock divider: %ld.%ld\n",
+			mclk / pclk, 10 * mclk % pclk / pclk);
+
+	ret = ov6650_s_crop(sd, &a);
+	if (!ret)
+		ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask);
+	if (!ret)
+		ret = ov6650_reg_write(client, REG_CLKRC, clkrc);
+	if (!ret)
+		ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask);
+
+	if (!ret) {
+		mf->colorspace	= priv->colorspace;
+		mf->width = priv->rect.width >> half_scale;
+		mf->height = priv->rect.height >> half_scale;
+	}
+
+	return ret;
+}
+
+static int ov6650_try_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov6650 *priv = to_ov6650(client);
+
+	if (is_unscaled_ok(mf->width, mf->height, &priv->rect))
+		v4l_bound_align_image(&mf->width, 2, W_CIF, 1,
+				&mf->height, 2, H_CIF, 1, 0);
+
+	mf->field = V4L2_FIELD_NONE;
+
+	switch (mf->code) {
+	case V4L2_MBUS_FMT_Y10_1X10:
+		mf->code = V4L2_MBUS_FMT_Y8_1X8;
+	case V4L2_MBUS_FMT_Y8_1X8:
+	case V4L2_MBUS_FMT_YVYU8_2X8:
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+	case V4L2_MBUS_FMT_VYUY8_2X8:
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		mf->colorspace = V4L2_COLORSPACE_JPEG;
+		break;
+	default:
+		mf->code = V4L2_MBUS_FMT_SBGGR8_1X8;
+	case V4L2_MBUS_FMT_SBGGR8_1X8:
+		mf->colorspace = V4L2_COLORSPACE_SRGB;
+		break;
+	}
+
+	return 0;
+}
+
+static int ov6650_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			   enum v4l2_mbus_pixelcode *code)
+{
+	if (index >= ARRAY_SIZE(ov6650_codes))
+		return -EINVAL;
+
+	*code = ov6650_codes[index];
+	return 0;
+}
+
+static int ov6650_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov6650 *priv = to_ov6650(client);
+	struct v4l2_captureparm *cp = &parms->parm.capture;
+
+	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	memset(cp, 0, sizeof(*cp));
+	cp->capability = V4L2_CAP_TIMEPERFRAME;
+	cp->timeperframe.numerator = GET_CLKRC_DIV(to_clkrc(&priv->tpf,
+			priv->pclk_limit, priv->pclk_max));
+	cp->timeperframe.denominator = FRAME_RATE_MAX;
+
+	dev_dbg(&client->dev, "Frame interval: %u/%u s\n",
+		cp->timeperframe.numerator, cp->timeperframe.denominator);
+
+	return 0;
+}
+
+static int ov6650_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov6650 *priv = to_ov6650(client);
+	struct v4l2_captureparm *cp = &parms->parm.capture;
+	struct v4l2_fract *tpf = &cp->timeperframe;
+	int div, ret;
+	u8 clkrc;
+
+	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (cp->extendedmode != 0)
+		return -EINVAL;
+
+	if (tpf->numerator == 0 || tpf->denominator == 0)
+		div = 1;  /* Reset to full rate */
+	else
+		div = (tpf->numerator * FRAME_RATE_MAX) / tpf->denominator;
+
+	if (div == 0)
+		div = 1;
+	else if (div > GET_CLKRC_DIV(CLKRC_DIV_MASK))
+		div = GET_CLKRC_DIV(CLKRC_DIV_MASK);
+
+	/*
+	 * Keep result to be used as tpf limit
+	 * for subseqent clock divider calculations
+	 */
+	priv->tpf.numerator = div;
+	priv->tpf.denominator = FRAME_RATE_MAX;
+
+	clkrc = to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max);
+
+	ret = ov6650_reg_rmw(client, REG_CLKRC, clkrc, CLKRC_DIV_MASK);
+	if (!ret) {
+		tpf->numerator = GET_CLKRC_DIV(clkrc);
+		tpf->denominator = FRAME_RATE_MAX;
+	}
+
+	return ret;
+}
+
+/* Soft reset the camera. This has nothing to do with the RESET pin! */
+static int ov6650_reset(struct i2c_client *client)
+{
+	int ret;
+
+	dev_dbg(&client->dev, "reset\n");
+
+	ret = ov6650_reg_rmw(client, REG_COMA, COMA_RESET, 0);
+	if (ret)
+		dev_err(&client->dev,
+			"An error occurred while entering soft reset!\n");
+
+	return ret;
+}
+
+/* program default register values */
+static int ov6650_prog_dflt(struct i2c_client *client)
+{
+	int ret;
+
+	dev_dbg(&client->dev, "initializing\n");
+
+	ret = ov6650_reg_write(client, REG_COMA, 0);	/* ~COMA_RESET */
+	if (!ret)
+		ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_BAND_FILTER);
+
+	return ret;
+}
+
+static int ov6650_video_probe(struct i2c_client *client)
+{
+	struct ov6650 *priv = to_ov6650(client);
+	u8		pidh, pidl, midh, midl;
+	int		ret;
+
+	ret = ov6650_s_power(&priv->subdev, 1);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * check and show product ID and manufacturer ID
+	 */
+	ret = ov6650_reg_read(client, REG_PIDH, &pidh);
+	if (!ret)
+		ret = ov6650_reg_read(client, REG_PIDL, &pidl);
+	if (!ret)
+		ret = ov6650_reg_read(client, REG_MIDH, &midh);
+	if (!ret)
+		ret = ov6650_reg_read(client, REG_MIDL, &midl);
+
+	if (ret)
+		goto done;
+
+	if ((pidh != OV6650_PIDH) || (pidl != OV6650_PIDL)) {
+		dev_err(&client->dev, "Product ID error 0x%02x:0x%02x\n",
+				pidh, pidl);
+		ret = -ENODEV;
+		goto done;
+	}
+
+	dev_info(&client->dev,
+		"ov6650 Product ID 0x%02x:0x%02x Manufacturer ID 0x%02x:0x%02x\n",
+		pidh, pidl, midh, midl);
+
+	ret = ov6650_reset(client);
+	if (!ret)
+		ret = ov6650_prog_dflt(client);
+	if (!ret)
+		ret = v4l2_ctrl_handler_setup(&priv->hdl);
+
+done:
+	ov6650_s_power(&priv->subdev, 0);
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops ov6550_ctrl_ops = {
+	.g_volatile_ctrl = ov6550_g_volatile_ctrl,
+	.s_ctrl = ov6550_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops ov6650_core_ops = {
+	.g_chip_ident		= ov6650_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register		= ov6650_get_register,
+	.s_register		= ov6650_set_register,
+#endif
+	.s_power		= ov6650_s_power,
+};
+
+/* Request bus settings on camera side */
+static int ov6650_g_mbus_config(struct v4l2_subdev *sd,
+				struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	cfg->flags = V4L2_MBUS_MASTER |
+		V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
+		V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
+		V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
+		V4L2_MBUS_DATA_ACTIVE_HIGH;
+	cfg->type = V4L2_MBUS_PARALLEL;
+	cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+	return 0;
+}
+
+/* Alter bus settings on camera side */
+static int ov6650_s_mbus_config(struct v4l2_subdev *sd,
+				const struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	unsigned long flags = soc_camera_apply_board_flags(icl, cfg);
+	int ret;
+
+	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+		ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0);
+	else
+		ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING);
+	if (ret)
+		return ret;
+
+	if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+		ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0);
+	else
+		ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW);
+	if (ret)
+		return ret;
+
+	if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
+		ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0);
+	else
+		ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH);
+
+	return ret;
+}
+
+static struct v4l2_subdev_video_ops ov6650_video_ops = {
+	.s_stream	= ov6650_s_stream,
+	.g_mbus_fmt	= ov6650_g_fmt,
+	.s_mbus_fmt	= ov6650_s_fmt,
+	.try_mbus_fmt	= ov6650_try_fmt,
+	.enum_mbus_fmt	= ov6650_enum_fmt,
+	.cropcap	= ov6650_cropcap,
+	.g_crop		= ov6650_g_crop,
+	.s_crop		= ov6650_s_crop,
+	.g_parm		= ov6650_g_parm,
+	.s_parm		= ov6650_s_parm,
+	.g_mbus_config	= ov6650_g_mbus_config,
+	.s_mbus_config	= ov6650_s_mbus_config,
+};
+
+static struct v4l2_subdev_ops ov6650_subdev_ops = {
+	.core	= &ov6650_core_ops,
+	.video	= &ov6650_video_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+static int ov6650_probe(struct i2c_client *client,
+			const struct i2c_device_id *did)
+{
+	struct ov6650 *priv;
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	int ret;
+
+	if (!icl) {
+		dev_err(&client->dev, "Missing platform_data for driver\n");
+		return -EINVAL;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&client->dev,
+			"Failed to allocate memory for private data!\n");
+		return -ENOMEM;
+	}
+
+	v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops);
+	v4l2_ctrl_handler_init(&priv->hdl, 13);
+	v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+			V4L2_CID_HFLIP, 0, 1, 1, 0);
+	priv->autogain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+	priv->gain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+			V4L2_CID_GAIN, 0, 0x3f, 1, DEF_GAIN);
+	priv->autowb = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+			V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
+	priv->blue = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+			V4L2_CID_BLUE_BALANCE, 0, 0xff, 1, DEF_BLUE);
+	priv->red = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+			V4L2_CID_RED_BALANCE, 0, 0xff, 1, DEF_RED);
+	v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 0xf, 1, 0x8);
+	v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+			V4L2_CID_HUE, 0, HUE_MASK, 1, DEF_HUE);
+	v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x80);
+	priv->autoexposure = v4l2_ctrl_new_std_menu(&priv->hdl,
+			&ov6550_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
+			V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO);
+	priv->exposure = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+			V4L2_CID_EXPOSURE, 0, 0xff, 1, DEF_AECH);
+	v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+			V4L2_CID_GAMMA, 0, 0xff, 1, 0x12);
+
+	priv->subdev.ctrl_handler = &priv->hdl;
+	if (priv->hdl.error) {
+		int err = priv->hdl.error;
+
+		kfree(priv);
+		return err;
+	}
+	v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true);
+	v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true);
+	v4l2_ctrl_auto_cluster(2, &priv->autoexposure,
+				V4L2_EXPOSURE_MANUAL, true);
+
+	priv->rect.left	  = DEF_HSTRT << 1;
+	priv->rect.top	  = DEF_VSTRT << 1;
+	priv->rect.width  = W_CIF;
+	priv->rect.height = H_CIF;
+	priv->half_scale  = false;
+	priv->code	  = V4L2_MBUS_FMT_YUYV8_2X8;
+	priv->colorspace  = V4L2_COLORSPACE_JPEG;
+
+	ret = ov6650_video_probe(client);
+	if (ret) {
+		v4l2_ctrl_handler_free(&priv->hdl);
+		kfree(priv);
+	}
+
+	return ret;
+}
+
+static int ov6650_remove(struct i2c_client *client)
+{
+	struct ov6650 *priv = to_ov6650(client);
+
+	v4l2_device_unregister_subdev(&priv->subdev);
+	v4l2_ctrl_handler_free(&priv->hdl);
+	kfree(priv);
+	return 0;
+}
+
+static const struct i2c_device_id ov6650_id[] = {
+	{ "ov6650", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ov6650_id);
+
+static struct i2c_driver ov6650_i2c_driver = {
+	.driver = {
+		.name = "ov6650",
+	},
+	.probe    = ov6650_probe,
+	.remove   = ov6650_remove,
+	.id_table = ov6650_id,
+};
+
+module_i2c_driver(ov6650_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650");
+MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c
new file mode 100644
index 0000000..e4a1075
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov772x.c
@@ -0,0 +1,1137 @@
+/*
+ * ov772x Camera Driver
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov7670 and soc_camera_platform driver,
+ *
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/ov772x.h>
+#include <media/soc_camera.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
+
+/*
+ * register offset
+ */
+#define GAIN        0x00 /* AGC - Gain control gain setting */
+#define BLUE        0x01 /* AWB - Blue channel gain setting */
+#define RED         0x02 /* AWB - Red   channel gain setting */
+#define GREEN       0x03 /* AWB - Green channel gain setting */
+#define COM1        0x04 /* Common control 1 */
+#define BAVG        0x05 /* U/B Average Level */
+#define GAVG        0x06 /* Y/Gb Average Level */
+#define RAVG        0x07 /* V/R Average Level */
+#define AECH        0x08 /* Exposure Value - AEC MSBs */
+#define COM2        0x09 /* Common control 2 */
+#define PID         0x0A /* Product ID Number MSB */
+#define VER         0x0B /* Product ID Number LSB */
+#define COM3        0x0C /* Common control 3 */
+#define COM4        0x0D /* Common control 4 */
+#define COM5        0x0E /* Common control 5 */
+#define COM6        0x0F /* Common control 6 */
+#define AEC         0x10 /* Exposure Value */
+#define CLKRC       0x11 /* Internal clock */
+#define COM7        0x12 /* Common control 7 */
+#define COM8        0x13 /* Common control 8 */
+#define COM9        0x14 /* Common control 9 */
+#define COM10       0x15 /* Common control 10 */
+#define REG16       0x16 /* Register 16 */
+#define HSTART      0x17 /* Horizontal sensor size */
+#define HSIZE       0x18 /* Horizontal frame (HREF column) end high 8-bit */
+#define VSTART      0x19 /* Vertical frame (row) start high 8-bit */
+#define VSIZE       0x1A /* Vertical sensor size */
+#define PSHFT       0x1B /* Data format - pixel delay select */
+#define MIDH        0x1C /* Manufacturer ID byte - high */
+#define MIDL        0x1D /* Manufacturer ID byte - low  */
+#define LAEC        0x1F /* Fine AEC value */
+#define COM11       0x20 /* Common control 11 */
+#define BDBASE      0x22 /* Banding filter Minimum AEC value */
+#define DBSTEP      0x23 /* Banding filter Maximum Setp */
+#define AEW         0x24 /* AGC/AEC - Stable operating region (upper limit) */
+#define AEB         0x25 /* AGC/AEC - Stable operating region (lower limit) */
+#define VPT         0x26 /* AGC/AEC Fast mode operating region */
+#define REG28       0x28 /* Register 28 */
+#define HOUTSIZE    0x29 /* Horizontal data output size MSBs */
+#define EXHCH       0x2A /* Dummy pixel insert MSB */
+#define EXHCL       0x2B /* Dummy pixel insert LSB */
+#define VOUTSIZE    0x2C /* Vertical data output size MSBs */
+#define ADVFL       0x2D /* LSB of insert dummy lines in Vertical direction */
+#define ADVFH       0x2E /* MSG of insert dummy lines in Vertical direction */
+#define YAVE        0x2F /* Y/G Channel Average value */
+#define LUMHTH      0x30 /* Histogram AEC/AGC Luminance high level threshold */
+#define LUMLTH      0x31 /* Histogram AEC/AGC Luminance low  level threshold */
+#define HREF        0x32 /* Image start and size control */
+#define DM_LNL      0x33 /* Dummy line low  8 bits */
+#define DM_LNH      0x34 /* Dummy line high 8 bits */
+#define ADOFF_B     0x35 /* AD offset compensation value for B  channel */
+#define ADOFF_R     0x36 /* AD offset compensation value for R  channel */
+#define ADOFF_GB    0x37 /* AD offset compensation value for Gb channel */
+#define ADOFF_GR    0x38 /* AD offset compensation value for Gr channel */
+#define OFF_B       0x39 /* Analog process B  channel offset value */
+#define OFF_R       0x3A /* Analog process R  channel offset value */
+#define OFF_GB      0x3B /* Analog process Gb channel offset value */
+#define OFF_GR      0x3C /* Analog process Gr channel offset value */
+#define COM12       0x3D /* Common control 12 */
+#define COM13       0x3E /* Common control 13 */
+#define COM14       0x3F /* Common control 14 */
+#define COM15       0x40 /* Common control 15*/
+#define COM16       0x41 /* Common control 16 */
+#define TGT_B       0x42 /* BLC blue channel target value */
+#define TGT_R       0x43 /* BLC red  channel target value */
+#define TGT_GB      0x44 /* BLC Gb   channel target value */
+#define TGT_GR      0x45 /* BLC Gr   channel target value */
+/* for ov7720 */
+#define LCC0        0x46 /* Lens correction control 0 */
+#define LCC1        0x47 /* Lens correction option 1 - X coordinate */
+#define LCC2        0x48 /* Lens correction option 2 - Y coordinate */
+#define LCC3        0x49 /* Lens correction option 3 */
+#define LCC4        0x4A /* Lens correction option 4 - radius of the circular */
+#define LCC5        0x4B /* Lens correction option 5 */
+#define LCC6        0x4C /* Lens correction option 6 */
+/* for ov7725 */
+#define LC_CTR      0x46 /* Lens correction control */
+#define LC_XC       0x47 /* X coordinate of lens correction center relative */
+#define LC_YC       0x48 /* Y coordinate of lens correction center relative */
+#define LC_COEF     0x49 /* Lens correction coefficient */
+#define LC_RADI     0x4A /* Lens correction radius */
+#define LC_COEFB    0x4B /* Lens B channel compensation coefficient */
+#define LC_COEFR    0x4C /* Lens R channel compensation coefficient */
+
+#define FIXGAIN     0x4D /* Analog fix gain amplifer */
+#define AREF0       0x4E /* Sensor reference control */
+#define AREF1       0x4F /* Sensor reference current control */
+#define AREF2       0x50 /* Analog reference control */
+#define AREF3       0x51 /* ADC    reference control */
+#define AREF4       0x52 /* ADC    reference control */
+#define AREF5       0x53 /* ADC    reference control */
+#define AREF6       0x54 /* Analog reference control */
+#define AREF7       0x55 /* Analog reference control */
+#define UFIX        0x60 /* U channel fixed value output */
+#define VFIX        0x61 /* V channel fixed value output */
+#define AWBB_BLK    0x62 /* AWB option for advanced AWB */
+#define AWB_CTRL0   0x63 /* AWB control byte 0 */
+#define DSP_CTRL1   0x64 /* DSP control byte 1 */
+#define DSP_CTRL2   0x65 /* DSP control byte 2 */
+#define DSP_CTRL3   0x66 /* DSP control byte 3 */
+#define DSP_CTRL4   0x67 /* DSP control byte 4 */
+#define AWB_BIAS    0x68 /* AWB BLC level clip */
+#define AWB_CTRL1   0x69 /* AWB control  1 */
+#define AWB_CTRL2   0x6A /* AWB control  2 */
+#define AWB_CTRL3   0x6B /* AWB control  3 */
+#define AWB_CTRL4   0x6C /* AWB control  4 */
+#define AWB_CTRL5   0x6D /* AWB control  5 */
+#define AWB_CTRL6   0x6E /* AWB control  6 */
+#define AWB_CTRL7   0x6F /* AWB control  7 */
+#define AWB_CTRL8   0x70 /* AWB control  8 */
+#define AWB_CTRL9   0x71 /* AWB control  9 */
+#define AWB_CTRL10  0x72 /* AWB control 10 */
+#define AWB_CTRL11  0x73 /* AWB control 11 */
+#define AWB_CTRL12  0x74 /* AWB control 12 */
+#define AWB_CTRL13  0x75 /* AWB control 13 */
+#define AWB_CTRL14  0x76 /* AWB control 14 */
+#define AWB_CTRL15  0x77 /* AWB control 15 */
+#define AWB_CTRL16  0x78 /* AWB control 16 */
+#define AWB_CTRL17  0x79 /* AWB control 17 */
+#define AWB_CTRL18  0x7A /* AWB control 18 */
+#define AWB_CTRL19  0x7B /* AWB control 19 */
+#define AWB_CTRL20  0x7C /* AWB control 20 */
+#define AWB_CTRL21  0x7D /* AWB control 21 */
+#define GAM1        0x7E /* Gamma Curve  1st segment input end point */
+#define GAM2        0x7F /* Gamma Curve  2nd segment input end point */
+#define GAM3        0x80 /* Gamma Curve  3rd segment input end point */
+#define GAM4        0x81 /* Gamma Curve  4th segment input end point */
+#define GAM5        0x82 /* Gamma Curve  5th segment input end point */
+#define GAM6        0x83 /* Gamma Curve  6th segment input end point */
+#define GAM7        0x84 /* Gamma Curve  7th segment input end point */
+#define GAM8        0x85 /* Gamma Curve  8th segment input end point */
+#define GAM9        0x86 /* Gamma Curve  9th segment input end point */
+#define GAM10       0x87 /* Gamma Curve 10th segment input end point */
+#define GAM11       0x88 /* Gamma Curve 11th segment input end point */
+#define GAM12       0x89 /* Gamma Curve 12th segment input end point */
+#define GAM13       0x8A /* Gamma Curve 13th segment input end point */
+#define GAM14       0x8B /* Gamma Curve 14th segment input end point */
+#define GAM15       0x8C /* Gamma Curve 15th segment input end point */
+#define SLOP        0x8D /* Gamma curve highest segment slope */
+#define DNSTH       0x8E /* De-noise threshold */
+#define EDGE_STRNGT 0x8F /* Edge strength  control when manual mode */
+#define EDGE_TRSHLD 0x90 /* Edge threshold control when manual mode */
+#define DNSOFF      0x91 /* Auto De-noise threshold control */
+#define EDGE_UPPER  0x92 /* Edge strength upper limit when Auto mode */
+#define EDGE_LOWER  0x93 /* Edge strength lower limit when Auto mode */
+#define MTX1        0x94 /* Matrix coefficient 1 */
+#define MTX2        0x95 /* Matrix coefficient 2 */
+#define MTX3        0x96 /* Matrix coefficient 3 */
+#define MTX4        0x97 /* Matrix coefficient 4 */
+#define MTX5        0x98 /* Matrix coefficient 5 */
+#define MTX6        0x99 /* Matrix coefficient 6 */
+#define MTX_CTRL    0x9A /* Matrix control */
+#define BRIGHT      0x9B /* Brightness control */
+#define CNTRST      0x9C /* Contrast contrast */
+#define CNTRST_CTRL 0x9D /* Contrast contrast center */
+#define UVAD_J0     0x9E /* Auto UV adjust contrast 0 */
+#define UVAD_J1     0x9F /* Auto UV adjust contrast 1 */
+#define SCAL0       0xA0 /* Scaling control 0 */
+#define SCAL1       0xA1 /* Scaling control 1 */
+#define SCAL2       0xA2 /* Scaling control 2 */
+#define FIFODLYM    0xA3 /* FIFO manual mode delay control */
+#define FIFODLYA    0xA4 /* FIFO auto   mode delay control */
+#define SDE         0xA6 /* Special digital effect control */
+#define USAT        0xA7 /* U component saturation control */
+#define VSAT        0xA8 /* V component saturation control */
+/* for ov7720 */
+#define HUE0        0xA9 /* Hue control 0 */
+#define HUE1        0xAA /* Hue control 1 */
+/* for ov7725 */
+#define HUECOS      0xA9 /* Cosine value */
+#define HUESIN      0xAA /* Sine value */
+
+#define SIGN        0xAB /* Sign bit for Hue and contrast */
+#define DSPAUTO     0xAC /* DSP auto function ON/OFF control */
+
+/*
+ * register detail
+ */
+
+/* COM2 */
+#define SOFT_SLEEP_MODE 0x10	/* Soft sleep mode */
+				/* Output drive capability */
+#define OCAP_1x         0x00	/* 1x */
+#define OCAP_2x         0x01	/* 2x */
+#define OCAP_3x         0x02	/* 3x */
+#define OCAP_4x         0x03	/* 4x */
+
+/* COM3 */
+#define SWAP_MASK       (SWAP_RGB | SWAP_YUV | SWAP_ML)
+#define IMG_MASK        (VFLIP_IMG | HFLIP_IMG)
+
+#define VFLIP_IMG       0x80	/* Vertical flip image ON/OFF selection */
+#define HFLIP_IMG       0x40	/* Horizontal mirror image ON/OFF selection */
+#define SWAP_RGB        0x20	/* Swap B/R  output sequence in RGB mode */
+#define SWAP_YUV        0x10	/* Swap Y/UV output sequence in YUV mode */
+#define SWAP_ML         0x08	/* Swap output MSB/LSB */
+				/* Tri-state option for output clock */
+#define NOTRI_CLOCK     0x04	/*   0: Tri-state    at this period */
+				/*   1: No tri-state at this period */
+				/* Tri-state option for output data */
+#define NOTRI_DATA      0x02	/*   0: Tri-state    at this period */
+				/*   1: No tri-state at this period */
+#define SCOLOR_TEST     0x01	/* Sensor color bar test pattern */
+
+/* COM4 */
+				/* PLL frequency control */
+#define PLL_BYPASS      0x00	/*  00: Bypass PLL */
+#define PLL_4x          0x40	/*  01: PLL 4x */
+#define PLL_6x          0x80	/*  10: PLL 6x */
+#define PLL_8x          0xc0	/*  11: PLL 8x */
+				/* AEC evaluate window */
+#define AEC_FULL        0x00	/*  00: Full window */
+#define AEC_1p2         0x10	/*  01: 1/2  window */
+#define AEC_1p4         0x20	/*  10: 1/4  window */
+#define AEC_2p3         0x30	/*  11: Low 2/3 window */
+
+/* COM5 */
+#define AFR_ON_OFF      0x80	/* Auto frame rate control ON/OFF selection */
+#define AFR_SPPED       0x40	/* Auto frame rate control speed selection */
+				/* Auto frame rate max rate control */
+#define AFR_NO_RATE     0x00	/*     No  reduction of frame rate */
+#define AFR_1p2         0x10	/*     Max reduction to 1/2 frame rate */
+#define AFR_1p4         0x20	/*     Max reduction to 1/4 frame rate */
+#define AFR_1p8         0x30	/* Max reduction to 1/8 frame rate */
+				/* Auto frame rate active point control */
+#define AF_2x           0x00	/*     Add frame when AGC reaches  2x gain */
+#define AF_4x           0x04	/*     Add frame when AGC reaches  4x gain */
+#define AF_8x           0x08	/*     Add frame when AGC reaches  8x gain */
+#define AF_16x          0x0c	/* Add frame when AGC reaches 16x gain */
+				/* AEC max step control */
+#define AEC_NO_LIMIT    0x01	/*   0 : AEC incease step has limit */
+				/*   1 : No limit to AEC increase step */
+
+/* COM7 */
+				/* SCCB Register Reset */
+#define SCCB_RESET      0x80	/*   0 : No change */
+				/*   1 : Resets all registers to default */
+				/* Resolution selection */
+#define SLCT_MASK       0x40	/*   Mask of VGA or QVGA */
+#define SLCT_VGA        0x00	/*   0 : VGA */
+#define SLCT_QVGA       0x40	/*   1 : QVGA */
+#define ITU656_ON_OFF   0x20	/* ITU656 protocol ON/OFF selection */
+#define SENSOR_RAW	0x10	/* Sensor RAW */
+				/* RGB output format control */
+#define FMT_MASK        0x0c	/*      Mask of color format */
+#define FMT_GBR422      0x00	/*      00 : GBR 4:2:2 */
+#define FMT_RGB565      0x04	/*      01 : RGB 565 */
+#define FMT_RGB555      0x08	/*      10 : RGB 555 */
+#define FMT_RGB444      0x0c	/* 11 : RGB 444 */
+				/* Output format control */
+#define OFMT_MASK       0x03    /*      Mask of output format */
+#define OFMT_YUV        0x00	/*      00 : YUV */
+#define OFMT_P_BRAW     0x01	/*      01 : Processed Bayer RAW */
+#define OFMT_RGB        0x02	/*      10 : RGB */
+#define OFMT_BRAW       0x03	/* 11 : Bayer RAW */
+
+/* COM8 */
+#define FAST_ALGO       0x80	/* Enable fast AGC/AEC algorithm */
+				/* AEC Setp size limit */
+#define UNLMT_STEP      0x40	/*   0 : Step size is limited */
+				/*   1 : Unlimited step size */
+#define BNDF_ON_OFF     0x20	/* Banding filter ON/OFF */
+#define AEC_BND         0x10	/* Enable AEC below banding value */
+#define AEC_ON_OFF      0x08	/* Fine AEC ON/OFF control */
+#define AGC_ON          0x04	/* AGC Enable */
+#define AWB_ON          0x02	/* AWB Enable */
+#define AEC_ON          0x01	/* AEC Enable */
+
+/* COM9 */
+#define BASE_AECAGC     0x80	/* Histogram or average based AEC/AGC */
+				/* Automatic gain ceiling - maximum AGC value */
+#define GAIN_2x         0x00	/*    000 :   2x */
+#define GAIN_4x         0x10	/*    001 :   4x */
+#define GAIN_8x         0x20	/*    010 :   8x */
+#define GAIN_16x        0x30	/*    011 :  16x */
+#define GAIN_32x        0x40	/*    100 :  32x */
+#define GAIN_64x        0x50	/* 101 :  64x */
+#define GAIN_128x       0x60	/* 110 : 128x */
+#define DROP_VSYNC      0x04	/* Drop VSYNC output of corrupt frame */
+#define DROP_HREF       0x02	/* Drop HREF  output of corrupt frame */
+
+/* COM11 */
+#define SGLF_ON_OFF     0x02	/* Single frame ON/OFF selection */
+#define SGLF_TRIG       0x01	/* Single frame transfer trigger */
+
+/* HREF */
+#define HREF_VSTART_SHIFT	6	/* VSTART LSB */
+#define HREF_HSTART_SHIFT	4	/* HSTART 2 LSBs */
+#define HREF_VSIZE_SHIFT	2	/* VSIZE LSB */
+#define HREF_HSIZE_SHIFT	0	/* HSIZE 2 LSBs */
+
+/* EXHCH */
+#define EXHCH_VSIZE_SHIFT	2	/* VOUTSIZE LSB */
+#define EXHCH_HSIZE_SHIFT	0	/* HOUTSIZE 2 LSBs */
+
+/* DSP_CTRL1 */
+#define FIFO_ON         0x80	/* FIFO enable/disable selection */
+#define UV_ON_OFF       0x40	/* UV adjust function ON/OFF selection */
+#define YUV444_2_422    0x20	/* YUV444 to 422 UV channel option selection */
+#define CLR_MTRX_ON_OFF 0x10	/* Color matrix ON/OFF selection */
+#define INTPLT_ON_OFF   0x08	/* Interpolation ON/OFF selection */
+#define GMM_ON_OFF      0x04	/* Gamma function ON/OFF selection */
+#define AUTO_BLK_ON_OFF 0x02	/* Black defect auto correction ON/OFF */
+#define AUTO_WHT_ON_OFF 0x01	/* White define auto correction ON/OFF */
+
+/* DSP_CTRL3 */
+#define UV_MASK         0x80	/* UV output sequence option */
+#define UV_ON           0x80	/*   ON */
+#define UV_OFF          0x00	/*   OFF */
+#define CBAR_MASK       0x20	/* DSP Color bar mask */
+#define CBAR_ON         0x20	/*   ON */
+#define CBAR_OFF        0x00	/*   OFF */
+
+/* DSP_CTRL4 */
+#define DSP_OFMT_YUV	0x00
+#define DSP_OFMT_RGB	0x00
+#define DSP_OFMT_RAW8	0x02
+#define DSP_OFMT_RAW10	0x03
+
+/* DSPAUTO (DSP Auto Function ON/OFF Control) */
+#define AWB_ACTRL       0x80 /* AWB auto threshold control */
+#define DENOISE_ACTRL   0x40 /* De-noise auto threshold control */
+#define EDGE_ACTRL      0x20 /* Edge enhancement auto strength control */
+#define UV_ACTRL        0x10 /* UV adjust auto slope control */
+#define SCAL0_ACTRL     0x08 /* Auto scaling factor control */
+#define SCAL1_2_ACTRL   0x04 /* Auto scaling factor control */
+
+#define VGA_WIDTH		640
+#define VGA_HEIGHT		480
+#define QVGA_WIDTH		320
+#define QVGA_HEIGHT		240
+#define OV772X_MAX_WIDTH	VGA_WIDTH
+#define OV772X_MAX_HEIGHT	VGA_HEIGHT
+
+/*
+ * ID
+ */
+#define OV7720  0x7720
+#define OV7725  0x7721
+#define VERSION(pid, ver) ((pid<<8)|(ver&0xFF))
+
+/*
+ * struct
+ */
+
+struct ov772x_color_format {
+	enum v4l2_mbus_pixelcode code;
+	enum v4l2_colorspace colorspace;
+	u8 dsp3;
+	u8 dsp4;
+	u8 com3;
+	u8 com7;
+};
+
+struct ov772x_win_size {
+	char                     *name;
+	unsigned char             com7_bit;
+	struct v4l2_rect	  rect;
+};
+
+struct ov772x_priv {
+	struct v4l2_subdev                subdev;
+	struct v4l2_ctrl_handler	  hdl;
+	struct ov772x_camera_info        *info;
+	const struct ov772x_color_format *cfmt;
+	const struct ov772x_win_size     *win;
+	int                               model;
+	unsigned short                    flag_vflip:1;
+	unsigned short                    flag_hflip:1;
+	/* band_filter = COM8[5] ? 256 - BDBASE : 0 */
+	unsigned short                    band_filter;
+};
+
+/*
+ * supported color format list
+ */
+static const struct ov772x_color_format ov772x_cfmts[] = {
+	{
+		.code		= V4L2_MBUS_FMT_YUYV8_2X8,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.dsp3		= 0x0,
+		.dsp4		= DSP_OFMT_YUV,
+		.com3		= SWAP_YUV,
+		.com7		= OFMT_YUV,
+	},
+	{
+		.code		= V4L2_MBUS_FMT_YVYU8_2X8,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.dsp3		= UV_ON,
+		.dsp4		= DSP_OFMT_YUV,
+		.com3		= SWAP_YUV,
+		.com7		= OFMT_YUV,
+	},
+	{
+		.code		= V4L2_MBUS_FMT_UYVY8_2X8,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.dsp3		= 0x0,
+		.dsp4		= DSP_OFMT_YUV,
+		.com3		= 0x0,
+		.com7		= OFMT_YUV,
+	},
+	{
+		.code		= V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
+		.dsp3		= 0x0,
+		.dsp4		= DSP_OFMT_YUV,
+		.com3		= SWAP_RGB,
+		.com7		= FMT_RGB555 | OFMT_RGB,
+	},
+	{
+		.code		= V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
+		.dsp3		= 0x0,
+		.dsp4		= DSP_OFMT_YUV,
+		.com3		= 0x0,
+		.com7		= FMT_RGB555 | OFMT_RGB,
+	},
+	{
+		.code		= V4L2_MBUS_FMT_RGB565_2X8_LE,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
+		.dsp3		= 0x0,
+		.dsp4		= DSP_OFMT_YUV,
+		.com3		= SWAP_RGB,
+		.com7		= FMT_RGB565 | OFMT_RGB,
+	},
+	{
+		.code		= V4L2_MBUS_FMT_RGB565_2X8_BE,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
+		.dsp3		= 0x0,
+		.dsp4		= DSP_OFMT_YUV,
+		.com3		= 0x0,
+		.com7		= FMT_RGB565 | OFMT_RGB,
+	},
+	{
+		/* Setting DSP4 to DSP_OFMT_RAW8 still gives 10-bit output,
+		 * regardless of the COM7 value. We can thus only support 10-bit
+		 * Bayer until someone figures it out.
+		 */
+		.code		= V4L2_MBUS_FMT_SBGGR10_1X10,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
+		.dsp3		= 0x0,
+		.dsp4		= DSP_OFMT_RAW10,
+		.com3		= 0x0,
+		.com7		= SENSOR_RAW | OFMT_BRAW,
+	},
+};
+
+
+/*
+ * window size list
+ */
+
+static const struct ov772x_win_size ov772x_win_sizes[] = {
+	{
+		.name     = "VGA",
+		.com7_bit = SLCT_VGA,
+		.rect = {
+			.left = 140,
+			.top = 14,
+			.width = VGA_WIDTH,
+			.height = VGA_HEIGHT,
+		},
+	}, {
+		.name     = "QVGA",
+		.com7_bit = SLCT_QVGA,
+		.rect = {
+			.left = 252,
+			.top = 6,
+			.width = QVGA_WIDTH,
+			.height = QVGA_HEIGHT,
+		},
+	},
+};
+
+/*
+ * general function
+ */
+
+static struct ov772x_priv *to_ov772x(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct ov772x_priv, subdev);
+}
+
+static inline int ov772x_read(struct i2c_client *client, u8 addr)
+{
+	return i2c_smbus_read_byte_data(client, addr);
+}
+
+static inline int ov772x_write(struct i2c_client *client, u8 addr, u8 value)
+{
+	return i2c_smbus_write_byte_data(client, addr, value);
+}
+
+static int ov772x_mask_set(struct i2c_client *client, u8  command, u8  mask,
+			   u8  set)
+{
+	s32 val = ov772x_read(client, command);
+	if (val < 0)
+		return val;
+
+	val &= ~mask;
+	val |= set & mask;
+
+	return ov772x_write(client, command, val);
+}
+
+static int ov772x_reset(struct i2c_client *client)
+{
+	int ret;
+
+	ret = ov772x_write(client, COM7, SCCB_RESET);
+	if (ret < 0)
+		return ret;
+
+	msleep(1);
+
+	return ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
+}
+
+/*
+ * soc_camera_ops function
+ */
+
+static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov772x_priv *priv = to_ov772x(sd);
+
+	if (!enable) {
+		ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
+		return 0;
+	}
+
+	ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0);
+
+	dev_dbg(&client->dev, "format %d, win %s\n",
+		priv->cfmt->code, priv->win->name);
+
+	return 0;
+}
+
+static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ov772x_priv *priv = container_of(ctrl->handler,
+						struct ov772x_priv, hdl);
+	struct v4l2_subdev *sd = &priv->subdev;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret = 0;
+	u8 val;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		val = ctrl->val ? VFLIP_IMG : 0x00;
+		priv->flag_vflip = ctrl->val;
+		if (priv->info->flags & OV772X_FLAG_VFLIP)
+			val ^= VFLIP_IMG;
+		return ov772x_mask_set(client, COM3, VFLIP_IMG, val);
+	case V4L2_CID_HFLIP:
+		val = ctrl->val ? HFLIP_IMG : 0x00;
+		priv->flag_hflip = ctrl->val;
+		if (priv->info->flags & OV772X_FLAG_HFLIP)
+			val ^= HFLIP_IMG;
+		return ov772x_mask_set(client, COM3, HFLIP_IMG, val);
+	case V4L2_CID_BAND_STOP_FILTER:
+		if (!ctrl->val) {
+			/* Switch the filter off, it is on now */
+			ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff);
+			if (!ret)
+				ret = ov772x_mask_set(client, COM8,
+						      BNDF_ON_OFF, 0);
+		} else {
+			/* Switch the filter on, set AEC low limit */
+			val = 256 - ctrl->val;
+			ret = ov772x_mask_set(client, COM8,
+					      BNDF_ON_OFF, BNDF_ON_OFF);
+			if (!ret)
+				ret = ov772x_mask_set(client, BDBASE,
+						      0xff, val);
+		}
+		if (!ret)
+			priv->band_filter = ctrl->val;
+		return ret;
+	}
+
+	return -EINVAL;
+}
+
+static int ov772x_g_chip_ident(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_chip_ident *id)
+{
+	struct ov772x_priv *priv = to_ov772x(sd);
+
+	id->ident    = priv->model;
+	id->revision = 0;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov772x_g_register(struct v4l2_subdev *sd,
+			     struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+
+	reg->size = 1;
+	if (reg->reg > 0xff)
+		return -EINVAL;
+
+	ret = ov772x_read(client, reg->reg);
+	if (ret < 0)
+		return ret;
+
+	reg->val = (__u64)ret;
+
+	return 0;
+}
+
+static int ov772x_s_register(struct v4l2_subdev *sd,
+			     struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->reg > 0xff ||
+	    reg->val > 0xff)
+		return -EINVAL;
+
+	return ov772x_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov772x_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	return soc_camera_set_power(&client->dev, icl, on);
+}
+
+static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
+{
+	const struct ov772x_win_size *win = &ov772x_win_sizes[0];
+	u32 best_diff = UINT_MAX;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(ov772x_win_sizes); ++i) {
+		u32 diff = abs(width - ov772x_win_sizes[i].rect.width)
+			 + abs(height - ov772x_win_sizes[i].rect.height);
+		if (diff < best_diff) {
+			best_diff = diff;
+			win = &ov772x_win_sizes[i];
+		}
+	}
+
+	return win;
+}
+
+static void ov772x_select_params(const struct v4l2_mbus_framefmt *mf,
+				 const struct ov772x_color_format **cfmt,
+				 const struct ov772x_win_size **win)
+{
+	unsigned int i;
+
+	/* Select a format. */
+	*cfmt = &ov772x_cfmts[0];
+
+	for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) {
+		if (mf->code == ov772x_cfmts[i].code) {
+			*cfmt = &ov772x_cfmts[i];
+			break;
+		}
+	}
+
+	/* Select a window size. */
+	*win = ov772x_select_win(mf->width, mf->height);
+}
+
+static int ov772x_set_params(struct ov772x_priv *priv,
+			     const struct ov772x_color_format *cfmt,
+			     const struct ov772x_win_size *win)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
+	int ret;
+	u8  val;
+
+	/*
+	 * reset hardware
+	 */
+	ov772x_reset(client);
+
+	/*
+	 * Edge Ctrl
+	 */
+	if (priv->info->edgectrl.strength & OV772X_MANUAL_EDGE_CTRL) {
+
+		/*
+		 * Manual Edge Control Mode
+		 *
+		 * Edge auto strength bit is set by default.
+		 * Remove it when manual mode.
+		 */
+
+		ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00);
+		if (ret < 0)
+			goto ov772x_set_fmt_error;
+
+		ret = ov772x_mask_set(client,
+				      EDGE_TRSHLD, OV772X_EDGE_THRESHOLD_MASK,
+				      priv->info->edgectrl.threshold);
+		if (ret < 0)
+			goto ov772x_set_fmt_error;
+
+		ret = ov772x_mask_set(client,
+				      EDGE_STRNGT, OV772X_EDGE_STRENGTH_MASK,
+				      priv->info->edgectrl.strength);
+		if (ret < 0)
+			goto ov772x_set_fmt_error;
+
+	} else if (priv->info->edgectrl.upper > priv->info->edgectrl.lower) {
+		/*
+		 * Auto Edge Control Mode
+		 *
+		 * set upper and lower limit
+		 */
+		ret = ov772x_mask_set(client,
+				      EDGE_UPPER, OV772X_EDGE_UPPER_MASK,
+				      priv->info->edgectrl.upper);
+		if (ret < 0)
+			goto ov772x_set_fmt_error;
+
+		ret = ov772x_mask_set(client,
+				      EDGE_LOWER, OV772X_EDGE_LOWER_MASK,
+				      priv->info->edgectrl.lower);
+		if (ret < 0)
+			goto ov772x_set_fmt_error;
+	}
+
+	/* Format and window size */
+	ret = ov772x_write(client, HSTART, win->rect.left >> 2);
+	if (ret < 0)
+		goto ov772x_set_fmt_error;
+	ret = ov772x_write(client, HSIZE, win->rect.width >> 2);
+	if (ret < 0)
+		goto ov772x_set_fmt_error;
+	ret = ov772x_write(client, VSTART, win->rect.top >> 1);
+	if (ret < 0)
+		goto ov772x_set_fmt_error;
+	ret = ov772x_write(client, VSIZE, win->rect.height >> 1);
+	if (ret < 0)
+		goto ov772x_set_fmt_error;
+	ret = ov772x_write(client, HOUTSIZE, win->rect.width >> 2);
+	if (ret < 0)
+		goto ov772x_set_fmt_error;
+	ret = ov772x_write(client, VOUTSIZE, win->rect.height >> 1);
+	if (ret < 0)
+		goto ov772x_set_fmt_error;
+	ret = ov772x_write(client, HREF,
+			   ((win->rect.top & 1) << HREF_VSTART_SHIFT) |
+			   ((win->rect.left & 3) << HREF_HSTART_SHIFT) |
+			   ((win->rect.height & 1) << HREF_VSIZE_SHIFT) |
+			   ((win->rect.width & 3) << HREF_HSIZE_SHIFT));
+	if (ret < 0)
+		goto ov772x_set_fmt_error;
+	ret = ov772x_write(client, EXHCH,
+			   ((win->rect.height & 1) << EXHCH_VSIZE_SHIFT) |
+			   ((win->rect.width & 3) << EXHCH_HSIZE_SHIFT));
+	if (ret < 0)
+		goto ov772x_set_fmt_error;
+
+	/*
+	 * set DSP_CTRL3
+	 */
+	val = cfmt->dsp3;
+	if (val) {
+		ret = ov772x_mask_set(client,
+				      DSP_CTRL3, UV_MASK, val);
+		if (ret < 0)
+			goto ov772x_set_fmt_error;
+	}
+
+	/* DSP_CTRL4: AEC reference point and DSP output format. */
+	if (cfmt->dsp4) {
+		ret = ov772x_write(client, DSP_CTRL4, cfmt->dsp4);
+		if (ret < 0)
+			goto ov772x_set_fmt_error;
+	}
+
+	/*
+	 * set COM3
+	 */
+	val = cfmt->com3;
+	if (priv->info->flags & OV772X_FLAG_VFLIP)
+		val |= VFLIP_IMG;
+	if (priv->info->flags & OV772X_FLAG_HFLIP)
+		val |= HFLIP_IMG;
+	if (priv->flag_vflip)
+		val ^= VFLIP_IMG;
+	if (priv->flag_hflip)
+		val ^= HFLIP_IMG;
+
+	ret = ov772x_mask_set(client,
+			      COM3, SWAP_MASK | IMG_MASK, val);
+	if (ret < 0)
+		goto ov772x_set_fmt_error;
+
+	/* COM7: Sensor resolution and output format control. */
+	ret = ov772x_write(client, COM7, win->com7_bit | cfmt->com7);
+	if (ret < 0)
+		goto ov772x_set_fmt_error;
+
+	/*
+	 * set COM8
+	 */
+	if (priv->band_filter) {
+		ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1);
+		if (!ret)
+			ret = ov772x_mask_set(client, BDBASE,
+					      0xff, 256 - priv->band_filter);
+		if (ret < 0)
+			goto ov772x_set_fmt_error;
+	}
+
+	return ret;
+
+ov772x_set_fmt_error:
+
+	ov772x_reset(client);
+
+	return ret;
+}
+
+static int ov772x_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	a->c.left	= 0;
+	a->c.top	= 0;
+	a->c.width	= VGA_WIDTH;
+	a->c.height	= VGA_HEIGHT;
+	a->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	a->bounds.left			= 0;
+	a->bounds.top			= 0;
+	a->bounds.width			= OV772X_MAX_WIDTH;
+	a->bounds.height		= OV772X_MAX_HEIGHT;
+	a->defrect			= a->bounds;
+	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int ov772x_g_fmt(struct v4l2_subdev *sd,
+			struct v4l2_mbus_framefmt *mf)
+{
+	struct ov772x_priv *priv = to_ov772x(sd);
+
+	mf->width	= priv->win->rect.width;
+	mf->height	= priv->win->rect.height;
+	mf->code	= priv->cfmt->code;
+	mf->colorspace	= priv->cfmt->colorspace;
+	mf->field	= V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static int ov772x_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+{
+	struct ov772x_priv *priv = to_ov772x(sd);
+	const struct ov772x_color_format *cfmt;
+	const struct ov772x_win_size *win;
+	int ret;
+
+	ov772x_select_params(mf, &cfmt, &win);
+
+	ret = ov772x_set_params(priv, cfmt, win);
+	if (ret < 0)
+		return ret;
+
+	priv->win = win;
+	priv->cfmt = cfmt;
+
+	mf->code = cfmt->code;
+	mf->width = win->rect.width;
+	mf->height = win->rect.height;
+	mf->field = V4L2_FIELD_NONE;
+	mf->colorspace = cfmt->colorspace;
+
+	return 0;
+}
+
+static int ov772x_try_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_mbus_framefmt *mf)
+{
+	const struct ov772x_color_format *cfmt;
+	const struct ov772x_win_size *win;
+
+	ov772x_select_params(mf, &cfmt, &win);
+
+	mf->code = cfmt->code;
+	mf->width = win->rect.width;
+	mf->height = win->rect.height;
+	mf->field = V4L2_FIELD_NONE;
+	mf->colorspace = cfmt->colorspace;
+
+	return 0;
+}
+
+static int ov772x_video_probe(struct ov772x_priv *priv)
+{
+	struct i2c_client  *client = v4l2_get_subdevdata(&priv->subdev);
+	u8                  pid, ver;
+	const char         *devname;
+	int		    ret;
+
+	ret = ov772x_s_power(&priv->subdev, 1);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * check and show product ID and manufacturer ID
+	 */
+	pid = ov772x_read(client, PID);
+	ver = ov772x_read(client, VER);
+
+	switch (VERSION(pid, ver)) {
+	case OV7720:
+		devname     = "ov7720";
+		priv->model = V4L2_IDENT_OV7720;
+		break;
+	case OV7725:
+		devname     = "ov7725";
+		priv->model = V4L2_IDENT_OV7725;
+		break;
+	default:
+		dev_err(&client->dev,
+			"Product ID error %x:%x\n", pid, ver);
+		ret = -ENODEV;
+		goto done;
+	}
+
+	dev_info(&client->dev,
+		 "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
+		 devname,
+		 pid,
+		 ver,
+		 ov772x_read(client, MIDH),
+		 ov772x_read(client, MIDL));
+	ret = v4l2_ctrl_handler_setup(&priv->hdl);
+
+done:
+	ov772x_s_power(&priv->subdev, 0);
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops ov772x_ctrl_ops = {
+	.s_ctrl = ov772x_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
+	.g_chip_ident	= ov772x_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register	= ov772x_g_register,
+	.s_register	= ov772x_s_register,
+#endif
+	.s_power	= ov772x_s_power,
+};
+
+static int ov772x_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			   enum v4l2_mbus_pixelcode *code)
+{
+	if (index >= ARRAY_SIZE(ov772x_cfmts))
+		return -EINVAL;
+
+	*code = ov772x_cfmts[index].code;
+	return 0;
+}
+
+static int ov772x_g_mbus_config(struct v4l2_subdev *sd,
+				struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
+		V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+		V4L2_MBUS_DATA_ACTIVE_HIGH;
+	cfg->type = V4L2_MBUS_PARALLEL;
+	cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+	return 0;
+}
+
+static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = {
+	.s_stream	= ov772x_s_stream,
+	.g_mbus_fmt	= ov772x_g_fmt,
+	.s_mbus_fmt	= ov772x_s_fmt,
+	.try_mbus_fmt	= ov772x_try_fmt,
+	.cropcap	= ov772x_cropcap,
+	.g_crop		= ov772x_g_crop,
+	.enum_mbus_fmt	= ov772x_enum_fmt,
+	.g_mbus_config	= ov772x_g_mbus_config,
+};
+
+static struct v4l2_subdev_ops ov772x_subdev_ops = {
+	.core	= &ov772x_subdev_core_ops,
+	.video	= &ov772x_subdev_video_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+
+static int ov772x_probe(struct i2c_client *client,
+			const struct i2c_device_id *did)
+{
+	struct ov772x_priv	*priv;
+	struct soc_camera_link	*icl = soc_camera_i2c_to_link(client);
+	struct i2c_adapter	*adapter = to_i2c_adapter(client->dev.parent);
+	int			ret;
+
+	if (!icl || !icl->priv) {
+		dev_err(&client->dev, "OV772X: missing platform data!\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		dev_err(&adapter->dev,
+			"I2C-Adapter doesn't support "
+			"I2C_FUNC_SMBUS_BYTE_DATA\n");
+		return -EIO;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->info = icl->priv;
+
+	v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops);
+	v4l2_ctrl_handler_init(&priv->hdl, 3);
+	v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
+			V4L2_CID_HFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
+			V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0);
+	priv->subdev.ctrl_handler = &priv->hdl;
+	if (priv->hdl.error) {
+		ret = priv->hdl.error;
+		goto done;
+	}
+
+	ret = ov772x_video_probe(priv);
+	if (ret < 0)
+		goto done;
+
+	priv->cfmt = &ov772x_cfmts[0];
+	priv->win = &ov772x_win_sizes[0];
+
+done:
+	if (ret) {
+		v4l2_ctrl_handler_free(&priv->hdl);
+		kfree(priv);
+	}
+	return ret;
+}
+
+static int ov772x_remove(struct i2c_client *client)
+{
+	struct ov772x_priv *priv = to_ov772x(i2c_get_clientdata(client));
+
+	v4l2_device_unregister_subdev(&priv->subdev);
+	v4l2_ctrl_handler_free(&priv->hdl);
+	kfree(priv);
+	return 0;
+}
+
+static const struct i2c_device_id ov772x_id[] = {
+	{ "ov772x", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ov772x_id);
+
+static struct i2c_driver ov772x_i2c_driver = {
+	.driver = {
+		.name = "ov772x",
+	},
+	.probe    = ov772x_probe,
+	.remove   = ov772x_remove,
+	.id_table = ov772x_id,
+};
+
+module_i2c_driver(ov772x_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for ov772x");
+MODULE_AUTHOR("Kuninori Morimoto");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c
new file mode 100644
index 0000000..b323684
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov9640.c
@@ -0,0 +1,763 @@
+/*
+ * OmniVision OV96xx Camera Driver
+ *
+ * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on ov772x camera driver:
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov7670 and soc_camera_platform driver,
+ *
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+
+#include "ov9640.h"
+
+#define to_ov9640_sensor(sd)	container_of(sd, struct ov9640_priv, subdev)
+
+/* default register setup */
+static const struct ov9640_reg ov9640_regs_dflt[] = {
+	{ OV9640_COM5,	OV9640_COM5_SYSCLK | OV9640_COM5_LONGEXP },
+	{ OV9640_COM6,	OV9640_COM6_OPT_BLC | OV9640_COM6_ADBLC_BIAS |
+			OV9640_COM6_FMT_RST | OV9640_COM6_ADBLC_OPTEN },
+	{ OV9640_PSHFT,	OV9640_PSHFT_VAL(0x01) },
+	{ OV9640_ACOM,	OV9640_ACOM_2X_ANALOG | OV9640_ACOM_RSVD },
+	{ OV9640_TSLB,	OV9640_TSLB_YUYV_UYVY },
+	{ OV9640_COM16,	OV9640_COM16_RB_AVG },
+
+	/* Gamma curve P */
+	{ 0x6c, 0x40 },	{ 0x6d, 0x30 },	{ 0x6e, 0x4b },	{ 0x6f, 0x60 },
+	{ 0x70, 0x70 },	{ 0x71, 0x70 },	{ 0x72, 0x70 },	{ 0x73, 0x70 },
+	{ 0x74, 0x60 },	{ 0x75, 0x60 },	{ 0x76, 0x50 },	{ 0x77, 0x48 },
+	{ 0x78, 0x3a },	{ 0x79, 0x2e },	{ 0x7a, 0x28 },	{ 0x7b, 0x22 },
+
+	/* Gamma curve T */
+	{ 0x7c, 0x04 },	{ 0x7d, 0x07 },	{ 0x7e, 0x10 },	{ 0x7f, 0x28 },
+	{ 0x80, 0x36 },	{ 0x81, 0x44 },	{ 0x82, 0x52 },	{ 0x83, 0x60 },
+	{ 0x84, 0x6c },	{ 0x85, 0x78 },	{ 0x86, 0x8c },	{ 0x87, 0x9e },
+	{ 0x88, 0xbb },	{ 0x89, 0xd2 },	{ 0x8a, 0xe6 },
+};
+
+/* Configurations
+ * NOTE: for YUV, alter the following registers:
+ * 		COM12 |= OV9640_COM12_YUV_AVG
+ *
+ *	 for RGB, alter the following registers:
+ *		COM7  |= OV9640_COM7_RGB
+ *		COM13 |= OV9640_COM13_RGB_AVG
+ *		COM15 |= proper RGB color encoding mode
+ */
+static const struct ov9640_reg ov9640_regs_qqcif[] = {
+	{ OV9640_CLKRC,	OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x0f) },
+	{ OV9640_COM1,	OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP },
+	{ OV9640_COM4,	OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
+	{ OV9640_COM7,	OV9640_COM7_QCIF },
+	{ OV9640_COM12,	OV9640_COM12_RSVD },
+	{ OV9640_COM13,	OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+	{ OV9640_COM15,	OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_qqvga[] = {
+	{ OV9640_CLKRC,	OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) },
+	{ OV9640_COM1,	OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP },
+	{ OV9640_COM4,	OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
+	{ OV9640_COM7,	OV9640_COM7_QVGA },
+	{ OV9640_COM12,	OV9640_COM12_RSVD },
+	{ OV9640_COM13,	OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+	{ OV9640_COM15,	OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_qcif[] = {
+	{ OV9640_CLKRC,	OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) },
+	{ OV9640_COM4,	OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
+	{ OV9640_COM7,	OV9640_COM7_QCIF },
+	{ OV9640_COM12,	OV9640_COM12_RSVD },
+	{ OV9640_COM13,	OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+	{ OV9640_COM15,	OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_qvga[] = {
+	{ OV9640_CLKRC,	OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) },
+	{ OV9640_COM4,	OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
+	{ OV9640_COM7,	OV9640_COM7_QVGA },
+	{ OV9640_COM12,	OV9640_COM12_RSVD },
+	{ OV9640_COM13,	OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+	{ OV9640_COM15,	OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_cif[] = {
+	{ OV9640_CLKRC,	OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) },
+	{ OV9640_COM3,	OV9640_COM3_VP },
+	{ OV9640_COM7,	OV9640_COM7_CIF },
+	{ OV9640_COM12,	OV9640_COM12_RSVD },
+	{ OV9640_COM13,	OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+	{ OV9640_COM15,	OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_vga[] = {
+	{ OV9640_CLKRC,	OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) },
+	{ OV9640_COM3,	OV9640_COM3_VP },
+	{ OV9640_COM7,	OV9640_COM7_VGA },
+	{ OV9640_COM12,	OV9640_COM12_RSVD },
+	{ OV9640_COM13,	OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+	{ OV9640_COM15,	OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_sxga[] = {
+	{ OV9640_CLKRC,	OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) },
+	{ OV9640_COM3,	OV9640_COM3_VP },
+	{ OV9640_COM7,	0 },
+	{ OV9640_COM12,	OV9640_COM12_RSVD },
+	{ OV9640_COM13,	OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+	{ OV9640_COM15,	OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_yuv[] = {
+	{ OV9640_MTX1,	0x58 },
+	{ OV9640_MTX2,	0x48 },
+	{ OV9640_MTX3,	0x10 },
+	{ OV9640_MTX4,	0x28 },
+	{ OV9640_MTX5,	0x48 },
+	{ OV9640_MTX6,	0x70 },
+	{ OV9640_MTX7,	0x40 },
+	{ OV9640_MTX8,	0x40 },
+	{ OV9640_MTX9,	0x40 },
+	{ OV9640_MTXS,	0x0f },
+};
+
+static const struct ov9640_reg ov9640_regs_rgb[] = {
+	{ OV9640_MTX1,	0x71 },
+	{ OV9640_MTX2,	0x3e },
+	{ OV9640_MTX3,	0x0c },
+	{ OV9640_MTX4,	0x33 },
+	{ OV9640_MTX5,	0x72 },
+	{ OV9640_MTX6,	0x00 },
+	{ OV9640_MTX7,	0x2b },
+	{ OV9640_MTX8,	0x66 },
+	{ OV9640_MTX9,	0xd2 },
+	{ OV9640_MTXS,	0x65 },
+};
+
+static enum v4l2_mbus_pixelcode ov9640_codes[] = {
+	V4L2_MBUS_FMT_UYVY8_2X8,
+	V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+	V4L2_MBUS_FMT_RGB565_2X8_LE,
+};
+
+/* read a register */
+static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val)
+{
+	int ret;
+	u8 data = reg;
+	struct i2c_msg msg = {
+		.addr	= client->addr,
+		.flags	= 0,
+		.len	= 1,
+		.buf	= &data,
+	};
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret < 0)
+		goto err;
+
+	msg.flags = I2C_M_RD;
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret < 0)
+		goto err;
+
+	*val = data;
+	return 0;
+
+err:
+	dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg);
+	return ret;
+}
+
+/* write a register */
+static int ov9640_reg_write(struct i2c_client *client, u8 reg, u8 val)
+{
+	int ret;
+	u8 _val;
+	unsigned char data[2] = { reg, val };
+	struct i2c_msg msg = {
+		.addr	= client->addr,
+		.flags	= 0,
+		.len	= 2,
+		.buf	= data,
+	};
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg);
+		return ret;
+	}
+
+	/* we have to read the register back ... no idea why, maybe HW bug */
+	ret = ov9640_reg_read(client, reg, &_val);
+	if (ret)
+		dev_err(&client->dev,
+			"Failed reading back register 0x%02x!\n", reg);
+
+	return 0;
+}
+
+
+/* Read a register, alter its bits, write it back */
+static int ov9640_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 unset)
+{
+	u8 val;
+	int ret;
+
+	ret = ov9640_reg_read(client, reg, &val);
+	if (ret) {
+		dev_err(&client->dev,
+			"[Read]-Modify-Write of register %02x failed!\n", reg);
+		return val;
+	}
+
+	val |= set;
+	val &= ~unset;
+
+	ret = ov9640_reg_write(client, reg, val);
+	if (ret)
+		dev_err(&client->dev,
+			"Read-Modify-[Write] of register %02x failed!\n", reg);
+
+	return ret;
+}
+
+/* Soft reset the camera. This has nothing to do with the RESET pin! */
+static int ov9640_reset(struct i2c_client *client)
+{
+	int ret;
+
+	ret = ov9640_reg_write(client, OV9640_COM7, OV9640_COM7_SCCB_RESET);
+	if (ret)
+		dev_err(&client->dev,
+			"An error occurred while entering soft reset!\n");
+
+	return ret;
+}
+
+/* Start/Stop streaming from the device */
+static int ov9640_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	return 0;
+}
+
+/* Set status of additional camera capabilities */
+static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ov9640_priv *priv = container_of(ctrl->handler, struct ov9640_priv, hdl);
+	struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		if (ctrl->val)
+			return ov9640_reg_rmw(client, OV9640_MVFP,
+							OV9640_MVFP_V, 0);
+		return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_V);
+	case V4L2_CID_HFLIP:
+		if (ctrl->val)
+			return ov9640_reg_rmw(client, OV9640_MVFP,
+							OV9640_MVFP_H, 0);
+		return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_H);
+	}
+	return -EINVAL;
+}
+
+/* Get chip identification */
+static int ov9640_g_chip_ident(struct v4l2_subdev *sd,
+				struct v4l2_dbg_chip_ident *id)
+{
+	struct ov9640_priv *priv = to_ov9640_sensor(sd);
+
+	id->ident	= priv->model;
+	id->revision	= priv->revision;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov9640_get_register(struct v4l2_subdev *sd,
+				struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+	u8 val;
+
+	if (reg->reg & ~0xff)
+		return -EINVAL;
+
+	reg->size = 1;
+
+	ret = ov9640_reg_read(client, reg->reg, &val);
+	if (ret)
+		return ret;
+
+	reg->val = (__u64)val;
+
+	return 0;
+}
+
+static int ov9640_set_register(struct v4l2_subdev *sd,
+				struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->reg & ~0xff || reg->val & ~0xff)
+		return -EINVAL;
+
+	return ov9640_reg_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov9640_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	return soc_camera_set_power(&client->dev, icl, on);
+}
+
+/* select nearest higher resolution for capture */
+static void ov9640_res_roundup(u32 *width, u32 *height)
+{
+	int i;
+	enum { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA };
+	int res_x[] = { 88, 160, 176, 320, 352, 640, 1280 };
+	int res_y[] = { 72, 120, 144, 240, 288, 480, 960 };
+
+	for (i = 0; i < ARRAY_SIZE(res_x); i++) {
+		if (res_x[i] >= *width && res_y[i] >= *height) {
+			*width = res_x[i];
+			*height = res_y[i];
+			return;
+		}
+	}
+
+	*width = res_x[SXGA];
+	*height = res_y[SXGA];
+}
+
+/* Prepare necessary register changes depending on color encoding */
+static void ov9640_alter_regs(enum v4l2_mbus_pixelcode code,
+			      struct ov9640_reg_alt *alt)
+{
+	switch (code) {
+	default:
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		alt->com12	= OV9640_COM12_YUV_AVG;
+		alt->com13	= OV9640_COM13_Y_DELAY_EN |
+					OV9640_COM13_YUV_DLY(0x01);
+		break;
+	case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+		alt->com7	= OV9640_COM7_RGB;
+		alt->com13	= OV9640_COM13_RGB_AVG;
+		alt->com15	= OV9640_COM15_RGB_555;
+		break;
+	case V4L2_MBUS_FMT_RGB565_2X8_LE:
+		alt->com7	= OV9640_COM7_RGB;
+		alt->com13	= OV9640_COM13_RGB_AVG;
+		alt->com15	= OV9640_COM15_RGB_565;
+		break;
+	};
+}
+
+/* Setup registers according to resolution and color encoding */
+static int ov9640_write_regs(struct i2c_client *client, u32 width,
+		enum v4l2_mbus_pixelcode code, struct ov9640_reg_alt *alts)
+{
+	const struct ov9640_reg	*ov9640_regs, *matrix_regs;
+	int			ov9640_regs_len, matrix_regs_len;
+	int			i, ret;
+	u8			val;
+
+	/* select register configuration for given resolution */
+	switch (width) {
+	case W_QQCIF:
+		ov9640_regs	= ov9640_regs_qqcif;
+		ov9640_regs_len	= ARRAY_SIZE(ov9640_regs_qqcif);
+		break;
+	case W_QQVGA:
+		ov9640_regs	= ov9640_regs_qqvga;
+		ov9640_regs_len	= ARRAY_SIZE(ov9640_regs_qqvga);
+		break;
+	case W_QCIF:
+		ov9640_regs	= ov9640_regs_qcif;
+		ov9640_regs_len	= ARRAY_SIZE(ov9640_regs_qcif);
+		break;
+	case W_QVGA:
+		ov9640_regs	= ov9640_regs_qvga;
+		ov9640_regs_len	= ARRAY_SIZE(ov9640_regs_qvga);
+		break;
+	case W_CIF:
+		ov9640_regs	= ov9640_regs_cif;
+		ov9640_regs_len	= ARRAY_SIZE(ov9640_regs_cif);
+		break;
+	case W_VGA:
+		ov9640_regs	= ov9640_regs_vga;
+		ov9640_regs_len	= ARRAY_SIZE(ov9640_regs_vga);
+		break;
+	case W_SXGA:
+		ov9640_regs	= ov9640_regs_sxga;
+		ov9640_regs_len	= ARRAY_SIZE(ov9640_regs_sxga);
+		break;
+	default:
+		dev_err(&client->dev, "Failed to select resolution!\n");
+		return -EINVAL;
+	}
+
+	/* select color matrix configuration for given color encoding */
+	if (code == V4L2_MBUS_FMT_UYVY8_2X8) {
+		matrix_regs	= ov9640_regs_yuv;
+		matrix_regs_len	= ARRAY_SIZE(ov9640_regs_yuv);
+	} else {
+		matrix_regs	= ov9640_regs_rgb;
+		matrix_regs_len	= ARRAY_SIZE(ov9640_regs_rgb);
+	}
+
+	/* write register settings into the module */
+	for (i = 0; i < ov9640_regs_len; i++) {
+		val = ov9640_regs[i].val;
+
+		switch (ov9640_regs[i].reg) {
+		case OV9640_COM7:
+			val |= alts->com7;
+			break;
+		case OV9640_COM12:
+			val |= alts->com12;
+			break;
+		case OV9640_COM13:
+			val |= alts->com13;
+			break;
+		case OV9640_COM15:
+			val |= alts->com15;
+			break;
+		}
+
+		ret = ov9640_reg_write(client, ov9640_regs[i].reg, val);
+		if (ret)
+			return ret;
+	}
+
+	/* write color matrix configuration into the module */
+	for (i = 0; i < matrix_regs_len; i++) {
+		ret = ov9640_reg_write(client, matrix_regs[i].reg,
+						matrix_regs[i].val);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+/* program default register values */
+static int ov9640_prog_dflt(struct i2c_client *client)
+{
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(ov9640_regs_dflt); i++) {
+		ret = ov9640_reg_write(client, ov9640_regs_dflt[i].reg,
+						ov9640_regs_dflt[i].val);
+		if (ret)
+			return ret;
+	}
+
+	/* wait for the changes to actually happen, 140ms are not enough yet */
+	mdelay(150);
+
+	return 0;
+}
+
+/* set the format we will capture in */
+static int ov9640_s_fmt(struct v4l2_subdev *sd,
+			struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov9640_reg_alt alts = {0};
+	enum v4l2_colorspace cspace;
+	enum v4l2_mbus_pixelcode code = mf->code;
+	int ret;
+
+	ov9640_res_roundup(&mf->width, &mf->height);
+	ov9640_alter_regs(mf->code, &alts);
+
+	ov9640_reset(client);
+
+	ret = ov9640_prog_dflt(client);
+	if (ret)
+		return ret;
+
+	switch (code) {
+	case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+	case V4L2_MBUS_FMT_RGB565_2X8_LE:
+		cspace = V4L2_COLORSPACE_SRGB;
+		break;
+	default:
+		code = V4L2_MBUS_FMT_UYVY8_2X8;
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		cspace = V4L2_COLORSPACE_JPEG;
+	}
+
+	ret = ov9640_write_regs(client, mf->width, code, &alts);
+	if (!ret) {
+		mf->code	= code;
+		mf->colorspace	= cspace;
+	}
+
+	return ret;
+}
+
+static int ov9640_try_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_mbus_framefmt *mf)
+{
+	ov9640_res_roundup(&mf->width, &mf->height);
+
+	mf->field = V4L2_FIELD_NONE;
+
+	switch (mf->code) {
+	case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+	case V4L2_MBUS_FMT_RGB565_2X8_LE:
+		mf->colorspace = V4L2_COLORSPACE_SRGB;
+		break;
+	default:
+		mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		mf->colorspace = V4L2_COLORSPACE_JPEG;
+	}
+
+	return 0;
+}
+
+static int ov9640_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			   enum v4l2_mbus_pixelcode *code)
+{
+	if (index >= ARRAY_SIZE(ov9640_codes))
+		return -EINVAL;
+
+	*code = ov9640_codes[index];
+	return 0;
+}
+
+static int ov9640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	a->c.left	= 0;
+	a->c.top	= 0;
+	a->c.width	= W_SXGA;
+	a->c.height	= H_SXGA;
+	a->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int ov9640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	a->bounds.left			= 0;
+	a->bounds.top			= 0;
+	a->bounds.width			= W_SXGA;
+	a->bounds.height		= H_SXGA;
+	a->defrect			= a->bounds;
+	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int ov9640_video_probe(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov9640_priv *priv = to_ov9640_sensor(sd);
+	u8		pid, ver, midh, midl;
+	const char	*devname;
+	int		ret;
+
+	ret = ov9640_s_power(&priv->subdev, 1);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * check and show product ID and manufacturer ID
+	 */
+
+	ret = ov9640_reg_read(client, OV9640_PID, &pid);
+	if (!ret)
+		ret = ov9640_reg_read(client, OV9640_VER, &ver);
+	if (!ret)
+		ret = ov9640_reg_read(client, OV9640_MIDH, &midh);
+	if (!ret)
+		ret = ov9640_reg_read(client, OV9640_MIDL, &midl);
+	if (ret)
+		goto done;
+
+	switch (VERSION(pid, ver)) {
+	case OV9640_V2:
+		devname		= "ov9640";
+		priv->model	= V4L2_IDENT_OV9640;
+		priv->revision	= 2;
+		break;
+	case OV9640_V3:
+		devname		= "ov9640";
+		priv->model	= V4L2_IDENT_OV9640;
+		priv->revision	= 3;
+		break;
+	default:
+		dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver);
+		ret = -ENODEV;
+		goto done;
+	}
+
+	dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
+		 devname, pid, ver, midh, midl);
+
+	ret = v4l2_ctrl_handler_setup(&priv->hdl);
+
+done:
+	ov9640_s_power(&priv->subdev, 0);
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops ov9640_ctrl_ops = {
+	.s_ctrl = ov9640_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops ov9640_core_ops = {
+	.g_chip_ident		= ov9640_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register		= ov9640_get_register,
+	.s_register		= ov9640_set_register,
+#endif
+	.s_power		= ov9640_s_power,
+};
+
+/* Request bus settings on camera side */
+static int ov9640_g_mbus_config(struct v4l2_subdev *sd,
+				struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
+		V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+		V4L2_MBUS_DATA_ACTIVE_HIGH;
+	cfg->type = V4L2_MBUS_PARALLEL;
+	cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+	return 0;
+}
+
+static struct v4l2_subdev_video_ops ov9640_video_ops = {
+	.s_stream	= ov9640_s_stream,
+	.s_mbus_fmt	= ov9640_s_fmt,
+	.try_mbus_fmt	= ov9640_try_fmt,
+	.enum_mbus_fmt	= ov9640_enum_fmt,
+	.cropcap	= ov9640_cropcap,
+	.g_crop		= ov9640_g_crop,
+	.g_mbus_config	= ov9640_g_mbus_config,
+};
+
+static struct v4l2_subdev_ops ov9640_subdev_ops = {
+	.core	= &ov9640_core_ops,
+	.video	= &ov9640_video_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+static int ov9640_probe(struct i2c_client *client,
+			const struct i2c_device_id *did)
+{
+	struct ov9640_priv *priv;
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	int ret;
+
+	if (!icl) {
+		dev_err(&client->dev, "Missing platform_data for driver\n");
+		return -EINVAL;
+	}
+
+	priv = kzalloc(sizeof(struct ov9640_priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&client->dev,
+			"Failed to allocate memory for private data!\n");
+		return -ENOMEM;
+	}
+
+	v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops);
+
+	v4l2_ctrl_handler_init(&priv->hdl, 2);
+	v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops,
+			V4L2_CID_HFLIP, 0, 1, 1, 0);
+	priv->subdev.ctrl_handler = &priv->hdl;
+	if (priv->hdl.error) {
+		int err = priv->hdl.error;
+
+		kfree(priv);
+		return err;
+	}
+
+	ret = ov9640_video_probe(client);
+
+	if (ret) {
+		v4l2_ctrl_handler_free(&priv->hdl);
+		kfree(priv);
+	}
+
+	return ret;
+}
+
+static int ov9640_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov9640_priv *priv = to_ov9640_sensor(sd);
+
+	v4l2_device_unregister_subdev(&priv->subdev);
+	v4l2_ctrl_handler_free(&priv->hdl);
+	kfree(priv);
+	return 0;
+}
+
+static const struct i2c_device_id ov9640_id[] = {
+	{ "ov9640", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ov9640_id);
+
+static struct i2c_driver ov9640_i2c_driver = {
+	.driver = {
+		.name = "ov9640",
+	},
+	.probe    = ov9640_probe,
+	.remove   = ov9640_remove,
+	.id_table = ov9640_id,
+};
+
+module_i2c_driver(ov9640_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx");
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/ov9640.h b/drivers/media/i2c/soc_camera/ov9640.h
new file mode 100644
index 0000000..6b33a97
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov9640.h
@@ -0,0 +1,207 @@
+/*
+ * OmniVision OV96xx Camera Header File
+ *
+ * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef	__DRIVERS_MEDIA_VIDEO_OV9640_H__
+#define	__DRIVERS_MEDIA_VIDEO_OV9640_H__
+
+/* Register definitions */
+#define	OV9640_GAIN	0x00
+#define	OV9640_BLUE	0x01
+#define	OV9640_RED	0x02
+#define	OV9640_VFER	0x03
+#define	OV9640_COM1	0x04
+#define	OV9640_BAVE	0x05
+#define	OV9640_GEAVE	0x06
+#define	OV9640_RSID	0x07
+#define	OV9640_RAVE	0x08
+#define	OV9640_COM2	0x09
+#define	OV9640_PID	0x0a
+#define	OV9640_VER	0x0b
+#define	OV9640_COM3	0x0c
+#define	OV9640_COM4	0x0d
+#define	OV9640_COM5	0x0e
+#define	OV9640_COM6	0x0f
+#define	OV9640_AECH	0x10
+#define	OV9640_CLKRC	0x11
+#define	OV9640_COM7	0x12
+#define	OV9640_COM8	0x13
+#define	OV9640_COM9	0x14
+#define	OV9640_COM10	0x15
+/* 0x16 - RESERVED */
+#define	OV9640_HSTART	0x17
+#define	OV9640_HSTOP	0x18
+#define	OV9640_VSTART	0x19
+#define	OV9640_VSTOP	0x1a
+#define	OV9640_PSHFT	0x1b
+#define	OV9640_MIDH	0x1c
+#define	OV9640_MIDL	0x1d
+#define	OV9640_MVFP	0x1e
+#define	OV9640_LAEC	0x1f
+#define	OV9640_BOS	0x20
+#define	OV9640_GBOS	0x21
+#define	OV9640_GROS	0x22
+#define	OV9640_ROS	0x23
+#define	OV9640_AEW	0x24
+#define	OV9640_AEB	0x25
+#define	OV9640_VPT	0x26
+#define	OV9640_BBIAS	0x27
+#define	OV9640_GBBIAS	0x28
+/* 0x29 - RESERVED */
+#define	OV9640_EXHCH	0x2a
+#define	OV9640_EXHCL	0x2b
+#define	OV9640_RBIAS	0x2c
+#define	OV9640_ADVFL	0x2d
+#define	OV9640_ADVFH	0x2e
+#define	OV9640_YAVE	0x2f
+#define	OV9640_HSYST	0x30
+#define	OV9640_HSYEN	0x31
+#define	OV9640_HREF	0x32
+#define	OV9640_CHLF	0x33
+#define	OV9640_ARBLM	0x34
+/* 0x35..0x36 - RESERVED */
+#define	OV9640_ADC	0x37
+#define	OV9640_ACOM	0x38
+#define	OV9640_OFON	0x39
+#define	OV9640_TSLB	0x3a
+#define	OV9640_COM11	0x3b
+#define	OV9640_COM12	0x3c
+#define	OV9640_COM13	0x3d
+#define	OV9640_COM14	0x3e
+#define	OV9640_EDGE	0x3f
+#define	OV9640_COM15	0x40
+#define	OV9640_COM16	0x41
+#define	OV9640_COM17	0x42
+/* 0x43..0x4e - RESERVED */
+#define	OV9640_MTX1	0x4f
+#define	OV9640_MTX2	0x50
+#define	OV9640_MTX3	0x51
+#define	OV9640_MTX4	0x52
+#define	OV9640_MTX5	0x53
+#define	OV9640_MTX6	0x54
+#define	OV9640_MTX7	0x55
+#define	OV9640_MTX8	0x56
+#define	OV9640_MTX9	0x57
+#define	OV9640_MTXS	0x58
+/* 0x59..0x61 - RESERVED */
+#define	OV9640_LCC1	0x62
+#define	OV9640_LCC2	0x63
+#define	OV9640_LCC3	0x64
+#define	OV9640_LCC4	0x65
+#define	OV9640_LCC5	0x66
+#define	OV9640_MANU	0x67
+#define	OV9640_MANV	0x68
+#define	OV9640_HV	0x69
+#define	OV9640_MBD	0x6a
+#define	OV9640_DBLV	0x6b
+#define	OV9640_GSP	0x6c	/* ... till 0x7b */
+#define	OV9640_GST	0x7c	/* ... till 0x8a */
+
+#define	OV9640_CLKRC_DPLL_EN	0x80
+#define	OV9640_CLKRC_DIRECT	0x40
+#define	OV9640_CLKRC_DIV(x)	((x) & 0x3f)
+
+#define	OV9640_PSHFT_VAL(x)	((x) & 0xff)
+
+#define	OV9640_ACOM_2X_ANALOG	0x80
+#define	OV9640_ACOM_RSVD	0x12
+
+#define	OV9640_MVFP_V		0x10
+#define	OV9640_MVFP_H		0x20
+
+#define	OV9640_COM1_HREF_NOSKIP	0x00
+#define	OV9640_COM1_HREF_2SKIP	0x04
+#define	OV9640_COM1_HREF_3SKIP	0x08
+#define	OV9640_COM1_QQFMT	0x20
+
+#define	OV9640_COM2_SSM		0x10
+
+#define	OV9640_COM3_VP		0x04
+
+#define	OV9640_COM4_QQ_VP	0x80
+#define	OV9640_COM4_RSVD	0x40
+
+#define	OV9640_COM5_SYSCLK	0x80
+#define	OV9640_COM5_LONGEXP	0x01
+
+#define	OV9640_COM6_OPT_BLC	0x40
+#define	OV9640_COM6_ADBLC_BIAS	0x08
+#define	OV9640_COM6_FMT_RST	0x82
+#define	OV9640_COM6_ADBLC_OPTEN	0x01
+
+#define	OV9640_COM7_RAW_RGB	0x01
+#define	OV9640_COM7_RGB		0x04
+#define	OV9640_COM7_QCIF	0x08
+#define	OV9640_COM7_QVGA	0x10
+#define	OV9640_COM7_CIF		0x20
+#define	OV9640_COM7_VGA		0x40
+#define	OV9640_COM7_SCCB_RESET	0x80
+
+#define	OV9640_TSLB_YVYU_YUYV	0x04
+#define	OV9640_TSLB_YUYV_UYVY	0x08
+
+#define	OV9640_COM12_YUV_AVG	0x04
+#define	OV9640_COM12_RSVD	0x40
+
+#define	OV9640_COM13_GAMMA_NONE	0x00
+#define	OV9640_COM13_GAMMA_Y	0x40
+#define	OV9640_COM13_GAMMA_RAW	0x80
+#define	OV9640_COM13_RGB_AVG	0x20
+#define	OV9640_COM13_MATRIX_EN	0x10
+#define	OV9640_COM13_Y_DELAY_EN	0x08
+#define	OV9640_COM13_YUV_DLY(x)	((x) & 0x07)
+
+#define	OV9640_COM15_OR_00FF	0x00
+#define	OV9640_COM15_OR_01FE	0x40
+#define	OV9640_COM15_OR_10F0	0xc0
+#define	OV9640_COM15_RGB_NORM	0x00
+#define	OV9640_COM15_RGB_565	0x10
+#define	OV9640_COM15_RGB_555	0x30
+
+#define	OV9640_COM16_RB_AVG	0x01
+
+/* IDs */
+#define	OV9640_V2		0x9648
+#define	OV9640_V3		0x9649
+#define	VERSION(pid, ver)	(((pid) << 8) | ((ver) & 0xFF))
+
+/* supported resolutions */
+enum {
+	W_QQCIF	= 88,
+	W_QQVGA	= 160,
+	W_QCIF	= 176,
+	W_QVGA	= 320,
+	W_CIF	= 352,
+	W_VGA	= 640,
+	W_SXGA	= 1280
+};
+#define	H_SXGA	960
+
+/* Misc. structures */
+struct ov9640_reg_alt {
+	u8	com7;
+	u8	com12;
+	u8	com13;
+	u8	com15;
+};
+
+struct ov9640_reg {
+	u8	reg;
+	u8	val;
+};
+
+struct ov9640_priv {
+	struct v4l2_subdev		subdev;
+	struct v4l2_ctrl_handler	hdl;
+
+	int				model;
+	int				revision;
+};
+
+#endif	/* __DRIVERS_MEDIA_VIDEO_OV9640_H__ */
diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c
new file mode 100644
index 0000000..7a55889
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov9740.c
@@ -0,0 +1,1020 @@
+/*
+ * OmniVision OV9740 Camera Driver
+ *
+ * Copyright (C) 2011 NVIDIA Corporation
+ *
+ * Based on ov9640 camera driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+#define to_ov9740(sd)		container_of(sd, struct ov9740_priv, subdev)
+
+/* General Status Registers */
+#define OV9740_MODEL_ID_HI		0x0000
+#define OV9740_MODEL_ID_LO		0x0001
+#define OV9740_REVISION_NUMBER		0x0002
+#define OV9740_MANUFACTURER_ID		0x0003
+#define OV9740_SMIA_VERSION		0x0004
+
+/* General Setup Registers */
+#define OV9740_MODE_SELECT		0x0100
+#define OV9740_IMAGE_ORT		0x0101
+#define OV9740_SOFTWARE_RESET		0x0103
+#define OV9740_GRP_PARAM_HOLD		0x0104
+#define OV9740_MSK_CORRUP_FM		0x0105
+
+/* Timing Setting */
+#define OV9740_FRM_LENGTH_LN_HI		0x0340 /* VTS */
+#define OV9740_FRM_LENGTH_LN_LO		0x0341 /* VTS */
+#define OV9740_LN_LENGTH_PCK_HI		0x0342 /* HTS */
+#define OV9740_LN_LENGTH_PCK_LO		0x0343 /* HTS */
+#define OV9740_X_ADDR_START_HI		0x0344
+#define OV9740_X_ADDR_START_LO		0x0345
+#define OV9740_Y_ADDR_START_HI		0x0346
+#define OV9740_Y_ADDR_START_LO		0x0347
+#define OV9740_X_ADDR_END_HI		0x0348
+#define OV9740_X_ADDR_END_LO		0x0349
+#define OV9740_Y_ADDR_END_HI		0x034a
+#define OV9740_Y_ADDR_END_LO		0x034b
+#define OV9740_X_OUTPUT_SIZE_HI		0x034c
+#define OV9740_X_OUTPUT_SIZE_LO		0x034d
+#define OV9740_Y_OUTPUT_SIZE_HI		0x034e
+#define OV9740_Y_OUTPUT_SIZE_LO		0x034f
+
+/* IO Control Registers */
+#define OV9740_IO_CREL00		0x3002
+#define OV9740_IO_CREL01		0x3004
+#define OV9740_IO_CREL02		0x3005
+#define OV9740_IO_OUTPUT_SEL01		0x3026
+#define OV9740_IO_OUTPUT_SEL02		0x3027
+
+/* AWB Registers */
+#define OV9740_AWB_MANUAL_CTRL		0x3406
+
+/* Analog Control Registers */
+#define OV9740_ANALOG_CTRL01		0x3601
+#define OV9740_ANALOG_CTRL02		0x3602
+#define OV9740_ANALOG_CTRL03		0x3603
+#define OV9740_ANALOG_CTRL04		0x3604
+#define OV9740_ANALOG_CTRL10		0x3610
+#define OV9740_ANALOG_CTRL12		0x3612
+#define OV9740_ANALOG_CTRL15		0x3615
+#define OV9740_ANALOG_CTRL20		0x3620
+#define OV9740_ANALOG_CTRL21		0x3621
+#define OV9740_ANALOG_CTRL22		0x3622
+#define OV9740_ANALOG_CTRL30		0x3630
+#define OV9740_ANALOG_CTRL31		0x3631
+#define OV9740_ANALOG_CTRL32		0x3632
+#define OV9740_ANALOG_CTRL33		0x3633
+
+/* Sensor Control */
+#define OV9740_SENSOR_CTRL03		0x3703
+#define OV9740_SENSOR_CTRL04		0x3704
+#define OV9740_SENSOR_CTRL05		0x3705
+#define OV9740_SENSOR_CTRL07		0x3707
+
+/* Timing Control */
+#define OV9740_TIMING_CTRL17		0x3817
+#define OV9740_TIMING_CTRL19		0x3819
+#define OV9740_TIMING_CTRL33		0x3833
+#define OV9740_TIMING_CTRL35		0x3835
+
+/* Banding Filter */
+#define OV9740_AEC_MAXEXPO_60_H		0x3a02
+#define OV9740_AEC_MAXEXPO_60_L		0x3a03
+#define OV9740_AEC_B50_STEP_HI		0x3a08
+#define OV9740_AEC_B50_STEP_LO		0x3a09
+#define OV9740_AEC_B60_STEP_HI		0x3a0a
+#define OV9740_AEC_B60_STEP_LO		0x3a0b
+#define OV9740_AEC_CTRL0D		0x3a0d
+#define OV9740_AEC_CTRL0E		0x3a0e
+#define OV9740_AEC_MAXEXPO_50_H		0x3a14
+#define OV9740_AEC_MAXEXPO_50_L		0x3a15
+
+/* AEC/AGC Control */
+#define OV9740_AEC_ENABLE		0x3503
+#define OV9740_GAIN_CEILING_01		0x3a18
+#define OV9740_GAIN_CEILING_02		0x3a19
+#define OV9740_AEC_HI_THRESHOLD		0x3a11
+#define OV9740_AEC_3A1A			0x3a1a
+#define OV9740_AEC_CTRL1B_WPT2		0x3a1b
+#define OV9740_AEC_CTRL0F_WPT		0x3a0f
+#define OV9740_AEC_CTRL10_BPT		0x3a10
+#define OV9740_AEC_CTRL1E_BPT2		0x3a1e
+#define OV9740_AEC_LO_THRESHOLD		0x3a1f
+
+/* BLC Control */
+#define OV9740_BLC_AUTO_ENABLE		0x4002
+#define OV9740_BLC_MODE			0x4005
+
+/* VFIFO */
+#define OV9740_VFIFO_READ_START_HI	0x4608
+#define OV9740_VFIFO_READ_START_LO	0x4609
+
+/* DVP Control */
+#define OV9740_DVP_VSYNC_CTRL02		0x4702
+#define OV9740_DVP_VSYNC_MODE		0x4704
+#define OV9740_DVP_VSYNC_CTRL06		0x4706
+
+/* PLL Setting */
+#define OV9740_PLL_MODE_CTRL01		0x3104
+#define OV9740_PRE_PLL_CLK_DIV		0x0305
+#define OV9740_PLL_MULTIPLIER		0x0307
+#define OV9740_VT_SYS_CLK_DIV		0x0303
+#define OV9740_VT_PIX_CLK_DIV		0x0301
+#define OV9740_PLL_CTRL3010		0x3010
+#define OV9740_VFIFO_CTRL00		0x460e
+
+/* ISP Control */
+#define OV9740_ISP_CTRL00		0x5000
+#define OV9740_ISP_CTRL01		0x5001
+#define OV9740_ISP_CTRL03		0x5003
+#define OV9740_ISP_CTRL05		0x5005
+#define OV9740_ISP_CTRL12		0x5012
+#define OV9740_ISP_CTRL19		0x5019
+#define OV9740_ISP_CTRL1A		0x501a
+#define OV9740_ISP_CTRL1E		0x501e
+#define OV9740_ISP_CTRL1F		0x501f
+#define OV9740_ISP_CTRL20		0x5020
+#define OV9740_ISP_CTRL21		0x5021
+
+/* AWB */
+#define OV9740_AWB_CTRL00		0x5180
+#define OV9740_AWB_CTRL01		0x5181
+#define OV9740_AWB_CTRL02		0x5182
+#define OV9740_AWB_CTRL03		0x5183
+#define OV9740_AWB_ADV_CTRL01		0x5184
+#define OV9740_AWB_ADV_CTRL02		0x5185
+#define OV9740_AWB_ADV_CTRL03		0x5186
+#define OV9740_AWB_ADV_CTRL04		0x5187
+#define OV9740_AWB_ADV_CTRL05		0x5188
+#define OV9740_AWB_ADV_CTRL06		0x5189
+#define OV9740_AWB_ADV_CTRL07		0x518a
+#define OV9740_AWB_ADV_CTRL08		0x518b
+#define OV9740_AWB_ADV_CTRL09		0x518c
+#define OV9740_AWB_ADV_CTRL10		0x518d
+#define OV9740_AWB_ADV_CTRL11		0x518e
+#define OV9740_AWB_CTRL0F		0x518f
+#define OV9740_AWB_CTRL10		0x5190
+#define OV9740_AWB_CTRL11		0x5191
+#define OV9740_AWB_CTRL12		0x5192
+#define OV9740_AWB_CTRL13		0x5193
+#define OV9740_AWB_CTRL14		0x5194
+
+/* MIPI Control */
+#define OV9740_MIPI_CTRL00		0x4800
+#define OV9740_MIPI_3837		0x3837
+#define OV9740_MIPI_CTRL01		0x4801
+#define OV9740_MIPI_CTRL03		0x4803
+#define OV9740_MIPI_CTRL05		0x4805
+#define OV9740_VFIFO_RD_CTRL		0x4601
+#define OV9740_MIPI_CTRL_3012		0x3012
+#define OV9740_SC_CMMM_MIPI_CTR		0x3014
+
+#define OV9740_MAX_WIDTH		1280
+#define OV9740_MAX_HEIGHT		720
+
+/* Misc. structures */
+struct ov9740_reg {
+	u16				reg;
+	u8				val;
+};
+
+struct ov9740_priv {
+	struct v4l2_subdev		subdev;
+	struct v4l2_ctrl_handler	hdl;
+
+	int				ident;
+	u16				model;
+	u8				revision;
+	u8				manid;
+	u8				smiaver;
+
+	bool				flag_vflip;
+	bool				flag_hflip;
+
+	/* For suspend/resume. */
+	struct v4l2_mbus_framefmt	current_mf;
+	bool				current_enable;
+};
+
+static const struct ov9740_reg ov9740_defaults[] = {
+	/* Software Reset */
+	{ OV9740_SOFTWARE_RESET,	0x01 },
+
+	/* Banding Filter */
+	{ OV9740_AEC_B50_STEP_HI,	0x00 },
+	{ OV9740_AEC_B50_STEP_LO,	0xe8 },
+	{ OV9740_AEC_CTRL0E,		0x03 },
+	{ OV9740_AEC_MAXEXPO_50_H,	0x15 },
+	{ OV9740_AEC_MAXEXPO_50_L,	0xc6 },
+	{ OV9740_AEC_B60_STEP_HI,	0x00 },
+	{ OV9740_AEC_B60_STEP_LO,	0xc0 },
+	{ OV9740_AEC_CTRL0D,		0x04 },
+	{ OV9740_AEC_MAXEXPO_60_H,	0x18 },
+	{ OV9740_AEC_MAXEXPO_60_L,	0x20 },
+
+	/* LC */
+	{ 0x5842, 0x02 }, { 0x5843, 0x5e }, { 0x5844, 0x04 }, { 0x5845, 0x32 },
+	{ 0x5846, 0x03 }, { 0x5847, 0x29 }, { 0x5848, 0x02 }, { 0x5849, 0xcc },
+
+	/* Un-documented OV9740 registers */
+	{ 0x5800, 0x29 }, { 0x5801, 0x25 }, { 0x5802, 0x20 }, { 0x5803, 0x21 },
+	{ 0x5804, 0x26 }, { 0x5805, 0x2e }, { 0x5806, 0x11 }, { 0x5807, 0x0c },
+	{ 0x5808, 0x09 }, { 0x5809, 0x0a }, { 0x580a, 0x0e }, { 0x580b, 0x16 },
+	{ 0x580c, 0x06 }, { 0x580d, 0x02 }, { 0x580e, 0x00 }, { 0x580f, 0x00 },
+	{ 0x5810, 0x04 }, { 0x5811, 0x0a }, { 0x5812, 0x05 }, { 0x5813, 0x02 },
+	{ 0x5814, 0x00 }, { 0x5815, 0x00 }, { 0x5816, 0x03 }, { 0x5817, 0x09 },
+	{ 0x5818, 0x0f }, { 0x5819, 0x0a }, { 0x581a, 0x07 }, { 0x581b, 0x08 },
+	{ 0x581c, 0x0b }, { 0x581d, 0x14 }, { 0x581e, 0x28 }, { 0x581f, 0x23 },
+	{ 0x5820, 0x1d }, { 0x5821, 0x1e }, { 0x5822, 0x24 }, { 0x5823, 0x2a },
+	{ 0x5824, 0x4f }, { 0x5825, 0x6f }, { 0x5826, 0x5f }, { 0x5827, 0x7f },
+	{ 0x5828, 0x9f }, { 0x5829, 0x5f }, { 0x582a, 0x8f }, { 0x582b, 0x9e },
+	{ 0x582c, 0x8f }, { 0x582d, 0x9f }, { 0x582e, 0x4f }, { 0x582f, 0x87 },
+	{ 0x5830, 0x86 }, { 0x5831, 0x97 }, { 0x5832, 0xae }, { 0x5833, 0x3f },
+	{ 0x5834, 0x8e }, { 0x5835, 0x7c }, { 0x5836, 0x7e }, { 0x5837, 0xaf },
+	{ 0x5838, 0x8f }, { 0x5839, 0x8f }, { 0x583a, 0x9f }, { 0x583b, 0x7f },
+	{ 0x583c, 0x5f },
+
+	/* Y Gamma */
+	{ 0x5480, 0x07 }, { 0x5481, 0x18 }, { 0x5482, 0x2c }, { 0x5483, 0x4e },
+	{ 0x5484, 0x5e }, { 0x5485, 0x6b }, { 0x5486, 0x77 }, { 0x5487, 0x82 },
+	{ 0x5488, 0x8c }, { 0x5489, 0x95 }, { 0x548a, 0xa4 }, { 0x548b, 0xb1 },
+	{ 0x548c, 0xc6 }, { 0x548d, 0xd8 }, { 0x548e, 0xe9 },
+
+	/* UV Gamma */
+	{ 0x5490, 0x0f }, { 0x5491, 0xff }, { 0x5492, 0x0d }, { 0x5493, 0x05 },
+	{ 0x5494, 0x07 }, { 0x5495, 0x1a }, { 0x5496, 0x04 }, { 0x5497, 0x01 },
+	{ 0x5498, 0x03 }, { 0x5499, 0x53 }, { 0x549a, 0x02 }, { 0x549b, 0xeb },
+	{ 0x549c, 0x02 }, { 0x549d, 0xa0 }, { 0x549e, 0x02 }, { 0x549f, 0x67 },
+	{ 0x54a0, 0x02 }, { 0x54a1, 0x3b }, { 0x54a2, 0x02 }, { 0x54a3, 0x18 },
+	{ 0x54a4, 0x01 }, { 0x54a5, 0xe7 }, { 0x54a6, 0x01 }, { 0x54a7, 0xc3 },
+	{ 0x54a8, 0x01 }, { 0x54a9, 0x94 }, { 0x54aa, 0x01 }, { 0x54ab, 0x72 },
+	{ 0x54ac, 0x01 }, { 0x54ad, 0x57 },
+
+	/* AWB */
+	{ OV9740_AWB_CTRL00,		0xf0 },
+	{ OV9740_AWB_CTRL01,		0x00 },
+	{ OV9740_AWB_CTRL02,		0x41 },
+	{ OV9740_AWB_CTRL03,		0x42 },
+	{ OV9740_AWB_ADV_CTRL01,	0x8a },
+	{ OV9740_AWB_ADV_CTRL02,	0x61 },
+	{ OV9740_AWB_ADV_CTRL03,	0xce },
+	{ OV9740_AWB_ADV_CTRL04,	0xa8 },
+	{ OV9740_AWB_ADV_CTRL05,	0x17 },
+	{ OV9740_AWB_ADV_CTRL06,	0x1f },
+	{ OV9740_AWB_ADV_CTRL07,	0x27 },
+	{ OV9740_AWB_ADV_CTRL08,	0x41 },
+	{ OV9740_AWB_ADV_CTRL09,	0x34 },
+	{ OV9740_AWB_ADV_CTRL10,	0xf0 },
+	{ OV9740_AWB_ADV_CTRL11,	0x10 },
+	{ OV9740_AWB_CTRL0F,		0xff },
+	{ OV9740_AWB_CTRL10,		0x00 },
+	{ OV9740_AWB_CTRL11,		0xff },
+	{ OV9740_AWB_CTRL12,		0x00 },
+	{ OV9740_AWB_CTRL13,		0xff },
+	{ OV9740_AWB_CTRL14,		0x00 },
+
+	/* CIP */
+	{ 0x530d, 0x12 },
+
+	/* CMX */
+	{ 0x5380, 0x01 }, { 0x5381, 0x00 }, { 0x5382, 0x00 }, { 0x5383, 0x17 },
+	{ 0x5384, 0x00 }, { 0x5385, 0x01 }, { 0x5386, 0x00 }, { 0x5387, 0x00 },
+	{ 0x5388, 0x00 }, { 0x5389, 0xe0 }, { 0x538a, 0x00 }, { 0x538b, 0x20 },
+	{ 0x538c, 0x00 }, { 0x538d, 0x00 }, { 0x538e, 0x00 }, { 0x538f, 0x16 },
+	{ 0x5390, 0x00 }, { 0x5391, 0x9c }, { 0x5392, 0x00 }, { 0x5393, 0xa0 },
+	{ 0x5394, 0x18 },
+
+	/* 50/60 Detection */
+	{ 0x3c0a, 0x9c }, { 0x3c0b, 0x3f },
+
+	/* Output Select */
+	{ OV9740_IO_OUTPUT_SEL01,	0x00 },
+	{ OV9740_IO_OUTPUT_SEL02,	0x00 },
+	{ OV9740_IO_CREL00,		0x00 },
+	{ OV9740_IO_CREL01,		0x00 },
+	{ OV9740_IO_CREL02,		0x00 },
+
+	/* AWB Control */
+	{ OV9740_AWB_MANUAL_CTRL,	0x00 },
+
+	/* Analog Control */
+	{ OV9740_ANALOG_CTRL03,		0xaa },
+	{ OV9740_ANALOG_CTRL32,		0x2f },
+	{ OV9740_ANALOG_CTRL20,		0x66 },
+	{ OV9740_ANALOG_CTRL21,		0xc0 },
+	{ OV9740_ANALOG_CTRL31,		0x52 },
+	{ OV9740_ANALOG_CTRL33,		0x50 },
+	{ OV9740_ANALOG_CTRL30,		0xca },
+	{ OV9740_ANALOG_CTRL04,		0x0c },
+	{ OV9740_ANALOG_CTRL01,		0x40 },
+	{ OV9740_ANALOG_CTRL02,		0x16 },
+	{ OV9740_ANALOG_CTRL10,		0xa1 },
+	{ OV9740_ANALOG_CTRL12,		0x24 },
+	{ OV9740_ANALOG_CTRL22,		0x9f },
+	{ OV9740_ANALOG_CTRL15,		0xf0 },
+
+	/* Sensor Control */
+	{ OV9740_SENSOR_CTRL03,		0x42 },
+	{ OV9740_SENSOR_CTRL04,		0x10 },
+	{ OV9740_SENSOR_CTRL05,		0x45 },
+	{ OV9740_SENSOR_CTRL07,		0x14 },
+
+	/* Timing Control */
+	{ OV9740_TIMING_CTRL33,		0x04 },
+	{ OV9740_TIMING_CTRL35,		0x02 },
+	{ OV9740_TIMING_CTRL19,		0x6e },
+	{ OV9740_TIMING_CTRL17,		0x94 },
+
+	/* AEC/AGC Control */
+	{ OV9740_AEC_ENABLE,		0x10 },
+	{ OV9740_GAIN_CEILING_01,	0x00 },
+	{ OV9740_GAIN_CEILING_02,	0x7f },
+	{ OV9740_AEC_HI_THRESHOLD,	0xa0 },
+	{ OV9740_AEC_3A1A,		0x05 },
+	{ OV9740_AEC_CTRL1B_WPT2,	0x50 },
+	{ OV9740_AEC_CTRL0F_WPT,	0x50 },
+	{ OV9740_AEC_CTRL10_BPT,	0x4c },
+	{ OV9740_AEC_CTRL1E_BPT2,	0x4c },
+	{ OV9740_AEC_LO_THRESHOLD,	0x26 },
+
+	/* BLC Control */
+	{ OV9740_BLC_AUTO_ENABLE,	0x45 },
+	{ OV9740_BLC_MODE,		0x18 },
+
+	/* DVP Control */
+	{ OV9740_DVP_VSYNC_CTRL02,	0x04 },
+	{ OV9740_DVP_VSYNC_MODE,	0x00 },
+	{ OV9740_DVP_VSYNC_CTRL06,	0x08 },
+
+	/* PLL Setting */
+	{ OV9740_PLL_MODE_CTRL01,	0x20 },
+	{ OV9740_PRE_PLL_CLK_DIV,	0x03 },
+	{ OV9740_PLL_MULTIPLIER,	0x4c },
+	{ OV9740_VT_SYS_CLK_DIV,	0x01 },
+	{ OV9740_VT_PIX_CLK_DIV,	0x08 },
+	{ OV9740_PLL_CTRL3010,		0x01 },
+	{ OV9740_VFIFO_CTRL00,		0x82 },
+
+	/* Timing Setting */
+	/* VTS */
+	{ OV9740_FRM_LENGTH_LN_HI,	0x03 },
+	{ OV9740_FRM_LENGTH_LN_LO,	0x07 },
+	/* HTS */
+	{ OV9740_LN_LENGTH_PCK_HI,	0x06 },
+	{ OV9740_LN_LENGTH_PCK_LO,	0x62 },
+
+	/* MIPI Control */
+	{ OV9740_MIPI_CTRL00,		0x44 }, /* 0x64 for discontinuous clk */
+	{ OV9740_MIPI_3837,		0x01 },
+	{ OV9740_MIPI_CTRL01,		0x0f },
+	{ OV9740_MIPI_CTRL03,		0x05 },
+	{ OV9740_MIPI_CTRL05,		0x10 },
+	{ OV9740_VFIFO_RD_CTRL,		0x16 },
+	{ OV9740_MIPI_CTRL_3012,	0x70 },
+	{ OV9740_SC_CMMM_MIPI_CTR,	0x01 },
+
+	/* YUYV order */
+	{ OV9740_ISP_CTRL19,		0x02 },
+};
+
+static enum v4l2_mbus_pixelcode ov9740_codes[] = {
+	V4L2_MBUS_FMT_YUYV8_2X8,
+};
+
+/* read a register */
+static int ov9740_reg_read(struct i2c_client *client, u16 reg, u8 *val)
+{
+	int ret;
+	struct i2c_msg msg[] = {
+		{
+			.addr	= client->addr,
+			.flags	= 0,
+			.len	= 2,
+			.buf	= (u8 *)&reg,
+		},
+		{
+			.addr	= client->addr,
+			.flags	= I2C_M_RD,
+			.len	= 1,
+			.buf	= val,
+		},
+	};
+
+	reg = swab16(reg);
+
+	ret = i2c_transfer(client->adapter, msg, 2);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed reading register 0x%04x!\n", reg);
+		return ret;
+	}
+
+	return 0;
+}
+
+/* write a register */
+static int ov9740_reg_write(struct i2c_client *client, u16 reg, u8 val)
+{
+	struct i2c_msg msg;
+	struct {
+		u16 reg;
+		u8 val;
+	} __packed buf;
+	int ret;
+
+	reg = swab16(reg);
+
+	buf.reg = reg;
+	buf.val = val;
+
+	msg.addr	= client->addr;
+	msg.flags	= 0;
+	msg.len		= 3;
+	msg.buf		= (u8 *)&buf;
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed writing register 0x%04x!\n", reg);
+		return ret;
+	}
+
+	return 0;
+}
+
+
+/* Read a register, alter its bits, write it back */
+static int ov9740_reg_rmw(struct i2c_client *client, u16 reg, u8 set, u8 unset)
+{
+	u8 val;
+	int ret;
+
+	ret = ov9740_reg_read(client, reg, &val);
+	if (ret < 0) {
+		dev_err(&client->dev,
+			"[Read]-Modify-Write of register 0x%04x failed!\n",
+			reg);
+		return ret;
+	}
+
+	val |= set;
+	val &= ~unset;
+
+	ret = ov9740_reg_write(client, reg, val);
+	if (ret < 0) {
+		dev_err(&client->dev,
+			"Read-Modify-[Write] of register 0x%04x failed!\n",
+			reg);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int ov9740_reg_write_array(struct i2c_client *client,
+				  const struct ov9740_reg *regarray,
+				  int regarraylen)
+{
+	int i;
+	int ret;
+
+	for (i = 0; i < regarraylen; i++) {
+		ret = ov9740_reg_write(client,
+				       regarray[i].reg, regarray[i].val);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+/* Start/Stop streaming from the device */
+static int ov9740_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov9740_priv *priv = to_ov9740(sd);
+	int ret;
+
+	/* Program orientation register. */
+	if (priv->flag_vflip)
+		ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x2, 0);
+	else
+		ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x2);
+	if (ret < 0)
+		return ret;
+
+	if (priv->flag_hflip)
+		ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x1, 0);
+	else
+		ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x1);
+	if (ret < 0)
+		return ret;
+
+	if (enable) {
+		dev_dbg(&client->dev, "Enabling Streaming\n");
+		/* Start Streaming */
+		ret = ov9740_reg_write(client, OV9740_MODE_SELECT, 0x01);
+
+	} else {
+		dev_dbg(&client->dev, "Disabling Streaming\n");
+		/* Software Reset */
+		ret = ov9740_reg_write(client, OV9740_SOFTWARE_RESET, 0x01);
+		if (!ret)
+			/* Setting Streaming to Standby */
+			ret = ov9740_reg_write(client, OV9740_MODE_SELECT,
+					       0x00);
+	}
+
+	priv->current_enable = enable;
+
+	return ret;
+}
+
+/* select nearest higher resolution for capture */
+static void ov9740_res_roundup(u32 *width, u32 *height)
+{
+	/* Width must be a multiple of 4 pixels. */
+	*width = ALIGN(*width, 4);
+
+	/* Max resolution is 1280x720 (720p). */
+	if (*width > OV9740_MAX_WIDTH)
+		*width = OV9740_MAX_WIDTH;
+
+	if (*height > OV9740_MAX_HEIGHT)
+		*height = OV9740_MAX_HEIGHT;
+}
+
+/* Setup registers according to resolution and color encoding */
+static int ov9740_set_res(struct i2c_client *client, u32 width, u32 height)
+{
+	u32 x_start;
+	u32 y_start;
+	u32 x_end;
+	u32 y_end;
+	bool scaling = 0;
+	u32 scale_input_x;
+	u32 scale_input_y;
+	int ret;
+
+	if ((width != OV9740_MAX_WIDTH) || (height != OV9740_MAX_HEIGHT))
+		scaling = 1;
+
+	/*
+	 * Try to use as much of the sensor area as possible when supporting
+	 * smaller resolutions.  Depending on the aspect ratio of the
+	 * chosen resolution, we can either use the full width of the sensor,
+	 * or the full height of the sensor (or both if the aspect ratio is
+	 * the same as 1280x720.
+	 */
+	if ((OV9740_MAX_WIDTH * height) > (OV9740_MAX_HEIGHT * width)) {
+		scale_input_x = (OV9740_MAX_HEIGHT * width) / height;
+		scale_input_y = OV9740_MAX_HEIGHT;
+	} else {
+		scale_input_x = OV9740_MAX_WIDTH;
+		scale_input_y = (OV9740_MAX_WIDTH * height) / width;
+	}
+
+	/* These describe the area of the sensor to use. */
+	x_start = (OV9740_MAX_WIDTH - scale_input_x) / 2;
+	y_start = (OV9740_MAX_HEIGHT - scale_input_y) / 2;
+	x_end = x_start + scale_input_x - 1;
+	y_end = y_start + scale_input_y - 1;
+
+	ret = ov9740_reg_write(client, OV9740_X_ADDR_START_HI, x_start >> 8);
+	if (ret)
+		goto done;
+	ret = ov9740_reg_write(client, OV9740_X_ADDR_START_LO, x_start & 0xff);
+	if (ret)
+		goto done;
+	ret = ov9740_reg_write(client, OV9740_Y_ADDR_START_HI, y_start >> 8);
+	if (ret)
+		goto done;
+	ret = ov9740_reg_write(client, OV9740_Y_ADDR_START_LO, y_start & 0xff);
+	if (ret)
+		goto done;
+
+	ret = ov9740_reg_write(client, OV9740_X_ADDR_END_HI, x_end >> 8);
+	if (ret)
+		goto done;
+	ret = ov9740_reg_write(client, OV9740_X_ADDR_END_LO, x_end & 0xff);
+	if (ret)
+		goto done;
+	ret = ov9740_reg_write(client, OV9740_Y_ADDR_END_HI, y_end >> 8);
+	if (ret)
+		goto done;
+	ret = ov9740_reg_write(client, OV9740_Y_ADDR_END_LO, y_end & 0xff);
+	if (ret)
+		goto done;
+
+	ret = ov9740_reg_write(client, OV9740_X_OUTPUT_SIZE_HI, width >> 8);
+	if (ret)
+		goto done;
+	ret = ov9740_reg_write(client, OV9740_X_OUTPUT_SIZE_LO, width & 0xff);
+	if (ret)
+		goto done;
+	ret = ov9740_reg_write(client, OV9740_Y_OUTPUT_SIZE_HI, height >> 8);
+	if (ret)
+		goto done;
+	ret = ov9740_reg_write(client, OV9740_Y_OUTPUT_SIZE_LO, height & 0xff);
+	if (ret)
+		goto done;
+
+	ret = ov9740_reg_write(client, OV9740_ISP_CTRL1E, scale_input_x >> 8);
+	if (ret)
+		goto done;
+	ret = ov9740_reg_write(client, OV9740_ISP_CTRL1F, scale_input_x & 0xff);
+	if (ret)
+		goto done;
+	ret = ov9740_reg_write(client, OV9740_ISP_CTRL20, scale_input_y >> 8);
+	if (ret)
+		goto done;
+	ret = ov9740_reg_write(client, OV9740_ISP_CTRL21, scale_input_y & 0xff);
+	if (ret)
+		goto done;
+
+	ret = ov9740_reg_write(client, OV9740_VFIFO_READ_START_HI,
+			       (scale_input_x - width) >> 8);
+	if (ret)
+		goto done;
+	ret = ov9740_reg_write(client, OV9740_VFIFO_READ_START_LO,
+			       (scale_input_x - width) & 0xff);
+	if (ret)
+		goto done;
+
+	ret = ov9740_reg_write(client, OV9740_ISP_CTRL00, 0xff);
+	if (ret)
+		goto done;
+	ret = ov9740_reg_write(client, OV9740_ISP_CTRL01, 0xef |
+							  (scaling << 4));
+	if (ret)
+		goto done;
+	ret = ov9740_reg_write(client, OV9740_ISP_CTRL03, 0xff);
+
+done:
+	return ret;
+}
+
+/* set the format we will capture in */
+static int ov9740_s_fmt(struct v4l2_subdev *sd,
+			struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov9740_priv *priv = to_ov9740(sd);
+	enum v4l2_colorspace cspace;
+	enum v4l2_mbus_pixelcode code = mf->code;
+	int ret;
+
+	ov9740_res_roundup(&mf->width, &mf->height);
+
+	switch (code) {
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+		cspace = V4L2_COLORSPACE_SRGB;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = ov9740_reg_write_array(client, ov9740_defaults,
+				     ARRAY_SIZE(ov9740_defaults));
+	if (ret < 0)
+		return ret;
+
+	ret = ov9740_set_res(client, mf->width, mf->height);
+	if (ret < 0)
+		return ret;
+
+	mf->code	= code;
+	mf->colorspace	= cspace;
+
+	memcpy(&priv->current_mf, mf, sizeof(struct v4l2_mbus_framefmt));
+
+	return ret;
+}
+
+static int ov9740_try_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_mbus_framefmt *mf)
+{
+	ov9740_res_roundup(&mf->width, &mf->height);
+
+	mf->field = V4L2_FIELD_NONE;
+	mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
+	mf->colorspace = V4L2_COLORSPACE_SRGB;
+
+	return 0;
+}
+
+static int ov9740_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			   enum v4l2_mbus_pixelcode *code)
+{
+	if (index >= ARRAY_SIZE(ov9740_codes))
+		return -EINVAL;
+
+	*code = ov9740_codes[index];
+
+	return 0;
+}
+
+static int ov9740_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	a->bounds.left		= 0;
+	a->bounds.top		= 0;
+	a->bounds.width		= OV9740_MAX_WIDTH;
+	a->bounds.height	= OV9740_MAX_HEIGHT;
+	a->defrect		= a->bounds;
+	a->type			= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int ov9740_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	a->c.left		= 0;
+	a->c.top		= 0;
+	a->c.width		= OV9740_MAX_WIDTH;
+	a->c.height		= OV9740_MAX_HEIGHT;
+	a->type			= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+/* Set status of additional camera capabilities */
+static int ov9740_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ov9740_priv *priv =
+		container_of(ctrl->handler, struct ov9740_priv, hdl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		priv->flag_vflip = ctrl->val;
+		break;
+	case V4L2_CID_HFLIP:
+		priv->flag_hflip = ctrl->val;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Get chip identification */
+static int ov9740_g_chip_ident(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_chip_ident *id)
+{
+	struct ov9740_priv *priv = to_ov9740(sd);
+
+	id->ident = priv->ident;
+	id->revision = priv->revision;
+
+	return 0;
+}
+
+static int ov9740_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	struct ov9740_priv *priv = to_ov9740(sd);
+	int ret;
+
+	if (on) {
+		ret = soc_camera_power_on(&client->dev, icl);
+		if (ret < 0)
+			return ret;
+
+		if (priv->current_enable) {
+			ov9740_s_fmt(sd, &priv->current_mf);
+			ov9740_s_stream(sd, 1);
+		}
+	} else {
+		if (priv->current_enable) {
+			ov9740_s_stream(sd, 0);
+			priv->current_enable = true;
+		}
+
+		soc_camera_power_off(&client->dev, icl);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov9740_get_register(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+	u8 val;
+
+	if (reg->reg & ~0xffff)
+		return -EINVAL;
+
+	reg->size = 2;
+
+	ret = ov9740_reg_read(client, reg->reg, &val);
+	if (ret)
+		return ret;
+
+	reg->val = (__u64)val;
+
+	return ret;
+}
+
+static int ov9740_set_register(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->reg & ~0xffff || reg->val & ~0xff)
+		return -EINVAL;
+
+	return ov9740_reg_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov9740_video_probe(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov9740_priv *priv = to_ov9740(sd);
+	u8 modelhi, modello;
+	int ret;
+
+	ret = ov9740_s_power(&priv->subdev, 1);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * check and show product ID and manufacturer ID
+	 */
+	ret = ov9740_reg_read(client, OV9740_MODEL_ID_HI, &modelhi);
+	if (ret < 0)
+		goto done;
+
+	ret = ov9740_reg_read(client, OV9740_MODEL_ID_LO, &modello);
+	if (ret < 0)
+		goto done;
+
+	priv->model = (modelhi << 8) | modello;
+
+	ret = ov9740_reg_read(client, OV9740_REVISION_NUMBER, &priv->revision);
+	if (ret < 0)
+		goto done;
+
+	ret = ov9740_reg_read(client, OV9740_MANUFACTURER_ID, &priv->manid);
+	if (ret < 0)
+		goto done;
+
+	ret = ov9740_reg_read(client, OV9740_SMIA_VERSION, &priv->smiaver);
+	if (ret < 0)
+		goto done;
+
+	if (priv->model != 0x9740) {
+		ret = -ENODEV;
+		goto done;
+	}
+
+	priv->ident = V4L2_IDENT_OV9740;
+
+	dev_info(&client->dev, "ov9740 Model ID 0x%04x, Revision 0x%02x, "
+		 "Manufacturer 0x%02x, SMIA Version 0x%02x\n",
+		 priv->model, priv->revision, priv->manid, priv->smiaver);
+
+	ret = v4l2_ctrl_handler_setup(&priv->hdl);
+
+done:
+	ov9740_s_power(&priv->subdev, 0);
+	return ret;
+}
+
+/* Request bus settings on camera side */
+static int ov9740_g_mbus_config(struct v4l2_subdev *sd,
+				struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
+		V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+		V4L2_MBUS_DATA_ACTIVE_HIGH;
+	cfg->type = V4L2_MBUS_PARALLEL;
+	cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+	return 0;
+}
+
+static struct v4l2_subdev_video_ops ov9740_video_ops = {
+	.s_stream	= ov9740_s_stream,
+	.s_mbus_fmt	= ov9740_s_fmt,
+	.try_mbus_fmt	= ov9740_try_fmt,
+	.enum_mbus_fmt	= ov9740_enum_fmt,
+	.cropcap	= ov9740_cropcap,
+	.g_crop		= ov9740_g_crop,
+	.g_mbus_config	= ov9740_g_mbus_config,
+};
+
+static struct v4l2_subdev_core_ops ov9740_core_ops = {
+	.g_chip_ident		= ov9740_g_chip_ident,
+	.s_power		= ov9740_s_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register		= ov9740_get_register,
+	.s_register		= ov9740_set_register,
+#endif
+};
+
+static struct v4l2_subdev_ops ov9740_subdev_ops = {
+	.core			= &ov9740_core_ops,
+	.video			= &ov9740_video_ops,
+};
+
+static const struct v4l2_ctrl_ops ov9740_ctrl_ops = {
+	.s_ctrl = ov9740_s_ctrl,
+};
+
+/*
+ * i2c_driver function
+ */
+static int ov9740_probe(struct i2c_client *client,
+			const struct i2c_device_id *did)
+{
+	struct ov9740_priv *priv;
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	int ret;
+
+	if (!icl) {
+		dev_err(&client->dev, "Missing platform_data for driver\n");
+		return -EINVAL;
+	}
+
+	priv = kzalloc(sizeof(struct ov9740_priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&client->dev, "Failed to allocate private data!\n");
+		return -ENOMEM;
+	}
+
+	v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops);
+	v4l2_ctrl_handler_init(&priv->hdl, 13);
+	v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops,
+			V4L2_CID_HFLIP, 0, 1, 1, 0);
+	priv->subdev.ctrl_handler = &priv->hdl;
+	if (priv->hdl.error) {
+		int err = priv->hdl.error;
+
+		kfree(priv);
+		return err;
+	}
+
+	ret = ov9740_video_probe(client);
+	if (ret < 0) {
+		v4l2_ctrl_handler_free(&priv->hdl);
+		kfree(priv);
+	}
+
+	return ret;
+}
+
+static int ov9740_remove(struct i2c_client *client)
+{
+	struct ov9740_priv *priv = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(&priv->subdev);
+	v4l2_ctrl_handler_free(&priv->hdl);
+	kfree(priv);
+	return 0;
+}
+
+static const struct i2c_device_id ov9740_id[] = {
+	{ "ov9740", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ov9740_id);
+
+static struct i2c_driver ov9740_i2c_driver = {
+	.driver = {
+		.name = "ov9740",
+	},
+	.probe    = ov9740_probe,
+	.remove   = ov9740_remove,
+	.id_table = ov9740_id,
+};
+
+module_i2c_driver(ov9740_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV9740");
+MODULE_AUTHOR("Andrew Chew <achew@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c
new file mode 100644
index 0000000..32226c9
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c
@@ -0,0 +1,1431 @@
+/*
+ * Driver for RJ54N1CB0C CMOS Image Sensor from Sharp
+ *
+ * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+
+#include <media/rj54n1cb0c.h>
+#include <media/soc_camera.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+#define RJ54N1_DEV_CODE			0x0400
+#define RJ54N1_DEV_CODE2		0x0401
+#define RJ54N1_OUT_SEL			0x0403
+#define RJ54N1_XY_OUTPUT_SIZE_S_H	0x0404
+#define RJ54N1_X_OUTPUT_SIZE_S_L	0x0405
+#define RJ54N1_Y_OUTPUT_SIZE_S_L	0x0406
+#define RJ54N1_XY_OUTPUT_SIZE_P_H	0x0407
+#define RJ54N1_X_OUTPUT_SIZE_P_L	0x0408
+#define RJ54N1_Y_OUTPUT_SIZE_P_L	0x0409
+#define RJ54N1_LINE_LENGTH_PCK_S_H	0x040a
+#define RJ54N1_LINE_LENGTH_PCK_S_L	0x040b
+#define RJ54N1_LINE_LENGTH_PCK_P_H	0x040c
+#define RJ54N1_LINE_LENGTH_PCK_P_L	0x040d
+#define RJ54N1_RESIZE_N			0x040e
+#define RJ54N1_RESIZE_N_STEP		0x040f
+#define RJ54N1_RESIZE_STEP		0x0410
+#define RJ54N1_RESIZE_HOLD_H		0x0411
+#define RJ54N1_RESIZE_HOLD_L		0x0412
+#define RJ54N1_H_OBEN_OFS		0x0413
+#define RJ54N1_V_OBEN_OFS		0x0414
+#define RJ54N1_RESIZE_CONTROL		0x0415
+#define RJ54N1_STILL_CONTROL		0x0417
+#define RJ54N1_INC_USE_SEL_H		0x0425
+#define RJ54N1_INC_USE_SEL_L		0x0426
+#define RJ54N1_MIRROR_STILL_MODE	0x0427
+#define RJ54N1_INIT_START		0x0428
+#define RJ54N1_SCALE_1_2_LEV		0x0429
+#define RJ54N1_SCALE_4_LEV		0x042a
+#define RJ54N1_Y_GAIN			0x04d8
+#define RJ54N1_APT_GAIN_UP		0x04fa
+#define RJ54N1_RA_SEL_UL		0x0530
+#define RJ54N1_BYTE_SWAP		0x0531
+#define RJ54N1_OUT_SIGPO		0x053b
+#define RJ54N1_WB_SEL_WEIGHT_I		0x054e
+#define RJ54N1_BIT8_WB			0x0569
+#define RJ54N1_HCAPS_WB			0x056a
+#define RJ54N1_VCAPS_WB			0x056b
+#define RJ54N1_HCAPE_WB			0x056c
+#define RJ54N1_VCAPE_WB			0x056d
+#define RJ54N1_EXPOSURE_CONTROL		0x058c
+#define RJ54N1_FRAME_LENGTH_S_H		0x0595
+#define RJ54N1_FRAME_LENGTH_S_L		0x0596
+#define RJ54N1_FRAME_LENGTH_P_H		0x0597
+#define RJ54N1_FRAME_LENGTH_P_L		0x0598
+#define RJ54N1_PEAK_H			0x05b7
+#define RJ54N1_PEAK_50			0x05b8
+#define RJ54N1_PEAK_60			0x05b9
+#define RJ54N1_PEAK_DIFF		0x05ba
+#define RJ54N1_IOC			0x05ef
+#define RJ54N1_TG_BYPASS		0x0700
+#define RJ54N1_PLL_L			0x0701
+#define RJ54N1_PLL_N			0x0702
+#define RJ54N1_PLL_EN			0x0704
+#define RJ54N1_RATIO_TG			0x0706
+#define RJ54N1_RATIO_T			0x0707
+#define RJ54N1_RATIO_R			0x0708
+#define RJ54N1_RAMP_TGCLK_EN		0x0709
+#define RJ54N1_OCLK_DSP			0x0710
+#define RJ54N1_RATIO_OP			0x0711
+#define RJ54N1_RATIO_O			0x0712
+#define RJ54N1_OCLK_SEL_EN		0x0713
+#define RJ54N1_CLK_RST			0x0717
+#define RJ54N1_RESET_STANDBY		0x0718
+#define RJ54N1_FWFLG			0x07fe
+
+#define E_EXCLK				(1 << 7)
+#define SOFT_STDBY			(1 << 4)
+#define SEN_RSTX			(1 << 2)
+#define TG_RSTX				(1 << 1)
+#define DSP_RSTX			(1 << 0)
+
+#define RESIZE_HOLD_SEL			(1 << 2)
+#define RESIZE_GO			(1 << 1)
+
+/*
+ * When cropping, the camera automatically centers the cropped region, there
+ * doesn't seem to be a way to specify an explicit location of the rectangle.
+ */
+#define RJ54N1_COLUMN_SKIP		0
+#define RJ54N1_ROW_SKIP			0
+#define RJ54N1_MAX_WIDTH		1600
+#define RJ54N1_MAX_HEIGHT		1200
+
+#define PLL_L				2
+#define PLL_N				0x31
+
+/* I2C addresses: 0x50, 0x51, 0x60, 0x61 */
+
+/* RJ54N1CB0C has only one fixed colorspace per pixelcode */
+struct rj54n1_datafmt {
+	enum v4l2_mbus_pixelcode	code;
+	enum v4l2_colorspace		colorspace;
+};
+
+/* Find a data format by a pixel code in an array */
+static const struct rj54n1_datafmt *rj54n1_find_datafmt(
+	enum v4l2_mbus_pixelcode code, const struct rj54n1_datafmt *fmt,
+	int n)
+{
+	int i;
+	for (i = 0; i < n; i++)
+		if (fmt[i].code == code)
+			return fmt + i;
+
+	return NULL;
+}
+
+static const struct rj54n1_datafmt rj54n1_colour_fmts[] = {
+	{V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+	{V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
+	{V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
+	{V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
+	{V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
+	{V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE, V4L2_COLORSPACE_SRGB},
+	{V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB},
+	{V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE, V4L2_COLORSPACE_SRGB},
+	{V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
+};
+
+struct rj54n1_clock_div {
+	u8 ratio_tg;	/* can be 0 or an odd number */
+	u8 ratio_t;
+	u8 ratio_r;
+	u8 ratio_op;
+	u8 ratio_o;
+};
+
+struct rj54n1 {
+	struct v4l2_subdev subdev;
+	struct v4l2_ctrl_handler hdl;
+	struct rj54n1_clock_div clk_div;
+	const struct rj54n1_datafmt *fmt;
+	struct v4l2_rect rect;	/* Sensor window */
+	unsigned int tgclk_mhz;
+	bool auto_wb;
+	unsigned short width;	/* Output window */
+	unsigned short height;
+	unsigned short resize;	/* Sensor * 1024 / resize = Output */
+	unsigned short scale;
+	u8 bank;
+};
+
+struct rj54n1_reg_val {
+	u16 reg;
+	u8 val;
+};
+
+static const struct rj54n1_reg_val bank_4[] = {
+	{0x417, 0},
+	{0x42c, 0},
+	{0x42d, 0xf0},
+	{0x42e, 0},
+	{0x42f, 0x50},
+	{0x430, 0xf5},
+	{0x431, 0x16},
+	{0x432, 0x20},
+	{0x433, 0},
+	{0x434, 0xc8},
+	{0x43c, 8},
+	{0x43e, 0x90},
+	{0x445, 0x83},
+	{0x4ba, 0x58},
+	{0x4bb, 4},
+	{0x4bc, 0x20},
+	{0x4db, 4},
+	{0x4fe, 2},
+};
+
+static const struct rj54n1_reg_val bank_5[] = {
+	{0x514, 0},
+	{0x516, 0},
+	{0x518, 0},
+	{0x51a, 0},
+	{0x51d, 0xff},
+	{0x56f, 0x28},
+	{0x575, 0x40},
+	{0x5bc, 0x48},
+	{0x5c1, 6},
+	{0x5e5, 0x11},
+	{0x5e6, 0x43},
+	{0x5e7, 0x33},
+	{0x5e8, 0x21},
+	{0x5e9, 0x30},
+	{0x5ea, 0x0},
+	{0x5eb, 0xa5},
+	{0x5ec, 0xff},
+	{0x5fe, 2},
+};
+
+static const struct rj54n1_reg_val bank_7[] = {
+	{0x70a, 0},
+	{0x714, 0xff},
+	{0x715, 0xff},
+	{0x716, 0x1f},
+	{0x7FE, 2},
+};
+
+static const struct rj54n1_reg_val bank_8[] = {
+	{0x800, 0x00},
+	{0x801, 0x01},
+	{0x802, 0x61},
+	{0x805, 0x00},
+	{0x806, 0x00},
+	{0x807, 0x00},
+	{0x808, 0x00},
+	{0x809, 0x01},
+	{0x80A, 0x61},
+	{0x80B, 0x00},
+	{0x80C, 0x01},
+	{0x80D, 0x00},
+	{0x80E, 0x00},
+	{0x80F, 0x00},
+	{0x810, 0x00},
+	{0x811, 0x01},
+	{0x812, 0x61},
+	{0x813, 0x00},
+	{0x814, 0x11},
+	{0x815, 0x00},
+	{0x816, 0x41},
+	{0x817, 0x00},
+	{0x818, 0x51},
+	{0x819, 0x01},
+	{0x81A, 0x1F},
+	{0x81B, 0x00},
+	{0x81C, 0x01},
+	{0x81D, 0x00},
+	{0x81E, 0x11},
+	{0x81F, 0x00},
+	{0x820, 0x41},
+	{0x821, 0x00},
+	{0x822, 0x51},
+	{0x823, 0x00},
+	{0x824, 0x00},
+	{0x825, 0x00},
+	{0x826, 0x47},
+	{0x827, 0x01},
+	{0x828, 0x4F},
+	{0x829, 0x00},
+	{0x82A, 0x00},
+	{0x82B, 0x00},
+	{0x82C, 0x30},
+	{0x82D, 0x00},
+	{0x82E, 0x40},
+	{0x82F, 0x00},
+	{0x830, 0xB3},
+	{0x831, 0x00},
+	{0x832, 0xE3},
+	{0x833, 0x00},
+	{0x834, 0x00},
+	{0x835, 0x00},
+	{0x836, 0x00},
+	{0x837, 0x00},
+	{0x838, 0x00},
+	{0x839, 0x01},
+	{0x83A, 0x61},
+	{0x83B, 0x00},
+	{0x83C, 0x01},
+	{0x83D, 0x00},
+	{0x83E, 0x00},
+	{0x83F, 0x00},
+	{0x840, 0x00},
+	{0x841, 0x01},
+	{0x842, 0x61},
+	{0x843, 0x00},
+	{0x844, 0x1D},
+	{0x845, 0x00},
+	{0x846, 0x00},
+	{0x847, 0x00},
+	{0x848, 0x00},
+	{0x849, 0x01},
+	{0x84A, 0x1F},
+	{0x84B, 0x00},
+	{0x84C, 0x05},
+	{0x84D, 0x00},
+	{0x84E, 0x19},
+	{0x84F, 0x01},
+	{0x850, 0x21},
+	{0x851, 0x01},
+	{0x852, 0x5D},
+	{0x853, 0x00},
+	{0x854, 0x00},
+	{0x855, 0x00},
+	{0x856, 0x19},
+	{0x857, 0x01},
+	{0x858, 0x21},
+	{0x859, 0x00},
+	{0x85A, 0x00},
+	{0x85B, 0x00},
+	{0x85C, 0x00},
+	{0x85D, 0x00},
+	{0x85E, 0x00},
+	{0x85F, 0x00},
+	{0x860, 0xB3},
+	{0x861, 0x00},
+	{0x862, 0xE3},
+	{0x863, 0x00},
+	{0x864, 0x00},
+	{0x865, 0x00},
+	{0x866, 0x00},
+	{0x867, 0x00},
+	{0x868, 0x00},
+	{0x869, 0xE2},
+	{0x86A, 0x00},
+	{0x86B, 0x01},
+	{0x86C, 0x06},
+	{0x86D, 0x00},
+	{0x86E, 0x00},
+	{0x86F, 0x00},
+	{0x870, 0x60},
+	{0x871, 0x8C},
+	{0x872, 0x10},
+	{0x873, 0x00},
+	{0x874, 0xE0},
+	{0x875, 0x00},
+	{0x876, 0x27},
+	{0x877, 0x01},
+	{0x878, 0x00},
+	{0x879, 0x00},
+	{0x87A, 0x00},
+	{0x87B, 0x03},
+	{0x87C, 0x00},
+	{0x87D, 0x00},
+	{0x87E, 0x00},
+	{0x87F, 0x00},
+	{0x880, 0x00},
+	{0x881, 0x00},
+	{0x882, 0x00},
+	{0x883, 0x00},
+	{0x884, 0x00},
+	{0x885, 0x00},
+	{0x886, 0xF8},
+	{0x887, 0x00},
+	{0x888, 0x03},
+	{0x889, 0x00},
+	{0x88A, 0x64},
+	{0x88B, 0x00},
+	{0x88C, 0x03},
+	{0x88D, 0x00},
+	{0x88E, 0xB1},
+	{0x88F, 0x00},
+	{0x890, 0x03},
+	{0x891, 0x01},
+	{0x892, 0x1D},
+	{0x893, 0x00},
+	{0x894, 0x03},
+	{0x895, 0x01},
+	{0x896, 0x4B},
+	{0x897, 0x00},
+	{0x898, 0xE5},
+	{0x899, 0x00},
+	{0x89A, 0x01},
+	{0x89B, 0x00},
+	{0x89C, 0x01},
+	{0x89D, 0x04},
+	{0x89E, 0xC8},
+	{0x89F, 0x00},
+	{0x8A0, 0x01},
+	{0x8A1, 0x01},
+	{0x8A2, 0x61},
+	{0x8A3, 0x00},
+	{0x8A4, 0x01},
+	{0x8A5, 0x00},
+	{0x8A6, 0x00},
+	{0x8A7, 0x00},
+	{0x8A8, 0x00},
+	{0x8A9, 0x00},
+	{0x8AA, 0x7F},
+	{0x8AB, 0x03},
+	{0x8AC, 0x00},
+	{0x8AD, 0x00},
+	{0x8AE, 0x00},
+	{0x8AF, 0x00},
+	{0x8B0, 0x00},
+	{0x8B1, 0x00},
+	{0x8B6, 0x00},
+	{0x8B7, 0x01},
+	{0x8B8, 0x00},
+	{0x8B9, 0x00},
+	{0x8BA, 0x02},
+	{0x8BB, 0x00},
+	{0x8BC, 0xFF},
+	{0x8BD, 0x00},
+	{0x8FE, 2},
+};
+
+static const struct rj54n1_reg_val bank_10[] = {
+	{0x10bf, 0x69}
+};
+
+/* Clock dividers - these are default register values, divider = register + 1 */
+static const struct rj54n1_clock_div clk_div = {
+	.ratio_tg	= 3 /* default: 5 */,
+	.ratio_t	= 4 /* default: 1 */,
+	.ratio_r	= 4 /* default: 0 */,
+	.ratio_op	= 1 /* default: 5 */,
+	.ratio_o	= 9 /* default: 0 */,
+};
+
+static struct rj54n1 *to_rj54n1(const struct i2c_client *client)
+{
+	return container_of(i2c_get_clientdata(client), struct rj54n1, subdev);
+}
+
+static int reg_read(struct i2c_client *client, const u16 reg)
+{
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+	int ret;
+
+	/* set bank */
+	if (rj54n1->bank != reg >> 8) {
+		dev_dbg(&client->dev, "[0x%x] = 0x%x\n", 0xff, reg >> 8);
+		ret = i2c_smbus_write_byte_data(client, 0xff, reg >> 8);
+		if (ret < 0)
+			return ret;
+		rj54n1->bank = reg >> 8;
+	}
+	return i2c_smbus_read_byte_data(client, reg & 0xff);
+}
+
+static int reg_write(struct i2c_client *client, const u16 reg,
+		     const u8 data)
+{
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+	int ret;
+
+	/* set bank */
+	if (rj54n1->bank != reg >> 8) {
+		dev_dbg(&client->dev, "[0x%x] = 0x%x\n", 0xff, reg >> 8);
+		ret = i2c_smbus_write_byte_data(client, 0xff, reg >> 8);
+		if (ret < 0)
+			return ret;
+		rj54n1->bank = reg >> 8;
+	}
+	dev_dbg(&client->dev, "[0x%x] = 0x%x\n", reg & 0xff, data);
+	return i2c_smbus_write_byte_data(client, reg & 0xff, data);
+}
+
+static int reg_set(struct i2c_client *client, const u16 reg,
+		   const u8 data, const u8 mask)
+{
+	int ret;
+
+	ret = reg_read(client, reg);
+	if (ret < 0)
+		return ret;
+	return reg_write(client, reg, (ret & ~mask) | (data & mask));
+}
+
+static int reg_write_multiple(struct i2c_client *client,
+			      const struct rj54n1_reg_val *rv, const int n)
+{
+	int i, ret;
+
+	for (i = 0; i < n; i++) {
+		ret = reg_write(client, rv->reg, rv->val);
+		if (ret < 0)
+			return ret;
+		rv++;
+	}
+
+	return 0;
+}
+
+static int rj54n1_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			   enum v4l2_mbus_pixelcode *code)
+{
+	if (index >= ARRAY_SIZE(rj54n1_colour_fmts))
+		return -EINVAL;
+
+	*code = rj54n1_colour_fmts[index].code;
+	return 0;
+}
+
+static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	/* Switch between preview and still shot modes */
+	return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80);
+}
+
+static int rj54n1_set_rect(struct i2c_client *client,
+			   u16 reg_x, u16 reg_y, u16 reg_xy,
+			   u32 width, u32 height)
+{
+	int ret;
+
+	ret = reg_write(client, reg_xy,
+			((width >> 4) & 0x70) |
+			((height >> 8) & 7));
+
+	if (!ret)
+		ret = reg_write(client, reg_x, width & 0xff);
+	if (!ret)
+		ret = reg_write(client, reg_y, height & 0xff);
+
+	return ret;
+}
+
+/*
+ * Some commands, specifically certain initialisation sequences, require
+ * a commit operation.
+ */
+static int rj54n1_commit(struct i2c_client *client)
+{
+	int ret = reg_write(client, RJ54N1_INIT_START, 1);
+	msleep(10);
+	if (!ret)
+		ret = reg_write(client, RJ54N1_INIT_START, 0);
+	return ret;
+}
+
+static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
+			       s32 *out_w, s32 *out_h);
+
+static int rj54n1_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+	struct v4l2_rect *rect = &a->c;
+	int dummy = 0, output_w, output_h,
+		input_w = rect->width, input_h = rect->height;
+	int ret;
+
+	/* arbitrary minimum width and height, edges unimportant */
+	soc_camera_limit_side(&dummy, &input_w,
+		     RJ54N1_COLUMN_SKIP, 8, RJ54N1_MAX_WIDTH);
+
+	soc_camera_limit_side(&dummy, &input_h,
+		     RJ54N1_ROW_SKIP, 8, RJ54N1_MAX_HEIGHT);
+
+	output_w = (input_w * 1024 + rj54n1->resize / 2) / rj54n1->resize;
+	output_h = (input_h * 1024 + rj54n1->resize / 2) / rj54n1->resize;
+
+	dev_dbg(&client->dev, "Scaling for %dx%d : %u = %dx%d\n",
+		input_w, input_h, rj54n1->resize, output_w, output_h);
+
+	ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h);
+	if (ret < 0)
+		return ret;
+
+	rj54n1->width		= output_w;
+	rj54n1->height		= output_h;
+	rj54n1->resize		= ret;
+	rj54n1->rect.width	= input_w;
+	rj54n1->rect.height	= input_h;
+
+	return 0;
+}
+
+static int rj54n1_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+
+	a->c	= rj54n1->rect;
+	a->type	= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int rj54n1_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	a->bounds.left			= RJ54N1_COLUMN_SKIP;
+	a->bounds.top			= RJ54N1_ROW_SKIP;
+	a->bounds.width			= RJ54N1_MAX_WIDTH;
+	a->bounds.height		= RJ54N1_MAX_HEIGHT;
+	a->defrect			= a->bounds;
+	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int rj54n1_g_fmt(struct v4l2_subdev *sd,
+			struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+
+	mf->code	= rj54n1->fmt->code;
+	mf->colorspace	= rj54n1->fmt->colorspace;
+	mf->field	= V4L2_FIELD_NONE;
+	mf->width	= rj54n1->width;
+	mf->height	= rj54n1->height;
+
+	return 0;
+}
+
+/*
+ * The actual geometry configuration routine. It scales the input window into
+ * the output one, updates the window sizes and returns an error or the resize
+ * coefficient on success. Note: we only use the "Fixed Scaling" on this camera.
+ */
+static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
+			       s32 *out_w, s32 *out_h)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+	unsigned int skip, resize, input_w = *in_w, input_h = *in_h,
+		output_w = *out_w, output_h = *out_h;
+	u16 inc_sel, wb_bit8, wb_left, wb_right, wb_top, wb_bottom;
+	unsigned int peak, peak_50, peak_60;
+	int ret;
+
+	/*
+	 * We have a problem with crops, where the window is larger than 512x384
+	 * and output window is larger than a half of the input one. In this
+	 * case we have to either reduce the input window to equal or below
+	 * 512x384 or the output window to equal or below 1/2 of the input.
+	 */
+	if (output_w > max(512U, input_w / 2)) {
+		if (2 * output_w > RJ54N1_MAX_WIDTH) {
+			input_w = RJ54N1_MAX_WIDTH;
+			output_w = RJ54N1_MAX_WIDTH / 2;
+		} else {
+			input_w = output_w * 2;
+		}
+
+		dev_dbg(&client->dev, "Adjusted output width: in %u, out %u\n",
+			input_w, output_w);
+	}
+
+	if (output_h > max(384U, input_h / 2)) {
+		if (2 * output_h > RJ54N1_MAX_HEIGHT) {
+			input_h = RJ54N1_MAX_HEIGHT;
+			output_h = RJ54N1_MAX_HEIGHT / 2;
+		} else {
+			input_h = output_h * 2;
+		}
+
+		dev_dbg(&client->dev, "Adjusted output height: in %u, out %u\n",
+			input_h, output_h);
+	}
+
+	/* Idea: use the read mode for snapshots, handle separate geometries */
+	ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_S_L,
+			      RJ54N1_Y_OUTPUT_SIZE_S_L,
+			      RJ54N1_XY_OUTPUT_SIZE_S_H, output_w, output_h);
+	if (!ret)
+		ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_P_L,
+			      RJ54N1_Y_OUTPUT_SIZE_P_L,
+			      RJ54N1_XY_OUTPUT_SIZE_P_H, output_w, output_h);
+
+	if (ret < 0)
+		return ret;
+
+	if (output_w > input_w && output_h > input_h) {
+		input_w = output_w;
+		input_h = output_h;
+
+		resize = 1024;
+	} else {
+		unsigned int resize_x, resize_y;
+		resize_x = (input_w * 1024 + output_w / 2) / output_w;
+		resize_y = (input_h * 1024 + output_h / 2) / output_h;
+
+		/* We want max(resize_x, resize_y), check if it still fits */
+		if (resize_x > resize_y &&
+		    (output_h * resize_x + 512) / 1024 > RJ54N1_MAX_HEIGHT)
+			resize = (RJ54N1_MAX_HEIGHT * 1024 + output_h / 2) /
+				output_h;
+		else if (resize_y > resize_x &&
+			 (output_w * resize_y + 512) / 1024 > RJ54N1_MAX_WIDTH)
+			resize = (RJ54N1_MAX_WIDTH * 1024 + output_w / 2) /
+				output_w;
+		else
+			resize = max(resize_x, resize_y);
+
+		/* Prohibited value ranges */
+		switch (resize) {
+		case 2040 ... 2047:
+			resize = 2039;
+			break;
+		case 4080 ... 4095:
+			resize = 4079;
+			break;
+		case 8160 ... 8191:
+			resize = 8159;
+			break;
+		case 16320 ... 16384:
+			resize = 16319;
+		}
+	}
+
+	/* Set scaling */
+	ret = reg_write(client, RJ54N1_RESIZE_HOLD_L, resize & 0xff);
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RESIZE_HOLD_H, resize >> 8);
+
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Configure a skipping bitmask. The sensor will select a skipping value
+	 * among set bits automatically. This is very unclear in the datasheet
+	 * too. I was told, in this register one enables all skipping values,
+	 * that are required for a specific resize, and the camera selects
+	 * automatically, which ones to use. But it is unclear how to identify,
+	 * which cropping values are needed. Secondly, why don't we just set all
+	 * bits and let the camera choose? Would it increase processing time and
+	 * reduce the framerate? Using 0xfffc for INC_USE_SEL doesn't seem to
+	 * improve the image quality or stability for larger frames (see comment
+	 * above), but I didn't check the framerate.
+	 */
+	skip = min(resize / 1024, 15U);
+
+	inc_sel = 1 << skip;
+
+	if (inc_sel <= 2)
+		inc_sel = 0xc;
+	else if (resize & 1023 && skip < 15)
+		inc_sel |= 1 << (skip + 1);
+
+	ret = reg_write(client, RJ54N1_INC_USE_SEL_L, inc_sel & 0xfc);
+	if (!ret)
+		ret = reg_write(client, RJ54N1_INC_USE_SEL_H, inc_sel >> 8);
+
+	if (!rj54n1->auto_wb) {
+		/* Auto white balance window */
+		wb_left	  = output_w / 16;
+		wb_right  = (3 * output_w / 4 - 3) / 4;
+		wb_top	  = output_h / 16;
+		wb_bottom = (3 * output_h / 4 - 3) / 4;
+		wb_bit8	  = ((wb_left >> 2) & 0x40) | ((wb_top >> 4) & 0x10) |
+			((wb_right >> 6) & 4) | ((wb_bottom >> 8) & 1);
+
+		if (!ret)
+			ret = reg_write(client, RJ54N1_BIT8_WB, wb_bit8);
+		if (!ret)
+			ret = reg_write(client, RJ54N1_HCAPS_WB, wb_left);
+		if (!ret)
+			ret = reg_write(client, RJ54N1_VCAPS_WB, wb_top);
+		if (!ret)
+			ret = reg_write(client, RJ54N1_HCAPE_WB, wb_right);
+		if (!ret)
+			ret = reg_write(client, RJ54N1_VCAPE_WB, wb_bottom);
+	}
+
+	/* Antiflicker */
+	peak = 12 * RJ54N1_MAX_WIDTH * (1 << 14) * resize / rj54n1->tgclk_mhz /
+		10000;
+	peak_50 = peak / 6;
+	peak_60 = peak / 5;
+
+	if (!ret)
+		ret = reg_write(client, RJ54N1_PEAK_H,
+				((peak_50 >> 4) & 0xf0) | (peak_60 >> 8));
+	if (!ret)
+		ret = reg_write(client, RJ54N1_PEAK_50, peak_50);
+	if (!ret)
+		ret = reg_write(client, RJ54N1_PEAK_60, peak_60);
+	if (!ret)
+		ret = reg_write(client, RJ54N1_PEAK_DIFF, peak / 150);
+
+	/* Start resizing */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RESIZE_CONTROL,
+				RESIZE_HOLD_SEL | RESIZE_GO | 1);
+
+	if (ret < 0)
+		return ret;
+
+	/* Constant taken from manufacturer's example */
+	msleep(230);
+
+	ret = reg_write(client, RJ54N1_RESIZE_CONTROL, RESIZE_HOLD_SEL | 1);
+	if (ret < 0)
+		return ret;
+
+	*in_w = (output_w * resize + 512) / 1024;
+	*in_h = (output_h * resize + 512) / 1024;
+	*out_w = output_w;
+	*out_h = output_h;
+
+	dev_dbg(&client->dev, "Scaled for %dx%d : %u = %ux%u, skip %u\n",
+		*in_w, *in_h, resize, output_w, output_h, skip);
+
+	return resize;
+}
+
+static int rj54n1_set_clock(struct i2c_client *client)
+{
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+	int ret;
+
+	/* Enable external clock */
+	ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK | SOFT_STDBY);
+	/* Leave stand-by. Note: use this when implementing suspend / resume */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK);
+
+	if (!ret)
+		ret = reg_write(client, RJ54N1_PLL_L, PLL_L);
+	if (!ret)
+		ret = reg_write(client, RJ54N1_PLL_N, PLL_N);
+
+	/* TGCLK dividers */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RATIO_TG,
+				rj54n1->clk_div.ratio_tg);
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RATIO_T,
+				rj54n1->clk_div.ratio_t);
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RATIO_R,
+				rj54n1->clk_div.ratio_r);
+
+	/* Enable TGCLK & RAMP */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RAMP_TGCLK_EN, 3);
+
+	/* Disable clock output */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_OCLK_DSP, 0);
+
+	/* Set divisors */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RATIO_OP,
+				rj54n1->clk_div.ratio_op);
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RATIO_O,
+				rj54n1->clk_div.ratio_o);
+
+	/* Enable OCLK */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_OCLK_SEL_EN, 1);
+
+	/* Use PLL for Timing Generator, write 2 to reserved bits */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_TG_BYPASS, 2);
+
+	/* Take sensor out of reset */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RESET_STANDBY,
+				E_EXCLK | SEN_RSTX);
+	/* Enable PLL */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_PLL_EN, 1);
+
+	/* Wait for PLL to stabilise */
+	msleep(10);
+
+	/* Enable clock to frequency divider */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_CLK_RST, 1);
+
+	if (!ret)
+		ret = reg_read(client, RJ54N1_CLK_RST);
+	if (ret != 1) {
+		dev_err(&client->dev,
+			"Resetting RJ54N1CB0C clock failed: %d!\n", ret);
+		return -EIO;
+	}
+
+	/* Start the PLL */
+	ret = reg_set(client, RJ54N1_OCLK_DSP, 1, 1);
+
+	/* Enable OCLK */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_OCLK_SEL_EN, 1);
+
+	return ret;
+}
+
+static int rj54n1_reg_init(struct i2c_client *client)
+{
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+	int ret = rj54n1_set_clock(client);
+
+	if (!ret)
+		ret = reg_write_multiple(client, bank_7, ARRAY_SIZE(bank_7));
+	if (!ret)
+		ret = reg_write_multiple(client, bank_10, ARRAY_SIZE(bank_10));
+
+	/* Set binning divisors */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_SCALE_1_2_LEV, 3 | (7 << 4));
+	if (!ret)
+		ret = reg_write(client, RJ54N1_SCALE_4_LEV, 0xf);
+
+	/* Switch to fixed resize mode */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RESIZE_CONTROL,
+				RESIZE_HOLD_SEL | 1);
+
+	/* Set gain */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_Y_GAIN, 0x84);
+
+	/*
+	 * Mirror the image back: default is upside down and left-to-right...
+	 * Set manual preview / still shot switching
+	 */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_MIRROR_STILL_MODE, 0x27);
+
+	if (!ret)
+		ret = reg_write_multiple(client, bank_4, ARRAY_SIZE(bank_4));
+
+	/* Auto exposure area */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_EXPOSURE_CONTROL, 0x80);
+	/* Check current auto WB config */
+	if (!ret)
+		ret = reg_read(client, RJ54N1_WB_SEL_WEIGHT_I);
+	if (ret >= 0) {
+		rj54n1->auto_wb = ret & 0x80;
+		ret = reg_write_multiple(client, bank_5, ARRAY_SIZE(bank_5));
+	}
+	if (!ret)
+		ret = reg_write_multiple(client, bank_8, ARRAY_SIZE(bank_8));
+
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RESET_STANDBY,
+				E_EXCLK | DSP_RSTX | SEN_RSTX);
+
+	/* Commit init */
+	if (!ret)
+		ret = rj54n1_commit(client);
+
+	/* Take DSP, TG, sensor out of reset */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RESET_STANDBY,
+				E_EXCLK | DSP_RSTX | TG_RSTX | SEN_RSTX);
+
+	/* Start register update? Same register as 0x?FE in many bank_* sets */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_FWFLG, 2);
+
+	/* Constant taken from manufacturer's example */
+	msleep(700);
+
+	return ret;
+}
+
+static int rj54n1_try_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+	const struct rj54n1_datafmt *fmt;
+	int align = mf->code == V4L2_MBUS_FMT_SBGGR10_1X10 ||
+		mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE ||
+		mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE ||
+		mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE ||
+		mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE;
+
+	dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n",
+		__func__, mf->code, mf->width, mf->height);
+
+	fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts,
+				  ARRAY_SIZE(rj54n1_colour_fmts));
+	if (!fmt) {
+		fmt = rj54n1->fmt;
+		mf->code = fmt->code;
+	}
+
+	mf->field	= V4L2_FIELD_NONE;
+	mf->colorspace	= fmt->colorspace;
+
+	v4l_bound_align_image(&mf->width, 112, RJ54N1_MAX_WIDTH, align,
+			      &mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0);
+
+	return 0;
+}
+
+static int rj54n1_s_fmt(struct v4l2_subdev *sd,
+			struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+	const struct rj54n1_datafmt *fmt;
+	int output_w, output_h, max_w, max_h,
+		input_w = rj54n1->rect.width, input_h = rj54n1->rect.height;
+	int ret;
+
+	/*
+	 * The host driver can call us without .try_fmt(), so, we have to take
+	 * care ourseleves
+	 */
+	rj54n1_try_fmt(sd, mf);
+
+	/*
+	 * Verify if the sensor has just been powered on. TODO: replace this
+	 * with proper PM, when a suitable API is available.
+	 */
+	ret = reg_read(client, RJ54N1_RESET_STANDBY);
+	if (ret < 0)
+		return ret;
+
+	if (!(ret & E_EXCLK)) {
+		ret = rj54n1_reg_init(client);
+		if (ret < 0)
+			return ret;
+	}
+
+	dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n",
+		__func__, mf->code, mf->width, mf->height);
+
+	/* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */
+	switch (mf->code) {
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+		ret = reg_write(client, RJ54N1_OUT_SEL, 0);
+		if (!ret)
+			ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
+		break;
+	case V4L2_MBUS_FMT_YVYU8_2X8:
+		ret = reg_write(client, RJ54N1_OUT_SEL, 0);
+		if (!ret)
+			ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
+		break;
+	case V4L2_MBUS_FMT_RGB565_2X8_LE:
+		ret = reg_write(client, RJ54N1_OUT_SEL, 0x11);
+		if (!ret)
+			ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
+		break;
+	case V4L2_MBUS_FMT_RGB565_2X8_BE:
+		ret = reg_write(client, RJ54N1_OUT_SEL, 0x11);
+		if (!ret)
+			ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
+		break;
+	case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE:
+		ret = reg_write(client, RJ54N1_OUT_SEL, 4);
+		if (!ret)
+			ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
+		if (!ret)
+			ret = reg_write(client, RJ54N1_RA_SEL_UL, 0);
+		break;
+	case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE:
+		ret = reg_write(client, RJ54N1_OUT_SEL, 4);
+		if (!ret)
+			ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
+		if (!ret)
+			ret = reg_write(client, RJ54N1_RA_SEL_UL, 8);
+		break;
+	case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE:
+		ret = reg_write(client, RJ54N1_OUT_SEL, 4);
+		if (!ret)
+			ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
+		if (!ret)
+			ret = reg_write(client, RJ54N1_RA_SEL_UL, 0);
+		break;
+	case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE:
+		ret = reg_write(client, RJ54N1_OUT_SEL, 4);
+		if (!ret)
+			ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
+		if (!ret)
+			ret = reg_write(client, RJ54N1_RA_SEL_UL, 8);
+		break;
+	case V4L2_MBUS_FMT_SBGGR10_1X10:
+		ret = reg_write(client, RJ54N1_OUT_SEL, 5);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	/* Special case: a raw mode with 10 bits of data per clock tick */
+	if (!ret)
+		ret = reg_set(client, RJ54N1_OCLK_SEL_EN,
+			      (mf->code == V4L2_MBUS_FMT_SBGGR10_1X10) << 1, 2);
+
+	if (ret < 0)
+		return ret;
+
+	/* Supported scales 1:1 >= scale > 1:16 */
+	max_w = mf->width * (16 * 1024 - 1) / 1024;
+	if (input_w > max_w)
+		input_w = max_w;
+	max_h = mf->height * (16 * 1024 - 1) / 1024;
+	if (input_h > max_h)
+		input_h = max_h;
+
+	output_w = mf->width;
+	output_h = mf->height;
+
+	ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h);
+	if (ret < 0)
+		return ret;
+
+	fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts,
+				  ARRAY_SIZE(rj54n1_colour_fmts));
+
+	rj54n1->fmt		= fmt;
+	rj54n1->resize		= ret;
+	rj54n1->rect.width	= input_w;
+	rj54n1->rect.height	= input_h;
+	rj54n1->width		= output_w;
+	rj54n1->height		= output_h;
+
+	mf->width		= output_w;
+	mf->height		= output_h;
+	mf->field		= V4L2_FIELD_NONE;
+	mf->colorspace		= fmt->colorspace;
+
+	return 0;
+}
+
+static int rj54n1_g_chip_ident(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_chip_ident *id)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+
+	if (id->match.addr != client->addr)
+		return -ENODEV;
+
+	id->ident	= V4L2_IDENT_RJ54N1CB0C;
+	id->revision	= 0;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int rj54n1_g_register(struct v4l2_subdev *sd,
+			     struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
+	    reg->reg < 0x400 || reg->reg > 0x1fff)
+		/* Registers > 0x0800 are only available from Sharp support */
+		return -EINVAL;
+
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	reg->size = 1;
+	reg->val = reg_read(client, reg->reg);
+
+	if (reg->val > 0xff)
+		return -EIO;
+
+	return 0;
+}
+
+static int rj54n1_s_register(struct v4l2_subdev *sd,
+			     struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
+	    reg->reg < 0x400 || reg->reg > 0x1fff)
+		/* Registers >= 0x0800 are only available from Sharp support */
+		return -EINVAL;
+
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	if (reg_write(client, reg->reg, reg->val) < 0)
+		return -EIO;
+
+	return 0;
+}
+#endif
+
+static int rj54n1_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	return soc_camera_set_power(&client->dev, icl, on);
+}
+
+static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct rj54n1 *rj54n1 = container_of(ctrl->handler, struct rj54n1, hdl);
+	struct v4l2_subdev *sd = &rj54n1->subdev;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int data;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		if (ctrl->val)
+			data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 1);
+		else
+			data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 1, 1);
+		if (data < 0)
+			return -EIO;
+		return 0;
+	case V4L2_CID_HFLIP:
+		if (ctrl->val)
+			data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 2);
+		else
+			data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 2, 2);
+		if (data < 0)
+			return -EIO;
+		return 0;
+	case V4L2_CID_GAIN:
+		if (reg_write(client, RJ54N1_Y_GAIN, ctrl->val * 2) < 0)
+			return -EIO;
+		return 0;
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		/* Auto WB area - whole image */
+		if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->val << 7,
+			    0x80) < 0)
+			return -EIO;
+		rj54n1->auto_wb = ctrl->val;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops rj54n1_ctrl_ops = {
+	.s_ctrl = rj54n1_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = {
+	.g_chip_ident	= rj54n1_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register	= rj54n1_g_register,
+	.s_register	= rj54n1_s_register,
+#endif
+	.s_power	= rj54n1_s_power,
+};
+
+static int rj54n1_g_mbus_config(struct v4l2_subdev *sd,
+				struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	cfg->flags =
+		V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
+		V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH |
+		V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH;
+	cfg->type = V4L2_MBUS_PARALLEL;
+	cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+	return 0;
+}
+
+static int rj54n1_s_mbus_config(struct v4l2_subdev *sd,
+				const struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	/* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */
+	if (soc_camera_apply_board_flags(icl, cfg) &
+	    V4L2_MBUS_PCLK_SAMPLE_RISING)
+		return reg_write(client, RJ54N1_OUT_SIGPO, 1 << 4);
+	else
+		return reg_write(client, RJ54N1_OUT_SIGPO, 0);
+}
+
+static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = {
+	.s_stream	= rj54n1_s_stream,
+	.s_mbus_fmt	= rj54n1_s_fmt,
+	.g_mbus_fmt	= rj54n1_g_fmt,
+	.try_mbus_fmt	= rj54n1_try_fmt,
+	.enum_mbus_fmt	= rj54n1_enum_fmt,
+	.g_crop		= rj54n1_g_crop,
+	.s_crop		= rj54n1_s_crop,
+	.cropcap	= rj54n1_cropcap,
+	.g_mbus_config	= rj54n1_g_mbus_config,
+	.s_mbus_config	= rj54n1_s_mbus_config,
+};
+
+static struct v4l2_subdev_ops rj54n1_subdev_ops = {
+	.core	= &rj54n1_subdev_core_ops,
+	.video	= &rj54n1_subdev_video_ops,
+};
+
+/*
+ * Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one
+ */
+static int rj54n1_video_probe(struct i2c_client *client,
+			      struct rj54n1_pdata *priv)
+{
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+	int data1, data2;
+	int ret;
+
+	ret = rj54n1_s_power(&rj54n1->subdev, 1);
+	if (ret < 0)
+		return ret;
+
+	/* Read out the chip version register */
+	data1 = reg_read(client, RJ54N1_DEV_CODE);
+	data2 = reg_read(client, RJ54N1_DEV_CODE2);
+
+	if (data1 != 0x51 || data2 != 0x10) {
+		ret = -ENODEV;
+		dev_info(&client->dev, "No RJ54N1CB0C found, read 0x%x:0x%x\n",
+			 data1, data2);
+		goto done;
+	}
+
+	/* Configure IOCTL polarity from the platform data: 0 or 1 << 7. */
+	ret = reg_write(client, RJ54N1_IOC, priv->ioctl_high << 7);
+	if (ret < 0)
+		goto done;
+
+	dev_info(&client->dev, "Detected a RJ54N1CB0C chip ID 0x%x:0x%x\n",
+		 data1, data2);
+
+	ret = v4l2_ctrl_handler_setup(&rj54n1->hdl);
+
+done:
+	rj54n1_s_power(&rj54n1->subdev, 0);
+	return ret;
+}
+
+static int rj54n1_probe(struct i2c_client *client,
+			const struct i2c_device_id *did)
+{
+	struct rj54n1 *rj54n1;
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct rj54n1_pdata *rj54n1_priv;
+	int ret;
+
+	if (!icl || !icl->priv) {
+		dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n");
+		return -EINVAL;
+	}
+
+	rj54n1_priv = icl->priv;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		dev_warn(&adapter->dev,
+			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
+		return -EIO;
+	}
+
+	rj54n1 = kzalloc(sizeof(struct rj54n1), GFP_KERNEL);
+	if (!rj54n1)
+		return -ENOMEM;
+
+	v4l2_i2c_subdev_init(&rj54n1->subdev, client, &rj54n1_subdev_ops);
+	v4l2_ctrl_handler_init(&rj54n1->hdl, 4);
+	v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
+			V4L2_CID_HFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
+			V4L2_CID_GAIN, 0, 127, 1, 66);
+	v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
+			V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
+	rj54n1->subdev.ctrl_handler = &rj54n1->hdl;
+	if (rj54n1->hdl.error) {
+		int err = rj54n1->hdl.error;
+
+		kfree(rj54n1);
+		return err;
+	}
+
+	rj54n1->clk_div		= clk_div;
+	rj54n1->rect.left	= RJ54N1_COLUMN_SKIP;
+	rj54n1->rect.top	= RJ54N1_ROW_SKIP;
+	rj54n1->rect.width	= RJ54N1_MAX_WIDTH;
+	rj54n1->rect.height	= RJ54N1_MAX_HEIGHT;
+	rj54n1->width		= RJ54N1_MAX_WIDTH;
+	rj54n1->height		= RJ54N1_MAX_HEIGHT;
+	rj54n1->fmt		= &rj54n1_colour_fmts[0];
+	rj54n1->resize		= 1024;
+	rj54n1->tgclk_mhz	= (rj54n1_priv->mclk_freq / PLL_L * PLL_N) /
+		(clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1);
+
+	ret = rj54n1_video_probe(client, rj54n1_priv);
+	if (ret < 0) {
+		v4l2_ctrl_handler_free(&rj54n1->hdl);
+		kfree(rj54n1);
+	}
+
+	return ret;
+}
+
+static int rj54n1_remove(struct i2c_client *client)
+{
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	v4l2_device_unregister_subdev(&rj54n1->subdev);
+	if (icl->free_bus)
+		icl->free_bus(icl);
+	v4l2_ctrl_handler_free(&rj54n1->hdl);
+	kfree(rj54n1);
+
+	return 0;
+}
+
+static const struct i2c_device_id rj54n1_id[] = {
+	{ "rj54n1cb0c", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rj54n1_id);
+
+static struct i2c_driver rj54n1_i2c_driver = {
+	.driver = {
+		.name = "rj54n1cb0c",
+	},
+	.probe		= rj54n1_probe,
+	.remove		= rj54n1_remove,
+	.id_table	= rj54n1_id,
+};
+
+module_i2c_driver(rj54n1_i2c_driver);
+
+MODULE_DESCRIPTION("Sharp RJ54N1CB0C Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/sh_mobile_csi2.c b/drivers/media/i2c/soc_camera/sh_mobile_csi2.c
new file mode 100644
index 0000000..0528650
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/sh_mobile_csi2.c
@@ -0,0 +1,398 @@
+/*
+ * Driver for the SH-Mobile MIPI CSI-2 unit
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+
+#include <media/sh_mobile_ceu.h>
+#include <media/sh_mobile_csi2.h>
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+#define SH_CSI2_TREF	0x00
+#define SH_CSI2_SRST	0x04
+#define SH_CSI2_PHYCNT	0x08
+#define SH_CSI2_CHKSUM	0x0C
+#define SH_CSI2_VCDT	0x10
+
+struct sh_csi2 {
+	struct v4l2_subdev		subdev;
+	struct list_head		list;
+	unsigned int			irq;
+	unsigned long			mipi_flags;
+	void __iomem			*base;
+	struct platform_device		*pdev;
+	struct sh_csi2_client_config	*client;
+};
+
+static int sh_csi2_try_fmt(struct v4l2_subdev *sd,
+			   struct v4l2_mbus_framefmt *mf)
+{
+	struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
+	struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
+
+	if (mf->width > 8188)
+		mf->width = 8188;
+	else if (mf->width & 1)
+		mf->width &= ~1;
+
+	switch (pdata->type) {
+	case SH_CSI2C:
+		switch (mf->code) {
+		case V4L2_MBUS_FMT_UYVY8_2X8:		/* YUV422 */
+		case V4L2_MBUS_FMT_YUYV8_1_5X8:		/* YUV420 */
+		case V4L2_MBUS_FMT_Y8_1X8:		/* RAW8 */
+		case V4L2_MBUS_FMT_SBGGR8_1X8:
+		case V4L2_MBUS_FMT_SGRBG8_1X8:
+			break;
+		default:
+			/* All MIPI CSI-2 devices must support one of primary formats */
+			mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
+		}
+		break;
+	case SH_CSI2I:
+		switch (mf->code) {
+		case V4L2_MBUS_FMT_Y8_1X8:		/* RAW8 */
+		case V4L2_MBUS_FMT_SBGGR8_1X8:
+		case V4L2_MBUS_FMT_SGRBG8_1X8:
+		case V4L2_MBUS_FMT_SBGGR10_1X10:	/* RAW10 */
+		case V4L2_MBUS_FMT_SBGGR12_1X12:	/* RAW12 */
+			break;
+		default:
+			/* All MIPI CSI-2 devices must support one of primary formats */
+			mf->code = V4L2_MBUS_FMT_SBGGR8_1X8;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * We have done our best in try_fmt to try and tell the sensor, which formats
+ * we support. If now the configuration is unsuitable for us we can only
+ * error out.
+ */
+static int sh_csi2_s_fmt(struct v4l2_subdev *sd,
+			 struct v4l2_mbus_framefmt *mf)
+{
+	struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
+	u32 tmp = (priv->client->channel & 3) << 8;
+
+	dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
+	if (mf->width > 8188 || mf->width & 1)
+		return -EINVAL;
+
+	switch (mf->code) {
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		tmp |= 0x1e;	/* YUV422 8 bit */
+		break;
+	case V4L2_MBUS_FMT_YUYV8_1_5X8:
+		tmp |= 0x18;	/* YUV420 8 bit */
+		break;
+	case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+		tmp |= 0x21;	/* RGB555 */
+		break;
+	case V4L2_MBUS_FMT_RGB565_2X8_BE:
+		tmp |= 0x22;	/* RGB565 */
+		break;
+	case V4L2_MBUS_FMT_Y8_1X8:
+	case V4L2_MBUS_FMT_SBGGR8_1X8:
+	case V4L2_MBUS_FMT_SGRBG8_1X8:
+		tmp |= 0x2a;	/* RAW8 */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	iowrite32(tmp, priv->base + SH_CSI2_VCDT);
+
+	return 0;
+}
+
+static int sh_csi2_g_mbus_config(struct v4l2_subdev *sd,
+				 struct v4l2_mbus_config *cfg)
+{
+	cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING |
+		V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
+		V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH;
+	cfg->type = V4L2_MBUS_PARALLEL;
+
+	return 0;
+}
+
+static int sh_csi2_s_mbus_config(struct v4l2_subdev *sd,
+				 const struct v4l2_mbus_config *cfg)
+{
+	struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
+	struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd);
+	struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd);
+	struct v4l2_mbus_config client_cfg = {.type = V4L2_MBUS_CSI2,
+					      .flags = priv->mipi_flags};
+
+	return v4l2_subdev_call(client_sd, video, s_mbus_config, &client_cfg);
+}
+
+static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = {
+	.s_mbus_fmt	= sh_csi2_s_fmt,
+	.try_mbus_fmt	= sh_csi2_try_fmt,
+	.g_mbus_config	= sh_csi2_g_mbus_config,
+	.s_mbus_config	= sh_csi2_s_mbus_config,
+};
+
+static void sh_csi2_hwinit(struct sh_csi2 *priv)
+{
+	struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
+	__u32 tmp = 0x10; /* Enable MIPI CSI clock lane */
+
+	/* Reflect registers immediately */
+	iowrite32(0x00000001, priv->base + SH_CSI2_TREF);
+	/* reset CSI2 harware */
+	iowrite32(0x00000001, priv->base + SH_CSI2_SRST);
+	udelay(5);
+	iowrite32(0x00000000, priv->base + SH_CSI2_SRST);
+
+	switch (pdata->type) {
+	case SH_CSI2C:
+		if (priv->client->lanes == 1)
+			tmp |= 1;
+		else
+			/* Default - both lanes */
+			tmp |= 3;
+		break;
+	case SH_CSI2I:
+		if (!priv->client->lanes || priv->client->lanes > 4)
+			/* Default - all 4 lanes */
+			tmp |= 0xf;
+		else
+			tmp |= (1 << priv->client->lanes) - 1;
+	}
+
+	if (priv->client->phy == SH_CSI2_PHY_MAIN)
+		tmp |= 0x8000;
+
+	iowrite32(tmp, priv->base + SH_CSI2_PHYCNT);
+
+	tmp = 0;
+	if (pdata->flags & SH_CSI2_ECC)
+		tmp |= 2;
+	if (pdata->flags & SH_CSI2_CRC)
+		tmp |= 1;
+	iowrite32(tmp, priv->base + SH_CSI2_CHKSUM);
+}
+
+static int sh_csi2_client_connect(struct sh_csi2 *priv)
+{
+	struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
+	struct soc_camera_device *icd = v4l2_get_subdev_hostdata(&priv->subdev);
+	struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd);
+	struct device *dev = v4l2_get_subdevdata(&priv->subdev);
+	struct v4l2_mbus_config cfg;
+	unsigned long common_flags, csi2_flags;
+	int i, ret;
+
+	if (priv->client)
+		return -EBUSY;
+
+	for (i = 0; i < pdata->num_clients; i++)
+		if (&pdata->clients[i].pdev->dev == icd->pdev)
+			break;
+
+	dev_dbg(dev, "%s(%p): found #%d\n", __func__, dev, i);
+
+	if (i == pdata->num_clients)
+		return -ENODEV;
+
+	/* Check if we can support this camera */
+	csi2_flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | V4L2_MBUS_CSI2_1_LANE;
+
+	switch (pdata->type) {
+	case SH_CSI2C:
+		if (pdata->clients[i].lanes != 1)
+			csi2_flags |= V4L2_MBUS_CSI2_2_LANE;
+		break;
+	case SH_CSI2I:
+		switch (pdata->clients[i].lanes) {
+		default:
+			csi2_flags |= V4L2_MBUS_CSI2_4_LANE;
+		case 3:
+			csi2_flags |= V4L2_MBUS_CSI2_3_LANE;
+		case 2:
+			csi2_flags |= V4L2_MBUS_CSI2_2_LANE;
+		}
+	}
+
+	cfg.type = V4L2_MBUS_CSI2;
+	ret = v4l2_subdev_call(client_sd, video, g_mbus_config, &cfg);
+	if (ret == -ENOIOCTLCMD)
+		common_flags = csi2_flags;
+	else if (!ret)
+		common_flags = soc_mbus_config_compatible(&cfg,
+							  csi2_flags);
+	else
+		common_flags = 0;
+
+	if (!common_flags)
+		return -EINVAL;
+
+	/* All good: camera MIPI configuration supported */
+	priv->mipi_flags = common_flags;
+	priv->client = pdata->clients + i;
+
+	pm_runtime_get_sync(dev);
+
+	sh_csi2_hwinit(priv);
+
+	return 0;
+}
+
+static void sh_csi2_client_disconnect(struct sh_csi2 *priv)
+{
+	if (!priv->client)
+		return;
+
+	priv->client = NULL;
+
+	pm_runtime_put(v4l2_get_subdevdata(&priv->subdev));
+}
+
+static int sh_csi2_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
+
+	if (on)
+		return sh_csi2_client_connect(priv);
+
+	sh_csi2_client_disconnect(priv);
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops = {
+	.s_power	= sh_csi2_s_power,
+};
+
+static struct v4l2_subdev_ops sh_csi2_subdev_ops = {
+	.core	= &sh_csi2_subdev_core_ops,
+	.video	= &sh_csi2_subdev_video_ops,
+};
+
+static __devinit int sh_csi2_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	unsigned int irq;
+	int ret;
+	struct sh_csi2 *priv;
+	/* Platform data specify the PHY, lanes, ECC, CRC */
+	struct sh_csi2_pdata *pdata = pdev->dev.platform_data;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	/* Interrupt unused so far */
+	irq = platform_get_irq(pdev, 0);
+
+	if (!res || (int)irq <= 0 || !pdata) {
+		dev_err(&pdev->dev, "Not enough CSI2 platform resources.\n");
+		return -ENODEV;
+	}
+
+	/* TODO: Add support for CSI2I. Careful: different register layout! */
+	if (pdata->type != SH_CSI2C) {
+		dev_err(&pdev->dev, "Only CSI2C supported ATM.\n");
+		return -EINVAL;
+	}
+
+	priv = kzalloc(sizeof(struct sh_csi2), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->irq = irq;
+
+	if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+		dev_err(&pdev->dev, "CSI2 register region already claimed\n");
+		ret = -EBUSY;
+		goto ereqreg;
+	}
+
+	priv->base = ioremap(res->start, resource_size(res));
+	if (!priv->base) {
+		ret = -ENXIO;
+		dev_err(&pdev->dev, "Unable to ioremap CSI2 registers.\n");
+		goto eremap;
+	}
+
+	priv->pdev = pdev;
+	platform_set_drvdata(pdev, priv);
+
+	v4l2_subdev_init(&priv->subdev, &sh_csi2_subdev_ops);
+	v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
+
+	snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s.mipi-csi",
+		 dev_name(pdata->v4l2_dev->dev));
+	ret = v4l2_device_register_subdev(pdata->v4l2_dev, &priv->subdev);
+	dev_dbg(&pdev->dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret);
+	if (ret < 0)
+		goto esdreg;
+
+	pm_runtime_enable(&pdev->dev);
+
+	dev_dbg(&pdev->dev, "CSI2 probed.\n");
+
+	return 0;
+
+esdreg:
+	iounmap(priv->base);
+eremap:
+	release_mem_region(res->start, resource_size(res));
+ereqreg:
+	kfree(priv);
+
+	return ret;
+}
+
+static __devexit int sh_csi2_remove(struct platform_device *pdev)
+{
+	struct sh_csi2 *priv = platform_get_drvdata(pdev);
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	v4l2_device_unregister_subdev(&priv->subdev);
+	pm_runtime_disable(&pdev->dev);
+	iounmap(priv->base);
+	release_mem_region(res->start, resource_size(res));
+	platform_set_drvdata(pdev, NULL);
+	kfree(priv);
+
+	return 0;
+}
+
+static struct platform_driver __refdata sh_csi2_pdrv = {
+	.remove	= __devexit_p(sh_csi2_remove),
+	.probe	= sh_csi2_probe,
+	.driver	= {
+		.name	= "sh-mobile-csi2",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(sh_csi2_pdrv);
+
+MODULE_DESCRIPTION("SH-Mobile MIPI CSI-2 driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sh-mobile-csi2");
diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c
new file mode 100644
index 0000000..140716e
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/tw9910.c
@@ -0,0 +1,973 @@
+/*
+ * tw9910 Video Driver
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov772x driver,
+ *
+ * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/soc_camera.h>
+#include <media/tw9910.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
+
+#define GET_ID(val)  ((val & 0xF8) >> 3)
+#define GET_REV(val) (val & 0x07)
+
+/*
+ * register offset
+ */
+#define ID		0x00 /* Product ID Code Register */
+#define STATUS1		0x01 /* Chip Status Register I */
+#define INFORM		0x02 /* Input Format */
+#define OPFORM		0x03 /* Output Format Control Register */
+#define DLYCTR		0x04 /* Hysteresis and HSYNC Delay Control */
+#define OUTCTR1		0x05 /* Output Control I */
+#define ACNTL1		0x06 /* Analog Control Register 1 */
+#define CROP_HI		0x07 /* Cropping Register, High */
+#define VDELAY_LO	0x08 /* Vertical Delay Register, Low */
+#define VACTIVE_LO	0x09 /* Vertical Active Register, Low */
+#define HDELAY_LO	0x0A /* Horizontal Delay Register, Low */
+#define HACTIVE_LO	0x0B /* Horizontal Active Register, Low */
+#define CNTRL1		0x0C /* Control Register I */
+#define VSCALE_LO	0x0D /* Vertical Scaling Register, Low */
+#define SCALE_HI	0x0E /* Scaling Register, High */
+#define HSCALE_LO	0x0F /* Horizontal Scaling Register, Low */
+#define BRIGHT		0x10 /* BRIGHTNESS Control Register */
+#define CONTRAST	0x11 /* CONTRAST Control Register */
+#define SHARPNESS	0x12 /* SHARPNESS Control Register I */
+#define SAT_U		0x13 /* Chroma (U) Gain Register */
+#define SAT_V		0x14 /* Chroma (V) Gain Register */
+#define HUE		0x15 /* Hue Control Register */
+#define CORING1		0x17
+#define CORING2		0x18 /* Coring and IF compensation */
+#define VBICNTL		0x19 /* VBI Control Register */
+#define ACNTL2		0x1A /* Analog Control 2 */
+#define OUTCTR2		0x1B /* Output Control 2 */
+#define SDT		0x1C /* Standard Selection */
+#define SDTR		0x1D /* Standard Recognition */
+#define TEST		0x1F /* Test Control Register */
+#define CLMPG		0x20 /* Clamping Gain */
+#define IAGC		0x21 /* Individual AGC Gain */
+#define AGCGAIN		0x22 /* AGC Gain */
+#define PEAKWT		0x23 /* White Peak Threshold */
+#define CLMPL		0x24 /* Clamp level */
+#define SYNCT		0x25 /* Sync Amplitude */
+#define MISSCNT		0x26 /* Sync Miss Count Register */
+#define PCLAMP		0x27 /* Clamp Position Register */
+#define VCNTL1		0x28 /* Vertical Control I */
+#define VCNTL2		0x29 /* Vertical Control II */
+#define CKILL		0x2A /* Color Killer Level Control */
+#define COMB		0x2B /* Comb Filter Control */
+#define LDLY		0x2C /* Luma Delay and H Filter Control */
+#define MISC1		0x2D /* Miscellaneous Control I */
+#define LOOP		0x2E /* LOOP Control Register */
+#define MISC2		0x2F /* Miscellaneous Control II */
+#define MVSN		0x30 /* Macrovision Detection */
+#define STATUS2		0x31 /* Chip STATUS II */
+#define HFREF		0x32 /* H monitor */
+#define CLMD		0x33 /* CLAMP MODE */
+#define IDCNTL		0x34 /* ID Detection Control */
+#define CLCNTL1		0x35 /* Clamp Control I */
+#define ANAPLLCTL	0x4C
+#define VBIMIN		0x4D
+#define HSLOWCTL	0x4E
+#define WSS3		0x4F
+#define FILLDATA	0x50
+#define SDID		0x51
+#define DID		0x52
+#define WSS1		0x53
+#define WSS2		0x54
+#define VVBI		0x55
+#define LCTL6		0x56
+#define LCTL7		0x57
+#define LCTL8		0x58
+#define LCTL9		0x59
+#define LCTL10		0x5A
+#define LCTL11		0x5B
+#define LCTL12		0x5C
+#define LCTL13		0x5D
+#define LCTL14		0x5E
+#define LCTL15		0x5F
+#define LCTL16		0x60
+#define LCTL17		0x61
+#define LCTL18		0x62
+#define LCTL19		0x63
+#define LCTL20		0x64
+#define LCTL21		0x65
+#define LCTL22		0x66
+#define LCTL23		0x67
+#define LCTL24		0x68
+#define LCTL25		0x69
+#define LCTL26		0x6A
+#define HSBEGIN		0x6B
+#define HSEND		0x6C
+#define OVSDLY		0x6D
+#define OVSEND		0x6E
+#define VBIDELAY	0x6F
+
+/*
+ * register detail
+ */
+
+/* INFORM */
+#define FC27_ON     0x40 /* 1 : Input crystal clock frequency is 27MHz */
+#define FC27_FF     0x00 /* 0 : Square pixel mode. */
+			 /*     Must use 24.54MHz for 60Hz field rate */
+			 /*     source or 29.5MHz for 50Hz field rate */
+#define IFSEL_S     0x10 /* 01 : S-video decoding */
+#define IFSEL_C     0x00 /* 00 : Composite video decoding */
+			 /* Y input video selection */
+#define YSEL_M0     0x00 /*  00 : Mux0 selected */
+#define YSEL_M1     0x04 /*  01 : Mux1 selected */
+#define YSEL_M2     0x08 /*  10 : Mux2 selected */
+#define YSEL_M3     0x10 /*  11 : Mux3 selected */
+
+/* OPFORM */
+#define MODE        0x80 /* 0 : CCIR601 compatible YCrCb 4:2:2 format */
+			 /* 1 : ITU-R-656 compatible data sequence format */
+#define LEN         0x40 /* 0 : 8-bit YCrCb 4:2:2 output format */
+			 /* 1 : 16-bit YCrCb 4:2:2 output format.*/
+#define LLCMODE     0x20 /* 1 : LLC output mode. */
+			 /* 0 : free-run output mode */
+#define AINC        0x10 /* Serial interface auto-indexing control */
+			 /* 0 : auto-increment */
+			 /* 1 : non-auto */
+#define VSCTL       0x08 /* 1 : Vertical out ctrl by DVALID */
+			 /* 0 : Vertical out ctrl by HACTIVE and DVALID */
+#define OEN_TRI_SEL_MASK	0x07
+#define OEN_TRI_SEL_ALL_ON	0x00 /* Enable output for Rev0/Rev1 */
+#define OEN_TRI_SEL_ALL_OFF_r0	0x06 /* All tri-stated for Rev0 */
+#define OEN_TRI_SEL_ALL_OFF_r1	0x07 /* All tri-stated for Rev1 */
+
+/* OUTCTR1 */
+#define VSP_LO      0x00 /* 0 : VS pin output polarity is active low */
+#define VSP_HI      0x80 /* 1 : VS pin output polarity is active high. */
+			 /* VS pin output control */
+#define VSSL_VSYNC  0x00 /*   0 : VSYNC  */
+#define VSSL_VACT   0x10 /*   1 : VACT   */
+#define VSSL_FIELD  0x20 /*   2 : FIELD  */
+#define VSSL_VVALID 0x30 /*   3 : VVALID */
+#define VSSL_ZERO   0x70 /*   7 : 0      */
+#define HSP_LOW     0x00 /* 0 : HS pin output polarity is active low */
+#define HSP_HI      0x08 /* 1 : HS pin output polarity is active high.*/
+			 /* HS pin output control */
+#define HSSL_HACT   0x00 /*   0 : HACT   */
+#define HSSL_HSYNC  0x01 /*   1 : HSYNC  */
+#define HSSL_DVALID 0x02 /*   2 : DVALID */
+#define HSSL_HLOCK  0x03 /*   3 : HLOCK  */
+#define HSSL_ASYNCW 0x04 /*   4 : ASYNCW */
+#define HSSL_ZERO   0x07 /*   7 : 0      */
+
+/* ACNTL1 */
+#define SRESET      0x80 /* resets the device to its default state
+			  * but all register content remain unchanged.
+			  * This bit is self-resetting.
+			  */
+#define ACNTL1_PDN_MASK	0x0e
+#define CLK_PDN		0x08 /* system clock power down */
+#define Y_PDN		0x04 /* Luma ADC power down */
+#define C_PDN		0x02 /* Chroma ADC power down */
+
+/* ACNTL2 */
+#define ACNTL2_PDN_MASK	0x40
+#define PLL_PDN		0x40 /* PLL power down */
+
+/* VBICNTL */
+
+/* RTSEL : control the real time signal output from the MPOUT pin */
+#define RTSEL_MASK  0x07
+#define RTSEL_VLOSS 0x00 /* 0000 = Video loss */
+#define RTSEL_HLOCK 0x01 /* 0001 = H-lock */
+#define RTSEL_SLOCK 0x02 /* 0010 = S-lock */
+#define RTSEL_VLOCK 0x03 /* 0011 = V-lock */
+#define RTSEL_MONO  0x04 /* 0100 = MONO */
+#define RTSEL_DET50 0x05 /* 0101 = DET50 */
+#define RTSEL_FIELD 0x06 /* 0110 = FIELD */
+#define RTSEL_RTCO  0x07 /* 0111 = RTCO ( Real Time Control ) */
+
+/* HSYNC start and end are constant for now */
+#define HSYNC_START	0x0260
+#define HSYNC_END	0x0300
+
+/*
+ * structure
+ */
+
+struct regval_list {
+	unsigned char reg_num;
+	unsigned char value;
+};
+
+struct tw9910_scale_ctrl {
+	char           *name;
+	unsigned short  width;
+	unsigned short  height;
+	u16             hscale;
+	u16             vscale;
+};
+
+struct tw9910_priv {
+	struct v4l2_subdev		subdev;
+	struct tw9910_video_info	*info;
+	const struct tw9910_scale_ctrl	*scale;
+	v4l2_std_id			norm;
+	u32				revision;
+};
+
+static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = {
+	{
+		.name   = "NTSC SQ",
+		.width  = 640,
+		.height = 480,
+		.hscale = 0x0100,
+		.vscale = 0x0100,
+	},
+	{
+		.name   = "NTSC CCIR601",
+		.width  = 720,
+		.height = 480,
+		.hscale = 0x0100,
+		.vscale = 0x0100,
+	},
+	{
+		.name   = "NTSC SQ (CIF)",
+		.width  = 320,
+		.height = 240,
+		.hscale = 0x0200,
+		.vscale = 0x0200,
+	},
+	{
+		.name   = "NTSC CCIR601 (CIF)",
+		.width  = 360,
+		.height = 240,
+		.hscale = 0x0200,
+		.vscale = 0x0200,
+	},
+	{
+		.name   = "NTSC SQ (QCIF)",
+		.width  = 160,
+		.height = 120,
+		.hscale = 0x0400,
+		.vscale = 0x0400,
+	},
+	{
+		.name   = "NTSC CCIR601 (QCIF)",
+		.width  = 180,
+		.height = 120,
+		.hscale = 0x0400,
+		.vscale = 0x0400,
+	},
+};
+
+static const struct tw9910_scale_ctrl tw9910_pal_scales[] = {
+	{
+		.name   = "PAL SQ",
+		.width  = 768,
+		.height = 576,
+		.hscale = 0x0100,
+		.vscale = 0x0100,
+	},
+	{
+		.name   = "PAL CCIR601",
+		.width  = 720,
+		.height = 576,
+		.hscale = 0x0100,
+		.vscale = 0x0100,
+	},
+	{
+		.name   = "PAL SQ (CIF)",
+		.width  = 384,
+		.height = 288,
+		.hscale = 0x0200,
+		.vscale = 0x0200,
+	},
+	{
+		.name   = "PAL CCIR601 (CIF)",
+		.width  = 360,
+		.height = 288,
+		.hscale = 0x0200,
+		.vscale = 0x0200,
+	},
+	{
+		.name   = "PAL SQ (QCIF)",
+		.width  = 192,
+		.height = 144,
+		.hscale = 0x0400,
+		.vscale = 0x0400,
+	},
+	{
+		.name   = "PAL CCIR601 (QCIF)",
+		.width  = 180,
+		.height = 144,
+		.hscale = 0x0400,
+		.vscale = 0x0400,
+	},
+};
+
+/*
+ * general function
+ */
+static struct tw9910_priv *to_tw9910(const struct i2c_client *client)
+{
+	return container_of(i2c_get_clientdata(client), struct tw9910_priv,
+			    subdev);
+}
+
+static int tw9910_mask_set(struct i2c_client *client, u8 command,
+			   u8 mask, u8 set)
+{
+	s32 val = i2c_smbus_read_byte_data(client, command);
+	if (val < 0)
+		return val;
+
+	val &= ~mask;
+	val |= set & mask;
+
+	return i2c_smbus_write_byte_data(client, command, val);
+}
+
+static int tw9910_set_scale(struct i2c_client *client,
+			    const struct tw9910_scale_ctrl *scale)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(client, SCALE_HI,
+					(scale->vscale & 0x0F00) >> 4 |
+					(scale->hscale & 0x0F00) >> 8);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_write_byte_data(client, HSCALE_LO,
+					scale->hscale & 0x00FF);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_write_byte_data(client, VSCALE_LO,
+					scale->vscale & 0x00FF);
+
+	return ret;
+}
+
+static int tw9910_set_hsync(struct i2c_client *client)
+{
+	struct tw9910_priv *priv = to_tw9910(client);
+	int ret;
+
+	/* bit 10 - 3 */
+	ret = i2c_smbus_write_byte_data(client, HSBEGIN,
+					(HSYNC_START & 0x07F8) >> 3);
+	if (ret < 0)
+		return ret;
+
+	/* bit 10 - 3 */
+	ret = i2c_smbus_write_byte_data(client, HSEND,
+					(HSYNC_END & 0x07F8) >> 3);
+	if (ret < 0)
+		return ret;
+
+	/* So far only revisions 0 and 1 have been seen */
+	/* bit 2 - 0 */
+	if (1 == priv->revision)
+		ret = tw9910_mask_set(client, HSLOWCTL, 0x77,
+				      (HSYNC_START & 0x0007) << 4 |
+				      (HSYNC_END   & 0x0007));
+
+	return ret;
+}
+
+static void tw9910_reset(struct i2c_client *client)
+{
+	tw9910_mask_set(client, ACNTL1, SRESET, SRESET);
+	msleep(1);
+}
+
+static int tw9910_power(struct i2c_client *client, int enable)
+{
+	int ret;
+	u8 acntl1;
+	u8 acntl2;
+
+	if (enable) {
+		acntl1 = 0;
+		acntl2 = 0;
+	} else {
+		acntl1 = CLK_PDN | Y_PDN | C_PDN;
+		acntl2 = PLL_PDN;
+	}
+
+	ret = tw9910_mask_set(client, ACNTL1, ACNTL1_PDN_MASK, acntl1);
+	if (ret < 0)
+		return ret;
+
+	return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2);
+}
+
+static const struct tw9910_scale_ctrl *tw9910_select_norm(v4l2_std_id norm,
+							  u32 width, u32 height)
+{
+	const struct tw9910_scale_ctrl *scale;
+	const struct tw9910_scale_ctrl *ret = NULL;
+	__u32 diff = 0xffffffff, tmp;
+	int size, i;
+
+	if (norm & V4L2_STD_NTSC) {
+		scale = tw9910_ntsc_scales;
+		size = ARRAY_SIZE(tw9910_ntsc_scales);
+	} else if (norm & V4L2_STD_PAL) {
+		scale = tw9910_pal_scales;
+		size = ARRAY_SIZE(tw9910_pal_scales);
+	} else {
+		return NULL;
+	}
+
+	for (i = 0; i < size; i++) {
+		tmp = abs(width - scale[i].width) +
+			abs(height - scale[i].height);
+		if (tmp < diff) {
+			diff = tmp;
+			ret = scale + i;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * subdevice operations
+ */
+static int tw9910_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct tw9910_priv *priv = to_tw9910(client);
+	u8 val;
+	int ret;
+
+	if (!enable) {
+		switch (priv->revision) {
+		case 0:
+			val = OEN_TRI_SEL_ALL_OFF_r0;
+			break;
+		case 1:
+			val = OEN_TRI_SEL_ALL_OFF_r1;
+			break;
+		default:
+			dev_err(&client->dev, "un-supported revision\n");
+			return -EINVAL;
+		}
+	} else {
+		val = OEN_TRI_SEL_ALL_ON;
+
+		if (!priv->scale) {
+			dev_err(&client->dev, "norm select error\n");
+			return -EPERM;
+		}
+
+		dev_dbg(&client->dev, "%s %dx%d\n",
+			priv->scale->name,
+			priv->scale->width,
+			priv->scale->height);
+	}
+
+	ret = tw9910_mask_set(client, OPFORM, OEN_TRI_SEL_MASK, val);
+	if (ret < 0)
+		return ret;
+
+	return tw9910_power(client, enable);
+}
+
+static int tw9910_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct tw9910_priv *priv = to_tw9910(client);
+
+	*norm = priv->norm;
+
+	return 0;
+}
+
+static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct tw9910_priv *priv = to_tw9910(client);
+
+	if (!(norm & (V4L2_STD_NTSC | V4L2_STD_PAL)))
+		return -EINVAL;
+
+	priv->norm = norm;
+
+	return 0;
+}
+
+static int tw9910_g_chip_ident(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_chip_ident *id)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct tw9910_priv *priv = to_tw9910(client);
+
+	id->ident = V4L2_IDENT_TW9910;
+	id->revision = priv->revision;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int tw9910_g_register(struct v4l2_subdev *sd,
+			     struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+
+	if (reg->reg > 0xff)
+		return -EINVAL;
+
+	ret = i2c_smbus_read_byte_data(client, reg->reg);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * ret      = int
+	 * reg->val = __u64
+	 */
+	reg->val = (__u64)ret;
+
+	return 0;
+}
+
+static int tw9910_s_register(struct v4l2_subdev *sd,
+			     struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->reg > 0xff ||
+	    reg->val > 0xff)
+		return -EINVAL;
+
+	return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
+}
+#endif
+
+static int tw9910_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	return soc_camera_set_power(&client->dev, icl, on);
+}
+
+static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct tw9910_priv *priv = to_tw9910(client);
+	int ret = -EINVAL;
+	u8 val;
+
+	/*
+	 * select suitable norm
+	 */
+	priv->scale = tw9910_select_norm(priv->norm, *width, *height);
+	if (!priv->scale)
+		goto tw9910_set_fmt_error;
+
+	/*
+	 * reset hardware
+	 */
+	tw9910_reset(client);
+
+	/*
+	 * set bus width
+	 */
+	val = 0x00;
+	if (SOCAM_DATAWIDTH_16 == priv->info->buswidth)
+		val = LEN;
+
+	ret = tw9910_mask_set(client, OPFORM, LEN, val);
+	if (ret < 0)
+		goto tw9910_set_fmt_error;
+
+	/*
+	 * select MPOUT behavior
+	 */
+	switch (priv->info->mpout) {
+	case TW9910_MPO_VLOSS:
+		val = RTSEL_VLOSS; break;
+	case TW9910_MPO_HLOCK:
+		val = RTSEL_HLOCK; break;
+	case TW9910_MPO_SLOCK:
+		val = RTSEL_SLOCK; break;
+	case TW9910_MPO_VLOCK:
+		val = RTSEL_VLOCK; break;
+	case TW9910_MPO_MONO:
+		val = RTSEL_MONO;  break;
+	case TW9910_MPO_DET50:
+		val = RTSEL_DET50; break;
+	case TW9910_MPO_FIELD:
+		val = RTSEL_FIELD; break;
+	case TW9910_MPO_RTCO:
+		val = RTSEL_RTCO;  break;
+	default:
+		val = 0;
+	}
+
+	ret = tw9910_mask_set(client, VBICNTL, RTSEL_MASK, val);
+	if (ret < 0)
+		goto tw9910_set_fmt_error;
+
+	/*
+	 * set scale
+	 */
+	ret = tw9910_set_scale(client, priv->scale);
+	if (ret < 0)
+		goto tw9910_set_fmt_error;
+
+	/*
+	 * set hsync
+	 */
+	ret = tw9910_set_hsync(client);
+	if (ret < 0)
+		goto tw9910_set_fmt_error;
+
+	*width = priv->scale->width;
+	*height = priv->scale->height;
+
+	return ret;
+
+tw9910_set_fmt_error:
+
+	tw9910_reset(client);
+	priv->scale = NULL;
+
+	return ret;
+}
+
+static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct tw9910_priv *priv = to_tw9910(client);
+
+	a->c.left	= 0;
+	a->c.top	= 0;
+	if (priv->norm & V4L2_STD_NTSC) {
+		a->c.width	= 640;
+		a->c.height	= 480;
+	} else {
+		a->c.width	= 768;
+		a->c.height	= 576;
+	}
+	a->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct tw9910_priv *priv = to_tw9910(client);
+
+	a->bounds.left			= 0;
+	a->bounds.top			= 0;
+	if (priv->norm & V4L2_STD_NTSC) {
+		a->bounds.width		= 640;
+		a->bounds.height	= 480;
+	} else {
+		a->bounds.width		= 768;
+		a->bounds.height	= 576;
+	}
+	a->defrect			= a->bounds;
+	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int tw9910_g_fmt(struct v4l2_subdev *sd,
+			struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct tw9910_priv *priv = to_tw9910(client);
+
+	if (!priv->scale) {
+		priv->scale = tw9910_select_norm(priv->norm, 640, 480);
+		if (!priv->scale)
+			return -EINVAL;
+	}
+
+	mf->width	= priv->scale->width;
+	mf->height	= priv->scale->height;
+	mf->code	= V4L2_MBUS_FMT_UYVY8_2X8;
+	mf->colorspace	= V4L2_COLORSPACE_JPEG;
+	mf->field	= V4L2_FIELD_INTERLACED_BT;
+
+	return 0;
+}
+
+static int tw9910_s_fmt(struct v4l2_subdev *sd,
+			struct v4l2_mbus_framefmt *mf)
+{
+	u32 width = mf->width, height = mf->height;
+	int ret;
+
+	WARN_ON(mf->field != V4L2_FIELD_ANY &&
+		mf->field != V4L2_FIELD_INTERLACED_BT);
+
+	/*
+	 * check color format
+	 */
+	if (mf->code != V4L2_MBUS_FMT_UYVY8_2X8)
+		return -EINVAL;
+
+	mf->colorspace = V4L2_COLORSPACE_JPEG;
+
+	ret = tw9910_set_frame(sd, &width, &height);
+	if (!ret) {
+		mf->width	= width;
+		mf->height	= height;
+	}
+	return ret;
+}
+
+static int tw9910_try_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_mbus_framefmt *mf)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct tw9910_priv *priv = to_tw9910(client);
+	const struct tw9910_scale_ctrl *scale;
+
+	if (V4L2_FIELD_ANY == mf->field) {
+		mf->field = V4L2_FIELD_INTERLACED_BT;
+	} else if (V4L2_FIELD_INTERLACED_BT != mf->field) {
+		dev_err(&client->dev, "Field type %d invalid.\n", mf->field);
+		return -EINVAL;
+	}
+
+	mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+	mf->colorspace = V4L2_COLORSPACE_JPEG;
+
+	/*
+	 * select suitable norm
+	 */
+	scale = tw9910_select_norm(priv->norm, mf->width, mf->height);
+	if (!scale)
+		return -EINVAL;
+
+	mf->width	= scale->width;
+	mf->height	= scale->height;
+
+	return 0;
+}
+
+static int tw9910_video_probe(struct i2c_client *client)
+{
+	struct tw9910_priv *priv = to_tw9910(client);
+	s32 id;
+	int ret;
+
+	/*
+	 * tw9910 only use 8 or 16 bit bus width
+	 */
+	if (SOCAM_DATAWIDTH_16 != priv->info->buswidth &&
+	    SOCAM_DATAWIDTH_8  != priv->info->buswidth) {
+		dev_err(&client->dev, "bus width error\n");
+		return -ENODEV;
+	}
+
+	ret = tw9910_s_power(&priv->subdev, 1);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * check and show Product ID
+	 * So far only revisions 0 and 1 have been seen
+	 */
+	id = i2c_smbus_read_byte_data(client, ID);
+	priv->revision = GET_REV(id);
+	id = GET_ID(id);
+
+	if (0x0B != id ||
+	    0x01 < priv->revision) {
+		dev_err(&client->dev,
+			"Product ID error %x:%x\n",
+			id, priv->revision);
+		ret = -ENODEV;
+		goto done;
+	}
+
+	dev_info(&client->dev,
+		 "tw9910 Product ID %0x:%0x\n", id, priv->revision);
+
+	priv->norm = V4L2_STD_NTSC;
+
+done:
+	tw9910_s_power(&priv->subdev, 0);
+	return ret;
+}
+
+static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
+	.g_chip_ident	= tw9910_g_chip_ident,
+	.s_std		= tw9910_s_std,
+	.g_std		= tw9910_g_std,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register	= tw9910_g_register,
+	.s_register	= tw9910_s_register,
+#endif
+	.s_power	= tw9910_s_power,
+};
+
+static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			   enum v4l2_mbus_pixelcode *code)
+{
+	if (index)
+		return -EINVAL;
+
+	*code = V4L2_MBUS_FMT_UYVY8_2X8;
+	return 0;
+}
+
+static int tw9910_g_mbus_config(struct v4l2_subdev *sd,
+				struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+	cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
+		V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
+		V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
+		V4L2_MBUS_DATA_ACTIVE_HIGH;
+	cfg->type = V4L2_MBUS_PARALLEL;
+	cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+	return 0;
+}
+
+static int tw9910_s_mbus_config(struct v4l2_subdev *sd,
+				const struct v4l2_mbus_config *cfg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+	u8 val = VSSL_VVALID | HSSL_DVALID;
+	unsigned long flags = soc_camera_apply_board_flags(icl, cfg);
+
+	/*
+	 * set OUTCTR1
+	 *
+	 * We use VVALID and DVALID signals to control VSYNC and HSYNC
+	 * outputs, in this mode their polarity is inverted.
+	 */
+	if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+		val |= HSP_HI;
+
+	if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+		val |= VSP_HI;
+
+	return i2c_smbus_write_byte_data(client, OUTCTR1, val);
+}
+
+static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = {
+	.s_stream	= tw9910_s_stream,
+	.g_mbus_fmt	= tw9910_g_fmt,
+	.s_mbus_fmt	= tw9910_s_fmt,
+	.try_mbus_fmt	= tw9910_try_fmt,
+	.cropcap	= tw9910_cropcap,
+	.g_crop		= tw9910_g_crop,
+	.enum_mbus_fmt	= tw9910_enum_fmt,
+	.g_mbus_config	= tw9910_g_mbus_config,
+	.s_mbus_config	= tw9910_s_mbus_config,
+};
+
+static struct v4l2_subdev_ops tw9910_subdev_ops = {
+	.core	= &tw9910_subdev_core_ops,
+	.video	= &tw9910_subdev_video_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+
+static int tw9910_probe(struct i2c_client *client,
+			const struct i2c_device_id *did)
+
+{
+	struct tw9910_priv		*priv;
+	struct tw9910_video_info	*info;
+	struct i2c_adapter		*adapter =
+		to_i2c_adapter(client->dev.parent);
+	struct soc_camera_link		*icl = soc_camera_i2c_to_link(client);
+	int				ret;
+
+	if (!icl || !icl->priv) {
+		dev_err(&client->dev, "TW9910: missing platform data!\n");
+		return -EINVAL;
+	}
+
+	info = icl->priv;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		dev_err(&client->dev,
+			"I2C-Adapter doesn't support "
+			"I2C_FUNC_SMBUS_BYTE_DATA\n");
+		return -EIO;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->info   = info;
+
+	v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops);
+
+	ret = tw9910_video_probe(client);
+	if (ret)
+		kfree(priv);
+
+	return ret;
+}
+
+static int tw9910_remove(struct i2c_client *client)
+{
+	struct tw9910_priv *priv = to_tw9910(client);
+
+	kfree(priv);
+	return 0;
+}
+
+static const struct i2c_device_id tw9910_id[] = {
+	{ "tw9910", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tw9910_id);
+
+static struct i2c_driver tw9910_i2c_driver = {
+	.driver = {
+		.name = "tw9910",
+	},
+	.probe    = tw9910_probe,
+	.remove   = tw9910_remove,
+	.id_table = tw9910_id,
+};
+
+module_i2c_driver(tw9910_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for tw9910");
+MODULE_AUTHOR("Kuninori Morimoto");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c
new file mode 100644
index 0000000..e9d95bd
--- /dev/null
+++ b/drivers/media/i2c/sr030pc30.c
@@ -0,0 +1,871 @@
+/*
+ * Driver for SiliconFile SR030PC30 VGA (1/10-Inch) Image Sensor with ISP
+ *
+ * Copyright (C) 2010 Samsung Electronics Co., Ltd
+ * Author: Sylwester Nawrocki, s.nawrocki@samsung.com
+ *
+ * Based on original driver authored by Dongsoo Nathaniel Kim
+ * and HeungJun Kim <riverful.kim@samsung.com>.
+ *
+ * Based on mt9v011 Micron Digital Image Sensor driver
+ * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-mediabus.h>
+#include <media/sr030pc30.h>
+
+static int debug;
+module_param(debug, int, 0644);
+
+#define MODULE_NAME	"SR030PC30"
+
+/*
+ * Register offsets within a page
+ * b15..b8 - page id, b7..b0 - register address
+ */
+#define POWER_CTRL_REG		0x0001
+#define PAGEMODE_REG		0x03
+#define DEVICE_ID_REG		0x0004
+#define NOON010PC30_ID		0x86
+#define SR030PC30_ID		0x8C
+#define VDO_CTL1_REG		0x0010
+#define SUBSAMPL_NONE_VGA	0
+#define SUBSAMPL_QVGA		0x10
+#define SUBSAMPL_QQVGA		0x20
+#define VDO_CTL2_REG		0x0011
+#define SYNC_CTL_REG		0x0012
+#define WIN_ROWH_REG		0x0020
+#define WIN_ROWL_REG		0x0021
+#define WIN_COLH_REG		0x0022
+#define WIN_COLL_REG		0x0023
+#define WIN_HEIGHTH_REG		0x0024
+#define WIN_HEIGHTL_REG		0x0025
+#define WIN_WIDTHH_REG		0x0026
+#define WIN_WIDTHL_REG		0x0027
+#define HBLANKH_REG		0x0040
+#define HBLANKL_REG		0x0041
+#define VSYNCH_REG		0x0042
+#define VSYNCL_REG		0x0043
+/* page 10 */
+#define ISP_CTL_REG(n)		(0x1010 + (n))
+#define YOFS_REG		0x1040
+#define DARK_YOFS_REG		0x1041
+#define AG_ABRTH_REG		0x1050
+#define SAT_CTL_REG		0x1060
+#define BSAT_REG		0x1061
+#define RSAT_REG		0x1062
+#define AG_SAT_TH_REG		0x1063
+/* page 11 */
+#define ZLPF_CTRL_REG		0x1110
+#define ZLPF_CTRL2_REG		0x1112
+#define ZLPF_AGH_THR_REG	0x1121
+#define ZLPF_THR_REG		0x1160
+#define ZLPF_DYN_THR_REG	0x1160
+/* page 12 */
+#define YCLPF_CTL1_REG		0x1240
+#define YCLPF_CTL2_REG		0x1241
+#define YCLPF_THR_REG		0x1250
+#define BLPF_CTL_REG		0x1270
+#define BLPF_THR1_REG		0x1274
+#define BLPF_THR2_REG		0x1275
+/* page 14 - Lens Shading Compensation */
+#define LENS_CTRL_REG		0x1410
+#define LENS_XCEN_REG		0x1420
+#define LENS_YCEN_REG		0x1421
+#define LENS_R_COMP_REG		0x1422
+#define LENS_G_COMP_REG		0x1423
+#define LENS_B_COMP_REG		0x1424
+/* page 15 - Color correction */
+#define CMC_CTL_REG		0x1510
+#define CMC_OFSGH_REG		0x1514
+#define CMC_OFSGL_REG		0x1516
+#define CMC_SIGN_REG		0x1517
+/* Color correction coefficients */
+#define CMC_COEF_REG(n)		(0x1530 + (n))
+/* Color correction offset coefficients */
+#define CMC_OFS_REG(n)		(0x1540 + (n))
+/* page 16 - Gamma correction */
+#define GMA_CTL_REG		0x1610
+/* Gamma correction coefficients 0.14 */
+#define GMA_COEF_REG(n)		(0x1630 + (n))
+/* page 20 - Auto Exposure */
+#define AE_CTL1_REG		0x2010
+#define AE_CTL2_REG		0x2011
+#define AE_FRM_CTL_REG		0x2020
+#define AE_FINE_CTL_REG(n)	(0x2028 + (n))
+#define EXP_TIMEH_REG		0x2083
+#define EXP_TIMEM_REG		0x2084
+#define EXP_TIMEL_REG		0x2085
+#define EXP_MMINH_REG		0x2086
+#define EXP_MMINL_REG		0x2087
+#define EXP_MMAXH_REG		0x2088
+#define EXP_MMAXM_REG		0x2089
+#define EXP_MMAXL_REG		0x208A
+/* page 22 - Auto White Balance */
+#define AWB_CTL1_REG		0x2210
+#define AWB_ENABLE		0x80
+#define AWB_CTL2_REG		0x2211
+#define MWB_ENABLE		0x01
+/* RGB gain control (manual WB) when AWB_CTL1[7]=0 */
+#define AWB_RGAIN_REG		0x2280
+#define AWB_GGAIN_REG		0x2281
+#define AWB_BGAIN_REG		0x2282
+#define AWB_RMAX_REG		0x2283
+#define AWB_RMIN_REG		0x2284
+#define AWB_BMAX_REG		0x2285
+#define AWB_BMIN_REG		0x2286
+/* R, B gain range in bright light conditions */
+#define AWB_RMAXB_REG		0x2287
+#define AWB_RMINB_REG		0x2288
+#define AWB_BMAXB_REG		0x2289
+#define AWB_BMINB_REG		0x228A
+/* manual white balance, when AWB_CTL2[0]=1 */
+#define MWB_RGAIN_REG		0x22B2
+#define MWB_BGAIN_REG		0x22B3
+/* the token to mark an array end */
+#define REG_TERM		0xFFFF
+
+/* Minimum and maximum exposure time in ms */
+#define EXPOS_MIN_MS		1
+#define EXPOS_MAX_MS		125
+
+struct sr030pc30_info {
+	struct v4l2_subdev sd;
+	const struct sr030pc30_platform_data *pdata;
+	const struct sr030pc30_format *curr_fmt;
+	const struct sr030pc30_frmsize *curr_win;
+	unsigned int auto_wb:1;
+	unsigned int auto_exp:1;
+	unsigned int hflip:1;
+	unsigned int vflip:1;
+	unsigned int sleep:1;
+	unsigned int exposure;
+	u8 blue_balance;
+	u8 red_balance;
+	u8 i2c_reg_page;
+};
+
+struct sr030pc30_format {
+	enum v4l2_mbus_pixelcode code;
+	enum v4l2_colorspace colorspace;
+	u16 ispctl1_reg;
+};
+
+struct sr030pc30_frmsize {
+	u16 width;
+	u16 height;
+	int vid_ctl1;
+};
+
+struct i2c_regval {
+	u16 addr;
+	u16 val;
+};
+
+static const struct v4l2_queryctrl sr030pc30_ctrl[] = {
+	{
+		.id		= V4L2_CID_AUTO_WHITE_BALANCE,
+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
+		.name		= "Auto White Balance",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 1,
+	}, {
+		.id		= V4L2_CID_RED_BALANCE,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Red Balance",
+		.minimum	= 0,
+		.maximum	= 127,
+		.step		= 1,
+		.default_value	= 64,
+		.flags		= 0,
+	}, {
+		.id		= V4L2_CID_BLUE_BALANCE,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Blue Balance",
+		.minimum	= 0,
+		.maximum	= 127,
+		.step		= 1,
+		.default_value	= 64,
+	}, {
+		.id		= V4L2_CID_EXPOSURE_AUTO,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Auto Exposure",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 1,
+	}, {
+		.id		= V4L2_CID_EXPOSURE,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Exposure",
+		.minimum	= EXPOS_MIN_MS,
+		.maximum	= EXPOS_MAX_MS,
+		.step		= 1,
+		.default_value	= 1,
+	}, {
+	}
+};
+
+/* supported resolutions */
+static const struct sr030pc30_frmsize sr030pc30_sizes[] = {
+	{
+		.width		= 640,
+		.height		= 480,
+		.vid_ctl1	= SUBSAMPL_NONE_VGA,
+	}, {
+		.width		= 320,
+		.height		= 240,
+		.vid_ctl1	= SUBSAMPL_QVGA,
+	}, {
+		.width		= 160,
+		.height		= 120,
+		.vid_ctl1	= SUBSAMPL_QQVGA,
+	},
+};
+
+/* supported pixel formats */
+static const struct sr030pc30_format sr030pc30_formats[] = {
+	{
+		.code		= V4L2_MBUS_FMT_YUYV8_2X8,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.ispctl1_reg	= 0x03,
+	}, {
+		.code		= V4L2_MBUS_FMT_YVYU8_2X8,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.ispctl1_reg	= 0x02,
+	}, {
+		.code		= V4L2_MBUS_FMT_VYUY8_2X8,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.ispctl1_reg	= 0,
+	}, {
+		.code		= V4L2_MBUS_FMT_UYVY8_2X8,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.ispctl1_reg	= 0x01,
+	}, {
+		.code		= V4L2_MBUS_FMT_RGB565_2X8_BE,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.ispctl1_reg	= 0x40,
+	},
+};
+
+static const struct i2c_regval sr030pc30_base_regs[] = {
+	/* Window size and position within pixel matrix */
+	{ WIN_ROWH_REG,		0x00 }, { WIN_ROWL_REG,		0x06 },
+	{ WIN_COLH_REG,		0x00 },	{ WIN_COLL_REG,		0x06 },
+	{ WIN_HEIGHTH_REG,	0x01 }, { WIN_HEIGHTL_REG,	0xE0 },
+	{ WIN_WIDTHH_REG,	0x02 }, { WIN_WIDTHL_REG,	0x80 },
+	{ HBLANKH_REG,		0x01 }, { HBLANKL_REG,		0x50 },
+	{ VSYNCH_REG,		0x00 }, { VSYNCL_REG,		0x14 },
+	{ SYNC_CTL_REG,		0 },
+	/* Color corection and saturation */
+	{ ISP_CTL_REG(0),	0x30 }, { YOFS_REG,		0x80 },
+	{ DARK_YOFS_REG,	0x04 }, { AG_ABRTH_REG,		0x78 },
+	{ SAT_CTL_REG,		0x1F }, { BSAT_REG,		0x90 },
+	{ AG_SAT_TH_REG,	0xF0 }, { 0x1064,		0x80 },
+	{ CMC_CTL_REG,		0x03 }, { CMC_OFSGH_REG,	0x3C },
+	{ CMC_OFSGL_REG,	0x2C }, { CMC_SIGN_REG,		0x2F },
+	{ CMC_COEF_REG(0),	0xCB }, { CMC_OFS_REG(0),	0x87 },
+	{ CMC_COEF_REG(1),	0x61 }, { CMC_OFS_REG(1),	0x18 },
+	{ CMC_COEF_REG(2),	0x16 }, { CMC_OFS_REG(2),	0x91 },
+	{ CMC_COEF_REG(3),	0x23 }, { CMC_OFS_REG(3),	0x94 },
+	{ CMC_COEF_REG(4),	0xCE }, { CMC_OFS_REG(4),	0x9f },
+	{ CMC_COEF_REG(5),	0x2B }, { CMC_OFS_REG(5),	0x33 },
+	{ CMC_COEF_REG(6),	0x01 }, { CMC_OFS_REG(6),	0x00 },
+	{ CMC_COEF_REG(7),	0x34 }, { CMC_OFS_REG(7),	0x94 },
+	{ CMC_COEF_REG(8),	0x75 }, { CMC_OFS_REG(8),	0x14 },
+	/* Color corection coefficients */
+	{ GMA_CTL_REG,		0x03 },	{ GMA_COEF_REG(0),	0x00 },
+	{ GMA_COEF_REG(1),	0x19 },	{ GMA_COEF_REG(2),	0x26 },
+	{ GMA_COEF_REG(3),	0x3B },	{ GMA_COEF_REG(4),	0x5D },
+	{ GMA_COEF_REG(5),	0x79 }, { GMA_COEF_REG(6),	0x8E },
+	{ GMA_COEF_REG(7),	0x9F },	{ GMA_COEF_REG(8),	0xAF },
+	{ GMA_COEF_REG(9),	0xBD },	{ GMA_COEF_REG(10),	0xCA },
+	{ GMA_COEF_REG(11),	0xDD }, { GMA_COEF_REG(12),	0xEC },
+	{ GMA_COEF_REG(13),	0xF7 },	{ GMA_COEF_REG(14),	0xFF },
+	/* Noise reduction, Z-LPF, YC-LPF and BLPF filters setup */
+	{ ZLPF_CTRL_REG,	0x99 }, { ZLPF_CTRL2_REG,	0x0E },
+	{ ZLPF_AGH_THR_REG,	0x29 }, { ZLPF_THR_REG,		0x0F },
+	{ ZLPF_DYN_THR_REG,	0x63 }, { YCLPF_CTL1_REG,	0x23 },
+	{ YCLPF_CTL2_REG,	0x3B }, { YCLPF_THR_REG,	0x05 },
+	{ BLPF_CTL_REG,		0x1D }, { BLPF_THR1_REG,	0x05 },
+	{ BLPF_THR2_REG,	0x04 },
+	/* Automatic white balance */
+	{ AWB_CTL1_REG,		0xFB }, { AWB_CTL2_REG,		0x26 },
+	{ AWB_RMAX_REG,		0x54 }, { AWB_RMIN_REG,		0x2B },
+	{ AWB_BMAX_REG,		0x57 }, { AWB_BMIN_REG,		0x29 },
+	{ AWB_RMAXB_REG,	0x50 }, { AWB_RMINB_REG,	0x43 },
+	{ AWB_BMAXB_REG,	0x30 }, { AWB_BMINB_REG,	0x22 },
+	/* Auto exposure */
+	{ AE_CTL1_REG,		0x8C }, { AE_CTL2_REG,		0x04 },
+	{ AE_FRM_CTL_REG,	0x01 }, { AE_FINE_CTL_REG(0),	0x3F },
+	{ AE_FINE_CTL_REG(1),	0xA3 }, { AE_FINE_CTL_REG(3),	0x34 },
+	/* Lens shading compensation */
+	{ LENS_CTRL_REG,	0x01 }, { LENS_XCEN_REG,	0x80 },
+	{ LENS_YCEN_REG,	0x70 }, { LENS_R_COMP_REG,	0x53 },
+	{ LENS_G_COMP_REG,	0x40 }, { LENS_B_COMP_REG,	0x3e },
+	{ REG_TERM,		0 },
+};
+
+static inline struct sr030pc30_info *to_sr030pc30(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct sr030pc30_info, sd);
+}
+
+static inline int set_i2c_page(struct sr030pc30_info *info,
+			       struct i2c_client *client, unsigned int reg)
+{
+	int ret = 0;
+	u32 page = reg >> 8 & 0xFF;
+
+	if (info->i2c_reg_page != page && (reg & 0xFF) != 0x03) {
+		ret = i2c_smbus_write_byte_data(client, PAGEMODE_REG, page);
+		if (!ret)
+			info->i2c_reg_page = page;
+	}
+	return ret;
+}
+
+static int cam_i2c_read(struct v4l2_subdev *sd, u32 reg_addr)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct sr030pc30_info *info = to_sr030pc30(sd);
+
+	int ret = set_i2c_page(info, client, reg_addr);
+	if (!ret)
+		ret = i2c_smbus_read_byte_data(client, reg_addr & 0xFF);
+	return ret;
+}
+
+static int cam_i2c_write(struct v4l2_subdev *sd, u32 reg_addr, u32 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct sr030pc30_info *info = to_sr030pc30(sd);
+
+	int ret = set_i2c_page(info, client, reg_addr);
+	if (!ret)
+		ret = i2c_smbus_write_byte_data(
+			client, reg_addr & 0xFF, val);
+	return ret;
+}
+
+static inline int sr030pc30_bulk_write_reg(struct v4l2_subdev *sd,
+				const struct i2c_regval *msg)
+{
+	while (msg->addr != REG_TERM) {
+		int ret = cam_i2c_write(sd, msg->addr, msg->val);
+		if (ret)
+			return ret;
+		msg++;
+	}
+	return 0;
+}
+
+/* Device reset and sleep mode control */
+static int sr030pc30_pwr_ctrl(struct v4l2_subdev *sd,
+				     bool reset, bool sleep)
+{
+	struct sr030pc30_info *info = to_sr030pc30(sd);
+	u8 reg = sleep ? 0xF1 : 0xF0;
+	int ret = 0;
+
+	if (reset)
+		ret = cam_i2c_write(sd, POWER_CTRL_REG, reg | 0x02);
+	if (!ret) {
+		ret = cam_i2c_write(sd, POWER_CTRL_REG, reg);
+		if (!ret) {
+			info->sleep = sleep;
+			if (reset)
+				info->i2c_reg_page = -1;
+		}
+	}
+	return ret;
+}
+
+static inline int sr030pc30_enable_autoexposure(struct v4l2_subdev *sd, int on)
+{
+	struct sr030pc30_info *info = to_sr030pc30(sd);
+	/* auto anti-flicker is also enabled here */
+	int ret = cam_i2c_write(sd, AE_CTL1_REG, on ? 0xDC : 0x0C);
+	if (!ret)
+		info->auto_exp = on;
+	return ret;
+}
+
+static int sr030pc30_set_exposure(struct v4l2_subdev *sd, int value)
+{
+	struct sr030pc30_info *info = to_sr030pc30(sd);
+
+	unsigned long expos = value * info->pdata->clk_rate / (8 * 1000);
+
+	int ret = cam_i2c_write(sd, EXP_TIMEH_REG, expos >> 16 & 0xFF);
+	if (!ret)
+		ret = cam_i2c_write(sd, EXP_TIMEM_REG, expos >> 8 & 0xFF);
+	if (!ret)
+		ret = cam_i2c_write(sd, EXP_TIMEL_REG, expos & 0xFF);
+	if (!ret) { /* Turn off AE */
+		info->exposure = value;
+		ret = sr030pc30_enable_autoexposure(sd, 0);
+	}
+	return ret;
+}
+
+/* Automatic white balance control */
+static int sr030pc30_enable_autowhitebalance(struct v4l2_subdev *sd, int on)
+{
+	struct sr030pc30_info *info = to_sr030pc30(sd);
+
+	int ret = cam_i2c_write(sd, AWB_CTL2_REG, on ? 0x2E : 0x2F);
+	if (!ret)
+		ret = cam_i2c_write(sd, AWB_CTL1_REG, on ? 0xFB : 0x7B);
+	if (!ret)
+		info->auto_wb = on;
+
+	return ret;
+}
+
+static int sr030pc30_set_flip(struct v4l2_subdev *sd)
+{
+	struct sr030pc30_info *info = to_sr030pc30(sd);
+
+	s32 reg = cam_i2c_read(sd, VDO_CTL2_REG);
+	if (reg < 0)
+		return reg;
+
+	reg &= 0x7C;
+	if (info->hflip)
+		reg |= 0x01;
+	if (info->vflip)
+		reg |= 0x02;
+	return cam_i2c_write(sd, VDO_CTL2_REG, reg | 0x80);
+}
+
+/* Configure resolution, color format and image flip */
+static int sr030pc30_set_params(struct v4l2_subdev *sd)
+{
+	struct sr030pc30_info *info = to_sr030pc30(sd);
+	int ret;
+
+	if (!info->curr_win)
+		return -EINVAL;
+
+	/* Configure the resolution through subsampling */
+	ret = cam_i2c_write(sd, VDO_CTL1_REG,
+			    info->curr_win->vid_ctl1);
+
+	if (!ret && info->curr_fmt)
+		ret = cam_i2c_write(sd, ISP_CTL_REG(0),
+				info->curr_fmt->ispctl1_reg);
+	if (!ret)
+		ret = sr030pc30_set_flip(sd);
+
+	return ret;
+}
+
+/* Find nearest matching image pixel size. */
+static int sr030pc30_try_frame_size(struct v4l2_mbus_framefmt *mf)
+{
+	unsigned int min_err = ~0;
+	int i = ARRAY_SIZE(sr030pc30_sizes);
+	const struct sr030pc30_frmsize *fsize = &sr030pc30_sizes[0],
+					*match = NULL;
+	while (i--) {
+		int err = abs(fsize->width - mf->width)
+				+ abs(fsize->height - mf->height);
+		if (err < min_err) {
+			min_err = err;
+			match = fsize;
+		}
+		fsize++;
+	}
+	if (match) {
+		mf->width  = match->width;
+		mf->height = match->height;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int sr030pc30_queryctrl(struct v4l2_subdev *sd,
+			       struct v4l2_queryctrl *qc)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(sr030pc30_ctrl); i++)
+		if (qc->id == sr030pc30_ctrl[i].id) {
+			*qc = sr030pc30_ctrl[i];
+			v4l2_dbg(1, debug, sd, "%s id: %d\n",
+				 __func__, qc->id);
+			return 0;
+		}
+
+	return -EINVAL;
+}
+
+static inline int sr030pc30_set_bluebalance(struct v4l2_subdev *sd, int value)
+{
+	int ret = cam_i2c_write(sd, MWB_BGAIN_REG, value);
+	if (!ret)
+		to_sr030pc30(sd)->blue_balance = value;
+	return ret;
+}
+
+static inline int sr030pc30_set_redbalance(struct v4l2_subdev *sd, int value)
+{
+	int ret = cam_i2c_write(sd, MWB_RGAIN_REG, value);
+	if (!ret)
+		to_sr030pc30(sd)->red_balance = value;
+	return ret;
+}
+
+static int sr030pc30_s_ctrl(struct v4l2_subdev *sd,
+			    struct v4l2_control *ctrl)
+{
+	int i, ret = 0;
+
+	for (i = 0; i < ARRAY_SIZE(sr030pc30_ctrl); i++)
+		if (ctrl->id == sr030pc30_ctrl[i].id)
+			break;
+
+	if (i == ARRAY_SIZE(sr030pc30_ctrl))
+		return -EINVAL;
+
+	if (ctrl->value < sr030pc30_ctrl[i].minimum ||
+		ctrl->value > sr030pc30_ctrl[i].maximum)
+			return -ERANGE;
+
+	v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n",
+			 __func__, ctrl->id, ctrl->value);
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		sr030pc30_enable_autowhitebalance(sd, ctrl->value);
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		ret = sr030pc30_set_bluebalance(sd, ctrl->value);
+		break;
+	case V4L2_CID_RED_BALANCE:
+		ret = sr030pc30_set_redbalance(sd, ctrl->value);
+		break;
+	case V4L2_CID_EXPOSURE_AUTO:
+		sr030pc30_enable_autoexposure(sd,
+			ctrl->value == V4L2_EXPOSURE_AUTO);
+		break;
+	case V4L2_CID_EXPOSURE:
+		ret = sr030pc30_set_exposure(sd, ctrl->value);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int sr030pc30_g_ctrl(struct v4l2_subdev *sd,
+			    struct v4l2_control *ctrl)
+{
+	struct sr030pc30_info *info = to_sr030pc30(sd);
+
+	v4l2_dbg(1, debug, sd, "%s: id: %d\n", __func__, ctrl->id);
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		ctrl->value = info->auto_wb;
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		ctrl->value = info->blue_balance;
+		break;
+	case V4L2_CID_RED_BALANCE:
+		ctrl->value = info->red_balance;
+		break;
+	case V4L2_CID_EXPOSURE_AUTO:
+		ctrl->value = info->auto_exp;
+		break;
+	case V4L2_CID_EXPOSURE:
+		ctrl->value = info->exposure;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int sr030pc30_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			      enum v4l2_mbus_pixelcode *code)
+{
+	if (!code || index >= ARRAY_SIZE(sr030pc30_formats))
+		return -EINVAL;
+
+	*code = sr030pc30_formats[index].code;
+	return 0;
+}
+
+static int sr030pc30_g_fmt(struct v4l2_subdev *sd,
+			   struct v4l2_mbus_framefmt *mf)
+{
+	struct sr030pc30_info *info = to_sr030pc30(sd);
+	int ret;
+
+	if (!mf)
+		return -EINVAL;
+
+	if (!info->curr_win || !info->curr_fmt) {
+		ret = sr030pc30_set_params(sd);
+		if (ret)
+			return ret;
+	}
+
+	mf->width	= info->curr_win->width;
+	mf->height	= info->curr_win->height;
+	mf->code	= info->curr_fmt->code;
+	mf->colorspace	= info->curr_fmt->colorspace;
+	mf->field	= V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+/* Return nearest media bus frame format. */
+static const struct sr030pc30_format *try_fmt(struct v4l2_subdev *sd,
+					      struct v4l2_mbus_framefmt *mf)
+{
+	int i = ARRAY_SIZE(sr030pc30_formats);
+
+	sr030pc30_try_frame_size(mf);
+
+	while (i--)
+		if (mf->code == sr030pc30_formats[i].code)
+			break;
+
+	mf->code = sr030pc30_formats[i].code;
+
+	return &sr030pc30_formats[i];
+}
+
+/* Return nearest media bus frame format. */
+static int sr030pc30_try_fmt(struct v4l2_subdev *sd,
+			     struct v4l2_mbus_framefmt *mf)
+{
+	if (!sd || !mf)
+		return -EINVAL;
+
+	try_fmt(sd, mf);
+	return 0;
+}
+
+static int sr030pc30_s_fmt(struct v4l2_subdev *sd,
+			   struct v4l2_mbus_framefmt *mf)
+{
+	struct sr030pc30_info *info = to_sr030pc30(sd);
+
+	if (!sd || !mf)
+		return -EINVAL;
+
+	info->curr_fmt = try_fmt(sd, mf);
+
+	return sr030pc30_set_params(sd);
+}
+
+static int sr030pc30_base_config(struct v4l2_subdev *sd)
+{
+	struct sr030pc30_info *info = to_sr030pc30(sd);
+	int ret;
+	unsigned long expmin, expmax;
+
+	ret = sr030pc30_bulk_write_reg(sd, sr030pc30_base_regs);
+	if (!ret) {
+		info->curr_fmt = &sr030pc30_formats[0];
+		info->curr_win = &sr030pc30_sizes[0];
+		ret = sr030pc30_set_params(sd);
+	}
+	if (!ret)
+		ret = sr030pc30_pwr_ctrl(sd, false, false);
+
+	if (!ret && !info->pdata)
+		return ret;
+
+	expmin = EXPOS_MIN_MS * info->pdata->clk_rate / (8 * 1000);
+	expmax = EXPOS_MAX_MS * info->pdata->clk_rate / (8 * 1000);
+
+	v4l2_dbg(1, debug, sd, "%s: expmin= %lx, expmax= %lx", __func__,
+		 expmin, expmax);
+
+	/* Setting up manual exposure time range */
+	ret = cam_i2c_write(sd, EXP_MMINH_REG, expmin >> 8 & 0xFF);
+	if (!ret)
+		ret = cam_i2c_write(sd, EXP_MMINL_REG, expmin & 0xFF);
+	if (!ret)
+		ret = cam_i2c_write(sd, EXP_MMAXH_REG, expmax >> 16 & 0xFF);
+	if (!ret)
+		ret = cam_i2c_write(sd, EXP_MMAXM_REG, expmax >> 8 & 0xFF);
+	if (!ret)
+		ret = cam_i2c_write(sd, EXP_MMAXL_REG, expmax & 0xFF);
+
+	return ret;
+}
+
+static int sr030pc30_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct sr030pc30_info *info = to_sr030pc30(sd);
+	const struct sr030pc30_platform_data *pdata = info->pdata;
+	int ret;
+
+	if (pdata == NULL) {
+		WARN(1, "No platform data!\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Put sensor into power sleep mode before switching off
+	 * power and disabling MCLK.
+	 */
+	if (!on)
+		sr030pc30_pwr_ctrl(sd, false, true);
+
+	/* set_power controls sensor's power and clock */
+	if (pdata->set_power) {
+		ret = pdata->set_power(&client->dev, on);
+		if (ret)
+			return ret;
+	}
+
+	if (on) {
+		ret = sr030pc30_base_config(sd);
+	} else {
+		ret = 0;
+		info->curr_win = NULL;
+		info->curr_fmt = NULL;
+	}
+
+	return ret;
+}
+
+static const struct v4l2_subdev_core_ops sr030pc30_core_ops = {
+	.s_power	= sr030pc30_s_power,
+	.queryctrl	= sr030pc30_queryctrl,
+	.s_ctrl		= sr030pc30_s_ctrl,
+	.g_ctrl		= sr030pc30_g_ctrl,
+};
+
+static const struct v4l2_subdev_video_ops sr030pc30_video_ops = {
+	.g_mbus_fmt	= sr030pc30_g_fmt,
+	.s_mbus_fmt	= sr030pc30_s_fmt,
+	.try_mbus_fmt	= sr030pc30_try_fmt,
+	.enum_mbus_fmt	= sr030pc30_enum_fmt,
+};
+
+static const struct v4l2_subdev_ops sr030pc30_ops = {
+	.core	= &sr030pc30_core_ops,
+	.video	= &sr030pc30_video_ops,
+};
+
+/*
+ * Detect sensor type. Return 0 if SR030PC30 was detected
+ * or -ENODEV otherwise.
+ */
+static int sr030pc30_detect(struct i2c_client *client)
+{
+	const struct sr030pc30_platform_data *pdata
+		= client->dev.platform_data;
+	int ret;
+
+	/* Enable sensor's power and clock */
+	if (pdata->set_power) {
+		ret = pdata->set_power(&client->dev, 1);
+		if (ret)
+			return ret;
+	}
+
+	ret = i2c_smbus_read_byte_data(client, DEVICE_ID_REG);
+
+	if (pdata->set_power)
+		pdata->set_power(&client->dev, 0);
+
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: I2C read failed\n", __func__);
+		return ret;
+	}
+
+	return ret == SR030PC30_ID ? 0 : -ENODEV;
+}
+
+
+static int sr030pc30_probe(struct i2c_client *client,
+			   const struct i2c_device_id *id)
+{
+	struct sr030pc30_info *info;
+	struct v4l2_subdev *sd;
+	const struct sr030pc30_platform_data *pdata
+		= client->dev.platform_data;
+	int ret;
+
+	if (!pdata) {
+		dev_err(&client->dev, "No platform data!");
+		return -EIO;
+	}
+
+	ret = sr030pc30_detect(client);
+	if (ret)
+		return ret;
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	sd = &info->sd;
+	strcpy(sd->name, MODULE_NAME);
+	info->pdata = client->dev.platform_data;
+
+	v4l2_i2c_subdev_init(sd, client, &sr030pc30_ops);
+
+	info->i2c_reg_page	= -1;
+	info->hflip		= 1;
+	info->auto_exp		= 1;
+	info->exposure		= 30;
+
+	return 0;
+}
+
+static int sr030pc30_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct sr030pc30_info *info = to_sr030pc30(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(info);
+	return 0;
+}
+
+static const struct i2c_device_id sr030pc30_id[] = {
+	{ MODULE_NAME, 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, sr030pc30_id);
+
+
+static struct i2c_driver sr030pc30_i2c_driver = {
+	.driver = {
+		.name = MODULE_NAME
+	},
+	.probe		= sr030pc30_probe,
+	.remove		= sr030pc30_remove,
+	.id_table	= sr030pc30_id,
+};
+
+module_i2c_driver(sr030pc30_i2c_driver);
+
+MODULE_DESCRIPTION("Siliconfile SR030PC30 camera driver");
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/tcm825x.c b/drivers/media/i2c/tcm825x.c
new file mode 100644
index 0000000..9252529
--- /dev/null
+++ b/drivers/media/i2c/tcm825x.c
@@ -0,0 +1,937 @@
+/*
+ * drivers/media/i2c/tcm825x.c
+ *
+ * TCM825X camera sensor driver.
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from David Cohen <david.cohen@indt.org.br>
+ *
+ * This driver was based on ov9640 sensor driver from MontaVista
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <media/v4l2-int-device.h>
+
+#include "tcm825x.h"
+
+/*
+ * The sensor has two fps modes: the lower one just gives half the fps
+ * at the same xclk than the high one.
+ */
+#define MAX_FPS 30
+#define MIN_FPS 8
+#define MAX_HALF_FPS (MAX_FPS / 2)
+#define HIGH_FPS_MODE_LOWER_LIMIT 14
+#define DEFAULT_FPS MAX_HALF_FPS
+
+struct tcm825x_sensor {
+	const struct tcm825x_platform_data *platform_data;
+	struct v4l2_int_device *v4l2_int_device;
+	struct i2c_client *i2c_client;
+	struct v4l2_pix_format pix;
+	struct v4l2_fract timeperframe;
+};
+
+/* list of image formats supported by TCM825X sensor */
+static const struct v4l2_fmtdesc tcm825x_formats[] = {
+	{
+		.description = "YUYV (YUV 4:2:2), packed",
+		.pixelformat = V4L2_PIX_FMT_UYVY,
+	}, {
+		/* Note:  V4L2 defines RGB565 as:
+		 *
+		 *      Byte 0                    Byte 1
+		 *      g2 g1 g0 r4 r3 r2 r1 r0   b4 b3 b2 b1 b0 g5 g4 g3
+		 *
+		 * We interpret RGB565 as:
+		 *
+		 *      Byte 0                    Byte 1
+		 *      g2 g1 g0 b4 b3 b2 b1 b0   r4 r3 r2 r1 r0 g5 g4 g3
+		 */
+		.description = "RGB565, le",
+		.pixelformat = V4L2_PIX_FMT_RGB565,
+	},
+};
+
+#define TCM825X_NUM_CAPTURE_FORMATS	ARRAY_SIZE(tcm825x_formats)
+
+/*
+ * TCM825X register configuration for all combinations of pixel format and
+ * image size
+ */
+static const struct tcm825x_reg subqcif	=	{ 0x20, TCM825X_PICSIZ };
+static const struct tcm825x_reg qcif	=	{ 0x18, TCM825X_PICSIZ };
+static const struct tcm825x_reg cif	=	{ 0x14, TCM825X_PICSIZ };
+static const struct tcm825x_reg qqvga	=	{ 0x0c, TCM825X_PICSIZ };
+static const struct tcm825x_reg qvga	=	{ 0x04, TCM825X_PICSIZ };
+static const struct tcm825x_reg vga	=	{ 0x00, TCM825X_PICSIZ };
+
+static const struct tcm825x_reg yuv422	=	{ 0x00, TCM825X_PICFMT };
+static const struct tcm825x_reg rgb565	=	{ 0x02, TCM825X_PICFMT };
+
+/* Our own specific controls */
+#define V4L2_CID_ALC				V4L2_CID_PRIVATE_BASE
+#define V4L2_CID_H_EDGE_EN			V4L2_CID_PRIVATE_BASE + 1
+#define V4L2_CID_V_EDGE_EN			V4L2_CID_PRIVATE_BASE + 2
+#define V4L2_CID_LENS				V4L2_CID_PRIVATE_BASE + 3
+#define V4L2_CID_MAX_EXPOSURE_TIME		V4L2_CID_PRIVATE_BASE + 4
+#define V4L2_CID_LAST_PRIV			V4L2_CID_MAX_EXPOSURE_TIME
+
+/*  Video controls  */
+static struct vcontrol {
+	struct v4l2_queryctrl qc;
+	u16 reg;
+	u16 start_bit;
+} video_control[] = {
+	{
+		{
+			.id = V4L2_CID_GAIN,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Gain",
+			.minimum = 0,
+			.maximum = 63,
+			.step = 1,
+		},
+		.reg = TCM825X_AG,
+		.start_bit = 0,
+	},
+	{
+		{
+			.id = V4L2_CID_RED_BALANCE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Red Balance",
+			.minimum = 0,
+			.maximum = 255,
+			.step = 1,
+		},
+		.reg = TCM825X_MRG,
+		.start_bit = 0,
+	},
+	{
+		{
+			.id = V4L2_CID_BLUE_BALANCE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Blue Balance",
+			.minimum = 0,
+			.maximum = 255,
+			.step = 1,
+		},
+		.reg = TCM825X_MBG,
+		.start_bit = 0,
+	},
+	{
+		{
+			.id = V4L2_CID_AUTO_WHITE_BALANCE,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+			.name = "Auto White Balance",
+			.minimum = 0,
+			.maximum = 1,
+			.step = 0,
+		},
+		.reg = TCM825X_AWBSW,
+		.start_bit = 7,
+	},
+	{
+		{
+			.id = V4L2_CID_EXPOSURE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Exposure Time",
+			.minimum = 0,
+			.maximum = 0x1fff,
+			.step = 1,
+		},
+		.reg = TCM825X_ESRSPD_U,
+		.start_bit = 0,
+	},
+	{
+		{
+			.id = V4L2_CID_HFLIP,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+			.name = "Mirror Image",
+			.minimum = 0,
+			.maximum = 1,
+			.step = 0,
+		},
+		.reg = TCM825X_H_INV,
+		.start_bit = 6,
+	},
+	{
+		{
+			.id = V4L2_CID_VFLIP,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+			.name = "Vertical Flip",
+			.minimum = 0,
+			.maximum = 1,
+			.step = 0,
+		},
+		.reg = TCM825X_V_INV,
+		.start_bit = 7,
+	},
+	/* Private controls */
+	{
+		{
+			.id = V4L2_CID_ALC,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+			.name = "Auto Luminance Control",
+			.minimum = 0,
+			.maximum = 1,
+			.step = 0,
+		},
+		.reg = TCM825X_ALCSW,
+		.start_bit = 7,
+	},
+	{
+		{
+			.id = V4L2_CID_H_EDGE_EN,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Horizontal Edge Enhancement",
+			.minimum = 0,
+			.maximum = 0xff,
+			.step = 1,
+		},
+		.reg = TCM825X_HDTG,
+		.start_bit = 0,
+	},
+	{
+		{
+			.id = V4L2_CID_V_EDGE_EN,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Vertical Edge Enhancement",
+			.minimum = 0,
+			.maximum = 0xff,
+			.step = 1,
+		},
+		.reg = TCM825X_VDTG,
+		.start_bit = 0,
+	},
+	{
+		{
+			.id = V4L2_CID_LENS,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Lens Shading Compensation",
+			.minimum = 0,
+			.maximum = 0x3f,
+			.step = 1,
+		},
+		.reg = TCM825X_LENS,
+		.start_bit = 0,
+	},
+	{
+		{
+			.id = V4L2_CID_MAX_EXPOSURE_TIME,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Maximum Exposure Time",
+			.minimum = 0,
+			.maximum = 0x3,
+			.step = 1,
+		},
+		.reg = TCM825X_ESRLIM,
+		.start_bit = 5,
+	},
+};
+
+
+static const struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] =
+{ &subqcif, &qqvga, &qcif, &qvga, &cif, &vga };
+
+static const struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] =
+{ &yuv422, &rgb565 };
+
+/*
+ * Read a value from a register in an TCM825X sensor device.  The value is
+ * returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tcm825x_read_reg(struct i2c_client *client, int reg)
+{
+	int err;
+	struct i2c_msg msg[2];
+	u8 reg_buf, data_buf = 0;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	msg[0].addr = client->addr;
+	msg[0].flags = 0;
+	msg[0].len = 1;
+	msg[0].buf = &reg_buf;
+	msg[1].addr = client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = 1;
+	msg[1].buf = &data_buf;
+
+	reg_buf = reg;
+
+	err = i2c_transfer(client->adapter, msg, 2);
+	if (err < 0)
+		return err;
+	return data_buf;
+}
+
+/*
+ * Write a value to a register in an TCM825X sensor device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tcm825x_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+	int err;
+	struct i2c_msg msg[1];
+	unsigned char data[2];
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	msg->addr = client->addr;
+	msg->flags = 0;
+	msg->len = 2;
+	msg->buf = data;
+	data[0] = reg;
+	data[1] = val;
+	err = i2c_transfer(client->adapter, msg, 1);
+	if (err >= 0)
+		return 0;
+	return err;
+}
+
+static int __tcm825x_write_reg_mask(struct i2c_client *client,
+				    u8 reg, u8 val, u8 mask)
+{
+	int rc;
+
+	/* need to do read - modify - write */
+	rc = tcm825x_read_reg(client, reg);
+	if (rc < 0)
+		return rc;
+
+	rc &= (~mask);	/* Clear the masked bits */
+	val &= mask;	/* Enforce mask on value */
+	val |= rc;
+
+	/* write the new value to the register */
+	rc = tcm825x_write_reg(client, reg, val);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+#define tcm825x_write_reg_mask(client, regmask, val)			\
+	__tcm825x_write_reg_mask(client, TCM825X_ADDR((regmask)), val,	\
+				 TCM825X_MASK((regmask)))
+
+
+/*
+ * Initialize a list of TCM825X registers.
+ * The list of registers is terminated by the pair of values
+ * { TCM825X_REG_TERM, TCM825X_VAL_TERM }.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tcm825x_write_default_regs(struct i2c_client *client,
+				      const struct tcm825x_reg *reglist)
+{
+	int err;
+	const struct tcm825x_reg *next = reglist;
+
+	while (!((next->reg == TCM825X_REG_TERM)
+		 && (next->val == TCM825X_VAL_TERM))) {
+		err = tcm825x_write_reg(client, next->reg, next->val);
+		if (err) {
+			dev_err(&client->dev, "register writing failed\n");
+			return err;
+		}
+		next++;
+	}
+
+	return 0;
+}
+
+static struct vcontrol *find_vctrl(int id)
+{
+	int i;
+
+	if (id < V4L2_CID_BASE)
+		return NULL;
+
+	for (i = 0; i < ARRAY_SIZE(video_control); i++)
+		if (video_control[i].qc.id == id)
+			return &video_control[i];
+
+	return NULL;
+}
+
+/*
+ * Find the best match for a requested image capture size.  The best match
+ * is chosen as the nearest match that has the same number or fewer pixels
+ * as the requested size, or the smallest image size if the requested size
+ * has fewer pixels than the smallest image.
+ */
+static enum image_size tcm825x_find_size(struct v4l2_int_device *s,
+					 unsigned int width,
+					 unsigned int height)
+{
+	enum image_size isize;
+	unsigned long pixels = width * height;
+	struct tcm825x_sensor *sensor = s->priv;
+
+	for (isize = subQCIF; isize < VGA; isize++) {
+		if (tcm825x_sizes[isize + 1].height
+		    * tcm825x_sizes[isize + 1].width > pixels) {
+			dev_dbg(&sensor->i2c_client->dev, "size %d\n", isize);
+
+			return isize;
+		}
+	}
+
+	dev_dbg(&sensor->i2c_client->dev, "format default VGA\n");
+
+	return VGA;
+}
+
+/*
+ * Configure the TCM825X for current image size, pixel format, and
+ * frame period. fper is the frame period (in seconds) expressed as a
+ * fraction. Returns zero if successful, or non-zero otherwise. The
+ * actual frame period is returned in fper.
+ */
+static int tcm825x_configure(struct v4l2_int_device *s)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	struct v4l2_pix_format *pix = &sensor->pix;
+	enum image_size isize = tcm825x_find_size(s, pix->width, pix->height);
+	struct v4l2_fract *fper = &sensor->timeperframe;
+	enum pixel_format pfmt;
+	int err;
+	u32 tgt_fps;
+	u8 val;
+
+	/* common register initialization */
+	err = tcm825x_write_default_regs(
+		sensor->i2c_client, sensor->platform_data->default_regs());
+	if (err)
+		return err;
+
+	/* configure image size */
+	val = tcm825x_siz_reg[isize]->val;
+	dev_dbg(&sensor->i2c_client->dev,
+		"configuring image size %d\n", isize);
+	err = tcm825x_write_reg_mask(sensor->i2c_client,
+				     tcm825x_siz_reg[isize]->reg, val);
+	if (err)
+		return err;
+
+	/* configure pixel format */
+	switch (pix->pixelformat) {
+	default:
+	case V4L2_PIX_FMT_RGB565:
+		pfmt = RGB565;
+		break;
+	case V4L2_PIX_FMT_UYVY:
+		pfmt = YUV422;
+		break;
+	}
+
+	dev_dbg(&sensor->i2c_client->dev,
+		"configuring pixel format %d\n", pfmt);
+	val = tcm825x_fmt_reg[pfmt]->val;
+
+	err = tcm825x_write_reg_mask(sensor->i2c_client,
+				     tcm825x_fmt_reg[pfmt]->reg, val);
+	if (err)
+		return err;
+
+	/*
+	 * For frame rate < 15, the FPS reg (addr 0x02, bit 7) must be
+	 * set. Frame rate will be halved from the normal.
+	 */
+	tgt_fps = fper->denominator / fper->numerator;
+	if (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) {
+		val = tcm825x_read_reg(sensor->i2c_client, 0x02);
+		val |= 0x80;
+		tcm825x_write_reg(sensor->i2c_client, 0x02, val);
+	}
+
+	return 0;
+}
+
+static int ioctl_queryctrl(struct v4l2_int_device *s,
+				struct v4l2_queryctrl *qc)
+{
+	struct vcontrol *control;
+
+	control = find_vctrl(qc->id);
+
+	if (control == NULL)
+		return -EINVAL;
+
+	*qc = control->qc;
+
+	return 0;
+}
+
+static int ioctl_g_ctrl(struct v4l2_int_device *s,
+			     struct v4l2_control *vc)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	struct i2c_client *client = sensor->i2c_client;
+	int val, r;
+	struct vcontrol *lvc;
+
+	/* exposure time is special, spread across 2 registers */
+	if (vc->id == V4L2_CID_EXPOSURE) {
+		int val_lower, val_upper;
+
+		val_upper = tcm825x_read_reg(client,
+					     TCM825X_ADDR(TCM825X_ESRSPD_U));
+		if (val_upper < 0)
+			return val_upper;
+		val_lower = tcm825x_read_reg(client,
+					     TCM825X_ADDR(TCM825X_ESRSPD_L));
+		if (val_lower < 0)
+			return val_lower;
+
+		vc->value = ((val_upper & 0x1f) << 8) | (val_lower);
+		return 0;
+	}
+
+	lvc = find_vctrl(vc->id);
+	if (lvc == NULL)
+		return -EINVAL;
+
+	r = tcm825x_read_reg(client, TCM825X_ADDR(lvc->reg));
+	if (r < 0)
+		return r;
+	val = r & TCM825X_MASK(lvc->reg);
+	val >>= lvc->start_bit;
+
+	if (val < 0)
+		return val;
+
+	if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP)
+		val ^= sensor->platform_data->is_upside_down();
+
+	vc->value = val;
+	return 0;
+}
+
+static int ioctl_s_ctrl(struct v4l2_int_device *s,
+			     struct v4l2_control *vc)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	struct i2c_client *client = sensor->i2c_client;
+	struct vcontrol *lvc;
+	int val = vc->value;
+
+	/* exposure time is special, spread across 2 registers */
+	if (vc->id == V4L2_CID_EXPOSURE) {
+		int val_lower, val_upper;
+		val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L);
+		val_upper = (val >> 8) & TCM825X_MASK(TCM825X_ESRSPD_U);
+
+		if (tcm825x_write_reg_mask(client,
+					   TCM825X_ESRSPD_U, val_upper))
+			return -EIO;
+
+		if (tcm825x_write_reg_mask(client,
+					   TCM825X_ESRSPD_L, val_lower))
+			return -EIO;
+
+		return 0;
+	}
+
+	lvc = find_vctrl(vc->id);
+	if (lvc == NULL)
+		return -EINVAL;
+
+	if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP)
+		val ^= sensor->platform_data->is_upside_down();
+
+	val = val << lvc->start_bit;
+	if (tcm825x_write_reg_mask(client, lvc->reg, val))
+		return -EIO;
+
+	return 0;
+}
+
+static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
+				   struct v4l2_fmtdesc *fmt)
+{
+	int index = fmt->index;
+
+	switch (fmt->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		if (index >= TCM825X_NUM_CAPTURE_FORMATS)
+			return -EINVAL;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	fmt->flags = tcm825x_formats[index].flags;
+	strlcpy(fmt->description, tcm825x_formats[index].description,
+		sizeof(fmt->description));
+	fmt->pixelformat = tcm825x_formats[index].pixelformat;
+
+	return 0;
+}
+
+static int ioctl_try_fmt_cap(struct v4l2_int_device *s,
+			     struct v4l2_format *f)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	enum image_size isize;
+	int ifmt;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+
+	isize = tcm825x_find_size(s, pix->width, pix->height);
+	dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %lu\n",
+		isize, (unsigned long)TCM825X_NUM_CAPTURE_FORMATS);
+
+	pix->width = tcm825x_sizes[isize].width;
+	pix->height = tcm825x_sizes[isize].height;
+
+	for (ifmt = 0; ifmt < TCM825X_NUM_CAPTURE_FORMATS; ifmt++)
+		if (pix->pixelformat == tcm825x_formats[ifmt].pixelformat)
+			break;
+
+	if (ifmt == TCM825X_NUM_CAPTURE_FORMATS)
+		ifmt = 0;	/* Default = YUV 4:2:2 */
+
+	pix->pixelformat = tcm825x_formats[ifmt].pixelformat;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = pix->width * TCM825X_BYTES_PER_PIXEL;
+	pix->sizeimage = pix->bytesperline * pix->height;
+	pix->priv = 0;
+	dev_dbg(&sensor->i2c_client->dev, "format = 0x%08x\n",
+		pix->pixelformat);
+
+	switch (pix->pixelformat) {
+	case V4L2_PIX_FMT_UYVY:
+	default:
+		pix->colorspace = V4L2_COLORSPACE_JPEG;
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		pix->colorspace = V4L2_COLORSPACE_SRGB;
+		break;
+	}
+
+	return 0;
+}
+
+static int ioctl_s_fmt_cap(struct v4l2_int_device *s,
+				struct v4l2_format *f)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	int rval;
+
+	rval = ioctl_try_fmt_cap(s, f);
+	if (rval)
+		return rval;
+
+	rval = tcm825x_configure(s);
+
+	sensor->pix = *pix;
+
+	return rval;
+}
+
+static int ioctl_g_fmt_cap(struct v4l2_int_device *s,
+				struct v4l2_format *f)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+
+	f->fmt.pix = sensor->pix;
+
+	return 0;
+}
+
+static int ioctl_g_parm(struct v4l2_int_device *s,
+			     struct v4l2_streamparm *a)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	struct v4l2_captureparm *cparm = &a->parm.capture;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	memset(a, 0, sizeof(*a));
+	a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	cparm->capability = V4L2_CAP_TIMEPERFRAME;
+	cparm->timeperframe = sensor->timeperframe;
+
+	return 0;
+}
+
+static int ioctl_s_parm(struct v4l2_int_device *s,
+			     struct v4l2_streamparm *a)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+	u32 tgt_fps;	/* target frames per secound */
+	int rval;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if ((timeperframe->numerator == 0)
+	    || (timeperframe->denominator == 0)) {
+		timeperframe->denominator = DEFAULT_FPS;
+		timeperframe->numerator = 1;
+	}
+
+	tgt_fps = timeperframe->denominator / timeperframe->numerator;
+
+	if (tgt_fps > MAX_FPS) {
+		timeperframe->denominator = MAX_FPS;
+		timeperframe->numerator = 1;
+	} else if (tgt_fps < MIN_FPS) {
+		timeperframe->denominator = MIN_FPS;
+		timeperframe->numerator = 1;
+	}
+
+	sensor->timeperframe = *timeperframe;
+
+	rval = tcm825x_configure(s);
+
+	return rval;
+}
+
+static int ioctl_s_power(struct v4l2_int_device *s, int on)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+
+	return sensor->platform_data->power_set(on);
+}
+
+/*
+ * Given the image capture format in pix, the nominal frame period in
+ * timeperframe, calculate the required xclk frequency.
+ *
+ * TCM825X input frequency characteristics are:
+ *     Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz
+ */
+
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	struct v4l2_fract *timeperframe = &sensor->timeperframe;
+	u32 tgt_xclk;	/* target xclk */
+	u32 tgt_fps;	/* target frames per secound */
+	int rval;
+
+	rval = sensor->platform_data->ifparm(p);
+	if (rval)
+		return rval;
+
+	tgt_fps = timeperframe->denominator / timeperframe->numerator;
+
+	tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ?
+		(2457 * tgt_fps) / MAX_HALF_FPS :
+		(2457 * tgt_fps) / MAX_FPS;
+	tgt_xclk *= 10000;
+
+	tgt_xclk = min(tgt_xclk, (u32)TCM825X_XCLK_MAX);
+	tgt_xclk = max(tgt_xclk, (u32)TCM825X_XCLK_MIN);
+
+	p->u.bt656.clock_curr = tgt_xclk;
+
+	return 0;
+}
+
+static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+
+	return sensor->platform_data->needs_reset(s, buf, &sensor->pix);
+}
+
+static int ioctl_reset(struct v4l2_int_device *s)
+{
+	return -EBUSY;
+}
+
+static int ioctl_init(struct v4l2_int_device *s)
+{
+	return tcm825x_configure(s);
+}
+
+static int ioctl_dev_exit(struct v4l2_int_device *s)
+{
+	return 0;
+}
+
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	int r;
+
+	r = tcm825x_read_reg(sensor->i2c_client, 0x01);
+	if (r < 0)
+		return r;
+	if (r == 0) {
+		dev_err(&sensor->i2c_client->dev, "device not detected\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[] = {
+	{ vidioc_int_dev_init_num,
+	  (v4l2_int_ioctl_func *)ioctl_dev_init },
+	{ vidioc_int_dev_exit_num,
+	  (v4l2_int_ioctl_func *)ioctl_dev_exit },
+	{ vidioc_int_s_power_num,
+	  (v4l2_int_ioctl_func *)ioctl_s_power },
+	{ vidioc_int_g_ifparm_num,
+	  (v4l2_int_ioctl_func *)ioctl_g_ifparm },
+	{ vidioc_int_g_needs_reset_num,
+	  (v4l2_int_ioctl_func *)ioctl_g_needs_reset },
+	{ vidioc_int_reset_num,
+	  (v4l2_int_ioctl_func *)ioctl_reset },
+	{ vidioc_int_init_num,
+	  (v4l2_int_ioctl_func *)ioctl_init },
+	{ vidioc_int_enum_fmt_cap_num,
+	  (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap },
+	{ vidioc_int_try_fmt_cap_num,
+	  (v4l2_int_ioctl_func *)ioctl_try_fmt_cap },
+	{ vidioc_int_g_fmt_cap_num,
+	  (v4l2_int_ioctl_func *)ioctl_g_fmt_cap },
+	{ vidioc_int_s_fmt_cap_num,
+	  (v4l2_int_ioctl_func *)ioctl_s_fmt_cap },
+	{ vidioc_int_g_parm_num,
+	  (v4l2_int_ioctl_func *)ioctl_g_parm },
+	{ vidioc_int_s_parm_num,
+	  (v4l2_int_ioctl_func *)ioctl_s_parm },
+	{ vidioc_int_queryctrl_num,
+	  (v4l2_int_ioctl_func *)ioctl_queryctrl },
+	{ vidioc_int_g_ctrl_num,
+	  (v4l2_int_ioctl_func *)ioctl_g_ctrl },
+	{ vidioc_int_s_ctrl_num,
+	  (v4l2_int_ioctl_func *)ioctl_s_ctrl },
+};
+
+static struct v4l2_int_slave tcm825x_slave = {
+	.ioctls = tcm825x_ioctl_desc,
+	.num_ioctls = ARRAY_SIZE(tcm825x_ioctl_desc),
+};
+
+static struct tcm825x_sensor tcm825x;
+
+static struct v4l2_int_device tcm825x_int_device = {
+	.module = THIS_MODULE,
+	.name = TCM825X_NAME,
+	.priv = &tcm825x,
+	.type = v4l2_int_type_slave,
+	.u = {
+		.slave = &tcm825x_slave,
+	},
+};
+
+static int tcm825x_probe(struct i2c_client *client,
+			 const struct i2c_device_id *did)
+{
+	struct tcm825x_sensor *sensor = &tcm825x;
+
+	if (i2c_get_clientdata(client))
+		return -EBUSY;
+
+	sensor->platform_data = client->dev.platform_data;
+
+	if (sensor->platform_data == NULL
+	    || !sensor->platform_data->is_okay())
+		return -ENODEV;
+
+	sensor->v4l2_int_device = &tcm825x_int_device;
+
+	sensor->i2c_client = client;
+	i2c_set_clientdata(client, sensor);
+
+	/* Make the default capture format QVGA RGB565 */
+	sensor->pix.width = tcm825x_sizes[QVGA].width;
+	sensor->pix.height = tcm825x_sizes[QVGA].height;
+	sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565;
+
+	return v4l2_int_device_register(sensor->v4l2_int_device);
+}
+
+static int tcm825x_remove(struct i2c_client *client)
+{
+	struct tcm825x_sensor *sensor = i2c_get_clientdata(client);
+
+	if (!client->adapter)
+		return -ENODEV;	/* our client isn't attached */
+
+	v4l2_int_device_unregister(sensor->v4l2_int_device);
+
+	return 0;
+}
+
+static const struct i2c_device_id tcm825x_id[] = {
+	{ "tcm825x", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tcm825x_id);
+
+static struct i2c_driver tcm825x_i2c_driver = {
+	.driver	= {
+		.name = TCM825X_NAME,
+	},
+	.probe	= tcm825x_probe,
+	.remove	= tcm825x_remove,
+	.id_table = tcm825x_id,
+};
+
+static struct tcm825x_sensor tcm825x = {
+	.timeperframe = {
+		.numerator   = 1,
+		.denominator = DEFAULT_FPS,
+	},
+};
+
+static int __init tcm825x_init(void)
+{
+	int rval;
+
+	rval = i2c_add_driver(&tcm825x_i2c_driver);
+	if (rval)
+		printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n",
+		       __func__);
+
+	return rval;
+}
+
+static void __exit tcm825x_exit(void)
+{
+	i2c_del_driver(&tcm825x_i2c_driver);
+}
+
+/*
+ * FIXME: Menelaus isn't ready (?) at module_init stage, so use
+ * late_initcall for now.
+ */
+late_initcall(tcm825x_init);
+module_exit(tcm825x_exit);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
+MODULE_DESCRIPTION("TCM825x camera sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/tcm825x.h b/drivers/media/i2c/tcm825x.h
new file mode 100644
index 0000000..8ebab95
--- /dev/null
+++ b/drivers/media/i2c/tcm825x.h
@@ -0,0 +1,200 @@
+/*
+ * drivers/media/i2c/tcm825x.h
+ *
+ * Register definitions for the TCM825X CameraChip.
+ *
+ * Author: David Cohen (david.cohen@indt.org.br)
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * This file was based on ov9640.h from MontaVista
+ */
+
+#ifndef TCM825X_H
+#define TCM825X_H
+
+#include <linux/videodev2.h>
+
+#include <media/v4l2-int-device.h>
+
+#define TCM825X_NAME "tcm825x"
+
+#define TCM825X_MASK(x)  x & 0x00ff
+#define TCM825X_ADDR(x) (x & 0xff00) >> 8
+
+/* The TCM825X I2C sensor chip has a fixed slave address of 0x3d. */
+#define TCM825X_I2C_ADDR	0x3d
+
+/*
+ * define register offsets for the TCM825X sensor chip
+ * OFFSET(8 bits) + MASK(8 bits)
+ * MASK bit 4 and 3 are used when the register uses more than one address
+ */
+#define TCM825X_FPS		0x0280
+#define TCM825X_ACF		0x0240
+#define TCM825X_DOUTBUF		0x020C
+#define TCM825X_DCLKP		0x0202
+#define TCM825X_ACFDET		0x0201
+#define TCM825X_DOUTSW		0x0380
+#define TCM825X_DATAHZ		0x0340
+#define TCM825X_PICSIZ		0x033c
+#define TCM825X_PICFMT		0x0302
+#define TCM825X_V_INV		0x0480
+#define TCM825X_H_INV		0x0440
+#define TCM825X_ESRLSW		0x0430
+#define TCM825X_V_LENGTH	0x040F
+#define TCM825X_ALCSW		0x0580
+#define TCM825X_ESRLIM		0x0560
+#define TCM825X_ESRSPD_U        0x051F
+#define TCM825X_ESRSPD_L        0x06FF
+#define TCM825X_AG		0x07FF
+#define TCM825X_ESRSPD2         0x06FF
+#define TCM825X_ALCMODE         0x0830
+#define TCM825X_ALCH            0x080F
+#define TCM825X_ALCL            0x09FF
+#define TCM825X_AWBSW           0x0A80
+#define TCM825X_MRG             0x0BFF
+#define TCM825X_MBG             0x0CFF
+#define TCM825X_GAMSW           0x0D80
+#define TCM825X_HDTG            0x0EFF
+#define TCM825X_VDTG            0x0FFF
+#define TCM825X_HDTCORE         0x10F0
+#define TCM825X_VDTCORE         0x100F
+#define TCM825X_CONT            0x11FF
+#define TCM825X_BRIGHT          0x12FF
+#define TCM825X_VHUE            0x137F
+#define TCM825X_UHUE            0x147F
+#define TCM825X_VGAIN           0x153F
+#define TCM825X_UGAIN           0x163F
+#define TCM825X_UVCORE          0x170F
+#define TCM825X_SATU            0x187F
+#define TCM825X_MHMODE          0x1980
+#define TCM825X_MHLPFSEL        0x1940
+#define TCM825X_YMODE           0x1930
+#define TCM825X_MIXHG           0x1907
+#define TCM825X_LENS            0x1A3F
+#define TCM825X_AGLIM           0x1BE0
+#define TCM825X_LENSRPOL        0x1B10
+#define TCM825X_LENSRGAIN       0x1B0F
+#define TCM825X_ES100S          0x1CFF
+#define TCM825X_ES120S          0x1DFF
+#define TCM825X_DMASK           0x1EC0
+#define TCM825X_CODESW          0x1E20
+#define TCM825X_CODESEL         0x1E10
+#define TCM825X_TESPIC          0x1E04
+#define TCM825X_PICSEL          0x1E03
+#define TCM825X_HNUM            0x20FF
+#define TCM825X_VOUTPH          0x287F
+#define TCM825X_ESROUT          0x327F
+#define TCM825X_ESROUT2         0x33FF
+#define TCM825X_AGOUT           0x34FF
+#define TCM825X_DGOUT           0x353F
+#define TCM825X_AGSLOW1         0x39C0
+#define TCM825X_FLLSMODE        0x3930
+#define TCM825X_FLLSLIM         0x390F
+#define TCM825X_DETSEL          0x3AF0
+#define TCM825X_ACDETNC         0x3A0F
+#define TCM825X_AGSLOW2         0x3BC0
+#define TCM825X_DG              0x3B3F
+#define TCM825X_REJHLEV         0x3CFF
+#define TCM825X_ALCLOCK         0x3D80
+#define TCM825X_FPSLNKSW        0x3D40
+#define TCM825X_ALCSPD          0x3D30
+#define TCM825X_REJH            0x3D03
+#define TCM825X_SHESRSW         0x3E80
+#define TCM825X_ESLIMSEL        0x3E40
+#define TCM825X_SHESRSPD        0x3E30
+#define TCM825X_ELSTEP          0x3E0C
+#define TCM825X_ELSTART         0x3E03
+#define TCM825X_AGMIN           0x3FFF
+#define TCM825X_PREGRG          0x423F
+#define TCM825X_PREGBG          0x433F
+#define TCM825X_PRERG           0x443F
+#define TCM825X_PREBG           0x453F
+#define TCM825X_MSKBR           0x477F
+#define TCM825X_MSKGR           0x487F
+#define TCM825X_MSKRB           0x497F
+#define TCM825X_MSKGB           0x4A7F
+#define TCM825X_MSKRG           0x4B7F
+#define TCM825X_MSKBG           0x4C7F
+#define TCM825X_HDTCSW          0x4D80
+#define TCM825X_VDTCSW          0x4D40
+#define TCM825X_DTCYL           0x4D3F
+#define TCM825X_HDTPSW          0x4E80
+#define TCM825X_VDTPSW          0x4E40
+#define TCM825X_DTCGAIN         0x4E3F
+#define TCM825X_DTLLIMSW        0x4F10
+#define TCM825X_DTLYLIM         0x4F0F
+#define TCM825X_YLCUTLMSK       0x5080
+#define TCM825X_YLCUTL          0x503F
+#define TCM825X_YLCUTHMSK       0x5180
+#define TCM825X_YLCUTH          0x513F
+#define TCM825X_UVSKNC          0x527F
+#define TCM825X_UVLJ            0x537F
+#define TCM825X_WBGMIN          0x54FF
+#define TCM825X_WBGMAX          0x55FF
+#define TCM825X_WBSPDUP         0x5603
+#define TCM825X_ALLAREA         0x5820
+#define TCM825X_WBLOCK          0x5810
+#define TCM825X_WB2SP           0x580F
+#define TCM825X_KIZUSW          0x5920
+#define TCM825X_PBRSW           0x5910
+#define TCM825X_ABCSW           0x5903
+#define TCM825X_PBDLV           0x5AFF
+#define TCM825X_PBC1LV          0x5BFF
+
+#define TCM825X_NUM_REGS	(TCM825X_ADDR(TCM825X_PBC1LV) + 1)
+
+#define TCM825X_BYTES_PER_PIXEL 2
+
+#define TCM825X_REG_TERM 0xff		/* terminating list entry for reg */
+#define TCM825X_VAL_TERM 0xff		/* terminating list entry for val */
+
+/* define a structure for tcm825x register initialization values */
+struct tcm825x_reg {
+	u8 val;
+	u16 reg;
+};
+
+enum image_size { subQCIF = 0, QQVGA, QCIF, QVGA, CIF, VGA };
+enum pixel_format { YUV422 = 0, RGB565 };
+#define NUM_IMAGE_SIZES 6
+#define NUM_PIXEL_FORMATS 2
+
+#define TCM825X_XCLK_MIN	11900000
+#define TCM825X_XCLK_MAX	25000000
+
+struct capture_size {
+	unsigned long width;
+	unsigned long height;
+};
+
+struct tcm825x_platform_data {
+	/* Is the sensor usable? Doesn't yet mean it's there, but you
+	 * can try! */
+	int (*is_okay)(void);
+	/* Set power state, zero is off, non-zero is on. */
+	int (*power_set)(int power);
+	/* Default registers written after power-on or reset. */
+	const struct tcm825x_reg *(*default_regs)(void);
+	int (*needs_reset)(struct v4l2_int_device *s, void *buf,
+			   struct v4l2_pix_format *fmt);
+	int (*ifparm)(struct v4l2_ifparm *p);
+	int (*is_upside_down)(void);
+};
+
+/* Array of image sizes supported by TCM825X.  These must be ordered from
+ * smallest image size to largest.
+ */
+static const struct capture_size tcm825x_sizes[] = {
+	{ 128,  96 }, /* subQCIF */
+	{ 160, 120 }, /* QQVGA */
+	{ 176, 144 }, /* QCIF */
+	{ 320, 240 }, /* QVGA */
+	{ 352, 288 }, /* CIF */
+	{ 640, 480 }, /* VGA */
+};
+
+#endif /* ifndef TCM825X_H */
diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c
new file mode 100644
index 0000000..f7707e6
--- /dev/null
+++ b/drivers/media/i2c/tda7432.c
@@ -0,0 +1,485 @@
+/*
+ * For the STS-Thompson TDA7432 audio processor chip
+ *
+ * Handles audio functions: volume, balance, tone, loudness
+ * This driver will not complain if used with any
+ * other i2c device with the same address.
+ *
+ * Muting and tone control by Jonathan Isom <jisom@ematic.com>
+ *
+ * Copyright (c) 2000 Eric Sandeen <eric_sandeen@bigfoot.com>
+ * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ * This code is placed under the terms of the GNU General Public License
+ * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
+ * Which was based on tda8425.c by Greg Alexander (c) 1998
+ *
+ * OPTIONS:
+ * debug    - set to 1 if you'd like to see debug messages
+ *            set to 2 if you'd like to be inundated with debug messages
+ *
+ * loudness - set between 0 and 15 for varying degrees of loudness effect
+ *
+ * maxvol   - set maximium volume to +20db (1), default is 0db(0)
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/i2c-addr.h>
+
+#ifndef VIDEO_AUDIO_BALANCE
+# define VIDEO_AUDIO_BALANCE 32
+#endif
+
+MODULE_AUTHOR("Eric Sandeen <eric_sandeen@bigfoot.com>");
+MODULE_DESCRIPTION("bttv driver for the tda7432 audio processor chip");
+MODULE_LICENSE("GPL");
+
+static int maxvol;
+static int loudness; /* disable loudness by default */
+static int debug;	 /* insmod parameter */
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Set debugging level from 0 to 3. Default is off(0).");
+module_param(loudness, int, S_IRUGO);
+MODULE_PARM_DESC(loudness, "Turn loudness on(1) else off(0). Default is off(0).");
+module_param(maxvol, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(maxvol, "Set maximium volume to +20dB(0) else +0dB(1). Default is +20dB(0).");
+
+
+/* Structure of address and subaddresses for the tda7432 */
+
+struct tda7432 {
+	struct v4l2_subdev sd;
+	int addr;
+	int input;
+	int volume;
+	int muted;
+	int bass, treble;
+	int lf, lr, rf, rr;
+	int loud;
+};
+
+static inline struct tda7432 *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct tda7432, sd);
+}
+
+/* The TDA7432 is made by STS-Thompson
+ * http://www.st.com
+ * http://us.st.com/stonline/books/pdf/docs/4056.pdf
+ *
+ * TDA7432: I2C-bus controlled basic audio processor
+ *
+ * The TDA7432 controls basic audio functions like volume, balance,
+ * and tone control (including loudness).  It also has four channel
+ * output (for front and rear).  Since most vidcap cards probably
+ * don't have 4 channel output, this driver will set front & rear
+ * together (no independent control).
+ */
+
+		/* Subaddresses for TDA7432 */
+
+#define TDA7432_IN	0x00 /* Input select                 */
+#define TDA7432_VL	0x01 /* Volume                       */
+#define TDA7432_TN	0x02 /* Bass, Treble (Tone)          */
+#define TDA7432_LF	0x03 /* Attenuation LF (Left Front)  */
+#define TDA7432_LR	0x04 /* Attenuation LR (Left Rear)   */
+#define TDA7432_RF	0x05 /* Attenuation RF (Right Front) */
+#define TDA7432_RR	0x06 /* Attenuation RR (Right Rear)  */
+#define TDA7432_LD	0x07 /* Loudness                     */
+
+
+		/* Masks for bits in TDA7432 subaddresses */
+
+/* Many of these not used - just for documentation */
+
+/* Subaddress 0x00 - Input selection and bass control */
+
+/* Bits 0,1,2 control input:
+ * 0x00 - Stereo input
+ * 0x02 - Mono input
+ * 0x03 - Mute  (Using Attenuators Plays better with modules)
+ * Mono probably isn't used - I'm guessing only the stereo
+ * input is connected on most cards, so we'll set it to stereo.
+ *
+ * Bit 3 controls bass cut: 0/1 is non-symmetric/symmetric bass cut
+ * Bit 4 controls bass range: 0/1 is extended/standard bass range
+ *
+ * Highest 3 bits not used
+ */
+
+#define TDA7432_STEREO_IN	0
+#define TDA7432_MONO_IN		2	/* Probably won't be used */
+#define TDA7432_BASS_SYM	1 << 3
+#define TDA7432_BASS_NORM	1 << 4
+
+/* Subaddress 0x01 - Volume */
+
+/* Lower 7 bits control volume from -79dB to +32dB in 1dB steps
+ * Recommended maximum is +20 dB
+ *
+ * +32dB: 0x00
+ * +20dB: 0x0c
+ *   0dB: 0x20
+ * -79dB: 0x6f
+ *
+ * MSB (bit 7) controls loudness: 1/0 is loudness on/off
+ */
+
+#define	TDA7432_VOL_0DB		0x20
+#define TDA7432_LD_ON		1 << 7
+
+
+/* Subaddress 0x02 - Tone control */
+
+/* Bits 0,1,2 control absolute treble gain from 0dB to 14dB
+ * 0x0 is 14dB, 0x7 is 0dB
+ *
+ * Bit 3 controls treble attenuation/gain (sign)
+ * 1 = gain (+)
+ * 0 = attenuation (-)
+ *
+ * Bits 4,5,6 control absolute bass gain from 0dB to 14dB
+ * (This is only true for normal base range, set in 0x00)
+ * 0x0 << 4 is 14dB, 0x7 is 0dB
+ *
+ * Bit 7 controls bass attenuation/gain (sign)
+ * 1 << 7 = gain (+)
+ * 0 << 7 = attenuation (-)
+ *
+ * Example:
+ * 1 1 0 1 0 1 0 1 is +4dB bass, -4dB treble
+ */
+
+#define TDA7432_TREBLE_0DB		0xf
+#define TDA7432_TREBLE			7
+#define TDA7432_TREBLE_GAIN		1 << 3
+#define TDA7432_BASS_0DB		0xf
+#define TDA7432_BASS			7 << 4
+#define TDA7432_BASS_GAIN		1 << 7
+
+
+/* Subaddress 0x03 - Left  Front attenuation */
+/* Subaddress 0x04 - Left  Rear  attenuation */
+/* Subaddress 0x05 - Right Front attenuation */
+/* Subaddress 0x06 - Right Rear  attenuation */
+
+/* Bits 0,1,2,3,4 control attenuation from 0dB to -37.5dB
+ * in 1.5dB steps.
+ *
+ * 0x00 is     0dB
+ * 0x1f is -37.5dB
+ *
+ * Bit 5 mutes that channel when set (1 = mute, 0 = unmute)
+ * We'll use the mute on the input, though (above)
+ * Bits 6,7 unused
+ */
+
+#define TDA7432_ATTEN_0DB	0x00
+#define TDA7432_MUTE        0x1 << 5
+
+
+/* Subaddress 0x07 - Loudness Control */
+
+/* Bits 0,1,2,3 control loudness from 0dB to -15dB in 1dB steps
+ * when bit 4 is NOT set
+ *
+ * 0x0 is   0dB
+ * 0xf is -15dB
+ *
+ * If bit 4 is set, then there is a flat attenuation according to
+ * the lower 4 bits, as above.
+ *
+ * Bits 5,6,7 unused
+ */
+
+
+
+/* Begin code */
+
+static int tda7432_write(struct v4l2_subdev *sd, int subaddr, int val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	unsigned char buffer[2];
+
+	v4l2_dbg(2, debug, sd, "In tda7432_write\n");
+	v4l2_dbg(1, debug, sd, "Writing %d 0x%x\n", subaddr, val);
+	buffer[0] = subaddr;
+	buffer[1] = val;
+	if (2 != i2c_master_send(client, buffer, 2)) {
+		v4l2_err(sd, "I/O error, trying (write %d 0x%x)\n",
+		       subaddr, val);
+		return -1;
+	}
+	return 0;
+}
+
+static int tda7432_set(struct v4l2_subdev *sd)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct tda7432 *t = to_state(sd);
+	unsigned char buf[16];
+
+	v4l2_dbg(1, debug, sd,
+		"tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
+		t->input, t->volume, t->bass, t->treble, t->lf, t->lr,
+		t->rf, t->rr, t->loud);
+	buf[0]  = TDA7432_IN;
+	buf[1]  = t->input;
+	buf[2]  = t->volume;
+	buf[3]  = t->bass;
+	buf[4]	= t->treble;
+	buf[5]  = t->lf;
+	buf[6]  = t->lr;
+	buf[7]  = t->rf;
+	buf[8]  = t->rr;
+	buf[9]  = t->loud;
+	if (10 != i2c_master_send(client, buf, 10)) {
+		v4l2_err(sd, "I/O error, trying tda7432_set\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void do_tda7432_init(struct v4l2_subdev *sd)
+{
+	struct tda7432 *t = to_state(sd);
+
+	v4l2_dbg(2, debug, sd, "In tda7432_init\n");
+
+	t->input  = TDA7432_STEREO_IN |  /* Main (stereo) input   */
+		    TDA7432_BASS_SYM  |  /* Symmetric bass cut    */
+		    TDA7432_BASS_NORM;   /* Normal bass range     */
+	t->volume =  0x3b ;				 /* -27dB Volume            */
+	if (loudness)			 /* Turn loudness on?     */
+		t->volume |= TDA7432_LD_ON;
+	t->muted    = 1;
+	t->treble   = TDA7432_TREBLE_0DB; /* 0dB Treble            */
+	t->bass		= TDA7432_BASS_0DB; 	 /* 0dB Bass              */
+	t->lf     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
+	t->lr     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
+	t->rf     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
+	t->rr     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
+	t->loud   = loudness;		 /* insmod parameter      */
+
+	tda7432_set(sd);
+}
+
+static int tda7432_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	struct tda7432 *t = to_state(sd);
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		ctrl->value=t->muted;
+		return 0;
+	case V4L2_CID_AUDIO_VOLUME:
+		if (!maxvol){  /* max +20db */
+			ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 630;
+		} else {       /* max 0db   */
+			ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 829;
+		}
+		return 0;
+	case V4L2_CID_AUDIO_BALANCE:
+	{
+		if ( (t->lf) < (t->rf) )
+			/* right is attenuated, balance shifted left */
+			ctrl->value = (32768 - 1057*(t->rf));
+		else
+			/* left is attenuated, balance shifted right */
+			ctrl->value = (32768 + 1057*(t->lf));
+		return 0;
+	}
+	case V4L2_CID_AUDIO_BASS:
+	{
+		/* Bass/treble 4 bits each */
+		int bass=t->bass;
+		if(bass >= 0x8)
+			bass = ~(bass - 0x8) & 0xf;
+		ctrl->value = (bass << 12)+(bass << 8)+(bass << 4)+(bass);
+		return 0;
+	}
+	case V4L2_CID_AUDIO_TREBLE:
+	{
+		int treble=t->treble;
+		if(treble >= 0x8)
+			treble = ~(treble - 0x8) & 0xf;
+		ctrl->value = (treble << 12)+(treble << 8)+(treble << 4)+(treble);
+		return 0;
+	}
+	}
+	return -EINVAL;
+}
+
+static int tda7432_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	struct tda7432 *t = to_state(sd);
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		t->muted=ctrl->value;
+		break;
+	case V4L2_CID_AUDIO_VOLUME:
+		if(!maxvol){ /* max +20db */
+			t->volume = 0x6f - ((ctrl->value)/630);
+		} else {    /* max 0db   */
+			t->volume = 0x6f - ((ctrl->value)/829);
+		}
+		if (loudness)		/* Turn on the loudness bit */
+			t->volume |= TDA7432_LD_ON;
+
+		tda7432_write(sd, TDA7432_VL, t->volume);
+		return 0;
+	case V4L2_CID_AUDIO_BALANCE:
+		if (ctrl->value < 32768) {
+			/* shifted to left, attenuate right */
+			t->rr = (32768 - ctrl->value)/1057;
+			t->rf = t->rr;
+			t->lr = TDA7432_ATTEN_0DB;
+			t->lf = TDA7432_ATTEN_0DB;
+		} else if(ctrl->value > 32769) {
+			/* shifted to right, attenuate left */
+			t->lf = (ctrl->value - 32768)/1057;
+			t->lr = t->lf;
+			t->rr = TDA7432_ATTEN_0DB;
+			t->rf = TDA7432_ATTEN_0DB;
+		} else {
+			/* centered */
+			t->rr = TDA7432_ATTEN_0DB;
+			t->rf = TDA7432_ATTEN_0DB;
+			t->lf = TDA7432_ATTEN_0DB;
+			t->lr = TDA7432_ATTEN_0DB;
+		}
+		break;
+	case V4L2_CID_AUDIO_BASS:
+		t->bass = ctrl->value >> 12;
+		if(t->bass>= 0x8)
+				t->bass = (~t->bass & 0xf) + 0x8 ;
+
+		tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble);
+		return 0;
+	case V4L2_CID_AUDIO_TREBLE:
+		t->treble= ctrl->value >> 12;
+		if(t->treble>= 0x8)
+				t->treble = (~t->treble & 0xf) + 0x8 ;
+
+		tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+
+	/* Used for both mute and balance changes */
+	if (t->muted)
+	{
+		/* Mute & update balance*/
+		tda7432_write(sd, TDA7432_LF, t->lf | TDA7432_MUTE);
+		tda7432_write(sd, TDA7432_LR, t->lr | TDA7432_MUTE);
+		tda7432_write(sd, TDA7432_RF, t->rf | TDA7432_MUTE);
+		tda7432_write(sd, TDA7432_RR, t->rr | TDA7432_MUTE);
+	} else {
+		tda7432_write(sd, TDA7432_LF, t->lf);
+		tda7432_write(sd, TDA7432_LR, t->lr);
+		tda7432_write(sd, TDA7432_RF, t->rf);
+		tda7432_write(sd, TDA7432_RR, t->rr);
+	}
+	return 0;
+}
+
+static int tda7432_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+	switch (qc->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
+	case V4L2_CID_AUDIO_MUTE:
+		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+	case V4L2_CID_AUDIO_BALANCE:
+	case V4L2_CID_AUDIO_BASS:
+	case V4L2_CID_AUDIO_TREBLE:
+		return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
+	}
+	return -EINVAL;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tda7432_core_ops = {
+	.queryctrl = tda7432_queryctrl,
+	.g_ctrl = tda7432_g_ctrl,
+	.s_ctrl = tda7432_s_ctrl,
+};
+
+static const struct v4l2_subdev_ops tda7432_ops = {
+	.core = &tda7432_core_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+/* *********************** *
+ * i2c interface functions *
+ * *********************** */
+
+static int tda7432_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct tda7432 *t;
+	struct v4l2_subdev *sd;
+
+	v4l_info(client, "chip found @ 0x%02x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	t = kzalloc(sizeof(*t), GFP_KERNEL);
+	if (!t)
+		return -ENOMEM;
+	sd = &t->sd;
+	v4l2_i2c_subdev_init(sd, client, &tda7432_ops);
+	if (loudness < 0 || loudness > 15) {
+		v4l2_warn(sd, "loudness parameter must be between 0 and 15\n");
+		if (loudness < 0)
+			loudness = 0;
+		if (loudness > 15)
+			loudness = 15;
+	}
+
+	do_tda7432_init(sd);
+	return 0;
+}
+
+static int tda7432_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	do_tda7432_init(sd);
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_state(sd));
+	return 0;
+}
+
+static const struct i2c_device_id tda7432_id[] = {
+	{ "tda7432", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tda7432_id);
+
+static struct i2c_driver tda7432_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "tda7432",
+	},
+	.probe		= tda7432_probe,
+	.remove		= tda7432_remove,
+	.id_table	= tda7432_id,
+};
+
+module_i2c_driver(tda7432_driver);
diff --git a/drivers/media/i2c/tda9840.c b/drivers/media/i2c/tda9840.c
new file mode 100644
index 0000000..3d7ddd9
--- /dev/null
+++ b/drivers/media/i2c/tda9840.c
@@ -0,0 +1,224 @@
+ /*
+    tda9840 - i2c-driver for the tda9840 by SGS Thomson
+
+    Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
+    Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
+
+    The tda9840 is a stereo/dual sound processor with digital
+    identification. It can be found at address 0x84 on the i2c-bus.
+
+    For detailed informations download the specifications directly
+    from SGS Thomson at http://www.st.com
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+
+
+#include <linux/module.h>
+#include <linux/ioctl.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_DESCRIPTION("tda9840 driver");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0644);
+
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define	SWITCH		0x00
+#define	LEVEL_ADJUST	0x02
+#define	STEREO_ADJUST	0x03
+#define	TEST		0x04
+
+#define TDA9840_SET_MUTE                0x00
+#define TDA9840_SET_MONO                0x10
+#define TDA9840_SET_STEREO              0x2a
+#define TDA9840_SET_LANG1               0x12
+#define TDA9840_SET_LANG2               0x1e
+#define TDA9840_SET_BOTH                0x1a
+#define TDA9840_SET_BOTH_R              0x16
+#define TDA9840_SET_EXTERNAL            0x7a
+
+
+static void tda9840_write(struct v4l2_subdev *sd, u8 reg, u8 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (i2c_smbus_write_byte_data(client, reg, val))
+		v4l2_dbg(1, debug, sd, "error writing %02x to %02x\n",
+				val, reg);
+}
+
+static int tda9840_status(struct v4l2_subdev *sd)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 byte;
+
+	if (1 != i2c_master_recv(client, &byte, 1)) {
+		v4l2_dbg(1, debug, sd,
+			"i2c_master_recv() failed\n");
+		return -EIO;
+	}
+
+	if (byte & 0x80) {
+		v4l2_dbg(1, debug, sd,
+			"TDA9840_DETECT: register contents invalid\n");
+		return -EINVAL;
+	}
+
+	v4l2_dbg(1, debug, sd, "TDA9840_DETECT: byte: 0x%02x\n", byte);
+	return byte & 0x60;
+}
+
+static int tda9840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
+{
+	int stat = tda9840_status(sd);
+	int byte;
+
+	if (t->index)
+		return -EINVAL;
+
+	stat = stat < 0 ? 0 : stat;
+	if (stat == 0 || stat == 0x60) /* mono input */
+		byte = TDA9840_SET_MONO;
+	else if (stat == 0x40) /* stereo input */
+		byte = (t->audmode == V4L2_TUNER_MODE_MONO) ?
+			TDA9840_SET_MONO : TDA9840_SET_STEREO;
+	else { /* bilingual */
+		switch (t->audmode) {
+		case V4L2_TUNER_MODE_LANG1_LANG2:
+			byte = TDA9840_SET_BOTH;
+			break;
+		case V4L2_TUNER_MODE_LANG2:
+			byte = TDA9840_SET_LANG2;
+			break;
+		default:
+			byte = TDA9840_SET_LANG1;
+			break;
+		}
+	}
+	v4l2_dbg(1, debug, sd, "TDA9840_SWITCH: 0x%02x\n", byte);
+	tda9840_write(sd, SWITCH, byte);
+	return 0;
+}
+
+static int tda9840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
+{
+	int stat = tda9840_status(sd);
+
+	if (stat < 0)
+		return stat;
+
+	t->rxsubchans = V4L2_TUNER_SUB_MONO;
+
+	switch (stat & 0x60) {
+	case 0x00:
+		t->rxsubchans = V4L2_TUNER_SUB_MONO;
+		break;
+	case 0x20:
+		t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+		break;
+	case 0x40:
+		t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
+		break;
+	default: /* Incorrect detect */
+		t->rxsubchans = V4L2_TUNER_MODE_MONO;
+		break;
+	}
+	return 0;
+}
+
+static int tda9840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TDA9840, 0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tda9840_core_ops = {
+	.g_chip_ident = tda9840_g_chip_ident,
+};
+
+static const struct v4l2_subdev_tuner_ops tda9840_tuner_ops = {
+	.s_tuner = tda9840_s_tuner,
+	.g_tuner = tda9840_g_tuner,
+};
+
+static const struct v4l2_subdev_ops tda9840_ops = {
+	.core = &tda9840_core_ops,
+	.tuner = &tda9840_tuner_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int tda9840_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct v4l2_subdev *sd;
+
+	/* let's see whether this adapter can support what we need */
+	if (!i2c_check_functionality(client->adapter,
+			I2C_FUNC_SMBUS_READ_BYTE_DATA |
+			I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+	if (sd == NULL)
+		return -ENOMEM;
+	v4l2_i2c_subdev_init(sd, client, &tda9840_ops);
+
+	/* set initial values for level & stereo - adjustment, mode */
+	tda9840_write(sd, LEVEL_ADJUST, 0);
+	tda9840_write(sd, STEREO_ADJUST, 0);
+	tda9840_write(sd, SWITCH, TDA9840_SET_STEREO);
+	return 0;
+}
+
+static int tda9840_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(sd);
+	return 0;
+}
+
+static const struct i2c_device_id tda9840_id[] = {
+	{ "tda9840", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tda9840_id);
+
+static struct i2c_driver tda9840_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "tda9840",
+	},
+	.probe		= tda9840_probe,
+	.remove		= tda9840_remove,
+	.id_table	= tda9840_id,
+};
+
+module_i2c_driver(tda9840_driver);
diff --git a/drivers/media/i2c/tea6415c.c b/drivers/media/i2c/tea6415c.c
new file mode 100644
index 0000000..d1d6ea1
--- /dev/null
+++ b/drivers/media/i2c/tea6415c.c
@@ -0,0 +1,187 @@
+ /*
+    tea6415c - i2c-driver for the tea6415c by SGS Thomson
+
+    Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
+    Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
+
+    The tea6415c is a bus controlled video-matrix-switch
+    with 8 inputs and 6 outputs.
+    It is cascadable, i.e. it can be found at the addresses
+    0x86 and 0x06 on the i2c-bus.
+
+    For detailed informations download the specifications directly
+    from SGS Thomson at http://www.st.com
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License vs published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mvss Ave, Cambridge, MA 02139, USA.
+  */
+
+
+#include <linux/module.h>
+#include <linux/ioctl.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include "tea6415c.h"
+
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_DESCRIPTION("tea6415c driver");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0644);
+
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+
+/* makes a connection between the input-pin 'i' and the output-pin 'o' */
+static int tea6415c_s_routing(struct v4l2_subdev *sd,
+			      u32 i, u32 o, u32 config)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 byte = 0;
+	int ret;
+
+	v4l2_dbg(1, debug, sd, "i=%d, o=%d\n", i, o);
+
+	/* check if the pins are valid */
+	if (0 == ((1 == i ||  3 == i ||  5 == i ||  6 == i ||  8 == i || 10 == i || 20 == i || 11 == i)
+	      && (18 == o || 17 == o || 16 == o || 15 == o || 14 == o || 13 == o)))
+		return -EINVAL;
+
+	/* to understand this, have a look at the tea6415c-specs (p.5) */
+	switch (o) {
+	case 18:
+		byte = 0x00;
+		break;
+	case 14:
+		byte = 0x20;
+		break;
+	case 16:
+		byte = 0x10;
+		break;
+	case 17:
+		byte = 0x08;
+		break;
+	case 15:
+		byte = 0x18;
+		break;
+	case 13:
+		byte = 0x28;
+		break;
+	};
+
+	switch (i) {
+	case 5:
+		byte |= 0x00;
+		break;
+	case 8:
+		byte |= 0x04;
+		break;
+	case 3:
+		byte |= 0x02;
+		break;
+	case 20:
+		byte |= 0x06;
+		break;
+	case 6:
+		byte |= 0x01;
+		break;
+	case 10:
+		byte |= 0x05;
+		break;
+	case 1:
+		byte |= 0x03;
+		break;
+	case 11:
+		byte |= 0x07;
+		break;
+	};
+
+	ret = i2c_smbus_write_byte(client, byte);
+	if (ret) {
+		v4l2_dbg(1, debug, sd,
+			"i2c_smbus_write_byte() failed, ret:%d\n", ret);
+		return -EIO;
+	}
+	return ret;
+}
+
+static int tea6415c_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEA6415C, 0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tea6415c_core_ops = {
+	.g_chip_ident = tea6415c_g_chip_ident,
+};
+
+static const struct v4l2_subdev_video_ops tea6415c_video_ops = {
+	.s_routing = tea6415c_s_routing,
+};
+
+static const struct v4l2_subdev_ops tea6415c_ops = {
+	.core = &tea6415c_core_ops,
+	.video = &tea6415c_video_ops,
+};
+
+static int tea6415c_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct v4l2_subdev *sd;
+
+	/* let's see whether this adapter can support what we need */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+	sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+	if (sd == NULL)
+		return -ENOMEM;
+	v4l2_i2c_subdev_init(sd, client, &tea6415c_ops);
+	return 0;
+}
+
+static int tea6415c_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(sd);
+	return 0;
+}
+
+static const struct i2c_device_id tea6415c_id[] = {
+	{ "tea6415c", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tea6415c_id);
+
+static struct i2c_driver tea6415c_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "tea6415c",
+	},
+	.probe		= tea6415c_probe,
+	.remove		= tea6415c_remove,
+	.id_table	= tea6415c_id,
+};
+
+module_i2c_driver(tea6415c_driver);
diff --git a/drivers/media/i2c/tea6415c.h b/drivers/media/i2c/tea6415c.h
new file mode 100644
index 0000000..3a47d69
--- /dev/null
+++ b/drivers/media/i2c/tea6415c.h
@@ -0,0 +1,27 @@
+#ifndef __INCLUDED_TEA6415C__
+#define __INCLUDED_TEA6415C__
+
+/* the tea6415c's design is quite brain-dead. although there are
+   8 inputs and 6 outputs, these aren't enumerated in any way. because
+   I don't want to say "connect input pin 20 to output pin 17", I define
+   a "virtual" pin-order. */
+
+/* input pins */
+#define TEA6415C_OUTPUT1 18
+#define TEA6415C_OUTPUT2 14
+#define TEA6415C_OUTPUT3 16
+#define TEA6415C_OUTPUT4 17
+#define TEA6415C_OUTPUT5 13
+#define TEA6415C_OUTPUT6 15
+
+/* output pins */
+#define TEA6415C_INPUT1 5
+#define TEA6415C_INPUT2 8
+#define TEA6415C_INPUT3 3
+#define TEA6415C_INPUT4 20
+#define TEA6415C_INPUT5 6
+#define TEA6415C_INPUT6 10
+#define TEA6415C_INPUT7 1
+#define TEA6415C_INPUT8 11
+
+#endif
diff --git a/drivers/media/i2c/tea6420.c b/drivers/media/i2c/tea6420.c
new file mode 100644
index 0000000..3875721
--- /dev/null
+++ b/drivers/media/i2c/tea6420.c
@@ -0,0 +1,169 @@
+ /*
+    tea6420 - i2c-driver for the tea6420 by SGS Thomson
+
+    Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
+    Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
+
+    The tea6420 is a bus controlled audio-matrix with 5 stereo inputs,
+    4 stereo outputs and gain control for each output.
+    It is cascadable, i.e. it can be found at the addresses 0x98
+    and 0x9a on the i2c-bus.
+
+    For detailed informations download the specifications directly
+    from SGS Thomson at http://www.st.com
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+
+
+#include <linux/module.h>
+#include <linux/ioctl.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include "tea6420.h"
+
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_DESCRIPTION("tea6420 driver");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0644);
+
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+
+/* make a connection between the input 'i' and the output 'o'
+   with gain 'g' (note: i = 6 means 'mute') */
+static int tea6420_s_routing(struct v4l2_subdev *sd,
+			     u32 i, u32 o, u32 config)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int g = (o >> 4) & 0xf;
+	u8 byte;
+	int ret;
+
+	o &= 0xf;
+	v4l2_dbg(1, debug, sd, "i=%d, o=%d, g=%d\n", i, o, g);
+
+	/* check if the parameters are valid */
+	if (i < 1 || i > 6 || o < 1 || o > 4 || g < 0 || g > 6 || g % 2 != 0)
+		return -EINVAL;
+
+	byte = ((o - 1) << 5);
+	byte |= (i - 1);
+
+	/* to understand this, have a look at the tea6420-specs (p.5) */
+	switch (g) {
+	case 0:
+		byte |= (3 << 3);
+		break;
+	case 2:
+		byte |= (2 << 3);
+		break;
+	case 4:
+		byte |= (1 << 3);
+		break;
+	case 6:
+		break;
+	}
+
+	ret = i2c_smbus_write_byte(client, byte);
+	if (ret) {
+		v4l2_dbg(1, debug, sd,
+			"i2c_smbus_write_byte() failed, ret:%d\n", ret);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int tea6420_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEA6420, 0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tea6420_core_ops = {
+	.g_chip_ident = tea6420_g_chip_ident,
+};
+
+static const struct v4l2_subdev_audio_ops tea6420_audio_ops = {
+	.s_routing = tea6420_s_routing,
+};
+
+static const struct v4l2_subdev_ops tea6420_ops = {
+	.core = &tea6420_core_ops,
+	.audio = &tea6420_audio_ops,
+};
+
+static int tea6420_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct v4l2_subdev *sd;
+	int err, i;
+
+	/* let's see whether this adapter can support what we need */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+	if (sd == NULL)
+		return -ENOMEM;
+	v4l2_i2c_subdev_init(sd, client, &tea6420_ops);
+
+	/* set initial values: set "mute"-input to all outputs at gain 0 */
+	err = 0;
+	for (i = 1; i < 5; i++)
+		err += tea6420_s_routing(sd, 6, i, 0);
+	if (err) {
+		v4l_dbg(1, debug, client, "could not initialize tea6420\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int tea6420_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(sd);
+	return 0;
+}
+
+static const struct i2c_device_id tea6420_id[] = {
+	{ "tea6420", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tea6420_id);
+
+static struct i2c_driver tea6420_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "tea6420",
+	},
+	.probe		= tea6420_probe,
+	.remove		= tea6420_remove,
+	.id_table	= tea6420_id,
+};
+
+module_i2c_driver(tea6420_driver);
diff --git a/drivers/media/i2c/tea6420.h b/drivers/media/i2c/tea6420.h
new file mode 100644
index 0000000..4aa3edb
--- /dev/null
+++ b/drivers/media/i2c/tea6420.h
@@ -0,0 +1,24 @@
+#ifndef __INCLUDED_TEA6420__
+#define __INCLUDED_TEA6420__
+
+/* input pins */
+#define TEA6420_OUTPUT1 1
+#define TEA6420_OUTPUT2 2
+#define TEA6420_OUTPUT3 3
+#define TEA6420_OUTPUT4 4
+
+/* output pins */
+#define TEA6420_INPUT1 1
+#define TEA6420_INPUT2 2
+#define TEA6420_INPUT3 3
+#define TEA6420_INPUT4 4
+#define TEA6420_INPUT5 5
+#define TEA6420_INPUT6 6
+
+/* gain on the output pins, ORed with the output pin */
+#define TEA6420_GAIN0 0x00
+#define TEA6420_GAIN2 0x20
+#define TEA6420_GAIN4 0x40
+#define TEA6420_GAIN6 0x60
+
+#endif
diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c
new file mode 100644
index 0000000..e5c0eed
--- /dev/null
+++ b/drivers/media/i2c/ths7303.c
@@ -0,0 +1,140 @@
+/*
+ * ths7303- THS7303 Video Amplifier driver
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; 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/init.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_DESCRIPTION("TI THS7303 video amplifier driver");
+MODULE_AUTHOR("Chaithrika U S");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+
+/* following function is used to set ths7303 */
+static int ths7303_setvalue(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	int err = 0;
+	u8 val;
+	struct i2c_client *client;
+
+	client = v4l2_get_subdevdata(sd);
+
+	if (std & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) {
+		val = 0x02;
+		v4l2_dbg(1, debug, sd, "setting value for SDTV format\n");
+	} else {
+		val = 0x00;
+		v4l2_dbg(1, debug, sd, "disabling all channels\n");
+	}
+
+	err |= i2c_smbus_write_byte_data(client, 0x01, val);
+	err |= i2c_smbus_write_byte_data(client, 0x02, val);
+	err |= i2c_smbus_write_byte_data(client, 0x03, val);
+
+	if (err)
+		v4l2_err(sd, "write failed\n");
+
+	return err;
+}
+
+static int ths7303_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+	return ths7303_setvalue(sd, norm);
+}
+
+static int ths7303_g_chip_ident(struct v4l2_subdev *sd,
+				struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_THS7303, 0);
+}
+
+static const struct v4l2_subdev_video_ops ths7303_video_ops = {
+	.s_std_output	= ths7303_s_std_output,
+};
+
+static const struct v4l2_subdev_core_ops ths7303_core_ops = {
+	.g_chip_ident = ths7303_g_chip_ident,
+};
+
+static const struct v4l2_subdev_ops ths7303_ops = {
+	.core	= &ths7303_core_ops,
+	.video 	= &ths7303_video_ops,
+};
+
+static int ths7303_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct v4l2_subdev *sd;
+	v4l2_std_id std_id = V4L2_STD_NTSC;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+	if (sd == NULL)
+		return -ENOMEM;
+
+	v4l2_i2c_subdev_init(sd, client, &ths7303_ops);
+
+	return ths7303_setvalue(sd, std_id);
+}
+
+static int ths7303_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(sd);
+
+	return 0;
+}
+
+static const struct i2c_device_id ths7303_id[] = {
+	{"ths7303", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, ths7303_id);
+
+static struct i2c_driver ths7303_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "ths7303",
+	},
+	.probe		= ths7303_probe,
+	.remove		= ths7303_remove,
+	.id_table	= ths7303_id,
+};
+
+module_i2c_driver(ths7303_driver);
diff --git a/drivers/media/i2c/tlv320aic23b.c b/drivers/media/i2c/tlv320aic23b.c
new file mode 100644
index 0000000..809a75a
--- /dev/null
+++ b/drivers/media/i2c/tlv320aic23b.c
@@ -0,0 +1,230 @@
+/*
+ * tlv320aic23b - driver version 0.0.1
+ *
+ * Copyright (C) 2006 Scott Alfter <salfter@ssai.us>
+ *
+ * Based on wm8775 driver
+ *
+ * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to>
+ * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+MODULE_DESCRIPTION("tlv320aic23b driver");
+MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+
+/* ----------------------------------------------------------------------- */
+
+struct tlv320aic23b_state {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+};
+
+static inline struct tlv320aic23b_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct tlv320aic23b_state, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct tlv320aic23b_state, hdl)->sd;
+}
+
+static int tlv320aic23b_write(struct v4l2_subdev *sd, int reg, u16 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int i;
+
+	if ((reg < 0 || reg > 9) && (reg != 15)) {
+		v4l2_err(sd, "Invalid register R%d\n", reg);
+		return -1;
+	}
+
+	for (i = 0; i < 3; i++)
+		if (i2c_smbus_write_byte_data(client,
+				(reg << 1) | (val >> 8), val & 0xff) == 0)
+			return 0;
+	v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg);
+	return -1;
+}
+
+static int tlv320aic23b_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
+{
+	switch (freq) {
+	case 32000: /* set sample rate to 32 kHz */
+		tlv320aic23b_write(sd, 8, 0x018);
+		break;
+	case 44100: /* set sample rate to 44.1 kHz */
+		tlv320aic23b_write(sd, 8, 0x022);
+		break;
+	case 48000: /* set sample rate to 48 kHz */
+		tlv320aic23b_write(sd, 8, 0x000);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int tlv320aic23b_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		tlv320aic23b_write(sd, 0, 0x180); /* mute both channels */
+		/* set gain on both channels to +3.0 dB */
+		if (!ctrl->val)
+			tlv320aic23b_write(sd, 0, 0x119);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int tlv320aic23b_log_status(struct v4l2_subdev *sd)
+{
+	struct tlv320aic23b_state *state = to_state(sd);
+
+	v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_ctrl_ops tlv320aic23b_ctrl_ops = {
+	.s_ctrl = tlv320aic23b_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops tlv320aic23b_core_ops = {
+	.log_status = tlv320aic23b_log_status,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+};
+
+static const struct v4l2_subdev_audio_ops tlv320aic23b_audio_ops = {
+	.s_clock_freq = tlv320aic23b_s_clock_freq,
+};
+
+static const struct v4l2_subdev_ops tlv320aic23b_ops = {
+	.core = &tlv320aic23b_core_ops,
+	.audio = &tlv320aic23b_audio_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static int tlv320aic23b_probe(struct i2c_client *client,
+			      const struct i2c_device_id *id)
+{
+	struct tlv320aic23b_state *state;
+	struct v4l2_subdev *sd;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	state = kzalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &tlv320aic23b_ops);
+
+	/* Initialize tlv320aic23b */
+
+	/* RESET */
+	tlv320aic23b_write(sd, 15, 0x000);
+	/* turn off DAC & mic input */
+	tlv320aic23b_write(sd, 6, 0x00A);
+	/* left-justified, 24-bit, master mode */
+	tlv320aic23b_write(sd, 7, 0x049);
+	/* set gain on both channels to +3.0 dB */
+	tlv320aic23b_write(sd, 0, 0x119);
+	/* set sample rate to 48 kHz */
+	tlv320aic23b_write(sd, 8, 0x000);
+	/* activate digital interface */
+	tlv320aic23b_write(sd, 9, 0x001);
+
+	v4l2_ctrl_handler_init(&state->hdl, 1);
+	v4l2_ctrl_new_std(&state->hdl, &tlv320aic23b_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+	sd->ctrl_handler = &state->hdl;
+	if (state->hdl.error) {
+		int err = state->hdl.error;
+
+		v4l2_ctrl_handler_free(&state->hdl);
+		kfree(state);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&state->hdl);
+	return 0;
+}
+
+static int tlv320aic23b_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct tlv320aic23b_state *state = to_state(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&state->hdl);
+	kfree(state);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id tlv320aic23b_id[] = {
+	{ "tlv320aic23b", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tlv320aic23b_id);
+
+static struct i2c_driver tlv320aic23b_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "tlv320aic23b",
+	},
+	.probe		= tlv320aic23b_probe,
+	.remove		= tlv320aic23b_remove,
+	.id_table	= tlv320aic23b_id,
+};
+
+module_i2c_driver(tlv320aic23b_driver);
diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c
new file mode 100644
index 0000000..321b315
--- /dev/null
+++ b/drivers/media/i2c/tvaudio.c
@@ -0,0 +1,2118 @@
+/*
+ * Driver for simple i2c audio chips.
+ *
+ * Copyright (c) 2000 Gerd Knorr
+ * based on code by:
+ *   Eric Sandeen (eric_sandeen@bigfoot.com)
+ *   Steve VanDeBogart (vandebo@uclink.berkeley.edu)
+ *   Greg Alexander (galexand@acm.org)
+ *
+ * Copyright(c) 2005-2008 Mauro Carvalho Chehab
+ *	- Some cleanups, code fixes, etc
+ *	- Convert it to V4L2 API
+ *
+ * This code is placed under the terms of the GNU General Public License
+ *
+ * OPTIONS:
+ *   debug - set to 1 if you'd like to see debug messages
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+#include <media/tvaudio.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+#include <media/i2c-addr.h>
+
+/* ---------------------------------------------------------------------- */
+/* insmod args                                                            */
+
+static int debug;	/* insmod parameter */
+module_param(debug, int, 0644);
+
+MODULE_DESCRIPTION("device driver for various i2c TV sound decoder / audiomux chips");
+MODULE_AUTHOR("Eric Sandeen, Steve VanDeBogart, Greg Alexander, Gerd Knorr");
+MODULE_LICENSE("GPL");
+
+#define UNSET    (-1U)
+
+/* ---------------------------------------------------------------------- */
+/* our structs                                                            */
+
+#define MAXREGS 256
+
+struct CHIPSTATE;
+typedef int  (*getvalue)(int);
+typedef int  (*checkit)(struct CHIPSTATE*);
+typedef int  (*initialize)(struct CHIPSTATE*);
+typedef int  (*getrxsubchans)(struct CHIPSTATE *);
+typedef void (*setaudmode)(struct CHIPSTATE*, int mode);
+
+/* i2c command */
+typedef struct AUDIOCMD {
+	int             count;             /* # of bytes to send */
+	unsigned char   bytes[MAXREGS+1];  /* addr, data, data, ... */
+} audiocmd;
+
+/* chip description */
+struct CHIPDESC {
+	char       *name;             /* chip name         */
+	int        addr_lo, addr_hi;  /* i2c address range */
+	int        registers;         /* # of registers    */
+
+	int        *insmodopt;
+	checkit    checkit;
+	initialize initialize;
+	int        flags;
+#define CHIP_HAS_VOLUME      1
+#define CHIP_HAS_BASSTREBLE  2
+#define CHIP_HAS_INPUTSEL    4
+#define CHIP_NEED_CHECKMODE  8
+
+	/* various i2c command sequences */
+	audiocmd   init;
+
+	/* which register has which value */
+	int    leftreg,rightreg,treblereg,bassreg;
+
+	/* initialize with (defaults to 65535/65535/32768/32768 */
+	int    leftinit,rightinit,trebleinit,bassinit;
+
+	/* functions to convert the values (v4l -> chip) */
+	getvalue volfunc,treblefunc,bassfunc;
+
+	/* get/set mode */
+	getrxsubchans	getrxsubchans;
+	setaudmode	setaudmode;
+
+	/* input switch register + values for v4l inputs */
+	int  inputreg;
+	int  inputmap[4];
+	int  inputmute;
+	int  inputmask;
+};
+
+/* current state of the chip */
+struct CHIPSTATE {
+	struct v4l2_subdev sd;
+
+	/* chip-specific description - should point to
+	   an entry at CHIPDESC table */
+	struct CHIPDESC *desc;
+
+	/* shadow register set */
+	audiocmd   shadow;
+
+	/* current settings */
+	__u16 left, right, treble, bass, muted;
+	int prevmode;
+	int radio;
+	int input;
+
+	/* thread */
+	struct task_struct   *thread;
+	struct timer_list    wt;
+	int 		     audmode;
+};
+
+static inline struct CHIPSTATE *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct CHIPSTATE, sd);
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* i2c I/O functions                                                      */
+
+static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
+{
+	struct v4l2_subdev *sd = &chip->sd;
+	struct i2c_client *c = v4l2_get_subdevdata(sd);
+	unsigned char buffer[2];
+
+	if (subaddr < 0) {
+		v4l2_dbg(1, debug, sd, "chip_write: 0x%x\n", val);
+		chip->shadow.bytes[1] = val;
+		buffer[0] = val;
+		if (1 != i2c_master_send(c, buffer, 1)) {
+			v4l2_warn(sd, "I/O error (write 0x%x)\n", val);
+			return -1;
+		}
+	} else {
+		if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
+			v4l2_info(sd,
+				"Tried to access a non-existent register: %d\n",
+				subaddr);
+			return -EINVAL;
+		}
+
+		v4l2_dbg(1, debug, sd, "chip_write: reg%d=0x%x\n",
+			subaddr, val);
+		chip->shadow.bytes[subaddr+1] = val;
+		buffer[0] = subaddr;
+		buffer[1] = val;
+		if (2 != i2c_master_send(c, buffer, 2)) {
+			v4l2_warn(sd, "I/O error (write reg%d=0x%x)\n",
+				subaddr, val);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int chip_write_masked(struct CHIPSTATE *chip,
+			     int subaddr, int val, int mask)
+{
+	struct v4l2_subdev *sd = &chip->sd;
+
+	if (mask != 0) {
+		if (subaddr < 0) {
+			val = (chip->shadow.bytes[1] & ~mask) | (val & mask);
+		} else {
+			if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
+				v4l2_info(sd,
+					"Tried to access a non-existent register: %d\n",
+					subaddr);
+				return -EINVAL;
+			}
+
+			val = (chip->shadow.bytes[subaddr+1] & ~mask) | (val & mask);
+		}
+	}
+	return chip_write(chip, subaddr, val);
+}
+
+static int chip_read(struct CHIPSTATE *chip)
+{
+	struct v4l2_subdev *sd = &chip->sd;
+	struct i2c_client *c = v4l2_get_subdevdata(sd);
+	unsigned char buffer;
+
+	if (1 != i2c_master_recv(c, &buffer, 1)) {
+		v4l2_warn(sd, "I/O error (read)\n");
+		return -1;
+	}
+	v4l2_dbg(1, debug, sd, "chip_read: 0x%x\n", buffer);
+	return buffer;
+}
+
+static int chip_read2(struct CHIPSTATE *chip, int subaddr)
+{
+	struct v4l2_subdev *sd = &chip->sd;
+	struct i2c_client *c = v4l2_get_subdevdata(sd);
+	unsigned char write[1];
+	unsigned char read[1];
+	struct i2c_msg msgs[2] = {
+		{ c->addr, 0,        1, write },
+		{ c->addr, I2C_M_RD, 1, read  }
+	};
+
+	write[0] = subaddr;
+
+	if (2 != i2c_transfer(c->adapter, msgs, 2)) {
+		v4l2_warn(sd, "I/O error (read2)\n");
+		return -1;
+	}
+	v4l2_dbg(1, debug, sd, "chip_read2: reg%d=0x%x\n",
+		subaddr, read[0]);
+	return read[0];
+}
+
+static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
+{
+	struct v4l2_subdev *sd = &chip->sd;
+	struct i2c_client *c = v4l2_get_subdevdata(sd);
+	int i;
+
+	if (0 == cmd->count)
+		return 0;
+
+	if (cmd->count + cmd->bytes[0] - 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
+		v4l2_info(sd,
+			 "Tried to access a non-existent register range: %d to %d\n",
+			 cmd->bytes[0] + 1, cmd->bytes[0] + cmd->count - 1);
+		return -EINVAL;
+	}
+
+	/* FIXME: it seems that the shadow bytes are wrong bellow !*/
+
+	/* update our shadow register set; print bytes if (debug > 0) */
+	v4l2_dbg(1, debug, sd, "chip_cmd(%s): reg=%d, data:",
+		name, cmd->bytes[0]);
+	for (i = 1; i < cmd->count; i++) {
+		if (debug)
+			printk(KERN_CONT " 0x%x", cmd->bytes[i]);
+		chip->shadow.bytes[i+cmd->bytes[0]] = cmd->bytes[i];
+	}
+	if (debug)
+		printk(KERN_CONT "\n");
+
+	/* send data to the chip */
+	if (cmd->count != i2c_master_send(c, cmd->bytes, cmd->count)) {
+		v4l2_warn(sd, "I/O error (%s)\n", name);
+		return -1;
+	}
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* kernel thread for doing i2c stuff asyncronly
+ *   right now it is used only to check the audio mode (mono/stereo/whatever)
+ *   some time after switching to another TV channel, then turn on stereo
+ *   if available, ...
+ */
+
+static void chip_thread_wake(unsigned long data)
+{
+	struct CHIPSTATE *chip = (struct CHIPSTATE*)data;
+	wake_up_process(chip->thread);
+}
+
+static int chip_thread(void *data)
+{
+	struct CHIPSTATE *chip = data;
+	struct CHIPDESC  *desc = chip->desc;
+	struct v4l2_subdev *sd = &chip->sd;
+	int mode, selected;
+
+	v4l2_dbg(1, debug, sd, "thread started\n");
+	set_freezable();
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (!kthread_should_stop())
+			schedule();
+		set_current_state(TASK_RUNNING);
+		try_to_freeze();
+		if (kthread_should_stop())
+			break;
+		v4l2_dbg(1, debug, sd, "thread wakeup\n");
+
+		/* don't do anything for radio */
+		if (chip->radio)
+			continue;
+
+		/* have a look what's going on */
+		mode = desc->getrxsubchans(chip);
+		if (mode == chip->prevmode)
+			continue;
+
+		/* chip detected a new audio mode - set it */
+		v4l2_dbg(1, debug, sd, "thread checkmode\n");
+
+		chip->prevmode = mode;
+
+		selected = V4L2_TUNER_MODE_MONO;
+		switch (chip->audmode) {
+		case V4L2_TUNER_MODE_MONO:
+			if (mode & V4L2_TUNER_SUB_LANG1)
+				selected = V4L2_TUNER_MODE_LANG1;
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+		case V4L2_TUNER_MODE_LANG1:
+			if (mode & V4L2_TUNER_SUB_LANG1)
+				selected = V4L2_TUNER_MODE_LANG1;
+			else if (mode & V4L2_TUNER_SUB_STEREO)
+				selected = V4L2_TUNER_MODE_STEREO;
+			break;
+		case V4L2_TUNER_MODE_LANG2:
+			if (mode & V4L2_TUNER_SUB_LANG2)
+				selected = V4L2_TUNER_MODE_LANG2;
+			else if (mode & V4L2_TUNER_SUB_STEREO)
+				selected = V4L2_TUNER_MODE_STEREO;
+			break;
+		case V4L2_TUNER_MODE_LANG1_LANG2:
+			if (mode & V4L2_TUNER_SUB_LANG2)
+				selected = V4L2_TUNER_MODE_LANG1_LANG2;
+			else if (mode & V4L2_TUNER_SUB_STEREO)
+				selected = V4L2_TUNER_MODE_STEREO;
+		}
+		desc->setaudmode(chip, selected);
+
+		/* schedule next check */
+		mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
+	}
+
+	v4l2_dbg(1, debug, sd, "thread exiting\n");
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for tda9840                */
+
+#define TDA9840_SW         0x00
+#define TDA9840_LVADJ      0x02
+#define TDA9840_STADJ      0x03
+#define TDA9840_TEST       0x04
+
+#define TDA9840_MONO       0x10
+#define TDA9840_STEREO     0x2a
+#define TDA9840_DUALA      0x12
+#define TDA9840_DUALB      0x1e
+#define TDA9840_DUALAB     0x1a
+#define TDA9840_DUALBA     0x16
+#define TDA9840_EXTERNAL   0x7a
+
+#define TDA9840_DS_DUAL    0x20 /* Dual sound identified          */
+#define TDA9840_ST_STEREO  0x40 /* Stereo sound identified        */
+#define TDA9840_PONRES     0x80 /* Power-on reset detected if = 1 */
+
+#define TDA9840_TEST_INT1SN 0x1 /* Integration time 0.5s when set */
+#define TDA9840_TEST_INTFU 0x02 /* Disables integrator function */
+
+static int tda9840_getrxsubchans(struct CHIPSTATE *chip)
+{
+	struct v4l2_subdev *sd = &chip->sd;
+	int val, mode;
+
+	val = chip_read(chip);
+	mode = V4L2_TUNER_SUB_MONO;
+	if (val & TDA9840_DS_DUAL)
+		mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+	if (val & TDA9840_ST_STEREO)
+		mode = V4L2_TUNER_SUB_STEREO;
+
+	v4l2_dbg(1, debug, sd,
+		"tda9840_getrxsubchans(): raw chip read: %d, return: %d\n",
+		val, mode);
+	return mode;
+}
+
+static void tda9840_setaudmode(struct CHIPSTATE *chip, int mode)
+{
+	int update = 1;
+	int t = chip->shadow.bytes[TDA9840_SW + 1] & ~0x7e;
+
+	switch (mode) {
+	case V4L2_TUNER_MODE_MONO:
+		t |= TDA9840_MONO;
+		break;
+	case V4L2_TUNER_MODE_STEREO:
+		t |= TDA9840_STEREO;
+		break;
+	case V4L2_TUNER_MODE_LANG1:
+		t |= TDA9840_DUALA;
+		break;
+	case V4L2_TUNER_MODE_LANG2:
+		t |= TDA9840_DUALB;
+		break;
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+		t |= TDA9840_DUALAB;
+		break;
+	default:
+		update = 0;
+	}
+
+	if (update)
+		chip_write(chip, TDA9840_SW, t);
+}
+
+static int tda9840_checkit(struct CHIPSTATE *chip)
+{
+	int rc;
+	rc = chip_read(chip);
+	/* lower 5 bits should be 0 */
+	return ((rc & 0x1f) == 0) ? 1 : 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for tda985x                */
+
+/* subaddresses for TDA9855 */
+#define TDA9855_VR	0x00 /* Volume, right */
+#define TDA9855_VL	0x01 /* Volume, left */
+#define TDA9855_BA	0x02 /* Bass */
+#define TDA9855_TR	0x03 /* Treble */
+#define TDA9855_SW	0x04 /* Subwoofer - not connected on DTV2000 */
+
+/* subaddresses for TDA9850 */
+#define TDA9850_C4	0x04 /* Control 1 for TDA9850 */
+
+/* subaddesses for both chips */
+#define TDA985x_C5	0x05 /* Control 2 for TDA9850, Control 1 for TDA9855 */
+#define TDA985x_C6	0x06 /* Control 3 for TDA9850, Control 2 for TDA9855 */
+#define TDA985x_C7	0x07 /* Control 4 for TDA9850, Control 3 for TDA9855 */
+#define TDA985x_A1	0x08 /* Alignment 1 for both chips */
+#define TDA985x_A2	0x09 /* Alignment 2 for both chips */
+#define TDA985x_A3	0x0a /* Alignment 3 for both chips */
+
+/* Masks for bits in TDA9855 subaddresses */
+/* 0x00 - VR in TDA9855 */
+/* 0x01 - VL in TDA9855 */
+/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f)
+ * in 1dB steps - mute is 0x27 */
+
+
+/* 0x02 - BA in TDA9855 */
+/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19)
+ * in .5dB steps - 0 is 0x0E */
+
+
+/* 0x03 - TR in TDA9855 */
+/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb)
+ * in 3dB steps - 0 is 0x7 */
+
+/* Masks for bits in both chips' subaddresses */
+/* 0x04 - SW in TDA9855, C4/Control 1 in TDA9850 */
+/* Unique to TDA9855: */
+/* 4 bits << 2 control subwoofer/surround gain from -14db (0x1) to 14db (0xf)
+ * in 3dB steps - mute is 0x0 */
+
+/* Unique to TDA9850: */
+/* lower 4 bits control stereo noise threshold, over which stereo turns off
+ * set to values of 0x00 through 0x0f for Ster1 through Ster16 */
+
+
+/* 0x05 - C5 - Control 1 in TDA9855 , Control 2 in TDA9850*/
+/* Unique to TDA9855: */
+#define TDA9855_MUTE	1<<7 /* GMU, Mute at outputs */
+#define TDA9855_AVL	1<<6 /* AVL, Automatic Volume Level */
+#define TDA9855_LOUD	1<<5 /* Loudness, 1==off */
+#define TDA9855_SUR	1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */
+			     /* Bits 0 to 3 select various combinations
+			      * of line in and line out, only the
+			      * interesting ones are defined */
+#define TDA9855_EXT	1<<2 /* Selects inputs LIR and LIL.  Pins 41 & 12 */
+#define TDA9855_INT	0    /* Selects inputs LOR and LOL.  (internal) */
+
+/* Unique to TDA9850:  */
+/* lower 4 bits contol SAP noise threshold, over which SAP turns off
+ * set to values of 0x00 through 0x0f for SAP1 through SAP16 */
+
+
+/* 0x06 - C6 - Control 2 in TDA9855, Control 3 in TDA9850 */
+/* Common to TDA9855 and TDA9850: */
+#define TDA985x_SAP	3<<6 /* Selects SAP output, mute if not received */
+#define TDA985x_MONOSAP	2<<6 /* Selects Mono on left, SAP on right */
+#define TDA985x_STEREO	1<<6 /* Selects Stereo ouput, mono if not received */
+#define TDA985x_MONO	0    /* Forces Mono output */
+#define TDA985x_LMU	1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */
+
+/* Unique to TDA9855: */
+#define TDA9855_TZCM	1<<5 /* If set, don't mute till zero crossing */
+#define TDA9855_VZCM	1<<4 /* If set, don't change volume till zero crossing*/
+#define TDA9855_LINEAR	0    /* Linear Stereo */
+#define TDA9855_PSEUDO	1    /* Pseudo Stereo */
+#define TDA9855_SPAT_30	2    /* Spatial Stereo, 30% anti-phase crosstalk */
+#define TDA9855_SPAT_50	3    /* Spatial Stereo, 52% anti-phase crosstalk */
+#define TDA9855_E_MONO	7    /* Forced mono - mono select elseware, so useless*/
+
+/* 0x07 - C7 - Control 3 in TDA9855, Control 4 in TDA9850 */
+/* Common to both TDA9855 and TDA9850: */
+/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF)
+ * in .5dB steps -  0dB is 0x7 */
+
+/* 0x08, 0x09 - A1 and A2 (read/write) */
+/* Common to both TDA9855 and TDA9850: */
+/* lower 5 bites are wideband and spectral expander alignment
+ * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */
+#define TDA985x_STP	1<<5 /* Stereo Pilot/detect (read-only) */
+#define TDA985x_SAPP	1<<6 /* SAP Pilot/detect (read-only) */
+#define TDA985x_STS	1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/
+
+/* 0x0a - A3 */
+/* Common to both TDA9855 and TDA9850: */
+/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1),
+ * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */
+#define TDA985x_ADJ	1<<7 /* Stereo adjust on/off (wideband and spectral */
+
+static int tda9855_volume(int val) { return val/0x2e8+0x27; }
+static int tda9855_bass(int val)   { return val/0xccc+0x06; }
+static int tda9855_treble(int val) { return (val/0x1c71+0x3)<<1; }
+
+static int  tda985x_getrxsubchans(struct CHIPSTATE *chip)
+{
+	int mode, val;
+
+	/* Add mono mode regardless of SAP and stereo */
+	/* Allows forced mono */
+	mode = V4L2_TUNER_SUB_MONO;
+	val = chip_read(chip);
+	if (val & TDA985x_STP)
+		mode = V4L2_TUNER_SUB_STEREO;
+	if (val & TDA985x_SAPP)
+		mode |= V4L2_TUNER_SUB_SAP;
+	return mode;
+}
+
+static void tda985x_setaudmode(struct CHIPSTATE *chip, int mode)
+{
+	int update = 1;
+	int c6 = chip->shadow.bytes[TDA985x_C6+1] & 0x3f;
+
+	switch (mode) {
+	case V4L2_TUNER_MODE_MONO:
+		c6 |= TDA985x_MONO;
+		break;
+	case V4L2_TUNER_MODE_STEREO:
+	case V4L2_TUNER_MODE_LANG1:
+		c6 |= TDA985x_STEREO;
+		break;
+	case V4L2_TUNER_MODE_SAP:
+		c6 |= TDA985x_SAP;
+		break;
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+		c6 |= TDA985x_MONOSAP;
+		break;
+	default:
+		update = 0;
+	}
+	if (update)
+		chip_write(chip,TDA985x_C6,c6);
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for tda9873h               */
+
+/* Subaddresses for TDA9873H */
+
+#define TDA9873_SW	0x00 /* Switching                    */
+#define TDA9873_AD	0x01 /* Adjust                       */
+#define TDA9873_PT	0x02 /* Port                         */
+
+/* Subaddress 0x00: Switching Data
+ * B7..B0:
+ *
+ * B1, B0: Input source selection
+ *  0,  0  internal
+ *  1,  0  external stereo
+ *  0,  1  external mono
+ */
+#define TDA9873_INP_MASK    3
+#define TDA9873_INTERNAL    0
+#define TDA9873_EXT_STEREO  2
+#define TDA9873_EXT_MONO    1
+
+/*    B3, B2: output signal select
+ * B4    : transmission mode
+ *  0, 0, 1   Mono
+ *  1, 0, 0   Stereo
+ *  1, 1, 1   Stereo (reversed channel)
+ *  0, 0, 0   Dual AB
+ *  0, 0, 1   Dual AA
+ *  0, 1, 0   Dual BB
+ *  0, 1, 1   Dual BA
+ */
+
+#define TDA9873_TR_MASK     (7 << 2)
+#define TDA9873_TR_MONO     4
+#define TDA9873_TR_STEREO   1 << 4
+#define TDA9873_TR_REVERSE  ((1 << 3) | (1 << 2))
+#define TDA9873_TR_DUALA    1 << 2
+#define TDA9873_TR_DUALB    1 << 3
+#define TDA9873_TR_DUALAB   0
+
+/* output level controls
+ * B5:  output level switch (0 = reduced gain, 1 = normal gain)
+ * B6:  mute                (1 = muted)
+ * B7:  auto-mute           (1 = auto-mute enabled)
+ */
+
+#define TDA9873_GAIN_NORMAL 1 << 5
+#define TDA9873_MUTE        1 << 6
+#define TDA9873_AUTOMUTE    1 << 7
+
+/* Subaddress 0x01:  Adjust/standard */
+
+/* Lower 4 bits (C3..C0) control stereo adjustment on R channel (-0.6 - +0.7 dB)
+ * Recommended value is +0 dB
+ */
+
+#define	TDA9873_STEREO_ADJ	0x06 /* 0dB gain */
+
+/* Bits C6..C4 control FM stantard
+ * C6, C5, C4
+ *  0,  0,  0   B/G (PAL FM)
+ *  0,  0,  1   M
+ *  0,  1,  0   D/K(1)
+ *  0,  1,  1   D/K(2)
+ *  1,  0,  0   D/K(3)
+ *  1,  0,  1   I
+ */
+#define TDA9873_BG		0
+#define TDA9873_M       1
+#define TDA9873_DK1     2
+#define TDA9873_DK2     3
+#define TDA9873_DK3     4
+#define TDA9873_I       5
+
+/* C7 controls identification response time (1=fast/0=normal)
+ */
+#define TDA9873_IDR_NORM 0
+#define TDA9873_IDR_FAST 1 << 7
+
+
+/* Subaddress 0x02: Port data */
+
+/* E1, E0   free programmable ports P1/P2
+    0,  0   both ports low
+    0,  1   P1 high
+    1,  0   P2 high
+    1,  1   both ports high
+*/
+
+#define TDA9873_PORTS    3
+
+/* E2: test port */
+#define TDA9873_TST_PORT 1 << 2
+
+/* E5..E3 control mono output channel (together with transmission mode bit B4)
+ *
+ * E5 E4 E3 B4     OUTM
+ *  0  0  0  0     mono
+ *  0  0  1  0     DUAL B
+ *  0  1  0  1     mono (from stereo decoder)
+ */
+#define TDA9873_MOUT_MONO   0
+#define TDA9873_MOUT_FMONO  0
+#define TDA9873_MOUT_DUALA  0
+#define TDA9873_MOUT_DUALB  1 << 3
+#define TDA9873_MOUT_ST     1 << 4
+#define TDA9873_MOUT_EXTM   ((1 << 4) | (1 << 3))
+#define TDA9873_MOUT_EXTL   1 << 5
+#define TDA9873_MOUT_EXTR   ((1 << 5) | (1 << 3))
+#define TDA9873_MOUT_EXTLR  ((1 << 5) | (1 << 4))
+#define TDA9873_MOUT_MUTE   ((1 << 5) | (1 << 4) | (1 << 3))
+
+/* Status bits: (chip read) */
+#define TDA9873_PONR        0 /* Power-on reset detected if = 1 */
+#define TDA9873_STEREO      2 /* Stereo sound is identified     */
+#define TDA9873_DUAL        4 /* Dual sound is identified       */
+
+static int tda9873_getrxsubchans(struct CHIPSTATE *chip)
+{
+	struct v4l2_subdev *sd = &chip->sd;
+	int val,mode;
+
+	val = chip_read(chip);
+	mode = V4L2_TUNER_SUB_MONO;
+	if (val & TDA9873_STEREO)
+		mode = V4L2_TUNER_SUB_STEREO;
+	if (val & TDA9873_DUAL)
+		mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+	v4l2_dbg(1, debug, sd,
+		"tda9873_getrxsubchans(): raw chip read: %d, return: %d\n",
+		val, mode);
+	return mode;
+}
+
+static void tda9873_setaudmode(struct CHIPSTATE *chip, int mode)
+{
+	struct v4l2_subdev *sd = &chip->sd;
+	int sw_data  = chip->shadow.bytes[TDA9873_SW+1] & ~ TDA9873_TR_MASK;
+	/*	int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
+
+	if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) {
+		v4l2_dbg(1, debug, sd,
+			 "tda9873_setaudmode(): external input\n");
+		return;
+	}
+
+	v4l2_dbg(1, debug, sd,
+		 "tda9873_setaudmode(): chip->shadow.bytes[%d] = %d\n",
+		 TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
+	v4l2_dbg(1, debug, sd, "tda9873_setaudmode(): sw_data  = %d\n",
+		 sw_data);
+
+	switch (mode) {
+	case V4L2_TUNER_MODE_MONO:
+		sw_data |= TDA9873_TR_MONO;
+		break;
+	case V4L2_TUNER_MODE_STEREO:
+		sw_data |= TDA9873_TR_STEREO;
+		break;
+	case V4L2_TUNER_MODE_LANG1:
+		sw_data |= TDA9873_TR_DUALA;
+		break;
+	case V4L2_TUNER_MODE_LANG2:
+		sw_data |= TDA9873_TR_DUALB;
+		break;
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+		sw_data |= TDA9873_TR_DUALAB;
+		break;
+	default:
+		return;
+	}
+
+	chip_write(chip, TDA9873_SW, sw_data);
+	v4l2_dbg(1, debug, sd,
+		"tda9873_setaudmode(): req. mode %d; chip_write: %d\n",
+		mode, sw_data);
+}
+
+static int tda9873_checkit(struct CHIPSTATE *chip)
+{
+	int rc;
+
+	if (-1 == (rc = chip_read2(chip,254)))
+		return 0;
+	return (rc & ~0x1f) == 0x80;
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* audio chip description - defines+functions for tda9874h and tda9874a   */
+/* Dariusz Kowalewski <darekk@automex.pl>                                 */
+
+/* Subaddresses for TDA9874H and TDA9874A (slave rx) */
+#define TDA9874A_AGCGR		0x00	/* AGC gain */
+#define TDA9874A_GCONR		0x01	/* general config */
+#define TDA9874A_MSR		0x02	/* monitor select */
+#define TDA9874A_C1FRA		0x03	/* carrier 1 freq. */
+#define TDA9874A_C1FRB		0x04	/* carrier 1 freq. */
+#define TDA9874A_C1FRC		0x05	/* carrier 1 freq. */
+#define TDA9874A_C2FRA		0x06	/* carrier 2 freq. */
+#define TDA9874A_C2FRB		0x07	/* carrier 2 freq. */
+#define TDA9874A_C2FRC		0x08	/* carrier 2 freq. */
+#define TDA9874A_DCR		0x09	/* demodulator config */
+#define TDA9874A_FMER		0x0a	/* FM de-emphasis */
+#define TDA9874A_FMMR		0x0b	/* FM dematrix */
+#define TDA9874A_C1OLAR		0x0c	/* ch.1 output level adj. */
+#define TDA9874A_C2OLAR		0x0d	/* ch.2 output level adj. */
+#define TDA9874A_NCONR		0x0e	/* NICAM config */
+#define TDA9874A_NOLAR		0x0f	/* NICAM output level adj. */
+#define TDA9874A_NLELR		0x10	/* NICAM lower error limit */
+#define TDA9874A_NUELR		0x11	/* NICAM upper error limit */
+#define TDA9874A_AMCONR		0x12	/* audio mute control */
+#define TDA9874A_SDACOSR	0x13	/* stereo DAC output select */
+#define TDA9874A_AOSR		0x14	/* analog output select */
+#define TDA9874A_DAICONR	0x15	/* digital audio interface config */
+#define TDA9874A_I2SOSR		0x16	/* I2S-bus output select */
+#define TDA9874A_I2SOLAR	0x17	/* I2S-bus output level adj. */
+#define TDA9874A_MDACOSR	0x18	/* mono DAC output select (tda9874a) */
+#define TDA9874A_ESP		0xFF	/* easy standard progr. (tda9874a) */
+
+/* Subaddresses for TDA9874H and TDA9874A (slave tx) */
+#define TDA9874A_DSR		0x00	/* device status */
+#define TDA9874A_NSR		0x01	/* NICAM status */
+#define TDA9874A_NECR		0x02	/* NICAM error count */
+#define TDA9874A_DR1		0x03	/* add. data LSB */
+#define TDA9874A_DR2		0x04	/* add. data MSB */
+#define TDA9874A_LLRA		0x05	/* monitor level read-out LSB */
+#define TDA9874A_LLRB		0x06	/* monitor level read-out MSB */
+#define TDA9874A_SIFLR		0x07	/* SIF level */
+#define TDA9874A_TR2		252	/* test reg. 2 */
+#define TDA9874A_TR1		253	/* test reg. 1 */
+#define TDA9874A_DIC		254	/* device id. code */
+#define TDA9874A_SIC		255	/* software id. code */
+
+
+static int tda9874a_mode = 1;		/* 0: A2, 1: NICAM */
+static int tda9874a_GCONR = 0xc0;	/* default config. input pin: SIFSEL=0 */
+static int tda9874a_NCONR = 0x01;	/* default NICAM config.: AMSEL=0,AMUTE=1 */
+static int tda9874a_ESP = 0x07;		/* default standard: NICAM D/K */
+static int tda9874a_dic = -1;		/* device id. code */
+
+/* insmod options for tda9874a */
+static unsigned int tda9874a_SIF   = UNSET;
+static unsigned int tda9874a_AMSEL = UNSET;
+static unsigned int tda9874a_STD   = UNSET;
+module_param(tda9874a_SIF, int, 0444);
+module_param(tda9874a_AMSEL, int, 0444);
+module_param(tda9874a_STD, int, 0444);
+
+/*
+ * initialization table for tda9874 decoder:
+ *  - carrier 1 freq. registers (3 bytes)
+ *  - carrier 2 freq. registers (3 bytes)
+ *  - demudulator config register
+ *  - FM de-emphasis register (slow identification mode)
+ * Note: frequency registers must be written in single i2c transfer.
+ */
+static struct tda9874a_MODES {
+	char *name;
+	audiocmd cmd;
+} tda9874a_modelist[9] = {
+  {	"A2, B/G", /* default */
+	{ 9, { TDA9874A_C1FRA, 0x72,0x95,0x55, 0x77,0xA0,0x00, 0x00,0x00 }} },
+  {	"A2, M (Korea)",
+	{ 9, { TDA9874A_C1FRA, 0x5D,0xC0,0x00, 0x62,0x6A,0xAA, 0x20,0x22 }} },
+  {	"A2, D/K (1)",
+	{ 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x82,0x60,0x00, 0x00,0x00 }} },
+  {	"A2, D/K (2)",
+	{ 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x8C,0x75,0x55, 0x00,0x00 }} },
+  {	"A2, D/K (3)",
+	{ 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x77,0xA0,0x00, 0x00,0x00 }} },
+  {	"NICAM, I",
+	{ 9, { TDA9874A_C1FRA, 0x7D,0x00,0x00, 0x88,0x8A,0xAA, 0x08,0x33 }} },
+  {	"NICAM, B/G",
+	{ 9, { TDA9874A_C1FRA, 0x72,0x95,0x55, 0x79,0xEA,0xAA, 0x08,0x33 }} },
+  {	"NICAM, D/K",
+	{ 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x79,0xEA,0xAA, 0x08,0x33 }} },
+  {	"NICAM, L",
+	{ 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x79,0xEA,0xAA, 0x09,0x33 }} }
+};
+
+static int tda9874a_setup(struct CHIPSTATE *chip)
+{
+	struct v4l2_subdev *sd = &chip->sd;
+
+	chip_write(chip, TDA9874A_AGCGR, 0x00); /* 0 dB */
+	chip_write(chip, TDA9874A_GCONR, tda9874a_GCONR);
+	chip_write(chip, TDA9874A_MSR, (tda9874a_mode) ? 0x03:0x02);
+	if(tda9874a_dic == 0x11) {
+		chip_write(chip, TDA9874A_FMMR, 0x80);
+	} else { /* dic == 0x07 */
+		chip_cmd(chip,"tda9874_modelist",&tda9874a_modelist[tda9874a_STD].cmd);
+		chip_write(chip, TDA9874A_FMMR, 0x00);
+	}
+	chip_write(chip, TDA9874A_C1OLAR, 0x00); /* 0 dB */
+	chip_write(chip, TDA9874A_C2OLAR, 0x00); /* 0 dB */
+	chip_write(chip, TDA9874A_NCONR, tda9874a_NCONR);
+	chip_write(chip, TDA9874A_NOLAR, 0x00); /* 0 dB */
+	/* Note: If signal quality is poor you may want to change NICAM */
+	/* error limit registers (NLELR and NUELR) to some greater values. */
+	/* Then the sound would remain stereo, but won't be so clear. */
+	chip_write(chip, TDA9874A_NLELR, 0x14); /* default */
+	chip_write(chip, TDA9874A_NUELR, 0x50); /* default */
+
+	if(tda9874a_dic == 0x11) {
+		chip_write(chip, TDA9874A_AMCONR, 0xf9);
+		chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80);
+		chip_write(chip, TDA9874A_AOSR, 0x80);
+		chip_write(chip, TDA9874A_MDACOSR, (tda9874a_mode) ? 0x82:0x80);
+		chip_write(chip, TDA9874A_ESP, tda9874a_ESP);
+	} else { /* dic == 0x07 */
+		chip_write(chip, TDA9874A_AMCONR, 0xfb);
+		chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80);
+		chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */
+	}
+	v4l2_dbg(1, debug, sd, "tda9874a_setup(): %s [0x%02X].\n",
+		tda9874a_modelist[tda9874a_STD].name,tda9874a_STD);
+	return 1;
+}
+
+static int tda9874a_getrxsubchans(struct CHIPSTATE *chip)
+{
+	struct v4l2_subdev *sd = &chip->sd;
+	int dsr,nsr,mode;
+	int necr; /* just for debugging */
+
+	mode = V4L2_TUNER_SUB_MONO;
+
+	if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR)))
+		return mode;
+	if(-1 == (nsr = chip_read2(chip,TDA9874A_NSR)))
+		return mode;
+	if(-1 == (necr = chip_read2(chip,TDA9874A_NECR)))
+		return mode;
+
+	/* need to store dsr/nsr somewhere */
+	chip->shadow.bytes[MAXREGS-2] = dsr;
+	chip->shadow.bytes[MAXREGS-1] = nsr;
+
+	if(tda9874a_mode) {
+		/* Note: DSR.RSSF and DSR.AMSTAT bits are also checked.
+		 * If NICAM auto-muting is enabled, DSR.AMSTAT=1 indicates
+		 * that sound has (temporarily) switched from NICAM to
+		 * mono FM (or AM) on 1st sound carrier due to high NICAM bit
+		 * error count. So in fact there is no stereo in this case :-(
+		 * But changing the mode to V4L2_TUNER_MODE_MONO would switch
+		 * external 4052 multiplexer in audio_hook().
+		 */
+		if(nsr & 0x02) /* NSR.S/MB=1 */
+			mode = V4L2_TUNER_SUB_STEREO;
+		if(nsr & 0x01) /* NSR.D/SB=1 */
+			mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+	} else {
+		if(dsr & 0x02) /* DSR.IDSTE=1 */
+			mode = V4L2_TUNER_SUB_STEREO;
+		if(dsr & 0x04) /* DSR.IDDUA=1 */
+			mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+	}
+
+	v4l2_dbg(1, debug, sd,
+		 "tda9874a_getrxsubchans(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
+		 dsr, nsr, necr, mode);
+	return mode;
+}
+
+static void tda9874a_setaudmode(struct CHIPSTATE *chip, int mode)
+{
+	struct v4l2_subdev *sd = &chip->sd;
+
+	/* Disable/enable NICAM auto-muting (based on DSR.RSSF status bit). */
+	/* If auto-muting is disabled, we can hear a signal of degrading quality. */
+	if (tda9874a_mode) {
+		if(chip->shadow.bytes[MAXREGS-2] & 0x20) /* DSR.RSSF=1 */
+			tda9874a_NCONR &= 0xfe; /* enable */
+		else
+			tda9874a_NCONR |= 0x01; /* disable */
+		chip_write(chip, TDA9874A_NCONR, tda9874a_NCONR);
+	}
+
+	/* Note: TDA9874A supports automatic FM dematrixing (FMMR register)
+	 * and has auto-select function for audio output (AOSR register).
+	 * Old TDA9874H doesn't support these features.
+	 * TDA9874A also has additional mono output pin (OUTM), which
+	 * on same (all?) tv-cards is not used, anyway (as well as MONOIN).
+	 */
+	if(tda9874a_dic == 0x11) {
+		int aosr = 0x80;
+		int mdacosr = (tda9874a_mode) ? 0x82:0x80;
+
+		switch(mode) {
+		case V4L2_TUNER_MODE_MONO:
+		case V4L2_TUNER_MODE_STEREO:
+			break;
+		case V4L2_TUNER_MODE_LANG1:
+			aosr = 0x80; /* auto-select, dual A/A */
+			mdacosr = (tda9874a_mode) ? 0x82:0x80;
+			break;
+		case V4L2_TUNER_MODE_LANG2:
+			aosr = 0xa0; /* auto-select, dual B/B */
+			mdacosr = (tda9874a_mode) ? 0x83:0x81;
+			break;
+		case V4L2_TUNER_MODE_LANG1_LANG2:
+			aosr = 0x00; /* always route L to L and R to R */
+			mdacosr = (tda9874a_mode) ? 0x82:0x80;
+			break;
+		default:
+			return;
+		}
+		chip_write(chip, TDA9874A_AOSR, aosr);
+		chip_write(chip, TDA9874A_MDACOSR, mdacosr);
+
+		v4l2_dbg(1, debug, sd,
+			"tda9874a_setaudmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
+			mode, aosr, mdacosr);
+
+	} else { /* dic == 0x07 */
+		int fmmr,aosr;
+
+		switch(mode) {
+		case V4L2_TUNER_MODE_MONO:
+			fmmr = 0x00; /* mono */
+			aosr = 0x10; /* A/A */
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+			if(tda9874a_mode) {
+				fmmr = 0x00;
+				aosr = 0x00; /* handled by NICAM auto-mute */
+			} else {
+				fmmr = (tda9874a_ESP == 1) ? 0x05 : 0x04; /* stereo */
+				aosr = 0x00;
+			}
+			break;
+		case V4L2_TUNER_MODE_LANG1:
+			fmmr = 0x02; /* dual */
+			aosr = 0x10; /* dual A/A */
+			break;
+		case V4L2_TUNER_MODE_LANG2:
+			fmmr = 0x02; /* dual */
+			aosr = 0x20; /* dual B/B */
+			break;
+		case V4L2_TUNER_MODE_LANG1_LANG2:
+			fmmr = 0x02; /* dual */
+			aosr = 0x00; /* dual A/B */
+			break;
+		default:
+			return;
+		}
+		chip_write(chip, TDA9874A_FMMR, fmmr);
+		chip_write(chip, TDA9874A_AOSR, aosr);
+
+		v4l2_dbg(1, debug, sd,
+			"tda9874a_setaudmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
+			mode, fmmr, aosr);
+	}
+}
+
+static int tda9874a_checkit(struct CHIPSTATE *chip)
+{
+	struct v4l2_subdev *sd = &chip->sd;
+	int dic,sic;	/* device id. and software id. codes */
+
+	if(-1 == (dic = chip_read2(chip,TDA9874A_DIC)))
+		return 0;
+	if(-1 == (sic = chip_read2(chip,TDA9874A_SIC)))
+		return 0;
+
+	v4l2_dbg(1, debug, sd, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
+
+	if((dic == 0x11)||(dic == 0x07)) {
+		v4l2_info(sd, "found tda9874%s.\n", (dic == 0x11) ? "a" : "h");
+		tda9874a_dic = dic;	/* remember device id. */
+		return 1;
+	}
+	return 0;	/* not found */
+}
+
+static int tda9874a_initialize(struct CHIPSTATE *chip)
+{
+	if (tda9874a_SIF > 2)
+		tda9874a_SIF = 1;
+	if (tda9874a_STD >= ARRAY_SIZE(tda9874a_modelist))
+		tda9874a_STD = 0;
+	if(tda9874a_AMSEL > 1)
+		tda9874a_AMSEL = 0;
+
+	if(tda9874a_SIF == 1)
+		tda9874a_GCONR = 0xc0;	/* sound IF input 1 */
+	else
+		tda9874a_GCONR = 0xc1;	/* sound IF input 2 */
+
+	tda9874a_ESP = tda9874a_STD;
+	tda9874a_mode = (tda9874a_STD < 5) ? 0 : 1;
+
+	if(tda9874a_AMSEL == 0)
+		tda9874a_NCONR = 0x01; /* auto-mute: analog mono input */
+	else
+		tda9874a_NCONR = 0x05; /* auto-mute: 1st carrier FM or AM */
+
+	tda9874a_setup(chip);
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* audio chip description - defines+functions for tda9875                 */
+/* The TDA9875 is made by Philips Semiconductor
+ * http://www.semiconductors.philips.com
+ * TDA9875: I2C-bus controlled DSP audio processor, FM demodulator
+ *
+ */
+
+/* subaddresses for TDA9875 */
+#define TDA9875_MUT         0x12  /*General mute  (value --> 0b11001100*/
+#define TDA9875_CFG         0x01  /* Config register (value --> 0b00000000 */
+#define TDA9875_DACOS       0x13  /*DAC i/o select (ADC) 0b0000100*/
+#define TDA9875_LOSR        0x16  /*Line output select regirter 0b0100 0001*/
+
+#define TDA9875_CH1V        0x0c  /*Channel 1 volume (mute)*/
+#define TDA9875_CH2V        0x0d  /*Channel 2 volume (mute)*/
+#define TDA9875_SC1         0x14  /*SCART 1 in (mono)*/
+#define TDA9875_SC2         0x15  /*SCART 2 in (mono)*/
+
+#define TDA9875_ADCIS       0x17  /*ADC input select (mono) 0b0110 000*/
+#define TDA9875_AER         0x19  /*Audio effect (AVL+Pseudo) 0b0000 0110*/
+#define TDA9875_MCS         0x18  /*Main channel select (DAC) 0b0000100*/
+#define TDA9875_MVL         0x1a  /* Main volume gauche */
+#define TDA9875_MVR         0x1b  /* Main volume droite */
+#define TDA9875_MBA         0x1d  /* Main Basse */
+#define TDA9875_MTR         0x1e  /* Main treble */
+#define TDA9875_ACS         0x1f  /* Auxiliary channel select (FM) 0b0000000*/
+#define TDA9875_AVL         0x20  /* Auxiliary volume gauche */
+#define TDA9875_AVR         0x21  /* Auxiliary volume droite */
+#define TDA9875_ABA         0x22  /* Auxiliary Basse */
+#define TDA9875_ATR         0x23  /* Auxiliary treble */
+
+#define TDA9875_MSR         0x02  /* Monitor select register */
+#define TDA9875_C1MSB       0x03  /* Carrier 1 (FM) frequency register MSB */
+#define TDA9875_C1MIB       0x04  /* Carrier 1 (FM) frequency register (16-8]b */
+#define TDA9875_C1LSB       0x05  /* Carrier 1 (FM) frequency register LSB */
+#define TDA9875_C2MSB       0x06  /* Carrier 2 (nicam) frequency register MSB */
+#define TDA9875_C2MIB       0x07  /* Carrier 2 (nicam) frequency register (16-8]b */
+#define TDA9875_C2LSB       0x08  /* Carrier 2 (nicam) frequency register LSB */
+#define TDA9875_DCR         0x09  /* Demodulateur configuration regirter*/
+#define TDA9875_DEEM        0x0a  /* FM de-emphasis regirter*/
+#define TDA9875_FMAT        0x0b  /* FM Matrix regirter*/
+
+/* values */
+#define TDA9875_MUTE_ON	    0xff /* general mute */
+#define TDA9875_MUTE_OFF    0xcc /* general no mute */
+
+static int tda9875_initialize(struct CHIPSTATE *chip)
+{
+	chip_write(chip, TDA9875_CFG, 0xd0); /*reg de config 0 (reset)*/
+	chip_write(chip, TDA9875_MSR, 0x03);    /* Monitor 0b00000XXX*/
+	chip_write(chip, TDA9875_C1MSB, 0x00);  /*Car1(FM) MSB XMHz*/
+	chip_write(chip, TDA9875_C1MIB, 0x00);  /*Car1(FM) MIB XMHz*/
+	chip_write(chip, TDA9875_C1LSB, 0x00);  /*Car1(FM) LSB XMHz*/
+	chip_write(chip, TDA9875_C2MSB, 0x00);  /*Car2(NICAM) MSB XMHz*/
+	chip_write(chip, TDA9875_C2MIB, 0x00);  /*Car2(NICAM) MIB XMHz*/
+	chip_write(chip, TDA9875_C2LSB, 0x00);  /*Car2(NICAM) LSB XMHz*/
+	chip_write(chip, TDA9875_DCR, 0x00);    /*Demod config 0x00*/
+	chip_write(chip, TDA9875_DEEM, 0x44);   /*DE-Emph 0b0100 0100*/
+	chip_write(chip, TDA9875_FMAT, 0x00);   /*FM Matrix reg 0x00*/
+	chip_write(chip, TDA9875_SC1, 0x00);    /* SCART 1 (SC1)*/
+	chip_write(chip, TDA9875_SC2, 0x01);    /* SCART 2 (sc2)*/
+
+	chip_write(chip, TDA9875_CH1V, 0x10);  /* Channel volume 1 mute*/
+	chip_write(chip, TDA9875_CH2V, 0x10);  /* Channel volume 2 mute */
+	chip_write(chip, TDA9875_DACOS, 0x02); /* sig DAC i/o(in:nicam)*/
+	chip_write(chip, TDA9875_ADCIS, 0x6f); /* sig ADC input(in:mono)*/
+	chip_write(chip, TDA9875_LOSR, 0x00);  /* line out (in:mono)*/
+	chip_write(chip, TDA9875_AER, 0x00);   /*06 Effect (AVL+PSEUDO) */
+	chip_write(chip, TDA9875_MCS, 0x44);   /* Main ch select (DAC) */
+	chip_write(chip, TDA9875_MVL, 0x03);   /* Vol Main left 10dB */
+	chip_write(chip, TDA9875_MVR, 0x03);   /* Vol Main right 10dB*/
+	chip_write(chip, TDA9875_MBA, 0x00);   /* Main Bass Main 0dB*/
+	chip_write(chip, TDA9875_MTR, 0x00);   /* Main Treble Main 0dB*/
+	chip_write(chip, TDA9875_ACS, 0x44);   /* Aux chan select (dac)*/
+	chip_write(chip, TDA9875_AVL, 0x00);   /* Vol Aux left 0dB*/
+	chip_write(chip, TDA9875_AVR, 0x00);   /* Vol Aux right 0dB*/
+	chip_write(chip, TDA9875_ABA, 0x00);   /* Aux Bass Main 0dB*/
+	chip_write(chip, TDA9875_ATR, 0x00);   /* Aux Aigus Main 0dB*/
+
+	chip_write(chip, TDA9875_MUT, 0xcc);   /* General mute  */
+	return 0;
+}
+
+static int tda9875_volume(int val) { return (unsigned char)(val / 602 - 84); }
+static int tda9875_bass(int val) { return (unsigned char)(max(-12, val / 2115 - 15)); }
+static int tda9875_treble(int val) { return (unsigned char)(val / 2622 - 12); }
+
+/* ----------------------------------------------------------------------- */
+
+
+/* *********************** *
+ * i2c interface functions *
+ * *********************** */
+
+static int tda9875_checkit(struct CHIPSTATE *chip)
+{
+	struct v4l2_subdev *sd = &chip->sd;
+	int dic, rev;
+
+	dic = chip_read2(chip, 254);
+	rev = chip_read2(chip, 255);
+
+	if (dic == 0 || dic == 2) { /* tda9875 and tda9875A */
+		v4l2_info(sd, "found tda9875%s rev. %d.\n",
+			dic == 0 ? "" : "A", rev);
+		return 1;
+	}
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for tea6420                */
+
+#define TEA6300_VL         0x00  /* volume left */
+#define TEA6300_VR         0x01  /* volume right */
+#define TEA6300_BA         0x02  /* bass */
+#define TEA6300_TR         0x03  /* treble */
+#define TEA6300_FA         0x04  /* fader control */
+#define TEA6300_S          0x05  /* switch register */
+				 /* values for those registers: */
+#define TEA6300_S_SA       0x01  /* stereo A input */
+#define TEA6300_S_SB       0x02  /* stereo B */
+#define TEA6300_S_SC       0x04  /* stereo C */
+#define TEA6300_S_GMU      0x80  /* general mute */
+
+#define TEA6320_V          0x00  /* volume (0-5)/loudness off (6)/zero crossing mute(7) */
+#define TEA6320_FFR        0x01  /* fader front right (0-5) */
+#define TEA6320_FFL        0x02  /* fader front left (0-5) */
+#define TEA6320_FRR        0x03  /* fader rear right (0-5) */
+#define TEA6320_FRL        0x04  /* fader rear left (0-5) */
+#define TEA6320_BA         0x05  /* bass (0-4) */
+#define TEA6320_TR         0x06  /* treble (0-4) */
+#define TEA6320_S          0x07  /* switch register */
+				 /* values for those registers: */
+#define TEA6320_S_SA       0x07  /* stereo A input */
+#define TEA6320_S_SB       0x06  /* stereo B */
+#define TEA6320_S_SC       0x05  /* stereo C */
+#define TEA6320_S_SD       0x04  /* stereo D */
+#define TEA6320_S_GMU      0x80  /* general mute */
+
+#define TEA6420_S_SA       0x00  /* stereo A input */
+#define TEA6420_S_SB       0x01  /* stereo B */
+#define TEA6420_S_SC       0x02  /* stereo C */
+#define TEA6420_S_SD       0x03  /* stereo D */
+#define TEA6420_S_SE       0x04  /* stereo E */
+#define TEA6420_S_GMU      0x05  /* general mute */
+
+static int tea6300_shift10(int val) { return val >> 10; }
+static int tea6300_shift12(int val) { return val >> 12; }
+
+/* Assumes 16bit input (values 0x3f to 0x0c are unique, values less than */
+/* 0x0c mirror those immediately higher) */
+static int tea6320_volume(int val) { return (val / (65535/(63-12)) + 12) & 0x3f; }
+static int tea6320_shift11(int val) { return val >> 11; }
+static int tea6320_initialize(struct CHIPSTATE * chip)
+{
+	chip_write(chip, TEA6320_FFR, 0x3f);
+	chip_write(chip, TEA6320_FFL, 0x3f);
+	chip_write(chip, TEA6320_FRR, 0x3f);
+	chip_write(chip, TEA6320_FRL, 0x3f);
+
+	return 0;
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for tda8425                */
+
+#define TDA8425_VL         0x00  /* volume left */
+#define TDA8425_VR         0x01  /* volume right */
+#define TDA8425_BA         0x02  /* bass */
+#define TDA8425_TR         0x03  /* treble */
+#define TDA8425_S1         0x08  /* switch functions */
+				 /* values for those registers: */
+#define TDA8425_S1_OFF     0xEE  /* audio off (mute on) */
+#define TDA8425_S1_CH1     0xCE  /* audio channel 1 (mute off) - "linear stereo" mode */
+#define TDA8425_S1_CH2     0xCF  /* audio channel 2 (mute off) - "linear stereo" mode */
+#define TDA8425_S1_MU      0x20  /* mute bit */
+#define TDA8425_S1_STEREO  0x18  /* stereo bits */
+#define TDA8425_S1_STEREO_SPATIAL 0x18 /* spatial stereo */
+#define TDA8425_S1_STEREO_LINEAR  0x08 /* linear stereo */
+#define TDA8425_S1_STEREO_PSEUDO  0x10 /* pseudo stereo */
+#define TDA8425_S1_STEREO_MONO    0x00 /* forced mono */
+#define TDA8425_S1_ML      0x06        /* language selector */
+#define TDA8425_S1_ML_SOUND_A 0x02     /* sound a */
+#define TDA8425_S1_ML_SOUND_B 0x04     /* sound b */
+#define TDA8425_S1_ML_STEREO  0x06     /* stereo */
+#define TDA8425_S1_IS      0x01        /* channel selector */
+
+
+static int tda8425_shift10(int val) { return (val >> 10) | 0xc0; }
+static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; }
+
+static void tda8425_setaudmode(struct CHIPSTATE *chip, int mode)
+{
+	int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1;
+
+	switch (mode) {
+	case V4L2_TUNER_MODE_LANG1:
+		s1 |= TDA8425_S1_ML_SOUND_A;
+		s1 |= TDA8425_S1_STEREO_PSEUDO;
+		break;
+	case V4L2_TUNER_MODE_LANG2:
+		s1 |= TDA8425_S1_ML_SOUND_B;
+		s1 |= TDA8425_S1_STEREO_PSEUDO;
+		break;
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+		s1 |= TDA8425_S1_ML_STEREO;
+		s1 |= TDA8425_S1_STEREO_LINEAR;
+		break;
+	case V4L2_TUNER_MODE_MONO:
+		s1 |= TDA8425_S1_ML_STEREO;
+		s1 |= TDA8425_S1_STEREO_MONO;
+		break;
+	case V4L2_TUNER_MODE_STEREO:
+		s1 |= TDA8425_S1_ML_STEREO;
+		s1 |= TDA8425_S1_STEREO_SPATIAL;
+		break;
+	default:
+		return;
+	}
+	chip_write(chip,TDA8425_S1,s1);
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for pic16c54 (PV951)       */
+
+/* the registers of 16C54, I2C sub address. */
+#define PIC16C54_REG_KEY_CODE     0x01	       /* Not use. */
+#define PIC16C54_REG_MISC         0x02
+
+/* bit definition of the RESET register, I2C data. */
+#define PIC16C54_MISC_RESET_REMOTE_CTL 0x01 /* bit 0, Reset to receive the key */
+					    /*        code of remote controller */
+#define PIC16C54_MISC_MTS_MAIN         0x02 /* bit 1 */
+#define PIC16C54_MISC_MTS_SAP          0x04 /* bit 2 */
+#define PIC16C54_MISC_MTS_BOTH         0x08 /* bit 3 */
+#define PIC16C54_MISC_SND_MUTE         0x10 /* bit 4, Mute Audio(Line-in and Tuner) */
+#define PIC16C54_MISC_SND_NOTMUTE      0x20 /* bit 5 */
+#define PIC16C54_MISC_SWITCH_TUNER     0x40 /* bit 6	, Switch to Line-in */
+#define PIC16C54_MISC_SWITCH_LINE      0x80 /* bit 7	, Switch to Tuner */
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for TA8874Z                */
+
+/* write 1st byte */
+#define TA8874Z_LED_STE	0x80
+#define TA8874Z_LED_BIL	0x40
+#define TA8874Z_LED_EXT	0x20
+#define TA8874Z_MONO_SET	0x10
+#define TA8874Z_MUTE	0x08
+#define TA8874Z_F_MONO	0x04
+#define TA8874Z_MODE_SUB	0x02
+#define TA8874Z_MODE_MAIN	0x01
+
+/* write 2nd byte */
+/*#define TA8874Z_TI	0x80  */ /* test mode */
+#define TA8874Z_SEPARATION	0x3f
+#define TA8874Z_SEPARATION_DEFAULT	0x10
+
+/* read */
+#define TA8874Z_B1	0x80
+#define TA8874Z_B0	0x40
+#define TA8874Z_CHAG_FLAG	0x20
+
+/*
+ *        B1 B0
+ * mono    L  H
+ * stereo  L  L
+ * BIL     H  L
+ */
+static int ta8874z_getrxsubchans(struct CHIPSTATE *chip)
+{
+	int val, mode;
+
+	val = chip_read(chip);
+	mode = V4L2_TUNER_SUB_MONO;
+	if (val & TA8874Z_B1){
+		mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+	}else if (!(val & TA8874Z_B0)){
+		mode = V4L2_TUNER_SUB_STEREO;
+	}
+	/* v4l2_dbg(1, debug, &chip->sd,
+		 "ta8874z_getrxsubchans(): raw chip read: 0x%02x, return: 0x%02x\n",
+		 val, mode); */
+	return mode;
+}
+
+static audiocmd ta8874z_stereo = { 2, {0, TA8874Z_SEPARATION_DEFAULT}};
+static audiocmd ta8874z_mono = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}};
+static audiocmd ta8874z_main = {2, { 0, TA8874Z_SEPARATION_DEFAULT}};
+static audiocmd ta8874z_sub = {2, { TA8874Z_MODE_SUB, TA8874Z_SEPARATION_DEFAULT}};
+static audiocmd ta8874z_both = {2, { TA8874Z_MODE_MAIN | TA8874Z_MODE_SUB, TA8874Z_SEPARATION_DEFAULT}};
+
+static void ta8874z_setaudmode(struct CHIPSTATE *chip, int mode)
+{
+	struct v4l2_subdev *sd = &chip->sd;
+	int update = 1;
+	audiocmd *t = NULL;
+
+	v4l2_dbg(1, debug, sd, "ta8874z_setaudmode(): mode: 0x%02x\n", mode);
+
+	switch(mode){
+	case V4L2_TUNER_MODE_MONO:
+		t = &ta8874z_mono;
+		break;
+	case V4L2_TUNER_MODE_STEREO:
+		t = &ta8874z_stereo;
+		break;
+	case V4L2_TUNER_MODE_LANG1:
+		t = &ta8874z_main;
+		break;
+	case V4L2_TUNER_MODE_LANG2:
+		t = &ta8874z_sub;
+		break;
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+		t = &ta8874z_both;
+		break;
+	default:
+		update = 0;
+	}
+
+	if(update)
+		chip_cmd(chip, "TA8874Z", t);
+}
+
+static int ta8874z_checkit(struct CHIPSTATE *chip)
+{
+	int rc;
+	rc = chip_read(chip);
+	return ((rc & 0x1f) == 0x1f) ? 1 : 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - struct CHIPDESC                              */
+
+/* insmod options to enable/disable individual audio chips */
+static int tda8425  = 1;
+static int tda9840  = 1;
+static int tda9850  = 1;
+static int tda9855  = 1;
+static int tda9873  = 1;
+static int tda9874a = 1;
+static int tda9875  = 1;
+static int tea6300;	/* default 0 - address clash with msp34xx */
+static int tea6320;	/* default 0 - address clash with msp34xx */
+static int tea6420  = 1;
+static int pic16c54 = 1;
+static int ta8874z;	/* default 0 - address clash with tda9840 */
+
+module_param(tda8425, int, 0444);
+module_param(tda9840, int, 0444);
+module_param(tda9850, int, 0444);
+module_param(tda9855, int, 0444);
+module_param(tda9873, int, 0444);
+module_param(tda9874a, int, 0444);
+module_param(tda9875, int, 0444);
+module_param(tea6300, int, 0444);
+module_param(tea6320, int, 0444);
+module_param(tea6420, int, 0444);
+module_param(pic16c54, int, 0444);
+module_param(ta8874z, int, 0444);
+
+static struct CHIPDESC chiplist[] = {
+	{
+		.name       = "tda9840",
+		.insmodopt  = &tda9840,
+		.addr_lo    = I2C_ADDR_TDA9840 >> 1,
+		.addr_hi    = I2C_ADDR_TDA9840 >> 1,
+		.registers  = 5,
+		.flags      = CHIP_NEED_CHECKMODE,
+
+		/* callbacks */
+		.checkit    = tda9840_checkit,
+		.getrxsubchans = tda9840_getrxsubchans,
+		.setaudmode = tda9840_setaudmode,
+
+		.init       = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
+				/* ,TDA9840_SW, TDA9840_MONO */} }
+	},
+	{
+		.name       = "tda9873h",
+		.insmodopt  = &tda9873,
+		.addr_lo    = I2C_ADDR_TDA985x_L >> 1,
+		.addr_hi    = I2C_ADDR_TDA985x_H >> 1,
+		.registers  = 3,
+		.flags      = CHIP_HAS_INPUTSEL | CHIP_NEED_CHECKMODE,
+
+		/* callbacks */
+		.checkit    = tda9873_checkit,
+		.getrxsubchans = tda9873_getrxsubchans,
+		.setaudmode = tda9873_setaudmode,
+
+		.init       = { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } },
+		.inputreg   = TDA9873_SW,
+		.inputmute  = TDA9873_MUTE | TDA9873_AUTOMUTE,
+		.inputmap   = {0xa0, 0xa2, 0xa0, 0xa0},
+		.inputmask  = TDA9873_INP_MASK|TDA9873_MUTE|TDA9873_AUTOMUTE,
+
+	},
+	{
+		.name       = "tda9874h/a",
+		.insmodopt  = &tda9874a,
+		.addr_lo    = I2C_ADDR_TDA9874 >> 1,
+		.addr_hi    = I2C_ADDR_TDA9874 >> 1,
+		.flags      = CHIP_NEED_CHECKMODE,
+
+		/* callbacks */
+		.initialize = tda9874a_initialize,
+		.checkit    = tda9874a_checkit,
+		.getrxsubchans = tda9874a_getrxsubchans,
+		.setaudmode = tda9874a_setaudmode,
+	},
+	{
+		.name       = "tda9875",
+		.insmodopt  = &tda9875,
+		.addr_lo    = I2C_ADDR_TDA9875 >> 1,
+		.addr_hi    = I2C_ADDR_TDA9875 >> 1,
+		.flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE,
+
+		/* callbacks */
+		.initialize = tda9875_initialize,
+		.checkit    = tda9875_checkit,
+		.volfunc    = tda9875_volume,
+		.bassfunc   = tda9875_bass,
+		.treblefunc = tda9875_treble,
+		.leftreg    = TDA9875_MVL,
+		.rightreg   = TDA9875_MVR,
+		.bassreg    = TDA9875_MBA,
+		.treblereg  = TDA9875_MTR,
+		.leftinit   = 58880,
+		.rightinit  = 58880,
+	},
+	{
+		.name       = "tda9850",
+		.insmodopt  = &tda9850,
+		.addr_lo    = I2C_ADDR_TDA985x_L >> 1,
+		.addr_hi    = I2C_ADDR_TDA985x_H >> 1,
+		.registers  = 11,
+
+		.getrxsubchans = tda985x_getrxsubchans,
+		.setaudmode = tda985x_setaudmode,
+
+		.init       = { 8, { TDA9850_C4, 0x08, 0x08, TDA985x_STEREO, 0x07, 0x10, 0x10, 0x03 } }
+	},
+	{
+		.name       = "tda9855",
+		.insmodopt  = &tda9855,
+		.addr_lo    = I2C_ADDR_TDA985x_L >> 1,
+		.addr_hi    = I2C_ADDR_TDA985x_H >> 1,
+		.registers  = 11,
+		.flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE,
+
+		.leftreg    = TDA9855_VL,
+		.rightreg   = TDA9855_VR,
+		.bassreg    = TDA9855_BA,
+		.treblereg  = TDA9855_TR,
+
+		/* callbacks */
+		.volfunc    = tda9855_volume,
+		.bassfunc   = tda9855_bass,
+		.treblefunc = tda9855_treble,
+		.getrxsubchans = tda985x_getrxsubchans,
+		.setaudmode = tda985x_setaudmode,
+
+		.init       = { 12, { 0, 0x6f, 0x6f, 0x0e, 0x07<<1, 0x8<<2,
+				    TDA9855_MUTE | TDA9855_AVL | TDA9855_LOUD | TDA9855_INT,
+				    TDA985x_STEREO | TDA9855_LINEAR | TDA9855_TZCM | TDA9855_VZCM,
+				    0x07, 0x10, 0x10, 0x03 }}
+	},
+	{
+		.name       = "tea6300",
+		.insmodopt  = &tea6300,
+		.addr_lo    = I2C_ADDR_TEA6300 >> 1,
+		.addr_hi    = I2C_ADDR_TEA6300 >> 1,
+		.registers  = 6,
+		.flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
+
+		.leftreg    = TEA6300_VR,
+		.rightreg   = TEA6300_VL,
+		.bassreg    = TEA6300_BA,
+		.treblereg  = TEA6300_TR,
+
+		/* callbacks */
+		.volfunc    = tea6300_shift10,
+		.bassfunc   = tea6300_shift12,
+		.treblefunc = tea6300_shift12,
+
+		.inputreg   = TEA6300_S,
+		.inputmap   = { TEA6300_S_SA, TEA6300_S_SB, TEA6300_S_SC },
+		.inputmute  = TEA6300_S_GMU,
+	},
+	{
+		.name       = "tea6320",
+		.insmodopt  = &tea6320,
+		.addr_lo    = I2C_ADDR_TEA6300 >> 1,
+		.addr_hi    = I2C_ADDR_TEA6300 >> 1,
+		.registers  = 8,
+		.flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
+
+		.leftreg    = TEA6320_V,
+		.rightreg   = TEA6320_V,
+		.bassreg    = TEA6320_BA,
+		.treblereg  = TEA6320_TR,
+
+		/* callbacks */
+		.initialize = tea6320_initialize,
+		.volfunc    = tea6320_volume,
+		.bassfunc   = tea6320_shift11,
+		.treblefunc = tea6320_shift11,
+
+		.inputreg   = TEA6320_S,
+		.inputmap   = { TEA6320_S_SA, TEA6420_S_SB, TEA6300_S_SC, TEA6320_S_SD },
+		.inputmute  = TEA6300_S_GMU,
+	},
+	{
+		.name       = "tea6420",
+		.insmodopt  = &tea6420,
+		.addr_lo    = I2C_ADDR_TEA6420 >> 1,
+		.addr_hi    = I2C_ADDR_TEA6420 >> 1,
+		.registers  = 1,
+		.flags      = CHIP_HAS_INPUTSEL,
+
+		.inputreg   = -1,
+		.inputmap   = { TEA6420_S_SA, TEA6420_S_SB, TEA6420_S_SC },
+		.inputmute  = TEA6300_S_GMU,
+	},
+	{
+		.name       = "tda8425",
+		.insmodopt  = &tda8425,
+		.addr_lo    = I2C_ADDR_TDA8425 >> 1,
+		.addr_hi    = I2C_ADDR_TDA8425 >> 1,
+		.registers  = 9,
+		.flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
+
+		.leftreg    = TDA8425_VL,
+		.rightreg   = TDA8425_VR,
+		.bassreg    = TDA8425_BA,
+		.treblereg  = TDA8425_TR,
+
+		/* callbacks */
+		.volfunc    = tda8425_shift10,
+		.bassfunc   = tda8425_shift12,
+		.treblefunc = tda8425_shift12,
+		.setaudmode = tda8425_setaudmode,
+
+		.inputreg   = TDA8425_S1,
+		.inputmap   = { TDA8425_S1_CH1, TDA8425_S1_CH1, TDA8425_S1_CH1 },
+		.inputmute  = TDA8425_S1_OFF,
+
+	},
+	{
+		.name       = "pic16c54 (PV951)",
+		.insmodopt  = &pic16c54,
+		.addr_lo    = I2C_ADDR_PIC16C54 >> 1,
+		.addr_hi    = I2C_ADDR_PIC16C54>> 1,
+		.registers  = 2,
+		.flags      = CHIP_HAS_INPUTSEL,
+
+		.inputreg   = PIC16C54_REG_MISC,
+		.inputmap   = {PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_TUNER,
+			     PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE,
+			     PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE,
+			     PIC16C54_MISC_SND_MUTE},
+		.inputmute  = PIC16C54_MISC_SND_MUTE,
+	},
+	{
+		.name       = "ta8874z",
+		.checkit    = ta8874z_checkit,
+		.insmodopt  = &ta8874z,
+		.addr_lo    = I2C_ADDR_TDA9840 >> 1,
+		.addr_hi    = I2C_ADDR_TDA9840 >> 1,
+		.registers  = 2,
+
+		/* callbacks */
+		.getrxsubchans = ta8874z_getrxsubchans,
+		.setaudmode = ta8874z_setaudmode,
+
+		.init       = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}},
+	},
+	{ .name = NULL } /* EOF */
+};
+
+
+/* ---------------------------------------------------------------------- */
+
+static int tvaudio_g_ctrl(struct v4l2_subdev *sd,
+			    struct v4l2_control *ctrl)
+{
+	struct CHIPSTATE *chip = to_state(sd);
+	struct CHIPDESC *desc = chip->desc;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		if (!(desc->flags & CHIP_HAS_INPUTSEL))
+			break;
+		ctrl->value=chip->muted;
+		return 0;
+	case V4L2_CID_AUDIO_VOLUME:
+		if (!(desc->flags & CHIP_HAS_VOLUME))
+			break;
+		ctrl->value = max(chip->left,chip->right);
+		return 0;
+	case V4L2_CID_AUDIO_BALANCE:
+	{
+		int volume;
+		if (!(desc->flags & CHIP_HAS_VOLUME))
+			break;
+		volume = max(chip->left,chip->right);
+		if (volume)
+			ctrl->value=(32768*min(chip->left,chip->right))/volume;
+		else
+			ctrl->value=32768;
+		return 0;
+	}
+	case V4L2_CID_AUDIO_BASS:
+		if (!(desc->flags & CHIP_HAS_BASSTREBLE))
+			break;
+		ctrl->value = chip->bass;
+		return 0;
+	case V4L2_CID_AUDIO_TREBLE:
+		if (!(desc->flags & CHIP_HAS_BASSTREBLE))
+			break;
+		ctrl->value = chip->treble;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int tvaudio_s_ctrl(struct v4l2_subdev *sd,
+			    struct v4l2_control *ctrl)
+{
+	struct CHIPSTATE *chip = to_state(sd);
+	struct CHIPDESC *desc = chip->desc;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		if (!(desc->flags & CHIP_HAS_INPUTSEL))
+			break;
+
+		if (ctrl->value < 0 || ctrl->value >= 2)
+			return -ERANGE;
+		chip->muted = ctrl->value;
+		if (chip->muted)
+			chip_write_masked(chip,desc->inputreg,desc->inputmute,desc->inputmask);
+		else
+			chip_write_masked(chip,desc->inputreg,
+					desc->inputmap[chip->input],desc->inputmask);
+		return 0;
+	case V4L2_CID_AUDIO_VOLUME:
+	{
+		int volume,balance;
+
+		if (!(desc->flags & CHIP_HAS_VOLUME))
+			break;
+
+		volume = max(chip->left,chip->right);
+		if (volume)
+			balance=(32768*min(chip->left,chip->right))/volume;
+		else
+			balance=32768;
+
+		volume=ctrl->value;
+		chip->left = (min(65536 - balance,32768) * volume) / 32768;
+		chip->right = (min(balance,volume *(__u16)32768)) / 32768;
+
+		chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
+		chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
+
+		return 0;
+	}
+	case V4L2_CID_AUDIO_BALANCE:
+	{
+		int volume, balance;
+
+		if (!(desc->flags & CHIP_HAS_VOLUME))
+			break;
+
+		volume = max(chip->left, chip->right);
+		balance = ctrl->value;
+		chip->left = (min(65536 - balance, 32768) * volume) / 32768;
+		chip->right = (min(balance, volume * (__u16)32768)) / 32768;
+
+		chip_write(chip, desc->leftreg, desc->volfunc(chip->left));
+		chip_write(chip, desc->rightreg, desc->volfunc(chip->right));
+
+		return 0;
+	}
+	case V4L2_CID_AUDIO_BASS:
+		if (!(desc->flags & CHIP_HAS_BASSTREBLE))
+			break;
+		chip->bass = ctrl->value;
+		chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
+
+		return 0;
+	case V4L2_CID_AUDIO_TREBLE:
+		if (!(desc->flags & CHIP_HAS_BASSTREBLE))
+			break;
+		chip->treble = ctrl->value;
+		chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
+
+		return 0;
+	}
+	return -EINVAL;
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* video4linux interface                                                  */
+
+static int tvaudio_s_radio(struct v4l2_subdev *sd)
+{
+	struct CHIPSTATE *chip = to_state(sd);
+
+	chip->radio = 1;
+	/* del_timer(&chip->wt); */
+	return 0;
+}
+
+static int tvaudio_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+	struct CHIPSTATE *chip = to_state(sd);
+	struct CHIPDESC *desc = chip->desc;
+
+	switch (qc->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		if (desc->flags & CHIP_HAS_INPUTSEL)
+			return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+		break;
+	case V4L2_CID_AUDIO_VOLUME:
+		if (desc->flags & CHIP_HAS_VOLUME)
+			return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
+		break;
+	case V4L2_CID_AUDIO_BALANCE:
+		if (desc->flags & CHIP_HAS_VOLUME)
+			return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
+		break;
+	case V4L2_CID_AUDIO_BASS:
+	case V4L2_CID_AUDIO_TREBLE:
+		if (desc->flags & CHIP_HAS_BASSTREBLE)
+			return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
+		break;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int tvaudio_s_routing(struct v4l2_subdev *sd,
+			     u32 input, u32 output, u32 config)
+{
+	struct CHIPSTATE *chip = to_state(sd);
+	struct CHIPDESC *desc = chip->desc;
+
+	if (!(desc->flags & CHIP_HAS_INPUTSEL))
+		return 0;
+	if (input >= 4)
+		return -EINVAL;
+	/* There are four inputs: tuner, radio, extern and intern. */
+	chip->input = input;
+	if (chip->muted)
+		return 0;
+	chip_write_masked(chip, desc->inputreg,
+			desc->inputmap[chip->input], desc->inputmask);
+	return 0;
+}
+
+static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct CHIPSTATE *chip = to_state(sd);
+	struct CHIPDESC *desc = chip->desc;
+
+	if (!desc->setaudmode)
+		return 0;
+	if (chip->radio)
+		return 0;
+
+	switch (vt->audmode) {
+	case V4L2_TUNER_MODE_MONO:
+	case V4L2_TUNER_MODE_STEREO:
+	case V4L2_TUNER_MODE_LANG1:
+	case V4L2_TUNER_MODE_LANG2:
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+		break;
+	default:
+		return -EINVAL;
+	}
+	chip->audmode = vt->audmode;
+
+	if (chip->thread)
+		wake_up_process(chip->thread);
+	else
+		desc->setaudmode(chip, vt->audmode);
+
+	return 0;
+}
+
+static int tvaudio_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct CHIPSTATE *chip = to_state(sd);
+	struct CHIPDESC *desc = chip->desc;
+
+	if (!desc->getrxsubchans)
+		return 0;
+	if (chip->radio)
+		return 0;
+
+	vt->audmode = chip->audmode;
+	vt->rxsubchans = desc->getrxsubchans(chip);
+	vt->capability = V4L2_TUNER_CAP_STEREO |
+		V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+
+	return 0;
+}
+
+static int tvaudio_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct CHIPSTATE *chip = to_state(sd);
+
+	chip->radio = 0;
+	return 0;
+}
+
+static int tvaudio_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+{
+	struct CHIPSTATE *chip = to_state(sd);
+	struct CHIPDESC *desc = chip->desc;
+
+	/* For chips that provide getrxsubchans and setaudmode, and doesn't
+	   automatically follows the stereo carrier, a kthread is
+	   created to set the audio standard. In this case, when then
+	   the video channel is changed, tvaudio starts on MONO mode.
+	   After waiting for 2 seconds, the kernel thread is called,
+	   to follow whatever audio standard is pointed by the
+	   audio carrier.
+	 */
+	if (chip->thread) {
+		desc->setaudmode(chip, V4L2_TUNER_MODE_MONO);
+		chip->prevmode = -1; /* reset previous mode */
+		mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
+	}
+	return 0;
+}
+
+static int tvaudio_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVAUDIO, 0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tvaudio_core_ops = {
+	.g_chip_ident = tvaudio_g_chip_ident,
+	.queryctrl = tvaudio_queryctrl,
+	.g_ctrl = tvaudio_g_ctrl,
+	.s_ctrl = tvaudio_s_ctrl,
+	.s_std = tvaudio_s_std,
+};
+
+static const struct v4l2_subdev_tuner_ops tvaudio_tuner_ops = {
+	.s_radio = tvaudio_s_radio,
+	.s_frequency = tvaudio_s_frequency,
+	.s_tuner = tvaudio_s_tuner,
+	.g_tuner = tvaudio_g_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops tvaudio_audio_ops = {
+	.s_routing = tvaudio_s_routing,
+};
+
+static const struct v4l2_subdev_ops tvaudio_ops = {
+	.core = &tvaudio_core_ops,
+	.tuner = &tvaudio_tuner_ops,
+	.audio = &tvaudio_audio_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+
+/* i2c registration                                                       */
+
+static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct CHIPSTATE *chip;
+	struct CHIPDESC  *desc;
+	struct v4l2_subdev *sd;
+
+	if (debug) {
+		printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");
+		printk(KERN_INFO "tvaudio: known chips: ");
+		for (desc = chiplist; desc->name != NULL; desc++)
+			printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name);
+		printk("\n");
+	}
+
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+	sd = &chip->sd;
+	v4l2_i2c_subdev_init(sd, client, &tvaudio_ops);
+
+	/* find description for the chip */
+	v4l2_dbg(1, debug, sd, "chip found @ 0x%x\n", client->addr<<1);
+	for (desc = chiplist; desc->name != NULL; desc++) {
+		if (0 == *(desc->insmodopt))
+			continue;
+		if (client->addr < desc->addr_lo ||
+		    client->addr > desc->addr_hi)
+			continue;
+		if (desc->checkit && !desc->checkit(chip))
+			continue;
+		break;
+	}
+	if (desc->name == NULL) {
+		v4l2_dbg(1, debug, sd, "no matching chip description found\n");
+		kfree(chip);
+		return -EIO;
+	}
+	v4l2_info(sd, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name);
+	if (desc->flags) {
+		v4l2_dbg(1, debug, sd, "matches:%s%s%s.\n",
+			(desc->flags & CHIP_HAS_VOLUME)     ? " volume"      : "",
+			(desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",
+			(desc->flags & CHIP_HAS_INPUTSEL)   ? " audiomux"    : "");
+	}
+
+	/* fill required data structures */
+	if (!id)
+		strlcpy(client->name, desc->name, I2C_NAME_SIZE);
+	chip->desc = desc;
+	chip->shadow.count = desc->registers+1;
+	chip->prevmode = -1;
+	chip->audmode = V4L2_TUNER_MODE_LANG1;
+
+	/* initialization  */
+	if (desc->initialize != NULL)
+		desc->initialize(chip);
+	else
+		chip_cmd(chip, "init", &desc->init);
+
+	if (desc->flags & CHIP_HAS_VOLUME) {
+		if (!desc->volfunc) {
+			/* This shouldn't be happen. Warn user, but keep working
+			   without volume controls
+			 */
+			v4l2_info(sd, "volume callback undefined!\n");
+			desc->flags &= ~CHIP_HAS_VOLUME;
+		} else {
+			chip->left  = desc->leftinit  ? desc->leftinit  : 65535;
+			chip->right = desc->rightinit ? desc->rightinit : 65535;
+			chip_write(chip, desc->leftreg,
+				   desc->volfunc(chip->left));
+			chip_write(chip, desc->rightreg,
+				   desc->volfunc(chip->right));
+		}
+	}
+	if (desc->flags & CHIP_HAS_BASSTREBLE) {
+		if (!desc->bassfunc || !desc->treblefunc) {
+			/* This shouldn't be happen. Warn user, but keep working
+			   without bass/treble controls
+			 */
+			v4l2_info(sd, "bass/treble callbacks undefined!\n");
+			desc->flags &= ~CHIP_HAS_BASSTREBLE;
+		} else {
+			chip->treble = desc->trebleinit ?
+						desc->trebleinit : 32768;
+			chip->bass   = desc->bassinit   ?
+						desc->bassinit   : 32768;
+			chip_write(chip, desc->bassreg,
+				   desc->bassfunc(chip->bass));
+			chip_write(chip, desc->treblereg,
+				   desc->treblefunc(chip->treble));
+		}
+	}
+
+	chip->thread = NULL;
+	init_timer(&chip->wt);
+	if (desc->flags & CHIP_NEED_CHECKMODE) {
+		if (!desc->getrxsubchans || !desc->setaudmode) {
+			/* This shouldn't be happen. Warn user, but keep working
+			   without kthread
+			 */
+			v4l2_info(sd, "set/get mode callbacks undefined!\n");
+			return 0;
+		}
+		/* start async thread */
+		chip->wt.function = chip_thread_wake;
+		chip->wt.data     = (unsigned long)chip;
+		chip->thread = kthread_run(chip_thread, chip, client->name);
+		if (IS_ERR(chip->thread)) {
+			v4l2_warn(sd, "failed to create kthread\n");
+			chip->thread = NULL;
+		}
+	}
+	return 0;
+}
+
+static int tvaudio_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct CHIPSTATE *chip = to_state(sd);
+
+	del_timer_sync(&chip->wt);
+	if (chip->thread) {
+		/* shutdown async thread */
+		kthread_stop(chip->thread);
+		chip->thread = NULL;
+	}
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(chip);
+	return 0;
+}
+
+/* This driver supports many devices and the idea is to let the driver
+   detect which device is present. So rather than listing all supported
+   devices here, we pretend to support a single, fake device type. */
+static const struct i2c_device_id tvaudio_id[] = {
+	{ "tvaudio", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tvaudio_id);
+
+static struct i2c_driver tvaudio_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "tvaudio",
+	},
+	.probe		= tvaudio_probe,
+	.remove		= tvaudio_remove,
+	.id_table	= tvaudio_id,
+};
+
+module_i2c_driver(tvaudio_driver);
diff --git a/drivers/media/i2c/tveeprom.c b/drivers/media/i2c/tveeprom.c
new file mode 100644
index 0000000..3b6cf03
--- /dev/null
+++ b/drivers/media/i2c/tveeprom.c
@@ -0,0 +1,792 @@
+/*
+ * tveeprom - eeprom decoder for tvcard configuration eeproms
+ *
+ * Data and decoding routines shamelessly borrowed from bttv-cards.c
+ * eeprom access routine shamelessly borrowed from bttv-if.c
+ * which are:
+
+    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+			   & Marcus Metzler (mocm@thp.uni-koeln.de)
+    (c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+
+ * Adjustments to fit a more general model and all bugs:
+
+	Copyright (C) 2003 John Klar <linpvr at projectplasma.com>
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+
+#include <media/tuner.h>
+#include <media/tveeprom.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver");
+MODULE_AUTHOR("John Klar");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define STRM(array, i) \
+	(i < sizeof(array) / sizeof(char *) ? array[i] : "unknown")
+
+#define tveeprom_info(fmt, arg...) \
+	v4l_printk(KERN_INFO, "tveeprom", c->adapter, c->addr, fmt , ## arg)
+#define tveeprom_warn(fmt, arg...) \
+	v4l_printk(KERN_WARNING, "tveeprom", c->adapter, c->addr, fmt , ## arg)
+#define tveeprom_dbg(fmt, arg...) do { \
+	if (debug) \
+		v4l_printk(KERN_DEBUG, "tveeprom", \
+				c->adapter, c->addr, fmt , ## arg); \
+	} while (0)
+
+/*
+ * The Hauppauge eeprom uses an 8bit field to determine which
+ * tuner formats the tuner supports.
+ */
+static struct HAUPPAUGE_TUNER_FMT
+{
+	int	id;
+	char *name;
+}
+hauppauge_tuner_fmt[] =
+{
+	{ V4L2_STD_UNKNOWN,                   " UNKNOWN" },
+	{ V4L2_STD_UNKNOWN,                   " FM" },
+	{ V4L2_STD_B|V4L2_STD_GH,             " PAL(B/G)" },
+	{ V4L2_STD_MN,                        " NTSC(M)" },
+	{ V4L2_STD_PAL_I,                     " PAL(I)" },
+	{ V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, " SECAM(L/L')" },
+	{ V4L2_STD_DK,                        " PAL(D/D1/K)" },
+	{ V4L2_STD_ATSC,                      " ATSC/DVB Digital" },
+};
+
+/* This is the full list of possible tuners. Many thanks to Hauppauge for
+   supplying this information. Note that many tuners where only used for
+   testing and never made it to the outside world. So you will only see
+   a subset in actual produced cards. */
+static struct HAUPPAUGE_TUNER
+{
+	int  id;
+	char *name;
+}
+hauppauge_tuner[] =
+{
+	/* 0-9 */
+	{ TUNER_ABSENT,        		"None" },
+	{ TUNER_ABSENT,        		"External" },
+	{ TUNER_ABSENT,        		"Unspecified" },
+	{ TUNER_PHILIPS_PAL,   		"Philips FI1216" },
+	{ TUNER_PHILIPS_SECAM, 		"Philips FI1216MF" },
+	{ TUNER_PHILIPS_NTSC,  		"Philips FI1236" },
+	{ TUNER_PHILIPS_PAL_I, 		"Philips FI1246" },
+	{ TUNER_PHILIPS_PAL_DK,		"Philips FI1256" },
+	{ TUNER_PHILIPS_PAL,   		"Philips FI1216 MK2" },
+	{ TUNER_PHILIPS_SECAM, 		"Philips FI1216MF MK2" },
+	/* 10-19 */
+	{ TUNER_PHILIPS_NTSC,  		"Philips FI1236 MK2" },
+	{ TUNER_PHILIPS_PAL_I, 		"Philips FI1246 MK2" },
+	{ TUNER_PHILIPS_PAL_DK,		"Philips FI1256 MK2" },
+	{ TUNER_TEMIC_NTSC,    		"Temic 4032FY5" },
+	{ TUNER_TEMIC_PAL,     		"Temic 4002FH5" },
+	{ TUNER_TEMIC_PAL_I,   		"Temic 4062FY5" },
+	{ TUNER_PHILIPS_PAL,   		"Philips FR1216 MK2" },
+	{ TUNER_PHILIPS_SECAM, 		"Philips FR1216MF MK2" },
+	{ TUNER_PHILIPS_NTSC,  		"Philips FR1236 MK2" },
+	{ TUNER_PHILIPS_PAL_I, 		"Philips FR1246 MK2" },
+	/* 20-29 */
+	{ TUNER_PHILIPS_PAL_DK,		"Philips FR1256 MK2" },
+	{ TUNER_PHILIPS_PAL,   		"Philips FM1216" },
+	{ TUNER_PHILIPS_SECAM, 		"Philips FM1216MF" },
+	{ TUNER_PHILIPS_NTSC,  		"Philips FM1236" },
+	{ TUNER_PHILIPS_PAL_I, 		"Philips FM1246" },
+	{ TUNER_PHILIPS_PAL_DK,		"Philips FM1256" },
+	{ TUNER_TEMIC_4036FY5_NTSC, 	"Temic 4036FY5" },
+	{ TUNER_ABSENT,        		"Samsung TCPN9082D" },
+	{ TUNER_ABSENT,        		"Samsung TCPM9092P" },
+	{ TUNER_TEMIC_4006FH5_PAL, 	"Temic 4006FH5" },
+	/* 30-39 */
+	{ TUNER_ABSENT,        		"Samsung TCPN9085D" },
+	{ TUNER_ABSENT,        		"Samsung TCPB9085P" },
+	{ TUNER_ABSENT,        		"Samsung TCPL9091P" },
+	{ TUNER_TEMIC_4039FR5_NTSC, 	"Temic 4039FR5" },
+	{ TUNER_PHILIPS_FQ1216ME,   	"Philips FQ1216 ME" },
+	{ TUNER_TEMIC_4066FY5_PAL_I, 	"Temic 4066FY5" },
+	{ TUNER_PHILIPS_NTSC,        	"Philips TD1536" },
+	{ TUNER_PHILIPS_NTSC,        	"Philips TD1536D" },
+	{ TUNER_PHILIPS_NTSC,  		"Philips FMR1236" }, /* mono radio */
+	{ TUNER_ABSENT,        		"Philips FI1256MP" },
+	/* 40-49 */
+	{ TUNER_ABSENT,        		"Samsung TCPQ9091P" },
+	{ TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" },
+	{ TUNER_TEMIC_4009FR5_PAL, 	"Temic 4009FR5" },
+	{ TUNER_TEMIC_4046FM5,     	"Temic 4046FM5" },
+	{ TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" },
+	{ TUNER_ABSENT,        		"Philips TD1536D FH 44"},
+	{ TUNER_LG_NTSC_FM,    		"LG TP18NSR01F"},
+	{ TUNER_LG_PAL_FM,     		"LG TP18PSB01D"},
+	{ TUNER_LG_PAL,        		"LG TP18PSB11D"},
+	{ TUNER_LG_PAL_I_FM,   		"LG TAPC-I001D"},
+	/* 50-59 */
+	{ TUNER_LG_PAL_I,      		"LG TAPC-I701D"},
+	{ TUNER_ABSENT,       		"Temic 4042FI5"},
+	{ TUNER_MICROTUNE_4049FM5, 	"Microtune 4049 FM5"},
+	{ TUNER_ABSENT,        		"LG TPI8NSR11F"},
+	{ TUNER_ABSENT,        		"Microtune 4049 FM5 Alt I2C"},
+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"Philips FQ1216ME MK3"},
+	{ TUNER_ABSENT,        		"Philips FI1236 MK3"},
+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"Philips FM1216 ME MK3"},
+	{ TUNER_PHILIPS_FM1236_MK3, 	"Philips FM1236 MK3"},
+	{ TUNER_ABSENT,        		"Philips FM1216MP MK3"},
+	/* 60-69 */
+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"LG S001D MK3"},
+	{ TUNER_ABSENT,        		"LG M001D MK3"},
+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"LG S701D MK3"},
+	{ TUNER_ABSENT,        		"LG M701D MK3"},
+	{ TUNER_ABSENT,        		"Temic 4146FM5"},
+	{ TUNER_ABSENT,        		"Temic 4136FY5"},
+	{ TUNER_ABSENT,        		"Temic 4106FH5"},
+	{ TUNER_ABSENT,        		"Philips FQ1216LMP MK3"},
+	{ TUNER_LG_NTSC_TAPE,  		"LG TAPE H001F MK3"},
+	{ TUNER_LG_NTSC_TAPE,  		"LG TAPE H701F MK3"},
+	/* 70-79 */
+	{ TUNER_ABSENT,        		"LG TALN H200T"},
+	{ TUNER_ABSENT,        		"LG TALN H250T"},
+	{ TUNER_ABSENT,        		"LG TALN M200T"},
+	{ TUNER_ABSENT,        		"LG TALN Z200T"},
+	{ TUNER_ABSENT,        		"LG TALN S200T"},
+	{ TUNER_ABSENT,        		"Thompson DTT7595"},
+	{ TUNER_ABSENT,        		"Thompson DTT7592"},
+	{ TUNER_ABSENT,        		"Silicon TDA8275C1 8290"},
+	{ TUNER_ABSENT,        		"Silicon TDA8275C1 8290 FM"},
+	{ TUNER_ABSENT,        		"Thompson DTT757"},
+	/* 80-89 */
+	{ TUNER_PHILIPS_FQ1216LME_MK3, 	"Philips FQ1216LME MK3"},
+	{ TUNER_LG_PAL_NEW_TAPC, 	"LG TAPC G701D"},
+	{ TUNER_LG_NTSC_NEW_TAPC, 	"LG TAPC H791F"},
+	{ TUNER_LG_PAL_NEW_TAPC, 	"TCL 2002MB 3"},
+	{ TUNER_LG_PAL_NEW_TAPC, 	"TCL 2002MI 3"},
+	{ TUNER_TCL_2002N,     		"TCL 2002N 6A"},
+	{ TUNER_PHILIPS_FM1236_MK3, 	"Philips FQ1236 MK3"},
+	{ TUNER_SAMSUNG_TCPN_2121P30A, 	"Samsung TCPN 2121P30A"},
+	{ TUNER_ABSENT,        		"Samsung TCPE 4121P30A"},
+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"TCL MFPE05 2"},
+	/* 90-99 */
+	{ TUNER_ABSENT,        		"LG TALN H202T"},
+	{ TUNER_PHILIPS_FQ1216AME_MK4, 	"Philips FQ1216AME MK4"},
+	{ TUNER_PHILIPS_FQ1236A_MK4, 	"Philips FQ1236A MK4"},
+	{ TUNER_ABSENT,       		"Philips FQ1286A MK4"},
+	{ TUNER_ABSENT,        		"Philips FQ1216ME MK5"},
+	{ TUNER_ABSENT,        		"Philips FQ1236 MK5"},
+	{ TUNER_SAMSUNG_TCPG_6121P30A, 	"Samsung TCPG 6121P30A"},
+	{ TUNER_TCL_2002MB,    		"TCL 2002MB_3H"},
+	{ TUNER_ABSENT,        		"TCL 2002MI_3H"},
+	{ TUNER_TCL_2002N,     		"TCL 2002N 5H"},
+	/* 100-109 */
+	{ TUNER_PHILIPS_FMD1216ME_MK3, 	"Philips FMD1216ME"},
+	{ TUNER_TEA5767,       		"Philips TEA5768HL FM Radio"},
+	{ TUNER_ABSENT,        		"Panasonic ENV57H12D5"},
+	{ TUNER_PHILIPS_FM1236_MK3, 	"TCL MFNM05-4"},
+	{ TUNER_PHILIPS_FM1236_MK3,	"TCL MNM05-4"},
+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"TCL MPE05-2"},
+	{ TUNER_ABSENT,        		"TCL MQNM05-4"},
+	{ TUNER_ABSENT,        		"LG TAPC-W701D"},
+	{ TUNER_ABSENT,        		"TCL 9886P-WM"},
+	{ TUNER_ABSENT,        		"TCL 1676NM-WM"},
+	/* 110-119 */
+	{ TUNER_ABSENT,        		"Thompson DTT75105"},
+	{ TUNER_ABSENT,        		"Conexant_CX24109"},
+	{ TUNER_TCL_2002N,     		"TCL M2523_5N_E"},
+	{ TUNER_TCL_2002MB,    		"TCL M2523_3DB_E"},
+	{ TUNER_ABSENT,        		"Philips 8275A"},
+	{ TUNER_ABSENT,        		"Microtune MT2060"},
+	{ TUNER_PHILIPS_FM1236_MK3, 	"Philips FM1236 MK5"},
+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"Philips FM1216ME MK5"},
+	{ TUNER_ABSENT,        		"TCL M2523_3DI_E"},
+	{ TUNER_ABSENT,        		"Samsung THPD5222FG30A"},
+	/* 120-129 */
+	{ TUNER_XC2028,        		"Xceive XC3028"},
+	{ TUNER_PHILIPS_FQ1216LME_MK3,	"Philips FQ1216LME MK5"},
+	{ TUNER_ABSENT,        		"Philips FQD1216LME"},
+	{ TUNER_ABSENT,        		"Conexant CX24118A"},
+	{ TUNER_ABSENT,        		"TCL DMF11WIP"},
+	{ TUNER_ABSENT,        		"TCL MFNM05_4H_E"},
+	{ TUNER_ABSENT,        		"TCL MNM05_4H_E"},
+	{ TUNER_ABSENT,        		"TCL MPE05_2H_E"},
+	{ TUNER_ABSENT,        		"TCL MQNM05_4_U"},
+	{ TUNER_ABSENT,        		"TCL M2523_5NH_E"},
+	/* 130-139 */
+	{ TUNER_ABSENT,        		"TCL M2523_3DBH_E"},
+	{ TUNER_ABSENT,        		"TCL M2523_3DIH_E"},
+	{ TUNER_ABSENT,        		"TCL MFPE05_2_U"},
+	{ TUNER_PHILIPS_FMD1216MEX_MK3,	"Philips FMD1216MEX"},
+	{ TUNER_ABSENT,        		"Philips FRH2036B"},
+	{ TUNER_ABSENT,        		"Panasonic ENGF75_01GF"},
+	{ TUNER_ABSENT,        		"MaxLinear MXL5005"},
+	{ TUNER_ABSENT,        		"MaxLinear MXL5003"},
+	{ TUNER_ABSENT,        		"Xceive XC2028"},
+	{ TUNER_ABSENT,        		"Microtune MT2131"},
+	/* 140-149 */
+	{ TUNER_ABSENT,        		"Philips 8275A_8295"},
+	{ TUNER_ABSENT,        		"TCL MF02GIP_5N_E"},
+	{ TUNER_ABSENT,        		"TCL MF02GIP_3DB_E"},
+	{ TUNER_ABSENT,        		"TCL MF02GIP_3DI_E"},
+	{ TUNER_ABSENT,        		"Microtune MT2266"},
+	{ TUNER_ABSENT,        		"TCL MF10WPP_4N_E"},
+	{ TUNER_ABSENT,        		"LG TAPQ_H702F"},
+	{ TUNER_ABSENT,        		"TCL M09WPP_4N_E"},
+	{ TUNER_ABSENT,        		"MaxLinear MXL5005_v2"},
+	{ TUNER_PHILIPS_TDA8290, 	"Philips 18271_8295"},
+	/* 150-159 */
+	{ TUNER_XC5000,                 "Xceive XC5000"},
+	{ TUNER_ABSENT,                 "Xceive XC3028L"},
+	{ TUNER_ABSENT,                 "NXP 18271C2_716x"},
+	{ TUNER_ABSENT,                 "Xceive XC4000"},
+	{ TUNER_ABSENT,                 "Dibcom 7070"},
+	{ TUNER_PHILIPS_TDA8290,        "NXP 18271C2"},
+	{ TUNER_ABSENT,                 "Siano SMS1010"},
+	{ TUNER_ABSENT,                 "Siano SMS1150"},
+	{ TUNER_ABSENT,                 "MaxLinear 5007"},
+	{ TUNER_ABSENT,                 "TCL M09WPP_2P_E"},
+	/* 160-169 */
+	{ TUNER_ABSENT,                 "Siano SMS1180"},
+	{ TUNER_ABSENT,                 "Maxim_MAX2165"},
+	{ TUNER_ABSENT,                 "Siano SMS1140"},
+	{ TUNER_ABSENT,                 "Siano SMS1150 B1"},
+	{ TUNER_ABSENT,                 "MaxLinear 111"},
+	{ TUNER_ABSENT,                 "Dibcom 7770"},
+	{ TUNER_ABSENT,                 "Siano SMS1180VNS"},
+	{ TUNER_ABSENT,                 "Siano SMS1184"},
+	{ TUNER_PHILIPS_FQ1236_MK5,	"TCL M30WTP-4N-E"},
+	{ TUNER_ABSENT,                 "TCL_M11WPP_2PN_E"},
+	/* 170-179 */
+	{ TUNER_ABSENT,                 "MaxLinear 301"},
+	{ TUNER_ABSENT,                 "Mirics MSi001"},
+	{ TUNER_ABSENT,                 "MaxLinear MxL241SF"},
+	{ TUNER_XC5000C,                "Xceive XC5000C"},
+	{ TUNER_ABSENT,                 "Montage M68TS2020"},
+	{ TUNER_ABSENT,                 "Siano SMS1530"},
+	{ TUNER_ABSENT,                 "Dibcom 7090"},
+	{ TUNER_ABSENT,                 "Xceive XC5200C"},
+	{ TUNER_ABSENT,                 "NXP 18273"},
+	{ TUNER_ABSENT,                 "Montage M88TS2022"},
+	/* 180-189 */
+	{ TUNER_ABSENT,                 "NXP 18272M"},
+	{ TUNER_ABSENT,                 "NXP 18272S"},
+};
+
+/* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are
+ * internal to a video chip, i.e. not a separate audio chip. */
+static struct HAUPPAUGE_AUDIOIC
+{
+	u32   id;
+	char *name;
+}
+audioIC[] =
+{
+	/* 0-4 */
+	{ V4L2_IDENT_NONE,      "None"      },
+	{ V4L2_IDENT_UNKNOWN,   "TEA6300"   },
+	{ V4L2_IDENT_UNKNOWN,   "TEA6320"   },
+	{ V4L2_IDENT_UNKNOWN,   "TDA9850"   },
+	{ V4L2_IDENT_MSPX4XX,   "MSP3400C"  },
+	/* 5-9 */
+	{ V4L2_IDENT_MSPX4XX,   "MSP3410D"  },
+	{ V4L2_IDENT_MSPX4XX,   "MSP3415"   },
+	{ V4L2_IDENT_MSPX4XX,   "MSP3430"   },
+	{ V4L2_IDENT_MSPX4XX,   "MSP3438"   },
+	{ V4L2_IDENT_UNKNOWN,   "CS5331"    },
+	/* 10-14 */
+	{ V4L2_IDENT_MSPX4XX,   "MSP3435"   },
+	{ V4L2_IDENT_MSPX4XX,   "MSP3440"   },
+	{ V4L2_IDENT_MSPX4XX,   "MSP3445"   },
+	{ V4L2_IDENT_MSPX4XX,   "MSP3411"   },
+	{ V4L2_IDENT_MSPX4XX,   "MSP3416"   },
+	/* 15-19 */
+	{ V4L2_IDENT_MSPX4XX,   "MSP3425"   },
+	{ V4L2_IDENT_MSPX4XX,   "MSP3451"   },
+	{ V4L2_IDENT_MSPX4XX,   "MSP3418"   },
+	{ V4L2_IDENT_UNKNOWN,   "Type 0x12" },
+	{ V4L2_IDENT_UNKNOWN,   "OKI7716"   },
+	/* 20-24 */
+	{ V4L2_IDENT_MSPX4XX,   "MSP4410"   },
+	{ V4L2_IDENT_MSPX4XX,   "MSP4420"   },
+	{ V4L2_IDENT_MSPX4XX,   "MSP4440"   },
+	{ V4L2_IDENT_MSPX4XX,   "MSP4450"   },
+	{ V4L2_IDENT_MSPX4XX,   "MSP4408"   },
+	/* 25-29 */
+	{ V4L2_IDENT_MSPX4XX,   "MSP4418"   },
+	{ V4L2_IDENT_MSPX4XX,   "MSP4428"   },
+	{ V4L2_IDENT_MSPX4XX,   "MSP4448"   },
+	{ V4L2_IDENT_MSPX4XX,   "MSP4458"   },
+	{ V4L2_IDENT_MSPX4XX,   "Type 0x1d" },
+	/* 30-34 */
+	{ V4L2_IDENT_AMBIGUOUS, "CX880"     },
+	{ V4L2_IDENT_AMBIGUOUS, "CX881"     },
+	{ V4L2_IDENT_AMBIGUOUS, "CX883"     },
+	{ V4L2_IDENT_AMBIGUOUS, "CX882"     },
+	{ V4L2_IDENT_AMBIGUOUS, "CX25840"   },
+	/* 35-39 */
+	{ V4L2_IDENT_AMBIGUOUS, "CX25841"   },
+	{ V4L2_IDENT_AMBIGUOUS, "CX25842"   },
+	{ V4L2_IDENT_AMBIGUOUS, "CX25843"   },
+	{ V4L2_IDENT_AMBIGUOUS, "CX23418"   },
+	{ V4L2_IDENT_AMBIGUOUS, "CX23885"   },
+	/* 40-44 */
+	{ V4L2_IDENT_AMBIGUOUS, "CX23888"   },
+	{ V4L2_IDENT_AMBIGUOUS, "SAA7131"   },
+	{ V4L2_IDENT_AMBIGUOUS, "CX23887"   },
+	{ V4L2_IDENT_AMBIGUOUS, "SAA7164"   },
+	{ V4L2_IDENT_AMBIGUOUS, "AU8522"    },
+};
+
+/* This list is supplied by Hauppauge. Thanks! */
+static const char *decoderIC[] = {
+	/* 0-4 */
+	"None", "BT815", "BT817", "BT819", "BT815A",
+	/* 5-9 */
+	"BT817A", "BT819A", "BT827", "BT829", "BT848",
+	/* 10-14 */
+	"BT848A", "BT849A", "BT829A", "BT827A", "BT878",
+	/* 15-19 */
+	"BT879", "BT880", "VPX3226E", "SAA7114", "SAA7115",
+	/* 20-24 */
+	"CX880", "CX881", "CX883", "SAA7111", "SAA7113",
+	/* 25-29 */
+	"CX882", "TVP5150A", "CX25840", "CX25841", "CX25842",
+	/* 30-34 */
+	"CX25843", "CX23418", "NEC61153", "CX23885", "CX23888",
+	/* 35-39 */
+	"SAA7131", "CX25837", "CX23887", "CX23885A", "CX23887A",
+	/* 40-42 */
+	"SAA7164", "CX23885B", "AU8522"
+};
+
+static int hasRadioTuner(int tunerType)
+{
+	switch (tunerType) {
+	case 18: /* PNPEnv_TUNER_FR1236_MK2 */
+	case 23: /* PNPEnv_TUNER_FM1236 */
+	case 38: /* PNPEnv_TUNER_FMR1236 */
+	case 16: /* PNPEnv_TUNER_FR1216_MK2 */
+	case 19: /* PNPEnv_TUNER_FR1246_MK2 */
+	case 21: /* PNPEnv_TUNER_FM1216 */
+	case 24: /* PNPEnv_TUNER_FM1246 */
+	case 17: /* PNPEnv_TUNER_FR1216MF_MK2 */
+	case 22: /* PNPEnv_TUNER_FM1216MF */
+	case 20: /* PNPEnv_TUNER_FR1256_MK2 */
+	case 25: /* PNPEnv_TUNER_FM1256 */
+	case 33: /* PNPEnv_TUNER_4039FR5 */
+	case 42: /* PNPEnv_TUNER_4009FR5 */
+	case 52: /* PNPEnv_TUNER_4049FM5 */
+	case 54: /* PNPEnv_TUNER_4049FM5_AltI2C */
+	case 44: /* PNPEnv_TUNER_4009FN5 */
+	case 31: /* PNPEnv_TUNER_TCPB9085P */
+	case 30: /* PNPEnv_TUNER_TCPN9085D */
+	case 46: /* PNPEnv_TUNER_TP18NSR01F */
+	case 47: /* PNPEnv_TUNER_TP18PSB01D */
+	case 49: /* PNPEnv_TUNER_TAPC_I001D */
+	case 60: /* PNPEnv_TUNER_TAPE_S001D_MK3 */
+	case 57: /* PNPEnv_TUNER_FM1216ME_MK3 */
+	case 59: /* PNPEnv_TUNER_FM1216MP_MK3 */
+	case 58: /* PNPEnv_TUNER_FM1236_MK3 */
+	case 68: /* PNPEnv_TUNER_TAPE_H001F_MK3 */
+	case 61: /* PNPEnv_TUNER_TAPE_M001D_MK3 */
+	case 78: /* PNPEnv_TUNER_TDA8275C1_8290_FM */
+	case 89: /* PNPEnv_TUNER_TCL_MFPE05_2 */
+	case 92: /* PNPEnv_TUNER_PHILIPS_FQ1236A_MK4 */
+	case 105:
+		return 1;
+	}
+	return 0;
+}
+
+void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
+				unsigned char *eeprom_data)
+{
+	/* ----------------------------------------------
+	** The hauppauge eeprom format is tagged
+	**
+	** if packet[0] == 0x84, then packet[0..1] == length
+	** else length = packet[0] & 3f;
+	** if packet[0] & f8 == f8, then EOD and packet[1] == checksum
+	**
+	** In our (ivtv) case we're interested in the following:
+	** tuner type:   tag [00].05 or [0a].01 (index into hauppauge_tuner)
+	** tuner fmts:   tag [00].04 or [0a].00 (bitmask index into
+	**		 hauppauge_tuner_fmt)
+	** radio:        tag [00].{last} or [0e].00  (bitmask.  bit2=FM)
+	** audio proc:   tag [02].01 or [05].00 (mask with 0x7f)
+	** decoder proc: tag [09].01)
+
+	** Fun info:
+	** model:      tag [00].07-08 or [06].00-01
+	** revision:   tag [00].09-0b or [06].04-06
+	** serial#:    tag [01].05-07 or [04].04-06
+
+	** # of inputs/outputs ???
+	*/
+
+	int i, j, len, done, beenhere, tag, start;
+
+	int tuner1 = 0, t_format1 = 0, audioic = -1;
+	char *t_name1 = NULL;
+	const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" };
+
+	int tuner2 = 0, t_format2 = 0;
+	char *t_name2 = NULL;
+	const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" };
+
+	memset(tvee, 0, sizeof(*tvee));
+	tvee->tuner_type = TUNER_ABSENT;
+	tvee->tuner2_type = TUNER_ABSENT;
+
+	done = len = beenhere = 0;
+
+	/* Different eeprom start offsets for em28xx, cx2388x and cx23418 */
+	if (eeprom_data[0] == 0x1a &&
+	    eeprom_data[1] == 0xeb &&
+	    eeprom_data[2] == 0x67 &&
+	    eeprom_data[3] == 0x95)
+		start = 0xa0; /* Generic em28xx offset */
+	else if ((eeprom_data[0] & 0xe1) == 0x01 &&
+		 eeprom_data[1] == 0x00 &&
+		 eeprom_data[2] == 0x00 &&
+		 eeprom_data[8] == 0x84)
+		start = 8; /* Generic cx2388x offset */
+	else if (eeprom_data[1] == 0x70 &&
+		 eeprom_data[2] == 0x00 &&
+		 eeprom_data[4] == 0x74 &&
+		 eeprom_data[8] == 0x84)
+		start = 8; /* Generic cx23418 offset (models 74xxx) */
+	else
+		start = 0;
+
+	for (i = start; !done && i < 256; i += len) {
+		if (eeprom_data[i] == 0x84) {
+			len = eeprom_data[i + 1] + (eeprom_data[i + 2] << 8);
+			i += 3;
+		} else if ((eeprom_data[i] & 0xf0) == 0x70) {
+			if (eeprom_data[i] & 0x08) {
+				/* verify checksum! */
+				done = 1;
+				break;
+			}
+			len = eeprom_data[i] & 0x07;
+			++i;
+		} else {
+			tveeprom_warn("Encountered bad packet header [%02x]. "
+				"Corrupt or not a Hauppauge eeprom.\n",
+				eeprom_data[i]);
+			return;
+		}
+
+		if (debug) {
+			tveeprom_info("Tag [%02x] + %d bytes:",
+					eeprom_data[i], len - 1);
+			for (j = 1; j < len; j++)
+				printk(KERN_CONT " %02x", eeprom_data[i + j]);
+			printk(KERN_CONT "\n");
+		}
+
+		/* process by tag */
+		tag = eeprom_data[i];
+		switch (tag) {
+		case 0x00:
+			/* tag: 'Comprehensive' */
+			tuner1 = eeprom_data[i+6];
+			t_format1 = eeprom_data[i+5];
+			tvee->has_radio = eeprom_data[i+len-1];
+			/* old style tag, don't know how to detect
+			IR presence, mark as unknown. */
+			tvee->has_ir = 0;
+			tvee->model =
+				eeprom_data[i+8] +
+				(eeprom_data[i+9] << 8);
+			tvee->revision = eeprom_data[i+10] +
+				(eeprom_data[i+11] << 8) +
+				(eeprom_data[i+12] << 16);
+			break;
+
+		case 0x01:
+			/* tag: 'SerialID' */
+			tvee->serial_number =
+				eeprom_data[i+6] +
+				(eeprom_data[i+7] << 8) +
+				(eeprom_data[i+8] << 16);
+			break;
+
+		case 0x02:
+			/* tag 'AudioInfo'
+			Note mask with 0x7F, high bit used on some older models
+			to indicate 4052 mux was removed in favor of using MSP
+			inputs directly. */
+			audioic = eeprom_data[i+2] & 0x7f;
+			if (audioic < ARRAY_SIZE(audioIC))
+				tvee->audio_processor = audioIC[audioic].id;
+			else
+				tvee->audio_processor = V4L2_IDENT_UNKNOWN;
+			break;
+
+		/* case 0x03: tag 'EEInfo' */
+
+		case 0x04:
+			/* tag 'SerialID2' */
+			tvee->serial_number =
+				eeprom_data[i+5] +
+				(eeprom_data[i+6] << 8) +
+				(eeprom_data[i+7] << 16);
+
+			if ((eeprom_data[i + 8] & 0xf0) &&
+					(tvee->serial_number < 0xffffff)) {
+				tvee->MAC_address[0] = 0x00;
+				tvee->MAC_address[1] = 0x0D;
+				tvee->MAC_address[2] = 0xFE;
+				tvee->MAC_address[3] = eeprom_data[i + 7];
+				tvee->MAC_address[4] = eeprom_data[i + 6];
+				tvee->MAC_address[5] = eeprom_data[i + 5];
+				tvee->has_MAC_address = 1;
+			}
+			break;
+
+		case 0x05:
+			/* tag 'Audio2'
+			Note mask with 0x7F, high bit used on some older models
+			to indicate 4052 mux was removed in favor of using MSP
+			inputs directly. */
+			audioic = eeprom_data[i+1] & 0x7f;
+			if (audioic < ARRAY_SIZE(audioIC))
+				tvee->audio_processor = audioIC[audioic].id;
+			else
+				tvee->audio_processor = V4L2_IDENT_UNKNOWN;
+
+			break;
+
+		case 0x06:
+			/* tag 'ModelRev' */
+			tvee->model =
+				eeprom_data[i + 1] +
+				(eeprom_data[i + 2] << 8) +
+				(eeprom_data[i + 3] << 16) +
+				(eeprom_data[i + 4] << 24);
+			tvee->revision =
+				eeprom_data[i + 5] +
+				(eeprom_data[i + 6] << 8) +
+				(eeprom_data[i + 7] << 16);
+			break;
+
+		case 0x07:
+			/* tag 'Details': according to Hauppauge not interesting
+			on any PCI-era or later boards. */
+			break;
+
+		/* there is no tag 0x08 defined */
+
+		case 0x09:
+			/* tag 'Video' */
+			tvee->decoder_processor = eeprom_data[i + 1];
+			break;
+
+		case 0x0a:
+			/* tag 'Tuner' */
+			if (beenhere == 0) {
+				tuner1 = eeprom_data[i + 2];
+				t_format1 = eeprom_data[i + 1];
+				beenhere = 1;
+			} else {
+				/* a second (radio) tuner may be present */
+				tuner2 = eeprom_data[i + 2];
+				t_format2 = eeprom_data[i + 1];
+				/* not a TV tuner? */
+				if (t_format2 == 0)
+					tvee->has_radio = 1; /* must be radio */
+			}
+			break;
+
+		case 0x0b:
+			/* tag 'Inputs': according to Hauppauge this is specific
+			to each driver family, so no good assumptions can be
+			made. */
+			break;
+
+		/* case 0x0c: tag 'Balun' */
+		/* case 0x0d: tag 'Teletext' */
+
+		case 0x0e:
+			/* tag: 'Radio' */
+			tvee->has_radio = eeprom_data[i+1];
+			break;
+
+		case 0x0f:
+			/* tag 'IRInfo' */
+			tvee->has_ir = 1 | (eeprom_data[i+1] << 1);
+			break;
+
+		/* case 0x10: tag 'VBIInfo' */
+		/* case 0x11: tag 'QCInfo' */
+		/* case 0x12: tag 'InfoBits' */
+
+		default:
+			tveeprom_dbg("Not sure what to do with tag [%02x]\n",
+					tag);
+			/* dump the rest of the packet? */
+		}
+	}
+
+	if (!done) {
+		tveeprom_warn("Ran out of data!\n");
+		return;
+	}
+
+	if (tvee->revision != 0) {
+		tvee->rev_str[0] = 32 + ((tvee->revision >> 18) & 0x3f);
+		tvee->rev_str[1] = 32 + ((tvee->revision >> 12) & 0x3f);
+		tvee->rev_str[2] = 32 + ((tvee->revision >>  6) & 0x3f);
+		tvee->rev_str[3] = 32 + (tvee->revision & 0x3f);
+		tvee->rev_str[4] = 0;
+	}
+
+	if (hasRadioTuner(tuner1) && !tvee->has_radio) {
+		tveeprom_info("The eeprom says no radio is present, but the tuner type\n");
+		tveeprom_info("indicates otherwise. I will assume that radio is present.\n");
+		tvee->has_radio = 1;
+	}
+
+	if (tuner1 < ARRAY_SIZE(hauppauge_tuner)) {
+		tvee->tuner_type = hauppauge_tuner[tuner1].id;
+		t_name1 = hauppauge_tuner[tuner1].name;
+	} else {
+		t_name1 = "unknown";
+	}
+
+	if (tuner2 < ARRAY_SIZE(hauppauge_tuner)) {
+		tvee->tuner2_type = hauppauge_tuner[tuner2].id;
+		t_name2 = hauppauge_tuner[tuner2].name;
+	} else {
+		t_name2 = "unknown";
+	}
+
+	tvee->tuner_hauppauge_model = tuner1;
+	tvee->tuner2_hauppauge_model = tuner2;
+	tvee->tuner_formats = 0;
+	tvee->tuner2_formats = 0;
+	for (i = j = 0; i < 8; i++) {
+		if (t_format1 & (1 << i)) {
+			tvee->tuner_formats |= hauppauge_tuner_fmt[i].id;
+			t_fmt_name1[j++] = hauppauge_tuner_fmt[i].name;
+		}
+	}
+	for (i = j = 0; i < 8; i++) {
+		if (t_format2 & (1 << i)) {
+			tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id;
+			t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name;
+		}
+	}
+
+	tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n",
+		tvee->model, tvee->rev_str, tvee->serial_number);
+	if (tvee->has_MAC_address == 1)
+		tveeprom_info("MAC address is %pM\n", tvee->MAC_address);
+	tveeprom_info("tuner model is %s (idx %d, type %d)\n",
+		t_name1, tuner1, tvee->tuner_type);
+	tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
+		t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2],
+		t_fmt_name1[3],	t_fmt_name1[4], t_fmt_name1[5],
+		t_fmt_name1[6], t_fmt_name1[7],	t_format1);
+	if (tuner2)
+		tveeprom_info("second tuner model is %s (idx %d, type %d)\n",
+					t_name2, tuner2, tvee->tuner2_type);
+	if (t_format2)
+		tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
+			t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2],
+			t_fmt_name2[3],	t_fmt_name2[4], t_fmt_name2[5],
+			t_fmt_name2[6], t_fmt_name2[7], t_format2);
+	if (audioic < 0) {
+		tveeprom_info("audio processor is unknown (no idx)\n");
+		tvee->audio_processor = V4L2_IDENT_UNKNOWN;
+	} else {
+		if (audioic < ARRAY_SIZE(audioIC))
+			tveeprom_info("audio processor is %s (idx %d)\n",
+					audioIC[audioic].name, audioic);
+		else
+			tveeprom_info("audio processor is unknown (idx %d)\n",
+								audioic);
+	}
+	if (tvee->decoder_processor)
+		tveeprom_info("decoder processor is %s (idx %d)\n",
+			STRM(decoderIC, tvee->decoder_processor),
+			tvee->decoder_processor);
+	if (tvee->has_ir)
+		tveeprom_info("has %sradio, has %sIR receiver, has %sIR transmitter\n",
+				tvee->has_radio ? "" : "no ",
+				(tvee->has_ir & 2) ? "" : "no ",
+				(tvee->has_ir & 4) ? "" : "no ");
+	else
+		tveeprom_info("has %sradio\n",
+				tvee->has_radio ? "" : "no ");
+}
+EXPORT_SYMBOL(tveeprom_hauppauge_analog);
+
+/* ----------------------------------------------------------------------- */
+/* generic helper functions                                                */
+
+int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len)
+{
+	unsigned char buf;
+	int err;
+
+	buf = 0;
+	err = i2c_master_send(c, &buf, 1);
+	if (err != 1) {
+		tveeprom_info("Huh, no eeprom present (err=%d)?\n", err);
+		return -1;
+	}
+	err = i2c_master_recv(c, eedata, len);
+	if (err != len) {
+		tveeprom_warn("i2c eeprom read error (err=%d)\n", err);
+		return -1;
+	}
+	if (debug) {
+		int i;
+
+		tveeprom_info("full 256-byte eeprom dump:\n");
+		for (i = 0; i < len; i++) {
+			if (0 == (i % 16))
+				tveeprom_info("%02x:", i);
+			printk(KERN_CONT " %02x", eedata[i]);
+			if (15 == (i % 16))
+				printk(KERN_CONT "\n");
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL(tveeprom_read);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
new file mode 100644
index 0000000..1f3943b
--- /dev/null
+++ b/drivers/media/i2c/tvp514x.c
@@ -0,0 +1,1166 @@
+/*
+ * drivers/media/i2c/tvp514x.c
+ *
+ * TI TVP5146/47 decoder driver
+ *
+ * Copyright (C) 2008 Texas Instruments Inc
+ * Author: Vaibhav Hiremath <hvaibhav@ti.com>
+ *
+ * Contributors:
+ *     Sivaraj R <sivaraj@ti.com>
+ *     Brijesh R Jadav <brijesh.j@ti.com>
+ *     Hardik Shah <hardik.shah@ti.com>
+ *     Manjunath Hadli <mrh@ti.com>
+ *     Karicheri Muralidharan <m-karicheri2@ti.com>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+#include <media/tvp514x.h>
+
+#include "tvp514x_regs.h"
+
+/* Module Name */
+#define TVP514X_MODULE_NAME		"tvp514x"
+
+/* Private macros for TVP */
+#define I2C_RETRY_COUNT                 (5)
+#define LOCK_RETRY_COUNT                (5)
+#define LOCK_RETRY_DELAY                (200)
+
+/* Debug functions */
+static bool debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("TVP514X linux decoder driver");
+MODULE_LICENSE("GPL");
+
+/* enum tvp514x_std - enum for supported standards */
+enum tvp514x_std {
+	STD_NTSC_MJ = 0,
+	STD_PAL_BDGHIN,
+	STD_INVALID
+};
+
+/**
+ * struct tvp514x_std_info - Structure to store standard informations
+ * @width: Line width in pixels
+ * @height:Number of active lines
+ * @video_std: Value to write in REG_VIDEO_STD register
+ * @standard: v4l2 standard structure information
+ */
+struct tvp514x_std_info {
+	unsigned long width;
+	unsigned long height;
+	u8 video_std;
+	struct v4l2_standard standard;
+};
+
+static struct tvp514x_reg tvp514x_reg_list_default[0x40];
+
+static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable);
+/**
+ * struct tvp514x_decoder - TVP5146/47 decoder object
+ * @sd: Subdevice Slave handle
+ * @tvp514x_regs: copy of hw's regs with preset values.
+ * @pdata: Board specific
+ * @ver: Chip version
+ * @streaming: TVP5146/47 decoder streaming - enabled or disabled.
+ * @current_std: Current standard
+ * @num_stds: Number of standards
+ * @std_list: Standards list
+ * @input: Input routing at chip level
+ * @output: Output routing at chip level
+ */
+struct tvp514x_decoder {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)];
+	const struct tvp514x_platform_data *pdata;
+
+	int ver;
+	int streaming;
+
+	enum tvp514x_std current_std;
+	int num_stds;
+	const struct tvp514x_std_info *std_list;
+	/* Input and Output Routing parameters */
+	u32 input;
+	u32 output;
+};
+
+/* TVP514x default register values */
+static struct tvp514x_reg tvp514x_reg_list_default[] = {
+	/* Composite selected */
+	{TOK_WRITE, REG_INPUT_SEL, 0x05},
+	{TOK_WRITE, REG_AFE_GAIN_CTRL, 0x0F},
+	/* Auto mode */
+	{TOK_WRITE, REG_VIDEO_STD, 0x00},
+	{TOK_WRITE, REG_OPERATION_MODE, 0x00},
+	{TOK_SKIP, REG_AUTOSWITCH_MASK, 0x3F},
+	{TOK_WRITE, REG_COLOR_KILLER, 0x10},
+	{TOK_WRITE, REG_LUMA_CONTROL1, 0x00},
+	{TOK_WRITE, REG_LUMA_CONTROL2, 0x00},
+	{TOK_WRITE, REG_LUMA_CONTROL3, 0x02},
+	{TOK_WRITE, REG_BRIGHTNESS, 0x80},
+	{TOK_WRITE, REG_CONTRAST, 0x80},
+	{TOK_WRITE, REG_SATURATION, 0x80},
+	{TOK_WRITE, REG_HUE, 0x00},
+	{TOK_WRITE, REG_CHROMA_CONTROL1, 0x00},
+	{TOK_WRITE, REG_CHROMA_CONTROL2, 0x0E},
+	/* Reserved */
+	{TOK_SKIP, 0x0F, 0x00},
+	{TOK_WRITE, REG_COMP_PR_SATURATION, 0x80},
+	{TOK_WRITE, REG_COMP_Y_CONTRAST, 0x80},
+	{TOK_WRITE, REG_COMP_PB_SATURATION, 0x80},
+	/* Reserved */
+	{TOK_SKIP, 0x13, 0x00},
+	{TOK_WRITE, REG_COMP_Y_BRIGHTNESS, 0x80},
+	/* Reserved */
+	{TOK_SKIP, 0x15, 0x00},
+	/* NTSC timing */
+	{TOK_SKIP, REG_AVID_START_PIXEL_LSB, 0x55},
+	{TOK_SKIP, REG_AVID_START_PIXEL_MSB, 0x00},
+	{TOK_SKIP, REG_AVID_STOP_PIXEL_LSB, 0x25},
+	{TOK_SKIP, REG_AVID_STOP_PIXEL_MSB, 0x03},
+	/* NTSC timing */
+	{TOK_SKIP, REG_HSYNC_START_PIXEL_LSB, 0x00},
+	{TOK_SKIP, REG_HSYNC_START_PIXEL_MSB, 0x00},
+	{TOK_SKIP, REG_HSYNC_STOP_PIXEL_LSB, 0x40},
+	{TOK_SKIP, REG_HSYNC_STOP_PIXEL_MSB, 0x00},
+	/* NTSC timing */
+	{TOK_SKIP, REG_VSYNC_START_LINE_LSB, 0x04},
+	{TOK_SKIP, REG_VSYNC_START_LINE_MSB, 0x00},
+	{TOK_SKIP, REG_VSYNC_STOP_LINE_LSB, 0x07},
+	{TOK_SKIP, REG_VSYNC_STOP_LINE_MSB, 0x00},
+	/* NTSC timing */
+	{TOK_SKIP, REG_VBLK_START_LINE_LSB, 0x01},
+	{TOK_SKIP, REG_VBLK_START_LINE_MSB, 0x00},
+	{TOK_SKIP, REG_VBLK_STOP_LINE_LSB, 0x15},
+	{TOK_SKIP, REG_VBLK_STOP_LINE_MSB, 0x00},
+	/* Reserved */
+	{TOK_SKIP, 0x26, 0x00},
+	/* Reserved */
+	{TOK_SKIP, 0x27, 0x00},
+	{TOK_SKIP, REG_FAST_SWTICH_CONTROL, 0xCC},
+	/* Reserved */
+	{TOK_SKIP, 0x29, 0x00},
+	{TOK_SKIP, REG_FAST_SWTICH_SCART_DELAY, 0x00},
+	/* Reserved */
+	{TOK_SKIP, 0x2B, 0x00},
+	{TOK_SKIP, REG_SCART_DELAY, 0x00},
+	{TOK_SKIP, REG_CTI_DELAY, 0x00},
+	{TOK_SKIP, REG_CTI_CONTROL, 0x00},
+	/* Reserved */
+	{TOK_SKIP, 0x2F, 0x00},
+	/* Reserved */
+	{TOK_SKIP, 0x30, 0x00},
+	/* Reserved */
+	{TOK_SKIP, 0x31, 0x00},
+	/* HS, VS active high */
+	{TOK_WRITE, REG_SYNC_CONTROL, 0x00},
+	/* 10-bit BT.656 */
+	{TOK_WRITE, REG_OUTPUT_FORMATTER1, 0x00},
+	/* Enable clk & data */
+	{TOK_WRITE, REG_OUTPUT_FORMATTER2, 0x11},
+	/* Enable AVID & FLD */
+	{TOK_WRITE, REG_OUTPUT_FORMATTER3, 0xEE},
+	/* Enable VS & HS */
+	{TOK_WRITE, REG_OUTPUT_FORMATTER4, 0xAF},
+	{TOK_WRITE, REG_OUTPUT_FORMATTER5, 0xFF},
+	{TOK_WRITE, REG_OUTPUT_FORMATTER6, 0xFF},
+	/* Clear status */
+	{TOK_WRITE, REG_CLEAR_LOST_LOCK, 0x01},
+	{TOK_TERM, 0, 0},
+};
+
+/**
+ * Supported standards -
+ *
+ * Currently supports two standards only, need to add support for rest of the
+ * modes, like SECAM, etc...
+ */
+static const struct tvp514x_std_info tvp514x_std_list[] = {
+	/* Standard: STD_NTSC_MJ */
+	[STD_NTSC_MJ] = {
+	 .width = NTSC_NUM_ACTIVE_PIXELS,
+	 .height = NTSC_NUM_ACTIVE_LINES,
+	 .video_std = VIDEO_STD_NTSC_MJ_BIT,
+	 .standard = {
+		      .index = 0,
+		      .id = V4L2_STD_NTSC,
+		      .name = "NTSC",
+		      .frameperiod = {1001, 30000},
+		      .framelines = 525
+		     },
+	/* Standard: STD_PAL_BDGHIN */
+	},
+	[STD_PAL_BDGHIN] = {
+	 .width = PAL_NUM_ACTIVE_PIXELS,
+	 .height = PAL_NUM_ACTIVE_LINES,
+	 .video_std = VIDEO_STD_PAL_BDGHIN_BIT,
+	 .standard = {
+		      .index = 1,
+		      .id = V4L2_STD_PAL,
+		      .name = "PAL",
+		      .frameperiod = {1, 25},
+		      .framelines = 625
+		     },
+	},
+	/* Standard: need to add for additional standard */
+};
+
+
+static inline struct tvp514x_decoder *to_decoder(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct tvp514x_decoder, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct tvp514x_decoder, hdl)->sd;
+}
+
+
+/**
+ * tvp514x_read_reg() - Read a value from a register in an TVP5146/47.
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: TVP5146/47 register address
+ *
+ * Returns value read if successful, or non-zero (-1) otherwise.
+ */
+static int tvp514x_read_reg(struct v4l2_subdev *sd, u8 reg)
+{
+	int err, retry = 0;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+read_again:
+
+	err = i2c_smbus_read_byte_data(client, reg);
+	if (err < 0) {
+		if (retry <= I2C_RETRY_COUNT) {
+			v4l2_warn(sd, "Read: retry ... %d\n", retry);
+			retry++;
+			msleep_interruptible(10);
+			goto read_again;
+		}
+	}
+
+	return err;
+}
+
+/**
+ * dump_reg() - dump the register content of TVP5146/47.
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: TVP5146/47 register address
+ */
+static void dump_reg(struct v4l2_subdev *sd, u8 reg)
+{
+	u32 val;
+
+	val = tvp514x_read_reg(sd, reg);
+	v4l2_info(sd, "Reg(0x%.2X): 0x%.2X\n", reg, val);
+}
+
+/**
+ * tvp514x_write_reg() - Write a value to a register in TVP5146/47
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: TVP5146/47 register address
+ * @val: value to be written to the register
+ *
+ * Write a value to a register in an TVP5146/47 decoder device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tvp514x_write_reg(struct v4l2_subdev *sd, u8 reg, u8 val)
+{
+	int err, retry = 0;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+write_again:
+
+	err = i2c_smbus_write_byte_data(client, reg, val);
+	if (err) {
+		if (retry <= I2C_RETRY_COUNT) {
+			v4l2_warn(sd, "Write: retry ... %d\n", retry);
+			retry++;
+			msleep_interruptible(10);
+			goto write_again;
+		}
+	}
+
+	return err;
+}
+
+/**
+ * tvp514x_write_regs() : Initializes a list of TVP5146/47 registers
+ * @sd: ptr to v4l2_subdev struct
+ * @reglist: list of TVP5146/47 registers and values
+ *
+ * Initializes a list of TVP5146/47 registers:-
+ *		if token is TOK_TERM, then entire write operation terminates
+ *		if token is TOK_DELAY, then a delay of 'val' msec is introduced
+ *		if token is TOK_SKIP, then the register write is skipped
+ *		if token is TOK_WRITE, then the register write is performed
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tvp514x_write_regs(struct v4l2_subdev *sd,
+			      const struct tvp514x_reg reglist[])
+{
+	int err;
+	const struct tvp514x_reg *next = reglist;
+
+	for (; next->token != TOK_TERM; next++) {
+		if (next->token == TOK_DELAY) {
+			msleep(next->val);
+			continue;
+		}
+
+		if (next->token == TOK_SKIP)
+			continue;
+
+		err = tvp514x_write_reg(sd, next->reg, (u8) next->val);
+		if (err) {
+			v4l2_err(sd, "Write failed. Err[%d]\n", err);
+			return err;
+		}
+	}
+	return 0;
+}
+
+/**
+ * tvp514x_query_current_std() : Query the current standard detected by TVP5146/47
+ * @sd: ptr to v4l2_subdev struct
+ *
+ * Returns the current standard detected by TVP5146/47, STD_INVALID if there is no
+ * standard detected.
+ */
+static enum tvp514x_std tvp514x_query_current_std(struct v4l2_subdev *sd)
+{
+	u8 std, std_status;
+
+	std = tvp514x_read_reg(sd, REG_VIDEO_STD);
+	if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT)
+		/* use the standard status register */
+		std_status = tvp514x_read_reg(sd, REG_VIDEO_STD_STATUS);
+	else
+		/* use the standard register itself */
+		std_status = std;
+
+	switch (std_status & VIDEO_STD_MASK) {
+	case VIDEO_STD_NTSC_MJ_BIT:
+		return STD_NTSC_MJ;
+
+	case VIDEO_STD_PAL_BDGHIN_BIT:
+		return STD_PAL_BDGHIN;
+
+	default:
+		return STD_INVALID;
+	}
+
+	return STD_INVALID;
+}
+
+/* TVP5146/47 register dump function */
+static void tvp514x_reg_dump(struct v4l2_subdev *sd)
+{
+	dump_reg(sd, REG_INPUT_SEL);
+	dump_reg(sd, REG_AFE_GAIN_CTRL);
+	dump_reg(sd, REG_VIDEO_STD);
+	dump_reg(sd, REG_OPERATION_MODE);
+	dump_reg(sd, REG_COLOR_KILLER);
+	dump_reg(sd, REG_LUMA_CONTROL1);
+	dump_reg(sd, REG_LUMA_CONTROL2);
+	dump_reg(sd, REG_LUMA_CONTROL3);
+	dump_reg(sd, REG_BRIGHTNESS);
+	dump_reg(sd, REG_CONTRAST);
+	dump_reg(sd, REG_SATURATION);
+	dump_reg(sd, REG_HUE);
+	dump_reg(sd, REG_CHROMA_CONTROL1);
+	dump_reg(sd, REG_CHROMA_CONTROL2);
+	dump_reg(sd, REG_COMP_PR_SATURATION);
+	dump_reg(sd, REG_COMP_Y_CONTRAST);
+	dump_reg(sd, REG_COMP_PB_SATURATION);
+	dump_reg(sd, REG_COMP_Y_BRIGHTNESS);
+	dump_reg(sd, REG_AVID_START_PIXEL_LSB);
+	dump_reg(sd, REG_AVID_START_PIXEL_MSB);
+	dump_reg(sd, REG_AVID_STOP_PIXEL_LSB);
+	dump_reg(sd, REG_AVID_STOP_PIXEL_MSB);
+	dump_reg(sd, REG_HSYNC_START_PIXEL_LSB);
+	dump_reg(sd, REG_HSYNC_START_PIXEL_MSB);
+	dump_reg(sd, REG_HSYNC_STOP_PIXEL_LSB);
+	dump_reg(sd, REG_HSYNC_STOP_PIXEL_MSB);
+	dump_reg(sd, REG_VSYNC_START_LINE_LSB);
+	dump_reg(sd, REG_VSYNC_START_LINE_MSB);
+	dump_reg(sd, REG_VSYNC_STOP_LINE_LSB);
+	dump_reg(sd, REG_VSYNC_STOP_LINE_MSB);
+	dump_reg(sd, REG_VBLK_START_LINE_LSB);
+	dump_reg(sd, REG_VBLK_START_LINE_MSB);
+	dump_reg(sd, REG_VBLK_STOP_LINE_LSB);
+	dump_reg(sd, REG_VBLK_STOP_LINE_MSB);
+	dump_reg(sd, REG_SYNC_CONTROL);
+	dump_reg(sd, REG_OUTPUT_FORMATTER1);
+	dump_reg(sd, REG_OUTPUT_FORMATTER2);
+	dump_reg(sd, REG_OUTPUT_FORMATTER3);
+	dump_reg(sd, REG_OUTPUT_FORMATTER4);
+	dump_reg(sd, REG_OUTPUT_FORMATTER5);
+	dump_reg(sd, REG_OUTPUT_FORMATTER6);
+	dump_reg(sd, REG_CLEAR_LOST_LOCK);
+}
+
+/**
+ * tvp514x_configure() - Configure the TVP5146/47 registers
+ * @sd: ptr to v4l2_subdev struct
+ * @decoder: ptr to tvp514x_decoder structure
+ *
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tvp514x_configure(struct v4l2_subdev *sd,
+		struct tvp514x_decoder *decoder)
+{
+	int err;
+
+	/* common register initialization */
+	err =
+	    tvp514x_write_regs(sd, decoder->tvp514x_regs);
+	if (err)
+		return err;
+
+	if (debug)
+		tvp514x_reg_dump(sd);
+
+	return 0;
+}
+
+/**
+ * tvp514x_detect() - Detect if an tvp514x is present, and if so which revision.
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @decoder: pointer to tvp514x_decoder structure
+ *
+ * A device is considered to be detected if the chip ID (LSB and MSB)
+ * registers match the expected values.
+ * Any value of the rom version register is accepted.
+ * Returns ENODEV error number if no device is detected, or zero
+ * if a device is detected.
+ */
+static int tvp514x_detect(struct v4l2_subdev *sd,
+		struct tvp514x_decoder *decoder)
+{
+	u8 chip_id_msb, chip_id_lsb, rom_ver;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	chip_id_msb = tvp514x_read_reg(sd, REG_CHIP_ID_MSB);
+	chip_id_lsb = tvp514x_read_reg(sd, REG_CHIP_ID_LSB);
+	rom_ver = tvp514x_read_reg(sd, REG_ROM_VERSION);
+
+	v4l2_dbg(1, debug, sd,
+		 "chip id detected msb:0x%x lsb:0x%x rom version:0x%x\n",
+		 chip_id_msb, chip_id_lsb, rom_ver);
+	if ((chip_id_msb != TVP514X_CHIP_ID_MSB)
+		|| ((chip_id_lsb != TVP5146_CHIP_ID_LSB)
+		&& (chip_id_lsb != TVP5147_CHIP_ID_LSB))) {
+		/* We didn't read the values we expected, so this must not be
+		 * an TVP5146/47.
+		 */
+		v4l2_err(sd, "chip id mismatch msb:0x%x lsb:0x%x\n",
+				chip_id_msb, chip_id_lsb);
+		return -ENODEV;
+	}
+
+	decoder->ver = rom_ver;
+
+	v4l2_info(sd, "%s (Version - 0x%.2x) found at 0x%x (%s)\n",
+			client->name, decoder->ver,
+			client->addr << 1, client->adapter->name);
+	return 0;
+}
+
+/**
+ * tvp514x_querystd() - V4L2 decoder interface handler for querystd
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @std_id: standard V4L2 std_id ioctl enum
+ *
+ * Returns the current standard detected by TVP5146/47. If no active input is
+ * detected then *std_id is set to 0 and the function returns 0.
+ */
+static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
+{
+	struct tvp514x_decoder *decoder = to_decoder(sd);
+	enum tvp514x_std current_std;
+	enum tvp514x_input input_sel;
+	u8 sync_lock_status, lock_mask;
+
+	if (std_id == NULL)
+		return -EINVAL;
+
+	*std_id = V4L2_STD_UNKNOWN;
+
+	/* query the current standard */
+	current_std = tvp514x_query_current_std(sd);
+	if (current_std == STD_INVALID)
+		return 0;
+
+	input_sel = decoder->input;
+
+	switch (input_sel) {
+	case INPUT_CVBS_VI1A:
+	case INPUT_CVBS_VI1B:
+	case INPUT_CVBS_VI1C:
+	case INPUT_CVBS_VI2A:
+	case INPUT_CVBS_VI2B:
+	case INPUT_CVBS_VI2C:
+	case INPUT_CVBS_VI3A:
+	case INPUT_CVBS_VI3B:
+	case INPUT_CVBS_VI3C:
+	case INPUT_CVBS_VI4A:
+		lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT |
+			STATUS_HORZ_SYNC_LOCK_BIT |
+			STATUS_VIRT_SYNC_LOCK_BIT;
+		break;
+
+	case INPUT_SVIDEO_VI2A_VI1A:
+	case INPUT_SVIDEO_VI2B_VI1B:
+	case INPUT_SVIDEO_VI2C_VI1C:
+	case INPUT_SVIDEO_VI2A_VI3A:
+	case INPUT_SVIDEO_VI2B_VI3B:
+	case INPUT_SVIDEO_VI2C_VI3C:
+	case INPUT_SVIDEO_VI4A_VI1A:
+	case INPUT_SVIDEO_VI4A_VI1B:
+	case INPUT_SVIDEO_VI4A_VI1C:
+	case INPUT_SVIDEO_VI4A_VI3A:
+	case INPUT_SVIDEO_VI4A_VI3B:
+	case INPUT_SVIDEO_VI4A_VI3C:
+		lock_mask = STATUS_HORZ_SYNC_LOCK_BIT |
+			STATUS_VIRT_SYNC_LOCK_BIT;
+		break;
+		/*Need to add other interfaces*/
+	default:
+		return -EINVAL;
+	}
+	/* check whether signal is locked */
+	sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1);
+	if (lock_mask != (sync_lock_status & lock_mask))
+		return 0;	/* No input detected */
+
+	*std_id = decoder->std_list[current_std].standard.id;
+
+	v4l2_dbg(1, debug, sd, "Current STD: %s\n",
+			decoder->std_list[current_std].standard.name);
+	return 0;
+}
+
+/**
+ * tvp514x_s_std() - V4L2 decoder interface handler for s_std
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @std_id: standard V4L2 v4l2_std_id ioctl enum
+ *
+ * If std_id is supported, sets the requested standard. Otherwise, returns
+ * -EINVAL
+ */
+static int tvp514x_s_std(struct v4l2_subdev *sd, v4l2_std_id std_id)
+{
+	struct tvp514x_decoder *decoder = to_decoder(sd);
+	int err, i;
+
+	for (i = 0; i < decoder->num_stds; i++)
+		if (std_id & decoder->std_list[i].standard.id)
+			break;
+
+	if ((i == decoder->num_stds) || (i == STD_INVALID))
+		return -EINVAL;
+
+	err = tvp514x_write_reg(sd, REG_VIDEO_STD,
+				decoder->std_list[i].video_std);
+	if (err)
+		return err;
+
+	decoder->current_std = i;
+	decoder->tvp514x_regs[REG_VIDEO_STD].val =
+		decoder->std_list[i].video_std;
+
+	v4l2_dbg(1, debug, sd, "Standard set to: %s\n",
+			decoder->std_list[i].standard.name);
+	return 0;
+}
+
+/**
+ * tvp514x_s_routing() - V4L2 decoder interface handler for s_routing
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @input: input selector for routing the signal
+ * @output: output selector for routing the signal
+ * @config: config value. Not used
+ *
+ * If index is valid, selects the requested input. Otherwise, returns -EINVAL if
+ * the input is not supported or there is no active signal present in the
+ * selected input.
+ */
+static int tvp514x_s_routing(struct v4l2_subdev *sd,
+				u32 input, u32 output, u32 config)
+{
+	struct tvp514x_decoder *decoder = to_decoder(sd);
+	int err;
+	enum tvp514x_input input_sel;
+	enum tvp514x_output output_sel;
+	u8 sync_lock_status, lock_mask;
+	int try_count = LOCK_RETRY_COUNT;
+
+	if ((input >= INPUT_INVALID) ||
+			(output >= OUTPUT_INVALID))
+		/* Index out of bound */
+		return -EINVAL;
+
+	/*
+	 * For the sequence streamon -> streamoff and again s_input
+	 * it fails to lock the signal, since streamoff puts TVP514x
+	 * into power off state which leads to failure in sub-sequent s_input.
+	 *
+	 * So power up the TVP514x device here, since it is important to lock
+	 * the signal at this stage.
+	 */
+	if (!decoder->streaming)
+		tvp514x_s_stream(sd, 1);
+
+	input_sel = input;
+	output_sel = output;
+
+	err = tvp514x_write_reg(sd, REG_INPUT_SEL, input_sel);
+	if (err)
+		return err;
+
+	output_sel |= tvp514x_read_reg(sd,
+			REG_OUTPUT_FORMATTER1) & 0x7;
+	err = tvp514x_write_reg(sd, REG_OUTPUT_FORMATTER1,
+			output_sel);
+	if (err)
+		return err;
+
+	decoder->tvp514x_regs[REG_INPUT_SEL].val = input_sel;
+	decoder->tvp514x_regs[REG_OUTPUT_FORMATTER1].val = output_sel;
+
+	/* Clear status */
+	msleep(LOCK_RETRY_DELAY);
+	err =
+	    tvp514x_write_reg(sd, REG_CLEAR_LOST_LOCK, 0x01);
+	if (err)
+		return err;
+
+	switch (input_sel) {
+	case INPUT_CVBS_VI1A:
+	case INPUT_CVBS_VI1B:
+	case INPUT_CVBS_VI1C:
+	case INPUT_CVBS_VI2A:
+	case INPUT_CVBS_VI2B:
+	case INPUT_CVBS_VI2C:
+	case INPUT_CVBS_VI3A:
+	case INPUT_CVBS_VI3B:
+	case INPUT_CVBS_VI3C:
+	case INPUT_CVBS_VI4A:
+		lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT |
+			STATUS_HORZ_SYNC_LOCK_BIT |
+			STATUS_VIRT_SYNC_LOCK_BIT;
+		break;
+
+	case INPUT_SVIDEO_VI2A_VI1A:
+	case INPUT_SVIDEO_VI2B_VI1B:
+	case INPUT_SVIDEO_VI2C_VI1C:
+	case INPUT_SVIDEO_VI2A_VI3A:
+	case INPUT_SVIDEO_VI2B_VI3B:
+	case INPUT_SVIDEO_VI2C_VI3C:
+	case INPUT_SVIDEO_VI4A_VI1A:
+	case INPUT_SVIDEO_VI4A_VI1B:
+	case INPUT_SVIDEO_VI4A_VI1C:
+	case INPUT_SVIDEO_VI4A_VI3A:
+	case INPUT_SVIDEO_VI4A_VI3B:
+	case INPUT_SVIDEO_VI4A_VI3C:
+		lock_mask = STATUS_HORZ_SYNC_LOCK_BIT |
+			STATUS_VIRT_SYNC_LOCK_BIT;
+		break;
+	/* Need to add other interfaces*/
+	default:
+		return -EINVAL;
+	}
+
+	while (try_count-- > 0) {
+		/* Allow decoder to sync up with new input */
+		msleep(LOCK_RETRY_DELAY);
+
+		sync_lock_status = tvp514x_read_reg(sd,
+				REG_STATUS1);
+		if (lock_mask == (sync_lock_status & lock_mask))
+			/* Input detected */
+			break;
+	}
+
+	if (try_count < 0)
+		return -EINVAL;
+
+	decoder->input = input;
+	decoder->output = output;
+
+	v4l2_dbg(1, debug, sd, "Input set to: %d\n", input_sel);
+
+	return 0;
+}
+
+/**
+ * tvp514x_s_ctrl() - V4L2 decoder interface handler for s_ctrl
+ * @ctrl: pointer to v4l2_ctrl structure
+ *
+ * If the requested control is supported, sets the control's current
+ * value in HW. Otherwise, returns -EINVAL if the control is not supported.
+ */
+static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct tvp514x_decoder *decoder = to_decoder(sd);
+	int err = -EINVAL, value;
+
+	value = ctrl->val;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		err = tvp514x_write_reg(sd, REG_BRIGHTNESS, value);
+		if (!err)
+			decoder->tvp514x_regs[REG_BRIGHTNESS].val = value;
+		break;
+	case V4L2_CID_CONTRAST:
+		err = tvp514x_write_reg(sd, REG_CONTRAST, value);
+		if (!err)
+			decoder->tvp514x_regs[REG_CONTRAST].val = value;
+		break;
+	case V4L2_CID_SATURATION:
+		err = tvp514x_write_reg(sd, REG_SATURATION, value);
+		if (!err)
+			decoder->tvp514x_regs[REG_SATURATION].val = value;
+		break;
+	case V4L2_CID_HUE:
+		if (value == 180)
+			value = 0x7F;
+		else if (value == -180)
+			value = 0x80;
+		err = tvp514x_write_reg(sd, REG_HUE, value);
+		if (!err)
+			decoder->tvp514x_regs[REG_HUE].val = value;
+		break;
+	case V4L2_CID_AUTOGAIN:
+		err = tvp514x_write_reg(sd, REG_AFE_GAIN_CTRL, value ? 0x0f : 0x0c);
+		if (!err)
+			decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value;
+		break;
+	}
+
+	v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d\n",
+			ctrl->id, ctrl->val);
+	return err;
+}
+
+/**
+ * tvp514x_enum_mbus_fmt() - V4L2 decoder interface handler for enum_mbus_fmt
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @index: index of pixelcode to retrieve
+ * @code: receives the pixelcode
+ *
+ * Enumerates supported mediabus formats
+ */
+static int
+tvp514x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+					enum v4l2_mbus_pixelcode *code)
+{
+	if (index)
+		return -EINVAL;
+
+	*code = V4L2_MBUS_FMT_YUYV10_2X10;
+	return 0;
+}
+
+/**
+ * tvp514x_mbus_fmt_cap() - V4L2 decoder interface handler for try/s/g_mbus_fmt
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @f: pointer to the mediabus format structure
+ *
+ * Negotiates the image capture size and mediabus format.
+ */
+static int
+tvp514x_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
+{
+	struct tvp514x_decoder *decoder = to_decoder(sd);
+	enum tvp514x_std current_std;
+
+	if (f == NULL)
+		return -EINVAL;
+
+	/* Calculate height and width based on current standard */
+	current_std = decoder->current_std;
+
+	f->code = V4L2_MBUS_FMT_YUYV10_2X10;
+	f->width = decoder->std_list[current_std].width;
+	f->height = decoder->std_list[current_std].height;
+	f->field = V4L2_FIELD_INTERLACED;
+	f->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+	v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d\n",
+			f->width, f->height);
+	return 0;
+}
+
+/**
+ * tvp514x_g_parm() - V4L2 decoder interface handler for g_parm
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the decoder's video CAPTURE parameters.
+ */
+static int
+tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+	struct tvp514x_decoder *decoder = to_decoder(sd);
+	struct v4l2_captureparm *cparm;
+	enum tvp514x_std current_std;
+
+	if (a == NULL)
+		return -EINVAL;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		/* only capture is supported */
+		return -EINVAL;
+
+	/* get the current standard */
+	current_std = decoder->current_std;
+
+	cparm = &a->parm.capture;
+	cparm->capability = V4L2_CAP_TIMEPERFRAME;
+	cparm->timeperframe =
+		decoder->std_list[current_std].standard.frameperiod;
+
+	return 0;
+}
+
+/**
+ * tvp514x_s_parm() - V4L2 decoder interface handler for s_parm
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the decoder to use the input parameters, if possible. If
+ * not possible, returns the appropriate error code.
+ */
+static int
+tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+	struct tvp514x_decoder *decoder = to_decoder(sd);
+	struct v4l2_fract *timeperframe;
+	enum tvp514x_std current_std;
+
+	if (a == NULL)
+		return -EINVAL;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		/* only capture is supported */
+		return -EINVAL;
+
+	timeperframe = &a->parm.capture.timeperframe;
+
+	/* get the current standard */
+	current_std = decoder->current_std;
+
+	*timeperframe =
+	    decoder->std_list[current_std].standard.frameperiod;
+
+	return 0;
+}
+
+/**
+ * tvp514x_s_stream() - V4L2 decoder i/f handler for s_stream
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @enable: streaming enable or disable
+ *
+ * Sets streaming to enable or disable, if possible.
+ */
+static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	int err = 0;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct tvp514x_decoder *decoder = to_decoder(sd);
+
+	if (decoder->streaming == enable)
+		return 0;
+
+	switch (enable) {
+	case 0:
+	{
+		/* Power Down Sequence */
+		err = tvp514x_write_reg(sd, REG_OPERATION_MODE, 0x01);
+		if (err) {
+			v4l2_err(sd, "Unable to turn off decoder\n");
+			return err;
+		}
+		decoder->streaming = enable;
+		break;
+	}
+	case 1:
+	{
+		struct tvp514x_reg *int_seq = (struct tvp514x_reg *)
+				client->driver->id_table->driver_data;
+
+		/* Power Up Sequence */
+		err = tvp514x_write_regs(sd, int_seq);
+		if (err) {
+			v4l2_err(sd, "Unable to turn on decoder\n");
+			return err;
+		}
+		/* Detect if not already detected */
+		err = tvp514x_detect(sd, decoder);
+		if (err) {
+			v4l2_err(sd, "Unable to detect decoder\n");
+			return err;
+		}
+		err = tvp514x_configure(sd, decoder);
+		if (err) {
+			v4l2_err(sd, "Unable to configure decoder\n");
+			return err;
+		}
+		decoder->streaming = enable;
+		break;
+	}
+	default:
+		err = -ENODEV;
+		break;
+	}
+
+	return err;
+}
+
+static const struct v4l2_ctrl_ops tvp514x_ctrl_ops = {
+	.s_ctrl = tvp514x_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops tvp514x_core_ops = {
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+	.s_std = tvp514x_s_std,
+};
+
+static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
+	.s_routing = tvp514x_s_routing,
+	.querystd = tvp514x_querystd,
+	.enum_mbus_fmt = tvp514x_enum_mbus_fmt,
+	.g_mbus_fmt = tvp514x_mbus_fmt,
+	.try_mbus_fmt = tvp514x_mbus_fmt,
+	.s_mbus_fmt = tvp514x_mbus_fmt,
+	.g_parm = tvp514x_g_parm,
+	.s_parm = tvp514x_s_parm,
+	.s_stream = tvp514x_s_stream,
+};
+
+static const struct v4l2_subdev_ops tvp514x_ops = {
+	.core = &tvp514x_core_ops,
+	.video = &tvp514x_video_ops,
+};
+
+static struct tvp514x_decoder tvp514x_dev = {
+	.streaming = 0,
+	.current_std = STD_NTSC_MJ,
+	.std_list = tvp514x_std_list,
+	.num_stds = ARRAY_SIZE(tvp514x_std_list),
+
+};
+
+/**
+ * tvp514x_probe() - decoder driver i2c probe handler
+ * @client: i2c driver client device structure
+ * @id: i2c driver id table
+ *
+ * Register decoder as an i2c client device and V4L2
+ * device.
+ */
+static int
+tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct tvp514x_decoder *decoder;
+	struct v4l2_subdev *sd;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	if (!client->dev.platform_data) {
+		v4l2_err(client, "No platform data!!\n");
+		return -ENODEV;
+	}
+
+	decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
+	if (!decoder)
+		return -ENOMEM;
+
+	/* Initialize the tvp514x_decoder with default configuration */
+	*decoder = tvp514x_dev;
+	/* Copy default register configuration */
+	memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default,
+			sizeof(tvp514x_reg_list_default));
+
+	/* Copy board specific information here */
+	decoder->pdata = client->dev.platform_data;
+
+	/**
+	 * Fetch platform specific data, and configure the
+	 * tvp514x_reg_list[] accordingly. Since this is one
+	 * time configuration, no need to preserve.
+	 */
+	decoder->tvp514x_regs[REG_OUTPUT_FORMATTER2].val |=
+		(decoder->pdata->clk_polarity << 1);
+	decoder->tvp514x_regs[REG_SYNC_CONTROL].val |=
+		((decoder->pdata->hs_polarity << 2) |
+		 (decoder->pdata->vs_polarity << 3));
+	/* Set default standard to auto */
+	decoder->tvp514x_regs[REG_VIDEO_STD].val =
+		VIDEO_STD_AUTO_SWITCH_BIT;
+
+	/* Register with V4L2 layer as slave device */
+	sd = &decoder->sd;
+	v4l2_i2c_subdev_init(sd, client, &tvp514x_ops);
+
+	v4l2_ctrl_handler_init(&decoder->hdl, 5);
+	v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+		V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+		V4L2_CID_CONTRAST, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+		V4L2_CID_SATURATION, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+		V4L2_CID_HUE, -180, 180, 180, 0);
+	v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+		V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+	sd->ctrl_handler = &decoder->hdl;
+	if (decoder->hdl.error) {
+		int err = decoder->hdl.error;
+
+		v4l2_ctrl_handler_free(&decoder->hdl);
+		kfree(decoder);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&decoder->hdl);
+
+	v4l2_info(sd, "%s decoder driver registered !!\n", sd->name);
+
+	return 0;
+
+}
+
+/**
+ * tvp514x_remove() - decoder driver i2c remove handler
+ * @client: i2c driver client device structure
+ *
+ * Unregister decoder as an i2c client device and V4L2
+ * device. Complement of tvp514x_probe().
+ */
+static int tvp514x_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct tvp514x_decoder *decoder = to_decoder(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&decoder->hdl);
+	kfree(decoder);
+	return 0;
+}
+/* TVP5146 Init/Power on Sequence */
+static const struct tvp514x_reg tvp5146_init_reg_seq[] = {
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02},
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0x80},
+	{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
+	{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
+	{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00},
+	{TOK_WRITE, REG_OPERATION_MODE, 0x01},
+	{TOK_WRITE, REG_OPERATION_MODE, 0x00},
+	{TOK_TERM, 0, 0},
+};
+
+/* TVP5147 Init/Power on Sequence */
+static const struct tvp514x_reg tvp5147_init_reg_seq[] =	{
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02},
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0x80},
+	{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
+	{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x16},
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xA0},
+	{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x16},
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+	{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
+	{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00},
+	{TOK_WRITE, REG_OPERATION_MODE, 0x01},
+	{TOK_WRITE, REG_OPERATION_MODE, 0x00},
+	{TOK_TERM, 0, 0},
+};
+
+/* TVP5146M2/TVP5147M1 Init/Power on Sequence */
+static const struct tvp514x_reg tvp514xm_init_reg_seq[] = {
+	{TOK_WRITE, REG_OPERATION_MODE, 0x01},
+	{TOK_WRITE, REG_OPERATION_MODE, 0x00},
+	{TOK_TERM, 0, 0},
+};
+
+/**
+ * I2C Device Table -
+ *
+ * name - Name of the actual device/chip.
+ * driver_data - Driver data
+ */
+static const struct i2c_device_id tvp514x_id[] = {
+	{"tvp5146", (unsigned long)tvp5146_init_reg_seq},
+	{"tvp5146m2", (unsigned long)tvp514xm_init_reg_seq},
+	{"tvp5147", (unsigned long)tvp5147_init_reg_seq},
+	{"tvp5147m1", (unsigned long)tvp514xm_init_reg_seq},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, tvp514x_id);
+
+static struct i2c_driver tvp514x_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = TVP514X_MODULE_NAME,
+	},
+	.probe = tvp514x_probe,
+	.remove = tvp514x_remove,
+	.id_table = tvp514x_id,
+};
+
+module_i2c_driver(tvp514x_driver);
diff --git a/drivers/media/i2c/tvp514x_regs.h b/drivers/media/i2c/tvp514x_regs.h
new file mode 100644
index 0000000..d23aa2f
--- /dev/null
+++ b/drivers/media/i2c/tvp514x_regs.h
@@ -0,0 +1,287 @@
+/*
+ * drivers/media/i2c/tvp514x_regs.h
+ *
+ * Copyright (C) 2008 Texas Instruments Inc
+ * Author: Vaibhav Hiremath <hvaibhav@ti.com>
+ *
+ * Contributors:
+ *     Sivaraj R <sivaraj@ti.com>
+ *     Brijesh R Jadav <brijesh.j@ti.com>
+ *     Hardik Shah <hardik.shah@ti.com>
+ *     Manjunath Hadli <mrh@ti.com>
+ *     Karicheri Muralidharan <m-karicheri2@ti.com>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _TVP514X_REGS_H
+#define _TVP514X_REGS_H
+
+/*
+ * TVP5146/47 registers
+ */
+#define REG_INPUT_SEL			(0x00)
+#define REG_AFE_GAIN_CTRL		(0x01)
+#define REG_VIDEO_STD			(0x02)
+#define REG_OPERATION_MODE		(0x03)
+#define REG_AUTOSWITCH_MASK		(0x04)
+
+#define REG_COLOR_KILLER		(0x05)
+#define REG_LUMA_CONTROL1		(0x06)
+#define REG_LUMA_CONTROL2		(0x07)
+#define REG_LUMA_CONTROL3		(0x08)
+
+#define REG_BRIGHTNESS			(0x09)
+#define REG_CONTRAST			(0x0A)
+#define REG_SATURATION			(0x0B)
+#define REG_HUE				(0x0C)
+
+#define REG_CHROMA_CONTROL1		(0x0D)
+#define REG_CHROMA_CONTROL2		(0x0E)
+
+/* 0x0F Reserved */
+
+#define REG_COMP_PR_SATURATION		(0x10)
+#define REG_COMP_Y_CONTRAST		(0x11)
+#define REG_COMP_PB_SATURATION		(0x12)
+
+/* 0x13 Reserved */
+
+#define REG_COMP_Y_BRIGHTNESS		(0x14)
+
+/* 0x15 Reserved */
+
+#define REG_AVID_START_PIXEL_LSB	(0x16)
+#define REG_AVID_START_PIXEL_MSB	(0x17)
+#define REG_AVID_STOP_PIXEL_LSB		(0x18)
+#define REG_AVID_STOP_PIXEL_MSB		(0x19)
+
+#define REG_HSYNC_START_PIXEL_LSB	(0x1A)
+#define REG_HSYNC_START_PIXEL_MSB	(0x1B)
+#define REG_HSYNC_STOP_PIXEL_LSB	(0x1C)
+#define REG_HSYNC_STOP_PIXEL_MSB	(0x1D)
+
+#define REG_VSYNC_START_LINE_LSB	(0x1E)
+#define REG_VSYNC_START_LINE_MSB	(0x1F)
+#define REG_VSYNC_STOP_LINE_LSB		(0x20)
+#define REG_VSYNC_STOP_LINE_MSB		(0x21)
+
+#define REG_VBLK_START_LINE_LSB		(0x22)
+#define REG_VBLK_START_LINE_MSB		(0x23)
+#define REG_VBLK_STOP_LINE_LSB		(0x24)
+#define REG_VBLK_STOP_LINE_MSB		(0x25)
+
+/* 0x26 - 0x27 Reserved */
+
+#define REG_FAST_SWTICH_CONTROL		(0x28)
+
+/* 0x29 Reserved */
+
+#define REG_FAST_SWTICH_SCART_DELAY	(0x2A)
+
+/* 0x2B Reserved */
+
+#define REG_SCART_DELAY			(0x2C)
+#define REG_CTI_DELAY			(0x2D)
+#define REG_CTI_CONTROL			(0x2E)
+
+/* 0x2F - 0x31 Reserved */
+
+#define REG_SYNC_CONTROL		(0x32)
+#define REG_OUTPUT_FORMATTER1		(0x33)
+#define REG_OUTPUT_FORMATTER2		(0x34)
+#define REG_OUTPUT_FORMATTER3		(0x35)
+#define REG_OUTPUT_FORMATTER4		(0x36)
+#define REG_OUTPUT_FORMATTER5		(0x37)
+#define REG_OUTPUT_FORMATTER6		(0x38)
+#define REG_CLEAR_LOST_LOCK		(0x39)
+
+#define REG_STATUS1			(0x3A)
+#define REG_STATUS2			(0x3B)
+
+#define REG_AGC_GAIN_STATUS_LSB		(0x3C)
+#define REG_AGC_GAIN_STATUS_MSB		(0x3D)
+
+/* 0x3E Reserved */
+
+#define REG_VIDEO_STD_STATUS		(0x3F)
+#define REG_GPIO_INPUT1			(0x40)
+#define REG_GPIO_INPUT2			(0x41)
+
+/* 0x42 - 0x45 Reserved */
+
+#define REG_AFE_COARSE_GAIN_CH1		(0x46)
+#define REG_AFE_COARSE_GAIN_CH2		(0x47)
+#define REG_AFE_COARSE_GAIN_CH3		(0x48)
+#define REG_AFE_COARSE_GAIN_CH4		(0x49)
+
+#define REG_AFE_FINE_GAIN_PB_B_LSB	(0x4A)
+#define REG_AFE_FINE_GAIN_PB_B_MSB	(0x4B)
+#define REG_AFE_FINE_GAIN_Y_G_CHROMA_LSB	(0x4C)
+#define REG_AFE_FINE_GAIN_Y_G_CHROMA_MSB	(0x4D)
+#define REG_AFE_FINE_GAIN_PR_R_LSB	(0x4E)
+#define REG_AFE_FINE_GAIN_PR_R_MSB	(0x4F)
+#define REG_AFE_FINE_GAIN_CVBS_LUMA_LSB	(0x50)
+#define REG_AFE_FINE_GAIN_CVBS_LUMA_MSB	(0x51)
+
+/* 0x52 - 0x68 Reserved */
+
+#define REG_FBIT_VBIT_CONTROL1		(0x69)
+
+/* 0x6A - 0x6B Reserved */
+
+#define REG_BACKEND_AGC_CONTROL		(0x6C)
+
+/* 0x6D - 0x6E Reserved */
+
+#define REG_AGC_DECREMENT_SPEED_CONTROL	(0x6F)
+#define REG_ROM_VERSION			(0x70)
+
+/* 0x71 - 0x73 Reserved */
+
+#define REG_AGC_WHITE_PEAK_PROCESSING	(0x74)
+#define REG_FBIT_VBIT_CONTROL2		(0x75)
+#define REG_VCR_TRICK_MODE_CONTROL	(0x76)
+#define REG_HORIZONTAL_SHAKE_INCREMENT	(0x77)
+#define REG_AGC_INCREMENT_SPEED		(0x78)
+#define REG_AGC_INCREMENT_DELAY		(0x79)
+
+/* 0x7A - 0x7F Reserved */
+
+#define REG_CHIP_ID_MSB			(0x80)
+#define REG_CHIP_ID_LSB			(0x81)
+
+/* 0x82 Reserved */
+
+#define REG_CPLL_SPEED_CONTROL		(0x83)
+
+/* 0x84 - 0x96 Reserved */
+
+#define REG_STATUS_REQUEST		(0x97)
+
+/* 0x98 - 0x99 Reserved */
+
+#define REG_VERTICAL_LINE_COUNT_LSB	(0x9A)
+#define REG_VERTICAL_LINE_COUNT_MSB	(0x9B)
+
+/* 0x9C - 0x9D Reserved */
+
+#define REG_AGC_DECREMENT_DELAY		(0x9E)
+
+/* 0x9F - 0xB0 Reserved */
+
+#define REG_VDP_TTX_FILTER_1_MASK1	(0xB1)
+#define REG_VDP_TTX_FILTER_1_MASK2	(0xB2)
+#define REG_VDP_TTX_FILTER_1_MASK3	(0xB3)
+#define REG_VDP_TTX_FILTER_1_MASK4	(0xB4)
+#define REG_VDP_TTX_FILTER_1_MASK5	(0xB5)
+#define REG_VDP_TTX_FILTER_2_MASK1	(0xB6)
+#define REG_VDP_TTX_FILTER_2_MASK2	(0xB7)
+#define REG_VDP_TTX_FILTER_2_MASK3	(0xB8)
+#define REG_VDP_TTX_FILTER_2_MASK4	(0xB9)
+#define REG_VDP_TTX_FILTER_2_MASK5	(0xBA)
+#define REG_VDP_TTX_FILTER_CONTROL	(0xBB)
+#define REG_VDP_FIFO_WORD_COUNT		(0xBC)
+#define REG_VDP_FIFO_INTERRUPT_THRLD	(0xBD)
+
+/* 0xBE Reserved */
+
+#define REG_VDP_FIFO_RESET		(0xBF)
+#define REG_VDP_FIFO_OUTPUT_CONTROL	(0xC0)
+#define REG_VDP_LINE_NUMBER_INTERRUPT	(0xC1)
+#define REG_VDP_PIXEL_ALIGNMENT_LSB	(0xC2)
+#define REG_VDP_PIXEL_ALIGNMENT_MSB	(0xC3)
+
+/* 0xC4 - 0xD5 Reserved */
+
+#define REG_VDP_LINE_START		(0xD6)
+#define REG_VDP_LINE_STOP		(0xD7)
+#define REG_VDP_GLOBAL_LINE_MODE	(0xD8)
+#define REG_VDP_FULL_FIELD_ENABLE	(0xD9)
+#define REG_VDP_FULL_FIELD_MODE		(0xDA)
+
+/* 0xDB - 0xDF Reserved */
+
+#define REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR	(0xE0)
+#define REG_VBUS_DATA_ACCESS_VBUS_ADDR_INCR	(0xE1)
+#define REG_FIFO_READ_DATA			(0xE2)
+
+/* 0xE3 - 0xE7 Reserved */
+
+#define REG_VBUS_ADDRESS_ACCESS1	(0xE8)
+#define REG_VBUS_ADDRESS_ACCESS2	(0xE9)
+#define REG_VBUS_ADDRESS_ACCESS3	(0xEA)
+
+/* 0xEB - 0xEF Reserved */
+
+#define REG_INTERRUPT_RAW_STATUS0	(0xF0)
+#define REG_INTERRUPT_RAW_STATUS1	(0xF1)
+#define REG_INTERRUPT_STATUS0		(0xF2)
+#define REG_INTERRUPT_STATUS1		(0xF3)
+#define REG_INTERRUPT_MASK0		(0xF4)
+#define REG_INTERRUPT_MASK1		(0xF5)
+#define REG_INTERRUPT_CLEAR0		(0xF6)
+#define REG_INTERRUPT_CLEAR1		(0xF7)
+
+/* 0xF8 - 0xFF Reserved */
+
+/*
+ * Mask and bit definitions of TVP5146/47 registers
+ */
+/* The ID values we are looking for */
+#define TVP514X_CHIP_ID_MSB		(0x51)
+#define TVP5146_CHIP_ID_LSB		(0x46)
+#define TVP5147_CHIP_ID_LSB		(0x47)
+
+#define VIDEO_STD_MASK			(0x07)
+#define VIDEO_STD_AUTO_SWITCH_BIT	(0x00)
+#define VIDEO_STD_NTSC_MJ_BIT		(0x01)
+#define VIDEO_STD_PAL_BDGHIN_BIT	(0x02)
+#define VIDEO_STD_PAL_M_BIT		(0x03)
+#define VIDEO_STD_PAL_COMBINATION_N_BIT	(0x04)
+#define VIDEO_STD_NTSC_4_43_BIT		(0x05)
+#define VIDEO_STD_SECAM_BIT		(0x06)
+#define VIDEO_STD_PAL_60_BIT		(0x07)
+
+/*
+ * Status bit
+ */
+#define STATUS_TV_VCR_BIT		(1<<0)
+#define STATUS_HORZ_SYNC_LOCK_BIT	(1<<1)
+#define STATUS_VIRT_SYNC_LOCK_BIT	(1<<2)
+#define STATUS_CLR_SUBCAR_LOCK_BIT	(1<<3)
+#define STATUS_LOST_LOCK_DETECT_BIT	(1<<4)
+#define STATUS_FEILD_RATE_BIT		(1<<5)
+#define STATUS_LINE_ALTERNATING_BIT	(1<<6)
+#define STATUS_PEAK_WHITE_DETECT_BIT	(1<<7)
+
+/* Tokens for register write */
+#define TOK_WRITE                       (0)     /* token for write operation */
+#define TOK_TERM                        (1)     /* terminating token */
+#define TOK_DELAY                       (2)     /* delay token for reg list */
+#define TOK_SKIP                        (3)     /* token to skip a register */
+/**
+ * struct tvp514x_reg - Structure for TVP5146/47 register initialization values
+ * @token - Token: TOK_WRITE, TOK_TERM etc..
+ * @reg - Register offset
+ * @val - Register Value for TOK_WRITE or delay in ms for TOK_DELAY
+ */
+struct tvp514x_reg {
+	u8 token;
+	u8 reg;
+	u32 val;
+};
+
+#endif				/* ifndef _TVP514X_REGS_H */
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
new file mode 100644
index 0000000..a751b6c
--- /dev/null
+++ b/drivers/media/i2c/tvp5150.c
@@ -0,0 +1,1274 @@
+/*
+ * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder driver
+ *
+ * Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <media/v4l2-device.h>
+#include <media/tvp5150.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+#include "tvp5150_reg.h"
+
+#define TVP5150_H_MAX		720
+#define TVP5150_V_MAX_525_60	480
+#define TVP5150_V_MAX_OTHERS	576
+#define TVP5150_MAX_CROP_LEFT	511
+#define TVP5150_MAX_CROP_TOP	127
+#define TVP5150_CROP_SHIFT	2
+
+MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
+MODULE_LICENSE("GPL");
+
+
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+struct tvp5150 {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	struct v4l2_rect rect;
+
+	v4l2_std_id norm;	/* Current set standard */
+	u32 input;
+	u32 output;
+	int enable;
+};
+
+static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct tvp5150, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct tvp5150, hdl)->sd;
+}
+
+static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
+{
+	struct i2c_client *c = v4l2_get_subdevdata(sd);
+	unsigned char buffer[1];
+	int rc;
+
+	buffer[0] = addr;
+
+	rc = i2c_master_send(c, buffer, 1);
+	if (rc < 0) {
+		v4l2_err(sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
+		return rc;
+	}
+
+	msleep(10);
+
+	rc = i2c_master_recv(c, buffer, 1);
+	if (rc < 0) {
+		v4l2_err(sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
+		return rc;
+	}
+
+	v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]);
+
+	return (buffer[0]);
+}
+
+static inline void tvp5150_write(struct v4l2_subdev *sd, unsigned char addr,
+				 unsigned char value)
+{
+	struct i2c_client *c = v4l2_get_subdevdata(sd);
+	unsigned char buffer[2];
+	int rc;
+
+	buffer[0] = addr;
+	buffer[1] = value;
+	v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
+	if (2 != (rc = i2c_master_send(c, buffer, 2)))
+		v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 2)\n", rc);
+}
+
+static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init,
+				const u8 end, int max_line)
+{
+	int i = 0;
+
+	while (init != (u8)(end + 1)) {
+		if ((i % max_line) == 0) {
+			if (i > 0)
+				printk("\n");
+			printk("tvp5150: %s reg 0x%02x = ", s, init);
+		}
+		printk("%02x ", tvp5150_read(sd, init));
+
+		init++;
+		i++;
+	}
+	printk("\n");
+}
+
+static int tvp5150_log_status(struct v4l2_subdev *sd)
+{
+	printk("tvp5150: Video input source selection #1 = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_VD_IN_SRC_SEL_1));
+	printk("tvp5150: Analog channel controls = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_ANAL_CHL_CTL));
+	printk("tvp5150: Operation mode controls = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_OP_MODE_CTL));
+	printk("tvp5150: Miscellaneous controls = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_MISC_CTL));
+	printk("tvp5150: Autoswitch mask= 0x%02x\n",
+			tvp5150_read(sd, TVP5150_AUTOSW_MSK));
+	printk("tvp5150: Color killer threshold control = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_COLOR_KIL_THSH_CTL));
+	printk("tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n",
+			tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_1),
+			tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_2),
+			tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_3));
+	printk("tvp5150: Brightness control = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_BRIGHT_CTL));
+	printk("tvp5150: Color saturation control = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_SATURATION_CTL));
+	printk("tvp5150: Hue control = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_HUE_CTL));
+	printk("tvp5150: Contrast control = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_CONTRAST_CTL));
+	printk("tvp5150: Outputs and data rates select = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_DATA_RATE_SEL));
+	printk("tvp5150: Configuration shared pins = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_CONF_SHARED_PIN));
+	printk("tvp5150: Active video cropping start = 0x%02x%02x\n",
+			tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_MSB),
+			tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_LSB));
+	printk("tvp5150: Active video cropping stop  = 0x%02x%02x\n",
+			tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_MSB),
+			tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_LSB));
+	printk("tvp5150: Genlock/RTC = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_GENLOCK));
+	printk("tvp5150: Horizontal sync start = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_HORIZ_SYNC_START));
+	printk("tvp5150: Vertical blanking start = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_VERT_BLANKING_START));
+	printk("tvp5150: Vertical blanking stop = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_VERT_BLANKING_STOP));
+	printk("tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n",
+			tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_1),
+			tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_2));
+	printk("tvp5150: Interrupt reset register B = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_INT_RESET_REG_B));
+	printk("tvp5150: Interrupt enable register B = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_INT_ENABLE_REG_B));
+	printk("tvp5150: Interrupt configuration register B = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_INTT_CONFIG_REG_B));
+	printk("tvp5150: Video standard = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_VIDEO_STD));
+	printk("tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n",
+			tvp5150_read(sd, TVP5150_CB_GAIN_FACT),
+			tvp5150_read(sd, TVP5150_CR_GAIN_FACTOR));
+	printk("tvp5150: Macrovision on counter = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_MACROVISION_ON_CTR));
+	printk("tvp5150: Macrovision off counter = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_MACROVISION_OFF_CTR));
+	printk("tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n",
+			(tvp5150_read(sd, TVP5150_REV_SELECT) & 1) ? 3 : 4);
+	printk("tvp5150: Device ID = %02x%02x\n",
+			tvp5150_read(sd, TVP5150_MSB_DEV_ID),
+			tvp5150_read(sd, TVP5150_LSB_DEV_ID));
+	printk("tvp5150: ROM version = (hex) %02x.%02x\n",
+			tvp5150_read(sd, TVP5150_ROM_MAJOR_VER),
+			tvp5150_read(sd, TVP5150_ROM_MINOR_VER));
+	printk("tvp5150: Vertical line count = 0x%02x%02x\n",
+			tvp5150_read(sd, TVP5150_VERT_LN_COUNT_MSB),
+			tvp5150_read(sd, TVP5150_VERT_LN_COUNT_LSB));
+	printk("tvp5150: Interrupt status register B = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_INT_STATUS_REG_B));
+	printk("tvp5150: Interrupt active register B = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_INT_ACTIVE_REG_B));
+	printk("tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n",
+			tvp5150_read(sd, TVP5150_STATUS_REG_1),
+			tvp5150_read(sd, TVP5150_STATUS_REG_2),
+			tvp5150_read(sd, TVP5150_STATUS_REG_3),
+			tvp5150_read(sd, TVP5150_STATUS_REG_4),
+			tvp5150_read(sd, TVP5150_STATUS_REG_5));
+
+	dump_reg_range(sd, "Teletext filter 1",   TVP5150_TELETEXT_FIL1_INI,
+			TVP5150_TELETEXT_FIL1_END, 8);
+	dump_reg_range(sd, "Teletext filter 2",   TVP5150_TELETEXT_FIL2_INI,
+			TVP5150_TELETEXT_FIL2_END, 8);
+
+	printk("tvp5150: Teletext filter enable = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_TELETEXT_FIL_ENA));
+	printk("tvp5150: Interrupt status register A = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_INT_STATUS_REG_A));
+	printk("tvp5150: Interrupt enable register A = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_INT_ENABLE_REG_A));
+	printk("tvp5150: Interrupt configuration = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_INT_CONF));
+	printk("tvp5150: VDP status register = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_VDP_STATUS_REG));
+	printk("tvp5150: FIFO word count = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_FIFO_WORD_COUNT));
+	printk("tvp5150: FIFO interrupt threshold = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_FIFO_INT_THRESHOLD));
+	printk("tvp5150: FIFO reset = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_FIFO_RESET));
+	printk("tvp5150: Line number interrupt = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_LINE_NUMBER_INT));
+	printk("tvp5150: Pixel alignment register = 0x%02x%02x\n",
+			tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_HIGH),
+			tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_LOW));
+	printk("tvp5150: FIFO output control = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_FIFO_OUT_CTRL));
+	printk("tvp5150: Full field enable = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_FULL_FIELD_ENA));
+	printk("tvp5150: Full field mode register = 0x%02x\n",
+			tvp5150_read(sd, TVP5150_FULL_FIELD_MODE_REG));
+
+	dump_reg_range(sd, "CC   data",   TVP5150_CC_DATA_INI,
+			TVP5150_CC_DATA_END, 8);
+
+	dump_reg_range(sd, "WSS  data",   TVP5150_WSS_DATA_INI,
+			TVP5150_WSS_DATA_END, 8);
+
+	dump_reg_range(sd, "VPS  data",   TVP5150_VPS_DATA_INI,
+			TVP5150_VPS_DATA_END, 8);
+
+	dump_reg_range(sd, "VITC data",   TVP5150_VITC_DATA_INI,
+			TVP5150_VITC_DATA_END, 10);
+
+	dump_reg_range(sd, "Line mode",   TVP5150_LINE_MODE_INI,
+			TVP5150_LINE_MODE_END, 8);
+	return 0;
+}
+
+/****************************************************************************
+			Basic functions
+ ****************************************************************************/
+
+static inline void tvp5150_selmux(struct v4l2_subdev *sd)
+{
+	int opmode = 0;
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	int input = 0;
+	int val;
+
+	if ((decoder->output & TVP5150_BLACK_SCREEN) || !decoder->enable)
+		input = 8;
+
+	switch (decoder->input) {
+	case TVP5150_COMPOSITE1:
+		input |= 2;
+		/* fall through */
+	case TVP5150_COMPOSITE0:
+		break;
+	case TVP5150_SVIDEO:
+	default:
+		input |= 1;
+		break;
+	}
+
+	v4l2_dbg(1, debug, sd, "Selecting video route: route input=%i, output=%i "
+			"=> tvp5150 input=%i, opmode=%i\n",
+			decoder->input, decoder->output,
+			input, opmode);
+
+	tvp5150_write(sd, TVP5150_OP_MODE_CTL, opmode);
+	tvp5150_write(sd, TVP5150_VD_IN_SRC_SEL_1, input);
+
+	/* Svideo should enable YCrCb output and disable GPCL output
+	 * For Composite and TV, it should be the reverse
+	 */
+	val = tvp5150_read(sd, TVP5150_MISC_CTL);
+	if (val < 0) {
+		v4l2_err(sd, "%s: failed with error = %d\n", __func__, val);
+		return;
+	}
+
+	if (decoder->input == TVP5150_SVIDEO)
+		val = (val & ~0x40) | 0x10;
+	else
+		val = (val & ~0x10) | 0x40;
+	tvp5150_write(sd, TVP5150_MISC_CTL, val);
+};
+
+struct i2c_reg_value {
+	unsigned char reg;
+	unsigned char value;
+};
+
+/* Default values as sugested at TVP5150AM1 datasheet */
+static const struct i2c_reg_value tvp5150_init_default[] = {
+	{ /* 0x00 */
+		TVP5150_VD_IN_SRC_SEL_1,0x00
+	},
+	{ /* 0x01 */
+		TVP5150_ANAL_CHL_CTL,0x15
+	},
+	{ /* 0x02 */
+		TVP5150_OP_MODE_CTL,0x00
+	},
+	{ /* 0x03 */
+		TVP5150_MISC_CTL,0x01
+	},
+	{ /* 0x06 */
+		TVP5150_COLOR_KIL_THSH_CTL,0x10
+	},
+	{ /* 0x07 */
+		TVP5150_LUMA_PROC_CTL_1,0x60
+	},
+	{ /* 0x08 */
+		TVP5150_LUMA_PROC_CTL_2,0x00
+	},
+	{ /* 0x09 */
+		TVP5150_BRIGHT_CTL,0x80
+	},
+	{ /* 0x0a */
+		TVP5150_SATURATION_CTL,0x80
+	},
+	{ /* 0x0b */
+		TVP5150_HUE_CTL,0x00
+	},
+	{ /* 0x0c */
+		TVP5150_CONTRAST_CTL,0x80
+	},
+	{ /* 0x0d */
+		TVP5150_DATA_RATE_SEL,0x47
+	},
+	{ /* 0x0e */
+		TVP5150_LUMA_PROC_CTL_3,0x00
+	},
+	{ /* 0x0f */
+		TVP5150_CONF_SHARED_PIN,0x08
+	},
+	{ /* 0x11 */
+		TVP5150_ACT_VD_CROP_ST_MSB,0x00
+	},
+	{ /* 0x12 */
+		TVP5150_ACT_VD_CROP_ST_LSB,0x00
+	},
+	{ /* 0x13 */
+		TVP5150_ACT_VD_CROP_STP_MSB,0x00
+	},
+	{ /* 0x14 */
+		TVP5150_ACT_VD_CROP_STP_LSB,0x00
+	},
+	{ /* 0x15 */
+		TVP5150_GENLOCK,0x01
+	},
+	{ /* 0x16 */
+		TVP5150_HORIZ_SYNC_START,0x80
+	},
+	{ /* 0x18 */
+		TVP5150_VERT_BLANKING_START,0x00
+	},
+	{ /* 0x19 */
+		TVP5150_VERT_BLANKING_STOP,0x00
+	},
+	{ /* 0x1a */
+		TVP5150_CHROMA_PROC_CTL_1,0x0c
+	},
+	{ /* 0x1b */
+		TVP5150_CHROMA_PROC_CTL_2,0x14
+	},
+	{ /* 0x1c */
+		TVP5150_INT_RESET_REG_B,0x00
+	},
+	{ /* 0x1d */
+		TVP5150_INT_ENABLE_REG_B,0x00
+	},
+	{ /* 0x1e */
+		TVP5150_INTT_CONFIG_REG_B,0x00
+	},
+	{ /* 0x28 */
+		TVP5150_VIDEO_STD,0x00
+	},
+	{ /* 0x2e */
+		TVP5150_MACROVISION_ON_CTR,0x0f
+	},
+	{ /* 0x2f */
+		TVP5150_MACROVISION_OFF_CTR,0x01
+	},
+	{ /* 0xbb */
+		TVP5150_TELETEXT_FIL_ENA,0x00
+	},
+	{ /* 0xc0 */
+		TVP5150_INT_STATUS_REG_A,0x00
+	},
+	{ /* 0xc1 */
+		TVP5150_INT_ENABLE_REG_A,0x00
+	},
+	{ /* 0xc2 */
+		TVP5150_INT_CONF,0x04
+	},
+	{ /* 0xc8 */
+		TVP5150_FIFO_INT_THRESHOLD,0x80
+	},
+	{ /* 0xc9 */
+		TVP5150_FIFO_RESET,0x00
+	},
+	{ /* 0xca */
+		TVP5150_LINE_NUMBER_INT,0x00
+	},
+	{ /* 0xcb */
+		TVP5150_PIX_ALIGN_REG_LOW,0x4e
+	},
+	{ /* 0xcc */
+		TVP5150_PIX_ALIGN_REG_HIGH,0x00
+	},
+	{ /* 0xcd */
+		TVP5150_FIFO_OUT_CTRL,0x01
+	},
+	{ /* 0xcf */
+		TVP5150_FULL_FIELD_ENA,0x00
+	},
+	{ /* 0xd0 */
+		TVP5150_LINE_MODE_INI,0x00
+	},
+	{ /* 0xfc */
+		TVP5150_FULL_FIELD_MODE_REG,0x7f
+	},
+	{ /* end of data */
+		0xff,0xff
+	}
+};
+
+/* Default values as sugested at TVP5150AM1 datasheet */
+static const struct i2c_reg_value tvp5150_init_enable[] = {
+	{
+		TVP5150_CONF_SHARED_PIN, 2
+	},{	/* Automatic offset and AGC enabled */
+		TVP5150_ANAL_CHL_CTL, 0x15
+	},{	/* Activate YCrCb output 0x9 or 0xd ? */
+		TVP5150_MISC_CTL, 0x6f
+	},{	/* Activates video std autodetection for all standards */
+		TVP5150_AUTOSW_MSK, 0x0
+	},{	/* Default format: 0x47. For 4:2:2: 0x40 */
+		TVP5150_DATA_RATE_SEL, 0x47
+	},{
+		TVP5150_CHROMA_PROC_CTL_1, 0x0c
+	},{
+		TVP5150_CHROMA_PROC_CTL_2, 0x54
+	},{	/* Non documented, but initialized on WinTV USB2 */
+		0x27, 0x20
+	},{
+		0xff,0xff
+	}
+};
+
+struct tvp5150_vbi_type {
+	unsigned int vbi_type;
+	unsigned int ini_line;
+	unsigned int end_line;
+	unsigned int by_field :1;
+};
+
+struct i2c_vbi_ram_value {
+	u16 reg;
+	struct tvp5150_vbi_type type;
+	unsigned char values[16];
+};
+
+/* This struct have the values for each supported VBI Standard
+ * by
+ tvp5150_vbi_types should follow the same order as vbi_ram_default
+ * value 0 means rom position 0x10, value 1 means rom position 0x30
+ * and so on. There are 16 possible locations from 0 to 15.
+ */
+
+static struct i2c_vbi_ram_value vbi_ram_default[] =
+{
+	/* FIXME: Current api doesn't handle all VBI types, those not
+	   yet supported are placed under #if 0 */
+#if 0
+	{0x010, /* Teletext, SECAM, WST System A */
+		{V4L2_SLICED_TELETEXT_SECAM,6,23,1},
+		{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26,
+		  0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 }
+	},
+#endif
+	{0x030, /* Teletext, PAL, WST System B */
+		{V4L2_SLICED_TELETEXT_B,6,22,1},
+		{ 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b,
+		  0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 }
+	},
+#if 0
+	{0x050, /* Teletext, PAL, WST System C */
+		{V4L2_SLICED_TELETEXT_PAL_C,6,22,1},
+		{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
+		  0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
+	},
+	{0x070, /* Teletext, NTSC, WST System B */
+		{V4L2_SLICED_TELETEXT_NTSC_B,10,21,1},
+		{ 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23,
+		  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
+	},
+	{0x090, /* Tetetext, NTSC NABTS System C */
+		{V4L2_SLICED_TELETEXT_NTSC_C,10,21,1},
+		{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
+		  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 }
+	},
+	{0x0b0, /* Teletext, NTSC-J, NABTS System D */
+		{V4L2_SLICED_TELETEXT_NTSC_D,10,21,1},
+		{ 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23,
+		  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
+	},
+	{0x0d0, /* Closed Caption, PAL/SECAM */
+		{V4L2_SLICED_CAPTION_625,22,22,1},
+		{ 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
+		  0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
+	},
+#endif
+	{0x0f0, /* Closed Caption, NTSC */
+		{V4L2_SLICED_CAPTION_525,21,21,1},
+		{ 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
+		  0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
+	},
+	{0x110, /* Wide Screen Signal, PAL/SECAM */
+		{V4L2_SLICED_WSS_625,23,23,1},
+		{ 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42,
+		  0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 }
+	},
+#if 0
+	{0x130, /* Wide Screen Signal, NTSC C */
+		{V4L2_SLICED_WSS_525,20,20,1},
+		{ 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43,
+		  0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 }
+	},
+	{0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */
+		{V4l2_SLICED_VITC_625,6,22,0},
+		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
+		  0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
+	},
+	{0x170, /* Vertical Interval Timecode (VITC), NTSC */
+		{V4l2_SLICED_VITC_525,10,20,0},
+		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
+		  0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
+	},
+#endif
+	{0x190, /* Video Program System (VPS), PAL */
+		{V4L2_SLICED_VPS,16,16,0},
+		{ 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d,
+		  0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 }
+	},
+	/* 0x1d0 User programmable */
+
+	/* End of struct */
+	{ (u16)-1 }
+};
+
+static int tvp5150_write_inittab(struct v4l2_subdev *sd,
+				const struct i2c_reg_value *regs)
+{
+	while (regs->reg != 0xff) {
+		tvp5150_write(sd, regs->reg, regs->value);
+		regs++;
+	}
+	return 0;
+}
+
+static int tvp5150_vdp_init(struct v4l2_subdev *sd,
+				const struct i2c_vbi_ram_value *regs)
+{
+	unsigned int i;
+
+	/* Disable Full Field */
+	tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0);
+
+	/* Before programming, Line mode should be at 0xff */
+	for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++)
+		tvp5150_write(sd, i, 0xff);
+
+	/* Load Ram Table */
+	while (regs->reg != (u16)-1) {
+		tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8);
+		tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_LOW, regs->reg);
+
+		for (i = 0; i < 16; i++)
+			tvp5150_write(sd, TVP5150_VDP_CONF_RAM_DATA, regs->values[i]);
+
+		regs++;
+	}
+	return 0;
+}
+
+/* Fills VBI capabilities based on i2c_vbi_ram_value struct */
+static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd,
+				struct v4l2_sliced_vbi_cap *cap)
+{
+	const struct i2c_vbi_ram_value *regs = vbi_ram_default;
+	int line;
+
+	v4l2_dbg(1, debug, sd, "g_sliced_vbi_cap\n");
+	memset(cap, 0, sizeof *cap);
+
+	while (regs->reg != (u16)-1 ) {
+		for (line=regs->type.ini_line;line<=regs->type.end_line;line++) {
+			cap->service_lines[0][line] |= regs->type.vbi_type;
+		}
+		cap->service_set |= regs->type.vbi_type;
+
+		regs++;
+	}
+	return 0;
+}
+
+/* Set vbi processing
+ * type - one of tvp5150_vbi_types
+ * line - line to gather data
+ * fields: bit 0 field1, bit 1, field2
+ * flags (default=0xf0) is a bitmask, were set means:
+ *	bit 7: enable filtering null bytes on CC
+ *	bit 6: send data also to FIFO
+ *	bit 5: don't allow data with errors on FIFO
+ *	bit 4: enable ECC when possible
+ * pix_align = pix alignment:
+ *	LSB = field1
+ *	MSB = field2
+ */
+static int tvp5150_set_vbi(struct v4l2_subdev *sd,
+			const struct i2c_vbi_ram_value *regs,
+			unsigned int type,u8 flags, int line,
+			const int fields)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	v4l2_std_id std = decoder->norm;
+	u8 reg;
+	int pos=0;
+
+	if (std == V4L2_STD_ALL) {
+		v4l2_err(sd, "VBI can't be configured without knowing number of lines\n");
+		return 0;
+	} else if (std & V4L2_STD_625_50) {
+		/* Don't follow NTSC Line number convension */
+		line += 3;
+	}
+
+	if (line<6||line>27)
+		return 0;
+
+	while (regs->reg != (u16)-1 ) {
+		if ((type & regs->type.vbi_type) &&
+		    (line>=regs->type.ini_line) &&
+		    (line<=regs->type.end_line)) {
+			type=regs->type.vbi_type;
+			break;
+		}
+
+		regs++;
+		pos++;
+	}
+	if (regs->reg == (u16)-1)
+		return 0;
+
+	type=pos | (flags & 0xf0);
+	reg=((line-6)<<1)+TVP5150_LINE_MODE_INI;
+
+	if (fields&1) {
+		tvp5150_write(sd, reg, type);
+	}
+
+	if (fields&2) {
+		tvp5150_write(sd, reg+1, type);
+	}
+
+	return type;
+}
+
+static int tvp5150_get_vbi(struct v4l2_subdev *sd,
+			const struct i2c_vbi_ram_value *regs, int line)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	v4l2_std_id std = decoder->norm;
+	u8 reg;
+	int pos, type = 0;
+	int i, ret = 0;
+
+	if (std == V4L2_STD_ALL) {
+		v4l2_err(sd, "VBI can't be configured without knowing number of lines\n");
+		return 0;
+	} else if (std & V4L2_STD_625_50) {
+		/* Don't follow NTSC Line number convension */
+		line += 3;
+	}
+
+	if (line < 6 || line > 27)
+		return 0;
+
+	reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI;
+
+	for (i = 0; i <= 1; i++) {
+		ret = tvp5150_read(sd, reg + i);
+		if (ret < 0) {
+			v4l2_err(sd, "%s: failed with error = %d\n",
+				 __func__, ret);
+			return 0;
+		}
+		pos = ret & 0x0f;
+		if (pos < 0x0f)
+			type |= regs[pos].type.vbi_type;
+	}
+
+	return type;
+}
+
+static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	int fmt = 0;
+
+	decoder->norm = std;
+
+	/* First tests should be against specific std */
+
+	if (std == V4L2_STD_ALL) {
+		fmt = VIDEO_STD_AUTO_SWITCH_BIT;	/* Autodetect mode */
+	} else if (std & V4L2_STD_NTSC_443) {
+		fmt = VIDEO_STD_NTSC_4_43_BIT;
+	} else if (std & V4L2_STD_PAL_M) {
+		fmt = VIDEO_STD_PAL_M_BIT;
+	} else if (std & (V4L2_STD_PAL_N | V4L2_STD_PAL_Nc)) {
+		fmt = VIDEO_STD_PAL_COMBINATION_N_BIT;
+	} else {
+		/* Then, test against generic ones */
+		if (std & V4L2_STD_NTSC)
+			fmt = VIDEO_STD_NTSC_MJ_BIT;
+		else if (std & V4L2_STD_PAL)
+			fmt = VIDEO_STD_PAL_BDGHIN_BIT;
+		else if (std & V4L2_STD_SECAM)
+			fmt = VIDEO_STD_SECAM_BIT;
+	}
+
+	v4l2_dbg(1, debug, sd, "Set video std register to %d.\n", fmt);
+	tvp5150_write(sd, TVP5150_VIDEO_STD, fmt);
+	return 0;
+}
+
+static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+
+	if (decoder->norm == std)
+		return 0;
+
+	/* Change cropping height limits */
+	if (std & V4L2_STD_525_60)
+		decoder->rect.height = TVP5150_V_MAX_525_60;
+	else
+		decoder->rect.height = TVP5150_V_MAX_OTHERS;
+
+
+	return tvp5150_set_std(sd, std);
+}
+
+static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+
+	/* Initializes TVP5150 to its default values */
+	tvp5150_write_inittab(sd, tvp5150_init_default);
+
+	/* Initializes VDP registers */
+	tvp5150_vdp_init(sd, vbi_ram_default);
+
+	/* Selects decoder input */
+	tvp5150_selmux(sd);
+
+	/* Initializes TVP5150 to stream enabled values */
+	tvp5150_write_inittab(sd, tvp5150_init_enable);
+
+	/* Initialize image preferences */
+	v4l2_ctrl_handler_setup(&decoder->hdl);
+
+	tvp5150_set_std(sd, decoder->norm);
+	return 0;
+};
+
+static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		tvp5150_write(sd, TVP5150_BRIGHT_CTL, ctrl->val);
+		return 0;
+	case V4L2_CID_CONTRAST:
+		tvp5150_write(sd, TVP5150_CONTRAST_CTL, ctrl->val);
+		return 0;
+	case V4L2_CID_SATURATION:
+		tvp5150_write(sd, TVP5150_SATURATION_CTL, ctrl->val);
+		return 0;
+	case V4L2_CID_HUE:
+		tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->val);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd)
+{
+	int val = tvp5150_read(sd, TVP5150_STATUS_REG_5);
+
+	switch (val & 0x0F) {
+	case 0x01:
+		return V4L2_STD_NTSC;
+	case 0x03:
+		return V4L2_STD_PAL;
+	case 0x05:
+		return V4L2_STD_PAL_M;
+	case 0x07:
+		return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc;
+	case 0x09:
+		return V4L2_STD_NTSC_443;
+	case 0xb:
+		return V4L2_STD_SECAM;
+	default:
+		return V4L2_STD_UNKNOWN;
+	}
+}
+
+static int tvp5150_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+						enum v4l2_mbus_pixelcode *code)
+{
+	if (index)
+		return -EINVAL;
+
+	*code = V4L2_MBUS_FMT_UYVY8_2X8;
+	return 0;
+}
+
+static int tvp5150_mbus_fmt(struct v4l2_subdev *sd,
+			    struct v4l2_mbus_framefmt *f)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+
+	if (f == NULL)
+		return -EINVAL;
+
+	tvp5150_reset(sd, 0);
+
+	f->width = decoder->rect.width;
+	f->height = decoder->rect.height;
+
+	f->code = V4L2_MBUS_FMT_UYVY8_2X8;
+	f->field = V4L2_FIELD_SEQ_TB;
+	f->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+	v4l2_dbg(1, debug, sd, "width = %d, height = %d\n", f->width,
+			f->height);
+	return 0;
+}
+
+static int tvp5150_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct v4l2_rect rect = a->c;
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	v4l2_std_id std;
+	int hmax;
+
+	v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n",
+		__func__, rect.left, rect.top, rect.width, rect.height);
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	/* tvp5150 has some special limits */
+	rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
+	rect.width = clamp(rect.width,
+			   TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
+			   TVP5150_H_MAX - rect.left);
+	rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
+
+	/* Calculate height based on current standard */
+	if (decoder->norm == V4L2_STD_ALL)
+		std = tvp5150_read_std(sd);
+	else
+		std = decoder->norm;
+
+	if (std & V4L2_STD_525_60)
+		hmax = TVP5150_V_MAX_525_60;
+	else
+		hmax = TVP5150_V_MAX_OTHERS;
+
+	rect.height = clamp(rect.height,
+			    hmax - TVP5150_MAX_CROP_TOP - rect.top,
+			    hmax - rect.top);
+
+	tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top);
+	tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP,
+		      rect.top + rect.height - hmax);
+	tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_MSB,
+		      rect.left >> TVP5150_CROP_SHIFT);
+	tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_LSB,
+		      rect.left | (1 << TVP5150_CROP_SHIFT));
+	tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_MSB,
+		      (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
+		      TVP5150_CROP_SHIFT);
+	tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_LSB,
+		      rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
+
+	decoder->rect = rect;
+
+	return 0;
+}
+
+static int tvp5150_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
+
+	a->c	= decoder->rect;
+	a->type	= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int tvp5150_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
+	v4l2_std_id std;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	a->bounds.left			= 0;
+	a->bounds.top			= 0;
+	a->bounds.width			= TVP5150_H_MAX;
+
+	/* Calculate height based on current standard */
+	if (decoder->norm == V4L2_STD_ALL)
+		std = tvp5150_read_std(sd);
+	else
+		std = decoder->norm;
+
+	if (std & V4L2_STD_525_60)
+		a->bounds.height = TVP5150_V_MAX_525_60;
+	else
+		a->bounds.height = TVP5150_V_MAX_OTHERS;
+
+	a->defrect			= a->bounds;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+/****************************************************************************
+			I2C Command
+ ****************************************************************************/
+
+static int tvp5150_s_routing(struct v4l2_subdev *sd,
+			     u32 input, u32 output, u32 config)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+
+	decoder->input = input;
+	decoder->output = output;
+	tvp5150_selmux(sd);
+	return 0;
+}
+
+static int tvp5150_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
+{
+	/* this is for capturing 36 raw vbi lines
+	   if there's a way to cut off the beginning 2 vbi lines
+	   with the tvp5150 then the vbi line count could be lowered
+	   to 17 lines/field again, although I couldn't find a register
+	   which could do that cropping */
+	if (fmt->sample_format == V4L2_PIX_FMT_GREY)
+		tvp5150_write(sd, TVP5150_LUMA_PROC_CTL_1, 0x70);
+	if (fmt->count[0] == 18 && fmt->count[1] == 18) {
+		tvp5150_write(sd, TVP5150_VERT_BLANKING_START, 0x00);
+		tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, 0x01);
+	}
+	return 0;
+}
+
+static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
+{
+	int i;
+
+	if (svbi->service_set != 0) {
+		for (i = 0; i <= 23; i++) {
+			svbi->service_lines[1][i] = 0;
+			svbi->service_lines[0][i] =
+				tvp5150_set_vbi(sd, vbi_ram_default,
+				       svbi->service_lines[0][i], 0xf0, i, 3);
+		}
+		/* Enables FIFO */
+		tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 1);
+	} else {
+		/* Disables FIFO*/
+		tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 0);
+
+		/* Disable Full Field */
+		tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0);
+
+		/* Disable Line modes */
+		for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++)
+			tvp5150_write(sd, i, 0xff);
+	}
+	return 0;
+}
+
+static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
+{
+	int i, mask = 0;
+
+	memset(svbi, 0, sizeof(*svbi));
+
+	for (i = 0; i <= 23; i++) {
+		svbi->service_lines[0][i] =
+			tvp5150_get_vbi(sd, vbi_ram_default, i);
+		mask |= svbi->service_lines[0][i];
+	}
+	svbi->service_set = mask;
+	return 0;
+}
+
+static int tvp5150_g_chip_ident(struct v4l2_subdev *sd,
+				struct v4l2_dbg_chip_ident *chip)
+{
+	int rev;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	rev = tvp5150_read(sd, TVP5150_ROM_MAJOR_VER) << 8 |
+	      tvp5150_read(sd, TVP5150_ROM_MINOR_VER);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVP5150,
+					  rev);
+}
+
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	int res;
+
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	res = tvp5150_read(sd, reg->reg & 0xff);
+	if (res < 0) {
+		v4l2_err(sd, "%s: failed with error = %d\n", __func__, res);
+		return res;
+	}
+
+	reg->val = res;
+	reg->size = 1;
+	return 0;
+}
+
+static int tvp5150_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff);
+	return 0;
+}
+#endif
+
+static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	int status = tvp5150_read(sd, 0x88);
+
+	vt->signal = ((status & 0x04) && (status & 0x02)) ? 0xffff : 0x0;
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
+	.s_ctrl = tvp5150_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
+	.log_status = tvp5150_log_status,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+	.s_std = tvp5150_s_std,
+	.reset = tvp5150_reset,
+	.g_chip_ident = tvp5150_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = tvp5150_g_register,
+	.s_register = tvp5150_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
+	.g_tuner = tvp5150_g_tuner,
+};
+
+static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
+	.s_routing = tvp5150_s_routing,
+	.enum_mbus_fmt = tvp5150_enum_mbus_fmt,
+	.s_mbus_fmt = tvp5150_mbus_fmt,
+	.try_mbus_fmt = tvp5150_mbus_fmt,
+	.g_mbus_fmt = tvp5150_mbus_fmt,
+	.s_crop = tvp5150_s_crop,
+	.g_crop = tvp5150_g_crop,
+	.cropcap = tvp5150_cropcap,
+};
+
+static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
+	.g_sliced_vbi_cap = tvp5150_g_sliced_vbi_cap,
+	.g_sliced_fmt = tvp5150_g_sliced_fmt,
+	.s_sliced_fmt = tvp5150_s_sliced_fmt,
+	.s_raw_fmt = tvp5150_s_raw_fmt,
+};
+
+static const struct v4l2_subdev_ops tvp5150_ops = {
+	.core = &tvp5150_core_ops,
+	.tuner = &tvp5150_tuner_ops,
+	.video = &tvp5150_video_ops,
+	.vbi = &tvp5150_vbi_ops,
+};
+
+
+/****************************************************************************
+			I2C Client & Driver
+ ****************************************************************************/
+
+static int tvp5150_probe(struct i2c_client *c,
+			 const struct i2c_device_id *id)
+{
+	struct tvp5150 *core;
+	struct v4l2_subdev *sd;
+	int tvp5150_id[4];
+	int i, res;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(c->adapter,
+	     I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+		return -EIO;
+
+	core = kzalloc(sizeof(struct tvp5150), GFP_KERNEL);
+	if (!core) {
+		return -ENOMEM;
+	}
+	sd = &core->sd;
+	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
+
+	/* 
+	 * Read consequent registers - TVP5150_MSB_DEV_ID, TVP5150_LSB_DEV_ID,
+	 * TVP5150_ROM_MAJOR_VER, TVP5150_ROM_MINOR_VER 
+	 */
+	for (i = 0; i < 4; i++) {
+		res = tvp5150_read(sd, TVP5150_MSB_DEV_ID + i);
+		if (res < 0)
+			goto free_core;
+		tvp5150_id[i] = res;
+	}
+
+	v4l_info(c, "chip found @ 0x%02x (%s)\n",
+		 c->addr << 1, c->adapter->name);
+
+	if (tvp5150_id[2] == 4 && tvp5150_id[3] == 0) { /* Is TVP5150AM1 */
+		v4l2_info(sd, "tvp%02x%02xam1 detected.\n",
+			  tvp5150_id[0], tvp5150_id[1]);
+
+		/* ITU-T BT.656.4 timing */
+		tvp5150_write(sd, TVP5150_REV_SELECT, 0);
+	} else {
+		/* Is TVP5150A */
+		if (tvp5150_id[2] == 3 || tvp5150_id[3] == 0x21) {
+			v4l2_info(sd, "tvp%02x%02xa detected.\n",
+				  tvp5150_id[2], tvp5150_id[3]);
+		} else {
+			v4l2_info(sd, "*** unknown tvp%02x%02x chip detected.\n",
+				  tvp5150_id[2], tvp5150_id[3]);
+			v4l2_info(sd, "*** Rom ver is %d.%d\n",
+				  tvp5150_id[2], tvp5150_id[3]);
+		}
+	}
+
+	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
+	core->input = TVP5150_COMPOSITE1;
+	core->enable = 1;
+
+	v4l2_ctrl_handler_init(&core->hdl, 4);
+	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
+			V4L2_CID_HUE, -128, 127, 1, 0);
+	sd->ctrl_handler = &core->hdl;
+	if (core->hdl.error) {
+		res = core->hdl.error;
+		v4l2_ctrl_handler_free(&core->hdl);
+		goto free_core;
+	}
+	v4l2_ctrl_handler_setup(&core->hdl);
+
+	/* Default is no cropping */
+	core->rect.top = 0;
+	if (tvp5150_read_std(sd) & V4L2_STD_525_60)
+		core->rect.height = TVP5150_V_MAX_525_60;
+	else
+		core->rect.height = TVP5150_V_MAX_OTHERS;
+	core->rect.left = 0;
+	core->rect.width = TVP5150_H_MAX;
+
+	if (debug > 1)
+		tvp5150_log_status(sd);
+	return 0;
+
+free_core:
+	kfree(core);
+	return res;
+}
+
+static int tvp5150_remove(struct i2c_client *c)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(c);
+	struct tvp5150 *decoder = to_tvp5150(sd);
+
+	v4l2_dbg(1, debug, sd,
+		"tvp5150.c: removing tvp5150 adapter on address 0x%x\n",
+		c->addr << 1);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&decoder->hdl);
+	kfree(to_tvp5150(sd));
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id tvp5150_id[] = {
+	{ "tvp5150", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tvp5150_id);
+
+static struct i2c_driver tvp5150_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "tvp5150",
+	},
+	.probe		= tvp5150_probe,
+	.remove		= tvp5150_remove,
+	.id_table	= tvp5150_id,
+};
+
+module_i2c_driver(tvp5150_driver);
diff --git a/drivers/media/i2c/tvp5150_reg.h b/drivers/media/i2c/tvp5150_reg.h
new file mode 100644
index 0000000..25a9949
--- /dev/null
+++ b/drivers/media/i2c/tvp5150_reg.h
@@ -0,0 +1,139 @@
+/*
+ * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder registers
+ *
+ * Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
+#define TVP5150_VD_IN_SRC_SEL_1      0x00 /* Video input source selection #1 */
+#define TVP5150_ANAL_CHL_CTL         0x01 /* Analog channel controls */
+#define TVP5150_OP_MODE_CTL          0x02 /* Operation mode controls */
+#define TVP5150_MISC_CTL             0x03 /* Miscellaneous controls */
+#define TVP5150_AUTOSW_MSK           0x04 /* Autoswitch mask: TVP5150A / TVP5150AM */
+
+/* Reserved 05h */
+
+#define TVP5150_COLOR_KIL_THSH_CTL   0x06 /* Color killer threshold control */
+#define TVP5150_LUMA_PROC_CTL_1      0x07 /* Luminance processing control #1 */
+#define TVP5150_LUMA_PROC_CTL_2      0x08 /* Luminance processing control #2 */
+#define TVP5150_BRIGHT_CTL           0x09 /* Brightness control */
+#define TVP5150_SATURATION_CTL       0x0a /* Color saturation control */
+#define TVP5150_HUE_CTL              0x0b /* Hue control */
+#define TVP5150_CONTRAST_CTL         0x0c /* Contrast control */
+#define TVP5150_DATA_RATE_SEL        0x0d /* Outputs and data rates select */
+#define TVP5150_LUMA_PROC_CTL_3      0x0e /* Luminance processing control #3 */
+#define TVP5150_CONF_SHARED_PIN      0x0f /* Configuration shared pins */
+
+/* Reserved 10h */
+
+#define TVP5150_ACT_VD_CROP_ST_MSB   0x11 /* Active video cropping start MSB */
+#define TVP5150_ACT_VD_CROP_ST_LSB   0x12 /* Active video cropping start LSB */
+#define TVP5150_ACT_VD_CROP_STP_MSB  0x13 /* Active video cropping stop MSB */
+#define TVP5150_ACT_VD_CROP_STP_LSB  0x14 /* Active video cropping stop LSB */
+#define TVP5150_GENLOCK              0x15 /* Genlock/RTC */
+#define TVP5150_HORIZ_SYNC_START     0x16 /* Horizontal sync start */
+
+/* Reserved 17h */
+
+#define TVP5150_VERT_BLANKING_START 0x18 /* Vertical blanking start */
+#define TVP5150_VERT_BLANKING_STOP  0x19 /* Vertical blanking stop */
+#define TVP5150_CHROMA_PROC_CTL_1   0x1a /* Chrominance processing control #1 */
+#define TVP5150_CHROMA_PROC_CTL_2   0x1b /* Chrominance processing control #2 */
+#define TVP5150_INT_RESET_REG_B     0x1c /* Interrupt reset register B */
+#define TVP5150_INT_ENABLE_REG_B    0x1d /* Interrupt enable register B */
+#define TVP5150_INTT_CONFIG_REG_B   0x1e /* Interrupt configuration register B */
+
+/* Reserved 1Fh-27h */
+
+#define VIDEO_STD_MASK			 (0x07 >> 1)
+#define TVP5150_VIDEO_STD                0x28 /* Video standard */
+#define VIDEO_STD_AUTO_SWITCH_BIT	 0x00
+#define VIDEO_STD_NTSC_MJ_BIT		 0x02
+#define VIDEO_STD_PAL_BDGHIN_BIT	 0x04
+#define VIDEO_STD_PAL_M_BIT		 0x06
+#define VIDEO_STD_PAL_COMBINATION_N_BIT	 0x08
+#define VIDEO_STD_NTSC_4_43_BIT		 0x0a
+#define VIDEO_STD_SECAM_BIT		 0x0c
+
+#define VIDEO_STD_NTSC_MJ_BIT_AS                 0x01
+#define VIDEO_STD_PAL_BDGHIN_BIT_AS              0x03
+#define VIDEO_STD_PAL_M_BIT_AS		         0x05
+#define VIDEO_STD_PAL_COMBINATION_N_BIT_AS	 0x07
+#define VIDEO_STD_NTSC_4_43_BIT_AS		 0x09
+#define VIDEO_STD_SECAM_BIT_AS		         0x0b
+
+/* Reserved 29h-2bh */
+
+#define TVP5150_CB_GAIN_FACT        0x2c /* Cb gain factor */
+#define TVP5150_CR_GAIN_FACTOR      0x2d /* Cr gain factor */
+#define TVP5150_MACROVISION_ON_CTR  0x2e /* Macrovision on counter */
+#define TVP5150_MACROVISION_OFF_CTR 0x2f /* Macrovision off counter */
+#define TVP5150_REV_SELECT          0x30 /* revision select (TVP5150AM1 only) */
+
+/* Reserved	31h-7Fh */
+
+#define TVP5150_MSB_DEV_ID          0x80 /* MSB of device ID */
+#define TVP5150_LSB_DEV_ID          0x81 /* LSB of device ID */
+#define TVP5150_ROM_MAJOR_VER       0x82 /* ROM major version */
+#define TVP5150_ROM_MINOR_VER       0x83 /* ROM minor version */
+#define TVP5150_VERT_LN_COUNT_MSB   0x84 /* Vertical line count MSB */
+#define TVP5150_VERT_LN_COUNT_LSB   0x85 /* Vertical line count LSB */
+#define TVP5150_INT_STATUS_REG_B    0x86 /* Interrupt status register B */
+#define TVP5150_INT_ACTIVE_REG_B    0x87 /* Interrupt active register B */
+#define TVP5150_STATUS_REG_1        0x88 /* Status register #1 */
+#define TVP5150_STATUS_REG_2        0x89 /* Status register #2 */
+#define TVP5150_STATUS_REG_3        0x8a /* Status register #3 */
+#define TVP5150_STATUS_REG_4        0x8b /* Status register #4 */
+#define TVP5150_STATUS_REG_5        0x8c /* Status register #5 */
+/* Reserved	8Dh-8Fh */
+ /* Closed caption data registers */
+#define TVP5150_CC_DATA_INI         0x90
+#define TVP5150_CC_DATA_END         0x93
+
+ /* WSS data registers */
+#define TVP5150_WSS_DATA_INI        0x94
+#define TVP5150_WSS_DATA_END        0x99
+
+/* VPS data registers */
+#define TVP5150_VPS_DATA_INI        0x9a
+#define TVP5150_VPS_DATA_END        0xa6
+
+/* VITC data registers */
+#define TVP5150_VITC_DATA_INI       0xa7
+#define TVP5150_VITC_DATA_END       0xaf
+
+#define TVP5150_VBI_FIFO_READ_DATA  0xb0 /* VBI FIFO read data */
+
+/* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL1_INI  0xb1
+#define TVP5150_TELETEXT_FIL1_END  0xb5
+
+/* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL2_INI  0xb6
+#define TVP5150_TELETEXT_FIL2_END  0xba
+
+#define TVP5150_TELETEXT_FIL_ENA    0xbb /* Teletext filter enable */
+/* Reserved	BCh-BFh */
+#define TVP5150_INT_STATUS_REG_A    0xc0 /* Interrupt status register A */
+#define TVP5150_INT_ENABLE_REG_A    0xc1 /* Interrupt enable register A */
+#define TVP5150_INT_CONF            0xc2 /* Interrupt configuration */
+#define TVP5150_VDP_CONF_RAM_DATA   0xc3 /* VDP configuration RAM data */
+#define TVP5150_CONF_RAM_ADDR_LOW   0xc4 /* Configuration RAM address low byte */
+#define TVP5150_CONF_RAM_ADDR_HIGH  0xc5 /* Configuration RAM address high byte */
+#define TVP5150_VDP_STATUS_REG      0xc6 /* VDP status register */
+#define TVP5150_FIFO_WORD_COUNT     0xc7 /* FIFO word count */
+#define TVP5150_FIFO_INT_THRESHOLD  0xc8 /* FIFO interrupt threshold */
+#define TVP5150_FIFO_RESET          0xc9 /* FIFO reset */
+#define TVP5150_LINE_NUMBER_INT     0xca /* Line number interrupt */
+#define TVP5150_PIX_ALIGN_REG_LOW   0xcb /* Pixel alignment register low byte */
+#define TVP5150_PIX_ALIGN_REG_HIGH  0xcc /* Pixel alignment register high byte */
+#define TVP5150_FIFO_OUT_CTRL       0xcd /* FIFO output control */
+/* Reserved	CEh */
+#define TVP5150_FULL_FIELD_ENA      0xcf /* Full field enable 1 */
+
+/* Line mode registers */
+#define TVP5150_LINE_MODE_INI       0xd0
+#define TVP5150_LINE_MODE_END       0xfb
+
+#define TVP5150_FULL_FIELD_MODE_REG 0xfc /* Full field mode register */
+/* Reserved	FDh-FFh */
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c
new file mode 100644
index 0000000..fb6a5b5
--- /dev/null
+++ b/drivers/media/i2c/tvp7002.c
@@ -0,0 +1,1145 @@
+/* Texas Instruments Triple 8-/10-BIT 165-/110-MSPS Video and Graphics
+ * Digitizer with Horizontal PLL registers
+ *
+ * Copyright (C) 2009 Texas Instruments Inc
+ * Author: Santiago Nunez-Corrales <santiago.nunez@ridgerun.com>
+ *
+ * This code is partially based upon the TVP5150 driver
+ * written by Mauro Carvalho Chehab (mchehab@infradead.org),
+ * the TVP514x driver written by Vaibhav Hiremath <hvaibhav@ti.com>
+ * and the TVP7002 driver in the TI LSP 2.10.00.14. Revisions by
+ * Muralidharan Karicheri and Snehaprabha Narnakaje (TI).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/tvp7002.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include "tvp7002_reg.h"
+
+MODULE_DESCRIPTION("TI TVP7002 Video and Graphics Digitizer driver");
+MODULE_AUTHOR("Santiago Nunez-Corrales <santiago.nunez@ridgerun.com>");
+MODULE_LICENSE("GPL");
+
+/* Module Name */
+#define TVP7002_MODULE_NAME	"tvp7002"
+
+/* I2C retry attempts */
+#define I2C_RETRY_COUNT		(5)
+
+/* End of registers */
+#define TVP7002_EOR		0x5c
+
+/* Read write definition for registers */
+#define TVP7002_READ		0
+#define TVP7002_WRITE		1
+#define TVP7002_RESERVED	2
+
+/* Interlaced vs progressive mask and shift */
+#define TVP7002_IP_SHIFT	5
+#define TVP7002_INPR_MASK	(0x01 << TVP7002_IP_SHIFT)
+
+/* Shift for CPL and LPF registers */
+#define TVP7002_CL_SHIFT	8
+#define TVP7002_CL_MASK		0x0f
+
+/* Debug functions */
+static bool debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+/* Structure for register values */
+struct i2c_reg_value {
+	u8 reg;
+	u8 value;
+	u8 type;
+};
+
+/*
+ * Register default values (according to tvp7002 datasheet)
+ * In the case of read-only registers, the value (0xff) is
+ * never written. R/W functionality is controlled by the
+ * writable bit in the register struct definition.
+ */
+static const struct i2c_reg_value tvp7002_init_default[] = {
+	{ TVP7002_CHIP_REV, 0xff, TVP7002_READ },
+	{ TVP7002_HPLL_FDBK_DIV_MSBS, 0x67, TVP7002_WRITE },
+	{ TVP7002_HPLL_FDBK_DIV_LSBS, 0x20, TVP7002_WRITE },
+	{ TVP7002_HPLL_CRTL, 0xa0, TVP7002_WRITE },
+	{ TVP7002_HPLL_PHASE_SEL, 0x80, TVP7002_WRITE },
+	{ TVP7002_CLAMP_START, 0x32, TVP7002_WRITE },
+	{ TVP7002_CLAMP_W, 0x20, TVP7002_WRITE },
+	{ TVP7002_HSYNC_OUT_W, 0x60, TVP7002_WRITE },
+	{ TVP7002_B_FINE_GAIN, 0x00, TVP7002_WRITE },
+	{ TVP7002_G_FINE_GAIN, 0x00, TVP7002_WRITE },
+	{ TVP7002_R_FINE_GAIN, 0x00, TVP7002_WRITE },
+	{ TVP7002_B_FINE_OFF_MSBS, 0x80, TVP7002_WRITE },
+	{ TVP7002_G_FINE_OFF_MSBS, 0x80, TVP7002_WRITE },
+	{ TVP7002_R_FINE_OFF_MSBS, 0x80, TVP7002_WRITE },
+	{ TVP7002_SYNC_CTL_1, 0x20, TVP7002_WRITE },
+	{ TVP7002_HPLL_AND_CLAMP_CTL, 0x2e, TVP7002_WRITE },
+	{ TVP7002_SYNC_ON_G_THRS, 0x5d, TVP7002_WRITE },
+	{ TVP7002_SYNC_SEPARATOR_THRS, 0x47, TVP7002_WRITE },
+	{ TVP7002_HPLL_PRE_COAST, 0x00, TVP7002_WRITE },
+	{ TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE },
+	{ TVP7002_SYNC_DETECT_STAT, 0xff, TVP7002_READ },
+	{ TVP7002_OUT_FORMATTER, 0x47, TVP7002_WRITE },
+	{ TVP7002_MISC_CTL_1, 0x01, TVP7002_WRITE },
+	{ TVP7002_MISC_CTL_2, 0x00, TVP7002_WRITE },
+	{ TVP7002_MISC_CTL_3, 0x01, TVP7002_WRITE },
+	{ TVP7002_IN_MUX_SEL_1, 0x00, TVP7002_WRITE },
+	{ TVP7002_IN_MUX_SEL_2, 0x67, TVP7002_WRITE },
+	{ TVP7002_B_AND_G_COARSE_GAIN, 0x77, TVP7002_WRITE },
+	{ TVP7002_R_COARSE_GAIN, 0x07, TVP7002_WRITE },
+	{ TVP7002_FINE_OFF_LSBS, 0x00, TVP7002_WRITE },
+	{ TVP7002_B_COARSE_OFF, 0x10, TVP7002_WRITE },
+	{ TVP7002_G_COARSE_OFF, 0x10, TVP7002_WRITE },
+	{ TVP7002_R_COARSE_OFF, 0x10, TVP7002_WRITE },
+	{ TVP7002_HSOUT_OUT_START, 0x08, TVP7002_WRITE },
+	{ TVP7002_MISC_CTL_4, 0x00, TVP7002_WRITE },
+	{ TVP7002_B_DGTL_ALC_OUT_LSBS, 0xff, TVP7002_READ },
+	{ TVP7002_G_DGTL_ALC_OUT_LSBS, 0xff, TVP7002_READ },
+	{ TVP7002_R_DGTL_ALC_OUT_LSBS, 0xff, TVP7002_READ },
+	{ TVP7002_AUTO_LVL_CTL_ENABLE, 0x80, TVP7002_WRITE },
+	{ TVP7002_DGTL_ALC_OUT_MSBS, 0xff, TVP7002_READ },
+	{ TVP7002_AUTO_LVL_CTL_FILTER, 0x53, TVP7002_WRITE },
+	{ 0x29, 0x08, TVP7002_RESERVED },
+	{ TVP7002_FINE_CLAMP_CTL, 0x07, TVP7002_WRITE },
+	/* PWR_CTL is controlled only by the probe and reset functions */
+	{ TVP7002_PWR_CTL, 0x00, TVP7002_RESERVED },
+	{ TVP7002_ADC_SETUP, 0x50, TVP7002_WRITE },
+	{ TVP7002_COARSE_CLAMP_CTL, 0x00, TVP7002_WRITE },
+	{ TVP7002_SOG_CLAMP, 0x80, TVP7002_WRITE },
+	{ TVP7002_RGB_COARSE_CLAMP_CTL, 0x8c, TVP7002_WRITE },
+	{ TVP7002_SOG_COARSE_CLAMP_CTL, 0x04, TVP7002_WRITE },
+	{ TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE },
+	{ 0x32, 0x18, TVP7002_RESERVED },
+	{ 0x33, 0x60, TVP7002_RESERVED },
+	{ TVP7002_MVIS_STRIPPER_W, 0xff, TVP7002_RESERVED },
+	{ TVP7002_VSYNC_ALGN, 0x10, TVP7002_WRITE },
+	{ TVP7002_SYNC_BYPASS, 0x00, TVP7002_WRITE },
+	{ TVP7002_L_FRAME_STAT_LSBS, 0xff, TVP7002_READ },
+	{ TVP7002_L_FRAME_STAT_MSBS, 0xff, TVP7002_READ },
+	{ TVP7002_CLK_L_STAT_LSBS, 0xff, TVP7002_READ },
+	{ TVP7002_CLK_L_STAT_MSBS, 0xff, TVP7002_READ },
+	{ TVP7002_HSYNC_W, 0xff, TVP7002_READ },
+	{ TVP7002_VSYNC_W, 0xff, TVP7002_READ },
+	{ TVP7002_L_LENGTH_TOL, 0x03, TVP7002_WRITE },
+	{ 0x3e, 0x60, TVP7002_RESERVED },
+	{ TVP7002_VIDEO_BWTH_CTL, 0x01, TVP7002_WRITE },
+	{ TVP7002_AVID_START_PIXEL_LSBS, 0x01, TVP7002_WRITE },
+	{ TVP7002_AVID_START_PIXEL_MSBS, 0x2c, TVP7002_WRITE },
+	{ TVP7002_AVID_STOP_PIXEL_LSBS, 0x06, TVP7002_WRITE },
+	{ TVP7002_AVID_STOP_PIXEL_MSBS, 0x2c, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_0_START_L_OFF, 0x05, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_1_START_L_OFF, 0x00, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_0_DURATION, 0x1e, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_1_DURATION, 0x00, TVP7002_WRITE },
+	{ TVP7002_FBIT_F_0_START_L_OFF, 0x00, TVP7002_WRITE },
+	{ TVP7002_FBIT_F_1_START_L_OFF, 0x00, TVP7002_WRITE },
+	{ TVP7002_YUV_Y_G_COEF_LSBS, 0xe3, TVP7002_WRITE },
+	{ TVP7002_YUV_Y_G_COEF_MSBS, 0x16, TVP7002_WRITE },
+	{ TVP7002_YUV_Y_B_COEF_LSBS, 0x4f, TVP7002_WRITE },
+	{ TVP7002_YUV_Y_B_COEF_MSBS, 0x02, TVP7002_WRITE },
+	{ TVP7002_YUV_Y_R_COEF_LSBS, 0xce, TVP7002_WRITE },
+	{ TVP7002_YUV_Y_R_COEF_MSBS, 0x06, TVP7002_WRITE },
+	{ TVP7002_YUV_U_G_COEF_LSBS, 0xab, TVP7002_WRITE },
+	{ TVP7002_YUV_U_G_COEF_MSBS, 0xf3, TVP7002_WRITE },
+	{ TVP7002_YUV_U_B_COEF_LSBS, 0x00, TVP7002_WRITE },
+	{ TVP7002_YUV_U_B_COEF_MSBS, 0x10, TVP7002_WRITE },
+	{ TVP7002_YUV_U_R_COEF_LSBS, 0x55, TVP7002_WRITE },
+	{ TVP7002_YUV_U_R_COEF_MSBS, 0xfc, TVP7002_WRITE },
+	{ TVP7002_YUV_V_G_COEF_LSBS, 0x78, TVP7002_WRITE },
+	{ TVP7002_YUV_V_G_COEF_MSBS, 0xf1, TVP7002_WRITE },
+	{ TVP7002_YUV_V_B_COEF_LSBS, 0x88, TVP7002_WRITE },
+	{ TVP7002_YUV_V_B_COEF_MSBS, 0xfe, TVP7002_WRITE },
+	{ TVP7002_YUV_V_R_COEF_LSBS, 0x00, TVP7002_WRITE },
+	{ TVP7002_YUV_V_R_COEF_MSBS, 0x10, TVP7002_WRITE },
+	/* This signals end of register values */
+	{ TVP7002_EOR, 0xff, TVP7002_RESERVED }
+};
+
+/* Register parameters for 480P */
+static const struct i2c_reg_value tvp7002_parms_480P[] = {
+	{ TVP7002_HPLL_FDBK_DIV_MSBS, 0x35, TVP7002_WRITE },
+	{ TVP7002_HPLL_FDBK_DIV_LSBS, 0xa0, TVP7002_WRITE },
+	{ TVP7002_HPLL_CRTL, 0x02, TVP7002_WRITE },
+	{ TVP7002_AVID_START_PIXEL_LSBS, 0x91, TVP7002_WRITE },
+	{ TVP7002_AVID_START_PIXEL_MSBS, 0x00, TVP7002_WRITE },
+	{ TVP7002_AVID_STOP_PIXEL_LSBS, 0x0B, TVP7002_WRITE },
+	{ TVP7002_AVID_STOP_PIXEL_MSBS, 0x00, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_0_START_L_OFF, 0x03, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_1_START_L_OFF, 0x01, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_0_DURATION, 0x13, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_1_DURATION, 0x13, TVP7002_WRITE },
+	{ TVP7002_ALC_PLACEMENT, 0x18, TVP7002_WRITE },
+	{ TVP7002_CLAMP_START, 0x06, TVP7002_WRITE },
+	{ TVP7002_CLAMP_W, 0x10, TVP7002_WRITE },
+	{ TVP7002_HPLL_PRE_COAST, 0x03, TVP7002_WRITE },
+	{ TVP7002_HPLL_POST_COAST, 0x03, TVP7002_WRITE },
+	{ TVP7002_EOR, 0xff, TVP7002_RESERVED }
+};
+
+/* Register parameters for 576P */
+static const struct i2c_reg_value tvp7002_parms_576P[] = {
+	{ TVP7002_HPLL_FDBK_DIV_MSBS, 0x36, TVP7002_WRITE },
+	{ TVP7002_HPLL_FDBK_DIV_LSBS, 0x00, TVP7002_WRITE },
+	{ TVP7002_HPLL_CRTL, 0x18, TVP7002_WRITE },
+	{ TVP7002_AVID_START_PIXEL_LSBS, 0x9B, TVP7002_WRITE },
+	{ TVP7002_AVID_START_PIXEL_MSBS, 0x00, TVP7002_WRITE },
+	{ TVP7002_AVID_STOP_PIXEL_LSBS, 0x0F, TVP7002_WRITE },
+	{ TVP7002_AVID_STOP_PIXEL_MSBS, 0x00, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_0_START_L_OFF, 0x00, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_1_START_L_OFF, 0x00, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_0_DURATION, 0x2D, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_1_DURATION, 0x00, TVP7002_WRITE },
+	{ TVP7002_ALC_PLACEMENT, 0x18, TVP7002_WRITE },
+	{ TVP7002_CLAMP_START, 0x06, TVP7002_WRITE },
+	{ TVP7002_CLAMP_W, 0x10, TVP7002_WRITE },
+	{ TVP7002_HPLL_PRE_COAST, 0x03, TVP7002_WRITE },
+	{ TVP7002_HPLL_POST_COAST, 0x03, TVP7002_WRITE },
+	{ TVP7002_EOR, 0xff, TVP7002_RESERVED }
+};
+
+/* Register parameters for 1080I60 */
+static const struct i2c_reg_value tvp7002_parms_1080I60[] = {
+	{ TVP7002_HPLL_FDBK_DIV_MSBS, 0x89, TVP7002_WRITE },
+	{ TVP7002_HPLL_FDBK_DIV_LSBS, 0x80, TVP7002_WRITE },
+	{ TVP7002_HPLL_CRTL, 0x98, TVP7002_WRITE },
+	{ TVP7002_AVID_START_PIXEL_LSBS, 0x06, TVP7002_WRITE },
+	{ TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE },
+	{ TVP7002_AVID_STOP_PIXEL_LSBS, 0x8a, TVP7002_WRITE },
+	{ TVP7002_AVID_STOP_PIXEL_MSBS, 0x08, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_0_START_L_OFF, 0x02, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_1_START_L_OFF, 0x02, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_0_DURATION, 0x16, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_1_DURATION, 0x17, TVP7002_WRITE },
+	{ TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE },
+	{ TVP7002_CLAMP_START, 0x32, TVP7002_WRITE },
+	{ TVP7002_CLAMP_W, 0x20, TVP7002_WRITE },
+	{ TVP7002_HPLL_PRE_COAST, 0x01, TVP7002_WRITE },
+	{ TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE },
+	{ TVP7002_EOR, 0xff, TVP7002_RESERVED }
+};
+
+/* Register parameters for 1080P60 */
+static const struct i2c_reg_value tvp7002_parms_1080P60[] = {
+	{ TVP7002_HPLL_FDBK_DIV_MSBS, 0x89, TVP7002_WRITE },
+	{ TVP7002_HPLL_FDBK_DIV_LSBS, 0x80, TVP7002_WRITE },
+	{ TVP7002_HPLL_CRTL, 0xE0, TVP7002_WRITE },
+	{ TVP7002_AVID_START_PIXEL_LSBS, 0x06, TVP7002_WRITE },
+	{ TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE },
+	{ TVP7002_AVID_STOP_PIXEL_LSBS, 0x8a, TVP7002_WRITE },
+	{ TVP7002_AVID_STOP_PIXEL_MSBS, 0x08, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_0_START_L_OFF, 0x02, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_1_START_L_OFF, 0x02, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_0_DURATION, 0x16, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_1_DURATION, 0x17, TVP7002_WRITE },
+	{ TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE },
+	{ TVP7002_CLAMP_START, 0x32, TVP7002_WRITE },
+	{ TVP7002_CLAMP_W, 0x20, TVP7002_WRITE },
+	{ TVP7002_HPLL_PRE_COAST, 0x01, TVP7002_WRITE },
+	{ TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE },
+	{ TVP7002_EOR, 0xff, TVP7002_RESERVED }
+};
+
+/* Register parameters for 1080I50 */
+static const struct i2c_reg_value tvp7002_parms_1080I50[] = {
+	{ TVP7002_HPLL_FDBK_DIV_MSBS, 0xa5, TVP7002_WRITE },
+	{ TVP7002_HPLL_FDBK_DIV_LSBS, 0x00, TVP7002_WRITE },
+	{ TVP7002_HPLL_CRTL, 0x98, TVP7002_WRITE },
+	{ TVP7002_AVID_START_PIXEL_LSBS, 0x06, TVP7002_WRITE },
+	{ TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE },
+	{ TVP7002_AVID_STOP_PIXEL_LSBS, 0x8a, TVP7002_WRITE },
+	{ TVP7002_AVID_STOP_PIXEL_MSBS, 0x08, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_0_START_L_OFF, 0x02, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_1_START_L_OFF, 0x02, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_0_DURATION, 0x16, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_1_DURATION, 0x17, TVP7002_WRITE },
+	{ TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE },
+	{ TVP7002_CLAMP_START, 0x32, TVP7002_WRITE },
+	{ TVP7002_CLAMP_W, 0x20, TVP7002_WRITE },
+	{ TVP7002_HPLL_PRE_COAST, 0x01, TVP7002_WRITE },
+	{ TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE },
+	{ TVP7002_EOR, 0xff, TVP7002_RESERVED }
+};
+
+/* Register parameters for 720P60 */
+static const struct i2c_reg_value tvp7002_parms_720P60[] = {
+	{ TVP7002_HPLL_FDBK_DIV_MSBS, 0x67, TVP7002_WRITE },
+	{ TVP7002_HPLL_FDBK_DIV_LSBS, 0x20, TVP7002_WRITE },
+	{ TVP7002_HPLL_CRTL, 0xa0, TVP7002_WRITE },
+	{ TVP7002_AVID_START_PIXEL_LSBS, 0x47, TVP7002_WRITE },
+	{ TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE },
+	{ TVP7002_AVID_STOP_PIXEL_LSBS, 0x4B, TVP7002_WRITE },
+	{ TVP7002_AVID_STOP_PIXEL_MSBS, 0x06, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_0_START_L_OFF, 0x05, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_1_START_L_OFF, 0x00, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_0_DURATION, 0x2D, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_1_DURATION, 0x00, TVP7002_WRITE },
+	{ TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE },
+	{ TVP7002_CLAMP_START, 0x32, TVP7002_WRITE },
+	{ TVP7002_CLAMP_W, 0x20, TVP7002_WRITE },
+	{ TVP7002_HPLL_PRE_COAST, 0x00, TVP7002_WRITE },
+	{ TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE },
+	{ TVP7002_EOR, 0xff, TVP7002_RESERVED }
+};
+
+/* Register parameters for 720P50 */
+static const struct i2c_reg_value tvp7002_parms_720P50[] = {
+	{ TVP7002_HPLL_FDBK_DIV_MSBS, 0x7b, TVP7002_WRITE },
+	{ TVP7002_HPLL_FDBK_DIV_LSBS, 0xc0, TVP7002_WRITE },
+	{ TVP7002_HPLL_CRTL, 0x98, TVP7002_WRITE },
+	{ TVP7002_AVID_START_PIXEL_LSBS, 0x47, TVP7002_WRITE },
+	{ TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE },
+	{ TVP7002_AVID_STOP_PIXEL_LSBS, 0x4B, TVP7002_WRITE },
+	{ TVP7002_AVID_STOP_PIXEL_MSBS, 0x06, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_0_START_L_OFF, 0x05, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_1_START_L_OFF, 0x00, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_0_DURATION, 0x2D, TVP7002_WRITE },
+	{ TVP7002_VBLK_F_1_DURATION, 0x00, TVP7002_WRITE },
+	{ TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE },
+	{ TVP7002_CLAMP_START, 0x32, TVP7002_WRITE },
+	{ TVP7002_CLAMP_W, 0x20, TVP7002_WRITE },
+	{ TVP7002_HPLL_PRE_COAST, 0x01, TVP7002_WRITE },
+	{ TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE },
+	{ TVP7002_EOR, 0xff, TVP7002_RESERVED }
+};
+
+/* Preset definition for handling device operation */
+struct tvp7002_preset_definition {
+	u32 preset;
+	struct v4l2_dv_timings timings;
+	const struct i2c_reg_value *p_settings;
+	enum v4l2_colorspace color_space;
+	enum v4l2_field scanmode;
+	u16 progressive;
+	u16 lines_per_frame;
+	u16 cpl_min;
+	u16 cpl_max;
+};
+
+/* Struct list for digital video presets */
+static const struct tvp7002_preset_definition tvp7002_presets[] = {
+	{
+		V4L2_DV_720P60,
+		V4L2_DV_BT_CEA_1280X720P60,
+		tvp7002_parms_720P60,
+		V4L2_COLORSPACE_REC709,
+		V4L2_FIELD_NONE,
+		1,
+		0x2EE,
+		135,
+		153
+	},
+	{
+		V4L2_DV_1080I60,
+		V4L2_DV_BT_CEA_1920X1080I60,
+		tvp7002_parms_1080I60,
+		V4L2_COLORSPACE_REC709,
+		V4L2_FIELD_INTERLACED,
+		0,
+		0x465,
+		181,
+		205
+	},
+	{
+		V4L2_DV_1080I50,
+		V4L2_DV_BT_CEA_1920X1080I50,
+		tvp7002_parms_1080I50,
+		V4L2_COLORSPACE_REC709,
+		V4L2_FIELD_INTERLACED,
+		0,
+		0x465,
+		217,
+		245
+	},
+	{
+		V4L2_DV_720P50,
+		V4L2_DV_BT_CEA_1280X720P50,
+		tvp7002_parms_720P50,
+		V4L2_COLORSPACE_REC709,
+		V4L2_FIELD_NONE,
+		1,
+		0x2EE,
+		163,
+		183
+	},
+	{
+		V4L2_DV_1080P60,
+		V4L2_DV_BT_CEA_1920X1080P60,
+		tvp7002_parms_1080P60,
+		V4L2_COLORSPACE_REC709,
+		V4L2_FIELD_NONE,
+		1,
+		0x465,
+		90,
+		102
+	},
+	{
+		V4L2_DV_480P59_94,
+		V4L2_DV_BT_CEA_720X480P59_94,
+		tvp7002_parms_480P,
+		V4L2_COLORSPACE_SMPTE170M,
+		V4L2_FIELD_NONE,
+		1,
+		0x20D,
+		0xffff,
+		0xffff
+	},
+	{
+		V4L2_DV_576P50,
+		V4L2_DV_BT_CEA_720X576P50,
+		tvp7002_parms_576P,
+		V4L2_COLORSPACE_SMPTE170M,
+		V4L2_FIELD_NONE,
+		1,
+		0x271,
+		0xffff,
+		0xffff
+	}
+};
+
+#define NUM_PRESETS	ARRAY_SIZE(tvp7002_presets)
+
+/* Device definition */
+struct tvp7002 {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	const struct tvp7002_config *pdata;
+
+	int ver;
+	int streaming;
+
+	const struct tvp7002_preset_definition *current_preset;
+};
+
+/*
+ * to_tvp7002 - Obtain device handler TVP7002
+ * @sd: ptr to v4l2_subdev struct
+ *
+ * Returns device handler tvp7002.
+ */
+static inline struct tvp7002 *to_tvp7002(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct tvp7002, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct tvp7002, hdl)->sd;
+}
+
+/*
+ * tvp7002_read - Read a value from a register in an TVP7002
+ * @sd: ptr to v4l2_subdev struct
+ * @addr: TVP7002 register address
+ * @dst: pointer to 8-bit destination
+ *
+ * Returns value read if successful, or non-zero (-1) otherwise.
+ */
+static int tvp7002_read(struct v4l2_subdev *sd, u8 addr, u8 *dst)
+{
+	struct i2c_client *c = v4l2_get_subdevdata(sd);
+	int retry;
+	int error;
+
+	for (retry = 0; retry < I2C_RETRY_COUNT; retry++) {
+		error = i2c_smbus_read_byte_data(c, addr);
+
+		if (error >= 0) {
+			*dst = (u8)error;
+			return 0;
+		}
+
+		msleep_interruptible(10);
+	}
+	v4l2_err(sd, "TVP7002 read error %d\n", error);
+	return error;
+}
+
+/*
+ * tvp7002_read_err() - Read a register value with error code
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @reg: destination register
+ * @val: value to be read
+ * @err: pointer to error value
+ *
+ * Read a value in a register and save error value in pointer.
+ * Also update the register table if successful
+ */
+static inline void tvp7002_read_err(struct v4l2_subdev *sd, u8 reg,
+							u8 *dst, int *err)
+{
+	if (!*err)
+		*err = tvp7002_read(sd, reg, dst);
+}
+
+/*
+ * tvp7002_write() - Write a value to a register in TVP7002
+ * @sd: ptr to v4l2_subdev struct
+ * @addr: TVP7002 register address
+ * @value: value to be written to the register
+ *
+ * Write a value to a register in an TVP7002 decoder device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tvp7002_write(struct v4l2_subdev *sd, u8 addr, u8 value)
+{
+	struct i2c_client *c;
+	int retry;
+	int error;
+
+	c = v4l2_get_subdevdata(sd);
+
+	for (retry = 0; retry < I2C_RETRY_COUNT; retry++) {
+		error = i2c_smbus_write_byte_data(c, addr, value);
+
+		if (error >= 0)
+			return 0;
+
+		v4l2_warn(sd, "Write: retry ... %d\n", retry);
+		msleep_interruptible(10);
+	}
+	v4l2_err(sd, "TVP7002 write error %d\n", error);
+	return error;
+}
+
+/*
+ * tvp7002_write_err() - Write a register value with error code
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @reg: destination register
+ * @val: value to be written
+ * @err: pointer to error value
+ *
+ * Write a value in a register and save error value in pointer.
+ * Also update the register table if successful
+ */
+static inline void tvp7002_write_err(struct v4l2_subdev *sd, u8 reg,
+							u8 val, int *err)
+{
+	if (!*err)
+		*err = tvp7002_write(sd, reg, val);
+}
+
+/*
+ * tvp7002_g_chip_ident() - Get chip identification number
+ * @sd: ptr to v4l2_subdev struct
+ * @chip: ptr to v4l2_dbg_chip_ident struct
+ *
+ * Obtains the chip's identification number.
+ * Returns zero or -EINVAL if read operation fails.
+ */
+static int tvp7002_g_chip_ident(struct v4l2_subdev *sd,
+					struct v4l2_dbg_chip_ident *chip)
+{
+	u8 rev;
+	int error;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	error = tvp7002_read(sd, TVP7002_CHIP_REV, &rev);
+
+	if (error < 0)
+		return error;
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVP7002, rev);
+}
+
+/*
+ * tvp7002_write_inittab() - Write initialization values
+ * @sd: ptr to v4l2_subdev struct
+ * @regs: ptr to i2c_reg_value struct
+ *
+ * Write initialization values.
+ * Returns zero or -EINVAL if read operation fails.
+ */
+static int tvp7002_write_inittab(struct v4l2_subdev *sd,
+					const struct i2c_reg_value *regs)
+{
+	int error = 0;
+
+	/* Initialize the first (defined) registers */
+	while (TVP7002_EOR != regs->reg) {
+		if (TVP7002_WRITE == regs->type)
+			tvp7002_write_err(sd, regs->reg, regs->value, &error);
+		regs++;
+	}
+
+	return error;
+}
+
+/*
+ * tvp7002_s_dv_preset() - Set digital video preset
+ * @sd: ptr to v4l2_subdev struct
+ * @dv_preset: ptr to v4l2_dv_preset struct
+ *
+ * Set the digital video preset for a TVP7002 decoder device.
+ * Returns zero when successful or -EINVAL if register access fails.
+ */
+static int tvp7002_s_dv_preset(struct v4l2_subdev *sd,
+					struct v4l2_dv_preset *dv_preset)
+{
+	struct tvp7002 *device = to_tvp7002(sd);
+	u32 preset;
+	int i;
+
+	for (i = 0; i < NUM_PRESETS; i++) {
+		preset = tvp7002_presets[i].preset;
+		if (preset == dv_preset->preset) {
+			device->current_preset = &tvp7002_presets[i];
+			return tvp7002_write_inittab(sd, tvp7002_presets[i].p_settings);
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int tvp7002_s_dv_timings(struct v4l2_subdev *sd,
+					struct v4l2_dv_timings *dv_timings)
+{
+	struct tvp7002 *device = to_tvp7002(sd);
+	const struct v4l2_bt_timings *bt = &dv_timings->bt;
+	int i;
+
+	if (dv_timings->type != V4L2_DV_BT_656_1120)
+		return -EINVAL;
+	for (i = 0; i < NUM_PRESETS; i++) {
+		const struct v4l2_bt_timings *t = &tvp7002_presets[i].timings.bt;
+
+		if (!memcmp(bt, t, &bt->standards - &bt->width)) {
+			device->current_preset = &tvp7002_presets[i];
+			return tvp7002_write_inittab(sd, tvp7002_presets[i].p_settings);
+		}
+	}
+	return -EINVAL;
+}
+
+static int tvp7002_g_dv_timings(struct v4l2_subdev *sd,
+					struct v4l2_dv_timings *dv_timings)
+{
+	struct tvp7002 *device = to_tvp7002(sd);
+
+	*dv_timings = device->current_preset->timings;
+	return 0;
+}
+
+/*
+ * tvp7002_s_ctrl() - Set a control
+ * @ctrl: ptr to v4l2_ctrl struct
+ *
+ * Set a control in TVP7002 decoder device.
+ * Returns zero when successful or -EINVAL if register access fails.
+ */
+static int tvp7002_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	int error = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_GAIN:
+		tvp7002_write_err(sd, TVP7002_R_FINE_GAIN, ctrl->val, &error);
+		tvp7002_write_err(sd, TVP7002_G_FINE_GAIN, ctrl->val, &error);
+		tvp7002_write_err(sd, TVP7002_B_FINE_GAIN, ctrl->val, &error);
+		return error;
+	}
+	return -EINVAL;
+}
+
+/*
+ * tvp7002_mbus_fmt() - V4L2 decoder interface handler for try/s/g_mbus_fmt
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @f: pointer to mediabus format structure
+ *
+ * Negotiate the image capture size and mediabus format.
+ * There is only one possible format, so this single function works for
+ * get, set and try.
+ */
+static int tvp7002_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
+{
+	struct tvp7002 *device = to_tvp7002(sd);
+	struct v4l2_dv_enum_preset e_preset;
+	int error;
+
+	/* Calculate height and width based on current standard */
+	error = v4l_fill_dv_preset_info(device->current_preset->preset, &e_preset);
+	if (error)
+		return error;
+
+	f->width = e_preset.width;
+	f->height = e_preset.height;
+	f->code = V4L2_MBUS_FMT_YUYV10_1X20;
+	f->field = device->current_preset->scanmode;
+	f->colorspace = device->current_preset->color_space;
+
+	v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d",
+			f->width, f->height);
+	return 0;
+}
+
+/*
+ * tvp7002_query_dv_preset() - query DV preset
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @qpreset: standard V4L2 v4l2_dv_preset structure
+ *
+ * Returns the current DV preset by TVP7002. If no active input is
+ * detected, returns -EINVAL
+ */
+static int tvp7002_query_dv(struct v4l2_subdev *sd, int *index)
+{
+	const struct tvp7002_preset_definition *presets = tvp7002_presets;
+	u8 progressive;
+	u32 lpfr;
+	u32 cpln;
+	int error = 0;
+	u8 lpf_lsb;
+	u8 lpf_msb;
+	u8 cpl_lsb;
+	u8 cpl_msb;
+
+	/* Return invalid index if no active input is detected */
+	*index = NUM_PRESETS;
+
+	/* Read standards from device registers */
+	tvp7002_read_err(sd, TVP7002_L_FRAME_STAT_LSBS, &lpf_lsb, &error);
+	tvp7002_read_err(sd, TVP7002_L_FRAME_STAT_MSBS, &lpf_msb, &error);
+
+	if (error < 0)
+		return error;
+
+	tvp7002_read_err(sd, TVP7002_CLK_L_STAT_LSBS, &cpl_lsb, &error);
+	tvp7002_read_err(sd, TVP7002_CLK_L_STAT_MSBS, &cpl_msb, &error);
+
+	if (error < 0)
+		return error;
+
+	/* Get lines per frame, clocks per line and interlaced/progresive */
+	lpfr = lpf_lsb | ((TVP7002_CL_MASK & lpf_msb) << TVP7002_CL_SHIFT);
+	cpln = cpl_lsb | ((TVP7002_CL_MASK & cpl_msb) << TVP7002_CL_SHIFT);
+	progressive = (lpf_msb & TVP7002_INPR_MASK) >> TVP7002_IP_SHIFT;
+
+	/* Do checking of video modes */
+	for (*index = 0; *index < NUM_PRESETS; (*index)++, presets++)
+		if (lpfr == presets->lines_per_frame &&
+			progressive == presets->progressive) {
+			if (presets->cpl_min == 0xffff)
+				break;
+			if (cpln >= presets->cpl_min && cpln <= presets->cpl_max)
+				break;
+		}
+
+	if (*index == NUM_PRESETS) {
+		v4l2_dbg(1, debug, sd, "detection failed: lpf = %x, cpl = %x\n",
+								lpfr, cpln);
+		return -ENOLINK;
+	}
+
+	/* Update lines per frame and clocks per line info */
+	v4l2_dbg(1, debug, sd, "detected preset: %d\n", *index);
+	return 0;
+}
+
+static int tvp7002_query_dv_preset(struct v4l2_subdev *sd,
+					struct v4l2_dv_preset *qpreset)
+{
+	int index;
+	int err = tvp7002_query_dv(sd, &index);
+
+	if (err || index == NUM_PRESETS) {
+		qpreset->preset = V4L2_DV_INVALID;
+		if (err == -ENOLINK)
+			err = 0;
+		return err;
+	}
+	qpreset->preset = tvp7002_presets[index].preset;
+	return 0;
+}
+
+static int tvp7002_query_dv_timings(struct v4l2_subdev *sd,
+					struct v4l2_dv_timings *timings)
+{
+	int index;
+	int err = tvp7002_query_dv(sd, &index);
+
+	if (err)
+		return err;
+	*timings = tvp7002_presets[index].timings;
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/*
+ * tvp7002_g_register() - Get the value of a register
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: ptr to v4l2_dbg_register struct
+ *
+ * Get the value of a TVP7002 decoder device register.
+ * Returns zero when successful, -EINVAL if register read fails or
+ * access to I2C client fails, -EPERM if the call is not allowed
+ * by disabled CAP_SYS_ADMIN.
+ */
+static int tvp7002_g_register(struct v4l2_subdev *sd,
+						struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 val;
+	int ret;
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	ret = tvp7002_read(sd, reg->reg & 0xff, &val);
+	reg->val = val;
+	return ret;
+}
+
+/*
+ * tvp7002_s_register() - set a control
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: ptr to v4l2_dbg_register struct
+ *
+ * Get the value of a TVP7002 decoder device register.
+ * Returns zero when successful, -EINVAL if register read fails or
+ * -EPERM if call not allowed.
+ */
+static int tvp7002_s_register(struct v4l2_subdev *sd,
+						struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	return tvp7002_write(sd, reg->reg & 0xff, reg->val & 0xff);
+}
+#endif
+
+/*
+ * tvp7002_enum_mbus_fmt() - Enum supported mediabus formats
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @index: format index
+ * @code: pointer to mediabus format
+ *
+ * Enumerate supported mediabus formats.
+ */
+
+static int tvp7002_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+					enum v4l2_mbus_pixelcode *code)
+{
+	/* Check requested format index is within range */
+	if (index)
+		return -EINVAL;
+	*code = V4L2_MBUS_FMT_YUYV10_1X20;
+	return 0;
+}
+
+/*
+ * tvp7002_s_stream() - V4L2 decoder i/f handler for s_stream
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @enable: streaming enable or disable
+ *
+ * Sets streaming to enable or disable, if possible.
+ */
+static int tvp7002_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct tvp7002 *device = to_tvp7002(sd);
+	int error = 0;
+
+	if (device->streaming == enable)
+		return 0;
+
+	if (enable) {
+		/* Set output state on (low impedance means stream on) */
+		error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x00);
+		device->streaming = enable;
+	} else {
+		/* Set output state off (high impedance means stream off) */
+		error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x03);
+		if (error)
+			v4l2_dbg(1, debug, sd, "Unable to stop streaming\n");
+
+		device->streaming = enable;
+	}
+
+	return error;
+}
+
+/*
+ * tvp7002_log_status() - Print information about register settings
+ * @sd: ptr to v4l2_subdev struct
+ *
+ * Log register values of a TVP7002 decoder device.
+ * Returns zero or -EINVAL if read operation fails.
+ */
+static int tvp7002_log_status(struct v4l2_subdev *sd)
+{
+	const struct tvp7002_preset_definition *presets = tvp7002_presets;
+	struct tvp7002 *device = to_tvp7002(sd);
+	struct v4l2_dv_enum_preset e_preset;
+	struct v4l2_dv_preset detected;
+	int i;
+
+	detected.preset = V4L2_DV_INVALID;
+	/* Find my current standard*/
+	tvp7002_query_dv_preset(sd, &detected);
+
+	/* Print standard related code values */
+	for (i = 0; i < NUM_PRESETS; i++, presets++)
+		if (presets->preset == detected.preset)
+			break;
+
+	if (v4l_fill_dv_preset_info(device->current_preset->preset, &e_preset))
+		return -EINVAL;
+
+	v4l2_info(sd, "Selected DV Preset: %s\n", e_preset.name);
+	v4l2_info(sd, "   Pixels per line: %u\n", e_preset.width);
+	v4l2_info(sd, "   Lines per frame: %u\n\n", e_preset.height);
+	if (i == NUM_PRESETS) {
+		v4l2_info(sd, "Detected DV Preset: None\n");
+	} else {
+		if (v4l_fill_dv_preset_info(presets->preset, &e_preset))
+			return -EINVAL;
+		v4l2_info(sd, "Detected DV Preset: %s\n", e_preset.name);
+		v4l2_info(sd, "  Pixels per line: %u\n", e_preset.width);
+		v4l2_info(sd, "  Lines per frame: %u\n\n", e_preset.height);
+	}
+	v4l2_info(sd, "Streaming enabled: %s\n",
+					device->streaming ? "yes" : "no");
+
+	/* Print the current value of the gain control */
+	v4l2_ctrl_handler_log_status(&device->hdl, sd->name);
+
+	return 0;
+}
+
+/*
+ * tvp7002_enum_dv_presets() - Enum supported digital video formats
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @preset: pointer to format struct
+ *
+ * Enumerate supported digital video formats.
+ */
+static int tvp7002_enum_dv_presets(struct v4l2_subdev *sd,
+		struct v4l2_dv_enum_preset *preset)
+{
+	/* Check requested format index is within range */
+	if (preset->index >= NUM_PRESETS)
+		return -EINVAL;
+
+	return v4l_fill_dv_preset_info(tvp7002_presets[preset->index].preset, preset);
+}
+
+static int tvp7002_enum_dv_timings(struct v4l2_subdev *sd,
+		struct v4l2_enum_dv_timings *timings)
+{
+	/* Check requested format index is within range */
+	if (timings->index >= NUM_PRESETS)
+		return -EINVAL;
+
+	timings->timings = tvp7002_presets[timings->index].timings;
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = {
+	.s_ctrl = tvp7002_s_ctrl,
+};
+
+/* V4L2 core operation handlers */
+static const struct v4l2_subdev_core_ops tvp7002_core_ops = {
+	.g_chip_ident = tvp7002_g_chip_ident,
+	.log_status = tvp7002_log_status,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = tvp7002_g_register,
+	.s_register = tvp7002_s_register,
+#endif
+};
+
+/* Specific video subsystem operation handlers */
+static const struct v4l2_subdev_video_ops tvp7002_video_ops = {
+	.enum_dv_presets = tvp7002_enum_dv_presets,
+	.s_dv_preset = tvp7002_s_dv_preset,
+	.query_dv_preset = tvp7002_query_dv_preset,
+	.g_dv_timings = tvp7002_g_dv_timings,
+	.s_dv_timings = tvp7002_s_dv_timings,
+	.enum_dv_timings = tvp7002_enum_dv_timings,
+	.query_dv_timings = tvp7002_query_dv_timings,
+	.s_stream = tvp7002_s_stream,
+	.g_mbus_fmt = tvp7002_mbus_fmt,
+	.try_mbus_fmt = tvp7002_mbus_fmt,
+	.s_mbus_fmt = tvp7002_mbus_fmt,
+	.enum_mbus_fmt = tvp7002_enum_mbus_fmt,
+};
+
+/* V4L2 top level operation handlers */
+static const struct v4l2_subdev_ops tvp7002_ops = {
+	.core = &tvp7002_core_ops,
+	.video = &tvp7002_video_ops,
+};
+
+/*
+ * tvp7002_probe - Probe a TVP7002 device
+ * @c: ptr to i2c_client struct
+ * @id: ptr to i2c_device_id struct
+ *
+ * Initialize the TVP7002 device
+ * Returns zero when successful, -EINVAL if register read fails or
+ * -EIO if i2c access is not available.
+ */
+static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
+{
+	struct v4l2_subdev *sd;
+	struct tvp7002 *device;
+	struct v4l2_dv_preset preset;
+	int polarity_a;
+	int polarity_b;
+	u8 revision;
+
+	int error;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(c->adapter,
+		I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+		return -EIO;
+
+	if (!c->dev.platform_data) {
+		v4l_err(c, "No platform data!!\n");
+		return -ENODEV;
+	}
+
+	device = kzalloc(sizeof(struct tvp7002), GFP_KERNEL);
+
+	if (!device)
+		return -ENOMEM;
+
+	sd = &device->sd;
+	device->pdata = c->dev.platform_data;
+	device->current_preset = tvp7002_presets;
+
+	/* Tell v4l2 the device is ready */
+	v4l2_i2c_subdev_init(sd, c, &tvp7002_ops);
+	v4l_info(c, "tvp7002 found @ 0x%02x (%s)\n",
+					c->addr, c->adapter->name);
+
+	error = tvp7002_read(sd, TVP7002_CHIP_REV, &revision);
+	if (error < 0)
+		goto found_error;
+
+	/* Get revision number */
+	v4l2_info(sd, "Rev. %02x detected.\n", revision);
+	if (revision != 0x02)
+		v4l2_info(sd, "Unknown revision detected.\n");
+
+	/* Initializes TVP7002 to its default values */
+	error = tvp7002_write_inittab(sd, tvp7002_init_default);
+
+	if (error < 0)
+		goto found_error;
+
+	/* Set polarity information after registers have been set */
+	polarity_a = 0x20 | device->pdata->hs_polarity << 5
+			| device->pdata->vs_polarity << 2;
+	error = tvp7002_write(sd, TVP7002_SYNC_CTL_1, polarity_a);
+	if (error < 0)
+		goto found_error;
+
+	polarity_b = 0x01  | device->pdata->fid_polarity << 2
+			| device->pdata->sog_polarity << 1
+			| device->pdata->clk_polarity;
+	error = tvp7002_write(sd, TVP7002_MISC_CTL_3, polarity_b);
+	if (error < 0)
+		goto found_error;
+
+	/* Set registers according to default video mode */
+	preset.preset = device->current_preset->preset;
+	error = tvp7002_s_dv_preset(sd, &preset);
+
+	v4l2_ctrl_handler_init(&device->hdl, 1);
+	v4l2_ctrl_new_std(&device->hdl, &tvp7002_ctrl_ops,
+			V4L2_CID_GAIN, 0, 255, 1, 0);
+	sd->ctrl_handler = &device->hdl;
+	if (device->hdl.error) {
+		int err = device->hdl.error;
+
+		v4l2_ctrl_handler_free(&device->hdl);
+		kfree(device);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&device->hdl);
+
+found_error:
+	if (error < 0)
+		kfree(device);
+
+	return error;
+}
+
+/*
+ * tvp7002_remove - Remove TVP7002 device support
+ * @c: ptr to i2c_client struct
+ *
+ * Reset the TVP7002 device
+ * Returns zero.
+ */
+static int tvp7002_remove(struct i2c_client *c)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(c);
+	struct tvp7002 *device = to_tvp7002(sd);
+
+	v4l2_dbg(1, debug, sd, "Removing tvp7002 adapter"
+				"on address 0x%x\n", c->addr);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&device->hdl);
+	kfree(device);
+	return 0;
+}
+
+/* I2C Device ID table */
+static const struct i2c_device_id tvp7002_id[] = {
+	{ "tvp7002", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tvp7002_id);
+
+/* I2C driver data */
+static struct i2c_driver tvp7002_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = TVP7002_MODULE_NAME,
+	},
+	.probe = tvp7002_probe,
+	.remove = tvp7002_remove,
+	.id_table = tvp7002_id,
+};
+
+module_i2c_driver(tvp7002_driver);
diff --git a/drivers/media/i2c/tvp7002_reg.h b/drivers/media/i2c/tvp7002_reg.h
new file mode 100644
index 0000000..0e34ca9
--- /dev/null
+++ b/drivers/media/i2c/tvp7002_reg.h
@@ -0,0 +1,150 @@
+/* Texas Instruments Triple 8-/10-BIT 165-/110-MSPS Video and Graphics
+ * Digitizer with Horizontal PLL registers
+ *
+ * Copyright (C) 2009 Texas Instruments Inc
+ * Author: Santiago Nunez-Corrales <santiago.nunez@ridgerun.com>
+ *
+ * This code is partially based upon the TVP5150 driver
+ * written by Mauro Carvalho Chehab (mchehab@infradead.org),
+ * the TVP514x driver written by Vaibhav Hiremath <hvaibhav@ti.com>
+ * and the TVP7002 driver in the TI LSP 2.10.00.14
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Naming conventions
+ * ------------------
+ *
+ * FDBK:  Feedback
+ * DIV:   Divider
+ * CTL:   Control
+ * SEL:   Select
+ * IN:    Input
+ * OUT:   Output
+ * R:     Red
+ * G:     Green
+ * B:     Blue
+ * OFF:   Offset
+ * THRS:  Threshold
+ * DGTL:  Digital
+ * LVL:   Level
+ * PWR:   Power
+ * MVIS:  Macrovision
+ * W:     Width
+ * H:     Height
+ * ALGN:  Alignment
+ * CLK:   Clocks
+ * TOL:   Tolerance
+ * BWTH:  Bandwidth
+ * COEF:  Coefficient
+ * STAT:  Status
+ * AUTO:  Automatic
+ * FLD:   Field
+ * L:	  Line
+ */
+
+#define TVP7002_CHIP_REV		0x00
+#define TVP7002_HPLL_FDBK_DIV_MSBS	0x01
+#define TVP7002_HPLL_FDBK_DIV_LSBS	0x02
+#define TVP7002_HPLL_CRTL		0x03
+#define TVP7002_HPLL_PHASE_SEL		0x04
+#define TVP7002_CLAMP_START		0x05
+#define TVP7002_CLAMP_W			0x06
+#define TVP7002_HSYNC_OUT_W		0x07
+#define TVP7002_B_FINE_GAIN		0x08
+#define TVP7002_G_FINE_GAIN		0x09
+#define TVP7002_R_FINE_GAIN		0x0a
+#define TVP7002_B_FINE_OFF_MSBS		0x0b
+#define TVP7002_G_FINE_OFF_MSBS         0x0c
+#define TVP7002_R_FINE_OFF_MSBS         0x0d
+#define TVP7002_SYNC_CTL_1		0x0e
+#define TVP7002_HPLL_AND_CLAMP_CTL	0x0f
+#define TVP7002_SYNC_ON_G_THRS		0x10
+#define TVP7002_SYNC_SEPARATOR_THRS	0x11
+#define TVP7002_HPLL_PRE_COAST		0x12
+#define TVP7002_HPLL_POST_COAST		0x13
+#define TVP7002_SYNC_DETECT_STAT	0x14
+#define TVP7002_OUT_FORMATTER		0x15
+#define TVP7002_MISC_CTL_1		0x16
+#define TVP7002_MISC_CTL_2              0x17
+#define TVP7002_MISC_CTL_3              0x18
+#define TVP7002_IN_MUX_SEL_1		0x19
+#define TVP7002_IN_MUX_SEL_2            0x1a
+#define TVP7002_B_AND_G_COARSE_GAIN	0x1b
+#define TVP7002_R_COARSE_GAIN		0x1c
+#define TVP7002_FINE_OFF_LSBS		0x1d
+#define TVP7002_B_COARSE_OFF		0x1e
+#define TVP7002_G_COARSE_OFF            0x1f
+#define TVP7002_R_COARSE_OFF            0x20
+#define TVP7002_HSOUT_OUT_START		0x21
+#define TVP7002_MISC_CTL_4		0x22
+#define TVP7002_B_DGTL_ALC_OUT_LSBS	0x23
+#define TVP7002_G_DGTL_ALC_OUT_LSBS     0x24
+#define TVP7002_R_DGTL_ALC_OUT_LSBS     0x25
+#define TVP7002_AUTO_LVL_CTL_ENABLE	0x26
+#define TVP7002_DGTL_ALC_OUT_MSBS	0x27
+#define TVP7002_AUTO_LVL_CTL_FILTER	0x28
+/* Reserved 0x29*/
+#define TVP7002_FINE_CLAMP_CTL		0x2a
+#define TVP7002_PWR_CTL			0x2b
+#define TVP7002_ADC_SETUP		0x2c
+#define TVP7002_COARSE_CLAMP_CTL	0x2d
+#define TVP7002_SOG_CLAMP		0x2e
+#define TVP7002_RGB_COARSE_CLAMP_CTL	0x2f
+#define TVP7002_SOG_COARSE_CLAMP_CTL	0x30
+#define TVP7002_ALC_PLACEMENT		0x31
+/* Reserved 0x32 */
+/* Reserved 0x33 */
+#define TVP7002_MVIS_STRIPPER_W		0x34
+#define TVP7002_VSYNC_ALGN		0x35
+#define TVP7002_SYNC_BYPASS		0x36
+#define TVP7002_L_FRAME_STAT_LSBS	0x37
+#define TVP7002_L_FRAME_STAT_MSBS	0x38
+#define TVP7002_CLK_L_STAT_LSBS		0x39
+#define TVP7002_CLK_L_STAT_MSBS      	0x3a
+#define TVP7002_HSYNC_W			0x3b
+#define TVP7002_VSYNC_W                 0x3c
+#define TVP7002_L_LENGTH_TOL 		0x3d
+/* Reserved 0x3e */
+#define TVP7002_VIDEO_BWTH_CTL		0x3f
+#define TVP7002_AVID_START_PIXEL_LSBS	0x40
+#define TVP7002_AVID_START_PIXEL_MSBS   0x41
+#define TVP7002_AVID_STOP_PIXEL_LSBS  	0x42
+#define TVP7002_AVID_STOP_PIXEL_MSBS    0x43
+#define TVP7002_VBLK_F_0_START_L_OFF	0x44
+#define TVP7002_VBLK_F_1_START_L_OFF    0x45
+#define TVP7002_VBLK_F_0_DURATION	0x46
+#define TVP7002_VBLK_F_1_DURATION       0x47
+#define TVP7002_FBIT_F_0_START_L_OFF	0x48
+#define TVP7002_FBIT_F_1_START_L_OFF    0x49
+#define TVP7002_YUV_Y_G_COEF_LSBS	0x4a
+#define TVP7002_YUV_Y_G_COEF_MSBS       0x4b
+#define TVP7002_YUV_Y_B_COEF_LSBS       0x4c
+#define TVP7002_YUV_Y_B_COEF_MSBS       0x4d
+#define TVP7002_YUV_Y_R_COEF_LSBS       0x4e
+#define TVP7002_YUV_Y_R_COEF_MSBS       0x4f
+#define TVP7002_YUV_U_G_COEF_LSBS       0x50
+#define TVP7002_YUV_U_G_COEF_MSBS       0x51
+#define TVP7002_YUV_U_B_COEF_LSBS       0x52
+#define TVP7002_YUV_U_B_COEF_MSBS       0x53
+#define TVP7002_YUV_U_R_COEF_LSBS       0x54
+#define TVP7002_YUV_U_R_COEF_MSBS       0x55
+#define TVP7002_YUV_V_G_COEF_LSBS       0x56
+#define TVP7002_YUV_V_G_COEF_MSBS       0x57
+#define TVP7002_YUV_V_B_COEF_LSBS       0x58
+#define TVP7002_YUV_V_B_COEF_MSBS       0x59
+#define TVP7002_YUV_V_R_COEF_LSBS       0x5a
+#define TVP7002_YUV_V_R_COEF_MSBS       0x5b
+
diff --git a/drivers/media/i2c/upd64031a.c b/drivers/media/i2c/upd64031a.c
new file mode 100644
index 0000000..1e74465
--- /dev/null
+++ b/drivers/media/i2c/upd64031a.c
@@ -0,0 +1,274 @@
+/*
+ * upd64031A - NEC Electronics Ghost Reduction for NTSC in Japan
+ *
+ * 2003 by T.Adachi <tadachi@tadachi-net.com>
+ * 2003 by Takeru KOMORIYA <komoriya@paken.org>
+ * 2006 by Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/upd64031a.h>
+
+/* --------------------- read registers functions define -------------------- */
+
+/* bit masks */
+#define GR_MODE_MASK              0xc0
+#define DIRECT_3DYCS_CONNECT_MASK 0xc0
+#define SYNC_CIRCUIT_MASK         0xa0
+
+/* -------------------------------------------------------------------------- */
+
+MODULE_DESCRIPTION("uPD64031A driver");
+MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0644);
+
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+
+enum {
+	R00 = 0, R01, R02, R03, R04,
+	R05, R06, R07, R08, R09,
+	R0A, R0B, R0C, R0D, R0E, R0F,
+	/* unused registers
+	 R10, R11, R12, R13, R14,
+	 R15, R16, R17,
+	 */
+	TOT_REGS
+};
+
+struct upd64031a_state {
+	struct v4l2_subdev sd;
+	u8 regs[TOT_REGS];
+	u8 gr_mode;
+	u8 direct_3dycs_connect;
+	u8 ext_comp_sync;
+	u8 ext_vert_sync;
+};
+
+static inline struct upd64031a_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct upd64031a_state, sd);
+}
+
+static u8 upd64031a_init[] = {
+	0x00, 0xb8, 0x48, 0xd2, 0xe6,
+	0x03, 0x10, 0x0b, 0xaf, 0x7f,
+	0x00, 0x00, 0x1d, 0x5e, 0x00,
+	0xd0
+};
+
+/* ------------------------------------------------------------------------ */
+
+static u8 upd64031a_read(struct v4l2_subdev *sd, u8 reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 buf[2];
+
+	if (reg >= sizeof(buf))
+		return 0xff;
+	i2c_master_recv(client, buf, 2);
+	return buf[reg];
+}
+
+/* ------------------------------------------------------------------------ */
+
+static void upd64031a_write(struct v4l2_subdev *sd, u8 reg, u8 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 buf[2];
+
+	buf[0] = reg;
+	buf[1] = val;
+	v4l2_dbg(1, debug, sd, "write reg: %02X val: %02X\n", reg, val);
+	if (i2c_master_send(client, buf, 2) != 2)
+		v4l2_err(sd, "I/O error write 0x%02x/0x%02x\n", reg, val);
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* The input changed due to new input or channel changed */
+static int upd64031a_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+{
+	struct upd64031a_state *state = to_state(sd);
+	u8 reg = state->regs[R00];
+
+	v4l2_dbg(1, debug, sd, "changed input or channel\n");
+	upd64031a_write(sd, R00, reg | 0x10);
+	upd64031a_write(sd, R00, reg & ~0x10);
+	return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int upd64031a_s_routing(struct v4l2_subdev *sd,
+			       u32 input, u32 output, u32 config)
+{
+	struct upd64031a_state *state = to_state(sd);
+	u8 r00, r05, r08;
+
+	state->gr_mode = (input & 3) << 6;
+	state->direct_3dycs_connect = (input & 0xc) << 4;
+	state->ext_comp_sync =
+		(input & UPD64031A_COMPOSITE_EXTERNAL) << 1;
+	state->ext_vert_sync =
+		(input & UPD64031A_VERTICAL_EXTERNAL) << 2;
+	r00 = (state->regs[R00] & ~GR_MODE_MASK) | state->gr_mode;
+	r05 = (state->regs[R00] & ~SYNC_CIRCUIT_MASK) |
+		state->ext_comp_sync | state->ext_vert_sync;
+	r08 = (state->regs[R08] & ~DIRECT_3DYCS_CONNECT_MASK) |
+		state->direct_3dycs_connect;
+	upd64031a_write(sd, R00, r00);
+	upd64031a_write(sd, R05, r05);
+	upd64031a_write(sd, R08, r08);
+	return upd64031a_s_frequency(sd, NULL);
+}
+
+static int upd64031a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_UPD64031A, 0);
+}
+
+static int upd64031a_log_status(struct v4l2_subdev *sd)
+{
+	v4l2_info(sd, "Status: SA00=0x%02x SA01=0x%02x\n",
+			upd64031a_read(sd, 0), upd64031a_read(sd, 1));
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int upd64031a_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	reg->val = upd64031a_read(sd, reg->reg & 0xff);
+	reg->size = 1;
+	return 0;
+}
+
+static int upd64031a_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	upd64031a_write(sd, reg->reg & 0xff, reg->val & 0xff);
+	return 0;
+}
+#endif
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops upd64031a_core_ops = {
+	.log_status = upd64031a_log_status,
+	.g_chip_ident = upd64031a_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = upd64031a_g_register,
+	.s_register = upd64031a_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops upd64031a_tuner_ops = {
+	.s_frequency = upd64031a_s_frequency,
+};
+
+static const struct v4l2_subdev_video_ops upd64031a_video_ops = {
+	.s_routing = upd64031a_s_routing,
+};
+
+static const struct v4l2_subdev_ops upd64031a_ops = {
+	.core = &upd64031a_core_ops,
+	.tuner = &upd64031a_tuner_ops,
+	.video = &upd64031a_video_ops,
+};
+
+/* ------------------------------------------------------------------------ */
+
+/* i2c implementation */
+
+static int upd64031a_probe(struct i2c_client *client,
+			   const struct i2c_device_id *id)
+{
+	struct upd64031a_state *state;
+	struct v4l2_subdev *sd;
+	int i;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	state = kzalloc(sizeof(struct upd64031a_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &upd64031a_ops);
+	memcpy(state->regs, upd64031a_init, sizeof(state->regs));
+	state->gr_mode = UPD64031A_GR_ON << 6;
+	state->direct_3dycs_connect = UPD64031A_3DYCS_COMPOSITE << 4;
+	state->ext_comp_sync = state->ext_vert_sync = 0;
+	for (i = 0; i < TOT_REGS; i++)
+		upd64031a_write(sd, i, state->regs[i]);
+	return 0;
+}
+
+static int upd64031a_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_state(sd));
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id upd64031a_id[] = {
+	{ "upd64031a", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, upd64031a_id);
+
+static struct i2c_driver upd64031a_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "upd64031a",
+	},
+	.probe		= upd64031a_probe,
+	.remove		= upd64031a_remove,
+	.id_table	= upd64031a_id,
+};
+
+module_i2c_driver(upd64031a_driver);
diff --git a/drivers/media/i2c/upd64083.c b/drivers/media/i2c/upd64083.c
new file mode 100644
index 0000000..75d6acc
--- /dev/null
+++ b/drivers/media/i2c/upd64083.c
@@ -0,0 +1,246 @@
+/*
+ * upd6408x - NEC Electronics 3-Dimensional Y/C separation driver
+ *
+ * 2003 by T.Adachi (tadachi@tadachi-net.com)
+ * 2003 by Takeru KOMORIYA <komoriya@paken.org>
+ * 2006 by Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/upd64083.h>
+
+MODULE_DESCRIPTION("uPD64083 driver");
+MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static bool debug;
+module_param(debug, bool, 0644);
+
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+
+enum {
+	R00 = 0, R01, R02, R03, R04,
+	R05, R06, R07, R08, R09,
+	R0A, R0B, R0C, R0D, R0E, R0F,
+	R10, R11, R12, R13, R14,
+	R15, R16,
+	TOT_REGS
+};
+
+struct upd64083_state {
+	struct v4l2_subdev sd;
+	u8 mode;
+	u8 ext_y_adc;
+	u8 regs[TOT_REGS];
+};
+
+static inline struct upd64083_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct upd64083_state, sd);
+}
+
+/* Initial values when used in combination with the
+   NEC upd64031a ghost reduction chip. */
+static u8 upd64083_init[] = {
+	0x1f, 0x01, 0xa0, 0x2d, 0x29,  /* we use EXCSS=0 */
+	0x36, 0xdd, 0x05, 0x56, 0x48,
+	0x00, 0x3a, 0xa0, 0x05, 0x08,
+	0x44, 0x60, 0x08, 0x52, 0xf8,
+	0x53, 0x60, 0x10
+};
+
+/* ------------------------------------------------------------------------ */
+
+static void upd64083_write(struct v4l2_subdev *sd, u8 reg, u8 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 buf[2];
+
+	buf[0] = reg;
+	buf[1] = val;
+	v4l2_dbg(1, debug, sd, "write reg: %02x val: %02x\n", reg, val);
+	if (i2c_master_send(client, buf, 2) != 2)
+		v4l2_err(sd, "I/O error write 0x%02x/0x%02x\n", reg, val);
+}
+
+/* ------------------------------------------------------------------------ */
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static u8 upd64083_read(struct v4l2_subdev *sd, u8 reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 buf[7];
+
+	if (reg >= sizeof(buf))
+		return 0xff;
+	i2c_master_recv(client, buf, sizeof(buf));
+	return buf[reg];
+}
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static int upd64083_s_routing(struct v4l2_subdev *sd,
+			      u32 input, u32 output, u32 config)
+{
+	struct upd64083_state *state = to_state(sd);
+	u8 r00, r02;
+
+	if (input > 7 || (input & 6) == 6)
+		return -EINVAL;
+	state->mode = (input & 3) << 6;
+	state->ext_y_adc = (input & UPD64083_EXT_Y_ADC) << 3;
+	r00 = (state->regs[R00] & ~(3 << 6)) | state->mode;
+	r02 = (state->regs[R02] & ~(1 << 5)) | state->ext_y_adc;
+	upd64083_write(sd, R00, r00);
+	upd64083_write(sd, R02, r02);
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int upd64083_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	reg->val = upd64083_read(sd, reg->reg & 0xff);
+	reg->size = 1;
+	return 0;
+}
+
+static int upd64083_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	upd64083_write(sd, reg->reg & 0xff, reg->val & 0xff);
+	return 0;
+}
+#endif
+
+static int upd64083_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_UPD64083, 0);
+}
+
+static int upd64083_log_status(struct v4l2_subdev *sd)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 buf[7];
+
+	i2c_master_recv(client, buf, 7);
+	v4l2_info(sd, "Status: SA00=%02x SA01=%02x SA02=%02x SA03=%02x "
+		      "SA04=%02x SA05=%02x SA06=%02x\n",
+		buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops upd64083_core_ops = {
+	.log_status = upd64083_log_status,
+	.g_chip_ident = upd64083_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = upd64083_g_register,
+	.s_register = upd64083_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops upd64083_video_ops = {
+	.s_routing = upd64083_s_routing,
+};
+
+static const struct v4l2_subdev_ops upd64083_ops = {
+	.core = &upd64083_core_ops,
+	.video = &upd64083_video_ops,
+};
+
+/* ------------------------------------------------------------------------ */
+
+/* i2c implementation */
+
+static int upd64083_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct upd64083_state *state;
+	struct v4l2_subdev *sd;
+	int i;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	state = kzalloc(sizeof(struct upd64083_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &upd64083_ops);
+	/* Initially assume that a ghost reduction chip is present */
+	state->mode = 0;  /* YCS mode */
+	state->ext_y_adc = (1 << 5);
+	memcpy(state->regs, upd64083_init, TOT_REGS);
+	for (i = 0; i < TOT_REGS; i++)
+		upd64083_write(sd, i, state->regs[i]);
+	return 0;
+}
+
+static int upd64083_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_state(sd));
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id upd64083_id[] = {
+	{ "upd64083", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, upd64083_id);
+
+static struct i2c_driver upd64083_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "upd64083",
+	},
+	.probe		= upd64083_probe,
+	.remove		= upd64083_remove,
+	.id_table	= upd64083_id,
+};
+
+module_i2c_driver(upd64083_driver);
diff --git a/drivers/media/i2c/vp27smpx.c b/drivers/media/i2c/vp27smpx.c
new file mode 100644
index 0000000..7cfbc9d
--- /dev/null
+++ b/drivers/media/i2c/vp27smpx.c
@@ -0,0 +1,211 @@
+/*
+ * vp27smpx - driver version 0.0.1
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Based on a tvaudio patch from Takahiro Adachi <tadachi@tadachi-net.com>
+ * and Kazuhiko Kawakami <kazz-0@mail.goo.ne.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_DESCRIPTION("vp27smpx driver");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+
+/* ----------------------------------------------------------------------- */
+
+struct vp27smpx_state {
+	struct v4l2_subdev sd;
+	int radio;
+	u32 audmode;
+};
+
+static inline struct vp27smpx_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct vp27smpx_state, sd);
+}
+
+static void vp27smpx_set_audmode(struct v4l2_subdev *sd, u32 audmode)
+{
+	struct vp27smpx_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 data[3] = { 0x00, 0x00, 0x04 };
+
+	switch (audmode) {
+	case V4L2_TUNER_MODE_MONO:
+	case V4L2_TUNER_MODE_LANG1:
+		break;
+	case V4L2_TUNER_MODE_STEREO:
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+		data[1] = 0x01;
+		break;
+	case V4L2_TUNER_MODE_LANG2:
+		data[1] = 0x02;
+		break;
+	}
+
+	if (i2c_master_send(client, data, sizeof(data)) != sizeof(data))
+		v4l2_err(sd, "I/O error setting audmode\n");
+	else
+		state->audmode = audmode;
+}
+
+static int vp27smpx_s_radio(struct v4l2_subdev *sd)
+{
+	struct vp27smpx_state *state = to_state(sd);
+
+	state->radio = 1;
+	return 0;
+}
+
+static int vp27smpx_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+	struct vp27smpx_state *state = to_state(sd);
+
+	state->radio = 0;
+	return 0;
+}
+
+static int vp27smpx_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct vp27smpx_state *state = to_state(sd);
+
+	if (!state->radio)
+		vp27smpx_set_audmode(sd, vt->audmode);
+	return 0;
+}
+
+static int vp27smpx_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct vp27smpx_state *state = to_state(sd);
+
+	if (state->radio)
+		return 0;
+	vt->audmode = state->audmode;
+	vt->capability = V4L2_TUNER_CAP_STEREO |
+		V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+	vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+	return 0;
+}
+
+static int vp27smpx_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_VP27SMPX, 0);
+}
+
+static int vp27smpx_log_status(struct v4l2_subdev *sd)
+{
+	struct vp27smpx_state *state = to_state(sd);
+
+	v4l2_info(sd, "Audio Mode: %u%s\n", state->audmode,
+			state->radio ? " (Radio)" : "");
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops vp27smpx_core_ops = {
+	.log_status = vp27smpx_log_status,
+	.g_chip_ident = vp27smpx_g_chip_ident,
+	.s_std = vp27smpx_s_std,
+};
+
+static const struct v4l2_subdev_tuner_ops vp27smpx_tuner_ops = {
+	.s_radio = vp27smpx_s_radio,
+	.s_tuner = vp27smpx_s_tuner,
+	.g_tuner = vp27smpx_g_tuner,
+};
+
+static const struct v4l2_subdev_ops vp27smpx_ops = {
+	.core = &vp27smpx_core_ops,
+	.tuner = &vp27smpx_tuner_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static int vp27smpx_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct vp27smpx_state *state;
+	struct v4l2_subdev *sd;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &vp27smpx_ops);
+	state->audmode = V4L2_TUNER_MODE_STEREO;
+
+	/* initialize vp27smpx */
+	vp27smpx_set_audmode(sd, state->audmode);
+	return 0;
+}
+
+static int vp27smpx_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_state(sd));
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id vp27smpx_id[] = {
+	{ "vp27smpx", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, vp27smpx_id);
+
+static struct i2c_driver vp27smpx_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "vp27smpx",
+	},
+	.probe		= vp27smpx_probe,
+	.remove		= vp27smpx_remove,
+	.id_table	= vp27smpx_id,
+};
+
+module_i2c_driver(vp27smpx_driver);
diff --git a/drivers/media/i2c/vpx3220.c b/drivers/media/i2c/vpx3220.c
new file mode 100644
index 0000000..2f67b4c
--- /dev/null
+++ b/drivers/media/i2c/vpx3220.c
@@ -0,0 +1,591 @@
+/*
+ * vpx3220a, vpx3216b & vpx3214c video decoder driver version 0.0.1
+ *
+ * Copyright (C) 2001 Laurent Pinchart <lpinchart@freegates.be>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
+MODULE_AUTHOR("Laurent Pinchart");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+
+#define VPX_TIMEOUT_COUNT  10
+
+/* ----------------------------------------------------------------------- */
+
+struct vpx3220 {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	unsigned char reg[255];
+
+	v4l2_std_id norm;
+	int ident;
+	int input;
+	int enable;
+};
+
+static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct vpx3220, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct vpx3220, hdl)->sd;
+}
+
+static char *inputs[] = { "internal", "composite", "svideo" };
+
+/* ----------------------------------------------------------------------- */
+
+static inline int vpx3220_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct vpx3220 *decoder = i2c_get_clientdata(client);
+
+	decoder->reg[reg] = value;
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline int vpx3220_read(struct v4l2_subdev *sd, u8 reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int vpx3220_fp_status(struct v4l2_subdev *sd)
+{
+	unsigned char status;
+	unsigned int i;
+
+	for (i = 0; i < VPX_TIMEOUT_COUNT; i++) {
+		status = vpx3220_read(sd, 0x29);
+
+		if (!(status & 4))
+			return 0;
+
+		udelay(10);
+
+		if (need_resched())
+			cond_resched();
+	}
+
+	return -1;
+}
+
+static int vpx3220_fp_write(struct v4l2_subdev *sd, u8 fpaddr, u16 data)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	/* Write the 16-bit address to the FPWR register */
+	if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) {
+		v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
+		return -1;
+	}
+
+	if (vpx3220_fp_status(sd) < 0)
+		return -1;
+
+	/* Write the 16-bit data to the FPDAT register */
+	if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) {
+		v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
+		return -1;
+	}
+
+	return 0;
+}
+
+static u16 vpx3220_fp_read(struct v4l2_subdev *sd, u16 fpaddr)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	s16 data;
+
+	/* Write the 16-bit address to the FPRD register */
+	if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) {
+		v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
+		return -1;
+	}
+
+	if (vpx3220_fp_status(sd) < 0)
+		return -1;
+
+	/* Read the 16-bit data from the FPDAT register */
+	data = i2c_smbus_read_word_data(client, 0x28);
+	if (data == -1) {
+		v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
+		return -1;
+	}
+
+	return swab16(data);
+}
+
+static int vpx3220_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len)
+{
+	u8 reg;
+	int ret = -1;
+
+	while (len >= 2) {
+		reg = *data++;
+		ret = vpx3220_write(sd, reg, *data++);
+		if (ret < 0)
+			break;
+		len -= 2;
+	}
+
+	return ret;
+}
+
+static int vpx3220_write_fp_block(struct v4l2_subdev *sd,
+		const u16 *data, unsigned int len)
+{
+	u8 reg;
+	int ret = 0;
+
+	while (len > 1) {
+		reg = *data++;
+		ret |= vpx3220_fp_write(sd, reg, *data++);
+		len -= 2;
+	}
+
+	return ret;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static const unsigned short init_ntsc[] = {
+	0x1c, 0x00,		/* NTSC tint angle */
+	0x88, 17,		/* Window 1 vertical */
+	0x89, 240,		/* Vertical lines in */
+	0x8a, 240,		/* Vertical lines out */
+	0x8b, 000,		/* Horizontal begin */
+	0x8c, 640,		/* Horizontal length */
+	0x8d, 640,		/* Number of pixels */
+	0x8f, 0xc00,		/* Disable window 2 */
+	0xf0, 0x73,		/* 13.5 MHz transport, Forced
+				 * mode, latch windows */
+	0xf2, 0x13,		/* NTSC M, composite input */
+	0xe7, 0x1e1,		/* Enable vertical standard
+				 * locking @ 240 lines */
+};
+
+static const unsigned short init_pal[] = {
+	0x88, 23,		/* Window 1 vertical begin */
+	0x89, 288,		/* Vertical lines in (16 lines
+				 * skipped by the VFE) */
+	0x8a, 288,		/* Vertical lines out (16 lines
+				 * skipped by the VFE) */
+	0x8b, 16,		/* Horizontal begin */
+	0x8c, 768,		/* Horizontal length */
+	0x8d, 784, 		/* Number of pixels
+				 * Must be >= Horizontal begin + Horizontal length */
+	0x8f, 0xc00,		/* Disable window 2 */
+	0xf0, 0x77,		/* 13.5 MHz transport, Forced
+				 * mode, latch windows */
+	0xf2, 0x3d1,		/* PAL B,G,H,I, composite input */
+	0xe7, 0x241,		/* PAL/SECAM set to 288 lines */
+};
+
+static const unsigned short init_secam[] = {
+	0x88, 23,		/* Window 1 vertical begin */
+	0x89, 288,		/* Vertical lines in (16 lines
+				 * skipped by the VFE) */
+	0x8a, 288,		/* Vertical lines out (16 lines
+				 * skipped by the VFE) */
+	0x8b, 16,		/* Horizontal begin */
+	0x8c, 768,		/* Horizontal length */
+	0x8d, 784,		/* Number of pixels
+				 * Must be >= Horizontal begin + Horizontal length */
+	0x8f, 0xc00,		/* Disable window 2 */
+	0xf0, 0x77,		/* 13.5 MHz transport, Forced
+				 * mode, latch windows */
+	0xf2, 0x3d5,		/* SECAM, composite input */
+	0xe7, 0x241,		/* PAL/SECAM set to 288 lines */
+};
+
+static const unsigned char init_common[] = {
+	0xf2, 0x00,		/* Disable all outputs */
+	0x33, 0x0d,		/* Luma : VIN2, Chroma : CIN
+				 * (clamp off) */
+	0xd8, 0xa8,		/* HREF/VREF active high, VREF
+				 * pulse = 2, Odd/Even flag */
+	0x20, 0x03,		/* IF compensation 0dB/oct */
+	0xe0, 0xff,		/* Open up all comparators */
+	0xe1, 0x00,
+	0xe2, 0x7f,
+	0xe3, 0x80,
+	0xe4, 0x7f,
+	0xe5, 0x80,
+	0xe6, 0x00,		/* Brightness set to 0 */
+	0xe7, 0xe0,		/* Contrast to 1.0, noise shaping
+				 * 10 to 8 2-bit error diffusion */
+	0xe8, 0xf8,		/* YUV422, CbCr binary offset,
+				 * ... (p.32) */
+	0xea, 0x18,		/* LLC2 connected, output FIFO
+				 * reset with VACTintern */
+	0xf0, 0x8a,		/* Half full level to 10, bus
+				 * shuffler [7:0, 23:16, 15:8] */
+	0xf1, 0x18,		/* Single clock, sync mode, no
+				 * FE delay, no HLEN counter */
+	0xf8, 0x12,		/* Port A, PIXCLK, HF# & FE#
+				 * strength to 2 */
+	0xf9, 0x24,		/* Port B, HREF, VREF, PREF &
+				 * ALPHA strength to 4 */
+};
+
+static const unsigned short init_fp[] = {
+	0x59, 0,
+	0xa0, 2070,		/* ACC reference */
+	0xa3, 0,
+	0xa4, 0,
+	0xa8, 30,
+	0xb2, 768,
+	0xbe, 27,
+	0x58, 0,
+	0x26, 0,
+	0x4b, 0x298,		/* PLL gain */
+};
+
+
+static int vpx3220_init(struct v4l2_subdev *sd, u32 val)
+{
+	struct vpx3220 *decoder = to_vpx3220(sd);
+
+	vpx3220_write_block(sd, init_common, sizeof(init_common));
+	vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
+	if (decoder->norm & V4L2_STD_NTSC)
+		vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
+	else if (decoder->norm & V4L2_STD_PAL)
+		vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
+	else if (decoder->norm & V4L2_STD_SECAM)
+		vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1);
+	else
+		vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
+	return 0;
+}
+
+static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
+{
+	int res = V4L2_IN_ST_NO_SIGNAL, status;
+	v4l2_std_id std = 0;
+
+	status = vpx3220_fp_read(sd, 0x0f3);
+
+	v4l2_dbg(1, debug, sd, "status: 0x%04x\n", status);
+
+	if (status < 0)
+		return status;
+
+	if ((status & 0x20) == 0) {
+		res = 0;
+
+		switch (status & 0x18) {
+		case 0x00:
+		case 0x10:
+		case 0x14:
+		case 0x18:
+			std = V4L2_STD_PAL;
+			break;
+
+		case 0x08:
+			std = V4L2_STD_SECAM;
+			break;
+
+		case 0x04:
+		case 0x0c:
+		case 0x1c:
+			std = V4L2_STD_NTSC;
+			break;
+		}
+	}
+	if (pstd)
+		*pstd = std;
+	if (pstatus)
+		*pstatus = res;
+	return 0;
+}
+
+static int vpx3220_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	v4l2_dbg(1, debug, sd, "querystd\n");
+	return vpx3220_status(sd, NULL, std);
+}
+
+static int vpx3220_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+	v4l2_dbg(1, debug, sd, "g_input_status\n");
+	return vpx3220_status(sd, status, NULL);
+}
+
+static int vpx3220_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct vpx3220 *decoder = to_vpx3220(sd);
+	int temp_input;
+
+	/* Here we back up the input selection because it gets
+	   overwritten when we fill the registers with the
+	   chosen video norm */
+	temp_input = vpx3220_fp_read(sd, 0xf2);
+
+	v4l2_dbg(1, debug, sd, "s_std %llx\n", (unsigned long long)std);
+	if (std & V4L2_STD_NTSC) {
+		vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
+		v4l2_dbg(1, debug, sd, "norm switched to NTSC\n");
+	} else if (std & V4L2_STD_PAL) {
+		vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
+		v4l2_dbg(1, debug, sd, "norm switched to PAL\n");
+	} else if (std & V4L2_STD_SECAM) {
+		vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1);
+		v4l2_dbg(1, debug, sd, "norm switched to SECAM\n");
+	} else {
+		return -EINVAL;
+	}
+
+	decoder->norm = std;
+
+	/* And here we set the backed up video input again */
+	vpx3220_fp_write(sd, 0xf2, temp_input | 0x0010);
+	udelay(10);
+	return 0;
+}
+
+static int vpx3220_s_routing(struct v4l2_subdev *sd,
+			     u32 input, u32 output, u32 config)
+{
+	int data;
+
+	/* RJ:   input = 0: ST8 (PCTV) input
+		 input = 1: COMPOSITE  input
+		 input = 2: SVHS       input  */
+
+	const int input_vals[3][2] = {
+		{0x0c, 0},
+		{0x0d, 0},
+		{0x0e, 1}
+	};
+
+	if (input > 2)
+		return -EINVAL;
+
+	v4l2_dbg(1, debug, sd, "input switched to %s\n", inputs[input]);
+
+	vpx3220_write(sd, 0x33, input_vals[input][0]);
+
+	data = vpx3220_fp_read(sd, 0xf2) & ~(0x0020);
+	if (data < 0)
+		return data;
+	/* 0x0010 is required to latch the setting */
+	vpx3220_fp_write(sd, 0xf2,
+			data | (input_vals[input][1] << 5) | 0x0010);
+
+	udelay(10);
+	return 0;
+}
+
+static int vpx3220_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	v4l2_dbg(1, debug, sd, "s_stream %s\n", enable ? "on" : "off");
+
+	vpx3220_write(sd, 0xf2, (enable ? 0x1b : 0x00));
+	return 0;
+}
+
+static int vpx3220_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		vpx3220_write(sd, 0xe6, ctrl->val);
+		return 0;
+	case V4L2_CID_CONTRAST:
+		/* Bit 7 and 8 is for noise shaping */
+		vpx3220_write(sd, 0xe7, ctrl->val + 192);
+		return 0;
+	case V4L2_CID_SATURATION:
+		vpx3220_fp_write(sd, 0xa0, ctrl->val);
+		return 0;
+	case V4L2_CID_HUE:
+		vpx3220_fp_write(sd, 0x1c, ctrl->val);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct vpx3220 *decoder = to_vpx3220(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_ctrl_ops vpx3220_ctrl_ops = {
+	.s_ctrl = vpx3220_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops vpx3220_core_ops = {
+	.g_chip_ident = vpx3220_g_chip_ident,
+	.init = vpx3220_init,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+	.s_std = vpx3220_s_std,
+};
+
+static const struct v4l2_subdev_video_ops vpx3220_video_ops = {
+	.s_routing = vpx3220_s_routing,
+	.s_stream = vpx3220_s_stream,
+	.querystd = vpx3220_querystd,
+	.g_input_status = vpx3220_g_input_status,
+};
+
+static const struct v4l2_subdev_ops vpx3220_ops = {
+	.core = &vpx3220_core_ops,
+	.video = &vpx3220_video_ops,
+};
+
+/* -----------------------------------------------------------------------
+ * Client management code
+ */
+
+static int vpx3220_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct vpx3220 *decoder;
+	struct v4l2_subdev *sd;
+	const char *name = NULL;
+	u8 ver;
+	u16 pn;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter,
+		I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL);
+	if (decoder == NULL)
+		return -ENOMEM;
+	sd = &decoder->sd;
+	v4l2_i2c_subdev_init(sd, client, &vpx3220_ops);
+	decoder->norm = V4L2_STD_PAL;
+	decoder->input = 0;
+	decoder->enable = 1;
+	v4l2_ctrl_handler_init(&decoder->hdl, 4);
+	v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
+		V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
+	v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
+		V4L2_CID_CONTRAST, 0, 63, 1, 32);
+	v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
+		V4L2_CID_SATURATION, 0, 4095, 1, 2048);
+	v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
+		V4L2_CID_HUE, -512, 511, 1, 0);
+	sd->ctrl_handler = &decoder->hdl;
+	if (decoder->hdl.error) {
+		int err = decoder->hdl.error;
+
+		v4l2_ctrl_handler_free(&decoder->hdl);
+		kfree(decoder);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&decoder->hdl);
+
+	ver = i2c_smbus_read_byte_data(client, 0x00);
+	pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) +
+		i2c_smbus_read_byte_data(client, 0x01);
+	decoder->ident = V4L2_IDENT_VPX3220A;
+	if (ver == 0xec) {
+		switch (pn) {
+		case 0x4680:
+			name = "vpx3220a";
+			break;
+		case 0x4260:
+			name = "vpx3216b";
+			decoder->ident = V4L2_IDENT_VPX3216B;
+			break;
+		case 0x4280:
+			name = "vpx3214c";
+			decoder->ident = V4L2_IDENT_VPX3214C;
+			break;
+		}
+	}
+	if (name)
+		v4l2_info(sd, "%s found @ 0x%x (%s)\n", name,
+			client->addr << 1, client->adapter->name);
+	else
+		v4l2_info(sd, "chip (%02x:%04x) found @ 0x%x (%s)\n",
+			ver, pn, client->addr << 1, client->adapter->name);
+
+	vpx3220_write_block(sd, init_common, sizeof(init_common));
+	vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
+	/* Default to PAL */
+	vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
+	return 0;
+}
+
+static int vpx3220_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct vpx3220 *decoder = to_vpx3220(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&decoder->hdl);
+	kfree(decoder);
+	return 0;
+}
+
+static const struct i2c_device_id vpx3220_id[] = {
+	{ "vpx3220a", 0 },
+	{ "vpx3216b", 0 },
+	{ "vpx3214c", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, vpx3220_id);
+
+static struct i2c_driver vpx3220_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "vpx3220",
+	},
+	.probe		= vpx3220_probe,
+	.remove		= vpx3220_remove,
+	.id_table	= vpx3220_id,
+};
+
+module_i2c_driver(vpx3220_driver);
diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c
new file mode 100644
index 0000000..42ae9dc
--- /dev/null
+++ b/drivers/media/i2c/vs6624.c
@@ -0,0 +1,928 @@
+/*
+ * vs6624.c ST VS6624 CMOS image sensor driver
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+
+#include "vs6624_regs.h"
+
+#define VGA_WIDTH       640
+#define VGA_HEIGHT      480
+#define QVGA_WIDTH      320
+#define QVGA_HEIGHT     240
+#define QQVGA_WIDTH     160
+#define QQVGA_HEIGHT    120
+#define CIF_WIDTH       352
+#define CIF_HEIGHT      288
+#define QCIF_WIDTH      176
+#define QCIF_HEIGHT     144
+#define QQCIF_WIDTH     88
+#define QQCIF_HEIGHT    72
+
+#define MAX_FRAME_RATE  30
+
+struct vs6624 {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	struct v4l2_fract frame_rate;
+	struct v4l2_mbus_framefmt fmt;
+	unsigned ce_pin;
+};
+
+static const struct vs6624_format {
+	enum v4l2_mbus_pixelcode mbus_code;
+	enum v4l2_colorspace colorspace;
+} vs6624_formats[] = {
+	{
+		.mbus_code      = V4L2_MBUS_FMT_UYVY8_2X8,
+		.colorspace     = V4L2_COLORSPACE_JPEG,
+	},
+	{
+		.mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
+		.colorspace     = V4L2_COLORSPACE_JPEG,
+	},
+	{
+		.mbus_code      = V4L2_MBUS_FMT_RGB565_2X8_LE,
+		.colorspace     = V4L2_COLORSPACE_SRGB,
+	},
+};
+
+static struct v4l2_mbus_framefmt vs6624_default_fmt = {
+	.width = VGA_WIDTH,
+	.height = VGA_HEIGHT,
+	.code = V4L2_MBUS_FMT_UYVY8_2X8,
+	.field = V4L2_FIELD_NONE,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+};
+
+static const u16 vs6624_p1[] = {
+	0x8104, 0x03,
+	0x8105, 0x01,
+	0xc900, 0x03,
+	0xc904, 0x47,
+	0xc905, 0x10,
+	0xc906, 0x80,
+	0xc907, 0x3a,
+	0x903a, 0x02,
+	0x903b, 0x47,
+	0x903c, 0x15,
+	0xc908, 0x31,
+	0xc909, 0xdc,
+	0xc90a, 0x80,
+	0xc90b, 0x44,
+	0x9044, 0x02,
+	0x9045, 0x31,
+	0x9046, 0xe2,
+	0xc90c, 0x07,
+	0xc90d, 0xe0,
+	0xc90e, 0x80,
+	0xc90f, 0x47,
+	0x9047, 0x90,
+	0x9048, 0x83,
+	0x9049, 0x81,
+	0x904a, 0xe0,
+	0x904b, 0x60,
+	0x904c, 0x08,
+	0x904d, 0x90,
+	0x904e, 0xc0,
+	0x904f, 0x43,
+	0x9050, 0x74,
+	0x9051, 0x01,
+	0x9052, 0xf0,
+	0x9053, 0x80,
+	0x9054, 0x05,
+	0x9055, 0xE4,
+	0x9056, 0x90,
+	0x9057, 0xc0,
+	0x9058, 0x43,
+	0x9059, 0xf0,
+	0x905a, 0x02,
+	0x905b, 0x07,
+	0x905c, 0xec,
+	0xc910, 0x5d,
+	0xc911, 0xca,
+	0xc912, 0x80,
+	0xc913, 0x5d,
+	0x905d, 0xa3,
+	0x905e, 0x04,
+	0x905f, 0xf0,
+	0x9060, 0xa3,
+	0x9061, 0x04,
+	0x9062, 0xf0,
+	0x9063, 0x22,
+	0xc914, 0x72,
+	0xc915, 0x92,
+	0xc916, 0x80,
+	0xc917, 0x64,
+	0x9064, 0x74,
+	0x9065, 0x01,
+	0x9066, 0x02,
+	0x9067, 0x72,
+	0x9068, 0x95,
+	0xc918, 0x47,
+	0xc919, 0xf2,
+	0xc91a, 0x81,
+	0xc91b, 0x69,
+	0x9169, 0x74,
+	0x916a, 0x02,
+	0x916b, 0xf0,
+	0x916c, 0xec,
+	0x916d, 0xb4,
+	0x916e, 0x10,
+	0x916f, 0x0a,
+	0x9170, 0x90,
+	0x9171, 0x80,
+	0x9172, 0x16,
+	0x9173, 0xe0,
+	0x9174, 0x70,
+	0x9175, 0x04,
+	0x9176, 0x90,
+	0x9177, 0xd3,
+	0x9178, 0xc4,
+	0x9179, 0xf0,
+	0x917a, 0x22,
+	0xc91c, 0x0a,
+	0xc91d, 0xbe,
+	0xc91e, 0x80,
+	0xc91f, 0x73,
+	0x9073, 0xfc,
+	0x9074, 0xa3,
+	0x9075, 0xe0,
+	0x9076, 0xf5,
+	0x9077, 0x82,
+	0x9078, 0x8c,
+	0x9079, 0x83,
+	0x907a, 0xa3,
+	0x907b, 0xa3,
+	0x907c, 0xe0,
+	0x907d, 0xfc,
+	0x907e, 0xa3,
+	0x907f, 0xe0,
+	0x9080, 0xc3,
+	0x9081, 0x9f,
+	0x9082, 0xff,
+	0x9083, 0xec,
+	0x9084, 0x9e,
+	0x9085, 0xfe,
+	0x9086, 0x02,
+	0x9087, 0x0a,
+	0x9088, 0xea,
+	0xc920, 0x47,
+	0xc921, 0x38,
+	0xc922, 0x80,
+	0xc923, 0x89,
+	0x9089, 0xec,
+	0x908a, 0xd3,
+	0x908b, 0x94,
+	0x908c, 0x20,
+	0x908d, 0x40,
+	0x908e, 0x01,
+	0x908f, 0x1c,
+	0x9090, 0x90,
+	0x9091, 0xd3,
+	0x9092, 0xd4,
+	0x9093, 0xec,
+	0x9094, 0xf0,
+	0x9095, 0x02,
+	0x9096, 0x47,
+	0x9097, 0x3d,
+	0xc924, 0x45,
+	0xc925, 0xca,
+	0xc926, 0x80,
+	0xc927, 0x98,
+	0x9098, 0x12,
+	0x9099, 0x77,
+	0x909a, 0xd6,
+	0x909b, 0x02,
+	0x909c, 0x45,
+	0x909d, 0xcd,
+	0xc928, 0x20,
+	0xc929, 0xd5,
+	0xc92a, 0x80,
+	0xc92b, 0x9e,
+	0x909e, 0x90,
+	0x909f, 0x82,
+	0x90a0, 0x18,
+	0x90a1, 0xe0,
+	0x90a2, 0xb4,
+	0x90a3, 0x03,
+	0x90a4, 0x0e,
+	0x90a5, 0x90,
+	0x90a6, 0x83,
+	0x90a7, 0xbf,
+	0x90a8, 0xe0,
+	0x90a9, 0x60,
+	0x90aa, 0x08,
+	0x90ab, 0x90,
+	0x90ac, 0x81,
+	0x90ad, 0xfc,
+	0x90ae, 0xe0,
+	0x90af, 0xff,
+	0x90b0, 0xc3,
+	0x90b1, 0x13,
+	0x90b2, 0xf0,
+	0x90b3, 0x90,
+	0x90b4, 0x81,
+	0x90b5, 0xfc,
+	0x90b6, 0xe0,
+	0x90b7, 0xff,
+	0x90b8, 0x02,
+	0x90b9, 0x20,
+	0x90ba, 0xda,
+	0xc92c, 0x70,
+	0xc92d, 0xbc,
+	0xc92e, 0x80,
+	0xc92f, 0xbb,
+	0x90bb, 0x90,
+	0x90bc, 0x82,
+	0x90bd, 0x18,
+	0x90be, 0xe0,
+	0x90bf, 0xb4,
+	0x90c0, 0x03,
+	0x90c1, 0x06,
+	0x90c2, 0x90,
+	0x90c3, 0xc1,
+	0x90c4, 0x06,
+	0x90c5, 0x74,
+	0x90c6, 0x05,
+	0x90c7, 0xf0,
+	0x90c8, 0x90,
+	0x90c9, 0xd3,
+	0x90ca, 0xa0,
+	0x90cb, 0x02,
+	0x90cc, 0x70,
+	0x90cd, 0xbf,
+	0xc930, 0x72,
+	0xc931, 0x21,
+	0xc932, 0x81,
+	0xc933, 0x3b,
+	0x913b, 0x7d,
+	0x913c, 0x02,
+	0x913d, 0x7f,
+	0x913e, 0x7b,
+	0x913f, 0x02,
+	0x9140, 0x72,
+	0x9141, 0x25,
+	0xc934, 0x28,
+	0xc935, 0xae,
+	0xc936, 0x80,
+	0xc937, 0xd2,
+	0x90d2, 0xf0,
+	0x90d3, 0x90,
+	0x90d4, 0xd2,
+	0x90d5, 0x0a,
+	0x90d6, 0x02,
+	0x90d7, 0x28,
+	0x90d8, 0xb4,
+	0xc938, 0x28,
+	0xc939, 0xb1,
+	0xc93a, 0x80,
+	0xc93b, 0xd9,
+	0x90d9, 0x90,
+	0x90da, 0x83,
+	0x90db, 0xba,
+	0x90dc, 0xe0,
+	0x90dd, 0xff,
+	0x90de, 0x90,
+	0x90df, 0xd2,
+	0x90e0, 0x08,
+	0x90e1, 0xe0,
+	0x90e2, 0xe4,
+	0x90e3, 0xef,
+	0x90e4, 0xf0,
+	0x90e5, 0xa3,
+	0x90e6, 0xe0,
+	0x90e7, 0x74,
+	0x90e8, 0xff,
+	0x90e9, 0xf0,
+	0x90ea, 0x90,
+	0x90eb, 0xd2,
+	0x90ec, 0x0a,
+	0x90ed, 0x02,
+	0x90ee, 0x28,
+	0x90ef, 0xb4,
+	0xc93c, 0x29,
+	0xc93d, 0x79,
+	0xc93e, 0x80,
+	0xc93f, 0xf0,
+	0x90f0, 0xf0,
+	0x90f1, 0x90,
+	0x90f2, 0xd2,
+	0x90f3, 0x0e,
+	0x90f4, 0x02,
+	0x90f5, 0x29,
+	0x90f6, 0x7f,
+	0xc940, 0x29,
+	0xc941, 0x7c,
+	0xc942, 0x80,
+	0xc943, 0xf7,
+	0x90f7, 0x90,
+	0x90f8, 0x83,
+	0x90f9, 0xba,
+	0x90fa, 0xe0,
+	0x90fb, 0xff,
+	0x90fc, 0x90,
+	0x90fd, 0xd2,
+	0x90fe, 0x0c,
+	0x90ff, 0xe0,
+	0x9100, 0xe4,
+	0x9101, 0xef,
+	0x9102, 0xf0,
+	0x9103, 0xa3,
+	0x9104, 0xe0,
+	0x9105, 0x74,
+	0x9106, 0xff,
+	0x9107, 0xf0,
+	0x9108, 0x90,
+	0x9109, 0xd2,
+	0x910a, 0x0e,
+	0x910b, 0x02,
+	0x910c, 0x29,
+	0x910d, 0x7f,
+	0xc944, 0x2a,
+	0xc945, 0x42,
+	0xc946, 0x81,
+	0xc947, 0x0e,
+	0x910e, 0xf0,
+	0x910f, 0x90,
+	0x9110, 0xd2,
+	0x9111, 0x12,
+	0x9112, 0x02,
+	0x9113, 0x2a,
+	0x9114, 0x48,
+	0xc948, 0x2a,
+	0xc949, 0x45,
+	0xc94a, 0x81,
+	0xc94b, 0x15,
+	0x9115, 0x90,
+	0x9116, 0x83,
+	0x9117, 0xba,
+	0x9118, 0xe0,
+	0x9119, 0xff,
+	0x911a, 0x90,
+	0x911b, 0xd2,
+	0x911c, 0x10,
+	0x911d, 0xe0,
+	0x911e, 0xe4,
+	0x911f, 0xef,
+	0x9120, 0xf0,
+	0x9121, 0xa3,
+	0x9122, 0xe0,
+	0x9123, 0x74,
+	0x9124, 0xff,
+	0x9125, 0xf0,
+	0x9126, 0x90,
+	0x9127, 0xd2,
+	0x9128, 0x12,
+	0x9129, 0x02,
+	0x912a, 0x2a,
+	0x912b, 0x48,
+	0xc900, 0x01,
+	0x0000, 0x00,
+};
+
+static const u16 vs6624_p2[] = {
+	0x806f, 0x01,
+	0x058c, 0x01,
+	0x0000, 0x00,
+};
+
+static const u16 vs6624_run_setup[] = {
+	0x1d18, 0x00,				/* Enableconstrainedwhitebalance */
+	VS6624_PEAK_MIN_OUT_G_MSB, 0x3c,	/* Damper PeakGain Output MSB */
+	VS6624_PEAK_MIN_OUT_G_LSB, 0x66,	/* Damper PeakGain Output LSB */
+	VS6624_CM_LOW_THR_MSB, 0x65,		/* Damper Low MSB */
+	VS6624_CM_LOW_THR_LSB, 0xd1,		/* Damper Low LSB */
+	VS6624_CM_HIGH_THR_MSB, 0x66,		/* Damper High MSB */
+	VS6624_CM_HIGH_THR_LSB, 0x62,		/* Damper High LSB */
+	VS6624_CM_MIN_OUT_MSB, 0x00,		/* Damper Min output MSB */
+	VS6624_CM_MIN_OUT_LSB, 0x00,		/* Damper Min output LSB */
+	VS6624_NORA_DISABLE, 0x00,		/* Nora fDisable */
+	VS6624_NORA_USAGE, 0x04,		/* Nora usage */
+	VS6624_NORA_LOW_THR_MSB, 0x63,		/* Damper Low MSB Changed 0x63 to 0x65 */
+	VS6624_NORA_LOW_THR_LSB, 0xd1,		/* Damper Low LSB */
+	VS6624_NORA_HIGH_THR_MSB, 0x68,		/* Damper High MSB */
+	VS6624_NORA_HIGH_THR_LSB, 0xdd,		/* Damper High LSB */
+	VS6624_NORA_MIN_OUT_MSB, 0x3a,		/* Damper Min output MSB */
+	VS6624_NORA_MIN_OUT_LSB, 0x00,		/* Damper Min output LSB */
+	VS6624_F2B_DISABLE, 0x00,		/* Disable */
+	0x1d8a, 0x30,				/* MAXWeightHigh */
+	0x1d91, 0x62,				/* fpDamperLowThresholdHigh MSB */
+	0x1d92, 0x4a,				/* fpDamperLowThresholdHigh LSB */
+	0x1d95, 0x65,				/* fpDamperHighThresholdHigh MSB */
+	0x1d96, 0x0e,				/* fpDamperHighThresholdHigh LSB */
+	0x1da1, 0x3a,				/* fpMinimumDamperOutputLow MSB */
+	0x1da2, 0xb8,				/* fpMinimumDamperOutputLow LSB */
+	0x1e08, 0x06,				/* MAXWeightLow */
+	0x1e0a, 0x0a,				/* MAXWeightHigh */
+	0x1601, 0x3a,				/* Red A MSB */
+	0x1602, 0x14,				/* Red A LSB */
+	0x1605, 0x3b,				/* Blue A MSB */
+	0x1606, 0x85,				/* BLue A LSB */
+	0x1609, 0x3b,				/* RED B MSB */
+	0x160a, 0x85,				/* RED B LSB */
+	0x160d, 0x3a,				/* Blue B MSB */
+	0x160e, 0x14,				/* Blue B LSB */
+	0x1611, 0x30,				/* Max Distance from Locus MSB */
+	0x1612, 0x8f,				/* Max Distance from Locus MSB */
+	0x1614, 0x01,				/* Enable constrainer */
+	0x0000, 0x00,
+};
+
+static const u16 vs6624_default[] = {
+	VS6624_CONTRAST0, 0x84,
+	VS6624_SATURATION0, 0x75,
+	VS6624_GAMMA0, 0x11,
+	VS6624_CONTRAST1, 0x84,
+	VS6624_SATURATION1, 0x75,
+	VS6624_GAMMA1, 0x11,
+	VS6624_MAN_RG, 0x80,
+	VS6624_MAN_GG, 0x80,
+	VS6624_MAN_BG, 0x80,
+	VS6624_WB_MODE, 0x1,
+	VS6624_EXPO_COMPENSATION, 0xfe,
+	VS6624_EXPO_METER, 0x0,
+	VS6624_LIGHT_FREQ, 0x64,
+	VS6624_PEAK_GAIN, 0xe,
+	VS6624_PEAK_LOW_THR, 0x28,
+	VS6624_HMIRROR0, 0x0,
+	VS6624_VFLIP0, 0x0,
+	VS6624_ZOOM_HSTEP0_MSB, 0x0,
+	VS6624_ZOOM_HSTEP0_LSB, 0x1,
+	VS6624_ZOOM_VSTEP0_MSB, 0x0,
+	VS6624_ZOOM_VSTEP0_LSB, 0x1,
+	VS6624_PAN_HSTEP0_MSB, 0x0,
+	VS6624_PAN_HSTEP0_LSB, 0xf,
+	VS6624_PAN_VSTEP0_MSB, 0x0,
+	VS6624_PAN_VSTEP0_LSB, 0xf,
+	VS6624_SENSOR_MODE, 0x1,
+	VS6624_SYNC_CODE_SETUP, 0x21,
+	VS6624_DISABLE_FR_DAMPER, 0x0,
+	VS6624_FR_DEN, 0x1,
+	VS6624_FR_NUM_LSB, 0xf,
+	VS6624_INIT_PIPE_SETUP, 0x0,
+	VS6624_IMG_FMT0, 0x0,
+	VS6624_YUV_SETUP, 0x1,
+	VS6624_IMAGE_SIZE0, 0x2,
+	0x0000, 0x00,
+};
+
+static inline struct vs6624 *to_vs6624(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct vs6624, sd);
+}
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct vs6624, hdl)->sd;
+}
+
+static int vs6624_read(struct v4l2_subdev *sd, u16 index)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 buf[2];
+
+	buf[0] = index >> 8;
+	buf[1] = index;
+	i2c_master_send(client, buf, 2);
+	i2c_master_recv(client, buf, 1);
+
+	return buf[0];
+}
+
+static int vs6624_write(struct v4l2_subdev *sd, u16 index,
+				u8 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 buf[3];
+
+	buf[0] = index >> 8;
+	buf[1] = index;
+	buf[2] = value;
+
+	return i2c_master_send(client, buf, 3);
+}
+
+static int vs6624_writeregs(struct v4l2_subdev *sd, const u16 *regs)
+{
+	u16 reg;
+	u8 data;
+
+	while (*regs != 0x00) {
+		reg = *regs++;
+		data = *regs++;
+
+		vs6624_write(sd, reg, data);
+	}
+	return 0;
+}
+
+static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_CONTRAST:
+		vs6624_write(sd, VS6624_CONTRAST0, ctrl->val);
+		break;
+	case V4L2_CID_SATURATION:
+		vs6624_write(sd, VS6624_SATURATION0, ctrl->val);
+		break;
+	case V4L2_CID_HFLIP:
+		vs6624_write(sd, VS6624_HMIRROR0, ctrl->val);
+		break;
+	case V4L2_CID_VFLIP:
+		vs6624_write(sd, VS6624_VFLIP0, ctrl->val);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vs6624_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+				enum v4l2_mbus_pixelcode *code)
+{
+	if (index >= ARRAY_SIZE(vs6624_formats))
+		return -EINVAL;
+
+	*code = vs6624_formats[index].mbus_code;
+	return 0;
+}
+
+static int vs6624_try_mbus_fmt(struct v4l2_subdev *sd,
+				struct v4l2_mbus_framefmt *fmt)
+{
+	int index;
+
+	for (index = 0; index < ARRAY_SIZE(vs6624_formats); index++)
+		if (vs6624_formats[index].mbus_code == fmt->code)
+			break;
+	if (index >= ARRAY_SIZE(vs6624_formats)) {
+		/* default to first format */
+		index = 0;
+		fmt->code = vs6624_formats[0].mbus_code;
+	}
+
+	/* sensor mode is VGA */
+	if (fmt->width > VGA_WIDTH)
+		fmt->width = VGA_WIDTH;
+	if (fmt->height > VGA_HEIGHT)
+		fmt->height = VGA_HEIGHT;
+	fmt->width = fmt->width & (~3);
+	fmt->height = fmt->height & (~3);
+	fmt->field = V4L2_FIELD_NONE;
+	fmt->colorspace = vs6624_formats[index].colorspace;
+	return 0;
+}
+
+static int vs6624_s_mbus_fmt(struct v4l2_subdev *sd,
+				struct v4l2_mbus_framefmt *fmt)
+{
+	struct vs6624 *sensor = to_vs6624(sd);
+	int ret;
+
+	ret = vs6624_try_mbus_fmt(sd, fmt);
+	if (ret)
+		return ret;
+
+	/* set image format */
+	switch (fmt->code) {
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
+		vs6624_write(sd, VS6624_YUV_SETUP, 0x1);
+		break;
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+		vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
+		vs6624_write(sd, VS6624_YUV_SETUP, 0x3);
+		break;
+	case V4L2_MBUS_FMT_RGB565_2X8_LE:
+		vs6624_write(sd, VS6624_IMG_FMT0, 0x4);
+		vs6624_write(sd, VS6624_RGB_SETUP, 0x0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set image size */
+	if ((fmt->width == VGA_WIDTH) && (fmt->height == VGA_HEIGHT))
+		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x2);
+	else if ((fmt->width == QVGA_WIDTH) && (fmt->height == QVGA_HEIGHT))
+		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x4);
+	else if ((fmt->width == QQVGA_WIDTH) && (fmt->height == QQVGA_HEIGHT))
+		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x6);
+	else if ((fmt->width == CIF_WIDTH) && (fmt->height == CIF_HEIGHT))
+		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x3);
+	else if ((fmt->width == QCIF_WIDTH) && (fmt->height == QCIF_HEIGHT))
+		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x5);
+	else if ((fmt->width == QQCIF_WIDTH) && (fmt->height == QQCIF_HEIGHT))
+		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x7);
+	else {
+		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x8);
+		vs6624_write(sd, VS6624_MAN_HSIZE0_MSB, fmt->width >> 8);
+		vs6624_write(sd, VS6624_MAN_HSIZE0_LSB, fmt->width & 0xFF);
+		vs6624_write(sd, VS6624_MAN_VSIZE0_MSB, fmt->height >> 8);
+		vs6624_write(sd, VS6624_MAN_VSIZE0_LSB, fmt->height & 0xFF);
+		vs6624_write(sd, VS6624_CROP_CTRL0, 0x1);
+	}
+
+	sensor->fmt = *fmt;
+
+	return 0;
+}
+
+static int vs6624_g_mbus_fmt(struct v4l2_subdev *sd,
+				struct v4l2_mbus_framefmt *fmt)
+{
+	struct vs6624 *sensor = to_vs6624(sd);
+
+	*fmt = sensor->fmt;
+	return 0;
+}
+
+static int vs6624_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+	struct vs6624 *sensor = to_vs6624(sd);
+	struct v4l2_captureparm *cp = &parms->parm.capture;
+
+	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	memset(cp, 0, sizeof(*cp));
+	cp->capability = V4L2_CAP_TIMEPERFRAME;
+	cp->timeperframe.numerator = sensor->frame_rate.denominator;
+	cp->timeperframe.denominator = sensor->frame_rate.numerator;
+	return 0;
+}
+
+static int vs6624_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+	struct vs6624 *sensor = to_vs6624(sd);
+	struct v4l2_captureparm *cp = &parms->parm.capture;
+	struct v4l2_fract *tpf = &cp->timeperframe;
+
+	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (cp->extendedmode != 0)
+		return -EINVAL;
+
+	if (tpf->numerator == 0 || tpf->denominator == 0
+		|| (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) {
+		/* reset to max frame rate */
+		tpf->numerator = 1;
+		tpf->denominator = MAX_FRAME_RATE;
+	}
+	sensor->frame_rate.numerator = tpf->denominator;
+	sensor->frame_rate.denominator = tpf->numerator;
+	vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
+	vs6624_write(sd, VS6624_FR_NUM_MSB,
+			sensor->frame_rate.numerator >> 8);
+	vs6624_write(sd, VS6624_FR_NUM_LSB,
+			sensor->frame_rate.numerator & 0xFF);
+	vs6624_write(sd, VS6624_FR_DEN,
+			sensor->frame_rate.denominator & 0xFF);
+	return 0;
+}
+
+static int vs6624_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	if (enable)
+		vs6624_write(sd, VS6624_USER_CMD, 0x2);
+	else
+		vs6624_write(sd, VS6624_USER_CMD, 0x4);
+	udelay(100);
+	return 0;
+}
+
+static int vs6624_g_chip_ident(struct v4l2_subdev *sd,
+		struct v4l2_dbg_chip_ident *chip)
+{
+	int rev;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	rev = (vs6624_read(sd, VS6624_FW_VSN_MAJOR) << 8)
+		| vs6624_read(sd, VS6624_FW_VSN_MINOR);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_VS6624, rev);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	reg->val = vs6624_read(sd, reg->reg & 0xffff);
+	reg->size = 1;
+	return 0;
+}
+
+static int vs6624_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff);
+	return 0;
+}
+#endif
+
+static const struct v4l2_ctrl_ops vs6624_ctrl_ops = {
+	.s_ctrl = vs6624_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops vs6624_core_ops = {
+	.g_chip_ident = vs6624_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = vs6624_g_register,
+	.s_register = vs6624_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops vs6624_video_ops = {
+	.enum_mbus_fmt = vs6624_enum_mbus_fmt,
+	.try_mbus_fmt = vs6624_try_mbus_fmt,
+	.s_mbus_fmt = vs6624_s_mbus_fmt,
+	.g_mbus_fmt = vs6624_g_mbus_fmt,
+	.s_parm = vs6624_s_parm,
+	.g_parm = vs6624_g_parm,
+	.s_stream = vs6624_s_stream,
+};
+
+static const struct v4l2_subdev_ops vs6624_ops = {
+	.core = &vs6624_core_ops,
+	.video = &vs6624_video_ops,
+};
+
+static int __devinit vs6624_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct vs6624 *sensor;
+	struct v4l2_subdev *sd;
+	struct v4l2_ctrl_handler *hdl;
+	const unsigned *ce;
+	int ret;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+		return -EIO;
+
+	ce = client->dev.platform_data;
+	if (ce == NULL)
+		return -EINVAL;
+
+	ret = gpio_request(*ce, "VS6624 Chip Enable");
+	if (ret) {
+		v4l_err(client, "failed to request GPIO %d\n", *ce);
+		return ret;
+	}
+	gpio_direction_output(*ce, 1);
+	/* wait 100ms before any further i2c writes are performed */
+	mdelay(100);
+
+	sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
+	if (sensor == NULL) {
+		gpio_free(*ce);
+		return -ENOMEM;
+	}
+
+	sd = &sensor->sd;
+	v4l2_i2c_subdev_init(sd, client, &vs6624_ops);
+
+	vs6624_writeregs(sd, vs6624_p1);
+	vs6624_write(sd, VS6624_MICRO_EN, 0x2);
+	vs6624_write(sd, VS6624_DIO_EN, 0x1);
+	mdelay(10);
+	vs6624_writeregs(sd, vs6624_p2);
+
+	vs6624_writeregs(sd, vs6624_default);
+	vs6624_write(sd, VS6624_HSYNC_SETUP, 0xF);
+	vs6624_writeregs(sd, vs6624_run_setup);
+
+	/* set frame rate */
+	sensor->frame_rate.numerator = MAX_FRAME_RATE;
+	sensor->frame_rate.denominator = 1;
+	vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
+	vs6624_write(sd, VS6624_FR_NUM_MSB,
+			sensor->frame_rate.numerator >> 8);
+	vs6624_write(sd, VS6624_FR_NUM_LSB,
+			sensor->frame_rate.numerator & 0xFF);
+	vs6624_write(sd, VS6624_FR_DEN,
+			sensor->frame_rate.denominator & 0xFF);
+
+	sensor->fmt = vs6624_default_fmt;
+	sensor->ce_pin = *ce;
+
+	v4l_info(client, "chip found @ 0x%02x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	hdl = &sensor->hdl;
+	v4l2_ctrl_handler_init(hdl, 4);
+	v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x87);
+	v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 0xFF, 1, 0x78);
+	v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
+			V4L2_CID_HFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+	/* hook the control handler into the driver */
+	sd->ctrl_handler = hdl;
+	if (hdl->error) {
+		int err = hdl->error;
+
+		v4l2_ctrl_handler_free(hdl);
+		kfree(sensor);
+		gpio_free(*ce);
+		return err;
+	}
+
+	/* initialize the hardware to the default control values */
+	ret = v4l2_ctrl_handler_setup(hdl);
+	if (ret) {
+		v4l2_ctrl_handler_free(hdl);
+		kfree(sensor);
+		gpio_free(*ce);
+	}
+	return ret;
+}
+
+static int __devexit vs6624_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct vs6624 *sensor = to_vs6624(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(sd->ctrl_handler);
+	gpio_free(sensor->ce_pin);
+	kfree(sensor);
+	return 0;
+}
+
+static const struct i2c_device_id vs6624_id[] = {
+	{"vs6624", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, vs6624_id);
+
+static struct i2c_driver vs6624_driver = {
+	.driver = {
+		.owner  = THIS_MODULE,
+		.name   = "vs6624",
+	},
+	.probe          = vs6624_probe,
+	.remove         = __devexit_p(vs6624_remove),
+	.id_table       = vs6624_id,
+};
+
+static __init int vs6624_init(void)
+{
+	return i2c_add_driver(&vs6624_driver);
+}
+
+static __exit void vs6624_exit(void)
+{
+	i2c_del_driver(&vs6624_driver);
+}
+
+module_init(vs6624_init);
+module_exit(vs6624_exit);
+
+MODULE_DESCRIPTION("VS6624 sensor driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/vs6624_regs.h b/drivers/media/i2c/vs6624_regs.h
new file mode 100644
index 0000000..6ba2ee2
--- /dev/null
+++ b/drivers/media/i2c/vs6624_regs.h
@@ -0,0 +1,337 @@
+/*
+ * vs6624 - ST VS6624 CMOS image sensor registers
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _VS6624_REGS_H_
+#define _VS6624_REGS_H_
+
+/* low level control registers */
+#define VS6624_MICRO_EN               0xC003 /* power enable for all MCU clock */
+#define VS6624_DIO_EN                 0xC044 /* enable digital I/O */
+/* device parameters */
+#define VS6624_DEV_ID_MSB             0x0001 /* device id MSB */
+#define VS6624_DEV_ID_LSB             0x0002 /* device id LSB */
+#define VS6624_FW_VSN_MAJOR           0x0004 /* firmware version major */
+#define VS6624_FW_VSN_MINOR           0x0006 /* firmware version minor */
+#define VS6624_PATCH_VSN_MAJOR        0x0008 /* patch version major */
+#define VS6624_PATCH_VSN_MINOR        0x000A /* patch version minor */
+/* host interface manager control */
+#define VS6624_USER_CMD               0x0180 /* user level control of operating states */
+/* host interface manager status */
+#define VS6624_STATE                  0x0202 /* current state of the mode manager */
+/* run mode control */
+#define VS6624_METER_ON               0x0280 /* if false AE and AWB are disabled */
+/* mode setup */
+#define VS6624_ACTIVE_PIPE_SETUP      0x0302 /* select the active bank for non view live mode */
+#define VS6624_SENSOR_MODE            0x0308 /* select the different sensor mode */
+/* pipe setup bank0 */
+#define VS6624_IMAGE_SIZE0            0x0380 /* required output dimension */
+#define VS6624_MAN_HSIZE0_MSB         0x0383 /* input required manual H size MSB */
+#define VS6624_MAN_HSIZE0_LSB         0x0384 /* input required manual H size LSB */
+#define VS6624_MAN_VSIZE0_MSB         0x0387 /* input required manual V size MSB */
+#define VS6624_MAN_VSIZE0_LSB         0x0388 /* input required manual V size LSB */
+#define VS6624_ZOOM_HSTEP0_MSB        0x038B /* set the zoom H step MSB */
+#define VS6624_ZOOM_HSTEP0_LSB        0x038C /* set the zoom H step LSB */
+#define VS6624_ZOOM_VSTEP0_MSB        0x038F /* set the zoom V step MSB */
+#define VS6624_ZOOM_VSTEP0_LSB        0x0390 /* set the zoom V step LSB */
+#define VS6624_ZOOM_CTRL0             0x0392 /* control zoon in, out and stop */
+#define VS6624_PAN_HSTEP0_MSB         0x0395 /* set the pan H step MSB */
+#define VS6624_PAN_HSTEP0_LSB         0x0396 /* set the pan H step LSB */
+#define VS6624_PAN_VSTEP0_MSB         0x0399 /* set the pan V step MSB */
+#define VS6624_PAN_VSTEP0_LSB         0x039A /* set the pan V step LSB */
+#define VS6624_PAN_CTRL0              0x039C /* control pan operation */
+#define VS6624_CROP_CTRL0             0x039E /* select cropping mode */
+#define VS6624_CROP_HSTART0_MSB       0x03A1 /* set the cropping H start address MSB */
+#define VS6624_CROP_HSTART0_LSB       0x03A2 /* set the cropping H start address LSB */
+#define VS6624_CROP_HSIZE0_MSB        0x03A5 /* set the cropping H size MSB */
+#define VS6624_CROP_HSIZE0_LSB        0x03A6 /* set the cropping H size LSB */
+#define VS6624_CROP_VSTART0_MSB       0x03A9 /* set the cropping V start address MSB */
+#define VS6624_CROP_VSTART0_LSB       0x03AA /* set the cropping V start address LSB */
+#define VS6624_CROP_VSIZE0_MSB        0x03AD /* set the cropping V size MSB */
+#define VS6624_CROP_VSIZE0_LSB        0x03AE /* set the cropping V size LSB */
+#define VS6624_IMG_FMT0               0x03B0 /* select required output image format */
+#define VS6624_BAYER_OUT_ALIGN0       0x03B2 /* set bayer output alignment */
+#define VS6624_CONTRAST0              0x03B4 /* contrast control for output */
+#define VS6624_SATURATION0            0x03B6 /* saturation control for output */
+#define VS6624_GAMMA0                 0x03B8 /* gamma settings */
+#define VS6624_HMIRROR0               0x03BA /* horizontal image orientation flip */
+#define VS6624_VFLIP0                 0x03BC /* vertical image orientation flip */
+#define VS6624_CHANNEL_ID0            0x03BE /* logical DMA channel number */
+/* pipe setup bank1 */
+#define VS6624_IMAGE_SIZE1            0x0400 /* required output dimension */
+#define VS6624_MAN_HSIZE1_MSB         0x0403 /* input required manual H size MSB */
+#define VS6624_MAN_HSIZE1_LSB         0x0404 /* input required manual H size LSB */
+#define VS6624_MAN_VSIZE1_MSB         0x0407 /* input required manual V size MSB */
+#define VS6624_MAN_VSIZE1_LSB         0x0408 /* input required manual V size LSB */
+#define VS6624_ZOOM_HSTEP1_MSB        0x040B /* set the zoom H step MSB */
+#define VS6624_ZOOM_HSTEP1_LSB        0x040C /* set the zoom H step LSB */
+#define VS6624_ZOOM_VSTEP1_MSB        0x040F /* set the zoom V step MSB */
+#define VS6624_ZOOM_VSTEP1_LSB        0x0410 /* set the zoom V step LSB */
+#define VS6624_ZOOM_CTRL1             0x0412 /* control zoon in, out and stop */
+#define VS6624_PAN_HSTEP1_MSB         0x0415 /* set the pan H step MSB */
+#define VS6624_PAN_HSTEP1_LSB         0x0416 /* set the pan H step LSB */
+#define VS6624_PAN_VSTEP1_MSB         0x0419 /* set the pan V step MSB */
+#define VS6624_PAN_VSTEP1_LSB         0x041A /* set the pan V step LSB */
+#define VS6624_PAN_CTRL1              0x041C /* control pan operation */
+#define VS6624_CROP_CTRL1             0x041E /* select cropping mode */
+#define VS6624_CROP_HSTART1_MSB       0x0421 /* set the cropping H start address MSB */
+#define VS6624_CROP_HSTART1_LSB       0x0422 /* set the cropping H start address LSB */
+#define VS6624_CROP_HSIZE1_MSB        0x0425 /* set the cropping H size MSB */
+#define VS6624_CROP_HSIZE1_LSB        0x0426 /* set the cropping H size LSB */
+#define VS6624_CROP_VSTART1_MSB       0x0429 /* set the cropping V start address MSB */
+#define VS6624_CROP_VSTART1_LSB       0x042A /* set the cropping V start address LSB */
+#define VS6624_CROP_VSIZE1_MSB        0x042D /* set the cropping V size MSB */
+#define VS6624_CROP_VSIZE1_LSB        0x042E /* set the cropping V size LSB */
+#define VS6624_IMG_FMT1               0x0430 /* select required output image format */
+#define VS6624_BAYER_OUT_ALIGN1       0x0432 /* set bayer output alignment */
+#define VS6624_CONTRAST1              0x0434 /* contrast control for output */
+#define VS6624_SATURATION1            0x0436 /* saturation control for output */
+#define VS6624_GAMMA1                 0x0438 /* gamma settings */
+#define VS6624_HMIRROR1               0x043A /* horizontal image orientation flip */
+#define VS6624_VFLIP1                 0x043C /* vertical image orientation flip */
+#define VS6624_CHANNEL_ID1            0x043E /* logical DMA channel number */
+/* view live control */
+#define VS6624_VIEW_LIVE_EN           0x0480 /* enable view live mode */
+#define VS6624_INIT_PIPE_SETUP        0x0482 /* select initial pipe setup bank */
+/* view live status */
+#define VS6624_CUR_PIPE_SETUP         0x0500 /* indicates most recently applied setup bank */
+/* power management */
+#define VS6624_TIME_TO_POWER_DOWN     0x0580 /* automatically transition time to stop mode */
+/* video timing parameter host inputs */
+#define VS6624_EXT_CLK_FREQ_NUM_MSB   0x0605 /* external clock frequency numerator MSB */
+#define VS6624_EXT_CLK_FREQ_NUM_LSB   0x0606 /* external clock frequency numerator LSB */
+#define VS6624_EXT_CLK_FREQ_DEN       0x0608 /* external clock frequency denominator */
+/* video timing control */
+#define VS6624_SYS_CLK_MODE           0x0880 /* decides system clock frequency */
+/* frame dimension parameter host inputs */
+#define VS6624_LIGHT_FREQ             0x0C80 /* AC frequency used for flicker free time */
+#define VS6624_FLICKER_COMPAT         0x0C82 /* flicker compatible frame length */
+/* static frame rate control */
+#define VS6624_FR_NUM_MSB             0x0D81 /* desired frame rate numerator MSB */
+#define VS6624_FR_NUM_LSB             0x0D82 /* desired frame rate numerator LSB */
+#define VS6624_FR_DEN                 0x0D84 /* desired frame rate denominator */
+/* automatic frame rate control */
+#define VS6624_DISABLE_FR_DAMPER      0x0E80 /* defines frame rate mode */
+#define VS6624_MIN_DAMPER_OUT_MSB     0x0E8C /* minimum frame rate MSB */
+#define VS6624_MIN_DAMPER_OUT_LSB     0x0E8A /* minimum frame rate LSB */
+/* exposure controls */
+#define VS6624_EXPO_MODE              0x1180 /* exposure mode */
+#define VS6624_EXPO_METER             0x1182 /* weights to be associated with the zones */
+#define VS6624_EXPO_TIME_NUM          0x1184 /* exposure time numerator */
+#define VS6624_EXPO_TIME_DEN          0x1186 /* exposure time denominator */
+#define VS6624_EXPO_TIME_MSB          0x1189 /* exposure time for the Manual Mode MSB */
+#define VS6624_EXPO_TIME_LSB          0x118A /* exposure time for the Manual Mode LSB */
+#define VS6624_EXPO_COMPENSATION      0x1190 /* exposure compensation */
+#define VS6624_DIRECT_COARSE_MSB      0x1195 /* coarse integration lines for Direct Mode MSB */
+#define VS6624_DIRECT_COARSE_LSB      0x1196 /* coarse integration lines for Direct Mode LSB */
+#define VS6624_DIRECT_FINE_MSB        0x1199 /* fine integration pixels for Direct Mode MSB */
+#define VS6624_DIRECT_FINE_LSB        0x119A /* fine integration pixels for Direct Mode LSB */
+#define VS6624_DIRECT_ANAL_GAIN_MSB   0x119D /* analog gain for Direct Mode MSB */
+#define VS6624_DIRECT_ANAL_GAIN_LSB   0x119E /* analog gain for Direct Mode LSB */
+#define VS6624_DIRECT_DIGI_GAIN_MSB   0x11A1 /* digital gain for Direct Mode MSB */
+#define VS6624_DIRECT_DIGI_GAIN_LSB   0x11A2 /* digital gain for Direct Mode LSB */
+#define VS6624_FLASH_COARSE_MSB       0x11A5 /* coarse integration lines for Flash Gun Mode MSB */
+#define VS6624_FLASH_COARSE_LSB       0x11A6 /* coarse integration lines for Flash Gun Mode LSB */
+#define VS6624_FLASH_FINE_MSB         0x11A9 /* fine integration pixels for Flash Gun Mode MSB */
+#define VS6624_FLASH_FINE_LSB         0x11AA /* fine integration pixels for Flash Gun Mode LSB */
+#define VS6624_FLASH_ANAL_GAIN_MSB    0x11AD /* analog gain for Flash Gun Mode MSB */
+#define VS6624_FLASH_ANAL_GAIN_LSB    0x11AE /* analog gain for Flash Gun Mode LSB */
+#define VS6624_FLASH_DIGI_GAIN_MSB    0x11B1 /* digital gain for Flash Gun Mode MSB */
+#define VS6624_FLASH_DIGI_GAIN_LSB    0x11B2 /* digital gain for Flash Gun Mode LSB */
+#define VS6624_FREEZE_AE              0x11B4 /* freeze auto exposure */
+#define VS6624_MAX_INT_TIME_MSB       0x11B7 /* user maximum integration time MSB */
+#define VS6624_MAX_INT_TIME_LSB       0x11B8 /* user maximum integration time LSB */
+#define VS6624_FLASH_AG_THR_MSB       0x11BB /* recommend flash gun analog gain threshold MSB */
+#define VS6624_FLASH_AG_THR_LSB       0x11BC /* recommend flash gun analog gain threshold LSB */
+#define VS6624_ANTI_FLICKER_MODE      0x11C0 /* anti flicker mode */
+/* white balance control */
+#define VS6624_WB_MODE                0x1480 /* set white balance mode */
+#define VS6624_MAN_RG                 0x1482 /* user setting for red channel gain */
+#define VS6624_MAN_GG                 0x1484 /* user setting for green channel gain */
+#define VS6624_MAN_BG                 0x1486 /* user setting for blue channel gain */
+#define VS6624_FLASH_RG_MSB           0x148B /* red gain for Flash Gun MSB */
+#define VS6624_FLASH_RG_LSB           0x148C /* red gain for Flash Gun LSB */
+#define VS6624_FLASH_GG_MSB           0x148F /* green gain for Flash Gun MSB */
+#define VS6624_FLASH_GG_LSB           0x1490 /* green gain for Flash Gun LSB */
+#define VS6624_FLASH_BG_MSB           0x1493 /* blue gain for Flash Gun MSB */
+#define VS6624_FLASH_BG_LSB           0x1494 /* blue gain for Flash Gun LSB */
+/* sensor setup */
+#define VS6624_BC_OFFSET              0x1990 /* Black Correction Offset */
+/* image stability */
+#define VS6624_STABLE_WB              0x1900 /* white balance stable */
+#define VS6624_STABLE_EXPO            0x1902 /* exposure stable */
+#define VS6624_STABLE                 0x1906 /* system stable */
+/* flash control */
+#define VS6624_FLASH_MODE             0x1A80 /* flash mode */
+#define VS6624_FLASH_OFF_LINE_MSB     0x1A83 /* off line at flash pulse mode MSB */
+#define VS6624_FLASH_OFF_LINE_LSB     0x1A84 /* off line at flash pulse mode LSB */
+/* flash status */
+#define VS6624_FLASH_RECOM            0x1B00 /* flash gun is recommended */
+#define VS6624_FLASH_GRAB_COMPLETE    0x1B02 /* flash gun image has been grabbed */
+/* scythe filter controls */
+#define VS6624_SCYTHE_FILTER          0x1D80 /* disable scythe defect correction */
+/* jack filter controls */
+#define VS6624_JACK_FILTER            0x1E00 /* disable jack defect correction */
+/* demosaic control */
+#define VS6624_ANTI_ALIAS_FILTER      0x1E80 /* anti alias filter suppress */
+/* color matrix dampers */
+#define VS6624_CM_DISABLE             0x1F00 /* disable color matrix damper */
+#define VS6624_CM_LOW_THR_MSB         0x1F03 /* low threshold for exposure MSB */
+#define VS6624_CM_LOW_THR_LSB         0x1F04 /* low threshold for exposure LSB */
+#define VS6624_CM_HIGH_THR_MSB        0x1F07 /* high threshold for exposure MSB */
+#define VS6624_CM_HIGH_THR_LSB        0x1F08 /* high threshold for exposure LSB */
+#define VS6624_CM_MIN_OUT_MSB         0x1F0B /* minimum possible damper output MSB */
+#define VS6624_CM_MIN_OUT_LSB         0x1F0C /* minimum possible damper output LSB */
+/* peaking control */
+#define VS6624_PEAK_GAIN              0x2000 /* controls peaking gain */
+#define VS6624_PEAK_G_DISABLE         0x2002 /* disable peak gain damping */
+#define VS6624_PEAK_LOW_THR_G_MSB     0x2005 /* low threshold for exposure for gain MSB */
+#define VS6624_PEAK_LOW_THR_G_LSB     0x2006 /* low threshold for exposure for gain LSB */
+#define VS6624_PEAK_HIGH_THR_G_MSB    0x2009 /* high threshold for exposure for gain MSB */
+#define VS6624_PEAK_HIGH_THR_G_LSB    0x200A /* high threshold for exposure for gain LSB */
+#define VS6624_PEAK_MIN_OUT_G_MSB     0x200D /* minimum damper output for gain MSB */
+#define VS6624_PEAK_MIN_OUT_G_LSB     0x200E /* minimum damper output for gain LSB */
+#define VS6624_PEAK_LOW_THR           0x2010 /* adjust degree of coring */
+#define VS6624_PEAK_C_DISABLE         0x2012 /* disable coring damping */
+#define VS6624_PEAK_HIGH_THR          0x2014 /* adjust maximum gain */
+#define VS6624_PEAK_LOW_THR_C_MSB     0x2017 /* low threshold for exposure for coring MSB */
+#define VS6624_PEAK_LOW_THR_C_LSB     0x2018 /* low threshold for exposure for coring LSB */
+#define VS6624_PEAK_HIGH_THR_C_MSB    0x201B /* high threshold for exposure for coring MSB */
+#define VS6624_PEAK_HIGH_THR_C_LSB    0x201C /* high threshold for exposure for coring LSB */
+#define VS6624_PEAK_MIN_OUT_C_MSB     0x201F /* minimum damper output for coring MSB */
+#define VS6624_PEAK_MIN_OUT_C_LSB     0x2020 /* minimum damper output for coring LSB */
+/* pipe 0 RGB to YUV matrix manual control */
+#define VS6624_RYM0_MAN_CTRL          0x2180 /* enable manual RGB to YUV matrix */
+#define VS6624_RYM0_W00_MSB           0x2183 /* row 0 column 0 of YUV matrix MSB */
+#define VS6624_RYM0_W00_LSB           0x2184 /* row 0 column 0 of YUV matrix LSB */
+#define VS6624_RYM0_W01_MSB           0x2187 /* row 0 column 1 of YUV matrix MSB */
+#define VS6624_RYM0_W01_LSB           0x2188 /* row 0 column 1 of YUV matrix LSB */
+#define VS6624_RYM0_W02_MSB           0x218C /* row 0 column 2 of YUV matrix MSB */
+#define VS6624_RYM0_W02_LSB           0x218D /* row 0 column 2 of YUV matrix LSB */
+#define VS6624_RYM0_W10_MSB           0x2190 /* row 1 column 0 of YUV matrix MSB */
+#define VS6624_RYM0_W10_LSB           0x218F /* row 1 column 0 of YUV matrix LSB */
+#define VS6624_RYM0_W11_MSB           0x2193 /* row 1 column 1 of YUV matrix MSB */
+#define VS6624_RYM0_W11_LSB           0x2194 /* row 1 column 1 of YUV matrix LSB */
+#define VS6624_RYM0_W12_MSB           0x2197 /* row 1 column 2 of YUV matrix MSB */
+#define VS6624_RYM0_W12_LSB           0x2198 /* row 1 column 2 of YUV matrix LSB */
+#define VS6624_RYM0_W20_MSB           0x219B /* row 2 column 0 of YUV matrix MSB */
+#define VS6624_RYM0_W20_LSB           0x219C /* row 2 column 0 of YUV matrix LSB */
+#define VS6624_RYM0_W21_MSB           0x21A0 /* row 2 column 1 of YUV matrix MSB */
+#define VS6624_RYM0_W21_LSB           0x219F /* row 2 column 1 of YUV matrix LSB */
+#define VS6624_RYM0_W22_MSB           0x21A3 /* row 2 column 2 of YUV matrix MSB */
+#define VS6624_RYM0_W22_LSB           0x21A4 /* row 2 column 2 of YUV matrix LSB */
+#define VS6624_RYM0_YINY_MSB          0x21A7 /* Y in Y MSB */
+#define VS6624_RYM0_YINY_LSB          0x21A8 /* Y in Y LSB */
+#define VS6624_RYM0_YINCB_MSB         0x21AB /* Y in Cb MSB */
+#define VS6624_RYM0_YINCB_LSB         0x21AC /* Y in Cb LSB */
+#define VS6624_RYM0_YINCR_MSB         0x21B0 /* Y in Cr MSB */
+#define VS6624_RYM0_YINCR_LSB         0x21AF /* Y in Cr LSB */
+/* pipe 1 RGB to YUV matrix manual control */
+#define VS6624_RYM1_MAN_CTRL          0x2200 /* enable manual RGB to YUV matrix */
+#define VS6624_RYM1_W00_MSB           0x2203 /* row 0 column 0 of YUV matrix MSB */
+#define VS6624_RYM1_W00_LSB           0x2204 /* row 0 column 0 of YUV matrix LSB */
+#define VS6624_RYM1_W01_MSB           0x2207 /* row 0 column 1 of YUV matrix MSB */
+#define VS6624_RYM1_W01_LSB           0x2208 /* row 0 column 1 of YUV matrix LSB */
+#define VS6624_RYM1_W02_MSB           0x220C /* row 0 column 2 of YUV matrix MSB */
+#define VS6624_RYM1_W02_LSB           0x220D /* row 0 column 2 of YUV matrix LSB */
+#define VS6624_RYM1_W10_MSB           0x2210 /* row 1 column 0 of YUV matrix MSB */
+#define VS6624_RYM1_W10_LSB           0x220F /* row 1 column 0 of YUV matrix LSB */
+#define VS6624_RYM1_W11_MSB           0x2213 /* row 1 column 1 of YUV matrix MSB */
+#define VS6624_RYM1_W11_LSB           0x2214 /* row 1 column 1 of YUV matrix LSB */
+#define VS6624_RYM1_W12_MSB           0x2217 /* row 1 column 2 of YUV matrix MSB */
+#define VS6624_RYM1_W12_LSB           0x2218 /* row 1 column 2 of YUV matrix LSB */
+#define VS6624_RYM1_W20_MSB           0x221B /* row 2 column 0 of YUV matrix MSB */
+#define VS6624_RYM1_W20_LSB           0x221C /* row 2 column 0 of YUV matrix LSB */
+#define VS6624_RYM1_W21_MSB           0x2220 /* row 2 column 1 of YUV matrix MSB */
+#define VS6624_RYM1_W21_LSB           0x221F /* row 2 column 1 of YUV matrix LSB */
+#define VS6624_RYM1_W22_MSB           0x2223 /* row 2 column 2 of YUV matrix MSB */
+#define VS6624_RYM1_W22_LSB           0x2224 /* row 2 column 2 of YUV matrix LSB */
+#define VS6624_RYM1_YINY_MSB          0x2227 /* Y in Y MSB */
+#define VS6624_RYM1_YINY_LSB          0x2228 /* Y in Y LSB */
+#define VS6624_RYM1_YINCB_MSB         0x222B /* Y in Cb MSB */
+#define VS6624_RYM1_YINCB_LSB         0x222C /* Y in Cb LSB */
+#define VS6624_RYM1_YINCR_MSB         0x2220 /* Y in Cr MSB */
+#define VS6624_RYM1_YINCR_LSB         0x222F /* Y in Cr LSB */
+/* pipe 0 gamma manual control */
+#define VS6624_GAMMA_MAN_CTRL0        0x2280 /* enable manual gamma setup */
+#define VS6624_GAMMA_PEAK_R0          0x2282 /* peaked red channel gamma value */
+#define VS6624_GAMMA_PEAK_G0          0x2284 /* peaked green channel gamma value */
+#define VS6624_GAMMA_PEAK_B0          0x2286 /* peaked blue channel gamma value */
+#define VS6624_GAMMA_UNPEAK_R0        0x2288 /* unpeaked red channel gamma value */
+#define VS6624_GAMMA_UNPEAK_G0        0x228A /* unpeaked green channel gamma value */
+#define VS6624_GAMMA_UNPEAK_B0        0x228C /* unpeaked blue channel gamma value */
+/* pipe 1 gamma manual control */
+#define VS6624_GAMMA_MAN_CTRL1        0x2300 /* enable manual gamma setup */
+#define VS6624_GAMMA_PEAK_R1          0x2302 /* peaked red channel gamma value */
+#define VS6624_GAMMA_PEAK_G1          0x2304 /* peaked green channel gamma value */
+#define VS6624_GAMMA_PEAK_B1          0x2306 /* peaked blue channel gamma value */
+#define VS6624_GAMMA_UNPEAK_R1        0x2308 /* unpeaked red channel gamma value */
+#define VS6624_GAMMA_UNPEAK_G1        0x230A /* unpeaked green channel gamma value */
+#define VS6624_GAMMA_UNPEAK_B1        0x230C /* unpeaked blue channel gamma value */
+/* fade to black */
+#define VS6624_F2B_DISABLE            0x2480 /* disable fade to black */
+#define VS6624_F2B_BLACK_VAL_MSB      0x2483 /* black value MSB */
+#define VS6624_F2B_BLACK_VAL_LSB      0x2484 /* black value LSB */
+#define VS6624_F2B_LOW_THR_MSB        0x2487 /* low threshold for exposure MSB */
+#define VS6624_F2B_LOW_THR_LSB        0x2488 /* low threshold for exposure LSB */
+#define VS6624_F2B_HIGH_THR_MSB       0x248B /* high threshold for exposure MSB */
+#define VS6624_F2B_HIGH_THR_LSB       0x248C /* high threshold for exposure LSB */
+#define VS6624_F2B_MIN_OUT_MSB        0x248F /* minimum damper output MSB */
+#define VS6624_F2B_MIN_OUT_LSB        0x2490 /* minimum damper output LSB */
+/* output formatter control */
+#define VS6624_CODE_CK_EN             0x2580 /* code check enable */
+#define VS6624_BLANK_FMT              0x2582 /* blank format */
+#define VS6624_SYNC_CODE_SETUP        0x2584 /* sync code setup */
+#define VS6624_HSYNC_SETUP            0x2586 /* H sync setup */
+#define VS6624_VSYNC_SETUP            0x2588 /* V sync setup */
+#define VS6624_PCLK_SETUP             0x258A /* PCLK setup */
+#define VS6624_PCLK_EN                0x258C /* PCLK enable */
+#define VS6624_OPF_SP_SETUP           0x258E /* output formatter sp setup */
+#define VS6624_BLANK_DATA_MSB         0x2590 /* blank data MSB */
+#define VS6624_BLANK_DATA_LSB         0x2592 /* blank data LSB */
+#define VS6624_RGB_SETUP              0x2594 /* RGB setup */
+#define VS6624_YUV_SETUP              0x2596 /* YUV setup */
+#define VS6624_VSYNC_RIS_COARSE_H     0x2598 /* V sync rising coarse high */
+#define VS6624_VSYNC_RIS_COARSE_L     0x259A /* V sync rising coarse low */
+#define VS6624_VSYNC_RIS_FINE_H       0x259C /* V sync rising fine high */
+#define VS6624_VSYNC_RIS_FINE_L       0x259E /* V sync rising fine low */
+#define VS6624_VSYNC_FALL_COARSE_H    0x25A0 /* V sync falling coarse high */
+#define VS6624_VSYNC_FALL_COARSE_L    0x25A2 /* V sync falling coarse low */
+#define VS6624_VSYNC_FALL_FINE_H      0x25A4 /* V sync falling fine high */
+#define VS6624_VSYNC_FALL_FINE_L      0x25A6 /* V sync falling fine low */
+#define VS6624_HSYNC_RIS_H            0x25A8 /* H sync rising high */
+#define VS6624_HSYNC_RIS_L            0x25AA /* H sync rising low */
+#define VS6624_HSYNC_FALL_H           0x25AC /* H sync falling high */
+#define VS6624_HSYNC_FALL_L           0x25AE /* H sync falling low */
+#define VS6624_OUT_IF                 0x25B0 /* output interface */
+#define VS6624_CCP_EXT_DATA           0x25B2 /* CCP extra data */
+/* NoRA controls */
+#define VS6624_NORA_DISABLE           0x2600 /* NoRA control mode */
+#define VS6624_NORA_USAGE             0x2602 /* usage */
+#define VS6624_NORA_SPLIT_KN          0x2604 /* split kn */
+#define VS6624_NORA_SPLIT_NI          0x2606 /* split ni */
+#define VS6624_NORA_TIGHT_G           0x2608 /* tight green */
+#define VS6624_NORA_DISABLE_NP        0x260A /* disable noro promoting */
+#define VS6624_NORA_LOW_THR_MSB       0x260D /* low threshold for exposure MSB */
+#define VS6624_NORA_LOW_THR_LSB       0x260E /* low threshold for exposure LSB */
+#define VS6624_NORA_HIGH_THR_MSB      0x2611 /* high threshold for exposure MSB */
+#define VS6624_NORA_HIGH_THR_LSB      0x2612 /* high threshold for exposure LSB */
+#define VS6624_NORA_MIN_OUT_MSB       0x2615 /* minimum damper output MSB */
+#define VS6624_NORA_MIN_OUT_LSB       0x2616 /* minimum damper output LSB */
+
+#endif
diff --git a/drivers/media/i2c/wm8739.c b/drivers/media/i2c/wm8739.c
new file mode 100644
index 0000000..3bb99e9
--- /dev/null
+++ b/drivers/media/i2c/wm8739.c
@@ -0,0 +1,294 @@
+/*
+ * wm8739
+ *
+ * Copyright (C) 2005 T. Adachi <tadachi@tadachi-net.com>
+ *
+ * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl>
+ * - Cleanup
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+MODULE_DESCRIPTION("wm8739 driver");
+MODULE_AUTHOR("T. Adachi, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug;
+
+module_param(debug, int, 0644);
+
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+
+/* ------------------------------------------------------------------------ */
+
+enum {
+	R0 = 0, R1,
+	R5 = 5, R6, R7, R8, R9, R15 = 15,
+	TOT_REGS
+};
+
+struct wm8739_state {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	struct {
+		/* audio cluster */
+		struct v4l2_ctrl *volume;
+		struct v4l2_ctrl *mute;
+		struct v4l2_ctrl *balance;
+	};
+	u32 clock_freq;
+};
+
+static inline struct wm8739_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct wm8739_state, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct wm8739_state, hdl)->sd;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int wm8739_write(struct v4l2_subdev *sd, int reg, u16 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int i;
+
+	if (reg < 0 || reg >= TOT_REGS) {
+		v4l2_err(sd, "Invalid register R%d\n", reg);
+		return -1;
+	}
+
+	v4l2_dbg(1, debug, sd, "write: %02x %02x\n", reg, val);
+
+	for (i = 0; i < 3; i++)
+		if (i2c_smbus_write_byte_data(client,
+				(reg << 1) | (val >> 8), val & 0xff) == 0)
+			return 0;
+	v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg);
+	return -1;
+}
+
+static int wm8739_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct wm8739_state *state = to_state(sd);
+	unsigned int work_l, work_r;
+	u8 vol_l;	/* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
+	u8 vol_r;	/* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
+	u16 mute;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* normalize ( 65535 to 0 -> 31 to 0 (12dB to -34.5dB) ) */
+	work_l = (min(65536 - state->balance->val, 32768) * state->volume->val) / 32768;
+	work_r = (min(state->balance->val, 32768) * state->volume->val) / 32768;
+
+	vol_l = (long)work_l * 31 / 65535;
+	vol_r = (long)work_r * 31 / 65535;
+
+	/* set audio volume etc. */
+	mute = state->mute->val ? 0x80 : 0;
+
+	/* Volume setting: bits 0-4, 0x1f = 12 dB, 0x00 = -34.5 dB
+	 * Default setting: 0x17 = 0 dB
+	 */
+	wm8739_write(sd, R0, (vol_l & 0x1f) | mute);
+	wm8739_write(sd, R1, (vol_r & 0x1f) | mute);
+	return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int wm8739_s_clock_freq(struct v4l2_subdev *sd, u32 audiofreq)
+{
+	struct wm8739_state *state = to_state(sd);
+
+	state->clock_freq = audiofreq;
+	/* de-activate */
+	wm8739_write(sd, R9, 0x000);
+	switch (audiofreq) {
+	case 44100:
+		/* 256fps, fs=44.1k */
+		wm8739_write(sd, R8, 0x020);
+		break;
+	case 48000:
+		/* 256fps, fs=48k */
+		wm8739_write(sd, R8, 0x000);
+		break;
+	case 32000:
+		/* 256fps, fs=32k */
+		wm8739_write(sd, R8, 0x018);
+		break;
+	default:
+		break;
+	}
+	/* activate */
+	wm8739_write(sd, R9, 0x001);
+	return 0;
+}
+
+static int wm8739_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_WM8739, 0);
+}
+
+static int wm8739_log_status(struct v4l2_subdev *sd)
+{
+	struct wm8739_state *state = to_state(sd);
+
+	v4l2_info(sd, "Frequency: %u Hz\n", state->clock_freq);
+	v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_ctrl_ops wm8739_ctrl_ops = {
+	.s_ctrl = wm8739_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops wm8739_core_ops = {
+	.log_status = wm8739_log_status,
+	.g_chip_ident = wm8739_g_chip_ident,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+};
+
+static const struct v4l2_subdev_audio_ops wm8739_audio_ops = {
+	.s_clock_freq = wm8739_s_clock_freq,
+};
+
+static const struct v4l2_subdev_ops wm8739_ops = {
+	.core = &wm8739_core_ops,
+	.audio = &wm8739_audio_ops,
+};
+
+/* ------------------------------------------------------------------------ */
+
+/* i2c implementation */
+
+static int wm8739_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct wm8739_state *state;
+	struct v4l2_subdev *sd;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	state = kzalloc(sizeof(struct wm8739_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &wm8739_ops);
+	v4l2_ctrl_handler_init(&state->hdl, 2);
+	state->volume = v4l2_ctrl_new_std(&state->hdl, &wm8739_ctrl_ops,
+			V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 50736);
+	state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8739_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+	state->balance = v4l2_ctrl_new_std(&state->hdl, &wm8739_ctrl_ops,
+			V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768);
+	sd->ctrl_handler = &state->hdl;
+	if (state->hdl.error) {
+		int err = state->hdl.error;
+
+		v4l2_ctrl_handler_free(&state->hdl);
+		kfree(state);
+		return err;
+	}
+	v4l2_ctrl_cluster(3, &state->volume);
+
+	state->clock_freq = 48000;
+
+	/* Initialize wm8739 */
+
+	/* reset */
+	wm8739_write(sd, R15, 0x00);
+	/* filter setting, high path, offet clear */
+	wm8739_write(sd, R5, 0x000);
+	/* ADC, OSC, Power Off mode Disable */
+	wm8739_write(sd, R6, 0x000);
+	/* Digital Audio interface format:
+	   Enable Master mode, 24 bit, MSB first/left justified */
+	wm8739_write(sd, R7, 0x049);
+	/* sampling control: normal, 256fs, 48KHz sampling rate */
+	wm8739_write(sd, R8, 0x000);
+	/* activate */
+	wm8739_write(sd, R9, 0x001);
+	/* set volume/mute */
+	v4l2_ctrl_handler_setup(&state->hdl);
+	return 0;
+}
+
+static int wm8739_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct wm8739_state *state = to_state(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&state->hdl);
+	kfree(to_state(sd));
+	return 0;
+}
+
+static const struct i2c_device_id wm8739_id[] = {
+	{ "wm8739", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8739_id);
+
+static struct i2c_driver wm8739_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "wm8739",
+	},
+	.probe		= wm8739_probe,
+	.remove		= wm8739_remove,
+	.id_table	= wm8739_id,
+};
+
+module_i2c_driver(wm8739_driver);
diff --git a/drivers/media/i2c/wm8775.c b/drivers/media/i2c/wm8775.c
new file mode 100644
index 0000000..bee77ea
--- /dev/null
+++ b/drivers/media/i2c/wm8775.c
@@ -0,0 +1,342 @@
+/*
+ * wm8775 - driver version 0.0.1
+ *
+ * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to>
+ *
+ * Based on saa7115 driver
+ *
+ * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl>
+ * - Cleanup
+ * - V4L2 API update
+ * - sound fixes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+#include <media/wm8775.h>
+
+MODULE_DESCRIPTION("wm8775 driver");
+MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+
+
+/* ----------------------------------------------------------------------- */
+
+enum {
+	R7 = 7, R11 = 11,
+	R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R23 = 23,
+	TOT_REGS
+};
+
+#define ALC_HOLD 0x85 /* R17: use zero cross detection, ALC hold time 42.6 ms */
+#define ALC_EN 0x100  /* R17: ALC enable */
+
+struct wm8775_state {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	struct v4l2_ctrl *mute;
+	struct v4l2_ctrl *vol;
+	struct v4l2_ctrl *bal;
+	struct v4l2_ctrl *loud;
+	u8 input;		/* Last selected input (0-0xf) */
+};
+
+static inline struct wm8775_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct wm8775_state, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct wm8775_state, hdl)->sd;
+}
+
+static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int i;
+
+	if (reg < 0 || reg >= TOT_REGS) {
+		v4l2_err(sd, "Invalid register R%d\n", reg);
+		return -1;
+	}
+
+	for (i = 0; i < 3; i++)
+		if (i2c_smbus_write_byte_data(client,
+				(reg << 1) | (val >> 8), val & 0xff) == 0)
+			return 0;
+	v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg);
+	return -1;
+}
+
+static void wm8775_set_audio(struct v4l2_subdev *sd, int quietly)
+{
+	struct wm8775_state *state = to_state(sd);
+	u8 vol_l, vol_r;
+	int muted = 0 != state->mute->val;
+	u16 volume = (u16)state->vol->val;
+	u16 balance = (u16)state->bal->val;
+
+	/* normalize ( 65535 to 0 -> 255 to 0 (+24dB to -103dB) ) */
+	vol_l = (min(65536 - balance, 32768) * volume) >> 23;
+	vol_r = (min(balance, (u16)32768) * volume) >> 23;
+
+	/* Mute */
+	if (muted || quietly)
+		wm8775_write(sd, R21, 0x0c0 | state->input);
+
+	wm8775_write(sd, R14, vol_l | 0x100); /* 0x100= Left channel ADC zero cross enable */
+	wm8775_write(sd, R15, vol_r | 0x100); /* 0x100= Right channel ADC zero cross enable */
+
+	/* Un-mute */
+	if (!muted)
+		wm8775_write(sd, R21, state->input);
+}
+
+static int wm8775_s_routing(struct v4l2_subdev *sd,
+			    u32 input, u32 output, u32 config)
+{
+	struct wm8775_state *state = to_state(sd);
+
+	/* There are 4 inputs and one output. Zero or more inputs
+	   are multiplexed together to the output. Hence there are
+	   16 combinations.
+	   If only one input is active (the normal case) then the
+	   input values 1, 2, 4 or 8 should be used. */
+	if (input > 15) {
+		v4l2_err(sd, "Invalid input %d.\n", input);
+		return -EINVAL;
+	}
+	state->input = input;
+	if (!v4l2_ctrl_g_ctrl(state->mute))
+		return 0;
+	if (!v4l2_ctrl_g_ctrl(state->vol))
+		return 0;
+	if (!v4l2_ctrl_g_ctrl(state->bal))
+		return 0;
+	wm8775_set_audio(sd, 1);
+	return 0;
+}
+
+static int wm8775_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+	case V4L2_CID_AUDIO_VOLUME:
+	case V4L2_CID_AUDIO_BALANCE:
+		wm8775_set_audio(sd, 0);
+		return 0;
+	case V4L2_CID_AUDIO_LOUDNESS:
+		wm8775_write(sd, R17, (ctrl->val ? ALC_EN : 0) | ALC_HOLD);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int wm8775_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_WM8775, 0);
+}
+
+static int wm8775_log_status(struct v4l2_subdev *sd)
+{
+	struct wm8775_state *state = to_state(sd);
+
+	v4l2_info(sd, "Input: %d\n", state->input);
+	v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
+	return 0;
+}
+
+static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+{
+	wm8775_set_audio(sd, 0);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_ctrl_ops wm8775_ctrl_ops = {
+	.s_ctrl = wm8775_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops wm8775_core_ops = {
+	.log_status = wm8775_log_status,
+	.g_chip_ident = wm8775_g_chip_ident,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+};
+
+static const struct v4l2_subdev_tuner_ops wm8775_tuner_ops = {
+	.s_frequency = wm8775_s_frequency,
+};
+
+static const struct v4l2_subdev_audio_ops wm8775_audio_ops = {
+	.s_routing = wm8775_s_routing,
+};
+
+static const struct v4l2_subdev_ops wm8775_ops = {
+	.core = &wm8775_core_ops,
+	.tuner = &wm8775_tuner_ops,
+	.audio = &wm8775_audio_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static int wm8775_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct wm8775_state *state;
+	struct v4l2_subdev *sd;
+	int err;
+	bool is_nova_s = false;
+
+	if (client->dev.platform_data) {
+		struct wm8775_platform_data *data = client->dev.platform_data;
+		is_nova_s = data->is_nova_s;
+	}
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%02x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	state = kzalloc(sizeof(struct wm8775_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &wm8775_ops);
+	state->input = 2;
+
+	v4l2_ctrl_handler_init(&state->hdl, 4);
+	state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+	state->vol = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
+			V4L2_CID_AUDIO_VOLUME, 0, 65535, (65535+99)/100, 0xCF00); /* 0dB*/
+	state->bal = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
+			V4L2_CID_AUDIO_BALANCE, 0, 65535, (65535+99)/100, 32768);
+	state->loud = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
+			V4L2_CID_AUDIO_LOUDNESS, 0, 1, 1, 1);
+	sd->ctrl_handler = &state->hdl;
+	err = state->hdl.error;
+	if (err) {
+		v4l2_ctrl_handler_free(&state->hdl);
+		kfree(state);
+		return err;
+	}
+
+	/* Initialize wm8775 */
+
+	/* RESET */
+	wm8775_write(sd, R23, 0x000);
+	/* Disable zero cross detect timeout */
+	wm8775_write(sd, R7, 0x000);
+	/* HPF enable, left justified, 24-bit (Philips) mode */
+	wm8775_write(sd, R11, 0x021);
+	/* Master mode, clock ratio 256fs */
+	wm8775_write(sd, R12, 0x102);
+	/* Powered up */
+	wm8775_write(sd, R13, 0x000);
+
+	if (!is_nova_s) {
+		/* ADC gain +2.5dB, enable zero cross */
+		wm8775_write(sd, R14, 0x1d4);
+		/* ADC gain +2.5dB, enable zero cross */
+		wm8775_write(sd, R15, 0x1d4);
+		/* ALC Stereo, ALC target level -1dB FS max gain +8dB */
+		wm8775_write(sd, R16, 0x1bf);
+		/* Enable gain control, use zero cross detection,
+		   ALC hold time 42.6 ms */
+		wm8775_write(sd, R17, 0x185);
+	} else {
+		/* ALC stereo, ALC target level -5dB FS, ALC max gain +8dB */
+		wm8775_write(sd, R16, 0x1bb);
+		/* Set ALC mode and hold time */
+		wm8775_write(sd, R17, (state->loud->val ? ALC_EN : 0) | ALC_HOLD);
+	}
+	/* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */
+	wm8775_write(sd, R18, 0x0a2);
+	/* Enable noise gate, threshold -72dBfs */
+	wm8775_write(sd, R19, 0x005);
+	if (!is_nova_s) {
+		/* Transient window 4ms, lower PGA gain limit -1dB */
+		wm8775_write(sd, R20, 0x07a);
+		/* LRBOTH = 1, use input 2. */
+		wm8775_write(sd, R21, 0x102);
+	} else {
+		/* Transient window 4ms, ALC min gain -5dB  */
+		wm8775_write(sd, R20, 0x0fb);
+
+		wm8775_set_audio(sd, 1);      /* set volume/mute/mux */
+	}
+	return 0;
+}
+
+static int wm8775_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct wm8775_state *state = to_state(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&state->hdl);
+	kfree(state);
+	return 0;
+}
+
+static const struct i2c_device_id wm8775_id[] = {
+	{ "wm8775", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8775_id);
+
+static struct i2c_driver wm8775_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "wm8775",
+	},
+	.probe		= wm8775_probe,
+	.remove		= wm8775_remove,
+	.id_table	= wm8775_id,
+};
+
+module_i2c_driver(wm8775_driver);
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 6f9eb94..d01fcb7 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -59,7 +59,9 @@ static int media_device_get_info(struct media_device *dev,
 	info.hw_revision = dev->hw_revision;
 	info.driver_version = dev->driver_version;
 
-	return copy_to_user(__info, &info, sizeof(*__info));
+	if (copy_to_user(__info, &info, sizeof(*__info)))
+		return -EFAULT;
+	return 0;
 }
 
 static struct media_entity *find_entity(struct media_device *mdev, u32 id)
diff --git a/drivers/media/mmc/Kconfig b/drivers/media/mmc/Kconfig
new file mode 100644
index 0000000..8c30ada
--- /dev/null
+++ b/drivers/media/mmc/Kconfig
@@ -0,0 +1,2 @@
+comment "Supported MMC/SDIO adapters"
+source "drivers/media/mmc/siano/Kconfig"
diff --git a/drivers/media/mmc/Makefile b/drivers/media/mmc/Makefile
new file mode 100644
index 0000000..31e297a
--- /dev/null
+++ b/drivers/media/mmc/Makefile
@@ -0,0 +1 @@
+obj-y += siano/
diff --git a/drivers/media/mmc/siano/Kconfig b/drivers/media/mmc/siano/Kconfig
new file mode 100644
index 0000000..fa62475
--- /dev/null
+++ b/drivers/media/mmc/siano/Kconfig
@@ -0,0 +1,10 @@
+#
+# Siano Mobile Silicon Digital TV device configuration
+#
+
+config SMS_SDIO_DRV
+	tristate "Siano SMS1xxx based MDTV via SDIO interface"
+	depends on DVB_CORE && RC_CORE && HAS_DMA
+	depends on MMC
+	---help---
+	  Choose if you would like to have Siano's support for SDIO interface
diff --git a/drivers/media/mmc/siano/Makefile b/drivers/media/mmc/siano/Makefile
new file mode 100644
index 0000000..0e01f97
--- /dev/null
+++ b/drivers/media/mmc/siano/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_SMS_SDIO_DRV) += smssdio.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/common/siano
+ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
+
diff --git a/drivers/media/mmc/siano/smssdio.c b/drivers/media/mmc/siano/smssdio.c
new file mode 100644
index 0000000..d6f3f10
--- /dev/null
+++ b/drivers/media/mmc/siano/smssdio.c
@@ -0,0 +1,365 @@
+/*
+ *  smssdio.c - Siano 1xxx SDIO interface driver
+ *
+ *  Copyright 2008 Pierre Ossman
+ *
+ * Based on code by Siano Mobile Silicon, Inc.,
+ * Copyright (C) 2006-2008, Uri Shkolnik
+ *
+ * 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 hardware is a bit odd in that all transfers should be done
+ * to/from the SMSSDIO_DATA register, yet the "increase address" bit
+ * always needs to be set.
+ *
+ * Also, buffers from the card are always aligned to 128 byte
+ * boundaries.
+ */
+
+/*
+ * General cleanup notes:
+ *
+ * - only typedefs should be name *_t
+ *
+ * - use ERR_PTR and friends for smscore_register_device()
+ *
+ * - smscore_getbuffer should zero fields
+ *
+ * Fix stop command
+ */
+
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/module.h>
+
+#include "smscoreapi.h"
+#include "sms-cards.h"
+
+/* Registers */
+
+#define SMSSDIO_DATA		0x00
+#define SMSSDIO_INT		0x04
+#define SMSSDIO_BLOCK_SIZE	128
+
+static const struct sdio_device_id smssdio_ids[] __devinitconst = {
+	{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR),
+	 .driver_data = SMS1XXX_BOARD_SIANO_STELLAR},
+	{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0),
+	 .driver_data = SMS1XXX_BOARD_SIANO_NOVA_A},
+	{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_B0),
+	 .driver_data = SMS1XXX_BOARD_SIANO_NOVA_B},
+	{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VEGA_A0),
+	 .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
+	{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE),
+	 .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
+	{ /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(sdio, smssdio_ids);
+
+struct smssdio_device {
+	struct sdio_func *func;
+
+	struct smscore_device_t *coredev;
+
+	struct smscore_buffer_t *split_cb;
+};
+
+/*******************************************************************/
+/* Siano core callbacks                                            */
+/*******************************************************************/
+
+static int smssdio_sendrequest(void *context, void *buffer, size_t size)
+{
+	int ret = 0;
+	struct smssdio_device *smsdev;
+
+	smsdev = context;
+
+	sdio_claim_host(smsdev->func);
+
+	while (size >= smsdev->func->cur_blksize) {
+		ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA,
+					buffer, smsdev->func->cur_blksize);
+		if (ret)
+			goto out;
+
+		buffer += smsdev->func->cur_blksize;
+		size -= smsdev->func->cur_blksize;
+	}
+
+	if (size) {
+		ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA,
+					buffer, size);
+	}
+
+out:
+	sdio_release_host(smsdev->func);
+
+	return ret;
+}
+
+/*******************************************************************/
+/* SDIO callbacks                                                  */
+/*******************************************************************/
+
+static void smssdio_interrupt(struct sdio_func *func)
+{
+	int ret;
+
+	struct smssdio_device *smsdev;
+	struct smscore_buffer_t *cb;
+	struct SmsMsgHdr_ST *hdr;
+	size_t size;
+
+	smsdev = sdio_get_drvdata(func);
+
+	/*
+	 * The interrupt register has no defined meaning. It is just
+	 * a way of turning of the level triggered interrupt.
+	 */
+	(void)sdio_readb(func, SMSSDIO_INT, &ret);
+	if (ret) {
+		sms_err("Unable to read interrupt register!\n");
+		return;
+	}
+
+	if (smsdev->split_cb == NULL) {
+		cb = smscore_getbuffer(smsdev->coredev);
+		if (!cb) {
+			sms_err("Unable to allocate data buffer!\n");
+			return;
+		}
+
+		ret = sdio_memcpy_fromio(smsdev->func,
+					 cb->p,
+					 SMSSDIO_DATA,
+					 SMSSDIO_BLOCK_SIZE);
+		if (ret) {
+			sms_err("Error %d reading initial block!\n", ret);
+			return;
+		}
+
+		hdr = cb->p;
+
+		if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) {
+			smsdev->split_cb = cb;
+			return;
+		}
+
+		if (hdr->msgLength > smsdev->func->cur_blksize)
+			size = hdr->msgLength - smsdev->func->cur_blksize;
+		else
+			size = 0;
+	} else {
+		cb = smsdev->split_cb;
+		hdr = cb->p;
+
+		size = hdr->msgLength - sizeof(struct SmsMsgHdr_ST);
+
+		smsdev->split_cb = NULL;
+	}
+
+	if (size) {
+		void *buffer;
+
+		buffer = cb->p + (hdr->msgLength - size);
+		size = ALIGN(size, SMSSDIO_BLOCK_SIZE);
+
+		BUG_ON(smsdev->func->cur_blksize != SMSSDIO_BLOCK_SIZE);
+
+		/*
+		 * First attempt to transfer all of it in one go...
+		 */
+		ret = sdio_memcpy_fromio(smsdev->func,
+					 buffer,
+					 SMSSDIO_DATA,
+					 size);
+		if (ret && ret != -EINVAL) {
+			smscore_putbuffer(smsdev->coredev, cb);
+			sms_err("Error %d reading data from card!\n", ret);
+			return;
+		}
+
+		/*
+		 * ..then fall back to one block at a time if that is
+		 * not possible...
+		 *
+		 * (we have to do this manually because of the
+		 * problem with the "increase address" bit)
+		 */
+		if (ret == -EINVAL) {
+			while (size) {
+				ret = sdio_memcpy_fromio(smsdev->func,
+						  buffer, SMSSDIO_DATA,
+						  smsdev->func->cur_blksize);
+				if (ret) {
+					smscore_putbuffer(smsdev->coredev, cb);
+					sms_err("Error %d reading "
+						"data from card!\n", ret);
+					return;
+				}
+
+				buffer += smsdev->func->cur_blksize;
+				if (size > smsdev->func->cur_blksize)
+					size -= smsdev->func->cur_blksize;
+				else
+					size = 0;
+			}
+		}
+	}
+
+	cb->size = hdr->msgLength;
+	cb->offset = 0;
+
+	smscore_onresponse(smsdev->coredev, cb);
+}
+
+static int __devinit smssdio_probe(struct sdio_func *func,
+			 const struct sdio_device_id *id)
+{
+	int ret;
+
+	int board_id;
+	struct smssdio_device *smsdev;
+	struct smsdevice_params_t params;
+
+	board_id = id->driver_data;
+
+	smsdev = kzalloc(sizeof(struct smssdio_device), GFP_KERNEL);
+	if (!smsdev)
+		return -ENOMEM;
+
+	smsdev->func = func;
+
+	memset(&params, 0, sizeof(struct smsdevice_params_t));
+
+	params.device = &func->dev;
+	params.buffer_size = 0x5000;	/* ?? */
+	params.num_buffers = 22;	/* ?? */
+	params.context = smsdev;
+
+	snprintf(params.devpath, sizeof(params.devpath),
+		 "sdio\\%s", sdio_func_id(func));
+
+	params.sendrequest_handler = smssdio_sendrequest;
+
+	params.device_type = sms_get_board(board_id)->type;
+
+	if (params.device_type != SMS_STELLAR)
+		params.flags |= SMS_DEVICE_FAMILY2;
+	else {
+		/*
+		 * FIXME: Stellar needs special handling...
+		 */
+		ret = -ENODEV;
+		goto free;
+	}
+
+	ret = smscore_register_device(&params, &smsdev->coredev);
+	if (ret < 0)
+		goto free;
+
+	smscore_set_board_id(smsdev->coredev, board_id);
+
+	sdio_claim_host(func);
+
+	ret = sdio_enable_func(func);
+	if (ret)
+		goto release;
+
+	ret = sdio_set_block_size(func, SMSSDIO_BLOCK_SIZE);
+	if (ret)
+		goto disable;
+
+	ret = sdio_claim_irq(func, smssdio_interrupt);
+	if (ret)
+		goto disable;
+
+	sdio_set_drvdata(func, smsdev);
+
+	sdio_release_host(func);
+
+	ret = smscore_start_device(smsdev->coredev);
+	if (ret < 0)
+		goto reclaim;
+
+	return 0;
+
+reclaim:
+	sdio_claim_host(func);
+	sdio_release_irq(func);
+disable:
+	sdio_disable_func(func);
+release:
+	sdio_release_host(func);
+	smscore_unregister_device(smsdev->coredev);
+free:
+	kfree(smsdev);
+
+	return ret;
+}
+
+static void smssdio_remove(struct sdio_func *func)
+{
+	struct smssdio_device *smsdev;
+
+	smsdev = sdio_get_drvdata(func);
+
+	/* FIXME: racy! */
+	if (smsdev->split_cb)
+		smscore_putbuffer(smsdev->coredev, smsdev->split_cb);
+
+	smscore_unregister_device(smsdev->coredev);
+
+	sdio_claim_host(func);
+	sdio_release_irq(func);
+	sdio_disable_func(func);
+	sdio_release_host(func);
+
+	kfree(smsdev);
+}
+
+static struct sdio_driver smssdio_driver = {
+	.name = "smssdio",
+	.id_table = smssdio_ids,
+	.probe = smssdio_probe,
+	.remove = smssdio_remove,
+};
+
+/*******************************************************************/
+/* Module functions                                                */
+/*******************************************************************/
+
+static int __init smssdio_module_init(void)
+{
+	int ret = 0;
+
+	printk(KERN_INFO "smssdio: Siano SMS1xxx SDIO driver\n");
+	printk(KERN_INFO "smssdio: Copyright Pierre Ossman\n");
+
+	ret = sdio_register_driver(&smssdio_driver);
+
+	return ret;
+}
+
+static void __exit smssdio_module_exit(void)
+{
+	sdio_unregister_driver(&smssdio_driver);
+}
+
+module_init(smssdio_module_init);
+module_exit(smssdio_module_exit);
+
+MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver");
+MODULE_AUTHOR("Pierre Ossman");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/parport/Kconfig b/drivers/media/parport/Kconfig
new file mode 100644
index 0000000..48138fe
--- /dev/null
+++ b/drivers/media/parport/Kconfig
@@ -0,0 +1,47 @@
+menu "V4L ISA and parallel port devices"
+	visible if (ISA || PARPORT) && MEDIA_CAMERA_SUPPORT
+
+config VIDEO_BWQCAM
+	tristate "Quickcam BW Video For Linux"
+	depends on PARPORT && VIDEO_V4L2
+	help
+	  Say Y have if you the black and white version of the QuickCam
+	  camera. See the next option for the color version.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bw-qcam.
+
+config VIDEO_CQCAM
+	tristate "QuickCam Colour Video For Linux"
+	depends on PARPORT && VIDEO_V4L2
+	help
+	  This is the video4linux driver for the colour version of the
+	  Connectix QuickCam.  If you have one of these cameras, say Y here,
+	  otherwise say N.  This driver does not work with the original
+	  monochrome QuickCam, QuickCam VC or QuickClip.  It is also available
+	  as a module (c-qcam).
+	  Read <file:Documentation/video4linux/CQcam.txt> for more information.
+
+config VIDEO_PMS
+	tristate "Mediavision Pro Movie Studio Video For Linux"
+	depends on ISA && VIDEO_V4L2
+	help
+	  Say Y if you have the ISA Mediavision Pro Movie Studio
+	  capture card.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pms.
+
+config VIDEO_W9966
+	tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux"
+	depends on PARPORT_1284 && PARPORT && VIDEO_V4L2
+	help
+	  Video4linux driver for Winbond's w9966 based Webcams.
+	  Currently tested with the LifeView FlyCam Supra.
+	  If you have one of these cameras, say Y here
+	  otherwise say N.
+	  This driver is also available as a module (w9966).
+
+	  Check out <file:Documentation/video4linux/w9966.txt> for more
+	  information.
+endmenu
diff --git a/drivers/media/parport/Makefile b/drivers/media/parport/Makefile
new file mode 100644
index 0000000..4eea06d
--- /dev/null
+++ b/drivers/media/parport/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
+obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
+obj-$(CONFIG_VIDEO_W9966) += w9966.o
+obj-$(CONFIG_VIDEO_PMS) += pms.o
diff --git a/drivers/media/parport/bw-qcam.c b/drivers/media/parport/bw-qcam.c
new file mode 100644
index 0000000..5b75a64
--- /dev/null
+++ b/drivers/media/parport/bw-qcam.c
@@ -0,0 +1,1113 @@
+/*
+ *    QuickCam Driver For Video4Linux.
+ *
+ *	Video4Linux conversion work by Alan Cox.
+ *	Parport compatibility by Phil Blundell.
+ *	Busy loop avoidance by Mark Cooke.
+ *
+ *    Module parameters:
+ *
+ *	maxpoll=<1 - 5000>
+ *
+ *	  When polling the QuickCam for a response, busy-wait for a
+ *	  maximum of this many loops. The default of 250 gives little
+ *	  impact on interactive response.
+ *
+ *	  NOTE: If this parameter is set too high, the processor
+ *		will busy wait until this loop times out, and then
+ *		slowly poll for a further 5 seconds before failing
+ *		the transaction. You have been warned.
+ *
+ *	yieldlines=<1 - 250>
+ *
+ *	  When acquiring a frame from the camera, the data gathering
+ *	  loop will yield back to the scheduler after completing
+ *	  this many lines. The default of 4 provides a trade-off
+ *	  between increased frame acquisition time and impact on
+ *	  interactive response.
+ */
+
+/* qcam-lib.c -- Library for programming with the Connectix QuickCam.
+ * See the included documentation for usage instructions and details
+ * of the protocol involved. */
+
+
+/* Version 0.5, August 4, 1996 */
+/* Version 0.7, August 27, 1996 */
+/* Version 0.9, November 17, 1996 */
+
+
+/******************************************************************
+
+Copyright (C) 1996 by Scott Laird
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/parport.h>
+#include <linux/sched.h>
+#include <linux/videodev2.h>
+#include <linux/mutex.h>
+#include <asm/uaccess.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+
+/* One from column A... */
+#define QC_NOTSET 0
+#define QC_UNIDIR 1
+#define QC_BIDIR  2
+#define QC_SERIAL 3
+
+/* ... and one from column B */
+#define QC_ANY          0x00
+#define QC_FORCE_UNIDIR 0x10
+#define QC_FORCE_BIDIR  0x20
+#define QC_FORCE_SERIAL 0x30
+/* in the port_mode member */
+
+#define QC_MODE_MASK    0x07
+#define QC_FORCE_MASK   0x70
+
+#define MAX_HEIGHT 243
+#define MAX_WIDTH 336
+
+/* Bit fields for status flags */
+#define QC_PARAM_CHANGE	0x01 /* Camera status change has occurred */
+
+struct qcam {
+	struct v4l2_device v4l2_dev;
+	struct video_device vdev;
+	struct v4l2_ctrl_handler hdl;
+	struct pardevice *pdev;
+	struct parport *pport;
+	struct mutex lock;
+	int width, height;
+	int bpp;
+	int mode;
+	int contrast, brightness, whitebal;
+	int port_mode;
+	int transfer_scale;
+	int top, left;
+	int status;
+	unsigned int saved_bits;
+	unsigned long in_use;
+};
+
+static unsigned int maxpoll = 250;   /* Maximum busy-loop count for qcam I/O */
+static unsigned int yieldlines = 4;  /* Yield after this many during capture */
+static int video_nr = -1;
+static unsigned int force_init;		/* Whether to probe aggressively */
+
+module_param(maxpoll, int, 0);
+module_param(yieldlines, int, 0);
+module_param(video_nr, int, 0);
+
+/* Set force_init=1 to avoid detection by polling status register and
+ * immediately attempt to initialize qcam */
+module_param(force_init, int, 0);
+
+#define MAX_CAMS 4
+static struct qcam *qcams[MAX_CAMS];
+static unsigned int num_cams;
+
+static inline int read_lpstatus(struct qcam *q)
+{
+	return parport_read_status(q->pport);
+}
+
+static inline int read_lpdata(struct qcam *q)
+{
+	return parport_read_data(q->pport);
+}
+
+static inline void write_lpdata(struct qcam *q, int d)
+{
+	parport_write_data(q->pport, d);
+}
+
+static void write_lpcontrol(struct qcam *q, int d)
+{
+	if (d & 0x20) {
+		/* Set bidirectional mode to reverse (data in) */
+		parport_data_reverse(q->pport);
+	} else {
+		/* Set bidirectional mode to forward (data out) */
+		parport_data_forward(q->pport);
+	}
+
+	/* Now issue the regular port command, but strip out the
+	 * direction flag */
+	d &= ~0x20;
+	parport_write_control(q->pport, d);
+}
+
+
+/* qc_waithand busy-waits for a handshake signal from the QuickCam.
+ * Almost all communication with the camera requires handshaking. */
+
+static int qc_waithand(struct qcam *q, int val)
+{
+	int status;
+	int runs = 0;
+
+	if (val) {
+		while (!((status = read_lpstatus(q)) & 8)) {
+			/* 1000 is enough spins on the I/O for all normal
+			   cases, at that point we start to poll slowly
+			   until the camera wakes up. However, we are
+			   busy blocked until the camera responds, so
+			   setting it lower is much better for interactive
+			   response. */
+
+			if (runs++ > maxpoll)
+				msleep_interruptible(5);
+			if (runs > (maxpoll + 1000)) /* 5 seconds */
+				return -1;
+		}
+	} else {
+		while (((status = read_lpstatus(q)) & 8)) {
+			/* 1000 is enough spins on the I/O for all normal
+			   cases, at that point we start to poll slowly
+			   until the camera wakes up. However, we are
+			   busy blocked until the camera responds, so
+			   setting it lower is much better for interactive
+			   response. */
+
+			if (runs++ > maxpoll)
+				msleep_interruptible(5);
+			if (runs++ > (maxpoll + 1000)) /* 5 seconds */
+				return -1;
+		}
+	}
+
+	return status;
+}
+
+/* Waithand2 is used when the qcam is in bidirectional mode, and the
+ * handshaking signal is CamRdy2 (bit 0 of data reg) instead of CamRdy1
+ * (bit 3 of status register).  It also returns the last value read,
+ * since this data is useful. */
+
+static unsigned int qc_waithand2(struct qcam *q, int val)
+{
+	unsigned int status;
+	int runs = 0;
+
+	do {
+		status = read_lpdata(q);
+		/* 1000 is enough spins on the I/O for all normal
+		   cases, at that point we start to poll slowly
+		   until the camera wakes up. However, we are
+		   busy blocked until the camera responds, so
+		   setting it lower is much better for interactive
+		   response. */
+
+		if (runs++ > maxpoll)
+			msleep_interruptible(5);
+		if (runs++ > (maxpoll + 1000)) /* 5 seconds */
+			return 0;
+	} while ((status & 1) != val);
+
+	return status;
+}
+
+/* qc_command is probably a bit of a misnomer -- it's used to send
+ * bytes *to* the camera.  Generally, these bytes are either commands
+ * or arguments to commands, so the name fits, but it still bugs me a
+ * bit.  See the documentation for a list of commands. */
+
+static int qc_command(struct qcam *q, int command)
+{
+	int n1, n2;
+	int cmd;
+
+	write_lpdata(q, command);
+	write_lpcontrol(q, 6);
+
+	n1 = qc_waithand(q, 1);
+
+	write_lpcontrol(q, 0xe);
+	n2 = qc_waithand(q, 0);
+
+	cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
+	return cmd;
+}
+
+static int qc_readparam(struct qcam *q)
+{
+	int n1, n2;
+	int cmd;
+
+	write_lpcontrol(q, 6);
+	n1 = qc_waithand(q, 1);
+
+	write_lpcontrol(q, 0xe);
+	n2 = qc_waithand(q, 0);
+
+	cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
+	return cmd;
+}
+
+
+/* Try to detect a QuickCam.  It appears to flash the upper 4 bits of
+   the status register at 5-10 Hz.  This is only used in the autoprobe
+   code.  Be aware that this isn't the way Connectix detects the
+   camera (they send a reset and try to handshake), but this should be
+   almost completely safe, while their method screws up my printer if
+   I plug it in before the camera. */
+
+static int qc_detect(struct qcam *q)
+{
+	int reg, lastreg;
+	int count = 0;
+	int i;
+
+	if (force_init)
+		return 1;
+
+	lastreg = reg = read_lpstatus(q) & 0xf0;
+
+	for (i = 0; i < 500; i++) {
+		reg = read_lpstatus(q) & 0xf0;
+		if (reg != lastreg)
+			count++;
+		lastreg = reg;
+		mdelay(2);
+	}
+
+
+#if 0
+	/* Force camera detection during testing. Sometimes the camera
+	   won't be flashing these bits. Possibly unloading the module
+	   in the middle of a grab? Or some timeout condition?
+	   I've seen this parameter as low as 19 on my 450Mhz box - mpc */
+	printk(KERN_DEBUG "Debugging: QCam detection counter <30-200 counts as detected>: %d\n", count);
+	return 1;
+#endif
+
+	/* Be (even more) liberal in what you accept...  */
+
+	if (count > 20 && count < 400) {
+		return 1;	/* found */
+	} else {
+		printk(KERN_ERR "No Quickcam found on port %s\n",
+				q->pport->name);
+		printk(KERN_DEBUG "Quickcam detection counter: %u\n", count);
+		return 0;	/* not found */
+	}
+}
+
+/* Decide which scan mode to use.  There's no real requirement that
+ * the scanmode match the resolution in q->height and q-> width -- the
+ * camera takes the picture at the resolution specified in the
+ * "scanmode" and then returns the image at the resolution specified
+ * with the resolution commands.  If the scan is bigger than the
+ * requested resolution, the upper-left hand corner of the scan is
+ * returned.  If the scan is smaller, then the rest of the image
+ * returned contains garbage. */
+
+static int qc_setscanmode(struct qcam *q)
+{
+	int old_mode = q->mode;
+
+	switch (q->transfer_scale) {
+	case 1:
+		q->mode = 0;
+		break;
+	case 2:
+		q->mode = 4;
+		break;
+	case 4:
+		q->mode = 8;
+		break;
+	}
+
+	switch (q->bpp) {
+	case 4:
+		break;
+	case 6:
+		q->mode += 2;
+		break;
+	}
+
+	switch (q->port_mode & QC_MODE_MASK) {
+	case QC_BIDIR:
+		q->mode += 1;
+		break;
+	case QC_NOTSET:
+	case QC_UNIDIR:
+		break;
+	}
+
+	if (q->mode != old_mode)
+		q->status |= QC_PARAM_CHANGE;
+
+	return 0;
+}
+
+
+/* Reset the QuickCam.  This uses the same sequence the Windows
+ * QuickPic program uses.  Someone with a bi-directional port should
+ * check that bi-directional mode is detected right, and then
+ * implement bi-directional mode in qc_readbyte(). */
+
+static void qc_reset(struct qcam *q)
+{
+	switch (q->port_mode & QC_FORCE_MASK) {
+	case QC_FORCE_UNIDIR:
+		q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
+		break;
+
+	case QC_FORCE_BIDIR:
+		q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
+		break;
+
+	case QC_ANY:
+		write_lpcontrol(q, 0x20);
+		write_lpdata(q, 0x75);
+
+		if (read_lpdata(q) != 0x75)
+			q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
+		else
+			q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
+		break;
+	}
+
+	write_lpcontrol(q, 0xb);
+	udelay(250);
+	write_lpcontrol(q, 0xe);
+	qc_setscanmode(q);		/* in case port_mode changed */
+}
+
+
+
+/* Reset the QuickCam and program for brightness, contrast,
+ * white-balance, and resolution. */
+
+static void qc_set(struct qcam *q)
+{
+	int val;
+	int val2;
+
+	qc_reset(q);
+
+	/* Set the brightness.  Yes, this is repetitive, but it works.
+	 * Shorter versions seem to fail subtly.  Feel free to try :-). */
+	/* I think the problem was in qc_command, not here -- bls */
+
+	qc_command(q, 0xb);
+	qc_command(q, q->brightness);
+
+	val = q->height / q->transfer_scale;
+	qc_command(q, 0x11);
+	qc_command(q, val);
+	if ((q->port_mode & QC_MODE_MASK) == QC_UNIDIR && q->bpp == 6) {
+		/* The normal "transfers per line" calculation doesn't seem to work
+		   as expected here (and yet it works fine in qc_scan).  No idea
+		   why this case is the odd man out.  Fortunately, Laird's original
+		   working version gives me a good way to guess at working values.
+		   -- bls */
+		val = q->width;
+		val2 = q->transfer_scale * 4;
+	} else {
+		val = q->width * q->bpp;
+		val2 = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) *
+			q->transfer_scale;
+	}
+	val = DIV_ROUND_UP(val, val2);
+	qc_command(q, 0x13);
+	qc_command(q, val);
+
+	/* Setting top and left -- bls */
+	qc_command(q, 0xd);
+	qc_command(q, q->top);
+	qc_command(q, 0xf);
+	qc_command(q, q->left / 2);
+
+	qc_command(q, 0x19);
+	qc_command(q, q->contrast);
+	qc_command(q, 0x1f);
+	qc_command(q, q->whitebal);
+
+	/* Clear flag that we must update the grabbing parameters on the camera
+	   before we grab the next frame */
+	q->status &= (~QC_PARAM_CHANGE);
+}
+
+/* Qc_readbytes reads some bytes from the QC and puts them in
+   the supplied buffer.  It returns the number of bytes read,
+   or -1 on error. */
+
+static inline int qc_readbytes(struct qcam *q, char buffer[])
+{
+	int ret = 1;
+	unsigned int hi, lo;
+	unsigned int hi2, lo2;
+	static int state;
+
+	if (buffer == NULL) {
+		state = 0;
+		return 0;
+	}
+
+	switch (q->port_mode & QC_MODE_MASK) {
+	case QC_BIDIR:		/* Bi-directional Port */
+		write_lpcontrol(q, 0x26);
+		lo = (qc_waithand2(q, 1) >> 1);
+		hi = (read_lpstatus(q) >> 3) & 0x1f;
+		write_lpcontrol(q, 0x2e);
+		lo2 = (qc_waithand2(q, 0) >> 1);
+		hi2 = (read_lpstatus(q) >> 3) & 0x1f;
+		switch (q->bpp) {
+		case 4:
+			buffer[0] = lo & 0xf;
+			buffer[1] = ((lo & 0x70) >> 4) | ((hi & 1) << 3);
+			buffer[2] = (hi & 0x1e) >> 1;
+			buffer[3] = lo2 & 0xf;
+			buffer[4] = ((lo2 & 0x70) >> 4) | ((hi2 & 1) << 3);
+			buffer[5] = (hi2 & 0x1e) >> 1;
+			ret = 6;
+			break;
+		case 6:
+			buffer[0] = lo & 0x3f;
+			buffer[1] = ((lo & 0x40) >> 6) | (hi << 1);
+			buffer[2] = lo2 & 0x3f;
+			buffer[3] = ((lo2 & 0x40) >> 6) | (hi2 << 1);
+			ret = 4;
+			break;
+		}
+		break;
+
+	case QC_UNIDIR:	/* Unidirectional Port */
+		write_lpcontrol(q, 6);
+		lo = (qc_waithand(q, 1) & 0xf0) >> 4;
+		write_lpcontrol(q, 0xe);
+		hi = (qc_waithand(q, 0) & 0xf0) >> 4;
+
+		switch (q->bpp) {
+		case 4:
+			buffer[0] = lo;
+			buffer[1] = hi;
+			ret = 2;
+			break;
+		case 6:
+			switch (state) {
+			case 0:
+				buffer[0] = (lo << 2) | ((hi & 0xc) >> 2);
+				q->saved_bits = (hi & 3) << 4;
+				state = 1;
+				ret = 1;
+				break;
+			case 1:
+				buffer[0] = lo | q->saved_bits;
+				q->saved_bits = hi << 2;
+				state = 2;
+				ret = 1;
+				break;
+			case 2:
+				buffer[0] = ((lo & 0xc) >> 2) | q->saved_bits;
+				buffer[1] = ((lo & 3) << 4) | hi;
+				state = 0;
+				ret = 2;
+				break;
+			}
+			break;
+		}
+		break;
+	}
+	return ret;
+}
+
+/* requests a scan from the camera.  It sends the correct instructions
+ * to the camera and then reads back the correct number of bytes.  In
+ * previous versions of this routine the return structure contained
+ * the raw output from the camera, and there was a 'qc_convertscan'
+ * function that converted that to a useful format.  In version 0.3 I
+ * rolled qc_convertscan into qc_scan and now I only return the
+ * converted scan.  The format is just an one-dimensional array of
+ * characters, one for each pixel, with 0=black up to n=white, where
+ * n=2^(bit depth)-1.  Ask me for more details if you don't understand
+ * this. */
+
+static long qc_capture(struct qcam *q, char __user *buf, unsigned long len)
+{
+	int i, j, k, yield;
+	int bytes;
+	int linestotrans, transperline;
+	int divisor;
+	int pixels_per_line;
+	int pixels_read = 0;
+	int got = 0;
+	char buffer[6];
+	int  shift = 8 - q->bpp;
+	char invert;
+
+	if (q->mode == -1)
+		return -ENXIO;
+
+	qc_command(q, 0x7);
+	qc_command(q, q->mode);
+
+	if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) {
+		write_lpcontrol(q, 0x2e);	/* turn port around */
+		write_lpcontrol(q, 0x26);
+		qc_waithand(q, 1);
+		write_lpcontrol(q, 0x2e);
+		qc_waithand(q, 0);
+	}
+
+	/* strange -- should be 15:63 below, but 4bpp is odd */
+	invert = (q->bpp == 4) ? 16 : 63;
+
+	linestotrans = q->height / q->transfer_scale;
+	pixels_per_line = q->width / q->transfer_scale;
+	transperline = q->width * q->bpp;
+	divisor = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) *
+		q->transfer_scale;
+	transperline = DIV_ROUND_UP(transperline, divisor);
+
+	for (i = 0, yield = yieldlines; i < linestotrans; i++) {
+		for (pixels_read = j = 0; j < transperline; j++) {
+			bytes = qc_readbytes(q, buffer);
+			for (k = 0; k < bytes && (pixels_read + k) < pixels_per_line; k++) {
+				int o;
+				if (buffer[k] == 0 && invert == 16) {
+					/* 4bpp is odd (again) -- inverter is 16, not 15, but output
+					   must be 0-15 -- bls */
+					buffer[k] = 16;
+				}
+				o = i * pixels_per_line + pixels_read + k;
+				if (o < len) {
+					u8 ch = invert - buffer[k];
+					got++;
+					put_user(ch << shift, buf + o);
+				}
+			}
+			pixels_read += bytes;
+		}
+		qc_readbytes(q, NULL);	/* reset state machine */
+
+		/* Grabbing an entire frame from the quickcam is a lengthy
+		   process. We don't (usually) want to busy-block the
+		   processor for the entire frame. yieldlines is a module
+		   parameter. If we yield every line, the minimum frame
+		   time will be 240 / 200 = 1.2 seconds. The compile-time
+		   default is to yield every 4 lines. */
+		if (i >= yield) {
+			msleep_interruptible(5);
+			yield = i + yieldlines;
+		}
+	}
+
+	if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) {
+		write_lpcontrol(q, 2);
+		write_lpcontrol(q, 6);
+		udelay(3);
+		write_lpcontrol(q, 0xe);
+	}
+	if (got < len)
+		return got;
+	return len;
+}
+
+/*
+ *	Video4linux interfacing
+ */
+
+static int qcam_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *vcap)
+{
+	struct qcam *qcam = video_drvdata(file);
+
+	strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
+	strlcpy(vcap->card, "Connectix B&W Quickcam", sizeof(vcap->card));
+	strlcpy(vcap->bus_info, qcam->pport->name, sizeof(vcap->bus_info));
+	vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
+	return 0;
+}
+
+static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+	if (vin->index > 0)
+		return -EINVAL;
+	strlcpy(vin->name, "Camera", sizeof(vin->name));
+	vin->type = V4L2_INPUT_TYPE_CAMERA;
+	vin->audioset = 0;
+	vin->tuner = 0;
+	vin->std = 0;
+	vin->status = 0;
+	return 0;
+}
+
+static int qcam_g_input(struct file *file, void *fh, unsigned int *inp)
+{
+	*inp = 0;
+	return 0;
+}
+
+static int qcam_s_input(struct file *file, void *fh, unsigned int inp)
+{
+	return (inp > 0) ? -EINVAL : 0;
+}
+
+static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct qcam *qcam = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	pix->width = qcam->width / qcam->transfer_scale;
+	pix->height = qcam->height / qcam->transfer_scale;
+	pix->pixelformat = (qcam->bpp == 4) ? V4L2_PIX_FMT_Y4 : V4L2_PIX_FMT_Y6;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = pix->width;
+	pix->sizeimage = pix->width * pix->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SRGB;
+	return 0;
+}
+
+static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	if (pix->height <= 60 || pix->width <= 80) {
+		pix->height = 60;
+		pix->width = 80;
+	} else if (pix->height <= 120 || pix->width <= 160) {
+		pix->height = 120;
+		pix->width = 160;
+	} else {
+		pix->height = 240;
+		pix->width = 320;
+	}
+	if (pix->pixelformat != V4L2_PIX_FMT_Y4 &&
+	    pix->pixelformat != V4L2_PIX_FMT_Y6)
+		pix->pixelformat = V4L2_PIX_FMT_Y4;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = pix->width;
+	pix->sizeimage = pix->width * pix->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SRGB;
+	return 0;
+}
+
+static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct qcam *qcam = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+	int ret = qcam_try_fmt_vid_cap(file, fh, fmt);
+
+	if (ret)
+		return ret;
+	qcam->width = 320;
+	qcam->height = 240;
+	if (pix->height == 60)
+		qcam->transfer_scale = 4;
+	else if (pix->height == 120)
+		qcam->transfer_scale = 2;
+	else
+		qcam->transfer_scale = 1;
+	if (pix->pixelformat == V4L2_PIX_FMT_Y6)
+		qcam->bpp = 6;
+	else
+		qcam->bpp = 4;
+
+	mutex_lock(&qcam->lock);
+	qc_setscanmode(qcam);
+	/* We must update the camera before we grab. We could
+	   just have changed the grab size */
+	qcam->status |= QC_PARAM_CHANGE;
+	mutex_unlock(&qcam->lock);
+	return 0;
+}
+
+static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
+{
+	static struct v4l2_fmtdesc formats[] = {
+		{ 0, 0, 0,
+		  "4-Bit Monochrome", V4L2_PIX_FMT_Y4,
+		  { 0, 0, 0, 0 }
+		},
+		{ 1, 0, 0,
+		  "6-Bit Monochrome", V4L2_PIX_FMT_Y6,
+		  { 0, 0, 0, 0 }
+		},
+	};
+	enum v4l2_buf_type type = fmt->type;
+
+	if (fmt->index > 1)
+		return -EINVAL;
+
+	*fmt = formats[fmt->index];
+	fmt->type = type;
+	return 0;
+}
+
+static int qcam_enum_framesizes(struct file *file, void *fh,
+					 struct v4l2_frmsizeenum *fsize)
+{
+	static const struct v4l2_frmsize_discrete sizes[] = {
+		{  80,  60 },
+		{ 160, 120 },
+		{ 320, 240 },
+	};
+
+	if (fsize->index > 2)
+		return -EINVAL;
+	if (fsize->pixel_format != V4L2_PIX_FMT_Y4 &&
+	    fsize->pixel_format != V4L2_PIX_FMT_Y6)
+		return -EINVAL;
+	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+	fsize->discrete = sizes[fsize->index];
+	return 0;
+}
+
+static ssize_t qcam_read(struct file *file, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct qcam *qcam = video_drvdata(file);
+	int len;
+	parport_claim_or_block(qcam->pdev);
+
+	mutex_lock(&qcam->lock);
+
+	qc_reset(qcam);
+
+	/* Update the camera parameters if we need to */
+	if (qcam->status & QC_PARAM_CHANGE)
+		qc_set(qcam);
+
+	len = qc_capture(qcam, buf, count);
+
+	mutex_unlock(&qcam->lock);
+
+	parport_release(qcam->pdev);
+	return len;
+}
+
+static unsigned int qcam_poll(struct file *filp, poll_table *wait)
+{
+	return v4l2_ctrl_poll(filp, wait) | POLLIN | POLLRDNORM;
+}
+
+static int qcam_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct qcam *qcam =
+		container_of(ctrl->handler, struct qcam, hdl);
+	int ret = 0;
+
+	mutex_lock(&qcam->lock);
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		qcam->brightness = ctrl->val;
+		break;
+	case V4L2_CID_CONTRAST:
+		qcam->contrast = ctrl->val;
+		break;
+	case V4L2_CID_GAMMA:
+		qcam->whitebal = ctrl->val;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	if (ret == 0) {
+		qc_setscanmode(qcam);
+		qcam->status |= QC_PARAM_CHANGE;
+	}
+	mutex_unlock(&qcam->lock);
+	return ret;
+}
+
+static const struct v4l2_file_operations qcam_fops = {
+	.owner		= THIS_MODULE,
+	.open		= v4l2_fh_open,
+	.release	= v4l2_fh_release,
+	.poll		= qcam_poll,
+	.unlocked_ioctl = video_ioctl2,
+	.read		= qcam_read,
+};
+
+static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
+	.vidioc_querycap    		    = qcam_querycap,
+	.vidioc_g_input      		    = qcam_g_input,
+	.vidioc_s_input      		    = qcam_s_input,
+	.vidioc_enum_input   		    = qcam_enum_input,
+	.vidioc_enum_fmt_vid_cap 	    = qcam_enum_fmt_vid_cap,
+	.vidioc_enum_framesizes		    = qcam_enum_framesizes,
+	.vidioc_g_fmt_vid_cap 		    = qcam_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap  		    = qcam_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap  	    = qcam_try_fmt_vid_cap,
+	.vidioc_log_status		    = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event		    = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event	    = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_ctrl_ops qcam_ctrl_ops = {
+	.s_ctrl = qcam_s_ctrl,
+};
+
+/* Initialize the QuickCam driver control structure.  This is where
+ * defaults are set for people who don't have a config file.*/
+
+static struct qcam *qcam_init(struct parport *port)
+{
+	struct qcam *qcam;
+	struct v4l2_device *v4l2_dev;
+
+	qcam = kzalloc(sizeof(struct qcam), GFP_KERNEL);
+	if (qcam == NULL)
+		return NULL;
+
+	v4l2_dev = &qcam->v4l2_dev;
+	snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "bw-qcam%d", num_cams);
+
+	if (v4l2_device_register(port->dev, v4l2_dev) < 0) {
+		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+		kfree(qcam);
+		return NULL;
+	}
+
+	v4l2_ctrl_handler_init(&qcam->hdl, 3);
+	v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+			  V4L2_CID_BRIGHTNESS, 0, 255, 1, 180);
+	v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+			  V4L2_CID_CONTRAST, 0, 255, 1, 192);
+	v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+			  V4L2_CID_GAMMA, 0, 255, 1, 105);
+	if (qcam->hdl.error) {
+		v4l2_err(v4l2_dev, "couldn't register controls\n");
+		v4l2_ctrl_handler_free(&qcam->hdl);
+		kfree(qcam);
+		return NULL;
+	}
+	qcam->pport = port;
+	qcam->pdev = parport_register_device(port, v4l2_dev->name, NULL, NULL,
+			NULL, 0, NULL);
+	if (qcam->pdev == NULL) {
+		v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
+		v4l2_ctrl_handler_free(&qcam->hdl);
+		kfree(qcam);
+		return NULL;
+	}
+
+	strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name));
+	qcam->vdev.v4l2_dev = v4l2_dev;
+	qcam->vdev.ctrl_handler = &qcam->hdl;
+	qcam->vdev.fops = &qcam_fops;
+	qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
+	set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags);
+	qcam->vdev.release = video_device_release_empty;
+	video_set_drvdata(&qcam->vdev, qcam);
+
+	mutex_init(&qcam->lock);
+
+	qcam->port_mode = (QC_ANY | QC_NOTSET);
+	qcam->width = 320;
+	qcam->height = 240;
+	qcam->bpp = 4;
+	qcam->transfer_scale = 2;
+	qcam->contrast = 192;
+	qcam->brightness = 180;
+	qcam->whitebal = 105;
+	qcam->top = 1;
+	qcam->left = 14;
+	qcam->mode = -1;
+	qcam->status = QC_PARAM_CHANGE;
+	return qcam;
+}
+
+static int qc_calibrate(struct qcam *q)
+{
+	/*
+	 *	Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96
+	 *	The white balance is an individual value for each
+	 *	quickcam.
+	 */
+
+	int value;
+	int count = 0;
+
+	qc_command(q, 27);	/* AutoAdjustOffset */
+	qc_command(q, 0);	/* Dummy Parameter, ignored by the camera */
+
+	/* GetOffset (33) will read 255 until autocalibration */
+	/* is finished. After that, a value of 1-254 will be */
+	/* returned. */
+
+	do {
+		qc_command(q, 33);
+		value = qc_readparam(q);
+		mdelay(1);
+		schedule();
+		count++;
+	} while (value == 0xff && count < 2048);
+
+	q->whitebal = value;
+	return value;
+}
+
+static int init_bwqcam(struct parport *port)
+{
+	struct qcam *qcam;
+
+	if (num_cams == MAX_CAMS) {
+		printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS);
+		return -ENOSPC;
+	}
+
+	qcam = qcam_init(port);
+	if (qcam == NULL)
+		return -ENODEV;
+
+	parport_claim_or_block(qcam->pdev);
+
+	qc_reset(qcam);
+
+	if (qc_detect(qcam) == 0) {
+		parport_release(qcam->pdev);
+		parport_unregister_device(qcam->pdev);
+		kfree(qcam);
+		return -ENODEV;
+	}
+	qc_calibrate(qcam);
+	v4l2_ctrl_handler_setup(&qcam->hdl);
+
+	parport_release(qcam->pdev);
+
+	v4l2_info(&qcam->v4l2_dev, "Connectix Quickcam on %s\n", qcam->pport->name);
+
+	if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
+		parport_unregister_device(qcam->pdev);
+		kfree(qcam);
+		return -ENODEV;
+	}
+
+	qcams[num_cams++] = qcam;
+
+	return 0;
+}
+
+static void close_bwqcam(struct qcam *qcam)
+{
+	video_unregister_device(&qcam->vdev);
+	v4l2_ctrl_handler_free(&qcam->hdl);
+	parport_unregister_device(qcam->pdev);
+	kfree(qcam);
+}
+
+/* The parport parameter controls which parports will be scanned.
+ * Scanning all parports causes some printers to print a garbage page.
+ *       -- March 14, 1999  Billy Donahue <billy@escape.com> */
+#ifdef MODULE
+static char *parport[MAX_CAMS] = { NULL, };
+module_param_array(parport, charp, NULL, 0);
+#endif
+
+static int accept_bwqcam(struct parport *port)
+{
+#ifdef MODULE
+	int n;
+
+	if (parport[0] && strncmp(parport[0], "auto", 4) != 0) {
+		/* user gave parport parameters */
+		for (n = 0; n < MAX_CAMS && parport[n]; n++) {
+			char *ep;
+			unsigned long r;
+			r = simple_strtoul(parport[n], &ep, 0);
+			if (ep == parport[n]) {
+				printk(KERN_ERR
+					"bw-qcam: bad port specifier \"%s\"\n",
+					parport[n]);
+				continue;
+			}
+			if (r == port->number)
+				return 1;
+		}
+		return 0;
+	}
+#endif
+	return 1;
+}
+
+static void bwqcam_attach(struct parport *port)
+{
+	if (accept_bwqcam(port))
+		init_bwqcam(port);
+}
+
+static void bwqcam_detach(struct parport *port)
+{
+	int i;
+	for (i = 0; i < num_cams; i++) {
+		struct qcam *qcam = qcams[i];
+		if (qcam && qcam->pdev->port == port) {
+			qcams[i] = NULL;
+			close_bwqcam(qcam);
+		}
+	}
+}
+
+static struct parport_driver bwqcam_driver = {
+	.name	= "bw-qcam",
+	.attach	= bwqcam_attach,
+	.detach	= bwqcam_detach,
+};
+
+static void __exit exit_bw_qcams(void)
+{
+	parport_unregister_driver(&bwqcam_driver);
+}
+
+static int __init init_bw_qcams(void)
+{
+#ifdef MODULE
+	/* Do some sanity checks on the module parameters. */
+	if (maxpoll > 5000) {
+		printk(KERN_INFO "Connectix Quickcam max-poll was above 5000. Using 5000.\n");
+		maxpoll = 5000;
+	}
+
+	if (yieldlines < 1) {
+		printk(KERN_INFO "Connectix Quickcam yieldlines was less than 1. Using 1.\n");
+		yieldlines = 1;
+	}
+#endif
+	return parport_register_driver(&bwqcam_driver);
+}
+
+module_init(init_bw_qcams);
+module_exit(exit_bw_qcams);
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.3");
diff --git a/drivers/media/parport/c-qcam.c b/drivers/media/parport/c-qcam.c
new file mode 100644
index 0000000..ec51e1f
--- /dev/null
+++ b/drivers/media/parport/c-qcam.c
@@ -0,0 +1,883 @@
+/*
+ *	Video4Linux Colour QuickCam driver
+ *	Copyright 1997-2000 Philip Blundell <philb@gnu.org>
+ *
+ *    Module parameters:
+ *
+ *	parport=auto      -- probe all parports (default)
+ *	parport=0         -- parport0 becomes qcam1
+ *	parport=2,0,1     -- parports 2,0,1 are tried in that order
+ *
+ *	probe=0		  -- do no probing, assume camera is present
+ *	probe=1		  -- use IEEE-1284 autoprobe data only (default)
+ *	probe=2		  -- probe aggressively for cameras
+ *
+ *	force_rgb=1       -- force data format to RGB (default is BGR)
+ *
+ * The parport parameter controls which parports will be scanned.
+ * Scanning all parports causes some printers to print a garbage page.
+ *       -- March 14, 1999  Billy Donahue <billy@escape.com>
+ *
+ * Fixed data format to BGR, added force_rgb parameter. Added missing
+ * parport_unregister_driver() on module removal.
+ *       -- May 28, 2000  Claudio Matsuoka <claudio@conectiva.com>
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/parport.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/jiffies.h>
+#include <linux/videodev2.h>
+#include <asm/uaccess.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+
+struct qcam {
+	struct v4l2_device v4l2_dev;
+	struct video_device vdev;
+	struct v4l2_ctrl_handler hdl;
+	struct pardevice *pdev;
+	struct parport *pport;
+	int width, height;
+	int ccd_width, ccd_height;
+	int mode;
+	int contrast, brightness, whitebal;
+	int top, left;
+	unsigned int bidirectional;
+	struct mutex lock;
+};
+
+/* cameras maximum */
+#define MAX_CAMS 4
+
+/* The three possible QuickCam modes */
+#define QC_MILLIONS	0x18
+#define QC_BILLIONS	0x10
+#define QC_THOUSANDS	0x08	/* with VIDEC compression (not supported) */
+
+/* The three possible decimations */
+#define QC_DECIMATION_1		0
+#define QC_DECIMATION_2		2
+#define QC_DECIMATION_4		4
+
+#define BANNER "Colour QuickCam for Video4Linux v0.06"
+
+static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
+static int probe = 2;
+static bool force_rgb;
+static int video_nr = -1;
+
+/* FIXME: parport=auto would never have worked, surely? --RR */
+MODULE_PARM_DESC(parport, "parport=<auto|n[,n]...> for port detection method\n"
+			  "probe=<0|1|2> for camera detection method\n"
+			  "force_rgb=<0|1> for RGB data format (default BGR)");
+module_param_array(parport, int, NULL, 0);
+module_param(probe, int, 0);
+module_param(force_rgb, bool, 0);
+module_param(video_nr, int, 0);
+
+static struct qcam *qcams[MAX_CAMS];
+static unsigned int num_cams;
+
+static inline void qcam_set_ack(struct qcam *qcam, unsigned int i)
+{
+	/* note: the QC specs refer to the PCAck pin by voltage, not
+	   software level.  PC ports have builtin inverters. */
+	parport_frob_control(qcam->pport, 8, i ? 8 : 0);
+}
+
+static inline unsigned int qcam_ready1(struct qcam *qcam)
+{
+	return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0;
+}
+
+static inline unsigned int qcam_ready2(struct qcam *qcam)
+{
+	return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0;
+}
+
+static unsigned int qcam_await_ready1(struct qcam *qcam, int value)
+{
+	struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
+	unsigned long oldjiffies = jiffies;
+	unsigned int i;
+
+	for (oldjiffies = jiffies;
+	     time_before(jiffies, oldjiffies + msecs_to_jiffies(40));)
+		if (qcam_ready1(qcam) == value)
+			return 0;
+
+	/* If the camera didn't respond within 1/25 second, poll slowly
+	   for a while. */
+	for (i = 0; i < 50; i++) {
+		if (qcam_ready1(qcam) == value)
+			return 0;
+		msleep_interruptible(100);
+	}
+
+	/* Probably somebody pulled the plug out.  Not much we can do. */
+	v4l2_err(v4l2_dev, "ready1 timeout (%d) %x %x\n", value,
+	       parport_read_status(qcam->pport),
+	       parport_read_control(qcam->pport));
+	return 1;
+}
+
+static unsigned int qcam_await_ready2(struct qcam *qcam, int value)
+{
+	struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
+	unsigned long oldjiffies = jiffies;
+	unsigned int i;
+
+	for (oldjiffies = jiffies;
+	     time_before(jiffies, oldjiffies + msecs_to_jiffies(40));)
+		if (qcam_ready2(qcam) == value)
+			return 0;
+
+	/* If the camera didn't respond within 1/25 second, poll slowly
+	   for a while. */
+	for (i = 0; i < 50; i++) {
+		if (qcam_ready2(qcam) == value)
+			return 0;
+		msleep_interruptible(100);
+	}
+
+	/* Probably somebody pulled the plug out.  Not much we can do. */
+	v4l2_err(v4l2_dev, "ready2 timeout (%d) %x %x %x\n", value,
+	       parport_read_status(qcam->pport),
+	       parport_read_control(qcam->pport),
+	       parport_read_data(qcam->pport));
+	return 1;
+}
+
+static int qcam_read_data(struct qcam *qcam)
+{
+	unsigned int idata;
+
+	qcam_set_ack(qcam, 0);
+	if (qcam_await_ready1(qcam, 1))
+		return -1;
+	idata = parport_read_status(qcam->pport) & 0xf0;
+	qcam_set_ack(qcam, 1);
+	if (qcam_await_ready1(qcam, 0))
+		return -1;
+	idata |= parport_read_status(qcam->pport) >> 4;
+	return idata;
+}
+
+static int qcam_write_data(struct qcam *qcam, unsigned int data)
+{
+	struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
+	unsigned int idata;
+
+	parport_write_data(qcam->pport, data);
+	idata = qcam_read_data(qcam);
+	if (data != idata) {
+		v4l2_warn(v4l2_dev, "sent %x but received %x\n", data,
+		       idata);
+		return 1;
+	}
+	return 0;
+}
+
+static inline int qcam_set(struct qcam *qcam, unsigned int cmd, unsigned int data)
+{
+	if (qcam_write_data(qcam, cmd))
+		return -1;
+	if (qcam_write_data(qcam, data))
+		return -1;
+	return 0;
+}
+
+static inline int qcam_get(struct qcam *qcam, unsigned int cmd)
+{
+	if (qcam_write_data(qcam, cmd))
+		return -1;
+	return qcam_read_data(qcam);
+}
+
+static int qc_detect(struct qcam *qcam)
+{
+	unsigned int stat, ostat, i, count = 0;
+
+	/* The probe routine below is not very reliable.  The IEEE-1284
+	   probe takes precedence. */
+	/* XXX Currently parport provides no way to distinguish between
+	   "the IEEE probe was not done" and "the probe was done, but
+	   no device was found".  Fix this one day. */
+	if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA
+	    && qcam->pport->probe_info[0].model
+	    && !strcmp(qcam->pdev->port->probe_info[0].model,
+		       "Color QuickCam 2.0")) {
+		printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n");
+		return 1;
+	}
+
+	if (probe < 2)
+		return 0;
+
+	parport_write_control(qcam->pport, 0xc);
+
+	/* look for a heartbeat */
+	ostat = stat = parport_read_status(qcam->pport);
+	for (i = 0; i < 250; i++) {
+		mdelay(1);
+		stat = parport_read_status(qcam->pport);
+		if (ostat != stat) {
+			if (++count >= 3)
+				return 1;
+			ostat = stat;
+		}
+	}
+
+	/* Reset the camera and try again */
+	parport_write_control(qcam->pport, 0xc);
+	parport_write_control(qcam->pport, 0x8);
+	mdelay(1);
+	parport_write_control(qcam->pport, 0xc);
+	mdelay(1);
+	count = 0;
+
+	ostat = stat = parport_read_status(qcam->pport);
+	for (i = 0; i < 250; i++) {
+		mdelay(1);
+		stat = parport_read_status(qcam->pport);
+		if (ostat != stat) {
+			if (++count >= 3)
+				return 1;
+			ostat = stat;
+		}
+	}
+
+	/* no (or flatline) camera, give up */
+	return 0;
+}
+
+static void qc_reset(struct qcam *qcam)
+{
+	parport_write_control(qcam->pport, 0xc);
+	parport_write_control(qcam->pport, 0x8);
+	mdelay(1);
+	parport_write_control(qcam->pport, 0xc);
+	mdelay(1);
+}
+
+/* Reset the QuickCam and program for brightness, contrast,
+ * white-balance, and resolution. */
+
+static void qc_setup(struct qcam *qcam)
+{
+	qc_reset(qcam);
+
+	/* Set the brightness. */
+	qcam_set(qcam, 11, qcam->brightness);
+
+	/* Set the height and width.  These refer to the actual
+	   CCD area *before* applying the selected decimation.  */
+	qcam_set(qcam, 17, qcam->ccd_height);
+	qcam_set(qcam, 19, qcam->ccd_width / 2);
+
+	/* Set top and left.  */
+	qcam_set(qcam, 0xd, qcam->top);
+	qcam_set(qcam, 0xf, qcam->left);
+
+	/* Set contrast and white balance.  */
+	qcam_set(qcam, 0x19, qcam->contrast);
+	qcam_set(qcam, 0x1f, qcam->whitebal);
+
+	/* Set the speed.  */
+	qcam_set(qcam, 45, 2);
+}
+
+/* Read some bytes from the camera and put them in the buffer.
+   nbytes should be a multiple of 3, because bidirectional mode gives
+   us three bytes at a time.  */
+
+static unsigned int qcam_read_bytes(struct qcam *qcam, unsigned char *buf, unsigned int nbytes)
+{
+	unsigned int bytes = 0;
+
+	qcam_set_ack(qcam, 0);
+	if (qcam->bidirectional) {
+		/* It's a bidirectional port */
+		while (bytes < nbytes) {
+			unsigned int lo1, hi1, lo2, hi2;
+			unsigned char r, g, b;
+
+			if (qcam_await_ready2(qcam, 1))
+				return bytes;
+			lo1 = parport_read_data(qcam->pport) >> 1;
+			hi1 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10;
+			qcam_set_ack(qcam, 1);
+			if (qcam_await_ready2(qcam, 0))
+				return bytes;
+			lo2 = parport_read_data(qcam->pport) >> 1;
+			hi2 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10;
+			qcam_set_ack(qcam, 0);
+			r = lo1 | ((hi1 & 1) << 7);
+			g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1);
+			b = lo2 | ((hi2 & 1) << 7);
+			if (force_rgb) {
+				buf[bytes++] = r;
+				buf[bytes++] = g;
+				buf[bytes++] = b;
+			} else {
+				buf[bytes++] = b;
+				buf[bytes++] = g;
+				buf[bytes++] = r;
+			}
+		}
+	} else {
+		/* It's a unidirectional port */
+		int i = 0, n = bytes;
+		unsigned char rgb[3];
+
+		while (bytes < nbytes) {
+			unsigned int hi, lo;
+
+			if (qcam_await_ready1(qcam, 1))
+				return bytes;
+			hi = (parport_read_status(qcam->pport) & 0xf0);
+			qcam_set_ack(qcam, 1);
+			if (qcam_await_ready1(qcam, 0))
+				return bytes;
+			lo = (parport_read_status(qcam->pport) & 0xf0);
+			qcam_set_ack(qcam, 0);
+			/* flip some bits */
+			rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;
+			if (i >= 2) {
+get_fragment:
+				if (force_rgb) {
+					buf[n++] = rgb[0];
+					buf[n++] = rgb[1];
+					buf[n++] = rgb[2];
+				} else {
+					buf[n++] = rgb[2];
+					buf[n++] = rgb[1];
+					buf[n++] = rgb[0];
+				}
+			}
+		}
+		if (i) {
+			i = 0;
+			goto get_fragment;
+		}
+	}
+	return bytes;
+}
+
+#define BUFSZ	150
+
+static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len)
+{
+	struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
+	unsigned lines, pixelsperline;
+	unsigned int is_bi_dir = qcam->bidirectional;
+	size_t wantlen, outptr = 0;
+	char tmpbuf[BUFSZ];
+
+	if (!access_ok(VERIFY_WRITE, buf, len))
+		return -EFAULT;
+
+	/* Wait for camera to become ready */
+	for (;;) {
+		int i = qcam_get(qcam, 41);
+
+		if (i == -1) {
+			qc_setup(qcam);
+			return -EIO;
+		}
+		if ((i & 0x80) == 0)
+			break;
+		schedule();
+	}
+
+	if (qcam_set(qcam, 7, (qcam->mode | (is_bi_dir ? 1 : 0)) + 1))
+		return -EIO;
+
+	lines = qcam->height;
+	pixelsperline = qcam->width;
+
+	if (is_bi_dir) {
+		/* Turn the port around */
+		parport_data_reverse(qcam->pport);
+		mdelay(3);
+		qcam_set_ack(qcam, 0);
+		if (qcam_await_ready1(qcam, 1)) {
+			qc_setup(qcam);
+			return -EIO;
+		}
+		qcam_set_ack(qcam, 1);
+		if (qcam_await_ready1(qcam, 0)) {
+			qc_setup(qcam);
+			return -EIO;
+		}
+	}
+
+	wantlen = lines * pixelsperline * 24 / 8;
+
+	while (wantlen) {
+		size_t t, s;
+
+		s = (wantlen > BUFSZ) ? BUFSZ : wantlen;
+		t = qcam_read_bytes(qcam, tmpbuf, s);
+		if (outptr < len) {
+			size_t sz = len - outptr;
+
+			if (sz > t)
+				sz = t;
+			if (__copy_to_user(buf + outptr, tmpbuf, sz))
+				break;
+			outptr += sz;
+		}
+		wantlen -= t;
+		if (t < s)
+			break;
+		cond_resched();
+	}
+
+	len = outptr;
+
+	if (wantlen) {
+		v4l2_err(v4l2_dev, "short read.\n");
+		if (is_bi_dir)
+			parport_data_forward(qcam->pport);
+		qc_setup(qcam);
+		return len;
+	}
+
+	if (is_bi_dir) {
+		int l;
+
+		do {
+			l = qcam_read_bytes(qcam, tmpbuf, 3);
+			cond_resched();
+		} while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
+		if (force_rgb) {
+			if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
+				v4l2_err(v4l2_dev, "bad EOF\n");
+		} else {
+			if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
+				v4l2_err(v4l2_dev, "bad EOF\n");
+		}
+		qcam_set_ack(qcam, 0);
+		if (qcam_await_ready1(qcam, 1)) {
+			v4l2_err(v4l2_dev, "no ack after EOF\n");
+			parport_data_forward(qcam->pport);
+			qc_setup(qcam);
+			return len;
+		}
+		parport_data_forward(qcam->pport);
+		mdelay(3);
+		qcam_set_ack(qcam, 1);
+		if (qcam_await_ready1(qcam, 0)) {
+			v4l2_err(v4l2_dev, "no ack to port turnaround\n");
+			qc_setup(qcam);
+			return len;
+		}
+	} else {
+		int l;
+
+		do {
+			l = qcam_read_bytes(qcam, tmpbuf, 1);
+			cond_resched();
+		} while (l && tmpbuf[0] == 0x7e);
+		l = qcam_read_bytes(qcam, tmpbuf + 1, 2);
+		if (force_rgb) {
+			if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
+				v4l2_err(v4l2_dev, "bad EOF\n");
+		} else {
+			if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
+				v4l2_err(v4l2_dev, "bad EOF\n");
+		}
+	}
+
+	qcam_write_data(qcam, 0);
+	return len;
+}
+
+/*
+ *	Video4linux interfacing
+ */
+
+static int qcam_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *vcap)
+{
+	struct qcam *qcam = video_drvdata(file);
+
+	strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
+	strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card));
+	strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
+	vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
+	return 0;
+}
+
+static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+	if (vin->index > 0)
+		return -EINVAL;
+	strlcpy(vin->name, "Camera", sizeof(vin->name));
+	vin->type = V4L2_INPUT_TYPE_CAMERA;
+	vin->audioset = 0;
+	vin->tuner = 0;
+	vin->std = 0;
+	vin->status = 0;
+	return 0;
+}
+
+static int qcam_g_input(struct file *file, void *fh, unsigned int *inp)
+{
+	*inp = 0;
+	return 0;
+}
+
+static int qcam_s_input(struct file *file, void *fh, unsigned int inp)
+{
+	return (inp > 0) ? -EINVAL : 0;
+}
+
+static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct qcam *qcam = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	pix->width = qcam->width;
+	pix->height = qcam->height;
+	pix->pixelformat = V4L2_PIX_FMT_RGB24;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = 3 * qcam->width;
+	pix->sizeimage = 3 * qcam->width * qcam->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SRGB;
+	return 0;
+}
+
+static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	if (pix->height < 60 || pix->width < 80) {
+		pix->height = 60;
+		pix->width = 80;
+	} else if (pix->height < 120 || pix->width < 160) {
+		pix->height = 120;
+		pix->width = 160;
+	} else {
+		pix->height = 240;
+		pix->width = 320;
+	}
+	pix->pixelformat = V4L2_PIX_FMT_RGB24;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = 3 * pix->width;
+	pix->sizeimage = 3 * pix->width * pix->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SRGB;
+	return 0;
+}
+
+static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct qcam *qcam = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+	int ret = qcam_try_fmt_vid_cap(file, fh, fmt);
+
+	if (ret)
+		return ret;
+	switch (pix->height) {
+	case 60:
+		qcam->mode = QC_DECIMATION_4;
+		break;
+	case 120:
+		qcam->mode = QC_DECIMATION_2;
+		break;
+	default:
+		qcam->mode = QC_DECIMATION_1;
+		break;
+	}
+
+	mutex_lock(&qcam->lock);
+	qcam->mode |= QC_MILLIONS;
+	qcam->height = pix->height;
+	qcam->width = pix->width;
+	parport_claim_or_block(qcam->pdev);
+	qc_setup(qcam);
+	parport_release(qcam->pdev);
+	mutex_unlock(&qcam->lock);
+	return 0;
+}
+
+static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
+{
+	static struct v4l2_fmtdesc formats[] = {
+		{ 0, 0, 0,
+		  "RGB 8:8:8", V4L2_PIX_FMT_RGB24,
+		  { 0, 0, 0, 0 }
+		},
+	};
+	enum v4l2_buf_type type = fmt->type;
+
+	if (fmt->index > 0)
+		return -EINVAL;
+
+	*fmt = formats[fmt->index];
+	fmt->type = type;
+	return 0;
+}
+
+static ssize_t qcam_read(struct file *file, char __user *buf,
+			 size_t count, loff_t *ppos)
+{
+	struct qcam *qcam = video_drvdata(file);
+	int len;
+
+	mutex_lock(&qcam->lock);
+	parport_claim_or_block(qcam->pdev);
+	/* Probably should have a semaphore against multiple users */
+	len = qc_capture(qcam, buf, count);
+	parport_release(qcam->pdev);
+	mutex_unlock(&qcam->lock);
+	return len;
+}
+
+static int qcam_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct qcam *qcam =
+		container_of(ctrl->handler, struct qcam, hdl);
+	int ret = 0;
+
+	mutex_lock(&qcam->lock);
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		qcam->brightness = ctrl->val;
+		break;
+	case V4L2_CID_CONTRAST:
+		qcam->contrast = ctrl->val;
+		break;
+	case V4L2_CID_GAMMA:
+		qcam->whitebal = ctrl->val;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	if (ret == 0) {
+		parport_claim_or_block(qcam->pdev);
+		qc_setup(qcam);
+		parport_release(qcam->pdev);
+	}
+	mutex_unlock(&qcam->lock);
+	return ret;
+}
+
+static const struct v4l2_file_operations qcam_fops = {
+	.owner		= THIS_MODULE,
+	.open		= v4l2_fh_open,
+	.release	= v4l2_fh_release,
+	.poll		= v4l2_ctrl_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.read		= qcam_read,
+};
+
+static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
+	.vidioc_querycap    		    = qcam_querycap,
+	.vidioc_g_input      		    = qcam_g_input,
+	.vidioc_s_input      		    = qcam_s_input,
+	.vidioc_enum_input   		    = qcam_enum_input,
+	.vidioc_enum_fmt_vid_cap	    = qcam_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap 		    = qcam_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap  		    = qcam_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap  	    = qcam_try_fmt_vid_cap,
+	.vidioc_log_status		    = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event		    = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event	    = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_ctrl_ops qcam_ctrl_ops = {
+	.s_ctrl = qcam_s_ctrl,
+};
+
+/* Initialize the QuickCam driver control structure. */
+
+static struct qcam *qcam_init(struct parport *port)
+{
+	struct qcam *qcam;
+	struct v4l2_device *v4l2_dev;
+
+	qcam = kzalloc(sizeof(*qcam), GFP_KERNEL);
+	if (qcam == NULL)
+		return NULL;
+
+	v4l2_dev = &qcam->v4l2_dev;
+	strlcpy(v4l2_dev->name, "c-qcam", sizeof(v4l2_dev->name));
+
+	if (v4l2_device_register(NULL, v4l2_dev) < 0) {
+		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+		kfree(qcam);
+		return NULL;
+	}
+
+	v4l2_ctrl_handler_init(&qcam->hdl, 3);
+	v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+			  V4L2_CID_BRIGHTNESS, 0, 255, 1, 240);
+	v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+			  V4L2_CID_CONTRAST, 0, 255, 1, 192);
+	v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+			  V4L2_CID_GAMMA, 0, 255, 1, 128);
+	if (qcam->hdl.error) {
+		v4l2_err(v4l2_dev, "couldn't register controls\n");
+		v4l2_ctrl_handler_free(&qcam->hdl);
+		kfree(qcam);
+		return NULL;
+	}
+
+	qcam->pport = port;
+	qcam->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
+					  NULL, 0, NULL);
+
+	qcam->bidirectional = (qcam->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0;
+
+	if (qcam->pdev == NULL) {
+		v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
+		v4l2_ctrl_handler_free(&qcam->hdl);
+		kfree(qcam);
+		return NULL;
+	}
+
+	strlcpy(qcam->vdev.name, "Colour QuickCam", sizeof(qcam->vdev.name));
+	qcam->vdev.v4l2_dev = v4l2_dev;
+	qcam->vdev.fops = &qcam_fops;
+	qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
+	qcam->vdev.release = video_device_release_empty;
+	qcam->vdev.ctrl_handler = &qcam->hdl;
+	set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags);
+	video_set_drvdata(&qcam->vdev, qcam);
+
+	mutex_init(&qcam->lock);
+	qcam->width = qcam->ccd_width = 320;
+	qcam->height = qcam->ccd_height = 240;
+	qcam->mode = QC_MILLIONS | QC_DECIMATION_1;
+	qcam->contrast = 192;
+	qcam->brightness = 240;
+	qcam->whitebal = 128;
+	qcam->top = 1;
+	qcam->left = 14;
+	return qcam;
+}
+
+static int init_cqcam(struct parport *port)
+{
+	struct qcam *qcam;
+	struct v4l2_device *v4l2_dev;
+
+	if (parport[0] != -1) {
+		/* The user gave specific instructions */
+		int i, found = 0;
+
+		for (i = 0; i < MAX_CAMS && parport[i] != -1; i++) {
+			if (parport[0] == port->number)
+				found = 1;
+		}
+		if (!found)
+			return -ENODEV;
+	}
+
+	if (num_cams == MAX_CAMS)
+		return -ENOSPC;
+
+	qcam = qcam_init(port);
+	if (qcam == NULL)
+		return -ENODEV;
+
+	v4l2_dev = &qcam->v4l2_dev;
+
+	parport_claim_or_block(qcam->pdev);
+
+	qc_reset(qcam);
+
+	if (probe && qc_detect(qcam) == 0) {
+		parport_release(qcam->pdev);
+		parport_unregister_device(qcam->pdev);
+		kfree(qcam);
+		return -ENODEV;
+	}
+
+	qc_setup(qcam);
+
+	parport_release(qcam->pdev);
+
+	if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
+		v4l2_err(v4l2_dev, "Unable to register Colour QuickCam on %s\n",
+		       qcam->pport->name);
+		parport_unregister_device(qcam->pdev);
+		kfree(qcam);
+		return -ENODEV;
+	}
+
+	v4l2_info(v4l2_dev, "%s: Colour QuickCam found on %s\n",
+	       video_device_node_name(&qcam->vdev), qcam->pport->name);
+
+	qcams[num_cams++] = qcam;
+
+	return 0;
+}
+
+static void close_cqcam(struct qcam *qcam)
+{
+	video_unregister_device(&qcam->vdev);
+	v4l2_ctrl_handler_free(&qcam->hdl);
+	parport_unregister_device(qcam->pdev);
+	kfree(qcam);
+}
+
+static void cq_attach(struct parport *port)
+{
+	init_cqcam(port);
+}
+
+static void cq_detach(struct parport *port)
+{
+	/* Write this some day. */
+}
+
+static struct parport_driver cqcam_driver = {
+	.name = "cqcam",
+	.attach = cq_attach,
+	.detach = cq_detach,
+};
+
+static int __init cqcam_init(void)
+{
+	printk(KERN_INFO BANNER "\n");
+
+	return parport_register_driver(&cqcam_driver);
+}
+
+static void __exit cqcam_cleanup(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < num_cams; i++)
+		close_cqcam(qcams[i]);
+
+	parport_unregister_driver(&cqcam_driver);
+}
+
+MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
+MODULE_DESCRIPTION(BANNER);
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.4");
+
+module_init(cqcam_init);
+module_exit(cqcam_cleanup);
diff --git a/drivers/media/parport/pms.c b/drivers/media/parport/pms.c
new file mode 100644
index 0000000..77f9c92
--- /dev/null
+++ b/drivers/media/parport/pms.c
@@ -0,0 +1,1152 @@
+/*
+ *	Media Vision Pro Movie Studio
+ *			or
+ *	"all you need is an I2C bus some RAM and a prayer"
+ *
+ *	This draws heavily on code
+ *
+ *	(c) Wolfgang Koehler,  wolf@first.gmd.de, Dec. 1994
+ *	Kiefernring 15
+ *	14478 Potsdam, Germany
+ *
+ *	Most of this code is directly derived from his userspace driver.
+ *	His driver works so send any reports to alan@lxorguk.ukuu.org.uk
+ *	unless the userspace driver also doesn't work for you...
+ *
+ *      Changes:
+ *	25-11-2009 	Hans Verkuil <hverkuil@xs4all.nl>
+ * 			- converted to version 2 of the V4L API.
+ *      08/07/2003      Daniele Bellucci <bellucda@tiscali.it>
+ *                      - pms_capture: report back -EFAULT
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/isa.h>
+#include <asm/io.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-device.h>
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.5");
+
+#define MOTOROLA	1
+#define PHILIPS2	2               /* SAA7191 */
+#define PHILIPS1	3
+#define MVVMEMORYWIDTH	0x40		/* 512 bytes */
+
+struct i2c_info {
+	u8 slave;
+	u8 sub;
+	u8 data;
+	u8 hits;
+};
+
+struct pms {
+	struct v4l2_device v4l2_dev;
+	struct video_device vdev;
+	struct v4l2_ctrl_handler hdl;
+	int height;
+	int width;
+	int depth;
+	int input;
+	struct mutex lock;
+	int i2c_count;
+	struct i2c_info i2cinfo[64];
+
+	int decoder;
+	int standard;	/* 0 - auto 1 - ntsc 2 - pal 3 - secam */
+	v4l2_std_id std;
+	int io;
+	int data;
+	void __iomem *mem;
+};
+
+/*
+ *	I/O ports and Shared Memory
+ */
+
+static int io_port = 0x250;
+module_param(io_port, int, 0);
+
+static int mem_base = 0xc8000;
+module_param(mem_base, int, 0);
+
+static int video_nr = -1;
+module_param(video_nr, int, 0);
+
+
+static inline void mvv_write(struct pms *dev, u8 index, u8 value)
+{
+	outw(index | (value << 8), dev->io);
+}
+
+static inline u8 mvv_read(struct pms *dev, u8 index)
+{
+	outb(index, dev->io);
+	return inb(dev->data);
+}
+
+static int pms_i2c_stat(struct pms *dev, u8 slave)
+{
+	int counter = 0;
+	int i;
+
+	outb(0x28, dev->io);
+
+	while ((inb(dev->data) & 0x01) == 0)
+		if (counter++ == 256)
+			break;
+
+	while ((inb(dev->data) & 0x01) != 0)
+		if (counter++ == 256)
+			break;
+
+	outb(slave, dev->io);
+
+	counter = 0;
+	while ((inb(dev->data) & 0x01) == 0)
+		if (counter++ == 256)
+			break;
+
+	while ((inb(dev->data) & 0x01) != 0)
+		if (counter++ == 256)
+			break;
+
+	for (i = 0; i < 12; i++) {
+		char st = inb(dev->data);
+
+		if ((st & 2) != 0)
+			return -1;
+		if ((st & 1) == 0)
+			break;
+	}
+	outb(0x29, dev->io);
+	return inb(dev->data);
+}
+
+static int pms_i2c_write(struct pms *dev, u16 slave, u16 sub, u16 data)
+{
+	int skip = 0;
+	int count;
+	int i;
+
+	for (i = 0; i < dev->i2c_count; i++) {
+		if ((dev->i2cinfo[i].slave == slave) &&
+		    (dev->i2cinfo[i].sub == sub)) {
+			if (dev->i2cinfo[i].data == data)
+				skip = 1;
+			dev->i2cinfo[i].data = data;
+			i = dev->i2c_count + 1;
+		}
+	}
+
+	if (i == dev->i2c_count && dev->i2c_count < 64) {
+		dev->i2cinfo[dev->i2c_count].slave = slave;
+		dev->i2cinfo[dev->i2c_count].sub = sub;
+		dev->i2cinfo[dev->i2c_count].data = data;
+		dev->i2c_count++;
+	}
+
+	if (skip)
+		return 0;
+
+	mvv_write(dev, 0x29, sub);
+	mvv_write(dev, 0x2A, data);
+	mvv_write(dev, 0x28, slave);
+
+	outb(0x28, dev->io);
+
+	count = 0;
+	while ((inb(dev->data) & 1) == 0)
+		if (count > 255)
+			break;
+	while ((inb(dev->data) & 1) != 0)
+		if (count > 255)
+			break;
+
+	count = inb(dev->data);
+
+	if (count & 2)
+		return -1;
+	return count;
+}
+
+static int pms_i2c_read(struct pms *dev, int slave, int sub)
+{
+	int i;
+
+	for (i = 0; i < dev->i2c_count; i++) {
+		if (dev->i2cinfo[i].slave == slave && dev->i2cinfo[i].sub == sub)
+			return dev->i2cinfo[i].data;
+	}
+	return 0;
+}
+
+
+static void pms_i2c_andor(struct pms *dev, int slave, int sub, int and, int or)
+{
+	u8 tmp;
+
+	tmp = pms_i2c_read(dev, slave, sub);
+	tmp = (tmp & and) | or;
+	pms_i2c_write(dev, slave, sub, tmp);
+}
+
+/*
+ *	Control functions
+ */
+
+
+static void pms_videosource(struct pms *dev, short source)
+{
+	switch (dev->decoder) {
+	case MOTOROLA:
+		break;
+	case PHILIPS2:
+		pms_i2c_andor(dev, 0x8a, 0x06, 0x7f, source ? 0x80 : 0);
+		break;
+	case PHILIPS1:
+		break;
+	}
+	mvv_write(dev, 0x2E, 0x31);
+	/* Was: mvv_write(dev, 0x2E, source ? 0x31 : 0x30);
+	   But could not make this work correctly. Only Composite input
+	   worked for me. */
+}
+
+static void pms_hue(struct pms *dev, short hue)
+{
+	switch (dev->decoder) {
+	case MOTOROLA:
+		pms_i2c_write(dev, 0x8a, 0x00, hue);
+		break;
+	case PHILIPS2:
+		pms_i2c_write(dev, 0x8a, 0x07, hue);
+		break;
+	case PHILIPS1:
+		pms_i2c_write(dev, 0x42, 0x07, hue);
+		break;
+	}
+}
+
+static void pms_saturation(struct pms *dev, short sat)
+{
+	switch (dev->decoder) {
+	case MOTOROLA:
+		pms_i2c_write(dev, 0x8a, 0x00, sat);
+		break;
+	case PHILIPS1:
+		pms_i2c_write(dev, 0x42, 0x12, sat);
+		break;
+	}
+}
+
+
+static void pms_contrast(struct pms *dev, short contrast)
+{
+	switch (dev->decoder) {
+	case MOTOROLA:
+		pms_i2c_write(dev, 0x8a, 0x00, contrast);
+		break;
+	case PHILIPS1:
+		pms_i2c_write(dev, 0x42, 0x13, contrast);
+		break;
+	}
+}
+
+static void pms_brightness(struct pms *dev, short brightness)
+{
+	switch (dev->decoder) {
+	case MOTOROLA:
+		pms_i2c_write(dev, 0x8a, 0x00, brightness);
+		pms_i2c_write(dev, 0x8a, 0x00, brightness);
+		pms_i2c_write(dev, 0x8a, 0x00, brightness);
+		break;
+	case PHILIPS1:
+		pms_i2c_write(dev, 0x42, 0x19, brightness);
+		break;
+	}
+}
+
+
+static void pms_format(struct pms *dev, short format)
+{
+	int target;
+
+	dev->standard = format;
+
+	if (dev->decoder == PHILIPS1)
+		target = 0x42;
+	else if (dev->decoder == PHILIPS2)
+		target = 0x8a;
+	else
+		return;
+
+	switch (format) {
+	case 0:	/* Auto */
+		pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00);
+		pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x80);
+		break;
+	case 1: /* NTSC */
+		pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00);
+		pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x40);
+		break;
+	case 2: /* PAL */
+		pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00);
+		pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x00);
+		break;
+	case 3:	/* SECAM */
+		pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x01);
+		pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x00);
+		break;
+	}
+}
+
+#ifdef FOR_FUTURE_EXPANSION
+
+/*
+ *	These features of the PMS card are not currently exposes. They
+ *	could become a private v4l ioctl for PMSCONFIG or somesuch if
+ *	people need it. We also don't yet use the PMS interrupt.
+ */
+
+static void pms_hstart(struct pms *dev, short start)
+{
+	switch (dev->decoder) {
+	case PHILIPS1:
+		pms_i2c_write(dev, 0x8a, 0x05, start);
+		pms_i2c_write(dev, 0x8a, 0x18, start);
+		break;
+	case PHILIPS2:
+		pms_i2c_write(dev, 0x42, 0x05, start);
+		pms_i2c_write(dev, 0x42, 0x18, start);
+		break;
+	}
+}
+
+/*
+ *	Bandpass filters
+ */
+
+static void pms_bandpass(struct pms *dev, short pass)
+{
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x06, 0xcf, (pass & 0x03) << 4);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x06, 0xcf, (pass & 0x03) << 4);
+}
+
+static void pms_antisnow(struct pms *dev, short snow)
+{
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x06, 0xf3, (snow & 0x03) << 2);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x06, 0xf3, (snow & 0x03) << 2);
+}
+
+static void pms_sharpness(struct pms *dev, short sharp)
+{
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x06, 0xfc, sharp & 0x03);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x06, 0xfc, sharp & 0x03);
+}
+
+static void pms_chromaagc(struct pms *dev, short agc)
+{
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x0c, 0x9f, (agc & 0x03) << 5);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x0c, 0x9f, (agc & 0x03) << 5);
+}
+
+static void pms_vertnoise(struct pms *dev, short noise)
+{
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x10, 0xfc, noise & 3);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x10, 0xfc, noise & 3);
+}
+
+static void pms_forcecolour(struct pms *dev, short colour)
+{
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x0c, 0x7f, (colour & 1) << 7);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x0c, 0x7, (colour & 1) << 7);
+}
+
+static void pms_antigamma(struct pms *dev, short gamma)
+{
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0xb8, 0x00, 0x7f, (gamma & 1) << 7);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x20, 0x7, (gamma & 1) << 7);
+}
+
+static void pms_prefilter(struct pms *dev, short filter)
+{
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x06, 0xbf, (filter & 1) << 6);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x06, 0xbf, (filter & 1) << 6);
+}
+
+static void pms_hfilter(struct pms *dev, short filter)
+{
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0xb8, 0x04, 0x1f, (filter & 7) << 5);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x24, 0x1f, (filter & 7) << 5);
+}
+
+static void pms_vfilter(struct pms *dev, short filter)
+{
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0xb8, 0x08, 0x9f, (filter & 3) << 5);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x28, 0x9f, (filter & 3) << 5);
+}
+
+static void pms_killcolour(struct pms *dev, short colour)
+{
+	if (dev->decoder == PHILIPS2) {
+		pms_i2c_andor(dev, 0x8a, 0x08, 0x07, (colour & 0x1f) << 3);
+		pms_i2c_andor(dev, 0x8a, 0x09, 0x07, (colour & 0x1f) << 3);
+	} else if (dev->decoder == PHILIPS1) {
+		pms_i2c_andor(dev, 0x42, 0x08, 0x07, (colour & 0x1f) << 3);
+		pms_i2c_andor(dev, 0x42, 0x09, 0x07, (colour & 0x1f) << 3);
+	}
+}
+
+static void pms_chromagain(struct pms *dev, short chroma)
+{
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_write(dev, 0x8a, 0x11, chroma);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_write(dev, 0x42, 0x11, chroma);
+}
+
+
+static void pms_spacialcompl(struct pms *dev, short data)
+{
+	mvv_write(dev, 0x3b, data);
+}
+
+static void pms_spacialcomph(struct pms *dev, short data)
+{
+	mvv_write(dev, 0x3a, data);
+}
+
+static void pms_vstart(struct pms *dev, short start)
+{
+	mvv_write(dev, 0x16, start);
+	mvv_write(dev, 0x17, (start >> 8) & 0x01);
+}
+
+#endif
+
+static void pms_secamcross(struct pms *dev, short cross)
+{
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x0f, 0xdf, (cross & 1) << 5);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x0f, 0xdf, (cross & 1) << 5);
+}
+
+
+static void pms_swsense(struct pms *dev, short sense)
+{
+	if (dev->decoder == PHILIPS2) {
+		pms_i2c_write(dev, 0x8a, 0x0a, sense);
+		pms_i2c_write(dev, 0x8a, 0x0b, sense);
+	} else if (dev->decoder == PHILIPS1) {
+		pms_i2c_write(dev, 0x42, 0x0a, sense);
+		pms_i2c_write(dev, 0x42, 0x0b, sense);
+	}
+}
+
+
+static void pms_framerate(struct pms *dev, short frr)
+{
+	int fps = (dev->std & V4L2_STD_525_60) ? 30 : 25;
+
+	if (frr == 0)
+		return;
+	fps = fps/frr;
+	mvv_write(dev, 0x14, 0x80 | fps);
+	mvv_write(dev, 0x15, 1);
+}
+
+static void pms_vert(struct pms *dev, u8 deciden, u8 decinum)
+{
+	mvv_write(dev, 0x1c, deciden);	/* Denominator */
+	mvv_write(dev, 0x1d, decinum);	/* Numerator */
+}
+
+/*
+ *	Turn 16bit ratios into best small ratio the chipset can grok
+ */
+
+static void pms_vertdeci(struct pms *dev, unsigned short decinum, unsigned short deciden)
+{
+	/* Knock it down by / 5 once */
+	if (decinum % 5 == 0) {
+		deciden /= 5;
+		decinum /= 5;
+	}
+	/*
+	 *	3's
+	 */
+	while (decinum % 3 == 0 && deciden % 3 == 0) {
+		deciden /= 3;
+		decinum /= 3;
+	}
+	/*
+	 *	2's
+	 */
+	while (decinum % 2 == 0 && deciden % 2 == 0) {
+		decinum /= 2;
+		deciden /= 2;
+	}
+	/*
+	 *	Fudgyify
+	 */
+	while (deciden > 32) {
+		deciden /= 2;
+		decinum = (decinum + 1) / 2;
+	}
+	if (deciden == 32)
+		deciden--;
+	pms_vert(dev, deciden, decinum);
+}
+
+static void pms_horzdeci(struct pms *dev, short decinum, short deciden)
+{
+	if (decinum <= 512) {
+		if (decinum % 5 == 0) {
+			decinum /= 5;
+			deciden /= 5;
+		}
+	} else {
+		decinum = 512;
+		deciden = 640;	/* 768 would be ideal */
+	}
+
+	while (((decinum | deciden) & 1) == 0) {
+		decinum >>= 1;
+		deciden >>= 1;
+	}
+	while (deciden > 32) {
+		deciden >>= 1;
+		decinum = (decinum + 1) >> 1;
+	}
+	if (deciden == 32)
+		deciden--;
+
+	mvv_write(dev, 0x24, 0x80 | deciden);
+	mvv_write(dev, 0x25, decinum);
+}
+
+static void pms_resolution(struct pms *dev, short width, short height)
+{
+	int fg_height;
+
+	fg_height = height;
+	if (fg_height > 280)
+		fg_height = 280;
+
+	mvv_write(dev, 0x18, fg_height);
+	mvv_write(dev, 0x19, fg_height >> 8);
+
+	if (dev->std & V4L2_STD_525_60) {
+		mvv_write(dev, 0x1a, 0xfc);
+		mvv_write(dev, 0x1b, 0x00);
+		if (height > fg_height)
+			pms_vertdeci(dev, 240, 240);
+		else
+			pms_vertdeci(dev, fg_height, 240);
+	} else {
+		mvv_write(dev, 0x1a, 0x1a);
+		mvv_write(dev, 0x1b, 0x01);
+		if (fg_height > 256)
+			pms_vertdeci(dev, 270, 270);
+		else
+			pms_vertdeci(dev, fg_height, 270);
+	}
+	mvv_write(dev, 0x12, 0);
+	mvv_write(dev, 0x13, MVVMEMORYWIDTH);
+	mvv_write(dev, 0x42, 0x00);
+	mvv_write(dev, 0x43, 0x00);
+	mvv_write(dev, 0x44, MVVMEMORYWIDTH);
+
+	mvv_write(dev, 0x22, width + 8);
+	mvv_write(dev, 0x23, (width + 8) >> 8);
+
+	if (dev->std & V4L2_STD_525_60)
+		pms_horzdeci(dev, width, 640);
+	else
+		pms_horzdeci(dev, width + 8, 768);
+
+	mvv_write(dev, 0x30, mvv_read(dev, 0x30) & 0xfe);
+	mvv_write(dev, 0x08, mvv_read(dev, 0x08) | 0x01);
+	mvv_write(dev, 0x01, mvv_read(dev, 0x01) & 0xfd);
+	mvv_write(dev, 0x32, 0x00);
+	mvv_write(dev, 0x33, MVVMEMORYWIDTH);
+}
+
+
+/*
+ *	Set Input
+ */
+
+static void pms_vcrinput(struct pms *dev, short input)
+{
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x0d, 0x7f, (input & 1) << 7);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x0d, 0x7f, (input & 1) << 7);
+}
+
+
+static int pms_capture(struct pms *dev, char __user *buf, int rgb555, int count)
+{
+	int y;
+	int dw = 2 * dev->width;
+	char tmp[dw + 32]; /* using a temp buffer is faster than direct  */
+	int cnt = 0;
+	int len = 0;
+	unsigned char r8 = 0x5;  /* value for reg8  */
+
+	if (rgb555)
+		r8 |= 0x20; /* else use untranslated rgb = 565 */
+	mvv_write(dev, 0x08, r8); /* capture rgb555/565, init DRAM, PC enable */
+
+/*	printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */
+
+	for (y = 0; y < dev->height; y++) {
+		writeb(0, dev->mem);  /* synchronisiert neue Zeile */
+
+		/*
+		 *	This is in truth a fifo, be very careful as if you
+		 *	forgot this odd things will occur 8)
+		 */
+
+		memcpy_fromio(tmp, dev->mem, dw + 32); /* discard 16 word   */
+		cnt -= dev->height;
+		while (cnt <= 0) {
+			/*
+			 *	Don't copy too far
+			 */
+			int dt = dw;
+			if (dt + len > count)
+				dt = count - len;
+			cnt += dev->height;
+			if (copy_to_user(buf, tmp + 32, dt))
+				return len ? len : -EFAULT;
+			buf += dt;
+			len += dt;
+		}
+	}
+	return len;
+}
+
+
+/*
+ *	Video4linux interfacing
+ */
+
+static int pms_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *vcap)
+{
+	struct pms *dev = video_drvdata(file);
+
+	strlcpy(vcap->driver, dev->v4l2_dev.name, sizeof(vcap->driver));
+	strlcpy(vcap->card, "Mediavision PMS", sizeof(vcap->card));
+	snprintf(vcap->bus_info, sizeof(vcap->bus_info),
+			"ISA:%s", dev->v4l2_dev.name);
+	vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
+	return 0;
+}
+
+static int pms_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+	static const char *inputs[4] = {
+		"Composite",
+		"S-Video",
+		"Composite (VCR)",
+		"S-Video (VCR)"
+	};
+
+	if (vin->index > 3)
+		return -EINVAL;
+	strlcpy(vin->name, inputs[vin->index], sizeof(vin->name));
+	vin->type = V4L2_INPUT_TYPE_CAMERA;
+	vin->audioset = 0;
+	vin->tuner = 0;
+	vin->std = V4L2_STD_ALL;
+	vin->status = 0;
+	return 0;
+}
+
+static int pms_g_input(struct file *file, void *fh, unsigned int *inp)
+{
+	struct pms *dev = video_drvdata(file);
+
+	*inp = dev->input;
+	return 0;
+}
+
+static int pms_s_input(struct file *file, void *fh, unsigned int inp)
+{
+	struct pms *dev = video_drvdata(file);
+
+	if (inp > 3)
+		return -EINVAL;
+
+	dev->input = inp;
+	pms_videosource(dev, inp & 1);
+	pms_vcrinput(dev, inp >> 1);
+	return 0;
+}
+
+static int pms_g_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+	struct pms *dev = video_drvdata(file);
+
+	*std = dev->std;
+	return 0;
+}
+
+static int pms_s_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+	struct pms *dev = video_drvdata(file);
+	int ret = 0;
+
+	dev->std = *std;
+	if (dev->std & V4L2_STD_NTSC) {
+		pms_framerate(dev, 30);
+		pms_secamcross(dev, 0);
+		pms_format(dev, 1);
+	} else if (dev->std & V4L2_STD_PAL) {
+		pms_framerate(dev, 25);
+		pms_secamcross(dev, 0);
+		pms_format(dev, 2);
+	} else if (dev->std & V4L2_STD_SECAM) {
+		pms_framerate(dev, 25);
+		pms_secamcross(dev, 1);
+		pms_format(dev, 2);
+	} else {
+		ret = -EINVAL;
+	}
+	/*
+	switch (v->mode) {
+	case VIDEO_MODE_AUTO:
+		pms_framerate(dev, 25);
+		pms_secamcross(dev, 0);
+		pms_format(dev, 0);
+		break;
+	}*/
+	return ret;
+}
+
+static int pms_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct pms *dev = container_of(ctrl->handler, struct pms, hdl);
+	int ret = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		pms_brightness(dev, ctrl->val);
+		break;
+	case V4L2_CID_CONTRAST:
+		pms_contrast(dev, ctrl->val);
+		break;
+	case V4L2_CID_SATURATION:
+		pms_saturation(dev, ctrl->val);
+		break;
+	case V4L2_CID_HUE:
+		pms_hue(dev, ctrl->val);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int pms_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct pms *dev = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	pix->width = dev->width;
+	pix->height = dev->height;
+	pix->pixelformat = dev->width == 15 ?
+			    V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB565;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = 2 * dev->width;
+	pix->sizeimage = 2 * dev->width * dev->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SRGB;
+	return 0;
+}
+
+static int pms_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	if (pix->height < 16 || pix->height > 480)
+		return -EINVAL;
+	if (pix->width < 16 || pix->width > 640)
+		return -EINVAL;
+	if (pix->pixelformat != V4L2_PIX_FMT_RGB555 &&
+	    pix->pixelformat != V4L2_PIX_FMT_RGB565)
+		return -EINVAL;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = 2 * pix->width;
+	pix->sizeimage = 2 * pix->width * pix->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SRGB;
+	return 0;
+}
+
+static int pms_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct pms *dev = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+	int ret = pms_try_fmt_vid_cap(file, fh, fmt);
+
+	if (ret)
+		return ret;
+	dev->width = pix->width;
+	dev->height = pix->height;
+	dev->depth = (pix->pixelformat == V4L2_PIX_FMT_RGB555) ? 15 : 16;
+	pms_resolution(dev, dev->width, dev->height);
+	/* Ok we figured out what to use from our wide choice */
+	return 0;
+}
+
+static int pms_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
+{
+	static struct v4l2_fmtdesc formats[] = {
+		{ 0, 0, 0,
+		  "RGB 5:5:5", V4L2_PIX_FMT_RGB555,
+		  { 0, 0, 0, 0 }
+		},
+		{ 1, 0, 0,
+		  "RGB 5:6:5", V4L2_PIX_FMT_RGB565,
+		  { 0, 0, 0, 0 }
+		},
+	};
+	enum v4l2_buf_type type = fmt->type;
+
+	if (fmt->index > 1)
+		return -EINVAL;
+
+	*fmt = formats[fmt->index];
+	fmt->type = type;
+	return 0;
+}
+
+static ssize_t pms_read(struct file *file, char __user *buf,
+		    size_t count, loff_t *ppos)
+{
+	struct pms *dev = video_drvdata(file);
+	int len;
+
+	len = pms_capture(dev, buf, (dev->depth == 15), count);
+	return len;
+}
+
+static unsigned int pms_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct v4l2_fh *fh = file->private_data;
+	unsigned int res = POLLIN | POLLRDNORM;
+
+	if (v4l2_event_pending(fh))
+		res |= POLLPRI;
+	poll_wait(file, &fh->wait, wait);
+	return res;
+}
+
+static const struct v4l2_file_operations pms_fops = {
+	.owner		= THIS_MODULE,
+	.open           = v4l2_fh_open,
+	.release        = v4l2_fh_release,
+	.poll           = pms_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.read           = pms_read,
+};
+
+static const struct v4l2_ioctl_ops pms_ioctl_ops = {
+	.vidioc_querycap	    = pms_querycap,
+	.vidioc_g_input		    = pms_g_input,
+	.vidioc_s_input		    = pms_s_input,
+	.vidioc_enum_input	    = pms_enum_input,
+	.vidioc_g_std		    = pms_g_std,
+	.vidioc_s_std		    = pms_s_std,
+	.vidioc_enum_fmt_vid_cap    = pms_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	    = pms_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	    = pms_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap     = pms_try_fmt_vid_cap,
+	.vidioc_subscribe_event     = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event   = v4l2_event_unsubscribe,
+};
+
+/*
+ *	Probe for and initialise the Mediavision PMS
+ */
+
+static int init_mediavision(struct pms *dev)
+{
+	int idec, decst;
+	int i;
+	static const unsigned char i2c_defs[] = {
+		0x4c, 0x30, 0x00, 0xe8,
+		0xb6, 0xe2, 0x00, 0x00,
+		0xff, 0xff, 0x00, 0x00,
+		0x00, 0x00, 0x78, 0x98,
+		0x00, 0x00, 0x00, 0x00,
+		0x34, 0x0a, 0xf4, 0xce,
+		0xe4
+	};
+
+	dev->mem = ioremap(mem_base, 0x800);
+	if (!dev->mem)
+		return -ENOMEM;
+
+	if (!request_region(0x9a01, 1, "Mediavision PMS config")) {
+		printk(KERN_WARNING "mediavision: unable to detect: 0x9a01 in use.\n");
+		iounmap(dev->mem);
+		return -EBUSY;
+	}
+	if (!request_region(dev->io, 3, "Mediavision PMS")) {
+		printk(KERN_WARNING "mediavision: I/O port %d in use.\n", dev->io);
+		release_region(0x9a01, 1);
+		iounmap(dev->mem);
+		return -EBUSY;
+	}
+	outb(0xb8, 0x9a01);		/* Unlock */
+	outb(dev->io >> 4, 0x9a01);	/* Set IO port */
+
+
+	decst = pms_i2c_stat(dev, 0x43);
+
+	if (decst != -1)
+		idec = 2;
+	else if (pms_i2c_stat(dev, 0xb9) != -1)
+		idec = 3;
+	else if (pms_i2c_stat(dev, 0x8b) != -1)
+		idec = 1;
+	else
+		idec = 0;
+
+	printk(KERN_INFO "PMS type is %d\n", idec);
+	if (idec == 0) {
+		release_region(dev->io, 3);
+		release_region(0x9a01, 1);
+		iounmap(dev->mem);
+		return -ENODEV;
+	}
+
+	/*
+	 *	Ok we have a PMS of some sort
+	 */
+
+	mvv_write(dev, 0x04, mem_base >> 12);	/* Set the memory area */
+
+	/* Ok now load the defaults */
+
+	for (i = 0; i < 0x19; i++) {
+		if (i2c_defs[i] == 0xff)
+			pms_i2c_andor(dev, 0x8a, i, 0x07, 0x00);
+		else
+			pms_i2c_write(dev, 0x8a, i, i2c_defs[i]);
+	}
+
+	pms_i2c_write(dev, 0xb8, 0x00, 0x12);
+	pms_i2c_write(dev, 0xb8, 0x04, 0x00);
+	pms_i2c_write(dev, 0xb8, 0x07, 0x00);
+	pms_i2c_write(dev, 0xb8, 0x08, 0x00);
+	pms_i2c_write(dev, 0xb8, 0x09, 0xff);
+	pms_i2c_write(dev, 0xb8, 0x0a, 0x00);
+	pms_i2c_write(dev, 0xb8, 0x0b, 0x10);
+	pms_i2c_write(dev, 0xb8, 0x10, 0x03);
+
+	mvv_write(dev, 0x01, 0x00);
+	mvv_write(dev, 0x05, 0xa0);
+	mvv_write(dev, 0x08, 0x25);
+	mvv_write(dev, 0x09, 0x00);
+	mvv_write(dev, 0x0a, 0x20 | MVVMEMORYWIDTH);
+
+	mvv_write(dev, 0x10, 0x02);
+	mvv_write(dev, 0x1e, 0x0c);
+	mvv_write(dev, 0x1f, 0x03);
+	mvv_write(dev, 0x26, 0x06);
+
+	mvv_write(dev, 0x2b, 0x00);
+	mvv_write(dev, 0x2c, 0x20);
+	mvv_write(dev, 0x2d, 0x00);
+	mvv_write(dev, 0x2f, 0x70);
+	mvv_write(dev, 0x32, 0x00);
+	mvv_write(dev, 0x33, MVVMEMORYWIDTH);
+	mvv_write(dev, 0x34, 0x00);
+	mvv_write(dev, 0x35, 0x00);
+	mvv_write(dev, 0x3a, 0x80);
+	mvv_write(dev, 0x3b, 0x10);
+	mvv_write(dev, 0x20, 0x00);
+	mvv_write(dev, 0x21, 0x00);
+	mvv_write(dev, 0x30, 0x22);
+	return 0;
+}
+
+/*
+ *	Initialization and module stuff
+ */
+
+#ifndef MODULE
+static int enable;
+module_param(enable, int, 0);
+#endif
+
+static const struct v4l2_ctrl_ops pms_ctrl_ops = {
+	.s_ctrl = pms_s_ctrl,
+};
+
+static int pms_probe(struct device *pdev, unsigned int card)
+{
+	struct pms *dev;
+	struct v4l2_device *v4l2_dev;
+	struct v4l2_ctrl_handler *hdl;
+	int res;
+
+#ifndef MODULE
+	if (!enable) {
+		pr_err("PMS: not enabled, use pms.enable=1 to probe\n");
+		return -ENODEV;
+	}
+#endif
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL)
+		return -ENOMEM;
+
+	dev->decoder = PHILIPS2;
+	dev->io = io_port;
+	dev->data = io_port + 1;
+	v4l2_dev = &dev->v4l2_dev;
+	hdl = &dev->hdl;
+
+	res = v4l2_device_register(pdev, v4l2_dev);
+	if (res < 0) {
+		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+		goto free_dev;
+	}
+	v4l2_info(v4l2_dev, "Mediavision Pro Movie Studio driver 0.05\n");
+
+	res = init_mediavision(dev);
+	if (res) {
+		v4l2_err(v4l2_dev, "Board not found.\n");
+		goto free_io;
+	}
+
+	v4l2_ctrl_handler_init(hdl, 4);
+	v4l2_ctrl_new_std(hdl, &pms_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 255, 1, 139);
+	v4l2_ctrl_new_std(hdl, &pms_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 255, 1, 70);
+	v4l2_ctrl_new_std(hdl, &pms_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 255, 1, 64);
+	v4l2_ctrl_new_std(hdl, &pms_ctrl_ops,
+			V4L2_CID_HUE, 0, 255, 1, 0);
+	if (hdl->error) {
+		res = hdl->error;
+		goto free_hdl;
+	}
+
+	mutex_init(&dev->lock);
+	strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
+	dev->vdev.v4l2_dev = v4l2_dev;
+	dev->vdev.ctrl_handler = hdl;
+	dev->vdev.fops = &pms_fops;
+	dev->vdev.ioctl_ops = &pms_ioctl_ops;
+	dev->vdev.release = video_device_release_empty;
+	dev->vdev.lock = &dev->lock;
+	dev->vdev.tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
+	set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags);
+	video_set_drvdata(&dev->vdev, dev);
+	dev->std = V4L2_STD_NTSC_M;
+	dev->height = 240;
+	dev->width = 320;
+	dev->depth = 16;
+	pms_swsense(dev, 75);
+	pms_resolution(dev, 320, 240);
+	pms_videosource(dev, 0);
+	pms_vcrinput(dev, 0);
+	v4l2_ctrl_handler_setup(hdl);
+	res = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr);
+	if (res >= 0)
+		return 0;
+
+free_hdl:
+	v4l2_ctrl_handler_free(hdl);
+	v4l2_device_unregister(&dev->v4l2_dev);
+free_io:
+	release_region(dev->io, 3);
+	release_region(0x9a01, 1);
+	iounmap(dev->mem);
+free_dev:
+	kfree(dev);
+	return res;
+}
+
+static int pms_remove(struct device *pdev, unsigned int card)
+{
+	struct pms *dev = dev_get_drvdata(pdev);
+
+	video_unregister_device(&dev->vdev);
+	v4l2_ctrl_handler_free(&dev->hdl);
+	release_region(dev->io, 3);
+	release_region(0x9a01, 1);
+	iounmap(dev->mem);
+	return 0;
+}
+
+static struct isa_driver pms_driver = {
+	.probe		= pms_probe,
+	.remove		= pms_remove,
+	.driver		= {
+		.name	= "pms",
+	},
+};
+
+static int __init pms_init(void)
+{
+	return isa_register_driver(&pms_driver, 1);
+}
+
+static void __exit pms_exit(void)
+{
+	isa_unregister_driver(&pms_driver);
+}
+
+module_init(pms_init);
+module_exit(pms_exit);
diff --git a/drivers/media/parport/w9966.c b/drivers/media/parport/w9966.c
new file mode 100644
index 0000000..db2a600
--- /dev/null
+++ b/drivers/media/parport/w9966.c
@@ -0,0 +1,981 @@
+/*
+	Winbond w9966cf Webcam parport driver.
+
+	Version 0.33
+
+	Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.se>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+/*
+	Supported devices:
+	*Lifeview FlyCam Supra (using the Philips saa7111a chip)
+
+	Does any other model using the w9966 interface chip exist ?
+
+	Todo:
+
+	*Add a working EPP mode, since DMA ECP read isn't implemented
+	in the parport drivers. (That's why it's so sloow)
+
+	*Add support for other ccd-control chips than the saa7111
+	please send me feedback on what kind of chips you have.
+
+	*Add proper probing. I don't know what's wrong with the IEEE1284
+	parport drivers but (IEEE1284_MODE_NIBBLE|IEEE1284_DEVICE_ID)
+	and nibble read seems to be broken for some peripherals.
+
+	*Add probing for onboard SRAM, port directions etc. (if possible)
+
+	*Add support for the hardware compressed modes (maybe using v4l2)
+
+	*Fix better support for the capture window (no skewed images, v4l
+	interface to capt. window)
+
+	*Probably some bugs that I don't know of
+
+	Please support me by sending feedback!
+
+	Changes:
+
+	Alan Cox:	Removed RGB mode for kernel merge, added THIS_MODULE
+			and owner support for newer module locks
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <linux/parport.h>
+
+/*#define DEBUG*/				/* Undef me for production */
+
+#ifdef DEBUG
+#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __func__ , ##a)
+#else
+#define DPRINTF(x...)
+#endif
+
+/*
+ *	Defines, simple typedefs etc.
+ */
+
+#define W9966_DRIVERNAME	"W9966CF Webcam"
+#define W9966_MAXCAMS		4	/* Maximum number of cameras */
+#define W9966_RBUFFER		2048	/* Read buffer (must be an even number) */
+#define W9966_SRAMSIZE		131072	/* 128kb */
+#define W9966_SRAMID		0x02	/* check w9966cf.pdf */
+
+/* Empirically determined window limits */
+#define W9966_WND_MIN_X		16
+#define W9966_WND_MIN_Y		14
+#define W9966_WND_MAX_X		705
+#define W9966_WND_MAX_Y		253
+#define W9966_WND_MAX_W		(W9966_WND_MAX_X - W9966_WND_MIN_X)
+#define W9966_WND_MAX_H		(W9966_WND_MAX_Y - W9966_WND_MIN_Y)
+
+/* Keep track of our current state */
+#define W9966_STATE_PDEV	0x01
+#define W9966_STATE_CLAIMED	0x02
+#define W9966_STATE_VDEV	0x04
+
+#define W9966_I2C_W_ID		0x48
+#define W9966_I2C_R_ID		0x49
+#define W9966_I2C_R_DATA	0x08
+#define W9966_I2C_R_CLOCK	0x04
+#define W9966_I2C_W_DATA	0x02
+#define W9966_I2C_W_CLOCK	0x01
+
+struct w9966 {
+	struct v4l2_device v4l2_dev;
+	struct v4l2_ctrl_handler hdl;
+	unsigned char dev_state;
+	unsigned char i2c_state;
+	unsigned short ppmode;
+	struct parport *pport;
+	struct pardevice *pdev;
+	struct video_device vdev;
+	unsigned short width;
+	unsigned short height;
+	unsigned char brightness;
+	signed char contrast;
+	signed char color;
+	signed char hue;
+	struct mutex lock;
+};
+
+/*
+ *	Module specific properties
+ */
+
+MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>");
+MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.33.1");
+
+#ifdef MODULE
+static char *pardev[] = {[0 ... W9966_MAXCAMS] = ""};
+#else
+static char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
+#endif
+module_param_array(pardev, charp, NULL, 0);
+MODULE_PARM_DESC(pardev, "pardev: where to search for\n"
+		"\teach camera. 'aggressive' means brute-force search.\n"
+		"\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n"
+		"\tcam 1 to parport3 and search every parport for cam 2 etc...");
+
+static int parmode;
+module_param(parmode, int, 0);
+MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp");
+
+static int video_nr = -1;
+module_param(video_nr, int, 0);
+
+static struct w9966 w9966_cams[W9966_MAXCAMS];
+
+/*
+ *	Private function defines
+ */
+
+
+/* Set camera phase flags, so we know what to uninit when terminating */
+static inline void w9966_set_state(struct w9966 *cam, int mask, int val)
+{
+	cam->dev_state = (cam->dev_state & ~mask) ^ val;
+}
+
+/* Get camera phase flags */
+static inline int w9966_get_state(struct w9966 *cam, int mask, int val)
+{
+	return ((cam->dev_state & mask) == val);
+}
+
+/* Claim parport for ourself */
+static void w9966_pdev_claim(struct w9966 *cam)
+{
+	if (w9966_get_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED))
+		return;
+	parport_claim_or_block(cam->pdev);
+	w9966_set_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED);
+}
+
+/* Release parport for others to use */
+static void w9966_pdev_release(struct w9966 *cam)
+{
+	if (w9966_get_state(cam, W9966_STATE_CLAIMED, 0))
+		return;
+	parport_release(cam->pdev);
+	w9966_set_state(cam, W9966_STATE_CLAIMED, 0);
+}
+
+/* Read register from W9966 interface-chip
+   Expects a claimed pdev
+   -1 on error, else register data (byte) */
+static int w9966_read_reg(struct w9966 *cam, int reg)
+{
+	/* ECP, read, regtransfer, REG, REG, REG, REG, REG */
+	const unsigned char addr = 0x80 | (reg & 0x1f);
+	unsigned char val;
+
+	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
+		return -1;
+	if (parport_write(cam->pport, &addr, 1) != 1)
+		return -1;
+	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
+		return -1;
+	if (parport_read(cam->pport, &val, 1) != 1)
+		return -1;
+
+	return val;
+}
+
+/* Write register to W9966 interface-chip
+   Expects a claimed pdev
+   -1 on error */
+static int w9966_write_reg(struct w9966 *cam, int reg, int data)
+{
+	/* ECP, write, regtransfer, REG, REG, REG, REG, REG */
+	const unsigned char addr = 0xc0 | (reg & 0x1f);
+	const unsigned char val = data;
+
+	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
+		return -1;
+	if (parport_write(cam->pport, &addr, 1) != 1)
+		return -1;
+	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
+		return -1;
+	if (parport_write(cam->pport, &val, 1) != 1)
+		return -1;
+
+	return 0;
+}
+
+/*
+ *	Ugly and primitive i2c protocol functions
+ */
+
+/* Sets the data line on the i2c bus.
+   Expects a claimed pdev. */
+static void w9966_i2c_setsda(struct w9966 *cam, int state)
+{
+	if (state)
+		cam->i2c_state |= W9966_I2C_W_DATA;
+	else
+		cam->i2c_state &= ~W9966_I2C_W_DATA;
+
+	w9966_write_reg(cam, 0x18, cam->i2c_state);
+	udelay(5);
+}
+
+/* Get peripheral clock line
+   Expects a claimed pdev. */
+static int w9966_i2c_getscl(struct w9966 *cam)
+{
+	const unsigned char state = w9966_read_reg(cam, 0x18);
+	return ((state & W9966_I2C_R_CLOCK) > 0);
+}
+
+/* Sets the clock line on the i2c bus.
+   Expects a claimed pdev. -1 on error */
+static int w9966_i2c_setscl(struct w9966 *cam, int state)
+{
+	unsigned long timeout;
+
+	if (state)
+		cam->i2c_state |= W9966_I2C_W_CLOCK;
+	else
+		cam->i2c_state &= ~W9966_I2C_W_CLOCK;
+
+	w9966_write_reg(cam, 0x18, cam->i2c_state);
+	udelay(5);
+
+	/* we go to high, we also expect the peripheral to ack. */
+	if (state) {
+		timeout = jiffies + 100;
+		while (!w9966_i2c_getscl(cam)) {
+			if (time_after(jiffies, timeout))
+				return -1;
+		}
+	}
+	return 0;
+}
+
+#if 0
+/* Get peripheral data line
+   Expects a claimed pdev. */
+static int w9966_i2c_getsda(struct w9966 *cam)
+{
+	const unsigned char state = w9966_read_reg(cam, 0x18);
+	return ((state & W9966_I2C_R_DATA) > 0);
+}
+#endif
+
+/* Write a byte with ack to the i2c bus.
+   Expects a claimed pdev. -1 on error */
+static int w9966_i2c_wbyte(struct w9966 *cam, int data)
+{
+	int i;
+
+	for (i = 7; i >= 0; i--) {
+		w9966_i2c_setsda(cam, (data >> i) & 0x01);
+
+		if (w9966_i2c_setscl(cam, 1) == -1)
+			return -1;
+		w9966_i2c_setscl(cam, 0);
+	}
+
+	w9966_i2c_setsda(cam, 1);
+
+	if (w9966_i2c_setscl(cam, 1) == -1)
+		return -1;
+	w9966_i2c_setscl(cam, 0);
+
+	return 0;
+}
+
+/* Read a data byte with ack from the i2c-bus
+   Expects a claimed pdev. -1 on error */
+#if 0
+static int w9966_i2c_rbyte(struct w9966 *cam)
+{
+	unsigned char data = 0x00;
+	int i;
+
+	w9966_i2c_setsda(cam, 1);
+
+	for (i = 0; i < 8; i++) {
+		if (w9966_i2c_setscl(cam, 1) == -1)
+			return -1;
+		data = data << 1;
+		if (w9966_i2c_getsda(cam))
+			data |= 0x01;
+
+		w9966_i2c_setscl(cam, 0);
+	}
+	return data;
+}
+#endif
+
+/* Read a register from the i2c device.
+   Expects claimed pdev. -1 on error */
+#if 0
+static int w9966_read_reg_i2c(struct w9966 *cam, int reg)
+{
+	int data;
+
+	w9966_i2c_setsda(cam, 0);
+	w9966_i2c_setscl(cam, 0);
+
+	if (w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
+	    w9966_i2c_wbyte(cam, reg) == -1)
+		return -1;
+
+	w9966_i2c_setsda(cam, 1);
+	if (w9966_i2c_setscl(cam, 1) == -1)
+		return -1;
+	w9966_i2c_setsda(cam, 0);
+	w9966_i2c_setscl(cam, 0);
+
+	if (w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1)
+		return -1;
+	data = w9966_i2c_rbyte(cam);
+	if (data == -1)
+		return -1;
+
+	w9966_i2c_setsda(cam, 0);
+
+	if (w9966_i2c_setscl(cam, 1) == -1)
+		return -1;
+	w9966_i2c_setsda(cam, 1);
+
+	return data;
+}
+#endif
+
+/* Write a register to the i2c device.
+   Expects claimed pdev. -1 on error */
+static int w9966_write_reg_i2c(struct w9966 *cam, int reg, int data)
+{
+	w9966_i2c_setsda(cam, 0);
+	w9966_i2c_setscl(cam, 0);
+
+	if (w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
+			w9966_i2c_wbyte(cam, reg) == -1 ||
+			w9966_i2c_wbyte(cam, data) == -1)
+		return -1;
+
+	w9966_i2c_setsda(cam, 0);
+	if (w9966_i2c_setscl(cam, 1) == -1)
+		return -1;
+
+	w9966_i2c_setsda(cam, 1);
+
+	return 0;
+}
+
+/* Find a good length for capture window (used both for W and H)
+   A bit ugly but pretty functional. The capture length
+   have to match the downscale */
+static int w9966_findlen(int near, int size, int maxlen)
+{
+	int bestlen = size;
+	int besterr = abs(near - bestlen);
+	int len;
+
+	for (len = size + 1; len < maxlen; len++) {
+		int err;
+		if (((64 * size) % len) != 0)
+			continue;
+
+		err = abs(near - len);
+
+		/* Only continue as long as we keep getting better values */
+		if (err > besterr)
+			break;
+
+		besterr = err;
+		bestlen = len;
+	}
+
+	return bestlen;
+}
+
+/* Modify capture window (if necessary)
+   and calculate downscaling
+   Return -1 on error */
+static int w9966_calcscale(int size, int min, int max, int *beg, int *end, unsigned char *factor)
+{
+	int maxlen = max - min;
+	int len = *end - *beg + 1;
+	int newlen = w9966_findlen(len, size, maxlen);
+	int err = newlen - len;
+
+	/* Check for bad format */
+	if (newlen > maxlen || newlen < size)
+		return -1;
+
+	/* Set factor (6 bit fixed) */
+	*factor = (64 * size) / newlen;
+	if (*factor == 64)
+		*factor = 0x00;	/* downscale is disabled */
+	else
+		*factor |= 0x80; /* set downscale-enable bit */
+
+	/* Modify old beginning and end */
+	*beg -= err / 2;
+	*end += err - (err / 2);
+
+	/* Move window if outside borders */
+	if (*beg < min) {
+		*end += min - *beg;
+		*beg += min - *beg;
+	}
+	if (*end > max) {
+		*beg -= *end - max;
+		*end -= *end - max;
+	}
+
+	return 0;
+}
+
+/* Setup the cameras capture window etc.
+   Expects a claimed pdev
+   return -1 on error */
+static int w9966_setup(struct w9966 *cam, int x1, int y1, int x2, int y2, int w, int h)
+{
+	unsigned int i;
+	unsigned int enh_s, enh_e;
+	unsigned char scale_x, scale_y;
+	unsigned char regs[0x1c];
+	unsigned char saa7111_regs[] = {
+		0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00,
+		0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00,
+		0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0
+	};
+
+
+	if (w * h * 2 > W9966_SRAMSIZE) {
+		DPRINTF("capture window exceeds SRAM size!.\n");
+		w = 200; h = 160;	/* Pick default values */
+	}
+
+	w &= ~0x1;
+	if (w < 2)
+		w = 2;
+	if (h < 1)
+		h = 1;
+	if (w > W9966_WND_MAX_W)
+		w = W9966_WND_MAX_W;
+	if (h > W9966_WND_MAX_H)
+		h = W9966_WND_MAX_H;
+
+	cam->width = w;
+	cam->height = h;
+
+	enh_s = 0;
+	enh_e = w * h * 2;
+
+	/* Modify capture window if necessary and calculate downscaling */
+	if (w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 ||
+			w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0)
+		return -1;
+
+	DPRINTF("%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n",
+			w, h, x1, x2, y1, y2, scale_x & ~0x80, scale_y & ~0x80);
+
+	/* Setup registers */
+	regs[0x00] = 0x00;			/* Set normal operation */
+	regs[0x01] = 0x18;			/* Capture mode */
+	regs[0x02] = scale_y;			/* V-scaling */
+	regs[0x03] = scale_x;			/* H-scaling */
+
+	/* Capture window */
+	regs[0x04] = (x1 & 0x0ff);		/* X-start (8 low bits) */
+	regs[0x05] = (x1 & 0x300)>>8;		/* X-start (2 high bits) */
+	regs[0x06] = (y1 & 0x0ff);		/* Y-start (8 low bits) */
+	regs[0x07] = (y1 & 0x300)>>8;		/* Y-start (2 high bits) */
+	regs[0x08] = (x2 & 0x0ff);		/* X-end (8 low bits) */
+	regs[0x09] = (x2 & 0x300)>>8;		/* X-end (2 high bits) */
+	regs[0x0a] = (y2 & 0x0ff);		/* Y-end (8 low bits) */
+
+	regs[0x0c] = W9966_SRAMID;		/* SRAM-banks (1x 128kb) */
+
+	/* Enhancement layer */
+	regs[0x0d] = (enh_s & 0x000ff);		/* Enh. start (0-7) */
+	regs[0x0e] = (enh_s & 0x0ff00) >> 8;	/* Enh. start (8-15) */
+	regs[0x0f] = (enh_s & 0x70000) >> 16;	/* Enh. start (16-17/18??) */
+	regs[0x10] = (enh_e & 0x000ff);		/* Enh. end (0-7) */
+	regs[0x11] = (enh_e & 0x0ff00) >> 8;	/* Enh. end (8-15) */
+	regs[0x12] = (enh_e & 0x70000) >> 16;	/* Enh. end (16-17/18??) */
+
+	/* Misc */
+	regs[0x13] = 0x40;			/* VEE control (raw 4:2:2) */
+	regs[0x17] = 0x00;			/* ??? */
+	regs[0x18] = cam->i2c_state = 0x00;	/* Serial bus */
+	regs[0x19] = 0xff;			/* I/O port direction control */
+	regs[0x1a] = 0xff;			/* I/O port data register */
+	regs[0x1b] = 0x10;			/* ??? */
+
+	/* SAA7111 chip settings */
+	saa7111_regs[0x0a] = cam->brightness;
+	saa7111_regs[0x0b] = cam->contrast;
+	saa7111_regs[0x0c] = cam->color;
+	saa7111_regs[0x0d] = cam->hue;
+
+	/* Reset (ECP-fifo & serial-bus) */
+	if (w9966_write_reg(cam, 0x00, 0x03) == -1)
+		return -1;
+
+	/* Write regs to w9966cf chip */
+	for (i = 0; i < 0x1c; i++)
+		if (w9966_write_reg(cam, i, regs[i]) == -1)
+			return -1;
+
+	/* Write regs to saa7111 chip */
+	for (i = 0; i < 0x20; i++)
+		if (w9966_write_reg_i2c(cam, i, saa7111_regs[i]) == -1)
+			return -1;
+
+	return 0;
+}
+
+/*
+ *	Video4linux interfacing
+ */
+
+static int cam_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *vcap)
+{
+	struct w9966 *cam = video_drvdata(file);
+
+	strlcpy(vcap->driver, cam->v4l2_dev.name, sizeof(vcap->driver));
+	strlcpy(vcap->card, W9966_DRIVERNAME, sizeof(vcap->card));
+	strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
+	vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
+	return 0;
+}
+
+static int cam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+	if (vin->index > 0)
+		return -EINVAL;
+	strlcpy(vin->name, "Camera", sizeof(vin->name));
+	vin->type = V4L2_INPUT_TYPE_CAMERA;
+	vin->audioset = 0;
+	vin->tuner = 0;
+	vin->std = 0;
+	vin->status = 0;
+	return 0;
+}
+
+static int cam_g_input(struct file *file, void *fh, unsigned int *inp)
+{
+	*inp = 0;
+	return 0;
+}
+
+static int cam_s_input(struct file *file, void *fh, unsigned int inp)
+{
+	return (inp > 0) ? -EINVAL : 0;
+}
+
+static int cam_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct w9966 *cam =
+		container_of(ctrl->handler, struct w9966, hdl);
+	int ret = 0;
+
+	mutex_lock(&cam->lock);
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		cam->brightness = ctrl->val;
+		break;
+	case V4L2_CID_CONTRAST:
+		cam->contrast = ctrl->val;
+		break;
+	case V4L2_CID_SATURATION:
+		cam->color = ctrl->val;
+		break;
+	case V4L2_CID_HUE:
+		cam->hue = ctrl->val;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret == 0) {
+		w9966_pdev_claim(cam);
+
+		if (w9966_write_reg_i2c(cam, 0x0a, cam->brightness) == -1 ||
+		    w9966_write_reg_i2c(cam, 0x0b, cam->contrast) == -1 ||
+		    w9966_write_reg_i2c(cam, 0x0c, cam->color) == -1 ||
+		    w9966_write_reg_i2c(cam, 0x0d, cam->hue) == -1) {
+			ret = -EIO;
+		}
+
+		w9966_pdev_release(cam);
+	}
+	mutex_unlock(&cam->lock);
+	return ret;
+}
+
+static int cam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct w9966 *cam = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	pix->width = cam->width;
+	pix->height = cam->height;
+	pix->pixelformat = V4L2_PIX_FMT_YUYV;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = 2 * cam->width;
+	pix->sizeimage = 2 * cam->width * cam->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	return 0;
+}
+
+static int cam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	if (pix->width < 2)
+		pix->width = 2;
+	if (pix->height < 1)
+		pix->height = 1;
+	if (pix->width > W9966_WND_MAX_W)
+		pix->width = W9966_WND_MAX_W;
+	if (pix->height > W9966_WND_MAX_H)
+		pix->height = W9966_WND_MAX_H;
+	pix->pixelformat = V4L2_PIX_FMT_YUYV;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = 2 * pix->width;
+	pix->sizeimage = 2 * pix->width * pix->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	return 0;
+}
+
+static int cam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct w9966 *cam = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+	int ret = cam_try_fmt_vid_cap(file, fh, fmt);
+
+	if (ret)
+		return ret;
+
+	mutex_lock(&cam->lock);
+	/* Update camera regs */
+	w9966_pdev_claim(cam);
+	ret = w9966_setup(cam, 0, 0, 1023, 1023, pix->width, pix->height);
+	w9966_pdev_release(cam);
+	mutex_unlock(&cam->lock);
+	return ret;
+}
+
+static int cam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
+{
+	static struct v4l2_fmtdesc formats[] = {
+		{ 0, 0, 0,
+		  "YUV 4:2:2", V4L2_PIX_FMT_YUYV,
+		  { 0, 0, 0, 0 }
+		},
+	};
+	enum v4l2_buf_type type = fmt->type;
+
+	if (fmt->index > 0)
+		return -EINVAL;
+
+	*fmt = formats[fmt->index];
+	fmt->type = type;
+	return 0;
+}
+
+/* Capture data */
+static ssize_t w9966_v4l_read(struct file *file, char  __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct w9966 *cam = video_drvdata(file);
+	unsigned char addr = 0xa0;	/* ECP, read, CCD-transfer, 00000 */
+	unsigned char __user *dest = (unsigned char __user *)buf;
+	unsigned long dleft = count;
+	unsigned char *tbuf;
+
+	/* Why would anyone want more than this?? */
+	if (count > cam->width * cam->height * 2)
+		return -EINVAL;
+
+	mutex_lock(&cam->lock);
+	w9966_pdev_claim(cam);
+	w9966_write_reg(cam, 0x00, 0x02);	/* Reset ECP-FIFO buffer */
+	w9966_write_reg(cam, 0x00, 0x00);	/* Return to normal operation */
+	w9966_write_reg(cam, 0x01, 0x98);	/* Enable capture */
+
+	/* write special capture-addr and negotiate into data transfer */
+	if ((parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0) ||
+			(parport_write(cam->pport, &addr, 1) != 1) ||
+			(parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0)) {
+		w9966_pdev_release(cam);
+		mutex_unlock(&cam->lock);
+		return -EFAULT;
+	}
+
+	tbuf = kmalloc(W9966_RBUFFER, GFP_KERNEL);
+	if (tbuf == NULL) {
+		count = -ENOMEM;
+		goto out;
+	}
+
+	while (dleft > 0) {
+		unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft;
+
+		if (parport_read(cam->pport, tbuf, tsize) < tsize) {
+			count = -EFAULT;
+			goto out;
+		}
+		if (copy_to_user(dest, tbuf, tsize) != 0) {
+			count = -EFAULT;
+			goto out;
+		}
+		dest += tsize;
+		dleft -= tsize;
+	}
+
+	w9966_write_reg(cam, 0x01, 0x18);	/* Disable capture */
+
+out:
+	kfree(tbuf);
+	w9966_pdev_release(cam);
+	mutex_unlock(&cam->lock);
+
+	return count;
+}
+
+static const struct v4l2_file_operations w9966_fops = {
+	.owner		= THIS_MODULE,
+	.open		= v4l2_fh_open,
+	.release	= v4l2_fh_release,
+	.poll		= v4l2_ctrl_poll,
+	.unlocked_ioctl = video_ioctl2,
+	.read           = w9966_v4l_read,
+};
+
+static const struct v4l2_ioctl_ops w9966_ioctl_ops = {
+	.vidioc_querycap    		    = cam_querycap,
+	.vidioc_g_input      		    = cam_g_input,
+	.vidioc_s_input      		    = cam_s_input,
+	.vidioc_enum_input   		    = cam_enum_input,
+	.vidioc_enum_fmt_vid_cap 	    = cam_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap 		    = cam_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap  		    = cam_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap  	    = cam_try_fmt_vid_cap,
+	.vidioc_log_status		    = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event		    = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event	    = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_ctrl_ops cam_ctrl_ops = {
+	.s_ctrl = cam_s_ctrl,
+};
+
+
+/* Initialize camera device. Setup all internal flags, set a
+   default video mode, setup ccd-chip, register v4l device etc..
+   Also used for 'probing' of hardware.
+   -1 on error */
+static int w9966_init(struct w9966 *cam, struct parport *port)
+{
+	struct v4l2_device *v4l2_dev = &cam->v4l2_dev;
+
+	if (cam->dev_state != 0)
+		return -1;
+
+	strlcpy(v4l2_dev->name, "w9966", sizeof(v4l2_dev->name));
+
+	if (v4l2_device_register(NULL, v4l2_dev) < 0) {
+		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+		return -1;
+	}
+
+	v4l2_ctrl_handler_init(&cam->hdl, 4);
+	v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops,
+			  V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops,
+			  V4L2_CID_CONTRAST, -64, 64, 1, 64);
+	v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops,
+			  V4L2_CID_SATURATION, -64, 64, 1, 64);
+	v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops,
+			  V4L2_CID_HUE, -128, 127, 1, 0);
+	if (cam->hdl.error) {
+		v4l2_err(v4l2_dev, "couldn't register controls\n");
+		return -1;
+	}
+	cam->pport = port;
+	cam->brightness = 128;
+	cam->contrast = 64;
+	cam->color = 64;
+	cam->hue = 0;
+
+	/* Select requested transfer mode */
+	switch (parmode) {
+	default:	/* Auto-detect (priority: hw-ecp, hw-epp, sw-ecp) */
+	case 0:
+		if (port->modes & PARPORT_MODE_ECP)
+			cam->ppmode = IEEE1284_MODE_ECP;
+		else if (port->modes & PARPORT_MODE_EPP)
+			cam->ppmode = IEEE1284_MODE_EPP;
+		else
+			cam->ppmode = IEEE1284_MODE_ECP;
+		break;
+	case 1:		/* hw- or sw-ecp */
+		cam->ppmode = IEEE1284_MODE_ECP;
+		break;
+	case 2:		/* hw- or sw-epp */
+		cam->ppmode = IEEE1284_MODE_EPP;
+		break;
+	}
+
+	/* Tell the parport driver that we exists */
+	cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL);
+	if (cam->pdev == NULL) {
+		DPRINTF("parport_register_device() failed\n");
+		return -1;
+	}
+	w9966_set_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV);
+
+	w9966_pdev_claim(cam);
+
+	/* Setup a default capture mode */
+	if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) {
+		DPRINTF("w9966_setup() failed.\n");
+		return -1;
+	}
+
+	w9966_pdev_release(cam);
+
+	/* Fill in the video_device struct and register us to v4l */
+	strlcpy(cam->vdev.name, W9966_DRIVERNAME, sizeof(cam->vdev.name));
+	cam->vdev.v4l2_dev = v4l2_dev;
+	cam->vdev.fops = &w9966_fops;
+	cam->vdev.ioctl_ops = &w9966_ioctl_ops;
+	cam->vdev.release = video_device_release_empty;
+	cam->vdev.ctrl_handler = &cam->hdl;
+	set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags);
+	video_set_drvdata(&cam->vdev, cam);
+
+	mutex_init(&cam->lock);
+
+	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
+		return -1;
+
+	w9966_set_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
+
+	/* All ok */
+	v4l2_info(v4l2_dev, "Found and initialized a webcam on %s.\n",
+			cam->pport->name);
+	return 0;
+}
+
+
+/* Terminate everything gracefully */
+static void w9966_term(struct w9966 *cam)
+{
+	/* Unregister from v4l */
+	if (w9966_get_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) {
+		video_unregister_device(&cam->vdev);
+		w9966_set_state(cam, W9966_STATE_VDEV, 0);
+	}
+
+	v4l2_ctrl_handler_free(&cam->hdl);
+
+	/* Terminate from IEEE1284 mode and release pdev block */
+	if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
+		w9966_pdev_claim(cam);
+		parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT);
+		w9966_pdev_release(cam);
+	}
+
+	/* Unregister from parport */
+	if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
+		parport_unregister_device(cam->pdev);
+		w9966_set_state(cam, W9966_STATE_PDEV, 0);
+	}
+	memset(cam, 0, sizeof(*cam));
+}
+
+
+/* Called once for every parport on init */
+static void w9966_attach(struct parport *port)
+{
+	int i;
+
+	for (i = 0; i < W9966_MAXCAMS; i++) {
+		if (w9966_cams[i].dev_state != 0)	/* Cam is already assigned */
+			continue;
+		if (strcmp(pardev[i], "aggressive") == 0 || strcmp(pardev[i], port->name) == 0) {
+			if (w9966_init(&w9966_cams[i], port) != 0)
+				w9966_term(&w9966_cams[i]);
+			break;	/* return */
+		}
+	}
+}
+
+/* Called once for every parport on termination */
+static void w9966_detach(struct parport *port)
+{
+	int i;
+
+	for (i = 0; i < W9966_MAXCAMS; i++)
+		if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port)
+			w9966_term(&w9966_cams[i]);
+}
+
+
+static struct parport_driver w9966_ppd = {
+	.name = W9966_DRIVERNAME,
+	.attach = w9966_attach,
+	.detach = w9966_detach,
+};
+
+/* Module entry point */
+static int __init w9966_mod_init(void)
+{
+	int i;
+
+	for (i = 0; i < W9966_MAXCAMS; i++)
+		w9966_cams[i].dev_state = 0;
+
+	return parport_register_driver(&w9966_ppd);
+}
+
+/* Module cleanup */
+static void __exit w9966_mod_term(void)
+{
+	parport_unregister_driver(&w9966_ppd);
+}
+
+module_init(w9966_mod_init);
+module_exit(w9966_mod_term);
diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig
new file mode 100644
index 0000000..4243d5d
--- /dev/null
+++ b/drivers/media/pci/Kconfig
@@ -0,0 +1,45 @@
+#
+# DVB device configuration
+#
+
+menu "Media PCI Adapters"
+	visible if PCI && MEDIA_SUPPORT
+
+if MEDIA_CAMERA_SUPPORT
+	comment "Media capture support"
+source "drivers/media/pci/meye/Kconfig"
+source "drivers/media/pci/sta2x11/Kconfig"
+endif
+
+if MEDIA_ANALOG_TV_SUPPORT
+	comment "Media capture/analog TV support"
+source "drivers/media/pci/ivtv/Kconfig"
+source "drivers/media/pci/zoran/Kconfig"
+source "drivers/media/pci/saa7146/Kconfig"
+endif
+
+if MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT
+	comment "Media capture/analog/hybrid TV support"
+source "drivers/media/pci/cx18/Kconfig"
+source "drivers/media/pci/cx23885/Kconfig"
+source "drivers/media/pci/cx25821/Kconfig"
+source "drivers/media/pci/cx88/Kconfig"
+source "drivers/media/pci/bt8xx/Kconfig"
+source "drivers/media/pci/saa7134/Kconfig"
+source "drivers/media/pci/saa7164/Kconfig"
+
+endif
+
+if MEDIA_DIGITAL_TV_SUPPORT
+	comment "Media digital TV PCI Adapters"
+source "drivers/media/pci/ttpci/Kconfig"
+source "drivers/media/pci/b2c2/Kconfig"
+source "drivers/media/pci/pluto2/Kconfig"
+source "drivers/media/pci/dm1105/Kconfig"
+source "drivers/media/pci/pt1/Kconfig"
+source "drivers/media/pci/mantis/Kconfig"
+source "drivers/media/pci/ngene/Kconfig"
+source "drivers/media/pci/ddbridge/Kconfig"
+endif
+
+endmenu
diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile
new file mode 100644
index 0000000..35cc578
--- /dev/null
+++ b/drivers/media/pci/Makefile
@@ -0,0 +1,26 @@
+#
+# Makefile for the kernel multimedia device drivers.
+#
+
+obj-y        +=	ttpci/		\
+		b2c2/		\
+		pluto2/		\
+		dm1105/		\
+		pt1/		\
+		mantis/		\
+		ngene/		\
+		ddbridge/	\
+		b2c2/		\
+		saa7146/
+
+obj-$(CONFIG_VIDEO_IVTV) += ivtv/
+obj-$(CONFIG_VIDEO_ZORAN) += zoran/
+obj-$(CONFIG_VIDEO_CX18) += cx18/
+obj-$(CONFIG_VIDEO_CX23885) += cx23885/
+obj-$(CONFIG_VIDEO_CX25821) += cx25821/
+obj-$(CONFIG_VIDEO_CX88) += cx88/
+obj-$(CONFIG_VIDEO_BT848) += bt8xx/
+obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
+obj-$(CONFIG_VIDEO_SAA7164) += saa7164/
+obj-$(CONFIG_VIDEO_MEYE) += meye/
+obj-$(CONFIG_STA2X11_VIP) += sta2x11/
diff --git a/drivers/media/pci/b2c2/Kconfig b/drivers/media/pci/b2c2/Kconfig
new file mode 100644
index 0000000..aaa1f30
--- /dev/null
+++ b/drivers/media/pci/b2c2/Kconfig
@@ -0,0 +1,6 @@
+config DVB_B2C2_FLEXCOP_PCI
+	tristate "Technisat/B2C2 Air/Sky/Cable2PC PCI"
+	help
+	  Support for the Air/Sky/CableStar2 PCI card (DVB/ATSC) by Technisat/B2C2.
+
+	  Say Y if you own such a device and want to use it.
diff --git a/drivers/media/pci/b2c2/Makefile b/drivers/media/pci/b2c2/Makefile
new file mode 100644
index 0000000..b894320
--- /dev/null
+++ b/drivers/media/pci/b2c2/Makefile
@@ -0,0 +1,9 @@
+ifneq ($(CONFIG_DVB_B2C2_FLEXCOP_PCI),)
+b2c2-flexcop-pci-objs += flexcop-dma.o
+endif
+
+b2c2-flexcop-pci-objs += flexcop-pci.o
+obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o
+
+ccflags-y += -Idrivers/media/dvb-core/
+ccflags-y += -Idrivers/media/common/b2c2/
diff --git a/drivers/media/pci/b2c2/flexcop-dma.c b/drivers/media/pci/b2c2/flexcop-dma.c
new file mode 100644
index 0000000..2881e0d
--- /dev/null
+++ b/drivers/media/pci/b2c2/flexcop-dma.c
@@ -0,0 +1,172 @@
+/*
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-dma.c - configuring and controlling the DMA of the FlexCop
+ * see flexcop.c for copyright information
+ */
+#include "flexcop.h"
+
+int flexcop_dma_allocate(struct pci_dev *pdev,
+		struct flexcop_dma *dma, u32 size)
+{
+	u8 *tcpu;
+	dma_addr_t tdma = 0;
+
+	if (size % 2) {
+		err("dma buffersize has to be even.");
+		return -EINVAL;
+	}
+
+	if ((tcpu = pci_alloc_consistent(pdev, size, &tdma)) != NULL) {
+		dma->pdev = pdev;
+		dma->cpu_addr0 = tcpu;
+		dma->dma_addr0 = tdma;
+		dma->cpu_addr1 = tcpu + size/2;
+		dma->dma_addr1 = tdma + size/2;
+		dma->size = size/2;
+		return 0;
+	}
+	return -ENOMEM;
+}
+EXPORT_SYMBOL(flexcop_dma_allocate);
+
+void flexcop_dma_free(struct flexcop_dma *dma)
+{
+	pci_free_consistent(dma->pdev, dma->size*2,
+			dma->cpu_addr0, dma->dma_addr0);
+	memset(dma,0,sizeof(struct flexcop_dma));
+}
+EXPORT_SYMBOL(flexcop_dma_free);
+
+int flexcop_dma_config(struct flexcop_device *fc,
+		struct flexcop_dma *dma,
+		flexcop_dma_index_t dma_idx)
+{
+	flexcop_ibi_value v0x0,v0x4,v0xc;
+	v0x0.raw = v0x4.raw = v0xc.raw = 0;
+
+	v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2;
+	v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2;
+	v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;
+
+	if ((dma_idx & FC_DMA_1) == dma_idx) {
+		fc->write_ibi_reg(fc,dma1_000,v0x0);
+		fc->write_ibi_reg(fc,dma1_004,v0x4);
+		fc->write_ibi_reg(fc,dma1_00c,v0xc);
+	} else if ((dma_idx & FC_DMA_2) == dma_idx) {
+		fc->write_ibi_reg(fc,dma2_010,v0x0);
+		fc->write_ibi_reg(fc,dma2_014,v0x4);
+		fc->write_ibi_reg(fc,dma2_01c,v0xc);
+	} else {
+		err("either DMA1 or DMA2 can be configured within one "
+			"flexcop_dma_config call.");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_config);
+
+/* start the DMA transfers, but not the DMA IRQs */
+int flexcop_dma_xfer_control(struct flexcop_device *fc,
+		flexcop_dma_index_t dma_idx,
+		flexcop_dma_addr_index_t index,
+		int onoff)
+{
+	flexcop_ibi_value v0x0,v0xc;
+	flexcop_ibi_register r0x0,r0xc;
+
+	if ((dma_idx & FC_DMA_1) == dma_idx) {
+		r0x0 = dma1_000;
+		r0xc = dma1_00c;
+	} else if ((dma_idx & FC_DMA_2) == dma_idx) {
+		r0x0 = dma2_010;
+		r0xc = dma2_01c;
+	} else {
+		err("either transfer DMA1 or DMA2 can be started within one "
+			"flexcop_dma_xfer_control call.");
+		return -EINVAL;
+	}
+
+	v0x0 = fc->read_ibi_reg(fc,r0x0);
+	v0xc = fc->read_ibi_reg(fc,r0xc);
+
+	deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
+	deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);
+
+	if (index & FC_DMA_SUBADDR_0)
+		v0x0.dma_0x0.dma_0start = onoff;
+
+	if (index & FC_DMA_SUBADDR_1)
+		v0xc.dma_0xc.dma_1start = onoff;
+
+	fc->write_ibi_reg(fc,r0x0,v0x0);
+	fc->write_ibi_reg(fc,r0xc,v0xc);
+
+	deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
+	deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);
+	return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_xfer_control);
+
+static int flexcop_dma_remap(struct flexcop_device *fc,
+		flexcop_dma_index_t dma_idx,
+		int onoff)
+{
+	flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c;
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+	deb_info("%s\n",__func__);
+	v.dma_0xc.remap_enable = onoff;
+	fc->write_ibi_reg(fc,r,v);
+	return 0;
+}
+
+int flexcop_dma_control_size_irq(struct flexcop_device *fc,
+		flexcop_dma_index_t no,
+		int onoff)
+{
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+
+	if (no & FC_DMA_1)
+		v.ctrl_208.DMA1_IRQ_Enable_sig = onoff;
+
+	if (no & FC_DMA_2)
+		v.ctrl_208.DMA2_IRQ_Enable_sig = onoff;
+
+	fc->write_ibi_reg(fc,ctrl_208,v);
+	return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_control_size_irq);
+
+int flexcop_dma_control_timer_irq(struct flexcop_device *fc,
+		flexcop_dma_index_t no,
+		int onoff)
+{
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+
+	if (no & FC_DMA_1)
+		v.ctrl_208.DMA1_Timer_Enable_sig = onoff;
+
+	if (no & FC_DMA_2)
+		v.ctrl_208.DMA2_Timer_Enable_sig = onoff;
+
+	fc->write_ibi_reg(fc,ctrl_208,v);
+	return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
+
+/* 1 cycles = 1.97 msec */
+int flexcop_dma_config_timer(struct flexcop_device *fc,
+		flexcop_dma_index_t dma_idx, u8 cycles)
+{
+	flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+
+	flexcop_dma_remap(fc,dma_idx,0);
+
+	deb_info("%s\n",__func__);
+	v.dma_0x4_write.dmatimer = cycles;
+	fc->write_ibi_reg(fc,r,v);
+	return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_config_timer);
+
diff --git a/drivers/media/pci/b2c2/flexcop-pci.c b/drivers/media/pci/b2c2/flexcop-pci.c
new file mode 100644
index 0000000..44f8fb5
--- /dev/null
+++ b/drivers/media/pci/b2c2/flexcop-pci.c
@@ -0,0 +1,450 @@
+/*
+ * Linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-pci.c - covers the PCI part including DMA transfers
+ * see flexcop.c for copyright information
+ */
+
+#define FC_LOG_PREFIX "flexcop-pci"
+#include "flexcop-common.h"
+
+static int enable_pid_filtering = 1;
+module_param(enable_pid_filtering, int, 0444);
+MODULE_PARM_DESC(enable_pid_filtering,
+	"enable hardware pid filtering: supported values: 0 (fullts), 1");
+
+static int irq_chk_intv = 100;
+module_param(irq_chk_intv, int, 0644);
+MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ streaming watchdog.");
+
+#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
+#define dprintk(level,args...) \
+	do { if ((debug & level)) printk(args); } while (0)
+#define DEBSTATUS ""
+#else
+#define dprintk(level,args...)
+#define DEBSTATUS " (debugging is not enabled)"
+#endif
+
+#define deb_info(args...) dprintk(0x01, args)
+#define deb_reg(args...) dprintk(0x02, args)
+#define deb_ts(args...) dprintk(0x04, args)
+#define deb_irq(args...) dprintk(0x08, args)
+#define deb_chk(args...) dprintk(0x10, args)
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,
+	"set debug level (1=info,2=regs,4=TS,8=irqdma,16=check (|-able))."
+	DEBSTATUS);
+
+#define DRIVER_VERSION "0.1"
+#define DRIVER_NAME "flexcop-pci"
+#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
+
+struct flexcop_pci {
+	struct pci_dev *pdev;
+
+#define FC_PCI_INIT     0x01
+#define FC_PCI_DMA_INIT 0x02
+	int init_state;
+
+	void __iomem *io_mem;
+	u32 irq;
+	/* buffersize (at least for DMA1, need to be % 188 == 0,
+	 * this logic is required */
+#define FC_DEFAULT_DMA1_BUFSIZE (1280 * 188)
+#define FC_DEFAULT_DMA2_BUFSIZE (10 * 188)
+	struct flexcop_dma dma[2];
+
+	int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */
+	u32 last_dma1_cur_pos;
+	/* position of the pointer last time the timer/packet irq occurred */
+	int count;
+	int count_prev;
+	int stream_problem;
+
+	spinlock_t irq_lock;
+	unsigned long last_irq;
+
+	struct delayed_work irq_check_work;
+	struct flexcop_device *fc_dev;
+};
+
+static int lastwreg, lastwval, lastrreg, lastrval;
+
+static flexcop_ibi_value flexcop_pci_read_ibi_reg(struct flexcop_device *fc,
+		flexcop_ibi_register r)
+{
+	struct flexcop_pci *fc_pci = fc->bus_specific;
+	flexcop_ibi_value v;
+	v.raw = readl(fc_pci->io_mem + r);
+
+	if (lastrreg != r || lastrval != v.raw) {
+		lastrreg = r; lastrval = v.raw;
+		deb_reg("new rd: %3x: %08x\n", r, v.raw);
+	}
+
+	return v;
+}
+
+static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc,
+		flexcop_ibi_register r, flexcop_ibi_value v)
+{
+	struct flexcop_pci *fc_pci = fc->bus_specific;
+
+	if (lastwreg != r || lastwval != v.raw) {
+		lastwreg = r; lastwval = v.raw;
+		deb_reg("new wr: %3x: %08x\n", r, v.raw);
+	}
+
+	writel(v.raw, fc_pci->io_mem + r);
+	return 0;
+}
+
+static void flexcop_pci_irq_check_work(struct work_struct *work)
+{
+	struct flexcop_pci *fc_pci =
+		container_of(work, struct flexcop_pci, irq_check_work.work);
+	struct flexcop_device *fc = fc_pci->fc_dev;
+
+	if (fc->feedcount) {
+
+		if (fc_pci->count == fc_pci->count_prev) {
+			deb_chk("no IRQ since the last check\n");
+			if (fc_pci->stream_problem++ == 3) {
+				struct dvb_demux_feed *feed;
+				deb_info("flexcop-pci: stream problem, resetting pid filter\n");
+
+				spin_lock_irq(&fc->demux.lock);
+				list_for_each_entry(feed, &fc->demux.feed_list,
+						list_head) {
+					flexcop_pid_feed_control(fc, feed, 0);
+				}
+
+				list_for_each_entry(feed, &fc->demux.feed_list,
+						list_head) {
+					flexcop_pid_feed_control(fc, feed, 1);
+				}
+				spin_unlock_irq(&fc->demux.lock);
+
+				fc_pci->stream_problem = 0;
+			}
+		} else {
+			fc_pci->stream_problem = 0;
+			fc_pci->count_prev = fc_pci->count;
+		}
+	}
+
+	schedule_delayed_work(&fc_pci->irq_check_work,
+			msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
+}
+
+/* When PID filtering is turned on, we use the timer IRQ, because small amounts
+ * of data need to be passed to the user space instantly as well. When PID
+ * filtering is turned off, we use the page-change-IRQ */
+static irqreturn_t flexcop_pci_isr(int irq, void *dev_id)
+{
+	struct flexcop_pci *fc_pci = dev_id;
+	struct flexcop_device *fc = fc_pci->fc_dev;
+	unsigned long flags;
+	flexcop_ibi_value v;
+	irqreturn_t ret = IRQ_HANDLED;
+
+	spin_lock_irqsave(&fc_pci->irq_lock, flags);
+	v = fc->read_ibi_reg(fc, irq_20c);
+
+	/* errors */
+	if (v.irq_20c.Data_receiver_error)
+		deb_chk("data receiver error\n");
+	if (v.irq_20c.Continuity_error_flag)
+		deb_chk("Contunuity error flag is set\n");
+	if (v.irq_20c.LLC_SNAP_FLAG_set)
+		deb_chk("LLC_SNAP_FLAG_set is set\n");
+	if (v.irq_20c.Transport_Error)
+		deb_chk("Transport error\n");
+
+	if ((fc_pci->count % 1000) == 0)
+		deb_chk("%d valid irq took place so far\n", fc_pci->count);
+
+	if (v.irq_20c.DMA1_IRQ_Status == 1) {
+		if (fc_pci->active_dma1_addr == 0)
+			flexcop_pass_dmx_packets(fc_pci->fc_dev,
+					fc_pci->dma[0].cpu_addr0,
+					fc_pci->dma[0].size / 188);
+		else
+			flexcop_pass_dmx_packets(fc_pci->fc_dev,
+					fc_pci->dma[0].cpu_addr1,
+					fc_pci->dma[0].size / 188);
+
+		deb_irq("page change to page: %d\n",!fc_pci->active_dma1_addr);
+		fc_pci->active_dma1_addr = !fc_pci->active_dma1_addr;
+		/* for the timer IRQ we only can use buffer dmx feeding, because we don't have
+		 * complete TS packets when reading from the DMA memory */
+	} else if (v.irq_20c.DMA1_Timer_Status == 1) {
+		dma_addr_t cur_addr =
+			fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2;
+		u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0;
+
+		deb_irq("%u irq: %08x cur_addr: %llx: cur_pos: %08x, "
+			"last_cur_pos: %08x ",
+				jiffies_to_usecs(jiffies - fc_pci->last_irq),
+				v.raw, (unsigned long long)cur_addr, cur_pos,
+				fc_pci->last_dma1_cur_pos);
+		fc_pci->last_irq = jiffies;
+
+		/* buffer end was reached, restarted from the beginning
+		 * pass the data from last_cur_pos to the buffer end to the demux
+		 */
+		if (cur_pos < fc_pci->last_dma1_cur_pos) {
+			deb_irq(" end was reached: passing %d bytes ",
+				(fc_pci->dma[0].size*2 - 1) -
+				fc_pci->last_dma1_cur_pos);
+			flexcop_pass_dmx_data(fc_pci->fc_dev,
+				fc_pci->dma[0].cpu_addr0 +
+					fc_pci->last_dma1_cur_pos,
+				(fc_pci->dma[0].size*2) -
+					fc_pci->last_dma1_cur_pos);
+			fc_pci->last_dma1_cur_pos = 0;
+		}
+
+		if (cur_pos > fc_pci->last_dma1_cur_pos) {
+			deb_irq(" passing %d bytes ",
+				cur_pos - fc_pci->last_dma1_cur_pos);
+			flexcop_pass_dmx_data(fc_pci->fc_dev,
+				fc_pci->dma[0].cpu_addr0 +
+					fc_pci->last_dma1_cur_pos,
+				cur_pos - fc_pci->last_dma1_cur_pos);
+		}
+		deb_irq("\n");
+
+		fc_pci->last_dma1_cur_pos = cur_pos;
+		fc_pci->count++;
+	} else {
+		deb_irq("isr for flexcop called, "
+			"apparently without reason (%08x)\n", v.raw);
+		ret = IRQ_NONE;
+	}
+
+	spin_unlock_irqrestore(&fc_pci->irq_lock, flags);
+	return ret;
+}
+
+static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff)
+{
+	struct flexcop_pci *fc_pci = fc->bus_specific;
+	if (onoff) {
+		flexcop_dma_config(fc, &fc_pci->dma[0], FC_DMA_1);
+		flexcop_dma_config(fc, &fc_pci->dma[1], FC_DMA_2);
+		flexcop_dma_config_timer(fc, FC_DMA_1, 0);
+		flexcop_dma_xfer_control(fc, FC_DMA_1,
+				FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1, 1);
+		deb_irq("DMA xfer enabled\n");
+
+		fc_pci->last_dma1_cur_pos = 0;
+		flexcop_dma_control_timer_irq(fc, FC_DMA_1, 1);
+		deb_irq("IRQ enabled\n");
+		fc_pci->count_prev = fc_pci->count;
+	} else {
+		flexcop_dma_control_timer_irq(fc, FC_DMA_1, 0);
+		deb_irq("IRQ disabled\n");
+
+		flexcop_dma_xfer_control(fc, FC_DMA_1,
+			 FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1, 0);
+		deb_irq("DMA xfer disabled\n");
+	}
+	return 0;
+}
+
+static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci)
+{
+	int ret;
+	ret = flexcop_dma_allocate(fc_pci->pdev, &fc_pci->dma[0],
+			FC_DEFAULT_DMA1_BUFSIZE);
+	if (ret != 0)
+		return ret;
+
+	ret = flexcop_dma_allocate(fc_pci->pdev, &fc_pci->dma[1],
+			FC_DEFAULT_DMA2_BUFSIZE);
+	if (ret != 0) {
+		flexcop_dma_free(&fc_pci->dma[0]);
+		return ret;
+	}
+
+	flexcop_sram_set_dest(fc_pci->fc_dev, FC_SRAM_DEST_MEDIA |
+			FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1);
+	flexcop_sram_set_dest(fc_pci->fc_dev, FC_SRAM_DEST_CAO |
+			FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
+	fc_pci->init_state |= FC_PCI_DMA_INIT;
+	return ret;
+}
+
+static void flexcop_pci_dma_exit(struct flexcop_pci *fc_pci)
+{
+	if (fc_pci->init_state & FC_PCI_DMA_INIT) {
+		flexcop_dma_free(&fc_pci->dma[0]);
+		flexcop_dma_free(&fc_pci->dma[1]);
+	}
+	fc_pci->init_state &= ~FC_PCI_DMA_INIT;
+}
+
+static int flexcop_pci_init(struct flexcop_pci *fc_pci)
+{
+	int ret;
+
+	info("card revision %x", fc_pci->pdev->revision);
+
+	if ((ret = pci_enable_device(fc_pci->pdev)) != 0)
+		return ret;
+	pci_set_master(fc_pci->pdev);
+
+	if ((ret = pci_request_regions(fc_pci->pdev, DRIVER_NAME)) != 0)
+		goto err_pci_disable_device;
+
+	fc_pci->io_mem = pci_iomap(fc_pci->pdev, 0, 0x800);
+
+	if (!fc_pci->io_mem) {
+		err("cannot map io memory\n");
+		ret = -EIO;
+		goto err_pci_release_regions;
+	}
+
+	pci_set_drvdata(fc_pci->pdev, fc_pci);
+	spin_lock_init(&fc_pci->irq_lock);
+	if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr,
+					IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0)
+		goto err_pci_iounmap;
+
+	fc_pci->init_state |= FC_PCI_INIT;
+	return ret;
+
+err_pci_iounmap:
+	pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
+	pci_set_drvdata(fc_pci->pdev, NULL);
+err_pci_release_regions:
+	pci_release_regions(fc_pci->pdev);
+err_pci_disable_device:
+	pci_disable_device(fc_pci->pdev);
+	return ret;
+}
+
+static void flexcop_pci_exit(struct flexcop_pci *fc_pci)
+{
+	if (fc_pci->init_state & FC_PCI_INIT) {
+		free_irq(fc_pci->pdev->irq, fc_pci);
+		pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
+		pci_set_drvdata(fc_pci->pdev, NULL);
+		pci_release_regions(fc_pci->pdev);
+		pci_disable_device(fc_pci->pdev);
+	}
+	fc_pci->init_state &= ~FC_PCI_INIT;
+}
+
+static int flexcop_pci_probe(struct pci_dev *pdev,
+		const struct pci_device_id *ent)
+{
+	struct flexcop_device *fc;
+	struct flexcop_pci *fc_pci;
+	int ret = -ENOMEM;
+
+	if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_pci))) == NULL) {
+		err("out of memory\n");
+		return -ENOMEM;
+	}
+
+	/* general flexcop init */
+	fc_pci = fc->bus_specific;
+	fc_pci->fc_dev = fc;
+
+	fc->read_ibi_reg = flexcop_pci_read_ibi_reg;
+	fc->write_ibi_reg = flexcop_pci_write_ibi_reg;
+	fc->i2c_request = flexcop_i2c_request;
+	fc->get_mac_addr = flexcop_eeprom_check_mac_addr;
+	fc->stream_control = flexcop_pci_stream_control;
+
+	if (enable_pid_filtering)
+		info("will use the HW PID filter.");
+	else
+		info("will pass the complete TS to the demuxer.");
+
+	fc->pid_filtering = enable_pid_filtering;
+	fc->bus_type = FC_PCI;
+	fc->dev = &pdev->dev;
+	fc->owner = THIS_MODULE;
+
+	/* bus specific part */
+	fc_pci->pdev = pdev;
+	if ((ret = flexcop_pci_init(fc_pci)) != 0)
+		goto err_kfree;
+
+	/* init flexcop */
+	if ((ret = flexcop_device_initialize(fc)) != 0)
+		goto err_pci_exit;
+
+	/* init dma */
+	if ((ret = flexcop_pci_dma_init(fc_pci)) != 0)
+		goto err_fc_exit;
+
+	INIT_DELAYED_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work);
+
+	if (irq_chk_intv > 0)
+		schedule_delayed_work(&fc_pci->irq_check_work,
+				msecs_to_jiffies(irq_chk_intv < 100 ?
+					100 :
+					irq_chk_intv));
+	return ret;
+
+err_fc_exit:
+	flexcop_device_exit(fc);
+err_pci_exit:
+	flexcop_pci_exit(fc_pci);
+err_kfree:
+	flexcop_device_kfree(fc);
+	return ret;
+}
+
+/* in theory every _exit function should be called exactly two times,
+ * here and in the bail-out-part of the _init-function
+ */
+static void flexcop_pci_remove(struct pci_dev *pdev)
+{
+	struct flexcop_pci *fc_pci = pci_get_drvdata(pdev);
+
+	if (irq_chk_intv > 0)
+		cancel_delayed_work(&fc_pci->irq_check_work);
+
+	flexcop_pci_dma_exit(fc_pci);
+	flexcop_device_exit(fc_pci->fc_dev);
+	flexcop_pci_exit(fc_pci);
+	flexcop_device_kfree(fc_pci->fc_dev);
+}
+
+static struct pci_device_id flexcop_pci_tbl[] = {
+	{ PCI_DEVICE(0x13d0, 0x2103) },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl);
+
+static struct pci_driver flexcop_pci_driver = {
+	.name     = "b2c2_flexcop_pci",
+	.id_table = flexcop_pci_tbl,
+	.probe    = flexcop_pci_probe,
+	.remove   = flexcop_pci_remove,
+};
+
+static int __init flexcop_pci_module_init(void)
+{
+	return pci_register_driver(&flexcop_pci_driver);
+}
+
+static void __exit flexcop_pci_module_exit(void)
+{
+	pci_unregister_driver(&flexcop_pci_driver);
+}
+
+module_init(flexcop_pci_module_init);
+module_exit(flexcop_pci_module_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_NAME);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/bt8xx/Kconfig b/drivers/media/pci/bt8xx/Kconfig
new file mode 100644
index 0000000..f2667a5
--- /dev/null
+++ b/drivers/media/pci/bt8xx/Kconfig
@@ -0,0 +1,43 @@
+config VIDEO_BT848
+	tristate "BT848 Video For Linux"
+	depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2
+	select I2C_ALGOBIT
+	select VIDEO_BTCX
+	select VIDEOBUF_DMA_SG
+	depends on RC_CORE
+	select VIDEO_TUNER
+	select VIDEO_TVEEPROM
+	select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_TDA7432 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_SAA6588 if VIDEO_HELPER_CHIPS_AUTO
+	---help---
+	  Support for BT848 based frame grabber/overlay boards. This includes
+	  the Miro, Hauppauge and STB boards. Please read the material in
+	  <file:Documentation/video4linux/bttv/> for more information.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bttv.
+
+config DVB_BT8XX
+	tristate "DVB/ATSC Support for bt878 based TV cards"
+	depends on DVB_CORE && PCI && I2C && VIDEO_BT848
+	select DVB_MT352 if !DVB_FE_CUSTOMISE
+	select DVB_SP887X if !DVB_FE_CUSTOMISE
+	select DVB_NXT6000 if !DVB_FE_CUSTOMISE
+	select DVB_CX24110 if !DVB_FE_CUSTOMISE
+	select DVB_OR51211 if !DVB_FE_CUSTOMISE
+	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Support for PCI cards based on the Bt8xx PCI bridge. Examples are
+	  the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
+	  the pcHDTV HD2000 cards, the DViCO FusionHDTV Lite cards, and
+	  some AVerMedia cards.
+
+	  Since these cards have no MPEG decoder onboard, they transmit
+	  only compressed MPEG data over the PCI bus, so you need
+	  an external software decoder to watch TV on your computer.
+
+	  Say Y if you own such a device and want to use it.
diff --git a/drivers/media/pci/bt8xx/Makefile b/drivers/media/pci/bt8xx/Makefile
new file mode 100644
index 0000000..5f06597
--- /dev/null
+++ b/drivers/media/pci/bt8xx/Makefile
@@ -0,0 +1,11 @@
+bttv-objs      :=      bttv-driver.o bttv-cards.o bttv-if.o \
+		       bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \
+		       bttv-input.o bttv-audio-hook.o
+
+obj-$(CONFIG_VIDEO_BT848) += bttv.o
+obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/tuners
diff --git a/drivers/media/pci/bt8xx/bt848.h b/drivers/media/pci/bt8xx/bt848.h
new file mode 100644
index 0000000..c37e6ac
--- /dev/null
+++ b/drivers/media/pci/bt8xx/bt848.h
@@ -0,0 +1,369 @@
+/*
+    bt848.h - Bt848 register offsets
+
+    Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _BT848_H_
+#define _BT848_H_
+
+#ifndef PCI_VENDOR_ID_BROOKTREE
+#define PCI_VENDOR_ID_BROOKTREE 0x109e
+#endif
+#ifndef PCI_DEVICE_ID_BT848
+#define PCI_DEVICE_ID_BT848     0x350
+#endif
+#ifndef PCI_DEVICE_ID_BT849
+#define PCI_DEVICE_ID_BT849     0x351
+#endif
+#ifndef PCI_DEVICE_ID_FUSION879
+#define PCI_DEVICE_ID_FUSION879	0x36c
+#endif
+
+#ifndef PCI_DEVICE_ID_BT878
+#define PCI_DEVICE_ID_BT878     0x36e
+#endif
+#ifndef PCI_DEVICE_ID_BT879
+#define PCI_DEVICE_ID_BT879     0x36f
+#endif
+
+/* Brooktree 848 registers */
+
+#define BT848_DSTATUS          0x000
+#define BT848_DSTATUS_PRES     (1<<7)
+#define BT848_DSTATUS_HLOC     (1<<6)
+#define BT848_DSTATUS_FIELD    (1<<5)
+#define BT848_DSTATUS_NUML     (1<<4)
+#define BT848_DSTATUS_CSEL     (1<<3)
+#define BT848_DSTATUS_PLOCK    (1<<2)
+#define BT848_DSTATUS_LOF      (1<<1)
+#define BT848_DSTATUS_COF      (1<<0)
+
+#define BT848_IFORM            0x004
+#define BT848_IFORM_HACTIVE    (1<<7)
+#define BT848_IFORM_MUXSEL     (3<<5)
+#define BT848_IFORM_MUX0       (2<<5)
+#define BT848_IFORM_MUX1       (3<<5)
+#define BT848_IFORM_MUX2       (1<<5)
+#define BT848_IFORM_XTSEL      (3<<3)
+#define BT848_IFORM_XT0        (1<<3)
+#define BT848_IFORM_XT1        (2<<3)
+#define BT848_IFORM_XTAUTO     (3<<3)
+#define BT848_IFORM_XTBOTH     (3<<3)
+#define BT848_IFORM_NTSC       1
+#define BT848_IFORM_NTSC_J     2
+#define BT848_IFORM_PAL_BDGHI  3
+#define BT848_IFORM_PAL_M      4
+#define BT848_IFORM_PAL_N      5
+#define BT848_IFORM_SECAM      6
+#define BT848_IFORM_PAL_NC     7
+#define BT848_IFORM_AUTO       0
+#define BT848_IFORM_NORM       7
+
+#define BT848_TDEC             0x008
+#define BT848_TDEC_DEC_FIELD   (1<<7)
+#define BT848_TDEC_FLDALIGN    (1<<6)
+#define BT848_TDEC_DEC_RAT     (0x1f)
+
+#define BT848_E_CROP           0x00C
+#define BT848_O_CROP           0x08C
+
+#define BT848_E_VDELAY_LO      0x010
+#define BT848_O_VDELAY_LO      0x090
+
+#define BT848_E_VACTIVE_LO     0x014
+#define BT848_O_VACTIVE_LO     0x094
+
+#define BT848_E_HDELAY_LO      0x018
+#define BT848_O_HDELAY_LO      0x098
+
+#define BT848_E_HACTIVE_LO     0x01C
+#define BT848_O_HACTIVE_LO     0x09C
+
+#define BT848_E_HSCALE_HI      0x020
+#define BT848_O_HSCALE_HI      0x0A0
+
+#define BT848_E_HSCALE_LO      0x024
+#define BT848_O_HSCALE_LO      0x0A4
+
+#define BT848_BRIGHT           0x028
+
+#define BT848_E_CONTROL        0x02C
+#define BT848_O_CONTROL        0x0AC
+#define BT848_CONTROL_LNOTCH    (1<<7)
+#define BT848_CONTROL_COMP      (1<<6)
+#define BT848_CONTROL_LDEC      (1<<5)
+#define BT848_CONTROL_CBSENSE   (1<<4)
+#define BT848_CONTROL_CON_MSB   (1<<2)
+#define BT848_CONTROL_SAT_U_MSB (1<<1)
+#define BT848_CONTROL_SAT_V_MSB (1<<0)
+
+#define BT848_CONTRAST_LO      0x030
+#define BT848_SAT_U_LO         0x034
+#define BT848_SAT_V_LO         0x038
+#define BT848_HUE              0x03C
+
+#define BT848_E_SCLOOP         0x040
+#define BT848_O_SCLOOP         0x0C0
+#define BT848_SCLOOP_CAGC       (1<<6)
+#define BT848_SCLOOP_CKILL      (1<<5)
+#define BT848_SCLOOP_HFILT_AUTO (0<<3)
+#define BT848_SCLOOP_HFILT_CIF  (1<<3)
+#define BT848_SCLOOP_HFILT_QCIF (2<<3)
+#define BT848_SCLOOP_HFILT_ICON (3<<3)
+
+#define BT848_SCLOOP_PEAK       (1<<7)
+#define BT848_SCLOOP_HFILT_MINP (1<<3)
+#define BT848_SCLOOP_HFILT_MEDP (2<<3)
+#define BT848_SCLOOP_HFILT_MAXP (3<<3)
+
+
+#define BT848_OFORM            0x048
+#define BT848_OFORM_RANGE      (1<<7)
+#define BT848_OFORM_CORE0      (0<<5)
+#define BT848_OFORM_CORE8      (1<<5)
+#define BT848_OFORM_CORE16     (2<<5)
+#define BT848_OFORM_CORE32     (3<<5)
+
+#define BT848_E_VSCALE_HI      0x04C
+#define BT848_O_VSCALE_HI      0x0CC
+#define BT848_VSCALE_YCOMB     (1<<7)
+#define BT848_VSCALE_COMB      (1<<6)
+#define BT848_VSCALE_INT       (1<<5)
+#define BT848_VSCALE_HI        15
+
+#define BT848_E_VSCALE_LO      0x050
+#define BT848_O_VSCALE_LO      0x0D0
+#define BT848_TEST             0x054
+#define BT848_ADELAY           0x060
+#define BT848_BDELAY           0x064
+
+#define BT848_ADC              0x068
+#define BT848_ADC_RESERVED     (2<<6)
+#define BT848_ADC_SYNC_T       (1<<5)
+#define BT848_ADC_AGC_EN       (1<<4)
+#define BT848_ADC_CLK_SLEEP    (1<<3)
+#define BT848_ADC_Y_SLEEP      (1<<2)
+#define BT848_ADC_C_SLEEP      (1<<1)
+#define BT848_ADC_CRUSH        (1<<0)
+
+#define BT848_WC_UP            0x044
+#define BT848_WC_DOWN          0x078
+
+#define BT848_E_VTC            0x06C
+#define BT848_O_VTC            0x0EC
+#define BT848_VTC_HSFMT        (1<<7)
+#define BT848_VTC_VFILT_2TAP   0
+#define BT848_VTC_VFILT_3TAP   1
+#define BT848_VTC_VFILT_4TAP   2
+#define BT848_VTC_VFILT_5TAP   3
+
+#define BT848_SRESET           0x07C
+
+#define BT848_COLOR_FMT             0x0D4
+#define BT848_COLOR_FMT_O_RGB32     (0<<4)
+#define BT848_COLOR_FMT_O_RGB24     (1<<4)
+#define BT848_COLOR_FMT_O_RGB16     (2<<4)
+#define BT848_COLOR_FMT_O_RGB15     (3<<4)
+#define BT848_COLOR_FMT_O_YUY2      (4<<4)
+#define BT848_COLOR_FMT_O_BtYUV     (5<<4)
+#define BT848_COLOR_FMT_O_Y8        (6<<4)
+#define BT848_COLOR_FMT_O_RGB8      (7<<4)
+#define BT848_COLOR_FMT_O_YCrCb422  (8<<4)
+#define BT848_COLOR_FMT_O_YCrCb411  (9<<4)
+#define BT848_COLOR_FMT_O_RAW       (14<<4)
+#define BT848_COLOR_FMT_E_RGB32     0
+#define BT848_COLOR_FMT_E_RGB24     1
+#define BT848_COLOR_FMT_E_RGB16     2
+#define BT848_COLOR_FMT_E_RGB15     3
+#define BT848_COLOR_FMT_E_YUY2      4
+#define BT848_COLOR_FMT_E_BtYUV     5
+#define BT848_COLOR_FMT_E_Y8        6
+#define BT848_COLOR_FMT_E_RGB8      7
+#define BT848_COLOR_FMT_E_YCrCb422  8
+#define BT848_COLOR_FMT_E_YCrCb411  9
+#define BT848_COLOR_FMT_E_RAW       14
+
+#define BT848_COLOR_FMT_RGB32       0x00
+#define BT848_COLOR_FMT_RGB24       0x11
+#define BT848_COLOR_FMT_RGB16       0x22
+#define BT848_COLOR_FMT_RGB15       0x33
+#define BT848_COLOR_FMT_YUY2        0x44
+#define BT848_COLOR_FMT_BtYUV       0x55
+#define BT848_COLOR_FMT_Y8          0x66
+#define BT848_COLOR_FMT_RGB8        0x77
+#define BT848_COLOR_FMT_YCrCb422    0x88
+#define BT848_COLOR_FMT_YCrCb411    0x99
+#define BT848_COLOR_FMT_RAW         0xee
+
+#define BT848_VTOTAL_LO             0xB0
+#define BT848_VTOTAL_HI             0xB4
+
+#define BT848_COLOR_CTL                0x0D8
+#define BT848_COLOR_CTL_EXT_FRMRATE    (1<<7)
+#define BT848_COLOR_CTL_COLOR_BARS     (1<<6)
+#define BT848_COLOR_CTL_RGB_DED        (1<<5)
+#define BT848_COLOR_CTL_GAMMA          (1<<4)
+#define BT848_COLOR_CTL_WSWAP_ODD      (1<<3)
+#define BT848_COLOR_CTL_WSWAP_EVEN     (1<<2)
+#define BT848_COLOR_CTL_BSWAP_ODD      (1<<1)
+#define BT848_COLOR_CTL_BSWAP_EVEN     (1<<0)
+
+#define BT848_CAP_CTL                  0x0DC
+#define BT848_CAP_CTL_DITH_FRAME       (1<<4)
+#define BT848_CAP_CTL_CAPTURE_VBI_ODD  (1<<3)
+#define BT848_CAP_CTL_CAPTURE_VBI_EVEN (1<<2)
+#define BT848_CAP_CTL_CAPTURE_ODD      (1<<1)
+#define BT848_CAP_CTL_CAPTURE_EVEN     (1<<0)
+
+#define BT848_VBI_PACK_SIZE    0x0E0
+
+#define BT848_VBI_PACK_DEL     0x0E4
+#define BT848_VBI_PACK_DEL_VBI_HDELAY 0xfc
+#define BT848_VBI_PACK_DEL_EXT_FRAME  2
+#define BT848_VBI_PACK_DEL_VBI_PKT_HI 1
+
+
+#define BT848_INT_STAT         0x100
+#define BT848_INT_MASK         0x104
+
+#define BT848_INT_ETBF         (1<<23)
+
+#define BT848_INT_RISCS   (0xf<<28)
+#define BT848_INT_RISC_EN (1<<27)
+#define BT848_INT_RACK    (1<<25)
+#define BT848_INT_FIELD   (1<<24)
+#define BT848_INT_SCERR   (1<<19)
+#define BT848_INT_OCERR   (1<<18)
+#define BT848_INT_PABORT  (1<<17)
+#define BT848_INT_RIPERR  (1<<16)
+#define BT848_INT_PPERR   (1<<15)
+#define BT848_INT_FDSR    (1<<14)
+#define BT848_INT_FTRGT   (1<<13)
+#define BT848_INT_FBUS    (1<<12)
+#define BT848_INT_RISCI   (1<<11)
+#define BT848_INT_GPINT   (1<<9)
+#define BT848_INT_I2CDONE (1<<8)
+#define BT848_INT_VPRES   (1<<5)
+#define BT848_INT_HLOCK   (1<<4)
+#define BT848_INT_OFLOW   (1<<3)
+#define BT848_INT_HSYNC   (1<<2)
+#define BT848_INT_VSYNC   (1<<1)
+#define BT848_INT_FMTCHG  (1<<0)
+
+
+#define BT848_GPIO_DMA_CTL             0x10C
+#define BT848_GPIO_DMA_CTL_GPINTC      (1<<15)
+#define BT848_GPIO_DMA_CTL_GPINTI      (1<<14)
+#define BT848_GPIO_DMA_CTL_GPWEC       (1<<13)
+#define BT848_GPIO_DMA_CTL_GPIOMODE    (3<<11)
+#define BT848_GPIO_DMA_CTL_GPCLKMODE   (1<<10)
+#define BT848_GPIO_DMA_CTL_PLTP23_4    (0<<6)
+#define BT848_GPIO_DMA_CTL_PLTP23_8    (1<<6)
+#define BT848_GPIO_DMA_CTL_PLTP23_16   (2<<6)
+#define BT848_GPIO_DMA_CTL_PLTP23_32   (3<<6)
+#define BT848_GPIO_DMA_CTL_PLTP1_4     (0<<4)
+#define BT848_GPIO_DMA_CTL_PLTP1_8     (1<<4)
+#define BT848_GPIO_DMA_CTL_PLTP1_16    (2<<4)
+#define BT848_GPIO_DMA_CTL_PLTP1_32    (3<<4)
+#define BT848_GPIO_DMA_CTL_PKTP_4      (0<<2)
+#define BT848_GPIO_DMA_CTL_PKTP_8      (1<<2)
+#define BT848_GPIO_DMA_CTL_PKTP_16     (2<<2)
+#define BT848_GPIO_DMA_CTL_PKTP_32     (3<<2)
+#define BT848_GPIO_DMA_CTL_RISC_ENABLE (1<<1)
+#define BT848_GPIO_DMA_CTL_FIFO_ENABLE (1<<0)
+
+#define BT848_I2C              0x110
+#define BT878_I2C_MODE         (1<<7)
+#define BT878_I2C_RATE         (1<<6)
+#define BT878_I2C_NOSTOP       (1<<5)
+#define BT878_I2C_NOSTART      (1<<4)
+#define BT848_I2C_DIV          (0xf<<4)
+#define BT848_I2C_SYNC         (1<<3)
+#define BT848_I2C_W3B	       (1<<2)
+#define BT848_I2C_SCL          (1<<1)
+#define BT848_I2C_SDA          (1<<0)
+
+#define BT848_RISC_STRT_ADD    0x114
+#define BT848_GPIO_OUT_EN      0x118
+#define BT848_GPIO_REG_INP     0x11C
+#define BT848_RISC_COUNT       0x120
+#define BT848_GPIO_DATA        0x200
+
+
+/* Bt848 RISC commands */
+
+/* only for the SYNC RISC command */
+#define BT848_FIFO_STATUS_FM1  0x06
+#define BT848_FIFO_STATUS_FM3  0x0e
+#define BT848_FIFO_STATUS_SOL  0x02
+#define BT848_FIFO_STATUS_EOL4 0x01
+#define BT848_FIFO_STATUS_EOL3 0x0d
+#define BT848_FIFO_STATUS_EOL2 0x09
+#define BT848_FIFO_STATUS_EOL1 0x05
+#define BT848_FIFO_STATUS_VRE  0x04
+#define BT848_FIFO_STATUS_VRO  0x0c
+#define BT848_FIFO_STATUS_PXV  0x00
+
+#define BT848_RISC_RESYNC      (1<<15)
+
+/* WRITE and SKIP */
+/* disable which bytes of each DWORD */
+#define BT848_RISC_BYTE0       (1U<<12)
+#define BT848_RISC_BYTE1       (1U<<13)
+#define BT848_RISC_BYTE2       (1U<<14)
+#define BT848_RISC_BYTE3       (1U<<15)
+#define BT848_RISC_BYTE_ALL    (0x0fU<<12)
+#define BT848_RISC_BYTE_NONE   0
+/* cause RISCI */
+#define BT848_RISC_IRQ         (1U<<24)
+/* RISC command is last one in this line */
+#define BT848_RISC_EOL         (1U<<26)
+/* RISC command is first one in this line */
+#define BT848_RISC_SOL         (1U<<27)
+
+#define BT848_RISC_WRITE       (0x01U<<28)
+#define BT848_RISC_SKIP        (0x02U<<28)
+#define BT848_RISC_WRITEC      (0x05U<<28)
+#define BT848_RISC_JUMP        (0x07U<<28)
+#define BT848_RISC_SYNC        (0x08U<<28)
+
+#define BT848_RISC_WRITE123    (0x09U<<28)
+#define BT848_RISC_SKIP123     (0x0aU<<28)
+#define BT848_RISC_WRITE1S23   (0x0bU<<28)
+
+
+/* Bt848A and higher only !! */
+#define BT848_TGLB             0x080
+#define BT848_TGCTRL           0x084
+#define BT848_FCAP             0x0E8
+#define BT848_PLL_F_LO         0x0F0
+#define BT848_PLL_F_HI         0x0F4
+
+#define BT848_PLL_XCI          0x0F8
+#define BT848_PLL_X            (1<<7)
+#define BT848_PLL_C            (1<<6)
+
+#define BT848_DVSIF            0x0FC
+
+/* Bt878 register */
+
+#define BT878_DEVCTRL 0x40
+#define BT878_EN_TBFX 0x02
+#define BT878_EN_VSFX 0x04
+
+#endif
diff --git a/drivers/media/pci/bt8xx/bt878.c b/drivers/media/pci/bt8xx/bt878.c
new file mode 100644
index 0000000..b34fa95
--- /dev/null
+++ b/drivers/media/pci/bt8xx/bt878.c
@@ -0,0 +1,609 @@
+/*
+ * bt878.c: part of the driver for the Pinnacle PCTV Sat DVB PCI card
+ *
+ * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de>
+ *
+ * large parts based on the bttv driver
+ * Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@metzlerbros.de)
+ *                        & Marcus Metzler (mocm@metzlerbros.de)
+ * (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <linux/ioport.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/kmod.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "bt878.h"
+#include "dst_priv.h"
+
+
+/**************************************/
+/* Miscellaneous utility  definitions */
+/**************************************/
+
+static unsigned int bt878_verbose = 1;
+static unsigned int bt878_debug;
+
+module_param_named(verbose, bt878_verbose, int, 0444);
+MODULE_PARM_DESC(verbose,
+		 "verbose startup messages, default is 1 (yes)");
+module_param_named(debug, bt878_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off).");
+
+int bt878_num;
+struct bt878 bt878[BT878_MAX];
+
+EXPORT_SYMBOL(bt878_num);
+EXPORT_SYMBOL(bt878);
+
+#define btwrite(dat,adr)    bmtwrite((dat), (bt->bt878_mem+(adr)))
+#define btread(adr)         bmtread(bt->bt878_mem+(adr))
+
+#define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
+#define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
+#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
+
+#if defined(dprintk)
+#undef dprintk
+#endif
+#define dprintk(fmt, arg...) \
+	do { \
+		if (bt878_debug) \
+			printk(KERN_DEBUG fmt, ##arg); \
+	} while (0)
+
+static void bt878_mem_free(struct bt878 *bt)
+{
+	if (bt->buf_cpu) {
+		pci_free_consistent(bt->dev, bt->buf_size, bt->buf_cpu,
+				    bt->buf_dma);
+		bt->buf_cpu = NULL;
+	}
+
+	if (bt->risc_cpu) {
+		pci_free_consistent(bt->dev, bt->risc_size, bt->risc_cpu,
+				    bt->risc_dma);
+		bt->risc_cpu = NULL;
+	}
+}
+
+static int bt878_mem_alloc(struct bt878 *bt)
+{
+	if (!bt->buf_cpu) {
+		bt->buf_size = 128 * 1024;
+
+		bt->buf_cpu =
+		    pci_alloc_consistent(bt->dev, bt->buf_size,
+					 &bt->buf_dma);
+
+		if (!bt->buf_cpu)
+			return -ENOMEM;
+
+		memset(bt->buf_cpu, 0, bt->buf_size);
+	}
+
+	if (!bt->risc_cpu) {
+		bt->risc_size = PAGE_SIZE;
+		bt->risc_cpu =
+		    pci_alloc_consistent(bt->dev, bt->risc_size,
+					 &bt->risc_dma);
+
+		if (!bt->risc_cpu) {
+			bt878_mem_free(bt);
+			return -ENOMEM;
+		}
+
+		memset(bt->risc_cpu, 0, bt->risc_size);
+	}
+
+	return 0;
+}
+
+/* RISC instructions */
+#define RISC_WRITE		(0x01 << 28)
+#define RISC_JUMP		(0x07 << 28)
+#define RISC_SYNC		(0x08 << 28)
+
+/* RISC bits */
+#define RISC_WR_SOL		(1 << 27)
+#define RISC_WR_EOL		(1 << 26)
+#define RISC_IRQ		(1 << 24)
+#define RISC_STATUS(status)	((((~status) & 0x0F) << 20) | ((status & 0x0F) << 16))
+#define RISC_SYNC_RESYNC	(1 << 15)
+#define RISC_SYNC_FM1		0x06
+#define RISC_SYNC_VRO		0x0C
+
+#define RISC_FLUSH()		bt->risc_pos = 0
+#define RISC_INSTR(instr)	bt->risc_cpu[bt->risc_pos++] = cpu_to_le32(instr)
+
+static int bt878_make_risc(struct bt878 *bt)
+{
+	bt->block_bytes = bt->buf_size >> 4;
+	bt->block_count = 1 << 4;
+	bt->line_bytes = bt->block_bytes;
+	bt->line_count = bt->block_count;
+
+	while (bt->line_bytes > 4095) {
+		bt->line_bytes >>= 1;
+		bt->line_count <<= 1;
+	}
+
+	if (bt->line_count > 255) {
+		printk(KERN_ERR "bt878: buffer size error!\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+static void bt878_risc_program(struct bt878 *bt, u32 op_sync_orin)
+{
+	u32 buf_pos = 0;
+	u32 line;
+
+	RISC_FLUSH();
+	RISC_INSTR(RISC_SYNC | RISC_SYNC_FM1 | op_sync_orin);
+	RISC_INSTR(0);
+
+	dprintk("bt878: risc len lines %u, bytes per line %u\n",
+			bt->line_count, bt->line_bytes);
+	for (line = 0; line < bt->line_count; line++) {
+		// At the beginning of every block we issue an IRQ with previous (finished) block number set
+		if (!(buf_pos % bt->block_bytes))
+			RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL |
+				   RISC_IRQ |
+				   RISC_STATUS(((buf_pos /
+						 bt->block_bytes) +
+						(bt->block_count -
+						 1)) %
+					       bt->block_count) | bt->
+				   line_bytes);
+		else
+			RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL |
+				   bt->line_bytes);
+		RISC_INSTR(bt->buf_dma + buf_pos);
+		buf_pos += bt->line_bytes;
+	}
+
+	RISC_INSTR(RISC_SYNC | op_sync_orin | RISC_SYNC_VRO);
+	RISC_INSTR(0);
+
+	RISC_INSTR(RISC_JUMP);
+	RISC_INSTR(bt->risc_dma);
+
+	btwrite((bt->line_count << 16) | bt->line_bytes, BT878_APACK_LEN);
+}
+
+/*****************************/
+/* Start/Stop grabbing funcs */
+/*****************************/
+
+void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin,
+		u32 irq_err_ignore)
+{
+	u32 int_mask;
+
+	dprintk("bt878 debug: bt878_start (ctl=%8.8x)\n", controlreg);
+	/* complete the writing of the risc dma program now we have
+	 * the card specifics
+	 */
+	bt878_risc_program(bt, op_sync_orin);
+	controlreg &= ~0x1f;
+	controlreg |= 0x1b;
+
+	btwrite(bt->risc_dma, BT878_ARISC_START);
+
+	/* original int mask had :
+	 *    6    2    8    4    0
+	 * 1111 1111 1000 0000 0000
+	 * SCERR|OCERR|PABORT|RIPERR|FDSR|FTRGT|FBUS|RISCI
+	 * Hacked for DST to:
+	 * SCERR | OCERR | FDSR | FTRGT | FBUS | RISCI
+	 */
+	int_mask = BT878_ASCERR | BT878_AOCERR | BT878_APABORT |
+		BT878_ARIPERR | BT878_APPERR | BT878_AFDSR | BT878_AFTRGT |
+		BT878_AFBUS | BT878_ARISCI;
+
+
+	/* ignore pesky bits */
+	int_mask &= ~irq_err_ignore;
+
+	btwrite(int_mask, BT878_AINT_MASK);
+	btwrite(controlreg, BT878_AGPIO_DMA_CTL);
+}
+
+void bt878_stop(struct bt878 *bt)
+{
+	u32 stat;
+	int i = 0;
+
+	dprintk("bt878 debug: bt878_stop\n");
+
+	btwrite(0, BT878_AINT_MASK);
+	btand(~0x13, BT878_AGPIO_DMA_CTL);
+
+	do {
+		stat = btread(BT878_AINT_STAT);
+		if (!(stat & BT878_ARISC_EN))
+			break;
+		i++;
+	} while (i < 500);
+
+	dprintk("bt878(%d) debug: bt878_stop, i=%d, stat=0x%8.8x\n",
+		bt->nr, i, stat);
+}
+
+EXPORT_SYMBOL(bt878_start);
+EXPORT_SYMBOL(bt878_stop);
+
+/*****************************/
+/* Interrupt service routine */
+/*****************************/
+
+static irqreturn_t bt878_irq(int irq, void *dev_id)
+{
+	u32 stat, astat, mask;
+	int count;
+	struct bt878 *bt;
+
+	bt = (struct bt878 *) dev_id;
+
+	count = 0;
+	while (1) {
+		stat = btread(BT878_AINT_STAT);
+		mask = btread(BT878_AINT_MASK);
+		if (!(astat = (stat & mask)))
+			return IRQ_NONE;	/* this interrupt is not for me */
+/*		dprintk("bt878(%d) debug: irq count %d, stat 0x%8.8x, mask 0x%8.8x\n",bt->nr,count,stat,mask); */
+		btwrite(astat, BT878_AINT_STAT);	/* try to clear interrupt condition */
+
+
+		if (astat & (BT878_ASCERR | BT878_AOCERR)) {
+			if (bt878_verbose) {
+				printk(KERN_INFO
+				       "bt878(%d): irq%s%s risc_pc=%08x\n",
+				       bt->nr,
+				       (astat & BT878_ASCERR) ? " SCERR" :
+				       "",
+				       (astat & BT878_AOCERR) ? " OCERR" :
+				       "", btread(BT878_ARISC_PC));
+			}
+		}
+		if (astat & (BT878_APABORT | BT878_ARIPERR | BT878_APPERR)) {
+			if (bt878_verbose) {
+				printk(KERN_INFO
+				     "bt878(%d): irq%s%s%s risc_pc=%08x\n",
+				     bt->nr,
+				     (astat & BT878_APABORT) ? " PABORT" :
+				     "",
+				     (astat & BT878_ARIPERR) ? " RIPERR" :
+				     "",
+				     (astat & BT878_APPERR) ? " PPERR" :
+				     "", btread(BT878_ARISC_PC));
+			}
+		}
+		if (astat & (BT878_AFDSR | BT878_AFTRGT | BT878_AFBUS)) {
+			if (bt878_verbose) {
+				printk(KERN_INFO
+				     "bt878(%d): irq%s%s%s risc_pc=%08x\n",
+				     bt->nr,
+				     (astat & BT878_AFDSR) ? " FDSR" : "",
+				     (astat & BT878_AFTRGT) ? " FTRGT" :
+				     "",
+				     (astat & BT878_AFBUS) ? " FBUS" : "",
+				     btread(BT878_ARISC_PC));
+			}
+		}
+		if (astat & BT878_ARISCI) {
+			bt->finished_block = (stat & BT878_ARISCS) >> 28;
+			tasklet_schedule(&bt->tasklet);
+			break;
+		}
+		count++;
+		if (count > 20) {
+			btwrite(0, BT878_AINT_MASK);
+			printk(KERN_ERR
+			       "bt878(%d): IRQ lockup, cleared int mask\n",
+			       bt->nr);
+			break;
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+int
+bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp)
+{
+	int retval;
+
+	retval = 0;
+	if (mutex_lock_interruptible(&bt->gpio_lock))
+		return -ERESTARTSYS;
+	/* special gpio signal */
+	switch (cmd) {
+	    case DST_IG_ENABLE:
+		// dprintk("dvb_bt8xx: dst enable mask 0x%02x enb 0x%02x \n", mp->dstg.enb.mask, mp->dstg.enb.enable);
+		retval = bttv_gpio_enable(bt->bttv_nr,
+				mp->enb.mask,
+				mp->enb.enable);
+		break;
+	    case DST_IG_WRITE:
+		// dprintk("dvb_bt8xx: dst write gpio mask 0x%02x out 0x%02x\n", mp->dstg.outp.mask, mp->dstg.outp.highvals);
+		retval = bttv_write_gpio(bt->bttv_nr,
+				mp->outp.mask,
+				mp->outp.highvals);
+
+		break;
+	    case DST_IG_READ:
+		/* read */
+		retval =  bttv_read_gpio(bt->bttv_nr, &mp->rd.value);
+		// dprintk("dvb_bt8xx: dst read gpio 0x%02x\n", (unsigned)mp->dstg.rd.value);
+		break;
+	    case DST_IG_TS:
+		/* Set packet size */
+		bt->TS_Size = mp->psize;
+		break;
+
+	    default:
+		retval = -EINVAL;
+		break;
+	}
+	mutex_unlock(&bt->gpio_lock);
+	return retval;
+}
+
+EXPORT_SYMBOL(bt878_device_control);
+
+#define BROOKTREE_878_DEVICE(vend, dev, name) \
+	{ \
+		.vendor = PCI_VENDOR_ID_BROOKTREE, \
+		.device = PCI_DEVICE_ID_BROOKTREE_878, \
+		.subvendor = (vend), .subdevice = (dev), \
+		.driver_data = (unsigned long) name \
+	}
+
+static struct pci_device_id bt878_pci_tbl[] __devinitdata = {
+	BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"),
+	BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"),
+	BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"),
+	BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"),
+	BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"),
+	BROOKTREE_878_DEVICE(0x270f, 0xfc00,
+				"ChainTech digitop DST-1000 DVB-S"),
+	BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"),
+	BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"),
+	BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"),
+	BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"),
+	BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"),
+	BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"),
+	{ }
+};
+
+MODULE_DEVICE_TABLE(pci, bt878_pci_tbl);
+
+static const char * __devinit card_name(const struct pci_device_id *id)
+{
+	return id->driver_data ? (const char *)id->driver_data : "Unknown";
+}
+
+/***********************/
+/* PCI device handling */
+/***********************/
+
+static int __devinit bt878_probe(struct pci_dev *dev,
+				 const struct pci_device_id *pci_id)
+{
+	int result = 0;
+	unsigned char lat;
+	struct bt878 *bt;
+#if defined(__powerpc__)
+	unsigned int cmd;
+#endif
+	unsigned int cardid;
+
+	printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n",
+	       bt878_num);
+	if (bt878_num >= BT878_MAX) {
+		printk(KERN_ERR "bt878: Too many devices inserted\n");
+		result = -ENOMEM;
+		goto fail0;
+	}
+	if (pci_enable_device(dev))
+		return -EIO;
+
+	cardid = dev->subsystem_device << 16;
+	cardid |= dev->subsystem_vendor;
+
+	printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n",
+				__func__, cardid, card_name(pci_id));
+
+	bt = &bt878[bt878_num];
+	bt->dev = dev;
+	bt->nr = bt878_num;
+	bt->shutdown = 0;
+
+	bt->id = dev->device;
+	bt->irq = dev->irq;
+	bt->bt878_adr = pci_resource_start(dev, 0);
+	if (!request_mem_region(pci_resource_start(dev, 0),
+				pci_resource_len(dev, 0), "bt878")) {
+		result = -EBUSY;
+		goto fail0;
+	}
+
+	bt->revision = dev->revision;
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+
+
+	printk(KERN_INFO "bt878(%d): Bt%x (rev %d) at %02x:%02x.%x, ",
+	       bt878_num, bt->id, bt->revision, dev->bus->number,
+	       PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+	printk("irq: %d, latency: %d, memory: 0x%lx\n",
+	       bt->irq, lat, bt->bt878_adr);
+
+
+#if defined(__powerpc__)
+	/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
+	/* response on cards with no firmware is not enabled by OF */
+	pci_read_config_dword(dev, PCI_COMMAND, &cmd);
+	cmd = (cmd | PCI_COMMAND_MEMORY);
+	pci_write_config_dword(dev, PCI_COMMAND, cmd);
+#endif
+
+#ifdef __sparc__
+	bt->bt878_mem = (unsigned char *) bt->bt878_adr;
+#else
+	bt->bt878_mem = ioremap(bt->bt878_adr, 0x1000);
+#endif
+
+	/* clear interrupt mask */
+	btwrite(0, BT848_INT_MASK);
+
+	result = request_irq(bt->irq, bt878_irq,
+			     IRQF_SHARED | IRQF_DISABLED, "bt878",
+			     (void *) bt);
+	if (result == -EINVAL) {
+		printk(KERN_ERR "bt878(%d): Bad irq number or handler\n",
+		       bt878_num);
+		goto fail1;
+	}
+	if (result == -EBUSY) {
+		printk(KERN_ERR
+		       "bt878(%d): IRQ %d busy, change your PnP config in BIOS\n",
+		       bt878_num, bt->irq);
+		goto fail1;
+	}
+	if (result < 0)
+		goto fail1;
+
+	pci_set_master(dev);
+	pci_set_drvdata(dev, bt);
+
+	if ((result = bt878_mem_alloc(bt))) {
+		printk(KERN_ERR "bt878: failed to allocate memory!\n");
+		goto fail2;
+	}
+
+	bt878_make_risc(bt);
+	btwrite(0, BT878_AINT_MASK);
+	bt878_num++;
+
+	return 0;
+
+      fail2:
+	free_irq(bt->irq, bt);
+      fail1:
+	release_mem_region(pci_resource_start(bt->dev, 0),
+			   pci_resource_len(bt->dev, 0));
+      fail0:
+	pci_disable_device(dev);
+	return result;
+}
+
+static void __devexit bt878_remove(struct pci_dev *pci_dev)
+{
+	u8 command;
+	struct bt878 *bt = pci_get_drvdata(pci_dev);
+
+	if (bt878_verbose)
+		printk(KERN_INFO "bt878(%d): unloading\n", bt->nr);
+
+	/* turn off all capturing, DMA and IRQs */
+	btand(~0x13, BT878_AGPIO_DMA_CTL);
+
+	/* first disable interrupts before unmapping the memory! */
+	btwrite(0, BT878_AINT_MASK);
+	btwrite(~0U, BT878_AINT_STAT);
+
+	/* disable PCI bus-mastering */
+	pci_read_config_byte(bt->dev, PCI_COMMAND, &command);
+	/* Should this be &=~ ?? */
+	command &= ~PCI_COMMAND_MASTER;
+	pci_write_config_byte(bt->dev, PCI_COMMAND, command);
+
+	free_irq(bt->irq, bt);
+	printk(KERN_DEBUG "bt878_mem: 0x%p.\n", bt->bt878_mem);
+	if (bt->bt878_mem)
+		iounmap(bt->bt878_mem);
+
+	release_mem_region(pci_resource_start(bt->dev, 0),
+			   pci_resource_len(bt->dev, 0));
+	/* wake up any waiting processes
+	   because shutdown flag is set, no new processes (in this queue)
+	   are expected
+	 */
+	bt->shutdown = 1;
+	bt878_mem_free(bt);
+
+	pci_set_drvdata(pci_dev, NULL);
+	pci_disable_device(pci_dev);
+	return;
+}
+
+static struct pci_driver bt878_pci_driver = {
+      .name	= "bt878",
+      .id_table = bt878_pci_tbl,
+      .probe	= bt878_probe,
+      .remove	= __devexit_p(bt878_remove),
+};
+
+/*******************************/
+/* Module management functions */
+/*******************************/
+
+static int __init bt878_init_module(void)
+{
+	bt878_num = 0;
+
+	printk(KERN_INFO "bt878: AUDIO driver version %d.%d.%d loaded\n",
+	       (BT878_VERSION_CODE >> 16) & 0xff,
+	       (BT878_VERSION_CODE >> 8) & 0xff,
+	       BT878_VERSION_CODE & 0xff);
+
+	return pci_register_driver(&bt878_pci_driver);
+}
+
+static void __exit bt878_cleanup_module(void)
+{
+	pci_unregister_driver(&bt878_pci_driver);
+}
+
+module_init(bt878_init_module);
+module_exit(bt878_cleanup_module);
+
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/bt8xx/bt878.h b/drivers/media/pci/bt8xx/bt878.h
new file mode 100644
index 0000000..d19b592
--- /dev/null
+++ b/drivers/media/pci/bt8xx/bt878.h
@@ -0,0 +1,159 @@
+/*
+    bt878.h - Bt878 audio module (register offsets)
+
+    Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _BT878_H_
+#define _BT878_H_
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+
+#include "bt848.h"
+#include "bttv.h"
+
+#define BT878_VERSION_CODE 0x000000
+
+#define BT878_AINT_STAT		0x100
+#define BT878_ARISCS		(0xf<<28)
+#define BT878_ARISC_EN		(1<<27)
+#define BT878_ASCERR		(1<<19)
+#define BT878_AOCERR		(1<<18)
+#define BT878_APABORT		(1<<17)
+#define BT878_ARIPERR		(1<<16)
+#define BT878_APPERR		(1<<15)
+#define BT878_AFDSR		(1<<14)
+#define BT878_AFTRGT		(1<<13)
+#define BT878_AFBUS		(1<<12)
+#define BT878_ARISCI		(1<<11)
+#define BT878_AOFLOW		(1<<3)
+
+#define BT878_AINT_MASK		0x104
+
+#define BT878_AGPIO_DMA_CTL	0x10c
+#define BT878_A_GAIN		(0xf<<28)
+#define BT878_A_G2X		(1<<27)
+#define BT878_A_PWRDN		(1<<26)
+#define BT878_A_SEL		(3<<24)
+#define BT878_DA_SCE		(1<<23)
+#define BT878_DA_LRI		(1<<22)
+#define BT878_DA_MLB		(1<<21)
+#define BT878_DA_LRD		(0x1f<<16)
+#define BT878_DA_DPM		(1<<15)
+#define BT878_DA_SBR		(1<<14)
+#define BT878_DA_ES2		(1<<13)
+#define BT878_DA_LMT		(1<<12)
+#define BT878_DA_SDR		(0xf<<8)
+#define BT878_DA_IOM		(3<<6)
+#define BT878_DA_APP		(1<<5)
+#define BT878_ACAP_EN		(1<<4)
+#define BT878_PKTP		(3<<2)
+#define BT878_RISC_EN		(1<<1)
+#define BT878_FIFO_EN		1
+
+#define BT878_APACK_LEN		0x110
+#define BT878_AFP_LEN		(0xff<<16)
+#define BT878_ALP_LEN		0xfff
+
+#define BT878_ARISC_START	0x114
+
+#define BT878_ARISC_PC		0x120
+
+/* BT878 FUNCTION 0 REGISTERS */
+#define BT878_GPIO_DMA_CTL	0x10c
+
+/* Interrupt register */
+#define BT878_INT_STAT		0x100
+#define BT878_INT_MASK		0x104
+#define BT878_I2CRACK		(1<<25)
+#define BT878_I2CDONE		(1<<8)
+
+#define BT878_MAX 4
+
+#define BT878_RISC_SYNC_MASK	(1 << 15)
+
+
+#define BTTV_BOARD_UNKNOWN                 0x00
+#define BTTV_BOARD_PINNACLESAT             0x5e
+#define BTTV_BOARD_NEBULA_DIGITV           0x68
+#define BTTV_BOARD_PC_HDTV                 0x70
+#define BTTV_BOARD_TWINHAN_DST             0x71
+#define BTTV_BOARD_AVDVBT_771              0x7b
+#define BTTV_BOARD_AVDVBT_761              0x7c
+#define BTTV_BOARD_DVICO_DVBT_LITE         0x80
+#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87
+
+extern int bt878_num;
+
+struct bt878 {
+	struct mutex gpio_lock;
+	unsigned int nr;
+	unsigned int bttv_nr;
+	struct i2c_adapter *adapter;
+	struct pci_dev *dev;
+	unsigned int id;
+	unsigned int TS_Size;
+	unsigned char revision;
+	unsigned int irq;
+	unsigned long bt878_adr;
+	volatile void __iomem *bt878_mem; /* function 1 */
+
+	volatile u32 finished_block;
+	volatile u32 last_block;
+	u32 block_count;
+	u32 block_bytes;
+	u32 line_bytes;
+	u32 line_count;
+
+	u32 buf_size;
+	u8 *buf_cpu;
+	dma_addr_t buf_dma;
+
+	u32 risc_size;
+	__le32 *risc_cpu;
+	dma_addr_t risc_dma;
+	u32 risc_pos;
+
+	struct tasklet_struct tasklet;
+	int shutdown;
+};
+
+extern struct bt878 bt878[BT878_MAX];
+
+void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin,
+		u32 irq_err_ignore);
+void bt878_stop(struct bt878 *bt);
+
+#if defined(__powerpc__)	/* big-endian */
+static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val)
+{
+	st_le32(addr, val);
+	eieio();
+}
+
+#define bmtwrite(dat,adr)  io_st_le32((adr),(dat))
+#define bmtread(adr)       ld_le32((adr))
+#else
+#define bmtwrite(dat,adr)  writel((dat), (adr))
+#define bmtread(adr)       readl(adr)
+#endif
+
+#endif
diff --git a/drivers/media/pci/bt8xx/bttv-audio-hook.c b/drivers/media/pci/bt8xx/bttv-audio-hook.c
new file mode 100644
index 0000000..2364d16
--- /dev/null
+++ b/drivers/media/pci/bt8xx/bttv-audio-hook.c
@@ -0,0 +1,382 @@
+/*
+ * Handlers for board audio hooks, splitted from bttv-cards
+ *
+ * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License
+ */
+
+#include "bttv-audio-hook.h"
+
+#include <linux/delay.h>
+
+/* ----------------------------------------------------------------------- */
+/* winview                                                                 */
+
+void winview_volume(struct bttv *btv, __u16 volume)
+{
+	/* PT2254A programming Jon Tombs, jon@gte.esi.us.es */
+	int bits_out, loops, vol, data;
+
+	/* 32 levels logarithmic */
+	vol = 32 - ((volume>>11));
+	/* units */
+	bits_out = (PT2254_DBS_IN_2>>(vol%5));
+	/* tens */
+	bits_out |= (PT2254_DBS_IN_10>>(vol/5));
+	bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL;
+	data = gpio_read();
+	data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
+		  WINVIEW_PT2254_STROBE);
+	for (loops = 17; loops >= 0 ; loops--) {
+		if (bits_out & (1<<loops))
+			data |=  WINVIEW_PT2254_DATA;
+		else
+			data &= ~WINVIEW_PT2254_DATA;
+		gpio_write(data);
+		udelay(5);
+		data |= WINVIEW_PT2254_CLK;
+		gpio_write(data);
+		udelay(5);
+		data &= ~WINVIEW_PT2254_CLK;
+		gpio_write(data);
+	}
+	data |=  WINVIEW_PT2254_STROBE;
+	data &= ~WINVIEW_PT2254_DATA;
+	gpio_write(data);
+	udelay(10);
+	data &= ~WINVIEW_PT2254_STROBE;
+	gpio_write(data);
+}
+
+/* ----------------------------------------------------------------------- */
+/* mono/stereo control for various cards (which don't use i2c chips but    */
+/* connect something to the GPIO pins                                      */
+
+void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned int con = 0;
+
+	if (set) {
+		gpio_inout(0x300, 0x300);
+		if (t->audmode & V4L2_TUNER_MODE_LANG1)
+			con = 0x000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)
+			con = 0x300;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
+			con = 0x200;
+/*		if (t->audmode & V4L2_TUNER_MODE_MONO)
+ *			con = 0x100; */
+		gpio_bits(0x300, con);
+	} else {
+		t->audmode = V4L2_TUNER_MODE_STEREO |
+			  V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned int val, con;
+
+	if (btv->radio_user)
+		return;
+
+	val = gpio_read();
+	if (set) {
+		con = 0x000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG2) {
+			if (t->audmode & V4L2_TUNER_MODE_LANG1) {
+				/* LANG1 + LANG2 */
+				con = 0x100;
+			}
+			else {
+				/* LANG2 */
+				con = 0x300;
+			}
+		}
+		if (con != (val & 0x300)) {
+			gpio_bits(0x300, con);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"gvbctv5pci");
+		}
+	} else {
+		switch (val & 0x70) {
+		  case 0x10:
+			t->rxsubchans = V4L2_TUNER_SUB_LANG1 |  V4L2_TUNER_SUB_LANG2;
+			break;
+		  case 0x30:
+			t->rxsubchans = V4L2_TUNER_SUB_LANG2;
+			break;
+		  case 0x50:
+			t->rxsubchans = V4L2_TUNER_SUB_LANG1;
+			break;
+		  case 0x60:
+			t->rxsubchans = V4L2_TUNER_SUB_STEREO;
+			break;
+		  case 0x70:
+			t->rxsubchans = V4L2_TUNER_SUB_MONO;
+			break;
+		  default:
+			t->rxsubchans = V4L2_TUNER_SUB_MONO |
+					 V4L2_TUNER_SUB_STEREO |
+					 V4L2_TUNER_SUB_LANG1 |
+					 V4L2_TUNER_SUB_LANG2;
+		}
+		t->audmode = V4L2_TUNER_MODE_STEREO |
+			  V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+/*
+ * Mario Medina Nussbaum <medisoft@alohabbs.org.mx>
+ *  I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo,
+ *  0xdde enables mono and 0xccd enables sap
+ *
+ * Petr Vandrovec <VANDROVE@vc.cvut.cz>
+ *  P.S.: At least mask in line above is wrong - GPIO pins 3,2 select
+ *  input/output sound connection, so both must be set for output mode.
+ *
+ * Looks like it's needed only for the "tvphone", the "tvphone 98"
+ * handles this with a tda9840
+ *
+ */
+
+void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	int val = 0;
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)   /* SAP */
+			val = 0x02;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
+			val = 0x01;
+		if (val) {
+			gpio_bits(0x03,val);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"avermedia");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1;
+		return;
+	}
+}
+
+
+void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	int val = 0;
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)   /* SAP */
+			val = 0x01;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)  /* STEREO */
+			val = 0x02;
+		btaor(val, ~0x03, BT848_GPIO_DATA);
+		if (bttv_gpio)
+			bttv_gpio_tracking(btv,"avermedia");
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+		return;
+	}
+}
+
+/* Lifetec 9415 handling */
+
+void lt9415_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	int val = 0;
+
+	if (gpio_read() & 0x4000) {
+		t->audmode = V4L2_TUNER_MODE_MONO;
+		return;
+	}
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)  /* A2 SAP */
+			val = 0x0080;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO) /* A2 stereo */
+			val = 0x0880;
+		if ((t->audmode & V4L2_TUNER_MODE_LANG1) ||
+		    (t->audmode & V4L2_TUNER_MODE_MONO))
+			val = 0;
+		gpio_bits(0x0880, val);
+		if (bttv_gpio)
+			bttv_gpio_tracking(btv,"lt9415");
+	} else {
+		/* autodetect doesn't work with this card :-( */
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+		return;
+	}
+}
+
+/* TDA9821 on TerraTV+ Bt848, Bt878 */
+void terratv_audio(struct bttv *btv,  struct v4l2_tuner *t, int set)
+{
+	unsigned int con = 0;
+
+	if (set) {
+		gpio_inout(0x180000,0x180000);
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)
+			con = 0x080000;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
+			con = 0x180000;
+		gpio_bits(0x180000, con);
+		if (bttv_gpio)
+			bttv_gpio_tracking(btv,"terratv");
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+
+void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned long val = 0;
+
+	if (set) {
+		/*btor (0xc32000, BT848_GPIO_OUT_EN);*/
+		if (t->audmode & V4L2_TUNER_MODE_MONO)		/* Mono */
+			val = 0x420000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG1)	/* Mono */
+			val = 0x420000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)	/* SAP */
+			val = 0x410000;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)	/* Stereo */
+			val = 0x020000;
+		if (val) {
+			gpio_bits(0x430000, val);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"winfast2000");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			  V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+/*
+ * Dariusz Kowalewski <darekk@automex.pl>
+ * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM
+ * revision 9B has on-board TDA9874A sound decoder).
+ *
+ * Note: There are card variants without tda9874a. Forcing the "stereo sound route"
+ *       will mute this cards.
+ */
+void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned int val = 0;
+
+	if (btv->radio_user)
+		return;
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_MONO)	{
+			val = 0x01;
+		}
+		if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2))
+		    || (t->audmode & V4L2_TUNER_MODE_STEREO)) {
+			val = 0x02;
+		}
+		if (val) {
+			gpio_bits(0x03,val);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"pvbt878p9b");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+/*
+ * Dariusz Kowalewski <darekk@automex.pl>
+ * sound control for FlyVideo 2000S (with tda9874 decoder)
+ * based on pvbt878p9b_audio() - this is not tested, please fix!!!
+ */
+void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned int val = 0xffff;
+
+	if (btv->radio_user)
+		return;
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_MONO)	{
+			val = 0x0000;
+		}
+		if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2))
+		    || (t->audmode & V4L2_TUNER_MODE_STEREO)) {
+			val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */
+		}
+		if (val != 0xffff) {
+			gpio_bits(0x1800, val);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"fv2000s");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+/*
+ * sound control for Canopus WinDVR PCI
+ * Masaki Suzuki <masaki@btree.org>
+ */
+void windvr_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned long val = 0;
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_MONO)
+			val = 0x040000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG1)
+			val = 0;
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)
+			val = 0x100000;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
+			val = 0;
+		if (val) {
+			gpio_bits(0x140000, val);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"windvr");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			  V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+/*
+ * sound control for AD-TVK503
+ * Hiroshi Takekawa <sian@big.or.jp>
+ */
+void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned int con = 0xffffff;
+
+	/* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */
+
+	if (set) {
+		/* btor(***, BT848_GPIO_OUT_EN); */
+		if (t->audmode & V4L2_TUNER_MODE_LANG1)
+			con = 0x00000000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)
+			con = 0x00180000;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
+			con = 0x00000000;
+		if (t->audmode & V4L2_TUNER_MODE_MONO)
+			con = 0x00060000;
+		if (con != 0xffffff) {
+			gpio_bits(0x1e0000,con);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv, "adtvk503");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			  V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
+	}
+}
diff --git a/drivers/media/pci/bt8xx/bttv-audio-hook.h b/drivers/media/pci/bt8xx/bttv-audio-hook.h
new file mode 100644
index 0000000..159d07a
--- /dev/null
+++ b/drivers/media/pci/bt8xx/bttv-audio-hook.h
@@ -0,0 +1,23 @@
+/*
+ * Handlers for board audio hooks, splitted from bttv-cards
+ *
+ * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License
+ */
+
+#include "bttvp.h"
+
+void winview_volume (struct bttv *btv, __u16 volume);
+
+void lt9415_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void terratv_audio(struct bttv *btv,  struct v4l2_tuner *tuner, int set);
+void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void windvr_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+
diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c
new file mode 100644
index 0000000..38952fa
--- /dev/null
+++ b/drivers/media/pci/bt8xx/bttv-cards.c
@@ -0,0 +1,4895 @@
+/*
+
+    bttv-cards.c
+
+    this file has configuration informations - card-specific stuff
+    like the big tvcards array for the most part
+
+    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+			   & Marcus Metzler (mocm@thp.uni-koeln.de)
+    (c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+#include <net/checksum.h>
+
+#include <asm/unaligned.h>
+#include <asm/io.h>
+
+#include "bttvp.h"
+#include <media/v4l2-common.h>
+#include <media/tvaudio.h>
+#include "bttv-audio-hook.h"
+
+/* fwd decl */
+static void boot_msp34xx(struct bttv *btv, int pin);
+static void hauppauge_eeprom(struct bttv *btv);
+static void avermedia_eeprom(struct bttv *btv);
+static void osprey_eeprom(struct bttv *btv, const u8 ee[256]);
+static void modtec_eeprom(struct bttv *btv);
+static void init_PXC200(struct bttv *btv);
+static void init_RTV24(struct bttv *btv);
+
+static void rv605_muxsel(struct bttv *btv, unsigned int input);
+static void eagle_muxsel(struct bttv *btv, unsigned int input);
+static void xguard_muxsel(struct bttv *btv, unsigned int input);
+static void ivc120_muxsel(struct bttv *btv, unsigned int input);
+static void gvc1100_muxsel(struct bttv *btv, unsigned int input);
+
+static void PXC200_muxsel(struct bttv *btv, unsigned int input);
+
+static void picolo_tetra_muxsel(struct bttv *btv, unsigned int input);
+static void picolo_tetra_init(struct bttv *btv);
+
+static void tibetCS16_muxsel(struct bttv *btv, unsigned int input);
+static void tibetCS16_init(struct bttv *btv);
+
+static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input);
+static void kodicom4400r_init(struct bttv *btv);
+
+static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input);
+static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input);
+
+static void geovision_muxsel(struct bttv *btv, unsigned int input);
+
+static void phytec_muxsel(struct bttv *btv, unsigned int input);
+
+static void gv800s_muxsel(struct bttv *btv, unsigned int input);
+static void gv800s_init(struct bttv *btv);
+
+static void td3116_muxsel(struct bttv *btv, unsigned int input);
+
+static int terratec_active_radio_upgrade(struct bttv *btv);
+static int tea5757_read(struct bttv *btv);
+static int tea5757_write(struct bttv *btv, int value);
+static void identify_by_eeprom(struct bttv *btv,
+			       unsigned char eeprom_data[256]);
+static int __devinit pvr_boot(struct bttv *btv);
+
+/* config variables */
+static unsigned int triton1;
+static unsigned int vsfx;
+static unsigned int latency = UNSET;
+int no_overlay=-1;
+
+static unsigned int card[BTTV_MAX]   = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
+static unsigned int pll[BTTV_MAX]    = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
+static unsigned int tuner[BTTV_MAX]  = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
+static unsigned int svhs[BTTV_MAX]   = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
+static unsigned int remote[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
+static unsigned int audiodev[BTTV_MAX];
+static unsigned int saa6588[BTTV_MAX];
+static struct bttv  *master[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = NULL };
+static unsigned int autoload = UNSET;
+static unsigned int gpiomask = UNSET;
+static unsigned int audioall = UNSET;
+static unsigned int audiomux[5] = { [ 0 ... 4 ] = UNSET };
+
+/* insmod options */
+module_param(triton1,    int, 0444);
+module_param(vsfx,       int, 0444);
+module_param(no_overlay, int, 0444);
+module_param(latency,    int, 0444);
+module_param(gpiomask,   int, 0444);
+module_param(audioall,   int, 0444);
+module_param(autoload,   int, 0444);
+
+module_param_array(card,     int, NULL, 0444);
+module_param_array(pll,      int, NULL, 0444);
+module_param_array(tuner,    int, NULL, 0444);
+module_param_array(svhs,     int, NULL, 0444);
+module_param_array(remote,   int, NULL, 0444);
+module_param_array(audiodev, int, NULL, 0444);
+module_param_array(audiomux, int, NULL, 0444);
+
+MODULE_PARM_DESC(triton1,"set ETBF pci config bit "
+		 "[enable bug compatibility for triton1 + others]");
+MODULE_PARM_DESC(vsfx,"set VSFX pci config bit "
+		 "[yet another chipset flaw workaround]");
+MODULE_PARM_DESC(latency,"pci latency timer");
+MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
+MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
+MODULE_PARM_DESC(tuner,"specify installed tuner type");
+MODULE_PARM_DESC(autoload, "obsolete option, please do not use anymore");
+MODULE_PARM_DESC(audiodev, "specify audio device:\n"
+		"\t\t-1 = no audio\n"
+		"\t\t 0 = autodetect (default)\n"
+		"\t\t 1 = msp3400\n"
+		"\t\t 2 = tda7432\n"
+		"\t\t 3 = tvaudio");
+MODULE_PARM_DESC(saa6588, "if 1, then load the saa6588 RDS module, default (0) is to use the card definition.");
+MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)"
+		" [some VIA/SIS chipsets are known to have problem with overlay]");
+
+/* ----------------------------------------------------------------------- */
+/* list of card IDs for bt878+ cards                                       */
+
+static struct CARD {
+	unsigned id;
+	int cardnr;
+	char *name;
+} cards[] __devinitdata = {
+	{ 0x13eb0070, BTTV_BOARD_HAUPPAUGE878,  "Hauppauge WinTV" },
+	{ 0x39000070, BTTV_BOARD_HAUPPAUGE878,  "Hauppauge WinTV-D" },
+	{ 0x45000070, BTTV_BOARD_HAUPPAUGEPVR,  "Hauppauge WinTV/PVR" },
+	{ 0xff000070, BTTV_BOARD_OSPREY1x0,     "Osprey-100" },
+	{ 0xff010070, BTTV_BOARD_OSPREY2x0_SVID,"Osprey-200" },
+	{ 0xff020070, BTTV_BOARD_OSPREY500,     "Osprey-500" },
+	{ 0xff030070, BTTV_BOARD_OSPREY2000,    "Osprey-2000" },
+	{ 0xff040070, BTTV_BOARD_OSPREY540,     "Osprey-540" },
+	{ 0xff070070, BTTV_BOARD_OSPREY440,     "Osprey-440" },
+
+	{ 0x00011002, BTTV_BOARD_ATI_TVWONDER,  "ATI TV Wonder" },
+	{ 0x00031002, BTTV_BOARD_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
+
+	{ 0x6606107d, BTTV_BOARD_WINFAST2000,   "Leadtek WinFast TV 2000" },
+	{ 0x6607107d, BTTV_BOARD_WINFASTVC100,  "Leadtek WinFast VC 100" },
+	{ 0x6609107d, BTTV_BOARD_WINFAST2000,   "Leadtek TV 2000 XP" },
+	{ 0x263610b4, BTTV_BOARD_STB2,          "STB TV PCI FM, Gateway P/N 6000704" },
+	{ 0x264510b4, BTTV_BOARD_STB2,          "STB TV PCI FM, Gateway P/N 6000704" },
+	{ 0x402010fc, BTTV_BOARD_GVBCTV3PCI,    "I-O Data Co. GV-BCTV3/PCI" },
+	{ 0x405010fc, BTTV_BOARD_GVBCTV4PCI,    "I-O Data Co. GV-BCTV4/PCI" },
+	{ 0x407010fc, BTTV_BOARD_GVBCTV5PCI,    "I-O Data Co. GV-BCTV5/PCI" },
+	{ 0xd01810fc, BTTV_BOARD_GVBCTV5PCI,    "I-O Data Co. GV-BCTV5/PCI" },
+
+	{ 0x001211bd, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV" },
+	/* some cards ship with byteswapped IDs ... */
+	{ 0x1200bd11, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV [bswap]" },
+	{ 0xff00bd11, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV [bswap]" },
+	/* this seems to happen as well ... */
+	{ 0xff1211bd, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV" },
+
+	{ 0x3000121a, BTTV_BOARD_VOODOOTV_200,  "3Dfx VoodooTV 200" },
+	{ 0x263710b4, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM" },
+	{ 0x3060121a, BTTV_BOARD_STB2,	  "3Dfx VoodooTV 100/ STB OEM" },
+
+	{ 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
+	{ 0xa005144f, BTTV_BOARD_MAGICTVIEW063, "CPH06X TView99-Card" },
+	{ 0x3002144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" },
+	{ 0x3005144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" },
+	{ 0x5000144f, BTTV_BOARD_MAGICTVIEW061, "Askey CPH050" },
+	{ 0x300014ff, BTTV_BOARD_MAGICTVIEW061, "TView 99 (CPH061)" },
+	{ 0x300214ff, BTTV_BOARD_PHOEBE_TVMAS,  "Phoebe TV Master (CPH060)" },
+
+	{ 0x00011461, BTTV_BOARD_AVPHONE98,     "AVerMedia TVPhone98" },
+	{ 0x00021461, BTTV_BOARD_AVERMEDIA98,   "AVermedia TVCapture 98" },
+	{ 0x00031461, BTTV_BOARD_AVPHONE98,     "AVerMedia TVPhone98" },
+	{ 0x00041461, BTTV_BOARD_AVERMEDIA98,   "AVerMedia TVCapture 98" },
+	{ 0x03001461, BTTV_BOARD_AVERMEDIA98,   "VDOMATE TV TUNER CARD" },
+
+	{ 0x1117153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Philips PAL B/G)" },
+	{ 0x1118153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Temic PAL B/G)" },
+	{ 0x1119153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Philips PAL I)" },
+	{ 0x111a153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Temic PAL I)" },
+
+	{ 0x1123153b, BTTV_BOARD_TERRATVRADIO,  "Terratec TV Radio+" },
+	{ 0x1127153b, BTTV_BOARD_TERRATV,       "Terratec TV+ (V1.05)"    },
+	/* clashes with FlyVideo
+	 *{ 0x18521852, BTTV_BOARD_TERRATV,     "Terratec TV+ (V1.10)"    }, */
+	{ 0x1134153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (LR102)" },
+	{ 0x1135153b, BTTV_BOARD_TERRATVALUER,  "Terratec TValue Radio" }, /* LR102 */
+	{ 0x5018153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue" },       /* ?? */
+	{ 0xff3b153b, BTTV_BOARD_TERRATVALUER,  "Terratec TValue Radio" }, /* ?? */
+
+	{ 0x400015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
+	{ 0x400a15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
+	{ 0x400d15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+	{ 0x401015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+	{ 0x401615b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+
+	{ 0x1430aa00, BTTV_BOARD_PV143,         "Provideo PV143A" },
+	{ 0x1431aa00, BTTV_BOARD_PV143,         "Provideo PV143B" },
+	{ 0x1432aa00, BTTV_BOARD_PV143,         "Provideo PV143C" },
+	{ 0x1433aa00, BTTV_BOARD_PV143,         "Provideo PV143D" },
+	{ 0x1433aa03, BTTV_BOARD_PV143,         "Security Eyes" },
+
+	{ 0x1460aa00, BTTV_BOARD_PV150,         "Provideo PV150A-1" },
+	{ 0x1461aa01, BTTV_BOARD_PV150,         "Provideo PV150A-2" },
+	{ 0x1462aa02, BTTV_BOARD_PV150,         "Provideo PV150A-3" },
+	{ 0x1463aa03, BTTV_BOARD_PV150,         "Provideo PV150A-4" },
+
+	{ 0x1464aa04, BTTV_BOARD_PV150,         "Provideo PV150B-1" },
+	{ 0x1465aa05, BTTV_BOARD_PV150,         "Provideo PV150B-2" },
+	{ 0x1466aa06, BTTV_BOARD_PV150,         "Provideo PV150B-3" },
+	{ 0x1467aa07, BTTV_BOARD_PV150,         "Provideo PV150B-4" },
+
+	{ 0xa132ff00, BTTV_BOARD_IVC100,        "IVC-100"  },
+	{ 0xa1550000, BTTV_BOARD_IVC200,        "IVC-200"  },
+	{ 0xa1550001, BTTV_BOARD_IVC200,        "IVC-200"  },
+	{ 0xa1550002, BTTV_BOARD_IVC200,        "IVC-200"  },
+	{ 0xa1550003, BTTV_BOARD_IVC200,        "IVC-200"  },
+	{ 0xa1550100, BTTV_BOARD_IVC200,        "IVC-200G" },
+	{ 0xa1550101, BTTV_BOARD_IVC200,        "IVC-200G" },
+	{ 0xa1550102, BTTV_BOARD_IVC200,        "IVC-200G" },
+	{ 0xa1550103, BTTV_BOARD_IVC200,        "IVC-200G" },
+	{ 0xa1550800, BTTV_BOARD_IVC200,        "IVC-200"  },
+	{ 0xa1550801, BTTV_BOARD_IVC200,        "IVC-200"  },
+	{ 0xa1550802, BTTV_BOARD_IVC200,        "IVC-200"  },
+	{ 0xa1550803, BTTV_BOARD_IVC200,        "IVC-200"  },
+	{ 0xa182ff00, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff01, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff02, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff03, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff04, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff05, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff06, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff07, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff08, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff09, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff0a, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff0b, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff0c, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff0d, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff0e, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff0f, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xf0500000, BTTV_BOARD_IVCE8784,      "IVCE-8784" },
+	{ 0xf0500001, BTTV_BOARD_IVCE8784,      "IVCE-8784" },
+	{ 0xf0500002, BTTV_BOARD_IVCE8784,      "IVCE-8784" },
+	{ 0xf0500003, BTTV_BOARD_IVCE8784,      "IVCE-8784" },
+
+	{ 0x41424344, BTTV_BOARD_GRANDTEC,      "GrandTec Multi Capture" },
+	{ 0x01020304, BTTV_BOARD_XGUARD,        "Grandtec Grand X-Guard" },
+
+	{ 0x18501851, BTTV_BOARD_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
+	{ 0xa0501851, BTTV_BOARD_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
+	{ 0x18511851, BTTV_BOARD_FLYVIDEO98EZ,  "FlyVideo 98EZ (LR51)/ CyberMail AV" },
+	{ 0x18521852, BTTV_BOARD_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
+	{ 0x41a0a051, BTTV_BOARD_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" },
+	{ 0x18501f7f, BTTV_BOARD_FLYVIDEO_98,   "Lifeview Flyvideo 98" },
+
+	{ 0x010115cb, BTTV_BOARD_GMV1,          "AG GMV1" },
+	{ 0x010114c7, BTTV_BOARD_MODTEC_205,    "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
+
+	{ 0x10b42636, BTTV_BOARD_HAUPPAUGE878,  "STB ???" },
+	{ 0x217d6606, BTTV_BOARD_WINFAST2000,   "Leadtek WinFast TV 2000" },
+	{ 0xfff6f6ff, BTTV_BOARD_WINFAST2000,   "Leadtek WinFast TV 2000" },
+	{ 0x03116000, BTTV_BOARD_SENSORAY311_611, "Sensoray 311" },
+	{ 0x06116000, BTTV_BOARD_SENSORAY311_611, "Sensoray 611" },
+	{ 0x00790e11, BTTV_BOARD_WINDVR,        "Canopus WinDVR PCI" },
+	{ 0xa0fca1a0, BTTV_BOARD_ZOLTRIX,       "Face to Face Tvmax" },
+	{ 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" },
+	{ 0x146caa0c, BTTV_BOARD_PV951,         "ituner spectra8" },
+	{ 0x200a1295, BTTV_BOARD_PXC200,        "ImageNation PXC200A" },
+
+	{ 0x40111554, BTTV_BOARD_PV_BT878P_9B,  "Prolink Pixelview PV-BT" },
+	{ 0x17de0a01, BTTV_BOARD_KWORLD,        "Mecer TV/FM/Video Tuner" },
+
+	{ 0x01051805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #1" },
+	{ 0x01061805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #2" },
+	{ 0x01071805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" },
+	{ 0x01081805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" },
+
+	{ 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" },
+
+	{ 0x53534149, BTTV_BOARD_SSAI_SECURITY, "SSAI Security Video Interface" },
+	{ 0x5353414a, BTTV_BOARD_SSAI_ULTRASOUND, "SSAI Ultrasound Video Interface" },
+
+	/* likely broken, vendor id doesn't match the other magic views ...
+	 * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */
+
+	/* Duplicate PCI ID, reconfigure for this board during the eeprom read.
+	* { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB,  "Hauppauge ImpactVCB" }, */
+
+	{ 0x109e036e, BTTV_BOARD_CONCEPTRONIC_CTVFMI2,	"Conceptronic CTVFMi v2"},
+
+	/* DVB cards (using pci function .1 for mpeg data xfer) */
+	{ 0x001c11bd, BTTV_BOARD_PINNACLESAT,   "Pinnacle PCTV Sat" },
+	{ 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
+	{ 0x20007063, BTTV_BOARD_PC_HDTV,       "pcHDTV HD-2000 TV"},
+	{ 0x002611bd, BTTV_BOARD_TWINHAN_DST,   "Pinnacle PCTV SAT CI" },
+	{ 0x00011822, BTTV_BOARD_TWINHAN_DST,   "Twinhan VisionPlus DVB" },
+	{ 0xfc00270f, BTTV_BOARD_TWINHAN_DST,   "ChainTech digitop DST-1000 DVB-S" },
+	{ 0x07711461, BTTV_BOARD_AVDVBT_771,    "AVermedia AverTV DVB-T 771" },
+	{ 0x07611461, BTTV_BOARD_AVDVBT_761,    "AverMedia AverTV DVB-T 761" },
+	{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE,    "DViCO FusionHDTV DVB-T Lite" },
+	{ 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE,    "Ultraview DVB-T Lite" },
+	{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,    "DViCO FusionHDTV 5 Lite" },
+	{ 0x00261822, BTTV_BOARD_TWINHAN_DST,	"DNTV Live! Mini "},
+	{ 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2,	"DViCO FusionHDTV 2" },
+	{ 0x763c008a, BTTV_BOARD_GEOVISION_GV600,	"GeoVision GV-600" },
+	{ 0x18011000, BTTV_BOARD_ENLTV_FM_2,	"Encore ENL TV-FM-2" },
+	{ 0x763d800a, BTTV_BOARD_GEOVISION_GV800S, "GeoVision GV-800(S) (master)" },
+	{ 0x763d800b, BTTV_BOARD_GEOVISION_GV800S_SL,	"GeoVision GV-800(S) (slave)" },
+	{ 0x763d800c, BTTV_BOARD_GEOVISION_GV800S_SL,	"GeoVision GV-800(S) (slave)" },
+	{ 0x763d800d, BTTV_BOARD_GEOVISION_GV800S_SL,	"GeoVision GV-800(S) (slave)" },
+
+	{ 0x15401830, BTTV_BOARD_PV183,         "Provideo PV183-1" },
+	{ 0x15401831, BTTV_BOARD_PV183,         "Provideo PV183-2" },
+	{ 0x15401832, BTTV_BOARD_PV183,         "Provideo PV183-3" },
+	{ 0x15401833, BTTV_BOARD_PV183,         "Provideo PV183-4" },
+	{ 0x15401834, BTTV_BOARD_PV183,         "Provideo PV183-5" },
+	{ 0x15401835, BTTV_BOARD_PV183,         "Provideo PV183-6" },
+	{ 0x15401836, BTTV_BOARD_PV183,         "Provideo PV183-7" },
+	{ 0x15401837, BTTV_BOARD_PV183,         "Provideo PV183-8" },
+	{ 0x3116f200, BTTV_BOARD_TVT_TD3116,	"Tongwei Video Technology TD-3116" },
+	{ 0x02280279, BTTV_BOARD_APOSONIC_WDVR, "Aposonic W-DVR" },
+	{ 0, -1, NULL }
+};
+
+/* ----------------------------------------------------------------------- */
+/* array with description for bt848 / bt878 tv/grabber cards               */
+
+struct tvcard bttv_tvcards[] = {
+	/* ---- card 0x00 ---------------------------------- */
+	[BTTV_BOARD_UNKNOWN] = {
+		.name		= " *** UNKNOWN/GENERIC *** ",
+		.video_inputs	= 4,
+		.svhs		= 2,
+		.muxsel		= MUXSEL(2, 3, 1, 0),
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_MIRO] = {
+		.name		= "MIRO PCTV",
+		.video_inputs	= 4,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 15,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 2, 0, 0, 0 },
+		.gpiomute 	= 10,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_HAUPPAUGE] = {
+		.name		= "Hauppauge (bt848)",
+		.video_inputs	= 4,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 7,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0, 1, 2, 3 },
+		.gpiomute 	= 4,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_STB] = {
+		.name		= "STB, Gateway P/N 6000699 (bt848)",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 7,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 4, 0, 2, 3 },
+		.gpiomute 	= 1,
+		.no_msp34xx	= 1,
+		.tuner_type     = TUNER_PHILIPS_NTSC,
+		.tuner_addr	= ADDR_UNSET,
+		.pll            = PLL_28,
+		.has_radio      = 1,
+	},
+
+	/* ---- card 0x04 ---------------------------------- */
+	[BTTV_BOARD_INTEL] = {
+		.name		= "Intel Create and Share PCI/ Smart Video Recorder III",
+		.video_inputs	= 4,
+		/* .audio_inputs= 0, */
+		.svhs		= 2,
+		.gpiomask	= 0,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0 },
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_DIAMOND] = {
+		.name		= "Diamond DTV2000",
+		.video_inputs	= 4,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 3,
+		.muxsel		= MUXSEL(2, 3, 1, 0),
+		.gpiomux 	= { 0, 1, 0, 1 },
+		.gpiomute 	= 3,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_AVERMEDIA] = {
+		.name		= "AVerMedia TVPhone",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 3,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomask	= 0x0f,
+		.gpiomux 	= { 0x0c, 0x04, 0x08, 0x04 },
+		/*                0x04 for some cards ?? */
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.audio_mode_gpio= avermedia_tvphone_audio,
+		.has_remote     = 1,
+	},
+	[BTTV_BOARD_MATRIX_VISION] = {
+		.name		= "MATRIX-Vision MV-Delta",
+		.video_inputs	= 5,
+		/* .audio_inputs= 1, */
+		.svhs		= 3,
+		.gpiomask	= 0,
+		.muxsel		= MUXSEL(2, 3, 1, 0, 0),
+		.gpiomux 	= { 0 },
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+
+	/* ---- card 0x08 ---------------------------------- */
+	[BTTV_BOARD_FLYVIDEO] = {
+		.name		= "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26",
+		.video_inputs	= 4,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0xc00,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0, 0xc00, 0x800, 0x400 },
+		.gpiomute 	= 0xc00,
+		.pll		= PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_TURBOTV] = {
+		.name		= "IMS/IXmicro TurboTV",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 3,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 1, 1, 2, 3 },
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_TEMIC_PAL,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_HAUPPAUGE878] = {
+		.name		= "Hauppauge (bt878)",
+		.video_inputs	= 4,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0x0f, /* old: 7 */
+		.muxsel		= MUXSEL(2, 0, 1, 1),
+		.gpiomux 	= { 0, 1, 2, 3 },
+		.gpiomute 	= 4,
+		.pll		= PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_MIROPRO] = {
+		.name		= "MIRO PCTV pro",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0x3014f,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0x20001,0x10001, 0, 0 },
+		.gpiomute 	= 10,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+
+	/* ---- card 0x0c ---------------------------------- */
+	[BTTV_BOARD_ADSTECH_TV] = {
+		.name		= "ADS Technologies Channel Surfer TV (bt848)",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 15,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 13, 14, 11, 7 },
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_AVERMEDIA98] = {
+		.name		= "AVerMedia TVCapture 98",
+		.video_inputs	= 3,
+		/* .audio_inputs= 4, */
+		.svhs		= 2,
+		.gpiomask	= 15,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 13, 14, 11, 7 },
+		.msp34xx_alt    = 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.audio_mode_gpio= avermedia_tv_stereo_audio,
+		.no_gpioirq     = 1,
+	},
+	[BTTV_BOARD_VHX] = {
+		.name		= "Aimslab Video Highway Xtreme (VHX)",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 7,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0, 2, 1, 3 }, /* old: {0, 1, 2, 3, 4} */
+		.gpiomute 	= 4,
+		.pll		= PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_ZOLTRIX] = {
+		.name		= "Zoltrix TV-Max",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 15,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0, 0, 1, 0 },
+		.gpiomute 	= 10,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+
+	/* ---- card 0x10 ---------------------------------- */
+	[BTTV_BOARD_PIXVIEWPLAYTV] = {
+		.name		= "Prolink Pixelview PlayTV (bt878)",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0x01fe00,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		/* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
+		.gpiomux        = { 0x001e00, 0, 0x018000, 0x014000 },
+		.gpiomute 	= 0x002000,
+		.pll		= PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_WINVIEW_601] = {
+		.name		= "Leadtek WinView 601",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0x8300f8,
+		.muxsel		= MUXSEL(2, 3, 1, 1, 0),
+		.gpiomux 	= { 0x4fa007,0xcfa007,0xcfa007,0xcfa007 },
+		.gpiomute 	= 0xcfa007,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.volume_gpio	= winview_volume,
+		.has_radio	= 1,
+	},
+	[BTTV_BOARD_AVEC_INTERCAP] = {
+		.name		= "AVEC Intercapture",
+		.video_inputs	= 3,
+		/* .audio_inputs= 2, */
+		.svhs		= 2,
+		.gpiomask	= 0,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 1, 0, 0, 0 },
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_LIFE_FLYKIT] = {
+		.name		= "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
+		.video_inputs	= 4,
+		/* .audio_inputs= 1, */
+		.svhs		= NO_SVHS,
+		.gpiomask	= 0x8dff00,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0 },
+		.no_msp34xx	= 1,
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+
+	/* ---- card 0x14 ---------------------------------- */
+	[BTTV_BOARD_CEI_RAFFLES] = {
+		.name		= "CEI Raffles Card",
+		.video_inputs	= 3,
+		/* .audio_inputs= 3, */
+		.svhs		= 2,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_CONFERENCETV] = {
+		.name		= "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
+		.video_inputs	= 4,
+		/* .audio_inputs= 2,  tuner, line in */
+		.svhs		= 2,
+		.gpiomask	= 0x1800,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0, 0x800, 0x1000, 0x1000 },
+		.gpiomute 	= 0x1800,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL_I,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_PHOEBE_TVMAS] = {
+		.name		= "Askey CPH050/ Phoebe Tv Master + FM",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0xc00,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0, 1, 0x800, 0x400 },
+		.gpiomute 	= 0xc00,
+		.pll		= PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_MODTEC_205] = {
+		.name		= "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= NO_SVHS,
+		.has_dig_in	= 1,
+		.gpiomask	= 7,
+		.muxsel		= MUXSEL(2, 3, 0), /* input 2 is digital */
+		/* .digital_mode= DIGITAL_MODE_CAMERA, */
+		.gpiomux 	= { 0, 0, 0, 0 },
+		.no_msp34xx	= 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ALPS_TSBB5_PAL_I,
+		.tuner_addr	= ADDR_UNSET,
+	},
+
+	/* ---- card 0x18 ---------------------------------- */
+	[BTTV_BOARD_MAGICTVIEW061] = {
+		.name		= "Askey CPH05X/06X (bt878) [many vendors]",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0xe00,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= {0x400, 0x400, 0x400, 0x400 },
+		.gpiomute 	= 0xc00,
+		.pll		= PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.has_remote     = 1,
+		.has_radio	= 1,  /* not every card has radio */
+	},
+	[BTTV_BOARD_VOBIS_BOOSTAR] = {
+		.name           = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask       = 0x1f0fff,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 0x20000, 0x30000, 0x10000, 0 },
+		.gpiomute 	= 0x40000,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.audio_mode_gpio= terratv_audio,
+	},
+	[BTTV_BOARD_HAUPPAUG_WCAM] = {
+		.name		= "Hauppauge WinCam newer (bt878)",
+		.video_inputs	= 4,
+		/* .audio_inputs= 1, */
+		.svhs		= 3,
+		.gpiomask	= 7,
+		.muxsel		= MUXSEL(2, 0, 1, 1),
+		.gpiomux 	= { 0, 1, 2, 3 },
+		.gpiomute 	= 4,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_MAXI] = {
+		.name		= "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
+		.video_inputs	= 4,
+		/* .audio_inputs= 2, */
+		.svhs		= 2,
+		.gpiomask	= 0x1800,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0, 0x800, 0x1000, 0x1000 },
+		.gpiomute 	= 0x1800,
+		.pll            = PLL_28,
+		.tuner_type	= TUNER_PHILIPS_SECAM,
+		.tuner_addr	= ADDR_UNSET,
+	},
+
+	/* ---- card 0x1c ---------------------------------- */
+	[BTTV_BOARD_TERRATV] = {
+		.name           = "Terratec TerraTV+ Version 1.1 (bt878)",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0x1f0fff,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0x20000, 0x30000, 0x10000, 0x00000 },
+		.gpiomute 	= 0x40000,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.audio_mode_gpio= terratv_audio,
+		/* GPIO wiring:
+		External 20 pin connector (for Active Radio Upgrade board)
+		gpio00: i2c-sda
+		gpio01: i2c-scl
+		gpio02: om5610-data
+		gpio03: om5610-clk
+		gpio04: om5610-wre
+		gpio05: om5610-stereo
+		gpio06: rds6588-davn
+		gpio07: Pin 7 n.c.
+		gpio08: nIOW
+		gpio09+10: nIOR, nSEL ?? (bt878)
+			gpio09: nIOR (bt848)
+			gpio10: nSEL (bt848)
+		Sound Routing:
+		gpio16: u2-A0 (1st 4052bt)
+		gpio17: u2-A1
+		gpio18: u2-nEN
+		gpio19: u4-A0 (2nd 4052)
+		gpio20: u4-A1
+			u4-nEN - GND
+		Btspy:
+			00000 : Cdrom (internal audio input)
+			10000 : ext. Video audio input
+			20000 : TV Mono
+			a0000 : TV Mono/2
+		1a0000 : TV Stereo
+			30000 : Radio
+			40000 : Mute
+	*/
+
+	},
+	[BTTV_BOARD_PXC200] = {
+		/* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
+		.name		= "Imagenation PXC200",
+		.video_inputs	= 5,
+		/* .audio_inputs= 1, */
+		.svhs		= 1, /* was: 4 */
+		.gpiomask	= 0,
+		.muxsel		= MUXSEL(2, 3, 1, 0, 0),
+		.gpiomux 	= { 0 },
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.muxsel_hook    = PXC200_muxsel,
+
+	},
+	[BTTV_BOARD_FLYVIDEO_98] = {
+		.name		= "Lifeview FlyVideo 98 LR50",
+		.video_inputs	= 4,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0x1800,  /* 0x8dfe00 */
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0, 0x0800, 0x1000, 0x1000 },
+		.gpiomute 	= 0x1800,
+		.pll            = PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_IPROTV] = {
+		.name		= "Formac iProTV, Formac ProTV I (bt848)",
+		.video_inputs	= 4,
+		/* .audio_inputs= 1, */
+		.svhs		= 3,
+		.gpiomask	= 1,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 1, 0, 0, 0 },
+		.pll            = PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+	},
+
+	/* ---- card 0x20 ---------------------------------- */
+	[BTTV_BOARD_INTEL_C_S_PCI] = {
+		.name		= "Intel Create and Share PCI/ Smart Video Recorder III",
+		.video_inputs	= 4,
+		/* .audio_inputs= 0, */
+		.svhs		= 2,
+		.gpiomask	= 0,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0 },
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_TERRATVALUE] = {
+		.name           = "Terratec TerraTValue Version Bt878",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0xffff00,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0x500, 0, 0x300, 0x900 },
+		.gpiomute 	= 0x900,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_WINFAST2000] = {
+		.name		= "Leadtek WinFast 2000/ WinFast 2000 XP",
+		.video_inputs	= 4,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		/* TV, CVid, SVid, CVid over SVid connector */
+		.muxsel		= MUXSEL(2, 3, 1, 1, 0),
+		/* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
+		.gpiomask	= 0xb33000,
+		.gpiomux 	= { 0x122000,0x1000,0x0000,0x620000 },
+		.gpiomute 	= 0x800000,
+		/* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
+			gpio23 -- hef4052:nEnable (0x800000)
+			gpio12 -- hef4052:A1
+			gpio13 -- hef4052:A0
+		0x0000: external audio
+		0x1000: FM
+		0x2000: TV
+		0x3000: n.c.
+		Note: There exists another variant "Winfast 2000" with tv stereo !?
+		Note: eeprom only contains FF and pci subsystem id 107d:6606
+		*/
+		.pll		= PLL_28,
+		.has_radio	= 1,
+		.tuner_type	= TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */
+		.tuner_addr	= ADDR_UNSET,
+		.audio_mode_gpio= winfast2000_audio,
+		.has_remote     = 1,
+	},
+	[BTTV_BOARD_CHRONOS_VS2] = {
+		.name		= "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
+		.video_inputs	= 4,
+		/* .audio_inputs= 3, */
+		.svhs		= 2,
+		.gpiomask	= 0x1800,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0, 0x800, 0x1000, 0x1000 },
+		.gpiomute 	= 0x1800,
+		.pll		= PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+
+	/* ---- card 0x24 ---------------------------------- */
+	[BTTV_BOARD_TYPHOON_TVIEW] = {
+		.name		= "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
+		.video_inputs	= 4,
+		/* .audio_inputs= 3, */
+		.svhs		= 2,
+		.gpiomask	= 0x1800,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0, 0x800, 0x1000, 0x1000 },
+		.gpiomute 	= 0x1800,
+		.pll		= PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.has_radio	= 1,
+	},
+	[BTTV_BOARD_PXELVWPLTVPRO] = {
+		.name		= "Prolink PixelView PlayTV pro",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0xff,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0x21, 0x20, 0x24, 0x2c },
+		.gpiomute 	= 0x29,
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_MAGICTVIEW063] = {
+		.name		= "Askey CPH06X TView99",
+		.video_inputs	= 4,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0x551e00,
+		.muxsel		= MUXSEL(2, 3, 1, 0),
+		.gpiomux 	= { 0x551400, 0x551200, 0, 0 },
+		.gpiomute 	= 0x551c00,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL_I,
+		.tuner_addr	= ADDR_UNSET,
+		.has_remote     = 1,
+	},
+	[BTTV_BOARD_PINNACLE] = {
+		.name		= "Pinnacle PCTV Studio/Rave",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0x03000F,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 2, 0xd0001, 0, 0 },
+		.gpiomute 	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+
+	/* ---- card 0x28 ---------------------------------- */
+	[BTTV_BOARD_STB2] = {
+		.name		= "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 7,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 4, 0, 2, 3 },
+		.gpiomute 	= 1,
+		.no_msp34xx	= 1,
+		.tuner_type     = TUNER_PHILIPS_NTSC,
+		.tuner_addr	= ADDR_UNSET,
+		.pll            = PLL_28,
+		.has_radio      = 1,
+	},
+	[BTTV_BOARD_AVPHONE98] = {
+		.name		= "AVerMedia TVPhone 98",
+		.video_inputs	= 3,
+		/* .audio_inputs= 4, */
+		.svhs		= 2,
+		.gpiomask	= 15,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 13, 4, 11, 7 },
+		.pll		= PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.has_radio	= 1,
+		.audio_mode_gpio= avermedia_tvphone_audio,
+	},
+	[BTTV_BOARD_PV951] = {
+		.name		= "ProVideo PV951", /* pic16c54 */
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0, 0, 0, 0},
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL_I,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_ONAIR_TV] = {
+		.name		= "Little OnAir TV",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0xe00b,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0xff9ff6, 0xff9ff6, 0xff1ff7, 0 },
+		.gpiomute 	= 0xff3ffc,
+		.no_msp34xx	= 1,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+
+	/* ---- card 0x2c ---------------------------------- */
+	[BTTV_BOARD_SIGMA_TVII_FM] = {
+		.name		= "Sigma TVII-FM",
+		.video_inputs	= 2,
+		/* .audio_inputs= 1, */
+		.svhs		= NO_SVHS,
+		.gpiomask	= 3,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 1, 1, 0, 2 },
+		.gpiomute 	= 3,
+		.no_msp34xx	= 1,
+		.pll		= PLL_NONE,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_MATRIX_VISION2] = {
+		.name		= "MATRIX-Vision MV-Delta 2",
+		.video_inputs	= 5,
+		/* .audio_inputs= 1, */
+		.svhs		= 3,
+		.gpiomask	= 0,
+		.muxsel		= MUXSEL(2, 3, 1, 0, 0),
+		.gpiomux 	= { 0 },
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_ZOLTRIX_GENIE] = {
+		.name		= "Zoltrix Genie TV/FM",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0xbcf03f,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0xbc803f, 0xbc903f, 0xbcb03f, 0 },
+		.gpiomute 	= 0xbcb03f,
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_TEMIC_4039FR5_NTSC,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_TERRATVRADIO] = {
+		.name		= "Terratec TV/Radio+",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0x70000,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0x20000, 0x30000, 0x10000, 0 },
+		.gpiomute 	= 0x40000,
+		.no_msp34xx	= 1,
+		.pll		= PLL_35,
+		.tuner_type	= TUNER_PHILIPS_PAL_I,
+		.tuner_addr	= ADDR_UNSET,
+		.has_radio	= 1,
+	},
+
+	/* ---- card 0x30 ---------------------------------- */
+	[BTTV_BOARD_DYNALINK] = {
+		.name		= "Askey CPH03x/ Dynalink Magic TView",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 15,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= {2,0,0,0 },
+		.gpiomute 	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_GVBCTV3PCI] = {
+		.name		= "IODATA GV-BCTV3/PCI",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0x010f00,
+		.muxsel		= MUXSEL(2, 3, 0, 0),
+		.gpiomux 	= {0x10000, 0, 0x10000, 0 },
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_ALPS_TSHC6_NTSC,
+		.tuner_addr	= ADDR_UNSET,
+		.audio_mode_gpio= gvbctv3pci_audio,
+	},
+	[BTTV_BOARD_PXELVWPLTVPAK] = {
+		.name		= "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
+		.video_inputs	= 5,
+		/* .audio_inputs= 1, */
+		.svhs		= 3,
+		.has_dig_in	= 1,
+		.gpiomask	= 0xAA0000,
+		.muxsel		= MUXSEL(2, 3, 1, 1, 0), /* in 4 is digital */
+		/* .digital_mode= DIGITAL_MODE_CAMERA, */
+		.gpiomux 	= { 0x20000, 0, 0x80000, 0x80000 },
+		.gpiomute 	= 0xa8000,
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL_I,
+		.tuner_addr	= ADDR_UNSET,
+		.has_remote	= 1,
+		/* GPIO wiring: (different from Rev.4C !)
+			GPIO17: U4.A0 (first hef4052bt)
+			GPIO19: U4.A1
+			GPIO20: U5.A1 (second hef4052bt)
+			GPIO21: U4.nEN
+			GPIO22: BT832 Reset Line
+			GPIO23: A5,A0, U5,nEN
+		Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22
+		*/
+	},
+	[BTTV_BOARD_EAGLE] = {
+		.name           = "Eagle Wireless Capricorn2 (bt878A)",
+		.video_inputs   = 4,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.gpiomask       = 7,
+		.muxsel         = MUXSEL(2, 0, 1, 1),
+		.gpiomux        = { 0, 1, 2, 3 },
+		.gpiomute 	= 4,
+		.pll            = PLL_28,
+		.tuner_type     = UNSET /* TUNER_ALPS_TMDH2_NTSC */,
+		.tuner_addr	= ADDR_UNSET,
+	},
+
+	/* ---- card 0x34 ---------------------------------- */
+	[BTTV_BOARD_PINNACLEPRO] = {
+		/* David Härdeman <david@2gen.com> */
+		.name           = "Pinnacle PCTV Studio Pro",
+		.video_inputs   = 4,
+		/* .audio_inputs= 1, */
+		.svhs           = 3,
+		.gpiomask       = 0x03000F,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 1, 0xd0001, 0, 0 },
+		.gpiomute 	= 10,
+				/* sound path (5 sources):
+				MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable)
+					0= ext. Audio IN
+					1= from MUX2
+					2= Mono TV sound from Tuner
+					3= not connected
+				MUX2 (mask 0x30000):
+					0,2,3= from MSP34xx
+					1= FM stereo Radio from Tuner */
+		.pll            = PLL_28,
+		.tuner_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_TVIEW_RDS_FM] = {
+		/* Claas Langbehn <claas@bigfoot.com>,
+		Sven Grothklags <sven@upb.de> */
+		.name		= "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
+		.video_inputs	= 4,
+		/* .audio_inputs= 3, */
+		.svhs		= 2,
+		.gpiomask	= 0x1c,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0, 0, 0x10, 8 },
+		.gpiomute 	= 4,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.has_radio	= 1,
+	},
+	[BTTV_BOARD_LIFETEC_9415] = {
+		/* Tim Röstermundt <rosterm@uni-muenster.de>
+		in de.comp.os.unix.linux.hardware:
+			options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
+			gpiomux =0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
+			options tuner type=5 */
+		.name		= "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
+		.video_inputs	= 4,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0x18e0,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0x0000,0x0800,0x1000,0x1000 },
+		.gpiomute 	= 0x18e0,
+			/* For cards with tda9820/tda9821:
+				0x0000: Tuner normal stereo
+				0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
+				0x0880: Tuner A2 stereo */
+		.pll		= PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_BESTBUY_EASYTV] = {
+		/* Miguel Angel Alvarez <maacruz@navegalia.com>
+		old Easy TV BT848 version (model CPH031) */
+		.name           = "Askey CPH031/ BESTBUY Easy TV",
+		.video_inputs	= 4,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.gpiomask       = 0xF,
+		.muxsel         = MUXSEL(2, 3, 1, 0),
+		.gpiomux        = { 2, 0, 0, 0 },
+		.gpiomute 	= 10,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_TEMIC_PAL,
+		.tuner_addr	= ADDR_UNSET,
+	},
+
+	/* ---- card 0x38 ---------------------------------- */
+	[BTTV_BOARD_FLYVIDEO_98FM] = {
+		/* Gordon Heydon <gjheydon@bigfoot.com ('98) */
+		.name           = "Lifeview FlyVideo 98FM LR50",
+		.video_inputs   = 4,
+		/* .audio_inputs= 3, */
+		.svhs           = 2,
+		.gpiomask       = 0x1800,
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
+		.gpiomute 	= 0x1800,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+	},
+		/* This is the ultimate cheapo capture card
+		* just a BT848A on a small PCB!
+		* Steve Hosgood <steve@equiinet.com> */
+	[BTTV_BOARD_GRANDTEC] = {
+		.name           = "GrandTec 'Grand Video Capture' (Bt848)",
+		.video_inputs   = 2,
+		/* .audio_inputs= 0, */
+		.svhs           = 1,
+		.gpiomask       = 0,
+		.muxsel         = MUXSEL(3, 1),
+		.gpiomux        = { 0 },
+		.no_msp34xx     = 1,
+		.pll            = PLL_35,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_ASKEY_CPH060] = {
+		/* Daniel Herrington <daniel.herrington@home.com> */
+		.name           = "Askey CPH060/ Phoebe TV Master Only (No FM)",
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.gpiomask       = 0xe00,
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 0x400, 0x400, 0x400, 0x400 },
+		.gpiomute 	= 0x800,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_TEMIC_4036FY5_NTSC,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_ASKEY_CPH03X] = {
+		/* Matti Mottus <mottus@physic.ut.ee> */
+		.name		= "Askey CPH03x TV Capturer",
+		.video_inputs	= 4,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask       = 0x03000F,
+		.muxsel		= MUXSEL(2, 3, 1, 0),
+		.gpiomux        = { 2, 0, 0, 0 },
+		.gpiomute 	= 1,
+		.pll            = PLL_28,
+		.tuner_type	= TUNER_TEMIC_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.has_remote	= 1,
+	},
+
+	/* ---- card 0x3c ---------------------------------- */
+	[BTTV_BOARD_MM100PCTV] = {
+		/* Philip Blundell <philb@gnu.org> */
+		.name           = "Modular Technology MM100PCTV",
+		.video_inputs   = 2,
+		/* .audio_inputs= 2, */
+		.svhs		= NO_SVHS,
+		.gpiomask       = 11,
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 2, 0, 0, 1 },
+		.gpiomute 	= 8,
+		.pll            = PLL_35,
+		.tuner_type     = TUNER_TEMIC_PAL,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_GMV1] = {
+		/* Adrian Cox <adrian@humboldt.co.uk */
+		.name		= "AG Electronics GMV1",
+		.video_inputs   = 2,
+		/* .audio_inputs= 0, */
+		.svhs		= 1,
+		.gpiomask       = 0xF,
+		.muxsel		= MUXSEL(2, 2),
+		.gpiomux        = { },
+		.no_msp34xx     = 1,
+		.pll		= PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_BESTBUY_EASYTV2] = {
+		/* Miguel Angel Alvarez <maacruz@navegalia.com>
+		new Easy TV BT878 version (model CPH061)
+		special thanks to Informatica Mieres for providing the card */
+		.name           = "Askey CPH061/ BESTBUY Easy TV (bt878)",
+		.video_inputs	= 3,
+		/* .audio_inputs= 2, */
+		.svhs           = 2,
+		.gpiomask       = 0xFF,
+		.muxsel         = MUXSEL(2, 3, 1, 0),
+		.gpiomux        = { 1, 0, 4, 4 },
+		.gpiomute 	= 9,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_ATI_TVWONDER] = {
+		/* Lukas Gebauer <geby@volny.cz> */
+		.name		= "ATI TV-Wonder",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0xf03f,
+		.muxsel		= MUXSEL(2, 3, 1, 0),
+		.gpiomux 	= { 0xbffe, 0, 0xbfff, 0 },
+		.gpiomute 	= 0xbffe,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_TEMIC_4006FN5_MULTI_PAL,
+		.tuner_addr	= ADDR_UNSET,
+	},
+
+	/* ---- card 0x40 ---------------------------------- */
+	[BTTV_BOARD_ATI_TVWONDERVE] = {
+		/* Lukas Gebauer <geby@volny.cz> */
+		.name		= "ATI TV-Wonder VE",
+		.video_inputs	= 2,
+		/* .audio_inputs= 1, */
+		.svhs		= NO_SVHS,
+		.gpiomask	= 1,
+		.muxsel		= MUXSEL(2, 3, 0, 1),
+		.gpiomux 	= { 0, 0, 1, 0 },
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_TEMIC_4006FN5_MULTI_PAL,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_FLYVIDEO2000] = {
+		/* DeeJay <deejay@westel900.net (2000S) */
+		.name           = "Lifeview FlyVideo 2000S LR90",
+		.video_inputs   = 3,
+		/* .audio_inputs= 3, */
+		.svhs           = 2,
+		.gpiomask	= 0x18e0,
+		.muxsel		= MUXSEL(2, 3, 0, 1),
+				/* Radio changed from 1e80 to 0x800 to make
+				FlyVideo2000S in .hu happy (gm)*/
+				/* -dk-???: set mute=0x1800 for tda9874h daughterboard */
+		.gpiomux 	= { 0x0000,0x0800,0x1000,0x1000 },
+		.gpiomute 	= 0x1800,
+		.audio_mode_gpio= fv2000s_audio,
+		.no_msp34xx	= 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_TERRATVALUER] = {
+		.name		= "Terratec TValueRadio",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0xffff00,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0x500, 0x500, 0x300, 0x900 },
+		.gpiomute 	= 0x900,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.has_radio	= 1,
+	},
+	[BTTV_BOARD_GVBCTV4PCI] = {
+		/* TANAKA Kei <peg00625@nifty.com> */
+		.name           = "IODATA GV-BCTV4/PCI",
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.gpiomask       = 0x010f00,
+		.muxsel         = MUXSEL(2, 3, 0, 0),
+		.gpiomux        = {0x10000, 0, 0x10000, 0 },
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_SHARP_2U5JF5540_NTSC,
+		.tuner_addr	= ADDR_UNSET,
+		.audio_mode_gpio= gvbctv3pci_audio,
+	},
+
+	/* ---- card 0x44 ---------------------------------- */
+	[BTTV_BOARD_VOODOOTV_FM] = {
+		.name           = "3Dfx VoodooTV FM (Euro)",
+		/* try "insmod msp3400 simple=0" if you have
+		* sound problems with this card. */
+		.video_inputs   = 4,
+		/* .audio_inputs= 1, */
+		.svhs           = NO_SVHS,
+		.gpiomask       = 0x4f8a00,
+		/* 0x100000: 1=MSP enabled (0=disable again)
+		* 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
+		.gpiomux        = {0x947fff, 0x987fff,0x947fff,0x947fff },
+		.gpiomute 	= 0x947fff,
+		/* tvtuner, radio,   external,internal, mute,  stereo
+		* tuner, Composit, SVid, Composit-on-Svid-adapter */
+		.muxsel         = MUXSEL(2, 3, 0, 1),
+		.tuner_type     = TUNER_MT2032,
+		.tuner_addr	= ADDR_UNSET,
+		.pll		= PLL_28,
+		.has_radio	= 1,
+	},
+	[BTTV_BOARD_VOODOOTV_200] = {
+		.name           = "VoodooTV 200 (USA)",
+		/* try "insmod msp3400 simple=0" if you have
+		* sound problems with this card. */
+		.video_inputs   = 4,
+		/* .audio_inputs= 1, */
+		.svhs           = NO_SVHS,
+		.gpiomask       = 0x4f8a00,
+		/* 0x100000: 1=MSP enabled (0=disable again)
+		* 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
+		.gpiomux        = {0x947fff, 0x987fff,0x947fff,0x947fff },
+		.gpiomute 	= 0x947fff,
+		/* tvtuner, radio,   external,internal, mute,  stereo
+		* tuner, Composit, SVid, Composit-on-Svid-adapter */
+		.muxsel         = MUXSEL(2, 3, 0, 1),
+		.tuner_type     = TUNER_MT2032,
+		.tuner_addr	= ADDR_UNSET,
+		.pll		= PLL_28,
+		.has_radio	= 1,
+	},
+	[BTTV_BOARD_AIMMS] = {
+		/* Philip Blundell <pb@nexus.co.uk> */
+		.name           = "Active Imaging AIMMS",
+		.video_inputs   = 1,
+		/* .audio_inputs= 0, */
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.pll            = PLL_28,
+		.muxsel         = MUXSEL(2),
+		.gpiomask       = 0
+	},
+	[BTTV_BOARD_PV_BT878P_PLUS] = {
+		/* Tomasz Pyra <hellfire@sedez.iq.pl> */
+		.name           = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)",
+		.video_inputs   = 3,
+		/* .audio_inputs= 4, */
+		.svhs           = 2,
+		.gpiomask       = 15,
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 0, 0, 11, 7 }, /* TV and Radio with same GPIO ! */
+		.gpiomute 	= 13,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_LG_PAL_I_FM,
+		.tuner_addr	= ADDR_UNSET,
+		.has_remote     = 1,
+		/* GPIO wiring:
+			GPIO0: U4.A0 (hef4052bt)
+			GPIO1: U4.A1
+			GPIO2: U4.A1 (second hef4052bt)
+			GPIO3: U4.nEN, U5.A0, A5.nEN
+			GPIO8-15: vrd866b ?
+		*/
+	},
+	[BTTV_BOARD_FLYVIDEO98EZ] = {
+		.name		= "Lifeview FlyVideo 98EZ (capture only) LR51",
+		.video_inputs	= 4,
+		/* .audio_inputs= 0, */
+		.svhs		= 2,
+		/* AV1, AV2, SVHS, CVid adapter on SVHS */
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.pll		= PLL_28,
+		.no_msp34xx	= 1,
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+
+	/* ---- card 0x48 ---------------------------------- */
+	[BTTV_BOARD_PV_BT878P_9B] = {
+		/* Dariusz Kowalewski <darekk@automex.pl> */
+		.name		= "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
+		.video_inputs	= 4,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0x3f,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 0x01, 0x00, 0x03, 0x03 },
+		.gpiomute 	= 0x09,
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.audio_mode_gpio= pvbt878p9b_audio, /* Note: not all cards have stereo */
+		.has_radio	= 1,  /* Note: not all cards have radio */
+		.has_remote     = 1,
+		/* GPIO wiring:
+			GPIO0: A0 hef4052
+			GPIO1: A1 hef4052
+			GPIO3: nEN hef4052
+			GPIO8-15: vrd866b
+			GPIO20,22,23: R30,R29,R28
+		*/
+	},
+	[BTTV_BOARD_SENSORAY311_611] = {
+		/* Clay Kunz <ckunz@mail.arc.nasa.gov> */
+		/* you must jumper JP5 for the 311 card (PC/104+) to work */
+		.name           = "Sensoray 311/611",
+		.video_inputs   = 5,
+		/* .audio_inputs= 0, */
+		.svhs           = 4,
+		.gpiomask       = 0,
+		.muxsel         = MUXSEL(2, 3, 1, 0, 0),
+		.gpiomux        = { 0 },
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_RV605] = {
+		/* Miguel Freitas <miguel@cetuc.puc-rio.br> */
+		.name           = "RemoteVision MX (RV605)",
+		.video_inputs   = 16,
+		/* .audio_inputs= 0, */
+		.svhs           = NO_SVHS,
+		.gpiomask       = 0x00,
+		.gpiomask2      = 0x07ff,
+		.muxsel         = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3),
+		.no_msp34xx     = 1,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.muxsel_hook    = rv605_muxsel,
+	},
+	[BTTV_BOARD_POWERCLR_MTV878] = {
+		.name           = "Powercolor MTV878/ MTV878R/ MTV878F",
+		.video_inputs   = 3,
+		/* .audio_inputs= 2, */
+		.svhs           = 2,
+		.gpiomask       = 0x1C800F,  /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */
+		.muxsel         = MUXSEL(2, 1, 1),
+		.gpiomux        = { 0, 1, 2, 2 },
+		.gpiomute 	= 4,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.pll		= PLL_28,
+		.has_radio	= 1,
+	},
+
+	/* ---- card 0x4c ---------------------------------- */
+	[BTTV_BOARD_WINDVR] = {
+		/* Masaki Suzuki <masaki@btree.org> */
+		.name           = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)",
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.gpiomask       = 0x140007,
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 0, 1, 2, 3 },
+		.gpiomute 	= 4,
+		.tuner_type     = TUNER_PHILIPS_NTSC,
+		.tuner_addr	= ADDR_UNSET,
+		.audio_mode_gpio= windvr_audio,
+	},
+	[BTTV_BOARD_GRANDTEC_MULTI] = {
+		.name           = "GrandTec Multi Capture Card (Bt878)",
+		.video_inputs   = 4,
+		/* .audio_inputs= 0, */
+		.svhs           = NO_SVHS,
+		.gpiomask       = 0,
+		.muxsel         = MUXSEL(2, 3, 1, 0),
+		.gpiomux        = { 0 },
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_KWORLD] = {
+		.name           = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
+		.video_inputs   = 4,
+		/* .audio_inputs= 3, */
+		.svhs           = 2,
+		.gpiomask       = 7,
+		/* Tuner, SVid, SVHS, SVid to SVHS connector */
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 0, 0, 4, 4 },/* Yes, this tuner uses the same audio output for TV and FM radio!
+						* This card lacks external Audio In, so we mute it on Ext. & Int.
+						* The PCB can take a sbx1637/sbx1673, wiring unknown.
+						* This card lacks PCI subsystem ID, sigh.
+						* gpiomux =1: lower volume, 2+3: mute
+						* btwincap uses 0x80000/0x80003
+						*/
+		.gpiomute 	= 4,
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		/* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
+		radio signal strength indicators work fine. */
+		.has_radio	= 1,
+		/* GPIO Info:
+			GPIO0,1:   HEF4052 A0,A1
+			GPIO2:     HEF4052 nENABLE
+			GPIO3-7:   n.c.
+			GPIO8-13:  IRDC357 data0-5 (data6 n.c. ?) [chip not present on my card]
+			GPIO14,15: ??
+			GPIO16-21: n.c.
+			GPIO22,23: ??
+			??       : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/
+	},
+	[BTTV_BOARD_DSP_TCVIDEO] = {
+		/* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
+		.name           = "DSP Design TCVIDEO",
+		.video_inputs   = 4,
+		.svhs           = NO_SVHS,
+		.muxsel         = MUXSEL(2, 3, 1, 0),
+		.pll            = PLL_28,
+		.tuner_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+	},
+
+		/* ---- card 0x50 ---------------------------------- */
+	[BTTV_BOARD_HAUPPAUGEPVR] = {
+		.name           = "Hauppauge WinTV PVR",
+		.video_inputs   = 4,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.muxsel         = MUXSEL(2, 0, 1, 1),
+		.pll            = PLL_28,
+		.tuner_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+
+		.gpiomask       = 7,
+		.gpiomux        = {7},
+	},
+	[BTTV_BOARD_GVBCTV5PCI] = {
+		.name           = "IODATA GV-BCTV5/PCI",
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.gpiomask       = 0x0f0f80,
+		.muxsel         = MUXSEL(2, 3, 1, 0),
+		.gpiomux        = {0x030000, 0x010000, 0, 0 },
+		.gpiomute 	= 0x020000,
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_NTSC_M,
+		.tuner_addr	= ADDR_UNSET,
+		.audio_mode_gpio= gvbctv5pci_audio,
+		.has_radio      = 1,
+	},
+	[BTTV_BOARD_OSPREY1x0] = {
+		.name           = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
+		.video_inputs   = 4,                  /* id-inputs-clock */
+		/* .audio_inputs= 0, */
+		.svhs           = 3,
+		.muxsel         = MUXSEL(3, 2, 0, 1),
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+	},
+	[BTTV_BOARD_OSPREY1x0_848] = {
+		.name           = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
+		.video_inputs   = 3,
+		/* .audio_inputs= 0, */
+		.svhs           = 2,
+		.muxsel         = MUXSEL(2, 3, 1),
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+	},
+
+		/* ---- card 0x54 ---------------------------------- */
+	[BTTV_BOARD_OSPREY101_848] = {
+		.name           = "Osprey 101 (848)", /* 0x05-40C0-C1 */
+		.video_inputs   = 2,
+		/* .audio_inputs= 0, */
+		.svhs           = 1,
+		.muxsel         = MUXSEL(3, 1),
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+	},
+	[BTTV_BOARD_OSPREY1x1] = {
+		.name           = "Osprey 101/151",       /* 0x1(4|5)-0004-C4 */
+		.video_inputs   = 1,
+		/* .audio_inputs= 0, */
+		.svhs           = NO_SVHS,
+		.muxsel         = MUXSEL(0),
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+	},
+	[BTTV_BOARD_OSPREY1x1_SVID] = {
+		.name           = "Osprey 101/151 w/ svid",  /* 0x(16|17|20)-00C4-C1 */
+		.video_inputs   = 2,
+		/* .audio_inputs= 0, */
+		.svhs           = 1,
+		.muxsel         = MUXSEL(0, 1),
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+	},
+	[BTTV_BOARD_OSPREY2xx] = {
+		.name           = "Osprey 200/201/250/251",  /* 0x1(8|9|E|F)-0004-C4 */
+		.video_inputs   = 1,
+		/* .audio_inputs= 1, */
+		.svhs           = NO_SVHS,
+		.muxsel         = MUXSEL(0),
+		.pll            = PLL_28,
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+	},
+
+		/* ---- card 0x58 ---------------------------------- */
+	[BTTV_BOARD_OSPREY2x0_SVID] = {
+		.name           = "Osprey 200/250",   /* 0x1(A|B)-00C4-C1 */
+		.video_inputs   = 2,
+		/* .audio_inputs= 1, */
+		.svhs           = 1,
+		.muxsel         = MUXSEL(0, 1),
+		.pll            = PLL_28,
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+	},
+	[BTTV_BOARD_OSPREY2x0] = {
+		.name           = "Osprey 210/220/230",   /* 0x1(A|B)-04C0-C1 */
+		.video_inputs   = 2,
+		/* .audio_inputs= 1, */
+		.svhs           = 1,
+		.muxsel         = MUXSEL(2, 3),
+		.pll            = PLL_28,
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+	},
+	[BTTV_BOARD_OSPREY500] = {
+		.name           = "Osprey 500",   /* 500 */
+		.video_inputs   = 2,
+		/* .audio_inputs= 1, */
+		.svhs           = 1,
+		.muxsel         = MUXSEL(2, 3),
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+	},
+	[BTTV_BOARD_OSPREY540] = {
+		.name           = "Osprey 540",   /* 540 */
+		.video_inputs   = 4,
+		/* .audio_inputs= 1, */
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+	},
+
+		/* ---- card 0x5C ---------------------------------- */
+	[BTTV_BOARD_OSPREY2000] = {
+		.name           = "Osprey 2000",  /* 2000 */
+		.video_inputs   = 2,
+		/* .audio_inputs= 1, */
+		.svhs           = 1,
+		.muxsel         = MUXSEL(2, 3),
+		.pll            = PLL_28,
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,      /* must avoid, conflicts with the bt860 */
+	},
+	[BTTV_BOARD_IDS_EAGLE] = {
+		/* M G Berberich <berberic@forwiss.uni-passau.de> */
+		.name           = "IDS Eagle",
+		.video_inputs   = 4,
+		/* .audio_inputs= 0, */
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.svhs           = NO_SVHS,
+		.gpiomask       = 0,
+		.muxsel         = MUXSEL(2, 2, 2, 2),
+		.muxsel_hook    = eagle_muxsel,
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+	},
+	[BTTV_BOARD_PINNACLESAT] = {
+		.name           = "Pinnacle PCTV Sat",
+		.video_inputs   = 2,
+		/* .audio_inputs= 0, */
+		.svhs           = 1,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+		.muxsel         = MUXSEL(3, 1),
+		.pll            = PLL_28,
+		.no_gpioirq     = 1,
+		.has_dvb        = 1,
+	},
+	[BTTV_BOARD_FORMAC_PROTV] = {
+		.name           = "Formac ProTV II (bt878)",
+		.video_inputs   = 4,
+		/* .audio_inputs= 1, */
+		.svhs           = 3,
+		.gpiomask       = 2,
+		/* TV, Comp1, Composite over SVID con, SVID */
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 2, 2, 0, 0 },
+		.pll            = PLL_28,
+		.has_radio      = 1,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+	/* sound routing:
+		GPIO=0x00,0x01,0x03: mute (?)
+		0x02: both TV and radio (tuner: FM1216/I)
+		The card has onboard audio connectors labeled "cdrom" and "board",
+		not soldered here, though unknown wiring.
+		Card lacks: external audio in, pci subsystem id.
+	*/
+	},
+
+		/* ---- card 0x60 ---------------------------------- */
+	[BTTV_BOARD_MACHTV] = {
+		.name           = "MachTV",
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.svhs           = NO_SVHS,
+		.gpiomask       = 7,
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 0, 1, 2, 3},
+		.gpiomute 	= 4,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.pll            = PLL_28,
+	},
+	[BTTV_BOARD_EURESYS_PICOLO] = {
+		.name           = "Euresys Picolo",
+		.video_inputs   = 3,
+		/* .audio_inputs= 0, */
+		.svhs           = 2,
+		.gpiomask       = 0,
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+		.muxsel         = MUXSEL(2, 0, 1),
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_PV150] = {
+		/* Luc Van Hoeylandt <luc@e-magic.be> */
+		.name           = "ProVideo PV150", /* 0x4f */
+		.video_inputs   = 2,
+		/* .audio_inputs= 0, */
+		.svhs           = NO_SVHS,
+		.gpiomask       = 0,
+		.muxsel         = MUXSEL(2, 3),
+		.gpiomux        = { 0 },
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_AD_TVK503] = {
+		/* Hiroshi Takekawa <sian@big.or.jp> */
+		/* This card lacks subsystem ID */
+		.name           = "AD-TVK503", /* 0x63 */
+		.video_inputs   = 4,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.gpiomask       = 0x001e8007,
+		.muxsel         = MUXSEL(2, 3, 1, 0),
+		/*                  Tuner, Radio, external, internal, off,  on */
+		.gpiomux        = { 0x08,  0x0f,  0x0a,     0x08 },
+		.gpiomute 	= 0x0f,
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_NTSC,
+		.tuner_addr	= ADDR_UNSET,
+		.audio_mode_gpio= adtvk503_audio,
+	},
+
+		/* ---- card 0x64 ---------------------------------- */
+	[BTTV_BOARD_HERCULES_SM_TV] = {
+		.name           = "Hercules Smart TV Stereo",
+		.video_inputs   = 4,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.gpiomask       = 0x00,
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		/* Notes:
+		- card lacks subsystem ID
+		- stereo variant w/ daughter board with tda9874a @0xb0
+		- Audio Routing:
+			always from tda9874 independent of GPIO (?)
+			external line in: unknown
+		- Other chips: em78p156elp @ 0x96 (probably IR remote control)
+			hef4053 (instead 4052) for unknown function
+		*/
+	},
+	[BTTV_BOARD_PACETV] = {
+		.name           = "Pace TV & Radio Card",
+		.video_inputs   = 4,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		/* Tuner, CVid, SVid, CVid over SVid connector */
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomask       = 0,
+		.no_tda7432     = 1,
+		.tuner_type     = TUNER_PHILIPS_PAL_I,
+		.tuner_addr	= ADDR_UNSET,
+		.has_radio      = 1,
+		.pll            = PLL_28,
+		/* Bt878, Bt832, FI1246 tuner; no pci subsystem id
+		only internal line out: (4pin header) RGGL
+		Radio must be decoded by msp3410d (not routed through)*/
+		/*
+		.digital_mode   = DIGITAL_MODE_CAMERA,  todo!
+		*/
+	},
+	[BTTV_BOARD_IVC200] = {
+		/* Chris Willing <chris@vislab.usyd.edu.au> */
+		.name           = "IVC-200",
+		.video_inputs   = 1,
+		/* .audio_inputs= 0, */
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.svhs           = NO_SVHS,
+		.gpiomask       = 0xdf,
+		.muxsel         = MUXSEL(2),
+		.pll            = PLL_28,
+	},
+	[BTTV_BOARD_IVCE8784] = {
+		.name           = "IVCE-8784",
+		.video_inputs   = 1,
+		/* .audio_inputs= 0, */
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr     = ADDR_UNSET,
+		.svhs           = NO_SVHS,
+		.gpiomask       = 0xdf,
+		.muxsel         = MUXSEL(2),
+		.pll            = PLL_28,
+	},
+	[BTTV_BOARD_XGUARD] = {
+		.name           = "Grand X-Guard / Trust 814PCI",
+		.video_inputs   = 16,
+		/* .audio_inputs= 0, */
+		.svhs           = NO_SVHS,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.gpiomask2      = 0xff,
+		.muxsel         = MUXSEL(2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0),
+		.muxsel_hook    = xguard_muxsel,
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+		.pll            = PLL_28,
+	},
+
+		/* ---- card 0x68 ---------------------------------- */
+	[BTTV_BOARD_NEBULA_DIGITV] = {
+		.name           = "Nebula Electronics DigiTV",
+		.video_inputs   = 1,
+		.svhs           = NO_SVHS,
+		.muxsel         = MUXSEL(2, 3, 1, 0),
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.has_dvb        = 1,
+		.has_remote	= 1,
+		.gpiomask	= 0x1b,
+		.no_gpioirq     = 1,
+	},
+	[BTTV_BOARD_PV143] = {
+		/* Jorge Boncompte - DTI2 <jorge@dti2.net> */
+		.name           = "ProVideo PV143",
+		.video_inputs   = 4,
+		/* .audio_inputs= 0, */
+		.svhs           = NO_SVHS,
+		.gpiomask       = 0,
+		.muxsel         = MUXSEL(2, 3, 1, 0),
+		.gpiomux        = { 0 },
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_VD009X1_VD011_MINIDIN] = {
+		/* M.Klahr@phytec.de */
+		.name           = "PHYTEC VD-009-X1 VD-011 MiniDIN (bt878)",
+		.video_inputs   = 4,
+		/* .audio_inputs= 0, */
+		.svhs           = 3,
+		.gpiomask       = 0x00,
+		.muxsel         = MUXSEL(2, 3, 1, 0),
+		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_VD009X1_VD011_COMBI] = {
+		.name           = "PHYTEC VD-009-X1 VD-011 Combi (bt878)",
+		.video_inputs   = 4,
+		/* .audio_inputs= 0, */
+		.svhs           = 3,
+		.gpiomask       = 0x00,
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+
+		/* ---- card 0x6c ---------------------------------- */
+	[BTTV_BOARD_VD009_MINIDIN] = {
+		.name           = "PHYTEC VD-009 MiniDIN (bt878)",
+		.video_inputs   = 10,
+		/* .audio_inputs= 0, */
+		.svhs           = 9,
+		.gpiomask       = 0x00,
+		.gpiomask2      = 0x03, /* used for external vodeo mux */
+		.muxsel         = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 0),
+		.muxsel_hook	= phytec_muxsel,
+		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_VD009_COMBI] = {
+		.name           = "PHYTEC VD-009 Combi (bt878)",
+		.video_inputs   = 10,
+		/* .audio_inputs= 0, */
+		.svhs           = 9,
+		.gpiomask       = 0x00,
+		.gpiomask2      = 0x03, /* used for external vodeo mux */
+		.muxsel         = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 1),
+		.muxsel_hook	= phytec_muxsel,
+		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_IVC100] = {
+		.name           = "IVC-100",
+		.video_inputs   = 4,
+		/* .audio_inputs= 0, */
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.svhs           = NO_SVHS,
+		.gpiomask       = 0xdf,
+		.muxsel         = MUXSEL(2, 3, 1, 0),
+		.pll            = PLL_28,
+	},
+	[BTTV_BOARD_IVC120] = {
+		/* IVC-120G - Alan Garfield <alan@fromorbit.com> */
+		.name           = "IVC-120G",
+		.video_inputs   = 16,
+		/* .audio_inputs= 0, */
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.svhs           = NO_SVHS,   /* card has no svhs */
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+		.gpiomask       = 0x00,
+		.muxsel         = MUXSEL(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+		.muxsel_hook    = ivc120_muxsel,
+		.pll            = PLL_28,
+	},
+
+		/* ---- card 0x70 ---------------------------------- */
+	[BTTV_BOARD_PC_HDTV] = {
+		.name           = "pcHDTV HD-2000 TV",
+		.video_inputs   = 4,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.muxsel         = MUXSEL(2, 3, 1, 0),
+		.tuner_type     = TUNER_PHILIPS_FCV1236D,
+		.tuner_addr	= ADDR_UNSET,
+		.has_dvb        = 1,
+	},
+	[BTTV_BOARD_TWINHAN_DST] = {
+		.name           = "Twinhan DST + clones",
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.no_video       = 1,
+		.has_dvb        = 1,
+	},
+	[BTTV_BOARD_WINFASTVC100] = {
+		.name           = "Winfast VC100",
+		.video_inputs   = 3,
+		/* .audio_inputs= 0, */
+		.svhs           = 1,
+		/* Vid In, SVid In, Vid over SVid in connector */
+		.muxsel		= MUXSEL(3, 1, 1, 3),
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.pll            = PLL_28,
+	},
+	[BTTV_BOARD_TEV560] = {
+		.name           = "Teppro TEV-560/InterVision IV-560",
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.gpiomask       = 3,
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 1, 1, 1, 1 },
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.pll            = PLL_35,
+	},
+
+		/* ---- card 0x74 ---------------------------------- */
+	[BTTV_BOARD_SIMUS_GVC1100] = {
+		.name           = "SIMUS GVC1100",
+		.video_inputs   = 4,
+		/* .audio_inputs= 0, */
+		.svhs           = NO_SVHS,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.pll            = PLL_28,
+		.muxsel         = MUXSEL(2, 2, 2, 2),
+		.gpiomask       = 0x3F,
+		.muxsel_hook    = gvc1100_muxsel,
+	},
+	[BTTV_BOARD_NGSTV_PLUS] = {
+		/* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */
+		.name           = "NGS NGSTV+",
+		.video_inputs   = 3,
+		.svhs           = 2,
+		.gpiomask       = 0x008007,
+		.muxsel         = MUXSEL(2, 3, 0, 0),
+		.gpiomux        = { 0, 0, 0, 0 },
+		.gpiomute 	= 0x000003,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.has_remote     = 1,
+	},
+	[BTTV_BOARD_LMLBT4] = {
+		/* http://linuxmedialabs.com */
+		.name           = "LMLBT4",
+		.video_inputs   = 4, /* IN1,IN2,IN3,IN4 */
+		/* .audio_inputs= 0, */
+		.svhs           = NO_SVHS,
+		.muxsel         = MUXSEL(2, 3, 1, 0),
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_TEKRAM_M205] = {
+		/* Helmroos Harri <harri.helmroos@pp.inet.fi> */
+		.name           = "Tekram M205 PRO",
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.svhs           = 2,
+		.gpiomask       = 0x68,
+		.muxsel         = MUXSEL(2, 3, 1),
+		.gpiomux        = { 0x68, 0x68, 0x61, 0x61 },
+		.pll            = PLL_28,
+	},
+
+		/* ---- card 0x78 ---------------------------------- */
+	[BTTV_BOARD_CONTVFMI] = {
+		/* Javier Cendan Ares <jcendan@lycos.es> */
+		/* bt878 TV + FM without subsystem ID */
+		.name           = "Conceptronic CONTVFMi",
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.gpiomask       = 0x008007,
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 0, 1, 2, 2 },
+		.gpiomute 	= 3,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.has_remote     = 1,
+		.has_radio      = 1,
+	},
+	[BTTV_BOARD_PICOLO_TETRA_CHIP] = {
+		/*Eric DEBIEF <debief@telemsa.com>*/
+		/*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controlled*/
+		/* adds picolo_tetra_muxsel(), picolo_tetra_init(), the following declaration strucure, and #define BTTV_BOARD_PICOLO_TETRA_CHIP*/
+		/*0x79 in bttv.h*/
+		.name           = "Euresys Picolo Tetra",
+		.video_inputs   = 4,
+		/* .audio_inputs= 0, */
+		.svhs           = NO_SVHS,
+		.gpiomask       = 0,
+		.gpiomask2      = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+		/*878A input is always MUX0, see above.*/
+		.muxsel         = MUXSEL(2, 2, 2, 2),
+		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
+		.pll            = PLL_28,
+		.muxsel_hook    = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_SPIRIT_TV] = {
+		/* Spirit TV Tuner from http://spiritmodems.com.au */
+		/* Stafford Goodsell <surge@goliath.homeunix.org> */
+		.name           = "Spirit TV Tuner",
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.gpiomask       = 0x0000000f,
+		.muxsel         = MUXSEL(2, 1, 1),
+		.gpiomux        = { 0x02, 0x00, 0x00, 0x00 },
+		.tuner_type     = TUNER_TEMIC_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.no_msp34xx     = 1,
+	},
+	[BTTV_BOARD_AVDVBT_771] = {
+		/* Wolfram Joost <wojo@frokaschwei.de> */
+		.name           = "AVerMedia AVerTV DVB-T 771",
+		.video_inputs   = 2,
+		.svhs           = 1,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.muxsel         = MUXSEL(3, 3),
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+		.pll            = PLL_28,
+		.has_dvb        = 1,
+		.no_gpioirq     = 1,
+		.has_remote     = 1,
+	},
+		/* ---- card 0x7c ---------------------------------- */
+	[BTTV_BOARD_AVDVBT_761] = {
+		/* Matt Jesson <dvb@jesson.eclipse.co.uk> */
+		/* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */
+		.name           = "AverMedia AverTV DVB-T 761",
+		.video_inputs   = 2,
+		.svhs           = 1,
+		.muxsel         = MUXSEL(3, 1, 2, 0), /* Comp0, S-Video, ?, ? */
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.has_dvb        = 1,
+		.no_gpioirq     = 1,
+		.has_remote     = 1,
+	},
+	[BTTV_BOARD_MATRIX_VISIONSQ] = {
+		/* andre.schwarz@matrix-vision.de */
+		.name		= "MATRIX Vision Sigma-SQ",
+		.video_inputs	= 16,
+		/* .audio_inputs= 0, */
+		.svhs		= NO_SVHS,
+		.gpiomask	= 0x0,
+		.muxsel		= MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3),
+		.muxsel_hook	= sigmaSQ_muxsel,
+		.gpiomux	= { 0 },
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_MATRIX_VISIONSLC] = {
+		/* andre.schwarz@matrix-vision.de */
+		.name		= "MATRIX Vision Sigma-SLC",
+		.video_inputs	= 4,
+		/* .audio_inputs= 0, */
+		.svhs		= NO_SVHS,
+		.gpiomask	= 0x0,
+		.muxsel		= MUXSEL(2, 2, 2, 2),
+		.muxsel_hook	= sigmaSLC_muxsel,
+		.gpiomux	= { 0 },
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+		/* BTTV_BOARD_APAC_VIEWCOMP */
+	[BTTV_BOARD_APAC_VIEWCOMP] = {
+		/* Attila Kondoros <attila.kondoros@chello.hu> */
+		/* bt878 TV + FM 0x00000000 subsystem ID */
+		.name           = "APAC Viewcomp 878(AMAX)",
+		.video_inputs   = 2,
+		/* .audio_inputs= 1, */
+		.svhs           = NO_SVHS,
+		.gpiomask       = 0xFF,
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 2, 0, 0, 0 },
+		.gpiomute 	= 10,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.has_remote     = 1,   /* miniremote works, see ir-kbd-gpio.c */
+		.has_radio      = 1,   /* not every card has radio */
+	},
+
+		/* ---- card 0x80 ---------------------------------- */
+	[BTTV_BOARD_DVICO_DVBT_LITE] = {
+		/* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
+		.name           = "DViCO FusionHDTV DVB-T Lite",
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+		.pll            = PLL_28,
+		.no_video       = 1,
+		.has_dvb        = 1,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_VGEAR_MYVCD] = {
+		/* Steven <photon38@pchome.com.tw> */
+		.name           = "V-Gear MyVCD",
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.gpiomask       = 0x3f,
+		.muxsel         = MUXSEL(2, 3, 1, 0),
+		.gpiomux        = {0x31, 0x31, 0x31, 0x31 },
+		.gpiomute 	= 0x31,
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_NTSC_M,
+		.tuner_addr	= ADDR_UNSET,
+		.has_radio      = 0,
+	},
+	[BTTV_BOARD_SUPER_TV] = {
+		/* Rick C <cryptdragoon@gmail.com> */
+		.name           = "Super TV Tuner",
+		.video_inputs   = 4,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.muxsel         = MUXSEL(2, 3, 1, 0),
+		.tuner_type     = TUNER_PHILIPS_NTSC,
+		.tuner_addr	= ADDR_UNSET,
+		.gpiomask       = 0x008007,
+		.gpiomux        = { 0, 0x000001,0,0 },
+		.has_radio      = 1,
+	},
+	[BTTV_BOARD_TIBET_CS16] = {
+		/* Chris Fanning <video4linux@haydon.net> */
+		.name           = "Tibet Systems 'Progress DVR' CS16",
+		.video_inputs   = 16,
+		/* .audio_inputs= 0, */
+		.svhs           = NO_SVHS,
+		.muxsel         = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),
+		.pll		= PLL_28,
+		.no_msp34xx     = 1,
+		.no_tda7432	= 1,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.muxsel_hook    = tibetCS16_muxsel,
+	},
+	[BTTV_BOARD_KODICOM_4400R] = {
+		/* Bill Brack <wbrack@mmm.com.hk> */
+		/*
+		* Note that, because of the card's wiring, the "master"
+		* BT878A chip (i.e. the one which controls the analog switch
+		* and must use this card type) is the 2nd one detected.  The
+		* other 3 chips should use card type 0x85, whose description
+		* follows this one.  There is a EEPROM on the card (which is
+		* connected to the I2C of one of those other chips), but is
+		* not currently handled.  There is also a facility for a
+		* "monitor", which is also not currently implemented.
+		*/
+		.name           = "Kodicom 4400R (master)",
+		.video_inputs	= 16,
+		/* .audio_inputs= 0, */
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.svhs		= NO_SVHS,
+		/* GPIO bits 0-9 used for analog switch:
+		*   00 - 03:	camera selector
+		*   04 - 06:	channel (controller) selector
+		*   07:	data (1->on, 0->off)
+		*   08:	strobe
+		*   09:	reset
+		* bit 16 is input from sync separator for the channel
+		*/
+		.gpiomask	= 0x0003ff,
+		.no_gpioirq     = 1,
+		.muxsel		= MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3),
+		.pll		= PLL_28,
+		.no_msp34xx	= 1,
+		.no_tda7432	= 1,
+		.muxsel_hook	= kodicom4400r_muxsel,
+	},
+	[BTTV_BOARD_KODICOM_4400R_SL] = {
+		/* Bill Brack <wbrack@mmm.com.hk> */
+		/* Note that, for reasons unknown, the "master" BT878A chip (i.e. the
+		* one which controls the analog switch, and must use the card type)
+		* is the 2nd one detected.  The other 3 chips should use this card
+		* type
+		*/
+		.name		= "Kodicom 4400R (slave)",
+		.video_inputs	= 16,
+		/* .audio_inputs= 0, */
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.svhs		= NO_SVHS,
+		.gpiomask	= 0x010000,
+		.no_gpioirq     = 1,
+		.muxsel		= MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3),
+		.pll		= PLL_28,
+		.no_msp34xx	= 1,
+		.no_tda7432	= 1,
+		.muxsel_hook	= kodicom4400r_muxsel,
+	},
+		/* ---- card 0x86---------------------------------- */
+	[BTTV_BOARD_ADLINK_RTV24] = {
+		/* Michael Henson <mhenson@clarityvi.com> */
+		/* Adlink RTV24 with special unlock codes */
+		.name           = "Adlink RTV24",
+		.video_inputs   = 4,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.muxsel         = MUXSEL(2, 3, 1, 0),
+		.tuner_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.pll            = PLL_28,
+	},
+		/* ---- card 0x87---------------------------------- */
+	[BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE] = {
+		/* Michael Krufky <mkrufky@m1k.net> */
+		.name           = "DViCO FusionHDTV 5 Lite",
+		.tuner_type     = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */
+		.tuner_addr	= ADDR_UNSET,
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.muxsel		= MUXSEL(2, 3, 1),
+		.gpiomask       = 0x00e00007,
+		.gpiomux        = { 0x00400005, 0, 0x00000001, 0 },
+		.gpiomute 	= 0x00c00007,
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+		.has_dvb        = 1,
+	},
+		/* ---- card 0x88---------------------------------- */
+	[BTTV_BOARD_ACORP_Y878F] = {
+		/* Mauro Carvalho Chehab <mchehab@infradead.org> */
+		.name		= "Acorp Y878F",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0x01fe00,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 0x001e00, 0, 0x018000, 0x014000 },
+		.gpiomute 	= 0x002000,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_YMEC_TVF66T5_B_DFF,
+		.tuner_addr	= 0xc1 >>1,
+		.has_radio	= 1,
+	},
+		/* ---- card 0x89 ---------------------------------- */
+	[BTTV_BOARD_CONCEPTRONIC_CTVFMI2] = {
+		.name           = "Conceptronic CTVFMi v2",
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.gpiomask       = 0x001c0007,
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 0, 1, 2, 2 },
+		.gpiomute 	= 3,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_TENA_9533_DI,
+		.tuner_addr	= ADDR_UNSET,
+		.has_remote     = 1,
+		.has_radio      = 1,
+	},
+		/* ---- card 0x8a ---------------------------------- */
+	[BTTV_BOARD_PV_BT878P_2E] = {
+		.name		= "Prolink Pixelview PV-BT878P+ (Rev.2E)",
+		.video_inputs	= 5,
+		/* .audio_inputs= 1, */
+		.svhs		= 3,
+		.has_dig_in	= 1,
+		.gpiomask	= 0x01fe00,
+		.muxsel		= MUXSEL(2, 3, 1, 1, 0), /* in 4 is digital */
+		/* .digital_mode= DIGITAL_MODE_CAMERA, */
+		.gpiomux	= { 0x00400, 0x10400, 0x04400, 0x80000 },
+		.gpiomute	= 0x12400,
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_LG_PAL_FM,
+		.tuner_addr	= ADDR_UNSET,
+		.has_remote	= 1,
+	},
+		/* ---- card 0x8b ---------------------------------- */
+	[BTTV_BOARD_PV_M4900] = {
+		/* Sérgio Fortier <sergiofortier@yahoo.com.br> */
+		.name           = "Prolink PixelView PlayTV MPEG2 PV-M4900",
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.gpiomask       = 0x3f,
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 0x21, 0x20, 0x24, 0x2c },
+		.gpiomute 	= 0x29,
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_YMEC_TVF_5533MF,
+		.tuner_addr     = ADDR_UNSET,
+		.has_radio      = 1,
+		.has_remote     = 1,
+	},
+		/* ---- card 0x8c ---------------------------------- */
+	/* Has four Bt878 chips behind a PCI bridge, each chip has:
+	     one external BNC composite input (mux 2)
+	     three internal composite inputs (unknown muxes)
+	     an 18-bit stereo A/D (CS5331A), which has:
+	       one external stereo unblanced (RCA) audio connection
+	       one (or 3?) internal stereo balanced (XLR) audio connection
+	       input is selected via gpio to a 14052B mux
+		 (mask=0x300, unbal=0x000, bal=0x100, ??=0x200,0x300)
+	       gain is controlled via an X9221A chip on the I2C bus @0x28
+	       sample rate is controlled via gpio to an MK1413S
+		 (mask=0x3, 32kHz=0x0, 44.1kHz=0x1, 48kHz=0x2, ??=0x3)
+	     There is neither a tuner nor an svideo input. */
+	[BTTV_BOARD_OSPREY440]  = {
+		.name           = "Osprey 440",
+		.video_inputs   = 4,
+		/* .audio_inputs= 2, */
+		.svhs           = NO_SVHS,
+		.muxsel         = MUXSEL(2, 3, 0, 1), /* 3,0,1 are guesses */
+		.gpiomask	= 0x303,
+		.gpiomute	= 0x000, /* int + 32kHz */
+		.gpiomux	= { 0, 0, 0x000, 0x100},
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr     = ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+	},
+		/* ---- card 0x8d ---------------------------------- */
+	[BTTV_BOARD_ASOUND_SKYEYE] = {
+		.name		= "Asound Skyeye PCTV",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 15,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 2, 0, 0, 0 },
+		.gpiomute 	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_NTSC,
+		.tuner_addr	= ADDR_UNSET,
+	},
+		/* ---- card 0x8e ---------------------------------- */
+	[BTTV_BOARD_SABRENT_TVFM] = {
+		.name		= "Sabrent TV-FM (bttv version)",
+		.video_inputs	= 3,
+		/* .audio_inputs= 1, */
+		.svhs		= 2,
+		.gpiomask	= 0x108007,
+		.muxsel		= MUXSEL(2, 3, 1, 1),
+		.gpiomux 	= { 100000, 100002, 100002, 100000 },
+		.no_msp34xx	= 1,
+		.no_tda7432     = 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_TNF_5335MF,
+		.tuner_addr	= ADDR_UNSET,
+		.has_radio      = 1,
+	},
+	/* ---- card 0x8f ---------------------------------- */
+	[BTTV_BOARD_HAUPPAUGE_IMPACTVCB] = {
+		.name		= "Hauppauge ImpactVCB (bt878)",
+		.video_inputs	= 4,
+		/* .audio_inputs= 0, */
+		.svhs		= NO_SVHS,
+		.gpiomask	= 0x0f, /* old: 7 */
+		.muxsel		= MUXSEL(0, 1, 3, 2), /* Composite 0-3 */
+		.no_msp34xx	= 1,
+		.no_tda7432     = 1,
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_MACHTV_MAGICTV] = {
+		/* Julian Calaby <julian.calaby@gmail.com>
+		 * Slightly different from original MachTV definition (0x60)
+
+		 * FIXME: RegSpy says gpiomask should be "0x001c800f", but it
+		 * stuffs up remote chip. Bug is a pin on the jaecs is not set
+		 * properly (methinks) causing no keyup bits being set */
+
+		.name           = "MagicTV", /* rebranded MachTV */
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.gpiomask       = 7,
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 0, 1, 2, 3 },
+		.gpiomute 	= 4,
+		.tuner_type     = TUNER_TEMIC_4009FR5_PAL,
+		.tuner_addr     = ADDR_UNSET,
+		.pll            = PLL_28,
+		.has_radio      = 1,
+		.has_remote     = 1,
+	},
+	[BTTV_BOARD_SSAI_SECURITY] = {
+		.name		= "SSAI Security Video Interface",
+		.video_inputs	= 4,
+		/* .audio_inputs= 0, */
+		.svhs		= NO_SVHS,
+		.muxsel		= MUXSEL(0, 1, 2, 3),
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_SSAI_ULTRASOUND] = {
+		.name		= "SSAI Ultrasound Video Interface",
+		.video_inputs	= 2,
+		/* .audio_inputs= 0, */
+		.svhs		= 1,
+		.muxsel		= MUXSEL(2, 0, 1, 3),
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	/* ---- card 0x94---------------------------------- */
+	[BTTV_BOARD_DVICO_FUSIONHDTV_2] = {
+		.name           = "DViCO FusionHDTV 2",
+		.tuner_type     = TUNER_PHILIPS_FCV1236D,
+		.tuner_addr	= ADDR_UNSET,
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.muxsel		= MUXSEL(2, 3, 1),
+		.gpiomask       = 0x00e00007,
+		.gpiomux        = { 0x00400005, 0, 0x00000001, 0 },
+		.gpiomute 	= 0x00c00007,
+		.no_msp34xx     = 1,
+		.no_tda7432     = 1,
+	},
+	/* ---- card 0x95---------------------------------- */
+	[BTTV_BOARD_TYPHOON_TVTUNERPCI] = {
+		.name           = "Typhoon TV-Tuner PCI (50684)",
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.gpiomask       = 0x3014f,
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 0x20001,0x10001, 0, 0 },
+		.gpiomute       = 10,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_PAL_I,
+		.tuner_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_GEOVISION_GV600] = {
+		/* emhn@usb.ve */
+		.name		= "Geovision GV-600",
+		.video_inputs	= 16,
+		/* .audio_inputs= 0, */
+		.svhs		= NO_SVHS,
+		.gpiomask	= 0x0,
+		.muxsel		= MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),
+		.muxsel_hook	= geovision_muxsel,
+		.gpiomux	= { 0 },
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_KOZUMI_KTV_01C] = {
+		/* Mauro Lacy <mauro@lacy.com.ar>
+		 * Based on MagicTV and Conceptronic CONTVFMi */
+
+		.name           = "Kozumi KTV-01C",
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		.gpiomask       = 0x008007,
+		.muxsel         = MUXSEL(2, 3, 1, 1),
+		.gpiomux        = { 0, 1, 2, 2 }, /* CONTVFMi */
+		.gpiomute 	= 3, /* CONTVFMi */
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* TCL MK3 */
+		.tuner_addr     = ADDR_UNSET,
+		.pll            = PLL_28,
+		.has_radio      = 1,
+		.has_remote     = 1,
+	},
+	[BTTV_BOARD_ENLTV_FM_2] = {
+		/* Encore TV Tuner Pro ENL TV-FM-2
+		   Mauro Carvalho Chehab <mchehab@infradead.org */
+		.name           = "Encore ENL TV-FM-2",
+		.video_inputs   = 3,
+		/* .audio_inputs= 1, */
+		.svhs           = 2,
+		/* bit 6          -> IR disabled
+		   bit 18/17 = 00 -> mute
+			       01 -> enable external audio input
+			       10 -> internal audio input (mono?)
+			       11 -> internal audio input
+		 */
+		.gpiomask       = 0x060040,
+		.muxsel         = MUXSEL(2, 3, 3),
+		.gpiomux        = { 0x60000, 0x60000, 0x20000, 0x20000 },
+		.gpiomute 	= 0,
+		.tuner_type	= TUNER_TCL_MF02GIP_5N,
+		.tuner_addr     = ADDR_UNSET,
+		.pll            = PLL_28,
+		.has_radio      = 1,
+		.has_remote     = 1,
+	},
+		[BTTV_BOARD_VD012] = {
+		/* D.Heer@Phytec.de */
+		.name           = "PHYTEC VD-012 (bt878)",
+		.video_inputs   = 4,
+		/* .audio_inputs= 0, */
+		.svhs           = NO_SVHS,
+		.gpiomask       = 0x00,
+		.muxsel         = MUXSEL(0, 2, 3, 1),
+		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+		[BTTV_BOARD_VD012_X1] = {
+		/* D.Heer@Phytec.de */
+		.name           = "PHYTEC VD-012-X1 (bt878)",
+		.video_inputs   = 4,
+		/* .audio_inputs= 0, */
+		.svhs           = 3,
+		.gpiomask       = 0x00,
+		.muxsel         = MUXSEL(2, 3, 1),
+		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+		[BTTV_BOARD_VD012_X2] = {
+		/* D.Heer@Phytec.de */
+		.name           = "PHYTEC VD-012-X2 (bt878)",
+		.video_inputs   = 4,
+		/* .audio_inputs= 0, */
+		.svhs           = 3,
+		.gpiomask       = 0x00,
+		.muxsel         = MUXSEL(3, 2, 1),
+		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+		[BTTV_BOARD_GEOVISION_GV800S] = {
+		/* Bruno Christo <bchristo@inf.ufsm.br>
+		 *
+		 * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
+		 * 	1 audio input  per BT878A = 4 audio inputs
+		 * 	4 video inputs per BT878A = 16 video inputs
+		 * This is the first BT878A chip of the GV-800(S). It's the
+		 * "master" chip and it controls the video inputs through an
+		 * analog multiplexer (a CD22M3494) via some GPIO pins. The
+		 * slaves should use card type 0x9e (following this one).
+		 * There is a EEPROM on the card which is currently not handled.
+		 * The audio input is not working yet.
+		 */
+		.name           = "Geovision GV-800(S) (master)",
+		.video_inputs   = 4,
+		/* .audio_inputs= 1, */
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.svhs           = NO_SVHS,
+		.gpiomask	= 0xf107f,
+		.no_gpioirq     = 1,
+		.muxsel		= MUXSEL(2, 2, 2, 2),
+		.pll		= PLL_28,
+		.no_msp34xx	= 1,
+		.no_tda7432	= 1,
+		.muxsel_hook    = gv800s_muxsel,
+	},
+		[BTTV_BOARD_GEOVISION_GV800S_SL] = {
+		/* Bruno Christo <bchristo@inf.ufsm.br>
+		 *
+		 * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
+		 * 	1 audio input  per BT878A = 4 audio inputs
+		 * 	4 video inputs per BT878A = 16 video inputs
+		 * The 3 other BT878A chips are "slave" chips of the GV-800(S)
+		 * and should use this card type.
+		 * The audio input is not working yet.
+		 */
+		.name           = "Geovision GV-800(S) (slave)",
+		.video_inputs   = 4,
+		/* .audio_inputs= 1, */
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.svhs           = NO_SVHS,
+		.gpiomask	= 0x00,
+		.no_gpioirq     = 1,
+		.muxsel		= MUXSEL(2, 2, 2, 2),
+		.pll		= PLL_28,
+		.no_msp34xx	= 1,
+		.no_tda7432	= 1,
+		.muxsel_hook    = gv800s_muxsel,
+	},
+	[BTTV_BOARD_PV183] = {
+		.name           = "ProVideo PV183", /* 0x9f */
+		.video_inputs   = 2,
+		/* .audio_inputs= 0, */
+		.svhs           = NO_SVHS,
+		.gpiomask       = 0,
+		.muxsel         = MUXSEL(2, 3),
+		.gpiomux        = { 0 },
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+	},
+	[BTTV_BOARD_TVT_TD3116] = {
+		.name           = "Tongwei Video Technology TD-3116",
+		.video_inputs   = 16,
+		.gpiomask       = 0xc00ff,
+		.muxsel         = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),
+		.muxsel_hook    = td3116_muxsel,
+		.svhs           = NO_SVHS,
+		.pll		= PLL_28,
+		.tuner_type     = TUNER_ABSENT,
+	},
+	[BTTV_BOARD_APOSONIC_WDVR] = {
+		.name           = "Aposonic W-DVR",
+		.video_inputs   = 4,
+		.svhs           = NO_SVHS,
+		.muxsel         = MUXSEL(2, 3, 1, 0),
+		.tuner_type     = TUNER_ABSENT,
+	},
+
+};
+
+static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
+
+/* ----------------------------------------------------------------------- */
+
+static unsigned char eeprom_data[256];
+
+/*
+ * identify card
+ */
+void __devinit bttv_idcard(struct bttv *btv)
+{
+	unsigned int gpiobits;
+	int i,type;
+
+	/* read PCI subsystem ID */
+	btv->cardid  = btv->c.pci->subsystem_device << 16;
+	btv->cardid |= btv->c.pci->subsystem_vendor;
+
+	if (0 != btv->cardid && 0xffffffff != btv->cardid) {
+		/* look for the card */
+		for (type = -1, i = 0; cards[i].id != 0; i++)
+			if (cards[i].id  == btv->cardid)
+				type = i;
+
+		if (type != -1) {
+			/* found it */
+			pr_info("%d: detected: %s [card=%d], PCI subsystem ID is %04x:%04x\n",
+				btv->c.nr, cards[type].name, cards[type].cardnr,
+				btv->cardid & 0xffff,
+				(btv->cardid >> 16) & 0xffff);
+			btv->c.type = cards[type].cardnr;
+		} else {
+			/* 404 */
+			pr_info("%d: subsystem: %04x:%04x (UNKNOWN)\n",
+				btv->c.nr, btv->cardid & 0xffff,
+				(btv->cardid >> 16) & 0xffff);
+			pr_debug("please mail id, board name and the correct card= insmod option to linux-media@vger.kernel.org\n");
+		}
+	}
+
+	/* let the user override the autodetected type */
+	if (card[btv->c.nr] < bttv_num_tvcards)
+		btv->c.type=card[btv->c.nr];
+
+	/* print which card config we are using */
+	pr_info("%d: using: %s [card=%d,%s]\n",
+		btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type,
+		card[btv->c.nr] < bttv_num_tvcards
+		? "insmod option" : "autodetected");
+
+	/* overwrite gpio stuff ?? */
+	if (UNSET == audioall && UNSET == audiomux[0])
+		return;
+
+	if (UNSET != audiomux[0]) {
+		gpiobits = 0;
+		for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) {
+			bttv_tvcards[btv->c.type].gpiomux[i] = audiomux[i];
+			gpiobits |= audiomux[i];
+		}
+	} else {
+		gpiobits = audioall;
+		for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) {
+			bttv_tvcards[btv->c.type].gpiomux[i] = audioall;
+		}
+	}
+	bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits;
+	pr_info("%d: gpio config override: mask=0x%x, mux=",
+		btv->c.nr, bttv_tvcards[btv->c.type].gpiomask);
+	for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) {
+		pr_cont("%s0x%x",
+			i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]);
+	}
+	pr_cont("\n");
+}
+
+/*
+ * (most) board specific initialisations goes here
+ */
+
+/* Some Modular Technology cards have an eeprom, but no subsystem ID */
+static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256])
+{
+	int type = -1;
+
+	if (0 == strncmp(eeprom_data,"GET MM20xPCTV",13))
+		type = BTTV_BOARD_MODTEC_205;
+	else if (0 == strncmp(eeprom_data+20,"Picolo",7))
+		type = BTTV_BOARD_EURESYS_PICOLO;
+	else if (eeprom_data[0] == 0x84 && eeprom_data[2]== 0)
+		type = BTTV_BOARD_HAUPPAUGE; /* old bt848 */
+
+	if (-1 != type) {
+		btv->c.type = type;
+		pr_info("%d: detected by eeprom: %s [card=%d]\n",
+			btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type);
+	}
+}
+
+static void flyvideo_gpio(struct bttv *btv)
+{
+	int gpio, has_remote, has_radio, is_capture_only;
+	int is_lr90, has_tda9820_tda9821;
+	int tuner_type = UNSET, ttype;
+
+	gpio_inout(0xffffff, 0);
+	udelay(8);  /* without this we would see the 0x1800 mask */
+	gpio = gpio_read();
+	/* FIXME: must restore OUR_EN ??? */
+
+	/* all cards provide GPIO info, some have an additional eeprom
+	 * LR50: GPIO coding can be found lower right CP1 .. CP9
+	 *       CP9=GPIO23 .. CP1=GPIO15; when OPEN, the corresponding GPIO reads 1.
+	 *       GPIO14-12: n.c.
+	 * LR90: GP9=GPIO23 .. GP1=GPIO15 (right above the bt878)
+
+	 * lowest 3 bytes are remote control codes (no handshake needed)
+	 * xxxFFF: No remote control chip soldered
+	 * xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered
+	 * Note: Some bits are Audio_Mask !
+	 */
+	ttype = (gpio & 0x0f0000) >> 16;
+	switch (ttype) {
+	case 0x0:
+		tuner_type = 2;  /* NTSC, e.g. TPI8NSR11P */
+		break;
+	case 0x2:
+		tuner_type = 39; /* LG NTSC (newer TAPC series) TAPC-H701P */
+		break;
+	case 0x4:
+		tuner_type = 5;  /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */
+		break;
+	case 0x6:
+		tuner_type = 37; /* LG PAL (newer TAPC series) TAPC-G702P */
+		break;
+	case 0xC:
+		tuner_type = 3;  /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */
+		break;
+	default:
+		pr_info("%d: FlyVideo_gpio: unknown tuner type\n", btv->c.nr);
+		break;
+	}
+
+	has_remote          =   gpio & 0x800000;
+	has_radio	    =   gpio & 0x400000;
+	/*   unknown                   0x200000;
+	 *   unknown2                  0x100000; */
+	is_capture_only     = !(gpio & 0x008000); /* GPIO15 */
+	has_tda9820_tda9821 = !(gpio & 0x004000);
+	is_lr90             = !(gpio & 0x002000); /* else LR26/LR50 (LR38/LR51 f. capture only) */
+	/*
+	 * gpio & 0x001000    output bit for audio routing */
+
+	if (is_capture_only)
+		tuner_type = TUNER_ABSENT; /* No tuner present */
+
+	pr_info("%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n",
+		btv->c.nr, has_radio ? "yes" : "no",
+		has_remote ? "yes" : "no", tuner_type, gpio);
+	pr_info("%d: FlyVideo  LR90=%s tda9821/tda9820=%s capture_only=%s\n",
+		btv->c.nr, is_lr90 ? "yes" : "no",
+		has_tda9820_tda9821 ? "yes" : "no",
+		is_capture_only ? "yes" : "no");
+
+	if (tuner_type != UNSET) /* only set if known tuner autodetected, else let insmod option through */
+		btv->tuner_type = tuner_type;
+	btv->has_radio = has_radio;
+
+	/* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80
+	 * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00
+	 * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */
+	if (has_tda9820_tda9821)
+		btv->audio_mode_gpio = lt9415_audio;
+	/* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */
+}
+
+static int miro_tunermap[] = { 0,6,2,3,   4,5,6,0,  3,0,4,5,  5,2,16,1,
+			       14,2,17,1, 4,1,4,3,  1,2,16,1, 4,4,4,4 };
+static int miro_fmtuner[]  = { 0,0,0,0,   0,0,0,0,  0,0,0,0,  0,0,0,1,
+			       1,1,1,1,   1,1,1,0,  0,0,0,0,  0,1,0,0 };
+
+static void miro_pinnacle_gpio(struct bttv *btv)
+{
+	int id,msp,gpio;
+	char *info;
+
+	gpio_inout(0xffffff, 0);
+	gpio = gpio_read();
+	id   = ((gpio>>10) & 63) -1;
+	msp  = bttv_I2CRead(btv, I2C_ADDR_MSP3400, "MSP34xx");
+	if (id < 32) {
+		btv->tuner_type = miro_tunermap[id];
+		if (0 == (gpio & 0x20)) {
+			btv->has_radio = 1;
+			if (!miro_fmtuner[id]) {
+				btv->has_matchbox = 1;
+				btv->mbox_we    = (1<<6);
+				btv->mbox_most  = (1<<7);
+				btv->mbox_clk   = (1<<8);
+				btv->mbox_data  = (1<<9);
+				btv->mbox_mask  = (1<<6)|(1<<7)|(1<<8)|(1<<9);
+			}
+		} else {
+			btv->has_radio = 0;
+		}
+		if (-1 != msp) {
+			if (btv->c.type == BTTV_BOARD_MIRO)
+				btv->c.type = BTTV_BOARD_MIROPRO;
+			if (btv->c.type == BTTV_BOARD_PINNACLE)
+				btv->c.type = BTTV_BOARD_PINNACLEPRO;
+		}
+		pr_info("%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
+			btv->c.nr, id+1, btv->tuner_type,
+			!btv->has_radio ? "no" :
+			(btv->has_matchbox ? "matchbox" : "fmtuner"),
+			(-1 == msp) ? "no" : "yes");
+	} else {
+		/* new cards with microtune tuner */
+		id = 63 - id;
+		btv->has_radio = 0;
+		switch (id) {
+		case 1:
+			info = "PAL / mono";
+			btv->tda9887_conf = TDA9887_INTERCARRIER;
+			break;
+		case 2:
+			info = "PAL+SECAM / stereo";
+			btv->has_radio = 1;
+			btv->tda9887_conf = TDA9887_QSS;
+			break;
+		case 3:
+			info = "NTSC / stereo";
+			btv->has_radio = 1;
+			btv->tda9887_conf = TDA9887_QSS;
+			break;
+		case 4:
+			info = "PAL+SECAM / mono";
+			btv->tda9887_conf = TDA9887_QSS;
+			break;
+		case 5:
+			info = "NTSC / mono";
+			btv->tda9887_conf = TDA9887_INTERCARRIER;
+			break;
+		case 6:
+			info = "NTSC / stereo";
+			btv->tda9887_conf = TDA9887_INTERCARRIER;
+			break;
+		case 7:
+			info = "PAL / stereo";
+			btv->tda9887_conf = TDA9887_INTERCARRIER;
+			break;
+		default:
+			info = "oops: unknown card";
+			break;
+		}
+		if (-1 != msp)
+			btv->c.type = BTTV_BOARD_PINNACLEPRO;
+		pr_info("%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n",
+			btv->c.nr, id, info, btv->has_radio ? "yes" : "no");
+		btv->tuner_type = TUNER_MT2032;
+	}
+}
+
+/* GPIO21   L: Buffer aktiv, H: Buffer inaktiv */
+#define LM1882_SYNC_DRIVE     0x200000L
+
+static void init_ids_eagle(struct bttv *btv)
+{
+	gpio_inout(0xffffff,0xFFFF37);
+	gpio_write(0x200020);
+
+	/* flash strobe inverter ?! */
+	gpio_write(0x200024);
+
+	/* switch sync drive off */
+	gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE);
+
+	/* set BT848 muxel to 2 */
+	btaor((2)<<5, ~(2<<5), BT848_IFORM);
+}
+
+/* Muxsel helper for the IDS Eagle.
+ * the eagles does not use the standard muxsel-bits but
+ * has its own multiplexer */
+static void eagle_muxsel(struct bttv *btv, unsigned int input)
+{
+	gpio_bits(3, input & 3);
+
+	/* composite */
+	/* set chroma ADC to sleep */
+	btor(BT848_ADC_C_SLEEP, BT848_ADC);
+	/* set to composite video */
+	btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
+	btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
+
+	/* switch sync drive off */
+	gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE);
+}
+
+static void gvc1100_muxsel(struct bttv *btv, unsigned int input)
+{
+	static const int masks[] = {0x30, 0x01, 0x12, 0x23};
+	gpio_write(masks[input%4]);
+}
+
+/* LMLBT4x initialization - to allow access to GPIO bits for sensors input and
+   alarms output
+
+   GPIObit    | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+   assignment | TI | O3|INx| O2| O1|IN4|IN3|IN2|IN1|   |   |
+
+   IN - sensor inputs, INx - sensor inputs and TI XORed together
+   O1,O2,O3 - alarm outputs (relays)
+
+   OUT ENABLE   1    1   0  . 1  1   0   0 . 0   0   0    0   = 0x6C0
+
+*/
+
+static void init_lmlbt4x(struct bttv *btv)
+{
+	pr_debug("LMLBT4x init\n");
+	btwrite(0x000000, BT848_GPIO_REG_INP);
+	gpio_inout(0xffffff, 0x0006C0);
+	gpio_write(0x000000);
+}
+
+static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input)
+{
+	unsigned int inmux = input % 8;
+	gpio_inout( 0xf, 0xf );
+	gpio_bits( 0xf, inmux );
+}
+
+static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input)
+{
+	unsigned int inmux = input % 4;
+	gpio_inout( 3<<9, 3<<9 );
+	gpio_bits( 3<<9, inmux<<9 );
+}
+
+static void geovision_muxsel(struct bttv *btv, unsigned int input)
+{
+	unsigned int inmux = input % 16;
+	gpio_inout(0xf, 0xf);
+	gpio_bits(0xf, inmux);
+}
+
+/*
+ * The TD3116 has 2 74HC4051 muxes wired to the MUX0 input of a bt878.
+ * The first 74HC4051 has the lower 8 inputs, the second one the higher 8.
+ * The muxes are controlled via a 74HC373 latch which is connected to
+ * GPIOs 0-7. GPIO 18 is connected to the LE signal of the latch.
+ * Q0 of the latch is connected to the Enable (~E) input of the first
+ * 74HC4051. Q1 - Q3 are connected to S0 - S2 of the same 74HC4051.
+ * Q4 - Q7 are connected to the second 74HC4051 in the same way.
+ */
+
+static void td3116_latch_value(struct bttv *btv, u32 value)
+{
+	gpio_bits((1<<18) | 0xff, value);
+	gpio_bits((1<<18) | 0xff, (1<<18) | value);
+	udelay(1);
+	gpio_bits((1<<18) | 0xff, value);
+}
+
+static void td3116_muxsel(struct bttv *btv, unsigned int input)
+{
+	u32 value;
+	u32 highbit;
+
+	highbit = (input & 0x8) >> 3 ;
+
+	/* Disable outputs and set value in the mux */
+	value = 0x11; /* Disable outputs */
+	value |= ((input & 0x7) << 1)  << (4 * highbit);
+	td3116_latch_value(btv, value);
+
+	/* Enable the correct output */
+	value &= ~0x11;
+	value |= ((highbit ^ 0x1) << 4) | highbit;
+	td3116_latch_value(btv, value);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void bttv_reset_audio(struct bttv *btv)
+{
+	/*
+	 * BT878A has a audio-reset register.
+	 * 1. This register is an audio reset function but it is in
+	 *    function-0 (video capture) address space.
+	 * 2. It is enough to do this once per power-up of the card.
+	 * 3. There is a typo in the Conexant doc -- it is not at
+	 *    0x5B, but at 0x058. (B is an odd-number, obviously a typo!).
+	 * --//Shrikumar 030609
+	 */
+	if (btv->id != 878)
+		return;
+
+	if (bttv_debug)
+		pr_debug("%d: BT878A ARESET\n", btv->c.nr);
+	btwrite((1<<7), 0x058);
+	udelay(10);
+	btwrite(     0, 0x058);
+}
+
+/* initialization part one -- before registering i2c bus */
+void __devinit bttv_init_card1(struct bttv *btv)
+{
+	switch (btv->c.type) {
+	case BTTV_BOARD_HAUPPAUGE:
+	case BTTV_BOARD_HAUPPAUGE878:
+		boot_msp34xx(btv,5);
+		break;
+	case BTTV_BOARD_VOODOOTV_200:
+	case BTTV_BOARD_VOODOOTV_FM:
+		boot_msp34xx(btv,20);
+		break;
+	case BTTV_BOARD_AVERMEDIA98:
+		boot_msp34xx(btv,11);
+		break;
+	case BTTV_BOARD_HAUPPAUGEPVR:
+		pvr_boot(btv);
+		break;
+	case BTTV_BOARD_TWINHAN_DST:
+	case BTTV_BOARD_AVDVBT_771:
+	case BTTV_BOARD_PINNACLESAT:
+		btv->use_i2c_hw = 1;
+		break;
+	case BTTV_BOARD_ADLINK_RTV24:
+		init_RTV24( btv );
+		break;
+
+	}
+	if (!bttv_tvcards[btv->c.type].has_dvb)
+		bttv_reset_audio(btv);
+}
+
+/* initialization part two -- after registering i2c bus */
+void __devinit bttv_init_card2(struct bttv *btv)
+{
+	btv->tuner_type = UNSET;
+
+	if (BTTV_BOARD_UNKNOWN == btv->c.type) {
+		bttv_readee(btv,eeprom_data,0xa0);
+		identify_by_eeprom(btv,eeprom_data);
+	}
+
+	switch (btv->c.type) {
+	case BTTV_BOARD_MIRO:
+	case BTTV_BOARD_MIROPRO:
+	case BTTV_BOARD_PINNACLE:
+	case BTTV_BOARD_PINNACLEPRO:
+		/* miro/pinnacle */
+		miro_pinnacle_gpio(btv);
+		break;
+	case BTTV_BOARD_FLYVIDEO_98:
+	case BTTV_BOARD_MAXI:
+	case BTTV_BOARD_LIFE_FLYKIT:
+	case BTTV_BOARD_FLYVIDEO:
+	case BTTV_BOARD_TYPHOON_TVIEW:
+	case BTTV_BOARD_CHRONOS_VS2:
+	case BTTV_BOARD_FLYVIDEO_98FM:
+	case BTTV_BOARD_FLYVIDEO2000:
+	case BTTV_BOARD_FLYVIDEO98EZ:
+	case BTTV_BOARD_CONFERENCETV:
+	case BTTV_BOARD_LIFETEC_9415:
+		flyvideo_gpio(btv);
+		break;
+	case BTTV_BOARD_HAUPPAUGE:
+	case BTTV_BOARD_HAUPPAUGE878:
+	case BTTV_BOARD_HAUPPAUGEPVR:
+		/* pick up some config infos from the eeprom */
+		bttv_readee(btv,eeprom_data,0xa0);
+		hauppauge_eeprom(btv);
+		break;
+	case BTTV_BOARD_AVERMEDIA98:
+	case BTTV_BOARD_AVPHONE98:
+		bttv_readee(btv,eeprom_data,0xa0);
+		avermedia_eeprom(btv);
+		break;
+	case BTTV_BOARD_PXC200:
+		init_PXC200(btv);
+		break;
+	case BTTV_BOARD_PICOLO_TETRA_CHIP:
+		picolo_tetra_init(btv);
+		break;
+	case BTTV_BOARD_VHX:
+		btv->has_radio    = 1;
+		btv->has_matchbox = 1;
+		btv->mbox_we      = 0x20;
+		btv->mbox_most    = 0;
+		btv->mbox_clk     = 0x08;
+		btv->mbox_data    = 0x10;
+		btv->mbox_mask    = 0x38;
+		break;
+	case BTTV_BOARD_VOBIS_BOOSTAR:
+	case BTTV_BOARD_TERRATV:
+		terratec_active_radio_upgrade(btv);
+		break;
+	case BTTV_BOARD_MAGICTVIEW061:
+		if (btv->cardid == 0x3002144f) {
+			btv->has_radio=1;
+			pr_info("%d: radio detected by subsystem id (CPH05x)\n",
+				btv->c.nr);
+		}
+		break;
+	case BTTV_BOARD_STB2:
+		if (btv->cardid == 0x3060121a) {
+			/* Fix up entry for 3DFX VoodooTV 100,
+			   which is an OEM STB card variant. */
+			btv->has_radio=0;
+			btv->tuner_type=TUNER_TEMIC_NTSC;
+		}
+		break;
+	case BTTV_BOARD_OSPREY1x0:
+	case BTTV_BOARD_OSPREY1x0_848:
+	case BTTV_BOARD_OSPREY101_848:
+	case BTTV_BOARD_OSPREY1x1:
+	case BTTV_BOARD_OSPREY1x1_SVID:
+	case BTTV_BOARD_OSPREY2xx:
+	case BTTV_BOARD_OSPREY2x0_SVID:
+	case BTTV_BOARD_OSPREY2x0:
+	case BTTV_BOARD_OSPREY440:
+	case BTTV_BOARD_OSPREY500:
+	case BTTV_BOARD_OSPREY540:
+	case BTTV_BOARD_OSPREY2000:
+		bttv_readee(btv,eeprom_data,0xa0);
+		osprey_eeprom(btv, eeprom_data);
+		break;
+	case BTTV_BOARD_IDS_EAGLE:
+		init_ids_eagle(btv);
+		break;
+	case BTTV_BOARD_MODTEC_205:
+		bttv_readee(btv,eeprom_data,0xa0);
+		modtec_eeprom(btv);
+		break;
+	case BTTV_BOARD_LMLBT4:
+		init_lmlbt4x(btv);
+		break;
+	case BTTV_BOARD_TIBET_CS16:
+		tibetCS16_init(btv);
+		break;
+	case BTTV_BOARD_KODICOM_4400R:
+		kodicom4400r_init(btv);
+		break;
+	case BTTV_BOARD_GEOVISION_GV800S:
+		gv800s_init(btv);
+		break;
+	}
+
+	/* pll configuration */
+	if (!(btv->id==848 && btv->revision==0x11)) {
+		/* defaults from card list */
+		if (PLL_28 == bttv_tvcards[btv->c.type].pll) {
+			btv->pll.pll_ifreq=28636363;
+			btv->pll.pll_crystal=BT848_IFORM_XT0;
+		}
+		if (PLL_35 == bttv_tvcards[btv->c.type].pll) {
+			btv->pll.pll_ifreq=35468950;
+			btv->pll.pll_crystal=BT848_IFORM_XT1;
+		}
+		/* insmod options can override */
+		switch (pll[btv->c.nr]) {
+		case 0: /* none */
+			btv->pll.pll_crystal = 0;
+			btv->pll.pll_ifreq   = 0;
+			btv->pll.pll_ofreq   = 0;
+			break;
+		case 1: /* 28 MHz */
+		case 28:
+			btv->pll.pll_ifreq   = 28636363;
+			btv->pll.pll_ofreq   = 0;
+			btv->pll.pll_crystal = BT848_IFORM_XT0;
+			break;
+		case 2: /* 35 MHz */
+		case 35:
+			btv->pll.pll_ifreq   = 35468950;
+			btv->pll.pll_ofreq   = 0;
+			btv->pll.pll_crystal = BT848_IFORM_XT1;
+			break;
+		}
+	}
+	btv->pll.pll_current = -1;
+
+	/* tuner configuration (from card list / autodetect / insmod option) */
+	if (UNSET != bttv_tvcards[btv->c.type].tuner_type)
+		if (UNSET == btv->tuner_type)
+			btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
+	if (UNSET != tuner[btv->c.nr])
+		btv->tuner_type = tuner[btv->c.nr];
+
+	if (btv->tuner_type == TUNER_ABSENT)
+		pr_info("%d: tuner absent\n", btv->c.nr);
+	else if (btv->tuner_type == UNSET)
+		pr_warn("%d: tuner type unset\n", btv->c.nr);
+	else
+		pr_info("%d: tuner type=%d\n", btv->c.nr, btv->tuner_type);
+
+	if (autoload != UNSET) {
+		pr_warn("%d: the autoload option is obsolete\n", btv->c.nr);
+		pr_warn("%d: use option msp3400, tda7432 or tvaudio to override which audio module should be used\n",
+			btv->c.nr);
+	}
+
+	if (UNSET == btv->tuner_type)
+		btv->tuner_type = TUNER_ABSENT;
+
+	btv->dig = bttv_tvcards[btv->c.type].has_dig_in ?
+		   bttv_tvcards[btv->c.type].video_inputs - 1 : UNSET;
+	btv->svhs = bttv_tvcards[btv->c.type].svhs == NO_SVHS ?
+		    UNSET : bttv_tvcards[btv->c.type].svhs;
+	if (svhs[btv->c.nr] != UNSET)
+		btv->svhs = svhs[btv->c.nr];
+	if (remote[btv->c.nr] != UNSET)
+		btv->has_remote = remote[btv->c.nr];
+
+	if (bttv_tvcards[btv->c.type].has_radio)
+		btv->has_radio = 1;
+	if (bttv_tvcards[btv->c.type].has_remote)
+		btv->has_remote = 1;
+	if (!bttv_tvcards[btv->c.type].no_gpioirq)
+		btv->gpioirq = 1;
+	if (bttv_tvcards[btv->c.type].volume_gpio)
+		btv->volume_gpio = bttv_tvcards[btv->c.type].volume_gpio;
+	if (bttv_tvcards[btv->c.type].audio_mode_gpio)
+		btv->audio_mode_gpio = bttv_tvcards[btv->c.type].audio_mode_gpio;
+
+	if (btv->tuner_type == TUNER_ABSENT)
+		return;  /* no tuner or related drivers to load */
+
+	if (btv->has_saa6588 || saa6588[btv->c.nr]) {
+		/* Probe for RDS receiver chip */
+		static const unsigned short addrs[] = {
+			0x20 >> 1,
+			0x22 >> 1,
+			I2C_CLIENT_END
+		};
+		struct v4l2_subdev *sd;
+
+		sd = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+			&btv->c.i2c_adap, "saa6588", 0, addrs);
+		btv->has_saa6588 = (sd != NULL);
+	}
+
+	/* try to detect audio/fader chips */
+
+	/* First check if the user specified the audio chip via a module
+	   option. */
+
+	switch (audiodev[btv->c.nr]) {
+	case -1:
+		return;	/* do not load any audio module */
+
+	case 0: /* autodetect */
+		break;
+
+	case 1: {
+		/* The user specified that we should probe for msp3400 */
+		static const unsigned short addrs[] = {
+			I2C_ADDR_MSP3400 >> 1,
+			I2C_ADDR_MSP3400_ALT >> 1,
+			I2C_CLIENT_END
+		};
+
+		btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+			&btv->c.i2c_adap, "msp3400", 0, addrs);
+		if (btv->sd_msp34xx)
+			return;
+		goto no_audio;
+	}
+
+	case 2: {
+		/* The user specified that we should probe for tda7432 */
+		static const unsigned short addrs[] = {
+			I2C_ADDR_TDA7432 >> 1,
+			I2C_CLIENT_END
+		};
+
+		if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+				&btv->c.i2c_adap, "tda7432", 0, addrs))
+			return;
+		goto no_audio;
+	}
+
+	case 3: {
+		/* The user specified that we should probe for tvaudio */
+		btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+			&btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs());
+		if (btv->sd_tvaudio)
+			return;
+		goto no_audio;
+	}
+
+	default:
+		pr_warn("%d: unknown audiodev value!\n", btv->c.nr);
+		return;
+	}
+
+	/* There were no overrides, so now we try to discover this through the
+	   card definition */
+
+	/* probe for msp3400 first: this driver can detect whether or not
+	   it really is a msp3400, so it will return NULL when the device
+	   found is really something else (e.g. a tea6300). */
+	if (!bttv_tvcards[btv->c.type].no_msp34xx) {
+		btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+			&btv->c.i2c_adap, "msp3400",
+			0, I2C_ADDRS(I2C_ADDR_MSP3400 >> 1));
+	} else if (bttv_tvcards[btv->c.type].msp34xx_alt) {
+		btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+			&btv->c.i2c_adap, "msp3400",
+			0, I2C_ADDRS(I2C_ADDR_MSP3400_ALT >> 1));
+	}
+
+	/* If we found a msp34xx, then we're done. */
+	if (btv->sd_msp34xx)
+		return;
+
+	/* it might also be a tda7432. */
+	if (!bttv_tvcards[btv->c.type].no_tda7432) {
+		static const unsigned short addrs[] = {
+			I2C_ADDR_TDA7432 >> 1,
+			I2C_CLIENT_END
+		};
+
+		if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+				&btv->c.i2c_adap, "tda7432", 0, addrs))
+			return;
+	}
+
+	/* Now see if we can find one of the tvaudio devices. */
+	btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+		&btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs());
+	if (btv->sd_tvaudio)
+		return;
+
+no_audio:
+	pr_warn("%d: audio absent, no audio device found!\n", btv->c.nr);
+}
+
+
+/* initialize the tuner */
+void __devinit bttv_init_tuner(struct bttv *btv)
+{
+	int addr = ADDR_UNSET;
+
+	if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr)
+		addr = bttv_tvcards[btv->c.type].tuner_addr;
+
+	if (btv->tuner_type != TUNER_ABSENT) {
+		struct tuner_setup tun_setup;
+
+		/* Load tuner module before issuing tuner config call! */
+		if (btv->has_radio)
+			v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+				&btv->c.i2c_adap, "tuner",
+				0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
+		v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+				&btv->c.i2c_adap, "tuner",
+				0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+		v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+				&btv->c.i2c_adap, "tuner",
+				0, v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
+
+		tun_setup.mode_mask = T_ANALOG_TV;
+		tun_setup.type = btv->tuner_type;
+		tun_setup.addr = addr;
+
+		if (btv->has_radio)
+			tun_setup.mode_mask |= T_RADIO;
+
+		bttv_call_all(btv, tuner, s_type_addr, &tun_setup);
+	}
+
+	if (btv->tda9887_conf) {
+		struct v4l2_priv_tun_config tda9887_cfg;
+
+		tda9887_cfg.tuner = TUNER_TDA9887;
+		tda9887_cfg.priv = &btv->tda9887_conf;
+
+		bttv_call_all(btv, tuner, s_config, &tda9887_cfg);
+	}
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void modtec_eeprom(struct bttv *btv)
+{
+	if( strncmp(&(eeprom_data[0x1e]),"Temic 4066 FY5",14) ==0) {
+		btv->tuner_type=TUNER_TEMIC_4066FY5_PAL_I;
+		pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n",
+			btv->c.nr, &eeprom_data[0x1e]);
+	} else if (strncmp(&(eeprom_data[0x1e]),"Alps TSBB5",10) ==0) {
+		btv->tuner_type=TUNER_ALPS_TSBB5_PAL_I;
+		pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n",
+			btv->c.nr, &eeprom_data[0x1e]);
+	} else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) {
+		btv->tuner_type=TUNER_PHILIPS_NTSC;
+		pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n",
+			btv->c.nr, &eeprom_data[0x1e]);
+	} else {
+		pr_info("%d: Modtec: Unknown TunerString: %s\n",
+			btv->c.nr, &eeprom_data[0x1e]);
+	}
+}
+
+static void __devinit hauppauge_eeprom(struct bttv *btv)
+{
+	struct tveeprom tv;
+
+	tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data);
+	btv->tuner_type = tv.tuner_type;
+	btv->has_radio  = tv.has_radio;
+
+	pr_info("%d: Hauppauge eeprom indicates model#%d\n",
+		btv->c.nr, tv.model);
+
+	/*
+	 * Some of the 878 boards have duplicate PCI IDs. Switch the board
+	 * type based on model #.
+	 */
+	if(tv.model == 64900) {
+		pr_info("%d: Switching board type from %s to %s\n",
+			btv->c.nr,
+			bttv_tvcards[btv->c.type].name,
+			bttv_tvcards[BTTV_BOARD_HAUPPAUGE_IMPACTVCB].name);
+		btv->c.type = BTTV_BOARD_HAUPPAUGE_IMPACTVCB;
+	}
+
+	/* The 61334 needs the msp3410 to do the radio demod to get sound */
+	if (tv.model == 61334)
+		btv->radio_uses_msp_demodulator = 1;
+}
+
+static int terratec_active_radio_upgrade(struct bttv *btv)
+{
+	int freq;
+
+	btv->has_radio    = 1;
+	btv->has_matchbox = 1;
+	btv->mbox_we      = 0x10;
+	btv->mbox_most    = 0x20;
+	btv->mbox_clk     = 0x08;
+	btv->mbox_data    = 0x04;
+	btv->mbox_mask    = 0x3c;
+
+	btv->mbox_iow     = 1 <<  8;
+	btv->mbox_ior     = 1 <<  9;
+	btv->mbox_csel    = 1 << 10;
+
+	freq=88000/62.5;
+	tea5757_write(btv, 5 * freq + 0x358); /* write 0x1ed8 */
+	if (0x1ed8 == tea5757_read(btv)) {
+		pr_info("%d: Terratec Active Radio Upgrade found\n", btv->c.nr);
+		btv->has_radio    = 1;
+		btv->has_saa6588  = 1;
+		btv->has_matchbox = 1;
+	} else {
+		btv->has_radio    = 0;
+		btv->has_matchbox = 0;
+	}
+	return 0;
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+/*
+ * minimal bootstrap for the WinTV/PVR -- upload altera firmware.
+ *
+ * The hcwamc.rbf firmware file is on the Hauppauge driver CD.  Have
+ * a look at Pvr/pvr45xxx.EXE (self-extracting zip archive, can be
+ * unpacked with unzip).
+ */
+#define PVR_GPIO_DELAY		10
+
+#define BTTV_ALT_DATA		0x000001
+#define BTTV_ALT_DCLK		0x100000
+#define BTTV_ALT_NCONFIG	0x800000
+
+static int __devinit pvr_altera_load(struct bttv *btv, const u8 *micro,
+				     u32 microlen)
+{
+	u32 n;
+	u8 bits;
+	int i;
+
+	gpio_inout(0xffffff,BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG);
+	gpio_write(0);
+	udelay(PVR_GPIO_DELAY);
+
+	gpio_write(BTTV_ALT_NCONFIG);
+	udelay(PVR_GPIO_DELAY);
+
+	for (n = 0; n < microlen; n++) {
+		bits = micro[n];
+		for (i = 0 ; i < 8 ; i++) {
+			gpio_bits(BTTV_ALT_DCLK,0);
+			if (bits & 0x01)
+				gpio_bits(BTTV_ALT_DATA,BTTV_ALT_DATA);
+			else
+				gpio_bits(BTTV_ALT_DATA,0);
+			gpio_bits(BTTV_ALT_DCLK,BTTV_ALT_DCLK);
+			bits >>= 1;
+		}
+	}
+	gpio_bits(BTTV_ALT_DCLK,0);
+	udelay(PVR_GPIO_DELAY);
+
+	/* begin Altera init loop (Not necessary,but doesn't hurt) */
+	for (i = 0 ; i < 30 ; i++) {
+		gpio_bits(BTTV_ALT_DCLK,0);
+		gpio_bits(BTTV_ALT_DCLK,BTTV_ALT_DCLK);
+	}
+	gpio_bits(BTTV_ALT_DCLK,0);
+	return 0;
+}
+
+static int __devinit pvr_boot(struct bttv *btv)
+{
+	const struct firmware *fw_entry;
+	int rc;
+
+	rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->c.pci->dev);
+	if (rc != 0) {
+		pr_warn("%d: no altera firmware [via hotplug]\n", btv->c.nr);
+		return rc;
+	}
+	rc = pvr_altera_load(btv, fw_entry->data, fw_entry->size);
+	pr_info("%d: altera firmware upload %s\n",
+		btv->c.nr, (rc < 0) ? "failed" : "ok");
+	release_firmware(fw_entry);
+	return rc;
+}
+
+/* ----------------------------------------------------------------------- */
+/* some osprey specific stuff                                              */
+
+static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256])
+{
+	int i;
+	u32 serial = 0;
+	int cardid = -1;
+
+	/* This code will nevery actually get called in this case.... */
+	if (btv->c.type == BTTV_BOARD_UNKNOWN) {
+		/* this might be an antique... check for MMAC label in eeprom */
+		if (!strncmp(ee, "MMAC", 4)) {
+			u8 checksum = 0;
+			for (i = 0; i < 21; i++)
+				checksum += ee[i];
+			if (checksum != ee[21])
+				return;
+			cardid = BTTV_BOARD_OSPREY1x0_848;
+			for (i = 12; i < 21; i++)
+				serial *= 10, serial += ee[i] - '0';
+		}
+	} else {
+		unsigned short type;
+
+		for (i = 4*16; i < 8*16; i += 16) {
+			u16 checksum = ip_compute_csum(ee + i, 16);
+
+			if ((checksum&0xff) + (checksum>>8) == 0xff)
+				break;
+		}
+		if (i >= 8*16)
+			return;
+		ee += i;
+
+		/* found a valid descriptor */
+		type = get_unaligned_be16((__be16 *)(ee+4));
+
+		switch(type) {
+		/* 848 based */
+		case 0x0004:
+			cardid = BTTV_BOARD_OSPREY1x0_848;
+			break;
+		case 0x0005:
+			cardid = BTTV_BOARD_OSPREY101_848;
+			break;
+
+		/* 878 based */
+		case 0x0012:
+		case 0x0013:
+			cardid = BTTV_BOARD_OSPREY1x0;
+			break;
+		case 0x0014:
+		case 0x0015:
+			cardid = BTTV_BOARD_OSPREY1x1;
+			break;
+		case 0x0016:
+		case 0x0017:
+		case 0x0020:
+			cardid = BTTV_BOARD_OSPREY1x1_SVID;
+			break;
+		case 0x0018:
+		case 0x0019:
+		case 0x001E:
+		case 0x001F:
+			cardid = BTTV_BOARD_OSPREY2xx;
+			break;
+		case 0x001A:
+		case 0x001B:
+			cardid = BTTV_BOARD_OSPREY2x0_SVID;
+			break;
+		case 0x0040:
+			cardid = BTTV_BOARD_OSPREY500;
+			break;
+		case 0x0050:
+		case 0x0056:
+			cardid = BTTV_BOARD_OSPREY540;
+			/* bttv_osprey_540_init(btv); */
+			break;
+		case 0x0060:
+		case 0x0070:
+		case 0x00A0:
+			cardid = BTTV_BOARD_OSPREY2x0;
+			/* enable output on select control lines */
+			gpio_inout(0xffffff,0x000303);
+			break;
+		case 0x00D8:
+			cardid = BTTV_BOARD_OSPREY440;
+			break;
+		default:
+			/* unknown...leave generic, but get serial # */
+			pr_info("%d: osprey eeprom: unknown card type 0x%04x\n",
+				btv->c.nr, type);
+			break;
+		}
+		serial = get_unaligned_be32((__be32 *)(ee+6));
+	}
+
+	pr_info("%d: osprey eeprom: card=%d '%s' serial=%u\n",
+		btv->c.nr, cardid,
+		cardid > 0 ? bttv_tvcards[cardid].name : "Unknown", serial);
+
+	if (cardid<0 || btv->c.type == cardid)
+		return;
+
+	/* card type isn't set correctly */
+	if (card[btv->c.nr] < bttv_num_tvcards) {
+		pr_warn("%d: osprey eeprom: Not overriding user specified card type\n",
+			btv->c.nr);
+	} else {
+		pr_info("%d: osprey eeprom: Changing card type from %d to %d\n",
+			btv->c.nr, btv->c.type, cardid);
+		btv->c.type = cardid;
+	}
+}
+
+/* ----------------------------------------------------------------------- */
+/* AVermedia specific stuff, from  bktr_card.c                             */
+
+static int tuner_0_table[] = {
+	TUNER_PHILIPS_NTSC,  TUNER_PHILIPS_PAL /* PAL-BG*/,
+	TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL /* PAL-I*/,
+	TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL,
+	TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM,
+	TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL,
+	TUNER_PHILIPS_FM1216ME_MK3 };
+
+static int tuner_1_table[] = {
+	TUNER_TEMIC_NTSC,  TUNER_TEMIC_PAL,
+	TUNER_TEMIC_PAL,   TUNER_TEMIC_PAL,
+	TUNER_TEMIC_PAL,   TUNER_TEMIC_PAL,
+	TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */
+	TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL};
+
+static void __devinit avermedia_eeprom(struct bttv *btv)
+{
+	int tuner_make, tuner_tv_fm, tuner_format, tuner_type = 0;
+
+	tuner_make      = (eeprom_data[0x41] & 0x7);
+	tuner_tv_fm     = (eeprom_data[0x41] & 0x18) >> 3;
+	tuner_format    = (eeprom_data[0x42] & 0xf0) >> 4;
+	btv->has_remote = (eeprom_data[0x42] & 0x01);
+
+	if (tuner_make == 0 || tuner_make == 2)
+		if (tuner_format <= 0x0a)
+			tuner_type = tuner_0_table[tuner_format];
+	if (tuner_make == 1)
+		if (tuner_format <= 9)
+			tuner_type = tuner_1_table[tuner_format];
+
+	if (tuner_make == 4)
+		if (tuner_format == 0x09)
+			tuner_type = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */
+
+	pr_info("%d: Avermedia eeprom[0x%02x%02x]: tuner=",
+		btv->c.nr, eeprom_data[0x41], eeprom_data[0x42]);
+	if (tuner_type) {
+		btv->tuner_type = tuner_type;
+		pr_cont("%d", tuner_type);
+	} else
+		pr_cont("Unknown type");
+	pr_cont(" radio:%s remote control:%s\n",
+	       tuner_tv_fm     ? "yes" : "no",
+	       btv->has_remote ? "yes" : "no");
+}
+
+/*
+ * For Voodoo TV/FM and Voodoo 200.  These cards' tuners use a TDA9880
+ * analog demod, which is not I2C controlled like the newer and more common
+ * TDA9887 series.  Instead is has two tri-state input pins, S0 and S1,
+ * that control the IF for the video and audio.  Apparently, bttv GPIO
+ * 0x10000 is connected to S0.  S0 low selects a 38.9 MHz VIF for B/G/D/K/I
+ * (i.e., PAL) while high selects 45.75 MHz for M/N (i.e., NTSC).
+ */
+u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits)
+{
+
+	if (btv->audio == TVAUDIO_INPUT_TUNER) {
+		if (bttv_tvnorms[btv->tvnorm].v4l2_id & V4L2_STD_MN)
+			gpiobits |= 0x10000;
+		else
+			gpiobits &= ~0x10000;
+	}
+
+	gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpiobits);
+	return gpiobits;
+}
+
+
+/*
+ * reset/enable the MSP on some Hauppauge cards
+ * Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)!
+ *
+ * Hauppauge:  pin  5
+ * Voodoo:     pin 20
+ */
+static void __devinit boot_msp34xx(struct bttv *btv, int pin)
+{
+	int mask = (1 << pin);
+
+	gpio_inout(mask,mask);
+	gpio_bits(mask,0);
+	mdelay(2);
+	udelay(500);
+	gpio_bits(mask,mask);
+
+	if (bttv_gpio)
+		bttv_gpio_tracking(btv,"msp34xx");
+	if (bttv_verbose)
+		pr_info("%d: Hauppauge/Voodoo msp34xx: reset line init [%d]\n",
+			btv->c.nr, pin);
+}
+
+/* ----------------------------------------------------------------------- */
+/*  Imagenation L-Model PXC200 Framegrabber */
+/*  This is basically the same procedure as
+ *  used by Alessandro Rubini in his pxc200
+ *  driver, but using BTTV functions */
+
+static void __devinit init_PXC200(struct bttv *btv)
+{
+	static int vals[] __devinitdata = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d,
+					    0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+					    0x00 };
+	unsigned int i;
+	int tmp;
+	u32 val;
+
+	/* Initialise GPIO-connevted stuff */
+	gpio_inout(0xffffff, (1<<13));
+	gpio_write(0);
+	udelay(3);
+	gpio_write(1<<13);
+	/* GPIO inputs are pulled up, so no need to drive
+	 * reset pin any longer */
+	gpio_bits(0xffffff, 0);
+	if (bttv_gpio)
+		bttv_gpio_tracking(btv,"pxc200");
+
+	/*  we could/should try and reset/control the AD pots? but
+	    right now  we simply  turned off the crushing.  Without
+	    this the AGC drifts drifts
+	    remember the EN is reverse logic -->
+	    setting BT848_ADC_AGC_EN disable the AGC
+	    tboult@eecs.lehigh.edu
+	*/
+
+	btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC);
+
+	/*	Initialise MAX517 DAC */
+	pr_info("Setting DAC reference voltage level ...\n");
+	bttv_I2CWrite(btv,0x5E,0,0x80,1);
+
+	/*	Initialise 12C508 PIC */
+	/*	The I2CWrite and I2CRead commmands are actually to the
+	 *	same chips - but the R/W bit is included in the address
+	 *	argument so the numbers are different */
+
+
+	pr_info("Initialising 12C508 PIC chip ...\n");
+
+	/* First of all, enable the clock line. This is used in the PXC200-F */
+	val = btread(BT848_GPIO_DMA_CTL);
+	val |= BT848_GPIO_DMA_CTL_GPCLKMODE;
+	btwrite(val, BT848_GPIO_DMA_CTL);
+
+	/* Then, push to 0 the reset pin long enough to reset the *
+	 * device same as above for the reset line, but not the same
+	 * value sent to the GPIO-connected stuff
+	 * which one is the good one? */
+	gpio_inout(0xffffff,(1<<2));
+	gpio_write(0);
+	udelay(10);
+	gpio_write(1<<2);
+
+	for (i = 0; i < ARRAY_SIZE(vals); i++) {
+		tmp=bttv_I2CWrite(btv,0x1E,0,vals[i],1);
+		if (tmp != -1) {
+			pr_info("I2C Write(%2.2x) = %i\nI2C Read () = %2.2x\n\n",
+			       vals[i],tmp,bttv_I2CRead(btv,0x1F,NULL));
+		}
+	}
+
+	pr_info("PXC200 Initialised\n");
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+/*
+ *  The Adlink RTV-24 (aka Angelo) has some special initialisation to unlock
+ *  it. This apparently involves the following procedure for each 878 chip:
+ *
+ *  1) write 0x00C3FEFF to the GPIO_OUT_EN register
+ *
+ *  2)  write to GPIO_DATA
+ *      - 0x0E
+ *      - sleep 1ms
+ *      - 0x10 + 0x0E
+ *      - sleep 10ms
+ *      - 0x0E
+ *     read from GPIO_DATA into buf (uint_32)
+ *      - if ( data>>18 & 0x01 != 0) || ( buf>>19 & 0x01 != 1 )
+ *                 error. ERROR_CPLD_Check_Failed stop.
+ *
+ *  3) write to GPIO_DATA
+ *      - write 0x4400 + 0x0E
+ *      - sleep 10ms
+ *      - write 0x4410 + 0x0E
+ *      - sleep 1ms
+ *      - write 0x0E
+ *     read from GPIO_DATA into buf (uint_32)
+ *      - if ( buf>>18 & 0x01 ) || ( buf>>19 & 0x01 != 0 )
+ *                error. ERROR_CPLD_Check_Failed.
+ */
+/* ----------------------------------------------------------------------- */
+static void
+init_RTV24 (struct bttv *btv)
+{
+	uint32_t dataRead = 0;
+	long watchdog_value = 0x0E;
+
+	pr_info("%d: Adlink RTV-24 initialisation in progress ...\n",
+		btv->c.nr);
+
+	btwrite (0x00c3feff, BT848_GPIO_OUT_EN);
+
+	btwrite (0 + watchdog_value, BT848_GPIO_DATA);
+	msleep (1);
+	btwrite (0x10 + watchdog_value, BT848_GPIO_DATA);
+	msleep (10);
+	btwrite (0 + watchdog_value, BT848_GPIO_DATA);
+
+	dataRead = btread (BT848_GPIO_DATA);
+
+	if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 1)) {
+		pr_info("%d: Adlink RTV-24 initialisation(1) ERROR_CPLD_Check_Failed (read %d)\n",
+			btv->c.nr, dataRead);
+	}
+
+	btwrite (0x4400 + watchdog_value, BT848_GPIO_DATA);
+	msleep (10);
+	btwrite (0x4410 + watchdog_value, BT848_GPIO_DATA);
+	msleep (1);
+	btwrite (watchdog_value, BT848_GPIO_DATA);
+	msleep (1);
+	dataRead = btread (BT848_GPIO_DATA);
+
+	if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 0)) {
+		pr_info("%d: Adlink RTV-24 initialisation(2) ERROR_CPLD_Check_Failed (read %d)\n",
+			btv->c.nr, dataRead);
+
+		return;
+	}
+
+	pr_info("%d: Adlink RTV-24 initialisation complete\n", btv->c.nr);
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+/* Miro Pro radio stuff -- the tea5757 is connected to some GPIO ports     */
+/*
+ * Copyright (c) 1999 Csaba Halasz <qgehali@uni-miskolc.hu>
+ * This code is placed under the terms of the GNU General Public License
+ *
+ * Brutally hacked by Dan Sheridan <dan.sheridan@contact.org.uk> djs52 8/3/00
+ */
+
+static void bus_low(struct bttv *btv, int bit)
+{
+	if (btv->mbox_ior) {
+		gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+			  btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
+		udelay(5);
+	}
+
+	gpio_bits(bit,0);
+	udelay(5);
+
+	if (btv->mbox_ior) {
+		gpio_bits(btv->mbox_iow | btv->mbox_csel, 0);
+		udelay(5);
+	}
+}
+
+static void bus_high(struct bttv *btv, int bit)
+{
+	if (btv->mbox_ior) {
+		gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+			  btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
+		udelay(5);
+	}
+
+	gpio_bits(bit,bit);
+	udelay(5);
+
+	if (btv->mbox_ior) {
+		gpio_bits(btv->mbox_iow | btv->mbox_csel, 0);
+		udelay(5);
+	}
+}
+
+static int bus_in(struct bttv *btv, int bit)
+{
+	if (btv->mbox_ior) {
+		gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+			  btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
+		udelay(5);
+
+		gpio_bits(btv->mbox_iow | btv->mbox_csel, 0);
+		udelay(5);
+	}
+	return gpio_read() & (bit);
+}
+
+/* TEA5757 register bits */
+#define TEA_FREQ		0:14
+#define TEA_BUFFER		15:15
+
+#define TEA_SIGNAL_STRENGTH	16:17
+
+#define TEA_PORT1		18:18
+#define TEA_PORT0		19:19
+
+#define TEA_BAND		20:21
+#define TEA_BAND_FM		0
+#define TEA_BAND_MW		1
+#define TEA_BAND_LW		2
+#define TEA_BAND_SW		3
+
+#define TEA_MONO		22:22
+#define TEA_ALLOW_STEREO	0
+#define TEA_FORCE_MONO		1
+
+#define TEA_SEARCH_DIRECTION	23:23
+#define TEA_SEARCH_DOWN		0
+#define TEA_SEARCH_UP		1
+
+#define TEA_STATUS		24:24
+#define TEA_STATUS_TUNED	0
+#define TEA_STATUS_SEARCHING	1
+
+/* Low-level stuff */
+static int tea5757_read(struct bttv *btv)
+{
+	unsigned long timeout;
+	int value = 0;
+	int i;
+
+	/* better safe than sorry */
+	gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we);
+
+	if (btv->mbox_ior) {
+		gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+			  btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
+		udelay(5);
+	}
+
+	if (bttv_gpio)
+		bttv_gpio_tracking(btv,"tea5757 read");
+
+	bus_low(btv,btv->mbox_we);
+	bus_low(btv,btv->mbox_clk);
+
+	udelay(10);
+	timeout= jiffies + msecs_to_jiffies(1000);
+
+	/* wait for DATA line to go low; error if it doesn't */
+	while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout))
+		schedule();
+	if (bus_in(btv,btv->mbox_data)) {
+		pr_warn("%d: tea5757: read timeout\n", btv->c.nr);
+		return -1;
+	}
+
+	dprintk("%d: tea5757:", btv->c.nr);
+	for (i = 0; i < 24; i++) {
+		udelay(5);
+		bus_high(btv,btv->mbox_clk);
+		udelay(5);
+		dprintk_cont("%c",
+			     bus_in(btv, btv->mbox_most) == 0 ? 'T' : '-');
+		bus_low(btv,btv->mbox_clk);
+		value <<= 1;
+		value |= (bus_in(btv,btv->mbox_data) == 0)?0:1;  /* MSB first */
+		dprintk_cont("%c",
+			     bus_in(btv, btv->mbox_most) == 0 ? 'S' : 'M');
+	}
+	dprintk_cont("\n");
+	dprintk("%d: tea5757: read 0x%X\n", btv->c.nr, value);
+	return value;
+}
+
+static int tea5757_write(struct bttv *btv, int value)
+{
+	int i;
+	int reg = value;
+
+	gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we | btv->mbox_data);
+
+	if (btv->mbox_ior) {
+		gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+			  btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
+		udelay(5);
+	}
+	if (bttv_gpio)
+		bttv_gpio_tracking(btv,"tea5757 write");
+
+	dprintk("%d: tea5757: write 0x%X\n", btv->c.nr, value);
+	bus_low(btv,btv->mbox_clk);
+	bus_high(btv,btv->mbox_we);
+	for (i = 0; i < 25; i++) {
+		if (reg & 0x1000000)
+			bus_high(btv,btv->mbox_data);
+		else
+			bus_low(btv,btv->mbox_data);
+		reg <<= 1;
+		bus_high(btv,btv->mbox_clk);
+		udelay(10);
+		bus_low(btv,btv->mbox_clk);
+		udelay(10);
+	}
+	bus_low(btv,btv->mbox_we);  /* unmute !!! */
+	return 0;
+}
+
+void tea5757_set_freq(struct bttv *btv, unsigned short freq)
+{
+	dprintk("tea5757_set_freq %d\n",freq);
+	tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */
+}
+
+/* RemoteVision MX (rv605) muxsel helper [Miguel Freitas]
+ *
+ * This is needed because rv605 don't use a normal multiplex, but a crosspoint
+ * switch instead (CD22M3494E). This IC can have multiple active connections
+ * between Xn (input) and Yn (output) pins. We need to clear any existing
+ * connection prior to establish a new one, pulsing the STROBE pin.
+ *
+ * The board hardwire Y0 (xpoint) to MUX1 and MUXOUT to Yin.
+ * GPIO pins are wired as:
+ *  GPIO[0:3] - AX[0:3] (xpoint) - P1[0:3] (microcontroller)
+ *  GPIO[4:6] - AY[0:2] (xpoint) - P1[4:6] (microcontroller)
+ *  GPIO[7]   - DATA (xpoint)    - P1[7] (microcontroller)
+ *  GPIO[8]   -                  - P3[5] (microcontroller)
+ *  GPIO[9]   - RESET (xpoint)   - P3[6] (microcontroller)
+ *  GPIO[10]  - STROBE (xpoint)  - P3[7] (microcontroller)
+ *  GPINTR    -                  - P3[4] (microcontroller)
+ *
+ * The microcontroller is a 80C32 like. It should be possible to change xpoint
+ * configuration either directly (as we are doing) or using the microcontroller
+ * which is also wired to I2C interface. I have no further info on the
+ * microcontroller features, one would need to disassembly the firmware.
+ * note: the vendor refused to give any information on this product, all
+ *       that stuff was found using a multimeter! :)
+ */
+static void rv605_muxsel(struct bttv *btv, unsigned int input)
+{
+	static const u8 muxgpio[] = { 0x3, 0x1, 0x2, 0x4, 0xf, 0x7, 0xe, 0x0,
+				      0xd, 0xb, 0xc, 0x6, 0x9, 0x5, 0x8, 0xa };
+
+	gpio_bits(0x07f, muxgpio[input]);
+
+	/* reset all conections */
+	gpio_bits(0x200,0x200);
+	mdelay(1);
+	gpio_bits(0x200,0x000);
+	mdelay(1);
+
+	/* create a new connection */
+	gpio_bits(0x480,0x480);
+	mdelay(1);
+	gpio_bits(0x480,0x080);
+	mdelay(1);
+}
+
+/* Tibet Systems 'Progress DVR' CS16 muxsel helper [Chris Fanning]
+ *
+ * The CS16 (available on eBay cheap) is a PCI board with four Fusion
+ * 878A chips, a PCI bridge, an Atmel microcontroller, four sync separator
+ * chips, ten eight input analog multiplexors, a not chip and a few
+ * other components.
+ *
+ * 16 inputs on a secondary bracket are provided and can be selected
+ * from each of the four capture chips.  Two of the eight input
+ * multiplexors are used to select from any of the 16 input signals.
+ *
+ * Unsupported hardware capabilities:
+ *  . A video output monitor on the secondary bracket can be selected from
+ *    one of the 878A chips.
+ *  . Another passthrough but I haven't spent any time investigating it.
+ *  . Digital I/O (logic level connected to GPIO) is available from an
+ *    onboard header.
+ *
+ * The on chip input mux should always be set to 2.
+ * GPIO[16:19] - Video input selection
+ * GPIO[0:3]   - Video output monitor select (only available from one 878A)
+ * GPIO[?:?]   - Digital I/O.
+ *
+ * There is an ATMEL microcontroller with an 8031 core on board.  I have not
+ * determined what function (if any) it provides.  With the microcontroller
+ * and sync separator chips a guess is that it might have to do with video
+ * switching and maybe some digital I/O.
+ */
+static void tibetCS16_muxsel(struct bttv *btv, unsigned int input)
+{
+	/* video mux */
+	gpio_bits(0x0f0000, input << 16);
+}
+
+static void tibetCS16_init(struct bttv *btv)
+{
+	/* enable gpio bits, mask obtained via btSpy */
+	gpio_inout(0xffffff, 0x0f7fff);
+	gpio_write(0x0f7fff);
+}
+
+/*
+ * The following routines for the Kodicom-4400r get a little mind-twisting.
+ * There is a "master" controller and three "slave" controllers, together
+ * an analog switch which connects any of 16 cameras to any of the BT87A's.
+ * The analog switch is controlled by the "master", but the detection order
+ * of the four BT878A chips is in an order which I just don't understand.
+ * The "master" is actually the second controller to be detected.  The
+ * logic on the board uses logical numbers for the 4 controllers, but
+ * those numbers are different from the detection sequence.  When working
+ * with the analog switch, we need to "map" from the detection sequence
+ * over to the board's logical controller number.  This mapping sequence
+ * is {3, 0, 2, 1}, i.e. the first controller to be detected is logical
+ * unit 3, the second (which is the master) is logical unit 0, etc.
+ * We need to maintain the status of the analog switch (which of the 16
+ * cameras is connected to which of the 4 controllers).  Rather than
+ * add to the bttv structure for this, we use the data reserved for
+ * the mbox (unused for this card type).
+ */
+
+/*
+ * First a routine to set the analog switch, which controls which camera
+ * is routed to which controller.  The switch comprises an X-address
+ * (gpio bits 0-3, representing the camera, ranging from 0-15), and a
+ * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3).
+ * A data value (gpio bit 7) of '1' enables the switch, and '0' disables
+ * the switch.  A STROBE bit (gpio bit 8) latches the data value into the
+ * specified address.  The idea is to set the address and data, then bring
+ * STROBE high, and finally bring STROBE back to low.
+ */
+static void kodicom4400r_write(struct bttv *btv,
+			       unsigned char xaddr,
+			       unsigned char yaddr,
+			       unsigned char data) {
+	unsigned int udata;
+
+	udata = (data << 7) | ((yaddr&3) << 4) | (xaddr&0xf);
+	gpio_bits(0x1ff, udata);		/* write ADDR and DAT */
+	gpio_bits(0x1ff, udata | (1 << 8));	/* strobe high */
+	gpio_bits(0x1ff, udata);		/* strobe low */
+}
+
+/*
+ * Next the mux select.  Both the "master" and "slave" 'cards' (controllers)
+ * use this routine.  The routine finds the "master" for the card, maps
+ * the controller number from the detected position over to the logical
+ * number, writes the appropriate data to the analog switch, and housekeeps
+ * the local copy of the switch information.  The parameter 'input' is the
+ * requested camera number (0 - 15).
+ */
+static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input)
+{
+	char *sw_status;
+	int xaddr, yaddr;
+	struct bttv *mctlr;
+	static unsigned char map[4] = {3, 0, 2, 1};
+
+	mctlr = master[btv->c.nr];
+	if (mctlr == NULL) {	/* ignore if master not yet detected */
+		return;
+	}
+	yaddr = (btv->c.nr - mctlr->c.nr + 1) & 3; /* the '&' is for safety */
+	yaddr = map[yaddr];
+	sw_status = (char *)(&mctlr->mbox_we);
+	xaddr = input & 0xf;
+	/* Check if the controller/camera pair has changed, else ignore */
+	if (sw_status[yaddr] != xaddr)
+	{
+		/* "open" the old switch, "close" the new one, save the new */
+		kodicom4400r_write(mctlr, sw_status[yaddr], yaddr, 0);
+		sw_status[yaddr] = xaddr;
+		kodicom4400r_write(mctlr, xaddr, yaddr, 1);
+	}
+}
+
+/*
+ * During initialisation, we need to reset the analog switch.  We
+ * also preset the switch to map the 4 connectors on the card to the
+ * *user's* (see above description of kodicom4400r_muxsel) channels
+ * 0 through 3
+ */
+static void kodicom4400r_init(struct bttv *btv)
+{
+	char *sw_status = (char *)(&btv->mbox_we);
+	int ix;
+
+	gpio_inout(0x0003ff, 0x0003ff);
+	gpio_write(1 << 9);	/* reset MUX */
+	gpio_write(0);
+	/* Preset camera 0 to the 4 controllers */
+	for (ix = 0; ix < 4; ix++) {
+		sw_status[ix] = ix;
+		kodicom4400r_write(btv, ix, ix, 1);
+	}
+	/*
+	 * Since this is the "master", we need to set up the
+	 * other three controller chips' pointers to this structure
+	 * for later use in the muxsel routine.
+	 */
+	if ((btv->c.nr<1) || (btv->c.nr>BTTV_MAX-3))
+	    return;
+	master[btv->c.nr-1] = btv;
+	master[btv->c.nr]   = btv;
+	master[btv->c.nr+1] = btv;
+	master[btv->c.nr+2] = btv;
+}
+
+/* The Grandtec X-Guard framegrabber card uses two Dual 4-channel
+ * video multiplexers to provide up to 16 video inputs. These
+ * multiplexers are controlled by the lower 8 GPIO pins of the
+ * bt878. The multiplexers probably Pericom PI5V331Q or similar.
+
+ * xxx0 is pin xxx of multiplexer U5,
+ * yyy1 is pin yyy of multiplexer U2
+ */
+#define ENA0    0x01
+#define ENB0    0x02
+#define ENA1    0x04
+#define ENB1    0x08
+
+#define IN10    0x10
+#define IN00    0x20
+#define IN11    0x40
+#define IN01    0x80
+
+static void xguard_muxsel(struct bttv *btv, unsigned int input)
+{
+	static const int masks[] = {
+		ENB0, ENB0|IN00, ENB0|IN10, ENB0|IN00|IN10,
+		ENA0, ENA0|IN00, ENA0|IN10, ENA0|IN00|IN10,
+		ENB1, ENB1|IN01, ENB1|IN11, ENB1|IN01|IN11,
+		ENA1, ENA1|IN01, ENA1|IN11, ENA1|IN01|IN11,
+	};
+	gpio_write(masks[input%16]);
+}
+static void picolo_tetra_init(struct bttv *btv)
+{
+	/*This is the video input redirection fonctionality : I DID NOT USED IT. */
+	btwrite (0x08<<16,BT848_GPIO_DATA);/*GPIO[19] [==> 4053 B+C] set to 1 */
+	btwrite (0x04<<16,BT848_GPIO_DATA);/*GPIO[18] [==> 4053 A]  set to 1*/
+}
+static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input)
+{
+
+	dprintk("%d : picolo_tetra_muxsel =>  input = %d\n", btv->c.nr, input);
+	/*Just set the right path in the analog multiplexers : channel 1 -> 4 ==> Analog Mux ==> MUX0*/
+	/*GPIO[20]&GPIO[21] used to choose the right input*/
+	btwrite (input<<20,BT848_GPIO_DATA);
+
+}
+
+/*
+ * ivc120_muxsel [Added by Alan Garfield <alan@fromorbit.com>]
+ *
+ * The IVC120G security card has 4 i2c controlled TDA8540 matrix
+ * swichers to provide 16 channels to MUX0. The TDA8540's have
+ * 4 independent outputs and as such the IVC120G also has the
+ * optional "Monitor Out" bus. This allows the card to be looking
+ * at one input while the monitor is looking at another.
+ *
+ * Since I've couldn't be bothered figuring out how to add an
+ * independent muxsel for the monitor bus, I've just set it to
+ * whatever the card is looking at.
+ *
+ *  OUT0 of the TDA8540's is connected to MUX0         (0x03)
+ *  OUT1 of the TDA8540's is connected to "Monitor Out"        (0x0C)
+ *
+ *  TDA8540_ALT3 IN0-3 = Channel 13 - 16       (0x03)
+ *  TDA8540_ALT4 IN0-3 = Channel 1 - 4         (0x03)
+ *  TDA8540_ALT5 IN0-3 = Channel 5 - 8         (0x03)
+ *  TDA8540_ALT6 IN0-3 = Channel 9 - 12                (0x03)
+ *
+ */
+
+/* All 7 possible sub-ids for the TDA8540 Matrix Switcher */
+#define I2C_TDA8540        0x90
+#define I2C_TDA8540_ALT1   0x92
+#define I2C_TDA8540_ALT2   0x94
+#define I2C_TDA8540_ALT3   0x96
+#define I2C_TDA8540_ALT4   0x98
+#define I2C_TDA8540_ALT5   0x9a
+#define I2C_TDA8540_ALT6   0x9c
+
+static void ivc120_muxsel(struct bttv *btv, unsigned int input)
+{
+	/* Simple maths */
+	int key = input % 4;
+	int matrix = input / 4;
+
+	dprintk("%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n",
+		btv->c.nr, input, matrix, key);
+
+	/* Handles the input selection on the TDA8540's */
+	bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x00,
+		      ((matrix == 3) ? (key | key << 2) : 0x00), 1);
+	bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x00,
+		      ((matrix == 0) ? (key | key << 2) : 0x00), 1);
+	bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x00,
+		      ((matrix == 1) ? (key | key << 2) : 0x00), 1);
+	bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x00,
+		      ((matrix == 2) ? (key | key << 2) : 0x00), 1);
+
+	/* Handles the output enables on the TDA8540's */
+	bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x02,
+		      ((matrix == 3) ? 0x03 : 0x00), 1);  /* 13 - 16 */
+	bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x02,
+		      ((matrix == 0) ? 0x03 : 0x00), 1);  /* 1-4 */
+	bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x02,
+		      ((matrix == 1) ? 0x03 : 0x00), 1);  /* 5-8 */
+	bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x02,
+		      ((matrix == 2) ? 0x03 : 0x00), 1);  /* 9-12 */
+
+	/* 878's MUX0 is already selected for input via muxsel values */
+}
+
+
+/* PXC200 muxsel helper
+ * luke@syseng.anu.edu.au
+ * another transplant
+ * from Alessandro Rubini (rubini@linux.it)
+ *
+ * There are 4 kinds of cards:
+ * PXC200L which is bt848
+ * PXC200F which is bt848 with PIC controlling mux
+ * PXC200AL which is bt878
+ * PXC200AF which is bt878 with PIC controlling mux
+ */
+#define PX_CFG_PXC200F 0x01
+#define PX_FLAG_PXC200A  0x00001000 /* a pxc200A is bt-878 based */
+#define PX_I2C_PIC       0x0f
+#define PX_PXC200A_CARDID 0x200a1295
+#define PX_I2C_CMD_CFG   0x00
+
+static void PXC200_muxsel(struct bttv *btv, unsigned int input)
+{
+	int rc;
+	long mux;
+	int bitmask;
+	unsigned char buf[2];
+
+	/* Read PIC config to determine if this is a PXC200F */
+	/* PX_I2C_CMD_CFG*/
+	buf[0]=0;
+	buf[1]=0;
+	rc=bttv_I2CWrite(btv,(PX_I2C_PIC<<1),buf[0],buf[1],1);
+	if (rc) {
+		pr_debug("%d: PXC200_muxsel: pic cfg write failed:%d\n",
+			 btv->c.nr, rc);
+	  /* not PXC ? do nothing */
+		return;
+	}
+
+	rc=bttv_I2CRead(btv,(PX_I2C_PIC<<1),NULL);
+	if (!(rc & PX_CFG_PXC200F)) {
+		pr_debug("%d: PXC200_muxsel: not PXC200F rc:%d\n",
+			 btv->c.nr, rc);
+		return;
+	}
+
+
+	/* The multiplexer in the 200F is handled by the GPIO port */
+	/* get correct mapping between inputs  */
+	/*  mux = bttv_tvcards[btv->type].muxsel[input] & 3; */
+	/* ** not needed!?   */
+	mux = input;
+
+	/* make sure output pins are enabled */
+	/* bitmask=0x30f; */
+	bitmask=0x302;
+	/* check whether we have a PXC200A */
+	if (btv->cardid == PX_PXC200A_CARDID)  {
+	   bitmask ^= 0x180; /* use 7 and 9, not 8 and 9 */
+	   bitmask |= 7<<4; /* the DAC */
+	}
+	btwrite(bitmask, BT848_GPIO_OUT_EN);
+
+	bitmask = btread(BT848_GPIO_DATA);
+	if (btv->cardid == PX_PXC200A_CARDID)
+	  bitmask = (bitmask & ~0x280) | ((mux & 2) << 8) | ((mux & 1) << 7);
+	else /* older device */
+	  bitmask = (bitmask & ~0x300) | ((mux & 3) << 8);
+	btwrite(bitmask,BT848_GPIO_DATA);
+
+	/*
+	 * Was "to be safe, set the bt848 to input 0"
+	 * Actually, since it's ok at load time, better not messing
+	 * with these bits (on PXC200AF you need to set mux 2 here)
+	 *
+	 * needed because bttv-driver sets mux before calling this function
+	 */
+	if (btv->cardid == PX_PXC200A_CARDID)
+	  btaor(2<<5, ~BT848_IFORM_MUXSEL, BT848_IFORM);
+	else /* older device */
+	  btand(~BT848_IFORM_MUXSEL,BT848_IFORM);
+
+	pr_debug("%d: setting input channel to:%d\n", btv->c.nr, (int)mux);
+}
+
+static void phytec_muxsel(struct bttv *btv, unsigned int input)
+{
+	unsigned int mux = input % 4;
+
+	if (input == btv->svhs)
+		mux = 0;
+
+	gpio_bits(0x3, mux);
+}
+
+/*
+ * GeoVision GV-800(S) functions
+ * Bruno Christo <bchristo@inf.ufsm.br>
+*/
+
+/* This is a function to control the analog switch, which determines which
+ * camera is routed to which controller.  The switch comprises an X-address
+ * (gpio bits 0-3, representing the camera, ranging from 0-15), and a
+ * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3).
+ * A data value (gpio bit 18) of '1' enables the switch, and '0' disables
+ * the switch.  A STROBE bit (gpio bit 17) latches the data value into the
+ * specified address. There is also a chip select (gpio bit 16).
+ * The idea is to set the address and chip select together, bring
+ * STROBE high, write the data, and finally bring STROBE back to low.
+ */
+static void gv800s_write(struct bttv *btv,
+			 unsigned char xaddr,
+			 unsigned char yaddr,
+			 unsigned char data) {
+	/* On the "master" 878A:
+	* GPIO bits 0-9 are used for the analog switch:
+	*   00 - 03:	camera selector
+	*   04 - 06:	878A (controller) selector
+	*   16: 	cselect
+	*   17:		strobe
+	*   18: 	data (1->on, 0->off)
+	*   19:		reset
+	*/
+	const u32 ADDRESS = ((xaddr&0xf) | (yaddr&3)<<4);
+	const u32 CSELECT = 1<<16;
+	const u32 STROBE = 1<<17;
+	const u32 DATA = data<<18;
+
+	gpio_bits(0x1007f, ADDRESS | CSELECT);	/* write ADDRESS and CSELECT */
+	gpio_bits(0x20000, STROBE);		/* STROBE high */
+	gpio_bits(0x40000, DATA);		/* write DATA */
+	gpio_bits(0x20000, ~STROBE);		/* STROBE low */
+}
+
+/*
+ * GeoVision GV-800(S) muxsel
+ *
+ * Each of the 4 cards (controllers) use this function.
+ * The controller using this function selects the input through the GPIO pins
+ * of the "master" card. A pointer to this card is stored in master[btv->c.nr].
+ *
+ * The parameter 'input' is the requested camera number (0-4) on the controller.
+ * The map array has the address of each input. Note that the addresses in the
+ * array are in the sequence the original GeoVision driver uses, that is, set
+ * every controller to input 0, then to input 1, 2, 3, repeat. This means that
+ * the physical "camera 1" connector corresponds to controller 0 input 0,
+ * "camera 2" corresponds to controller 1 input 0, and so on.
+ *
+ * After getting the input address, the function then writes the appropriate
+ * data to the analog switch, and housekeeps the local copy of the switch
+ * information.
+ */
+static void gv800s_muxsel(struct bttv *btv, unsigned int input)
+{
+	struct bttv *mctlr;
+	char *sw_status;
+	int xaddr, yaddr;
+	static unsigned int map[4][4] = { { 0x0, 0x4, 0xa, 0x6 },
+					  { 0x1, 0x5, 0xb, 0x7 },
+					  { 0x2, 0x8, 0xc, 0xe },
+					  { 0x3, 0x9, 0xd, 0xf } };
+	input = input%4;
+	mctlr = master[btv->c.nr];
+	if (mctlr == NULL) {
+		/* do nothing until the "master" is detected */
+		return;
+	}
+	yaddr = (btv->c.nr - mctlr->c.nr) & 3;
+	sw_status = (char *)(&mctlr->mbox_we);
+	xaddr = map[yaddr][input] & 0xf;
+
+	/* Check if the controller/camera pair has changed, ignore otherwise */
+	if (sw_status[yaddr] != xaddr) {
+		/* disable the old switch, enable the new one and save status */
+		gv800s_write(mctlr, sw_status[yaddr], yaddr, 0);
+		sw_status[yaddr] = xaddr;
+		gv800s_write(mctlr, xaddr, yaddr, 1);
+	}
+}
+
+/* GeoVision GV-800(S) "master" chip init */
+static void gv800s_init(struct bttv *btv)
+{
+	char *sw_status = (char *)(&btv->mbox_we);
+	int ix;
+
+	gpio_inout(0xf107f, 0xf107f);
+	gpio_write(1<<19); /* reset the analog MUX */
+	gpio_write(0);
+
+	/* Preset camera 0 to the 4 controllers */
+	for (ix = 0; ix < 4; ix++) {
+		sw_status[ix] = ix;
+		gv800s_write(btv, ix, ix, 1);
+	}
+
+	/* Inputs on the "master" controller need this brightness fix */
+	bttv_I2CWrite(btv, 0x18, 0x5, 0x90, 1);
+
+	if (btv->c.nr > BTTV_MAX-4)
+		return;
+	/*
+	 * Store the "master" controller pointer in the master
+	 * array for later use in the muxsel function.
+	 */
+	master[btv->c.nr]   = btv;
+	master[btv->c.nr+1] = btv;
+	master[btv->c.nr+2] = btv;
+	master[btv->c.nr+3] = btv;
+}
+
+/* ----------------------------------------------------------------------- */
+/* motherboard chipset specific stuff                                      */
+
+void __init bttv_check_chipset(void)
+{
+	int pcipci_fail = 0;
+	struct pci_dev *dev = NULL;
+
+	if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) 	/* should check if target is AGP */
+		pcipci_fail = 1;
+	if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF))
+		triton1 = 1;
+	if (pci_pci_problems & PCIPCI_VSFX)
+		vsfx = 1;
+#ifdef PCIPCI_ALIMAGIK
+	if (pci_pci_problems & PCIPCI_ALIMAGIK)
+		latency = 0x0A;
+#endif
+
+
+	/* print warnings about any quirks found */
+	if (triton1)
+		pr_info("Host bridge needs ETBF enabled\n");
+	if (vsfx)
+		pr_info("Host bridge needs VSFX enabled\n");
+	if (pcipci_fail) {
+		pr_info("bttv and your chipset may not work together\n");
+		if (!no_overlay) {
+			pr_info("overlay will be disabled\n");
+			no_overlay = 1;
+		} else {
+			pr_info("overlay forced. Use this option at your own risk.\n");
+		}
+	}
+	if (UNSET != latency)
+		pr_info("pci latency fixup [%d]\n", latency);
+	while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL,
+				      PCI_DEVICE_ID_INTEL_82441, dev))) {
+		unsigned char b;
+		pci_read_config_byte(dev, 0x53, &b);
+		if (bttv_debug)
+			pr_info("Host bridge: 82441FX Natoma, bufcon=0x%02x\n",
+				b);
+	}
+}
+
+int __devinit bttv_handle_chipset(struct bttv *btv)
+{
+	unsigned char command;
+
+	if (!triton1 && !vsfx && UNSET == latency)
+		return 0;
+
+	if (bttv_verbose) {
+		if (triton1)
+			pr_info("%d: enabling ETBF (430FX/VP3 compatibility)\n",
+				btv->c.nr);
+		if (vsfx && btv->id >= 878)
+			pr_info("%d: enabling VSFX\n", btv->c.nr);
+		if (UNSET != latency)
+			pr_info("%d: setting pci timer to %d\n",
+				btv->c.nr, latency);
+	}
+
+	if (btv->id < 878) {
+		/* bt848 (mis)uses a bit in the irq mask for etbf */
+		if (triton1)
+			btv->triton1 = BT848_INT_ETBF;
+	} else {
+		/* bt878 has a bit in the pci config space for it */
+		pci_read_config_byte(btv->c.pci, BT878_DEVCTRL, &command);
+		if (triton1)
+			command |= BT878_EN_TBFX;
+		if (vsfx)
+			command |= BT878_EN_VSFX;
+		pci_write_config_byte(btv->c.pci, BT878_DEVCTRL, command);
+	}
+	if (UNSET != latency)
+		pci_write_config_byte(btv->c.pci, PCI_LATENCY_TIMER, latency);
+	return 0;
+}
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
new file mode 100644
index 0000000..b58ff87
--- /dev/null
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -0,0 +1,4630 @@
+/*
+
+    bttv - Bt848 frame grabber driver
+
+    Copyright (C) 1996,97,98 Ralph  Metzler <rjkm@thp.uni-koeln.de>
+			   & Marcus Metzler <mocm@thp.uni-koeln.de>
+    (c) 1999-2002 Gerd Knorr <kraxel@bytesex.org>
+
+    some v4l2 code lines are taken from Justin's bttv2 driver which is
+    (c) 2000 Justin Schoeman <justin@suntiger.ee.up.ac.za>
+
+    V4L1 removal from:
+    (c) 2005-2006 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
+
+    Fixes to be fully V4L2 compliant by
+    (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+
+    Cropping and overscan support
+    Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
+    Sponsored by OPQ Systems AB
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/kdev_t.h>
+#include "bttvp.h"
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/tvaudio.h>
+#include <media/msp3400.h>
+
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+#include <media/saa6588.h>
+
+#define BTTV_VERSION "0.9.19"
+
+unsigned int bttv_num;			/* number of Bt848s in use */
+struct bttv *bttvs[BTTV_MAX];
+
+unsigned int bttv_debug;
+unsigned int bttv_verbose = 1;
+unsigned int bttv_gpio;
+
+/* config variables */
+#ifdef __BIG_ENDIAN
+static unsigned int bigendian=1;
+#else
+static unsigned int bigendian;
+#endif
+static unsigned int radio[BTTV_MAX];
+static unsigned int irq_debug;
+static unsigned int gbuffers = 8;
+static unsigned int gbufsize = 0x208000;
+static unsigned int reset_crop = 1;
+
+static int video_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
+static int radio_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
+static int vbi_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
+static int debug_latency;
+static int disable_ir;
+
+static unsigned int fdsr;
+
+/* options */
+static unsigned int combfilter;
+static unsigned int lumafilter;
+static unsigned int automute    = 1;
+static unsigned int chroma_agc;
+static unsigned int adc_crush   = 1;
+static unsigned int whitecrush_upper = 0xCF;
+static unsigned int whitecrush_lower = 0x7F;
+static unsigned int vcr_hack;
+static unsigned int irq_iswitch;
+static unsigned int uv_ratio    = 50;
+static unsigned int full_luma_range;
+static unsigned int coring;
+
+/* API features (turn on/off stuff for testing) */
+static unsigned int v4l2        = 1;
+
+/* insmod args */
+module_param(bttv_verbose,      int, 0644);
+module_param(bttv_gpio,         int, 0644);
+module_param(bttv_debug,        int, 0644);
+module_param(irq_debug,         int, 0644);
+module_param(debug_latency,     int, 0644);
+module_param(disable_ir,        int, 0444);
+
+module_param(fdsr,              int, 0444);
+module_param(gbuffers,          int, 0444);
+module_param(gbufsize,          int, 0444);
+module_param(reset_crop,        int, 0444);
+
+module_param(v4l2,              int, 0644);
+module_param(bigendian,         int, 0644);
+module_param(irq_iswitch,       int, 0644);
+module_param(combfilter,        int, 0444);
+module_param(lumafilter,        int, 0444);
+module_param(automute,          int, 0444);
+module_param(chroma_agc,        int, 0444);
+module_param(adc_crush,         int, 0444);
+module_param(whitecrush_upper,  int, 0444);
+module_param(whitecrush_lower,  int, 0444);
+module_param(vcr_hack,          int, 0444);
+module_param(uv_ratio,          int, 0444);
+module_param(full_luma_range,   int, 0444);
+module_param(coring,            int, 0444);
+
+module_param_array(radio,       int, NULL, 0444);
+module_param_array(video_nr,    int, NULL, 0444);
+module_param_array(radio_nr,    int, NULL, 0444);
+module_param_array(vbi_nr,      int, NULL, 0444);
+
+MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
+MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
+MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
+MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
+MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
+MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
+MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
+MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
+MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
+MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default "
+		 "is 1 (yes) for compatibility with older applications");
+MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
+MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
+MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
+MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207");
+MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127");
+MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
+MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
+MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");
+MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");
+MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");
+MODULE_PARM_DESC(video_nr, "video device numbers");
+MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
+MODULE_PARM_DESC(radio_nr, "radio device numbers");
+
+MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
+MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(BTTV_VERSION);
+
+/* ----------------------------------------------------------------------- */
+/* sysfs                                                                   */
+
+static ssize_t show_card(struct device *cd,
+			 struct device_attribute *attr, char *buf)
+{
+	struct video_device *vfd = container_of(cd, struct video_device, dev);
+	struct bttv *btv = video_get_drvdata(vfd);
+	return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
+}
+static DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
+
+/* ----------------------------------------------------------------------- */
+/* dvb auto-load setup                                                     */
+#if defined(CONFIG_MODULES) && defined(MODULE)
+static void request_module_async(struct work_struct *work)
+{
+	request_module("dvb-bt8xx");
+}
+
+static void request_modules(struct bttv *dev)
+{
+	INIT_WORK(&dev->request_module_wk, request_module_async);
+	schedule_work(&dev->request_module_wk);
+}
+
+static void flush_request_modules(struct bttv *dev)
+{
+	flush_work_sync(&dev->request_module_wk);
+}
+#else
+#define request_modules(dev)
+#define flush_request_modules(dev)
+#endif /* CONFIG_MODULES */
+
+
+/* ----------------------------------------------------------------------- */
+/* static data                                                             */
+
+/* special timing tables from conexant... */
+static u8 SRAM_Table[][60] =
+{
+	/* PAL digital input over GPIO[7:0] */
+	{
+		45, // 45 bytes following
+		0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,
+		0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,
+		0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,
+		0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,
+		0x37,0x00,0xAF,0x21,0x00
+	},
+	/* NTSC digital input over GPIO[7:0] */
+	{
+		51, // 51 bytes following
+		0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,
+		0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,
+		0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,
+		0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,
+		0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,
+		0x00,
+	},
+	// TGB_NTSC392 // quartzsight
+	// This table has been modified to be used for Fusion Rev D
+	{
+		0x2A, // size of table = 42
+		0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
+		0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
+		0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
+		0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
+		0x20, 0x00
+	}
+};
+
+/* minhdelayx1	first video pixel we can capture on a line and
+   hdelayx1	start of active video, both relative to rising edge of
+		/HRESET pulse (0H) in 1 / fCLKx1.
+   swidth	width of active video and
+   totalwidth	total line width, both in 1 / fCLKx1.
+   sqwidth	total line width in square pixels.
+   vdelay	start of active video in 2 * field lines relative to
+		trailing edge of /VRESET pulse (VDELAY register).
+   sheight	height of active video in 2 * field lines.
+   videostart0	ITU-R frame line number of the line corresponding
+		to vdelay in the first field. */
+#define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth,	 \
+		vdelay, sheight, videostart0)				 \
+	.cropcap.bounds.left = minhdelayx1,				 \
+	/* * 2 because vertically we count field lines times two, */	 \
+	/* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */		 \
+	.cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \
+	/* 4 is a safety margin at the end of the line. */		 \
+	.cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4,	 \
+	.cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY,	 \
+	.cropcap.defrect.left = hdelayx1,				 \
+	.cropcap.defrect.top = (videostart0) * 2,			 \
+	.cropcap.defrect.width = swidth,				 \
+	.cropcap.defrect.height = sheight,				 \
+	.cropcap.pixelaspect.numerator = totalwidth,			 \
+	.cropcap.pixelaspect.denominator = sqwidth,
+
+const struct bttv_tvnorm bttv_tvnorms[] = {
+	/* PAL-BDGHI */
+	/* max. active video is actually 922, but 924 is divisible by 4 and 3! */
+	/* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
+	{
+		.v4l2_id        = V4L2_STD_PAL,
+		.name           = "PAL",
+		.Fsc            = 35468950,
+		.swidth         = 924,
+		.sheight        = 576,
+		.totalwidth     = 1135,
+		.adelay         = 0x7f,
+		.bdelay         = 0x72,
+		.iform          = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+		.scaledtwidth   = 1135,
+		.hdelayx1       = 186,
+		.hactivex1      = 924,
+		.vdelay         = 0x20,
+		.vbipack        = 255, /* min (2048 / 4, 0x1ff) & 0xff */
+		.sram           = 0,
+		/* ITU-R frame line number of the first VBI line
+		   we can capture, of the first and second field.
+		   The last line is determined by cropcap.bounds. */
+		.vbistart       = { 7, 320 },
+		CROPCAP(/* minhdelayx1 */ 68,
+			/* hdelayx1 */ 186,
+			/* Should be (768 * 1135 + 944 / 2) / 944.
+			   cropcap.defrect is used for image width
+			   checks, so we keep the old value 924. */
+			/* swidth */ 924,
+			/* totalwidth */ 1135,
+			/* sqwidth */ 944,
+			/* vdelay */ 0x20,
+			/* sheight */ 576,
+			/* videostart0 */ 23)
+		/* bt878 (and bt848?) can capture another
+		   line below active video. */
+		.cropcap.bounds.height = (576 + 2) + 0x20 - 2,
+	},{
+		.v4l2_id        = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
+		.name           = "NTSC",
+		.Fsc            = 28636363,
+		.swidth         = 768,
+		.sheight        = 480,
+		.totalwidth     = 910,
+		.adelay         = 0x68,
+		.bdelay         = 0x5d,
+		.iform          = (BT848_IFORM_NTSC|BT848_IFORM_XT0),
+		.scaledtwidth   = 910,
+		.hdelayx1       = 128,
+		.hactivex1      = 910,
+		.vdelay         = 0x1a,
+		.vbipack        = 144, /* min (1600 / 4, 0x1ff) & 0xff */
+		.sram           = 1,
+		.vbistart	= { 10, 273 },
+		CROPCAP(/* minhdelayx1 */ 68,
+			/* hdelayx1 */ 128,
+			/* Should be (640 * 910 + 780 / 2) / 780? */
+			/* swidth */ 768,
+			/* totalwidth */ 910,
+			/* sqwidth */ 780,
+			/* vdelay */ 0x1a,
+			/* sheight */ 480,
+			/* videostart0 */ 23)
+	},{
+		.v4l2_id        = V4L2_STD_SECAM,
+		.name           = "SECAM",
+		.Fsc            = 35468950,
+		.swidth         = 924,
+		.sheight        = 576,
+		.totalwidth     = 1135,
+		.adelay         = 0x7f,
+		.bdelay         = 0xb0,
+		.iform          = (BT848_IFORM_SECAM|BT848_IFORM_XT1),
+		.scaledtwidth   = 1135,
+		.hdelayx1       = 186,
+		.hactivex1      = 922,
+		.vdelay         = 0x20,
+		.vbipack        = 255,
+		.sram           = 0, /* like PAL, correct? */
+		.vbistart	= { 7, 320 },
+		CROPCAP(/* minhdelayx1 */ 68,
+			/* hdelayx1 */ 186,
+			/* swidth */ 924,
+			/* totalwidth */ 1135,
+			/* sqwidth */ 944,
+			/* vdelay */ 0x20,
+			/* sheight */ 576,
+			/* videostart0 */ 23)
+	},{
+		.v4l2_id        = V4L2_STD_PAL_Nc,
+		.name           = "PAL-Nc",
+		.Fsc            = 28636363,
+		.swidth         = 640,
+		.sheight        = 576,
+		.totalwidth     = 910,
+		.adelay         = 0x68,
+		.bdelay         = 0x5d,
+		.iform          = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
+		.scaledtwidth   = 780,
+		.hdelayx1       = 130,
+		.hactivex1      = 734,
+		.vdelay         = 0x1a,
+		.vbipack        = 144,
+		.sram           = -1,
+		.vbistart	= { 7, 320 },
+		CROPCAP(/* minhdelayx1 */ 68,
+			/* hdelayx1 */ 130,
+			/* swidth */ (640 * 910 + 780 / 2) / 780,
+			/* totalwidth */ 910,
+			/* sqwidth */ 780,
+			/* vdelay */ 0x1a,
+			/* sheight */ 576,
+			/* videostart0 */ 23)
+	},{
+		.v4l2_id        = V4L2_STD_PAL_M,
+		.name           = "PAL-M",
+		.Fsc            = 28636363,
+		.swidth         = 640,
+		.sheight        = 480,
+		.totalwidth     = 910,
+		.adelay         = 0x68,
+		.bdelay         = 0x5d,
+		.iform          = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
+		.scaledtwidth   = 780,
+		.hdelayx1       = 135,
+		.hactivex1      = 754,
+		.vdelay         = 0x1a,
+		.vbipack        = 144,
+		.sram           = -1,
+		.vbistart	= { 10, 273 },
+		CROPCAP(/* minhdelayx1 */ 68,
+			/* hdelayx1 */ 135,
+			/* swidth */ (640 * 910 + 780 / 2) / 780,
+			/* totalwidth */ 910,
+			/* sqwidth */ 780,
+			/* vdelay */ 0x1a,
+			/* sheight */ 480,
+			/* videostart0 */ 23)
+	},{
+		.v4l2_id        = V4L2_STD_PAL_N,
+		.name           = "PAL-N",
+		.Fsc            = 35468950,
+		.swidth         = 768,
+		.sheight        = 576,
+		.totalwidth     = 1135,
+		.adelay         = 0x7f,
+		.bdelay         = 0x72,
+		.iform          = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
+		.scaledtwidth   = 944,
+		.hdelayx1       = 186,
+		.hactivex1      = 922,
+		.vdelay         = 0x20,
+		.vbipack        = 144,
+		.sram           = -1,
+		.vbistart       = { 7, 320 },
+		CROPCAP(/* minhdelayx1 */ 68,
+			/* hdelayx1 */ 186,
+			/* swidth */ (768 * 1135 + 944 / 2) / 944,
+			/* totalwidth */ 1135,
+			/* sqwidth */ 944,
+			/* vdelay */ 0x20,
+			/* sheight */ 576,
+			/* videostart0 */ 23)
+	},{
+		.v4l2_id        = V4L2_STD_NTSC_M_JP,
+		.name           = "NTSC-JP",
+		.Fsc            = 28636363,
+		.swidth         = 640,
+		.sheight        = 480,
+		.totalwidth     = 910,
+		.adelay         = 0x68,
+		.bdelay         = 0x5d,
+		.iform          = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
+		.scaledtwidth   = 780,
+		.hdelayx1       = 135,
+		.hactivex1      = 754,
+		.vdelay         = 0x16,
+		.vbipack        = 144,
+		.sram           = -1,
+		.vbistart       = { 10, 273 },
+		CROPCAP(/* minhdelayx1 */ 68,
+			/* hdelayx1 */ 135,
+			/* swidth */ (640 * 910 + 780 / 2) / 780,
+			/* totalwidth */ 910,
+			/* sqwidth */ 780,
+			/* vdelay */ 0x16,
+			/* sheight */ 480,
+			/* videostart0 */ 23)
+	},{
+		/* that one hopefully works with the strange timing
+		 * which video recorders produce when playing a NTSC
+		 * tape on a PAL TV ... */
+		.v4l2_id        = V4L2_STD_PAL_60,
+		.name           = "PAL-60",
+		.Fsc            = 35468950,
+		.swidth         = 924,
+		.sheight        = 480,
+		.totalwidth     = 1135,
+		.adelay         = 0x7f,
+		.bdelay         = 0x72,
+		.iform          = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+		.scaledtwidth   = 1135,
+		.hdelayx1       = 186,
+		.hactivex1      = 924,
+		.vdelay         = 0x1a,
+		.vbipack        = 255,
+		.vtotal         = 524,
+		.sram           = -1,
+		.vbistart	= { 10, 273 },
+		CROPCAP(/* minhdelayx1 */ 68,
+			/* hdelayx1 */ 186,
+			/* swidth */ 924,
+			/* totalwidth */ 1135,
+			/* sqwidth */ 944,
+			/* vdelay */ 0x1a,
+			/* sheight */ 480,
+			/* videostart0 */ 23)
+	}
+};
+static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
+
+/* ----------------------------------------------------------------------- */
+/* bttv format list
+   packed pixel formats must come first */
+static const struct bttv_format formats[] = {
+	{
+		.name     = "8 bpp, gray",
+		.fourcc   = V4L2_PIX_FMT_GREY,
+		.btformat = BT848_COLOR_FMT_Y8,
+		.depth    = 8,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "8 bpp, dithered color",
+		.fourcc   = V4L2_PIX_FMT_HI240,
+		.btformat = BT848_COLOR_FMT_RGB8,
+		.depth    = 8,
+		.flags    = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
+	},{
+		.name     = "15 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_RGB555,
+		.btformat = BT848_COLOR_FMT_RGB15,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "15 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB555X,
+		.btformat = BT848_COLOR_FMT_RGB15,
+		.btswap   = 0x03, /* byteswap */
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "16 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_RGB565,
+		.btformat = BT848_COLOR_FMT_RGB16,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "16 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB565X,
+		.btformat = BT848_COLOR_FMT_RGB16,
+		.btswap   = 0x03, /* byteswap */
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "24 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_BGR24,
+		.btformat = BT848_COLOR_FMT_RGB24,
+		.depth    = 24,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "32 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_BGR32,
+		.btformat = BT848_COLOR_FMT_RGB32,
+		.depth    = 32,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "32 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB32,
+		.btformat = BT848_COLOR_FMT_RGB32,
+		.btswap   = 0x0f, /* byte+word swap */
+		.depth    = 32,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "4:2:2, packed, YUYV",
+		.fourcc   = V4L2_PIX_FMT_YUYV,
+		.btformat = BT848_COLOR_FMT_YUY2,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "4:2:2, packed, UYVY",
+		.fourcc   = V4L2_PIX_FMT_UYVY,
+		.btformat = BT848_COLOR_FMT_YUY2,
+		.btswap   = 0x03, /* byteswap */
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "4:2:2, planar, Y-Cb-Cr",
+		.fourcc   = V4L2_PIX_FMT_YUV422P,
+		.btformat = BT848_COLOR_FMT_YCrCb422,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PLANAR,
+		.hshift   = 1,
+		.vshift   = 0,
+	},{
+		.name     = "4:2:0, planar, Y-Cb-Cr",
+		.fourcc   = V4L2_PIX_FMT_YUV420,
+		.btformat = BT848_COLOR_FMT_YCrCb422,
+		.depth    = 12,
+		.flags    = FORMAT_FLAGS_PLANAR,
+		.hshift   = 1,
+		.vshift   = 1,
+	},{
+		.name     = "4:2:0, planar, Y-Cr-Cb",
+		.fourcc   = V4L2_PIX_FMT_YVU420,
+		.btformat = BT848_COLOR_FMT_YCrCb422,
+		.depth    = 12,
+		.flags    = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
+		.hshift   = 1,
+		.vshift   = 1,
+	},{
+		.name     = "4:1:1, planar, Y-Cb-Cr",
+		.fourcc   = V4L2_PIX_FMT_YUV411P,
+		.btformat = BT848_COLOR_FMT_YCrCb411,
+		.depth    = 12,
+		.flags    = FORMAT_FLAGS_PLANAR,
+		.hshift   = 2,
+		.vshift   = 0,
+	},{
+		.name     = "4:1:0, planar, Y-Cb-Cr",
+		.fourcc   = V4L2_PIX_FMT_YUV410,
+		.btformat = BT848_COLOR_FMT_YCrCb411,
+		.depth    = 9,
+		.flags    = FORMAT_FLAGS_PLANAR,
+		.hshift   = 2,
+		.vshift   = 2,
+	},{
+		.name     = "4:1:0, planar, Y-Cr-Cb",
+		.fourcc   = V4L2_PIX_FMT_YVU410,
+		.btformat = BT848_COLOR_FMT_YCrCb411,
+		.depth    = 9,
+		.flags    = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
+		.hshift   = 2,
+		.vshift   = 2,
+	},{
+		.name     = "raw scanlines",
+		.fourcc   = -1,
+		.btformat = BT848_COLOR_FMT_RAW,
+		.depth    = 8,
+		.flags    = FORMAT_FLAGS_RAW,
+	}
+};
+static const unsigned int FORMATS = ARRAY_SIZE(formats);
+
+/* ----------------------------------------------------------------------- */
+
+#define V4L2_CID_PRIVATE_CHROMA_AGC  (V4L2_CID_PRIVATE_BASE + 0)
+#define V4L2_CID_PRIVATE_COMBFILTER  (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_PRIVATE_AUTOMUTE    (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_PRIVATE_LUMAFILTER  (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_PRIVATE_AGC_CRUSH   (V4L2_CID_PRIVATE_BASE + 4)
+#define V4L2_CID_PRIVATE_VCR_HACK    (V4L2_CID_PRIVATE_BASE + 5)
+#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER   (V4L2_CID_PRIVATE_BASE + 6)
+#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER   (V4L2_CID_PRIVATE_BASE + 7)
+#define V4L2_CID_PRIVATE_UV_RATIO    (V4L2_CID_PRIVATE_BASE + 8)
+#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE    (V4L2_CID_PRIVATE_BASE + 9)
+#define V4L2_CID_PRIVATE_CORING      (V4L2_CID_PRIVATE_BASE + 10)
+#define V4L2_CID_PRIVATE_LASTP1      (V4L2_CID_PRIVATE_BASE + 11)
+
+static const struct v4l2_queryctrl no_ctl = {
+	.name  = "42",
+	.flags = V4L2_CTRL_FLAG_DISABLED,
+};
+static const struct v4l2_queryctrl bttv_ctls[] = {
+	/* --- video --- */
+	{
+		.id            = V4L2_CID_BRIGHTNESS,
+		.name          = "Brightness",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 256,
+		.default_value = 32768,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_CONTRAST,
+		.name          = "Contrast",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 128,
+		.default_value = 27648,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_SATURATION,
+		.name          = "Saturation",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 128,
+		.default_value = 32768,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_HUE,
+		.name          = "Hue",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 256,
+		.default_value = 32768,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},
+	/* --- audio --- */
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_AUDIO_VOLUME,
+		.name          = "Volume",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535/100,
+		.default_value = 65535,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_AUDIO_BALANCE,
+		.name          = "Balance",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535/100,
+		.default_value = 32768,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_AUDIO_BASS,
+		.name          = "Bass",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535/100,
+		.default_value = 32768,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_AUDIO_TREBLE,
+		.name          = "Treble",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535/100,
+		.default_value = 32768,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},
+	/* --- private --- */
+	{
+		.id            = V4L2_CID_PRIVATE_CHROMA_AGC,
+		.name          = "chroma agc",
+		.minimum       = 0,
+		.maximum       = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_PRIVATE_COMBFILTER,
+		.name          = "combfilter",
+		.minimum       = 0,
+		.maximum       = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_PRIVATE_AUTOMUTE,
+		.name          = "automute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_PRIVATE_LUMAFILTER,
+		.name          = "luma decimation filter",
+		.minimum       = 0,
+		.maximum       = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_PRIVATE_AGC_CRUSH,
+		.name          = "agc crush",
+		.minimum       = 0,
+		.maximum       = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_PRIVATE_VCR_HACK,
+		.name          = "vcr hack",
+		.minimum       = 0,
+		.maximum       = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,
+		.name          = "whitecrush upper",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = 0xCF,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,
+		.name          = "whitecrush lower",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = 0x7F,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_PRIVATE_UV_RATIO,
+		.name          = "uv ratio",
+		.minimum       = 0,
+		.maximum       = 100,
+		.step          = 1,
+		.default_value = 50,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
+		.name          = "full luma range",
+		.minimum       = 0,
+		.maximum       = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_PRIVATE_CORING,
+		.name          = "coring",
+		.minimum       = 0,
+		.maximum       = 3,
+		.step          = 1,
+		.default_value = 0,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	}
+
+
+
+};
+
+static const struct v4l2_queryctrl *ctrl_by_id(int id)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++)
+		if (bttv_ctls[i].id == id)
+			return bttv_ctls+i;
+
+	return NULL;
+}
+
+/* ----------------------------------------------------------------------- */
+/* resource management                                                     */
+
+/*
+   RESOURCE_    allocated by                freed by
+
+   VIDEO_READ   bttv_read 1)                bttv_read 2)
+
+   VIDEO_STREAM VIDIOC_STREAMON             VIDIOC_STREAMOFF
+		 VIDIOC_QBUF 1)              bttv_release
+		 VIDIOCMCAPTURE 1)
+
+   OVERLAY	 VIDIOCCAPTURE on            VIDIOCCAPTURE off
+		 VIDIOC_OVERLAY on           VIDIOC_OVERLAY off
+		 3)                          bttv_release
+
+   VBI		 VIDIOC_STREAMON             VIDIOC_STREAMOFF
+		 VIDIOC_QBUF 1)              bttv_release
+		 bttv_read, bttv_poll 1) 4)
+
+   1) The resource must be allocated when we enter buffer prepare functions
+      and remain allocated while buffers are in the DMA queue.
+   2) This is a single frame read.
+   3) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when
+      RESOURCE_OVERLAY is allocated.
+   4) This is a continuous read, implies VIDIOC_STREAMON.
+
+   Note this driver permits video input and standard changes regardless if
+   resources are allocated.
+*/
+
+#define VBI_RESOURCES (RESOURCE_VBI)
+#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \
+			 RESOURCE_VIDEO_STREAM | \
+			 RESOURCE_OVERLAY)
+
+static
+int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit)
+{
+	int xbits; /* mutual exclusive resources */
+
+	if (fh->resources & bit)
+		/* have it already allocated */
+		return 1;
+
+	xbits = bit;
+	if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM))
+		xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;
+
+	/* is it free? */
+	if (btv->resources & xbits) {
+		/* no, someone else uses it */
+		goto fail;
+	}
+
+	if ((bit & VIDEO_RESOURCES)
+	    && 0 == (btv->resources & VIDEO_RESOURCES)) {
+		/* Do crop - use current, don't - use default parameters. */
+		__s32 top = btv->crop[!!fh->do_crop].rect.top;
+
+		if (btv->vbi_end > top)
+			goto fail;
+
+		/* We cannot capture the same line as video and VBI data.
+		   Claim scan lines crop[].rect.top to bottom. */
+		btv->crop_start = top;
+	} else if (bit & VBI_RESOURCES) {
+		__s32 end = fh->vbi_fmt.end;
+
+		if (end > btv->crop_start)
+			goto fail;
+
+		/* Claim scan lines above fh->vbi_fmt.end. */
+		btv->vbi_end = end;
+	}
+
+	/* it's free, grab it */
+	fh->resources  |= bit;
+	btv->resources |= bit;
+	return 1;
+
+ fail:
+	return 0;
+}
+
+static
+int check_btres(struct bttv_fh *fh, int bit)
+{
+	return (fh->resources & bit);
+}
+
+static
+int locked_btres(struct bttv *btv, int bit)
+{
+	return (btv->resources & bit);
+}
+
+/* Call with btv->lock down. */
+static void
+disclaim_vbi_lines(struct bttv *btv)
+{
+	btv->vbi_end = 0;
+}
+
+/* Call with btv->lock down. */
+static void
+disclaim_video_lines(struct bttv *btv)
+{
+	const struct bttv_tvnorm *tvnorm;
+	u8 crop;
+
+	tvnorm = &bttv_tvnorms[btv->tvnorm];
+	btv->crop_start = tvnorm->cropcap.bounds.top
+		+ tvnorm->cropcap.bounds.height;
+
+	/* VBI capturing ends at VDELAY, start of video capturing, no
+	   matter how many lines the VBI RISC program expects. When video
+	   capturing is off, it shall no longer "preempt" VBI capturing,
+	   so we set VDELAY to maximum. */
+	crop = btread(BT848_E_CROP) | 0xc0;
+	btwrite(crop, BT848_E_CROP);
+	btwrite(0xfe, BT848_E_VDELAY_LO);
+	btwrite(crop, BT848_O_CROP);
+	btwrite(0xfe, BT848_O_VDELAY_LO);
+}
+
+static
+void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits)
+{
+	if ((fh->resources & bits) != bits) {
+		/* trying to free resources not allocated by us ... */
+		pr_err("BUG! (btres)\n");
+	}
+	fh->resources  &= ~bits;
+	btv->resources &= ~bits;
+
+	bits = btv->resources;
+
+	if (0 == (bits & VIDEO_RESOURCES))
+		disclaim_video_lines(btv);
+
+	if (0 == (bits & VBI_RESOURCES))
+		disclaim_vbi_lines(btv);
+}
+
+/* ----------------------------------------------------------------------- */
+/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC          */
+
+/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C
+   PLL_X = Reference pre-divider (0=1, 1=2)
+   PLL_C = Post divider (0=6, 1=4)
+   PLL_I = Integer input
+   PLL_F = Fractional input
+
+   F_input = 28.636363 MHz:
+   PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
+*/
+
+static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
+{
+	unsigned char fl, fh, fi;
+
+	/* prevent overflows */
+	fin/=4;
+	fout/=4;
+
+	fout*=12;
+	fi=fout/fin;
+
+	fout=(fout%fin)*256;
+	fh=fout/fin;
+
+	fout=(fout%fin)*256;
+	fl=fout/fin;
+
+	btwrite(fl, BT848_PLL_F_LO);
+	btwrite(fh, BT848_PLL_F_HI);
+	btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);
+}
+
+static void set_pll(struct bttv *btv)
+{
+	int i;
+
+	if (!btv->pll.pll_crystal)
+		return;
+
+	if (btv->pll.pll_ofreq == btv->pll.pll_current) {
+		dprintk("%d: PLL: no change required\n", btv->c.nr);
+		return;
+	}
+
+	if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {
+		/* no PLL needed */
+		if (btv->pll.pll_current == 0)
+			return;
+		if (bttv_verbose)
+			pr_info("%d: PLL can sleep, using XTAL (%d)\n",
+				btv->c.nr, btv->pll.pll_ifreq);
+		btwrite(0x00,BT848_TGCTRL);
+		btwrite(0x00,BT848_PLL_XCI);
+		btv->pll.pll_current = 0;
+		return;
+	}
+
+	if (bttv_verbose)
+		pr_info("%d: Setting PLL: %d => %d (needs up to 100ms)\n",
+			btv->c.nr,
+			btv->pll.pll_ifreq, btv->pll.pll_ofreq);
+	set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
+
+	for (i=0; i<10; i++) {
+		/*  Let other people run while the PLL stabilizes */
+		msleep(10);
+
+		if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
+			btwrite(0,BT848_DSTATUS);
+		} else {
+			btwrite(0x08,BT848_TGCTRL);
+			btv->pll.pll_current = btv->pll.pll_ofreq;
+			if (bttv_verbose)
+				pr_info("PLL set ok\n");
+			return;
+		}
+	}
+	btv->pll.pll_current = -1;
+	if (bttv_verbose)
+		pr_info("Setting PLL failed\n");
+	return;
+}
+
+/* used to switch between the bt848's analog/digital video capture modes */
+static void bt848A_set_timing(struct bttv *btv)
+{
+	int i, len;
+	int table_idx = bttv_tvnorms[btv->tvnorm].sram;
+	int fsc       = bttv_tvnorms[btv->tvnorm].Fsc;
+
+	if (btv->input == btv->dig) {
+		dprintk("%d: load digital timing table (table_idx=%d)\n",
+			btv->c.nr,table_idx);
+
+		/* timing change...reset timing generator address */
+		btwrite(0x00, BT848_TGCTRL);
+		btwrite(0x02, BT848_TGCTRL);
+		btwrite(0x00, BT848_TGCTRL);
+
+		len=SRAM_Table[table_idx][0];
+		for(i = 1; i <= len; i++)
+			btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
+		btv->pll.pll_ofreq = 27000000;
+
+		set_pll(btv);
+		btwrite(0x11, BT848_TGCTRL);
+		btwrite(0x41, BT848_DVSIF);
+	} else {
+		btv->pll.pll_ofreq = fsc;
+		set_pll(btv);
+		btwrite(0x0, BT848_DVSIF);
+	}
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void bt848_bright(struct bttv *btv, int bright)
+{
+	int value;
+
+	// printk("set bright: %d\n", bright); // DEBUG
+	btv->bright = bright;
+
+	/* We want -128 to 127 we get 0-65535 */
+	value = (bright >> 8) - 128;
+	btwrite(value & 0xff, BT848_BRIGHT);
+}
+
+static void bt848_hue(struct bttv *btv, int hue)
+{
+	int value;
+
+	btv->hue = hue;
+
+	/* -128 to 127 */
+	value = (hue >> 8) - 128;
+	btwrite(value & 0xff, BT848_HUE);
+}
+
+static void bt848_contrast(struct bttv *btv, int cont)
+{
+	int value,hibit;
+
+	btv->contrast = cont;
+
+	/* 0-511 */
+	value = (cont  >> 7);
+	hibit = (value >> 6) & 4;
+	btwrite(value & 0xff, BT848_CONTRAST_LO);
+	btaor(hibit, ~4, BT848_E_CONTROL);
+	btaor(hibit, ~4, BT848_O_CONTROL);
+}
+
+static void bt848_sat(struct bttv *btv, int color)
+{
+	int val_u,val_v,hibits;
+
+	btv->saturation = color;
+
+	/* 0-511 for the color */
+	val_u   = ((color * btv->opt_uv_ratio) / 50) >> 7;
+	val_v   = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
+	hibits  = (val_u >> 7) & 2;
+	hibits |= (val_v >> 8) & 1;
+	btwrite(val_u & 0xff, BT848_SAT_U_LO);
+	btwrite(val_v & 0xff, BT848_SAT_V_LO);
+	btaor(hibits, ~3, BT848_E_CONTROL);
+	btaor(hibits, ~3, BT848_O_CONTROL);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int
+video_mux(struct bttv *btv, unsigned int input)
+{
+	int mux,mask2;
+
+	if (input >= bttv_tvcards[btv->c.type].video_inputs)
+		return -EINVAL;
+
+	/* needed by RemoteVideo MX */
+	mask2 = bttv_tvcards[btv->c.type].gpiomask2;
+	if (mask2)
+		gpio_inout(mask2,mask2);
+
+	if (input == btv->svhs)  {
+		btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
+		btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
+	} else {
+		btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
+		btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
+	}
+	mux = bttv_muxsel(btv, input);
+	btaor(mux<<5, ~(3<<5), BT848_IFORM);
+	dprintk("%d: video mux: input=%d mux=%d\n", btv->c.nr, input, mux);
+
+	/* card specific hook */
+	if(bttv_tvcards[btv->c.type].muxsel_hook)
+		bttv_tvcards[btv->c.type].muxsel_hook (btv, input);
+	return 0;
+}
+
+static char *audio_modes[] = {
+	"audio: tuner", "audio: radio", "audio: extern",
+	"audio: intern", "audio: mute"
+};
+
+static int
+audio_mux(struct bttv *btv, int input, int mute)
+{
+	int gpio_val, signal;
+	struct v4l2_control ctrl;
+
+	gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
+		   bttv_tvcards[btv->c.type].gpiomask);
+	signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
+
+	btv->mute = mute;
+	btv->audio = input;
+
+	/* automute */
+	mute = mute || (btv->opt_automute && !signal && !btv->radio_user);
+
+	if (mute)
+		gpio_val = bttv_tvcards[btv->c.type].gpiomute;
+	else
+		gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];
+
+	switch (btv->c.type) {
+	case BTTV_BOARD_VOODOOTV_FM:
+	case BTTV_BOARD_VOODOOTV_200:
+		gpio_val = bttv_tda9880_setnorm(btv, gpio_val);
+		break;
+
+	default:
+		gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
+	}
+
+	if (bttv_gpio)
+		bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]);
+	if (in_interrupt())
+		return 0;
+
+	ctrl.id = V4L2_CID_AUDIO_MUTE;
+	ctrl.value = btv->mute;
+	bttv_call_all(btv, core, s_ctrl, &ctrl);
+	if (btv->sd_msp34xx) {
+		u32 in;
+
+		/* Note: the inputs tuner/radio/extern/intern are translated
+		   to msp routings. This assumes common behavior for all msp3400
+		   based TV cards. When this assumption fails, then the
+		   specific MSP routing must be added to the card table.
+		   For now this is sufficient. */
+		switch (input) {
+		case TVAUDIO_INPUT_RADIO:
+			/* Some boards need the msp do to the radio demod */
+			if (btv->radio_uses_msp_demodulator) {
+				in = MSP_INPUT_DEFAULT;
+				break;
+			}
+			in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
+				    MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
+			break;
+		case TVAUDIO_INPUT_EXTERN:
+			in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
+				    MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
+			break;
+		case TVAUDIO_INPUT_INTERN:
+			/* Yes, this is the same input as for RADIO. I doubt
+			   if this is ever used. The only board with an INTERN
+			   input is the BTTV_BOARD_AVERMEDIA98. I wonder how
+			   that was tested. My guess is that the whole INTERN
+			   input does not work. */
+			in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
+				    MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
+			break;
+		case TVAUDIO_INPUT_TUNER:
+		default:
+			/* This is the only card that uses TUNER2, and afaik,
+			   is the only difference between the VOODOOTV_FM
+			   and VOODOOTV_200 */
+			if (btv->c.type == BTTV_BOARD_VOODOOTV_200)
+				in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
+					MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER);
+			else
+				in = MSP_INPUT_DEFAULT;
+			break;
+		}
+		v4l2_subdev_call(btv->sd_msp34xx, audio, s_routing,
+			       in, MSP_OUTPUT_DEFAULT, 0);
+	}
+	if (btv->sd_tvaudio) {
+		v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing,
+				input, 0, 0);
+	}
+	return 0;
+}
+
+static inline int
+audio_mute(struct bttv *btv, int mute)
+{
+	return audio_mux(btv, btv->audio, mute);
+}
+
+static inline int
+audio_input(struct bttv *btv, int input)
+{
+	return audio_mux(btv, input, btv->mute);
+}
+
+static void
+bttv_crop_calc_limits(struct bttv_crop *c)
+{
+	/* Scale factor min. 1:1, max. 16:1. Min. image size
+	   48 x 32. Scaled width must be a multiple of 4. */
+
+	if (1) {
+		/* For bug compatibility with VIDIOCGCAP and image
+		   size checks in earlier driver versions. */
+		c->min_scaled_width = 48;
+		c->min_scaled_height = 32;
+	} else {
+		c->min_scaled_width =
+			(max(48, c->rect.width >> 4) + 3) & ~3;
+		c->min_scaled_height =
+			max(32, c->rect.height >> 4);
+	}
+
+	c->max_scaled_width  = c->rect.width & ~3;
+	c->max_scaled_height = c->rect.height;
+}
+
+static void
+bttv_crop_reset(struct bttv_crop *c, unsigned int norm)
+{
+	c->rect = bttv_tvnorms[norm].cropcap.defrect;
+	bttv_crop_calc_limits(c);
+}
+
+/* Call with btv->lock down. */
+static int
+set_tvnorm(struct bttv *btv, unsigned int norm)
+{
+	const struct bttv_tvnorm *tvnorm;
+	v4l2_std_id id;
+
+	BUG_ON(norm >= BTTV_TVNORMS);
+	BUG_ON(btv->tvnorm >= BTTV_TVNORMS);
+
+	tvnorm = &bttv_tvnorms[norm];
+
+	if (memcmp(&bttv_tvnorms[btv->tvnorm].cropcap, &tvnorm->cropcap,
+		    sizeof (tvnorm->cropcap))) {
+		bttv_crop_reset(&btv->crop[0], norm);
+		btv->crop[1] = btv->crop[0]; /* current = default */
+
+		if (0 == (btv->resources & VIDEO_RESOURCES)) {
+			btv->crop_start = tvnorm->cropcap.bounds.top
+				+ tvnorm->cropcap.bounds.height;
+		}
+	}
+
+	btv->tvnorm = norm;
+
+	btwrite(tvnorm->adelay, BT848_ADELAY);
+	btwrite(tvnorm->bdelay, BT848_BDELAY);
+	btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
+	      BT848_IFORM);
+	btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
+	btwrite(1, BT848_VBI_PACK_DEL);
+	bt848A_set_timing(btv);
+
+	switch (btv->c.type) {
+	case BTTV_BOARD_VOODOOTV_FM:
+	case BTTV_BOARD_VOODOOTV_200:
+		bttv_tda9880_setnorm(btv, gpio_read());
+		break;
+	}
+	id = tvnorm->v4l2_id;
+	bttv_call_all(btv, core, s_std, id);
+
+	return 0;
+}
+
+/* Call with btv->lock down. */
+static void
+set_input(struct bttv *btv, unsigned int input, unsigned int norm)
+{
+	unsigned long flags;
+
+	btv->input = input;
+	if (irq_iswitch) {
+		spin_lock_irqsave(&btv->s_lock,flags);
+		if (btv->curr.frame_irq) {
+			/* active capture -> delayed input switch */
+			btv->new_input = input;
+		} else {
+			video_mux(btv,input);
+		}
+		spin_unlock_irqrestore(&btv->s_lock,flags);
+	} else {
+		video_mux(btv,input);
+	}
+	audio_input(btv, (btv->tuner_type != TUNER_ABSENT && input == 0) ?
+			 TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN);
+	set_tvnorm(btv, norm);
+}
+
+static void init_irqreg(struct bttv *btv)
+{
+	/* clear status */
+	btwrite(0xfffffUL, BT848_INT_STAT);
+
+	if (bttv_tvcards[btv->c.type].no_video) {
+		/* i2c only */
+		btwrite(BT848_INT_I2CDONE,
+			BT848_INT_MASK);
+	} else {
+		/* full video */
+		btwrite((btv->triton1)  |
+			(btv->gpioirq ? BT848_INT_GPINT : 0) |
+			BT848_INT_SCERR |
+			(fdsr ? BT848_INT_FDSR : 0) |
+			BT848_INT_RISCI | BT848_INT_OCERR |
+			BT848_INT_FMTCHG|BT848_INT_HLOCK|
+			BT848_INT_I2CDONE,
+			BT848_INT_MASK);
+	}
+}
+
+static void init_bt848(struct bttv *btv)
+{
+	int val;
+
+	if (bttv_tvcards[btv->c.type].no_video) {
+		/* very basic init only */
+		init_irqreg(btv);
+		return;
+	}
+
+	btwrite(0x00, BT848_CAP_CTL);
+	btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
+	btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
+
+	/* set planar and packed mode trigger points and         */
+	/* set rising edge of inverted GPINTR pin as irq trigger */
+	btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
+		BT848_GPIO_DMA_CTL_PLTP1_16|
+		BT848_GPIO_DMA_CTL_PLTP23_16|
+		BT848_GPIO_DMA_CTL_GPINTC|
+		BT848_GPIO_DMA_CTL_GPINTI,
+		BT848_GPIO_DMA_CTL);
+
+	val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
+	btwrite(val, BT848_E_SCLOOP);
+	btwrite(val, BT848_O_SCLOOP);
+
+	btwrite(0x20, BT848_E_VSCALE_HI);
+	btwrite(0x20, BT848_O_VSCALE_HI);
+	btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
+		BT848_ADC);
+
+	btwrite(whitecrush_upper, BT848_WC_UP);
+	btwrite(whitecrush_lower, BT848_WC_DOWN);
+
+	if (btv->opt_lumafilter) {
+		btwrite(0, BT848_E_CONTROL);
+		btwrite(0, BT848_O_CONTROL);
+	} else {
+		btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
+		btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
+	}
+
+	bt848_bright(btv,   btv->bright);
+	bt848_hue(btv,      btv->hue);
+	bt848_contrast(btv, btv->contrast);
+	bt848_sat(btv,      btv->saturation);
+
+	/* interrupt */
+	init_irqreg(btv);
+}
+
+static void bttv_reinit_bt848(struct bttv *btv)
+{
+	unsigned long flags;
+
+	if (bttv_verbose)
+		pr_info("%d: reset, reinitialize\n", btv->c.nr);
+	spin_lock_irqsave(&btv->s_lock,flags);
+	btv->errors=0;
+	bttv_set_dma(btv,0);
+	spin_unlock_irqrestore(&btv->s_lock,flags);
+
+	init_bt848(btv);
+	btv->pll.pll_current = -1;
+	set_input(btv, btv->input, btv->tvnorm);
+}
+
+static int bttv_g_ctrl(struct file *file, void *priv,
+					struct v4l2_control *c)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		c->value = btv->bright;
+		break;
+	case V4L2_CID_HUE:
+		c->value = btv->hue;
+		break;
+	case V4L2_CID_CONTRAST:
+		c->value = btv->contrast;
+		break;
+	case V4L2_CID_SATURATION:
+		c->value = btv->saturation;
+		break;
+
+	case V4L2_CID_AUDIO_MUTE:
+	case V4L2_CID_AUDIO_VOLUME:
+	case V4L2_CID_AUDIO_BALANCE:
+	case V4L2_CID_AUDIO_BASS:
+	case V4L2_CID_AUDIO_TREBLE:
+		bttv_call_all(btv, core, g_ctrl, c);
+		break;
+
+	case V4L2_CID_PRIVATE_CHROMA_AGC:
+		c->value = btv->opt_chroma_agc;
+		break;
+	case V4L2_CID_PRIVATE_COMBFILTER:
+		c->value = btv->opt_combfilter;
+		break;
+	case V4L2_CID_PRIVATE_LUMAFILTER:
+		c->value = btv->opt_lumafilter;
+		break;
+	case V4L2_CID_PRIVATE_AUTOMUTE:
+		c->value = btv->opt_automute;
+		break;
+	case V4L2_CID_PRIVATE_AGC_CRUSH:
+		c->value = btv->opt_adc_crush;
+		break;
+	case V4L2_CID_PRIVATE_VCR_HACK:
+		c->value = btv->opt_vcr_hack;
+		break;
+	case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
+		c->value = btv->opt_whitecrush_upper;
+		break;
+	case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
+		c->value = btv->opt_whitecrush_lower;
+		break;
+	case V4L2_CID_PRIVATE_UV_RATIO:
+		c->value = btv->opt_uv_ratio;
+		break;
+	case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
+		c->value = btv->opt_full_luma_range;
+		break;
+	case V4L2_CID_PRIVATE_CORING:
+		c->value = btv->opt_coring;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int bttv_s_ctrl(struct file *file, void *f,
+					struct v4l2_control *c)
+{
+	int err;
+	int val;
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+
+	err = v4l2_prio_check(&btv->prio, fh->prio);
+	if (0 != err)
+		return err;
+
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		bt848_bright(btv, c->value);
+		break;
+	case V4L2_CID_HUE:
+		bt848_hue(btv, c->value);
+		break;
+	case V4L2_CID_CONTRAST:
+		bt848_contrast(btv, c->value);
+		break;
+	case V4L2_CID_SATURATION:
+		bt848_sat(btv, c->value);
+		break;
+	case V4L2_CID_AUDIO_MUTE:
+		audio_mute(btv, c->value);
+		/* fall through */
+	case V4L2_CID_AUDIO_VOLUME:
+		if (btv->volume_gpio)
+			btv->volume_gpio(btv, c->value);
+
+		bttv_call_all(btv, core, s_ctrl, c);
+		break;
+	case V4L2_CID_AUDIO_BALANCE:
+	case V4L2_CID_AUDIO_BASS:
+	case V4L2_CID_AUDIO_TREBLE:
+		bttv_call_all(btv, core, s_ctrl, c);
+		break;
+
+	case V4L2_CID_PRIVATE_CHROMA_AGC:
+		btv->opt_chroma_agc = c->value;
+		val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
+		btwrite(val, BT848_E_SCLOOP);
+		btwrite(val, BT848_O_SCLOOP);
+		break;
+	case V4L2_CID_PRIVATE_COMBFILTER:
+		btv->opt_combfilter = c->value;
+		break;
+	case V4L2_CID_PRIVATE_LUMAFILTER:
+		btv->opt_lumafilter = c->value;
+		if (btv->opt_lumafilter) {
+			btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
+			btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
+		} else {
+			btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);
+			btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);
+		}
+		break;
+	case V4L2_CID_PRIVATE_AUTOMUTE:
+		btv->opt_automute = c->value;
+		break;
+	case V4L2_CID_PRIVATE_AGC_CRUSH:
+		btv->opt_adc_crush = c->value;
+		btwrite(BT848_ADC_RESERVED |
+				(btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
+				BT848_ADC);
+		break;
+	case V4L2_CID_PRIVATE_VCR_HACK:
+		btv->opt_vcr_hack = c->value;
+		break;
+	case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
+		btv->opt_whitecrush_upper = c->value;
+		btwrite(c->value, BT848_WC_UP);
+		break;
+	case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
+		btv->opt_whitecrush_lower = c->value;
+		btwrite(c->value, BT848_WC_DOWN);
+		break;
+	case V4L2_CID_PRIVATE_UV_RATIO:
+		btv->opt_uv_ratio = c->value;
+		bt848_sat(btv, btv->saturation);
+		break;
+	case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
+		btv->opt_full_luma_range = c->value;
+		btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
+		break;
+	case V4L2_CID_PRIVATE_CORING:
+		btv->opt_coring = c->value;
+		btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+void bttv_gpio_tracking(struct bttv *btv, char *comment)
+{
+	unsigned int outbits, data;
+	outbits = btread(BT848_GPIO_OUT_EN);
+	data    = btread(BT848_GPIO_DATA);
+	pr_debug("%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
+		 btv->c.nr, outbits, data & outbits, data & ~outbits, comment);
+}
+
+static void bttv_field_count(struct bttv *btv)
+{
+	int need_count = 0;
+
+	if (btv->users)
+		need_count++;
+
+	if (need_count) {
+		/* start field counter */
+		btor(BT848_INT_VSYNC,BT848_INT_MASK);
+	} else {
+		/* stop field counter */
+		btand(~BT848_INT_VSYNC,BT848_INT_MASK);
+		btv->field_count = 0;
+	}
+}
+
+static const struct bttv_format*
+format_by_fourcc(int fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < FORMATS; i++) {
+		if (-1 == formats[i].fourcc)
+			continue;
+		if (formats[i].fourcc == fourcc)
+			return formats+i;
+	}
+	return NULL;
+}
+
+/* ----------------------------------------------------------------------- */
+/* misc helpers                                                            */
+
+static int
+bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
+		    struct bttv_buffer *new)
+{
+	struct bttv_buffer *old;
+	unsigned long flags;
+	int retval = 0;
+
+	dprintk("switch_overlay: enter [new=%p]\n", new);
+	if (new)
+		new->vb.state = VIDEOBUF_DONE;
+	spin_lock_irqsave(&btv->s_lock,flags);
+	old = btv->screen;
+	btv->screen = new;
+	btv->loop_irq |= 1;
+	bttv_set_dma(btv, 0x03);
+	spin_unlock_irqrestore(&btv->s_lock,flags);
+	if (NULL != old) {
+		dprintk("switch_overlay: old=%p state is %d\n",
+			old, old->vb.state);
+		bttv_dma_free(&fh->cap,btv, old);
+		kfree(old);
+	}
+	if (NULL == new)
+		free_btres_lock(btv,fh,RESOURCE_OVERLAY);
+	dprintk("switch_overlay: done\n");
+	return retval;
+}
+
+/* ----------------------------------------------------------------------- */
+/* video4linux (1) interface                                               */
+
+static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
+			       struct bttv_buffer *buf,
+			       const struct bttv_format *fmt,
+			       unsigned int width, unsigned int height,
+			       enum v4l2_field field)
+{
+	struct bttv_fh *fh = q->priv_data;
+	int redo_dma_risc = 0;
+	struct bttv_crop c;
+	int norm;
+	int rc;
+
+	/* check settings */
+	if (NULL == fmt)
+		return -EINVAL;
+	if (fmt->btformat == BT848_COLOR_FMT_RAW) {
+		width  = RAW_BPL;
+		height = RAW_LINES*2;
+		if (width*height > buf->vb.bsize)
+			return -EINVAL;
+		buf->vb.size = buf->vb.bsize;
+
+		/* Make sure tvnorm and vbi_end remain consistent
+		   until we're done. */
+
+		norm = btv->tvnorm;
+
+		/* In this mode capturing always starts at defrect.top
+		   (default VDELAY), ignoring cropping parameters. */
+		if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) {
+			return -EINVAL;
+		}
+
+		c.rect = bttv_tvnorms[norm].cropcap.defrect;
+	} else {
+		norm = btv->tvnorm;
+		c = btv->crop[!!fh->do_crop];
+
+		if (width < c.min_scaled_width ||
+		    width > c.max_scaled_width ||
+		    height < c.min_scaled_height)
+			return -EINVAL;
+
+		switch (field) {
+		case V4L2_FIELD_TOP:
+		case V4L2_FIELD_BOTTOM:
+		case V4L2_FIELD_ALTERNATE:
+			/* btv->crop counts frame lines. Max. scale
+			   factor is 16:1 for frames, 8:1 for fields. */
+			if (height * 2 > c.max_scaled_height)
+				return -EINVAL;
+			break;
+
+		default:
+			if (height > c.max_scaled_height)
+				return -EINVAL;
+			break;
+		}
+
+		buf->vb.size = (width * height * fmt->depth) >> 3;
+		if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+			return -EINVAL;
+	}
+
+	/* alloc + fill struct bttv_buffer (if changed) */
+	if (buf->vb.width != width || buf->vb.height != height ||
+	    buf->vb.field != field ||
+	    buf->tvnorm != norm || buf->fmt != fmt ||
+	    buf->crop.top != c.rect.top ||
+	    buf->crop.left != c.rect.left ||
+	    buf->crop.width != c.rect.width ||
+	    buf->crop.height != c.rect.height) {
+		buf->vb.width  = width;
+		buf->vb.height = height;
+		buf->vb.field  = field;
+		buf->tvnorm    = norm;
+		buf->fmt       = fmt;
+		buf->crop      = c.rect;
+		redo_dma_risc = 1;
+	}
+
+	/* alloc risc memory */
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		redo_dma_risc = 1;
+		if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))
+			goto fail;
+	}
+
+	if (redo_dma_risc)
+		if (0 != (rc = bttv_buffer_risc(btv,buf)))
+			goto fail;
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+ fail:
+	bttv_dma_free(q,btv,buf);
+	return rc;
+}
+
+static int
+buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+	struct bttv_fh *fh = q->priv_data;
+
+	*size = fh->fmt->depth*fh->width*fh->height >> 3;
+	if (0 == *count)
+		*count = gbuffers;
+	if (*size * *count > gbuffers * gbufsize)
+		*count = (gbuffers * gbufsize) / *size;
+	return 0;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+	       enum v4l2_field field)
+{
+	struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
+	struct bttv_fh *fh = q->priv_data;
+
+	return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt,
+				   fh->width, fh->height, field);
+}
+
+static void
+buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
+	struct bttv_fh *fh = q->priv_data;
+	struct bttv    *btv = fh->btv;
+
+	buf->vb.state = VIDEOBUF_QUEUED;
+	list_add_tail(&buf->vb.queue,&btv->capture);
+	if (!btv->curr.frame_irq) {
+		btv->loop_irq |= 1;
+		bttv_set_dma(btv, 0x03);
+	}
+}
+
+static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
+	struct bttv_fh *fh = q->priv_data;
+
+	bttv_dma_free(q,fh->btv,buf);
+}
+
+static struct videobuf_queue_ops bttv_video_qops = {
+	.buf_setup    = buffer_setup,
+	.buf_prepare  = buffer_prepare,
+	.buf_queue    = buffer_queue,
+	.buf_release  = buffer_release,
+};
+
+static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct bttv_fh *fh  = priv;
+	struct bttv *btv = fh->btv;
+	unsigned int i;
+	int err;
+
+	err = v4l2_prio_check(&btv->prio, fh->prio);
+	if (err)
+		goto err;
+
+	for (i = 0; i < BTTV_TVNORMS; i++)
+		if (*id & bttv_tvnorms[i].v4l2_id)
+			break;
+	if (i == BTTV_TVNORMS) {
+		err = -EINVAL;
+		goto err;
+	}
+
+	set_tvnorm(btv, i);
+
+err:
+
+	return err;
+}
+
+static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+
+	if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
+		*id = V4L2_STD_625_50;
+	else
+		*id = V4L2_STD_525_60;
+	return 0;
+}
+
+static int bttv_enum_input(struct file *file, void *priv,
+					struct v4l2_input *i)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	int rc = 0;
+
+	if (i->index >= bttv_tvcards[btv->c.type].video_inputs) {
+		rc = -EINVAL;
+		goto err;
+	}
+
+	i->type     = V4L2_INPUT_TYPE_CAMERA;
+	i->audioset = 1;
+
+	if (btv->tuner_type != TUNER_ABSENT && i->index == 0) {
+		sprintf(i->name, "Television");
+		i->type  = V4L2_INPUT_TYPE_TUNER;
+		i->tuner = 0;
+	} else if (i->index == btv->svhs) {
+		sprintf(i->name, "S-Video");
+	} else {
+		sprintf(i->name, "Composite%d", i->index);
+	}
+
+	if (i->index == btv->input) {
+		__u32 dstatus = btread(BT848_DSTATUS);
+		if (0 == (dstatus & BT848_DSTATUS_PRES))
+			i->status |= V4L2_IN_ST_NO_SIGNAL;
+		if (0 == (dstatus & BT848_DSTATUS_HLOC))
+			i->status |= V4L2_IN_ST_NO_H_LOCK;
+	}
+
+	i->std = BTTV_NORMS;
+
+err:
+
+	return rc;
+}
+
+static int bttv_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+
+	*i = btv->input;
+
+	return 0;
+}
+
+static int bttv_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct bttv_fh *fh  = priv;
+	struct bttv *btv = fh->btv;
+
+	int err;
+
+	err = v4l2_prio_check(&btv->prio, fh->prio);
+	if (unlikely(err))
+		goto err;
+
+	if (i > bttv_tvcards[btv->c.type].video_inputs) {
+		err = -EINVAL;
+		goto err;
+	}
+
+	set_input(btv, i, btv->tvnorm);
+
+err:
+	return 0;
+}
+
+static int bttv_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *t)
+{
+	struct bttv_fh *fh  = priv;
+	struct bttv *btv = fh->btv;
+	int err;
+
+	if (unlikely(0 != t->index))
+		return -EINVAL;
+
+	if (unlikely(btv->tuner_type == TUNER_ABSENT)) {
+		err = -EINVAL;
+		goto err;
+	}
+
+	err = v4l2_prio_check(&btv->prio, fh->prio);
+	if (unlikely(err))
+		goto err;
+
+	bttv_call_all(btv, tuner, s_tuner, t);
+
+	if (btv->audio_mode_gpio)
+		btv->audio_mode_gpio(btv, t, 1);
+
+err:
+
+	return 0;
+}
+
+static int bttv_g_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct bttv_fh *fh  = priv;
+	struct bttv *btv = fh->btv;
+
+	f->type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+	f->frequency = btv->freq;
+
+	return 0;
+}
+
+static int bttv_s_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct bttv_fh *fh  = priv;
+	struct bttv *btv = fh->btv;
+	int err;
+
+	if (unlikely(f->tuner != 0))
+		return -EINVAL;
+
+	err = v4l2_prio_check(&btv->prio, fh->prio);
+	if (unlikely(err))
+		goto err;
+
+	if (unlikely(f->type != (btv->radio_user
+		? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV))) {
+		err = -EINVAL;
+		goto err;
+	}
+	btv->freq = f->frequency;
+	bttv_call_all(btv, tuner, s_frequency, f);
+	if (btv->has_matchbox && btv->radio_user)
+		tea5757_set_freq(btv, btv->freq);
+err:
+
+	return 0;
+}
+
+static int bttv_log_status(struct file *file, void *f)
+{
+	struct bttv_fh *fh  = f;
+	struct bttv *btv = fh->btv;
+
+	bttv_call_all(btv, core, log_status);
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int bttv_g_register(struct file *file, void *f,
+					struct v4l2_dbg_register *reg)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (!v4l2_chip_match_host(&reg->match))
+		return -EINVAL;
+
+	/* bt848 has a 12-bit register space */
+	reg->reg &= 0xfff;
+	reg->val = btread(reg->reg);
+	reg->size = 1;
+
+	return 0;
+}
+
+static int bttv_s_register(struct file *file, void *f,
+					struct v4l2_dbg_register *reg)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (!v4l2_chip_match_host(&reg->match))
+		return -EINVAL;
+
+	/* bt848 has a 12-bit register space */
+	reg->reg &= 0xfff;
+	btwrite(reg->val, reg->reg);
+
+	return 0;
+}
+#endif
+
+/* Given cropping boundaries b and the scaled width and height of a
+   single field or frame, which must not exceed hardware limits, this
+   function adjusts the cropping parameters c. */
+static void
+bttv_crop_adjust	(struct bttv_crop *             c,
+			 const struct v4l2_rect *	b,
+			 __s32                          width,
+			 __s32                          height,
+			 enum v4l2_field                field)
+{
+	__s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field);
+	__s32 max_left;
+	__s32 max_top;
+
+	if (width < c->min_scaled_width) {
+		/* Max. hor. scale factor 16:1. */
+		c->rect.width = width * 16;
+	} else if (width > c->max_scaled_width) {
+		/* Min. hor. scale factor 1:1. */
+		c->rect.width = width;
+
+		max_left = b->left + b->width - width;
+		max_left = min(max_left, (__s32) MAX_HDELAY);
+		if (c->rect.left > max_left)
+			c->rect.left = max_left;
+	}
+
+	if (height < c->min_scaled_height) {
+		/* Max. vert. scale factor 16:1, single fields 8:1. */
+		c->rect.height = height * 16;
+	} else if (frame_height > c->max_scaled_height) {
+		/* Min. vert. scale factor 1:1.
+		   Top and height count field lines times two. */
+		c->rect.height = (frame_height + 1) & ~1;
+
+		max_top = b->top + b->height - c->rect.height;
+		if (c->rect.top > max_top)
+			c->rect.top = max_top;
+	}
+
+	bttv_crop_calc_limits(c);
+}
+
+/* Returns an error if scaling to a frame or single field with the given
+   width and height is not possible with the current cropping parameters
+   and width aligned according to width_mask. If adjust_size is TRUE the
+   function may adjust the width and/or height instead, rounding width
+   to (width + width_bias) & width_mask. If adjust_crop is TRUE it may
+   also adjust the current cropping parameters to get closer to the
+   desired image size. */
+static int
+limit_scaled_size_lock       (struct bttv_fh *               fh,
+			 __s32 *                        width,
+			 __s32 *                        height,
+			 enum v4l2_field                field,
+			 unsigned int			width_mask,
+			 unsigned int			width_bias,
+			 int                            adjust_size,
+			 int                            adjust_crop)
+{
+	struct bttv *btv = fh->btv;
+	const struct v4l2_rect *b;
+	struct bttv_crop *c;
+	__s32 min_width;
+	__s32 min_height;
+	__s32 max_width;
+	__s32 max_height;
+	int rc;
+
+	BUG_ON((int) width_mask >= 0 ||
+	       width_bias >= (unsigned int) -width_mask);
+
+	/* Make sure tvnorm, vbi_end and the current cropping parameters
+	   remain consistent until we're done. */
+
+	b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
+
+	/* Do crop - use current, don't - use default parameters. */
+	c = &btv->crop[!!fh->do_crop];
+
+	if (fh->do_crop
+	    && adjust_size
+	    && adjust_crop
+	    && !locked_btres(btv, VIDEO_RESOURCES)) {
+		min_width = 48;
+		min_height = 32;
+
+		/* We cannot scale up. When the scaled image is larger
+		   than crop.rect we adjust the crop.rect as required
+		   by the V4L2 spec, hence cropcap.bounds are our limit. */
+		max_width = min(b->width, (__s32) MAX_HACTIVE);
+		max_height = b->height;
+
+		/* We cannot capture the same line as video and VBI data.
+		   Note btv->vbi_end is really a minimum, see
+		   bttv_vbi_try_fmt(). */
+		if (btv->vbi_end > b->top) {
+			max_height -= btv->vbi_end - b->top;
+			rc = -EBUSY;
+			if (min_height > max_height)
+				goto fail;
+		}
+	} else {
+		rc = -EBUSY;
+		if (btv->vbi_end > c->rect.top)
+			goto fail;
+
+		min_width  = c->min_scaled_width;
+		min_height = c->min_scaled_height;
+		max_width  = c->max_scaled_width;
+		max_height = c->max_scaled_height;
+
+		adjust_crop = 0;
+	}
+
+	min_width = (min_width - width_mask - 1) & width_mask;
+	max_width = max_width & width_mask;
+
+	/* Max. scale factor is 16:1 for frames, 8:1 for fields. */
+	min_height = min_height;
+	/* Min. scale factor is 1:1. */
+	max_height >>= !V4L2_FIELD_HAS_BOTH(field);
+
+	if (adjust_size) {
+		*width = clamp(*width, min_width, max_width);
+		*height = clamp(*height, min_height, max_height);
+
+		/* Round after clamping to avoid overflow. */
+		*width = (*width + width_bias) & width_mask;
+
+		if (adjust_crop) {
+			bttv_crop_adjust(c, b, *width, *height, field);
+
+			if (btv->vbi_end > c->rect.top) {
+				/* Move the crop window out of the way. */
+				c->rect.top = btv->vbi_end;
+			}
+		}
+	} else {
+		rc = -EINVAL;
+		if (*width  < min_width ||
+		    *height < min_height ||
+		    *width  > max_width ||
+		    *height > max_height ||
+		    0 != (*width & ~width_mask))
+			goto fail;
+	}
+
+	rc = 0; /* success */
+
+ fail:
+
+	return rc;
+}
+
+/* Returns an error if the given overlay window dimensions are not
+   possible with the current cropping parameters. If adjust_size is
+   TRUE the function may adjust the window width and/or height
+   instead, however it always rounds the horizontal position and
+   width as btcx_align() does. If adjust_crop is TRUE the function
+   may also adjust the current cropping parameters to get closer
+   to the desired window size. */
+static int
+verify_window_lock		(struct bttv_fh *               fh,
+			 struct v4l2_window *           win,
+			 int                            adjust_size,
+			 int                            adjust_crop)
+{
+	enum v4l2_field field;
+	unsigned int width_mask;
+	int rc;
+
+	if (win->w.width  < 48 || win->w.height < 32)
+		return -EINVAL;
+	if (win->clipcount > 2048)
+		return -EINVAL;
+
+	field = win->field;
+
+	if (V4L2_FIELD_ANY == field) {
+		__s32 height2;
+
+		height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1;
+		field = (win->w.height > height2)
+			? V4L2_FIELD_INTERLACED
+			: V4L2_FIELD_TOP;
+	}
+	switch (field) {
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+	case V4L2_FIELD_INTERLACED:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* 4-byte alignment. */
+	if (NULL == fh->ovfmt)
+		return -EINVAL;
+	width_mask = ~0;
+	switch (fh->ovfmt->depth) {
+	case 8:
+	case 24:
+		width_mask = ~3;
+		break;
+	case 16:
+		width_mask = ~1;
+		break;
+	case 32:
+		break;
+	default:
+		BUG();
+	}
+
+	win->w.width -= win->w.left & ~width_mask;
+	win->w.left = (win->w.left - width_mask - 1) & width_mask;
+
+	rc = limit_scaled_size_lock(fh, &win->w.width, &win->w.height,
+			       field, width_mask,
+			       /* width_bias: round down */ 0,
+			       adjust_size, adjust_crop);
+	if (0 != rc)
+		return rc;
+
+	win->field = field;
+	return 0;
+}
+
+static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv,
+			struct v4l2_window *win, int fixup)
+{
+	struct v4l2_clip *clips = NULL;
+	int n,size,retval = 0;
+
+	if (NULL == fh->ovfmt)
+		return -EINVAL;
+	if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
+		return -EINVAL;
+	retval = verify_window_lock(fh, win,
+			       /* adjust_size */ fixup,
+			       /* adjust_crop */ fixup);
+	if (0 != retval)
+		return retval;
+
+	/* copy clips  --  luckily v4l1 + v4l2 are binary
+	   compatible here ...*/
+	n = win->clipcount;
+	size = sizeof(*clips)*(n+4);
+	clips = kmalloc(size,GFP_KERNEL);
+	if (NULL == clips)
+		return -ENOMEM;
+	if (n > 0) {
+		if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
+			kfree(clips);
+			return -EFAULT;
+		}
+	}
+
+	/* clip against screen */
+	if (NULL != btv->fbuf.base)
+		n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
+				      &win->w, clips, n);
+	btcx_sort_clips(clips,n);
+
+	/* 4-byte alignments */
+	switch (fh->ovfmt->depth) {
+	case 8:
+	case 24:
+		btcx_align(&win->w, clips, n, 3);
+		break;
+	case 16:
+		btcx_align(&win->w, clips, n, 1);
+		break;
+	case 32:
+		/* no alignment fixups needed */
+		break;
+	default:
+		BUG();
+	}
+
+	kfree(fh->ov.clips);
+	fh->ov.clips    = clips;
+	fh->ov.nclips   = n;
+
+	fh->ov.w        = win->w;
+	fh->ov.field    = win->field;
+	fh->ov.setup_ok = 1;
+
+	btv->init.ov.w.width   = win->w.width;
+	btv->init.ov.w.height  = win->w.height;
+	btv->init.ov.field     = win->field;
+
+	/* update overlay if needed */
+	retval = 0;
+	if (check_btres(fh, RESOURCE_OVERLAY)) {
+		struct bttv_buffer *new;
+
+		new = videobuf_sg_alloc(sizeof(*new));
+		new->crop = btv->crop[!!fh->do_crop].rect;
+		bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
+		retval = bttv_switch_overlay(btv,fh,new);
+	}
+	return retval;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
+{
+	struct videobuf_queue* q = NULL;
+
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		q = &fh->cap;
+		break;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		q = &fh->vbi;
+		break;
+	default:
+		BUG();
+	}
+	return q;
+}
+
+static int bttv_resource(struct bttv_fh *fh)
+{
+	int res = 0;
+
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		res = RESOURCE_VIDEO_STREAM;
+		break;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		res = RESOURCE_VBI;
+		break;
+	default:
+		BUG();
+	}
+	return res;
+}
+
+static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type)
+{
+	struct videobuf_queue *q = bttv_queue(fh);
+	int res = bttv_resource(fh);
+
+	if (check_btres(fh,res))
+		return -EBUSY;
+	if (videobuf_queue_is_busy(q))
+		return -EBUSY;
+	fh->type = type;
+	return 0;
+}
+
+static void
+pix_format_set_size     (struct v4l2_pix_format *       f,
+			 const struct bttv_format *     fmt,
+			 unsigned int                   width,
+			 unsigned int                   height)
+{
+	f->width = width;
+	f->height = height;
+
+	if (fmt->flags & FORMAT_FLAGS_PLANAR) {
+		f->bytesperline = width; /* Y plane */
+		f->sizeimage = (width * height * fmt->depth) >> 3;
+	} else {
+		f->bytesperline = (width * fmt->depth) >> 3;
+		f->sizeimage = height * f->bytesperline;
+	}
+}
+
+static int bttv_g_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct bttv_fh *fh  = priv;
+
+	pix_format_set_size(&f->fmt.pix, fh->fmt,
+				fh->width, fh->height);
+	f->fmt.pix.field        = fh->cap.field;
+	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+
+	return 0;
+}
+
+static int bttv_g_fmt_vid_overlay(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct bttv_fh *fh  = priv;
+
+	f->fmt.win.w     = fh->ov.w;
+	f->fmt.win.field = fh->ov.field;
+
+	return 0;
+}
+
+static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
+						struct v4l2_format *f)
+{
+	const struct bttv_format *fmt;
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	enum v4l2_field field;
+	__s32 width, height;
+	int rc;
+
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	if (NULL == fmt)
+		return -EINVAL;
+
+	field = f->fmt.pix.field;
+
+	if (V4L2_FIELD_ANY == field) {
+		__s32 height2;
+
+		height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+		field = (f->fmt.pix.height > height2)
+			? V4L2_FIELD_INTERLACED
+			: V4L2_FIELD_BOTTOM;
+	}
+
+	if (V4L2_FIELD_SEQ_BT == field)
+		field = V4L2_FIELD_SEQ_TB;
+
+	switch (field) {
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+	case V4L2_FIELD_ALTERNATE:
+	case V4L2_FIELD_INTERLACED:
+		break;
+	case V4L2_FIELD_SEQ_TB:
+		if (fmt->flags & FORMAT_FLAGS_PLANAR)
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	width = f->fmt.pix.width;
+	height = f->fmt.pix.height;
+
+	rc = limit_scaled_size_lock(fh, &width, &height, field,
+			       /* width_mask: 4 pixels */ ~3,
+			       /* width_bias: nearest */ 2,
+			       /* adjust_size */ 1,
+			       /* adjust_crop */ 0);
+	if (0 != rc)
+		return rc;
+
+	/* update data for the application */
+	f->fmt.pix.field = field;
+	pix_format_set_size(&f->fmt.pix, fmt, width, height);
+
+	return 0;
+}
+
+static int bttv_try_fmt_vid_overlay(struct file *file, void *priv,
+						struct v4l2_format *f)
+{
+	struct bttv_fh *fh = priv;
+
+	return verify_window_lock(fh, &f->fmt.win,
+			/* adjust_size */ 1,
+			/* adjust_crop */ 0);
+}
+
+static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	int retval;
+	const struct bttv_format *fmt;
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	__s32 width, height;
+	enum v4l2_field field;
+
+	retval = bttv_switch_type(fh, f->type);
+	if (0 != retval)
+		return retval;
+
+	retval = bttv_try_fmt_vid_cap(file, priv, f);
+	if (0 != retval)
+		return retval;
+
+	width = f->fmt.pix.width;
+	height = f->fmt.pix.height;
+	field = f->fmt.pix.field;
+
+	retval = limit_scaled_size_lock(fh, &width, &height, f->fmt.pix.field,
+			       /* width_mask: 4 pixels */ ~3,
+			       /* width_bias: nearest */ 2,
+			       /* adjust_size */ 1,
+			       /* adjust_crop */ 1);
+	if (0 != retval)
+		return retval;
+
+	f->fmt.pix.field = field;
+
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+
+	/* update our state informations */
+	fh->fmt              = fmt;
+	fh->cap.field        = f->fmt.pix.field;
+	fh->cap.last         = V4L2_FIELD_NONE;
+	fh->width            = f->fmt.pix.width;
+	fh->height           = f->fmt.pix.height;
+	btv->init.fmt        = fmt;
+	btv->init.width      = f->fmt.pix.width;
+	btv->init.height     = f->fmt.pix.height;
+
+	return 0;
+}
+
+static int bttv_s_fmt_vid_overlay(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+
+	if (no_overlay > 0) {
+		pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+		return -EINVAL;
+	}
+
+	return setup_window_lock(fh, btv, &f->fmt.win, 1);
+}
+
+static int bttv_querycap(struct file *file, void  *priv,
+				struct v4l2_capability *cap)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+
+	if (0 == v4l2)
+		return -EINVAL;
+
+	strlcpy(cap->driver, "bttv", sizeof(cap->driver));
+	strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card));
+	snprintf(cap->bus_info, sizeof(cap->bus_info),
+		 "PCI:%s", pci_name(btv->c.pci));
+	cap->capabilities =
+		V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_VBI_CAPTURE |
+		V4L2_CAP_READWRITE |
+		V4L2_CAP_STREAMING;
+	if (no_overlay <= 0)
+		cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+
+	/*
+	 * No need to lock here: those vars are initialized during board
+	 * probe and remains untouched during the rest of the driver lifecycle
+	 */
+	if (btv->has_saa6588)
+		cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
+	if (btv->tuner_type != TUNER_ABSENT)
+		cap->capabilities |= V4L2_CAP_TUNER;
+	return 0;
+}
+
+static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f)
+{
+	int index = -1, i;
+
+	for (i = 0; i < FORMATS; i++) {
+		if (formats[i].fourcc != -1)
+			index++;
+		if ((unsigned int)index == f->index)
+			break;
+	}
+	if (FORMATS == i)
+		return -EINVAL;
+
+	f->pixelformat = formats[i].fourcc;
+	strlcpy(f->description, formats[i].name, sizeof(f->description));
+
+	return i;
+}
+
+static int bttv_enum_fmt_vid_cap(struct file *file, void  *priv,
+				struct v4l2_fmtdesc *f)
+{
+	int rc = bttv_enum_fmt_cap_ovr(f);
+
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+static int bttv_enum_fmt_vid_overlay(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	int rc;
+
+	if (no_overlay > 0) {
+		pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+		return -EINVAL;
+	}
+
+	rc = bttv_enum_fmt_cap_ovr(f);
+
+	if (rc < 0)
+		return rc;
+
+	if (!(formats[rc].flags & FORMAT_FLAGS_PACKED))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int bttv_g_fbuf(struct file *file, void *f,
+				struct v4l2_framebuffer *fb)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+
+	*fb = btv->fbuf;
+	fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+	if (fh->ovfmt)
+		fb->fmt.pixelformat  = fh->ovfmt->fourcc;
+	return 0;
+}
+
+static int bttv_overlay(struct file *file, void *f, unsigned int on)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+	struct bttv_buffer *new;
+	int retval = 0;
+
+	if (on) {
+		/* verify args */
+		if (unlikely(!btv->fbuf.base)) {
+			return -EINVAL;
+		}
+		if (unlikely(!fh->ov.setup_ok)) {
+			dprintk("%d: overlay: !setup_ok\n", btv->c.nr);
+			retval = -EINVAL;
+		}
+		if (retval)
+			return retval;
+	}
+
+	if (!check_alloc_btres_lock(btv, fh, RESOURCE_OVERLAY))
+		return -EBUSY;
+
+	if (on) {
+		fh->ov.tvnorm = btv->tvnorm;
+		new = videobuf_sg_alloc(sizeof(*new));
+		new->crop = btv->crop[!!fh->do_crop].rect;
+		bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
+	} else {
+		new = NULL;
+	}
+
+	/* switch over */
+	retval = bttv_switch_overlay(btv, fh, new);
+	return retval;
+}
+
+static int bttv_s_fbuf(struct file *file, void *f,
+				struct v4l2_framebuffer *fb)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+	const struct bttv_format *fmt;
+	int retval;
+
+	if (!capable(CAP_SYS_ADMIN) &&
+		!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	/* check args */
+	fmt = format_by_fourcc(fb->fmt.pixelformat);
+	if (NULL == fmt)
+		return -EINVAL;
+	if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
+		return -EINVAL;
+
+	retval = -EINVAL;
+	if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
+		__s32 width = fb->fmt.width;
+		__s32 height = fb->fmt.height;
+
+		retval = limit_scaled_size_lock(fh, &width, &height,
+					   V4L2_FIELD_INTERLACED,
+					   /* width_mask */ ~3,
+					   /* width_bias */ 2,
+					   /* adjust_size */ 0,
+					   /* adjust_crop */ 0);
+		if (0 != retval)
+			return retval;
+	}
+
+	/* ok, accept it */
+	btv->fbuf.base       = fb->base;
+	btv->fbuf.fmt.width  = fb->fmt.width;
+	btv->fbuf.fmt.height = fb->fmt.height;
+	if (0 != fb->fmt.bytesperline)
+		btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
+	else
+		btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
+
+	retval = 0;
+	fh->ovfmt = fmt;
+	btv->init.ovfmt = fmt;
+	if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
+		fh->ov.w.left   = 0;
+		fh->ov.w.top    = 0;
+		fh->ov.w.width  = fb->fmt.width;
+		fh->ov.w.height = fb->fmt.height;
+		btv->init.ov.w.width  = fb->fmt.width;
+		btv->init.ov.w.height = fb->fmt.height;
+			kfree(fh->ov.clips);
+		fh->ov.clips = NULL;
+		fh->ov.nclips = 0;
+
+		if (check_btres(fh, RESOURCE_OVERLAY)) {
+			struct bttv_buffer *new;
+
+			new = videobuf_sg_alloc(sizeof(*new));
+			new->crop = btv->crop[!!fh->do_crop].rect;
+			bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
+			retval = bttv_switch_overlay(btv, fh, new);
+		}
+	}
+	return retval;
+}
+
+static int bttv_reqbufs(struct file *file, void *priv,
+				struct v4l2_requestbuffers *p)
+{
+	struct bttv_fh *fh = priv;
+	return videobuf_reqbufs(bttv_queue(fh), p);
+}
+
+static int bttv_querybuf(struct file *file, void *priv,
+				struct v4l2_buffer *b)
+{
+	struct bttv_fh *fh = priv;
+	return videobuf_querybuf(bttv_queue(fh), b);
+}
+
+static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	int res = bttv_resource(fh);
+
+	if (!check_alloc_btres_lock(btv, fh, res))
+		return -EBUSY;
+
+	return videobuf_qbuf(bttv_queue(fh), b);
+}
+
+static int bttv_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct bttv_fh *fh = priv;
+	return videobuf_dqbuf(bttv_queue(fh), b,
+			file->f_flags & O_NONBLOCK);
+}
+
+static int bttv_streamon(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	int res = bttv_resource(fh);
+
+	if (!check_alloc_btres_lock(btv, fh, res))
+		return -EBUSY;
+	return videobuf_streamon(bttv_queue(fh));
+}
+
+
+static int bttv_streamoff(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	int retval;
+	int res = bttv_resource(fh);
+
+
+	retval = videobuf_streamoff(bttv_queue(fh));
+	if (retval < 0)
+		return retval;
+	free_btres_lock(btv, fh, res);
+	return 0;
+}
+
+static int bttv_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *c)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	const struct v4l2_queryctrl *ctrl;
+
+	if ((c->id <  V4L2_CID_BASE ||
+	     c->id >= V4L2_CID_LASTP1) &&
+	    (c->id <  V4L2_CID_PRIVATE_BASE ||
+	     c->id >= V4L2_CID_PRIVATE_LASTP1))
+		return -EINVAL;
+
+	if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME))
+		*c = no_ctl;
+	else {
+		ctrl = ctrl_by_id(c->id);
+
+		*c = (NULL != ctrl) ? *ctrl : no_ctl;
+	}
+
+	return 0;
+}
+
+static int bttv_g_parm(struct file *file, void *f,
+				struct v4l2_streamparm *parm)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+
+	v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id,
+				    &parm->parm.capture.timeperframe);
+
+	return 0;
+}
+
+static int bttv_g_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+
+	if (btv->tuner_type == TUNER_ABSENT)
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+
+	t->rxsubchans = V4L2_TUNER_SUB_MONO;
+	bttv_call_all(btv, tuner, g_tuner, t);
+	strcpy(t->name, "Television");
+	t->capability = V4L2_TUNER_CAP_NORM;
+	t->type       = V4L2_TUNER_ANALOG_TV;
+	if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
+		t->signal = 0xffff;
+
+	if (btv->audio_mode_gpio)
+		btv->audio_mode_gpio(btv, t, 0);
+
+	return 0;
+}
+
+static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+
+	*p = v4l2_prio_max(&btv->prio);
+
+	return 0;
+}
+
+static int bttv_s_priority(struct file *file, void *f,
+					enum v4l2_priority prio)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+	int	rc;
+
+	rc = v4l2_prio_change(&btv->prio, &fh->prio, prio);
+
+	return rc;
+}
+
+static int bttv_cropcap(struct file *file, void *priv,
+				struct v4l2_cropcap *cap)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+
+	if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
+
+	*cap = bttv_tvnorms[btv->tvnorm].cropcap;
+
+	return 0;
+}
+
+static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
+
+	/* No fh->do_crop = 1; because btv->crop[1] may be
+	   inconsistent with fh->width or fh->height and apps
+	   do not expect a change here. */
+
+	crop->c = btv->crop[!!fh->do_crop].rect;
+
+	return 0;
+}
+
+static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+	const struct v4l2_rect *b;
+	int retval;
+	struct bttv_crop c;
+	__s32 b_left;
+	__s32 b_top;
+	__s32 b_right;
+	__s32 b_bottom;
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
+
+	/* Make sure tvnorm, vbi_end and the current cropping
+	   parameters remain consistent until we're done. Note
+	   read() may change vbi_end in check_alloc_btres_lock(). */
+	retval = v4l2_prio_check(&btv->prio, fh->prio);
+	if (0 != retval) {
+		return retval;
+	}
+
+	retval = -EBUSY;
+
+	if (locked_btres(fh->btv, VIDEO_RESOURCES)) {
+		return retval;
+	}
+
+	b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
+
+	b_left = b->left;
+	b_right = b_left + b->width;
+	b_bottom = b->top + b->height;
+
+	b_top = max(b->top, btv->vbi_end);
+	if (b_top + 32 >= b_bottom) {
+		return retval;
+	}
+
+	/* Min. scaled size 48 x 32. */
+	c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
+	c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
+
+	c.rect.width = clamp(crop->c.width,
+			     48, b_right - c.rect.left);
+
+	c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
+	/* Top and height must be a multiple of two. */
+	c.rect.top = (c.rect.top + 1) & ~1;
+
+	c.rect.height = clamp(crop->c.height,
+			      32, b_bottom - c.rect.top);
+	c.rect.height = (c.rect.height + 1) & ~1;
+
+	bttv_crop_calc_limits(&c);
+
+	btv->crop[1] = c;
+
+	fh->do_crop = 1;
+
+	if (fh->width < c.min_scaled_width) {
+		fh->width = c.min_scaled_width;
+		btv->init.width = c.min_scaled_width;
+	} else if (fh->width > c.max_scaled_width) {
+		fh->width = c.max_scaled_width;
+		btv->init.width = c.max_scaled_width;
+	}
+
+	if (fh->height < c.min_scaled_height) {
+		fh->height = c.min_scaled_height;
+		btv->init.height = c.min_scaled_height;
+	} else if (fh->height > c.max_scaled_height) {
+		fh->height = c.max_scaled_height;
+		btv->init.height = c.max_scaled_height;
+	}
+
+	return 0;
+}
+
+static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	if (unlikely(a->index))
+		return -EINVAL;
+
+	strcpy(a->name, "audio");
+	return 0;
+}
+
+static int bttv_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	if (unlikely(a->index))
+		return -EINVAL;
+
+	return 0;
+}
+
+static ssize_t bttv_read(struct file *file, char __user *data,
+			 size_t count, loff_t *ppos)
+{
+	struct bttv_fh *fh = file->private_data;
+	int retval = 0;
+
+	if (fh->btv->errors)
+		bttv_reinit_bt848(fh->btv);
+	dprintk("%d: read count=%d type=%s\n",
+		fh->btv->c.nr, (int)count, v4l2_type_names[fh->type]);
+
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		if (!check_alloc_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ)) {
+			/* VIDEO_READ in use by another fh,
+			   or VIDEO_STREAM by any fh. */
+			return -EBUSY;
+		}
+		retval = videobuf_read_one(&fh->cap, data, count, ppos,
+					   file->f_flags & O_NONBLOCK);
+		free_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ);
+		break;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI))
+			return -EBUSY;
+		retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
+					      file->f_flags & O_NONBLOCK);
+		break;
+	default:
+		BUG();
+	}
+	return retval;
+}
+
+static unsigned int bttv_poll(struct file *file, poll_table *wait)
+{
+	struct bttv_fh *fh = file->private_data;
+	struct bttv_buffer *buf;
+	enum v4l2_field field;
+	unsigned int rc = POLLERR;
+
+	if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
+		if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI))
+			return POLLERR;
+		return videobuf_poll_stream(file, &fh->vbi, wait);
+	}
+
+	if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
+		/* streaming capture */
+		if (list_empty(&fh->cap.stream))
+			goto err;
+		buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
+	} else {
+		/* read() capture */
+		if (NULL == fh->cap.read_buf) {
+			/* need to capture a new frame */
+			if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM))
+				goto err;
+			fh->cap.read_buf = videobuf_sg_alloc(fh->cap.msize);
+			if (NULL == fh->cap.read_buf)
+				goto err;
+			fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
+			field = videobuf_next_field(&fh->cap);
+			if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
+				kfree (fh->cap.read_buf);
+				fh->cap.read_buf = NULL;
+				goto err;
+			}
+			fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
+			fh->cap.read_off = 0;
+		}
+		buf = (struct bttv_buffer*)fh->cap.read_buf;
+	}
+
+	poll_wait(file, &buf->vb.done, wait);
+	if (buf->vb.state == VIDEOBUF_DONE ||
+	    buf->vb.state == VIDEOBUF_ERROR)
+		rc =  POLLIN|POLLRDNORM;
+	else
+		rc = 0;
+err:
+	return rc;
+}
+
+static int bttv_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct bttv *btv = video_drvdata(file);
+	struct bttv_fh *fh;
+	enum v4l2_buf_type type = 0;
+
+	dprintk("open dev=%s\n", video_device_node_name(vdev));
+
+	if (vdev->vfl_type == VFL_TYPE_GRABBER) {
+		type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	} else if (vdev->vfl_type == VFL_TYPE_VBI) {
+		type = V4L2_BUF_TYPE_VBI_CAPTURE;
+	} else {
+		WARN_ON(1);
+		return -ENODEV;
+	}
+
+	dprintk("%d: open called (type=%s)\n",
+		btv->c.nr, v4l2_type_names[type]);
+
+	/* allocate per filehandle data */
+	fh = kmalloc(sizeof(*fh), GFP_KERNEL);
+	if (unlikely(!fh))
+		return -ENOMEM;
+	file->private_data = fh;
+
+	*fh = btv->init;
+
+	fh->type = type;
+	fh->ov.setup_ok = 0;
+
+	v4l2_prio_open(&btv->prio, &fh->prio);
+
+	videobuf_queue_sg_init(&fh->cap, &bttv_video_qops,
+			    &btv->c.pci->dev, &btv->s_lock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			    V4L2_FIELD_INTERLACED,
+			    sizeof(struct bttv_buffer),
+			    fh, &btv->lock);
+	videobuf_queue_sg_init(&fh->vbi, &bttv_vbi_qops,
+			    &btv->c.pci->dev, &btv->s_lock,
+			    V4L2_BUF_TYPE_VBI_CAPTURE,
+			    V4L2_FIELD_SEQ_TB,
+			    sizeof(struct bttv_buffer),
+			    fh, &btv->lock);
+	set_tvnorm(btv,btv->tvnorm);
+	set_input(btv, btv->input, btv->tvnorm);
+
+	btv->users++;
+
+	/* The V4L2 spec requires one global set of cropping parameters
+	   which only change on request. These are stored in btv->crop[1].
+	   However for compatibility with V4L apps and cropping unaware
+	   V4L2 apps we now reset the cropping parameters as seen through
+	   this fh, which is to say VIDIOC_G_CROP and scaling limit checks
+	   will use btv->crop[0], the default cropping parameters for the
+	   current video standard, and VIDIOC_S_FMT will not implicitely
+	   change the cropping parameters until VIDIOC_S_CROP has been
+	   called. */
+	fh->do_crop = !reset_crop; /* module parameter */
+
+	/* Likewise there should be one global set of VBI capture
+	   parameters, but for compatibility with V4L apps and earlier
+	   driver versions each fh has its own parameters. */
+	bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
+
+	bttv_field_count(btv);
+	return 0;
+}
+
+static int bttv_release(struct file *file)
+{
+	struct bttv_fh *fh = file->private_data;
+	struct bttv *btv = fh->btv;
+
+	/* turn off overlay */
+	if (check_btres(fh, RESOURCE_OVERLAY))
+		bttv_switch_overlay(btv,fh,NULL);
+
+	/* stop video capture */
+	if (check_btres(fh, RESOURCE_VIDEO_STREAM)) {
+		videobuf_streamoff(&fh->cap);
+		free_btres_lock(btv,fh,RESOURCE_VIDEO_STREAM);
+	}
+	if (fh->cap.read_buf) {
+		buffer_release(&fh->cap,fh->cap.read_buf);
+		kfree(fh->cap.read_buf);
+	}
+	if (check_btres(fh, RESOURCE_VIDEO_READ)) {
+		free_btres_lock(btv, fh, RESOURCE_VIDEO_READ);
+	}
+
+	/* stop vbi capture */
+	if (check_btres(fh, RESOURCE_VBI)) {
+		videobuf_stop(&fh->vbi);
+		free_btres_lock(btv,fh,RESOURCE_VBI);
+	}
+
+	/* free stuff */
+
+	videobuf_mmap_free(&fh->cap);
+	videobuf_mmap_free(&fh->vbi);
+	v4l2_prio_close(&btv->prio, fh->prio);
+	file->private_data = NULL;
+	kfree(fh);
+
+	btv->users--;
+	bttv_field_count(btv);
+
+	if (!btv->users)
+		audio_mute(btv, 1);
+
+	return 0;
+}
+
+static int
+bttv_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct bttv_fh *fh = file->private_data;
+
+	dprintk("%d: mmap type=%s 0x%lx+%ld\n",
+		fh->btv->c.nr, v4l2_type_names[fh->type],
+		vma->vm_start, vma->vm_end - vma->vm_start);
+	return videobuf_mmap_mapper(bttv_queue(fh),vma);
+}
+
+static const struct v4l2_file_operations bttv_fops =
+{
+	.owner		  = THIS_MODULE,
+	.open		  = bttv_open,
+	.release	  = bttv_release,
+	.unlocked_ioctl	  = video_ioctl2,
+	.read		  = bttv_read,
+	.mmap		  = bttv_mmap,
+	.poll		  = bttv_poll,
+};
+
+static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
+	.vidioc_querycap                = bttv_querycap,
+	.vidioc_enum_fmt_vid_cap        = bttv_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap           = bttv_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap         = bttv_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap           = bttv_s_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_overlay    = bttv_enum_fmt_vid_overlay,
+	.vidioc_g_fmt_vid_overlay       = bttv_g_fmt_vid_overlay,
+	.vidioc_try_fmt_vid_overlay     = bttv_try_fmt_vid_overlay,
+	.vidioc_s_fmt_vid_overlay       = bttv_s_fmt_vid_overlay,
+	.vidioc_g_fmt_vbi_cap           = bttv_g_fmt_vbi_cap,
+	.vidioc_try_fmt_vbi_cap         = bttv_try_fmt_vbi_cap,
+	.vidioc_s_fmt_vbi_cap           = bttv_s_fmt_vbi_cap,
+	.vidioc_g_audio                 = bttv_g_audio,
+	.vidioc_s_audio                 = bttv_s_audio,
+	.vidioc_cropcap                 = bttv_cropcap,
+	.vidioc_reqbufs                 = bttv_reqbufs,
+	.vidioc_querybuf                = bttv_querybuf,
+	.vidioc_qbuf                    = bttv_qbuf,
+	.vidioc_dqbuf                   = bttv_dqbuf,
+	.vidioc_s_std                   = bttv_s_std,
+	.vidioc_enum_input              = bttv_enum_input,
+	.vidioc_g_input                 = bttv_g_input,
+	.vidioc_s_input                 = bttv_s_input,
+	.vidioc_queryctrl               = bttv_queryctrl,
+	.vidioc_g_ctrl                  = bttv_g_ctrl,
+	.vidioc_s_ctrl                  = bttv_s_ctrl,
+	.vidioc_streamon                = bttv_streamon,
+	.vidioc_streamoff               = bttv_streamoff,
+	.vidioc_g_tuner                 = bttv_g_tuner,
+	.vidioc_s_tuner                 = bttv_s_tuner,
+	.vidioc_g_crop                  = bttv_g_crop,
+	.vidioc_s_crop                  = bttv_s_crop,
+	.vidioc_g_fbuf                  = bttv_g_fbuf,
+	.vidioc_s_fbuf                  = bttv_s_fbuf,
+	.vidioc_overlay                 = bttv_overlay,
+	.vidioc_g_priority              = bttv_g_priority,
+	.vidioc_s_priority              = bttv_s_priority,
+	.vidioc_g_parm                  = bttv_g_parm,
+	.vidioc_g_frequency             = bttv_g_frequency,
+	.vidioc_s_frequency             = bttv_s_frequency,
+	.vidioc_log_status		= bttv_log_status,
+	.vidioc_querystd		= bttv_querystd,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register		= bttv_g_register,
+	.vidioc_s_register		= bttv_s_register,
+#endif
+};
+
+static struct video_device bttv_video_template = {
+	.fops         = &bttv_fops,
+	.ioctl_ops    = &bttv_ioctl_ops,
+	.tvnorms      = BTTV_NORMS,
+	.current_norm = V4L2_STD_PAL,
+};
+
+/* ----------------------------------------------------------------------- */
+/* radio interface                                                         */
+
+static int radio_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct bttv *btv = video_drvdata(file);
+	struct bttv_fh *fh;
+
+	dprintk("open dev=%s\n", video_device_node_name(vdev));
+
+	dprintk("%d: open called (radio)\n", btv->c.nr);
+
+	/* allocate per filehandle data */
+	fh = kmalloc(sizeof(*fh), GFP_KERNEL);
+	if (unlikely(!fh))
+		return -ENOMEM;
+	file->private_data = fh;
+	*fh = btv->init;
+
+	v4l2_prio_open(&btv->prio, &fh->prio);
+
+	btv->radio_user++;
+
+	bttv_call_all(btv, tuner, s_radio);
+	audio_input(btv,TVAUDIO_INPUT_RADIO);
+
+	return 0;
+}
+
+static int radio_release(struct file *file)
+{
+	struct bttv_fh *fh = file->private_data;
+	struct bttv *btv = fh->btv;
+	struct saa6588_command cmd;
+
+	v4l2_prio_close(&btv->prio, fh->prio);
+	file->private_data = NULL;
+	kfree(fh);
+
+	btv->radio_user--;
+
+	bttv_call_all(btv, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
+
+	return 0;
+}
+
+static int radio_querycap(struct file *file, void *priv,
+					struct v4l2_capability *cap)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+
+	strcpy(cap->driver, "bttv");
+	strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card));
+	sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci));
+	cap->capabilities = V4L2_CAP_TUNER;
+
+	return 0;
+}
+
+static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+
+	if (btv->tuner_type == TUNER_ABSENT)
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+	strcpy(t->name, "Radio");
+	t->type = V4L2_TUNER_RADIO;
+
+	bttv_call_all(btv, tuner, g_tuner, t);
+
+	if (btv->audio_mode_gpio)
+		btv->audio_mode_gpio(btv, t, 0);
+
+	return 0;
+}
+
+static int radio_enum_input(struct file *file, void *priv,
+				struct v4l2_input *i)
+{
+	if (i->index != 0)
+		return -EINVAL;
+
+	strcpy(i->name, "Radio");
+	i->type = V4L2_INPUT_TYPE_TUNER;
+
+	return 0;
+}
+
+static int radio_g_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	if (unlikely(a->index))
+		return -EINVAL;
+
+	strcpy(a->name, "Radio");
+
+	return 0;
+}
+
+static int radio_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *t)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+
+	if (0 != t->index)
+		return -EINVAL;
+
+	bttv_call_all(btv, tuner, s_tuner, t);
+	return 0;
+}
+
+static int radio_s_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	if (unlikely(a->index))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int radio_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	if (unlikely(i))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+	return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *c)
+{
+	const struct v4l2_queryctrl *ctrl;
+
+	if (c->id <  V4L2_CID_BASE ||
+			c->id >= V4L2_CID_LASTP1)
+		return -EINVAL;
+
+	if (c->id == V4L2_CID_AUDIO_MUTE) {
+		ctrl = ctrl_by_id(c->id);
+		*c = *ctrl;
+	} else
+		*c = no_ctl;
+
+	return 0;
+}
+
+static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static ssize_t radio_read(struct file *file, char __user *data,
+			 size_t count, loff_t *ppos)
+{
+	struct bttv_fh *fh = file->private_data;
+	struct bttv *btv = fh->btv;
+	struct saa6588_command cmd;
+	cmd.block_count = count/3;
+	cmd.buffer = data;
+	cmd.instance = file;
+	cmd.result = -ENODEV;
+
+	bttv_call_all(btv, core, ioctl, SAA6588_CMD_READ, &cmd);
+
+	return cmd.result;
+}
+
+static unsigned int radio_poll(struct file *file, poll_table *wait)
+{
+	struct bttv_fh *fh = file->private_data;
+	struct bttv *btv = fh->btv;
+	struct saa6588_command cmd;
+	cmd.instance = file;
+	cmd.event_list = wait;
+	cmd.result = -ENODEV;
+	bttv_call_all(btv, core, ioctl, SAA6588_CMD_POLL, &cmd);
+
+	return cmd.result;
+}
+
+static const struct v4l2_file_operations radio_fops =
+{
+	.owner	  = THIS_MODULE,
+	.open	  = radio_open,
+	.read     = radio_read,
+	.release  = radio_release,
+	.unlocked_ioctl = video_ioctl2,
+	.poll     = radio_poll,
+};
+
+static const struct v4l2_ioctl_ops radio_ioctl_ops = {
+	.vidioc_querycap        = radio_querycap,
+	.vidioc_g_tuner         = radio_g_tuner,
+	.vidioc_enum_input      = radio_enum_input,
+	.vidioc_g_audio         = radio_g_audio,
+	.vidioc_s_tuner         = radio_s_tuner,
+	.vidioc_s_audio         = radio_s_audio,
+	.vidioc_s_input         = radio_s_input,
+	.vidioc_s_std           = radio_s_std,
+	.vidioc_queryctrl       = radio_queryctrl,
+	.vidioc_g_input         = radio_g_input,
+	.vidioc_g_ctrl          = bttv_g_ctrl,
+	.vidioc_s_ctrl          = bttv_s_ctrl,
+	.vidioc_g_frequency     = bttv_g_frequency,
+	.vidioc_s_frequency     = bttv_s_frequency,
+};
+
+static struct video_device radio_template = {
+	.fops      = &radio_fops,
+	.ioctl_ops = &radio_ioctl_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+/* some debug code                                                         */
+
+static int bttv_risc_decode(u32 risc)
+{
+	static char *instr[16] = {
+		[ BT848_RISC_WRITE     >> 28 ] = "write",
+		[ BT848_RISC_SKIP      >> 28 ] = "skip",
+		[ BT848_RISC_WRITEC    >> 28 ] = "writec",
+		[ BT848_RISC_JUMP      >> 28 ] = "jump",
+		[ BT848_RISC_SYNC      >> 28 ] = "sync",
+		[ BT848_RISC_WRITE123  >> 28 ] = "write123",
+		[ BT848_RISC_SKIP123   >> 28 ] = "skip123",
+		[ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23",
+	};
+	static int incr[16] = {
+		[ BT848_RISC_WRITE     >> 28 ] = 2,
+		[ BT848_RISC_JUMP      >> 28 ] = 2,
+		[ BT848_RISC_SYNC      >> 28 ] = 2,
+		[ BT848_RISC_WRITE123  >> 28 ] = 5,
+		[ BT848_RISC_SKIP123   >> 28 ] = 2,
+		[ BT848_RISC_WRITE1S23 >> 28 ] = 3,
+	};
+	static char *bits[] = {
+		"be0",  "be1",  "be2",  "be3/resync",
+		"set0", "set1", "set2", "set3",
+		"clr0", "clr1", "clr2", "clr3",
+		"irq",  "res",  "eol",  "sol",
+	};
+	int i;
+
+	pr_cont("0x%08x [ %s", risc,
+	       instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
+	for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
+		if (risc & (1 << (i + 12)))
+			pr_cont(" %s", bits[i]);
+	pr_cont(" count=%d ]\n", risc & 0xfff);
+	return incr[risc >> 28] ? incr[risc >> 28] : 1;
+}
+
+static void bttv_risc_disasm(struct bttv *btv,
+			     struct btcx_riscmem *risc)
+{
+	unsigned int i,j,n;
+
+	pr_info("%s: risc disasm: %p [dma=0x%08lx]\n",
+		btv->c.v4l2_dev.name, risc->cpu, (unsigned long)risc->dma);
+	for (i = 0; i < (risc->size >> 2); i += n) {
+		pr_info("%s:   0x%lx: ",
+			btv->c.v4l2_dev.name,
+			(unsigned long)(risc->dma + (i<<2)));
+		n = bttv_risc_decode(le32_to_cpu(risc->cpu[i]));
+		for (j = 1; j < n; j++)
+			pr_info("%s:   0x%lx: 0x%08x [ arg #%d ]\n",
+				btv->c.v4l2_dev.name,
+				(unsigned long)(risc->dma + ((i+j)<<2)),
+				risc->cpu[i+j], j);
+		if (0 == risc->cpu[i])
+			break;
+	}
+}
+
+static void bttv_print_riscaddr(struct bttv *btv)
+{
+	pr_info("  main: %08llx\n", (unsigned long long)btv->main.dma);
+	pr_info("  vbi : o=%08llx e=%08llx\n",
+		btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
+		btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
+	pr_info("  cap : o=%08llx e=%08llx\n",
+		btv->curr.top
+		? (unsigned long long)btv->curr.top->top.dma : 0,
+		btv->curr.bottom
+		? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
+	pr_info("  scr : o=%08llx e=%08llx\n",
+		btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
+		btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
+	bttv_risc_disasm(btv, &btv->main);
+}
+
+/* ----------------------------------------------------------------------- */
+/* irq handler                                                             */
+
+static char *irq_name[] = {
+	"FMTCHG",  // format change detected (525 vs. 625)
+	"VSYNC",   // vertical sync (new field)
+	"HSYNC",   // horizontal sync
+	"OFLOW",   // chroma/luma AGC overflow
+	"HLOCK",   // horizontal lock changed
+	"VPRES",   // video presence changed
+	"6", "7",
+	"I2CDONE", // hw irc operation finished
+	"GPINT",   // gpio port triggered irq
+	"10",
+	"RISCI",   // risc instruction triggered irq
+	"FBUS",    // pixel data fifo dropped data (high pci bus latencies)
+	"FTRGT",   // pixel data fifo overrun
+	"FDSR",    // fifo data stream resyncronisation
+	"PPERR",   // parity error (data transfer)
+	"RIPERR",  // parity error (read risc instructions)
+	"PABORT",  // pci abort
+	"OCERR",   // risc instruction error
+	"SCERR",   // syncronisation error
+};
+
+static void bttv_print_irqbits(u32 print, u32 mark)
+{
+	unsigned int i;
+
+	pr_cont("bits:");
+	for (i = 0; i < ARRAY_SIZE(irq_name); i++) {
+		if (print & (1 << i))
+			pr_cont(" %s", irq_name[i]);
+		if (mark & (1 << i))
+			pr_cont("*");
+	}
+}
+
+static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
+{
+	pr_warn("%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
+		btv->c.nr,
+		(unsigned long)btv->main.dma,
+		(unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_VBI+1]),
+		(unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_FIELD+1]),
+		(unsigned long)rc);
+
+	if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
+		pr_notice("%d: Oh, there (temporarily?) is no input signal. "
+			  "Ok, then this is harmless, don't worry ;)\n",
+			  btv->c.nr);
+		return;
+	}
+	pr_notice("%d: Uhm. Looks like we have unusual high IRQ latencies\n",
+		  btv->c.nr);
+	pr_notice("%d: Lets try to catch the culpit red-handed ...\n",
+		  btv->c.nr);
+	dump_stack();
+}
+
+static int
+bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
+{
+	struct bttv_buffer *item;
+
+	memset(set,0,sizeof(*set));
+
+	/* capture request ? */
+	if (!list_empty(&btv->capture)) {
+		set->frame_irq = 1;
+		item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
+		if (V4L2_FIELD_HAS_TOP(item->vb.field))
+			set->top    = item;
+		if (V4L2_FIELD_HAS_BOTTOM(item->vb.field))
+			set->bottom = item;
+
+		/* capture request for other field ? */
+		if (!V4L2_FIELD_HAS_BOTH(item->vb.field) &&
+		    (item->vb.queue.next != &btv->capture)) {
+			item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue);
+			/* Mike Isely <isely@pobox.com> - Only check
+			 * and set up the bottom field in the logic
+			 * below.  Don't ever do the top field.  This
+			 * of course means that if we set up the
+			 * bottom field in the above code that we'll
+			 * actually skip a field.  But that's OK.
+			 * Having processed only a single buffer this
+			 * time, then the next time around the first
+			 * available buffer should be for a top field.
+			 * That will then cause us here to set up a
+			 * top then a bottom field in the normal way.
+			 * The alternative to this understanding is
+			 * that we set up the second available buffer
+			 * as a top field, but that's out of order
+			 * since this driver always processes the top
+			 * field first - the effect will be the two
+			 * buffers being returned in the wrong order,
+			 * with the second buffer also being delayed
+			 * by one field time (owing to the fifo nature
+			 * of videobuf).  Worse still, we'll be stuck
+			 * doing fields out of order now every time
+			 * until something else causes a field to be
+			 * dropped.  By effectively forcing a field to
+			 * drop this way then we always get back into
+			 * sync within a single frame time.  (Out of
+			 * order fields can screw up deinterlacing
+			 * algorithms.) */
+			if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) {
+				if (NULL == set->bottom &&
+				    V4L2_FIELD_BOTTOM == item->vb.field) {
+					set->bottom = item;
+				}
+				if (NULL != set->top  &&  NULL != set->bottom)
+					set->top_irq = 2;
+			}
+		}
+	}
+
+	/* screen overlay ? */
+	if (NULL != btv->screen) {
+		if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {
+			if (NULL == set->top && NULL == set->bottom) {
+				set->top    = btv->screen;
+				set->bottom = btv->screen;
+			}
+		} else {
+			if (V4L2_FIELD_TOP == btv->screen->vb.field &&
+			    NULL == set->top) {
+				set->top = btv->screen;
+			}
+			if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&
+			    NULL == set->bottom) {
+				set->bottom = btv->screen;
+			}
+		}
+	}
+
+	dprintk("%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",
+		btv->c.nr, set->top, set->bottom,
+		btv->screen, set->frame_irq, set->top_irq);
+	return 0;
+}
+
+static void
+bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
+		      struct bttv_buffer_set *curr, unsigned int state)
+{
+	struct timeval ts;
+
+	do_gettimeofday(&ts);
+
+	if (wakeup->top == wakeup->bottom) {
+		if (NULL != wakeup->top && curr->top != wakeup->top) {
+			if (irq_debug > 1)
+				pr_debug("%d: wakeup: both=%p\n",
+					 btv->c.nr, wakeup->top);
+			wakeup->top->vb.ts = ts;
+			wakeup->top->vb.field_count = btv->field_count;
+			wakeup->top->vb.state = state;
+			wake_up(&wakeup->top->vb.done);
+		}
+	} else {
+		if (NULL != wakeup->top && curr->top != wakeup->top) {
+			if (irq_debug > 1)
+				pr_debug("%d: wakeup: top=%p\n",
+					 btv->c.nr, wakeup->top);
+			wakeup->top->vb.ts = ts;
+			wakeup->top->vb.field_count = btv->field_count;
+			wakeup->top->vb.state = state;
+			wake_up(&wakeup->top->vb.done);
+		}
+		if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
+			if (irq_debug > 1)
+				pr_debug("%d: wakeup: bottom=%p\n",
+					 btv->c.nr, wakeup->bottom);
+			wakeup->bottom->vb.ts = ts;
+			wakeup->bottom->vb.field_count = btv->field_count;
+			wakeup->bottom->vb.state = state;
+			wake_up(&wakeup->bottom->vb.done);
+		}
+	}
+}
+
+static void
+bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
+		    unsigned int state)
+{
+	struct timeval ts;
+
+	if (NULL == wakeup)
+		return;
+
+	do_gettimeofday(&ts);
+	wakeup->vb.ts = ts;
+	wakeup->vb.field_count = btv->field_count;
+	wakeup->vb.state = state;
+	wake_up(&wakeup->vb.done);
+}
+
+static void bttv_irq_timeout(unsigned long data)
+{
+	struct bttv *btv = (struct bttv *)data;
+	struct bttv_buffer_set old,new;
+	struct bttv_buffer *ovbi;
+	struct bttv_buffer *item;
+	unsigned long flags;
+
+	if (bttv_verbose) {
+		pr_info("%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",
+			btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total,
+			btread(BT848_RISC_COUNT));
+		bttv_print_irqbits(btread(BT848_INT_STAT),0);
+		pr_cont("\n");
+	}
+
+	spin_lock_irqsave(&btv->s_lock,flags);
+
+	/* deactivate stuff */
+	memset(&new,0,sizeof(new));
+	old  = btv->curr;
+	ovbi = btv->cvbi;
+	btv->curr = new;
+	btv->cvbi = NULL;
+	btv->loop_irq = 0;
+	bttv_buffer_activate_video(btv, &new);
+	bttv_buffer_activate_vbi(btv,   NULL);
+	bttv_set_dma(btv, 0);
+
+	/* wake up */
+	bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_ERROR);
+	bttv_irq_wakeup_vbi(btv, ovbi, VIDEOBUF_ERROR);
+
+	/* cancel all outstanding capture / vbi requests */
+	while (!list_empty(&btv->capture)) {
+		item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
+		list_del(&item->vb.queue);
+		item->vb.state = VIDEOBUF_ERROR;
+		wake_up(&item->vb.done);
+	}
+	while (!list_empty(&btv->vcapture)) {
+		item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
+		list_del(&item->vb.queue);
+		item->vb.state = VIDEOBUF_ERROR;
+		wake_up(&item->vb.done);
+	}
+
+	btv->errors++;
+	spin_unlock_irqrestore(&btv->s_lock,flags);
+}
+
+static void
+bttv_irq_wakeup_top(struct bttv *btv)
+{
+	struct bttv_buffer *wakeup = btv->curr.top;
+
+	if (NULL == wakeup)
+		return;
+
+	spin_lock(&btv->s_lock);
+	btv->curr.top_irq = 0;
+	btv->curr.top = NULL;
+	bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
+
+	do_gettimeofday(&wakeup->vb.ts);
+	wakeup->vb.field_count = btv->field_count;
+	wakeup->vb.state = VIDEOBUF_DONE;
+	wake_up(&wakeup->vb.done);
+	spin_unlock(&btv->s_lock);
+}
+
+static inline int is_active(struct btcx_riscmem *risc, u32 rc)
+{
+	if (rc < risc->dma)
+		return 0;
+	if (rc > risc->dma + risc->size)
+		return 0;
+	return 1;
+}
+
+static void
+bttv_irq_switch_video(struct bttv *btv)
+{
+	struct bttv_buffer_set new;
+	struct bttv_buffer_set old;
+	dma_addr_t rc;
+
+	spin_lock(&btv->s_lock);
+
+	/* new buffer set */
+	bttv_irq_next_video(btv, &new);
+	rc = btread(BT848_RISC_COUNT);
+	if ((btv->curr.top    && is_active(&btv->curr.top->top,       rc)) ||
+	    (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) {
+		btv->framedrop++;
+		if (debug_latency)
+			bttv_irq_debug_low_latency(btv, rc);
+		spin_unlock(&btv->s_lock);
+		return;
+	}
+
+	/* switch over */
+	old = btv->curr;
+	btv->curr = new;
+	btv->loop_irq &= ~1;
+	bttv_buffer_activate_video(btv, &new);
+	bttv_set_dma(btv, 0);
+
+	/* switch input */
+	if (UNSET != btv->new_input) {
+		video_mux(btv,btv->new_input);
+		btv->new_input = UNSET;
+	}
+
+	/* wake up finished buffers */
+	bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_DONE);
+	spin_unlock(&btv->s_lock);
+}
+
+static void
+bttv_irq_switch_vbi(struct bttv *btv)
+{
+	struct bttv_buffer *new = NULL;
+	struct bttv_buffer *old;
+	u32 rc;
+
+	spin_lock(&btv->s_lock);
+
+	if (!list_empty(&btv->vcapture))
+		new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
+	old = btv->cvbi;
+
+	rc = btread(BT848_RISC_COUNT);
+	if (NULL != old && (is_active(&old->top,    rc) ||
+			    is_active(&old->bottom, rc))) {
+		btv->framedrop++;
+		if (debug_latency)
+			bttv_irq_debug_low_latency(btv, rc);
+		spin_unlock(&btv->s_lock);
+		return;
+	}
+
+	/* switch */
+	btv->cvbi = new;
+	btv->loop_irq &= ~4;
+	bttv_buffer_activate_vbi(btv, new);
+	bttv_set_dma(btv, 0);
+
+	bttv_irq_wakeup_vbi(btv, old, VIDEOBUF_DONE);
+	spin_unlock(&btv->s_lock);
+}
+
+static irqreturn_t bttv_irq(int irq, void *dev_id)
+{
+	u32 stat,astat;
+	u32 dstat;
+	int count;
+	struct bttv *btv;
+	int handled = 0;
+
+	btv=(struct bttv *)dev_id;
+
+	count=0;
+	while (1) {
+		/* get/clear interrupt status bits */
+		stat=btread(BT848_INT_STAT);
+		astat=stat&btread(BT848_INT_MASK);
+		if (!astat)
+			break;
+		handled = 1;
+		btwrite(stat,BT848_INT_STAT);
+
+		/* get device status bits */
+		dstat=btread(BT848_DSTATUS);
+
+		if (irq_debug) {
+			pr_debug("%d: irq loop=%d fc=%d riscs=%x, riscc=%08x, ",
+				 btv->c.nr, count, btv->field_count,
+				 stat>>28, btread(BT848_RISC_COUNT));
+			bttv_print_irqbits(stat,astat);
+			if (stat & BT848_INT_HLOCK)
+				pr_cont("   HLOC => %s",
+					dstat & BT848_DSTATUS_HLOC
+					? "yes" : "no");
+			if (stat & BT848_INT_VPRES)
+				pr_cont("   PRES => %s",
+					dstat & BT848_DSTATUS_PRES
+					? "yes" : "no");
+			if (stat & BT848_INT_FMTCHG)
+				pr_cont("   NUML => %s",
+					dstat & BT848_DSTATUS_NUML
+					? "625" : "525");
+			pr_cont("\n");
+		}
+
+		if (astat&BT848_INT_VSYNC)
+			btv->field_count++;
+
+		if ((astat & BT848_INT_GPINT) && btv->remote) {
+			bttv_input_irq(btv);
+		}
+
+		if (astat & BT848_INT_I2CDONE) {
+			btv->i2c_done = stat;
+			wake_up(&btv->i2c_queue);
+		}
+
+		if ((astat & BT848_INT_RISCI)  &&  (stat & (4<<28)))
+			bttv_irq_switch_vbi(btv);
+
+		if ((astat & BT848_INT_RISCI)  &&  (stat & (2<<28)))
+			bttv_irq_wakeup_top(btv);
+
+		if ((astat & BT848_INT_RISCI)  &&  (stat & (1<<28)))
+			bttv_irq_switch_video(btv);
+
+		if ((astat & BT848_INT_HLOCK)  &&  btv->opt_automute)
+			audio_mute(btv, btv->mute);  /* trigger automute */
+
+		if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
+			pr_info("%d: %s%s @ %08x,",
+				btv->c.nr,
+				(astat & BT848_INT_SCERR) ? "SCERR" : "",
+				(astat & BT848_INT_OCERR) ? "OCERR" : "",
+				btread(BT848_RISC_COUNT));
+			bttv_print_irqbits(stat,astat);
+			pr_cont("\n");
+			if (bttv_debug)
+				bttv_print_riscaddr(btv);
+		}
+		if (fdsr && astat & BT848_INT_FDSR) {
+			pr_info("%d: FDSR @ %08x\n",
+				btv->c.nr, btread(BT848_RISC_COUNT));
+			if (bttv_debug)
+				bttv_print_riscaddr(btv);
+		}
+
+		count++;
+		if (count > 4) {
+
+			if (count > 8 || !(astat & BT848_INT_GPINT)) {
+				btwrite(0, BT848_INT_MASK);
+
+				pr_err("%d: IRQ lockup, cleared int mask [",
+				       btv->c.nr);
+			} else {
+				pr_err("%d: IRQ lockup, clearing GPINT from int mask [",
+				       btv->c.nr);
+
+				btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
+						BT848_INT_MASK);
+			};
+
+			bttv_print_irqbits(stat,astat);
+
+			pr_cont("]\n");
+		}
+	}
+	btv->irq_total++;
+	if (handled)
+		btv->irq_me++;
+	return IRQ_RETVAL(handled);
+}
+
+
+/* ----------------------------------------------------------------------- */
+/* initialitation                                                          */
+
+static struct video_device *vdev_init(struct bttv *btv,
+				      const struct video_device *template,
+				      const char *type_name)
+{
+	struct video_device *vfd;
+
+	vfd = video_device_alloc();
+	if (NULL == vfd)
+		return NULL;
+	*vfd = *template;
+	vfd->v4l2_dev = &btv->c.v4l2_dev;
+	vfd->release = video_device_release;
+	vfd->debug   = bttv_debug;
+	video_set_drvdata(vfd, btv);
+	snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
+		 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
+		 type_name, bttv_tvcards[btv->c.type].name);
+	return vfd;
+}
+
+static void bttv_unregister_video(struct bttv *btv)
+{
+	if (btv->video_dev) {
+		if (video_is_registered(btv->video_dev))
+			video_unregister_device(btv->video_dev);
+		else
+			video_device_release(btv->video_dev);
+		btv->video_dev = NULL;
+	}
+	if (btv->vbi_dev) {
+		if (video_is_registered(btv->vbi_dev))
+			video_unregister_device(btv->vbi_dev);
+		else
+			video_device_release(btv->vbi_dev);
+		btv->vbi_dev = NULL;
+	}
+	if (btv->radio_dev) {
+		if (video_is_registered(btv->radio_dev))
+			video_unregister_device(btv->radio_dev);
+		else
+			video_device_release(btv->radio_dev);
+		btv->radio_dev = NULL;
+	}
+}
+
+/* register video4linux devices */
+static int __devinit bttv_register_video(struct bttv *btv)
+{
+	if (no_overlay > 0)
+		pr_notice("Overlay support disabled\n");
+
+	/* video */
+	btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
+
+	if (NULL == btv->video_dev)
+		goto err;
+	if (video_register_device(btv->video_dev, VFL_TYPE_GRABBER,
+				  video_nr[btv->c.nr]) < 0)
+		goto err;
+	pr_info("%d: registered device %s\n",
+		btv->c.nr, video_device_node_name(btv->video_dev));
+	if (device_create_file(&btv->video_dev->dev,
+				     &dev_attr_card)<0) {
+		pr_err("%d: device_create_file 'card' failed\n", btv->c.nr);
+		goto err;
+	}
+
+	/* vbi */
+	btv->vbi_dev = vdev_init(btv, &bttv_video_template, "vbi");
+
+	if (NULL == btv->vbi_dev)
+		goto err;
+	if (video_register_device(btv->vbi_dev, VFL_TYPE_VBI,
+				  vbi_nr[btv->c.nr]) < 0)
+		goto err;
+	pr_info("%d: registered device %s\n",
+		btv->c.nr, video_device_node_name(btv->vbi_dev));
+
+	if (!btv->has_radio)
+		return 0;
+	/* radio */
+	btv->radio_dev = vdev_init(btv, &radio_template, "radio");
+	if (NULL == btv->radio_dev)
+		goto err;
+	if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,
+				  radio_nr[btv->c.nr]) < 0)
+		goto err;
+	pr_info("%d: registered device %s\n",
+		btv->c.nr, video_device_node_name(btv->radio_dev));
+
+	/* all done */
+	return 0;
+
+ err:
+	bttv_unregister_video(btv);
+	return -1;
+}
+
+
+/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
+/* response on cards with no firmware is not enabled by OF */
+static void pci_set_command(struct pci_dev *dev)
+{
+#if defined(__powerpc__)
+	unsigned int cmd;
+
+	pci_read_config_dword(dev, PCI_COMMAND, &cmd);
+	cmd = (cmd | PCI_COMMAND_MEMORY );
+	pci_write_config_dword(dev, PCI_COMMAND, cmd);
+#endif
+}
+
+static int __devinit bttv_probe(struct pci_dev *dev,
+				const struct pci_device_id *pci_id)
+{
+	int result;
+	unsigned char lat;
+	struct bttv *btv;
+
+	if (bttv_num == BTTV_MAX)
+		return -ENOMEM;
+	pr_info("Bt8xx card found (%d)\n", bttv_num);
+	bttvs[bttv_num] = btv = kzalloc(sizeof(*btv), GFP_KERNEL);
+	if (btv == NULL) {
+		pr_err("out of memory\n");
+		return -ENOMEM;
+	}
+	btv->c.nr  = bttv_num;
+	snprintf(btv->c.v4l2_dev.name, sizeof(btv->c.v4l2_dev.name),
+			"bttv%d", btv->c.nr);
+
+	/* initialize structs / fill in defaults */
+	mutex_init(&btv->lock);
+	spin_lock_init(&btv->s_lock);
+	spin_lock_init(&btv->gpio_lock);
+	init_waitqueue_head(&btv->i2c_queue);
+	INIT_LIST_HEAD(&btv->c.subs);
+	INIT_LIST_HEAD(&btv->capture);
+	INIT_LIST_HEAD(&btv->vcapture);
+	v4l2_prio_init(&btv->prio);
+
+	init_timer(&btv->timeout);
+	btv->timeout.function = bttv_irq_timeout;
+	btv->timeout.data     = (unsigned long)btv;
+
+	btv->i2c_rc = -1;
+	btv->tuner_type  = UNSET;
+	btv->new_input   = UNSET;
+	btv->has_radio=radio[btv->c.nr];
+
+	/* pci stuff (init, get irq/mmio, ... */
+	btv->c.pci = dev;
+	btv->id  = dev->device;
+	if (pci_enable_device(dev)) {
+		pr_warn("%d: Can't enable device\n", btv->c.nr);
+		return -EIO;
+	}
+	if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) {
+		pr_warn("%d: No suitable DMA available\n", btv->c.nr);
+		return -EIO;
+	}
+	if (!request_mem_region(pci_resource_start(dev,0),
+				pci_resource_len(dev,0),
+				btv->c.v4l2_dev.name)) {
+		pr_warn("%d: can't request iomem (0x%llx)\n",
+			btv->c.nr,
+			(unsigned long long)pci_resource_start(dev, 0));
+		return -EBUSY;
+	}
+	pci_set_master(dev);
+	pci_set_command(dev);
+
+	result = v4l2_device_register(&dev->dev, &btv->c.v4l2_dev);
+	if (result < 0) {
+		pr_warn("%d: v4l2_device_register() failed\n", btv->c.nr);
+		goto fail0;
+	}
+
+	btv->revision = dev->revision;
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+	pr_info("%d: Bt%d (rev %d) at %s, irq: %d, latency: %d, mmio: 0x%llx\n",
+		bttv_num, btv->id, btv->revision, pci_name(dev),
+		btv->c.pci->irq, lat,
+		(unsigned long long)pci_resource_start(dev, 0));
+	schedule();
+
+	btv->bt848_mmio = ioremap(pci_resource_start(dev, 0), 0x1000);
+	if (NULL == btv->bt848_mmio) {
+		pr_err("%d: ioremap() failed\n", btv->c.nr);
+		result = -EIO;
+		goto fail1;
+	}
+
+	/* identify card */
+	bttv_idcard(btv);
+
+	/* disable irqs, register irq handler */
+	btwrite(0, BT848_INT_MASK);
+	result = request_irq(btv->c.pci->irq, bttv_irq,
+	    IRQF_SHARED | IRQF_DISABLED, btv->c.v4l2_dev.name, (void *)btv);
+	if (result < 0) {
+		pr_err("%d: can't get IRQ %d\n",
+		       bttv_num, btv->c.pci->irq);
+		goto fail1;
+	}
+
+	if (0 != bttv_handle_chipset(btv)) {
+		result = -EIO;
+		goto fail2;
+	}
+
+	/* init options from insmod args */
+	btv->opt_combfilter = combfilter;
+	btv->opt_lumafilter = lumafilter;
+	btv->opt_automute   = automute;
+	btv->opt_chroma_agc = chroma_agc;
+	btv->opt_adc_crush  = adc_crush;
+	btv->opt_vcr_hack   = vcr_hack;
+	btv->opt_whitecrush_upper  = whitecrush_upper;
+	btv->opt_whitecrush_lower  = whitecrush_lower;
+	btv->opt_uv_ratio   = uv_ratio;
+	btv->opt_full_luma_range   = full_luma_range;
+	btv->opt_coring     = coring;
+
+	/* fill struct bttv with some useful defaults */
+	btv->init.btv         = btv;
+	btv->init.ov.w.width  = 320;
+	btv->init.ov.w.height = 240;
+	btv->init.fmt         = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+	btv->init.width       = 320;
+	btv->init.height      = 240;
+	btv->input = 0;
+
+	/* initialize hardware */
+	if (bttv_gpio)
+		bttv_gpio_tracking(btv,"pre-init");
+
+	bttv_risc_init_main(btv);
+	init_bt848(btv);
+
+	/* gpio */
+	btwrite(0x00, BT848_GPIO_REG_INP);
+	btwrite(0x00, BT848_GPIO_OUT_EN);
+	if (bttv_verbose)
+		bttv_gpio_tracking(btv,"init");
+
+	/* needs to be done before i2c is registered */
+	bttv_init_card1(btv);
+
+	/* register i2c + gpio */
+	init_bttv_i2c(btv);
+
+	/* some card-specific stuff (needs working i2c) */
+	bttv_init_card2(btv);
+	bttv_init_tuner(btv);
+	init_irqreg(btv);
+
+	/* register video4linux + input */
+	if (!bttv_tvcards[btv->c.type].no_video) {
+		bttv_register_video(btv);
+		bt848_bright(btv,32768);
+		bt848_contrast(btv, 27648);
+		bt848_hue(btv,32768);
+		bt848_sat(btv,32768);
+		audio_mute(btv, 1);
+		set_input(btv, 0, btv->tvnorm);
+		bttv_crop_reset(&btv->crop[0], btv->tvnorm);
+		btv->crop[1] = btv->crop[0]; /* current = default */
+		disclaim_vbi_lines(btv);
+		disclaim_video_lines(btv);
+	}
+
+	/* add subdevices and autoload dvb-bt8xx if needed */
+	if (bttv_tvcards[btv->c.type].has_dvb) {
+		bttv_sub_add_device(&btv->c, "dvb");
+		request_modules(btv);
+	}
+
+	if (!disable_ir) {
+		init_bttv_i2c_ir(btv);
+		bttv_input_init(btv);
+	}
+
+	/* everything is fine */
+	bttv_num++;
+	return 0;
+
+fail2:
+	free_irq(btv->c.pci->irq,btv);
+
+fail1:
+	v4l2_device_unregister(&btv->c.v4l2_dev);
+
+fail0:
+	if (btv->bt848_mmio)
+		iounmap(btv->bt848_mmio);
+	release_mem_region(pci_resource_start(btv->c.pci,0),
+			   pci_resource_len(btv->c.pci,0));
+	return result;
+}
+
+static void __devexit bttv_remove(struct pci_dev *pci_dev)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+	struct bttv *btv = to_bttv(v4l2_dev);
+
+	if (bttv_verbose)
+		pr_info("%d: unloading\n", btv->c.nr);
+
+	if (bttv_tvcards[btv->c.type].has_dvb)
+		flush_request_modules(btv);
+
+	/* shutdown everything (DMA+IRQs) */
+	btand(~15, BT848_GPIO_DMA_CTL);
+	btwrite(0, BT848_INT_MASK);
+	btwrite(~0x0, BT848_INT_STAT);
+	btwrite(0x0, BT848_GPIO_OUT_EN);
+	if (bttv_gpio)
+		bttv_gpio_tracking(btv,"cleanup");
+
+	/* tell gpio modules we are leaving ... */
+	btv->shutdown=1;
+	bttv_input_fini(btv);
+	bttv_sub_del_devices(&btv->c);
+
+	/* unregister i2c_bus + input */
+	fini_bttv_i2c(btv);
+
+	/* unregister video4linux */
+	bttv_unregister_video(btv);
+
+	/* free allocated memory */
+	btcx_riscmem_free(btv->c.pci,&btv->main);
+
+	/* free ressources */
+	free_irq(btv->c.pci->irq,btv);
+	iounmap(btv->bt848_mmio);
+	release_mem_region(pci_resource_start(btv->c.pci,0),
+			   pci_resource_len(btv->c.pci,0));
+
+	v4l2_device_unregister(&btv->c.v4l2_dev);
+	bttvs[btv->c.nr] = NULL;
+	kfree(btv);
+
+	return;
+}
+
+#ifdef CONFIG_PM
+static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+	struct bttv *btv = to_bttv(v4l2_dev);
+	struct bttv_buffer_set idle;
+	unsigned long flags;
+
+	dprintk("%d: suspend %d\n", btv->c.nr, state.event);
+
+	/* stop dma + irqs */
+	spin_lock_irqsave(&btv->s_lock,flags);
+	memset(&idle, 0, sizeof(idle));
+	btv->state.video = btv->curr;
+	btv->state.vbi   = btv->cvbi;
+	btv->state.loop_irq = btv->loop_irq;
+	btv->curr = idle;
+	btv->loop_irq = 0;
+	bttv_buffer_activate_video(btv, &idle);
+	bttv_buffer_activate_vbi(btv, NULL);
+	bttv_set_dma(btv, 0);
+	btwrite(0, BT848_INT_MASK);
+	spin_unlock_irqrestore(&btv->s_lock,flags);
+
+	/* save bt878 state */
+	btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN);
+	btv->state.gpio_data   = gpio_read();
+
+	/* save pci state */
+	pci_save_state(pci_dev);
+	if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
+		pci_disable_device(pci_dev);
+		btv->state.disabled = 1;
+	}
+	return 0;
+}
+
+static int bttv_resume(struct pci_dev *pci_dev)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+	struct bttv *btv = to_bttv(v4l2_dev);
+	unsigned long flags;
+	int err;
+
+	dprintk("%d: resume\n", btv->c.nr);
+
+	/* restore pci state */
+	if (btv->state.disabled) {
+		err=pci_enable_device(pci_dev);
+		if (err) {
+			pr_warn("%d: Can't enable device\n", btv->c.nr);
+			return err;
+		}
+		btv->state.disabled = 0;
+	}
+	err=pci_set_power_state(pci_dev, PCI_D0);
+	if (err) {
+		pci_disable_device(pci_dev);
+		pr_warn("%d: Can't enable device\n", btv->c.nr);
+		btv->state.disabled = 1;
+		return err;
+	}
+
+	pci_restore_state(pci_dev);
+
+	/* restore bt878 state */
+	bttv_reinit_bt848(btv);
+	gpio_inout(0xffffff, btv->state.gpio_enable);
+	gpio_write(btv->state.gpio_data);
+
+	/* restart dma */
+	spin_lock_irqsave(&btv->s_lock,flags);
+	btv->curr = btv->state.video;
+	btv->cvbi = btv->state.vbi;
+	btv->loop_irq = btv->state.loop_irq;
+	bttv_buffer_activate_video(btv, &btv->curr);
+	bttv_buffer_activate_vbi(btv, btv->cvbi);
+	bttv_set_dma(btv, 0);
+	spin_unlock_irqrestore(&btv->s_lock,flags);
+	return 0;
+}
+#endif
+
+static struct pci_device_id bttv_pci_tbl[] = {
+	{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848), 0},
+	{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0},
+	{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0},
+	{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879), 0},
+	{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_FUSION879), 0},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
+
+static struct pci_driver bttv_pci_driver = {
+	.name     = "bttv",
+	.id_table = bttv_pci_tbl,
+	.probe    = bttv_probe,
+	.remove   = __devexit_p(bttv_remove),
+#ifdef CONFIG_PM
+	.suspend  = bttv_suspend,
+	.resume   = bttv_resume,
+#endif
+};
+
+static int __init bttv_init_module(void)
+{
+	int ret;
+
+	bttv_num = 0;
+
+	pr_info("driver version %s loaded\n", BTTV_VERSION);
+	if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
+		gbuffers = 2;
+	if (gbufsize > BTTV_MAX_FBUF)
+		gbufsize = BTTV_MAX_FBUF;
+	gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
+	if (bttv_verbose)
+		pr_info("using %d buffers with %dk (%d pages) each for capture\n",
+			gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT);
+
+	bttv_check_chipset();
+
+	ret = bus_register(&bttv_sub_bus_type);
+	if (ret < 0) {
+		pr_warn("bus_register error: %d\n", ret);
+		return ret;
+	}
+	ret = pci_register_driver(&bttv_pci_driver);
+	if (ret < 0)
+		bus_unregister(&bttv_sub_bus_type);
+
+	return ret;
+}
+
+static void __exit bttv_cleanup_module(void)
+{
+	pci_unregister_driver(&bttv_pci_driver);
+	bus_unregister(&bttv_sub_bus_type);
+}
+
+module_init(bttv_init_module);
+module_exit(bttv_cleanup_module);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/bt8xx/bttv-gpio.c b/drivers/media/pci/bt8xx/bttv-gpio.c
new file mode 100644
index 0000000..922e823
--- /dev/null
+++ b/drivers/media/pci/bt8xx/bttv-gpio.c
@@ -0,0 +1,189 @@
+/*
+
+    bttv-gpio.c  --  gpio sub drivers
+
+    sysfs-based sub driver interface for bttv
+    mainly intended for gpio access
+
+
+    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+			   & Marcus Metzler (mocm@thp.uni-koeln.de)
+    (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+
+#include "bttvp.h"
+
+/* ----------------------------------------------------------------------- */
+/* internal: the bttv "bus"                                                */
+
+static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct bttv_sub_driver *sub = to_bttv_sub_drv(drv);
+	int len = strlen(sub->wanted);
+
+	if (0 == strncmp(dev_name(dev), sub->wanted, len))
+		return 1;
+	return 0;
+}
+
+static int bttv_sub_probe(struct device *dev)
+{
+	struct bttv_sub_device *sdev = to_bttv_sub_dev(dev);
+	struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver);
+
+	return sub->probe ? sub->probe(sdev) : -ENODEV;
+}
+
+static int bttv_sub_remove(struct device *dev)
+{
+	struct bttv_sub_device *sdev = to_bttv_sub_dev(dev);
+	struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver);
+
+	if (sub->remove)
+		sub->remove(sdev);
+	return 0;
+}
+
+struct bus_type bttv_sub_bus_type = {
+	.name   = "bttv-sub",
+	.match  = &bttv_sub_bus_match,
+	.probe  = bttv_sub_probe,
+	.remove = bttv_sub_remove,
+};
+
+static void release_sub_device(struct device *dev)
+{
+	struct bttv_sub_device *sub = to_bttv_sub_dev(dev);
+	kfree(sub);
+}
+
+int bttv_sub_add_device(struct bttv_core *core, char *name)
+{
+	struct bttv_sub_device *sub;
+	int err;
+
+	sub = kzalloc(sizeof(*sub),GFP_KERNEL);
+	if (NULL == sub)
+		return -ENOMEM;
+
+	sub->core        = core;
+	sub->dev.parent  = &core->pci->dev;
+	sub->dev.bus     = &bttv_sub_bus_type;
+	sub->dev.release = release_sub_device;
+	dev_set_name(&sub->dev, "%s%d", name, core->nr);
+
+	err = device_register(&sub->dev);
+	if (0 != err) {
+		kfree(sub);
+		return err;
+	}
+	pr_info("%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev));
+	list_add_tail(&sub->list,&core->subs);
+	return 0;
+}
+
+int bttv_sub_del_devices(struct bttv_core *core)
+{
+	struct bttv_sub_device *sub, *save;
+
+	list_for_each_entry_safe(sub, save, &core->subs, list) {
+		list_del(&sub->list);
+		device_unregister(&sub->dev);
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+/* external: sub-driver register/unregister                                */
+
+int bttv_sub_register(struct bttv_sub_driver *sub, char *wanted)
+{
+	sub->drv.bus = &bttv_sub_bus_type;
+	snprintf(sub->wanted,sizeof(sub->wanted),"%s",wanted);
+	return driver_register(&sub->drv);
+}
+EXPORT_SYMBOL(bttv_sub_register);
+
+int bttv_sub_unregister(struct bttv_sub_driver *sub)
+{
+	driver_unregister(&sub->drv);
+	return 0;
+}
+EXPORT_SYMBOL(bttv_sub_unregister);
+
+/* ----------------------------------------------------------------------- */
+/* external: gpio access functions                                         */
+
+void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits)
+{
+	struct bttv *btv = container_of(core, struct bttv, c);
+	unsigned long flags;
+	u32 data;
+
+	spin_lock_irqsave(&btv->gpio_lock,flags);
+	data = btread(BT848_GPIO_OUT_EN);
+	data = data & ~mask;
+	data = data | (mask & outbits);
+	btwrite(data,BT848_GPIO_OUT_EN);
+	spin_unlock_irqrestore(&btv->gpio_lock,flags);
+}
+
+u32 bttv_gpio_read(struct bttv_core *core)
+{
+	struct bttv *btv = container_of(core, struct bttv, c);
+	u32 value;
+
+	value = btread(BT848_GPIO_DATA);
+	return value;
+}
+
+void bttv_gpio_write(struct bttv_core *core, u32 value)
+{
+	struct bttv *btv = container_of(core, struct bttv, c);
+
+	btwrite(value,BT848_GPIO_DATA);
+}
+
+void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits)
+{
+	struct bttv *btv = container_of(core, struct bttv, c);
+	unsigned long flags;
+	u32 data;
+
+	spin_lock_irqsave(&btv->gpio_lock,flags);
+	data = btread(BT848_GPIO_DATA);
+	data = data & ~mask;
+	data = data | (mask & bits);
+	btwrite(data,BT848_GPIO_DATA);
+	spin_unlock_irqrestore(&btv->gpio_lock,flags);
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/bt8xx/bttv-i2c.c b/drivers/media/pci/bt8xx/bttv-i2c.c
new file mode 100644
index 0000000..580c8e6
--- /dev/null
+++ b/drivers/media/pci/bt8xx/bttv-i2c.c
@@ -0,0 +1,397 @@
+/*
+
+    bttv-i2c.c  --  all the i2c code is here
+
+    bttv - Bt848 frame grabber driver
+
+    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+			   & Marcus Metzler (mocm@thp.uni-koeln.de)
+    (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
+
+    (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
+	- Multituner support and i2c address binding
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "bttvp.h"
+#include <media/v4l2-common.h>
+#include <linux/jiffies.h>
+#include <asm/io.h>
+
+static int i2c_debug;
+static int i2c_hw;
+static int i2c_scan;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "configure i2c debug level");
+module_param(i2c_hw,    int, 0444);
+MODULE_PARM_DESC(i2c_hw,"force use of hardware i2c support, "
+			"instead of software bitbang");
+module_param(i2c_scan,  int, 0444);
+MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
+
+static unsigned int i2c_udelay = 5;
+module_param(i2c_udelay, int, 0444);
+MODULE_PARM_DESC(i2c_udelay,"soft i2c delay at insmod time, in usecs "
+		"(should be 5 or higher). Lower value means higher bus speed.");
+
+/* ----------------------------------------------------------------------- */
+/* I2C functions - bitbanging adapter (software i2c)                       */
+
+static void bttv_bit_setscl(void *data, int state)
+{
+	struct bttv *btv = (struct bttv*)data;
+
+	if (state)
+		btv->i2c_state |= 0x02;
+	else
+		btv->i2c_state &= ~0x02;
+	btwrite(btv->i2c_state, BT848_I2C);
+	btread(BT848_I2C);
+}
+
+static void bttv_bit_setsda(void *data, int state)
+{
+	struct bttv *btv = (struct bttv*)data;
+
+	if (state)
+		btv->i2c_state |= 0x01;
+	else
+		btv->i2c_state &= ~0x01;
+	btwrite(btv->i2c_state, BT848_I2C);
+	btread(BT848_I2C);
+}
+
+static int bttv_bit_getscl(void *data)
+{
+	struct bttv *btv = (struct bttv*)data;
+	int state;
+
+	state = btread(BT848_I2C) & 0x02 ? 1 : 0;
+	return state;
+}
+
+static int bttv_bit_getsda(void *data)
+{
+	struct bttv *btv = (struct bttv*)data;
+	int state;
+
+	state = btread(BT848_I2C) & 0x01;
+	return state;
+}
+
+static struct i2c_algo_bit_data __devinitdata bttv_i2c_algo_bit_template = {
+	.setsda  = bttv_bit_setsda,
+	.setscl  = bttv_bit_setscl,
+	.getsda  = bttv_bit_getsda,
+	.getscl  = bttv_bit_getscl,
+	.udelay  = 16,
+	.timeout = 200,
+};
+
+/* ----------------------------------------------------------------------- */
+/* I2C functions - hardware i2c                                            */
+
+static u32 functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL;
+}
+
+static int
+bttv_i2c_wait_done(struct bttv *btv)
+{
+	int rc = 0;
+
+	/* timeout */
+	if (wait_event_interruptible_timeout(btv->i2c_queue,
+	    btv->i2c_done, msecs_to_jiffies(85)) == -ERESTARTSYS)
+		rc = -EIO;
+
+	if (btv->i2c_done & BT848_INT_RACK)
+		rc = 1;
+	btv->i2c_done = 0;
+	return rc;
+}
+
+#define I2C_HW (BT878_I2C_MODE  | BT848_I2C_SYNC |\
+		BT848_I2C_SCL | BT848_I2C_SDA)
+
+static int
+bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
+{
+	u32 xmit;
+	int retval,cnt;
+
+	/* sanity checks */
+	if (0 == msg->len)
+		return -EINVAL;
+
+	/* start, address + first byte */
+	xmit = (msg->addr << 25) | (msg->buf[0] << 16) | I2C_HW;
+	if (msg->len > 1 || !last)
+		xmit |= BT878_I2C_NOSTOP;
+	btwrite(xmit, BT848_I2C);
+	retval = bttv_i2c_wait_done(btv);
+	if (retval < 0)
+		goto err;
+	if (retval == 0)
+		goto eio;
+	if (i2c_debug) {
+		pr_cont(" <W %02x %02x", msg->addr << 1, msg->buf[0]);
+	}
+
+	for (cnt = 1; cnt < msg->len; cnt++ ) {
+		/* following bytes */
+		xmit = (msg->buf[cnt] << 24) | I2C_HW | BT878_I2C_NOSTART;
+		if (cnt < msg->len-1 || !last)
+			xmit |= BT878_I2C_NOSTOP;
+		btwrite(xmit, BT848_I2C);
+		retval = bttv_i2c_wait_done(btv);
+		if (retval < 0)
+			goto err;
+		if (retval == 0)
+			goto eio;
+		if (i2c_debug)
+			pr_cont(" %02x", msg->buf[cnt]);
+	}
+	if (!(xmit & BT878_I2C_NOSTOP))
+		pr_cont(">\n");
+	return msg->len;
+
+ eio:
+	retval = -EIO;
+ err:
+	if (i2c_debug)
+		pr_cont(" ERR: %d\n",retval);
+	return retval;
+}
+
+static int
+bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
+{
+	u32 xmit;
+	u32 cnt;
+	int retval;
+
+	for (cnt = 0; cnt < msg->len; cnt++) {
+		xmit = (msg->addr << 25) | (1 << 24) | I2C_HW;
+		if (cnt < msg->len-1)
+			xmit |= BT848_I2C_W3B;
+		if (cnt < msg->len-1 || !last)
+			xmit |= BT878_I2C_NOSTOP;
+		if (cnt)
+			xmit |= BT878_I2C_NOSTART;
+
+		if (i2c_debug) {
+			if (!(xmit & BT878_I2C_NOSTART))
+				pr_cont(" <R %02x", (msg->addr << 1) +1);
+		}
+
+		btwrite(xmit, BT848_I2C);
+		retval = bttv_i2c_wait_done(btv);
+		if (retval < 0)
+			goto err;
+		if (retval == 0)
+			goto eio;
+		msg->buf[cnt] = ((u32)btread(BT848_I2C) >> 8) & 0xff;
+		if (i2c_debug) {
+			pr_cont(" =%02x", msg->buf[cnt]);
+		}
+		if (i2c_debug && !(xmit & BT878_I2C_NOSTOP))
+			pr_cont(" >\n");
+	}
+
+
+	return msg->len;
+
+ eio:
+	retval = -EIO;
+ err:
+	if (i2c_debug)
+		pr_cont(" ERR: %d\n",retval);
+	return retval;
+}
+
+static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
+{
+	struct v4l2_device *v4l2_dev = i2c_get_adapdata(i2c_adap);
+	struct bttv *btv = to_bttv(v4l2_dev);
+	int retval = 0;
+	int i;
+
+	if (i2c_debug)
+		pr_debug("bt-i2c:");
+
+	btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT);
+	for (i = 0 ; i < num; i++) {
+		if (msgs[i].flags & I2C_M_RD) {
+			/* read */
+			retval = bttv_i2c_readbytes(btv, &msgs[i], i+1 == num);
+			if (retval < 0)
+				goto err;
+		} else {
+			/* write */
+			retval = bttv_i2c_sendbytes(btv, &msgs[i], i+1 == num);
+			if (retval < 0)
+				goto err;
+		}
+	}
+	return num;
+
+ err:
+	return retval;
+}
+
+static const struct i2c_algorithm bttv_algo = {
+	.master_xfer   = bttv_i2c_xfer,
+	.functionality = functionality,
+};
+
+/* ----------------------------------------------------------------------- */
+/* I2C functions - common stuff                                            */
+
+/* read I2C */
+int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
+{
+	unsigned char buffer = 0;
+
+	if (0 != btv->i2c_rc)
+		return -1;
+	if (bttv_verbose && NULL != probe_for)
+		pr_info("%d: i2c: checking for %s @ 0x%02x... ",
+			btv->c.nr, probe_for, addr);
+	btv->i2c_client.addr = addr >> 1;
+	if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
+		if (NULL != probe_for) {
+			if (bttv_verbose)
+				pr_cont("not found\n");
+		} else
+			pr_warn("%d: i2c read 0x%x: error\n",
+				btv->c.nr, addr);
+		return -1;
+	}
+	if (bttv_verbose && NULL != probe_for)
+		pr_cont("found\n");
+	return buffer;
+}
+
+/* write I2C */
+int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
+		    unsigned char b2, int both)
+{
+	unsigned char buffer[2];
+	int bytes = both ? 2 : 1;
+
+	if (0 != btv->i2c_rc)
+		return -1;
+	btv->i2c_client.addr = addr >> 1;
+	buffer[0] = b1;
+	buffer[1] = b2;
+	if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes))
+		return -1;
+	return 0;
+}
+
+/* read EEPROM content */
+void __devinit bttv_readee(struct bttv *btv, unsigned char *eedata, int addr)
+{
+	memset(eedata, 0, 256);
+	if (0 != btv->i2c_rc)
+		return;
+	btv->i2c_client.addr = addr >> 1;
+	tveeprom_read(&btv->i2c_client, eedata, 256);
+}
+
+static char *i2c_devs[128] = {
+	[ 0x1c >> 1 ] = "lgdt330x",
+	[ 0x30 >> 1 ] = "IR (hauppauge)",
+	[ 0x80 >> 1 ] = "msp34xx",
+	[ 0x86 >> 1 ] = "tda9887",
+	[ 0xa0 >> 1 ] = "eeprom",
+	[ 0xc0 >> 1 ] = "tuner (analog)",
+	[ 0xc2 >> 1 ] = "tuner (analog)",
+};
+
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+	unsigned char buf;
+	int i,rc;
+
+	for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
+		c->addr = i;
+		rc = i2c_master_recv(c,&buf,0);
+		if (rc < 0)
+			continue;
+		pr_info("%s: i2c scan: found device @ 0x%x  [%s]\n",
+			name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+	}
+}
+
+/* init + register i2c adapter */
+int __devinit init_bttv_i2c(struct bttv *btv)
+{
+	strlcpy(btv->i2c_client.name, "bttv internal", I2C_NAME_SIZE);
+
+	if (i2c_hw)
+		btv->use_i2c_hw = 1;
+	if (btv->use_i2c_hw) {
+		/* bt878 */
+		strlcpy(btv->c.i2c_adap.name, "bt878",
+			sizeof(btv->c.i2c_adap.name));
+		btv->c.i2c_adap.algo = &bttv_algo;
+	} else {
+		/* bt848 */
+	/* Prevents usage of invalid delay values */
+		if (i2c_udelay<5)
+			i2c_udelay=5;
+
+		strlcpy(btv->c.i2c_adap.name, "bttv",
+			sizeof(btv->c.i2c_adap.name));
+		memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
+		       sizeof(bttv_i2c_algo_bit_template));
+		btv->i2c_algo.udelay = i2c_udelay;
+		btv->i2c_algo.data = btv;
+		btv->c.i2c_adap.algo_data = &btv->i2c_algo;
+	}
+	btv->c.i2c_adap.owner = THIS_MODULE;
+
+	btv->c.i2c_adap.dev.parent = &btv->c.pci->dev;
+	snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name),
+		 "bt%d #%d [%s]", btv->id, btv->c.nr,
+		 btv->use_i2c_hw ? "hw" : "sw");
+
+	i2c_set_adapdata(&btv->c.i2c_adap, &btv->c.v4l2_dev);
+	btv->i2c_client.adapter = &btv->c.i2c_adap;
+
+
+	if (btv->use_i2c_hw) {
+		btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap);
+	} else {
+		bttv_bit_setscl(btv,1);
+		bttv_bit_setsda(btv,1);
+		btv->i2c_rc = i2c_bit_add_bus(&btv->c.i2c_adap);
+	}
+	if (0 == btv->i2c_rc && i2c_scan)
+		do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client);
+
+	return btv->i2c_rc;
+}
diff --git a/drivers/media/pci/bt8xx/bttv-if.c b/drivers/media/pci/bt8xx/bttv-if.c
new file mode 100644
index 0000000..a6a540d
--- /dev/null
+++ b/drivers/media/pci/bt8xx/bttv-if.c
@@ -0,0 +1,121 @@
+/*
+
+    bttv-if.c  --  old gpio interface to other kernel modules
+		   don't use in new code, will go away in 2.7
+		   have a look at bttv-gpio.c instead.
+
+    bttv - Bt848 frame grabber driver
+
+    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+			   & Marcus Metzler (mocm@thp.uni-koeln.de)
+    (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include "bttvp.h"
+
+EXPORT_SYMBOL(bttv_get_pcidev);
+EXPORT_SYMBOL(bttv_gpio_enable);
+EXPORT_SYMBOL(bttv_read_gpio);
+EXPORT_SYMBOL(bttv_write_gpio);
+
+/* ----------------------------------------------------------------------- */
+/* Exported functions - for other modules which want to access the         */
+/*                      gpio ports (IR for example)                        */
+/*                      see bttv.h for comments                            */
+
+struct pci_dev* bttv_get_pcidev(unsigned int card)
+{
+	if (card >= bttv_num)
+		return NULL;
+	if (!bttvs[card])
+		return NULL;
+
+	return bttvs[card]->c.pci;
+}
+
+
+int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data)
+{
+	struct bttv *btv;
+
+	if (card >= bttv_num) {
+		return -EINVAL;
+	}
+
+	btv = bttvs[card];
+	if (!btv)
+		return -ENODEV;
+
+	gpio_inout(mask,data);
+	if (bttv_gpio)
+		bttv_gpio_tracking(btv,"extern enable");
+	return 0;
+}
+
+int bttv_read_gpio(unsigned int card, unsigned long *data)
+{
+	struct bttv *btv;
+
+	if (card >= bttv_num) {
+		return -EINVAL;
+	}
+
+	btv = bttvs[card];
+	if (!btv)
+		return -ENODEV;
+
+	if(btv->shutdown) {
+		return -ENODEV;
+	}
+
+/* prior setting BT848_GPIO_REG_INP is (probably) not needed
+   because we set direct input on init */
+	*data = gpio_read();
+	return 0;
+}
+
+int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data)
+{
+	struct bttv *btv;
+
+	if (card >= bttv_num) {
+		return -EINVAL;
+	}
+
+	btv = bttvs[card];
+	if (!btv)
+		return -ENODEV;
+
+/* prior setting BT848_GPIO_REG_INP is (probably) not needed
+   because direct input is set on init */
+	gpio_bits(mask,data);
+	if (bttv_gpio)
+		bttv_gpio_tracking(btv,"extern write");
+	return 0;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c
new file mode 100644
index 0000000..ef4c7cd
--- /dev/null
+++ b/drivers/media/pci/bt8xx/bttv-input.c
@@ -0,0 +1,589 @@
+/*
+ *
+ * Copyright (c) 2003 Gerd Knorr
+ * Copyright (c) 2003 Pavel Machek
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+
+#include "bttv.h"
+#include "bttvp.h"
+
+
+static int ir_debug;
+module_param(ir_debug, int, 0644);
+
+static int ir_rc5_remote_gap = 885;
+module_param(ir_rc5_remote_gap, int, 0644);
+
+#undef dprintk
+#define dprintk(fmt, ...)			\
+do {						\
+	if (ir_debug >= 1)			\
+		pr_info(fmt, ##__VA_ARGS__);	\
+} while (0)
+
+#define DEVNAME "bttv-input"
+
+#define MODULE_NAME "bttv"
+
+/* ---------------------------------------------------------------------- */
+
+static void ir_handle_key(struct bttv *btv)
+{
+	struct bttv_ir *ir = btv->remote;
+	u32 gpio,data;
+
+	/* read gpio value */
+	gpio = bttv_gpio_read(&btv->c);
+	if (ir->polling) {
+		if (ir->last_gpio == gpio)
+			return;
+		ir->last_gpio = gpio;
+	}
+
+	/* extract data */
+	data = ir_extract_bits(gpio, ir->mask_keycode);
+	dprintk("irq gpio=0x%x code=%d | %s%s%s\n",
+		gpio, data,
+		ir->polling               ? "poll"  : "irq",
+		(gpio & ir->mask_keydown) ? " down" : "",
+		(gpio & ir->mask_keyup)   ? " up"   : "");
+
+	if ((ir->mask_keydown && (gpio & ir->mask_keydown)) ||
+	    (ir->mask_keyup   && !(gpio & ir->mask_keyup))) {
+		rc_keydown_notimeout(ir->dev, data, 0);
+	} else {
+		/* HACK: Probably, ir->mask_keydown is missing
+		   for this board */
+		if (btv->c.type == BTTV_BOARD_WINFAST2000)
+			rc_keydown_notimeout(ir->dev, data, 0);
+
+		rc_keyup(ir->dev);
+	}
+}
+
+static void ir_enltv_handle_key(struct bttv *btv)
+{
+	struct bttv_ir *ir = btv->remote;
+	u32 gpio, data, keyup;
+
+	/* read gpio value */
+	gpio = bttv_gpio_read(&btv->c);
+
+	/* extract data */
+	data = ir_extract_bits(gpio, ir->mask_keycode);
+
+	/* Check if it is keyup */
+	keyup = (gpio & ir->mask_keyup) ? 1 << 31 : 0;
+
+	if ((ir->last_gpio & 0x7f) != data) {
+		dprintk("gpio=0x%x code=%d | %s\n",
+			gpio, data,
+			(gpio & ir->mask_keyup) ? " up" : "up/down");
+
+		rc_keydown_notimeout(ir->dev, data, 0);
+		if (keyup)
+			rc_keyup(ir->dev);
+	} else {
+		if ((ir->last_gpio & 1 << 31) == keyup)
+			return;
+
+		dprintk("(cnt) gpio=0x%x code=%d | %s\n",
+			gpio, data,
+			(gpio & ir->mask_keyup) ? " up" : "down");
+
+		if (keyup)
+			rc_keyup(ir->dev);
+		else
+			rc_keydown_notimeout(ir->dev, data, 0);
+	}
+
+	ir->last_gpio = data | keyup;
+}
+
+static int bttv_rc5_irq(struct bttv *btv);
+
+void bttv_input_irq(struct bttv *btv)
+{
+	struct bttv_ir *ir = btv->remote;
+
+	if (ir->rc5_gpio)
+		bttv_rc5_irq(btv);
+	else if (!ir->polling)
+		ir_handle_key(btv);
+}
+
+static void bttv_input_timer(unsigned long data)
+{
+	struct bttv *btv = (struct bttv*)data;
+	struct bttv_ir *ir = btv->remote;
+
+	if (btv->c.type == BTTV_BOARD_ENLTV_FM_2)
+		ir_enltv_handle_key(btv);
+	else
+		ir_handle_key(btv);
+	mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
+}
+
+/*
+ * FIXME: Nebula digi uses the legacy way to decode RC5, instead of relying
+ * on the rc-core way. As we need to be sure that both IRQ transitions are
+ * properly triggered, Better to touch it only with this hardware for
+ * testing.
+ */
+
+#define RC5_START(x)	(((x) >> 12) & 3)
+#define RC5_TOGGLE(x)	(((x) >> 11) & 1)
+#define RC5_ADDR(x)	(((x) >> 6) & 31)
+#define RC5_INSTR(x)	((x) & 63)
+
+/* decode raw bit pattern to RC5 code */
+static u32 bttv_rc5_decode(unsigned int code)
+{
+	unsigned int org_code = code;
+	unsigned int pair;
+	unsigned int rc5 = 0;
+	int i;
+
+	for (i = 0; i < 14; ++i) {
+		pair = code & 0x3;
+		code >>= 2;
+
+		rc5 <<= 1;
+		switch (pair) {
+		case 0:
+		case 2:
+			break;
+		case 1:
+			rc5 |= 1;
+		break;
+		case 3:
+			dprintk("rc5_decode(%x) bad code\n",
+				org_code);
+			return 0;
+		}
+	}
+	dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
+		"instr=%x\n", rc5, org_code, RC5_START(rc5),
+		RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
+	return rc5;
+}
+
+static void bttv_rc5_timer_end(unsigned long data)
+{
+	struct bttv_ir *ir = (struct bttv_ir *)data;
+	struct timeval tv;
+	u32 gap;
+	u32 rc5 = 0;
+
+	/* get time */
+	do_gettimeofday(&tv);
+
+	/* avoid overflow with gap >1s */
+	if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+		gap = 200000;
+	} else {
+		gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+		    tv.tv_usec - ir->base_time.tv_usec;
+	}
+
+	/* signal we're ready to start a new code */
+	ir->active = false;
+
+	/* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */
+	if (gap < 28000) {
+		dprintk("spurious timer_end\n");
+		return;
+	}
+
+	if (ir->last_bit < 20) {
+		/* ignore spurious codes (caused by light/other remotes) */
+		dprintk("short code: %x\n", ir->code);
+	} else {
+		ir->code = (ir->code << ir->shift_by) | 1;
+		rc5 = bttv_rc5_decode(ir->code);
+
+		/* two start bits? */
+		if (RC5_START(rc5) != ir->start) {
+			pr_info(DEVNAME ":"
+			       " rc5 start bits invalid: %u\n", RC5_START(rc5));
+
+			/* right address? */
+		} else if (RC5_ADDR(rc5) == ir->addr) {
+			u32 toggle = RC5_TOGGLE(rc5);
+			u32 instr = RC5_INSTR(rc5);
+
+			/* Good code */
+			rc_keydown(ir->dev, instr, toggle);
+			dprintk("instruction %x, toggle %x\n",
+				instr, toggle);
+		}
+	}
+}
+
+static int bttv_rc5_irq(struct bttv *btv)
+{
+	struct bttv_ir *ir = btv->remote;
+	struct timeval tv;
+	u32 gpio;
+	u32 gap;
+	unsigned long current_jiffies;
+
+	/* read gpio port */
+	gpio = bttv_gpio_read(&btv->c);
+
+	/* get time of bit */
+	current_jiffies = jiffies;
+	do_gettimeofday(&tv);
+
+	/* avoid overflow with gap >1s */
+	if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+		gap = 200000;
+	} else {
+		gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+		    tv.tv_usec - ir->base_time.tv_usec;
+	}
+
+	dprintk("RC5 IRQ: gap %d us for %s\n",
+		gap, (gpio & 0x20) ? "mark" : "space");
+
+	/* remote IRQ? */
+	if (!(gpio & 0x20))
+		return 0;
+
+	/* active code => add bit */
+	if (ir->active) {
+		/* only if in the code (otherwise spurious IRQ or timer
+		   late) */
+		if (ir->last_bit < 28) {
+			ir->last_bit = (gap - ir_rc5_remote_gap / 2) /
+			    ir_rc5_remote_gap;
+			ir->code |= 1 << ir->last_bit;
+		}
+		/* starting new code */
+	} else {
+		ir->active = true;
+		ir->code = 0;
+		ir->base_time = tv;
+		ir->last_bit = 0;
+
+		mod_timer(&ir->timer, current_jiffies + msecs_to_jiffies(30));
+	}
+
+	/* toggle GPIO pin 4 to reset the irq */
+	bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
+	bttv_gpio_write(&btv->c, gpio | (1 << 4));
+	return 1;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir)
+{
+	if (ir->polling) {
+		setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv);
+		ir->timer.expires  = jiffies + msecs_to_jiffies(1000);
+		add_timer(&ir->timer);
+	} else if (ir->rc5_gpio) {
+		/* set timer_end for code completion */
+		setup_timer(&ir->timer, bttv_rc5_timer_end, (unsigned long)ir);
+		ir->shift_by = 1;
+		ir->start = 3;
+		ir->addr = 0x0;
+		ir->rc5_remote_gap = ir_rc5_remote_gap;
+	}
+}
+
+static void bttv_ir_stop(struct bttv *btv)
+{
+	if (btv->remote->polling)
+		del_timer_sync(&btv->remote->timer);
+
+	if (btv->remote->rc5_gpio) {
+		u32 gpio;
+
+		del_timer_sync(&btv->remote->timer);
+
+		gpio = bttv_gpio_read(&btv->c);
+		bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
+	}
+}
+
+/*
+ * Get_key functions used by I2C remotes
+ */
+
+static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char b;
+
+	/* poll IR chip */
+	if (1 != i2c_master_recv(ir->c, &b, 1)) {
+		dprintk("read error\n");
+		return -EIO;
+	}
+
+	/* ignore 0xaa */
+	if (b==0xaa)
+		return 0;
+	dprintk("key %02x\n", b);
+
+	/*
+	 * NOTE:
+	 * lirc_i2c maps the pv951 code as:
+	 *	addr = 0x61D6
+	 * 	cmd = bit_reverse (b)
+	 * So, it seems that this device uses NEC extended
+	 * I decided to not fix the table, due to two reasons:
+	 * 	1) Without the actual device, this is only a guess;
+	 * 	2) As the addr is not reported via I2C, nor can be changed,
+	 * 	   the device is bound to the vendor-provided RC.
+	 */
+
+	*ir_key = b;
+	*ir_raw = b;
+	return 1;
+}
+
+/* Instantiate the I2C IR receiver device, if present */
+void __devinit init_bttv_i2c_ir(struct bttv *btv)
+{
+	const unsigned short addr_list[] = {
+		0x1a, 0x18, 0x64, 0x30, 0x71,
+		I2C_CLIENT_END
+	};
+	struct i2c_board_info info;
+
+	if (0 != btv->i2c_rc)
+		return;
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	memset(&btv->init_data, 0, sizeof(btv->init_data));
+	strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+
+	switch (btv->c.type) {
+	case BTTV_BOARD_PV951:
+		btv->init_data.name = "PV951";
+		btv->init_data.get_key = get_key_pv951;
+		btv->init_data.ir_codes = RC_MAP_PV951;
+		info.addr = 0x4b;
+		break;
+	default:
+		/*
+		 * The external IR receiver is at i2c address 0x34 (0x35 for
+		 * reads).  Future Hauppauge cards will have an internal
+		 * receiver at 0x30 (0x31 for reads).  In theory, both can be
+		 * fitted, and Hauppauge suggest an external overrides an
+		 * internal.
+		 * That's why we probe 0x1a (~0x34) first. CB
+		 */
+
+		i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL);
+		return;
+	}
+
+	if (btv->init_data.name)
+		info.platform_data = &btv->init_data;
+	i2c_new_device(&btv->c.i2c_adap, &info);
+
+	return;
+}
+
+int __devexit fini_bttv_i2c(struct bttv *btv)
+{
+	if (0 != btv->i2c_rc)
+		return 0;
+
+	return i2c_del_adapter(&btv->c.i2c_adap);
+}
+
+int bttv_input_init(struct bttv *btv)
+{
+	struct bttv_ir *ir;
+	char *ir_codes = NULL;
+	struct rc_dev *rc;
+	int err = -ENOMEM;
+
+	if (!btv->has_remote)
+		return -ENODEV;
+
+	ir = kzalloc(sizeof(*ir),GFP_KERNEL);
+	rc = rc_allocate_device();
+	if (!ir || !rc)
+		goto err_out_free;
+
+	/* detect & configure */
+	switch (btv->c.type) {
+	case BTTV_BOARD_AVERMEDIA:
+	case BTTV_BOARD_AVPHONE98:
+	case BTTV_BOARD_AVERMEDIA98:
+		ir_codes         = RC_MAP_AVERMEDIA;
+		ir->mask_keycode = 0xf88000;
+		ir->mask_keydown = 0x010000;
+		ir->polling      = 50; // ms
+		break;
+
+	case BTTV_BOARD_AVDVBT_761:
+	case BTTV_BOARD_AVDVBT_771:
+		ir_codes         = RC_MAP_AVERMEDIA_DVBT;
+		ir->mask_keycode = 0x0f00c0;
+		ir->mask_keydown = 0x000020;
+		ir->polling      = 50; // ms
+		break;
+
+	case BTTV_BOARD_PXELVWPLTVPAK:
+		ir_codes         = RC_MAP_PIXELVIEW;
+		ir->mask_keycode = 0x003e00;
+		ir->mask_keyup   = 0x010000;
+		ir->polling      = 50; // ms
+		break;
+	case BTTV_BOARD_PV_M4900:
+	case BTTV_BOARD_PV_BT878P_9B:
+	case BTTV_BOARD_PV_BT878P_PLUS:
+		ir_codes         = RC_MAP_PIXELVIEW;
+		ir->mask_keycode = 0x001f00;
+		ir->mask_keyup   = 0x008000;
+		ir->polling      = 50; // ms
+		break;
+
+	case BTTV_BOARD_WINFAST2000:
+		ir_codes         = RC_MAP_WINFAST;
+		ir->mask_keycode = 0x1f8;
+		break;
+	case BTTV_BOARD_MAGICTVIEW061:
+	case BTTV_BOARD_MAGICTVIEW063:
+		ir_codes         = RC_MAP_WINFAST;
+		ir->mask_keycode = 0x0008e000;
+		ir->mask_keydown = 0x00200000;
+		break;
+	case BTTV_BOARD_APAC_VIEWCOMP:
+		ir_codes         = RC_MAP_APAC_VIEWCOMP;
+		ir->mask_keycode = 0x001f00;
+		ir->mask_keyup   = 0x008000;
+		ir->polling      = 50; // ms
+		break;
+	case BTTV_BOARD_ASKEY_CPH03X:
+	case BTTV_BOARD_CONCEPTRONIC_CTVFMI2:
+	case BTTV_BOARD_CONTVFMI:
+		ir_codes         = RC_MAP_PIXELVIEW;
+		ir->mask_keycode = 0x001F00;
+		ir->mask_keyup   = 0x006000;
+		ir->polling      = 50; // ms
+		break;
+	case BTTV_BOARD_NEBULA_DIGITV:
+		ir_codes = RC_MAP_NEBULA;
+		ir->rc5_gpio = true;
+		break;
+	case BTTV_BOARD_MACHTV_MAGICTV:
+		ir_codes         = RC_MAP_APAC_VIEWCOMP;
+		ir->mask_keycode = 0x001F00;
+		ir->mask_keyup   = 0x004000;
+		ir->polling      = 50; /* ms */
+		break;
+	case BTTV_BOARD_KOZUMI_KTV_01C:
+		ir_codes         = RC_MAP_PCTV_SEDNA;
+		ir->mask_keycode = 0x001f00;
+		ir->mask_keyup   = 0x006000;
+		ir->polling      = 50; /* ms */
+		break;
+	case BTTV_BOARD_ENLTV_FM_2:
+		ir_codes         = RC_MAP_ENCORE_ENLTV2;
+		ir->mask_keycode = 0x00fd00;
+		ir->mask_keyup   = 0x000080;
+		ir->polling      = 1; /* ms */
+		ir->last_gpio    = ir_extract_bits(bttv_gpio_read(&btv->c),
+						   ir->mask_keycode);
+		break;
+	}
+	if (NULL == ir_codes) {
+		dprintk("Ooops: IR config error [card=%d]\n", btv->c.type);
+		err = -ENODEV;
+		goto err_out_free;
+	}
+
+	if (ir->rc5_gpio) {
+		u32 gpio;
+		/* enable remote irq */
+		bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4);
+		gpio = bttv_gpio_read(&btv->c);
+		bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
+		bttv_gpio_write(&btv->c, gpio | (1 << 4));
+	} else {
+		/* init hardware-specific stuff */
+		bttv_gpio_inout(&btv->c, ir->mask_keycode | ir->mask_keydown, 0);
+	}
+
+	/* init input device */
+	ir->dev = rc;
+
+	snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)",
+		 btv->c.type);
+	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
+		 pci_name(btv->c.pci));
+
+	rc->input_name = ir->name;
+	rc->input_phys = ir->phys;
+	rc->input_id.bustype = BUS_PCI;
+	rc->input_id.version = 1;
+	if (btv->c.pci->subsystem_vendor) {
+		rc->input_id.vendor  = btv->c.pci->subsystem_vendor;
+		rc->input_id.product = btv->c.pci->subsystem_device;
+	} else {
+		rc->input_id.vendor  = btv->c.pci->vendor;
+		rc->input_id.product = btv->c.pci->device;
+	}
+	rc->dev.parent = &btv->c.pci->dev;
+	rc->map_name = ir_codes;
+	rc->driver_name = MODULE_NAME;
+
+	btv->remote = ir;
+	bttv_ir_start(btv, ir);
+
+	/* all done */
+	err = rc_register_device(rc);
+	if (err)
+		goto err_out_stop;
+
+	return 0;
+
+ err_out_stop:
+	bttv_ir_stop(btv);
+	btv->remote = NULL;
+ err_out_free:
+	rc_free_device(rc);
+	kfree(ir);
+	return err;
+}
+
+void bttv_input_fini(struct bttv *btv)
+{
+	if (btv->remote == NULL)
+		return;
+
+	bttv_ir_stop(btv);
+	rc_unregister_device(btv->remote->dev);
+	kfree(btv->remote);
+	btv->remote = NULL;
+}
diff --git a/drivers/media/pci/bt8xx/bttv-risc.c b/drivers/media/pci/bt8xx/bttv-risc.c
new file mode 100644
index 0000000..82cc47d
--- /dev/null
+++ b/drivers/media/pci/bt8xx/bttv-risc.c
@@ -0,0 +1,909 @@
+/*
+
+    bttv-risc.c  --  interfaces to other kernel modules
+
+    bttv risc code handling
+	- memory management
+	- generation
+
+    (c) 2000-2003 Gerd Knorr <kraxel@bytesex.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <media/v4l2-ioctl.h>
+
+#include "bttvp.h"
+
+#define VCR_HACK_LINES 4
+
+/* ---------------------------------------------------------- */
+/* risc code generators                                       */
+
+int
+bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
+		 struct scatterlist *sglist,
+		 unsigned int offset, unsigned int bpl,
+		 unsigned int padding, unsigned int skip_lines,
+		 unsigned int store_lines)
+{
+	u32 instructions,line,todo;
+	struct scatterlist *sg;
+	__le32 *rp;
+	int rc;
+
+	/* estimate risc mem: worst case is one write per page border +
+	   one write per scan line + sync + jump (all 2 dwords).  padding
+	   can cause next bpl to start close to a page border.  First DMA
+	   region may be smaller than PAGE_SIZE */
+	instructions  = skip_lines * 4;
+	instructions += (1 + ((bpl + padding) * store_lines)
+			 / PAGE_SIZE + store_lines) * 8;
+	instructions += 2 * 8;
+	if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0)
+		return rc;
+
+	/* sync instruction */
+	rp = risc->cpu;
+	*(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
+	*(rp++) = cpu_to_le32(0);
+
+	while (skip_lines-- > 0) {
+		*(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL |
+				      BT848_RISC_EOL | bpl);
+	}
+
+	/* scan lines */
+	sg = sglist;
+	for (line = 0; line < store_lines; line++) {
+		if ((btv->opt_vcr_hack) &&
+		    (line >= (store_lines - VCR_HACK_LINES)))
+			continue;
+		while (offset && offset >= sg_dma_len(sg)) {
+			offset -= sg_dma_len(sg);
+			sg++;
+		}
+		if (bpl <= sg_dma_len(sg)-offset) {
+			/* fits into current chunk */
+			*(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
+					    BT848_RISC_EOL|bpl);
+			*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+			offset+=bpl;
+		} else {
+			/* scanline needs to be splitted */
+			todo = bpl;
+			*(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
+					    (sg_dma_len(sg)-offset));
+			*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+			todo -= (sg_dma_len(sg)-offset);
+			offset = 0;
+			sg++;
+			while (todo > sg_dma_len(sg)) {
+				*(rp++)=cpu_to_le32(BT848_RISC_WRITE|
+						    sg_dma_len(sg));
+				*(rp++)=cpu_to_le32(sg_dma_address(sg));
+				todo -= sg_dma_len(sg);
+				sg++;
+			}
+			*(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
+					    todo);
+			*(rp++)=cpu_to_le32(sg_dma_address(sg));
+			offset += todo;
+		}
+		offset += padding;
+	}
+
+	/* save pointer to jmp instruction address */
+	risc->jmp = rp;
+	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
+	return 0;
+}
+
+static int
+bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
+		 struct scatterlist *sglist,
+		 unsigned int yoffset,  unsigned int ybpl,
+		 unsigned int ypadding, unsigned int ylines,
+		 unsigned int uoffset,  unsigned int voffset,
+		 unsigned int hshift,   unsigned int vshift,
+		 unsigned int cpadding)
+{
+	unsigned int instructions,line,todo,ylen,chroma;
+	__le32 *rp;
+	u32 ri;
+	struct scatterlist *ysg;
+	struct scatterlist *usg;
+	struct scatterlist *vsg;
+	int topfield = (0 == yoffset);
+	int rc;
+
+	/* estimate risc mem: worst case is one write per page border +
+	   one write per scan line (5 dwords)
+	   plus sync + jump (2 dwords) */
+	instructions  = ((3 + (ybpl + ypadding) * ylines * 2)
+			 / PAGE_SIZE) + ylines;
+	instructions += 2;
+	if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
+		return rc;
+
+	/* sync instruction */
+	rp = risc->cpu;
+	*(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);
+	*(rp++) = cpu_to_le32(0);
+
+	/* scan lines */
+	ysg = sglist;
+	usg = sglist;
+	vsg = sglist;
+	for (line = 0; line < ylines; line++) {
+		if ((btv->opt_vcr_hack) &&
+		    (line >= (ylines - VCR_HACK_LINES)))
+			continue;
+		switch (vshift) {
+		case 0:
+			chroma = 1;
+			break;
+		case 1:
+			if (topfield)
+				chroma = ((line & 1) == 0);
+			else
+				chroma = ((line & 1) == 1);
+			break;
+		case 2:
+			if (topfield)
+				chroma = ((line & 3) == 0);
+			else
+				chroma = ((line & 3) == 2);
+			break;
+		default:
+			chroma = 0;
+			break;
+		}
+
+		for (todo = ybpl; todo > 0; todo -= ylen) {
+			/* go to next sg entry if needed */
+			while (yoffset && yoffset >= sg_dma_len(ysg)) {
+				yoffset -= sg_dma_len(ysg);
+				ysg++;
+			}
+			while (uoffset && uoffset >= sg_dma_len(usg)) {
+				uoffset -= sg_dma_len(usg);
+				usg++;
+			}
+			while (voffset && voffset >= sg_dma_len(vsg)) {
+				voffset -= sg_dma_len(vsg);
+				vsg++;
+			}
+
+			/* calculate max number of bytes we can write */
+			ylen = todo;
+			if (yoffset + ylen > sg_dma_len(ysg))
+				ylen = sg_dma_len(ysg) - yoffset;
+			if (chroma) {
+				if (uoffset + (ylen>>hshift) > sg_dma_len(usg))
+					ylen = (sg_dma_len(usg) - uoffset) << hshift;
+				if (voffset + (ylen>>hshift) > sg_dma_len(vsg))
+					ylen = (sg_dma_len(vsg) - voffset) << hshift;
+				ri = BT848_RISC_WRITE123;
+			} else {
+				ri = BT848_RISC_WRITE1S23;
+			}
+			if (ybpl == todo)
+				ri |= BT848_RISC_SOL;
+			if (ylen == todo)
+				ri |= BT848_RISC_EOL;
+
+			/* write risc instruction */
+			*(rp++)=cpu_to_le32(ri | ylen);
+			*(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
+					    (ylen >> hshift));
+			*(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset);
+			yoffset += ylen;
+			if (chroma) {
+				*(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset);
+				uoffset += ylen >> hshift;
+				*(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset);
+				voffset += ylen >> hshift;
+			}
+		}
+		yoffset += ypadding;
+		if (chroma) {
+			uoffset += cpadding;
+			voffset += cpadding;
+		}
+	}
+
+	/* save pointer to jmp instruction address */
+	risc->jmp = rp;
+	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
+	return 0;
+}
+
+static int
+bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
+		  const struct bttv_format *fmt, struct bttv_overlay *ov,
+		  int skip_even, int skip_odd)
+{
+	int dwords, rc, line, maxy, start, end;
+	unsigned skip, nskips;
+	struct btcx_skiplist *skips;
+	__le32 *rp;
+	u32 ri,ra;
+	u32 addr;
+
+	/* skip list for window clipping */
+	if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL)))
+		return -ENOMEM;
+
+	/* estimate risc mem: worst case is (1.5*clip+1) * lines instructions
+	   + sync + jump (all 2 dwords) */
+	dwords  = (3 * ov->nclips + 2) *
+		((skip_even || skip_odd) ? (ov->w.height+1)>>1 :  ov->w.height);
+	dwords += 4;
+	if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,dwords*4)) < 0) {
+		kfree(skips);
+		return rc;
+	}
+
+	/* sync instruction */
+	rp = risc->cpu;
+	*(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
+	*(rp++) = cpu_to_le32(0);
+
+	addr  = (unsigned long)btv->fbuf.base;
+	addr += btv->fbuf.fmt.bytesperline * ov->w.top;
+	addr += (fmt->depth >> 3)          * ov->w.left;
+
+	/* scan lines */
+	for (maxy = -1, line = 0; line < ov->w.height;
+	     line++, addr += btv->fbuf.fmt.bytesperline) {
+		if ((btv->opt_vcr_hack) &&
+		     (line >= (ov->w.height - VCR_HACK_LINES)))
+			continue;
+		if ((line%2) == 0  &&  skip_even)
+			continue;
+		if ((line%2) == 1  &&  skip_odd)
+			continue;
+
+		/* calculate clipping */
+		if (line > maxy)
+			btcx_calc_skips(line, ov->w.width, &maxy,
+					skips, &nskips, ov->clips, ov->nclips);
+
+		/* write out risc code */
+		for (start = 0, skip = 0; start < ov->w.width; start = end) {
+			if (skip >= nskips) {
+				ri  = BT848_RISC_WRITE;
+				end = ov->w.width;
+			} else if (start < skips[skip].start) {
+				ri  = BT848_RISC_WRITE;
+				end = skips[skip].start;
+			} else {
+				ri  = BT848_RISC_SKIP;
+				end = skips[skip].end;
+				skip++;
+			}
+			if (BT848_RISC_WRITE == ri)
+				ra = addr + (fmt->depth>>3)*start;
+			else
+				ra = 0;
+
+			if (0 == start)
+				ri |= BT848_RISC_SOL;
+			if (ov->w.width == end)
+				ri |= BT848_RISC_EOL;
+			ri |= (fmt->depth>>3) * (end-start);
+
+			*(rp++)=cpu_to_le32(ri);
+			if (0 != ra)
+				*(rp++)=cpu_to_le32(ra);
+		}
+	}
+
+	/* save pointer to jmp instruction address */
+	risc->jmp = rp;
+	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
+	kfree(skips);
+	return 0;
+}
+
+/* ---------------------------------------------------------- */
+
+static void
+bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,
+		  int width, int height, int interleaved,
+		  const struct bttv_tvnorm *tvnorm)
+{
+	u32 xsf, sr;
+	int vdelay;
+
+	int swidth       = tvnorm->swidth;
+	int totalwidth   = tvnorm->totalwidth;
+	int scaledtwidth = tvnorm->scaledtwidth;
+
+	if (btv->input == btv->dig) {
+		swidth       = 720;
+		totalwidth   = 858;
+		scaledtwidth = 858;
+	}
+
+	vdelay = tvnorm->vdelay;
+
+	xsf = (width*scaledtwidth)/swidth;
+	geo->hscale =  ((totalwidth*4096UL)/xsf-4096);
+	geo->hdelay =  tvnorm->hdelayx1;
+	geo->hdelay =  (geo->hdelay*width)/swidth;
+	geo->hdelay &= 0x3fe;
+	sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
+	geo->vscale =  (0x10000UL-sr) & 0x1fff;
+	geo->crop   =  ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
+		((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
+	geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
+	geo->vdelay  =  vdelay;
+	geo->width   =  width;
+	geo->sheight =  tvnorm->sheight;
+	geo->vtotal  =  tvnorm->vtotal;
+
+	if (btv->opt_combfilter) {
+		geo->vtc  = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
+		geo->comb = (width < 769) ? 1 : 0;
+	} else {
+		geo->vtc  = 0;
+		geo->comb = 0;
+	}
+}
+
+static void
+bttv_calc_geo		(struct bttv *                  btv,
+			 struct bttv_geometry *         geo,
+			 unsigned int                   width,
+			 unsigned int                   height,
+			 int                            both_fields,
+			 const struct bttv_tvnorm *     tvnorm,
+			 const struct v4l2_rect *       crop)
+{
+	unsigned int c_width;
+	unsigned int c_height;
+	u32 sr;
+
+	if ((crop->left == tvnorm->cropcap.defrect.left
+	     && crop->top == tvnorm->cropcap.defrect.top
+	     && crop->width == tvnorm->cropcap.defrect.width
+	     && crop->height == tvnorm->cropcap.defrect.height
+	     && width <= tvnorm->swidth /* see PAL-Nc et al */)
+	    || btv->input == btv->dig) {
+		bttv_calc_geo_old(btv, geo, width, height,
+				  both_fields, tvnorm);
+		return;
+	}
+
+	/* For bug compatibility the image size checks permit scale
+	   factors > 16. See bttv_crop_calc_limits(). */
+	c_width = min((unsigned int) crop->width, width * 16);
+	c_height = min((unsigned int) crop->height, height * 16);
+
+	geo->width = width;
+	geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096;
+	/* Even to store Cb first, odd for Cr. */
+	geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1;
+
+	geo->sheight = c_height;
+	geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY;
+	sr = c_height >> !both_fields;
+	sr = (sr * 512U + (height >> 1)) / height - 512;
+	geo->vscale = (0x10000UL - sr) & 0x1fff;
+	geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0;
+	geo->vtotal = tvnorm->vtotal;
+
+	geo->crop = (((geo->width   >> 8) & 0x03) |
+		     ((geo->hdelay  >> 6) & 0x0c) |
+		     ((geo->sheight >> 4) & 0x30) |
+		     ((geo->vdelay  >> 2) & 0xc0));
+
+	if (btv->opt_combfilter) {
+		geo->vtc  = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
+		geo->comb = (width < 769) ? 1 : 0;
+	} else {
+		geo->vtc  = 0;
+		geo->comb = 0;
+	}
+}
+
+static void
+bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
+{
+	int off = odd ? 0x80 : 0x00;
+
+	if (geo->comb)
+		btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
+	else
+		btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
+
+	btwrite(geo->vtc,             BT848_E_VTC+off);
+	btwrite(geo->hscale >> 8,     BT848_E_HSCALE_HI+off);
+	btwrite(geo->hscale & 0xff,   BT848_E_HSCALE_LO+off);
+	btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
+	btwrite(geo->vscale & 0xff,   BT848_E_VSCALE_LO+off);
+	btwrite(geo->width & 0xff,    BT848_E_HACTIVE_LO+off);
+	btwrite(geo->hdelay & 0xff,   BT848_E_HDELAY_LO+off);
+	btwrite(geo->sheight & 0xff,  BT848_E_VACTIVE_LO+off);
+	btwrite(geo->vdelay & 0xff,   BT848_E_VDELAY_LO+off);
+	btwrite(geo->crop,            BT848_E_CROP+off);
+	btwrite(geo->vtotal>>8,       BT848_VTOTAL_HI);
+	btwrite(geo->vtotal & 0xff,   BT848_VTOTAL_LO);
+}
+
+/* ---------------------------------------------------------- */
+/* risc group / risc main loop / dma management               */
+
+void
+bttv_set_dma(struct bttv *btv, int override)
+{
+	unsigned long cmd;
+	int capctl;
+
+	btv->cap_ctl = 0;
+	if (NULL != btv->curr.top)      btv->cap_ctl |= 0x02;
+	if (NULL != btv->curr.bottom)   btv->cap_ctl |= 0x01;
+	if (NULL != btv->cvbi)          btv->cap_ctl |= 0x0c;
+
+	capctl  = 0;
+	capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00;  /* capture  */
+	capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00;  /* vbi data */
+	capctl |= override;
+
+	d2printk("%d: capctl=%x lirq=%d top=%08llx/%08llx even=%08llx/%08llx\n",
+		 btv->c.nr,capctl,btv->loop_irq,
+		 btv->cvbi         ? (unsigned long long)btv->cvbi->top.dma            : 0,
+		 btv->curr.top     ? (unsigned long long)btv->curr.top->top.dma        : 0,
+		 btv->cvbi         ? (unsigned long long)btv->cvbi->bottom.dma         : 0,
+		 btv->curr.bottom  ? (unsigned long long)btv->curr.bottom->bottom.dma  : 0);
+
+	cmd = BT848_RISC_JUMP;
+	if (btv->loop_irq) {
+		cmd |= BT848_RISC_IRQ;
+		cmd |= (btv->loop_irq  & 0x0f) << 16;
+		cmd |= (~btv->loop_irq & 0x0f) << 20;
+	}
+	if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) {
+		mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT);
+	} else {
+		del_timer(&btv->timeout);
+	}
+	btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
+
+	btaor(capctl, ~0x0f, BT848_CAP_CTL);
+	if (capctl) {
+		if (btv->dma_on)
+			return;
+		btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
+		btor(3, BT848_GPIO_DMA_CTL);
+		btv->dma_on = 1;
+	} else {
+		if (!btv->dma_on)
+			return;
+		btand(~3, BT848_GPIO_DMA_CTL);
+		btv->dma_on = 0;
+	}
+	return;
+}
+
+int
+bttv_risc_init_main(struct bttv *btv)
+{
+	int rc;
+
+	if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0)
+		return rc;
+	dprintk("%d: risc main @ %08llx\n",
+		btv->c.nr, (unsigned long long)btv->main.dma);
+
+	btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
+				       BT848_FIFO_STATUS_VRE);
+	btv->main.cpu[1] = cpu_to_le32(0);
+	btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP);
+	btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2));
+
+	/* top field */
+	btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP);
+	btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2));
+	btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
+	btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));
+
+	btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
+				       BT848_FIFO_STATUS_VRO);
+	btv->main.cpu[9] = cpu_to_le32(0);
+
+	/* bottom field */
+	btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
+	btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));
+	btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
+	btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
+
+	/* jump back to top field */
+	btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
+	btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
+
+	return 0;
+}
+
+int
+bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
+	       int irqflags)
+{
+	unsigned long cmd;
+	unsigned long next = btv->main.dma + ((slot+2) << 2);
+
+	if (NULL == risc) {
+		d2printk("%d: risc=%p slot[%d]=NULL\n", btv->c.nr, risc, slot);
+		btv->main.cpu[slot+1] = cpu_to_le32(next);
+	} else {
+		d2printk("%d: risc=%p slot[%d]=%08llx irq=%d\n",
+			 btv->c.nr, risc, slot,
+			 (unsigned long long)risc->dma, irqflags);
+		cmd = BT848_RISC_JUMP;
+		if (irqflags) {
+			cmd |= BT848_RISC_IRQ;
+			cmd |= (irqflags  & 0x0f) << 16;
+			cmd |= (~irqflags & 0x0f) << 20;
+		}
+		risc->jmp[0] = cpu_to_le32(cmd);
+		risc->jmp[1] = cpu_to_le32(next);
+		btv->main.cpu[slot+1] = cpu_to_le32(risc->dma);
+	}
+	return 0;
+}
+
+void
+bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf)
+{
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
+	BUG_ON(in_interrupt());
+	videobuf_waiton(q, &buf->vb, 0, 0);
+	videobuf_dma_unmap(q->dev, dma);
+	videobuf_dma_free(dma);
+	btcx_riscmem_free(btv->c.pci,&buf->bottom);
+	btcx_riscmem_free(btv->c.pci,&buf->top);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+int
+bttv_buffer_activate_vbi(struct bttv *btv,
+			 struct bttv_buffer *vbi)
+{
+	struct btcx_riscmem *top;
+	struct btcx_riscmem *bottom;
+	int top_irq_flags;
+	int bottom_irq_flags;
+
+	top = NULL;
+	bottom = NULL;
+	top_irq_flags = 0;
+	bottom_irq_flags = 0;
+
+	if (vbi) {
+		unsigned int crop, vdelay;
+
+		vbi->vb.state = VIDEOBUF_ACTIVE;
+		list_del(&vbi->vb.queue);
+
+		/* VDELAY is start of video, end of VBI capturing. */
+		crop = btread(BT848_E_CROP);
+		vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2);
+
+		if (vbi->geo.vdelay > vdelay) {
+			vdelay = vbi->geo.vdelay & 0xfe;
+			crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0);
+
+			btwrite(vdelay, BT848_E_VDELAY_LO);
+			btwrite(crop,	BT848_E_CROP);
+			btwrite(vdelay, BT848_O_VDELAY_LO);
+			btwrite(crop,	BT848_O_CROP);
+		}
+
+		if (vbi->vbi_count[0] > 0) {
+			top = &vbi->top;
+			top_irq_flags = 4;
+		}
+
+		if (vbi->vbi_count[1] > 0) {
+			top_irq_flags = 0;
+			bottom = &vbi->bottom;
+			bottom_irq_flags = 4;
+		}
+	}
+
+	bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags);
+	bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags);
+
+	return 0;
+}
+
+int
+bttv_buffer_activate_video(struct bttv *btv,
+			   struct bttv_buffer_set *set)
+{
+	/* video capture */
+	if (NULL != set->top  &&  NULL != set->bottom) {
+		if (set->top == set->bottom) {
+			set->top->vb.state    = VIDEOBUF_ACTIVE;
+			if (set->top->vb.queue.next)
+				list_del(&set->top->vb.queue);
+		} else {
+			set->top->vb.state    = VIDEOBUF_ACTIVE;
+			set->bottom->vb.state = VIDEOBUF_ACTIVE;
+			if (set->top->vb.queue.next)
+				list_del(&set->top->vb.queue);
+			if (set->bottom->vb.queue.next)
+				list_del(&set->bottom->vb.queue);
+		}
+		bttv_apply_geo(btv, &set->top->geo, 1);
+		bttv_apply_geo(btv, &set->bottom->geo,0);
+		bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
+			       set->top_irq);
+		bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
+			       set->frame_irq);
+		btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f),
+		      ~0xff, BT848_COLOR_FMT);
+		btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
+		      ~0x0f, BT848_COLOR_CTL);
+	} else if (NULL != set->top) {
+		set->top->vb.state  = VIDEOBUF_ACTIVE;
+		if (set->top->vb.queue.next)
+			list_del(&set->top->vb.queue);
+		bttv_apply_geo(btv, &set->top->geo,1);
+		bttv_apply_geo(btv, &set->top->geo,0);
+		bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
+			       set->frame_irq);
+		bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL,           0);
+		btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
+		btaor(set->top->btswap & 0x0f,   ~0x0f, BT848_COLOR_CTL);
+	} else if (NULL != set->bottom) {
+		set->bottom->vb.state = VIDEOBUF_ACTIVE;
+		if (set->bottom->vb.queue.next)
+			list_del(&set->bottom->vb.queue);
+		bttv_apply_geo(btv, &set->bottom->geo,1);
+		bttv_apply_geo(btv, &set->bottom->geo,0);
+		bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
+		bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
+			       set->frame_irq);
+		btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
+		btaor(set->bottom->btswap & 0x0f,   ~0x0f, BT848_COLOR_CTL);
+	} else {
+		bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
+		bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
+	}
+	return 0;
+}
+
+/* ---------------------------------------------------------- */
+
+/* calculate geometry, build risc code */
+int
+bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
+{
+	const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
+	dprintk("%d: buffer field: %s  format: %s  size: %dx%d\n",
+		btv->c.nr, v4l2_field_names[buf->vb.field],
+		buf->fmt->name, buf->vb.width, buf->vb.height);
+
+	/* packed pixel modes */
+	if (buf->fmt->flags & FORMAT_FLAGS_PACKED) {
+		int bpl = (buf->fmt->depth >> 3) * buf->vb.width;
+		int bpf = bpl * (buf->vb.height >> 1);
+
+		bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
+			      V4L2_FIELD_HAS_BOTH(buf->vb.field),
+			      tvnorm,&buf->crop);
+
+		switch (buf->vb.field) {
+		case V4L2_FIELD_TOP:
+			bttv_risc_packed(btv,&buf->top,dma->sglist,
+					 /* offset */ 0,bpl,
+					 /* padding */ 0,/* skip_lines */ 0,
+					 buf->vb.height);
+			break;
+		case V4L2_FIELD_BOTTOM:
+			bttv_risc_packed(btv,&buf->bottom,dma->sglist,
+					 0,bpl,0,0,buf->vb.height);
+			break;
+		case V4L2_FIELD_INTERLACED:
+			bttv_risc_packed(btv,&buf->top,dma->sglist,
+					 0,bpl,bpl,0,buf->vb.height >> 1);
+			bttv_risc_packed(btv,&buf->bottom,dma->sglist,
+					 bpl,bpl,bpl,0,buf->vb.height >> 1);
+			break;
+		case V4L2_FIELD_SEQ_TB:
+			bttv_risc_packed(btv,&buf->top,dma->sglist,
+					 0,bpl,0,0,buf->vb.height >> 1);
+			bttv_risc_packed(btv,&buf->bottom,dma->sglist,
+					 bpf,bpl,0,0,buf->vb.height >> 1);
+			break;
+		default:
+			BUG();
+		}
+	}
+
+	/* planar modes */
+	if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) {
+		int uoffset, voffset;
+		int ypadding, cpadding, lines;
+
+		/* calculate chroma offsets */
+		uoffset = buf->vb.width * buf->vb.height;
+		voffset = buf->vb.width * buf->vb.height;
+		if (buf->fmt->flags & FORMAT_FLAGS_CrCb) {
+			/* Y-Cr-Cb plane order */
+			uoffset >>= buf->fmt->hshift;
+			uoffset >>= buf->fmt->vshift;
+			uoffset  += voffset;
+		} else {
+			/* Y-Cb-Cr plane order */
+			voffset >>= buf->fmt->hshift;
+			voffset >>= buf->fmt->vshift;
+			voffset  += uoffset;
+		}
+
+		switch (buf->vb.field) {
+		case V4L2_FIELD_TOP:
+			bttv_calc_geo(btv,&buf->geo,buf->vb.width,
+				      buf->vb.height,/* both_fields */ 0,
+				      tvnorm,&buf->crop);
+			bttv_risc_planar(btv, &buf->top, dma->sglist,
+					 0,buf->vb.width,0,buf->vb.height,
+					 uoffset,voffset,buf->fmt->hshift,
+					 buf->fmt->vshift,0);
+			break;
+		case V4L2_FIELD_BOTTOM:
+			bttv_calc_geo(btv,&buf->geo,buf->vb.width,
+				      buf->vb.height,0,
+				      tvnorm,&buf->crop);
+			bttv_risc_planar(btv, &buf->bottom, dma->sglist,
+					 0,buf->vb.width,0,buf->vb.height,
+					 uoffset,voffset,buf->fmt->hshift,
+					 buf->fmt->vshift,0);
+			break;
+		case V4L2_FIELD_INTERLACED:
+			bttv_calc_geo(btv,&buf->geo,buf->vb.width,
+				      buf->vb.height,1,
+				      tvnorm,&buf->crop);
+			lines    = buf->vb.height >> 1;
+			ypadding = buf->vb.width;
+			cpadding = buf->vb.width >> buf->fmt->hshift;
+			bttv_risc_planar(btv,&buf->top,
+					 dma->sglist,
+					 0,buf->vb.width,ypadding,lines,
+					 uoffset,voffset,
+					 buf->fmt->hshift,
+					 buf->fmt->vshift,
+					 cpadding);
+			bttv_risc_planar(btv,&buf->bottom,
+					 dma->sglist,
+					 ypadding,buf->vb.width,ypadding,lines,
+					 uoffset+cpadding,
+					 voffset+cpadding,
+					 buf->fmt->hshift,
+					 buf->fmt->vshift,
+					 cpadding);
+			break;
+		case V4L2_FIELD_SEQ_TB:
+			bttv_calc_geo(btv,&buf->geo,buf->vb.width,
+				      buf->vb.height,1,
+				      tvnorm,&buf->crop);
+			lines    = buf->vb.height >> 1;
+			ypadding = buf->vb.width;
+			cpadding = buf->vb.width >> buf->fmt->hshift;
+			bttv_risc_planar(btv,&buf->top,
+					 dma->sglist,
+					 0,buf->vb.width,0,lines,
+					 uoffset >> 1,
+					 voffset >> 1,
+					 buf->fmt->hshift,
+					 buf->fmt->vshift,
+					 0);
+			bttv_risc_planar(btv,&buf->bottom,
+					 dma->sglist,
+					 lines * ypadding,buf->vb.width,0,lines,
+					 lines * ypadding + (uoffset >> 1),
+					 lines * ypadding + (voffset >> 1),
+					 buf->fmt->hshift,
+					 buf->fmt->vshift,
+					 0);
+			break;
+		default:
+			BUG();
+		}
+	}
+
+	/* raw data */
+	if (buf->fmt->flags & FORMAT_FLAGS_RAW) {
+		/* build risc code */
+		buf->vb.field = V4L2_FIELD_SEQ_TB;
+		bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
+			      1,tvnorm,&buf->crop);
+		bttv_risc_packed(btv, &buf->top,  dma->sglist,
+				 /* offset */ 0, RAW_BPL, /* padding */ 0,
+				 /* skip_lines */ 0, RAW_LINES);
+		bttv_risc_packed(btv, &buf->bottom, dma->sglist,
+				 buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
+	}
+
+	/* copy format info */
+	buf->btformat = buf->fmt->btformat;
+	buf->btswap   = buf->fmt->btswap;
+	return 0;
+}
+
+/* ---------------------------------------------------------- */
+
+/* calculate geometry, build risc code */
+int
+bttv_overlay_risc(struct bttv *btv,
+		  struct bttv_overlay *ov,
+		  const struct bttv_format *fmt,
+		  struct bttv_buffer *buf)
+{
+	/* check interleave, bottom+top fields */
+	dprintk("%d: overlay fields: %s format: %s  size: %dx%d\n",
+		btv->c.nr, v4l2_field_names[buf->vb.field],
+		fmt->name, ov->w.width, ov->w.height);
+
+	/* calculate geometry */
+	bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
+		      V4L2_FIELD_HAS_BOTH(ov->field),
+		      &bttv_tvnorms[ov->tvnorm],&buf->crop);
+
+	/* build risc code */
+	switch (ov->field) {
+	case V4L2_FIELD_TOP:
+		bttv_risc_overlay(btv, &buf->top,    fmt, ov, 0, 0);
+		break;
+	case V4L2_FIELD_BOTTOM:
+		bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0);
+		break;
+	case V4L2_FIELD_INTERLACED:
+		bttv_risc_overlay(btv, &buf->top,    fmt, ov, 0, 1);
+		bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0);
+		break;
+	default:
+		BUG();
+	}
+
+	/* copy format info */
+	buf->btformat = fmt->btformat;
+	buf->btswap   = fmt->btswap;
+	buf->vb.field = ov->field;
+	return 0;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/bt8xx/bttv-vbi.c b/drivers/media/pci/bt8xx/bttv-vbi.c
new file mode 100644
index 0000000..b433267
--- /dev/null
+++ b/drivers/media/pci/bt8xx/bttv-vbi.c
@@ -0,0 +1,459 @@
+/*
+
+    bttv - Bt848 frame grabber driver
+    vbi interface
+
+    (c) 2002 Gerd Knorr <kraxel@bytesex.org>
+
+    Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
+    Sponsored by OPQ Systems AB
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/kdev_t.h>
+#include <media/v4l2-ioctl.h>
+#include <asm/io.h>
+#include "bttvp.h"
+
+/* Offset from line sync pulse leading edge (0H) to start of VBI capture,
+   in fCLKx2 pixels.  According to the datasheet, VBI capture starts
+   VBI_HDELAY fCLKx1 pixels from the tailing edgeof /HRESET, and /HRESET
+   is 64 fCLKx1 pixels wide.  VBI_HDELAY is set to 0, so this should be
+   (64 + 0) * 2 = 128 fCLKx2 pixels.  But it's not!  The datasheet is
+   Just Plain Wrong.  The real value appears to be different for
+   different revisions of the bt8x8 chips, and to be affected by the
+   horizontal scaling factor.  Experimentally, the value is measured
+   to be about 244.  */
+#define VBI_OFFSET 244
+
+/* 2048 for compatibility with earlier driver versions. The driver
+   really stores 1024 + tvnorm->vbipack * 4 samples per line in the
+   buffer. Note tvnorm->vbipack is <= 0xFF (limit of VBIPACK_LO + HI
+   is 0x1FF DWORDs) and VBI read()s store a frame counter in the last
+   four bytes of the VBI image. */
+#define VBI_BPL 2048
+
+/* Compatibility. */
+#define VBI_DEFLINES 16
+
+static unsigned int vbibufs = 4;
+static unsigned int vbi_debug;
+
+module_param(vbibufs,   int, 0444);
+module_param(vbi_debug, int, 0644);
+MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32, default 4");
+MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)");
+
+#ifdef dprintk
+# undef dprintk
+#endif
+#define dprintk(fmt, ...)						\
+do {									\
+	if (vbi_debug)							\
+		pr_debug("%d: " fmt, btv->c.nr, ##__VA_ARGS__);		\
+} while (0)
+
+#define IMAGE_SIZE(fmt) \
+	(((fmt)->count[0] + (fmt)->count[1]) * (fmt)->samples_per_line)
+
+/* ----------------------------------------------------------------------- */
+/* vbi risc code + mm                                                      */
+
+static int vbi_buffer_setup(struct videobuf_queue *q,
+			    unsigned int *count, unsigned int *size)
+{
+	struct bttv_fh *fh = q->priv_data;
+	struct bttv *btv = fh->btv;
+
+	if (0 == *count)
+		*count = vbibufs;
+
+	*size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
+
+	dprintk("setup: samples=%u start=%d,%d count=%u,%u\n",
+		fh->vbi_fmt.fmt.samples_per_line,
+		fh->vbi_fmt.fmt.start[0],
+		fh->vbi_fmt.fmt.start[1],
+		fh->vbi_fmt.fmt.count[0],
+		fh->vbi_fmt.fmt.count[1]);
+
+	return 0;
+}
+
+static int vbi_buffer_prepare(struct videobuf_queue *q,
+			      struct videobuf_buffer *vb,
+			      enum v4l2_field field)
+{
+	struct bttv_fh *fh = q->priv_data;
+	struct bttv *btv = fh->btv;
+	struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
+	const struct bttv_tvnorm *tvnorm;
+	unsigned int skip_lines0, skip_lines1, min_vdelay;
+	int redo_dma_risc;
+	int rc;
+
+	buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+		return -EINVAL;
+
+	tvnorm = fh->vbi_fmt.tvnorm;
+
+	/* There's no VBI_VDELAY register, RISC must skip the lines
+	   we don't want. With default parameters we skip zero lines
+	   as earlier driver versions did. The driver permits video
+	   standard changes while capturing, so we use vbi_fmt.tvnorm
+	   instead of btv->tvnorm to skip zero lines after video
+	   standard changes as well. */
+
+	skip_lines0 = 0;
+	skip_lines1 = 0;
+
+	if (fh->vbi_fmt.fmt.count[0] > 0)
+		skip_lines0 = max(0, (fh->vbi_fmt.fmt.start[0]
+				      - tvnorm->vbistart[0]));
+	if (fh->vbi_fmt.fmt.count[1] > 0)
+		skip_lines1 = max(0, (fh->vbi_fmt.fmt.start[1]
+				      - tvnorm->vbistart[1]));
+
+	redo_dma_risc = 0;
+
+	if (buf->vbi_skip[0] != skip_lines0 ||
+	    buf->vbi_skip[1] != skip_lines1 ||
+	    buf->vbi_count[0] != fh->vbi_fmt.fmt.count[0] ||
+	    buf->vbi_count[1] != fh->vbi_fmt.fmt.count[1]) {
+		buf->vbi_skip[0] = skip_lines0;
+		buf->vbi_skip[1] = skip_lines1;
+		buf->vbi_count[0] = fh->vbi_fmt.fmt.count[0];
+		buf->vbi_count[1] = fh->vbi_fmt.fmt.count[1];
+		redo_dma_risc = 1;
+	}
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		redo_dma_risc = 1;
+		if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
+			goto fail;
+	}
+
+	if (redo_dma_risc) {
+		unsigned int bpl, padding, offset;
+		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
+		bpl = 2044; /* max. vbipack */
+		padding = VBI_BPL - bpl;
+
+		if (fh->vbi_fmt.fmt.count[0] > 0) {
+			rc = bttv_risc_packed(btv, &buf->top,
+					      dma->sglist,
+					      /* offset */ 0, bpl,
+					      padding, skip_lines0,
+					      fh->vbi_fmt.fmt.count[0]);
+			if (0 != rc)
+				goto fail;
+		}
+
+		if (fh->vbi_fmt.fmt.count[1] > 0) {
+			offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL;
+
+			rc = bttv_risc_packed(btv, &buf->bottom,
+					      dma->sglist,
+					      offset, bpl,
+					      padding, skip_lines1,
+					      fh->vbi_fmt.fmt.count[1]);
+			if (0 != rc)
+				goto fail;
+		}
+	}
+
+	/* VBI capturing ends at VDELAY, start of video capturing,
+	   no matter where the RISC program ends. VDELAY minimum is 2,
+	   bounds.top is the corresponding first field line number
+	   times two. VDELAY counts half field lines. */
+	min_vdelay = MIN_VDELAY;
+	if (fh->vbi_fmt.end >= tvnorm->cropcap.bounds.top)
+		min_vdelay += fh->vbi_fmt.end - tvnorm->cropcap.bounds.top;
+
+	/* For bttv_buffer_activate_vbi(). */
+	buf->geo.vdelay = min_vdelay;
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	buf->vb.field = field;
+	dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
+		vb, &buf->top, &buf->bottom,
+		v4l2_field_names[buf->vb.field]);
+	return 0;
+
+ fail:
+	bttv_dma_free(q,btv,buf);
+	return rc;
+}
+
+static void
+vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct bttv_fh *fh = q->priv_data;
+	struct bttv *btv = fh->btv;
+	struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
+
+	dprintk("queue %p\n",vb);
+	buf->vb.state = VIDEOBUF_QUEUED;
+	list_add_tail(&buf->vb.queue,&btv->vcapture);
+	if (NULL == btv->cvbi) {
+		fh->btv->loop_irq |= 4;
+		bttv_set_dma(btv,0x0c);
+	}
+}
+
+static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct bttv_fh *fh = q->priv_data;
+	struct bttv *btv = fh->btv;
+	struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
+
+	dprintk("free %p\n",vb);
+	bttv_dma_free(q,fh->btv,buf);
+}
+
+struct videobuf_queue_ops bttv_vbi_qops = {
+	.buf_setup    = vbi_buffer_setup,
+	.buf_prepare  = vbi_buffer_prepare,
+	.buf_queue    = vbi_buffer_queue,
+	.buf_release  = vbi_buffer_release,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm,
+			__s32 crop_start)
+{
+	__s32 min_start, max_start, max_end, f2_offset;
+	unsigned int i;
+
+	/* For compatibility with earlier driver versions we must pretend
+	   the VBI and video capture window may overlap. In reality RISC
+	   magic aborts VBI capturing at the first line of video capturing,
+	   leaving the rest of the buffer unchanged, usually all zero.
+	   VBI capturing must always start before video capturing. >> 1
+	   because cropping counts field lines times two. */
+	min_start = tvnorm->vbistart[0];
+	max_start = (crop_start >> 1) - 1;
+	max_end = (tvnorm->cropcap.bounds.top
+		   + tvnorm->cropcap.bounds.height) >> 1;
+
+	if (min_start > max_start)
+		return -EBUSY;
+
+	BUG_ON(max_start >= max_end);
+
+	f->sampling_rate    = tvnorm->Fsc;
+	f->samples_per_line = VBI_BPL;
+	f->sample_format    = V4L2_PIX_FMT_GREY;
+	f->offset           = VBI_OFFSET;
+
+	f2_offset = tvnorm->vbistart[1] - tvnorm->vbistart[0];
+
+	for (i = 0; i < 2; ++i) {
+		if (0 == f->count[i]) {
+			/* No data from this field. We leave f->start[i]
+			   alone because VIDIOCSVBIFMT is w/o and EINVALs
+			   when a driver does not support exactly the
+			   requested parameters. */
+		} else {
+			s64 start, count;
+
+			start = clamp(f->start[i], min_start, max_start);
+			/* s64 to prevent overflow. */
+			count = (s64) f->start[i] + f->count[i] - start;
+			f->start[i] = start;
+			f->count[i] = clamp(count, (s64) 1,
+					    max_end - start);
+		}
+
+		min_start += f2_offset;
+		max_start += f2_offset;
+		max_end += f2_offset;
+	}
+
+	if (0 == (f->count[0] | f->count[1])) {
+		/* As in earlier driver versions. */
+		f->start[0] = tvnorm->vbistart[0];
+		f->start[1] = tvnorm->vbistart[1];
+		f->count[0] = 1;
+		f->count[1] = 1;
+	}
+
+	f->flags = 0;
+
+	f->reserved[0] = 0;
+	f->reserved[1] = 0;
+
+	return 0;
+}
+
+int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+	const struct bttv_tvnorm *tvnorm;
+	__s32 crop_start;
+
+	mutex_lock(&btv->lock);
+
+	tvnorm = &bttv_tvnorms[btv->tvnorm];
+	crop_start = btv->crop_start;
+
+	mutex_unlock(&btv->lock);
+
+	return try_fmt(&frt->fmt.vbi, tvnorm, crop_start);
+}
+
+
+int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+	const struct bttv_tvnorm *tvnorm;
+	__s32 start1, end;
+	int rc;
+
+	mutex_lock(&btv->lock);
+
+	rc = -EBUSY;
+	if (fh->resources & RESOURCE_VBI)
+		goto fail;
+
+	tvnorm = &bttv_tvnorms[btv->tvnorm];
+
+	rc = try_fmt(&frt->fmt.vbi, tvnorm, btv->crop_start);
+	if (0 != rc)
+		goto fail;
+
+	start1 = frt->fmt.vbi.start[1] - tvnorm->vbistart[1] +
+		tvnorm->vbistart[0];
+
+	/* First possible line of video capturing. Should be
+	   max(f->start[0] + f->count[0], start1 + f->count[1]) * 2
+	   when capturing both fields. But for compatibility we must
+	   pretend the VBI and video capture window may overlap,
+	   so end = start + 1, the lowest possible value, times two
+	   because vbi_fmt.end counts field lines times two. */
+	end = max(frt->fmt.vbi.start[0], start1) * 2 + 2;
+
+	mutex_lock(&fh->vbi.vb_lock);
+
+	fh->vbi_fmt.fmt    = frt->fmt.vbi;
+	fh->vbi_fmt.tvnorm = tvnorm;
+	fh->vbi_fmt.end    = end;
+
+	mutex_unlock(&fh->vbi.vb_lock);
+
+	rc = 0;
+
+ fail:
+	mutex_unlock(&btv->lock);
+
+	return rc;
+}
+
+
+int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
+{
+	struct bttv_fh *fh = f;
+	const struct bttv_tvnorm *tvnorm;
+
+	frt->fmt.vbi = fh->vbi_fmt.fmt;
+
+	tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
+
+	if (tvnorm != fh->vbi_fmt.tvnorm) {
+		__s32 max_end;
+		unsigned int i;
+
+		/* As in vbi_buffer_prepare() this imitates the
+		   behaviour of earlier driver versions after video
+		   standard changes, with default parameters anyway. */
+
+		max_end = (tvnorm->cropcap.bounds.top
+			   + tvnorm->cropcap.bounds.height) >> 1;
+
+		frt->fmt.vbi.sampling_rate = tvnorm->Fsc;
+
+		for (i = 0; i < 2; ++i) {
+			__s32 new_start;
+
+			new_start = frt->fmt.vbi.start[i]
+				+ tvnorm->vbistart[i]
+				- fh->vbi_fmt.tvnorm->vbistart[i];
+
+			frt->fmt.vbi.start[i] = min(new_start, max_end - 1);
+			frt->fmt.vbi.count[i] =
+				min((__s32) frt->fmt.vbi.count[i],
+					  max_end - frt->fmt.vbi.start[i]);
+
+			max_end += tvnorm->vbistart[1]
+				- tvnorm->vbistart[0];
+		}
+	}
+	return 0;
+}
+
+void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm)
+{
+	const struct bttv_tvnorm *tvnorm;
+	unsigned int real_samples_per_line;
+	unsigned int real_count;
+
+	tvnorm = &bttv_tvnorms[norm];
+
+	f->fmt.sampling_rate    = tvnorm->Fsc;
+	f->fmt.samples_per_line = VBI_BPL;
+	f->fmt.sample_format    = V4L2_PIX_FMT_GREY;
+	f->fmt.offset           = VBI_OFFSET;
+	f->fmt.start[0]		= tvnorm->vbistart[0];
+	f->fmt.start[1]		= tvnorm->vbistart[1];
+	f->fmt.count[0]		= VBI_DEFLINES;
+	f->fmt.count[1]		= VBI_DEFLINES;
+	f->fmt.flags            = 0;
+	f->fmt.reserved[0]      = 0;
+	f->fmt.reserved[1]      = 0;
+
+	/* For compatibility the buffer size must be 2 * VBI_DEFLINES *
+	   VBI_BPL regardless of the current video standard. */
+	real_samples_per_line   = 1024 + tvnorm->vbipack * 4;
+	real_count              = ((tvnorm->cropcap.defrect.top >> 1)
+				   - tvnorm->vbistart[0]);
+
+	BUG_ON(real_samples_per_line > VBI_BPL);
+	BUG_ON(real_count > VBI_DEFLINES);
+
+	f->tvnorm               = tvnorm;
+
+	/* See bttv_vbi_fmt_set(). */
+	f->end                  = tvnorm->vbistart[0] * 2 + 2;
+}
+
+/* ----------------------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/bt8xx/bttv.h b/drivers/media/pci/bt8xx/bttv.h
new file mode 100644
index 0000000..79a1124
--- /dev/null
+++ b/drivers/media/pci/bt8xx/bttv.h
@@ -0,0 +1,376 @@
+/*
+ *
+ *  bttv - Bt848 frame grabber driver
+ *
+ *  card ID's and external interfaces of the bttv driver
+ *  basically stuff needed by other drivers (i2c, lirc, ...)
+ *  and is supported not to change much over time.
+ *
+ *  Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
+ *  (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+
+#ifndef _BTTV_H_
+#define _BTTV_H_
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/i2c-addr.h>
+#include <media/tuner.h>
+
+/* ---------------------------------------------------------- */
+/* exported by bttv-cards.c                                   */
+
+#define BTTV_BOARD_UNKNOWN                 0x00
+#define BTTV_BOARD_MIRO                    0x01
+#define BTTV_BOARD_HAUPPAUGE               0x02
+#define BTTV_BOARD_STB                     0x03
+#define BTTV_BOARD_INTEL                   0x04
+#define BTTV_BOARD_DIAMOND                 0x05
+#define BTTV_BOARD_AVERMEDIA               0x06
+#define BTTV_BOARD_MATRIX_VISION           0x07
+#define BTTV_BOARD_FLYVIDEO                0x08
+#define BTTV_BOARD_TURBOTV                 0x09
+#define BTTV_BOARD_HAUPPAUGE878            0x0a
+#define BTTV_BOARD_MIROPRO                 0x0b
+#define BTTV_BOARD_ADSTECH_TV              0x0c
+#define BTTV_BOARD_AVERMEDIA98             0x0d
+#define BTTV_BOARD_VHX                     0x0e
+#define BTTV_BOARD_ZOLTRIX                 0x0f
+#define BTTV_BOARD_PIXVIEWPLAYTV           0x10
+#define BTTV_BOARD_WINVIEW_601             0x11
+#define BTTV_BOARD_AVEC_INTERCAP           0x12
+#define BTTV_BOARD_LIFE_FLYKIT             0x13
+#define BTTV_BOARD_CEI_RAFFLES             0x14
+#define BTTV_BOARD_CONFERENCETV            0x15
+#define BTTV_BOARD_PHOEBE_TVMAS            0x16
+#define BTTV_BOARD_MODTEC_205              0x17
+#define BTTV_BOARD_MAGICTVIEW061           0x18
+#define BTTV_BOARD_VOBIS_BOOSTAR           0x19
+#define BTTV_BOARD_HAUPPAUG_WCAM           0x1a
+#define BTTV_BOARD_MAXI                    0x1b
+#define BTTV_BOARD_TERRATV                 0x1c
+#define BTTV_BOARD_PXC200                  0x1d
+#define BTTV_BOARD_FLYVIDEO_98             0x1e
+#define BTTV_BOARD_IPROTV                  0x1f
+#define BTTV_BOARD_INTEL_C_S_PCI           0x20
+#define BTTV_BOARD_TERRATVALUE             0x21
+#define BTTV_BOARD_WINFAST2000             0x22
+#define BTTV_BOARD_CHRONOS_VS2             0x23
+#define BTTV_BOARD_TYPHOON_TVIEW           0x24
+#define BTTV_BOARD_PXELVWPLTVPRO           0x25
+#define BTTV_BOARD_MAGICTVIEW063           0x26
+#define BTTV_BOARD_PINNACLE                0x27
+#define BTTV_BOARD_STB2                    0x28
+#define BTTV_BOARD_AVPHONE98               0x29
+#define BTTV_BOARD_PV951                   0x2a
+#define BTTV_BOARD_ONAIR_TV                0x2b
+#define BTTV_BOARD_SIGMA_TVII_FM           0x2c
+#define BTTV_BOARD_MATRIX_VISION2          0x2d
+#define BTTV_BOARD_ZOLTRIX_GENIE           0x2e
+#define BTTV_BOARD_TERRATVRADIO            0x2f
+#define BTTV_BOARD_DYNALINK                0x30
+#define BTTV_BOARD_GVBCTV3PCI              0x31
+#define BTTV_BOARD_PXELVWPLTVPAK           0x32
+#define BTTV_BOARD_EAGLE                   0x33
+#define BTTV_BOARD_PINNACLEPRO             0x34
+#define BTTV_BOARD_TVIEW_RDS_FM            0x35
+#define BTTV_BOARD_LIFETEC_9415            0x36
+#define BTTV_BOARD_BESTBUY_EASYTV          0x37
+#define BTTV_BOARD_FLYVIDEO_98FM           0x38
+#define BTTV_BOARD_GRANDTEC                0x39
+#define BTTV_BOARD_ASKEY_CPH060            0x3a
+#define BTTV_BOARD_ASKEY_CPH03X            0x3b
+#define BTTV_BOARD_MM100PCTV               0x3c
+#define BTTV_BOARD_GMV1                    0x3d
+#define BTTV_BOARD_BESTBUY_EASYTV2         0x3e
+#define BTTV_BOARD_ATI_TVWONDER            0x3f
+#define BTTV_BOARD_ATI_TVWONDERVE          0x40
+#define BTTV_BOARD_FLYVIDEO2000            0x41
+#define BTTV_BOARD_TERRATVALUER            0x42
+#define BTTV_BOARD_GVBCTV4PCI              0x43
+#define BTTV_BOARD_VOODOOTV_FM             0x44
+#define BTTV_BOARD_AIMMS                   0x45
+#define BTTV_BOARD_PV_BT878P_PLUS          0x46
+#define BTTV_BOARD_FLYVIDEO98EZ            0x47
+#define BTTV_BOARD_PV_BT878P_9B            0x48
+#define BTTV_BOARD_SENSORAY311_611         0x49
+#define BTTV_BOARD_RV605                   0x4a
+#define BTTV_BOARD_POWERCLR_MTV878         0x4b
+#define BTTV_BOARD_WINDVR                  0x4c
+#define BTTV_BOARD_GRANDTEC_MULTI          0x4d
+#define BTTV_BOARD_KWORLD                  0x4e
+#define BTTV_BOARD_DSP_TCVIDEO             0x4f
+#define BTTV_BOARD_HAUPPAUGEPVR            0x50
+#define BTTV_BOARD_GVBCTV5PCI              0x51
+#define BTTV_BOARD_OSPREY1x0               0x52
+#define BTTV_BOARD_OSPREY1x0_848           0x53
+#define BTTV_BOARD_OSPREY101_848           0x54
+#define BTTV_BOARD_OSPREY1x1               0x55
+#define BTTV_BOARD_OSPREY1x1_SVID          0x56
+#define BTTV_BOARD_OSPREY2xx               0x57
+#define BTTV_BOARD_OSPREY2x0_SVID          0x58
+#define BTTV_BOARD_OSPREY2x0               0x59
+#define BTTV_BOARD_OSPREY500               0x5a
+#define BTTV_BOARD_OSPREY540               0x5b
+#define BTTV_BOARD_OSPREY2000              0x5c
+#define BTTV_BOARD_IDS_EAGLE               0x5d
+#define BTTV_BOARD_PINNACLESAT             0x5e
+#define BTTV_BOARD_FORMAC_PROTV            0x5f
+#define BTTV_BOARD_MACHTV                  0x60
+#define BTTV_BOARD_EURESYS_PICOLO          0x61
+#define BTTV_BOARD_PV150                   0x62
+#define BTTV_BOARD_AD_TVK503               0x63
+#define BTTV_BOARD_HERCULES_SM_TV          0x64
+#define BTTV_BOARD_PACETV                  0x65
+#define BTTV_BOARD_IVC200                  0x66
+#define BTTV_BOARD_XGUARD                  0x67
+#define BTTV_BOARD_NEBULA_DIGITV           0x68
+#define BTTV_BOARD_PV143                   0x69
+#define BTTV_BOARD_VD009X1_VD011_MINIDIN   0x6a
+#define BTTV_BOARD_VD009X1_VD011_COMBI     0x6b
+#define BTTV_BOARD_VD009_MINIDIN           0x6c
+#define BTTV_BOARD_VD009_COMBI             0x6d
+#define BTTV_BOARD_IVC100                  0x6e
+#define BTTV_BOARD_IVC120                  0x6f
+#define BTTV_BOARD_PC_HDTV                 0x70
+#define BTTV_BOARD_TWINHAN_DST             0x71
+#define BTTV_BOARD_WINFASTVC100            0x72
+#define BTTV_BOARD_TEV560                  0x73
+#define BTTV_BOARD_SIMUS_GVC1100           0x74
+#define BTTV_BOARD_NGSTV_PLUS              0x75
+#define BTTV_BOARD_LMLBT4                  0x76
+#define BTTV_BOARD_TEKRAM_M205             0x77
+#define BTTV_BOARD_CONTVFMI                0x78
+#define BTTV_BOARD_PICOLO_TETRA_CHIP       0x79
+#define BTTV_BOARD_SPIRIT_TV               0x7a
+#define BTTV_BOARD_AVDVBT_771              0x7b
+#define BTTV_BOARD_AVDVBT_761              0x7c
+#define BTTV_BOARD_MATRIX_VISIONSQ         0x7d
+#define BTTV_BOARD_MATRIX_VISIONSLC        0x7e
+#define BTTV_BOARD_APAC_VIEWCOMP           0x7f
+#define BTTV_BOARD_DVICO_DVBT_LITE         0x80
+#define BTTV_BOARD_VGEAR_MYVCD             0x81
+#define BTTV_BOARD_SUPER_TV                0x82
+#define BTTV_BOARD_TIBET_CS16              0x83
+#define BTTV_BOARD_KODICOM_4400R           0x84
+#define BTTV_BOARD_KODICOM_4400R_SL        0x85
+#define BTTV_BOARD_ADLINK_RTV24            0x86
+#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87
+#define BTTV_BOARD_ACORP_Y878F             0x88
+#define BTTV_BOARD_CONCEPTRONIC_CTVFMI2    0x89
+#define BTTV_BOARD_PV_BT878P_2E            0x8a
+#define BTTV_BOARD_PV_M4900                0x8b
+#define BTTV_BOARD_OSPREY440               0x8c
+#define BTTV_BOARD_ASOUND_SKYEYE	   0x8d
+#define BTTV_BOARD_SABRENT_TVFM   	   0x8e
+#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB     0x8f
+#define BTTV_BOARD_MACHTV_MAGICTV          0x90
+#define BTTV_BOARD_SSAI_SECURITY	   0x91
+#define BTTV_BOARD_SSAI_ULTRASOUND	   0x92
+#define BTTV_BOARD_VOODOOTV_200		   0x93
+#define BTTV_BOARD_DVICO_FUSIONHDTV_2	   0x94
+#define BTTV_BOARD_TYPHOON_TVTUNERPCI	   0x95
+#define BTTV_BOARD_GEOVISION_GV600	   0x96
+#define BTTV_BOARD_KOZUMI_KTV_01C          0x97
+#define BTTV_BOARD_ENLTV_FM_2		   0x98
+#define BTTV_BOARD_VD012		   0x99
+#define BTTV_BOARD_VD012_X1		   0x9a
+#define BTTV_BOARD_VD012_X2		   0x9b
+#define BTTV_BOARD_IVCE8784		   0x9c
+#define BTTV_BOARD_GEOVISION_GV800S	   0x9d
+#define BTTV_BOARD_GEOVISION_GV800S_SL	   0x9e
+#define BTTV_BOARD_PV183                   0x9f
+#define BTTV_BOARD_TVT_TD3116		   0xa0
+#define BTTV_BOARD_APOSONIC_WDVR           0xa1
+
+/* more card-specific defines */
+#define PT2254_L_CHANNEL 0x10
+#define PT2254_R_CHANNEL 0x08
+#define PT2254_DBS_IN_2 0x400
+#define PT2254_DBS_IN_10 0x20000
+#define WINVIEW_PT2254_CLK  0x40
+#define WINVIEW_PT2254_DATA 0x20
+#define WINVIEW_PT2254_STROBE 0x80
+
+struct bttv_core {
+	/* device structs */
+	struct v4l2_device   v4l2_dev;
+	struct pci_dev       *pci;
+	struct i2c_adapter   i2c_adap;
+	struct list_head     subs;     /* struct bttv_sub_device */
+
+	/* device config */
+	unsigned int         nr;       /* dev nr (for printk("bttv%d: ...");  */
+	unsigned int         type;     /* card type (pointer into tvcards[])  */
+};
+
+struct bttv;
+
+struct tvcard {
+	char *name;
+	void (*volume_gpio)(struct bttv *btv, __u16 volume);
+	void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+	void (*muxsel_hook)(struct bttv *btv, unsigned int input);
+
+	/* MUX bits for each input, two bits per input starting with the LSB */
+	u32 muxsel; /* Use MUXSEL() to set */
+
+	u32 gpiomask;
+	u32 gpiomux[4];  /* Tuner, Radio, external, internal */
+	u32 gpiomute;    /* GPIO mute setting */
+	u32 gpiomask2;   /* GPIO MUX mask */
+
+	unsigned int tuner_type;
+	u8 tuner_addr;
+	u8 video_inputs;	/* Number of inputs */
+	unsigned int svhs:4;	/* Which input is s-video */
+#define NO_SVHS	15
+	unsigned int pll:2;
+#define PLL_NONE 0
+#define PLL_28   1
+#define PLL_35   2
+
+	/* i2c audio flags */
+	unsigned int no_msp34xx:1;
+	unsigned int no_tda7432:1;
+	unsigned int msp34xx_alt:1;
+	/* Note: currently no card definition needs to mark the presence
+	   of a RDS saa6588 chip. If this is ever needed, then add a new
+	   'has_saa6588' bit here. */
+
+	unsigned int no_video:1; /* video pci function is unused */
+	unsigned int has_dvb:1;
+	unsigned int has_remote:1;
+	unsigned int has_radio:1;
+	unsigned int has_dig_in:1; /* Has digital input (always last input) */
+	unsigned int no_gpioirq:1;
+};
+
+extern struct tvcard bttv_tvcards[];
+
+/*
+ * This bit of cpp voodoo is used to create a macro with a variable number of
+ * arguments (1 to 16).  It will pack each argument into a word two bits at a
+ * time.  It can't be a function because it needs to be compile time constant to
+ * initialize structures.  Since each argument must fit in two bits, it's ok
+ * that they are changed to octal.  One should not use hex number, macros, or
+ * anything else with this macro.  Just use plain integers from 0 to 3.
+ */
+#define _MUXSELf(a)      	0##a << 30
+#define _MUXSELe(a, b...)	0##a << 28 | _MUXSELf(b)
+#define _MUXSELd(a, b...)	0##a << 26 | _MUXSELe(b)
+#define _MUXSELc(a, b...)	0##a << 24 | _MUXSELd(b)
+#define _MUXSELb(a, b...)	0##a << 22 | _MUXSELc(b)
+#define _MUXSELa(a, b...)	0##a << 20 | _MUXSELb(b)
+#define _MUXSEL9(a, b...)	0##a << 18 | _MUXSELa(b)
+#define _MUXSEL8(a, b...)	0##a << 16 | _MUXSEL9(b)
+#define _MUXSEL7(a, b...)	0##a << 14 | _MUXSEL8(b)
+#define _MUXSEL6(a, b...)	0##a << 12 | _MUXSEL7(b)
+#define _MUXSEL5(a, b...)	0##a << 10 | _MUXSEL6(b)
+#define _MUXSEL4(a, b...)	0##a << 8  | _MUXSEL5(b)
+#define _MUXSEL3(a, b...)	0##a << 6  | _MUXSEL4(b)
+#define _MUXSEL2(a, b...)	0##a << 4  | _MUXSEL3(b)
+#define _MUXSEL1(a, b...)	0##a << 2  | _MUXSEL2(b)
+#define MUXSEL(a, b...)		(a | _MUXSEL1(b))
+
+/* identification / initialization of the card */
+extern void bttv_idcard(struct bttv *btv);
+extern void bttv_init_card1(struct bttv *btv);
+extern void bttv_init_card2(struct bttv *btv);
+extern void bttv_init_tuner(struct bttv *btv);
+
+/* card-specific funtions */
+extern void tea5757_set_freq(struct bttv *btv, unsigned short freq);
+extern u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits);
+
+/* extra tweaks for some chipsets */
+extern void bttv_check_chipset(void);
+extern int bttv_handle_chipset(struct bttv *btv);
+
+/* ---------------------------------------------------------- */
+/* exported by bttv-if.c                                      */
+
+/* this obsolete -- please use the sysfs-based
+   interface below for new code */
+
+extern struct pci_dev* bttv_get_pcidev(unsigned int card);
+
+/* sets GPOE register (BT848_GPIO_OUT_EN) to new value:
+   data | (current_GPOE_value & ~mask)
+   returns negative value if error occurred
+*/
+extern int bttv_gpio_enable(unsigned int card,
+			    unsigned long mask, unsigned long data);
+
+/* fills data with GPDATA register contents
+   returns negative value if error occurred
+*/
+extern int bttv_read_gpio(unsigned int card, unsigned long *data);
+
+/* sets GPDATA register to new value:
+  (data & mask) | (current_GPDATA_value & ~mask)
+  returns negative value if error occurred
+*/
+extern int bttv_write_gpio(unsigned int card,
+			   unsigned long mask, unsigned long data);
+
+
+
+
+/* ---------------------------------------------------------- */
+/* sysfs/driver-moded based gpio access interface             */
+
+struct bttv_sub_device {
+	struct device    dev;
+	struct bttv_core *core;
+	struct list_head list;
+};
+#define to_bttv_sub_dev(x) container_of((x), struct bttv_sub_device, dev)
+
+struct bttv_sub_driver {
+	struct device_driver   drv;
+	char                   wanted[20];
+	int                    (*probe)(struct bttv_sub_device *sub);
+	void                   (*remove)(struct bttv_sub_device *sub);
+};
+#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
+
+int bttv_sub_register(struct bttv_sub_driver *drv, char *wanted);
+int bttv_sub_unregister(struct bttv_sub_driver *drv);
+
+/* gpio access functions */
+void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits);
+u32 bttv_gpio_read(struct bttv_core *core);
+void bttv_gpio_write(struct bttv_core *core, u32 value);
+void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits);
+
+#define gpio_inout(mask,bits)  bttv_gpio_inout(&btv->c, mask, bits)
+#define gpio_read()            bttv_gpio_read(&btv->c)
+#define gpio_write(value)      bttv_gpio_write(&btv->c, value)
+#define gpio_bits(mask,bits)   bttv_gpio_bits(&btv->c, mask, bits)
+
+
+/* ---------------------------------------------------------- */
+/* i2c                                                        */
+
+#define bttv_call_all(btv, o, f, args...) \
+	v4l2_device_call_all(&btv->c.v4l2_dev, 0, o, f, ##args)
+
+extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for);
+extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
+			 unsigned char b2, int both);
+extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr);
+
+extern int bttv_input_init(struct bttv *dev);
+extern void bttv_input_fini(struct bttv *dev);
+extern void bttv_input_irq(struct bttv *dev);
+
+#endif /* _BTTV_H_ */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h
new file mode 100644
index 0000000..70fd4f2
--- /dev/null
+++ b/drivers/media/pci/bt8xx/bttvp.h
@@ -0,0 +1,535 @@
+/*
+
+    bttv - Bt848 frame grabber driver
+
+    bttv's *private* header file  --  nobody other than bttv itself
+    should ever include this file.
+
+    (c) 2000-2002 Gerd Knorr <kraxel@bytesex.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _BTTVP_H_
+#define _BTTVP_H_
+
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/pci.h>
+#include <linux/input.h>
+#include <linux/mutex.h>
+#include <linux/scatterlist.h>
+#include <asm/io.h>
+#include <media/v4l2-common.h>
+#include <linux/device.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/tveeprom.h>
+#include <media/rc-core.h>
+#include <media/ir-kbd-i2c.h>
+
+#include "bt848.h"
+#include "bttv.h"
+#include "btcx-risc.h"
+
+#ifdef __KERNEL__
+
+#define FORMAT_FLAGS_DITHER       0x01
+#define FORMAT_FLAGS_PACKED       0x02
+#define FORMAT_FLAGS_PLANAR       0x04
+#define FORMAT_FLAGS_RAW          0x08
+#define FORMAT_FLAGS_CrCb         0x10
+
+#define RISC_SLOT_O_VBI        4
+#define RISC_SLOT_O_FIELD      6
+#define RISC_SLOT_E_VBI       10
+#define RISC_SLOT_E_FIELD     12
+#define RISC_SLOT_LOOP        14
+
+#define RESOURCE_OVERLAY       1
+#define RESOURCE_VIDEO_STREAM  2
+#define RESOURCE_VBI           4
+#define RESOURCE_VIDEO_READ    8
+
+#define RAW_LINES            640
+#define RAW_BPL             1024
+
+#define UNSET (-1U)
+
+/* Min. value in VDELAY register. */
+#define MIN_VDELAY 2
+/* Even to get Cb first, odd for Cr. */
+#define MAX_HDELAY (0x3FF & -2)
+/* Limits scaled width, which must be a multiple of 4. */
+#define MAX_HACTIVE (0x3FF & -4)
+
+#define BTTV_NORMS    (\
+		V4L2_STD_PAL    | V4L2_STD_PAL_N | \
+		V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \
+		V4L2_STD_NTSC   | V4L2_STD_PAL_M | \
+		V4L2_STD_PAL_60)
+/* ---------------------------------------------------------- */
+
+struct bttv_tvnorm {
+	int   v4l2_id;
+	char  *name;
+	u32   Fsc;
+	u16   swidth, sheight; /* scaled standard width, height */
+	u16   totalwidth;
+	u8    adelay, bdelay, iform;
+	u32   scaledtwidth;
+	u16   hdelayx1, hactivex1;
+	u16   vdelay;
+	u8    vbipack;
+	u16   vtotal;
+	int   sram;
+	/* ITU-R frame line number of the first VBI line we can
+	   capture, of the first and second field. The last possible line
+	   is determined by cropcap.bounds. */
+	u16   vbistart[2];
+	/* Horizontally this counts fCLKx1 samples following the leading
+	   edge of the horizontal sync pulse, vertically ITU-R frame line
+	   numbers of the first field times two (2, 4, 6, ... 524 or 624). */
+	struct v4l2_cropcap cropcap;
+};
+extern const struct bttv_tvnorm bttv_tvnorms[];
+
+struct bttv_format {
+	char *name;
+	int  fourcc;          /* video4linux 2      */
+	int  btformat;        /* BT848_COLOR_FMT_*  */
+	int  btswap;          /* BT848_COLOR_CTL_*  */
+	int  depth;           /* bit/pixel          */
+	int  flags;
+	int  hshift,vshift;   /* for planar modes   */
+};
+
+struct bttv_ir {
+	struct rc_dev           *dev;
+	struct timer_list       timer;
+
+	char                    name[32];
+	char                    phys[32];
+
+	/* Usual gpio signalling */
+	u32                     mask_keycode;
+	u32                     mask_keydown;
+	u32                     mask_keyup;
+	u32                     polling;
+	u32                     last_gpio;
+	int                     shift_by;
+	int                     start; // What should RC5_START() be
+	int                     addr; // What RC5_ADDR() should be.
+	int                     rc5_remote_gap;
+
+	/* RC5 gpio */
+	bool			rc5_gpio;   /* Is RC5 legacy GPIO enabled? */
+	u32                     last_bit;   /* last raw bit seen */
+	u32                     code;       /* raw code under construction */
+	struct timeval          base_time;  /* time of last seen code */
+	bool                    active;     /* building raw code */
+};
+
+
+/* ---------------------------------------------------------- */
+
+struct bttv_geometry {
+	u8  vtc,crop,comb;
+	u16 width,hscale,hdelay;
+	u16 sheight,vscale,vdelay,vtotal;
+};
+
+struct bttv_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer     vb;
+
+	/* bttv specific */
+	const struct bttv_format   *fmt;
+	unsigned int               tvnorm;
+	int                        btformat;
+	int                        btswap;
+	struct bttv_geometry       geo;
+	struct btcx_riscmem        top;
+	struct btcx_riscmem        bottom;
+	struct v4l2_rect           crop;
+	unsigned int               vbi_skip[2];
+	unsigned int               vbi_count[2];
+};
+
+struct bttv_buffer_set {
+	struct bttv_buffer     *top;       /* top field buffer    */
+	struct bttv_buffer     *bottom;    /* bottom field buffer */
+	unsigned int           top_irq;
+	unsigned int           frame_irq;
+};
+
+struct bttv_overlay {
+	unsigned int           tvnorm;
+	struct v4l2_rect       w;
+	enum v4l2_field        field;
+	struct v4l2_clip       *clips;
+	int                    nclips;
+	int                    setup_ok;
+};
+
+struct bttv_vbi_fmt {
+	struct v4l2_vbi_format fmt;
+
+	/* fmt.start[] and count[] refer to this video standard. */
+	const struct bttv_tvnorm *tvnorm;
+
+	/* Earliest possible start of video capturing with this
+	   v4l2_vbi_format, in struct bttv_crop.rect units. */
+	__s32                  end;
+};
+
+/* bttv-vbi.c */
+void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm);
+
+struct bttv_crop {
+	/* A cropping rectangle in struct bttv_tvnorm.cropcap units. */
+	struct v4l2_rect       rect;
+
+	/* Scaled image size limits with this crop rect. Divide
+	   max_height, but not min_height, by two when capturing
+	   single fields. See also bttv_crop_reset() and
+	   bttv_crop_adjust() in bttv-driver.c. */
+	__s32                  min_scaled_width;
+	__s32                  min_scaled_height;
+	__s32                  max_scaled_width;
+	__s32                  max_scaled_height;
+};
+
+struct bttv_fh {
+	struct bttv              *btv;
+	int resources;
+#ifdef VIDIOC_G_PRIORITY
+	enum v4l2_priority       prio;
+#endif
+	enum v4l2_buf_type       type;
+
+	/* video capture */
+	struct videobuf_queue    cap;
+	const struct bttv_format *fmt;
+	int                      width;
+	int                      height;
+
+	/* video overlay */
+	const struct bttv_format *ovfmt;
+	struct bttv_overlay      ov;
+
+	/* Application called VIDIOC_S_CROP. */
+	int                      do_crop;
+
+	/* vbi capture */
+	struct videobuf_queue    vbi;
+	/* Current VBI capture window as seen through this fh (cannot
+	   be global for compatibility with earlier drivers). Protected
+	   by struct bttv.lock and struct bttv_fh.vbi.lock. */
+	struct bttv_vbi_fmt      vbi_fmt;
+};
+
+/* ---------------------------------------------------------- */
+/* bttv-risc.c                                                */
+
+/* risc code generators - capture */
+int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
+		     struct scatterlist *sglist,
+		     unsigned int offset, unsigned int bpl,
+		     unsigned int pitch, unsigned int skip_lines,
+		     unsigned int store_lines);
+
+/* control dma register + risc main loop */
+void bttv_set_dma(struct bttv *btv, int override);
+int bttv_risc_init_main(struct bttv *btv);
+int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
+		   int irqflags);
+
+/* capture buffer handling */
+int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf);
+int bttv_buffer_activate_video(struct bttv *btv,
+			       struct bttv_buffer_set *set);
+int bttv_buffer_activate_vbi(struct bttv *btv,
+			     struct bttv_buffer *vbi);
+void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv,
+		   struct bttv_buffer *buf);
+
+/* overlay handling */
+int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
+		      const struct bttv_format *fmt,
+		      struct bttv_buffer *buf);
+
+
+/* ---------------------------------------------------------- */
+/* bttv-vbi.c                                                 */
+
+int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
+int bttv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
+int bttv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
+
+extern struct videobuf_queue_ops bttv_vbi_qops;
+
+/* ---------------------------------------------------------- */
+/* bttv-gpio.c */
+
+extern struct bus_type bttv_sub_bus_type;
+int bttv_sub_add_device(struct bttv_core *core, char *name);
+int bttv_sub_del_devices(struct bttv_core *core);
+
+/* ---------------------------------------------------------- */
+/* bttv-cards.c                                               */
+
+extern int no_overlay;
+
+/* ---------------------------------------------------------- */
+/* bttv-input.c                                               */
+
+extern void init_bttv_i2c_ir(struct bttv *btv);
+extern int fini_bttv_i2c(struct bttv *btv);
+
+/* ---------------------------------------------------------- */
+/* bttv-driver.c                                              */
+
+/* insmod options */
+extern unsigned int bttv_verbose;
+extern unsigned int bttv_debug;
+extern unsigned int bttv_gpio;
+extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
+extern int init_bttv_i2c(struct bttv *btv);
+
+#define dprintk(fmt, ...)			\
+do {						\
+	if (bttv_debug >= 1)			\
+		pr_debug(fmt, ##__VA_ARGS__);	\
+} while (0)
+#define dprintk_cont(fmt, ...)			\
+do {						\
+	if (bttv_debug >= 1)			\
+		pr_cont(fmt, ##__VA_ARGS__);	\
+} while (0)
+#define d2printk(fmt, ...)			\
+do {						\
+	if (bttv_debug >= 2)			\
+		printk(fmt, ##__VA_ARGS__);	\
+} while (0)
+
+#define BTTV_MAX_FBUF   0x208000
+#define BTTV_TIMEOUT    msecs_to_jiffies(500)    /* 0.5 seconds */
+#define BTTV_FREE_IDLE  msecs_to_jiffies(1000)   /* one second */
+
+
+struct bttv_pll_info {
+	unsigned int pll_ifreq;    /* PLL input frequency        */
+	unsigned int pll_ofreq;    /* PLL output frequency       */
+	unsigned int pll_crystal;  /* Crystal used for input     */
+	unsigned int pll_current;  /* Currently programmed ofreq */
+};
+
+/* for gpio-connected remote control */
+struct bttv_input {
+	struct input_dev      *dev;
+	char                  name[32];
+	char                  phys[32];
+	u32                   mask_keycode;
+	u32                   mask_keydown;
+};
+
+struct bttv_suspend_state {
+	u32  gpio_enable;
+	u32  gpio_data;
+	int  disabled;
+	int  loop_irq;
+	struct bttv_buffer_set video;
+	struct bttv_buffer     *vbi;
+};
+
+struct bttv {
+	struct bttv_core c;
+
+	/* pci device config */
+	unsigned short id;
+	unsigned char revision;
+	unsigned char __iomem *bt848_mmio;   /* pointer to mmio */
+
+	/* card configuration info */
+	unsigned int cardid;   /* pci subsystem id (bt878 based ones) */
+	unsigned int tuner_type;  /* tuner chip type */
+	unsigned int tda9887_conf;
+	unsigned int svhs, dig;
+	unsigned int has_saa6588:1;
+	struct bttv_pll_info pll;
+	int triton1;
+	int gpioirq;
+
+	int use_i2c_hw;
+
+	/* old gpio interface */
+	int shutdown;
+
+	void (*volume_gpio)(struct bttv *btv, __u16 volume);
+	void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+
+	/* new gpio interface */
+	spinlock_t gpio_lock;
+
+	/* i2c layer */
+	struct i2c_algo_bit_data   i2c_algo;
+	struct i2c_client          i2c_client;
+	int                        i2c_state, i2c_rc;
+	int                        i2c_done;
+	wait_queue_head_t          i2c_queue;
+	struct v4l2_subdev 	  *sd_msp34xx;
+	struct v4l2_subdev 	  *sd_tvaudio;
+
+	/* video4linux (1) */
+	struct video_device *video_dev;
+	struct video_device *radio_dev;
+	struct video_device *vbi_dev;
+
+	/* infrared remote */
+	int has_remote;
+	struct bttv_ir *remote;
+
+	/* I2C remote data */
+	struct IR_i2c_init_data    init_data;
+
+	/* locking */
+	spinlock_t s_lock;
+	struct mutex lock;
+	int resources;
+#ifdef VIDIOC_G_PRIORITY
+	struct v4l2_prio_state prio;
+#endif
+
+	/* video state */
+	unsigned int input;
+	unsigned int audio;
+	unsigned int mute;
+	unsigned long freq;
+	unsigned int tvnorm;
+	int hue, contrast, bright, saturation;
+	struct v4l2_framebuffer fbuf;
+	unsigned int field_count;
+
+	/* various options */
+	int opt_combfilter;
+	int opt_lumafilter;
+	int opt_automute;
+	int opt_chroma_agc;
+	int opt_adc_crush;
+	int opt_vcr_hack;
+	int opt_whitecrush_upper;
+	int opt_whitecrush_lower;
+	int opt_uv_ratio;
+	int opt_full_luma_range;
+	int opt_coring;
+
+	/* radio data/state */
+	int has_radio;
+	int radio_user;
+	int radio_uses_msp_demodulator;
+
+	/* miro/pinnacle + Aimslab VHX
+	   philips matchbox (tea5757 radio tuner) support */
+	int has_matchbox;
+	int mbox_we;
+	int mbox_data;
+	int mbox_clk;
+	int mbox_most;
+	int mbox_mask;
+
+	/* ISA stuff (Terratec Active Radio Upgrade) */
+	int mbox_ior;
+	int mbox_iow;
+	int mbox_csel;
+
+	/* risc memory management data
+	   - must acquire s_lock before changing these
+	   - only the irq handler is supported to touch top + bottom + vcurr */
+	struct btcx_riscmem     main;
+	struct bttv_buffer      *screen;    /* overlay             */
+	struct list_head        capture;    /* video capture queue */
+	struct list_head        vcapture;   /* vbi capture queue   */
+	struct bttv_buffer_set  curr;       /* active buffers      */
+	struct bttv_buffer      *cvbi;      /* active vbi buffer   */
+	int                     loop_irq;
+	int                     new_input;
+
+	unsigned long cap_ctl;
+	unsigned long dma_on;
+	struct timer_list timeout;
+	struct bttv_suspend_state state;
+
+	/* stats */
+	unsigned int errors;
+	unsigned int framedrop;
+	unsigned int irq_total;
+	unsigned int irq_me;
+
+	unsigned int users;
+	struct bttv_fh init;
+
+	/* used to make dvb-bt8xx autoloadable */
+	struct work_struct request_module_wk;
+
+	/* Default (0) and current (1) video capturing and overlay
+	   cropping parameters in bttv_tvnorm.cropcap units. Protected
+	   by bttv.lock. */
+	struct bttv_crop crop[2];
+
+	/* Earliest possible start of video capturing in
+	   bttv_tvnorm.cropcap line units. Set by check_alloc_btres()
+	   and free_btres(). Protected by bttv.lock. */
+	__s32			vbi_end;
+
+	/* Latest possible end of VBI capturing (= crop[x].rect.top when
+	   VIDEO_RESOURCES are locked). Set by check_alloc_btres()
+	   and free_btres(). Protected by bttv.lock. */
+	__s32			crop_start;
+};
+
+static inline struct bttv *to_bttv(struct v4l2_device *v4l2_dev)
+{
+	return container_of(v4l2_dev, struct bttv, c.v4l2_dev);
+}
+
+/* our devices */
+#define BTTV_MAX 32
+extern unsigned int bttv_num;
+extern struct bttv *bttvs[BTTV_MAX];
+
+static inline unsigned int bttv_muxsel(const struct bttv *btv,
+				       unsigned int input)
+{
+	return (bttv_tvcards[btv->c.type].muxsel >> (input * 2)) & 3;
+}
+
+#endif
+
+#define btwrite(dat,adr)    writel((dat), btv->bt848_mmio+(adr))
+#define btread(adr)         readl(btv->bt848_mmio+(adr))
+
+#define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
+#define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
+#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
+
+#endif /* _BTTVP_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/bt8xx/dst.c b/drivers/media/pci/bt8xx/dst.c
new file mode 100644
index 0000000..430b3eb
--- /dev/null
+++ b/drivers/media/pci/bt8xx/dst.c
@@ -0,0 +1,1873 @@
+/*
+	Frontend/Card driver for TwinHan DST Frontend
+	Copyright (C) 2003 Jamie Honan
+	Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <asm/div64.h>
+#include "dvb_frontend.h"
+#include "dst_priv.h"
+#include "dst_common.h"
+
+static unsigned int verbose = 1;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+
+static unsigned int dst_addons;
+module_param(dst_addons, int, 0644);
+MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)");
+
+static unsigned int dst_algo;
+module_param(dst_algo, int, 0644);
+MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)");
+
+#define HAS_LOCK		1
+#define ATTEMPT_TUNE		2
+#define HAS_POWER		4
+
+#define DST_ERROR		0
+#define DST_NOTICE		1
+#define DST_INFO		2
+#define DST_DEBUG		3
+
+#define dprintk(x, y, z, format, arg...) do {				\
+	if (z) {							\
+		if	((x > DST_ERROR) && (x > y))			\
+			printk(KERN_ERR "dst(%d) %s: " format "\n",	\
+				state->bt->nr, __func__ , ##arg);	\
+		else if	((x > DST_NOTICE) && (x > y))			\
+			printk(KERN_NOTICE "dst(%d) %s: " format "\n",  \
+				state->bt->nr, __func__ , ##arg);	\
+		else if ((x > DST_INFO) && (x > y))			\
+			printk(KERN_INFO "dst(%d) %s: " format "\n",	\
+				state->bt->nr, __func__ , ##arg);	\
+		else if ((x > DST_DEBUG) && (x > y))			\
+			printk(KERN_DEBUG "dst(%d) %s: " format "\n",	\
+				state->bt->nr,  __func__ , ##arg);	\
+	} else {							\
+		if (x > y)						\
+			printk(format, ##arg);				\
+	}								\
+} while(0)
+
+static int dst_command(struct dst_state *state, u8 *data, u8 len);
+
+static void dst_packsize(struct dst_state *state, int psize)
+{
+	union dst_gpio_packet bits;
+
+	bits.psize = psize;
+	bt878_device_control(state->bt, DST_IG_TS, &bits);
+}
+
+static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb,
+			 u32 outhigh, int delay)
+{
+	union dst_gpio_packet enb;
+	union dst_gpio_packet bits;
+	int err;
+
+	enb.enb.mask = mask;
+	enb.enb.enable = enbb;
+
+	dprintk(verbose, DST_INFO, 1, "mask=[%04x], enbb=[%04x], outhigh=[%04x]", mask, enbb, outhigh);
+	if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) {
+		dprintk(verbose, DST_INFO, 1, "dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)", err, mask, enbb);
+		return -EREMOTEIO;
+	}
+	udelay(1000);
+	/* because complete disabling means no output, no need to do output packet */
+	if (enbb == 0)
+		return 0;
+	if (delay)
+		msleep(10);
+	bits.outp.mask = enbb;
+	bits.outp.highvals = outhigh;
+	if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) {
+		dprintk(verbose, DST_INFO, 1, "dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)", err, enbb, outhigh);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int dst_gpio_inb(struct dst_state *state, u8 *result)
+{
+	union dst_gpio_packet rd_packet;
+	int err;
+
+	*result = 0;
+	if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)", err);
+		return -EREMOTEIO;
+	}
+	*result = (u8) rd_packet.rd.value;
+
+	return 0;
+}
+
+int rdc_reset_state(struct dst_state *state)
+{
+	dprintk(verbose, DST_INFO, 1, "Resetting state machine");
+	if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, 0, NO_DELAY) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !");
+		return -1;
+	}
+	msleep(10);
+	if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, RDC_8820_INT, NO_DELAY) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !");
+		msleep(10);
+		return -1;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(rdc_reset_state);
+
+static int rdc_8820_reset(struct dst_state *state)
+{
+	dprintk(verbose, DST_DEBUG, 1, "Resetting DST");
+	if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !");
+		return -1;
+	}
+	udelay(1000);
+	if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, RDC_8820_RESET, DELAY) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int dst_pio_enable(struct dst_state *state)
+{
+	if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !");
+		return -1;
+	}
+	udelay(1000);
+
+	return 0;
+}
+
+int dst_pio_disable(struct dst_state *state)
+{
+	if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_DISABLE, RDC_8820_PIO_0_DISABLE, NO_DELAY) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !");
+		return -1;
+	}
+	if (state->type_flags & DST_TYPE_HAS_FW_1)
+		udelay(1000);
+
+	return 0;
+}
+EXPORT_SYMBOL(dst_pio_disable);
+
+int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode)
+{
+	u8 reply;
+	int i;
+
+	for (i = 0; i < 200; i++) {
+		if (dst_gpio_inb(state, &reply) < 0) {
+			dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb ERROR !");
+			return -1;
+		}
+		if ((reply & RDC_8820_PIO_0_ENABLE) == 0) {
+			dprintk(verbose, DST_INFO, 1, "dst wait ready after %d", i);
+			return 1;
+		}
+		msleep(10);
+	}
+	dprintk(verbose, DST_NOTICE, 1, "dst wait NOT ready after %d", i);
+
+	return 0;
+}
+EXPORT_SYMBOL(dst_wait_dst_ready);
+
+int dst_error_recovery(struct dst_state *state)
+{
+	dprintk(verbose, DST_NOTICE, 1, "Trying to return from previous errors.");
+	dst_pio_disable(state);
+	msleep(10);
+	dst_pio_enable(state);
+	msleep(10);
+
+	return 0;
+}
+EXPORT_SYMBOL(dst_error_recovery);
+
+int dst_error_bailout(struct dst_state *state)
+{
+	dprintk(verbose, DST_INFO, 1, "Trying to bailout from previous error.");
+	rdc_8820_reset(state);
+	dst_pio_disable(state);
+	msleep(10);
+
+	return 0;
+}
+EXPORT_SYMBOL(dst_error_bailout);
+
+int dst_comm_init(struct dst_state *state)
+{
+	dprintk(verbose, DST_INFO, 1, "Initializing DST.");
+	if ((dst_pio_enable(state)) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "PIO Enable Failed");
+		return -1;
+	}
+	if ((rdc_reset_state(state)) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "RDC 8820 State RESET Failed.");
+		return -1;
+	}
+	if (state->type_flags & DST_TYPE_HAS_FW_1)
+		msleep(100);
+	else
+		msleep(5);
+
+	return 0;
+}
+EXPORT_SYMBOL(dst_comm_init);
+
+int write_dst(struct dst_state *state, u8 *data, u8 len)
+{
+	struct i2c_msg msg = {
+		.addr = state->config->demod_address,
+		.flags = 0,
+		.buf = data,
+		.len = len
+	};
+
+	int err;
+	u8 cnt, i;
+
+	dprintk(verbose, DST_NOTICE, 0, "writing [ ");
+	for (i = 0; i < len; i++)
+		dprintk(verbose, DST_NOTICE, 0, "%02x ", data[i]);
+	dprintk(verbose, DST_NOTICE, 0, "]\n");
+
+	for (cnt = 0; cnt < 2; cnt++) {
+		if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) {
+			dprintk(verbose, DST_INFO, 1, "_write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, data[0]);
+			dst_error_recovery(state);
+			continue;
+		} else
+			break;
+	}
+	if (cnt >= 2) {
+		dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET");
+		dst_error_bailout(state);
+
+		return -1;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(write_dst);
+
+int read_dst(struct dst_state *state, u8 *ret, u8 len)
+{
+	struct i2c_msg msg = {
+		.addr = state->config->demod_address,
+		.flags = I2C_M_RD,
+		.buf = ret,
+		.len = len
+	};
+
+	int err;
+	int cnt;
+
+	for (cnt = 0; cnt < 2; cnt++) {
+		if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) {
+			dprintk(verbose, DST_INFO, 1, "read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, ret[0]);
+			dst_error_recovery(state);
+			continue;
+		} else
+			break;
+	}
+	if (cnt >= 2) {
+		dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET");
+		dst_error_bailout(state);
+
+		return -1;
+	}
+	dprintk(verbose, DST_DEBUG, 1, "reply is 0x%x", ret[0]);
+	for (err = 1; err < len; err++)
+		dprintk(verbose, DST_DEBUG, 0, " 0x%x", ret[err]);
+	if (err > 1)
+		dprintk(verbose, DST_DEBUG, 0, "\n");
+
+	return 0;
+}
+EXPORT_SYMBOL(read_dst);
+
+static int dst_set_polarization(struct dst_state *state)
+{
+	switch (state->voltage) {
+	case SEC_VOLTAGE_13:	/*	Vertical	*/
+		dprintk(verbose, DST_INFO, 1, "Polarization=[Vertical]");
+		state->tx_tuna[8] &= ~0x40;
+		break;
+	case SEC_VOLTAGE_18:	/*	Horizontal	*/
+		dprintk(verbose, DST_INFO, 1, "Polarization=[Horizontal]");
+		state->tx_tuna[8] |= 0x40;
+		break;
+	case SEC_VOLTAGE_OFF:
+		break;
+	}
+
+	return 0;
+}
+
+static int dst_set_freq(struct dst_state *state, u32 freq)
+{
+	state->frequency = freq;
+	dprintk(verbose, DST_INFO, 1, "set Frequency %u", freq);
+
+	if (state->dst_type == DST_TYPE_IS_SAT) {
+		freq = freq / 1000;
+		if (freq < 950 || freq > 2150)
+			return -EINVAL;
+		state->tx_tuna[2] = (freq >> 8);
+		state->tx_tuna[3] = (u8) freq;
+		state->tx_tuna[4] = 0x01;
+		state->tx_tuna[8] &= ~0x04;
+		if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
+			if (freq < 1531)
+				state->tx_tuna[8] |= 0x04;
+		}
+	} else if (state->dst_type == DST_TYPE_IS_TERR) {
+		freq = freq / 1000;
+		if (freq < 137000 || freq > 858000)
+			return -EINVAL;
+		state->tx_tuna[2] = (freq >> 16) & 0xff;
+		state->tx_tuna[3] = (freq >> 8) & 0xff;
+		state->tx_tuna[4] = (u8) freq;
+	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
+		freq = freq / 1000;
+		state->tx_tuna[2] = (freq >> 16) & 0xff;
+		state->tx_tuna[3] = (freq >> 8) & 0xff;
+		state->tx_tuna[4] = (u8) freq;
+	} else if (state->dst_type == DST_TYPE_IS_ATSC) {
+		freq = freq / 1000;
+		if (freq < 51000 || freq > 858000)
+			return -EINVAL;
+		state->tx_tuna[2] = (freq >> 16) & 0xff;
+		state->tx_tuna[3] = (freq >>  8) & 0xff;
+		state->tx_tuna[4] = (u8) freq;
+		state->tx_tuna[5] = 0x00;		/*	ATSC	*/
+		state->tx_tuna[6] = 0x00;
+		if (state->dst_hw_cap & DST_TYPE_HAS_ANALOG)
+			state->tx_tuna[7] = 0x00;	/*	Digital	*/
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int dst_set_bandwidth(struct dst_state *state, u32 bandwidth)
+{
+	state->bandwidth = bandwidth;
+
+	if (state->dst_type != DST_TYPE_IS_TERR)
+		return -EOPNOTSUPP;
+
+	switch (bandwidth) {
+	case 6000000:
+		if (state->dst_hw_cap & DST_TYPE_HAS_CA)
+			state->tx_tuna[7] = 0x06;
+		else {
+			state->tx_tuna[6] = 0x06;
+			state->tx_tuna[7] = 0x00;
+		}
+		break;
+	case 7000000:
+		if (state->dst_hw_cap & DST_TYPE_HAS_CA)
+			state->tx_tuna[7] = 0x07;
+		else {
+			state->tx_tuna[6] = 0x07;
+			state->tx_tuna[7] = 0x00;
+		}
+		break;
+	case 8000000:
+		if (state->dst_hw_cap & DST_TYPE_HAS_CA)
+			state->tx_tuna[7] = 0x08;
+		else {
+			state->tx_tuna[6] = 0x08;
+			state->tx_tuna[7] = 0x00;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int dst_set_inversion(struct dst_state *state, fe_spectral_inversion_t inversion)
+{
+	state->inversion = inversion;
+	switch (inversion) {
+	case INVERSION_OFF:	/*	Inversion = Normal	*/
+		state->tx_tuna[8] &= ~0x80;
+		break;
+	case INVERSION_ON:
+		state->tx_tuna[8] |= 0x80;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int dst_set_fec(struct dst_state *state, fe_code_rate_t fec)
+{
+	state->fec = fec;
+	return 0;
+}
+
+static fe_code_rate_t dst_get_fec(struct dst_state *state)
+{
+	return state->fec;
+}
+
+static int dst_set_symbolrate(struct dst_state *state, u32 srate)
+{
+	u32 symcalc;
+	u64 sval;
+
+	state->symbol_rate = srate;
+	if (state->dst_type == DST_TYPE_IS_TERR) {
+		return -EOPNOTSUPP;
+	}
+	dprintk(verbose, DST_INFO, 1, "set symrate %u", srate);
+	srate /= 1000;
+	if (state->dst_type == DST_TYPE_IS_SAT) {
+		if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
+			sval = srate;
+			sval <<= 20;
+			do_div(sval, 88000);
+			symcalc = (u32) sval;
+			dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc);
+			state->tx_tuna[5] = (u8) (symcalc >> 12);
+			state->tx_tuna[6] = (u8) (symcalc >> 4);
+			state->tx_tuna[7] = (u8) (symcalc << 4);
+		} else {
+			state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f;
+			state->tx_tuna[6] = (u8) (srate >> 8);
+			state->tx_tuna[7] = (u8) srate;
+		}
+		state->tx_tuna[8] &= ~0x20;
+		if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
+			if (srate > 8000)
+				state->tx_tuna[8] |= 0x20;
+		}
+	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
+		dprintk(verbose, DST_DEBUG, 1, "%s", state->fw_name);
+		if (!strncmp(state->fw_name, "DCTNEW", 6)) {
+			state->tx_tuna[5] = (u8) (srate >> 8);
+			state->tx_tuna[6] = (u8) srate;
+			state->tx_tuna[7] = 0x00;
+		} else if (!strncmp(state->fw_name, "DCT-CI", 6)) {
+			state->tx_tuna[5] = 0x00;
+			state->tx_tuna[6] = (u8) (srate >> 8);
+			state->tx_tuna[7] = (u8) srate;
+		}
+	}
+	return 0;
+}
+
+static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation)
+{
+	if (state->dst_type != DST_TYPE_IS_CABLE)
+		return -EOPNOTSUPP;
+
+	state->modulation = modulation;
+	switch (modulation) {
+	case QAM_16:
+		state->tx_tuna[8] = 0x10;
+		break;
+	case QAM_32:
+		state->tx_tuna[8] = 0x20;
+		break;
+	case QAM_64:
+		state->tx_tuna[8] = 0x40;
+		break;
+	case QAM_128:
+		state->tx_tuna[8] = 0x80;
+		break;
+	case QAM_256:
+		if (!strncmp(state->fw_name, "DCTNEW", 6))
+			state->tx_tuna[8] = 0xff;
+		else if (!strncmp(state->fw_name, "DCT-CI", 6))
+			state->tx_tuna[8] = 0x00;
+		break;
+	case QPSK:
+	case QAM_AUTO:
+	case VSB_8:
+	case VSB_16:
+	default:
+		return -EINVAL;
+
+	}
+
+	return 0;
+}
+
+static fe_modulation_t dst_get_modulation(struct dst_state *state)
+{
+	return state->modulation;
+}
+
+
+u8 dst_check_sum(u8 *buf, u32 len)
+{
+	u32 i;
+	u8 val = 0;
+	if (!len)
+		return 0;
+	for (i = 0; i < len; i++) {
+		val += buf[i];
+	}
+	return ((~val) + 1);
+}
+EXPORT_SYMBOL(dst_check_sum);
+
+static void dst_type_flags_print(struct dst_state *state)
+{
+	u32 type_flags = state->type_flags;
+
+	dprintk(verbose, DST_ERROR, 0, "DST type flags :");
+	if (type_flags & DST_TYPE_HAS_TS188)
+		dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_TS188);
+	if (type_flags & DST_TYPE_HAS_NEWTUNE_2)
+		dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner 2", DST_TYPE_HAS_NEWTUNE_2);
+	if (type_flags & DST_TYPE_HAS_TS204)
+		dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204);
+	if (type_flags & DST_TYPE_HAS_VLF)
+		dprintk(verbose, DST_ERROR, 0, " 0x%x VLF", DST_TYPE_HAS_VLF);
+	if (type_flags & DST_TYPE_HAS_SYMDIV)
+		dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV);
+	if (type_flags & DST_TYPE_HAS_FW_1)
+		dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 1", DST_TYPE_HAS_FW_1);
+	if (type_flags & DST_TYPE_HAS_FW_2)
+		dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 2", DST_TYPE_HAS_FW_2);
+	if (type_flags & DST_TYPE_HAS_FW_3)
+		dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 3", DST_TYPE_HAS_FW_3);
+	dprintk(verbose, DST_ERROR, 0, "\n");
+}
+
+
+static int dst_type_print(struct dst_state *state, u8 type)
+{
+	char *otype;
+	switch (type) {
+	case DST_TYPE_IS_SAT:
+		otype = "satellite";
+		break;
+
+	case DST_TYPE_IS_TERR:
+		otype = "terrestrial";
+		break;
+
+	case DST_TYPE_IS_CABLE:
+		otype = "cable";
+		break;
+
+	case DST_TYPE_IS_ATSC:
+		otype = "atsc";
+		break;
+
+	default:
+		dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type);
+		return -EINVAL;
+	}
+	dprintk(verbose, DST_INFO, 1, "DST type: %s", otype);
+
+	return 0;
+}
+
+static struct tuner_types tuner_list[] = {
+	{
+		.tuner_type = TUNER_TYPE_L64724,
+		.tuner_name = "L 64724",
+		.board_name = "UNKNOWN",
+		.fw_name    = "UNKNOWN"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_STV0299,
+		.tuner_name = "STV 0299",
+		.board_name = "VP1020",
+		.fw_name    = "DST-MOT"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_STV0299,
+		.tuner_name = "STV 0299",
+		.board_name = "VP1020",
+		.fw_name    = "DST-03T"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_MB86A15,
+		.tuner_name = "MB 86A15",
+		.board_name = "VP1022",
+		.fw_name    = "DST-03T"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_MB86A15,
+		.tuner_name = "MB 86A15",
+		.board_name = "VP1025",
+		.fw_name    = "DST-03T"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_STV0299,
+		.tuner_name = "STV 0299",
+		.board_name = "VP1030",
+		.fw_name    = "DST-CI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_STV0299,
+		.tuner_name = "STV 0299",
+		.board_name = "VP1030",
+		.fw_name    = "DSTMCI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP2021",
+		.fw_name    = "DCTNEW"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP2030",
+		.fw_name    = "DCT-CI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP2031",
+		.fw_name    = "DCT-CI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP2040",
+		.fw_name    = "DCT-CI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP3020",
+		.fw_name    = "DTTFTA"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP3021",
+		.fw_name    = "DTTFTA"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_TDA10046,
+		.tuner_name = "TDA10046",
+		.board_name = "VP3040",
+		.fw_name    = "DTT-CI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP3051",
+		.fw_name    = "DTTNXT"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_NXT200x,
+		.tuner_name = "NXT200x",
+		.board_name = "VP3220",
+		.fw_name    = "ATSCDI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_NXT200x,
+		.tuner_name = "NXT200x",
+		.board_name = "VP3250",
+		.fw_name    = "ATSCAD"
+	},
+};
+
+/*
+	Known cards list
+	Satellite
+	-------------------
+		  200103A
+	VP-1020   DST-MOT	LG(old), TS=188
+
+	VP-1020   DST-03T	LG(new), TS=204
+	VP-1022   DST-03T	LG(new), TS=204
+	VP-1025   DST-03T	LG(new), TS=204
+
+	VP-1030   DSTMCI,	LG(new), TS=188
+	VP-1032   DSTMCI,	LG(new), TS=188
+
+	Cable
+	-------------------
+	VP-2030   DCT-CI,	Samsung, TS=204
+	VP-2021   DCT-CI,	Unknown, TS=204
+	VP-2031   DCT-CI,	Philips, TS=188
+	VP-2040   DCT-CI,	Philips, TS=188, with CA daughter board
+	VP-2040   DCT-CI,	Philips, TS=204, without CA daughter board
+
+	Terrestrial
+	-------------------
+	VP-3050  DTTNXT			 TS=188
+	VP-3040  DTT-CI,	Philips, TS=188
+	VP-3040  DTT-CI,	Philips, TS=204
+
+	ATSC
+	-------------------
+	VP-3220  ATSCDI,		 TS=188
+	VP-3250  ATSCAD,		 TS=188
+
+*/
+
+static struct dst_types dst_tlist[] = {
+	{
+		.device_id = "200103A",
+		.offset = 0,
+		.dst_type =  DST_TYPE_IS_SAT,
+		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS,
+		.dst_feature = 0,
+		.tuner_type = 0
+	},	/*	obsolete	*/
+
+	{
+		.device_id = "DST-020",
+		.offset = 0,
+		.dst_type =  DST_TYPE_IS_SAT,
+		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
+		.dst_feature = 0,
+		.tuner_type = 0
+	},	/*	obsolete	*/
+
+	{
+		.device_id = "DST-030",
+		.offset =  0,
+		.dst_type = DST_TYPE_IS_SAT,
+		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
+		.dst_feature = 0,
+		.tuner_type = 0
+	},	/*	obsolete	*/
+
+	{
+		.device_id = "DST-03T",
+		.offset = 0,
+		.dst_type = DST_TYPE_IS_SAT,
+		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2,
+		.dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5
+							 | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO,
+		.tuner_type = TUNER_TYPE_MULTI
+	 },
+
+	{
+		.device_id = "DST-MOT",
+		.offset =  0,
+		.dst_type = DST_TYPE_IS_SAT,
+		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
+		.dst_feature = 0,
+		.tuner_type = 0
+	},	/*	obsolete	*/
+
+	{
+		.device_id = "DST-CI",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_SAT,
+		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_1,
+		.dst_feature = DST_TYPE_HAS_CA,
+		.tuner_type = 0
+	},	/*	An OEM board	*/
+
+	{
+		.device_id = "DSTMCI",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_SAT,
+		.type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT | DST_TYPE_HAS_VLF,
+		.dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4
+							| DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC,
+		.tuner_type = TUNER_TYPE_MULTI
+	},
+
+	{
+		.device_id = "DSTFCI",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_SAT,
+		.type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
+		.dst_feature = 0,
+		.tuner_type = 0
+	},	/* unknown to vendor	*/
+
+	{
+		.device_id = "DCT-CI",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_CABLE,
+		.type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_1	| DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_VLF,
+		.dst_feature = DST_TYPE_HAS_CA,
+		.tuner_type = 0
+	},
+
+	{
+		.device_id = "DCTNEW",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_CABLE,
+		.type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_MULTI_FE,
+		.dst_feature = 0,
+		.tuner_type = 0
+	},
+
+	{
+		.device_id = "DTT-CI",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_TERR,
+		.type_flags = DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_VLF,
+		.dst_feature = DST_TYPE_HAS_CA,
+		.tuner_type = 0
+	},
+
+	{
+		.device_id = "DTTDIG",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_TERR,
+		.type_flags = DST_TYPE_HAS_FW_2,
+		.dst_feature = 0,
+		.tuner_type = 0
+	},
+
+	{
+		.device_id = "DTTNXT",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_TERR,
+		.type_flags = DST_TYPE_HAS_FW_2,
+		.dst_feature = DST_TYPE_HAS_ANALOG,
+		.tuner_type = 0
+	},
+
+	{
+		.device_id = "ATSCDI",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_ATSC,
+		.type_flags = DST_TYPE_HAS_FW_2,
+		.dst_feature = 0,
+		.tuner_type = 0
+	},
+
+	{
+		.device_id = "ATSCAD",
+		.offset = 1,
+		.dst_type = DST_TYPE_IS_ATSC,
+		.type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD,
+		.dst_feature = DST_TYPE_HAS_MAC | DST_TYPE_HAS_ANALOG,
+		.tuner_type = 0
+	},
+
+	{ }
+
+};
+
+static int dst_get_mac(struct dst_state *state)
+{
+	u8 get_mac[] = { 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+	get_mac[7] = dst_check_sum(get_mac, 7);
+	if (dst_command(state, get_mac, 8) < 0) {
+		dprintk(verbose, DST_INFO, 1, "Unsupported Command");
+		return -1;
+	}
+	memset(&state->mac_address, '\0', 8);
+	memcpy(&state->mac_address, &state->rxbuffer, 6);
+	dprintk(verbose, DST_ERROR, 1, "MAC Address=[%pM]", state->mac_address);
+
+	return 0;
+}
+
+static int dst_fw_ver(struct dst_state *state)
+{
+	u8 get_ver[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+	get_ver[7] = dst_check_sum(get_ver, 7);
+	if (dst_command(state, get_ver, 8) < 0) {
+		dprintk(verbose, DST_INFO, 1, "Unsupported Command");
+		return -1;
+	}
+	memcpy(&state->fw_version, &state->rxbuffer, 8);
+	dprintk(verbose, DST_ERROR, 1, "Firmware Ver = %x.%x Build = %02x, on %x:%x, %x-%x-20%02x",
+		state->fw_version[0] >> 4, state->fw_version[0] & 0x0f,
+		state->fw_version[1],
+		state->fw_version[5], state->fw_version[6],
+		state->fw_version[4], state->fw_version[3], state->fw_version[2]);
+
+	return 0;
+}
+
+static int dst_card_type(struct dst_state *state)
+{
+	int j;
+	struct tuner_types *p_tuner_list = NULL;
+
+	u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+	get_type[7] = dst_check_sum(get_type, 7);
+	if (dst_command(state, get_type, 8) < 0) {
+		dprintk(verbose, DST_INFO, 1, "Unsupported Command");
+		return -1;
+	}
+	memset(&state->card_info, '\0', 8);
+	memcpy(&state->card_info, &state->rxbuffer, 7);
+	dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]);
+
+	for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
+		if (!strcmp(&state->card_info[0], p_tuner_list->board_name)) {
+			state->tuner_type = p_tuner_list->tuner_type;
+			dprintk(verbose, DST_ERROR, 1, "DST has [%s] tuner, tuner type=[%d]",
+				p_tuner_list->tuner_name, p_tuner_list->tuner_type);
+		}
+	}
+
+	return 0;
+}
+
+static int dst_get_vendor(struct dst_state *state)
+{
+	u8 get_vendor[] = { 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+	get_vendor[7] = dst_check_sum(get_vendor, 7);
+	if (dst_command(state, get_vendor, 8) < 0) {
+		dprintk(verbose, DST_INFO, 1, "Unsupported Command");
+		return -1;
+	}
+	memset(&state->vendor, '\0', 8);
+	memcpy(&state->vendor, &state->rxbuffer, 7);
+	dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]);
+
+	return 0;
+}
+
+static void debug_dst_buffer(struct dst_state *state)
+{
+	int i;
+
+	if (verbose > 2) {
+		printk("%s: [", __func__);
+		for (i = 0; i < 8; i++)
+			printk(" %02x", state->rxbuffer[i]);
+		printk("]\n");
+	}
+}
+
+static int dst_check_stv0299(struct dst_state *state)
+{
+	u8 check_stv0299[] = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+	check_stv0299[7] = dst_check_sum(check_stv0299, 7);
+	if (dst_command(state, check_stv0299, 8) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "Cmd=[0x04] failed");
+		return -1;
+	}
+	debug_dst_buffer(state);
+
+	if (memcmp(&check_stv0299, &state->rxbuffer, 8)) {
+		dprintk(verbose, DST_ERROR, 1, "Found a STV0299 NIM");
+		state->tuner_type = TUNER_TYPE_STV0299;
+		return 0;
+	}
+
+	return -1;
+}
+
+static int dst_check_mb86a15(struct dst_state *state)
+{
+	u8 check_mb86a15[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+	check_mb86a15[7] = dst_check_sum(check_mb86a15, 7);
+	if (dst_command(state, check_mb86a15, 8) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "Cmd=[0x10], failed");
+		return -1;
+	}
+	debug_dst_buffer(state);
+
+	if (memcmp(&check_mb86a15, &state->rxbuffer, 8) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "Found a MB86A15 NIM");
+		state->tuner_type = TUNER_TYPE_MB86A15;
+		return 0;
+	}
+
+	return -1;
+}
+
+static int dst_get_tuner_info(struct dst_state *state)
+{
+	u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+	u8 get_tuner_2[] = { 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+	get_tuner_1[7] = dst_check_sum(get_tuner_1, 7);
+	get_tuner_2[7] = dst_check_sum(get_tuner_2, 7);
+	dprintk(verbose, DST_ERROR, 1, "DST TYpe = MULTI FE");
+	if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
+		if (dst_command(state, get_tuner_1, 8) < 0) {
+			dprintk(verbose, DST_INFO, 1, "Cmd=[0x13], Unsupported");
+			goto force;
+		}
+	} else {
+		if (dst_command(state, get_tuner_2, 8) < 0) {
+			dprintk(verbose, DST_INFO, 1, "Cmd=[0xb], Unsupported");
+			goto force;
+		}
+	}
+	memcpy(&state->board_info, &state->rxbuffer, 8);
+	if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
+		dprintk(verbose, DST_ERROR, 1, "DST type has TS=188");
+	}
+	if (state->board_info[0] == 0xbc) {
+		if (state->dst_type != DST_TYPE_IS_ATSC)
+			state->type_flags |= DST_TYPE_HAS_TS188;
+		else
+			state->type_flags |= DST_TYPE_HAS_NEWTUNE_2;
+
+		if (state->board_info[1] == 0x01) {
+			state->dst_hw_cap |= DST_TYPE_HAS_DBOARD;
+			dprintk(verbose, DST_ERROR, 1, "DST has Daughterboard");
+		}
+	}
+
+	return 0;
+force:
+	if (!strncmp(state->fw_name, "DCT-CI", 6)) {
+		state->type_flags |= DST_TYPE_HAS_TS204;
+		dprintk(verbose, DST_ERROR, 1, "Forcing [%s] to TS188", state->fw_name);
+	}
+
+	return -1;
+}
+
+static int dst_get_device_id(struct dst_state *state)
+{
+	u8 reply;
+
+	int i, j;
+	struct dst_types *p_dst_type = NULL;
+	struct tuner_types *p_tuner_list = NULL;
+
+	u8 use_dst_type = 0;
+	u32 use_type_flags = 0;
+
+	static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
+
+	state->tuner_type = 0;
+	device_type[7] = dst_check_sum(device_type, 7);
+
+	if (write_dst(state, device_type, FIXED_COMM))
+		return -1;		/*	Write failed		*/
+	if ((dst_pio_disable(state)) < 0)
+		return -1;
+	if (read_dst(state, &reply, GET_ACK))
+		return -1;		/*	Read failure		*/
+	if (reply != ACK) {
+		dprintk(verbose, DST_INFO, 1, "Write not Acknowledged! [Reply=0x%02x]", reply);
+		return -1;		/*	Unack'd write		*/
+	}
+	if (!dst_wait_dst_ready(state, DEVICE_INIT))
+		return -1;		/*	DST not ready yet	*/
+	if (read_dst(state, state->rxbuffer, FIXED_COMM))
+		return -1;
+
+	dst_pio_disable(state);
+	if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) {
+		dprintk(verbose, DST_INFO, 1, "Checksum failure!");
+		return -1;		/*	Checksum failure	*/
+	}
+	state->rxbuffer[7] = '\0';
+
+	for (i = 0, p_dst_type = dst_tlist; i < ARRAY_SIZE(dst_tlist); i++, p_dst_type++) {
+		if (!strncmp (&state->rxbuffer[p_dst_type->offset], p_dst_type->device_id, strlen (p_dst_type->device_id))) {
+			use_type_flags = p_dst_type->type_flags;
+			use_dst_type = p_dst_type->dst_type;
+
+			/*	Card capabilities	*/
+			state->dst_hw_cap = p_dst_type->dst_feature;
+			dprintk(verbose, DST_ERROR, 1, "Recognise [%s]", p_dst_type->device_id);
+			strncpy(&state->fw_name[0], p_dst_type->device_id, 6);
+			/*	Multiple tuners		*/
+			if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) {
+				switch (use_dst_type) {
+				case DST_TYPE_IS_SAT:
+					/*	STV0299 check	*/
+					if (dst_check_stv0299(state) < 0) {
+						dprintk(verbose, DST_ERROR, 1, "Unsupported");
+						state->tuner_type = TUNER_TYPE_MB86A15;
+					}
+					break;
+				default:
+					break;
+				}
+				if (dst_check_mb86a15(state) < 0)
+					dprintk(verbose, DST_ERROR, 1, "Unsupported");
+			/*	Single tuner		*/
+			} else {
+				state->tuner_type = p_dst_type->tuner_type;
+			}
+			for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
+				if (!(strncmp(p_dst_type->device_id, p_tuner_list->fw_name, 7)) &&
+					p_tuner_list->tuner_type == state->tuner_type) {
+					dprintk(verbose, DST_ERROR, 1, "[%s] has a [%s]",
+						p_dst_type->device_id, p_tuner_list->tuner_name);
+				}
+			}
+			break;
+		}
+	}
+
+	if (i >= ARRAY_SIZE(dst_tlist)) {
+		dprintk(verbose, DST_ERROR, 1, "Unable to recognize %s or %s", &state->rxbuffer[0], &state->rxbuffer[1]);
+		dprintk(verbose, DST_ERROR, 1, "please email linux-dvb@linuxtv.org with this type in");
+		use_dst_type = DST_TYPE_IS_SAT;
+		use_type_flags = DST_TYPE_HAS_SYMDIV;
+	}
+	dst_type_print(state, use_dst_type);
+	state->type_flags = use_type_flags;
+	state->dst_type = use_dst_type;
+	dst_type_flags_print(state);
+
+	return 0;
+}
+
+static int dst_probe(struct dst_state *state)
+{
+	mutex_init(&state->dst_mutex);
+	if (dst_addons & DST_TYPE_HAS_CA) {
+		if ((rdc_8820_reset(state)) < 0) {
+			dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
+			return -1;
+		}
+		msleep(4000);
+	} else {
+		msleep(100);
+	}
+	if ((dst_comm_init(state)) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed.");
+		return -1;
+	}
+	msleep(100);
+	if (dst_get_device_id(state) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "unknown device.");
+		return -1;
+	}
+	if (dst_get_mac(state) < 0) {
+		dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command");
+	}
+	if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) {
+		if (dst_get_tuner_info(state) < 0)
+			dprintk(verbose, DST_INFO, 1, "Tuner: Unsupported command");
+	}
+	if (state->type_flags & DST_TYPE_HAS_TS204) {
+		dst_packsize(state, 204);
+	}
+	if (state->type_flags & DST_TYPE_HAS_FW_BUILD) {
+		if (dst_fw_ver(state) < 0) {
+			dprintk(verbose, DST_INFO, 1, "FW: Unsupported command");
+			return 0;
+		}
+		if (dst_card_type(state) < 0) {
+			dprintk(verbose, DST_INFO, 1, "Card: Unsupported command");
+			return 0;
+		}
+		if (dst_get_vendor(state) < 0) {
+			dprintk(verbose, DST_INFO, 1, "Vendor: Unsupported command");
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+static int dst_command(struct dst_state *state, u8 *data, u8 len)
+{
+	u8 reply;
+
+	mutex_lock(&state->dst_mutex);
+	if ((dst_comm_init(state)) < 0) {
+		dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed.");
+		goto error;
+	}
+	if (write_dst(state, data, len)) {
+		dprintk(verbose, DST_INFO, 1, "Trying to recover.. ");
+		if ((dst_error_recovery(state)) < 0) {
+			dprintk(verbose, DST_ERROR, 1, "Recovery Failed.");
+			goto error;
+		}
+		goto error;
+	}
+	if ((dst_pio_disable(state)) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "PIO Disable Failed.");
+		goto error;
+	}
+	if (state->type_flags & DST_TYPE_HAS_FW_1)
+		mdelay(3);
+	if (read_dst(state, &reply, GET_ACK)) {
+		dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. ");
+		if ((dst_error_recovery(state)) < 0) {
+			dprintk(verbose, DST_INFO, 1, "Recovery Failed.");
+			goto error;
+		}
+		goto error;
+	}
+	if (reply != ACK) {
+		dprintk(verbose, DST_INFO, 1, "write not acknowledged 0x%02x ", reply);
+		goto error;
+	}
+	if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3))
+		goto error;
+	if (state->type_flags & DST_TYPE_HAS_FW_1)
+		mdelay(3);
+	else
+		udelay(2000);
+	if (!dst_wait_dst_ready(state, NO_DELAY))
+		goto error;
+	if (read_dst(state, state->rxbuffer, FIXED_COMM)) {
+		dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. ");
+		if ((dst_error_recovery(state)) < 0) {
+			dprintk(verbose, DST_INFO, 1, "Recovery failed.");
+			goto error;
+		}
+		goto error;
+	}
+	if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) {
+		dprintk(verbose, DST_INFO, 1, "checksum failure");
+		goto error;
+	}
+	mutex_unlock(&state->dst_mutex);
+	return 0;
+
+error:
+	mutex_unlock(&state->dst_mutex);
+	return -EIO;
+
+}
+
+static int dst_get_signal(struct dst_state *state)
+{
+	int retval;
+	u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb };
+	//dprintk("%s: Getting Signal strength and other parameters\n", __func__);
+	if ((state->diseq_flags & ATTEMPT_TUNE) == 0) {
+		state->decode_lock = state->decode_strength = state->decode_snr = 0;
+		return 0;
+	}
+	if (0 == (state->diseq_flags & HAS_LOCK)) {
+		state->decode_lock = state->decode_strength = state->decode_snr = 0;
+		return 0;
+	}
+	if (time_after_eq(jiffies, state->cur_jiff + (HZ / 5))) {
+		retval = dst_command(state, get_signal, 8);
+		if (retval < 0)
+			return retval;
+		if (state->dst_type == DST_TYPE_IS_SAT) {
+			state->decode_lock = ((state->rxbuffer[6] & 0x10) == 0) ? 1 : 0;
+			state->decode_strength = state->rxbuffer[5] << 8;
+			state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3];
+		} else if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) {
+			state->decode_lock = (state->rxbuffer[1]) ? 1 : 0;
+			state->decode_strength = state->rxbuffer[4] << 8;
+			state->decode_snr = state->rxbuffer[3] << 8;
+		} else if (state->dst_type == DST_TYPE_IS_ATSC) {
+			state->decode_lock = (state->rxbuffer[6] == 0x00) ? 1 : 0;
+			state->decode_strength = state->rxbuffer[4] << 8;
+			state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3];
+		}
+		state->cur_jiff = jiffies;
+	}
+	return 0;
+}
+
+static int dst_tone_power_cmd(struct dst_state *state)
+{
+	u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 };
+
+	if (state->dst_type != DST_TYPE_IS_SAT)
+		return -EOPNOTSUPP;
+	paket[4] = state->tx_tuna[4];
+	paket[2] = state->tx_tuna[2];
+	paket[3] = state->tx_tuna[3];
+	paket[7] = dst_check_sum (paket, 7);
+	return dst_command(state, paket, 8);
+}
+
+static int dst_get_tuna(struct dst_state *state)
+{
+	int retval;
+
+	if ((state->diseq_flags & ATTEMPT_TUNE) == 0)
+		return 0;
+	state->diseq_flags &= ~(HAS_LOCK);
+	if (!dst_wait_dst_ready(state, NO_DELAY))
+		return -EIO;
+	if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+		!(state->dst_type == DST_TYPE_IS_ATSC))
+
+		retval = read_dst(state, state->rx_tuna, 10);
+	else
+		retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM);
+	if (retval < 0) {
+		dprintk(verbose, DST_DEBUG, 1, "read not successful");
+		return retval;
+	}
+	if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+	   !(state->dst_type == DST_TYPE_IS_ATSC)) {
+
+		if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
+			dprintk(verbose, DST_INFO, 1, "checksum failure ? ");
+			return -EIO;
+		}
+	} else {
+		if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) {
+			dprintk(verbose, DST_INFO, 1, "checksum failure? ");
+			return -EIO;
+		}
+	}
+	if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0)
+		return 0;
+	if (state->dst_type == DST_TYPE_IS_SAT) {
+		state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3];
+	} else {
+		state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 16) + (state->rx_tuna[3] << 8) + state->rx_tuna[4];
+	}
+	state->decode_freq = state->decode_freq * 1000;
+	state->decode_lock = 1;
+	state->diseq_flags |= HAS_LOCK;
+
+	return 1;
+}
+
+static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+
+static int dst_write_tuna(struct dvb_frontend *fe)
+{
+	struct dst_state *state = fe->demodulator_priv;
+	int retval;
+	u8 reply;
+
+	dprintk(verbose, DST_INFO, 1, "type_flags 0x%x ", state->type_flags);
+	state->decode_freq = 0;
+	state->decode_lock = state->decode_strength = state->decode_snr = 0;
+	if (state->dst_type == DST_TYPE_IS_SAT) {
+		if (!(state->diseq_flags & HAS_POWER))
+			dst_set_voltage(fe, SEC_VOLTAGE_13);
+	}
+	state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
+	mutex_lock(&state->dst_mutex);
+	if ((dst_comm_init(state)) < 0) {
+		dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed.");
+		goto error;
+	}
+//	if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+	if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+		(!(state->dst_type == DST_TYPE_IS_ATSC))) {
+
+		state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9);
+		retval = write_dst(state, &state->tx_tuna[0], 10);
+	} else {
+		state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7);
+		retval = write_dst(state, &state->tx_tuna[2], FIXED_COMM);
+	}
+	if (retval < 0) {
+		dst_pio_disable(state);
+		dprintk(verbose, DST_DEBUG, 1, "write not successful");
+		goto werr;
+	}
+	if ((dst_pio_disable(state)) < 0) {
+		dprintk(verbose, DST_DEBUG, 1, "DST PIO disable failed !");
+		goto error;
+	}
+	if ((read_dst(state, &reply, GET_ACK) < 0)) {
+		dprintk(verbose, DST_DEBUG, 1, "read verify not successful.");
+		goto error;
+	}
+	if (reply != ACK) {
+		dprintk(verbose, DST_DEBUG, 1, "write not acknowledged 0x%02x ", reply);
+		goto error;
+	}
+	state->diseq_flags |= ATTEMPT_TUNE;
+	retval = dst_get_tuna(state);
+werr:
+	mutex_unlock(&state->dst_mutex);
+	return retval;
+
+error:
+	mutex_unlock(&state->dst_mutex);
+	return -EIO;
+}
+
+/*
+ * line22k0    0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00
+ * line22k1    0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00
+ * line22k2    0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00
+ * tone        0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00
+ * data        0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00
+ * power_off   0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00
+ * power_on    0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00
+ * Diseqc 1    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec
+ * Diseqc 2    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8
+ * Diseqc 3    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4
+ * Diseqc 4    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0
+ */
+
+static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd)
+{
+	struct dst_state *state = fe->demodulator_priv;
+	u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec };
+
+	if (state->dst_type != DST_TYPE_IS_SAT)
+		return -EOPNOTSUPP;
+	if (cmd->msg_len > 0 && cmd->msg_len < 5)
+		memcpy(&paket[3], cmd->msg, cmd->msg_len);
+	else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5)
+		memcpy(&paket[2], cmd->msg, cmd->msg_len);
+	else
+		return -EINVAL;
+	paket[7] = dst_check_sum(&paket[0], 7);
+	return dst_command(state, paket, 8);
+}
+
+static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	int need_cmd, retval = 0;
+	struct dst_state *state = fe->demodulator_priv;
+
+	state->voltage = voltage;
+	if (state->dst_type != DST_TYPE_IS_SAT)
+		return -EOPNOTSUPP;
+
+	need_cmd = 0;
+
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+	case SEC_VOLTAGE_18:
+		if ((state->diseq_flags & HAS_POWER) == 0)
+			need_cmd = 1;
+		state->diseq_flags |= HAS_POWER;
+		state->tx_tuna[4] = 0x01;
+		break;
+	case SEC_VOLTAGE_OFF:
+		need_cmd = 1;
+		state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE);
+		state->tx_tuna[4] = 0x00;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (need_cmd)
+		retval = dst_tone_power_cmd(state);
+
+	return retval;
+}
+
+static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct dst_state *state = fe->demodulator_priv;
+
+	state->tone = tone;
+	if (state->dst_type != DST_TYPE_IS_SAT)
+		return -EOPNOTSUPP;
+
+	switch (tone) {
+	case SEC_TONE_OFF:
+		if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+		    state->tx_tuna[2] = 0x00;
+		else
+		    state->tx_tuna[2] = 0xff;
+		break;
+
+	case SEC_TONE_ON:
+		state->tx_tuna[2] = 0x02;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return dst_tone_power_cmd(state);
+}
+
+static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd)
+{
+	struct dst_state *state = fe->demodulator_priv;
+
+	if (state->dst_type != DST_TYPE_IS_SAT)
+		return -EOPNOTSUPP;
+	state->minicmd = minicmd;
+	switch (minicmd) {
+	case SEC_MINI_A:
+		state->tx_tuna[3] = 0x02;
+		break;
+	case SEC_MINI_B:
+		state->tx_tuna[3] = 0xff;
+		break;
+	}
+	return dst_tone_power_cmd(state);
+}
+
+
+static int dst_init(struct dvb_frontend *fe)
+{
+	struct dst_state *state = fe->demodulator_priv;
+
+	static u8 sat_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x00, 0x73, 0x21, 0x00, 0x00 };
+	static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 };
+	static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
+	static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
+	static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
+	static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
+	static u8 atsc_tuner[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
+
+	state->inversion = INVERSION_OFF;
+	state->voltage = SEC_VOLTAGE_13;
+	state->tone = SEC_TONE_OFF;
+	state->diseq_flags = 0;
+	state->k22 = 0x02;
+	state->bandwidth = 7000000;
+	state->cur_jiff = jiffies;
+	if (state->dst_type == DST_TYPE_IS_SAT)
+		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204));
+	else if (state->dst_type == DST_TYPE_IS_TERR)
+		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204));
+	else if (state->dst_type == DST_TYPE_IS_CABLE)
+		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204));
+	else if (state->dst_type == DST_TYPE_IS_ATSC)
+		memcpy(state->tx_tuna, atsc_tuner, sizeof (atsc_tuner));
+
+	return 0;
+}
+
+static int dst_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct dst_state *state = fe->demodulator_priv;
+
+	*status = 0;
+	if (state->diseq_flags & HAS_LOCK) {
+//		dst_get_signal(state);	// don't require(?) to ask MCU
+		if (state->decode_lock)
+			*status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI;
+	}
+
+	return 0;
+}
+
+static int dst_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct dst_state *state = fe->demodulator_priv;
+
+	int retval = dst_get_signal(state);
+	*strength = state->decode_strength;
+
+	return retval;
+}
+
+static int dst_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct dst_state *state = fe->demodulator_priv;
+
+	int retval = dst_get_signal(state);
+	*snr = state->decode_snr;
+
+	return retval;
+}
+
+static int dst_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	int retval = -EINVAL;
+	struct dst_state *state = fe->demodulator_priv;
+
+	if (p != NULL) {
+		retval = dst_set_freq(state, p->frequency);
+		if(retval != 0)
+			return retval;
+		dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
+
+		if (state->dst_type == DST_TYPE_IS_SAT) {
+			if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+				dst_set_inversion(state, p->inversion);
+			dst_set_fec(state, p->fec_inner);
+			dst_set_symbolrate(state, p->symbol_rate);
+			dst_set_polarization(state);
+			dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate);
+
+		} else if (state->dst_type == DST_TYPE_IS_TERR)
+			dst_set_bandwidth(state, p->bandwidth_hz);
+		else if (state->dst_type == DST_TYPE_IS_CABLE) {
+			dst_set_fec(state, p->fec_inner);
+			dst_set_symbolrate(state, p->symbol_rate);
+			dst_set_modulation(state, p->modulation);
+		}
+		retval = dst_write_tuna(fe);
+	}
+
+	return retval;
+}
+
+static int dst_tune_frontend(struct dvb_frontend* fe,
+			    bool re_tune,
+			    unsigned int mode_flags,
+			    unsigned int *delay,
+			    fe_status_t *status)
+{
+	struct dst_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+	if (re_tune) {
+		dst_set_freq(state, p->frequency);
+		dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
+
+		if (state->dst_type == DST_TYPE_IS_SAT) {
+			if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+				dst_set_inversion(state, p->inversion);
+			dst_set_fec(state, p->fec_inner);
+			dst_set_symbolrate(state, p->symbol_rate);
+			dst_set_polarization(state);
+			dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate);
+
+		} else if (state->dst_type == DST_TYPE_IS_TERR)
+			dst_set_bandwidth(state, p->bandwidth_hz);
+		else if (state->dst_type == DST_TYPE_IS_CABLE) {
+			dst_set_fec(state, p->fec_inner);
+			dst_set_symbolrate(state, p->symbol_rate);
+			dst_set_modulation(state, p->modulation);
+		}
+		dst_write_tuna(fe);
+	}
+
+	if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
+		dst_read_status(fe, status);
+
+	*delay = HZ/10;
+	return 0;
+}
+
+static int dst_get_tuning_algo(struct dvb_frontend *fe)
+{
+	return dst_algo ? DVBFE_ALGO_HW : DVBFE_ALGO_SW;
+}
+
+static int dst_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct dst_state *state = fe->demodulator_priv;
+
+	p->frequency = state->decode_freq;
+	if (state->dst_type == DST_TYPE_IS_SAT) {
+		if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+			p->inversion = state->inversion;
+		p->symbol_rate = state->symbol_rate;
+		p->fec_inner = dst_get_fec(state);
+	} else if (state->dst_type == DST_TYPE_IS_TERR) {
+		p->bandwidth_hz = state->bandwidth;
+	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
+		p->symbol_rate = state->symbol_rate;
+		p->fec_inner = dst_get_fec(state);
+		p->modulation = dst_get_modulation(state);
+	}
+
+	return 0;
+}
+
+static void dst_release(struct dvb_frontend *fe)
+{
+	struct dst_state *state = fe->demodulator_priv;
+	if (state->dst_ca) {
+		dvb_unregister_device(state->dst_ca);
+#ifdef CONFIG_MEDIA_ATTACH
+		symbol_put(dst_ca_attach);
+#endif
+	}
+	kfree(state);
+}
+
+static struct dvb_frontend_ops dst_dvbt_ops;
+static struct dvb_frontend_ops dst_dvbs_ops;
+static struct dvb_frontend_ops dst_dvbc_ops;
+static struct dvb_frontend_ops dst_atsc_ops;
+
+struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter)
+{
+	/* check if the ASIC is there */
+	if (dst_probe(state) < 0) {
+		kfree(state);
+		return NULL;
+	}
+	/* determine settings based on type */
+	/* create dvb_frontend */
+	switch (state->dst_type) {
+	case DST_TYPE_IS_TERR:
+		memcpy(&state->frontend.ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
+		break;
+	case DST_TYPE_IS_CABLE:
+		memcpy(&state->frontend.ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
+		break;
+	case DST_TYPE_IS_SAT:
+		memcpy(&state->frontend.ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
+		break;
+	case DST_TYPE_IS_ATSC:
+		memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops));
+		break;
+	default:
+		dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist.");
+		kfree(state);
+		return NULL;
+	}
+	state->frontend.demodulator_priv = state;
+
+	return state;				/*	Manu (DST is a card not a frontend)	*/
+}
+
+EXPORT_SYMBOL(dst_attach);
+
+static struct dvb_frontend_ops dst_dvbt_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "DST DVB-T",
+		.frequency_min = 137000000,
+		.frequency_max = 858000000,
+		.frequency_stepsize = 166667,
+		.caps = FE_CAN_FEC_AUTO			|
+			FE_CAN_QAM_AUTO			|
+			FE_CAN_QAM_16			|
+			FE_CAN_QAM_32			|
+			FE_CAN_QAM_64			|
+			FE_CAN_QAM_128			|
+			FE_CAN_QAM_256			|
+			FE_CAN_TRANSMISSION_MODE_AUTO	|
+			FE_CAN_GUARD_INTERVAL_AUTO
+	},
+
+	.release = dst_release,
+	.init = dst_init,
+	.tune = dst_tune_frontend,
+	.set_frontend = dst_set_frontend,
+	.get_frontend = dst_get_frontend,
+	.get_frontend_algo = dst_get_tuning_algo,
+	.read_status = dst_read_status,
+	.read_signal_strength = dst_read_signal_strength,
+	.read_snr = dst_read_snr,
+};
+
+static struct dvb_frontend_ops dst_dvbs_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name = "DST DVB-S",
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		.frequency_stepsize = 1000,	/* kHz for QPSK frontends */
+		.frequency_tolerance = 29500,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+	/*     . symbol_rate_tolerance	=	???,*/
+		.caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK
+	},
+
+	.release = dst_release,
+	.init = dst_init,
+	.tune = dst_tune_frontend,
+	.set_frontend = dst_set_frontend,
+	.get_frontend = dst_get_frontend,
+	.get_frontend_algo = dst_get_tuning_algo,
+	.read_status = dst_read_status,
+	.read_signal_strength = dst_read_signal_strength,
+	.read_snr = dst_read_snr,
+	.diseqc_send_burst = dst_send_burst,
+	.diseqc_send_master_cmd = dst_set_diseqc,
+	.set_voltage = dst_set_voltage,
+	.set_tone = dst_set_tone,
+};
+
+static struct dvb_frontend_ops dst_dvbc_ops = {
+	.delsys = { SYS_DVBC_ANNEX_A },
+	.info = {
+		.name = "DST DVB-C",
+		.frequency_stepsize = 62500,
+		.frequency_min = 51000000,
+		.frequency_max = 858000000,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+		.caps = FE_CAN_FEC_AUTO |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_QAM_16	|
+			FE_CAN_QAM_32	|
+			FE_CAN_QAM_64	|
+			FE_CAN_QAM_128	|
+			FE_CAN_QAM_256
+	},
+
+	.release = dst_release,
+	.init = dst_init,
+	.tune = dst_tune_frontend,
+	.set_frontend = dst_set_frontend,
+	.get_frontend = dst_get_frontend,
+	.get_frontend_algo = dst_get_tuning_algo,
+	.read_status = dst_read_status,
+	.read_signal_strength = dst_read_signal_strength,
+	.read_snr = dst_read_snr,
+};
+
+static struct dvb_frontend_ops dst_atsc_ops = {
+	.delsys = { SYS_ATSC },
+	.info = {
+		.name = "DST ATSC",
+		.frequency_stepsize = 62500,
+		.frequency_min = 510000000,
+		.frequency_max = 858000000,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+		.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+	},
+
+	.release = dst_release,
+	.init = dst_init,
+	.tune = dst_tune_frontend,
+	.set_frontend = dst_set_frontend,
+	.get_frontend = dst_get_frontend,
+	.get_frontend_algo = dst_get_tuning_algo,
+	.read_status = dst_read_status,
+	.read_signal_strength = dst_read_signal_strength,
+	.read_snr = dst_read_snr,
+};
+
+MODULE_DESCRIPTION("DST DVB-S/T/C/ATSC Combo Frontend driver");
+MODULE_AUTHOR("Jamie Honan, Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c
new file mode 100644
index 0000000..ee3884f
--- /dev/null
+++ b/drivers/media/pci/bt8xx/dst_ca.c
@@ -0,0 +1,726 @@
+/*
+	CA-driver for TwinHan DST Frontend/Card
+
+	Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/dvb/ca.h>
+#include "dvbdev.h"
+#include "dvb_frontend.h"
+#include "dst_ca.h"
+#include "dst_common.h"
+
+#define DST_CA_ERROR		0
+#define DST_CA_NOTICE		1
+#define DST_CA_INFO		2
+#define DST_CA_DEBUG		3
+
+#define dprintk(x, y, z, format, arg...) do {						\
+	if (z) {									\
+		if	((x > DST_CA_ERROR) && (x > y))					\
+			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);	\
+		else if	((x > DST_CA_NOTICE) && (x > y))				\
+			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
+		else if ((x > DST_CA_INFO) && (x > y))					\
+			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);	\
+		else if ((x > DST_CA_DEBUG) && (x > y))					\
+			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
+	} else {									\
+		if (x > y)								\
+			printk(format, ## arg);						\
+	}										\
+} while(0)
+
+
+static DEFINE_MUTEX(dst_ca_mutex);
+static unsigned int verbose = 5;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+
+/*	Need some more work	*/
+static int ca_set_slot_descr(void)
+{
+	/*	We could make this more graceful ?	*/
+	return -EOPNOTSUPP;
+}
+
+/*	Need some more work	*/
+static int ca_set_pid(void)
+{
+	/*	We could make this more graceful ?	*/
+	return -EOPNOTSUPP;
+}
+
+static void put_command_and_length(u8 *data, int command, int length)
+{
+	data[0] = (command >> 16) & 0xff;
+	data[1] = (command >> 8) & 0xff;
+	data[2] = command & 0xff;
+	data[3] = length;
+}
+
+static void put_checksum(u8 *check_string, int length)
+{
+	dprintk(verbose, DST_CA_DEBUG, 1, " Computing string checksum.");
+	dprintk(verbose, DST_CA_DEBUG, 1, "  -> string length : 0x%02x", length);
+	check_string[length] = dst_check_sum (check_string, length);
+	dprintk(verbose, DST_CA_DEBUG, 1, "  -> checksum      : 0x%02x", check_string[length]);
+}
+
+static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read)
+{
+	u8 reply;
+
+	mutex_lock(&state->dst_mutex);
+	dst_comm_init(state);
+	msleep(65);
+
+	if (write_dst(state, data, len)) {
+		dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover");
+		dst_error_recovery(state);
+		goto error;
+	}
+	if ((dst_pio_disable(state)) < 0) {
+		dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed.");
+		goto error;
+	}
+	if (read_dst(state, &reply, GET_ACK) < 0) {
+		dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
+		dst_error_recovery(state);
+		goto error;
+	}
+	if (read) {
+		if (! dst_wait_dst_ready(state, LONG_DELAY)) {
+			dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready");
+			goto error;
+		}
+		if (read_dst(state, ca_string, 128) < 0) {	/*	Try to make this dynamic	*/
+			dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
+			dst_error_recovery(state);
+			goto error;
+		}
+	}
+	mutex_unlock(&state->dst_mutex);
+	return 0;
+
+error:
+	mutex_unlock(&state->dst_mutex);
+	return -EIO;
+}
+
+
+static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, int read)
+{
+	u8 dst_ca_comm_err = 0;
+
+	while (dst_ca_comm_err < RETRIES) {
+		dprintk(verbose, DST_CA_NOTICE, 1, " Put Command");
+		if (dst_ci_command(state, data, ca_string, len, read)) {	// If error
+			dst_error_recovery(state);
+			dst_ca_comm_err++; // work required here.
+		} else {
+			break;
+		}
+	}
+
+	if(dst_ca_comm_err == RETRIES)
+		return -1;
+
+	return 0;
+}
+
+
+
+static int ca_get_app_info(struct dst_state *state)
+{
+	int length, str_length;
+	static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff};
+
+	put_checksum(&command[0], command[0]);
+	if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) {
+		dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
+		return -1;
+	}
+	dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
+	dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================");
+	dprintk(verbose, DST_CA_INFO, 1, " Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]",
+		state->messages[7], (state->messages[8] << 8) | state->messages[9],
+		(state->messages[10] << 8) | state->messages[11], __func__, (char *)(&state->messages[12]));
+	dprintk(verbose, DST_CA_INFO, 1, " ==================================================================================================");
+
+	// Transform dst message to correct application_info message
+	length = state->messages[5];
+	str_length = length - 6;
+	if (str_length < 0) {
+		str_length = 0;
+		dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering.");
+	}
+
+	// First, the command and length fields
+	put_command_and_length(&state->messages[0], CA_APP_INFO, length);
+
+	// Copy application_type, application_manufacturer and manufacturer_code
+	memcpy(&state->messages[4], &state->messages[7], 5);
+
+	// Set string length and copy string
+	state->messages[9] = str_length;
+	memcpy(&state->messages[10], &state->messages[12], str_length);
+
+	return 0;
+}
+
+static int ca_get_ca_info(struct dst_state *state)
+{
+	int srcPtr, dstPtr, i, num_ids;
+	static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff};
+	const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7;
+
+	put_checksum(&slot_command[0], slot_command[0]);
+	if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) {
+		dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
+		return -1;
+	}
+	dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
+
+	// Print raw data
+	dprintk(verbose, DST_CA_INFO, 0, " DST data = [");
+	for (i = 0; i < state->messages[0] + 1; i++) {
+		dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]);
+	}
+	dprintk(verbose, DST_CA_INFO, 0, "]\n");
+
+	// Set the command and length of the output
+	num_ids = state->messages[in_num_ids_pos];
+	if (num_ids >= 100) {
+		num_ids = 100;
+		dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering.");
+	}
+	put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2);
+
+	dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = [");
+	srcPtr = in_system_id_pos;
+	dstPtr = out_system_id_pos;
+	for(i = 0; i < num_ids; i++) {
+		dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]);
+		// Append to output
+		state->messages[dstPtr + 0] = state->messages[srcPtr + 0];
+		state->messages[dstPtr + 1] = state->messages[srcPtr + 1];
+		srcPtr += 2;
+		dstPtr += 2;
+	}
+	dprintk(verbose, DST_CA_INFO, 0, "]\n");
+
+	return 0;
+}
+
+static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void __user *arg)
+{
+	int i;
+	u8 slot_cap[256];
+	static u8 slot_command[8] = {0x07, 0x40, 0x02, 0x00, 0x02, 0x00, 0x00, 0xff};
+
+	put_checksum(&slot_command[0], slot_command[0]);
+	if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) {
+		dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
+		return -1;
+	}
+	dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !");
+
+	/*	Will implement the rest soon		*/
+
+	dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]);
+	dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
+	for (i = 0; i < slot_cap[0] + 1; i++)
+		dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]);
+	dprintk(verbose, DST_CA_INFO, 0, "\n");
+
+	p_ca_caps->slot_num = 1;
+	p_ca_caps->slot_type = 1;
+	p_ca_caps->descr_num = slot_cap[7];
+	p_ca_caps->descr_type = 1;
+
+	if (copy_to_user(arg, p_ca_caps, sizeof (struct ca_caps)))
+		return -EFAULT;
+
+	return 0;
+}
+
+/*	Need some more work	*/
+static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
+{
+	return -EOPNOTSUPP;
+}
+
+
+static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void __user *arg)
+{
+	int i;
+	static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
+
+	u8 *slot_info = state->messages;
+
+	put_checksum(&slot_command[0], 7);
+	if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) {
+		dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
+		return -1;
+	}
+	dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
+
+	/*	Will implement the rest soon		*/
+
+	dprintk(verbose, DST_CA_INFO, 1, " Slot info = [%d]", slot_info[3]);
+	dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
+	for (i = 0; i < 8; i++)
+		dprintk(verbose, DST_CA_INFO, 0, " %d", slot_info[i]);
+	dprintk(verbose, DST_CA_INFO, 0, "\n");
+
+	if (slot_info[4] & 0x80) {
+		p_ca_slot_info->flags = CA_CI_MODULE_PRESENT;
+		p_ca_slot_info->num = 1;
+		p_ca_slot_info->type = CA_CI;
+	} else if (slot_info[4] & 0x40) {
+		p_ca_slot_info->flags = CA_CI_MODULE_READY;
+		p_ca_slot_info->num = 1;
+		p_ca_slot_info->type = CA_CI;
+	} else
+		p_ca_slot_info->flags = 0;
+
+	if (copy_to_user(arg, p_ca_slot_info, sizeof (struct ca_slot_info)))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
+{
+	u8 i = 0;
+	u32 command = 0;
+
+	if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg)))
+		return -EFAULT;
+
+	if (p_ca_message->msg) {
+		dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%*ph]",
+			3, p_ca_message->msg);
+
+		for (i = 0; i < 3; i++) {
+			command = command | p_ca_message->msg[i];
+			if (i < 2)
+				command = command << 8;
+		}
+		dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command);
+
+		switch (command) {
+		case CA_APP_INFO:
+			memcpy(p_ca_message->msg, state->messages, 128);
+			if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
+				return -EFAULT;
+			break;
+		case CA_INFO:
+			memcpy(p_ca_message->msg, state->messages, 128);
+			if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
+				return -EFAULT;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length)
+{
+	if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) {
+		hw_buffer->msg[2] = p_ca_message->msg[1];	/*	MSB	*/
+		hw_buffer->msg[3] = p_ca_message->msg[2];	/*	LSB	*/
+	} else {
+		if (length > 247) {
+			dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !");
+			return -1;
+		}
+		hw_buffer->msg[0] = (length & 0xff) + 7;
+		hw_buffer->msg[1] = 0x40;
+		hw_buffer->msg[2] = 0x03;
+		hw_buffer->msg[3] = 0x00;
+		hw_buffer->msg[4] = 0x03;
+		hw_buffer->msg[5] = length & 0xff;
+		hw_buffer->msg[6] = 0x00;
+
+		/*
+		 *	Need to compute length for EN50221 section 8.3.2, for the time being
+		 *	assuming 8.3.2 is not applicable
+		 */
+		memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length);
+	}
+
+	return 0;
+}
+
+static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply)
+{
+	if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) {
+		dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed.");
+		dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST.");
+		rdc_reset_state(state);
+		return -1;
+	}
+	dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success.");
+
+	return 0;
+}
+
+static u32 asn_1_decode(u8 *asn_1_array)
+{
+	u8 length_field = 0, word_count = 0, count = 0;
+	u32 length = 0;
+
+	length_field = asn_1_array[0];
+	dprintk(verbose, DST_CA_DEBUG, 1, " Length field=[%02x]", length_field);
+	if (length_field < 0x80) {
+		length = length_field & 0x7f;
+		dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%02x]\n", length);
+	} else {
+		word_count = length_field & 0x7f;
+		for (count = 0; count < word_count; count++) {
+			length = length  << 8;
+			length += asn_1_array[count + 1];
+			dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length);
+		}
+	}
+	return length;
+}
+
+static int debug_string(u8 *msg, u32 length, u32 offset)
+{
+	u32 i;
+
+	dprintk(verbose, DST_CA_DEBUG, 0, " String=[ ");
+	for (i = offset; i < length; i++)
+		dprintk(verbose, DST_CA_DEBUG, 0, "%02x ", msg[i]);
+	dprintk(verbose, DST_CA_DEBUG, 0, "]\n");
+
+	return 0;
+}
+
+
+static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
+{
+	u32 length = 0;
+	u8 tag_length = 8;
+
+	length = asn_1_decode(&p_ca_message->msg[3]);
+	dprintk(verbose, DST_CA_DEBUG, 1, " CA Message length=[%d]", length);
+	debug_string(&p_ca_message->msg[4], length, 0); /*	length is excluding tag & length	*/
+
+	memset(hw_buffer->msg, '\0', length);
+	handle_dst_tag(state, p_ca_message, hw_buffer, length);
+	put_checksum(hw_buffer->msg, hw_buffer->msg[0]);
+
+	debug_string(hw_buffer->msg, (length + tag_length), 0); /*	tags too	*/
+	write_to_8820(state, hw_buffer, (length + tag_length), reply);
+
+	return 0;
+}
+
+
+/*	Board supports CA PMT reply ?		*/
+static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
+{
+	int ca_pmt_reply_test = 0;
+
+	/*	Do test board			*/
+	/*	Not there yet but soon		*/
+
+	/*	CA PMT Reply capable		*/
+	if (ca_pmt_reply_test) {
+		if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) {
+			dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
+			return -1;
+		}
+
+	/*	Process CA PMT Reply		*/
+	/*	will implement soon		*/
+		dprintk(verbose, DST_CA_ERROR, 1, " Not there yet");
+	}
+	/*	CA PMT Reply not capable	*/
+	if (!ca_pmt_reply_test) {
+		if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) {
+			dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
+			return -1;
+		}
+		dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !");
+	/*	put a dummy message		*/
+
+	}
+	return 0;
+}
+
+static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
+{
+	int i = 0;
+
+	u32 command = 0;
+	struct ca_msg *hw_buffer;
+	int result = 0;
+
+	if ((hw_buffer = kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
+		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
+		return -ENOMEM;
+	}
+	dprintk(verbose, DST_CA_DEBUG, 1, " ");
+
+	if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) {
+		result = -EFAULT;
+		goto free_mem_and_exit;
+	}
+
+
+	if (p_ca_message->msg) {
+		/*	EN50221 tag	*/
+		command = 0;
+
+		for (i = 0; i < 3; i++) {
+			command = command | p_ca_message->msg[i];
+			if (i < 2)
+				command = command << 8;
+		}
+		dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command);
+
+		switch (command) {
+		case CA_PMT:
+			dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT");
+			if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) {	// code simplification started
+				dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !");
+				result = -1;
+				goto free_mem_and_exit;
+			}
+			dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !");
+			break;
+		case CA_PMT_REPLY:
+			dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY");
+			/*      Have to handle the 2 basic types of cards here  */
+			if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) {
+				dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !");
+				result = -1;
+				goto free_mem_and_exit;
+			}
+			dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !");
+			break;
+		case CA_APP_INFO_ENQUIRY:		// only for debugging
+			dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information");
+
+			if ((ca_get_app_info(state)) < 0) {
+				dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !");
+				result = -1;
+				goto free_mem_and_exit;
+			}
+			dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
+			break;
+		case CA_INFO_ENQUIRY:
+			dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information");
+
+			if ((ca_get_ca_info(state)) < 0) {
+				dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !");
+				result = -1;
+				goto free_mem_and_exit;
+			}
+			dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !");
+			break;
+		}
+	}
+free_mem_and_exit:
+	kfree (hw_buffer);
+
+	return result;
+}
+
+static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioctl_arg)
+{
+	struct dvb_device *dvbdev;
+	struct dst_state *state;
+	struct ca_slot_info *p_ca_slot_info;
+	struct ca_caps *p_ca_caps;
+	struct ca_msg *p_ca_message;
+	void __user *arg = (void __user *)ioctl_arg;
+	int result = 0;
+
+	mutex_lock(&dst_ca_mutex);
+	dvbdev = file->private_data;
+	state = (struct dst_state *)dvbdev->priv;
+	p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
+	p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
+	p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL);
+	if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) {
+		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
+		result = -ENOMEM;
+		goto free_mem_and_exit;
+	}
+
+	/*	We have now only the standard ioctl's, the driver is upposed to handle internals.	*/
+	switch (cmd) {
+	case CA_SEND_MSG:
+		dprintk(verbose, DST_CA_INFO, 1, " Sending message");
+		if ((ca_send_message(state, p_ca_message, arg)) < 0) {
+			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !");
+			result = -1;
+			goto free_mem_and_exit;
+		}
+		break;
+	case CA_GET_MSG:
+		dprintk(verbose, DST_CA_INFO, 1, " Getting message");
+		if ((ca_get_message(state, p_ca_message, arg)) < 0) {
+			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !");
+			result = -1;
+			goto free_mem_and_exit;
+		}
+		dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !");
+		break;
+	case CA_RESET:
+		dprintk(verbose, DST_CA_ERROR, 1, " Resetting DST");
+		dst_error_bailout(state);
+		msleep(4000);
+		break;
+	case CA_GET_SLOT_INFO:
+		dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info");
+		if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) {
+			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !");
+			result = -1;
+			goto free_mem_and_exit;
+		}
+		dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !");
+		break;
+	case CA_GET_CAP:
+		dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities");
+		if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) {
+			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !");
+			result = -1;
+			goto free_mem_and_exit;
+		}
+		dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !");
+		break;
+	case CA_GET_DESCR_INFO:
+		dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description");
+		if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) {
+			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !");
+			result = -1;
+			goto free_mem_and_exit;
+		}
+		dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !");
+		break;
+	case CA_SET_DESCR:
+		dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler");
+		if ((ca_set_slot_descr()) < 0) {
+			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !");
+			result = -1;
+			goto free_mem_and_exit;
+		}
+		dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !");
+		break;
+	case CA_SET_PID:
+		dprintk(verbose, DST_CA_INFO, 1, " Setting PID");
+		if ((ca_set_pid()) < 0) {
+			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !");
+			result = -1;
+			goto free_mem_and_exit;
+		}
+		dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !");
+	default:
+		result = -EOPNOTSUPP;
+	};
+ free_mem_and_exit:
+	kfree (p_ca_message);
+	kfree (p_ca_slot_info);
+	kfree (p_ca_caps);
+
+	mutex_unlock(&dst_ca_mutex);
+	return result;
+}
+
+static int dst_ca_open(struct inode *inode, struct file *file)
+{
+	dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file);
+	try_module_get(THIS_MODULE);
+
+	return 0;
+}
+
+static int dst_ca_release(struct inode *inode, struct file *file)
+{
+	dprintk(verbose, DST_CA_DEBUG, 1, " Device closed.");
+	module_put(THIS_MODULE);
+
+	return 0;
+}
+
+static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
+{
+	ssize_t bytes_read = 0;
+
+	dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
+
+	return bytes_read;
+}
+
+static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
+{
+	dprintk(verbose, DST_CA_DEBUG, 1, " Device write.");
+
+	return 0;
+}
+
+static const struct file_operations dst_ca_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = dst_ca_ioctl,
+	.open = dst_ca_open,
+	.release = dst_ca_release,
+	.read = dst_ca_read,
+	.write = dst_ca_write,
+	.llseek = noop_llseek,
+};
+
+static struct dvb_device dvbdev_ca = {
+	.priv = NULL,
+	.users = 1,
+	.readers = 1,
+	.writers = 1,
+	.fops = &dst_ca_fops
+};
+
+struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter)
+{
+	struct dvb_device *dvbdev;
+
+	dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device");
+	if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) {
+		dst->dst_ca = dvbdev;
+		return dst->dst_ca;
+	}
+
+	return NULL;
+}
+
+EXPORT_SYMBOL(dst_ca_attach);
+
+MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/bt8xx/dst_ca.h b/drivers/media/pci/bt8xx/dst_ca.h
new file mode 100644
index 0000000..59cd0dd
--- /dev/null
+++ b/drivers/media/pci/bt8xx/dst_ca.h
@@ -0,0 +1,58 @@
+/*
+	CA-driver for TwinHan DST Frontend/Card
+
+	Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _DST_CA_H_
+#define _DST_CA_H_
+
+#define RETRIES			5
+
+
+#define	CA_APP_INFO_ENQUIRY	0x9f8020
+#define	CA_APP_INFO		0x9f8021
+#define	CA_ENTER_MENU		0x9f8022
+#define CA_INFO_ENQUIRY		0x9f8030
+#define	CA_INFO			0x9f8031
+#define CA_PMT			0x9f8032
+#define CA_PMT_REPLY		0x9f8033
+
+#define CA_CLOSE_MMI		0x9f8800
+#define CA_DISPLAY_CONTROL	0x9f8801
+#define CA_DISPLAY_REPLY	0x9f8802
+#define CA_TEXT_LAST		0x9f8803
+#define CA_TEXT_MORE		0x9f8804
+#define CA_KEYPAD_CONTROL	0x9f8805
+#define CA_KEYPRESS		0x9f8806
+
+#define CA_ENQUIRY		0x9f8807
+#define CA_ANSWER		0x9f8808
+#define CA_MENU_LAST		0x9f8809
+#define CA_MENU_MORE		0x9f880a
+#define CA_MENU_ANSWER		0x9f880b
+#define CA_LIST_LAST		0x9f880c
+#define CA_LIST_MORE		0x9f880d
+
+
+struct dst_ca_private {
+	struct dst_state *dst;
+	struct dvb_device *dvbdev;
+};
+
+
+#endif
diff --git a/drivers/media/pci/bt8xx/dst_common.h b/drivers/media/pci/bt8xx/dst_common.h
new file mode 100644
index 0000000..d70d98f
--- /dev/null
+++ b/drivers/media/pci/bt8xx/dst_common.h
@@ -0,0 +1,182 @@
+/*
+	Frontend-driver for TwinHan DST Frontend
+
+	Copyright (C) 2003 Jamie Honan
+	Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef DST_COMMON_H
+#define DST_COMMON_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include "bt878.h"
+
+#include "dst_ca.h"
+
+
+#define NO_DELAY		0
+#define LONG_DELAY		1
+#define DEVICE_INIT		2
+
+#define DELAY			1
+
+#define DST_TYPE_IS_SAT		0
+#define DST_TYPE_IS_TERR	1
+#define DST_TYPE_IS_CABLE	2
+#define DST_TYPE_IS_ATSC	3
+
+#define DST_TYPE_HAS_TS188	1
+#define DST_TYPE_HAS_TS204	2
+#define DST_TYPE_HAS_SYMDIV	4
+#define DST_TYPE_HAS_FW_1	8
+#define DST_TYPE_HAS_FW_2	16
+#define DST_TYPE_HAS_FW_3	32
+#define DST_TYPE_HAS_FW_BUILD	64
+#define DST_TYPE_HAS_OBS_REGS	128
+#define DST_TYPE_HAS_INC_COUNT	256
+#define DST_TYPE_HAS_MULTI_FE	512
+#define DST_TYPE_HAS_NEWTUNE_2	1024
+#define DST_TYPE_HAS_DBOARD	2048
+#define DST_TYPE_HAS_VLF	4096
+
+/*	Card capability list	*/
+
+#define DST_TYPE_HAS_MAC	1
+#define DST_TYPE_HAS_DISEQC3	2
+#define DST_TYPE_HAS_DISEQC4	4
+#define DST_TYPE_HAS_DISEQC5	8
+#define DST_TYPE_HAS_MOTO	16
+#define DST_TYPE_HAS_CA		32
+#define	DST_TYPE_HAS_ANALOG	64	/*	Analog inputs	*/
+#define DST_TYPE_HAS_SESSION	128
+
+#define TUNER_TYPE_MULTI	1
+#define TUNER_TYPE_UNKNOWN	2
+/*	DVB-S		*/
+#define TUNER_TYPE_L64724	4
+#define TUNER_TYPE_STV0299	8
+#define TUNER_TYPE_MB86A15	16
+
+/*	DVB-T		*/
+#define TUNER_TYPE_TDA10046	32
+
+/*	ATSC		*/
+#define TUNER_TYPE_NXT200x	64
+
+
+#define RDC_8820_PIO_0_DISABLE	0
+#define RDC_8820_PIO_0_ENABLE	1
+#define RDC_8820_INT		2
+#define RDC_8820_RESET		4
+
+/*	DST Communication	*/
+#define GET_REPLY		1
+#define NO_REPLY		0
+
+#define GET_ACK			1
+#define FIXED_COMM		8
+
+#define ACK			0xff
+
+struct dst_state {
+
+	struct i2c_adapter* i2c;
+
+	struct bt878* bt;
+
+	/* configuration settings */
+	const struct dst_config* config;
+
+	struct dvb_frontend frontend;
+
+	/* private ASIC data */
+	u8 tx_tuna[10];
+	u8 rx_tuna[10];
+	u8 rxbuffer[10];
+	u8 diseq_flags;
+	u8 dst_type;
+	u32 type_flags;
+	u32 frequency;		/* intermediate frequency in kHz for QPSK */
+	fe_spectral_inversion_t inversion;
+	u32 symbol_rate;	/* symbol rate in Symbols per second */
+	fe_code_rate_t fec;
+	fe_sec_voltage_t voltage;
+	fe_sec_tone_mode_t tone;
+	u32 decode_freq;
+	u8 decode_lock;
+	u16 decode_strength;
+	u16 decode_snr;
+	unsigned long cur_jiff;
+	u8 k22;
+	u32 bandwidth;
+	u32 dst_hw_cap;
+	u8 dst_fw_version;
+	fe_sec_mini_cmd_t minicmd;
+	fe_modulation_t modulation;
+	u8 messages[256];
+	u8 mac_address[8];
+	u8 fw_version[8];
+	u8 card_info[8];
+	u8 vendor[8];
+	u8 board_info[8];
+	u32 tuner_type;
+	char *tuner_name;
+	struct mutex dst_mutex;
+	u8 fw_name[8];
+	struct dvb_device *dst_ca;
+};
+
+struct tuner_types {
+	u32 tuner_type;
+	char *tuner_name;
+	char *board_name;
+	char *fw_name;
+};
+
+struct dst_types {
+	char *device_id;
+	int offset;
+	u8 dst_type;
+	u32 type_flags;
+	u32 dst_feature;
+	u32 tuner_type;
+};
+
+struct dst_config
+{
+	/* the ASIC i2c address */
+	u8 demod_address;
+};
+
+int rdc_reset_state(struct dst_state *state);
+
+int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode);
+int dst_pio_disable(struct dst_state *state);
+int dst_error_recovery(struct dst_state* state);
+int dst_error_bailout(struct dst_state *state);
+int dst_comm_init(struct dst_state* state);
+
+int write_dst(struct dst_state *state, u8 * data, u8 len);
+int read_dst(struct dst_state *state, u8 * ret, u8 len);
+u8 dst_check_sum(u8 * buf, u32 len);
+struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter);
+struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter);
+
+
+#endif // DST_COMMON_H
diff --git a/drivers/media/pci/bt8xx/dst_priv.h b/drivers/media/pci/bt8xx/dst_priv.h
new file mode 100644
index 0000000..3974a4c
--- /dev/null
+++ b/drivers/media/pci/bt8xx/dst_priv.h
@@ -0,0 +1,35 @@
+/*
+ * dst-bt878.h: part of the DST driver for the TwinHan DST Frontend
+ *
+ * Copyright (C) 2003 Jamie Honan
+ */
+
+struct dst_gpio_enable {
+	u32	mask;
+	u32	enable;
+};
+
+struct dst_gpio_output {
+	u32	mask;
+	u32	highvals;
+};
+
+struct dst_gpio_read {
+	unsigned long value;
+};
+
+union dst_gpio_packet {
+	struct dst_gpio_enable enb;
+	struct dst_gpio_output outp;
+	struct dst_gpio_read rd;
+	int    psize;
+};
+
+#define DST_IG_ENABLE	0
+#define DST_IG_WRITE	1
+#define DST_IG_READ	2
+#define DST_IG_TS       3
+
+struct bt878;
+
+int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp);
diff --git a/drivers/media/pci/bt8xx/dvb-bt8xx.c b/drivers/media/pci/bt8xx/dvb-bt8xx.c
new file mode 100644
index 0000000..81fab9a
--- /dev/null
+++ b/drivers/media/pci/bt8xx/dvb-bt8xx.c
@@ -0,0 +1,975 @@
+/*
+ * Bt8xx based DVB adapter driver
+ *
+ * Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#define pr_fmt(fmt) "dvb_bt8xx: " fmt
+
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb-bt8xx.h"
+#include "bt878.h"
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define dprintk( args... ) \
+	do { \
+		if (debug) printk(KERN_DEBUG args); \
+	} while (0)
+
+#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
+
+static void dvb_bt8xx_task(unsigned long data)
+{
+	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *)data;
+
+	//printk("%d ", card->bt->finished_block);
+
+	while (card->bt->last_block != card->bt->finished_block) {
+		(card->bt->TS_Size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter)
+			(&card->demux,
+			 &card->bt->buf_cpu[card->bt->last_block *
+					    card->bt->block_bytes],
+			 card->bt->block_bytes);
+		card->bt->last_block = (card->bt->last_block + 1) %
+					card->bt->block_count;
+	}
+}
+
+static int dvb_bt8xx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux*dvbdmx = dvbdmxfeed->demux;
+	struct dvb_bt8xx_card *card = dvbdmx->priv;
+	int rc;
+
+	dprintk("dvb_bt8xx: start_feed\n");
+
+	if (!dvbdmx->dmx.frontend)
+		return -EINVAL;
+
+	mutex_lock(&card->lock);
+	card->nfeeds++;
+	rc = card->nfeeds;
+	if (card->nfeeds == 1)
+		bt878_start(card->bt, card->gpio_mode,
+			    card->op_sync_orin, card->irq_err_ignore);
+	mutex_unlock(&card->lock);
+	return rc;
+}
+
+static int dvb_bt8xx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct dvb_bt8xx_card *card = dvbdmx->priv;
+
+	dprintk("dvb_bt8xx: stop_feed\n");
+
+	if (!dvbdmx->dmx.frontend)
+		return -EINVAL;
+
+	mutex_lock(&card->lock);
+	card->nfeeds--;
+	if (card->nfeeds == 0)
+		bt878_stop(card->bt);
+	mutex_unlock(&card->lock);
+
+	return 0;
+}
+
+static int is_pci_slot_eq(struct pci_dev* adev, struct pci_dev* bdev)
+{
+	if ((adev->subsystem_vendor == bdev->subsystem_vendor) &&
+		(adev->subsystem_device == bdev->subsystem_device) &&
+		(adev->bus->number == bdev->bus->number) &&
+		(PCI_SLOT(adev->devfn) == PCI_SLOT(bdev->devfn)))
+		return 1;
+	return 0;
+}
+
+static struct bt878 __devinit *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci_dev* bttv_pci_dev)
+{
+	unsigned int card_nr;
+
+	/* Hmm, n squared. Hope n is small */
+	for (card_nr = 0; card_nr < bt878_num; card_nr++)
+		if (is_pci_slot_eq(bt878[card_nr].dev, bttv_pci_dev))
+			return &bt878[card_nr];
+	return NULL;
+}
+
+static int thomson_dtt7579_demod_init(struct dvb_frontend* fe)
+{
+	static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 };
+	static u8 mt352_reset [] = { 0x50, 0x80 };
+	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+	static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 };
+	static u8 mt352_gpp_ctl_cfg [] = { 0x8C, 0x33 };
+	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
+
+	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+	udelay(2000);
+	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+
+	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
+	mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg));
+	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
+
+	return 0;
+}
+
+static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend *fe, u8* pllbuf, int buf_len)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 div;
+	unsigned char bs = 0;
+	unsigned char cp = 0;
+
+	if (buf_len < 5)
+		return -EINVAL;
+
+	div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+
+	if (c->frequency < 542000000)
+		cp = 0xb4;
+	else if (c->frequency < 771000000)
+		cp = 0xbc;
+	else
+		cp = 0xf4;
+
+	if (c->frequency == 0)
+		bs = 0x03;
+	else if (c->frequency < 443250000)
+		bs = 0x02;
+	else
+		bs = 0x08;
+
+	pllbuf[0] = 0x60;
+	pllbuf[1] = div >> 8;
+	pllbuf[2] = div & 0xff;
+	pllbuf[3] = cp;
+	pllbuf[4] = bs;
+
+	return 5;
+}
+
+static struct mt352_config thomson_dtt7579_config = {
+	.demod_address = 0x0f,
+	.demod_init = thomson_dtt7579_demod_init,
+};
+
+static struct zl10353_config thomson_dtt7579_zl10353_config = {
+	.demod_address = 0x0f,
+};
+
+static int cx24108_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 freq = c->frequency;
+	int i, a, n, pump;
+	u32 band, pll;
+	u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000,
+		1576000,1718000,1856000,2036000,2150000};
+	u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000,
+		0x00102000,0x00104000,0x00108000,0x00110000,
+		0x00120000,0x00140000};
+
+	#define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */
+	dprintk("cx24108 debug: entering SetTunerFreq, freq=%d\n", freq);
+
+	/* This is really the bit driving the tuner chip cx24108 */
+
+	if (freq<950000)
+		freq = 950000; /* kHz */
+	else if (freq>2150000)
+		freq = 2150000; /* satellite IF is 950..2150MHz */
+
+	/* decide which VCO to use for the input frequency */
+	for(i = 1; (i < ARRAY_SIZE(osci) - 1) && (osci[i] < freq); i++);
+	dprintk("cx24108 debug: select vco #%d (f=%d)\n", i, freq);
+	band=bandsel[i];
+	/* the gain values must be set by SetSymbolrate */
+	/* compute the pll divider needed, from Conexant data sheet,
+	   resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4,
+	   depending on the divider bit. It is set to /4 on the 2 lowest
+	   bands  */
+	n=((i<=2?2:1)*freq*10L)/(XTAL/100);
+	a=n%32; n/=32; if(a==0) n--;
+	pump=(freq<(osci[i-1]+osci[i])/2);
+	pll=0xf8000000|
+	    ((pump?1:2)<<(14+11))|
+	    ((n&0x1ff)<<(5+11))|
+	    ((a&0x1f)<<11);
+	/* everything is shifted left 11 bits to left-align the bits in the
+	   32bit word. Output to the tuner goes MSB-aligned, after all */
+	dprintk("cx24108 debug: pump=%d, n=%d, a=%d\n", pump, n, a);
+	cx24110_pll_write(fe,band);
+	/* set vga and vca to their widest-band settings, as a precaution.
+	   SetSymbolrate might not be called to set this up */
+	cx24110_pll_write(fe,0x500c0000);
+	cx24110_pll_write(fe,0x83f1f800);
+	cx24110_pll_write(fe,pll);
+	//writereg(client,0x56,0x7f);
+
+	return 0;
+}
+
+static int pinnsat_tuner_init(struct dvb_frontend* fe)
+{
+	struct dvb_bt8xx_card *card = fe->dvb->priv;
+
+	bttv_gpio_enable(card->bttv_nr, 1, 1);  /* output */
+	bttv_write_gpio(card->bttv_nr, 1, 1);   /* relay on */
+
+	return 0;
+}
+
+static int pinnsat_tuner_sleep(struct dvb_frontend* fe)
+{
+	struct dvb_bt8xx_card *card = fe->dvb->priv;
+
+	bttv_write_gpio(card->bttv_nr, 1, 0);   /* relay off */
+
+	return 0;
+}
+
+static struct cx24110_config pctvsat_config = {
+	.demod_address = 0x55,
+};
+
+static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
+	u8 cfg, cpump, band_select;
+	u8 data[4];
+	u32 div;
+	struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = (36000000 + c->frequency + 83333) / 166666;
+	cfg = 0x88;
+
+	if (c->frequency < 175000000)
+		cpump = 2;
+	else if (c->frequency < 390000000)
+		cpump = 1;
+	else if (c->frequency < 470000000)
+		cpump = 2;
+	else if (c->frequency < 750000000)
+		cpump = 2;
+	else
+		cpump = 3;
+
+	if (c->frequency < 175000000)
+		band_select = 0x0e;
+	else if (c->frequency < 470000000)
+		band_select = 0x05;
+	else
+		band_select = 0x03;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = ((div >> 10) & 0x60) | cfg;
+	data[3] = (cpump << 6) | band_select;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(card->i2c_adapter, &msg, 1);
+	return (div * 166666 - 36000000);
+}
+
+static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+	struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv;
+
+	return request_firmware(fw, name, &bt->bt->dev->dev);
+}
+
+static struct sp887x_config microtune_mt7202dtf_config = {
+	.demod_address = 0x70,
+	.request_firmware = microtune_mt7202dtf_request_firmware,
+};
+
+static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
+{
+	static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d };
+	static u8 mt352_reset [] = { 0x50, 0x80 };
+	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+	static u8 mt352_agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
+				       0x00, 0xFF, 0x00, 0x40, 0x40 };
+	static u8 mt352_av771_extra[] = { 0xB5, 0x7A };
+	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
+
+	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+	udelay(2000);
+	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+
+	mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg));
+	udelay(2000);
+	mt352_write(fe, mt352_av771_extra,sizeof(mt352_av771_extra));
+	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
+
+	return 0;
+}
+
+static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 div;
+	unsigned char bs = 0;
+	unsigned char cp = 0;
+
+	if (buf_len < 5) return -EINVAL;
+
+	div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+
+	if (c->frequency < 150000000)
+		cp = 0xB4;
+	else if (c->frequency < 173000000)
+		cp = 0xBC;
+	else if (c->frequency < 250000000)
+		cp = 0xB4;
+	else if (c->frequency < 400000000)
+		cp = 0xBC;
+	else if (c->frequency < 420000000)
+		cp = 0xF4;
+	else if (c->frequency < 470000000)
+		cp = 0xFC;
+	else if (c->frequency < 600000000)
+		cp = 0xBC;
+	else if (c->frequency < 730000000)
+		cp = 0xF4;
+	else
+		cp = 0xFC;
+
+	if (c->frequency < 150000000)
+		bs = 0x01;
+	else if (c->frequency < 173000000)
+		bs = 0x01;
+	else if (c->frequency < 250000000)
+		bs = 0x02;
+	else if (c->frequency < 400000000)
+		bs = 0x02;
+	else if (c->frequency < 420000000)
+		bs = 0x02;
+	else if (c->frequency < 470000000)
+		bs = 0x02;
+	else if (c->frequency < 600000000)
+		bs = 0x08;
+	else if (c->frequency < 730000000)
+		bs = 0x08;
+	else
+		bs = 0x08;
+
+	pllbuf[0] = 0x61;
+	pllbuf[1] = div >> 8;
+	pllbuf[2] = div & 0xff;
+	pllbuf[3] = cp;
+	pllbuf[4] = bs;
+
+	return 5;
+}
+
+static struct mt352_config advbt771_samsung_tdtc9251dh0_config = {
+	.demod_address = 0x0f,
+	.demod_init = advbt771_samsung_tdtc9251dh0_demod_init,
+};
+
+static struct dst_config dst_config = {
+	.demod_address = 0x55,
+};
+
+static int or51211_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+	struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv;
+
+	return request_firmware(fw, name, &bt->bt->dev->dev);
+}
+
+static void or51211_setmode(struct dvb_frontend * fe, int mode)
+{
+	struct dvb_bt8xx_card *bt = fe->dvb->priv;
+	bttv_write_gpio(bt->bttv_nr, 0x0002, mode);   /* Reset */
+	msleep(20);
+}
+
+static void or51211_reset(struct dvb_frontend * fe)
+{
+	struct dvb_bt8xx_card *bt = fe->dvb->priv;
+
+	/* RESET DEVICE
+	 * reset is controlled by GPIO-0
+	 * when set to 0 causes reset and when to 1 for normal op
+	 * must remain reset for 128 clock cycles on a 50Mhz clock
+	 * also PRM1 PRM2 & PRM4 are controlled by GPIO-1,GPIO-2 & GPIO-4
+	 * We assume that the reset has be held low long enough or we
+	 * have been reset by a power on.  When the driver is unloaded
+	 * reset set to 0 so if reloaded we have been reset.
+	 */
+	/* reset & PRM1,2&4 are outputs */
+	int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F);
+	if (ret != 0)
+		printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR (%i)\n", ret);
+	bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000);   /* Reset */
+	msleep(20);
+	/* Now set for normal operation */
+	bttv_write_gpio(bt->bttv_nr, 0x0001F, 0x0001);
+	/* wait for operation to begin */
+	msleep(500);
+}
+
+static void or51211_sleep(struct dvb_frontend * fe)
+{
+	struct dvb_bt8xx_card *bt = fe->dvb->priv;
+	bttv_write_gpio(bt->bttv_nr, 0x0001, 0x0000);
+}
+
+static struct or51211_config or51211_config = {
+	.demod_address = 0x15,
+	.request_firmware = or51211_request_firmware,
+	.setmode = or51211_setmode,
+	.reset = or51211_reset,
+	.sleep = or51211_sleep,
+};
+
+static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
+	u8 buf[4];
+	u32 div;
+	struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) };
+
+	div = (c->frequency + 36166667) / 166667;
+
+	buf[0] = (div >> 8) & 0x7F;
+	buf[1] = div & 0xFF;
+	buf[2] = 0x85;
+	if ((c->frequency >= 47000000) && (c->frequency < 153000000))
+		buf[3] = 0x01;
+	else if ((c->frequency >= 153000000) && (c->frequency < 430000000))
+		buf[3] = 0x02;
+	else if ((c->frequency >= 430000000) && (c->frequency < 824000000))
+		buf[3] = 0x0C;
+	else if ((c->frequency >= 824000000) && (c->frequency < 863000000))
+		buf[3] = 0x8C;
+	else
+		return -EINVAL;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(card->i2c_adapter, &msg, 1);
+	return 0;
+}
+
+static struct nxt6000_config vp3021_alps_tded4_config = {
+	.demod_address = 0x0a,
+	.clock_inversion = 1,
+};
+
+static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
+{
+	static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d };
+	static u8 mt352_reset [] = { 0x50, 0x80 };
+	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+	static u8 mt352_agc_cfg [] = { 0x67, 0x20, 0xa0 };
+	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
+
+	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+	udelay(2000);
+	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+	mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg));
+	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
+
+	return 0;
+}
+
+static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend *fe,  u8 *pllbuf, int buf_len)
+{
+	u32 div;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+	if (buf_len < 5)
+		return -EINVAL;
+
+	div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+
+	pllbuf[0] = 0x61;
+	pllbuf[1] = (div >> 8) & 0x7F;
+	pllbuf[2] = div & 0xFF;
+	pllbuf[3] = 0x85;
+
+	dprintk("frequency %u, div %u\n", c->frequency, div);
+
+	if (c->frequency < 470000000)
+		pllbuf[4] = 0x02;
+	else if (c->frequency > 823000000)
+		pllbuf[4] = 0x88;
+	else
+		pllbuf[4] = 0x08;
+
+	if (c->bandwidth_hz == 8000000)
+		pllbuf[4] |= 0x04;
+
+	return 5;
+}
+
+static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
+{
+	/*
+	 * Reset the frontend, must be called before trying
+	 * to initialise the MT352 or mt352_attach
+	 * will fail. Same goes for the nxt6000 frontend.
+	 *
+	 */
+
+	int ret = bttv_gpio_enable(bt->bttv_nr, 0x08, 0x08);
+	if (ret != 0)
+		printk(KERN_WARNING "digitv_alps_tded4: Init Error - Can't Reset DVR (%i)\n", ret);
+
+	/* Pulse the reset line */
+	bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */
+	bttv_write_gpio(bt->bttv_nr, 0x08, 0x00); /* Low  */
+	msleep(100);
+
+	bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */
+}
+
+static struct mt352_config digitv_alps_tded4_config = {
+	.demod_address = 0x0a,
+	.demod_init = digitv_alps_tded4_demod_init,
+};
+
+static struct lgdt330x_config tdvs_tua6034_config = {
+	.demod_address    = 0x0e,
+	.demod_chip       = LGDT3303,
+	.serial_mpeg      = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
+};
+
+static void lgdt330x_reset(struct dvb_bt8xx_card *bt)
+{
+	/* Set pin 27 of the lgdt3303 chip high to reset the frontend */
+
+	/* Pulse the reset line */
+	bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
+	bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000000); /* Low  */
+	msleep(100);
+
+	bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
+	msleep(100);
+}
+
+static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
+{
+	struct dst_state* state = NULL;
+
+	switch(type) {
+	case BTTV_BOARD_DVICO_DVBT_LITE:
+		card->fe = dvb_attach(mt352_attach, &thomson_dtt7579_config, card->i2c_adapter);
+
+		if (card->fe == NULL)
+			card->fe = dvb_attach(zl10353_attach, &thomson_dtt7579_zl10353_config,
+						  card->i2c_adapter);
+
+		if (card->fe != NULL) {
+			card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs;
+			card->fe->ops.info.frequency_min = 174000000;
+			card->fe->ops.info.frequency_max = 862000000;
+		}
+		break;
+
+	case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
+		lgdt330x_reset(card);
+		card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
+		if (card->fe != NULL) {
+			dvb_attach(simple_tuner_attach, card->fe,
+				   card->i2c_adapter, 0x61,
+				   TUNER_LG_TDVS_H06XF);
+			dprintk ("dvb_bt8xx: lgdt330x detected\n");
+		}
+		break;
+
+	case BTTV_BOARD_NEBULA_DIGITV:
+		/*
+		 * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK);
+		 * this would be a cleaner solution than trying each frontend in turn.
+		 */
+
+		/* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */
+		digitv_alps_tded4_reset(card);
+		card->fe = dvb_attach(nxt6000_attach, &vp3021_alps_tded4_config, card->i2c_adapter);
+		if (card->fe != NULL) {
+			card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params;
+			dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
+			break;
+		}
+
+		/* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */
+		digitv_alps_tded4_reset(card);
+		card->fe = dvb_attach(mt352_attach, &digitv_alps_tded4_config, card->i2c_adapter);
+
+		if (card->fe != NULL) {
+			card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs;
+			dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n");
+		}
+		break;
+
+	case BTTV_BOARD_AVDVBT_761:
+		card->fe = dvb_attach(sp887x_attach, &microtune_mt7202dtf_config, card->i2c_adapter);
+		if (card->fe) {
+			card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params;
+		}
+		break;
+
+	case BTTV_BOARD_AVDVBT_771:
+		card->fe = dvb_attach(mt352_attach, &advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
+		if (card->fe != NULL) {
+			card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs;
+			card->fe->ops.info.frequency_min = 174000000;
+			card->fe->ops.info.frequency_max = 862000000;
+		}
+		break;
+
+	case BTTV_BOARD_TWINHAN_DST:
+		/*	DST is not a frontend driver !!!		*/
+		state = kmalloc(sizeof (struct dst_state), GFP_KERNEL);
+		if (!state) {
+			pr_err("No memory\n");
+			break;
+		}
+		/*	Setup the Card					*/
+		state->config = &dst_config;
+		state->i2c = card->i2c_adapter;
+		state->bt = card->bt;
+		state->dst_ca = NULL;
+		/*	DST is not a frontend, attaching the ASIC	*/
+		if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) {
+			pr_err("%s: Could not find a Twinhan DST\n", __func__);
+			break;
+		}
+		/*	Attach other DST peripherals if any		*/
+		/*	Conditional Access device			*/
+		card->fe = &state->frontend;
+		if (state->dst_hw_cap & DST_TYPE_HAS_CA)
+			dvb_attach(dst_ca_attach, state, &card->dvb_adapter);
+		break;
+
+	case BTTV_BOARD_PINNACLESAT:
+		card->fe = dvb_attach(cx24110_attach, &pctvsat_config, card->i2c_adapter);
+		if (card->fe) {
+			card->fe->ops.tuner_ops.init = pinnsat_tuner_init;
+			card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep;
+			card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params;
+		}
+		break;
+
+	case BTTV_BOARD_PC_HDTV:
+		card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter);
+		if (card->fe != NULL)
+			dvb_attach(simple_tuner_attach, card->fe,
+				   card->i2c_adapter, 0x61,
+				   TUNER_PHILIPS_FCV1236D);
+		break;
+	}
+
+	if (card->fe == NULL)
+		pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
+		       card->bt->dev->vendor,
+		       card->bt->dev->device,
+		       card->bt->dev->subsystem_vendor,
+		       card->bt->dev->subsystem_device);
+	else
+		if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
+			pr_err("Frontend registration failed!\n");
+			dvb_frontend_detach(card->fe);
+			card->fe = NULL;
+		}
+}
+
+static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
+{
+	int result;
+
+	result = dvb_register_adapter(&card->dvb_adapter, card->card_name,
+				      THIS_MODULE, &card->bt->dev->dev,
+				      adapter_nr);
+	if (result < 0) {
+		pr_err("dvb_register_adapter failed (errno = %d)\n", result);
+		return result;
+	}
+	card->dvb_adapter.priv = card;
+
+	card->bt->adapter = card->i2c_adapter;
+
+	memset(&card->demux, 0, sizeof(struct dvb_demux));
+
+	card->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING;
+
+	card->demux.priv = card;
+	card->demux.filternum = 256;
+	card->demux.feednum = 256;
+	card->demux.start_feed = dvb_bt8xx_start_feed;
+	card->demux.stop_feed = dvb_bt8xx_stop_feed;
+	card->demux.write_to_decoder = NULL;
+
+	result = dvb_dmx_init(&card->demux);
+	if (result < 0) {
+		pr_err("dvb_dmx_init failed (errno = %d)\n", result);
+		goto err_unregister_adaptor;
+	}
+
+	card->dmxdev.filternum = 256;
+	card->dmxdev.demux = &card->demux.dmx;
+	card->dmxdev.capabilities = 0;
+
+	result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter);
+	if (result < 0) {
+		pr_err("dvb_dmxdev_init failed (errno = %d)\n", result);
+		goto err_dmx_release;
+	}
+
+	card->fe_hw.source = DMX_FRONTEND_0;
+
+	result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw);
+	if (result < 0) {
+		pr_err("dvb_dmx_init failed (errno = %d)\n", result);
+		goto err_dmxdev_release;
+	}
+
+	card->fe_mem.source = DMX_MEMORY_FE;
+
+	result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem);
+	if (result < 0) {
+		pr_err("dvb_dmx_init failed (errno = %d)\n", result);
+		goto err_remove_hw_frontend;
+	}
+
+	result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw);
+	if (result < 0) {
+		pr_err("dvb_dmx_init failed (errno = %d)\n", result);
+		goto err_remove_mem_frontend;
+	}
+
+	result = dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx);
+	if (result < 0) {
+		pr_err("dvb_net_init failed (errno = %d)\n", result);
+		goto err_disconnect_frontend;
+	}
+
+	tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card);
+
+	frontend_init(card, type);
+
+	return 0;
+
+err_disconnect_frontend:
+	card->demux.dmx.disconnect_frontend(&card->demux.dmx);
+err_remove_mem_frontend:
+	card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
+err_remove_hw_frontend:
+	card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
+err_dmxdev_release:
+	dvb_dmxdev_release(&card->dmxdev);
+err_dmx_release:
+	dvb_dmx_release(&card->demux);
+err_unregister_adaptor:
+	dvb_unregister_adapter(&card->dvb_adapter);
+	return result;
+}
+
+static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
+{
+	struct dvb_bt8xx_card *card;
+	struct pci_dev* bttv_pci_dev;
+	int ret;
+
+	if (!(card = kzalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL)))
+		return -ENOMEM;
+
+	mutex_init(&card->lock);
+	card->bttv_nr = sub->core->nr;
+	strlcpy(card->card_name, sub->core->v4l2_dev.name, sizeof(card->card_name));
+	card->i2c_adapter = &sub->core->i2c_adap;
+
+	switch(sub->core->type) {
+	case BTTV_BOARD_PINNACLESAT:
+		card->gpio_mode = 0x0400c060;
+		/* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR,
+			      BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */
+		card->op_sync_orin = BT878_RISC_SYNC_MASK;
+		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
+		break;
+
+	case BTTV_BOARD_DVICO_DVBT_LITE:
+		card->gpio_mode = 0x0400C060;
+		card->op_sync_orin = BT878_RISC_SYNC_MASK;
+		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
+		/* 26, 15, 14, 6, 5
+		 * A_PWRDN  DA_DPM DA_SBR DA_IOM_DA
+		 * DA_APP(parallel) */
+		break;
+
+	case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
+		card->gpio_mode = 0x0400c060;
+		card->op_sync_orin = BT878_RISC_SYNC_MASK;
+		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
+		break;
+
+	case BTTV_BOARD_NEBULA_DIGITV:
+	case BTTV_BOARD_AVDVBT_761:
+		card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
+		card->op_sync_orin = BT878_RISC_SYNC_MASK;
+		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
+		/* A_PWRDN DA_SBR DA_APP (high speed serial) */
+		break;
+
+	case BTTV_BOARD_AVDVBT_771: //case 0x07711461:
+		card->gpio_mode = 0x0400402B;
+		card->op_sync_orin = BT878_RISC_SYNC_MASK;
+		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
+		/* A_PWRDN DA_SBR  DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/
+		break;
+
+	case BTTV_BOARD_TWINHAN_DST:
+		card->gpio_mode = 0x2204f2c;
+		card->op_sync_orin = BT878_RISC_SYNC_MASK;
+		card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR |
+				       BT878_APPERR | BT878_AFBUS;
+		/* 25,21,14,11,10,9,8,3,2 then
+		 * 0x33 = 5,4,1,0
+		 * A_SEL=SML, DA_MLB, DA_SBR,
+		 * DA_SDR=f, fifo trigger = 32 DWORDS
+		 * IOM = 0 == audio A/D
+		 * DPM = 0 == digital audio mode
+		 * == async data parallel port
+		 * then 0x33 (13 is set by start_capture)
+		 * DA_APP = async data parallel port,
+		 * ACAP_EN = 1,
+		 * RISC+FIFO ENABLE */
+		break;
+
+	case BTTV_BOARD_PC_HDTV:
+		card->gpio_mode = 0x0100EC7B;
+		card->op_sync_orin = BT878_RISC_SYNC_MASK;
+		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
+		break;
+
+	default:
+		pr_err("Unknown bttv card type: %d\n", sub->core->type);
+		kfree(card);
+		return -ENODEV;
+	}
+
+	dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name);
+
+	if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) {
+		pr_err("no pci device for card %d\n", card->bttv_nr);
+		kfree(card);
+		return -ENODEV;
+	}
+
+	if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) {
+		pr_err("unable to determine DMA core of card %d,\n", card->bttv_nr);
+		pr_err("if you have the ALSA bt87x audio driver installed, try removing it.\n");
+
+		kfree(card);
+		return -ENODEV;
+	}
+
+	mutex_init(&card->bt->gpio_lock);
+	card->bt->bttv_nr = sub->core->nr;
+
+	if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) {
+		kfree(card);
+		return ret;
+	}
+
+	dev_set_drvdata(&sub->dev, card);
+	return 0;
+}
+
+static void dvb_bt8xx_remove(struct bttv_sub_device *sub)
+{
+	struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev);
+
+	dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr);
+
+	bt878_stop(card->bt);
+	tasklet_kill(&card->bt->tasklet);
+	dvb_net_release(&card->dvbnet);
+	card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
+	card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
+	dvb_dmxdev_release(&card->dmxdev);
+	dvb_dmx_release(&card->demux);
+	if (card->fe) {
+		dvb_unregister_frontend(card->fe);
+		dvb_frontend_detach(card->fe);
+	}
+	dvb_unregister_adapter(&card->dvb_adapter);
+
+	kfree(card);
+}
+
+static struct bttv_sub_driver driver = {
+	.drv = {
+		.name		= "dvb-bt8xx",
+	},
+	.probe		= dvb_bt8xx_probe,
+	.remove		= dvb_bt8xx_remove,
+	/* FIXME:
+	 * .shutdown	= dvb_bt8xx_shutdown,
+	 * .suspend	= dvb_bt8xx_suspend,
+	 * .resume	= dvb_bt8xx_resume,
+	 */
+};
+
+static int __init dvb_bt8xx_init(void)
+{
+	return bttv_sub_register(&driver, "dvb");
+}
+
+static void __exit dvb_bt8xx_exit(void)
+{
+	bttv_sub_unregister(&driver);
+}
+
+module_init(dvb_bt8xx_init);
+module_exit(dvb_bt8xx_exit);
+
+MODULE_DESCRIPTION("Bt8xx based DVB adapter driver");
+MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/bt8xx/dvb-bt8xx.h b/drivers/media/pci/bt8xx/dvb-bt8xx.h
new file mode 100644
index 0000000..4499ed2
--- /dev/null
+++ b/drivers/media/pci/bt8xx/dvb-bt8xx.h
@@ -0,0 +1,63 @@
+/*
+ * Bt8xx based DVB adapter driver
+ *
+ * Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org>
+ * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de>
+ * Copyright (C) 1999-2001 Ralph  Metzler & Marcus Metzler for convergence integrated media GmbH
+ * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef DVB_BT8XX_H
+#define DVB_BT8XX_H
+
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include "dvbdev.h"
+#include "dvb_net.h"
+#include "bttv.h"
+#include "mt352.h"
+#include "sp887x.h"
+#include "dst_common.h"
+#include "nxt6000.h"
+#include "cx24110.h"
+#include "or51211.h"
+#include "lgdt330x.h"
+#include "zl10353.h"
+#include "tuner-simple.h"
+
+struct dvb_bt8xx_card {
+	struct mutex lock;
+	int nfeeds;
+	char card_name[32];
+	struct dvb_adapter dvb_adapter;
+	struct bt878 *bt;
+	unsigned int bttv_nr;
+	struct dvb_demux demux;
+	struct dmxdev dmxdev;
+	struct dmx_frontend fe_hw;
+	struct dmx_frontend fe_mem;
+	u32 gpio_mode;
+	u32 op_sync_orin;
+	u32 irq_err_ignore;
+	struct i2c_adapter *i2c_adapter;
+	struct dvb_net dvbnet;
+
+	struct dvb_frontend* fe;
+};
+
+#endif /* DVB_BT8XX_H */
diff --git a/drivers/media/pci/cx18/Kconfig b/drivers/media/pci/cx18/Kconfig
new file mode 100644
index 0000000..53b3c77
--- /dev/null
+++ b/drivers/media/pci/cx18/Kconfig
@@ -0,0 +1,35 @@
+config VIDEO_CX18
+	tristate "Conexant cx23418 MPEG encoder support"
+	depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL
+	select I2C_ALGOBIT
+	select VIDEOBUF_VMALLOC
+	depends on RC_CORE
+	select VIDEO_TUNER
+	select VIDEO_TVEEPROM
+	select VIDEO_CX2341X
+	select VIDEO_CS5345
+	select DVB_S5H1409 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
+	---help---
+	  This is a video4linux driver for Conexant cx23418 based
+	  PCI combo video recorder devices.
+
+	  This is used in devices such as the Hauppauge HVR-1600
+	  cards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx18.
+
+config VIDEO_CX18_ALSA
+	tristate "Conexant 23418 DMA audio support"
+	depends on VIDEO_CX18 && SND && EXPERIMENTAL
+	select SND_PCM
+	---help---
+	  This is a video4linux driver for direct (DMA) audio on
+	  Conexant 23418 based TV cards using ALSA.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx18-alsa.
diff --git a/drivers/media/pci/cx18/Makefile b/drivers/media/pci/cx18/Makefile
new file mode 100644
index 0000000..d3ff154
--- /dev/null
+++ b/drivers/media/pci/cx18/Makefile
@@ -0,0 +1,13 @@
+cx18-objs    := cx18-driver.o cx18-cards.o cx18-i2c.o cx18-firmware.o cx18-gpio.o \
+	cx18-queue.o cx18-streams.o cx18-fileops.o cx18-ioctl.o cx18-controls.o \
+	cx18-mailbox.o cx18-vbi.o cx18-audio.o cx18-video.o cx18-irq.o \
+	cx18-av-core.o cx18-av-audio.o cx18-av-firmware.o cx18-av-vbi.o cx18-scb.o \
+	cx18-dvb.o cx18-io.o
+cx18-alsa-objs := cx18-alsa-main.o cx18-alsa-pcm.o
+
+obj-$(CONFIG_VIDEO_CX18) += cx18.o
+obj-$(CONFIG_VIDEO_CX18_ALSA) += cx18-alsa.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+ccflags-y += -Idrivers/media/tuners
diff --git a/drivers/media/pci/cx18/cx18-alsa-main.c b/drivers/media/pci/cx18/cx18-alsa-main.c
new file mode 100644
index 0000000..6d2a982
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-alsa-main.c
@@ -0,0 +1,295 @@
+/*
+ *  ALSA interface to cx18 PCM capture streams
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@md.metrocast.net>
+ *  Copyright (C) 2009  Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ *  Portions of this work were sponsored by ONELAN Limited.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+
+#include <media/v4l2-device.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+
+#include "cx18-driver.h"
+#include "cx18-version.h"
+#include "cx18-alsa.h"
+#include "cx18-alsa-mixer.h"
+#include "cx18-alsa-pcm.h"
+
+int cx18_alsa_debug;
+
+#define CX18_DEBUG_ALSA_INFO(fmt, arg...) \
+	do { \
+		if (cx18_alsa_debug & 2) \
+			printk(KERN_INFO "%s: " fmt, "cx18-alsa", ## arg); \
+	} while (0);
+
+module_param_named(debug, cx18_alsa_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+		 "Debug level (bitmask). Default: 0\n"
+		 "\t\t\t  1/0x0001: warning\n"
+		 "\t\t\t  2/0x0002: info\n");
+
+MODULE_AUTHOR("Andy Walls");
+MODULE_DESCRIPTION("CX23418 ALSA Interface");
+MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder");
+MODULE_LICENSE("GPL");
+
+MODULE_VERSION(CX18_VERSION);
+
+static inline
+struct snd_cx18_card *to_snd_cx18_card(struct v4l2_device *v4l2_dev)
+{
+	return to_cx18(v4l2_dev)->alsa;
+}
+
+static inline
+struct snd_cx18_card *p_to_snd_cx18_card(struct v4l2_device **v4l2_dev)
+{
+	return container_of(v4l2_dev, struct snd_cx18_card, v4l2_dev);
+}
+
+static void snd_cx18_card_free(struct snd_cx18_card *cxsc)
+{
+	if (cxsc == NULL)
+		return;
+
+	if (cxsc->v4l2_dev != NULL)
+		to_cx18(cxsc->v4l2_dev)->alsa = NULL;
+
+	/* FIXME - take any other stopping actions needed */
+
+	kfree(cxsc);
+}
+
+static void snd_cx18_card_private_free(struct snd_card *sc)
+{
+	if (sc == NULL)
+		return;
+	snd_cx18_card_free(sc->private_data);
+	sc->private_data = NULL;
+	sc->private_free = NULL;
+}
+
+static int snd_cx18_card_create(struct v4l2_device *v4l2_dev,
+				       struct snd_card *sc,
+				       struct snd_cx18_card **cxsc)
+{
+	*cxsc = kzalloc(sizeof(struct snd_cx18_card), GFP_KERNEL);
+	if (*cxsc == NULL)
+		return -ENOMEM;
+
+	(*cxsc)->v4l2_dev = v4l2_dev;
+	(*cxsc)->sc = sc;
+
+	sc->private_data = *cxsc;
+	sc->private_free = snd_cx18_card_private_free;
+
+	return 0;
+}
+
+static int snd_cx18_card_set_names(struct snd_cx18_card *cxsc)
+{
+	struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
+	struct snd_card *sc = cxsc->sc;
+
+	/* sc->driver is used by alsa-lib's configurator: simple, unique */
+	strlcpy(sc->driver, "CX23418", sizeof(sc->driver));
+
+	/* sc->shortname is a symlink in /proc/asound: CX18-M -> cardN */
+	snprintf(sc->shortname,  sizeof(sc->shortname), "CX18-%d",
+		 cx->instance);
+
+	/* sc->longname is read from /proc/asound/cards */
+	snprintf(sc->longname, sizeof(sc->longname),
+		 "CX23418 #%d %s TV/FM Radio/Line-In Capture",
+		 cx->instance, cx->card_name);
+
+	return 0;
+}
+
+static int snd_cx18_init(struct v4l2_device *v4l2_dev)
+{
+	struct cx18 *cx = to_cx18(v4l2_dev);
+	struct snd_card *sc = NULL;
+	struct snd_cx18_card *cxsc;
+	int ret;
+
+	/* Numbrs steps from "Writing an ALSA Driver" by Takashi Iwai */
+
+	/* (1) Check and increment the device index */
+	/* This is a no-op for us.  We'll use the cx->instance */
+
+	/* (2) Create a card instance */
+	ret = snd_card_create(SNDRV_DEFAULT_IDX1, /* use first available id */
+			      SNDRV_DEFAULT_STR1, /* xid from end of shortname*/
+			      THIS_MODULE, 0, &sc);
+	if (ret) {
+		CX18_ALSA_ERR("%s: snd_card_create() failed with err %d\n",
+			      __func__, ret);
+		goto err_exit;
+	}
+
+	/* (3) Create a main component */
+	ret = snd_cx18_card_create(v4l2_dev, sc, &cxsc);
+	if (ret) {
+		CX18_ALSA_ERR("%s: snd_cx18_card_create() failed with err %d\n",
+			      __func__, ret);
+		goto err_exit_free;
+	}
+
+	/* (4) Set the driver ID and name strings */
+	snd_cx18_card_set_names(cxsc);
+
+
+	ret = snd_cx18_pcm_create(cxsc);
+	if (ret) {
+		CX18_ALSA_ERR("%s: snd_cx18_pcm_create() failed with err %d\n",
+			      __func__, ret);
+		goto err_exit_free;
+	}
+	/* FIXME - proc files */
+
+	/* (7) Set the driver data and return 0 */
+	/* We do this out of normal order for PCI drivers to avoid races */
+	cx->alsa = cxsc;
+
+	/* (6) Register the card instance */
+	ret = snd_card_register(sc);
+	if (ret) {
+		cx->alsa = NULL;
+		CX18_ALSA_ERR("%s: snd_card_register() failed with err %d\n",
+			      __func__, ret);
+		goto err_exit_free;
+	}
+
+	return 0;
+
+err_exit_free:
+	if (sc != NULL)
+		snd_card_free(sc);
+	kfree(cxsc);
+err_exit:
+	return ret;
+}
+
+int cx18_alsa_load(struct cx18 *cx)
+{
+	struct v4l2_device *v4l2_dev = &cx->v4l2_dev;
+	struct cx18_stream *s;
+
+	if (v4l2_dev == NULL) {
+		printk(KERN_ERR "cx18-alsa: %s: struct v4l2_device * is NULL\n",
+		       __func__);
+		return 0;
+	}
+
+	cx = to_cx18(v4l2_dev);
+	if (cx == NULL) {
+		printk(KERN_ERR "cx18-alsa cx is NULL\n");
+		return 0;
+	}
+
+	s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM];
+	if (s->video_dev == NULL) {
+		CX18_DEBUG_ALSA_INFO("%s: PCM stream for card is disabled - "
+				     "skipping\n", __func__);
+		return 0;
+	}
+
+	if (cx->alsa != NULL) {
+		CX18_ALSA_ERR("%s: struct snd_cx18_card * already exists\n",
+			      __func__);
+		return 0;
+	}
+
+	if (snd_cx18_init(v4l2_dev)) {
+		CX18_ALSA_ERR("%s: failed to create struct snd_cx18_card\n",
+			      __func__);
+	} else {
+		CX18_DEBUG_ALSA_INFO("%s: created cx18 ALSA interface instance "
+				     "\n", __func__);
+	}
+	return 0;
+}
+
+static int __init cx18_alsa_init(void)
+{
+	printk(KERN_INFO "cx18-alsa: module loading...\n");
+	cx18_ext_init = &cx18_alsa_load;
+	return 0;
+}
+
+static void __exit snd_cx18_exit(struct snd_cx18_card *cxsc)
+{
+	struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
+
+	/* FIXME - pointer checks & shutdown cxsc */
+
+	snd_card_free(cxsc->sc);
+	cx->alsa = NULL;
+}
+
+static int __exit cx18_alsa_exit_callback(struct device *dev, void *data)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+	struct snd_cx18_card *cxsc;
+
+	if (v4l2_dev == NULL) {
+		printk(KERN_ERR "cx18-alsa: %s: struct v4l2_device * is NULL\n",
+		       __func__);
+		return 0;
+	}
+
+	cxsc = to_snd_cx18_card(v4l2_dev);
+	if (cxsc == NULL) {
+		CX18_ALSA_WARN("%s: struct snd_cx18_card * is NULL\n",
+			       __func__);
+		return 0;
+	}
+
+	snd_cx18_exit(cxsc);
+	return 0;
+}
+
+static void __exit cx18_alsa_exit(void)
+{
+	struct device_driver *drv;
+	int ret;
+
+	printk(KERN_INFO "cx18-alsa: module unloading...\n");
+
+	drv = driver_find("cx18", &pci_bus_type);
+	ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback);
+	(void)ret;	/* suppress compiler warning */
+
+	cx18_ext_init = NULL;
+	printk(KERN_INFO "cx18-alsa: module unload complete\n");
+}
+
+module_init(cx18_alsa_init);
+module_exit(cx18_alsa_exit);
diff --git a/drivers/media/pci/cx18/cx18-alsa-mixer.c b/drivers/media/pci/cx18/cx18-alsa-mixer.c
new file mode 100644
index 0000000..341bddc
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-alsa-mixer.c
@@ -0,0 +1,175 @@
+/*
+ *  ALSA mixer controls for the
+ *  ALSA interface to cx18 PCM capture streams
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+
+#include "cx18-alsa.h"
+#include "cx18-driver.h"
+
+/*
+ * Note the cx18-av-core volume scale is funny, due to the alignment of the
+ * scale with another chip's range:
+ *
+ * v4l2_control value	/512	indicated dB	actual dB	reg 0x8d4
+ * 0x0000 - 0x01ff	  0	-119		-96		228
+ * 0x0200 - 0x02ff	  1	-118		-96		228
+ * ...
+ * 0x2c00 - 0x2dff	 22	 -97		-96		228
+ * 0x2e00 - 0x2fff	 23	 -96		-96		228
+ * 0x3000 - 0x31ff	 24	 -95		-95		226
+ * ...
+ * 0xee00 - 0xefff	119	   0		  0		 36
+ * ...
+ * 0xfe00 - 0xffff	127	  +8		 +8		 20
+ */
+static inline int dB_to_cx18_av_vol(int dB)
+{
+	if (dB < -96)
+		dB = -96;
+	else if (dB > 8)
+		dB = 8;
+	return (dB + 119) << 9;
+}
+
+static inline int cx18_av_vol_to_dB(int v)
+{
+	if (v < (23 << 9))
+		v = (23 << 9);
+	else if (v > (127 << 9))
+		v = (127 << 9);
+	return (v >> 9) - 119;
+}
+
+static int snd_cx18_mixer_tv_vol_info(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	/* We're already translating values, just keep this control in dB */
+	uinfo->value.integer.min  = -96;
+	uinfo->value.integer.max  =   8;
+	uinfo->value.integer.step =   1;
+	return 0;
+}
+
+static int snd_cx18_mixer_tv_vol_get(struct snd_kcontrol *kctl,
+				     struct snd_ctl_elem_value *uctl)
+{
+	struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl);
+	struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
+	struct v4l2_control vctrl;
+	int ret;
+
+	vctrl.id = V4L2_CID_AUDIO_VOLUME;
+	vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]);
+
+	snd_cx18_lock(cxsc);
+	ret = v4l2_subdev_call(cx->sd_av, core, g_ctrl, &vctrl);
+	snd_cx18_unlock(cxsc);
+
+	if (!ret)
+		uctl->value.integer.value[0] = cx18_av_vol_to_dB(vctrl.value);
+	return ret;
+}
+
+static int snd_cx18_mixer_tv_vol_put(struct snd_kcontrol *kctl,
+				     struct snd_ctl_elem_value *uctl)
+{
+	struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl);
+	struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
+	struct v4l2_control vctrl;
+	int ret;
+
+	vctrl.id = V4L2_CID_AUDIO_VOLUME;
+	vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]);
+
+	snd_cx18_lock(cxsc);
+
+	/* Fetch current state */
+	ret = v4l2_subdev_call(cx->sd_av, core, g_ctrl, &vctrl);
+
+	if (ret ||
+	    (cx18_av_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) {
+
+		/* Set, if needed */
+		vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]);
+		ret = v4l2_subdev_call(cx->sd_av, core, s_ctrl, &vctrl);
+		if (!ret)
+			ret = 1; /* Indicate control was changed w/o error */
+	}
+	snd_cx18_unlock(cxsc);
+
+	return ret;
+}
+
+
+/* This is a bit of overkill, the slider is already in dB internally */
+static DECLARE_TLV_DB_SCALE(snd_cx18_mixer_tv_vol_db_scale, -9600, 100, 0);
+
+static struct snd_kcontrol_new snd_cx18_mixer_tv_vol __initdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Analog TV Capture Volume",
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+		  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+	.info = snd_cx18_mixer_tv_volume_info,
+	.get = snd_cx18_mixer_tv_volume_get,
+	.put = snd_cx18_mixer_tv_volume_put,
+	.tlv.p = snd_cx18_mixer_tv_vol_db_scale
+};
+
+/* FIXME - add mute switch and balance, bass, treble sliders:
+	V4L2_CID_AUDIO_MUTE
+
+	V4L2_CID_AUDIO_BALANCE
+
+	V4L2_CID_AUDIO_BASS
+	V4L2_CID_AUDIO_TREBLE
+*/
+
+/* FIXME - add stereo, lang1, lang2, mono menu */
+/* FIXME - add CS5345 I2S volume for HVR-1600 */
+
+int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc)
+{
+	struct v4l2_device *v4l2_dev = cxsc->v4l2_dev;
+	struct snd_card *sc = cxsc->sc;
+	int ret;
+
+	strlcpy(sc->mixername, "CX23418 Mixer", sizeof(sc->mixername));
+
+	ret = snd_ctl_add(sc, snd_ctl_new1(snd_cx18_mixer_tv_vol, cxsc));
+	if (ret) {
+		CX18_ALSA_WARN("%s: failed to add %s control, err %d\n",
+				__func__, snd_cx18_mixer_tv_vol.name, ret);
+	}
+	return ret;
+}
diff --git a/drivers/media/pci/cx18/cx18-alsa-mixer.h b/drivers/media/pci/cx18/cx18-alsa-mixer.h
new file mode 100644
index 0000000..ec92387
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-alsa-mixer.h
@@ -0,0 +1,23 @@
+/*
+ *  ALSA mixer controls for the
+ *  ALSA interface to cx18 PCM capture streams
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc);
diff --git a/drivers/media/pci/cx18/cx18-alsa-pcm.c b/drivers/media/pci/cx18/cx18-alsa-pcm.c
new file mode 100644
index 0000000..7a5b84a
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-alsa-pcm.c
@@ -0,0 +1,356 @@
+/*
+ *  ALSA PCM device for the
+ *  ALSA interface to cx18 PCM capture streams
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@md.metrocast.net>
+ *  Copyright (C) 2009  Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ *  Portions of this work were sponsored by ONELAN Limited.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+
+#include <media/v4l2-device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+#include "cx18-driver.h"
+#include "cx18-queue.h"
+#include "cx18-streams.h"
+#include "cx18-fileops.h"
+#include "cx18-alsa.h"
+
+static unsigned int pcm_debug;
+module_param(pcm_debug, int, 0644);
+MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm");
+
+#define dprintk(fmt, arg...) do {					\
+	    if (pcm_debug)						\
+		printk(KERN_INFO "cx18-alsa-pcm %s: " fmt,		\
+				  __func__, ##arg); 			\
+	} while (0)
+
+static struct snd_pcm_hardware snd_cx18_hw_capture = {
+	.info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		SNDRV_PCM_INFO_MMAP           |
+		SNDRV_PCM_INFO_INTERLEAVED    |
+		SNDRV_PCM_INFO_MMAP_VALID,
+
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+	.rates = SNDRV_PCM_RATE_48000,
+
+	.rate_min = 48000,
+	.rate_max = 48000,
+	.channels_min = 2,
+	.channels_max = 2,
+	.buffer_bytes_max = 62720 * 8,	/* just about the value in usbaudio.c */
+	.period_bytes_min = 64,		/* 12544/2, */
+	.period_bytes_max = 12544,
+	.periods_min = 2,
+	.periods_max = 98,		/* 12544, */
+};
+
+void cx18_alsa_announce_pcm_data(struct snd_cx18_card *cxsc, u8 *pcm_data,
+				 size_t num_bytes)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_pcm_runtime *runtime;
+	unsigned int oldptr;
+	unsigned int stride;
+	int period_elapsed = 0;
+	int length;
+
+	dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zd\n", cxsc,
+		pcm_data, num_bytes);
+
+	substream = cxsc->capture_pcm_substream;
+	if (substream == NULL) {
+		dprintk("substream was NULL\n");
+		return;
+	}
+
+	runtime = substream->runtime;
+	if (runtime == NULL) {
+		dprintk("runtime was NULL\n");
+		return;
+	}
+
+	stride = runtime->frame_bits >> 3;
+	if (stride == 0) {
+		dprintk("stride is zero\n");
+		return;
+	}
+
+	length = num_bytes / stride;
+	if (length == 0) {
+		dprintk("%s: length was zero\n", __func__);
+		return;
+	}
+
+	if (runtime->dma_area == NULL) {
+		dprintk("dma area was NULL - ignoring\n");
+		return;
+	}
+
+	oldptr = cxsc->hwptr_done_capture;
+	if (oldptr + length >= runtime->buffer_size) {
+		unsigned int cnt =
+			runtime->buffer_size - oldptr;
+		memcpy(runtime->dma_area + oldptr * stride, pcm_data,
+		       cnt * stride);
+		memcpy(runtime->dma_area, pcm_data + cnt * stride,
+		       length * stride - cnt * stride);
+	} else {
+		memcpy(runtime->dma_area + oldptr * stride, pcm_data,
+		       length * stride);
+	}
+	snd_pcm_stream_lock(substream);
+
+	cxsc->hwptr_done_capture += length;
+	if (cxsc->hwptr_done_capture >=
+	    runtime->buffer_size)
+		cxsc->hwptr_done_capture -=
+			runtime->buffer_size;
+
+	cxsc->capture_transfer_done += length;
+	if (cxsc->capture_transfer_done >=
+	    runtime->period_size) {
+		cxsc->capture_transfer_done -=
+			runtime->period_size;
+		period_elapsed = 1;
+	}
+
+	snd_pcm_stream_unlock(substream);
+
+	if (period_elapsed)
+		snd_pcm_period_elapsed(substream);
+}
+
+static int snd_cx18_pcm_capture_open(struct snd_pcm_substream *substream)
+{
+	struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct v4l2_device *v4l2_dev = cxsc->v4l2_dev;
+	struct cx18 *cx = to_cx18(v4l2_dev);
+	struct cx18_stream *s;
+	struct cx18_open_id item;
+	int ret;
+
+	/* Instruct the cx18 to start sending packets */
+	snd_cx18_lock(cxsc);
+	s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM];
+
+	item.cx = cx;
+	item.type = s->type;
+	item.open_id = cx->open_id++;
+
+	/* See if the stream is available */
+	if (cx18_claim_stream(&item, item.type)) {
+		/* No, it's already in use */
+		snd_cx18_unlock(cxsc);
+		return -EBUSY;
+	}
+
+	if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) ||
+	    test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+		/* We're already streaming.  No additional action required */
+		snd_cx18_unlock(cxsc);
+		return 0;
+	}
+
+
+	runtime->hw = snd_cx18_hw_capture;
+	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	cxsc->capture_pcm_substream = substream;
+	runtime->private_data = cx;
+
+	cx->pcm_announce_callback = cx18_alsa_announce_pcm_data;
+
+	/* Not currently streaming, so start it up */
+	set_bit(CX18_F_S_STREAMING, &s->s_flags);
+	ret = cx18_start_v4l2_encode_stream(s);
+	snd_cx18_unlock(cxsc);
+
+	return ret;
+}
+
+static int snd_cx18_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+	struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
+	struct v4l2_device *v4l2_dev = cxsc->v4l2_dev;
+	struct cx18 *cx = to_cx18(v4l2_dev);
+	struct cx18_stream *s;
+
+	/* Instruct the cx18 to stop sending packets */
+	snd_cx18_lock(cxsc);
+	s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM];
+	cx18_stop_v4l2_encode_stream(s, 0);
+	clear_bit(CX18_F_S_STREAMING, &s->s_flags);
+
+	cx18_release_stream(s);
+
+	cx->pcm_announce_callback = NULL;
+	snd_cx18_unlock(cxsc);
+
+	return 0;
+}
+
+static int snd_cx18_pcm_ioctl(struct snd_pcm_substream *substream,
+		     unsigned int cmd, void *arg)
+{
+	struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
+	int ret;
+
+	snd_cx18_lock(cxsc);
+	ret = snd_pcm_lib_ioctl(substream, cmd, arg);
+	snd_cx18_unlock(cxsc);
+	return ret;
+}
+
+
+static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
+					size_t size)
+{
+	struct snd_pcm_runtime *runtime = subs->runtime;
+
+	dprintk("Allocating vbuffer\n");
+	if (runtime->dma_area) {
+		if (runtime->dma_bytes > size)
+			return 0;
+
+		vfree(runtime->dma_area);
+	}
+	runtime->dma_area = vmalloc(size);
+	if (!runtime->dma_area)
+		return -ENOMEM;
+
+	runtime->dma_bytes = size;
+
+	return 0;
+}
+
+static int snd_cx18_pcm_hw_params(struct snd_pcm_substream *substream,
+			 struct snd_pcm_hw_params *params)
+{
+	dprintk("%s called\n", __func__);
+
+	return snd_pcm_alloc_vmalloc_buffer(substream,
+					   params_buffer_bytes(params));
+}
+
+static int snd_cx18_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
+	unsigned long flags;
+
+	spin_lock_irqsave(&cxsc->slock, flags);
+	if (substream->runtime->dma_area) {
+		dprintk("freeing pcm capture region\n");
+		vfree(substream->runtime->dma_area);
+		substream->runtime->dma_area = NULL;
+	}
+	spin_unlock_irqrestore(&cxsc->slock, flags);
+
+	return 0;
+}
+
+static int snd_cx18_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
+
+	cxsc->hwptr_done_capture = 0;
+	cxsc->capture_transfer_done = 0;
+
+	return 0;
+}
+
+static int snd_cx18_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	return 0;
+}
+
+static
+snd_pcm_uframes_t snd_cx18_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	unsigned long flags;
+	snd_pcm_uframes_t hwptr_done;
+	struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
+
+	spin_lock_irqsave(&cxsc->slock, flags);
+	hwptr_done = cxsc->hwptr_done_capture;
+	spin_unlock_irqrestore(&cxsc->slock, flags);
+
+	return hwptr_done;
+}
+
+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
+					     unsigned long offset)
+{
+	void *pageptr = subs->runtime->dma_area + offset;
+
+	return vmalloc_to_page(pageptr);
+}
+
+static struct snd_pcm_ops snd_cx18_pcm_capture_ops = {
+	.open		= snd_cx18_pcm_capture_open,
+	.close		= snd_cx18_pcm_capture_close,
+	.ioctl		= snd_cx18_pcm_ioctl,
+	.hw_params	= snd_cx18_pcm_hw_params,
+	.hw_free	= snd_cx18_pcm_hw_free,
+	.prepare	= snd_cx18_pcm_prepare,
+	.trigger	= snd_cx18_pcm_trigger,
+	.pointer	= snd_cx18_pcm_pointer,
+	.page		= snd_pcm_get_vmalloc_page,
+};
+
+int snd_cx18_pcm_create(struct snd_cx18_card *cxsc)
+{
+	struct snd_pcm *sp;
+	struct snd_card *sc = cxsc->sc;
+	struct v4l2_device *v4l2_dev = cxsc->v4l2_dev;
+	struct cx18 *cx = to_cx18(v4l2_dev);
+	int ret;
+
+	ret = snd_pcm_new(sc, "CX23418 PCM",
+			  0, /* PCM device 0, the only one for this card */
+			  0, /* 0 playback substreams */
+			  1, /* 1 capture substream */
+			  &sp);
+	if (ret) {
+		CX18_ALSA_ERR("%s: snd_cx18_pcm_create() failed with err %d\n",
+			      __func__, ret);
+		goto err_exit;
+	}
+
+	spin_lock_init(&cxsc->slock);
+
+	snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_CAPTURE,
+			&snd_cx18_pcm_capture_ops);
+	sp->info_flags = 0;
+	sp->private_data = cxsc;
+	strlcpy(sp->name, cx->card_name, sizeof(sp->name));
+
+	return 0;
+
+err_exit:
+	return ret;
+}
diff --git a/drivers/media/pci/cx18/cx18-alsa-pcm.h b/drivers/media/pci/cx18/cx18-alsa-pcm.h
new file mode 100644
index 0000000..d26e51f
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-alsa-pcm.h
@@ -0,0 +1,27 @@
+/*
+ *  ALSA PCM device for the
+ *  ALSA interface to cx18 PCM capture streams
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+int __init snd_cx18_pcm_create(struct snd_cx18_card *cxsc);
+
+/* Used by cx18-mailbox to announce the PCM data to the module */
+void cx18_alsa_announce_pcm_data(struct snd_cx18_card *card, u8 *pcm_data,
+				 size_t num_bytes);
diff --git a/drivers/media/pci/cx18/cx18-alsa.h b/drivers/media/pci/cx18/cx18-alsa.h
new file mode 100644
index 0000000..447da37
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-alsa.h
@@ -0,0 +1,75 @@
+/*
+ *  ALSA interface to cx18 PCM capture streams
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+struct snd_card;
+
+struct snd_cx18_card {
+	struct v4l2_device *v4l2_dev;
+	struct snd_card *sc;
+	unsigned int capture_transfer_done;
+	unsigned int hwptr_done_capture;
+	struct snd_pcm_substream *capture_pcm_substream;
+	spinlock_t slock;
+};
+
+extern int cx18_alsa_debug;
+
+/*
+ * File operations that manipulate the encoder or video or audio subdevices
+ * need to be serialized.  Use the same lock we use for v4l2 file ops.
+ */
+static inline void snd_cx18_lock(struct snd_cx18_card *cxsc)
+{
+	struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
+	mutex_lock(&cx->serialize_lock);
+}
+
+static inline void snd_cx18_unlock(struct snd_cx18_card *cxsc)
+{
+	struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
+	mutex_unlock(&cx->serialize_lock);
+}
+
+#define CX18_ALSA_DBGFLG_WARN  (1 << 0)
+#define CX18_ALSA_DBGFLG_WARN  (1 << 0)
+#define CX18_ALSA_DBGFLG_INFO  (1 << 1)
+
+#define CX18_ALSA_DEBUG(x, type, fmt, args...) \
+	do { \
+		if ((x) & cx18_alsa_debug) \
+			printk(KERN_INFO "%s-alsa: " type ": " fmt, \
+				v4l2_dev->name , ## args); \
+	} while (0)
+
+#define CX18_ALSA_DEBUG_WARN(fmt, args...) \
+	CX18_ALSA_DEBUG(CX18_ALSA_DBGFLG_WARN, "warning", fmt , ## args)
+
+#define CX18_ALSA_DEBUG_INFO(fmt, args...) \
+	CX18_ALSA_DEBUG(CX18_ALSA_DBGFLG_INFO, "info", fmt , ## args)
+
+#define CX18_ALSA_ERR(fmt, args...) \
+	printk(KERN_ERR "%s-alsa: " fmt, v4l2_dev->name , ## args)
+
+#define CX18_ALSA_WARN(fmt, args...) \
+	printk(KERN_WARNING "%s-alsa: " fmt, v4l2_dev->name , ## args)
+
+#define CX18_ALSA_INFO(fmt, args...) \
+	printk(KERN_INFO "%s-alsa: " fmt, v4l2_dev->name , ## args)
diff --git a/drivers/media/pci/cx18/cx18-audio.c b/drivers/media/pci/cx18/cx18-audio.c
new file mode 100644
index 0000000..3526892
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-audio.c
@@ -0,0 +1,92 @@
+/*
+ *  cx18 audio-related functions
+ *
+ *  Derived from ivtv-audio.c
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-io.h"
+#include "cx18-cards.h"
+#include "cx18-audio.h"
+
+#define CX18_AUDIO_ENABLE    0xc72014
+#define CX18_AI1_MUX_MASK    0x30
+#define CX18_AI1_MUX_I2S1    0x00
+#define CX18_AI1_MUX_I2S2    0x10
+#define CX18_AI1_MUX_843_I2S 0x20
+
+/* Selects the audio input and output according to the current
+   settings. */
+int cx18_audio_set_io(struct cx18 *cx)
+{
+	const struct cx18_card_audio_input *in;
+	u32 u, v;
+	int err;
+
+	/* Determine which input to use */
+	if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags))
+		in = &cx->card->radio_input;
+	else
+		in = &cx->card->audio_inputs[cx->audio_input];
+
+	/* handle muxer chips */
+	v4l2_subdev_call(cx->sd_extmux, audio, s_routing,
+			 (u32) in->muxer_input, 0, 0);
+
+	err = cx18_call_hw_err(cx, cx->card->hw_audio_ctrl,
+			       audio, s_routing, in->audio_input, 0, 0);
+	if (err)
+		return err;
+
+	/* FIXME - this internal mux should be abstracted to a subdev */
+	u = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
+	v = u & ~CX18_AI1_MUX_MASK;
+	switch (in->audio_input) {
+	case CX18_AV_AUDIO_SERIAL1:
+		v |= CX18_AI1_MUX_I2S1;
+		break;
+	case CX18_AV_AUDIO_SERIAL2:
+		v |= CX18_AI1_MUX_I2S2;
+		break;
+	default:
+		v |= CX18_AI1_MUX_843_I2S;
+		break;
+	}
+	if (v == u) {
+		/* force a toggle of some AI1 MUX control bits */
+		u &= ~CX18_AI1_MUX_MASK;
+		switch (in->audio_input) {
+		case CX18_AV_AUDIO_SERIAL1:
+			u |= CX18_AI1_MUX_843_I2S;
+			break;
+		case CX18_AV_AUDIO_SERIAL2:
+			u |= CX18_AI1_MUX_843_I2S;
+			break;
+		default:
+			u |= CX18_AI1_MUX_I2S1;
+			break;
+		}
+		cx18_write_reg_expect(cx, u | 0xb00, CX18_AUDIO_ENABLE,
+				      u, CX18_AI1_MUX_MASK);
+	}
+	cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+			      v, CX18_AI1_MUX_MASK);
+	return 0;
+}
diff --git a/drivers/media/pci/cx18/cx18-audio.h b/drivers/media/pci/cx18/cx18-audio.h
new file mode 100644
index 0000000..2731d29
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-audio.h
@@ -0,0 +1,24 @@
+/*
+ *  cx18 audio-related functions
+ *
+ *  Derived from ivtv-audio.c
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+int cx18_audio_set_io(struct cx18 *cx);
diff --git a/drivers/media/pci/cx18/cx18-av-audio.c b/drivers/media/pci/cx18/cx18-av-audio.c
new file mode 100644
index 0000000..4a24ffb
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-av-audio.c
@@ -0,0 +1,471 @@
+/*
+ *  cx18 ADEC audio functions
+ *
+ *  Derived from cx25840-audio.c
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#include "cx18-driver.h"
+
+static int set_audclk_freq(struct cx18 *cx, u32 freq)
+{
+	struct cx18_av_state *state = &cx->av_state;
+
+	if (freq != 32000 && freq != 44100 && freq != 48000)
+		return -EINVAL;
+
+	/*
+	 * The PLL parameters are based on the external crystal frequency that
+	 * would ideally be:
+	 *
+	 * NTSC Color subcarrier freq * 8 =
+	 * 	4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
+	 *
+	 * The accidents of history and rationale that explain from where this
+	 * combination of magic numbers originate can be found in:
+	 *
+	 * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in
+	 * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80
+	 *
+	 * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the
+	 * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83
+	 *
+	 * As Mike Bradley has rightly pointed out, it's not the exact crystal
+	 * frequency that matters, only that all parts of the driver and
+	 * firmware are using the same value (close to the ideal value).
+	 *
+	 * Since I have a strong suspicion that, if the firmware ever assumes a
+	 * crystal value at all, it will assume 28.636360 MHz, the crystal
+	 * freq used in calculations in this driver will be:
+	 *
+	 *	xtal_freq = 28.636360 MHz
+	 *
+	 * an error of less than 0.13 ppm which is way, way better than any off
+	 * the shelf crystal will have for accuracy anyway.
+	 *
+	 * Below I aim to run the PLLs' VCOs near 400 MHz to minimze error.
+	 *
+	 * Many thanks to Jeff Campbell and Mike Bradley for their extensive
+	 * investigation, experimentation, testing, and suggested solutions of
+	 * of audio/video sync problems with SVideo and CVBS captures.
+	 */
+
+	if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
+		switch (freq) {
+		case 32000:
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20
+			 */
+			cx18_av_write4(cx, 0x108, 0x200d040f);
+
+			/* VID_PLL Fraction = 0x2be2fe */
+			/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+			cx18_av_write4(cx, 0x10c, 0x002be2fe);
+
+			/* AUX_PLL Fraction = 0x176740c */
+			/* xtal * 0xd.bb3a060/0x20 = 32000 * 384: 393 MHz p-pd*/
+			cx18_av_write4(cx, 0x110, 0x0176740c);
+
+			/* src3/4/6_ctl */
+			/* 0x1.f77f = (4 * xtal/8*2/455) / 32000 */
+			cx18_av_write4(cx, 0x900, 0x0801f77f);
+			cx18_av_write4(cx, 0x904, 0x0801f77f);
+			cx18_av_write4(cx, 0x90c, 0x0801f77f);
+
+			/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */
+			cx18_av_write(cx, 0x127, 0x60);
+
+			/* AUD_COUNT = 0x2fff = 8 samples * 4 * 384 - 1 */
+			cx18_av_write4(cx, 0x12c, 0x11202fff);
+
+			/*
+			 * EN_AV_LOCK = 0
+			 * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 =
+			 *  ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8
+			 */
+			cx18_av_write4(cx, 0x128, 0xa00d2ef8);
+			break;
+
+		case 44100:
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x18
+			 */
+			cx18_av_write4(cx, 0x108, 0x180e040f);
+
+			/* VID_PLL Fraction = 0x2be2fe */
+			/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+			cx18_av_write4(cx, 0x10c, 0x002be2fe);
+
+			/* AUX_PLL Fraction = 0x062a1f2 */
+			/* xtal * 0xe.3150f90/0x18 = 44100 * 384: 406 MHz p-pd*/
+			cx18_av_write4(cx, 0x110, 0x0062a1f2);
+
+			/* src3/4/6_ctl */
+			/* 0x1.6d59 = (4 * xtal/8*2/455) / 44100 */
+			cx18_av_write4(cx, 0x900, 0x08016d59);
+			cx18_av_write4(cx, 0x904, 0x08016d59);
+			cx18_av_write4(cx, 0x90c, 0x08016d59);
+
+			/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x18 */
+			cx18_av_write(cx, 0x127, 0x58);
+
+			/* AUD_COUNT = 0x92ff = 49 samples * 2 * 384 - 1 */
+			cx18_av_write4(cx, 0x12c, 0x112092ff);
+
+			/*
+			 * EN_AV_LOCK = 0
+			 * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 =
+			 *  ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8
+			 */
+			cx18_av_write4(cx, 0x128, 0xa01d4bf8);
+			break;
+
+		case 48000:
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x16
+			 */
+			cx18_av_write4(cx, 0x108, 0x160e040f);
+
+			/* VID_PLL Fraction = 0x2be2fe */
+			/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+			cx18_av_write4(cx, 0x10c, 0x002be2fe);
+
+			/* AUX_PLL Fraction = 0x05227ad */
+			/* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz p-pd*/
+			cx18_av_write4(cx, 0x110, 0x005227ad);
+
+			/* src3/4/6_ctl */
+			/* 0x1.4faa = (4 * xtal/8*2/455) / 48000 */
+			cx18_av_write4(cx, 0x900, 0x08014faa);
+			cx18_av_write4(cx, 0x904, 0x08014faa);
+			cx18_av_write4(cx, 0x90c, 0x08014faa);
+
+			/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
+			cx18_av_write(cx, 0x127, 0x56);
+
+			/* AUD_COUNT = 0x5fff = 4 samples * 16 * 384 - 1 */
+			cx18_av_write4(cx, 0x12c, 0x11205fff);
+
+			/*
+			 * EN_AV_LOCK = 0
+			 * VID_COUNT = 0x1193f8 = 143999.000 * 8 =
+			 *  ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8
+			 */
+			cx18_av_write4(cx, 0x128, 0xa01193f8);
+			break;
+		}
+	} else {
+		switch (freq) {
+		case 32000:
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x30
+			 */
+			cx18_av_write4(cx, 0x108, 0x300d040f);
+
+			/* VID_PLL Fraction = 0x2be2fe */
+			/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+			cx18_av_write4(cx, 0x10c, 0x002be2fe);
+
+			/* AUX_PLL Fraction = 0x176740c */
+			/* xtal * 0xd.bb3a060/0x30 = 32000 * 256: 393 MHz p-pd*/
+			cx18_av_write4(cx, 0x110, 0x0176740c);
+
+			/* src1_ctl */
+			/* 0x1.0000 = 32000/32000 */
+			cx18_av_write4(cx, 0x8f8, 0x08010000);
+
+			/* src3/4/6_ctl */
+			/* 0x2.0000 = 2 * (32000/32000) */
+			cx18_av_write4(cx, 0x900, 0x08020000);
+			cx18_av_write4(cx, 0x904, 0x08020000);
+			cx18_av_write4(cx, 0x90c, 0x08020000);
+
+			/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x30 */
+			cx18_av_write(cx, 0x127, 0x70);
+
+			/* AUD_COUNT = 0x1fff = 8 samples * 4 * 256 - 1 */
+			cx18_av_write4(cx, 0x12c, 0x11201fff);
+
+			/*
+			 * EN_AV_LOCK = 0
+			 * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 =
+			 *  ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8
+			 */
+			cx18_av_write4(cx, 0x128, 0xa00d2ef8);
+			break;
+
+		case 44100:
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x24
+			 */
+			cx18_av_write4(cx, 0x108, 0x240e040f);
+
+			/* VID_PLL Fraction = 0x2be2fe */
+			/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+			cx18_av_write4(cx, 0x10c, 0x002be2fe);
+
+			/* AUX_PLL Fraction = 0x062a1f2 */
+			/* xtal * 0xe.3150f90/0x24 = 44100 * 256: 406 MHz p-pd*/
+			cx18_av_write4(cx, 0x110, 0x0062a1f2);
+
+			/* src1_ctl */
+			/* 0x1.60cd = 44100/32000 */
+			cx18_av_write4(cx, 0x8f8, 0x080160cd);
+
+			/* src3/4/6_ctl */
+			/* 0x1.7385 = 2 * (32000/44100) */
+			cx18_av_write4(cx, 0x900, 0x08017385);
+			cx18_av_write4(cx, 0x904, 0x08017385);
+			cx18_av_write4(cx, 0x90c, 0x08017385);
+
+			/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x24 */
+			cx18_av_write(cx, 0x127, 0x64);
+
+			/* AUD_COUNT = 0x61ff = 49 samples * 2 * 256 - 1 */
+			cx18_av_write4(cx, 0x12c, 0x112061ff);
+
+			/*
+			 * EN_AV_LOCK = 0
+			 * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 =
+			 *  ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8
+			 */
+			cx18_av_write4(cx, 0x128, 0xa01d4bf8);
+			break;
+
+		case 48000:
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20
+			 */
+			cx18_av_write4(cx, 0x108, 0x200d040f);
+
+			/* VID_PLL Fraction = 0x2be2fe */
+			/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+			cx18_av_write4(cx, 0x10c, 0x002be2fe);
+
+			/* AUX_PLL Fraction = 0x176740c */
+			/* xtal * 0xd.bb3a060/0x20 = 48000 * 256: 393 MHz p-pd*/
+			cx18_av_write4(cx, 0x110, 0x0176740c);
+
+			/* src1_ctl */
+			/* 0x1.8000 = 48000/32000 */
+			cx18_av_write4(cx, 0x8f8, 0x08018000);
+
+			/* src3/4/6_ctl */
+			/* 0x1.5555 = 2 * (32000/48000) */
+			cx18_av_write4(cx, 0x900, 0x08015555);
+			cx18_av_write4(cx, 0x904, 0x08015555);
+			cx18_av_write4(cx, 0x90c, 0x08015555);
+
+			/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */
+			cx18_av_write(cx, 0x127, 0x60);
+
+			/* AUD_COUNT = 0x3fff = 4 samples * 16 * 256 - 1 */
+			cx18_av_write4(cx, 0x12c, 0x11203fff);
+
+			/*
+			 * EN_AV_LOCK = 0
+			 * VID_COUNT = 0x1193f8 = 143999.000 * 8 =
+			 *  ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8
+			 */
+			cx18_av_write4(cx, 0x128, 0xa01193f8);
+			break;
+		}
+	}
+
+	state->audclk_freq = freq;
+
+	return 0;
+}
+
+void cx18_av_audio_set_path(struct cx18 *cx)
+{
+	struct cx18_av_state *state = &cx->av_state;
+	u8 v;
+
+	/* stop microcontroller */
+	v = cx18_av_read(cx, 0x803) & ~0x10;
+	cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
+
+	/* assert soft reset */
+	v = cx18_av_read(cx, 0x810) | 0x01;
+	cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
+
+	/* Mute everything to prevent the PFFT! */
+	cx18_av_write(cx, 0x8d3, 0x1f);
+
+	if (state->aud_input <= CX18_AV_AUDIO_SERIAL2) {
+		/* Set Path1 to Serial Audio Input */
+		cx18_av_write4(cx, 0x8d0, 0x01011012);
+
+		/* The microcontroller should not be started for the
+		 * non-tuner inputs: autodetection is specific for
+		 * TV audio. */
+	} else {
+		/* Set Path1 to Analog Demod Main Channel */
+		cx18_av_write4(cx, 0x8d0, 0x1f063870);
+	}
+
+	set_audclk_freq(cx, state->audclk_freq);
+
+	/* deassert soft reset */
+	v = cx18_av_read(cx, 0x810) & ~0x01;
+	cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
+
+	if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
+		/* When the microcontroller detects the
+		 * audio format, it will unmute the lines */
+		v = cx18_av_read(cx, 0x803) | 0x10;
+		cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
+	}
+}
+
+static void set_volume(struct cx18 *cx, int volume)
+{
+	/* First convert the volume to msp3400 values (0-127) */
+	int vol = volume >> 9;
+	/* now scale it up to cx18_av values
+	 * -114dB to -96dB maps to 0
+	 * this should be 19, but in my testing that was 4dB too loud */
+	if (vol <= 23)
+		vol = 0;
+	else
+		vol -= 23;
+
+	/* PATH1_VOLUME */
+	cx18_av_write(cx, 0x8d4, 228 - (vol * 2));
+}
+
+static void set_bass(struct cx18 *cx, int bass)
+{
+	/* PATH1_EQ_BASS_VOL */
+	cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
+}
+
+static void set_treble(struct cx18 *cx, int treble)
+{
+	/* PATH1_EQ_TREBLE_VOL */
+	cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
+}
+
+static void set_balance(struct cx18 *cx, int balance)
+{
+	int bal = balance >> 8;
+	if (bal > 0x80) {
+		/* PATH1_BAL_LEFT */
+		cx18_av_and_or(cx, 0x8d5, 0x7f, 0x80);
+		/* PATH1_BAL_LEVEL */
+		cx18_av_and_or(cx, 0x8d5, ~0x7f, bal & 0x7f);
+	} else {
+		/* PATH1_BAL_LEFT */
+		cx18_av_and_or(cx, 0x8d5, 0x7f, 0x00);
+		/* PATH1_BAL_LEVEL */
+		cx18_av_and_or(cx, 0x8d5, ~0x7f, 0x80 - bal);
+	}
+}
+
+static void set_mute(struct cx18 *cx, int mute)
+{
+	struct cx18_av_state *state = &cx->av_state;
+	u8 v;
+
+	if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
+		/* Must turn off microcontroller in order to mute sound.
+		 * Not sure if this is the best method, but it does work.
+		 * If the microcontroller is running, then it will undo any
+		 * changes to the mute register. */
+		v = cx18_av_read(cx, 0x803);
+		if (mute) {
+			/* disable microcontroller */
+			v &= ~0x10;
+			cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
+			cx18_av_write(cx, 0x8d3, 0x1f);
+		} else {
+			/* enable microcontroller */
+			v |= 0x10;
+			cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
+		}
+	} else {
+		/* SRC1_MUTE_EN */
+		cx18_av_and_or(cx, 0x8d3, ~0x2, mute ? 0x02 : 0x00);
+	}
+}
+
+int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
+{
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+	struct cx18_av_state *state = &cx->av_state;
+	int retval;
+	u8 v;
+
+	if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
+		v = cx18_av_read(cx, 0x803) & ~0x10;
+		cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
+		cx18_av_write(cx, 0x8d3, 0x1f);
+	}
+	v = cx18_av_read(cx, 0x810) | 0x1;
+	cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
+
+	retval = set_audclk_freq(cx, freq);
+
+	v = cx18_av_read(cx, 0x810) & ~0x1;
+	cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
+	if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
+		v = cx18_av_read(cx, 0x803) | 0x10;
+		cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
+	}
+	return retval;
+}
+
+static int cx18_av_audio_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		set_volume(cx, ctrl->val);
+		break;
+	case V4L2_CID_AUDIO_BASS:
+		set_bass(cx, ctrl->val);
+		break;
+	case V4L2_CID_AUDIO_TREBLE:
+		set_treble(cx, ctrl->val);
+		break;
+	case V4L2_CID_AUDIO_BALANCE:
+		set_balance(cx, ctrl->val);
+		break;
+	case V4L2_CID_AUDIO_MUTE:
+		set_mute(cx, ctrl->val);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops = {
+	.s_ctrl = cx18_av_audio_s_ctrl,
+};
diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c
new file mode 100644
index 0000000..f164b7f
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-av-core.c
@@ -0,0 +1,1401 @@
+/*
+ *  cx18 ADEC audio functions
+ *
+ *  Derived from cx25840-core.c
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#include <media/v4l2-chip-ident.h>
+#include "cx18-driver.h"
+#include "cx18-io.h"
+#include "cx18-cards.h"
+
+int cx18_av_write(struct cx18 *cx, u16 addr, u8 value)
+{
+	u32 reg = 0xc40000 + (addr & ~3);
+	u32 mask = 0xff;
+	int shift = (addr & 3) * 8;
+	u32 x = cx18_read_reg(cx, reg);
+
+	x = (x & ~(mask << shift)) | ((u32)value << shift);
+	cx18_write_reg(cx, x, reg);
+	return 0;
+}
+
+int cx18_av_write_expect(struct cx18 *cx, u16 addr, u8 value, u8 eval, u8 mask)
+{
+	u32 reg = 0xc40000 + (addr & ~3);
+	int shift = (addr & 3) * 8;
+	u32 x = cx18_read_reg(cx, reg);
+
+	x = (x & ~((u32)0xff << shift)) | ((u32)value << shift);
+	cx18_write_reg_expect(cx, x, reg,
+				((u32)eval << shift), ((u32)mask << shift));
+	return 0;
+}
+
+int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value)
+{
+	cx18_write_reg(cx, value, 0xc40000 + addr);
+	return 0;
+}
+
+int
+cx18_av_write4_expect(struct cx18 *cx, u16 addr, u32 value, u32 eval, u32 mask)
+{
+	cx18_write_reg_expect(cx, value, 0xc40000 + addr, eval, mask);
+	return 0;
+}
+
+int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value)
+{
+	cx18_write_reg_noretry(cx, value, 0xc40000 + addr);
+	return 0;
+}
+
+u8 cx18_av_read(struct cx18 *cx, u16 addr)
+{
+	u32 x = cx18_read_reg(cx, 0xc40000 + (addr & ~3));
+	int shift = (addr & 3) * 8;
+
+	return (x >> shift) & 0xff;
+}
+
+u32 cx18_av_read4(struct cx18 *cx, u16 addr)
+{
+	return cx18_read_reg(cx, 0xc40000 + addr);
+}
+
+int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask,
+		   u8 or_value)
+{
+	return cx18_av_write(cx, addr,
+			     (cx18_av_read(cx, addr) & and_mask) |
+			     or_value);
+}
+
+int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
+		   u32 or_value)
+{
+	return cx18_av_write4(cx, addr,
+			     (cx18_av_read4(cx, addr) & and_mask) |
+			     or_value);
+}
+
+static void cx18_av_init(struct cx18 *cx)
+{
+	/*
+	 * The crystal freq used in calculations in this driver will be
+	 * 28.636360 MHz.
+	 * Aim to run the PLLs' VCOs near 400 MHz to minimze errors.
+	 */
+
+	/*
+	 * VDCLK  Integer = 0x0f, Post Divider = 0x04
+	 * AIMCLK Integer = 0x0e, Post Divider = 0x16
+	 */
+	cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
+
+	/* VDCLK Fraction = 0x2be2fe */
+	/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
+	cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
+
+	/* AIMCLK Fraction = 0x05227ad */
+	/* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/
+	cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
+
+	/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
+	cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
+}
+
+static void cx18_av_initialize(struct v4l2_subdev *sd)
+{
+	struct cx18_av_state *state = to_cx18_av_state(sd);
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+	int default_volume;
+	u32 v;
+
+	cx18_av_loadfw(cx);
+	/* Stop 8051 code execution */
+	cx18_av_write4_expect(cx, CXADEC_DL_CTL, 0x03000000,
+						 0x03000000, 0x13000000);
+
+	/* initallize the PLL by toggling sleep bit */
+	v = cx18_av_read4(cx, CXADEC_HOST_REG1);
+	/* enable sleep mode - register appears to be read only... */
+	cx18_av_write4_expect(cx, CXADEC_HOST_REG1, v | 1, v, 0xfffe);
+	/* disable sleep mode */
+	cx18_av_write4_expect(cx, CXADEC_HOST_REG1, v & 0xfffe,
+						    v & 0xfffe, 0xffff);
+
+	/* initialize DLLs */
+	v = cx18_av_read4(cx, CXADEC_DLL1_DIAG_CTRL) & 0xE1FFFEFF;
+	/* disable FLD */
+	cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v);
+	/* enable FLD */
+	cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v | 0x10000100);
+
+	v = cx18_av_read4(cx, CXADEC_DLL2_DIAG_CTRL) & 0xE1FFFEFF;
+	/* disable FLD */
+	cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v);
+	/* enable FLD */
+	cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v | 0x06000100);
+
+	/* set analog bias currents. Set Vreg to 1.20V. */
+	cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL1, 0x000A1802);
+
+	v = cx18_av_read4(cx, CXADEC_AFE_DIAG_CTRL3) | 1;
+	/* enable TUNE_FIL_RST */
+	cx18_av_write4_expect(cx, CXADEC_AFE_DIAG_CTRL3, v, v, 0x03009F0F);
+	/* disable TUNE_FIL_RST */
+	cx18_av_write4_expect(cx, CXADEC_AFE_DIAG_CTRL3,
+			      v & 0xFFFFFFFE, v & 0xFFFFFFFE, 0x03009F0F);
+
+	/* enable 656 output */
+	cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x040C00);
+
+	/* video output drive strength */
+	cx18_av_and_or4(cx, CXADEC_PIN_CTRL2, ~0, 0x2);
+
+	/* reset video */
+	cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000);
+	cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0);
+
+	/*
+	 * Disable Video Auto-config of the Analog Front End and Video PLL.
+	 *
+	 * Since we only use BT.656 pixel mode, which works for both 525 and 625
+	 * line systems, it's just easier for us to set registers
+	 * 0x102 (CXADEC_CHIP_CTRL), 0x104-0x106 (CXADEC_AFE_CTRL),
+	 * 0x108-0x109 (CXADEC_PLL_CTRL1), and 0x10c-0x10f (CXADEC_VID_PLL_FRAC)
+	 * ourselves, than to run around cleaning up after the auto-config.
+	 *
+	 * (Note: my CX23418 chip doesn't seem to let the ACFG_DIS bit
+	 * get set to 1, but OTOH, it doesn't seem to do AFE and VID PLL
+	 * autoconfig either.)
+	 *
+	 * As a default, also turn off Dual mode for ADC2 and set ADC2 to CH3.
+	 */
+	cx18_av_and_or4(cx, CXADEC_CHIP_CTRL, 0xFFFBFFFF, 0x00120000);
+
+	/* Setup the Video and and Aux/Audio PLLs */
+	cx18_av_init(cx);
+
+	/* set video to auto-detect */
+	/* Clear bits 11-12 to enable slow locking mode.  Set autodetect mode */
+	/* set the comb notch = 1 */
+	cx18_av_and_or4(cx, CXADEC_MODE_CTRL, 0xFFF7E7F0, 0x02040800);
+
+	/* Enable wtw_en in CRUSH_CTRL (Set bit 22) */
+	/* Enable maj_sel in CRUSH_CTRL (Set bit 20) */
+	cx18_av_and_or4(cx, CXADEC_CRUSH_CTRL, ~0, 0x00500000);
+
+	/* Set VGA_TRACK_RANGE to 0x20 */
+	cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000);
+
+	/*
+	 * Initial VBI setup
+	 * VIP-1.1, 10 bit mode, enable Raw, disable sliced,
+	 * don't clamp raw samples when codes are in use, 1 byte user D-words,
+	 * IDID0 has line #, RP code V bit transition on VBLANK, data during
+	 * blanking intervals
+	 */
+	cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4013252e);
+
+	/* Set the video input.
+	   The setting in MODE_CTRL gets lost when we do the above setup */
+	/* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */
+	/* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */
+
+	/*
+	 * Analog Front End (AFE)
+	 * Default to luma on ch1/ADC1, chroma on ch2/ADC2, SIF on ch3/ADC2
+	 *  bypass_ch[1-3]     use filter
+	 *  droop_comp_ch[1-3] disable
+	 *  clamp_en_ch[1-3]   disable
+	 *  aud_in_sel         ADC2
+	 *  luma_in_sel        ADC1
+	 *  chroma_in_sel      ADC2
+	 *  clamp_sel_ch[2-3]  midcode
+	 *  clamp_sel_ch1      video decoder
+	 *  vga_sel_ch3        audio decoder
+	 *  vga_sel_ch[1-2]    video decoder
+	 *  half_bw_ch[1-3]    disable
+	 *  +12db_ch[1-3]      disable
+	 */
+	cx18_av_and_or4(cx, CXADEC_AFE_CTRL, 0xFF000000, 0x00005D00);
+
+/* 	if(dwEnable && dw3DCombAvailable) { */
+/*      	CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */
+/*    } else { */
+/*      	CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */
+/*    } */
+	cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F);
+	default_volume = cx18_av_read(cx, 0x8d4);
+	/*
+	 * Enforce the legacy volume scale mapping limits to avoid
+	 * -ERANGE errors when initializing the volume control
+	 */
+	if (default_volume > 228) {
+		/* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */
+		default_volume = 228;
+		cx18_av_write(cx, 0x8d4, 228);
+	} else if (default_volume < 20) {
+		/* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */
+		default_volume = 20;
+		cx18_av_write(cx, 0x8d4, 20);
+	}
+	default_volume = (((228 - default_volume) >> 1) + 23) << 9;
+	state->volume->cur.val = state->volume->default_value = default_volume;
+	v4l2_ctrl_handler_setup(&state->hdl);
+}
+
+static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
+{
+	cx18_av_initialize(sd);
+	return 0;
+}
+
+static int cx18_av_load_fw(struct v4l2_subdev *sd)
+{
+	struct cx18_av_state *state = to_cx18_av_state(sd);
+
+	if (!state->is_initialized) {
+		/* initialize on first use */
+		state->is_initialized = 1;
+		cx18_av_initialize(sd);
+	}
+	return 0;
+}
+
+void cx18_av_std_setup(struct cx18 *cx)
+{
+	struct cx18_av_state *state = &cx->av_state;
+	struct v4l2_subdev *sd = &state->sd;
+	v4l2_std_id std = state->std;
+
+	/*
+	 * Video ADC crystal clock to pixel clock SRC decimation ratio
+	 * 28.636360 MHz/13.5 Mpps * 256 = 0x21f.07b
+	 */
+	const int src_decimation = 0x21f;
+
+	int hblank, hactive, burst, vblank, vactive, sc;
+	int vblank656;
+	int luma_lpf, uv_lpf, comb;
+	u32 pll_int, pll_frac, pll_post;
+
+	/* datasheet startup, step 8d */
+	if (std & ~V4L2_STD_NTSC)
+		cx18_av_write(cx, 0x49f, 0x11);
+	else
+		cx18_av_write(cx, 0x49f, 0x14);
+
+	/*
+	 * Note: At the end of a field, there are 3 sets of half line duration
+	 * (double horizontal rate) pulses:
+	 *
+	 * 5 (625) or 6 (525) half-lines to blank for the vertical retrace
+	 * 5 (625) or 6 (525) vertical sync pulses of half line duration
+	 * 5 (625) or 6 (525) half-lines of equalization pulses
+	 */
+	if (std & V4L2_STD_625_50) {
+		/*
+		 * The following relationships of half line counts should hold:
+		 * 625 = vblank656 + vactive
+		 * 10 = vblank656 - vblank = vsync pulses + equalization pulses
+		 *
+		 * vblank656: half lines after line 625/mid-313 of blanked video
+		 * vblank:    half lines, after line 5/317, of blanked video
+		 * vactive:   half lines of active video +
+		 * 		5 half lines after the end of active video
+		 *
+		 * As far as I can tell:
+		 * vblank656 starts counting from the falling edge of the first
+		 * 	vsync pulse (start of line 1 or mid-313)
+		 * vblank starts counting from the after the 5 vsync pulses and
+		 * 	5 or 4 equalization pulses (start of line 6 or 318)
+		 *
+		 * For 625 line systems the driver will extract VBI information
+		 * from lines 6-23 and lines 318-335 (but the slicer can only
+		 * handle 17 lines, not the 18 in the vblank region).
+		 * In addition, we need vblank656 and vblank to be one whole
+		 * line longer, to cover line 24 and 336, so the SAV/EAV RP
+		 * codes get generated such that the encoder can actually
+		 * extract line 23 & 335 (WSS).  We'll lose 1 line in each field
+		 * at the top of the screen.
+		 *
+		 * It appears the 5 half lines that happen after active
+		 * video must be included in vactive (579 instead of 574),
+		 * otherwise the colors get badly displayed in various regions
+		 * of the screen.  I guess the chroma comb filter gets confused
+		 * without them (at least when a PVR-350 is the PAL source).
+		 */
+		vblank656 = 48; /* lines  1 -  24  &  313 - 336 */
+		vblank = 38;    /* lines  6 -  24  &  318 - 336 */
+		vactive = 579;  /* lines 24 - 313  &  337 - 626 */
+
+		/*
+		 * For a 13.5 Mpps clock and 15,625 Hz line rate, a line is
+		 * is 864 pixels = 720 active + 144 blanking.  ITU-R BT.601
+		 * specifies 12 luma clock periods or ~ 0.9 * 13.5 Mpps after
+		 * the end of active video to start a horizontal line, so that
+		 * leaves 132 pixels of hblank to ignore.
+		 */
+		hblank = 132;
+		hactive = 720;
+
+		/*
+		 * Burst gate delay (for 625 line systems)
+		 * Hsync leading edge to color burst rise = 5.6 us
+		 * Color burst width = 2.25 us
+		 * Gate width = 4 pixel clocks
+		 * (5.6 us + 2.25/2 us) * 13.5 Mpps + 4/2 clocks = 92.79 clocks
+		 */
+		burst = 93;
+		luma_lpf = 2;
+		if (std & V4L2_STD_PAL) {
+			uv_lpf = 1;
+			comb = 0x20;
+			/* sc = 4433618.75 * src_decimation/28636360 * 2^13 */
+			sc = 688700;
+		} else if (std == V4L2_STD_PAL_Nc) {
+			uv_lpf = 1;
+			comb = 0x20;
+			/* sc = 3582056.25 * src_decimation/28636360 * 2^13 */
+			sc = 556422;
+		} else { /* SECAM */
+			uv_lpf = 0;
+			comb = 0;
+			/* (fr + fb)/2 = (4406260 + 4250000)/2 = 4328130 */
+			/* sc = 4328130 * src_decimation/28636360 * 2^13 */
+			sc = 672314;
+		}
+	} else {
+		/*
+		 * The following relationships of half line counts should hold:
+		 * 525 = prevsync + vblank656 + vactive
+		 * 12 = vblank656 - vblank = vsync pulses + equalization pulses
+		 *
+		 * prevsync:  6 half-lines before the vsync pulses
+		 * vblank656: half lines, after line 3/mid-266, of blanked video
+		 * vblank:    half lines, after line 9/272, of blanked video
+		 * vactive:   half lines of active video
+		 *
+		 * As far as I can tell:
+		 * vblank656 starts counting from the falling edge of the first
+		 * 	vsync pulse (start of line 4 or mid-266)
+		 * vblank starts counting from the after the 6 vsync pulses and
+		 * 	6 or 5 equalization pulses (start of line 10 or 272)
+		 *
+		 * For 525 line systems the driver will extract VBI information
+		 * from lines 10-21 and lines 273-284.
+		 */
+		vblank656 = 38; /* lines  4 -  22  &  266 - 284 */
+		vblank = 26;	/* lines 10 -  22  &  272 - 284 */
+		vactive = 481;  /* lines 23 - 263  &  285 - 525 */
+
+		/*
+		 * For a 13.5 Mpps clock and 15,734.26 Hz line rate, a line is
+		 * is 858 pixels = 720 active + 138 blanking.  The Hsync leading
+		 * edge should happen 1.2 us * 13.5 Mpps ~= 16 pixels after the
+		 * end of active video, leaving 122 pixels of hblank to ignore
+		 * before active video starts.
+		 */
+		hactive = 720;
+		hblank = 122;
+		luma_lpf = 1;
+		uv_lpf = 1;
+
+		/*
+		 * Burst gate delay (for 525 line systems)
+		 * Hsync leading edge to color burst rise = 5.3 us
+		 * Color burst width = 2.5 us
+		 * Gate width = 4 pixel clocks
+		 * (5.3 us + 2.5/2 us) * 13.5 Mpps + 4/2 clocks = 90.425 clocks
+		 */
+		if (std == V4L2_STD_PAL_60) {
+			burst = 90;
+			luma_lpf = 2;
+			comb = 0x20;
+			/* sc = 4433618.75 * src_decimation/28636360 * 2^13 */
+			sc = 688700;
+		} else if (std == V4L2_STD_PAL_M) {
+			/* The 97 needs to be verified against PAL-M timings */
+			burst = 97;
+			comb = 0x20;
+			/* sc = 3575611.49 * src_decimation/28636360 * 2^13 */
+			sc = 555421;
+		} else {
+			burst = 90;
+			comb = 0x66;
+			/* sc = 3579545.45.. * src_decimation/28636360 * 2^13 */
+			sc = 556032;
+		}
+	}
+
+	/* DEBUG: Displays configured PLL frequency */
+	pll_int = cx18_av_read(cx, 0x108);
+	pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff;
+	pll_post = cx18_av_read(cx, 0x109);
+	CX18_DEBUG_INFO_DEV(sd, "PLL regs = int: %u, frac: %u, post: %u\n",
+			    pll_int, pll_frac, pll_post);
+
+	if (pll_post) {
+		int fsc, pll;
+		u64 tmp;
+
+		pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25;
+		pll /= pll_post;
+		CX18_DEBUG_INFO_DEV(sd, "Video PLL = %d.%06d MHz\n",
+				    pll / 1000000, pll % 1000000);
+		CX18_DEBUG_INFO_DEV(sd, "Pixel rate = %d.%06d Mpixel/sec\n",
+				    pll / 8000000, (pll / 8) % 1000000);
+
+		CX18_DEBUG_INFO_DEV(sd, "ADC XTAL/pixel clock decimation ratio "
+				    "= %d.%03d\n", src_decimation / 256,
+				    ((src_decimation % 256) * 1000) / 256);
+
+		tmp = 28636360 * (u64) sc;
+		do_div(tmp, src_decimation);
+		fsc = tmp >> 13;
+		CX18_DEBUG_INFO_DEV(sd,
+				    "Chroma sub-carrier initial freq = %d.%06d "
+				    "MHz\n", fsc / 1000000, fsc % 1000000);
+
+		CX18_DEBUG_INFO_DEV(sd, "hblank %i, hactive %i, vblank %i, "
+				    "vactive %i, vblank656 %i, src_dec %i, "
+				    "burst 0x%02x, luma_lpf %i, uv_lpf %i, "
+				    "comb 0x%02x, sc 0x%06x\n",
+				    hblank, hactive, vblank, vactive, vblank656,
+				    src_decimation, burst, luma_lpf, uv_lpf,
+				    comb, sc);
+	}
+
+	/* Sets horizontal blanking delay and active lines */
+	cx18_av_write(cx, 0x470, hblank);
+	cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) |
+						(hactive << 4)));
+	cx18_av_write(cx, 0x472, hactive >> 4);
+
+	/* Sets burst gate delay */
+	cx18_av_write(cx, 0x473, burst);
+
+	/* Sets vertical blanking delay and active duration */
+	cx18_av_write(cx, 0x474, vblank);
+	cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) |
+						(vactive << 4)));
+	cx18_av_write(cx, 0x476, vactive >> 4);
+	cx18_av_write(cx, 0x477, vblank656);
+
+	/* Sets src decimation rate */
+	cx18_av_write(cx, 0x478, 0xff & src_decimation);
+	cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8));
+
+	/* Sets Luma and UV Low pass filters */
+	cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
+
+	/* Enables comb filters */
+	cx18_av_write(cx, 0x47b, comb);
+
+	/* Sets SC Step*/
+	cx18_av_write(cx, 0x47c, sc);
+	cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
+	cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
+
+	if (std & V4L2_STD_625_50) {
+		state->slicer_line_delay = 1;
+		state->slicer_line_offset = (6 + state->slicer_line_delay - 2);
+	} else {
+		state->slicer_line_delay = 0;
+		state->slicer_line_offset = (10 + state->slicer_line_delay - 2);
+	}
+	cx18_av_write(cx, 0x47f, state->slicer_line_delay);
+}
+
+static void input_change(struct cx18 *cx)
+{
+	struct cx18_av_state *state = &cx->av_state;
+	v4l2_std_id std = state->std;
+	u8 v;
+
+	/* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */
+	cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
+	cx18_av_and_or(cx, 0x401, ~0x60, 0);
+	cx18_av_and_or(cx, 0x401, ~0x60, 0x60);
+
+	if (std & V4L2_STD_525_60) {
+		if (std == V4L2_STD_NTSC_M_JP) {
+			/* Japan uses EIAJ audio standard */
+			cx18_av_write_expect(cx, 0x808, 0xf7, 0xf7, 0xff);
+			cx18_av_write_expect(cx, 0x80b, 0x02, 0x02, 0x3f);
+		} else if (std == V4L2_STD_NTSC_M_KR) {
+			/* South Korea uses A2 audio standard */
+			cx18_av_write_expect(cx, 0x808, 0xf8, 0xf8, 0xff);
+			cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f);
+		} else {
+			/* Others use the BTSC audio standard */
+			cx18_av_write_expect(cx, 0x808, 0xf6, 0xf6, 0xff);
+			cx18_av_write_expect(cx, 0x80b, 0x01, 0x01, 0x3f);
+		}
+	} else if (std & V4L2_STD_PAL) {
+		/* Follow tuner change procedure for PAL */
+		cx18_av_write_expect(cx, 0x808, 0xff, 0xff, 0xff);
+		cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f);
+	} else if (std & V4L2_STD_SECAM) {
+		/* Select autodetect for SECAM */
+		cx18_av_write_expect(cx, 0x808, 0xff, 0xff, 0xff);
+		cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f);
+	}
+
+	v = cx18_av_read(cx, 0x803);
+	if (v & 0x10) {
+		/* restart audio decoder microcontroller */
+		v &= ~0x10;
+		cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
+		v |= 0x10;
+		cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
+	}
+}
+
+static int cx18_av_s_frequency(struct v4l2_subdev *sd,
+			       struct v4l2_frequency *freq)
+{
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+	input_change(cx);
+	return 0;
+}
+
+static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
+					enum cx18_av_audio_input aud_input)
+{
+	struct cx18_av_state *state = &cx->av_state;
+	struct v4l2_subdev *sd = &state->sd;
+
+	enum analog_signal_type {
+		NONE, CVBS, Y, C, SIF, Pb, Pr
+	} ch[3] = {NONE, NONE, NONE};
+
+	u8 afe_mux_cfg;
+	u8 adc2_cfg;
+	u8 input_mode;
+	u32 afe_cfg;
+	int i;
+
+	CX18_DEBUG_INFO_DEV(sd, "decoder set video input %d, audio input %d\n",
+			    vid_input, aud_input);
+
+	if (vid_input >= CX18_AV_COMPOSITE1 &&
+	    vid_input <= CX18_AV_COMPOSITE8) {
+		afe_mux_cfg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1);
+		ch[0] = CVBS;
+		input_mode = 0x0;
+	} else if (vid_input >= CX18_AV_COMPONENT_LUMA1) {
+		int luma = vid_input & 0xf000;
+		int r_chroma = vid_input & 0xf0000;
+		int b_chroma = vid_input & 0xf00000;
+
+		if ((vid_input & ~0xfff000) ||
+		    luma < CX18_AV_COMPONENT_LUMA1 ||
+		    luma > CX18_AV_COMPONENT_LUMA8 ||
+		    r_chroma < CX18_AV_COMPONENT_R_CHROMA4 ||
+		    r_chroma > CX18_AV_COMPONENT_R_CHROMA6 ||
+		    b_chroma < CX18_AV_COMPONENT_B_CHROMA7 ||
+		    b_chroma > CX18_AV_COMPONENT_B_CHROMA8) {
+			CX18_ERR_DEV(sd, "0x%06x is not a valid video input!\n",
+				     vid_input);
+			return -EINVAL;
+		}
+		afe_mux_cfg = (luma - CX18_AV_COMPONENT_LUMA1) >> 12;
+		ch[0] = Y;
+		afe_mux_cfg |= (r_chroma - CX18_AV_COMPONENT_R_CHROMA4) >> 12;
+		ch[1] = Pr;
+		afe_mux_cfg |= (b_chroma - CX18_AV_COMPONENT_B_CHROMA7) >> 14;
+		ch[2] = Pb;
+		input_mode = 0x6;
+	} else {
+		int luma = vid_input & 0xf0;
+		int chroma = vid_input & 0xf00;
+
+		if ((vid_input & ~0xff0) ||
+		    luma < CX18_AV_SVIDEO_LUMA1 ||
+		    luma > CX18_AV_SVIDEO_LUMA8 ||
+		    chroma < CX18_AV_SVIDEO_CHROMA4 ||
+		    chroma > CX18_AV_SVIDEO_CHROMA8) {
+			CX18_ERR_DEV(sd, "0x%06x is not a valid video input!\n",
+				     vid_input);
+			return -EINVAL;
+		}
+		afe_mux_cfg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4);
+		ch[0] = Y;
+		if (chroma >= CX18_AV_SVIDEO_CHROMA7) {
+			afe_mux_cfg &= 0x3f;
+			afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2;
+			ch[2] = C;
+		} else {
+			afe_mux_cfg &= 0xcf;
+			afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4;
+			ch[1] = C;
+		}
+		input_mode = 0x2;
+	}
+
+	switch (aud_input) {
+	case CX18_AV_AUDIO_SERIAL1:
+	case CX18_AV_AUDIO_SERIAL2:
+		/* do nothing, use serial audio input */
+		break;
+	case CX18_AV_AUDIO4:
+		afe_mux_cfg &= ~0x30;
+		ch[1] = SIF;
+		break;
+	case CX18_AV_AUDIO5:
+		afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x10;
+		ch[1] = SIF;
+		break;
+	case CX18_AV_AUDIO6:
+		afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x20;
+		ch[1] = SIF;
+		break;
+	case CX18_AV_AUDIO7:
+		afe_mux_cfg &= ~0xc0;
+		ch[2] = SIF;
+		break;
+	case CX18_AV_AUDIO8:
+		afe_mux_cfg = (afe_mux_cfg & ~0xc0) | 0x40;
+		ch[2] = SIF;
+		break;
+
+	default:
+		CX18_ERR_DEV(sd, "0x%04x is not a valid audio input!\n",
+			     aud_input);
+		return -EINVAL;
+	}
+
+	/* Set up analog front end multiplexers */
+	cx18_av_write_expect(cx, 0x103, afe_mux_cfg, afe_mux_cfg, 0xf7);
+	/* Set INPUT_MODE to Composite, S-Video, or Component */
+	cx18_av_and_or(cx, 0x401, ~0x6, input_mode);
+
+	/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
+	adc2_cfg = cx18_av_read(cx, 0x102);
+	if (ch[2] == NONE)
+		adc2_cfg &= ~0x2; /* No sig on CH3, set ADC2 to CH2 for input */
+	else
+		adc2_cfg |= 0x2;  /* Signal on CH3, set ADC2 to CH3 for input */
+
+	/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
+	if (ch[1] != NONE && ch[2] != NONE)
+		adc2_cfg |= 0x4; /* Set dual mode */
+	else
+		adc2_cfg &= ~0x4; /* Clear dual mode */
+	cx18_av_write_expect(cx, 0x102, adc2_cfg, adc2_cfg, 0x17);
+
+	/* Configure the analog front end */
+	afe_cfg = cx18_av_read4(cx, CXADEC_AFE_CTRL);
+	afe_cfg &= 0xff000000;
+	afe_cfg |= 0x00005000; /* CHROMA_IN, AUD_IN: ADC2; LUMA_IN: ADC1 */
+	if (ch[1] != NONE && ch[2] != NONE)
+		afe_cfg |= 0x00000030; /* half_bw_ch[2-3] since in dual mode */
+
+	for (i = 0; i < 3; i++) {
+		switch (ch[i]) {
+		default:
+		case NONE:
+			/* CLAMP_SEL = Fixed to midcode clamp level */
+			afe_cfg |= (0x00000200 << i);
+			break;
+		case CVBS:
+		case Y:
+			if (i > 0)
+				afe_cfg |= 0x00002000; /* LUMA_IN_SEL: ADC2 */
+			break;
+		case C:
+		case Pb:
+		case Pr:
+			/* CLAMP_SEL = Fixed to midcode clamp level */
+			afe_cfg |= (0x00000200 << i);
+			if (i == 0 && ch[i] == C)
+				afe_cfg &= ~0x00001000; /* CHROMA_IN_SEL ADC1 */
+			break;
+		case SIF:
+			/*
+			 * VGA_GAIN_SEL = Audio Decoder
+			 * CLAMP_SEL = Fixed to midcode clamp level
+			 */
+			afe_cfg |= (0x00000240 << i);
+			if (i == 0)
+				afe_cfg &= ~0x00004000; /* AUD_IN_SEL ADC1 */
+			break;
+		}
+	}
+
+	cx18_av_write4(cx, CXADEC_AFE_CTRL, afe_cfg);
+
+	state->vid_input = vid_input;
+	state->aud_input = aud_input;
+	cx18_av_audio_set_path(cx);
+	input_change(cx);
+	return 0;
+}
+
+static int cx18_av_s_video_routing(struct v4l2_subdev *sd,
+				   u32 input, u32 output, u32 config)
+{
+	struct cx18_av_state *state = to_cx18_av_state(sd);
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+	return set_input(cx, input, state->aud_input);
+}
+
+static int cx18_av_s_audio_routing(struct v4l2_subdev *sd,
+				   u32 input, u32 output, u32 config)
+{
+	struct cx18_av_state *state = to_cx18_av_state(sd);
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+	return set_input(cx, state->vid_input, input);
+}
+
+static int cx18_av_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct cx18_av_state *state = to_cx18_av_state(sd);
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+	u8 vpres;
+	u8 mode;
+	int val = 0;
+
+	if (state->radio)
+		return 0;
+
+	vpres = cx18_av_read(cx, 0x40e) & 0x20;
+	vt->signal = vpres ? 0xffff : 0x0;
+
+	vt->capability |=
+		    V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+		    V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+
+	mode = cx18_av_read(cx, 0x804);
+
+	/* get rxsubchans and audmode */
+	if ((mode & 0xf) == 1)
+		val |= V4L2_TUNER_SUB_STEREO;
+	else
+		val |= V4L2_TUNER_SUB_MONO;
+
+	if (mode == 2 || mode == 4)
+		val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+
+	if (mode & 0x10)
+		val |= V4L2_TUNER_SUB_SAP;
+
+	vt->rxsubchans = val;
+	vt->audmode = state->audmode;
+	return 0;
+}
+
+static int cx18_av_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct cx18_av_state *state = to_cx18_av_state(sd);
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+	u8 v;
+
+	if (state->radio)
+		return 0;
+
+	v = cx18_av_read(cx, 0x809);
+	v &= ~0xf;
+
+	switch (vt->audmode) {
+	case V4L2_TUNER_MODE_MONO:
+		/* mono      -> mono
+		   stereo    -> mono
+		   bilingual -> lang1 */
+		break;
+	case V4L2_TUNER_MODE_STEREO:
+	case V4L2_TUNER_MODE_LANG1:
+		/* mono      -> mono
+		   stereo    -> stereo
+		   bilingual -> lang1 */
+		v |= 0x4;
+		break;
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+		/* mono      -> mono
+		   stereo    -> stereo
+		   bilingual -> lang1/lang2 */
+		v |= 0x7;
+		break;
+	case V4L2_TUNER_MODE_LANG2:
+		/* mono      -> mono
+		   stereo    -> stereo
+		   bilingual -> lang2 */
+		v |= 0x1;
+		break;
+	default:
+		return -EINVAL;
+	}
+	cx18_av_write_expect(cx, 0x809, v, v, 0xff);
+	state->audmode = vt->audmode;
+	return 0;
+}
+
+static int cx18_av_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+	struct cx18_av_state *state = to_cx18_av_state(sd);
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+	u8 fmt = 0; 	/* zero is autodetect */
+	u8 pal_m = 0;
+
+	if (state->radio == 0 && state->std == norm)
+		return 0;
+
+	state->radio = 0;
+	state->std = norm;
+
+	/* First tests should be against specific std */
+	if (state->std == V4L2_STD_NTSC_M_JP) {
+		fmt = 0x2;
+	} else if (state->std == V4L2_STD_NTSC_443) {
+		fmt = 0x3;
+	} else if (state->std == V4L2_STD_PAL_M) {
+		pal_m = 1;
+		fmt = 0x5;
+	} else if (state->std == V4L2_STD_PAL_N) {
+		fmt = 0x6;
+	} else if (state->std == V4L2_STD_PAL_Nc) {
+		fmt = 0x7;
+	} else if (state->std == V4L2_STD_PAL_60) {
+		fmt = 0x8;
+	} else {
+		/* Then, test against generic ones */
+		if (state->std & V4L2_STD_NTSC)
+			fmt = 0x1;
+		else if (state->std & V4L2_STD_PAL)
+			fmt = 0x4;
+		else if (state->std & V4L2_STD_SECAM)
+			fmt = 0xc;
+	}
+
+	CX18_DEBUG_INFO_DEV(sd, "changing video std to fmt %i\n", fmt);
+
+	/* Follow step 9 of section 3.16 in the cx18_av datasheet.
+	   Without this PAL may display a vertical ghosting effect.
+	   This happens for example with the Yuan MPC622. */
+	if (fmt >= 4 && fmt < 8) {
+		/* Set format to NTSC-M */
+		cx18_av_and_or(cx, 0x400, ~0xf, 1);
+		/* Turn off LCOMB */
+		cx18_av_and_or(cx, 0x47b, ~6, 0);
+	}
+	cx18_av_and_or(cx, 0x400, ~0x2f, fmt | 0x20);
+	cx18_av_and_or(cx, 0x403, ~0x3, pal_m);
+	cx18_av_std_setup(cx);
+	input_change(cx);
+	return 0;
+}
+
+static int cx18_av_s_radio(struct v4l2_subdev *sd)
+{
+	struct cx18_av_state *state = to_cx18_av_state(sd);
+	state->radio = 1;
+	return 0;
+}
+
+static int cx18_av_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		cx18_av_write(cx, 0x414, ctrl->val - 128);
+		break;
+
+	case V4L2_CID_CONTRAST:
+		cx18_av_write(cx, 0x415, ctrl->val << 1);
+		break;
+
+	case V4L2_CID_SATURATION:
+		cx18_av_write(cx, 0x420, ctrl->val << 1);
+		cx18_av_write(cx, 0x421, ctrl->val << 1);
+		break;
+
+	case V4L2_CID_HUE:
+		cx18_av_write(cx, 0x422, ctrl->val);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
+{
+	struct cx18_av_state *state = to_cx18_av_state(sd);
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+	int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
+	int is_50Hz = !(state->std & V4L2_STD_525_60);
+
+	if (fmt->code != V4L2_MBUS_FMT_FIXED)
+		return -EINVAL;
+
+	fmt->field = V4L2_FIELD_INTERLACED;
+	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+	Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4;
+	Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4;
+
+	Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4;
+	Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4;
+
+	/*
+	 * This adjustment reflects the excess of vactive, set in
+	 * cx18_av_std_setup(), above standard values:
+	 *
+	 * 480 + 1 for 60 Hz systems
+	 * 576 + 3 for 50 Hz systems
+	 */
+	Vlines = fmt->height + (is_50Hz ? 3 : 1);
+
+	/*
+	 * Invalid height and width scaling requests are:
+	 * 1. width less than 1/16 of the source width
+	 * 2. width greater than the source width
+	 * 3. height less than 1/8 of the source height
+	 * 4. height greater than the source height
+	 */
+	if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) ||
+	    (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
+		CX18_ERR_DEV(sd, "%dx%d is not a valid size!\n",
+			     fmt->width, fmt->height);
+		return -ERANGE;
+	}
+
+	HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20);
+	VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
+	VSC &= 0x1fff;
+
+	if (fmt->width >= 385)
+		filter = 0;
+	else if (fmt->width > 192)
+		filter = 1;
+	else if (fmt->width > 96)
+		filter = 2;
+	else
+		filter = 3;
+
+	CX18_DEBUG_INFO_DEV(sd,
+			    "decoder set size %dx%d -> scale  %ux%u\n",
+			    fmt->width, fmt->height, HSC, VSC);
+
+	/* HSCALE=HSC */
+	cx18_av_write(cx, 0x418, HSC & 0xff);
+	cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff);
+	cx18_av_write(cx, 0x41a, HSC >> 16);
+	/* VSCALE=VSC */
+	cx18_av_write(cx, 0x41c, VSC & 0xff);
+	cx18_av_write(cx, 0x41d, VSC >> 8);
+	/* VS_INTRLACE=1 VFILT=filter */
+	cx18_av_write(cx, 0x41e, 0x8 | filter);
+	return 0;
+}
+
+static int cx18_av_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+	CX18_DEBUG_INFO_DEV(sd, "%s output\n", enable ? "enable" : "disable");
+	if (enable) {
+		cx18_av_write(cx, 0x115, 0x8c);
+		cx18_av_write(cx, 0x116, 0x07);
+	} else {
+		cx18_av_write(cx, 0x115, 0x00);
+		cx18_av_write(cx, 0x116, 0x00);
+	}
+	return 0;
+}
+
+static void log_video_status(struct cx18 *cx)
+{
+	static const char *const fmt_strs[] = {
+		"0x0",
+		"NTSC-M", "NTSC-J", "NTSC-4.43",
+		"PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
+		"0x9", "0xA", "0xB",
+		"SECAM",
+		"0xD", "0xE", "0xF"
+	};
+
+	struct cx18_av_state *state = &cx->av_state;
+	struct v4l2_subdev *sd = &state->sd;
+	u8 vidfmt_sel = cx18_av_read(cx, 0x400) & 0xf;
+	u8 gen_stat1 = cx18_av_read(cx, 0x40d);
+	u8 gen_stat2 = cx18_av_read(cx, 0x40e);
+	int vid_input = state->vid_input;
+
+	CX18_INFO_DEV(sd, "Video signal:              %spresent\n",
+		      (gen_stat2 & 0x20) ? "" : "not ");
+	CX18_INFO_DEV(sd, "Detected format:           %s\n",
+		      fmt_strs[gen_stat1 & 0xf]);
+
+	CX18_INFO_DEV(sd, "Specified standard:        %s\n",
+		      vidfmt_sel ? fmt_strs[vidfmt_sel]
+				 : "automatic detection");
+
+	if (vid_input >= CX18_AV_COMPOSITE1 &&
+	    vid_input <= CX18_AV_COMPOSITE8) {
+		CX18_INFO_DEV(sd, "Specified video input:     Composite %d\n",
+			      vid_input - CX18_AV_COMPOSITE1 + 1);
+	} else {
+		CX18_INFO_DEV(sd, "Specified video input:     "
+			      "S-Video (Luma In%d, Chroma In%d)\n",
+			      (vid_input & 0xf0) >> 4,
+			      (vid_input & 0xf00) >> 8);
+	}
+
+	CX18_INFO_DEV(sd, "Specified audioclock freq: %d Hz\n",
+		      state->audclk_freq);
+}
+
+static void log_audio_status(struct cx18 *cx)
+{
+	struct cx18_av_state *state = &cx->av_state;
+	struct v4l2_subdev *sd = &state->sd;
+	u8 download_ctl = cx18_av_read(cx, 0x803);
+	u8 mod_det_stat0 = cx18_av_read(cx, 0x804);
+	u8 mod_det_stat1 = cx18_av_read(cx, 0x805);
+	u8 audio_config = cx18_av_read(cx, 0x808);
+	u8 pref_mode = cx18_av_read(cx, 0x809);
+	u8 afc0 = cx18_av_read(cx, 0x80b);
+	u8 mute_ctl = cx18_av_read(cx, 0x8d3);
+	int aud_input = state->aud_input;
+	char *p;
+
+	switch (mod_det_stat0) {
+	case 0x00: p = "mono"; break;
+	case 0x01: p = "stereo"; break;
+	case 0x02: p = "dual"; break;
+	case 0x04: p = "tri"; break;
+	case 0x10: p = "mono with SAP"; break;
+	case 0x11: p = "stereo with SAP"; break;
+	case 0x12: p = "dual with SAP"; break;
+	case 0x14: p = "tri with SAP"; break;
+	case 0xfe: p = "forced mode"; break;
+	default: p = "not defined"; break;
+	}
+	CX18_INFO_DEV(sd, "Detected audio mode:       %s\n", p);
+
+	switch (mod_det_stat1) {
+	case 0x00: p = "not defined"; break;
+	case 0x01: p = "EIAJ"; break;
+	case 0x02: p = "A2-M"; break;
+	case 0x03: p = "A2-BG"; break;
+	case 0x04: p = "A2-DK1"; break;
+	case 0x05: p = "A2-DK2"; break;
+	case 0x06: p = "A2-DK3"; break;
+	case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
+	case 0x08: p = "AM-L"; break;
+	case 0x09: p = "NICAM-BG"; break;
+	case 0x0a: p = "NICAM-DK"; break;
+	case 0x0b: p = "NICAM-I"; break;
+	case 0x0c: p = "NICAM-L"; break;
+	case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
+	case 0x0e: p = "IF FM Radio"; break;
+	case 0x0f: p = "BTSC"; break;
+	case 0x10: p = "detected chrominance"; break;
+	case 0xfd: p = "unknown audio standard"; break;
+	case 0xfe: p = "forced audio standard"; break;
+	case 0xff: p = "no detected audio standard"; break;
+	default: p = "not defined"; break;
+	}
+	CX18_INFO_DEV(sd, "Detected audio standard:   %s\n", p);
+	CX18_INFO_DEV(sd, "Audio muted:               %s\n",
+		      (mute_ctl & 0x2) ? "yes" : "no");
+	CX18_INFO_DEV(sd, "Audio microcontroller:     %s\n",
+		      (download_ctl & 0x10) ? "running" : "stopped");
+
+	switch (audio_config >> 4) {
+	case 0x00: p = "undefined"; break;
+	case 0x01: p = "BTSC"; break;
+	case 0x02: p = "EIAJ"; break;
+	case 0x03: p = "A2-M"; break;
+	case 0x04: p = "A2-BG"; break;
+	case 0x05: p = "A2-DK1"; break;
+	case 0x06: p = "A2-DK2"; break;
+	case 0x07: p = "A2-DK3"; break;
+	case 0x08: p = "A1 (6.0 MHz FM Mono)"; break;
+	case 0x09: p = "AM-L"; break;
+	case 0x0a: p = "NICAM-BG"; break;
+	case 0x0b: p = "NICAM-DK"; break;
+	case 0x0c: p = "NICAM-I"; break;
+	case 0x0d: p = "NICAM-L"; break;
+	case 0x0e: p = "FM radio"; break;
+	case 0x0f: p = "automatic detection"; break;
+	default: p = "undefined"; break;
+	}
+	CX18_INFO_DEV(sd, "Configured audio standard: %s\n", p);
+
+	if ((audio_config >> 4) < 0xF) {
+		switch (audio_config & 0xF) {
+		case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break;
+		case 0x01: p = "MONO2 (LANGUAGE B)"; break;
+		case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
+		case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
+		case 0x04: p = "STEREO"; break;
+		case 0x05: p = "DUAL1 (AC)"; break;
+		case 0x06: p = "DUAL2 (BC)"; break;
+		case 0x07: p = "DUAL3 (AB)"; break;
+		default: p = "undefined";
+		}
+		CX18_INFO_DEV(sd, "Configured audio mode:     %s\n", p);
+	} else {
+		switch (audio_config & 0xF) {
+		case 0x00: p = "BG"; break;
+		case 0x01: p = "DK1"; break;
+		case 0x02: p = "DK2"; break;
+		case 0x03: p = "DK3"; break;
+		case 0x04: p = "I"; break;
+		case 0x05: p = "L"; break;
+		case 0x06: p = "BTSC"; break;
+		case 0x07: p = "EIAJ"; break;
+		case 0x08: p = "A2-M"; break;
+		case 0x09: p = "FM Radio (4.5 MHz)"; break;
+		case 0x0a: p = "FM Radio (5.5 MHz)"; break;
+		case 0x0b: p = "S-Video"; break;
+		case 0x0f: p = "automatic standard and mode detection"; break;
+		default: p = "undefined"; break;
+		}
+		CX18_INFO_DEV(sd, "Configured audio system:   %s\n", p);
+	}
+
+	if (aud_input)
+		CX18_INFO_DEV(sd, "Specified audio input:     Tuner (In%d)\n",
+			      aud_input);
+	else
+		CX18_INFO_DEV(sd, "Specified audio input:     External\n");
+
+	switch (pref_mode & 0xf) {
+	case 0: p = "mono/language A"; break;
+	case 1: p = "language B"; break;
+	case 2: p = "language C"; break;
+	case 3: p = "analog fallback"; break;
+	case 4: p = "stereo"; break;
+	case 5: p = "language AC"; break;
+	case 6: p = "language BC"; break;
+	case 7: p = "language AB"; break;
+	default: p = "undefined"; break;
+	}
+	CX18_INFO_DEV(sd, "Preferred audio mode:      %s\n", p);
+
+	if ((audio_config & 0xf) == 0xf) {
+		switch ((afc0 >> 3) & 0x1) {
+		case 0: p = "system DK"; break;
+		case 1: p = "system L"; break;
+		}
+		CX18_INFO_DEV(sd, "Selected 65 MHz format:    %s\n", p);
+
+		switch (afc0 & 0x7) {
+		case 0: p = "Chroma"; break;
+		case 1: p = "BTSC"; break;
+		case 2: p = "EIAJ"; break;
+		case 3: p = "A2-M"; break;
+		case 4: p = "autodetect"; break;
+		default: p = "undefined"; break;
+		}
+		CX18_INFO_DEV(sd, "Selected 45 MHz format:    %s\n", p);
+	}
+}
+
+static int cx18_av_log_status(struct v4l2_subdev *sd)
+{
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+	log_video_status(cx);
+	log_audio_status(cx);
+	return 0;
+}
+
+static inline int cx18_av_dbg_match(const struct v4l2_dbg_match *match)
+{
+	return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 1;
+}
+
+static int cx18_av_g_chip_ident(struct v4l2_subdev *sd,
+				struct v4l2_dbg_chip_ident *chip)
+{
+	struct cx18_av_state *state = to_cx18_av_state(sd);
+
+	if (cx18_av_dbg_match(&chip->match)) {
+		chip->ident = state->id;
+		chip->revision = state->rev;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int cx18_av_g_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+	if (!cx18_av_dbg_match(&reg->match))
+		return -EINVAL;
+	if ((reg->reg & 0x3) != 0)
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	reg->size = 4;
+	reg->val = cx18_av_read4(cx, reg->reg & 0x00000ffc);
+	return 0;
+}
+
+static int cx18_av_s_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+	if (!cx18_av_dbg_match(&reg->match))
+		return -EINVAL;
+	if ((reg->reg & 0x3) != 0)
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	cx18_av_write4(cx, reg->reg & 0x00000ffc, reg->val);
+	return 0;
+}
+#endif
+
+static const struct v4l2_ctrl_ops cx18_av_ctrl_ops = {
+	.s_ctrl = cx18_av_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops cx18_av_general_ops = {
+	.g_chip_ident = cx18_av_g_chip_ident,
+	.log_status = cx18_av_log_status,
+	.load_fw = cx18_av_load_fw,
+	.reset = cx18_av_reset,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+	.s_std = cx18_av_s_std,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = cx18_av_g_register,
+	.s_register = cx18_av_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops cx18_av_tuner_ops = {
+	.s_radio = cx18_av_s_radio,
+	.s_frequency = cx18_av_s_frequency,
+	.g_tuner = cx18_av_g_tuner,
+	.s_tuner = cx18_av_s_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops cx18_av_audio_ops = {
+	.s_clock_freq = cx18_av_s_clock_freq,
+	.s_routing = cx18_av_s_audio_routing,
+};
+
+static const struct v4l2_subdev_video_ops cx18_av_video_ops = {
+	.s_routing = cx18_av_s_video_routing,
+	.s_stream = cx18_av_s_stream,
+	.s_mbus_fmt = cx18_av_s_mbus_fmt,
+};
+
+static const struct v4l2_subdev_vbi_ops cx18_av_vbi_ops = {
+	.decode_vbi_line = cx18_av_decode_vbi_line,
+	.g_sliced_fmt = cx18_av_g_sliced_fmt,
+	.s_sliced_fmt = cx18_av_s_sliced_fmt,
+	.s_raw_fmt = cx18_av_s_raw_fmt,
+};
+
+static const struct v4l2_subdev_ops cx18_av_ops = {
+	.core = &cx18_av_general_ops,
+	.tuner = &cx18_av_tuner_ops,
+	.audio = &cx18_av_audio_ops,
+	.video = &cx18_av_video_ops,
+	.vbi = &cx18_av_vbi_ops,
+};
+
+int cx18_av_probe(struct cx18 *cx)
+{
+	struct cx18_av_state *state = &cx->av_state;
+	struct v4l2_subdev *sd;
+	int err;
+
+	state->rev = cx18_av_read4(cx, CXADEC_CHIP_CTRL) & 0xffff;
+	state->id = ((state->rev >> 4) == CXADEC_CHIP_TYPE_MAKO)
+		    ? V4L2_IDENT_CX23418_843 : V4L2_IDENT_UNKNOWN;
+
+	state->vid_input = CX18_AV_COMPOSITE7;
+	state->aud_input = CX18_AV_AUDIO8;
+	state->audclk_freq = 48000;
+	state->audmode = V4L2_TUNER_MODE_LANG1;
+	state->slicer_line_delay = 0;
+	state->slicer_line_offset = (10 + state->slicer_line_delay - 2);
+
+	sd = &state->sd;
+	v4l2_subdev_init(sd, &cx18_av_ops);
+	v4l2_set_subdevdata(sd, cx);
+	snprintf(sd->name, sizeof(sd->name),
+		 "%s %03x", cx->v4l2_dev.name, (state->rev >> 4));
+	sd->grp_id = CX18_HW_418_AV;
+	v4l2_ctrl_handler_init(&state->hdl, 9);
+	v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 127, 1, 64);
+	v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 127, 1, 64);
+	v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops,
+			V4L2_CID_HUE, -128, 127, 1, 0);
+
+	state->volume = v4l2_ctrl_new_std(&state->hdl,
+			&cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME,
+			0, 65535, 65535 / 100, 0);
+	v4l2_ctrl_new_std(&state->hdl,
+			&cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE,
+			0, 1, 1, 0);
+	v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops,
+			V4L2_CID_AUDIO_BALANCE,
+			0, 65535, 65535 / 100, 32768);
+	v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops,
+			V4L2_CID_AUDIO_BASS,
+			0, 65535, 65535 / 100, 32768);
+	v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops,
+			V4L2_CID_AUDIO_TREBLE,
+			0, 65535, 65535 / 100, 32768);
+	sd->ctrl_handler = &state->hdl;
+	if (state->hdl.error) {
+		int err = state->hdl.error;
+
+		v4l2_ctrl_handler_free(&state->hdl);
+		return err;
+	}
+	err = v4l2_device_register_subdev(&cx->v4l2_dev, sd);
+	if (err)
+		v4l2_ctrl_handler_free(&state->hdl);
+	else
+		cx18_av_init(cx);
+	return err;
+}
diff --git a/drivers/media/pci/cx18/cx18-av-core.h b/drivers/media/pci/cx18/cx18-av-core.h
new file mode 100644
index 0000000..e9c69d9
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-av-core.h
@@ -0,0 +1,391 @@
+/*
+ *  cx18 ADEC header
+ *
+ *  Derived from cx25840-core.h
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#ifndef _CX18_AV_CORE_H_
+#define _CX18_AV_CORE_H_
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+struct cx18;
+
+enum cx18_av_video_input {
+	/* Composite video inputs In1-In8 */
+	CX18_AV_COMPOSITE1 = 1,
+	CX18_AV_COMPOSITE2,
+	CX18_AV_COMPOSITE3,
+	CX18_AV_COMPOSITE4,
+	CX18_AV_COMPOSITE5,
+	CX18_AV_COMPOSITE6,
+	CX18_AV_COMPOSITE7,
+	CX18_AV_COMPOSITE8,
+
+	/* S-Video inputs consist of one luma input (In1-In8) ORed with one
+	   chroma input (In5-In8) */
+	CX18_AV_SVIDEO_LUMA1 = 0x10,
+	CX18_AV_SVIDEO_LUMA2 = 0x20,
+	CX18_AV_SVIDEO_LUMA3 = 0x30,
+	CX18_AV_SVIDEO_LUMA4 = 0x40,
+	CX18_AV_SVIDEO_LUMA5 = 0x50,
+	CX18_AV_SVIDEO_LUMA6 = 0x60,
+	CX18_AV_SVIDEO_LUMA7 = 0x70,
+	CX18_AV_SVIDEO_LUMA8 = 0x80,
+	CX18_AV_SVIDEO_CHROMA4 = 0x400,
+	CX18_AV_SVIDEO_CHROMA5 = 0x500,
+	CX18_AV_SVIDEO_CHROMA6 = 0x600,
+	CX18_AV_SVIDEO_CHROMA7 = 0x700,
+	CX18_AV_SVIDEO_CHROMA8 = 0x800,
+
+	/* S-Video aliases for common luma/chroma combinations */
+	CX18_AV_SVIDEO1 = 0x510,
+	CX18_AV_SVIDEO2 = 0x620,
+	CX18_AV_SVIDEO3 = 0x730,
+	CX18_AV_SVIDEO4 = 0x840,
+
+	/* Component Video inputs consist of one luma input (In1-In8) ORed
+	   with a red chroma (In4-In6) and blue chroma input (In7-In8) */
+	CX18_AV_COMPONENT_LUMA1 = 0x1000,
+	CX18_AV_COMPONENT_LUMA2 = 0x2000,
+	CX18_AV_COMPONENT_LUMA3 = 0x3000,
+	CX18_AV_COMPONENT_LUMA4 = 0x4000,
+	CX18_AV_COMPONENT_LUMA5 = 0x5000,
+	CX18_AV_COMPONENT_LUMA6 = 0x6000,
+	CX18_AV_COMPONENT_LUMA7 = 0x7000,
+	CX18_AV_COMPONENT_LUMA8 = 0x8000,
+	CX18_AV_COMPONENT_R_CHROMA4 = 0x40000,
+	CX18_AV_COMPONENT_R_CHROMA5 = 0x50000,
+	CX18_AV_COMPONENT_R_CHROMA6 = 0x60000,
+	CX18_AV_COMPONENT_B_CHROMA7 = 0x700000,
+	CX18_AV_COMPONENT_B_CHROMA8 = 0x800000,
+
+	/* Component Video aliases for common combinations */
+	CX18_AV_COMPONENT1 = 0x861000,
+};
+
+enum cx18_av_audio_input {
+	/* Audio inputs: serial or In4-In8 */
+	CX18_AV_AUDIO_SERIAL1,
+	CX18_AV_AUDIO_SERIAL2,
+	CX18_AV_AUDIO4 = 4,
+	CX18_AV_AUDIO5,
+	CX18_AV_AUDIO6,
+	CX18_AV_AUDIO7,
+	CX18_AV_AUDIO8,
+};
+
+struct cx18_av_state {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	struct v4l2_ctrl *volume;
+	int radio;
+	v4l2_std_id std;
+	enum cx18_av_video_input vid_input;
+	enum cx18_av_audio_input aud_input;
+	u32 audclk_freq;
+	int audmode;
+	u32 id;
+	u32 rev;
+	int is_initialized;
+
+	/*
+	 * The VBI slicer starts operating and counting lines, beginning at
+	 * slicer line count of 1, at D lines after the deassertion of VRESET.
+	 * This staring field line, S, is 6 (& 319) or 10 (& 273) for 625 or 525
+	 * line systems respectively.  Sliced ancillary data captured on VBI
+	 * slicer line M is inserted after the VBI slicer is done with line M,
+	 * when VBI slicer line count is N = M+1.  Thus when the VBI slicer
+	 * reports a VBI slicer line number with ancillary data, the IDID0 byte
+	 * indicates VBI slicer line N.  The actual field line that the captured
+	 * data comes from is
+	 *
+	 * L = M+(S+D-1) = N-1+(S+D-1) = N + (S+D-2).
+	 *
+	 * L is the line in the field, not frame, from which the VBI data came.
+	 * N is the line reported by the slicer in the ancillary data.
+	 * D is the slicer_line_delay value programmed into register 0x47f.
+	 * S is 6 for 625 line systems or 10 for 525 line systems
+	 * (S+D-2) is the slicer_line_offset used to convert slicer reported
+	 * line counts to actual field lines.
+	 */
+	int slicer_line_delay;
+	int slicer_line_offset;
+};
+
+
+/* Registers */
+#define CXADEC_CHIP_TYPE_TIGER     0x837
+#define CXADEC_CHIP_TYPE_MAKO      0x843
+
+#define CXADEC_HOST_REG1           0x000
+#define CXADEC_HOST_REG2           0x001
+
+#define CXADEC_CHIP_CTRL           0x100
+#define CXADEC_AFE_CTRL            0x104
+#define CXADEC_PLL_CTRL1           0x108
+#define CXADEC_VID_PLL_FRAC        0x10C
+#define CXADEC_AUX_PLL_FRAC        0x110
+#define CXADEC_PIN_CTRL1           0x114
+#define CXADEC_PIN_CTRL2           0x118
+#define CXADEC_PIN_CFG1            0x11C
+#define CXADEC_PIN_CFG2            0x120
+
+#define CXADEC_PIN_CFG3            0x124
+#define CXADEC_I2S_MCLK            0x127
+
+#define CXADEC_AUD_LOCK1           0x128
+#define CXADEC_AUD_LOCK2           0x12C
+#define CXADEC_POWER_CTRL          0x130
+#define CXADEC_AFE_DIAG_CTRL1      0x134
+#define CXADEC_AFE_DIAG_CTRL2      0x138
+#define CXADEC_AFE_DIAG_CTRL3      0x13C
+#define CXADEC_PLL_DIAG_CTRL       0x140
+#define CXADEC_TEST_CTRL1          0x144
+#define CXADEC_TEST_CTRL2          0x148
+#define CXADEC_BIST_STAT           0x14C
+#define CXADEC_DLL1_DIAG_CTRL      0x158
+#define CXADEC_DLL2_DIAG_CTRL      0x15C
+
+/* IR registers */
+#define CXADEC_IR_CTRL_REG         0x200
+#define CXADEC_IR_TXCLK_REG        0x204
+#define CXADEC_IR_RXCLK_REG        0x208
+#define CXADEC_IR_CDUTY_REG        0x20C
+#define CXADEC_IR_STAT_REG         0x210
+#define CXADEC_IR_IRQEN_REG        0x214
+#define CXADEC_IR_FILTER_REG       0x218
+#define CXADEC_IR_FIFO_REG         0x21C
+
+/* Video Registers */
+#define CXADEC_MODE_CTRL           0x400
+#define CXADEC_OUT_CTRL1           0x404
+#define CXADEC_OUT_CTRL2           0x408
+#define CXADEC_GEN_STAT            0x40C
+#define CXADEC_INT_STAT_MASK       0x410
+#define CXADEC_LUMA_CTRL           0x414
+
+#define CXADEC_BRIGHTNESS_CTRL_BYTE 0x414
+#define CXADEC_CONTRAST_CTRL_BYTE  0x415
+#define CXADEC_LUMA_CTRL_BYTE_3    0x416
+
+#define CXADEC_HSCALE_CTRL         0x418
+#define CXADEC_VSCALE_CTRL         0x41C
+
+#define CXADEC_CHROMA_CTRL         0x420
+
+#define CXADEC_USAT_CTRL_BYTE      0x420
+#define CXADEC_VSAT_CTRL_BYTE      0x421
+#define CXADEC_HUE_CTRL_BYTE       0x422
+
+#define CXADEC_VBI_LINE_CTRL1      0x424
+#define CXADEC_VBI_LINE_CTRL2      0x428
+#define CXADEC_VBI_LINE_CTRL3      0x42C
+#define CXADEC_VBI_LINE_CTRL4      0x430
+#define CXADEC_VBI_LINE_CTRL5      0x434
+#define CXADEC_VBI_FC_CFG          0x438
+#define CXADEC_VBI_MISC_CFG1       0x43C
+#define CXADEC_VBI_MISC_CFG2       0x440
+#define CXADEC_VBI_PAY1            0x444
+#define CXADEC_VBI_PAY2            0x448
+#define CXADEC_VBI_CUST1_CFG1      0x44C
+#define CXADEC_VBI_CUST1_CFG2      0x450
+#define CXADEC_VBI_CUST1_CFG3      0x454
+#define CXADEC_VBI_CUST2_CFG1      0x458
+#define CXADEC_VBI_CUST2_CFG2      0x45C
+#define CXADEC_VBI_CUST2_CFG3      0x460
+#define CXADEC_VBI_CUST3_CFG1      0x464
+#define CXADEC_VBI_CUST3_CFG2      0x468
+#define CXADEC_VBI_CUST3_CFG3      0x46C
+#define CXADEC_HORIZ_TIM_CTRL      0x470
+#define CXADEC_VERT_TIM_CTRL       0x474
+#define CXADEC_SRC_COMB_CFG        0x478
+#define CXADEC_CHROMA_VBIOFF_CFG   0x47C
+#define CXADEC_FIELD_COUNT         0x480
+#define CXADEC_MISC_TIM_CTRL       0x484
+#define CXADEC_DFE_CTRL1           0x488
+#define CXADEC_DFE_CTRL2           0x48C
+#define CXADEC_DFE_CTRL3           0x490
+#define CXADEC_PLL_CTRL2           0x494
+#define CXADEC_HTL_CTRL            0x498
+#define CXADEC_COMB_CTRL           0x49C
+#define CXADEC_CRUSH_CTRL          0x4A0
+#define CXADEC_SOFT_RST_CTRL       0x4A4
+#define CXADEC_MV_DT_CTRL2         0x4A8
+#define CXADEC_MV_DT_CTRL3         0x4AC
+#define CXADEC_MISC_DIAG_CTRL      0x4B8
+
+#define CXADEC_DL_CTL              0x800
+#define CXADEC_DL_CTL_ADDRESS_LOW  0x800   /* Byte 1 in DL_CTL */
+#define CXADEC_DL_CTL_ADDRESS_HIGH 0x801   /* Byte 2 in DL_CTL */
+#define CXADEC_DL_CTL_DATA         0x802   /* Byte 3 in DL_CTL */
+#define CXADEC_DL_CTL_CONTROL      0x803   /* Byte 4 in DL_CTL */
+
+#define CXADEC_STD_DET_STATUS      0x804
+
+#define CXADEC_STD_DET_CTL         0x808
+#define CXADEC_STD_DET_CTL_AUD_CTL   0x808 /* Byte 1 in STD_DET_CTL */
+#define CXADEC_STD_DET_CTL_PREF_MODE 0x809 /* Byte 2 in STD_DET_CTL */
+
+#define CXADEC_DW8051_INT          0x80C
+#define CXADEC_GENERAL_CTL         0x810
+#define CXADEC_AAGC_CTL            0x814
+#define CXADEC_IF_SRC_CTL          0x818
+#define CXADEC_ANLOG_DEMOD_CTL     0x81C
+#define CXADEC_ROT_FREQ_CTL        0x820
+#define CXADEC_FM1_CTL             0x824
+#define CXADEC_PDF_CTL             0x828
+#define CXADEC_DFT1_CTL1           0x82C
+#define CXADEC_DFT1_CTL2           0x830
+#define CXADEC_DFT_STATUS          0x834
+#define CXADEC_DFT2_CTL1           0x838
+#define CXADEC_DFT2_CTL2           0x83C
+#define CXADEC_DFT2_STATUS         0x840
+#define CXADEC_DFT3_CTL1           0x844
+#define CXADEC_DFT3_CTL2           0x848
+#define CXADEC_DFT3_STATUS         0x84C
+#define CXADEC_DFT4_CTL1           0x850
+#define CXADEC_DFT4_CTL2           0x854
+#define CXADEC_DFT4_STATUS         0x858
+#define CXADEC_AM_MTS_DET          0x85C
+#define CXADEC_ANALOG_MUX_CTL      0x860
+#define CXADEC_DIG_PLL_CTL1        0x864
+#define CXADEC_DIG_PLL_CTL2        0x868
+#define CXADEC_DIG_PLL_CTL3        0x86C
+#define CXADEC_DIG_PLL_CTL4        0x870
+#define CXADEC_DIG_PLL_CTL5        0x874
+#define CXADEC_DEEMPH_GAIN_CTL     0x878
+#define CXADEC_DEEMPH_COEF1        0x87C
+#define CXADEC_DEEMPH_COEF2        0x880
+#define CXADEC_DBX1_CTL1           0x884
+#define CXADEC_DBX1_CTL2           0x888
+#define CXADEC_DBX1_STATUS         0x88C
+#define CXADEC_DBX2_CTL1           0x890
+#define CXADEC_DBX2_CTL2           0x894
+#define CXADEC_DBX2_STATUS         0x898
+#define CXADEC_AM_FM_DIFF          0x89C
+
+/* NICAM registers go here */
+#define CXADEC_NICAM_STATUS        0x8C8
+#define CXADEC_DEMATRIX_CTL        0x8CC
+
+#define CXADEC_PATH1_CTL1          0x8D0
+#define CXADEC_PATH1_VOL_CTL       0x8D4
+#define CXADEC_PATH1_EQ_CTL        0x8D8
+#define CXADEC_PATH1_SC_CTL        0x8DC
+
+#define CXADEC_PATH2_CTL1          0x8E0
+#define CXADEC_PATH2_VOL_CTL       0x8E4
+#define CXADEC_PATH2_EQ_CTL        0x8E8
+#define CXADEC_PATH2_SC_CTL        0x8EC
+
+#define CXADEC_SRC_CTL             0x8F0
+#define CXADEC_SRC_LF_COEF         0x8F4
+#define CXADEC_SRC1_CTL            0x8F8
+#define CXADEC_SRC2_CTL            0x8FC
+#define CXADEC_SRC3_CTL            0x900
+#define CXADEC_SRC4_CTL            0x904
+#define CXADEC_SRC5_CTL            0x908
+#define CXADEC_SRC6_CTL            0x90C
+
+#define CXADEC_BASEBAND_OUT_SEL    0x910
+#define CXADEC_I2S_IN_CTL          0x914
+#define CXADEC_I2S_OUT_CTL         0x918
+#define CXADEC_AC97_CTL            0x91C
+#define CXADEC_QAM_PDF             0x920
+#define CXADEC_QAM_CONST_DEC       0x924
+#define CXADEC_QAM_ROTATOR_FREQ    0x948
+
+/* Bit definitions / settings used in Mako Audio */
+#define CXADEC_PREF_MODE_MONO_LANGA        0
+#define CXADEC_PREF_MODE_MONO_LANGB        1
+#define CXADEC_PREF_MODE_MONO_LANGC        2
+#define CXADEC_PREF_MODE_FALLBACK          3
+#define CXADEC_PREF_MODE_STEREO            4
+#define CXADEC_PREF_MODE_DUAL_LANG_AC      5
+#define CXADEC_PREF_MODE_DUAL_LANG_BC      6
+#define CXADEC_PREF_MODE_DUAL_LANG_AB      7
+
+
+#define CXADEC_DETECT_STEREO               1
+#define CXADEC_DETECT_DUAL                 2
+#define CXADEC_DETECT_TRI                  4
+#define CXADEC_DETECT_SAP                  0x10
+#define CXADEC_DETECT_NO_SIGNAL            0xFF
+
+#define CXADEC_SELECT_AUDIO_STANDARD_BG    0xF0  /* NICAM BG and A2 BG */
+#define CXADEC_SELECT_AUDIO_STANDARD_DK1   0xF1  /* NICAM DK and A2 DK */
+#define CXADEC_SELECT_AUDIO_STANDARD_DK2   0xF2
+#define CXADEC_SELECT_AUDIO_STANDARD_DK3   0xF3
+#define CXADEC_SELECT_AUDIO_STANDARD_I     0xF4  /* NICAM I and A1 */
+#define CXADEC_SELECT_AUDIO_STANDARD_L     0xF5  /* NICAM L and System L AM */
+#define CXADEC_SELECT_AUDIO_STANDARD_BTSC  0xF6
+#define CXADEC_SELECT_AUDIO_STANDARD_EIAJ  0xF7
+#define CXADEC_SELECT_AUDIO_STANDARD_A2_M  0xF8  /* A2 M */
+#define CXADEC_SELECT_AUDIO_STANDARD_FM    0xF9  /* FM radio */
+#define CXADEC_SELECT_AUDIO_STANDARD_AUTO  0xFF  /* Auto detect */
+
+static inline struct cx18_av_state *to_cx18_av_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct cx18_av_state, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct cx18_av_state, hdl)->sd;
+}
+
+/* ----------------------------------------------------------------------- */
+/* cx18_av-core.c 							   */
+int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
+int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value);
+int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value);
+int cx18_av_write_expect(struct cx18 *cx, u16 addr, u8 value, u8 eval, u8 mask);
+int cx18_av_write4_expect(struct cx18 *cx, u16 addr, u32 value, u32 eval,
+			  u32 mask);
+u8 cx18_av_read(struct cx18 *cx, u16 addr);
+u32 cx18_av_read4(struct cx18 *cx, u16 addr);
+int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
+int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
+void cx18_av_std_setup(struct cx18 *cx);
+
+int cx18_av_probe(struct cx18 *cx);
+
+/* ----------------------------------------------------------------------- */
+/* cx18_av-firmware.c                                                      */
+int cx18_av_loadfw(struct cx18 *cx);
+
+/* ----------------------------------------------------------------------- */
+/* cx18_av-audio.c                                                         */
+int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
+void cx18_av_audio_set_path(struct cx18 *cx);
+extern const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops;
+
+/* ----------------------------------------------------------------------- */
+/* cx18_av-vbi.c                                                           */
+int cx18_av_decode_vbi_line(struct v4l2_subdev *sd,
+			   struct v4l2_decode_vbi_line *vbi);
+int cx18_av_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt);
+int cx18_av_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt);
+int cx18_av_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt);
+
+#endif
diff --git a/drivers/media/pci/cx18/cx18-av-firmware.c b/drivers/media/pci/cx18/cx18-av-firmware.c
new file mode 100644
index 0000000..a34fd08
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-av-firmware.c
@@ -0,0 +1,225 @@
+/*
+ *  cx18 ADEC firmware functions
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#include "cx18-driver.h"
+#include "cx18-io.h"
+#include <linux/firmware.h>
+
+#define CX18_AUDIO_ENABLE    0xc72014
+#define CX18_AI1_MUX_MASK    0x30
+#define CX18_AI1_MUX_I2S1    0x00
+#define CX18_AI1_MUX_I2S2    0x10
+#define CX18_AI1_MUX_843_I2S 0x20
+#define CX18_AI1_MUX_INVALID 0x30
+
+#define FWFILE "v4l-cx23418-dig.fw"
+
+static int cx18_av_verifyfw(struct cx18 *cx, const struct firmware *fw)
+{
+	struct v4l2_subdev *sd = &cx->av_state.sd;
+	int ret = 0;
+	const u8 *data;
+	u32 size;
+	int addr;
+	u32 expected, dl_control;
+
+	/* Ensure we put the 8051 in reset and enable firmware upload mode */
+	dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+	do {
+		dl_control &= 0x00ffffff;
+		dl_control |= 0x0f000000;
+		cx18_av_write4_noretry(cx, CXADEC_DL_CTL, dl_control);
+		dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+	} while ((dl_control & 0xff000000) != 0x0f000000);
+
+	/* Read and auto increment until at address 0x0000 */
+	while (dl_control & 0x3fff)
+		dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+
+	data = fw->data;
+	size = fw->size;
+	for (addr = 0; addr < size; addr++) {
+		dl_control &= 0xffff3fff; /* ignore top 2 bits of address */
+		expected = 0x0f000000 | ((u32)data[addr] << 16) | addr;
+		if (expected != dl_control) {
+			CX18_ERR_DEV(sd, "verification of %s firmware load "
+				     "failed: expected %#010x got %#010x\n",
+				     FWFILE, expected, dl_control);
+			ret = -EIO;
+			break;
+		}
+		dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+	}
+	if (ret == 0)
+		CX18_INFO_DEV(sd, "verified load of %s firmware (%d bytes)\n",
+			      FWFILE, size);
+	return ret;
+}
+
+int cx18_av_loadfw(struct cx18 *cx)
+{
+	struct v4l2_subdev *sd = &cx->av_state.sd;
+	const struct firmware *fw = NULL;
+	u32 size;
+	u32 u, v;
+	const u8 *ptr;
+	int i;
+	int retries1 = 0;
+
+	if (request_firmware(&fw, FWFILE, &cx->pci_dev->dev) != 0) {
+		CX18_ERR_DEV(sd, "unable to open firmware %s\n", FWFILE);
+		return -EINVAL;
+	}
+
+	/* The firmware load often has byte errors, so allow for several
+	   retries, both at byte level and at the firmware load level. */
+	while (retries1 < 5) {
+		cx18_av_write4_expect(cx, CXADEC_CHIP_CTRL, 0x00010000,
+					  0x00008430, 0xffffffff); /* cx25843 */
+		cx18_av_write_expect(cx, CXADEC_STD_DET_CTL, 0xf6, 0xf6, 0xff);
+
+		/* Reset the Mako core, Register is alias of CXADEC_CHIP_CTRL */
+		cx18_av_write4_expect(cx, 0x8100, 0x00010000,
+					  0x00008430, 0xffffffff); /* cx25843 */
+
+		/* Put the 8051 in reset and enable firmware upload */
+		cx18_av_write4_noretry(cx, CXADEC_DL_CTL, 0x0F000000);
+
+		ptr = fw->data;
+		size = fw->size;
+
+		for (i = 0; i < size; i++) {
+			u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16);
+			u32 value = 0;
+			int retries2;
+			int unrec_err = 0;
+
+			for (retries2 = 0; retries2 < CX18_MAX_MMIO_WR_RETRIES;
+			     retries2++) {
+				cx18_av_write4_noretry(cx, CXADEC_DL_CTL,
+						       dl_control);
+				udelay(10);
+				value = cx18_av_read4(cx, CXADEC_DL_CTL);
+				if (value == dl_control)
+					break;
+				/* Check if we can correct the byte by changing
+				   the address.  We can only write the lower
+				   address byte of the address. */
+				if ((value & 0x3F00) != (dl_control & 0x3F00)) {
+					unrec_err = 1;
+					break;
+				}
+			}
+			if (unrec_err || retries2 >= CX18_MAX_MMIO_WR_RETRIES)
+				break;
+		}
+		if (i == size)
+			break;
+		retries1++;
+	}
+	if (retries1 >= 5) {
+		CX18_ERR_DEV(sd, "unable to load firmware %s\n", FWFILE);
+		release_firmware(fw);
+		return -EIO;
+	}
+
+	cx18_av_write4_expect(cx, CXADEC_DL_CTL,
+				0x03000000 | fw->size, 0x03000000, 0x13000000);
+
+	CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size);
+
+	if (cx18_av_verifyfw(cx, fw) == 0)
+		cx18_av_write4_expect(cx, CXADEC_DL_CTL,
+				0x13000000 | fw->size, 0x13000000, 0x13000000);
+
+	/* Output to the 416 */
+	cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000);
+
+	/* Audio input control 1 set to Sony mode */
+	/* Audio output input 2 is 0 for slave operation input */
+	/* 0xC4000914[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */
+	/* 0xC4000914[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge
+	   after WS transition for first bit of audio word. */
+	cx18_av_write4(cx, CXADEC_I2S_IN_CTL, 0x000000A0);
+
+	/* Audio output control 1 is set to Sony mode */
+	/* Audio output control 2 is set to 1 for master mode */
+	/* 0xC4000918[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */
+	/* 0xC4000918[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge
+	   after WS transition for first bit of audio word. */
+	/* 0xC4000918[8]: 0 = slave operation, 1 = master (SCK_OUT and WS_OUT
+	   are generated) */
+	cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0);
+
+	/* set alt I2s master clock to /0x16 and enable alt divider i2s
+	   passthrough */
+	cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5600B687);
+
+	cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, 0x000000F6, 0x000000F6,
+								  0x3F00FFFF);
+	/* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */
+
+	/* Set bit 0 in register 0x9CC to signify that this is MiniMe. */
+	/* Register 0x09CC is defined by the Merlin firmware, and doesn't
+	   have a name in the spec. */
+	cx18_av_write4(cx, 0x09CC, 1);
+
+	v = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
+	/* If bit 11 is 1, clear bit 10 */
+	if (v & 0x800)
+		cx18_write_reg_expect(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE,
+				      0, 0x400);
+
+	/* Toggle the AI1 MUX */
+	v = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
+	u = v & CX18_AI1_MUX_MASK;
+	v &= ~CX18_AI1_MUX_MASK;
+	if (u == CX18_AI1_MUX_843_I2S || u == CX18_AI1_MUX_INVALID) {
+		/* Switch to I2S1 */
+		v |= CX18_AI1_MUX_I2S1;
+		cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+				      v, CX18_AI1_MUX_MASK);
+		/* Switch back to the A/V decoder core I2S output */
+		v = (v & ~CX18_AI1_MUX_MASK) | CX18_AI1_MUX_843_I2S;
+	} else {
+		/* Switch to the A/V decoder core I2S output */
+		v |= CX18_AI1_MUX_843_I2S;
+		cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+				      v, CX18_AI1_MUX_MASK);
+		/* Switch back to I2S1 or I2S2 */
+		v = (v & ~CX18_AI1_MUX_MASK) | u;
+	}
+	cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+			      v, CX18_AI1_MUX_MASK);
+
+	/* Enable WW auto audio standard detection */
+	v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
+	v |= 0xFF;   /* Auto by default */
+	v |= 0x400;  /* Stereo by default */
+	v |= 0x14000000;
+	cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, v, v, 0x3F00FFFF);
+
+	release_firmware(fw);
+	return 0;
+}
+
+MODULE_FIRMWARE(FWFILE);
diff --git a/drivers/media/pci/cx18/cx18-av-vbi.c b/drivers/media/pci/cx18/cx18-av-vbi.c
new file mode 100644
index 0000000..baa36fb
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-av-vbi.c
@@ -0,0 +1,311 @@
+/*
+ *  cx18 ADEC VBI functions
+ *
+ *  Derived from cx25840-vbi.c
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+
+#include "cx18-driver.h"
+
+/*
+ * For sliced VBI output, we set up to use VIP-1.1, 8-bit mode,
+ * NN counts 1 byte Dwords, an IDID with the VBI line # in it.
+ * Thus, according to the VIP-2 Spec, our VBI ancillary data lines
+ * (should!) look like:
+ *	4 byte EAV code:          0xff 0x00 0x00 0xRP
+ *	unknown number of possible idle bytes
+ *	3 byte Anc data preamble: 0x00 0xff 0xff
+ *	1 byte data identifier:   ne010iii (parity bits, 010, DID bits)
+ *	1 byte secondary data id: nessssss (parity bits, SDID bits)
+ *	1 byte data word count:   necccccc (parity bits, NN Dword count)
+ *	2 byte Internal DID:	  VBI-line-# 0x80
+ *	NN data bytes
+ *	1 byte checksum
+ *	Fill bytes needed to fil out to 4*NN bytes of payload
+ *
+ * The RP codes for EAVs when in VIP-1.1 mode, not in raw mode, &
+ * in the vertical blanking interval are:
+ *	0xb0 (Task         0 VerticalBlank HorizontalBlank 0 0 0 0)
+ *	0xf0 (Task EvenField VerticalBlank HorizontalBlank 0 0 0 0)
+ *
+ * Since the V bit is only allowed to toggle in the EAV RP code, just
+ * before the first active region line and for active lines, they are:
+ *	0x90 (Task         0 0 HorizontalBlank 0 0 0 0)
+ *	0xd0 (Task EvenField 0 HorizontalBlank 0 0 0 0)
+ *
+ * The user application DID bytes we care about are:
+ *	0x91 (1 0 010        0 !ActiveLine AncDataPresent)
+ *	0x55 (0 1 010 2ndField !ActiveLine AncDataPresent)
+ *
+ */
+static const u8 sliced_vbi_did[2] = { 0x91, 0x55 };
+
+struct vbi_anc_data {
+	/* u8 eav[4]; */
+	/* u8 idle[]; Variable number of idle bytes */
+	u8 preamble[3];
+	u8 did;
+	u8 sdid;
+	u8 data_count;
+	u8 idid[2];
+	u8 payload[1]; /* data_count of payload */
+	/* u8 checksum; */
+	/* u8 fill[]; Variable number of fill bytes */
+};
+
+static int odd_parity(u8 c)
+{
+	c ^= (c >> 4);
+	c ^= (c >> 2);
+	c ^= (c >> 1);
+
+	return c & 1;
+}
+
+static int decode_vps(u8 *dst, u8 *p)
+{
+	static const u8 biphase_tbl[] = {
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+		0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+		0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+		0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+		0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+		0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+		0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+		0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
+		0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
+		0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
+		0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
+		0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+		0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+		0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+		0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+		0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
+		0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
+		0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
+		0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
+		0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+		0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+		0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+		0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+		0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+		0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+	};
+
+	u8 c, err = 0;
+	int i;
+
+	for (i = 0; i < 2 * 13; i += 2) {
+		err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
+		c = (biphase_tbl[p[i + 1]] & 0xf) |
+		    ((biphase_tbl[p[i]] & 0xf) << 4);
+		dst[i / 2] = c;
+	}
+
+	return err & 0xf0;
+}
+
+int cx18_av_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
+{
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+	struct cx18_av_state *state = &cx->av_state;
+	static const u16 lcr2vbi[] = {
+		0, V4L2_SLICED_TELETEXT_B, 0,	/* 1 */
+		0, V4L2_SLICED_WSS_625, 0,	/* 4 */
+		V4L2_SLICED_CAPTION_525,	/* 6 */
+		0, 0, V4L2_SLICED_VPS, 0, 0,	/* 9 */
+		0, 0, 0, 0
+	};
+	int is_pal = !(state->std & V4L2_STD_525_60);
+	int i;
+
+	memset(svbi, 0, sizeof(*svbi));
+	/* we're done if raw VBI is active */
+	if ((cx18_av_read(cx, 0x404) & 0x10) == 0)
+		return 0;
+
+	if (is_pal) {
+		for (i = 7; i <= 23; i++) {
+			u8 v = cx18_av_read(cx, 0x424 + i - 7);
+
+			svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+			svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+			svbi->service_set |= svbi->service_lines[0][i] |
+				svbi->service_lines[1][i];
+		}
+	} else {
+		for (i = 10; i <= 21; i++) {
+			u8 v = cx18_av_read(cx, 0x424 + i - 10);
+
+			svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+			svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+			svbi->service_set |= svbi->service_lines[0][i] |
+				svbi->service_lines[1][i];
+		}
+	}
+	return 0;
+}
+
+int cx18_av_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
+{
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+	struct cx18_av_state *state = &cx->av_state;
+
+	/* Setup standard */
+	cx18_av_std_setup(cx);
+
+	/* VBI Offset */
+	cx18_av_write(cx, 0x47f, state->slicer_line_delay);
+	cx18_av_write(cx, 0x404, 0x2e);
+	return 0;
+}
+
+int cx18_av_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
+{
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+	struct cx18_av_state *state = &cx->av_state;
+	int is_pal = !(state->std & V4L2_STD_525_60);
+	int i, x;
+	u8 lcr[24];
+
+	for (x = 0; x <= 23; x++)
+		lcr[x] = 0x00;
+
+	/* Setup standard */
+	cx18_av_std_setup(cx);
+
+	/* Sliced VBI */
+	cx18_av_write(cx, 0x404, 0x32);	/* Ancillary data */
+	cx18_av_write(cx, 0x406, 0x13);
+	cx18_av_write(cx, 0x47f, state->slicer_line_delay);
+
+	/* Force impossible lines to 0 */
+	if (is_pal) {
+		for (i = 0; i <= 6; i++)
+			svbi->service_lines[0][i] =
+				svbi->service_lines[1][i] = 0;
+	} else {
+		for (i = 0; i <= 9; i++)
+			svbi->service_lines[0][i] =
+				svbi->service_lines[1][i] = 0;
+
+		for (i = 22; i <= 23; i++)
+			svbi->service_lines[0][i] =
+				svbi->service_lines[1][i] = 0;
+	}
+
+	/* Build register values for requested service lines */
+	for (i = 7; i <= 23; i++) {
+		for (x = 0; x <= 1; x++) {
+			switch (svbi->service_lines[1-x][i]) {
+			case V4L2_SLICED_TELETEXT_B:
+				lcr[i] |= 1 << (4 * x);
+				break;
+			case V4L2_SLICED_WSS_625:
+				lcr[i] |= 4 << (4 * x);
+				break;
+			case V4L2_SLICED_CAPTION_525:
+				lcr[i] |= 6 << (4 * x);
+				break;
+			case V4L2_SLICED_VPS:
+				lcr[i] |= 9 << (4 * x);
+				break;
+			}
+		}
+	}
+
+	if (is_pal) {
+		for (x = 1, i = 0x424; i <= 0x434; i++, x++)
+			cx18_av_write(cx, i, lcr[6 + x]);
+	} else {
+		for (x = 1, i = 0x424; i <= 0x430; i++, x++)
+			cx18_av_write(cx, i, lcr[9 + x]);
+		for (i = 0x431; i <= 0x434; i++)
+			cx18_av_write(cx, i, 0);
+	}
+
+	cx18_av_write(cx, 0x43c, 0x16);
+	/* Should match vblank set in cx18_av_std_setup() */
+	cx18_av_write(cx, 0x474, is_pal ? 38 : 26);
+	return 0;
+}
+
+int cx18_av_decode_vbi_line(struct v4l2_subdev *sd,
+				   struct v4l2_decode_vbi_line *vbi)
+{
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+	struct cx18_av_state *state = &cx->av_state;
+	struct vbi_anc_data *anc = (struct vbi_anc_data *)vbi->p;
+	u8 *p;
+	int did, sdid, l, err = 0;
+
+	/*
+	 * Check for the ancillary data header for sliced VBI
+	 */
+	if (anc->preamble[0] ||
+			anc->preamble[1] != 0xff || anc->preamble[2] != 0xff ||
+			(anc->did != sliced_vbi_did[0] &&
+			 anc->did != sliced_vbi_did[1])) {
+		vbi->line = vbi->type = 0;
+		return 0;
+	}
+
+	did = anc->did;
+	sdid = anc->sdid & 0xf;
+	l = anc->idid[0] & 0x3f;
+	l += state->slicer_line_offset;
+	p = anc->payload;
+
+	/* Decode the SDID set by the slicer */
+	switch (sdid) {
+	case 1:
+		sdid = V4L2_SLICED_TELETEXT_B;
+		break;
+	case 4:
+		sdid = V4L2_SLICED_WSS_625;
+		break;
+	case 6:
+		sdid = V4L2_SLICED_CAPTION_525;
+		err = !odd_parity(p[0]) || !odd_parity(p[1]);
+		break;
+	case 9:
+		sdid = V4L2_SLICED_VPS;
+		if (decode_vps(p, p) != 0)
+			err = 1;
+		break;
+	default:
+		sdid = 0;
+		err = 1;
+		break;
+	}
+
+	vbi->type = err ? 0 : sdid;
+	vbi->line = err ? 0 : l;
+	vbi->is_second_field = err ? 0 : (did == sliced_vbi_did[1]);
+	vbi->p = p;
+	return 0;
+}
diff --git a/drivers/media/pci/cx18/cx18-cards.c b/drivers/media/pci/cx18/cx18-cards.c
new file mode 100644
index 0000000..c07c849
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-cards.c
@@ -0,0 +1,638 @@
+/*
+ *  cx18 functions to query card hardware
+ *
+ *  Derived from ivtv-cards.c
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-cards.h"
+#include "cx18-av-core.h"
+#include "cx18-i2c.h"
+#include <media/cs5345.h>
+
+#define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM)
+
+/********************** card configuration *******************************/
+
+/* usual i2c tuner addresses to probe */
+static struct cx18_card_tuner_i2c cx18_i2c_std = {
+	.radio = { I2C_CLIENT_END },
+	.demod = { 0x43, I2C_CLIENT_END },
+	.tv    = { 0x61, 0x60, I2C_CLIENT_END },
+};
+
+/*
+ * usual i2c tuner addresses to probe with additional demod address for
+ * an NXP TDA8295 at 0x42 (N.B. it can possibly be at 0x4b or 0x4c too).
+ */
+static struct cx18_card_tuner_i2c cx18_i2c_nxp = {
+	.radio = { I2C_CLIENT_END },
+	.demod = { 0x42, 0x43, I2C_CLIENT_END },
+	.tv    = { 0x61, 0x60, I2C_CLIENT_END },
+};
+
+/* Please add new PCI IDs to: http://pci-ids.ucw.cz/
+   This keeps the PCI ID database up to date. Note that the entries
+   must be added under vendor 0x4444 (Conexant) as subsystem IDs.
+   New vendor IDs should still be added to the vendor ID list. */
+
+/* Hauppauge HVR-1600 cards */
+
+/* Note: for Hauppauge cards the tveeprom information is used instead
+   of PCI IDs */
+static const struct cx18_card cx18_card_hvr1600_esmt = {
+	.type = CX18_CARD_HVR_1600_ESMT,
+	.name = "Hauppauge HVR-1600",
+	.comment = "Simultaneous Digital and Analog TV capture supported\n",
+	.v4l2_capabilities = CX18_CAP_ENCODER,
+	.hw_audio_ctrl = CX18_HW_418_AV,
+	.hw_muxer = CX18_HW_CS5345,
+	.hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
+		  CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL |
+		  CX18_HW_Z8F0811_IR_HAUP,
+	.video_inputs = {
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE7 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1, CX18_AV_SVIDEO1    },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 },
+		{ CX18_CARD_INPUT_SVIDEO2,    2, CX18_AV_SVIDEO2    },
+		{ CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 },
+	},
+	.audio_inputs = {
+		{ CX18_CARD_INPUT_AUD_TUNER,
+		  CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
+		{ CX18_CARD_INPUT_LINE_IN1,
+		  CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 },
+		{ CX18_CARD_INPUT_LINE_IN2,
+		  CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 },
+	},
+	.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
+			 CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 },
+	.ddr = {
+		/* ESMT M13S128324A-5B memory */
+		.chip_config = 0x003,
+		.refresh = 0x30c,
+		.timing1 = 0x44220e82,
+		.timing2 = 0x08,
+		.tune_lane = 0,
+		.initial_emrs = 0,
+	},
+	.gpio_init.initial_value = 0x3001,
+	.gpio_init.direction = 0x3001,
+	.gpio_i2c_slave_reset = {
+		.active_lo_mask = 0x3001,
+		.msecs_asserted = 10,
+		.msecs_recovery = 40,
+		.ir_reset_mask  = 0x0001,
+	},
+	.i2c = &cx18_i2c_std,
+};
+
+static const struct cx18_card cx18_card_hvr1600_s5h1411 = {
+	.type = CX18_CARD_HVR_1600_S5H1411,
+	.name = "Hauppauge HVR-1600",
+	.comment = "Simultaneous Digital and Analog TV capture supported\n",
+	.v4l2_capabilities = CX18_CAP_ENCODER,
+	.hw_audio_ctrl = CX18_HW_418_AV,
+	.hw_muxer = CX18_HW_CS5345,
+	.hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
+		  CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL |
+		  CX18_HW_Z8F0811_IR_HAUP,
+	.video_inputs = {
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE7 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1, CX18_AV_SVIDEO1    },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 },
+		{ CX18_CARD_INPUT_SVIDEO2,    2, CX18_AV_SVIDEO2    },
+		{ CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 },
+	},
+	.audio_inputs = {
+		{ CX18_CARD_INPUT_AUD_TUNER,
+		  CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
+		{ CX18_CARD_INPUT_LINE_IN1,
+		  CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 },
+		{ CX18_CARD_INPUT_LINE_IN2,
+		  CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 },
+	},
+	.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
+			 CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 },
+	.ddr = {
+		/* ESMT M13S128324A-5B memory */
+		.chip_config = 0x003,
+		.refresh = 0x30c,
+		.timing1 = 0x44220e82,
+		.timing2 = 0x08,
+		.tune_lane = 0,
+		.initial_emrs = 0,
+	},
+	.gpio_init.initial_value = 0x3801,
+	.gpio_init.direction = 0x3801,
+	.gpio_i2c_slave_reset = {
+		.active_lo_mask = 0x3801,
+		.msecs_asserted = 10,
+		.msecs_recovery = 40,
+		.ir_reset_mask  = 0x0001,
+	},
+	.i2c = &cx18_i2c_nxp,
+};
+
+static const struct cx18_card cx18_card_hvr1600_samsung = {
+	.type = CX18_CARD_HVR_1600_SAMSUNG,
+	.name = "Hauppauge HVR-1600 (Preproduction)",
+	.comment = "Simultaneous Digital and Analog TV capture supported\n",
+	.v4l2_capabilities = CX18_CAP_ENCODER,
+	.hw_audio_ctrl = CX18_HW_418_AV,
+	.hw_muxer = CX18_HW_CS5345,
+	.hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
+		  CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL |
+		  CX18_HW_Z8F0811_IR_HAUP,
+	.video_inputs = {
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE7 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1, CX18_AV_SVIDEO1    },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 },
+		{ CX18_CARD_INPUT_SVIDEO2,    2, CX18_AV_SVIDEO2    },
+		{ CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 },
+	},
+	.audio_inputs = {
+		{ CX18_CARD_INPUT_AUD_TUNER,
+		  CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
+		{ CX18_CARD_INPUT_LINE_IN1,
+		  CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 },
+		{ CX18_CARD_INPUT_LINE_IN2,
+		  CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 },
+	},
+	.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
+			 CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 },
+	.ddr = {
+		/* Samsung K4D263238G-VC33 memory */
+		.chip_config = 0x003,
+		.refresh = 0x30c,
+		.timing1 = 0x23230b73,
+		.timing2 = 0x08,
+		.tune_lane = 0,
+		.initial_emrs = 2,
+	},
+	.gpio_init.initial_value = 0x3001,
+	.gpio_init.direction = 0x3001,
+	.gpio_i2c_slave_reset = {
+		.active_lo_mask = 0x3001,
+		.msecs_asserted = 10,
+		.msecs_recovery = 40,
+		.ir_reset_mask  = 0x0001,
+	},
+	.i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Compro VideoMate H900: note that this card is analog only! */
+
+static const struct cx18_card_pci_info cx18_pci_h900[] = {
+	{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_COMPRO, 0xe100 },
+	{ 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_h900 = {
+	.type = CX18_CARD_COMPRO_H900,
+	.name = "Compro VideoMate H900",
+	.comment = "Analog TV capture supported\n",
+	.v4l2_capabilities = CX18_CAP_ENCODER,
+	.hw_audio_ctrl = CX18_HW_418_AV,
+	.hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL,
+	.video_inputs = {
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1,
+			CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ CX18_CARD_INPUT_AUD_TUNER,
+		  CX18_AV_AUDIO5, 0 },
+		{ CX18_CARD_INPUT_LINE_IN1,
+		  CX18_AV_AUDIO_SERIAL1, 0 },
+	},
+	.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
+			 CX18_AV_AUDIO_SERIAL1, 0 },
+	.tuners = {
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+	},
+	.ddr = {
+		/* EtronTech EM6A9160TS-5G memory */
+		.chip_config = 0x50003,
+		.refresh = 0x753,
+		.timing1 = 0x24330e84,
+		.timing2 = 0x1f,
+		.tune_lane = 0,
+		.initial_emrs = 0,
+	},
+	.xceive_pin = 15,
+	.pci_list = cx18_pci_h900,
+	.i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Yuan MPC718: not working at the moment! */
+
+static const struct cx18_card_pci_info cx18_pci_mpc718[] = {
+	{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_YUAN, 0x0718 },
+	{ 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_mpc718 = {
+	.type = CX18_CARD_YUAN_MPC718,
+	.name = "Yuan MPC718 MiniPCI DVB-T/Analog",
+	.comment = "Experimenters needed for device to work well.\n"
+		  "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
+	.v4l2_capabilities = CX18_CAP_ENCODER,
+	.hw_audio_ctrl = CX18_HW_418_AV,
+	.hw_muxer = CX18_HW_GPIO_MUX,
+	.hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
+		  CX18_HW_GPIO_MUX | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
+	.video_inputs = {
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1,
+				CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
+		{ CX18_CARD_INPUT_SVIDEO2,    2,
+				CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 },
+		{ CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 },
+	},
+	.audio_inputs = {
+		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5,        0 },
+		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
+		{ CX18_CARD_INPUT_LINE_IN2,  CX18_AV_AUDIO_SERIAL2, 1 },
+	},
+	.tuners = {
+		/* XC3028 tuner */
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+	},
+	/* FIXME - the FM radio is just a guess and driver doesn't use SIF */
+	.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
+	.ddr = {
+		/* Hynix HY5DU283222B DDR RAM */
+		.chip_config = 0x303,
+		.refresh = 0x3bd,
+		.timing1 = 0x36320966,
+		.timing2 = 0x1f,
+		.tune_lane = 0,
+		.initial_emrs = 2,
+	},
+	.gpio_init.initial_value = 0x1,
+	.gpio_init.direction = 0x3,
+	/* FIXME - these GPIO's are just guesses */
+	.gpio_audio_input = { .mask   = 0x3,
+			      .tuner  = 0x1,
+			      .linein = 0x3,
+			      .radio  = 0x1 },
+	.xceive_pin = 0,
+	.pci_list = cx18_pci_mpc718,
+	.i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* GoTView PCI */
+
+static const struct cx18_card_pci_info cx18_pci_gotview_dvd3[] = {
+	{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_GOTVIEW, 0x3343 },
+	{ 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_gotview_dvd3 = {
+	.type = CX18_CARD_GOTVIEW_PCI_DVD3,
+	.name = "GoTView PCI DVD3 Hybrid",
+	.comment = "Experimenters needed for device to work well.\n"
+		  "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
+	.v4l2_capabilities = CX18_CAP_ENCODER,
+	.hw_audio_ctrl = CX18_HW_418_AV,
+	.hw_muxer = CX18_HW_GPIO_MUX,
+	.hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
+		  CX18_HW_GPIO_MUX | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
+	.video_inputs = {
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1,
+				CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
+		{ CX18_CARD_INPUT_SVIDEO2,    2,
+				CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 },
+		{ CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 },
+	},
+	.audio_inputs = {
+		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5,        0 },
+		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
+		{ CX18_CARD_INPUT_LINE_IN2,  CX18_AV_AUDIO_SERIAL2, 1 },
+	},
+	.tuners = {
+		/* XC3028 tuner */
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+	},
+	/* FIXME - the FM radio is just a guess and driver doesn't use SIF */
+	.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
+	.ddr = {
+		/* Hynix HY5DU283222B DDR RAM */
+		.chip_config = 0x303,
+		.refresh = 0x3bd,
+		.timing1 = 0x36320966,
+		.timing2 = 0x1f,
+		.tune_lane = 0,
+		.initial_emrs = 2,
+	},
+	.gpio_init.initial_value = 0x1,
+	.gpio_init.direction = 0x3,
+
+	.gpio_audio_input = { .mask   = 0x3,
+			      .tuner  = 0x1,
+			      .linein = 0x2,
+			      .radio  = 0x1 },
+	.xceive_pin = 0,
+	.pci_list = cx18_pci_gotview_dvd3,
+	.i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Conexant Raptor PAL/SECAM: note that this card is analog only! */
+
+static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = {
+	{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_CONEXANT, 0x0009 },
+	{ 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_cnxt_raptor_pal = {
+	.type = CX18_CARD_CNXT_RAPTOR_PAL,
+	.name = "Conexant Raptor PAL/SECAM",
+	.comment = "Analog TV capture supported\n",
+	.v4l2_capabilities = CX18_CAP_ENCODER,
+	.hw_audio_ctrl = CX18_HW_418_AV,
+	.hw_muxer = CX18_HW_GPIO_MUX,
+	.hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX,
+	.video_inputs = {
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1,
+			CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
+		{ CX18_CARD_INPUT_SVIDEO2,    2,
+			CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 },
+		{ CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 },
+	},
+	.audio_inputs = {
+		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 	    0 },
+		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
+		{ CX18_CARD_INPUT_LINE_IN2,  CX18_AV_AUDIO_SERIAL2, 1 },
+	},
+	.tuners = {
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+	},
+	.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 2 },
+	.ddr = {
+		/* MT 46V16M16 memory */
+		.chip_config = 0x50306,
+		.refresh = 0x753,
+		.timing1 = 0x33220953,
+		.timing2 = 0x09,
+		.tune_lane = 0,
+		.initial_emrs = 0,
+	},
+	.gpio_init.initial_value = 0x1002,
+	.gpio_init.direction = 0xf002,
+	.gpio_audio_input = { .mask   = 0xf002,
+			      .tuner  = 0x1002,   /* LED D1  Tuner AF  */
+			      .linein = 0x2000,   /* LED D2  Line In 1 */
+			      .radio  = 0x4002 }, /* LED D3  Tuner AF  */
+	.pci_list = cx18_pci_cnxt_raptor_pal,
+	.i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Toshiba Qosmio laptop internal DVB-T/Analog Hybrid Tuner */
+
+static const struct cx18_card_pci_info cx18_pci_toshiba_qosmio_dvbt[] = {
+	{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_TOSHIBA, 0x0110 },
+	{ 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = {
+	.type = CX18_CARD_TOSHIBA_QOSMIO_DVBT,
+	.name = "Toshiba Qosmio DVB-T/Analog",
+	.comment = "Experimenters and photos needed for device to work well.\n"
+		  "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
+	.v4l2_capabilities = CX18_CAP_ENCODER,
+	.hw_audio_ctrl = CX18_HW_418_AV,
+	.hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL,
+	.video_inputs = {
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE6 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1,
+			CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 	    0 },
+		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
+	},
+	.tuners = {
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+	},
+	.ddr = {
+		.chip_config = 0x202,
+		.refresh = 0x3bb,
+		.timing1 = 0x33320a63,
+		.timing2 = 0x0a,
+		.tune_lane = 0,
+		.initial_emrs = 0x42,
+	},
+	.xceive_pin = 15,
+	.pci_list = cx18_pci_toshiba_qosmio_dvbt,
+	.i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Leadtek WinFast PVR2100 */
+
+static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = {
+	{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, /* PVR2100   */
+	{ 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_leadtek_pvr2100 = {
+	.type = CX18_CARD_LEADTEK_PVR2100,
+	.name = "Leadtek WinFast PVR2100",
+	.comment = "Experimenters and photos needed for device to work well.\n"
+		  "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
+	.v4l2_capabilities = CX18_CAP_ENCODER,
+	.hw_audio_ctrl = CX18_HW_418_AV,
+	.hw_muxer = CX18_HW_GPIO_MUX,
+	.hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX |
+		  CX18_HW_GPIO_RESET_CTRL,
+	.video_inputs = {
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1,
+			CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE7 },
+		{ CX18_CARD_INPUT_COMPONENT1, 1, CX18_AV_COMPONENT1 },
+	},
+	.audio_inputs = {
+		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 	    0 },
+		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
+	},
+	.tuners = {
+		/* XC2028 tuner */
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+	},
+	.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
+	.ddr = {
+		/* Pointer to proper DDR config values provided by Terry Wu */
+		.chip_config = 0x303,
+		.refresh = 0x3bb,
+		.timing1 = 0x24220e83,
+		.timing2 = 0x1f,
+		.tune_lane = 0,
+		.initial_emrs = 0x2,
+	},
+	.gpio_init.initial_value = 0x6,
+	.gpio_init.direction = 0x7,
+	.gpio_audio_input = { .mask   = 0x7,
+			      .tuner  = 0x6, .linein = 0x2, .radio  = 0x2 },
+	.xceive_pin = 1,
+	.pci_list = cx18_pci_leadtek_pvr2100,
+	.i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Leadtek WinFast DVR3100 H */
+
+static const struct cx18_card_pci_info cx18_pci_leadtek_dvr3100h[] = {
+	{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */
+	{ 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_leadtek_dvr3100h = {
+	.type = CX18_CARD_LEADTEK_DVR3100H,
+	.name = "Leadtek WinFast DVR3100 H",
+	.comment = "Simultaneous DVB-T and Analog capture supported,\n"
+		  "\texcept when capturing Analog from the antenna input.\n",
+	.v4l2_capabilities = CX18_CAP_ENCODER,
+	.hw_audio_ctrl = CX18_HW_418_AV,
+	.hw_muxer = CX18_HW_GPIO_MUX,
+	.hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX |
+		  CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
+	.video_inputs = {
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1,
+			CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE7 },
+		{ CX18_CARD_INPUT_COMPONENT1, 1, CX18_AV_COMPONENT1 },
+	},
+	.audio_inputs = {
+		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 	    0 },
+		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
+	},
+	.tuners = {
+		/* XC3028 tuner */
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+	},
+	.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
+	.ddr = {
+		/* Pointer to proper DDR config values provided by Terry Wu */
+		.chip_config = 0x303,
+		.refresh = 0x3bb,
+		.timing1 = 0x24220e83,
+		.timing2 = 0x1f,
+		.tune_lane = 0,
+		.initial_emrs = 0x2,
+	},
+	.gpio_init.initial_value = 0x6,
+	.gpio_init.direction = 0x7,
+	.gpio_audio_input = { .mask   = 0x7,
+			      .tuner  = 0x6, .linein = 0x2, .radio  = 0x2 },
+	.xceive_pin = 1,
+	.pci_list = cx18_pci_leadtek_dvr3100h,
+	.i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+static const struct cx18_card *cx18_card_list[] = {
+	&cx18_card_hvr1600_esmt,
+	&cx18_card_hvr1600_samsung,
+	&cx18_card_h900,
+	&cx18_card_mpc718,
+	&cx18_card_cnxt_raptor_pal,
+	&cx18_card_toshiba_qosmio_dvbt,
+	&cx18_card_leadtek_pvr2100,
+	&cx18_card_leadtek_dvr3100h,
+	&cx18_card_gotview_dvd3,
+	&cx18_card_hvr1600_s5h1411
+};
+
+const struct cx18_card *cx18_get_card(u16 index)
+{
+	if (index >= ARRAY_SIZE(cx18_card_list))
+		return NULL;
+	return cx18_card_list[index];
+}
+
+int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input)
+{
+	const struct cx18_card_video_input *card_input =
+		cx->card->video_inputs + index;
+	static const char * const input_strs[] = {
+		"Tuner 1",
+		"S-Video 1",
+		"S-Video 2",
+		"Composite 1",
+		"Composite 2",
+		"Component 1"
+	};
+
+	if (index >= cx->nof_inputs)
+		return -EINVAL;
+	input->index = index;
+	strlcpy(input->name, input_strs[card_input->video_type - 1],
+			sizeof(input->name));
+	input->type = (card_input->video_type == CX18_CARD_INPUT_VID_TUNER ?
+			V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA);
+	input->audioset = (1 << cx->nof_audio_inputs) - 1;
+	input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ?
+				cx->tuner_std : V4L2_STD_ALL;
+	return 0;
+}
+
+int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *audio)
+{
+	const struct cx18_card_audio_input *aud_input =
+		cx->card->audio_inputs + index;
+	static const char * const input_strs[] = {
+		"Tuner 1",
+		"Line In 1",
+		"Line In 2"
+	};
+
+	memset(audio, 0, sizeof(*audio));
+	if (index >= cx->nof_audio_inputs)
+		return -EINVAL;
+	strlcpy(audio->name, input_strs[aud_input->audio_type - 1],
+			sizeof(audio->name));
+	audio->index = index;
+	audio->capability = V4L2_AUDCAP_STEREO;
+	return 0;
+}
diff --git a/drivers/media/pci/cx18/cx18-cards.h b/drivers/media/pci/cx18/cx18-cards.h
new file mode 100644
index 0000000..add7391
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-cards.h
@@ -0,0 +1,157 @@
+/*
+ *  cx18 functions to query card hardware
+ *
+ *  Derived from ivtv-cards.c
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* hardware flags */
+#define CX18_HW_TUNER			(1 << 0)
+#define CX18_HW_TVEEPROM		(1 << 1)
+#define CX18_HW_CS5345			(1 << 2)
+#define CX18_HW_DVB			(1 << 3)
+#define CX18_HW_418_AV			(1 << 4)
+#define CX18_HW_GPIO_MUX		(1 << 5)
+#define CX18_HW_GPIO_RESET_CTRL		(1 << 6)
+#define CX18_HW_Z8F0811_IR_TX_HAUP	(1 << 7)
+#define CX18_HW_Z8F0811_IR_RX_HAUP	(1 << 8)
+#define CX18_HW_Z8F0811_IR_HAUP	(CX18_HW_Z8F0811_IR_RX_HAUP | \
+				 CX18_HW_Z8F0811_IR_TX_HAUP)
+
+#define CX18_HW_IR_ANY (CX18_HW_Z8F0811_IR_RX_HAUP | \
+			CX18_HW_Z8F0811_IR_TX_HAUP)
+
+/* video inputs */
+#define	CX18_CARD_INPUT_VID_TUNER	1
+#define	CX18_CARD_INPUT_SVIDEO1 	2
+#define	CX18_CARD_INPUT_SVIDEO2 	3
+#define	CX18_CARD_INPUT_COMPOSITE1 	4
+#define	CX18_CARD_INPUT_COMPOSITE2 	5
+#define	CX18_CARD_INPUT_COMPONENT1 	6
+
+/* audio inputs */
+#define	CX18_CARD_INPUT_AUD_TUNER	1
+#define	CX18_CARD_INPUT_LINE_IN1 	2
+#define	CX18_CARD_INPUT_LINE_IN2 	3
+
+#define CX18_CARD_MAX_VIDEO_INPUTS 6
+#define CX18_CARD_MAX_AUDIO_INPUTS 3
+#define CX18_CARD_MAX_TUNERS  	   2
+
+/* V4L2 capability aliases */
+#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
+			  V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | \
+			  V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)
+
+struct cx18_card_video_input {
+	u8  video_type; 	/* video input type */
+	u8  audio_index;	/* index in cx18_card_audio_input array */
+	u32 video_input;	/* hardware video input */
+};
+
+struct cx18_card_audio_input {
+	u8  audio_type;		/* audio input type */
+	u32 audio_input;	/* hardware audio input */
+	u16 muxer_input;	/* hardware muxer input for boards with a
+				   multiplexer chip */
+};
+
+struct cx18_card_pci_info {
+	u16 device;
+	u16 subsystem_vendor;
+	u16 subsystem_device;
+};
+
+/* GPIO definitions */
+
+/* The mask is the set of bits used by the operation */
+
+struct cx18_gpio_init { /* set initial GPIO DIR and OUT values */
+	u32 direction; 	/* DIR setting. Leave to 0 if no init is needed */
+	u32 initial_value;
+};
+
+struct cx18_gpio_i2c_slave_reset {
+	u32 active_lo_mask; /* GPIO outputs that reset i2c chips when low */
+	u32 active_hi_mask; /* GPIO outputs that reset i2c chips when high */
+	int msecs_asserted; /* time period reset must remain asserted */
+	int msecs_recovery; /* time after deassert for chips to be ready */
+	u32 ir_reset_mask;  /* GPIO to reset the Zilog Z8F0811 IR contoller */
+};
+
+struct cx18_gpio_audio_input { 	/* select tuner/line in input */
+	u32 mask; 		/* leave to 0 if not supported */
+	u32 tuner;
+	u32 linein;
+	u32 radio;
+};
+
+struct cx18_card_tuner {
+	v4l2_std_id std; 	/* standard for which the tuner is suitable */
+	int 	    tuner; 	/* tuner ID (from tuner.h) */
+};
+
+struct cx18_card_tuner_i2c {
+	unsigned short radio[2];/* radio tuner i2c address to probe */
+	unsigned short demod[3];/* demodulator i2c address to probe */
+	unsigned short tv[4];	/* tv tuner i2c addresses to probe */
+};
+
+struct cx18_ddr {		/* DDR config data */
+	u32 chip_config;
+	u32 refresh;
+	u32 timing1;
+	u32 timing2;
+	u32 tune_lane;
+	u32 initial_emrs;
+};
+
+/* for card information/parameters */
+struct cx18_card {
+	int type;
+	char *name;
+	char *comment;
+	u32 v4l2_capabilities;
+	u32 hw_audio_ctrl;	/* hardware used for the V4L2 controls (only
+				   1 dev allowed currently) */
+	u32 hw_muxer;		/* hardware used to multiplex audio input */
+	u32 hw_all;		/* all hardware used by the board */
+	struct cx18_card_video_input video_inputs[CX18_CARD_MAX_VIDEO_INPUTS];
+	struct cx18_card_audio_input audio_inputs[CX18_CARD_MAX_AUDIO_INPUTS];
+	struct cx18_card_audio_input radio_input;
+
+	/* GPIO card-specific settings */
+	u8 xceive_pin; 		/* XCeive tuner GPIO reset pin */
+	struct cx18_gpio_init 		 gpio_init;
+	struct cx18_gpio_i2c_slave_reset gpio_i2c_slave_reset;
+	struct cx18_gpio_audio_input    gpio_audio_input;
+
+	struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS];
+	struct cx18_card_tuner_i2c *i2c;
+
+	struct cx18_ddr ddr;
+
+	/* list of device and subsystem vendor/devices that
+	   correspond to this card type. */
+	const struct cx18_card_pci_info *pci_list;
+};
+
+int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input);
+int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *input);
+const struct cx18_card *cx18_get_card(u16 index);
diff --git a/drivers/media/pci/cx18/cx18-controls.c b/drivers/media/pci/cx18/cx18-controls.c
new file mode 100644
index 0000000..282a3d2
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-controls.c
@@ -0,0 +1,131 @@
+/*
+ *  cx18 ioctl control functions
+ *
+ *  Derived from ivtv-controls.c
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "cx18-driver.h"
+#include "cx18-cards.h"
+#include "cx18-ioctl.h"
+#include "cx18-audio.h"
+#include "cx18-mailbox.h"
+#include "cx18-controls.h"
+
+static int cx18_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt)
+{
+	struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
+	int type = cxhdl->stream_type->val;
+
+	if (atomic_read(&cx->ana_capturing) > 0)
+		return -EBUSY;
+
+	if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV ||
+	    !(type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS ||
+	      type == V4L2_MPEG_STREAM_TYPE_MPEG2_DVD ||
+	      type == V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD)) {
+		/* Only IVTV fmt VBI insertion & only MPEG-2 PS type streams */
+		cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE;
+		CX18_DEBUG_INFO("disabled insertion of sliced VBI data into "
+				"the MPEG stream\n");
+		return 0;
+	}
+
+	/* Allocate sliced VBI buffers if needed. */
+	if (cx->vbi.sliced_mpeg_data[0] == NULL) {
+		int i;
+
+		for (i = 0; i < CX18_VBI_FRAMES; i++) {
+			cx->vbi.sliced_mpeg_data[i] =
+			       kmalloc(CX18_SLICED_MPEG_DATA_BUFSZ, GFP_KERNEL);
+			if (cx->vbi.sliced_mpeg_data[i] == NULL) {
+				while (--i >= 0) {
+					kfree(cx->vbi.sliced_mpeg_data[i]);
+					cx->vbi.sliced_mpeg_data[i] = NULL;
+				}
+				cx->vbi.insert_mpeg =
+						  V4L2_MPEG_STREAM_VBI_FMT_NONE;
+				CX18_WARN("Unable to allocate buffers for "
+					  "sliced VBI data insertion\n");
+				return -ENOMEM;
+			}
+		}
+	}
+
+	cx->vbi.insert_mpeg = fmt;
+	CX18_DEBUG_INFO("enabled insertion of sliced VBI data into the MPEG PS,"
+			"when sliced VBI is enabled\n");
+
+	/*
+	 * If our current settings have no lines set for capture, store a valid,
+	 * default set of service lines to capture, in our current settings.
+	 */
+	if (cx18_get_service_set(cx->vbi.sliced_in) == 0) {
+		if (cx->is_60hz)
+			cx->vbi.sliced_in->service_set =
+							V4L2_SLICED_CAPTION_525;
+		else
+			cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
+		cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz);
+	}
+	return 0;
+}
+
+static int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val)
+{
+	struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
+	int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+	struct v4l2_mbus_framefmt fmt;
+
+	/* fix videodecoder resolution */
+	fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1);
+	fmt.height = cxhdl->height;
+	fmt.code = V4L2_MBUS_FMT_FIXED;
+	v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt);
+	return 0;
+}
+
+static int cx18_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx)
+{
+	static const u32 freqs[3] = { 44100, 48000, 32000 };
+	struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
+
+	/* The audio clock of the digitizer must match the codec sample
+	   rate otherwise you get some very strange effects. */
+	if (idx < ARRAY_SIZE(freqs))
+		cx18_call_all(cx, audio, s_clock_freq, freqs[idx]);
+	return 0;
+}
+
+static int cx18_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val)
+{
+	struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
+
+	cx->dualwatch_stereo_mode = val;
+	return 0;
+}
+
+struct cx2341x_handler_ops cx18_cxhdl_ops = {
+	.s_audio_mode = cx18_s_audio_mode,
+	.s_audio_sampling_freq = cx18_s_audio_sampling_freq,
+	.s_video_encoding = cx18_s_video_encoding,
+	.s_stream_vbi_fmt = cx18_s_stream_vbi_fmt,
+};
diff --git a/drivers/media/pci/cx18/cx18-controls.h b/drivers/media/pci/cx18/cx18-controls.h
new file mode 100644
index 0000000..cb5dfc7
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-controls.h
@@ -0,0 +1,24 @@
+/*
+ *  cx18 ioctl control functions
+ *
+ *  Derived from ivtv-controls.h
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+extern struct cx2341x_handler_ops cx18_cxhdl_ops;
diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c
new file mode 100644
index 0000000..c67733d
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-driver.c
@@ -0,0 +1,1360 @@
+/*
+ *  cx18 driver initialization and card probing
+ *
+ *  Derived from ivtv-driver.c
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-io.h"
+#include "cx18-version.h"
+#include "cx18-cards.h"
+#include "cx18-i2c.h"
+#include "cx18-irq.h"
+#include "cx18-gpio.h"
+#include "cx18-firmware.h"
+#include "cx18-queue.h"
+#include "cx18-streams.h"
+#include "cx18-av-core.h"
+#include "cx18-scb.h"
+#include "cx18-mailbox.h"
+#include "cx18-ioctl.h"
+#include "cx18-controls.h"
+#include "tuner-xc2028.h"
+#include <linux/dma-mapping.h>
+#include <media/tveeprom.h>
+
+/* If you have already X v4l cards, then set this to X. This way
+   the device numbers stay matched. Example: you have a WinTV card
+   without radio and a Compro H900 with. Normally this would give a
+   video1 device together with a radio0 device for the Compro. By
+   setting this to 1 you ensure that radio0 is now also radio1. */
+int cx18_first_minor;
+
+/* Callback for registering extensions */
+int (*cx18_ext_init)(struct cx18 *);
+EXPORT_SYMBOL(cx18_ext_init);
+
+/* add your revision and whatnot here */
+static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
+	{PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci, cx18_pci_tbl);
+
+static atomic_t cx18_instance = ATOMIC_INIT(0);
+
+/* Parameter declarations */
+static int cardtype[CX18_MAX_CARDS];
+static int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1 };
+static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1 };
+static unsigned cardtype_c = 1;
+static unsigned tuner_c = 1;
+static unsigned radio_c = 1;
+static char pal[] = "--";
+static char secam[] = "--";
+static char ntsc[] = "-";
+
+/* Buffers */
+static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS;
+static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS;
+static int enc_idx_buffers = CX18_DEFAULT_ENC_IDX_BUFFERS;
+static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS;
+static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS;
+static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS;
+
+static int enc_ts_bufsize = CX18_DEFAULT_ENC_TS_BUFSIZE;
+static int enc_mpg_bufsize = CX18_DEFAULT_ENC_MPG_BUFSIZE;
+static int enc_idx_bufsize = CX18_DEFAULT_ENC_IDX_BUFSIZE;
+static int enc_yuv_bufsize = CX18_DEFAULT_ENC_YUV_BUFSIZE;
+static int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE;
+
+static int enc_ts_bufs = -1;
+static int enc_mpg_bufs = -1;
+static int enc_idx_bufs = CX18_MAX_FW_MDLS_PER_STREAM;
+static int enc_yuv_bufs = -1;
+static int enc_vbi_bufs = -1;
+static int enc_pcm_bufs = -1;
+
+
+static int cx18_pci_latency = 1;
+
+static int mmio_ndelay;
+static int retry_mmio = 1;
+
+int cx18_debug;
+
+module_param_array(tuner, int, &tuner_c, 0644);
+module_param_array(radio, int, &radio_c, 0644);
+module_param_array(cardtype, int, &cardtype_c, 0644);
+module_param_string(pal, pal, sizeof(pal), 0644);
+module_param_string(secam, secam, sizeof(secam), 0644);
+module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
+module_param_named(debug, cx18_debug, int, 0644);
+module_param(mmio_ndelay, int, 0644);
+module_param(retry_mmio, int, 0644);
+module_param(cx18_pci_latency, int, 0644);
+module_param(cx18_first_minor, int, 0644);
+
+module_param(enc_ts_buffers, int, 0644);
+module_param(enc_mpg_buffers, int, 0644);
+module_param(enc_idx_buffers, int, 0644);
+module_param(enc_yuv_buffers, int, 0644);
+module_param(enc_vbi_buffers, int, 0644);
+module_param(enc_pcm_buffers, int, 0644);
+
+module_param(enc_ts_bufsize, int, 0644);
+module_param(enc_mpg_bufsize, int, 0644);
+module_param(enc_idx_bufsize, int, 0644);
+module_param(enc_yuv_bufsize, int, 0644);
+module_param(enc_pcm_bufsize, int, 0644);
+
+module_param(enc_ts_bufs, int, 0644);
+module_param(enc_mpg_bufs, int, 0644);
+module_param(enc_idx_bufs, int, 0644);
+module_param(enc_yuv_bufs, int, 0644);
+module_param(enc_vbi_bufs, int, 0644);
+module_param(enc_pcm_bufs, int, 0644);
+
+MODULE_PARM_DESC(tuner, "Tuner type selection,\n"
+			"\t\t\tsee tuner.h for values");
+MODULE_PARM_DESC(radio,
+		 "Enable or disable the radio. Use only if autodetection\n"
+		 "\t\t\tfails. 0 = disable, 1 = enable");
+MODULE_PARM_DESC(cardtype,
+		 "Only use this option if your card is not detected properly.\n"
+		 "\t\tSpecify card type:\n"
+		 "\t\t\t 1 = Hauppauge HVR 1600 (ESMT memory)\n"
+		 "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n"
+		 "\t\t\t 3 = Compro VideoMate H900\n"
+		 "\t\t\t 4 = Yuan MPC718\n"
+		 "\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
+		 "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n"
+		 "\t\t\t 7 = Leadtek WinFast PVR2100\n"
+		 "\t\t\t 8 = Leadtek WinFast DVR3100 H\n"
+		 "\t\t\t 9 = GoTView PCI DVD3 Hybrid\n"
+		 "\t\t\t 10 = Hauppauge HVR 1600 (S5H1411)\n"
+		 "\t\t\t 0 = Autodetect (default)\n"
+		 "\t\t\t-1 = Ignore this card\n\t\t");
+MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
+MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC");
+MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K");
+MODULE_PARM_DESC(debug,
+		 "Debug level (bitmask). Default: 0\n"
+		 "\t\t\t  1/0x0001: warning\n"
+		 "\t\t\t  2/0x0002: info\n"
+		 "\t\t\t  4/0x0004: mailbox\n"
+		 "\t\t\t  8/0x0008: dma\n"
+		 "\t\t\t 16/0x0010: ioctl\n"
+		 "\t\t\t 32/0x0020: file\n"
+		 "\t\t\t 64/0x0040: i2c\n"
+		 "\t\t\t128/0x0080: irq\n"
+		 "\t\t\t256/0x0100: high volume\n");
+MODULE_PARM_DESC(cx18_pci_latency,
+		 "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
+		 "\t\t\tDefault: Yes");
+MODULE_PARM_DESC(retry_mmio,
+		 "(Deprecated) MMIO writes are now always checked and retried\n"
+		 "\t\t\tEffectively: 1 [Yes]");
+MODULE_PARM_DESC(mmio_ndelay,
+		 "(Deprecated) MMIO accesses are now never purposely delayed\n"
+		 "\t\t\tEffectively: 0 ns");
+MODULE_PARM_DESC(enc_ts_buffers,
+		 "Encoder TS buffer memory (MB). (enc_ts_bufs can override)\n"
+		 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS));
+MODULE_PARM_DESC(enc_ts_bufsize,
+		 "Size of an encoder TS buffer (kB)\n"
+		 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFSIZE));
+MODULE_PARM_DESC(enc_ts_bufs,
+		 "Number of encoder TS buffers\n"
+		 "\t\t\tDefault is computed from other enc_ts_* parameters");
+MODULE_PARM_DESC(enc_mpg_buffers,
+		 "Encoder MPG buffer memory (MB). (enc_mpg_bufs can override)\n"
+		 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS));
+MODULE_PARM_DESC(enc_mpg_bufsize,
+		 "Size of an encoder MPG buffer (kB)\n"
+		 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFSIZE));
+MODULE_PARM_DESC(enc_mpg_bufs,
+		 "Number of encoder MPG buffers\n"
+		 "\t\t\tDefault is computed from other enc_mpg_* parameters");
+MODULE_PARM_DESC(enc_idx_buffers,
+		 "(Deprecated) Encoder IDX buffer memory (MB)\n"
+		 "\t\t\tIgnored, except 0 disables IDX buffer allocations\n"
+		 "\t\t\tDefault: 1 [Enabled]");
+MODULE_PARM_DESC(enc_idx_bufsize,
+		 "Size of an encoder IDX buffer (kB)\n"
+		 "\t\t\tAllowed values are multiples of 1.5 kB rounded up\n"
+		 "\t\t\t(multiples of size required for 64 index entries)\n"
+		 "\t\t\tDefault: 2");
+MODULE_PARM_DESC(enc_idx_bufs,
+		 "Number of encoder IDX buffers\n"
+		 "\t\t\tDefault: " __stringify(CX18_MAX_FW_MDLS_PER_STREAM));
+MODULE_PARM_DESC(enc_yuv_buffers,
+		 "Encoder YUV buffer memory (MB). (enc_yuv_bufs can override)\n"
+		 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS));
+MODULE_PARM_DESC(enc_yuv_bufsize,
+		 "Size of an encoder YUV buffer (kB)\n"
+		 "\t\t\tAllowed values are multiples of 33.75 kB rounded up\n"
+		 "\t\t\t(multiples of size required for 32 screen lines)\n"
+		 "\t\t\tDefault: 102");
+MODULE_PARM_DESC(enc_yuv_bufs,
+		 "Number of encoder YUV buffers\n"
+		 "\t\t\tDefault is computed from other enc_yuv_* parameters");
+MODULE_PARM_DESC(enc_vbi_buffers,
+		 "Encoder VBI buffer memory (MB). (enc_vbi_bufs can override)\n"
+		 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS));
+MODULE_PARM_DESC(enc_vbi_bufs,
+		 "Number of encoder VBI buffers\n"
+		 "\t\t\tDefault is computed from enc_vbi_buffers");
+MODULE_PARM_DESC(enc_pcm_buffers,
+		 "Encoder PCM buffer memory (MB). (enc_pcm_bufs can override)\n"
+		 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS));
+MODULE_PARM_DESC(enc_pcm_bufsize,
+		 "Size of an encoder PCM buffer (kB)\n"
+		 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFSIZE));
+MODULE_PARM_DESC(enc_pcm_bufs,
+		 "Number of encoder PCM buffers\n"
+		 "\t\t\tDefault is computed from other enc_pcm_* parameters");
+
+MODULE_PARM_DESC(cx18_first_minor,
+		 "Set device node number assigned to first card");
+
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_DESCRIPTION("CX23418 driver");
+MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder");
+MODULE_LICENSE("GPL");
+
+MODULE_VERSION(CX18_VERSION);
+
+#if defined(CONFIG_MODULES) && defined(MODULE)
+static void request_module_async(struct work_struct *work)
+{
+	struct cx18 *dev = container_of(work, struct cx18, request_module_wk);
+
+	/* Make sure cx18-alsa module is loaded */
+	request_module("cx18-alsa");
+
+	/* Initialize cx18-alsa for this instance of the cx18 device */
+	if (cx18_ext_init != NULL)
+		cx18_ext_init(dev);
+}
+
+static void request_modules(struct cx18 *dev)
+{
+	INIT_WORK(&dev->request_module_wk, request_module_async);
+	schedule_work(&dev->request_module_wk);
+}
+
+static void flush_request_modules(struct cx18 *dev)
+{
+	flush_work_sync(&dev->request_module_wk);
+}
+#else
+#define request_modules(dev)
+#define flush_request_modules(dev)
+#endif /* CONFIG_MODULES */
+
+/* Generic utility functions */
+int cx18_msleep_timeout(unsigned int msecs, int intr)
+{
+	long int timeout = msecs_to_jiffies(msecs);
+	int sig;
+
+	do {
+		set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+		timeout = schedule_timeout(timeout);
+		sig = intr ? signal_pending(current) : 0;
+	} while (!sig && timeout);
+	return sig;
+}
+
+/* Release ioremapped memory */
+static void cx18_iounmap(struct cx18 *cx)
+{
+	if (cx == NULL)
+		return;
+
+	/* Release io memory */
+	if (cx->enc_mem != NULL) {
+		CX18_DEBUG_INFO("releasing enc_mem\n");
+		iounmap(cx->enc_mem);
+		cx->enc_mem = NULL;
+	}
+}
+
+static void cx18_eeprom_dump(struct cx18 *cx, unsigned char *eedata, int len)
+{
+	int i;
+
+	CX18_INFO("eeprom dump:\n");
+	for (i = 0; i < len; i++) {
+		if (0 == (i % 16))
+			CX18_INFO("eeprom %02x:", i);
+		printk(KERN_CONT " %02x", eedata[i]);
+		if (15 == (i % 16))
+			printk(KERN_CONT "\n");
+	}
+}
+
+/* Hauppauge card? get values from tveeprom */
+void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
+{
+	struct i2c_client c;
+	u8 eedata[256];
+
+	memset(&c, 0, sizeof(c));
+	strlcpy(c.name, "cx18 tveeprom tmp", sizeof(c.name));
+	c.adapter = &cx->i2c_adap[0];
+	c.addr = 0xA0 >> 1;
+
+	memset(tv, 0, sizeof(*tv));
+	if (tveeprom_read(&c, eedata, sizeof(eedata)))
+		return;
+
+	switch (cx->card->type) {
+	case CX18_CARD_HVR_1600_ESMT:
+	case CX18_CARD_HVR_1600_SAMSUNG:
+	case CX18_CARD_HVR_1600_S5H1411:
+		tveeprom_hauppauge_analog(&c, tv, eedata);
+		break;
+	case CX18_CARD_YUAN_MPC718:
+	case CX18_CARD_GOTVIEW_PCI_DVD3:
+		tv->model = 0x718;
+		cx18_eeprom_dump(cx, eedata, sizeof(eedata));
+		CX18_INFO("eeprom PCI ID: %02x%02x:%02x%02x\n",
+			  eedata[2], eedata[1], eedata[4], eedata[3]);
+		break;
+	default:
+		tv->model = 0xffffffff;
+		cx18_eeprom_dump(cx, eedata, sizeof(eedata));
+		break;
+	}
+}
+
+static void cx18_process_eeprom(struct cx18 *cx)
+{
+	struct tveeprom tv;
+
+	cx18_read_eeprom(cx, &tv);
+
+	/* Many thanks to Steven Toth from Hauppauge for providing the
+	   model numbers */
+	/* Note: the Samsung memory models cannot be reliably determined
+	   from the model number. Use the cardtype module option if you
+	   have one of these preproduction models. */
+	switch (tv.model) {
+	case 74301: /* Retail models */
+	case 74321:
+	case 74351: /* OEM models */
+	case 74361:
+		/* Digital side is s5h1411/tda18271 */
+		cx->card = cx18_get_card(CX18_CARD_HVR_1600_S5H1411);
+		break;
+	case 74021: /* Retail models */
+	case 74031:
+	case 74041:
+	case 74141:
+	case 74541: /* OEM models */
+	case 74551:
+	case 74591:
+	case 74651:
+	case 74691:
+	case 74751:
+	case 74891:
+		/* Digital side is s5h1409/mxl5005s */
+		cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+		break;
+	case 0x718:
+		return;
+	case 0xffffffff:
+		CX18_INFO("Unknown EEPROM encoding\n");
+		return;
+	case 0:
+		CX18_ERR("Invalid EEPROM\n");
+		return;
+	default:
+		CX18_ERR("Unknown model %d, defaulting to original HVR-1600 "
+			 "(cardtype=1)\n", tv.model);
+		cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+		break;
+	}
+
+	cx->v4l2_cap = cx->card->v4l2_capabilities;
+	cx->card_name = cx->card->name;
+	cx->card_i2c = cx->card->i2c;
+
+	CX18_INFO("Autodetected %s\n", cx->card_name);
+
+	if (tv.tuner_type == TUNER_ABSENT)
+		CX18_ERR("tveeprom cannot autodetect tuner!\n");
+
+	if (cx->options.tuner == -1)
+		cx->options.tuner = tv.tuner_type;
+	if (cx->options.radio == -1)
+		cx->options.radio = (tv.has_radio != 0);
+
+	if (cx->std != 0)
+		/* user specified tuner standard */
+		return;
+
+	/* autodetect tuner standard */
+#define TVEEPROM_TUNER_FORMAT_ALL (V4L2_STD_B  | V4L2_STD_GH | \
+				   V4L2_STD_MN | \
+				   V4L2_STD_PAL_I | \
+				   V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC | \
+				   V4L2_STD_DK)
+	if ((tv.tuner_formats & TVEEPROM_TUNER_FORMAT_ALL)
+					== TVEEPROM_TUNER_FORMAT_ALL) {
+		CX18_DEBUG_INFO("Worldwide tuner detected\n");
+		cx->std = V4L2_STD_ALL;
+	} else if (tv.tuner_formats & V4L2_STD_PAL) {
+		CX18_DEBUG_INFO("PAL tuner detected\n");
+		cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
+	} else if (tv.tuner_formats & V4L2_STD_NTSC) {
+		CX18_DEBUG_INFO("NTSC tuner detected\n");
+		cx->std |= V4L2_STD_NTSC_M;
+	} else if (tv.tuner_formats & V4L2_STD_SECAM) {
+		CX18_DEBUG_INFO("SECAM tuner detected\n");
+		cx->std |= V4L2_STD_SECAM_L;
+	} else {
+		CX18_INFO("No tuner detected, default to NTSC-M\n");
+		cx->std |= V4L2_STD_NTSC_M;
+	}
+}
+
+static v4l2_std_id cx18_parse_std(struct cx18 *cx)
+{
+	switch (pal[0]) {
+	case '6':
+		return V4L2_STD_PAL_60;
+	case 'b':
+	case 'B':
+	case 'g':
+	case 'G':
+		return V4L2_STD_PAL_BG;
+	case 'h':
+	case 'H':
+		return V4L2_STD_PAL_H;
+	case 'n':
+	case 'N':
+		if (pal[1] == 'c' || pal[1] == 'C')
+			return V4L2_STD_PAL_Nc;
+		return V4L2_STD_PAL_N;
+	case 'i':
+	case 'I':
+		return V4L2_STD_PAL_I;
+	case 'd':
+	case 'D':
+	case 'k':
+	case 'K':
+		return V4L2_STD_PAL_DK;
+	case 'M':
+	case 'm':
+		return V4L2_STD_PAL_M;
+	case '-':
+		break;
+	default:
+		CX18_WARN("pal= argument not recognised\n");
+		return 0;
+	}
+
+	switch (secam[0]) {
+	case 'b':
+	case 'B':
+	case 'g':
+	case 'G':
+	case 'h':
+	case 'H':
+		return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
+	case 'd':
+	case 'D':
+	case 'k':
+	case 'K':
+		return V4L2_STD_SECAM_DK;
+	case 'l':
+	case 'L':
+		if (secam[1] == 'C' || secam[1] == 'c')
+			return V4L2_STD_SECAM_LC;
+		return V4L2_STD_SECAM_L;
+	case '-':
+		break;
+	default:
+		CX18_WARN("secam= argument not recognised\n");
+		return 0;
+	}
+
+	switch (ntsc[0]) {
+	case 'm':
+	case 'M':
+		return V4L2_STD_NTSC_M;
+	case 'j':
+	case 'J':
+		return V4L2_STD_NTSC_M_JP;
+	case 'k':
+	case 'K':
+		return V4L2_STD_NTSC_M_KR;
+	case '-':
+		break;
+	default:
+		CX18_WARN("ntsc= argument not recognised\n");
+		return 0;
+	}
+
+	/* no match found */
+	return 0;
+}
+
+static void cx18_process_options(struct cx18 *cx)
+{
+	int i, j;
+
+	cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers;
+	cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
+	cx->options.megabytes[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_buffers;
+	cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers;
+	cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers;
+	cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
+	cx->options.megabytes[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control only */
+
+	cx->stream_buffers[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufs;
+	cx->stream_buffers[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufs;
+	cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufs;
+	cx->stream_buffers[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufs;
+	cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_bufs;
+	cx->stream_buffers[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufs;
+	cx->stream_buffers[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control, no data */
+
+	cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufsize;
+	cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize;
+	cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize;
+	cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize;
+	cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_active_samples * 36;
+	cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize;
+	cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */
+
+	/* Ensure stream_buffers & stream_buf_size are valid */
+	for (i = 0; i < CX18_MAX_STREAMS; i++) {
+		if (cx->stream_buffers[i] == 0 ||     /* User said 0 buffers */
+		    cx->options.megabytes[i] <= 0 ||  /* User said 0 MB total */
+		    cx->stream_buf_size[i] <= 0) {    /* User said buf size 0 */
+			cx->options.megabytes[i] = 0;
+			cx->stream_buffers[i] = 0;
+			cx->stream_buf_size[i] = 0;
+			continue;
+		}
+		/*
+		 * YUV is a special case where the stream_buf_size needs to be
+		 * an integral multiple of 33.75 kB (storage for 32 screens
+		 * lines to maintain alignment in case of lost buffers).
+		 *
+		 * IDX is a special case where the stream_buf_size should be
+		 * an integral multiple of 1.5 kB (storage for 64 index entries
+		 * to maintain alignment in case of lost buffers).
+		 *
+		 */
+		if (i == CX18_ENC_STREAM_TYPE_YUV) {
+			cx->stream_buf_size[i] *= 1024;
+			cx->stream_buf_size[i] -=
+			   (cx->stream_buf_size[i] % CX18_UNIT_ENC_YUV_BUFSIZE);
+
+			if (cx->stream_buf_size[i] < CX18_UNIT_ENC_YUV_BUFSIZE)
+				cx->stream_buf_size[i] =
+						CX18_UNIT_ENC_YUV_BUFSIZE;
+		} else if (i == CX18_ENC_STREAM_TYPE_IDX) {
+			cx->stream_buf_size[i] *= 1024;
+			cx->stream_buf_size[i] -=
+			   (cx->stream_buf_size[i] % CX18_UNIT_ENC_IDX_BUFSIZE);
+
+			if (cx->stream_buf_size[i] < CX18_UNIT_ENC_IDX_BUFSIZE)
+				cx->stream_buf_size[i] =
+						CX18_UNIT_ENC_IDX_BUFSIZE;
+		}
+		/*
+		 * YUV and IDX are special cases where the stream_buf_size is
+		 * now in bytes.
+		 * VBI is a special case where the stream_buf_size is fixed
+		 * and already in bytes
+		 */
+		if (i == CX18_ENC_STREAM_TYPE_VBI ||
+		    i == CX18_ENC_STREAM_TYPE_YUV ||
+		    i == CX18_ENC_STREAM_TYPE_IDX) {
+			if (cx->stream_buffers[i] < 0) {
+				cx->stream_buffers[i] =
+					cx->options.megabytes[i] * 1024 * 1024
+					/ cx->stream_buf_size[i];
+			} else {
+				/* N.B. This might round down to 0 */
+				cx->options.megabytes[i] =
+					cx->stream_buffers[i]
+					* cx->stream_buf_size[i]/(1024 * 1024);
+			}
+		} else {
+			/* All other streams have stream_buf_size in kB here */
+			if (cx->stream_buffers[i] < 0) {
+				cx->stream_buffers[i] =
+						cx->options.megabytes[i] * 1024
+						/ cx->stream_buf_size[i];
+			} else {
+				/* N.B. This might round down to 0 */
+				cx->options.megabytes[i] =
+						cx->stream_buffers[i]
+						* cx->stream_buf_size[i] / 1024;
+			}
+			/* convert from kB to bytes */
+			cx->stream_buf_size[i] *= 1024;
+		}
+		CX18_DEBUG_INFO("Stream type %d options: %d MB, %d buffers, "
+				"%d bytes\n", i, cx->options.megabytes[i],
+				cx->stream_buffers[i], cx->stream_buf_size[i]);
+	}
+
+	cx->options.cardtype = cardtype[cx->instance];
+	cx->options.tuner = tuner[cx->instance];
+	cx->options.radio = radio[cx->instance];
+
+	cx->std = cx18_parse_std(cx);
+	if (cx->options.cardtype == -1) {
+		CX18_INFO("Ignore card\n");
+		return;
+	}
+	cx->card = cx18_get_card(cx->options.cardtype - 1);
+	if (cx->card)
+		CX18_INFO("User specified %s card\n", cx->card->name);
+	else if (cx->options.cardtype != 0)
+		CX18_ERR("Unknown user specified type, trying to autodetect card\n");
+	if (cx->card == NULL) {
+		if (cx->pci_dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) {
+			cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+			CX18_INFO("Autodetected Hauppauge card\n");
+		}
+	}
+	if (cx->card == NULL) {
+		for (i = 0; (cx->card = cx18_get_card(i)); i++) {
+			if (cx->card->pci_list == NULL)
+				continue;
+			for (j = 0; cx->card->pci_list[j].device; j++) {
+				if (cx->pci_dev->device !=
+				    cx->card->pci_list[j].device)
+					continue;
+				if (cx->pci_dev->subsystem_vendor !=
+				    cx->card->pci_list[j].subsystem_vendor)
+					continue;
+				if (cx->pci_dev->subsystem_device !=
+				    cx->card->pci_list[j].subsystem_device)
+					continue;
+				CX18_INFO("Autodetected %s card\n", cx->card->name);
+				goto done;
+			}
+		}
+	}
+done:
+
+	if (cx->card == NULL) {
+		cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+		CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n",
+			 cx->pci_dev->vendor, cx->pci_dev->device);
+		CX18_ERR("              subsystem vendor/device: [%04x:%04x]\n",
+			 cx->pci_dev->subsystem_vendor,
+			 cx->pci_dev->subsystem_device);
+		CX18_ERR("Defaulting to %s card\n", cx->card->name);
+		CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
+		CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n");
+		CX18_ERR("Prefix your subject line with [UNKNOWN CX18 CARD].\n");
+	}
+	cx->v4l2_cap = cx->card->v4l2_capabilities;
+	cx->card_name = cx->card->name;
+	cx->card_i2c = cx->card->i2c;
+}
+
+static int __devinit cx18_create_in_workq(struct cx18 *cx)
+{
+	snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in",
+		 cx->v4l2_dev.name);
+	cx->in_work_queue = alloc_ordered_workqueue(cx->in_workq_name, 0);
+	if (cx->in_work_queue == NULL) {
+		CX18_ERR("Unable to create incoming mailbox handler thread\n");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void __devinit cx18_init_in_work_orders(struct cx18 *cx)
+{
+	int i;
+	for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) {
+		cx->in_work_order[i].cx = cx;
+		cx->in_work_order[i].str = cx->epu_debug_str;
+		INIT_WORK(&cx->in_work_order[i].work, cx18_in_work_handler);
+	}
+}
+
+/* Precondition: the cx18 structure has been memset to 0. Only
+   the dev and instance fields have been filled in.
+   No assumptions on the card type may be made here (see cx18_init_struct2
+   for that).
+ */
+static int __devinit cx18_init_struct1(struct cx18 *cx)
+{
+	int ret;
+
+	cx->base_addr = pci_resource_start(cx->pci_dev, 0);
+
+	mutex_init(&cx->serialize_lock);
+	mutex_init(&cx->gpio_lock);
+	mutex_init(&cx->epu2apu_mb_lock);
+	mutex_init(&cx->epu2cpu_mb_lock);
+
+	ret = cx18_create_in_workq(cx);
+	if (ret)
+		return ret;
+
+	cx18_init_in_work_orders(cx);
+
+	/* start counting open_id at 1 */
+	cx->open_id = 1;
+
+	/* Initial settings */
+	cx->cxhdl.port = CX2341X_PORT_MEMORY;
+	cx->cxhdl.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI;
+	cx->cxhdl.ops = &cx18_cxhdl_ops;
+	cx->cxhdl.func = cx18_api_func;
+	cx->cxhdl.priv = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
+	ret = cx2341x_handler_init(&cx->cxhdl, 50);
+	if (ret)
+		return ret;
+	cx->v4l2_dev.ctrl_handler = &cx->cxhdl.hdl;
+
+	cx->temporal_strength = cx->cxhdl.video_temporal_filter->cur.val;
+	cx->spatial_strength = cx->cxhdl.video_spatial_filter->cur.val;
+	cx->filter_mode = cx->cxhdl.video_spatial_filter_mode->cur.val |
+		(cx->cxhdl.video_temporal_filter_mode->cur.val << 1) |
+		(cx->cxhdl.video_median_filter_type->cur.val << 2);
+
+	init_waitqueue_head(&cx->cap_w);
+	init_waitqueue_head(&cx->mb_apu_waitq);
+	init_waitqueue_head(&cx->mb_cpu_waitq);
+	init_waitqueue_head(&cx->dma_waitq);
+
+	/* VBI */
+	cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
+	cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced;
+
+	/* IVTV style VBI insertion into MPEG streams */
+	INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_buf.list);
+	INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.list);
+	INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.buf_list);
+	list_add(&cx->vbi.sliced_mpeg_buf.list,
+		 &cx->vbi.sliced_mpeg_mdl.buf_list);
+	return 0;
+}
+
+/* Second initialization part. Here the card type has been
+   autodetected. */
+static void __devinit cx18_init_struct2(struct cx18 *cx)
+{
+	int i;
+
+	for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS; i++)
+		if (cx->card->video_inputs[i].video_type == 0)
+			break;
+	cx->nof_inputs = i;
+	for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS; i++)
+		if (cx->card->audio_inputs[i].audio_type == 0)
+			break;
+	cx->nof_audio_inputs = i;
+
+	/* Find tuner input */
+	for (i = 0; i < cx->nof_inputs; i++) {
+		if (cx->card->video_inputs[i].video_type ==
+				CX18_CARD_INPUT_VID_TUNER)
+			break;
+	}
+	if (i == cx->nof_inputs)
+		i = 0;
+	cx->active_input = i;
+	cx->audio_input = cx->card->video_inputs[i].audio_index;
+}
+
+static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
+			  const struct pci_device_id *pci_id)
+{
+	u16 cmd;
+	unsigned char pci_latency;
+
+	CX18_DEBUG_INFO("Enabling pci device\n");
+
+	if (pci_enable_device(pci_dev)) {
+		CX18_ERR("Can't enable device %d!\n", cx->instance);
+		return -EIO;
+	}
+	if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32))) {
+		CX18_ERR("No suitable DMA available, card %d\n", cx->instance);
+		return -EIO;
+	}
+	if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) {
+		CX18_ERR("Cannot request encoder memory region, card %d\n",
+			 cx->instance);
+		return -EIO;
+	}
+
+	/* Enable bus mastering and memory mapped IO for the CX23418 */
+	pci_read_config_word(pci_dev, PCI_COMMAND, &cmd);
+	cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+	pci_write_config_word(pci_dev, PCI_COMMAND, cmd);
+
+	cx->card_rev = pci_dev->revision;
+	pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency);
+
+	if (pci_latency < 64 && cx18_pci_latency) {
+		CX18_INFO("Unreasonably low latency timer, "
+			       "setting to 64 (was %d)\n", pci_latency);
+		pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, 64);
+		pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency);
+	}
+
+	CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, "
+		   "irq: %d, latency: %d, memory: 0x%llx\n",
+		   cx->pci_dev->device, cx->card_rev, pci_dev->bus->number,
+		   PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn),
+		   cx->pci_dev->irq, pci_latency, (u64)cx->base_addr);
+
+	return 0;
+}
+
+static void cx18_init_subdevs(struct cx18 *cx)
+{
+	u32 hw = cx->card->hw_all;
+	u32 device;
+	int i;
+
+	for (i = 0, device = 1; i < 32; i++, device <<= 1) {
+
+		if (!(device & hw))
+			continue;
+
+		switch (device) {
+		case CX18_HW_DVB:
+		case CX18_HW_TVEEPROM:
+			/* These subordinate devices do not use probing */
+			cx->hw_flags |= device;
+			break;
+		case CX18_HW_418_AV:
+			/* The A/V decoder gets probed earlier to set PLLs */
+			/* Just note that the card uses it (i.e. has analog) */
+			cx->hw_flags |= device;
+			break;
+		case CX18_HW_GPIO_RESET_CTRL:
+			/*
+			 * The Reset Controller gets probed and added to
+			 * hw_flags earlier for i2c adapter/bus initialization
+			 */
+			break;
+		case CX18_HW_GPIO_MUX:
+			if (cx18_gpio_register(cx, device) == 0)
+				cx->hw_flags |= device;
+			break;
+		default:
+			if (cx18_i2c_register(cx, i) == 0)
+				cx->hw_flags |= device;
+			break;
+		}
+	}
+
+	if (cx->hw_flags & CX18_HW_418_AV)
+		cx->sd_av = cx18_find_hw(cx, CX18_HW_418_AV);
+
+	if (cx->card->hw_muxer != 0)
+		cx->sd_extmux = cx18_find_hw(cx, cx->card->hw_muxer);
+}
+
+static int __devinit cx18_probe(struct pci_dev *pci_dev,
+				const struct pci_device_id *pci_id)
+{
+	int retval = 0;
+	int i;
+	u32 devtype;
+	struct cx18 *cx;
+
+	/* FIXME - module parameter arrays constrain max instances */
+	i = atomic_inc_return(&cx18_instance) - 1;
+	if (i >= CX18_MAX_CARDS) {
+		printk(KERN_ERR "cx18: cannot manage card %d, driver has a "
+		       "limit of 0 - %d\n", i, CX18_MAX_CARDS - 1);
+		return -ENOMEM;
+	}
+
+	cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC);
+	if (cx == NULL) {
+		printk(KERN_ERR "cx18: cannot manage card %d, out of memory\n",
+		       i);
+		return -ENOMEM;
+	}
+	cx->pci_dev = pci_dev;
+	cx->instance = i;
+
+	retval = v4l2_device_register(&pci_dev->dev, &cx->v4l2_dev);
+	if (retval) {
+		printk(KERN_ERR "cx18: v4l2_device_register of card %d failed"
+		       "\n", cx->instance);
+		kfree(cx);
+		return retval;
+	}
+	snprintf(cx->v4l2_dev.name, sizeof(cx->v4l2_dev.name), "cx18-%d",
+		 cx->instance);
+	CX18_INFO("Initializing card %d\n", cx->instance);
+
+	cx18_process_options(cx);
+	if (cx->options.cardtype == -1) {
+		retval = -ENODEV;
+		goto err;
+	}
+
+	retval = cx18_init_struct1(cx);
+	if (retval)
+		goto err;
+
+	CX18_DEBUG_INFO("base addr: 0x%llx\n", (u64)cx->base_addr);
+
+	/* PCI Device Setup */
+	retval = cx18_setup_pci(cx, pci_dev, pci_id);
+	if (retval != 0)
+		goto free_workqueues;
+
+	/* map io memory */
+	CX18_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n",
+		   (u64)cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE);
+	cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET,
+				       CX18_MEM_SIZE);
+	if (!cx->enc_mem) {
+		CX18_ERR("ioremap failed. Can't get a window into CX23418 "
+			 "memory and register space\n");
+		CX18_ERR("Each capture card with a CX23418 needs 64 MB of "
+			 "vmalloc address space for the window\n");
+		CX18_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
+		CX18_ERR("Use the vmalloc= kernel command line option to set "
+			 "VmallocTotal to a larger value\n");
+		retval = -ENOMEM;
+		goto free_mem;
+	}
+	cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET;
+	devtype = cx18_read_reg(cx, 0xC72028);
+	switch (devtype & 0xff000000) {
+	case 0xff000000:
+		CX18_INFO("cx23418 revision %08x (A)\n", devtype);
+		break;
+	case 0x01000000:
+		CX18_INFO("cx23418 revision %08x (B)\n", devtype);
+		break;
+	default:
+		CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype);
+		break;
+	}
+
+	cx18_init_power(cx, 1);
+	cx18_init_memory(cx);
+
+	cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET);
+	cx18_init_scb(cx);
+
+	cx18_gpio_init(cx);
+
+	/* Initialize integrated A/V decoder early to set PLLs, just in case */
+	retval = cx18_av_probe(cx);
+	if (retval) {
+		CX18_ERR("Could not register A/V decoder subdevice\n");
+		goto free_map;
+	}
+
+	/* Initialize GPIO Reset Controller to do chip resets during i2c init */
+	if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) {
+		if (cx18_gpio_register(cx, CX18_HW_GPIO_RESET_CTRL) != 0)
+			CX18_WARN("Could not register GPIO reset controller"
+				  "subdevice; proceeding anyway.\n");
+		else
+			cx->hw_flags |= CX18_HW_GPIO_RESET_CTRL;
+	}
+
+	/* active i2c  */
+	CX18_DEBUG_INFO("activating i2c...\n");
+	retval = init_cx18_i2c(cx);
+	if (retval) {
+		CX18_ERR("Could not initialize i2c\n");
+		goto free_map;
+	}
+
+	if (cx->card->hw_all & CX18_HW_TVEEPROM) {
+		/* Based on the model number the cardtype may be changed.
+		   The PCI IDs are not always reliable. */
+		const struct cx18_card *orig_card = cx->card;
+		cx18_process_eeprom(cx);
+
+		if (cx->card != orig_card) {
+			/* Changed the cardtype; re-reset the I2C chips */
+			cx18_gpio_init(cx);
+			cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL,
+					core, reset, (u32) CX18_GPIO_RESET_I2C);
+		}
+	}
+	if (cx->card->comment)
+		CX18_INFO("%s", cx->card->comment);
+	if (cx->card->v4l2_capabilities == 0) {
+		retval = -ENODEV;
+		goto free_i2c;
+	}
+	cx18_init_memory(cx);
+	cx18_init_scb(cx);
+
+	/* Register IRQ */
+	retval = request_irq(cx->pci_dev->irq, cx18_irq_handler,
+			     IRQF_SHARED | IRQF_DISABLED,
+			     cx->v4l2_dev.name, (void *)cx);
+	if (retval) {
+		CX18_ERR("Failed to register irq %d\n", retval);
+		goto free_i2c;
+	}
+
+	if (cx->std == 0)
+		cx->std = V4L2_STD_NTSC_M;
+
+	if (cx->options.tuner == -1) {
+		for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) {
+			if ((cx->std & cx->card->tuners[i].std) == 0)
+				continue;
+			cx->options.tuner = cx->card->tuners[i].tuner;
+			break;
+		}
+	}
+	/* if no tuner was found, then pick the first tuner in the card list */
+	if (cx->options.tuner == -1 && cx->card->tuners[0].std) {
+		cx->std = cx->card->tuners[0].std;
+		if (cx->std & V4L2_STD_PAL)
+			cx->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
+		else if (cx->std & V4L2_STD_NTSC)
+			cx->std = V4L2_STD_NTSC_M;
+		else if (cx->std & V4L2_STD_SECAM)
+			cx->std = V4L2_STD_SECAM_L;
+		cx->options.tuner = cx->card->tuners[0].tuner;
+	}
+	if (cx->options.radio == -1)
+		cx->options.radio = (cx->card->radio_input.audio_type != 0);
+
+	/* The card is now fully identified, continue with card-specific
+	   initialization. */
+	cx18_init_struct2(cx);
+
+	cx18_init_subdevs(cx);
+
+	if (cx->std & V4L2_STD_525_60)
+		cx->is_60hz = 1;
+	else
+		cx->is_50hz = 1;
+
+	cx2341x_handler_set_50hz(&cx->cxhdl, !cx->is_60hz);
+
+	if (cx->options.radio > 0)
+		cx->v4l2_cap |= V4L2_CAP_RADIO;
+
+	if (cx->options.tuner > -1) {
+		struct tuner_setup setup;
+
+		setup.addr = ADDR_UNSET;
+		setup.type = cx->options.tuner;
+		setup.mode_mask = T_ANALOG_TV;  /* matches TV tuners */
+		if (cx->options.radio > 0)
+			setup.mode_mask |= T_RADIO;
+		setup.tuner_callback = (setup.type == TUNER_XC2028) ?
+			cx18_reset_tuner_gpio : NULL;
+		cx18_call_all(cx, tuner, s_type_addr, &setup);
+		if (setup.type == TUNER_XC2028) {
+			static struct xc2028_ctrl ctrl = {
+				.fname = XC2028_DEFAULT_FIRMWARE,
+				.max_len = 64,
+			};
+			struct v4l2_priv_tun_config cfg = {
+				.tuner = cx->options.tuner,
+				.priv = &ctrl,
+			};
+			cx18_call_all(cx, tuner, s_config, &cfg);
+		}
+	}
+
+	/* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
+	   are not. */
+	cx->tuner_std = cx->std;
+	if (cx->std == V4L2_STD_ALL)
+		cx->std = V4L2_STD_NTSC_M;
+
+	retval = cx18_streams_setup(cx);
+	if (retval) {
+		CX18_ERR("Error %d setting up streams\n", retval);
+		goto free_irq;
+	}
+	retval = cx18_streams_register(cx);
+	if (retval) {
+		CX18_ERR("Error %d registering devices\n", retval);
+		goto free_streams;
+	}
+
+	CX18_INFO("Initialized card: %s\n", cx->card_name);
+
+	/* Load cx18 submodules (cx18-alsa) */
+	request_modules(cx);
+	return 0;
+
+free_streams:
+	cx18_streams_cleanup(cx, 1);
+free_irq:
+	free_irq(cx->pci_dev->irq, (void *)cx);
+free_i2c:
+	exit_cx18_i2c(cx);
+free_map:
+	cx18_iounmap(cx);
+free_mem:
+	release_mem_region(cx->base_addr, CX18_MEM_SIZE);
+free_workqueues:
+	destroy_workqueue(cx->in_work_queue);
+err:
+	if (retval == 0)
+		retval = -ENODEV;
+	CX18_ERR("Error %d on initialization\n", retval);
+
+	v4l2_device_unregister(&cx->v4l2_dev);
+	kfree(cx);
+	return retval;
+}
+
+int cx18_init_on_first_open(struct cx18 *cx)
+{
+	int video_input;
+	int fw_retry_count = 3;
+	struct v4l2_frequency vf;
+	struct cx18_open_id fh;
+	v4l2_std_id std;
+
+	fh.cx = cx;
+
+	if (test_bit(CX18_F_I_FAILED, &cx->i_flags))
+		return -ENXIO;
+
+	if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags))
+		return 0;
+
+	while (--fw_retry_count > 0) {
+		/* load firmware */
+		if (cx18_firmware_init(cx) == 0)
+			break;
+		if (fw_retry_count > 1)
+			CX18_WARN("Retry loading firmware\n");
+	}
+
+	if (fw_retry_count == 0) {
+		set_bit(CX18_F_I_FAILED, &cx->i_flags);
+		return -ENXIO;
+	}
+	set_bit(CX18_F_I_LOADED_FW, &cx->i_flags);
+
+	/*
+	 * Init the firmware twice to work around a silicon bug
+	 * with the digital TS.
+	 *
+	 * The second firmware load requires us to normalize the APU state,
+	 * or the audio for the first analog capture will be badly incorrect.
+	 *
+	 * I can't seem to call APU_RESETAI and have it succeed without the
+	 * APU capturing audio, so we start and stop it here to do the reset
+	 */
+
+	/* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */
+	cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0);
+	cx18_vapi(cx, CX18_APU_RESETAI, 0);
+	cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG);
+
+	fw_retry_count = 3;
+	while (--fw_retry_count > 0) {
+		/* load firmware */
+		if (cx18_firmware_init(cx) == 0)
+			break;
+		if (fw_retry_count > 1)
+			CX18_WARN("Retry loading firmware\n");
+	}
+
+	if (fw_retry_count == 0) {
+		set_bit(CX18_F_I_FAILED, &cx->i_flags);
+		return -ENXIO;
+	}
+
+	/*
+	 * The second firmware load requires us to normalize the APU state,
+	 * or the audio for the first analog capture will be badly incorrect.
+	 *
+	 * I can't seem to call APU_RESETAI and have it succeed without the
+	 * APU capturing audio, so we start and stop it here to do the reset
+	 */
+
+	/* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */
+	cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0);
+	cx18_vapi(cx, CX18_APU_RESETAI, 0);
+	cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG);
+
+	/* Init the A/V decoder, if it hasn't been already */
+	v4l2_subdev_call(cx->sd_av, core, load_fw);
+
+	vf.tuner = 0;
+	vf.type = V4L2_TUNER_ANALOG_TV;
+	vf.frequency = 6400; /* the tuner 'baseline' frequency */
+
+	/* Set initial frequency. For PAL/SECAM broadcasts no
+	   'default' channel exists AFAIK. */
+	if (cx->std == V4L2_STD_NTSC_M_JP)
+		vf.frequency = 1460;	/* ch. 1 91250*16/1000 */
+	else if (cx->std & V4L2_STD_NTSC_M)
+		vf.frequency = 1076;	/* ch. 4 67250*16/1000 */
+
+	video_input = cx->active_input;
+	cx->active_input++;	/* Force update of input */
+	cx18_s_input(NULL, &fh, video_input);
+
+	/* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
+	   in one place. */
+	cx->std++;		/* Force full standard initialization */
+	std = (cx->tuner_std == V4L2_STD_ALL) ? V4L2_STD_NTSC_M : cx->tuner_std;
+	cx18_s_std(NULL, &fh, &std);
+	cx18_s_frequency(NULL, &fh, &vf);
+	return 0;
+}
+
+static void cx18_cancel_in_work_orders(struct cx18 *cx)
+{
+	int i;
+	for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++)
+		cancel_work_sync(&cx->in_work_order[i].work);
+}
+
+static void cx18_cancel_out_work_orders(struct cx18 *cx)
+{
+	int i;
+	for (i = 0; i < CX18_MAX_STREAMS; i++)
+		if (&cx->streams[i].video_dev != NULL)
+			cancel_work_sync(&cx->streams[i].out_work_order);
+}
+
+static void cx18_remove(struct pci_dev *pci_dev)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+	struct cx18 *cx = to_cx18(v4l2_dev);
+	int i;
+
+	CX18_DEBUG_INFO("Removing Card\n");
+
+	flush_request_modules(cx);
+
+	/* Stop all captures */
+	CX18_DEBUG_INFO("Stopping all streams\n");
+	if (atomic_read(&cx->tot_capturing) > 0)
+		cx18_stop_all_captures(cx);
+
+	/* Stop interrupts that cause incoming work to be queued */
+	cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+
+	/* Incoming work can cause outgoing work, so clean up incoming first */
+	cx18_cancel_in_work_orders(cx);
+	cx18_cancel_out_work_orders(cx);
+
+	/* Stop ack interrupts that may have been needed for work to finish */
+	cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+
+	cx18_halt_firmware(cx);
+
+	destroy_workqueue(cx->in_work_queue);
+
+	cx18_streams_cleanup(cx, 1);
+
+	exit_cx18_i2c(cx);
+
+	free_irq(cx->pci_dev->irq, (void *)cx);
+
+	cx18_iounmap(cx);
+
+	release_mem_region(cx->base_addr, CX18_MEM_SIZE);
+
+	pci_disable_device(cx->pci_dev);
+
+	if (cx->vbi.sliced_mpeg_data[0] != NULL)
+		for (i = 0; i < CX18_VBI_FRAMES; i++)
+			kfree(cx->vbi.sliced_mpeg_data[i]);
+
+	v4l2_ctrl_handler_free(&cx->av_state.hdl);
+
+	CX18_INFO("Removed %s\n", cx->card_name);
+
+	v4l2_device_unregister(v4l2_dev);
+	kfree(cx);
+}
+
+
+/* define a pci_driver for card detection */
+static struct pci_driver cx18_pci_driver = {
+      .name =     "cx18",
+      .id_table = cx18_pci_tbl,
+      .probe =    cx18_probe,
+      .remove =   cx18_remove,
+};
+
+static int __init module_start(void)
+{
+	printk(KERN_INFO "cx18:  Start initialization, version %s\n",
+	       CX18_VERSION);
+
+	/* Validate parameters */
+	if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) {
+		printk(KERN_ERR "cx18:  Exiting, cx18_first_minor must be between 0 and %d\n",
+		     CX18_MAX_CARDS - 1);
+		return -1;
+	}
+
+	if (cx18_debug < 0 || cx18_debug > 511) {
+		cx18_debug = 0;
+		printk(KERN_INFO "cx18:   Debug value must be >= 0 and <= 511!\n");
+	}
+
+	if (pci_register_driver(&cx18_pci_driver)) {
+		printk(KERN_ERR "cx18:   Error detecting PCI card\n");
+		return -ENODEV;
+	}
+	printk(KERN_INFO "cx18:  End initialization\n");
+	return 0;
+}
+
+static void __exit module_cleanup(void)
+{
+	pci_unregister_driver(&cx18_pci_driver);
+}
+
+module_init(module_start);
+module_exit(module_cleanup);
+MODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE);
diff --git a/drivers/media/pci/cx18/cx18-driver.h b/drivers/media/pci/cx18/cx18-driver.h
new file mode 100644
index 0000000..2767c64
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-driver.h
@@ -0,0 +1,730 @@
+/*
+ *  cx18 driver internal defines and structures
+ *
+ *  Derived from ivtv-driver.h
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#ifndef CX18_DRIVER_H
+#define CX18_DRIVER_H
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/list.h>
+#include <linux/unistd.h>
+#include <linux/pagemap.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <asm/byteorder.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/tuner.h>
+#include <media/ir-kbd-i2c.h>
+#include "cx18-mailbox.h"
+#include "cx18-av-core.h"
+#include "cx23418.h"
+
+/* DVB */
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+
+/* Videobuf / YUV support */
+#include <media/videobuf-core.h>
+#include <media/videobuf-vmalloc.h>
+
+#ifndef CONFIG_PCI
+#  error "This driver requires kernel PCI support."
+#endif
+
+#define CX18_MEM_OFFSET	0x00000000
+#define CX18_MEM_SIZE	0x04000000
+#define CX18_REG_OFFSET	0x02000000
+
+/* Maximum cx18 driver instances. */
+#define CX18_MAX_CARDS 32
+
+/* Supported cards */
+#define CX18_CARD_HVR_1600_ESMT	      0	/* Hauppauge HVR 1600 (ESMT memory) */
+#define CX18_CARD_HVR_1600_SAMSUNG    1	/* Hauppauge HVR 1600 (Samsung memory) */
+#define CX18_CARD_COMPRO_H900 	      2	/* Compro VideoMate H900 */
+#define CX18_CARD_YUAN_MPC718 	      3	/* Yuan MPC718 */
+#define CX18_CARD_CNXT_RAPTOR_PAL     4	/* Conexant Raptor PAL */
+#define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/
+#define CX18_CARD_LEADTEK_PVR2100     6 /* Leadtek WinFast PVR2100 */
+#define CX18_CARD_LEADTEK_DVR3100H    7 /* Leadtek WinFast DVR3100 H */
+#define CX18_CARD_GOTVIEW_PCI_DVD3    8 /* GoTView PCI DVD3 Hybrid */
+#define CX18_CARD_HVR_1600_S5H1411    9 /* Hauppauge HVR 1600 s5h1411/tda18271*/
+#define CX18_CARD_LAST		      9
+
+#define CX18_ENC_STREAM_TYPE_MPG  0
+#define CX18_ENC_STREAM_TYPE_TS   1
+#define CX18_ENC_STREAM_TYPE_YUV  2
+#define CX18_ENC_STREAM_TYPE_VBI  3
+#define CX18_ENC_STREAM_TYPE_PCM  4
+#define CX18_ENC_STREAM_TYPE_IDX  5
+#define CX18_ENC_STREAM_TYPE_RAD  6
+#define CX18_MAX_STREAMS	  7
+
+/* system vendor and device IDs */
+#define PCI_VENDOR_ID_CX      0x14f1
+#define PCI_DEVICE_ID_CX23418 0x5b7a
+
+/* subsystem vendor ID */
+#define CX18_PCI_ID_HAUPPAUGE 		0x0070
+#define CX18_PCI_ID_COMPRO 		0x185b
+#define CX18_PCI_ID_YUAN 		0x12ab
+#define CX18_PCI_ID_CONEXANT		0x14f1
+#define CX18_PCI_ID_TOSHIBA		0x1179
+#define CX18_PCI_ID_LEADTEK		0x107D
+#define CX18_PCI_ID_GOTVIEW		0x5854
+
+/* ======================================================================== */
+/* ========================== START USER SETTABLE DMA VARIABLES =========== */
+/* ======================================================================== */
+
+/* DMA Buffers, Default size in MB allocated */
+#define CX18_DEFAULT_ENC_TS_BUFFERS  1
+#define CX18_DEFAULT_ENC_MPG_BUFFERS 2
+#define CX18_DEFAULT_ENC_IDX_BUFFERS 1
+#define CX18_DEFAULT_ENC_YUV_BUFFERS 2
+#define CX18_DEFAULT_ENC_VBI_BUFFERS 1
+#define CX18_DEFAULT_ENC_PCM_BUFFERS 1
+
+/* Maximum firmware DMA buffers per stream */
+#define CX18_MAX_FW_MDLS_PER_STREAM 63
+
+/* YUV buffer sizes in bytes to ensure integer # of frames per buffer */
+#define CX18_UNIT_ENC_YUV_BUFSIZE	(720 *  32 * 3 / 2) /* bytes */
+#define CX18_625_LINE_ENC_YUV_BUFSIZE	(CX18_UNIT_ENC_YUV_BUFSIZE * 576/32)
+#define CX18_525_LINE_ENC_YUV_BUFSIZE	(CX18_UNIT_ENC_YUV_BUFSIZE * 480/32)
+
+/* IDX buffer size should be a multiple of the index entry size from the chip */
+struct cx18_enc_idx_entry {
+	__le32 length;
+	__le32 offset_low;
+	__le32 offset_high;
+	__le32 flags;
+	__le32 pts_low;
+	__le32 pts_high;
+} __attribute__ ((packed));
+#define CX18_UNIT_ENC_IDX_BUFSIZE \
+	(sizeof(struct cx18_enc_idx_entry) * V4L2_ENC_IDX_ENTRIES)
+
+/* DMA buffer, default size in kB allocated */
+#define CX18_DEFAULT_ENC_TS_BUFSIZE   32
+#define CX18_DEFAULT_ENC_MPG_BUFSIZE  32
+#define CX18_DEFAULT_ENC_IDX_BUFSIZE  (CX18_UNIT_ENC_IDX_BUFSIZE * 1 / 1024 + 1)
+#define CX18_DEFAULT_ENC_YUV_BUFSIZE  (CX18_UNIT_ENC_YUV_BUFSIZE * 3 / 1024 + 1)
+#define CX18_DEFAULT_ENC_PCM_BUFSIZE   4
+
+/* i2c stuff */
+#define I2C_CLIENTS_MAX 16
+
+/* debugging */
+
+/* Flag to turn on high volume debugging */
+#define CX18_DBGFLG_WARN  (1 << 0)
+#define CX18_DBGFLG_INFO  (1 << 1)
+#define CX18_DBGFLG_API   (1 << 2)
+#define CX18_DBGFLG_DMA   (1 << 3)
+#define CX18_DBGFLG_IOCTL (1 << 4)
+#define CX18_DBGFLG_FILE  (1 << 5)
+#define CX18_DBGFLG_I2C   (1 << 6)
+#define CX18_DBGFLG_IRQ   (1 << 7)
+/* Flag to turn on high volume debugging */
+#define CX18_DBGFLG_HIGHVOL (1 << 8)
+
+/* NOTE: extra space before comma in 'fmt , ## args' is required for
+   gcc-2.95, otherwise it won't compile. */
+#define CX18_DEBUG(x, type, fmt, args...) \
+	do { \
+		if ((x) & cx18_debug) \
+			v4l2_info(&cx->v4l2_dev, " " type ": " fmt , ## args); \
+	} while (0)
+#define CX18_DEBUG_WARN(fmt, args...)  CX18_DEBUG(CX18_DBGFLG_WARN, "warning", fmt , ## args)
+#define CX18_DEBUG_INFO(fmt, args...)  CX18_DEBUG(CX18_DBGFLG_INFO, "info", fmt , ## args)
+#define CX18_DEBUG_API(fmt, args...)   CX18_DEBUG(CX18_DBGFLG_API, "api", fmt , ## args)
+#define CX18_DEBUG_DMA(fmt, args...)   CX18_DEBUG(CX18_DBGFLG_DMA, "dma", fmt , ## args)
+#define CX18_DEBUG_IOCTL(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define CX18_DEBUG_FILE(fmt, args...)  CX18_DEBUG(CX18_DBGFLG_FILE, "file", fmt , ## args)
+#define CX18_DEBUG_I2C(fmt, args...)   CX18_DEBUG(CX18_DBGFLG_I2C, "i2c", fmt , ## args)
+#define CX18_DEBUG_IRQ(fmt, args...)   CX18_DEBUG(CX18_DBGFLG_IRQ, "irq", fmt , ## args)
+
+#define CX18_DEBUG_HIGH_VOL(x, type, fmt, args...) \
+	do { \
+		if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \
+			v4l2_info(&cx->v4l2_dev, " " type ": " fmt , ## args); \
+	} while (0)
+#define CX18_DEBUG_HI_WARN(fmt, args...)  CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_WARN, "warning", fmt , ## args)
+#define CX18_DEBUG_HI_INFO(fmt, args...)  CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_INFO, "info", fmt , ## args)
+#define CX18_DEBUG_HI_API(fmt, args...)   CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_API, "api", fmt , ## args)
+#define CX18_DEBUG_HI_DMA(fmt, args...)   CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_DMA, "dma", fmt , ## args)
+#define CX18_DEBUG_HI_IOCTL(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define CX18_DEBUG_HI_FILE(fmt, args...)  CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_FILE, "file", fmt , ## args)
+#define CX18_DEBUG_HI_I2C(fmt, args...)   CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_I2C, "i2c", fmt , ## args)
+#define CX18_DEBUG_HI_IRQ(fmt, args...)   CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IRQ, "irq", fmt , ## args)
+
+/* Standard kernel messages */
+#define CX18_ERR(fmt, args...)      v4l2_err(&cx->v4l2_dev, fmt , ## args)
+#define CX18_WARN(fmt, args...)     v4l2_warn(&cx->v4l2_dev, fmt , ## args)
+#define CX18_INFO(fmt, args...)     v4l2_info(&cx->v4l2_dev, fmt , ## args)
+
+/* Messages for internal subdevs to use */
+#define CX18_DEBUG_DEV(x, dev, type, fmt, args...) \
+	do { \
+		if ((x) & cx18_debug) \
+			v4l2_info(dev, " " type ": " fmt , ## args); \
+	} while (0)
+#define CX18_DEBUG_WARN_DEV(dev, fmt, args...) \
+		CX18_DEBUG_DEV(CX18_DBGFLG_WARN, dev, "warning", fmt , ## args)
+#define CX18_DEBUG_INFO_DEV(dev, fmt, args...) \
+		CX18_DEBUG_DEV(CX18_DBGFLG_INFO, dev, "info", fmt , ## args)
+#define CX18_DEBUG_API_DEV(dev, fmt, args...) \
+		CX18_DEBUG_DEV(CX18_DBGFLG_API, dev, "api", fmt , ## args)
+#define CX18_DEBUG_DMA_DEV(dev, fmt, args...) \
+		CX18_DEBUG_DEV(CX18_DBGFLG_DMA, dev, "dma", fmt , ## args)
+#define CX18_DEBUG_IOCTL_DEV(dev, fmt, args...) \
+		CX18_DEBUG_DEV(CX18_DBGFLG_IOCTL, dev, "ioctl", fmt , ## args)
+#define CX18_DEBUG_FILE_DEV(dev, fmt, args...) \
+		CX18_DEBUG_DEV(CX18_DBGFLG_FILE, dev, "file", fmt , ## args)
+#define CX18_DEBUG_I2C_DEV(dev, fmt, args...) \
+		CX18_DEBUG_DEV(CX18_DBGFLG_I2C, dev, "i2c", fmt , ## args)
+#define CX18_DEBUG_IRQ_DEV(dev, fmt, args...) \
+		CX18_DEBUG_DEV(CX18_DBGFLG_IRQ, dev, "irq", fmt , ## args)
+
+#define CX18_DEBUG_HIGH_VOL_DEV(x, dev, type, fmt, args...) \
+	do { \
+		if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \
+			v4l2_info(dev, " " type ": " fmt , ## args); \
+	} while (0)
+#define CX18_DEBUG_HI_WARN_DEV(dev, fmt, args...) \
+	CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_WARN, dev, "warning", fmt , ## args)
+#define CX18_DEBUG_HI_INFO_DEV(dev, fmt, args...) \
+	CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_INFO, dev, "info", fmt , ## args)
+#define CX18_DEBUG_HI_API_DEV(dev, fmt, args...) \
+	CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_API, dev, "api", fmt , ## args)
+#define CX18_DEBUG_HI_DMA_DEV(dev, fmt, args...) \
+	CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_DMA, dev, "dma", fmt , ## args)
+#define CX18_DEBUG_HI_IOCTL_DEV(dev, fmt, args...) \
+	CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_IOCTL, dev, "ioctl", fmt , ## args)
+#define CX18_DEBUG_HI_FILE_DEV(dev, fmt, args...) \
+	CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_FILE, dev, "file", fmt , ## args)
+#define CX18_DEBUG_HI_I2C_DEV(dev, fmt, args...) \
+	CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_I2C, dev, "i2c", fmt , ## args)
+#define CX18_DEBUG_HI_IRQ_DEV(dev, fmt, args...) \
+	CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_IRQ, dev, "irq", fmt , ## args)
+
+#define CX18_ERR_DEV(dev, fmt, args...)      v4l2_err(dev, fmt , ## args)
+#define CX18_WARN_DEV(dev, fmt, args...)     v4l2_warn(dev, fmt , ## args)
+#define CX18_INFO_DEV(dev, fmt, args...)     v4l2_info(dev, fmt , ## args)
+
+extern int cx18_debug;
+
+struct cx18_options {
+	int megabytes[CX18_MAX_STREAMS]; /* Size in megabytes of each stream */
+	int cardtype;		/* force card type on load */
+	int tuner;		/* set tuner on load */
+	int radio;		/* enable/disable radio */
+};
+
+/* per-mdl bit flags */
+#define CX18_F_M_NEED_SWAP  0	/* mdl buffer data must be endianess swapped */
+
+/* per-stream, s_flags */
+#define CX18_F_S_CLAIMED 	3	/* this stream is claimed */
+#define CX18_F_S_STREAMING      4	/* the fw is decoding/encoding this stream */
+#define CX18_F_S_INTERNAL_USE	5	/* this stream is used internally (sliced VBI processing) */
+#define CX18_F_S_STREAMOFF	7	/* signal end of stream EOS */
+#define CX18_F_S_APPL_IO        8	/* this stream is used read/written by an application */
+#define CX18_F_S_STOPPING	9	/* telling the fw to stop capturing */
+
+/* per-cx18, i_flags */
+#define CX18_F_I_LOADED_FW		0 	/* Loaded firmware 1st time */
+#define CX18_F_I_EOS			4 	/* End of encoder stream */
+#define CX18_F_I_RADIO_USER		5 	/* radio tuner is selected */
+#define CX18_F_I_ENC_PAUSED		13 	/* the encoder is paused */
+#define CX18_F_I_INITED			21 	/* set after first open */
+#define CX18_F_I_FAILED			22 	/* set if first open failed */
+
+/* These are the VBI types as they appear in the embedded VBI private packets. */
+#define CX18_SLICED_TYPE_TELETEXT_B     (1)
+#define CX18_SLICED_TYPE_CAPTION_525    (4)
+#define CX18_SLICED_TYPE_WSS_625        (5)
+#define CX18_SLICED_TYPE_VPS            (7)
+
+/**
+ * list_entry_is_past_end - check if a previous loop cursor is off list end
+ * @pos:	the type * previously used as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Check if the entry's list_head is the head of the list, thus it's not a
+ * real entry but was the loop cursor that walked past the end
+ */
+#define list_entry_is_past_end(pos, head, member) \
+	(&pos->member == (head))
+
+struct cx18_buffer {
+	struct list_head list;
+	dma_addr_t dma_handle;
+	char *buf;
+
+	u32 bytesused;
+	u32 readpos;
+};
+
+struct cx18_mdl {
+	struct list_head list;
+	u32 id;		/* index into cx->scb->cpu_mdl[] of 1st cx18_mdl_ent */
+
+	unsigned int skipped;
+	unsigned long m_flags;
+
+	struct list_head buf_list;
+	struct cx18_buffer *curr_buf; /* current buffer in list for reading */
+
+	u32 bytesused;
+	u32 readpos;
+};
+
+struct cx18_queue {
+	struct list_head list;
+	atomic_t depth;
+	u32 bytesused;
+	spinlock_t lock;
+};
+
+struct cx18_stream; /* forward reference */
+
+struct cx18_dvb {
+	struct cx18_stream *stream;
+	struct dmx_frontend hw_frontend;
+	struct dmx_frontend mem_frontend;
+	struct dmxdev dmxdev;
+	struct dvb_adapter dvb_adapter;
+	struct dvb_demux demux;
+	struct dvb_frontend *fe;
+	struct dvb_net dvbnet;
+	int enabled;
+	int feeding;
+	struct mutex feedlock;
+};
+
+struct cx18;	 /* forward reference */
+struct cx18_scb; /* forward reference */
+
+
+#define CX18_MAX_MDL_ACKS 2
+#define CX18_MAX_IN_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7)
+/* CPU_DE_RELEASE_MDL can burst CX18_MAX_FW_MDLS_PER_STREAM orders in a group */
+
+#define CX18_F_EWO_MB_STALE_UPON_RECEIPT 0x1
+#define CX18_F_EWO_MB_STALE_WHILE_PROC   0x2
+#define CX18_F_EWO_MB_STALE \
+	     (CX18_F_EWO_MB_STALE_UPON_RECEIPT | CX18_F_EWO_MB_STALE_WHILE_PROC)
+
+struct cx18_in_work_order {
+	struct work_struct work;
+	atomic_t pending;
+	struct cx18 *cx;
+	unsigned long flags;
+	int rpu;
+	struct cx18_mailbox mb;
+	struct cx18_mdl_ack mdl_ack[CX18_MAX_MDL_ACKS];
+	char *str;
+};
+
+#define CX18_INVALID_TASK_HANDLE 0xffffffff
+
+struct cx18_stream {
+	/* These first five fields are always set, even if the stream
+	   is not actually created. */
+	struct video_device *video_dev;	/* NULL when stream not created */
+	struct cx18_dvb *dvb;		/* DVB / Digital Transport */
+	struct cx18 *cx; 		/* for ease of use */
+	const char *name;		/* name of the stream */
+	int type;			/* stream type */
+	u32 handle;			/* task handle */
+	unsigned int mdl_base_idx;
+
+	u32 id;
+	unsigned long s_flags;	/* status flags, see above */
+	int dma;		/* can be PCI_DMA_TODEVICE,
+				   PCI_DMA_FROMDEVICE or
+				   PCI_DMA_NONE */
+	wait_queue_head_t waitq;
+
+	/* Buffers */
+	struct list_head buf_pool;	/* buffers not attached to an MDL */
+	u32 buffers;			/* total buffers owned by this stream */
+	u32 buf_size;			/* size in bytes of a single buffer */
+
+	/* MDL sizes - all stream MDLs are the same size */
+	u32 bufs_per_mdl;
+	u32 mdl_size;		/* total bytes in all buffers in a mdl */
+
+	/* MDL Queues */
+	struct cx18_queue q_free;	/* free - in rotation, not committed */
+	struct cx18_queue q_busy;	/* busy - in use by firmware */
+	struct cx18_queue q_full;	/* full - data for user apps */
+	struct cx18_queue q_idle;	/* idle - not in rotation */
+
+	struct work_struct out_work_order;
+
+	/* Videobuf for YUV video */
+	u32 pixelformat;
+	u32 vb_bytes_per_frame;
+	struct list_head vb_capture;    /* video capture queue */
+	spinlock_t vb_lock;
+	struct timer_list vb_timeout;
+
+	struct videobuf_queue vbuf_q;
+	spinlock_t vbuf_q_lock; /* Protect vbuf_q */
+	enum v4l2_buf_type vb_type;
+};
+
+struct cx18_videobuf_buffer {
+	/* Common video buffer sub-system struct */
+	struct videobuf_buffer vb;
+	v4l2_std_id tvnorm; /* selected tv norm */
+	u32 bytes_used;
+};
+
+struct cx18_open_id {
+	struct v4l2_fh fh;
+	u32 open_id;
+	int type;
+	struct cx18 *cx;
+};
+
+static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh)
+{
+	return container_of(fh, struct cx18_open_id, fh);
+}
+
+static inline struct cx18_open_id *file2id(struct file *file)
+{
+	return fh2id(file->private_data);
+}
+
+/* forward declaration of struct defined in cx18-cards.h */
+struct cx18_card;
+
+/*
+ * A note about "sliced" VBI data as implemented in this driver:
+ *
+ * Currently we collect the sliced VBI in the form of Ancillary Data
+ * packets, inserted by the AV core decoder/digitizer/slicer in the
+ * horizontal blanking region of the VBI lines, in "raw" mode as far as
+ * the Encoder is concerned.  We don't ever tell the Encoder itself
+ * to provide sliced VBI. (AV Core: sliced mode - Encoder: raw mode)
+ *
+ * We then process the ancillary data ourselves to send the sliced data
+ * to the user application directly or build up MPEG-2 private stream 1
+ * packets to splice into (only!) MPEG-2 PS streams for the user app.
+ *
+ * (That's how ivtv essentially does it.)
+ *
+ * The Encoder should be able to extract certain sliced VBI data for
+ * us and provide it in a separate stream or splice it into any type of
+ * MPEG PS or TS stream, but this isn't implemented yet.
+ */
+
+/*
+ * Number of "raw" VBI samples per horizontal line we tell the Encoder to
+ * grab from the decoder/digitizer/slicer output for raw or sliced VBI.
+ * It depends on the pixel clock and the horiz rate:
+ *
+ * (1/Fh)*(2*Fp) = Samples/line
+ *     = 4 bytes EAV + Anc data in hblank + 4 bytes SAV + active samples
+ *
+ *  Sliced VBI data is sent as ancillary data during horizontal blanking
+ *  Raw VBI is sent as active video samples during vertcal blanking
+ *
+ *  We use a  BT.656 pxiel clock of 13.5 MHz and a BT.656 active line
+ *  length of 720 pixels @ 4:2:2 sampling.  Thus...
+ *
+ *  For systems that use a 15.734 kHz horizontal rate, such as
+ *  NTSC-M, PAL-M, PAL-60, and other 60 Hz/525 line systems, we have:
+ *
+ *  (1/15.734 kHz) * 2 * 13.5 MHz = 1716 samples/line =
+ *  4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples
+ *
+ *  For systems that use a 15.625 kHz horizontal rate, such as
+ *  PAL-B/G/H, PAL-I, SECAM-L and other 50 Hz/625 line systems, we have:
+ *
+ *  (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line =
+ *  4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples
+ */
+static const u32 vbi_active_samples = 1444; /* 4 byte SAV + 720 Y + 720 U/V */
+static const u32 vbi_hblank_samples_60Hz = 272; /* 4 byte EAV + 268 anc/fill */
+static const u32 vbi_hblank_samples_50Hz = 284; /* 4 byte EAV + 280 anc/fill */
+
+#define CX18_VBI_FRAMES 32
+
+struct vbi_info {
+	/* Current state of v4l2 VBI settings for this device */
+	struct v4l2_format in;
+	struct v4l2_sliced_vbi_format *sliced_in; /* pointer to in.fmt.sliced */
+	u32 count;    /* Count of VBI data lines: 60 Hz: 12 or 50 Hz: 18 */
+	u32 start[2]; /* First VBI data line per field: 10 & 273 or 6 & 318 */
+
+	u32 frame; /* Count of VBI buffers/frames received from Encoder */
+
+	/*
+	 * Vars for creation and insertion of MPEG Private Stream 1 packets
+	 * of sliced VBI data into an MPEG PS
+	 */
+
+	/* Boolean: create and insert Private Stream 1 packets into the PS */
+	int insert_mpeg;
+
+	/*
+	 * Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
+	 * Used in cx18-vbi.c only for collecting sliced data, and as a source
+	 * during conversion of sliced VBI data into MPEG Priv Stream 1 packets.
+	 * We don't need to save state here, but the array may have been a bit
+	 * too big (2304 bytes) to alloc from the stack.
+	 */
+	struct v4l2_sliced_vbi_data sliced_data[36];
+
+	/*
+	 * A ring buffer of driver-generated MPEG-2 PS
+	 * Program Pack/Private Stream 1 packets for sliced VBI data insertion
+	 * into the MPEG PS stream.
+	 *
+	 * In each sliced_mpeg_data[] buffer is:
+	 * 	16 byte MPEG-2 PS Program Pack Header
+	 * 	16 byte MPEG-2 Private Stream 1 PES Header
+	 * 	 4 byte magic number: "itv0" or "ITV0"
+	 * 	 4 byte first  field line mask, if "itv0"
+	 * 	 4 byte second field line mask, if "itv0"
+	 * 	36 lines, if "ITV0"; or <36 lines, if "itv0"; of sliced VBI data
+	 *
+	 * 	Each line in the payload is
+	 *	 1 byte line header derived from the SDID (WSS, CC, VPS, etc.)
+	 *	42 bytes of line data
+	 *
+	 * That's a maximum 1552 bytes of payload in the Private Stream 1 packet
+	 * which is the payload size a PVR-350 (CX23415) MPEG decoder will
+	 * accept for VBI data. So, including the headers, it's a maximum 1584
+	 * bytes total.
+	 */
+#define CX18_SLICED_MPEG_DATA_MAXSZ	1584
+	/* copy_vbi_buf() needs 8 temp bytes on the end for the worst case */
+#define CX18_SLICED_MPEG_DATA_BUFSZ	(CX18_SLICED_MPEG_DATA_MAXSZ+8)
+	u8 *sliced_mpeg_data[CX18_VBI_FRAMES];
+	u32 sliced_mpeg_size[CX18_VBI_FRAMES];
+
+	/* Count of Program Pack/Program Stream 1 packets inserted into PS */
+	u32 inserted_frame;
+
+	/*
+	 * A dummy driver stream transfer mdl & buffer with a copy of the next
+	 * sliced_mpeg_data[] buffer for output to userland apps.
+	 * Only used in cx18-fileops.c, but its state needs to persist at times.
+	 */
+	struct cx18_mdl sliced_mpeg_mdl;
+	struct cx18_buffer sliced_mpeg_buf;
+};
+
+/* Per cx23418, per I2C bus private algo callback data */
+struct cx18_i2c_algo_callback_data {
+	struct cx18 *cx;
+	int bus_index;   /* 0 or 1 for the cx23418's 1st or 2nd I2C bus */
+};
+
+#define CX18_MAX_MMIO_WR_RETRIES 10
+
+/* Struct to hold info about cx18 cards */
+struct cx18 {
+	int instance;
+	struct pci_dev *pci_dev;
+	struct v4l2_device v4l2_dev;
+	struct v4l2_subdev *sd_av;     /* A/V decoder/digitizer sub-device */
+	struct v4l2_subdev *sd_extmux; /* External multiplexer sub-dev */
+
+	const struct cx18_card *card;	/* card information */
+	const char *card_name;  /* full name of the card */
+	const struct cx18_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */
+	u8 is_50hz;
+	u8 is_60hz;
+	u8 nof_inputs;		/* number of video inputs */
+	u8 nof_audio_inputs;	/* number of audio inputs */
+	u32 v4l2_cap;		/* V4L2 capabilities of card */
+	u32 hw_flags; 		/* Hardware description of the board */
+	unsigned int free_mdl_idx;
+	struct cx18_scb __iomem *scb; /* pointer to SCB */
+	struct mutex epu2apu_mb_lock; /* protect driver to chip mailbox in SCB*/
+	struct mutex epu2cpu_mb_lock; /* protect driver to chip mailbox in SCB*/
+
+	struct cx18_av_state av_state;
+
+	/* codec settings */
+	struct cx2341x_handler cxhdl;
+	u32 filter_mode;
+	u32 temporal_strength;
+	u32 spatial_strength;
+
+	/* dualwatch */
+	unsigned long dualwatch_jiffies;
+	u32 dualwatch_stereo_mode;
+
+	struct mutex serialize_lock;    /* mutex used to serialize open/close/start/stop/ioctl operations */
+	struct cx18_options options; 	/* User options */
+	int stream_buffers[CX18_MAX_STREAMS]; /* # of buffers for each stream */
+	int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */
+	struct cx18_stream streams[CX18_MAX_STREAMS]; 	/* Stream data */
+	struct snd_cx18_card *alsa; /* ALSA interface for PCM capture stream */
+	void (*pcm_announce_callback)(struct snd_cx18_card *card, u8 *pcm_data,
+				      size_t num_bytes);
+
+	unsigned long i_flags;  /* global cx18 flags */
+	atomic_t ana_capturing;	/* count number of active analog capture streams */
+	atomic_t tot_capturing;	/* total count number of active capture streams */
+	int search_pack_header;
+
+	int open_id;		/* incremented each time an open occurs, used as
+				   unique ID. Starts at 1, so 0 can be used as
+				   uninitialized value in the stream->id. */
+
+	resource_size_t base_addr;
+
+	u8 card_rev;
+	void __iomem *enc_mem, *reg_mem;
+
+	struct vbi_info vbi;
+
+	u64 mpg_data_received;
+	u64 vbi_data_inserted;
+
+	wait_queue_head_t mb_apu_waitq;
+	wait_queue_head_t mb_cpu_waitq;
+	wait_queue_head_t cap_w;
+	/* when the current DMA is finished this queue is woken up */
+	wait_queue_head_t dma_waitq;
+
+	u32 sw1_irq_mask;
+	u32 sw2_irq_mask;
+	u32 hw2_irq_mask;
+
+	struct workqueue_struct *in_work_queue;
+	char in_workq_name[11]; /* "cx18-NN-in" */
+	struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS];
+	char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */
+
+	/* i2c */
+	struct i2c_adapter i2c_adap[2];
+	struct i2c_algo_bit_data i2c_algo[2];
+	struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2];
+
+	struct IR_i2c_init_data ir_i2c_init_data;
+
+	/* gpio */
+	u32 gpio_dir;
+	u32 gpio_val;
+	struct mutex gpio_lock;
+	struct v4l2_subdev sd_gpiomux;
+	struct v4l2_subdev sd_resetctrl;
+
+	/* v4l2 and User settings */
+
+	/* codec settings */
+	u32 audio_input;
+	u32 active_input;
+	v4l2_std_id std;
+	v4l2_std_id tuner_std;	/* The norm of the tuner (fixed) */
+
+	/* Used for cx18-alsa module loading */
+	struct work_struct request_module_wk;
+};
+
+static inline struct cx18 *to_cx18(struct v4l2_device *v4l2_dev)
+{
+	return container_of(v4l2_dev, struct cx18, v4l2_dev);
+}
+
+/* cx18 extensions to be loaded */
+extern int (*cx18_ext_init)(struct cx18 *);
+
+/* Globals */
+extern int cx18_first_minor;
+
+/*==============Prototypes==================*/
+
+/* Return non-zero if a signal is pending */
+int cx18_msleep_timeout(unsigned int msecs, int intr);
+
+/* Read Hauppauge eeprom */
+struct tveeprom; /* forward reference */
+void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv);
+
+/* First-open initialization: load firmware, etc. */
+int cx18_init_on_first_open(struct cx18 *cx);
+
+/* Test if the current VBI mode is raw (1) or sliced (0) */
+static inline int cx18_raw_vbi(const struct cx18 *cx)
+{
+	return cx->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE;
+}
+
+/* Call the specified callback for all subdevs with a grp_id bit matching the
+ * mask in hw (if 0, then match them all). Ignore any errors. */
+#define cx18_call_hw(cx, hw, o, f, args...)				\
+	do {								\
+		struct v4l2_subdev *__sd;				\
+		__v4l2_device_call_subdevs_p(&(cx)->v4l2_dev, __sd,	\
+			!(hw) || (__sd->grp_id & (hw)), o, f , ##args);	\
+	} while (0)
+
+#define cx18_call_all(cx, o, f, args...) cx18_call_hw(cx, 0, o, f , ##args)
+
+/* Call the specified callback for all subdevs with a grp_id bit matching the
+ * mask in hw (if 0, then match them all). If the callback returns an error
+ * other than 0 or -ENOIOCTLCMD, then return with that error code. */
+#define cx18_call_hw_err(cx, hw, o, f, args...)				\
+({									\
+	struct v4l2_subdev *__sd;					\
+	__v4l2_device_call_subdevs_until_err_p(&(cx)->v4l2_dev,		\
+			__sd, !(hw) || (__sd->grp_id & (hw)), o, f,	\
+			##args);					\
+})
+
+#define cx18_call_all_err(cx, o, f, args...) \
+	cx18_call_hw_err(cx, 0, o, f , ##args)
+
+#endif /* CX18_DRIVER_H */
diff --git a/drivers/media/pci/cx18/cx18-dvb.c b/drivers/media/pci/cx18/cx18-dvb.c
new file mode 100644
index 0000000..3eac59c
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-dvb.c
@@ -0,0 +1,609 @@
+/*
+ *  cx18 functions for DVB support
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cx18-version.h"
+#include "cx18-dvb.h"
+#include "cx18-io.h"
+#include "cx18-queue.h"
+#include "cx18-streams.h"
+#include "cx18-cards.h"
+#include "cx18-gpio.h"
+#include "s5h1409.h"
+#include "mxl5005s.h"
+#include "s5h1411.h"
+#include "tda18271.h"
+#include "zl10353.h"
+
+#include <linux/firmware.h>
+#include "mt352.h"
+#include "mt352_priv.h"
+#include "tuner-xc2028.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define FWFILE "dvb-cx18-mpc718-mt352.fw"
+
+#define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000
+#define CX18_CLOCK_ENABLE2		 0xc71024
+#define CX18_DMUX_CLK_MASK		 0x0080
+
+/*
+ * CX18_CARD_HVR_1600_ESMT
+ * CX18_CARD_HVR_1600_SAMSUNG
+ */
+
+static struct mxl5005s_config hauppauge_hvr1600_tuner = {
+	.i2c_address     = 0xC6 >> 1,
+	.if_freq         = IF_FREQ_5380000HZ,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_C_H,
+	.rssi_enable     = MXL_RSSI_ENABLE,
+	.cap_select      = MXL_CAP_SEL_ENABLE,
+	.div_out         = MXL_DIV_OUT_4,
+	.clock_out       = MXL_CLOCK_OUT_DISABLE,
+	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+	.top		 = MXL5005S_TOP_25P2,
+	.mod_mode        = MXL_DIGITAL_MODE,
+	.if_mode         = MXL_ZERO_IF,
+	.qam_gain        = 0x02,
+	.AgcMasterByte   = 0x00,
+};
+
+static struct s5h1409_config hauppauge_hvr1600_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_SERIAL_OUTPUT,
+	.gpio          = S5H1409_GPIO_ON,
+	.qam_if        = 44000,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+	.hvr1600_opt   = S5H1409_HVR1600_OPTIMIZE
+};
+
+/*
+ * CX18_CARD_HVR_1600_S5H1411
+ */
+static struct s5h1411_config hcw_s5h1411_config = {
+	.output_mode   = S5H1411_SERIAL_OUTPUT,
+	.gpio          = S5H1411_GPIO_OFF,
+	.vsb_if        = S5H1411_IF_44000,
+	.qam_if        = S5H1411_IF_4000,
+	.inversion     = S5H1411_INVERSION_ON,
+	.status_mode   = S5H1411_DEMODLOCKING,
+	.mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+	.atsc_6   = { .if_freq = 5380, .agc_mode = 3, .std = 3,
+		      .if_lvl = 6, .rfagc_top = 0x37 },
+	.qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 0,
+		      .if_lvl = 6, .rfagc_top = 0x37 },
+};
+
+static struct tda18271_config hauppauge_tda18271_config = {
+	.std_map = &hauppauge_tda18271_std_map,
+	.gate    = TDA18271_GATE_DIGITAL,
+	.output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
+/*
+ * CX18_CARD_LEADTEK_DVR3100H
+ */
+/* Information/confirmation of proper config values provided by Terry Wu */
+static struct zl10353_config leadtek_dvr3100h_demod = {
+	.demod_address         = 0x1e >> 1, /* Datasheet suggested straps */
+	.if2                   = 45600,     /* 4.560 MHz IF from the XC3028 */
+	.parallel_ts           = 1,         /* Not a serial TS */
+	.no_tuner              = 1,         /* XC3028 is not behind the gate */
+	.disable_i2c_gate_ctrl = 1,         /* Disable the I2C gate */
+};
+
+/*
+ * CX18_CARD_YUAN_MPC718
+ */
+/*
+ * Due to
+ *
+ * 1. an absence of information on how to prgram the MT352
+ * 2. the Linux mt352 module pushing MT352 initialzation off onto us here
+ *
+ * We have to use an init sequence that *you* must extract from the Windows
+ * driver (yuanrap.sys) and which we load as a firmware.
+ *
+ * If someone can provide me with a Zarlink MT352 (Intel CE6352?) Design Manual
+ * with chip programming details, then I can remove this annoyance.
+ */
+static int yuan_mpc718_mt352_reqfw(struct cx18_stream *stream,
+				   const struct firmware **fw)
+{
+	struct cx18 *cx = stream->cx;
+	const char *fn = FWFILE;
+	int ret;
+
+	ret = request_firmware(fw, fn, &cx->pci_dev->dev);
+	if (ret)
+		CX18_ERR("Unable to open firmware file %s\n", fn);
+	else {
+		size_t sz = (*fw)->size;
+		if (sz < 2 || sz > 64 || (sz % 2) != 0) {
+			CX18_ERR("Firmware %s has a bad size: %lu bytes\n",
+				 fn, (unsigned long) sz);
+			ret = -EILSEQ;
+			release_firmware(*fw);
+			*fw = NULL;
+		}
+	}
+
+	if (ret) {
+		CX18_ERR("The MPC718 board variant with the MT352 DVB-T"
+			  "demodualtor will not work without it\n");
+		CX18_ERR("Run 'linux/Documentation/dvb/get_dvb_firmware "
+			  "mpc718' if you need the firmware\n");
+	}
+	return ret;
+}
+
+static int yuan_mpc718_mt352_init(struct dvb_frontend *fe)
+{
+	struct cx18_dvb *dvb = container_of(fe->dvb,
+					    struct cx18_dvb, dvb_adapter);
+	struct cx18_stream *stream = dvb->stream;
+	const struct firmware *fw = NULL;
+	int ret;
+	int i;
+	u8 buf[3];
+
+	ret = yuan_mpc718_mt352_reqfw(stream, &fw);
+	if (ret)
+		return ret;
+
+	/* Loop through all the register-value pairs in the firmware file */
+	for (i = 0; i < fw->size; i += 2) {
+		buf[0] = fw->data[i];
+		/* Intercept a few registers we want to set ourselves */
+		switch (buf[0]) {
+		case TRL_NOMINAL_RATE_0:
+			/* Set our custom OFDM bandwidth in the case below */
+			break;
+		case TRL_NOMINAL_RATE_1:
+			/* 6 MHz: 64/7 * 6/8 / 20.48 * 2^16 = 0x55b6.db6 */
+			/* 7 MHz: 64/7 * 7/8 / 20.48 * 2^16 = 0x6400 */
+			/* 8 MHz: 64/7 * 8/8 / 20.48 * 2^16 = 0x7249.249 */
+			buf[1] = 0x72;
+			buf[2] = 0x49;
+			mt352_write(fe, buf, 3);
+			break;
+		case INPUT_FREQ_0:
+			/* Set our custom IF in the case below */
+			break;
+		case INPUT_FREQ_1:
+			/* 4.56 MHz IF: (20.48 - 4.56)/20.48 * 2^14 = 0x31c0 */
+			buf[1] = 0x31;
+			buf[2] = 0xc0;
+			mt352_write(fe, buf, 3);
+			break;
+		default:
+			/* Pass through the register-value pair from the fw */
+			buf[1] = fw->data[i+1];
+			mt352_write(fe, buf, 2);
+			break;
+		}
+	}
+
+	buf[0] = (u8) TUNER_GO;
+	buf[1] = 0x01; /* Go */
+	mt352_write(fe, buf, 2);
+	release_firmware(fw);
+	return 0;
+}
+
+static struct mt352_config yuan_mpc718_mt352_demod = {
+	.demod_address = 0x1e >> 1,
+	.adc_clock     = 20480,     /* 20.480 MHz */
+	.if2           =  4560,     /*  4.560 MHz */
+	.no_tuner      = 1,         /* XC3028 is not behind the gate */
+	.demod_init    = yuan_mpc718_mt352_init,
+};
+
+static struct zl10353_config yuan_mpc718_zl10353_demod = {
+	.demod_address         = 0x1e >> 1, /* Datasheet suggested straps */
+	.if2                   = 45600,     /* 4.560 MHz IF from the XC3028 */
+	.parallel_ts           = 1,         /* Not a serial TS */
+	.no_tuner              = 1,         /* XC3028 is not behind the gate */
+	.disable_i2c_gate_ctrl = 1,         /* Disable the I2C gate */
+};
+
+static struct zl10353_config gotview_dvd3_zl10353_demod = {
+	.demod_address         = 0x1e >> 1, /* Datasheet suggested straps */
+	.if2                   = 45600,     /* 4.560 MHz IF from the XC3028 */
+	.parallel_ts           = 1,         /* Not a serial TS */
+	.no_tuner              = 1,         /* XC3028 is not behind the gate */
+	.disable_i2c_gate_ctrl = 1,         /* Disable the I2C gate */
+};
+
+static int dvb_register(struct cx18_stream *stream);
+
+/* Kernel DVB framework calls this when the feed needs to start.
+ * The CX18 framework should enable the transport DMA handling
+ * and queue processing.
+ */
+static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct cx18_stream *stream = (struct cx18_stream *) demux->priv;
+	struct cx18 *cx;
+	int ret;
+	u32 v;
+
+	if (!stream)
+		return -EINVAL;
+
+	cx = stream->cx;
+	CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n",
+			feed->pid, feed->index);
+
+	mutex_lock(&cx->serialize_lock);
+	ret = cx18_init_on_first_open(cx);
+	mutex_unlock(&cx->serialize_lock);
+	if (ret) {
+		CX18_ERR("Failed to initialize firmware starting DVB feed\n");
+		return ret;
+	}
+	ret = -EINVAL;
+
+	switch (cx->card->type) {
+	case CX18_CARD_HVR_1600_ESMT:
+	case CX18_CARD_HVR_1600_SAMSUNG:
+	case CX18_CARD_HVR_1600_S5H1411:
+		v = cx18_read_reg(cx, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
+		v |= 0x00400000; /* Serial Mode */
+		v |= 0x00002000; /* Data Length - Byte */
+		v |= 0x00010000; /* Error - Polarity */
+		v |= 0x00020000; /* Error - Passthru */
+		v |= 0x000c0000; /* Error - Ignore */
+		cx18_write_reg(cx, v, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
+		break;
+
+	case CX18_CARD_LEADTEK_DVR3100H:
+	case CX18_CARD_YUAN_MPC718:
+	case CX18_CARD_GOTVIEW_PCI_DVD3:
+	default:
+		/* Assumption - Parallel transport - Signalling
+		 * undefined or default.
+		 */
+		break;
+	}
+
+	if (!demux->dmx.frontend)
+		return -EINVAL;
+
+	mutex_lock(&stream->dvb->feedlock);
+	if (stream->dvb->feeding++ == 0) {
+		CX18_DEBUG_INFO("Starting Transport DMA\n");
+		mutex_lock(&cx->serialize_lock);
+		set_bit(CX18_F_S_STREAMING, &stream->s_flags);
+		ret = cx18_start_v4l2_encode_stream(stream);
+		if (ret < 0) {
+			CX18_DEBUG_INFO("Failed to start Transport DMA\n");
+			stream->dvb->feeding--;
+			if (stream->dvb->feeding == 0)
+				clear_bit(CX18_F_S_STREAMING, &stream->s_flags);
+		}
+		mutex_unlock(&cx->serialize_lock);
+	} else
+		ret = 0;
+	mutex_unlock(&stream->dvb->feedlock);
+
+	return ret;
+}
+
+/* Kernel DVB framework calls this when the feed needs to stop. */
+static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct cx18_stream *stream = (struct cx18_stream *)demux->priv;
+	struct cx18 *cx;
+	int ret = -EINVAL;
+
+	if (stream) {
+		cx = stream->cx;
+		CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n",
+				feed->pid, feed->index);
+
+		mutex_lock(&stream->dvb->feedlock);
+		if (--stream->dvb->feeding == 0) {
+			CX18_DEBUG_INFO("Stopping Transport DMA\n");
+			mutex_lock(&cx->serialize_lock);
+			ret = cx18_stop_v4l2_encode_stream(stream, 0);
+			mutex_unlock(&cx->serialize_lock);
+		} else
+			ret = 0;
+		mutex_unlock(&stream->dvb->feedlock);
+	}
+
+	return ret;
+}
+
+int cx18_dvb_register(struct cx18_stream *stream)
+{
+	struct cx18 *cx = stream->cx;
+	struct cx18_dvb *dvb = stream->dvb;
+	struct dvb_adapter *dvb_adapter;
+	struct dvb_demux *dvbdemux;
+	struct dmx_demux *dmx;
+	int ret;
+
+	if (!dvb)
+		return -EINVAL;
+
+	dvb->enabled = 0;
+	dvb->stream = stream;
+
+	ret = dvb_register_adapter(&dvb->dvb_adapter,
+			CX18_DRIVER_NAME,
+			THIS_MODULE, &cx->pci_dev->dev, adapter_nr);
+	if (ret < 0)
+		goto err_out;
+
+	dvb_adapter = &dvb->dvb_adapter;
+
+	dvbdemux = &dvb->demux;
+
+	dvbdemux->priv = (void *)stream;
+
+	dvbdemux->filternum = 256;
+	dvbdemux->feednum = 256;
+	dvbdemux->start_feed = cx18_dvb_start_feed;
+	dvbdemux->stop_feed = cx18_dvb_stop_feed;
+	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+		DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
+	ret = dvb_dmx_init(dvbdemux);
+	if (ret < 0)
+		goto err_dvb_unregister_adapter;
+
+	dmx = &dvbdemux->dmx;
+
+	dvb->hw_frontend.source = DMX_FRONTEND_0;
+	dvb->mem_frontend.source = DMX_MEMORY_FE;
+	dvb->dmxdev.filternum = 256;
+	dvb->dmxdev.demux = dmx;
+
+	ret = dvb_dmxdev_init(&dvb->dmxdev, dvb_adapter);
+	if (ret < 0)
+		goto err_dvb_dmx_release;
+
+	ret = dmx->add_frontend(dmx, &dvb->hw_frontend);
+	if (ret < 0)
+		goto err_dvb_dmxdev_release;
+
+	ret = dmx->add_frontend(dmx, &dvb->mem_frontend);
+	if (ret < 0)
+		goto err_remove_hw_frontend;
+
+	ret = dmx->connect_frontend(dmx, &dvb->hw_frontend);
+	if (ret < 0)
+		goto err_remove_mem_frontend;
+
+	ret = dvb_register(stream);
+	if (ret < 0)
+		goto err_disconnect_frontend;
+
+	dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx);
+
+	CX18_INFO("DVB Frontend registered\n");
+	CX18_INFO("Registered DVB adapter%d for %s (%d x %d.%02d kB)\n",
+		  stream->dvb->dvb_adapter.num, stream->name,
+		  stream->buffers, stream->buf_size/1024,
+		  (stream->buf_size * 100 / 1024) % 100);
+
+	mutex_init(&dvb->feedlock);
+	dvb->enabled = 1;
+	return ret;
+
+err_disconnect_frontend:
+	dmx->disconnect_frontend(dmx);
+err_remove_mem_frontend:
+	dmx->remove_frontend(dmx, &dvb->mem_frontend);
+err_remove_hw_frontend:
+	dmx->remove_frontend(dmx, &dvb->hw_frontend);
+err_dvb_dmxdev_release:
+	dvb_dmxdev_release(&dvb->dmxdev);
+err_dvb_dmx_release:
+	dvb_dmx_release(dvbdemux);
+err_dvb_unregister_adapter:
+	dvb_unregister_adapter(dvb_adapter);
+err_out:
+	return ret;
+}
+
+void cx18_dvb_unregister(struct cx18_stream *stream)
+{
+	struct cx18 *cx = stream->cx;
+	struct cx18_dvb *dvb = stream->dvb;
+	struct dvb_adapter *dvb_adapter;
+	struct dvb_demux *dvbdemux;
+	struct dmx_demux *dmx;
+
+	CX18_INFO("unregister DVB\n");
+
+	if (dvb == NULL || !dvb->enabled)
+		return;
+
+	dvb_adapter = &dvb->dvb_adapter;
+	dvbdemux = &dvb->demux;
+	dmx = &dvbdemux->dmx;
+
+	dmx->close(dmx);
+	dvb_net_release(&dvb->dvbnet);
+	dmx->remove_frontend(dmx, &dvb->mem_frontend);
+	dmx->remove_frontend(dmx, &dvb->hw_frontend);
+	dvb_dmxdev_release(&dvb->dmxdev);
+	dvb_dmx_release(dvbdemux);
+	dvb_unregister_frontend(dvb->fe);
+	dvb_frontend_detach(dvb->fe);
+	dvb_unregister_adapter(dvb_adapter);
+}
+
+/* All the DVB attach calls go here, this function get's modified
+ * for each new card. cx18_dvb_start_feed() will also need changes.
+ */
+static int dvb_register(struct cx18_stream *stream)
+{
+	struct cx18_dvb *dvb = stream->dvb;
+	struct cx18 *cx = stream->cx;
+	int ret = 0;
+
+	switch (cx->card->type) {
+	case CX18_CARD_HVR_1600_ESMT:
+	case CX18_CARD_HVR_1600_SAMSUNG:
+		dvb->fe = dvb_attach(s5h1409_attach,
+			&hauppauge_hvr1600_config,
+			&cx->i2c_adap[0]);
+		if (dvb->fe != NULL) {
+			dvb_attach(mxl5005s_attach, dvb->fe,
+				&cx->i2c_adap[0],
+				&hauppauge_hvr1600_tuner);
+			ret = 0;
+		}
+		break;
+	case CX18_CARD_HVR_1600_S5H1411:
+		dvb->fe = dvb_attach(s5h1411_attach,
+				     &hcw_s5h1411_config,
+				     &cx->i2c_adap[0]);
+		if (dvb->fe != NULL)
+			dvb_attach(tda18271_attach, dvb->fe,
+				   0x60, &cx->i2c_adap[0],
+				   &hauppauge_tda18271_config);
+		break;
+	case CX18_CARD_LEADTEK_DVR3100H:
+		dvb->fe = dvb_attach(zl10353_attach,
+				     &leadtek_dvr3100h_demod,
+				     &cx->i2c_adap[1]);
+		if (dvb->fe != NULL) {
+			struct dvb_frontend *fe;
+			struct xc2028_config cfg = {
+				.i2c_adap = &cx->i2c_adap[1],
+				.i2c_addr = 0xc2 >> 1,
+				.ctrl = NULL,
+			};
+			static struct xc2028_ctrl ctrl = {
+				.fname   = XC2028_DEFAULT_FIRMWARE,
+				.max_len = 64,
+				.demod   = XC3028_FE_ZARLINK456,
+				.type    = XC2028_AUTO,
+			};
+
+			fe = dvb_attach(xc2028_attach, dvb->fe, &cfg);
+			if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+				fe->ops.tuner_ops.set_config(fe, &ctrl);
+		}
+		break;
+	case CX18_CARD_YUAN_MPC718:
+		/*
+		 * TODO
+		 * Apparently, these cards also could instead have a
+		 * DiBcom demod supported by one of the db7000 drivers
+		 */
+		dvb->fe = dvb_attach(mt352_attach,
+				     &yuan_mpc718_mt352_demod,
+				     &cx->i2c_adap[1]);
+		if (dvb->fe == NULL)
+			dvb->fe = dvb_attach(zl10353_attach,
+					     &yuan_mpc718_zl10353_demod,
+					     &cx->i2c_adap[1]);
+		if (dvb->fe != NULL) {
+			struct dvb_frontend *fe;
+			struct xc2028_config cfg = {
+				.i2c_adap = &cx->i2c_adap[1],
+				.i2c_addr = 0xc2 >> 1,
+				.ctrl = NULL,
+			};
+			static struct xc2028_ctrl ctrl = {
+				.fname   = XC2028_DEFAULT_FIRMWARE,
+				.max_len = 64,
+				.demod   = XC3028_FE_ZARLINK456,
+				.type    = XC2028_AUTO,
+			};
+
+			fe = dvb_attach(xc2028_attach, dvb->fe, &cfg);
+			if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+				fe->ops.tuner_ops.set_config(fe, &ctrl);
+		}
+		break;
+	case CX18_CARD_GOTVIEW_PCI_DVD3:
+			dvb->fe = dvb_attach(zl10353_attach,
+					     &gotview_dvd3_zl10353_demod,
+					     &cx->i2c_adap[1]);
+		if (dvb->fe != NULL) {
+			struct dvb_frontend *fe;
+			struct xc2028_config cfg = {
+				.i2c_adap = &cx->i2c_adap[1],
+				.i2c_addr = 0xc2 >> 1,
+				.ctrl = NULL,
+			};
+			static struct xc2028_ctrl ctrl = {
+				.fname   = XC2028_DEFAULT_FIRMWARE,
+				.max_len = 64,
+				.demod   = XC3028_FE_ZARLINK456,
+				.type    = XC2028_AUTO,
+			};
+
+			fe = dvb_attach(xc2028_attach, dvb->fe, &cfg);
+			if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+				fe->ops.tuner_ops.set_config(fe, &ctrl);
+		}
+		break;
+	default:
+		/* No Digital Tv Support */
+		break;
+	}
+
+	if (dvb->fe == NULL) {
+		CX18_ERR("frontend initialization failed\n");
+		return -1;
+	}
+
+	dvb->fe->callback = cx18_reset_tuner_gpio;
+
+	ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe);
+	if (ret < 0) {
+		if (dvb->fe->ops.release)
+			dvb->fe->ops.release(dvb->fe);
+		return ret;
+	}
+
+	/*
+	 * The firmware seems to enable the TS DMUX clock
+	 * under various circumstances.  However, since we know we
+	 * might use it, let's just turn it on ourselves here.
+	 */
+	cx18_write_reg_expect(cx,
+			      (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK,
+			      CX18_CLOCK_ENABLE2,
+			      CX18_DMUX_CLK_MASK,
+			      (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK);
+
+	return ret;
+}
+
+MODULE_FIRMWARE(FWFILE);
diff --git a/drivers/media/pci/cx18/cx18-dvb.h b/drivers/media/pci/cx18/cx18-dvb.h
new file mode 100644
index 0000000..bf8d8f6
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-dvb.h
@@ -0,0 +1,25 @@
+/*
+ *  cx18 functions for DVB support
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cx18-driver.h"
+
+int cx18_dvb_register(struct cx18_stream *stream);
+void cx18_dvb_unregister(struct cx18_stream *stream);
diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c
new file mode 100644
index 0000000..4bfd865
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-fileops.c
@@ -0,0 +1,881 @@
+/*
+ *  cx18 file operation functions
+ *
+ *  Derived from ivtv-fileops.c
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-fileops.h"
+#include "cx18-i2c.h"
+#include "cx18-queue.h"
+#include "cx18-vbi.h"
+#include "cx18-audio.h"
+#include "cx18-mailbox.h"
+#include "cx18-scb.h"
+#include "cx18-streams.h"
+#include "cx18-controls.h"
+#include "cx18-ioctl.h"
+#include "cx18-cards.h"
+
+/* This function tries to claim the stream for a specific file descriptor.
+   If no one else is using this stream then the stream is claimed and
+   associated VBI and IDX streams are also automatically claimed.
+   Possible error returns: -EBUSY if someone else has claimed
+   the stream or 0 on success. */
+int cx18_claim_stream(struct cx18_open_id *id, int type)
+{
+	struct cx18 *cx = id->cx;
+	struct cx18_stream *s = &cx->streams[type];
+	struct cx18_stream *s_assoc;
+
+	/* Nothing should ever try to directly claim the IDX stream */
+	if (type == CX18_ENC_STREAM_TYPE_IDX) {
+		CX18_WARN("MPEG Index stream cannot be claimed "
+			  "directly, but something tried.\n");
+		return -EINVAL;
+	}
+
+	if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) {
+		/* someone already claimed this stream */
+		if (s->id == id->open_id) {
+			/* yes, this file descriptor did. So that's OK. */
+			return 0;
+		}
+		if (s->id == -1 && type == CX18_ENC_STREAM_TYPE_VBI) {
+			/* VBI is handled already internally, now also assign
+			   the file descriptor to this stream for external
+			   reading of the stream. */
+			s->id = id->open_id;
+			CX18_DEBUG_INFO("Start Read VBI\n");
+			return 0;
+		}
+		/* someone else is using this stream already */
+		CX18_DEBUG_INFO("Stream %d is busy\n", type);
+		return -EBUSY;
+	}
+	s->id = id->open_id;
+
+	/*
+	 * CX18_ENC_STREAM_TYPE_MPG needs to claim:
+	 * CX18_ENC_STREAM_TYPE_VBI, if VBI insertion is on for sliced VBI, or
+	 * CX18_ENC_STREAM_TYPE_IDX, if VBI insertion is off for sliced VBI
+	 * (We don't yet fix up MPEG Index entries for our inserted packets).
+	 *
+	 * For all other streams we're done.
+	 */
+	if (type != CX18_ENC_STREAM_TYPE_MPG)
+		return 0;
+
+	s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
+	if (cx->vbi.insert_mpeg && !cx18_raw_vbi(cx))
+		s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+	else if (!cx18_stream_enabled(s_assoc))
+		return 0;
+
+	set_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags);
+
+	/* mark that it is used internally */
+	set_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags);
+	return 0;
+}
+EXPORT_SYMBOL(cx18_claim_stream);
+
+/* This function releases a previously claimed stream. It will take into
+   account associated VBI streams. */
+void cx18_release_stream(struct cx18_stream *s)
+{
+	struct cx18 *cx = s->cx;
+	struct cx18_stream *s_assoc;
+
+	s->id = -1;
+	if (s->type == CX18_ENC_STREAM_TYPE_IDX) {
+		/*
+		 * The IDX stream is only used internally, and can
+		 * only be indirectly unclaimed by unclaiming the MPG stream.
+		 */
+		return;
+	}
+
+	if (s->type == CX18_ENC_STREAM_TYPE_VBI &&
+		test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) {
+		/* this stream is still in use internally */
+		return;
+	}
+	if (!test_and_clear_bit(CX18_F_S_CLAIMED, &s->s_flags)) {
+		CX18_DEBUG_WARN("Release stream %s not in use!\n", s->name);
+		return;
+	}
+
+	cx18_flush_queues(s);
+
+	/*
+	 * CX18_ENC_STREAM_TYPE_MPG needs to release the
+	 * CX18_ENC_STREAM_TYPE_VBI and/or CX18_ENC_STREAM_TYPE_IDX streams.
+	 *
+	 * For all other streams we're done.
+	 */
+	if (s->type != CX18_ENC_STREAM_TYPE_MPG)
+		return;
+
+	/* Unclaim the associated MPEG Index stream */
+	s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
+	if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) {
+		clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags);
+		cx18_flush_queues(s_assoc);
+	}
+
+	/* Unclaim the associated VBI stream */
+	s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+	if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) {
+		if (s_assoc->id == -1) {
+			/*
+			 * The VBI stream is not still claimed by a file
+			 * descriptor, so completely unclaim it.
+			 */
+			clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags);
+			cx18_flush_queues(s_assoc);
+		}
+	}
+}
+EXPORT_SYMBOL(cx18_release_stream);
+
+static void cx18_dualwatch(struct cx18 *cx)
+{
+	struct v4l2_tuner vt;
+	u32 new_stereo_mode;
+	const u32 dual = 0x0200;
+
+	new_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode);
+	memset(&vt, 0, sizeof(vt));
+	cx18_call_all(cx, tuner, g_tuner, &vt);
+	if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 &&
+			(vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
+		new_stereo_mode = dual;
+
+	if (new_stereo_mode == cx->dualwatch_stereo_mode)
+		return;
+
+	CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n",
+			   cx->dualwatch_stereo_mode, new_stereo_mode);
+	if (v4l2_ctrl_s_ctrl(cx->cxhdl.audio_mode, new_stereo_mode))
+		CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
+}
+
+
+static struct cx18_mdl *cx18_get_mdl(struct cx18_stream *s, int non_block,
+				     int *err)
+{
+	struct cx18 *cx = s->cx;
+	struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+	struct cx18_mdl *mdl;
+	DEFINE_WAIT(wait);
+
+	*err = 0;
+	while (1) {
+		if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
+			/* Process pending program updates and VBI data */
+			if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) {
+				cx->dualwatch_jiffies = jiffies;
+				cx18_dualwatch(cx);
+			}
+			if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
+			    !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
+				while ((mdl = cx18_dequeue(s_vbi,
+							   &s_vbi->q_full))) {
+					/* byteswap and process VBI data */
+					cx18_process_vbi_data(cx, mdl,
+							      s_vbi->type);
+					cx18_stream_put_mdl_fw(s_vbi, mdl);
+				}
+			}
+			mdl = &cx->vbi.sliced_mpeg_mdl;
+			if (mdl->readpos != mdl->bytesused)
+				return mdl;
+		}
+
+		/* do we have new data? */
+		mdl = cx18_dequeue(s, &s->q_full);
+		if (mdl) {
+			if (!test_and_clear_bit(CX18_F_M_NEED_SWAP,
+						&mdl->m_flags))
+				return mdl;
+			if (s->type == CX18_ENC_STREAM_TYPE_MPG)
+				/* byteswap MPG data */
+				cx18_mdl_swap(mdl);
+			else {
+				/* byteswap and process VBI data */
+				cx18_process_vbi_data(cx, mdl, s->type);
+			}
+			return mdl;
+		}
+
+		/* return if end of stream */
+		if (!test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+			CX18_DEBUG_INFO("EOS %s\n", s->name);
+			return NULL;
+		}
+
+		/* return if file was opened with O_NONBLOCK */
+		if (non_block) {
+			*err = -EAGAIN;
+			return NULL;
+		}
+
+		/* wait for more data to arrive */
+		prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
+		/* New buffers might have become available before we were added
+		   to the waitqueue */
+		if (!atomic_read(&s->q_full.depth))
+			schedule();
+		finish_wait(&s->waitq, &wait);
+		if (signal_pending(current)) {
+			/* return if a signal was received */
+			CX18_DEBUG_INFO("User stopped %s\n", s->name);
+			*err = -EINTR;
+			return NULL;
+		}
+	}
+}
+
+static void cx18_setup_sliced_vbi_mdl(struct cx18 *cx)
+{
+	struct cx18_mdl *mdl = &cx->vbi.sliced_mpeg_mdl;
+	struct cx18_buffer *buf = &cx->vbi.sliced_mpeg_buf;
+	int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;
+
+	buf->buf = cx->vbi.sliced_mpeg_data[idx];
+	buf->bytesused = cx->vbi.sliced_mpeg_size[idx];
+	buf->readpos = 0;
+
+	mdl->curr_buf = NULL;
+	mdl->bytesused = cx->vbi.sliced_mpeg_size[idx];
+	mdl->readpos = 0;
+}
+
+static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
+	struct cx18_buffer *buf, char __user *ubuf, size_t ucount, bool *stop)
+{
+	struct cx18 *cx = s->cx;
+	size_t len = buf->bytesused - buf->readpos;
+
+	*stop = false;
+	if (len > ucount)
+		len = ucount;
+	if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG &&
+	    !cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) {
+		/*
+		 * Try to find a good splice point in the PS, just before
+		 * an MPEG-2 Program Pack start code, and provide only
+		 * up to that point to the user, so it's easy to insert VBI data
+		 * the next time around.
+		 *
+		 * This will not work for an MPEG-2 TS and has only been
+		 * verified by analysis to work for an MPEG-2 PS.  Helen Buus
+		 * pointed out this works for the CX23416 MPEG-2 DVD compatible
+		 * stream, and research indicates both the MPEG 2 SVCD and DVD
+		 * stream types use an MPEG-2 PS container.
+		 */
+		/*
+		 * An MPEG-2 Program Stream (PS) is a series of
+		 * MPEG-2 Program Packs terminated by an
+		 * MPEG Program End Code after the last Program Pack.
+		 * A Program Pack may hold a PS System Header packet and any
+		 * number of Program Elementary Stream (PES) Packets
+		 */
+		const char *start = buf->buf + buf->readpos;
+		const char *p = start + 1;
+		const u8 *q;
+		u8 ch = cx->search_pack_header ? 0xba : 0xe0;
+		int stuffing, i;
+
+		while (start + len > p) {
+			/* Scan for a 0 to find a potential MPEG-2 start code */
+			q = memchr(p, 0, start + len - p);
+			if (q == NULL)
+				break;
+			p = q + 1;
+			/*
+			 * Keep looking if not a
+			 * MPEG-2 Pack header start code:  0x00 0x00 0x01 0xba
+			 * or MPEG-2 video PES start code: 0x00 0x00 0x01 0xe0
+			 */
+			if ((char *)q + 15 >= buf->buf + buf->bytesused ||
+			    q[1] != 0 || q[2] != 1 || q[3] != ch)
+				continue;
+
+			/* If expecting the primary video PES */
+			if (!cx->search_pack_header) {
+				/* Continue if it couldn't be a PES packet */
+				if ((q[6] & 0xc0) != 0x80)
+					continue;
+				/* Check if a PTS or PTS & DTS follow */
+				if (((q[7] & 0xc0) == 0x80 &&  /* PTS only */
+				     (q[9] & 0xf0) == 0x20) || /* PTS only */
+				    ((q[7] & 0xc0) == 0xc0 &&  /* PTS & DTS */
+				     (q[9] & 0xf0) == 0x30)) { /* DTS follows */
+					/* Assume we found the video PES hdr */
+					ch = 0xba; /* next want a Program Pack*/
+					cx->search_pack_header = 1;
+					p = q + 9; /* Skip this video PES hdr */
+				}
+				continue;
+			}
+
+			/* We may have found a Program Pack start code */
+
+			/* Get the count of stuffing bytes & verify them */
+			stuffing = q[13] & 7;
+			/* all stuffing bytes must be 0xff */
+			for (i = 0; i < stuffing; i++)
+				if (q[14 + i] != 0xff)
+					break;
+			if (i == stuffing && /* right number of stuffing bytes*/
+			    (q[4] & 0xc4) == 0x44 && /* marker check */
+			    (q[12] & 3) == 3 &&  /* marker check */
+			    q[14 + stuffing] == 0 && /* PES Pack or Sys Hdr */
+			    q[15 + stuffing] == 0 &&
+			    q[16 + stuffing] == 1) {
+				/* We declare we actually found a Program Pack*/
+				cx->search_pack_header = 0; /* expect vid PES */
+				len = (char *)q - start;
+				cx18_setup_sliced_vbi_mdl(cx);
+				*stop = true;
+				break;
+			}
+		}
+	}
+	if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) {
+		CX18_DEBUG_WARN("copy %zd bytes to user failed for %s\n",
+				len, s->name);
+		return -EFAULT;
+	}
+	buf->readpos += len;
+	if (s->type == CX18_ENC_STREAM_TYPE_MPG &&
+	    buf != &cx->vbi.sliced_mpeg_buf)
+		cx->mpg_data_received += len;
+	return len;
+}
+
+static size_t cx18_copy_mdl_to_user(struct cx18_stream *s,
+		struct cx18_mdl *mdl, char __user *ubuf, size_t ucount)
+{
+	size_t tot_written = 0;
+	int rc;
+	bool stop = false;
+
+	if (mdl->curr_buf == NULL)
+		mdl->curr_buf = list_first_entry(&mdl->buf_list,
+						 struct cx18_buffer, list);
+
+	if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) {
+		/*
+		 * For some reason we've exhausted the buffers, but the MDL
+		 * object still said some data was unread.
+		 * Fix that and bail out.
+		 */
+		mdl->readpos = mdl->bytesused;
+		return 0;
+	}
+
+	list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) {
+
+		if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused)
+			continue;
+
+		rc = cx18_copy_buf_to_user(s, mdl->curr_buf, ubuf + tot_written,
+					   ucount - tot_written, &stop);
+		if (rc < 0)
+			return rc;
+		mdl->readpos += rc;
+		tot_written += rc;
+
+		if (stop ||	/* Forced stopping point for VBI insertion */
+		    tot_written >= ucount ||	/* Reader request statisfied */
+		    mdl->curr_buf->readpos < mdl->curr_buf->bytesused ||
+		    mdl->readpos >= mdl->bytesused) /* MDL buffers drained */
+			break;
+	}
+	return tot_written;
+}
+
+static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
+		size_t tot_count, int non_block)
+{
+	struct cx18 *cx = s->cx;
+	size_t tot_written = 0;
+	int single_frame = 0;
+
+	if (atomic_read(&cx->ana_capturing) == 0 && s->id == -1) {
+		/* shouldn't happen */
+		CX18_DEBUG_WARN("Stream %s not initialized before read\n",
+				s->name);
+		return -EIO;
+	}
+
+	/* Each VBI buffer is one frame, the v4l2 API says that for VBI the
+	   frames should arrive one-by-one, so make sure we never output more
+	   than one VBI frame at a time */
+	if (s->type == CX18_ENC_STREAM_TYPE_VBI && !cx18_raw_vbi(cx))
+		single_frame = 1;
+
+	for (;;) {
+		struct cx18_mdl *mdl;
+		int rc;
+
+		mdl = cx18_get_mdl(s, non_block, &rc);
+		/* if there is no data available... */
+		if (mdl == NULL) {
+			/* if we got data, then return that regardless */
+			if (tot_written)
+				break;
+			/* EOS condition */
+			if (rc == 0) {
+				clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+				clear_bit(CX18_F_S_APPL_IO, &s->s_flags);
+				cx18_release_stream(s);
+			}
+			/* set errno */
+			return rc;
+		}
+
+		rc = cx18_copy_mdl_to_user(s, mdl, ubuf + tot_written,
+				tot_count - tot_written);
+
+		if (mdl != &cx->vbi.sliced_mpeg_mdl) {
+			if (mdl->readpos == mdl->bytesused)
+				cx18_stream_put_mdl_fw(s, mdl);
+			else
+				cx18_push(s, mdl, &s->q_full);
+		} else if (mdl->readpos == mdl->bytesused) {
+			int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;
+
+			cx->vbi.sliced_mpeg_size[idx] = 0;
+			cx->vbi.inserted_frame++;
+			cx->vbi_data_inserted += mdl->bytesused;
+		}
+		if (rc < 0)
+			return rc;
+		tot_written += rc;
+
+		if (tot_written == tot_count || single_frame)
+			break;
+	}
+	return tot_written;
+}
+
+static ssize_t cx18_read_pos(struct cx18_stream *s, char __user *ubuf,
+		size_t count, loff_t *pos, int non_block)
+{
+	ssize_t rc = count ? cx18_read(s, ubuf, count, non_block) : 0;
+	struct cx18 *cx = s->cx;
+
+	CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc);
+	if (rc > 0)
+		pos += rc;
+	return rc;
+}
+
+int cx18_start_capture(struct cx18_open_id *id)
+{
+	struct cx18 *cx = id->cx;
+	struct cx18_stream *s = &cx->streams[id->type];
+	struct cx18_stream *s_vbi;
+	struct cx18_stream *s_idx;
+
+	if (s->type == CX18_ENC_STREAM_TYPE_RAD) {
+		/* you cannot read from these stream types. */
+		return -EPERM;
+	}
+
+	/* Try to claim this stream. */
+	if (cx18_claim_stream(id, s->type))
+		return -EBUSY;
+
+	/* If capture is already in progress, then we also have to
+	   do nothing extra. */
+	if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) ||
+	    test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+		set_bit(CX18_F_S_APPL_IO, &s->s_flags);
+		return 0;
+	}
+
+	/* Start associated VBI or IDX stream capture if required */
+	s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+	s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
+	if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
+		/*
+		 * The VBI and IDX streams should have been claimed
+		 * automatically, if for internal use, when the MPG stream was
+		 * claimed.  We only need to start these streams capturing.
+		 */
+		if (test_bit(CX18_F_S_INTERNAL_USE, &s_idx->s_flags) &&
+		    !test_and_set_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) {
+			if (cx18_start_v4l2_encode_stream(s_idx)) {
+				CX18_DEBUG_WARN("IDX capture start failed\n");
+				clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags);
+				goto start_failed;
+			}
+			CX18_DEBUG_INFO("IDX capture started\n");
+		}
+		if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
+		    !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) {
+			if (cx18_start_v4l2_encode_stream(s_vbi)) {
+				CX18_DEBUG_WARN("VBI capture start failed\n");
+				clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
+				goto start_failed;
+			}
+			CX18_DEBUG_INFO("VBI insertion started\n");
+		}
+	}
+
+	/* Tell the card to start capturing */
+	if (!cx18_start_v4l2_encode_stream(s)) {
+		/* We're done */
+		set_bit(CX18_F_S_APPL_IO, &s->s_flags);
+		/* Resume a possibly paused encoder */
+		if (test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+			cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, s->handle);
+		return 0;
+	}
+
+start_failed:
+	CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name);
+
+	/*
+	 * The associated VBI and IDX streams for internal use are released
+	 * automatically when the MPG stream is released.  We only need to stop
+	 * the associated stream.
+	 */
+	if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
+		/* Stop the IDX stream which is always for internal use */
+		if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) {
+			cx18_stop_v4l2_encode_stream(s_idx, 0);
+			clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags);
+		}
+		/* Stop the VBI stream, if only running for internal use */
+		if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) &&
+		    !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
+			cx18_stop_v4l2_encode_stream(s_vbi, 0);
+			clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
+		}
+	}
+	clear_bit(CX18_F_S_STREAMING, &s->s_flags);
+	cx18_release_stream(s); /* Also releases associated streams */
+	return -EIO;
+}
+
+ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
+		loff_t *pos)
+{
+	struct cx18_open_id *id = file2id(filp);
+	struct cx18 *cx = id->cx;
+	struct cx18_stream *s = &cx->streams[id->type];
+	int rc;
+
+	CX18_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);
+
+	mutex_lock(&cx->serialize_lock);
+	rc = cx18_start_capture(id);
+	mutex_unlock(&cx->serialize_lock);
+	if (rc)
+		return rc;
+
+	if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+		(id->type == CX18_ENC_STREAM_TYPE_YUV)) {
+		return videobuf_read_stream(&s->vbuf_q, buf, count, pos, 0,
+			filp->f_flags & O_NONBLOCK);
+	}
+
+	return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
+}
+
+unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
+{
+	struct cx18_open_id *id = file2id(filp);
+	struct cx18 *cx = id->cx;
+	struct cx18_stream *s = &cx->streams[id->type];
+	int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+
+	/* Start a capture if there is none */
+	if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+		int rc;
+
+		mutex_lock(&cx->serialize_lock);
+		rc = cx18_start_capture(id);
+		mutex_unlock(&cx->serialize_lock);
+		if (rc) {
+			CX18_DEBUG_INFO("Could not start capture for %s (%d)\n",
+					s->name, rc);
+			return POLLERR;
+		}
+		CX18_DEBUG_FILE("Encoder poll started capture\n");
+	}
+
+	if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+		(id->type == CX18_ENC_STREAM_TYPE_YUV)) {
+		int videobuf_poll = videobuf_poll_stream(filp, &s->vbuf_q, wait);
+                if (eof && videobuf_poll == POLLERR)
+                        return POLLHUP;
+                else
+                        return videobuf_poll;
+	}
+
+	/* add stream's waitq to the poll list */
+	CX18_DEBUG_HI_FILE("Encoder poll\n");
+	poll_wait(filp, &s->waitq, wait);
+
+	if (atomic_read(&s->q_full.depth))
+		return POLLIN | POLLRDNORM;
+	if (eof)
+		return POLLHUP;
+	return 0;
+}
+
+int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct cx18_open_id *id = file->private_data;
+	struct cx18 *cx = id->cx;
+	struct cx18_stream *s = &cx->streams[id->type];
+	int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+
+	if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+		(id->type == CX18_ENC_STREAM_TYPE_YUV)) {
+
+		/* Start a capture if there is none */
+		if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+			int rc;
+
+			mutex_lock(&cx->serialize_lock);
+			rc = cx18_start_capture(id);
+			mutex_unlock(&cx->serialize_lock);
+			if (rc) {
+				CX18_DEBUG_INFO(
+					"Could not start capture for %s (%d)\n",
+					s->name, rc);
+				return -EINVAL;
+			}
+			CX18_DEBUG_FILE("Encoder mmap started capture\n");
+		}
+
+		return videobuf_mmap_mapper(&s->vbuf_q, vma);
+	}
+
+	return -EINVAL;
+}
+
+void cx18_vb_timeout(unsigned long data)
+{
+	struct cx18_stream *s = (struct cx18_stream *)data;
+	struct cx18_videobuf_buffer *buf;
+	unsigned long flags;
+
+	/* Return all of the buffers in error state, so the vbi/vid inode
+	 * can return from blocking.
+	 */
+	spin_lock_irqsave(&s->vb_lock, flags);
+	while (!list_empty(&s->vb_capture)) {
+		buf = list_entry(s->vb_capture.next,
+			struct cx18_videobuf_buffer, vb.queue);
+		list_del(&buf->vb.queue);
+		buf->vb.state = VIDEOBUF_ERROR;
+		wake_up(&buf->vb.done);
+	}
+	spin_unlock_irqrestore(&s->vb_lock, flags);
+}
+
+void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
+{
+	struct cx18 *cx = id->cx;
+	struct cx18_stream *s = &cx->streams[id->type];
+	struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+	struct cx18_stream *s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
+
+	CX18_DEBUG_IOCTL("close() of %s\n", s->name);
+
+	/* 'Unclaim' this stream */
+
+	/* Stop capturing */
+	if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+		CX18_DEBUG_INFO("close stopping capture\n");
+		if (id->type == CX18_ENC_STREAM_TYPE_MPG) {
+			/* Stop internal use associated VBI and IDX streams */
+			if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) &&
+			    !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
+				CX18_DEBUG_INFO("close stopping embedded VBI "
+						"capture\n");
+				cx18_stop_v4l2_encode_stream(s_vbi, 0);
+			}
+			if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) {
+				CX18_DEBUG_INFO("close stopping IDX capture\n");
+				cx18_stop_v4l2_encode_stream(s_idx, 0);
+			}
+		}
+		if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
+		    test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags))
+			/* Also used internally, don't stop capturing */
+			s->id = -1;
+		else
+			cx18_stop_v4l2_encode_stream(s, gop_end);
+	}
+	if (!gop_end) {
+		clear_bit(CX18_F_S_APPL_IO, &s->s_flags);
+		clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+		cx18_release_stream(s);
+	}
+}
+
+int cx18_v4l2_close(struct file *filp)
+{
+	struct v4l2_fh *fh = filp->private_data;
+	struct cx18_open_id *id = fh2id(fh);
+	struct cx18 *cx = id->cx;
+	struct cx18_stream *s = &cx->streams[id->type];
+
+	CX18_DEBUG_IOCTL("close() of %s\n", s->name);
+
+	mutex_lock(&cx->serialize_lock);
+	/* Stop radio */
+	if (id->type == CX18_ENC_STREAM_TYPE_RAD &&
+			v4l2_fh_is_singular_file(filp)) {
+		/* Closing radio device, return to TV mode */
+		cx18_mute(cx);
+		/* Mark that the radio is no longer in use */
+		clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags);
+		/* Switch tuner to TV */
+		cx18_call_all(cx, core, s_std, cx->std);
+		/* Select correct audio input (i.e. TV tuner or Line in) */
+		cx18_audio_set_io(cx);
+		if (atomic_read(&cx->ana_capturing) > 0) {
+			/* Undo video mute */
+			cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
+			    (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute) |
+			    (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8)));
+		}
+		/* Done! Unmute and continue. */
+		cx18_unmute(cx);
+	}
+
+	v4l2_fh_del(fh);
+	v4l2_fh_exit(fh);
+
+	/* 'Unclaim' this stream */
+	if (s->id == id->open_id)
+		cx18_stop_capture(id, 0);
+	kfree(id);
+	mutex_unlock(&cx->serialize_lock);
+	return 0;
+}
+
+static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
+{
+	struct cx18 *cx = s->cx;
+	struct cx18_open_id *item;
+
+	CX18_DEBUG_FILE("open %s\n", s->name);
+
+	/* Allocate memory */
+	item = kzalloc(sizeof(struct cx18_open_id), GFP_KERNEL);
+	if (NULL == item) {
+		CX18_DEBUG_WARN("nomem on v4l2 open\n");
+		return -ENOMEM;
+	}
+	v4l2_fh_init(&item->fh, s->video_dev);
+
+	item->cx = cx;
+	item->type = s->type;
+
+	item->open_id = cx->open_id++;
+	filp->private_data = &item->fh;
+	v4l2_fh_add(&item->fh);
+
+	if (item->type == CX18_ENC_STREAM_TYPE_RAD &&
+			v4l2_fh_is_singular_file(filp)) {
+		if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+			if (atomic_read(&cx->ana_capturing) > 0) {
+				/* switching to radio while capture is
+				   in progress is not polite */
+				v4l2_fh_del(&item->fh);
+				v4l2_fh_exit(&item->fh);
+				kfree(item);
+				return -EBUSY;
+			}
+		}
+
+		/* Mark that the radio is being used. */
+		set_bit(CX18_F_I_RADIO_USER, &cx->i_flags);
+		/* We have the radio */
+		cx18_mute(cx);
+		/* Switch tuner to radio */
+		cx18_call_all(cx, tuner, s_radio);
+		/* Select the correct audio input (i.e. radio tuner) */
+		cx18_audio_set_io(cx);
+		/* Done! Unmute and continue. */
+		cx18_unmute(cx);
+	}
+	return 0;
+}
+
+int cx18_v4l2_open(struct file *filp)
+{
+	int res;
+	struct video_device *video_dev = video_devdata(filp);
+	struct cx18_stream *s = video_get_drvdata(video_dev);
+	struct cx18 *cx = s->cx;
+
+	mutex_lock(&cx->serialize_lock);
+	if (cx18_init_on_first_open(cx)) {
+		CX18_ERR("Failed to initialize on %s\n",
+			 video_device_node_name(video_dev));
+		mutex_unlock(&cx->serialize_lock);
+		return -ENXIO;
+	}
+	res = cx18_serialized_open(s, filp);
+	mutex_unlock(&cx->serialize_lock);
+	return res;
+}
+
+void cx18_mute(struct cx18 *cx)
+{
+	u32 h;
+	if (atomic_read(&cx->ana_capturing)) {
+		h = cx18_find_handle(cx);
+		if (h != CX18_INVALID_TASK_HANDLE)
+			cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 1);
+		else
+			CX18_ERR("Can't find valid task handle for mute\n");
+	}
+	CX18_DEBUG_INFO("Mute\n");
+}
+
+void cx18_unmute(struct cx18 *cx)
+{
+	u32 h;
+	if (atomic_read(&cx->ana_capturing)) {
+		h = cx18_find_handle(cx);
+		if (h != CX18_INVALID_TASK_HANDLE) {
+			cx18_msleep_timeout(100, 0);
+			cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, h, 12);
+			cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 0);
+		} else
+			CX18_ERR("Can't find valid task handle for unmute\n");
+	}
+	CX18_DEBUG_INFO("Unmute\n");
+}
diff --git a/drivers/media/pci/cx18/cx18-fileops.h b/drivers/media/pci/cx18/cx18-fileops.h
new file mode 100644
index 0000000..b9e5110
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-fileops.h
@@ -0,0 +1,41 @@
+/*
+ *  cx18 file operation functions
+ *
+ *  Derived from ivtv-fileops.h
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+/* Testing/Debugging */
+int cx18_v4l2_open(struct file *filp);
+ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
+		      loff_t *pos);
+ssize_t cx18_v4l2_write(struct file *filp, const char __user *buf, size_t count,
+		       loff_t *pos);
+int cx18_v4l2_close(struct file *filp);
+unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait);
+int cx18_start_capture(struct cx18_open_id *id);
+void cx18_stop_capture(struct cx18_open_id *id, int gop_end);
+void cx18_mute(struct cx18 *cx);
+void cx18_unmute(struct cx18 *cx);
+int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma);
+void cx18_vb_timeout(unsigned long data);
+
+/* Shared with cx18-alsa module */
+int cx18_claim_stream(struct cx18_open_id *id, int type);
+void cx18_release_stream(struct cx18_stream *s);
diff --git a/drivers/media/pci/cx18/cx18-firmware.c b/drivers/media/pci/cx18/cx18-firmware.c
new file mode 100644
index 0000000..a1c1cec
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-firmware.c
@@ -0,0 +1,459 @@
+/*
+ *  cx18 firmware functions
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-io.h"
+#include "cx18-scb.h"
+#include "cx18-irq.h"
+#include "cx18-firmware.h"
+#include "cx18-cards.h"
+#include <linux/firmware.h>
+
+#define CX18_PROC_SOFT_RESET 		0xc70010
+#define CX18_DDR_SOFT_RESET          	0xc70014
+#define CX18_CLOCK_SELECT1           	0xc71000
+#define CX18_CLOCK_SELECT2           	0xc71004
+#define CX18_HALF_CLOCK_SELECT1      	0xc71008
+#define CX18_HALF_CLOCK_SELECT2      	0xc7100C
+#define CX18_CLOCK_POLARITY1         	0xc71010
+#define CX18_CLOCK_POLARITY2         	0xc71014
+#define CX18_ADD_DELAY_ENABLE1       	0xc71018
+#define CX18_ADD_DELAY_ENABLE2       	0xc7101C
+#define CX18_CLOCK_ENABLE1           	0xc71020
+#define CX18_CLOCK_ENABLE2           	0xc71024
+
+#define CX18_REG_BUS_TIMEOUT_EN      	0xc72024
+
+#define CX18_FAST_CLOCK_PLL_INT      	0xc78000
+#define CX18_FAST_CLOCK_PLL_FRAC     	0xc78004
+#define CX18_FAST_CLOCK_PLL_POST     	0xc78008
+#define CX18_FAST_CLOCK_PLL_PRESCALE 	0xc7800C
+#define CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH 0xc78010
+
+#define CX18_SLOW_CLOCK_PLL_INT      	0xc78014
+#define CX18_SLOW_CLOCK_PLL_FRAC     	0xc78018
+#define CX18_SLOW_CLOCK_PLL_POST     	0xc7801C
+#define CX18_MPEG_CLOCK_PLL_INT		0xc78040
+#define CX18_MPEG_CLOCK_PLL_FRAC	0xc78044
+#define CX18_MPEG_CLOCK_PLL_POST	0xc78048
+#define CX18_PLL_POWER_DOWN          	0xc78088
+#define CX18_SW1_INT_STATUS             0xc73104
+#define CX18_SW1_INT_ENABLE_PCI         0xc7311C
+#define CX18_SW2_INT_SET                0xc73140
+#define CX18_SW2_INT_STATUS             0xc73144
+#define CX18_ADEC_CONTROL            	0xc78120
+
+#define CX18_DDR_REQUEST_ENABLE      	0xc80000
+#define CX18_DDR_CHIP_CONFIG         	0xc80004
+#define CX18_DDR_REFRESH            	0xc80008
+#define CX18_DDR_TIMING1             	0xc8000C
+#define CX18_DDR_TIMING2             	0xc80010
+#define CX18_DDR_POWER_REG		0xc8001C
+
+#define CX18_DDR_TUNE_LANE           	0xc80048
+#define CX18_DDR_INITIAL_EMRS        	0xc80054
+#define CX18_DDR_MB_PER_ROW_7        	0xc8009C
+#define CX18_DDR_BASE_63_ADDR        	0xc804FC
+
+#define CX18_WMB_CLIENT02            	0xc90108
+#define CX18_WMB_CLIENT05            	0xc90114
+#define CX18_WMB_CLIENT06            	0xc90118
+#define CX18_WMB_CLIENT07            	0xc9011C
+#define CX18_WMB_CLIENT08            	0xc90120
+#define CX18_WMB_CLIENT09            	0xc90124
+#define CX18_WMB_CLIENT10            	0xc90128
+#define CX18_WMB_CLIENT11            	0xc9012C
+#define CX18_WMB_CLIENT12            	0xc90130
+#define CX18_WMB_CLIENT13            	0xc90134
+#define CX18_WMB_CLIENT14            	0xc90138
+
+#define CX18_DSP0_INTERRUPT_MASK     	0xd0004C
+
+#define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */
+#define APU_ROM_SYNC2 0x72646548 /* "rdeH" */
+
+struct cx18_apu_rom_seghdr {
+	u32 sync1;
+	u32 sync2;
+	u32 addr;
+	u32 size;
+};
+
+static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx)
+{
+	const struct firmware *fw = NULL;
+	int i, j;
+	unsigned size;
+	u32 __iomem *dst = (u32 __iomem *)mem;
+	const u32 *src;
+
+	if (request_firmware(&fw, fn, &cx->pci_dev->dev)) {
+		CX18_ERR("Unable to open firmware %s\n", fn);
+		CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n");
+		return -ENOMEM;
+	}
+
+	src = (const u32 *)fw->data;
+
+	for (i = 0; i < fw->size; i += 4096) {
+		cx18_setup_page(cx, i);
+		for (j = i; j < fw->size && j < i + 4096; j += 4) {
+			/* no need for endianness conversion on the ppc */
+			cx18_raw_writel(cx, *src, dst);
+			if (cx18_raw_readl(cx, dst) != *src) {
+				CX18_ERR("Mismatch at offset %x\n", i);
+				release_firmware(fw);
+				cx18_setup_page(cx, 0);
+				return -EIO;
+			}
+			dst++;
+			src++;
+		}
+	}
+	if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
+		CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
+	size = fw->size;
+	release_firmware(fw);
+	cx18_setup_page(cx, SCB_OFFSET);
+	return size;
+}
+
+static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx,
+				u32 *entry_addr)
+{
+	const struct firmware *fw = NULL;
+	int i, j;
+	unsigned size;
+	const u32 *src;
+	struct cx18_apu_rom_seghdr seghdr;
+	const u8 *vers;
+	u32 offset = 0;
+	u32 apu_version = 0;
+	int sz;
+
+	if (request_firmware(&fw, fn, &cx->pci_dev->dev)) {
+		CX18_ERR("unable to open firmware %s\n", fn);
+		CX18_ERR("did you put the firmware in the hotplug firmware directory?\n");
+		cx18_setup_page(cx, 0);
+		return -ENOMEM;
+	}
+
+	*entry_addr = 0;
+	src = (const u32 *)fw->data;
+	vers = fw->data + sizeof(seghdr);
+	sz = fw->size;
+
+	apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32];
+	while (offset + sizeof(seghdr) < fw->size) {
+		const u32 *shptr = src + offset / 4;
+
+		seghdr.sync1 = le32_to_cpu(shptr[0]);
+		seghdr.sync2 = le32_to_cpu(shptr[1]);
+		seghdr.addr = le32_to_cpu(shptr[2]);
+		seghdr.size = le32_to_cpu(shptr[3]);
+
+		offset += sizeof(seghdr);
+		if (seghdr.sync1 != APU_ROM_SYNC1 ||
+		    seghdr.sync2 != APU_ROM_SYNC2) {
+			offset += seghdr.size;
+			continue;
+		}
+		CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr,
+				seghdr.addr + seghdr.size - 1);
+		if (*entry_addr == 0)
+			*entry_addr = seghdr.addr;
+		if (offset + seghdr.size > sz)
+			break;
+		for (i = 0; i < seghdr.size; i += 4096) {
+			cx18_setup_page(cx, seghdr.addr + i);
+			for (j = i; j < seghdr.size && j < i + 4096; j += 4) {
+				/* no need for endianness conversion on the ppc */
+				cx18_raw_writel(cx, src[(offset + j) / 4],
+						dst + seghdr.addr + j);
+				if (cx18_raw_readl(cx, dst + seghdr.addr + j)
+				    != src[(offset + j) / 4]) {
+					CX18_ERR("Mismatch at offset %x\n",
+						 offset + j);
+					release_firmware(fw);
+					cx18_setup_page(cx, 0);
+					return -EIO;
+				}
+			}
+		}
+		offset += seghdr.size;
+	}
+	if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
+		CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n",
+				fn, apu_version, fw->size);
+	size = fw->size;
+	release_firmware(fw);
+	cx18_setup_page(cx, 0);
+	return size;
+}
+
+void cx18_halt_firmware(struct cx18 *cx)
+{
+	CX18_DEBUG_INFO("Preparing for firmware halt.\n");
+	cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET,
+				  0x0000000F, 0x000F000F);
+	cx18_write_reg_expect(cx, 0x00020002, CX18_ADEC_CONTROL,
+				  0x00000002, 0x00020002);
+}
+
+void cx18_init_power(struct cx18 *cx, int lowpwr)
+{
+	/* power-down Spare and AOM PLLs */
+	/* power-up fast, slow and mpeg PLLs */
+	cx18_write_reg(cx, 0x00000008, CX18_PLL_POWER_DOWN);
+
+	/* ADEC out of sleep */
+	cx18_write_reg_expect(cx, 0x00020000, CX18_ADEC_CONTROL,
+				  0x00000000, 0x00020002);
+
+	/*
+	 * The PLL parameters are based on the external crystal frequency that
+	 * would ideally be:
+	 *
+	 * NTSC Color subcarrier freq * 8 =
+	 * 	4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
+	 *
+	 * The accidents of history and rationale that explain from where this
+	 * combination of magic numbers originate can be found in:
+	 *
+	 * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in
+	 * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80
+	 *
+	 * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the
+	 * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83
+	 *
+	 * As Mike Bradley has rightly pointed out, it's not the exact crystal
+	 * frequency that matters, only that all parts of the driver and
+	 * firmware are using the same value (close to the ideal value).
+	 *
+	 * Since I have a strong suspicion that, if the firmware ever assumes a
+	 * crystal value at all, it will assume 28.636360 MHz, the crystal
+	 * freq used in calculations in this driver will be:
+	 *
+	 *	xtal_freq = 28.636360 MHz
+	 *
+	 * an error of less than 0.13 ppm which is way, way better than any off
+	 * the shelf crystal will have for accuracy anyway.
+	 *
+	 * Below I aim to run the PLLs' VCOs near 400 MHz to minimze errors.
+	 *
+	 * Many thanks to Jeff Campbell and Mike Bradley for their extensive
+	 * investigation, experimentation, testing, and suggested solutions of
+	 * of audio/video sync problems with SVideo and CVBS captures.
+	 */
+
+	/* the fast clock is at 200/245 MHz */
+	/* 1 * xtal_freq * 0x0d.f7df9b8 / 2 = 200 MHz: 400 MHz pre post-divide*/
+	/* 1 * xtal_freq * 0x11.1c71eb8 / 2 = 245 MHz: 490 MHz pre post-divide*/
+	cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
+	cx18_write_reg(cx, lowpwr ? 0x1EFBF37 : 0x038E3D7,
+						CX18_FAST_CLOCK_PLL_FRAC);
+
+	cx18_write_reg(cx, 2, CX18_FAST_CLOCK_PLL_POST);
+	cx18_write_reg(cx, 1, CX18_FAST_CLOCK_PLL_PRESCALE);
+	cx18_write_reg(cx, 4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);
+
+	/* set slow clock to 125/120 MHz */
+	/* xtal_freq * 0x0d.1861a20 / 3 = 125 MHz: 375 MHz before post-divide */
+	/* xtal_freq * 0x0c.92493f8 / 3 = 120 MHz: 360 MHz before post-divide */
+	cx18_write_reg(cx, lowpwr ? 0xD : 0xC, CX18_SLOW_CLOCK_PLL_INT);
+	cx18_write_reg(cx, lowpwr ? 0x30C344 : 0x124927F,
+						CX18_SLOW_CLOCK_PLL_FRAC);
+	cx18_write_reg(cx, 3, CX18_SLOW_CLOCK_PLL_POST);
+
+	/* mpeg clock pll 54MHz */
+	/* xtal_freq * 0xf.15f17f0 / 8 = 54 MHz: 432 MHz before post-divide */
+	cx18_write_reg(cx, 0xF, CX18_MPEG_CLOCK_PLL_INT);
+	cx18_write_reg(cx, 0x2BE2FE, CX18_MPEG_CLOCK_PLL_FRAC);
+	cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST);
+
+	/* Defaults */
+	/* APU = SC or SC/2 = 125/62.5 */
+	/* EPU = SC = 125 */
+	/* DDR = FC = 180 */
+	/* ENC = SC = 125 */
+	/* AI1 = SC = 125 */
+	/* VIM2 = disabled */
+	/* PCI = FC/2 = 90 */
+	/* AI2 = disabled */
+	/* DEMUX = disabled */
+	/* AO = SC/2 = 62.5 */
+	/* SER = 54MHz */
+	/* VFC = disabled */
+	/* USB = disabled */
+
+	if (lowpwr) {
+		cx18_write_reg_expect(cx, 0xFFFF0020, CX18_CLOCK_SELECT1,
+					  0x00000020, 0xFFFFFFFF);
+		cx18_write_reg_expect(cx, 0xFFFF0004, CX18_CLOCK_SELECT2,
+					  0x00000004, 0xFFFFFFFF);
+	} else {
+		/* This doesn't explicitly set every clock select */
+		cx18_write_reg_expect(cx, 0x00060004, CX18_CLOCK_SELECT1,
+					  0x00000004, 0x00060006);
+		cx18_write_reg_expect(cx, 0x00060006, CX18_CLOCK_SELECT2,
+					  0x00000006, 0x00060006);
+	}
+
+	cx18_write_reg_expect(cx, 0xFFFF0002, CX18_HALF_CLOCK_SELECT1,
+				  0x00000002, 0xFFFFFFFF);
+	cx18_write_reg_expect(cx, 0xFFFF0104, CX18_HALF_CLOCK_SELECT2,
+				  0x00000104, 0xFFFFFFFF);
+	cx18_write_reg_expect(cx, 0xFFFF9026, CX18_CLOCK_ENABLE1,
+				  0x00009026, 0xFFFFFFFF);
+	cx18_write_reg_expect(cx, 0xFFFF3105, CX18_CLOCK_ENABLE2,
+				  0x00003105, 0xFFFFFFFF);
+}
+
+void cx18_init_memory(struct cx18 *cx)
+{
+	cx18_msleep_timeout(10, 0);
+	cx18_write_reg_expect(cx, 0x00010000, CX18_DDR_SOFT_RESET,
+				  0x00000000, 0x00010001);
+	cx18_msleep_timeout(10, 0);
+
+	cx18_write_reg(cx, cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG);
+
+	cx18_msleep_timeout(10, 0);
+
+	cx18_write_reg(cx, cx->card->ddr.refresh, CX18_DDR_REFRESH);
+	cx18_write_reg(cx, cx->card->ddr.timing1, CX18_DDR_TIMING1);
+	cx18_write_reg(cx, cx->card->ddr.timing2, CX18_DDR_TIMING2);
+
+	cx18_msleep_timeout(10, 0);
+
+	/* Initialize DQS pad time */
+	cx18_write_reg(cx, cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE);
+	cx18_write_reg(cx, cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS);
+
+	cx18_msleep_timeout(10, 0);
+
+	cx18_write_reg_expect(cx, 0x00020000, CX18_DDR_SOFT_RESET,
+				  0x00000000, 0x00020002);
+	cx18_msleep_timeout(10, 0);
+
+	/* use power-down mode when idle */
+	cx18_write_reg(cx, 0x00000010, CX18_DDR_POWER_REG);
+
+	cx18_write_reg_expect(cx, 0x00010001, CX18_REG_BUS_TIMEOUT_EN,
+				  0x00000001, 0x00010001);
+
+	cx18_write_reg(cx, 0x48, CX18_DDR_MB_PER_ROW_7);
+	cx18_write_reg(cx, 0xE0000, CX18_DDR_BASE_63_ADDR);
+
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT02);  /* AO */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT09);  /* AI2 */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT05);  /* VIM1 */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT06);  /* AI1 */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT07);  /* 3D comb */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT10);  /* ME */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT12);  /* ENC */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT13);  /* PK */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT11);  /* RC */
+	cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT14);  /* AVO */
+}
+
+#define CX18_CPU_FIRMWARE "v4l-cx23418-cpu.fw"
+#define CX18_APU_FIRMWARE "v4l-cx23418-apu.fw"
+
+int cx18_firmware_init(struct cx18 *cx)
+{
+	u32 fw_entry_addr;
+	int sz, retries;
+	u32 api_args[MAX_MB_ARGUMENTS];
+
+	/* Allow chip to control CLKRUN */
+	cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK);
+
+	/* Stop the firmware */
+	cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET,
+				  0x0000000F, 0x000F000F);
+
+	cx18_msleep_timeout(1, 0);
+
+	/* If the CPU is still running */
+	if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) == 0) {
+		CX18_ERR("%s: couldn't stop CPU to load firmware\n", __func__);
+		return -EIO;
+	}
+
+	cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+	cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+
+	sz = load_cpu_fw_direct(CX18_CPU_FIRMWARE, cx->enc_mem, cx);
+	if (sz <= 0)
+		return sz;
+
+	/* The SCB & IPC area *must* be correct before starting the firmwares */
+	cx18_init_scb(cx);
+
+	fw_entry_addr = 0;
+	sz = load_apu_fw_direct(CX18_APU_FIRMWARE, cx->enc_mem, cx,
+				&fw_entry_addr);
+	if (sz <= 0)
+		return sz;
+
+	/* Start the CPU. The CPU will take care of the APU for us. */
+	cx18_write_reg_expect(cx, 0x00080000, CX18_PROC_SOFT_RESET,
+				  0x00000000, 0x00080008);
+
+	/* Wait up to 500 ms for the APU to come out of reset */
+	for (retries = 0;
+	     retries < 50 && (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1;
+	     retries++)
+		cx18_msleep_timeout(10, 0);
+
+	cx18_msleep_timeout(200, 0);
+
+	if (retries == 50 &&
+	    (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1) {
+		CX18_ERR("Could not start the CPU\n");
+		return -EIO;
+	}
+
+	/*
+	 * The CPU had once before set up to receive an interrupt for it's
+	 * outgoing IRQ_CPU_TO_EPU_ACK to us.  If it ever does this, we get an
+	 * interrupt when it sends us an ack, but by the time we process it,
+	 * that flag in the SW2 status register has been cleared by the CPU
+	 * firmware.  We'll prevent that not so useful condition from happening
+	 * by clearing the CPU's interrupt enables for Ack IRQ's we want to
+	 * process.
+	 */
+	cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+
+	/* Try a benign command to see if the CPU is alive and well */
+	sz = cx18_vapi_result(cx, api_args, CX18_CPU_DEBUG_PEEK32, 1, 0);
+	if (sz < 0)
+		return sz;
+
+	/* initialize GPIO */
+	cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400);
+	return 0;
+}
+
+MODULE_FIRMWARE(CX18_CPU_FIRMWARE);
+MODULE_FIRMWARE(CX18_APU_FIRMWARE);
diff --git a/drivers/media/pci/cx18/cx18-firmware.h b/drivers/media/pci/cx18/cx18-firmware.h
new file mode 100644
index 0000000..38d4c05
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-firmware.h
@@ -0,0 +1,25 @@
+/*
+ *  cx18 firmware functions
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+int cx18_firmware_init(struct cx18 *cx);
+void cx18_halt_firmware(struct cx18 *cx);
+void cx18_init_memory(struct cx18 *cx);
+void cx18_init_power(struct cx18 *cx, int lowpwr);
diff --git a/drivers/media/pci/cx18/cx18-gpio.c b/drivers/media/pci/cx18/cx18-gpio.c
new file mode 100644
index 0000000..5374aeb
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-gpio.c
@@ -0,0 +1,347 @@
+/*
+ *  cx18 gpio functions
+ *
+ *  Derived from ivtv-gpio.c
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-io.h"
+#include "cx18-cards.h"
+#include "cx18-gpio.h"
+#include "tuner-xc2028.h"
+
+/********************* GPIO stuffs *********************/
+
+/* GPIO registers */
+#define CX18_REG_GPIO_IN     0xc72010
+#define CX18_REG_GPIO_OUT1   0xc78100
+#define CX18_REG_GPIO_DIR1   0xc78108
+#define CX18_REG_GPIO_OUT2   0xc78104
+#define CX18_REG_GPIO_DIR2   0xc7810c
+
+/*
+ * HVR-1600 GPIO pins, courtesy of Hauppauge:
+ *
+ * gpio0: zilog ir process reset pin
+ * gpio1: zilog programming pin (you should never use this)
+ * gpio12: cx24227 reset pin
+ * gpio13: cs5345 reset pin
+*/
+
+/*
+ * File scope utility functions
+ */
+static void gpio_write(struct cx18 *cx)
+{
+	u32 dir_lo = cx->gpio_dir & 0xffff;
+	u32 val_lo = cx->gpio_val & 0xffff;
+	u32 dir_hi = cx->gpio_dir >> 16;
+	u32 val_hi = cx->gpio_val >> 16;
+
+	cx18_write_reg_expect(cx, dir_lo << 16,
+					CX18_REG_GPIO_DIR1, ~dir_lo, dir_lo);
+	cx18_write_reg_expect(cx, (dir_lo << 16) | val_lo,
+					CX18_REG_GPIO_OUT1, val_lo, dir_lo);
+	cx18_write_reg_expect(cx, dir_hi << 16,
+					CX18_REG_GPIO_DIR2, ~dir_hi, dir_hi);
+	cx18_write_reg_expect(cx, (dir_hi << 16) | val_hi,
+					CX18_REG_GPIO_OUT2, val_hi, dir_hi);
+}
+
+static void gpio_update(struct cx18 *cx, u32 mask, u32 data)
+{
+	if (mask == 0)
+		return;
+
+	mutex_lock(&cx->gpio_lock);
+	cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask);
+	gpio_write(cx);
+	mutex_unlock(&cx->gpio_lock);
+}
+
+static void gpio_reset_seq(struct cx18 *cx, u32 active_lo, u32 active_hi,
+			   unsigned int assert_msecs,
+			   unsigned int recovery_msecs)
+{
+	u32 mask;
+
+	mask = active_lo | active_hi;
+	if (mask == 0)
+		return;
+
+	/*
+	 * Assuming that active_hi and active_lo are a subsets of the bits in
+	 * gpio_dir.  Also assumes that active_lo and active_hi don't overlap
+	 * in any bit position
+	 */
+
+	/* Assert */
+	gpio_update(cx, mask, ~active_lo);
+	schedule_timeout_uninterruptible(msecs_to_jiffies(assert_msecs));
+
+	/* Deassert */
+	gpio_update(cx, mask, ~active_hi);
+	schedule_timeout_uninterruptible(msecs_to_jiffies(recovery_msecs));
+}
+
+/*
+ * GPIO Multiplexer - logical device
+ */
+static int gpiomux_log_status(struct v4l2_subdev *sd)
+{
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+	mutex_lock(&cx->gpio_lock);
+	CX18_INFO_DEV(sd, "GPIO:  direction 0x%08x, value 0x%08x\n",
+		      cx->gpio_dir, cx->gpio_val);
+	mutex_unlock(&cx->gpio_lock);
+	return 0;
+}
+
+static int gpiomux_s_radio(struct v4l2_subdev *sd)
+{
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+	/*
+	 * FIXME - work out the cx->active/audio_input mess - this is
+	 * intended to handle the switch to radio mode and set the
+	 * audio routing, but we need to update the state in cx
+	 */
+	gpio_update(cx, cx->card->gpio_audio_input.mask,
+			cx->card->gpio_audio_input.radio);
+	return 0;
+}
+
+static int gpiomux_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+	u32 data;
+
+	switch (cx->card->audio_inputs[cx->audio_input].muxer_input) {
+	case 1:
+		data = cx->card->gpio_audio_input.linein;
+		break;
+	case 0:
+		data = cx->card->gpio_audio_input.tuner;
+		break;
+	default:
+		/*
+		 * FIXME - work out the cx->active/audio_input mess - this is
+		 * intended to handle the switch from radio mode and set the
+		 * audio routing, but we need to update the state in cx
+		 */
+		data = cx->card->gpio_audio_input.tuner;
+		break;
+	}
+	gpio_update(cx, cx->card->gpio_audio_input.mask, data);
+	return 0;
+}
+
+static int gpiomux_s_audio_routing(struct v4l2_subdev *sd,
+				   u32 input, u32 output, u32 config)
+{
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+	u32 data;
+
+	switch (input) {
+	case 0:
+		data = cx->card->gpio_audio_input.tuner;
+		break;
+	case 1:
+		data = cx->card->gpio_audio_input.linein;
+		break;
+	case 2:
+		data = cx->card->gpio_audio_input.radio;
+		break;
+	default:
+		return -EINVAL;
+	}
+	gpio_update(cx, cx->card->gpio_audio_input.mask, data);
+	return 0;
+}
+
+static const struct v4l2_subdev_core_ops gpiomux_core_ops = {
+	.log_status = gpiomux_log_status,
+	.s_std = gpiomux_s_std,
+};
+
+static const struct v4l2_subdev_tuner_ops gpiomux_tuner_ops = {
+	.s_radio = gpiomux_s_radio,
+};
+
+static const struct v4l2_subdev_audio_ops gpiomux_audio_ops = {
+	.s_routing = gpiomux_s_audio_routing,
+};
+
+static const struct v4l2_subdev_ops gpiomux_ops = {
+	.core = &gpiomux_core_ops,
+	.tuner = &gpiomux_tuner_ops,
+	.audio = &gpiomux_audio_ops,
+};
+
+/*
+ * GPIO Reset Controller - logical device
+ */
+static int resetctrl_log_status(struct v4l2_subdev *sd)
+{
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+	mutex_lock(&cx->gpio_lock);
+	CX18_INFO_DEV(sd, "GPIO:  direction 0x%08x, value 0x%08x\n",
+		      cx->gpio_dir, cx->gpio_val);
+	mutex_unlock(&cx->gpio_lock);
+	return 0;
+}
+
+static int resetctrl_reset(struct v4l2_subdev *sd, u32 val)
+{
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+	const struct cx18_gpio_i2c_slave_reset *p;
+
+	p = &cx->card->gpio_i2c_slave_reset;
+	switch (val) {
+	case CX18_GPIO_RESET_I2C:
+		gpio_reset_seq(cx, p->active_lo_mask, p->active_hi_mask,
+			       p->msecs_asserted, p->msecs_recovery);
+		break;
+	case CX18_GPIO_RESET_Z8F0811:
+		/*
+		 * Assert timing for the Z8F0811 on HVR-1600 boards:
+		 * 1. Assert RESET for min of 4 clock cycles at 18.432 MHz to
+		 *    initiate
+		 * 2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock
+		 *    cycles (6,601,085 nanoseconds ~= 7 milliseconds)
+		 * 3. DBG pin must be high before chip exits reset for normal
+		 *    operation.  DBG is open drain and hopefully pulled high
+		 *    since we don't normally drive it (GPIO 1?) for the
+		 *    HVR-1600
+		 * 4. Z8F0811 won't exit reset until RESET is deasserted
+		 * 5. Zilog comes out of reset, loads reset vector address and
+		 *    executes from there. Required recovery delay unknown.
+		 */
+		gpio_reset_seq(cx, p->ir_reset_mask, 0,
+			       p->msecs_asserted, p->msecs_recovery);
+		break;
+	case CX18_GPIO_RESET_XC2028:
+		if (cx->card->tuners[0].tuner == TUNER_XC2028)
+			gpio_reset_seq(cx, (1 << cx->card->xceive_pin), 0,
+				       1, 1);
+		break;
+	}
+	return 0;
+}
+
+static const struct v4l2_subdev_core_ops resetctrl_core_ops = {
+	.log_status = resetctrl_log_status,
+	.reset = resetctrl_reset,
+};
+
+static const struct v4l2_subdev_ops resetctrl_ops = {
+	.core = &resetctrl_core_ops,
+};
+
+/*
+ * External entry points
+ */
+void cx18_gpio_init(struct cx18 *cx)
+{
+	mutex_lock(&cx->gpio_lock);
+	cx->gpio_dir = cx->card->gpio_init.direction;
+	cx->gpio_val = cx->card->gpio_init.initial_value;
+
+	if (cx->card->tuners[0].tuner == TUNER_XC2028) {
+		cx->gpio_dir |= 1 << cx->card->xceive_pin;
+		cx->gpio_val |= 1 << cx->card->xceive_pin;
+	}
+
+	if (cx->gpio_dir == 0) {
+		mutex_unlock(&cx->gpio_lock);
+		return;
+	}
+
+	CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n",
+			cx18_read_reg(cx, CX18_REG_GPIO_DIR1),
+			cx18_read_reg(cx, CX18_REG_GPIO_DIR2),
+			cx18_read_reg(cx, CX18_REG_GPIO_OUT1),
+			cx18_read_reg(cx, CX18_REG_GPIO_OUT2));
+
+	gpio_write(cx);
+	mutex_unlock(&cx->gpio_lock);
+}
+
+int cx18_gpio_register(struct cx18 *cx, u32 hw)
+{
+	struct v4l2_subdev *sd;
+	const struct v4l2_subdev_ops *ops;
+	char *str;
+
+	switch (hw) {
+	case CX18_HW_GPIO_MUX:
+		sd = &cx->sd_gpiomux;
+		ops = &gpiomux_ops;
+		str = "gpio-mux";
+		break;
+	case CX18_HW_GPIO_RESET_CTRL:
+		sd = &cx->sd_resetctrl;
+		ops = &resetctrl_ops;
+		str = "gpio-reset-ctrl";
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	v4l2_subdev_init(sd, ops);
+	v4l2_set_subdevdata(sd, cx);
+	snprintf(sd->name, sizeof(sd->name), "%s %s", cx->v4l2_dev.name, str);
+	sd->grp_id = hw;
+	return v4l2_device_register_subdev(&cx->v4l2_dev, sd);
+}
+
+void cx18_reset_ir_gpio(void *data)
+{
+	struct cx18 *cx = to_cx18((struct v4l2_device *)data);
+
+	if (cx->card->gpio_i2c_slave_reset.ir_reset_mask == 0)
+		return;
+
+	CX18_DEBUG_INFO("Resetting IR microcontroller\n");
+
+	v4l2_subdev_call(&cx->sd_resetctrl,
+			 core, reset, CX18_GPIO_RESET_Z8F0811);
+}
+EXPORT_SYMBOL(cx18_reset_ir_gpio);
+/* This symbol is exported for use by lirc_pvr150 for the IR-blaster */
+
+/* Xceive tuner reset function */
+int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value)
+{
+	struct i2c_algo_bit_data *algo = dev;
+	struct cx18_i2c_algo_callback_data *cb_data = algo->data;
+	struct cx18 *cx = cb_data->cx;
+
+	if (cmd != XC2028_TUNER_RESET ||
+	    cx->card->tuners[0].tuner != TUNER_XC2028)
+		return 0;
+
+	CX18_DEBUG_INFO("Resetting XCeive tuner\n");
+	return v4l2_subdev_call(&cx->sd_resetctrl,
+				core, reset, CX18_GPIO_RESET_XC2028);
+}
diff --git a/drivers/media/pci/cx18/cx18-gpio.h b/drivers/media/pci/cx18/cx18-gpio.h
new file mode 100644
index 0000000..4aea2ef
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-gpio.h
@@ -0,0 +1,34 @@
+/*
+ *  cx18 gpio functions
+ *
+ *  Derived from ivtv-gpio.h
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+void cx18_gpio_init(struct cx18 *cx);
+int cx18_gpio_register(struct cx18 *cx, u32 hw);
+
+enum cx18_gpio_reset_type {
+	CX18_GPIO_RESET_I2C     = 0,
+	CX18_GPIO_RESET_Z8F0811 = 1,
+	CX18_GPIO_RESET_XC2028  = 2,
+};
+
+void cx18_reset_ir_gpio(void *data);
+int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value);
diff --git a/drivers/media/pci/cx18/cx18-i2c.c b/drivers/media/pci/cx18/cx18-i2c.c
new file mode 100644
index 0000000..51609d5
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-i2c.c
@@ -0,0 +1,330 @@
+/*
+ *  cx18 I2C functions
+ *
+ *  Derived from ivtv-i2c.c
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-io.h"
+#include "cx18-cards.h"
+#include "cx18-gpio.h"
+#include "cx18-i2c.h"
+#include "cx18-irq.h"
+
+#define CX18_REG_I2C_1_WR   0xf15000
+#define CX18_REG_I2C_1_RD   0xf15008
+#define CX18_REG_I2C_2_WR   0xf25100
+#define CX18_REG_I2C_2_RD   0xf25108
+
+#define SETSCL_BIT      0x0001
+#define SETSDL_BIT      0x0002
+#define GETSCL_BIT      0x0004
+#define GETSDL_BIT      0x0008
+
+#define CX18_CS5345_I2C_ADDR		0x4c
+#define CX18_Z8F0811_IR_TX_I2C_ADDR	0x70
+#define CX18_Z8F0811_IR_RX_I2C_ADDR	0x71
+
+/* This array should match the CX18_HW_ defines */
+static const u8 hw_addrs[] = {
+	0,				/* CX18_HW_TUNER */
+	0,				/* CX18_HW_TVEEPROM */
+	CX18_CS5345_I2C_ADDR,		/* CX18_HW_CS5345 */
+	0,				/* CX18_HW_DVB */
+	0,				/* CX18_HW_418_AV */
+	0,				/* CX18_HW_GPIO_MUX */
+	0,				/* CX18_HW_GPIO_RESET_CTRL */
+	CX18_Z8F0811_IR_TX_I2C_ADDR,	/* CX18_HW_Z8F0811_IR_TX_HAUP */
+	CX18_Z8F0811_IR_RX_I2C_ADDR,	/* CX18_HW_Z8F0811_IR_RX_HAUP */
+};
+
+/* This array should match the CX18_HW_ defines */
+/* This might well become a card-specific array */
+static const u8 hw_bus[] = {
+	1,	/* CX18_HW_TUNER */
+	0,	/* CX18_HW_TVEEPROM */
+	0,	/* CX18_HW_CS5345 */
+	0,	/* CX18_HW_DVB */
+	0,	/* CX18_HW_418_AV */
+	0,	/* CX18_HW_GPIO_MUX */
+	0,	/* CX18_HW_GPIO_RESET_CTRL */
+	0,	/* CX18_HW_Z8F0811_IR_TX_HAUP */
+	0,	/* CX18_HW_Z8F0811_IR_RX_HAUP */
+};
+
+/* This array should match the CX18_HW_ defines */
+static const char * const hw_devicenames[] = {
+	"tuner",
+	"tveeprom",
+	"cs5345",
+	"cx23418_DTV",
+	"cx23418_AV",
+	"gpio_mux",
+	"gpio_reset_ctrl",
+	"ir_tx_z8f0811_haup",
+	"ir_rx_z8f0811_haup",
+};
+
+static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw,
+			   const char *type, u8 addr)
+{
+	struct i2c_board_info info;
+	struct IR_i2c_init_data *init_data = &cx->ir_i2c_init_data;
+	unsigned short addr_list[2] = { addr, I2C_CLIENT_END };
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	strlcpy(info.type, type, I2C_NAME_SIZE);
+
+	/* Our default information for ir-kbd-i2c.c to use */
+	switch (hw) {
+	case CX18_HW_Z8F0811_IR_RX_HAUP:
+		init_data->ir_codes = RC_MAP_HAUPPAUGE;
+		init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+		init_data->type = RC_TYPE_RC5;
+		init_data->name = cx->card_name;
+		info.platform_data = init_data;
+		break;
+	}
+
+	return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ?
+	       -1 : 0;
+}
+
+int cx18_i2c_register(struct cx18 *cx, unsigned idx)
+{
+	struct v4l2_subdev *sd;
+	int bus = hw_bus[idx];
+	struct i2c_adapter *adap = &cx->i2c_adap[bus];
+	const char *type = hw_devicenames[idx];
+	u32 hw = 1 << idx;
+
+	if (idx >= ARRAY_SIZE(hw_addrs))
+		return -1;
+
+	if (hw == CX18_HW_TUNER) {
+		/* special tuner group handling */
+		sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
+				adap, type, 0, cx->card_i2c->radio);
+		if (sd != NULL)
+			sd->grp_id = hw;
+		sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
+				adap, type, 0, cx->card_i2c->demod);
+		if (sd != NULL)
+			sd->grp_id = hw;
+		sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
+				adap, type, 0, cx->card_i2c->tv);
+		if (sd != NULL)
+			sd->grp_id = hw;
+		return sd != NULL ? 0 : -1;
+	}
+
+	if (hw & CX18_HW_IR_ANY)
+		return cx18_i2c_new_ir(cx, adap, hw, type, hw_addrs[idx]);
+
+	/* Is it not an I2C device or one we do not wish to register? */
+	if (!hw_addrs[idx])
+		return -1;
+
+	/* It's an I2C device other than an analog tuner or IR chip */
+	sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, type, hw_addrs[idx],
+				 NULL);
+	if (sd != NULL)
+		sd->grp_id = hw;
+	return sd != NULL ? 0 : -1;
+}
+
+/* Find the first member of the subdev group id in hw */
+struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw)
+{
+	struct v4l2_subdev *result = NULL;
+	struct v4l2_subdev *sd;
+
+	spin_lock(&cx->v4l2_dev.lock);
+	v4l2_device_for_each_subdev(sd, &cx->v4l2_dev) {
+		if (sd->grp_id == hw) {
+			result = sd;
+			break;
+		}
+	}
+	spin_unlock(&cx->v4l2_dev.lock);
+	return result;
+}
+
+static void cx18_setscl(void *data, int state)
+{
+	struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+	int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
+	u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
+	u32 r = cx18_read_reg(cx, addr);
+
+	if (state)
+		cx18_write_reg(cx, r | SETSCL_BIT, addr);
+	else
+		cx18_write_reg(cx, r & ~SETSCL_BIT, addr);
+}
+
+static void cx18_setsda(void *data, int state)
+{
+	struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+	int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
+	u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
+	u32 r = cx18_read_reg(cx, addr);
+
+	if (state)
+		cx18_write_reg(cx, r | SETSDL_BIT, addr);
+	else
+		cx18_write_reg(cx, r & ~SETSDL_BIT, addr);
+}
+
+static int cx18_getscl(void *data)
+{
+	struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+	int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
+	u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
+
+	return cx18_read_reg(cx, addr) & GETSCL_BIT;
+}
+
+static int cx18_getsda(void *data)
+{
+	struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+	int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
+	u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
+
+	return cx18_read_reg(cx, addr) & GETSDL_BIT;
+}
+
+/* template for i2c-bit-algo */
+static struct i2c_adapter cx18_i2c_adap_template = {
+	.name = "cx18 i2c driver",
+	.algo = NULL,                   /* set by i2c-algo-bit */
+	.algo_data = NULL,              /* filled from template */
+	.owner = THIS_MODULE,
+};
+
+#define CX18_SCL_PERIOD (10) /* usecs. 10 usec is period for a 100 KHz clock */
+#define CX18_ALGO_BIT_TIMEOUT (2) /* seconds */
+
+static struct i2c_algo_bit_data cx18_i2c_algo_template = {
+	.setsda		= cx18_setsda,
+	.setscl		= cx18_setscl,
+	.getsda		= cx18_getsda,
+	.getscl		= cx18_getscl,
+	.udelay		= CX18_SCL_PERIOD/2,       /* 1/2 clock period in usec*/
+	.timeout	= CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */
+};
+
+/* init + register i2c adapter */
+int init_cx18_i2c(struct cx18 *cx)
+{
+	int i, err;
+	CX18_DEBUG_I2C("i2c init\n");
+
+	for (i = 0; i < 2; i++) {
+		/* Setup algorithm for adapter */
+		memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template,
+			sizeof(struct i2c_algo_bit_data));
+		cx->i2c_algo_cb_data[i].cx = cx;
+		cx->i2c_algo_cb_data[i].bus_index = i;
+		cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i];
+
+		/* Setup adapter */
+		memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
+			sizeof(struct i2c_adapter));
+		cx->i2c_adap[i].algo_data = &cx->i2c_algo[i];
+		sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name),
+				" #%d-%d", cx->instance, i);
+		i2c_set_adapdata(&cx->i2c_adap[i], &cx->v4l2_dev);
+		cx->i2c_adap[i].dev.parent = &cx->pci_dev->dev;
+	}
+
+	if (cx18_read_reg(cx, CX18_REG_I2C_2_WR) != 0x0003c02f) {
+		/* Reset/Unreset I2C hardware block */
+		/* Clock select 220MHz */
+		cx18_write_reg_expect(cx, 0x10000000, 0xc71004,
+					  0x00000000, 0x10001000);
+		/* Clock Enable */
+		cx18_write_reg_expect(cx, 0x10001000, 0xc71024,
+					  0x00001000, 0x10001000);
+	}
+	/* courtesy of Steven Toth <stoth@hauppauge.com> */
+	cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0);
+	mdelay(10);
+	cx18_write_reg_expect(cx, 0x00c000c0, 0xc7001c, 0x000000c0, 0x00c000c0);
+	mdelay(10);
+	cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0);
+	mdelay(10);
+
+	/* Set to edge-triggered intrs. */
+	cx18_write_reg(cx, 0x00c00000, 0xc730c8);
+	/* Clear any stale intrs */
+	cx18_write_reg_expect(cx, HW2_I2C1_INT|HW2_I2C2_INT, HW2_INT_CLR_STATUS,
+		       ~(HW2_I2C1_INT|HW2_I2C2_INT), HW2_I2C1_INT|HW2_I2C2_INT);
+
+	/* Hw I2C1 Clock Freq ~100kHz */
+	cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_1_WR);
+	cx18_setscl(&cx->i2c_algo_cb_data[0], 1);
+	cx18_setsda(&cx->i2c_algo_cb_data[0], 1);
+
+	/* Hw I2C2 Clock Freq ~100kHz */
+	cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_2_WR);
+	cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
+	cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
+
+	cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL,
+		     core, reset, (u32) CX18_GPIO_RESET_I2C);
+
+	err = i2c_bit_add_bus(&cx->i2c_adap[0]);
+	if (err)
+		goto err;
+	err = i2c_bit_add_bus(&cx->i2c_adap[1]);
+	if (err)
+		goto err_del_bus_0;
+	return 0;
+
+ err_del_bus_0:
+	i2c_del_adapter(&cx->i2c_adap[0]);
+ err:
+	return err;
+}
+
+void exit_cx18_i2c(struct cx18 *cx)
+{
+	int i;
+	CX18_DEBUG_I2C("i2c exit\n");
+	cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_1_WR) | 4,
+							CX18_REG_I2C_1_WR);
+	cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_2_WR) | 4,
+							CX18_REG_I2C_2_WR);
+
+	for (i = 0; i < 2; i++) {
+		i2c_del_adapter(&cx->i2c_adap[i]);
+	}
+}
+
+/*
+   Hauppauge HVR1600 should have:
+   32 cx24227
+   98 unknown
+   a0 eeprom
+   c2 tuner
+   e? zilog ir
+   */
diff --git a/drivers/media/pci/cx18/cx18-i2c.h b/drivers/media/pci/cx18/cx18-i2c.h
new file mode 100644
index 0000000..1180fdc
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-i2c.h
@@ -0,0 +1,29 @@
+/*
+ *  cx18 I2C functions
+ *
+ *  Derived from ivtv-i2c.h
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+int cx18_i2c_register(struct cx18 *cx, unsigned idx);
+struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw);
+
+/* init + register i2c adapter */
+int init_cx18_i2c(struct cx18 *cx);
+void exit_cx18_i2c(struct cx18 *cx);
diff --git a/drivers/media/pci/cx18/cx18-io.c b/drivers/media/pci/cx18/cx18-io.c
new file mode 100644
index 0000000..49b9dbd
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-io.c
@@ -0,0 +1,97 @@
+/*
+ *  cx18 driver PCI memory mapped IO access routines
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-io.h"
+#include "cx18-irq.h"
+
+void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count)
+{
+	u8 __iomem *dst = addr;
+	u16 val2 = val | (val << 8);
+	u32 val4 = val2 | (val2 << 16);
+
+	/* Align writes on the CX23418's addresses */
+	if ((count > 0) && ((unsigned long)dst & 1)) {
+		cx18_writeb(cx, (u8) val, dst);
+		count--;
+		dst++;
+	}
+	if ((count > 1) && ((unsigned long)dst & 2)) {
+		cx18_writew(cx, val2, dst);
+		count -= 2;
+		dst += 2;
+	}
+	while (count > 3) {
+		cx18_writel(cx, val4, dst);
+		count -= 4;
+		dst += 4;
+	}
+	if (count > 1) {
+		cx18_writew(cx, val2, dst);
+		count -= 2;
+		dst += 2;
+	}
+	if (count > 0)
+		cx18_writeb(cx, (u8) val, dst);
+}
+
+void cx18_sw1_irq_enable(struct cx18 *cx, u32 val)
+{
+	cx18_write_reg_expect(cx, val, SW1_INT_STATUS, ~val, val);
+	cx->sw1_irq_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) | val;
+	cx18_write_reg(cx, cx->sw1_irq_mask, SW1_INT_ENABLE_PCI);
+}
+
+void cx18_sw1_irq_disable(struct cx18 *cx, u32 val)
+{
+	cx->sw1_irq_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) & ~val;
+	cx18_write_reg(cx, cx->sw1_irq_mask, SW1_INT_ENABLE_PCI);
+}
+
+void cx18_sw2_irq_enable(struct cx18 *cx, u32 val)
+{
+	cx18_write_reg_expect(cx, val, SW2_INT_STATUS, ~val, val);
+	cx->sw2_irq_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) | val;
+	cx18_write_reg(cx, cx->sw2_irq_mask, SW2_INT_ENABLE_PCI);
+}
+
+void cx18_sw2_irq_disable(struct cx18 *cx, u32 val)
+{
+	cx->sw2_irq_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) & ~val;
+	cx18_write_reg(cx, cx->sw2_irq_mask, SW2_INT_ENABLE_PCI);
+}
+
+void cx18_sw2_irq_disable_cpu(struct cx18 *cx, u32 val)
+{
+	u32 r;
+	r = cx18_read_reg(cx, SW2_INT_ENABLE_CPU);
+	cx18_write_reg(cx, r & ~val, SW2_INT_ENABLE_CPU);
+}
+
+void cx18_setup_page(struct cx18 *cx, u32 addr)
+{
+	u32 val;
+	val = cx18_read_reg(cx, 0xD000F8);
+	val = (val & ~0x1f00) | ((addr >> 17) & 0x1f00);
+	cx18_write_reg(cx, val, 0xD000F8);
+}
diff --git a/drivers/media/pci/cx18/cx18-io.h b/drivers/media/pci/cx18/cx18-io.h
new file mode 100644
index 0000000..18974d8
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-io.h
@@ -0,0 +1,191 @@
+/*
+ *  cx18 driver PCI memory mapped IO access routines
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#ifndef CX18_IO_H
+#define CX18_IO_H
+
+#include "cx18-driver.h"
+
+/*
+ * Readback and retry of MMIO access for reliability:
+ * The concept was suggested by Steve Toth <stoth@linuxtv.org>.
+ * The implmentation is the fault of Andy Walls <awalls@md.metrocast.net>.
+ *
+ * *write* functions are implied to retry the mmio unless suffixed with _noretry
+ * *read* functions never retry the mmio (it never helps to do so)
+ */
+
+/* Non byteswapping memory mapped IO */
+static inline u32 cx18_raw_readl(struct cx18 *cx, const void __iomem *addr)
+{
+	return __raw_readl(addr);
+}
+
+static inline
+void cx18_raw_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+	__raw_writel(val, addr);
+}
+
+static inline void cx18_raw_writel(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+	int i;
+	for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) {
+		cx18_raw_writel_noretry(cx, val, addr);
+		if (val == cx18_raw_readl(cx, addr))
+			break;
+	}
+}
+
+/* Normal memory mapped IO */
+static inline u32 cx18_readl(struct cx18 *cx, const void __iomem *addr)
+{
+	return readl(addr);
+}
+
+static inline
+void cx18_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+	writel(val, addr);
+}
+
+static inline void cx18_writel(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+	int i;
+	for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) {
+		cx18_writel_noretry(cx, val, addr);
+		if (val == cx18_readl(cx, addr))
+			break;
+	}
+}
+
+static inline
+void cx18_writel_expect(struct cx18 *cx, u32 val, void __iomem *addr,
+			u32 eval, u32 mask)
+{
+	int i;
+	u32 r;
+	eval &= mask;
+	for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) {
+		cx18_writel_noretry(cx, val, addr);
+		r = cx18_readl(cx, addr);
+		if (r == 0xffffffff && eval != 0xffffffff)
+			continue;
+		if (eval == (r & mask))
+			break;
+	}
+}
+
+static inline u16 cx18_readw(struct cx18 *cx, const void __iomem *addr)
+{
+	return readw(addr);
+}
+
+static inline
+void cx18_writew_noretry(struct cx18 *cx, u16 val, void __iomem *addr)
+{
+	writew(val, addr);
+}
+
+static inline void cx18_writew(struct cx18 *cx, u16 val, void __iomem *addr)
+{
+	int i;
+	for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) {
+		cx18_writew_noretry(cx, val, addr);
+		if (val == cx18_readw(cx, addr))
+			break;
+	}
+}
+
+static inline u8 cx18_readb(struct cx18 *cx, const void __iomem *addr)
+{
+	return readb(addr);
+}
+
+static inline
+void cx18_writeb_noretry(struct cx18 *cx, u8 val, void __iomem *addr)
+{
+	writeb(val, addr);
+}
+
+static inline void cx18_writeb(struct cx18 *cx, u8 val, void __iomem *addr)
+{
+	int i;
+	for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) {
+		cx18_writeb_noretry(cx, val, addr);
+		if (val == cx18_readb(cx, addr))
+			break;
+	}
+}
+
+static inline
+void cx18_memcpy_fromio(struct cx18 *cx, void *to,
+			const void __iomem *from, unsigned int len)
+{
+	memcpy_fromio(to, from, len);
+}
+
+void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count);
+
+
+/* Access "register" region of CX23418 memory mapped I/O */
+static inline void cx18_write_reg_noretry(struct cx18 *cx, u32 val, u32 reg)
+{
+	cx18_writel_noretry(cx, val, cx->reg_mem + reg);
+}
+
+static inline void cx18_write_reg(struct cx18 *cx, u32 val, u32 reg)
+{
+	cx18_writel(cx, val, cx->reg_mem + reg);
+}
+
+static inline void cx18_write_reg_expect(struct cx18 *cx, u32 val, u32 reg,
+					 u32 eval, u32 mask)
+{
+	cx18_writel_expect(cx, val, cx->reg_mem + reg, eval, mask);
+}
+
+static inline u32 cx18_read_reg(struct cx18 *cx, u32 reg)
+{
+	return cx18_readl(cx, cx->reg_mem + reg);
+}
+
+
+/* Access "encoder memory" region of CX23418 memory mapped I/O */
+static inline void cx18_write_enc(struct cx18 *cx, u32 val, u32 addr)
+{
+	cx18_writel(cx, val, cx->enc_mem + addr);
+}
+
+static inline u32 cx18_read_enc(struct cx18 *cx, u32 addr)
+{
+	return cx18_readl(cx, cx->enc_mem + addr);
+}
+
+void cx18_sw1_irq_enable(struct cx18 *cx, u32 val);
+void cx18_sw1_irq_disable(struct cx18 *cx, u32 val);
+void cx18_sw2_irq_enable(struct cx18 *cx, u32 val);
+void cx18_sw2_irq_disable(struct cx18 *cx, u32 val);
+void cx18_sw2_irq_disable_cpu(struct cx18 *cx, u32 val);
+void cx18_setup_page(struct cx18 *cx, u32 addr);
+
+#endif /* CX18_IO_H */
diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c
new file mode 100644
index 0000000..e9912db
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-ioctl.c
@@ -0,0 +1,1194 @@
+/*
+ *  cx18 ioctl system call
+ *
+ *  Derived from ivtv-ioctl.c
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-io.h"
+#include "cx18-version.h"
+#include "cx18-mailbox.h"
+#include "cx18-i2c.h"
+#include "cx18-queue.h"
+#include "cx18-fileops.h"
+#include "cx18-vbi.h"
+#include "cx18-audio.h"
+#include "cx18-video.h"
+#include "cx18-streams.h"
+#include "cx18-ioctl.h"
+#include "cx18-gpio.h"
+#include "cx18-controls.h"
+#include "cx18-cards.h"
+#include "cx18-av-core.h"
+#include <media/tveeprom.h>
+#include <media/v4l2-chip-ident.h>
+
+u16 cx18_service2vbi(int type)
+{
+	switch (type) {
+	case V4L2_SLICED_TELETEXT_B:
+		return CX18_SLICED_TYPE_TELETEXT_B;
+	case V4L2_SLICED_CAPTION_525:
+		return CX18_SLICED_TYPE_CAPTION_525;
+	case V4L2_SLICED_WSS_625:
+		return CX18_SLICED_TYPE_WSS_625;
+	case V4L2_SLICED_VPS:
+		return CX18_SLICED_TYPE_VPS;
+	default:
+		return 0;
+	}
+}
+
+/* Check if VBI services are allowed on the (field, line) for the video std */
+static int valid_service_line(int field, int line, int is_pal)
+{
+	return (is_pal && line >= 6 &&
+		((field == 0 && line <= 23) || (field == 1 && line <= 22))) ||
+	       (!is_pal && line >= 10 && line < 22);
+}
+
+/*
+ * For a (field, line, std) and inbound potential set of services for that line,
+ * return the first valid service of those passed in the incoming set for that
+ * line in priority order:
+ * CC, VPS, or WSS over TELETEXT for well known lines
+ * TELETEXT, before VPS, before CC, before WSS, for other lines
+ */
+static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
+{
+	u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
+	int i;
+
+	set = set & valid_set;
+	if (set == 0 || !valid_service_line(field, line, is_pal))
+		return 0;
+	if (!is_pal) {
+		if (line == 21 && (set & V4L2_SLICED_CAPTION_525))
+			return V4L2_SLICED_CAPTION_525;
+	} else {
+		if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS))
+			return V4L2_SLICED_VPS;
+		if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625))
+			return V4L2_SLICED_WSS_625;
+		if (line == 23)
+			return 0;
+	}
+	for (i = 0; i < 32; i++) {
+		if ((1 << i) & set)
+			return 1 << i;
+	}
+	return 0;
+}
+
+/*
+ * Expand the service_set of *fmt into valid service_lines for the std,
+ * and clear the passed in fmt->service_set
+ */
+void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+{
+	u16 set = fmt->service_set;
+	int f, l;
+
+	fmt->service_set = 0;
+	for (f = 0; f < 2; f++) {
+		for (l = 0; l < 24; l++)
+			fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal);
+	}
+}
+
+/*
+ * Sanitize the service_lines in *fmt per the video std, and return 1
+ * if any service_line is left as valid after santization
+ */
+static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+{
+	int f, l;
+	u16 set = 0;
+
+	for (f = 0; f < 2; f++) {
+		for (l = 0; l < 24; l++) {
+			fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
+			set |= fmt->service_lines[f][l];
+		}
+	}
+	return set != 0;
+}
+
+/* Compute the service_set from the assumed valid service_lines of *fmt */
+u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
+{
+	int f, l;
+	u16 set = 0;
+
+	for (f = 0; f < 2; f++) {
+		for (l = 0; l < 24; l++)
+			set |= fmt->service_lines[f][l];
+	}
+	return set;
+}
+
+static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	struct cx18_open_id *id = fh2id(fh);
+	struct cx18 *cx = id->cx;
+	struct cx18_stream *s = &cx->streams[id->type];
+	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+	pixfmt->width = cx->cxhdl.width;
+	pixfmt->height = cx->cxhdl.height;
+	pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	pixfmt->field = V4L2_FIELD_INTERLACED;
+	pixfmt->priv = 0;
+	if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
+		pixfmt->pixelformat = s->pixelformat;
+		pixfmt->sizeimage = s->vb_bytes_per_frame;
+		pixfmt->bytesperline = 720;
+	} else {
+		pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
+		pixfmt->sizeimage = 128 * 1024;
+		pixfmt->bytesperline = 0;
+	}
+	return 0;
+}
+
+static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+	struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
+
+	vbifmt->sampling_rate = 27000000;
+	vbifmt->offset = 248; /* FIXME - slightly wrong for both 50 & 60 Hz */
+	vbifmt->samples_per_line = vbi_active_samples - 4;
+	vbifmt->sample_format = V4L2_PIX_FMT_GREY;
+	vbifmt->start[0] = cx->vbi.start[0];
+	vbifmt->start[1] = cx->vbi.start[1];
+	vbifmt->count[0] = vbifmt->count[1] = cx->vbi.count;
+	vbifmt->flags = 0;
+	vbifmt->reserved[0] = 0;
+	vbifmt->reserved[1] = 0;
+	return 0;
+}
+
+static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
+					struct v4l2_format *fmt)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+	/* sane, V4L2 spec compliant, defaults */
+	vbifmt->reserved[0] = 0;
+	vbifmt->reserved[1] = 0;
+	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+	memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
+	vbifmt->service_set = 0;
+
+	/*
+	 * Fetch the configured service_lines and total service_set from the
+	 * digitizer/slicer.  Note, cx18_av_vbi() wipes the passed in
+	 * fmt->fmt.sliced under valid calling conditions
+	 */
+	if (v4l2_subdev_call(cx->sd_av, vbi, g_sliced_fmt, &fmt->fmt.sliced))
+		return -EINVAL;
+
+	/* Ensure V4L2 spec compliant output */
+	vbifmt->reserved[0] = 0;
+	vbifmt->reserved[1] = 0;
+	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+	vbifmt->service_set = cx18_get_service_set(vbifmt);
+	return 0;
+}
+
+static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	struct cx18_open_id *id = fh2id(fh);
+	struct cx18 *cx = id->cx;
+	int w = fmt->fmt.pix.width;
+	int h = fmt->fmt.pix.height;
+	int min_h = 2;
+
+	w = min(w, 720);
+	w = max(w, 2);
+	if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
+		/* YUV height must be a multiple of 32 */
+		h &= ~0x1f;
+		min_h = 32;
+	}
+	h = min(h, cx->is_50hz ? 576 : 480);
+	h = max(h, min_h);
+
+	fmt->fmt.pix.width = w;
+	fmt->fmt.pix.height = h;
+	return 0;
+}
+
+static int cx18_try_fmt_vbi_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	return cx18_g_fmt_vbi_cap(file, fh, fmt);
+}
+
+static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
+					struct v4l2_format *fmt)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+	vbifmt->reserved[0] = 0;
+	vbifmt->reserved[1] = 0;
+
+	/* If given a service set, expand it validly & clear passed in set */
+	if (vbifmt->service_set)
+		cx18_expand_service_set(vbifmt, cx->is_50hz);
+	/* Sanitize the service_lines, and compute the new set if any valid */
+	if (check_service_set(vbifmt, cx->is_50hz))
+		vbifmt->service_set = cx18_get_service_set(vbifmt);
+	return 0;
+}
+
+static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	struct cx18_open_id *id = fh2id(fh);
+	struct cx18 *cx = id->cx;
+	struct v4l2_mbus_framefmt mbus_fmt;
+	struct cx18_stream *s = &cx->streams[id->type];
+	int ret;
+	int w, h;
+
+	ret = cx18_try_fmt_vid_cap(file, fh, fmt);
+	if (ret)
+		return ret;
+	w = fmt->fmt.pix.width;
+	h = fmt->fmt.pix.height;
+
+	if (cx->cxhdl.width == w && cx->cxhdl.height == h &&
+	    s->pixelformat == fmt->fmt.pix.pixelformat)
+		return 0;
+
+	if (atomic_read(&cx->ana_capturing) > 0)
+		return -EBUSY;
+
+	s->pixelformat = fmt->fmt.pix.pixelformat;
+	/* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
+	   UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
+	if (s->pixelformat == V4L2_PIX_FMT_HM12)
+		s->vb_bytes_per_frame = h * 720 * 3 / 2;
+	else
+		s->vb_bytes_per_frame = h * 720 * 2;
+
+	mbus_fmt.width = cx->cxhdl.width = w;
+	mbus_fmt.height = cx->cxhdl.height = h;
+	mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
+	v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt);
+	return cx18_g_fmt_vid_cap(file, fh, fmt);
+}
+
+static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	struct cx18_open_id *id = fh2id(fh);
+	struct cx18 *cx = id->cx;
+	int ret;
+
+	/*
+	 * Changing the Encoder's Raw VBI parameters won't have any effect
+	 * if any analog capture is ongoing
+	 */
+	if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
+		return -EBUSY;
+
+	/*
+	 * Set the digitizer registers for raw active VBI.
+	 * Note cx18_av_vbi_wipes out a lot of the passed in fmt under valid
+	 * calling conditions
+	 */
+	ret = v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &fmt->fmt.vbi);
+	if (ret)
+		return ret;
+
+	/* Store our new v4l2 (non-)sliced VBI state */
+	cx->vbi.sliced_in->service_set = 0;
+	cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
+
+	return cx18_g_fmt_vbi_cap(file, fh, fmt);
+}
+
+static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
+					struct v4l2_format *fmt)
+{
+	struct cx18_open_id *id = fh2id(fh);
+	struct cx18 *cx = id->cx;
+	int ret;
+	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+	cx18_try_fmt_sliced_vbi_cap(file, fh, fmt);
+
+	/*
+	 * Changing the Encoder's Raw VBI parameters won't have any effect
+	 * if any analog capture is ongoing
+	 */
+	if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
+		return -EBUSY;
+
+	/*
+	 * Set the service_lines requested in the digitizer/slicer registers.
+	 * Note, cx18_av_vbi() wipes some "impossible" service lines in the
+	 * passed in fmt->fmt.sliced under valid calling conditions
+	 */
+	ret = v4l2_subdev_call(cx->sd_av, vbi, s_sliced_fmt, &fmt->fmt.sliced);
+	if (ret)
+		return ret;
+	/* Store our current v4l2 sliced VBI settings */
+	cx->vbi.in.type =  V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+	memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
+	return 0;
+}
+
+static int cx18_g_chip_ident(struct file *file, void *fh,
+				struct v4l2_dbg_chip_ident *chip)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+	int err = 0;
+
+	chip->ident = V4L2_IDENT_NONE;
+	chip->revision = 0;
+	switch (chip->match.type) {
+	case V4L2_CHIP_MATCH_HOST:
+		switch (chip->match.addr) {
+		case 0:
+			chip->ident = V4L2_IDENT_CX23418;
+			chip->revision = cx18_read_reg(cx, 0xC72028);
+			break;
+		case 1:
+			/*
+			 * The A/V decoder is always present, but in the rare
+			 * case that the card doesn't have analog, we don't
+			 * use it.  We find it w/o using the cx->sd_av pointer
+			 */
+			cx18_call_hw(cx, CX18_HW_418_AV,
+				     core, g_chip_ident, chip);
+			break;
+		default:
+			/*
+			 * Could return ident = V4L2_IDENT_UNKNOWN if we had
+			 * other host chips at higher addresses, but we don't
+			 */
+			err = -EINVAL; /* per V4L2 spec */
+			break;
+		}
+		break;
+	case V4L2_CHIP_MATCH_I2C_DRIVER:
+		/* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */
+		cx18_call_all(cx, core, g_chip_ident, chip);
+		break;
+	case V4L2_CHIP_MATCH_I2C_ADDR:
+		/*
+		 * We could return V4L2_IDENT_UNKNOWN, but we don't do the work
+		 * to look if a chip is at the address with no driver.  That's a
+		 * dangerous thing to do with EEPROMs anyway.
+		 */
+		cx18_call_all(cx, core, g_chip_ident, chip);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+	return err;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+	struct v4l2_dbg_register *regs = arg;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
+		return -EINVAL;
+
+	regs->size = 4;
+	if (cmd == VIDIOC_DBG_S_REGISTER)
+		cx18_write_enc(cx, regs->val, regs->reg);
+	else
+		regs->val = cx18_read_enc(cx, regs->reg);
+	return 0;
+}
+
+static int cx18_g_register(struct file *file, void *fh,
+				struct v4l2_dbg_register *reg)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+
+	if (v4l2_chip_match_host(&reg->match))
+		return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg);
+	/* FIXME - errors shouldn't be ignored */
+	cx18_call_all(cx, core, g_register, reg);
+	return 0;
+}
+
+static int cx18_s_register(struct file *file, void *fh,
+				struct v4l2_dbg_register *reg)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+
+	if (v4l2_chip_match_host(&reg->match))
+		return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg);
+	/* FIXME - errors shouldn't be ignored */
+	cx18_call_all(cx, core, s_register, reg);
+	return 0;
+}
+#endif
+
+static int cx18_querycap(struct file *file, void *fh,
+				struct v4l2_capability *vcap)
+{
+	struct cx18_open_id *id = fh2id(fh);
+	struct cx18 *cx = id->cx;
+
+	strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
+	strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
+	snprintf(vcap->bus_info, sizeof(vcap->bus_info),
+		 "PCI:%s", pci_name(cx->pci_dev));
+	vcap->capabilities = cx->v4l2_cap; 	    /* capabilities */
+	if (id->type == CX18_ENC_STREAM_TYPE_YUV)
+		vcap->capabilities |= V4L2_CAP_STREAMING;
+	return 0;
+}
+
+static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+
+	return cx18_get_audio_input(cx, vin->index, vin);
+}
+
+static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+
+	vin->index = cx->audio_input;
+	return cx18_get_audio_input(cx, vin->index, vin);
+}
+
+static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+
+	if (vout->index >= cx->nof_audio_inputs)
+		return -EINVAL;
+	cx->audio_input = vout->index;
+	cx18_audio_set_io(cx);
+	return 0;
+}
+
+static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+
+	/* set it to defaults from our table */
+	return cx18_get_input(cx, vin->index, vin);
+}
+
+static int cx18_cropcap(struct file *file, void *fh,
+			struct v4l2_cropcap *cropcap)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+
+	if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	cropcap->bounds.top = cropcap->bounds.left = 0;
+	cropcap->bounds.width = 720;
+	cropcap->bounds.height = cx->is_50hz ? 576 : 480;
+	cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
+	cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
+	cropcap->defrect = cropcap->bounds;
+	return 0;
+}
+
+static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+	struct cx18_open_id *id = fh2id(fh);
+	struct cx18 *cx = id->cx;
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	CX18_DEBUG_WARN("VIDIOC_S_CROP not implemented\n");
+	return -EINVAL;
+}
+
+static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	CX18_DEBUG_WARN("VIDIOC_G_CROP not implemented\n");
+	return -EINVAL;
+}
+
+static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
+					struct v4l2_fmtdesc *fmt)
+{
+	static const struct v4l2_fmtdesc formats[] = {
+		{ 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
+		  "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 }
+		},
+		{ 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED,
+		  "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 }
+		},
+		{ 2, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
+		  "UYVY 4:2:2", V4L2_PIX_FMT_UYVY, { 0, 0, 0, 0 }
+		},
+	};
+
+	if (fmt->index > ARRAY_SIZE(formats) - 1)
+		return -EINVAL;
+	*fmt = formats[fmt->index];
+	return 0;
+}
+
+static int cx18_g_input(struct file *file, void *fh, unsigned int *i)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+
+	*i = cx->active_input;
+	return 0;
+}
+
+int cx18_s_input(struct file *file, void *fh, unsigned int inp)
+{
+	struct cx18_open_id *id = fh2id(fh);
+	struct cx18 *cx = id->cx;
+
+	if (inp >= cx->nof_inputs)
+		return -EINVAL;
+
+	if (inp == cx->active_input) {
+		CX18_DEBUG_INFO("Input unchanged\n");
+		return 0;
+	}
+
+	CX18_DEBUG_INFO("Changing input from %d to %d\n",
+			cx->active_input, inp);
+
+	cx->active_input = inp;
+	/* Set the audio input to whatever is appropriate for the input type. */
+	cx->audio_input = cx->card->video_inputs[inp].audio_index;
+
+	/* prevent others from messing with the streams until
+	   we're finished changing inputs. */
+	cx18_mute(cx);
+	cx18_video_set_io(cx);
+	cx18_audio_set_io(cx);
+	cx18_unmute(cx);
+	return 0;
+}
+
+static int cx18_g_frequency(struct file *file, void *fh,
+				struct v4l2_frequency *vf)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+
+	if (vf->tuner != 0)
+		return -EINVAL;
+
+	cx18_call_all(cx, tuner, g_frequency, vf);
+	return 0;
+}
+
+int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+	struct cx18_open_id *id = fh2id(fh);
+	struct cx18 *cx = id->cx;
+
+	if (vf->tuner != 0)
+		return -EINVAL;
+
+	cx18_mute(cx);
+	CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
+	cx18_call_all(cx, tuner, s_frequency, vf);
+	cx18_unmute(cx);
+	return 0;
+}
+
+static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+
+	*std = cx->std;
+	return 0;
+}
+
+int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+	struct cx18_open_id *id = fh2id(fh);
+	struct cx18 *cx = id->cx;
+
+	if ((*std & V4L2_STD_ALL) == 0)
+		return -EINVAL;
+
+	if (*std == cx->std)
+		return 0;
+
+	if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
+	    atomic_read(&cx->ana_capturing) > 0) {
+		/* Switching standard would turn off the radio or mess
+		   with already running streams, prevent that by
+		   returning EBUSY. */
+		return -EBUSY;
+	}
+
+	cx->std = *std;
+	cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
+	cx->is_50hz = !cx->is_60hz;
+	cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz);
+	cx->cxhdl.width = 720;
+	cx->cxhdl.height = cx->is_50hz ? 576 : 480;
+	cx->vbi.count = cx->is_50hz ? 18 : 12;
+	cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
+	cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
+	CX18_DEBUG_INFO("Switching standard to %llx.\n",
+			(unsigned long long) cx->std);
+
+	/* Tuner */
+	cx18_call_all(cx, core, s_std, cx->std);
+	return 0;
+}
+
+static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+	struct cx18_open_id *id = fh2id(fh);
+	struct cx18 *cx = id->cx;
+
+	if (vt->index != 0)
+		return -EINVAL;
+
+	cx18_call_all(cx, tuner, s_tuner, vt);
+	return 0;
+}
+
+static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+
+	if (vt->index != 0)
+		return -EINVAL;
+
+	cx18_call_all(cx, tuner, g_tuner, vt);
+
+	if (vt->type == V4L2_TUNER_RADIO)
+		strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
+	else
+		strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
+	return 0;
+}
+
+static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
+					struct v4l2_sliced_vbi_cap *cap)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+	int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
+	int f, l;
+
+	if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+		return -EINVAL;
+
+	cap->service_set = 0;
+	for (f = 0; f < 2; f++) {
+		for (l = 0; l < 24; l++) {
+			if (valid_service_line(f, l, cx->is_50hz)) {
+				/*
+				 * We can find all v4l2 supported vbi services
+				 * for the standard, on a valid line for the std
+				 */
+				cap->service_lines[f][l] = set;
+				cap->service_set |= set;
+			} else
+				cap->service_lines[f][l] = 0;
+		}
+	}
+	for (f = 0; f < 3; f++)
+		cap->reserved[f] = 0;
+	return 0;
+}
+
+static int _cx18_process_idx_data(struct cx18_buffer *buf,
+				  struct v4l2_enc_idx *idx)
+{
+	int consumed, remaining;
+	struct v4l2_enc_idx_entry *e_idx;
+	struct cx18_enc_idx_entry *e_buf;
+
+	/* Frame type lookup: 1=I, 2=P, 4=B */
+	const int mapping[8] = {
+		-1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P,
+		-1, V4L2_ENC_IDX_FRAME_B, -1, -1, -1
+	};
+
+	/*
+	 * Assumption here is that a buf holds an integral number of
+	 * struct cx18_enc_idx_entry objects and is properly aligned.
+	 * This is enforced by the module options on IDX buffer sizes.
+	 */
+	remaining = buf->bytesused - buf->readpos;
+	consumed = 0;
+	e_idx = &idx->entry[idx->entries];
+	e_buf = (struct cx18_enc_idx_entry *) &buf->buf[buf->readpos];
+
+	while (remaining >= sizeof(struct cx18_enc_idx_entry) &&
+	       idx->entries < V4L2_ENC_IDX_ENTRIES) {
+
+		e_idx->offset = (((u64) le32_to_cpu(e_buf->offset_high)) << 32)
+				| le32_to_cpu(e_buf->offset_low);
+
+		e_idx->pts = (((u64) (le32_to_cpu(e_buf->pts_high) & 1)) << 32)
+			     | le32_to_cpu(e_buf->pts_low);
+
+		e_idx->length = le32_to_cpu(e_buf->length);
+
+		e_idx->flags = mapping[le32_to_cpu(e_buf->flags) & 0x7];
+
+		e_idx->reserved[0] = 0;
+		e_idx->reserved[1] = 0;
+
+		idx->entries++;
+		e_idx = &idx->entry[idx->entries];
+		e_buf++;
+
+		remaining -= sizeof(struct cx18_enc_idx_entry);
+		consumed += sizeof(struct cx18_enc_idx_entry);
+	}
+
+	/* Swallow any partial entries at the end, if there are any */
+	if (remaining > 0 && remaining < sizeof(struct cx18_enc_idx_entry))
+		consumed += remaining;
+
+	buf->readpos += consumed;
+	return consumed;
+}
+
+static int cx18_process_idx_data(struct cx18_stream *s, struct cx18_mdl *mdl,
+				 struct v4l2_enc_idx *idx)
+{
+	if (s->type != CX18_ENC_STREAM_TYPE_IDX)
+		return -EINVAL;
+
+	if (mdl->curr_buf == NULL)
+		mdl->curr_buf = list_first_entry(&mdl->buf_list,
+						 struct cx18_buffer, list);
+
+	if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) {
+		/*
+		 * For some reason we've exhausted the buffers, but the MDL
+		 * object still said some data was unread.
+		 * Fix that and bail out.
+		 */
+		mdl->readpos = mdl->bytesused;
+		return 0;
+	}
+
+	list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) {
+
+		/* Skip any empty buffers in the MDL */
+		if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused)
+			continue;
+
+		mdl->readpos += _cx18_process_idx_data(mdl->curr_buf, idx);
+
+		/* exit when MDL drained or request satisfied */
+		if (idx->entries >= V4L2_ENC_IDX_ENTRIES ||
+		    mdl->curr_buf->readpos < mdl->curr_buf->bytesused ||
+		    mdl->readpos >= mdl->bytesused)
+			break;
+	}
+	return 0;
+}
+
+static int cx18_g_enc_index(struct file *file, void *fh,
+				struct v4l2_enc_idx *idx)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+	struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
+	s32 tmp;
+	struct cx18_mdl *mdl;
+
+	if (!cx18_stream_enabled(s)) /* Module options inhibited IDX stream */
+		return -EINVAL;
+
+	/* Compute the best case number of entries we can buffer */
+	tmp = s->buffers -
+			  s->bufs_per_mdl * CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN;
+	if (tmp <= 0)
+		tmp = 1;
+	tmp = tmp * s->buf_size / sizeof(struct cx18_enc_idx_entry);
+
+	/* Fill out the header of the return structure */
+	idx->entries = 0;
+	idx->entries_cap = tmp;
+	memset(idx->reserved, 0, sizeof(idx->reserved));
+
+	/* Pull IDX MDLs and buffers from q_full and populate the entries */
+	do {
+		mdl = cx18_dequeue(s, &s->q_full);
+		if (mdl == NULL) /* No more IDX data right now */
+			break;
+
+		/* Extract the Index entry data from the MDL and buffers */
+		cx18_process_idx_data(s, mdl, idx);
+		if (mdl->readpos < mdl->bytesused) {
+			/* We finished with data remaining, push the MDL back */
+			cx18_push(s, mdl, &s->q_full);
+			break;
+		}
+
+		/* We drained this MDL, schedule it to go to the firmware */
+		cx18_enqueue(s, mdl, &s->q_free);
+
+	} while (idx->entries < V4L2_ENC_IDX_ENTRIES);
+
+	/* Tell the work handler to send free IDX MDLs to the firmware */
+	cx18_stream_load_fw_queue(s);
+	return 0;
+}
+
+static struct videobuf_queue *cx18_vb_queue(struct cx18_open_id *id)
+{
+	struct videobuf_queue *q = NULL;
+	struct cx18 *cx = id->cx;
+	struct cx18_stream *s = &cx->streams[id->type];
+
+	switch (s->vb_type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		q = &s->vbuf_q;
+		break;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		break;
+	default:
+		break;
+	}
+	return q;
+}
+
+static int cx18_streamon(struct file *file, void *priv,
+	enum v4l2_buf_type type)
+{
+	struct cx18_open_id *id = file->private_data;
+	struct cx18 *cx = id->cx;
+	struct cx18_stream *s = &cx->streams[id->type];
+
+	/* Start the hardware only if we're the video device */
+	if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+		(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+		return -EINVAL;
+
+	if (id->type != CX18_ENC_STREAM_TYPE_YUV)
+		return -EINVAL;
+
+	/* Establish a buffer timeout */
+	mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies);
+
+	return videobuf_streamon(cx18_vb_queue(id));
+}
+
+static int cx18_streamoff(struct file *file, void *priv,
+	enum v4l2_buf_type type)
+{
+	struct cx18_open_id *id = file->private_data;
+	struct cx18 *cx = id->cx;
+	struct cx18_stream *s = &cx->streams[id->type];
+
+	/* Start the hardware only if we're the video device */
+	if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+		(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+		return -EINVAL;
+
+	if (id->type != CX18_ENC_STREAM_TYPE_YUV)
+		return -EINVAL;
+
+	return videobuf_streamoff(cx18_vb_queue(id));
+}
+
+static int cx18_reqbufs(struct file *file, void *priv,
+	struct v4l2_requestbuffers *rb)
+{
+	struct cx18_open_id *id = file->private_data;
+	struct cx18 *cx = id->cx;
+	struct cx18_stream *s = &cx->streams[id->type];
+
+	if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+		(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+		return -EINVAL;
+
+	return videobuf_reqbufs(cx18_vb_queue(id), rb);
+}
+
+static int cx18_querybuf(struct file *file, void *priv,
+	struct v4l2_buffer *b)
+{
+	struct cx18_open_id *id = file->private_data;
+	struct cx18 *cx = id->cx;
+	struct cx18_stream *s = &cx->streams[id->type];
+
+	if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+		(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+		return -EINVAL;
+
+	return videobuf_querybuf(cx18_vb_queue(id), b);
+}
+
+static int cx18_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct cx18_open_id *id = file->private_data;
+	struct cx18 *cx = id->cx;
+	struct cx18_stream *s = &cx->streams[id->type];
+
+	if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+		(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+		return -EINVAL;
+
+	return videobuf_qbuf(cx18_vb_queue(id), b);
+}
+
+static int cx18_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct cx18_open_id *id = file->private_data;
+	struct cx18 *cx = id->cx;
+	struct cx18_stream *s = &cx->streams[id->type];
+
+	if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+		(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+		return -EINVAL;
+
+	return videobuf_dqbuf(cx18_vb_queue(id), b, file->f_flags & O_NONBLOCK);
+}
+
+static int cx18_encoder_cmd(struct file *file, void *fh,
+				struct v4l2_encoder_cmd *enc)
+{
+	struct cx18_open_id *id = fh2id(fh);
+	struct cx18 *cx = id->cx;
+	u32 h;
+
+	switch (enc->cmd) {
+	case V4L2_ENC_CMD_START:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+		enc->flags = 0;
+		return cx18_start_capture(id);
+
+	case V4L2_ENC_CMD_STOP:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+		cx18_stop_capture(id,
+				  enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
+		break;
+
+	case V4L2_ENC_CMD_PAUSE:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+		enc->flags = 0;
+		if (!atomic_read(&cx->ana_capturing))
+			return -EPERM;
+		if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+			return 0;
+		h = cx18_find_handle(cx);
+		if (h == CX18_INVALID_TASK_HANDLE) {
+			CX18_ERR("Can't find valid task handle for "
+				 "V4L2_ENC_CMD_PAUSE\n");
+			return -EBADFD;
+		}
+		cx18_mute(cx);
+		cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, h);
+		break;
+
+	case V4L2_ENC_CMD_RESUME:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+		enc->flags = 0;
+		if (!atomic_read(&cx->ana_capturing))
+			return -EPERM;
+		if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+			return 0;
+		h = cx18_find_handle(cx);
+		if (h == CX18_INVALID_TASK_HANDLE) {
+			CX18_ERR("Can't find valid task handle for "
+				 "V4L2_ENC_CMD_RESUME\n");
+			return -EBADFD;
+		}
+		cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, h);
+		cx18_unmute(cx);
+		break;
+
+	default:
+		CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cx18_try_encoder_cmd(struct file *file, void *fh,
+				struct v4l2_encoder_cmd *enc)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+
+	switch (enc->cmd) {
+	case V4L2_ENC_CMD_START:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+		enc->flags = 0;
+		break;
+
+	case V4L2_ENC_CMD_STOP:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+		break;
+
+	case V4L2_ENC_CMD_PAUSE:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+		enc->flags = 0;
+		break;
+
+	case V4L2_ENC_CMD_RESUME:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+		enc->flags = 0;
+		break;
+
+	default:
+		CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cx18_log_status(struct file *file, void *fh)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+	struct v4l2_input vidin;
+	struct v4l2_audio audin;
+	int i;
+
+	CX18_INFO("Version: %s  Card: %s\n", CX18_VERSION, cx->card_name);
+	if (cx->hw_flags & CX18_HW_TVEEPROM) {
+		struct tveeprom tv;
+
+		cx18_read_eeprom(cx, &tv);
+	}
+	cx18_call_all(cx, core, log_status);
+	cx18_get_input(cx, cx->active_input, &vidin);
+	cx18_get_audio_input(cx, cx->audio_input, &audin);
+	CX18_INFO("Video Input: %s\n", vidin.name);
+	CX18_INFO("Audio Input: %s\n", audin.name);
+	mutex_lock(&cx->gpio_lock);
+	CX18_INFO("GPIO:  direction 0x%08x, value 0x%08x\n",
+		cx->gpio_dir, cx->gpio_val);
+	mutex_unlock(&cx->gpio_lock);
+	CX18_INFO("Tuner: %s\n",
+		test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?  "Radio" : "TV");
+	v4l2_ctrl_handler_log_status(&cx->cxhdl.hdl, cx->v4l2_dev.name);
+	CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
+	for (i = 0; i < CX18_MAX_STREAMS; i++) {
+		struct cx18_stream *s = &cx->streams[i];
+
+		if (s->video_dev == NULL || s->buffers == 0)
+			continue;
+		CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
+			  s->name, s->s_flags,
+			  atomic_read(&s->q_full.depth) * s->bufs_per_mdl * 100
+			   / s->buffers,
+			  (s->buffers * s->buf_size) / 1024, s->buffers);
+	}
+	CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
+			(long long)cx->mpg_data_received,
+			(long long)cx->vbi_data_inserted);
+	return 0;
+}
+
+static long cx18_default(struct file *file, void *fh, bool valid_prio,
+							int cmd, void *arg)
+{
+	struct cx18 *cx = fh2id(fh)->cx;
+
+	switch (cmd) {
+	case VIDIOC_INT_RESET: {
+		u32 val = *(u32 *)arg;
+
+		if ((val == 0) || (val & 0x01))
+			cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, core, reset,
+				     (u32) CX18_GPIO_RESET_Z8F0811);
+		break;
+	}
+
+	default:
+		return -ENOTTY;
+	}
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
+	.vidioc_querycap                = cx18_querycap,
+	.vidioc_s_audio                 = cx18_s_audio,
+	.vidioc_g_audio                 = cx18_g_audio,
+	.vidioc_enumaudio               = cx18_enumaudio,
+	.vidioc_enum_input              = cx18_enum_input,
+	.vidioc_cropcap                 = cx18_cropcap,
+	.vidioc_s_crop                  = cx18_s_crop,
+	.vidioc_g_crop                  = cx18_g_crop,
+	.vidioc_g_input                 = cx18_g_input,
+	.vidioc_s_input                 = cx18_s_input,
+	.vidioc_g_frequency             = cx18_g_frequency,
+	.vidioc_s_frequency             = cx18_s_frequency,
+	.vidioc_s_tuner                 = cx18_s_tuner,
+	.vidioc_g_tuner                 = cx18_g_tuner,
+	.vidioc_g_enc_index             = cx18_g_enc_index,
+	.vidioc_g_std                   = cx18_g_std,
+	.vidioc_s_std                   = cx18_s_std,
+	.vidioc_log_status              = cx18_log_status,
+	.vidioc_enum_fmt_vid_cap        = cx18_enum_fmt_vid_cap,
+	.vidioc_encoder_cmd             = cx18_encoder_cmd,
+	.vidioc_try_encoder_cmd         = cx18_try_encoder_cmd,
+	.vidioc_g_fmt_vid_cap           = cx18_g_fmt_vid_cap,
+	.vidioc_g_fmt_vbi_cap           = cx18_g_fmt_vbi_cap,
+	.vidioc_g_fmt_sliced_vbi_cap    = cx18_g_fmt_sliced_vbi_cap,
+	.vidioc_s_fmt_vid_cap           = cx18_s_fmt_vid_cap,
+	.vidioc_s_fmt_vbi_cap           = cx18_s_fmt_vbi_cap,
+	.vidioc_s_fmt_sliced_vbi_cap    = cx18_s_fmt_sliced_vbi_cap,
+	.vidioc_try_fmt_vid_cap         = cx18_try_fmt_vid_cap,
+	.vidioc_try_fmt_vbi_cap         = cx18_try_fmt_vbi_cap,
+	.vidioc_try_fmt_sliced_vbi_cap  = cx18_try_fmt_sliced_vbi_cap,
+	.vidioc_g_sliced_vbi_cap        = cx18_g_sliced_vbi_cap,
+	.vidioc_g_chip_ident            = cx18_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register              = cx18_g_register,
+	.vidioc_s_register              = cx18_s_register,
+#endif
+	.vidioc_default                 = cx18_default,
+	.vidioc_streamon                = cx18_streamon,
+	.vidioc_streamoff               = cx18_streamoff,
+	.vidioc_reqbufs                 = cx18_reqbufs,
+	.vidioc_querybuf                = cx18_querybuf,
+	.vidioc_qbuf                    = cx18_qbuf,
+	.vidioc_dqbuf                   = cx18_dqbuf,
+};
+
+void cx18_set_funcs(struct video_device *vdev)
+{
+	vdev->ioctl_ops = &cx18_ioctl_ops;
+}
diff --git a/drivers/media/pci/cx18/cx18-ioctl.h b/drivers/media/pci/cx18/cx18-ioctl.h
new file mode 100644
index 0000000..2f9dd59
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-ioctl.h
@@ -0,0 +1,31 @@
+/*
+ *  cx18 ioctl system call
+ *
+ *  Derived from ivtv-ioctl.h
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+u16 cx18_service2vbi(int type);
+void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
+u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt);
+void cx18_set_funcs(struct video_device *vdev);
+int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std);
+int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+int cx18_s_input(struct file *file, void *fh, unsigned int inp);
diff --git a/drivers/media/pci/cx18/cx18-irq.c b/drivers/media/pci/cx18/cx18-irq.c
new file mode 100644
index 0000000..80edfe9
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-irq.c
@@ -0,0 +1,81 @@
+/*
+ *  cx18 interrupt handling
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-io.h"
+#include "cx18-irq.h"
+#include "cx18-mailbox.h"
+#include "cx18-scb.h"
+
+static void xpu_ack(struct cx18 *cx, u32 sw2)
+{
+	if (sw2 & IRQ_CPU_TO_EPU_ACK)
+		wake_up(&cx->mb_cpu_waitq);
+	if (sw2 & IRQ_APU_TO_EPU_ACK)
+		wake_up(&cx->mb_apu_waitq);
+}
+
+static void epu_cmd(struct cx18 *cx, u32 sw1)
+{
+	if (sw1 & IRQ_CPU_TO_EPU)
+		cx18_api_epu_cmd_irq(cx, CPU);
+	if (sw1 & IRQ_APU_TO_EPU)
+		cx18_api_epu_cmd_irq(cx, APU);
+}
+
+irqreturn_t cx18_irq_handler(int irq, void *dev_id)
+{
+	struct cx18 *cx = (struct cx18 *)dev_id;
+	u32 sw1, sw2, hw2;
+
+	sw1 = cx18_read_reg(cx, SW1_INT_STATUS) & cx->sw1_irq_mask;
+	sw2 = cx18_read_reg(cx, SW2_INT_STATUS) & cx->sw2_irq_mask;
+	hw2 = cx18_read_reg(cx, HW2_INT_CLR_STATUS) & cx->hw2_irq_mask;
+
+	if (sw1)
+		cx18_write_reg_expect(cx, sw1, SW1_INT_STATUS, ~sw1, sw1);
+	if (sw2)
+		cx18_write_reg_expect(cx, sw2, SW2_INT_STATUS, ~sw2, sw2);
+	if (hw2)
+		cx18_write_reg_expect(cx, hw2, HW2_INT_CLR_STATUS, ~hw2, hw2);
+
+	if (sw1 || sw2 || hw2)
+		CX18_DEBUG_HI_IRQ("received interrupts "
+				  "SW1: %x  SW2: %x  HW2: %x\n", sw1, sw2, hw2);
+
+	/*
+	 * SW1 responses have to happen first.  The sending XPU times out the
+	 * incoming mailboxes on us rather rapidly.
+	 */
+	if (sw1)
+		epu_cmd(cx, sw1);
+
+	/* To do: interrupt-based I2C handling
+	if (hw2 & (HW2_I2C1_INT|HW2_I2C2_INT)) {
+	}
+	*/
+
+	if (sw2)
+		xpu_ack(cx, sw2);
+
+	return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE;
+}
diff --git a/drivers/media/pci/cx18/cx18-irq.h b/drivers/media/pci/cx18/cx18-irq.h
new file mode 100644
index 0000000..30e7eaf
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-irq.h
@@ -0,0 +1,35 @@
+/*
+ *  cx18 interrupt handling
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#define HW2_I2C1_INT			(1 << 22)
+#define HW2_I2C2_INT			(1 << 23)
+#define HW2_INT_CLR_STATUS		0xc730c4
+#define HW2_INT_MASK5_PCI		0xc730e4
+#define SW1_INT_SET                     0xc73100
+#define SW1_INT_STATUS                  0xc73104
+#define SW1_INT_ENABLE_PCI              0xc7311c
+#define SW2_INT_SET                     0xc73140
+#define SW2_INT_STATUS                  0xc73144
+#define SW2_INT_ENABLE_CPU              0xc73158
+#define SW2_INT_ENABLE_PCI              0xc7315c
+
+irqreturn_t cx18_irq_handler(int irq, void *dev_id);
diff --git a/drivers/media/pci/cx18/cx18-mailbox.c b/drivers/media/pci/cx18/cx18-mailbox.c
new file mode 100644
index 0000000..eabf00c
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-mailbox.c
@@ -0,0 +1,870 @@
+/*
+ *  cx18 mailbox functions
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include <stdarg.h>
+
+#include "cx18-driver.h"
+#include "cx18-io.h"
+#include "cx18-scb.h"
+#include "cx18-irq.h"
+#include "cx18-mailbox.h"
+#include "cx18-queue.h"
+#include "cx18-streams.h"
+#include "cx18-alsa-pcm.h" /* FIXME make configurable */
+
+static const char *rpu_str[] = { "APU", "CPU", "EPU", "HPU" };
+
+#define API_FAST (1 << 2) /* Short timeout */
+#define API_SLOW (1 << 3) /* Additional 300ms timeout */
+
+struct cx18_api_info {
+	u32 cmd;
+	u8 flags;		/* Flags, see above */
+	u8 rpu;			/* Processing unit */
+	const char *name; 	/* The name of the command */
+};
+
+#define API_ENTRY(rpu, x, f) { (x), (f), (rpu), #x }
+
+static const struct cx18_api_info api_info[] = {
+	/* MPEG encoder API */
+	API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE,		0),
+	API_ENTRY(CPU, CX18_EPU_DEBUG, 				0),
+	API_ENTRY(CPU, CX18_CREATE_TASK, 			0),
+	API_ENTRY(CPU, CX18_DESTROY_TASK, 			0),
+	API_ENTRY(CPU, CX18_CPU_CAPTURE_START,                  API_SLOW),
+	API_ENTRY(CPU, CX18_CPU_CAPTURE_STOP,                   API_SLOW),
+	API_ENTRY(CPU, CX18_CPU_CAPTURE_PAUSE,                  0),
+	API_ENTRY(CPU, CX18_CPU_CAPTURE_RESUME,                 0),
+	API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE,               0),
+	API_ENTRY(CPU, CX18_CPU_SET_STREAM_OUTPUT_TYPE,         0),
+	API_ENTRY(CPU, CX18_CPU_SET_VIDEO_IN,                   0),
+	API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RATE,                 0),
+	API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RESOLUTION,           0),
+	API_ENTRY(CPU, CX18_CPU_SET_FILTER_PARAM,               0),
+	API_ENTRY(CPU, CX18_CPU_SET_SPATIAL_FILTER_TYPE,        0),
+	API_ENTRY(CPU, CX18_CPU_SET_MEDIAN_CORING,              0),
+	API_ENTRY(CPU, CX18_CPU_SET_INDEXTABLE,                 0),
+	API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PARAMETERS,           0),
+	API_ENTRY(CPU, CX18_CPU_SET_VIDEO_MUTE,                 0),
+	API_ENTRY(CPU, CX18_CPU_SET_AUDIO_MUTE,                 0),
+	API_ENTRY(CPU, CX18_CPU_SET_MISC_PARAMETERS,            0),
+	API_ENTRY(CPU, CX18_CPU_SET_RAW_VBI_PARAM,              API_SLOW),
+	API_ENTRY(CPU, CX18_CPU_SET_CAPTURE_LINE_NO,            0),
+	API_ENTRY(CPU, CX18_CPU_SET_COPYRIGHT,                  0),
+	API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PID,                  0),
+	API_ENTRY(CPU, CX18_CPU_SET_VIDEO_PID,                  0),
+	API_ENTRY(CPU, CX18_CPU_SET_VER_CROP_LINE,              0),
+	API_ENTRY(CPU, CX18_CPU_SET_GOP_STRUCTURE,              0),
+	API_ENTRY(CPU, CX18_CPU_SET_SCENE_CHANGE_DETECTION,     0),
+	API_ENTRY(CPU, CX18_CPU_SET_ASPECT_RATIO,               0),
+	API_ENTRY(CPU, CX18_CPU_SET_SKIP_INPUT_FRAME,           0),
+	API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM,           0),
+	API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER,      0),
+	API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS,                    0),
+	API_ENTRY(CPU, CX18_CPU_SET_VFC_PARAM,                  0),
+	API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK,			0),
+	API_ENTRY(CPU, CX18_CPU_DE_SET_MDL,			API_FAST),
+	API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL,			API_SLOW),
+	API_ENTRY(APU, CX18_APU_START,				0),
+	API_ENTRY(APU, CX18_APU_STOP,				0),
+	API_ENTRY(APU, CX18_APU_RESETAI,			0),
+	API_ENTRY(CPU, CX18_CPU_DEBUG_PEEK32,			0),
+	API_ENTRY(0, 0,						0),
+};
+
+static const struct cx18_api_info *find_api_info(u32 cmd)
+{
+	int i;
+
+	for (i = 0; api_info[i].cmd; i++)
+		if (api_info[i].cmd == cmd)
+			return &api_info[i];
+	return NULL;
+}
+
+/* Call with buf of n*11+1 bytes */
+static char *u32arr2hex(u32 data[], int n, char *buf)
+{
+	char *p;
+	int i;
+
+	for (i = 0, p = buf; i < n; i++, p += 11) {
+		/* kernel snprintf() appends '\0' always */
+		snprintf(p, 12, " %#010x", data[i]);
+	}
+	*p = '\0';
+	return buf;
+}
+
+static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name)
+{
+	char argstr[MAX_MB_ARGUMENTS*11+1];
+
+	if (!(cx18_debug & CX18_DBGFLG_API))
+		return;
+
+	CX18_DEBUG_API("%s: req %#010x ack %#010x cmd %#010x err %#010x args%s"
+		       "\n", name, mb->request, mb->ack, mb->cmd, mb->error,
+		       u32arr2hex(mb->args, MAX_MB_ARGUMENTS, argstr));
+}
+
+
+/*
+ * Functions that run in a work_queue work handling context
+ */
+
+static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl)
+{
+	struct cx18_buffer *buf;
+
+	if (s->dvb == NULL || !s->dvb->enabled || mdl->bytesused == 0)
+		return;
+
+	/* We ignore mdl and buf readpos accounting here - it doesn't matter */
+
+	/* The likely case */
+	if (list_is_singular(&mdl->buf_list)) {
+		buf = list_first_entry(&mdl->buf_list, struct cx18_buffer,
+				       list);
+		if (buf->bytesused)
+			dvb_dmx_swfilter(&s->dvb->demux,
+					 buf->buf, buf->bytesused);
+		return;
+	}
+
+	list_for_each_entry(buf, &mdl->buf_list, list) {
+		if (buf->bytesused == 0)
+			break;
+		dvb_dmx_swfilter(&s->dvb->demux, buf->buf, buf->bytesused);
+	}
+}
+
+static void cx18_mdl_send_to_videobuf(struct cx18_stream *s,
+	struct cx18_mdl *mdl)
+{
+	struct cx18_videobuf_buffer *vb_buf;
+	struct cx18_buffer *buf;
+	u8 *p;
+	u32 offset = 0;
+	int dispatch = 0;
+
+	if (mdl->bytesused == 0)
+		return;
+
+	/* Acquire a videobuf buffer, clone to and and release it */
+	spin_lock(&s->vb_lock);
+	if (list_empty(&s->vb_capture))
+		goto out;
+
+	vb_buf = list_first_entry(&s->vb_capture, struct cx18_videobuf_buffer,
+		vb.queue);
+
+	p = videobuf_to_vmalloc(&vb_buf->vb);
+	if (!p)
+		goto out;
+
+	offset = vb_buf->bytes_used;
+	list_for_each_entry(buf, &mdl->buf_list, list) {
+		if (buf->bytesused == 0)
+			break;
+
+		if ((offset + buf->bytesused) <= vb_buf->vb.bsize) {
+			memcpy(p + offset, buf->buf, buf->bytesused);
+			offset += buf->bytesused;
+			vb_buf->bytes_used += buf->bytesused;
+		}
+	}
+
+	/* If we've filled the buffer as per the callers res then dispatch it */
+	if (vb_buf->bytes_used >= s->vb_bytes_per_frame) {
+		dispatch = 1;
+		vb_buf->bytes_used = 0;
+	}
+
+	if (dispatch) {
+		vb_buf->vb.ts = ktime_to_timeval(ktime_get());
+		list_del(&vb_buf->vb.queue);
+		vb_buf->vb.state = VIDEOBUF_DONE;
+		wake_up(&vb_buf->vb.done);
+	}
+
+	mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies);
+
+out:
+	spin_unlock(&s->vb_lock);
+}
+
+static void cx18_mdl_send_to_alsa(struct cx18 *cx, struct cx18_stream *s,
+				  struct cx18_mdl *mdl)
+{
+	struct cx18_buffer *buf;
+
+	if (mdl->bytesused == 0)
+		return;
+
+	/* We ignore mdl and buf readpos accounting here - it doesn't matter */
+
+	/* The likely case */
+	if (list_is_singular(&mdl->buf_list)) {
+		buf = list_first_entry(&mdl->buf_list, struct cx18_buffer,
+				       list);
+		if (buf->bytesused)
+			cx->pcm_announce_callback(cx->alsa, buf->buf,
+						  buf->bytesused);
+		return;
+	}
+
+	list_for_each_entry(buf, &mdl->buf_list, list) {
+		if (buf->bytesused == 0)
+			break;
+		cx->pcm_announce_callback(cx->alsa, buf->buf, buf->bytesused);
+	}
+}
+
+static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order)
+{
+	u32 handle, mdl_ack_count, id;
+	struct cx18_mailbox *mb;
+	struct cx18_mdl_ack *mdl_ack;
+	struct cx18_stream *s;
+	struct cx18_mdl *mdl;
+	int i;
+
+	mb = &order->mb;
+	handle = mb->args[0];
+	s = cx18_handle_to_stream(cx, handle);
+
+	if (s == NULL) {
+		CX18_WARN("Got DMA done notification for unknown/inactive"
+			  " handle %d, %s mailbox seq no %d\n", handle,
+			  (order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) ?
+			  "stale" : "good", mb->request);
+		return;
+	}
+
+	mdl_ack_count = mb->args[2];
+	mdl_ack = order->mdl_ack;
+	for (i = 0; i < mdl_ack_count; i++, mdl_ack++) {
+		id = mdl_ack->id;
+		/*
+		 * Simple integrity check for processing a stale (and possibly
+		 * inconsistent mailbox): make sure the MDL id is in the
+		 * valid range for the stream.
+		 *
+		 * We go through the trouble of dealing with stale mailboxes
+		 * because most of the time, the mailbox data is still valid and
+		 * unchanged (and in practice the firmware ping-pongs the
+		 * two mdl_ack buffers so mdl_acks are not stale).
+		 *
+		 * There are occasions when we get a half changed mailbox,
+		 * which this check catches for a handle & id mismatch.  If the
+		 * handle and id do correspond, the worst case is that we
+		 * completely lost the old MDL, but pick up the new MDL
+		 * early (but the new mdl_ack is guaranteed to be good in this
+		 * case as the firmware wouldn't point us to a new mdl_ack until
+		 * it's filled in).
+		 *
+		 * cx18_queue_get_mdl() will detect the lost MDLs
+		 * and send them back to q_free for fw rotation eventually.
+		 */
+		if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) &&
+		    !(id >= s->mdl_base_idx &&
+		      id < (s->mdl_base_idx + s->buffers))) {
+			CX18_WARN("Fell behind! Ignoring stale mailbox with "
+				  " inconsistent data. Lost MDL for mailbox "
+				  "seq no %d\n", mb->request);
+			break;
+		}
+		mdl = cx18_queue_get_mdl(s, id, mdl_ack->data_used);
+
+		CX18_DEBUG_HI_DMA("DMA DONE for %s (MDL %d)\n", s->name, id);
+		if (mdl == NULL) {
+			CX18_WARN("Could not find MDL %d for stream %s\n",
+				  id, s->name);
+			continue;
+		}
+
+		CX18_DEBUG_HI_DMA("%s recv bytesused = %d\n",
+				  s->name, mdl->bytesused);
+
+		if (s->type == CX18_ENC_STREAM_TYPE_TS) {
+			cx18_mdl_send_to_dvb(s, mdl);
+			cx18_enqueue(s, mdl, &s->q_free);
+		} else if (s->type == CX18_ENC_STREAM_TYPE_PCM) {
+			/* Pass the data to cx18-alsa */
+			if (cx->pcm_announce_callback != NULL) {
+				cx18_mdl_send_to_alsa(cx, s, mdl);
+				cx18_enqueue(s, mdl, &s->q_free);
+			} else {
+				cx18_enqueue(s, mdl, &s->q_full);
+			}
+		} else if (s->type == CX18_ENC_STREAM_TYPE_YUV) {
+			cx18_mdl_send_to_videobuf(s, mdl);
+			cx18_enqueue(s, mdl, &s->q_free);
+		} else {
+			cx18_enqueue(s, mdl, &s->q_full);
+			if (s->type == CX18_ENC_STREAM_TYPE_IDX)
+				cx18_stream_rotate_idx_mdls(cx);
+		}
+	}
+	/* Put as many MDLs as possible back into fw use */
+	cx18_stream_load_fw_queue(s);
+
+	wake_up(&cx->dma_waitq);
+	if (s->id != -1)
+		wake_up(&s->waitq);
+}
+
+static void epu_debug(struct cx18 *cx, struct cx18_in_work_order *order)
+{
+	char *p;
+	char *str = order->str;
+
+	CX18_DEBUG_INFO("%x %s\n", order->mb.args[0], str);
+	p = strchr(str, '.');
+	if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str)
+		CX18_INFO("FW version: %s\n", p - 1);
+}
+
+static void epu_cmd(struct cx18 *cx, struct cx18_in_work_order *order)
+{
+	switch (order->rpu) {
+	case CPU:
+	{
+		switch (order->mb.cmd) {
+		case CX18_EPU_DMA_DONE:
+			epu_dma_done(cx, order);
+			break;
+		case CX18_EPU_DEBUG:
+			epu_debug(cx, order);
+			break;
+		default:
+			CX18_WARN("Unknown CPU to EPU mailbox command %#0x\n",
+				  order->mb.cmd);
+			break;
+		}
+		break;
+	}
+	case APU:
+		CX18_WARN("Unknown APU to EPU mailbox command %#0x\n",
+			  order->mb.cmd);
+		break;
+	default:
+		break;
+	}
+}
+
+static
+void free_in_work_order(struct cx18 *cx, struct cx18_in_work_order *order)
+{
+	atomic_set(&order->pending, 0);
+}
+
+void cx18_in_work_handler(struct work_struct *work)
+{
+	struct cx18_in_work_order *order =
+			container_of(work, struct cx18_in_work_order, work);
+	struct cx18 *cx = order->cx;
+	epu_cmd(cx, order);
+	free_in_work_order(cx, order);
+}
+
+
+/*
+ * Functions that run in an interrupt handling context
+ */
+
+static void mb_ack_irq(struct cx18 *cx, struct cx18_in_work_order *order)
+{
+	struct cx18_mailbox __iomem *ack_mb;
+	u32 ack_irq, req;
+
+	switch (order->rpu) {
+	case APU:
+		ack_irq = IRQ_EPU_TO_APU_ACK;
+		ack_mb = &cx->scb->apu2epu_mb;
+		break;
+	case CPU:
+		ack_irq = IRQ_EPU_TO_CPU_ACK;
+		ack_mb = &cx->scb->cpu2epu_mb;
+		break;
+	default:
+		CX18_WARN("Unhandled RPU (%d) for command %x ack\n",
+			  order->rpu, order->mb.cmd);
+		return;
+	}
+
+	req = order->mb.request;
+	/* Don't ack if the RPU has gotten impatient and timed us out */
+	if (req != cx18_readl(cx, &ack_mb->request) ||
+	    req == cx18_readl(cx, &ack_mb->ack)) {
+		CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our "
+				"incoming %s to EPU mailbox (sequence no. %u) "
+				"while processing\n",
+				rpu_str[order->rpu], rpu_str[order->rpu], req);
+		order->flags |= CX18_F_EWO_MB_STALE_WHILE_PROC;
+		return;
+	}
+	cx18_writel(cx, req, &ack_mb->ack);
+	cx18_write_reg_expect(cx, ack_irq, SW2_INT_SET, ack_irq, ack_irq);
+	return;
+}
+
+static int epu_dma_done_irq(struct cx18 *cx, struct cx18_in_work_order *order)
+{
+	u32 handle, mdl_ack_offset, mdl_ack_count;
+	struct cx18_mailbox *mb;
+	int i;
+
+	mb = &order->mb;
+	handle = mb->args[0];
+	mdl_ack_offset = mb->args[1];
+	mdl_ack_count = mb->args[2];
+
+	if (handle == CX18_INVALID_TASK_HANDLE ||
+	    mdl_ack_count == 0 || mdl_ack_count > CX18_MAX_MDL_ACKS) {
+		if ((order->flags & CX18_F_EWO_MB_STALE) == 0)
+			mb_ack_irq(cx, order);
+		return -1;
+	}
+
+	for (i = 0; i < sizeof(struct cx18_mdl_ack) * mdl_ack_count; i += sizeof(u32))
+		((u32 *)order->mdl_ack)[i / sizeof(u32)] =
+			cx18_readl(cx, cx->enc_mem + mdl_ack_offset + i);
+
+	if ((order->flags & CX18_F_EWO_MB_STALE) == 0)
+		mb_ack_irq(cx, order);
+	return 1;
+}
+
+static
+int epu_debug_irq(struct cx18 *cx, struct cx18_in_work_order *order)
+{
+	u32 str_offset;
+	char *str = order->str;
+
+	str[0] = '\0';
+	str_offset = order->mb.args[1];
+	if (str_offset) {
+		cx18_setup_page(cx, str_offset);
+		cx18_memcpy_fromio(cx, str, cx->enc_mem + str_offset, 252);
+		str[252] = '\0';
+		cx18_setup_page(cx, SCB_OFFSET);
+	}
+
+	if ((order->flags & CX18_F_EWO_MB_STALE) == 0)
+		mb_ack_irq(cx, order);
+
+	return str_offset ? 1 : 0;
+}
+
+static inline
+int epu_cmd_irq(struct cx18 *cx, struct cx18_in_work_order *order)
+{
+	int ret = -1;
+
+	switch (order->rpu) {
+	case CPU:
+	{
+		switch (order->mb.cmd) {
+		case CX18_EPU_DMA_DONE:
+			ret = epu_dma_done_irq(cx, order);
+			break;
+		case CX18_EPU_DEBUG:
+			ret = epu_debug_irq(cx, order);
+			break;
+		default:
+			CX18_WARN("Unknown CPU to EPU mailbox command %#0x\n",
+				  order->mb.cmd);
+			break;
+		}
+		break;
+	}
+	case APU:
+		CX18_WARN("Unknown APU to EPU mailbox command %#0x\n",
+			  order->mb.cmd);
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+static inline
+struct cx18_in_work_order *alloc_in_work_order_irq(struct cx18 *cx)
+{
+	int i;
+	struct cx18_in_work_order *order = NULL;
+
+	for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) {
+		/*
+		 * We only need "pending" atomic to inspect its contents,
+		 * and need not do a check and set because:
+		 * 1. Any work handler thread only clears "pending" and only
+		 * on one, particular work order at a time, per handler thread.
+		 * 2. "pending" is only set here, and we're serialized because
+		 * we're called in an IRQ handler context.
+		 */
+		if (atomic_read(&cx->in_work_order[i].pending) == 0) {
+			order = &cx->in_work_order[i];
+			atomic_set(&order->pending, 1);
+			break;
+		}
+	}
+	return order;
+}
+
+void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
+{
+	struct cx18_mailbox __iomem *mb;
+	struct cx18_mailbox *order_mb;
+	struct cx18_in_work_order *order;
+	int submit;
+	int i;
+
+	switch (rpu) {
+	case CPU:
+		mb = &cx->scb->cpu2epu_mb;
+		break;
+	case APU:
+		mb = &cx->scb->apu2epu_mb;
+		break;
+	default:
+		return;
+	}
+
+	order = alloc_in_work_order_irq(cx);
+	if (order == NULL) {
+		CX18_WARN("Unable to find blank work order form to schedule "
+			  "incoming mailbox command processing\n");
+		return;
+	}
+
+	order->flags = 0;
+	order->rpu = rpu;
+	order_mb = &order->mb;
+
+	/* mb->cmd and mb->args[0] through mb->args[2] */
+	for (i = 0; i < 4; i++)
+		(&order_mb->cmd)[i] = cx18_readl(cx, &mb->cmd + i);
+
+	/* mb->request and mb->ack.  N.B. we want to read mb->ack last */
+	for (i = 0; i < 2; i++)
+		(&order_mb->request)[i] = cx18_readl(cx, &mb->request + i);
+
+	if (order_mb->request == order_mb->ack) {
+		CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our "
+				"incoming %s to EPU mailbox (sequence no. %u)"
+				"\n",
+				rpu_str[rpu], rpu_str[rpu], order_mb->request);
+		if (cx18_debug & CX18_DBGFLG_WARN)
+			dump_mb(cx, order_mb, "incoming");
+		order->flags = CX18_F_EWO_MB_STALE_UPON_RECEIPT;
+	}
+
+	/*
+	 * Individual EPU command processing is responsible for ack-ing
+	 * a non-stale mailbox as soon as possible
+	 */
+	submit = epu_cmd_irq(cx, order);
+	if (submit > 0) {
+		queue_work(cx->in_work_queue, &order->work);
+	}
+}
+
+
+/*
+ * Functions called from a non-interrupt, non work_queue context
+ */
+
+static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
+{
+	const struct cx18_api_info *info = find_api_info(cmd);
+	u32 irq, req, ack, err;
+	struct cx18_mailbox __iomem *mb;
+	wait_queue_head_t *waitq;
+	struct mutex *mb_lock;
+	unsigned long int t0, timeout, ret;
+	int i;
+	char argstr[MAX_MB_ARGUMENTS*11+1];
+	DEFINE_WAIT(w);
+
+	if (info == NULL) {
+		CX18_WARN("unknown cmd %x\n", cmd);
+		return -EINVAL;
+	}
+
+	if (cx18_debug & CX18_DBGFLG_API) { /* only call u32arr2hex if needed */
+		if (cmd == CX18_CPU_DE_SET_MDL) {
+			if (cx18_debug & CX18_DBGFLG_HIGHVOL)
+				CX18_DEBUG_HI_API("%s\tcmd %#010x args%s\n",
+						info->name, cmd,
+						u32arr2hex(data, args, argstr));
+		} else
+			CX18_DEBUG_API("%s\tcmd %#010x args%s\n",
+				       info->name, cmd,
+				       u32arr2hex(data, args, argstr));
+	}
+
+	switch (info->rpu) {
+	case APU:
+		waitq = &cx->mb_apu_waitq;
+		mb_lock = &cx->epu2apu_mb_lock;
+		irq = IRQ_EPU_TO_APU;
+		mb = &cx->scb->epu2apu_mb;
+		break;
+	case CPU:
+		waitq = &cx->mb_cpu_waitq;
+		mb_lock = &cx->epu2cpu_mb_lock;
+		irq = IRQ_EPU_TO_CPU;
+		mb = &cx->scb->epu2cpu_mb;
+		break;
+	default:
+		CX18_WARN("Unknown RPU (%d) for API call\n", info->rpu);
+		return -EINVAL;
+	}
+
+	mutex_lock(mb_lock);
+	/*
+	 * Wait for an in-use mailbox to complete
+	 *
+	 * If the XPU is responding with Ack's, the mailbox shouldn't be in
+	 * a busy state, since we serialize access to it on our end.
+	 *
+	 * If the wait for ack after sending a previous command was interrupted
+	 * by a signal, we may get here and find a busy mailbox.  After waiting,
+	 * mark it "not busy" from our end, if the XPU hasn't ack'ed it still.
+	 */
+	req = cx18_readl(cx, &mb->request);
+	timeout = msecs_to_jiffies(10);
+	ret = wait_event_timeout(*waitq,
+				 (ack = cx18_readl(cx, &mb->ack)) == req,
+				 timeout);
+	if (req != ack) {
+		/* waited long enough, make the mbox "not busy" from our end */
+		cx18_writel(cx, req, &mb->ack);
+		CX18_ERR("mbox was found stuck busy when setting up for %s; "
+			 "clearing busy and trying to proceed\n", info->name);
+	} else if (ret != timeout)
+		CX18_DEBUG_API("waited %u msecs for busy mbox to be acked\n",
+			       jiffies_to_msecs(timeout-ret));
+
+	/* Build the outgoing mailbox */
+	req = ((req & 0xfffffffe) == 0xfffffffe) ? 1 : req + 1;
+
+	cx18_writel(cx, cmd, &mb->cmd);
+	for (i = 0; i < args; i++)
+		cx18_writel(cx, data[i], &mb->args[i]);
+	cx18_writel(cx, 0, &mb->error);
+	cx18_writel(cx, req, &mb->request);
+	cx18_writel(cx, req - 1, &mb->ack); /* ensure ack & req are distinct */
+
+	/*
+	 * Notify the XPU and wait for it to send an Ack back
+	 */
+	timeout = msecs_to_jiffies((info->flags & API_FAST) ? 10 : 20);
+
+	CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n",
+			  irq, info->name);
+
+	/* So we don't miss the wakeup, prepare to wait before notifying fw */
+	prepare_to_wait(waitq, &w, TASK_UNINTERRUPTIBLE);
+	cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq);
+
+	t0 = jiffies;
+	ack = cx18_readl(cx, &mb->ack);
+	if (ack != req) {
+		schedule_timeout(timeout);
+		ret = jiffies - t0;
+		ack = cx18_readl(cx, &mb->ack);
+	} else {
+		ret = jiffies - t0;
+	}
+
+	finish_wait(waitq, &w);
+
+	if (req != ack) {
+		mutex_unlock(mb_lock);
+		if (ret >= timeout) {
+			/* Timed out */
+			CX18_DEBUG_WARN("sending %s timed out waiting %d msecs "
+					"for RPU acknowledgement\n",
+					info->name, jiffies_to_msecs(ret));
+		} else {
+			CX18_DEBUG_WARN("woken up before mailbox ack was ready "
+					"after submitting %s to RPU.  only "
+					"waited %d msecs on req %u but awakened"
+					" with unmatched ack %u\n",
+					info->name,
+					jiffies_to_msecs(ret),
+					req, ack);
+		}
+		return -EINVAL;
+	}
+
+	if (ret >= timeout)
+		CX18_DEBUG_WARN("failed to be awakened upon RPU acknowledgment "
+				"sending %s; timed out waiting %d msecs\n",
+				info->name, jiffies_to_msecs(ret));
+	else
+		CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n",
+				  jiffies_to_msecs(ret), info->name);
+
+	/* Collect data returned by the XPU */
+	for (i = 0; i < MAX_MB_ARGUMENTS; i++)
+		data[i] = cx18_readl(cx, &mb->args[i]);
+	err = cx18_readl(cx, &mb->error);
+	mutex_unlock(mb_lock);
+
+	/*
+	 * Wait for XPU to perform extra actions for the caller in some cases.
+	 * e.g. CX18_CPU_DE_RELEASE_MDL will cause the CPU to send all MDLs
+	 * back in a burst shortly thereafter
+	 */
+	if (info->flags & API_SLOW)
+		cx18_msleep_timeout(300, 0);
+
+	if (err)
+		CX18_DEBUG_API("mailbox error %08x for command %s\n", err,
+				info->name);
+	return err ? -EIO : 0;
+}
+
+int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[])
+{
+	return cx18_api_call(cx, cmd, args, data);
+}
+
+static int cx18_set_filter_param(struct cx18_stream *s)
+{
+	struct cx18 *cx = s->cx;
+	u32 mode;
+	int ret;
+
+	mode = (cx->filter_mode & 1) ? 2 : (cx->spatial_strength ? 1 : 0);
+	ret = cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
+			s->handle, 1, mode, cx->spatial_strength);
+	mode = (cx->filter_mode & 2) ? 2 : (cx->temporal_strength ? 1 : 0);
+	ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
+			s->handle, 0, mode, cx->temporal_strength);
+	ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
+			s->handle, 2, cx->filter_mode >> 2, 0);
+	return ret;
+}
+
+int cx18_api_func(void *priv, u32 cmd, int in, int out,
+		u32 data[CX2341X_MBOX_MAX_DATA])
+{
+	struct cx18_stream *s = priv;
+	struct cx18 *cx = s->cx;
+
+	switch (cmd) {
+	case CX2341X_ENC_SET_OUTPUT_PORT:
+		return 0;
+	case CX2341X_ENC_SET_FRAME_RATE:
+		return cx18_vapi(cx, CX18_CPU_SET_VIDEO_IN, 6,
+				s->handle, 0, 0, 0, 0, data[0]);
+	case CX2341X_ENC_SET_FRAME_SIZE:
+		return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RESOLUTION, 3,
+				s->handle, data[1], data[0]);
+	case CX2341X_ENC_SET_STREAM_TYPE:
+		return cx18_vapi(cx, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 2,
+				s->handle, data[0]);
+	case CX2341X_ENC_SET_ASPECT_RATIO:
+		return cx18_vapi(cx, CX18_CPU_SET_ASPECT_RATIO, 2,
+				s->handle, data[0]);
+
+	case CX2341X_ENC_SET_GOP_PROPERTIES:
+		return cx18_vapi(cx, CX18_CPU_SET_GOP_STRUCTURE, 3,
+				s->handle, data[0], data[1]);
+	case CX2341X_ENC_SET_GOP_CLOSURE:
+		return 0;
+	case CX2341X_ENC_SET_AUDIO_PROPERTIES:
+		return cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2,
+				s->handle, data[0]);
+	case CX2341X_ENC_MUTE_AUDIO:
+		return cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
+				s->handle, data[0]);
+	case CX2341X_ENC_SET_BIT_RATE:
+		return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RATE, 5,
+				s->handle, data[0], data[1], data[2], data[3]);
+	case CX2341X_ENC_MUTE_VIDEO:
+		return cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
+				s->handle, data[0]);
+	case CX2341X_ENC_SET_FRAME_DROP_RATE:
+		return cx18_vapi(cx, CX18_CPU_SET_SKIP_INPUT_FRAME, 2,
+				s->handle, data[0]);
+	case CX2341X_ENC_MISC:
+		return cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 4,
+				s->handle, data[0], data[1], data[2]);
+	case CX2341X_ENC_SET_DNR_FILTER_MODE:
+		cx->filter_mode = (data[0] & 3) | (data[1] << 2);
+		return cx18_set_filter_param(s);
+	case CX2341X_ENC_SET_DNR_FILTER_PROPS:
+		cx->spatial_strength = data[0];
+		cx->temporal_strength = data[1];
+		return cx18_set_filter_param(s);
+	case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
+		return cx18_vapi(cx, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 3,
+				s->handle, data[0], data[1]);
+	case CX2341X_ENC_SET_CORING_LEVELS:
+		return cx18_vapi(cx, CX18_CPU_SET_MEDIAN_CORING, 5,
+				s->handle, data[0], data[1], data[2], data[3]);
+	}
+	CX18_WARN("Unknown cmd %x\n", cmd);
+	return 0;
+}
+
+int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS],
+		u32 cmd, int args, ...)
+{
+	va_list ap;
+	int i;
+
+	va_start(ap, args);
+	for (i = 0; i < args; i++)
+		data[i] = va_arg(ap, u32);
+	va_end(ap);
+	return cx18_api(cx, cmd, args, data);
+}
+
+int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...)
+{
+	u32 data[MAX_MB_ARGUMENTS];
+	va_list ap;
+	int i;
+
+	if (cx == NULL) {
+		CX18_ERR("cx == NULL (cmd=%x)\n", cmd);
+		return 0;
+	}
+	if (args > MAX_MB_ARGUMENTS) {
+		CX18_ERR("args too big (cmd=%x)\n", cmd);
+		args = MAX_MB_ARGUMENTS;
+	}
+	va_start(ap, args);
+	for (i = 0; i < args; i++)
+		data[i] = va_arg(ap, u32);
+	va_end(ap);
+	return cx18_api(cx, cmd, args, data);
+}
diff --git a/drivers/media/pci/cx18/cx18-mailbox.h b/drivers/media/pci/cx18/cx18-mailbox.h
new file mode 100644
index 0000000..b63fdfa
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-mailbox.h
@@ -0,0 +1,95 @@
+/*
+ *  cx18 mailbox functions
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#ifndef _CX18_MAILBOX_H_
+#define _CX18_MAILBOX_H_
+
+/* mailbox max args */
+#define MAX_MB_ARGUMENTS 6
+/* compatibility, should be same as the define in cx2341x.h */
+#define CX2341X_MBOX_MAX_DATA 16
+
+#define MB_RESERVED_HANDLE_0 0
+#define MB_RESERVED_HANDLE_1 0xFFFFFFFF
+
+#define APU 0
+#define CPU 1
+#define EPU 2
+#define HPU 3
+
+struct cx18;
+
+/*
+ * This structure is used by CPU to provide completed MDL & buffers information.
+ * Its structure is dictated by the layout of the SCB, required by the
+ * firmware, but its definition needs to be here, instead of in cx18-scb.h,
+ * for mailbox work order scheduling
+ */
+struct cx18_mdl_ack {
+    u32 id;        /* ID of a completed MDL */
+    u32 data_used; /* Total data filled in the MDL with 'id' */
+};
+
+/* The cx18_mailbox struct is the mailbox structure which is used for passing
+   messages between processors */
+struct cx18_mailbox {
+    /* The sender sets a handle in 'request' after he fills the command. The
+       'request' should be different than 'ack'. The sender, also, generates
+       an interrupt on XPU2YPU_irq where XPU is the sender and YPU is the
+       receiver. */
+    u32       request;
+    /* The receiver detects a new command when 'req' is different than 'ack'.
+       He sets 'ack' to the same value as 'req' to clear the command. He, also,
+       generates an interrupt on YPU2XPU_irq where XPU is the sender and YPU
+       is the receiver. */
+    u32       ack;
+    u32       reserved[6];
+    /* 'cmd' identifies the command. The list of these commands are in
+       cx23418.h */
+    u32       cmd;
+    /* Each command can have up to 6 arguments */
+    u32       args[MAX_MB_ARGUMENTS];
+    /* The return code can be one of the codes in the file cx23418.h. If the
+       command is completed successfully, the error will be ERR_SYS_SUCCESS.
+       If it is pending, the code is ERR_SYS_PENDING. If it failed, the error
+       code would indicate the task from which the error originated and will
+       be one of the errors in cx23418.h. In that case, the following
+       applies ((error & 0xff) != 0).
+       If the command is pending, the return will be passed in a MB from the
+       receiver to the sender. 'req' will be returned in args[0] */
+    u32       error;
+};
+
+struct cx18_stream;
+
+int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]);
+int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd,
+		int args, ...);
+int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...);
+int cx18_api_func(void *priv, u32 cmd, int in, int out,
+		u32 data[CX2341X_MBOX_MAX_DATA]);
+
+void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu);
+
+void cx18_in_work_handler(struct work_struct *work);
+
+#endif
diff --git a/drivers/media/pci/cx18/cx18-queue.c b/drivers/media/pci/cx18/cx18-queue.c
new file mode 100644
index 0000000..8884537
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-queue.c
@@ -0,0 +1,443 @@
+/*
+ *  cx18 buffer queues
+ *
+ *  Derived from ivtv-queue.c
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-queue.h"
+#include "cx18-streams.h"
+#include "cx18-scb.h"
+#include "cx18-io.h"
+
+void cx18_buf_swap(struct cx18_buffer *buf)
+{
+	int i;
+
+	for (i = 0; i < buf->bytesused; i += 4)
+		swab32s((u32 *)(buf->buf + i));
+}
+
+void _cx18_mdl_swap(struct cx18_mdl *mdl)
+{
+	struct cx18_buffer *buf;
+
+	list_for_each_entry(buf, &mdl->buf_list, list) {
+		if (buf->bytesused == 0)
+			break;
+		cx18_buf_swap(buf);
+	}
+}
+
+void cx18_queue_init(struct cx18_queue *q)
+{
+	INIT_LIST_HEAD(&q->list);
+	atomic_set(&q->depth, 0);
+	q->bytesused = 0;
+}
+
+struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl,
+				 struct cx18_queue *q, int to_front)
+{
+	/* clear the mdl if it is not to be enqueued to the full queue */
+	if (q != &s->q_full) {
+		mdl->bytesused = 0;
+		mdl->readpos = 0;
+		mdl->m_flags = 0;
+		mdl->skipped = 0;
+		mdl->curr_buf = NULL;
+	}
+
+	/* q_busy is restricted to a max buffer count imposed by firmware */
+	if (q == &s->q_busy &&
+	    atomic_read(&q->depth) >= CX18_MAX_FW_MDLS_PER_STREAM)
+		q = &s->q_free;
+
+	spin_lock(&q->lock);
+
+	if (to_front)
+		list_add(&mdl->list, &q->list); /* LIFO */
+	else
+		list_add_tail(&mdl->list, &q->list); /* FIFO */
+	q->bytesused += mdl->bytesused - mdl->readpos;
+	atomic_inc(&q->depth);
+
+	spin_unlock(&q->lock);
+	return q;
+}
+
+struct cx18_mdl *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
+{
+	struct cx18_mdl *mdl = NULL;
+
+	spin_lock(&q->lock);
+	if (!list_empty(&q->list)) {
+		mdl = list_first_entry(&q->list, struct cx18_mdl, list);
+		list_del_init(&mdl->list);
+		q->bytesused -= mdl->bytesused - mdl->readpos;
+		mdl->skipped = 0;
+		atomic_dec(&q->depth);
+	}
+	spin_unlock(&q->lock);
+	return mdl;
+}
+
+static void _cx18_mdl_update_bufs_for_cpu(struct cx18_stream *s,
+					  struct cx18_mdl *mdl)
+{
+	struct cx18_buffer *buf;
+	u32 buf_size = s->buf_size;
+	u32 bytesused = mdl->bytesused;
+
+	list_for_each_entry(buf, &mdl->buf_list, list) {
+		buf->readpos = 0;
+		if (bytesused >= buf_size) {
+			buf->bytesused = buf_size;
+			bytesused -= buf_size;
+		} else {
+			buf->bytesused = bytesused;
+			bytesused = 0;
+		}
+		cx18_buf_sync_for_cpu(s, buf);
+	}
+}
+
+static inline void cx18_mdl_update_bufs_for_cpu(struct cx18_stream *s,
+						struct cx18_mdl *mdl)
+{
+	struct cx18_buffer *buf;
+
+	if (list_is_singular(&mdl->buf_list)) {
+		buf = list_first_entry(&mdl->buf_list, struct cx18_buffer,
+				       list);
+		buf->bytesused = mdl->bytesused;
+		buf->readpos = 0;
+		cx18_buf_sync_for_cpu(s, buf);
+	} else {
+		_cx18_mdl_update_bufs_for_cpu(s, mdl);
+	}
+}
+
+struct cx18_mdl *cx18_queue_get_mdl(struct cx18_stream *s, u32 id,
+	u32 bytesused)
+{
+	struct cx18 *cx = s->cx;
+	struct cx18_mdl *mdl;
+	struct cx18_mdl *tmp;
+	struct cx18_mdl *ret = NULL;
+	LIST_HEAD(sweep_up);
+
+	/*
+	 * We don't have to acquire multiple q locks here, because we are
+	 * serialized by the single threaded work handler.
+	 * MDLs from the firmware will thus remain in order as
+	 * they are moved from q_busy to q_full or to the dvb ring buffer.
+	 */
+	spin_lock(&s->q_busy.lock);
+	list_for_each_entry_safe(mdl, tmp, &s->q_busy.list, list) {
+		/*
+		 * We should find what the firmware told us is done,
+		 * right at the front of the queue.  If we don't, we likely have
+		 * missed an mdl done message from the firmware.
+		 * Once we skip an mdl repeatedly, relative to the size of
+		 * q_busy, we have high confidence we've missed it.
+		 */
+		if (mdl->id != id) {
+			mdl->skipped++;
+			if (mdl->skipped >= atomic_read(&s->q_busy.depth)-1) {
+				/* mdl must have fallen out of rotation */
+				CX18_WARN("Skipped %s, MDL %d, %d "
+					  "times - it must have dropped out of "
+					  "rotation\n", s->name, mdl->id,
+					  mdl->skipped);
+				/* Sweep it up to put it back into rotation */
+				list_move_tail(&mdl->list, &sweep_up);
+				atomic_dec(&s->q_busy.depth);
+			}
+			continue;
+		}
+		/*
+		 * We pull the desired mdl off of the queue here.  Something
+		 * will have to put it back on a queue later.
+		 */
+		list_del_init(&mdl->list);
+		atomic_dec(&s->q_busy.depth);
+		ret = mdl;
+		break;
+	}
+	spin_unlock(&s->q_busy.lock);
+
+	/*
+	 * We found the mdl for which we were looking.  Get it ready for
+	 * the caller to put on q_full or in the dvb ring buffer.
+	 */
+	if (ret != NULL) {
+		ret->bytesused = bytesused;
+		ret->skipped = 0;
+		/* 0'ed readpos, m_flags & curr_buf when mdl went on q_busy */
+		cx18_mdl_update_bufs_for_cpu(s, ret);
+		if (s->type != CX18_ENC_STREAM_TYPE_TS)
+			set_bit(CX18_F_M_NEED_SWAP, &ret->m_flags);
+	}
+
+	/* Put any mdls the firmware is ignoring back into normal rotation */
+	list_for_each_entry_safe(mdl, tmp, &sweep_up, list) {
+		list_del_init(&mdl->list);
+		cx18_enqueue(s, mdl, &s->q_free);
+	}
+	return ret;
+}
+
+/* Move all mdls of a queue, while flushing the mdl */
+static void cx18_queue_flush(struct cx18_stream *s,
+			     struct cx18_queue *q_src, struct cx18_queue *q_dst)
+{
+	struct cx18_mdl *mdl;
+
+	/* It only makes sense to flush to q_free or q_idle */
+	if (q_src == q_dst || q_dst == &s->q_full || q_dst == &s->q_busy)
+		return;
+
+	spin_lock(&q_src->lock);
+	spin_lock(&q_dst->lock);
+	while (!list_empty(&q_src->list)) {
+		mdl = list_first_entry(&q_src->list, struct cx18_mdl, list);
+		list_move_tail(&mdl->list, &q_dst->list);
+		mdl->bytesused = 0;
+		mdl->readpos = 0;
+		mdl->m_flags = 0;
+		mdl->skipped = 0;
+		mdl->curr_buf = NULL;
+		atomic_inc(&q_dst->depth);
+	}
+	cx18_queue_init(q_src);
+	spin_unlock(&q_src->lock);
+	spin_unlock(&q_dst->lock);
+}
+
+void cx18_flush_queues(struct cx18_stream *s)
+{
+	cx18_queue_flush(s, &s->q_busy, &s->q_free);
+	cx18_queue_flush(s, &s->q_full, &s->q_free);
+}
+
+/*
+ * Note, s->buf_pool is not protected by a lock,
+ * the stream better not have *anything* going on when calling this
+ */
+void cx18_unload_queues(struct cx18_stream *s)
+{
+	struct cx18_queue *q_idle = &s->q_idle;
+	struct cx18_mdl *mdl;
+	struct cx18_buffer *buf;
+
+	/* Move all MDLS to q_idle */
+	cx18_queue_flush(s, &s->q_busy, q_idle);
+	cx18_queue_flush(s, &s->q_full, q_idle);
+	cx18_queue_flush(s, &s->q_free, q_idle);
+
+	/* Reset MDL id's and move all buffers back to the stream's buf_pool */
+	spin_lock(&q_idle->lock);
+	list_for_each_entry(mdl, &q_idle->list, list) {
+		while (!list_empty(&mdl->buf_list)) {
+			buf = list_first_entry(&mdl->buf_list,
+					       struct cx18_buffer, list);
+			list_move_tail(&buf->list, &s->buf_pool);
+			buf->bytesused = 0;
+			buf->readpos = 0;
+		}
+		mdl->id = s->mdl_base_idx; /* reset id to a "safe" value */
+		/* all other mdl fields were cleared by cx18_queue_flush() */
+	}
+	spin_unlock(&q_idle->lock);
+}
+
+/*
+ * Note, s->buf_pool is not protected by a lock,
+ * the stream better not have *anything* going on when calling this
+ */
+void cx18_load_queues(struct cx18_stream *s)
+{
+	struct cx18 *cx = s->cx;
+	struct cx18_mdl *mdl;
+	struct cx18_buffer *buf;
+	int mdl_id;
+	int i;
+	u32 partial_buf_size;
+
+	/*
+	 * Attach buffers to MDLs, give the MDLs ids, and add MDLs to q_free
+	 * Excess MDLs are left on q_idle
+	 * Excess buffers are left in buf_pool and/or on an MDL in q_idle
+	 */
+	mdl_id = s->mdl_base_idx;
+	for (mdl = cx18_dequeue(s, &s->q_idle), i = s->bufs_per_mdl;
+	     mdl != NULL && i == s->bufs_per_mdl;
+	     mdl = cx18_dequeue(s, &s->q_idle)) {
+
+		mdl->id = mdl_id;
+
+		for (i = 0; i < s->bufs_per_mdl; i++) {
+			if (list_empty(&s->buf_pool))
+				break;
+
+			buf = list_first_entry(&s->buf_pool, struct cx18_buffer,
+					       list);
+			list_move_tail(&buf->list, &mdl->buf_list);
+
+			/* update the firmware's MDL array with this buffer */
+			cx18_writel(cx, buf->dma_handle,
+				    &cx->scb->cpu_mdl[mdl_id + i].paddr);
+			cx18_writel(cx, s->buf_size,
+				    &cx->scb->cpu_mdl[mdl_id + i].length);
+		}
+
+		if (i == s->bufs_per_mdl) {
+			/*
+			 * The encoder doesn't honor s->mdl_size.  So in the
+			 * case of a non-integral number of buffers to meet
+			 * mdl_size, we lie about the size of the last buffer
+			 * in the MDL to get the encoder to really only send
+			 * us mdl_size bytes per MDL transfer.
+			 */
+			partial_buf_size = s->mdl_size % s->buf_size;
+			if (partial_buf_size) {
+				cx18_writel(cx, partial_buf_size,
+				      &cx->scb->cpu_mdl[mdl_id + i - 1].length);
+			}
+			cx18_enqueue(s, mdl, &s->q_free);
+		} else {
+			/* Not enough buffers for this MDL; we won't use it */
+			cx18_push(s, mdl, &s->q_idle);
+		}
+		mdl_id += i;
+	}
+}
+
+void _cx18_mdl_sync_for_device(struct cx18_stream *s, struct cx18_mdl *mdl)
+{
+	int dma = s->dma;
+	u32 buf_size = s->buf_size;
+	struct pci_dev *pci_dev = s->cx->pci_dev;
+	struct cx18_buffer *buf;
+
+	list_for_each_entry(buf, &mdl->buf_list, list)
+		pci_dma_sync_single_for_device(pci_dev, buf->dma_handle,
+					       buf_size, dma);
+}
+
+int cx18_stream_alloc(struct cx18_stream *s)
+{
+	struct cx18 *cx = s->cx;
+	int i;
+
+	if (s->buffers == 0)
+		return 0;
+
+	CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers "
+			"(%d.%02d kB total)\n",
+		s->name, s->buffers, s->buf_size,
+		s->buffers * s->buf_size / 1024,
+		(s->buffers * s->buf_size * 100 / 1024) % 100);
+
+	if (((char __iomem *)&cx->scb->cpu_mdl[cx->free_mdl_idx + s->buffers] -
+				(char __iomem *)cx->scb) > SCB_RESERVED_SIZE) {
+		unsigned bufsz = (((char __iomem *)cx->scb) + SCB_RESERVED_SIZE -
+					((char __iomem *)cx->scb->cpu_mdl));
+
+		CX18_ERR("Too many buffers, cannot fit in SCB area\n");
+		CX18_ERR("Max buffers = %zd\n",
+			bufsz / sizeof(struct cx18_mdl_ent));
+		return -ENOMEM;
+	}
+
+	s->mdl_base_idx = cx->free_mdl_idx;
+
+	/* allocate stream buffers and MDLs */
+	for (i = 0; i < s->buffers; i++) {
+		struct cx18_mdl *mdl;
+		struct cx18_buffer *buf;
+
+		/* 1 MDL per buffer to handle the worst & also default case */
+		mdl = kzalloc(sizeof(struct cx18_mdl), GFP_KERNEL|__GFP_NOWARN);
+		if (mdl == NULL)
+			break;
+
+		buf = kzalloc(sizeof(struct cx18_buffer),
+				GFP_KERNEL|__GFP_NOWARN);
+		if (buf == NULL) {
+			kfree(mdl);
+			break;
+		}
+
+		buf->buf = kmalloc(s->buf_size, GFP_KERNEL|__GFP_NOWARN);
+		if (buf->buf == NULL) {
+			kfree(mdl);
+			kfree(buf);
+			break;
+		}
+
+		INIT_LIST_HEAD(&mdl->list);
+		INIT_LIST_HEAD(&mdl->buf_list);
+		mdl->id = s->mdl_base_idx; /* a somewhat safe value */
+		cx18_enqueue(s, mdl, &s->q_idle);
+
+		INIT_LIST_HEAD(&buf->list);
+		buf->dma_handle = pci_map_single(s->cx->pci_dev,
+				buf->buf, s->buf_size, s->dma);
+		cx18_buf_sync_for_cpu(s, buf);
+		list_add_tail(&buf->list, &s->buf_pool);
+	}
+	if (i == s->buffers) {
+		cx->free_mdl_idx += s->buffers;
+		return 0;
+	}
+	CX18_ERR("Couldn't allocate buffers for %s stream\n", s->name);
+	cx18_stream_free(s);
+	return -ENOMEM;
+}
+
+void cx18_stream_free(struct cx18_stream *s)
+{
+	struct cx18_mdl *mdl;
+	struct cx18_buffer *buf;
+	struct cx18 *cx = s->cx;
+
+	CX18_DEBUG_INFO("Deallocating buffers for %s stream\n", s->name);
+
+	/* move all buffers to buf_pool and all MDLs to q_idle */
+	cx18_unload_queues(s);
+
+	/* empty q_idle */
+	while ((mdl = cx18_dequeue(s, &s->q_idle)))
+		kfree(mdl);
+
+	/* empty buf_pool */
+	while (!list_empty(&s->buf_pool)) {
+		buf = list_first_entry(&s->buf_pool, struct cx18_buffer, list);
+		list_del_init(&buf->list);
+
+		pci_unmap_single(s->cx->pci_dev, buf->dma_handle,
+				s->buf_size, s->dma);
+		kfree(buf->buf);
+		kfree(buf);
+	}
+}
diff --git a/drivers/media/pci/cx18/cx18-queue.h b/drivers/media/pci/cx18/cx18-queue.h
new file mode 100644
index 0000000..4201ddc
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-queue.h
@@ -0,0 +1,98 @@
+/*
+ *  cx18 buffer queues
+ *
+ *  Derived from ivtv-queue.h
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#define CX18_DMA_UNMAPPED	((u32) -1)
+
+/* cx18_buffer utility functions */
+
+static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s,
+	struct cx18_buffer *buf)
+{
+	pci_dma_sync_single_for_cpu(s->cx->pci_dev, buf->dma_handle,
+				s->buf_size, s->dma);
+}
+
+static inline void cx18_buf_sync_for_device(struct cx18_stream *s,
+	struct cx18_buffer *buf)
+{
+	pci_dma_sync_single_for_device(s->cx->pci_dev, buf->dma_handle,
+				s->buf_size, s->dma);
+}
+
+void _cx18_mdl_sync_for_device(struct cx18_stream *s, struct cx18_mdl *mdl);
+
+static inline void cx18_mdl_sync_for_device(struct cx18_stream *s,
+					    struct cx18_mdl *mdl)
+{
+	if (list_is_singular(&mdl->buf_list))
+		cx18_buf_sync_for_device(s, list_first_entry(&mdl->buf_list,
+							     struct cx18_buffer,
+							     list));
+	else
+		_cx18_mdl_sync_for_device(s, mdl);
+}
+
+void cx18_buf_swap(struct cx18_buffer *buf);
+void _cx18_mdl_swap(struct cx18_mdl *mdl);
+
+static inline void cx18_mdl_swap(struct cx18_mdl *mdl)
+{
+	if (list_is_singular(&mdl->buf_list))
+		cx18_buf_swap(list_first_entry(&mdl->buf_list,
+					       struct cx18_buffer, list));
+	else
+		_cx18_mdl_swap(mdl);
+}
+
+/* cx18_queue utility functions */
+struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl,
+				 struct cx18_queue *q, int to_front);
+
+static inline
+struct cx18_queue *cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl,
+				struct cx18_queue *q)
+{
+	return _cx18_enqueue(s, mdl, q, 0); /* FIFO */
+}
+
+static inline
+struct cx18_queue *cx18_push(struct cx18_stream *s, struct cx18_mdl *mdl,
+			     struct cx18_queue *q)
+{
+	return _cx18_enqueue(s, mdl, q, 1); /* LIFO */
+}
+
+void cx18_queue_init(struct cx18_queue *q);
+struct cx18_mdl *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q);
+struct cx18_mdl *cx18_queue_get_mdl(struct cx18_stream *s, u32 id,
+	u32 bytesused);
+void cx18_flush_queues(struct cx18_stream *s);
+
+/* queue MDL reconfiguration helpers */
+void cx18_unload_queues(struct cx18_stream *s);
+void cx18_load_queues(struct cx18_stream *s);
+
+/* cx18_stream utility functions */
+int cx18_stream_alloc(struct cx18_stream *s);
+void cx18_stream_free(struct cx18_stream *s);
diff --git a/drivers/media/pci/cx18/cx18-scb.c b/drivers/media/pci/cx18/cx18-scb.c
new file mode 100644
index 0000000..85cc596
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-scb.c
@@ -0,0 +1,122 @@
+/*
+ *  cx18 System Control Block initialization
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-io.h"
+#include "cx18-scb.h"
+
+void cx18_init_scb(struct cx18 *cx)
+{
+	cx18_setup_page(cx, SCB_OFFSET);
+	cx18_memset_io(cx, cx->scb, 0, 0x10000);
+
+	cx18_writel(cx, IRQ_APU_TO_CPU,     &cx->scb->apu2cpu_irq);
+	cx18_writel(cx, IRQ_CPU_TO_APU_ACK, &cx->scb->cpu2apu_irq_ack);
+	cx18_writel(cx, IRQ_HPU_TO_CPU,     &cx->scb->hpu2cpu_irq);
+	cx18_writel(cx, IRQ_CPU_TO_HPU_ACK, &cx->scb->cpu2hpu_irq_ack);
+	cx18_writel(cx, IRQ_PPU_TO_CPU,     &cx->scb->ppu2cpu_irq);
+	cx18_writel(cx, IRQ_CPU_TO_PPU_ACK, &cx->scb->cpu2ppu_irq_ack);
+	cx18_writel(cx, IRQ_EPU_TO_CPU,     &cx->scb->epu2cpu_irq);
+	cx18_writel(cx, IRQ_CPU_TO_EPU_ACK, &cx->scb->cpu2epu_irq_ack);
+
+	cx18_writel(cx, IRQ_CPU_TO_APU,     &cx->scb->cpu2apu_irq);
+	cx18_writel(cx, IRQ_APU_TO_CPU_ACK, &cx->scb->apu2cpu_irq_ack);
+	cx18_writel(cx, IRQ_HPU_TO_APU,     &cx->scb->hpu2apu_irq);
+	cx18_writel(cx, IRQ_APU_TO_HPU_ACK, &cx->scb->apu2hpu_irq_ack);
+	cx18_writel(cx, IRQ_PPU_TO_APU,     &cx->scb->ppu2apu_irq);
+	cx18_writel(cx, IRQ_APU_TO_PPU_ACK, &cx->scb->apu2ppu_irq_ack);
+	cx18_writel(cx, IRQ_EPU_TO_APU,     &cx->scb->epu2apu_irq);
+	cx18_writel(cx, IRQ_APU_TO_EPU_ACK, &cx->scb->apu2epu_irq_ack);
+
+	cx18_writel(cx, IRQ_CPU_TO_HPU,     &cx->scb->cpu2hpu_irq);
+	cx18_writel(cx, IRQ_HPU_TO_CPU_ACK, &cx->scb->hpu2cpu_irq_ack);
+	cx18_writel(cx, IRQ_APU_TO_HPU,     &cx->scb->apu2hpu_irq);
+	cx18_writel(cx, IRQ_HPU_TO_APU_ACK, &cx->scb->hpu2apu_irq_ack);
+	cx18_writel(cx, IRQ_PPU_TO_HPU,     &cx->scb->ppu2hpu_irq);
+	cx18_writel(cx, IRQ_HPU_TO_PPU_ACK, &cx->scb->hpu2ppu_irq_ack);
+	cx18_writel(cx, IRQ_EPU_TO_HPU,     &cx->scb->epu2hpu_irq);
+	cx18_writel(cx, IRQ_HPU_TO_EPU_ACK, &cx->scb->hpu2epu_irq_ack);
+
+	cx18_writel(cx, IRQ_CPU_TO_PPU,     &cx->scb->cpu2ppu_irq);
+	cx18_writel(cx, IRQ_PPU_TO_CPU_ACK, &cx->scb->ppu2cpu_irq_ack);
+	cx18_writel(cx, IRQ_APU_TO_PPU,     &cx->scb->apu2ppu_irq);
+	cx18_writel(cx, IRQ_PPU_TO_APU_ACK, &cx->scb->ppu2apu_irq_ack);
+	cx18_writel(cx, IRQ_HPU_TO_PPU,     &cx->scb->hpu2ppu_irq);
+	cx18_writel(cx, IRQ_PPU_TO_HPU_ACK, &cx->scb->ppu2hpu_irq_ack);
+	cx18_writel(cx, IRQ_EPU_TO_PPU,     &cx->scb->epu2ppu_irq);
+	cx18_writel(cx, IRQ_PPU_TO_EPU_ACK, &cx->scb->ppu2epu_irq_ack);
+
+	cx18_writel(cx, IRQ_CPU_TO_EPU,     &cx->scb->cpu2epu_irq);
+	cx18_writel(cx, IRQ_EPU_TO_CPU_ACK, &cx->scb->epu2cpu_irq_ack);
+	cx18_writel(cx, IRQ_APU_TO_EPU,     &cx->scb->apu2epu_irq);
+	cx18_writel(cx, IRQ_EPU_TO_APU_ACK, &cx->scb->epu2apu_irq_ack);
+	cx18_writel(cx, IRQ_HPU_TO_EPU,     &cx->scb->hpu2epu_irq);
+	cx18_writel(cx, IRQ_EPU_TO_HPU_ACK, &cx->scb->epu2hpu_irq_ack);
+	cx18_writel(cx, IRQ_PPU_TO_EPU,     &cx->scb->ppu2epu_irq);
+	cx18_writel(cx, IRQ_EPU_TO_PPU_ACK, &cx->scb->epu2ppu_irq_ack);
+
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2cpu_mb),
+			&cx->scb->apu2cpu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2cpu_mb),
+			&cx->scb->hpu2cpu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2cpu_mb),
+			&cx->scb->ppu2cpu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2cpu_mb),
+			&cx->scb->epu2cpu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2apu_mb),
+			&cx->scb->cpu2apu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2apu_mb),
+			&cx->scb->hpu2apu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2apu_mb),
+			&cx->scb->ppu2apu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2apu_mb),
+			&cx->scb->epu2apu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2hpu_mb),
+			&cx->scb->cpu2hpu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2hpu_mb),
+			&cx->scb->apu2hpu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2hpu_mb),
+			&cx->scb->ppu2hpu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2hpu_mb),
+			&cx->scb->epu2hpu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2ppu_mb),
+			&cx->scb->cpu2ppu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2ppu_mb),
+			&cx->scb->apu2ppu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2ppu_mb),
+			&cx->scb->hpu2ppu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2ppu_mb),
+			&cx->scb->epu2ppu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2epu_mb),
+			&cx->scb->cpu2epu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2epu_mb),
+			&cx->scb->apu2epu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2epu_mb),
+			&cx->scb->hpu2epu_mb_offset);
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2epu_mb),
+			&cx->scb->ppu2epu_mb_offset);
+
+	cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu_state),
+			&cx->scb->ipc_offset);
+
+	cx18_writel(cx, 1, &cx->scb->epu_state);
+}
diff --git a/drivers/media/pci/cx18/cx18-scb.h b/drivers/media/pci/cx18/cx18-scb.h
new file mode 100644
index 0000000..0887765
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-scb.h
@@ -0,0 +1,280 @@
+/*
+ *  cx18 System Control Block initialization
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#ifndef CX18_SCB_H
+#define CX18_SCB_H
+
+#include "cx18-mailbox.h"
+
+/* NOTE: All ACK interrupts are in the SW2 register.  All non-ACK interrupts
+   are in the SW1 register. */
+
+#define IRQ_APU_TO_CPU         0x00000001
+#define IRQ_CPU_TO_APU_ACK     0x00000001
+#define IRQ_HPU_TO_CPU         0x00000002
+#define IRQ_CPU_TO_HPU_ACK     0x00000002
+#define IRQ_PPU_TO_CPU         0x00000004
+#define IRQ_CPU_TO_PPU_ACK     0x00000004
+#define IRQ_EPU_TO_CPU         0x00000008
+#define IRQ_CPU_TO_EPU_ACK     0x00000008
+
+#define IRQ_CPU_TO_APU         0x00000010
+#define IRQ_APU_TO_CPU_ACK     0x00000010
+#define IRQ_HPU_TO_APU         0x00000020
+#define IRQ_APU_TO_HPU_ACK     0x00000020
+#define IRQ_PPU_TO_APU         0x00000040
+#define IRQ_APU_TO_PPU_ACK     0x00000040
+#define IRQ_EPU_TO_APU         0x00000080
+#define IRQ_APU_TO_EPU_ACK     0x00000080
+
+#define IRQ_CPU_TO_HPU         0x00000100
+#define IRQ_HPU_TO_CPU_ACK     0x00000100
+#define IRQ_APU_TO_HPU         0x00000200
+#define IRQ_HPU_TO_APU_ACK     0x00000200
+#define IRQ_PPU_TO_HPU         0x00000400
+#define IRQ_HPU_TO_PPU_ACK     0x00000400
+#define IRQ_EPU_TO_HPU         0x00000800
+#define IRQ_HPU_TO_EPU_ACK     0x00000800
+
+#define IRQ_CPU_TO_PPU         0x00001000
+#define IRQ_PPU_TO_CPU_ACK     0x00001000
+#define IRQ_APU_TO_PPU         0x00002000
+#define IRQ_PPU_TO_APU_ACK     0x00002000
+#define IRQ_HPU_TO_PPU         0x00004000
+#define IRQ_PPU_TO_HPU_ACK     0x00004000
+#define IRQ_EPU_TO_PPU         0x00008000
+#define IRQ_PPU_TO_EPU_ACK     0x00008000
+
+#define IRQ_CPU_TO_EPU         0x00010000
+#define IRQ_EPU_TO_CPU_ACK     0x00010000
+#define IRQ_APU_TO_EPU         0x00020000
+#define IRQ_EPU_TO_APU_ACK     0x00020000
+#define IRQ_HPU_TO_EPU         0x00040000
+#define IRQ_EPU_TO_HPU_ACK     0x00040000
+#define IRQ_PPU_TO_EPU         0x00080000
+#define IRQ_EPU_TO_PPU_ACK     0x00080000
+
+#define SCB_OFFSET  0xDC0000
+
+/* If Firmware uses fixed memory map, it shall not allocate the area
+   between SCB_OFFSET and SCB_OFFSET+SCB_RESERVED_SIZE-1 inclusive */
+#define SCB_RESERVED_SIZE 0x10000
+
+
+/* This structure is used by EPU to provide memory descriptors in its memory */
+struct cx18_mdl_ent {
+    u32 paddr;  /* Physical address of a buffer segment */
+    u32 length; /* Length of the buffer segment */
+};
+
+struct cx18_scb {
+	/* These fields form the System Control Block which is used at boot time
+	   for localizing the IPC data as well as the code positions for all
+	   processors. The offsets are from the start of this struct. */
+
+	/* Offset where to find the Inter-Processor Communication data */
+	u32 ipc_offset;
+	u32 reserved01[7];
+	/* Offset where to find the start of the CPU code */
+	u32 cpu_code_offset;
+	u32 reserved02[3];
+	/* Offset where to find the start of the APU code */
+	u32 apu_code_offset;
+	u32 reserved03[3];
+	/* Offset where to find the start of the HPU code */
+	u32 hpu_code_offset;
+	u32 reserved04[3];
+	/* Offset where to find the start of the PPU code */
+	u32 ppu_code_offset;
+	u32 reserved05[3];
+
+	/* These fields form Inter-Processor Communication data which is used
+	   by all processors to locate the information needed for communicating
+	   with other processors */
+
+	/* Fields for CPU: */
+
+	/* bit 0: 1/0 processor ready/not ready. Set other bits to 0. */
+	u32 cpu_state;
+	u32 reserved1[7];
+	/* Offset to the mailbox used for sending commands from APU to CPU */
+	u32 apu2cpu_mb_offset;
+	/* Value to write to register SW1 register set (0xC7003100) after the
+	   command is ready */
+	u32 apu2cpu_irq;
+	/* Value to write to register SW2 register set (0xC7003140) after the
+	   command is cleared */
+	u32 cpu2apu_irq_ack;
+	u32 reserved2[13];
+
+	u32 hpu2cpu_mb_offset;
+	u32 hpu2cpu_irq;
+	u32 cpu2hpu_irq_ack;
+	u32 reserved3[13];
+
+	u32 ppu2cpu_mb_offset;
+	u32 ppu2cpu_irq;
+	u32 cpu2ppu_irq_ack;
+	u32 reserved4[13];
+
+	u32 epu2cpu_mb_offset;
+	u32 epu2cpu_irq;
+	u32 cpu2epu_irq_ack;
+	u32 reserved5[13];
+	u32 reserved6[8];
+
+	/* Fields for APU: */
+
+	u32 apu_state;
+	u32 reserved11[7];
+	u32 cpu2apu_mb_offset;
+	u32 cpu2apu_irq;
+	u32 apu2cpu_irq_ack;
+	u32 reserved12[13];
+
+	u32 hpu2apu_mb_offset;
+	u32 hpu2apu_irq;
+	u32 apu2hpu_irq_ack;
+	u32 reserved13[13];
+
+	u32 ppu2apu_mb_offset;
+	u32 ppu2apu_irq;
+	u32 apu2ppu_irq_ack;
+	u32 reserved14[13];
+
+	u32 epu2apu_mb_offset;
+	u32 epu2apu_irq;
+	u32 apu2epu_irq_ack;
+	u32 reserved15[13];
+	u32 reserved16[8];
+
+	/* Fields for HPU: */
+
+	u32 hpu_state;
+	u32 reserved21[7];
+	u32 cpu2hpu_mb_offset;
+	u32 cpu2hpu_irq;
+	u32 hpu2cpu_irq_ack;
+	u32 reserved22[13];
+
+	u32 apu2hpu_mb_offset;
+	u32 apu2hpu_irq;
+	u32 hpu2apu_irq_ack;
+	u32 reserved23[13];
+
+	u32 ppu2hpu_mb_offset;
+	u32 ppu2hpu_irq;
+	u32 hpu2ppu_irq_ack;
+	u32 reserved24[13];
+
+	u32 epu2hpu_mb_offset;
+	u32 epu2hpu_irq;
+	u32 hpu2epu_irq_ack;
+	u32 reserved25[13];
+	u32 reserved26[8];
+
+	/* Fields for PPU: */
+
+	u32 ppu_state;
+	u32 reserved31[7];
+	u32 cpu2ppu_mb_offset;
+	u32 cpu2ppu_irq;
+	u32 ppu2cpu_irq_ack;
+	u32 reserved32[13];
+
+	u32 apu2ppu_mb_offset;
+	u32 apu2ppu_irq;
+	u32 ppu2apu_irq_ack;
+	u32 reserved33[13];
+
+	u32 hpu2ppu_mb_offset;
+	u32 hpu2ppu_irq;
+	u32 ppu2hpu_irq_ack;
+	u32 reserved34[13];
+
+	u32 epu2ppu_mb_offset;
+	u32 epu2ppu_irq;
+	u32 ppu2epu_irq_ack;
+	u32 reserved35[13];
+	u32 reserved36[8];
+
+	/* Fields for EPU: */
+
+	u32 epu_state;
+	u32 reserved41[7];
+	u32 cpu2epu_mb_offset;
+	u32 cpu2epu_irq;
+	u32 epu2cpu_irq_ack;
+	u32 reserved42[13];
+
+	u32 apu2epu_mb_offset;
+	u32 apu2epu_irq;
+	u32 epu2apu_irq_ack;
+	u32 reserved43[13];
+
+	u32 hpu2epu_mb_offset;
+	u32 hpu2epu_irq;
+	u32 epu2hpu_irq_ack;
+	u32 reserved44[13];
+
+	u32 ppu2epu_mb_offset;
+	u32 ppu2epu_irq;
+	u32 epu2ppu_irq_ack;
+	u32 reserved45[13];
+	u32 reserved46[8];
+
+	u32 semaphores[8];  /* Semaphores */
+
+	u32 reserved50[32]; /* Reserved for future use */
+
+	struct cx18_mailbox  apu2cpu_mb;
+	struct cx18_mailbox  hpu2cpu_mb;
+	struct cx18_mailbox  ppu2cpu_mb;
+	struct cx18_mailbox  epu2cpu_mb;
+
+	struct cx18_mailbox  cpu2apu_mb;
+	struct cx18_mailbox  hpu2apu_mb;
+	struct cx18_mailbox  ppu2apu_mb;
+	struct cx18_mailbox  epu2apu_mb;
+
+	struct cx18_mailbox  cpu2hpu_mb;
+	struct cx18_mailbox  apu2hpu_mb;
+	struct cx18_mailbox  ppu2hpu_mb;
+	struct cx18_mailbox  epu2hpu_mb;
+
+	struct cx18_mailbox  cpu2ppu_mb;
+	struct cx18_mailbox  apu2ppu_mb;
+	struct cx18_mailbox  hpu2ppu_mb;
+	struct cx18_mailbox  epu2ppu_mb;
+
+	struct cx18_mailbox  cpu2epu_mb;
+	struct cx18_mailbox  apu2epu_mb;
+	struct cx18_mailbox  hpu2epu_mb;
+	struct cx18_mailbox  ppu2epu_mb;
+
+	struct cx18_mdl_ack  cpu_mdl_ack[CX18_MAX_STREAMS][CX18_MAX_MDL_ACKS];
+	struct cx18_mdl_ent  cpu_mdl[1];
+};
+
+void cx18_init_scb(struct cx18 *cx);
+
+#endif
diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c
new file mode 100644
index 0000000..9d598ab
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-streams.c
@@ -0,0 +1,1060 @@
+/*
+ *  cx18 init/start/stop/exit stream functions
+ *
+ *  Derived from ivtv-streams.c
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-io.h"
+#include "cx18-fileops.h"
+#include "cx18-mailbox.h"
+#include "cx18-i2c.h"
+#include "cx18-queue.h"
+#include "cx18-ioctl.h"
+#include "cx18-streams.h"
+#include "cx18-cards.h"
+#include "cx18-scb.h"
+#include "cx18-dvb.h"
+
+#define CX18_DSP0_INTERRUPT_MASK     	0xd0004C
+
+static struct v4l2_file_operations cx18_v4l2_enc_fops = {
+	.owner = THIS_MODULE,
+	.read = cx18_v4l2_read,
+	.open = cx18_v4l2_open,
+	.unlocked_ioctl = video_ioctl2,
+	.release = cx18_v4l2_close,
+	.poll = cx18_v4l2_enc_poll,
+	.mmap = cx18_v4l2_mmap,
+};
+
+/* offset from 0 to register ts v4l2 minors on */
+#define CX18_V4L2_ENC_TS_OFFSET   16
+/* offset from 0 to register pcm v4l2 minors on */
+#define CX18_V4L2_ENC_PCM_OFFSET  24
+/* offset from 0 to register yuv v4l2 minors on */
+#define CX18_V4L2_ENC_YUV_OFFSET  32
+
+static struct {
+	const char *name;
+	int vfl_type;
+	int num_offset;
+	int dma;
+	enum v4l2_buf_type buf_type;
+} cx18_stream_info[] = {
+	{	/* CX18_ENC_STREAM_TYPE_MPG */
+		"encoder MPEG",
+		VFL_TYPE_GRABBER, 0,
+		PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+	},
+	{	/* CX18_ENC_STREAM_TYPE_TS */
+		"TS",
+		VFL_TYPE_GRABBER, -1,
+		PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+	},
+	{	/* CX18_ENC_STREAM_TYPE_YUV */
+		"encoder YUV",
+		VFL_TYPE_GRABBER, CX18_V4L2_ENC_YUV_OFFSET,
+		PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+	},
+	{	/* CX18_ENC_STREAM_TYPE_VBI */
+		"encoder VBI",
+		VFL_TYPE_VBI, 0,
+		PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VBI_CAPTURE,
+	},
+	{	/* CX18_ENC_STREAM_TYPE_PCM */
+		"encoder PCM audio",
+		VFL_TYPE_GRABBER, CX18_V4L2_ENC_PCM_OFFSET,
+		PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_PRIVATE,
+	},
+	{	/* CX18_ENC_STREAM_TYPE_IDX */
+		"encoder IDX",
+		VFL_TYPE_GRABBER, -1,
+		PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+	},
+	{	/* CX18_ENC_STREAM_TYPE_RAD */
+		"encoder radio",
+		VFL_TYPE_RADIO, 0,
+		PCI_DMA_NONE, V4L2_BUF_TYPE_PRIVATE,
+	},
+};
+
+
+void cx18_dma_free(struct videobuf_queue *q,
+	struct cx18_stream *s, struct cx18_videobuf_buffer *buf)
+{
+	videobuf_waiton(q, &buf->vb, 0, 0);
+	videobuf_vmalloc_free(&buf->vb);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int cx18_prepare_buffer(struct videobuf_queue *q,
+	struct cx18_stream *s,
+	struct cx18_videobuf_buffer *buf,
+	u32 pixelformat,
+	unsigned int width, unsigned int height,
+	enum v4l2_field field)
+{
+        struct cx18 *cx = s->cx;
+	int rc = 0;
+
+	/* check settings */
+	buf->bytes_used = 0;
+
+	if ((width  < 48) || (height < 32))
+		return -EINVAL;
+
+	buf->vb.size = (width * height * 2);
+	if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size))
+		return -EINVAL;
+
+	/* alloc + fill struct (if changed) */
+	if (buf->vb.width != width || buf->vb.height != height ||
+	    buf->vb.field != field || s->pixelformat != pixelformat ||
+	    buf->tvnorm != cx->std) {
+
+		buf->vb.width  = width;
+		buf->vb.height = height;
+		buf->vb.field  = field;
+		buf->tvnorm    = cx->std;
+		s->pixelformat = pixelformat;
+
+		/* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
+		   UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
+		if (s->pixelformat == V4L2_PIX_FMT_HM12)
+			s->vb_bytes_per_frame = height * 720 * 3 / 2;
+		else
+			s->vb_bytes_per_frame = height * 720 * 2;
+		cx18_dma_free(q, s, buf);
+	}
+
+	if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size))
+		return -EINVAL;
+
+	if (buf->vb.field == 0)
+		buf->vb.field = V4L2_FIELD_INTERLACED;
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		buf->vb.width  = width;
+		buf->vb.height = height;
+		buf->vb.field  = field;
+		buf->tvnorm    = cx->std;
+		s->pixelformat = pixelformat;
+
+		/* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
+		   UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
+		if (s->pixelformat == V4L2_PIX_FMT_HM12)
+			s->vb_bytes_per_frame = height * 720 * 3 / 2;
+		else
+			s->vb_bytes_per_frame = height * 720 * 2;
+		rc = videobuf_iolock(q, &buf->vb, NULL);
+		if (rc != 0)
+			goto fail;
+	}
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+fail:
+	cx18_dma_free(q, s, buf);
+	return rc;
+
+}
+
+/* VB_MIN_BUFSIZE is lcm(1440 * 480, 1440 * 576)
+   1440 is a single line of 4:2:2 YUV at 720 luma samples wide
+*/
+#define VB_MIN_BUFFERS 32
+#define VB_MIN_BUFSIZE 4147200
+
+static int buffer_setup(struct videobuf_queue *q,
+	unsigned int *count, unsigned int *size)
+{
+	struct cx18_stream *s = q->priv_data;
+	struct cx18 *cx = s->cx;
+
+	*size = 2 * cx->cxhdl.width * cx->cxhdl.height;
+	if (*count == 0)
+		*count = VB_MIN_BUFFERS;
+
+	while (*size * *count > VB_MIN_BUFFERS * VB_MIN_BUFSIZE)
+		(*count)--;
+
+	q->field = V4L2_FIELD_INTERLACED;
+	q->last = V4L2_FIELD_INTERLACED;
+
+	return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *q,
+	struct videobuf_buffer *vb,
+	enum v4l2_field field)
+{
+	struct cx18_videobuf_buffer *buf =
+		container_of(vb, struct cx18_videobuf_buffer, vb);
+	struct cx18_stream *s = q->priv_data;
+	struct cx18 *cx = s->cx;
+
+	return cx18_prepare_buffer(q, s, buf, s->pixelformat,
+		cx->cxhdl.width, cx->cxhdl.height, field);
+}
+
+static void buffer_release(struct videobuf_queue *q,
+	struct videobuf_buffer *vb)
+{
+	struct cx18_videobuf_buffer *buf =
+		container_of(vb, struct cx18_videobuf_buffer, vb);
+	struct cx18_stream *s = q->priv_data;
+
+	cx18_dma_free(q, s, buf);
+}
+
+static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct cx18_videobuf_buffer *buf =
+		container_of(vb, struct cx18_videobuf_buffer, vb);
+	struct cx18_stream *s = q->priv_data;
+
+	buf->vb.state = VIDEOBUF_QUEUED;
+
+	list_add_tail(&buf->vb.queue, &s->vb_capture);
+}
+
+static struct videobuf_queue_ops cx18_videobuf_qops = {
+	.buf_setup    = buffer_setup,
+	.buf_prepare  = buffer_prepare,
+	.buf_queue    = buffer_queue,
+	.buf_release  = buffer_release,
+};
+
+static void cx18_stream_init(struct cx18 *cx, int type)
+{
+	struct cx18_stream *s = &cx->streams[type];
+	struct video_device *video_dev = s->video_dev;
+
+	/* we need to keep video_dev, so restore it afterwards */
+	memset(s, 0, sizeof(*s));
+	s->video_dev = video_dev;
+
+	/* initialize cx18_stream fields */
+	s->dvb = NULL;
+	s->cx = cx;
+	s->type = type;
+	s->name = cx18_stream_info[type].name;
+	s->handle = CX18_INVALID_TASK_HANDLE;
+
+	s->dma = cx18_stream_info[type].dma;
+	s->buffers = cx->stream_buffers[type];
+	s->buf_size = cx->stream_buf_size[type];
+	INIT_LIST_HEAD(&s->buf_pool);
+	s->bufs_per_mdl = 1;
+	s->mdl_size = s->buf_size * s->bufs_per_mdl;
+
+	init_waitqueue_head(&s->waitq);
+	s->id = -1;
+	spin_lock_init(&s->q_free.lock);
+	cx18_queue_init(&s->q_free);
+	spin_lock_init(&s->q_busy.lock);
+	cx18_queue_init(&s->q_busy);
+	spin_lock_init(&s->q_full.lock);
+	cx18_queue_init(&s->q_full);
+	spin_lock_init(&s->q_idle.lock);
+	cx18_queue_init(&s->q_idle);
+
+	INIT_WORK(&s->out_work_order, cx18_out_work_handler);
+
+	INIT_LIST_HEAD(&s->vb_capture);
+	s->vb_timeout.function = cx18_vb_timeout;
+	s->vb_timeout.data = (unsigned long)s;
+	init_timer(&s->vb_timeout);
+	spin_lock_init(&s->vb_lock);
+	if (type == CX18_ENC_STREAM_TYPE_YUV) {
+		spin_lock_init(&s->vbuf_q_lock);
+
+		s->vb_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		videobuf_queue_vmalloc_init(&s->vbuf_q, &cx18_videobuf_qops,
+			&cx->pci_dev->dev, &s->vbuf_q_lock,
+			V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			V4L2_FIELD_INTERLACED,
+			sizeof(struct cx18_videobuf_buffer),
+			s, &cx->serialize_lock);
+
+		/* Assume the previous pixel default */
+		s->pixelformat = V4L2_PIX_FMT_HM12;
+		s->vb_bytes_per_frame = cx->cxhdl.height * 720 * 3 / 2;
+	}
+}
+
+static int cx18_prep_dev(struct cx18 *cx, int type)
+{
+	struct cx18_stream *s = &cx->streams[type];
+	u32 cap = cx->v4l2_cap;
+	int num_offset = cx18_stream_info[type].num_offset;
+	int num = cx->instance + cx18_first_minor + num_offset;
+
+	/*
+	 * These five fields are always initialized.
+	 * For analog capture related streams, if video_dev == NULL then the
+	 * stream is not in use.
+	 * For the TS stream, if dvb == NULL then the stream is not in use.
+	 * In those cases no other fields but these four can be used.
+	 */
+	s->video_dev = NULL;
+	s->dvb = NULL;
+	s->cx = cx;
+	s->type = type;
+	s->name = cx18_stream_info[type].name;
+
+	/* Check whether the radio is supported */
+	if (type == CX18_ENC_STREAM_TYPE_RAD && !(cap & V4L2_CAP_RADIO))
+		return 0;
+
+	/* Check whether VBI is supported */
+	if (type == CX18_ENC_STREAM_TYPE_VBI &&
+	    !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)))
+		return 0;
+
+	/* User explicitly selected 0 buffers for these streams, so don't
+	   create them. */
+	if (cx18_stream_info[type].dma != PCI_DMA_NONE &&
+	    cx->stream_buffers[type] == 0) {
+		CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name);
+		return 0;
+	}
+
+	cx18_stream_init(cx, type);
+
+	/* Allocate the cx18_dvb struct only for the TS on cards with DTV */
+	if (type == CX18_ENC_STREAM_TYPE_TS) {
+		if (cx->card->hw_all & CX18_HW_DVB) {
+			s->dvb = kzalloc(sizeof(struct cx18_dvb), GFP_KERNEL);
+			if (s->dvb == NULL) {
+				CX18_ERR("Couldn't allocate cx18_dvb structure"
+					 " for %s\n", s->name);
+				return -ENOMEM;
+			}
+		} else {
+			/* Don't need buffers for the TS, if there is no DVB */
+			s->buffers = 0;
+		}
+	}
+
+	if (num_offset == -1)
+		return 0;
+
+	/* allocate and initialize the v4l2 video device structure */
+	s->video_dev = video_device_alloc();
+	if (s->video_dev == NULL) {
+		CX18_ERR("Couldn't allocate v4l2 video_device for %s\n",
+				s->name);
+		return -ENOMEM;
+	}
+
+	snprintf(s->video_dev->name, sizeof(s->video_dev->name), "%s %s",
+		 cx->v4l2_dev.name, s->name);
+
+	s->video_dev->num = num;
+	s->video_dev->v4l2_dev = &cx->v4l2_dev;
+	s->video_dev->fops = &cx18_v4l2_enc_fops;
+	s->video_dev->release = video_device_release;
+	s->video_dev->tvnorms = V4L2_STD_ALL;
+	s->video_dev->lock = &cx->serialize_lock;
+	set_bit(V4L2_FL_USE_FH_PRIO, &s->video_dev->flags);
+	cx18_set_funcs(s->video_dev);
+	return 0;
+}
+
+/* Initialize v4l2 variables and register v4l2 devices */
+int cx18_streams_setup(struct cx18 *cx)
+{
+	int type, ret;
+
+	/* Setup V4L2 Devices */
+	for (type = 0; type < CX18_MAX_STREAMS; type++) {
+		/* Prepare device */
+		ret = cx18_prep_dev(cx, type);
+		if (ret < 0)
+			break;
+
+		/* Allocate Stream */
+		ret = cx18_stream_alloc(&cx->streams[type]);
+		if (ret < 0)
+			break;
+	}
+	if (type == CX18_MAX_STREAMS)
+		return 0;
+
+	/* One or more streams could not be initialized. Clean 'em all up. */
+	cx18_streams_cleanup(cx, 0);
+	return ret;
+}
+
+static int cx18_reg_dev(struct cx18 *cx, int type)
+{
+	struct cx18_stream *s = &cx->streams[type];
+	int vfl_type = cx18_stream_info[type].vfl_type;
+	const char *name;
+	int num, ret;
+
+	if (type == CX18_ENC_STREAM_TYPE_TS && s->dvb != NULL) {
+		ret = cx18_dvb_register(s);
+		if (ret < 0) {
+			CX18_ERR("DVB failed to register\n");
+			return ret;
+		}
+	}
+
+	if (s->video_dev == NULL)
+		return 0;
+
+	num = s->video_dev->num;
+	/* card number + user defined offset + device offset */
+	if (type != CX18_ENC_STREAM_TYPE_MPG) {
+		struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
+
+		if (s_mpg->video_dev)
+			num = s_mpg->video_dev->num
+			    + cx18_stream_info[type].num_offset;
+	}
+	video_set_drvdata(s->video_dev, s);
+
+	/* Register device. First try the desired minor, then any free one. */
+	ret = video_register_device_no_warn(s->video_dev, vfl_type, num);
+	if (ret < 0) {
+		CX18_ERR("Couldn't register v4l2 device for %s (device node number %d)\n",
+			s->name, num);
+		video_device_release(s->video_dev);
+		s->video_dev = NULL;
+		return ret;
+	}
+
+	name = video_device_node_name(s->video_dev);
+
+	switch (vfl_type) {
+	case VFL_TYPE_GRABBER:
+		CX18_INFO("Registered device %s for %s (%d x %d.%02d kB)\n",
+			  name, s->name, cx->stream_buffers[type],
+			  cx->stream_buf_size[type] / 1024,
+			  (cx->stream_buf_size[type] * 100 / 1024) % 100);
+		break;
+
+	case VFL_TYPE_RADIO:
+		CX18_INFO("Registered device %s for %s\n", name, s->name);
+		break;
+
+	case VFL_TYPE_VBI:
+		if (cx->stream_buffers[type])
+			CX18_INFO("Registered device %s for %s "
+				  "(%d x %d bytes)\n",
+				  name, s->name, cx->stream_buffers[type],
+				  cx->stream_buf_size[type]);
+		else
+			CX18_INFO("Registered device %s for %s\n",
+				name, s->name);
+		break;
+	}
+
+	return 0;
+}
+
+/* Register v4l2 devices */
+int cx18_streams_register(struct cx18 *cx)
+{
+	int type;
+	int err;
+	int ret = 0;
+
+	/* Register V4L2 devices */
+	for (type = 0; type < CX18_MAX_STREAMS; type++) {
+		err = cx18_reg_dev(cx, type);
+		if (err && ret == 0)
+			ret = err;
+	}
+
+	if (ret == 0)
+		return 0;
+
+	/* One or more streams could not be initialized. Clean 'em all up. */
+	cx18_streams_cleanup(cx, 1);
+	return ret;
+}
+
+/* Unregister v4l2 devices */
+void cx18_streams_cleanup(struct cx18 *cx, int unregister)
+{
+	struct video_device *vdev;
+	int type;
+
+	/* Teardown all streams */
+	for (type = 0; type < CX18_MAX_STREAMS; type++) {
+
+		/* The TS has a cx18_dvb structure, not a video_device */
+		if (type == CX18_ENC_STREAM_TYPE_TS) {
+			if (cx->streams[type].dvb != NULL) {
+				if (unregister)
+					cx18_dvb_unregister(&cx->streams[type]);
+				kfree(cx->streams[type].dvb);
+				cx->streams[type].dvb = NULL;
+				cx18_stream_free(&cx->streams[type]);
+			}
+			continue;
+		}
+
+		/* No struct video_device, but can have buffers allocated */
+		if (type == CX18_ENC_STREAM_TYPE_IDX) {
+			/* If the module params didn't inhibit IDX ... */
+			if (cx->stream_buffers[type] != 0) {
+				cx->stream_buffers[type] = 0;
+				/*
+				 * Before calling cx18_stream_free(),
+				 * check if the IDX stream was actually set up.
+				 * Needed, since the cx18_probe() error path
+				 * exits through here as well as normal clean up
+				 */
+				if (cx->streams[type].buffers != 0)
+					cx18_stream_free(&cx->streams[type]);
+			}
+			continue;
+		}
+
+		/* If struct video_device exists, can have buffers allocated */
+		vdev = cx->streams[type].video_dev;
+
+		cx->streams[type].video_dev = NULL;
+		if (vdev == NULL)
+			continue;
+
+		if (type == CX18_ENC_STREAM_TYPE_YUV)
+			videobuf_mmap_free(&cx->streams[type].vbuf_q);
+
+		cx18_stream_free(&cx->streams[type]);
+
+		/* Unregister or release device */
+		if (unregister)
+			video_unregister_device(vdev);
+		else
+			video_device_release(vdev);
+	}
+}
+
+static void cx18_vbi_setup(struct cx18_stream *s)
+{
+	struct cx18 *cx = s->cx;
+	int raw = cx18_raw_vbi(cx);
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	int lines;
+
+	if (cx->is_60hz) {
+		cx->vbi.count = 12;
+		cx->vbi.start[0] = 10;
+		cx->vbi.start[1] = 273;
+	} else {        /* PAL/SECAM */
+		cx->vbi.count = 18;
+		cx->vbi.start[0] = 6;
+		cx->vbi.start[1] = 318;
+	}
+
+	/* setup VBI registers */
+	if (raw)
+		v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &cx->vbi.in.fmt.vbi);
+	else
+		v4l2_subdev_call(cx->sd_av, vbi, s_sliced_fmt, &cx->vbi.in.fmt.sliced);
+
+	/*
+	 * Send the CX18_CPU_SET_RAW_VBI_PARAM API command to setup Encoder Raw
+	 * VBI when the first analog capture channel starts, as once it starts
+	 * (e.g. MPEG), we can't effect any change in the Encoder Raw VBI setup
+	 * (i.e. for the VBI capture channels).  We also send it for each
+	 * analog capture channel anyway just to make sure we get the proper
+	 * behavior
+	 */
+	if (raw) {
+		lines = cx->vbi.count * 2;
+	} else {
+		/*
+		 * For 525/60 systems, according to the VIP 2 & BT.656 std:
+		 * The EAV RP code's Field bit toggles on line 4, a few lines
+		 * after the Vertcal Blank bit has already toggled.
+		 * Tell the encoder to capture 21-4+1=18 lines per field,
+		 * since we want lines 10 through 21.
+		 *
+		 * For 625/50 systems, according to the VIP 2 & BT.656 std:
+		 * The EAV RP code's Field bit toggles on line 1, a few lines
+		 * after the Vertcal Blank bit has already toggled.
+		 * (We've actually set the digitizer so that the Field bit
+		 * toggles on line 2.) Tell the encoder to capture 23-2+1=22
+		 * lines per field, since we want lines 6 through 23.
+		 */
+		lines = cx->is_60hz ? (21 - 4 + 1) * 2 : (23 - 2 + 1) * 2;
+	}
+
+	data[0] = s->handle;
+	/* Lines per field */
+	data[1] = (lines / 2) | ((lines / 2) << 16);
+	/* bytes per line */
+	data[2] = (raw ? vbi_active_samples
+		       : (cx->is_60hz ? vbi_hblank_samples_60Hz
+				      : vbi_hblank_samples_50Hz));
+	/* Every X number of frames a VBI interrupt arrives
+	   (frames as in 25 or 30 fps) */
+	data[3] = 1;
+	/*
+	 * Set the SAV/EAV RP codes to look for as start/stop points
+	 * when in VIP-1.1 mode
+	 */
+	if (raw) {
+		/*
+		 * Start codes for beginning of "active" line in vertical blank
+		 * 0x20 (               VerticalBlank                )
+		 * 0x60 (     EvenField VerticalBlank                )
+		 */
+		data[4] = 0x20602060;
+		/*
+		 * End codes for end of "active" raw lines and regular lines
+		 * 0x30 (               VerticalBlank HorizontalBlank)
+		 * 0x70 (     EvenField VerticalBlank HorizontalBlank)
+		 * 0x90 (Task                         HorizontalBlank)
+		 * 0xd0 (Task EvenField               HorizontalBlank)
+		 */
+		data[5] = 0x307090d0;
+	} else {
+		/*
+		 * End codes for active video, we want data in the hblank region
+		 * 0xb0 (Task         0 VerticalBlank HorizontalBlank)
+		 * 0xf0 (Task EvenField VerticalBlank HorizontalBlank)
+		 *
+		 * Since the V bit is only allowed to toggle in the EAV RP code,
+		 * just before the first active region line, these two
+		 * are problematic:
+		 * 0x90 (Task                         HorizontalBlank)
+		 * 0xd0 (Task EvenField               HorizontalBlank)
+		 *
+		 * We have set the digitzer such that we don't have to worry
+		 * about these problem codes.
+		 */
+		data[4] = 0xB0F0B0F0;
+		/*
+		 * Start codes for beginning of active line in vertical blank
+		 * 0xa0 (Task           VerticalBlank                )
+		 * 0xe0 (Task EvenField VerticalBlank                )
+		 */
+		data[5] = 0xA0E0A0E0;
+	}
+
+	CX18_DEBUG_INFO("Setup VBI h: %d lines %x bpl %d fr %d %x %x\n",
+			data[0], data[1], data[2], data[3], data[4], data[5]);
+
+	cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
+}
+
+void cx18_stream_rotate_idx_mdls(struct cx18 *cx)
+{
+	struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
+	struct cx18_mdl *mdl;
+
+	if (!cx18_stream_enabled(s))
+		return;
+
+	/* Return if the firmware is not running low on MDLs */
+	if ((atomic_read(&s->q_free.depth) + atomic_read(&s->q_busy.depth)) >=
+					    CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN)
+		return;
+
+	/* Return if there are no MDLs to rotate back to the firmware */
+	if (atomic_read(&s->q_full.depth) < 2)
+		return;
+
+	/*
+	 * Take the oldest IDX MDL still holding data, and discard its index
+	 * entries by scheduling the MDL to go back to the firmware
+	 */
+	mdl = cx18_dequeue(s, &s->q_full);
+	if (mdl != NULL)
+		cx18_enqueue(s, mdl, &s->q_free);
+}
+
+static
+struct cx18_queue *_cx18_stream_put_mdl_fw(struct cx18_stream *s,
+					   struct cx18_mdl *mdl)
+{
+	struct cx18 *cx = s->cx;
+	struct cx18_queue *q;
+
+	/* Don't give it to the firmware, if we're not running a capture */
+	if (s->handle == CX18_INVALID_TASK_HANDLE ||
+	    test_bit(CX18_F_S_STOPPING, &s->s_flags) ||
+	    !test_bit(CX18_F_S_STREAMING, &s->s_flags))
+		return cx18_enqueue(s, mdl, &s->q_free);
+
+	q = cx18_enqueue(s, mdl, &s->q_busy);
+	if (q != &s->q_busy)
+		return q; /* The firmware has the max MDLs it can handle */
+
+	cx18_mdl_sync_for_device(s, mdl);
+	cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
+		  (void __iomem *) &cx->scb->cpu_mdl[mdl->id] - cx->enc_mem,
+		  s->bufs_per_mdl, mdl->id, s->mdl_size);
+	return q;
+}
+
+static
+void _cx18_stream_load_fw_queue(struct cx18_stream *s)
+{
+	struct cx18_queue *q;
+	struct cx18_mdl *mdl;
+
+	if (atomic_read(&s->q_free.depth) == 0 ||
+	    atomic_read(&s->q_busy.depth) >= CX18_MAX_FW_MDLS_PER_STREAM)
+		return;
+
+	/* Move from q_free to q_busy notifying the firmware, until the limit */
+	do {
+		mdl = cx18_dequeue(s, &s->q_free);
+		if (mdl == NULL)
+			break;
+		q = _cx18_stream_put_mdl_fw(s, mdl);
+	} while (atomic_read(&s->q_busy.depth) < CX18_MAX_FW_MDLS_PER_STREAM
+		 && q == &s->q_busy);
+}
+
+void cx18_out_work_handler(struct work_struct *work)
+{
+	struct cx18_stream *s =
+			 container_of(work, struct cx18_stream, out_work_order);
+
+	_cx18_stream_load_fw_queue(s);
+}
+
+static void cx18_stream_configure_mdls(struct cx18_stream *s)
+{
+	cx18_unload_queues(s);
+
+	switch (s->type) {
+	case CX18_ENC_STREAM_TYPE_YUV:
+		/*
+		 * Height should be a multiple of 32 lines.
+		 * Set the MDL size to the exact size needed for one frame.
+		 * Use enough buffers per MDL to cover the MDL size
+		 */
+		if (s->pixelformat == V4L2_PIX_FMT_HM12)
+			s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2;
+		else
+			s->mdl_size = 720 * s->cx->cxhdl.height * 2;
+		s->bufs_per_mdl = s->mdl_size / s->buf_size;
+		if (s->mdl_size % s->buf_size)
+			s->bufs_per_mdl++;
+		break;
+	case CX18_ENC_STREAM_TYPE_VBI:
+		s->bufs_per_mdl = 1;
+		if  (cx18_raw_vbi(s->cx)) {
+			s->mdl_size = (s->cx->is_60hz ? 12 : 18)
+						       * 2 * vbi_active_samples;
+		} else {
+			/*
+			 * See comment in cx18_vbi_setup() below about the
+			 * extra lines we capture in sliced VBI mode due to
+			 * the lines on which EAV RP codes toggle.
+			*/
+			s->mdl_size = s->cx->is_60hz
+				   ? (21 - 4 + 1) * 2 * vbi_hblank_samples_60Hz
+				   : (23 - 2 + 1) * 2 * vbi_hblank_samples_50Hz;
+		}
+		break;
+	default:
+		s->bufs_per_mdl = 1;
+		s->mdl_size = s->buf_size * s->bufs_per_mdl;
+		break;
+	}
+
+	cx18_load_queues(s);
+}
+
+int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
+{
+	u32 data[MAX_MB_ARGUMENTS];
+	struct cx18 *cx = s->cx;
+	int captype = 0;
+	struct cx18_stream *s_idx;
+
+	if (!cx18_stream_enabled(s))
+		return -EINVAL;
+
+	CX18_DEBUG_INFO("Start encoder stream %s\n", s->name);
+
+	switch (s->type) {
+	case CX18_ENC_STREAM_TYPE_MPG:
+		captype = CAPTURE_CHANNEL_TYPE_MPEG;
+		cx->mpg_data_received = cx->vbi_data_inserted = 0;
+		cx->dualwatch_jiffies = jiffies;
+		cx->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode);
+		cx->search_pack_header = 0;
+		break;
+
+	case CX18_ENC_STREAM_TYPE_IDX:
+		captype = CAPTURE_CHANNEL_TYPE_INDEX;
+		break;
+	case CX18_ENC_STREAM_TYPE_TS:
+		captype = CAPTURE_CHANNEL_TYPE_TS;
+		break;
+	case CX18_ENC_STREAM_TYPE_YUV:
+		captype = CAPTURE_CHANNEL_TYPE_YUV;
+		break;
+	case CX18_ENC_STREAM_TYPE_PCM:
+		captype = CAPTURE_CHANNEL_TYPE_PCM;
+		break;
+	case CX18_ENC_STREAM_TYPE_VBI:
+#ifdef CX18_ENCODER_PARSES_SLICED
+		captype = cx18_raw_vbi(cx) ?
+		     CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI;
+#else
+		/*
+		 * Currently we set things up so that Sliced VBI from the
+		 * digitizer is handled as Raw VBI by the encoder
+		 */
+		captype = CAPTURE_CHANNEL_TYPE_VBI;
+#endif
+		cx->vbi.frame = 0;
+		cx->vbi.inserted_frame = 0;
+		memset(cx->vbi.sliced_mpeg_size,
+			0, sizeof(cx->vbi.sliced_mpeg_size));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Clear Streamoff flags in case left from last capture */
+	clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+
+	cx18_vapi_result(cx, data, CX18_CREATE_TASK, 1, CPU_CMD_MASK_CAPTURE);
+	s->handle = data[0];
+	cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype);
+
+	/*
+	 * For everything but CAPTURE_CHANNEL_TYPE_TS, play it safe and
+	 * set up all the parameters, as it is not obvious which parameters the
+	 * firmware shares across capture channel types and which it does not.
+	 *
+	 * Some of the cx18_vapi() calls below apply to only certain capture
+	 * channel types.  We're hoping there's no harm in calling most of them
+	 * anyway, as long as the values are all consistent.  Setting some
+	 * shared parameters will have no effect once an analog capture channel
+	 * has started streaming.
+	 */
+	if (captype != CAPTURE_CHANNEL_TYPE_TS) {
+		cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0);
+		cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1);
+		cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0);
+		cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1);
+
+		/*
+		 * Audio related reset according to
+		 * Documentation/video4linux/cx2341x/fw-encoder-api.txt
+		 */
+		if (atomic_read(&cx->ana_capturing) == 0)
+			cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2,
+				  s->handle, 12);
+
+		/*
+		 * Number of lines for Field 1 & Field 2 according to
+		 * Documentation/video4linux/cx2341x/fw-encoder-api.txt
+		 * Field 1 is 312 for 625 line systems in BT.656
+		 * Field 2 is 313 for 625 line systems in BT.656
+		 */
+		cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3,
+			  s->handle, 312, 313);
+
+		if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE)
+			cx18_vbi_setup(s);
+
+		/*
+		 * Select to receive I, P, and B frame index entries, if the
+		 * index stream is enabled.  Otherwise disable index entry
+		 * generation.
+		 */
+		s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
+		cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 2,
+				 s->handle, cx18_stream_enabled(s_idx) ? 7 : 0);
+
+		/* Call out to the common CX2341x API setup for user controls */
+		cx->cxhdl.priv = s;
+		cx2341x_handler_setup(&cx->cxhdl);
+
+		/*
+		 * When starting a capture and we're set for radio,
+		 * ensure the video is muted, despite the user control.
+		 */
+		if (!cx->cxhdl.video_mute &&
+		    test_bit(CX18_F_I_RADIO_USER, &cx->i_flags))
+			cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
+			  (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1);
+
+		/* Enable the Video Format Converter for UYVY 4:2:2 support,
+		 * rather than the default HM12 Macroblovk 4:2:0 support.
+		 */
+		if (captype == CAPTURE_CHANNEL_TYPE_YUV) {
+			if (s->pixelformat == V4L2_PIX_FMT_UYVY)
+				cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2,
+					s->handle, 1);
+			else
+				/* If in doubt, default to HM12 */
+				cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2,
+					s->handle, 0);
+		}
+	}
+
+	if (atomic_read(&cx->tot_capturing) == 0) {
+		cx2341x_handler_set_busy(&cx->cxhdl, 1);
+		clear_bit(CX18_F_I_EOS, &cx->i_flags);
+		cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK);
+	}
+
+	cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle,
+		(void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem,
+		(void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem);
+
+	/* Init all the cpu_mdls for this stream */
+	cx18_stream_configure_mdls(s);
+	_cx18_stream_load_fw_queue(s);
+
+	/* begin_capture */
+	if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
+		CX18_DEBUG_WARN("Error starting capture!\n");
+		/* Ensure we're really not capturing before releasing MDLs */
+		set_bit(CX18_F_S_STOPPING, &s->s_flags);
+		if (s->type == CX18_ENC_STREAM_TYPE_MPG)
+			cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1);
+		else
+			cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);
+		clear_bit(CX18_F_S_STREAMING, &s->s_flags);
+		/* FIXME - CX18_F_S_STREAMOFF as well? */
+		cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
+		cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
+		s->handle = CX18_INVALID_TASK_HANDLE;
+		clear_bit(CX18_F_S_STOPPING, &s->s_flags);
+		if (atomic_read(&cx->tot_capturing) == 0) {
+			set_bit(CX18_F_I_EOS, &cx->i_flags);
+			cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
+		}
+		return -EINVAL;
+	}
+
+	/* you're live! sit back and await interrupts :) */
+	if (captype != CAPTURE_CHANNEL_TYPE_TS)
+		atomic_inc(&cx->ana_capturing);
+	atomic_inc(&cx->tot_capturing);
+	return 0;
+}
+EXPORT_SYMBOL(cx18_start_v4l2_encode_stream);
+
+void cx18_stop_all_captures(struct cx18 *cx)
+{
+	int i;
+
+	for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) {
+		struct cx18_stream *s = &cx->streams[i];
+
+		if (!cx18_stream_enabled(s))
+			continue;
+		if (test_bit(CX18_F_S_STREAMING, &s->s_flags))
+			cx18_stop_v4l2_encode_stream(s, 0);
+	}
+}
+
+int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
+{
+	struct cx18 *cx = s->cx;
+
+	if (!cx18_stream_enabled(s))
+		return -EINVAL;
+
+	/* This function assumes that you are allowed to stop the capture
+	   and that we are actually capturing */
+
+	CX18_DEBUG_INFO("Stop Capture\n");
+
+	if (atomic_read(&cx->tot_capturing) == 0)
+		return 0;
+
+	set_bit(CX18_F_S_STOPPING, &s->s_flags);
+	if (s->type == CX18_ENC_STREAM_TYPE_MPG)
+		cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end);
+	else
+		cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);
+
+	if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) {
+		CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
+	}
+
+	if (s->type != CX18_ENC_STREAM_TYPE_TS)
+		atomic_dec(&cx->ana_capturing);
+	atomic_dec(&cx->tot_capturing);
+
+	/* Clear capture and no-read bits */
+	clear_bit(CX18_F_S_STREAMING, &s->s_flags);
+
+	/* Tell the CX23418 it can't use our buffers anymore */
+	cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
+
+	cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
+	s->handle = CX18_INVALID_TASK_HANDLE;
+	clear_bit(CX18_F_S_STOPPING, &s->s_flags);
+
+	if (atomic_read(&cx->tot_capturing) > 0)
+		return 0;
+
+	cx2341x_handler_set_busy(&cx->cxhdl, 0);
+	cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
+	wake_up(&s->waitq);
+
+	return 0;
+}
+EXPORT_SYMBOL(cx18_stop_v4l2_encode_stream);
+
+u32 cx18_find_handle(struct cx18 *cx)
+{
+	int i;
+
+	/* find first available handle to be used for global settings */
+	for (i = 0; i < CX18_MAX_STREAMS; i++) {
+		struct cx18_stream *s = &cx->streams[i];
+
+		if (s->video_dev && (s->handle != CX18_INVALID_TASK_HANDLE))
+			return s->handle;
+	}
+	return CX18_INVALID_TASK_HANDLE;
+}
+
+struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle)
+{
+	int i;
+	struct cx18_stream *s;
+
+	if (handle == CX18_INVALID_TASK_HANDLE)
+		return NULL;
+
+	for (i = 0; i < CX18_MAX_STREAMS; i++) {
+		s = &cx->streams[i];
+		if (s->handle != handle)
+			continue;
+		if (cx18_stream_enabled(s))
+			return s;
+	}
+	return NULL;
+}
diff --git a/drivers/media/pci/cx18/cx18-streams.h b/drivers/media/pci/cx18/cx18-streams.h
new file mode 100644
index 0000000..713b0e6
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-streams.h
@@ -0,0 +1,62 @@
+/*
+ *  cx18 init/start/stop/exit stream functions
+ *
+ *  Derived from ivtv-streams.h
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+u32 cx18_find_handle(struct cx18 *cx);
+struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle);
+int cx18_streams_setup(struct cx18 *cx);
+int cx18_streams_register(struct cx18 *cx);
+void cx18_streams_cleanup(struct cx18 *cx, int unregister);
+
+#define CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN (3)
+void cx18_stream_rotate_idx_mdls(struct cx18 *cx);
+
+static inline bool cx18_stream_enabled(struct cx18_stream *s)
+{
+	return s->video_dev ||
+	       (s->dvb && s->dvb->enabled) ||
+	       (s->type == CX18_ENC_STREAM_TYPE_IDX &&
+		s->cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] != 0);
+}
+
+/* Related to submission of mdls to firmware */
+static inline void cx18_stream_load_fw_queue(struct cx18_stream *s)
+{
+	schedule_work(&s->out_work_order);
+}
+
+static inline void cx18_stream_put_mdl_fw(struct cx18_stream *s,
+					  struct cx18_mdl *mdl)
+{
+	/* Put mdl on q_free; the out work handler will move mdl(s) to q_busy */
+	cx18_enqueue(s, mdl, &s->q_free);
+	cx18_stream_load_fw_queue(s);
+}
+
+void cx18_out_work_handler(struct work_struct *work);
+
+/* Capture related */
+int cx18_start_v4l2_encode_stream(struct cx18_stream *s);
+int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end);
+
+void cx18_stop_all_captures(struct cx18 *cx);
diff --git a/drivers/media/pci/cx18/cx18-vbi.c b/drivers/media/pci/cx18/cx18-vbi.c
new file mode 100644
index 0000000..6d3121f
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-vbi.c
@@ -0,0 +1,277 @@
+/*
+ *  cx18 Vertical Blank Interval support functions
+ *
+ *  Derived from ivtv-vbi.c
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-vbi.h"
+#include "cx18-ioctl.h"
+#include "cx18-queue.h"
+
+/*
+ * Raster Reference/Protection (RP) bytes, used in Start/End Active
+ * Video codes emitted from the digitzer in VIP 1.x mode, that flag the start
+ * of VBI sample or VBI ancillary data regions in the digitial ratser line.
+ *
+ * Task FieldEven VerticalBlank HorizontalBlank 0 0 0 0
+ */
+static const u8 raw_vbi_sav_rp[2] = { 0x20, 0x60 };    /* __V_, _FV_ */
+static const u8 sliced_vbi_eav_rp[2] = { 0xb0, 0xf0 }; /* T_VH, TFVH */
+
+static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
+{
+	int line = 0;
+	int i;
+	u32 linemask[2] = { 0, 0 };
+	unsigned short size;
+	static const u8 mpeg_hdr_data[] = {
+		/* MPEG-2 Program Pack */
+		0x00, 0x00, 0x01, 0xba,		    /* Prog Pack start code */
+		0x44, 0x00, 0x0c, 0x66, 0x24, 0x01, /* SCR, SCR Ext, markers */
+		0x01, 0xd1, 0xd3,		    /* Mux Rate, markers */
+		0xfa, 0xff, 0xff,		    /* Res, Suff cnt, Stuff */
+		/* MPEG-2 Private Stream 1 PES Packet */
+		0x00, 0x00, 0x01, 0xbd,		    /* Priv Stream 1 start */
+		0x00, 0x1a,			    /* length */
+		0x84, 0x80, 0x07,		    /* flags, hdr data len */
+		0x21, 0x00, 0x5d, 0x63, 0xa7, 	    /* PTS, markers */
+		0xff, 0xff			    /* stuffing */
+	};
+	const int sd = sizeof(mpeg_hdr_data);	/* start of vbi data */
+	int idx = cx->vbi.frame % CX18_VBI_FRAMES;
+	u8 *dst = &cx->vbi.sliced_mpeg_data[idx][0];
+
+	for (i = 0; i < lines; i++) {
+		struct v4l2_sliced_vbi_data *sdata = cx->vbi.sliced_data + i;
+		int f, l;
+
+		if (sdata->id == 0)
+			continue;
+
+		l = sdata->line - 6;
+		f = sdata->field;
+		if (f)
+			l += 18;
+		if (l < 32)
+			linemask[0] |= (1 << l);
+		else
+			linemask[1] |= (1 << (l - 32));
+		dst[sd + 12 + line * 43] = cx18_service2vbi(sdata->id);
+		memcpy(dst + sd + 12 + line * 43 + 1, sdata->data, 42);
+		line++;
+	}
+	memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data));
+	if (line == 36) {
+		/* All lines are used, so there is no space for the linemask
+		   (the max size of the VBI data is 36 * 43 + 4 bytes).
+		   So in this case we use the magic number 'ITV0'. */
+		memcpy(dst + sd, "ITV0", 4);
+		memcpy(dst + sd + 4, dst + sd + 12, line * 43);
+		size = 4 + ((43 * line + 3) & ~3);
+	} else {
+		memcpy(dst + sd, "itv0", 4);
+		cpu_to_le32s(&linemask[0]);
+		cpu_to_le32s(&linemask[1]);
+		memcpy(dst + sd + 4, &linemask[0], 8);
+		size = 12 + ((43 * line + 3) & ~3);
+	}
+	dst[4+16] = (size + 10) >> 8;
+	dst[5+16] = (size + 10) & 0xff;
+	dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6);
+	dst[10+16] = (pts_stamp >> 22) & 0xff;
+	dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff);
+	dst[12+16] = (pts_stamp >> 7) & 0xff;
+	dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1);
+	cx->vbi.sliced_mpeg_size[idx] = sd + size;
+}
+
+/* Compress raw VBI format, removes leading SAV codes and surplus space
+   after the frame.  Returns new compressed size. */
+/* FIXME - this function ignores the input size. */
+static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size, u32 hdr_size)
+{
+	u32 line_size = vbi_active_samples;
+	u32 lines = cx->vbi.count * 2;
+	u8 *q = buf;
+	u8 *p;
+	int i;
+
+	/* Skip the header */
+	buf += hdr_size;
+
+	for (i = 0; i < lines; i++) {
+		p = buf + i * line_size;
+
+		/* Look for SAV code */
+		if (p[0] != 0xff || p[1] || p[2] ||
+		    (p[3] != raw_vbi_sav_rp[0] &&
+		     p[3] != raw_vbi_sav_rp[1]))
+			break;
+		if (i == lines - 1) {
+			/* last line is hdr_size bytes short - extrapolate it */
+			memcpy(q, p + 4, line_size - 4 - hdr_size);
+			q += line_size - 4 - hdr_size;
+			p += line_size - hdr_size - 1;
+			memset(q, (int) *p, hdr_size);
+		} else {
+			memcpy(q, p + 4, line_size - 4);
+			q += line_size - 4;
+		}
+	}
+	return lines * (line_size - 4);
+}
+
+static u32 compress_sliced_buf(struct cx18 *cx, u8 *buf, u32 size,
+			       const u32 hdr_size)
+{
+	struct v4l2_decode_vbi_line vbi;
+	int i;
+	u32 line = 0;
+	u32 line_size = cx->is_60hz ? vbi_hblank_samples_60Hz
+				    : vbi_hblank_samples_50Hz;
+
+	/* find the first valid line */
+	for (i = hdr_size, buf += hdr_size; i < size; i++, buf++) {
+		if (buf[0] == 0xff && !buf[1] && !buf[2] &&
+		    (buf[3] == sliced_vbi_eav_rp[0] ||
+		     buf[3] == sliced_vbi_eav_rp[1]))
+			break;
+	}
+
+	/*
+	 * The last line is short by hdr_size bytes, but for the remaining
+	 * checks against size, we pretend that it is not, by counting the
+	 * header bytes we knowingly skipped
+	 */
+	size -= (i - hdr_size);
+	if (size < line_size)
+		return line;
+
+	for (i = 0; i < size / line_size; i++) {
+		u8 *p = buf + i * line_size;
+
+		/* Look for EAV code  */
+		if (p[0] != 0xff || p[1] || p[2] ||
+		    (p[3] != sliced_vbi_eav_rp[0] &&
+		     p[3] != sliced_vbi_eav_rp[1]))
+			continue;
+		vbi.p = p + 4;
+		v4l2_subdev_call(cx->sd_av, vbi, decode_vbi_line, &vbi);
+		if (vbi.type) {
+			cx->vbi.sliced_data[line].id = vbi.type;
+			cx->vbi.sliced_data[line].field = vbi.is_second_field;
+			cx->vbi.sliced_data[line].line = vbi.line;
+			memcpy(cx->vbi.sliced_data[line].data, vbi.p, 42);
+			line++;
+		}
+	}
+	return line;
+}
+
+static void _cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf)
+{
+	/*
+	 * The CX23418 provides a 12 byte header in its raw VBI buffers to us:
+	 * 0x3fffffff [4 bytes of something] [4 byte presentation time stamp]
+	 */
+	struct vbi_data_hdr {
+		__be32 magic;
+		__be32 unknown;
+		__be32 pts;
+	} *hdr = (struct vbi_data_hdr *) buf->buf;
+
+	u8 *p = (u8 *) buf->buf;
+	u32 size = buf->bytesused;
+	u32 pts;
+	int lines;
+
+	/*
+	 * The CX23418 sends us data that is 32 bit little-endian swapped,
+	 * but we want the raw VBI bytes in the order they were in the raster
+	 * line.  This has a side effect of making the header big endian
+	 */
+	cx18_buf_swap(buf);
+
+	/* Raw VBI data */
+	if (cx18_raw_vbi(cx)) {
+
+		size = buf->bytesused =
+		     compress_raw_buf(cx, p, size, sizeof(struct vbi_data_hdr));
+
+		/*
+		 * Hack needed for compatibility with old VBI software.
+		 * Write the frame # at the last 4 bytes of the frame
+		 */
+		p += size - 4;
+		memcpy(p, &cx->vbi.frame, 4);
+		cx->vbi.frame++;
+		return;
+	}
+
+	/* Sliced VBI data with data insertion */
+
+	pts = (be32_to_cpu(hdr->magic) == 0x3fffffff) ? be32_to_cpu(hdr->pts)
+						      : 0;
+
+	lines = compress_sliced_buf(cx, p, size, sizeof(struct vbi_data_hdr));
+
+	/* always return at least one empty line */
+	if (lines == 0) {
+		cx->vbi.sliced_data[0].id = 0;
+		cx->vbi.sliced_data[0].line = 0;
+		cx->vbi.sliced_data[0].field = 0;
+		lines = 1;
+	}
+	buf->bytesused = size = lines * sizeof(cx->vbi.sliced_data[0]);
+	memcpy(p, &cx->vbi.sliced_data[0], size);
+
+	if (cx->vbi.insert_mpeg)
+		copy_vbi_data(cx, lines, pts);
+	cx->vbi.frame++;
+}
+
+void cx18_process_vbi_data(struct cx18 *cx, struct cx18_mdl *mdl,
+			   int streamtype)
+{
+	struct cx18_buffer *buf;
+	u32 orig_used;
+
+	if (streamtype != CX18_ENC_STREAM_TYPE_VBI)
+		return;
+
+	/*
+	 * Big assumption here:
+	 * Every buffer hooked to the MDL's buf_list is a complete VBI frame
+	 * that ends at the end of the buffer.
+	 *
+	 * To assume anything else would make the code in this file
+	 * more complex, or require extra memcpy()'s to make the
+	 * buffers satisfy the above assumption.  It's just simpler to set
+	 * up the encoder buffer transfers to make the assumption true.
+	 */
+	list_for_each_entry(buf, &mdl->buf_list, list) {
+		orig_used = buf->bytesused;
+		if (orig_used == 0)
+			break;
+		_cx18_process_vbi_data(cx, buf);
+		mdl->bytesused -= (orig_used - buf->bytesused);
+	}
+}
diff --git a/drivers/media/pci/cx18/cx18-vbi.h b/drivers/media/pci/cx18/cx18-vbi.h
new file mode 100644
index 0000000..b365cf4
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-vbi.h
@@ -0,0 +1,26 @@
+/*
+ *  cx18 Vertical Blank Interval support functions
+ *
+ *  Derived from ivtv-vbi.h
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+void cx18_process_vbi_data(struct cx18 *cx, struct cx18_mdl *mdl,
+			   int streamtype);
+int cx18_used_line(struct cx18 *cx, int line, int field);
diff --git a/drivers/media/pci/cx18/cx18-version.h b/drivers/media/pci/cx18/cx18-version.h
new file mode 100644
index 0000000..fed48b6
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-version.h
@@ -0,0 +1,28 @@
+/*
+ *  cx18 driver version information
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#ifndef CX18_VERSION_H
+#define CX18_VERSION_H
+
+#define CX18_DRIVER_NAME "cx18"
+#define CX18_VERSION "1.5.1"
+
+#endif
diff --git a/drivers/media/pci/cx18/cx18-video.c b/drivers/media/pci/cx18/cx18-video.c
new file mode 100644
index 0000000..6dc84aa
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-video.c
@@ -0,0 +1,32 @@
+/*
+ *  cx18 video interface functions
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-video.h"
+#include "cx18-cards.h"
+
+void cx18_video_set_io(struct cx18 *cx)
+{
+	int inp = cx->active_input;
+
+	v4l2_subdev_call(cx->sd_av, video, s_routing,
+			cx->card->video_inputs[inp].video_input, 0, 0);
+}
diff --git a/drivers/media/pci/cx18/cx18-video.h b/drivers/media/pci/cx18/cx18-video.h
new file mode 100644
index 0000000..529006a
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-video.h
@@ -0,0 +1,22 @@
+/*
+ *  cx18 video interface functions
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+void cx18_video_set_io(struct cx18 *cx);
diff --git a/drivers/media/pci/cx18/cx23418.h b/drivers/media/pci/cx18/cx23418.h
new file mode 100644
index 0000000..767a8d2
--- /dev/null
+++ b/drivers/media/pci/cx18/cx23418.h
@@ -0,0 +1,492 @@
+/*
+ *  cx18 header containing common defines.
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#ifndef CX23418_H
+#define CX23418_H
+
+#include <media/cx2341x.h>
+
+#define MGR_CMD_MASK            		0x40000000
+/* The MSB of the command code indicates that this is the completion of a
+   command */
+#define MGR_CMD_MASK_ACK        		(MGR_CMD_MASK | 0x80000000)
+
+/* Description: This command creates a new instance of a certain task
+   IN[0]  - Task ID. This is one of the XPU_CMD_MASK_YYY where XPU is
+	    the processor on which the task YYY will be created
+   OUT[0] - Task handle. This handle is passed along with commands to
+	    dispatch to the right instance of the task
+   ReturnCode - One of the ERR_SYS_... */
+#define CX18_CREATE_TASK      			(MGR_CMD_MASK | 0x0001)
+
+/* Description: This command destroys an instance of a task
+   IN[0] - Task handle. Hanlde of the task to destroy
+   ReturnCode - One of the ERR_SYS_... */
+#define CX18_DESTROY_TASK     			(MGR_CMD_MASK | 0x0002)
+
+/* All commands for CPU have the following mask set */
+#define CPU_CMD_MASK                        	0x20000000
+#define CPU_CMD_MASK_DEBUG       		(CPU_CMD_MASK | 0x00000000)
+#define CPU_CMD_MASK_ACK                    	(CPU_CMD_MASK | 0x80000000)
+#define CPU_CMD_MASK_CAPTURE                	(CPU_CMD_MASK | 0x00020000)
+#define CPU_CMD_MASK_TS                     	(CPU_CMD_MASK | 0x00040000)
+
+#define EPU_CMD_MASK                        	0x02000000
+#define EPU_CMD_MASK_DEBUG       		(EPU_CMD_MASK | 0x000000)
+#define EPU_CMD_MASK_DE                     	(EPU_CMD_MASK | 0x040000)
+
+#define APU_CMD_MASK 				0x10000000
+#define APU_CMD_MASK_ACK 			(APU_CMD_MASK | 0x80000000)
+
+#define CX18_APU_ENCODING_METHOD_MPEG		(0 << 28)
+#define CX18_APU_ENCODING_METHOD_AC3		(1 << 28)
+
+/* Description: Command APU to start audio
+   IN[0] - audio parameters (same as CX18_CPU_SET_AUDIO_PARAMETERS?)
+   IN[1] - caller buffer address, or 0
+   ReturnCode - ??? */
+#define CX18_APU_START				(APU_CMD_MASK | 0x01)
+
+/* Description: Command APU to stop audio
+   IN[0] - encoding method to stop
+   ReturnCode - ??? */
+#define CX18_APU_STOP				(APU_CMD_MASK | 0x02)
+
+/* Description: Command APU to reset the AI
+   ReturnCode - ??? */
+#define CX18_APU_RESETAI 			(APU_CMD_MASK | 0x05)
+
+/* Description: This command indicates that a Memory Descriptor List has been
+   filled with the requested channel type
+   IN[0] - Task handle. Handle of the task
+   IN[1] - Offset of the MDL_ACK from the beginning of the local DDR.
+   IN[2] - Number of CNXT_MDL_ACK structures in the array pointed to by IN[1]
+   ReturnCode - One of the ERR_DE_... */
+#define CX18_EPU_DMA_DONE              		(EPU_CMD_MASK_DE | 0x0001)
+
+/* Something interesting happened
+   IN[0] - A value to log
+   IN[1] - An offset of a string in the MiniMe memory;
+	   0/zero/NULL means "I have nothing to say" */
+#define CX18_EPU_DEBUG 				(EPU_CMD_MASK_DEBUG | 0x0003)
+
+/* Reads memory/registers (32-bit)
+   IN[0] - Address
+   OUT[1] - Value */
+#define CX18_CPU_DEBUG_PEEK32			(CPU_CMD_MASK_DEBUG | 0x0003)
+
+/* Description: This command starts streaming with the set channel type
+   IN[0] - Task handle. Handle of the task to start
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_CAPTURE_START               	(CPU_CMD_MASK_CAPTURE | 0x0002)
+
+/* Description: This command stops streaming with the set channel type
+   IN[0] - Task handle. Handle of the task to stop
+   IN[1] - 0 = stop at end of GOP, 1 = stop at end of frame (MPEG only)
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_CAPTURE_STOP                	(CPU_CMD_MASK_CAPTURE | 0x0003)
+
+/* Description: This command pauses streaming with the set channel type
+   IN[0] - Task handle. Handle of the task to pause
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_CAPTURE_PAUSE               	(CPU_CMD_MASK_CAPTURE | 0x0007)
+
+/* Description: This command resumes streaming with the set channel type
+   IN[0] - Task handle. Handle of the task to resume
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_CAPTURE_RESUME              	(CPU_CMD_MASK_CAPTURE | 0x0008)
+
+#define CAPTURE_CHANNEL_TYPE_NONE  		0
+#define CAPTURE_CHANNEL_TYPE_MPEG  		1
+#define CAPTURE_CHANNEL_TYPE_INDEX 		2
+#define CAPTURE_CHANNEL_TYPE_YUV   		3
+#define CAPTURE_CHANNEL_TYPE_PCM   		4
+#define CAPTURE_CHANNEL_TYPE_VBI   		5
+#define CAPTURE_CHANNEL_TYPE_SLICED_VBI		6
+#define CAPTURE_CHANNEL_TYPE_TS			7
+#define CAPTURE_CHANNEL_TYPE_MAX   		15
+
+/* Description: This command sets the channel type. This can only be done
+   when stopped.
+   IN[0] - Task handle. Handle of the task to start
+   IN[1] - Channel Type. See Below.
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_CHANNEL_TYPE      		(CPU_CMD_MASK_CAPTURE + 1)
+
+/* Description: Set stream output type
+   IN[0] - task handle. Handle of the task to start
+   IN[1] - type
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_STREAM_OUTPUT_TYPE		(CPU_CMD_MASK_CAPTURE | 0x0012)
+
+/* Description: Set video input resolution and frame rate
+   IN[0] - task handle
+   IN[1] - reserved
+   IN[2] - reserved
+   IN[3] - reserved
+   IN[4] - reserved
+   IN[5] - frame rate, 0 - 29.97f/s, 1 - 25f/s
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_IN                	(CPU_CMD_MASK_CAPTURE | 0x0004)
+
+/* Description: Set video frame rate
+   IN[0] - task handle. Handle of the task to start
+   IN[1] - video bit rate mode
+   IN[2] - video average rate
+   IN[3] - video peak rate
+   IN[4] - system mux rate
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_RATE              	(CPU_CMD_MASK_CAPTURE | 0x0005)
+
+/* Description: Set video output resolution
+   IN[0] - task handle
+   IN[1] - horizontal size
+   IN[2] - vertical size
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_RESOLUTION		(CPU_CMD_MASK_CAPTURE | 0x0006)
+
+/* Description: This command set filter parameters
+   IN[0] - Task handle. Handle of the task
+   IN[1] - type, 0 - temporal, 1 - spatial, 2 - median
+   IN[2] - mode,  temporal/spatial: 0 - disable, 1 - static, 2 - dynamic
+			median:	0 = disable, 1 = horizontal, 2 = vertical,
+				3 = horizontal/vertical, 4 = diagonal
+   IN[3] - strength, temporal 0 - 31, spatial 0 - 15
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_FILTER_PARAM            	(CPU_CMD_MASK_CAPTURE | 0x0009)
+
+/* Description: This command set spatial filter type
+   IN[0] - Task handle.
+   IN[1] - luma type: 0 = disable, 1 = 1D horizontal only, 2 = 1D vertical only,
+		      3 = 2D H/V separable, 4 = 2D symmetric non-separable
+   IN[2] - chroma type: 0 - disable, 1 = 1D horizontal
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_SPATIAL_FILTER_TYPE     	(CPU_CMD_MASK_CAPTURE | 0x000C)
+
+/* Description: This command set coring levels for median filter
+   IN[0] - Task handle.
+   IN[1] - luma_high
+   IN[2] - luma_low
+   IN[3] - chroma_high
+   IN[4] - chroma_low
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_MEDIAN_CORING           	(CPU_CMD_MASK_CAPTURE | 0x000E)
+
+/* Description: This command set the picture type mask for index file
+   IN[0] - Task handle (ignored by firmware)
+   IN[1] - 	0 = disable index file output
+			1 = output I picture
+			2 = P picture
+			4 = B picture
+			other = illegal */
+#define CX18_CPU_SET_INDEXTABLE         	(CPU_CMD_MASK_CAPTURE | 0x0010)
+
+/* Description: Set audio parameters
+   IN[0] - task handle. Handle of the task to start
+   IN[1] - audio parameter
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_AUDIO_PARAMETERS		(CPU_CMD_MASK_CAPTURE | 0x0011)
+
+/* Description: Set video mute
+   IN[0] - task handle. Handle of the task to start
+   IN[1] - bit31-24: muteYvalue
+	   bit23-16: muteUvalue
+	   bit15-8:  muteVvalue
+	   bit0:     1:mute, 0: unmute
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_MUTE			(CPU_CMD_MASK_CAPTURE | 0x0013)
+
+/* Description: Set audio mute
+   IN[0] - task handle. Handle of the task to start
+   IN[1] - mute/unmute
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_AUDIO_MUTE			(CPU_CMD_MASK_CAPTURE | 0x0014)
+
+/* Description: Set stream output type
+   IN[0] - task handle. Handle of the task to start
+   IN[1] - subType
+	    SET_INITIAL_SCR      		1
+	    SET_QUALITY_MODE            2
+	    SET_VIM_PROTECT_MODE        3
+	    SET_PTS_CORRECTION          4
+	    SET_USB_FLUSH_MODE          5
+	    SET_MERAQPAR_ENABLE         6
+	    SET_NAV_PACK_INSERTION      7
+	    SET_SCENE_CHANGE_ENABLE     8
+   IN[2] - parameter 1
+   IN[3] - parameter 2
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_MISC_PARAMETERS		(CPU_CMD_MASK_CAPTURE | 0x0015)
+
+/* Description: Set raw VBI parameters
+   IN[0] - Task handle
+   IN[1] - No. of input lines per field:
+				bit[15:0]: field 1,
+				bit[31:16]: field 2
+   IN[2] - No. of input bytes per line
+   IN[3] - No. of output frames per transfer
+   IN[4] - start code
+   IN[5] - stop code
+   ReturnCode */
+#define CX18_CPU_SET_RAW_VBI_PARAM		(CPU_CMD_MASK_CAPTURE | 0x0016)
+
+/* Description: Set capture line No.
+   IN[0] - task handle. Handle of the task to start
+   IN[1] - height1
+   IN[2] - height2
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_CAPTURE_LINE_NO		(CPU_CMD_MASK_CAPTURE | 0x0017)
+
+/* Description: Set copyright
+   IN[0] - task handle. Handle of the task to start
+   IN[1] - copyright
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_COPYRIGHT			(CPU_CMD_MASK_CAPTURE | 0x0018)
+
+/* Description: Set audio PID
+   IN[0] - task handle. Handle of the task to start
+   IN[1] - PID
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_AUDIO_PID			(CPU_CMD_MASK_CAPTURE | 0x0019)
+
+/* Description: Set video PID
+   IN[0] - task handle. Handle of the task to start
+   IN[1] - PID
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_PID			(CPU_CMD_MASK_CAPTURE | 0x001A)
+
+/* Description: Set Vertical Crop Line
+   IN[0] - task handle. Handle of the task to start
+   IN[1] - Line
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VER_CROP_LINE		(CPU_CMD_MASK_CAPTURE | 0x001B)
+
+/* Description: Set COP structure
+   IN[0] - task handle. Handle of the task to start
+   IN[1] - M
+   IN[2] - N
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_GOP_STRUCTURE		(CPU_CMD_MASK_CAPTURE | 0x001C)
+
+/* Description: Set Scene Change Detection
+   IN[0] - task handle. Handle of the task to start
+   IN[1] - scene change
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_SCENE_CHANGE_DETECTION	(CPU_CMD_MASK_CAPTURE | 0x001D)
+
+/* Description: Set Aspect Ratio
+   IN[0] - task handle. Handle of the task to start
+   IN[1] - AspectRatio
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_ASPECT_RATIO		(CPU_CMD_MASK_CAPTURE | 0x001E)
+
+/* Description: Set Skip Input Frame
+   IN[0] - task handle. Handle of the task to start
+   IN[1] - skip input frames
+   ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_SKIP_INPUT_FRAME		(CPU_CMD_MASK_CAPTURE | 0x001F)
+
+/* Description: Set sliced VBI parameters -
+   Note This API will only apply to MPEG and Sliced VBI Channels
+   IN[0] - Task handle
+   IN[1] - output type, 0 - CC, 1 - Moji, 2 - Teletext
+   IN[2] - start / stop line
+			bit[15:0] start line number
+			bit[31:16] stop line number
+   IN[3] - number of output frames per interrupt
+   IN[4] - VBI insertion mode
+			bit 0:	output user data, 1 - enable
+			bit 1:	output private stream, 1 - enable
+			bit 2:	mux option, 0 - in GOP, 1 - in picture
+			bit[7:0] 	private stream ID
+   IN[5] - insertion period while mux option is in picture
+   ReturnCode - VBI data offset */
+#define CX18_CPU_SET_SLICED_VBI_PARAM		(CPU_CMD_MASK_CAPTURE | 0x0020)
+
+/* Description: Set the user data place holder
+   IN[0] - type of data (0 for user)
+   IN[1] - Stuffing period
+   IN[2] - ID data size in word (less than 10)
+   IN[3] - Pointer to ID buffer */
+#define CX18_CPU_SET_USERDATA_PLACE_HOLDER	(CPU_CMD_MASK_CAPTURE | 0x0021)
+
+
+/* Description:
+   In[0] Task Handle
+   return parameter:
+   Out[0]  Reserved
+   Out[1]  Video PTS bit[32:2] of last output video frame.
+   Out[2]  Video PTS bit[ 1:0] of last output video frame.
+   Out[3]  Hardware Video PTS counter bit[31:0],
+	     these bits get incremented on every 90kHz clock tick.
+   Out[4]  Hardware Video PTS counter bit32,
+	     these bits get incremented on every 90kHz clock tick.
+   ReturnCode */
+#define CX18_CPU_GET_ENC_PTS			(CPU_CMD_MASK_CAPTURE | 0x0022)
+
+/* Description: Set VFC parameters
+   IN[0] - task handle
+   IN[1] - VFC enable flag, 1 - enable, 0 - disable
+*/
+#define CX18_CPU_SET_VFC_PARAM                  (CPU_CMD_MASK_CAPTURE | 0x0023)
+
+/* Below is the list of commands related to the data exchange */
+#define CPU_CMD_MASK_DE 			(CPU_CMD_MASK | 0x040000)
+
+/* Description: This command provides the physical base address of the local
+   DDR as viewed by EPU
+   IN[0] - Physical offset where EPU has the local DDR mapped
+   ReturnCode - One of the ERR_DE_... */
+#define CPU_CMD_DE_SetBase 			(CPU_CMD_MASK_DE | 0x0001)
+
+/* Description: This command provides the offsets in the device memory where
+   the 2 cx18_mdl_ack blocks reside
+   IN[0] - Task handle. Handle of the task to start
+   IN[1] - Offset of the first cx18_mdl_ack from the beginning of the
+	   local DDR.
+   IN[2] - Offset of the second cx18_mdl_ack from the beginning of the
+	   local DDR.
+   ReturnCode - One of the ERR_DE_... */
+#define CX18_CPU_DE_SET_MDL_ACK                	(CPU_CMD_MASK_DE | 0x0002)
+
+/* Description: This command provides the offset to a Memory Descriptor List
+   IN[0] - Task handle. Handle of the task to start
+   IN[1] - Offset of the MDL from the beginning of the local DDR.
+   IN[2] - Number of cx18_mdl_ent structures in the array pointed to by IN[1]
+   IN[3] - Buffer ID
+   IN[4] - Total buffer length
+   ReturnCode - One of the ERR_DE_... */
+#define CX18_CPU_DE_SET_MDL                   	(CPU_CMD_MASK_DE | 0x0005)
+
+/* Description: This command requests return of all current Memory
+   Descriptor Lists to the driver
+   IN[0] - Task handle. Handle of the task to start
+   ReturnCode - One of the ERR_DE_... */
+#define CX18_CPU_DE_RELEASE_MDL               	(CPU_CMD_MASK_DE | 0x0006)
+
+/* Description: This command signals the cpu that the dat buffer has been
+   consumed and ready for re-use.
+   IN[0] - Task handle. Handle of the task
+   IN[1] - Offset of the data block from the beginning of the local DDR.
+   IN[2] - Number of bytes in the data block
+   ReturnCode - One of the ERR_DE_... */
+/* #define CX18_CPU_DE_RELEASE_BUFFER           (CPU_CMD_MASK_DE | 0x0007) */
+
+/* No Error / Success */
+#define CNXT_OK                 0x000000
+
+/* Received unknown command */
+#define CXERR_UNK_CMD           0x000001
+
+/* First parameter in the command is invalid */
+#define CXERR_INVALID_PARAM1    0x000002
+
+/* Second parameter in the command is invalid */
+#define CXERR_INVALID_PARAM2    0x000003
+
+/* Device interface is not open/found */
+#define CXERR_DEV_NOT_FOUND     0x000004
+
+/* Requested function is not implemented/available */
+#define CXERR_NOTSUPPORTED      0x000005
+
+/* Invalid pointer is provided */
+#define CXERR_BADPTR            0x000006
+
+/* Unable to allocate memory */
+#define CXERR_NOMEM             0x000007
+
+/* Object/Link not found */
+#define CXERR_LINK              0x000008
+
+/* Device busy, command cannot be executed */
+#define CXERR_BUSY              0x000009
+
+/* File/device/handle is not open. */
+#define CXERR_NOT_OPEN          0x00000A
+
+/* Value is out of range */
+#define CXERR_OUTOFRANGE        0x00000B
+
+/* Buffer overflow */
+#define CXERR_OVERFLOW          0x00000C
+
+/* Version mismatch */
+#define CXERR_BADVER            0x00000D
+
+/* Operation timed out */
+#define CXERR_TIMEOUT           0x00000E
+
+/* Operation aborted */
+#define CXERR_ABORT             0x00000F
+
+/* Specified I2C device not found for read/write */
+#define CXERR_I2CDEV_NOTFOUND   0x000010
+
+/* Error in I2C data xfer (but I2C device is present) */
+#define CXERR_I2CDEV_XFERERR    0x000011
+
+/* Chanel changing component not ready */
+#define CXERR_CHANNELNOTREADY   0x000012
+
+/* PPU (Presensation/Decoder) mail box is corrupted */
+#define CXERR_PPU_MB_CORRUPT    0x000013
+
+/* CPU (Capture/Encoder) mail box is corrupted */
+#define CXERR_CPU_MB_CORRUPT    0x000014
+
+/* APU (Audio) mail box is corrupted */
+#define CXERR_APU_MB_CORRUPT    0x000015
+
+/* Unable to open file for reading */
+#define CXERR_FILE_OPEN_READ    0x000016
+
+/* Unable to open file for writing */
+#define CXERR_FILE_OPEN_WRITE   0x000017
+
+/* Unable to find the I2C section specified */
+#define CXERR_I2C_BADSECTION    0x000018
+
+/* Error in I2C data xfer (but I2C device is present) */
+#define CXERR_I2CDEV_DATALOW    0x000019
+
+/* Error in I2C data xfer (but I2C device is present) */
+#define CXERR_I2CDEV_CLOCKLOW   0x00001A
+
+/* No Interrupt received from HW (for I2C access) */
+#define CXERR_NO_HW_I2C_INTR    0x00001B
+
+/* RPU is not ready to accept commands! */
+#define CXERR_RPU_NOT_READY     0x00001C
+
+/* RPU is not ready to accept commands! */
+#define CXERR_RPU_NO_ACK        0x00001D
+
+/* The are no buffers ready. Try again soon! */
+#define CXERR_NODATA_AGAIN      0x00001E
+
+/* The stream is stopping. Function not allowed now! */
+#define CXERR_STOPPING_STATUS   0x00001F
+
+/* Trying to access hardware when the power is turned OFF */
+#define CXERR_DEVPOWER_OFF      0x000020
+
+#endif /* CX23418_H */
diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig
new file mode 100644
index 0000000..b391e9b
--- /dev/null
+++ b/drivers/media/pci/cx23885/Kconfig
@@ -0,0 +1,46 @@
+config VIDEO_CX23885
+	tristate "Conexant cx23885 (2388x successor) support"
+	depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT && SND
+	select SND_PCM
+	select I2C_ALGOBIT
+	select VIDEO_BTCX
+	select VIDEO_TUNER
+	select VIDEO_TVEEPROM
+	depends on RC_CORE
+	select VIDEOBUF_DVB
+	select VIDEOBUF_DMA_SG
+	select VIDEO_CX25840
+	select VIDEO_CX2341X
+	select DVB_DIB7000P if !DVB_FE_CUSTOMISE
+	select DVB_S5H1409 if !DVB_FE_CUSTOMISE
+	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
+	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10048 if !DVB_FE_CUSTOMISE
+	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+	select DVB_STV6110 if !DVB_FE_CUSTOMISE
+	select DVB_CX24116 if !DVB_FE_CUSTOMISE
+	select DVB_STV0900 if !DVB_FE_CUSTOMISE
+	select DVB_DS3000 if !DVB_FE_CUSTOMISE
+	select DVB_STV0367 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
+	---help---
+	  This is a video4linux driver for Conexant 23885 based
+	  TV cards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx23885
+
+config MEDIA_ALTERA_CI
+	tristate "Altera FPGA based CI module"
+	depends on VIDEO_CX23885 && DVB_CORE
+	select ALTERA_STAPL
+	---help---
+	  An Altera FPGA CI module for NetUP Dual DVB-T/C RF CI card.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called altera-ci
diff --git a/drivers/media/pci/cx23885/Makefile b/drivers/media/pci/cx23885/Makefile
new file mode 100644
index 0000000..a2cbdcf
--- /dev/null
+++ b/drivers/media/pci/cx23885/Makefile
@@ -0,0 +1,15 @@
+cx23885-objs	:= cx23885-cards.o cx23885-video.o cx23885-vbi.o \
+		    cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \
+		    cx23885-ioctl.o cx23885-ir.o cx23885-av.o cx23885-input.o \
+		    cx23888-ir.o netup-init.o cimax2.o netup-eeprom.o \
+		    cx23885-f300.o cx23885-alsa.o
+
+obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
+obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o
+
+ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+
+ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c
new file mode 100644
index 0000000..1fa8927
--- /dev/null
+++ b/drivers/media/pci/cx23885/altera-ci.c
@@ -0,0 +1,837 @@
+/*
+ * altera-ci.c
+ *
+ *  CI driver in conjunction with NetUp Dual DVB-T/C RF CI card
+ *
+ * Copyright (C) 2010,2011 NetUP Inc.
+ * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * currently cx23885 GPIO's used.
+ * GPIO-0 ~INT in
+ * GPIO-1 TMS out
+ * GPIO-2 ~reset chips out
+ * GPIO-3 to GPIO-10 data/addr for CA in/out
+ * GPIO-11 ~CS out
+ * GPIO-12 AD_RG out
+ * GPIO-13 ~WR out
+ * GPIO-14 ~RD out
+ * GPIO-15 ~RDY in
+ * GPIO-16 TCK out
+ * GPIO-17 TDO in
+ * GPIO-18 TDI out
+ */
+/*
+ *  Bit definitions for MC417_RWD and MC417_OEN registers
+ * bits 31-16
+ * +-----------+
+ * | Reserved  |
+ * +-----------+
+ *   bit 15  bit 14  bit 13 bit 12  bit 11  bit 10  bit 9   bit 8
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |  TDI  |  TDO  |  TCK  |  RDY# |  #RD  |  #WR  | AD_RG |  #CS  |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *  bit 7   bit 6   bit 5   bit 4   bit 3   bit 2   bit 1   bit 0
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |  DATA7|  DATA6|  DATA5|  DATA4|  DATA3|  DATA2|  DATA1|  DATA0|
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#include <media/videobuf-dma-sg.h>
+#include <media/videobuf-dvb.h>
+#include "altera-ci.h"
+#include "dvb_ca_en50221.h"
+
+/* FPGA regs */
+#define NETUP_CI_INT_CTRL	0x00
+#define NETUP_CI_BUSCTRL2	0x01
+#define NETUP_CI_ADDR0		0x04
+#define NETUP_CI_ADDR1		0x05
+#define NETUP_CI_DATA		0x06
+#define NETUP_CI_BUSCTRL	0x07
+#define NETUP_CI_PID_ADDR0	0x08
+#define NETUP_CI_PID_ADDR1	0x09
+#define NETUP_CI_PID_DATA	0x0a
+#define NETUP_CI_TSA_DIV	0x0c
+#define NETUP_CI_TSB_DIV	0x0d
+#define NETUP_CI_REVISION	0x0f
+
+/* const for ci op */
+#define NETUP_CI_FLG_CTL	1
+#define NETUP_CI_FLG_RD		1
+#define NETUP_CI_FLG_AD		1
+
+static unsigned int ci_dbg;
+module_param(ci_dbg, int, 0644);
+MODULE_PARM_DESC(ci_dbg, "Enable CI debugging");
+
+static unsigned int pid_dbg;
+module_param(pid_dbg, int, 0644);
+MODULE_PARM_DESC(pid_dbg, "Enable PID filtering debugging");
+
+MODULE_DESCRIPTION("altera FPGA CI module");
+MODULE_AUTHOR("Igor M. Liplianin  <liplianin@netup.ru>");
+MODULE_LICENSE("GPL");
+
+#define ci_dbg_print(args...) \
+	do { \
+		if (ci_dbg) \
+			printk(KERN_DEBUG args); \
+	} while (0)
+
+#define pid_dbg_print(args...) \
+	do { \
+		if (pid_dbg) \
+			printk(KERN_DEBUG args); \
+	} while (0)
+
+struct altera_ci_state;
+struct netup_hw_pid_filter;
+
+struct fpga_internal {
+	void *dev;
+	struct mutex fpga_mutex;/* two CI's on the same fpga */
+	struct netup_hw_pid_filter *pid_filt[2];
+	struct altera_ci_state *state[2];
+	struct work_struct work;
+	int (*fpga_rw) (void *dev, int flag, int data, int rw);
+	int cis_used;
+	int filts_used;
+	int strt_wrk;
+};
+
+/* stores all private variables for communication with CI */
+struct altera_ci_state {
+	struct fpga_internal *internal;
+	struct dvb_ca_en50221 ca;
+	int status;
+	int nr;
+};
+
+/* stores all private variables for hardware pid filtering */
+struct netup_hw_pid_filter {
+	struct fpga_internal *internal;
+	struct dvb_demux *demux;
+	/* save old functions */
+	int (*start_feed)(struct dvb_demux_feed *feed);
+	int (*stop_feed)(struct dvb_demux_feed *feed);
+
+	int status;
+	int nr;
+};
+
+/* internal params node */
+struct fpga_inode {
+	/* pointer for internal params, one for each pair of CI's */
+	struct fpga_internal		*internal;
+	struct fpga_inode		*next_inode;
+};
+
+/* first internal params */
+static struct fpga_inode *fpga_first_inode;
+
+/* find chip by dev */
+static struct fpga_inode *find_inode(void *dev)
+{
+	struct fpga_inode *temp_chip = fpga_first_inode;
+
+	if (temp_chip == NULL)
+		return temp_chip;
+
+	/*
+	 Search for the last fpga CI chip or
+	 find it by dev */
+	while ((temp_chip != NULL) &&
+				(temp_chip->internal->dev != dev))
+		temp_chip = temp_chip->next_inode;
+
+	return temp_chip;
+}
+/* check demux */
+static struct fpga_internal *check_filter(struct fpga_internal *temp_int,
+						void *demux_dev, int filt_nr)
+{
+	if (temp_int == NULL)
+		return NULL;
+
+	if ((temp_int->pid_filt[filt_nr]) == NULL)
+		return NULL;
+
+	if (temp_int->pid_filt[filt_nr]->demux == demux_dev)
+		return temp_int;
+
+	return NULL;
+}
+
+/* find chip by demux */
+static struct fpga_inode *find_dinode(void *demux_dev)
+{
+	struct fpga_inode *temp_chip = fpga_first_inode;
+	struct fpga_internal *temp_int;
+
+	/*
+	 * Search of the last fpga CI chip or
+	 * find it by demux
+	 */
+	while (temp_chip != NULL) {
+		if (temp_chip->internal != NULL) {
+			temp_int = temp_chip->internal;
+			if (check_filter(temp_int, demux_dev, 0))
+				break;
+			if (check_filter(temp_int, demux_dev, 1))
+				break;
+		}
+
+		temp_chip = temp_chip->next_inode;
+	}
+
+	return temp_chip;
+}
+
+/* deallocating chip */
+static void remove_inode(struct fpga_internal *internal)
+{
+	struct fpga_inode *prev_node = fpga_first_inode;
+	struct fpga_inode *del_node = find_inode(internal->dev);
+
+	if (del_node != NULL) {
+		if (del_node == fpga_first_inode) {
+			fpga_first_inode = del_node->next_inode;
+		} else {
+			while (prev_node->next_inode != del_node)
+				prev_node = prev_node->next_inode;
+
+			if (del_node->next_inode == NULL)
+				prev_node->next_inode = NULL;
+			else
+				prev_node->next_inode =
+					prev_node->next_inode->next_inode;
+		}
+
+		kfree(del_node);
+	}
+}
+
+/* allocating new chip */
+static struct fpga_inode *append_internal(struct fpga_internal *internal)
+{
+	struct fpga_inode *new_node = fpga_first_inode;
+
+	if (new_node == NULL) {
+		new_node = kmalloc(sizeof(struct fpga_inode), GFP_KERNEL);
+		fpga_first_inode = new_node;
+	} else {
+		while (new_node->next_inode != NULL)
+			new_node = new_node->next_inode;
+
+		new_node->next_inode =
+				kmalloc(sizeof(struct fpga_inode), GFP_KERNEL);
+		if (new_node->next_inode != NULL)
+			new_node = new_node->next_inode;
+		else
+			new_node = NULL;
+	}
+
+	if (new_node != NULL) {
+		new_node->internal = internal;
+		new_node->next_inode = NULL;
+	}
+
+	return new_node;
+}
+
+static int netup_fpga_op_rw(struct fpga_internal *inter, int addr,
+							u8 val, u8 read)
+{
+	inter->fpga_rw(inter->dev, NETUP_CI_FLG_AD, addr, 0);
+	return inter->fpga_rw(inter->dev, 0, val, read);
+}
+
+/* flag - mem/io, read - read/write */
+int altera_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot,
+				u8 flag, u8 read, int addr, u8 val)
+{
+
+	struct altera_ci_state *state = en50221->data;
+	struct fpga_internal *inter = state->internal;
+
+	u8 store;
+	int mem = 0;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	mutex_lock(&inter->fpga_mutex);
+
+	netup_fpga_op_rw(inter, NETUP_CI_ADDR0, ((addr << 1) & 0xfe), 0);
+	netup_fpga_op_rw(inter, NETUP_CI_ADDR1, ((addr >> 7) & 0x7f), 0);
+	store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD);
+
+	store &= 0x0f;
+	store |= ((state->nr << 7) | (flag << 6));
+
+	netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, store, 0);
+	mem = netup_fpga_op_rw(inter, NETUP_CI_DATA, val, read);
+
+	mutex_unlock(&inter->fpga_mutex);
+
+	ci_dbg_print("%s: %s: addr=[0x%02x], %s=%x\n", __func__,
+			(read) ? "read" : "write", addr,
+			(flag == NETUP_CI_FLG_CTL) ? "ctl" : "mem",
+			(read) ? mem : val);
+
+	return mem;
+}
+
+int altera_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
+						int slot, int addr)
+{
+	return altera_ci_op_cam(en50221, slot, 0, NETUP_CI_FLG_RD, addr, 0);
+}
+
+int altera_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
+						int slot, int addr, u8 data)
+{
+	return altera_ci_op_cam(en50221, slot, 0, 0, addr, data);
+}
+
+int altera_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr)
+{
+	return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL,
+						NETUP_CI_FLG_RD, addr, 0);
+}
+
+int altera_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot,
+						u8 addr, u8 data)
+{
+	return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL, 0, addr, data);
+}
+
+int altera_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
+{
+	struct altera_ci_state *state = en50221->data;
+	struct fpga_internal *inter = state->internal;
+	/* reasonable timeout for CI reset is 10 seconds */
+	unsigned long t_out = jiffies + msecs_to_jiffies(9999);
+	int ret;
+
+	ci_dbg_print("%s\n", __func__);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	mutex_lock(&inter->fpga_mutex);
+
+	ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD);
+	netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL,
+				(ret & 0xcf) | (1 << (5 - state->nr)), 0);
+
+	mutex_unlock(&inter->fpga_mutex);
+
+	for (;;) {
+		mdelay(50);
+
+		mutex_lock(&inter->fpga_mutex);
+
+		ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL,
+						0, NETUP_CI_FLG_RD);
+		mutex_unlock(&inter->fpga_mutex);
+
+		if ((ret & (1 << (5 - state->nr))) == 0)
+			break;
+		if (time_after(jiffies, t_out))
+			break;
+	}
+
+
+	ci_dbg_print("%s: %d msecs\n", __func__,
+		jiffies_to_msecs(jiffies + msecs_to_jiffies(9999) - t_out));
+
+	return 0;
+}
+
+int altera_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
+{
+	/* not implemented */
+	return 0;
+}
+
+int altera_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot)
+{
+	struct altera_ci_state *state = en50221->data;
+	struct fpga_internal *inter = state->internal;
+	int ret;
+
+	ci_dbg_print("%s\n", __func__);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	mutex_lock(&inter->fpga_mutex);
+
+	ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD);
+	netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL,
+				(ret & 0x0f) | (1 << (3 - state->nr)), 0);
+
+	mutex_unlock(&inter->fpga_mutex);
+
+	return 0;
+}
+
+/* work handler */
+static void netup_read_ci_status(struct work_struct *work)
+{
+	struct fpga_internal *inter =
+			container_of(work, struct fpga_internal, work);
+	int ret;
+
+	ci_dbg_print("%s\n", __func__);
+
+	mutex_lock(&inter->fpga_mutex);
+	/* ack' irq */
+	ret = netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0, NETUP_CI_FLG_RD);
+	ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD);
+
+	mutex_unlock(&inter->fpga_mutex);
+
+	if (inter->state[1] != NULL) {
+		inter->state[1]->status =
+				((ret & 1) == 0 ?
+				DVB_CA_EN50221_POLL_CAM_PRESENT |
+				DVB_CA_EN50221_POLL_CAM_READY : 0);
+		ci_dbg_print("%s: setting CI[1] status = 0x%x\n",
+				__func__, inter->state[1]->status);
+	};
+
+	if (inter->state[0] != NULL) {
+		inter->state[0]->status =
+				((ret & 2) == 0 ?
+				DVB_CA_EN50221_POLL_CAM_PRESENT |
+				DVB_CA_EN50221_POLL_CAM_READY : 0);
+		ci_dbg_print("%s: setting CI[0] status = 0x%x\n",
+				__func__, inter->state[0]->status);
+	};
+}
+
+/* CI irq handler */
+int altera_ci_irq(void *dev)
+{
+	struct fpga_inode *temp_int = NULL;
+	struct fpga_internal *inter = NULL;
+
+	ci_dbg_print("%s\n", __func__);
+
+	if (dev != NULL) {
+		temp_int = find_inode(dev);
+		if (temp_int != NULL) {
+			inter = temp_int->internal;
+			schedule_work(&inter->work);
+		}
+	}
+
+	return 1;
+}
+EXPORT_SYMBOL(altera_ci_irq);
+
+int altera_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot,
+								int open)
+{
+	struct altera_ci_state *state = en50221->data;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	return state->status;
+}
+
+void altera_hw_filt_release(void *main_dev, int filt_nr)
+{
+	struct fpga_inode *temp_int = find_inode(main_dev);
+	struct netup_hw_pid_filter *pid_filt = NULL;
+
+	ci_dbg_print("%s\n", __func__);
+
+	if (temp_int != NULL) {
+		pid_filt = temp_int->internal->pid_filt[filt_nr - 1];
+		/* stored old feed controls */
+		pid_filt->demux->start_feed = pid_filt->start_feed;
+		pid_filt->demux->stop_feed = pid_filt->stop_feed;
+
+		if (((--(temp_int->internal->filts_used)) <= 0) &&
+			 ((temp_int->internal->cis_used) <= 0)) {
+
+			ci_dbg_print("%s: Actually removing\n", __func__);
+
+			remove_inode(temp_int->internal);
+			kfree(pid_filt->internal);
+		}
+
+		kfree(pid_filt);
+
+	}
+
+}
+EXPORT_SYMBOL(altera_hw_filt_release);
+
+void altera_ci_release(void *dev, int ci_nr)
+{
+	struct fpga_inode *temp_int = find_inode(dev);
+	struct altera_ci_state *state = NULL;
+
+	ci_dbg_print("%s\n", __func__);
+
+	if (temp_int != NULL) {
+		state = temp_int->internal->state[ci_nr - 1];
+		altera_hw_filt_release(dev, ci_nr);
+
+
+		if (((temp_int->internal->filts_used) <= 0) &&
+				((--(temp_int->internal->cis_used)) <= 0)) {
+
+			ci_dbg_print("%s: Actually removing\n", __func__);
+
+			remove_inode(temp_int->internal);
+			kfree(state->internal);
+		}
+
+		if (state != NULL) {
+			if (state->ca.data != NULL)
+				dvb_ca_en50221_release(&state->ca);
+
+			kfree(state);
+		}
+	}
+
+}
+EXPORT_SYMBOL(altera_ci_release);
+
+static void altera_pid_control(struct netup_hw_pid_filter *pid_filt,
+		u16 pid, int onoff)
+{
+	struct fpga_internal *inter = pid_filt->internal;
+	u8 store = 0;
+
+	/* pid 0-0x1f always enabled, don't touch them */
+	if ((pid == 0x2000) || (pid < 0x20))
+		return;
+
+	mutex_lock(&inter->fpga_mutex);
+
+	netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, (pid >> 3) & 0xff, 0);
+	netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1,
+			((pid >> 11) & 0x03) | (pid_filt->nr << 2), 0);
+
+	store = netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, 0, NETUP_CI_FLG_RD);
+
+	if (onoff)/* 0 - on, 1 - off */
+		store |= (1 << (pid & 7));
+	else
+		store &= ~(1 << (pid & 7));
+
+	netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, store, 0);
+
+	mutex_unlock(&inter->fpga_mutex);
+
+	pid_dbg_print("%s: (%d) set pid: %5d 0x%04x '%s'\n", __func__,
+		pid_filt->nr, pid, pid, onoff ? "off" : "on");
+}
+
+static void altera_toggle_fullts_streaming(struct netup_hw_pid_filter *pid_filt,
+					int filt_nr, int onoff)
+{
+	struct fpga_internal *inter = pid_filt->internal;
+	u8 store = 0;
+	int i;
+
+	pid_dbg_print("%s: pid_filt->nr[%d]  now %s\n", __func__, pid_filt->nr,
+			onoff ? "off" : "on");
+
+	if (onoff)/* 0 - on, 1 - off */
+		store = 0xff;/* ignore pid */
+	else
+		store = 0;/* enable pid */
+
+	mutex_lock(&inter->fpga_mutex);
+
+	for (i = 0; i < 1024; i++) {
+		netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, i & 0xff, 0);
+
+		netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1,
+				((i >> 8) & 0x03) | (pid_filt->nr << 2), 0);
+		/* pid 0-0x1f always enabled */
+		netup_fpga_op_rw(inter, NETUP_CI_PID_DATA,
+				(i > 3 ? store : 0), 0);
+	}
+
+	mutex_unlock(&inter->fpga_mutex);
+}
+
+int altera_pid_feed_control(void *demux_dev, int filt_nr,
+		struct dvb_demux_feed *feed, int onoff)
+{
+	struct fpga_inode *temp_int = find_dinode(demux_dev);
+	struct fpga_internal *inter = temp_int->internal;
+	struct netup_hw_pid_filter *pid_filt = inter->pid_filt[filt_nr - 1];
+
+	altera_pid_control(pid_filt, feed->pid, onoff ? 0 : 1);
+	/* call old feed proc's */
+	if (onoff)
+		pid_filt->start_feed(feed);
+	else
+		pid_filt->stop_feed(feed);
+
+	if (feed->pid == 0x2000)
+		altera_toggle_fullts_streaming(pid_filt, filt_nr,
+						onoff ? 0 : 1);
+
+	return 0;
+}
+EXPORT_SYMBOL(altera_pid_feed_control);
+
+int altera_ci_start_feed(struct dvb_demux_feed *feed, int num)
+{
+	altera_pid_feed_control(feed->demux, num, feed, 1);
+
+	return 0;
+}
+
+int altera_ci_stop_feed(struct dvb_demux_feed *feed, int num)
+{
+	altera_pid_feed_control(feed->demux, num, feed, 0);
+
+	return 0;
+}
+
+int altera_ci_start_feed_1(struct dvb_demux_feed *feed)
+{
+	return altera_ci_start_feed(feed, 1);
+}
+
+int altera_ci_stop_feed_1(struct dvb_demux_feed *feed)
+{
+	return altera_ci_stop_feed(feed, 1);
+}
+
+int altera_ci_start_feed_2(struct dvb_demux_feed *feed)
+{
+	return altera_ci_start_feed(feed, 2);
+}
+
+int altera_ci_stop_feed_2(struct dvb_demux_feed *feed)
+{
+	return altera_ci_stop_feed(feed, 2);
+}
+
+int altera_hw_filt_init(struct altera_ci_config *config, int hw_filt_nr)
+{
+	struct netup_hw_pid_filter *pid_filt = NULL;
+	struct fpga_inode *temp_int = find_inode(config->dev);
+	struct fpga_internal *inter = NULL;
+	int ret = 0;
+
+	pid_filt = kzalloc(sizeof(struct netup_hw_pid_filter), GFP_KERNEL);
+
+	ci_dbg_print("%s\n", __func__);
+
+	if (!pid_filt) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	if (temp_int != NULL) {
+		inter = temp_int->internal;
+		(inter->filts_used)++;
+		ci_dbg_print("%s: Find Internal Structure!\n", __func__);
+	} else {
+		inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL);
+		if (!inter) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		temp_int = append_internal(inter);
+		inter->filts_used = 1;
+		inter->dev = config->dev;
+		inter->fpga_rw = config->fpga_rw;
+		mutex_init(&inter->fpga_mutex);
+		inter->strt_wrk = 1;
+		ci_dbg_print("%s: Create New Internal Structure!\n", __func__);
+	}
+
+	ci_dbg_print("%s: setting hw pid filter = %p for ci = %d\n", __func__,
+						pid_filt, hw_filt_nr - 1);
+	inter->pid_filt[hw_filt_nr - 1] = pid_filt;
+	pid_filt->demux = config->demux;
+	pid_filt->internal = inter;
+	pid_filt->nr = hw_filt_nr - 1;
+	/* store old feed controls */
+	pid_filt->start_feed = config->demux->start_feed;
+	pid_filt->stop_feed = config->demux->stop_feed;
+	/* replace with new feed controls */
+	if (hw_filt_nr == 1) {
+		pid_filt->demux->start_feed = altera_ci_start_feed_1;
+		pid_filt->demux->stop_feed = altera_ci_stop_feed_1;
+	} else if (hw_filt_nr == 2) {
+		pid_filt->demux->start_feed = altera_ci_start_feed_2;
+		pid_filt->demux->stop_feed = altera_ci_stop_feed_2;
+	}
+
+	altera_toggle_fullts_streaming(pid_filt, 0, 1);
+
+	return 0;
+err:
+	ci_dbg_print("%s: Can't init hardware filter: Error %d\n",
+		     __func__, ret);
+
+	kfree(pid_filt);
+
+	return ret;
+}
+EXPORT_SYMBOL(altera_hw_filt_init);
+
+int altera_ci_init(struct altera_ci_config *config, int ci_nr)
+{
+	struct altera_ci_state *state;
+	struct fpga_inode *temp_int = find_inode(config->dev);
+	struct fpga_internal *inter = NULL;
+	int ret = 0;
+	u8 store = 0;
+
+	state = kzalloc(sizeof(struct altera_ci_state), GFP_KERNEL);
+
+	ci_dbg_print("%s\n", __func__);
+
+	if (!state) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	if (temp_int != NULL) {
+		inter = temp_int->internal;
+		(inter->cis_used)++;
+		ci_dbg_print("%s: Find Internal Structure!\n", __func__);
+	} else {
+		inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL);
+		if (!inter) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		temp_int = append_internal(inter);
+		inter->cis_used = 1;
+		inter->dev = config->dev;
+		inter->fpga_rw = config->fpga_rw;
+		mutex_init(&inter->fpga_mutex);
+		inter->strt_wrk = 1;
+		ci_dbg_print("%s: Create New Internal Structure!\n", __func__);
+	}
+
+	ci_dbg_print("%s: setting state = %p for ci = %d\n", __func__,
+						state, ci_nr - 1);
+	inter->state[ci_nr - 1] = state;
+	state->internal = inter;
+	state->nr = ci_nr - 1;
+
+	state->ca.owner = THIS_MODULE;
+	state->ca.read_attribute_mem = altera_ci_read_attribute_mem;
+	state->ca.write_attribute_mem = altera_ci_write_attribute_mem;
+	state->ca.read_cam_control = altera_ci_read_cam_ctl;
+	state->ca.write_cam_control = altera_ci_write_cam_ctl;
+	state->ca.slot_reset = altera_ci_slot_reset;
+	state->ca.slot_shutdown = altera_ci_slot_shutdown;
+	state->ca.slot_ts_enable = altera_ci_slot_ts_ctl;
+	state->ca.poll_slot_status = altera_poll_ci_slot_status;
+	state->ca.data = state;
+
+	ret = dvb_ca_en50221_init(config->adapter,
+				   &state->ca,
+				   /* flags */ 0,
+				   /* n_slots */ 1);
+	if (0 != ret)
+		goto err;
+
+	altera_hw_filt_init(config, ci_nr);
+
+	if (inter->strt_wrk) {
+		INIT_WORK(&inter->work, netup_read_ci_status);
+		inter->strt_wrk = 0;
+	}
+
+	ci_dbg_print("%s: CI initialized!\n", __func__);
+
+	mutex_lock(&inter->fpga_mutex);
+
+	/* Enable div */
+	netup_fpga_op_rw(inter, NETUP_CI_TSA_DIV, 0x0, 0);
+	netup_fpga_op_rw(inter, NETUP_CI_TSB_DIV, 0x0, 0);
+
+	/* enable TS out */
+	store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD);
+	store |= (3 << 4);
+	netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0);
+
+	ret = netup_fpga_op_rw(inter, NETUP_CI_REVISION, 0, NETUP_CI_FLG_RD);
+	/* enable irq */
+	netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0x44, 0);
+
+	mutex_unlock(&inter->fpga_mutex);
+
+	ci_dbg_print("%s: NetUP CI Revision = 0x%x\n", __func__, ret);
+
+	schedule_work(&inter->work);
+
+	return 0;
+err:
+	ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret);
+
+	kfree(state);
+
+	return ret;
+}
+EXPORT_SYMBOL(altera_ci_init);
+
+int altera_ci_tuner_reset(void *dev, int ci_nr)
+{
+	struct fpga_inode *temp_int = find_inode(dev);
+	struct fpga_internal *inter = NULL;
+	u8 store;
+
+	ci_dbg_print("%s\n", __func__);
+
+	if (temp_int == NULL)
+		return -1;
+
+	if (temp_int->internal == NULL)
+		return -1;
+
+	inter = temp_int->internal;
+
+	mutex_lock(&inter->fpga_mutex);
+
+	store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD);
+	store &= ~(4 << (2 - ci_nr));
+	netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0);
+	msleep(100);
+	store |= (4 << (2 - ci_nr));
+	netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0);
+
+	mutex_unlock(&inter->fpga_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(altera_ci_tuner_reset);
diff --git a/drivers/media/pci/cx23885/altera-ci.h b/drivers/media/pci/cx23885/altera-ci.h
new file mode 100644
index 0000000..70e4fd6
--- /dev/null
+++ b/drivers/media/pci/cx23885/altera-ci.h
@@ -0,0 +1,100 @@
+/*
+ * altera-ci.c
+ *
+ *  CI driver in conjunction with NetUp Dual DVB-T/C RF CI card
+ *
+ * Copyright (C) 2010 NetUP Inc.
+ * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef __ALTERA_CI_H
+#define __ALTERA_CI_H
+
+#define ALT_DATA	0x000000ff
+#define ALT_TDI		0x00008000
+#define ALT_TDO		0x00004000
+#define ALT_TCK		0x00002000
+#define ALT_RDY		0x00001000
+#define ALT_RD		0x00000800
+#define ALT_WR		0x00000400
+#define ALT_AD_RG	0x00000200
+#define ALT_CS		0x00000100
+
+struct altera_ci_config {
+	void *dev;/* main dev, for example cx23885_dev */
+	void *adapter;/* for CI to connect to */
+	struct dvb_demux *demux;/* for hardware PID filter to connect to */
+	int (*fpga_rw) (void *dev, int ad_rg, int val, int rw);
+};
+
+#if defined(CONFIG_MEDIA_ALTERA_CI) || (defined(CONFIG_MEDIA_ALTERA_CI_MODULE) \
+							&& defined(MODULE))
+
+extern int altera_ci_init(struct altera_ci_config *config, int ci_nr);
+extern void altera_ci_release(void *dev, int ci_nr);
+extern int altera_ci_irq(void *dev);
+extern int altera_ci_tuner_reset(void *dev, int ci_nr);
+
+#else
+
+static inline int altera_ci_init(struct altera_ci_config *config, int ci_nr)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return 0;
+}
+
+static inline void altera_ci_release(void *dev, int ci_nr)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+
+static inline int altera_ci_irq(void *dev)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return 0;
+}
+
+static inline int altera_ci_tuner_reset(void *dev, int ci_nr)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return 0;
+}
+
+#endif
+#if 0
+static inline int altera_hw_filt_init(struct altera_ci_config *config,
+							int hw_filt_nr)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return 0;
+}
+
+static inline void altera_hw_filt_release(void *dev, int filt_nr)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+
+static inline int altera_pid_feed_control(void *dev, int filt_nr,
+		struct dvb_demux_feed *dvbdmxfeed, int onoff)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return 0;
+}
+
+#endif /* CONFIG_MEDIA_ALTERA_CI */
+
+#endif /* __ALTERA_CI_H */
diff --git a/drivers/media/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c
new file mode 100644
index 0000000..c9f15d6
--- /dev/null
+++ b/drivers/media/pci/cx23885/cimax2.c
@@ -0,0 +1,536 @@
+/*
+ * cimax2.c
+ *
+ * CIMax2(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cx23885.h"
+#include "dvb_ca_en50221.h"
+/**** Bit definitions for MC417_RWD and MC417_OEN registers  ***
+  bits 31-16
++-----------+
+| Reserved  |
++-----------+
+  bit 15  bit 14  bit 13 bit 12  bit 11  bit 10  bit 9   bit 8
++-------+-------+-------+-------+-------+-------+-------+-------+
+|  WR#  |  RD#  |       |  ACK# |  ADHI |  ADLO |  CS1# |  CS0# |
++-------+-------+-------+-------+-------+-------+-------+-------+
+ bit 7   bit 6   bit 5   bit 4   bit 3   bit 2   bit 1   bit 0
++-------+-------+-------+-------+-------+-------+-------+-------+
+|  DATA7|  DATA6|  DATA5|  DATA4|  DATA3|  DATA2|  DATA1|  DATA0|
++-------+-------+-------+-------+-------+-------+-------+-------+
+***/
+/* MC417 */
+#define NETUP_DATA		0x000000ff
+#define NETUP_WR		0x00008000
+#define NETUP_RD		0x00004000
+#define NETUP_ACK		0x00001000
+#define NETUP_ADHI		0x00000800
+#define NETUP_ADLO		0x00000400
+#define NETUP_CS1		0x00000200
+#define NETUP_CS0		0x00000100
+#define NETUP_EN_ALL		0x00001000
+#define NETUP_CTRL_OFF		(NETUP_CS1 | NETUP_CS0 | NETUP_WR | NETUP_RD)
+#define NETUP_CI_CTL		0x04
+#define NETUP_CI_RD		1
+
+#define NETUP_IRQ_DETAM 	0x1
+#define NETUP_IRQ_IRQAM		0x4
+
+static unsigned int ci_dbg;
+module_param(ci_dbg, int, 0644);
+MODULE_PARM_DESC(ci_dbg, "Enable CI debugging");
+
+static unsigned int ci_irq_enable;
+module_param(ci_irq_enable, int, 0644);
+MODULE_PARM_DESC(ci_irq_enable, "Enable IRQ from CAM");
+
+#define ci_dbg_print(args...) \
+	do { \
+		if (ci_dbg) \
+			printk(KERN_DEBUG args); \
+	} while (0)
+
+#define ci_irq_flags() (ci_irq_enable ? NETUP_IRQ_IRQAM : 0)
+
+/* stores all private variables for communication with CI */
+struct netup_ci_state {
+	struct dvb_ca_en50221 ca;
+	struct mutex ca_mutex;
+	struct i2c_adapter *i2c_adap;
+	u8 ci_i2c_addr;
+	int status;
+	struct work_struct work;
+	void *priv;
+	u8 current_irq_mode;
+	int current_ci_flag;
+	unsigned long next_status_checked_time;
+};
+
+
+int netup_read_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg,
+						u8 *buf, int len)
+{
+	int ret;
+	struct i2c_msg msg[] = {
+		{
+			.addr	= addr,
+			.flags	= 0,
+			.buf	= &reg,
+			.len	= 1
+		}, {
+			.addr	= addr,
+			.flags	= I2C_M_RD,
+			.buf	= buf,
+			.len	= len
+		}
+	};
+
+	ret = i2c_transfer(i2c_adap, msg, 2);
+
+	if (ret != 2) {
+		ci_dbg_print("%s: i2c read error, Reg = 0x%02x, Status = %d\n",
+						__func__, reg, ret);
+
+		return -1;
+	}
+
+	ci_dbg_print("%s: i2c read Addr=0x%04x, Reg = 0x%02x, data = %02x\n",
+						__func__, addr, reg, buf[0]);
+
+	return 0;
+}
+
+int netup_write_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg,
+						u8 *buf, int len)
+{
+	int ret;
+	u8 buffer[len + 1];
+
+	struct i2c_msg msg = {
+		.addr	= addr,
+		.flags	= 0,
+		.buf	= &buffer[0],
+		.len	= len + 1
+	};
+
+	buffer[0] = reg;
+	memcpy(&buffer[1], buf, len);
+
+	ret = i2c_transfer(i2c_adap, &msg, 1);
+
+	if (ret != 1) {
+		ci_dbg_print("%s: i2c write error, Reg=[0x%02x], Status=%d\n",
+						__func__, reg, ret);
+		return -1;
+	}
+
+	return 0;
+}
+
+int netup_ci_get_mem(struct cx23885_dev *dev)
+{
+	int mem;
+	unsigned long timeout = jiffies + msecs_to_jiffies(1);
+
+	for (;;) {
+		mem = cx_read(MC417_RWD);
+		if ((mem & NETUP_ACK) == 0)
+			break;
+		if (time_after(jiffies, timeout))
+			break;
+		udelay(1);
+	}
+
+	cx_set(MC417_RWD, NETUP_CTRL_OFF);
+
+	return mem & 0xff;
+}
+
+int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot,
+				u8 flag, u8 read, int addr, u8 data)
+{
+	struct netup_ci_state *state = en50221->data;
+	struct cx23885_tsport *port = state->priv;
+	struct cx23885_dev *dev = port->dev;
+
+	u8 store;
+	int mem;
+	int ret;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	if (state->current_ci_flag != flag) {
+		ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr,
+				0, &store, 1);
+		if (ret != 0)
+			return ret;
+
+		store &= ~0x0c;
+		store |= flag;
+
+		ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+				0, &store, 1);
+		if (ret != 0)
+			return ret;
+	};
+	state->current_ci_flag = flag;
+
+	mutex_lock(&dev->gpio_lock);
+
+	/* write addr */
+	cx_write(MC417_OEN, NETUP_EN_ALL);
+	cx_write(MC417_RWD, NETUP_CTRL_OFF |
+				NETUP_ADLO | (0xff & addr));
+	cx_clear(MC417_RWD, NETUP_ADLO);
+	cx_write(MC417_RWD, NETUP_CTRL_OFF |
+				NETUP_ADHI | (0xff & (addr >> 8)));
+	cx_clear(MC417_RWD, NETUP_ADHI);
+
+	if (read) { /* data in */
+		cx_write(MC417_OEN, NETUP_EN_ALL | NETUP_DATA);
+	} else /* data out */
+		cx_write(MC417_RWD, NETUP_CTRL_OFF | data);
+
+	/* choose chip */
+	cx_clear(MC417_RWD,
+			(state->ci_i2c_addr == 0x40) ? NETUP_CS0 : NETUP_CS1);
+	/* read/write */
+	cx_clear(MC417_RWD, (read) ? NETUP_RD : NETUP_WR);
+	mem = netup_ci_get_mem(dev);
+
+	mutex_unlock(&dev->gpio_lock);
+
+	if (!read)
+		if (mem < 0)
+			return -EREMOTEIO;
+
+	ci_dbg_print("%s: %s: chipaddr=[0x%x] addr=[0x%02x], %s=%x\n", __func__,
+			(read) ? "read" : "write", state->ci_i2c_addr, addr,
+			(flag == NETUP_CI_CTL) ? "ctl" : "mem",
+			(read) ? mem : data);
+
+	if (read)
+		return mem;
+
+	return 0;
+}
+
+int netup_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
+						int slot, int addr)
+{
+	return netup_ci_op_cam(en50221, slot, 0, NETUP_CI_RD, addr, 0);
+}
+
+int netup_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
+						int slot, int addr, u8 data)
+{
+	return netup_ci_op_cam(en50221, slot, 0, 0, addr, data);
+}
+
+int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr)
+{
+	return netup_ci_op_cam(en50221, slot, NETUP_CI_CTL,
+							NETUP_CI_RD, addr, 0);
+}
+
+int netup_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot,
+							u8 addr, u8 data)
+{
+	return netup_ci_op_cam(en50221, slot, NETUP_CI_CTL, 0, addr, data);
+}
+
+int netup_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
+{
+	struct netup_ci_state *state = en50221->data;
+	u8 buf =  0x80;
+	int ret;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	udelay(500);
+	ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+							0, &buf, 1);
+
+	if (ret != 0)
+		return ret;
+
+	udelay(500);
+
+	buf = 0x00;
+	ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+							0, &buf, 1);
+
+	msleep(1000);
+	dvb_ca_en50221_camready_irq(&state->ca, 0);
+
+	return 0;
+
+}
+
+int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
+{
+	/* not implemented */
+	return 0;
+}
+
+int netup_ci_set_irq(struct dvb_ca_en50221 *en50221, u8 irq_mode)
+{
+	struct netup_ci_state *state = en50221->data;
+	int ret;
+
+	if (irq_mode == state->current_irq_mode)
+		return 0;
+
+	ci_dbg_print("%s: chipaddr=[0x%x] setting ci IRQ to [0x%x] \n",
+			__func__, state->ci_i2c_addr, irq_mode);
+	ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+							0x1b, &irq_mode, 1);
+
+	if (ret != 0)
+		return ret;
+
+	state->current_irq_mode = irq_mode;
+
+	return 0;
+}
+
+int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot)
+{
+	struct netup_ci_state *state = en50221->data;
+	u8 buf;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	netup_read_i2c(state->i2c_adap, state->ci_i2c_addr,
+			0, &buf, 1);
+	buf |= 0x60;
+
+	return netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+							0, &buf, 1);
+}
+
+/* work handler */
+static void netup_read_ci_status(struct work_struct *work)
+{
+	struct netup_ci_state *state =
+			container_of(work, struct netup_ci_state, work);
+	u8 buf[33];
+	int ret;
+
+	/* CAM module IRQ processing. fast operation */
+	dvb_ca_en50221_frda_irq(&state->ca, 0);
+
+	/* CAM module INSERT/REMOVE processing. slow operation because of i2c
+	 * transfers */
+	if (time_after(jiffies, state->next_status_checked_time)
+			|| !state->status) {
+		ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr,
+				0, &buf[0], 33);
+
+		state->next_status_checked_time = jiffies
+			+ msecs_to_jiffies(1000);
+
+		if (ret != 0)
+			return;
+
+		ci_dbg_print("%s: Slot Status Addr=[0x%04x], "
+				"Reg=[0x%02x], data=%02x, "
+				"TS config = %02x\n", __func__,
+				state->ci_i2c_addr, 0, buf[0],
+				buf[0]);
+
+
+		if (buf[0] & 1)
+			state->status = DVB_CA_EN50221_POLL_CAM_PRESENT |
+				DVB_CA_EN50221_POLL_CAM_READY;
+		else
+			state->status = 0;
+	}
+}
+
+/* CI irq handler */
+int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status)
+{
+	struct cx23885_tsport *port = NULL;
+	struct netup_ci_state *state = NULL;
+
+	ci_dbg_print("%s:\n", __func__);
+
+	if (0 == (pci_status & (PCI_MSK_GPIO0 | PCI_MSK_GPIO1)))
+		return 0;
+
+	if (pci_status & PCI_MSK_GPIO0) {
+		port = &dev->ts1;
+		state = port->port_priv;
+		schedule_work(&state->work);
+		ci_dbg_print("%s: Wakeup CI0\n", __func__);
+	}
+
+	if (pci_status & PCI_MSK_GPIO1) {
+		port = &dev->ts2;
+		state = port->port_priv;
+		schedule_work(&state->work);
+		ci_dbg_print("%s: Wakeup CI1\n", __func__);
+	}
+
+	return 1;
+}
+
+int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open)
+{
+	struct netup_ci_state *state = en50221->data;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	netup_ci_set_irq(en50221, open ? (NETUP_IRQ_DETAM | ci_irq_flags())
+			: NETUP_IRQ_DETAM);
+
+	return state->status;
+}
+
+int netup_ci_init(struct cx23885_tsport *port)
+{
+	struct netup_ci_state *state;
+	u8 cimax_init[34] = {
+		0x00, /* module A control*/
+		0x00, /* auto select mask high A */
+		0x00, /* auto select mask low A */
+		0x00, /* auto select pattern high A */
+		0x00, /* auto select pattern low A */
+		0x44, /* memory access time A */
+		0x00, /* invert input A */
+		0x00, /* RFU */
+		0x00, /* RFU */
+		0x00, /* module B control*/
+		0x00, /* auto select mask high B */
+		0x00, /* auto select mask low B */
+		0x00, /* auto select pattern high B */
+		0x00, /* auto select pattern low B */
+		0x44, /* memory access time B */
+		0x00, /* invert input B */
+		0x00, /* RFU */
+		0x00, /* RFU */
+		0x00, /* auto select mask high Ext */
+		0x00, /* auto select mask low Ext */
+		0x00, /* auto select pattern high Ext */
+		0x00, /* auto select pattern low Ext */
+		0x00, /* RFU */
+		0x02, /* destination - module A */
+		0x01, /* power on (use it like store place) */
+		0x00, /* RFU */
+		0x00, /* int status read only */
+		ci_irq_flags() | NETUP_IRQ_DETAM, /* DETAM, IRQAM unmasked */
+		0x05, /* EXTINT=active-high, INT=push-pull */
+		0x00, /* USCG1 */
+		0x04, /* ack active low */
+		0x00, /* LOCK = 0 */
+		0x33, /* serial mode, rising in, rising out, MSB first*/
+		0x31, /* synchronization */
+	};
+	int ret;
+
+	ci_dbg_print("%s\n", __func__);
+	state = kzalloc(sizeof(struct netup_ci_state), GFP_KERNEL);
+	if (!state) {
+		ci_dbg_print("%s: Unable create CI structure!\n", __func__);
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	port->port_priv = state;
+
+	switch (port->nr) {
+	case 1:
+		state->ci_i2c_addr = 0x40;
+		break;
+	case 2:
+		state->ci_i2c_addr = 0x41;
+		break;
+	}
+
+	state->i2c_adap = &port->dev->i2c_bus[0].i2c_adap;
+	state->ca.owner = THIS_MODULE;
+	state->ca.read_attribute_mem = netup_ci_read_attribute_mem;
+	state->ca.write_attribute_mem = netup_ci_write_attribute_mem;
+	state->ca.read_cam_control = netup_ci_read_cam_ctl;
+	state->ca.write_cam_control = netup_ci_write_cam_ctl;
+	state->ca.slot_reset = netup_ci_slot_reset;
+	state->ca.slot_shutdown = netup_ci_slot_shutdown;
+	state->ca.slot_ts_enable = netup_ci_slot_ts_ctl;
+	state->ca.poll_slot_status = netup_poll_ci_slot_status;
+	state->ca.data = state;
+	state->priv = port;
+	state->current_irq_mode = ci_irq_flags() | NETUP_IRQ_DETAM;
+
+	ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+						0, &cimax_init[0], 34);
+	/* lock registers */
+	ret |= netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+						0x1f, &cimax_init[0x18], 1);
+	/* power on slots */
+	ret |= netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+						0x18, &cimax_init[0x18], 1);
+
+	if (0 != ret)
+		goto err;
+
+	ret = dvb_ca_en50221_init(&port->frontends.adapter,
+				   &state->ca,
+				   /* flags */ 0,
+				   /* n_slots */ 1);
+	if (0 != ret)
+		goto err;
+
+	INIT_WORK(&state->work, netup_read_ci_status);
+	schedule_work(&state->work);
+
+	ci_dbg_print("%s: CI initialized!\n", __func__);
+
+	return 0;
+err:
+	ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret);
+	kfree(state);
+	return ret;
+}
+
+void netup_ci_exit(struct cx23885_tsport *port)
+{
+	struct netup_ci_state *state;
+
+	if (NULL == port)
+		return;
+
+	state = (struct netup_ci_state *)port->port_priv;
+	if (NULL == state)
+		return;
+
+	if (NULL == state->ca.data)
+		return;
+
+	dvb_ca_en50221_release(&state->ca);
+	kfree(state);
+}
diff --git a/drivers/media/pci/cx23885/cimax2.h b/drivers/media/pci/cx23885/cimax2.h
new file mode 100644
index 0000000..518744a
--- /dev/null
+++ b/drivers/media/pci/cx23885/cimax2.h
@@ -0,0 +1,47 @@
+/*
+ * cimax2.h
+ *
+ * CIMax(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef CIMAX2_H
+#define CIMAX2_H
+#include "dvb_ca_en50221.h"
+
+extern int netup_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
+						int slot, int addr);
+extern int netup_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
+						int slot, int addr, u8 data);
+extern int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221,
+						int slot, u8 addr);
+extern int netup_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221,
+						int slot, u8 addr, u8 data);
+extern int netup_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot);
+extern int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot);
+extern int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot);
+extern int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status);
+extern int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221,
+						int slot, int open);
+extern int netup_ci_init(struct cx23885_tsport *port);
+extern void netup_ci_exit(struct cx23885_tsport *port);
+
+#endif
diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c
new file mode 100644
index 0000000..5d5052d
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-417.c
@@ -0,0 +1,1790 @@
+/*
+ *
+ *  Support for a cx23417 mpeg encoder via cx23885 host port.
+ *
+ *    (c) 2004 Jelle Foks <jelle@foks.us>
+ *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
+ *    (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *      - CX23885/7/8 support
+ *
+ *  Includes parts from the ivtv driver <http://sourceforge.net/projects/ivtv/>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/cx2341x.h>
+
+#include "cx23885.h"
+#include "cx23885-ioctl.h"
+
+#define CX23885_FIRM_IMAGE_SIZE 376836
+#define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
+
+static unsigned int mpegbufs = 32;
+module_param(mpegbufs, int, 0644);
+MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32");
+static unsigned int mpeglines = 32;
+module_param(mpeglines, int, 0644);
+MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
+static unsigned int mpeglinesize = 512;
+module_param(mpeglinesize, int, 0644);
+MODULE_PARM_DESC(mpeglinesize,
+	"number of bytes in each line of an MPEG buffer, range 512-1024");
+
+static unsigned int v4l_debug;
+module_param(v4l_debug, int, 0644);
+MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
+
+#define dprintk(level, fmt, arg...)\
+	do { if (v4l_debug >= level) \
+		printk(KERN_DEBUG "%s: " fmt, \
+		(dev) ? dev->name : "cx23885[?]", ## arg); \
+	} while (0)
+
+static struct cx23885_tvnorm cx23885_tvnorms[] = {
+	{
+		.name      = "NTSC-M",
+		.id        = V4L2_STD_NTSC_M,
+	}, {
+		.name      = "NTSC-JP",
+		.id        = V4L2_STD_NTSC_M_JP,
+	}, {
+		.name      = "PAL-BG",
+		.id        = V4L2_STD_PAL_BG,
+	}, {
+		.name      = "PAL-DK",
+		.id        = V4L2_STD_PAL_DK,
+	}, {
+		.name      = "PAL-I",
+		.id        = V4L2_STD_PAL_I,
+	}, {
+		.name      = "PAL-M",
+		.id        = V4L2_STD_PAL_M,
+	}, {
+		.name      = "PAL-N",
+		.id        = V4L2_STD_PAL_N,
+	}, {
+		.name      = "PAL-Nc",
+		.id        = V4L2_STD_PAL_Nc,
+	}, {
+		.name      = "PAL-60",
+		.id        = V4L2_STD_PAL_60,
+	}, {
+		.name      = "SECAM-L",
+		.id        = V4L2_STD_SECAM_L,
+	}, {
+		.name      = "SECAM-DK",
+		.id        = V4L2_STD_SECAM_DK,
+	}
+};
+
+/* ------------------------------------------------------------------ */
+enum cx23885_capture_type {
+	CX23885_MPEG_CAPTURE,
+	CX23885_RAW_CAPTURE,
+	CX23885_RAW_PASSTHRU_CAPTURE
+};
+enum cx23885_capture_bits {
+	CX23885_RAW_BITS_NONE             = 0x00,
+	CX23885_RAW_BITS_YUV_CAPTURE      = 0x01,
+	CX23885_RAW_BITS_PCM_CAPTURE      = 0x02,
+	CX23885_RAW_BITS_VBI_CAPTURE      = 0x04,
+	CX23885_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
+	CX23885_RAW_BITS_TO_HOST_CAPTURE  = 0x10
+};
+enum cx23885_capture_end {
+	CX23885_END_AT_GOP, /* stop at the end of gop, generate irq */
+	CX23885_END_NOW, /* stop immediately, no irq */
+};
+enum cx23885_framerate {
+	CX23885_FRAMERATE_NTSC_30, /* NTSC: 30fps */
+	CX23885_FRAMERATE_PAL_25   /* PAL: 25fps */
+};
+enum cx23885_stream_port {
+	CX23885_OUTPUT_PORT_MEMORY,
+	CX23885_OUTPUT_PORT_STREAMING,
+	CX23885_OUTPUT_PORT_SERIAL
+};
+enum cx23885_data_xfer_status {
+	CX23885_MORE_BUFFERS_FOLLOW,
+	CX23885_LAST_BUFFER,
+};
+enum cx23885_picture_mask {
+	CX23885_PICTURE_MASK_NONE,
+	CX23885_PICTURE_MASK_I_FRAMES,
+	CX23885_PICTURE_MASK_I_P_FRAMES = 0x3,
+	CX23885_PICTURE_MASK_ALL_FRAMES = 0x7,
+};
+enum cx23885_vbi_mode_bits {
+	CX23885_VBI_BITS_SLICED,
+	CX23885_VBI_BITS_RAW,
+};
+enum cx23885_vbi_insertion_bits {
+	CX23885_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
+	CX23885_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
+	CX23885_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
+	CX23885_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
+	CX23885_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
+};
+enum cx23885_dma_unit {
+	CX23885_DMA_BYTES,
+	CX23885_DMA_FRAMES,
+};
+enum cx23885_dma_transfer_status_bits {
+	CX23885_DMA_TRANSFER_BITS_DONE = 0x01,
+	CX23885_DMA_TRANSFER_BITS_ERROR = 0x04,
+	CX23885_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
+};
+enum cx23885_pause {
+	CX23885_PAUSE_ENCODING,
+	CX23885_RESUME_ENCODING,
+};
+enum cx23885_copyright {
+	CX23885_COPYRIGHT_OFF,
+	CX23885_COPYRIGHT_ON,
+};
+enum cx23885_notification_type {
+	CX23885_NOTIFICATION_REFRESH,
+};
+enum cx23885_notification_status {
+	CX23885_NOTIFICATION_OFF,
+	CX23885_NOTIFICATION_ON,
+};
+enum cx23885_notification_mailbox {
+	CX23885_NOTIFICATION_NO_MAILBOX = -1,
+};
+enum cx23885_field1_lines {
+	CX23885_FIELD1_SAA7114 = 0x00EF, /* 239 */
+	CX23885_FIELD1_SAA7115 = 0x00F0, /* 240 */
+	CX23885_FIELD1_MICRONAS = 0x0105, /* 261 */
+};
+enum cx23885_field2_lines {
+	CX23885_FIELD2_SAA7114 = 0x00EF, /* 239 */
+	CX23885_FIELD2_SAA7115 = 0x00F0, /* 240 */
+	CX23885_FIELD2_MICRONAS = 0x0106, /* 262 */
+};
+enum cx23885_custom_data_type {
+	CX23885_CUSTOM_EXTENSION_USR_DATA,
+	CX23885_CUSTOM_PRIVATE_PACKET,
+};
+enum cx23885_mute {
+	CX23885_UNMUTE,
+	CX23885_MUTE,
+};
+enum cx23885_mute_video_mask {
+	CX23885_MUTE_VIDEO_V_MASK = 0x0000FF00,
+	CX23885_MUTE_VIDEO_U_MASK = 0x00FF0000,
+	CX23885_MUTE_VIDEO_Y_MASK = 0xFF000000,
+};
+enum cx23885_mute_video_shift {
+	CX23885_MUTE_VIDEO_V_SHIFT = 8,
+	CX23885_MUTE_VIDEO_U_SHIFT = 16,
+	CX23885_MUTE_VIDEO_Y_SHIFT = 24,
+};
+
+/* defines below are from ivtv-driver.h */
+#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
+
+/* Firmware API commands */
+#define IVTV_API_STD_TIMEOUT 500
+
+/* Registers */
+/* IVTV_REG_OFFSET */
+#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)
+#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)
+#define IVTV_REG_SPU (0x9050)
+#define IVTV_REG_HW_BLOCKS (0x9054)
+#define IVTV_REG_VPU (0x9058)
+#define IVTV_REG_APU (0xA064)
+
+/**** Bit definitions for MC417_RWD and MC417_OEN registers  ***
+  bits 31-16
++-----------+
+| Reserved  |
++-----------+
+  bit 15  bit 14  bit 13 bit 12  bit 11  bit 10  bit 9   bit 8
++-------+-------+-------+-------+-------+-------+-------+-------+
+| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0|
++-------+-------+-------+-------+-------+-------+-------+-------+
+ bit 7   bit 6   bit 5   bit 4   bit 3   bit 2   bit 1   bit 0
++-------+-------+-------+-------+-------+-------+-------+-------+
+|MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0|
++-------+-------+-------+-------+-------+-------+-------+-------+
+***/
+#define MC417_MIWR	0x8000
+#define MC417_MIRD	0x4000
+#define MC417_MICS	0x2000
+#define MC417_MIRDY	0x1000
+#define MC417_MIADDR	0x0F00
+#define MC417_MIDATA	0x00FF
+
+/* MIADDR* nibble definitions */
+#define  MCI_MEMORY_DATA_BYTE0          0x000
+#define  MCI_MEMORY_DATA_BYTE1          0x100
+#define  MCI_MEMORY_DATA_BYTE2          0x200
+#define  MCI_MEMORY_DATA_BYTE3          0x300
+#define  MCI_MEMORY_ADDRESS_BYTE2       0x400
+#define  MCI_MEMORY_ADDRESS_BYTE1       0x500
+#define  MCI_MEMORY_ADDRESS_BYTE0       0x600
+#define  MCI_REGISTER_DATA_BYTE0        0x800
+#define  MCI_REGISTER_DATA_BYTE1        0x900
+#define  MCI_REGISTER_DATA_BYTE2        0xA00
+#define  MCI_REGISTER_DATA_BYTE3        0xB00
+#define  MCI_REGISTER_ADDRESS_BYTE0     0xC00
+#define  MCI_REGISTER_ADDRESS_BYTE1     0xD00
+#define  MCI_REGISTER_MODE              0xE00
+
+/* Read and write modes */
+#define  MCI_MODE_REGISTER_READ         0
+#define  MCI_MODE_REGISTER_WRITE        1
+#define  MCI_MODE_MEMORY_READ           0
+#define  MCI_MODE_MEMORY_WRITE          0x40
+
+/*** Bit definitions for MC417_CTL register ****
+ bits 31-6   bits 5-4   bit 3    bits 2-1       Bit 0
++--------+-------------+--------+--------------+------------+
+|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN|
++--------+-------------+--------+--------------+------------+
+***/
+#define MC417_SPD_CTL(x)	(((x) << 4) & 0x00000030)
+#define MC417_GPIO_SEL(x)	(((x) << 1) & 0x00000006)
+#define MC417_UART_GPIO_EN	0x00000001
+
+/* Values for speed control */
+#define MC417_SPD_CTL_SLOW	0x1
+#define MC417_SPD_CTL_MEDIUM	0x0
+#define MC417_SPD_CTL_FAST	0x3     /* b'1x, but we use b'11 */
+
+/* Values for GPIO select */
+#define MC417_GPIO_SEL_GPIO3	0x3
+#define MC417_GPIO_SEL_GPIO2	0x2
+#define MC417_GPIO_SEL_GPIO1	0x1
+#define MC417_GPIO_SEL_GPIO0	0x0
+
+void cx23885_mc417_init(struct cx23885_dev *dev)
+{
+	u32 regval;
+
+	dprintk(2, "%s()\n", __func__);
+
+	/* Configure MC417_CTL register to defaults. */
+	regval = MC417_SPD_CTL(MC417_SPD_CTL_FAST)	|
+		 MC417_GPIO_SEL(MC417_GPIO_SEL_GPIO3)	|
+		 MC417_UART_GPIO_EN;
+	cx_write(MC417_CTL, regval);
+
+	/* Configure MC417_OEN to defaults. */
+	regval = MC417_MIRDY;
+	cx_write(MC417_OEN, regval);
+
+	/* Configure MC417_RWD to defaults. */
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS;
+	cx_write(MC417_RWD, regval);
+}
+
+static int mc417_wait_ready(struct cx23885_dev *dev)
+{
+	u32 mi_ready;
+	unsigned long timeout = jiffies + msecs_to_jiffies(1);
+
+	for (;;) {
+		mi_ready = cx_read(MC417_RWD) & MC417_MIRDY;
+		if (mi_ready != 0)
+			return 0;
+		if (time_after(jiffies, timeout))
+			return -1;
+		udelay(1);
+	}
+}
+
+int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value)
+{
+	u32 regval;
+
+	/* Enable MC417 GPIO outputs except for MC417_MIRDY,
+	 * which is an input.
+	 */
+	cx_write(MC417_OEN, MC417_MIRDY);
+
+	/* Write data byte 0 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0 |
+		(value & 0x000000FF);
+	cx_write(MC417_RWD, regval);
+
+	/* Transition CS/WR to effect write transaction across bus. */
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write data byte 1 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1 |
+		((value >> 8) & 0x000000FF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write data byte 2 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2 |
+		((value >> 16) & 0x000000FF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write data byte 3 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3 |
+		((value >> 24) & 0x000000FF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write address byte 0 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
+		(address & 0xFF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write address byte 1 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
+		((address >> 8) & 0xFF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Indicate that this is a write. */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
+		MCI_MODE_REGISTER_WRITE;
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Wait for the trans to complete (MC417_MIRDY asserted). */
+	return mc417_wait_ready(dev);
+}
+
+int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value)
+{
+	int retval;
+	u32 regval;
+	u32 tempval;
+	u32 dataval;
+
+	/* Enable MC417 GPIO outputs except for MC417_MIRDY,
+	 * which is an input.
+	 */
+	cx_write(MC417_OEN, MC417_MIRDY);
+
+	/* Write address byte 0 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
+		((address & 0x00FF));
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write address byte 1 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
+		((address >> 8) & 0xFF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Indicate that this is a register read. */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
+		MCI_MODE_REGISTER_READ;
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Wait for the trans to complete (MC417_MIRDY asserted). */
+	retval = mc417_wait_ready(dev);
+
+	/* switch the DAT0-7 GPIO[10:3] to input mode */
+	cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA);
+
+	/* Read data byte 0 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0;
+	cx_write(MC417_RWD, regval);
+
+	/* Transition RD to effect read transaction across bus.
+	 * Transtion 0x5000 -> 0x9000 correct (RD/RDY -> WR/RDY)?
+	 * Should it be 0x9000 -> 0xF000 (also why is RDY being set, its
+	 * input only...)
+	 */
+	regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0;
+	cx_write(MC417_RWD, regval);
+
+	/* Collect byte */
+	tempval = cx_read(MC417_RWD);
+	dataval = tempval & 0x000000FF;
+
+	/* Bring CS and RD high. */
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+	cx_write(MC417_RWD, regval);
+
+	/* Read data byte 1 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1;
+	cx_write(MC417_RWD, regval);
+	regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1;
+	cx_write(MC417_RWD, regval);
+	tempval = cx_read(MC417_RWD);
+	dataval |= ((tempval & 0x000000FF) << 8);
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+	cx_write(MC417_RWD, regval);
+
+	/* Read data byte 2 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2;
+	cx_write(MC417_RWD, regval);
+	regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2;
+	cx_write(MC417_RWD, regval);
+	tempval = cx_read(MC417_RWD);
+	dataval |= ((tempval & 0x000000FF) << 16);
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+	cx_write(MC417_RWD, regval);
+
+	/* Read data byte 3 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3;
+	cx_write(MC417_RWD, regval);
+	regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3;
+	cx_write(MC417_RWD, regval);
+	tempval = cx_read(MC417_RWD);
+	dataval |= ((tempval & 0x000000FF) << 24);
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+	cx_write(MC417_RWD, regval);
+
+	*value  = dataval;
+
+	return retval;
+}
+
+int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value)
+{
+	u32 regval;
+
+	/* Enable MC417 GPIO outputs except for MC417_MIRDY,
+	 * which is an input.
+	 */
+	cx_write(MC417_OEN, MC417_MIRDY);
+
+	/* Write data byte 0 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0 |
+		(value & 0x000000FF);
+	cx_write(MC417_RWD, regval);
+
+	/* Transition CS/WR to effect write transaction across bus. */
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write data byte 1 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1 |
+		((value >> 8) & 0x000000FF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write data byte 2 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2 |
+		((value >> 16) & 0x000000FF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write data byte 3 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3 |
+		((value >> 24) & 0x000000FF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write address byte 2 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
+		MCI_MODE_MEMORY_WRITE | ((address >> 16) & 0x3F);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write address byte 1 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
+		((address >> 8) & 0xFF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write address byte 0 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
+		(address & 0xFF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Wait for the trans to complete (MC417_MIRDY asserted). */
+	return mc417_wait_ready(dev);
+}
+
+int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value)
+{
+	int retval;
+	u32 regval;
+	u32 tempval;
+	u32 dataval;
+
+	/* Enable MC417 GPIO outputs except for MC417_MIRDY,
+	 * which is an input.
+	 */
+	cx_write(MC417_OEN, MC417_MIRDY);
+
+	/* Write address byte 2 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
+		MCI_MODE_MEMORY_READ | ((address >> 16) & 0x3F);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write address byte 1 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
+		((address >> 8) & 0xFF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write address byte 0 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
+		(address & 0xFF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Wait for the trans to complete (MC417_MIRDY asserted). */
+	retval = mc417_wait_ready(dev);
+
+	/* switch the DAT0-7 GPIO[10:3] to input mode */
+	cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA);
+
+	/* Read data byte 3 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3;
+	cx_write(MC417_RWD, regval);
+
+	/* Transition RD to effect read transaction across bus. */
+	regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3;
+	cx_write(MC417_RWD, regval);
+
+	/* Collect byte */
+	tempval = cx_read(MC417_RWD);
+	dataval = ((tempval & 0x000000FF) << 24);
+
+	/* Bring CS and RD high. */
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+	cx_write(MC417_RWD, regval);
+
+	/* Read data byte 2 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2;
+	cx_write(MC417_RWD, regval);
+	regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2;
+	cx_write(MC417_RWD, regval);
+	tempval = cx_read(MC417_RWD);
+	dataval |= ((tempval & 0x000000FF) << 16);
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+	cx_write(MC417_RWD, regval);
+
+	/* Read data byte 1 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1;
+	cx_write(MC417_RWD, regval);
+	regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1;
+	cx_write(MC417_RWD, regval);
+	tempval = cx_read(MC417_RWD);
+	dataval |= ((tempval & 0x000000FF) << 8);
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+	cx_write(MC417_RWD, regval);
+
+	/* Read data byte 0 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0;
+	cx_write(MC417_RWD, regval);
+	regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0;
+	cx_write(MC417_RWD, regval);
+	tempval = cx_read(MC417_RWD);
+	dataval |= (tempval & 0x000000FF);
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+	cx_write(MC417_RWD, regval);
+
+	*value  = dataval;
+
+	return retval;
+}
+
+void mc417_gpio_set(struct cx23885_dev *dev, u32 mask)
+{
+	u32 val;
+
+	/* Set the gpio value */
+	mc417_register_read(dev, 0x900C, &val);
+	val |= (mask & 0x000ffff);
+	mc417_register_write(dev, 0x900C, val);
+}
+
+void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask)
+{
+	u32 val;
+
+	/* Clear the gpio value */
+	mc417_register_read(dev, 0x900C, &val);
+	val &= ~(mask & 0x0000ffff);
+	mc417_register_write(dev, 0x900C, val);
+}
+
+void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
+{
+	u32 val;
+
+	/* Enable GPIO direction bits */
+	mc417_register_read(dev, 0x9020, &val);
+	if (asoutput)
+		val |= (mask & 0x0000ffff);
+	else
+		val &= ~(mask & 0x0000ffff);
+
+	mc417_register_write(dev, 0x9020, val);
+}
+/* ------------------------------------------------------------------ */
+
+/* MPEG encoder API */
+static char *cmd_to_str(int cmd)
+{
+	switch (cmd) {
+	case CX2341X_ENC_PING_FW:
+		return  "PING_FW";
+	case CX2341X_ENC_START_CAPTURE:
+		return  "START_CAPTURE";
+	case CX2341X_ENC_STOP_CAPTURE:
+		return  "STOP_CAPTURE";
+	case CX2341X_ENC_SET_AUDIO_ID:
+		return  "SET_AUDIO_ID";
+	case CX2341X_ENC_SET_VIDEO_ID:
+		return  "SET_VIDEO_ID";
+	case CX2341X_ENC_SET_PCR_ID:
+		return  "SET_PCR_ID";
+	case CX2341X_ENC_SET_FRAME_RATE:
+		return  "SET_FRAME_RATE";
+	case CX2341X_ENC_SET_FRAME_SIZE:
+		return  "SET_FRAME_SIZE";
+	case CX2341X_ENC_SET_BIT_RATE:
+		return  "SET_BIT_RATE";
+	case CX2341X_ENC_SET_GOP_PROPERTIES:
+		return  "SET_GOP_PROPERTIES";
+	case CX2341X_ENC_SET_ASPECT_RATIO:
+		return  "SET_ASPECT_RATIO";
+	case CX2341X_ENC_SET_DNR_FILTER_MODE:
+		return  "SET_DNR_FILTER_MODE";
+	case CX2341X_ENC_SET_DNR_FILTER_PROPS:
+		return  "SET_DNR_FILTER_PROPS";
+	case CX2341X_ENC_SET_CORING_LEVELS:
+		return  "SET_CORING_LEVELS";
+	case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
+		return  "SET_SPATIAL_FILTER_TYPE";
+	case CX2341X_ENC_SET_VBI_LINE:
+		return  "SET_VBI_LINE";
+	case CX2341X_ENC_SET_STREAM_TYPE:
+		return  "SET_STREAM_TYPE";
+	case CX2341X_ENC_SET_OUTPUT_PORT:
+		return  "SET_OUTPUT_PORT";
+	case CX2341X_ENC_SET_AUDIO_PROPERTIES:
+		return  "SET_AUDIO_PROPERTIES";
+	case CX2341X_ENC_HALT_FW:
+		return  "HALT_FW";
+	case CX2341X_ENC_GET_VERSION:
+		return  "GET_VERSION";
+	case CX2341X_ENC_SET_GOP_CLOSURE:
+		return  "SET_GOP_CLOSURE";
+	case CX2341X_ENC_GET_SEQ_END:
+		return  "GET_SEQ_END";
+	case CX2341X_ENC_SET_PGM_INDEX_INFO:
+		return  "SET_PGM_INDEX_INFO";
+	case CX2341X_ENC_SET_VBI_CONFIG:
+		return  "SET_VBI_CONFIG";
+	case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
+		return  "SET_DMA_BLOCK_SIZE";
+	case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
+		return  "GET_PREV_DMA_INFO_MB_10";
+	case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
+		return  "GET_PREV_DMA_INFO_MB_9";
+	case CX2341X_ENC_SCHED_DMA_TO_HOST:
+		return  "SCHED_DMA_TO_HOST";
+	case CX2341X_ENC_INITIALIZE_INPUT:
+		return  "INITIALIZE_INPUT";
+	case CX2341X_ENC_SET_FRAME_DROP_RATE:
+		return  "SET_FRAME_DROP_RATE";
+	case CX2341X_ENC_PAUSE_ENCODER:
+		return  "PAUSE_ENCODER";
+	case CX2341X_ENC_REFRESH_INPUT:
+		return  "REFRESH_INPUT";
+	case CX2341X_ENC_SET_COPYRIGHT:
+		return  "SET_COPYRIGHT";
+	case CX2341X_ENC_SET_EVENT_NOTIFICATION:
+		return  "SET_EVENT_NOTIFICATION";
+	case CX2341X_ENC_SET_NUM_VSYNC_LINES:
+		return  "SET_NUM_VSYNC_LINES";
+	case CX2341X_ENC_SET_PLACEHOLDER:
+		return  "SET_PLACEHOLDER";
+	case CX2341X_ENC_MUTE_VIDEO:
+		return  "MUTE_VIDEO";
+	case CX2341X_ENC_MUTE_AUDIO:
+		return  "MUTE_AUDIO";
+	case CX2341X_ENC_MISC:
+		return  "MISC";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static int cx23885_mbox_func(void *priv,
+			     u32 command,
+			     int in,
+			     int out,
+			     u32 data[CX2341X_MBOX_MAX_DATA])
+{
+	struct cx23885_dev *dev = priv;
+	unsigned long timeout;
+	u32 value, flag, retval = 0;
+	int i;
+
+	dprintk(3, "%s: command(0x%X) = %s\n", __func__, command,
+		cmd_to_str(command));
+
+	/* this may not be 100% safe if we can't read any memory location
+	   without side effects */
+	mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
+	if (value != 0x12345678) {
+		printk(KERN_ERR
+			"Firmware and/or mailbox pointer not initialized "
+			"or corrupted, signature = 0x%x, cmd = %s\n", value,
+			cmd_to_str(command));
+		return -1;
+	}
+
+	/* This read looks at 32 bits, but flag is only 8 bits.
+	 * Seems we also bail if CMD or TIMEOUT bytes are set???
+	 */
+	mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+	if (flag) {
+		printk(KERN_ERR "ERROR: Mailbox appears to be in use "
+			"(%x), cmd = %s\n", flag, cmd_to_str(command));
+		return -1;
+	}
+
+	flag |= 1; /* tell 'em we're working on it */
+	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+	/* write command + args + fill remaining with zeros */
+	/* command code */
+	mc417_memory_write(dev, dev->cx23417_mailbox + 1, command);
+	mc417_memory_write(dev, dev->cx23417_mailbox + 3,
+		IVTV_API_STD_TIMEOUT); /* timeout */
+	for (i = 0; i < in; i++) {
+		mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]);
+		dprintk(3, "API Input %d = %d\n", i, data[i]);
+	}
+	for (; i < CX2341X_MBOX_MAX_DATA; i++)
+		mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0);
+
+	flag |= 3; /* tell 'em we're done writing */
+	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+	/* wait for firmware to handle the API command */
+	timeout = jiffies + msecs_to_jiffies(10);
+	for (;;) {
+		mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+		if (0 != (flag & 4))
+			break;
+		if (time_after(jiffies, timeout)) {
+			printk(KERN_ERR "ERROR: API Mailbox timeout\n");
+			return -1;
+		}
+		udelay(10);
+	}
+
+	/* read output values */
+	for (i = 0; i < out; i++) {
+		mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i);
+		dprintk(3, "API Output %d = %d\n", i, data[i]);
+	}
+
+	mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval);
+	dprintk(3, "API result = %d\n", retval);
+
+	flag = 0;
+	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+	return retval;
+}
+
+/* We don't need to call the API often, so using just one
+ * mailbox will probably suffice
+ */
+static int cx23885_api_cmd(struct cx23885_dev *dev,
+			   u32 command,
+			   u32 inputcnt,
+			   u32 outputcnt,
+			   ...)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	va_list vargs;
+	int i, err;
+
+	dprintk(3, "%s() cmds = 0x%08x\n", __func__, command);
+
+	va_start(vargs, outputcnt);
+	for (i = 0; i < inputcnt; i++)
+		data[i] = va_arg(vargs, int);
+
+	err = cx23885_mbox_func(dev, command, inputcnt, outputcnt, data);
+	for (i = 0; i < outputcnt; i++) {
+		int *vptr = va_arg(vargs, int *);
+		*vptr = data[i];
+	}
+	va_end(vargs);
+
+	return err;
+}
+
+static int cx23885_find_mailbox(struct cx23885_dev *dev)
+{
+	u32 signature[4] = {
+		0x12345678, 0x34567812, 0x56781234, 0x78123456
+	};
+	int signaturecnt = 0;
+	u32 value;
+	int i;
+
+	dprintk(2, "%s()\n", __func__);
+
+	for (i = 0; i < CX23885_FIRM_IMAGE_SIZE; i++) {
+		mc417_memory_read(dev, i, &value);
+		if (value == signature[signaturecnt])
+			signaturecnt++;
+		else
+			signaturecnt = 0;
+		if (4 == signaturecnt) {
+			dprintk(1, "Mailbox signature found at 0x%x\n", i+1);
+			return i+1;
+		}
+	}
+	printk(KERN_ERR "Mailbox signature values not found!\n");
+	return -1;
+}
+
+static int cx23885_load_firmware(struct cx23885_dev *dev)
+{
+	static const unsigned char magic[8] = {
+		0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
+	};
+	const struct firmware *firmware;
+	int i, retval = 0;
+	u32 value = 0;
+	u32 gpio_output = 0;
+	u32 gpio_value;
+	u32 checksum = 0;
+	u32 *dataptr;
+
+	dprintk(2, "%s()\n", __func__);
+
+	/* Save GPIO settings before reset of APU */
+	retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
+	retval |= mc417_memory_read(dev, 0x900C, &gpio_value);
+
+	retval  = mc417_register_write(dev,
+		IVTV_REG_VPU, 0xFFFFFFED);
+	retval |= mc417_register_write(dev,
+		IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+	retval |= mc417_register_write(dev,
+		IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800);
+	retval |= mc417_register_write(dev,
+		IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
+	retval |= mc417_register_write(dev,
+		IVTV_REG_APU, 0);
+
+	if (retval != 0) {
+		printk(KERN_ERR "%s: Error with mc417_register_write\n",
+			__func__);
+		return -1;
+	}
+
+	retval = request_firmware(&firmware, CX23885_FIRM_IMAGE_NAME,
+				  &dev->pci->dev);
+
+	if (retval != 0) {
+		printk(KERN_ERR
+			"ERROR: Hotplug firmware request failed (%s).\n",
+			CX23885_FIRM_IMAGE_NAME);
+		printk(KERN_ERR "Please fix your hotplug setup, the board will "
+			"not work without firmware loaded!\n");
+		return -1;
+	}
+
+	if (firmware->size != CX23885_FIRM_IMAGE_SIZE) {
+		printk(KERN_ERR "ERROR: Firmware size mismatch "
+			"(have %zd, expected %d)\n",
+			firmware->size, CX23885_FIRM_IMAGE_SIZE);
+		release_firmware(firmware);
+		return -1;
+	}
+
+	if (0 != memcmp(firmware->data, magic, 8)) {
+		printk(KERN_ERR
+			"ERROR: Firmware magic mismatch, wrong file?\n");
+		release_firmware(firmware);
+		return -1;
+	}
+
+	/* transfer to the chip */
+	dprintk(2, "Loading firmware ...\n");
+	dataptr = (u32 *)firmware->data;
+	for (i = 0; i < (firmware->size >> 2); i++) {
+		value = *dataptr;
+		checksum += ~value;
+		if (mc417_memory_write(dev, i, value) != 0) {
+			printk(KERN_ERR "ERROR: Loading firmware failed!\n");
+			release_firmware(firmware);
+			return -1;
+		}
+		dataptr++;
+	}
+
+	/* read back to verify with the checksum */
+	dprintk(1, "Verifying firmware ...\n");
+	for (i--; i >= 0; i--) {
+		if (mc417_memory_read(dev, i, &value) != 0) {
+			printk(KERN_ERR "ERROR: Reading firmware failed!\n");
+			release_firmware(firmware);
+			return -1;
+		}
+		checksum -= ~value;
+	}
+	if (checksum) {
+		printk(KERN_ERR
+			"ERROR: Firmware load failed (checksum mismatch).\n");
+		release_firmware(firmware);
+		return -1;
+	}
+	release_firmware(firmware);
+	dprintk(1, "Firmware upload successful.\n");
+
+	retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
+		IVTV_CMD_HW_BLOCKS_RST);
+
+	/* F/W power up disturbs the GPIOs, restore state */
+	retval |= mc417_register_write(dev, 0x9020, gpio_output);
+	retval |= mc417_register_write(dev, 0x900C, gpio_value);
+
+	retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
+	retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
+
+	/* Hardcoded GPIO's here */
+	retval |= mc417_register_write(dev, 0x9020, 0x4000);
+	retval |= mc417_register_write(dev, 0x900C, 0x4000);
+
+	mc417_register_read(dev, 0x9020, &gpio_output);
+	mc417_register_read(dev, 0x900C, &gpio_value);
+
+	if (retval < 0)
+		printk(KERN_ERR "%s: Error with mc417_register_write\n",
+			__func__);
+	return 0;
+}
+
+void cx23885_417_check_encoder(struct cx23885_dev *dev)
+{
+	u32 status, seq;
+
+	status = seq = 0;
+	cx23885_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq);
+	dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq);
+}
+
+static void cx23885_codec_settings(struct cx23885_dev *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+
+	/* Dynamically change the height based on video standard */
+	if (dev->encodernorm.id & V4L2_STD_525_60)
+		dev->ts1.height = 480;
+	else
+		dev->ts1.height = 576;
+
+	/* assign frame size */
+	cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+				dev->ts1.height, dev->ts1.width);
+
+	dev->mpeg_params.width = dev->ts1.width;
+	dev->mpeg_params.height = dev->ts1.height;
+	dev->mpeg_params.is_50hz =
+		(dev->encodernorm.id & V4L2_STD_625_50) != 0;
+
+	cx2341x_update(dev, cx23885_mbox_func, NULL, &dev->mpeg_params);
+
+	cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
+	cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
+}
+
+static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder)
+{
+	int version;
+	int retval;
+	u32 i, data[7];
+
+	dprintk(1, "%s()\n", __func__);
+
+	retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
+	if (retval < 0) {
+		dprintk(2, "%s() PING OK\n", __func__);
+		retval = cx23885_load_firmware(dev);
+		if (retval < 0) {
+			printk(KERN_ERR "%s() f/w load failed\n", __func__);
+			return retval;
+		}
+		retval = cx23885_find_mailbox(dev);
+		if (retval < 0) {
+			printk(KERN_ERR "%s() mailbox < 0, error\n",
+				__func__);
+			return -1;
+		}
+		dev->cx23417_mailbox = retval;
+		retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
+		if (retval < 0) {
+			printk(KERN_ERR
+				"ERROR: cx23417 firmware ping failed!\n");
+			return -1;
+		}
+		retval = cx23885_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
+			&version);
+		if (retval < 0) {
+			printk(KERN_ERR "ERROR: cx23417 firmware get encoder :"
+				"version failed!\n");
+			return -1;
+		}
+		dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
+		msleep(200);
+	}
+
+	cx23885_codec_settings(dev);
+	msleep(60);
+
+	cx23885_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
+		CX23885_FIELD1_SAA7115, CX23885_FIELD2_SAA7115);
+	cx23885_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
+		CX23885_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0);
+
+	/* Setup to capture VBI */
+	data[0] = 0x0001BD00;
+	data[1] = 1;          /* frames per interrupt */
+	data[2] = 4;          /* total bufs */
+	data[3] = 0x91559155; /* start codes */
+	data[4] = 0x206080C0; /* stop codes */
+	data[5] = 6;          /* lines */
+	data[6] = 64;         /* BPL */
+
+	cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
+		data[2], data[3], data[4], data[5], data[6]);
+
+	for (i = 2; i <= 24; i++) {
+		int valid;
+
+		valid = ((i >= 19) && (i <= 21));
+		cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i,
+				valid, 0 , 0, 0);
+		cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
+				i | 0x80000000, valid, 0, 0, 0);
+	}
+
+	cx23885_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX23885_UNMUTE);
+	msleep(60);
+
+	/* initialize the video input */
+	cx23885_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
+	msleep(60);
+
+	/* Enable VIP style pixel invalidation so we work with scaled mode */
+	mc417_memory_write(dev, 2120, 0x00000080);
+
+	/* start capturing to the host interface */
+	if (startencoder) {
+		cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
+			CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE);
+		msleep(10);
+	}
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int bb_buf_setup(struct videobuf_queue *q,
+	unsigned int *count, unsigned int *size)
+{
+	struct cx23885_fh *fh = q->priv_data;
+
+	fh->dev->ts1.ts_packet_size  = mpeglinesize;
+	fh->dev->ts1.ts_packet_count = mpeglines;
+
+	*size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
+	*count = mpegbufs;
+
+	return 0;
+}
+
+static int bb_buf_prepare(struct videobuf_queue *q,
+	struct videobuf_buffer *vb, enum v4l2_field field)
+{
+	struct cx23885_fh *fh = q->priv_data;
+	return cx23885_buf_prepare(q, &fh->dev->ts1,
+		(struct cx23885_buffer *)vb,
+		field);
+}
+
+static void bb_buf_queue(struct videobuf_queue *q,
+	struct videobuf_buffer *vb)
+{
+	struct cx23885_fh *fh = q->priv_data;
+	cx23885_buf_queue(&fh->dev->ts1, (struct cx23885_buffer *)vb);
+}
+
+static void bb_buf_release(struct videobuf_queue *q,
+	struct videobuf_buffer *vb)
+{
+	cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
+}
+
+static struct videobuf_queue_ops cx23885_qops = {
+	.buf_setup    = bb_buf_setup,
+	.buf_prepare  = bb_buf_prepare,
+	.buf_queue    = bb_buf_queue,
+	.buf_release  = bb_buf_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+static const u32 *ctrl_classes[] = {
+	cx2341x_mpeg_ctrls,
+	NULL
+};
+
+static int cx23885_queryctrl(struct cx23885_dev *dev,
+	struct v4l2_queryctrl *qctrl)
+{
+	qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+	if (qctrl->id == 0)
+		return -EINVAL;
+
+	/* MPEG V4L2 controls */
+	if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
+		qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+
+	return 0;
+}
+
+static int cx23885_querymenu(struct cx23885_dev *dev,
+	struct v4l2_querymenu *qmenu)
+{
+	struct v4l2_queryctrl qctrl;
+
+	qctrl.id = qmenu->id;
+	cx23885_queryctrl(dev, &qctrl);
+	return v4l2_ctrl_query_menu(qmenu, &qctrl,
+		cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id));
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	call_all(dev, core, g_std, id);
+
+	return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++)
+		if (*id & cx23885_tvnorms[i].id)
+			break;
+	if (i == ARRAY_SIZE(cx23885_tvnorms))
+		return -EINVAL;
+	dev->encodernorm = cx23885_tvnorms[i];
+
+	/* Have the drier core notify the subdevices */
+	mutex_lock(&dev->lock);
+	cx23885_set_tvnorm(dev, *id);
+	mutex_unlock(&dev->lock);
+
+	return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+	struct v4l2_input *i)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	dprintk(1, "%s()\n", __func__);
+	return cx23885_enum_input(dev, i);
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	return cx23885_get_input(file, priv, i);
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	return cx23885_set_input(file, priv, i);
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	if (UNSET == dev->tuner_type)
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+	strcpy(t->name, "Television");
+	call_all(dev, tuner, g_tuner, t);
+
+	dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
+
+	return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	if (UNSET == dev->tuner_type)
+		return -EINVAL;
+
+	/* Update the A/V core */
+	call_all(dev, tuner, s_tuner, t);
+
+	return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	if (UNSET == dev->tuner_type)
+		return -EINVAL;
+	f->type = V4L2_TUNER_ANALOG_TV;
+	f->frequency = dev->freq;
+
+	call_all(dev, tuner, g_frequency, f);
+
+	return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+	struct v4l2_frequency *f)
+{
+	return cx23885_set_frequency(file, priv, f);
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+	struct v4l2_control *ctl)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+	return cx23885_get_control(dev, ctl);
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+	struct v4l2_control *ctl)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+	return cx23885_set_control(dev, ctl);
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+				struct v4l2_capability *cap)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_tsport  *tsport = &dev->ts1;
+
+	strlcpy(cap->driver, dev->name, sizeof(cap->driver));
+	strlcpy(cap->card, cx23885_boards[tsport->dev->board].name,
+		sizeof(cap->card));
+	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+	cap->capabilities =
+		V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_READWRITE     |
+		V4L2_CAP_STREAMING     |
+		0;
+	if (UNSET != dev->tuner_type)
+		cap->capabilities |= V4L2_CAP_TUNER;
+
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	if (f->index != 0)
+		return -EINVAL;
+
+	strlcpy(f->description, "MPEG", sizeof(f->description));
+	f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage    =
+		dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+	f->fmt.pix.colorspace   = 0;
+	f->fmt.pix.width        = dev->ts1.width;
+	f->fmt.pix.height       = dev->ts1.height;
+	f->fmt.pix.field        = fh->mpegq.field;
+	dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+		dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage    =
+		dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+	f->fmt.pix.colorspace   = 0;
+	dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+		dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage    =
+		dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+	f->fmt.pix.colorspace   = 0;
+	dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+		f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+	return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+				struct v4l2_requestbuffers *p)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+
+	return videobuf_reqbufs(&fh->mpegq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+				struct v4l2_buffer *p)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+
+	return videobuf_querybuf(&fh->mpegq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv,
+				struct v4l2_buffer *p)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+
+	return videobuf_qbuf(&fh->mpegq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct cx23885_fh  *fh  = priv;
+
+	return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK);
+}
+
+
+static int vidioc_streamon(struct file *file, void *priv,
+				enum v4l2_buf_type i)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+
+	return videobuf_streamon(&fh->mpegq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+
+	return videobuf_streamoff(&fh->mpegq);
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+				struct v4l2_ext_controls *f)
+{
+	struct cx23885_fh  *fh  = priv;
+	struct cx23885_dev *dev = fh->dev;
+
+	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+		return -EINVAL;
+	return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS);
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+				struct v4l2_ext_controls *f)
+{
+	struct cx23885_fh  *fh  = priv;
+	struct cx23885_dev *dev = fh->dev;
+	struct cx2341x_mpeg_params p;
+	int err;
+
+	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+		return -EINVAL;
+
+	p = dev->mpeg_params;
+	err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS);
+
+	if (err == 0) {
+		err = cx2341x_update(dev, cx23885_mbox_func,
+			&dev->mpeg_params, &p);
+		dev->mpeg_params = p;
+	}
+	return err;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+				struct v4l2_ext_controls *f)
+{
+	struct cx23885_fh  *fh  = priv;
+	struct cx23885_dev *dev = fh->dev;
+	struct cx2341x_mpeg_params p;
+	int err;
+
+	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+		return -EINVAL;
+
+	p = dev->mpeg_params;
+	err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
+	return err;
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+	struct cx23885_fh  *fh  = priv;
+	struct cx23885_dev *dev = fh->dev;
+	char name[32 + 2];
+
+	snprintf(name, sizeof(name), "%s/2", dev->name);
+	printk(KERN_INFO
+		"%s/2: ============  START LOG STATUS  ============\n",
+	       dev->name);
+	call_all(dev, core, log_status);
+	cx2341x_log_status(&dev->mpeg_params, name);
+	printk(KERN_INFO
+		"%s/2: =============  END LOG STATUS  =============\n",
+	       dev->name);
+	return 0;
+}
+
+static int vidioc_querymenu(struct file *file, void *priv,
+				struct v4l2_querymenu *a)
+{
+	struct cx23885_fh  *fh  = priv;
+	struct cx23885_dev *dev = fh->dev;
+
+	return cx23885_querymenu(dev, a);
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+				struct v4l2_queryctrl *c)
+{
+	struct cx23885_fh  *fh  = priv;
+	struct cx23885_dev *dev = fh->dev;
+
+	return cx23885_queryctrl(dev, c);
+}
+
+static int mpeg_open(struct file *file)
+{
+	struct cx23885_dev *dev = video_drvdata(file);
+	struct cx23885_fh *fh;
+
+	dprintk(2, "%s()\n", __func__);
+
+	/* allocate + initialize per filehandle data */
+	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+	if (!fh)
+		return -ENOMEM;
+
+	file->private_data = fh;
+	fh->dev      = dev;
+
+	videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops,
+			    &dev->pci->dev, &dev->ts1.slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			    V4L2_FIELD_INTERLACED,
+			    sizeof(struct cx23885_buffer),
+			    fh, NULL);
+	return 0;
+}
+
+static int mpeg_release(struct file *file)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	dprintk(2, "%s()\n", __func__);
+
+	/* FIXME: Review this crap */
+	/* Shut device down on last close */
+	if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
+		if (atomic_dec_return(&dev->v4l_reader_count) == 0) {
+			/* stop mpeg capture */
+			cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+				CX23885_END_NOW, CX23885_MPEG_CAPTURE,
+				CX23885_RAW_BITS_NONE);
+
+			msleep(500);
+			cx23885_417_check_encoder(dev);
+
+			cx23885_cancel_buffers(&fh->dev->ts1);
+		}
+	}
+
+	if (fh->mpegq.streaming)
+		videobuf_streamoff(&fh->mpegq);
+	if (fh->mpegq.reading)
+		videobuf_read_stop(&fh->mpegq);
+
+	videobuf_mmap_free(&fh->mpegq);
+	file->private_data = NULL;
+	kfree(fh);
+
+	return 0;
+}
+
+static ssize_t mpeg_read(struct file *file, char __user *data,
+	size_t count, loff_t *ppos)
+{
+	struct cx23885_fh *fh = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	dprintk(2, "%s()\n", __func__);
+
+	/* Deal w/ A/V decoder * and mpeg encoder sync issues. */
+	/* Start mpeg encoder on first read. */
+	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+		if (atomic_inc_return(&dev->v4l_reader_count) == 1) {
+			if (cx23885_initialize_codec(dev, 1) < 0)
+				return -EINVAL;
+		}
+	}
+
+	return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
+				    file->f_flags & O_NONBLOCK);
+}
+
+static unsigned int mpeg_poll(struct file *file,
+	struct poll_table_struct *wait)
+{
+	struct cx23885_fh *fh = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	dprintk(2, "%s\n", __func__);
+
+	return videobuf_poll_stream(file, &fh->mpegq, wait);
+}
+
+static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct cx23885_fh *fh = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	dprintk(2, "%s()\n", __func__);
+
+	return videobuf_mmap_mapper(&fh->mpegq, vma);
+}
+
+static struct v4l2_file_operations mpeg_fops = {
+	.owner	       = THIS_MODULE,
+	.open	       = mpeg_open,
+	.release       = mpeg_release,
+	.read	       = mpeg_read,
+	.poll          = mpeg_poll,
+	.mmap	       = mpeg_mmap,
+	.ioctl	       = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
+	.vidioc_querystd	 = vidioc_g_std,
+	.vidioc_g_std		 = vidioc_g_std,
+	.vidioc_s_std		 = vidioc_s_std,
+	.vidioc_enum_input	 = vidioc_enum_input,
+	.vidioc_g_input		 = vidioc_g_input,
+	.vidioc_s_input		 = vidioc_s_input,
+	.vidioc_g_tuner		 = vidioc_g_tuner,
+	.vidioc_s_tuner		 = vidioc_s_tuner,
+	.vidioc_g_frequency	 = vidioc_g_frequency,
+	.vidioc_s_frequency	 = vidioc_s_frequency,
+	.vidioc_s_ctrl		 = vidioc_s_ctrl,
+	.vidioc_g_ctrl		 = vidioc_g_ctrl,
+	.vidioc_querycap	 = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	 = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	 = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	 = vidioc_s_fmt_vid_cap,
+	.vidioc_reqbufs		 = vidioc_reqbufs,
+	.vidioc_querybuf	 = vidioc_querybuf,
+	.vidioc_qbuf		 = vidioc_qbuf,
+	.vidioc_dqbuf		 = vidioc_dqbuf,
+	.vidioc_streamon	 = vidioc_streamon,
+	.vidioc_streamoff	 = vidioc_streamoff,
+	.vidioc_g_ext_ctrls	 = vidioc_g_ext_ctrls,
+	.vidioc_s_ext_ctrls	 = vidioc_s_ext_ctrls,
+	.vidioc_try_ext_ctrls	 = vidioc_try_ext_ctrls,
+	.vidioc_log_status	 = vidioc_log_status,
+	.vidioc_querymenu	 = vidioc_querymenu,
+	.vidioc_queryctrl	 = vidioc_queryctrl,
+	.vidioc_g_chip_ident	 = cx23885_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register	 = cx23885_g_register,
+	.vidioc_s_register	 = cx23885_s_register,
+#endif
+};
+
+static struct video_device cx23885_mpeg_template = {
+	.name          = "cx23885",
+	.fops          = &mpeg_fops,
+	.ioctl_ops     = &mpeg_ioctl_ops,
+	.tvnorms       = CX23885_NORMS,
+	.current_norm  = V4L2_STD_NTSC_M,
+};
+
+void cx23885_417_unregister(struct cx23885_dev *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+
+	if (dev->v4l_device) {
+		if (video_is_registered(dev->v4l_device))
+			video_unregister_device(dev->v4l_device);
+		else
+			video_device_release(dev->v4l_device);
+		dev->v4l_device = NULL;
+	}
+}
+
+static struct video_device *cx23885_video_dev_alloc(
+	struct cx23885_tsport *tsport,
+	struct pci_dev *pci,
+	struct video_device *template,
+	char *type)
+{
+	struct video_device *vfd;
+	struct cx23885_dev *dev = tsport->dev;
+
+	dprintk(1, "%s()\n", __func__);
+
+	vfd = video_device_alloc();
+	if (NULL == vfd)
+		return NULL;
+	*vfd = *template;
+	snprintf(vfd->name, sizeof(vfd->name), "%s (%s)",
+		cx23885_boards[tsport->dev->board].name, type);
+	vfd->parent  = &pci->dev;
+	vfd->release = video_device_release;
+	return vfd;
+}
+
+int cx23885_417_register(struct cx23885_dev *dev)
+{
+	/* FIXME: Port1 hardcoded here */
+	int err = -ENODEV;
+	struct cx23885_tsport *tsport = &dev->ts1;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (cx23885_boards[dev->board].portb != CX23885_MPEG_ENCODER)
+		return err;
+
+	/* Set default TV standard */
+	dev->encodernorm = cx23885_tvnorms[0];
+
+	if (dev->encodernorm.id & V4L2_STD_525_60)
+		tsport->height = 480;
+	else
+		tsport->height = 576;
+
+	tsport->width = 720;
+	cx2341x_fill_defaults(&dev->mpeg_params);
+
+	dev->mpeg_params.port = CX2341X_PORT_SERIAL;
+
+	/* Allocate and initialize V4L video device */
+	dev->v4l_device = cx23885_video_dev_alloc(tsport,
+		dev->pci, &cx23885_mpeg_template, "mpeg");
+	video_set_drvdata(dev->v4l_device, dev);
+	err = video_register_device(dev->v4l_device,
+		VFL_TYPE_GRABBER, -1);
+	if (err < 0) {
+		printk(KERN_INFO "%s: can't register mpeg device\n", dev->name);
+		return err;
+	}
+
+	printk(KERN_INFO "%s: registered device %s [mpeg]\n",
+	       dev->name, video_device_node_name(dev->v4l_device));
+
+	/* ST: Configure the encoder paramaters, but don't begin
+	 * encoding, this resolves an issue where the first time the
+	 * encoder is started video can be choppy.
+	 */
+	cx23885_initialize_codec(dev, 0);
+
+	return 0;
+}
+
+MODULE_FIRMWARE(CX23885_FIRM_IMAGE_NAME);
diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c
new file mode 100644
index 0000000..7951692
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-alsa.c
@@ -0,0 +1,535 @@
+/*
+ *
+ *  Support for CX23885 analog audio capture
+ *
+ *    (c) 2008 Mijhail Moreyra <mijhail.moreyra@gmail.com>
+ *    Adapted from cx88-alsa.c
+ *    (c) 2009 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+
+#include <asm/delay.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+
+#include <sound/tlv.h>
+
+
+#include "cx23885.h"
+#include "cx23885-reg.h"
+
+#define AUDIO_SRAM_CHANNEL	SRAM_CH07
+
+#define dprintk(level, fmt, arg...)	if (audio_debug >= level) \
+	printk(KERN_INFO "%s: " fmt, chip->dev->name , ## arg)
+
+#define dprintk_core(level, fmt, arg...)	if (audio_debug >= level) \
+	printk(KERN_DEBUG "%s: " fmt, chip->dev->name , ## arg)
+
+/****************************************************************************
+			Module global static vars
+ ****************************************************************************/
+
+static unsigned int disable_analog_audio;
+module_param(disable_analog_audio, int, 0644);
+MODULE_PARM_DESC(disable_analog_audio, "disable analog audio ALSA driver");
+
+static unsigned int audio_debug;
+module_param(audio_debug, int, 0644);
+MODULE_PARM_DESC(audio_debug, "enable debug messages [analog audio]");
+
+/****************************************************************************
+			Board specific funtions
+ ****************************************************************************/
+
+/* Constants taken from cx88-reg.h */
+#define AUD_INT_DN_RISCI1       (1 <<  0)
+#define AUD_INT_UP_RISCI1       (1 <<  1)
+#define AUD_INT_RDS_DN_RISCI1   (1 <<  2)
+#define AUD_INT_DN_RISCI2       (1 <<  4) /* yes, 3 is skipped */
+#define AUD_INT_UP_RISCI2       (1 <<  5)
+#define AUD_INT_RDS_DN_RISCI2   (1 <<  6)
+#define AUD_INT_DN_SYNC         (1 << 12)
+#define AUD_INT_UP_SYNC         (1 << 13)
+#define AUD_INT_RDS_DN_SYNC     (1 << 14)
+#define AUD_INT_OPC_ERR         (1 << 16)
+#define AUD_INT_BER_IRQ         (1 << 20)
+#define AUD_INT_MCHG_IRQ        (1 << 21)
+#define GP_COUNT_CONTROL_RESET	0x3
+
+/*
+ * BOARD Specific: Sets audio DMA
+ */
+
+static int cx23885_start_audio_dma(struct cx23885_audio_dev *chip)
+{
+	struct cx23885_audio_buffer *buf = chip->buf;
+	struct cx23885_dev *dev  = chip->dev;
+	struct sram_channel *audio_ch =
+		&dev->sram_channels[AUDIO_SRAM_CHANNEL];
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* Make sure RISC/FIFO are off before changing FIFO/RISC settings */
+	cx_clear(AUD_INT_DMA_CTL, 0x11);
+
+	/* setup fifo + format - out channel */
+	cx23885_sram_channel_setup(chip->dev, audio_ch, buf->bpl,
+		buf->risc.dma);
+
+	/* sets bpl size */
+	cx_write(AUD_INT_A_LNGTH, buf->bpl);
+
+	/* This is required to get good audio (1 seems to be ok) */
+	cx_write(AUD_INT_A_MODE, 1);
+
+	/* reset counter */
+	cx_write(AUD_INT_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET);
+	atomic_set(&chip->count, 0);
+
+	dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d "
+		"byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start+12)>>1,
+		chip->num_periods, buf->bpl * chip->num_periods);
+
+	/* Enables corresponding bits at AUD_INT_STAT */
+	cx_write(AUDIO_INT_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+				    AUD_INT_DN_RISCI1);
+
+	/* Clean any pending interrupt bits already set */
+	cx_write(AUDIO_INT_INT_STAT, ~0);
+
+	/* enable audio irqs */
+	cx_set(PCI_INT_MSK, chip->dev->pci_irqmask | PCI_MSK_AUD_INT);
+
+	/* start dma */
+	cx_set(DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */
+	cx_set(AUD_INT_DMA_CTL, 0x11); /* audio downstream FIFO and
+					  RISC enable */
+	if (audio_debug)
+		cx23885_sram_channel_dump(chip->dev, audio_ch);
+
+	return 0;
+}
+
+/*
+ * BOARD Specific: Resets audio DMA
+ */
+static int cx23885_stop_audio_dma(struct cx23885_audio_dev *chip)
+{
+	struct cx23885_dev *dev = chip->dev;
+	dprintk(1, "Stopping audio DMA\n");
+
+	/* stop dma */
+	cx_clear(AUD_INT_DMA_CTL, 0x11);
+
+	/* disable irqs */
+	cx_clear(PCI_INT_MSK, PCI_MSK_AUD_INT);
+	cx_clear(AUDIO_INT_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+				    AUD_INT_DN_RISCI1);
+
+	if (audio_debug)
+		cx23885_sram_channel_dump(chip->dev,
+			&dev->sram_channels[AUDIO_SRAM_CHANNEL]);
+
+	return 0;
+}
+
+/*
+ * BOARD Specific: Handles audio IRQ
+ */
+int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask)
+{
+	struct cx23885_audio_dev *chip = dev->audio_dev;
+
+	if (0 == (status & mask))
+		return 0;
+
+	cx_write(AUDIO_INT_INT_STAT, status);
+
+	/* risc op code error */
+	if (status & AUD_INT_OPC_ERR) {
+		printk(KERN_WARNING "%s/1: Audio risc op code error\n",
+			dev->name);
+		cx_clear(AUD_INT_DMA_CTL, 0x11);
+		cx23885_sram_channel_dump(dev,
+			&dev->sram_channels[AUDIO_SRAM_CHANNEL]);
+	}
+	if (status & AUD_INT_DN_SYNC) {
+		dprintk(1, "Downstream sync error\n");
+		cx_write(AUD_INT_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET);
+		return 1;
+	}
+	/* risc1 downstream */
+	if (status & AUD_INT_DN_RISCI1) {
+		atomic_set(&chip->count, cx_read(AUD_INT_A_GPCNT));
+		snd_pcm_period_elapsed(chip->substream);
+	}
+	/* FIXME: Any other status should deserve a special handling? */
+
+	return 1;
+}
+
+static int dsp_buffer_free(struct cx23885_audio_dev *chip)
+{
+	BUG_ON(!chip->dma_size);
+
+	dprintk(2, "Freeing buffer\n");
+	videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc);
+	videobuf_dma_free(chip->dma_risc);
+	btcx_riscmem_free(chip->pci, &chip->buf->risc);
+	kfree(chip->buf);
+
+	chip->dma_risc = NULL;
+	chip->dma_size = 0;
+
+	return 0;
+}
+
+/****************************************************************************
+				ALSA PCM Interface
+ ****************************************************************************/
+
+/*
+ * Digital hardware definition
+ */
+#define DEFAULT_FIFO_SIZE	4096
+
+static struct snd_pcm_hardware snd_cx23885_digital_hw = {
+	.info = SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		SNDRV_PCM_INFO_MMAP_VALID,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+	.rates =		SNDRV_PCM_RATE_48000,
+	.rate_min =		48000,
+	.rate_max =		48000,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* Analog audio output will be full of clicks and pops if there
+	   are not exactly four lines in the SRAM FIFO buffer.  */
+	.period_bytes_min = DEFAULT_FIFO_SIZE/4,
+	.period_bytes_max = DEFAULT_FIFO_SIZE/4,
+	.periods_min = 1,
+	.periods_max = 1024,
+	.buffer_bytes_max = (1024*1024),
+};
+
+/*
+ * audio pcm capture open callback
+ */
+static int snd_cx23885_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int err;
+
+	if (!chip) {
+		printk(KERN_ERR "BUG: cx23885 can't find device struct."
+				" Can't proceed with open\n");
+		return -ENODEV;
+	}
+
+	err = snd_pcm_hw_constraint_pow2(runtime, 0,
+		SNDRV_PCM_HW_PARAM_PERIODS);
+	if (err < 0)
+		goto _error;
+
+	chip->substream = substream;
+
+	runtime->hw = snd_cx23885_digital_hw;
+
+	if (chip->dev->sram_channels[AUDIO_SRAM_CHANNEL].fifo_size !=
+		DEFAULT_FIFO_SIZE) {
+		unsigned int bpl = chip->dev->
+			sram_channels[AUDIO_SRAM_CHANNEL].fifo_size / 4;
+		bpl &= ~7; /* must be multiple of 8 */
+		runtime->hw.period_bytes_min = bpl;
+		runtime->hw.period_bytes_max = bpl;
+	}
+
+	return 0;
+_error:
+	dprintk(1, "Error opening PCM!\n");
+	return err;
+}
+
+/*
+ * audio close callback
+ */
+static int snd_cx23885_close(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+/*
+ * hw_params callback
+ */
+static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *hw_params)
+{
+	struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);
+	struct videobuf_dmabuf *dma;
+
+	struct cx23885_audio_buffer *buf;
+	int ret;
+
+	if (substream->runtime->dma_area) {
+		dsp_buffer_free(chip);
+		substream->runtime->dma_area = NULL;
+	}
+
+	chip->period_size = params_period_bytes(hw_params);
+	chip->num_periods = params_periods(hw_params);
+	chip->dma_size = chip->period_size * params_periods(hw_params);
+
+	BUG_ON(!chip->dma_size);
+	BUG_ON(chip->num_periods & (chip->num_periods-1));
+
+	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+	if (NULL == buf)
+		return -ENOMEM;
+
+	buf->bpl = chip->period_size;
+
+	dma = &buf->dma;
+	videobuf_dma_init(dma);
+	ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
+			(PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
+	if (ret < 0)
+		goto error;
+
+	ret = videobuf_dma_map(&chip->pci->dev, dma);
+	if (ret < 0)
+		goto error;
+
+	ret = cx23885_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
+				   chip->period_size, chip->num_periods, 1);
+	if (ret < 0)
+		goto error;
+
+	/* Loop back to start of program */
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
+	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
+
+	chip->buf = buf;
+	chip->dma_risc = dma;
+
+	substream->runtime->dma_area = chip->dma_risc->vaddr;
+	substream->runtime->dma_bytes = chip->dma_size;
+	substream->runtime->dma_addr = 0;
+
+	return 0;
+
+error:
+	kfree(buf);
+	return ret;
+}
+
+/*
+ * hw free callback
+ */
+static int snd_cx23885_hw_free(struct snd_pcm_substream *substream)
+{
+
+	struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);
+
+	if (substream->runtime->dma_area) {
+		dsp_buffer_free(chip);
+		substream->runtime->dma_area = NULL;
+	}
+
+	return 0;
+}
+
+/*
+ * prepare callback
+ */
+static int snd_cx23885_prepare(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+/*
+ * trigger callback
+ */
+static int snd_cx23885_card_trigger(struct snd_pcm_substream *substream,
+	int cmd)
+{
+	struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);
+	int err;
+
+	/* Local interrupts are already disabled by ALSA */
+	spin_lock(&chip->lock);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		err = cx23885_start_audio_dma(chip);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		err = cx23885_stop_audio_dma(chip);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	spin_unlock(&chip->lock);
+
+	return err;
+}
+
+/*
+ * pointer callback
+ */
+static snd_pcm_uframes_t snd_cx23885_pointer(
+	struct snd_pcm_substream *substream)
+{
+	struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	u16 count;
+
+	count = atomic_read(&chip->count);
+
+	return runtime->period_size * (count & (runtime->periods-1));
+}
+
+/*
+ * page callback (needed for mmap)
+ */
+static struct page *snd_cx23885_page(struct snd_pcm_substream *substream,
+				unsigned long offset)
+{
+	void *pageptr = substream->runtime->dma_area + offset;
+	return vmalloc_to_page(pageptr);
+}
+
+/*
+ * operators
+ */
+static struct snd_pcm_ops snd_cx23885_pcm_ops = {
+	.open = snd_cx23885_pcm_open,
+	.close = snd_cx23885_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_cx23885_hw_params,
+	.hw_free = snd_cx23885_hw_free,
+	.prepare = snd_cx23885_prepare,
+	.trigger = snd_cx23885_card_trigger,
+	.pointer = snd_cx23885_pointer,
+	.page = snd_cx23885_page,
+};
+
+/*
+ * create a PCM device
+ */
+static int snd_cx23885_pcm(struct cx23885_audio_dev *chip, int device,
+	char *name)
+{
+	int err;
+	struct snd_pcm *pcm;
+
+	err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
+	if (err < 0)
+		return err;
+	pcm->private_data = chip;
+	strcpy(pcm->name, name);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx23885_pcm_ops);
+
+	return 0;
+}
+
+/****************************************************************************
+			Basic Flow for Sound Devices
+ ****************************************************************************/
+
+/*
+ * Alsa Constructor - Component probe
+ */
+
+struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev)
+{
+	struct snd_card *card;
+	struct cx23885_audio_dev *chip;
+	int err;
+
+	if (disable_analog_audio)
+		return NULL;
+
+	if (dev->sram_channels[AUDIO_SRAM_CHANNEL].cmds_start == 0) {
+		printk(KERN_WARNING "%s(): Missing SRAM channel configuration "
+			"for analog TV Audio\n", __func__);
+		return NULL;
+	}
+
+	err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+			THIS_MODULE, sizeof(struct cx23885_audio_dev), &card);
+	if (err < 0)
+		goto error;
+
+	chip = (struct cx23885_audio_dev *) card->private_data;
+	chip->dev = dev;
+	chip->pci = dev->pci;
+	chip->card = card;
+	spin_lock_init(&chip->lock);
+
+	snd_card_set_dev(card, &dev->pci->dev);
+
+	err = snd_cx23885_pcm(chip, 0, "CX23885 Digital");
+	if (err < 0)
+		goto error;
+
+	strcpy(card->driver, "CX23885");
+	sprintf(card->shortname, "Conexant CX23885");
+	sprintf(card->longname, "%s at %s", card->shortname, dev->name);
+
+	err = snd_card_register(card);
+	if (err < 0)
+		goto error;
+
+	dprintk(0, "registered ALSA audio device\n");
+
+	return chip;
+
+error:
+	snd_card_free(card);
+	printk(KERN_ERR "%s(): Failed to register analog "
+			"audio adapter\n", __func__);
+
+	return NULL;
+}
+
+/*
+ * ALSA destructor
+ */
+void cx23885_audio_unregister(struct cx23885_dev *dev)
+{
+	struct cx23885_audio_dev *chip = dev->audio_dev;
+
+	snd_card_free(chip->card);
+}
diff --git a/drivers/media/pci/cx23885/cx23885-av.c b/drivers/media/pci/cx23885/cx23885-av.c
new file mode 100644
index 0000000..134ebdd
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-av.c
@@ -0,0 +1,35 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  AV device support routines - non-input, non-vl42_subdev routines
+ *
+ *  Copyright (C) 2010  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#include "cx23885.h"
+
+void cx23885_av_work_handler(struct work_struct *work)
+{
+	struct cx23885_dev *dev =
+			   container_of(work, struct cx23885_dev, cx25840_work);
+	bool handled;
+
+	v4l2_subdev_call(dev->sd_cx25840, core, interrupt_service_routine,
+			 PCI_MSK_AV_CORE, &handled);
+	cx23885_irq_enable(dev, PCI_MSK_AV_CORE);
+}
diff --git a/drivers/media/pci/cx23885/cx23885-av.h b/drivers/media/pci/cx23885/cx23885-av.h
new file mode 100644
index 0000000..d2915c3
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-av.h
@@ -0,0 +1,27 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  AV device support routines - non-input, non-vl42_subdev routines
+ *
+ *  Copyright (C) 2010  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#ifndef _CX23885_AV_H_
+#define _CX23885_AV_H_
+void cx23885_av_work_handler(struct work_struct *work);
+#endif
diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c
new file mode 100644
index 0000000..d889bd2
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-cards.c
@@ -0,0 +1,1684 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <media/cx25840.h>
+#include <linux/firmware.h>
+#include <misc/altera.h>
+
+#include "cx23885.h"
+#include "tuner-xc2028.h"
+#include "netup-eeprom.h"
+#include "netup-init.h"
+#include "altera-ci.h"
+#include "xc4000.h"
+#include "xc5000.h"
+#include "cx23888-ir.h"
+
+static unsigned int netup_card_rev = 4;
+module_param(netup_card_rev, int, 0644);
+MODULE_PARM_DESC(netup_card_rev,
+		"NetUP Dual DVB-T/C CI card revision");
+static unsigned int enable_885_ir;
+module_param(enable_885_ir, int, 0644);
+MODULE_PARM_DESC(enable_885_ir,
+		 "Enable integrated IR controller for supported\n"
+		 "\t\t    CX2388[57] boards that are wired for it:\n"
+		 "\t\t\tHVR-1250 (reported safe)\n"
+		 "\t\t\tTerraTec Cinergy T PCIe Dual (not well tested, appears to be safe)\n"
+		 "\t\t\tTeVii S470 (reported unsafe)\n"
+		 "\t\t    This can cause an interrupt storm with some cards.\n"
+		 "\t\t    Default: 0 [Disabled]");
+
+/* ------------------------------------------------------------------ */
+/* board config info                                                  */
+
+struct cx23885_board cx23885_boards[] = {
+	[CX23885_BOARD_UNKNOWN] = {
+		.name		= "UNKNOWN/GENERIC",
+		/* Ensure safe default for unknown boards */
+		.clk_freq       = 0,
+		.input          = {{
+			.type   = CX23885_VMUX_COMPOSITE1,
+			.vmux   = 0,
+		}, {
+			.type   = CX23885_VMUX_COMPOSITE2,
+			.vmux   = 1,
+		}, {
+			.type   = CX23885_VMUX_COMPOSITE3,
+			.vmux   = 2,
+		}, {
+			.type   = CX23885_VMUX_COMPOSITE4,
+			.vmux   = 3,
+		} },
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1800lp] = {
+		.name		= "Hauppauge WinTV-HVR1800lp",
+		.portc		= CX23885_MPEG_DVB,
+		.input          = {{
+			.type   = CX23885_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0xff00,
+		}, {
+			.type   = CX23885_VMUX_DEBUG,
+			.vmux   = 0,
+			.gpio0  = 0xff01,
+		}, {
+			.type   = CX23885_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0xff02,
+		}, {
+			.type   = CX23885_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0xff02,
+		} },
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1800] = {
+		.name		= "Hauppauge WinTV-HVR1800",
+		.porta		= CX23885_ANALOG_VIDEO,
+		.portb		= CX23885_MPEG_ENCODER,
+		.portc		= CX23885_MPEG_DVB,
+		.tuner_type	= TUNER_PHILIPS_TDA8290,
+		.tuner_addr	= 0x42, /* 0x84 >> 1 */
+		.tuner_bus	= 1,
+		.input          = {{
+			.type   = CX23885_VMUX_TELEVISION,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN5_CH2 |
+					CX25840_VIN2_CH1,
+			.amux   = CX25840_AUDIO8,
+			.gpio0  = 0,
+		}, {
+			.type   = CX23885_VMUX_COMPOSITE1,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN4_CH2 |
+					CX25840_VIN6_CH1,
+			.amux   = CX25840_AUDIO7,
+			.gpio0  = 0,
+		}, {
+			.type   = CX23885_VMUX_SVIDEO,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN4_CH2 |
+					CX25840_VIN8_CH1 |
+					CX25840_SVIDEO_ON,
+			.amux   = CX25840_AUDIO7,
+			.gpio0  = 0,
+		} },
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1250] = {
+		.name		= "Hauppauge WinTV-HVR1250",
+		.porta		= CX23885_ANALOG_VIDEO,
+		.portc		= CX23885_MPEG_DVB,
+#ifdef MT2131_NO_ANALOG_SUPPORT_YET
+		.tuner_type	= TUNER_PHILIPS_TDA8290,
+		.tuner_addr	= 0x42, /* 0x84 >> 1 */
+		.tuner_bus	= 1,
+#endif
+		.force_bff	= 1,
+		.input          = {{
+#ifdef MT2131_NO_ANALOG_SUPPORT_YET
+			.type   = CX23885_VMUX_TELEVISION,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN5_CH2 |
+					CX25840_VIN2_CH1,
+			.amux   = CX25840_AUDIO8,
+			.gpio0  = 0xff00,
+		}, {
+#endif
+			.type   = CX23885_VMUX_COMPOSITE1,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN4_CH2 |
+					CX25840_VIN6_CH1,
+			.amux   = CX25840_AUDIO7,
+			.gpio0  = 0xff02,
+		}, {
+			.type   = CX23885_VMUX_SVIDEO,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN4_CH2 |
+					CX25840_VIN8_CH1 |
+					CX25840_SVIDEO_ON,
+			.amux   = CX25840_AUDIO7,
+			.gpio0  = 0xff02,
+		} },
+	},
+	[CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = {
+		.name		= "DViCO FusionHDTV5 Express",
+		.portb		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1500Q] = {
+		.name		= "Hauppauge WinTV-HVR1500Q",
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1500] = {
+		.name		= "Hauppauge WinTV-HVR1500",
+		.porta		= CX23885_ANALOG_VIDEO,
+		.portc		= CX23885_MPEG_DVB,
+		.tuner_type	= TUNER_XC2028,
+		.tuner_addr	= 0x61, /* 0xc2 >> 1 */
+		.input          = {{
+			.type   = CX23885_VMUX_TELEVISION,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN5_CH2 |
+					CX25840_VIN2_CH1,
+			.gpio0  = 0,
+		}, {
+			.type   = CX23885_VMUX_COMPOSITE1,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN4_CH2 |
+					CX25840_VIN6_CH1,
+			.gpio0  = 0,
+		}, {
+			.type   = CX23885_VMUX_SVIDEO,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN4_CH2 |
+					CX25840_VIN8_CH1 |
+					CX25840_SVIDEO_ON,
+			.gpio0  = 0,
+		} },
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1200] = {
+		.name		= "Hauppauge WinTV-HVR1200",
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1700] = {
+		.name		= "Hauppauge WinTV-HVR1700",
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1400] = {
+		.name		= "Hauppauge WinTV-HVR1400",
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP] = {
+		.name		= "DViCO FusionHDTV7 Dual Express",
+		.portb		= CX23885_MPEG_DVB,
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP] = {
+		.name		= "DViCO FusionHDTV DVB-T Dual Express",
+		.portb		= CX23885_MPEG_DVB,
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H] = {
+		.name		= "Leadtek Winfast PxDVR3200 H",
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000] = {
+		.name		= "Leadtek Winfast PxDVR3200 H XC4000",
+		.porta		= CX23885_ANALOG_VIDEO,
+		.portc		= CX23885_MPEG_DVB,
+		.tuner_type	= TUNER_XC4000,
+		.tuner_addr	= 0x61,
+		.radio_type	= UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input		= {{
+			.type	= CX23885_VMUX_TELEVISION,
+			.vmux	= CX25840_VIN2_CH1 |
+				  CX25840_VIN5_CH2 |
+				  CX25840_NONE0_CH3,
+		}, {
+			.type	= CX23885_VMUX_COMPOSITE1,
+			.vmux	= CX25840_COMPOSITE1,
+		}, {
+			.type	= CX23885_VMUX_SVIDEO,
+			.vmux	= CX25840_SVIDEO_LUMA3 |
+				  CX25840_SVIDEO_CHROMA4,
+		}, {
+			.type	= CX23885_VMUX_COMPONENT,
+			.vmux	= CX25840_VIN7_CH1 |
+				  CX25840_VIN6_CH2 |
+				  CX25840_VIN8_CH3 |
+				  CX25840_COMPONENT_ON,
+		} },
+	},
+	[CX23885_BOARD_COMPRO_VIDEOMATE_E650F] = {
+		.name		= "Compro VideoMate E650F",
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_TBS_6920] = {
+		.name		= "TurboSight TBS 6920",
+		.portb		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_TEVII_S470] = {
+		.name		= "TeVii S470",
+		.portb		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_DVBWORLD_2005] = {
+		.name		= "DVBWorld DVB-S2 2005",
+		.portb		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_NETUP_DUAL_DVBS2_CI] = {
+		.ci_type	= 1,
+		.name		= "NetUP Dual DVB-S2 CI",
+		.portb		= CX23885_MPEG_DVB,
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1270] = {
+		.name		= "Hauppauge WinTV-HVR1270",
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1275] = {
+		.name		= "Hauppauge WinTV-HVR1275",
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1255] = {
+		.name		= "Hauppauge WinTV-HVR1255",
+		.porta		= CX23885_ANALOG_VIDEO,
+		.portc		= CX23885_MPEG_DVB,
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= 0x42, /* 0x84 >> 1 */
+		.force_bff	= 1,
+		.input          = {{
+			.type   = CX23885_VMUX_TELEVISION,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN5_CH2 |
+					CX25840_VIN2_CH1 |
+					CX25840_DIF_ON,
+			.amux   = CX25840_AUDIO8,
+		}, {
+			.type   = CX23885_VMUX_COMPOSITE1,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN4_CH2 |
+					CX25840_VIN6_CH1,
+			.amux   = CX25840_AUDIO7,
+		}, {
+			.type   = CX23885_VMUX_SVIDEO,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN4_CH2 |
+					CX25840_VIN8_CH1 |
+					CX25840_SVIDEO_ON,
+			.amux   = CX25840_AUDIO7,
+		} },
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1255_22111] = {
+		.name		= "Hauppauge WinTV-HVR1255",
+		.porta		= CX23885_ANALOG_VIDEO,
+		.portc		= CX23885_MPEG_DVB,
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= 0x42, /* 0x84 >> 1 */
+		.force_bff	= 1,
+		.input          = {{
+			.type   = CX23885_VMUX_TELEVISION,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN5_CH2 |
+					CX25840_VIN2_CH1 |
+					CX25840_DIF_ON,
+			.amux   = CX25840_AUDIO8,
+		}, {
+			.type   = CX23885_VMUX_SVIDEO,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN4_CH2 |
+					CX25840_VIN8_CH1 |
+					CX25840_SVIDEO_ON,
+			.amux   = CX25840_AUDIO7,
+		} },
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1210] = {
+		.name		= "Hauppauge WinTV-HVR1210",
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_MYGICA_X8506] = {
+		.name		= "Mygica X8506 DMB-TH",
+		.tuner_type = TUNER_XC5000,
+		.tuner_addr = 0x61,
+		.tuner_bus	= 1,
+		.porta		= CX23885_ANALOG_VIDEO,
+		.portb		= CX23885_MPEG_DVB,
+		.input		= {
+			{
+				.type   = CX23885_VMUX_TELEVISION,
+				.vmux   = CX25840_COMPOSITE2,
+			},
+			{
+				.type   = CX23885_VMUX_COMPOSITE1,
+				.vmux   = CX25840_COMPOSITE8,
+			},
+			{
+				.type   = CX23885_VMUX_SVIDEO,
+				.vmux   = CX25840_SVIDEO_LUMA3 |
+						CX25840_SVIDEO_CHROMA4,
+			},
+			{
+				.type   = CX23885_VMUX_COMPONENT,
+				.vmux   = CX25840_COMPONENT_ON |
+					CX25840_VIN1_CH1 |
+					CX25840_VIN6_CH2 |
+					CX25840_VIN7_CH3,
+			},
+		},
+	},
+	[CX23885_BOARD_MAGICPRO_PROHDTVE2] = {
+		.name		= "Magic-Pro ProHDTV Extreme 2",
+		.tuner_type = TUNER_XC5000,
+		.tuner_addr = 0x61,
+		.tuner_bus	= 1,
+		.porta		= CX23885_ANALOG_VIDEO,
+		.portb		= CX23885_MPEG_DVB,
+		.input		= {
+			{
+				.type   = CX23885_VMUX_TELEVISION,
+				.vmux   = CX25840_COMPOSITE2,
+			},
+			{
+				.type   = CX23885_VMUX_COMPOSITE1,
+				.vmux   = CX25840_COMPOSITE8,
+			},
+			{
+				.type   = CX23885_VMUX_SVIDEO,
+				.vmux   = CX25840_SVIDEO_LUMA3 |
+						CX25840_SVIDEO_CHROMA4,
+			},
+			{
+				.type   = CX23885_VMUX_COMPONENT,
+				.vmux   = CX25840_COMPONENT_ON |
+					CX25840_VIN1_CH1 |
+					CX25840_VIN6_CH2 |
+					CX25840_VIN7_CH3,
+			},
+		},
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1850] = {
+		.name		= "Hauppauge WinTV-HVR1850",
+		.porta		= CX23885_ANALOG_VIDEO,
+		.portb		= CX23885_MPEG_ENCODER,
+		.portc		= CX23885_MPEG_DVB,
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= 0x42, /* 0x84 >> 1 */
+		.force_bff	= 1,
+		.input          = {{
+			.type   = CX23885_VMUX_TELEVISION,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN5_CH2 |
+					CX25840_VIN2_CH1 |
+					CX25840_DIF_ON,
+			.amux   = CX25840_AUDIO8,
+		}, {
+			.type   = CX23885_VMUX_COMPOSITE1,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN4_CH2 |
+					CX25840_VIN6_CH1,
+			.amux   = CX25840_AUDIO7,
+		}, {
+			.type   = CX23885_VMUX_SVIDEO,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN4_CH2 |
+					CX25840_VIN8_CH1 |
+					CX25840_SVIDEO_ON,
+			.amux   = CX25840_AUDIO7,
+		} },
+	},
+	[CX23885_BOARD_COMPRO_VIDEOMATE_E800] = {
+		.name		= "Compro VideoMate E800",
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1290] = {
+		.name		= "Hauppauge WinTV-HVR1290",
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_MYGICA_X8558PRO] = {
+		.name		= "Mygica X8558 PRO DMB-TH",
+		.portb		= CX23885_MPEG_DVB,
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_LEADTEK_WINFAST_PXTV1200] = {
+		.name           = "LEADTEK WinFast PxTV1200",
+		.porta          = CX23885_ANALOG_VIDEO,
+		.tuner_type     = TUNER_XC2028,
+		.tuner_addr     = 0x61,
+		.tuner_bus	= 1,
+		.input          = {{
+			.type   = CX23885_VMUX_TELEVISION,
+			.vmux   = CX25840_VIN2_CH1 |
+				  CX25840_VIN5_CH2 |
+				  CX25840_NONE0_CH3,
+		}, {
+			.type   = CX23885_VMUX_COMPOSITE1,
+			.vmux   = CX25840_COMPOSITE1,
+		}, {
+			.type   = CX23885_VMUX_SVIDEO,
+			.vmux   = CX25840_SVIDEO_LUMA3 |
+				  CX25840_SVIDEO_CHROMA4,
+		}, {
+			.type   = CX23885_VMUX_COMPONENT,
+			.vmux   = CX25840_VIN7_CH1 |
+				  CX25840_VIN6_CH2 |
+				  CX25840_VIN8_CH3 |
+				  CX25840_COMPONENT_ON,
+		} },
+	},
+	[CX23885_BOARD_GOTVIEW_X5_3D_HYBRID] = {
+		.name		= "GoTView X5 3D Hybrid",
+		.tuner_type	= TUNER_XC5000,
+		.tuner_addr	= 0x64,
+		.tuner_bus	= 1,
+		.porta		= CX23885_ANALOG_VIDEO,
+		.portb		= CX23885_MPEG_DVB,
+		.input          = {{
+			.type   = CX23885_VMUX_TELEVISION,
+			.vmux   = CX25840_VIN2_CH1 |
+				  CX25840_VIN5_CH2,
+			.gpio0	= 0x02,
+		}, {
+			.type   = CX23885_VMUX_COMPOSITE1,
+			.vmux   = CX23885_VMUX_COMPOSITE1,
+		}, {
+			.type   = CX23885_VMUX_SVIDEO,
+			.vmux   = CX25840_SVIDEO_LUMA3 |
+				  CX25840_SVIDEO_CHROMA4,
+		} },
+	},
+	[CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF] = {
+		.ci_type	= 2,
+		.name		= "NetUP Dual DVB-T/C-CI RF",
+		.porta		= CX23885_ANALOG_VIDEO,
+		.portb		= CX23885_MPEG_DVB,
+		.portc		= CX23885_MPEG_DVB,
+		.num_fds_portb	= 2,
+		.num_fds_portc	= 2,
+		.tuner_type	= TUNER_XC5000,
+		.tuner_addr	= 0x64,
+		.input          = { {
+				.type   = CX23885_VMUX_TELEVISION,
+				.vmux   = CX25840_COMPOSITE1,
+		} },
+	},
+	[CX23885_BOARD_MPX885] = {
+		.name		= "MPX-885",
+		.porta		= CX23885_ANALOG_VIDEO,
+		.input          = {{
+			.type   = CX23885_VMUX_COMPOSITE1,
+			.vmux   = CX25840_COMPOSITE1,
+			.amux   = CX25840_AUDIO6,
+			.gpio0  = 0,
+		}, {
+			.type   = CX23885_VMUX_COMPOSITE2,
+			.vmux   = CX25840_COMPOSITE2,
+			.amux   = CX25840_AUDIO6,
+			.gpio0  = 0,
+		}, {
+			.type   = CX23885_VMUX_COMPOSITE3,
+			.vmux   = CX25840_COMPOSITE3,
+			.amux   = CX25840_AUDIO7,
+			.gpio0  = 0,
+		}, {
+			.type   = CX23885_VMUX_COMPOSITE4,
+			.vmux   = CX25840_COMPOSITE4,
+			.amux   = CX25840_AUDIO7,
+			.gpio0  = 0,
+		} },
+	},
+	[CX23885_BOARD_MYGICA_X8507] = {
+		.name		= "Mygica X8507",
+		.tuner_type = TUNER_XC5000,
+		.tuner_addr = 0x61,
+		.tuner_bus	= 1,
+		.porta		= CX23885_ANALOG_VIDEO,
+		.input		= {
+			{
+				.type   = CX23885_VMUX_TELEVISION,
+				.vmux   = CX25840_COMPOSITE2,
+				.amux   = CX25840_AUDIO8,
+			},
+			{
+				.type   = CX23885_VMUX_COMPOSITE1,
+				.vmux   = CX25840_COMPOSITE8,
+			},
+			{
+				.type   = CX23885_VMUX_SVIDEO,
+				.vmux   = CX25840_SVIDEO_LUMA3 |
+						CX25840_SVIDEO_CHROMA4,
+			},
+			{
+				.type   = CX23885_VMUX_COMPONENT,
+				.vmux   = CX25840_COMPONENT_ON |
+					CX25840_VIN1_CH1 |
+					CX25840_VIN6_CH2 |
+					CX25840_VIN7_CH3,
+			},
+		},
+	},
+	[CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL] = {
+		.name		= "TerraTec Cinergy T PCIe Dual",
+		.portb		= CX23885_MPEG_DVB,
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_TEVII_S471] = {
+		.name		= "TeVii S471",
+		.portb		= CX23885_MPEG_DVB,
+	}
+};
+const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
+
+/* ------------------------------------------------------------------ */
+/* PCI subsystem IDs                                                  */
+
+struct cx23885_subid cx23885_subids[] = {
+	{
+		.subvendor = 0x0070,
+		.subdevice = 0x3400,
+		.card      = CX23885_BOARD_UNKNOWN,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x7600,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1800lp,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x7800,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1800,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x7801,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1800,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x7809,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1800,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x7911,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1250,
+	}, {
+		.subvendor = 0x18ac,
+		.subdevice = 0xd500,
+		.card      = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x7790,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x7797,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x7710,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1500,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x7717,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1500,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x71d1,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1200,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x71d3,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1200,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x8101,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1700,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x8010,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1400,
+	}, {
+		.subvendor = 0x18ac,
+		.subdevice = 0xd618,
+		.card      = CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP,
+	}, {
+		.subvendor = 0x18ac,
+		.subdevice = 0xdb78,
+		.card      = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP,
+	}, {
+		.subvendor = 0x107d,
+		.subdevice = 0x6681,
+		.card      = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H,
+	}, {
+		.subvendor = 0x107d,
+		.subdevice = 0x6f39,
+		.card	   = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000,
+	}, {
+		.subvendor = 0x185b,
+		.subdevice = 0xe800,
+		.card      = CX23885_BOARD_COMPRO_VIDEOMATE_E650F,
+	}, {
+		.subvendor = 0x6920,
+		.subdevice = 0x8888,
+		.card      = CX23885_BOARD_TBS_6920,
+	}, {
+		.subvendor = 0xd470,
+		.subdevice = 0x9022,
+		.card      = CX23885_BOARD_TEVII_S470,
+	}, {
+		.subvendor = 0x0001,
+		.subdevice = 0x2005,
+		.card      = CX23885_BOARD_DVBWORLD_2005,
+	}, {
+		.subvendor = 0x1b55,
+		.subdevice = 0x2a2c,
+		.card      = CX23885_BOARD_NETUP_DUAL_DVBS2_CI,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x2211,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1270,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x2215,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1275,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x221d,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1275,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x2251,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1255,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x2259,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1255_22111,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x2291,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x2295,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x2299,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x229d,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x22f0,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x22f1,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1255,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x22f2,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1275,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x22f3,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x22f4,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x22f5,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
+	}, {
+		.subvendor = 0x14f1,
+		.subdevice = 0x8651,
+		.card      = CX23885_BOARD_MYGICA_X8506,
+	}, {
+		.subvendor = 0x14f1,
+		.subdevice = 0x8657,
+		.card      = CX23885_BOARD_MAGICPRO_PROHDTVE2,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x8541,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1850,
+	}, {
+		.subvendor = 0x1858,
+		.subdevice = 0xe800,
+		.card      = CX23885_BOARD_COMPRO_VIDEOMATE_E800,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x8551,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1290,
+	}, {
+		.subvendor = 0x14f1,
+		.subdevice = 0x8578,
+		.card      = CX23885_BOARD_MYGICA_X8558PRO,
+	}, {
+		.subvendor = 0x107d,
+		.subdevice = 0x6f22,
+		.card      = CX23885_BOARD_LEADTEK_WINFAST_PXTV1200,
+	}, {
+		.subvendor = 0x5654,
+		.subdevice = 0x2390,
+		.card      = CX23885_BOARD_GOTVIEW_X5_3D_HYBRID,
+	}, {
+		.subvendor = 0x1b55,
+		.subdevice = 0xe2e4,
+		.card      = CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF,
+	}, {
+		.subvendor = 0x14f1,
+		.subdevice = 0x8502,
+		.card      = CX23885_BOARD_MYGICA_X8507,
+	}, {
+		.subvendor = 0x153b,
+		.subdevice = 0x117e,
+		.card      = CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL,
+	}, {
+		.subvendor = 0xd471,
+		.subdevice = 0x9022,
+		.card      = CX23885_BOARD_TEVII_S471,
+	},
+};
+const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
+
+void cx23885_card_list(struct cx23885_dev *dev)
+{
+	int i;
+
+	if (0 == dev->pci->subsystem_vendor &&
+	    0 == dev->pci->subsystem_device) {
+		printk(KERN_INFO
+			"%s: Board has no valid PCIe Subsystem ID and can't\n"
+		       "%s: be autodetected. Pass card=<n> insmod option\n"
+		       "%s: to workaround that. Redirect complaints to the\n"
+		       "%s: vendor of the TV card.  Best regards,\n"
+		       "%s:         -- tux\n",
+		       dev->name, dev->name, dev->name, dev->name, dev->name);
+	} else {
+		printk(KERN_INFO
+			"%s: Your board isn't known (yet) to the driver.\n"
+		       "%s: Try to pick one of the existing card configs via\n"
+		       "%s: card=<n> insmod option.  Updating to the latest\n"
+		       "%s: version might help as well.\n",
+		       dev->name, dev->name, dev->name, dev->name);
+	}
+	printk(KERN_INFO "%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+	       dev->name);
+	for (i = 0; i < cx23885_bcount; i++)
+		printk(KERN_INFO "%s:    card=%d -> %s\n",
+		       dev->name, i, cx23885_boards[i].name);
+}
+
+static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
+{
+	struct tveeprom tv;
+
+	tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv,
+		eeprom_data);
+
+	/* Make sure we support the board model */
+	switch (tv.model) {
+	case 22001:
+		/* WinTV-HVR1270 (PCIe, Retail, half height)
+		 * ATSC/QAM and basic analog, IR Blast */
+	case 22009:
+		/* WinTV-HVR1210 (PCIe, Retail, half height)
+		 * DVB-T and basic analog, IR Blast */
+	case 22011:
+		/* WinTV-HVR1270 (PCIe, Retail, half height)
+		 * ATSC/QAM and basic analog, IR Recv */
+	case 22019:
+		/* WinTV-HVR1210 (PCIe, Retail, half height)
+		 * DVB-T and basic analog, IR Recv */
+	case 22021:
+		/* WinTV-HVR1275 (PCIe, Retail, half height)
+		 * ATSC/QAM and basic analog, IR Recv */
+	case 22029:
+		/* WinTV-HVR1210 (PCIe, Retail, half height)
+		 * DVB-T and basic analog, IR Recv */
+	case 22101:
+		/* WinTV-HVR1270 (PCIe, Retail, full height)
+		 * ATSC/QAM and basic analog, IR Blast */
+	case 22109:
+		/* WinTV-HVR1210 (PCIe, Retail, full height)
+		 * DVB-T and basic analog, IR Blast */
+	case 22111:
+		/* WinTV-HVR1270 (PCIe, Retail, full height)
+		 * ATSC/QAM and basic analog, IR Recv */
+	case 22119:
+		/* WinTV-HVR1210 (PCIe, Retail, full height)
+		 * DVB-T and basic analog, IR Recv */
+	case 22121:
+		/* WinTV-HVR1275 (PCIe, Retail, full height)
+		 * ATSC/QAM and basic analog, IR Recv */
+	case 22129:
+		/* WinTV-HVR1210 (PCIe, Retail, full height)
+		 * DVB-T and basic analog, IR Recv */
+	case 71009:
+		/* WinTV-HVR1200 (PCIe, Retail, full height)
+		 * DVB-T and basic analog */
+	case 71359:
+		/* WinTV-HVR1200 (PCIe, OEM, half height)
+		 * DVB-T and basic analog */
+	case 71439:
+		/* WinTV-HVR1200 (PCIe, OEM, half height)
+		 * DVB-T and basic analog */
+	case 71449:
+		/* WinTV-HVR1200 (PCIe, OEM, full height)
+		 * DVB-T and basic analog */
+	case 71939:
+		/* WinTV-HVR1200 (PCIe, OEM, half height)
+		 * DVB-T and basic analog */
+	case 71949:
+		/* WinTV-HVR1200 (PCIe, OEM, full height)
+		 * DVB-T and basic analog */
+	case 71959:
+		/* WinTV-HVR1200 (PCIe, OEM, full height)
+		 * DVB-T and basic analog */
+	case 71979:
+		/* WinTV-HVR1200 (PCIe, OEM, half height)
+		 * DVB-T and basic analog */
+	case 71999:
+		/* WinTV-HVR1200 (PCIe, OEM, full height)
+		 * DVB-T and basic analog */
+	case 76601:
+		/* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual
+			channel ATSC and MPEG2 HW Encoder */
+	case 77001:
+		/* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC
+			and Basic analog */
+	case 77011:
+		/* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC
+			and Basic analog */
+	case 77041:
+		/* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM
+			and Basic analog */
+	case 77051:
+		/* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM
+			and Basic analog */
+	case 78011:
+		/* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM,
+			Dual channel ATSC and MPEG2 HW Encoder */
+	case 78501:
+		/* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM,
+			Dual channel ATSC and MPEG2 HW Encoder */
+	case 78521:
+		/* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM,
+			Dual channel ATSC and MPEG2 HW Encoder */
+	case 78531:
+		/* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM,
+			Dual channel ATSC and MPEG2 HW Encoder */
+	case 78631:
+		/* WinTV-HVR1800 (PCIe, OEM, No IR, No FM,
+			Dual channel ATSC and MPEG2 HW Encoder */
+	case 79001:
+		/* WinTV-HVR1250 (PCIe, Retail, IR, full height,
+			ATSC and Basic analog */
+	case 79101:
+		/* WinTV-HVR1250 (PCIe, Retail, IR, half height,
+			ATSC and Basic analog */
+	case 79501:
+		/* WinTV-HVR1250 (PCIe, No IR, half height,
+			ATSC [at least] and Basic analog) */
+	case 79561:
+		/* WinTV-HVR1250 (PCIe, OEM, No IR, half height,
+			ATSC and Basic analog */
+	case 79571:
+		/* WinTV-HVR1250 (PCIe, OEM, No IR, full height,
+		 ATSC and Basic analog */
+	case 79671:
+		/* WinTV-HVR1250 (PCIe, OEM, No IR, half height,
+			ATSC and Basic analog */
+	case 80019:
+		/* WinTV-HVR1400 (Express Card, Retail, IR,
+		 * DVB-T and Basic analog */
+	case 81509:
+		/* WinTV-HVR1700 (PCIe, OEM, No IR, half height)
+		 * DVB-T and MPEG2 HW Encoder */
+	case 81519:
+		/* WinTV-HVR1700 (PCIe, OEM, No IR, full height)
+		 * DVB-T and MPEG2 HW Encoder */
+		break;
+	case 85021:
+		/* WinTV-HVR1850 (PCIe, Retail, 3.5mm in, IR, FM,
+			Dual channel ATSC and MPEG2 HW Encoder */
+		break;
+	case 85721:
+		/* WinTV-HVR1290 (PCIe, OEM, RCA in, IR,
+			Dual channel ATSC and Basic analog */
+		break;
+	default:
+		printk(KERN_WARNING "%s: warning: "
+			"unknown hauppauge model #%d\n",
+			dev->name, tv.model);
+		break;
+	}
+
+	printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+			dev->name, tv.model);
+}
+
+int cx23885_tuner_callback(void *priv, int component, int command, int arg)
+{
+	struct cx23885_tsport *port = priv;
+	struct cx23885_dev *dev = port->dev;
+	u32 bitmask = 0;
+
+	if ((command == XC2028_RESET_CLK) || (command == XC2028_I2C_FLUSH))
+		return 0;
+
+	if (command != 0) {
+		printk(KERN_ERR "%s(): Unknown command 0x%x.\n",
+			__func__, command);
+		return -EINVAL;
+	}
+
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1400:
+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
+	case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+	case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+	case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
+		/* Tuner Reset Command */
+		bitmask = 0x04;
+		break;
+	case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
+	case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+		/* Two identical tuners on two different i2c buses,
+		 * we need to reset the correct gpio. */
+		if (port->nr == 1)
+			bitmask = 0x01;
+		else if (port->nr == 2)
+			bitmask = 0x04;
+		break;
+	case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
+		/* Tuner Reset Command */
+		bitmask = 0x02;
+		break;
+	case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+		altera_ci_tuner_reset(dev, port->nr);
+		break;
+	}
+
+	if (bitmask) {
+		/* Drive the tuner into reset and back out */
+		cx_clear(GP0_IO, bitmask);
+		mdelay(200);
+		cx_set(GP0_IO, bitmask);
+	}
+
+	return 0;
+}
+
+void cx23885_gpio_setup(struct cx23885_dev *dev)
+{
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+		/* GPIO-0 cx24227 demodulator reset */
+		cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
+		/* GPIO-0 cx24227 demodulator */
+		/* GPIO-2 xc3028 tuner */
+
+		/* Put the parts into reset */
+		cx_set(GP0_IO, 0x00050000);
+		cx_clear(GP0_IO, 0x00000005);
+		msleep(5);
+
+		/* Bring the parts out of reset */
+		cx_set(GP0_IO, 0x00050005);
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+		/* GPIO-0 cx24227 demodulator reset */
+		/* GPIO-2 xc5000 tuner reset */
+		cx_set(GP0_IO, 0x00050005); /* Bring the part out of reset */
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+		/* GPIO-0 656_CLK */
+		/* GPIO-1 656_D0 */
+		/* GPIO-2 8295A Reset */
+		/* GPIO-3-10 cx23417 data0-7 */
+		/* GPIO-11-14 cx23417 addr0-3 */
+		/* GPIO-15-18 cx23417 READY, CS, RD, WR */
+		/* GPIO-19 IR_RX */
+
+		/* CX23417 GPIO's */
+		/* EIO15 Zilog Reset */
+		/* EIO14 S5H1409/CX24227 Reset */
+		mc417_gpio_enable(dev, GPIO_15 | GPIO_14, 1);
+
+		/* Put the demod into reset and protect the eeprom */
+		mc417_gpio_clear(dev, GPIO_15 | GPIO_14);
+		mdelay(100);
+
+		/* Bring the demod and blaster out of reset */
+		mc417_gpio_set(dev, GPIO_15 | GPIO_14);
+		mdelay(100);
+
+		/* Force the TDA8295A into reset and back */
+		cx23885_gpio_enable(dev, GPIO_2, 1);
+		cx23885_gpio_set(dev, GPIO_2);
+		mdelay(20);
+		cx23885_gpio_clear(dev, GPIO_2);
+		mdelay(20);
+		cx23885_gpio_set(dev, GPIO_2);
+		mdelay(20);
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1200:
+		/* GPIO-0 tda10048 demodulator reset */
+		/* GPIO-2 tda18271 tuner reset */
+
+		/* Put the parts into reset and back */
+		cx_set(GP0_IO, 0x00050000);
+		mdelay(20);
+		cx_clear(GP0_IO, 0x00000005);
+		mdelay(20);
+		cx_set(GP0_IO, 0x00050005);
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1700:
+		/* GPIO-0 TDA10048 demodulator reset */
+		/* GPIO-2 TDA8295A Reset */
+		/* GPIO-3-10 cx23417 data0-7 */
+		/* GPIO-11-14 cx23417 addr0-3 */
+		/* GPIO-15-18 cx23417 READY, CS, RD, WR */
+
+		/* The following GPIO's are on the interna AVCore (cx25840) */
+		/* GPIO-19 IR_RX */
+		/* GPIO-20 IR_TX 416/DVBT Select */
+		/* GPIO-21 IIS DAT */
+		/* GPIO-22 IIS WCLK */
+		/* GPIO-23 IIS BCLK */
+
+		/* Put the parts into reset and back */
+		cx_set(GP0_IO, 0x00050000);
+		mdelay(20);
+		cx_clear(GP0_IO, 0x00000005);
+		mdelay(20);
+		cx_set(GP0_IO, 0x00050005);
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1400:
+		/* GPIO-0  Dibcom7000p demodulator reset */
+		/* GPIO-2  xc3028L tuner reset */
+		/* GPIO-13 LED */
+
+		/* Put the parts into reset and back */
+		cx_set(GP0_IO, 0x00050000);
+		mdelay(20);
+		cx_clear(GP0_IO, 0x00000005);
+		mdelay(20);
+		cx_set(GP0_IO, 0x00050005);
+		break;
+	case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
+		/* GPIO-0 xc5000 tuner reset i2c bus 0 */
+		/* GPIO-1 s5h1409 demod reset i2c bus 0 */
+		/* GPIO-2 xc5000 tuner reset i2c bus 1 */
+		/* GPIO-3 s5h1409 demod reset i2c bus 0 */
+
+		/* Put the parts into reset and back */
+		cx_set(GP0_IO, 0x000f0000);
+		mdelay(20);
+		cx_clear(GP0_IO, 0x0000000f);
+		mdelay(20);
+		cx_set(GP0_IO, 0x000f000f);
+		break;
+	case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+		/* GPIO-0 portb xc3028 reset */
+		/* GPIO-1 portb zl10353 reset */
+		/* GPIO-2 portc xc3028 reset */
+		/* GPIO-3 portc zl10353 reset */
+
+		/* Put the parts into reset and back */
+		cx_set(GP0_IO, 0x000f0000);
+		mdelay(20);
+		cx_clear(GP0_IO, 0x0000000f);
+		mdelay(20);
+		cx_set(GP0_IO, 0x000f000f);
+		break;
+	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
+	case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+	case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+	case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
+		/* GPIO-2  xc3028 tuner reset */
+
+		/* The following GPIO's are on the internal AVCore (cx25840) */
+		/* GPIO-?  zl10353 demod reset */
+
+		/* Put the parts into reset and back */
+		cx_set(GP0_IO, 0x00040000);
+		mdelay(20);
+		cx_clear(GP0_IO, 0x00000004);
+		mdelay(20);
+		cx_set(GP0_IO, 0x00040004);
+		break;
+	case CX23885_BOARD_TBS_6920:
+		cx_write(MC417_CTL, 0x00000036);
+		cx_write(MC417_OEN, 0x00001000);
+		cx_set(MC417_RWD, 0x00000002);
+		mdelay(200);
+		cx_clear(MC417_RWD, 0x00000800);
+		mdelay(200);
+		cx_set(MC417_RWD, 0x00000800);
+		mdelay(200);
+		break;
+	case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+		/* GPIO-0 INTA from CiMax1
+		   GPIO-1 INTB from CiMax2
+		   GPIO-2 reset chips
+		   GPIO-3 to GPIO-10 data/addr for CA
+		   GPIO-11 ~CS0 to CiMax1
+		   GPIO-12 ~CS1 to CiMax2
+		   GPIO-13 ADL0 load LSB addr
+		   GPIO-14 ADL1 load MSB addr
+		   GPIO-15 ~RDY from CiMax
+		   GPIO-17 ~RD to CiMax
+		   GPIO-18 ~WR to CiMax
+		 */
+		cx_set(GP0_IO, 0x00040000); /* GPIO as out */
+		/* GPIO1 and GPIO2 as INTA and INTB from CiMaxes, reset low */
+		cx_clear(GP0_IO, 0x00030004);
+		mdelay(100);/* reset delay */
+		cx_set(GP0_IO, 0x00040004); /* GPIO as out, reset high */
+		cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */
+		/* GPIO-15 IN as ~ACK, rest as OUT */
+		cx_write(MC417_OEN, 0x00001000);
+		/* ~RD, ~WR high; ADL0, ADL1 low; ~CS0, ~CS1 high */
+		cx_write(MC417_RWD, 0x0000c300);
+		/* enable irq */
+		cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1270:
+	case CX23885_BOARD_HAUPPAUGE_HVR1275:
+	case CX23885_BOARD_HAUPPAUGE_HVR1255:
+	case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
+	case CX23885_BOARD_HAUPPAUGE_HVR1210:
+		/* GPIO-5 RF Control: 0 = RF1 Terrestrial, 1 = RF2 Cable */
+		/* GPIO-6 I2C Gate which can isolate the demod from the bus */
+		/* GPIO-9 Demod reset */
+
+		/* Put the parts into reset and back */
+		cx23885_gpio_enable(dev, GPIO_9 | GPIO_6 | GPIO_5, 1);
+		cx23885_gpio_set(dev, GPIO_9 | GPIO_6 | GPIO_5);
+		cx23885_gpio_clear(dev, GPIO_9);
+		mdelay(20);
+		cx23885_gpio_set(dev, GPIO_9);
+		break;
+	case CX23885_BOARD_MYGICA_X8506:
+	case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+	case CX23885_BOARD_MYGICA_X8507:
+		/* GPIO-0 (0)Analog / (1)Digital TV */
+		/* GPIO-1 reset XC5000 */
+		/* GPIO-2 reset LGS8GL5 / LGS8G75 */
+		cx23885_gpio_enable(dev, GPIO_0 | GPIO_1 | GPIO_2, 1);
+		cx23885_gpio_clear(dev, GPIO_1 | GPIO_2);
+		mdelay(100);
+		cx23885_gpio_set(dev, GPIO_0 | GPIO_1 | GPIO_2);
+		mdelay(100);
+		break;
+	case CX23885_BOARD_MYGICA_X8558PRO:
+		/* GPIO-0 reset first ATBM8830 */
+		/* GPIO-1 reset second ATBM8830 */
+		cx23885_gpio_enable(dev, GPIO_0 | GPIO_1, 1);
+		cx23885_gpio_clear(dev, GPIO_0 | GPIO_1);
+		mdelay(100);
+		cx23885_gpio_set(dev, GPIO_0 | GPIO_1);
+		mdelay(100);
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+		/* GPIO-0 656_CLK */
+		/* GPIO-1 656_D0 */
+		/* GPIO-2 Wake# */
+		/* GPIO-3-10 cx23417 data0-7 */
+		/* GPIO-11-14 cx23417 addr0-3 */
+		/* GPIO-15-18 cx23417 READY, CS, RD, WR */
+		/* GPIO-19 IR_RX */
+		/* GPIO-20 C_IR_TX */
+		/* GPIO-21 I2S DAT */
+		/* GPIO-22 I2S WCLK */
+		/* GPIO-23 I2S BCLK */
+		/* ALT GPIO: EXP GPIO LATCH */
+
+		/* CX23417 GPIO's */
+		/* GPIO-14 S5H1411/CX24228 Reset */
+		/* GPIO-13 EEPROM write protect */
+		mc417_gpio_enable(dev, GPIO_14 | GPIO_13, 1);
+
+		/* Put the demod into reset and protect the eeprom */
+		mc417_gpio_clear(dev, GPIO_14 | GPIO_13);
+		mdelay(100);
+
+		/* Bring the demod out of reset */
+		mc417_gpio_set(dev, GPIO_14);
+		mdelay(100);
+
+		/* CX24228 GPIO */
+		/* Connected to IF / Mux */
+		break;
+	case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
+		cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
+		break;
+	case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+		/* GPIO-0 ~INT in
+		   GPIO-1 TMS out
+		   GPIO-2 ~reset chips out
+		   GPIO-3 to GPIO-10 data/addr for CA in/out
+		   GPIO-11 ~CS out
+		   GPIO-12 ADDR out
+		   GPIO-13 ~WR out
+		   GPIO-14 ~RD out
+		   GPIO-15 ~RDY in
+		   GPIO-16 TCK out
+		   GPIO-17 TDO in
+		   GPIO-18 TDI out
+		 */
+		cx_set(GP0_IO, 0x00060000); /* GPIO-1,2 as out */
+		/* GPIO-0 as INT, reset & TMS low */
+		cx_clear(GP0_IO, 0x00010006);
+		mdelay(100);/* reset delay */
+		cx_set(GP0_IO, 0x00000004); /* reset high */
+		cx_write(MC417_CTL, 0x00000037);/* enable GPIO-3..18 pins */
+		/* GPIO-17 is TDO in, GPIO-15 is ~RDY in, rest is out */
+		cx_write(MC417_OEN, 0x00005000);
+		/* ~RD, ~WR high; ADDR low; ~CS high */
+		cx_write(MC417_RWD, 0x00000d00);
+		/* enable irq */
+		cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
+		break;
+	}
+}
+
+int cx23885_ir_init(struct cx23885_dev *dev)
+{
+	static struct v4l2_subdev_io_pin_config ir_rxtx_pin_cfg[] = {
+		{
+			.flags	  = V4L2_SUBDEV_IO_PIN_INPUT,
+			.pin	  = CX23885_PIN_IR_RX_GPIO19,
+			.function = CX23885_PAD_IR_RX,
+			.value	  = 0,
+			.strength = CX25840_PIN_DRIVE_MEDIUM,
+		}, {
+			.flags	  = V4L2_SUBDEV_IO_PIN_OUTPUT,
+			.pin	  = CX23885_PIN_IR_TX_GPIO20,
+			.function = CX23885_PAD_IR_TX,
+			.value	  = 0,
+			.strength = CX25840_PIN_DRIVE_MEDIUM,
+		}
+	};
+	const size_t ir_rxtx_pin_cfg_count = ARRAY_SIZE(ir_rxtx_pin_cfg);
+
+	static struct v4l2_subdev_io_pin_config ir_rx_pin_cfg[] = {
+		{
+			.flags	  = V4L2_SUBDEV_IO_PIN_INPUT,
+			.pin	  = CX23885_PIN_IR_RX_GPIO19,
+			.function = CX23885_PAD_IR_RX,
+			.value	  = 0,
+			.strength = CX25840_PIN_DRIVE_MEDIUM,
+		}
+	};
+	const size_t ir_rx_pin_cfg_count = ARRAY_SIZE(ir_rx_pin_cfg);
+
+	struct v4l2_subdev_ir_parameters params;
+	int ret = 0;
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+	case CX23885_BOARD_HAUPPAUGE_HVR1200:
+	case CX23885_BOARD_HAUPPAUGE_HVR1400:
+	case CX23885_BOARD_HAUPPAUGE_HVR1275:
+	case CX23885_BOARD_HAUPPAUGE_HVR1255:
+	case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
+	case CX23885_BOARD_HAUPPAUGE_HVR1210:
+		/* FIXME: Implement me */
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1270:
+		ret = cx23888_ir_probe(dev);
+		if (ret)
+			break;
+		dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR);
+		v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+				 ir_rx_pin_cfg_count, ir_rx_pin_cfg);
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+		ret = cx23888_ir_probe(dev);
+		if (ret)
+			break;
+		dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR);
+		v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+				 ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg);
+		/*
+		 * For these boards we need to invert the Tx output via the
+		 * IR controller to have the LED off while idle
+		 */
+		v4l2_subdev_call(dev->sd_ir, ir, tx_g_parameters, &params);
+		params.enable = false;
+		params.shutdown = false;
+		params.invert_level = true;
+		v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, &params);
+		params.shutdown = true;
+		v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, &params);
+		break;
+	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+	case CX23885_BOARD_TEVII_S470:
+		if (!enable_885_ir)
+			break;
+		dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE);
+		if (dev->sd_ir == NULL) {
+			ret = -ENODEV;
+			break;
+		}
+		v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+				 ir_rx_pin_cfg_count, ir_rx_pin_cfg);
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+		if (!enable_885_ir)
+			break;
+		dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE);
+		if (dev->sd_ir == NULL) {
+			ret = -ENODEV;
+			break;
+		}
+		v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+				 ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg);
+		break;
+	case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+		request_module("ir-kbd-i2c");
+		break;
+	}
+
+	return ret;
+}
+
+void cx23885_ir_fini(struct cx23885_dev *dev)
+{
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1270:
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+		cx23885_irq_remove(dev, PCI_MSK_IR);
+		cx23888_ir_remove(dev);
+		dev->sd_ir = NULL;
+		break;
+	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+	case CX23885_BOARD_TEVII_S470:
+	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+		cx23885_irq_remove(dev, PCI_MSK_AV_CORE);
+		/* sd_ir is a duplicate pointer to the AV Core, just clear it */
+		dev->sd_ir = NULL;
+		break;
+	}
+}
+
+int netup_jtag_io(void *device, int tms, int tdi, int read_tdo)
+{
+	int data;
+	int tdo = 0;
+	struct cx23885_dev *dev = (struct cx23885_dev *)device;
+	/*TMS*/
+	data = ((cx_read(GP0_IO)) & (~0x00000002));
+	data |= (tms ? 0x00020002 : 0x00020000);
+	cx_write(GP0_IO, data);
+
+	/*TDI*/
+	data = ((cx_read(MC417_RWD)) & (~0x0000a000));
+	data |= (tdi ? 0x00008000 : 0);
+	cx_write(MC417_RWD, data);
+	if (read_tdo)
+		tdo = (data & 0x00004000) ? 1 : 0; /*TDO*/
+
+	cx_write(MC417_RWD, data | 0x00002000);
+	udelay(1);
+	/*TCK*/
+	cx_write(MC417_RWD, data);
+
+	return tdo;
+}
+
+void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
+{
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1270:
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+		if (dev->sd_ir)
+			cx23885_irq_add_enable(dev, PCI_MSK_IR);
+		break;
+	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+	case CX23885_BOARD_TEVII_S470:
+	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+		if (dev->sd_ir)
+			cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE);
+		break;
+	}
+}
+
+void cx23885_card_setup(struct cx23885_dev *dev)
+{
+	struct cx23885_tsport *ts1 = &dev->ts1;
+	struct cx23885_tsport *ts2 = &dev->ts2;
+
+	static u8 eeprom[256];
+
+	if (dev->i2c_bus[0].i2c_rc == 0) {
+		dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
+		tveeprom_read(&dev->i2c_bus[0].i2c_client,
+			      eeprom, sizeof(eeprom));
+	}
+
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+		if (dev->i2c_bus[0].i2c_rc == 0) {
+			if (eeprom[0x80] != 0x84)
+				hauppauge_eeprom(dev, eeprom+0xc0);
+			else
+				hauppauge_eeprom(dev, eeprom+0x80);
+		}
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+	case CX23885_BOARD_HAUPPAUGE_HVR1400:
+		if (dev->i2c_bus[0].i2c_rc == 0)
+			hauppauge_eeprom(dev, eeprom+0x80);
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+	case CX23885_BOARD_HAUPPAUGE_HVR1200:
+	case CX23885_BOARD_HAUPPAUGE_HVR1700:
+	case CX23885_BOARD_HAUPPAUGE_HVR1270:
+	case CX23885_BOARD_HAUPPAUGE_HVR1275:
+	case CX23885_BOARD_HAUPPAUGE_HVR1255:
+	case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
+	case CX23885_BOARD_HAUPPAUGE_HVR1210:
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+		if (dev->i2c_bus[0].i2c_rc == 0)
+			hauppauge_eeprom(dev, eeprom+0xc0);
+		break;
+	}
+
+	switch (dev->board) {
+	case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
+	case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+		ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		/* break omitted intentionally */
+	case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
+		ts1->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+		/* Defaults for VID B - Analog encoder */
+		/* DREQ_POL, SMODE, PUNC_CLK, MCLK_POL Serial bus + punc clk */
+		ts1->gen_ctrl_val    = 0x10e;
+		ts1->ts_clk_en_val   = 0x1; /* Enable TS_CLK */
+		ts1->src_sel_val     = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+
+		/* APB_TSVALERR_POL (active low)*/
+		ts1->vld_misc_val    = 0x2000;
+		ts1->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4 | 0xc);
+		cx_write(0x130184, 0xc);
+
+		/* Defaults for VID C */
+		ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		break;
+	case CX23885_BOARD_TBS_6920:
+		ts1->gen_ctrl_val  = 0x4; /* Parallel */
+		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		break;
+	case CX23885_BOARD_TEVII_S470:
+	case CX23885_BOARD_TEVII_S471:
+	case CX23885_BOARD_DVBWORLD_2005:
+		ts1->gen_ctrl_val  = 0x5; /* Parallel */
+		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		break;
+	case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+	case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+		ts1->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		break;
+	case CX23885_BOARD_MYGICA_X8506:
+	case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+		ts1->gen_ctrl_val  = 0x5; /* Parallel */
+		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		break;
+	case CX23885_BOARD_MYGICA_X8558PRO:
+		ts1->gen_ctrl_val  = 0x5; /* Parallel */
+		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+	case CX23885_BOARD_HAUPPAUGE_HVR1200:
+	case CX23885_BOARD_HAUPPAUGE_HVR1700:
+	case CX23885_BOARD_HAUPPAUGE_HVR1400:
+	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
+	case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+	case CX23885_BOARD_HAUPPAUGE_HVR1270:
+	case CX23885_BOARD_HAUPPAUGE_HVR1275:
+	case CX23885_BOARD_HAUPPAUGE_HVR1255:
+	case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
+	case CX23885_BOARD_HAUPPAUGE_HVR1210:
+	case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+	case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
+	default:
+		ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+	}
+
+	/* Certain boards support analog, or require the avcore to be
+	 * loaded, ensure this happens.
+	 */
+	switch (dev->board) {
+	case CX23885_BOARD_TEVII_S470:
+		/* Currently only enabled for the integrated IR controller */
+		if (!enable_885_ir)
+			break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+	case CX23885_BOARD_HAUPPAUGE_HVR1700:
+	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
+	case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+	case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+	case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+	case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+	case CX23885_BOARD_HAUPPAUGE_HVR1255:
+	case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
+	case CX23885_BOARD_HAUPPAUGE_HVR1270:
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_MYGICA_X8506:
+	case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+	case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
+	case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
+	case CX23885_BOARD_MPX885:
+	case CX23885_BOARD_MYGICA_X8507:
+	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+		dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+				&dev->i2c_bus[2].i2c_adap,
+				"cx25840", 0x88 >> 1, NULL);
+		if (dev->sd_cx25840) {
+			dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE;
+			v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
+		}
+		break;
+	}
+
+	/* AUX-PLL 27MHz CLK */
+	switch (dev->board) {
+	case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+		netup_initialize(dev);
+		break;
+	case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: {
+		int ret;
+		const struct firmware *fw;
+		const char *filename = "dvb-netup-altera-01.fw";
+		char *action = "configure";
+		static struct netup_card_info cinfo;
+		struct altera_config netup_config = {
+			.dev = dev,
+			.action = action,
+			.jtag_io = netup_jtag_io,
+		};
+
+		netup_initialize(dev);
+
+		netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
+		if (netup_card_rev)
+			cinfo.rev = netup_card_rev;
+
+		switch (cinfo.rev) {
+		case 0x4:
+			filename = "dvb-netup-altera-04.fw";
+			break;
+		default:
+			filename = "dvb-netup-altera-01.fw";
+			break;
+		}
+		printk(KERN_INFO "NetUP card rev=0x%x fw_filename=%s\n",
+				cinfo.rev, filename);
+
+		ret = request_firmware(&fw, filename, &dev->pci->dev);
+		if (ret != 0)
+			printk(KERN_ERR "did not find the firmware file. (%s) "
+			"Please see linux/Documentation/dvb/ for more details "
+			"on firmware-problems.", filename);
+		else
+			altera_init(&netup_config, fw);
+
+		release_firmware(fw);
+		break;
+	}
+	}
+}
+
+/* ------------------------------------------------------------------ */
diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c
new file mode 100644
index 0000000..697728f
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-core.c
@@ -0,0 +1,2234 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/div64.h>
+#include <linux/firmware.h>
+
+#include "cx23885.h"
+#include "cimax2.h"
+#include "altera-ci.h"
+#include "cx23888-ir.h"
+#include "cx23885-ir.h"
+#include "cx23885-av.h"
+#include "cx23885-input.h"
+
+MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
+MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CX23885_VERSION);
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+static unsigned int card[]  = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
+module_param_array(card,  int, NULL, 0444);
+MODULE_PARM_DESC(card, "card type");
+
+#define dprintk(level, fmt, arg...)\
+	do { if (debug >= level)\
+		printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg);\
+	} while (0)
+
+static unsigned int cx23885_devcount;
+
+#define NO_SYNC_LINE (-1U)
+
+/* FIXME, these allocations will change when
+ * analog arrives. The be reviewed.
+ * CX23887 Assumptions
+ * 1 line = 16 bytes of CDT
+ * cmds size = 80
+ * cdt size = 16 * linesize
+ * iqsize = 64
+ * maxlines = 6
+ *
+ * Address Space:
+ * 0x00000000 0x00008fff FIFO clusters
+ * 0x00010000 0x000104af Channel Management Data Structures
+ * 0x000104b0 0x000104ff Free
+ * 0x00010500 0x000108bf 15 channels * iqsize
+ * 0x000108c0 0x000108ff Free
+ * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables
+ *                       15 channels * (iqsize + (maxlines * linesize))
+ * 0x00010ea0 0x00010xxx Free
+ */
+
+static struct sram_channel cx23885_sram_channels[] = {
+	[SRAM_CH01] = {
+		.name		= "VID A",
+		.cmds_start	= 0x10000,
+		.ctrl_start	= 0x10380,
+		.cdt		= 0x104c0,
+		.fifo_start	= 0x40,
+		.fifo_size	= 0x2800,
+		.ptr1_reg	= DMA1_PTR1,
+		.ptr2_reg	= DMA1_PTR2,
+		.cnt1_reg	= DMA1_CNT1,
+		.cnt2_reg	= DMA1_CNT2,
+	},
+	[SRAM_CH02] = {
+		.name		= "ch2",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA2_PTR1,
+		.ptr2_reg	= DMA2_PTR2,
+		.cnt1_reg	= DMA2_CNT1,
+		.cnt2_reg	= DMA2_CNT2,
+	},
+	[SRAM_CH03] = {
+		.name		= "TS1 B",
+		.cmds_start	= 0x100A0,
+		.ctrl_start	= 0x10400,
+		.cdt		= 0x10580,
+		.fifo_start	= 0x5000,
+		.fifo_size	= 0x1000,
+		.ptr1_reg	= DMA3_PTR1,
+		.ptr2_reg	= DMA3_PTR2,
+		.cnt1_reg	= DMA3_CNT1,
+		.cnt2_reg	= DMA3_CNT2,
+	},
+	[SRAM_CH04] = {
+		.name		= "ch4",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA4_PTR1,
+		.ptr2_reg	= DMA4_PTR2,
+		.cnt1_reg	= DMA4_CNT1,
+		.cnt2_reg	= DMA4_CNT2,
+	},
+	[SRAM_CH05] = {
+		.name		= "ch5",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA5_PTR1,
+		.ptr2_reg	= DMA5_PTR2,
+		.cnt1_reg	= DMA5_CNT1,
+		.cnt2_reg	= DMA5_CNT2,
+	},
+	[SRAM_CH06] = {
+		.name		= "TS2 C",
+		.cmds_start	= 0x10140,
+		.ctrl_start	= 0x10440,
+		.cdt		= 0x105e0,
+		.fifo_start	= 0x6000,
+		.fifo_size	= 0x1000,
+		.ptr1_reg	= DMA5_PTR1,
+		.ptr2_reg	= DMA5_PTR2,
+		.cnt1_reg	= DMA5_CNT1,
+		.cnt2_reg	= DMA5_CNT2,
+	},
+	[SRAM_CH07] = {
+		.name		= "TV Audio",
+		.cmds_start	= 0x10190,
+		.ctrl_start	= 0x10480,
+		.cdt		= 0x10a00,
+		.fifo_start	= 0x7000,
+		.fifo_size	= 0x1000,
+		.ptr1_reg	= DMA6_PTR1,
+		.ptr2_reg	= DMA6_PTR2,
+		.cnt1_reg	= DMA6_CNT1,
+		.cnt2_reg	= DMA6_CNT2,
+	},
+	[SRAM_CH08] = {
+		.name		= "ch8",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA7_PTR1,
+		.ptr2_reg	= DMA7_PTR2,
+		.cnt1_reg	= DMA7_CNT1,
+		.cnt2_reg	= DMA7_CNT2,
+	},
+	[SRAM_CH09] = {
+		.name		= "ch9",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA8_PTR1,
+		.ptr2_reg	= DMA8_PTR2,
+		.cnt1_reg	= DMA8_CNT1,
+		.cnt2_reg	= DMA8_CNT2,
+	},
+};
+
+static struct sram_channel cx23887_sram_channels[] = {
+	[SRAM_CH01] = {
+		.name		= "VID A",
+		.cmds_start	= 0x10000,
+		.ctrl_start	= 0x105b0,
+		.cdt		= 0x107b0,
+		.fifo_start	= 0x40,
+		.fifo_size	= 0x2800,
+		.ptr1_reg	= DMA1_PTR1,
+		.ptr2_reg	= DMA1_PTR2,
+		.cnt1_reg	= DMA1_CNT1,
+		.cnt2_reg	= DMA1_CNT2,
+	},
+	[SRAM_CH02] = {
+		.name		= "VID A (VBI)",
+		.cmds_start	= 0x10050,
+		.ctrl_start	= 0x105F0,
+		.cdt		= 0x10810,
+		.fifo_start	= 0x3000,
+		.fifo_size	= 0x1000,
+		.ptr1_reg	= DMA2_PTR1,
+		.ptr2_reg	= DMA2_PTR2,
+		.cnt1_reg	= DMA2_CNT1,
+		.cnt2_reg	= DMA2_CNT2,
+	},
+	[SRAM_CH03] = {
+		.name		= "TS1 B",
+		.cmds_start	= 0x100A0,
+		.ctrl_start	= 0x10630,
+		.cdt		= 0x10870,
+		.fifo_start	= 0x5000,
+		.fifo_size	= 0x1000,
+		.ptr1_reg	= DMA3_PTR1,
+		.ptr2_reg	= DMA3_PTR2,
+		.cnt1_reg	= DMA3_CNT1,
+		.cnt2_reg	= DMA3_CNT2,
+	},
+	[SRAM_CH04] = {
+		.name		= "ch4",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA4_PTR1,
+		.ptr2_reg	= DMA4_PTR2,
+		.cnt1_reg	= DMA4_CNT1,
+		.cnt2_reg	= DMA4_CNT2,
+	},
+	[SRAM_CH05] = {
+		.name		= "ch5",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA5_PTR1,
+		.ptr2_reg	= DMA5_PTR2,
+		.cnt1_reg	= DMA5_CNT1,
+		.cnt2_reg	= DMA5_CNT2,
+	},
+	[SRAM_CH06] = {
+		.name		= "TS2 C",
+		.cmds_start	= 0x10140,
+		.ctrl_start	= 0x10670,
+		.cdt		= 0x108d0,
+		.fifo_start	= 0x6000,
+		.fifo_size	= 0x1000,
+		.ptr1_reg	= DMA5_PTR1,
+		.ptr2_reg	= DMA5_PTR2,
+		.cnt1_reg	= DMA5_CNT1,
+		.cnt2_reg	= DMA5_CNT2,
+	},
+	[SRAM_CH07] = {
+		.name		= "TV Audio",
+		.cmds_start	= 0x10190,
+		.ctrl_start	= 0x106B0,
+		.cdt		= 0x10930,
+		.fifo_start	= 0x7000,
+		.fifo_size	= 0x1000,
+		.ptr1_reg	= DMA6_PTR1,
+		.ptr2_reg	= DMA6_PTR2,
+		.cnt1_reg	= DMA6_CNT1,
+		.cnt2_reg	= DMA6_CNT2,
+	},
+	[SRAM_CH08] = {
+		.name		= "ch8",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA7_PTR1,
+		.ptr2_reg	= DMA7_PTR2,
+		.cnt1_reg	= DMA7_CNT1,
+		.cnt2_reg	= DMA7_CNT2,
+	},
+	[SRAM_CH09] = {
+		.name		= "ch9",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA8_PTR1,
+		.ptr2_reg	= DMA8_PTR2,
+		.cnt1_reg	= DMA8_CNT1,
+		.cnt2_reg	= DMA8_CNT2,
+	},
+};
+
+void cx23885_irq_add(struct cx23885_dev *dev, u32 mask)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
+
+	dev->pci_irqmask |= mask;
+
+	spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
+}
+
+void cx23885_irq_add_enable(struct cx23885_dev *dev, u32 mask)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
+
+	dev->pci_irqmask |= mask;
+	cx_set(PCI_INT_MSK, mask);
+
+	spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
+}
+
+void cx23885_irq_enable(struct cx23885_dev *dev, u32 mask)
+{
+	u32 v;
+	unsigned long flags;
+	spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
+
+	v = mask & dev->pci_irqmask;
+	if (v)
+		cx_set(PCI_INT_MSK, v);
+
+	spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
+}
+
+static inline void cx23885_irq_enable_all(struct cx23885_dev *dev)
+{
+	cx23885_irq_enable(dev, 0xffffffff);
+}
+
+void cx23885_irq_disable(struct cx23885_dev *dev, u32 mask)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
+
+	cx_clear(PCI_INT_MSK, mask);
+
+	spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
+}
+
+static inline void cx23885_irq_disable_all(struct cx23885_dev *dev)
+{
+	cx23885_irq_disable(dev, 0xffffffff);
+}
+
+void cx23885_irq_remove(struct cx23885_dev *dev, u32 mask)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
+
+	dev->pci_irqmask &= ~mask;
+	cx_clear(PCI_INT_MSK, mask);
+
+	spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
+}
+
+static u32 cx23885_irq_get_mask(struct cx23885_dev *dev)
+{
+	u32 v;
+	unsigned long flags;
+	spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
+
+	v = cx_read(PCI_INT_MSK);
+
+	spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
+	return v;
+}
+
+static int cx23885_risc_decode(u32 risc)
+{
+	static char *instr[16] = {
+		[RISC_SYNC    >> 28] = "sync",
+		[RISC_WRITE   >> 28] = "write",
+		[RISC_WRITEC  >> 28] = "writec",
+		[RISC_READ    >> 28] = "read",
+		[RISC_READC   >> 28] = "readc",
+		[RISC_JUMP    >> 28] = "jump",
+		[RISC_SKIP    >> 28] = "skip",
+		[RISC_WRITERM >> 28] = "writerm",
+		[RISC_WRITECM >> 28] = "writecm",
+		[RISC_WRITECR >> 28] = "writecr",
+	};
+	static int incr[16] = {
+		[RISC_WRITE   >> 28] = 3,
+		[RISC_JUMP    >> 28] = 3,
+		[RISC_SKIP    >> 28] = 1,
+		[RISC_SYNC    >> 28] = 1,
+		[RISC_WRITERM >> 28] = 3,
+		[RISC_WRITECM >> 28] = 3,
+		[RISC_WRITECR >> 28] = 4,
+	};
+	static char *bits[] = {
+		"12",   "13",   "14",   "resync",
+		"cnt0", "cnt1", "18",   "19",
+		"20",   "21",   "22",   "23",
+		"irq1", "irq2", "eol",  "sol",
+	};
+	int i;
+
+	printk("0x%08x [ %s", risc,
+	       instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
+	for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--)
+		if (risc & (1 << (i + 12)))
+			printk(" %s", bits[i]);
+	printk(" count=%d ]\n", risc & 0xfff);
+	return incr[risc >> 28] ? incr[risc >> 28] : 1;
+}
+
+void cx23885_wakeup(struct cx23885_tsport *port,
+			   struct cx23885_dmaqueue *q, u32 count)
+{
+	struct cx23885_dev *dev = port->dev;
+	struct cx23885_buffer *buf;
+	int bc;
+
+	for (bc = 0;; bc++) {
+		if (list_empty(&q->active))
+			break;
+		buf = list_entry(q->active.next,
+				 struct cx23885_buffer, vb.queue);
+
+		/* count comes from the hw and is is 16bit wide --
+		 * this trick handles wrap-arounds correctly for
+		 * up to 32767 buffers in flight... */
+		if ((s16) (count - buf->count) < 0)
+			break;
+
+		do_gettimeofday(&buf->vb.ts);
+		dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
+			count, buf->count);
+		buf->vb.state = VIDEOBUF_DONE;
+		list_del(&buf->vb.queue);
+		wake_up(&buf->vb.done);
+	}
+	if (list_empty(&q->active))
+		del_timer(&q->timeout);
+	else
+		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
+	if (bc != 1)
+		printk(KERN_WARNING "%s: %d buffers handled (should be 1)\n",
+		       __func__, bc);
+}
+
+int cx23885_sram_channel_setup(struct cx23885_dev *dev,
+				      struct sram_channel *ch,
+				      unsigned int bpl, u32 risc)
+{
+	unsigned int i, lines;
+	u32 cdt;
+
+	if (ch->cmds_start == 0) {
+		dprintk(1, "%s() Erasing channel [%s]\n", __func__,
+			ch->name);
+		cx_write(ch->ptr1_reg, 0);
+		cx_write(ch->ptr2_reg, 0);
+		cx_write(ch->cnt2_reg, 0);
+		cx_write(ch->cnt1_reg, 0);
+		return 0;
+	} else {
+		dprintk(1, "%s() Configuring channel [%s]\n", __func__,
+			ch->name);
+	}
+
+	bpl   = (bpl + 7) & ~7; /* alignment */
+	cdt   = ch->cdt;
+	lines = ch->fifo_size / bpl;
+	if (lines > 6)
+		lines = 6;
+	BUG_ON(lines < 2);
+
+	cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+	cx_write(8 + 4, 8);
+	cx_write(8 + 8, 0);
+
+	/* write CDT */
+	for (i = 0; i < lines; i++) {
+		dprintk(2, "%s() 0x%08x <- 0x%08x\n", __func__, cdt + 16*i,
+			ch->fifo_start + bpl*i);
+		cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
+		cx_write(cdt + 16*i +  4, 0);
+		cx_write(cdt + 16*i +  8, 0);
+		cx_write(cdt + 16*i + 12, 0);
+	}
+
+	/* write CMDS */
+	if (ch->jumponly)
+		cx_write(ch->cmds_start + 0, 8);
+	else
+		cx_write(ch->cmds_start + 0, risc);
+	cx_write(ch->cmds_start +  4, 0); /* 64 bits 63-32 */
+	cx_write(ch->cmds_start +  8, cdt);
+	cx_write(ch->cmds_start + 12, (lines*16) >> 3);
+	cx_write(ch->cmds_start + 16, ch->ctrl_start);
+	if (ch->jumponly)
+		cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2));
+	else
+		cx_write(ch->cmds_start + 20, 64 >> 2);
+	for (i = 24; i < 80; i += 4)
+		cx_write(ch->cmds_start + i, 0);
+
+	/* fill registers */
+	cx_write(ch->ptr1_reg, ch->fifo_start);
+	cx_write(ch->ptr2_reg, cdt);
+	cx_write(ch->cnt2_reg, (lines*16) >> 3);
+	cx_write(ch->cnt1_reg, (bpl >> 3) - 1);
+
+	dprintk(2, "[bridge %d] sram setup %s: bpl=%d lines=%d\n",
+		dev->bridge,
+		ch->name,
+		bpl,
+		lines);
+
+	return 0;
+}
+
+void cx23885_sram_channel_dump(struct cx23885_dev *dev,
+				      struct sram_channel *ch)
+{
+	static char *name[] = {
+		"init risc lo",
+		"init risc hi",
+		"cdt base",
+		"cdt size",
+		"iq base",
+		"iq size",
+		"risc pc lo",
+		"risc pc hi",
+		"iq wr ptr",
+		"iq rd ptr",
+		"cdt current",
+		"pci target lo",
+		"pci target hi",
+		"line / byte",
+	};
+	u32 risc;
+	unsigned int i, j, n;
+
+	printk(KERN_WARNING "%s: %s - dma channel status dump\n",
+	       dev->name, ch->name);
+	for (i = 0; i < ARRAY_SIZE(name); i++)
+		printk(KERN_WARNING "%s:   cmds: %-15s: 0x%08x\n",
+		       dev->name, name[i],
+		       cx_read(ch->cmds_start + 4*i));
+
+	for (i = 0; i < 4; i++) {
+		risc = cx_read(ch->cmds_start + 4 * (i + 14));
+		printk(KERN_WARNING "%s:   risc%d: ", dev->name, i);
+		cx23885_risc_decode(risc);
+	}
+	for (i = 0; i < (64 >> 2); i += n) {
+		risc = cx_read(ch->ctrl_start + 4 * i);
+		/* No consideration for bits 63-32 */
+
+		printk(KERN_WARNING "%s:   (0x%08x) iq %x: ", dev->name,
+		       ch->ctrl_start + 4 * i, i);
+		n = cx23885_risc_decode(risc);
+		for (j = 1; j < n; j++) {
+			risc = cx_read(ch->ctrl_start + 4 * (i + j));
+			printk(KERN_WARNING "%s:   iq %x: 0x%08x [ arg #%d ]\n",
+			       dev->name, i+j, risc, j);
+		}
+	}
+
+	printk(KERN_WARNING "%s: fifo: 0x%08x -> 0x%x\n",
+	       dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
+	printk(KERN_WARNING "%s: ctrl: 0x%08x -> 0x%x\n",
+	       dev->name, ch->ctrl_start, ch->ctrl_start + 6*16);
+	printk(KERN_WARNING "%s:   ptr1_reg: 0x%08x\n",
+	       dev->name, cx_read(ch->ptr1_reg));
+	printk(KERN_WARNING "%s:   ptr2_reg: 0x%08x\n",
+	       dev->name, cx_read(ch->ptr2_reg));
+	printk(KERN_WARNING "%s:   cnt1_reg: 0x%08x\n",
+	       dev->name, cx_read(ch->cnt1_reg));
+	printk(KERN_WARNING "%s:   cnt2_reg: 0x%08x\n",
+	       dev->name, cx_read(ch->cnt2_reg));
+}
+
+static void cx23885_risc_disasm(struct cx23885_tsport *port,
+				struct btcx_riscmem *risc)
+{
+	struct cx23885_dev *dev = port->dev;
+	unsigned int i, j, n;
+
+	printk(KERN_INFO "%s: risc disasm: %p [dma=0x%08lx]\n",
+	       dev->name, risc->cpu, (unsigned long)risc->dma);
+	for (i = 0; i < (risc->size >> 2); i += n) {
+		printk(KERN_INFO "%s:   %04d: ", dev->name, i);
+		n = cx23885_risc_decode(le32_to_cpu(risc->cpu[i]));
+		for (j = 1; j < n; j++)
+			printk(KERN_INFO "%s:   %04d: 0x%08x [ arg #%d ]\n",
+			       dev->name, i + j, risc->cpu[i + j], j);
+		if (risc->cpu[i] == cpu_to_le32(RISC_JUMP))
+			break;
+	}
+}
+
+static void cx23885_shutdown(struct cx23885_dev *dev)
+{
+	/* disable RISC controller */
+	cx_write(DEV_CNTRL2, 0);
+
+	/* Disable all IR activity */
+	cx_write(IR_CNTRL_REG, 0);
+
+	/* Disable Video A/B activity */
+	cx_write(VID_A_DMA_CTL, 0);
+	cx_write(VID_B_DMA_CTL, 0);
+	cx_write(VID_C_DMA_CTL, 0);
+
+	/* Disable Audio activity */
+	cx_write(AUD_INT_DMA_CTL, 0);
+	cx_write(AUD_EXT_DMA_CTL, 0);
+
+	/* Disable Serial port */
+	cx_write(UART_CTL, 0);
+
+	/* Disable Interrupts */
+	cx23885_irq_disable_all(dev);
+	cx_write(VID_A_INT_MSK, 0);
+	cx_write(VID_B_INT_MSK, 0);
+	cx_write(VID_C_INT_MSK, 0);
+	cx_write(AUDIO_INT_INT_MSK, 0);
+	cx_write(AUDIO_EXT_INT_MSK, 0);
+
+}
+
+static void cx23885_reset(struct cx23885_dev *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+
+	cx23885_shutdown(dev);
+
+	cx_write(PCI_INT_STAT, 0xffffffff);
+	cx_write(VID_A_INT_STAT, 0xffffffff);
+	cx_write(VID_B_INT_STAT, 0xffffffff);
+	cx_write(VID_C_INT_STAT, 0xffffffff);
+	cx_write(AUDIO_INT_INT_STAT, 0xffffffff);
+	cx_write(AUDIO_EXT_INT_STAT, 0xffffffff);
+	cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000);
+	cx_write(PAD_CTRL, 0x00500300);
+
+	mdelay(100);
+
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],
+		720*4, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], 128, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH03],
+		188*4, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH04], 128, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH05], 128, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH06],
+		188*4, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH07], 128, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH08], 128, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH09], 128, 0);
+
+	cx23885_gpio_setup(dev);
+}
+
+
+static int cx23885_pci_quirks(struct cx23885_dev *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+
+	/* The cx23885 bridge has a weird bug which causes NMI to be asserted
+	 * when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not
+	 * occur on the cx23887 bridge.
+	 */
+	if (dev->bridge == CX23885_BRIDGE_885)
+		cx_clear(RDR_TLCTL0, 1 << 4);
+
+	return 0;
+}
+
+static int get_resources(struct cx23885_dev *dev)
+{
+	if (request_mem_region(pci_resource_start(dev->pci, 0),
+			       pci_resource_len(dev->pci, 0),
+			       dev->name))
+		return 0;
+
+	printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
+		dev->name, (unsigned long long)pci_resource_start(dev->pci, 0));
+
+	return -EBUSY;
+}
+
+static void cx23885_timeout(unsigned long data);
+int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+				u32 reg, u32 mask, u32 value);
+
+static int cx23885_init_tsport(struct cx23885_dev *dev,
+	struct cx23885_tsport *port, int portno)
+{
+	dprintk(1, "%s(portno=%d)\n", __func__, portno);
+
+	/* Transport bus init dma queue  - Common settings */
+	port->dma_ctl_val        = 0x11; /* Enable RISC controller and Fifo */
+	port->ts_int_msk_val     = 0x1111; /* TS port bits for RISC */
+	port->vld_misc_val       = 0x0;
+	port->hw_sop_ctrl_val    = (0x47 << 16 | 188 << 4);
+
+	spin_lock_init(&port->slock);
+	port->dev = dev;
+	port->nr = portno;
+
+	INIT_LIST_HEAD(&port->mpegq.active);
+	INIT_LIST_HEAD(&port->mpegq.queued);
+	port->mpegq.timeout.function = cx23885_timeout;
+	port->mpegq.timeout.data = (unsigned long)port;
+	init_timer(&port->mpegq.timeout);
+
+	mutex_init(&port->frontends.lock);
+	INIT_LIST_HEAD(&port->frontends.felist);
+	port->frontends.active_fe_id = 0;
+
+	/* This should be hardcoded allow a single frontend
+	 * attachment to this tsport, keeping the -dvb.c
+	 * code clean and safe.
+	 */
+	if (!port->num_frontends)
+		port->num_frontends = 1;
+
+	switch (portno) {
+	case 1:
+		port->reg_gpcnt          = VID_B_GPCNT;
+		port->reg_gpcnt_ctl      = VID_B_GPCNT_CTL;
+		port->reg_dma_ctl        = VID_B_DMA_CTL;
+		port->reg_lngth          = VID_B_LNGTH;
+		port->reg_hw_sop_ctrl    = VID_B_HW_SOP_CTL;
+		port->reg_gen_ctrl       = VID_B_GEN_CTL;
+		port->reg_bd_pkt_status  = VID_B_BD_PKT_STATUS;
+		port->reg_sop_status     = VID_B_SOP_STATUS;
+		port->reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT;
+		port->reg_vld_misc       = VID_B_VLD_MISC;
+		port->reg_ts_clk_en      = VID_B_TS_CLK_EN;
+		port->reg_src_sel        = VID_B_SRC_SEL;
+		port->reg_ts_int_msk     = VID_B_INT_MSK;
+		port->reg_ts_int_stat    = VID_B_INT_STAT;
+		port->sram_chno          = SRAM_CH03; /* VID_B */
+		port->pci_irqmask        = 0x02; /* VID_B bit1 */
+		break;
+	case 2:
+		port->reg_gpcnt          = VID_C_GPCNT;
+		port->reg_gpcnt_ctl      = VID_C_GPCNT_CTL;
+		port->reg_dma_ctl        = VID_C_DMA_CTL;
+		port->reg_lngth          = VID_C_LNGTH;
+		port->reg_hw_sop_ctrl    = VID_C_HW_SOP_CTL;
+		port->reg_gen_ctrl       = VID_C_GEN_CTL;
+		port->reg_bd_pkt_status  = VID_C_BD_PKT_STATUS;
+		port->reg_sop_status     = VID_C_SOP_STATUS;
+		port->reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT;
+		port->reg_vld_misc       = VID_C_VLD_MISC;
+		port->reg_ts_clk_en      = VID_C_TS_CLK_EN;
+		port->reg_src_sel        = 0;
+		port->reg_ts_int_msk     = VID_C_INT_MSK;
+		port->reg_ts_int_stat    = VID_C_INT_STAT;
+		port->sram_chno          = SRAM_CH06; /* VID_C */
+		port->pci_irqmask        = 0x04; /* VID_C bit2 */
+		break;
+	default:
+		BUG();
+	}
+
+	cx23885_risc_stopper(dev->pci, &port->mpegq.stopper,
+		     port->reg_dma_ctl, port->dma_ctl_val, 0x00);
+
+	return 0;
+}
+
+static void cx23885_dev_checkrevision(struct cx23885_dev *dev)
+{
+	switch (cx_read(RDR_CFG2) & 0xff) {
+	case 0x00:
+		/* cx23885 */
+		dev->hwrevision = 0xa0;
+		break;
+	case 0x01:
+		/* CX23885-12Z */
+		dev->hwrevision = 0xa1;
+		break;
+	case 0x02:
+		/* CX23885-13Z/14Z */
+		dev->hwrevision = 0xb0;
+		break;
+	case 0x03:
+		if (dev->pci->device == 0x8880) {
+			/* CX23888-21Z/22Z */
+			dev->hwrevision = 0xc0;
+		} else {
+			/* CX23885-14Z */
+			dev->hwrevision = 0xa4;
+		}
+		break;
+	case 0x04:
+		if (dev->pci->device == 0x8880) {
+			/* CX23888-31Z */
+			dev->hwrevision = 0xd0;
+		} else {
+			/* CX23885-15Z, CX23888-31Z */
+			dev->hwrevision = 0xa5;
+		}
+		break;
+	case 0x0e:
+		/* CX23887-15Z */
+		dev->hwrevision = 0xc0;
+		break;
+	case 0x0f:
+		/* CX23887-14Z */
+		dev->hwrevision = 0xb1;
+		break;
+	default:
+		printk(KERN_ERR "%s() New hardware revision found 0x%x\n",
+			__func__, dev->hwrevision);
+	}
+	if (dev->hwrevision)
+		printk(KERN_INFO "%s() Hardware revision = 0x%02x\n",
+			__func__, dev->hwrevision);
+	else
+		printk(KERN_ERR "%s() Hardware revision unknown 0x%x\n",
+			__func__, dev->hwrevision);
+}
+
+/* Find the first v4l2_subdev member of the group id in hw */
+struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw)
+{
+	struct v4l2_subdev *result = NULL;
+	struct v4l2_subdev *sd;
+
+	spin_lock(&dev->v4l2_dev.lock);
+	v4l2_device_for_each_subdev(sd, &dev->v4l2_dev) {
+		if (sd->grp_id == hw) {
+			result = sd;
+			break;
+		}
+	}
+	spin_unlock(&dev->v4l2_dev.lock);
+	return result;
+}
+
+static int cx23885_dev_setup(struct cx23885_dev *dev)
+{
+	int i;
+
+	spin_lock_init(&dev->pci_irqmask_lock);
+
+	mutex_init(&dev->lock);
+	mutex_init(&dev->gpio_lock);
+
+	atomic_inc(&dev->refcount);
+
+	dev->nr = cx23885_devcount++;
+	sprintf(dev->name, "cx23885[%d]", dev->nr);
+
+	/* Configure the internal memory */
+	if (dev->pci->device == 0x8880) {
+		/* Could be 887 or 888, assume a default */
+		dev->bridge = CX23885_BRIDGE_887;
+		/* Apply a sensible clock frequency for the PCIe bridge */
+		dev->clk_freq = 25000000;
+		dev->sram_channels = cx23887_sram_channels;
+	} else
+	if (dev->pci->device == 0x8852) {
+		dev->bridge = CX23885_BRIDGE_885;
+		/* Apply a sensible clock frequency for the PCIe bridge */
+		dev->clk_freq = 28000000;
+		dev->sram_channels = cx23885_sram_channels;
+	} else
+		BUG();
+
+	dprintk(1, "%s() Memory configured for PCIe bridge type %d\n",
+		__func__, dev->bridge);
+
+	/* board config */
+	dev->board = UNSET;
+	if (card[dev->nr] < cx23885_bcount)
+		dev->board = card[dev->nr];
+	for (i = 0; UNSET == dev->board  &&  i < cx23885_idcount; i++)
+		if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor &&
+		    dev->pci->subsystem_device == cx23885_subids[i].subdevice)
+			dev->board = cx23885_subids[i].card;
+	if (UNSET == dev->board) {
+		dev->board = CX23885_BOARD_UNKNOWN;
+		cx23885_card_list(dev);
+	}
+
+	/* If the user specific a clk freq override, apply it */
+	if (cx23885_boards[dev->board].clk_freq > 0)
+		dev->clk_freq = cx23885_boards[dev->board].clk_freq;
+
+	dev->pci_bus  = dev->pci->bus->number;
+	dev->pci_slot = PCI_SLOT(dev->pci->devfn);
+	cx23885_irq_add(dev, 0x001f00);
+
+	/* External Master 1 Bus */
+	dev->i2c_bus[0].nr = 0;
+	dev->i2c_bus[0].dev = dev;
+	dev->i2c_bus[0].reg_stat  = I2C1_STAT;
+	dev->i2c_bus[0].reg_ctrl  = I2C1_CTRL;
+	dev->i2c_bus[0].reg_addr  = I2C1_ADDR;
+	dev->i2c_bus[0].reg_rdata = I2C1_RDATA;
+	dev->i2c_bus[0].reg_wdata = I2C1_WDATA;
+	dev->i2c_bus[0].i2c_period = (0x9d << 24); /* 100kHz */
+
+	/* External Master 2 Bus */
+	dev->i2c_bus[1].nr = 1;
+	dev->i2c_bus[1].dev = dev;
+	dev->i2c_bus[1].reg_stat  = I2C2_STAT;
+	dev->i2c_bus[1].reg_ctrl  = I2C2_CTRL;
+	dev->i2c_bus[1].reg_addr  = I2C2_ADDR;
+	dev->i2c_bus[1].reg_rdata = I2C2_RDATA;
+	dev->i2c_bus[1].reg_wdata = I2C2_WDATA;
+	dev->i2c_bus[1].i2c_period = (0x9d << 24); /* 100kHz */
+
+	/* Internal Master 3 Bus */
+	dev->i2c_bus[2].nr = 2;
+	dev->i2c_bus[2].dev = dev;
+	dev->i2c_bus[2].reg_stat  = I2C3_STAT;
+	dev->i2c_bus[2].reg_ctrl  = I2C3_CTRL;
+	dev->i2c_bus[2].reg_addr  = I2C3_ADDR;
+	dev->i2c_bus[2].reg_rdata = I2C3_RDATA;
+	dev->i2c_bus[2].reg_wdata = I2C3_WDATA;
+	dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */
+
+	if ((cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) ||
+		(cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER))
+		cx23885_init_tsport(dev, &dev->ts1, 1);
+
+	if ((cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) ||
+		(cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER))
+		cx23885_init_tsport(dev, &dev->ts2, 2);
+
+	if (get_resources(dev) < 0) {
+		printk(KERN_ERR "CORE %s No more PCIe resources for "
+		       "subsystem: %04x:%04x\n",
+		       dev->name, dev->pci->subsystem_vendor,
+		       dev->pci->subsystem_device);
+
+		cx23885_devcount--;
+		return -ENODEV;
+	}
+
+	/* PCIe stuff */
+	dev->lmmio = ioremap(pci_resource_start(dev->pci, 0),
+			     pci_resource_len(dev->pci, 0));
+
+	dev->bmmio = (u8 __iomem *)dev->lmmio;
+
+	printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+	       dev->name, dev->pci->subsystem_vendor,
+	       dev->pci->subsystem_device, cx23885_boards[dev->board].name,
+	       dev->board, card[dev->nr] == dev->board ?
+	       "insmod option" : "autodetected");
+
+	cx23885_pci_quirks(dev);
+
+	/* Assume some sensible defaults */
+	dev->tuner_type = cx23885_boards[dev->board].tuner_type;
+	dev->tuner_addr = cx23885_boards[dev->board].tuner_addr;
+	dev->tuner_bus = cx23885_boards[dev->board].tuner_bus;
+	dev->radio_type = cx23885_boards[dev->board].radio_type;
+	dev->radio_addr = cx23885_boards[dev->board].radio_addr;
+
+	dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x tuner_bus = %d\n",
+		__func__, dev->tuner_type, dev->tuner_addr, dev->tuner_bus);
+	dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n",
+		__func__, dev->radio_type, dev->radio_addr);
+
+	/* The cx23417 encoder has GPIO's that need to be initialised
+	 * before DVB, so that demodulators and tuners are out of
+	 * reset before DVB uses them.
+	 */
+	if ((cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) ||
+		(cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER))
+			cx23885_mc417_init(dev);
+
+	/* init hardware */
+	cx23885_reset(dev);
+
+	cx23885_i2c_register(&dev->i2c_bus[0]);
+	cx23885_i2c_register(&dev->i2c_bus[1]);
+	cx23885_i2c_register(&dev->i2c_bus[2]);
+	cx23885_card_setup(dev);
+	call_all(dev, core, s_power, 0);
+	cx23885_ir_init(dev);
+
+	if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
+		if (cx23885_video_register(dev) < 0) {
+			printk(KERN_ERR "%s() Failed to register analog "
+				"video adapters on VID_A\n", __func__);
+		}
+	}
+
+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
+		if (cx23885_boards[dev->board].num_fds_portb)
+			dev->ts1.num_frontends =
+				cx23885_boards[dev->board].num_fds_portb;
+		if (cx23885_dvb_register(&dev->ts1) < 0) {
+			printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n",
+			       __func__);
+		}
+	} else
+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) {
+		if (cx23885_417_register(dev) < 0) {
+			printk(KERN_ERR
+				"%s() Failed to register 417 on VID_B\n",
+			       __func__);
+		}
+	}
+
+	if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
+		if (cx23885_boards[dev->board].num_fds_portc)
+			dev->ts2.num_frontends =
+				cx23885_boards[dev->board].num_fds_portc;
+		if (cx23885_dvb_register(&dev->ts2) < 0) {
+			printk(KERN_ERR
+				"%s() Failed to register dvb on VID_C\n",
+			       __func__);
+		}
+	} else
+	if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) {
+		if (cx23885_417_register(dev) < 0) {
+			printk(KERN_ERR
+				"%s() Failed to register 417 on VID_C\n",
+			       __func__);
+		}
+	}
+
+	cx23885_dev_checkrevision(dev);
+
+	/* disable MSI for NetUP cards, otherwise CI is not working */
+	if (cx23885_boards[dev->board].ci_type > 0)
+		cx_clear(RDR_RDRCTL1, 1 << 8);
+
+	switch (dev->board) {
+	case CX23885_BOARD_TEVII_S470:
+	case CX23885_BOARD_TEVII_S471:
+		cx_clear(RDR_RDRCTL1, 1 << 8);
+		break;
+	}
+
+	return 0;
+}
+
+static void cx23885_dev_unregister(struct cx23885_dev *dev)
+{
+	release_mem_region(pci_resource_start(dev->pci, 0),
+			   pci_resource_len(dev->pci, 0));
+
+	if (!atomic_dec_and_test(&dev->refcount))
+		return;
+
+	if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO)
+		cx23885_video_unregister(dev);
+
+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+		cx23885_dvb_unregister(&dev->ts1);
+
+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+		cx23885_417_unregister(dev);
+
+	if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
+		cx23885_dvb_unregister(&dev->ts2);
+
+	if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)
+		cx23885_417_unregister(dev);
+
+	cx23885_i2c_unregister(&dev->i2c_bus[2]);
+	cx23885_i2c_unregister(&dev->i2c_bus[1]);
+	cx23885_i2c_unregister(&dev->i2c_bus[0]);
+
+	iounmap(dev->lmmio);
+}
+
+static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
+			       unsigned int offset, u32 sync_line,
+			       unsigned int bpl, unsigned int padding,
+			       unsigned int lines,  unsigned int lpi)
+{
+	struct scatterlist *sg;
+	unsigned int line, todo, sol;
+
+	/* sync instruction */
+	if (sync_line != NO_SYNC_LINE)
+		*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
+
+	/* scan lines */
+	sg = sglist;
+	for (line = 0; line < lines; line++) {
+		while (offset && offset >= sg_dma_len(sg)) {
+			offset -= sg_dma_len(sg);
+			sg++;
+		}
+
+		if (lpi && line > 0 && !(line % lpi))
+			sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC;
+		else
+			sol = RISC_SOL;
+
+		if (bpl <= sg_dma_len(sg)-offset) {
+			/* fits into current chunk */
+			*(rp++) = cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl);
+			*(rp++) = cpu_to_le32(sg_dma_address(sg)+offset);
+			*(rp++) = cpu_to_le32(0); /* bits 63-32 */
+			offset += bpl;
+		} else {
+			/* scanline needs to be split */
+			todo = bpl;
+			*(rp++) = cpu_to_le32(RISC_WRITE|sol|
+					    (sg_dma_len(sg)-offset));
+			*(rp++) = cpu_to_le32(sg_dma_address(sg)+offset);
+			*(rp++) = cpu_to_le32(0); /* bits 63-32 */
+			todo -= (sg_dma_len(sg)-offset);
+			offset = 0;
+			sg++;
+			while (todo > sg_dma_len(sg)) {
+				*(rp++) = cpu_to_le32(RISC_WRITE|
+						    sg_dma_len(sg));
+				*(rp++) = cpu_to_le32(sg_dma_address(sg));
+				*(rp++) = cpu_to_le32(0); /* bits 63-32 */
+				todo -= sg_dma_len(sg);
+				sg++;
+			}
+			*(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
+			*(rp++) = cpu_to_le32(sg_dma_address(sg));
+			*(rp++) = cpu_to_le32(0); /* bits 63-32 */
+			offset += todo;
+		}
+		offset += padding;
+	}
+
+	return rp;
+}
+
+int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+			struct scatterlist *sglist, unsigned int top_offset,
+			unsigned int bottom_offset, unsigned int bpl,
+			unsigned int padding, unsigned int lines)
+{
+	u32 instructions, fields;
+	__le32 *rp;
+	int rc;
+
+	fields = 0;
+	if (UNSET != top_offset)
+		fields++;
+	if (UNSET != bottom_offset)
+		fields++;
+
+	/* estimate risc mem: worst case is one write per page border +
+	   one write per scan line + syncs + jump (all 2 dwords).  Padding
+	   can cause next bpl to start close to a page border.  First DMA
+	   region may be smaller than PAGE_SIZE */
+	/* write and jump need and extra dword */
+	instructions  = fields * (1 + ((bpl + padding) * lines)
+		/ PAGE_SIZE + lines);
+	instructions += 2;
+	rc = btcx_riscmem_alloc(pci, risc, instructions*12);
+	if (rc < 0)
+		return rc;
+
+	/* write risc instructions */
+	rp = risc->cpu;
+	if (UNSET != top_offset)
+		rp = cx23885_risc_field(rp, sglist, top_offset, 0,
+					bpl, padding, lines, 0);
+	if (UNSET != bottom_offset)
+		rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
+					bpl, padding, lines, 0);
+
+	/* save pointer to jmp instruction address */
+	risc->jmp = rp;
+	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
+	return 0;
+}
+
+int cx23885_risc_databuffer(struct pci_dev *pci,
+				   struct btcx_riscmem *risc,
+				   struct scatterlist *sglist,
+				   unsigned int bpl,
+				   unsigned int lines, unsigned int lpi)
+{
+	u32 instructions;
+	__le32 *rp;
+	int rc;
+
+	/* estimate risc mem: worst case is one write per page border +
+	   one write per scan line + syncs + jump (all 2 dwords).  Here
+	   there is no padding and no sync.  First DMA region may be smaller
+	   than PAGE_SIZE */
+	/* Jump and write need an extra dword */
+	instructions  = 1 + (bpl * lines) / PAGE_SIZE + lines;
+	instructions += 1;
+
+	rc = btcx_riscmem_alloc(pci, risc, instructions*12);
+	if (rc < 0)
+		return rc;
+
+	/* write risc instructions */
+	rp = risc->cpu;
+	rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE,
+				bpl, 0, lines, lpi);
+
+	/* save pointer to jmp instruction address */
+	risc->jmp = rp;
+	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
+	return 0;
+}
+
+int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+			struct scatterlist *sglist, unsigned int top_offset,
+			unsigned int bottom_offset, unsigned int bpl,
+			unsigned int padding, unsigned int lines)
+{
+	u32 instructions, fields;
+	__le32 *rp;
+	int rc;
+
+	fields = 0;
+	if (UNSET != top_offset)
+		fields++;
+	if (UNSET != bottom_offset)
+		fields++;
+
+	/* estimate risc mem: worst case is one write per page border +
+	   one write per scan line + syncs + jump (all 2 dwords).  Padding
+	   can cause next bpl to start close to a page border.  First DMA
+	   region may be smaller than PAGE_SIZE */
+	/* write and jump need and extra dword */
+	instructions  = fields * (1 + ((bpl + padding) * lines)
+		/ PAGE_SIZE + lines);
+	instructions += 2;
+	rc = btcx_riscmem_alloc(pci, risc, instructions*12);
+	if (rc < 0)
+		return rc;
+	/* write risc instructions */
+	rp = risc->cpu;
+
+	/* Sync to line 6, so US CC line 21 will appear in line '12'
+	 * in the userland vbi payload */
+	if (UNSET != top_offset)
+		rp = cx23885_risc_field(rp, sglist, top_offset, 6,
+					bpl, padding, lines, 0);
+
+	if (UNSET != bottom_offset)
+		rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x207,
+					bpl, padding, lines, 0);
+
+
+
+	/* save pointer to jmp instruction address */
+	risc->jmp = rp;
+	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
+	return 0;
+}
+
+
+int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+				u32 reg, u32 mask, u32 value)
+{
+	__le32 *rp;
+	int rc;
+
+	rc = btcx_riscmem_alloc(pci, risc, 4*16);
+	if (rc < 0)
+		return rc;
+
+	/* write risc instructions */
+	rp = risc->cpu;
+	*(rp++) = cpu_to_le32(RISC_WRITECR  | RISC_IRQ2);
+	*(rp++) = cpu_to_le32(reg);
+	*(rp++) = cpu_to_le32(value);
+	*(rp++) = cpu_to_le32(mask);
+	*(rp++) = cpu_to_le32(RISC_JUMP);
+	*(rp++) = cpu_to_le32(risc->dma);
+	*(rp++) = cpu_to_le32(0); /* bits 63-32 */
+	return 0;
+}
+
+void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
+{
+	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+
+	BUG_ON(in_interrupt());
+	videobuf_waiton(q, &buf->vb, 0, 0);
+	videobuf_dma_unmap(q->dev, dma);
+	videobuf_dma_free(dma);
+	btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
+{
+	struct cx23885_dev *dev = port->dev;
+
+	dprintk(1, "%s() Register Dump\n", __func__);
+	dprintk(1, "%s() DEV_CNTRL2               0x%08X\n", __func__,
+		cx_read(DEV_CNTRL2));
+	dprintk(1, "%s() PCI_INT_MSK              0x%08X\n", __func__,
+		cx23885_irq_get_mask(dev));
+	dprintk(1, "%s() AUD_INT_INT_MSK          0x%08X\n", __func__,
+		cx_read(AUDIO_INT_INT_MSK));
+	dprintk(1, "%s() AUD_INT_DMA_CTL          0x%08X\n", __func__,
+		cx_read(AUD_INT_DMA_CTL));
+	dprintk(1, "%s() AUD_EXT_INT_MSK          0x%08X\n", __func__,
+		cx_read(AUDIO_EXT_INT_MSK));
+	dprintk(1, "%s() AUD_EXT_DMA_CTL          0x%08X\n", __func__,
+		cx_read(AUD_EXT_DMA_CTL));
+	dprintk(1, "%s() PAD_CTRL                 0x%08X\n", __func__,
+		cx_read(PAD_CTRL));
+	dprintk(1, "%s() ALT_PIN_OUT_SEL          0x%08X\n", __func__,
+		cx_read(ALT_PIN_OUT_SEL));
+	dprintk(1, "%s() GPIO2                    0x%08X\n", __func__,
+		cx_read(GPIO2));
+	dprintk(1, "%s() gpcnt(0x%08X)          0x%08X\n", __func__,
+		port->reg_gpcnt, cx_read(port->reg_gpcnt));
+	dprintk(1, "%s() gpcnt_ctl(0x%08X)      0x%08x\n", __func__,
+		port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl));
+	dprintk(1, "%s() dma_ctl(0x%08X)        0x%08x\n", __func__,
+		port->reg_dma_ctl, cx_read(port->reg_dma_ctl));
+	if (port->reg_src_sel)
+		dprintk(1, "%s() src_sel(0x%08X)        0x%08x\n", __func__,
+			port->reg_src_sel, cx_read(port->reg_src_sel));
+	dprintk(1, "%s() lngth(0x%08X)          0x%08x\n", __func__,
+		port->reg_lngth, cx_read(port->reg_lngth));
+	dprintk(1, "%s() hw_sop_ctrl(0x%08X)    0x%08x\n", __func__,
+		port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl));
+	dprintk(1, "%s() gen_ctrl(0x%08X)       0x%08x\n", __func__,
+		port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl));
+	dprintk(1, "%s() bd_pkt_status(0x%08X)  0x%08x\n", __func__,
+		port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status));
+	dprintk(1, "%s() sop_status(0x%08X)     0x%08x\n", __func__,
+		port->reg_sop_status, cx_read(port->reg_sop_status));
+	dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __func__,
+		port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat));
+	dprintk(1, "%s() vld_misc(0x%08X)       0x%08x\n", __func__,
+		port->reg_vld_misc, cx_read(port->reg_vld_misc));
+	dprintk(1, "%s() ts_clk_en(0x%08X)      0x%08x\n", __func__,
+		port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en));
+	dprintk(1, "%s() ts_int_msk(0x%08X)     0x%08x\n", __func__,
+		port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk));
+}
+
+static int cx23885_start_dma(struct cx23885_tsport *port,
+			     struct cx23885_dmaqueue *q,
+			     struct cx23885_buffer   *buf)
+{
+	struct cx23885_dev *dev = port->dev;
+	u32 reg;
+
+	dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__,
+		buf->vb.width, buf->vb.height, buf->vb.field);
+
+	/* Stop the fifo and risc engine for this port */
+	cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
+
+	/* setup fifo + format */
+	cx23885_sram_channel_setup(dev,
+				   &dev->sram_channels[port->sram_chno],
+				   port->ts_packet_size, buf->risc.dma);
+	if (debug > 5) {
+		cx23885_sram_channel_dump(dev,
+			&dev->sram_channels[port->sram_chno]);
+		cx23885_risc_disasm(port, &buf->risc);
+	}
+
+	/* write TS length to chip */
+	cx_write(port->reg_lngth, buf->vb.width);
+
+	if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
+		(!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) {
+		printk("%s() Unsupported .portb/c (0x%08x)/(0x%08x)\n",
+			__func__,
+			cx23885_boards[dev->board].portb,
+			cx23885_boards[dev->board].portc);
+		return -EINVAL;
+	}
+
+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+		cx23885_av_clk(dev, 0);
+
+	udelay(100);
+
+	/* If the port supports SRC SELECT, configure it */
+	if (port->reg_src_sel)
+		cx_write(port->reg_src_sel, port->src_sel_val);
+
+	cx_write(port->reg_hw_sop_ctrl, port->hw_sop_ctrl_val);
+	cx_write(port->reg_ts_clk_en, port->ts_clk_en_val);
+	cx_write(port->reg_vld_misc, port->vld_misc_val);
+	cx_write(port->reg_gen_ctrl, port->gen_ctrl_val);
+	udelay(100);
+
+	/* NOTE: this is 2 (reserved) for portb, does it matter? */
+	/* reset counter to zero */
+	cx_write(port->reg_gpcnt_ctl, 3);
+	q->count = 1;
+
+	/* Set VIDB pins to input */
+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
+		reg = cx_read(PAD_CTRL);
+		reg &= ~0x3; /* Clear TS1_OE & TS1_SOP_OE */
+		cx_write(PAD_CTRL, reg);
+	}
+
+	/* Set VIDC pins to input */
+	if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
+		reg = cx_read(PAD_CTRL);
+		reg &= ~0x4; /* Clear TS2_SOP_OE */
+		cx_write(PAD_CTRL, reg);
+	}
+
+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) {
+
+		reg = cx_read(PAD_CTRL);
+		reg = reg & ~0x1;    /* Clear TS1_OE */
+
+		/* FIXME, bit 2 writing here is questionable */
+		/* set TS1_SOP_OE and TS1_OE_HI */
+		reg = reg | 0xa;
+		cx_write(PAD_CTRL, reg);
+
+		/* FIXME and these two registers should be documented. */
+		cx_write(CLK_DELAY, cx_read(CLK_DELAY) | 0x80000011);
+		cx_write(ALT_PIN_OUT_SEL, 0x10100045);
+	}
+
+	switch (dev->bridge) {
+	case CX23885_BRIDGE_885:
+	case CX23885_BRIDGE_887:
+	case CX23885_BRIDGE_888:
+		/* enable irqs */
+		dprintk(1, "%s() enabling TS int's and DMA\n", __func__);
+		cx_set(port->reg_ts_int_msk,  port->ts_int_msk_val);
+		cx_set(port->reg_dma_ctl, port->dma_ctl_val);
+		cx23885_irq_add(dev, port->pci_irqmask);
+		cx23885_irq_enable_all(dev);
+		break;
+	default:
+		BUG();
+	}
+
+	cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */
+
+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+		cx23885_av_clk(dev, 1);
+
+	if (debug > 4)
+		cx23885_tsport_reg_dump(port);
+
+	return 0;
+}
+
+static int cx23885_stop_dma(struct cx23885_tsport *port)
+{
+	struct cx23885_dev *dev = port->dev;
+	u32 reg;
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* Stop interrupts and DMA */
+	cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val);
+	cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
+
+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) {
+
+		reg = cx_read(PAD_CTRL);
+
+		/* Set TS1_OE */
+		reg = reg | 0x1;
+
+		/* clear TS1_SOP_OE and TS1_OE_HI */
+		reg = reg & ~0xa;
+		cx_write(PAD_CTRL, reg);
+		cx_write(port->reg_src_sel, 0);
+		cx_write(port->reg_gen_ctrl, 8);
+
+	}
+
+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+		cx23885_av_clk(dev, 0);
+
+	return 0;
+}
+
+int cx23885_restart_queue(struct cx23885_tsport *port,
+				struct cx23885_dmaqueue *q)
+{
+	struct cx23885_dev *dev = port->dev;
+	struct cx23885_buffer *buf;
+
+	dprintk(5, "%s()\n", __func__);
+	if (list_empty(&q->active)) {
+		struct cx23885_buffer *prev;
+		prev = NULL;
+
+		dprintk(5, "%s() queue is empty\n", __func__);
+
+		for (;;) {
+			if (list_empty(&q->queued))
+				return 0;
+			buf = list_entry(q->queued.next, struct cx23885_buffer,
+					 vb.queue);
+			if (NULL == prev) {
+				list_del(&buf->vb.queue);
+				list_add_tail(&buf->vb.queue, &q->active);
+				cx23885_start_dma(port, q, buf);
+				buf->vb.state = VIDEOBUF_ACTIVE;
+				buf->count    = q->count++;
+				mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+				dprintk(5, "[%p/%d] restart_queue - f/active\n",
+					buf, buf->vb.i);
+
+			} else if (prev->vb.width  == buf->vb.width  &&
+				   prev->vb.height == buf->vb.height &&
+				   prev->fmt       == buf->fmt) {
+				list_del(&buf->vb.queue);
+				list_add_tail(&buf->vb.queue, &q->active);
+				buf->vb.state = VIDEOBUF_ACTIVE;
+				buf->count    = q->count++;
+				prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+				/* 64 bit bits 63-32 */
+				prev->risc.jmp[2] = cpu_to_le32(0);
+				dprintk(5, "[%p/%d] restart_queue - m/active\n",
+					buf, buf->vb.i);
+			} else {
+				return 0;
+			}
+			prev = buf;
+		}
+		return 0;
+	}
+
+	buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
+	dprintk(2, "restart_queue [%p/%d]: restart dma\n",
+		buf, buf->vb.i);
+	cx23885_start_dma(port, q, buf);
+	list_for_each_entry(buf, &q->active, vb.queue)
+		buf->count = q->count++;
+	mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
+			struct cx23885_buffer *buf, enum v4l2_field field)
+{
+	struct cx23885_dev *dev = port->dev;
+	int size = port->ts_packet_size * port->ts_packet_count;
+	int rc;
+
+	dprintk(1, "%s: %p\n", __func__, buf);
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+		return -EINVAL;
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		buf->vb.width  = port->ts_packet_size;
+		buf->vb.height = port->ts_packet_count;
+		buf->vb.size   = size;
+		buf->vb.field  = field /*V4L2_FIELD_TOP*/;
+
+		rc = videobuf_iolock(q, &buf->vb, NULL);
+		if (0 != rc)
+			goto fail;
+		cx23885_risc_databuffer(dev->pci, &buf->risc,
+					videobuf_to_dma(&buf->vb)->sglist,
+					buf->vb.width, buf->vb.height, 0);
+	}
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+ fail:
+	cx23885_free_buffer(q, buf);
+	return rc;
+}
+
+void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
+{
+	struct cx23885_buffer    *prev;
+	struct cx23885_dev *dev = port->dev;
+	struct cx23885_dmaqueue  *cx88q = &port->mpegq;
+
+	/* add jump to stopper */
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+	buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma);
+	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
+
+	if (list_empty(&cx88q->active)) {
+		dprintk(1, "queue is empty - first active\n");
+		list_add_tail(&buf->vb.queue, &cx88q->active);
+		cx23885_start_dma(port, cx88q, buf);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		buf->count    = cx88q->count++;
+		mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT);
+		dprintk(1, "[%p/%d] %s - first active\n",
+			buf, buf->vb.i, __func__);
+	} else {
+		dprintk(1, "queue is not empty - append to active\n");
+		prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
+				  vb.queue);
+		list_add_tail(&buf->vb.queue, &cx88q->active);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		buf->count    = cx88q->count++;
+		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+		prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
+		dprintk(1, "[%p/%d] %s - append to active\n",
+			 buf, buf->vb.i, __func__);
+	}
+}
+
+/* ----------------------------------------------------------- */
+
+static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
+			      int restart)
+{
+	struct cx23885_dev *dev = port->dev;
+	struct cx23885_dmaqueue *q = &port->mpegq;
+	struct cx23885_buffer *buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->slock, flags);
+	while (!list_empty(&q->active)) {
+		buf = list_entry(q->active.next, struct cx23885_buffer,
+				 vb.queue);
+		list_del(&buf->vb.queue);
+		buf->vb.state = VIDEOBUF_ERROR;
+		wake_up(&buf->vb.done);
+		dprintk(1, "[%p/%d] %s - dma=0x%08lx\n",
+			buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
+	}
+	if (restart) {
+		dprintk(1, "restarting queue\n");
+		cx23885_restart_queue(port, q);
+	}
+	spin_unlock_irqrestore(&port->slock, flags);
+}
+
+void cx23885_cancel_buffers(struct cx23885_tsport *port)
+{
+	struct cx23885_dev *dev = port->dev;
+	struct cx23885_dmaqueue *q = &port->mpegq;
+
+	dprintk(1, "%s()\n", __func__);
+	del_timer_sync(&q->timeout);
+	cx23885_stop_dma(port);
+	do_cancel_buffers(port, "cancel", 0);
+}
+
+static void cx23885_timeout(unsigned long data)
+{
+	struct cx23885_tsport *port = (struct cx23885_tsport *)data;
+	struct cx23885_dev *dev = port->dev;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (debug > 5)
+		cx23885_sram_channel_dump(dev,
+			&dev->sram_channels[port->sram_chno]);
+
+	cx23885_stop_dma(port);
+	do_cancel_buffers(port, "timeout", 1);
+}
+
+int cx23885_irq_417(struct cx23885_dev *dev, u32 status)
+{
+	/* FIXME: port1 assumption here. */
+	struct cx23885_tsport *port = &dev->ts1;
+	int count = 0;
+	int handled = 0;
+
+	if (status == 0)
+		return handled;
+
+	count = cx_read(port->reg_gpcnt);
+	dprintk(7, "status: 0x%08x  mask: 0x%08x count: 0x%x\n",
+		status, cx_read(port->reg_ts_int_msk), count);
+
+	if ((status & VID_B_MSK_BAD_PKT)         ||
+		(status & VID_B_MSK_OPC_ERR)     ||
+		(status & VID_B_MSK_VBI_OPC_ERR) ||
+		(status & VID_B_MSK_SYNC)        ||
+		(status & VID_B_MSK_VBI_SYNC)    ||
+		(status & VID_B_MSK_OF)          ||
+		(status & VID_B_MSK_VBI_OF)) {
+		printk(KERN_ERR "%s: V4L mpeg risc op code error, status "
+			"= 0x%x\n", dev->name, status);
+		if (status & VID_B_MSK_BAD_PKT)
+			dprintk(1, "        VID_B_MSK_BAD_PKT\n");
+		if (status & VID_B_MSK_OPC_ERR)
+			dprintk(1, "        VID_B_MSK_OPC_ERR\n");
+		if (status & VID_B_MSK_VBI_OPC_ERR)
+			dprintk(1, "        VID_B_MSK_VBI_OPC_ERR\n");
+		if (status & VID_B_MSK_SYNC)
+			dprintk(1, "        VID_B_MSK_SYNC\n");
+		if (status & VID_B_MSK_VBI_SYNC)
+			dprintk(1, "        VID_B_MSK_VBI_SYNC\n");
+		if (status & VID_B_MSK_OF)
+			dprintk(1, "        VID_B_MSK_OF\n");
+		if (status & VID_B_MSK_VBI_OF)
+			dprintk(1, "        VID_B_MSK_VBI_OF\n");
+
+		cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
+		cx23885_sram_channel_dump(dev,
+			&dev->sram_channels[port->sram_chno]);
+		cx23885_417_check_encoder(dev);
+	} else if (status & VID_B_MSK_RISCI1) {
+		dprintk(7, "        VID_B_MSK_RISCI1\n");
+		spin_lock(&port->slock);
+		cx23885_wakeup(port, &port->mpegq, count);
+		spin_unlock(&port->slock);
+	} else if (status & VID_B_MSK_RISCI2) {
+		dprintk(7, "        VID_B_MSK_RISCI2\n");
+		spin_lock(&port->slock);
+		cx23885_restart_queue(port, &port->mpegq);
+		spin_unlock(&port->slock);
+	}
+	if (status) {
+		cx_write(port->reg_ts_int_stat, status);
+		handled = 1;
+	}
+
+	return handled;
+}
+
+static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status)
+{
+	struct cx23885_dev *dev = port->dev;
+	int handled = 0;
+	u32 count;
+
+	if ((status & VID_BC_MSK_OPC_ERR) ||
+		(status & VID_BC_MSK_BAD_PKT) ||
+		(status & VID_BC_MSK_SYNC) ||
+		(status & VID_BC_MSK_OF)) {
+
+		if (status & VID_BC_MSK_OPC_ERR)
+			dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n",
+				VID_BC_MSK_OPC_ERR);
+
+		if (status & VID_BC_MSK_BAD_PKT)
+			dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n",
+				VID_BC_MSK_BAD_PKT);
+
+		if (status & VID_BC_MSK_SYNC)
+			dprintk(7, " (VID_BC_MSK_SYNC    0x%08x)\n",
+				VID_BC_MSK_SYNC);
+
+		if (status & VID_BC_MSK_OF)
+			dprintk(7, " (VID_BC_MSK_OF      0x%08x)\n",
+				VID_BC_MSK_OF);
+
+		printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name);
+
+		cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
+		cx23885_sram_channel_dump(dev,
+			&dev->sram_channels[port->sram_chno]);
+
+	} else if (status & VID_BC_MSK_RISCI1) {
+
+		dprintk(7, " (RISCI1            0x%08x)\n", VID_BC_MSK_RISCI1);
+
+		spin_lock(&port->slock);
+		count = cx_read(port->reg_gpcnt);
+		cx23885_wakeup(port, &port->mpegq, count);
+		spin_unlock(&port->slock);
+
+	} else if (status & VID_BC_MSK_RISCI2) {
+
+		dprintk(7, " (RISCI2            0x%08x)\n", VID_BC_MSK_RISCI2);
+
+		spin_lock(&port->slock);
+		cx23885_restart_queue(port, &port->mpegq);
+		spin_unlock(&port->slock);
+
+	}
+	if (status) {
+		cx_write(port->reg_ts_int_stat, status);
+		handled = 1;
+	}
+
+	return handled;
+}
+
+static irqreturn_t cx23885_irq(int irq, void *dev_id)
+{
+	struct cx23885_dev *dev = dev_id;
+	struct cx23885_tsport *ts1 = &dev->ts1;
+	struct cx23885_tsport *ts2 = &dev->ts2;
+	u32 pci_status, pci_mask;
+	u32 vida_status, vida_mask;
+	u32 audint_status, audint_mask;
+	u32 ts1_status, ts1_mask;
+	u32 ts2_status, ts2_mask;
+	int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0;
+	int audint_count = 0;
+	bool subdev_handled;
+
+	pci_status = cx_read(PCI_INT_STAT);
+	pci_mask = cx23885_irq_get_mask(dev);
+	vida_status = cx_read(VID_A_INT_STAT);
+	vida_mask = cx_read(VID_A_INT_MSK);
+	audint_status = cx_read(AUDIO_INT_INT_STAT);
+	audint_mask = cx_read(AUDIO_INT_INT_MSK);
+	ts1_status = cx_read(VID_B_INT_STAT);
+	ts1_mask = cx_read(VID_B_INT_MSK);
+	ts2_status = cx_read(VID_C_INT_STAT);
+	ts2_mask = cx_read(VID_C_INT_MSK);
+
+	if ((pci_status == 0) && (ts2_status == 0) && (ts1_status == 0))
+		goto out;
+
+	vida_count = cx_read(VID_A_GPCNT);
+	audint_count = cx_read(AUD_INT_A_GPCNT);
+	ts1_count = cx_read(ts1->reg_gpcnt);
+	ts2_count = cx_read(ts2->reg_gpcnt);
+	dprintk(7, "pci_status: 0x%08x  pci_mask: 0x%08x\n",
+		pci_status, pci_mask);
+	dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n",
+		vida_status, vida_mask, vida_count);
+	dprintk(7, "audint_status: 0x%08x audint_mask: 0x%08x count: 0x%x\n",
+		audint_status, audint_mask, audint_count);
+	dprintk(7, "ts1_status: 0x%08x  ts1_mask: 0x%08x count: 0x%x\n",
+		ts1_status, ts1_mask, ts1_count);
+	dprintk(7, "ts2_status: 0x%08x  ts2_mask: 0x%08x count: 0x%x\n",
+		ts2_status, ts2_mask, ts2_count);
+
+	if (pci_status & (PCI_MSK_RISC_RD | PCI_MSK_RISC_WR |
+			  PCI_MSK_AL_RD   | PCI_MSK_AL_WR   | PCI_MSK_APB_DMA |
+			  PCI_MSK_VID_C   | PCI_MSK_VID_B   | PCI_MSK_VID_A   |
+			  PCI_MSK_AUD_INT | PCI_MSK_AUD_EXT |
+			  PCI_MSK_GPIO0   | PCI_MSK_GPIO1   |
+			  PCI_MSK_AV_CORE | PCI_MSK_IR)) {
+
+		if (pci_status & PCI_MSK_RISC_RD)
+			dprintk(7, " (PCI_MSK_RISC_RD   0x%08x)\n",
+				PCI_MSK_RISC_RD);
+
+		if (pci_status & PCI_MSK_RISC_WR)
+			dprintk(7, " (PCI_MSK_RISC_WR   0x%08x)\n",
+				PCI_MSK_RISC_WR);
+
+		if (pci_status & PCI_MSK_AL_RD)
+			dprintk(7, " (PCI_MSK_AL_RD     0x%08x)\n",
+				PCI_MSK_AL_RD);
+
+		if (pci_status & PCI_MSK_AL_WR)
+			dprintk(7, " (PCI_MSK_AL_WR     0x%08x)\n",
+				PCI_MSK_AL_WR);
+
+		if (pci_status & PCI_MSK_APB_DMA)
+			dprintk(7, " (PCI_MSK_APB_DMA   0x%08x)\n",
+				PCI_MSK_APB_DMA);
+
+		if (pci_status & PCI_MSK_VID_C)
+			dprintk(7, " (PCI_MSK_VID_C     0x%08x)\n",
+				PCI_MSK_VID_C);
+
+		if (pci_status & PCI_MSK_VID_B)
+			dprintk(7, " (PCI_MSK_VID_B     0x%08x)\n",
+				PCI_MSK_VID_B);
+
+		if (pci_status & PCI_MSK_VID_A)
+			dprintk(7, " (PCI_MSK_VID_A     0x%08x)\n",
+				PCI_MSK_VID_A);
+
+		if (pci_status & PCI_MSK_AUD_INT)
+			dprintk(7, " (PCI_MSK_AUD_INT   0x%08x)\n",
+				PCI_MSK_AUD_INT);
+
+		if (pci_status & PCI_MSK_AUD_EXT)
+			dprintk(7, " (PCI_MSK_AUD_EXT   0x%08x)\n",
+				PCI_MSK_AUD_EXT);
+
+		if (pci_status & PCI_MSK_GPIO0)
+			dprintk(7, " (PCI_MSK_GPIO0     0x%08x)\n",
+				PCI_MSK_GPIO0);
+
+		if (pci_status & PCI_MSK_GPIO1)
+			dprintk(7, " (PCI_MSK_GPIO1     0x%08x)\n",
+				PCI_MSK_GPIO1);
+
+		if (pci_status & PCI_MSK_AV_CORE)
+			dprintk(7, " (PCI_MSK_AV_CORE   0x%08x)\n",
+				PCI_MSK_AV_CORE);
+
+		if (pci_status & PCI_MSK_IR)
+			dprintk(7, " (PCI_MSK_IR        0x%08x)\n",
+				PCI_MSK_IR);
+	}
+
+	if (cx23885_boards[dev->board].ci_type == 1 &&
+			(pci_status & (PCI_MSK_GPIO1 | PCI_MSK_GPIO0)))
+		handled += netup_ci_slot_status(dev, pci_status);
+
+	if (cx23885_boards[dev->board].ci_type == 2 &&
+			(pci_status & PCI_MSK_GPIO0))
+		handled += altera_ci_irq(dev);
+
+	if (ts1_status) {
+		if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+			handled += cx23885_irq_ts(ts1, ts1_status);
+		else
+		if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+			handled += cx23885_irq_417(dev, ts1_status);
+	}
+
+	if (ts2_status) {
+		if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
+			handled += cx23885_irq_ts(ts2, ts2_status);
+		else
+		if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)
+			handled += cx23885_irq_417(dev, ts2_status);
+	}
+
+	if (vida_status)
+		handled += cx23885_video_irq(dev, vida_status);
+
+	if (audint_status)
+		handled += cx23885_audio_irq(dev, audint_status, audint_mask);
+
+	if (pci_status & PCI_MSK_IR) {
+		subdev_handled = false;
+		v4l2_subdev_call(dev->sd_ir, core, interrupt_service_routine,
+				 pci_status, &subdev_handled);
+		if (subdev_handled)
+			handled++;
+	}
+
+	if ((pci_status & pci_mask) & PCI_MSK_AV_CORE) {
+		cx23885_irq_disable(dev, PCI_MSK_AV_CORE);
+		if (!schedule_work(&dev->cx25840_work))
+			printk(KERN_ERR "%s: failed to set up deferred work for"
+			       " AV Core/IR interrupt. Interrupt is disabled"
+			       " and won't be re-enabled\n", dev->name);
+		handled++;
+	}
+
+	if (handled)
+		cx_write(PCI_INT_STAT, pci_status);
+out:
+	return IRQ_RETVAL(handled);
+}
+
+static void cx23885_v4l2_dev_notify(struct v4l2_subdev *sd,
+				    unsigned int notification, void *arg)
+{
+	struct cx23885_dev *dev;
+
+	if (sd == NULL)
+		return;
+
+	dev = to_cx23885(sd->v4l2_dev);
+
+	switch (notification) {
+	case V4L2_SUBDEV_IR_RX_NOTIFY: /* Possibly called in an IRQ context */
+		if (sd == dev->sd_ir)
+			cx23885_ir_rx_v4l2_dev_notify(sd, *(u32 *)arg);
+		break;
+	case V4L2_SUBDEV_IR_TX_NOTIFY: /* Possibly called in an IRQ context */
+		if (sd == dev->sd_ir)
+			cx23885_ir_tx_v4l2_dev_notify(sd, *(u32 *)arg);
+		break;
+	}
+}
+
+static void cx23885_v4l2_dev_notify_init(struct cx23885_dev *dev)
+{
+	INIT_WORK(&dev->cx25840_work, cx23885_av_work_handler);
+	INIT_WORK(&dev->ir_rx_work, cx23885_ir_rx_work_handler);
+	INIT_WORK(&dev->ir_tx_work, cx23885_ir_tx_work_handler);
+	dev->v4l2_dev.notify = cx23885_v4l2_dev_notify;
+}
+
+static inline int encoder_on_portb(struct cx23885_dev *dev)
+{
+	return cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER;
+}
+
+static inline int encoder_on_portc(struct cx23885_dev *dev)
+{
+	return cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER;
+}
+
+/* Mask represents 32 different GPIOs, GPIO's are split into multiple
+ * registers depending on the board configuration (and whether the
+ * 417 encoder (wi it's own GPIO's) are present. Each GPIO bit will
+ * be pushed into the correct hardware register, regardless of the
+ * physical location. Certain registers are shared so we sanity check
+ * and report errors if we think we're tampering with a GPIo that might
+ * be assigned to the encoder (and used for the host bus).
+ *
+ * GPIO  2 thru  0 - On the cx23885 bridge
+ * GPIO 18 thru  3 - On the cx23417 host bus interface
+ * GPIO 23 thru 19 - On the cx25840 a/v core
+ */
+void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask)
+{
+	if (mask & 0x7)
+		cx_set(GP0_IO, mask & 0x7);
+
+	if (mask & 0x0007fff8) {
+		if (encoder_on_portb(dev) || encoder_on_portc(dev))
+			printk(KERN_ERR
+				"%s: Setting GPIO on encoder ports\n",
+				dev->name);
+		cx_set(MC417_RWD, (mask & 0x0007fff8) >> 3);
+	}
+
+	/* TODO: 23-19 */
+	if (mask & 0x00f80000)
+		printk(KERN_INFO "%s: Unsupported\n", dev->name);
+}
+
+void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask)
+{
+	if (mask & 0x00000007)
+		cx_clear(GP0_IO, mask & 0x7);
+
+	if (mask & 0x0007fff8) {
+		if (encoder_on_portb(dev) || encoder_on_portc(dev))
+			printk(KERN_ERR
+				"%s: Clearing GPIO moving on encoder ports\n",
+				dev->name);
+		cx_clear(MC417_RWD, (mask & 0x7fff8) >> 3);
+	}
+
+	/* TODO: 23-19 */
+	if (mask & 0x00f80000)
+		printk(KERN_INFO "%s: Unsupported\n", dev->name);
+}
+
+u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask)
+{
+	if (mask & 0x00000007)
+		return (cx_read(GP0_IO) >> 8) & mask & 0x7;
+
+	if (mask & 0x0007fff8) {
+		if (encoder_on_portb(dev) || encoder_on_portc(dev))
+			printk(KERN_ERR
+				"%s: Reading GPIO moving on encoder ports\n",
+				dev->name);
+		return (cx_read(MC417_RWD) & ((mask & 0x7fff8) >> 3)) << 3;
+	}
+
+	/* TODO: 23-19 */
+	if (mask & 0x00f80000)
+		printk(KERN_INFO "%s: Unsupported\n", dev->name);
+
+	return 0;
+}
+
+void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
+{
+	if ((mask & 0x00000007) && asoutput)
+		cx_set(GP0_IO, (mask & 0x7) << 16);
+	else if ((mask & 0x00000007) && !asoutput)
+		cx_clear(GP0_IO, (mask & 0x7) << 16);
+
+	if (mask & 0x0007fff8) {
+		if (encoder_on_portb(dev) || encoder_on_portc(dev))
+			printk(KERN_ERR
+				"%s: Enabling GPIO on encoder ports\n",
+				dev->name);
+	}
+
+	/* MC417_OEN is active low for output, write 1 for an input */
+	if ((mask & 0x0007fff8) && asoutput)
+		cx_clear(MC417_OEN, (mask & 0x7fff8) >> 3);
+
+	else if ((mask & 0x0007fff8) && !asoutput)
+		cx_set(MC417_OEN, (mask & 0x7fff8) >> 3);
+
+	/* TODO: 23-19 */
+}
+
+static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
+				     const struct pci_device_id *pci_id)
+{
+	struct cx23885_dev *dev;
+	int err;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (NULL == dev)
+		return -ENOMEM;
+
+	err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
+	if (err < 0)
+		goto fail_free;
+
+	/* Prepare to handle notifications from subdevices */
+	cx23885_v4l2_dev_notify_init(dev);
+
+	/* pci init */
+	dev->pci = pci_dev;
+	if (pci_enable_device(pci_dev)) {
+		err = -EIO;
+		goto fail_unreg;
+	}
+
+	if (cx23885_dev_setup(dev) < 0) {
+		err = -EINVAL;
+		goto fail_unreg;
+	}
+
+	/* print pci info */
+	dev->pci_rev = pci_dev->revision;
+	pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
+	printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
+	       "latency: %d, mmio: 0x%llx\n", dev->name,
+	       pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
+	       dev->pci_lat,
+		(unsigned long long)pci_resource_start(pci_dev, 0));
+
+	pci_set_master(pci_dev);
+	if (!pci_dma_supported(pci_dev, 0xffffffff)) {
+		printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
+		err = -EIO;
+		goto fail_irq;
+	}
+
+	err = request_irq(pci_dev->irq, cx23885_irq,
+			  IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+	if (err < 0) {
+		printk(KERN_ERR "%s: can't get IRQ %d\n",
+		       dev->name, pci_dev->irq);
+		goto fail_irq;
+	}
+
+	switch (dev->board) {
+	case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+		cx23885_irq_add_enable(dev, PCI_MSK_GPIO1 | PCI_MSK_GPIO0);
+		break;
+	case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+		cx23885_irq_add_enable(dev, PCI_MSK_GPIO0);
+		break;
+	}
+
+	/*
+	 * The CX2388[58] IR controller can start firing interrupts when
+	 * enabled, so these have to take place after the cx23885_irq() handler
+	 * is hooked up by the call to request_irq() above.
+	 */
+	cx23885_ir_pci_int_enable(dev);
+	cx23885_input_init(dev);
+
+	return 0;
+
+fail_irq:
+	cx23885_dev_unregister(dev);
+fail_unreg:
+	v4l2_device_unregister(&dev->v4l2_dev);
+fail_free:
+	kfree(dev);
+	return err;
+}
+
+static void __devexit cx23885_finidev(struct pci_dev *pci_dev)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+	struct cx23885_dev *dev = to_cx23885(v4l2_dev);
+
+	cx23885_input_fini(dev);
+	cx23885_ir_fini(dev);
+
+	cx23885_shutdown(dev);
+
+	pci_disable_device(pci_dev);
+
+	/* unregister stuff */
+	free_irq(pci_dev->irq, dev);
+
+	cx23885_dev_unregister(dev);
+	v4l2_device_unregister(v4l2_dev);
+	kfree(dev);
+}
+
+static struct pci_device_id cx23885_pci_tbl[] = {
+	{
+		/* CX23885 */
+		.vendor       = 0x14f1,
+		.device       = 0x8852,
+		.subvendor    = PCI_ANY_ID,
+		.subdevice    = PCI_ANY_ID,
+	}, {
+		/* CX23887 Rev 2 */
+		.vendor       = 0x14f1,
+		.device       = 0x8880,
+		.subvendor    = PCI_ANY_ID,
+		.subdevice    = PCI_ANY_ID,
+	}, {
+		/* --- end of list --- */
+	}
+};
+MODULE_DEVICE_TABLE(pci, cx23885_pci_tbl);
+
+static struct pci_driver cx23885_pci_driver = {
+	.name     = "cx23885",
+	.id_table = cx23885_pci_tbl,
+	.probe    = cx23885_initdev,
+	.remove   = __devexit_p(cx23885_finidev),
+	/* TODO */
+	.suspend  = NULL,
+	.resume   = NULL,
+};
+
+static int __init cx23885_init(void)
+{
+	printk(KERN_INFO "cx23885 driver version %s loaded\n",
+		CX23885_VERSION);
+	return pci_register_driver(&cx23885_pci_driver);
+}
+
+static void __exit cx23885_fini(void)
+{
+	pci_unregister_driver(&cx23885_pci_driver);
+}
+
+module_init(cx23885_init);
+module_exit(cx23885_fini);
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
new file mode 100644
index 0000000..f3202a5
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -0,0 +1,1356 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/file.h>
+#include <linux/suspend.h>
+
+#include "cx23885.h"
+#include <media/v4l2-common.h>
+
+#include "dvb_ca_en50221.h"
+#include "s5h1409.h"
+#include "s5h1411.h"
+#include "mt2131.h"
+#include "tda8290.h"
+#include "tda18271.h"
+#include "lgdt330x.h"
+#include "xc4000.h"
+#include "xc5000.h"
+#include "max2165.h"
+#include "tda10048.h"
+#include "tuner-xc2028.h"
+#include "tuner-simple.h"
+#include "dib7000p.h"
+#include "dibx000_common.h"
+#include "zl10353.h"
+#include "stv0900.h"
+#include "stv0900_reg.h"
+#include "stv6110.h"
+#include "lnbh24.h"
+#include "cx24116.h"
+#include "cimax2.h"
+#include "lgs8gxx.h"
+#include "netup-eeprom.h"
+#include "netup-init.h"
+#include "lgdt3305.h"
+#include "atbm8830.h"
+#include "ds3000.h"
+#include "cx23885-f300.h"
+#include "altera-ci.h"
+#include "stv0367.h"
+#include "drxk.h"
+#include "mt2063.h"
+
+static unsigned int debug;
+
+#define dprintk(level, fmt, arg...)\
+	do { if (debug >= level)\
+		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
+	} while (0)
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int alt_tuner;
+module_param(alt_tuner, int, 0644);
+MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* ------------------------------------------------------------------ */
+
+static int dvb_buf_setup(struct videobuf_queue *q,
+			 unsigned int *count, unsigned int *size)
+{
+	struct cx23885_tsport *port = q->priv_data;
+
+	port->ts_packet_size  = 188 * 4;
+	port->ts_packet_count = 32;
+
+	*size  = port->ts_packet_size * port->ts_packet_count;
+	*count = 32;
+	return 0;
+}
+
+static int dvb_buf_prepare(struct videobuf_queue *q,
+			   struct videobuf_buffer *vb, enum v4l2_field field)
+{
+	struct cx23885_tsport *port = q->priv_data;
+	return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field);
+}
+
+static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct cx23885_tsport *port = q->priv_data;
+	cx23885_buf_queue(port, (struct cx23885_buffer *)vb);
+}
+
+static void dvb_buf_release(struct videobuf_queue *q,
+			    struct videobuf_buffer *vb)
+{
+	cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
+}
+
+static int cx23885_dvb_set_frontend(struct dvb_frontend *fe);
+
+static void cx23885_dvb_gate_ctrl(struct cx23885_tsport  *port, int open)
+{
+	struct videobuf_dvb_frontends *f;
+	struct videobuf_dvb_frontend *fe;
+
+	f = &port->frontends;
+
+	if (f->gate <= 1) /* undefined or fe0 */
+		fe = videobuf_dvb_get_frontend(f, 1);
+	else
+		fe = videobuf_dvb_get_frontend(f, f->gate);
+
+	if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
+		fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open);
+
+	/*
+	 * FIXME: Improve this path to avoid calling the
+	 * cx23885_dvb_set_frontend() every time it passes here.
+	 */
+	cx23885_dvb_set_frontend(fe->dvb.frontend);
+}
+
+static struct videobuf_queue_ops dvb_qops = {
+	.buf_setup    = dvb_buf_setup,
+	.buf_prepare  = dvb_buf_prepare,
+	.buf_queue    = dvb_buf_queue,
+	.buf_release  = dvb_buf_release,
+};
+
+static struct s5h1409_config hauppauge_generic_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_SERIAL_OUTPUT,
+	.gpio          = S5H1409_GPIO_ON,
+	.qam_if        = 44000,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct tda10048_config hauppauge_hvr1200_config = {
+	.demod_address    = 0x10 >> 1,
+	.output_mode      = TDA10048_SERIAL_OUTPUT,
+	.fwbulkwritelen   = TDA10048_BULKWRITE_200,
+	.inversion        = TDA10048_INVERSION_ON,
+	.dtv6_if_freq_khz = TDA10048_IF_3300,
+	.dtv7_if_freq_khz = TDA10048_IF_3800,
+	.dtv8_if_freq_khz = TDA10048_IF_4300,
+	.clk_freq_khz     = TDA10048_CLK_16000,
+};
+
+static struct tda10048_config hauppauge_hvr1210_config = {
+	.demod_address    = 0x10 >> 1,
+	.output_mode      = TDA10048_SERIAL_OUTPUT,
+	.fwbulkwritelen   = TDA10048_BULKWRITE_200,
+	.inversion        = TDA10048_INVERSION_ON,
+	.dtv6_if_freq_khz = TDA10048_IF_3300,
+	.dtv7_if_freq_khz = TDA10048_IF_3500,
+	.dtv8_if_freq_khz = TDA10048_IF_4000,
+	.clk_freq_khz     = TDA10048_CLK_16000,
+};
+
+static struct s5h1409_config hauppauge_ezqam_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_SERIAL_OUTPUT,
+	.gpio          = S5H1409_GPIO_OFF,
+	.qam_if        = 4000,
+	.inversion     = S5H1409_INVERSION_ON,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct s5h1409_config hauppauge_hvr1800lp_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_SERIAL_OUTPUT,
+	.gpio          = S5H1409_GPIO_OFF,
+	.qam_if        = 44000,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct s5h1409_config hauppauge_hvr1500_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_SERIAL_OUTPUT,
+	.gpio          = S5H1409_GPIO_OFF,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct mt2131_config hauppauge_generic_tunerconfig = {
+	0x61
+};
+
+static struct lgdt330x_config fusionhdtv_5_express = {
+	.demod_address = 0x0e,
+	.demod_chip = LGDT3303,
+	.serial_mpeg = 0x40,
+};
+
+static struct s5h1409_config hauppauge_hvr1500q_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_SERIAL_OUTPUT,
+	.gpio          = S5H1409_GPIO_ON,
+	.qam_if        = 44000,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct s5h1409_config dvico_s5h1409_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_SERIAL_OUTPUT,
+	.gpio          = S5H1409_GPIO_ON,
+	.qam_if        = 44000,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct s5h1411_config dvico_s5h1411_config = {
+	.output_mode   = S5H1411_SERIAL_OUTPUT,
+	.gpio          = S5H1411_GPIO_ON,
+	.qam_if        = S5H1411_IF_44000,
+	.vsb_if        = S5H1411_IF_44000,
+	.inversion     = S5H1411_INVERSION_OFF,
+	.status_mode   = S5H1411_DEMODLOCKING,
+	.mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct s5h1411_config hcw_s5h1411_config = {
+	.output_mode   = S5H1411_SERIAL_OUTPUT,
+	.gpio          = S5H1411_GPIO_OFF,
+	.vsb_if        = S5H1411_IF_44000,
+	.qam_if        = S5H1411_IF_4000,
+	.inversion     = S5H1411_INVERSION_ON,
+	.status_mode   = S5H1411_DEMODLOCKING,
+	.mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct xc5000_config hauppauge_hvr1500q_tunerconfig = {
+	.i2c_address      = 0x61,
+	.if_khz           = 5380,
+};
+
+static struct xc5000_config dvico_xc5000_tunerconfig = {
+	.i2c_address      = 0x64,
+	.if_khz           = 5380,
+};
+
+static struct tda829x_config tda829x_no_probe = {
+	.probe_tuner = TDA829X_DONT_PROBE,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+	.atsc_6   = { .if_freq = 5380, .agc_mode = 3, .std = 3,
+		      .if_lvl = 6, .rfagc_top = 0x37 },
+	.qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 0,
+		      .if_lvl = 6, .rfagc_top = 0x37 },
+};
+
+static struct tda18271_std_map hauppauge_hvr1200_tda18271_std_map = {
+	.dvbt_6   = { .if_freq = 3300, .agc_mode = 3, .std = 4,
+		      .if_lvl = 1, .rfagc_top = 0x37, },
+	.dvbt_7   = { .if_freq = 3800, .agc_mode = 3, .std = 5,
+		      .if_lvl = 1, .rfagc_top = 0x37, },
+	.dvbt_8   = { .if_freq = 4300, .agc_mode = 3, .std = 6,
+		      .if_lvl = 1, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config hauppauge_tda18271_config = {
+	.std_map = &hauppauge_tda18271_std_map,
+	.gate    = TDA18271_GATE_ANALOG,
+	.output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
+static struct tda18271_config hauppauge_hvr1200_tuner_config = {
+	.std_map = &hauppauge_hvr1200_tda18271_std_map,
+	.gate    = TDA18271_GATE_ANALOG,
+	.output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
+static struct tda18271_config hauppauge_hvr1210_tuner_config = {
+	.gate    = TDA18271_GATE_DIGITAL,
+	.output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
+static struct tda18271_std_map hauppauge_hvr127x_std_map = {
+	.atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 4,
+		      .if_lvl = 1, .rfagc_top = 0x58 },
+	.qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 5,
+		      .if_lvl = 1, .rfagc_top = 0x58 },
+};
+
+static struct tda18271_config hauppauge_hvr127x_config = {
+	.std_map = &hauppauge_hvr127x_std_map,
+	.output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
+static struct lgdt3305_config hauppauge_lgdt3305_config = {
+	.i2c_addr           = 0x0e,
+	.mpeg_mode          = LGDT3305_MPEG_SERIAL,
+	.tpclk_edge         = LGDT3305_TPCLK_FALLING_EDGE,
+	.tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
+	.deny_i2c_rptr      = 1,
+	.spectral_inversion = 1,
+	.qam_if_khz         = 4000,
+	.vsb_if_khz         = 3250,
+};
+
+static struct dibx000_agc_config xc3028_agc_config = {
+	BAND_VHF | BAND_UHF,	/* band_caps */
+
+	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0,
+	 * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+	 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0,
+	 * P_agc_nb_est=2, P_agc_write=0
+	 */
+	(0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) |
+		(3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */
+
+	712,	/* inv_gain */
+	21,	/* time_stabiliz */
+
+	0,	/* alpha_level */
+	118,	/* thlock */
+
+	0,	/* wbd_inv */
+	2867,	/* wbd_ref */
+	0,	/* wbd_sel */
+	2,	/* wbd_alpha */
+
+	0,	/* agc1_max */
+	0,	/* agc1_min */
+	39718,	/* agc2_max */
+	9930,	/* agc2_min */
+	0,	/* agc1_pt1 */
+	0,	/* agc1_pt2 */
+	0,	/* agc1_pt3 */
+	0,	/* agc1_slope1 */
+	0,	/* agc1_slope2 */
+	0,	/* agc2_pt1 */
+	128,	/* agc2_pt2 */
+	29,	/* agc2_slope1 */
+	29,	/* agc2_slope2 */
+
+	17,	/* alpha_mant */
+	27,	/* alpha_exp */
+	23,	/* beta_mant */
+	51,	/* beta_exp */
+
+	1,	/* perform_agc_softsplit */
+};
+
+/* PLL Configuration for COFDM BW_MHz = 8.000000
+ * With external clock = 30.000000 */
+static struct dibx000_bandwidth_config xc3028_bw_config = {
+	60000,	/* internal */
+	30000,	/* sampling */
+	1,	/* pll_cfg: prediv */
+	8,	/* pll_cfg: ratio */
+	3,	/* pll_cfg: range */
+	1,	/* pll_cfg: reset */
+	0,	/* pll_cfg: bypass */
+	0,	/* misc: refdiv */
+	0,	/* misc: bypclk_div */
+	1,	/* misc: IO_CLK_en_core */
+	1,	/* misc: ADClkSrc */
+	0,	/* misc: modulo */
+	(3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */
+	(1 << 25) | 5816102, /* ifreq = 5.200000 MHz */
+	20452225, /* timf */
+	30000000  /* xtal_hz */
+};
+
+static struct dib7000p_config hauppauge_hvr1400_dib7000_config = {
+	.output_mpeg2_in_188_bytes = 1,
+	.hostbus_diversity = 1,
+	.tuner_is_baseband = 0,
+	.update_lna  = NULL,
+
+	.agc_config_count = 1,
+	.agc = &xc3028_agc_config,
+	.bw  = &xc3028_bw_config,
+
+	.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+	.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+	.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+	.pwm_freq_div = 0,
+	.agc_control  = NULL,
+	.spur_protect = 0,
+
+	.output_mode = OUTMODE_MPEG2_SERIAL,
+};
+
+static struct zl10353_config dvico_fusionhdtv_xc3028 = {
+	.demod_address = 0x0f,
+	.if2           = 45600,
+	.no_tuner      = 1,
+	.disable_i2c_gate_ctrl = 1,
+};
+
+static struct stv0900_reg stv0900_ts_regs[] = {
+	{ R0900_TSGENERAL, 0x00 },
+	{ R0900_P1_TSSPEED, 0x40 },
+	{ R0900_P2_TSSPEED, 0x40 },
+	{ R0900_P1_TSCFGM, 0xc0 },
+	{ R0900_P2_TSCFGM, 0xc0 },
+	{ R0900_P1_TSCFGH, 0xe0 },
+	{ R0900_P2_TSCFGH, 0xe0 },
+	{ R0900_P1_TSCFGL, 0x20 },
+	{ R0900_P2_TSCFGL, 0x20 },
+	{ 0xffff, 0xff }, /* terminate */
+};
+
+static struct stv0900_config netup_stv0900_config = {
+	.demod_address = 0x68,
+	.demod_mode = 1, /* dual */
+	.xtal = 8000000,
+	.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
+	.diseqc_mode = 2,/* 2/3 PWM */
+	.ts_config_regs = stv0900_ts_regs,
+	.tun1_maddress = 0,/* 0x60 */
+	.tun2_maddress = 3,/* 0x63 */
+	.tun1_adc = 1,/* 1 Vpp */
+	.tun2_adc = 1,/* 1 Vpp */
+};
+
+static struct stv6110_config netup_stv6110_tunerconfig_a = {
+	.i2c_address = 0x60,
+	.mclk = 16000000,
+	.clk_div = 1,
+	.gain = 8, /* +16 dB  - maximum gain */
+};
+
+static struct stv6110_config netup_stv6110_tunerconfig_b = {
+	.i2c_address = 0x63,
+	.mclk = 16000000,
+	.clk_div = 1,
+	.gain = 8, /* +16 dB  - maximum gain */
+};
+
+static struct cx24116_config tbs_cx24116_config = {
+	.demod_address = 0x55,
+};
+
+static struct ds3000_config tevii_ds3000_config = {
+	.demod_address = 0x68,
+};
+
+static struct cx24116_config dvbworld_cx24116_config = {
+	.demod_address = 0x05,
+};
+
+static struct lgs8gxx_config mygica_x8506_lgs8gl5_config = {
+	.prod = LGS8GXX_PROD_LGS8GL5,
+	.demod_address = 0x19,
+	.serial_ts = 0,
+	.ts_clk_pol = 1,
+	.ts_clk_gated = 1,
+	.if_clk_freq = 30400, /* 30.4 MHz */
+	.if_freq = 5380, /* 5.38 MHz */
+	.if_neg_center = 1,
+	.ext_adc = 0,
+	.adc_signed = 0,
+	.if_neg_edge = 0,
+};
+
+static struct xc5000_config mygica_x8506_xc5000_config = {
+	.i2c_address = 0x61,
+	.if_khz = 5380,
+};
+
+static int cx23885_dvb_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct cx23885_tsport *port = fe->dvb->priv;
+	struct cx23885_dev *dev = port->dev;
+
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1275:
+		switch (p->modulation) {
+		case VSB_8:
+			cx23885_gpio_clear(dev, GPIO_5);
+			break;
+		case QAM_64:
+		case QAM_256:
+		default:
+			cx23885_gpio_set(dev, GPIO_5);
+			break;
+		}
+		break;
+	case CX23885_BOARD_MYGICA_X8506:
+	case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+		/* Select Digital TV */
+		cx23885_gpio_set(dev, GPIO_0);
+		break;
+	}
+	return 0;
+}
+
+static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = {
+	.prod = LGS8GXX_PROD_LGS8G75,
+	.demod_address = 0x19,
+	.serial_ts = 0,
+	.ts_clk_pol = 1,
+	.ts_clk_gated = 1,
+	.if_clk_freq = 30400, /* 30.4 MHz */
+	.if_freq = 6500, /* 6.50 MHz */
+	.if_neg_center = 1,
+	.ext_adc = 0,
+	.adc_signed = 1,
+	.adc_vpp = 2, /* 1.6 Vpp */
+	.if_neg_edge = 1,
+};
+
+static struct xc5000_config magicpro_prohdtve2_xc5000_config = {
+	.i2c_address = 0x61,
+	.if_khz = 6500,
+};
+
+static struct atbm8830_config mygica_x8558pro_atbm8830_cfg1 = {
+	.prod = ATBM8830_PROD_8830,
+	.demod_address = 0x44,
+	.serial_ts = 0,
+	.ts_sampling_edge = 1,
+	.ts_clk_gated = 0,
+	.osc_clk_freq = 30400, /* in kHz */
+	.if_freq = 0, /* zero IF */
+	.zif_swap_iq = 1,
+	.agc_min = 0x2E,
+	.agc_max = 0xFF,
+	.agc_hold_loop = 0,
+};
+
+static struct max2165_config mygic_x8558pro_max2165_cfg1 = {
+	.i2c_address = 0x60,
+	.osc_clk = 20
+};
+
+static struct atbm8830_config mygica_x8558pro_atbm8830_cfg2 = {
+	.prod = ATBM8830_PROD_8830,
+	.demod_address = 0x44,
+	.serial_ts = 1,
+	.ts_sampling_edge = 1,
+	.ts_clk_gated = 0,
+	.osc_clk_freq = 30400, /* in kHz */
+	.if_freq = 0, /* zero IF */
+	.zif_swap_iq = 1,
+	.agc_min = 0x2E,
+	.agc_max = 0xFF,
+	.agc_hold_loop = 0,
+};
+
+static struct max2165_config mygic_x8558pro_max2165_cfg2 = {
+	.i2c_address = 0x60,
+	.osc_clk = 20
+};
+static struct stv0367_config netup_stv0367_config[] = {
+	{
+		.demod_address = 0x1c,
+		.xtal = 27000000,
+		.if_khz = 4500,
+		.if_iq_mode = 0,
+		.ts_mode = 1,
+		.clk_pol = 0,
+	}, {
+		.demod_address = 0x1d,
+		.xtal = 27000000,
+		.if_khz = 4500,
+		.if_iq_mode = 0,
+		.ts_mode = 1,
+		.clk_pol = 0,
+	},
+};
+
+static struct xc5000_config netup_xc5000_config[] = {
+	{
+		.i2c_address = 0x61,
+		.if_khz = 4500,
+	}, {
+		.i2c_address = 0x64,
+		.if_khz = 4500,
+	},
+};
+
+static struct drxk_config terratec_drxk_config[] = {
+	{
+		.adr = 0x29,
+		.no_i2c_bridge = 1,
+	}, {
+		.adr = 0x2a,
+		.no_i2c_bridge = 1,
+	},
+};
+
+static struct mt2063_config terratec_mt2063_config[] = {
+	{
+		.tuner_address = 0x60,
+	}, {
+		.tuner_address = 0x67,
+	},
+};
+
+int netup_altera_fpga_rw(void *device, int flag, int data, int read)
+{
+	struct cx23885_dev *dev = (struct cx23885_dev *)device;
+	unsigned long timeout = jiffies + msecs_to_jiffies(1);
+	uint32_t mem = 0;
+
+	mem = cx_read(MC417_RWD);
+	if (read)
+		cx_set(MC417_OEN, ALT_DATA);
+	else {
+		cx_clear(MC417_OEN, ALT_DATA);/* D0-D7 out */
+		mem &= ~ALT_DATA;
+		mem |= (data & ALT_DATA);
+	}
+
+	if (flag)
+		mem |= ALT_AD_RG;
+	else
+		mem &= ~ALT_AD_RG;
+
+	mem &= ~ALT_CS;
+	if (read)
+		mem = (mem & ~ALT_RD) | ALT_WR;
+	else
+		mem = (mem & ~ALT_WR) | ALT_RD;
+
+	cx_write(MC417_RWD, mem);  /* start RW cycle */
+
+	for (;;) {
+		mem = cx_read(MC417_RWD);
+		if ((mem & ALT_RDY) == 0)
+			break;
+		if (time_after(jiffies, timeout))
+			break;
+		udelay(1);
+	}
+
+	cx_set(MC417_RWD, ALT_RD | ALT_WR | ALT_CS);
+	if (read)
+		return mem & ALT_DATA;
+
+	return 0;
+};
+
+static int dvb_register(struct cx23885_tsport *port)
+{
+	struct cx23885_dev *dev = port->dev;
+	struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL;
+	struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
+	int mfe_shared = 0; /* bus not shared by default */
+	int ret;
+
+	/* Get the first frontend */
+	fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+	if (!fe0)
+		return -EINVAL;
+
+	/* init struct videobuf_dvb */
+	fe0->dvb.name = dev->name;
+
+	/* multi-frontend gate control is undefined or defaults to fe0 */
+	port->frontends.gate = 0;
+
+	/* Sets the gate control callback to be used by i2c command calls */
+	port->gate_ctrl = cx23885_dvb_gate_ctrl;
+
+	/* init frontend */
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+		i2c_bus = &dev->i2c_bus[0];
+		fe0->dvb.frontend = dvb_attach(s5h1409_attach,
+						&hauppauge_generic_config,
+						&i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			dvb_attach(mt2131_attach, fe0->dvb.frontend,
+				   &i2c_bus->i2c_adap,
+				   &hauppauge_generic_tunerconfig, 0);
+		}
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1270:
+	case CX23885_BOARD_HAUPPAUGE_HVR1275:
+		i2c_bus = &dev->i2c_bus[0];
+		fe0->dvb.frontend = dvb_attach(lgdt3305_attach,
+					       &hauppauge_lgdt3305_config,
+					       &i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			dvb_attach(tda18271_attach, fe0->dvb.frontend,
+				   0x60, &dev->i2c_bus[1].i2c_adap,
+				   &hauppauge_hvr127x_config);
+		}
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1255:
+	case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
+		i2c_bus = &dev->i2c_bus[0];
+		fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+					       &hcw_s5h1411_config,
+					       &i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			dvb_attach(tda18271_attach, fe0->dvb.frontend,
+				   0x60, &dev->i2c_bus[1].i2c_adap,
+				   &hauppauge_tda18271_config);
+		}
+
+		tda18271_attach(&dev->ts1.analog_fe,
+			0x60, &dev->i2c_bus[1].i2c_adap,
+			&hauppauge_tda18271_config);
+
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+		i2c_bus = &dev->i2c_bus[0];
+		switch (alt_tuner) {
+		case 1:
+			fe0->dvb.frontend =
+				dvb_attach(s5h1409_attach,
+					   &hauppauge_ezqam_config,
+					   &i2c_bus->i2c_adap);
+			if (fe0->dvb.frontend != NULL) {
+				dvb_attach(tda829x_attach, fe0->dvb.frontend,
+					   &dev->i2c_bus[1].i2c_adap, 0x42,
+					   &tda829x_no_probe);
+				dvb_attach(tda18271_attach, fe0->dvb.frontend,
+					   0x60, &dev->i2c_bus[1].i2c_adap,
+					   &hauppauge_tda18271_config);
+			}
+			break;
+		case 0:
+		default:
+			fe0->dvb.frontend =
+				dvb_attach(s5h1409_attach,
+					   &hauppauge_generic_config,
+					   &i2c_bus->i2c_adap);
+			if (fe0->dvb.frontend != NULL)
+				dvb_attach(mt2131_attach, fe0->dvb.frontend,
+					   &i2c_bus->i2c_adap,
+					   &hauppauge_generic_tunerconfig, 0);
+			break;
+		}
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+		i2c_bus = &dev->i2c_bus[0];
+		fe0->dvb.frontend = dvb_attach(s5h1409_attach,
+						&hauppauge_hvr1800lp_config,
+						&i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			dvb_attach(mt2131_attach, fe0->dvb.frontend,
+				   &i2c_bus->i2c_adap,
+				   &hauppauge_generic_tunerconfig, 0);
+		}
+		break;
+	case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
+		i2c_bus = &dev->i2c_bus[0];
+		fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
+						&fusionhdtv_5_express,
+						&i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+				   &i2c_bus->i2c_adap, 0x61,
+				   TUNER_LG_TDVS_H06XF);
+		}
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+		i2c_bus = &dev->i2c_bus[1];
+		fe0->dvb.frontend = dvb_attach(s5h1409_attach,
+						&hauppauge_hvr1500q_config,
+						&dev->i2c_bus[0].i2c_adap);
+		if (fe0->dvb.frontend != NULL)
+			dvb_attach(xc5000_attach, fe0->dvb.frontend,
+				   &i2c_bus->i2c_adap,
+				   &hauppauge_hvr1500q_tunerconfig);
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
+		i2c_bus = &dev->i2c_bus[1];
+		fe0->dvb.frontend = dvb_attach(s5h1409_attach,
+						&hauppauge_hvr1500_config,
+						&dev->i2c_bus[0].i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			struct dvb_frontend *fe;
+			struct xc2028_config cfg = {
+				.i2c_adap  = &i2c_bus->i2c_adap,
+				.i2c_addr  = 0x61,
+			};
+			static struct xc2028_ctrl ctl = {
+				.fname       = XC2028_DEFAULT_FIRMWARE,
+				.max_len     = 64,
+				.demod       = XC3028_FE_OREN538,
+			};
+
+			fe = dvb_attach(xc2028_attach,
+					fe0->dvb.frontend, &cfg);
+			if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+				fe->ops.tuner_ops.set_config(fe, &ctl);
+		}
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1200:
+	case CX23885_BOARD_HAUPPAUGE_HVR1700:
+		i2c_bus = &dev->i2c_bus[0];
+		fe0->dvb.frontend = dvb_attach(tda10048_attach,
+			&hauppauge_hvr1200_config,
+			&i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			dvb_attach(tda829x_attach, fe0->dvb.frontend,
+				&dev->i2c_bus[1].i2c_adap, 0x42,
+				&tda829x_no_probe);
+			dvb_attach(tda18271_attach, fe0->dvb.frontend,
+				0x60, &dev->i2c_bus[1].i2c_adap,
+				&hauppauge_hvr1200_tuner_config);
+		}
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1210:
+		i2c_bus = &dev->i2c_bus[0];
+		fe0->dvb.frontend = dvb_attach(tda10048_attach,
+			&hauppauge_hvr1210_config,
+			&i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			dvb_attach(tda18271_attach, fe0->dvb.frontend,
+				0x60, &dev->i2c_bus[1].i2c_adap,
+				&hauppauge_hvr1210_tuner_config);
+		}
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1400:
+		i2c_bus = &dev->i2c_bus[0];
+		fe0->dvb.frontend = dvb_attach(dib7000p_attach,
+			&i2c_bus->i2c_adap,
+			0x12, &hauppauge_hvr1400_dib7000_config);
+		if (fe0->dvb.frontend != NULL) {
+			struct dvb_frontend *fe;
+			struct xc2028_config cfg = {
+				.i2c_adap  = &dev->i2c_bus[1].i2c_adap,
+				.i2c_addr  = 0x64,
+			};
+			static struct xc2028_ctrl ctl = {
+				.fname   = XC3028L_DEFAULT_FIRMWARE,
+				.max_len = 64,
+				.demod   = XC3028_FE_DIBCOM52,
+				/* This is true for all demods with
+					v36 firmware? */
+				.type    = XC2028_D2633,
+			};
+
+			fe = dvb_attach(xc2028_attach,
+					fe0->dvb.frontend, &cfg);
+			if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+				fe->ops.tuner_ops.set_config(fe, &ctl);
+		}
+		break;
+	case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
+		i2c_bus = &dev->i2c_bus[port->nr - 1];
+
+		fe0->dvb.frontend = dvb_attach(s5h1409_attach,
+						&dvico_s5h1409_config,
+						&i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend == NULL)
+			fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+							&dvico_s5h1411_config,
+							&i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL)
+			dvb_attach(xc5000_attach, fe0->dvb.frontend,
+				   &i2c_bus->i2c_adap,
+				   &dvico_xc5000_tunerconfig);
+		break;
+	case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: {
+		i2c_bus = &dev->i2c_bus[port->nr - 1];
+
+		fe0->dvb.frontend = dvb_attach(zl10353_attach,
+					       &dvico_fusionhdtv_xc3028,
+					       &i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			struct dvb_frontend      *fe;
+			struct xc2028_config	  cfg = {
+				.i2c_adap  = &i2c_bus->i2c_adap,
+				.i2c_addr  = 0x61,
+			};
+			static struct xc2028_ctrl ctl = {
+				.fname       = XC2028_DEFAULT_FIRMWARE,
+				.max_len     = 64,
+				.demod       = XC3028_FE_ZARLINK456,
+			};
+
+			fe = dvb_attach(xc2028_attach, fe0->dvb.frontend,
+					&cfg);
+			if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+				fe->ops.tuner_ops.set_config(fe, &ctl);
+		}
+		break;
+	}
+	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+	case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+	case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+		i2c_bus = &dev->i2c_bus[0];
+
+		fe0->dvb.frontend = dvb_attach(zl10353_attach,
+			&dvico_fusionhdtv_xc3028,
+			&i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			struct dvb_frontend      *fe;
+			struct xc2028_config	  cfg = {
+				.i2c_adap  = &dev->i2c_bus[1].i2c_adap,
+				.i2c_addr  = 0x61,
+			};
+			static struct xc2028_ctrl ctl = {
+				.fname       = XC2028_DEFAULT_FIRMWARE,
+				.max_len     = 64,
+				.demod       = XC3028_FE_ZARLINK456,
+			};
+
+			fe = dvb_attach(xc2028_attach, fe0->dvb.frontend,
+				&cfg);
+			if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+				fe->ops.tuner_ops.set_config(fe, &ctl);
+		}
+		break;
+	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
+		i2c_bus = &dev->i2c_bus[0];
+
+		fe0->dvb.frontend = dvb_attach(zl10353_attach,
+					       &dvico_fusionhdtv_xc3028,
+					       &i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			struct dvb_frontend	*fe;
+			struct xc4000_config	cfg = {
+				.i2c_address	  = 0x61,
+				.default_pm	  = 0,
+				.dvb_amplitude	  = 134,
+				.set_smoothedcvbs = 1,
+				.if_khz		  = 4560
+			};
+
+			fe = dvb_attach(xc4000_attach, fe0->dvb.frontend,
+					&dev->i2c_bus[1].i2c_adap, &cfg);
+			if (!fe) {
+				printk(KERN_ERR "%s/2: xc4000 attach failed\n",
+				       dev->name);
+				goto frontend_detach;
+			}
+		}
+		break;
+	case CX23885_BOARD_TBS_6920:
+		i2c_bus = &dev->i2c_bus[1];
+
+		fe0->dvb.frontend = dvb_attach(cx24116_attach,
+					&tbs_cx24116_config,
+					&i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL)
+			fe0->dvb.frontend->ops.set_voltage = f300_set_voltage;
+
+		break;
+	case CX23885_BOARD_TEVII_S470:
+		i2c_bus = &dev->i2c_bus[1];
+
+		fe0->dvb.frontend = dvb_attach(ds3000_attach,
+					&tevii_ds3000_config,
+					&i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL)
+			fe0->dvb.frontend->ops.set_voltage = f300_set_voltage;
+
+		break;
+	case CX23885_BOARD_DVBWORLD_2005:
+		i2c_bus = &dev->i2c_bus[1];
+
+		fe0->dvb.frontend = dvb_attach(cx24116_attach,
+			&dvbworld_cx24116_config,
+			&i2c_bus->i2c_adap);
+		break;
+	case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+		i2c_bus = &dev->i2c_bus[0];
+		switch (port->nr) {
+		/* port B */
+		case 1:
+			fe0->dvb.frontend = dvb_attach(stv0900_attach,
+							&netup_stv0900_config,
+							&i2c_bus->i2c_adap, 0);
+			if (fe0->dvb.frontend != NULL) {
+				if (dvb_attach(stv6110_attach,
+						fe0->dvb.frontend,
+						&netup_stv6110_tunerconfig_a,
+						&i2c_bus->i2c_adap)) {
+					if (!dvb_attach(lnbh24_attach,
+							fe0->dvb.frontend,
+							&i2c_bus->i2c_adap,
+							LNBH24_PCL | LNBH24_TTX,
+							LNBH24_TEN, 0x09))
+						printk(KERN_ERR
+							"No LNBH24 found!\n");
+
+				}
+			}
+			break;
+		/* port C */
+		case 2:
+			fe0->dvb.frontend = dvb_attach(stv0900_attach,
+							&netup_stv0900_config,
+							&i2c_bus->i2c_adap, 1);
+			if (fe0->dvb.frontend != NULL) {
+				if (dvb_attach(stv6110_attach,
+						fe0->dvb.frontend,
+						&netup_stv6110_tunerconfig_b,
+						&i2c_bus->i2c_adap)) {
+					if (!dvb_attach(lnbh24_attach,
+							fe0->dvb.frontend,
+							&i2c_bus->i2c_adap,
+							LNBH24_PCL | LNBH24_TTX,
+							LNBH24_TEN, 0x0a))
+						printk(KERN_ERR
+							"No LNBH24 found!\n");
+
+				}
+			}
+			break;
+		}
+		break;
+	case CX23885_BOARD_MYGICA_X8506:
+		i2c_bus = &dev->i2c_bus[0];
+		i2c_bus2 = &dev->i2c_bus[1];
+		fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
+			&mygica_x8506_lgs8gl5_config,
+			&i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			dvb_attach(xc5000_attach,
+				fe0->dvb.frontend,
+				&i2c_bus2->i2c_adap,
+				&mygica_x8506_xc5000_config);
+		}
+		break;
+	case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+		i2c_bus = &dev->i2c_bus[0];
+		i2c_bus2 = &dev->i2c_bus[1];
+		fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
+			&magicpro_prohdtve2_lgs8g75_config,
+			&i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			dvb_attach(xc5000_attach,
+				fe0->dvb.frontend,
+				&i2c_bus2->i2c_adap,
+				&magicpro_prohdtve2_xc5000_config);
+		}
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+		i2c_bus = &dev->i2c_bus[0];
+		fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+			&hcw_s5h1411_config,
+			&i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL)
+			dvb_attach(tda18271_attach, fe0->dvb.frontend,
+				0x60, &dev->i2c_bus[0].i2c_adap,
+				&hauppauge_tda18271_config);
+
+		tda18271_attach(&dev->ts1.analog_fe,
+			0x60, &dev->i2c_bus[1].i2c_adap,
+			&hauppauge_tda18271_config);
+
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+		i2c_bus = &dev->i2c_bus[0];
+		fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+			&hcw_s5h1411_config,
+			&i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL)
+			dvb_attach(tda18271_attach, fe0->dvb.frontend,
+				0x60, &dev->i2c_bus[0].i2c_adap,
+				&hauppauge_tda18271_config);
+		break;
+	case CX23885_BOARD_MYGICA_X8558PRO:
+		switch (port->nr) {
+		/* port B */
+		case 1:
+			i2c_bus = &dev->i2c_bus[0];
+			fe0->dvb.frontend = dvb_attach(atbm8830_attach,
+				&mygica_x8558pro_atbm8830_cfg1,
+				&i2c_bus->i2c_adap);
+			if (fe0->dvb.frontend != NULL) {
+				dvb_attach(max2165_attach,
+					fe0->dvb.frontend,
+					&i2c_bus->i2c_adap,
+					&mygic_x8558pro_max2165_cfg1);
+			}
+			break;
+		/* port C */
+		case 2:
+			i2c_bus = &dev->i2c_bus[1];
+			fe0->dvb.frontend = dvb_attach(atbm8830_attach,
+				&mygica_x8558pro_atbm8830_cfg2,
+				&i2c_bus->i2c_adap);
+			if (fe0->dvb.frontend != NULL) {
+				dvb_attach(max2165_attach,
+					fe0->dvb.frontend,
+					&i2c_bus->i2c_adap,
+					&mygic_x8558pro_max2165_cfg2);
+			}
+			break;
+		}
+		break;
+	case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+		i2c_bus = &dev->i2c_bus[0];
+		mfe_shared = 1;/* MFE */
+		port->frontends.gate = 0;/* not clear for me yet */
+		/* ports B, C */
+		/* MFE frontend 1 DVB-T */
+		fe0->dvb.frontend = dvb_attach(stv0367ter_attach,
+					&netup_stv0367_config[port->nr - 1],
+					&i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (NULL == dvb_attach(xc5000_attach,
+					fe0->dvb.frontend,
+					&i2c_bus->i2c_adap,
+					&netup_xc5000_config[port->nr - 1]))
+				goto frontend_detach;
+			/* load xc5000 firmware */
+			fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend);
+		}
+		/* MFE frontend 2 */
+		fe1 = videobuf_dvb_get_frontend(&port->frontends, 2);
+		if (fe1 == NULL)
+			goto frontend_detach;
+		/* DVB-C init */
+		fe1->dvb.frontend = dvb_attach(stv0367cab_attach,
+					&netup_stv0367_config[port->nr - 1],
+					&i2c_bus->i2c_adap);
+		if (fe1->dvb.frontend != NULL) {
+			fe1->dvb.frontend->id = 1;
+			if (NULL == dvb_attach(xc5000_attach,
+					fe1->dvb.frontend,
+					&i2c_bus->i2c_adap,
+					&netup_xc5000_config[port->nr - 1]))
+				goto frontend_detach;
+		}
+		break;
+	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+		i2c_bus = &dev->i2c_bus[0];
+		i2c_bus2 = &dev->i2c_bus[1];
+
+		switch (port->nr) {
+		/* port b */
+		case 1:
+			fe0->dvb.frontend = dvb_attach(drxk_attach,
+					&terratec_drxk_config[0],
+					&i2c_bus->i2c_adap);
+			if (fe0->dvb.frontend != NULL) {
+				if (!dvb_attach(mt2063_attach,
+						fe0->dvb.frontend,
+						&terratec_mt2063_config[0],
+						&i2c_bus2->i2c_adap))
+					goto frontend_detach;
+			}
+			break;
+		/* port c */
+		case 2:
+			fe0->dvb.frontend = dvb_attach(drxk_attach,
+					&terratec_drxk_config[1],
+					&i2c_bus->i2c_adap);
+			if (fe0->dvb.frontend != NULL) {
+				if (!dvb_attach(mt2063_attach,
+						fe0->dvb.frontend,
+						&terratec_mt2063_config[1],
+						&i2c_bus2->i2c_adap))
+					goto frontend_detach;
+			}
+			break;
+		}
+		break;
+	case CX23885_BOARD_TEVII_S471:
+		i2c_bus = &dev->i2c_bus[1];
+
+		fe0->dvb.frontend = dvb_attach(ds3000_attach,
+					&tevii_ds3000_config,
+					&i2c_bus->i2c_adap);
+		break;
+	default:
+		printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
+			" isn't supported yet\n",
+		       dev->name);
+		break;
+	}
+
+	if ((NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend)) {
+		printk(KERN_ERR "%s: frontend initialization failed\n",
+		       dev->name);
+		goto frontend_detach;
+	}
+
+	/* define general-purpose callback pointer */
+	fe0->dvb.frontend->callback = cx23885_tuner_callback;
+	if (fe1)
+		fe1->dvb.frontend->callback = cx23885_tuner_callback;
+#if 0
+	/* Ensure all frontends negotiate bus access */
+	fe0->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl;
+	if (fe1)
+		fe1->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl;
+#endif
+
+	/* Put the analog decoder in standby to keep it quiet */
+	call_all(dev, core, s_power, 0);
+
+	if (fe0->dvb.frontend->ops.analog_ops.standby)
+		fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
+
+	/* register everything */
+	ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
+					&dev->pci->dev, adapter_nr, mfe_shared);
+	if (ret)
+		goto frontend_detach;
+
+	/* init CI & MAC */
+	switch (dev->board) {
+	case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: {
+		static struct netup_card_info cinfo;
+
+		netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
+		memcpy(port->frontends.adapter.proposed_mac,
+				cinfo.port[port->nr - 1].mac, 6);
+		printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n",
+			port->nr, port->frontends.adapter.proposed_mac);
+
+		netup_ci_init(port);
+		break;
+		}
+	case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: {
+		struct altera_ci_config netup_ci_cfg = {
+			.dev = dev,/* magic number to identify*/
+			.adapter = &port->frontends.adapter,/* for CI */
+			.demux = &fe0->dvb.demux,/* for hw pid filter */
+			.fpga_rw = netup_altera_fpga_rw,
+		};
+
+		altera_ci_init(&netup_ci_cfg, port->nr);
+		break;
+		}
+	case CX23885_BOARD_TEVII_S470: {
+		u8 eeprom[256]; /* 24C02 i2c eeprom */
+
+		if (port->nr != 1)
+			break;
+
+		/* Read entire EEPROM */
+		dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
+		tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom));
+		printk(KERN_INFO "TeVii S470 MAC= %pM\n", eeprom + 0xa0);
+		memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
+		break;
+		}
+	}
+
+	return ret;
+
+frontend_detach:
+	port->gate_ctrl = NULL;
+	videobuf_dvb_dealloc_frontends(&port->frontends);
+	return -EINVAL;
+}
+
+int cx23885_dvb_register(struct cx23885_tsport *port)
+{
+
+	struct videobuf_dvb_frontend *fe0;
+	struct cx23885_dev *dev = port->dev;
+	int err, i;
+
+	/* Here we need to allocate the correct number of frontends,
+	 * as reflected in the cards struct. The reality is that currently
+	 * no cx23885 boards support this - yet. But, if we don't modify this
+	 * code then the second frontend would never be allocated (later)
+	 * and fail with error before the attach in dvb_register().
+	 * Without these changes we risk an OOPS later. The changes here
+	 * are for safety, and should provide a good foundation for the
+	 * future addition of any multi-frontend cx23885 based boards.
+	 */
+	printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__,
+		port->num_frontends);
+
+	for (i = 1; i <= port->num_frontends; i++) {
+		if (videobuf_dvb_alloc_frontend(
+			&port->frontends, i) == NULL) {
+			printk(KERN_ERR "%s() failed to alloc\n", __func__);
+			return -ENOMEM;
+		}
+
+		fe0 = videobuf_dvb_get_frontend(&port->frontends, i);
+		if (!fe0)
+			err = -EINVAL;
+
+		dprintk(1, "%s\n", __func__);
+		dprintk(1, " ->probed by Card=%d Name=%s, PCI %02x:%02x\n",
+			dev->board,
+			dev->name,
+			dev->pci_bus,
+			dev->pci_slot);
+
+		err = -ENODEV;
+
+		/* dvb stuff */
+		/* We have to init the queue for each frontend on a port. */
+		printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name);
+		videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops,
+			    &dev->pci->dev, &port->slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
+			    sizeof(struct cx23885_buffer), port, NULL);
+	}
+	err = dvb_register(port);
+	if (err != 0)
+		printk(KERN_ERR "%s() dvb_register failed err = %d\n",
+			__func__, err);
+
+	return err;
+}
+
+int cx23885_dvb_unregister(struct cx23885_tsport *port)
+{
+	struct videobuf_dvb_frontend *fe0;
+
+	/* FIXME: in an error condition where the we have
+	 * an expected number of frontends (attach problem)
+	 * then this might not clean up correctly, if 1
+	 * is invalid.
+	 * This comment only applies to future boards IF they
+	 * implement MFE support.
+	 */
+	fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+	if (fe0 && fe0->dvb.frontend)
+		videobuf_dvb_unregister_bus(&port->frontends);
+
+	switch (port->dev->board) {
+	case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+		netup_ci_exit(port);
+		break;
+	case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+		altera_ci_release(port->dev, port->nr);
+		break;
+	}
+
+	port->gate_ctrl = NULL;
+
+	return 0;
+}
+
diff --git a/drivers/media/pci/cx23885/cx23885-f300.c b/drivers/media/pci/cx23885/cx23885-f300.c
new file mode 100644
index 0000000..93998f2
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-f300.c
@@ -0,0 +1,177 @@
+/*
+ * Driver for Silicon Labs C8051F300 microcontroller.
+ *
+ * It is used for LNB power control in TeVii S470,
+ * TBS 6920 PCIe DVB-S2 cards.
+ *
+ * Microcontroller connected to cx23885 GPIO pins:
+ * GPIO0 - data		- P0.3 F300
+ * GPIO1 - reset	- P0.2 F300
+ * GPIO2 - clk		- P0.1 F300
+ * GPIO3 - busy		- P0.0 F300
+ *
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@me.by>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cx23885.h"
+
+#define F300_DATA	GPIO_0
+#define F300_RESET	GPIO_1
+#define F300_CLK	GPIO_2
+#define F300_BUSY	GPIO_3
+
+static void f300_set_line(struct cx23885_dev *dev, u32 line, u8 lvl)
+{
+	cx23885_gpio_enable(dev, line, 1);
+	if (lvl == 1)
+		cx23885_gpio_set(dev, line);
+	else
+		cx23885_gpio_clear(dev, line);
+}
+
+static u8 f300_get_line(struct cx23885_dev *dev, u32 line)
+{
+	cx23885_gpio_enable(dev, line, 0);
+
+	return cx23885_gpio_get(dev, line);
+}
+
+static void f300_send_byte(struct cx23885_dev *dev, u8 dta)
+{
+	u8 i;
+
+	for (i = 0; i < 8; i++) {
+		f300_set_line(dev, F300_CLK, 0);
+		udelay(30);
+		f300_set_line(dev, F300_DATA, (dta & 0x80) >> 7);/* msb first */
+		udelay(30);
+		dta <<= 1;
+		f300_set_line(dev, F300_CLK, 1);
+		udelay(30);
+	}
+}
+
+static u8 f300_get_byte(struct cx23885_dev *dev)
+{
+	u8 i, dta = 0;
+
+	for (i = 0; i < 8; i++) {
+		f300_set_line(dev, F300_CLK, 0);
+		udelay(30);
+		dta <<= 1;
+		f300_set_line(dev, F300_CLK, 1);
+		udelay(30);
+		dta |= f300_get_line(dev, F300_DATA);/* msb first */
+
+	}
+
+	return dta;
+}
+
+static u8 f300_xfer(struct dvb_frontend *fe, u8 *buf)
+{
+	struct cx23885_tsport *port = fe->dvb->priv;
+	struct cx23885_dev *dev = port->dev;
+	u8 i, temp, ret = 0;
+
+	temp = buf[0];
+	for (i = 0; i < buf[0]; i++)
+		temp += buf[i + 1];
+	temp = (~temp + 1);/* get check sum */
+	buf[1 + buf[0]] = temp;
+
+	f300_set_line(dev, F300_RESET, 1);
+	f300_set_line(dev, F300_CLK, 1);
+	udelay(30);
+	f300_set_line(dev, F300_DATA, 1);
+	msleep(1);
+
+	/* question: */
+	f300_set_line(dev, F300_RESET, 0);/* begin to send data */
+	msleep(1);
+
+	f300_send_byte(dev, 0xe0);/* the slave address is 0xe0, write */
+	msleep(1);
+
+	temp = buf[0];
+	temp += 2;
+	for (i = 0; i < temp; i++)
+		f300_send_byte(dev, buf[i]);
+
+	f300_set_line(dev, F300_RESET, 1);/* sent data over */
+	f300_set_line(dev, F300_DATA, 1);
+
+	/* answer: */
+	temp = 0;
+	for (i = 0; ((i < 8) & (temp == 0)); i++) {
+		msleep(1);
+		if (f300_get_line(dev, F300_BUSY) == 0)
+			temp = 1;
+	}
+
+	if (i > 7) {
+		printk(KERN_ERR "%s: timeout, the slave no response\n",
+								__func__);
+		ret = 1; /* timeout, the slave no response */
+	} else { /* the slave not busy, prepare for getting data */
+		f300_set_line(dev, F300_RESET, 0);/*ready...*/
+		msleep(1);
+		f300_send_byte(dev, 0xe1);/* 0xe1 is Read */
+		msleep(1);
+		temp = f300_get_byte(dev);/*get the data length */
+		if (temp > 14)
+			temp = 14;
+
+		for (i = 0; i < (temp + 1); i++)
+			f300_get_byte(dev);/* get data to empty buffer */
+
+		f300_set_line(dev, F300_RESET, 1);/* received data over */
+		f300_set_line(dev, F300_DATA, 1);
+	}
+
+	return ret;
+}
+
+int f300_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	u8 buf[16];
+
+	buf[0] = 0x05;
+	buf[1] = 0x38;/* write port */
+	buf[2] = 0x01;/* A port, lnb power */
+
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		buf[3] = 0x01;/* power on */
+		buf[4] = 0x02;/* B port, H/V */
+		buf[5] = 0x00;/*13V v*/
+		break;
+	case SEC_VOLTAGE_18:
+		buf[3] = 0x01;
+		buf[4] = 0x02;
+		buf[5] = 0x01;/* 18V h*/
+		break;
+	case SEC_VOLTAGE_OFF:
+		buf[3] = 0x00;/* power off */
+		buf[4] = 0x00;
+		buf[5] = 0x00;
+		break;
+	}
+
+	return f300_xfer(fe, buf);
+}
diff --git a/drivers/media/pci/cx23885/cx23885-f300.h b/drivers/media/pci/cx23885/cx23885-f300.h
new file mode 100644
index 0000000..e73344c
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-f300.h
@@ -0,0 +1,2 @@
+extern int f300_set_voltage(struct dvb_frontend *fe,
+				fe_sec_voltage_t voltage);
diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c
new file mode 100644
index 0000000..4887314
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-i2c.c
@@ -0,0 +1,396 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include "cx23885.h"
+
+#include <media/v4l2-common.h>
+
+static unsigned int i2c_debug;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+static unsigned int i2c_scan;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+#define dprintk(level, fmt, arg...)\
+	do { if (i2c_debug >= level)\
+		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
+	} while (0)
+
+#define I2C_WAIT_DELAY 32
+#define I2C_WAIT_RETRY 64
+
+#define I2C_EXTEND  (1 << 3)
+#define I2C_NOSTOP  (1 << 4)
+
+static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap)
+{
+	struct cx23885_i2c *bus = i2c_adap->algo_data;
+	struct cx23885_dev *dev = bus->dev;
+	return cx_read(bus->reg_stat) & 0x01;
+}
+
+static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)
+{
+	struct cx23885_i2c *bus = i2c_adap->algo_data;
+	struct cx23885_dev *dev = bus->dev;
+	return cx_read(bus->reg_stat) & 0x02 ? 1 : 0;
+}
+
+static int i2c_wait_done(struct i2c_adapter *i2c_adap)
+{
+	int count;
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		if (!i2c_is_busy(i2c_adap))
+			break;
+		udelay(I2C_WAIT_DELAY);
+	}
+
+	if (I2C_WAIT_RETRY == count)
+		return 0;
+
+	return 1;
+}
+
+static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
+			 const struct i2c_msg *msg, int joined_rlen)
+{
+	struct cx23885_i2c *bus = i2c_adap->algo_data;
+	struct cx23885_dev *dev = bus->dev;
+	u32 wdata, addr, ctrl;
+	int retval, cnt;
+
+	if (joined_rlen)
+		dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __func__,
+			msg->len, joined_rlen);
+	else
+		dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len);
+
+	/* Deal with i2c probe functions with zero payload */
+	if (msg->len == 0) {
+		cx_write(bus->reg_addr, msg->addr << 25);
+		cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2));
+		if (!i2c_wait_done(i2c_adap))
+			return -EIO;
+		if (!i2c_slave_did_ack(i2c_adap))
+			return -ENXIO;
+
+		dprintk(1, "%s() returns 0\n", __func__);
+		return 0;
+	}
+
+
+	/* dev, reg + first byte */
+	addr = (msg->addr << 25) | msg->buf[0];
+	wdata = msg->buf[0];
+	ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
+
+	if (msg->len > 1)
+		ctrl |= I2C_NOSTOP | I2C_EXTEND;
+	else if (joined_rlen)
+		ctrl |= I2C_NOSTOP;
+
+	cx_write(bus->reg_addr, addr);
+	cx_write(bus->reg_wdata, wdata);
+	cx_write(bus->reg_ctrl, ctrl);
+
+	if (!i2c_wait_done(i2c_adap))
+		goto eio;
+	if (i2c_debug) {
+		printk(" <W %02x %02x", msg->addr << 1, msg->buf[0]);
+		if (!(ctrl & I2C_NOSTOP))
+			printk(" >\n");
+	}
+
+	for (cnt = 1; cnt < msg->len; cnt++) {
+		/* following bytes */
+		wdata = msg->buf[cnt];
+		ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
+
+		if (cnt < msg->len - 1)
+			ctrl |= I2C_NOSTOP | I2C_EXTEND;
+		else if (joined_rlen)
+			ctrl |= I2C_NOSTOP;
+
+		cx_write(bus->reg_addr, addr);
+		cx_write(bus->reg_wdata, wdata);
+		cx_write(bus->reg_ctrl, ctrl);
+
+		if (!i2c_wait_done(i2c_adap))
+			goto eio;
+		if (i2c_debug) {
+			dprintk(1, " %02x", msg->buf[cnt]);
+			if (!(ctrl & I2C_NOSTOP))
+				dprintk(1, " >\n");
+		}
+	}
+	return msg->len;
+
+ eio:
+	retval = -EIO;
+	if (i2c_debug)
+		printk(KERN_ERR " ERR: %d\n", retval);
+	return retval;
+}
+
+static int i2c_readbytes(struct i2c_adapter *i2c_adap,
+			 const struct i2c_msg *msg, int joined)
+{
+	struct cx23885_i2c *bus = i2c_adap->algo_data;
+	struct cx23885_dev *dev = bus->dev;
+	u32 ctrl, cnt;
+	int retval;
+
+
+	if (i2c_debug && !joined)
+		dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len);
+
+	/* Deal with i2c probe functions with zero payload */
+	if (msg->len == 0) {
+		cx_write(bus->reg_addr, msg->addr << 25);
+		cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1);
+		if (!i2c_wait_done(i2c_adap))
+			return -EIO;
+		if (!i2c_slave_did_ack(i2c_adap))
+			return -ENXIO;
+
+
+		dprintk(1, "%s() returns 0\n", __func__);
+		return 0;
+	}
+
+	if (i2c_debug) {
+		if (joined)
+			dprintk(1, " R");
+		else
+			dprintk(1, " <R %02x", (msg->addr << 1) + 1);
+	}
+
+	for (cnt = 0; cnt < msg->len; cnt++) {
+
+		ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1;
+
+		if (cnt < msg->len - 1)
+			ctrl |= I2C_NOSTOP | I2C_EXTEND;
+
+		cx_write(bus->reg_addr, msg->addr << 25);
+		cx_write(bus->reg_ctrl, ctrl);
+
+		if (!i2c_wait_done(i2c_adap))
+			goto eio;
+		msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff;
+		if (i2c_debug) {
+			dprintk(1, " %02x", msg->buf[cnt]);
+			if (!(ctrl & I2C_NOSTOP))
+				dprintk(1, " >\n");
+		}
+	}
+	return msg->len;
+
+ eio:
+	retval = -EIO;
+	if (i2c_debug)
+		printk(KERN_ERR " ERR: %d\n", retval);
+	return retval;
+}
+
+static int i2c_xfer(struct i2c_adapter *i2c_adap,
+		    struct i2c_msg *msgs, int num)
+{
+	struct cx23885_i2c *bus = i2c_adap->algo_data;
+	struct cx23885_dev *dev = bus->dev;
+	int i, retval = 0;
+
+	dprintk(1, "%s(num = %d)\n", __func__, num);
+
+	for (i = 0 ; i < num; i++) {
+		dprintk(1, "%s(num = %d) addr = 0x%02x  len = 0x%x\n",
+			__func__, num, msgs[i].addr, msgs[i].len);
+		if (msgs[i].flags & I2C_M_RD) {
+			/* read */
+			retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
+		} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
+			   msgs[i].addr == msgs[i + 1].addr) {
+			/* write then read from same address */
+			retval = i2c_sendbytes(i2c_adap, &msgs[i],
+					       msgs[i + 1].len);
+			if (retval < 0)
+				goto err;
+			i++;
+			retval = i2c_readbytes(i2c_adap, &msgs[i], 1);
+		} else {
+			/* write */
+			retval = i2c_sendbytes(i2c_adap, &msgs[i], 0);
+		}
+		if (retval < 0)
+			goto err;
+	}
+	return num;
+
+ err:
+	return retval;
+}
+
+static u32 cx23885_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm cx23885_i2c_algo_template = {
+	.master_xfer	= i2c_xfer,
+	.functionality	= cx23885_functionality,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_adapter cx23885_i2c_adap_template = {
+	.name              = "cx23885",
+	.owner             = THIS_MODULE,
+	.algo              = &cx23885_i2c_algo_template,
+};
+
+static struct i2c_client cx23885_i2c_client_template = {
+	.name	= "cx23885 internal",
+};
+
+static char *i2c_devs[128] = {
+	[0x10 >> 1] = "tda10048",
+	[0x12 >> 1] = "dib7000pc",
+	[0x1c >> 1] = "lgdt3303",
+	[0x86 >> 1] = "tda9887",
+	[0x32 >> 1] = "cx24227",
+	[0x88 >> 1] = "cx25837",
+	[0x84 >> 1] = "tda8295",
+	[0x98 >> 1] = "flatiron",
+	[0xa0 >> 1] = "eeprom",
+	[0xc0 >> 1] = "tuner/mt2131/tda8275",
+	[0xc2 >> 1] = "tuner/mt2131/tda8275/xc5000/xc3028",
+	[0xc8 >> 1] = "tuner/xc3028L",
+};
+
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+	unsigned char buf;
+	int i, rc;
+
+	for (i = 0; i < 128; i++) {
+		c->addr = i;
+		rc = i2c_master_recv(c, &buf, 0);
+		if (rc < 0)
+			continue;
+		printk(KERN_INFO "%s: i2c scan: found device @ 0x%x  [%s]\n",
+		       name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+	}
+}
+
+/* init + register i2c adapter */
+int cx23885_i2c_register(struct cx23885_i2c *bus)
+{
+	struct cx23885_dev *dev = bus->dev;
+
+	dprintk(1, "%s(bus = %d)\n", __func__, bus->nr);
+
+	bus->i2c_adap = cx23885_i2c_adap_template;
+	bus->i2c_client = cx23885_i2c_client_template;
+	bus->i2c_adap.dev.parent = &dev->pci->dev;
+
+	strlcpy(bus->i2c_adap.name, bus->dev->name,
+		sizeof(bus->i2c_adap.name));
+
+	bus->i2c_adap.algo_data = bus;
+	i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev);
+	i2c_add_adapter(&bus->i2c_adap);
+
+	bus->i2c_client.adapter = &bus->i2c_adap;
+
+	if (0 == bus->i2c_rc) {
+		dprintk(1, "%s: i2c bus %d registered\n", dev->name, bus->nr);
+		if (i2c_scan) {
+			printk(KERN_INFO "%s: scan bus %d:\n",
+					dev->name, bus->nr);
+			do_i2c_scan(dev->name, &bus->i2c_client);
+		}
+	} else
+		printk(KERN_WARNING "%s: i2c bus %d register FAILED\n",
+			dev->name, bus->nr);
+
+	/* Instantiate the IR receiver device, if present */
+	if (0 == bus->i2c_rc) {
+		struct i2c_board_info info;
+		const unsigned short addr_list[] = {
+			0x6b, I2C_CLIENT_END
+		};
+
+		memset(&info, 0, sizeof(struct i2c_board_info));
+		strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+		/* Use quick read command for probe, some IR chips don't
+		 * support writes */
+		i2c_new_probed_device(&bus->i2c_adap, &info, addr_list,
+				      i2c_probe_func_quick_read);
+	}
+
+	return bus->i2c_rc;
+}
+
+int cx23885_i2c_unregister(struct cx23885_i2c *bus)
+{
+	i2c_del_adapter(&bus->i2c_adap);
+	return 0;
+}
+
+void cx23885_av_clk(struct cx23885_dev *dev, int enable)
+{
+	/* write 0 to bus 2 addr 0x144 via i2x_xfer() */
+	char buffer[3];
+	struct i2c_msg msg;
+	dprintk(1, "%s(enabled = %d)\n", __func__, enable);
+
+	/* Register 0x144 */
+	buffer[0] = 0x01;
+	buffer[1] = 0x44;
+	if (enable == 1)
+		buffer[2] = 0x05;
+	else
+		buffer[2] = 0x00;
+
+	msg.addr = 0x44;
+	msg.flags = I2C_M_TEN;
+	msg.len = 3;
+	msg.buf = buffer;
+
+	i2c_xfer(&dev->i2c_bus[2].i2c_adap, &msg, 1);
+}
+
+/* ----------------------------------------------------------------------- */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
new file mode 100644
index 0000000..5606672
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-input.c
@@ -0,0 +1,365 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  Infrared remote control input device
+ *
+ *  Most of this file is
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@md.metrocast.net>
+ *
+ *  However, the cx23885_input_{init,fini} functions contained herein are
+ *  derived from Linux kernel files linux/media/video/.../...-input.c marked as:
+ *
+ *  Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+ *  Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+ *		       Markus Rechberger <mrechberger@gmail.com>
+ *		       Mauro Carvalho Chehab <mchehab@infradead.org>
+ *		       Sascha Sommer <saschasommer@freenet.de>
+ *  Copyright (C) 2004, 2005 Chris Pascoe
+ *  Copyright (C) 2003, 2004 Gerd Knorr
+ *  Copyright (C) 2003 Pavel Machek
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#include <linux/slab.h>
+#include <media/rc-core.h>
+#include <media/v4l2-subdev.h>
+
+#include "cx23885.h"
+
+#define MODULE_NAME "cx23885"
+
+static void cx23885_input_process_measurements(struct cx23885_dev *dev,
+					       bool overrun)
+{
+	struct cx23885_kernel_ir *kernel_ir = dev->kernel_ir;
+
+	ssize_t num;
+	int count, i;
+	bool handle = false;
+	struct ir_raw_event ir_core_event[64];
+
+	do {
+		num = 0;
+		v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ir_core_event,
+				 sizeof(ir_core_event), &num);
+
+		count = num / sizeof(struct ir_raw_event);
+
+		for (i = 0; i < count; i++) {
+			ir_raw_event_store(kernel_ir->rc,
+					   &ir_core_event[i]);
+			handle = true;
+		}
+	} while (num != 0);
+
+	if (overrun)
+		ir_raw_event_reset(kernel_ir->rc);
+	else if (handle)
+		ir_raw_event_handle(kernel_ir->rc);
+}
+
+void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
+{
+	struct v4l2_subdev_ir_parameters params;
+	int overrun, data_available;
+
+	if (dev->sd_ir == NULL || events == 0)
+		return;
+
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1270:
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+	case CX23885_BOARD_TEVII_S470:
+	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+		/*
+		 * The only boards we handle right now.  However other boards
+		 * using the CX2388x integrated IR controller should be similar
+		 */
+		break;
+	default:
+		return;
+	}
+
+	overrun = events & (V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN |
+			    V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN);
+
+	data_available = events & (V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED |
+				   V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ);
+
+	if (overrun) {
+		/* If there was a FIFO overrun, stop the device */
+		v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
+		params.enable = false;
+		/* Mitigate race with cx23885_input_ir_stop() */
+		params.shutdown = atomic_read(&dev->ir_input_stopping);
+		v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
+	}
+
+	if (data_available)
+		cx23885_input_process_measurements(dev, overrun);
+
+	if (overrun) {
+		/* If there was a FIFO overrun, clear & restart the device */
+		params.enable = true;
+		/* Mitigate race with cx23885_input_ir_stop() */
+		params.shutdown = atomic_read(&dev->ir_input_stopping);
+		v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
+	}
+}
+
+static int cx23885_input_ir_start(struct cx23885_dev *dev)
+{
+	struct v4l2_subdev_ir_parameters params;
+
+	if (dev->sd_ir == NULL)
+		return -ENODEV;
+
+	atomic_set(&dev->ir_input_stopping, 0);
+
+	v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1270:
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+		/*
+		 * The IR controller on this board only returns pulse widths.
+		 * Any other mode setting will fail to set up the device.
+		*/
+		params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
+		params.enable = true;
+		params.interrupt_enable = true;
+		params.shutdown = false;
+
+		/* Setup for baseband compatible with both RC-5 and RC-6A */
+		params.modulation = false;
+		/* RC-5:  2,222,222 ns = 1/36 kHz * 32 cycles * 2 marks * 1.25*/
+		/* RC-6A: 3,333,333 ns = 1/36 kHz * 16 cycles * 6 marks * 1.25*/
+		params.max_pulse_width = 3333333; /* ns */
+		/* RC-5:    666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */
+		/* RC-6A:   333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */
+		params.noise_filter_min_width = 333333; /* ns */
+		/*
+		 * This board has inverted receive sense:
+		 * mark is received as low logic level;
+		 * falling edges are detected as rising edges; etc.
+		 */
+		params.invert_level = true;
+		break;
+	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+	case CX23885_BOARD_TEVII_S470:
+		/*
+		 * The IR controller on this board only returns pulse widths.
+		 * Any other mode setting will fail to set up the device.
+		 */
+		params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
+		params.enable = true;
+		params.interrupt_enable = true;
+		params.shutdown = false;
+
+		/* Setup for a standard NEC protocol */
+		params.carrier_freq = 37917; /* Hz, 455 kHz/12 for NEC */
+		params.carrier_range_lower = 33000; /* Hz */
+		params.carrier_range_upper = 43000; /* Hz */
+		params.duty_cycle = 33; /* percent, 33 percent for NEC */
+
+		/*
+		 * NEC max pulse width: (64/3)/(455 kHz/12) * 16 nec_units
+		 * (64/3)/(455 kHz/12) * 16 nec_units * 1.375 = 12378022 ns
+		 */
+		params.max_pulse_width = 12378022; /* ns */
+
+		/*
+		 * NEC noise filter min width: (64/3)/(455 kHz/12) * 1 nec_unit
+		 * (64/3)/(455 kHz/12) * 1 nec_units * 0.625 = 351648 ns
+		 */
+		params.noise_filter_min_width = 351648; /* ns */
+
+		params.modulation = false;
+		params.invert_level = true;
+		break;
+	}
+	v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
+	return 0;
+}
+
+static int cx23885_input_ir_open(struct rc_dev *rc)
+{
+	struct cx23885_kernel_ir *kernel_ir = rc->priv;
+
+	if (kernel_ir->cx == NULL)
+		return -ENODEV;
+
+	return cx23885_input_ir_start(kernel_ir->cx);
+}
+
+static void cx23885_input_ir_stop(struct cx23885_dev *dev)
+{
+	struct v4l2_subdev_ir_parameters params;
+
+	if (dev->sd_ir == NULL)
+		return;
+
+	/*
+	 * Stop the sd_ir subdevice from generating notifications and
+	 * scheduling work.
+	 * It is shutdown this way in order to mitigate a race with
+	 * cx23885_input_rx_work_handler() in the overrun case, which could
+	 * re-enable the subdevice.
+	 */
+	atomic_set(&dev->ir_input_stopping, 1);
+	v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
+	while (params.shutdown == false) {
+		params.enable = false;
+		params.interrupt_enable = false;
+		params.shutdown = true;
+		v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
+		v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
+	}
+	flush_work_sync(&dev->cx25840_work);
+	flush_work_sync(&dev->ir_rx_work);
+	flush_work_sync(&dev->ir_tx_work);
+}
+
+static void cx23885_input_ir_close(struct rc_dev *rc)
+{
+	struct cx23885_kernel_ir *kernel_ir = rc->priv;
+
+	if (kernel_ir->cx != NULL)
+		cx23885_input_ir_stop(kernel_ir->cx);
+}
+
+int cx23885_input_init(struct cx23885_dev *dev)
+{
+	struct cx23885_kernel_ir *kernel_ir;
+	struct rc_dev *rc;
+	char *rc_map;
+	enum rc_driver_type driver_type;
+	unsigned long allowed_protos;
+
+	int ret;
+
+	/*
+	 * If the IR device (hardware registers, chip, GPIO lines, etc.) isn't
+	 * encapsulated in a v4l2_subdev, then I'm not going to deal with it.
+	 */
+	if (dev->sd_ir == NULL)
+		return -ENODEV;
+
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1270:
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+		/* Integrated CX2388[58] IR controller */
+		driver_type = RC_DRIVER_IR_RAW;
+		allowed_protos = RC_TYPE_ALL;
+		/* The grey Hauppauge RC-5 remote */
+		rc_map = RC_MAP_HAUPPAUGE;
+		break;
+	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+		/* Integrated CX23885 IR controller */
+		driver_type = RC_DRIVER_IR_RAW;
+		allowed_protos = RC_TYPE_NEC;
+		/* The grey Terratec remote with orange buttons */
+		rc_map = RC_MAP_NEC_TERRATEC_CINERGY_XS;
+		break;
+	case CX23885_BOARD_TEVII_S470:
+		/* Integrated CX23885 IR controller */
+		driver_type = RC_DRIVER_IR_RAW;
+		allowed_protos = RC_TYPE_ALL;
+		/* A guess at the remote */
+		rc_map = RC_MAP_TEVII_NEC;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	/* cx23885 board instance kernel IR state */
+	kernel_ir = kzalloc(sizeof(struct cx23885_kernel_ir), GFP_KERNEL);
+	if (kernel_ir == NULL)
+		return -ENOMEM;
+
+	kernel_ir->cx = dev;
+	kernel_ir->name = kasprintf(GFP_KERNEL, "cx23885 IR (%s)",
+				    cx23885_boards[dev->board].name);
+	kernel_ir->phys = kasprintf(GFP_KERNEL, "pci-%s/ir0",
+				    pci_name(dev->pci));
+
+	/* input device */
+	rc = rc_allocate_device();
+	if (!rc) {
+		ret = -ENOMEM;
+		goto err_out_free;
+	}
+
+	kernel_ir->rc = rc;
+	rc->input_name = kernel_ir->name;
+	rc->input_phys = kernel_ir->phys;
+	rc->input_id.bustype = BUS_PCI;
+	rc->input_id.version = 1;
+	if (dev->pci->subsystem_vendor) {
+		rc->input_id.vendor  = dev->pci->subsystem_vendor;
+		rc->input_id.product = dev->pci->subsystem_device;
+	} else {
+		rc->input_id.vendor  = dev->pci->vendor;
+		rc->input_id.product = dev->pci->device;
+	}
+	rc->dev.parent = &dev->pci->dev;
+	rc->driver_type = driver_type;
+	rc->allowed_protos = allowed_protos;
+	rc->priv = kernel_ir;
+	rc->open = cx23885_input_ir_open;
+	rc->close = cx23885_input_ir_close;
+	rc->map_name = rc_map;
+	rc->driver_name = MODULE_NAME;
+
+	/* Go */
+	dev->kernel_ir = kernel_ir;
+	ret = rc_register_device(rc);
+	if (ret)
+		goto err_out_stop;
+
+	return 0;
+
+err_out_stop:
+	cx23885_input_ir_stop(dev);
+	dev->kernel_ir = NULL;
+	rc_free_device(rc);
+err_out_free:
+	kfree(kernel_ir->phys);
+	kfree(kernel_ir->name);
+	kfree(kernel_ir);
+	return ret;
+}
+
+void cx23885_input_fini(struct cx23885_dev *dev)
+{
+	/* Always stop the IR hardware from generating interrupts */
+	cx23885_input_ir_stop(dev);
+
+	if (dev->kernel_ir == NULL)
+		return;
+	rc_unregister_device(dev->kernel_ir->rc);
+	kfree(dev->kernel_ir->phys);
+	kfree(dev->kernel_ir->name);
+	kfree(dev->kernel_ir);
+	dev->kernel_ir = NULL;
+}
diff --git a/drivers/media/pci/cx23885/cx23885-input.h b/drivers/media/pci/cx23885/cx23885-input.h
new file mode 100644
index 0000000..75ef15d
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-input.h
@@ -0,0 +1,30 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  Infrared remote control input device
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#ifndef _CX23885_INPUT_H_
+#define _CX23885_INPUT_H_
+int cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events);
+
+int cx23885_input_init(struct cx23885_dev *dev);
+void cx23885_input_fini(struct cx23885_dev *dev);
+#endif
diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.c b/drivers/media/pci/cx23885/cx23885-ioctl.c
new file mode 100644
index 0000000..44812ca
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-ioctl.c
@@ -0,0 +1,208 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  Various common ioctl() support functions
+ *
+ *  Copyright (c) 2009 Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cx23885.h"
+#include <media/v4l2-chip-ident.h>
+
+int cx23885_g_chip_ident(struct file *file, void *fh,
+			 struct v4l2_dbg_chip_ident *chip)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+	int err = 0;
+	u8 rev;
+
+	chip->ident = V4L2_IDENT_NONE;
+	chip->revision = 0;
+	switch (chip->match.type) {
+	case V4L2_CHIP_MATCH_HOST:
+		switch (chip->match.addr) {
+		case 0:
+			rev = cx_read(RDR_CFG2) & 0xff;
+			switch (dev->pci->device) {
+			case 0x8852:
+				/* rev 0x04 could be '885 or '888. Pick '888. */
+				if (rev == 0x04)
+					chip->ident = V4L2_IDENT_CX23888;
+				else
+					chip->ident = V4L2_IDENT_CX23885;
+				break;
+			case 0x8880:
+				if (rev == 0x0e || rev == 0x0f)
+					chip->ident = V4L2_IDENT_CX23887;
+				else
+					chip->ident = V4L2_IDENT_CX23888;
+				break;
+			default:
+				chip->ident = V4L2_IDENT_UNKNOWN;
+				break;
+			}
+			chip->revision = (dev->pci->device << 16) | (rev << 8) |
+					 (dev->hwrevision & 0xff);
+			break;
+		case 1:
+			if (dev->v4l_device != NULL) {
+				chip->ident = V4L2_IDENT_CX23417;
+				chip->revision = 0;
+			}
+			break;
+		case 2:
+			/*
+			 * The integrated IR controller on the CX23888 is
+			 * host chip 2.  It may not be used/initialized or sd_ir
+			 * may be pointing at the cx25840 subdevice for the
+			 * IR controller on the CX23885.  Thus we find it
+			 * without using the dev->sd_ir pointer.
+			 */
+			call_hw(dev, CX23885_HW_888_IR, core, g_chip_ident,
+				chip);
+			break;
+		default:
+			err = -EINVAL; /* per V4L2 spec */
+			break;
+		}
+		break;
+	case V4L2_CHIP_MATCH_I2C_DRIVER:
+		/* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */
+		call_all(dev, core, g_chip_ident, chip);
+		break;
+	case V4L2_CHIP_MATCH_I2C_ADDR:
+		/*
+		 * We could return V4L2_IDENT_UNKNOWN, but we don't do the work
+		 * to look if a chip is at the address with no driver.  That's a
+		 * dangerous thing to do with EEPROMs anyway.
+		 */
+		call_all(dev, core, g_chip_ident, chip);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+	return err;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int cx23885_g_host_register(struct cx23885_dev *dev,
+				   struct v4l2_dbg_register *reg)
+{
+	if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0))
+		return -EINVAL;
+
+	reg->size = 4;
+	reg->val = cx_read(reg->reg);
+	return 0;
+}
+
+static int cx23417_g_register(struct cx23885_dev *dev,
+			      struct v4l2_dbg_register *reg)
+{
+	u32 value;
+
+	if (dev->v4l_device == NULL)
+		return -EINVAL;
+
+	if ((reg->reg & 0x3) != 0 || reg->reg >= 0x10000)
+		return -EINVAL;
+
+	if (mc417_register_read(dev, (u16) reg->reg, &value))
+		return -EINVAL; /* V4L2 spec, but -EREMOTEIO really */
+
+	reg->size = 4;
+	reg->val = value;
+	return 0;
+}
+
+int cx23885_g_register(struct file *file, void *fh,
+		       struct v4l2_dbg_register *reg)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (reg->match.type == V4L2_CHIP_MATCH_HOST) {
+		switch (reg->match.addr) {
+		case 0:
+			return cx23885_g_host_register(dev, reg);
+		case 1:
+			return cx23417_g_register(dev, reg);
+		default:
+			break;
+		}
+	}
+
+	/* FIXME - any error returns should not be ignored */
+	call_all(dev, core, g_register, reg);
+	return 0;
+}
+
+static int cx23885_s_host_register(struct cx23885_dev *dev,
+				   struct v4l2_dbg_register *reg)
+{
+	if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0))
+		return -EINVAL;
+
+	reg->size = 4;
+	cx_write(reg->reg, reg->val);
+	return 0;
+}
+
+static int cx23417_s_register(struct cx23885_dev *dev,
+			      struct v4l2_dbg_register *reg)
+{
+	if (dev->v4l_device == NULL)
+		return -EINVAL;
+
+	if ((reg->reg & 0x3) != 0 || reg->reg >= 0x10000)
+		return -EINVAL;
+
+	if (mc417_register_write(dev, (u16) reg->reg, (u32) reg->val))
+		return -EINVAL; /* V4L2 spec, but -EREMOTEIO really */
+
+	reg->size = 4;
+	return 0;
+}
+
+int cx23885_s_register(struct file *file, void *fh,
+		       struct v4l2_dbg_register *reg)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (reg->match.type == V4L2_CHIP_MATCH_HOST) {
+		switch (reg->match.addr) {
+		case 0:
+			return cx23885_s_host_register(dev, reg);
+		case 1:
+			return cx23417_s_register(dev, reg);
+		default:
+			break;
+		}
+	}
+
+	/* FIXME - any error returns should not be ignored */
+	call_all(dev, core, s_register, reg);
+	return 0;
+}
+#endif
diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.h b/drivers/media/pci/cx23885/cx23885-ioctl.h
new file mode 100644
index 0000000..315be0c
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-ioctl.h
@@ -0,0 +1,39 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  Various common ioctl() support functions
+ *
+ *  Copyright (c) 2009 Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _CX23885_IOCTL_H_
+#define _CX23885_IOCTL_H_
+
+int cx23885_g_chip_ident(struct file *file, void *fh,
+			 struct v4l2_dbg_chip_ident *chip);
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+int cx23885_g_register(struct file *file, void *fh,
+		       struct v4l2_dbg_register *reg);
+
+
+int cx23885_s_register(struct file *file, void *fh,
+		       struct v4l2_dbg_register *reg);
+
+#endif
+#endif
diff --git a/drivers/media/pci/cx23885/cx23885-ir.c b/drivers/media/pci/cx23885/cx23885-ir.c
new file mode 100644
index 0000000..7125247
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-ir.c
@@ -0,0 +1,117 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  Infrared device support routines - non-input, non-vl42_subdev routines
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#include <media/v4l2-device.h>
+
+#include "cx23885.h"
+#include "cx23885-input.h"
+
+#define CX23885_IR_RX_FIFO_SERVICE_REQ		0
+#define CX23885_IR_RX_END_OF_RX_DETECTED	1
+#define CX23885_IR_RX_HW_FIFO_OVERRUN		2
+#define CX23885_IR_RX_SW_FIFO_OVERRUN		3
+
+#define CX23885_IR_TX_FIFO_SERVICE_REQ		0
+
+
+void cx23885_ir_rx_work_handler(struct work_struct *work)
+{
+	struct cx23885_dev *dev =
+			     container_of(work, struct cx23885_dev, ir_rx_work);
+	u32 events = 0;
+	unsigned long *notifications = &dev->ir_rx_notifications;
+
+	if (test_and_clear_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications))
+		events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN;
+	if (test_and_clear_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications))
+		events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN;
+	if (test_and_clear_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications))
+		events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED;
+	if (test_and_clear_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications))
+		events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ;
+
+	if (events == 0)
+		return;
+
+	if (dev->kernel_ir)
+		cx23885_input_rx_work_handler(dev, events);
+}
+
+void cx23885_ir_tx_work_handler(struct work_struct *work)
+{
+	struct cx23885_dev *dev =
+			     container_of(work, struct cx23885_dev, ir_tx_work);
+	u32 events = 0;
+	unsigned long *notifications = &dev->ir_tx_notifications;
+
+	if (test_and_clear_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications))
+		events |= V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ;
+
+	if (events == 0)
+		return;
+
+}
+
+/* Possibly called in an IRQ context */
+void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)
+{
+	struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev);
+	unsigned long *notifications = &dev->ir_rx_notifications;
+
+	if (events & V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ)
+		set_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications);
+	if (events & V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED)
+		set_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications);
+	if (events & V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN)
+		set_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications);
+	if (events & V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN)
+		set_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications);
+
+	/*
+	 * For the integrated AV core, we are already in a workqueue context.
+	 * For the CX23888 integrated IR, we are in an interrupt context.
+	 */
+	if (sd == dev->sd_cx25840)
+		cx23885_ir_rx_work_handler(&dev->ir_rx_work);
+	else
+		schedule_work(&dev->ir_rx_work);
+}
+
+/* Possibly called in an IRQ context */
+void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)
+{
+	struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev);
+	unsigned long *notifications = &dev->ir_tx_notifications;
+
+	if (events & V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ)
+		set_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications);
+
+	/*
+	 * For the integrated AV core, we are already in a workqueue context.
+	 * For the CX23888 integrated IR, we are in an interrupt context.
+	 */
+	if (sd == dev->sd_cx25840)
+		cx23885_ir_tx_work_handler(&dev->ir_tx_work);
+	else
+		schedule_work(&dev->ir_tx_work);
+}
diff --git a/drivers/media/pci/cx23885/cx23885-ir.h b/drivers/media/pci/cx23885/cx23885-ir.h
new file mode 100644
index 0000000..0c9d8bd
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-ir.h
@@ -0,0 +1,31 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  Infrared device support routines - non-input, non-vl42_subdev routines
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#ifndef _CX23885_IR_H_
+#define _CX23885_IR_H_
+void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events);
+void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events);
+
+void cx23885_ir_rx_work_handler(struct work_struct *work);
+void cx23885_ir_tx_work_handler(struct work_struct *work);
+#endif
diff --git a/drivers/media/pci/cx23885/cx23885-reg.h b/drivers/media/pci/cx23885/cx23885-reg.h
new file mode 100644
index 0000000..a99936e
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-reg.h
@@ -0,0 +1,452 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _CX23885_REG_H_
+#define _CX23885_REG_H_
+
+/*
+Address Map
+0x00000000 -> 0x00009000   TX SRAM  (Fifos)
+0x00010000 -> 0x00013c00   RX SRAM  CMDS + CDT
+
+EACH CMDS struct is 0x80 bytes long
+
+DMAx_PTR1 = 0x03040 address of first cluster
+DMAx_PTR2 = 0x10600 address of the CDT
+DMAx_CNT1 = cluster size in (bytes >> 4) -1
+DMAx_CNT2 = total cdt size for all entries >> 3
+
+Cluster Descriptor entry = 4 DWORDS
+ DWORD 0 -> ptr to cluster
+ DWORD 1 Reserved
+ DWORD 2 Reserved
+ DWORD 3 Reserved
+
+Channel manager Data Structure entry = 20 DWORD
+  0  IntialProgramCounterLow
+  1  IntialProgramCounterHigh
+  2  ClusterDescriptorTableBase
+  3  ClusterDescriptorTableSize
+  4  InstructionQueueBase
+  5  InstructionQueueSize
+...  Reserved
+ 19  Reserved
+*/
+
+/* Risc Instructions */
+#define RISC_CNT_INC		 0x00010000
+#define RISC_CNT_RESET		 0x00030000
+#define RISC_IRQ1		 0x01000000
+#define RISC_IRQ2		 0x02000000
+#define RISC_EOL		 0x04000000
+#define RISC_SOL		 0x08000000
+#define RISC_WRITE		 0x10000000
+#define RISC_SKIP		 0x20000000
+#define RISC_JUMP		 0x70000000
+#define RISC_SYNC		 0x80000000
+#define RISC_RESYNC		 0x80008000
+#define RISC_READ		 0x90000000
+#define RISC_WRITERM		 0xB0000000
+#define RISC_WRITECM		 0xC0000000
+#define RISC_WRITECR		 0xD0000000
+#define RISC_WRITEC		 0x50000000
+#define RISC_READC		 0xA0000000
+
+
+/* Audio and Video Core */
+#define HOST_REG1		0x00000000
+#define HOST_REG2		0x00000001
+#define HOST_REG3		0x00000002
+
+/* Chip Configuration Registers */
+#define CHIP_CTRL		0x00000100
+#define AFE_CTRL		0x00000104
+#define VID_PLL_INT_POST	0x00000108
+#define VID_PLL_FRAC		0x0000010C
+#define AUX_PLL_INT_POST	0x00000110
+#define AUX_PLL_FRAC		0x00000114
+#define SYS_PLL_INT_POST	0x00000118
+#define SYS_PLL_FRAC		0x0000011C
+#define PIN_CTRL		0x00000120
+#define AUD_IO_CTRL		0x00000124
+#define AUD_LOCK1		0x00000128
+#define AUD_LOCK2		0x0000012C
+#define POWER_CTRL		0x00000130
+#define AFE_DIAG_CTRL1		0x00000134
+#define AFE_DIAG_CTRL3		0x0000013C
+#define PLL_DIAG_CTRL		0x00000140
+#define AFE_CLK_OUT_CTRL	0x00000144
+#define DLL1_DIAG_CTRL		0x0000015C
+
+/* GPIO[23:19] Output Enable */
+#define GPIO2_OUT_EN_REG	0x00000160
+/* GPIO[23:19] Data Registers */
+#define GPIO2			0x00000164
+
+#define IFADC_CTRL		0x00000180
+
+/* Infrared Remote Registers */
+#define IR_CNTRL_REG	0x00000200
+#define IR_TXCLK_REG	0x00000204
+#define IR_RXCLK_REG	0x00000208
+#define IR_CDUTY_REG	0x0000020C
+#define IR_STAT_REG	0x00000210
+#define IR_IRQEN_REG	0x00000214
+#define IR_FILTR_REG	0x00000218
+#define IR_FIFO_REG	0x0000023C
+
+/* Video Decoder Registers */
+#define MODE_CTRL		0x00000400
+#define OUT_CTRL1		0x00000404
+#define OUT_CTRL2		0x00000408
+#define GEN_STAT		0x0000040C
+#define INT_STAT_MASK		0x00000410
+#define LUMA_CTRL		0x00000414
+#define HSCALE_CTRL		0x00000418
+#define VSCALE_CTRL		0x0000041C
+#define CHROMA_CTRL		0x00000420
+#define VBI_LINE_CTRL1		0x00000424
+#define VBI_LINE_CTRL2		0x00000428
+#define VBI_LINE_CTRL3		0x0000042C
+#define VBI_LINE_CTRL4		0x00000430
+#define VBI_LINE_CTRL5		0x00000434
+#define VBI_FC_CFG		0x00000438
+#define VBI_MISC_CFG1		0x0000043C
+#define VBI_MISC_CFG2		0x00000440
+#define VBI_PAY1		0x00000444
+#define VBI_PAY2		0x00000448
+#define VBI_CUST1_CFG1		0x0000044C
+#define VBI_CUST1_CFG2		0x00000450
+#define VBI_CUST1_CFG3		0x00000454
+#define VBI_CUST2_CFG1		0x00000458
+#define VBI_CUST2_CFG2		0x0000045C
+#define VBI_CUST2_CFG3		0x00000460
+#define VBI_CUST3_CFG1		0x00000464
+#define VBI_CUST3_CFG2		0x00000468
+#define VBI_CUST3_CFG3		0x0000046C
+#define HORIZ_TIM_CTRL		0x00000470
+#define VERT_TIM_CTRL		0x00000474
+#define SRC_COMB_CFG		0x00000478
+#define CHROMA_VBIOFF_CFG	0x0000047C
+#define FIELD_COUNT		0x00000480
+#define MISC_TIM_CTRL		0x00000484
+#define DFE_CTRL1		0x00000488
+#define DFE_CTRL2		0x0000048C
+#define DFE_CTRL3		0x00000490
+#define PLL_CTRL		0x00000494
+#define HTL_CTRL		0x00000498
+#define COMB_CTRL		0x0000049C
+#define CRUSH_CTRL		0x000004A0
+#define SOFT_RST_CTRL		0x000004A4
+#define CX885_VERSION		0x000004B4
+#define VBI_PASS_CTRL		0x000004BC
+
+/* Audio Decoder Registers */
+/* 8051 Configuration */
+#define DL_CTL		0x00000800
+#define STD_DET_STATUS	0x00000804
+#define STD_DET_CTL	0x00000808
+#define DW8051_INT	0x0000080C
+#define GENERAL_CTL	0x00000810
+#define AAGC_CTL	0x00000814
+#define DEMATRIX_CTL	0x000008CC
+#define PATH1_CTL1	0x000008D0
+#define PATH1_VOL_CTL	0x000008D4
+#define PATH1_EQ_CTL	0x000008D8
+#define PATH1_SC_CTL	0x000008DC
+#define PATH2_CTL1	0x000008E0
+#define PATH2_VOL_CTL	0x000008E4
+#define PATH2_EQ_CTL	0x000008E8
+#define PATH2_SC_CTL	0x000008EC
+
+/* Sample Rate Converter */
+#define SRC_CTL		0x000008F0
+#define SRC_LF_COEF	0x000008F4
+#define SRC1_CTL	0x000008F8
+#define SRC2_CTL	0x000008FC
+#define SRC3_CTL	0x00000900
+#define SRC4_CTL	0x00000904
+#define SRC5_CTL	0x00000908
+#define SRC6_CTL	0x0000090C
+#define BAND_OUT_SEL	0x00000910
+#define I2S_N_CTL	0x00000914
+#define I2S_OUT_CTL	0x00000918
+#define AUTOCONFIG_REG	0x000009C4
+
+/* Audio ADC Registers */
+#define DSM_CTRL1	0x00000000
+#define DSM_CTRL2	0x00000001
+#define CHP_EN_CTRL	0x00000002
+#define CHP_CLK_CTRL1	0x00000004
+#define CHP_CLK_CTRL2	0x00000005
+#define BG_REF_CTRL	0x00000006
+#define SD2_SW_CTRL1	0x00000008
+#define SD2_SW_CTRL2	0x00000009
+#define SD2_BIAS_CTRL	0x0000000A
+#define AMP_BIAS_CTRL	0x0000000C
+#define CH_PWR_CTRL1	0x0000000E
+#define FLD_CH_SEL      (1 << 3)
+#define CH_PWR_CTRL2	0x0000000F
+#define DSM_STATUS1	0x00000010
+#define DSM_STATUS2	0x00000011
+#define DIG_CTL1	0x00000012
+#define DIG_CTL2	0x00000013
+#define I2S_TX_CFG	0x0000001A
+
+#define DEV_CNTRL2	0x00040000
+
+#define PCI_MSK_IR        (1 << 28)
+#define PCI_MSK_AV_CORE   (1 << 27)
+#define PCI_MSK_GPIO1     (1 << 24)
+#define PCI_MSK_GPIO0     (1 << 23)
+#define PCI_MSK_APB_DMA   (1 << 12)
+#define PCI_MSK_AL_WR     (1 << 11)
+#define PCI_MSK_AL_RD     (1 << 10)
+#define PCI_MSK_RISC_WR   (1 <<  9)
+#define PCI_MSK_RISC_RD   (1 <<  8)
+#define PCI_MSK_AUD_EXT   (1 <<  4)
+#define PCI_MSK_AUD_INT   (1 <<  3)
+#define PCI_MSK_VID_C     (1 <<  2)
+#define PCI_MSK_VID_B     (1 <<  1)
+#define PCI_MSK_VID_A      1
+#define PCI_INT_MSK	0x00040010
+
+#define PCI_INT_STAT	0x00040014
+#define PCI_INT_MSTAT	0x00040018
+
+#define VID_A_INT_MSK	0x00040020
+#define VID_A_INT_STAT	0x00040024
+#define VID_A_INT_MSTAT	0x00040028
+#define VID_A_INT_SSTAT	0x0004002C
+
+#define VID_B_INT_MSK	0x00040030
+#define VID_B_MSK_BAD_PKT     (1 << 20)
+#define VID_B_MSK_VBI_OPC_ERR (1 << 17)
+#define VID_B_MSK_OPC_ERR     (1 << 16)
+#define VID_B_MSK_VBI_SYNC    (1 << 13)
+#define VID_B_MSK_SYNC        (1 << 12)
+#define VID_B_MSK_VBI_OF      (1 <<  9)
+#define VID_B_MSK_OF          (1 <<  8)
+#define VID_B_MSK_VBI_RISCI2  (1 <<  5)
+#define VID_B_MSK_RISCI2      (1 <<  4)
+#define VID_B_MSK_VBI_RISCI1  (1 <<  1)
+#define VID_B_MSK_RISCI1       1
+#define VID_B_INT_STAT	0x00040034
+#define VID_B_INT_MSTAT	0x00040038
+#define VID_B_INT_SSTAT	0x0004003C
+
+#define VID_B_MSK_BAD_PKT (1 << 20)
+#define VID_B_MSK_OPC_ERR (1 << 16)
+#define VID_B_MSK_SYNC    (1 << 12)
+#define VID_B_MSK_OF      (1 <<  8)
+#define VID_B_MSK_RISCI2  (1 <<  4)
+#define VID_B_MSK_RISCI1   1
+
+#define VID_C_MSK_BAD_PKT (1 << 20)
+#define VID_C_MSK_OPC_ERR (1 << 16)
+#define VID_C_MSK_SYNC    (1 << 12)
+#define VID_C_MSK_OF      (1 <<  8)
+#define VID_C_MSK_RISCI2  (1 <<  4)
+#define VID_C_MSK_RISCI1   1
+
+/* A superset for testing purposes */
+#define VID_BC_MSK_BAD_PKT (1 << 20)
+#define VID_BC_MSK_OPC_ERR (1 << 16)
+#define VID_BC_MSK_SYNC    (1 << 12)
+#define VID_BC_MSK_OF      (1 <<  8)
+#define VID_BC_MSK_VBI_RISCI2 (1 <<  5)
+#define VID_BC_MSK_RISCI2  (1 <<  4)
+#define VID_BC_MSK_VBI_RISCI1 (1 <<  1)
+#define VID_BC_MSK_RISCI1   1
+
+#define VID_C_INT_MSK	0x00040040
+#define VID_C_INT_STAT	0x00040044
+#define VID_C_INT_MSTAT	0x00040048
+#define VID_C_INT_SSTAT	0x0004004C
+
+#define AUDIO_INT_INT_MSK	0x00040050
+#define AUDIO_INT_INT_STAT	0x00040054
+#define AUDIO_INT_INT_MSTAT	0x00040058
+#define AUDIO_INT_INT_SSTAT	0x0004005C
+
+#define AUDIO_EXT_INT_MSK	0x00040060
+#define AUDIO_EXT_INT_STAT	0x00040064
+#define AUDIO_EXT_INT_MSTAT	0x00040068
+#define AUDIO_EXT_INT_SSTAT	0x0004006C
+
+#define RDR_CFG0	0x00050000
+#define RDR_CFG1	0x00050004
+#define RDR_CFG2	0x00050008
+#define RDR_RDRCTL1	0x0005030c
+#define RDR_TLCTL0	0x00050318
+
+/* APB DMAC Current Buffer Pointer */
+#define DMA1_PTR1	0x00100000
+#define DMA2_PTR1	0x00100004
+#define DMA3_PTR1	0x00100008
+#define DMA4_PTR1	0x0010000C
+#define DMA5_PTR1	0x00100010
+#define DMA6_PTR1	0x00100014
+#define DMA7_PTR1	0x00100018
+#define DMA8_PTR1	0x0010001C
+
+/* APB DMAC Current Table Pointer */
+#define DMA1_PTR2	0x00100040
+#define DMA2_PTR2	0x00100044
+#define DMA3_PTR2	0x00100048
+#define DMA4_PTR2	0x0010004C
+#define DMA5_PTR2	0x00100050
+#define DMA6_PTR2	0x00100054
+#define DMA7_PTR2	0x00100058
+#define DMA8_PTR2	0x0010005C
+
+/* APB DMAC Buffer Limit */
+#define DMA1_CNT1	0x00100080
+#define DMA2_CNT1	0x00100084
+#define DMA3_CNT1	0x00100088
+#define DMA4_CNT1	0x0010008C
+#define DMA5_CNT1	0x00100090
+#define DMA6_CNT1	0x00100094
+#define DMA7_CNT1	0x00100098
+#define DMA8_CNT1	0x0010009C
+
+/* APB DMAC Table Size */
+#define DMA1_CNT2	0x001000C0
+#define DMA2_CNT2	0x001000C4
+#define DMA3_CNT2	0x001000C8
+#define DMA4_CNT2	0x001000CC
+#define DMA5_CNT2	0x001000D0
+#define DMA6_CNT2	0x001000D4
+#define DMA7_CNT2	0x001000D8
+#define DMA8_CNT2	0x001000DC
+
+/* Timer Counters */
+#define TM_CNT_LDW	0x00110000
+#define TM_CNT_UW	0x00110004
+#define TM_LMT_LDW	0x00110008
+#define TM_LMT_UW	0x0011000C
+
+/* GPIO */
+#define GP0_IO		0x00110010
+#define GPIO_ISM	0x00110014
+#define SOFT_RESET	0x0011001C
+
+/* GPIO (417 Microsoftcontroller) RW Data */
+#define MC417_RWD	0x00110020
+
+/* GPIO (417 Microsoftcontroller) Output Enable, Low Active */
+#define MC417_OEN	0x00110024
+#define MC417_CTL	0x00110028
+#define ALT_PIN_OUT_SEL 0x0011002C
+#define CLK_DELAY	0x00110048
+#define PAD_CTRL	0x0011004C
+
+/* Video A Interface */
+#define VID_A_GPCNT		0x00130020
+#define VBI_A_GPCNT		0x00130024
+#define VID_A_GPCNT_CTL		0x00130030
+#define VBI_A_GPCNT_CTL		0x00130034
+#define VID_A_DMA_CTL		0x00130040
+#define VID_A_VIP_CTRL		0x00130080
+#define VID_A_PIXEL_FRMT	0x00130084
+#define VID_A_VBI_CTRL		0x00130088
+
+/* Video B Interface */
+#define VID_B_DMA		0x00130100
+#define VBI_B_DMA		0x00130108
+#define VID_B_GPCNT		0x00130120
+#define VBI_B_GPCNT		0x00130124
+#define VID_B_GPCNT_CTL		0x00130134
+#define VBI_B_GPCNT_CTL		0x00130138
+#define VID_B_DMA_CTL		0x00130140
+#define VID_B_SRC_SEL		0x00130144
+#define VID_B_LNGTH		0x00130150
+#define VID_B_HW_SOP_CTL	0x00130154
+#define VID_B_GEN_CTL		0x00130158
+#define VID_B_BD_PKT_STATUS	0x0013015C
+#define VID_B_SOP_STATUS	0x00130160
+#define VID_B_FIFO_OVFL_STAT	0x00130164
+#define VID_B_VLD_MISC		0x00130168
+#define VID_B_TS_CLK_EN		0x0013016C
+#define VID_B_VIP_CTRL		0x00130180
+#define VID_B_PIXEL_FRMT	0x00130184
+
+/* Video C Interface */
+#define VID_C_GPCNT		0x00130220
+#define VID_C_GPCNT_CTL		0x00130230
+#define VBI_C_GPCNT_CTL		0x00130234
+#define VID_C_DMA_CTL		0x00130240
+#define VID_C_LNGTH		0x00130250
+#define VID_C_HW_SOP_CTL	0x00130254
+#define VID_C_GEN_CTL		0x00130258
+#define VID_C_BD_PKT_STATUS	0x0013025C
+#define VID_C_SOP_STATUS	0x00130260
+#define VID_C_FIFO_OVFL_STAT	0x00130264
+#define VID_C_VLD_MISC		0x00130268
+#define VID_C_TS_CLK_EN		0x0013026C
+
+/* Internal Audio Interface */
+#define AUD_INT_A_GPCNT		0x00140020
+#define AUD_INT_B_GPCNT		0x00140024
+#define AUD_INT_A_GPCNT_CTL	0x00140030
+#define AUD_INT_B_GPCNT_CTL	0x00140034
+#define AUD_INT_DMA_CTL		0x00140040
+#define AUD_INT_A_LNGTH		0x00140050
+#define AUD_INT_B_LNGTH		0x00140054
+#define AUD_INT_A_MODE		0x00140058
+#define AUD_INT_B_MODE		0x0014005C
+
+/* External Audio Interface */
+#define AUD_EXT_DMA		0x00140100
+#define AUD_EXT_GPCNT		0x00140120
+#define AUD_EXT_GPCNT_CTL	0x00140130
+#define AUD_EXT_DMA_CTL		0x00140140
+#define AUD_EXT_LNGTH		0x00140150
+#define AUD_EXT_A_MODE		0x00140158
+
+/* I2C Bus 1 */
+#define I2C1_ADDR	0x00180000
+#define I2C1_WDATA	0x00180004
+#define I2C1_CTRL	0x00180008
+#define I2C1_RDATA	0x0018000C
+#define I2C1_STAT	0x00180010
+
+/* I2C Bus 2 */
+#define I2C2_ADDR	0x00190000
+#define I2C2_WDATA	0x00190004
+#define I2C2_CTRL	0x00190008
+#define I2C2_RDATA	0x0019000C
+#define I2C2_STAT	0x00190010
+
+/* I2C Bus 3 */
+#define I2C3_ADDR	0x001A0000
+#define I2C3_WDATA	0x001A0004
+#define I2C3_CTRL	0x001A0008
+#define I2C3_RDATA	0x001A000C
+#define I2C3_STAT	0x001A0010
+
+/* UART */
+#define UART_CTL	0x001B0000
+#define UART_BRD	0x001B0004
+#define UART_ISR	0x001B000C
+#define UART_CNT	0x001B0010
+
+#endif /* _CX23885_REG_H_ */
diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c
new file mode 100644
index 0000000..a1154f0
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-vbi.c
@@ -0,0 +1,295 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+
+#include "cx23885.h"
+
+static unsigned int vbibufs = 4;
+module_param(vbibufs, int, 0644);
+MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
+
+static unsigned int vbi_debug;
+module_param(vbi_debug, int, 0644);
+MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
+
+#define dprintk(level, fmt, arg...)\
+	do { if (vbi_debug >= level)\
+		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
+	} while (0)
+
+/* ------------------------------------------------------------------ */
+
+#define VBI_LINE_LENGTH 1440
+#define NTSC_VBI_START_LINE 10        /* line 10 - 21 */
+#define NTSC_VBI_END_LINE   21
+#define NTSC_VBI_LINES      (NTSC_VBI_END_LINE - NTSC_VBI_START_LINE + 1)
+
+
+int cx23885_vbi_fmt(struct file *file, void *priv,
+	struct v4l2_format *f)
+{
+	struct cx23885_fh *fh = priv;
+	struct cx23885_dev *dev = fh->dev;
+
+	if (dev->tvnorm & V4L2_STD_525_60) {
+		/* ntsc */
+		f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
+		f->fmt.vbi.sampling_rate = 27000000;
+		f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+		f->fmt.vbi.offset = 0;
+		f->fmt.vbi.flags = 0;
+		f->fmt.vbi.start[0] = 10;
+		f->fmt.vbi.count[0] = 17;
+		f->fmt.vbi.start[1] = 263 + 10 + 1;
+		f->fmt.vbi.count[1] = 17;
+	} else if (dev->tvnorm & V4L2_STD_625_50) {
+		/* pal */
+		f->fmt.vbi.sampling_rate = 35468950;
+		f->fmt.vbi.start[0] = 7 - 1;
+		f->fmt.vbi.start[1] = 319 - 1;
+	}
+
+	return 0;
+}
+
+/* We're given the Video Interrupt status register.
+ * The cx23885_video_irq() func has already validated
+ * the potential error bits, we just need to
+ * deal with vbi payload and return indication if
+ * we actually processed any payload.
+ */
+int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status)
+{
+	u32 count;
+	int handled = 0;
+
+	if (status & VID_BC_MSK_VBI_RISCI1) {
+		dprintk(1, "%s() VID_BC_MSK_VBI_RISCI1\n", __func__);
+		spin_lock(&dev->slock);
+		count = cx_read(VID_A_GPCNT);
+		cx23885_video_wakeup(dev, &dev->vbiq, count);
+		spin_unlock(&dev->slock);
+		handled++;
+	}
+
+	if (status & VID_BC_MSK_VBI_RISCI2) {
+		dprintk(1, "%s() VID_BC_MSK_VBI_RISCI2\n", __func__);
+		dprintk(2, "stopper vbi\n");
+		spin_lock(&dev->slock);
+		cx23885_restart_vbi_queue(dev, &dev->vbiq);
+		spin_unlock(&dev->slock);
+		handled++;
+	}
+
+	return handled;
+}
+
+static int cx23885_start_vbi_dma(struct cx23885_dev    *dev,
+			 struct cx23885_dmaqueue *q,
+			 struct cx23885_buffer   *buf)
+{
+	dprintk(1, "%s()\n", __func__);
+
+	/* setup fifo + format */
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02],
+				buf->vb.width, buf->risc.dma);
+
+	/* reset counter */
+	cx_write(VID_A_GPCNT_CTL, 3);
+	cx_write(VID_A_VBI_CTRL, 3);
+	cx_write(VBI_A_GPCNT_CTL, 3);
+	q->count = 1;
+
+	/* enable irq */
+	cx23885_irq_add_enable(dev, 0x01);
+	cx_set(VID_A_INT_MSK, 0x000022);
+
+	/* start dma */
+	cx_set(DEV_CNTRL2, (1<<5));
+	cx_set(VID_A_DMA_CTL, 0x22); /* FIFO and RISC enable */
+
+	return 0;
+}
+
+
+int cx23885_restart_vbi_queue(struct cx23885_dev    *dev,
+			     struct cx23885_dmaqueue *q)
+{
+	struct cx23885_buffer *buf;
+	struct list_head *item;
+
+	if (list_empty(&q->active))
+		return 0;
+
+	buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
+	dprintk(2, "restart_queue [%p/%d]: restart dma\n",
+		buf, buf->vb.i);
+	cx23885_start_vbi_dma(dev, q, buf);
+	list_for_each(item, &q->active) {
+		buf = list_entry(item, struct cx23885_buffer, vb.queue);
+		buf->count = q->count++;
+	}
+	mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30));
+	return 0;
+}
+
+void cx23885_vbi_timeout(unsigned long data)
+{
+	struct cx23885_dev *dev = (struct cx23885_dev *)data;
+	struct cx23885_dmaqueue *q = &dev->vbiq;
+	struct cx23885_buffer *buf;
+	unsigned long flags;
+
+	/* Stop the VBI engine */
+	cx_clear(VID_A_DMA_CTL, 0x22);
+
+	spin_lock_irqsave(&dev->slock, flags);
+	while (!list_empty(&q->active)) {
+		buf = list_entry(q->active.next, struct cx23885_buffer,
+			vb.queue);
+		list_del(&buf->vb.queue);
+		buf->vb.state = VIDEOBUF_ERROR;
+		wake_up(&buf->vb.done);
+		printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name,
+		       buf, buf->vb.i, (unsigned long)buf->risc.dma);
+	}
+	cx23885_restart_vbi_queue(dev, q);
+	spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+/* ------------------------------------------------------------------ */
+#define VBI_LINE_LENGTH 1440
+#define VBI_LINE_COUNT 17
+
+static int
+vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+	*size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
+	if (0 == *count)
+		*count = vbibufs;
+	if (*count < 2)
+		*count = 2;
+	if (*count > 32)
+		*count = 32;
+	return 0;
+}
+
+static int
+vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+	    enum v4l2_field field)
+{
+	struct cx23885_fh *fh  = q->priv_data;
+	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_buffer *buf = container_of(vb,
+		struct cx23885_buffer, vb);
+	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+	unsigned int size;
+	int rc;
+
+	size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+		return -EINVAL;
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		buf->vb.width  = VBI_LINE_LENGTH;
+		buf->vb.height = VBI_LINE_COUNT;
+		buf->vb.size   = size;
+		buf->vb.field  = V4L2_FIELD_SEQ_TB;
+
+		rc = videobuf_iolock(q, &buf->vb, NULL);
+		if (0 != rc)
+			goto fail;
+		cx23885_risc_vbibuffer(dev->pci, &buf->risc,
+				 dma->sglist,
+				 0, buf->vb.width * buf->vb.height,
+				 buf->vb.width, 0,
+				 buf->vb.height);
+	}
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+ fail:
+	cx23885_free_buffer(q, buf);
+	return rc;
+}
+
+static void
+vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct cx23885_buffer   *buf =
+		container_of(vb, struct cx23885_buffer, vb);
+	struct cx23885_buffer   *prev;
+	struct cx23885_fh       *fh   = vq->priv_data;
+	struct cx23885_dev      *dev  = fh->dev;
+	struct cx23885_dmaqueue *q    = &dev->vbiq;
+
+	/* add jump to stopper */
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
+
+	if (list_empty(&q->active)) {
+		list_add_tail(&buf->vb.queue, &q->active);
+		cx23885_start_vbi_dma(dev, q, buf);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		buf->count    = q->count++;
+		mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30));
+		dprintk(2, "[%p/%d] vbi_queue - first active\n",
+			buf, buf->vb.i);
+
+	} else {
+		prev = list_entry(q->active.prev, struct cx23885_buffer,
+			vb.queue);
+		list_add_tail(&buf->vb.queue, &q->active);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		buf->count    = q->count++;
+		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+		prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */
+		dprintk(2, "[%p/%d] buffer_queue - append to active\n",
+			buf, buf->vb.i);
+	}
+}
+
+static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct cx23885_buffer *buf =
+		container_of(vb, struct cx23885_buffer, vb);
+
+	cx23885_free_buffer(q, buf);
+}
+
+struct videobuf_queue_ops cx23885_vbi_qops = {
+	.buf_setup    = vbi_setup,
+	.buf_prepare  = vbi_prepare,
+	.buf_queue    = vbi_queue,
+	.buf_release  = vbi_release,
+};
+
+/* ------------------------------------------------------------------ */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
new file mode 100644
index 0000000..22f8e7f
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -0,0 +1,1926 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <asm/div64.h>
+
+#include "cx23885.h"
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include "cx23885-ioctl.h"
+#include "tuner-xc2028.h"
+
+#include <media/cx25840.h>
+
+MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
+MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
+MODULE_LICENSE("GPL");
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
+static unsigned int vbi_nr[]   = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(video_nr, int, NULL, 0444);
+module_param_array(vbi_nr,   int, NULL, 0444);
+module_param_array(radio_nr, int, NULL, 0444);
+
+MODULE_PARM_DESC(video_nr, "video device numbers");
+MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
+MODULE_PARM_DESC(radio_nr, "radio device numbers");
+
+static unsigned int video_debug;
+module_param(video_debug, int, 0644);
+MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
+
+static unsigned int irq_debug;
+module_param(irq_debug, int, 0644);
+MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]");
+
+static unsigned int vid_limit = 16;
+module_param(vid_limit, int, 0644);
+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
+
+#define dprintk(level, fmt, arg...)\
+	do { if (video_debug >= level)\
+		printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg);\
+	} while (0)
+
+/* ------------------------------------------------------------------- */
+/* static data                                                         */
+
+#define FORMAT_FLAGS_PACKED       0x01
+#if 0
+static struct cx23885_fmt formats[] = {
+	{
+		.name     = "8 bpp, gray",
+		.fourcc   = V4L2_PIX_FMT_GREY,
+		.depth    = 8,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "15 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_RGB555,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "15 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB555X,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "16 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_RGB565,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "16 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB565X,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "24 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_BGR24,
+		.depth    = 24,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "32 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_BGR32,
+		.depth    = 32,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "32 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB32,
+		.depth    = 32,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "4:2:2, packed, YUYV",
+		.fourcc   = V4L2_PIX_FMT_YUYV,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "4:2:2, packed, UYVY",
+		.fourcc   = V4L2_PIX_FMT_UYVY,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},
+};
+#else
+static struct cx23885_fmt formats[] = {
+	{
+#if 0
+		.name     = "4:2:2, packed, UYVY",
+		.fourcc   = V4L2_PIX_FMT_UYVY,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+#endif
+		.name     = "4:2:2, packed, YUYV",
+		.fourcc   = V4L2_PIX_FMT_YUYV,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}
+};
+#endif
+
+static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++)
+		if (formats[i].fourcc == fourcc)
+			return formats+i;
+
+	printk(KERN_ERR "%s(%c%c%c%c) NOT FOUND\n", __func__,
+		(fourcc & 0xff),
+		((fourcc >> 8) & 0xff),
+		((fourcc >> 16) & 0xff),
+		((fourcc >> 24) & 0xff)
+		);
+	return NULL;
+}
+
+/* ------------------------------------------------------------------- */
+
+static const struct v4l2_queryctrl no_ctl = {
+	.name  = "42",
+	.flags = V4L2_CTRL_FLAG_DISABLED,
+};
+
+static struct cx23885_ctrl cx23885_ctls[] = {
+	/* --- video --- */
+	{
+		.v = {
+			.id            = V4L2_CID_BRIGHTNESS,
+			.name          = "Brightness",
+			.minimum       = 0x00,
+			.maximum       = 0xff,
+			.step          = 1,
+			.default_value = 0x7f,
+			.type          = V4L2_CTRL_TYPE_INTEGER,
+		},
+		.off                   = 128,
+		.reg                   = LUMA_CTRL,
+		.mask                  = 0x00ff,
+		.shift                 = 0,
+	}, {
+		.v = {
+			.id            = V4L2_CID_CONTRAST,
+			.name          = "Contrast",
+			.minimum       = 0,
+			.maximum       = 0x7f,
+			.step          = 1,
+			.default_value = 0x3f,
+			.type          = V4L2_CTRL_TYPE_INTEGER,
+		},
+		.off                   = 0,
+		.reg                   = LUMA_CTRL,
+		.mask                  = 0xff00,
+		.shift                 = 8,
+	}, {
+		.v = {
+			.id            = V4L2_CID_HUE,
+			.name          = "Hue",
+			.minimum       = -127,
+			.maximum       = 128,
+			.step          = 1,
+			.default_value = 0x0,
+			.type          = V4L2_CTRL_TYPE_INTEGER,
+		},
+		.off                   = 128,
+		.reg                   = CHROMA_CTRL,
+		.mask                  = 0xff0000,
+		.shift                 = 16,
+	}, {
+		/* strictly, this only describes only U saturation.
+		 * V saturation is handled specially through code.
+		 */
+		.v = {
+			.id            = V4L2_CID_SATURATION,
+			.name          = "Saturation",
+			.minimum       = 0,
+			.maximum       = 0x7f,
+			.step          = 1,
+			.default_value = 0x3f,
+			.type          = V4L2_CTRL_TYPE_INTEGER,
+		},
+		.off                   = 0,
+		.reg                   = CHROMA_CTRL,
+		.mask                  = 0x00ff,
+		.shift                 = 0,
+	}, {
+	/* --- audio --- */
+		.v = {
+			.id            = V4L2_CID_AUDIO_MUTE,
+			.name          = "Mute",
+			.minimum       = 0,
+			.maximum       = 1,
+			.default_value = 1,
+			.type          = V4L2_CTRL_TYPE_BOOLEAN,
+		},
+		.reg                   = PATH1_CTL1,
+		.mask                  = (0x1f << 24),
+		.shift                 = 24,
+	}, {
+		.v = {
+			.id            = V4L2_CID_AUDIO_VOLUME,
+			.name          = "Volume",
+			.minimum       = 0,
+			.maximum       = 65535,
+			.step          = 65535 / 100,
+			.default_value = 65535,
+			.type          = V4L2_CTRL_TYPE_INTEGER,
+		},
+		.reg                   = PATH1_VOL_CTL,
+		.mask                  = 0xff,
+		.shift                 = 0,
+	}
+};
+static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls);
+
+/* Must be sorted from low to high control ID! */
+static const u32 cx23885_user_ctrls[] = {
+	V4L2_CID_USER_CLASS,
+	V4L2_CID_BRIGHTNESS,
+	V4L2_CID_CONTRAST,
+	V4L2_CID_SATURATION,
+	V4L2_CID_HUE,
+	V4L2_CID_AUDIO_VOLUME,
+	V4L2_CID_AUDIO_MUTE,
+	0
+};
+
+static const u32 *ctrl_classes[] = {
+	cx23885_user_ctrls,
+	NULL
+};
+
+void cx23885_video_wakeup(struct cx23885_dev *dev,
+	struct cx23885_dmaqueue *q, u32 count)
+{
+	struct cx23885_buffer *buf;
+	int bc;
+
+	for (bc = 0;; bc++) {
+		if (list_empty(&q->active))
+			break;
+		buf = list_entry(q->active.next,
+				 struct cx23885_buffer, vb.queue);
+
+		/* count comes from the hw and is is 16bit wide --
+		 * this trick handles wrap-arounds correctly for
+		 * up to 32767 buffers in flight... */
+		if ((s16) (count - buf->count) < 0)
+			break;
+
+		do_gettimeofday(&buf->vb.ts);
+		dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
+			count, buf->count);
+		buf->vb.state = VIDEOBUF_DONE;
+		list_del(&buf->vb.queue);
+		wake_up(&buf->vb.done);
+	}
+	if (list_empty(&q->active))
+		del_timer(&q->timeout);
+	else
+		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+	if (bc != 1)
+		printk(KERN_ERR "%s: %d buffers handled (should be 1)\n",
+			__func__, bc);
+}
+
+int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
+{
+	dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
+		__func__,
+		(unsigned int)norm,
+		v4l2_norm_to_name(norm));
+
+	dev->tvnorm = norm;
+
+	call_all(dev, core, s_std, norm);
+
+	return 0;
+}
+
+static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
+				    struct pci_dev *pci,
+				    struct video_device *template,
+				    char *type)
+{
+	struct video_device *vfd;
+	dprintk(1, "%s()\n", __func__);
+
+	vfd = video_device_alloc();
+	if (NULL == vfd)
+		return NULL;
+	*vfd = *template;
+	vfd->v4l2_dev = &dev->v4l2_dev;
+	vfd->release = video_device_release;
+	snprintf(vfd->name, sizeof(vfd->name), "%s (%s)",
+		 cx23885_boards[dev->board].name, type);
+	video_set_drvdata(vfd, dev);
+	return vfd;
+}
+
+static int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl)
+{
+	int i;
+
+	if (qctrl->id < V4L2_CID_BASE ||
+	    qctrl->id >= V4L2_CID_LASTP1)
+		return -EINVAL;
+	for (i = 0; i < CX23885_CTLS; i++)
+		if (cx23885_ctls[i].v.id == qctrl->id)
+			break;
+	if (i == CX23885_CTLS) {
+		*qctrl = no_ctl;
+		return 0;
+	}
+	*qctrl = cx23885_ctls[i].v;
+	return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* resource management                                                 */
+
+static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh,
+	unsigned int bit)
+{
+	dprintk(1, "%s()\n", __func__);
+	if (fh->resources & bit)
+		/* have it already allocated */
+		return 1;
+
+	/* is it free? */
+	mutex_lock(&dev->lock);
+	if (dev->resources & bit) {
+		/* no, someone else uses it */
+		mutex_unlock(&dev->lock);
+		return 0;
+	}
+	/* it's free, grab it */
+	fh->resources  |= bit;
+	dev->resources |= bit;
+	dprintk(1, "res: get %d\n", bit);
+	mutex_unlock(&dev->lock);
+	return 1;
+}
+
+static int res_check(struct cx23885_fh *fh, unsigned int bit)
+{
+	return fh->resources & bit;
+}
+
+static int res_locked(struct cx23885_dev *dev, unsigned int bit)
+{
+	return dev->resources & bit;
+}
+
+static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
+	unsigned int bits)
+{
+	BUG_ON((fh->resources & bits) != bits);
+	dprintk(1, "%s()\n", __func__);
+
+	mutex_lock(&dev->lock);
+	fh->resources  &= ~bits;
+	dev->resources &= ~bits;
+	dprintk(1, "res: put %d\n", bits);
+	mutex_unlock(&dev->lock);
+}
+
+static int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data)
+{
+	/* 8 bit registers, 8 bit values */
+	u8 buf[] = { reg, data };
+
+	struct i2c_msg msg = { .addr = 0x98 >> 1,
+		.flags = 0, .buf = buf, .len = 2 };
+
+	return i2c_transfer(&dev->i2c_bus[2].i2c_adap, &msg, 1);
+}
+
+static u8 cx23885_flatiron_read(struct cx23885_dev *dev, u8 reg)
+{
+	/* 8 bit registers, 8 bit values */
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+
+	struct i2c_msg msg[] = {
+		{ .addr = 0x98 >> 1, .flags = 0, .buf = b0, .len = 1 },
+		{ .addr = 0x98 >> 1, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+	};
+
+	ret = i2c_transfer(&dev->i2c_bus[2].i2c_adap, &msg[0], 2);
+	if (ret != 2)
+		printk(KERN_ERR "%s() error\n", __func__);
+
+	return b1[0];
+}
+
+static void cx23885_flatiron_dump(struct cx23885_dev *dev)
+{
+	int i;
+	dprintk(1, "Flatiron dump\n");
+	for (i = 0; i < 0x24; i++) {
+		dprintk(1, "FI[%02x] = %02x\n", i,
+			cx23885_flatiron_read(dev, i));
+	}
+}
+
+static int cx23885_flatiron_mux(struct cx23885_dev *dev, int input)
+{
+	u8 val;
+	dprintk(1, "%s(input = %d)\n", __func__, input);
+
+	if (input == 1)
+		val = cx23885_flatiron_read(dev, CH_PWR_CTRL1) & ~FLD_CH_SEL;
+	else if (input == 2)
+		val = cx23885_flatiron_read(dev, CH_PWR_CTRL1) | FLD_CH_SEL;
+	else
+		return -EINVAL;
+
+	val |= 0x20; /* Enable clock to delta-sigma and dec filter */
+
+	cx23885_flatiron_write(dev, CH_PWR_CTRL1, val);
+
+	/* Wake up */
+	cx23885_flatiron_write(dev, CH_PWR_CTRL2, 0);
+
+	if (video_debug)
+		cx23885_flatiron_dump(dev);
+
+	return 0;
+}
+
+static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
+{
+	dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n",
+		__func__,
+		input, INPUT(input)->vmux,
+		INPUT(input)->gpio0, INPUT(input)->gpio1,
+		INPUT(input)->gpio2, INPUT(input)->gpio3);
+	dev->input = input;
+
+	if (dev->board == CX23885_BOARD_MYGICA_X8506 ||
+		dev->board == CX23885_BOARD_MAGICPRO_PROHDTVE2 ||
+		dev->board == CX23885_BOARD_MYGICA_X8507) {
+		/* Select Analog TV */
+		if (INPUT(input)->type == CX23885_VMUX_TELEVISION)
+			cx23885_gpio_clear(dev, GPIO_0);
+	}
+
+	/* Tell the internal A/V decoder */
+	v4l2_subdev_call(dev->sd_cx25840, video, s_routing,
+			INPUT(input)->vmux, 0, 0);
+
+	if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) ||
+		(dev->board == CX23885_BOARD_MPX885) ||
+		(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1250) ||
+		(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) ||
+		(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) ||
+		(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850)) {
+		/* Configure audio routing */
+		v4l2_subdev_call(dev->sd_cx25840, audio, s_routing,
+			INPUT(input)->amux, 0, 0);
+
+		if (INPUT(input)->amux == CX25840_AUDIO7)
+			cx23885_flatiron_mux(dev, 1);
+		else if (INPUT(input)->amux == CX25840_AUDIO6)
+			cx23885_flatiron_mux(dev, 2);
+	}
+
+	return 0;
+}
+
+static int cx23885_audio_mux(struct cx23885_dev *dev, unsigned int input)
+{
+	dprintk(1, "%s(input=%d)\n", __func__, input);
+
+	/* The baseband video core of the cx23885 has two audio inputs.
+	 * LR1 and LR2. In almost every single case so far only HVR1xxx
+	 * cards we've only ever supported LR1. Time to support LR2,
+	 * which is available via the optional white breakout header on
+	 * the board.
+	 * We'll use a could of existing enums in the card struct to allow
+	 * devs to specify which baseband input they need, or just default
+	 * to what we've always used.
+	 */
+	if (INPUT(input)->amux == CX25840_AUDIO7)
+		cx23885_flatiron_mux(dev, 1);
+	else if (INPUT(input)->amux == CX25840_AUDIO6)
+		cx23885_flatiron_mux(dev, 2);
+	else {
+		/* Not specifically defined, assume the default. */
+		cx23885_flatiron_mux(dev, 1);
+	}
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+static int cx23885_start_video_dma(struct cx23885_dev *dev,
+			   struct cx23885_dmaqueue *q,
+			   struct cx23885_buffer *buf)
+{
+	dprintk(1, "%s()\n", __func__);
+
+	/* Stop the dma/fifo before we tamper with it's risc programs */
+	cx_clear(VID_A_DMA_CTL, 0x11);
+
+	/* setup fifo + format */
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],
+				buf->bpl, buf->risc.dma);
+
+	/* reset counter */
+	cx_write(VID_A_GPCNT_CTL, 3);
+	q->count = 1;
+
+	/* enable irq */
+	cx23885_irq_add_enable(dev, 0x01);
+	cx_set(VID_A_INT_MSK, 0x000011);
+
+	/* start dma */
+	cx_set(DEV_CNTRL2, (1<<5));
+	cx_set(VID_A_DMA_CTL, 0x11); /* FIFO and RISC enable */
+
+	return 0;
+}
+
+
+static int cx23885_restart_video_queue(struct cx23885_dev *dev,
+			       struct cx23885_dmaqueue *q)
+{
+	struct cx23885_buffer *buf, *prev;
+	struct list_head *item;
+	dprintk(1, "%s()\n", __func__);
+
+	if (!list_empty(&q->active)) {
+		buf = list_entry(q->active.next, struct cx23885_buffer,
+			vb.queue);
+		dprintk(2, "restart_queue [%p/%d]: restart dma\n",
+			buf, buf->vb.i);
+		cx23885_start_video_dma(dev, q, buf);
+		list_for_each(item, &q->active) {
+			buf = list_entry(item, struct cx23885_buffer,
+				vb.queue);
+			buf->count    = q->count++;
+		}
+		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+		return 0;
+	}
+
+	prev = NULL;
+	for (;;) {
+		if (list_empty(&q->queued))
+			return 0;
+		buf = list_entry(q->queued.next, struct cx23885_buffer,
+			vb.queue);
+		if (NULL == prev) {
+			list_move_tail(&buf->vb.queue, &q->active);
+			cx23885_start_video_dma(dev, q, buf);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			buf->count    = q->count++;
+			mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+			dprintk(2, "[%p/%d] restart_queue - first active\n",
+				buf, buf->vb.i);
+
+		} else if (prev->vb.width  == buf->vb.width  &&
+			   prev->vb.height == buf->vb.height &&
+			   prev->fmt       == buf->fmt) {
+			list_move_tail(&buf->vb.queue, &q->active);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			buf->count    = q->count++;
+			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+			prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */
+			dprintk(2, "[%p/%d] restart_queue - move to active\n",
+				buf, buf->vb.i);
+		} else {
+			return 0;
+		}
+		prev = buf;
+	}
+}
+
+static int buffer_setup(struct videobuf_queue *q, unsigned int *count,
+	unsigned int *size)
+{
+	struct cx23885_fh *fh = q->priv_data;
+
+	*size = fh->fmt->depth*fh->width*fh->height >> 3;
+	if (0 == *count)
+		*count = 32;
+	if (*size * *count > vid_limit * 1024 * 1024)
+		*count = (vid_limit * 1024 * 1024) / *size;
+	return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+	       enum v4l2_field field)
+{
+	struct cx23885_fh *fh  = q->priv_data;
+	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_buffer *buf =
+		container_of(vb, struct cx23885_buffer, vb);
+	int rc, init_buffer = 0;
+	u32 line0_offset, line1_offset;
+	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+	int field_tff;
+
+	BUG_ON(NULL == fh->fmt);
+	if (fh->width  < 48 || fh->width  > norm_maxw(dev->tvnorm) ||
+	    fh->height < 32 || fh->height > norm_maxh(dev->tvnorm))
+		return -EINVAL;
+	buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+		return -EINVAL;
+
+	if (buf->fmt       != fh->fmt    ||
+	    buf->vb.width  != fh->width  ||
+	    buf->vb.height != fh->height ||
+	    buf->vb.field  != field) {
+		buf->fmt       = fh->fmt;
+		buf->vb.width  = fh->width;
+		buf->vb.height = fh->height;
+		buf->vb.field  = field;
+		init_buffer = 1;
+	}
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		init_buffer = 1;
+		rc = videobuf_iolock(q, &buf->vb, NULL);
+		if (0 != rc)
+			goto fail;
+	}
+
+	if (init_buffer) {
+		buf->bpl = buf->vb.width * buf->fmt->depth >> 3;
+		switch (buf->vb.field) {
+		case V4L2_FIELD_TOP:
+			cx23885_risc_buffer(dev->pci, &buf->risc,
+					 dma->sglist, 0, UNSET,
+					 buf->bpl, 0, buf->vb.height);
+			break;
+		case V4L2_FIELD_BOTTOM:
+			cx23885_risc_buffer(dev->pci, &buf->risc,
+					 dma->sglist, UNSET, 0,
+					 buf->bpl, 0, buf->vb.height);
+			break;
+		case V4L2_FIELD_INTERLACED:
+			if (dev->tvnorm & V4L2_STD_NTSC)
+				/* NTSC or  */
+				field_tff = 1;
+			else
+				field_tff = 0;
+
+			if (cx23885_boards[dev->board].force_bff)
+				/* PAL / SECAM OR 888 in NTSC MODE */
+				field_tff = 0;
+
+			if (field_tff) {
+				/* cx25840 transmits NTSC bottom field first */
+				dprintk(1, "%s() Creating TFF/NTSC risc\n",
+					__func__);
+				line0_offset = buf->bpl;
+				line1_offset = 0;
+			} else {
+				/* All other formats are top field first */
+				dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n",
+					__func__);
+				line0_offset = 0;
+				line1_offset = buf->bpl;
+			}
+			cx23885_risc_buffer(dev->pci, &buf->risc,
+					dma->sglist, line0_offset,
+					line1_offset,
+					buf->bpl, buf->bpl,
+					buf->vb.height >> 1);
+			break;
+		case V4L2_FIELD_SEQ_TB:
+			cx23885_risc_buffer(dev->pci, &buf->risc,
+					 dma->sglist,
+					 0, buf->bpl * (buf->vb.height >> 1),
+					 buf->bpl, 0,
+					 buf->vb.height >> 1);
+			break;
+		case V4L2_FIELD_SEQ_BT:
+			cx23885_risc_buffer(dev->pci, &buf->risc,
+					 dma->sglist,
+					 buf->bpl * (buf->vb.height >> 1), 0,
+					 buf->bpl, 0,
+					 buf->vb.height >> 1);
+			break;
+		default:
+			BUG();
+		}
+	}
+	dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
+		buf, buf->vb.i,
+		fh->width, fh->height, fh->fmt->depth, fh->fmt->name,
+		(unsigned long)buf->risc.dma);
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+ fail:
+	cx23885_free_buffer(q, buf);
+	return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct cx23885_buffer   *buf = container_of(vb,
+		struct cx23885_buffer, vb);
+	struct cx23885_buffer   *prev;
+	struct cx23885_fh       *fh   = vq->priv_data;
+	struct cx23885_dev      *dev  = fh->dev;
+	struct cx23885_dmaqueue *q    = &dev->vidq;
+
+	/* add jump to stopper */
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
+
+	if (!list_empty(&q->queued)) {
+		list_add_tail(&buf->vb.queue, &q->queued);
+		buf->vb.state = VIDEOBUF_QUEUED;
+		dprintk(2, "[%p/%d] buffer_queue - append to queued\n",
+			buf, buf->vb.i);
+
+	} else if (list_empty(&q->active)) {
+		list_add_tail(&buf->vb.queue, &q->active);
+		cx23885_start_video_dma(dev, q, buf);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		buf->count    = q->count++;
+		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+		dprintk(2, "[%p/%d] buffer_queue - first active\n",
+			buf, buf->vb.i);
+
+	} else {
+		prev = list_entry(q->active.prev, struct cx23885_buffer,
+			vb.queue);
+		if (prev->vb.width  == buf->vb.width  &&
+		    prev->vb.height == buf->vb.height &&
+		    prev->fmt       == buf->fmt) {
+			list_add_tail(&buf->vb.queue, &q->active);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			buf->count    = q->count++;
+			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+			/* 64 bit bits 63-32 */
+			prev->risc.jmp[2] = cpu_to_le32(0);
+			dprintk(2, "[%p/%d] buffer_queue - append to active\n",
+				buf, buf->vb.i);
+
+		} else {
+			list_add_tail(&buf->vb.queue, &q->queued);
+			buf->vb.state = VIDEOBUF_QUEUED;
+			dprintk(2, "[%p/%d] buffer_queue - first queued\n",
+				buf, buf->vb.i);
+		}
+	}
+}
+
+static void buffer_release(struct videobuf_queue *q,
+	struct videobuf_buffer *vb)
+{
+	struct cx23885_buffer *buf = container_of(vb,
+		struct cx23885_buffer, vb);
+
+	cx23885_free_buffer(q, buf);
+}
+
+static struct videobuf_queue_ops cx23885_video_qops = {
+	.buf_setup    = buffer_setup,
+	.buf_prepare  = buffer_prepare,
+	.buf_queue    = buffer_queue,
+	.buf_release  = buffer_release,
+};
+
+static struct videobuf_queue *get_queue(struct cx23885_fh *fh)
+{
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return &fh->vidq;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		return &fh->vbiq;
+	default:
+		BUG();
+		return NULL;
+	}
+}
+
+static int get_resource(struct cx23885_fh *fh)
+{
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return RESOURCE_VIDEO;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		return RESOURCE_VBI;
+	default:
+		BUG();
+		return 0;
+	}
+}
+
+static int video_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct cx23885_dev *dev = video_drvdata(file);
+	struct cx23885_fh *fh;
+	enum v4l2_buf_type type = 0;
+	int radio = 0;
+
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_GRABBER:
+		type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		break;
+	case VFL_TYPE_VBI:
+		type = V4L2_BUF_TYPE_VBI_CAPTURE;
+		break;
+	case VFL_TYPE_RADIO:
+		radio = 1;
+		break;
+	}
+
+	dprintk(1, "open dev=%s radio=%d type=%s\n",
+		video_device_node_name(vdev), radio, v4l2_type_names[type]);
+
+	/* allocate + initialize per filehandle data */
+	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+	if (NULL == fh)
+		return -ENOMEM;
+
+	file->private_data = fh;
+	fh->dev      = dev;
+	fh->radio    = radio;
+	fh->type     = type;
+	fh->width    = 320;
+	fh->height   = 240;
+	fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_YUYV);
+
+	videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops,
+			    &dev->pci->dev, &dev->slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			    V4L2_FIELD_INTERLACED,
+			    sizeof(struct cx23885_buffer),
+			    fh, NULL);
+
+	videobuf_queue_sg_init(&fh->vbiq, &cx23885_vbi_qops,
+		&dev->pci->dev, &dev->slock,
+		V4L2_BUF_TYPE_VBI_CAPTURE,
+		V4L2_FIELD_SEQ_TB,
+		sizeof(struct cx23885_buffer),
+		fh, NULL);
+
+
+	dprintk(1, "post videobuf_queue_init()\n");
+
+	return 0;
+}
+
+static ssize_t video_read(struct file *file, char __user *data,
+	size_t count, loff_t *ppos)
+{
+	struct cx23885_fh *fh = file->private_data;
+
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		if (res_locked(fh->dev, RESOURCE_VIDEO))
+			return -EBUSY;
+		return videobuf_read_one(&fh->vidq, data, count, ppos,
+					 file->f_flags & O_NONBLOCK);
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		if (!res_get(fh->dev, fh, RESOURCE_VBI))
+			return -EBUSY;
+		return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1,
+					    file->f_flags & O_NONBLOCK);
+	default:
+		BUG();
+		return 0;
+	}
+}
+
+static unsigned int video_poll(struct file *file,
+	struct poll_table_struct *wait)
+{
+	struct cx23885_fh *fh = file->private_data;
+	struct cx23885_buffer *buf;
+	unsigned int rc = POLLERR;
+
+	if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
+		if (!res_get(fh->dev, fh, RESOURCE_VBI))
+			return POLLERR;
+		return videobuf_poll_stream(file, &fh->vbiq, wait);
+	}
+
+	mutex_lock(&fh->vidq.vb_lock);
+	if (res_check(fh, RESOURCE_VIDEO)) {
+		/* streaming capture */
+		if (list_empty(&fh->vidq.stream))
+			goto done;
+		buf = list_entry(fh->vidq.stream.next,
+			struct cx23885_buffer, vb.stream);
+	} else {
+		/* read() capture */
+		buf = (struct cx23885_buffer *)fh->vidq.read_buf;
+		if (NULL == buf)
+			goto done;
+	}
+	poll_wait(file, &buf->vb.done, wait);
+	if (buf->vb.state == VIDEOBUF_DONE ||
+	    buf->vb.state == VIDEOBUF_ERROR)
+		rc =  POLLIN|POLLRDNORM;
+	else
+		rc = 0;
+done:
+	mutex_unlock(&fh->vidq.vb_lock);
+	return rc;
+}
+
+static int video_release(struct file *file)
+{
+	struct cx23885_fh *fh = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	/* turn off overlay */
+	if (res_check(fh, RESOURCE_OVERLAY)) {
+		/* FIXME */
+		res_free(dev, fh, RESOURCE_OVERLAY);
+	}
+
+	/* stop video capture */
+	if (res_check(fh, RESOURCE_VIDEO)) {
+		videobuf_queue_cancel(&fh->vidq);
+		res_free(dev, fh, RESOURCE_VIDEO);
+	}
+	if (fh->vidq.read_buf) {
+		buffer_release(&fh->vidq, fh->vidq.read_buf);
+		kfree(fh->vidq.read_buf);
+	}
+
+	/* stop vbi capture */
+	if (res_check(fh, RESOURCE_VBI)) {
+		if (fh->vbiq.streaming)
+			videobuf_streamoff(&fh->vbiq);
+		if (fh->vbiq.reading)
+			videobuf_read_stop(&fh->vbiq);
+		res_free(dev, fh, RESOURCE_VBI);
+	}
+
+	videobuf_mmap_free(&fh->vidq);
+	videobuf_mmap_free(&fh->vbiq);
+
+	file->private_data = NULL;
+	kfree(fh);
+
+	/* We are not putting the tuner to sleep here on exit, because
+	 * we want to use the mpeg encoder in another session to capture
+	 * tuner video. Closing this will result in no video to the encoder.
+	 */
+
+	return 0;
+}
+
+static int video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct cx23885_fh *fh = file->private_data;
+
+	return videobuf_mmap_mapper(get_queue(fh), vma);
+}
+
+/* ------------------------------------------------------------------ */
+/* VIDEO CTRL IOCTLS                                                  */
+
+int cx23885_get_control(struct cx23885_dev *dev,
+	struct v4l2_control *ctl)
+{
+	dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__);
+	call_all(dev, core, g_ctrl, ctl);
+	return 0;
+}
+
+int cx23885_set_control(struct cx23885_dev *dev,
+	struct v4l2_control *ctl)
+{
+	dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__);
+	call_all(dev, core, s_ctrl, ctl);
+
+	return 0;
+}
+
+static void init_controls(struct cx23885_dev *dev)
+{
+	struct v4l2_control ctrl;
+	int i;
+
+	for (i = 0; i < CX23885_CTLS; i++) {
+		ctrl.id = cx23885_ctls[i].v.id;
+		ctrl.value = cx23885_ctls[i].v.default_value;
+
+		cx23885_set_control(dev, &ctrl);
+	}
+}
+
+/* ------------------------------------------------------------------ */
+/* VIDEO IOCTLS                                                       */
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+	struct v4l2_format *f)
+{
+	struct cx23885_fh *fh   = priv;
+
+	f->fmt.pix.width        = fh->width;
+	f->fmt.pix.height       = fh->height;
+	f->fmt.pix.field        = fh->vidq.field;
+	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * fh->fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+	struct v4l2_format *f)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	struct cx23885_fmt *fmt;
+	enum v4l2_field   field;
+	unsigned int      maxw, maxh;
+
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	if (NULL == fmt)
+		return -EINVAL;
+
+	field = f->fmt.pix.field;
+	maxw  = norm_maxw(dev->tvnorm);
+	maxh  = norm_maxh(dev->tvnorm);
+
+	if (V4L2_FIELD_ANY == field) {
+		field = (f->fmt.pix.height > maxh/2)
+			? V4L2_FIELD_INTERLACED
+			: V4L2_FIELD_BOTTOM;
+	}
+
+	switch (field) {
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+		maxh = maxh / 2;
+		break;
+	case V4L2_FIELD_INTERLACED:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	f->fmt.pix.field = field;
+	v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
+			      &f->fmt.pix.height, 32, maxh, 0, 0);
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+	struct v4l2_format *f)
+{
+	struct cx23885_fh *fh = priv;
+	struct cx23885_dev *dev  = ((struct cx23885_fh *)priv)->dev;
+	struct v4l2_mbus_framefmt mbus_fmt;
+	int err;
+
+	dprintk(2, "%s()\n", __func__);
+	err = vidioc_try_fmt_vid_cap(file, priv, f);
+
+	if (0 != err)
+		return err;
+	fh->fmt        = format_by_fourcc(f->fmt.pix.pixelformat);
+	fh->width      = f->fmt.pix.width;
+	fh->height     = f->fmt.pix.height;
+	fh->vidq.field = f->fmt.pix.field;
+	dprintk(2, "%s() width=%d height=%d field=%d\n", __func__,
+		fh->width, fh->height, fh->vidq.field);
+	v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+	call_all(dev, video, s_mbus_fmt, &mbus_fmt);
+	v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
+	return 0;
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+	struct v4l2_capability *cap)
+{
+	struct cx23885_dev *dev  = ((struct cx23885_fh *)priv)->dev;
+
+	strcpy(cap->driver, "cx23885");
+	strlcpy(cap->card, cx23885_boards[dev->board].name,
+		sizeof(cap->card));
+	sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
+	cap->capabilities =
+		V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_READWRITE     |
+		V4L2_CAP_STREAMING     |
+		V4L2_CAP_VBI_CAPTURE;
+	if (UNSET != dev->tuner_type)
+		cap->capabilities |= V4L2_CAP_TUNER;
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+	struct v4l2_fmtdesc *f)
+{
+	if (unlikely(f->index >= ARRAY_SIZE(formats)))
+		return -EINVAL;
+
+	strlcpy(f->description, formats[f->index].name,
+		sizeof(f->description));
+	f->pixelformat = formats[f->index].fourcc;
+
+	return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+	struct v4l2_requestbuffers *p)
+{
+	struct cx23885_fh *fh = priv;
+	return videobuf_reqbufs(get_queue(fh), p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+	struct v4l2_buffer *p)
+{
+	struct cx23885_fh *fh = priv;
+	return videobuf_querybuf(get_queue(fh), p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv,
+	struct v4l2_buffer *p)
+{
+	struct cx23885_fh *fh = priv;
+	return videobuf_qbuf(get_queue(fh), p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv,
+	struct v4l2_buffer *p)
+{
+	struct cx23885_fh *fh = priv;
+	return videobuf_dqbuf(get_queue(fh), p,
+				file->f_flags & O_NONBLOCK);
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+	enum v4l2_buf_type i)
+{
+	struct cx23885_fh *fh = priv;
+	struct cx23885_dev *dev = fh->dev;
+	dprintk(1, "%s()\n", __func__);
+
+	if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+		(fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
+		return -EINVAL;
+	if (unlikely(i != fh->type))
+		return -EINVAL;
+
+	if (unlikely(!res_get(dev, fh, get_resource(fh))))
+		return -EBUSY;
+
+	/* Don't start VBI streaming unless vida streaming
+	 * has already started.
+	 */
+	if ((fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) &&
+		((cx_read(VID_A_DMA_CTL) & 0x11) == 0))
+		return -EINVAL;
+
+	return videobuf_streamon(get_queue(fh));
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct cx23885_fh *fh = priv;
+	struct cx23885_dev *dev = fh->dev;
+	int err, res;
+	dprintk(1, "%s()\n", __func__);
+
+	if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+		(fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
+		return -EINVAL;
+	if (i != fh->type)
+		return -EINVAL;
+
+	res = get_resource(fh);
+	err = videobuf_streamoff(get_queue(fh));
+	if (err < 0)
+		return err;
+	res_free(dev, fh, res);
+	return 0;
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	dprintk(1, "%s()\n", __func__);
+
+	call_all(dev, core, g_std, id);
+
+	return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	dprintk(1, "%s()\n", __func__);
+
+	mutex_lock(&dev->lock);
+	cx23885_set_tvnorm(dev, *tvnorms);
+	mutex_unlock(&dev->lock);
+
+	return 0;
+}
+
+int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
+{
+	static const char *iname[] = {
+		[CX23885_VMUX_COMPOSITE1] = "Composite1",
+		[CX23885_VMUX_COMPOSITE2] = "Composite2",
+		[CX23885_VMUX_COMPOSITE3] = "Composite3",
+		[CX23885_VMUX_COMPOSITE4] = "Composite4",
+		[CX23885_VMUX_SVIDEO]     = "S-Video",
+		[CX23885_VMUX_COMPONENT]  = "Component",
+		[CX23885_VMUX_TELEVISION] = "Television",
+		[CX23885_VMUX_CABLE]      = "Cable TV",
+		[CX23885_VMUX_DVB]        = "DVB",
+		[CX23885_VMUX_DEBUG]      = "for debug only",
+	};
+	unsigned int n;
+	dprintk(1, "%s()\n", __func__);
+
+	n = i->index;
+	if (n >= MAX_CX23885_INPUT)
+		return -EINVAL;
+
+	if (0 == INPUT(n)->type)
+		return -EINVAL;
+
+	i->index = n;
+	i->type  = V4L2_INPUT_TYPE_CAMERA;
+	strcpy(i->name, iname[INPUT(n)->type]);
+	if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) ||
+		(CX23885_VMUX_CABLE == INPUT(n)->type)) {
+		i->type = V4L2_INPUT_TYPE_TUNER;
+		i->std = CX23885_NORMS;
+	}
+
+	/* Two selectable audio inputs for non-tv inputs */
+	if (INPUT(n)->type != CX23885_VMUX_TELEVISION)
+		i->audioset = 0x3;
+
+	if (dev->input == n) {
+		/* enum'd input matches our configured input.
+		 * Ask the video decoder to process the call
+		 * and give it an oppertunity to update the
+		 * status field.
+		 */
+		call_all(dev, video, g_input_status, &i->status);
+	}
+
+	return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+				struct v4l2_input *i)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	dprintk(1, "%s()\n", __func__);
+	return cx23885_enum_input(dev, i);
+}
+
+int cx23885_get_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+	*i = dev->input;
+	dprintk(1, "%s() returns %d\n", __func__, *i);
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	return cx23885_get_input(file, priv, i);
+}
+
+int cx23885_set_input(struct file *file, void *priv, unsigned int i)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+	dprintk(1, "%s(%d)\n", __func__, i);
+
+	if (i >= MAX_CX23885_INPUT) {
+		dprintk(1, "%s() -EINVAL\n", __func__);
+		return -EINVAL;
+	}
+
+	if (INPUT(i)->type == 0)
+		return -EINVAL;
+
+	mutex_lock(&dev->lock);
+	cx23885_video_mux(dev, i);
+
+	/* By default establish the default audio input for the card also */
+	/* Caller is free to use VIDIOC_S_AUDIO to override afterwards */
+	cx23885_audio_mux(dev, i);
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	return cx23885_set_input(file, priv, i);
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+	struct cx23885_fh  *fh  = priv;
+	struct cx23885_dev *dev = fh->dev;
+
+	printk(KERN_INFO
+		"%s/0: ============  START LOG STATUS  ============\n",
+		dev->name);
+	call_all(dev, core, log_status);
+	printk(KERN_INFO
+		"%s/0: =============  END LOG STATUS  =============\n",
+		dev->name);
+	return 0;
+}
+
+static int cx23885_query_audinput(struct file *file, void *priv,
+	struct v4l2_audio *i)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	static const char *iname[] = {
+		[0] = "Baseband L/R 1",
+		[1] = "Baseband L/R 2",
+	};
+	unsigned int n;
+	dprintk(1, "%s()\n", __func__);
+
+	n = i->index;
+	if (n >= 2)
+		return -EINVAL;
+
+	memset(i, 0, sizeof(*i));
+	i->index = n;
+	strcpy(i->name, iname[n]);
+	i->capability  = V4L2_AUDCAP_STEREO;
+	i->mode  = V4L2_AUDMODE_AVL;
+	return 0;
+
+}
+
+static int vidioc_enum_audinput(struct file *file, void *priv,
+				struct v4l2_audio *i)
+{
+	return cx23885_query_audinput(file, priv, i);
+}
+
+static int vidioc_g_audinput(struct file *file, void *priv,
+	struct v4l2_audio *i)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+	i->index = dev->audinput;
+	dprintk(1, "%s(input=%d)\n", __func__, i->index);
+
+	return cx23885_query_audinput(file, priv, i);
+}
+
+static int vidioc_s_audinput(struct file *file, void *priv,
+	struct v4l2_audio *i)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	if (i->index >= 2)
+		return -EINVAL;
+
+	dprintk(1, "%s(%d)\n", __func__, i->index);
+
+	dev->audinput = i->index;
+
+	/* Skip the audio defaults from the cards struct, caller wants
+	 * directly touch the audio mux hardware. */
+	cx23885_flatiron_mux(dev, dev->audinput + 1);
+	return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+				struct v4l2_queryctrl *qctrl)
+{
+	qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+	if (unlikely(qctrl->id == 0))
+		return -EINVAL;
+	return cx23885_ctrl_query(qctrl);
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctl)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+	return cx23885_get_control(dev, ctl);
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctl)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+	return cx23885_set_control(dev, ctl);
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+	if (unlikely(UNSET == dev->tuner_type))
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+
+	strcpy(t->name, "Television");
+
+	call_all(dev, tuner, g_tuner, t);
+	return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+	if (UNSET == dev->tuner_type)
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+	/* Update the A/V core */
+	call_all(dev, tuner, s_tuner, t);
+
+	return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct cx23885_fh *fh = priv;
+	struct cx23885_dev *dev = fh->dev;
+
+	if (unlikely(UNSET == dev->tuner_type))
+		return -EINVAL;
+
+	/* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
+	f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+	f->frequency = dev->freq;
+
+	call_all(dev, tuner, g_frequency, f);
+
+	return 0;
+}
+
+static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
+{
+	struct v4l2_control ctrl;
+
+	if (unlikely(UNSET == dev->tuner_type))
+		return -EINVAL;
+	if (unlikely(f->tuner != 0))
+		return -EINVAL;
+
+	mutex_lock(&dev->lock);
+	dev->freq = f->frequency;
+
+	/* I need to mute audio here */
+	ctrl.id = V4L2_CID_AUDIO_MUTE;
+	ctrl.value = 1;
+	cx23885_set_control(dev, &ctrl);
+
+	call_all(dev, tuner, s_frequency, f);
+
+	/* When changing channels it is required to reset TVAUDIO */
+	msleep(100);
+
+	/* I need to unmute audio here */
+	ctrl.value = 0;
+	cx23885_set_control(dev, &ctrl);
+
+	mutex_unlock(&dev->lock);
+
+	return 0;
+}
+
+static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
+	struct v4l2_frequency *f)
+{
+	struct v4l2_control ctrl;
+	struct videobuf_dvb_frontend *vfe;
+	struct dvb_frontend *fe;
+
+	struct analog_parameters params = {
+		.mode      = V4L2_TUNER_ANALOG_TV,
+		.audmode   = V4L2_TUNER_MODE_STEREO,
+		.std       = dev->tvnorm,
+		.frequency = f->frequency
+	};
+
+	mutex_lock(&dev->lock);
+	dev->freq = f->frequency;
+
+	/* I need to mute audio here */
+	ctrl.id = V4L2_CID_AUDIO_MUTE;
+	ctrl.value = 1;
+	cx23885_set_control(dev, &ctrl);
+
+	/* If HVR1850 */
+	dprintk(1, "%s() frequency=%d tuner=%d std=0x%llx\n", __func__,
+		params.frequency, f->tuner, params.std);
+
+	vfe = videobuf_dvb_get_frontend(&dev->ts2.frontends, 1);
+	if (!vfe) {
+		mutex_unlock(&dev->lock);
+		return -EINVAL;
+	}
+
+	fe = vfe->dvb.frontend;
+
+	if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) ||
+	    (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) ||
+	    (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111))
+		fe = &dev->ts1.analog_fe;
+
+	if (fe && fe->ops.tuner_ops.set_analog_params) {
+		call_all(dev, core, s_std, dev->tvnorm);
+		fe->ops.tuner_ops.set_analog_params(fe, &params);
+	}
+	else
+		printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__);
+
+	/* When changing channels it is required to reset TVAUDIO */
+	msleep(100);
+
+	/* I need to unmute audio here */
+	ctrl.value = 0;
+	cx23885_set_control(dev, &ctrl);
+
+	mutex_unlock(&dev->lock);
+
+	return 0;
+}
+
+int cx23885_set_frequency(struct file *file, void *priv,
+	struct v4l2_frequency *f)
+{
+	struct cx23885_fh *fh = priv;
+	struct cx23885_dev *dev = fh->dev;
+	int ret;
+
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1255:
+	case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+		ret = cx23885_set_freq_via_ops(dev, f);
+		break;
+	default:
+		ret = cx23885_set_freq(dev, f);
+	}
+
+	return ret;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+	struct v4l2_frequency *f)
+{
+	return cx23885_set_frequency(file, priv, f);
+}
+
+/* ----------------------------------------------------------- */
+
+static void cx23885_vid_timeout(unsigned long data)
+{
+	struct cx23885_dev *dev = (struct cx23885_dev *)data;
+	struct cx23885_dmaqueue *q = &dev->vidq;
+	struct cx23885_buffer *buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->slock, flags);
+	while (!list_empty(&q->active)) {
+		buf = list_entry(q->active.next,
+			struct cx23885_buffer, vb.queue);
+		list_del(&buf->vb.queue);
+		buf->vb.state = VIDEOBUF_ERROR;
+		wake_up(&buf->vb.done);
+		printk(KERN_ERR "%s: [%p/%d] timeout - dma=0x%08lx\n",
+			dev->name, buf, buf->vb.i,
+			(unsigned long)buf->risc.dma);
+	}
+	cx23885_restart_video_queue(dev, q);
+	spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
+{
+	u32 mask, count;
+	int handled = 0;
+
+	mask   = cx_read(VID_A_INT_MSK);
+	if (0 == (status & mask))
+		return handled;
+
+	cx_write(VID_A_INT_STAT, status);
+
+	/* risc op code error, fifo overflow or line sync detection error */
+	if ((status & VID_BC_MSK_OPC_ERR) ||
+		(status & VID_BC_MSK_SYNC) ||
+		(status & VID_BC_MSK_OF)) {
+
+		if (status & VID_BC_MSK_OPC_ERR) {
+			dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n",
+				VID_BC_MSK_OPC_ERR);
+			printk(KERN_WARNING "%s: video risc op code error\n",
+				dev->name);
+			cx23885_sram_channel_dump(dev,
+				&dev->sram_channels[SRAM_CH01]);
+		}
+
+		if (status & VID_BC_MSK_SYNC)
+			dprintk(7, " (VID_BC_MSK_SYNC 0x%08x) "
+				"video lines miss-match\n",
+				VID_BC_MSK_SYNC);
+
+		if (status & VID_BC_MSK_OF)
+			dprintk(7, " (VID_BC_MSK_OF 0x%08x) fifo overflow\n",
+				VID_BC_MSK_OF);
+
+	}
+
+	/* Video */
+	if (status & VID_BC_MSK_RISCI1) {
+		spin_lock(&dev->slock);
+		count = cx_read(VID_A_GPCNT);
+		cx23885_video_wakeup(dev, &dev->vidq, count);
+		spin_unlock(&dev->slock);
+		handled++;
+	}
+	if (status & VID_BC_MSK_RISCI2) {
+		dprintk(2, "stopper video\n");
+		spin_lock(&dev->slock);
+		cx23885_restart_video_queue(dev, &dev->vidq);
+		spin_unlock(&dev->slock);
+		handled++;
+	}
+
+	/* Allow the VBI framework to process it's payload */
+	handled += cx23885_vbi_irq(dev, status);
+
+	return handled;
+}
+
+/* ----------------------------------------------------------- */
+/* exported stuff                                              */
+
+static const struct v4l2_file_operations video_fops = {
+	.owner	       = THIS_MODULE,
+	.open	       = video_open,
+	.release       = video_release,
+	.read	       = video_read,
+	.poll          = video_poll,
+	.mmap	       = video_mmap,
+	.ioctl	       = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+	.vidioc_querycap      = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
+	.vidioc_g_fmt_vbi_cap     = cx23885_vbi_fmt,
+	.vidioc_try_fmt_vbi_cap   = cx23885_vbi_fmt,
+	.vidioc_s_fmt_vbi_cap     = cx23885_vbi_fmt,
+	.vidioc_reqbufs       = vidioc_reqbufs,
+	.vidioc_querybuf      = vidioc_querybuf,
+	.vidioc_qbuf          = vidioc_qbuf,
+	.vidioc_dqbuf         = vidioc_dqbuf,
+	.vidioc_s_std         = vidioc_s_std,
+	.vidioc_g_std         = vidioc_g_std,
+	.vidioc_querystd      = vidioc_g_std,
+	.vidioc_enum_input    = vidioc_enum_input,
+	.vidioc_g_input       = vidioc_g_input,
+	.vidioc_s_input       = vidioc_s_input,
+	.vidioc_log_status    = vidioc_log_status,
+	.vidioc_queryctrl     = vidioc_queryctrl,
+	.vidioc_g_ctrl        = vidioc_g_ctrl,
+	.vidioc_s_ctrl        = vidioc_s_ctrl,
+	.vidioc_streamon      = vidioc_streamon,
+	.vidioc_streamoff     = vidioc_streamoff,
+	.vidioc_g_tuner       = vidioc_g_tuner,
+	.vidioc_s_tuner       = vidioc_s_tuner,
+	.vidioc_g_frequency   = vidioc_g_frequency,
+	.vidioc_s_frequency   = vidioc_s_frequency,
+	.vidioc_g_chip_ident  = cx23885_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register    = cx23885_g_register,
+	.vidioc_s_register    = cx23885_s_register,
+#endif
+	.vidioc_enumaudio     = vidioc_enum_audinput,
+	.vidioc_g_audio       = vidioc_g_audinput,
+	.vidioc_s_audio       = vidioc_s_audinput,
+};
+
+static struct video_device cx23885_vbi_template;
+static struct video_device cx23885_video_template = {
+	.name                 = "cx23885-video",
+	.fops                 = &video_fops,
+	.ioctl_ops 	      = &video_ioctl_ops,
+	.tvnorms              = CX23885_NORMS,
+	.current_norm         = V4L2_STD_NTSC_M,
+};
+
+static const struct v4l2_file_operations radio_fops = {
+	.owner         = THIS_MODULE,
+	.open          = video_open,
+	.release       = video_release,
+	.ioctl         = video_ioctl2,
+};
+
+
+void cx23885_video_unregister(struct cx23885_dev *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+	cx23885_irq_remove(dev, 0x01);
+
+	if (dev->vbi_dev) {
+		if (video_is_registered(dev->vbi_dev))
+			video_unregister_device(dev->vbi_dev);
+		else
+			video_device_release(dev->vbi_dev);
+		dev->vbi_dev = NULL;
+		btcx_riscmem_free(dev->pci, &dev->vbiq.stopper);
+	}
+	if (dev->video_dev) {
+		if (video_is_registered(dev->video_dev))
+			video_unregister_device(dev->video_dev);
+		else
+			video_device_release(dev->video_dev);
+		dev->video_dev = NULL;
+
+		btcx_riscmem_free(dev->pci, &dev->vidq.stopper);
+	}
+
+	if (dev->audio_dev)
+		cx23885_audio_unregister(dev);
+}
+
+int cx23885_video_register(struct cx23885_dev *dev)
+{
+	int err;
+
+	dprintk(1, "%s()\n", __func__);
+	spin_lock_init(&dev->slock);
+
+	/* Initialize VBI template */
+	memcpy(&cx23885_vbi_template, &cx23885_video_template,
+		sizeof(cx23885_vbi_template));
+	strcpy(cx23885_vbi_template.name, "cx23885-vbi");
+
+	dev->tvnorm = cx23885_video_template.current_norm;
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&dev->vidq.active);
+	INIT_LIST_HEAD(&dev->vidq.queued);
+	dev->vidq.timeout.function = cx23885_vid_timeout;
+	dev->vidq.timeout.data = (unsigned long)dev;
+	init_timer(&dev->vidq.timeout);
+	cx23885_risc_stopper(dev->pci, &dev->vidq.stopper,
+		VID_A_DMA_CTL, 0x11, 0x00);
+
+	/* init vbi dma queues */
+	INIT_LIST_HEAD(&dev->vbiq.active);
+	INIT_LIST_HEAD(&dev->vbiq.queued);
+	dev->vbiq.timeout.function = cx23885_vbi_timeout;
+	dev->vbiq.timeout.data = (unsigned long)dev;
+	init_timer(&dev->vbiq.timeout);
+	cx23885_risc_stopper(dev->pci, &dev->vbiq.stopper,
+		VID_A_DMA_CTL, 0x22, 0x00);
+
+	cx23885_irq_add_enable(dev, 0x01);
+
+	if ((TUNER_ABSENT != dev->tuner_type) &&
+			((dev->tuner_bus == 0) || (dev->tuner_bus == 1))) {
+		struct v4l2_subdev *sd = NULL;
+
+		if (dev->tuner_addr)
+			sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+				&dev->i2c_bus[dev->tuner_bus].i2c_adap,
+				"tuner", dev->tuner_addr, NULL);
+		else
+			sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+				&dev->i2c_bus[dev->tuner_bus].i2c_adap,
+				"tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV));
+		if (sd) {
+			struct tuner_setup tun_setup;
+
+			memset(&tun_setup, 0, sizeof(tun_setup));
+			tun_setup.mode_mask = T_ANALOG_TV;
+			tun_setup.type = dev->tuner_type;
+			tun_setup.addr = v4l2_i2c_subdev_addr(sd);
+			tun_setup.tuner_callback = cx23885_tuner_callback;
+
+			v4l2_subdev_call(sd, tuner, s_type_addr, &tun_setup);
+
+			if (dev->board == CX23885_BOARD_LEADTEK_WINFAST_PXTV1200) {
+				struct xc2028_ctrl ctrl = {
+					.fname = XC2028_DEFAULT_FIRMWARE,
+					.max_len = 64
+				};
+				struct v4l2_priv_tun_config cfg = {
+					.tuner = dev->tuner_type,
+					.priv = &ctrl
+				};
+				v4l2_subdev_call(sd, tuner, s_config, &cfg);
+			}
+		}
+	}
+
+	/* register Video device */
+	dev->video_dev = cx23885_vdev_init(dev, dev->pci,
+		&cx23885_video_template, "video");
+	err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER,
+				    video_nr[dev->nr]);
+	if (err < 0) {
+		printk(KERN_INFO "%s: can't register video device\n",
+			dev->name);
+		goto fail_unreg;
+	}
+	printk(KERN_INFO "%s: registered device %s [v4l2]\n",
+	       dev->name, video_device_node_name(dev->video_dev));
+
+	/* register VBI device */
+	dev->vbi_dev = cx23885_vdev_init(dev, dev->pci,
+		&cx23885_vbi_template, "vbi");
+	err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+				    vbi_nr[dev->nr]);
+	if (err < 0) {
+		printk(KERN_INFO "%s: can't register vbi device\n",
+			dev->name);
+		goto fail_unreg;
+	}
+	printk(KERN_INFO "%s: registered device %s\n",
+	       dev->name, video_device_node_name(dev->vbi_dev));
+
+	/* Register ALSA audio device */
+	dev->audio_dev = cx23885_audio_register(dev);
+
+	/* initial device configuration */
+	mutex_lock(&dev->lock);
+	cx23885_set_tvnorm(dev, dev->tvnorm);
+	init_controls(dev);
+	cx23885_video_mux(dev, 0);
+	cx23885_audio_mux(dev, 0);
+	mutex_unlock(&dev->lock);
+
+	return 0;
+
+fail_unreg:
+	cx23885_video_unregister(dev);
+	return err;
+}
+
diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h
new file mode 100644
index 0000000..5d560c7
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885.h
@@ -0,0 +1,653 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/kdev_t.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-device.h>
+#include <media/tuner.h>
+#include <media/tveeprom.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/videobuf-dvb.h>
+#include <media/rc-core.h>
+
+#include "btcx-risc.h"
+#include "cx23885-reg.h"
+#include "media/cx2341x.h"
+
+#include <linux/mutex.h>
+
+#define CX23885_VERSION "0.0.3"
+
+#define UNSET (-1U)
+
+#define CX23885_MAXBOARDS 8
+
+/* Max number of inputs by card */
+#define MAX_CX23885_INPUT 8
+#define INPUT(nr) (&cx23885_boards[dev->board].input[nr])
+#define RESOURCE_OVERLAY       1
+#define RESOURCE_VIDEO         2
+#define RESOURCE_VBI           4
+
+#define BUFFER_TIMEOUT     (HZ)  /* 0.5 seconds */
+
+#define CX23885_BOARD_NOAUTO               UNSET
+#define CX23885_BOARD_UNKNOWN                  0
+#define CX23885_BOARD_HAUPPAUGE_HVR1800lp      1
+#define CX23885_BOARD_HAUPPAUGE_HVR1800        2
+#define CX23885_BOARD_HAUPPAUGE_HVR1250        3
+#define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP   4
+#define CX23885_BOARD_HAUPPAUGE_HVR1500Q       5
+#define CX23885_BOARD_HAUPPAUGE_HVR1500        6
+#define CX23885_BOARD_HAUPPAUGE_HVR1200        7
+#define CX23885_BOARD_HAUPPAUGE_HVR1700        8
+#define CX23885_BOARD_HAUPPAUGE_HVR1400        9
+#define CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP 10
+#define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP 11
+#define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H 12
+#define CX23885_BOARD_COMPRO_VIDEOMATE_E650F   13
+#define CX23885_BOARD_TBS_6920                 14
+#define CX23885_BOARD_TEVII_S470               15
+#define CX23885_BOARD_DVBWORLD_2005            16
+#define CX23885_BOARD_NETUP_DUAL_DVBS2_CI      17
+#define CX23885_BOARD_HAUPPAUGE_HVR1270        18
+#define CX23885_BOARD_HAUPPAUGE_HVR1275        19
+#define CX23885_BOARD_HAUPPAUGE_HVR1255        20
+#define CX23885_BOARD_HAUPPAUGE_HVR1210        21
+#define CX23885_BOARD_MYGICA_X8506             22
+#define CX23885_BOARD_MAGICPRO_PROHDTVE2       23
+#define CX23885_BOARD_HAUPPAUGE_HVR1850        24
+#define CX23885_BOARD_COMPRO_VIDEOMATE_E800    25
+#define CX23885_BOARD_HAUPPAUGE_HVR1290        26
+#define CX23885_BOARD_MYGICA_X8558PRO          27
+#define CX23885_BOARD_LEADTEK_WINFAST_PXTV1200 28
+#define CX23885_BOARD_GOTVIEW_X5_3D_HYBRID     29
+#define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30
+#define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000 31
+#define CX23885_BOARD_MPX885                   32
+#define CX23885_BOARD_MYGICA_X8507             33
+#define CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL 34
+#define CX23885_BOARD_TEVII_S471               35
+#define CX23885_BOARD_HAUPPAUGE_HVR1255_22111  36
+
+#define GPIO_0 0x00000001
+#define GPIO_1 0x00000002
+#define GPIO_2 0x00000004
+#define GPIO_3 0x00000008
+#define GPIO_4 0x00000010
+#define GPIO_5 0x00000020
+#define GPIO_6 0x00000040
+#define GPIO_7 0x00000080
+#define GPIO_8 0x00000100
+#define GPIO_9 0x00000200
+#define GPIO_10 0x00000400
+#define GPIO_11 0x00000800
+#define GPIO_12 0x00001000
+#define GPIO_13 0x00002000
+#define GPIO_14 0x00004000
+#define GPIO_15 0x00008000
+
+/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
+#define CX23885_NORMS (\
+	V4L2_STD_NTSC_M |  V4L2_STD_NTSC_M_JP |  V4L2_STD_NTSC_443 | \
+	V4L2_STD_PAL_BG |  V4L2_STD_PAL_DK    |  V4L2_STD_PAL_I    | \
+	V4L2_STD_PAL_M  |  V4L2_STD_PAL_N     |  V4L2_STD_PAL_Nc   | \
+	V4L2_STD_PAL_60 |  V4L2_STD_SECAM_L   |  V4L2_STD_SECAM_DK)
+
+struct cx23885_fmt {
+	char  *name;
+	u32   fourcc;          /* v4l2 format id */
+	int   depth;
+	int   flags;
+	u32   cxformat;
+};
+
+struct cx23885_ctrl {
+	struct v4l2_queryctrl v;
+	u32                   off;
+	u32                   reg;
+	u32                   mask;
+	u32                   shift;
+};
+
+struct cx23885_tvnorm {
+	char		*name;
+	v4l2_std_id	id;
+	u32		cxiformat;
+	u32		cxoformat;
+};
+
+struct cx23885_fh {
+	struct cx23885_dev         *dev;
+	enum v4l2_buf_type         type;
+	int                        radio;
+	u32                        resources;
+
+	/* video overlay */
+	struct v4l2_window         win;
+	struct v4l2_clip           *clips;
+	unsigned int               nclips;
+
+	/* video capture */
+	struct cx23885_fmt         *fmt;
+	unsigned int               width, height;
+
+	/* vbi capture */
+	struct videobuf_queue      vidq;
+	struct videobuf_queue      vbiq;
+
+	/* MPEG Encoder specifics ONLY */
+	struct videobuf_queue      mpegq;
+	atomic_t                   v4l_reading;
+};
+
+enum cx23885_itype {
+	CX23885_VMUX_COMPOSITE1 = 1,
+	CX23885_VMUX_COMPOSITE2,
+	CX23885_VMUX_COMPOSITE3,
+	CX23885_VMUX_COMPOSITE4,
+	CX23885_VMUX_SVIDEO,
+	CX23885_VMUX_COMPONENT,
+	CX23885_VMUX_TELEVISION,
+	CX23885_VMUX_CABLE,
+	CX23885_VMUX_DVB,
+	CX23885_VMUX_DEBUG,
+	CX23885_RADIO,
+};
+
+enum cx23885_src_sel_type {
+	CX23885_SRC_SEL_EXT_656_VIDEO = 0,
+	CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO
+};
+
+/* buffer for one video frame */
+struct cx23885_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+
+	/* cx23885 specific */
+	unsigned int           bpl;
+	struct btcx_riscmem    risc;
+	struct cx23885_fmt     *fmt;
+	u32                    count;
+};
+
+struct cx23885_input {
+	enum cx23885_itype type;
+	unsigned int    vmux;
+	unsigned int    amux;
+	u32             gpio0, gpio1, gpio2, gpio3;
+};
+
+typedef enum {
+	CX23885_MPEG_UNDEFINED = 0,
+	CX23885_MPEG_DVB,
+	CX23885_ANALOG_VIDEO,
+	CX23885_MPEG_ENCODER,
+} port_t;
+
+struct cx23885_board {
+	char                    *name;
+	port_t			porta, portb, portc;
+	int		num_fds_portb, num_fds_portc;
+	unsigned int		tuner_type;
+	unsigned int		radio_type;
+	unsigned char		tuner_addr;
+	unsigned char		radio_addr;
+	unsigned int		tuner_bus;
+
+	/* Vendors can and do run the PCIe bridge at different
+	 * clock rates, driven physically by crystals on the PCBs.
+	 * The core has to accommodate this. This allows the user
+	 * to add new boards with new frequencys. The value is
+	 * expressed in Hz.
+	 *
+	 * The core framework will default this value based on
+	 * current designs, but it can vary.
+	 */
+	u32			clk_freq;
+	struct cx23885_input    input[MAX_CX23885_INPUT];
+	int			ci_type; /* for NetUP */
+	/* Force bottom field first during DMA (888 workaround) */
+	u32                     force_bff;
+};
+
+struct cx23885_subid {
+	u16     subvendor;
+	u16     subdevice;
+	u32     card;
+};
+
+struct cx23885_i2c {
+	struct cx23885_dev *dev;
+
+	int                        nr;
+
+	/* i2c i/o */
+	struct i2c_adapter         i2c_adap;
+	struct i2c_client          i2c_client;
+	u32                        i2c_rc;
+
+	/* 885 registers used for raw addess */
+	u32                        i2c_period;
+	u32                        reg_ctrl;
+	u32                        reg_stat;
+	u32                        reg_addr;
+	u32                        reg_rdata;
+	u32                        reg_wdata;
+};
+
+struct cx23885_dmaqueue {
+	struct list_head       active;
+	struct list_head       queued;
+	struct timer_list      timeout;
+	struct btcx_riscmem    stopper;
+	u32                    count;
+};
+
+struct cx23885_tsport {
+	struct cx23885_dev *dev;
+
+	int                        nr;
+	int                        sram_chno;
+
+	struct videobuf_dvb_frontends frontends;
+
+	/* dma queues */
+	struct cx23885_dmaqueue    mpegq;
+	u32                        ts_packet_size;
+	u32                        ts_packet_count;
+
+	int                        width;
+	int                        height;
+
+	spinlock_t                 slock;
+
+	/* registers */
+	u32                        reg_gpcnt;
+	u32                        reg_gpcnt_ctl;
+	u32                        reg_dma_ctl;
+	u32                        reg_lngth;
+	u32                        reg_hw_sop_ctrl;
+	u32                        reg_gen_ctrl;
+	u32                        reg_bd_pkt_status;
+	u32                        reg_sop_status;
+	u32                        reg_fifo_ovfl_stat;
+	u32                        reg_vld_misc;
+	u32                        reg_ts_clk_en;
+	u32                        reg_ts_int_msk;
+	u32                        reg_ts_int_stat;
+	u32                        reg_src_sel;
+
+	/* Default register vals */
+	int                        pci_irqmask;
+	u32                        dma_ctl_val;
+	u32                        ts_int_msk_val;
+	u32                        gen_ctrl_val;
+	u32                        ts_clk_en_val;
+	u32                        src_sel_val;
+	u32                        vld_misc_val;
+	u32                        hw_sop_ctrl_val;
+
+	/* Allow a single tsport to have multiple frontends */
+	u32                        num_frontends;
+	void                (*gate_ctrl)(struct cx23885_tsport *port, int open);
+	void                       *port_priv;
+
+	/* Workaround for a temp dvb_frontend that the tuner can attached to */
+	struct dvb_frontend analog_fe;
+};
+
+struct cx23885_kernel_ir {
+	struct cx23885_dev	*cx;
+	char			*name;
+	char			*phys;
+
+	struct rc_dev		*rc;
+};
+
+struct cx23885_audio_buffer {
+	unsigned int		bpl;
+	struct btcx_riscmem	risc;
+	struct videobuf_dmabuf	dma;
+};
+
+struct cx23885_audio_dev {
+	struct cx23885_dev	*dev;
+
+	struct pci_dev		*pci;
+
+	struct snd_card		*card;
+
+	spinlock_t		lock;
+
+	atomic_t		count;
+
+	unsigned int		dma_size;
+	unsigned int		period_size;
+	unsigned int		num_periods;
+
+	struct videobuf_dmabuf	*dma_risc;
+
+	struct cx23885_audio_buffer   *buf;
+
+	struct snd_pcm_substream *substream;
+};
+
+struct cx23885_dev {
+	atomic_t                   refcount;
+	struct v4l2_device 	   v4l2_dev;
+
+	/* pci stuff */
+	struct pci_dev             *pci;
+	unsigned char              pci_rev, pci_lat;
+	int                        pci_bus, pci_slot;
+	u32                        __iomem *lmmio;
+	u8                         __iomem *bmmio;
+	int                        pci_irqmask;
+	spinlock_t		   pci_irqmask_lock; /* protects mask reg too */
+	int                        hwrevision;
+
+	/* This valud is board specific and is used to configure the
+	 * AV core so we see nice clean and stable video and audio. */
+	u32                        clk_freq;
+
+	/* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
+	struct cx23885_i2c         i2c_bus[3];
+
+	int                        nr;
+	struct mutex               lock;
+	struct mutex               gpio_lock;
+
+	/* board details */
+	unsigned int               board;
+	char                       name[32];
+
+	struct cx23885_tsport      ts1, ts2;
+
+	/* sram configuration */
+	struct sram_channel        *sram_channels;
+
+	enum {
+		CX23885_BRIDGE_UNDEFINED = 0,
+		CX23885_BRIDGE_885 = 885,
+		CX23885_BRIDGE_887 = 887,
+		CX23885_BRIDGE_888 = 888,
+	} bridge;
+
+	/* Analog video */
+	u32                        resources;
+	unsigned int               input;
+	unsigned int               audinput; /* Selectable audio input */
+	u32                        tvaudio;
+	v4l2_std_id                tvnorm;
+	unsigned int               tuner_type;
+	unsigned char              tuner_addr;
+	unsigned int               tuner_bus;
+	unsigned int               radio_type;
+	unsigned char              radio_addr;
+	unsigned int               has_radio;
+	struct v4l2_subdev 	   *sd_cx25840;
+	struct work_struct	   cx25840_work;
+
+	/* Infrared */
+	struct v4l2_subdev         *sd_ir;
+	struct work_struct	   ir_rx_work;
+	unsigned long		   ir_rx_notifications;
+	struct work_struct	   ir_tx_work;
+	unsigned long		   ir_tx_notifications;
+
+	struct cx23885_kernel_ir   *kernel_ir;
+	atomic_t		   ir_input_stopping;
+
+	/* V4l */
+	u32                        freq;
+	struct video_device        *video_dev;
+	struct video_device        *vbi_dev;
+	struct video_device        *radio_dev;
+
+	struct cx23885_dmaqueue    vidq;
+	struct cx23885_dmaqueue    vbiq;
+	spinlock_t                 slock;
+
+	/* MPEG Encoder ONLY settings */
+	u32                        cx23417_mailbox;
+	struct cx2341x_mpeg_params mpeg_params;
+	struct video_device        *v4l_device;
+	atomic_t                   v4l_reader_count;
+	struct cx23885_tvnorm      encodernorm;
+
+	/* Analog raw audio */
+	struct cx23885_audio_dev   *audio_dev;
+
+};
+
+static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev)
+{
+	return container_of(v4l2_dev, struct cx23885_dev, v4l2_dev);
+}
+
+#define call_all(dev, o, f, args...) \
+	v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args)
+
+#define CX23885_HW_888_IR  (1 << 0)
+#define CX23885_HW_AV_CORE (1 << 1)
+
+#define call_hw(dev, grpid, o, f, args...) \
+	v4l2_device_call_all(&dev->v4l2_dev, grpid, o, f, ##args)
+
+extern struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw);
+
+#define SRAM_CH01  0 /* Video A */
+#define SRAM_CH02  1 /* VBI A */
+#define SRAM_CH03  2 /* Video B */
+#define SRAM_CH04  3 /* Transport via B */
+#define SRAM_CH05  4 /* VBI B */
+#define SRAM_CH06  5 /* Video C */
+#define SRAM_CH07  6 /* Transport via C */
+#define SRAM_CH08  7 /* Audio Internal A */
+#define SRAM_CH09  8 /* Audio Internal B */
+#define SRAM_CH10  9 /* Audio External */
+#define SRAM_CH11 10 /* COMB_3D_N */
+#define SRAM_CH12 11 /* Comb 3D N1 */
+#define SRAM_CH13 12 /* Comb 3D N2 */
+#define SRAM_CH14 13 /* MOE Vid */
+#define SRAM_CH15 14 /* MOE RSLT */
+
+struct sram_channel {
+	char *name;
+	u32  cmds_start;
+	u32  ctrl_start;
+	u32  cdt;
+	u32  fifo_start;
+	u32  fifo_size;
+	u32  ptr1_reg;
+	u32  ptr2_reg;
+	u32  cnt1_reg;
+	u32  cnt2_reg;
+	u32  jumponly;
+};
+
+/* ----------------------------------------------------------- */
+
+#define cx_read(reg)             readl(dev->lmmio + ((reg)>>2))
+#define cx_write(reg, value)     writel((value), dev->lmmio + ((reg)>>2))
+
+#define cx_andor(reg, mask, value) \
+  writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\
+  ((value) & (mask)), dev->lmmio+((reg)>>2))
+
+#define cx_set(reg, bit)          cx_andor((reg), (bit), (bit))
+#define cx_clear(reg, bit)        cx_andor((reg), (bit), 0)
+
+/* ----------------------------------------------------------- */
+/* cx23885-core.c                                              */
+
+extern int cx23885_sram_channel_setup(struct cx23885_dev *dev,
+	struct sram_channel *ch,
+	unsigned int bpl, u32 risc);
+
+extern void cx23885_sram_channel_dump(struct cx23885_dev *dev,
+	struct sram_channel *ch);
+
+extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+	u32 reg, u32 mask, u32 value);
+
+extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+	struct scatterlist *sglist,
+	unsigned int top_offset, unsigned int bottom_offset,
+	unsigned int bpl, unsigned int padding, unsigned int lines);
+
+extern int cx23885_risc_vbibuffer(struct pci_dev *pci,
+	struct btcx_riscmem *risc, struct scatterlist *sglist,
+	unsigned int top_offset, unsigned int bottom_offset,
+	unsigned int bpl, unsigned int padding, unsigned int lines);
+
+void cx23885_cancel_buffers(struct cx23885_tsport *port);
+
+extern int cx23885_restart_queue(struct cx23885_tsport *port,
+				struct cx23885_dmaqueue *q);
+
+extern void cx23885_wakeup(struct cx23885_tsport *port,
+			   struct cx23885_dmaqueue *q, u32 count);
+
+extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask);
+extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask);
+extern u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask);
+extern void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask,
+	int asoutput);
+
+extern void cx23885_irq_add_enable(struct cx23885_dev *dev, u32 mask);
+extern void cx23885_irq_enable(struct cx23885_dev *dev, u32 mask);
+extern void cx23885_irq_disable(struct cx23885_dev *dev, u32 mask);
+extern void cx23885_irq_remove(struct cx23885_dev *dev, u32 mask);
+
+/* ----------------------------------------------------------- */
+/* cx23885-cards.c                                             */
+extern struct cx23885_board cx23885_boards[];
+extern const unsigned int cx23885_bcount;
+
+extern struct cx23885_subid cx23885_subids[];
+extern const unsigned int cx23885_idcount;
+
+extern int cx23885_tuner_callback(void *priv, int component,
+	int command, int arg);
+extern void cx23885_card_list(struct cx23885_dev *dev);
+extern int  cx23885_ir_init(struct cx23885_dev *dev);
+extern void cx23885_ir_pci_int_enable(struct cx23885_dev *dev);
+extern void cx23885_ir_fini(struct cx23885_dev *dev);
+extern void cx23885_gpio_setup(struct cx23885_dev *dev);
+extern void cx23885_card_setup(struct cx23885_dev *dev);
+extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev);
+
+extern int cx23885_dvb_register(struct cx23885_tsport *port);
+extern int cx23885_dvb_unregister(struct cx23885_tsport *port);
+
+extern int cx23885_buf_prepare(struct videobuf_queue *q,
+			       struct cx23885_tsport *port,
+			       struct cx23885_buffer *buf,
+			       enum v4l2_field field);
+extern void cx23885_buf_queue(struct cx23885_tsport *port,
+			      struct cx23885_buffer *buf);
+extern void cx23885_free_buffer(struct videobuf_queue *q,
+				struct cx23885_buffer *buf);
+
+/* ----------------------------------------------------------- */
+/* cx23885-video.c                                             */
+/* Video */
+extern int cx23885_video_register(struct cx23885_dev *dev);
+extern void cx23885_video_unregister(struct cx23885_dev *dev);
+extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status);
+extern void cx23885_video_wakeup(struct cx23885_dev *dev,
+	struct cx23885_dmaqueue *q, u32 count);
+int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i);
+int cx23885_set_input(struct file *file, void *priv, unsigned int i);
+int cx23885_get_input(struct file *file, void *priv, unsigned int *i);
+int cx23885_set_frequency(struct file *file, void *priv, struct v4l2_frequency *f);
+int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
+int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
+int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm);
+
+/* ----------------------------------------------------------- */
+/* cx23885-vbi.c                                               */
+extern int cx23885_vbi_fmt(struct file *file, void *priv,
+	struct v4l2_format *f);
+extern void cx23885_vbi_timeout(unsigned long data);
+extern struct videobuf_queue_ops cx23885_vbi_qops;
+extern int cx23885_restart_vbi_queue(struct cx23885_dev *dev,
+	struct cx23885_dmaqueue *q);
+extern int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status);
+
+/* cx23885-i2c.c                                                */
+extern int cx23885_i2c_register(struct cx23885_i2c *bus);
+extern int cx23885_i2c_unregister(struct cx23885_i2c *bus);
+extern void cx23885_av_clk(struct cx23885_dev *dev, int enable);
+
+/* ----------------------------------------------------------- */
+/* cx23885-417.c                                               */
+extern int cx23885_417_register(struct cx23885_dev *dev);
+extern void cx23885_417_unregister(struct cx23885_dev *dev);
+extern int cx23885_irq_417(struct cx23885_dev *dev, u32 status);
+extern void cx23885_417_check_encoder(struct cx23885_dev *dev);
+extern void cx23885_mc417_init(struct cx23885_dev *dev);
+extern int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value);
+extern int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value);
+extern int mc417_register_read(struct cx23885_dev *dev,
+				u16 address, u32 *value);
+extern int mc417_register_write(struct cx23885_dev *dev,
+				u16 address, u32 value);
+extern void mc417_gpio_set(struct cx23885_dev *dev, u32 mask);
+extern void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask);
+extern void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput);
+
+/* ----------------------------------------------------------- */
+/* cx23885-alsa.c                                             */
+extern struct cx23885_audio_dev *cx23885_audio_register(
+					struct cx23885_dev *dev);
+extern void cx23885_audio_unregister(struct cx23885_dev *dev);
+extern int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask);
+extern int cx23885_risc_databuffer(struct pci_dev *pci,
+				   struct btcx_riscmem *risc,
+				   struct scatterlist *sglist,
+				   unsigned int bpl,
+				   unsigned int lines,
+				   unsigned int lpi);
+
+/* ----------------------------------------------------------- */
+/* tv norms                                                    */
+
+static inline unsigned int norm_maxw(v4l2_std_id norm)
+{
+	return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
+}
+
+static inline unsigned int norm_maxh(v4l2_std_id norm)
+{
+	return (norm & V4L2_STD_625_50) ? 576 : 480;
+}
+
+static inline unsigned int norm_swidth(v4l2_std_id norm)
+{
+	return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
+}
diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c
new file mode 100644
index 0000000..c2bc39c
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23888-ir.c
@@ -0,0 +1,1271 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  CX23888 Integrated Consumer Infrared Controller
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#include <linux/kfifo.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/rc-core.h>
+
+#include "cx23885.h"
+
+static unsigned int ir_888_debug;
+module_param(ir_888_debug, int, 0644);
+MODULE_PARM_DESC(ir_888_debug, "enable debug messages [CX23888 IR controller]");
+
+#define CX23888_IR_REG_BASE 	0x170000
+/*
+ * These CX23888 register offsets have a straightforward one to one mapping
+ * to the CX23885 register offsets of 0x200 through 0x218
+ */
+#define CX23888_IR_CNTRL_REG	0x170000
+#define CNTRL_WIN_3_3	0x00000000
+#define CNTRL_WIN_4_3	0x00000001
+#define CNTRL_WIN_3_4	0x00000002
+#define CNTRL_WIN_4_4	0x00000003
+#define CNTRL_WIN	0x00000003
+#define CNTRL_EDG_NONE	0x00000000
+#define CNTRL_EDG_FALL	0x00000004
+#define CNTRL_EDG_RISE	0x00000008
+#define CNTRL_EDG_BOTH	0x0000000C
+#define CNTRL_EDG	0x0000000C
+#define CNTRL_DMD	0x00000010
+#define CNTRL_MOD	0x00000020
+#define CNTRL_RFE	0x00000040
+#define CNTRL_TFE	0x00000080
+#define CNTRL_RXE	0x00000100
+#define CNTRL_TXE	0x00000200
+#define CNTRL_RIC	0x00000400
+#define CNTRL_TIC	0x00000800
+#define CNTRL_CPL	0x00001000
+#define CNTRL_LBM	0x00002000
+#define CNTRL_R		0x00004000
+/* CX23888 specific control flag */
+#define CNTRL_IVO	0x00008000
+
+#define CX23888_IR_TXCLK_REG	0x170004
+#define TXCLK_TCD	0x0000FFFF
+
+#define CX23888_IR_RXCLK_REG	0x170008
+#define RXCLK_RCD	0x0000FFFF
+
+#define CX23888_IR_CDUTY_REG	0x17000C
+#define CDUTY_CDC	0x0000000F
+
+#define CX23888_IR_STATS_REG	0x170010
+#define STATS_RTO	0x00000001
+#define STATS_ROR	0x00000002
+#define STATS_RBY	0x00000004
+#define STATS_TBY	0x00000008
+#define STATS_RSR	0x00000010
+#define STATS_TSR	0x00000020
+
+#define CX23888_IR_IRQEN_REG	0x170014
+#define IRQEN_RTE	0x00000001
+#define IRQEN_ROE	0x00000002
+#define IRQEN_RSE	0x00000010
+#define IRQEN_TSE	0x00000020
+
+#define CX23888_IR_FILTR_REG	0x170018
+#define FILTR_LPF	0x0000FFFF
+
+/* This register doesn't follow the pattern; it's 0x23C on a CX23885 */
+#define CX23888_IR_FIFO_REG	0x170040
+#define FIFO_RXTX	0x0000FFFF
+#define FIFO_RXTX_LVL	0x00010000
+#define FIFO_RXTX_RTO	0x0001FFFF
+#define FIFO_RX_NDV	0x00020000
+#define FIFO_RX_DEPTH	8
+#define FIFO_TX_DEPTH	8
+
+/* CX23888 unique registers */
+#define CX23888_IR_SEEDP_REG	0x17001C
+#define CX23888_IR_TIMOL_REG	0x170020
+#define CX23888_IR_WAKE0_REG	0x170024
+#define CX23888_IR_WAKE1_REG	0x170028
+#define CX23888_IR_WAKE2_REG	0x17002C
+#define CX23888_IR_MASK0_REG	0x170030
+#define CX23888_IR_MASK1_REG	0x170034
+#define CX23888_IR_MAKS2_REG	0x170038
+#define CX23888_IR_DPIPG_REG	0x17003C
+#define CX23888_IR_LEARN_REG	0x170044
+
+#define CX23888_VIDCLK_FREQ	108000000 /* 108 MHz, BT.656 */
+#define CX23888_IR_REFCLK_FREQ	(CX23888_VIDCLK_FREQ / 2)
+
+/*
+ * We use this union internally for convenience, but callers to tx_write
+ * and rx_read will be expecting records of type struct ir_raw_event.
+ * Always ensure the size of this union is dictated by struct ir_raw_event.
+ */
+union cx23888_ir_fifo_rec {
+	u32 hw_fifo_data;
+	struct ir_raw_event ir_core_data;
+};
+
+#define CX23888_IR_RX_KFIFO_SIZE    (256 * sizeof(union cx23888_ir_fifo_rec))
+#define CX23888_IR_TX_KFIFO_SIZE    (256 * sizeof(union cx23888_ir_fifo_rec))
+
+struct cx23888_ir_state {
+	struct v4l2_subdev sd;
+	struct cx23885_dev *dev;
+	u32 id;
+	u32 rev;
+
+	struct v4l2_subdev_ir_parameters rx_params;
+	struct mutex rx_params_lock;
+	atomic_t rxclk_divider;
+	atomic_t rx_invert;
+
+	struct kfifo rx_kfifo;
+	spinlock_t rx_kfifo_lock;
+
+	struct v4l2_subdev_ir_parameters tx_params;
+	struct mutex tx_params_lock;
+	atomic_t txclk_divider;
+};
+
+static inline struct cx23888_ir_state *to_state(struct v4l2_subdev *sd)
+{
+	return v4l2_get_subdevdata(sd);
+}
+
+/*
+ * IR register block read and write functions
+ */
+static
+inline int cx23888_ir_write4(struct cx23885_dev *dev, u32 addr, u32 value)
+{
+	cx_write(addr, value);
+	return 0;
+}
+
+static inline u32 cx23888_ir_read4(struct cx23885_dev *dev, u32 addr)
+{
+	return cx_read(addr);
+}
+
+static inline int cx23888_ir_and_or4(struct cx23885_dev *dev, u32 addr,
+				     u32 and_mask, u32 or_value)
+{
+	cx_andor(addr, ~and_mask, or_value);
+	return 0;
+}
+
+/*
+ * Rx and Tx Clock Divider register computations
+ *
+ * Note the largest clock divider value of 0xffff corresponds to:
+ * 	(0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns
+ * which fits in 21 bits, so we'll use unsigned int for time arguments.
+ */
+static inline u16 count_to_clock_divider(unsigned int d)
+{
+	if (d > RXCLK_RCD + 1)
+		d = RXCLK_RCD;
+	else if (d < 2)
+		d = 1;
+	else
+		d--;
+	return (u16) d;
+}
+
+static inline u16 ns_to_clock_divider(unsigned int ns)
+{
+	return count_to_clock_divider(
+		DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ / 1000000 * ns, 1000));
+}
+
+static inline unsigned int clock_divider_to_ns(unsigned int divider)
+{
+	/* Period of the Rx or Tx clock in ns */
+	return DIV_ROUND_CLOSEST((divider + 1) * 1000,
+				 CX23888_IR_REFCLK_FREQ / 1000000);
+}
+
+static inline u16 carrier_freq_to_clock_divider(unsigned int freq)
+{
+	return count_to_clock_divider(
+			  DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, freq * 16));
+}
+
+static inline unsigned int clock_divider_to_carrier_freq(unsigned int divider)
+{
+	return DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, (divider + 1) * 16);
+}
+
+static inline u16 freq_to_clock_divider(unsigned int freq,
+					unsigned int rollovers)
+{
+	return count_to_clock_divider(
+		   DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, freq * rollovers));
+}
+
+static inline unsigned int clock_divider_to_freq(unsigned int divider,
+						 unsigned int rollovers)
+{
+	return DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ,
+				 (divider + 1) * rollovers);
+}
+
+/*
+ * Low Pass Filter register calculations
+ *
+ * Note the largest count value of 0xffff corresponds to:
+ * 	0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns
+ * which fits in 21 bits, so we'll use unsigned int for time arguments.
+ */
+static inline u16 count_to_lpf_count(unsigned int d)
+{
+	if (d > FILTR_LPF)
+		d = FILTR_LPF;
+	else if (d < 4)
+		d = 0;
+	return (u16) d;
+}
+
+static inline u16 ns_to_lpf_count(unsigned int ns)
+{
+	return count_to_lpf_count(
+		DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ / 1000000 * ns, 1000));
+}
+
+static inline unsigned int lpf_count_to_ns(unsigned int count)
+{
+	/* Duration of the Low Pass Filter rejection window in ns */
+	return DIV_ROUND_CLOSEST(count * 1000,
+				 CX23888_IR_REFCLK_FREQ / 1000000);
+}
+
+static inline unsigned int lpf_count_to_us(unsigned int count)
+{
+	/* Duration of the Low Pass Filter rejection window in us */
+	return DIV_ROUND_CLOSEST(count, CX23888_IR_REFCLK_FREQ / 1000000);
+}
+
+/*
+ * FIFO register pulse width count compuations
+ */
+static u32 clock_divider_to_resolution(u16 divider)
+{
+	/*
+	 * Resolution is the duration of 1 tick of the readable portion of
+	 * of the pulse width counter as read from the FIFO.  The two lsb's are
+	 * not readable, hence the << 2.  This function returns ns.
+	 */
+	return DIV_ROUND_CLOSEST((1 << 2)  * ((u32) divider + 1) * 1000,
+				 CX23888_IR_REFCLK_FREQ / 1000000);
+}
+
+static u64 pulse_width_count_to_ns(u16 count, u16 divider)
+{
+	u64 n;
+	u32 rem;
+
+	/*
+	 * The 2 lsb's of the pulse width timer count are not readable, hence
+	 * the (count << 2) | 0x3
+	 */
+	n = (((u64) count << 2) | 0x3) * (divider + 1) * 1000; /* millicycles */
+	rem = do_div(n, CX23888_IR_REFCLK_FREQ / 1000000);     /* / MHz => ns */
+	if (rem >= CX23888_IR_REFCLK_FREQ / 1000000 / 2)
+		n++;
+	return n;
+}
+
+static unsigned int pulse_width_count_to_us(u16 count, u16 divider)
+{
+	u64 n;
+	u32 rem;
+
+	/*
+	 * The 2 lsb's of the pulse width timer count are not readable, hence
+	 * the (count << 2) | 0x3
+	 */
+	n = (((u64) count << 2) | 0x3) * (divider + 1);    /* cycles      */
+	rem = do_div(n, CX23888_IR_REFCLK_FREQ / 1000000); /* / MHz => us */
+	if (rem >= CX23888_IR_REFCLK_FREQ / 1000000 / 2)
+		n++;
+	return (unsigned int) n;
+}
+
+/*
+ * Pulse Clocks computations: Combined Pulse Width Count & Rx Clock Counts
+ *
+ * The total pulse clock count is an 18 bit pulse width timer count as the most
+ * significant part and (up to) 16 bit clock divider count as a modulus.
+ * When the Rx clock divider ticks down to 0, it increments the 18 bit pulse
+ * width timer count's least significant bit.
+ */
+static u64 ns_to_pulse_clocks(u32 ns)
+{
+	u64 clocks;
+	u32 rem;
+	clocks = CX23888_IR_REFCLK_FREQ / 1000000 * (u64) ns; /* millicycles  */
+	rem = do_div(clocks, 1000);                         /* /1000 = cycles */
+	if (rem >= 1000 / 2)
+		clocks++;
+	return clocks;
+}
+
+static u16 pulse_clocks_to_clock_divider(u64 count)
+{
+	do_div(count, (FIFO_RXTX << 2) | 0x3);
+
+	/* net result needs to be rounded down and decremented by 1 */
+	if (count > RXCLK_RCD + 1)
+		count = RXCLK_RCD;
+	else if (count < 2)
+		count = 1;
+	else
+		count--;
+	return (u16) count;
+}
+
+/*
+ * IR Control Register helpers
+ */
+enum tx_fifo_watermark {
+	TX_FIFO_HALF_EMPTY = 0,
+	TX_FIFO_EMPTY      = CNTRL_TIC,
+};
+
+enum rx_fifo_watermark {
+	RX_FIFO_HALF_FULL = 0,
+	RX_FIFO_NOT_EMPTY = CNTRL_RIC,
+};
+
+static inline void control_tx_irq_watermark(struct cx23885_dev *dev,
+					    enum tx_fifo_watermark level)
+{
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_TIC, level);
+}
+
+static inline void control_rx_irq_watermark(struct cx23885_dev *dev,
+					    enum rx_fifo_watermark level)
+{
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_RIC, level);
+}
+
+static inline void control_tx_enable(struct cx23885_dev *dev, bool enable)
+{
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~(CNTRL_TXE | CNTRL_TFE),
+			   enable ? (CNTRL_TXE | CNTRL_TFE) : 0);
+}
+
+static inline void control_rx_enable(struct cx23885_dev *dev, bool enable)
+{
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~(CNTRL_RXE | CNTRL_RFE),
+			   enable ? (CNTRL_RXE | CNTRL_RFE) : 0);
+}
+
+static inline void control_tx_modulation_enable(struct cx23885_dev *dev,
+						bool enable)
+{
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_MOD,
+			   enable ? CNTRL_MOD : 0);
+}
+
+static inline void control_rx_demodulation_enable(struct cx23885_dev *dev,
+						  bool enable)
+{
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_DMD,
+			   enable ? CNTRL_DMD : 0);
+}
+
+static inline void control_rx_s_edge_detection(struct cx23885_dev *dev,
+					       u32 edge_types)
+{
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_EDG_BOTH,
+			   edge_types & CNTRL_EDG_BOTH);
+}
+
+static void control_rx_s_carrier_window(struct cx23885_dev *dev,
+					unsigned int carrier,
+					unsigned int *carrier_range_low,
+					unsigned int *carrier_range_high)
+{
+	u32 v;
+	unsigned int c16 = carrier * 16;
+
+	if (*carrier_range_low < DIV_ROUND_CLOSEST(c16, 16 + 3)) {
+		v = CNTRL_WIN_3_4;
+		*carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 4);
+	} else {
+		v = CNTRL_WIN_3_3;
+		*carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 3);
+	}
+
+	if (*carrier_range_high > DIV_ROUND_CLOSEST(c16, 16 - 3)) {
+		v |= CNTRL_WIN_4_3;
+		*carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 4);
+	} else {
+		v |= CNTRL_WIN_3_3;
+		*carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 3);
+	}
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_WIN, v);
+}
+
+static inline void control_tx_polarity_invert(struct cx23885_dev *dev,
+					      bool invert)
+{
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_CPL,
+			   invert ? CNTRL_CPL : 0);
+}
+
+static inline void control_tx_level_invert(struct cx23885_dev *dev,
+					  bool invert)
+{
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_IVO,
+			   invert ? CNTRL_IVO : 0);
+}
+
+/*
+ * IR Rx & Tx Clock Register helpers
+ */
+static unsigned int txclk_tx_s_carrier(struct cx23885_dev *dev,
+				       unsigned int freq,
+				       u16 *divider)
+{
+	*divider = carrier_freq_to_clock_divider(freq);
+	cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, *divider);
+	return clock_divider_to_carrier_freq(*divider);
+}
+
+static unsigned int rxclk_rx_s_carrier(struct cx23885_dev *dev,
+				       unsigned int freq,
+				       u16 *divider)
+{
+	*divider = carrier_freq_to_clock_divider(freq);
+	cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, *divider);
+	return clock_divider_to_carrier_freq(*divider);
+}
+
+static u32 txclk_tx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns,
+				      u16 *divider)
+{
+	u64 pulse_clocks;
+
+	if (ns > IR_MAX_DURATION)
+		ns = IR_MAX_DURATION;
+	pulse_clocks = ns_to_pulse_clocks(ns);
+	*divider = pulse_clocks_to_clock_divider(pulse_clocks);
+	cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, *divider);
+	return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider);
+}
+
+static u32 rxclk_rx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns,
+				      u16 *divider)
+{
+	u64 pulse_clocks;
+
+	if (ns > IR_MAX_DURATION)
+		ns = IR_MAX_DURATION;
+	pulse_clocks = ns_to_pulse_clocks(ns);
+	*divider = pulse_clocks_to_clock_divider(pulse_clocks);
+	cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, *divider);
+	return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider);
+}
+
+/*
+ * IR Tx Carrier Duty Cycle register helpers
+ */
+static unsigned int cduty_tx_s_duty_cycle(struct cx23885_dev *dev,
+					  unsigned int duty_cycle)
+{
+	u32 n;
+	n = DIV_ROUND_CLOSEST(duty_cycle * 100, 625); /* 16ths of 100% */
+	if (n != 0)
+		n--;
+	if (n > 15)
+		n = 15;
+	cx23888_ir_write4(dev, CX23888_IR_CDUTY_REG, n);
+	return DIV_ROUND_CLOSEST((n + 1) * 100, 16);
+}
+
+/*
+ * IR Filter Register helpers
+ */
+static u32 filter_rx_s_min_width(struct cx23885_dev *dev, u32 min_width_ns)
+{
+	u32 count = ns_to_lpf_count(min_width_ns);
+	cx23888_ir_write4(dev, CX23888_IR_FILTR_REG, count);
+	return lpf_count_to_ns(count);
+}
+
+/*
+ * IR IRQ Enable Register helpers
+ */
+static inline void irqenable_rx(struct cx23885_dev *dev, u32 mask)
+{
+	mask &= (IRQEN_RTE | IRQEN_ROE | IRQEN_RSE);
+	cx23888_ir_and_or4(dev, CX23888_IR_IRQEN_REG,
+			   ~(IRQEN_RTE | IRQEN_ROE | IRQEN_RSE), mask);
+}
+
+static inline void irqenable_tx(struct cx23885_dev *dev, u32 mask)
+{
+	mask &= IRQEN_TSE;
+	cx23888_ir_and_or4(dev, CX23888_IR_IRQEN_REG, ~IRQEN_TSE, mask);
+}
+
+/*
+ * V4L2 Subdevice IR Ops
+ */
+static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
+				  bool *handled)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	struct cx23885_dev *dev = state->dev;
+	unsigned long flags;
+
+	u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG);
+	u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG);
+	u32 stats = cx23888_ir_read4(dev, CX23888_IR_STATS_REG);
+
+	union cx23888_ir_fifo_rec rx_data[FIFO_RX_DEPTH];
+	unsigned int i, j, k;
+	u32 events, v;
+	int tsr, rsr, rto, ror, tse, rse, rte, roe, kror;
+
+	tsr = stats & STATS_TSR; /* Tx FIFO Service Request */
+	rsr = stats & STATS_RSR; /* Rx FIFO Service Request */
+	rto = stats & STATS_RTO; /* Rx Pulse Width Timer Time Out */
+	ror = stats & STATS_ROR; /* Rx FIFO Over Run */
+
+	tse = irqen & IRQEN_TSE; /* Tx FIFO Service Request IRQ Enable */
+	rse = irqen & IRQEN_RSE; /* Rx FIFO Service Reuqest IRQ Enable */
+	rte = irqen & IRQEN_RTE; /* Rx Pulse Width Timer Time Out IRQ Enable */
+	roe = irqen & IRQEN_ROE; /* Rx FIFO Over Run IRQ Enable */
+
+	*handled = false;
+	v4l2_dbg(2, ir_888_debug, sd, "IRQ Status:  %s %s %s %s %s %s\n",
+		 tsr ? "tsr" : "   ", rsr ? "rsr" : "   ",
+		 rto ? "rto" : "   ", ror ? "ror" : "   ",
+		 stats & STATS_TBY ? "tby" : "   ",
+		 stats & STATS_RBY ? "rby" : "   ");
+
+	v4l2_dbg(2, ir_888_debug, sd, "IRQ Enables: %s %s %s %s\n",
+		 tse ? "tse" : "   ", rse ? "rse" : "   ",
+		 rte ? "rte" : "   ", roe ? "roe" : "   ");
+
+	/*
+	 * Transmitter interrupt service
+	 */
+	if (tse && tsr) {
+		/*
+		 * TODO:
+		 * Check the watermark threshold setting
+		 * Pull FIFO_TX_DEPTH or FIFO_TX_DEPTH/2 entries from tx_kfifo
+		 * Push the data to the hardware FIFO.
+		 * If there was nothing more to send in the tx_kfifo, disable
+		 *	the TSR IRQ and notify the v4l2_device.
+		 * If there was something in the tx_kfifo, check the tx_kfifo
+		 *      level and notify the v4l2_device, if it is low.
+		 */
+		/* For now, inhibit TSR interrupt until Tx is implemented */
+		irqenable_tx(dev, 0);
+		events = V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ;
+		v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_TX_NOTIFY, &events);
+		*handled = true;
+	}
+
+	/*
+	 * Receiver interrupt service
+	 */
+	kror = 0;
+	if ((rse && rsr) || (rte && rto)) {
+		/*
+		 * Receive data on RSR to clear the STATS_RSR.
+		 * Receive data on RTO, since we may not have yet hit the RSR
+		 * watermark when we receive the RTO.
+		 */
+		for (i = 0, v = FIFO_RX_NDV;
+		     (v & FIFO_RX_NDV) && !kror; i = 0) {
+			for (j = 0;
+			     (v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) {
+				v = cx23888_ir_read4(dev, CX23888_IR_FIFO_REG);
+				rx_data[i].hw_fifo_data = v & ~FIFO_RX_NDV;
+				i++;
+			}
+			if (i == 0)
+				break;
+			j = i * sizeof(union cx23888_ir_fifo_rec);
+			k = kfifo_in_locked(&state->rx_kfifo,
+				      (unsigned char *) rx_data, j,
+				      &state->rx_kfifo_lock);
+			if (k != j)
+				kror++; /* rx_kfifo over run */
+		}
+		*handled = true;
+	}
+
+	events = 0;
+	v = 0;
+	if (kror) {
+		events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN;
+		v4l2_err(sd, "IR receiver software FIFO overrun\n");
+	}
+	if (roe && ror) {
+		/*
+		 * The RX FIFO Enable (CNTRL_RFE) must be toggled to clear
+		 * the Rx FIFO Over Run status (STATS_ROR)
+		 */
+		v |= CNTRL_RFE;
+		events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN;
+		v4l2_err(sd, "IR receiver hardware FIFO overrun\n");
+	}
+	if (rte && rto) {
+		/*
+		 * The IR Receiver Enable (CNTRL_RXE) must be toggled to clear
+		 * the Rx Pulse Width Timer Time Out (STATS_RTO)
+		 */
+		v |= CNTRL_RXE;
+		events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED;
+	}
+	if (v) {
+		/* Clear STATS_ROR & STATS_RTO as needed by reseting hardware */
+		cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl & ~v);
+		cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl);
+		*handled = true;
+	}
+
+	spin_lock_irqsave(&state->rx_kfifo_lock, flags);
+	if (kfifo_len(&state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2)
+		events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ;
+	spin_unlock_irqrestore(&state->rx_kfifo_lock, flags);
+
+	if (events)
+		v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events);
+	return 0;
+}
+
+/* Receiver */
+static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
+			      ssize_t *num)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	bool invert = (bool) atomic_read(&state->rx_invert);
+	u16 divider = (u16) atomic_read(&state->rxclk_divider);
+
+	unsigned int i, n;
+	union cx23888_ir_fifo_rec *p;
+	unsigned u, v, w;
+
+	n = count / sizeof(union cx23888_ir_fifo_rec)
+		* sizeof(union cx23888_ir_fifo_rec);
+	if (n == 0) {
+		*num = 0;
+		return 0;
+	}
+
+	n = kfifo_out_locked(&state->rx_kfifo, buf, n, &state->rx_kfifo_lock);
+
+	n /= sizeof(union cx23888_ir_fifo_rec);
+	*num = n * sizeof(union cx23888_ir_fifo_rec);
+
+	for (p = (union cx23888_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) {
+
+		if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
+			/* Assume RTO was because of no IR light input */
+			u = 0;
+			w = 1;
+		} else {
+			u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
+			if (invert)
+				u = u ? 0 : 1;
+			w = 0;
+		}
+
+		v = (unsigned) pulse_width_count_to_ns(
+				  (u16) (p->hw_fifo_data & FIFO_RXTX), divider);
+		if (v > IR_MAX_DURATION)
+			v = IR_MAX_DURATION;
+
+		init_ir_raw_event(&p->ir_core_data);
+		p->ir_core_data.pulse = u;
+		p->ir_core_data.duration = v;
+		p->ir_core_data.timeout = w;
+
+		v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns  %s  %s\n",
+			 v, u ? "mark" : "space", w ? "(timed out)" : "");
+		if (w)
+			v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n");
+	}
+	return 0;
+}
+
+static int cx23888_ir_rx_g_parameters(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_ir_parameters *p)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	mutex_lock(&state->rx_params_lock);
+	memcpy(p, &state->rx_params, sizeof(struct v4l2_subdev_ir_parameters));
+	mutex_unlock(&state->rx_params_lock);
+	return 0;
+}
+
+static int cx23888_ir_rx_shutdown(struct v4l2_subdev *sd)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	struct cx23885_dev *dev = state->dev;
+
+	mutex_lock(&state->rx_params_lock);
+
+	/* Disable or slow down all IR Rx circuits and counters */
+	irqenable_rx(dev, 0);
+	control_rx_enable(dev, false);
+	control_rx_demodulation_enable(dev, false);
+	control_rx_s_edge_detection(dev, CNTRL_EDG_NONE);
+	filter_rx_s_min_width(dev, 0);
+	cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, RXCLK_RCD);
+
+	state->rx_params.shutdown = true;
+
+	mutex_unlock(&state->rx_params_lock);
+	return 0;
+}
+
+static int cx23888_ir_rx_s_parameters(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_ir_parameters *p)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	struct cx23885_dev *dev = state->dev;
+	struct v4l2_subdev_ir_parameters *o = &state->rx_params;
+	u16 rxclk_divider;
+
+	if (p->shutdown)
+		return cx23888_ir_rx_shutdown(sd);
+
+	if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH)
+		return -ENOSYS;
+
+	mutex_lock(&state->rx_params_lock);
+
+	o->shutdown = p->shutdown;
+
+	o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
+
+	o->bytes_per_data_element = p->bytes_per_data_element
+				  = sizeof(union cx23888_ir_fifo_rec);
+
+	/* Before we tweak the hardware, we have to disable the receiver */
+	irqenable_rx(dev, 0);
+	control_rx_enable(dev, false);
+
+	control_rx_demodulation_enable(dev, p->modulation);
+	o->modulation = p->modulation;
+
+	if (p->modulation) {
+		p->carrier_freq = rxclk_rx_s_carrier(dev, p->carrier_freq,
+						     &rxclk_divider);
+
+		o->carrier_freq = p->carrier_freq;
+
+		o->duty_cycle = p->duty_cycle = 50;
+
+		control_rx_s_carrier_window(dev, p->carrier_freq,
+					    &p->carrier_range_lower,
+					    &p->carrier_range_upper);
+		o->carrier_range_lower = p->carrier_range_lower;
+		o->carrier_range_upper = p->carrier_range_upper;
+
+		p->max_pulse_width =
+			(u32) pulse_width_count_to_ns(FIFO_RXTX, rxclk_divider);
+	} else {
+		p->max_pulse_width =
+			    rxclk_rx_s_max_pulse_width(dev, p->max_pulse_width,
+						       &rxclk_divider);
+	}
+	o->max_pulse_width = p->max_pulse_width;
+	atomic_set(&state->rxclk_divider, rxclk_divider);
+
+	p->noise_filter_min_width =
+			  filter_rx_s_min_width(dev, p->noise_filter_min_width);
+	o->noise_filter_min_width = p->noise_filter_min_width;
+
+	p->resolution = clock_divider_to_resolution(rxclk_divider);
+	o->resolution = p->resolution;
+
+	/* FIXME - make this dependent on resolution for better performance */
+	control_rx_irq_watermark(dev, RX_FIFO_HALF_FULL);
+
+	control_rx_s_edge_detection(dev, CNTRL_EDG_BOTH);
+
+	o->invert_level = p->invert_level;
+	atomic_set(&state->rx_invert, p->invert_level);
+
+	o->interrupt_enable = p->interrupt_enable;
+	o->enable = p->enable;
+	if (p->enable) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&state->rx_kfifo_lock, flags);
+		kfifo_reset(&state->rx_kfifo);
+		/* reset tx_fifo too if there is one... */
+		spin_unlock_irqrestore(&state->rx_kfifo_lock, flags);
+		if (p->interrupt_enable)
+			irqenable_rx(dev, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE);
+		control_rx_enable(dev, p->enable);
+	}
+
+	mutex_unlock(&state->rx_params_lock);
+	return 0;
+}
+
+/* Transmitter */
+static int cx23888_ir_tx_write(struct v4l2_subdev *sd, u8 *buf, size_t count,
+			       ssize_t *num)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	struct cx23885_dev *dev = state->dev;
+	/* For now enable the Tx FIFO Service interrupt & pretend we did work */
+	irqenable_tx(dev, IRQEN_TSE);
+	*num = count;
+	return 0;
+}
+
+static int cx23888_ir_tx_g_parameters(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_ir_parameters *p)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	mutex_lock(&state->tx_params_lock);
+	memcpy(p, &state->tx_params, sizeof(struct v4l2_subdev_ir_parameters));
+	mutex_unlock(&state->tx_params_lock);
+	return 0;
+}
+
+static int cx23888_ir_tx_shutdown(struct v4l2_subdev *sd)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	struct cx23885_dev *dev = state->dev;
+
+	mutex_lock(&state->tx_params_lock);
+
+	/* Disable or slow down all IR Tx circuits and counters */
+	irqenable_tx(dev, 0);
+	control_tx_enable(dev, false);
+	control_tx_modulation_enable(dev, false);
+	cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, TXCLK_TCD);
+
+	state->tx_params.shutdown = true;
+
+	mutex_unlock(&state->tx_params_lock);
+	return 0;
+}
+
+static int cx23888_ir_tx_s_parameters(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_ir_parameters *p)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	struct cx23885_dev *dev = state->dev;
+	struct v4l2_subdev_ir_parameters *o = &state->tx_params;
+	u16 txclk_divider;
+
+	if (p->shutdown)
+		return cx23888_ir_tx_shutdown(sd);
+
+	if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH)
+		return -ENOSYS;
+
+	mutex_lock(&state->tx_params_lock);
+
+	o->shutdown = p->shutdown;
+
+	o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
+
+	o->bytes_per_data_element = p->bytes_per_data_element
+				  = sizeof(union cx23888_ir_fifo_rec);
+
+	/* Before we tweak the hardware, we have to disable the transmitter */
+	irqenable_tx(dev, 0);
+	control_tx_enable(dev, false);
+
+	control_tx_modulation_enable(dev, p->modulation);
+	o->modulation = p->modulation;
+
+	if (p->modulation) {
+		p->carrier_freq = txclk_tx_s_carrier(dev, p->carrier_freq,
+						     &txclk_divider);
+		o->carrier_freq = p->carrier_freq;
+
+		p->duty_cycle = cduty_tx_s_duty_cycle(dev, p->duty_cycle);
+		o->duty_cycle = p->duty_cycle;
+
+		p->max_pulse_width =
+			(u32) pulse_width_count_to_ns(FIFO_RXTX, txclk_divider);
+	} else {
+		p->max_pulse_width =
+			    txclk_tx_s_max_pulse_width(dev, p->max_pulse_width,
+						       &txclk_divider);
+	}
+	o->max_pulse_width = p->max_pulse_width;
+	atomic_set(&state->txclk_divider, txclk_divider);
+
+	p->resolution = clock_divider_to_resolution(txclk_divider);
+	o->resolution = p->resolution;
+
+	/* FIXME - make this dependent on resolution for better performance */
+	control_tx_irq_watermark(dev, TX_FIFO_HALF_EMPTY);
+
+	control_tx_polarity_invert(dev, p->invert_carrier_sense);
+	o->invert_carrier_sense = p->invert_carrier_sense;
+
+	control_tx_level_invert(dev, p->invert_level);
+	o->invert_level = p->invert_level;
+
+	o->interrupt_enable = p->interrupt_enable;
+	o->enable = p->enable;
+	if (p->enable) {
+		if (p->interrupt_enable)
+			irqenable_tx(dev, IRQEN_TSE);
+		control_tx_enable(dev, p->enable);
+	}
+
+	mutex_unlock(&state->tx_params_lock);
+	return 0;
+}
+
+
+/*
+ * V4L2 Subdevice Core Ops
+ */
+static int cx23888_ir_log_status(struct v4l2_subdev *sd)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	struct cx23885_dev *dev = state->dev;
+	char *s;
+	int i, j;
+
+	u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG);
+	u32 txclk = cx23888_ir_read4(dev, CX23888_IR_TXCLK_REG) & TXCLK_TCD;
+	u32 rxclk = cx23888_ir_read4(dev, CX23888_IR_RXCLK_REG) & RXCLK_RCD;
+	u32 cduty = cx23888_ir_read4(dev, CX23888_IR_CDUTY_REG) & CDUTY_CDC;
+	u32 stats = cx23888_ir_read4(dev, CX23888_IR_STATS_REG);
+	u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG);
+	u32 filtr = cx23888_ir_read4(dev, CX23888_IR_FILTR_REG) & FILTR_LPF;
+
+	v4l2_info(sd, "IR Receiver:\n");
+	v4l2_info(sd, "\tEnabled:                           %s\n",
+		  cntrl & CNTRL_RXE ? "yes" : "no");
+	v4l2_info(sd, "\tDemodulation from a carrier:       %s\n",
+		  cntrl & CNTRL_DMD ? "enabled" : "disabled");
+	v4l2_info(sd, "\tFIFO:                              %s\n",
+		  cntrl & CNTRL_RFE ? "enabled" : "disabled");
+	switch (cntrl & CNTRL_EDG) {
+	case CNTRL_EDG_NONE:
+		s = "disabled";
+		break;
+	case CNTRL_EDG_FALL:
+		s = "falling edge";
+		break;
+	case CNTRL_EDG_RISE:
+		s = "rising edge";
+		break;
+	case CNTRL_EDG_BOTH:
+		s = "rising & falling edges";
+		break;
+	default:
+		s = "??? edge";
+		break;
+	}
+	v4l2_info(sd, "\tPulse timers' start/stop trigger:  %s\n", s);
+	v4l2_info(sd, "\tFIFO data on pulse timer overflow: %s\n",
+		  cntrl & CNTRL_R ? "not loaded" : "overflow marker");
+	v4l2_info(sd, "\tFIFO interrupt watermark:          %s\n",
+		  cntrl & CNTRL_RIC ? "not empty" : "half full or greater");
+	v4l2_info(sd, "\tLoopback mode:                     %s\n",
+		  cntrl & CNTRL_LBM ? "loopback active" : "normal receive");
+	if (cntrl & CNTRL_DMD) {
+		v4l2_info(sd, "\tExpected carrier (16 clocks):      %u Hz\n",
+			  clock_divider_to_carrier_freq(rxclk));
+		switch (cntrl & CNTRL_WIN) {
+		case CNTRL_WIN_3_3:
+			i = 3;
+			j = 3;
+			break;
+		case CNTRL_WIN_4_3:
+			i = 4;
+			j = 3;
+			break;
+		case CNTRL_WIN_3_4:
+			i = 3;
+			j = 4;
+			break;
+		case CNTRL_WIN_4_4:
+			i = 4;
+			j = 4;
+			break;
+		default:
+			i = 0;
+			j = 0;
+			break;
+		}
+		v4l2_info(sd, "\tNext carrier edge window:          16 clocks "
+			  "-%1d/+%1d, %u to %u Hz\n", i, j,
+			  clock_divider_to_freq(rxclk, 16 + j),
+			  clock_divider_to_freq(rxclk, 16 - i));
+	}
+	v4l2_info(sd, "\tMax measurable pulse width:        %u us, %llu ns\n",
+		  pulse_width_count_to_us(FIFO_RXTX, rxclk),
+		  pulse_width_count_to_ns(FIFO_RXTX, rxclk));
+	v4l2_info(sd, "\tLow pass filter:                   %s\n",
+		  filtr ? "enabled" : "disabled");
+	if (filtr)
+		v4l2_info(sd, "\tMin acceptable pulse width (LPF):  %u us, "
+			  "%u ns\n",
+			  lpf_count_to_us(filtr),
+			  lpf_count_to_ns(filtr));
+	v4l2_info(sd, "\tPulse width timer timed-out:       %s\n",
+		  stats & STATS_RTO ? "yes" : "no");
+	v4l2_info(sd, "\tPulse width timer time-out intr:   %s\n",
+		  irqen & IRQEN_RTE ? "enabled" : "disabled");
+	v4l2_info(sd, "\tFIFO overrun:                      %s\n",
+		  stats & STATS_ROR ? "yes" : "no");
+	v4l2_info(sd, "\tFIFO overrun interrupt:            %s\n",
+		  irqen & IRQEN_ROE ? "enabled" : "disabled");
+	v4l2_info(sd, "\tBusy:                              %s\n",
+		  stats & STATS_RBY ? "yes" : "no");
+	v4l2_info(sd, "\tFIFO service requested:            %s\n",
+		  stats & STATS_RSR ? "yes" : "no");
+	v4l2_info(sd, "\tFIFO service request interrupt:    %s\n",
+		  irqen & IRQEN_RSE ? "enabled" : "disabled");
+
+	v4l2_info(sd, "IR Transmitter:\n");
+	v4l2_info(sd, "\tEnabled:                           %s\n",
+		  cntrl & CNTRL_TXE ? "yes" : "no");
+	v4l2_info(sd, "\tModulation onto a carrier:         %s\n",
+		  cntrl & CNTRL_MOD ? "enabled" : "disabled");
+	v4l2_info(sd, "\tFIFO:                              %s\n",
+		  cntrl & CNTRL_TFE ? "enabled" : "disabled");
+	v4l2_info(sd, "\tFIFO interrupt watermark:          %s\n",
+		  cntrl & CNTRL_TIC ? "not empty" : "half full or less");
+	v4l2_info(sd, "\tOutput pin level inversion         %s\n",
+		  cntrl & CNTRL_IVO ? "yes" : "no");
+	v4l2_info(sd, "\tCarrier polarity:                  %s\n",
+		  cntrl & CNTRL_CPL ? "space:burst mark:noburst"
+				    : "space:noburst mark:burst");
+	if (cntrl & CNTRL_MOD) {
+		v4l2_info(sd, "\tCarrier (16 clocks):               %u Hz\n",
+			  clock_divider_to_carrier_freq(txclk));
+		v4l2_info(sd, "\tCarrier duty cycle:                %2u/16\n",
+			  cduty + 1);
+	}
+	v4l2_info(sd, "\tMax pulse width:                   %u us, %llu ns\n",
+		  pulse_width_count_to_us(FIFO_RXTX, txclk),
+		  pulse_width_count_to_ns(FIFO_RXTX, txclk));
+	v4l2_info(sd, "\tBusy:                              %s\n",
+		  stats & STATS_TBY ? "yes" : "no");
+	v4l2_info(sd, "\tFIFO service requested:            %s\n",
+		  stats & STATS_TSR ? "yes" : "no");
+	v4l2_info(sd, "\tFIFO service request interrupt:    %s\n",
+		  irqen & IRQEN_TSE ? "enabled" : "disabled");
+
+	return 0;
+}
+
+static inline int cx23888_ir_dbg_match(const struct v4l2_dbg_match *match)
+{
+	return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 2;
+}
+
+static int cx23888_ir_g_chip_ident(struct v4l2_subdev *sd,
+				   struct v4l2_dbg_chip_ident *chip)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+
+	if (cx23888_ir_dbg_match(&chip->match)) {
+		chip->ident = state->id;
+		chip->revision = state->rev;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int cx23888_ir_g_register(struct v4l2_subdev *sd,
+				 struct v4l2_dbg_register *reg)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg;
+
+	if (!cx23888_ir_dbg_match(&reg->match))
+		return -EINVAL;
+	if ((addr & 0x3) != 0)
+		return -EINVAL;
+	if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG)
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	reg->size = 4;
+	reg->val = cx23888_ir_read4(state->dev, addr);
+	return 0;
+}
+
+static int cx23888_ir_s_register(struct v4l2_subdev *sd,
+				 struct v4l2_dbg_register *reg)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg;
+
+	if (!cx23888_ir_dbg_match(&reg->match))
+		return -EINVAL;
+	if ((addr & 0x3) != 0)
+		return -EINVAL;
+	if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG)
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	cx23888_ir_write4(state->dev, addr, reg->val);
+	return 0;
+}
+#endif
+
+static const struct v4l2_subdev_core_ops cx23888_ir_core_ops = {
+	.g_chip_ident = cx23888_ir_g_chip_ident,
+	.log_status = cx23888_ir_log_status,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = cx23888_ir_g_register,
+	.s_register = cx23888_ir_s_register,
+#endif
+	.interrupt_service_routine = cx23888_ir_irq_handler,
+};
+
+static const struct v4l2_subdev_ir_ops cx23888_ir_ir_ops = {
+	.rx_read = cx23888_ir_rx_read,
+	.rx_g_parameters = cx23888_ir_rx_g_parameters,
+	.rx_s_parameters = cx23888_ir_rx_s_parameters,
+
+	.tx_write = cx23888_ir_tx_write,
+	.tx_g_parameters = cx23888_ir_tx_g_parameters,
+	.tx_s_parameters = cx23888_ir_tx_s_parameters,
+};
+
+static const struct v4l2_subdev_ops cx23888_ir_controller_ops = {
+	.core = &cx23888_ir_core_ops,
+	.ir = &cx23888_ir_ir_ops,
+};
+
+static const struct v4l2_subdev_ir_parameters default_rx_params = {
+	.bytes_per_data_element = sizeof(union cx23888_ir_fifo_rec),
+	.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
+
+	.enable = false,
+	.interrupt_enable = false,
+	.shutdown = true,
+
+	.modulation = true,
+	.carrier_freq = 36000, /* 36 kHz - RC-5, RC-6, and RC-6A carrier */
+
+	/* RC-5:    666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */
+	/* RC-6A:   333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */
+	.noise_filter_min_width = 333333, /* ns */
+	.carrier_range_lower = 35000,
+	.carrier_range_upper = 37000,
+	.invert_level = false,
+};
+
+static const struct v4l2_subdev_ir_parameters default_tx_params = {
+	.bytes_per_data_element = sizeof(union cx23888_ir_fifo_rec),
+	.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
+
+	.enable = false,
+	.interrupt_enable = false,
+	.shutdown = true,
+
+	.modulation = true,
+	.carrier_freq = 36000, /* 36 kHz - RC-5 carrier */
+	.duty_cycle = 25,      /* 25 %   - RC-5 carrier */
+	.invert_level = false,
+	.invert_carrier_sense = false,
+};
+
+int cx23888_ir_probe(struct cx23885_dev *dev)
+{
+	struct cx23888_ir_state *state;
+	struct v4l2_subdev *sd;
+	struct v4l2_subdev_ir_parameters default_params;
+	int ret;
+
+	state = kzalloc(sizeof(struct cx23888_ir_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+
+	spin_lock_init(&state->rx_kfifo_lock);
+	if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL))
+		return -ENOMEM;
+
+	state->dev = dev;
+	state->id = V4L2_IDENT_CX23888_IR;
+	state->rev = 0;
+	sd = &state->sd;
+
+	v4l2_subdev_init(sd, &cx23888_ir_controller_ops);
+	v4l2_set_subdevdata(sd, state);
+	/* FIXME - fix the formatting of dev->v4l2_dev.name and use it */
+	snprintf(sd->name, sizeof(sd->name), "%s/888-ir", dev->name);
+	sd->grp_id = CX23885_HW_888_IR;
+
+	ret = v4l2_device_register_subdev(&dev->v4l2_dev, sd);
+	if (ret == 0) {
+		/*
+		 * Ensure no interrupts arrive from '888 specific conditions,
+		 * since we ignore them in this driver to have commonality with
+		 * similar IR controller cores.
+		 */
+		cx23888_ir_write4(dev, CX23888_IR_IRQEN_REG, 0);
+
+		mutex_init(&state->rx_params_lock);
+		memcpy(&default_params, &default_rx_params,
+		       sizeof(struct v4l2_subdev_ir_parameters));
+		v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params);
+
+		mutex_init(&state->tx_params_lock);
+		memcpy(&default_params, &default_tx_params,
+		       sizeof(struct v4l2_subdev_ir_parameters));
+		v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params);
+	} else {
+		kfifo_free(&state->rx_kfifo);
+	}
+	return ret;
+}
+
+int cx23888_ir_remove(struct cx23885_dev *dev)
+{
+	struct v4l2_subdev *sd;
+	struct cx23888_ir_state *state;
+
+	sd = cx23885_find_hw(dev, CX23885_HW_888_IR);
+	if (sd == NULL)
+		return -ENODEV;
+
+	cx23888_ir_rx_shutdown(sd);
+	cx23888_ir_tx_shutdown(sd);
+
+	state = to_state(sd);
+	v4l2_device_unregister_subdev(sd);
+	kfifo_free(&state->rx_kfifo);
+	kfree(state);
+	/* Nothing more to free() as state held the actual v4l2_subdev object */
+	return 0;
+}
diff --git a/drivers/media/pci/cx23885/cx23888-ir.h b/drivers/media/pci/cx23885/cx23888-ir.h
new file mode 100644
index 0000000..d2de41c
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23888-ir.h
@@ -0,0 +1,28 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  CX23888 Integrated Consumer Infrared Controller
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@md.metrocast.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#ifndef _CX23888_IR_H_
+#define _CX23888_IR_H_
+int cx23888_ir_probe(struct cx23885_dev *dev);
+int cx23888_ir_remove(struct cx23885_dev *dev);
+#endif
diff --git a/drivers/media/pci/cx23885/netup-eeprom.c b/drivers/media/pci/cx23885/netup-eeprom.c
new file mode 100644
index 0000000..98a48f5
--- /dev/null
+++ b/drivers/media/pci/cx23885/netup-eeprom.c
@@ -0,0 +1,107 @@
+
+/*
+ * netup-eeprom.c
+ *
+ * 24LC02 EEPROM driver in conjunction with NetUP Dual DVB-S2 CI card
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#
+#include "cx23885.h"
+#include "netup-eeprom.h"
+
+#define EEPROM_I2C_ADDR 0x50
+
+int netup_eeprom_read(struct i2c_adapter *i2c_adap, u8 addr)
+{
+	int ret;
+	unsigned char buf[2];
+
+	/* Read from EEPROM */
+	struct i2c_msg msg[] = {
+		{
+			.addr	= EEPROM_I2C_ADDR,
+			.flags	= 0,
+			.buf	= &buf[0],
+			.len	= 1
+		}, {
+			.addr	= EEPROM_I2C_ADDR,
+			.flags	= I2C_M_RD,
+			.buf	= &buf[1],
+			.len	= 1
+		}
+
+	};
+
+	buf[0] = addr;
+	buf[1] = 0x0;
+
+	ret = i2c_transfer(i2c_adap, msg, 2);
+
+	if (ret != 2) {
+		printk(KERN_ERR "eeprom i2c read error, status=%d\n", ret);
+		return -1;
+	}
+
+	return buf[1];
+};
+
+int netup_eeprom_write(struct i2c_adapter *i2c_adap, u8 addr, u8 data)
+{
+	int ret;
+	unsigned char bufw[2];
+
+	/* Write into EEPROM */
+	struct i2c_msg msg[] = {
+		{
+			.addr	= EEPROM_I2C_ADDR,
+			.flags	= 0,
+			.buf	= &bufw[0],
+			.len	= 2
+		}
+	};
+
+	bufw[0] = addr;
+	bufw[1] = data;
+
+	ret = i2c_transfer(i2c_adap, msg, 1);
+
+	if (ret != 1) {
+		printk(KERN_ERR "eeprom i2c write error, status=%d\n", ret);
+		return -1;
+	}
+
+	mdelay(10); /* prophylactic delay, datasheet write cycle time = 5 ms */
+	return 0;
+};
+
+void netup_get_card_info(struct i2c_adapter *i2c_adap,
+				struct netup_card_info *cinfo)
+{
+	int i, j;
+
+	cinfo->rev =  netup_eeprom_read(i2c_adap, 63);
+
+	for (i = 64, j = 0; i < 70; i++, j++)
+		cinfo->port[0].mac[j] =  netup_eeprom_read(i2c_adap, i);
+
+	for (i = 70, j = 0; i < 76; i++, j++)
+		cinfo->port[1].mac[j] =  netup_eeprom_read(i2c_adap, i);
+};
diff --git a/drivers/media/pci/cx23885/netup-eeprom.h b/drivers/media/pci/cx23885/netup-eeprom.h
new file mode 100644
index 0000000..13926e1
--- /dev/null
+++ b/drivers/media/pci/cx23885/netup-eeprom.h
@@ -0,0 +1,42 @@
+/*
+ * netup-eeprom.h
+ *
+ * 24LC02 EEPROM driver in conjunction with NetUP Dual DVB-S2 CI card
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef NETUP_EEPROM_H
+#define NETUP_EEPROM_H
+
+struct netup_port_info {
+	u8 mac[6];/* card MAC address */
+};
+
+struct netup_card_info {
+	struct netup_port_info port[2];/* ports - 1,2 */
+	u8 rev;/* card revision */
+};
+
+extern int netup_eeprom_read(struct i2c_adapter *i2c_adap, u8 addr);
+extern int netup_eeprom_write(struct i2c_adapter *i2c_adap, u8 addr, u8 data);
+extern void netup_get_card_info(struct i2c_adapter *i2c_adap,
+				struct netup_card_info *cinfo);
+
+#endif
diff --git a/drivers/media/pci/cx23885/netup-init.c b/drivers/media/pci/cx23885/netup-init.c
new file mode 100644
index 0000000..f4893e6
--- /dev/null
+++ b/drivers/media/pci/cx23885/netup-init.c
@@ -0,0 +1,125 @@
+/*
+ * netup-init.c
+ *
+ * NetUP Dual DVB-S2 CI driver
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cx23885.h"
+
+static void i2c_av_write(struct i2c_adapter *i2c, u16 reg, u8 val)
+{
+	int ret;
+	u8 buf[3];
+	struct i2c_msg msg = {
+		.addr	= 0x88 >> 1,
+		.flags	= 0,
+		.buf	= buf,
+		.len	= 3
+	};
+
+	buf[0] = reg >> 8;
+	buf[1] = reg & 0xff;
+	buf[2] = val;
+
+	ret = i2c_transfer(i2c, &msg, 1);
+
+	if (ret != 1)
+		printk(KERN_ERR "%s: i2c write error!\n", __func__);
+}
+
+static void i2c_av_write4(struct i2c_adapter *i2c, u16 reg, u32 val)
+{
+	int ret;
+	u8 buf[6];
+	struct i2c_msg msg = {
+		.addr	= 0x88 >> 1,
+		.flags	= 0,
+		.buf	= buf,
+		.len	= 6
+	};
+
+	buf[0] = reg >> 8;
+	buf[1] = reg & 0xff;
+	buf[2] = val & 0xff;
+	buf[3] = (val >> 8) & 0xff;
+	buf[4] = (val >> 16) & 0xff;
+	buf[5] = val >> 24;
+
+	ret = i2c_transfer(i2c, &msg, 1);
+
+	if (ret != 1)
+		printk(KERN_ERR "%s: i2c write error!\n", __func__);
+}
+
+static u8 i2c_av_read(struct i2c_adapter *i2c, u16 reg)
+{
+	int ret;
+	u8 buf[2];
+	struct i2c_msg msg = {
+		.addr	= 0x88 >> 1,
+		.flags	= 0,
+		.buf	= buf,
+		.len	= 2
+	};
+
+	buf[0] = reg >> 8;
+	buf[1] = reg & 0xff;
+
+	ret = i2c_transfer(i2c, &msg, 1);
+
+	if (ret != 1)
+		printk(KERN_ERR "%s: i2c write error!\n", __func__);
+
+	msg.flags = I2C_M_RD;
+	msg.len = 1;
+
+	ret = i2c_transfer(i2c, &msg, 1);
+
+	if (ret != 1)
+		printk(KERN_ERR "%s: i2c read error!\n", __func__);
+
+	return buf[0];
+}
+
+static void i2c_av_and_or(struct i2c_adapter *i2c, u16 reg, unsigned and_mask,
+								u8 or_value)
+{
+	i2c_av_write(i2c, reg, (i2c_av_read(i2c, reg) & and_mask) | or_value);
+}
+/* set 27MHz on AUX_CLK */
+void netup_initialize(struct cx23885_dev *dev)
+{
+	struct cx23885_i2c *i2c_bus = &dev->i2c_bus[2];
+	struct i2c_adapter *i2c = &i2c_bus->i2c_adap;
+
+	/* Stop microcontroller */
+	i2c_av_and_or(i2c, 0x803, ~0x10, 0x00);
+
+	/* Aux PLL frac for 27 MHz */
+	i2c_av_write4(i2c, 0x114, 0xea0eb3);
+
+	/* Aux PLL int for 27 MHz */
+	i2c_av_write4(i2c, 0x110, 0x090319);
+
+	/* start microcontroller */
+	i2c_av_and_or(i2c, 0x803, ~0x10, 0x10);
+}
diff --git a/drivers/media/pci/cx23885/netup-init.h b/drivers/media/pci/cx23885/netup-init.h
new file mode 100644
index 0000000..d26ae4b
--- /dev/null
+++ b/drivers/media/pci/cx23885/netup-init.h
@@ -0,0 +1,25 @@
+/*
+ * netup-init.h
+ *
+ * NetUP Dual DVB-S2 CI driver
+ *
+ * Copyright (C) 2009 NetUP Inc.
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+extern void netup_initialize(struct cx23885_dev *dev);
diff --git a/drivers/media/pci/cx25821/Kconfig b/drivers/media/pci/cx25821/Kconfig
new file mode 100644
index 0000000..5f6b542
--- /dev/null
+++ b/drivers/media/pci/cx25821/Kconfig
@@ -0,0 +1,34 @@
+config VIDEO_CX25821
+	tristate "Conexant cx25821 support"
+	depends on DVB_CORE && VIDEO_DEV && PCI && I2C
+	select I2C_ALGOBIT
+	select VIDEO_BTCX
+	select VIDEO_TVEEPROM
+	depends on RC_CORE
+	select VIDEOBUF_DVB
+	select VIDEOBUF_DMA_SG
+	select VIDEO_CX25840
+	select VIDEO_CX2341X
+	---help---
+	  This is a video4linux driver for Conexant 25821 based
+	  TV cards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx25821
+
+config VIDEO_CX25821_ALSA
+	tristate "Conexant 25821 DMA audio support"
+	depends on VIDEO_CX25821 && SND && EXPERIMENTAL
+	select SND_PCM
+	---help---
+	  This is a video4linux driver for direct (DMA) audio on
+	  Conexant 25821 based capture cards using ALSA.
+
+	  It only works with boards with function 01 enabled.
+	  To check if your board supports, use lspci -n.
+	  If supported, you should see 14f1:8801 or 14f1:8811
+	  PCI device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx25821-alsa.
+
diff --git a/drivers/media/pci/cx25821/Makefile b/drivers/media/pci/cx25821/Makefile
new file mode 100644
index 0000000..5bf3ea4
--- /dev/null
+++ b/drivers/media/pci/cx25821/Makefile
@@ -0,0 +1,13 @@
+cx25821-y   := cx25821-core.o cx25821-cards.o cx25821-i2c.o \
+		       cx25821-gpio.o cx25821-medusa-video.o \
+		       cx25821-video.o cx25821-video-upstream.o \
+		       cx25821-video-upstream-ch2.o \
+		       cx25821-audio-upstream.o
+
+obj-$(CONFIG_VIDEO_CX25821) += cx25821.o
+obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o
+
+ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c
new file mode 100644
index 0000000..1858a45
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-alsa.c
@@ -0,0 +1,784 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
+ *	Based on SAA713x ALSA driver and CX88 driver
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, version 2
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "cx25821.h"
+#include "cx25821-reg.h"
+
+#define AUDIO_SRAM_CHANNEL	SRAM_CH08
+
+#define dprintk(level, fmt, arg...)				\
+do {								\
+	if (debug >= level)					\
+		pr_info("%s/1: " fmt, chip->dev->name, ##arg);	\
+} while (0)
+#define dprintk_core(level, fmt, arg...)				\
+do {									\
+	if (debug >= level)						\
+		printk(KERN_DEBUG "%s/1: " fmt, chip->dev->name, ##arg); \
+} while (0)
+
+/****************************************************************************
+	Data type declarations - Can be moded to a header file later
+ ****************************************************************************/
+
+static struct snd_card *snd_cx25821_cards[SNDRV_CARDS];
+static int devno;
+
+struct cx25821_audio_buffer {
+	unsigned int bpl;
+	struct btcx_riscmem risc;
+	struct videobuf_dmabuf dma;
+};
+
+struct cx25821_audio_dev {
+	struct cx25821_dev *dev;
+	struct cx25821_dmaqueue q;
+
+	/* pci i/o */
+	struct pci_dev *pci;
+
+	/* audio controls */
+	int irq;
+
+	struct snd_card *card;
+
+	unsigned long iobase;
+	spinlock_t reg_lock;
+	atomic_t count;
+
+	unsigned int dma_size;
+	unsigned int period_size;
+	unsigned int num_periods;
+
+	struct videobuf_dmabuf *dma_risc;
+
+	struct cx25821_audio_buffer *buf;
+
+	struct snd_pcm_substream *substream;
+};
+
+
+/****************************************************************************
+			Module global static vars
+ ****************************************************************************/
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
+static bool enable[SNDRV_CARDS] = { 1, [1 ... (SNDRV_CARDS - 1)] = 1 };
+
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable cx25821 soundcard. default enabled.");
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for cx25821 capture interface(s).");
+
+/****************************************************************************
+				Module macros
+ ****************************************************************************/
+
+MODULE_DESCRIPTION("ALSA driver module for cx25821 based capture cards");
+MODULE_AUTHOR("Hiep Huynh");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Conexant,25821}");	/* "{{Conexant,23881}," */
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+/****************************************************************************
+			Module specific funtions
+ ****************************************************************************/
+/* Constants taken from cx88-reg.h */
+#define AUD_INT_DN_RISCI1       (1 <<  0)
+#define AUD_INT_UP_RISCI1       (1 <<  1)
+#define AUD_INT_RDS_DN_RISCI1   (1 <<  2)
+#define AUD_INT_DN_RISCI2       (1 <<  4)	/* yes, 3 is skipped */
+#define AUD_INT_UP_RISCI2       (1 <<  5)
+#define AUD_INT_RDS_DN_RISCI2   (1 <<  6)
+#define AUD_INT_DN_SYNC         (1 << 12)
+#define AUD_INT_UP_SYNC         (1 << 13)
+#define AUD_INT_RDS_DN_SYNC     (1 << 14)
+#define AUD_INT_OPC_ERR         (1 << 16)
+#define AUD_INT_BER_IRQ         (1 << 20)
+#define AUD_INT_MCHG_IRQ        (1 << 21)
+#define GP_COUNT_CONTROL_RESET	0x3
+
+#define PCI_MSK_AUD_EXT   (1 <<  4)
+#define PCI_MSK_AUD_INT   (1 <<  3)
+/*
+ * BOARD Specific: Sets audio DMA
+ */
+
+static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip)
+{
+	struct cx25821_audio_buffer *buf = chip->buf;
+	struct cx25821_dev *dev = chip->dev;
+	struct sram_channel *audio_ch =
+	    &cx25821_sram_channels[AUDIO_SRAM_CHANNEL];
+	u32 tmp = 0;
+
+	/* enable output on the GPIO 0 for the MCLK ADC (Audio) */
+	cx25821_set_gpiopin_direction(chip->dev, 0, 0);
+
+	/* Make sure RISC/FIFO are off before changing FIFO/RISC settings */
+	cx_clear(AUD_INT_DMA_CTL,
+		 FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN);
+
+	/* setup fifo + format - out channel */
+	cx25821_sram_channel_setup_audio(chip->dev, audio_ch, buf->bpl,
+					 buf->risc.dma);
+
+	/* sets bpl size */
+	cx_write(AUD_A_LNGTH, buf->bpl);
+
+	/* reset counter */
+	/* GP_COUNT_CONTROL_RESET = 0x3 */
+	cx_write(AUD_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET);
+	atomic_set(&chip->count, 0);
+
+	/* Set the input mode to 16-bit */
+	tmp = cx_read(AUD_A_CFG);
+	cx_write(AUD_A_CFG, tmp | FLD_AUD_DST_PK_MODE | FLD_AUD_DST_ENABLE |
+		 FLD_AUD_CLK_ENABLE);
+
+	/*
+	pr_info("DEBUG: Start audio DMA, %d B/line, cmds_start(0x%x)= %d lines/FIFO, %d periods, %d byte buffer\n",
+		buf->bpl, audio_ch->cmds_start,
+		cx_read(audio_ch->cmds_start + 12)>>1,
+		chip->num_periods, buf->bpl * chip->num_periods);
+	*/
+
+	/* Enables corresponding bits at AUD_INT_STAT */
+	cx_write(AUD_A_INT_MSK, FLD_AUD_DST_RISCI1 | FLD_AUD_DST_OF |
+		 FLD_AUD_DST_SYNC | FLD_AUD_DST_OPC_ERR);
+
+	/* Clean any pending interrupt bits already set */
+	cx_write(AUD_A_INT_STAT, ~0);
+
+	/* enable audio irqs */
+	cx_set(PCI_INT_MSK, chip->dev->pci_irqmask | PCI_MSK_AUD_INT);
+
+	/* Turn on audio downstream fifo and risc enable 0x101 */
+	tmp = cx_read(AUD_INT_DMA_CTL);
+	cx_set(AUD_INT_DMA_CTL, tmp |
+	       (FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN));
+
+	mdelay(100);
+	return 0;
+}
+
+/*
+ * BOARD Specific: Resets audio DMA
+ */
+static int _cx25821_stop_audio_dma(struct cx25821_audio_dev *chip)
+{
+	struct cx25821_dev *dev = chip->dev;
+
+	/* stop dma */
+	cx_clear(AUD_INT_DMA_CTL,
+		 FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN);
+
+	/* disable irqs */
+	cx_clear(PCI_INT_MSK, PCI_MSK_AUD_INT);
+	cx_clear(AUD_A_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+		 AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
+
+	return 0;
+}
+
+#define MAX_IRQ_LOOP 50
+
+/*
+ * BOARD Specific: IRQ dma bits
+ */
+static char *cx25821_aud_irqs[32] = {
+	"dn_risci1", "up_risci1", "rds_dn_risc1",	/* 0-2 */
+	NULL,						/* reserved */
+	"dn_risci2", "up_risci2", "rds_dn_risc2",	/* 4-6 */
+	NULL,						/* reserved */
+	"dnf_of", "upf_uf", "rds_dnf_uf",		/* 8-10 */
+	NULL,						/* reserved */
+	"dn_sync", "up_sync", "rds_dn_sync",		/* 12-14 */
+	NULL,						/* reserved */
+	"opc_err", "par_err", "rip_err",		/* 16-18 */
+	"pci_abort", "ber_irq", "mchg_irq"		/* 19-21 */
+};
+
+/*
+ * BOARD Specific: Threats IRQ audio specific calls
+ */
+static void cx25821_aud_irq(struct cx25821_audio_dev *chip, u32 status,
+			    u32 mask)
+{
+	struct cx25821_dev *dev = chip->dev;
+
+	if (0 == (status & mask))
+		return;
+
+	cx_write(AUD_A_INT_STAT, status);
+	if (debug > 1 || (status & mask & ~0xff))
+		cx25821_print_irqbits(dev->name, "irq aud", cx25821_aud_irqs,
+				ARRAY_SIZE(cx25821_aud_irqs), status, mask);
+
+	/* risc op code error */
+	if (status & AUD_INT_OPC_ERR) {
+		pr_warn("WARNING %s/1: Audio risc op code error\n", dev->name);
+
+		cx_clear(AUD_INT_DMA_CTL,
+			 FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN);
+		cx25821_sram_channel_dump_audio(dev,
+				&cx25821_sram_channels[AUDIO_SRAM_CHANNEL]);
+	}
+	if (status & AUD_INT_DN_SYNC) {
+		pr_warn("WARNING %s: Downstream sync error!\n", dev->name);
+		cx_write(AUD_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET);
+		return;
+	}
+
+	/* risc1 downstream */
+	if (status & AUD_INT_DN_RISCI1) {
+		atomic_set(&chip->count, cx_read(AUD_A_GPCNT));
+		snd_pcm_period_elapsed(chip->substream);
+	}
+}
+
+/*
+ * BOARD Specific: Handles IRQ calls
+ */
+static irqreturn_t cx25821_irq(int irq, void *dev_id)
+{
+	struct cx25821_audio_dev *chip = dev_id;
+	struct cx25821_dev *dev = chip->dev;
+	u32 status, pci_status;
+	u32 audint_status, audint_mask;
+	int loop, handled = 0;
+
+	audint_status = cx_read(AUD_A_INT_STAT);
+	audint_mask = cx_read(AUD_A_INT_MSK);
+	status = cx_read(PCI_INT_STAT);
+
+	for (loop = 0; loop < 1; loop++) {
+		status = cx_read(PCI_INT_STAT);
+		if (0 == status) {
+			status = cx_read(PCI_INT_STAT);
+			audint_status = cx_read(AUD_A_INT_STAT);
+			audint_mask = cx_read(AUD_A_INT_MSK);
+
+			if (status) {
+				handled = 1;
+				cx_write(PCI_INT_STAT, status);
+
+				cx25821_aud_irq(chip, audint_status,
+						audint_mask);
+				break;
+			} else {
+				goto out;
+			}
+		}
+
+		handled = 1;
+		cx_write(PCI_INT_STAT, status);
+
+		cx25821_aud_irq(chip, audint_status, audint_mask);
+	}
+
+	pci_status = cx_read(PCI_INT_STAT);
+
+	if (handled)
+		cx_write(PCI_INT_STAT, pci_status);
+
+out:
+	return IRQ_RETVAL(handled);
+}
+
+static int dsp_buffer_free(struct cx25821_audio_dev *chip)
+{
+	BUG_ON(!chip->dma_size);
+
+	dprintk(2, "Freeing buffer\n");
+	videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc);
+	videobuf_dma_free(chip->dma_risc);
+	btcx_riscmem_free(chip->pci, &chip->buf->risc);
+	kfree(chip->buf);
+
+	chip->dma_risc = NULL;
+	chip->dma_size = 0;
+
+	return 0;
+}
+
+/****************************************************************************
+				ALSA PCM Interface
+ ****************************************************************************/
+
+/*
+ * Digital hardware definition
+ */
+#define DEFAULT_FIFO_SIZE	384
+static struct snd_pcm_hardware snd_cx25821_digital_hw = {
+	.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+	.rates = SNDRV_PCM_RATE_48000,
+	.rate_min = 48000,
+	.rate_max = 48000,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* Analog audio output will be full of clicks and pops if there
+	   are not exactly four lines in the SRAM FIFO buffer.  */
+	.period_bytes_min = DEFAULT_FIFO_SIZE / 3,
+	.period_bytes_max = DEFAULT_FIFO_SIZE / 3,
+	.periods_min = 1,
+	.periods_max = AUDIO_LINE_SIZE,
+	/* 128 * 128 = 16384 = 1024 * 16 */
+	.buffer_bytes_max = (AUDIO_LINE_SIZE * AUDIO_LINE_SIZE),
+};
+
+/*
+ * audio pcm capture open callback
+ */
+static int snd_cx25821_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int err;
+	unsigned int bpl = 0;
+
+	if (!chip) {
+		pr_err("DEBUG: cx25821 can't find device struct. Can't proceed with open\n");
+		return -ENODEV;
+	}
+
+	err = snd_pcm_hw_constraint_pow2(runtime, 0,
+					 SNDRV_PCM_HW_PARAM_PERIODS);
+	if (err < 0)
+		goto _error;
+
+	chip->substream = substream;
+
+	runtime->hw = snd_cx25821_digital_hw;
+
+	if (cx25821_sram_channels[AUDIO_SRAM_CHANNEL].fifo_size !=
+	    DEFAULT_FIFO_SIZE) {
+		/* since there are 3 audio Clusters */
+		bpl = cx25821_sram_channels[AUDIO_SRAM_CHANNEL].fifo_size / 3;
+		bpl &= ~7;	/* must be multiple of 8 */
+
+		if (bpl > AUDIO_LINE_SIZE)
+			bpl = AUDIO_LINE_SIZE;
+
+		runtime->hw.period_bytes_min = bpl;
+		runtime->hw.period_bytes_max = bpl;
+	}
+
+	return 0;
+_error:
+	dprintk(1, "Error opening PCM!\n");
+	return err;
+}
+
+/*
+ * audio close callback
+ */
+static int snd_cx25821_close(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+/*
+ * hw_params callback
+ */
+static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *hw_params)
+{
+	struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream);
+	struct videobuf_dmabuf *dma;
+
+	struct cx25821_audio_buffer *buf;
+	int ret;
+
+	if (substream->runtime->dma_area) {
+		dsp_buffer_free(chip);
+		substream->runtime->dma_area = NULL;
+	}
+
+	chip->period_size = params_period_bytes(hw_params);
+	chip->num_periods = params_periods(hw_params);
+	chip->dma_size = chip->period_size * params_periods(hw_params);
+
+	BUG_ON(!chip->dma_size);
+	BUG_ON(chip->num_periods & (chip->num_periods - 1));
+
+	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+	if (NULL == buf)
+		return -ENOMEM;
+
+	if (chip->period_size > AUDIO_LINE_SIZE)
+		chip->period_size = AUDIO_LINE_SIZE;
+
+	buf->bpl = chip->period_size;
+
+	dma = &buf->dma;
+	videobuf_dma_init(dma);
+	ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
+			(PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
+	if (ret < 0)
+		goto error;
+
+	ret = videobuf_dma_map(&chip->pci->dev, dma);
+	if (ret < 0)
+		goto error;
+
+	ret = cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist,
+			chip->period_size, chip->num_periods, 1);
+	if (ret < 0) {
+		pr_info("DEBUG: ERROR after cx25821_risc_databuffer_audio()\n");
+		goto error;
+	}
+
+	/* Loop back to start of program */
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+	buf->risc.jmp[2] = cpu_to_le32(0);	/* bits 63-32 */
+
+	chip->buf = buf;
+	chip->dma_risc = dma;
+
+	substream->runtime->dma_area = chip->dma_risc->vaddr;
+	substream->runtime->dma_bytes = chip->dma_size;
+	substream->runtime->dma_addr = 0;
+
+	return 0;
+
+error:
+	kfree(buf);
+	return ret;
+}
+
+/*
+ * hw free callback
+ */
+static int snd_cx25821_hw_free(struct snd_pcm_substream *substream)
+{
+	struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream);
+
+	if (substream->runtime->dma_area) {
+		dsp_buffer_free(chip);
+		substream->runtime->dma_area = NULL;
+	}
+
+	return 0;
+}
+
+/*
+ * prepare callback
+ */
+static int snd_cx25821_prepare(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+/*
+ * trigger callback
+ */
+static int snd_cx25821_card_trigger(struct snd_pcm_substream *substream,
+				    int cmd)
+{
+	struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream);
+	int err = 0;
+
+	/* Local interrupts are already disabled by ALSA */
+	spin_lock(&chip->reg_lock);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		err = _cx25821_start_audio_dma(chip);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		err = _cx25821_stop_audio_dma(chip);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	spin_unlock(&chip->reg_lock);
+
+	return err;
+}
+
+/*
+ * pointer callback
+ */
+static snd_pcm_uframes_t snd_cx25821_pointer(struct snd_pcm_substream
+					     *substream)
+{
+	struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	u16 count;
+
+	count = atomic_read(&chip->count);
+
+	return runtime->period_size * (count & (runtime->periods - 1));
+}
+
+/*
+ * page callback (needed for mmap)
+ */
+static struct page *snd_cx25821_page(struct snd_pcm_substream *substream,
+				     unsigned long offset)
+{
+	void *pageptr = substream->runtime->dma_area + offset;
+
+	return vmalloc_to_page(pageptr);
+}
+
+/*
+ * operators
+ */
+static struct snd_pcm_ops snd_cx25821_pcm_ops = {
+	.open = snd_cx25821_pcm_open,
+	.close = snd_cx25821_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_cx25821_hw_params,
+	.hw_free = snd_cx25821_hw_free,
+	.prepare = snd_cx25821_prepare,
+	.trigger = snd_cx25821_card_trigger,
+	.pointer = snd_cx25821_pointer,
+	.page = snd_cx25821_page,
+};
+
+/*
+ * ALSA create a PCM device:  Called when initializing the board.
+ * Sets up the name and hooks up the callbacks
+ */
+static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device,
+			   char *name)
+{
+	struct snd_pcm *pcm;
+	int err;
+
+	err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
+	if (err < 0) {
+		pr_info("ERROR: FAILED snd_pcm_new() in %s\n", __func__);
+		return err;
+	}
+	pcm->private_data = chip;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, name);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx25821_pcm_ops);
+
+	return 0;
+}
+
+/****************************************************************************
+			Basic Flow for Sound Devices
+ ****************************************************************************/
+
+/*
+ * PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio
+ * Only boards with eeprom and byte 1 at eeprom=1 have it
+ */
+
+static DEFINE_PCI_DEVICE_TABLE(cx25821_audio_pci_tbl) = {
+	{0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci, cx25821_audio_pci_tbl);
+
+/*
+ * Not used in the function snd_cx25821_dev_free so removing
+ * from the file.
+ */
+/*
+static int snd_cx25821_free(struct cx25821_audio_dev *chip)
+{
+	if (chip->irq >= 0)
+		free_irq(chip->irq, chip);
+
+	cx25821_dev_unregister(chip->dev);
+	pci_disable_device(chip->pci);
+
+	return 0;
+}
+*/
+
+/*
+ * Component Destructor
+ */
+static void snd_cx25821_dev_free(struct snd_card *card)
+{
+	struct cx25821_audio_dev *chip = card->private_data;
+
+	/* snd_cx25821_free(chip); */
+	snd_card_free(chip->card);
+}
+
+/*
+ * Alsa Constructor - Component probe
+ */
+static int cx25821_audio_initdev(struct cx25821_dev *dev)
+{
+	struct snd_card *card;
+	struct cx25821_audio_dev *chip;
+	int err;
+
+	if (devno >= SNDRV_CARDS) {
+		pr_info("DEBUG ERROR: devno >= SNDRV_CARDS %s\n", __func__);
+		return -ENODEV;
+	}
+
+	if (!enable[devno]) {
+		++devno;
+		pr_info("DEBUG ERROR: !enable[devno] %s\n", __func__);
+		return -ENOENT;
+	}
+
+	err = snd_card_create(index[devno], id[devno], THIS_MODULE,
+			sizeof(struct cx25821_audio_dev), &card);
+	if (err < 0) {
+		pr_info("DEBUG ERROR: cannot create snd_card_new in %s\n",
+			__func__);
+		return err;
+	}
+
+	strcpy(card->driver, "cx25821");
+
+	/* Card "creation" */
+	card->private_free = snd_cx25821_dev_free;
+	chip = card->private_data;
+	spin_lock_init(&chip->reg_lock);
+
+	chip->dev = dev;
+	chip->card = card;
+	chip->pci = dev->pci;
+	chip->iobase = pci_resource_start(dev->pci, 0);
+
+	chip->irq = dev->pci->irq;
+
+	err = request_irq(dev->pci->irq, cx25821_irq,
+			  IRQF_SHARED, chip->dev->name, chip);
+
+	if (err < 0) {
+		pr_err("ERROR %s: can't get IRQ %d for ALSA\n", chip->dev->name,
+			dev->pci->irq);
+		goto error;
+	}
+
+	err = snd_cx25821_pcm(chip, 0, "cx25821 Digital");
+	if (err < 0) {
+		pr_info("DEBUG ERROR: cannot create snd_cx25821_pcm %s\n",
+			__func__);
+		goto error;
+	}
+
+	snd_card_set_dev(card, &chip->pci->dev);
+
+	strcpy(card->shortname, "cx25821");
+	sprintf(card->longname, "%s at 0x%lx irq %d", chip->dev->name,
+		chip->iobase, chip->irq);
+	strcpy(card->mixername, "CX25821");
+
+	pr_info("%s/%i: ALSA support for cx25821 boards\n", card->driver,
+		devno);
+
+	err = snd_card_register(card);
+	if (err < 0) {
+		pr_info("DEBUG ERROR: cannot register sound card %s\n",
+			__func__);
+		goto error;
+	}
+
+	snd_cx25821_cards[devno] = card;
+
+	devno++;
+	return 0;
+
+error:
+	snd_card_free(card);
+	return err;
+}
+
+/****************************************************************************
+				LINUX MODULE INIT
+ ****************************************************************************/
+static void cx25821_audio_fini(void)
+{
+	snd_card_free(snd_cx25821_cards[0]);
+}
+
+/*
+ * Module initializer
+ *
+ * Loops through present saa7134 cards, and assigns an ALSA device
+ * to each one
+ *
+ */
+static int cx25821_alsa_init(void)
+{
+	struct cx25821_dev *dev = NULL;
+	struct list_head *list;
+
+	mutex_lock(&cx25821_devlist_mutex);
+	list_for_each(list, &cx25821_devlist) {
+		dev = list_entry(list, struct cx25821_dev, devlist);
+		cx25821_audio_initdev(dev);
+	}
+	mutex_unlock(&cx25821_devlist_mutex);
+
+	if (dev == NULL)
+		pr_info("ERROR ALSA: no cx25821 cards found\n");
+
+	return 0;
+
+}
+
+late_initcall(cx25821_alsa_init);
+module_exit(cx25821_audio_fini);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/cx25821/cx25821-audio-upstream.c b/drivers/media/pci/cx25821/cx25821-audio-upstream.c
new file mode 100644
index 0000000..8b2a999
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-audio-upstream.c
@@ -0,0 +1,778 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <hiep.huynh@conexant.com>, <shu.lin@conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "cx25821-video.h"
+#include "cx25821-audio-upstream.h"
+
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/file.h>
+#include <linux/fcntl.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
+MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
+MODULE_LICENSE("GPL");
+
+static int _intr_msk = FLD_AUD_SRC_RISCI1 | FLD_AUD_SRC_OF |
+			FLD_AUD_SRC_SYNC | FLD_AUD_SRC_OPC_ERR;
+
+int cx25821_sram_channel_setup_upstream_audio(struct cx25821_dev *dev,
+					      struct sram_channel *ch,
+					      unsigned int bpl, u32 risc)
+{
+	unsigned int i, lines;
+	u32 cdt;
+
+	if (ch->cmds_start == 0) {
+		cx_write(ch->ptr1_reg, 0);
+		cx_write(ch->ptr2_reg, 0);
+		cx_write(ch->cnt2_reg, 0);
+		cx_write(ch->cnt1_reg, 0);
+		return 0;
+	}
+
+	bpl = (bpl + 7) & ~7;	/* alignment */
+	cdt = ch->cdt;
+	lines = ch->fifo_size / bpl;
+
+	if (lines > 3)
+		lines = 3;
+
+	BUG_ON(lines < 2);
+
+	/* write CDT */
+	for (i = 0; i < lines; i++) {
+		cx_write(cdt + 16 * i, ch->fifo_start + bpl * i);
+		cx_write(cdt + 16 * i + 4, 0);
+		cx_write(cdt + 16 * i + 8, 0);
+		cx_write(cdt + 16 * i + 12, 0);
+	}
+
+	/* write CMDS */
+	cx_write(ch->cmds_start + 0, risc);
+
+	cx_write(ch->cmds_start + 4, 0);
+	cx_write(ch->cmds_start + 8, cdt);
+	cx_write(ch->cmds_start + 12, AUDIO_CDT_SIZE_QW);
+	cx_write(ch->cmds_start + 16, ch->ctrl_start);
+
+	/* IQ size */
+	cx_write(ch->cmds_start + 20, AUDIO_IQ_SIZE_DW);
+
+	for (i = 24; i < 80; i += 4)
+		cx_write(ch->cmds_start + i, 0);
+
+	/* fill registers */
+	cx_write(ch->ptr1_reg, ch->fifo_start);
+	cx_write(ch->ptr2_reg, cdt);
+	cx_write(ch->cnt2_reg, AUDIO_CDT_SIZE_QW);
+	cx_write(ch->cnt1_reg, AUDIO_CLUSTER_SIZE_QW - 1);
+
+	return 0;
+}
+
+static __le32 *cx25821_risc_field_upstream_audio(struct cx25821_dev *dev,
+						 __le32 *rp,
+						 dma_addr_t databuf_phys_addr,
+						 unsigned int bpl,
+						 int fifo_enable)
+{
+	unsigned int line;
+	struct sram_channel *sram_ch =
+		dev->channels[dev->_audio_upstream_channel].sram_channels;
+	int offset = 0;
+
+	/* scan lines */
+	for (line = 0; line < LINES_PER_AUDIO_BUFFER; line++) {
+		*(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl);
+		*(rp++) = cpu_to_le32(databuf_phys_addr + offset);
+		*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
+
+		/* Check if we need to enable the FIFO
+		 * after the first 3 lines.
+		 * For the upstream audio channel,
+		 * the risc engine will enable the FIFO */
+		if (fifo_enable && line == 2) {
+			*(rp++) = RISC_WRITECR;
+			*(rp++) = sram_ch->dma_ctl;
+			*(rp++) = sram_ch->fld_aud_fifo_en;
+			*(rp++) = 0x00000020;
+		}
+
+		offset += AUDIO_LINE_SIZE;
+	}
+
+	return rp;
+}
+
+int cx25821_risc_buffer_upstream_audio(struct cx25821_dev *dev,
+				       struct pci_dev *pci,
+				       unsigned int bpl, unsigned int lines)
+{
+	__le32 *rp;
+	int fifo_enable = 0;
+	int frame = 0, i = 0;
+	int frame_size = AUDIO_DATA_BUF_SZ;
+	int databuf_offset = 0;
+	int risc_flag = RISC_CNT_INC;
+	dma_addr_t risc_phys_jump_addr;
+
+	/* Virtual address of Risc buffer program */
+	rp = dev->_risc_virt_addr;
+
+	/* sync instruction */
+	*(rp++) = cpu_to_le32(RISC_RESYNC | AUDIO_SYNC_LINE);
+
+	for (frame = 0; frame < NUM_AUDIO_FRAMES; frame++) {
+		databuf_offset = frame_size * frame;
+
+		if (frame == 0) {
+			fifo_enable = 1;
+			risc_flag = RISC_CNT_RESET;
+		} else {
+			fifo_enable = 0;
+			risc_flag = RISC_CNT_INC;
+		}
+
+		/* Calculate physical jump address */
+		if ((frame + 1) == NUM_AUDIO_FRAMES) {
+			risc_phys_jump_addr =
+			    dev->_risc_phys_start_addr +
+			    RISC_SYNC_INSTRUCTION_SIZE;
+		} else {
+			risc_phys_jump_addr =
+			    dev->_risc_phys_start_addr +
+			    RISC_SYNC_INSTRUCTION_SIZE +
+			    AUDIO_RISC_DMA_BUF_SIZE * (frame + 1);
+		}
+
+		rp = cx25821_risc_field_upstream_audio(dev, rp,
+				dev->_audiodata_buf_phys_addr + databuf_offset,
+				bpl, fifo_enable);
+
+		if (USE_RISC_NOOP_AUDIO) {
+			for (i = 0; i < NUM_NO_OPS; i++)
+				*(rp++) = cpu_to_le32(RISC_NOOP);
+		}
+
+		/* Loop to (Nth)FrameRISC or to Start of Risc program &
+		 * generate IRQ */
+		*(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag);
+		*(rp++) = cpu_to_le32(risc_phys_jump_addr);
+		*(rp++) = cpu_to_le32(0);
+
+		/* Recalculate virtual address based on frame index */
+		rp = dev->_risc_virt_addr + RISC_SYNC_INSTRUCTION_SIZE / 4 +
+			(AUDIO_RISC_DMA_BUF_SIZE * (frame + 1) / 4);
+	}
+
+	return 0;
+}
+
+void cx25821_free_memory_audio(struct cx25821_dev *dev)
+{
+	if (dev->_risc_virt_addr) {
+		pci_free_consistent(dev->pci, dev->_audiorisc_size,
+				    dev->_risc_virt_addr, dev->_risc_phys_addr);
+		dev->_risc_virt_addr = NULL;
+	}
+
+	if (dev->_audiodata_buf_virt_addr) {
+		pci_free_consistent(dev->pci, dev->_audiodata_buf_size,
+				    dev->_audiodata_buf_virt_addr,
+				    dev->_audiodata_buf_phys_addr);
+		dev->_audiodata_buf_virt_addr = NULL;
+	}
+}
+
+void cx25821_stop_upstream_audio(struct cx25821_dev *dev)
+{
+	struct sram_channel *sram_ch =
+		dev->channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B].sram_channels;
+	u32 tmp = 0;
+
+	if (!dev->_audio_is_running) {
+		printk(KERN_DEBUG
+		       pr_fmt("No audio file is currently running so return!\n"));
+		return;
+	}
+	/* Disable RISC interrupts */
+	cx_write(sram_ch->int_msk, 0);
+
+	/* Turn OFF risc and fifo enable in AUD_DMA_CNTRL */
+	tmp = cx_read(sram_ch->dma_ctl);
+	cx_write(sram_ch->dma_ctl,
+		 tmp & ~(sram_ch->fld_aud_fifo_en | sram_ch->fld_aud_risc_en));
+
+	/* Clear data buffer memory */
+	if (dev->_audiodata_buf_virt_addr)
+		memset(dev->_audiodata_buf_virt_addr, 0,
+		       dev->_audiodata_buf_size);
+
+	dev->_audio_is_running = 0;
+	dev->_is_first_audio_frame = 0;
+	dev->_audioframe_count = 0;
+	dev->_audiofile_status = END_OF_FILE;
+
+	kfree(dev->_irq_audio_queues);
+	dev->_irq_audio_queues = NULL;
+
+	kfree(dev->_audiofilename);
+}
+
+void cx25821_free_mem_upstream_audio(struct cx25821_dev *dev)
+{
+	if (dev->_audio_is_running)
+		cx25821_stop_upstream_audio(dev);
+
+	cx25821_free_memory_audio(dev);
+}
+
+int cx25821_get_audio_data(struct cx25821_dev *dev,
+			   struct sram_channel *sram_ch)
+{
+	struct file *myfile;
+	int frame_index_temp = dev->_audioframe_index;
+	int i = 0;
+	int line_size = AUDIO_LINE_SIZE;
+	int frame_size = AUDIO_DATA_BUF_SZ;
+	int frame_offset = frame_size * frame_index_temp;
+	ssize_t vfs_read_retval = 0;
+	char mybuf[line_size];
+	loff_t file_offset = dev->_audioframe_count * frame_size;
+	loff_t pos;
+	mm_segment_t old_fs;
+
+	if (dev->_audiofile_status == END_OF_FILE)
+		return 0;
+
+	myfile = filp_open(dev->_audiofilename, O_RDONLY | O_LARGEFILE, 0);
+
+	if (IS_ERR(myfile)) {
+		const int open_errno = -PTR_ERR(myfile);
+		pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
+		       __func__, dev->_audiofilename, open_errno);
+		return PTR_ERR(myfile);
+	} else {
+		if (!(myfile->f_op)) {
+			pr_err("%s(): File has no file operations registered!\n",
+				__func__);
+			filp_close(myfile, NULL);
+			return -EIO;
+		}
+
+		if (!myfile->f_op->read) {
+			pr_err("%s(): File has no READ operations registered!\n",
+				__func__);
+			filp_close(myfile, NULL);
+			return -EIO;
+		}
+
+		pos = myfile->f_pos;
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+
+		for (i = 0; i < dev->_audio_lines_count; i++) {
+			pos = file_offset;
+
+			vfs_read_retval = vfs_read(myfile, mybuf, line_size,
+									&pos);
+
+			if (vfs_read_retval > 0 && vfs_read_retval == line_size
+			    && dev->_audiodata_buf_virt_addr != NULL) {
+				memcpy((void *)(dev->_audiodata_buf_virt_addr +
+						frame_offset / 4), mybuf,
+					vfs_read_retval);
+			}
+
+			file_offset += vfs_read_retval;
+			frame_offset += vfs_read_retval;
+
+			if (vfs_read_retval < line_size) {
+				pr_info("Done: exit %s() since no more bytes to read from Audio file\n",
+					__func__);
+				break;
+			}
+		}
+
+		if (i > 0)
+			dev->_audioframe_count++;
+
+		dev->_audiofile_status = (vfs_read_retval == line_size) ?
+						IN_PROGRESS : END_OF_FILE;
+
+		set_fs(old_fs);
+		filp_close(myfile, NULL);
+	}
+
+	return 0;
+}
+
+static void cx25821_audioups_handler(struct work_struct *work)
+{
+	struct cx25821_dev *dev = container_of(work, struct cx25821_dev,
+			_audio_work_entry);
+
+	if (!dev) {
+		pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n",
+			__func__);
+		return;
+	}
+
+	cx25821_get_audio_data(dev, dev->channels[dev->_audio_upstream_channel].
+			sram_channels);
+}
+
+int cx25821_openfile_audio(struct cx25821_dev *dev,
+			   struct sram_channel *sram_ch)
+{
+	struct file *myfile;
+	int i = 0, j = 0;
+	int line_size = AUDIO_LINE_SIZE;
+	ssize_t vfs_read_retval = 0;
+	char mybuf[line_size];
+	loff_t pos;
+	loff_t offset = (unsigned long)0;
+	mm_segment_t old_fs;
+
+	myfile = filp_open(dev->_audiofilename, O_RDONLY | O_LARGEFILE, 0);
+
+	if (IS_ERR(myfile)) {
+		const int open_errno = -PTR_ERR(myfile);
+		pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
+			__func__, dev->_audiofilename, open_errno);
+		return PTR_ERR(myfile);
+	} else {
+		if (!(myfile->f_op)) {
+			pr_err("%s(): File has no file operations registered!\n",
+				__func__);
+			filp_close(myfile, NULL);
+			return -EIO;
+		}
+
+		if (!myfile->f_op->read) {
+			pr_err("%s(): File has no READ operations registered!\n",
+				__func__);
+			filp_close(myfile, NULL);
+			return -EIO;
+		}
+
+		pos = myfile->f_pos;
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+
+		for (j = 0; j < NUM_AUDIO_FRAMES; j++) {
+			for (i = 0; i < dev->_audio_lines_count; i++) {
+				pos = offset;
+
+				vfs_read_retval = vfs_read(myfile, mybuf,
+						line_size, &pos);
+
+				if (vfs_read_retval > 0 &&
+				    vfs_read_retval == line_size &&
+				    dev->_audiodata_buf_virt_addr != NULL) {
+					memcpy((void *)(dev->
+							_audiodata_buf_virt_addr
+							+ offset / 4), mybuf,
+					       vfs_read_retval);
+				}
+
+				offset += vfs_read_retval;
+
+				if (vfs_read_retval < line_size) {
+					pr_info("Done: exit %s() since no more bytes to read from Audio file\n",
+						__func__);
+					break;
+				}
+			}
+
+			if (i > 0)
+				dev->_audioframe_count++;
+
+			if (vfs_read_retval < line_size)
+				break;
+		}
+
+		dev->_audiofile_status = (vfs_read_retval == line_size) ?
+						IN_PROGRESS : END_OF_FILE;
+
+		set_fs(old_fs);
+		myfile->f_pos = 0;
+		filp_close(myfile, NULL);
+	}
+
+	return 0;
+}
+
+static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev,
+						 struct sram_channel *sram_ch,
+						 int bpl)
+{
+	int ret = 0;
+	dma_addr_t dma_addr;
+	dma_addr_t data_dma_addr;
+
+	cx25821_free_memory_audio(dev);
+
+	dev->_risc_virt_addr = pci_alloc_consistent(dev->pci,
+			dev->audio_upstream_riscbuf_size, &dma_addr);
+	dev->_risc_virt_start_addr = dev->_risc_virt_addr;
+	dev->_risc_phys_start_addr = dma_addr;
+	dev->_risc_phys_addr = dma_addr;
+	dev->_audiorisc_size = dev->audio_upstream_riscbuf_size;
+
+	if (!dev->_risc_virt_addr) {
+		printk(KERN_DEBUG
+			pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for RISC program! Returning\n"));
+		return -ENOMEM;
+	}
+	/* Clear out memory at address */
+	memset(dev->_risc_virt_addr, 0, dev->_audiorisc_size);
+
+	/* For Audio Data buffer allocation */
+	dev->_audiodata_buf_virt_addr = pci_alloc_consistent(dev->pci,
+			dev->audio_upstream_databuf_size, &data_dma_addr);
+	dev->_audiodata_buf_phys_addr = data_dma_addr;
+	dev->_audiodata_buf_size = dev->audio_upstream_databuf_size;
+
+	if (!dev->_audiodata_buf_virt_addr) {
+		printk(KERN_DEBUG
+			pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for data buffer! Returning\n"));
+		return -ENOMEM;
+	}
+	/* Clear out memory at address */
+	memset(dev->_audiodata_buf_virt_addr, 0, dev->_audiodata_buf_size);
+
+	ret = cx25821_openfile_audio(dev, sram_ch);
+	if (ret < 0)
+		return ret;
+
+	/* Creating RISC programs */
+	ret = cx25821_risc_buffer_upstream_audio(dev, dev->pci, bpl,
+						dev->_audio_lines_count);
+	if (ret < 0) {
+		printk(KERN_DEBUG
+			pr_fmt("ERROR creating audio upstream RISC programs!\n"));
+		goto error;
+	}
+
+	return 0;
+
+error:
+	return ret;
+}
+
+int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num,
+			       u32 status)
+{
+	int i = 0;
+	u32 int_msk_tmp;
+	struct sram_channel *channel = dev->channels[chan_num].sram_channels;
+	dma_addr_t risc_phys_jump_addr;
+	__le32 *rp;
+
+	if (status & FLD_AUD_SRC_RISCI1) {
+		/* Get interrupt_index of the program that interrupted */
+		u32 prog_cnt = cx_read(channel->gpcnt);
+
+		/* Since we've identified our IRQ, clear our bits from the
+		 * interrupt mask and interrupt status registers */
+		cx_write(channel->int_msk, 0);
+		cx_write(channel->int_stat, cx_read(channel->int_stat));
+
+		spin_lock(&dev->slock);
+
+		while (prog_cnt != dev->_last_index_irq) {
+			/* Update _last_index_irq */
+			if (dev->_last_index_irq < (NUMBER_OF_PROGRAMS - 1))
+				dev->_last_index_irq++;
+			else
+				dev->_last_index_irq = 0;
+
+			dev->_audioframe_index = dev->_last_index_irq;
+
+			queue_work(dev->_irq_audio_queues,
+				   &dev->_audio_work_entry);
+		}
+
+		if (dev->_is_first_audio_frame) {
+			dev->_is_first_audio_frame = 0;
+
+			if (dev->_risc_virt_start_addr != NULL) {
+				risc_phys_jump_addr =
+					dev->_risc_phys_start_addr +
+					RISC_SYNC_INSTRUCTION_SIZE +
+					AUDIO_RISC_DMA_BUF_SIZE;
+
+				rp = cx25821_risc_field_upstream_audio(dev,
+						dev->_risc_virt_start_addr + 1,
+						dev->_audiodata_buf_phys_addr,
+						AUDIO_LINE_SIZE, FIFO_DISABLE);
+
+				if (USE_RISC_NOOP_AUDIO) {
+					for (i = 0; i < NUM_NO_OPS; i++) {
+						*(rp++) =
+						    cpu_to_le32(RISC_NOOP);
+					}
+				}
+				/* Jump to 2nd Audio Frame */
+				*(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 |
+						RISC_CNT_RESET);
+				*(rp++) = cpu_to_le32(risc_phys_jump_addr);
+				*(rp++) = cpu_to_le32(0);
+			}
+		}
+
+		spin_unlock(&dev->slock);
+	} else {
+		if (status & FLD_AUD_SRC_OF)
+			pr_warn("%s(): Audio Received Overflow Error Interrupt!\n",
+				__func__);
+
+		if (status & FLD_AUD_SRC_SYNC)
+			pr_warn("%s(): Audio Received Sync Error Interrupt!\n",
+				__func__);
+
+		if (status & FLD_AUD_SRC_OPC_ERR)
+			pr_warn("%s(): Audio Received OpCode Error Interrupt!\n",
+				__func__);
+
+		/* Read and write back the interrupt status register to clear
+		 * our bits */
+		cx_write(channel->int_stat, cx_read(channel->int_stat));
+	}
+
+	if (dev->_audiofile_status == END_OF_FILE) {
+		pr_warn("EOF Channel Audio Framecount = %d\n",
+			dev->_audioframe_count);
+		return -1;
+	}
+	/* ElSE, set the interrupt mask register, re-enable irq. */
+	int_msk_tmp = cx_read(channel->int_msk);
+	cx_write(channel->int_msk, int_msk_tmp |= _intr_msk);
+
+	return 0;
+}
+
+static irqreturn_t cx25821_upstream_irq_audio(int irq, void *dev_id)
+{
+	struct cx25821_dev *dev = dev_id;
+	u32 audio_status;
+	int handled = 0;
+	struct sram_channel *sram_ch;
+
+	if (!dev)
+		return -1;
+
+	sram_ch = dev->channels[dev->_audio_upstream_channel].sram_channels;
+
+	audio_status = cx_read(sram_ch->int_stat);
+
+	/* Only deal with our interrupt */
+	if (audio_status) {
+		handled = cx25821_audio_upstream_irq(dev,
+				dev->_audio_upstream_channel, audio_status);
+	}
+
+	if (handled < 0)
+		cx25821_stop_upstream_audio(dev);
+	else
+		handled += handled;
+
+	return IRQ_RETVAL(handled);
+}
+
+static void cx25821_wait_fifo_enable(struct cx25821_dev *dev,
+				     struct sram_channel *sram_ch)
+{
+	int count = 0;
+	u32 tmp;
+
+	do {
+		/* Wait 10 microsecond before checking to see if the FIFO is
+		 * turned ON. */
+		udelay(10);
+
+		tmp = cx_read(sram_ch->dma_ctl);
+
+		/* 10 millisecond timeout */
+		if (count++ > 1000) {
+			pr_err("ERROR: %s() fifo is NOT turned on. Timeout!\n",
+				__func__);
+			return;
+		}
+
+	} while (!(tmp & sram_ch->fld_aud_fifo_en));
+
+}
+
+int cx25821_start_audio_dma_upstream(struct cx25821_dev *dev,
+				     struct sram_channel *sram_ch)
+{
+	u32 tmp = 0;
+	int err = 0;
+
+	/* Set the physical start address of the RISC program in the initial
+	 * program counter(IPC) member of the CMDS. */
+	cx_write(sram_ch->cmds_start + 0, dev->_risc_phys_addr);
+	/* Risc IPC High 64 bits 63-32 */
+	cx_write(sram_ch->cmds_start + 4, 0);
+
+	/* reset counter */
+	cx_write(sram_ch->gpcnt_ctl, 3);
+
+	/* Set the line length       (It looks like we do not need to set the
+	 * line length) */
+	cx_write(sram_ch->aud_length, AUDIO_LINE_SIZE & FLD_AUD_DST_LN_LNGTH);
+
+	/* Set the input mode to 16-bit */
+	tmp = cx_read(sram_ch->aud_cfg);
+	tmp |= FLD_AUD_SRC_ENABLE | FLD_AUD_DST_PK_MODE | FLD_AUD_CLK_ENABLE |
+		FLD_AUD_MASTER_MODE | FLD_AUD_CLK_SELECT_PLL_D |
+		FLD_AUD_SONY_MODE;
+	cx_write(sram_ch->aud_cfg, tmp);
+
+	/* Read and write back the interrupt status register to clear it */
+	tmp = cx_read(sram_ch->int_stat);
+	cx_write(sram_ch->int_stat, tmp);
+
+	/* Clear our bits from the interrupt status register. */
+	cx_write(sram_ch->int_stat, _intr_msk);
+
+	/* Set the interrupt mask register, enable irq. */
+	cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit));
+	tmp = cx_read(sram_ch->int_msk);
+	cx_write(sram_ch->int_msk, tmp |= _intr_msk);
+
+	err = request_irq(dev->pci->irq, cx25821_upstream_irq_audio,
+			IRQF_SHARED, dev->name, dev);
+	if (err < 0) {
+		pr_err("%s: can't get upstream IRQ %d\n", dev->name,
+				dev->pci->irq);
+		goto fail_irq;
+	}
+
+	/* Start the DMA  engine */
+	tmp = cx_read(sram_ch->dma_ctl);
+	cx_set(sram_ch->dma_ctl, tmp | sram_ch->fld_aud_risc_en);
+
+	dev->_audio_is_running = 1;
+	dev->_is_first_audio_frame = 1;
+
+	/* The fifo_en bit turns on by the first Risc program */
+	cx25821_wait_fifo_enable(dev, sram_ch);
+
+	return 0;
+
+fail_irq:
+	cx25821_dev_unregister(dev);
+	return err;
+}
+
+int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select)
+{
+	struct sram_channel *sram_ch;
+	int retval = 0;
+	int err = 0;
+	int str_length = 0;
+
+	if (dev->_audio_is_running) {
+		pr_warn("Audio Channel is still running so return!\n");
+		return 0;
+	}
+
+	dev->_audio_upstream_channel = channel_select;
+	sram_ch = dev->channels[channel_select].sram_channels;
+
+	/* Work queue */
+	INIT_WORK(&dev->_audio_work_entry, cx25821_audioups_handler);
+	dev->_irq_audio_queues =
+	    create_singlethread_workqueue("cx25821_audioworkqueue");
+
+	if (!dev->_irq_audio_queues) {
+		printk(KERN_DEBUG
+			pr_fmt("ERROR: create_singlethread_workqueue() for Audio FAILED!\n"));
+		return -ENOMEM;
+	}
+
+	dev->_last_index_irq = 0;
+	dev->_audio_is_running = 0;
+	dev->_audioframe_count = 0;
+	dev->_audiofile_status = RESET_STATUS;
+	dev->_audio_lines_count = LINES_PER_AUDIO_BUFFER;
+	_line_size = AUDIO_LINE_SIZE;
+
+	if (dev->input_audiofilename) {
+		str_length = strlen(dev->input_audiofilename);
+		dev->_audiofilename = kmemdup(dev->input_audiofilename,
+					      str_length + 1, GFP_KERNEL);
+
+		if (!dev->_audiofilename)
+			goto error;
+
+		/* Default if filename is empty string */
+		if (strcmp(dev->input_audiofilename, "") == 0)
+			dev->_audiofilename = "/root/audioGOOD.wav";
+	} else {
+		str_length = strlen(_defaultAudioName);
+		dev->_audiofilename = kmemdup(_defaultAudioName,
+					      str_length + 1, GFP_KERNEL);
+
+		if (!dev->_audiofilename)
+			goto error;
+	}
+
+	retval = cx25821_sram_channel_setup_upstream_audio(dev, sram_ch,
+							_line_size, 0);
+
+	dev->audio_upstream_riscbuf_size =
+		AUDIO_RISC_DMA_BUF_SIZE * NUM_AUDIO_PROGS +
+		RISC_SYNC_INSTRUCTION_SIZE;
+	dev->audio_upstream_databuf_size = AUDIO_DATA_BUF_SZ * NUM_AUDIO_PROGS;
+
+	/* Allocating buffers and prepare RISC program */
+	retval = cx25821_audio_upstream_buffer_prepare(dev, sram_ch,
+							_line_size);
+	if (retval < 0) {
+		pr_err("%s: Failed to set up Audio upstream buffers!\n",
+			dev->name);
+		goto error;
+	}
+	/* Start RISC engine */
+	cx25821_start_audio_dma_upstream(dev, sram_ch);
+
+	return 0;
+
+error:
+	cx25821_dev_unregister(dev);
+
+	return err;
+}
diff --git a/drivers/media/pci/cx25821/cx25821-audio-upstream.h b/drivers/media/pci/cx25821/cx25821-audio-upstream.h
new file mode 100644
index 0000000..af2ae7c
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-audio-upstream.h
@@ -0,0 +1,62 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <hiep.huynh@conexant.com>, <shu.lin@conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+#define NUM_AUDIO_PROGS       8
+#define NUM_AUDIO_FRAMES      8
+#define END_OF_FILE           0
+#define IN_PROGRESS           1
+#define RESET_STATUS          -1
+#define FIFO_DISABLE          0
+#define FIFO_ENABLE           1
+#define NUM_NO_OPS            4
+
+#define RISC_READ_INSTRUCTION_SIZE      12
+#define RISC_JUMP_INSTRUCTION_SIZE      12
+#define RISC_WRITECR_INSTRUCTION_SIZE   16
+#define RISC_SYNC_INSTRUCTION_SIZE      4
+#define DWORD_SIZE                      4
+#define AUDIO_SYNC_LINE                 4
+
+#define LINES_PER_AUDIO_BUFFER      15
+#define AUDIO_LINE_SIZE             128
+#define AUDIO_DATA_BUF_SZ           (AUDIO_LINE_SIZE * LINES_PER_AUDIO_BUFFER)
+
+#define USE_RISC_NOOP_AUDIO   1
+
+#ifdef USE_RISC_NOOP_AUDIO
+#define AUDIO_RISC_DMA_BUF_SIZE						\
+	(LINES_PER_AUDIO_BUFFER * RISC_READ_INSTRUCTION_SIZE +		\
+	 RISC_WRITECR_INSTRUCTION_SIZE + NUM_NO_OPS * DWORD_SIZE +	\
+	 RISC_JUMP_INSTRUCTION_SIZE)
+#endif
+
+#ifndef USE_RISC_NOOP_AUDIO
+#define AUDIO_RISC_DMA_BUF_SIZE						\
+	(LINES_PER_AUDIO_BUFFER * RISC_READ_INSTRUCTION_SIZE +		\
+	 RISC_WRITECR_INSTRUCTION_SIZE + RISC_JUMP_INSTRUCTION_SIZE)
+#endif
+
+static int _line_size;
+char *_defaultAudioName = "/root/audioGOOD.wav";
diff --git a/drivers/media/pci/cx25821/cx25821-audio.h b/drivers/media/pci/cx25821/cx25821-audio.h
new file mode 100644
index 0000000..1fc2d24
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-audio.h
@@ -0,0 +1,62 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __CX25821_AUDIO_H__
+#define __CX25821_AUDIO_H__
+
+#define USE_RISC_NOOP		1
+#define LINES_PER_BUFFER	15
+#define AUDIO_LINE_SIZE		128
+
+/* Number of buffer programs to use at once. */
+#define NUMBER_OF_PROGRAMS	8
+
+/*
+ * Max size of the RISC program for a buffer. - worst case is 2 writes per line
+ * Space is also added for the 4 no-op instructions added on the end.
+ */
+#ifndef USE_RISC_NOOP
+#define MAX_BUFFER_PROGRAM_SIZE						\
+	(2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE +		\
+	 RISC_WRITECR_INSTRUCTION_SIZE * 4)
+#endif
+
+/* MAE 12 July 2005 Try to use NOOP RISC instruction instead */
+#ifdef USE_RISC_NOOP
+#define MAX_BUFFER_PROGRAM_SIZE						\
+	(2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE +		\
+	 RISC_NOOP_INSTRUCTION_SIZE * 4)
+#endif
+
+/* Sizes of various instructions in bytes.  Used when adding instructions. */
+#define RISC_WRITE_INSTRUCTION_SIZE	12
+#define RISC_JUMP_INSTRUCTION_SIZE	12
+#define RISC_SKIP_INSTRUCTION_SIZE	4
+#define RISC_SYNC_INSTRUCTION_SIZE	4
+#define RISC_WRITECR_INSTRUCTION_SIZE	16
+#define RISC_NOOP_INSTRUCTION_SIZE	4
+
+#define MAX_AUDIO_DMA_BUFFER_SIZE					\
+	(MAX_BUFFER_PROGRAM_SIZE * NUMBER_OF_PROGRAMS +			\
+	 RISC_SYNC_INSTRUCTION_SIZE)
+
+#endif
diff --git a/drivers/media/pci/cx25821/cx25821-biffuncs.h b/drivers/media/pci/cx25821/cx25821-biffuncs.h
new file mode 100644
index 0000000..9326a7c
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-biffuncs.h
@@ -0,0 +1,45 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _BITFUNCS_H
+#define _BITFUNCS_H
+
+#define SetBit(Bit)  (1 << Bit)
+
+inline u8 getBit(u32 sample, u8 index)
+{
+	return (u8) ((sample >> index) & 1);
+}
+
+inline u32 clearBitAtPos(u32 value, u8 bit)
+{
+	return value & ~(1 << bit);
+}
+
+inline u32 setBitAtPos(u32 sample, u8 bit)
+{
+	sample |= (1 << bit);
+	return sample;
+
+}
+
+#endif
diff --git a/drivers/media/pci/cx25821/cx25821-cards.c b/drivers/media/pci/cx25821/cx25821-cards.c
new file mode 100644
index 0000000..99988c9
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-cards.c
@@ -0,0 +1,72 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
+ *	Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <media/cx25840.h>
+
+#include "cx25821.h"
+#include "tuner-xc2028.h"
+
+/* board config info */
+
+struct cx25821_board cx25821_boards[] = {
+	[UNKNOWN_BOARD] = {
+		.name = "UNKNOWN/GENERIC",
+		/* Ensure safe default for unknown boards */
+		.clk_freq = 0,
+	},
+
+	[CX25821_BOARD] = {
+		.name = "CX25821",
+		.portb = CX25821_RAW,
+		.portc = CX25821_264,
+		.input[0].type = CX25821_VMUX_COMPOSITE,
+	},
+
+};
+
+const unsigned int cx25821_bcount = ARRAY_SIZE(cx25821_boards);
+
+struct cx25821_subid cx25821_subids[] = {
+	{
+		.subvendor = 0x14f1,
+		.subdevice = 0x0920,
+		.card = CX25821_BOARD,
+	},
+};
+
+void cx25821_card_setup(struct cx25821_dev *dev)
+{
+	static u8 eeprom[256];
+
+	if (dev->i2c_bus[0].i2c_rc == 0) {
+		dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
+		tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom,
+				sizeof(eeprom));
+	}
+}
diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c
new file mode 100644
index 0000000..f11f6f0
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-core.c
@@ -0,0 +1,1502 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
+ *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include "cx25821.h"
+#include "cx25821-sram.h"
+#include "cx25821-video.h"
+
+MODULE_DESCRIPTION("Driver for Athena cards");
+MODULE_AUTHOR("Shu Lin - Hiep Huynh");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+static unsigned int card[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET };
+module_param_array(card, int, NULL, 0444);
+MODULE_PARM_DESC(card, "card type");
+
+static unsigned int cx25821_devcount;
+
+DEFINE_MUTEX(cx25821_devlist_mutex);
+EXPORT_SYMBOL(cx25821_devlist_mutex);
+LIST_HEAD(cx25821_devlist);
+EXPORT_SYMBOL(cx25821_devlist);
+
+struct sram_channel cx25821_sram_channels[] = {
+	[SRAM_CH00] = {
+		.i = SRAM_CH00,
+		.name = "VID A",
+		.cmds_start = VID_A_DOWN_CMDS,
+		.ctrl_start = VID_A_IQ,
+		.cdt = VID_A_CDT,
+		.fifo_start = VID_A_DOWN_CLUSTER_1,
+		.fifo_size = (VID_CLUSTER_SIZE << 2),
+		.ptr1_reg = DMA1_PTR1,
+		.ptr2_reg = DMA1_PTR2,
+		.cnt1_reg = DMA1_CNT1,
+		.cnt2_reg = DMA1_CNT2,
+		.int_msk = VID_A_INT_MSK,
+		.int_stat = VID_A_INT_STAT,
+		.int_mstat = VID_A_INT_MSTAT,
+		.dma_ctl = VID_DST_A_DMA_CTL,
+		.gpcnt_ctl = VID_DST_A_GPCNT_CTL,
+		.gpcnt = VID_DST_A_GPCNT,
+		.vip_ctl = VID_DST_A_VIP_CTL,
+		.pix_frmt = VID_DST_A_PIX_FRMT,
+	},
+
+	[SRAM_CH01] = {
+		.i = SRAM_CH01,
+		.name = "VID B",
+		.cmds_start = VID_B_DOWN_CMDS,
+		.ctrl_start = VID_B_IQ,
+		.cdt = VID_B_CDT,
+		.fifo_start = VID_B_DOWN_CLUSTER_1,
+		.fifo_size = (VID_CLUSTER_SIZE << 2),
+		.ptr1_reg = DMA2_PTR1,
+		.ptr2_reg = DMA2_PTR2,
+		.cnt1_reg = DMA2_CNT1,
+		.cnt2_reg = DMA2_CNT2,
+		.int_msk = VID_B_INT_MSK,
+		.int_stat = VID_B_INT_STAT,
+		.int_mstat = VID_B_INT_MSTAT,
+		.dma_ctl = VID_DST_B_DMA_CTL,
+		.gpcnt_ctl = VID_DST_B_GPCNT_CTL,
+		.gpcnt = VID_DST_B_GPCNT,
+		.vip_ctl = VID_DST_B_VIP_CTL,
+		.pix_frmt = VID_DST_B_PIX_FRMT,
+	},
+
+	[SRAM_CH02] = {
+		.i = SRAM_CH02,
+		.name = "VID C",
+		.cmds_start = VID_C_DOWN_CMDS,
+		.ctrl_start = VID_C_IQ,
+		.cdt = VID_C_CDT,
+		.fifo_start = VID_C_DOWN_CLUSTER_1,
+		.fifo_size = (VID_CLUSTER_SIZE << 2),
+		.ptr1_reg = DMA3_PTR1,
+		.ptr2_reg = DMA3_PTR2,
+		.cnt1_reg = DMA3_CNT1,
+		.cnt2_reg = DMA3_CNT2,
+		.int_msk = VID_C_INT_MSK,
+		.int_stat = VID_C_INT_STAT,
+		.int_mstat = VID_C_INT_MSTAT,
+		.dma_ctl = VID_DST_C_DMA_CTL,
+		.gpcnt_ctl = VID_DST_C_GPCNT_CTL,
+		.gpcnt = VID_DST_C_GPCNT,
+		.vip_ctl = VID_DST_C_VIP_CTL,
+		.pix_frmt = VID_DST_C_PIX_FRMT,
+	},
+
+	[SRAM_CH03] = {
+		.i = SRAM_CH03,
+		.name = "VID D",
+		.cmds_start = VID_D_DOWN_CMDS,
+		.ctrl_start = VID_D_IQ,
+		.cdt = VID_D_CDT,
+		.fifo_start = VID_D_DOWN_CLUSTER_1,
+		.fifo_size = (VID_CLUSTER_SIZE << 2),
+		.ptr1_reg = DMA4_PTR1,
+		.ptr2_reg = DMA4_PTR2,
+		.cnt1_reg = DMA4_CNT1,
+		.cnt2_reg = DMA4_CNT2,
+		.int_msk = VID_D_INT_MSK,
+		.int_stat = VID_D_INT_STAT,
+		.int_mstat = VID_D_INT_MSTAT,
+		.dma_ctl = VID_DST_D_DMA_CTL,
+		.gpcnt_ctl = VID_DST_D_GPCNT_CTL,
+		.gpcnt = VID_DST_D_GPCNT,
+		.vip_ctl = VID_DST_D_VIP_CTL,
+		.pix_frmt = VID_DST_D_PIX_FRMT,
+	},
+
+	[SRAM_CH04] = {
+		.i = SRAM_CH04,
+		.name = "VID E",
+		.cmds_start = VID_E_DOWN_CMDS,
+		.ctrl_start = VID_E_IQ,
+		.cdt = VID_E_CDT,
+		.fifo_start = VID_E_DOWN_CLUSTER_1,
+		.fifo_size = (VID_CLUSTER_SIZE << 2),
+		.ptr1_reg = DMA5_PTR1,
+		.ptr2_reg = DMA5_PTR2,
+		.cnt1_reg = DMA5_CNT1,
+		.cnt2_reg = DMA5_CNT2,
+		.int_msk = VID_E_INT_MSK,
+		.int_stat = VID_E_INT_STAT,
+		.int_mstat = VID_E_INT_MSTAT,
+		.dma_ctl = VID_DST_E_DMA_CTL,
+		.gpcnt_ctl = VID_DST_E_GPCNT_CTL,
+		.gpcnt = VID_DST_E_GPCNT,
+		.vip_ctl = VID_DST_E_VIP_CTL,
+		.pix_frmt = VID_DST_E_PIX_FRMT,
+	},
+
+	[SRAM_CH05] = {
+		.i = SRAM_CH05,
+		.name = "VID F",
+		.cmds_start = VID_F_DOWN_CMDS,
+		.ctrl_start = VID_F_IQ,
+		.cdt = VID_F_CDT,
+		.fifo_start = VID_F_DOWN_CLUSTER_1,
+		.fifo_size = (VID_CLUSTER_SIZE << 2),
+		.ptr1_reg = DMA6_PTR1,
+		.ptr2_reg = DMA6_PTR2,
+		.cnt1_reg = DMA6_CNT1,
+		.cnt2_reg = DMA6_CNT2,
+		.int_msk = VID_F_INT_MSK,
+		.int_stat = VID_F_INT_STAT,
+		.int_mstat = VID_F_INT_MSTAT,
+		.dma_ctl = VID_DST_F_DMA_CTL,
+		.gpcnt_ctl = VID_DST_F_GPCNT_CTL,
+		.gpcnt = VID_DST_F_GPCNT,
+		.vip_ctl = VID_DST_F_VIP_CTL,
+		.pix_frmt = VID_DST_F_PIX_FRMT,
+	},
+
+	[SRAM_CH06] = {
+		.i = SRAM_CH06,
+		.name = "VID G",
+		.cmds_start = VID_G_DOWN_CMDS,
+		.ctrl_start = VID_G_IQ,
+		.cdt = VID_G_CDT,
+		.fifo_start = VID_G_DOWN_CLUSTER_1,
+		.fifo_size = (VID_CLUSTER_SIZE << 2),
+		.ptr1_reg = DMA7_PTR1,
+		.ptr2_reg = DMA7_PTR2,
+		.cnt1_reg = DMA7_CNT1,
+		.cnt2_reg = DMA7_CNT2,
+		.int_msk = VID_G_INT_MSK,
+		.int_stat = VID_G_INT_STAT,
+		.int_mstat = VID_G_INT_MSTAT,
+		.dma_ctl = VID_DST_G_DMA_CTL,
+		.gpcnt_ctl = VID_DST_G_GPCNT_CTL,
+		.gpcnt = VID_DST_G_GPCNT,
+		.vip_ctl = VID_DST_G_VIP_CTL,
+		.pix_frmt = VID_DST_G_PIX_FRMT,
+	},
+
+	[SRAM_CH07] = {
+		.i = SRAM_CH07,
+		.name = "VID H",
+		.cmds_start = VID_H_DOWN_CMDS,
+		.ctrl_start = VID_H_IQ,
+		.cdt = VID_H_CDT,
+		.fifo_start = VID_H_DOWN_CLUSTER_1,
+		.fifo_size = (VID_CLUSTER_SIZE << 2),
+		.ptr1_reg = DMA8_PTR1,
+		.ptr2_reg = DMA8_PTR2,
+		.cnt1_reg = DMA8_CNT1,
+		.cnt2_reg = DMA8_CNT2,
+		.int_msk = VID_H_INT_MSK,
+		.int_stat = VID_H_INT_STAT,
+		.int_mstat = VID_H_INT_MSTAT,
+		.dma_ctl = VID_DST_H_DMA_CTL,
+		.gpcnt_ctl = VID_DST_H_GPCNT_CTL,
+		.gpcnt = VID_DST_H_GPCNT,
+		.vip_ctl = VID_DST_H_VIP_CTL,
+		.pix_frmt = VID_DST_H_PIX_FRMT,
+	},
+
+	[SRAM_CH08] = {
+		.name = "audio from",
+		.cmds_start = AUD_A_DOWN_CMDS,
+		.ctrl_start = AUD_A_IQ,
+		.cdt = AUD_A_CDT,
+		.fifo_start = AUD_A_DOWN_CLUSTER_1,
+		.fifo_size = AUDIO_CLUSTER_SIZE * 3,
+		.ptr1_reg = DMA17_PTR1,
+		.ptr2_reg = DMA17_PTR2,
+		.cnt1_reg = DMA17_CNT1,
+		.cnt2_reg = DMA17_CNT2,
+	},
+
+	[SRAM_CH09] = {
+		.i = SRAM_CH09,
+		.name = "VID Upstream I",
+		.cmds_start = VID_I_UP_CMDS,
+		.ctrl_start = VID_I_IQ,
+		.cdt = VID_I_CDT,
+		.fifo_start = VID_I_UP_CLUSTER_1,
+		.fifo_size = (VID_CLUSTER_SIZE << 2),
+		.ptr1_reg = DMA15_PTR1,
+		.ptr2_reg = DMA15_PTR2,
+		.cnt1_reg = DMA15_CNT1,
+		.cnt2_reg = DMA15_CNT2,
+		.int_msk = VID_I_INT_MSK,
+		.int_stat = VID_I_INT_STAT,
+		.int_mstat = VID_I_INT_MSTAT,
+		.dma_ctl = VID_SRC_I_DMA_CTL,
+		.gpcnt_ctl = VID_SRC_I_GPCNT_CTL,
+		.gpcnt = VID_SRC_I_GPCNT,
+
+		.vid_fmt_ctl = VID_SRC_I_FMT_CTL,
+		.vid_active_ctl1 = VID_SRC_I_ACTIVE_CTL1,
+		.vid_active_ctl2 = VID_SRC_I_ACTIVE_CTL2,
+		.vid_cdt_size = VID_SRC_I_CDT_SZ,
+		.irq_bit = 8,
+	},
+
+	[SRAM_CH10] = {
+		.i = SRAM_CH10,
+		.name = "VID Upstream J",
+		.cmds_start = VID_J_UP_CMDS,
+		.ctrl_start = VID_J_IQ,
+		.cdt = VID_J_CDT,
+		.fifo_start = VID_J_UP_CLUSTER_1,
+		.fifo_size = (VID_CLUSTER_SIZE << 2),
+		.ptr1_reg = DMA16_PTR1,
+		.ptr2_reg = DMA16_PTR2,
+		.cnt1_reg = DMA16_CNT1,
+		.cnt2_reg = DMA16_CNT2,
+		.int_msk = VID_J_INT_MSK,
+		.int_stat = VID_J_INT_STAT,
+		.int_mstat = VID_J_INT_MSTAT,
+		.dma_ctl = VID_SRC_J_DMA_CTL,
+		.gpcnt_ctl = VID_SRC_J_GPCNT_CTL,
+		.gpcnt = VID_SRC_J_GPCNT,
+
+		.vid_fmt_ctl = VID_SRC_J_FMT_CTL,
+		.vid_active_ctl1 = VID_SRC_J_ACTIVE_CTL1,
+		.vid_active_ctl2 = VID_SRC_J_ACTIVE_CTL2,
+		.vid_cdt_size = VID_SRC_J_CDT_SZ,
+		.irq_bit = 9,
+	},
+
+	[SRAM_CH11] = {
+		.i = SRAM_CH11,
+		.name = "Audio Upstream Channel B",
+		.cmds_start = AUD_B_UP_CMDS,
+		.ctrl_start = AUD_B_IQ,
+		.cdt = AUD_B_CDT,
+		.fifo_start = AUD_B_UP_CLUSTER_1,
+		.fifo_size = (AUDIO_CLUSTER_SIZE * 3),
+		.ptr1_reg = DMA22_PTR1,
+		.ptr2_reg = DMA22_PTR2,
+		.cnt1_reg = DMA22_CNT1,
+		.cnt2_reg = DMA22_CNT2,
+		.int_msk = AUD_B_INT_MSK,
+		.int_stat = AUD_B_INT_STAT,
+		.int_mstat = AUD_B_INT_MSTAT,
+		.dma_ctl = AUD_INT_DMA_CTL,
+		.gpcnt_ctl = AUD_B_GPCNT_CTL,
+		.gpcnt = AUD_B_GPCNT,
+		.aud_length = AUD_B_LNGTH,
+		.aud_cfg = AUD_B_CFG,
+		.fld_aud_fifo_en = FLD_AUD_SRC_B_FIFO_EN,
+		.fld_aud_risc_en = FLD_AUD_SRC_B_RISC_EN,
+		.irq_bit = 11,
+	},
+};
+EXPORT_SYMBOL(cx25821_sram_channels);
+
+struct sram_channel *channel0 = &cx25821_sram_channels[SRAM_CH00];
+struct sram_channel *channel1 = &cx25821_sram_channels[SRAM_CH01];
+struct sram_channel *channel2 = &cx25821_sram_channels[SRAM_CH02];
+struct sram_channel *channel3 = &cx25821_sram_channels[SRAM_CH03];
+struct sram_channel *channel4 = &cx25821_sram_channels[SRAM_CH04];
+struct sram_channel *channel5 = &cx25821_sram_channels[SRAM_CH05];
+struct sram_channel *channel6 = &cx25821_sram_channels[SRAM_CH06];
+struct sram_channel *channel7 = &cx25821_sram_channels[SRAM_CH07];
+struct sram_channel *channel9 = &cx25821_sram_channels[SRAM_CH09];
+struct sram_channel *channel10 = &cx25821_sram_channels[SRAM_CH10];
+struct sram_channel *channel11 = &cx25821_sram_channels[SRAM_CH11];
+
+struct cx25821_dmaqueue mpegq;
+
+static int cx25821_risc_decode(u32 risc)
+{
+	static const char * const instr[16] = {
+		[RISC_SYNC >> 28] = "sync",
+		[RISC_WRITE >> 28] = "write",
+		[RISC_WRITEC >> 28] = "writec",
+		[RISC_READ >> 28] = "read",
+		[RISC_READC >> 28] = "readc",
+		[RISC_JUMP >> 28] = "jump",
+		[RISC_SKIP >> 28] = "skip",
+		[RISC_WRITERM >> 28] = "writerm",
+		[RISC_WRITECM >> 28] = "writecm",
+		[RISC_WRITECR >> 28] = "writecr",
+	};
+	static const int incr[16] = {
+		[RISC_WRITE >> 28] = 3,
+		[RISC_JUMP >> 28] = 3,
+		[RISC_SKIP >> 28] = 1,
+		[RISC_SYNC >> 28] = 1,
+		[RISC_WRITERM >> 28] = 3,
+		[RISC_WRITECM >> 28] = 3,
+		[RISC_WRITECR >> 28] = 4,
+	};
+	static const char * const bits[] = {
+		"12", "13", "14", "resync",
+		"cnt0", "cnt1", "18", "19",
+		"20", "21", "22", "23",
+		"irq1", "irq2", "eol", "sol",
+	};
+	int i;
+
+	pr_cont("0x%08x [ %s",
+		risc, instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
+	for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--) {
+		if (risc & (1 << (i + 12)))
+			pr_cont(" %s", bits[i]);
+	}
+	pr_cont(" count=%d ]\n", risc & 0xfff);
+	return incr[risc >> 28] ? incr[risc >> 28] : 1;
+}
+
+static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap)
+{
+	struct cx25821_i2c *bus = i2c_adap->algo_data;
+	struct cx25821_dev *dev = bus->dev;
+	return cx_read(bus->reg_stat) & 0x01;
+}
+
+static void cx25821_registers_init(struct cx25821_dev *dev)
+{
+	u32 tmp;
+
+	/* enable RUN_RISC in Pecos */
+	cx_write(DEV_CNTRL2, 0x20);
+
+	/* Set the master PCI interrupt masks to enable video, audio, MBIF,
+	 * and GPIO interrupts
+	 * I2C interrupt masking is handled by the I2C objects themselves. */
+	cx_write(PCI_INT_MSK, 0x2001FFFF);
+
+	tmp = cx_read(RDR_TLCTL0);
+	tmp &= ~FLD_CFG_RCB_CK_EN;	/* Clear the RCB_CK_EN bit */
+	cx_write(RDR_TLCTL0, tmp);
+
+	/* PLL-A setting for the Audio Master Clock */
+	cx_write(PLL_A_INT_FRAC, 0x9807A58B);
+
+	/* PLL_A_POST = 0x1C, PLL_A_OUT_TO_PIN = 0x1 */
+	cx_write(PLL_A_POST_STAT_BIST, 0x8000019C);
+
+	/* clear reset bit [31] */
+	tmp = cx_read(PLL_A_INT_FRAC);
+	cx_write(PLL_A_INT_FRAC, tmp & 0x7FFFFFFF);
+
+	/* PLL-B setting for Mobilygen Host Bus Interface */
+	cx_write(PLL_B_INT_FRAC, 0x9883A86F);
+
+	/* PLL_B_POST = 0xD, PLL_B_OUT_TO_PIN = 0x0 */
+	cx_write(PLL_B_POST_STAT_BIST, 0x8000018D);
+
+	/* clear reset bit [31] */
+	tmp = cx_read(PLL_B_INT_FRAC);
+	cx_write(PLL_B_INT_FRAC, tmp & 0x7FFFFFFF);
+
+	/* PLL-C setting for video upstream channel */
+	cx_write(PLL_C_INT_FRAC, 0x96A0EA3F);
+
+	/* PLL_C_POST = 0x3, PLL_C_OUT_TO_PIN = 0x0 */
+	cx_write(PLL_C_POST_STAT_BIST, 0x80000103);
+
+	/* clear reset bit [31] */
+	tmp = cx_read(PLL_C_INT_FRAC);
+	cx_write(PLL_C_INT_FRAC, tmp & 0x7FFFFFFF);
+
+	/* PLL-D setting for audio upstream channel */
+	cx_write(PLL_D_INT_FRAC, 0x98757F5B);
+
+	/* PLL_D_POST = 0x13, PLL_D_OUT_TO_PIN = 0x0 */
+	cx_write(PLL_D_POST_STAT_BIST, 0x80000113);
+
+	/* clear reset bit [31] */
+	tmp = cx_read(PLL_D_INT_FRAC);
+	cx_write(PLL_D_INT_FRAC, tmp & 0x7FFFFFFF);
+
+	/* This selects the PLL C clock source for the video upstream channel
+	 * I and J */
+	tmp = cx_read(VID_CH_CLK_SEL);
+	cx_write(VID_CH_CLK_SEL, (tmp & 0x00FFFFFF) | 0x24000000);
+
+	/* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for
+	 * channel A-C
+	 * select 656/VIP DST for downstream Channel A - C */
+	tmp = cx_read(VID_CH_MODE_SEL);
+	/* cx_write( VID_CH_MODE_SEL, tmp | 0x1B0001FF); */
+	cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00);
+
+	/* enables 656 port I and J as output */
+	tmp = cx_read(CLK_RST);
+	/* use external ALT_PLL_REF pin as its reference clock instead */
+	tmp |= FLD_USE_ALT_PLL_REF;
+	cx_write(CLK_RST, tmp & ~(FLD_VID_I_CLK_NOE | FLD_VID_J_CLK_NOE));
+
+	mdelay(100);
+}
+
+int cx25821_sram_channel_setup(struct cx25821_dev *dev,
+			       struct sram_channel *ch,
+			       unsigned int bpl, u32 risc)
+{
+	unsigned int i, lines;
+	u32 cdt;
+
+	if (ch->cmds_start == 0) {
+		cx_write(ch->ptr1_reg, 0);
+		cx_write(ch->ptr2_reg, 0);
+		cx_write(ch->cnt2_reg, 0);
+		cx_write(ch->cnt1_reg, 0);
+		return 0;
+	}
+
+	bpl = (bpl + 7) & ~7;	/* alignment */
+	cdt = ch->cdt;
+	lines = ch->fifo_size / bpl;
+
+	if (lines > 4)
+		lines = 4;
+
+	BUG_ON(lines < 2);
+
+	cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+	cx_write(8 + 4, 8);
+	cx_write(8 + 8, 0);
+
+	/* write CDT */
+	for (i = 0; i < lines; i++) {
+		cx_write(cdt + 16 * i, ch->fifo_start + bpl * i);
+		cx_write(cdt + 16 * i + 4, 0);
+		cx_write(cdt + 16 * i + 8, 0);
+		cx_write(cdt + 16 * i + 12, 0);
+	}
+
+	/* init the first cdt buffer */
+	for (i = 0; i < 128; i++)
+		cx_write(ch->fifo_start + 4 * i, i);
+
+	/* write CMDS */
+	if (ch->jumponly)
+		cx_write(ch->cmds_start + 0, 8);
+	else
+		cx_write(ch->cmds_start + 0, risc);
+
+	cx_write(ch->cmds_start + 4, 0);	/* 64 bits 63-32 */
+	cx_write(ch->cmds_start + 8, cdt);
+	cx_write(ch->cmds_start + 12, (lines * 16) >> 3);
+	cx_write(ch->cmds_start + 16, ch->ctrl_start);
+
+	if (ch->jumponly)
+		cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2));
+	else
+		cx_write(ch->cmds_start + 20, 64 >> 2);
+
+	for (i = 24; i < 80; i += 4)
+		cx_write(ch->cmds_start + i, 0);
+
+	/* fill registers */
+	cx_write(ch->ptr1_reg, ch->fifo_start);
+	cx_write(ch->ptr2_reg, cdt);
+	cx_write(ch->cnt2_reg, (lines * 16) >> 3);
+	cx_write(ch->cnt1_reg, (bpl >> 3) - 1);
+
+	return 0;
+}
+EXPORT_SYMBOL(cx25821_sram_channel_setup);
+
+int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev,
+				     struct sram_channel *ch,
+				     unsigned int bpl, u32 risc)
+{
+	unsigned int i, lines;
+	u32 cdt;
+
+	if (ch->cmds_start == 0) {
+		cx_write(ch->ptr1_reg, 0);
+		cx_write(ch->ptr2_reg, 0);
+		cx_write(ch->cnt2_reg, 0);
+		cx_write(ch->cnt1_reg, 0);
+		return 0;
+	}
+
+	bpl = (bpl + 7) & ~7;	/* alignment */
+	cdt = ch->cdt;
+	lines = ch->fifo_size / bpl;
+
+	if (lines > 3)
+		lines = 3;	/* for AUDIO */
+
+	BUG_ON(lines < 2);
+
+	cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+	cx_write(8 + 4, 8);
+	cx_write(8 + 8, 0);
+
+	/* write CDT */
+	for (i = 0; i < lines; i++) {
+		cx_write(cdt + 16 * i, ch->fifo_start + bpl * i);
+		cx_write(cdt + 16 * i + 4, 0);
+		cx_write(cdt + 16 * i + 8, 0);
+		cx_write(cdt + 16 * i + 12, 0);
+	}
+
+	/* write CMDS */
+	if (ch->jumponly)
+		cx_write(ch->cmds_start + 0, 8);
+	else
+		cx_write(ch->cmds_start + 0, risc);
+
+	cx_write(ch->cmds_start + 4, 0);	/* 64 bits 63-32 */
+	cx_write(ch->cmds_start + 8, cdt);
+	cx_write(ch->cmds_start + 12, (lines * 16) >> 3);
+	cx_write(ch->cmds_start + 16, ch->ctrl_start);
+
+	/* IQ size */
+	if (ch->jumponly)
+		cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2));
+	else
+		cx_write(ch->cmds_start + 20, 64 >> 2);
+
+	/* zero out */
+	for (i = 24; i < 80; i += 4)
+		cx_write(ch->cmds_start + i, 0);
+
+	/* fill registers */
+	cx_write(ch->ptr1_reg, ch->fifo_start);
+	cx_write(ch->ptr2_reg, cdt);
+	cx_write(ch->cnt2_reg, (lines * 16) >> 3);
+	cx_write(ch->cnt1_reg, (bpl >> 3) - 1);
+
+	return 0;
+}
+EXPORT_SYMBOL(cx25821_sram_channel_setup_audio);
+
+void cx25821_sram_channel_dump(struct cx25821_dev *dev, struct sram_channel *ch)
+{
+	static char *name[] = {
+		"init risc lo",
+		"init risc hi",
+		"cdt base",
+		"cdt size",
+		"iq base",
+		"iq size",
+		"risc pc lo",
+		"risc pc hi",
+		"iq wr ptr",
+		"iq rd ptr",
+		"cdt current",
+		"pci target lo",
+		"pci target hi",
+		"line / byte",
+	};
+	u32 risc;
+	unsigned int i, j, n;
+
+	pr_warn("%s: %s - dma channel status dump\n", dev->name, ch->name);
+	for (i = 0; i < ARRAY_SIZE(name); i++)
+		pr_warn("cmds + 0x%2x:   %-15s: 0x%08x\n",
+			i * 4, name[i], cx_read(ch->cmds_start + 4 * i));
+
+	j = i * 4;
+	for (i = 0; i < 4;) {
+		risc = cx_read(ch->cmds_start + 4 * (i + 14));
+		pr_warn("cmds + 0x%2x:   risc%d: ", j + i * 4, i);
+		i += cx25821_risc_decode(risc);
+	}
+
+	for (i = 0; i < (64 >> 2); i += n) {
+		risc = cx_read(ch->ctrl_start + 4 * i);
+		/* No consideration for bits 63-32 */
+
+		pr_warn("ctrl + 0x%2x (0x%08x): iq %x: ",
+			i * 4, ch->ctrl_start + 4 * i, i);
+		n = cx25821_risc_decode(risc);
+		for (j = 1; j < n; j++) {
+			risc = cx_read(ch->ctrl_start + 4 * (i + j));
+			pr_warn("ctrl + 0x%2x :   iq %x: 0x%08x [ arg #%d ]\n",
+				4 * (i + j), i + j, risc, j);
+		}
+	}
+
+	pr_warn("        :   fifo: 0x%08x -> 0x%x\n",
+		ch->fifo_start, ch->fifo_start + ch->fifo_size);
+	pr_warn("        :   ctrl: 0x%08x -> 0x%x\n",
+		ch->ctrl_start, ch->ctrl_start + 6 * 16);
+	pr_warn("        :   ptr1_reg: 0x%08x\n",
+		cx_read(ch->ptr1_reg));
+	pr_warn("        :   ptr2_reg: 0x%08x\n",
+		cx_read(ch->ptr2_reg));
+	pr_warn("        :   cnt1_reg: 0x%08x\n",
+		cx_read(ch->cnt1_reg));
+	pr_warn("        :   cnt2_reg: 0x%08x\n",
+		cx_read(ch->cnt2_reg));
+}
+EXPORT_SYMBOL(cx25821_sram_channel_dump);
+
+void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev,
+				     struct sram_channel *ch)
+{
+	static const char * const name[] = {
+		"init risc lo",
+		"init risc hi",
+		"cdt base",
+		"cdt size",
+		"iq base",
+		"iq size",
+		"risc pc lo",
+		"risc pc hi",
+		"iq wr ptr",
+		"iq rd ptr",
+		"cdt current",
+		"pci target lo",
+		"pci target hi",
+		"line / byte",
+	};
+
+	u32 risc, value, tmp;
+	unsigned int i, j, n;
+
+	pr_info("\n%s: %s - dma Audio channel status dump\n",
+		dev->name, ch->name);
+
+	for (i = 0; i < ARRAY_SIZE(name); i++)
+		pr_info("%s: cmds + 0x%2x:   %-15s: 0x%08x\n",
+			dev->name, i * 4, name[i],
+			cx_read(ch->cmds_start + 4 * i));
+
+	j = i * 4;
+	for (i = 0; i < 4;) {
+		risc = cx_read(ch->cmds_start + 4 * (i + 14));
+		pr_warn("cmds + 0x%2x:   risc%d: ", j + i * 4, i);
+		i += cx25821_risc_decode(risc);
+	}
+
+	for (i = 0; i < (64 >> 2); i += n) {
+		risc = cx_read(ch->ctrl_start + 4 * i);
+		/* No consideration for bits 63-32 */
+
+		pr_warn("ctrl + 0x%2x (0x%08x): iq %x: ",
+			i * 4, ch->ctrl_start + 4 * i, i);
+		n = cx25821_risc_decode(risc);
+
+		for (j = 1; j < n; j++) {
+			risc = cx_read(ch->ctrl_start + 4 * (i + j));
+			pr_warn("ctrl + 0x%2x :   iq %x: 0x%08x [ arg #%d ]\n",
+				4 * (i + j), i + j, risc, j);
+		}
+	}
+
+	pr_warn("        :   fifo: 0x%08x -> 0x%x\n",
+		ch->fifo_start, ch->fifo_start + ch->fifo_size);
+	pr_warn("        :   ctrl: 0x%08x -> 0x%x\n",
+		ch->ctrl_start, ch->ctrl_start + 6 * 16);
+	pr_warn("        :   ptr1_reg: 0x%08x\n",
+		cx_read(ch->ptr1_reg));
+	pr_warn("        :   ptr2_reg: 0x%08x\n",
+		cx_read(ch->ptr2_reg));
+	pr_warn("        :   cnt1_reg: 0x%08x\n",
+		cx_read(ch->cnt1_reg));
+	pr_warn("        :   cnt2_reg: 0x%08x\n",
+		cx_read(ch->cnt2_reg));
+
+	for (i = 0; i < 4; i++) {
+		risc = cx_read(ch->cmds_start + 56 + (i * 4));
+		pr_warn("instruction %d = 0x%x\n", i, risc);
+	}
+
+	/* read data from the first cdt buffer */
+	risc = cx_read(AUD_A_CDT);
+	pr_warn("\nread cdt loc=0x%x\n", risc);
+	for (i = 0; i < 8; i++) {
+		n = cx_read(risc + i * 4);
+		pr_cont("0x%x ", n);
+	}
+	pr_cont("\n\n");
+
+	value = cx_read(CLK_RST);
+	CX25821_INFO(" CLK_RST = 0x%x\n\n", value);
+
+	value = cx_read(PLL_A_POST_STAT_BIST);
+	CX25821_INFO(" PLL_A_POST_STAT_BIST = 0x%x\n\n", value);
+	value = cx_read(PLL_A_INT_FRAC);
+	CX25821_INFO(" PLL_A_INT_FRAC = 0x%x\n\n", value);
+
+	value = cx_read(PLL_B_POST_STAT_BIST);
+	CX25821_INFO(" PLL_B_POST_STAT_BIST = 0x%x\n\n", value);
+	value = cx_read(PLL_B_INT_FRAC);
+	CX25821_INFO(" PLL_B_INT_FRAC = 0x%x\n\n", value);
+
+	value = cx_read(PLL_C_POST_STAT_BIST);
+	CX25821_INFO(" PLL_C_POST_STAT_BIST = 0x%x\n\n", value);
+	value = cx_read(PLL_C_INT_FRAC);
+	CX25821_INFO(" PLL_C_INT_FRAC = 0x%x\n\n", value);
+
+	value = cx_read(PLL_D_POST_STAT_BIST);
+	CX25821_INFO(" PLL_D_POST_STAT_BIST = 0x%x\n\n", value);
+	value = cx_read(PLL_D_INT_FRAC);
+	CX25821_INFO(" PLL_D_INT_FRAC = 0x%x\n\n", value);
+
+	value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp);
+	CX25821_INFO(" AFE_AB_DIAG_CTRL (0x10900090) = 0x%x\n\n", value);
+}
+EXPORT_SYMBOL(cx25821_sram_channel_dump_audio);
+
+static void cx25821_shutdown(struct cx25821_dev *dev)
+{
+	int i;
+
+	/* disable RISC controller */
+	cx_write(DEV_CNTRL2, 0);
+
+	/* Disable Video A/B activity */
+	for (i = 0; i < VID_CHANNEL_NUM; i++) {
+		cx_write(dev->channels[i].sram_channels->dma_ctl, 0);
+		cx_write(dev->channels[i].sram_channels->int_msk, 0);
+	}
+
+	for (i = VID_UPSTREAM_SRAM_CHANNEL_I;
+		i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) {
+		cx_write(dev->channels[i].sram_channels->dma_ctl, 0);
+		cx_write(dev->channels[i].sram_channels->int_msk, 0);
+	}
+
+	/* Disable Audio activity */
+	cx_write(AUD_INT_DMA_CTL, 0);
+
+	/* Disable Serial port */
+	cx_write(UART_CTL, 0);
+
+	/* Disable Interrupts */
+	cx_write(PCI_INT_MSK, 0);
+	cx_write(AUD_A_INT_MSK, 0);
+}
+
+void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select,
+			      u32 format)
+{
+	if (channel_select <= 7 && channel_select >= 0) {
+		cx_write(dev->channels[channel_select].sram_channels->pix_frmt,
+				format);
+		dev->channels[channel_select].pixel_formats = format;
+	}
+}
+
+static void cx25821_set_vip_mode(struct cx25821_dev *dev,
+				 struct sram_channel *ch)
+{
+	cx_write(ch->pix_frmt, PIXEL_FRMT_422);
+	cx_write(ch->vip_ctl, PIXEL_ENGINE_VIP1);
+}
+
+static void cx25821_initialize(struct cx25821_dev *dev)
+{
+	int i;
+
+	dprintk(1, "%s()\n", __func__);
+
+	cx25821_shutdown(dev);
+	cx_write(PCI_INT_STAT, 0xffffffff);
+
+	for (i = 0; i < VID_CHANNEL_NUM; i++)
+		cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff);
+
+	cx_write(AUD_A_INT_STAT, 0xffffffff);
+	cx_write(AUD_B_INT_STAT, 0xffffffff);
+	cx_write(AUD_C_INT_STAT, 0xffffffff);
+	cx_write(AUD_D_INT_STAT, 0xffffffff);
+	cx_write(AUD_E_INT_STAT, 0xffffffff);
+
+	cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000);
+	cx_write(PAD_CTRL, 0x12);	/* for I2C */
+	cx25821_registers_init(dev);	/* init Pecos registers */
+	mdelay(100);
+
+	for (i = 0; i < VID_CHANNEL_NUM; i++) {
+		cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
+		cx25821_sram_channel_setup(dev, dev->channels[i].sram_channels,
+						1440, 0);
+		dev->channels[i].pixel_formats = PIXEL_FRMT_422;
+		dev->channels[i].use_cif_resolution = FALSE;
+	}
+
+	/* Probably only affect Downstream */
+	for (i = VID_UPSTREAM_SRAM_CHANNEL_I;
+		i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) {
+		cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
+	}
+
+	cx25821_sram_channel_setup_audio(dev,
+			dev->channels[SRAM_CH08].sram_channels, 128, 0);
+
+	cx25821_gpio_init(dev);
+}
+
+static int cx25821_get_resources(struct cx25821_dev *dev)
+{
+	if (request_mem_region(pci_resource_start(dev->pci, 0),
+				pci_resource_len(dev->pci, 0), dev->name))
+		return 0;
+
+	pr_err("%s: can't get MMIO memory @ 0x%llx\n",
+		dev->name, (unsigned long long)pci_resource_start(dev->pci, 0));
+
+	return -EBUSY;
+}
+
+static void cx25821_dev_checkrevision(struct cx25821_dev *dev)
+{
+	dev->hwrevision = cx_read(RDR_CFG2) & 0xff;
+
+	pr_info("%s(): Hardware revision = 0x%02x\n",
+		__func__, dev->hwrevision);
+}
+
+static void cx25821_iounmap(struct cx25821_dev *dev)
+{
+	if (dev == NULL)
+		return;
+
+	/* Releasing IO memory */
+	if (dev->lmmio != NULL) {
+		CX25821_INFO("Releasing lmmio.\n");
+		iounmap(dev->lmmio);
+		dev->lmmio = NULL;
+	}
+}
+
+static int cx25821_dev_setup(struct cx25821_dev *dev)
+{
+	int i;
+
+	pr_info("\n***********************************\n");
+	pr_info("cx25821 set up\n");
+	pr_info("***********************************\n\n");
+
+	mutex_init(&dev->lock);
+
+	atomic_inc(&dev->refcount);
+
+	dev->nr = ++cx25821_devcount;
+	sprintf(dev->name, "cx25821[%d]", dev->nr);
+
+	mutex_lock(&cx25821_devlist_mutex);
+	list_add_tail(&dev->devlist, &cx25821_devlist);
+	mutex_unlock(&cx25821_devlist_mutex);
+
+	if (dev->pci->device != 0x8210) {
+		pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n",
+			__func__, dev->pci->device);
+		return -1;
+	} else {
+		pr_info("Athena Hardware device = 0x%02x\n", dev->pci->device);
+	}
+
+	/* Apply a sensible clock frequency for the PCIe bridge */
+	dev->clk_freq = 28000000;
+	for (i = 0; i < MAX_VID_CHANNEL_NUM; i++)
+		dev->channels[i].sram_channels = &cx25821_sram_channels[i];
+
+	if (dev->nr > 1)
+		CX25821_INFO("dev->nr > 1!");
+
+	/* board config */
+	dev->board = 1;		/* card[dev->nr]; */
+	dev->_max_num_decoders = MAX_DECODERS;
+
+	dev->pci_bus = dev->pci->bus->number;
+	dev->pci_slot = PCI_SLOT(dev->pci->devfn);
+	dev->pci_irqmask = 0x001f00;
+
+	/* External Master 1 Bus */
+	dev->i2c_bus[0].nr = 0;
+	dev->i2c_bus[0].dev = dev;
+	dev->i2c_bus[0].reg_stat = I2C1_STAT;
+	dev->i2c_bus[0].reg_ctrl = I2C1_CTRL;
+	dev->i2c_bus[0].reg_addr = I2C1_ADDR;
+	dev->i2c_bus[0].reg_rdata = I2C1_RDATA;
+	dev->i2c_bus[0].reg_wdata = I2C1_WDATA;
+	dev->i2c_bus[0].i2c_period = (0x07 << 24);	/* 1.95MHz */
+
+	if (cx25821_get_resources(dev) < 0) {
+		pr_err("%s: No more PCIe resources for subsystem: %04x:%04x\n",
+		       dev->name, dev->pci->subsystem_vendor,
+		       dev->pci->subsystem_device);
+
+		cx25821_devcount--;
+		return -EBUSY;
+	}
+
+	/* PCIe stuff */
+	dev->base_io_addr = pci_resource_start(dev->pci, 0);
+
+	if (!dev->base_io_addr) {
+		CX25821_ERR("No PCI Memory resources, exiting!\n");
+		return -ENODEV;
+	}
+
+	dev->lmmio = ioremap(dev->base_io_addr, pci_resource_len(dev->pci, 0));
+
+	if (!dev->lmmio) {
+		CX25821_ERR("ioremap failed, maybe increasing __VMALLOC_RESERVE in page.h\n");
+		cx25821_iounmap(dev);
+		return -ENOMEM;
+	}
+
+	dev->bmmio = (u8 __iomem *) dev->lmmio;
+
+	pr_info("%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+		dev->name, dev->pci->subsystem_vendor,
+		dev->pci->subsystem_device, cx25821_boards[dev->board].name,
+		dev->board, card[dev->nr] == dev->board ?
+		"insmod option" : "autodetected");
+
+	/* init hardware */
+	cx25821_initialize(dev);
+
+	cx25821_i2c_register(&dev->i2c_bus[0]);
+/*  cx25821_i2c_register(&dev->i2c_bus[1]);
+ *  cx25821_i2c_register(&dev->i2c_bus[2]); */
+
+	CX25821_INFO("i2c register! bus->i2c_rc = %d\n",
+			dev->i2c_bus[0].i2c_rc);
+
+	cx25821_card_setup(dev);
+
+	if (medusa_video_init(dev) < 0)
+		CX25821_ERR("%s(): Failed to initialize medusa!\n", __func__);
+
+	cx25821_video_register(dev);
+
+	/* register IOCTL device */
+	dev->ioctl_dev = cx25821_vdev_init(dev, dev->pci,
+			&cx25821_videoioctl_template, "video");
+
+	if (video_register_device
+	    (dev->ioctl_dev, VFL_TYPE_GRABBER, VIDEO_IOCTL_CH) < 0) {
+		cx25821_videoioctl_unregister(dev);
+		pr_err("%s(): Failed to register video adapter for IOCTL, so unregistering videoioctl device\n",
+		       __func__);
+	}
+
+	cx25821_dev_checkrevision(dev);
+	CX25821_INFO("setup done!\n");
+
+	return 0;
+}
+
+void cx25821_start_upstream_video_ch1(struct cx25821_dev *dev,
+				      struct upstream_user_struct *up_data)
+{
+	dev->_isNTSC = !strcmp(dev->vid_stdname, "NTSC") ? 1 : 0;
+
+	dev->tvnorm = !dev->_isNTSC ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M;
+	medusa_set_videostandard(dev);
+
+	cx25821_vidupstream_init_ch1(dev, dev->channel_select,
+				     dev->pixel_format);
+}
+
+void cx25821_start_upstream_video_ch2(struct cx25821_dev *dev,
+				      struct upstream_user_struct *up_data)
+{
+	dev->_isNTSC_ch2 = !strcmp(dev->vid_stdname_ch2, "NTSC") ? 1 : 0;
+
+	dev->tvnorm = !dev->_isNTSC_ch2 ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M;
+	medusa_set_videostandard(dev);
+
+	cx25821_vidupstream_init_ch2(dev, dev->channel_select_ch2,
+				     dev->pixel_format_ch2);
+}
+
+void cx25821_start_upstream_audio(struct cx25821_dev *dev,
+				  struct upstream_user_struct *up_data)
+{
+	cx25821_audio_upstream_init(dev, AUDIO_UPSTREAM_SRAM_CHANNEL_B);
+}
+
+void cx25821_dev_unregister(struct cx25821_dev *dev)
+{
+	int i;
+
+	if (!dev->base_io_addr)
+		return;
+
+	cx25821_free_mem_upstream_ch1(dev);
+	cx25821_free_mem_upstream_ch2(dev);
+	cx25821_free_mem_upstream_audio(dev);
+
+	release_mem_region(dev->base_io_addr, pci_resource_len(dev->pci, 0));
+
+	if (!atomic_dec_and_test(&dev->refcount))
+		return;
+
+	for (i = 0; i < VID_CHANNEL_NUM; i++)
+		cx25821_video_unregister(dev, i);
+
+	for (i = VID_UPSTREAM_SRAM_CHANNEL_I;
+	     i <= AUDIO_UPSTREAM_SRAM_CHANNEL_B; i++) {
+		cx25821_video_unregister(dev, i);
+	}
+
+	cx25821_videoioctl_unregister(dev);
+
+	cx25821_i2c_unregister(&dev->i2c_bus[0]);
+	cx25821_iounmap(dev);
+}
+EXPORT_SYMBOL(cx25821_dev_unregister);
+
+static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist,
+				  unsigned int offset, u32 sync_line,
+				  unsigned int bpl, unsigned int padding,
+				  unsigned int lines)
+{
+	struct scatterlist *sg;
+	unsigned int line, todo;
+
+	/* sync instruction */
+	if (sync_line != NO_SYNC_LINE)
+		*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
+
+	/* scan lines */
+	sg = sglist;
+	for (line = 0; line < lines; line++) {
+		while (offset && offset >= sg_dma_len(sg)) {
+			offset -= sg_dma_len(sg);
+			sg++;
+		}
+		if (bpl <= sg_dma_len(sg) - offset) {
+			/* fits into current chunk */
+			*(rp++) = cpu_to_le32(RISC_WRITE | RISC_SOL | RISC_EOL |
+					bpl);
+			*(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
+			*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
+			offset += bpl;
+		} else {
+			/* scanline needs to be split */
+			todo = bpl;
+			*(rp++) = cpu_to_le32(RISC_WRITE | RISC_SOL |
+					(sg_dma_len(sg) - offset));
+			*(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
+			*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
+			todo -= (sg_dma_len(sg) - offset);
+			offset = 0;
+			sg++;
+			while (todo > sg_dma_len(sg)) {
+				*(rp++) = cpu_to_le32(RISC_WRITE |
+						sg_dma_len(sg));
+				*(rp++) = cpu_to_le32(sg_dma_address(sg));
+				*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
+				todo -= sg_dma_len(sg);
+				sg++;
+			}
+			*(rp++) = cpu_to_le32(RISC_WRITE | RISC_EOL | todo);
+			*(rp++) = cpu_to_le32(sg_dma_address(sg));
+			*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
+			offset += todo;
+		}
+
+		offset += padding;
+	}
+
+	return rp;
+}
+
+int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+			struct scatterlist *sglist, unsigned int top_offset,
+			unsigned int bottom_offset, unsigned int bpl,
+			unsigned int padding, unsigned int lines)
+{
+	u32 instructions;
+	u32 fields;
+	__le32 *rp;
+	int rc;
+
+	fields = 0;
+	if (UNSET != top_offset)
+		fields++;
+	if (UNSET != bottom_offset)
+		fields++;
+
+	/* estimate risc mem: worst case is one write per page border +
+	   one write per scan line + syncs + jump (all 2 dwords).  Padding
+	   can cause next bpl to start close to a page border.  First DMA
+	   region may be smaller than PAGE_SIZE */
+	/* write and jump need and extra dword */
+	instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE +
+			lines);
+	instructions += 2;
+	rc = btcx_riscmem_alloc(pci, risc, instructions * 12);
+
+	if (rc < 0)
+		return rc;
+
+	/* write risc instructions */
+	rp = risc->cpu;
+
+	if (UNSET != top_offset) {
+		rp = cx25821_risc_field(rp, sglist, top_offset, 0, bpl, padding,
+					lines);
+	}
+
+	if (UNSET != bottom_offset) {
+		rp = cx25821_risc_field(rp, sglist, bottom_offset, 0x200, bpl,
+					padding, lines);
+	}
+
+	/* save pointer to jmp instruction address */
+	risc->jmp = rp;
+	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
+
+	return 0;
+}
+
+static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist,
+					unsigned int offset, u32 sync_line,
+					unsigned int bpl, unsigned int padding,
+					unsigned int lines, unsigned int lpi)
+{
+	struct scatterlist *sg;
+	unsigned int line, todo, sol;
+
+	/* sync instruction */
+	if (sync_line != NO_SYNC_LINE)
+		*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
+
+	/* scan lines */
+	sg = sglist;
+	for (line = 0; line < lines; line++) {
+		while (offset && offset >= sg_dma_len(sg)) {
+			offset -= sg_dma_len(sg);
+			sg++;
+		}
+
+		if (lpi && line > 0 && !(line % lpi))
+			sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC;
+		else
+			sol = RISC_SOL;
+
+		if (bpl <= sg_dma_len(sg) - offset) {
+			/* fits into current chunk */
+			*(rp++) = cpu_to_le32(RISC_WRITE | sol | RISC_EOL |
+					bpl);
+			*(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
+			*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
+			offset += bpl;
+		} else {
+			/* scanline needs to be split */
+			todo = bpl;
+			*(rp++) = cpu_to_le32(RISC_WRITE | sol |
+					(sg_dma_len(sg) - offset));
+			*(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
+			*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
+			todo -= (sg_dma_len(sg) - offset);
+			offset = 0;
+			sg++;
+			while (todo > sg_dma_len(sg)) {
+				*(rp++) = cpu_to_le32(RISC_WRITE |
+						sg_dma_len(sg));
+				*(rp++) = cpu_to_le32(sg_dma_address(sg));
+				*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
+				todo -= sg_dma_len(sg);
+				sg++;
+			}
+			*(rp++) = cpu_to_le32(RISC_WRITE | RISC_EOL | todo);
+			*(rp++) = cpu_to_le32(sg_dma_address(sg));
+			*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
+			offset += todo;
+		}
+		offset += padding;
+	}
+
+	return rp;
+}
+
+int cx25821_risc_databuffer_audio(struct pci_dev *pci,
+				  struct btcx_riscmem *risc,
+				  struct scatterlist *sglist,
+				  unsigned int bpl,
+				  unsigned int lines, unsigned int lpi)
+{
+	u32 instructions;
+	__le32 *rp;
+	int rc;
+
+	/* estimate risc mem: worst case is one write per page border +
+	   one write per scan line + syncs + jump (all 2 dwords).  Here
+	   there is no padding and no sync.  First DMA region may be smaller
+	   than PAGE_SIZE */
+	/* Jump and write need an extra dword */
+	instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
+	instructions += 1;
+
+	rc = btcx_riscmem_alloc(pci, risc, instructions * 12);
+	if (rc < 0)
+		return rc;
+
+	/* write risc instructions */
+	rp = risc->cpu;
+	rp = cx25821_risc_field_audio(rp, sglist, 0, NO_SYNC_LINE, bpl, 0,
+				      lines, lpi);
+
+	/* save pointer to jmp instruction address */
+	risc->jmp = rp;
+	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
+	return 0;
+}
+EXPORT_SYMBOL(cx25821_risc_databuffer_audio);
+
+int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+			 u32 reg, u32 mask, u32 value)
+{
+	__le32 *rp;
+	int rc;
+
+	rc = btcx_riscmem_alloc(pci, risc, 4 * 16);
+
+	if (rc < 0)
+		return rc;
+
+	/* write risc instructions */
+	rp = risc->cpu;
+
+	*(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ1);
+	*(rp++) = cpu_to_le32(reg);
+	*(rp++) = cpu_to_le32(value);
+	*(rp++) = cpu_to_le32(mask);
+	*(rp++) = cpu_to_le32(RISC_JUMP);
+	*(rp++) = cpu_to_le32(risc->dma);
+	*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
+	return 0;
+}
+
+void cx25821_free_buffer(struct videobuf_queue *q, struct cx25821_buffer *buf)
+{
+	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+
+	BUG_ON(in_interrupt());
+	videobuf_waiton(q, &buf->vb, 0, 0);
+	videobuf_dma_unmap(q->dev, dma);
+	videobuf_dma_free(dma);
+	btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static irqreturn_t cx25821_irq(int irq, void *dev_id)
+{
+	struct cx25821_dev *dev = dev_id;
+	u32 pci_status;
+	u32 vid_status;
+	int i, handled = 0;
+	u32 mask[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
+
+	pci_status = cx_read(PCI_INT_STAT);
+
+	if (pci_status == 0)
+		goto out;
+
+	for (i = 0; i < VID_CHANNEL_NUM; i++) {
+		if (pci_status & mask[i]) {
+			vid_status = cx_read(dev->channels[i].
+				sram_channels->int_stat);
+
+			if (vid_status)
+				handled += cx25821_video_irq(dev, i,
+						vid_status);
+
+			cx_write(PCI_INT_STAT, mask[i]);
+		}
+	}
+
+out:
+	return IRQ_RETVAL(handled);
+}
+
+void cx25821_print_irqbits(char *name, char *tag, char **strings,
+			   int len, u32 bits, u32 mask)
+{
+	unsigned int i;
+
+	printk(KERN_DEBUG pr_fmt("%s: %s [0x%x]"), name, tag, bits);
+
+	for (i = 0; i < len; i++) {
+		if (!(bits & (1 << i)))
+			continue;
+		if (strings[i])
+			pr_cont(" %s", strings[i]);
+		else
+			pr_cont(" %d", i);
+		if (!(mask & (1 << i)))
+			continue;
+		pr_cont("*");
+	}
+	pr_cont("\n");
+}
+EXPORT_SYMBOL(cx25821_print_irqbits);
+
+struct cx25821_dev *cx25821_dev_get(struct pci_dev *pci)
+{
+	struct cx25821_dev *dev = pci_get_drvdata(pci);
+	return dev;
+}
+EXPORT_SYMBOL(cx25821_dev_get);
+
+static int __devinit cx25821_initdev(struct pci_dev *pci_dev,
+				     const struct pci_device_id *pci_id)
+{
+	struct cx25821_dev *dev;
+	int err = 0;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (NULL == dev)
+		return -ENOMEM;
+
+	err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
+	if (err < 0)
+		goto fail_free;
+
+	/* pci init */
+	dev->pci = pci_dev;
+	if (pci_enable_device(pci_dev)) {
+		err = -EIO;
+
+		pr_info("pci enable failed!\n");
+
+		goto fail_unregister_device;
+	}
+
+	pr_info("Athena pci enable !\n");
+
+	err = cx25821_dev_setup(dev);
+	if (err) {
+		if (err == -EBUSY)
+			goto fail_unregister_device;
+		else
+			goto fail_unregister_pci;
+	}
+
+	/* print pci info */
+	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+	pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
+	pr_info("%s/0: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n",
+		dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
+		dev->pci_lat, (unsigned long long)dev->base_io_addr);
+
+	pci_set_master(pci_dev);
+	if (!pci_dma_supported(pci_dev, 0xffffffff)) {
+		pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
+		err = -EIO;
+		goto fail_irq;
+	}
+
+	err = request_irq(pci_dev->irq, cx25821_irq,
+			IRQF_SHARED, dev->name, dev);
+
+	if (err < 0) {
+		pr_err("%s: can't get IRQ %d\n", dev->name, pci_dev->irq);
+		goto fail_irq;
+	}
+
+	return 0;
+
+fail_irq:
+	pr_info("cx25821_initdev() can't get IRQ !\n");
+	cx25821_dev_unregister(dev);
+
+fail_unregister_pci:
+	pci_disable_device(pci_dev);
+fail_unregister_device:
+	v4l2_device_unregister(&dev->v4l2_dev);
+
+fail_free:
+	kfree(dev);
+	return err;
+}
+
+static void __devexit cx25821_finidev(struct pci_dev *pci_dev)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+	struct cx25821_dev *dev = get_cx25821(v4l2_dev);
+
+	cx25821_shutdown(dev);
+	pci_disable_device(pci_dev);
+
+	/* unregister stuff */
+	if (pci_dev->irq)
+		free_irq(pci_dev->irq, dev);
+
+	mutex_lock(&cx25821_devlist_mutex);
+	list_del(&dev->devlist);
+	mutex_unlock(&cx25821_devlist_mutex);
+
+	cx25821_dev_unregister(dev);
+	v4l2_device_unregister(v4l2_dev);
+	kfree(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(cx25821_pci_tbl) = {
+	{
+		/* CX25821 Athena */
+		.vendor = 0x14f1,
+		.device = 0x8210,
+		.subvendor = 0x14f1,
+		.subdevice = 0x0920,
+	}, {
+		/* CX25821 No Brand */
+		.vendor = 0x14f1,
+		.device = 0x8210,
+		.subvendor = 0x0000,
+		.subdevice = 0x0000,
+	}, {
+		/* --- end of list --- */
+	}
+};
+
+MODULE_DEVICE_TABLE(pci, cx25821_pci_tbl);
+
+static struct pci_driver cx25821_pci_driver = {
+	.name = "cx25821",
+	.id_table = cx25821_pci_tbl,
+	.probe = cx25821_initdev,
+	.remove = __devexit_p(cx25821_finidev),
+	/* TODO */
+	.suspend = NULL,
+	.resume = NULL,
+};
+
+static int __init cx25821_init(void)
+{
+	pr_info("driver version %d.%d.%d loaded\n",
+		(CX25821_VERSION_CODE >> 16) & 0xff,
+		(CX25821_VERSION_CODE >> 8) & 0xff,
+		CX25821_VERSION_CODE & 0xff);
+	return pci_register_driver(&cx25821_pci_driver);
+}
+
+static void __exit cx25821_fini(void)
+{
+	pci_unregister_driver(&cx25821_pci_driver);
+}
+
+module_init(cx25821_init);
+module_exit(cx25821_fini);
diff --git a/drivers/media/pci/cx25821/cx25821-gpio.c b/drivers/media/pci/cx25821/cx25821-gpio.c
new file mode 100644
index 0000000..29e43b0
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-gpio.c
@@ -0,0 +1,98 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cx25821.h"
+
+/********************* GPIO stuffs *********************/
+void cx25821_set_gpiopin_direction(struct cx25821_dev *dev,
+				   int pin_number, int pin_logic_value)
+{
+	int bit = pin_number;
+	u32 gpio_oe_reg = GPIO_LO_OE;
+	u32 gpio_register = 0;
+	u32 value = 0;
+
+	/* Check for valid pinNumber */
+	if (pin_number >= 47)
+		return;
+
+	if (pin_number > 31) {
+		bit = pin_number - 31;
+		gpio_oe_reg = GPIO_HI_OE;
+	}
+	/* Here we will make sure that the GPIOs 0 and 1 are output. keep the
+	 * rest as is */
+	gpio_register = cx_read(gpio_oe_reg);
+
+	if (pin_logic_value == 1)
+		value = gpio_register | Set_GPIO_Bit(bit);
+	else
+		value = gpio_register & Clear_GPIO_Bit(bit);
+
+	cx_write(gpio_oe_reg, value);
+}
+EXPORT_SYMBOL(cx25821_set_gpiopin_direction);
+
+static void cx25821_set_gpiopin_logicvalue(struct cx25821_dev *dev,
+					   int pin_number, int pin_logic_value)
+{
+	int bit = pin_number;
+	u32 gpio_reg = GPIO_LO;
+	u32 value = 0;
+
+	/* Check for valid pinNumber */
+	if (pin_number >= 47)
+		return;
+
+	/* change to output direction */
+	cx25821_set_gpiopin_direction(dev, pin_number, 0);
+
+	if (pin_number > 31) {
+		bit = pin_number - 31;
+		gpio_reg = GPIO_HI;
+	}
+
+	value = cx_read(gpio_reg);
+
+	if (pin_logic_value == 0)
+		value &= Clear_GPIO_Bit(bit);
+	else
+		value |= Set_GPIO_Bit(bit);
+
+	cx_write(gpio_reg, value);
+}
+
+void cx25821_gpio_init(struct cx25821_dev *dev)
+{
+	if (dev == NULL)
+		return;
+
+	switch (dev->board) {
+	case CX25821_BOARD_CONEXANT_ATHENA10:
+	default:
+		/* set GPIO 5 to select the path for Medusa/Athena */
+		cx25821_set_gpiopin_logicvalue(dev, 5, 1);
+		mdelay(20);
+		break;
+	}
+
+}
diff --git a/drivers/media/pci/cx25821/cx25821-i2c.c b/drivers/media/pci/cx25821/cx25821-i2c.c
new file mode 100644
index 0000000..9844549
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-i2c.c
@@ -0,0 +1,416 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
+ *	Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "cx25821.h"
+#include <linux/i2c.h>
+
+static unsigned int i2c_debug;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+static unsigned int i2c_scan;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+#define dprintk(level, fmt, arg...)					\
+do {									\
+	if (i2c_debug >= level)						\
+		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ##arg);	\
+} while (0)
+
+#define I2C_WAIT_DELAY 32
+#define I2C_WAIT_RETRY 64
+
+#define I2C_EXTEND  (1 << 3)
+#define I2C_NOSTOP  (1 << 4)
+
+static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap)
+{
+	struct cx25821_i2c *bus = i2c_adap->algo_data;
+	struct cx25821_dev *dev = bus->dev;
+	return cx_read(bus->reg_stat) & 0x01;
+}
+
+static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)
+{
+	struct cx25821_i2c *bus = i2c_adap->algo_data;
+	struct cx25821_dev *dev = bus->dev;
+	return cx_read(bus->reg_stat) & 0x02 ? 1 : 0;
+}
+
+static int i2c_wait_done(struct i2c_adapter *i2c_adap)
+{
+	int count;
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		if (!i2c_is_busy(i2c_adap))
+			break;
+		udelay(I2C_WAIT_DELAY);
+	}
+
+	if (I2C_WAIT_RETRY == count)
+		return 0;
+
+	return 1;
+}
+
+static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
+			 const struct i2c_msg *msg, int joined_rlen)
+{
+	struct cx25821_i2c *bus = i2c_adap->algo_data;
+	struct cx25821_dev *dev = bus->dev;
+	u32 wdata, addr, ctrl;
+	int retval, cnt;
+
+	if (joined_rlen)
+		dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __func__,
+			msg->len, joined_rlen);
+	else
+		dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len);
+
+	/* Deal with i2c probe functions with zero payload */
+	if (msg->len == 0) {
+		cx_write(bus->reg_addr, msg->addr << 25);
+		cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2));
+
+		if (!i2c_wait_done(i2c_adap))
+			return -EIO;
+
+		if (!i2c_slave_did_ack(i2c_adap))
+			return -EIO;
+
+		dprintk(1, "%s(): returns 0\n", __func__);
+		return 0;
+	}
+
+	/* dev, reg + first byte */
+	addr = (msg->addr << 25) | msg->buf[0];
+	wdata = msg->buf[0];
+
+	ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
+
+	if (msg->len > 1)
+		ctrl |= I2C_NOSTOP | I2C_EXTEND;
+	else if (joined_rlen)
+		ctrl |= I2C_NOSTOP;
+
+	cx_write(bus->reg_addr, addr);
+	cx_write(bus->reg_wdata, wdata);
+	cx_write(bus->reg_ctrl, ctrl);
+
+	retval = i2c_wait_done(i2c_adap);
+	if (retval < 0)
+		goto err;
+
+	if (retval == 0)
+		goto eio;
+
+	if (i2c_debug) {
+		if (!(ctrl & I2C_NOSTOP))
+			printk(" >\n");
+	}
+
+	for (cnt = 1; cnt < msg->len; cnt++) {
+		/* following bytes */
+		wdata = msg->buf[cnt];
+		ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
+
+		if (cnt < msg->len - 1)
+			ctrl |= I2C_NOSTOP | I2C_EXTEND;
+		else if (joined_rlen)
+			ctrl |= I2C_NOSTOP;
+
+		cx_write(bus->reg_addr, addr);
+		cx_write(bus->reg_wdata, wdata);
+		cx_write(bus->reg_ctrl, ctrl);
+
+		retval = i2c_wait_done(i2c_adap);
+		if (retval < 0)
+			goto err;
+
+		if (retval == 0)
+			goto eio;
+
+		if (i2c_debug) {
+			dprintk(1, " %02x", msg->buf[cnt]);
+			if (!(ctrl & I2C_NOSTOP))
+				dprintk(1, " >\n");
+		}
+	}
+
+	return msg->len;
+
+eio:
+	retval = -EIO;
+err:
+	if (i2c_debug)
+		pr_err(" ERR: %d\n", retval);
+	return retval;
+}
+
+static int i2c_readbytes(struct i2c_adapter *i2c_adap,
+			 const struct i2c_msg *msg, int joined)
+{
+	struct cx25821_i2c *bus = i2c_adap->algo_data;
+	struct cx25821_dev *dev = bus->dev;
+	u32 ctrl, cnt;
+	int retval;
+
+	if (i2c_debug && !joined)
+		dprintk(1, "6-%s(msg->len=%d)\n", __func__, msg->len);
+
+	/* Deal with i2c probe functions with zero payload */
+	if (msg->len == 0) {
+		cx_write(bus->reg_addr, msg->addr << 25);
+		cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1);
+		if (!i2c_wait_done(i2c_adap))
+			return -EIO;
+		if (!i2c_slave_did_ack(i2c_adap))
+			return -EIO;
+
+		dprintk(1, "%s(): returns 0\n", __func__);
+		return 0;
+	}
+
+	if (i2c_debug) {
+		if (joined)
+			dprintk(1, " R");
+		else
+			dprintk(1, " <R %02x", (msg->addr << 1) + 1);
+	}
+
+	for (cnt = 0; cnt < msg->len; cnt++) {
+
+		ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1;
+
+		if (cnt < msg->len - 1)
+			ctrl |= I2C_NOSTOP | I2C_EXTEND;
+
+		cx_write(bus->reg_addr, msg->addr << 25);
+		cx_write(bus->reg_ctrl, ctrl);
+
+		retval = i2c_wait_done(i2c_adap);
+		if (retval < 0)
+			goto err;
+		if (retval == 0)
+			goto eio;
+		msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff;
+
+		if (i2c_debug) {
+			dprintk(1, " %02x", msg->buf[cnt]);
+			if (!(ctrl & I2C_NOSTOP))
+				dprintk(1, " >\n");
+		}
+	}
+
+	return msg->len;
+eio:
+	retval = -EIO;
+err:
+	if (i2c_debug)
+		pr_err(" ERR: %d\n", retval);
+	return retval;
+}
+
+static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
+{
+	struct cx25821_i2c *bus = i2c_adap->algo_data;
+	struct cx25821_dev *dev = bus->dev;
+	int i, retval = 0;
+
+	dprintk(1, "%s(num = %d)\n", __func__, num);
+
+	for (i = 0; i < num; i++) {
+		dprintk(1, "%s(num = %d) addr = 0x%02x  len = 0x%x\n",
+			__func__, num, msgs[i].addr, msgs[i].len);
+
+		if (msgs[i].flags & I2C_M_RD) {
+			/* read */
+			retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
+		} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
+			   msgs[i].addr == msgs[i + 1].addr) {
+			/* write then read from same address */
+			retval = i2c_sendbytes(i2c_adap, &msgs[i],
+					msgs[i + 1].len);
+
+			if (retval < 0)
+				goto err;
+			i++;
+			retval = i2c_readbytes(i2c_adap, &msgs[i], 1);
+		} else {
+			/* write */
+			retval = i2c_sendbytes(i2c_adap, &msgs[i], 0);
+		}
+
+		if (retval < 0)
+			goto err;
+	}
+	return num;
+
+err:
+	return retval;
+}
+
+
+static u32 cx25821_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_WORD_DATA |
+		I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA;
+}
+
+static struct i2c_algorithm cx25821_i2c_algo_template = {
+	.master_xfer = i2c_xfer,
+	.functionality = cx25821_functionality,
+#ifdef NEED_ALGO_CONTROL
+	.algo_control = dummy_algo_control,
+#endif
+};
+
+static struct i2c_adapter cx25821_i2c_adap_template = {
+	.name = "cx25821",
+	.owner = THIS_MODULE,
+	.algo = &cx25821_i2c_algo_template,
+};
+
+static struct i2c_client cx25821_i2c_client_template = {
+	.name = "cx25821 internal",
+};
+
+/* init + register i2c adapter */
+int cx25821_i2c_register(struct cx25821_i2c *bus)
+{
+	struct cx25821_dev *dev = bus->dev;
+
+	dprintk(1, "%s(bus = %d)\n", __func__, bus->nr);
+
+	bus->i2c_adap = cx25821_i2c_adap_template;
+	bus->i2c_client = cx25821_i2c_client_template;
+	bus->i2c_adap.dev.parent = &dev->pci->dev;
+
+	strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name));
+
+	bus->i2c_adap.algo_data = bus;
+	i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev);
+	i2c_add_adapter(&bus->i2c_adap);
+
+	bus->i2c_client.adapter = &bus->i2c_adap;
+
+	/* set up the I2c */
+	bus->i2c_client.addr = (0x88 >> 1);
+
+	return bus->i2c_rc;
+}
+
+int cx25821_i2c_unregister(struct cx25821_i2c *bus)
+{
+	i2c_del_adapter(&bus->i2c_adap);
+	return 0;
+}
+
+void cx25821_av_clk(struct cx25821_dev *dev, int enable)
+{
+	/* write 0 to bus 2 addr 0x144 via i2x_xfer() */
+	char buffer[3];
+	struct i2c_msg msg;
+	dprintk(1, "%s(enabled = %d)\n", __func__, enable);
+
+	/* Register 0x144 */
+	buffer[0] = 0x01;
+	buffer[1] = 0x44;
+	if (enable == 1)
+		buffer[2] = 0x05;
+	else
+		buffer[2] = 0x00;
+
+	msg.addr = 0x44;
+	msg.flags = I2C_M_TEN;
+	msg.len = 3;
+	msg.buf = buffer;
+
+	i2c_xfer(&dev->i2c_bus[0].i2c_adap, &msg, 1);
+}
+
+int cx25821_i2c_read(struct cx25821_i2c *bus, u16 reg_addr, int *value)
+{
+	struct i2c_client *client = &bus->i2c_client;
+	int v = 0;
+	u8 addr[2] = { 0, 0 };
+	u8 buf[4] = { 0, 0, 0, 0 };
+
+	struct i2c_msg msgs[2] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 2,
+			.buf = addr,
+		}, {
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = 4,
+			.buf = buf,
+		}
+	};
+
+	addr[0] = (reg_addr >> 8);
+	addr[1] = (reg_addr & 0xff);
+	msgs[0].addr = 0x44;
+	msgs[1].addr = 0x44;
+
+	i2c_xfer(client->adapter, msgs, 2);
+
+	v = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	*value = v;
+
+	return v;
+}
+
+int cx25821_i2c_write(struct cx25821_i2c *bus, u16 reg_addr, int value)
+{
+	struct i2c_client *client = &bus->i2c_client;
+	int retval = 0;
+	u8 buf[6] = { 0, 0, 0, 0, 0, 0 };
+
+	struct i2c_msg msgs[1] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 6,
+			.buf = buf,
+		}
+	};
+
+	buf[0] = reg_addr >> 8;
+	buf[1] = reg_addr & 0xff;
+	buf[5] = (value >> 24) & 0xff;
+	buf[4] = (value >> 16) & 0xff;
+	buf[3] = (value >> 8) & 0xff;
+	buf[2] = value & 0xff;
+	client->flags = 0;
+	msgs[0].addr = 0x44;
+
+	retval = i2c_xfer(client->adapter, msgs, 1);
+
+	return retval;
+}
diff --git a/drivers/media/pci/cx25821/cx25821-medusa-defines.h b/drivers/media/pci/cx25821/cx25821-medusa-defines.h
new file mode 100644
index 0000000..7a9e647
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-medusa-defines.h
@@ -0,0 +1,42 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _MEDUSA_DEF_H_
+#define _MEDUSA_DEF_H_
+
+/* Video decoder that we supported */
+#define VDEC_A		0
+#define VDEC_B		1
+#define VDEC_C		2
+#define VDEC_D		3
+#define VDEC_E		4
+#define VDEC_F		5
+#define VDEC_G		6
+#define VDEC_H		7
+
+/* end of display sequence */
+#define END_OF_SEQ	0xF;
+
+/* registry string size */
+#define MAX_REGISTRY_SZ	40;
+
+#endif
diff --git a/drivers/media/pci/cx25821/cx25821-medusa-reg.h b/drivers/media/pci/cx25821/cx25821-medusa-reg.h
new file mode 100644
index 0000000..c98ac94
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-medusa-reg.h
@@ -0,0 +1,455 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MEDUSA_REGISTERS__
+#define __MEDUSA_REGISTERS__
+
+/* Serial Slave Registers */
+#define	HOST_REGISTER1				0x0000
+#define	HOST_REGISTER2				0x0001
+
+/* Chip Configuration Registers */
+#define	CHIP_CTRL				0x0100
+#define	AFE_AB_CTRL				0x0104
+#define	AFE_CD_CTRL				0x0108
+#define	AFE_EF_CTRL				0x010C
+#define	AFE_GH_CTRL				0x0110
+#define	DENC_AB_CTRL				0x0114
+#define	BYP_AB_CTRL				0x0118
+#define	MON_A_CTRL				0x011C
+#define	DISP_SEQ_A				0x0120
+#define	DISP_SEQ_B				0x0124
+#define	DISP_AB_CNT				0x0128
+#define	DISP_CD_CNT				0x012C
+#define	DISP_EF_CNT				0x0130
+#define	DISP_GH_CNT				0x0134
+#define	DISP_IJ_CNT				0x0138
+#define	PIN_OE_CTRL				0x013C
+#define	PIN_SPD_CTRL				0x0140
+#define	PIN_SPD_CTRL2				0x0144
+#define	IRQ_STAT_CTRL				0x0148
+#define	POWER_CTRL_AB				0x014C
+#define	POWER_CTRL_CD				0x0150
+#define	POWER_CTRL_EF				0x0154
+#define	POWER_CTRL_GH				0x0158
+#define	TUNE_CTRL				0x015C
+#define	BIAS_CTRL				0x0160
+#define	AFE_AB_DIAG_CTRL			0x0164
+#define	AFE_CD_DIAG_CTRL			0x0168
+#define	AFE_EF_DIAG_CTRL			0x016C
+#define	AFE_GH_DIAG_CTRL			0x0170
+#define	PLL_AB_DIAG_CTRL			0x0174
+#define	PLL_CD_DIAG_CTRL			0x0178
+#define	PLL_EF_DIAG_CTRL			0x017C
+#define	PLL_GH_DIAG_CTRL			0x0180
+#define	TEST_CTRL				0x0184
+#define	BIST_STAT				0x0188
+#define	BIST_STAT2				0x018C
+#define	BIST_VID_PLL_AB_STAT			0x0190
+#define	BIST_VID_PLL_CD_STAT			0x0194
+#define	BIST_VID_PLL_EF_STAT			0x0198
+#define	BIST_VID_PLL_GH_STAT			0x019C
+#define	DLL_DIAG_CTRL				0x01A0
+#define	DEV_CH_ID_CTRL				0x01A4
+#define	ABIST_CTRL_STATUS			0x01A8
+#define	ABIST_FREQ				0x01AC
+#define	ABIST_GOERT_SHIFT			0x01B0
+#define	ABIST_COEF12				0x01B4
+#define	ABIST_COEF34				0x01B8
+#define	ABIST_COEF56				0x01BC
+#define	ABIST_COEF7_SNR				0x01C0
+#define	ABIST_ADC_CAL				0x01C4
+#define	ABIST_BIN1_VGA0				0x01C8
+#define	ABIST_BIN2_VGA1				0x01CC
+#define	ABIST_BIN3_VGA2				0x01D0
+#define	ABIST_BIN4_VGA3				0x01D4
+#define	ABIST_BIN5_VGA4				0x01D8
+#define	ABIST_BIN6_VGA5				0x01DC
+#define	ABIST_BIN7_VGA6				0x0x1E0
+#define	ABIST_CLAMP_A				0x0x1E4
+#define	ABIST_CLAMP_B				0x0x1E8
+#define	ABIST_CLAMP_C				0x01EC
+#define	ABIST_CLAMP_D				0x01F0
+#define	ABIST_CLAMP_E				0x01F4
+#define	ABIST_CLAMP_F				0x01F8
+
+/* Digital Video Encoder A Registers */
+#define	DENC_A_REG_1				0x0200
+#define	DENC_A_REG_2				0x0204
+#define	DENC_A_REG_3				0x0208
+#define	DENC_A_REG_4				0x020C
+#define	DENC_A_REG_5				0x0210
+#define	DENC_A_REG_6				0x0214
+#define	DENC_A_REG_7				0x0218
+#define	DENC_A_REG_8				0x021C
+
+/* Digital Video Encoder B Registers */
+#define	DENC_B_REG_1				0x0300
+#define	DENC_B_REG_2				0x0304
+#define	DENC_B_REG_3				0x0308
+#define	DENC_B_REG_4				0x030C
+#define	DENC_B_REG_5				0x0310
+#define	DENC_B_REG_6				0x0314
+#define	DENC_B_REG_7				0x0318
+#define	DENC_B_REG_8				0x031C
+
+/* Video Decoder A Registers */
+#define	MODE_CTRL				0x1000
+#define	OUT_CTRL1				0x1004
+#define	OUT_CTRL_NS				0x1008
+#define	GEN_STAT				0x100C
+#define	INT_STAT_MASK				0x1010
+#define	LUMA_CTRL				0x1014
+#define	CHROMA_CTRL				0x1018
+#define	CRUSH_CTRL				0x101C
+#define	HORIZ_TIM_CTRL				0x1020
+#define	VERT_TIM_CTRL				0x1024
+#define	MISC_TIM_CTRL				0x1028
+#define	FIELD_COUNT				0x102C
+#define	HSCALE_CTRL				0x1030
+#define	VSCALE_CTRL				0x1034
+#define	MAN_VGA_CTRL				0x1038
+#define	MAN_AGC_CTRL				0x103C
+#define	DFE_CTRL1				0x1040
+#define	DFE_CTRL2				0x1044
+#define	DFE_CTRL3				0x1048
+#define	PLL_CTRL				0x104C
+#define	PLL_CTRL_FAST				0x1050
+#define	HTL_CTRL				0x1054
+#define	SRC_CFG					0x1058
+#define	SC_STEP_SIZE				0x105C
+#define	SC_CONVERGE_CTRL			0x1060
+#define	SC_LOOP_CTRL				0x1064
+#define	COMB_2D_HFS_CFG				0x1068
+#define	COMB_2D_HFD_CFG				0x106C
+#define	COMB_2D_LF_CFG				0x1070
+#define	COMB_2D_BLEND				0x1074
+#define	COMB_MISC_CTRL				0x1078
+#define	COMB_FLAT_THRESH_CTRL			0x107C
+#define	COMB_TEST				0x1080
+#define	BP_MISC_CTRL				0x1084
+#define	VCR_DET_CTRL				0x1088
+#define	NOISE_DET_CTRL				0x108C
+#define	COMB_FLAT_NOISE_CTRL			0x1090
+#define	VERSION					0x11F8
+#define	SOFT_RST_CTRL				0x11FC
+
+/* Video Decoder B Registers */
+#define	VDEC_B_MODE_CTRL			0x1200
+#define	VDEC_B_OUT_CTRL1			0x1204
+#define	VDEC_B_OUT_CTRL_NS			0x1208
+#define	VDEC_B_GEN_STAT				0x120C
+#define	VDEC_B_INT_STAT_MASK			0x1210
+#define	VDEC_B_LUMA_CTRL			0x1214
+#define	VDEC_B_CHROMA_CTRL			0x1218
+#define	VDEC_B_CRUSH_CTRL			0x121C
+#define	VDEC_B_HORIZ_TIM_CTRL			0x1220
+#define	VDEC_B_VERT_TIM_CTRL			0x1224
+#define	VDEC_B_MISC_TIM_CTRL			0x1228
+#define	VDEC_B_FIELD_COUNT			0x122C
+#define	VDEC_B_HSCALE_CTRL			0x1230
+#define	VDEC_B_VSCALE_CTRL			0x1234
+#define	VDEC_B_MAN_VGA_CTRL			0x1238
+#define	VDEC_B_MAN_AGC_CTRL			0x123C
+#define	VDEC_B_DFE_CTRL1			0x1240
+#define	VDEC_B_DFE_CTRL2			0x1244
+#define	VDEC_B_DFE_CTRL3			0x1248
+#define	VDEC_B_PLL_CTRL				0x124C
+#define	VDEC_B_PLL_CTRL_FAST			0x1250
+#define	VDEC_B_HTL_CTRL				0x1254
+#define	VDEC_B_SRC_CFG				0x1258
+#define	VDEC_B_SC_STEP_SIZE			0x125C
+#define	VDEC_B_SC_CONVERGE_CTRL			0x1260
+#define	VDEC_B_SC_LOOP_CTRL			0x1264
+#define	VDEC_B_COMB_2D_HFS_CFG			0x1268
+#define	VDEC_B_COMB_2D_HFD_CFG			0x126C
+#define	VDEC_B_COMB_2D_LF_CFG			0x1270
+#define	VDEC_B_COMB_2D_BLEND			0x1274
+#define	VDEC_B_COMB_MISC_CTRL			0x1278
+#define	VDEC_B_COMB_FLAT_THRESH_CTRL		0x127C
+#define	VDEC_B_COMB_TEST			0x1280
+#define	VDEC_B_BP_MISC_CTRL			0x1284
+#define	VDEC_B_VCR_DET_CTRL			0x1288
+#define	VDEC_B_NOISE_DET_CTRL			0x128C
+#define	VDEC_B_COMB_FLAT_NOISE_CTRL		0x1290
+#define	VDEC_B_VERSION				0x13F8
+#define	VDEC_B_SOFT_RST_CTRL			0x13FC
+
+/* Video Decoder C Registers */
+#define	VDEC_C_MODE_CTRL			0x1400
+#define	VDEC_C_OUT_CTRL1			0x1404
+#define	VDEC_C_OUT_CTRL_NS			0x1408
+#define	VDEC_C_GEN_STAT				0x140C
+#define	VDEC_C_INT_STAT_MASK			0x1410
+#define VDEC_C_LUMA_CTRL			0x1414
+#define VDEC_C_CHROMA_CTRL			0x1418
+#define	VDEC_C_CRUSH_CTRL			0x141C
+#define	VDEC_C_HORIZ_TIM_CTRL			0x1420
+#define	VDEC_C_VERT_TIM_CTRL			0x1424
+#define	VDEC_C_MISC_TIM_CTRL			0x1428
+#define	VDEC_C_FIELD_COUNT			0x142C
+#define	VDEC_C_HSCALE_CTRL			0x1430
+#define	VDEC_C_VSCALE_CTRL			0x1434
+#define	VDEC_C_MAN_VGA_CTRL			0x1438
+#define	VDEC_C_MAN_AGC_CTRL			0x143C
+#define	VDEC_C_DFE_CTRL1			0x1440
+#define	VDEC_C_DFE_CTRL2			0x1444
+#define	VDEC_C_DFE_CTRL3			0x1448
+#define	VDEC_C_PLL_CTRL				0x144C
+#define	VDEC_C_PLL_CTRL_FAST			0x1450
+#define	VDEC_C_HTL_CTRL				0x1454
+#define	VDEC_C_SRC_CFG				0x1458
+#define	VDEC_C_SC_STEP_SIZE			0x145C
+#define	VDEC_C_SC_CONVERGE_CTRL			0x1460
+#define	VDEC_C_SC_LOOP_CTRL			0x1464
+#define	VDEC_C_COMB_2D_HFS_CFG			0x1468
+#define	VDEC_C_COMB_2D_HFD_CFG			0x146C
+#define	VDEC_C_COMB_2D_LF_CFG			0x1470
+#define	VDEC_C_COMB_2D_BLEND			0x1474
+#define	VDEC_C_COMB_MISC_CTRL			0x1478
+#define	VDEC_C_COMB_FLAT_THRESH_CTRL		0x147C
+#define	VDEC_C_COMB_TEST			0x1480
+#define	VDEC_C_BP_MISC_CTRL			0x1484
+#define	VDEC_C_VCR_DET_CTRL			0x1488
+#define	VDEC_C_NOISE_DET_CTRL			0x148C
+#define	VDEC_C_COMB_FLAT_NOISE_CTRL		0x1490
+#define	VDEC_C_VERSION				0x15F8
+#define	VDEC_C_SOFT_RST_CTRL			0x15FC
+
+/* Video Decoder D Registers */
+#define VDEC_D_MODE_CTRL			0x1600
+#define VDEC_D_OUT_CTRL1			0x1604
+#define VDEC_D_OUT_CTRL_NS			0x1608
+#define VDEC_D_GEN_STAT				0x160C
+#define VDEC_D_INT_STAT_MASK			0x1610
+#define VDEC_D_LUMA_CTRL			0x1614
+#define VDEC_D_CHROMA_CTRL			0x1618
+#define VDEC_D_CRUSH_CTRL			0x161C
+#define VDEC_D_HORIZ_TIM_CTRL			0x1620
+#define VDEC_D_VERT_TIM_CTRL			0x1624
+#define VDEC_D_MISC_TIM_CTRL			0x1628
+#define VDEC_D_FIELD_COUNT			0x162C
+#define VDEC_D_HSCALE_CTRL			0x1630
+#define VDEC_D_VSCALE_CTRL			0x1634
+#define VDEC_D_MAN_VGA_CTRL			0x1638
+#define VDEC_D_MAN_AGC_CTRL			0x163C
+#define VDEC_D_DFE_CTRL1			0x1640
+#define VDEC_D_DFE_CTRL2			0x1644
+#define VDEC_D_DFE_CTRL3			0x1648
+#define VDEC_D_PLL_CTRL				0x164C
+#define VDEC_D_PLL_CTRL_FAST			0x1650
+#define VDEC_D_HTL_CTRL				0x1654
+#define VDEC_D_SRC_CFG				0x1658
+#define VDEC_D_SC_STEP_SIZE			0x165C
+#define VDEC_D_SC_CONVERGE_CTRL			0x1660
+#define VDEC_D_SC_LOOP_CTRL			0x1664
+#define VDEC_D_COMB_2D_HFS_CFG			0x1668
+#define VDEC_D_COMB_2D_HFD_CFG			0x166C
+#define VDEC_D_COMB_2D_LF_CFG			0x1670
+#define VDEC_D_COMB_2D_BLEND			0x1674
+#define VDEC_D_COMB_MISC_CTRL			0x1678
+#define VDEC_D_COMB_FLAT_THRESH_CTRL		0x167C
+#define VDEC_D_COMB_TEST			0x1680
+#define VDEC_D_BP_MISC_CTRL			0x1684
+#define VDEC_D_VCR_DET_CTRL			0x1688
+#define VDEC_D_NOISE_DET_CTRL			0x168C
+#define VDEC_D_COMB_FLAT_NOISE_CTRL		0x1690
+#define VDEC_D_VERSION				0x17F8
+#define VDEC_D_SOFT_RST_CTRL			0x17FC
+
+/* Video Decoder E Registers */
+#define	VDEC_E_MODE_CTRL			0x1800
+#define	VDEC_E_OUT_CTRL1			0x1804
+#define	VDEC_E_OUT_CTRL_NS			0x1808
+#define	VDEC_E_GEN_STAT				0x180C
+#define	VDEC_E_INT_STAT_MASK			0x1810
+#define	VDEC_E_LUMA_CTRL			0x1814
+#define	VDEC_E_CHROMA_CTRL			0x1818
+#define	VDEC_E_CRUSH_CTRL			0x181C
+#define	VDEC_E_HORIZ_TIM_CTRL			0x1820
+#define	VDEC_E_VERT_TIM_CTRL			0x1824
+#define	VDEC_E_MISC_TIM_CTRL			0x1828
+#define	VDEC_E_FIELD_COUNT			0x182C
+#define	VDEC_E_HSCALE_CTRL			0x1830
+#define	VDEC_E_VSCALE_CTRL			0x1834
+#define	VDEC_E_MAN_VGA_CTRL			0x1838
+#define	VDEC_E_MAN_AGC_CTRL			0x183C
+#define	VDEC_E_DFE_CTRL1			0x1840
+#define	VDEC_E_DFE_CTRL2			0x1844
+#define	VDEC_E_DFE_CTRL3			0x1848
+#define	VDEC_E_PLL_CTRL				0x184C
+#define	VDEC_E_PLL_CTRL_FAST			0x1850
+#define	VDEC_E_HTL_CTRL				0x1854
+#define	VDEC_E_SRC_CFG				0x1858
+#define	VDEC_E_SC_STEP_SIZE			0x185C
+#define	VDEC_E_SC_CONVERGE_CTRL			0x1860
+#define	VDEC_E_SC_LOOP_CTRL			0x1864
+#define	VDEC_E_COMB_2D_HFS_CFG			0x1868
+#define	VDEC_E_COMB_2D_HFD_CFG			0x186C
+#define	VDEC_E_COMB_2D_LF_CFG			0x1870
+#define	VDEC_E_COMB_2D_BLEND			0x1874
+#define	VDEC_E_COMB_MISC_CTRL			0x1878
+#define	VDEC_E_COMB_FLAT_THRESH_CTRL		0x187C
+#define	VDEC_E_COMB_TEST			0x1880
+#define	VDEC_E_BP_MISC_CTRL			0x1884
+#define	VDEC_E_VCR_DET_CTRL			0x1888
+#define	VDEC_E_NOISE_DET_CTRL			0x188C
+#define	VDEC_E_COMB_FLAT_NOISE_CTRL		0x1890
+#define	VDEC_E_VERSION				0x19F8
+#define	VDEC_E_SOFT_RST_CTRL			0x19FC
+
+/* Video Decoder F Registers */
+#define	VDEC_F_MODE_CTRL			0x1A00
+#define	VDEC_F_OUT_CTRL1			0x1A04
+#define	VDEC_F_OUT_CTRL_NS			0x1A08
+#define	VDEC_F_GEN_STAT				0x1A0C
+#define	VDEC_F_INT_STAT_MASK			0x1A10
+#define	VDEC_F_LUMA_CTRL			0x1A14
+#define	VDEC_F_CHROMA_CTRL			0x1A18
+#define	VDEC_F_CRUSH_CTRL			0x1A1C
+#define	VDEC_F_HORIZ_TIM_CTRL			0x1A20
+#define	VDEC_F_VERT_TIM_CTRL			0x1A24
+#define	VDEC_F_MISC_TIM_CTRL			0x1A28
+#define	VDEC_F_FIELD_COUNT			0x1A2C
+#define	VDEC_F_HSCALE_CTRL			0x1A30
+#define	VDEC_F_VSCALE_CTRL			0x1A34
+#define	VDEC_F_MAN_VGA_CTRL			0x1A38
+#define	VDEC_F_MAN_AGC_CTRL			0x1A3C
+#define	VDEC_F_DFE_CTRL1			0x1A40
+#define	VDEC_F_DFE_CTRL2			0x1A44
+#define	VDEC_F_DFE_CTRL3			0x1A48
+#define	VDEC_F_PLL_CTRL				0x1A4C
+#define	VDEC_F_PLL_CTRL_FAST			0x1A50
+#define	VDEC_F_HTL_CTRL				0x1A54
+#define	VDEC_F_SRC_CFG				0x1A58
+#define	VDEC_F_SC_STEP_SIZE			0x1A5C
+#define	VDEC_F_SC_CONVERGE_CTRL			0x1A60
+#define	VDEC_F_SC_LOOP_CTRL			0x1A64
+#define	VDEC_F_COMB_2D_HFS_CFG			0x1A68
+#define	VDEC_F_COMB_2D_HFD_CFG			0x1A6C
+#define	VDEC_F_COMB_2D_LF_CFG			0x1A70
+#define	VDEC_F_COMB_2D_BLEND			0x1A74
+#define	VDEC_F_COMB_MISC_CTRL			0x1A78
+#define	VDEC_F_COMB_FLAT_THRESH_CTRL		0x1A7C
+#define	VDEC_F_COMB_TEST			0x1A80
+#define	VDEC_F_BP_MISC_CTRL			0x1A84
+#define	VDEC_F_VCR_DET_CTRL			0x1A88
+#define	VDEC_F_NOISE_DET_CTRL			0x1A8C
+#define	VDEC_F_COMB_FLAT_NOISE_CTRL		0x1A90
+#define	VDEC_F_VERSION				0x1BF8
+#define	VDEC_F_SOFT_RST_CTRL			0x1BFC
+
+/* Video Decoder G Registers */
+#define	VDEC_G_MODE_CTRL			0x1C00
+#define	VDEC_G_OUT_CTRL1			0x1C04
+#define	VDEC_G_OUT_CTRL_NS			0x1C08
+#define	VDEC_G_GEN_STAT				0x1C0C
+#define	VDEC_G_INT_STAT_MASK			0x1C10
+#define	VDEC_G_LUMA_CTRL			0x1C14
+#define	VDEC_G_CHROMA_CTRL			0x1C18
+#define	VDEC_G_CRUSH_CTRL			0x1C1C
+#define	VDEC_G_HORIZ_TIM_CTRL			0x1C20
+#define	VDEC_G_VERT_TIM_CTRL			0x1C24
+#define	VDEC_G_MISC_TIM_CTRL			0x1C28
+#define	VDEC_G_FIELD_COUNT			0x1C2C
+#define	VDEC_G_HSCALE_CTRL			0x1C30
+#define	VDEC_G_VSCALE_CTRL			0x1C34
+#define	VDEC_G_MAN_VGA_CTRL			0x1C38
+#define	VDEC_G_MAN_AGC_CTRL			0x1C3C
+#define	VDEC_G_DFE_CTRL1			0x1C40
+#define	VDEC_G_DFE_CTRL2			0x1C44
+#define	VDEC_G_DFE_CTRL3			0x1C48
+#define	VDEC_G_PLL_CTRL				0x1C4C
+#define	VDEC_G_PLL_CTRL_FAST			0x1C50
+#define	VDEC_G_HTL_CTRL				0x1C54
+#define	VDEC_G_SRC_CFG				0x1C58
+#define	VDEC_G_SC_STEP_SIZE			0x1C5C
+#define	VDEC_G_SC_CONVERGE_CTRL			0x1C60
+#define	VDEC_G_SC_LOOP_CTRL			0x1C64
+#define	VDEC_G_COMB_2D_HFS_CFG			0x1C68
+#define	VDEC_G_COMB_2D_HFD_CFG			0x1C6C
+#define	VDEC_G_COMB_2D_LF_CFG			0x1C70
+#define	VDEC_G_COMB_2D_BLEND			0x1C74
+#define	VDEC_G_COMB_MISC_CTRL			0x1C78
+#define	VDEC_G_COMB_FLAT_THRESH_CTRL		0x1C7C
+#define	VDEC_G_COMB_TEST			0x1C80
+#define	VDEC_G_BP_MISC_CTRL			0x1C84
+#define	VDEC_G_VCR_DET_CTRL			0x1C88
+#define	VDEC_G_NOISE_DET_CTRL			0x1C8C
+#define	VDEC_G_COMB_FLAT_NOISE_CTRL		0x1C90
+#define	VDEC_G_VERSION				0x1DF8
+#define	VDEC_G_SOFT_RST_CTRL			0x1DFC
+
+/* Video Decoder H Registers  */
+#define	VDEC_H_MODE_CTRL			0x1E00
+#define	VDEC_H_OUT_CTRL1			0x1E04
+#define	VDEC_H_OUT_CTRL_NS			0x1E08
+#define	VDEC_H_GEN_STAT				0x1E0C
+#define	VDEC_H_INT_STAT_MASK			0x1E1E
+#define	VDEC_H_LUMA_CTRL			0x1E14
+#define	VDEC_H_CHROMA_CTRL			0x1E18
+#define	VDEC_H_CRUSH_CTRL			0x1E1C
+#define	VDEC_H_HORIZ_TIM_CTRL			0x1E20
+#define	VDEC_H_VERT_TIM_CTRL			0x1E24
+#define	VDEC_H_MISC_TIM_CTRL			0x1E28
+#define	VDEC_H_FIELD_COUNT			0x1E2C
+#define	VDEC_H_HSCALE_CTRL			0x1E30
+#define	VDEC_H_VSCALE_CTRL			0x1E34
+#define	VDEC_H_MAN_VGA_CTRL			0x1E38
+#define	VDEC_H_MAN_AGC_CTRL			0x1E3C
+#define	VDEC_H_DFE_CTRL1			0x1E40
+#define	VDEC_H_DFE_CTRL2			0x1E44
+#define	VDEC_H_DFE_CTRL3			0x1E48
+#define	VDEC_H_PLL_CTRL				0x1E4C
+#define	VDEC_H_PLL_CTRL_FAST			0x1E50
+#define	VDEC_H_HTL_CTRL				0x1E54
+#define	VDEC_H_SRC_CFG				0x1E58
+#define	VDEC_H_SC_STEP_SIZE			0x1E5C
+#define	VDEC_H_SC_CONVERGE_CTRL			0x1E60
+#define	VDEC_H_SC_LOOP_CTRL			0x1E64
+#define	VDEC_H_COMB_2D_HFS_CFG			0x1E68
+#define	VDEC_H_COMB_2D_HFD_CFG			0x1E6C
+#define	VDEC_H_COMB_2D_LF_CFG			0x1E70
+#define	VDEC_H_COMB_2D_BLEND			0x1E74
+#define	VDEC_H_COMB_MISC_CTRL			0x1E78
+#define	VDEC_H_COMB_FLAT_THRESH_CTRL		0x1E7C
+#define	VDEC_H_COMB_TEST			0x1E80
+#define	VDEC_H_BP_MISC_CTRL			0x1E84
+#define	VDEC_H_VCR_DET_CTRL			0x1E88
+#define	VDEC_H_NOISE_DET_CTRL			0x1E8C
+#define	VDEC_H_COMB_FLAT_NOISE_CTRL		0x1E90
+#define	VDEC_H_VERSION				0x1FF8
+#define	VDEC_H_SOFT_RST_CTRL			0x1FFC
+
+/*****************************************************************************/
+/* LUMA_CTRL register fields */
+#define VDEC_A_BRITE_CTRL			0x1014
+#define VDEC_A_CNTRST_CTRL			0x1015
+#define VDEC_A_PEAK_SEL				0x1016
+
+/*****************************************************************************/
+/* CHROMA_CTRL register fields */
+#define VDEC_A_USAT_CTRL			0x1018
+#define VDEC_A_VSAT_CTRL			0x1019
+#define VDEC_A_HUE_CTRL				0x101A
+
+#endif
diff --git a/drivers/media/pci/cx25821/cx25821-medusa-video.c b/drivers/media/pci/cx25821/cx25821-medusa-video.c
new file mode 100644
index 0000000..6a92e5c
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-medusa-video.c
@@ -0,0 +1,787 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "cx25821.h"
+#include "cx25821-medusa-video.h"
+#include "cx25821-biffuncs.h"
+
+/*
+ * medusa_enable_bluefield_output()
+ *
+ * Enable the generation of blue filed output if no video
+ *
+ */
+static void medusa_enable_bluefield_output(struct cx25821_dev *dev, int channel,
+					   int enable)
+{
+	u32 value = 0;
+	u32 tmp = 0;
+	int out_ctrl = OUT_CTRL1;
+	int out_ctrl_ns = OUT_CTRL_NS;
+
+	switch (channel) {
+	default:
+	case VDEC_A:
+		break;
+	case VDEC_B:
+		out_ctrl = VDEC_B_OUT_CTRL1;
+		out_ctrl_ns = VDEC_B_OUT_CTRL_NS;
+		break;
+	case VDEC_C:
+		out_ctrl = VDEC_C_OUT_CTRL1;
+		out_ctrl_ns = VDEC_C_OUT_CTRL_NS;
+		break;
+	case VDEC_D:
+		out_ctrl = VDEC_D_OUT_CTRL1;
+		out_ctrl_ns = VDEC_D_OUT_CTRL_NS;
+		break;
+	case VDEC_E:
+		out_ctrl = VDEC_E_OUT_CTRL1;
+		out_ctrl_ns = VDEC_E_OUT_CTRL_NS;
+		return;
+	case VDEC_F:
+		out_ctrl = VDEC_F_OUT_CTRL1;
+		out_ctrl_ns = VDEC_F_OUT_CTRL_NS;
+		return;
+	case VDEC_G:
+		out_ctrl = VDEC_G_OUT_CTRL1;
+		out_ctrl_ns = VDEC_G_OUT_CTRL_NS;
+		return;
+	case VDEC_H:
+		out_ctrl = VDEC_H_OUT_CTRL1;
+		out_ctrl_ns = VDEC_H_OUT_CTRL_NS;
+		return;
+	}
+
+	value = cx25821_i2c_read(&dev->i2c_bus[0], out_ctrl, &tmp);
+	value &= 0xFFFFFF7F;	/* clear BLUE_FIELD_EN */
+	if (enable)
+		value |= 0x00000080;	/* set BLUE_FIELD_EN */
+	cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl, value);
+
+	value = cx25821_i2c_read(&dev->i2c_bus[0], out_ctrl_ns, &tmp);
+	value &= 0xFFFFFF7F;
+	if (enable)
+		value |= 0x00000080;	/* set BLUE_FIELD_EN */
+	cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl_ns, value);
+}
+
+static int medusa_initialize_ntsc(struct cx25821_dev *dev)
+{
+	int ret_val = 0;
+	int i = 0;
+	u32 value = 0;
+	u32 tmp = 0;
+
+	mutex_lock(&dev->lock);
+
+	for (i = 0; i < MAX_DECODERS; i++) {
+		/* set video format NTSC-M */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				MODE_CTRL + (0x200 * i), &tmp);
+		value &= 0xFFFFFFF0;
+		/* enable the fast locking mode bit[16] */
+		value |= 0x10001;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				MODE_CTRL + (0x200 * i), value);
+
+		/* resolution NTSC 720x480 */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				HORIZ_TIM_CTRL + (0x200 * i), &tmp);
+		value &= 0x00C00C00;
+		value |= 0x612D0074;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				HORIZ_TIM_CTRL + (0x200 * i), value);
+
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				VERT_TIM_CTRL + (0x200 * i), &tmp);
+		value &= 0x00C00C00;
+		value |= 0x1C1E001A;	/* vblank_cnt + 2 to get camera ID */
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				VERT_TIM_CTRL + (0x200 * i), value);
+
+		/* chroma subcarrier step size */
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				SC_STEP_SIZE + (0x200 * i), 0x43E00000);
+
+		/* enable VIP optional active */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				OUT_CTRL_NS + (0x200 * i), &tmp);
+		value &= 0xFFFBFFFF;
+		value |= 0x00040000;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				OUT_CTRL_NS + (0x200 * i), value);
+
+		/* enable VIP optional active (VIP_OPT_AL) for direct output. */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				OUT_CTRL1 + (0x200 * i), &tmp);
+		value &= 0xFFFBFFFF;
+		value |= 0x00040000;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				OUT_CTRL1 + (0x200 * i), value);
+
+		/*
+		 * clear VPRES_VERT_EN bit, fixes the chroma run away problem
+		 * when the input switching rate < 16 fields
+		*/
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				MISC_TIM_CTRL + (0x200 * i), &tmp);
+		/* disable special play detection */
+		value = setBitAtPos(value, 14);
+		value = clearBitAtPos(value, 15);
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				MISC_TIM_CTRL + (0x200 * i), value);
+
+		/* set vbi_gate_en to 0 */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				DFE_CTRL1 + (0x200 * i), &tmp);
+		value = clearBitAtPos(value, 29);
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				DFE_CTRL1 + (0x200 * i), value);
+
+		/* Enable the generation of blue field output if no video */
+		medusa_enable_bluefield_output(dev, i, 1);
+	}
+
+	for (i = 0; i < MAX_ENCODERS; i++) {
+		/* NTSC hclock */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				DENC_A_REG_1 + (0x100 * i), &tmp);
+		value &= 0xF000FC00;
+		value |= 0x06B402D0;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				DENC_A_REG_1 + (0x100 * i), value);
+
+		/* burst begin and burst end */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				DENC_A_REG_2 + (0x100 * i), &tmp);
+		value &= 0xFF000000;
+		value |= 0x007E9054;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				DENC_A_REG_2 + (0x100 * i), value);
+
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				DENC_A_REG_3 + (0x100 * i), &tmp);
+		value &= 0xFC00FE00;
+		value |= 0x00EC00F0;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				DENC_A_REG_3 + (0x100 * i), value);
+
+		/* set NTSC vblank, no phase alternation, 7.5 IRE pedestal */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				DENC_A_REG_4 + (0x100 * i), &tmp);
+		value &= 0x00FCFFFF;
+		value |= 0x13020000;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				DENC_A_REG_4 + (0x100 * i), value);
+
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				DENC_A_REG_5 + (0x100 * i), &tmp);
+		value &= 0xFFFF0000;
+		value |= 0x0000E575;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				DENC_A_REG_5 + (0x100 * i), value);
+
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				DENC_A_REG_6 + (0x100 * i), 0x009A89C1);
+
+		/* Subcarrier Increment */
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				DENC_A_REG_7 + (0x100 * i), 0x21F07C1F);
+	}
+
+	/* set picture resolutions */
+	/* 0 - 720 */
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], HSCALE_CTRL, 0x0);
+	/* 0 - 480 */
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], VSCALE_CTRL, 0x0);
+
+	/* set Bypass input format to NTSC 525 lines */
+	value = cx25821_i2c_read(&dev->i2c_bus[0], BYP_AB_CTRL, &tmp);
+	value |= 0x00080200;
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value);
+
+	mutex_unlock(&dev->lock);
+
+	return ret_val;
+}
+
+static int medusa_PALCombInit(struct cx25821_dev *dev, int dec)
+{
+	int ret_val = -1;
+	u32 value = 0, tmp = 0;
+
+	/* Setup for 2D threshold */
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+			COMB_2D_HFS_CFG + (0x200 * dec), 0x20002861);
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+			COMB_2D_HFD_CFG + (0x200 * dec), 0x20002861);
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+			COMB_2D_LF_CFG + (0x200 * dec), 0x200A1023);
+
+	/* Setup flat chroma and luma thresholds */
+	value = cx25821_i2c_read(&dev->i2c_bus[0],
+			COMB_FLAT_THRESH_CTRL + (0x200 * dec), &tmp);
+	value &= 0x06230000;
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+			COMB_FLAT_THRESH_CTRL + (0x200 * dec), value);
+
+	/* set comb 2D blend */
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+			COMB_2D_BLEND + (0x200 * dec), 0x210F0F0F);
+
+	/* COMB MISC CONTROL */
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+			COMB_MISC_CTRL + (0x200 * dec), 0x41120A7F);
+
+	return ret_val;
+}
+
+static int medusa_initialize_pal(struct cx25821_dev *dev)
+{
+	int ret_val = 0;
+	int i = 0;
+	u32 value = 0;
+	u32 tmp = 0;
+
+	mutex_lock(&dev->lock);
+
+	for (i = 0; i < MAX_DECODERS; i++) {
+		/* set video format PAL-BDGHI */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				MODE_CTRL + (0x200 * i), &tmp);
+		value &= 0xFFFFFFF0;
+		/* enable the fast locking mode bit[16] */
+		value |= 0x10004;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				MODE_CTRL + (0x200 * i), value);
+
+		/* resolution PAL 720x576 */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				HORIZ_TIM_CTRL + (0x200 * i), &tmp);
+		value &= 0x00C00C00;
+		value |= 0x632D007D;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				HORIZ_TIM_CTRL + (0x200 * i), value);
+
+		/* vblank656_cnt=x26, vactive_cnt=240h, vblank_cnt=x24 */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				VERT_TIM_CTRL + (0x200 * i), &tmp);
+		value &= 0x00C00C00;
+		value |= 0x28240026;	/* vblank_cnt + 2 to get camera ID */
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				VERT_TIM_CTRL + (0x200 * i), value);
+
+		/* chroma subcarrier step size */
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				SC_STEP_SIZE + (0x200 * i), 0x5411E2D0);
+
+		/* enable VIP optional active */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				OUT_CTRL_NS + (0x200 * i), &tmp);
+		value &= 0xFFFBFFFF;
+		value |= 0x00040000;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				OUT_CTRL_NS + (0x200 * i), value);
+
+		/* enable VIP optional active (VIP_OPT_AL) for direct output. */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				OUT_CTRL1 + (0x200 * i), &tmp);
+		value &= 0xFFFBFFFF;
+		value |= 0x00040000;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				OUT_CTRL1 + (0x200 * i), value);
+
+		/*
+		 * clear VPRES_VERT_EN bit, fixes the chroma run away problem
+		 * when the input switching rate < 16 fields
+		 */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				MISC_TIM_CTRL + (0x200 * i), &tmp);
+		/* disable special play detection */
+		value = setBitAtPos(value, 14);
+		value = clearBitAtPos(value, 15);
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				MISC_TIM_CTRL + (0x200 * i), value);
+
+		/* set vbi_gate_en to 0 */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				DFE_CTRL1 + (0x200 * i), &tmp);
+		value = clearBitAtPos(value, 29);
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				DFE_CTRL1 + (0x200 * i), value);
+
+		medusa_PALCombInit(dev, i);
+
+		/* Enable the generation of blue field output if no video */
+		medusa_enable_bluefield_output(dev, i, 1);
+	}
+
+	for (i = 0; i < MAX_ENCODERS; i++) {
+		/* PAL hclock */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				DENC_A_REG_1 + (0x100 * i), &tmp);
+		value &= 0xF000FC00;
+		value |= 0x06C002D0;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				DENC_A_REG_1 + (0x100 * i), value);
+
+		/* burst begin and burst end */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				DENC_A_REG_2 + (0x100 * i), &tmp);
+		value &= 0xFF000000;
+		value |= 0x007E9754;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				DENC_A_REG_2 + (0x100 * i), value);
+
+		/* hblank and vactive */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				DENC_A_REG_3 + (0x100 * i), &tmp);
+		value &= 0xFC00FE00;
+		value |= 0x00FC0120;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				DENC_A_REG_3 + (0x100 * i), value);
+
+		/* set PAL vblank, phase alternation, 0 IRE pedestal */
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				DENC_A_REG_4 + (0x100 * i), &tmp);
+		value &= 0x00FCFFFF;
+		value |= 0x14010000;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				DENC_A_REG_4 + (0x100 * i), value);
+
+		value = cx25821_i2c_read(&dev->i2c_bus[0],
+				DENC_A_REG_5 + (0x100 * i), &tmp);
+		value &= 0xFFFF0000;
+		value |= 0x0000F078;
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				DENC_A_REG_5 + (0x100 * i), value);
+
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				DENC_A_REG_6 + (0x100 * i), 0x00A493CF);
+
+		/* Subcarrier Increment */
+		ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+				DENC_A_REG_7 + (0x100 * i), 0x2A098ACB);
+	}
+
+	/* set picture resolutions */
+	/* 0 - 720 */
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], HSCALE_CTRL, 0x0);
+	/* 0 - 576 */
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], VSCALE_CTRL, 0x0);
+
+	/* set Bypass input format to PAL 625 lines */
+	value = cx25821_i2c_read(&dev->i2c_bus[0], BYP_AB_CTRL, &tmp);
+	value &= 0xFFF7FDFF;
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value);
+
+	mutex_unlock(&dev->lock);
+
+	return ret_val;
+}
+
+int medusa_set_videostandard(struct cx25821_dev *dev)
+{
+	int status = STATUS_SUCCESS;
+	u32 value = 0, tmp = 0;
+
+	if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
+		status = medusa_initialize_pal(dev);
+	else
+		status = medusa_initialize_ntsc(dev);
+
+	/* Enable DENC_A output */
+	value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_A_REG_4, &tmp);
+	value = setBitAtPos(value, 4);
+	status = cx25821_i2c_write(&dev->i2c_bus[0], DENC_A_REG_4, value);
+
+	/* Enable DENC_B output */
+	value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_B_REG_4, &tmp);
+	value = setBitAtPos(value, 4);
+	status = cx25821_i2c_write(&dev->i2c_bus[0], DENC_B_REG_4, value);
+
+	return status;
+}
+
+void medusa_set_resolution(struct cx25821_dev *dev, int width,
+			   int decoder_select)
+{
+	int decoder = 0;
+	int decoder_count = 0;
+	u32 hscale = 0x0;
+	u32 vscale = 0x0;
+	const int MAX_WIDTH = 720;
+
+	mutex_lock(&dev->lock);
+
+	/* validate the width */
+	if (width > MAX_WIDTH) {
+		pr_info("%s(): width %d > MAX_WIDTH %d ! resetting to MAX_WIDTH\n",
+			__func__, width, MAX_WIDTH);
+		width = MAX_WIDTH;
+	}
+
+	if (decoder_select <= 7 && decoder_select >= 0) {
+		decoder = decoder_select;
+		decoder_count = decoder_select + 1;
+	} else {
+		decoder = 0;
+		decoder_count = _num_decoders;
+	}
+
+	switch (width) {
+	case 320:
+		hscale = 0x13E34B;
+		vscale = 0x0;
+		break;
+
+	case 352:
+		hscale = 0x10A273;
+		vscale = 0x0;
+		break;
+
+	case 176:
+		hscale = 0x3115B2;
+		vscale = 0x1E00;
+		break;
+
+	case 160:
+		hscale = 0x378D84;
+		vscale = 0x1E00;
+		break;
+
+	default:		/* 720 */
+		hscale = 0x0;
+		vscale = 0x0;
+		break;
+	}
+
+	for (; decoder < decoder_count; decoder++) {
+		/* write scaling values for each decoder */
+		cx25821_i2c_write(&dev->i2c_bus[0],
+				HSCALE_CTRL + (0x200 * decoder), hscale);
+		cx25821_i2c_write(&dev->i2c_bus[0],
+				VSCALE_CTRL + (0x200 * decoder), vscale);
+	}
+
+	mutex_unlock(&dev->lock);
+}
+
+static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder,
+				       int duration)
+{
+	u32 fld_cnt = 0;
+	u32 tmp = 0;
+	u32 disp_cnt_reg = DISP_AB_CNT;
+
+	mutex_lock(&dev->lock);
+
+	/* no support */
+	if (decoder < VDEC_A || decoder > VDEC_H) {
+		mutex_unlock(&dev->lock);
+		return;
+	}
+
+	switch (decoder) {
+	default:
+		break;
+	case VDEC_C:
+	case VDEC_D:
+		disp_cnt_reg = DISP_CD_CNT;
+		break;
+	case VDEC_E:
+	case VDEC_F:
+		disp_cnt_reg = DISP_EF_CNT;
+		break;
+	case VDEC_G:
+	case VDEC_H:
+		disp_cnt_reg = DISP_GH_CNT;
+		break;
+	}
+
+	_display_field_cnt[decoder] = duration;
+
+	/* update hardware */
+	fld_cnt = cx25821_i2c_read(&dev->i2c_bus[0], disp_cnt_reg, &tmp);
+
+	if (!(decoder % 2)) {	/* EVEN decoder */
+		fld_cnt &= 0xFFFF0000;
+		fld_cnt |= duration;
+	} else {
+		fld_cnt &= 0x0000FFFF;
+		fld_cnt |= ((u32) duration) << 16;
+	}
+
+	cx25821_i2c_write(&dev->i2c_bus[0], disp_cnt_reg, fld_cnt);
+
+	mutex_unlock(&dev->lock);
+}
+
+/* Map to Medusa register setting */
+static int mapM(int srcMin, int srcMax, int srcVal, int dstMin, int dstMax,
+		int *dstVal)
+{
+	int numerator;
+	int denominator;
+	int quotient;
+
+	if ((srcMin == srcMax) || (srcVal < srcMin) || (srcVal > srcMax))
+		return -1;
+	/*
+	 * This is the overall expression used:
+	 * *dstVal =
+	 *   (srcVal - srcMin)*(dstMax - dstMin) / (srcMax - srcMin) + dstMin;
+	 * but we need to account for rounding so below we use the modulus
+	 * operator to find the remainder and increment if necessary.
+	 */
+	numerator = (srcVal - srcMin) * (dstMax - dstMin);
+	denominator = srcMax - srcMin;
+	quotient = numerator / denominator;
+
+	if (2 * (numerator % denominator) >= denominator)
+		quotient++;
+
+	*dstVal = quotient + dstMin;
+
+	return 0;
+}
+
+static unsigned long convert_to_twos(long numeric, unsigned long bits_len)
+{
+	unsigned char temp;
+
+	if (numeric >= 0)
+		return numeric;
+	else {
+		temp = ~(abs(numeric) & 0xFF);
+		temp += 1;
+		return temp;
+	}
+}
+
+int medusa_set_brightness(struct cx25821_dev *dev, int brightness, int decoder)
+{
+	int ret_val = 0;
+	int value = 0;
+	u32 val = 0, tmp = 0;
+
+	mutex_lock(&dev->lock);
+	if ((brightness > VIDEO_PROCAMP_MAX) ||
+	    (brightness < VIDEO_PROCAMP_MIN)) {
+		mutex_unlock(&dev->lock);
+		return -1;
+	}
+	ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, brightness,
+			SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value);
+	value = convert_to_twos(value, 8);
+	val = cx25821_i2c_read(&dev->i2c_bus[0],
+			VDEC_A_BRITE_CTRL + (0x200 * decoder), &tmp);
+	val &= 0xFFFFFF00;
+	ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
+			VDEC_A_BRITE_CTRL + (0x200 * decoder), val | value);
+	mutex_unlock(&dev->lock);
+	return ret_val;
+}
+
+int medusa_set_contrast(struct cx25821_dev *dev, int contrast, int decoder)
+{
+	int ret_val = 0;
+	int value = 0;
+	u32 val = 0, tmp = 0;
+
+	mutex_lock(&dev->lock);
+
+	if ((contrast > VIDEO_PROCAMP_MAX) || (contrast < VIDEO_PROCAMP_MIN)) {
+		mutex_unlock(&dev->lock);
+		return -1;
+	}
+
+	ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, contrast,
+			UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value);
+	val = cx25821_i2c_read(&dev->i2c_bus[0],
+			VDEC_A_CNTRST_CTRL + (0x200 * decoder), &tmp);
+	val &= 0xFFFFFF00;
+	ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
+			VDEC_A_CNTRST_CTRL + (0x200 * decoder), val | value);
+
+	mutex_unlock(&dev->lock);
+	return ret_val;
+}
+
+int medusa_set_hue(struct cx25821_dev *dev, int hue, int decoder)
+{
+	int ret_val = 0;
+	int value = 0;
+	u32 val = 0, tmp = 0;
+
+	mutex_lock(&dev->lock);
+
+	if ((hue > VIDEO_PROCAMP_MAX) || (hue < VIDEO_PROCAMP_MIN)) {
+		mutex_unlock(&dev->lock);
+		return -1;
+	}
+
+	ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, hue,
+			SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value);
+
+	value = convert_to_twos(value, 8);
+	val = cx25821_i2c_read(&dev->i2c_bus[0],
+			VDEC_A_HUE_CTRL + (0x200 * decoder), &tmp);
+	val &= 0xFFFFFF00;
+
+	ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
+			VDEC_A_HUE_CTRL + (0x200 * decoder), val | value);
+
+	mutex_unlock(&dev->lock);
+	return ret_val;
+}
+
+int medusa_set_saturation(struct cx25821_dev *dev, int saturation, int decoder)
+{
+	int ret_val = 0;
+	int value = 0;
+	u32 val = 0, tmp = 0;
+
+	mutex_lock(&dev->lock);
+
+	if ((saturation > VIDEO_PROCAMP_MAX) ||
+	    (saturation < VIDEO_PROCAMP_MIN)) {
+		mutex_unlock(&dev->lock);
+		return -1;
+	}
+
+	ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, saturation,
+			UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value);
+
+	val = cx25821_i2c_read(&dev->i2c_bus[0],
+			VDEC_A_USAT_CTRL + (0x200 * decoder), &tmp);
+	val &= 0xFFFFFF00;
+	ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
+			VDEC_A_USAT_CTRL + (0x200 * decoder), val | value);
+
+	val = cx25821_i2c_read(&dev->i2c_bus[0],
+			VDEC_A_VSAT_CTRL + (0x200 * decoder), &tmp);
+	val &= 0xFFFFFF00;
+	ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
+			VDEC_A_VSAT_CTRL + (0x200 * decoder), val | value);
+
+	mutex_unlock(&dev->lock);
+	return ret_val;
+}
+
+/* Program the display sequence and monitor output. */
+
+int medusa_video_init(struct cx25821_dev *dev)
+{
+	u32 value = 0, tmp = 0;
+	int ret_val = 0;
+	int i = 0;
+
+	mutex_lock(&dev->lock);
+
+	_num_decoders = dev->_max_num_decoders;
+
+	/* disable Auto source selection on all video decoders */
+	value = cx25821_i2c_read(&dev->i2c_bus[0], MON_A_CTRL, &tmp);
+	value &= 0xFFFFF0FF;
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], MON_A_CTRL, value);
+
+	if (ret_val < 0)
+		goto error;
+
+	/* Turn off Master source switch enable */
+	value = cx25821_i2c_read(&dev->i2c_bus[0], MON_A_CTRL, &tmp);
+	value &= 0xFFFFFFDF;
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], MON_A_CTRL, value);
+
+	if (ret_val < 0)
+		goto error;
+
+	mutex_unlock(&dev->lock);
+
+	for (i = 0; i < _num_decoders; i++)
+		medusa_set_decoderduration(dev, i, _display_field_cnt[i]);
+
+	mutex_lock(&dev->lock);
+
+	/* Select monitor as DENC A input, power up the DAC */
+	value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_AB_CTRL, &tmp);
+	value &= 0xFF70FF70;
+	value |= 0x00090008;	/* set en_active */
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], DENC_AB_CTRL, value);
+
+	if (ret_val < 0)
+		goto error;
+
+	/* enable input is VIP/656 */
+	value = cx25821_i2c_read(&dev->i2c_bus[0], BYP_AB_CTRL, &tmp);
+	value |= 0x00040100;	/* enable VIP */
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value);
+
+	if (ret_val < 0)
+		goto error;
+
+	/* select AFE clock to output mode */
+	value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp);
+	value &= 0x83FFFFFF;
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL,
+			value | 0x10000000);
+
+	if (ret_val < 0)
+		goto error;
+
+	/* Turn on all of the data out and control output pins. */
+	value = cx25821_i2c_read(&dev->i2c_bus[0], PIN_OE_CTRL, &tmp);
+	value &= 0xFEF0FE00;
+	if (_num_decoders == MAX_DECODERS) {
+		/*
+		 * Note: The octal board does not support control pins(bit16-19)
+		 * These bits are ignored in the octal board.
+		 *
+		 * disable VDEC A-C port, default to Mobilygen Interface
+		 */
+		value |= 0x010001F8;
+	} else {
+		/* disable VDEC A-C port, default to Mobilygen Interface */
+		value |= 0x010F0108;
+	}
+
+	value |= 7;
+	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], PIN_OE_CTRL, value);
+
+	if (ret_val < 0)
+		goto error;
+
+
+	mutex_unlock(&dev->lock);
+
+	ret_val = medusa_set_videostandard(dev);
+
+	return ret_val;
+
+error:
+	mutex_unlock(&dev->lock);
+	return ret_val;
+}
diff --git a/drivers/media/pci/cx25821/cx25821-medusa-video.h b/drivers/media/pci/cx25821/cx25821-medusa-video.h
new file mode 100644
index 0000000..6175e09
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-medusa-video.h
@@ -0,0 +1,49 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _MEDUSA_VIDEO_H
+#define _MEDUSA_VIDEO_H
+
+#include "cx25821-medusa-defines.h"
+
+/* Color control constants */
+#define VIDEO_PROCAMP_MIN                 0
+#define VIDEO_PROCAMP_MAX                 10000
+#define UNSIGNED_BYTE_MIN                 0
+#define UNSIGNED_BYTE_MAX                 0xFF
+#define SIGNED_BYTE_MIN                   -128
+#define SIGNED_BYTE_MAX                   127
+
+/* Default video color settings */
+#define SHARPNESS_DEFAULT                 50
+#define SATURATION_DEFAULT              5000
+#define BRIGHTNESS_DEFAULT              6200
+#define CONTRAST_DEFAULT                5000
+#define HUE_DEFAULT                     5000
+
+unsigned short _num_decoders;
+unsigned short _num_cameras;
+
+unsigned int _video_standard;
+int _display_field_cnt[MAX_DECODERS];
+
+#endif
diff --git a/drivers/media/pci/cx25821/cx25821-reg.h b/drivers/media/pci/cx25821/cx25821-reg.h
new file mode 100644
index 0000000..a3fc25a
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-reg.h
@@ -0,0 +1,1592 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __CX25821_REGISTERS__
+#define __CX25821_REGISTERS__
+
+/* Risc Instructions */
+#define RISC_CNT_INC	 0x00010000
+#define RISC_CNT_RESET	 0x00030000
+#define RISC_IRQ1		 0x01000000
+#define RISC_IRQ2		 0x02000000
+#define RISC_EOL		 0x04000000
+#define RISC_SOL		 0x08000000
+#define RISC_WRITE		 0x10000000
+#define RISC_SKIP		 0x20000000
+#define RISC_JUMP		 0x70000000
+#define RISC_SYNC		 0x80000000
+#define RISC_RESYNC		 0x80008000
+#define RISC_READ		 0x90000000
+#define RISC_WRITERM	 0xB0000000
+#define RISC_WRITECM	 0xC0000000
+#define RISC_WRITECR	 0xD0000000
+#define RISC_WRITEC		 0x50000000
+#define RISC_READC		 0xA0000000
+
+#define RISC_SYNC_ODD		 0x00000000
+#define RISC_SYNC_EVEN		 0x00000200
+#define RISC_SYNC_ODD_VBI	 0x00000006
+#define RISC_SYNC_EVEN_VBI	 0x00000207
+#define RISC_NOOP			 0xF0000000
+
+/*****************************************************************************
+* ASB SRAM
+ *****************************************************************************/
+#define  TX_SRAM                   0x000000	/* Transmit SRAM */
+
+/*****************************************************************************/
+#define  RX_RAM                    0x010000	/* Receive SRAM */
+
+/*****************************************************************************
+* Application Layer (AL)
+ *****************************************************************************/
+#define  DEV_CNTRL2                0x040000	/* Device control */
+#define  FLD_RUN_RISC              0x00000020
+
+/* ***************************************************************************** */
+#define  PCI_INT_MSK               0x040010	/* PCI interrupt mask */
+#define  PCI_INT_STAT              0x040014	/* PCI interrupt status */
+#define  PCI_INT_MSTAT             0x040018	/* PCI interrupt masked status */
+#define  FLD_HAMMERHEAD_INT        (1 << 27)
+#define  FLD_UART_INT              (1 << 26)
+#define  FLD_IRQN_INT              (1 << 25)
+#define  FLD_TM_INT                (1 << 28)
+#define  FLD_I2C_3_RACK            (1 << 27)
+#define  FLD_I2C_3_INT             (1 << 26)
+#define  FLD_I2C_2_RACK            (1 << 25)
+#define  FLD_I2C_2_INT             (1 << 24)
+#define  FLD_I2C_1_RACK            (1 << 23)
+#define  FLD_I2C_1_INT             (1 << 22)
+
+#define  FLD_APB_DMA_BERR_INT      (1 << 21)
+#define  FLD_AL_WR_BERR_INT        (1 << 20)
+#define  FLD_AL_RD_BERR_INT        (1 << 19)
+#define  FLD_RISC_WR_BERR_INT      (1 << 18)
+#define  FLD_RISC_RD_BERR_INT      (1 << 17)
+
+#define  FLD_VID_I_INT             (1 << 8)
+#define  FLD_VID_H_INT             (1 << 7)
+#define  FLD_VID_G_INT             (1 << 6)
+#define  FLD_VID_F_INT             (1 << 5)
+#define  FLD_VID_E_INT             (1 << 4)
+#define  FLD_VID_D_INT             (1 << 3)
+#define  FLD_VID_C_INT             (1 << 2)
+#define  FLD_VID_B_INT             (1 << 1)
+#define  FLD_VID_A_INT             (1 << 0)
+
+/* ***************************************************************************** */
+#define  VID_A_INT_MSK             0x040020	/* Video A interrupt mask */
+#define  VID_A_INT_STAT            0x040024	/* Video A interrupt status */
+#define  VID_A_INT_MSTAT           0x040028	/* Video A interrupt masked status */
+#define  VID_A_INT_SSTAT           0x04002C	/* Video A interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_B_INT_MSK             0x040030	/* Video B interrupt mask */
+#define  VID_B_INT_STAT            0x040034	/* Video B interrupt status */
+#define  VID_B_INT_MSTAT           0x040038	/* Video B interrupt masked status */
+#define  VID_B_INT_SSTAT           0x04003C	/* Video B interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_C_INT_MSK             0x040040	/* Video C interrupt mask */
+#define  VID_C_INT_STAT            0x040044	/* Video C interrupt status */
+#define  VID_C_INT_MSTAT           0x040048	/* Video C interrupt masked status */
+#define  VID_C_INT_SSTAT           0x04004C	/* Video C interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_D_INT_MSK             0x040050	/* Video D interrupt mask */
+#define  VID_D_INT_STAT            0x040054	/* Video D interrupt status */
+#define  VID_D_INT_MSTAT           0x040058	/* Video D interrupt masked status */
+#define  VID_D_INT_SSTAT           0x04005C	/* Video D interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_E_INT_MSK             0x040060	/* Video E interrupt mask */
+#define  VID_E_INT_STAT            0x040064	/* Video E interrupt status */
+#define  VID_E_INT_MSTAT           0x040068	/* Video E interrupt masked status */
+#define  VID_E_INT_SSTAT           0x04006C	/* Video E interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_F_INT_MSK             0x040070	/* Video F interrupt mask */
+#define  VID_F_INT_STAT            0x040074	/* Video F interrupt status */
+#define  VID_F_INT_MSTAT           0x040078	/* Video F interrupt masked status */
+#define  VID_F_INT_SSTAT           0x04007C	/* Video F interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_G_INT_MSK             0x040080	/* Video G interrupt mask */
+#define  VID_G_INT_STAT            0x040084	/* Video G interrupt status */
+#define  VID_G_INT_MSTAT           0x040088	/* Video G interrupt masked status */
+#define  VID_G_INT_SSTAT           0x04008C	/* Video G interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_H_INT_MSK             0x040090	/* Video H interrupt mask */
+#define  VID_H_INT_STAT            0x040094	/* Video H interrupt status */
+#define  VID_H_INT_MSTAT           0x040098	/* Video H interrupt masked status */
+#define  VID_H_INT_SSTAT           0x04009C	/* Video H interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_I_INT_MSK             0x0400A0	/* Video I interrupt mask */
+#define  VID_I_INT_STAT            0x0400A4	/* Video I interrupt status */
+#define  VID_I_INT_MSTAT           0x0400A8	/* Video I interrupt masked status */
+#define  VID_I_INT_SSTAT           0x0400AC	/* Video I interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_J_INT_MSK             0x0400B0	/* Video J interrupt mask */
+#define  VID_J_INT_STAT            0x0400B4	/* Video J interrupt status */
+#define  VID_J_INT_MSTAT           0x0400B8	/* Video J interrupt masked status */
+#define  VID_J_INT_SSTAT           0x0400BC	/* Video J interrupt set status */
+
+#define  FLD_VID_SRC_OPC_ERR       0x00020000
+#define  FLD_VID_DST_OPC_ERR       0x00010000
+#define  FLD_VID_SRC_SYNC          0x00002000
+#define  FLD_VID_DST_SYNC          0x00001000
+#define  FLD_VID_SRC_UF            0x00000200
+#define  FLD_VID_DST_OF            0x00000100
+#define  FLD_VID_SRC_RISC2         0x00000020
+#define  FLD_VID_DST_RISC2         0x00000010
+#define  FLD_VID_SRC_RISC1         0x00000002
+#define  FLD_VID_DST_RISC1         0x00000001
+#define  FLD_VID_SRC_ERRORS		(FLD_VID_SRC_OPC_ERR | FLD_VID_SRC_SYNC | FLD_VID_SRC_UF)
+#define  FLD_VID_DST_ERRORS		(FLD_VID_DST_OPC_ERR | FLD_VID_DST_SYNC | FLD_VID_DST_OF)
+
+/* ***************************************************************************** */
+#define  AUD_A_INT_MSK             0x0400C0	/* Audio Int interrupt mask */
+#define  AUD_A_INT_STAT            0x0400C4	/* Audio Int interrupt status */
+#define  AUD_A_INT_MSTAT           0x0400C8	/* Audio Int interrupt masked status */
+#define  AUD_A_INT_SSTAT           0x0400CC	/* Audio Int interrupt set status */
+
+/* ***************************************************************************** */
+#define  AUD_B_INT_MSK             0x0400D0	/* Audio Int interrupt mask */
+#define  AUD_B_INT_STAT            0x0400D4	/* Audio Int interrupt status */
+#define  AUD_B_INT_MSTAT           0x0400D8	/* Audio Int interrupt masked status */
+#define  AUD_B_INT_SSTAT           0x0400DC	/* Audio Int interrupt set status */
+
+/* ***************************************************************************** */
+#define  AUD_C_INT_MSK             0x0400E0	/* Audio Int interrupt mask */
+#define  AUD_C_INT_STAT            0x0400E4	/* Audio Int interrupt status */
+#define  AUD_C_INT_MSTAT           0x0400E8	/* Audio Int interrupt masked status */
+#define  AUD_C_INT_SSTAT           0x0400EC	/* Audio Int interrupt set status */
+
+/* ***************************************************************************** */
+#define  AUD_D_INT_MSK             0x0400F0	/* Audio Int interrupt mask */
+#define  AUD_D_INT_STAT            0x0400F4	/* Audio Int interrupt status */
+#define  AUD_D_INT_MSTAT           0x0400F8	/* Audio Int interrupt masked status */
+#define  AUD_D_INT_SSTAT           0x0400FC	/* Audio Int interrupt set status */
+
+/* ***************************************************************************** */
+#define  AUD_E_INT_MSK             0x040100	/* Audio Int interrupt mask */
+#define  AUD_E_INT_STAT            0x040104	/* Audio Int interrupt status */
+#define  AUD_E_INT_MSTAT           0x040108	/* Audio Int interrupt masked status */
+#define  AUD_E_INT_SSTAT           0x04010C	/* Audio Int interrupt set status */
+
+#define  FLD_AUD_SRC_OPC_ERR       0x00020000
+#define  FLD_AUD_DST_OPC_ERR       0x00010000
+#define  FLD_AUD_SRC_SYNC          0x00002000
+#define  FLD_AUD_DST_SYNC          0x00001000
+#define  FLD_AUD_SRC_OF            0x00000200
+#define  FLD_AUD_DST_OF            0x00000100
+#define  FLD_AUD_SRC_RISCI2        0x00000020
+#define  FLD_AUD_DST_RISCI2        0x00000010
+#define  FLD_AUD_SRC_RISCI1        0x00000002
+#define  FLD_AUD_DST_RISCI1        0x00000001
+
+/* ***************************************************************************** */
+#define  MBIF_A_INT_MSK             0x040110	/* MBIF Int interrupt mask */
+#define  MBIF_A_INT_STAT            0x040114	/* MBIF Int interrupt status */
+#define  MBIF_A_INT_MSTAT           0x040118	/* MBIF Int interrupt masked status */
+#define  MBIF_A_INT_SSTAT           0x04011C	/* MBIF Int interrupt set status */
+
+/* ***************************************************************************** */
+#define  MBIF_B_INT_MSK             0x040120	/* MBIF Int interrupt mask */
+#define  MBIF_B_INT_STAT            0x040124	/* MBIF Int interrupt status */
+#define  MBIF_B_INT_MSTAT           0x040128	/* MBIF Int interrupt masked status */
+#define  MBIF_B_INT_SSTAT           0x04012C	/* MBIF Int interrupt set status */
+
+#define  FLD_MBIF_DST_OPC_ERR       0x00010000
+#define  FLD_MBIF_DST_SYNC          0x00001000
+#define  FLD_MBIF_DST_OF            0x00000100
+#define  FLD_MBIF_DST_RISCI2        0x00000010
+#define  FLD_MBIF_DST_RISCI1        0x00000001
+
+/* ***************************************************************************** */
+#define  AUD_EXT_INT_MSK           0x040060	/* Audio Ext interrupt mask */
+#define  AUD_EXT_INT_STAT          0x040064	/* Audio Ext interrupt status */
+#define  AUD_EXT_INT_MSTAT         0x040068	/* Audio Ext interrupt masked status */
+#define  AUD_EXT_INT_SSTAT         0x04006C	/* Audio Ext interrupt set status */
+#define  FLD_AUD_EXT_OPC_ERR       0x00010000
+#define  FLD_AUD_EXT_SYNC          0x00001000
+#define  FLD_AUD_EXT_OF            0x00000100
+#define  FLD_AUD_EXT_RISCI2        0x00000010
+#define  FLD_AUD_EXT_RISCI1        0x00000001
+
+/* ***************************************************************************** */
+#define  GPIO_LO                   0x110010	/* Lower  of GPIO pins [31:0] */
+#define  GPIO_HI                   0x110014	/* Upper WORD  of GPIO pins [47:31] */
+
+#define  GPIO_LO_OE                0x110018	/* Lower  of GPIO output enable [31:0] */
+#define  GPIO_HI_OE                0x11001C	/* Upper word  of GPIO output enable [47:32] */
+
+#define  GPIO_LO_INT_MSK           0x11003C	/* GPIO interrupt mask */
+#define  GPIO_LO_INT_STAT          0x110044	/* GPIO interrupt status */
+#define  GPIO_LO_INT_MSTAT         0x11004C	/* GPIO interrupt masked status */
+#define  GPIO_LO_ISM_SNS           0x110054	/* GPIO interrupt sensitivity */
+#define  GPIO_LO_ISM_POL           0x11005C	/* GPIO interrupt polarity */
+
+#define  GPIO_HI_INT_MSK           0x110040	/* GPIO interrupt mask */
+#define  GPIO_HI_INT_STAT          0x110048	/* GPIO interrupt status */
+#define  GPIO_HI_INT_MSTAT         0x110050	/* GPIO interrupt masked status */
+#define  GPIO_HI_ISM_SNS           0x110058	/* GPIO interrupt sensitivity */
+#define  GPIO_HI_ISM_POL           0x110060	/* GPIO interrupt polarity */
+
+#define  FLD_GPIO43_INT            (1 << 11)
+#define  FLD_GPIO42_INT            (1 << 10)
+#define  FLD_GPIO41_INT            (1 << 9)
+#define  FLD_GPIO40_INT            (1 << 8)
+
+#define  FLD_GPIO9_INT             (1 << 9)
+#define  FLD_GPIO8_INT             (1 << 8)
+#define  FLD_GPIO7_INT             (1 << 7)
+#define  FLD_GPIO6_INT             (1 << 6)
+#define  FLD_GPIO5_INT             (1 << 5)
+#define  FLD_GPIO4_INT             (1 << 4)
+#define  FLD_GPIO3_INT             (1 << 3)
+#define  FLD_GPIO2_INT             (1 << 2)
+#define  FLD_GPIO1_INT             (1 << 1)
+#define  FLD_GPIO0_INT             (1 << 0)
+
+/* ***************************************************************************** */
+#define  TC_REQ                    0x040090	/* Rider PCI Express traFFic class request */
+
+/* ***************************************************************************** */
+#define  TC_REQ_SET                0x040094	/* Rider PCI Express traFFic class request set */
+
+/* ***************************************************************************** */
+/* Rider */
+/* ***************************************************************************** */
+
+/* PCI Compatible Header */
+/* ***************************************************************************** */
+#define  RDR_CFG0                  0x050000
+#define  RDR_VENDOR_DEVICE_ID_CFG  0x050000
+
+/* ***************************************************************************** */
+#define  RDR_CFG1                  0x050004
+
+/* ***************************************************************************** */
+#define  RDR_CFG2                  0x050008
+
+/* ***************************************************************************** */
+#define  RDR_CFG3                  0x05000C
+
+/* ***************************************************************************** */
+#define  RDR_CFG4                  0x050010
+
+/* ***************************************************************************** */
+#define  RDR_CFG5                  0x050014
+
+/* ***************************************************************************** */
+#define  RDR_CFG6                  0x050018
+
+/* ***************************************************************************** */
+#define  RDR_CFG7                  0x05001C
+
+/* ***************************************************************************** */
+#define  RDR_CFG8                  0x050020
+
+/* ***************************************************************************** */
+#define  RDR_CFG9                  0x050024
+
+/* ***************************************************************************** */
+#define  RDR_CFGA                  0x050028
+
+/* ***************************************************************************** */
+#define  RDR_CFGB                  0x05002C
+#define  RDR_SUSSYSTEM_ID_CFG      0x05002C
+
+/* ***************************************************************************** */
+#define  RDR_CFGC                  0x050030
+
+/* ***************************************************************************** */
+#define  RDR_CFGD                  0x050034
+
+/* ***************************************************************************** */
+#define  RDR_CFGE                  0x050038
+
+/* ***************************************************************************** */
+#define  RDR_CFGF                  0x05003C
+
+/* ***************************************************************************** */
+/* PCI-Express Capabilities */
+/* ***************************************************************************** */
+#define  RDR_PECAP                 0x050040
+
+/* ***************************************************************************** */
+#define  RDR_PEDEVCAP              0x050044
+
+/* ***************************************************************************** */
+#define  RDR_PEDEVSC               0x050048
+
+/* ***************************************************************************** */
+#define  RDR_PELINKCAP             0x05004C
+
+/* ***************************************************************************** */
+#define  RDR_PELINKSC              0x050050
+
+/* ***************************************************************************** */
+#define  RDR_PMICAP                0x050080
+
+/* ***************************************************************************** */
+#define  RDR_PMCSR                 0x050084
+
+/* ***************************************************************************** */
+#define  RDR_VPDCAP                0x050090
+
+/* ***************************************************************************** */
+#define  RDR_VPDDATA               0x050094
+
+/* ***************************************************************************** */
+#define  RDR_MSICAP                0x0500A0
+
+/* ***************************************************************************** */
+#define  RDR_MSIARL                0x0500A4
+
+/* ***************************************************************************** */
+#define  RDR_MSIARU                0x0500A8
+
+/* ***************************************************************************** */
+#define  RDR_MSIDATA               0x0500AC
+
+/* ***************************************************************************** */
+/* PCI Express Extended Capabilities */
+/* ***************************************************************************** */
+#define  RDR_AERXCAP               0x050100
+
+/* ***************************************************************************** */
+#define  RDR_AERUESTA              0x050104
+
+/* ***************************************************************************** */
+#define  RDR_AERUEMSK              0x050108
+
+/* ***************************************************************************** */
+#define  RDR_AERUESEV              0x05010C
+
+/* ***************************************************************************** */
+#define  RDR_AERCESTA              0x050110
+
+/* ***************************************************************************** */
+#define  RDR_AERCEMSK              0x050114
+
+/* ***************************************************************************** */
+#define  RDR_AERCC                 0x050118
+
+/* ***************************************************************************** */
+#define  RDR_AERHL0                0x05011C
+
+/* ***************************************************************************** */
+#define  RDR_AERHL1                0x050120
+
+/* ***************************************************************************** */
+#define  RDR_AERHL2                0x050124
+
+/* ***************************************************************************** */
+#define  RDR_AERHL3                0x050128
+
+/* ***************************************************************************** */
+#define  RDR_VCXCAP                0x050200
+
+/* ***************************************************************************** */
+#define  RDR_VCCAP1                0x050204
+
+/* ***************************************************************************** */
+#define  RDR_VCCAP2                0x050208
+
+/* ***************************************************************************** */
+#define  RDR_VCSC                  0x05020C
+
+/* ***************************************************************************** */
+#define  RDR_VCR0_CAP              0x050210
+
+/* ***************************************************************************** */
+#define  RDR_VCR0_CTRL             0x050214
+
+/* ***************************************************************************** */
+#define  RDR_VCR0_STAT             0x050218
+
+/* ***************************************************************************** */
+#define  RDR_VCR1_CAP              0x05021C
+
+/* ***************************************************************************** */
+#define  RDR_VCR1_CTRL             0x050220
+
+/* ***************************************************************************** */
+#define  RDR_VCR1_STAT             0x050224
+
+/* ***************************************************************************** */
+#define  RDR_VCR2_CAP              0x050228
+
+/* ***************************************************************************** */
+#define  RDR_VCR2_CTRL             0x05022C
+
+/* ***************************************************************************** */
+#define  RDR_VCR2_STAT             0x050230
+
+/* ***************************************************************************** */
+#define  RDR_VCR3_CAP              0x050234
+
+/* ***************************************************************************** */
+#define  RDR_VCR3_CTRL             0x050238
+
+/* ***************************************************************************** */
+#define  RDR_VCR3_STAT             0x05023C
+
+/* ***************************************************************************** */
+#define  RDR_VCARB0                0x050240
+
+/* ***************************************************************************** */
+#define  RDR_VCARB1                0x050244
+
+/* ***************************************************************************** */
+#define  RDR_VCARB2                0x050248
+
+/* ***************************************************************************** */
+#define  RDR_VCARB3                0x05024C
+
+/* ***************************************************************************** */
+#define  RDR_VCARB4                0x050250
+
+/* ***************************************************************************** */
+#define  RDR_VCARB5                0x050254
+
+/* ***************************************************************************** */
+#define  RDR_VCARB6                0x050258
+
+/* ***************************************************************************** */
+#define  RDR_VCARB7                0x05025C
+
+/* ***************************************************************************** */
+#define  RDR_RDRSTAT0              0x050300
+
+/* ***************************************************************************** */
+#define  RDR_RDRSTAT1              0x050304
+
+/* ***************************************************************************** */
+#define  RDR_RDRCTL0               0x050308
+
+/* ***************************************************************************** */
+#define  RDR_RDRCTL1               0x05030C
+
+/* ***************************************************************************** */
+/* Transaction Layer Registers */
+/* ***************************************************************************** */
+#define  RDR_TLSTAT0               0x050310
+
+/* ***************************************************************************** */
+#define  RDR_TLSTAT1               0x050314
+
+/* ***************************************************************************** */
+#define  RDR_TLCTL0                0x050318
+#define  FLD_CFG_UR_CPL_MODE       0x00000040
+#define  FLD_CFG_CORR_ERR_QUITE    0x00000020
+#define  FLD_CFG_RCB_CK_EN         0x00000010
+#define  FLD_CFG_BNDRY_CK_EN       0x00000008
+#define  FLD_CFG_BYTE_EN_CK_EN     0x00000004
+#define  FLD_CFG_RELAX_ORDER_MSK   0x00000002
+#define  FLD_CFG_TAG_ORDER_EN      0x00000001
+
+/* ***************************************************************************** */
+#define  RDR_TLCTL1                0x05031C
+
+/* ***************************************************************************** */
+#define  RDR_REQRCAL               0x050320
+
+/* ***************************************************************************** */
+#define  RDR_REQRCAU               0x050324
+
+/* ***************************************************************************** */
+#define  RDR_REQEPA                0x050328
+
+/* ***************************************************************************** */
+#define  RDR_REQCTRL               0x05032C
+
+/* ***************************************************************************** */
+#define  RDR_REQSTAT               0x050330
+
+/* ***************************************************************************** */
+#define  RDR_TL_TEST               0x050334
+
+/* ***************************************************************************** */
+#define  RDR_VCR01_CTL             0x050348
+
+/* ***************************************************************************** */
+#define  RDR_VCR23_CTL             0x05034C
+
+/* ***************************************************************************** */
+#define  RDR_RX_VCR0_FC            0x050350
+
+/* ***************************************************************************** */
+#define  RDR_RX_VCR1_FC            0x050354
+
+/* ***************************************************************************** */
+#define  RDR_RX_VCR2_FC            0x050358
+
+/* ***************************************************************************** */
+#define  RDR_RX_VCR3_FC            0x05035C
+
+/* ***************************************************************************** */
+/* Data Link Layer Registers */
+/* ***************************************************************************** */
+#define  RDR_DLLSTAT               0x050360
+
+/* ***************************************************************************** */
+#define  RDR_DLLCTRL               0x050364
+
+/* ***************************************************************************** */
+#define  RDR_REPLAYTO              0x050368
+
+/* ***************************************************************************** */
+#define  RDR_ACKLATTO              0x05036C
+
+/* ***************************************************************************** */
+/* MAC Layer Registers */
+/* ***************************************************************************** */
+#define  RDR_MACSTAT0              0x050380
+
+/* ***************************************************************************** */
+#define  RDR_MACSTAT1              0x050384
+
+/* ***************************************************************************** */
+#define  RDR_MACCTRL0              0x050388
+
+/* ***************************************************************************** */
+#define  RDR_MACCTRL1              0x05038C
+
+/* ***************************************************************************** */
+#define  RDR_MACCTRL2              0x050390
+
+/* ***************************************************************************** */
+#define  RDR_MAC_LB_DATA           0x050394
+
+/* ***************************************************************************** */
+#define  RDR_L0S_EXIT_LAT          0x050398
+
+/* ***************************************************************************** */
+/* DMAC */
+/* ***************************************************************************** */
+#define  DMA1_PTR1                 0x100000	/* DMA Current Ptr : Ch#1 */
+
+/* ***************************************************************************** */
+#define  DMA2_PTR1                 0x100004	/* DMA Current Ptr : Ch#2 */
+
+/* ***************************************************************************** */
+#define  DMA3_PTR1                 0x100008	/* DMA Current Ptr : Ch#3 */
+
+/* ***************************************************************************** */
+#define  DMA4_PTR1                 0x10000C	/* DMA Current Ptr : Ch#4 */
+
+/* ***************************************************************************** */
+#define  DMA5_PTR1                 0x100010	/* DMA Current Ptr : Ch#5 */
+
+/* ***************************************************************************** */
+#define  DMA6_PTR1                 0x100014	/* DMA Current Ptr : Ch#6 */
+
+/* ***************************************************************************** */
+#define  DMA7_PTR1                 0x100018	/* DMA Current Ptr : Ch#7 */
+
+/* ***************************************************************************** */
+#define  DMA8_PTR1                 0x10001C	/* DMA Current Ptr : Ch#8 */
+
+/* ***************************************************************************** */
+#define  DMA9_PTR1                 0x100020	/* DMA Current Ptr : Ch#9 */
+
+/* ***************************************************************************** */
+#define  DMA10_PTR1                0x100024	/* DMA Current Ptr : Ch#10 */
+
+/* ***************************************************************************** */
+#define  DMA11_PTR1                0x100028	/* DMA Current Ptr : Ch#11 */
+
+/* ***************************************************************************** */
+#define  DMA12_PTR1                0x10002C	/* DMA Current Ptr : Ch#12 */
+
+/* ***************************************************************************** */
+#define  DMA13_PTR1                0x100030	/* DMA Current Ptr : Ch#13 */
+
+/* ***************************************************************************** */
+#define  DMA14_PTR1                0x100034	/* DMA Current Ptr : Ch#14 */
+
+/* ***************************************************************************** */
+#define  DMA15_PTR1                0x100038	/* DMA Current Ptr : Ch#15 */
+
+/* ***************************************************************************** */
+#define  DMA16_PTR1                0x10003C	/* DMA Current Ptr : Ch#16 */
+
+/* ***************************************************************************** */
+#define  DMA17_PTR1                0x100040	/* DMA Current Ptr : Ch#17 */
+
+/* ***************************************************************************** */
+#define  DMA18_PTR1                0x100044	/* DMA Current Ptr : Ch#18 */
+
+/* ***************************************************************************** */
+#define  DMA19_PTR1                0x100048	/* DMA Current Ptr : Ch#19 */
+
+/* ***************************************************************************** */
+#define  DMA20_PTR1                0x10004C	/* DMA Current Ptr : Ch#20 */
+
+/* ***************************************************************************** */
+#define  DMA21_PTR1                0x100050	/* DMA Current Ptr : Ch#21 */
+
+/* ***************************************************************************** */
+#define  DMA22_PTR1                0x100054	/* DMA Current Ptr : Ch#22 */
+
+/* ***************************************************************************** */
+#define  DMA23_PTR1                0x100058	/* DMA Current Ptr : Ch#23 */
+
+/* ***************************************************************************** */
+#define  DMA24_PTR1                0x10005C	/* DMA Current Ptr : Ch#24 */
+
+/* ***************************************************************************** */
+#define  DMA25_PTR1                0x100060	/* DMA Current Ptr : Ch#25 */
+
+/* ***************************************************************************** */
+#define  DMA26_PTR1                0x100064	/* DMA Current Ptr : Ch#26 */
+
+/* ***************************************************************************** */
+#define  DMA1_PTR2                 0x100080	/* DMA Tab Ptr : Ch#1 */
+
+/* ***************************************************************************** */
+#define  DMA2_PTR2                 0x100084	/* DMA Tab Ptr : Ch#2 */
+
+/* ***************************************************************************** */
+#define  DMA3_PTR2                 0x100088	/* DMA Tab Ptr : Ch#3 */
+
+/* ***************************************************************************** */
+#define  DMA4_PTR2                 0x10008C	/* DMA Tab Ptr : Ch#4 */
+
+/* ***************************************************************************** */
+#define  DMA5_PTR2                 0x100090	/* DMA Tab Ptr : Ch#5 */
+
+/* ***************************************************************************** */
+#define  DMA6_PTR2                 0x100094	/* DMA Tab Ptr : Ch#6 */
+
+/* ***************************************************************************** */
+#define  DMA7_PTR2                 0x100098	/* DMA Tab Ptr : Ch#7 */
+
+/* ***************************************************************************** */
+#define  DMA8_PTR2                 0x10009C	/* DMA Tab Ptr : Ch#8 */
+
+/* ***************************************************************************** */
+#define  DMA9_PTR2                 0x1000A0	/* DMA Tab Ptr : Ch#9 */
+
+/* ***************************************************************************** */
+#define  DMA10_PTR2                0x1000A4	/* DMA Tab Ptr : Ch#10 */
+
+/* ***************************************************************************** */
+#define  DMA11_PTR2                0x1000A8	/* DMA Tab Ptr : Ch#11 */
+
+/* ***************************************************************************** */
+#define  DMA12_PTR2                0x1000AC	/* DMA Tab Ptr : Ch#12 */
+
+/* ***************************************************************************** */
+#define  DMA13_PTR2                0x1000B0	/* DMA Tab Ptr : Ch#13 */
+
+/* ***************************************************************************** */
+#define  DMA14_PTR2                0x1000B4	/* DMA Tab Ptr : Ch#14 */
+
+/* ***************************************************************************** */
+#define  DMA15_PTR2                0x1000B8	/* DMA Tab Ptr : Ch#15 */
+
+/* ***************************************************************************** */
+#define  DMA16_PTR2                0x1000BC	/* DMA Tab Ptr : Ch#16 */
+
+/* ***************************************************************************** */
+#define  DMA17_PTR2                0x1000C0	/* DMA Tab Ptr : Ch#17 */
+
+/* ***************************************************************************** */
+#define  DMA18_PTR2                0x1000C4	/* DMA Tab Ptr : Ch#18 */
+
+/* ***************************************************************************** */
+#define  DMA19_PTR2                0x1000C8	/* DMA Tab Ptr : Ch#19 */
+
+/* ***************************************************************************** */
+#define  DMA20_PTR2                0x1000CC	/* DMA Tab Ptr : Ch#20 */
+
+/* ***************************************************************************** */
+#define  DMA21_PTR2                0x1000D0	/* DMA Tab Ptr : Ch#21 */
+
+/* ***************************************************************************** */
+#define  DMA22_PTR2                0x1000D4	/* DMA Tab Ptr : Ch#22 */
+
+/* ***************************************************************************** */
+#define  DMA23_PTR2                0x1000D8	/* DMA Tab Ptr : Ch#23 */
+
+/* ***************************************************************************** */
+#define  DMA24_PTR2                0x1000DC	/* DMA Tab Ptr : Ch#24 */
+
+/* ***************************************************************************** */
+#define  DMA25_PTR2                0x1000E0	/* DMA Tab Ptr : Ch#25 */
+
+/* ***************************************************************************** */
+#define  DMA26_PTR2                0x1000E4	/* DMA Tab Ptr : Ch#26 */
+
+/* ***************************************************************************** */
+#define  DMA1_CNT1                 0x100100	/* DMA BuFFer Size : Ch#1 */
+
+/* ***************************************************************************** */
+#define  DMA2_CNT1                 0x100104	/* DMA BuFFer Size : Ch#2 */
+
+/* ***************************************************************************** */
+#define  DMA3_CNT1                 0x100108	/* DMA BuFFer Size : Ch#3 */
+
+/* ***************************************************************************** */
+#define  DMA4_CNT1                 0x10010C	/* DMA BuFFer Size : Ch#4 */
+
+/* ***************************************************************************** */
+#define  DMA5_CNT1                 0x100110	/* DMA BuFFer Size : Ch#5 */
+
+/* ***************************************************************************** */
+#define  DMA6_CNT1                 0x100114	/* DMA BuFFer Size : Ch#6 */
+
+/* ***************************************************************************** */
+#define  DMA7_CNT1                 0x100118	/* DMA BuFFer Size : Ch#7 */
+
+/* ***************************************************************************** */
+#define  DMA8_CNT1                 0x10011C	/* DMA BuFFer Size : Ch#8 */
+
+/* ***************************************************************************** */
+#define  DMA9_CNT1                 0x100120	/* DMA BuFFer Size : Ch#9 */
+
+/* ***************************************************************************** */
+#define  DMA10_CNT1                0x100124	/* DMA BuFFer Size : Ch#10 */
+
+/* ***************************************************************************** */
+#define  DMA11_CNT1                0x100128	/* DMA BuFFer Size : Ch#11 */
+
+/* ***************************************************************************** */
+#define  DMA12_CNT1                0x10012C	/* DMA BuFFer Size : Ch#12 */
+
+/* ***************************************************************************** */
+#define  DMA13_CNT1                0x100130	/* DMA BuFFer Size : Ch#13 */
+
+/* ***************************************************************************** */
+#define  DMA14_CNT1                0x100134	/* DMA BuFFer Size : Ch#14 */
+
+/* ***************************************************************************** */
+#define  DMA15_CNT1                0x100138	/* DMA BuFFer Size : Ch#15 */
+
+/* ***************************************************************************** */
+#define  DMA16_CNT1                0x10013C	/* DMA BuFFer Size : Ch#16 */
+
+/* ***************************************************************************** */
+#define  DMA17_CNT1                0x100140	/* DMA BuFFer Size : Ch#17 */
+
+/* ***************************************************************************** */
+#define  DMA18_CNT1                0x100144	/* DMA BuFFer Size : Ch#18 */
+
+/* ***************************************************************************** */
+#define  DMA19_CNT1                0x100148	/* DMA BuFFer Size : Ch#19 */
+
+/* ***************************************************************************** */
+#define  DMA20_CNT1                0x10014C	/* DMA BuFFer Size : Ch#20 */
+
+/* ***************************************************************************** */
+#define  DMA21_CNT1                0x100150	/* DMA BuFFer Size : Ch#21 */
+
+/* ***************************************************************************** */
+#define  DMA22_CNT1                0x100154	/* DMA BuFFer Size : Ch#22 */
+
+/* ***************************************************************************** */
+#define  DMA23_CNT1                0x100158	/* DMA BuFFer Size : Ch#23 */
+
+/* ***************************************************************************** */
+#define  DMA24_CNT1                0x10015C	/* DMA BuFFer Size : Ch#24 */
+
+/* ***************************************************************************** */
+#define  DMA25_CNT1                0x100160	/* DMA BuFFer Size : Ch#25 */
+
+/* ***************************************************************************** */
+#define  DMA26_CNT1                0x100164	/* DMA BuFFer Size : Ch#26 */
+
+/* ***************************************************************************** */
+#define  DMA1_CNT2                 0x100180	/* DMA Table Size : Ch#1 */
+
+/* ***************************************************************************** */
+#define  DMA2_CNT2                 0x100184	/* DMA Table Size : Ch#2 */
+
+/* ***************************************************************************** */
+#define  DMA3_CNT2                 0x100188	/* DMA Table Size : Ch#3 */
+
+/* ***************************************************************************** */
+#define  DMA4_CNT2                 0x10018C	/* DMA Table Size : Ch#4 */
+
+/* ***************************************************************************** */
+#define  DMA5_CNT2                 0x100190	/* DMA Table Size : Ch#5 */
+
+/* ***************************************************************************** */
+#define  DMA6_CNT2                 0x100194	/* DMA Table Size : Ch#6 */
+
+/* ***************************************************************************** */
+#define  DMA7_CNT2                 0x100198	/* DMA Table Size : Ch#7 */
+
+/* ***************************************************************************** */
+#define  DMA8_CNT2                 0x10019C	/* DMA Table Size : Ch#8 */
+
+/* ***************************************************************************** */
+#define  DMA9_CNT2                 0x1001A0	/* DMA Table Size : Ch#9 */
+
+/* ***************************************************************************** */
+#define  DMA10_CNT2                0x1001A4	/* DMA Table Size : Ch#10 */
+
+/* ***************************************************************************** */
+#define  DMA11_CNT2                0x1001A8	/* DMA Table Size : Ch#11 */
+
+/* ***************************************************************************** */
+#define  DMA12_CNT2                0x1001AC	/* DMA Table Size : Ch#12 */
+
+/* ***************************************************************************** */
+#define  DMA13_CNT2                0x1001B0	/* DMA Table Size : Ch#13 */
+
+/* ***************************************************************************** */
+#define  DMA14_CNT2                0x1001B4	/* DMA Table Size : Ch#14 */
+
+/* ***************************************************************************** */
+#define  DMA15_CNT2                0x1001B8	/* DMA Table Size : Ch#15 */
+
+/* ***************************************************************************** */
+#define  DMA16_CNT2                0x1001BC	/* DMA Table Size : Ch#16 */
+
+/* ***************************************************************************** */
+#define  DMA17_CNT2                0x1001C0	/* DMA Table Size : Ch#17 */
+
+/* ***************************************************************************** */
+#define  DMA18_CNT2                0x1001C4	/* DMA Table Size : Ch#18 */
+
+/* ***************************************************************************** */
+#define  DMA19_CNT2                0x1001C8	/* DMA Table Size : Ch#19 */
+
+/* ***************************************************************************** */
+#define  DMA20_CNT2                0x1001CC	/* DMA Table Size : Ch#20 */
+
+/* ***************************************************************************** */
+#define  DMA21_CNT2                0x1001D0	/* DMA Table Size : Ch#21 */
+
+/* ***************************************************************************** */
+#define  DMA22_CNT2                0x1001D4	/* DMA Table Size : Ch#22 */
+
+/* ***************************************************************************** */
+#define  DMA23_CNT2                0x1001D8	/* DMA Table Size : Ch#23 */
+
+/* ***************************************************************************** */
+#define  DMA24_CNT2                0x1001DC	/* DMA Table Size : Ch#24 */
+
+/* ***************************************************************************** */
+#define  DMA25_CNT2                0x1001E0	/* DMA Table Size : Ch#25 */
+
+/* ***************************************************************************** */
+#define  DMA26_CNT2                0x1001E4	/* DMA Table Size : Ch#26 */
+
+/* ***************************************************************************** */
+ /* ITG */
+/* ***************************************************************************** */
+#define  TM_CNT_LDW                0x110000	/* Timer : Counter low */
+
+/* ***************************************************************************** */
+#define  TM_CNT_UW                 0x110004	/* Timer : Counter high word */
+
+/* ***************************************************************************** */
+#define  TM_LMT_LDW                0x110008	/* Timer : Limit low */
+
+/* ***************************************************************************** */
+#define  TM_LMT_UW                 0x11000C	/* Timer : Limit high word */
+
+/* ***************************************************************************** */
+#define  GP0_IO                    0x110010	/* GPIO output enables data I/O */
+#define  FLD_GP_OE                 0x00FF0000	/* GPIO: GP_OE output enable */
+#define  FLD_GP_IN                 0x0000FF00	/* GPIO: GP_IN status */
+#define  FLD_GP_OUT                0x000000FF	/* GPIO: GP_OUT control */
+
+/* ***************************************************************************** */
+#define  GPIO_ISM                  0x110014	/* GPIO interrupt sensitivity mode */
+#define  FLD_GP_ISM_SNS            0x00000070
+#define  FLD_GP_ISM_POL            0x00000007
+
+/* ***************************************************************************** */
+#define  SOFT_RESET                0x11001C	/* Output system reset reg */
+#define  FLD_PECOS_SOFT_RESET      0x00000001
+
+/* ***************************************************************************** */
+#define  MC416_RWD                 0x110020	/* MC416 GPIO[18:3] pin */
+#define  MC416_OEN                 0x110024	/* Output enable of GPIO[18:3] */
+#define  MC416_CTL                 0x110028
+
+/* ***************************************************************************** */
+#define  ALT_PIN_OUT_SEL           0x11002C	/* Alternate GPIO output select */
+
+#define  FLD_ALT_GPIO_OUT_SEL      0xF0000000
+/* 0          Disabled <-- default */
+/* 1          GPIO[0] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
+/* 8          ATT_IF */
+
+#define  FLD_AUX_PLL_CLK_ALT_SEL   0x0F000000
+/* 0          AUX_PLL_CLK<-- default */
+/* 1          GPIO[2] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
+
+#define  FLD_IR_TX_ALT_SEL         0x00F00000
+/* 0          IR_TX <-- default */
+/* 1          GPIO[1] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
+
+#define  FLD_IR_RX_ALT_SEL         0x000F0000
+/* 0          IR_RX <-- default */
+/* 1          GPIO[0] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
+
+#define  FLD_GPIO10_ALT_SEL        0x0000F000
+/* 0          GPIO[10] <-- default */
+/* 1          GPIO[0] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
+
+#define  FLD_GPIO2_ALT_SEL         0x00000F00
+/* 0          GPIO[2] <-- default */
+/* 1          GPIO[1] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
+
+#define  FLD_GPIO1_ALT_SEL         0x000000F0
+/* 0          GPIO[1] <-- default */
+/* 1          GPIO[0] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
+
+#define  FLD_GPIO0_ALT_SEL         0x0000000F
+/* 0          GPIO[0] <-- default */
+/* 1          GPIO[1] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
+
+#define  ALT_PIN_IN_SEL            0x110030	/* Alternate GPIO input select */
+
+#define  FLD_GPIO10_ALT_IN_SEL     0x0000F000
+/* 0          GPIO[10] <-- default */
+/* 1          IR_RX */
+/* 2          IR_TX */
+/* 3          AUX_PLL_CLK */
+/* 4          IF_ATT_SEL */
+/* 5          GPIO[0] */
+/* 6          GPIO[1] */
+/* 7          GPIO[2] */
+
+#define  FLD_GPIO2_ALT_IN_SEL      0x00000F00
+/* 0          GPIO[2] <-- default */
+/* 1          IR_RX */
+/* 2          IR_TX */
+/* 3          AUX_PLL_CLK */
+/* 4          IF_ATT_SEL */
+
+#define  FLD_GPIO1_ALT_IN_SEL      0x000000F0
+/* 0          GPIO[1] <-- default */
+/* 1          IR_RX */
+/* 2          IR_TX */
+/* 3          AUX_PLL_CLK */
+/* 4          IF_ATT_SEL */
+
+#define  FLD_GPIO0_ALT_IN_SEL      0x0000000F
+/* 0          GPIO[0] <-- default */
+/* 1          IR_RX */
+/* 2          IR_TX */
+/* 3          AUX_PLL_CLK */
+/* 4          IF_ATT_SEL */
+
+/* ***************************************************************************** */
+#define  TEST_BUS_CTL1             0x110040	/* Test bus control register #1 */
+
+/* ***************************************************************************** */
+#define  TEST_BUS_CTL2             0x110044	/* Test bus control register #2 */
+
+/* ***************************************************************************** */
+#define  CLK_DELAY                 0x110048	/* Clock delay */
+#define  FLD_MOE_CLK_DIS           0x80000000	/* Disable MoE clock */
+
+/* ***************************************************************************** */
+#define  PAD_CTRL                  0x110068	/* Pad drive strength control */
+
+/* ***************************************************************************** */
+#define  MBIST_CTRL                0x110050	/* SRAM memory built-in self test control */
+
+/* ***************************************************************************** */
+#define  MBIST_STAT                0x110054	/* SRAM memory built-in self test status */
+
+/* ***************************************************************************** */
+/* PLL registers */
+/* ***************************************************************************** */
+#define  PLL_A_INT_FRAC            0x110088
+#define  PLL_A_POST_STAT_BIST      0x11008C
+#define  PLL_B_INT_FRAC            0x110090
+#define  PLL_B_POST_STAT_BIST      0x110094
+#define  PLL_C_INT_FRAC            0x110098
+#define  PLL_C_POST_STAT_BIST      0x11009C
+#define  PLL_D_INT_FRAC            0x1100A0
+#define  PLL_D_POST_STAT_BIST      0x1100A4
+
+#define  CLK_RST                   0x11002C
+#define  FLD_VID_I_CLK_NOE         0x00001000
+#define  FLD_VID_J_CLK_NOE         0x00002000
+#define  FLD_USE_ALT_PLL_REF       0x00004000
+
+#define  VID_CH_MODE_SEL           0x110078
+#define  VID_CH_CLK_SEL            0x11007C
+
+/* ***************************************************************************** */
+#define  VBI_A_DMA                 0x130008	/* VBI A DMA data port */
+
+/* ***************************************************************************** */
+#define  VID_A_VIP_CTL             0x130080	/* Video A VIP format control */
+#define  FLD_VIP_MODE              0x00000001
+
+/* ***************************************************************************** */
+#define  VID_A_PIXEL_FRMT          0x130084	/* Video A pixel format */
+#define  FLD_VID_A_GAMMA_DIS       0x00000008
+#define  FLD_VID_A_FORMAT          0x00000007
+#define  FLD_VID_A_GAMMA_FACTOR    0x00000010
+
+/* ***************************************************************************** */
+#define  VID_A_VBI_CTL             0x130088	/* Video A VBI miscellaneous control */
+#define  FLD_VID_A_VIP_EXT         0x00000003
+
+/* ***************************************************************************** */
+#define  VID_B_DMA                 0x130100	/* Video B DMA data port */
+
+/* ***************************************************************************** */
+#define  VBI_B_DMA                 0x130108	/* VBI B DMA data port */
+
+/* ***************************************************************************** */
+#define  VID_B_SRC_SEL             0x130144	/* Video B source select */
+#define  FLD_VID_B_SRC_SEL         0x00000000
+
+/* ***************************************************************************** */
+#define  VID_B_LNGTH               0x130150	/* Video B line length */
+#define  FLD_VID_B_LN_LNGTH        0x00000FFF
+
+/* ***************************************************************************** */
+#define  VID_B_VIP_CTL             0x130180	/* Video B VIP format control */
+
+/* ***************************************************************************** */
+#define  VID_B_PIXEL_FRMT          0x130184	/* Video B pixel format */
+#define  FLD_VID_B_GAMMA_DIS       0x00000008
+#define  FLD_VID_B_FORMAT          0x00000007
+#define  FLD_VID_B_GAMMA_FACTOR    0x00000010
+
+/* ***************************************************************************** */
+#define  VID_C_DMA                 0x130200	/* Video C DMA data port */
+
+/* ***************************************************************************** */
+#define  VID_C_LNGTH               0x130250	/* Video C line length */
+#define  FLD_VID_C_LN_LNGTH        0x00000FFF
+
+/* ***************************************************************************** */
+/* Video Destination Channels */
+/* ***************************************************************************** */
+
+#define  VID_DST_A_GPCNT           0x130020	/* Video A general purpose counter */
+#define  VID_DST_B_GPCNT           0x130120	/* Video B general purpose counter */
+#define  VID_DST_C_GPCNT           0x130220	/* Video C general purpose counter */
+#define  VID_DST_D_GPCNT           0x130320	/* Video D general purpose counter */
+#define  VID_DST_E_GPCNT           0x130420	/* Video E general purpose counter */
+#define  VID_DST_F_GPCNT           0x130520	/* Video F general purpose counter */
+#define  VID_DST_G_GPCNT           0x130620	/* Video G general purpose counter */
+#define  VID_DST_H_GPCNT           0x130720	/* Video H general purpose counter */
+
+/* ***************************************************************************** */
+
+#define  VID_DST_A_GPCNT_CTL       0x130030	/* Video A general purpose control */
+#define  VID_DST_B_GPCNT_CTL       0x130130	/* Video B general purpose control */
+#define  VID_DST_C_GPCNT_CTL       0x130230	/* Video C general purpose control */
+#define  VID_DST_D_GPCNT_CTL       0x130330	/* Video D general purpose control */
+#define  VID_DST_E_GPCNT_CTL       0x130430	/* Video E general purpose control */
+#define  VID_DST_F_GPCNT_CTL       0x130530	/* Video F general purpose control */
+#define  VID_DST_G_GPCNT_CTL       0x130630	/* Video G general purpose control */
+#define  VID_DST_H_GPCNT_CTL       0x130730	/* Video H general purpose control */
+
+/* ***************************************************************************** */
+
+#define  VID_DST_A_DMA_CTL         0x130040	/* Video A DMA control */
+#define  VID_DST_B_DMA_CTL         0x130140	/* Video B DMA control */
+#define  VID_DST_C_DMA_CTL         0x130240	/* Video C DMA control */
+#define  VID_DST_D_DMA_CTL         0x130340	/* Video D DMA control */
+#define  VID_DST_E_DMA_CTL         0x130440	/* Video E DMA control */
+#define  VID_DST_F_DMA_CTL         0x130540	/* Video F DMA control */
+#define  VID_DST_G_DMA_CTL         0x130640	/* Video G DMA control */
+#define  VID_DST_H_DMA_CTL         0x130740	/* Video H DMA control */
+
+#define  FLD_VID_RISC_EN           0x00000010
+#define  FLD_VID_FIFO_EN           0x00000001
+
+/* ***************************************************************************** */
+
+#define  VID_DST_A_VIP_CTL         0x130080	/* Video A VIP control */
+#define  VID_DST_B_VIP_CTL         0x130180	/* Video B VIP control */
+#define  VID_DST_C_VIP_CTL         0x130280	/* Video C VIP control */
+#define  VID_DST_D_VIP_CTL         0x130380	/* Video D VIP control */
+#define  VID_DST_E_VIP_CTL         0x130480	/* Video E VIP control */
+#define  VID_DST_F_VIP_CTL         0x130580	/* Video F VIP control */
+#define  VID_DST_G_VIP_CTL         0x130680	/* Video G VIP control */
+#define  VID_DST_H_VIP_CTL         0x130780	/* Video H VIP control */
+
+/* ***************************************************************************** */
+
+#define  VID_DST_A_PIX_FRMT        0x130084	/* Video A Pixel format */
+#define  VID_DST_B_PIX_FRMT        0x130184	/* Video B Pixel format */
+#define  VID_DST_C_PIX_FRMT        0x130284	/* Video C Pixel format */
+#define  VID_DST_D_PIX_FRMT        0x130384	/* Video D Pixel format */
+#define  VID_DST_E_PIX_FRMT        0x130484	/* Video E Pixel format */
+#define  VID_DST_F_PIX_FRMT        0x130584	/* Video F Pixel format */
+#define  VID_DST_G_PIX_FRMT        0x130684	/* Video G Pixel format */
+#define  VID_DST_H_PIX_FRMT        0x130784	/* Video H Pixel format */
+
+/* ***************************************************************************** */
+/* Video Source Channels */
+/* ***************************************************************************** */
+
+#define  VID_SRC_A_GPCNT_CTL       0x130804	/* Video A general purpose control */
+#define  VID_SRC_B_GPCNT_CTL       0x130904	/* Video B general purpose control */
+#define  VID_SRC_C_GPCNT_CTL       0x130A04	/* Video C general purpose control */
+#define  VID_SRC_D_GPCNT_CTL       0x130B04	/* Video D general purpose control */
+#define  VID_SRC_E_GPCNT_CTL       0x130C04	/* Video E general purpose control */
+#define  VID_SRC_F_GPCNT_CTL       0x130D04	/* Video F general purpose control */
+#define  VID_SRC_I_GPCNT_CTL       0x130E04	/* Video I general purpose control */
+#define  VID_SRC_J_GPCNT_CTL       0x130F04	/* Video J general purpose control */
+
+/* ***************************************************************************** */
+
+#define  VID_SRC_A_GPCNT           0x130808	/* Video A general purpose counter */
+#define  VID_SRC_B_GPCNT           0x130908	/* Video B general purpose counter */
+#define  VID_SRC_C_GPCNT           0x130A08	/* Video C general purpose counter */
+#define  VID_SRC_D_GPCNT           0x130B08	/* Video D general purpose counter */
+#define  VID_SRC_E_GPCNT           0x130C08	/* Video E general purpose counter */
+#define  VID_SRC_F_GPCNT           0x130D08	/* Video F general purpose counter */
+#define  VID_SRC_I_GPCNT           0x130E08	/* Video I general purpose counter */
+#define  VID_SRC_J_GPCNT           0x130F08	/* Video J general purpose counter */
+
+/* ***************************************************************************** */
+
+#define  VID_SRC_A_DMA_CTL         0x13080C	/* Video A DMA control */
+#define  VID_SRC_B_DMA_CTL         0x13090C	/* Video B DMA control */
+#define  VID_SRC_C_DMA_CTL         0x130A0C	/* Video C DMA control */
+#define  VID_SRC_D_DMA_CTL         0x130B0C	/* Video D DMA control */
+#define  VID_SRC_E_DMA_CTL         0x130C0C	/* Video E DMA control */
+#define  VID_SRC_F_DMA_CTL         0x130D0C	/* Video F DMA control */
+#define  VID_SRC_I_DMA_CTL         0x130E0C	/* Video I DMA control */
+#define  VID_SRC_J_DMA_CTL         0x130F0C	/* Video J DMA control */
+
+#define  FLD_APB_RISC_EN           0x00000010
+#define  FLD_APB_FIFO_EN           0x00000001
+
+/* ***************************************************************************** */
+
+#define  VID_SRC_A_FMT_CTL         0x130810	/* Video A format control */
+#define  VID_SRC_B_FMT_CTL         0x130910	/* Video B format control */
+#define  VID_SRC_C_FMT_CTL         0x130A10	/* Video C format control */
+#define  VID_SRC_D_FMT_CTL         0x130B10	/* Video D format control */
+#define  VID_SRC_E_FMT_CTL         0x130C10	/* Video E format control */
+#define  VID_SRC_F_FMT_CTL         0x130D10	/* Video F format control */
+#define  VID_SRC_I_FMT_CTL         0x130E10	/* Video I format control */
+#define  VID_SRC_J_FMT_CTL         0x130F10	/* Video J format control */
+
+/* ***************************************************************************** */
+
+#define  VID_SRC_A_ACTIVE_CTL1     0x130814	/* Video A active control      1 */
+#define  VID_SRC_B_ACTIVE_CTL1     0x130914	/* Video B active control      1 */
+#define  VID_SRC_C_ACTIVE_CTL1     0x130A14	/* Video C active control      1 */
+#define  VID_SRC_D_ACTIVE_CTL1     0x130B14	/* Video D active control      1 */
+#define  VID_SRC_E_ACTIVE_CTL1     0x130C14	/* Video E active control      1 */
+#define  VID_SRC_F_ACTIVE_CTL1     0x130D14	/* Video F active control      1 */
+#define  VID_SRC_I_ACTIVE_CTL1     0x130E14	/* Video I active control      1 */
+#define  VID_SRC_J_ACTIVE_CTL1     0x130F14	/* Video J active control      1 */
+
+/* ***************************************************************************** */
+
+#define  VID_SRC_A_ACTIVE_CTL2     0x130818	/* Video A active control      2 */
+#define  VID_SRC_B_ACTIVE_CTL2     0x130918	/* Video B active control      2 */
+#define  VID_SRC_C_ACTIVE_CTL2     0x130A18	/* Video C active control      2 */
+#define  VID_SRC_D_ACTIVE_CTL2     0x130B18	/* Video D active control      2 */
+#define  VID_SRC_E_ACTIVE_CTL2     0x130C18	/* Video E active control      2 */
+#define  VID_SRC_F_ACTIVE_CTL2     0x130D18	/* Video F active control      2 */
+#define  VID_SRC_I_ACTIVE_CTL2     0x130E18	/* Video I active control      2 */
+#define  VID_SRC_J_ACTIVE_CTL2     0x130F18	/* Video J active control      2 */
+
+/* ***************************************************************************** */
+
+#define  VID_SRC_A_CDT_SZ          0x13081C	/* Video A CDT size */
+#define  VID_SRC_B_CDT_SZ          0x13091C	/* Video B CDT size */
+#define  VID_SRC_C_CDT_SZ          0x130A1C	/* Video C CDT size */
+#define  VID_SRC_D_CDT_SZ          0x130B1C	/* Video D CDT size */
+#define  VID_SRC_E_CDT_SZ          0x130C1C	/* Video E CDT size */
+#define  VID_SRC_F_CDT_SZ          0x130D1C	/* Video F CDT size */
+#define  VID_SRC_I_CDT_SZ          0x130E1C	/* Video I CDT size */
+#define  VID_SRC_J_CDT_SZ          0x130F1C	/* Video J CDT size */
+
+/* ***************************************************************************** */
+/* Audio I/F */
+/* ***************************************************************************** */
+#define  AUD_DST_A_DMA             0x140000	/* Audio Int A DMA data port */
+#define  AUD_SRC_A_DMA             0x140008	/* Audio Int A DMA data port */
+
+#define  AUD_A_GPCNT               0x140010	/* Audio Int A gp counter */
+#define  FLD_AUD_A_GP_CNT          0x0000FFFF
+
+#define  AUD_A_GPCNT_CTL           0x140014	/* Audio Int A gp control */
+
+#define  AUD_A_LNGTH               0x140018	/* Audio Int A line length */
+
+#define  AUD_A_CFG                 0x14001C	/* Audio Int A configuration */
+
+/* ***************************************************************************** */
+#define  AUD_DST_B_DMA             0x140100	/* Audio Int B DMA data port */
+#define  AUD_SRC_B_DMA             0x140108	/* Audio Int B DMA data port */
+
+#define  AUD_B_GPCNT               0x140110	/* Audio Int B gp counter */
+#define  FLD_AUD_B_GP_CNT          0x0000FFFF
+
+#define  AUD_B_GPCNT_CTL           0x140114	/* Audio Int B gp control */
+
+#define  AUD_B_LNGTH               0x140118	/* Audio Int B line length */
+
+#define  AUD_B_CFG                 0x14011C	/* Audio Int B configuration */
+
+/* ***************************************************************************** */
+#define  AUD_DST_C_DMA             0x140200	/* Audio Int C DMA data port */
+#define  AUD_SRC_C_DMA             0x140208	/* Audio Int C DMA data port */
+
+#define  AUD_C_GPCNT               0x140210	/* Audio Int C gp counter */
+#define  FLD_AUD_C_GP_CNT          0x0000FFFF
+
+#define  AUD_C_GPCNT_CTL           0x140214	/* Audio Int C gp control */
+
+#define  AUD_C_LNGTH               0x140218	/* Audio Int C line length */
+
+#define  AUD_C_CFG                 0x14021C	/* Audio Int C configuration */
+
+/* ***************************************************************************** */
+#define  AUD_DST_D_DMA             0x140300	/* Audio Int D DMA data port */
+#define  AUD_SRC_D_DMA             0x140308	/* Audio Int D DMA data port */
+
+#define  AUD_D_GPCNT               0x140310	/* Audio Int D gp counter */
+#define  FLD_AUD_D_GP_CNT          0x0000FFFF
+
+#define  AUD_D_GPCNT_CTL           0x140314	/* Audio Int D gp control */
+
+#define  AUD_D_LNGTH               0x140318	/* Audio Int D line length */
+
+#define  AUD_D_CFG                 0x14031C	/* Audio Int D configuration */
+
+/* ***************************************************************************** */
+#define  AUD_SRC_E_DMA             0x140400	/* Audio Int E DMA data port */
+
+#define  AUD_E_GPCNT               0x140410	/* Audio Int E gp counter */
+#define  FLD_AUD_E_GP_CNT          0x0000FFFF
+
+#define  AUD_E_GPCNT_CTL           0x140414	/* Audio Int E gp control */
+
+#define  AUD_E_CFG                 0x14041C	/* Audio Int E configuration */
+
+/* ***************************************************************************** */
+
+#define  FLD_AUD_DST_LN_LNGTH      0x00000FFF
+
+#define  FLD_AUD_DST_PK_MODE       0x00004000
+
+#define  FLD_AUD_CLK_ENABLE        0x00000200
+
+#define  FLD_AUD_MASTER_MODE       0x00000002
+
+#define  FLD_AUD_SONY_MODE         0x00000001
+
+#define  FLD_AUD_CLK_SELECT_PLL_D  0x00001800
+
+#define  FLD_AUD_DST_ENABLE        0x00020000
+
+#define  FLD_AUD_SRC_ENABLE        0x00010000
+
+/* ***************************************************************************** */
+#define  AUD_INT_DMA_CTL           0x140500	/* Audio Int DMA control */
+
+#define  FLD_AUD_SRC_E_RISC_EN     0x00008000
+#define  FLD_AUD_SRC_C_RISC_EN     0x00004000
+#define  FLD_AUD_SRC_B_RISC_EN     0x00002000
+#define  FLD_AUD_SRC_A_RISC_EN     0x00001000
+
+#define  FLD_AUD_DST_D_RISC_EN     0x00000800
+#define  FLD_AUD_DST_C_RISC_EN     0x00000400
+#define  FLD_AUD_DST_B_RISC_EN     0x00000200
+#define  FLD_AUD_DST_A_RISC_EN     0x00000100
+
+#define  FLD_AUD_SRC_E_FIFO_EN     0x00000080
+#define  FLD_AUD_SRC_C_FIFO_EN     0x00000040
+#define  FLD_AUD_SRC_B_FIFO_EN     0x00000020
+#define  FLD_AUD_SRC_A_FIFO_EN     0x00000010
+
+#define  FLD_AUD_DST_D_FIFO_EN     0x00000008
+#define  FLD_AUD_DST_C_FIFO_EN     0x00000004
+#define  FLD_AUD_DST_B_FIFO_EN     0x00000002
+#define  FLD_AUD_DST_A_FIFO_EN     0x00000001
+
+/* ***************************************************************************** */
+/*  */
+/* Mobilygen Interface Registers */
+/*  */
+/* ***************************************************************************** */
+/* Mobilygen Interface A */
+/* ***************************************************************************** */
+#define  MB_IF_A_DMA               0x150000	/* MBIF A DMA data port */
+#define  MB_IF_A_GPCN              0x150008	/* MBIF A GP counter */
+#define  MB_IF_A_GPCN_CTRL         0x15000C
+#define  MB_IF_A_DMA_CTRL          0x150010
+#define  MB_IF_A_LENGTH            0x150014
+#define  MB_IF_A_HDMA_XFER_SZ      0x150018
+#define  MB_IF_A_HCMD              0x15001C
+#define  MB_IF_A_HCONFIG           0x150020
+#define  MB_IF_A_DATA_STRUCT_0     0x150024
+#define  MB_IF_A_DATA_STRUCT_1     0x150028
+#define  MB_IF_A_DATA_STRUCT_2     0x15002C
+#define  MB_IF_A_DATA_STRUCT_3     0x150030
+#define  MB_IF_A_DATA_STRUCT_4     0x150034
+#define  MB_IF_A_DATA_STRUCT_5     0x150038
+#define  MB_IF_A_DATA_STRUCT_6     0x15003C
+#define  MB_IF_A_DATA_STRUCT_7     0x150040
+#define  MB_IF_A_DATA_STRUCT_8     0x150044
+#define  MB_IF_A_DATA_STRUCT_9     0x150048
+#define  MB_IF_A_DATA_STRUCT_A     0x15004C
+#define  MB_IF_A_DATA_STRUCT_B     0x150050
+#define  MB_IF_A_DATA_STRUCT_C     0x150054
+#define  MB_IF_A_DATA_STRUCT_D     0x150058
+#define  MB_IF_A_DATA_STRUCT_E     0x15005C
+#define  MB_IF_A_DATA_STRUCT_F     0x150060
+/* ***************************************************************************** */
+/* Mobilygen Interface B */
+/* ***************************************************************************** */
+#define  MB_IF_B_DMA               0x160000	/* MBIF A DMA data port */
+#define  MB_IF_B_GPCN              0x160008	/* MBIF A GP counter */
+#define  MB_IF_B_GPCN_CTRL         0x16000C
+#define  MB_IF_B_DMA_CTRL          0x160010
+#define  MB_IF_B_LENGTH            0x160014
+#define  MB_IF_B_HDMA_XFER_SZ      0x160018
+#define  MB_IF_B_HCMD              0x16001C
+#define  MB_IF_B_HCONFIG           0x160020
+#define  MB_IF_B_DATA_STRUCT_0     0x160024
+#define  MB_IF_B_DATA_STRUCT_1     0x160028
+#define  MB_IF_B_DATA_STRUCT_2     0x16002C
+#define  MB_IF_B_DATA_STRUCT_3     0x160030
+#define  MB_IF_B_DATA_STRUCT_4     0x160034
+#define  MB_IF_B_DATA_STRUCT_5     0x160038
+#define  MB_IF_B_DATA_STRUCT_6     0x16003C
+#define  MB_IF_B_DATA_STRUCT_7     0x160040
+#define  MB_IF_B_DATA_STRUCT_8     0x160044
+#define  MB_IF_B_DATA_STRUCT_9     0x160048
+#define  MB_IF_B_DATA_STRUCT_A     0x16004C
+#define  MB_IF_B_DATA_STRUCT_B     0x160050
+#define  MB_IF_B_DATA_STRUCT_C     0x160054
+#define  MB_IF_B_DATA_STRUCT_D     0x160058
+#define  MB_IF_B_DATA_STRUCT_E     0x16005C
+#define  MB_IF_B_DATA_STRUCT_F     0x160060
+
+/* MB_DMA_CTRL */
+#define  FLD_MB_IF_RISC_EN         0x00000010
+#define  FLD_MB_IF_FIFO_EN         0x00000001
+
+/* MB_LENGTH */
+#define  FLD_MB_IF_LN_LNGTH        0x00000FFF
+
+/* MB_HCMD register */
+#define  FLD_MB_HCMD_H_GO          0x80000000
+#define  FLD_MB_HCMD_H_BUSY        0x40000000
+#define  FLD_MB_HCMD_H_DMA_HOLD    0x10000000
+#define  FLD_MB_HCMD_H_DMA_BUSY    0x08000000
+#define  FLD_MB_HCMD_H_DMA_TYPE    0x04000000
+#define  FLD_MB_HCMD_H_DMA_XACT    0x02000000
+#define  FLD_MB_HCMD_H_RW_N        0x01000000
+#define  FLD_MB_HCMD_H_ADDR        0x00FF0000
+#define  FLD_MB_HCMD_H_DATA        0x0000FFFF
+
+/* ***************************************************************************** */
+/* I2C #1 */
+/* ***************************************************************************** */
+#define  I2C1_ADDR                 0x180000	/* I2C #1 address */
+#define  FLD_I2C_DADDR             0xfe000000	/* RW [31:25] I2C Device Address */
+						 /* RO [24] reserved */
+/* ***************************************************************************** */
+#define  FLD_I2C_SADDR             0x00FFFFFF	/* RW [23:0]  I2C Sub-address */
+
+/* ***************************************************************************** */
+#define  I2C1_WDATA                0x180004	/* I2C #1 write data */
+#define  FLD_I2C_WDATA             0xFFFFFFFF	/* RW [31:0] */
+
+/* ***************************************************************************** */
+#define  I2C1_CTRL                 0x180008	/* I2C #1 control */
+#define  FLD_I2C_PERIOD            0xFF000000	/* RW [31:24] */
+#define  FLD_I2C_SCL_IN            0x00200000	/* RW [21] */
+#define  FLD_I2C_SDA_IN            0x00100000	/* RW [20] */
+						 /* RO [19:18] reserved */
+#define  FLD_I2C_SCL_OUT           0x00020000	/* RW [17] */
+#define  FLD_I2C_SDA_OUT           0x00010000	/* RW [16] */
+						 /* RO [15] reserved */
+#define  FLD_I2C_DATA_LEN          0x00007000	/* RW [14:12] */
+#define  FLD_I2C_SADDR_INC         0x00000800	/* RW [11] */
+						 /* RO [10:9] reserved */
+#define  FLD_I2C_SADDR_LEN         0x00000300	/* RW [9:8] */
+						 /* RO [7:6] reserved */
+#define  FLD_I2C_SOFT              0x00000020	/* RW [5] */
+#define  FLD_I2C_NOSTOP            0x00000010	/* RW [4] */
+#define  FLD_I2C_EXTEND            0x00000008	/* RW [3] */
+#define  FLD_I2C_SYNC              0x00000004	/* RW [2] */
+#define  FLD_I2C_READ_SA           0x00000002	/* RW [1] */
+#define  FLD_I2C_READ_WRN          0x00000001	/* RW [0] */
+
+/* ***************************************************************************** */
+#define  I2C1_RDATA                0x18000C	/* I2C #1 read data */
+#define  FLD_I2C_RDATA             0xFFFFFFFF	/* RO [31:0] */
+
+/* ***************************************************************************** */
+#define  I2C1_STAT                 0x180010	/* I2C #1 status */
+#define  FLD_I2C_XFER_IN_PROG      0x00000002	/* RO [1] */
+#define  FLD_I2C_RACK              0x00000001	/* RO [0] */
+
+/* ***************************************************************************** */
+/* I2C #2 */
+/* ***************************************************************************** */
+#define  I2C2_ADDR                 0x190000	/* I2C #2 address */
+
+/* ***************************************************************************** */
+#define  I2C2_WDATA                0x190004	/* I2C #2 write data */
+
+/* ***************************************************************************** */
+#define  I2C2_CTRL                 0x190008	/* I2C #2 control */
+
+/* ***************************************************************************** */
+#define  I2C2_RDATA                0x19000C	/* I2C #2 read data */
+
+/* ***************************************************************************** */
+#define  I2C2_STAT                 0x190010	/* I2C #2 status */
+
+/* ***************************************************************************** */
+/* I2C #3 */
+/* ***************************************************************************** */
+#define  I2C3_ADDR                 0x1A0000	/* I2C #3 address */
+
+/* ***************************************************************************** */
+#define  I2C3_WDATA                0x1A0004	/* I2C #3 write data */
+
+/* ***************************************************************************** */
+#define  I2C3_CTRL                 0x1A0008	/* I2C #3 control */
+
+/* ***************************************************************************** */
+#define  I2C3_RDATA                0x1A000C	/* I2C #3 read data */
+
+/* ***************************************************************************** */
+#define  I2C3_STAT                 0x1A0010	/* I2C #3 status */
+
+/* ***************************************************************************** */
+/* UART */
+/* ***************************************************************************** */
+#define  UART_CTL                  0x1B0000	/* UART Control Register */
+#define  FLD_LOOP_BACK_EN          (1 << 7)	/* RW field - default 0 */
+#define  FLD_RX_TRG_SZ             (3 << 2)	/* RW field - default 0 */
+#define  FLD_RX_EN                 (1 << 1)	/* RW field - default 0 */
+#define  FLD_TX_EN                 (1 << 0)	/* RW field - default 0 */
+
+/* ***************************************************************************** */
+#define  UART_BRD                  0x1B0004	/* UART Baud Rate Divisor */
+#define  FLD_BRD                   0x0000FFFF	/* RW field - default 0x197 */
+
+/* ***************************************************************************** */
+#define  UART_DBUF                 0x1B0008	/* UART Tx/Rx Data BuFFer */
+#define  FLD_DB                    0xFFFFFFFF	/* RW field - default 0 */
+
+/* ***************************************************************************** */
+#define  UART_ISR                  0x1B000C	/* UART Interrupt Status */
+#define  FLD_RXD_TIMEOUT_EN        (1 << 7)	/* RW field - default 0 */
+#define  FLD_FRM_ERR_EN            (1 << 6)	/* RW field - default 0 */
+#define  FLD_RXD_RDY_EN            (1 << 5)	/* RW field - default 0 */
+#define  FLD_TXD_EMPTY_EN          (1 << 4)	/* RW field - default 0 */
+#define  FLD_RXD_OVERFLOW          (1 << 3)	/* RW field - default 0 */
+#define  FLD_FRM_ERR               (1 << 2)	/* RW field - default 0 */
+#define  FLD_RXD_RDY               (1 << 1)	/* RW field - default 0 */
+#define  FLD_TXD_EMPTY             (1 << 0)	/* RW field - default 0 */
+
+/* ***************************************************************************** */
+#define  UART_CNT                  0x1B0010	/* UART Tx/Rx FIFO Byte Count */
+#define  FLD_TXD_CNT               (0x1F << 8)	/* RW field - default 0 */
+#define  FLD_RXD_CNT               (0x1F << 0)	/* RW field - default 0 */
+
+/* ***************************************************************************** */
+/* Motion Detection */
+#define  MD_CH0_GRID_BLOCK_YCNT    0x170014
+#define  MD_CH1_GRID_BLOCK_YCNT    0x170094
+#define  MD_CH2_GRID_BLOCK_YCNT    0x170114
+#define  MD_CH3_GRID_BLOCK_YCNT    0x170194
+#define  MD_CH4_GRID_BLOCK_YCNT    0x170214
+#define  MD_CH5_GRID_BLOCK_YCNT    0x170294
+#define  MD_CH6_GRID_BLOCK_YCNT    0x170314
+#define  MD_CH7_GRID_BLOCK_YCNT    0x170394
+
+#define PIXEL_FRMT_422    4
+#define PIXEL_FRMT_411    5
+#define PIXEL_FRMT_Y8     6
+
+#define PIXEL_ENGINE_VIP1 0
+#define PIXEL_ENGINE_VIP2 1
+
+#endif /* Athena_REGISTERS */
diff --git a/drivers/media/pci/cx25821/cx25821-sram.h b/drivers/media/pci/cx25821/cx25821-sram.h
new file mode 100644
index 0000000..5f05d15
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-sram.h
@@ -0,0 +1,261 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ATHENA_SRAM_H__
+#define __ATHENA_SRAM_H__
+
+/* #define RX_SRAM_START_SIZE        = 0;  //  Start of reserved SRAM */
+#define VID_CMDS_SIZE             80	/* Video CMDS size in bytes */
+#define AUDIO_CMDS_SIZE           80	/* AUDIO CMDS size in bytes */
+#define MBIF_CMDS_SIZE            80	/* MBIF  CMDS size in bytes */
+
+/* #define RX_SRAM_POOL_START_SIZE   = 0;  //  Start of useable RX SRAM for buffers */
+#define VID_IQ_SIZE               64	/* VID instruction queue size in bytes */
+#define MBIF_IQ_SIZE              64
+#define AUDIO_IQ_SIZE             64	/* AUD instruction queue size in bytes */
+
+#define VID_CDT_SIZE              64	/* VID cluster descriptor table size in bytes */
+#define MBIF_CDT_SIZE             64	/* MBIF/HBI cluster descriptor table size in bytes */
+#define AUDIO_CDT_SIZE            48	/* AUD cluster descriptor table size in bytes */
+
+/* #define RX_SRAM_POOL_FREE_SIZE    = 16; //  Start of available RX SRAM */
+/* #define RX_SRAM_END_SIZE          = 0;  //  End of RX SRAM */
+
+/* #define TX_SRAM_POOL_START_SIZE   = 0;  //  Start of transmit pool SRAM */
+/* #define MSI_DATA_SIZE             = 64; //  Reserved (MSI Data, RISC working stora */
+
+#define VID_CLUSTER_SIZE          1440	/* VID cluster data line */
+#define AUDIO_CLUSTER_SIZE        128	/* AUDIO cluster data line */
+#define MBIF_CLUSTER_SIZE         1440	/* MBIF/HBI cluster data line */
+
+/* #define TX_SRAM_POOL_FREE_SIZE    = 704;    //  Start of available TX SRAM */
+/* #define TX_SRAM_END_SIZE          = 0;      //  End of TX SRAM */
+
+/* Receive SRAM */
+#define RX_SRAM_START             0x10000
+#define VID_A_DOWN_CMDS           0x10000
+#define VID_B_DOWN_CMDS           0x10050
+#define VID_C_DOWN_CMDS           0x100A0
+#define VID_D_DOWN_CMDS           0x100F0
+#define VID_E_DOWN_CMDS           0x10140
+#define VID_F_DOWN_CMDS           0x10190
+#define VID_G_DOWN_CMDS           0x101E0
+#define VID_H_DOWN_CMDS           0x10230
+#define VID_A_UP_CMDS             0x10280
+#define VID_B_UP_CMDS             0x102D0
+#define VID_C_UP_CMDS             0x10320
+#define VID_D_UP_CMDS             0x10370
+#define VID_E_UP_CMDS             0x103C0
+#define VID_F_UP_CMDS             0x10410
+#define VID_I_UP_CMDS             0x10460
+#define VID_J_UP_CMDS             0x104B0
+#define AUD_A_DOWN_CMDS           0x10500
+#define AUD_B_DOWN_CMDS           0x10550
+#define AUD_C_DOWN_CMDS           0x105A0
+#define AUD_D_DOWN_CMDS           0x105F0
+#define AUD_A_UP_CMDS             0x10640
+#define AUD_B_UP_CMDS             0x10690
+#define AUD_C_UP_CMDS             0x106E0
+#define AUD_E_UP_CMDS             0x10730
+#define MBIF_A_DOWN_CMDS          0x10780
+#define MBIF_B_DOWN_CMDS          0x107D0
+#define DMA_SCRATCH_PAD           0x10820	/* Scratch pad area from 0x10820 to 0x10B40 */
+
+/* #define RX_SRAM_POOL_START        = 0x105B0; */
+
+#define VID_A_IQ                  0x11000
+#define VID_B_IQ                  0x11040
+#define VID_C_IQ                  0x11080
+#define VID_D_IQ                  0x110C0
+#define VID_E_IQ                  0x11100
+#define VID_F_IQ                  0x11140
+#define VID_G_IQ                  0x11180
+#define VID_H_IQ                  0x111C0
+#define VID_I_IQ                  0x11200
+#define VID_J_IQ                  0x11240
+#define AUD_A_IQ                  0x11280
+#define AUD_B_IQ                  0x112C0
+#define AUD_C_IQ                  0x11300
+#define AUD_D_IQ                  0x11340
+#define AUD_E_IQ                  0x11380
+#define MBIF_A_IQ                 0x11000
+#define MBIF_B_IQ                 0x110C0
+
+#define VID_A_CDT                 0x10C00
+#define VID_B_CDT                 0x10C40
+#define VID_C_CDT                 0x10C80
+#define VID_D_CDT                 0x10CC0
+#define VID_E_CDT                 0x10D00
+#define VID_F_CDT                 0x10D40
+#define VID_G_CDT                 0x10D80
+#define VID_H_CDT                 0x10DC0
+#define VID_I_CDT                 0x10E00
+#define VID_J_CDT                 0x10E40
+#define AUD_A_CDT                 0x10E80
+#define AUD_B_CDT                 0x10EB0
+#define AUD_C_CDT                 0x10EE0
+#define AUD_D_CDT                 0x10F10
+#define AUD_E_CDT                 0x10F40
+#define MBIF_A_CDT                0x10C00
+#define MBIF_B_CDT                0x10CC0
+
+/* Cluster Buffer for RX */
+#define VID_A_UP_CLUSTER_1        0x11400
+#define VID_A_UP_CLUSTER_2        0x119A0
+#define VID_A_UP_CLUSTER_3        0x11F40
+#define VID_A_UP_CLUSTER_4        0x124E0
+
+#define VID_B_UP_CLUSTER_1        0x12A80
+#define VID_B_UP_CLUSTER_2        0x13020
+#define VID_B_UP_CLUSTER_3        0x135C0
+#define VID_B_UP_CLUSTER_4        0x13B60
+
+#define VID_C_UP_CLUSTER_1        0x14100
+#define VID_C_UP_CLUSTER_2        0x146A0
+#define VID_C_UP_CLUSTER_3        0x14C40
+#define VID_C_UP_CLUSTER_4        0x151E0
+
+#define VID_D_UP_CLUSTER_1        0x15780
+#define VID_D_UP_CLUSTER_2        0x15D20
+#define VID_D_UP_CLUSTER_3        0x162C0
+#define VID_D_UP_CLUSTER_4        0x16860
+
+#define VID_E_UP_CLUSTER_1        0x16E00
+#define VID_E_UP_CLUSTER_2        0x173A0
+#define VID_E_UP_CLUSTER_3        0x17940
+#define VID_E_UP_CLUSTER_4        0x17EE0
+
+#define VID_F_UP_CLUSTER_1        0x18480
+#define VID_F_UP_CLUSTER_2        0x18A20
+#define VID_F_UP_CLUSTER_3        0x18FC0
+#define VID_F_UP_CLUSTER_4        0x19560
+
+#define VID_I_UP_CLUSTER_1        0x19B00
+#define VID_I_UP_CLUSTER_2        0x1A0A0
+#define VID_I_UP_CLUSTER_3        0x1A640
+#define VID_I_UP_CLUSTER_4        0x1ABE0
+
+#define VID_J_UP_CLUSTER_1        0x1B180
+#define VID_J_UP_CLUSTER_2        0x1B720
+#define VID_J_UP_CLUSTER_3        0x1BCC0
+#define VID_J_UP_CLUSTER_4        0x1C260
+
+#define AUD_A_UP_CLUSTER_1        0x1C800
+#define AUD_A_UP_CLUSTER_2        0x1C880
+#define AUD_A_UP_CLUSTER_3        0x1C900
+
+#define AUD_B_UP_CLUSTER_1        0x1C980
+#define AUD_B_UP_CLUSTER_2        0x1CA00
+#define AUD_B_UP_CLUSTER_3        0x1CA80
+
+#define AUD_C_UP_CLUSTER_1        0x1CB00
+#define AUD_C_UP_CLUSTER_2        0x1CB80
+#define AUD_C_UP_CLUSTER_3        0x1CC00
+
+#define AUD_E_UP_CLUSTER_1        0x1CC80
+#define AUD_E_UP_CLUSTER_2        0x1CD00
+#define AUD_E_UP_CLUSTER_3        0x1CD80
+
+#define RX_SRAM_POOL_FREE         0x1CE00
+#define RX_SRAM_END               0x1D000
+
+/* Free Receive SRAM    144 Bytes */
+
+/* Transmit SRAM */
+#define TX_SRAM_POOL_START        0x00000
+
+#define VID_A_DOWN_CLUSTER_1      0x00040
+#define VID_A_DOWN_CLUSTER_2      0x005E0
+#define VID_A_DOWN_CLUSTER_3      0x00B80
+#define VID_A_DOWN_CLUSTER_4      0x01120
+
+#define VID_B_DOWN_CLUSTER_1      0x016C0
+#define VID_B_DOWN_CLUSTER_2      0x01C60
+#define VID_B_DOWN_CLUSTER_3      0x02200
+#define VID_B_DOWN_CLUSTER_4      0x027A0
+
+#define VID_C_DOWN_CLUSTER_1      0x02D40
+#define VID_C_DOWN_CLUSTER_2      0x032E0
+#define VID_C_DOWN_CLUSTER_3      0x03880
+#define VID_C_DOWN_CLUSTER_4      0x03E20
+
+#define VID_D_DOWN_CLUSTER_1      0x043C0
+#define VID_D_DOWN_CLUSTER_2      0x04960
+#define VID_D_DOWN_CLUSTER_3      0x04F00
+#define VID_D_DOWN_CLUSTER_4      0x054A0
+
+#define VID_E_DOWN_CLUSTER_1      0x05a40
+#define VID_E_DOWN_CLUSTER_2      0x05FE0
+#define VID_E_DOWN_CLUSTER_3      0x06580
+#define VID_E_DOWN_CLUSTER_4      0x06B20
+
+#define VID_F_DOWN_CLUSTER_1      0x070C0
+#define VID_F_DOWN_CLUSTER_2      0x07660
+#define VID_F_DOWN_CLUSTER_3      0x07C00
+#define VID_F_DOWN_CLUSTER_4      0x081A0
+
+#define VID_G_DOWN_CLUSTER_1      0x08740
+#define VID_G_DOWN_CLUSTER_2      0x08CE0
+#define VID_G_DOWN_CLUSTER_3      0x09280
+#define VID_G_DOWN_CLUSTER_4      0x09820
+
+#define VID_H_DOWN_CLUSTER_1      0x09DC0
+#define VID_H_DOWN_CLUSTER_2      0x0A360
+#define VID_H_DOWN_CLUSTER_3      0x0A900
+#define VID_H_DOWN_CLUSTER_4      0x0AEA0
+
+#define AUD_A_DOWN_CLUSTER_1      0x0B500
+#define AUD_A_DOWN_CLUSTER_2      0x0B580
+#define AUD_A_DOWN_CLUSTER_3      0x0B600
+
+#define AUD_B_DOWN_CLUSTER_1      0x0B680
+#define AUD_B_DOWN_CLUSTER_2      0x0B700
+#define AUD_B_DOWN_CLUSTER_3      0x0B780
+
+#define AUD_C_DOWN_CLUSTER_1      0x0B800
+#define AUD_C_DOWN_CLUSTER_2      0x0B880
+#define AUD_C_DOWN_CLUSTER_3      0x0B900
+
+#define AUD_D_DOWN_CLUSTER_1      0x0B980
+#define AUD_D_DOWN_CLUSTER_2      0x0BA00
+#define AUD_D_DOWN_CLUSTER_3      0x0BA80
+
+#define TX_SRAM_POOL_FREE         0x0BB00
+#define TX_SRAM_END               0x0C000
+
+#define BYTES_TO_DWORDS(bcount) ((bcount) >> 2)
+#define BYTES_TO_QWORDS(bcount) ((bcount) >> 3)
+#define BYTES_TO_OWORDS(bcount) ((bcount) >> 4)
+
+#define VID_IQ_SIZE_DW             BYTES_TO_DWORDS(VID_IQ_SIZE)
+#define VID_CDT_SIZE_QW            BYTES_TO_QWORDS(VID_CDT_SIZE)
+#define VID_CLUSTER_SIZE_OW        BYTES_TO_OWORDS(VID_CLUSTER_SIZE)
+
+#define AUDIO_IQ_SIZE_DW           BYTES_TO_DWORDS(AUDIO_IQ_SIZE)
+#define AUDIO_CDT_SIZE_QW          BYTES_TO_QWORDS(AUDIO_CDT_SIZE)
+#define AUDIO_CLUSTER_SIZE_QW      BYTES_TO_QWORDS(AUDIO_CLUSTER_SIZE)
+
+#define MBIF_IQ_SIZE_DW            BYTES_TO_DWORDS(MBIF_IQ_SIZE)
+#define MBIF_CDT_SIZE_QW           BYTES_TO_QWORDS(MBIF_CDT_SIZE)
+#define MBIF_CLUSTER_SIZE_OW       BYTES_TO_OWORDS(MBIF_CLUSTER_SIZE)
+
+#endif
diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c
new file mode 100644
index 0000000..c8c94fb
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c
@@ -0,0 +1,802 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <hiep.huynh@conexant.com>, <shu.lin@conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "cx25821-video.h"
+#include "cx25821-video-upstream-ch2.h"
+
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/file.h>
+#include <linux/fcntl.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
+MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
+MODULE_LICENSE("GPL");
+
+static int _intr_msk = FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC |
+			FLD_VID_SRC_OPC_ERR;
+
+static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev,
+					      __le32 *rp, unsigned int offset,
+					      unsigned int bpl, u32 sync_line,
+					      unsigned int lines,
+					      int fifo_enable, int field_type)
+{
+	unsigned int line, i;
+	int dist_betwn_starts = bpl * 2;
+
+	*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
+
+	if (USE_RISC_NOOP_VIDEO) {
+		for (i = 0; i < NUM_NO_OPS; i++)
+			*(rp++) = cpu_to_le32(RISC_NOOP);
+	}
+
+	/* scan lines */
+	for (line = 0; line < lines; line++) {
+		*(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl);
+		*(rp++) = cpu_to_le32(dev->_data_buf_phys_addr_ch2 + offset);
+		*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
+
+		if ((lines <= NTSC_FIELD_HEIGHT) ||
+		    (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) {
+			offset += dist_betwn_starts;
+		}
+	}
+
+	return rp;
+}
+
+static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev,
+					       __le32 *rp,
+					       dma_addr_t databuf_phys_addr,
+					       unsigned int offset,
+					       u32 sync_line, unsigned int bpl,
+					       unsigned int lines,
+					       int fifo_enable, int field_type)
+{
+	unsigned int line, i;
+	struct sram_channel *sram_ch =
+		dev->channels[dev->_channel2_upstream_select].sram_channels;
+	int dist_betwn_starts = bpl * 2;
+
+	/* sync instruction */
+	if (sync_line != NO_SYNC_LINE)
+		*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
+
+	if (USE_RISC_NOOP_VIDEO) {
+		for (i = 0; i < NUM_NO_OPS; i++)
+			*(rp++) = cpu_to_le32(RISC_NOOP);
+	}
+
+	/* scan lines */
+	for (line = 0; line < lines; line++) {
+		*(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl);
+		*(rp++) = cpu_to_le32(databuf_phys_addr + offset);
+		*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
+
+		if ((lines <= NTSC_FIELD_HEIGHT) ||
+		    (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) {
+			offset += dist_betwn_starts;
+		}
+
+	       /*
+		 check if we need to enable the FIFO after the first 4 lines
+		  For the upstream video channel, the risc engine will enable
+		  the FIFO.
+	       */
+		if (fifo_enable && line == 3) {
+			*(rp++) = RISC_WRITECR;
+			*(rp++) = sram_ch->dma_ctl;
+			*(rp++) = FLD_VID_FIFO_EN;
+			*(rp++) = 0x00000001;
+		}
+	}
+
+	return rp;
+}
+
+int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev,
+				     struct pci_dev *pci,
+				     unsigned int top_offset, unsigned int bpl,
+				     unsigned int lines)
+{
+	__le32 *rp;
+	int fifo_enable = 0;
+	int singlefield_lines = lines >> 1; /*get line count for single field */
+	int odd_num_lines = singlefield_lines;
+	int frame = 0;
+	int frame_size = 0;
+	int databuf_offset = 0;
+	int risc_program_size = 0;
+	int risc_flag = RISC_CNT_RESET;
+	unsigned int bottom_offset = bpl;
+	dma_addr_t risc_phys_jump_addr;
+
+	if (dev->_isNTSC_ch2) {
+		odd_num_lines = singlefield_lines + 1;
+		risc_program_size = FRAME1_VID_PROG_SIZE;
+		if (bpl == Y411_LINE_SZ)
+			frame_size = FRAME_SIZE_NTSC_Y411;
+		else
+			frame_size = FRAME_SIZE_NTSC_Y422;
+	} else {
+		risc_program_size = PAL_VID_PROG_SIZE;
+		if (bpl == Y411_LINE_SZ)
+			frame_size = FRAME_SIZE_PAL_Y411;
+		else
+			frame_size = FRAME_SIZE_PAL_Y422;
+	}
+
+	/* Virtual address of Risc buffer program */
+	rp = dev->_dma_virt_addr_ch2;
+
+	for (frame = 0; frame < NUM_FRAMES; frame++) {
+		databuf_offset = frame_size * frame;
+
+		if (UNSET != top_offset) {
+			fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE;
+			rp = cx25821_risc_field_upstream_ch2(dev, rp,
+				dev->_data_buf_phys_addr_ch2 + databuf_offset,
+				top_offset, 0, bpl, odd_num_lines, fifo_enable,
+				ODD_FIELD);
+		}
+
+		fifo_enable = FIFO_DISABLE;
+
+		/* Even field */
+		rp = cx25821_risc_field_upstream_ch2(dev, rp,
+				dev->_data_buf_phys_addr_ch2 + databuf_offset,
+				bottom_offset, 0x200, bpl, singlefield_lines,
+				fifo_enable, EVEN_FIELD);
+
+		if (frame == 0) {
+			risc_flag = RISC_CNT_RESET;
+			risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2 +
+					risc_program_size;
+		} else {
+			risc_flag = RISC_CNT_INC;
+			risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2;
+		}
+
+	       /*
+		* Loop to 2ndFrameRISC or to Start of
+		* Risc program & generate IRQ
+		*/
+		*(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag);
+		*(rp++) = cpu_to_le32(risc_phys_jump_addr);
+		*(rp++) = cpu_to_le32(0);
+	}
+
+	return 0;
+}
+
+void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev)
+{
+	struct sram_channel *sram_ch =
+		dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels;
+	u32 tmp = 0;
+
+	if (!dev->_is_running_ch2) {
+		pr_info("No video file is currently running so return!\n");
+		return;
+	}
+	/* Disable RISC interrupts */
+	tmp = cx_read(sram_ch->int_msk);
+	cx_write(sram_ch->int_msk, tmp & ~_intr_msk);
+
+	/* Turn OFF risc and fifo */
+	tmp = cx_read(sram_ch->dma_ctl);
+	cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN));
+
+	/* Clear data buffer memory */
+	if (dev->_data_buf_virt_addr_ch2)
+		memset(dev->_data_buf_virt_addr_ch2, 0,
+		       dev->_data_buf_size_ch2);
+
+	dev->_is_running_ch2 = 0;
+	dev->_is_first_frame_ch2 = 0;
+	dev->_frame_count_ch2 = 0;
+	dev->_file_status_ch2 = END_OF_FILE;
+
+	kfree(dev->_irq_queues_ch2);
+	dev->_irq_queues_ch2 = NULL;
+
+	kfree(dev->_filename_ch2);
+
+	tmp = cx_read(VID_CH_MODE_SEL);
+	cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00);
+}
+
+void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev)
+{
+	if (dev->_is_running_ch2)
+		cx25821_stop_upstream_video_ch2(dev);
+
+	if (dev->_dma_virt_addr_ch2) {
+		pci_free_consistent(dev->pci, dev->_risc_size_ch2,
+				    dev->_dma_virt_addr_ch2,
+				    dev->_dma_phys_addr_ch2);
+		dev->_dma_virt_addr_ch2 = NULL;
+	}
+
+	if (dev->_data_buf_virt_addr_ch2) {
+		pci_free_consistent(dev->pci, dev->_data_buf_size_ch2,
+				    dev->_data_buf_virt_addr_ch2,
+				    dev->_data_buf_phys_addr_ch2);
+		dev->_data_buf_virt_addr_ch2 = NULL;
+	}
+}
+
+int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
+{
+	struct file *myfile;
+	int frame_index_temp = dev->_frame_index_ch2;
+	int i = 0;
+	int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ?
+		Y411_LINE_SZ : Y422_LINE_SZ;
+	int frame_size = 0;
+	int frame_offset = 0;
+	ssize_t vfs_read_retval = 0;
+	char mybuf[line_size];
+	loff_t file_offset;
+	loff_t pos;
+	mm_segment_t old_fs;
+
+	if (dev->_file_status_ch2 == END_OF_FILE)
+		return 0;
+
+	if (dev->_isNTSC_ch2) {
+		frame_size = (line_size == Y411_LINE_SZ) ?
+			FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422;
+	} else {
+		frame_size = (line_size == Y411_LINE_SZ) ?
+			FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422;
+	}
+
+	frame_offset = (frame_index_temp > 0) ? frame_size : 0;
+	file_offset = dev->_frame_count_ch2 * frame_size;
+
+	myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0);
+	if (IS_ERR(myfile)) {
+		const int open_errno = -PTR_ERR(myfile);
+		pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
+		       __func__, dev->_filename_ch2, open_errno);
+		return PTR_ERR(myfile);
+	} else {
+		if (!(myfile->f_op)) {
+			pr_err("%s(): File has no file operations registered!\n",
+			       __func__);
+			filp_close(myfile, NULL);
+			return -EIO;
+		}
+
+		if (!myfile->f_op->read) {
+			pr_err("%s(): File has no READ operations registered!\n",
+			       __func__);
+			filp_close(myfile, NULL);
+			return -EIO;
+		}
+
+		pos = myfile->f_pos;
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+
+		for (i = 0; i < dev->_lines_count_ch2; i++) {
+			pos = file_offset;
+
+			vfs_read_retval = vfs_read(myfile, mybuf, line_size,
+					&pos);
+
+			if (vfs_read_retval > 0 && vfs_read_retval == line_size
+			    && dev->_data_buf_virt_addr_ch2 != NULL) {
+				memcpy((void *)(dev->_data_buf_virt_addr_ch2 +
+						frame_offset / 4), mybuf,
+						vfs_read_retval);
+			}
+
+			file_offset += vfs_read_retval;
+			frame_offset += vfs_read_retval;
+
+			if (vfs_read_retval < line_size) {
+				pr_info("Done: exit %s() since no more bytes to read from Video file\n",
+					__func__);
+				break;
+			}
+		}
+
+		if (i > 0)
+			dev->_frame_count_ch2++;
+
+		dev->_file_status_ch2 = (vfs_read_retval == line_size) ?
+			IN_PROGRESS : END_OF_FILE;
+
+		set_fs(old_fs);
+		filp_close(myfile, NULL);
+	}
+
+	return 0;
+}
+
+static void cx25821_vidups_handler_ch2(struct work_struct *work)
+{
+	struct cx25821_dev *dev = container_of(work, struct cx25821_dev,
+			_irq_work_entry_ch2);
+
+	if (!dev) {
+		pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n",
+		       __func__);
+		return;
+	}
+
+	cx25821_get_frame_ch2(dev, dev->channels[dev->
+			_channel2_upstream_select].sram_channels);
+}
+
+int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
+{
+	struct file *myfile;
+	int i = 0, j = 0;
+	int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ?
+		Y411_LINE_SZ : Y422_LINE_SZ;
+	ssize_t vfs_read_retval = 0;
+	char mybuf[line_size];
+	loff_t pos;
+	loff_t offset = (unsigned long)0;
+	mm_segment_t old_fs;
+
+	myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0);
+
+	if (IS_ERR(myfile)) {
+		const int open_errno = -PTR_ERR(myfile);
+		pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
+		       __func__, dev->_filename_ch2, open_errno);
+		return PTR_ERR(myfile);
+	} else {
+		if (!(myfile->f_op)) {
+			pr_err("%s(): File has no file operations registered!\n",
+			       __func__);
+			filp_close(myfile, NULL);
+			return -EIO;
+		}
+
+		if (!myfile->f_op->read) {
+			pr_err("%s(): File has no READ operations registered!  Returning\n",
+			       __func__);
+			filp_close(myfile, NULL);
+			return -EIO;
+		}
+
+		pos = myfile->f_pos;
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+
+		for (j = 0; j < NUM_FRAMES; j++) {
+			for (i = 0; i < dev->_lines_count_ch2; i++) {
+				pos = offset;
+
+				vfs_read_retval = vfs_read(myfile, mybuf,
+						line_size, &pos);
+
+				if (vfs_read_retval > 0 &&
+				    vfs_read_retval == line_size &&
+				    dev->_data_buf_virt_addr_ch2 != NULL) {
+					memcpy((void *)(dev->
+							_data_buf_virt_addr_ch2
+							+ offset / 4), mybuf,
+							vfs_read_retval);
+				}
+
+				offset += vfs_read_retval;
+
+				if (vfs_read_retval < line_size) {
+					pr_info("Done: exit %s() since no more bytes to read from Video file\n",
+						__func__);
+					break;
+				}
+			}
+
+			if (i > 0)
+				dev->_frame_count_ch2++;
+
+			if (vfs_read_retval < line_size)
+				break;
+		}
+
+		dev->_file_status_ch2 = (vfs_read_retval == line_size) ?
+			IN_PROGRESS : END_OF_FILE;
+
+		set_fs(old_fs);
+		myfile->f_pos = 0;
+		filp_close(myfile, NULL);
+	}
+
+	return 0;
+}
+
+static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
+					       struct sram_channel *sram_ch,
+					       int bpl)
+{
+	int ret = 0;
+	dma_addr_t dma_addr;
+	dma_addr_t data_dma_addr;
+
+	if (dev->_dma_virt_addr_ch2 != NULL) {
+		pci_free_consistent(dev->pci, dev->upstream_riscbuf_size_ch2,
+				    dev->_dma_virt_addr_ch2,
+				    dev->_dma_phys_addr_ch2);
+	}
+
+	dev->_dma_virt_addr_ch2 = pci_alloc_consistent(dev->pci,
+			dev->upstream_riscbuf_size_ch2, &dma_addr);
+	dev->_dma_virt_start_addr_ch2 = dev->_dma_virt_addr_ch2;
+	dev->_dma_phys_start_addr_ch2 = dma_addr;
+	dev->_dma_phys_addr_ch2 = dma_addr;
+	dev->_risc_size_ch2 = dev->upstream_riscbuf_size_ch2;
+
+	if (!dev->_dma_virt_addr_ch2) {
+		pr_err("FAILED to allocate memory for Risc buffer! Returning\n");
+		return -ENOMEM;
+	}
+
+	/* Iniitize at this address until n bytes to 0 */
+	memset(dev->_dma_virt_addr_ch2, 0, dev->_risc_size_ch2);
+
+	if (dev->_data_buf_virt_addr_ch2 != NULL) {
+		pci_free_consistent(dev->pci, dev->upstream_databuf_size_ch2,
+				    dev->_data_buf_virt_addr_ch2,
+				    dev->_data_buf_phys_addr_ch2);
+	}
+	/* For Video Data buffer allocation */
+	dev->_data_buf_virt_addr_ch2 = pci_alloc_consistent(dev->pci,
+			dev->upstream_databuf_size_ch2, &data_dma_addr);
+	dev->_data_buf_phys_addr_ch2 = data_dma_addr;
+	dev->_data_buf_size_ch2 = dev->upstream_databuf_size_ch2;
+
+	if (!dev->_data_buf_virt_addr_ch2) {
+		pr_err("FAILED to allocate memory for data buffer! Returning\n");
+		return -ENOMEM;
+	}
+
+	/* Initialize at this address until n bytes to 0 */
+	memset(dev->_data_buf_virt_addr_ch2, 0, dev->_data_buf_size_ch2);
+
+	ret = cx25821_openfile_ch2(dev, sram_ch);
+	if (ret < 0)
+		return ret;
+
+	/* Creating RISC programs */
+	ret = cx25821_risc_buffer_upstream_ch2(dev, dev->pci, 0, bpl,
+						dev->_lines_count_ch2);
+	if (ret < 0) {
+		pr_info("Failed creating Video Upstream Risc programs!\n");
+		goto error;
+	}
+
+	return 0;
+
+error:
+	return ret;
+}
+
+int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num,
+				   u32 status)
+{
+	u32 int_msk_tmp;
+	struct sram_channel *channel = dev->channels[chan_num].sram_channels;
+	int singlefield_lines = NTSC_FIELD_HEIGHT;
+	int line_size_in_bytes = Y422_LINE_SZ;
+	int odd_risc_prog_size = 0;
+	dma_addr_t risc_phys_jump_addr;
+	__le32 *rp;
+
+	if (status & FLD_VID_SRC_RISC1) {
+		/* We should only process one program per call */
+		u32 prog_cnt = cx_read(channel->gpcnt);
+
+		/*
+		 *  Since we've identified our IRQ, clear our bits from the
+		 *  interrupt mask and interrupt status registers
+		 */
+		int_msk_tmp = cx_read(channel->int_msk);
+		cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk);
+		cx_write(channel->int_stat, _intr_msk);
+
+		spin_lock(&dev->slock);
+
+		dev->_frame_index_ch2 = prog_cnt;
+
+		queue_work(dev->_irq_queues_ch2, &dev->_irq_work_entry_ch2);
+
+		if (dev->_is_first_frame_ch2) {
+			dev->_is_first_frame_ch2 = 0;
+
+			if (dev->_isNTSC_ch2) {
+				singlefield_lines += 1;
+				odd_risc_prog_size = ODD_FLD_NTSC_PROG_SIZE;
+			} else {
+				singlefield_lines = PAL_FIELD_HEIGHT;
+				odd_risc_prog_size = ODD_FLD_PAL_PROG_SIZE;
+			}
+
+			if (dev->_dma_virt_start_addr_ch2 != NULL) {
+				if (dev->_pixel_format_ch2 == PIXEL_FRMT_411)
+					line_size_in_bytes = Y411_LINE_SZ;
+				else
+					line_size_in_bytes = Y422_LINE_SZ;
+				risc_phys_jump_addr =
+					dev->_dma_phys_start_addr_ch2 +
+					odd_risc_prog_size;
+
+				rp = cx25821_update_riscprogram_ch2(dev,
+						dev->_dma_virt_start_addr_ch2,
+						TOP_OFFSET, line_size_in_bytes,
+						0x0, singlefield_lines,
+						FIFO_DISABLE, ODD_FIELD);
+
+			       /* Jump to Even Risc program of 1st Frame */
+				*(rp++) = cpu_to_le32(RISC_JUMP);
+				*(rp++) = cpu_to_le32(risc_phys_jump_addr);
+				*(rp++) = cpu_to_le32(0);
+			}
+		}
+
+		spin_unlock(&dev->slock);
+	}
+
+	if (dev->_file_status_ch2 == END_OF_FILE) {
+		pr_info("EOF Channel 2 Framecount = %d\n",
+			dev->_frame_count_ch2);
+		return -1;
+	}
+	/* ElSE, set the interrupt mask register, re-enable irq. */
+	int_msk_tmp = cx_read(channel->int_msk);
+	cx_write(channel->int_msk, int_msk_tmp |= _intr_msk);
+
+	return 0;
+}
+
+static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id)
+{
+	struct cx25821_dev *dev = dev_id;
+	u32 vid_status;
+	int handled = 0;
+	int channel_num = 0;
+	struct sram_channel *sram_ch;
+
+	if (!dev)
+		return -1;
+
+	channel_num = VID_UPSTREAM_SRAM_CHANNEL_J;
+	sram_ch = dev->channels[channel_num].sram_channels;
+
+	vid_status = cx_read(sram_ch->int_stat);
+
+	/* Only deal with our interrupt */
+	if (vid_status)
+		handled = cx25821_video_upstream_irq_ch2(dev, channel_num,
+				vid_status);
+
+	if (handled < 0)
+		cx25821_stop_upstream_video_ch2(dev);
+	else
+		handled += handled;
+
+	return IRQ_RETVAL(handled);
+}
+
+static void cx25821_set_pixelengine_ch2(struct cx25821_dev *dev,
+					struct sram_channel *ch, int pix_format)
+{
+	int width = WIDTH_D1;
+	int height = dev->_lines_count_ch2;
+	int num_lines, odd_num_lines;
+	u32 value;
+	int vip_mode = PIXEL_ENGINE_VIP1;
+
+	value = ((pix_format & 0x3) << 12) | (vip_mode & 0x7);
+	value &= 0xFFFFFFEF;
+	value |= dev->_isNTSC_ch2 ? 0 : 0x10;
+	cx_write(ch->vid_fmt_ctl, value);
+
+	/*
+	 *  set number of active pixels in each line. Default is 720
+	 * pixels in both NTSC and PAL format
+	 */
+	cx_write(ch->vid_active_ctl1, width);
+
+	num_lines = (height / 2) & 0x3FF;
+	odd_num_lines = num_lines;
+
+	if (dev->_isNTSC_ch2)
+		odd_num_lines += 1;
+
+	value = (num_lines << 16) | odd_num_lines;
+
+	/* set number of active lines in field 0 (top) and field 1 (bottom) */
+	cx_write(ch->vid_active_ctl2, value);
+
+	cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3);
+}
+
+int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev,
+					 struct sram_channel *sram_ch)
+{
+	u32 tmp = 0;
+	int err = 0;
+
+	/*
+	 *  656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface
+	 * for channel A-C
+	 */
+	tmp = cx_read(VID_CH_MODE_SEL);
+	cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF);
+
+	/*
+	 *  Set the physical start address of the RISC program in the initial
+	 *  program counter(IPC) member of the cmds.
+	 */
+	cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr_ch2);
+	cx_write(sram_ch->cmds_start + 4, 0); /* Risc IPC High 64 bits 63-32 */
+
+	/* reset counter */
+	cx_write(sram_ch->gpcnt_ctl, 3);
+
+	/* Clear our bits from the interrupt status register. */
+	cx_write(sram_ch->int_stat, _intr_msk);
+
+	/* Set the interrupt mask register, enable irq. */
+	cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit));
+	tmp = cx_read(sram_ch->int_msk);
+	cx_write(sram_ch->int_msk, tmp |= _intr_msk);
+
+	err = request_irq(dev->pci->irq, cx25821_upstream_irq_ch2,
+			IRQF_SHARED, dev->name, dev);
+	if (err < 0) {
+		pr_err("%s: can't get upstream IRQ %d\n",
+		       dev->name, dev->pci->irq);
+		goto fail_irq;
+	}
+	/* Start the DMA  engine */
+	tmp = cx_read(sram_ch->dma_ctl);
+	cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN);
+
+	dev->_is_running_ch2 = 1;
+	dev->_is_first_frame_ch2 = 1;
+
+	return 0;
+
+fail_irq:
+	cx25821_dev_unregister(dev);
+	return err;
+}
+
+int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
+				 int pixel_format)
+{
+	struct sram_channel *sram_ch;
+	u32 tmp;
+	int retval = 0;
+	int err = 0;
+	int data_frame_size = 0;
+	int risc_buffer_size = 0;
+	int str_length = 0;
+
+	if (dev->_is_running_ch2) {
+		pr_info("Video Channel is still running so return!\n");
+		return 0;
+	}
+
+	dev->_channel2_upstream_select = channel_select;
+	sram_ch = dev->channels[channel_select].sram_channels;
+
+	INIT_WORK(&dev->_irq_work_entry_ch2, cx25821_vidups_handler_ch2);
+	dev->_irq_queues_ch2 =
+	    create_singlethread_workqueue("cx25821_workqueue2");
+
+	if (!dev->_irq_queues_ch2) {
+		pr_err("create_singlethread_workqueue() for Video FAILED!\n");
+		return -ENOMEM;
+	}
+	/*
+	 * 656/VIP SRC Upstream Channel I & J and 7 -
+	 * Host Bus Interface for channel A-C
+	 */
+	tmp = cx_read(VID_CH_MODE_SEL);
+	cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF);
+
+	dev->_is_running_ch2 = 0;
+	dev->_frame_count_ch2 = 0;
+	dev->_file_status_ch2 = RESET_STATUS;
+	dev->_lines_count_ch2 = dev->_isNTSC_ch2 ? 480 : 576;
+	dev->_pixel_format_ch2 = pixel_format;
+	dev->_line_size_ch2 = (dev->_pixel_format_ch2 == PIXEL_FRMT_422) ?
+		(WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
+	data_frame_size = dev->_isNTSC_ch2 ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ;
+	risc_buffer_size = dev->_isNTSC_ch2 ?
+		NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE;
+
+	if (dev->input_filename_ch2) {
+		str_length = strlen(dev->input_filename_ch2);
+		dev->_filename_ch2 = kmemdup(dev->input_filename_ch2,
+					     str_length + 1, GFP_KERNEL);
+
+		if (!dev->_filename_ch2)
+			goto error;
+	} else {
+		str_length = strlen(dev->_defaultname_ch2);
+		dev->_filename_ch2 = kmemdup(dev->_defaultname_ch2,
+					     str_length + 1, GFP_KERNEL);
+
+		if (!dev->_filename_ch2)
+			goto error;
+	}
+
+	/* Default if filename is empty string */
+	if (strcmp(dev->input_filename_ch2, "") == 0) {
+		if (dev->_isNTSC_ch2) {
+			dev->_filename_ch2 = (dev->_pixel_format_ch2 ==
+				PIXEL_FRMT_411) ? "/root/vid411.yuv" :
+				"/root/vidtest.yuv";
+		} else {
+			dev->_filename_ch2 = (dev->_pixel_format_ch2 ==
+				PIXEL_FRMT_411) ? "/root/pal411.yuv" :
+				"/root/pal422.yuv";
+		}
+	}
+
+	retval = cx25821_sram_channel_setup_upstream(dev, sram_ch,
+						dev->_line_size_ch2, 0);
+
+	/* setup fifo + format */
+	cx25821_set_pixelengine_ch2(dev, sram_ch, dev->_pixel_format_ch2);
+
+	dev->upstream_riscbuf_size_ch2 = risc_buffer_size * 2;
+	dev->upstream_databuf_size_ch2 = data_frame_size * 2;
+
+	/* Allocating buffers and prepare RISC program */
+	retval = cx25821_upstream_buffer_prepare_ch2(dev, sram_ch,
+						dev->_line_size_ch2);
+	if (retval < 0) {
+		pr_err("%s: Failed to set up Video upstream buffers!\n",
+		       dev->name);
+		goto error;
+	}
+
+	cx25821_start_video_dma_upstream_ch2(dev, sram_ch);
+
+	return 0;
+
+error:
+	cx25821_dev_unregister(dev);
+
+	return err;
+}
diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.h b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.h
new file mode 100644
index 0000000..d42dab5
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.h
@@ -0,0 +1,138 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <hiep.huynh@conexant.com>, <shu.lin@conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+#define OPEN_FILE_1           0
+#define NUM_PROGS             8
+#define NUM_FRAMES            2
+#define ODD_FIELD             0
+#define EVEN_FIELD            1
+#define TOP_OFFSET            0
+#define FIFO_DISABLE          0
+#define FIFO_ENABLE           1
+#define TEST_FRAMES           5
+#define END_OF_FILE           0
+#define IN_PROGRESS           1
+#define RESET_STATUS          -1
+#define NUM_NO_OPS            5
+
+/* PAL and NTSC line sizes and number of lines. */
+#define WIDTH_D1              720
+#define NTSC_LINES_PER_FRAME  480
+#define PAL_LINES_PER_FRAME   576
+#define PAL_LINE_SZ           1440
+#define Y422_LINE_SZ          1440
+#define Y411_LINE_SZ          1080
+#define NTSC_FIELD_HEIGHT     240
+#define NTSC_ODD_FLD_LINES    241
+#define PAL_FIELD_HEIGHT      288
+
+#define FRAME_SIZE_NTSC_Y422    (NTSC_LINES_PER_FRAME * Y422_LINE_SZ)
+#define FRAME_SIZE_NTSC_Y411    (NTSC_LINES_PER_FRAME * Y411_LINE_SZ)
+#define FRAME_SIZE_PAL_Y422     (PAL_LINES_PER_FRAME * Y422_LINE_SZ)
+#define FRAME_SIZE_PAL_Y411     (PAL_LINES_PER_FRAME * Y411_LINE_SZ)
+
+#define NTSC_DATA_BUF_SZ        (Y422_LINE_SZ * NTSC_LINES_PER_FRAME)
+#define PAL_DATA_BUF_SZ         (Y422_LINE_SZ * PAL_LINES_PER_FRAME)
+
+#define RISC_WRITECR_INSTRUCTION_SIZE   16
+#define RISC_SYNC_INSTRUCTION_SIZE      4
+#define JUMP_INSTRUCTION_SIZE           12
+#define MAXSIZE_NO_OPS                  36
+#define DWORD_SIZE                      4
+
+#define USE_RISC_NOOP_VIDEO   1
+
+#ifdef USE_RISC_NOOP_VIDEO
+#define PAL_US_VID_PROG_SIZE						\
+	(PAL_FIELD_HEIGHT * 3 * DWORD_SIZE +				\
+	 RISC_WRITECR_INSTRUCTION_SIZE + RISC_SYNC_INSTRUCTION_SIZE +	\
+	 NUM_NO_OPS * DWORD_SIZE)
+
+#define PAL_RISC_BUF_SIZE         (2 * PAL_US_VID_PROG_SIZE)
+
+#define PAL_VID_PROG_SIZE						\
+	((PAL_FIELD_HEIGHT * 2) * 3 * DWORD_SIZE +			\
+	 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \
+	 JUMP_INSTRUCTION_SIZE + 2 * NUM_NO_OPS * DWORD_SIZE)
+
+#define ODD_FLD_PAL_PROG_SIZE						\
+	(PAL_FIELD_HEIGHT * 3 * DWORD_SIZE +				\
+	 RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE +	\
+	 NUM_NO_OPS * DWORD_SIZE)
+
+#define NTSC_US_VID_PROG_SIZE						\
+	((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE +			\
+	 RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE +	\
+	 NUM_NO_OPS * DWORD_SIZE)
+
+#define NTSC_RISC_BUF_SIZE						\
+	(2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE))
+
+#define FRAME1_VID_PROG_SIZE						\
+	((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) *			\
+	 3 * DWORD_SIZE + 2 * RISC_SYNC_INSTRUCTION_SIZE +		\
+	 RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE +	\
+	 2 * NUM_NO_OPS * DWORD_SIZE)
+
+#define ODD_FLD_NTSC_PROG_SIZE						\
+	(NTSC_ODD_FLD_LINES * 3 * DWORD_SIZE +				\
+	 RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE +	\
+	 NUM_NO_OPS * DWORD_SIZE)
+#endif
+
+#ifndef USE_RISC_NOOP_VIDEO
+#define PAL_US_VID_PROG_SIZE						\
+	((PAL_FIELD_HEIGHT + 1) * 3 * DWORD_SIZE +			\
+	 RISC_WRITECR_INSTRUCTION_SIZE)
+
+#define PAL_RISC_BUF_SIZE						\
+	(2 * (RISC_SYNC_INSTRUCTION_SIZE + PAL_US_VID_PROG_SIZE))
+
+#define PAL_VID_PROG_SIZE						\
+	((PAL_FIELD_HEIGHT * 2) * 3 * DWORD_SIZE +			\
+	 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \
+	 JUMP_INSTRUCTION_SIZE)
+
+#define ODD_FLD_PAL_PROG_SIZE						\
+	(PAL_FIELD_HEIGHT * 3 * DWORD_SIZE +				\
+	 RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE)
+
+#define ODD_FLD_NTSC_PROG_SIZE						\
+	(NTSC_ODD_FLD_LINES * 3 * DWORD_SIZE +				\
+	 RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE)
+
+#define NTSC_US_VID_PROG_SIZE						\
+	((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE +			\
+	 RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE)
+
+#define NTSC_RISC_BUF_SIZE						\
+	(2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE))
+
+#define FRAME1_VID_PROG_SIZE						\
+	((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) *			\
+	 3 * DWORD_SIZE + 2 * RISC_SYNC_INSTRUCTION_SIZE +		\
+	 RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE)
+
+#endif
diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.c b/drivers/media/pci/cx25821/cx25821-video-upstream.c
new file mode 100644
index 0000000..52c13e0
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-video-upstream.c
@@ -0,0 +1,856 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <hiep.huynh@conexant.com>, <shu.lin@conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "cx25821-video.h"
+#include "cx25821-video-upstream.h"
+
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/file.h>
+#include <linux/fcntl.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
+MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
+MODULE_LICENSE("GPL");
+
+static int _intr_msk = FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC |
+			FLD_VID_SRC_OPC_ERR;
+
+int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev,
+					struct sram_channel *ch,
+					unsigned int bpl, u32 risc)
+{
+	unsigned int i, lines;
+	u32 cdt;
+
+	if (ch->cmds_start == 0) {
+		cx_write(ch->ptr1_reg, 0);
+		cx_write(ch->ptr2_reg, 0);
+		cx_write(ch->cnt2_reg, 0);
+		cx_write(ch->cnt1_reg, 0);
+		return 0;
+	}
+
+	bpl = (bpl + 7) & ~7;	/* alignment */
+	cdt = ch->cdt;
+	lines = ch->fifo_size / bpl;
+
+	if (lines > 4)
+		lines = 4;
+
+	BUG_ON(lines < 2);
+
+	/* write CDT */
+	for (i = 0; i < lines; i++) {
+		cx_write(cdt + 16 * i, ch->fifo_start + bpl * i);
+		cx_write(cdt + 16 * i + 4, 0);
+		cx_write(cdt + 16 * i + 8, 0);
+		cx_write(cdt + 16 * i + 12, 0);
+	}
+
+	/* write CMDS */
+	cx_write(ch->cmds_start + 0, risc);
+
+	cx_write(ch->cmds_start + 4, 0);
+	cx_write(ch->cmds_start + 8, cdt);
+	cx_write(ch->cmds_start + 12, (lines * 16) >> 3);
+	cx_write(ch->cmds_start + 16, ch->ctrl_start);
+
+	cx_write(ch->cmds_start + 20, VID_IQ_SIZE_DW);
+
+	for (i = 24; i < 80; i += 4)
+		cx_write(ch->cmds_start + i, 0);
+
+	/* fill registers */
+	cx_write(ch->ptr1_reg, ch->fifo_start);
+	cx_write(ch->ptr2_reg, cdt);
+	cx_write(ch->cnt2_reg, (lines * 16) >> 3);
+	cx_write(ch->cnt1_reg, (bpl >> 3) - 1);
+
+	return 0;
+}
+
+static __le32 *cx25821_update_riscprogram(struct cx25821_dev *dev,
+					  __le32 *rp, unsigned int offset,
+					  unsigned int bpl, u32 sync_line,
+					  unsigned int lines, int fifo_enable,
+					  int field_type)
+{
+	unsigned int line, i;
+	int dist_betwn_starts = bpl * 2;
+
+	*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
+
+	if (USE_RISC_NOOP_VIDEO) {
+		for (i = 0; i < NUM_NO_OPS; i++)
+			*(rp++) = cpu_to_le32(RISC_NOOP);
+	}
+
+	/* scan lines */
+	for (line = 0; line < lines; line++) {
+		*(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl);
+		*(rp++) = cpu_to_le32(dev->_data_buf_phys_addr + offset);
+		*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
+
+		if ((lines <= NTSC_FIELD_HEIGHT)
+		    || (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC)) {
+			offset += dist_betwn_starts;
+		}
+	}
+
+	return rp;
+}
+
+static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp,
+					   dma_addr_t databuf_phys_addr,
+					   unsigned int offset, u32 sync_line,
+					   unsigned int bpl, unsigned int lines,
+					   int fifo_enable, int field_type)
+{
+	unsigned int line, i;
+	struct sram_channel *sram_ch =
+		dev->channels[dev->_channel_upstream_select].sram_channels;
+	int dist_betwn_starts = bpl * 2;
+
+	/* sync instruction */
+	if (sync_line != NO_SYNC_LINE)
+		*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
+
+	if (USE_RISC_NOOP_VIDEO) {
+		for (i = 0; i < NUM_NO_OPS; i++)
+			*(rp++) = cpu_to_le32(RISC_NOOP);
+	}
+
+	/* scan lines */
+	for (line = 0; line < lines; line++) {
+		*(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl);
+		*(rp++) = cpu_to_le32(databuf_phys_addr + offset);
+		*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
+
+		if ((lines <= NTSC_FIELD_HEIGHT)
+		    || (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC))
+			/* to skip the other field line */
+			offset += dist_betwn_starts;
+
+		/* check if we need to enable the FIFO after the first 4 lines
+		 * For the upstream video channel, the risc engine will enable
+		 * the FIFO. */
+		if (fifo_enable && line == 3) {
+			*(rp++) = RISC_WRITECR;
+			*(rp++) = sram_ch->dma_ctl;
+			*(rp++) = FLD_VID_FIFO_EN;
+			*(rp++) = 0x00000001;
+		}
+	}
+
+	return rp;
+}
+
+int cx25821_risc_buffer_upstream(struct cx25821_dev *dev,
+				 struct pci_dev *pci,
+				 unsigned int top_offset,
+				 unsigned int bpl, unsigned int lines)
+{
+	__le32 *rp;
+	int fifo_enable = 0;
+	/* get line count for single field */
+	int singlefield_lines = lines >> 1;
+	int odd_num_lines = singlefield_lines;
+	int frame = 0;
+	int frame_size = 0;
+	int databuf_offset = 0;
+	int risc_program_size = 0;
+	int risc_flag = RISC_CNT_RESET;
+	unsigned int bottom_offset = bpl;
+	dma_addr_t risc_phys_jump_addr;
+
+	if (dev->_isNTSC) {
+		odd_num_lines = singlefield_lines + 1;
+		risc_program_size = FRAME1_VID_PROG_SIZE;
+		frame_size = (bpl == Y411_LINE_SZ) ?
+			FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422;
+	} else {
+		risc_program_size = PAL_VID_PROG_SIZE;
+		frame_size = (bpl == Y411_LINE_SZ) ?
+			FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422;
+	}
+
+	/* Virtual address of Risc buffer program */
+	rp = dev->_dma_virt_addr;
+
+	for (frame = 0; frame < NUM_FRAMES; frame++) {
+		databuf_offset = frame_size * frame;
+
+		if (UNSET != top_offset) {
+			fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE;
+			rp = cx25821_risc_field_upstream(dev, rp,
+					dev->_data_buf_phys_addr +
+					databuf_offset, top_offset, 0, bpl,
+					odd_num_lines, fifo_enable, ODD_FIELD);
+		}
+
+		fifo_enable = FIFO_DISABLE;
+
+		/* Even Field */
+		rp = cx25821_risc_field_upstream(dev, rp,
+						 dev->_data_buf_phys_addr +
+						 databuf_offset, bottom_offset,
+						 0x200, bpl, singlefield_lines,
+						 fifo_enable, EVEN_FIELD);
+
+		if (frame == 0) {
+			risc_flag = RISC_CNT_RESET;
+			risc_phys_jump_addr = dev->_dma_phys_start_addr +
+				risc_program_size;
+		} else {
+			risc_phys_jump_addr = dev->_dma_phys_start_addr;
+			risc_flag = RISC_CNT_INC;
+		}
+
+		/* Loop to 2ndFrameRISC or to Start of Risc
+		 * program & generate IRQ
+		 */
+		*(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag);
+		*(rp++) = cpu_to_le32(risc_phys_jump_addr);
+		*(rp++) = cpu_to_le32(0);
+	}
+
+	return 0;
+}
+
+void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev)
+{
+	struct sram_channel *sram_ch =
+		dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels;
+	u32 tmp = 0;
+
+	if (!dev->_is_running) {
+		pr_info("No video file is currently running so return!\n");
+		return;
+	}
+	/* Disable RISC interrupts */
+	tmp = cx_read(sram_ch->int_msk);
+	cx_write(sram_ch->int_msk, tmp & ~_intr_msk);
+
+	/* Turn OFF risc and fifo enable */
+	tmp = cx_read(sram_ch->dma_ctl);
+	cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN));
+
+	/* Clear data buffer memory */
+	if (dev->_data_buf_virt_addr)
+		memset(dev->_data_buf_virt_addr, 0, dev->_data_buf_size);
+
+	dev->_is_running = 0;
+	dev->_is_first_frame = 0;
+	dev->_frame_count = 0;
+	dev->_file_status = END_OF_FILE;
+
+	kfree(dev->_irq_queues);
+	dev->_irq_queues = NULL;
+
+	kfree(dev->_filename);
+
+	tmp = cx_read(VID_CH_MODE_SEL);
+	cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00);
+}
+
+void cx25821_free_mem_upstream_ch1(struct cx25821_dev *dev)
+{
+	if (dev->_is_running)
+		cx25821_stop_upstream_video_ch1(dev);
+
+	if (dev->_dma_virt_addr) {
+		pci_free_consistent(dev->pci, dev->_risc_size,
+				    dev->_dma_virt_addr, dev->_dma_phys_addr);
+		dev->_dma_virt_addr = NULL;
+	}
+
+	if (dev->_data_buf_virt_addr) {
+		pci_free_consistent(dev->pci, dev->_data_buf_size,
+				    dev->_data_buf_virt_addr,
+				    dev->_data_buf_phys_addr);
+		dev->_data_buf_virt_addr = NULL;
+	}
+}
+
+int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
+{
+	struct file *myfile;
+	int frame_index_temp = dev->_frame_index;
+	int i = 0;
+	int line_size = (dev->_pixel_format == PIXEL_FRMT_411) ?
+		Y411_LINE_SZ : Y422_LINE_SZ;
+	int frame_size = 0;
+	int frame_offset = 0;
+	ssize_t vfs_read_retval = 0;
+	char mybuf[line_size];
+	loff_t file_offset;
+	loff_t pos;
+	mm_segment_t old_fs;
+
+	if (dev->_file_status == END_OF_FILE)
+		return 0;
+
+	if (dev->_isNTSC)
+		frame_size = (line_size == Y411_LINE_SZ) ?
+			FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422;
+	else
+		frame_size = (line_size == Y411_LINE_SZ) ?
+			FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422;
+
+	frame_offset = (frame_index_temp > 0) ? frame_size : 0;
+	file_offset = dev->_frame_count * frame_size;
+
+	myfile = filp_open(dev->_filename, O_RDONLY | O_LARGEFILE, 0);
+
+	if (IS_ERR(myfile)) {
+		const int open_errno = -PTR_ERR(myfile);
+		pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
+		       __func__, dev->_filename, open_errno);
+		return PTR_ERR(myfile);
+	} else {
+		if (!(myfile->f_op)) {
+			pr_err("%s(): File has no file operations registered!\n",
+			       __func__);
+			filp_close(myfile, NULL);
+			return -EIO;
+		}
+
+		if (!myfile->f_op->read) {
+			pr_err("%s(): File has no READ operations registered!\n",
+			       __func__);
+			filp_close(myfile, NULL);
+			return -EIO;
+		}
+
+		pos = myfile->f_pos;
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+
+		for (i = 0; i < dev->_lines_count; i++) {
+			pos = file_offset;
+
+			vfs_read_retval = vfs_read(myfile, mybuf, line_size,
+					&pos);
+
+			if (vfs_read_retval > 0 && vfs_read_retval == line_size
+			    && dev->_data_buf_virt_addr != NULL) {
+				memcpy((void *)(dev->_data_buf_virt_addr +
+						frame_offset / 4), mybuf,
+				       vfs_read_retval);
+			}
+
+			file_offset += vfs_read_retval;
+			frame_offset += vfs_read_retval;
+
+			if (vfs_read_retval < line_size) {
+				pr_info("Done: exit %s() since no more bytes to read from Video file\n",
+					__func__);
+				break;
+			}
+		}
+
+		if (i > 0)
+			dev->_frame_count++;
+
+		dev->_file_status = (vfs_read_retval == line_size) ?
+			IN_PROGRESS : END_OF_FILE;
+
+		set_fs(old_fs);
+		filp_close(myfile, NULL);
+	}
+
+	return 0;
+}
+
+static void cx25821_vidups_handler(struct work_struct *work)
+{
+	struct cx25821_dev *dev = container_of(work, struct cx25821_dev,
+			_irq_work_entry);
+
+	if (!dev) {
+		pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n",
+		       __func__);
+		return;
+	}
+
+	cx25821_get_frame(dev, dev->channels[dev->_channel_upstream_select].
+			sram_channels);
+}
+
+int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
+{
+	struct file *myfile;
+	int i = 0, j = 0;
+	int line_size = (dev->_pixel_format == PIXEL_FRMT_411) ?
+		Y411_LINE_SZ : Y422_LINE_SZ;
+	ssize_t vfs_read_retval = 0;
+	char mybuf[line_size];
+	loff_t pos;
+	loff_t offset = (unsigned long)0;
+	mm_segment_t old_fs;
+
+	myfile = filp_open(dev->_filename, O_RDONLY | O_LARGEFILE, 0);
+
+	if (IS_ERR(myfile)) {
+		const int open_errno = -PTR_ERR(myfile);
+		pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
+		       __func__, dev->_filename, open_errno);
+		return PTR_ERR(myfile);
+	} else {
+		if (!(myfile->f_op)) {
+			pr_err("%s(): File has no file operations registered!\n",
+			       __func__);
+			filp_close(myfile, NULL);
+			return -EIO;
+		}
+
+		if (!myfile->f_op->read) {
+			pr_err("%s(): File has no READ operations registered!  Returning\n",
+			       __func__);
+			filp_close(myfile, NULL);
+			return -EIO;
+		}
+
+		pos = myfile->f_pos;
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+
+		for (j = 0; j < NUM_FRAMES; j++) {
+			for (i = 0; i < dev->_lines_count; i++) {
+				pos = offset;
+
+				vfs_read_retval = vfs_read(myfile, mybuf,
+						line_size, &pos);
+
+				if (vfs_read_retval > 0
+				    && vfs_read_retval == line_size
+				    && dev->_data_buf_virt_addr != NULL) {
+					memcpy((void *)(dev->
+							_data_buf_virt_addr +
+							offset / 4), mybuf,
+					       vfs_read_retval);
+				}
+
+				offset += vfs_read_retval;
+
+				if (vfs_read_retval < line_size) {
+					pr_info("Done: exit %s() since no more bytes to read from Video file\n",
+						__func__);
+					break;
+				}
+			}
+
+			if (i > 0)
+				dev->_frame_count++;
+
+			if (vfs_read_retval < line_size)
+				break;
+		}
+
+		dev->_file_status = (vfs_read_retval == line_size) ?
+			IN_PROGRESS : END_OF_FILE;
+
+		set_fs(old_fs);
+		myfile->f_pos = 0;
+		filp_close(myfile, NULL);
+	}
+
+	return 0;
+}
+
+int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev,
+				    struct sram_channel *sram_ch, int bpl)
+{
+	int ret = 0;
+	dma_addr_t dma_addr;
+	dma_addr_t data_dma_addr;
+
+	if (dev->_dma_virt_addr != NULL)
+		pci_free_consistent(dev->pci, dev->upstream_riscbuf_size,
+				dev->_dma_virt_addr, dev->_dma_phys_addr);
+
+	dev->_dma_virt_addr = pci_alloc_consistent(dev->pci,
+			dev->upstream_riscbuf_size, &dma_addr);
+	dev->_dma_virt_start_addr = dev->_dma_virt_addr;
+	dev->_dma_phys_start_addr = dma_addr;
+	dev->_dma_phys_addr = dma_addr;
+	dev->_risc_size = dev->upstream_riscbuf_size;
+
+	if (!dev->_dma_virt_addr) {
+		pr_err("FAILED to allocate memory for Risc buffer! Returning\n");
+		return -ENOMEM;
+	}
+
+	/* Clear memory at address */
+	memset(dev->_dma_virt_addr, 0, dev->_risc_size);
+
+	if (dev->_data_buf_virt_addr != NULL)
+		pci_free_consistent(dev->pci, dev->upstream_databuf_size,
+				dev->_data_buf_virt_addr,
+				dev->_data_buf_phys_addr);
+	/* For Video Data buffer allocation */
+	dev->_data_buf_virt_addr = pci_alloc_consistent(dev->pci,
+			dev->upstream_databuf_size, &data_dma_addr);
+	dev->_data_buf_phys_addr = data_dma_addr;
+	dev->_data_buf_size = dev->upstream_databuf_size;
+
+	if (!dev->_data_buf_virt_addr) {
+		pr_err("FAILED to allocate memory for data buffer! Returning\n");
+		return -ENOMEM;
+	}
+
+	/* Clear memory at address */
+	memset(dev->_data_buf_virt_addr, 0, dev->_data_buf_size);
+
+	ret = cx25821_openfile(dev, sram_ch);
+	if (ret < 0)
+		return ret;
+
+	/* Create RISC programs */
+	ret = cx25821_risc_buffer_upstream(dev, dev->pci, 0, bpl,
+			dev->_lines_count);
+	if (ret < 0) {
+		pr_info("Failed creating Video Upstream Risc programs!\n");
+		goto error;
+	}
+
+	return 0;
+
+error:
+	return ret;
+}
+
+int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num,
+			       u32 status)
+{
+	u32 int_msk_tmp;
+	struct sram_channel *channel = dev->channels[chan_num].sram_channels;
+	int singlefield_lines = NTSC_FIELD_HEIGHT;
+	int line_size_in_bytes = Y422_LINE_SZ;
+	int odd_risc_prog_size = 0;
+	dma_addr_t risc_phys_jump_addr;
+	__le32 *rp;
+
+	if (status & FLD_VID_SRC_RISC1) {
+		/* We should only process one program per call */
+		u32 prog_cnt = cx_read(channel->gpcnt);
+
+		/* Since we've identified our IRQ, clear our bits from the
+		 * interrupt mask and interrupt status registers */
+		int_msk_tmp = cx_read(channel->int_msk);
+		cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk);
+		cx_write(channel->int_stat, _intr_msk);
+
+		spin_lock(&dev->slock);
+
+		dev->_frame_index = prog_cnt;
+
+		queue_work(dev->_irq_queues, &dev->_irq_work_entry);
+
+		if (dev->_is_first_frame) {
+			dev->_is_first_frame = 0;
+
+			if (dev->_isNTSC) {
+				singlefield_lines += 1;
+				odd_risc_prog_size = ODD_FLD_NTSC_PROG_SIZE;
+			} else {
+				singlefield_lines = PAL_FIELD_HEIGHT;
+				odd_risc_prog_size = ODD_FLD_PAL_PROG_SIZE;
+			}
+
+			if (dev->_dma_virt_start_addr != NULL) {
+				line_size_in_bytes =
+				    (dev->_pixel_format ==
+				     PIXEL_FRMT_411) ? Y411_LINE_SZ :
+				    Y422_LINE_SZ;
+				risc_phys_jump_addr =
+				    dev->_dma_phys_start_addr +
+				    odd_risc_prog_size;
+
+				rp = cx25821_update_riscprogram(dev,
+					dev->_dma_virt_start_addr, TOP_OFFSET,
+					line_size_in_bytes, 0x0,
+					singlefield_lines, FIFO_DISABLE,
+					ODD_FIELD);
+
+				/* Jump to Even Risc program of 1st Frame */
+				*(rp++) = cpu_to_le32(RISC_JUMP);
+				*(rp++) = cpu_to_le32(risc_phys_jump_addr);
+				*(rp++) = cpu_to_le32(0);
+			}
+		}
+
+		spin_unlock(&dev->slock);
+	} else {
+		if (status & FLD_VID_SRC_UF)
+			pr_err("%s(): Video Received Underflow Error Interrupt!\n",
+			       __func__);
+
+		if (status & FLD_VID_SRC_SYNC)
+			pr_err("%s(): Video Received Sync Error Interrupt!\n",
+			       __func__);
+
+		if (status & FLD_VID_SRC_OPC_ERR)
+			pr_err("%s(): Video Received OpCode Error Interrupt!\n",
+			       __func__);
+	}
+
+	if (dev->_file_status == END_OF_FILE) {
+		pr_err("EOF Channel 1 Framecount = %d\n", dev->_frame_count);
+		return -1;
+	}
+	/* ElSE, set the interrupt mask register, re-enable irq. */
+	int_msk_tmp = cx_read(channel->int_msk);
+	cx_write(channel->int_msk, int_msk_tmp |= _intr_msk);
+
+	return 0;
+}
+
+static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id)
+{
+	struct cx25821_dev *dev = dev_id;
+	u32 vid_status;
+	int handled = 0;
+	int channel_num = 0;
+	struct sram_channel *sram_ch;
+
+	if (!dev)
+		return -1;
+
+	channel_num = VID_UPSTREAM_SRAM_CHANNEL_I;
+
+	sram_ch = dev->channels[channel_num].sram_channels;
+
+	vid_status = cx_read(sram_ch->int_stat);
+
+	/* Only deal with our interrupt */
+	if (vid_status)
+		handled = cx25821_video_upstream_irq(dev, channel_num,
+				vid_status);
+
+	if (handled < 0)
+		cx25821_stop_upstream_video_ch1(dev);
+	else
+		handled += handled;
+
+	return IRQ_RETVAL(handled);
+}
+
+void cx25821_set_pixelengine(struct cx25821_dev *dev, struct sram_channel *ch,
+			     int pix_format)
+{
+	int width = WIDTH_D1;
+	int height = dev->_lines_count;
+	int num_lines, odd_num_lines;
+	u32 value;
+	int vip_mode = OUTPUT_FRMT_656;
+
+	value = ((pix_format & 0x3) << 12) | (vip_mode & 0x7);
+	value &= 0xFFFFFFEF;
+	value |= dev->_isNTSC ? 0 : 0x10;
+	cx_write(ch->vid_fmt_ctl, value);
+
+	/* set number of active pixels in each line.
+	 * Default is 720 pixels in both NTSC and PAL format */
+	cx_write(ch->vid_active_ctl1, width);
+
+	num_lines = (height / 2) & 0x3FF;
+	odd_num_lines = num_lines;
+
+	if (dev->_isNTSC)
+		odd_num_lines += 1;
+
+	value = (num_lines << 16) | odd_num_lines;
+
+	/* set number of active lines in field 0 (top) and field 1 (bottom) */
+	cx_write(ch->vid_active_ctl2, value);
+
+	cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3);
+}
+
+int cx25821_start_video_dma_upstream(struct cx25821_dev *dev,
+				     struct sram_channel *sram_ch)
+{
+	u32 tmp = 0;
+	int err = 0;
+
+	/* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for
+	 * channel A-C
+	 */
+	tmp = cx_read(VID_CH_MODE_SEL);
+	cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF);
+
+	/* Set the physical start address of the RISC program in the initial
+	 * program counter(IPC) member of the cmds.
+	 */
+	cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr);
+	/* Risc IPC High 64 bits 63-32 */
+	cx_write(sram_ch->cmds_start + 4, 0);
+
+	/* reset counter */
+	cx_write(sram_ch->gpcnt_ctl, 3);
+
+	/* Clear our bits from the interrupt status register. */
+	cx_write(sram_ch->int_stat, _intr_msk);
+
+	/* Set the interrupt mask register, enable irq. */
+	cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit));
+	tmp = cx_read(sram_ch->int_msk);
+	cx_write(sram_ch->int_msk, tmp |= _intr_msk);
+
+	err = request_irq(dev->pci->irq, cx25821_upstream_irq,
+			IRQF_SHARED, dev->name, dev);
+	if (err < 0) {
+		pr_err("%s: can't get upstream IRQ %d\n",
+		       dev->name, dev->pci->irq);
+		goto fail_irq;
+	}
+
+	/* Start the DMA  engine */
+	tmp = cx_read(sram_ch->dma_ctl);
+	cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN);
+
+	dev->_is_running = 1;
+	dev->_is_first_frame = 1;
+
+	return 0;
+
+fail_irq:
+	cx25821_dev_unregister(dev);
+	return err;
+}
+
+int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select,
+				 int pixel_format)
+{
+	struct sram_channel *sram_ch;
+	u32 tmp;
+	int retval = 0;
+	int err = 0;
+	int data_frame_size = 0;
+	int risc_buffer_size = 0;
+	int str_length = 0;
+
+	if (dev->_is_running) {
+		pr_info("Video Channel is still running so return!\n");
+		return 0;
+	}
+
+	dev->_channel_upstream_select = channel_select;
+	sram_ch = dev->channels[channel_select].sram_channels;
+
+	INIT_WORK(&dev->_irq_work_entry, cx25821_vidups_handler);
+	dev->_irq_queues = create_singlethread_workqueue("cx25821_workqueue");
+
+	if (!dev->_irq_queues) {
+		pr_err("create_singlethread_workqueue() for Video FAILED!\n");
+		return -ENOMEM;
+	}
+	/* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for
+	 * channel A-C
+	 */
+	tmp = cx_read(VID_CH_MODE_SEL);
+	cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF);
+
+	dev->_is_running = 0;
+	dev->_frame_count = 0;
+	dev->_file_status = RESET_STATUS;
+	dev->_lines_count = dev->_isNTSC ? 480 : 576;
+	dev->_pixel_format = pixel_format;
+	dev->_line_size = (dev->_pixel_format == PIXEL_FRMT_422) ?
+		(WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
+	data_frame_size = dev->_isNTSC ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ;
+	risc_buffer_size = dev->_isNTSC ?
+		NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE;
+
+	if (dev->input_filename) {
+		str_length = strlen(dev->input_filename);
+		dev->_filename = kmemdup(dev->input_filename, str_length + 1,
+					 GFP_KERNEL);
+
+		if (!dev->_filename)
+			goto error;
+	} else {
+		str_length = strlen(dev->_defaultname);
+		dev->_filename = kmemdup(dev->_defaultname, str_length + 1,
+					 GFP_KERNEL);
+
+		if (!dev->_filename)
+			goto error;
+	}
+
+	/* Default if filename is empty string */
+	if (strcmp(dev->input_filename, "") == 0) {
+		if (dev->_isNTSC) {
+			dev->_filename =
+				(dev->_pixel_format == PIXEL_FRMT_411) ?
+				"/root/vid411.yuv" : "/root/vidtest.yuv";
+		} else {
+			dev->_filename =
+				(dev->_pixel_format == PIXEL_FRMT_411) ?
+				"/root/pal411.yuv" : "/root/pal422.yuv";
+		}
+	}
+
+	dev->_is_running = 0;
+	dev->_frame_count = 0;
+	dev->_file_status = RESET_STATUS;
+	dev->_lines_count = dev->_isNTSC ? 480 : 576;
+	dev->_pixel_format = pixel_format;
+	dev->_line_size = (dev->_pixel_format == PIXEL_FRMT_422) ?
+		(WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
+
+	retval = cx25821_sram_channel_setup_upstream(dev, sram_ch,
+			dev->_line_size, 0);
+
+	/* setup fifo + format */
+	cx25821_set_pixelengine(dev, sram_ch, dev->_pixel_format);
+
+	dev->upstream_riscbuf_size = risc_buffer_size * 2;
+	dev->upstream_databuf_size = data_frame_size * 2;
+
+	/* Allocating buffers and prepare RISC program */
+	retval = cx25821_upstream_buffer_prepare(dev, sram_ch, dev->_line_size);
+	if (retval < 0) {
+		pr_err("%s: Failed to set up Video upstream buffers!\n",
+		       dev->name);
+		goto error;
+	}
+
+	cx25821_start_video_dma_upstream(dev, sram_ch);
+
+	return 0;
+
+error:
+	cx25821_dev_unregister(dev);
+
+	return err;
+}
diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.h b/drivers/media/pci/cx25821/cx25821-video-upstream.h
new file mode 100644
index 0000000..268ec8a
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-video-upstream.h
@@ -0,0 +1,139 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <hiep.huynh@conexant.com>, <shu.lin@conexant.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+#define OUTPUT_FRMT_656       0
+#define OPEN_FILE_1           0
+#define NUM_PROGS             8
+#define NUM_FRAMES            2
+#define ODD_FIELD             0
+#define EVEN_FIELD            1
+#define TOP_OFFSET            0
+#define FIFO_DISABLE          0
+#define FIFO_ENABLE           1
+#define TEST_FRAMES           5
+#define END_OF_FILE           0
+#define IN_PROGRESS           1
+#define RESET_STATUS          -1
+#define NUM_NO_OPS            5
+
+/* PAL and NTSC line sizes and number of lines. */
+#define WIDTH_D1              720
+#define NTSC_LINES_PER_FRAME  480
+#define PAL_LINES_PER_FRAME   576
+#define PAL_LINE_SZ           1440
+#define Y422_LINE_SZ          1440
+#define Y411_LINE_SZ          1080
+#define NTSC_FIELD_HEIGHT     240
+#define NTSC_ODD_FLD_LINES    241
+#define PAL_FIELD_HEIGHT      288
+
+#define FRAME_SIZE_NTSC_Y422    (NTSC_LINES_PER_FRAME * Y422_LINE_SZ)
+#define FRAME_SIZE_NTSC_Y411    (NTSC_LINES_PER_FRAME * Y411_LINE_SZ)
+#define FRAME_SIZE_PAL_Y422     (PAL_LINES_PER_FRAME * Y422_LINE_SZ)
+#define FRAME_SIZE_PAL_Y411     (PAL_LINES_PER_FRAME * Y411_LINE_SZ)
+
+#define NTSC_DATA_BUF_SZ        (Y422_LINE_SZ * NTSC_LINES_PER_FRAME)
+#define PAL_DATA_BUF_SZ         (Y422_LINE_SZ * PAL_LINES_PER_FRAME)
+
+#define RISC_WRITECR_INSTRUCTION_SIZE   16
+#define RISC_SYNC_INSTRUCTION_SIZE      4
+#define JUMP_INSTRUCTION_SIZE           12
+#define MAXSIZE_NO_OPS                  36
+#define DWORD_SIZE                      4
+
+#define USE_RISC_NOOP_VIDEO   1
+
+#ifdef USE_RISC_NOOP_VIDEO
+#define PAL_US_VID_PROG_SIZE						\
+	(PAL_FIELD_HEIGHT * 3 * DWORD_SIZE +				\
+	 RISC_WRITECR_INSTRUCTION_SIZE + RISC_SYNC_INSTRUCTION_SIZE +	\
+	 NUM_NO_OPS * DWORD_SIZE)
+
+#define PAL_RISC_BUF_SIZE           (2 * PAL_US_VID_PROG_SIZE)
+
+#define PAL_VID_PROG_SIZE						\
+	((PAL_FIELD_HEIGHT * 2) * 3 * DWORD_SIZE +			\
+	 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \
+	 JUMP_INSTRUCTION_SIZE + 2 * NUM_NO_OPS * DWORD_SIZE)
+
+#define ODD_FLD_PAL_PROG_SIZE						\
+	(PAL_FIELD_HEIGHT * 3 * DWORD_SIZE +				\
+	 RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE +	\
+	 NUM_NO_OPS * DWORD_SIZE)
+
+#define ODD_FLD_NTSC_PROG_SIZE						\
+	(NTSC_ODD_FLD_LINES * 3 * DWORD_SIZE +				\
+	 RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE +	\
+	 NUM_NO_OPS * DWORD_SIZE)
+
+#define NTSC_US_VID_PROG_SIZE						\
+	((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE +			\
+	 RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE +	\
+	 NUM_NO_OPS * DWORD_SIZE)
+
+#define NTSC_RISC_BUF_SIZE						\
+	(2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE))
+
+#define FRAME1_VID_PROG_SIZE						\
+	((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * 3 * DWORD_SIZE +	\
+	 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \
+	 JUMP_INSTRUCTION_SIZE + 2 * NUM_NO_OPS * DWORD_SIZE)
+
+#endif
+
+#ifndef USE_RISC_NOOP_VIDEO
+#define PAL_US_VID_PROG_SIZE						\
+	(PAL_FIELD_HEIGHT * 3 * DWORD_SIZE +				\
+	 RISC_WRITECR_INSTRUCTION_SIZE + RISC_SYNC_INSTRUCTION_SIZE +	\
+	 JUMP_INSTRUCTION_SIZE)
+
+#define PAL_RISC_BUF_SIZE		(2 * PAL_US_VID_PROG_SIZE)
+
+#define PAL_VID_PROG_SIZE						\
+	((PAL_FIELD_HEIGHT * 2) * 3 * DWORD_SIZE +			\
+	 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \
+	 JUMP_INSTRUCTION_SIZE)
+
+#define ODD_FLD_PAL_PROG_SIZE						\
+	(PAL_FIELD_HEIGHT * 3 * DWORD_SIZE +				\
+	 RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE)
+
+#define ODD_FLD_NTSC_PROG_SIZE						\
+	(NTSC_ODD_FLD_LINES * 3 * DWORD_SIZE +				\
+	 RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE)
+
+#define NTSC_US_VID_PROG_SIZE						\
+	((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE +			\
+	 RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE)
+
+#define NTSC_RISC_BUF_SIZE						\
+	(2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE))
+
+#define FRAME1_VID_PROG_SIZE						\
+	((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * 3 * DWORD_SIZE +	\
+	 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \
+	 JUMP_INSTRUCTION_SIZE)
+
+#endif
diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c
new file mode 100644
index 0000000..b38d437
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-video.c
@@ -0,0 +1,1990 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
+ *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
+ *  Parts adapted/taken from Eduardo Moscoso Rubino
+ *  Copyright (C) 2009 Eduardo Moscoso Rubino <moscoso@TopoLogica.com>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "cx25821-video.h"
+
+MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
+MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
+MODULE_LICENSE("GPL");
+
+static unsigned int video_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(video_nr, int, NULL, 0444);
+module_param_array(radio_nr, int, NULL, 0444);
+
+MODULE_PARM_DESC(video_nr, "video device numbers");
+MODULE_PARM_DESC(radio_nr, "radio device numbers");
+
+static unsigned int video_debug = VIDEO_DEBUG;
+module_param(video_debug, int, 0644);
+MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
+
+static unsigned int irq_debug;
+module_param(irq_debug, int, 0644);
+MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]");
+
+unsigned int vid_limit = 16;
+module_param(vid_limit, int, 0644);
+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
+
+static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num);
+
+static const struct v4l2_file_operations video_fops;
+static const struct v4l2_ioctl_ops video_ioctl_ops;
+
+#define FORMAT_FLAGS_PACKED       0x01
+
+struct cx25821_fmt formats[] = {
+	{
+		.name = "8 bpp, gray",
+		.fourcc = V4L2_PIX_FMT_GREY,
+		.depth = 8,
+		.flags = FORMAT_FLAGS_PACKED,
+	 }, {
+		.name = "4:1:1, packed, Y41P",
+		.fourcc = V4L2_PIX_FMT_Y41P,
+		.depth = 12,
+		.flags = FORMAT_FLAGS_PACKED,
+	}, {
+		.name = "4:2:2, packed, YUYV",
+		.fourcc = V4L2_PIX_FMT_YUYV,
+		.depth = 16,
+		.flags = FORMAT_FLAGS_PACKED,
+	}, {
+		.name = "4:2:2, packed, UYVY",
+		.fourcc = V4L2_PIX_FMT_UYVY,
+		.depth = 16,
+		.flags = FORMAT_FLAGS_PACKED,
+	}, {
+		.name = "4:2:0, YUV",
+		.fourcc = V4L2_PIX_FMT_YUV420,
+		.depth = 12,
+		.flags = FORMAT_FLAGS_PACKED,
+	},
+};
+
+int cx25821_get_format_size(void)
+{
+	return ARRAY_SIZE(formats);
+}
+
+struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc)
+{
+	unsigned int i;
+
+	if (fourcc == V4L2_PIX_FMT_Y41P || fourcc == V4L2_PIX_FMT_YUV411P)
+		return formats + 1;
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++)
+		if (formats[i].fourcc == fourcc)
+			return formats + i;
+
+	pr_err("%s(0x%08x) NOT FOUND\n", __func__, fourcc);
+	return NULL;
+}
+
+void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q,
+			  u32 count)
+{
+	struct cx25821_buffer *buf;
+	int bc;
+
+	for (bc = 0;; bc++) {
+		if (list_empty(&q->active)) {
+			dprintk(1, "bc=%d (=0: active empty)\n", bc);
+			break;
+		}
+
+		buf = list_entry(q->active.next, struct cx25821_buffer,
+				vb.queue);
+
+		/* count comes from the hw and it is 16bit wide --
+		 * this trick handles wrap-arounds correctly for
+		 * up to 32767 buffers in flight... */
+		if ((s16) (count - buf->count) < 0)
+			break;
+
+		do_gettimeofday(&buf->vb.ts);
+		buf->vb.state = VIDEOBUF_DONE;
+		list_del(&buf->vb.queue);
+		wake_up(&buf->vb.done);
+	}
+
+	if (list_empty(&q->active))
+		del_timer(&q->timeout);
+	else
+		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
+	if (bc != 1)
+		pr_err("%s: %d buffers handled (should be 1)\n", __func__, bc);
+}
+
+#ifdef TUNER_FLAG
+int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm)
+{
+	dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
+		__func__, (unsigned int)norm, v4l2_norm_to_name(norm));
+
+	dev->tvnorm = norm;
+
+	/* Tell the internal A/V decoder */
+	cx25821_call_all(dev, core, s_std, norm);
+
+	return 0;
+}
+#endif
+
+struct video_device *cx25821_vdev_init(struct cx25821_dev *dev,
+				       struct pci_dev *pci,
+				       struct video_device *template,
+				       char *type)
+{
+	struct video_device *vfd;
+	dprintk(1, "%s()\n", __func__);
+
+	vfd = video_device_alloc();
+	if (NULL == vfd)
+		return NULL;
+	*vfd = *template;
+	vfd->v4l2_dev = &dev->v4l2_dev;
+	vfd->release = video_device_release;
+	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type,
+		 cx25821_boards[dev->board].name);
+	video_set_drvdata(vfd, dev);
+	return vfd;
+}
+
+/*
+static int cx25821_ctrl_query(struct v4l2_queryctrl *qctrl)
+{
+	int i;
+
+	if (qctrl->id < V4L2_CID_BASE || qctrl->id >= V4L2_CID_LASTP1)
+		return -EINVAL;
+	for (i = 0; i < CX25821_CTLS; i++)
+		if (cx25821_ctls[i].v.id == qctrl->id)
+			break;
+	if (i == CX25821_CTLS) {
+		*qctrl = no_ctl;
+		return 0;
+	}
+	*qctrl = cx25821_ctls[i].v;
+	return 0;
+}
+*/
+
+/* resource management */
+int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh,
+		    unsigned int bit)
+{
+	dprintk(1, "%s()\n", __func__);
+	if (fh->resources & bit)
+		/* have it already allocated */
+		return 1;
+
+	/* is it free? */
+	mutex_lock(&dev->lock);
+	if (dev->channels[fh->channel_id].resources & bit) {
+		/* no, someone else uses it */
+		mutex_unlock(&dev->lock);
+		return 0;
+	}
+	/* it's free, grab it */
+	fh->resources |= bit;
+	dev->channels[fh->channel_id].resources |= bit;
+	dprintk(1, "res: get %d\n", bit);
+	mutex_unlock(&dev->lock);
+	return 1;
+}
+
+int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit)
+{
+	return fh->resources & bit;
+}
+
+int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit)
+{
+	return fh->dev->channels[fh->channel_id].resources & bit;
+}
+
+void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh,
+		      unsigned int bits)
+{
+	BUG_ON((fh->resources & bits) != bits);
+	dprintk(1, "%s()\n", __func__);
+
+	mutex_lock(&dev->lock);
+	fh->resources &= ~bits;
+	dev->channels[fh->channel_id].resources &= ~bits;
+	dprintk(1, "res: put %d\n", bits);
+	mutex_unlock(&dev->lock);
+}
+
+int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input)
+{
+	struct v4l2_routing route;
+	memset(&route, 0, sizeof(route));
+
+	dprintk(1, "%s(): video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n",
+		__func__, input, INPUT(input)->vmux, INPUT(input)->gpio0,
+		INPUT(input)->gpio1, INPUT(input)->gpio2, INPUT(input)->gpio3);
+	dev->input = input;
+
+	route.input = INPUT(input)->vmux;
+
+	/* Tell the internal A/V decoder */
+	cx25821_call_all(dev, video, s_routing, INPUT(input)->vmux, 0, 0);
+
+	return 0;
+}
+
+int cx25821_start_video_dma(struct cx25821_dev *dev,
+			    struct cx25821_dmaqueue *q,
+			    struct cx25821_buffer *buf,
+			    struct sram_channel *channel)
+{
+	int tmp = 0;
+
+	/* setup fifo + format */
+	cx25821_sram_channel_setup(dev, channel, buf->bpl, buf->risc.dma);
+
+	/* reset counter */
+	cx_write(channel->gpcnt_ctl, 3);
+	q->count = 1;
+
+	/* enable irq */
+	cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << channel->i));
+	cx_set(channel->int_msk, 0x11);
+
+	/* start dma */
+	cx_write(channel->dma_ctl, 0x11);	/* FIFO and RISC enable */
+
+	/* make sure upstream setting if any is reversed */
+	tmp = cx_read(VID_CH_MODE_SEL);
+	cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00);
+
+	return 0;
+}
+
+int cx25821_restart_video_queue(struct cx25821_dev *dev,
+				struct cx25821_dmaqueue *q,
+				struct sram_channel *channel)
+{
+	struct cx25821_buffer *buf, *prev;
+	struct list_head *item;
+
+	if (!list_empty(&q->active)) {
+		buf = list_entry(q->active.next, struct cx25821_buffer,
+				vb.queue);
+
+		cx25821_start_video_dma(dev, q, buf, channel);
+
+		list_for_each(item, &q->active) {
+			buf = list_entry(item, struct cx25821_buffer, vb.queue);
+			buf->count = q->count++;
+		}
+
+		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
+		return 0;
+	}
+
+	prev = NULL;
+	for (;;) {
+		if (list_empty(&q->queued))
+			return 0;
+
+		buf = list_entry(q->queued.next, struct cx25821_buffer,
+				vb.queue);
+
+		if (NULL == prev) {
+			list_move_tail(&buf->vb.queue, &q->active);
+			cx25821_start_video_dma(dev, q, buf, channel);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			buf->count = q->count++;
+			mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
+		} else if (prev->vb.width == buf->vb.width &&
+			   prev->vb.height == buf->vb.height &&
+			   prev->fmt == buf->fmt) {
+			list_move_tail(&buf->vb.queue, &q->active);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			buf->count = q->count++;
+			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+			prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */
+		} else {
+			return 0;
+		}
+		prev = buf;
+	}
+}
+
+void cx25821_vid_timeout(unsigned long data)
+{
+	struct cx25821_data *timeout_data = (struct cx25821_data *)data;
+	struct cx25821_dev *dev = timeout_data->dev;
+	struct sram_channel *channel = timeout_data->channel;
+	struct cx25821_dmaqueue *q = &dev->channels[channel->i].vidq;
+	struct cx25821_buffer *buf;
+	unsigned long flags;
+
+	/* cx25821_sram_channel_dump(dev, channel); */
+	cx_clear(channel->dma_ctl, 0x11);
+
+	spin_lock_irqsave(&dev->slock, flags);
+	while (!list_empty(&q->active)) {
+		buf = list_entry(q->active.next, struct cx25821_buffer,
+				vb.queue);
+		list_del(&buf->vb.queue);
+
+		buf->vb.state = VIDEOBUF_ERROR;
+		wake_up(&buf->vb.done);
+	}
+
+	cx25821_restart_video_queue(dev, q, channel);
+	spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
+{
+	u32 count = 0;
+	int handled = 0;
+	u32 mask;
+	struct sram_channel *channel = dev->channels[chan_num].sram_channels;
+
+	mask = cx_read(channel->int_msk);
+	if (0 == (status & mask))
+		return handled;
+
+	cx_write(channel->int_stat, status);
+
+	/* risc op code error */
+	if (status & (1 << 16)) {
+		pr_warn("%s, %s: video risc op code error\n",
+			dev->name, channel->name);
+		cx_clear(channel->dma_ctl, 0x11);
+		cx25821_sram_channel_dump(dev, channel);
+	}
+
+	/* risc1 y */
+	if (status & FLD_VID_DST_RISC1) {
+		spin_lock(&dev->slock);
+		count = cx_read(channel->gpcnt);
+		cx25821_video_wakeup(dev, &dev->channels[channel->i].vidq,
+				count);
+		spin_unlock(&dev->slock);
+		handled++;
+	}
+
+	/* risc2 y */
+	if (status & 0x10) {
+		dprintk(2, "stopper video\n");
+		spin_lock(&dev->slock);
+		cx25821_restart_video_queue(dev,
+				&dev->channels[channel->i].vidq, channel);
+		spin_unlock(&dev->slock);
+		handled++;
+	}
+	return handled;
+}
+
+void cx25821_videoioctl_unregister(struct cx25821_dev *dev)
+{
+	if (dev->ioctl_dev) {
+		if (video_is_registered(dev->ioctl_dev))
+			video_unregister_device(dev->ioctl_dev);
+		else
+			video_device_release(dev->ioctl_dev);
+
+		dev->ioctl_dev = NULL;
+	}
+}
+
+void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
+{
+	cx_clear(PCI_INT_MSK, 1);
+
+	if (dev->channels[chan_num].video_dev) {
+		if (video_is_registered(dev->channels[chan_num].video_dev))
+			video_unregister_device(
+					dev->channels[chan_num].video_dev);
+		else
+			video_device_release(
+					dev->channels[chan_num].video_dev);
+
+		dev->channels[chan_num].video_dev = NULL;
+
+		btcx_riscmem_free(dev->pci,
+				&dev->channels[chan_num].vidq.stopper);
+
+		pr_warn("device %d released!\n", chan_num);
+	}
+
+}
+
+int cx25821_video_register(struct cx25821_dev *dev)
+{
+	int err;
+	int i;
+
+	struct video_device cx25821_video_device = {
+		.name = "cx25821-video",
+		.fops = &video_fops,
+		.minor = -1,
+		.ioctl_ops = &video_ioctl_ops,
+		.tvnorms = CX25821_NORMS,
+		.current_norm = V4L2_STD_NTSC_M,
+	};
+
+	spin_lock_init(&dev->slock);
+
+	for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; ++i) {
+		cx25821_init_controls(dev, i);
+
+		cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper,
+			dev->channels[i].sram_channels->dma_ctl, 0x11, 0);
+
+		dev->channels[i].sram_channels = &cx25821_sram_channels[i];
+		dev->channels[i].video_dev = NULL;
+		dev->channels[i].resources = 0;
+
+		cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff);
+
+		INIT_LIST_HEAD(&dev->channels[i].vidq.active);
+		INIT_LIST_HEAD(&dev->channels[i].vidq.queued);
+
+		dev->channels[i].timeout_data.dev = dev;
+		dev->channels[i].timeout_data.channel =
+			&cx25821_sram_channels[i];
+		dev->channels[i].vidq.timeout.function = cx25821_vid_timeout;
+		dev->channels[i].vidq.timeout.data =
+			(unsigned long)&dev->channels[i].timeout_data;
+		init_timer(&dev->channels[i].vidq.timeout);
+
+		/* register v4l devices */
+		dev->channels[i].video_dev = cx25821_vdev_init(dev, dev->pci,
+				&cx25821_video_device, "video");
+
+		err = video_register_device(dev->channels[i].video_dev,
+				VFL_TYPE_GRABBER, video_nr[dev->nr]);
+
+		if (err < 0)
+			goto fail_unreg;
+
+	}
+
+	/* set PCI interrupt */
+	cx_set(PCI_INT_MSK, 0xff);
+
+	/* initial device configuration */
+	mutex_lock(&dev->lock);
+#ifdef TUNER_FLAG
+	dev->tvnorm = cx25821_video_device.current_norm;
+	cx25821_set_tvnorm(dev, dev->tvnorm);
+#endif
+	mutex_unlock(&dev->lock);
+
+	return 0;
+
+fail_unreg:
+	cx25821_video_unregister(dev, i);
+	return err;
+}
+
+int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count,
+		 unsigned int *size)
+{
+	struct cx25821_fh *fh = q->priv_data;
+
+	*size = fh->fmt->depth * fh->width * fh->height >> 3;
+
+	if (0 == *count)
+		*count = 32;
+
+	if (*size * *count > vid_limit * 1024 * 1024)
+		*count = (vid_limit * 1024 * 1024) / *size;
+
+	return 0;
+}
+
+int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+		   enum v4l2_field field)
+{
+	struct cx25821_fh *fh = q->priv_data;
+	struct cx25821_dev *dev = fh->dev;
+	struct cx25821_buffer *buf =
+		container_of(vb, struct cx25821_buffer, vb);
+	int rc, init_buffer = 0;
+	u32 line0_offset;
+	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+	int bpl_local = LINE_SIZE_D1;
+	int channel_opened = fh->channel_id;
+
+	BUG_ON(NULL == fh->fmt);
+	if (fh->width < 48 || fh->width > 720 ||
+	    fh->height < 32 || fh->height > 576)
+		return -EINVAL;
+
+	buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+
+	if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+		return -EINVAL;
+
+	if (buf->fmt != fh->fmt ||
+	    buf->vb.width != fh->width ||
+	    buf->vb.height != fh->height || buf->vb.field != field) {
+		buf->fmt = fh->fmt;
+		buf->vb.width = fh->width;
+		buf->vb.height = fh->height;
+		buf->vb.field = field;
+		init_buffer = 1;
+	}
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		init_buffer = 1;
+		rc = videobuf_iolock(q, &buf->vb, NULL);
+		if (0 != rc) {
+			printk(KERN_DEBUG pr_fmt("videobuf_iolock failed!\n"));
+			goto fail;
+		}
+	}
+
+	dprintk(1, "init_buffer=%d\n", init_buffer);
+
+	if (init_buffer) {
+
+		channel_opened = dev->channel_opened;
+		if (channel_opened < 0 || channel_opened > 7)
+			channel_opened = 7;
+
+		if (dev->channels[channel_opened].pixel_formats ==
+				PIXEL_FRMT_411)
+			buf->bpl = (buf->fmt->depth * buf->vb.width) >> 3;
+		else
+			buf->bpl = (buf->fmt->depth >> 3) * (buf->vb.width);
+
+		if (dev->channels[channel_opened].pixel_formats ==
+				PIXEL_FRMT_411) {
+			bpl_local = buf->bpl;
+		} else {
+			bpl_local = buf->bpl;   /* Default */
+
+			if (channel_opened >= 0 && channel_opened <= 7) {
+				if (dev->channels[channel_opened]
+						.use_cif_resolution) {
+					if (dev->tvnorm & V4L2_STD_PAL_BG ||
+					    dev->tvnorm & V4L2_STD_PAL_DK)
+						bpl_local = 352 << 1;
+					else
+						bpl_local = dev->channels[
+							channel_opened].
+							cif_width << 1;
+				}
+			}
+		}
+
+		switch (buf->vb.field) {
+		case V4L2_FIELD_TOP:
+			cx25821_risc_buffer(dev->pci, &buf->risc,
+					    dma->sglist, 0, UNSET,
+					    buf->bpl, 0, buf->vb.height);
+			break;
+		case V4L2_FIELD_BOTTOM:
+			cx25821_risc_buffer(dev->pci, &buf->risc,
+					    dma->sglist, UNSET, 0,
+					    buf->bpl, 0, buf->vb.height);
+			break;
+		case V4L2_FIELD_INTERLACED:
+			/* All other formats are top field first */
+			line0_offset = 0;
+			dprintk(1, "top field first\n");
+
+			cx25821_risc_buffer(dev->pci, &buf->risc,
+					    dma->sglist, line0_offset,
+					    bpl_local, bpl_local, bpl_local,
+					    buf->vb.height >> 1);
+			break;
+		case V4L2_FIELD_SEQ_TB:
+			cx25821_risc_buffer(dev->pci, &buf->risc,
+					    dma->sglist,
+					    0, buf->bpl * (buf->vb.height >> 1),
+					    buf->bpl, 0, buf->vb.height >> 1);
+			break;
+		case V4L2_FIELD_SEQ_BT:
+			cx25821_risc_buffer(dev->pci, &buf->risc,
+					    dma->sglist,
+					    buf->bpl * (buf->vb.height >> 1), 0,
+					    buf->bpl, 0, buf->vb.height >> 1);
+			break;
+		default:
+			BUG();
+		}
+	}
+
+	dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
+		buf, buf->vb.i, fh->width, fh->height, fh->fmt->depth,
+		fh->fmt->name, (unsigned long)buf->risc.dma);
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+
+	return 0;
+
+fail:
+	cx25821_free_buffer(q, buf);
+	return rc;
+}
+
+void cx25821_buffer_release(struct videobuf_queue *q,
+			    struct videobuf_buffer *vb)
+{
+	struct cx25821_buffer *buf =
+		container_of(vb, struct cx25821_buffer, vb);
+
+	cx25821_free_buffer(q, buf);
+}
+
+struct videobuf_queue *get_queue(struct cx25821_fh *fh)
+{
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return &fh->vidq;
+	default:
+		BUG();
+		return NULL;
+	}
+}
+
+int cx25821_get_resource(struct cx25821_fh *fh, int resource)
+{
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return resource;
+	default:
+		BUG();
+		return 0;
+	}
+}
+
+int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct cx25821_fh *fh = file->private_data;
+
+	return videobuf_mmap_mapper(get_queue(fh), vma);
+}
+
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct cx25821_buffer *buf =
+		container_of(vb, struct cx25821_buffer, vb);
+	struct cx25821_buffer *prev;
+	struct cx25821_fh *fh = vq->priv_data;
+	struct cx25821_dev *dev = fh->dev;
+	struct cx25821_dmaqueue *q = &dev->channels[fh->channel_id].vidq;
+
+	/* add jump to stopper */
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+	buf->risc.jmp[2] = cpu_to_le32(0);      /* bits 63-32 */
+
+	dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
+
+	if (!list_empty(&q->queued)) {
+		list_add_tail(&buf->vb.queue, &q->queued);
+		buf->vb.state = VIDEOBUF_QUEUED;
+		dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
+				buf->vb.i);
+
+	} else if (list_empty(&q->active)) {
+		list_add_tail(&buf->vb.queue, &q->active);
+		cx25821_start_video_dma(dev, q, buf,
+				dev->channels[fh->channel_id].sram_channels);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		buf->count = q->count++;
+		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
+		dprintk(2, "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
+				buf, buf->vb.i, buf->count, q->count);
+	} else {
+		prev = list_entry(q->active.prev, struct cx25821_buffer,
+				vb.queue);
+		if (prev->vb.width == buf->vb.width
+		   && prev->vb.height == buf->vb.height
+		   && prev->fmt == buf->fmt) {
+			list_add_tail(&buf->vb.queue, &q->active);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			buf->count = q->count++;
+			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+
+			/* 64 bit bits 63-32 */
+			prev->risc.jmp[2] = cpu_to_le32(0);
+			dprintk(2, "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
+					buf, buf->vb.i, buf->count);
+
+		} else {
+			list_add_tail(&buf->vb.queue, &q->queued);
+			buf->vb.state = VIDEOBUF_QUEUED;
+			dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
+					buf->vb.i);
+		}
+	}
+
+	if (list_empty(&q->active))
+		dprintk(2, "active queue empty!\n");
+}
+
+static struct videobuf_queue_ops cx25821_video_qops = {
+	.buf_setup = cx25821_buffer_setup,
+	.buf_prepare = cx25821_buffer_prepare,
+	.buf_queue = buffer_queue,
+	.buf_release = cx25821_buffer_release,
+};
+
+static int video_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct cx25821_dev *h, *dev = video_drvdata(file);
+	struct cx25821_fh *fh;
+	struct list_head *list;
+	int minor = video_devdata(file)->minor;
+	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	u32 pix_format;
+	int ch_id = 0;
+	int i;
+
+	dprintk(1, "open dev=%s type=%s\n", video_device_node_name(vdev),
+			v4l2_type_names[type]);
+
+	/* allocate + initialize per filehandle data */
+	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+	if (NULL == fh)
+		return -ENOMEM;
+
+	mutex_lock(&cx25821_devlist_mutex);
+
+	list_for_each(list, &cx25821_devlist)
+	{
+		h = list_entry(list, struct cx25821_dev, devlist);
+
+		for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) {
+			if (h->channels[i].video_dev &&
+			    h->channels[i].video_dev->minor == minor) {
+				dev = h;
+				ch_id = i;
+				type  = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+			}
+		}
+	}
+
+	if (NULL == dev) {
+		mutex_unlock(&cx25821_devlist_mutex);
+		kfree(fh);
+		return -ENODEV;
+	}
+
+	file->private_data = fh;
+	fh->dev = dev;
+	fh->type = type;
+	fh->width = 720;
+	fh->channel_id = ch_id;
+
+	if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
+		fh->height = 576;
+	else
+		fh->height = 480;
+
+	dev->channel_opened = fh->channel_id;
+	if (dev->channels[ch_id].pixel_formats == PIXEL_FRMT_411)
+		pix_format = V4L2_PIX_FMT_Y41P;
+	else
+		pix_format = V4L2_PIX_FMT_YUYV;
+	fh->fmt = cx25821_format_by_fourcc(pix_format);
+
+	v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio);
+
+	videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops, &dev->pci->dev,
+			&dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer),
+			fh, NULL);
+
+	dprintk(1, "post videobuf_queue_init()\n");
+	mutex_unlock(&cx25821_devlist_mutex);
+
+	return 0;
+}
+
+static ssize_t video_read(struct file *file, char __user * data, size_t count,
+			 loff_t *ppos)
+{
+	struct cx25821_fh *fh = file->private_data;
+
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		if (cx25821_res_locked(fh, RESOURCE_VIDEO0))
+			return -EBUSY;
+
+		return videobuf_read_one(&fh->vidq, data, count, ppos,
+					file->f_flags & O_NONBLOCK);
+
+	default:
+		BUG();
+		return 0;
+	}
+}
+
+static unsigned int video_poll(struct file *file,
+			      struct poll_table_struct *wait)
+{
+	struct cx25821_fh *fh = file->private_data;
+	struct cx25821_buffer *buf;
+
+	if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
+		/* streaming capture */
+		if (list_empty(&fh->vidq.stream))
+			return POLLERR;
+		buf = list_entry(fh->vidq.stream.next,
+				struct cx25821_buffer, vb.stream);
+	} else {
+		/* read() capture */
+		buf = (struct cx25821_buffer *)fh->vidq.read_buf;
+		if (NULL == buf)
+			return POLLERR;
+	}
+
+	poll_wait(file, &buf->vb.done, wait);
+	if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
+		if (buf->vb.state == VIDEOBUF_DONE) {
+			struct cx25821_dev *dev = fh->dev;
+
+			if (dev && dev->channels[fh->channel_id]
+					.use_cif_resolution) {
+				u8 cam_id = *((char *)buf->vb.baddr + 3);
+				memcpy((char *)buf->vb.baddr,
+				      (char *)buf->vb.baddr + (fh->width * 2),
+				      (fh->width * 2));
+				*((char *)buf->vb.baddr + 3) = cam_id;
+			}
+		}
+
+		return POLLIN | POLLRDNORM;
+	}
+
+	return 0;
+}
+
+static int video_release(struct file *file)
+{
+	struct cx25821_fh *fh = file->private_data;
+	struct cx25821_dev *dev = fh->dev;
+
+	/* stop the risc engine and fifo */
+	cx_write(channel0->dma_ctl, 0); /* FIFO and RISC disable */
+
+	/* stop video capture */
+	if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
+		videobuf_queue_cancel(&fh->vidq);
+		cx25821_res_free(dev, fh, RESOURCE_VIDEO0);
+	}
+
+	if (fh->vidq.read_buf) {
+		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
+		kfree(fh->vidq.read_buf);
+	}
+
+	videobuf_mmap_free(&fh->vidq);
+
+	v4l2_prio_close(&dev->channels[fh->channel_id].prio, fh->prio);
+	file->private_data = NULL;
+	kfree(fh);
+
+	return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct cx25821_fh *fh = priv;
+	struct cx25821_dev *dev = fh->dev;
+
+	if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
+		return -EINVAL;
+
+	if (unlikely(i != fh->type))
+		return -EINVAL;
+
+	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh,
+						RESOURCE_VIDEO0))))
+		return -EBUSY;
+
+	return videobuf_streamon(get_queue(fh));
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct cx25821_fh *fh = priv;
+	struct cx25821_dev *dev = fh->dev;
+	int err, res;
+
+	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (i != fh->type)
+		return -EINVAL;
+
+	res = cx25821_get_resource(fh, RESOURCE_VIDEO0);
+	err = videobuf_streamoff(get_queue(fh));
+	if (err < 0)
+		return err;
+	cx25821_res_free(dev, fh, res);
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct cx25821_fh *fh = priv;
+	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+	struct v4l2_mbus_framefmt mbus_fmt;
+	int err;
+	int pix_format = PIXEL_FRMT_422;
+
+	if (fh) {
+		err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
+				      fh->prio);
+		if (0 != err)
+			return err;
+	}
+
+	dprintk(2, "%s()\n", __func__);
+	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
+
+	if (0 != err)
+		return err;
+
+	fh->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
+	fh->vidq.field = f->fmt.pix.field;
+
+	/* check if width and height is valid based on set standard */
+	if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm))
+		fh->width = f->fmt.pix.width;
+
+	if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm))
+		fh->height = f->fmt.pix.height;
+
+	if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
+		pix_format = PIXEL_FRMT_411;
+	else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
+		pix_format = PIXEL_FRMT_422;
+	else
+		return -EINVAL;
+
+	cx25821_set_pixel_format(dev, SRAM_CH00, pix_format);
+
+	/* check if cif resolution */
+	if (fh->width == 320 || fh->width == 352)
+		dev->channels[fh->channel_id].use_cif_resolution = 1;
+	else
+		dev->channels[fh->channel_id].use_cif_resolution = 0;
+
+	dev->channels[fh->channel_id].cif_width = fh->width;
+	medusa_set_resolution(dev, fh->width, SRAM_CH00);
+
+	dprintk(2, "%s(): width=%d height=%d field=%d\n", __func__, fh->width,
+		fh->height, fh->vidq.field);
+	v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+	cx25821_call_all(dev, video, s_mbus_fmt, &mbus_fmt);
+
+	return 0;
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	int ret_val = 0;
+	struct cx25821_fh *fh = priv;
+	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+
+	ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
+
+	p->sequence = dev->channels[fh->channel_id].vidq.count;
+
+	return ret_val;
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+	struct cx25821_fh *fh = priv;
+	char name[32 + 2];
+
+	struct sram_channel *sram_ch = dev->channels[fh->channel_id]
+								.sram_channels;
+	u32 tmp = 0;
+
+	snprintf(name, sizeof(name), "%s/2", dev->name);
+	pr_info("%s/2: ============  START LOG STATUS  ============\n",
+		dev->name);
+	cx25821_call_all(dev, core, log_status);
+	tmp = cx_read(sram_ch->dma_ctl);
+	pr_info("Video input 0 is %s\n",
+		(tmp & 0x11) ? "streaming" : "stopped");
+	pr_info("%s/2: =============  END LOG STATUS  =============\n",
+		dev->name);
+	return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+			struct v4l2_control *ctl)
+{
+	struct cx25821_fh *fh = priv;
+	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+	int err;
+
+	if (fh) {
+		err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
+				      fh->prio);
+		if (0 != err)
+			return err;
+	}
+
+	return cx25821_set_control(dev, ctl, fh->channel_id);
+}
+
+/* VIDEO IOCTLS */
+int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+				 struct v4l2_format *f)
+{
+	struct cx25821_fh *fh = priv;
+
+	f->fmt.pix.width = fh->width;
+	f->fmt.pix.height = fh->height;
+	f->fmt.pix.field = fh->vidq.field;
+	f->fmt.pix.pixelformat = fh->fmt->fourcc;
+	f->fmt.pix.bytesperline = (f->fmt.pix.width * fh->fmt->depth) >> 3;
+	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return 0;
+}
+
+int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_format *f)
+{
+	struct cx25821_fmt *fmt;
+	enum v4l2_field field;
+	unsigned int maxw, maxh;
+
+	fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
+	if (NULL == fmt)
+		return -EINVAL;
+
+	field = f->fmt.pix.field;
+	maxw = 720;
+	maxh = 576;
+
+	if (V4L2_FIELD_ANY == field) {
+		if (f->fmt.pix.height > maxh / 2)
+			field = V4L2_FIELD_INTERLACED;
+		else
+			field = V4L2_FIELD_TOP;
+	}
+
+	switch (field) {
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+		maxh = maxh / 2;
+		break;
+	case V4L2_FIELD_INTERLACED:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	f->fmt.pix.field = field;
+	if (f->fmt.pix.height < 32)
+		f->fmt.pix.height = 32;
+	if (f->fmt.pix.height > maxh)
+		f->fmt.pix.height = maxh;
+	if (f->fmt.pix.width < 48)
+		f->fmt.pix.width = 48;
+	if (f->fmt.pix.width > maxw)
+		f->fmt.pix.width = maxw;
+	f->fmt.pix.width &= ~0x03;
+	f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
+	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return 0;
+}
+
+int cx25821_vidioc_querycap(struct file *file, void *priv,
+			    struct v4l2_capability *cap)
+{
+	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+
+	strcpy(cap->driver, "cx25821");
+	strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card));
+	sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
+	cap->version = CX25821_VERSION_CODE;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+		V4L2_CAP_STREAMING;
+	if (UNSET != dev->tuner_type)
+		cap->capabilities |= V4L2_CAP_TUNER;
+	return 0;
+}
+
+int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+			    struct v4l2_fmtdesc *f)
+{
+	if (unlikely(f->index >= ARRAY_SIZE(formats)))
+		return -EINVAL;
+
+	strlcpy(f->description, formats[f->index].name, sizeof(f->description));
+	f->pixelformat = formats[f->index].fourcc;
+
+	return 0;
+}
+
+int cx25821_vidioc_reqbufs(struct file *file, void *priv,
+			   struct v4l2_requestbuffers *p)
+{
+	struct cx25821_fh *fh = priv;
+	return videobuf_reqbufs(get_queue(fh), p);
+}
+
+int cx25821_vidioc_querybuf(struct file *file, void *priv,
+			    struct v4l2_buffer *p)
+{
+	struct cx25821_fh *fh = priv;
+	return videobuf_querybuf(get_queue(fh), p);
+}
+
+int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct cx25821_fh *fh = priv;
+	return videobuf_qbuf(get_queue(fh), p);
+}
+
+int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p)
+{
+	struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
+	struct cx25821_fh *fh = f;
+
+	*p = v4l2_prio_max(&dev->channels[fh->channel_id].prio);
+
+	return 0;
+}
+
+int cx25821_vidioc_s_priority(struct file *file, void *f,
+			      enum v4l2_priority prio)
+{
+	struct cx25821_fh *fh = f;
+	struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
+
+	return v4l2_prio_change(&dev->channels[fh->channel_id].prio, &fh->prio,
+			prio);
+}
+
+#ifdef TUNER_FLAG
+int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id * tvnorms)
+{
+	struct cx25821_fh *fh = priv;
+	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+	int err;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (fh) {
+		err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
+				      fh->prio);
+		if (0 != err)
+			return err;
+	}
+
+	if (dev->tvnorm == *tvnorms)
+		return 0;
+
+	mutex_lock(&dev->lock);
+	cx25821_set_tvnorm(dev, *tvnorms);
+	mutex_unlock(&dev->lock);
+
+	medusa_set_videostandard(dev);
+
+	return 0;
+}
+#endif
+
+int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i)
+{
+	static const char * const iname[] = {
+		[CX25821_VMUX_COMPOSITE] = "Composite",
+		[CX25821_VMUX_SVIDEO] = "S-Video",
+		[CX25821_VMUX_DEBUG] = "for debug only",
+	};
+	unsigned int n;
+	dprintk(1, "%s()\n", __func__);
+
+	n = i->index;
+	if (n >= 2)
+		return -EINVAL;
+
+	if (0 == INPUT(n)->type)
+		return -EINVAL;
+
+	i->type = V4L2_INPUT_TYPE_CAMERA;
+	strcpy(i->name, iname[INPUT(n)->type]);
+
+	i->std = CX25821_NORMS;
+	return 0;
+}
+
+int cx25821_vidioc_enum_input(struct file *file, void *priv,
+			      struct v4l2_input *i)
+{
+	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+	dprintk(1, "%s()\n", __func__);
+	return cx25821_enum_input(dev, i);
+}
+
+int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+
+	*i = dev->input;
+	dprintk(1, "%s(): returns %d\n", __func__, *i);
+	return 0;
+}
+
+int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct cx25821_fh *fh = priv;
+	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+	int err;
+
+	dprintk(1, "%s(%d)\n", __func__, i);
+
+	if (fh) {
+		err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
+				      fh->prio);
+		if (0 != err)
+			return err;
+	}
+
+	if (i >= CX25821_NR_INPUT) {
+		dprintk(1, "%s(): -EINVAL\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&dev->lock);
+	cx25821_video_mux(dev, i);
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+#ifdef TUNER_FLAG
+int cx25821_vidioc_g_frequency(struct file *file, void *priv,
+			       struct v4l2_frequency *f)
+{
+	struct cx25821_fh *fh = priv;
+	struct cx25821_dev *dev = fh->dev;
+
+	f->frequency = dev->freq;
+
+	cx25821_call_all(dev, tuner, g_frequency, f);
+
+	return 0;
+}
+
+int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f)
+{
+	mutex_lock(&dev->lock);
+	dev->freq = f->frequency;
+
+	cx25821_call_all(dev, tuner, s_frequency, f);
+
+	/* When changing channels it is required to reset TVAUDIO */
+	msleep(10);
+
+	mutex_unlock(&dev->lock);
+
+	return 0;
+}
+
+int cx25821_vidioc_s_frequency(struct file *file, void *priv,
+			       struct v4l2_frequency *f)
+{
+	struct cx25821_fh *fh = priv;
+	struct cx25821_dev *dev;
+	int err;
+
+	if (fh) {
+		dev = fh->dev;
+		err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
+				      fh->prio);
+		if (0 != err)
+			return err;
+	} else {
+		pr_err("Invalid fh pointer!\n");
+		return -EINVAL;
+	}
+
+	return cx25821_set_freq(dev, f);
+}
+#endif
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+int cx25821_vidioc_g_register(struct file *file, void *fh,
+		      struct v4l2_dbg_register *reg)
+{
+	struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev;
+
+	if (!v4l2_chip_match_host(&reg->match))
+		return -EINVAL;
+
+	cx25821_call_all(dev, core, g_register, reg);
+
+	return 0;
+}
+
+int cx25821_vidioc_s_register(struct file *file, void *fh,
+		      struct v4l2_dbg_register *reg)
+{
+	struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev;
+
+	if (!v4l2_chip_match_host(&reg->match))
+		return -EINVAL;
+
+	cx25821_call_all(dev, core, s_register, reg);
+
+	return 0;
+}
+
+#endif
+
+#ifdef TUNER_FLAG
+int cx25821_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+
+	if (unlikely(UNSET == dev->tuner_type))
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+
+	strcpy(t->name, "Television");
+	t->type = V4L2_TUNER_ANALOG_TV;
+	t->capability = V4L2_TUNER_CAP_NORM;
+	t->rangehigh = 0xffffffffUL;
+
+	t->signal = 0xffff;	/* LOCKED */
+	return 0;
+}
+
+int cx25821_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+	struct cx25821_fh *fh = priv;
+	int err;
+
+	if (fh) {
+		err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
+				      fh->prio);
+		if (0 != err)
+			return err;
+	}
+
+	dprintk(1, "%s()\n", __func__);
+	if (UNSET == dev->tuner_type)
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+
+	return 0;
+}
+
+#endif
+/*****************************************************************************/
+static const struct v4l2_queryctrl no_ctl = {
+	.name = "42",
+	.flags = V4L2_CTRL_FLAG_DISABLED,
+};
+
+static struct v4l2_queryctrl cx25821_ctls[] = {
+	/* --- video --- */
+	{
+		.id = V4L2_CID_BRIGHTNESS,
+		.name = "Brightness",
+		.minimum = 0,
+		.maximum = 10000,
+		.step = 1,
+		.default_value = 6200,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+	}, {
+		.id = V4L2_CID_CONTRAST,
+		.name = "Contrast",
+		.minimum = 0,
+		.maximum = 10000,
+		.step = 1,
+		.default_value = 5000,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+	}, {
+		.id = V4L2_CID_SATURATION,
+		.name = "Saturation",
+		.minimum = 0,
+		.maximum = 10000,
+		.step = 1,
+		.default_value = 5000,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+	}, {
+		.id = V4L2_CID_HUE,
+		.name = "Hue",
+		.minimum = 0,
+		.maximum = 10000,
+		.step = 1,
+		.default_value = 5000,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+	}
+};
+static const int CX25821_CTLS = ARRAY_SIZE(cx25821_ctls);
+
+static int cx25821_ctrl_query(struct v4l2_queryctrl *qctrl)
+{
+	int i;
+
+	if (qctrl->id < V4L2_CID_BASE || qctrl->id >= V4L2_CID_LASTP1)
+		return -EINVAL;
+	for (i = 0; i < CX25821_CTLS; i++)
+		if (cx25821_ctls[i].id == qctrl->id)
+			break;
+	if (i == CX25821_CTLS) {
+		*qctrl = no_ctl;
+		return 0;
+	}
+	*qctrl = cx25821_ctls[i];
+	return 0;
+}
+
+int cx25821_vidioc_queryctrl(struct file *file, void *priv,
+		     struct v4l2_queryctrl *qctrl)
+{
+	return cx25821_ctrl_query(qctrl);
+}
+
+/* ------------------------------------------------------------------ */
+/* VIDEO CTRL IOCTLS                                                  */
+
+static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id)
+{
+	unsigned int i;
+
+	for (i = 0; i < CX25821_CTLS; i++)
+		if (cx25821_ctls[i].id == id)
+			return cx25821_ctls + i;
+	return NULL;
+}
+
+int cx25821_vidioc_g_ctrl(struct file *file, void *priv,
+			  struct v4l2_control *ctl)
+{
+	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+	struct cx25821_fh *fh = priv;
+
+	const struct v4l2_queryctrl *ctrl;
+
+	ctrl = ctrl_by_id(ctl->id);
+
+	if (NULL == ctrl)
+		return -EINVAL;
+	switch (ctl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		ctl->value = dev->channels[fh->channel_id].ctl_bright;
+		break;
+	case V4L2_CID_HUE:
+		ctl->value = dev->channels[fh->channel_id].ctl_hue;
+		break;
+	case V4L2_CID_CONTRAST:
+		ctl->value = dev->channels[fh->channel_id].ctl_contrast;
+		break;
+	case V4L2_CID_SATURATION:
+		ctl->value = dev->channels[fh->channel_id].ctl_saturation;
+		break;
+	}
+	return 0;
+}
+
+int cx25821_set_control(struct cx25821_dev *dev,
+			struct v4l2_control *ctl, int chan_num)
+{
+	int err;
+	const struct v4l2_queryctrl *ctrl;
+
+	err = -EINVAL;
+
+	ctrl = ctrl_by_id(ctl->id);
+
+	if (NULL == ctrl)
+		return err;
+
+	switch (ctrl->type) {
+	case V4L2_CTRL_TYPE_BOOLEAN:
+	case V4L2_CTRL_TYPE_MENU:
+	case V4L2_CTRL_TYPE_INTEGER:
+		if (ctl->value < ctrl->minimum)
+			ctl->value = ctrl->minimum;
+		if (ctl->value > ctrl->maximum)
+			ctl->value = ctrl->maximum;
+		break;
+	default:
+		/* nothing */ ;
+	}
+
+	switch (ctl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		dev->channels[chan_num].ctl_bright = ctl->value;
+		medusa_set_brightness(dev, ctl->value, chan_num);
+		break;
+	case V4L2_CID_HUE:
+		dev->channels[chan_num].ctl_hue = ctl->value;
+		medusa_set_hue(dev, ctl->value, chan_num);
+		break;
+	case V4L2_CID_CONTRAST:
+		dev->channels[chan_num].ctl_contrast = ctl->value;
+		medusa_set_contrast(dev, ctl->value, chan_num);
+		break;
+	case V4L2_CID_SATURATION:
+		dev->channels[chan_num].ctl_saturation = ctl->value;
+		medusa_set_saturation(dev, ctl->value, chan_num);
+		break;
+	}
+
+	err = 0;
+
+	return err;
+}
+
+static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num)
+{
+	struct v4l2_control ctrl;
+	int i;
+	for (i = 0; i < CX25821_CTLS; i++) {
+		ctrl.id = cx25821_ctls[i].id;
+		ctrl.value = cx25821_ctls[i].default_value;
+
+		cx25821_set_control(dev, &ctrl, chan_num);
+	}
+}
+
+int cx25821_vidioc_cropcap(struct file *file, void *priv,
+			   struct v4l2_cropcap *cropcap)
+{
+	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+
+	if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	cropcap->bounds.top = 0;
+	cropcap->bounds.left = 0;
+	cropcap->bounds.width = 720;
+	cropcap->bounds.height = dev->tvnorm == V4L2_STD_PAL_BG ? 576 : 480;
+	cropcap->pixelaspect.numerator =
+		dev->tvnorm == V4L2_STD_PAL_BG ? 59 : 10;
+	cropcap->pixelaspect.denominator =
+		dev->tvnorm == V4L2_STD_PAL_BG ? 54 : 11;
+	cropcap->defrect = cropcap->bounds;
+	return 0;
+}
+
+int cx25821_vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop)
+{
+	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+	struct cx25821_fh *fh = priv;
+	int err;
+
+	if (fh) {
+		err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
+				      fh->prio);
+		if (0 != err)
+			return err;
+	}
+	/* cx25821_vidioc_s_crop not supported */
+	return -EINVAL;
+}
+
+int cx25821_vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop)
+{
+	/* cx25821_vidioc_g_crop not supported */
+	return -EINVAL;
+}
+
+int cx25821_vidioc_querystd(struct file *file, void *priv, v4l2_std_id * norm)
+{
+	/* medusa does not support video standard sensing of current input */
+	*norm = CX25821_NORMS;
+
+	return 0;
+}
+
+int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm)
+{
+	if (tvnorm == V4L2_STD_PAL_BG) {
+		if (width == 352 || width == 720)
+			return 1;
+		else
+			return 0;
+	}
+
+	if (tvnorm == V4L2_STD_NTSC_M) {
+		if (width == 320 || width == 352 || width == 720)
+			return 1;
+		else
+			return 0;
+	}
+	return 0;
+}
+
+int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm)
+{
+	if (tvnorm == V4L2_STD_PAL_BG) {
+		if (height == 576 || height == 288)
+			return 1;
+		else
+			return 0;
+	}
+
+	if (tvnorm == V4L2_STD_NTSC_M) {
+		if (height == 480 || height == 240)
+			return 1;
+		else
+			return 0;
+	}
+
+	return 0;
+}
+
+static long video_ioctl_upstream9(struct file *file, unsigned int cmd,
+				 unsigned long arg)
+{
+	struct cx25821_fh *fh = file->private_data;
+	struct cx25821_dev *dev = fh->dev;
+	int command = 0;
+	struct upstream_user_struct *data_from_user;
+
+	data_from_user = (struct upstream_user_struct *)arg;
+
+	if (!data_from_user) {
+		pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
+		return 0;
+	}
+
+	command = data_from_user->command;
+
+	if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
+		return 0;
+
+	dev->input_filename = data_from_user->input_filename;
+	dev->input_audiofilename = data_from_user->input_filename;
+	dev->vid_stdname = data_from_user->vid_stdname;
+	dev->pixel_format = data_from_user->pixel_format;
+	dev->channel_select = data_from_user->channel_select;
+	dev->command = data_from_user->command;
+
+	switch (command) {
+	case UPSTREAM_START_VIDEO:
+		cx25821_start_upstream_video_ch1(dev, data_from_user);
+		break;
+
+	case UPSTREAM_STOP_VIDEO:
+		cx25821_stop_upstream_video_ch1(dev);
+		break;
+	}
+
+	return 0;
+}
+
+static long video_ioctl_upstream10(struct file *file, unsigned int cmd,
+				  unsigned long arg)
+{
+	struct cx25821_fh *fh = file->private_data;
+	struct cx25821_dev *dev = fh->dev;
+	int command = 0;
+	struct upstream_user_struct *data_from_user;
+
+	data_from_user = (struct upstream_user_struct *)arg;
+
+	if (!data_from_user) {
+		pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
+		return 0;
+	}
+
+	command = data_from_user->command;
+
+	if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
+		return 0;
+
+	dev->input_filename_ch2 = data_from_user->input_filename;
+	dev->input_audiofilename = data_from_user->input_filename;
+	dev->vid_stdname_ch2 = data_from_user->vid_stdname;
+	dev->pixel_format_ch2 = data_from_user->pixel_format;
+	dev->channel_select_ch2 = data_from_user->channel_select;
+	dev->command_ch2 = data_from_user->command;
+
+	switch (command) {
+	case UPSTREAM_START_VIDEO:
+		cx25821_start_upstream_video_ch2(dev, data_from_user);
+		break;
+
+	case UPSTREAM_STOP_VIDEO:
+		cx25821_stop_upstream_video_ch2(dev);
+		break;
+	}
+
+	return 0;
+}
+
+static long video_ioctl_upstream11(struct file *file, unsigned int cmd,
+				  unsigned long arg)
+{
+	struct cx25821_fh *fh = file->private_data;
+	struct cx25821_dev *dev = fh->dev;
+	int command = 0;
+	struct upstream_user_struct *data_from_user;
+
+	data_from_user = (struct upstream_user_struct *)arg;
+
+	if (!data_from_user) {
+		pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
+		return 0;
+	}
+
+	command = data_from_user->command;
+
+	if (command != UPSTREAM_START_AUDIO && command != UPSTREAM_STOP_AUDIO)
+		return 0;
+
+	dev->input_filename = data_from_user->input_filename;
+	dev->input_audiofilename = data_from_user->input_filename;
+	dev->vid_stdname = data_from_user->vid_stdname;
+	dev->pixel_format = data_from_user->pixel_format;
+	dev->channel_select = data_from_user->channel_select;
+	dev->command = data_from_user->command;
+
+	switch (command) {
+	case UPSTREAM_START_AUDIO:
+		cx25821_start_upstream_audio(dev, data_from_user);
+		break;
+
+	case UPSTREAM_STOP_AUDIO:
+		cx25821_stop_upstream_audio(dev);
+		break;
+	}
+
+	return 0;
+}
+
+static long video_ioctl_set(struct file *file, unsigned int cmd,
+			   unsigned long arg)
+{
+	struct cx25821_fh *fh = file->private_data;
+	struct cx25821_dev *dev = fh->dev;
+	struct downstream_user_struct *data_from_user;
+	int command;
+	int width = 720;
+	int selected_channel = 0;
+	int pix_format = 0;
+	int i = 0;
+	int cif_enable = 0;
+	int cif_width = 0;
+
+	data_from_user = (struct downstream_user_struct *)arg;
+
+	if (!data_from_user) {
+		pr_err("%s(): User data is INVALID. Returning\n", __func__);
+		return 0;
+	}
+
+	command = data_from_user->command;
+
+	if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT
+	   && command != ENABLE_CIF_RESOLUTION && command != REG_READ
+	   && command != REG_WRITE && command != MEDUSA_READ
+	   && command != MEDUSA_WRITE) {
+		return 0;
+	}
+
+	switch (command) {
+	case SET_VIDEO_STD:
+		if (!strcmp(data_from_user->vid_stdname, "PAL"))
+			dev->tvnorm = V4L2_STD_PAL_BG;
+		else
+			dev->tvnorm = V4L2_STD_NTSC_M;
+		medusa_set_videostandard(dev);
+		break;
+
+	case SET_PIXEL_FORMAT:
+		selected_channel = data_from_user->decoder_select;
+		pix_format = data_from_user->pixel_format;
+
+		if (!(selected_channel <= 7 && selected_channel >= 0)) {
+			selected_channel -= 4;
+			selected_channel = selected_channel % 8;
+		}
+
+		if (selected_channel >= 0)
+			cx25821_set_pixel_format(dev, selected_channel,
+						pix_format);
+
+		break;
+
+	case ENABLE_CIF_RESOLUTION:
+		selected_channel = data_from_user->decoder_select;
+		cif_enable = data_from_user->cif_resolution_enable;
+		cif_width = data_from_user->cif_width;
+
+		if (cif_enable) {
+			if (dev->tvnorm & V4L2_STD_PAL_BG
+			    || dev->tvnorm & V4L2_STD_PAL_DK) {
+				width = 352;
+			} else {
+				width = cif_width;
+				if (cif_width != 320 && cif_width != 352)
+					width = 320;
+			}
+		}
+
+		if (!(selected_channel <= 7 && selected_channel >= 0)) {
+			selected_channel -= 4;
+			selected_channel = selected_channel % 8;
+		}
+
+		if (selected_channel <= 7 && selected_channel >= 0) {
+			dev->channels[selected_channel].use_cif_resolution =
+				cif_enable;
+			dev->channels[selected_channel].cif_width = width;
+		} else {
+			for (i = 0; i < VID_CHANNEL_NUM; i++) {
+				dev->channels[i].use_cif_resolution =
+					cif_enable;
+				dev->channels[i].cif_width = width;
+			}
+		}
+
+		medusa_set_resolution(dev, width, selected_channel);
+		break;
+	case REG_READ:
+		data_from_user->reg_data = cx_read(data_from_user->reg_address);
+		break;
+	case REG_WRITE:
+		cx_write(data_from_user->reg_address, data_from_user->reg_data);
+		break;
+	case MEDUSA_READ:
+		cx25821_i2c_read(&dev->i2c_bus[0],
+					 (u16) data_from_user->reg_address,
+					 &data_from_user->reg_data);
+		break;
+	case MEDUSA_WRITE:
+		cx25821_i2c_write(&dev->i2c_bus[0],
+				  (u16) data_from_user->reg_address,
+				  data_from_user->reg_data);
+		break;
+	}
+
+	return 0;
+}
+
+static long cx25821_video_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	int ret = 0;
+
+	struct cx25821_fh *fh = file->private_data;
+
+	/* check to see if it's the video upstream */
+	if (fh->channel_id == SRAM_CH09) {
+		ret = video_ioctl_upstream9(file, cmd, arg);
+		return ret;
+	} else if (fh->channel_id == SRAM_CH10) {
+		ret = video_ioctl_upstream10(file, cmd, arg);
+		return ret;
+	} else if (fh->channel_id == SRAM_CH11) {
+		ret = video_ioctl_upstream11(file, cmd, arg);
+		ret = video_ioctl_set(file, cmd, arg);
+		return ret;
+	}
+
+	return video_ioctl2(file, cmd, arg);
+}
+
+/* exported stuff */
+static const struct v4l2_file_operations video_fops = {
+	.owner = THIS_MODULE,
+	.open = video_open,
+	.release = video_release,
+	.read = video_read,
+	.poll = video_poll,
+	.mmap = cx25821_video_mmap,
+	.ioctl = cx25821_video_ioctl,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+	.vidioc_querycap = cx25821_vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
+	.vidioc_querybuf = cx25821_vidioc_querybuf,
+	.vidioc_qbuf = cx25821_vidioc_qbuf,
+	.vidioc_dqbuf = vidioc_dqbuf,
+#ifdef TUNER_FLAG
+	.vidioc_s_std = cx25821_vidioc_s_std,
+	.vidioc_querystd = cx25821_vidioc_querystd,
+#endif
+	.vidioc_cropcap = cx25821_vidioc_cropcap,
+	.vidioc_s_crop = cx25821_vidioc_s_crop,
+	.vidioc_g_crop = cx25821_vidioc_g_crop,
+	.vidioc_enum_input = cx25821_vidioc_enum_input,
+	.vidioc_g_input = cx25821_vidioc_g_input,
+	.vidioc_s_input = cx25821_vidioc_s_input,
+	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
+	.vidioc_s_ctrl = vidioc_s_ctrl,
+	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
+	.vidioc_streamon = vidioc_streamon,
+	.vidioc_streamoff = vidioc_streamoff,
+	.vidioc_log_status = vidioc_log_status,
+	.vidioc_g_priority = cx25821_vidioc_g_priority,
+	.vidioc_s_priority = cx25821_vidioc_s_priority,
+#ifdef TUNER_FLAG
+	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
+	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
+	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
+	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
+#endif
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register = cx25821_vidioc_g_register,
+	.vidioc_s_register = cx25821_vidioc_s_register,
+#endif
+};
+
+struct video_device cx25821_videoioctl_template = {
+	.name = "cx25821-videoioctl",
+	.fops = &video_fops,
+	.ioctl_ops = &video_ioctl_ops,
+	.tvnorms = CX25821_NORMS,
+	.current_norm = V4L2_STD_NTSC_M,
+};
diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h
new file mode 100644
index 0000000..9652a5e
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821-video.h
@@ -0,0 +1,186 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
+ *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef CX25821_VIDEO_H_
+#define CX25821_VIDEO_H_
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <asm/div64.h>
+
+#include "cx25821.h"
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+
+#define TUNER_FLAG
+
+#define VIDEO_DEBUG 0
+
+#define dprintk(level, fmt, arg...)					\
+do {									\
+	if (VIDEO_DEBUG >= level)					\
+		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ##arg);	\
+} while (0)
+
+/* For IOCTL to identify running upstream */
+#define UPSTREAM_START_VIDEO        700
+#define UPSTREAM_STOP_VIDEO         701
+#define UPSTREAM_START_AUDIO        702
+#define UPSTREAM_STOP_AUDIO         703
+#define UPSTREAM_DUMP_REGISTERS     702
+#define SET_VIDEO_STD               800
+#define SET_PIXEL_FORMAT            1000
+#define ENABLE_CIF_RESOLUTION       1001
+
+#define REG_READ		    900
+#define REG_WRITE		    901
+#define MEDUSA_READ		    910
+#define MEDUSA_WRITE		    911
+
+extern struct sram_channel *channel0;
+extern struct sram_channel *channel1;
+extern struct sram_channel *channel2;
+extern struct sram_channel *channel3;
+extern struct sram_channel *channel4;
+extern struct sram_channel *channel5;
+extern struct sram_channel *channel6;
+extern struct sram_channel *channel7;
+extern struct sram_channel *channel9;
+extern struct sram_channel *channel10;
+extern struct sram_channel *channel11;
+extern struct video_device cx25821_videoioctl_template;
+/* extern const u32 *ctrl_classes[]; */
+
+extern unsigned int vid_limit;
+
+#define FORMAT_FLAGS_PACKED       0x01
+extern struct cx25821_fmt formats[];
+extern struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc);
+extern struct cx25821_data timeout_data[MAX_VID_CHANNEL_NUM];
+
+extern void cx25821_video_wakeup(struct cx25821_dev *dev,
+				 struct cx25821_dmaqueue *q, u32 count);
+
+#ifdef TUNER_FLAG
+extern int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm);
+#endif
+
+extern int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh,
+			   unsigned int bit);
+extern int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit);
+extern int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit);
+extern void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh,
+			     unsigned int bits);
+extern int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input);
+extern int cx25821_start_video_dma(struct cx25821_dev *dev,
+				   struct cx25821_dmaqueue *q,
+				   struct cx25821_buffer *buf,
+				   struct sram_channel *channel);
+
+extern int cx25821_set_scale(struct cx25821_dev *dev, unsigned int width,
+			     unsigned int height, enum v4l2_field field);
+extern int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status);
+extern void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num);
+extern int cx25821_video_register(struct cx25821_dev *dev);
+extern int cx25821_get_format_size(void);
+
+extern int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count,
+				unsigned int *size);
+extern int cx25821_buffer_prepare(struct videobuf_queue *q,
+				  struct videobuf_buffer *vb,
+				  enum v4l2_field field);
+extern void cx25821_buffer_release(struct videobuf_queue *q,
+				   struct videobuf_buffer *vb);
+extern struct videobuf_queue *get_queue(struct cx25821_fh *fh);
+extern int cx25821_get_resource(struct cx25821_fh *fh, int resource);
+extern int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma);
+extern int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+					  struct v4l2_format *f);
+extern int cx25821_vidioc_querycap(struct file *file, void *priv,
+				   struct v4l2_capability *cap);
+extern int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+					   struct v4l2_fmtdesc *f);
+extern int cx25821_vidioc_reqbufs(struct file *file, void *priv,
+				  struct v4l2_requestbuffers *p);
+extern int cx25821_vidioc_querybuf(struct file *file, void *priv,
+				   struct v4l2_buffer *p);
+extern int cx25821_vidioc_qbuf(struct file *file, void *priv,
+			       struct v4l2_buffer *p);
+extern int cx25821_vidioc_s_std(struct file *file, void *priv,
+				v4l2_std_id *tvnorms);
+extern int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i);
+extern int cx25821_vidioc_enum_input(struct file *file, void *priv,
+				     struct v4l2_input *i);
+extern int cx25821_vidioc_g_input(struct file *file, void *priv,
+				  unsigned int *i);
+extern int cx25821_vidioc_s_input(struct file *file, void *priv,
+				  unsigned int i);
+extern int cx25821_vidioc_g_ctrl(struct file *file, void *priv,
+				 struct v4l2_control *ctl);
+extern int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f);
+extern int cx25821_vidioc_g_frequency(struct file *file, void *priv,
+				      struct v4l2_frequency *f);
+extern int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f);
+extern int cx25821_vidioc_s_frequency(struct file *file, void *priv,
+				      struct v4l2_frequency *f);
+extern int cx25821_vidioc_g_register(struct file *file, void *fh,
+				     struct v4l2_dbg_register *reg);
+extern int cx25821_vidioc_s_register(struct file *file, void *fh,
+				     struct v4l2_dbg_register *reg);
+extern int cx25821_vidioc_g_tuner(struct file *file, void *priv,
+				  struct v4l2_tuner *t);
+extern int cx25821_vidioc_s_tuner(struct file *file, void *priv,
+				  struct v4l2_tuner *t);
+
+extern int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm);
+extern int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm);
+
+extern int cx25821_vidioc_g_priority(struct file *file, void *f,
+				     enum v4l2_priority *p);
+extern int cx25821_vidioc_s_priority(struct file *file, void *f,
+				     enum v4l2_priority prio);
+
+extern int cx25821_vidioc_queryctrl(struct file *file, void *priv,
+				    struct v4l2_queryctrl *qctrl);
+extern int cx25821_set_control(struct cx25821_dev *dev,
+			       struct v4l2_control *ctrl, int chan_num);
+
+extern int cx25821_vidioc_cropcap(struct file *file, void *fh,
+				  struct v4l2_cropcap *cropcap);
+extern int cx25821_vidioc_s_crop(struct file *file, void *priv,
+				 struct v4l2_crop *crop);
+extern int cx25821_vidioc_g_crop(struct file *file, void *priv,
+				 struct v4l2_crop *crop);
+
+extern int cx25821_vidioc_querystd(struct file *file, void *priv,
+				   v4l2_std_id *norm);
+#endif
diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h
new file mode 100644
index 0000000..8a9c0c8
--- /dev/null
+++ b/drivers/media/pci/cx25821/cx25821.h
@@ -0,0 +1,615 @@
+/*
+ *  Driver for the Conexant CX25821 PCIe bridge
+ *
+ *  Copyright (C) 2009 Conexant Systems Inc.
+ *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
+ *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef CX25821_H_
+#define CX25821_H_
+
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/kdev_t.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/tuner.h>
+#include <media/tveeprom.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/videobuf-dvb.h>
+
+#include "btcx-risc.h"
+#include "cx25821-reg.h"
+#include "cx25821-medusa-reg.h"
+#include "cx25821-sram.h"
+#include "cx25821-audio.h"
+#include "media/cx2341x.h"
+
+#include <linux/version.h>
+#include <linux/mutex.h>
+
+#define CX25821_VERSION_CODE KERNEL_VERSION(0, 0, 106)
+
+#define UNSET (-1U)
+#define NO_SYNC_LINE (-1U)
+
+#define CX25821_MAXBOARDS 2
+
+#define TRUE    1
+#define FALSE   0
+#define LINE_SIZE_D1    1440
+
+/* Number of decoders and encoders */
+#define MAX_DECODERS            8
+#define MAX_ENCODERS            2
+#define QUAD_DECODERS           4
+#define MAX_CAMERAS             16
+
+/* Max number of inputs by card */
+#define MAX_CX25821_INPUT     8
+#define INPUT(nr) (&cx25821_boards[dev->board].input[nr])
+#define RESOURCE_VIDEO0       1
+#define RESOURCE_VIDEO1       2
+#define RESOURCE_VIDEO2       4
+#define RESOURCE_VIDEO3       8
+#define RESOURCE_VIDEO4       16
+#define RESOURCE_VIDEO5       32
+#define RESOURCE_VIDEO6       64
+#define RESOURCE_VIDEO7       128
+#define RESOURCE_VIDEO8       256
+#define RESOURCE_VIDEO9       512
+#define RESOURCE_VIDEO10      1024
+#define RESOURCE_VIDEO11      2048
+#define RESOURCE_VIDEO_IOCTL  4096
+
+#define BUFFER_TIMEOUT     (HZ)	/* 0.5 seconds */
+
+#define UNKNOWN_BOARD        0
+#define CX25821_BOARD        1
+
+/* Currently supported by the driver */
+#define CX25821_NORMS (\
+	V4L2_STD_NTSC_M |  V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_M_KR | \
+	V4L2_STD_PAL_BG |  V4L2_STD_PAL_DK    |  V4L2_STD_PAL_I    | \
+	V4L2_STD_PAL_M  |  V4L2_STD_PAL_N     |  V4L2_STD_PAL_H    | \
+	V4L2_STD_PAL_Nc)
+
+#define CX25821_BOARD_CONEXANT_ATHENA10 1
+#define MAX_VID_CHANNEL_NUM     12
+#define VID_CHANNEL_NUM 8
+#define CX25821_NR_INPUT 2
+
+struct cx25821_fmt {
+	char *name;
+	u32 fourcc;		/* v4l2 format id */
+	int depth;
+	int flags;
+	u32 cxformat;
+};
+
+struct cx25821_ctrl {
+	struct v4l2_queryctrl v;
+	u32 off;
+	u32 reg;
+	u32 mask;
+	u32 shift;
+};
+
+struct cx25821_tvnorm {
+	char *name;
+	v4l2_std_id id;
+	u32 cxiformat;
+	u32 cxoformat;
+};
+
+struct cx25821_fh {
+	struct cx25821_dev *dev;
+	enum v4l2_buf_type type;
+	int radio;
+	u32 resources;
+
+	enum v4l2_priority prio;
+
+	/* video overlay */
+	struct v4l2_window win;
+	struct v4l2_clip *clips;
+	unsigned int nclips;
+
+	/* video capture */
+	struct cx25821_fmt *fmt;
+	unsigned int width, height;
+	int channel_id;
+
+	/* vbi capture */
+	struct videobuf_queue vidq;
+	struct videobuf_queue vbiq;
+
+	/* H264 Encoder specifics ONLY */
+	struct videobuf_queue mpegq;
+	atomic_t v4l_reading;
+};
+
+enum cx25821_itype {
+	CX25821_VMUX_COMPOSITE = 1,
+	CX25821_VMUX_SVIDEO,
+	CX25821_VMUX_DEBUG,
+	CX25821_RADIO,
+};
+
+enum cx25821_src_sel_type {
+	CX25821_SRC_SEL_EXT_656_VIDEO = 0,
+	CX25821_SRC_SEL_PARALLEL_MPEG_VIDEO
+};
+
+/* buffer for one video frame */
+struct cx25821_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+
+	/* cx25821 specific */
+	unsigned int bpl;
+	struct btcx_riscmem risc;
+	struct cx25821_fmt *fmt;
+	u32 count;
+};
+
+struct cx25821_input {
+	enum cx25821_itype type;
+	unsigned int vmux;
+	u32 gpio0, gpio1, gpio2, gpio3;
+};
+
+enum port {
+	CX25821_UNDEFINED = 0,
+	CX25821_RAW,
+	CX25821_264
+};
+
+struct cx25821_board {
+	const char *name;
+	enum port porta;
+	enum port portb;
+	enum port portc;
+	unsigned int tuner_type;
+	unsigned int radio_type;
+	unsigned char tuner_addr;
+	unsigned char radio_addr;
+
+	u32 clk_freq;
+	struct cx25821_input input[CX25821_NR_INPUT];
+};
+
+struct cx25821_subid {
+	u16 subvendor;
+	u16 subdevice;
+	u32 card;
+};
+
+struct cx25821_i2c {
+	struct cx25821_dev *dev;
+
+	int nr;
+
+	/* i2c i/o */
+	struct i2c_adapter i2c_adap;
+	struct i2c_client i2c_client;
+	u32 i2c_rc;
+
+	/* cx25821 registers used for raw addess */
+	u32 i2c_period;
+	u32 reg_ctrl;
+	u32 reg_stat;
+	u32 reg_addr;
+	u32 reg_rdata;
+	u32 reg_wdata;
+};
+
+struct cx25821_dmaqueue {
+	struct list_head active;
+	struct list_head queued;
+	struct timer_list timeout;
+	struct btcx_riscmem stopper;
+	u32 count;
+};
+
+struct cx25821_data {
+	struct cx25821_dev *dev;
+	struct sram_channel *channel;
+};
+
+struct cx25821_channel {
+	struct v4l2_prio_state prio;
+
+	int ctl_bright;
+	int ctl_contrast;
+	int ctl_hue;
+	int ctl_saturation;
+	struct cx25821_data timeout_data;
+
+	struct video_device *video_dev;
+	struct cx25821_dmaqueue vidq;
+
+	struct sram_channel *sram_channels;
+
+	struct mutex lock;
+	int resources;
+
+	int pixel_formats;
+	int use_cif_resolution;
+	int cif_width;
+};
+
+struct cx25821_dev {
+	struct list_head devlist;
+	atomic_t refcount;
+	struct v4l2_device v4l2_dev;
+
+	/* pci stuff */
+	struct pci_dev *pci;
+	unsigned char pci_rev, pci_lat;
+	int pci_bus, pci_slot;
+	u32 base_io_addr;
+	u32 __iomem *lmmio;
+	u8 __iomem *bmmio;
+	int pci_irqmask;
+	int hwrevision;
+
+	u32 clk_freq;
+
+	/* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
+	struct cx25821_i2c i2c_bus[3];
+
+	int nr;
+	struct mutex lock;
+
+	struct cx25821_channel channels[MAX_VID_CHANNEL_NUM];
+
+	/* board details */
+	unsigned int board;
+	char name[32];
+
+	/* Analog video */
+	u32 resources;
+	unsigned int input;
+	u32 tvaudio;
+	v4l2_std_id tvnorm;
+	unsigned int tuner_type;
+	unsigned char tuner_addr;
+	unsigned int radio_type;
+	unsigned char radio_addr;
+	unsigned int has_radio;
+	unsigned int videc_type;
+	unsigned char videc_addr;
+	unsigned short _max_num_decoders;
+
+	/* Analog Audio Upstream */
+	int _audio_is_running;
+	int _audiopixel_format;
+	int _is_first_audio_frame;
+	int _audiofile_status;
+	int _audio_lines_count;
+	int _audioframe_count;
+	int _audio_upstream_channel;
+	int _last_index_irq;    /* The last interrupt index processed. */
+
+	__le32 *_risc_audio_jmp_addr;
+	__le32 *_risc_virt_start_addr;
+	__le32 *_risc_virt_addr;
+	dma_addr_t _risc_phys_addr;
+	dma_addr_t _risc_phys_start_addr;
+
+	unsigned int _audiorisc_size;
+	unsigned int _audiodata_buf_size;
+	__le32 *_audiodata_buf_virt_addr;
+	dma_addr_t _audiodata_buf_phys_addr;
+	char *_audiofilename;
+
+	/* V4l */
+	u32 freq;
+	struct video_device *vbi_dev;
+	struct video_device *radio_dev;
+	struct video_device *ioctl_dev;
+
+	spinlock_t slock;
+
+	/* Video Upstream */
+	int _line_size;
+	int _prog_cnt;
+	int _pixel_format;
+	int _is_first_frame;
+	int _is_running;
+	int _file_status;
+	int _lines_count;
+	int _frame_count;
+	int _channel_upstream_select;
+	unsigned int _risc_size;
+
+	__le32 *_dma_virt_start_addr;
+	__le32 *_dma_virt_addr;
+	dma_addr_t _dma_phys_addr;
+	dma_addr_t _dma_phys_start_addr;
+
+	unsigned int _data_buf_size;
+	__le32 *_data_buf_virt_addr;
+	dma_addr_t _data_buf_phys_addr;
+	char *_filename;
+	char *_defaultname;
+
+	int _line_size_ch2;
+	int _prog_cnt_ch2;
+	int _pixel_format_ch2;
+	int _is_first_frame_ch2;
+	int _is_running_ch2;
+	int _file_status_ch2;
+	int _lines_count_ch2;
+	int _frame_count_ch2;
+	int _channel2_upstream_select;
+	unsigned int _risc_size_ch2;
+
+	__le32 *_dma_virt_start_addr_ch2;
+	__le32 *_dma_virt_addr_ch2;
+	dma_addr_t _dma_phys_addr_ch2;
+	dma_addr_t _dma_phys_start_addr_ch2;
+
+	unsigned int _data_buf_size_ch2;
+	__le32 *_data_buf_virt_addr_ch2;
+	dma_addr_t _data_buf_phys_addr_ch2;
+	char *_filename_ch2;
+	char *_defaultname_ch2;
+
+	/* MPEG Encoder ONLY settings */
+	u32 cx23417_mailbox;
+	struct cx2341x_mpeg_params mpeg_params;
+	struct video_device *v4l_device;
+	atomic_t v4l_reader_count;
+	struct cx25821_tvnorm encodernorm;
+
+	u32 upstream_riscbuf_size;
+	u32 upstream_databuf_size;
+	u32 upstream_riscbuf_size_ch2;
+	u32 upstream_databuf_size_ch2;
+	u32 audio_upstream_riscbuf_size;
+	u32 audio_upstream_databuf_size;
+	int _isNTSC;
+	int _frame_index;
+	int _audioframe_index;
+	struct workqueue_struct *_irq_queues;
+	struct work_struct _irq_work_entry;
+	struct workqueue_struct *_irq_queues_ch2;
+	struct work_struct _irq_work_entry_ch2;
+	struct workqueue_struct *_irq_audio_queues;
+	struct work_struct _audio_work_entry;
+	char *input_filename;
+	char *input_filename_ch2;
+	int _frame_index_ch2;
+	int _isNTSC_ch2;
+	char *vid_stdname_ch2;
+	int pixel_format_ch2;
+	int channel_select_ch2;
+	int command_ch2;
+	char *input_audiofilename;
+	char *vid_stdname;
+	int pixel_format;
+	int channel_select;
+	int command;
+	int channel_opened;
+};
+
+struct upstream_user_struct {
+	char *input_filename;
+	char *vid_stdname;
+	int pixel_format;
+	int channel_select;
+	int command;
+};
+
+struct downstream_user_struct {
+	char *vid_stdname;
+	int pixel_format;
+	int cif_resolution_enable;
+	int cif_width;
+	int decoder_select;
+	int command;
+	int reg_address;
+	int reg_data;
+};
+
+extern struct upstream_user_struct *up_data;
+
+static inline struct cx25821_dev *get_cx25821(struct v4l2_device *v4l2_dev)
+{
+	return container_of(v4l2_dev, struct cx25821_dev, v4l2_dev);
+}
+
+#define cx25821_call_all(dev, o, f, args...) \
+	v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args)
+
+extern struct list_head cx25821_devlist;
+extern struct mutex cx25821_devlist_mutex;
+
+extern struct cx25821_board cx25821_boards[];
+extern struct cx25821_subid cx25821_subids[];
+
+#define SRAM_CH00  0		/* Video A */
+#define SRAM_CH01  1		/* Video B */
+#define SRAM_CH02  2		/* Video C */
+#define SRAM_CH03  3		/* Video D */
+#define SRAM_CH04  4		/* Video E */
+#define SRAM_CH05  5		/* Video F */
+#define SRAM_CH06  6		/* Video G */
+#define SRAM_CH07  7		/* Video H */
+
+#define SRAM_CH08  8		/* Audio A */
+#define SRAM_CH09  9		/* Video Upstream I */
+#define SRAM_CH10  10		/* Video Upstream J */
+#define SRAM_CH11  11		/* Audio Upstream AUD_CHANNEL_B */
+
+#define VID_UPSTREAM_SRAM_CHANNEL_I     SRAM_CH09
+#define VID_UPSTREAM_SRAM_CHANNEL_J     SRAM_CH10
+#define AUDIO_UPSTREAM_SRAM_CHANNEL_B   SRAM_CH11
+#define VIDEO_IOCTL_CH  11
+
+struct sram_channel {
+	char *name;
+	u32 i;
+	u32 cmds_start;
+	u32 ctrl_start;
+	u32 cdt;
+	u32 fifo_start;
+	u32 fifo_size;
+	u32 ptr1_reg;
+	u32 ptr2_reg;
+	u32 cnt1_reg;
+	u32 cnt2_reg;
+	u32 int_msk;
+	u32 int_stat;
+	u32 int_mstat;
+	u32 dma_ctl;
+	u32 gpcnt_ctl;
+	u32 gpcnt;
+	u32 aud_length;
+	u32 aud_cfg;
+	u32 fld_aud_fifo_en;
+	u32 fld_aud_risc_en;
+
+	/* For Upstream Video */
+	u32 vid_fmt_ctl;
+	u32 vid_active_ctl1;
+	u32 vid_active_ctl2;
+	u32 vid_cdt_size;
+
+	u32 vip_ctl;
+	u32 pix_frmt;
+	u32 jumponly;
+	u32 irq_bit;
+};
+extern struct sram_channel cx25821_sram_channels[];
+
+#define STATUS_SUCCESS         0
+#define STATUS_UNSUCCESSFUL    -1
+
+#define cx_read(reg)             readl(dev->lmmio + ((reg)>>2))
+#define cx_write(reg, value)     writel((value), dev->lmmio + ((reg)>>2))
+
+#define cx_andor(reg, mask, value) \
+	writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\
+	((value) & (mask)), dev->lmmio+((reg)>>2))
+
+#define cx_set(reg, bit)          cx_andor((reg), (bit), (bit))
+#define cx_clear(reg, bit)        cx_andor((reg), (bit), 0)
+
+#define Set_GPIO_Bit(Bit)                       (1 << Bit)
+#define Clear_GPIO_Bit(Bit)                     (~(1 << Bit))
+
+#define CX25821_ERR(fmt, args...)			\
+	pr_err("(%d): " fmt, dev->board, ##args)
+#define CX25821_WARN(fmt, args...)			\
+	pr_warn("(%d): " fmt, dev->board, ##args)
+#define CX25821_INFO(fmt, args...)			\
+	pr_info("(%d): " fmt, dev->board, ##args)
+
+extern int cx25821_i2c_register(struct cx25821_i2c *bus);
+extern void cx25821_card_setup(struct cx25821_dev *dev);
+extern int cx25821_ir_init(struct cx25821_dev *dev);
+extern int cx25821_i2c_read(struct cx25821_i2c *bus, u16 reg_addr, int *value);
+extern int cx25821_i2c_write(struct cx25821_i2c *bus, u16 reg_addr, int value);
+extern int cx25821_i2c_unregister(struct cx25821_i2c *bus);
+extern void cx25821_gpio_init(struct cx25821_dev *dev);
+extern void cx25821_set_gpiopin_direction(struct cx25821_dev *dev,
+					  int pin_number, int pin_logic_value);
+
+extern int medusa_video_init(struct cx25821_dev *dev);
+extern int medusa_set_videostandard(struct cx25821_dev *dev);
+extern void medusa_set_resolution(struct cx25821_dev *dev, int width,
+				  int decoder_select);
+extern int medusa_set_brightness(struct cx25821_dev *dev, int brightness,
+				 int decoder);
+extern int medusa_set_contrast(struct cx25821_dev *dev, int contrast,
+			       int decoder);
+extern int medusa_set_hue(struct cx25821_dev *dev, int hue, int decoder);
+extern int medusa_set_saturation(struct cx25821_dev *dev, int saturation,
+				 int decoder);
+
+extern int cx25821_sram_channel_setup(struct cx25821_dev *dev,
+				      struct sram_channel *ch, unsigned int bpl,
+				      u32 risc);
+
+extern int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+			       struct scatterlist *sglist,
+			       unsigned int top_offset,
+			       unsigned int bottom_offset,
+			       unsigned int bpl,
+			       unsigned int padding, unsigned int lines);
+extern int cx25821_risc_databuffer_audio(struct pci_dev *pci,
+					 struct btcx_riscmem *risc,
+					 struct scatterlist *sglist,
+					 unsigned int bpl,
+					 unsigned int lines, unsigned int lpi);
+extern void cx25821_free_buffer(struct videobuf_queue *q,
+				struct cx25821_buffer *buf);
+extern int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+				u32 reg, u32 mask, u32 value);
+extern void cx25821_sram_channel_dump(struct cx25821_dev *dev,
+				      struct sram_channel *ch);
+extern void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev,
+					    struct sram_channel *ch);
+
+extern struct cx25821_dev *cx25821_dev_get(struct pci_dev *pci);
+extern void cx25821_print_irqbits(char *name, char *tag, char **strings,
+				  int len, u32 bits, u32 mask);
+extern void cx25821_dev_unregister(struct cx25821_dev *dev);
+extern int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev,
+					    struct sram_channel *ch,
+					    unsigned int bpl, u32 risc);
+
+extern int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev,
+					int channel_select, int pixel_format);
+extern int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev,
+					int channel_select, int pixel_format);
+extern int cx25821_audio_upstream_init(struct cx25821_dev *dev,
+				       int channel_select);
+extern void cx25821_free_mem_upstream_ch1(struct cx25821_dev *dev);
+extern void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev);
+extern void cx25821_free_mem_upstream_audio(struct cx25821_dev *dev);
+extern void cx25821_start_upstream_video_ch1(struct cx25821_dev *dev,
+					     struct upstream_user_struct
+					     *up_data);
+extern void cx25821_start_upstream_video_ch2(struct cx25821_dev *dev,
+					     struct upstream_user_struct
+					     *up_data);
+extern void cx25821_start_upstream_audio(struct cx25821_dev *dev,
+					 struct upstream_user_struct *up_data);
+extern void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev);
+extern void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev);
+extern void cx25821_stop_upstream_audio(struct cx25821_dev *dev);
+extern int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev,
+					       struct sram_channel *ch,
+					       unsigned int bpl, u32 risc);
+extern void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel,
+				     u32 format);
+extern void cx25821_videoioctl_unregister(struct cx25821_dev *dev);
+extern struct video_device *cx25821_vdev_init(struct cx25821_dev *dev,
+					      struct pci_dev *pci,
+					      struct video_device *template,
+					      char *type);
+#endif
diff --git a/drivers/media/pci/cx88/Kconfig b/drivers/media/pci/cx88/Kconfig
new file mode 100644
index 0000000..3598dc0
--- /dev/null
+++ b/drivers/media/pci/cx88/Kconfig
@@ -0,0 +1,86 @@
+config VIDEO_CX88
+	tristate "Conexant 2388x (bt878 successor) support"
+	depends on VIDEO_DEV && PCI && I2C && RC_CORE
+	select I2C_ALGOBIT
+	select VIDEO_BTCX
+	select VIDEOBUF_DMA_SG
+	select VIDEO_TUNER
+	select VIDEO_TVEEPROM
+	select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO
+	---help---
+	  This is a video4linux driver for Conexant 2388x based
+	  TV cards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx8800
+
+config VIDEO_CX88_ALSA
+	tristate "Conexant 2388x DMA audio support"
+	depends on VIDEO_CX88 && SND
+	select SND_PCM
+	---help---
+	  This is a video4linux driver for direct (DMA) audio on
+	  Conexant 2388x based TV cards using ALSA.
+
+	  It only works with boards with function 01 enabled.
+	  To check if your board supports, use lspci -n.
+	  If supported, you should see 14f1:8801 or 14f1:8811
+	  PCI device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx88-alsa.
+
+config VIDEO_CX88_BLACKBIRD
+	tristate "Blackbird MPEG encoder support (cx2388x + cx23416)"
+	depends on VIDEO_CX88
+	select VIDEO_CX2341X
+	---help---
+	  This adds support for MPEG encoder cards based on the
+	  Blackbird reference design, using the Conexant 2388x
+	  and 23416 chips.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx88-blackbird.
+
+config VIDEO_CX88_DVB
+	tristate "DVB/ATSC Support for cx2388x based TV cards"
+	depends on VIDEO_CX88 && DVB_CORE
+	select VIDEOBUF_DVB
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select DVB_MT352 if !DVB_FE_CUSTOMISE
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select DVB_OR51132 if !DVB_FE_CUSTOMISE
+	select DVB_CX22702 if !DVB_FE_CUSTOMISE
+	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+	select DVB_NXT200X if !DVB_FE_CUSTOMISE
+	select DVB_CX24123 if !DVB_FE_CUSTOMISE
+	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
+	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
+	select DVB_CX24116 if !DVB_FE_CUSTOMISE
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_STV0288 if !DVB_FE_CUSTOMISE
+	select DVB_STB6000 if !DVB_FE_CUSTOMISE
+	select DVB_STV0900 if !DVB_FE_CUSTOMISE
+	select DVB_STB6100 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
+	---help---
+	  This adds support for DVB/ATSC cards based on the
+	  Conexant 2388x chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx88-dvb.
+
+config VIDEO_CX88_VP3054
+	tristate "VP-3054 Secondary I2C Bus Support"
+	default m
+	depends on VIDEO_CX88_DVB && DVB_MT352
+	---help---
+	  This adds DVB-T support for cards based on the
+	  Conexant 2388x chip and the MT352 demodulator,
+	  which also require support for the VP-3054
+	  Secondary I2C bus, such at DNTV Live! DVB-T Pro.
+
+config VIDEO_CX88_MPEG
+	tristate
+	depends on VIDEO_CX88_DVB || VIDEO_CX88_BLACKBIRD
+	default y
diff --git a/drivers/media/pci/cx88/Makefile b/drivers/media/pci/cx88/Makefile
new file mode 100644
index 0000000..d3679c3
--- /dev/null
+++ b/drivers/media/pci/cx88/Makefile
@@ -0,0 +1,16 @@
+cx88xx-objs	:= cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \
+		   cx88-dsp.o cx88-input.o
+cx8800-objs	:= cx88-video.o cx88-vbi.o
+cx8802-objs	:= cx88-mpeg.o
+
+obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o
+obj-$(CONFIG_VIDEO_CX88_MPEG) += cx8802.o
+obj-$(CONFIG_VIDEO_CX88_ALSA) += cx88-alsa.o
+obj-$(CONFIG_VIDEO_CX88_BLACKBIRD) += cx88-blackbird.o
+obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
+obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o
+
+ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c
new file mode 100644
index 0000000..3aa6856
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-alsa.c
@@ -0,0 +1,975 @@
+/*
+ *
+ *  Support for audio capture
+ *  PCI function #1 of the cx2388x.
+ *
+ *    (c) 2007 Trent Piepho <xyzzy@speakeasy.org>
+ *    (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>
+ *    (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *    Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
+ *    Based on dummy.c by Jaroslav Kysela <perex@perex.cz>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <media/wm8775.h>
+
+#include "cx88.h"
+#include "cx88-reg.h"
+
+#define dprintk(level,fmt, arg...)	if (debug >= level) \
+	printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg)
+
+#define dprintk_core(level,fmt, arg...)	if (debug >= level) \
+	printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg)
+
+/****************************************************************************
+	Data type declarations - Can be moded to a header file later
+ ****************************************************************************/
+
+struct cx88_audio_buffer {
+	unsigned int               bpl;
+	struct btcx_riscmem        risc;
+	struct videobuf_dmabuf     dma;
+};
+
+struct cx88_audio_dev {
+	struct cx88_core           *core;
+	struct cx88_dmaqueue       q;
+
+	/* pci i/o */
+	struct pci_dev             *pci;
+
+	/* audio controls */
+	int                        irq;
+
+	struct snd_card            *card;
+
+	spinlock_t                 reg_lock;
+	atomic_t		   count;
+
+	unsigned int               dma_size;
+	unsigned int               period_size;
+	unsigned int               num_periods;
+
+	struct videobuf_dmabuf     *dma_risc;
+
+	struct cx88_audio_buffer   *buf;
+
+	struct snd_pcm_substream   *substream;
+};
+typedef struct cx88_audio_dev snd_cx88_card_t;
+
+
+
+/****************************************************************************
+			Module global static vars
+ ****************************************************************************/
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static const char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
+static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
+
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled.");
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s).");
+
+
+/****************************************************************************
+				Module macros
+ ****************************************************************************/
+
+MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");
+MODULE_AUTHOR("Ricardo Cerqueira");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CX88_VERSION);
+
+MODULE_SUPPORTED_DEVICE("{{Conexant,23881},"
+			"{{Conexant,23882},"
+			"{{Conexant,23883}");
+static unsigned int debug;
+module_param(debug,int,0644);
+MODULE_PARM_DESC(debug,"enable debug messages");
+
+/****************************************************************************
+			Module specific funtions
+ ****************************************************************************/
+
+/*
+ * BOARD Specific: Sets audio DMA
+ */
+
+static int _cx88_start_audio_dma(snd_cx88_card_t *chip)
+{
+	struct cx88_audio_buffer *buf = chip->buf;
+	struct cx88_core *core=chip->core;
+	const struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
+
+	/* Make sure RISC/FIFO are off before changing FIFO/RISC settings */
+	cx_clear(MO_AUD_DMACNTRL, 0x11);
+
+	/* setup fifo + format - out channel */
+	cx88_sram_channel_setup(chip->core, audio_ch, buf->bpl, buf->risc.dma);
+
+	/* sets bpl size */
+	cx_write(MO_AUDD_LNGTH, buf->bpl);
+
+	/* reset counter */
+	cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);
+	atomic_set(&chip->count, 0);
+
+	dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d "
+		"byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1,
+		chip->num_periods, buf->bpl * chip->num_periods);
+
+	/* Enables corresponding bits at AUD_INT_STAT */
+	cx_write(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+				AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
+
+	/* Clean any pending interrupt bits already set */
+	cx_write(MO_AUD_INTSTAT, ~0);
+
+	/* enable audio irqs */
+	cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT);
+
+	/* start dma */
+	cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */
+	cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */
+
+	if (debug)
+		cx88_sram_channel_dump(chip->core, audio_ch);
+
+	return 0;
+}
+
+/*
+ * BOARD Specific: Resets audio DMA
+ */
+static int _cx88_stop_audio_dma(snd_cx88_card_t *chip)
+{
+	struct cx88_core *core=chip->core;
+	dprintk(1, "Stopping audio DMA\n");
+
+	/* stop dma */
+	cx_clear(MO_AUD_DMACNTRL, 0x11);
+
+	/* disable irqs */
+	cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT);
+	cx_clear(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+				AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
+
+	if (debug)
+		cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
+
+	return 0;
+}
+
+#define MAX_IRQ_LOOP 50
+
+/*
+ * BOARD Specific: IRQ dma bits
+ */
+static const char *cx88_aud_irqs[32] = {
+	"dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */
+	NULL,					  /* reserved */
+	"dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */
+	NULL,					  /* reserved */
+	"dnf_of", "upf_uf", "rds_dnf_uf",	  /* 8-10 */
+	NULL,					  /* reserved */
+	"dn_sync", "up_sync", "rds_dn_sync",	  /* 12-14 */
+	NULL,					  /* reserved */
+	"opc_err", "par_err", "rip_err",	  /* 16-18 */
+	"pci_abort", "ber_irq", "mchg_irq"	  /* 19-21 */
+};
+
+/*
+ * BOARD Specific: Threats IRQ audio specific calls
+ */
+static void cx8801_aud_irq(snd_cx88_card_t *chip)
+{
+	struct cx88_core *core = chip->core;
+	u32 status, mask;
+
+	status = cx_read(MO_AUD_INTSTAT);
+	mask   = cx_read(MO_AUD_INTMSK);
+	if (0 == (status & mask))
+		return;
+	cx_write(MO_AUD_INTSTAT, status);
+	if (debug > 1  ||  (status & mask & ~0xff))
+		cx88_print_irqbits(core->name, "irq aud",
+				   cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs),
+				   status, mask);
+	/* risc op code error */
+	if (status & AUD_INT_OPC_ERR) {
+		printk(KERN_WARNING "%s/1: Audio risc op code error\n",core->name);
+		cx_clear(MO_AUD_DMACNTRL, 0x11);
+		cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]);
+	}
+	if (status & AUD_INT_DN_SYNC) {
+		dprintk(1, "Downstream sync error\n");
+		cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);
+		return;
+	}
+	/* risc1 downstream */
+	if (status & AUD_INT_DN_RISCI1) {
+		atomic_set(&chip->count, cx_read(MO_AUDD_GPCNT));
+		snd_pcm_period_elapsed(chip->substream);
+	}
+	/* FIXME: Any other status should deserve a special handling? */
+}
+
+/*
+ * BOARD Specific: Handles IRQ calls
+ */
+static irqreturn_t cx8801_irq(int irq, void *dev_id)
+{
+	snd_cx88_card_t *chip = dev_id;
+	struct cx88_core *core = chip->core;
+	u32 status;
+	int loop, handled = 0;
+
+	for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
+		status = cx_read(MO_PCI_INTSTAT) &
+			(core->pci_irqmask | PCI_INT_AUDINT);
+		if (0 == status)
+			goto out;
+		dprintk(3, "cx8801_irq loop %d/%d, status %x\n",
+			loop, MAX_IRQ_LOOP, status);
+		handled = 1;
+		cx_write(MO_PCI_INTSTAT, status);
+
+		if (status & core->pci_irqmask)
+			cx88_core_irq(core, status);
+		if (status & PCI_INT_AUDINT)
+			cx8801_aud_irq(chip);
+	}
+
+	if (MAX_IRQ_LOOP == loop) {
+		printk(KERN_ERR
+		       "%s/1: IRQ loop detected, disabling interrupts\n",
+		       core->name);
+		cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT);
+	}
+
+ out:
+	return IRQ_RETVAL(handled);
+}
+
+
+static int dsp_buffer_free(snd_cx88_card_t *chip)
+{
+	BUG_ON(!chip->dma_size);
+
+	dprintk(2,"Freeing buffer\n");
+	videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc);
+	videobuf_dma_free(chip->dma_risc);
+	btcx_riscmem_free(chip->pci,&chip->buf->risc);
+	kfree(chip->buf);
+
+	chip->dma_risc = NULL;
+	chip->dma_size = 0;
+
+	return 0;
+}
+
+/****************************************************************************
+				ALSA PCM Interface
+ ****************************************************************************/
+
+/*
+ * Digital hardware definition
+ */
+#define DEFAULT_FIFO_SIZE	4096
+static const struct snd_pcm_hardware snd_cx88_digital_hw = {
+	.info = SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		SNDRV_PCM_INFO_MMAP_VALID,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+	.rates =		SNDRV_PCM_RATE_48000,
+	.rate_min =		48000,
+	.rate_max =		48000,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* Analog audio output will be full of clicks and pops if there
+	   are not exactly four lines in the SRAM FIFO buffer.  */
+	.period_bytes_min = DEFAULT_FIFO_SIZE/4,
+	.period_bytes_max = DEFAULT_FIFO_SIZE/4,
+	.periods_min = 1,
+	.periods_max = 1024,
+	.buffer_bytes_max = (1024*1024),
+};
+
+/*
+ * audio pcm capture open callback
+ */
+static int snd_cx88_pcm_open(struct snd_pcm_substream *substream)
+{
+	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int err;
+
+	if (!chip) {
+		printk(KERN_ERR "BUG: cx88 can't find device struct."
+				" Can't proceed with open\n");
+		return -ENODEV;
+	}
+
+	err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS);
+	if (err < 0)
+		goto _error;
+
+	chip->substream = substream;
+
+	runtime->hw = snd_cx88_digital_hw;
+
+	if (cx88_sram_channels[SRAM_CH25].fifo_size != DEFAULT_FIFO_SIZE) {
+		unsigned int bpl = cx88_sram_channels[SRAM_CH25].fifo_size / 4;
+		bpl &= ~7; /* must be multiple of 8 */
+		runtime->hw.period_bytes_min = bpl;
+		runtime->hw.period_bytes_max = bpl;
+	}
+
+	return 0;
+_error:
+	dprintk(1,"Error opening PCM!\n");
+	return err;
+}
+
+/*
+ * audio close callback
+ */
+static int snd_cx88_close(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+/*
+ * hw_params callback
+ */
+static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
+			      struct snd_pcm_hw_params * hw_params)
+{
+	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+	struct videobuf_dmabuf *dma;
+
+	struct cx88_audio_buffer *buf;
+	int ret;
+
+	if (substream->runtime->dma_area) {
+		dsp_buffer_free(chip);
+		substream->runtime->dma_area = NULL;
+	}
+
+	chip->period_size = params_period_bytes(hw_params);
+	chip->num_periods = params_periods(hw_params);
+	chip->dma_size = chip->period_size * params_periods(hw_params);
+
+	BUG_ON(!chip->dma_size);
+	BUG_ON(chip->num_periods & (chip->num_periods-1));
+
+	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+	if (NULL == buf)
+		return -ENOMEM;
+
+	buf->bpl = chip->period_size;
+
+	dma = &buf->dma;
+	videobuf_dma_init(dma);
+	ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
+			(PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
+	if (ret < 0)
+		goto error;
+
+	ret = videobuf_dma_map(&chip->pci->dev, dma);
+	if (ret < 0)
+		goto error;
+
+	ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
+				   chip->period_size, chip->num_periods, 1);
+	if (ret < 0)
+		goto error;
+
+	/* Loop back to start of program */
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
+	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+
+	chip->buf = buf;
+	chip->dma_risc = dma;
+
+	substream->runtime->dma_area = chip->dma_risc->vaddr;
+	substream->runtime->dma_bytes = chip->dma_size;
+	substream->runtime->dma_addr = 0;
+	return 0;
+
+error:
+	kfree(buf);
+	return ret;
+}
+
+/*
+ * hw free callback
+ */
+static int snd_cx88_hw_free(struct snd_pcm_substream * substream)
+{
+
+	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+
+	if (substream->runtime->dma_area) {
+		dsp_buffer_free(chip);
+		substream->runtime->dma_area = NULL;
+	}
+
+	return 0;
+}
+
+/*
+ * prepare callback
+ */
+static int snd_cx88_prepare(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+/*
+ * trigger callback
+ */
+static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+	int err;
+
+	/* Local interrupts are already disabled by ALSA */
+	spin_lock(&chip->reg_lock);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		err=_cx88_start_audio_dma(chip);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		err=_cx88_stop_audio_dma(chip);
+		break;
+	default:
+		err=-EINVAL;
+		break;
+	}
+
+	spin_unlock(&chip->reg_lock);
+
+	return err;
+}
+
+/*
+ * pointer callback
+ */
+static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream)
+{
+	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	u16 count;
+
+	count = atomic_read(&chip->count);
+
+//	dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __func__,
+//		count, new, count & (runtime->periods-1),
+//		runtime->period_size * (count & (runtime->periods-1)));
+	return runtime->period_size * (count & (runtime->periods-1));
+}
+
+/*
+ * page callback (needed for mmap)
+ */
+static struct page *snd_cx88_page(struct snd_pcm_substream *substream,
+				unsigned long offset)
+{
+	void *pageptr = substream->runtime->dma_area + offset;
+	return vmalloc_to_page(pageptr);
+}
+
+/*
+ * operators
+ */
+static struct snd_pcm_ops snd_cx88_pcm_ops = {
+	.open = snd_cx88_pcm_open,
+	.close = snd_cx88_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_cx88_hw_params,
+	.hw_free = snd_cx88_hw_free,
+	.prepare = snd_cx88_prepare,
+	.trigger = snd_cx88_card_trigger,
+	.pointer = snd_cx88_pointer,
+	.page = snd_cx88_page,
+};
+
+/*
+ * create a PCM device
+ */
+static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, const char *name)
+{
+	int err;
+	struct snd_pcm *pcm;
+
+	err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
+	if (err < 0)
+		return err;
+	pcm->private_data = chip;
+	strcpy(pcm->name, name);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx88_pcm_ops);
+
+	return 0;
+}
+
+/****************************************************************************
+				CONTROL INTERFACE
+ ****************************************************************************/
+static int snd_cx88_volume_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *info)
+{
+	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	info->count = 2;
+	info->value.integer.min = 0;
+	info->value.integer.max = 0x3f;
+
+	return 0;
+}
+
+static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *value)
+{
+	snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+	struct cx88_core *core=chip->core;
+	int vol = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f),
+	    bal = cx_read(AUD_BAL_CTL);
+
+	value->value.integer.value[(bal & 0x40) ? 0 : 1] = vol;
+	vol -= (bal & 0x3f);
+	value->value.integer.value[(bal & 0x40) ? 1 : 0] = vol < 0 ? 0 : vol;
+
+	return 0;
+}
+
+static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *value)
+{
+	snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+	struct cx88_core *core = chip->core;
+	int left = value->value.integer.value[0];
+	int right = value->value.integer.value[1];
+	int v, b;
+
+	/* Pass volume & balance onto any WM8775 */
+	if (left >= right) {
+		v = left << 10;
+		b = left ? (0x8000 * right) / left : 0x8000;
+	} else {
+		v = right << 10;
+		b = right ? 0xffff - (0x8000 * left) / right : 0x8000;
+	}
+	wm8775_s_ctrl(core, V4L2_CID_AUDIO_VOLUME, v);
+	wm8775_s_ctrl(core, V4L2_CID_AUDIO_BALANCE, b);
+}
+
+/* OK - TODO: test it */
+static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *value)
+{
+	snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+	struct cx88_core *core=chip->core;
+	int left, right, v, b;
+	int changed = 0;
+	u32 old;
+
+	if (core->board.audio_chip == V4L2_IDENT_WM8775)
+		snd_cx88_wm8775_volume_put(kcontrol, value);
+
+	left = value->value.integer.value[0] & 0x3f;
+	right = value->value.integer.value[1] & 0x3f;
+	b = right - left;
+	if (b < 0) {
+		v = 0x3f - left;
+		b = (-b) | 0x40;
+	} else {
+		v = 0x3f - right;
+	}
+	/* Do we really know this will always be called with IRQs on? */
+	spin_lock_irq(&chip->reg_lock);
+	old = cx_read(AUD_VOL_CTL);
+	if (v != (old & 0x3f)) {
+		cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, (old & ~0x3f) | v);
+		changed = 1;
+	}
+	if ((cx_read(AUD_BAL_CTL) & 0x7f) != b) {
+		cx_write(AUD_BAL_CTL, b);
+		changed = 1;
+	}
+	spin_unlock_irq(&chip->reg_lock);
+
+	return changed;
+}
+
+static const DECLARE_TLV_DB_SCALE(snd_cx88_db_scale, -6300, 100, 0);
+
+static const struct snd_kcontrol_new snd_cx88_volume = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+		  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+	.name = "Analog-TV Volume",
+	.info = snd_cx88_volume_info,
+	.get = snd_cx88_volume_get,
+	.put = snd_cx88_volume_put,
+	.tlv.p = snd_cx88_db_scale,
+};
+
+static int snd_cx88_switch_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *value)
+{
+	snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+	struct cx88_core *core = chip->core;
+	u32 bit = kcontrol->private_value;
+
+	value->value.integer.value[0] = !(cx_read(AUD_VOL_CTL) & bit);
+	return 0;
+}
+
+static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *value)
+{
+	snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+	struct cx88_core *core = chip->core;
+	u32 bit = kcontrol->private_value;
+	int ret = 0;
+	u32 vol;
+
+	spin_lock_irq(&chip->reg_lock);
+	vol = cx_read(AUD_VOL_CTL);
+	if (value->value.integer.value[0] != !(vol & bit)) {
+		vol ^= bit;
+		cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol);
+		/* Pass mute onto any WM8775 */
+		if ((core->board.audio_chip == V4L2_IDENT_WM8775) &&
+		    ((1<<6) == bit))
+			wm8775_s_ctrl(core, V4L2_CID_AUDIO_MUTE, 0 != (vol & bit));
+		ret = 1;
+	}
+	spin_unlock_irq(&chip->reg_lock);
+	return ret;
+}
+
+static const struct snd_kcontrol_new snd_cx88_dac_switch = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Audio-Out Switch",
+	.info = snd_ctl_boolean_mono_info,
+	.get = snd_cx88_switch_get,
+	.put = snd_cx88_switch_put,
+	.private_value = (1<<8),
+};
+
+static const struct snd_kcontrol_new snd_cx88_source_switch = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Analog-TV Switch",
+	.info = snd_ctl_boolean_mono_info,
+	.get = snd_cx88_switch_get,
+	.put = snd_cx88_switch_put,
+	.private_value = (1<<6),
+};
+
+static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *value)
+{
+	snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+	struct cx88_core *core = chip->core;
+	s32 val;
+
+	val = wm8775_g_ctrl(core, V4L2_CID_AUDIO_LOUDNESS);
+	value->value.integer.value[0] = val ? 1 : 0;
+	return 0;
+}
+
+static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *value)
+{
+	snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+	struct cx88_core *core = chip->core;
+	struct v4l2_control client_ctl;
+
+	memset(&client_ctl, 0, sizeof(client_ctl));
+	client_ctl.value = 0 != value->value.integer.value[0];
+	client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
+	call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
+
+	return 0;
+}
+
+static struct snd_kcontrol_new snd_cx88_alc_switch = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Line-In ALC Switch",
+	.info = snd_ctl_boolean_mono_info,
+	.get = snd_cx88_alc_get,
+	.put = snd_cx88_alc_put,
+};
+
+/****************************************************************************
+			Basic Flow for Sound Devices
+ ****************************************************************************/
+
+/*
+ * PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio
+ * Only boards with eeprom and byte 1 at eeprom=1 have it
+ */
+
+static const struct pci_device_id cx88_audio_pci_tbl[] __devinitdata = {
+	{0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{0, }
+};
+MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl);
+
+/*
+ * Chip-specific destructor
+ */
+
+static int snd_cx88_free(snd_cx88_card_t *chip)
+{
+
+	if (chip->irq >= 0)
+		free_irq(chip->irq, chip);
+
+	cx88_core_put(chip->core,chip->pci);
+
+	pci_disable_device(chip->pci);
+	return 0;
+}
+
+/*
+ * Component Destructor
+ */
+static void snd_cx88_dev_free(struct snd_card * card)
+{
+	snd_cx88_card_t *chip = card->private_data;
+
+	snd_cx88_free(chip);
+}
+
+
+/*
+ * Alsa Constructor - Component probe
+ */
+
+static int devno;
+static int __devinit snd_cx88_create(struct snd_card *card,
+				     struct pci_dev *pci,
+				     snd_cx88_card_t **rchip,
+				     struct cx88_core **core_ptr)
+{
+	snd_cx88_card_t   *chip;
+	struct cx88_core  *core;
+	int               err;
+	unsigned char     pci_lat;
+
+	*rchip = NULL;
+
+	err = pci_enable_device(pci);
+	if (err < 0)
+		return err;
+
+	pci_set_master(pci);
+
+	chip = card->private_data;
+
+	core = cx88_core_get(pci);
+	if (NULL == core) {
+		err = -EINVAL;
+		return err;
+	}
+
+	if (!pci_dma_supported(pci,DMA_BIT_MASK(32))) {
+		dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
+		err = -EIO;
+		cx88_core_put(core, pci);
+		return err;
+	}
+
+
+	/* pci init */
+	chip->card = card;
+	chip->pci = pci;
+	chip->irq = -1;
+	spin_lock_init(&chip->reg_lock);
+
+	chip->core = core;
+
+	/* get irq */
+	err = request_irq(chip->pci->irq, cx8801_irq,
+			  IRQF_SHARED | IRQF_DISABLED, chip->core->name, chip);
+	if (err < 0) {
+		dprintk(0, "%s: can't get IRQ %d\n",
+		       chip->core->name, chip->pci->irq);
+		return err;
+	}
+
+	/* print pci info */
+	pci_read_config_byte(pci, PCI_LATENCY_TIMER, &pci_lat);
+
+	dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, "
+	       "latency: %d, mmio: 0x%llx\n", core->name, devno,
+	       pci_name(pci), pci->revision, pci->irq,
+	       pci_lat, (unsigned long long)pci_resource_start(pci,0));
+
+	chip->irq = pci->irq;
+	synchronize_irq(chip->irq);
+
+	snd_card_set_dev(card, &pci->dev);
+
+	*rchip = chip;
+	*core_ptr = core;
+
+	return 0;
+}
+
+static int __devinit cx88_audio_initdev(struct pci_dev *pci,
+				    const struct pci_device_id *pci_id)
+{
+	struct snd_card  *card;
+	snd_cx88_card_t  *chip;
+	struct cx88_core *core = NULL;
+	int              err;
+
+	if (devno >= SNDRV_CARDS)
+		return (-ENODEV);
+
+	if (!enable[devno]) {
+		++devno;
+		return (-ENOENT);
+	}
+
+	err = snd_card_create(index[devno], id[devno], THIS_MODULE,
+			      sizeof(snd_cx88_card_t), &card);
+	if (err < 0)
+		return err;
+
+	card->private_free = snd_cx88_dev_free;
+
+	err = snd_cx88_create(card, pci, &chip, &core);
+	if (err < 0)
+		goto error;
+
+	err = snd_cx88_pcm(chip, 0, "CX88 Digital");
+	if (err < 0)
+		goto error;
+
+	err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_volume, chip));
+	if (err < 0)
+		goto error;
+	err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_dac_switch, chip));
+	if (err < 0)
+		goto error;
+	err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_source_switch, chip));
+	if (err < 0)
+		goto error;
+
+	/* If there's a wm8775 then add a Line-In ALC switch */
+	if (core->board.audio_chip == V4L2_IDENT_WM8775)
+		snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch, chip));
+
+	strcpy (card->driver, "CX88x");
+	sprintf(card->shortname, "Conexant CX%x", pci->device);
+	sprintf(card->longname, "%s at %#llx",
+		card->shortname,(unsigned long long)pci_resource_start(pci, 0));
+	strcpy (card->mixername, "CX88");
+
+	dprintk (0, "%s/%i: ALSA support for cx2388x boards\n",
+	       card->driver,devno);
+
+	err = snd_card_register(card);
+	if (err < 0)
+		goto error;
+	pci_set_drvdata(pci,card);
+
+	devno++;
+	return 0;
+
+error:
+	snd_card_free(card);
+	return err;
+}
+/*
+ * ALSA destructor
+ */
+static void __devexit cx88_audio_finidev(struct pci_dev *pci)
+{
+	struct cx88_audio_dev *card = pci_get_drvdata(pci);
+
+	snd_card_free((void *)card);
+
+	pci_set_drvdata(pci, NULL);
+
+	devno--;
+}
+
+/*
+ * PCI driver definition
+ */
+
+static struct pci_driver cx88_audio_pci_driver = {
+	.name     = "cx88_audio",
+	.id_table = cx88_audio_pci_tbl,
+	.probe    = cx88_audio_initdev,
+	.remove   = __devexit_p(cx88_audio_finidev),
+};
+
+/****************************************************************************
+				LINUX MODULE INIT
+ ****************************************************************************/
+
+/*
+ * module init
+ */
+static int __init cx88_audio_init(void)
+{
+	printk(KERN_INFO "cx2388x alsa driver version %s loaded\n",
+	       CX88_VERSION);
+	return pci_register_driver(&cx88_audio_pci_driver);
+}
+
+/*
+ * module remove
+ */
+static void __exit cx88_audio_fini(void)
+{
+	pci_unregister_driver(&cx88_audio_pci_driver);
+}
+
+module_init(cx88_audio_init);
+module_exit(cx88_audio_fini);
diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c
new file mode 100644
index 0000000..843ffd9
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-blackbird.c
@@ -0,0 +1,1299 @@
+/*
+ *
+ *  Support for a cx23416 mpeg encoder via cx2388x host port.
+ *  "blackbird" reference design.
+ *
+ *    (c) 2004 Jelle Foks <jelle@foks.us>
+ *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
+ *
+ *    (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *        - video_ioctl2 conversion
+ *
+ *  Includes parts from the ivtv driver <http://sourceforge.net/projects/ivtv/>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/cx2341x.h>
+
+#include "cx88.h"
+
+MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards");
+MODULE_AUTHOR("Jelle Foks <jelle@foks.us>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CX88_VERSION);
+
+static unsigned int mpegbufs = 32;
+module_param(mpegbufs,int,0644);
+MODULE_PARM_DESC(mpegbufs,"number of mpeg buffers, range 2-32");
+
+static unsigned int debug;
+module_param(debug,int,0644);
+MODULE_PARM_DESC(debug,"enable debug messages [blackbird]");
+
+#define dprintk(level,fmt, arg...)	if (debug >= level) \
+	printk(KERN_DEBUG "%s/2-bb: " fmt, dev->core->name , ## arg)
+
+
+/* ------------------------------------------------------------------ */
+
+#define BLACKBIRD_FIRM_IMAGE_SIZE 376836
+
+/* defines below are from ivtv-driver.h */
+
+#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
+
+/* Firmware API commands */
+#define IVTV_API_STD_TIMEOUT 500
+
+enum blackbird_capture_type {
+	BLACKBIRD_MPEG_CAPTURE,
+	BLACKBIRD_RAW_CAPTURE,
+	BLACKBIRD_RAW_PASSTHRU_CAPTURE
+};
+enum blackbird_capture_bits {
+	BLACKBIRD_RAW_BITS_NONE             = 0x00,
+	BLACKBIRD_RAW_BITS_YUV_CAPTURE      = 0x01,
+	BLACKBIRD_RAW_BITS_PCM_CAPTURE      = 0x02,
+	BLACKBIRD_RAW_BITS_VBI_CAPTURE      = 0x04,
+	BLACKBIRD_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
+	BLACKBIRD_RAW_BITS_TO_HOST_CAPTURE  = 0x10
+};
+enum blackbird_capture_end {
+	BLACKBIRD_END_AT_GOP, /* stop at the end of gop, generate irq */
+	BLACKBIRD_END_NOW, /* stop immediately, no irq */
+};
+enum blackbird_framerate {
+	BLACKBIRD_FRAMERATE_NTSC_30, /* NTSC: 30fps */
+	BLACKBIRD_FRAMERATE_PAL_25   /* PAL: 25fps */
+};
+enum blackbird_stream_port {
+	BLACKBIRD_OUTPUT_PORT_MEMORY,
+	BLACKBIRD_OUTPUT_PORT_STREAMING,
+	BLACKBIRD_OUTPUT_PORT_SERIAL
+};
+enum blackbird_data_xfer_status {
+	BLACKBIRD_MORE_BUFFERS_FOLLOW,
+	BLACKBIRD_LAST_BUFFER,
+};
+enum blackbird_picture_mask {
+	BLACKBIRD_PICTURE_MASK_NONE,
+	BLACKBIRD_PICTURE_MASK_I_FRAMES,
+	BLACKBIRD_PICTURE_MASK_I_P_FRAMES = 0x3,
+	BLACKBIRD_PICTURE_MASK_ALL_FRAMES = 0x7,
+};
+enum blackbird_vbi_mode_bits {
+	BLACKBIRD_VBI_BITS_SLICED,
+	BLACKBIRD_VBI_BITS_RAW,
+};
+enum blackbird_vbi_insertion_bits {
+	BLACKBIRD_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
+	BLACKBIRD_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
+	BLACKBIRD_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
+	BLACKBIRD_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
+	BLACKBIRD_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
+};
+enum blackbird_dma_unit {
+	BLACKBIRD_DMA_BYTES,
+	BLACKBIRD_DMA_FRAMES,
+};
+enum blackbird_dma_transfer_status_bits {
+	BLACKBIRD_DMA_TRANSFER_BITS_DONE = 0x01,
+	BLACKBIRD_DMA_TRANSFER_BITS_ERROR = 0x04,
+	BLACKBIRD_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
+};
+enum blackbird_pause {
+	BLACKBIRD_PAUSE_ENCODING,
+	BLACKBIRD_RESUME_ENCODING,
+};
+enum blackbird_copyright {
+	BLACKBIRD_COPYRIGHT_OFF,
+	BLACKBIRD_COPYRIGHT_ON,
+};
+enum blackbird_notification_type {
+	BLACKBIRD_NOTIFICATION_REFRESH,
+};
+enum blackbird_notification_status {
+	BLACKBIRD_NOTIFICATION_OFF,
+	BLACKBIRD_NOTIFICATION_ON,
+};
+enum blackbird_notification_mailbox {
+	BLACKBIRD_NOTIFICATION_NO_MAILBOX = -1,
+};
+enum blackbird_field1_lines {
+	BLACKBIRD_FIELD1_SAA7114 = 0x00EF, /* 239 */
+	BLACKBIRD_FIELD1_SAA7115 = 0x00F0, /* 240 */
+	BLACKBIRD_FIELD1_MICRONAS = 0x0105, /* 261 */
+};
+enum blackbird_field2_lines {
+	BLACKBIRD_FIELD2_SAA7114 = 0x00EF, /* 239 */
+	BLACKBIRD_FIELD2_SAA7115 = 0x00F0, /* 240 */
+	BLACKBIRD_FIELD2_MICRONAS = 0x0106, /* 262 */
+};
+enum blackbird_custom_data_type {
+	BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
+	BLACKBIRD_CUSTOM_PRIVATE_PACKET,
+};
+enum blackbird_mute {
+	BLACKBIRD_UNMUTE,
+	BLACKBIRD_MUTE,
+};
+enum blackbird_mute_video_mask {
+	BLACKBIRD_MUTE_VIDEO_V_MASK = 0x0000FF00,
+	BLACKBIRD_MUTE_VIDEO_U_MASK = 0x00FF0000,
+	BLACKBIRD_MUTE_VIDEO_Y_MASK = 0xFF000000,
+};
+enum blackbird_mute_video_shift {
+	BLACKBIRD_MUTE_VIDEO_V_SHIFT = 8,
+	BLACKBIRD_MUTE_VIDEO_U_SHIFT = 16,
+	BLACKBIRD_MUTE_VIDEO_Y_SHIFT = 24,
+};
+
+/* Registers */
+#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_SPU (0x9050 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_HW_BLOCKS (0x9054 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_VPU (0x9058 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_APU (0xA064 /*| IVTV_REG_OFFSET*/)
+
+/* ------------------------------------------------------------------ */
+
+static void host_setup(struct cx88_core *core)
+{
+	/* toggle reset of the host */
+	cx_write(MO_GPHST_SOFT_RST, 1);
+	udelay(100);
+	cx_write(MO_GPHST_SOFT_RST, 0);
+	udelay(100);
+
+	/* host port setup */
+	cx_write(MO_GPHST_WSC, 0x44444444U);
+	cx_write(MO_GPHST_XFR, 0);
+	cx_write(MO_GPHST_WDTH, 15);
+	cx_write(MO_GPHST_HDSHK, 0);
+	cx_write(MO_GPHST_MUX16, 0x44448888U);
+	cx_write(MO_GPHST_MODE, 0);
+}
+
+/* ------------------------------------------------------------------ */
+
+#define P1_MDATA0 0x390000
+#define P1_MDATA1 0x390001
+#define P1_MDATA2 0x390002
+#define P1_MDATA3 0x390003
+#define P1_MADDR2 0x390004
+#define P1_MADDR1 0x390005
+#define P1_MADDR0 0x390006
+#define P1_RDATA0 0x390008
+#define P1_RDATA1 0x390009
+#define P1_RDATA2 0x39000A
+#define P1_RDATA3 0x39000B
+#define P1_RADDR0 0x39000C
+#define P1_RADDR1 0x39000D
+#define P1_RRDWR  0x39000E
+
+static int wait_ready_gpio0_bit1(struct cx88_core *core, u32 state)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(1);
+	u32 gpio0,need;
+
+	need = state ? 2 : 0;
+	for (;;) {
+		gpio0 = cx_read(MO_GP0_IO) & 2;
+		if (need == gpio0)
+			return 0;
+		if (time_after(jiffies,timeout))
+			return -1;
+		udelay(1);
+	}
+}
+
+static int memory_write(struct cx88_core *core, u32 address, u32 value)
+{
+	/* Warning: address is dword address (4 bytes) */
+	cx_writeb(P1_MDATA0, (unsigned int)value);
+	cx_writeb(P1_MDATA1, (unsigned int)(value >> 8));
+	cx_writeb(P1_MDATA2, (unsigned int)(value >> 16));
+	cx_writeb(P1_MDATA3, (unsigned int)(value >> 24));
+	cx_writeb(P1_MADDR2, (unsigned int)(address >> 16) | 0x40);
+	cx_writeb(P1_MADDR1, (unsigned int)(address >> 8));
+	cx_writeb(P1_MADDR0, (unsigned int)address);
+	cx_read(P1_MDATA0);
+	cx_read(P1_MADDR0);
+
+	return wait_ready_gpio0_bit1(core,1);
+}
+
+static int memory_read(struct cx88_core *core, u32 address, u32 *value)
+{
+	int retval;
+	u32 val;
+
+	/* Warning: address is dword address (4 bytes) */
+	cx_writeb(P1_MADDR2, (unsigned int)(address >> 16) & ~0xC0);
+	cx_writeb(P1_MADDR1, (unsigned int)(address >> 8));
+	cx_writeb(P1_MADDR0, (unsigned int)address);
+	cx_read(P1_MADDR0);
+
+	retval = wait_ready_gpio0_bit1(core,1);
+
+	cx_writeb(P1_MDATA3, 0);
+	val     = (unsigned char)cx_read(P1_MDATA3) << 24;
+	cx_writeb(P1_MDATA2, 0);
+	val    |= (unsigned char)cx_read(P1_MDATA2) << 16;
+	cx_writeb(P1_MDATA1, 0);
+	val    |= (unsigned char)cx_read(P1_MDATA1) << 8;
+	cx_writeb(P1_MDATA0, 0);
+	val    |= (unsigned char)cx_read(P1_MDATA0);
+
+	*value  = val;
+	return retval;
+}
+
+static int register_write(struct cx88_core *core, u32 address, u32 value)
+{
+	cx_writeb(P1_RDATA0, (unsigned int)value);
+	cx_writeb(P1_RDATA1, (unsigned int)(value >> 8));
+	cx_writeb(P1_RDATA2, (unsigned int)(value >> 16));
+	cx_writeb(P1_RDATA3, (unsigned int)(value >> 24));
+	cx_writeb(P1_RADDR0, (unsigned int)address);
+	cx_writeb(P1_RADDR1, (unsigned int)(address >> 8));
+	cx_writeb(P1_RRDWR, 1);
+	cx_read(P1_RDATA0);
+	cx_read(P1_RADDR0);
+
+	return wait_ready_gpio0_bit1(core,1);
+}
+
+
+static int register_read(struct cx88_core *core, u32 address, u32 *value)
+{
+	int retval;
+	u32 val;
+
+	cx_writeb(P1_RADDR0, (unsigned int)address);
+	cx_writeb(P1_RADDR1, (unsigned int)(address >> 8));
+	cx_writeb(P1_RRDWR, 0);
+	cx_read(P1_RADDR0);
+
+	retval  = wait_ready_gpio0_bit1(core,1);
+	val     = (unsigned char)cx_read(P1_RDATA0);
+	val    |= (unsigned char)cx_read(P1_RDATA1) << 8;
+	val    |= (unsigned char)cx_read(P1_RDATA2) << 16;
+	val    |= (unsigned char)cx_read(P1_RDATA3) << 24;
+
+	*value  = val;
+	return retval;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
+{
+	struct cx8802_dev *dev = priv;
+	unsigned long timeout;
+	u32 value, flag, retval;
+	int i;
+
+	dprintk(1,"%s: 0x%X\n", __func__, command);
+
+	/* this may not be 100% safe if we can't read any memory location
+	   without side effects */
+	memory_read(dev->core, dev->mailbox - 4, &value);
+	if (value != 0x12345678) {
+		dprintk(0, "Firmware and/or mailbox pointer not initialized or corrupted\n");
+		return -1;
+	}
+
+	memory_read(dev->core, dev->mailbox, &flag);
+	if (flag) {
+		dprintk(0, "ERROR: Mailbox appears to be in use (%x)\n", flag);
+		return -1;
+	}
+
+	flag |= 1; /* tell 'em we're working on it */
+	memory_write(dev->core, dev->mailbox, flag);
+
+	/* write command + args + fill remaining with zeros */
+	memory_write(dev->core, dev->mailbox + 1, command); /* command code */
+	memory_write(dev->core, dev->mailbox + 3, IVTV_API_STD_TIMEOUT); /* timeout */
+	for (i = 0; i < in; i++) {
+		memory_write(dev->core, dev->mailbox + 4 + i, data[i]);
+		dprintk(1, "API Input %d = %d\n", i, data[i]);
+	}
+	for (; i < CX2341X_MBOX_MAX_DATA; i++)
+		memory_write(dev->core, dev->mailbox + 4 + i, 0);
+
+	flag |= 3; /* tell 'em we're done writing */
+	memory_write(dev->core, dev->mailbox, flag);
+
+	/* wait for firmware to handle the API command */
+	timeout = jiffies + msecs_to_jiffies(10);
+	for (;;) {
+		memory_read(dev->core, dev->mailbox, &flag);
+		if (0 != (flag & 4))
+			break;
+		if (time_after(jiffies,timeout)) {
+			dprintk(0, "ERROR: API Mailbox timeout\n");
+			return -1;
+		}
+		udelay(10);
+	}
+
+	/* read output values */
+	for (i = 0; i < out; i++) {
+		memory_read(dev->core, dev->mailbox + 4 + i, data + i);
+		dprintk(1, "API Output %d = %d\n", i, data[i]);
+	}
+
+	memory_read(dev->core, dev->mailbox + 2, &retval);
+	dprintk(1, "API result = %d\n",retval);
+
+	flag = 0;
+	memory_write(dev->core, dev->mailbox, flag);
+	return retval;
+}
+/* ------------------------------------------------------------------ */
+
+/* We don't need to call the API often, so using just one mailbox will probably suffice */
+static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
+			     u32 inputcnt, u32 outputcnt, ...)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	va_list vargs;
+	int i, err;
+
+	va_start(vargs, outputcnt);
+
+	for (i = 0; i < inputcnt; i++) {
+		data[i] = va_arg(vargs, int);
+	}
+	err = blackbird_mbox_func(dev, command, inputcnt, outputcnt, data);
+	for (i = 0; i < outputcnt; i++) {
+		int *vptr = va_arg(vargs, int *);
+		*vptr = data[i];
+	}
+	va_end(vargs);
+	return err;
+}
+
+static int blackbird_find_mailbox(struct cx8802_dev *dev)
+{
+	u32 signature[4]={0x12345678, 0x34567812, 0x56781234, 0x78123456};
+	int signaturecnt=0;
+	u32 value;
+	int i;
+
+	for (i = 0; i < BLACKBIRD_FIRM_IMAGE_SIZE; i++) {
+		memory_read(dev->core, i, &value);
+		if (value == signature[signaturecnt])
+			signaturecnt++;
+		else
+			signaturecnt = 0;
+		if (4 == signaturecnt) {
+			dprintk(1, "Mailbox signature found\n");
+			return i+1;
+		}
+	}
+	dprintk(0, "Mailbox signature values not found!\n");
+	return -1;
+}
+
+static int blackbird_load_firmware(struct cx8802_dev *dev)
+{
+	static const unsigned char magic[8] = {
+		0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
+	};
+	const struct firmware *firmware;
+	int i, retval = 0;
+	u32 value = 0;
+	u32 checksum = 0;
+	u32 *dataptr;
+
+	retval  = register_write(dev->core, IVTV_REG_VPU, 0xFFFFFFED);
+	retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+	retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_REFRESH, 0x80000640);
+	retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
+	msleep(1);
+	retval |= register_write(dev->core, IVTV_REG_APU, 0);
+
+	if (retval < 0)
+		dprintk(0, "Error with register_write\n");
+
+	retval = request_firmware(&firmware, CX2341X_FIRM_ENC_FILENAME,
+				  &dev->pci->dev);
+
+
+	if (retval != 0) {
+		dprintk(0, "ERROR: Hotplug firmware request failed (%s).\n",
+			CX2341X_FIRM_ENC_FILENAME);
+		dprintk(0, "Please fix your hotplug setup, the board will "
+			"not work without firmware loaded!\n");
+		return -1;
+	}
+
+	if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) {
+		dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d)\n",
+			firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE);
+		release_firmware(firmware);
+		return -1;
+	}
+
+	if (0 != memcmp(firmware->data, magic, 8)) {
+		dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\n");
+		release_firmware(firmware);
+		return -1;
+	}
+
+	/* transfer to the chip */
+	dprintk(1,"Loading firmware ...\n");
+	dataptr = (u32*)firmware->data;
+	for (i = 0; i < (firmware->size >> 2); i++) {
+		value = le32_to_cpu(*dataptr);
+		checksum += ~value;
+		memory_write(dev->core, i, value);
+		dataptr++;
+	}
+
+	/* read back to verify with the checksum */
+	for (i--; i >= 0; i--) {
+		memory_read(dev->core, i, &value);
+		checksum -= ~value;
+	}
+	if (checksum) {
+		dprintk(0, "ERROR: Firmware load failed (checksum mismatch).\n");
+		release_firmware(firmware);
+		return -1;
+	}
+	release_firmware(firmware);
+	dprintk(0, "Firmware upload successful.\n");
+
+	retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+	retval |= register_read(dev->core, IVTV_REG_SPU, &value);
+	retval |= register_write(dev->core, IVTV_REG_SPU, value & 0xFFFFFFFE);
+	msleep(1);
+
+	retval |= register_read(dev->core, IVTV_REG_VPU, &value);
+	retval |= register_write(dev->core, IVTV_REG_VPU, value & 0xFFFFFFE8);
+
+	if (retval < 0)
+		dprintk(0, "Error with register_write\n");
+	return 0;
+}
+
+/**
+ Settings used by the windows tv app for PVR2000:
+=================================================================================================================
+Profile | Codec | Resolution | CBR/VBR | Video Qlty   | V. Bitrate | Frmrate | Audio Codec | A. Bitrate | A. Mode
+-----------------------------------------------------------------------------------------------------------------
+MPEG-1  | MPEG1 | 352x288PAL | (CBR)   | 1000:Optimal | 2000 Kbps  | 25fps   | MPG1 Layer2 | 224kbps    | Stereo
+MPEG-2  | MPEG2 | 720x576PAL | VBR     | 600 :Good    | 4000 Kbps  | 25fps   | MPG1 Layer2 | 224kbps    | Stereo
+VCD     | MPEG1 | 352x288PAL | (CBR)   | 1000:Optimal | 1150 Kbps  | 25fps   | MPG1 Layer2 | 224kbps    | Stereo
+DVD     | MPEG2 | 720x576PAL | VBR     | 600 :Good    | 6000 Kbps  | 25fps   | MPG1 Layer2 | 224kbps    | Stereo
+DB* DVD | MPEG2 | 720x576PAL | CBR     | 600 :Good    | 6000 Kbps  | 25fps   | MPG1 Layer2 | 224kbps    | Stereo
+=================================================================================================================
+*DB: "DirectBurn"
+*/
+
+static void blackbird_codec_settings(struct cx8802_dev *dev)
+{
+	/* assign frame size */
+	blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+				dev->height, dev->width);
+
+	dev->cxhdl.width = dev->width;
+	dev->cxhdl.height = dev->height;
+	cx2341x_handler_set_50hz(&dev->cxhdl, dev->core->tvnorm & V4L2_STD_625_50);
+	cx2341x_handler_setup(&dev->cxhdl);
+}
+
+static int blackbird_initialize_codec(struct cx8802_dev *dev)
+{
+	struct cx88_core *core = dev->core;
+	int version;
+	int retval;
+
+	dprintk(1,"Initialize codec\n");
+	retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
+	if (retval < 0) {
+
+		dev->mpeg_active = 0;
+
+		/* ping was not successful, reset and upload firmware */
+		cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */
+		cx_write(MO_SRST_IO, 1); /* SYS_RSTO=1 */
+		retval = blackbird_load_firmware(dev);
+		if (retval < 0)
+			return retval;
+
+		retval = blackbird_find_mailbox(dev);
+		if (retval < 0)
+			return -1;
+
+		dev->mailbox = retval;
+
+		retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
+		if (retval < 0) {
+			dprintk(0, "ERROR: Firmware ping failed!\n");
+			return -1;
+		}
+
+		retval = blackbird_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, &version);
+		if (retval < 0) {
+			dprintk(0, "ERROR: Firmware get encoder version failed!\n");
+			return -1;
+		}
+		dprintk(0, "Firmware version is 0x%08x\n", version);
+	}
+
+	cx_write(MO_PINMUX_IO, 0x88); /* 656-8bit IO and enable MPEG parallel IO */
+	cx_clear(MO_INPUT_FORMAT, 0x100); /* chroma subcarrier lock to normal? */
+	cx_write(MO_VBOS_CONTROL, 0x84A00); /* no 656 mode, 8-bit pixels, disable VBI */
+	cx_clear(MO_OUTPUT_FORMAT, 0x0008); /* Normal Y-limits to let the mpeg encoder sync */
+
+	blackbird_codec_settings(dev);
+
+	blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
+			BLACKBIRD_FIELD1_SAA7115,
+			BLACKBIRD_FIELD2_SAA7115
+		);
+
+	blackbird_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
+			BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
+			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+	return 0;
+}
+
+static int blackbird_start_codec(struct file *file, void *priv)
+{
+	struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
+	struct cx88_core *core = dev->core;
+	/* start capturing to the host interface */
+	u32 reg;
+
+	int i;
+	int lastchange = -1;
+	int lastval = 0;
+
+	for (i = 0; (i < 10) && (i < (lastchange + 4)); i++) {
+		reg = cx_read(AUD_STATUS);
+
+		dprintk(1, "AUD_STATUS:%dL: 0x%x\n", i, reg);
+		if ((reg & 0x0F) != lastval) {
+			lastval = reg & 0x0F;
+			lastchange = i;
+		}
+		msleep(100);
+	}
+
+	/* unmute audio source */
+	cx_clear(AUD_VOL_CTL, (1 << 6));
+
+	blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0, 0);
+
+	/* initialize the video input */
+	blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
+
+	cx2341x_handler_set_busy(&dev->cxhdl, 1);
+
+	/* start capturing to the host interface */
+	blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
+			BLACKBIRD_MPEG_CAPTURE,
+			BLACKBIRD_RAW_BITS_NONE
+		);
+
+	dev->mpeg_active = 1;
+	return 0;
+}
+
+static int blackbird_stop_codec(struct cx8802_dev *dev)
+{
+	blackbird_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+			BLACKBIRD_END_NOW,
+			BLACKBIRD_MPEG_CAPTURE,
+			BLACKBIRD_RAW_BITS_NONE
+		);
+
+	cx2341x_handler_set_busy(&dev->cxhdl, 0);
+
+	dev->mpeg_active = 0;
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int bb_buf_setup(struct videobuf_queue *q,
+			unsigned int *count, unsigned int *size)
+{
+	struct cx8802_fh *fh = q->priv_data;
+
+	fh->dev->ts_packet_size  = 188 * 4; /* was: 512 */
+	fh->dev->ts_packet_count = mpegbufs; /* was: 100 */
+
+	*size = fh->dev->ts_packet_size * fh->dev->ts_packet_count;
+	*count = fh->dev->ts_packet_count;
+	return 0;
+}
+
+static int
+bb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+	       enum v4l2_field field)
+{
+	struct cx8802_fh *fh = q->priv_data;
+	return cx8802_buf_prepare(q, fh->dev, (struct cx88_buffer*)vb, field);
+}
+
+static void
+bb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct cx8802_fh *fh = q->priv_data;
+	cx8802_buf_queue(fh->dev, (struct cx88_buffer*)vb);
+}
+
+static void
+bb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	cx88_free_buffer(q, (struct cx88_buffer*)vb);
+}
+
+static struct videobuf_queue_ops blackbird_qops = {
+	.buf_setup    = bb_buf_setup,
+	.buf_prepare  = bb_buf_prepare,
+	.buf_queue    = bb_buf_queue,
+	.buf_release  = bb_buf_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int vidioc_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *cap)
+{
+	struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
+	struct cx88_core  *core = dev->core;
+
+	strcpy(cap->driver, "cx88_blackbird");
+	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+	cx88_querycap(file, core, cap);
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap (struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	if (f->index != 0)
+		return -EINVAL;
+
+	strlcpy(f->description, "MPEG", sizeof(f->description));
+	f->pixelformat = V4L2_PIX_FMT_MPEG;
+	f->flags = V4L2_FMT_FLAG_COMPRESSED;
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct cx8802_fh  *fh   = priv;
+	struct cx8802_dev *dev  = fh->dev;
+
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage    = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */;
+	f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
+	f->fmt.pix.width        = dev->width;
+	f->fmt.pix.height       = dev->height;
+	f->fmt.pix.field        = fh->mpegq.field;
+	dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+		dev->width, dev->height, fh->mpegq.field );
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct cx8802_fh  *fh   = priv;
+	struct cx8802_dev *dev  = fh->dev;
+
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage    = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */;
+	f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
+	dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+		dev->width, dev->height, fh->mpegq.field );
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap (struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct cx8802_fh  *fh   = priv;
+	struct cx8802_dev *dev  = fh->dev;
+	struct cx88_core  *core = dev->core;
+
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage    = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */;
+	f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
+	dev->width              = f->fmt.pix.width;
+	dev->height             = f->fmt.pix.height;
+	fh->mpegq.field         = f->fmt.pix.field;
+	cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+	blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+				f->fmt.pix.height, f->fmt.pix.width);
+	dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+		f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field );
+	return 0;
+}
+
+static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
+{
+	struct cx8802_fh  *fh   = priv;
+	return (videobuf_reqbufs(&fh->mpegq, p));
+}
+
+static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct cx8802_fh  *fh   = priv;
+	return (videobuf_querybuf(&fh->mpegq, p));
+}
+
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct cx8802_fh  *fh   = priv;
+	return (videobuf_qbuf(&fh->mpegq, p));
+}
+
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct cx8802_fh  *fh   = priv;
+	return (videobuf_dqbuf(&fh->mpegq, p,
+				file->f_flags & O_NONBLOCK));
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct cx8802_fh  *fh   = priv;
+	struct cx8802_dev *dev  = fh->dev;
+
+	if (!dev->mpeg_active)
+		blackbird_start_codec(file, fh);
+	return videobuf_streamon(&fh->mpegq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct cx8802_fh  *fh   = priv;
+	struct cx8802_dev *dev  = fh->dev;
+
+	if (dev->mpeg_active)
+		blackbird_stop_codec(dev);
+	return videobuf_streamoff(&fh->mpegq);
+}
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct cx8802_fh  *fh   = priv;
+	struct cx8802_dev *dev  = fh->dev;
+	struct cx88_core  *core = dev->core;
+
+	if (unlikely(UNSET == core->board.tuner_type))
+		return -EINVAL;
+	if (unlikely(f->tuner != 0))
+		return -EINVAL;
+	if (dev->mpeg_active)
+		blackbird_stop_codec(dev);
+
+	cx88_set_freq (core,f);
+	blackbird_initialize_codec(dev);
+	cx88_set_scale(dev->core, dev->width, dev->height,
+			fh->mpegq.field);
+	return 0;
+}
+
+static int vidioc_log_status (struct file *file, void *priv)
+{
+	struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
+	struct cx88_core  *core = dev->core;
+	char name[32 + 2];
+
+	snprintf(name, sizeof(name), "%s/2", core->name);
+	call_all(core, core, log_status);
+	v4l2_ctrl_handler_log_status(&dev->cxhdl.hdl, name);
+	return 0;
+}
+
+static int vidioc_enum_input (struct file *file, void *priv,
+				struct v4l2_input *i)
+{
+	struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
+	return cx88_enum_input (core,i);
+}
+
+static int vidioc_g_frequency (struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct cx8802_fh  *fh   = priv;
+	struct cx88_core  *core = fh->dev->core;
+
+	if (unlikely(UNSET == core->board.tuner_type))
+		return -EINVAL;
+	if (unlikely(f->tuner != 0))
+		return -EINVAL;
+
+	f->frequency = core->freq;
+	call_all(core, tuner, g_frequency, f);
+
+	return 0;
+}
+
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+	struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
+
+	*i = core->input;
+	return 0;
+}
+
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+	struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
+
+	if (i >= 4)
+		return -EINVAL;
+	if (0 == INPUT(i).type)
+		return -EINVAL;
+
+	mutex_lock(&core->lock);
+	cx88_newstation(core);
+	cx88_video_mux(core,i);
+	mutex_unlock(&core->lock);
+	return 0;
+}
+
+static int vidioc_g_tuner (struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
+	u32 reg;
+
+	if (unlikely(UNSET == core->board.tuner_type))
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+
+	strcpy(t->name, "Television");
+	t->capability = V4L2_TUNER_CAP_NORM;
+	t->rangehigh  = 0xffffffffUL;
+	call_all(core, tuner, g_tuner, t);
+
+	cx88_get_stereo(core ,t);
+	reg = cx_read(MO_DEVICE_STATUS);
+	t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
+	return 0;
+}
+
+static int vidioc_s_tuner (struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
+
+	if (UNSET == core->board.tuner_type)
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+
+	cx88_set_stereo(core, t->audmode, 1);
+	return 0;
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm)
+{
+	struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+
+	*tvnorm = core->tvnorm;
+	return 0;
+}
+
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
+
+	mutex_lock(&core->lock);
+	cx88_set_tvnorm(core,*id);
+	mutex_unlock(&core->lock);
+	return 0;
+}
+
+/* FIXME: cx88_ioctl_hook not implemented */
+
+static int mpeg_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct cx8802_dev *dev = video_drvdata(file);
+	struct cx8802_fh *fh;
+	struct cx8802_driver *drv = NULL;
+	int err;
+
+	dprintk( 1, "%s\n", __func__);
+
+	mutex_lock(&dev->core->lock);
+
+	/* Make sure we can acquire the hardware */
+	drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
+	if (!drv) {
+		dprintk(1, "%s: blackbird driver is not loaded\n", __func__);
+		mutex_unlock(&dev->core->lock);
+		return -ENODEV;
+	}
+
+	err = drv->request_acquire(drv);
+	if (err != 0) {
+		dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
+		mutex_unlock(&dev->core->lock);
+		return err;
+	}
+
+	if (!dev->core->mpeg_users && blackbird_initialize_codec(dev) < 0) {
+		drv->request_release(drv);
+		mutex_unlock(&dev->core->lock);
+		return -EINVAL;
+	}
+	dprintk(1, "open dev=%s\n", video_device_node_name(vdev));
+
+	/* allocate + initialize per filehandle data */
+	fh = kzalloc(sizeof(*fh),GFP_KERNEL);
+	if (NULL == fh) {
+		drv->request_release(drv);
+		mutex_unlock(&dev->core->lock);
+		return -ENOMEM;
+	}
+	v4l2_fh_init(&fh->fh, vdev);
+	file->private_data = fh;
+	fh->dev      = dev;
+
+	videobuf_queue_sg_init(&fh->mpegq, &blackbird_qops,
+			    &dev->pci->dev, &dev->slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			    V4L2_FIELD_INTERLACED,
+			    sizeof(struct cx88_buffer),
+			    fh, NULL);
+
+	/* FIXME: locking against other video device */
+	cx88_set_scale(dev->core, dev->width, dev->height,
+			fh->mpegq.field);
+
+	dev->core->mpeg_users++;
+	mutex_unlock(&dev->core->lock);
+	v4l2_fh_add(&fh->fh);
+	return 0;
+}
+
+static int mpeg_release(struct file *file)
+{
+	struct cx8802_fh  *fh  = file->private_data;
+	struct cx8802_dev *dev = fh->dev;
+	struct cx8802_driver *drv = NULL;
+
+	mutex_lock(&dev->core->lock);
+
+	if (dev->mpeg_active && dev->core->mpeg_users == 1)
+		blackbird_stop_codec(dev);
+
+	cx8802_cancel_buffers(fh->dev);
+	/* stop mpeg capture */
+	videobuf_stop(&fh->mpegq);
+
+	videobuf_mmap_free(&fh->mpegq);
+
+	v4l2_fh_del(&fh->fh);
+	v4l2_fh_exit(&fh->fh);
+	file->private_data = NULL;
+	kfree(fh);
+
+	/* Make sure we release the hardware */
+	drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
+	WARN_ON(!drv);
+	if (drv)
+		drv->request_release(drv);
+
+	dev->core->mpeg_users--;
+
+	mutex_unlock(&dev->core->lock);
+
+	return 0;
+}
+
+static ssize_t
+mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+{
+	struct cx8802_fh *fh = file->private_data;
+	struct cx8802_dev *dev = fh->dev;
+
+	if (!dev->mpeg_active)
+		blackbird_start_codec(file, fh);
+
+	return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
+				    file->f_flags & O_NONBLOCK);
+}
+
+static unsigned int
+mpeg_poll(struct file *file, struct poll_table_struct *wait)
+{
+	unsigned long req_events = poll_requested_events(wait);
+	struct cx8802_fh *fh = file->private_data;
+	struct cx8802_dev *dev = fh->dev;
+
+	if (!dev->mpeg_active && (req_events & (POLLIN | POLLRDNORM)))
+		blackbird_start_codec(file, fh);
+
+	return v4l2_ctrl_poll(file, wait) | videobuf_poll_stream(file, &fh->mpegq, wait);
+}
+
+static int
+mpeg_mmap(struct file *file, struct vm_area_struct * vma)
+{
+	struct cx8802_fh *fh = file->private_data;
+
+	return videobuf_mmap_mapper(&fh->mpegq, vma);
+}
+
+static const struct v4l2_file_operations mpeg_fops =
+{
+	.owner	       = THIS_MODULE,
+	.open	       = mpeg_open,
+	.release       = mpeg_release,
+	.read	       = mpeg_read,
+	.poll          = mpeg_poll,
+	.mmap	       = mpeg_mmap,
+	.unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
+	.vidioc_querycap      = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
+	.vidioc_reqbufs       = vidioc_reqbufs,
+	.vidioc_querybuf      = vidioc_querybuf,
+	.vidioc_qbuf          = vidioc_qbuf,
+	.vidioc_dqbuf         = vidioc_dqbuf,
+	.vidioc_streamon      = vidioc_streamon,
+	.vidioc_streamoff     = vidioc_streamoff,
+	.vidioc_s_frequency   = vidioc_s_frequency,
+	.vidioc_log_status    = vidioc_log_status,
+	.vidioc_enum_input    = vidioc_enum_input,
+	.vidioc_g_frequency   = vidioc_g_frequency,
+	.vidioc_g_input       = vidioc_g_input,
+	.vidioc_s_input       = vidioc_s_input,
+	.vidioc_g_tuner       = vidioc_g_tuner,
+	.vidioc_s_tuner       = vidioc_s_tuner,
+	.vidioc_g_std         = vidioc_g_std,
+	.vidioc_s_std         = vidioc_s_std,
+	.vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
+};
+
+static struct video_device cx8802_mpeg_template = {
+	.name                 = "cx8802",
+	.fops                 = &mpeg_fops,
+	.ioctl_ops 	      = &mpeg_ioctl_ops,
+	.tvnorms              = CX88_NORMS,
+};
+
+/* ------------------------------------------------------------------ */
+
+/* The CX8802 MPEG API will call this when we can use the hardware */
+static int cx8802_blackbird_advise_acquire(struct cx8802_driver *drv)
+{
+	struct cx88_core *core = drv->core;
+	int err = 0;
+
+	switch (core->boardnr) {
+	case CX88_BOARD_HAUPPAUGE_HVR1300:
+		/* By default, core setup will leave the cx22702 out of reset, on the bus.
+		 * We left the hardware on power up with the cx22702 active.
+		 * We're being given access to re-arrange the GPIOs.
+		 * Take the bus off the cx22702 and put the cx23416 on it.
+		 */
+		/* Toggle reset on cx22702 leaving i2c active */
+		cx_set(MO_GP0_IO, 0x00000080);
+		udelay(1000);
+		cx_clear(MO_GP0_IO, 0x00000080);
+		udelay(50);
+		cx_set(MO_GP0_IO, 0x00000080);
+		udelay(1000);
+		/* tri-state the cx22702 pins */
+		cx_set(MO_GP0_IO, 0x00000004);
+		udelay(1000);
+		break;
+	default:
+		err = -ENODEV;
+	}
+	return err;
+}
+
+/* The CX8802 MPEG API will call this when we need to release the hardware */
+static int cx8802_blackbird_advise_release(struct cx8802_driver *drv)
+{
+	struct cx88_core *core = drv->core;
+	int err = 0;
+
+	switch (core->boardnr) {
+	case CX88_BOARD_HAUPPAUGE_HVR1300:
+		/* Exit leaving the cx23416 on the bus */
+		break;
+	default:
+		err = -ENODEV;
+	}
+	return err;
+}
+
+static void blackbird_unregister_video(struct cx8802_dev *dev)
+{
+	if (dev->mpeg_dev) {
+		if (video_is_registered(dev->mpeg_dev))
+			video_unregister_device(dev->mpeg_dev);
+		else
+			video_device_release(dev->mpeg_dev);
+		dev->mpeg_dev = NULL;
+	}
+}
+
+static int blackbird_register_video(struct cx8802_dev *dev)
+{
+	int err;
+
+	dev->mpeg_dev = cx88_vdev_init(dev->core,dev->pci,
+				       &cx8802_mpeg_template,"mpeg");
+	dev->mpeg_dev->ctrl_handler = &dev->cxhdl.hdl;
+	video_set_drvdata(dev->mpeg_dev, dev);
+	err = video_register_device(dev->mpeg_dev,VFL_TYPE_GRABBER, -1);
+	if (err < 0) {
+		printk(KERN_INFO "%s/2: can't register mpeg device\n",
+		       dev->core->name);
+		return err;
+	}
+	printk(KERN_INFO "%s/2: registered device %s [mpeg]\n",
+	       dev->core->name, video_device_node_name(dev->mpeg_dev));
+	return 0;
+}
+
+/* ----------------------------------------------------------- */
+
+static int cx8802_blackbird_probe(struct cx8802_driver *drv)
+{
+	struct cx88_core *core = drv->core;
+	struct cx8802_dev *dev = core->dvbdev;
+	int err;
+
+	dprintk( 1, "%s\n", __func__);
+	dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
+		core->boardnr,
+		core->name,
+		core->pci_bus,
+		core->pci_slot);
+
+	err = -ENODEV;
+	if (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))
+		goto fail_core;
+
+	dev->width = 720;
+	if (core->tvnorm & V4L2_STD_525_60) {
+		dev->height = 480;
+	} else {
+		dev->height = 576;
+	}
+	dev->cxhdl.port = CX2341X_PORT_STREAMING;
+	dev->cxhdl.width = dev->width;
+	dev->cxhdl.height = dev->height;
+	dev->cxhdl.func = blackbird_mbox_func;
+	dev->cxhdl.priv = dev;
+	err = cx2341x_handler_init(&dev->cxhdl, 36);
+	if (err)
+		goto fail_core;
+	v4l2_ctrl_add_handler(&dev->cxhdl.hdl, &core->video_hdl);
+
+	/* blackbird stuff */
+	printk("%s/2: cx23416 based mpeg encoder (blackbird reference design)\n",
+	       core->name);
+	host_setup(dev->core);
+
+	blackbird_initialize_codec(dev);
+
+	/* initial device configuration: needed ? */
+//	init_controls(core);
+	cx88_set_tvnorm(core,core->tvnorm);
+	cx88_video_mux(core,0);
+	cx2341x_handler_set_50hz(&dev->cxhdl, dev->height == 576);
+	cx2341x_handler_setup(&dev->cxhdl);
+	blackbird_register_video(dev);
+
+	return 0;
+
+ fail_core:
+	return err;
+}
+
+static int cx8802_blackbird_remove(struct cx8802_driver *drv)
+{
+	struct cx88_core *core = drv->core;
+	struct cx8802_dev *dev = core->dvbdev;
+
+	/* blackbird */
+	blackbird_unregister_video(drv->core->dvbdev);
+	v4l2_ctrl_handler_free(&dev->cxhdl.hdl);
+
+	return 0;
+}
+
+static struct cx8802_driver cx8802_blackbird_driver = {
+	.type_id	= CX88_MPEG_BLACKBIRD,
+	.hw_access	= CX8802_DRVCTL_SHARED,
+	.probe		= cx8802_blackbird_probe,
+	.remove		= cx8802_blackbird_remove,
+	.advise_acquire	= cx8802_blackbird_advise_acquire,
+	.advise_release	= cx8802_blackbird_advise_release,
+};
+
+static int __init blackbird_init(void)
+{
+	printk(KERN_INFO "cx2388x blackbird driver version %s loaded\n",
+	       CX88_VERSION);
+	return cx8802_register_driver(&cx8802_blackbird_driver);
+}
+
+static void __exit blackbird_fini(void)
+{
+	cx8802_unregister_driver(&cx8802_blackbird_driver);
+}
+
+module_init(blackbird_init);
+module_exit(blackbird_fini);
+
+module_param_named(video_debug,cx8802_mpeg_template.debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages [video]");
diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c
new file mode 100644
index 0000000..4e9d4f7
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-cards.c
@@ -0,0 +1,3811 @@
+/*
+ *
+ * device driver for Conexant 2388x based TV cards
+ * card-specific stuff.
+ *
+ * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include "cx88.h"
+#include "tea5767.h"
+#include "xc4000.h"
+
+static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+static unsigned int card[]  = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(tuner, int, NULL, 0444);
+module_param_array(radio, int, NULL, 0444);
+module_param_array(card,  int, NULL, 0444);
+
+MODULE_PARM_DESC(tuner,"tuner type");
+MODULE_PARM_DESC(radio,"radio tuner type");
+MODULE_PARM_DESC(card,"card type");
+
+static unsigned int latency = UNSET;
+module_param(latency,int,0444);
+MODULE_PARM_DESC(latency,"pci latency timer");
+
+static int disable_ir;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(disable_ir, "Disable IR support");
+
+#define info_printk(core, fmt, arg...) \
+	printk(KERN_INFO "%s: " fmt, core->name , ## arg)
+
+#define warn_printk(core, fmt, arg...) \
+	printk(KERN_WARNING "%s: " fmt, core->name , ## arg)
+
+#define err_printk(core, fmt, arg...) \
+	printk(KERN_ERR "%s: " fmt, core->name , ## arg)
+
+
+/* ------------------------------------------------------------------ */
+/* board config info                                                  */
+
+/* If radio_type !=UNSET, radio_addr should be specified
+ */
+
+static const struct cx88_board cx88_boards[] = {
+	[CX88_BOARD_UNKNOWN] = {
+		.name		= "UNKNOWN/GENERIC",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 0,
+		},{
+			.type   = CX88_VMUX_COMPOSITE2,
+			.vmux   = 1,
+		},{
+			.type   = CX88_VMUX_COMPOSITE3,
+			.vmux   = 2,
+		},{
+			.type   = CX88_VMUX_COMPOSITE4,
+			.vmux   = 3,
+		}},
+	},
+	[CX88_BOARD_HAUPPAUGE] = {
+		.name		= "Hauppauge WinTV 34xxx models",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0xff00,  // internal decoder
+		},{
+			.type   = CX88_VMUX_DEBUG,
+			.vmux   = 0,
+			.gpio0  = 0xff01,  // mono from tuner chip
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0xff02,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0xff02,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0xff01,
+		},
+	},
+	[CX88_BOARD_GDI] = {
+		.name		= "GDI Black Gold",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+		}},
+	},
+	[CX88_BOARD_PIXELVIEW] = {
+		.name           = "PixelView",
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0xff00,  // internal decoder
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+		}},
+		.radio = {
+			 .type  = CX88_RADIO,
+			 .gpio0 = 0xff10,
+		},
+	},
+	[CX88_BOARD_ATI_WONDER_PRO] = {
+		.name           = "ATI TV Wonder Pro",
+		.tuner_type     = TUNER_PHILIPS_4IN1,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT | TDA9887_INTERCARRIER,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x03ff,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x03fe,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x03fe,
+		}},
+	},
+	[CX88_BOARD_WINFAST2000XP_EXPERT] = {
+		.name           = "Leadtek Winfast 2000XP Expert",
+		.tuner_type     = TUNER_PHILIPS_4IN1,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0	= 0x00F5e700,
+			.gpio1  = 0x00003004,
+			.gpio2  = 0x00F5e700,
+			.gpio3  = 0x02000000,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0	= 0x00F5c700,
+			.gpio1  = 0x00003004,
+			.gpio2  = 0x00F5c700,
+			.gpio3  = 0x02000000,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0	= 0x00F5c700,
+			.gpio1  = 0x00003004,
+			.gpio2  = 0x00F5c700,
+			.gpio3  = 0x02000000,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0	= 0x00F5d700,
+			.gpio1  = 0x00003004,
+			.gpio2  = 0x00F5d700,
+			.gpio3  = 0x02000000,
+		},
+	},
+	[CX88_BOARD_AVERTV_STUDIO_303] = {
+		.name           = "AverTV Studio 303 (M126)",
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio1  = 0xe09f,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio1  = 0xe05f,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio1  = 0xe05f,
+		}},
+		.radio = {
+			.gpio1  = 0xe0df,
+			.type   = CX88_RADIO,
+		},
+	},
+	[CX88_BOARD_MSI_TVANYWHERE_MASTER] = {
+		// added gpio values thanks to Michal
+		// values for PAL from DScaler
+		.name           = "MSI TV-@nywhere Master",
+		.tuner_type     = TUNER_MT2032,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf	= TDA9887_PRESENT | TDA9887_INTERCARRIER_NTSC,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x000040bf,
+			.gpio1  = 0x000080c0,
+			.gpio2  = 0x0000ff40,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x000040bf,
+			.gpio1  = 0x000080c0,
+			.gpio2  = 0x0000ff40,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x000040bf,
+			.gpio1  = 0x000080c0,
+			.gpio2  = 0x0000ff40,
+		}},
+		.radio = {
+			 .type   = CX88_RADIO,
+			 .vmux   = 3,
+			 .gpio0  = 0x000040bf,
+			 .gpio1  = 0x000080c0,
+			 .gpio2  = 0x0000ff20,
+		},
+	},
+	[CX88_BOARD_WINFAST_DV2000] = {
+		.name           = "Leadtek Winfast DV2000",
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x0035e700,
+			.gpio1  = 0x00003004,
+			.gpio2  = 0x0035e700,
+			.gpio3  = 0x02000000,
+		},{
+
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0035c700,
+			.gpio1  = 0x00003004,
+			.gpio2  = 0x0035c700,
+			.gpio3  = 0x02000000,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0035c700,
+			.gpio1  = 0x0035c700,
+			.gpio2  = 0x02000000,
+			.gpio3  = 0x02000000,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x0035d700,
+			.gpio1  = 0x00007004,
+			.gpio2  = 0x0035d700,
+			.gpio3  = 0x02000000,
+		},
+	},
+	[CX88_BOARD_LEADTEK_PVR2000] = {
+		// gpio values for PAL version from regspy by DScaler
+		.name           = "Leadtek PVR 2000",
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x0000bde2,
+			.audioroute = 1,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0000bde6,
+			.audioroute = 1,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0000bde6,
+			.audioroute = 1,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x0000bd62,
+			.audioroute = 1,
+		},
+		.mpeg           = CX88_MPEG_BLACKBIRD,
+	},
+	[CX88_BOARD_IODATA_GVVCP3PCI] = {
+		.name		= "IODATA GV-VCP3/PCI",
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 0,
+		},{
+			.type   = CX88_VMUX_COMPOSITE2,
+			.vmux   = 1,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+		}},
+	},
+	[CX88_BOARD_PROLINK_PLAYTVPVR] = {
+		.name           = "Prolink PlayTV PVR",
+		.tuner_type     = TUNER_PHILIPS_FM1236_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf	= TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0xbff0,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0xbff3,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0xbff3,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0xbff0,
+		},
+	},
+	[CX88_BOARD_ASUS_PVR_416] = {
+		.name		= "ASUS PVR-416",
+		.tuner_type     = TUNER_PHILIPS_FM1236_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x0000fde6,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
+			.audioroute = 1,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x0000fde2,
+		},
+		.mpeg           = CX88_MPEG_BLACKBIRD,
+	},
+	[CX88_BOARD_MSI_TVANYWHERE] = {
+		.name           = "MSI TV-@nywhere",
+		.tuner_type     = TUNER_MT2032,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x00000fbf,
+			.gpio2  = 0x0000fc08,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x00000fbf,
+			.gpio2  = 0x0000fc68,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x00000fbf,
+			.gpio2  = 0x0000fc68,
+		}},
+	},
+	[CX88_BOARD_KWORLD_DVB_T] = {
+		.name           = "KWorld/VStream XPert DVB-T",
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0700,
+			.gpio2  = 0x0101,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0700,
+			.gpio2  = 0x0101,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
+		.name           = "DViCO FusionHDTV DVB-T1",
+		.tuner_type     = TUNER_ABSENT, /* No analog tuner */
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x000027df,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x000027df,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_KWORLD_LTV883] = {
+		.name           = "KWorld LTV883RF",
+		.tuner_type     = TUNER_TNF_8831BGFF,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x07f8,
+		},{
+			.type   = CX88_VMUX_DEBUG,
+			.vmux   = 0,
+			.gpio0  = 0x07f9,  // mono from tuner chip
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x000007fa,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x000007fa,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x000007f8,
+		},
+	},
+	[CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q] = {
+		.name		= "DViCO FusionHDTV 3 Gold-Q",
+		.tuner_type     = TUNER_MICROTUNE_4042FI5,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		/*
+		   GPIO[0] resets DT3302 DTV receiver
+		    0 - reset asserted
+		    1 - normal operation
+		   GPIO[1] mutes analog audio output connector
+		    0 - enable selected source
+		    1 - mute
+		   GPIO[2] selects source for analog audio output connector
+		    0 - analog audio input connector on tab
+		    1 - analog DAC output from CX23881 chip
+		   GPIO[3] selects RF input connector on tuner module
+		    0 - RF connector labeled CABLE
+		    1 - RF connector labeled ANT
+		   GPIO[4] selects high RF for QAM256 mode
+		    0 - normal RF
+		    1 - high RF
+		*/
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0	= 0x0f0d,
+		},{
+			.type   = CX88_VMUX_CABLE,
+			.vmux   = 0,
+			.gpio0	= 0x0f05,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0	= 0x0f00,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0	= 0x0f00,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_HAUPPAUGE_DVB_T1] = {
+		.name           = "Hauppauge Nova-T DVB-T",
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_CONEXANT_DVB_T1] = {
+		.name           = "Conexant DVB-T reference design",
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_PROVIDEO_PV259] = {
+		.name		= "Provideo PV259",
+		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.audioroute = 1,
+		}},
+		.mpeg           = CX88_MPEG_BLACKBIRD,
+	},
+	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = {
+		.name           = "DViCO FusionHDTV DVB-T Plus",
+		.tuner_type     = TUNER_ABSENT, /* No analog tuner */
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x000027df,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x000027df,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_DNTV_LIVE_DVB_T] = {
+		.name		= "digitalnow DNTV Live! DVB-T",
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input		= {{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x00000700,
+			.gpio2  = 0x00000101,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x00000700,
+			.gpio2  = 0x00000101,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_PCHDTV_HD3000] = {
+		.name           = "pcHDTV HD3000 HDTV",
+		.tuner_type     = TUNER_THOMSON_DTT761X,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		/* GPIO[2] = audio source for analog audio out connector
+		 *  0 = analog audio input connector
+		 *  1 = CX88 audio DACs
+		 *
+		 * GPIO[7] = input to CX88's audio/chroma ADC
+		 *  0 = FM 10.7 MHz IF
+		 *  1 = Sound 4.5 MHz IF
+		 *
+		 * GPIO[1,5,6] = Oren 51132 pins 27,35,28 respectively
+		 *
+		 * GPIO[16] = Remote control input
+		 */
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x00008484,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x00008400,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x00008400,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x00008404,
+		},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_HAUPPAUGE_ROSLYN] = {
+		// entry added by Kaustubh D. Bhalerao <bhalerao.1@osu.edu>
+		// GPIO values obtained from regspy, courtesy Sean Covel
+		.name           = "Hauppauge WinTV 28xxx (Roslyn) models",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0xed1a,
+			.gpio2  = 0x00ff,
+		},{
+			.type   = CX88_VMUX_DEBUG,
+			.vmux   = 0,
+			.gpio0  = 0xff01,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0xff02,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0xed92,
+			.gpio2  = 0x00ff,
+		}},
+		.radio = {
+			 .type   = CX88_RADIO,
+			 .gpio0  = 0xed96,
+			 .gpio2  = 0x00ff,
+		 },
+		.mpeg           = CX88_MPEG_BLACKBIRD,
+	},
+	[CX88_BOARD_DIGITALLOGIC_MEC] = {
+		.name           = "Digital-Logic MICROSPACE Entertainment Center (MEC)",
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x00009d80,
+			.audioroute = 1,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x00009d76,
+			.audioroute = 1,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x00009d76,
+			.audioroute = 1,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x00009d00,
+			.audioroute = 1,
+		},
+		.mpeg           = CX88_MPEG_BLACKBIRD,
+	},
+	[CX88_BOARD_IODATA_GVBCTV7E] = {
+		.name           = "IODATA GV/BCTV7E",
+		.tuner_type     = TUNER_PHILIPS_FQ1286,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 1,
+			.gpio1  = 0x0000e03f,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 2,
+			.gpio1  = 0x0000e07f,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 3,
+			.gpio1  = 0x0000e07f,
+		}}
+	},
+	[CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO] = {
+		.name           = "PixelView PlayTV Ultra Pro (Stereo)",
+		/* May be also TUNER_YMEC_TVF_5533MF for NTSC/M or PAL/M */
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		/* Some variants use a tda9874 and so need the tvaudio module. */
+		.audio_chip     = V4L2_IDENT_TVAUDIO,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0xbf61,  /* internal decoder */
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0	= 0xbf63,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0	= 0xbf63,
+		}},
+		.radio = {
+			 .type  = CX88_RADIO,
+			 .gpio0 = 0xbf60,
+		 },
+	},
+	[CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = {
+		.name           = "DViCO FusionHDTV 3 Gold-T",
+		.tuner_type     = TUNER_THOMSON_DTT761X,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x97ed,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x97e9,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x97e9,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_ADSTECH_DVB_T_PCI] = {
+		.name           = "ADS Tech Instant TV DVB-T PCI",
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0700,
+			.gpio2  = 0x0101,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0700,
+			.gpio2  = 0x0101,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = {
+		.name           = "TerraTec Cinergy 1400 DVB-T",
+		.tuner_type     = TUNER_ABSENT,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 2,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = {
+		.name           = "DViCO FusionHDTV 5 Gold",
+		.tuner_type     = TUNER_LG_TDVS_H06XF, /* TDVS-H062F */
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x87fd,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x87f9,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x87f9,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_AVERMEDIA_ULTRATV_MC_550] = {
+		.name           = "AverMedia UltraTV Media Center PCI 550",
+		.tuner_type     = TUNER_PHILIPS_FM1236_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 0,
+			.gpio0  = 0x0000cd73,
+			.audioroute = 1,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 1,
+			.gpio0  = 0x0000cd73,
+			.audioroute = 1,
+		},{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 3,
+			.gpio0  = 0x0000cdb3,
+			.audioroute = 1,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.vmux   = 2,
+			.gpio0  = 0x0000cdf3,
+			.audioroute = 1,
+		},
+		.mpeg           = CX88_MPEG_BLACKBIRD,
+	},
+	[CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD] = {
+		 /* Alexander Wold <awold@bigfoot.com> */
+		 .name           = "Kworld V-Stream Xpert DVD",
+		 .tuner_type     = UNSET,
+		 .input          = {{
+			 .type   = CX88_VMUX_COMPOSITE1,
+			 .vmux   = 1,
+			 .gpio0  = 0x03000000,
+			 .gpio1  = 0x01000000,
+			 .gpio2  = 0x02000000,
+			 .gpio3  = 0x00100000,
+		 },{
+			 .type   = CX88_VMUX_SVIDEO,
+			 .vmux   = 2,
+			 .gpio0  = 0x03000000,
+			 .gpio1  = 0x01000000,
+			 .gpio2  = 0x02000000,
+			 .gpio3  = 0x00100000,
+		 }},
+	},
+	[CX88_BOARD_ATI_HDTVWONDER] = {
+		.name           = "ATI HDTV Wonder",
+		.tuner_type     = TUNER_PHILIPS_TUV1236D,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x00000ff7,
+			.gpio1  = 0x000000ff,
+			.gpio2  = 0x00000001,
+			.gpio3  = 0x00000000,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x00000ffe,
+			.gpio1  = 0x000000ff,
+			.gpio2  = 0x00000001,
+			.gpio3  = 0x00000000,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x00000ffe,
+			.gpio1  = 0x000000ff,
+			.gpio2  = 0x00000001,
+			.gpio3  = 0x00000000,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_WINFAST_DTV1000] = {
+		.name           = "WinFast DTV1000-T",
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_AVERTV_303] = {
+		.name           = "AVerTV 303 (M126)",
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x00ff,
+			.gpio1  = 0xe09f,
+			.gpio2  = 0x0010,
+			.gpio3  = 0x0000,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x00ff,
+			.gpio1  = 0xe05f,
+			.gpio2  = 0x0010,
+			.gpio3  = 0x0000,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x00ff,
+			.gpio1  = 0xe05f,
+			.gpio2  = 0x0010,
+			.gpio3  = 0x0000,
+		}},
+	},
+	[CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1] = {
+		.name		= "Hauppauge Nova-S-Plus DVB-S",
+		.tuner_type	= TUNER_ABSENT,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.audio_chip	= V4L2_IDENT_WM8775,
+		.i2sinputcntl   = 2,
+		.input		= {{
+			.type	= CX88_VMUX_DVB,
+			.vmux	= 0,
+			/* 2: Line-In */
+			.audioroute = 2,
+		},{
+			.type	= CX88_VMUX_COMPOSITE1,
+			.vmux	= 1,
+			/* 2: Line-In */
+			.audioroute = 2,
+		},{
+			.type	= CX88_VMUX_SVIDEO,
+			.vmux	= 2,
+			/* 2: Line-In */
+			.audioroute = 2,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = {
+		.name		= "Hauppauge Nova-SE2 DVB-S",
+		.tuner_type	= TUNER_ABSENT,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input		= {{
+			.type	= CX88_VMUX_DVB,
+			.vmux	= 0,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_KWORLD_DVBS_100] = {
+		.name		= "KWorld DVB-S 100",
+		.tuner_type	= TUNER_ABSENT,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.audio_chip = V4L2_IDENT_WM8775,
+		.input		= {{
+			.type	= CX88_VMUX_DVB,
+			.vmux	= 0,
+			/* 2: Line-In */
+			.audioroute = 2,
+		},{
+			.type	= CX88_VMUX_COMPOSITE1,
+			.vmux	= 1,
+			/* 2: Line-In */
+			.audioroute = 2,
+		},{
+			.type	= CX88_VMUX_SVIDEO,
+			.vmux	= 2,
+			/* 2: Line-In */
+			.audioroute = 2,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_HAUPPAUGE_HVR1100] = {
+		.name		= "Hauppauge WinTV-HVR1100 DVB-T/Hybrid",
+		.tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input		= {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+		},{
+			.type	= CX88_VMUX_COMPOSITE1,
+			.vmux	= 1,
+		},{
+			.type	= CX88_VMUX_SVIDEO,
+			.vmux	= 2,
+		}},
+		/* fixme: Add radio support */
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_HAUPPAUGE_HVR1100LP] = {
+		.name		= "Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)",
+		.tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input		= {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+		},{
+			.type	= CX88_VMUX_COMPOSITE1,
+			.vmux	= 1,
+		}},
+		/* fixme: Add radio support */
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_DNTV_LIVE_DVB_T_PRO] = {
+		.name           = "digitalnow DNTV Live! DVB-T Pro",
+		.tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
+				  TDA9887_PORT2_ACTIVE,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0xf80808,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0	= 0xf80808,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0	= 0xf80808,
+		}},
+		.radio = {
+			 .type  = CX88_RADIO,
+			 .gpio0 = 0xf80808,
+		},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_KWORLD_DVB_T_CX22702] = {
+		/* Kworld V-stream Xpert DVB-T with Thomson tuner */
+		/* DTT 7579 Conexant CX22702-19 Conexant CX2388x  */
+		/* Manenti Marco <marco_manenti@colman.it> */
+		.name           = "KWorld/VStream XPert DVB-T with cx22702",
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0700,
+			.gpio2  = 0x0101,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0700,
+			.gpio2  = 0x0101,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL] = {
+		.name           = "DViCO FusionHDTV DVB-T Dual Digital",
+		.tuner_type     = TUNER_ABSENT, /* No analog tuner */
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x000067df,
+		 },{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x000067df,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
+		.name           = "KWorld HardwareMpegTV XPert",
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x3de2,
+			.gpio2  = 0x00ff,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x3de6,
+			.audioroute = 1,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x3de6,
+			.audioroute = 1,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x3de6,
+			.gpio2  = 0x00ff,
+		},
+		.mpeg           = CX88_MPEG_BLACKBIRD,
+	},
+	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID] = {
+		.name           = "DViCO FusionHDTV DVB-T Hybrid",
+		.tuner_type     = TUNER_THOMSON_FE6600,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x0000a75f,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0000a75b,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0000a75b,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_PCHDTV_HD5500] = {
+		.name           = "pcHDTV HD5500 HDTV",
+		.tuner_type     = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x87fd,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x87f9,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x87f9,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_KWORLD_MCE200_DELUXE] = {
+		/* FIXME: tested TV input only, disabled composite,
+		   svideo and radio until they can be tested also. */
+		.name           = "Kworld MCE 200 Deluxe",
+		.tuner_type     = TUNER_TENA_9533_DI,
+		.radio_type     = UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x0000BDE6
+		}},
+		.mpeg           = CX88_MPEG_BLACKBIRD,
+	},
+	[CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = {
+		/* FIXME: SVideo, Composite and FM inputs are untested */
+		.name           = "PixelView PlayTV P7000",
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
+				  TDA9887_PORT2_ACTIVE,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x5da6,
+		}},
+		.mpeg           = CX88_MPEG_BLACKBIRD,
+	},
+	[CX88_BOARD_NPGTECH_REALTV_TOP10FM] = {
+		.name           = "NPG Tech Real TV FM Top 10",
+		.tuner_type     = TUNER_TNF_5335MF, /* Actually a TNF9535 */
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0	= 0x0788,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0	= 0x078b,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0	= 0x078b,
+		}},
+		.radio = {
+			 .type  = CX88_RADIO,
+			 .gpio0 = 0x074a,
+		},
+	},
+	[CX88_BOARD_WINFAST_DTV2000H] = {
+		.name           = "WinFast DTV2000 H",
+		.tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x00017304,
+			.gpio1  = 0x00008203,
+			.gpio2  = 0x00017304,
+			.gpio3  = 0x02000000,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0001d701,
+			.gpio1  = 0x0000b207,
+			.gpio2  = 0x0001d701,
+			.gpio3  = 0x02000000,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE2,
+			.vmux   = 2,
+			.gpio0  = 0x0001d503,
+			.gpio1  = 0x0000b207,
+			.gpio2  = 0x0001d503,
+			.gpio3  = 0x02000000,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 3,
+			.gpio0  = 0x0001d701,
+			.gpio1  = 0x0000b207,
+			.gpio2  = 0x0001d701,
+			.gpio3  = 0x02000000,
+		}},
+		.radio = {
+			 .type  = CX88_RADIO,
+			 .gpio0 = 0x00015702,
+			 .gpio1 = 0x0000f207,
+			 .gpio2 = 0x00015702,
+			 .gpio3 = 0x02000000,
+		},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_WINFAST_DTV2000H_J] = {
+		.name           = "WinFast DTV2000 H rev. J",
+		.tuner_type     = TUNER_PHILIPS_FMD1216MEX_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x00017300,
+			.gpio1  = 0x00008207,
+			.gpio2	= 0x00000000,
+			.gpio3  = 0x02000000,
+		},{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x00018300,
+			.gpio1  = 0x0000f207,
+			.gpio2	= 0x00017304,
+			.gpio3  = 0x02000000,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x00018301,
+			.gpio1  = 0x0000f207,
+			.gpio2	= 0x00017304,
+			.gpio3  = 0x02000000,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x00018301,
+			.gpio1  = 0x0000f207,
+			.gpio2	= 0x00017304,
+			.gpio3  = 0x02000000,
+		}},
+		.radio = {
+			 .type  = CX88_RADIO,
+			 .gpio0 = 0x00015702,
+			 .gpio1 = 0x0000f207,
+			 .gpio2 = 0x00015702,
+			 .gpio3 = 0x02000000,
+		},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_GENIATECH_DVBS] = {
+		.name          = "Geniatech DVB-S",
+		.tuner_type    = TUNER_ABSENT,
+		.radio_type    = UNSET,
+		.tuner_addr    = ADDR_UNSET,
+		.radio_addr    = ADDR_UNSET,
+		.input  = {{
+			.type  = CX88_VMUX_DVB,
+			.vmux  = 0,
+		},{
+			.type  = CX88_VMUX_COMPOSITE1,
+			.vmux  = 1,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_HAUPPAUGE_HVR3000] = {
+		.name           = "Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T",
+		.tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.audio_chip     = V4L2_IDENT_WM8775,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x84bf,
+			/* 1: TV Audio / FM Mono */
+			.audioroute = 1,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x84bf,
+			/* 2: Line-In */
+			.audioroute = 2,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x84bf,
+			/* 2: Line-In */
+			.audioroute = 2,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0	= 0x84bf,
+			/* 4: FM Stereo (untested) */
+			.audioroute = 8,
+		},
+		.mpeg           = CX88_MPEG_DVB,
+		.num_frontends	= 2,
+	},
+	[CX88_BOARD_NORWOOD_MICRO] = {
+		.name           = "Norwood Micro TV Tuner",
+		.tuner_type     = TUNER_TNF_5335MF,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x0709,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x070b,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x070b,
+		}},
+	},
+	[CX88_BOARD_TE_DTV_250_OEM_SWANN] = {
+		.name           = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM",
+		.tuner_type     = TUNER_LG_PAL_NEW_TAPC,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x003fffff,
+			.gpio1  = 0x00e00000,
+			.gpio2  = 0x003fffff,
+			.gpio3  = 0x02000000,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x003fffff,
+			.gpio1  = 0x00e00000,
+			.gpio2  = 0x003fffff,
+			.gpio3  = 0x02000000,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x003fffff,
+			.gpio1  = 0x00e00000,
+			.gpio2  = 0x003fffff,
+			.gpio3  = 0x02000000,
+		}},
+	},
+	[CX88_BOARD_HAUPPAUGE_HVR1300] = {
+		.name		= "Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder",
+		.tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.audio_chip     = V4L2_IDENT_WM8775,
+		/*
+		 * gpio0 as reported by Mike Crash <mike AT mikecrash.com>
+		 */
+		.input		= {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0	= 0xef88,
+			/* 1: TV Audio / FM Mono */
+			.audioroute = 1,
+		},{
+			.type	= CX88_VMUX_COMPOSITE1,
+			.vmux	= 1,
+			.gpio0	= 0xef88,
+			/* 2: Line-In */
+			.audioroute = 2,
+		},{
+			.type	= CX88_VMUX_SVIDEO,
+			.vmux	= 2,
+			.gpio0	= 0xef88,
+			/* 2: Line-In */
+			.audioroute = 2,
+		}},
+		.mpeg           = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0	= 0xef88,
+			/* 4: FM Stereo (untested) */
+			.audioroute = 8,
+		},
+	},
+	[CX88_BOARD_SAMSUNG_SMT_7020] = {
+		.name		= "Samsung SMT 7020 DVB-S",
+		.tuner_type	= TUNER_ABSENT,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input		= { {
+			.type	= CX88_VMUX_DVB,
+			.vmux	= 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_ADSTECH_PTV_390] = {
+		.name           = "ADS Tech Instant Video PCI",
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DEBUG,
+			.vmux   = 3,
+			.gpio0  = 0x04ff,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x07fa,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x07fa,
+		}},
+	},
+	[CX88_BOARD_PINNACLE_PCTV_HD_800i] = {
+		.name           = "Pinnacle PCTV HD 800i",
+		.tuner_type     = TUNER_XC5000,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x04fb,
+			.gpio1  = 0x10ff,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x04fb,
+			.gpio1  = 0x10ef,
+			.audioroute = 1,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x04fb,
+			.gpio1  = 0x10ef,
+			.audioroute = 1,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO] = {
+		.name           = "DViCO FusionHDTV 5 PCI nano",
+		/* xc3008 tuner, digital only for now */
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x000027df, /* Unconfirmed */
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x000027df, /* Unconfirmed */
+			.audioroute = 1,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x000027df, /* Unconfirmed */
+			.audioroute = 1,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_PINNACLE_HYBRID_PCTV] = {
+		.name           = "Pinnacle Hybrid PCTV",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_addr     = 0x61,
+		.radio_type     = UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = { {
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x004ff,
+			.gpio1  = 0x010ff,
+			.gpio2  = 0x00001,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x004fb,
+			.gpio1  = 0x010ef,
+			.audioroute = 1,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x004fb,
+			.gpio1  = 0x010ef,
+			.audioroute = 1,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x004ff,
+			.gpio1  = 0x010ff,
+			.gpio2  = 0x0ff,
+		},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	/* Terry Wu <terrywu2009@gmail.com> */
+	/* TV Audio :      set GPIO 2, 18, 19 value to 0, 1, 0 */
+	/* FM Audio :      set GPIO 2, 18, 19 value to 0, 0, 0 */
+	/* Line-in Audio : set GPIO 2, 18, 19 value to 0, 1, 1 */
+	/* Mute Audio :    set GPIO 2 value to 1               */
+	[CX88_BOARD_WINFAST_TV2000_XP_GLOBAL] = {
+		.name           = "Leadtek TV2000 XP Global",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_addr     = 0x61,
+		.radio_type     = UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = { {
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x0400,       /* pin 2 = 0 */
+			.gpio1  = 0x0000,
+			.gpio2  = 0x0C04,       /* pin 18 = 1, pin 19 = 0 */
+			.gpio3  = 0x0000,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0400,       /* pin 2 = 0 */
+			.gpio1  = 0x0000,
+			.gpio2  = 0x0C0C,       /* pin 18 = 1, pin 19 = 1 */
+			.gpio3  = 0x0000,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0400,       /* pin 2 = 0 */
+			.gpio1  = 0x0000,
+			.gpio2  = 0x0C0C,       /* pin 18 = 1, pin 19 = 1 */
+			.gpio3  = 0x0000,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x0400,        /* pin 2 = 0 */
+			.gpio1  = 0x0000,
+			.gpio2  = 0x0C00,       /* pin 18 = 0, pin 19 = 0 */
+			.gpio3  = 0x0000,
+		},
+	},
+	[CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36] = {
+		.name           = "Leadtek TV2000 XP Global (SC4100)",
+		.tuner_type     = TUNER_XC4000,
+		.tuner_addr     = 0x61,
+		.radio_type     = UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = { {
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x0400,       /* pin 2 = 0 */
+			.gpio1  = 0x0000,
+			.gpio2  = 0x0C04,       /* pin 18 = 1, pin 19 = 0 */
+			.gpio3  = 0x0000,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0400,       /* pin 2 = 0 */
+			.gpio1  = 0x0000,
+			.gpio2  = 0x0C0C,       /* pin 18 = 1, pin 19 = 1 */
+			.gpio3  = 0x0000,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0400,       /* pin 2 = 0 */
+			.gpio1  = 0x0000,
+			.gpio2  = 0x0C0C,       /* pin 18 = 1, pin 19 = 1 */
+			.gpio3  = 0x0000,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x0400,        /* pin 2 = 0 */
+			.gpio1  = 0x0000,
+			.gpio2  = 0x0C00,       /* pin 18 = 0, pin 19 = 0 */
+			.gpio3  = 0x0000,
+		},
+	},
+	[CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43] = {
+		.name           = "Leadtek TV2000 XP Global (XC4100)",
+		.tuner_type     = TUNER_XC4000,
+		.tuner_addr     = 0x61,
+		.radio_type     = UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = { {
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x0400,       /* pin 2 = 0 */
+			.gpio1  = 0x6040,       /* pin 14 = 1, pin 13 = 0 */
+			.gpio2  = 0x0000,
+			.gpio3  = 0x0000,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0400,       /* pin 2 = 0 */
+			.gpio1  = 0x6060,       /* pin 14 = 1, pin 13 = 1 */
+			.gpio2  = 0x0000,
+			.gpio3  = 0x0000,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0400,       /* pin 2 = 0 */
+			.gpio1  = 0x6060,       /* pin 14 = 1, pin 13 = 1 */
+			.gpio2  = 0x0000,
+			.gpio3  = 0x0000,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x0400,        /* pin 2 = 0 */
+			.gpio1  = 0x6000,        /* pin 14 = 1, pin 13 = 0 */
+			.gpio2  = 0x0000,
+			.gpio3  = 0x0000,
+		},
+	},
+	[CX88_BOARD_POWERCOLOR_REAL_ANGEL] = {
+		.name           = "PowerColor RA330",	/* Long names may confuse LIRC. */
+		.tuner_type     = TUNER_XC2028,
+		.tuner_addr     = 0x61,
+		.input          = { {
+			.type   = CX88_VMUX_DEBUG,
+			.vmux   = 3,		/* Due to the way the cx88 driver is written,	*/
+			.gpio0 = 0x00ff,	/* there is no way to deactivate audio pass-	*/
+			.gpio1 = 0xf39d,	/* through without this entry. Furthermore, if	*/
+			.gpio3 = 0x0000,	/* the TV mux entry is first, you get audio	*/
+		}, {				/* from the tuner on boot for a little while.	*/
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0 = 0x00ff,
+			.gpio1 = 0xf35d,
+			.gpio3 = 0x0000,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0 = 0x00ff,
+			.gpio1 = 0xf37d,
+			.gpio3 = 0x0000,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x000ff,
+			.gpio1  = 0x0f37d,
+			.gpio3  = 0x00000,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x000ff,
+			.gpio1  = 0x0f35d,
+			.gpio3  = 0x00000,
+		},
+	},
+	[CX88_BOARD_GENIATECH_X8000_MT] = {
+		/* Also PowerColor Real Angel 330 and Geniatech X800 OEM */
+		.name           = "Geniatech X8000-MT DVBT",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_addr     = 0x61,
+		.input          = { {
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x00000000,
+			.gpio1  = 0x00e3e341,
+			.gpio2  = 0x00000000,
+			.gpio3  = 0x00000000,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x00000000,
+			.gpio1  = 0x00e3e361,
+			.gpio2  = 0x00000000,
+			.gpio3  = 0x00000000,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x00000000,
+			.gpio1  = 0x00e3e361,
+			.gpio2  = 0x00000000,
+			.gpio3  = 0x00000000,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x00000000,
+			.gpio1  = 0x00e3e341,
+			.gpio2  = 0x00000000,
+			.gpio3  = 0x00000000,
+		},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO] = {
+		.name           = "DViCO FusionHDTV DVB-T PRO",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_addr     = 0x61,
+		.radio_type     = UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = { {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x000067df,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x000067df,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD] = {
+		.name           = "DViCO FusionHDTV 7 Gold",
+		.tuner_type     = TUNER_XC5000,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x10df,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x16d9,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x16d9,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_PROLINK_PV_8000GT] = {
+		.name           = "Prolink Pixelview MPEG 8000GT",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_addr     = 0x61,
+		.input          = { {
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0 = 0x0ff,
+			.gpio2 = 0x0cfb,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio2 = 0x0cfb,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio2 = 0x0cfb,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio2 = 0x0cfb,
+		},
+	},
+	[CX88_BOARD_PROLINK_PV_GLOBAL_XTREME] = {
+		.name           = "Prolink Pixelview Global Extreme",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_addr     = 0x61,
+		.input          = { {
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0 = 0x04fb,
+			.gpio1 = 0x04080,
+			.gpio2 = 0x0cf7,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0 = 0x04fb,
+			.gpio1 = 0x04080,
+			.gpio2 = 0x0cfb,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0 = 0x04fb,
+			.gpio1 = 0x04080,
+			.gpio2 = 0x0cfb,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0 = 0x04ff,
+			.gpio1 = 0x04080,
+			.gpio2 = 0x0cf7,
+		},
+	},
+	/* Both radio, analog and ATSC work with this board.
+	   However, for analog to work, s5h1409 gate should be open,
+	   otherwise, tuner-xc3028 won't be detected.
+	   A proper fix require using the newer i2c methods to add
+	   tuner-xc3028 without doing an i2c probe.
+	 */
+	[CX88_BOARD_KWORLD_ATSC_120] = {
+		.name           = "Kworld PlusTV HD PCI 120 (ATSC 120)",
+		.tuner_type     = TUNER_XC2028,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = { {
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x000000ff,
+			.gpio1  = 0x0000f35d,
+			.gpio2  = 0x00000000,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x000000ff,
+			.gpio1  = 0x0000f37e,
+			.gpio2  = 0x00000000,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x000000ff,
+			.gpio1  = 0x0000f37e,
+			.gpio2  = 0x00000000,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x000000ff,
+			.gpio1  = 0x0000f35d,
+			.gpio2  = 0x00000000,
+		},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_HAUPPAUGE_HVR4000] = {
+		.name           = "Hauppauge WinTV-HVR4000 DVB-S/S2/T/Hybrid",
+		.tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.audio_chip     = V4L2_IDENT_WM8775,
+		/*
+		 * GPIO0 (WINTV2000)
+		 *
+		 * Analogue     SAT     DVB-T
+		 * Antenna      0xc4bf  0xc4bb
+		 * Composite    0xc4bf  0xc4bb
+		 * S-Video      0xc4bf  0xc4bb
+		 * Composite1   0xc4ff  0xc4fb
+		 * S-Video1     0xc4ff  0xc4fb
+		 *
+		 * BIT  VALUE   FUNCTION GP{x}_IO
+		 * 0    1       I:?
+		 * 1    1       I:?
+		 * 2    1       O:MPEG PORT 0=DVB-T 1=DVB-S
+		 * 3    1       I:?
+		 * 4    1       I:?
+		 * 5    1       I:?
+		 * 6    0       O:INPUT SELECTOR 0=INTERNAL 1=EXPANSION
+		 * 7    1       O:DVB-T DEMOD RESET LOW
+		 *
+		 * BIT  VALUE   FUNCTION GP{x}_OE
+		 * 8    0       I
+		 * 9    0       I
+		 * a    1       O
+		 * b    0       I
+		 * c    0       I
+		 * d    0       I
+		 * e    1       O
+		 * f    1       O
+		 *
+		 * WM8775 ADC
+		 *
+		 * 1: TV Audio / FM Mono
+		 * 2: Line-In
+		 * 3: Line-In Expansion
+		 * 4: FM Stereo
+		 */
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0xc4bf,
+			/* 1: TV Audio / FM Mono */
+			.audioroute = 1,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0xc4bf,
+			/* 2: Line-In */
+			.audioroute = 2,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0xc4bf,
+			/* 2: Line-In */
+			.audioroute = 2,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0	= 0xc4bf,
+			/* 4: FM Stereo */
+			.audioroute = 8,
+		},
+		.mpeg           = CX88_MPEG_DVB,
+		.num_frontends	= 2,
+	},
+	[CX88_BOARD_HAUPPAUGE_HVR4000LITE] = {
+		.name           = "Hauppauge WinTV-HVR4000(Lite) DVB-S/S2",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_TEVII_S420] = {
+		.name           = "TeVii S420 DVB-S",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_TEVII_S460] = {
+		.name           = "TeVii S460 DVB-S/S2",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_TEVII_S464] = {
+		.name           = "TeVii S464 DVB-S/S2",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_OMICOM_SS4_PCI] = {
+		.name           = "Omicom SS4 DVB-S/S2 PCI",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_TBS_8910] = {
+		.name           = "TBS 8910 DVB-S",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_TBS_8920] = {
+		.name           = "TBS 8920 DVB-S/S2",
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+			.gpio0  = 0x8080,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_PROF_6200] = {
+		.name           = "Prof 6200 DVB-S",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_PROF_7300] = {
+		.name           = "PROF 7300 DVB-S/S2",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_SATTRADE_ST4200] = {
+		.name           = "SATTRADE ST4200 DVB-S/S2",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII] = {
+		.name           = "Terratec Cinergy HT PCI MKII",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_addr     = 0x61,
+		.radio_type     = UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = { {
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x004ff,
+			.gpio1  = 0x010ff,
+			.gpio2  = 0x00001,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x004fb,
+			.gpio1  = 0x010ef,
+			.audioroute = 1,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x004fb,
+			.gpio1  = 0x010ef,
+			.audioroute = 1,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x004ff,
+			.gpio1  = 0x010ff,
+			.gpio2  = 0x0ff,
+		},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_HAUPPAUGE_IRONLY] = {
+		.name           = "Hauppauge WinTV-IR Only",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+	},
+	[CX88_BOARD_WINFAST_DTV1800H] = {
+		.name           = "Leadtek WinFast DTV1800 Hybrid",
+		.tuner_type     = TUNER_XC2028,
+		.radio_type     = UNSET,
+		.tuner_addr     = 0x61,
+		.radio_addr     = ADDR_UNSET,
+		/*
+		 * GPIO setting
+		 *
+		 *  2: mute (0=off,1=on)
+		 * 12: tuner reset pin
+		 * 13: audio source (0=tuner audio,1=line in)
+		 * 14: FM (0=on,1=off ???)
+		 */
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x0400,       /* pin 2 = 0 */
+			.gpio1  = 0x6040,       /* pin 13 = 0, pin 14 = 1 */
+			.gpio2  = 0x0000,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0400,       /* pin 2 = 0 */
+			.gpio1  = 0x6060,       /* pin 13 = 1, pin 14 = 1 */
+			.gpio2  = 0x0000,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0400,       /* pin 2 = 0 */
+			.gpio1  = 0x6060,       /* pin 13 = 1, pin 14 = 1 */
+			.gpio2  = 0x0000,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x0400,       /* pin 2 = 0 */
+			.gpio1  = 0x6000,       /* pin 13 = 0, pin 14 = 0 */
+			.gpio2  = 0x0000,
+		},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_WINFAST_DTV1800H_XC4000] = {
+		.name		= "Leadtek WinFast DTV1800 H (XC4000)",
+		.tuner_type	= TUNER_XC4000,
+		.radio_type	= UNSET,
+		.tuner_addr	= 0x61,
+		.radio_addr	= ADDR_UNSET,
+		/*
+		 * GPIO setting
+		 *
+		 *  2: mute (0=off,1=on)
+		 * 12: tuner reset pin
+		 * 13: audio source (0=tuner audio,1=line in)
+		 * 14: FM (0=on,1=off ???)
+		 */
+		.input		= {{
+			.type	= CX88_VMUX_TELEVISION,
+			.vmux	= 0,
+			.gpio0	= 0x0400,	/* pin 2 = 0 */
+			.gpio1	= 0x6040,	/* pin 13 = 0, pin 14 = 1 */
+			.gpio2	= 0x0000,
+		}, {
+			.type	= CX88_VMUX_COMPOSITE1,
+			.vmux	= 1,
+			.gpio0	= 0x0400,	/* pin 2 = 0 */
+			.gpio1	= 0x6060,	/* pin 13 = 1, pin 14 = 1 */
+			.gpio2	= 0x0000,
+		}, {
+			.type	= CX88_VMUX_SVIDEO,
+			.vmux	= 2,
+			.gpio0	= 0x0400,	/* pin 2 = 0 */
+			.gpio1	= 0x6060,	/* pin 13 = 1, pin 14 = 1 */
+			.gpio2	= 0x0000,
+		}},
+		.radio = {
+			.type	= CX88_RADIO,
+			.gpio0	= 0x0400,	/* pin 2 = 0 */
+			.gpio1	= 0x6000,	/* pin 13 = 0, pin 14 = 0 */
+			.gpio2	= 0x0000,
+		},
+		.mpeg		= CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_WINFAST_DTV2000H_PLUS] = {
+		.name		= "Leadtek WinFast DTV2000 H PLUS",
+		.tuner_type	= TUNER_XC4000,
+		.radio_type	= UNSET,
+		.tuner_addr	= 0x61,
+		.radio_addr	= ADDR_UNSET,
+		/*
+		 * GPIO
+		 *   2: 1: mute audio
+		 *  12: 0: reset XC4000
+		 *  13: 1: audio input is line in (0: tuner)
+		 *  14: 0: FM radio
+		 *  16: 0: RF input is cable
+		 */
+		.input		= {{
+			.type	= CX88_VMUX_TELEVISION,
+			.vmux	= 0,
+			.gpio0	= 0x0403,
+			.gpio1	= 0xF0D7,
+			.gpio2	= 0x0101,
+			.gpio3	= 0x0000,
+		}, {
+			.type	= CX88_VMUX_CABLE,
+			.vmux	= 0,
+			.gpio0	= 0x0403,
+			.gpio1	= 0xF0D7,
+			.gpio2	= 0x0100,
+			.gpio3	= 0x0000,
+		}, {
+			.type	= CX88_VMUX_COMPOSITE1,
+			.vmux	= 1,
+			.gpio0	= 0x0403,	/* was 0x0407 */
+			.gpio1	= 0xF0F7,
+			.gpio2	= 0x0101,
+			.gpio3	= 0x0000,
+		}, {
+			.type	= CX88_VMUX_SVIDEO,
+			.vmux	= 2,
+			.gpio0	= 0x0403,	/* was 0x0407 */
+			.gpio1	= 0xF0F7,
+			.gpio2	= 0x0101,
+			.gpio3	= 0x0000,
+		}},
+		.radio = {
+			.type	= CX88_RADIO,
+			.gpio0	= 0x0403,
+			.gpio1	= 0xF097,
+			.gpio2	= 0x0100,
+			.gpio3	= 0x0000,
+		},
+		.mpeg		= CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_PROF_7301] = {
+		.name           = "Prof 7301 DVB-S/S2",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = { {
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_TWINHAN_VP1027_DVBS] = {
+		.name		= "Twinhan VP-1027 DVB-S",
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+		       .type   = CX88_VMUX_DVB,
+		       .vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+};
+
+/* ------------------------------------------------------------------ */
+/* PCI subsystem IDs                                                  */
+
+static const struct cx88_subid cx88_subids[] = {
+	{
+		.subvendor = 0x0070,
+		.subdevice = 0x3400,
+		.card      = CX88_BOARD_HAUPPAUGE,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x3401,
+		.card      = CX88_BOARD_HAUPPAUGE,
+	},{
+		.subvendor = 0x14c7,
+		.subdevice = 0x0106,
+		.card      = CX88_BOARD_GDI,
+	},{
+		.subvendor = 0x14c7,
+		.subdevice = 0x0107, /* with mpeg encoder */
+		.card      = CX88_BOARD_GDI,
+	},{
+		.subvendor = PCI_VENDOR_ID_ATI,
+		.subdevice = 0x00f8,
+		.card      = CX88_BOARD_ATI_WONDER_PRO,
+	}, {
+		.subvendor = PCI_VENDOR_ID_ATI,
+		.subdevice = 0x00f9,
+		.card      = CX88_BOARD_ATI_WONDER_PRO,
+	}, {
+		.subvendor = 0x107d,
+		.subdevice = 0x6611,
+		.card      = CX88_BOARD_WINFAST2000XP_EXPERT,
+	},{
+		.subvendor = 0x107d,
+		.subdevice = 0x6613,	/* NTSC */
+		.card      = CX88_BOARD_WINFAST2000XP_EXPERT,
+	},{
+		.subvendor = 0x107d,
+		.subdevice = 0x6620,
+		.card      = CX88_BOARD_WINFAST_DV2000,
+	},{
+		.subvendor = 0x107d,
+		.subdevice = 0x663b,
+		.card      = CX88_BOARD_LEADTEK_PVR2000,
+	},{
+		.subvendor = 0x107d,
+		.subdevice = 0x663c,
+		.card      = CX88_BOARD_LEADTEK_PVR2000,
+	},{
+		.subvendor = 0x1461,
+		.subdevice = 0x000b,
+		.card      = CX88_BOARD_AVERTV_STUDIO_303,
+	},{
+		.subvendor = 0x1462,
+		.subdevice = 0x8606,
+		.card      = CX88_BOARD_MSI_TVANYWHERE_MASTER,
+	},{
+		.subvendor = 0x10fc,
+		.subdevice = 0xd003,
+		.card      = CX88_BOARD_IODATA_GVVCP3PCI,
+	},{
+		.subvendor = 0x1043,
+		.subdevice = 0x4823,  /* with mpeg encoder */
+		.card      = CX88_BOARD_ASUS_PVR_416,
+	},{
+		.subvendor = 0x17de,
+		.subdevice = 0x08a6,
+		.card      = CX88_BOARD_KWORLD_DVB_T,
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xd810,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xd820,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T,
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xdb00,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9002,
+		.card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
+	},{
+		.subvendor = 0x14f1,
+		.subdevice = 0x0187,
+		.card      = CX88_BOARD_CONEXANT_DVB_T1,
+	},{
+		.subvendor = 0x1540,
+		.subdevice = 0x2580,
+		.card      = CX88_BOARD_PROVIDEO_PV259,
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xdb10,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
+	},{
+		.subvendor = 0x1554,
+		.subdevice = 0x4811,
+		.card      = CX88_BOARD_PIXELVIEW,
+	},{
+		.subvendor = 0x7063,
+		.subdevice = 0x3000, /* HD-3000 card */
+		.card      = CX88_BOARD_PCHDTV_HD3000,
+	},{
+		.subvendor = 0x17de,
+		.subdevice = 0xa8a6,
+		.card      = CX88_BOARD_DNTV_LIVE_DVB_T,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x2801,
+		.card      = CX88_BOARD_HAUPPAUGE_ROSLYN,
+	},{
+		.subvendor = 0x14f1,
+		.subdevice = 0x0342,
+		.card      = CX88_BOARD_DIGITALLOGIC_MEC,
+	},{
+		.subvendor = 0x10fc,
+		.subdevice = 0xd035,
+		.card      = CX88_BOARD_IODATA_GVBCTV7E,
+	},{
+		.subvendor = 0x1421,
+		.subdevice = 0x0334,
+		.card      = CX88_BOARD_ADSTECH_DVB_T_PCI,
+	},{
+		.subvendor = 0x153b,
+		.subdevice = 0x1166,
+		.card      = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1,
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xd500,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD,
+	},{
+		.subvendor = 0x1461,
+		.subdevice = 0x8011,
+		.card      = CX88_BOARD_AVERMEDIA_ULTRATV_MC_550,
+	},{
+		.subvendor = PCI_VENDOR_ID_ATI,
+		.subdevice = 0xa101,
+		.card      = CX88_BOARD_ATI_HDTVWONDER,
+	},{
+		.subvendor = 0x107d,
+		.subdevice = 0x665f,
+		.card      = CX88_BOARD_WINFAST_DTV1000,
+	},{
+		.subvendor = 0x1461,
+		.subdevice = 0x000a,
+		.card      = CX88_BOARD_AVERTV_303,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9200,
+		.card      = CX88_BOARD_HAUPPAUGE_NOVASE2_S1,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9201,
+		.card      = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9202,
+		.card      = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
+	},{
+		.subvendor = 0x17de,
+		.subdevice = 0x08b2,
+		.card      = CX88_BOARD_KWORLD_DVBS_100,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9400,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR1100,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9402,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR1100,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9800,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR1100LP,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9802,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR1100LP,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9001,
+		.card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
+	},{
+		.subvendor = 0x1822,
+		.subdevice = 0x0025,
+		.card      = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
+	},{
+		.subvendor = 0x17de,
+		.subdevice = 0x08a1,
+		.card      = CX88_BOARD_KWORLD_DVB_T_CX22702,
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xdb50,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL,
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xdb54,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL,
+		/* Re-branded DViCO: DigitalNow DVB-T Dual */
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xdb11,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
+		/* Re-branded DViCO: UltraView DVB-T Plus */
+	}, {
+		.subvendor = 0x18ac,
+		.subdevice = 0xdb30,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO,
+	}, {
+		.subvendor = 0x17de,
+		.subdevice = 0x0840,
+		.card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
+	},{
+		.subvendor = 0x1421,
+		.subdevice = 0x0305,
+		.card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xdb40,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xdb44,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
+	},{
+		.subvendor = 0x7063,
+		.subdevice = 0x5500,
+		.card      = CX88_BOARD_PCHDTV_HD5500,
+	},{
+		.subvendor = 0x17de,
+		.subdevice = 0x0841,
+		.card      = CX88_BOARD_KWORLD_MCE200_DELUXE,
+	},{
+		.subvendor = 0x1822,
+		.subdevice = 0x0019,
+		.card      = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
+	},{
+		.subvendor = 0x1554,
+		.subdevice = 0x4813,
+		.card      = CX88_BOARD_PIXELVIEW_PLAYTV_P7000,
+	},{
+		.subvendor = 0x14f1,
+		.subdevice = 0x0842,
+		.card      = CX88_BOARD_NPGTECH_REALTV_TOP10FM,
+	},{
+		.subvendor = 0x107d,
+		.subdevice = 0x665e,
+		.card      = CX88_BOARD_WINFAST_DTV2000H,
+	},{
+		.subvendor = 0x107d,
+		.subdevice = 0x6f2b,
+		.card      = CX88_BOARD_WINFAST_DTV2000H_J,
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
+	},{
+		.subvendor = 0x14f1,
+		.subdevice = 0x0084,
+		.card      = CX88_BOARD_GENIATECH_DVBS,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x1404,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR3000,
+	}, {
+		.subvendor = 0x18ac,
+		.subdevice = 0xdc00,
+		.card      = CX88_BOARD_SAMSUNG_SMT_7020,
+	}, {
+		.subvendor = 0x18ac,
+		.subdevice = 0xdccd,
+		.card      = CX88_BOARD_SAMSUNG_SMT_7020,
+	},{
+		.subvendor = 0x1461,
+		.subdevice = 0xc111, /* AverMedia M150-D */
+		/* This board is known to work with the ASUS PVR416 config */
+		.card      = CX88_BOARD_ASUS_PVR_416,
+	},{
+		.subvendor = 0xc180,
+		.subdevice = 0xc980,
+		.card      = CX88_BOARD_TE_DTV_250_OEM_SWANN,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9600,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR1300,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9601,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR1300,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9602,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR1300,
+	},{
+		.subvendor = 0x107d,
+		.subdevice = 0x6632,
+		.card      = CX88_BOARD_LEADTEK_PVR2000,
+	},{
+		.subvendor = 0x12ab,
+		.subdevice = 0x2300, /* Club3D Zap TV2100 */
+		.card      = CX88_BOARD_KWORLD_DVB_T_CX22702,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9000,
+		.card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x1400,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR3000,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x1401,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR3000,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x1402,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR3000,
+	},{
+		.subvendor = 0x1421,
+		.subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */
+		.card      = CX88_BOARD_KWORLD_DVBS_100,
+	},{
+		.subvendor = 0x1421,
+		.subdevice = 0x0390,
+		.card      = CX88_BOARD_ADSTECH_PTV_390,
+	},{
+		.subvendor = 0x11bd,
+		.subdevice = 0x0051,
+		.card      = CX88_BOARD_PINNACLE_PCTV_HD_800i,
+	}, {
+		.subvendor = 0x18ac,
+		.subdevice = 0xd530,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO,
+	}, {
+		.subvendor = 0x12ab,
+		.subdevice = 0x1788,
+		.card      = CX88_BOARD_PINNACLE_HYBRID_PCTV,
+	}, {
+		.subvendor = 0x14f1,
+		.subdevice = 0xea3d,
+		.card      = CX88_BOARD_POWERCOLOR_REAL_ANGEL,
+	}, {
+		.subvendor = 0x107d,
+		.subdevice = 0x6f18,
+		.card      = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL,
+	}, {
+		.subvendor = 0x14f1,
+		.subdevice = 0x8852,
+		.card      = CX88_BOARD_GENIATECH_X8000_MT,
+	}, {
+		.subvendor = 0x18ac,
+		.subdevice = 0xd610,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD,
+	}, {
+		.subvendor = 0x1554,
+		.subdevice = 0x4935,
+		.card      = CX88_BOARD_PROLINK_PV_8000GT,
+	}, {
+		.subvendor = 0x1554,
+		.subdevice = 0x4976,
+		.card      = CX88_BOARD_PROLINK_PV_GLOBAL_XTREME,
+	}, {
+		.subvendor = 0x17de,
+		.subdevice = 0x08c1,
+		.card      = CX88_BOARD_KWORLD_ATSC_120,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x6900,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR4000,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x6904,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR4000,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x6902,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR4000,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x6905,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR4000LITE,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x6906,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR4000LITE,
+	}, {
+		.subvendor = 0xd420,
+		.subdevice = 0x9022,
+		.card      = CX88_BOARD_TEVII_S420,
+	}, {
+		.subvendor = 0xd460,
+		.subdevice = 0x9022,
+		.card      = CX88_BOARD_TEVII_S460,
+	}, {
+		.subvendor = 0xd464,
+		.subdevice = 0x9022,
+		.card      = CX88_BOARD_TEVII_S464,
+	}, {
+		.subvendor = 0xA044,
+		.subdevice = 0x2011,
+		.card      = CX88_BOARD_OMICOM_SS4_PCI,
+	}, {
+		.subvendor = 0x8910,
+		.subdevice = 0x8888,
+		.card      = CX88_BOARD_TBS_8910,
+	}, {
+		.subvendor = 0x8920,
+		.subdevice = 0x8888,
+		.card      = CX88_BOARD_TBS_8920,
+	}, {
+		.subvendor = 0xb022,
+		.subdevice = 0x3022,
+		.card      = CX88_BOARD_PROF_6200,
+	}, {
+		.subvendor = 0xB033,
+		.subdevice = 0x3033,
+		.card      = CX88_BOARD_PROF_7300,
+	}, {
+		.subvendor = 0xb200,
+		.subdevice = 0x4200,
+		.card      = CX88_BOARD_SATTRADE_ST4200,
+	}, {
+		.subvendor = 0x153b,
+		.subdevice = 0x1177,
+		.card      = CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x9290,
+		.card      = CX88_BOARD_HAUPPAUGE_IRONLY,
+	}, {
+		.subvendor = 0x107d,
+		.subdevice = 0x6654,
+		.card      = CX88_BOARD_WINFAST_DTV1800H,
+	}, {
+		/* WinFast DTV1800 H with XC4000 tuner */
+		.subvendor = 0x107d,
+		.subdevice = 0x6f38,
+		.card      = CX88_BOARD_WINFAST_DTV1800H_XC4000,
+	}, {
+		.subvendor = 0x107d,
+		.subdevice = 0x6f42,
+		.card      = CX88_BOARD_WINFAST_DTV2000H_PLUS,
+	}, {
+		/* PVR2000 PAL Model [107d:6630] */
+		.subvendor = 0x107d,
+		.subdevice = 0x6630,
+		.card      = CX88_BOARD_LEADTEK_PVR2000,
+	}, {
+		/* PVR2000 PAL Model [107d:6638] */
+		.subvendor = 0x107d,
+		.subdevice = 0x6638,
+		.card      = CX88_BOARD_LEADTEK_PVR2000,
+	}, {
+		/* PVR2000 NTSC Model [107d:6631] */
+		.subvendor = 0x107d,
+		.subdevice = 0x6631,
+		.card      = CX88_BOARD_LEADTEK_PVR2000,
+	}, {
+		/* PVR2000 NTSC Model [107d:6637] */
+		.subvendor = 0x107d,
+		.subdevice = 0x6637,
+		.card      = CX88_BOARD_LEADTEK_PVR2000,
+	}, {
+		/* PVR2000 NTSC Model [107d:663d] */
+		.subvendor = 0x107d,
+		.subdevice = 0x663d,
+		.card      = CX88_BOARD_LEADTEK_PVR2000,
+	}, {
+		/* DV2000 NTSC Model [107d:6621] */
+		.subvendor = 0x107d,
+		.subdevice = 0x6621,
+		.card      = CX88_BOARD_WINFAST_DV2000,
+	}, {
+		/* TV2000 XP Global [107d:6618]  */
+		.subvendor = 0x107d,
+		.subdevice = 0x6618,
+		.card      = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL,
+	}, {
+		/* TV2000 XP Global [107d:6618] */
+		.subvendor = 0x107d,
+		.subdevice = 0x6619,
+		.card      = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL,
+	}, {
+		/* WinFast TV2000 XP Global with XC4000 tuner */
+		.subvendor = 0x107d,
+		.subdevice = 0x6f36,
+		.card      = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36,
+	}, {
+		/* WinFast TV2000 XP Global with XC4000 tuner and different GPIOs */
+		.subvendor = 0x107d,
+		.subdevice = 0x6f43,
+		.card      = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43,
+	}, {
+		.subvendor = 0xb034,
+		.subdevice = 0x3034,
+		.card      = CX88_BOARD_PROF_7301,
+	}, {
+		.subvendor = 0x1822,
+		.subdevice = 0x0023,
+		.card      = CX88_BOARD_TWINHAN_VP1027_DVBS,
+	},
+};
+
+/* ----------------------------------------------------------------------- */
+/* some leadtek specific stuff                                             */
+
+static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data)
+{
+	if (eeprom_data[4] != 0x7d ||
+	    eeprom_data[5] != 0x10 ||
+	    eeprom_data[7] != 0x66) {
+		warn_printk(core, "Leadtek eeprom invalid.\n");
+		return;
+	}
+
+	/* Terry Wu <terrywu2009@gmail.com> */
+	switch (eeprom_data[6]) {
+	case 0x13: /* SSID 6613 for TV2000 XP Expert NTSC Model */
+	case 0x21: /* SSID 6621 for DV2000 NTSC Model */
+	case 0x31: /* SSID 6631 for PVR2000 NTSC Model */
+	case 0x37: /* SSID 6637 for PVR2000 NTSC Model */
+	case 0x3d: /* SSID 6637 for PVR2000 NTSC Model */
+		core->board.tuner_type = TUNER_PHILIPS_FM1236_MK3;
+		break;
+	default:
+		core->board.tuner_type = TUNER_PHILIPS_FM1216ME_MK3;
+		break;
+	}
+
+	info_printk(core, "Leadtek Winfast 2000XP Expert config: "
+		    "tuner=%d, eeprom[0]=0x%02x\n",
+		    core->board.tuner_type, eeprom_data[0]);
+}
+
+static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
+{
+	struct tveeprom tv;
+
+	tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data);
+	core->board.tuner_type = tv.tuner_type;
+	core->tuner_formats = tv.tuner_formats;
+	core->board.radio.type = tv.has_radio ? CX88_RADIO : 0;
+
+	/* Make sure we support the board model */
+	switch (tv.model)
+	{
+	case 14009: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in) */
+	case 14019: /* WinTV-HVR3000 (Retail, IR Blaster, b/panel video, 3.5mm audio in) */
+	case 14029: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge) */
+	case 14109: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - low profile) */
+	case 14129: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge - LP) */
+	case 14559: /* WinTV-HVR3000 (OEM, no IR, b/panel video, 3.5mm audio in) */
+	case 14569: /* WinTV-HVR3000 (OEM, no IR, no back panel video) */
+	case 14659: /* WinTV-HVR3000 (OEM, no IR, b/panel video, RCA audio in - Low profile) */
+	case 14669: /* WinTV-HVR3000 (OEM, no IR, no b/panel video - Low profile) */
+	case 28552: /* WinTV-PVR 'Roslyn' (No IR) */
+	case 34519: /* WinTV-PCI-FM */
+	case 69009:
+		/* WinTV-HVR4000 (DVBS/S2/T, Video and IR, back panel inputs) */
+	case 69100: /* WinTV-HVR4000LITE (DVBS/S2, IR) */
+	case 69500: /* WinTV-HVR4000LITE (DVBS/S2, No IR) */
+	case 69559:
+		/* WinTV-HVR4000 (DVBS/S2/T, Video no IR, back panel inputs) */
+	case 69569: /* WinTV-HVR4000 (DVBS/S2/T, Video no IR) */
+	case 90002: /* Nova-T-PCI (9002) */
+	case 92001: /* Nova-S-Plus (Video and IR) */
+	case 92002: /* Nova-S-Plus (Video and IR) */
+	case 90003: /* Nova-T-PCI (9002 No RF out) */
+	case 90500: /* Nova-T-PCI (oem) */
+	case 90501: /* Nova-T-PCI (oem/IR) */
+	case 92000: /* Nova-SE2 (OEM, No Video or IR) */
+	case 92900: /* WinTV-IROnly (No analog or digital Video inputs) */
+	case 94009: /* WinTV-HVR1100 (Video and IR Retail) */
+	case 94501: /* WinTV-HVR1100 (Video and IR OEM) */
+	case 96009: /* WinTV-HVR1300 (PAL Video, MPEG Video and IR RX) */
+	case 96019: /* WinTV-HVR1300 (PAL Video, MPEG Video and IR RX/TX) */
+	case 96559: /* WinTV-HVR1300 (PAL Video, MPEG Video no IR) */
+	case 96569: /* WinTV-HVR1300 () */
+	case 96659: /* WinTV-HVR1300 () */
+	case 98559: /* WinTV-HVR1100LP (Video no IR, Retail - Low Profile) */
+		/* known */
+		break;
+	case CX88_BOARD_SAMSUNG_SMT_7020:
+		cx_set(MO_GP0_IO, 0x008989FF);
+		break;
+	default:
+		warn_printk(core, "warning: unknown hauppauge model #%d\n",
+			    tv.model);
+		break;
+	}
+
+	info_printk(core, "hauppauge eeprom: model=%d\n", tv.model);
+}
+
+/* ----------------------------------------------------------------------- */
+/* some GDI (was: Modular Technology) specific stuff                       */
+
+static const struct {
+	int  id;
+	int  fm;
+	const char *name;
+} gdi_tuner[] = {
+	[ 0x01 ] = { .id   = TUNER_ABSENT,
+		     .name = "NTSC_M" },
+	[ 0x02 ] = { .id   = TUNER_ABSENT,
+		     .name = "PAL_B" },
+	[ 0x03 ] = { .id   = TUNER_ABSENT,
+		     .name = "PAL_I" },
+	[ 0x04 ] = { .id   = TUNER_ABSENT,
+		     .name = "PAL_D" },
+	[ 0x05 ] = { .id   = TUNER_ABSENT,
+		     .name = "SECAM" },
+
+	[ 0x10 ] = { .id   = TUNER_ABSENT,
+		     .fm   = 1,
+		     .name = "TEMIC_4049" },
+	[ 0x11 ] = { .id   = TUNER_TEMIC_4136FY5,
+		     .name = "TEMIC_4136" },
+	[ 0x12 ] = { .id   = TUNER_ABSENT,
+		     .name = "TEMIC_4146" },
+
+	[ 0x20 ] = { .id   = TUNER_PHILIPS_FQ1216ME,
+		     .fm   = 1,
+		     .name = "PHILIPS_FQ1216_MK3" },
+	[ 0x21 ] = { .id   = TUNER_ABSENT, .fm = 1,
+		     .name = "PHILIPS_FQ1236_MK3" },
+	[ 0x22 ] = { .id   = TUNER_ABSENT,
+		     .name = "PHILIPS_FI1236_MK3" },
+	[ 0x23 ] = { .id   = TUNER_ABSENT,
+		     .name = "PHILIPS_FI1216_MK3" },
+};
+
+static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data)
+{
+	const char *name = (eeprom_data[0x0d] < ARRAY_SIZE(gdi_tuner))
+		? gdi_tuner[eeprom_data[0x0d]].name : NULL;
+
+	info_printk(core, "GDI: tuner=%s\n", name ? name : "unknown");
+	if (NULL == name)
+		return;
+	core->board.tuner_type = gdi_tuner[eeprom_data[0x0d]].id;
+	core->board.radio.type = gdi_tuner[eeprom_data[0x0d]].fm ?
+		CX88_RADIO : 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* some Divco specific stuff                                           */
+static int cx88_dvico_xc2028_callback(struct cx88_core *core,
+				      int command, int arg)
+{
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		switch (core->boardnr) {
+		case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
+			/* GPIO-4 xc3028 tuner */
+
+			cx_set(MO_GP0_IO, 0x00001000);
+			cx_clear(MO_GP0_IO, 0x00000010);
+			msleep(100);
+			cx_set(MO_GP0_IO, 0x00000010);
+			msleep(100);
+			break;
+		default:
+			cx_write(MO_GP0_IO, 0x101000);
+			mdelay(5);
+			cx_set(MO_GP0_IO, 0x101010);
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+/* ----------------------------------------------------------------------- */
+/* some Geniatech specific stuff                                           */
+
+static int cx88_xc3028_geniatech_tuner_callback(struct cx88_core *core,
+						int command, int mode)
+{
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		switch (INPUT(core->input).type) {
+		case CX88_RADIO:
+			break;
+		case CX88_VMUX_DVB:
+			cx_write(MO_GP1_IO, 0x030302);
+			mdelay(50);
+			break;
+		default:
+			cx_write(MO_GP1_IO, 0x030301);
+			mdelay(50);
+		}
+		cx_write(MO_GP1_IO, 0x101010);
+		mdelay(50);
+		cx_write(MO_GP1_IO, 0x101000);
+		mdelay(50);
+		cx_write(MO_GP1_IO, 0x101010);
+		mdelay(50);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int cx88_xc3028_winfast1800h_callback(struct cx88_core *core,
+					     int command, int arg)
+{
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		/* GPIO 12 (xc3028 tuner reset) */
+		cx_set(MO_GP1_IO, 0x1010);
+		mdelay(50);
+		cx_clear(MO_GP1_IO, 0x10);
+		mdelay(50);
+		cx_set(MO_GP1_IO, 0x10);
+		mdelay(50);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int cx88_xc4000_winfast2000h_plus_callback(struct cx88_core *core,
+						  int command, int arg)
+{
+	switch (command) {
+	case XC4000_TUNER_RESET:
+		/* GPIO 12 (xc4000 tuner reset) */
+		cx_set(MO_GP1_IO, 0x1010);
+		mdelay(50);
+		cx_clear(MO_GP1_IO, 0x10);
+		mdelay(75);
+		cx_set(MO_GP1_IO, 0x10);
+		mdelay(75);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+/* ------------------------------------------------------------------- */
+/* some Divco specific stuff                                           */
+static int cx88_pv_8000gt_callback(struct cx88_core *core,
+				   int command, int arg)
+{
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		cx_write(MO_GP2_IO, 0xcf7);
+		mdelay(50);
+		cx_write(MO_GP2_IO, 0xef5);
+		mdelay(50);
+		cx_write(MO_GP2_IO, 0xcf7);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+/* some DViCO specific stuff                                               */
+
+static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core)
+{
+	struct i2c_msg msg = { .addr = 0x45, .flags = 0 };
+	int i, err;
+	static u8 init_bufs[13][5] = {
+		{ 0x10, 0x00, 0x20, 0x01, 0x03 },
+		{ 0x10, 0x10, 0x01, 0x00, 0x21 },
+		{ 0x10, 0x10, 0x10, 0x00, 0xCA },
+		{ 0x10, 0x10, 0x12, 0x00, 0x08 },
+		{ 0x10, 0x10, 0x13, 0x00, 0x0A },
+		{ 0x10, 0x10, 0x16, 0x01, 0xC0 },
+		{ 0x10, 0x10, 0x22, 0x01, 0x3D },
+		{ 0x10, 0x10, 0x73, 0x01, 0x2E },
+		{ 0x10, 0x10, 0x72, 0x00, 0xC5 },
+		{ 0x10, 0x10, 0x71, 0x01, 0x97 },
+		{ 0x10, 0x10, 0x70, 0x00, 0x0F },
+		{ 0x10, 0x10, 0xB0, 0x00, 0x01 },
+		{ 0x03, 0x0C },
+	};
+
+	for (i = 0; i < ARRAY_SIZE(init_bufs); i++) {
+		msg.buf = init_bufs[i];
+		msg.len = (i != 12 ? 5 : 2);
+		err = i2c_transfer(&core->i2c_adap, &msg, 1);
+		if (err != 1) {
+			warn_printk(core, "dvico_fusionhdtv_hybrid_init buf %d "
+					  "failed (err = %d)!\n", i, err);
+			return;
+		}
+	}
+}
+
+static int cx88_xc2028_tuner_callback(struct cx88_core *core,
+				      int command, int arg)
+{
+	/* Board-specific callbacks */
+	switch (core->boardnr) {
+	case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
+	case CX88_BOARD_GENIATECH_X8000_MT:
+	case CX88_BOARD_KWORLD_ATSC_120:
+		return cx88_xc3028_geniatech_tuner_callback(core,
+							command, arg);
+	case CX88_BOARD_PROLINK_PV_8000GT:
+	case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
+		return cx88_pv_8000gt_callback(core, command, arg);
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+	case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
+		return cx88_dvico_xc2028_callback(core, command, arg);
+	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
+	case CX88_BOARD_WINFAST_DTV1800H:
+		return cx88_xc3028_winfast1800h_callback(core, command, arg);
+	}
+
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		switch (INPUT(core->input).type) {
+		case CX88_RADIO:
+			info_printk(core, "setting GPIO to radio!\n");
+			cx_write(MO_GP0_IO, 0x4ff);
+			mdelay(250);
+			cx_write(MO_GP2_IO, 0xff);
+			mdelay(250);
+			break;
+		case CX88_VMUX_DVB:	/* Digital TV*/
+		default:		/* Analog TV */
+			info_printk(core, "setting GPIO to TV!\n");
+			break;
+		}
+		cx_write(MO_GP1_IO, 0x101010);
+		mdelay(250);
+		cx_write(MO_GP1_IO, 0x101000);
+		mdelay(250);
+		cx_write(MO_GP1_IO, 0x101010);
+		mdelay(250);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int cx88_xc4000_tuner_callback(struct cx88_core *core,
+				      int command, int arg)
+{
+	/* Board-specific callbacks */
+	switch (core->boardnr) {
+	case CX88_BOARD_WINFAST_DTV1800H_XC4000:
+	case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36:
+	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43:
+		return cx88_xc4000_winfast2000h_plus_callback(core,
+							      command, arg);
+	}
+	return -EINVAL;
+}
+
+/* ----------------------------------------------------------------------- */
+/* Tuner callback function. Currently only needed for the Pinnacle 	   *
+ * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both	   *
+ * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c)    */
+
+static int cx88_xc5000_tuner_callback(struct cx88_core *core,
+				      int command, int arg)
+{
+	switch (core->boardnr) {
+	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
+		if (command == 0) { /* This is the reset command from xc5000 */
+
+			/* djh - According to the engineer at PCTV Systems,
+			   the xc5000 reset pin is supposed to be on GPIO12.
+			   However, despite three nights of effort, pulling
+			   that GPIO low didn't reset the xc5000.  While
+			   pulling MO_SRST_IO low does reset the xc5000, this
+			   also resets in the s5h1409 being reset as well.
+			   This causes tuning to always fail since the internal
+			   state of the s5h1409 does not match the driver's
+			   state.  Given that the only two conditions in which
+			   the driver performs a reset is during firmware load
+			   and powering down the chip, I am taking out the
+			   reset.  We know that the chip is being reset
+			   when the cx88 comes online, and not being able to
+			   do power management for this board is worse than
+			   not having any tuning at all. */
+			return 0;
+		} else {
+			err_printk(core, "xc5000: unknown tuner "
+				   "callback command.\n");
+			return -EINVAL;
+		}
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
+		if (command == 0) { /* This is the reset command from xc5000 */
+			cx_clear(MO_GP0_IO, 0x00000010);
+			msleep(10);
+			cx_set(MO_GP0_IO, 0x00000010);
+			return 0;
+		} else {
+			printk(KERN_ERR
+				"xc5000: unknown tuner callback command.\n");
+			return -EINVAL;
+		}
+		break;
+	}
+	return 0; /* Should never be here */
+}
+
+int cx88_tuner_callback(void *priv, int component, int command, int arg)
+{
+	struct i2c_algo_bit_data *i2c_algo = priv;
+	struct cx88_core *core;
+
+	if (!i2c_algo) {
+		printk(KERN_ERR "cx88: Error - i2c private data undefined.\n");
+		return -EINVAL;
+	}
+
+	core = i2c_algo->data;
+
+	if (!core) {
+		printk(KERN_ERR "cx88: Error - device struct undefined.\n");
+		return -EINVAL;
+	}
+
+	if (component != DVB_FRONTEND_COMPONENT_TUNER)
+		return -EINVAL;
+
+	switch (core->board.tuner_type) {
+		case TUNER_XC2028:
+			info_printk(core, "Calling XC2028/3028 callback\n");
+			return cx88_xc2028_tuner_callback(core, command, arg);
+		case TUNER_XC4000:
+			info_printk(core, "Calling XC4000 callback\n");
+			return cx88_xc4000_tuner_callback(core, command, arg);
+		case TUNER_XC5000:
+			info_printk(core, "Calling XC5000 callback\n");
+			return cx88_xc5000_tuner_callback(core, command, arg);
+	}
+	err_printk(core, "Error: Calling callback for tuner %d\n",
+		   core->board.tuner_type);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(cx88_tuner_callback);
+
+/* ----------------------------------------------------------------------- */
+
+static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
+{
+	int i;
+
+	if (0 == pci->subsystem_vendor &&
+	    0 == pci->subsystem_device) {
+		printk(KERN_ERR
+		       "%s: Your board has no valid PCI Subsystem ID and thus can't\n"
+		       "%s: be autodetected.  Please pass card=<n> insmod option to\n"
+		       "%s: workaround that.  Redirect complaints to the vendor of\n"
+		       "%s: the TV card.  Best regards,\n"
+		       "%s:         -- tux\n",
+		       core->name,core->name,core->name,core->name,core->name);
+	} else {
+		printk(KERN_ERR
+		       "%s: Your board isn't known (yet) to the driver.  You can\n"
+		       "%s: try to pick one of the existing card configs via\n"
+		       "%s: card=<n> insmod option.  Updating to the latest\n"
+		       "%s: version might help as well.\n",
+		       core->name,core->name,core->name,core->name);
+	}
+	err_printk(core, "Here is a list of valid choices for the card=<n> "
+		   "insmod option:\n");
+	for (i = 0; i < ARRAY_SIZE(cx88_boards); i++)
+		printk(KERN_ERR "%s:    card=%d -> %s\n",
+		       core->name, i, cx88_boards[i].name);
+}
+
+static void cx88_card_setup_pre_i2c(struct cx88_core *core)
+{
+	switch (core->boardnr) {
+	case CX88_BOARD_HAUPPAUGE_HVR1300:
+		/*
+		 * Bring the 702 demod up before i2c scanning/attach or devices are hidden
+		 * We leave here with the 702 on the bus
+		 *
+		 * "reset the IR receiver on GPIO[3]"
+		 * Reported by Mike Crash <mike AT mikecrash.com>
+		 */
+		cx_write(MO_GP0_IO, 0x0000ef88);
+		udelay(1000);
+		cx_clear(MO_GP0_IO, 0x00000088);
+		udelay(50);
+		cx_set(MO_GP0_IO, 0x00000088); /* 702 out of reset */
+		udelay(1000);
+		break;
+
+	case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
+	case CX88_BOARD_PROLINK_PV_8000GT:
+		cx_write(MO_GP2_IO, 0xcf7);
+		mdelay(50);
+		cx_write(MO_GP2_IO, 0xef5);
+		mdelay(50);
+		cx_write(MO_GP2_IO, 0xcf7);
+		msleep(10);
+		break;
+
+	case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
+		/* Enable the xc5000 tuner */
+		cx_set(MO_GP0_IO, 0x00001010);
+		break;
+
+	case CX88_BOARD_WINFAST_DTV2000H_J:
+	case CX88_BOARD_HAUPPAUGE_HVR3000:
+	case CX88_BOARD_HAUPPAUGE_HVR4000:
+		/* Init GPIO */
+		cx_write(MO_GP0_IO, core->board.input[0].gpio0);
+		udelay(1000);
+		cx_clear(MO_GP0_IO, 0x00000080);
+		udelay(50);
+		cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */
+		udelay(1000);
+		break;
+
+	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
+	case CX88_BOARD_WINFAST_DTV1800H:
+		cx88_xc3028_winfast1800h_callback(core, XC2028_TUNER_RESET, 0);
+		break;
+
+	case CX88_BOARD_WINFAST_DTV1800H_XC4000:
+	case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36:
+	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43:
+		cx88_xc4000_winfast2000h_plus_callback(core,
+						       XC4000_TUNER_RESET, 0);
+		break;
+
+	case CX88_BOARD_TWINHAN_VP1027_DVBS:
+		cx_write(MO_GP0_IO, 0x00003230);
+		cx_write(MO_GP0_IO, 0x00003210);
+		msleep(1);
+		cx_write(MO_GP0_IO, 0x00001230);
+		break;
+	}
+}
+
+/*
+ * Sets board-dependent xc3028 configuration
+ */
+void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl)
+{
+	memset(ctl, 0, sizeof(*ctl));
+
+	ctl->fname   = XC2028_DEFAULT_FIRMWARE;
+	ctl->max_len = 64;
+
+	switch (core->boardnr) {
+	case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
+		/* Now works with firmware version 2.7 */
+		if (core->i2c_algo.udelay < 16)
+			core->i2c_algo.udelay = 16;
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+	case CX88_BOARD_WINFAST_DTV1800H:
+		ctl->demod = XC3028_FE_ZARLINK456;
+		break;
+	case CX88_BOARD_KWORLD_ATSC_120:
+	case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
+		ctl->demod = XC3028_FE_OREN538;
+		break;
+	case CX88_BOARD_GENIATECH_X8000_MT:
+		/* FIXME: For this board, the xc3028 never recovers after being
+		   powered down (the reset GPIO probably is not set properly).
+		   We don't have access to the hardware so we cannot determine
+		   which GPIO is used for xc3028, so just disable power xc3028
+		   power management for now */
+		ctl->disable_power_mgmt = 1;
+		break;
+	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
+	case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
+	case CX88_BOARD_PROLINK_PV_8000GT:
+		/*
+		 * Those boards uses non-MTS firmware
+		 */
+		break;
+	case CX88_BOARD_PINNACLE_HYBRID_PCTV:
+	case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII:
+		ctl->demod = XC3028_FE_ZARLINK456;
+		ctl->mts = 1;
+		break;
+	default:
+		ctl->demod = XC3028_FE_OREN538;
+		ctl->mts = 1;
+	}
+}
+EXPORT_SYMBOL_GPL(cx88_setup_xc3028);
+
+static void cx88_card_setup(struct cx88_core *core)
+{
+	static u8 eeprom[256];
+	struct tuner_setup tun_setup;
+	unsigned int mode_mask = T_RADIO | T_ANALOG_TV;
+
+	memset(&tun_setup, 0, sizeof(tun_setup));
+
+	if (0 == core->i2c_rc) {
+		core->i2c_client.addr = 0xa0 >> 1;
+		tveeprom_read(&core->i2c_client, eeprom, sizeof(eeprom));
+	}
+
+	switch (core->boardnr) {
+	case CX88_BOARD_HAUPPAUGE:
+	case CX88_BOARD_HAUPPAUGE_ROSLYN:
+		if (0 == core->i2c_rc)
+			hauppauge_eeprom(core, eeprom+8);
+		break;
+	case CX88_BOARD_GDI:
+		if (0 == core->i2c_rc)
+			gdi_eeprom(core, eeprom);
+		break;
+	case CX88_BOARD_LEADTEK_PVR2000:
+	case CX88_BOARD_WINFAST_DV2000:
+	case CX88_BOARD_WINFAST2000XP_EXPERT:
+		if (0 == core->i2c_rc)
+			leadtek_eeprom(core, eeprom);
+		break;
+	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+	case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+	case CX88_BOARD_HAUPPAUGE_DVB_T1:
+	case CX88_BOARD_HAUPPAUGE_HVR1100:
+	case CX88_BOARD_HAUPPAUGE_HVR1100LP:
+	case CX88_BOARD_HAUPPAUGE_HVR3000:
+	case CX88_BOARD_HAUPPAUGE_HVR1300:
+	case CX88_BOARD_HAUPPAUGE_HVR4000:
+	case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+	case CX88_BOARD_HAUPPAUGE_IRONLY:
+		if (0 == core->i2c_rc)
+			hauppauge_eeprom(core, eeprom);
+		break;
+	case CX88_BOARD_KWORLD_DVBS_100:
+		cx_write(MO_GP0_IO, 0x000007f8);
+		cx_write(MO_GP1_IO, 0x00000001);
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+		/* GPIO0:0 is hooked to demod reset */
+		/* GPIO0:4 is hooked to xc3028 reset */
+		cx_write(MO_GP0_IO, 0x00111100);
+		msleep(1);
+		cx_write(MO_GP0_IO, 0x00111111);
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+		/* GPIO0:6 is hooked to FX2 reset pin */
+		cx_set(MO_GP0_IO, 0x00004040);
+		cx_clear(MO_GP0_IO, 0x00000040);
+		msleep(1000);
+		cx_set(MO_GP0_IO, 0x00004040);
+		/* FALLTHROUGH */
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
+		/* GPIO0:0 is hooked to mt352 reset pin */
+		cx_set(MO_GP0_IO, 0x00000101);
+		cx_clear(MO_GP0_IO, 0x00000001);
+		msleep(1);
+		cx_set(MO_GP0_IO, 0x00000101);
+		if (0 == core->i2c_rc &&
+		    core->boardnr == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID)
+			dvico_fusionhdtv_hybrid_init(core);
+		break;
+	case CX88_BOARD_KWORLD_DVB_T:
+	case CX88_BOARD_DNTV_LIVE_DVB_T:
+		cx_set(MO_GP0_IO, 0x00000707);
+		cx_set(MO_GP2_IO, 0x00000101);
+		cx_clear(MO_GP2_IO, 0x00000001);
+		msleep(1);
+		cx_clear(MO_GP0_IO, 0x00000007);
+		cx_set(MO_GP2_IO, 0x00000101);
+		break;
+	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
+		cx_write(MO_GP0_IO, 0x00080808);
+		break;
+	case CX88_BOARD_ATI_HDTVWONDER:
+		if (0 == core->i2c_rc) {
+			/* enable tuner */
+			int i;
+			static const u8 buffer [][2] = {
+				{0x10,0x12},
+				{0x13,0x04},
+				{0x16,0x00},
+				{0x14,0x04},
+				{0x17,0x00}
+			};
+			core->i2c_client.addr = 0x0a;
+
+			for (i = 0; i < ARRAY_SIZE(buffer); i++)
+				if (2 != i2c_master_send(&core->i2c_client,
+							buffer[i],2))
+					warn_printk(core, "Unable to enable "
+						    "tuner(%i).\n", i);
+		}
+		break;
+	case CX88_BOARD_MSI_TVANYWHERE_MASTER:
+	{
+		struct v4l2_priv_tun_config tea5767_cfg;
+		struct tea5767_ctrl ctl;
+
+		memset(&ctl, 0, sizeof(ctl));
+
+		ctl.high_cut  = 1;
+		ctl.st_noise  = 1;
+		ctl.deemph_75 = 1;
+		ctl.xtal_freq = TEA5767_HIGH_LO_13MHz;
+
+		tea5767_cfg.tuner = TUNER_TEA5767;
+		tea5767_cfg.priv  = &ctl;
+
+		call_all(core, tuner, s_config, &tea5767_cfg);
+		break;
+	}
+	case  CX88_BOARD_TEVII_S420:
+	case  CX88_BOARD_TEVII_S460:
+	case  CX88_BOARD_TEVII_S464:
+	case  CX88_BOARD_OMICOM_SS4_PCI:
+	case  CX88_BOARD_TBS_8910:
+	case  CX88_BOARD_TBS_8920:
+	case  CX88_BOARD_PROF_6200:
+	case  CX88_BOARD_PROF_7300:
+	case  CX88_BOARD_PROF_7301:
+	case  CX88_BOARD_SATTRADE_ST4200:
+		cx_write(MO_GP0_IO, 0x8000);
+		msleep(100);
+		cx_write(MO_SRST_IO, 0);
+		msleep(10);
+		cx_write(MO_GP0_IO, 0x8080);
+		msleep(100);
+		cx_write(MO_SRST_IO, 1);
+		msleep(100);
+		break;
+	} /*end switch() */
+
+
+	/* Setup tuners */
+	if ((core->board.radio_type != UNSET)) {
+		tun_setup.mode_mask      = T_RADIO;
+		tun_setup.type           = core->board.radio_type;
+		tun_setup.addr           = core->board.radio_addr;
+		tun_setup.tuner_callback = cx88_tuner_callback;
+		call_all(core, tuner, s_type_addr, &tun_setup);
+		mode_mask &= ~T_RADIO;
+	}
+
+	if (core->board.tuner_type != TUNER_ABSENT) {
+		tun_setup.mode_mask      = mode_mask;
+		tun_setup.type           = core->board.tuner_type;
+		tun_setup.addr           = core->board.tuner_addr;
+		tun_setup.tuner_callback = cx88_tuner_callback;
+
+		call_all(core, tuner, s_type_addr, &tun_setup);
+	}
+
+	if (core->board.tda9887_conf) {
+		struct v4l2_priv_tun_config tda9887_cfg;
+
+		tda9887_cfg.tuner = TUNER_TDA9887;
+		tda9887_cfg.priv  = &core->board.tda9887_conf;
+
+		call_all(core, tuner, s_config, &tda9887_cfg);
+	}
+
+	if (core->board.tuner_type == TUNER_XC2028) {
+		struct v4l2_priv_tun_config  xc2028_cfg;
+		struct xc2028_ctrl           ctl;
+
+		/* Fills device-dependent initialization parameters */
+		cx88_setup_xc3028(core, &ctl);
+
+		/* Sends parameters to xc2028/3028 tuner */
+		memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
+		xc2028_cfg.tuner = TUNER_XC2028;
+		xc2028_cfg.priv  = &ctl;
+		info_printk(core, "Asking xc2028/3028 to load firmware %s\n",
+			    ctl.fname);
+		call_all(core, tuner, s_config, &xc2028_cfg);
+	}
+	call_all(core, core, s_power, 0);
+}
+
+/* ------------------------------------------------------------------ */
+
+static int cx88_pci_quirks(const char *name, struct pci_dev *pci)
+{
+	unsigned int lat = UNSET;
+	u8 ctrl = 0;
+	u8 value;
+
+	/* check pci quirks */
+	if (pci_pci_problems & PCIPCI_TRITON) {
+		printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n",
+		       name);
+		ctrl |= CX88X_EN_TBFX;
+	}
+	if (pci_pci_problems & PCIPCI_NATOMA) {
+		printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n",
+		       name);
+		ctrl |= CX88X_EN_TBFX;
+	}
+	if (pci_pci_problems & PCIPCI_VIAETBF) {
+		printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n",
+		       name);
+		ctrl |= CX88X_EN_TBFX;
+	}
+	if (pci_pci_problems & PCIPCI_VSFX) {
+		printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n",
+		       name);
+		ctrl |= CX88X_EN_VSFX;
+	}
+#ifdef PCIPCI_ALIMAGIK
+	if (pci_pci_problems & PCIPCI_ALIMAGIK) {
+		printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
+		       name);
+		lat = 0x0A;
+	}
+#endif
+
+	/* check insmod options */
+	if (UNSET != latency)
+		lat = latency;
+
+	/* apply stuff */
+	if (ctrl) {
+		pci_read_config_byte(pci, CX88X_DEVCTRL, &value);
+		value |= ctrl;
+		pci_write_config_byte(pci, CX88X_DEVCTRL, value);
+	}
+	if (UNSET != lat) {
+		printk(KERN_INFO "%s: setting pci latency timer to %d\n",
+		       name, latency);
+		pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency);
+	}
+	return 0;
+}
+
+int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci)
+{
+	if (request_mem_region(pci_resource_start(pci,0),
+			       pci_resource_len(pci,0),
+			       core->name))
+		return 0;
+	printk(KERN_ERR
+	       "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n",
+	       core->name, PCI_FUNC(pci->devfn),
+	       (unsigned long long)pci_resource_start(pci, 0),
+	       pci->subsystem_vendor, pci->subsystem_device);
+	return -EBUSY;
+}
+
+/* Allocate and initialize the cx88 core struct.  One should hold the
+ * devlist mutex before calling this.  */
+struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
+{
+	struct cx88_core *core;
+	int i;
+
+	core = kzalloc(sizeof(*core), GFP_KERNEL);
+	if (core == NULL)
+		return NULL;
+
+	atomic_inc(&core->refcount);
+	core->pci_bus  = pci->bus->number;
+	core->pci_slot = PCI_SLOT(pci->devfn);
+	core->pci_irqmask = PCI_INT_RISC_RD_BERRINT | PCI_INT_RISC_WR_BERRINT |
+			    PCI_INT_BRDG_BERRINT | PCI_INT_SRC_DMA_BERRINT |
+			    PCI_INT_DST_DMA_BERRINT | PCI_INT_IPB_DMA_BERRINT;
+	mutex_init(&core->lock);
+
+	core->nr = nr;
+	sprintf(core->name, "cx88[%d]", core->nr);
+
+	strcpy(core->v4l2_dev.name, core->name);
+	if (v4l2_device_register(NULL, &core->v4l2_dev)) {
+		kfree(core);
+		return NULL;
+	}
+
+	if (v4l2_ctrl_handler_init(&core->video_hdl, 13)) {
+		v4l2_device_unregister(&core->v4l2_dev);
+		kfree(core);
+		return NULL;
+	}
+
+	if (v4l2_ctrl_handler_init(&core->audio_hdl, 13)) {
+		v4l2_ctrl_handler_free(&core->video_hdl);
+		v4l2_device_unregister(&core->v4l2_dev);
+		kfree(core);
+		return NULL;
+	}
+
+	if (0 != cx88_get_resources(core, pci)) {
+		v4l2_ctrl_handler_free(&core->video_hdl);
+		v4l2_ctrl_handler_free(&core->audio_hdl);
+		v4l2_device_unregister(&core->v4l2_dev);
+		kfree(core);
+		return NULL;
+	}
+
+	/* PCI stuff */
+	cx88_pci_quirks(core->name, pci);
+	core->lmmio = ioremap(pci_resource_start(pci, 0),
+			      pci_resource_len(pci, 0));
+	core->bmmio = (u8 __iomem *)core->lmmio;
+
+	if (core->lmmio == NULL) {
+		release_mem_region(pci_resource_start(pci, 0),
+			   pci_resource_len(pci, 0));
+		v4l2_ctrl_handler_free(&core->video_hdl);
+		v4l2_ctrl_handler_free(&core->audio_hdl);
+		v4l2_device_unregister(&core->v4l2_dev);
+		kfree(core);
+		return NULL;
+	}
+
+	/* board config */
+	core->boardnr = UNSET;
+	if (card[core->nr] < ARRAY_SIZE(cx88_boards))
+		core->boardnr = card[core->nr];
+	for (i = 0; UNSET == core->boardnr && i < ARRAY_SIZE(cx88_subids); i++)
+		if (pci->subsystem_vendor == cx88_subids[i].subvendor &&
+		    pci->subsystem_device == cx88_subids[i].subdevice)
+			core->boardnr = cx88_subids[i].card;
+	if (UNSET == core->boardnr) {
+		core->boardnr = CX88_BOARD_UNKNOWN;
+		cx88_card_list(core, pci);
+	}
+
+	memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board));
+
+	if (!core->board.num_frontends && (core->board.mpeg & CX88_MPEG_DVB))
+		core->board.num_frontends = 1;
+
+	info_printk(core, "subsystem: %04x:%04x, board: %s [card=%d,%s], frontend(s): %d\n",
+		pci->subsystem_vendor, pci->subsystem_device, core->board.name,
+		core->boardnr, card[core->nr] == core->boardnr ?
+		"insmod option" : "autodetected",
+		core->board.num_frontends);
+
+	if (tuner[core->nr] != UNSET)
+		core->board.tuner_type = tuner[core->nr];
+	if (radio[core->nr] != UNSET)
+		core->board.radio_type = radio[core->nr];
+
+	info_printk(core, "TV tuner type %d, Radio tuner type %d\n",
+		    core->board.tuner_type, core->board.radio_type);
+
+	/* init hardware */
+	cx88_reset(core);
+	cx88_card_setup_pre_i2c(core);
+	cx88_i2c_init(core, pci);
+
+	/* load tuner module, if needed */
+	if (TUNER_ABSENT != core->board.tuner_type) {
+		/* Ignore 0x6b and 0x6f on cx88 boards.
+		 * FusionHDTV5 RT Gold has an ir receiver at 0x6b
+		 * and an RTC at 0x6f which can get corrupted if probed. */
+		static const unsigned short tv_addrs[] = {
+			0x42, 0x43, 0x4a, 0x4b,		/* tda8290 */
+			0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+			0x68, 0x69, 0x6a, 0x6c, 0x6d, 0x6e,
+			I2C_CLIENT_END
+		};
+		int has_demod = (core->board.tda9887_conf & TDA9887_PRESENT);
+
+		/* I don't trust the radio_type as is stored in the card
+		   definitions, so we just probe for it.
+		   The radio_type is sometimes missing, or set to UNSET but
+		   later code configures a tea5767.
+		 */
+		v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
+				"tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
+		if (has_demod)
+			v4l2_i2c_new_subdev(&core->v4l2_dev,
+				&core->i2c_adap, "tuner",
+				0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+		if (core->board.tuner_addr == ADDR_UNSET) {
+			v4l2_i2c_new_subdev(&core->v4l2_dev,
+				&core->i2c_adap, "tuner",
+				0, has_demod ? tv_addrs + 4 : tv_addrs);
+		} else {
+			v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
+				"tuner", core->board.tuner_addr, NULL);
+		}
+	}
+
+	cx88_card_setup(core);
+	if (!disable_ir) {
+		cx88_i2c_init_ir(core);
+		cx88_ir_init(core, pci);
+	}
+
+	return core;
+}
diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c
new file mode 100644
index 0000000..c97b174
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-core.c
@@ -0,0 +1,1131 @@
+/*
+ *
+ * device driver for Conexant 2388x based TV cards
+ * driver core
+ *
+ * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *     - Multituner support
+ *     - video_ioctl2 conversion
+ *     - PAL/M fixes
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/kmod.h>
+#include <linux/sound.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/mutex.h>
+
+#include "cx88.h"
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+
+MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int core_debug;
+module_param(core_debug,int,0644);
+MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+
+static unsigned int nicam;
+module_param(nicam,int,0644);
+MODULE_PARM_DESC(nicam,"tv audio is nicam");
+
+static unsigned int nocomb;
+module_param(nocomb,int,0644);
+MODULE_PARM_DESC(nocomb,"disable comb filter");
+
+#define dprintk(level,fmt, arg...)	if (core_debug >= level)	\
+	printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
+
+static unsigned int cx88_devcount;
+static LIST_HEAD(cx88_devlist);
+static DEFINE_MUTEX(devlist);
+
+#define NO_SYNC_LINE (-1U)
+
+/* @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be
+	 generated _after_ lpi lines are transferred. */
+static __le32* cx88_risc_field(__le32 *rp, struct scatterlist *sglist,
+			    unsigned int offset, u32 sync_line,
+			    unsigned int bpl, unsigned int padding,
+			    unsigned int lines, unsigned int lpi)
+{
+	struct scatterlist *sg;
+	unsigned int line,todo,sol;
+
+	/* sync instruction */
+	if (sync_line != NO_SYNC_LINE)
+		*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
+
+	/* scan lines */
+	sg = sglist;
+	for (line = 0; line < lines; line++) {
+		while (offset && offset >= sg_dma_len(sg)) {
+			offset -= sg_dma_len(sg);
+			sg++;
+		}
+		if (lpi && line>0 && !(line % lpi))
+			sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC;
+		else
+			sol = RISC_SOL;
+		if (bpl <= sg_dma_len(sg)-offset) {
+			/* fits into current chunk */
+			*(rp++)=cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl);
+			*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+			offset+=bpl;
+		} else {
+			/* scanline needs to be split */
+			todo = bpl;
+			*(rp++)=cpu_to_le32(RISC_WRITE|sol|
+					    (sg_dma_len(sg)-offset));
+			*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+			todo -= (sg_dma_len(sg)-offset);
+			offset = 0;
+			sg++;
+			while (todo > sg_dma_len(sg)) {
+				*(rp++)=cpu_to_le32(RISC_WRITE|
+						    sg_dma_len(sg));
+				*(rp++)=cpu_to_le32(sg_dma_address(sg));
+				todo -= sg_dma_len(sg);
+				sg++;
+			}
+			*(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
+			*(rp++)=cpu_to_le32(sg_dma_address(sg));
+			offset += todo;
+		}
+		offset += padding;
+	}
+
+	return rp;
+}
+
+int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+		     struct scatterlist *sglist,
+		     unsigned int top_offset, unsigned int bottom_offset,
+		     unsigned int bpl, unsigned int padding, unsigned int lines)
+{
+	u32 instructions,fields;
+	__le32 *rp;
+	int rc;
+
+	fields = 0;
+	if (UNSET != top_offset)
+		fields++;
+	if (UNSET != bottom_offset)
+		fields++;
+
+	/* estimate risc mem: worst case is one write per page border +
+	   one write per scan line + syncs + jump (all 2 dwords).  Padding
+	   can cause next bpl to start close to a page border.  First DMA
+	   region may be smaller than PAGE_SIZE */
+	instructions  = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines);
+	instructions += 2;
+	if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
+		return rc;
+
+	/* write risc instructions */
+	rp = risc->cpu;
+	if (UNSET != top_offset)
+		rp = cx88_risc_field(rp, sglist, top_offset, 0,
+				     bpl, padding, lines, 0);
+	if (UNSET != bottom_offset)
+		rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200,
+				     bpl, padding, lines, 0);
+
+	/* save pointer to jmp instruction address */
+	risc->jmp = rp;
+	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
+	return 0;
+}
+
+int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+			 struct scatterlist *sglist, unsigned int bpl,
+			 unsigned int lines, unsigned int lpi)
+{
+	u32 instructions;
+	__le32 *rp;
+	int rc;
+
+	/* estimate risc mem: worst case is one write per page border +
+	   one write per scan line + syncs + jump (all 2 dwords).  Here
+	   there is no padding and no sync.  First DMA region may be smaller
+	   than PAGE_SIZE */
+	instructions  = 1 + (bpl * lines) / PAGE_SIZE + lines;
+	instructions += 1;
+	if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
+		return rc;
+
+	/* write risc instructions */
+	rp = risc->cpu;
+	rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines, lpi);
+
+	/* save pointer to jmp instruction address */
+	risc->jmp = rp;
+	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
+	return 0;
+}
+
+int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+		      u32 reg, u32 mask, u32 value)
+{
+	__le32 *rp;
+	int rc;
+
+	if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
+		return rc;
+
+	/* write risc instructions */
+	rp = risc->cpu;
+	*(rp++) = cpu_to_le32(RISC_WRITECR  | RISC_IRQ2 | RISC_IMM);
+	*(rp++) = cpu_to_le32(reg);
+	*(rp++) = cpu_to_le32(value);
+	*(rp++) = cpu_to_le32(mask);
+	*(rp++) = cpu_to_le32(RISC_JUMP);
+	*(rp++) = cpu_to_le32(risc->dma);
+	return 0;
+}
+
+void
+cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
+{
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
+	BUG_ON(in_interrupt());
+	videobuf_waiton(q, &buf->vb, 0, 0);
+	videobuf_dma_unmap(q->dev, dma);
+	videobuf_dma_free(dma);
+	btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+/* ------------------------------------------------------------------ */
+/* our SRAM memory layout                                             */
+
+/* we are going to put all thr risc programs into host memory, so we
+ * can use the whole SDRAM for the DMA fifos.  To simplify things, we
+ * use a static memory layout.  That surely will waste memory in case
+ * we don't use all DMA channels at the same time (which will be the
+ * case most of the time).  But that still gives us enough FIFO space
+ * to be able to deal with insane long pci latencies ...
+ *
+ * FIFO space allocations:
+ *    channel  21    (y video)  - 10.0k
+ *    channel  22    (u video)  -  2.0k
+ *    channel  23    (v video)  -  2.0k
+ *    channel  24    (vbi)      -  4.0k
+ *    channels 25+26 (audio)    -  4.0k
+ *    channel  28    (mpeg)     -  4.0k
+ *    channel  27    (audio rds)-  3.0k
+ *    TOTAL                     = 29.0k
+ *
+ * Every channel has 160 bytes control data (64 bytes instruction
+ * queue and 6 CDT entries), which is close to 2k total.
+ *
+ * Address layout:
+ *    0x0000 - 0x03ff    CMDs / reserved
+ *    0x0400 - 0x0bff    instruction queues + CDs
+ *    0x0c00 -           FIFOs
+ */
+
+const struct sram_channel cx88_sram_channels[] = {
+	[SRAM_CH21] = {
+		.name       = "video y / packed",
+		.cmds_start = 0x180040,
+		.ctrl_start = 0x180400,
+		.cdt        = 0x180400 + 64,
+		.fifo_start = 0x180c00,
+		.fifo_size  = 0x002800,
+		.ptr1_reg   = MO_DMA21_PTR1,
+		.ptr2_reg   = MO_DMA21_PTR2,
+		.cnt1_reg   = MO_DMA21_CNT1,
+		.cnt2_reg   = MO_DMA21_CNT2,
+	},
+	[SRAM_CH22] = {
+		.name       = "video u",
+		.cmds_start = 0x180080,
+		.ctrl_start = 0x1804a0,
+		.cdt        = 0x1804a0 + 64,
+		.fifo_start = 0x183400,
+		.fifo_size  = 0x000800,
+		.ptr1_reg   = MO_DMA22_PTR1,
+		.ptr2_reg   = MO_DMA22_PTR2,
+		.cnt1_reg   = MO_DMA22_CNT1,
+		.cnt2_reg   = MO_DMA22_CNT2,
+	},
+	[SRAM_CH23] = {
+		.name       = "video v",
+		.cmds_start = 0x1800c0,
+		.ctrl_start = 0x180540,
+		.cdt        = 0x180540 + 64,
+		.fifo_start = 0x183c00,
+		.fifo_size  = 0x000800,
+		.ptr1_reg   = MO_DMA23_PTR1,
+		.ptr2_reg   = MO_DMA23_PTR2,
+		.cnt1_reg   = MO_DMA23_CNT1,
+		.cnt2_reg   = MO_DMA23_CNT2,
+	},
+	[SRAM_CH24] = {
+		.name       = "vbi",
+		.cmds_start = 0x180100,
+		.ctrl_start = 0x1805e0,
+		.cdt        = 0x1805e0 + 64,
+		.fifo_start = 0x184400,
+		.fifo_size  = 0x001000,
+		.ptr1_reg   = MO_DMA24_PTR1,
+		.ptr2_reg   = MO_DMA24_PTR2,
+		.cnt1_reg   = MO_DMA24_CNT1,
+		.cnt2_reg   = MO_DMA24_CNT2,
+	},
+	[SRAM_CH25] = {
+		.name       = "audio from",
+		.cmds_start = 0x180140,
+		.ctrl_start = 0x180680,
+		.cdt        = 0x180680 + 64,
+		.fifo_start = 0x185400,
+		.fifo_size  = 0x001000,
+		.ptr1_reg   = MO_DMA25_PTR1,
+		.ptr2_reg   = MO_DMA25_PTR2,
+		.cnt1_reg   = MO_DMA25_CNT1,
+		.cnt2_reg   = MO_DMA25_CNT2,
+	},
+	[SRAM_CH26] = {
+		.name       = "audio to",
+		.cmds_start = 0x180180,
+		.ctrl_start = 0x180720,
+		.cdt        = 0x180680 + 64,  /* same as audio IN */
+		.fifo_start = 0x185400,       /* same as audio IN */
+		.fifo_size  = 0x001000,       /* same as audio IN */
+		.ptr1_reg   = MO_DMA26_PTR1,
+		.ptr2_reg   = MO_DMA26_PTR2,
+		.cnt1_reg   = MO_DMA26_CNT1,
+		.cnt2_reg   = MO_DMA26_CNT2,
+	},
+	[SRAM_CH28] = {
+		.name       = "mpeg",
+		.cmds_start = 0x180200,
+		.ctrl_start = 0x1807C0,
+		.cdt        = 0x1807C0 + 64,
+		.fifo_start = 0x186400,
+		.fifo_size  = 0x001000,
+		.ptr1_reg   = MO_DMA28_PTR1,
+		.ptr2_reg   = MO_DMA28_PTR2,
+		.cnt1_reg   = MO_DMA28_CNT1,
+		.cnt2_reg   = MO_DMA28_CNT2,
+	},
+	[SRAM_CH27] = {
+		.name       = "audio rds",
+		.cmds_start = 0x1801C0,
+		.ctrl_start = 0x180860,
+		.cdt        = 0x180860 + 64,
+		.fifo_start = 0x187400,
+		.fifo_size  = 0x000C00,
+		.ptr1_reg   = MO_DMA27_PTR1,
+		.ptr2_reg   = MO_DMA27_PTR2,
+		.cnt1_reg   = MO_DMA27_CNT1,
+		.cnt2_reg   = MO_DMA27_CNT2,
+	},
+};
+
+int cx88_sram_channel_setup(struct cx88_core *core,
+			    const struct sram_channel *ch,
+			    unsigned int bpl, u32 risc)
+{
+	unsigned int i,lines;
+	u32 cdt;
+
+	bpl   = (bpl + 7) & ~7; /* alignment */
+	cdt   = ch->cdt;
+	lines = ch->fifo_size / bpl;
+	if (lines > 6)
+		lines = 6;
+	BUG_ON(lines < 2);
+
+	/* write CDT */
+	for (i = 0; i < lines; i++)
+		cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
+
+	/* write CMDS */
+	cx_write(ch->cmds_start +  0, risc);
+	cx_write(ch->cmds_start +  4, cdt);
+	cx_write(ch->cmds_start +  8, (lines*16) >> 3);
+	cx_write(ch->cmds_start + 12, ch->ctrl_start);
+	cx_write(ch->cmds_start + 16, 64 >> 2);
+	for (i = 20; i < 64; i += 4)
+		cx_write(ch->cmds_start + i, 0);
+
+	/* fill registers */
+	cx_write(ch->ptr1_reg, ch->fifo_start);
+	cx_write(ch->ptr2_reg, cdt);
+	cx_write(ch->cnt1_reg, (bpl >> 3) -1);
+	cx_write(ch->cnt2_reg, (lines*16) >> 3);
+
+	dprintk(2,"sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines);
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* debug helper code                                                  */
+
+static int cx88_risc_decode(u32 risc)
+{
+	static const char * const instr[16] = {
+		[ RISC_SYNC    >> 28 ] = "sync",
+		[ RISC_WRITE   >> 28 ] = "write",
+		[ RISC_WRITEC  >> 28 ] = "writec",
+		[ RISC_READ    >> 28 ] = "read",
+		[ RISC_READC   >> 28 ] = "readc",
+		[ RISC_JUMP    >> 28 ] = "jump",
+		[ RISC_SKIP    >> 28 ] = "skip",
+		[ RISC_WRITERM >> 28 ] = "writerm",
+		[ RISC_WRITECM >> 28 ] = "writecm",
+		[ RISC_WRITECR >> 28 ] = "writecr",
+	};
+	static int const incr[16] = {
+		[ RISC_WRITE   >> 28 ] = 2,
+		[ RISC_JUMP    >> 28 ] = 2,
+		[ RISC_WRITERM >> 28 ] = 3,
+		[ RISC_WRITECM >> 28 ] = 3,
+		[ RISC_WRITECR >> 28 ] = 4,
+	};
+	static const char * const bits[] = {
+		"12",   "13",   "14",   "resync",
+		"cnt0", "cnt1", "18",   "19",
+		"20",   "21",   "22",   "23",
+		"irq1", "irq2", "eol",  "sol",
+	};
+	int i;
+
+	printk("0x%08x [ %s", risc,
+	       instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
+	for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
+		if (risc & (1 << (i + 12)))
+			printk(" %s",bits[i]);
+	printk(" count=%d ]\n", risc & 0xfff);
+	return incr[risc >> 28] ? incr[risc >> 28] : 1;
+}
+
+
+void cx88_sram_channel_dump(struct cx88_core *core,
+			    const struct sram_channel *ch)
+{
+	static const char * const name[] = {
+		"initial risc",
+		"cdt base",
+		"cdt size",
+		"iq base",
+		"iq size",
+		"risc pc",
+		"iq wr ptr",
+		"iq rd ptr",
+		"cdt current",
+		"pci target",
+		"line / byte",
+	};
+	u32 risc;
+	unsigned int i,j,n;
+
+	printk("%s: %s - dma channel status dump\n",
+	       core->name,ch->name);
+	for (i = 0; i < ARRAY_SIZE(name); i++)
+		printk("%s:   cmds: %-12s: 0x%08x\n",
+		       core->name,name[i],
+		       cx_read(ch->cmds_start + 4*i));
+	for (n = 1, i = 0; i < 4; i++) {
+		risc = cx_read(ch->cmds_start + 4 * (i+11));
+		printk("%s:   risc%d: ", core->name, i);
+		if (--n)
+			printk("0x%08x [ arg #%d ]\n", risc, n);
+		else
+			n = cx88_risc_decode(risc);
+	}
+	for (i = 0; i < 16; i += n) {
+		risc = cx_read(ch->ctrl_start + 4 * i);
+		printk("%s:   iq %x: ", core->name, i);
+		n = cx88_risc_decode(risc);
+		for (j = 1; j < n; j++) {
+			risc = cx_read(ch->ctrl_start + 4 * (i+j));
+			printk("%s:   iq %x: 0x%08x [ arg #%d ]\n",
+			       core->name, i+j, risc, j);
+		}
+	}
+
+	printk("%s: fifo: 0x%08x -> 0x%x\n",
+	       core->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
+	printk("%s: ctrl: 0x%08x -> 0x%x\n",
+	       core->name, ch->ctrl_start, ch->ctrl_start+6*16);
+	printk("%s:   ptr1_reg: 0x%08x\n",
+	       core->name,cx_read(ch->ptr1_reg));
+	printk("%s:   ptr2_reg: 0x%08x\n",
+	       core->name,cx_read(ch->ptr2_reg));
+	printk("%s:   cnt1_reg: 0x%08x\n",
+	       core->name,cx_read(ch->cnt1_reg));
+	printk("%s:   cnt2_reg: 0x%08x\n",
+	       core->name,cx_read(ch->cnt2_reg));
+}
+
+static const char *cx88_pci_irqs[32] = {
+	"vid", "aud", "ts", "vip", "hst", "5", "6", "tm1",
+	"src_dma", "dst_dma", "risc_rd_err", "risc_wr_err",
+	"brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err",
+	"i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1"
+};
+
+void cx88_print_irqbits(const char *name, const char *tag, const char *strings[],
+			int len, u32 bits, u32 mask)
+{
+	unsigned int i;
+
+	printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits);
+	for (i = 0; i < len; i++) {
+		if (!(bits & (1 << i)))
+			continue;
+		if (strings[i])
+			printk(" %s", strings[i]);
+		else
+			printk(" %d", i);
+		if (!(mask & (1 << i)))
+			continue;
+		printk("*");
+	}
+	printk("\n");
+}
+
+/* ------------------------------------------------------------------ */
+
+int cx88_core_irq(struct cx88_core *core, u32 status)
+{
+	int handled = 0;
+
+	if (status & PCI_INT_IR_SMPINT) {
+		cx88_ir_irq(core);
+		handled++;
+	}
+	if (!handled)
+		cx88_print_irqbits(core->name, "irq pci",
+				   cx88_pci_irqs, ARRAY_SIZE(cx88_pci_irqs),
+				   status, core->pci_irqmask);
+	return handled;
+}
+
+void cx88_wakeup(struct cx88_core *core,
+		 struct cx88_dmaqueue *q, u32 count)
+{
+	struct cx88_buffer *buf;
+	int bc;
+
+	for (bc = 0;; bc++) {
+		if (list_empty(&q->active))
+			break;
+		buf = list_entry(q->active.next,
+				 struct cx88_buffer, vb.queue);
+		/* count comes from the hw and is is 16bit wide --
+		 * this trick handles wrap-arounds correctly for
+		 * up to 32767 buffers in flight... */
+		if ((s16) (count - buf->count) < 0)
+			break;
+		do_gettimeofday(&buf->vb.ts);
+		dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
+			count, buf->count);
+		buf->vb.state = VIDEOBUF_DONE;
+		list_del(&buf->vb.queue);
+		wake_up(&buf->vb.done);
+	}
+	if (list_empty(&q->active)) {
+		del_timer(&q->timeout);
+	} else {
+		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+	}
+	if (bc != 1)
+		dprintk(2, "%s: %d buffers handled (should be 1)\n",
+			__func__, bc);
+}
+
+void cx88_shutdown(struct cx88_core *core)
+{
+	/* disable RISC controller + IRQs */
+	cx_write(MO_DEV_CNTRL2, 0);
+
+	/* stop dma transfers */
+	cx_write(MO_VID_DMACNTRL, 0x0);
+	cx_write(MO_AUD_DMACNTRL, 0x0);
+	cx_write(MO_TS_DMACNTRL, 0x0);
+	cx_write(MO_VIP_DMACNTRL, 0x0);
+	cx_write(MO_GPHST_DMACNTRL, 0x0);
+
+	/* stop interrupts */
+	cx_write(MO_PCI_INTMSK, 0x0);
+	cx_write(MO_VID_INTMSK, 0x0);
+	cx_write(MO_AUD_INTMSK, 0x0);
+	cx_write(MO_TS_INTMSK, 0x0);
+	cx_write(MO_VIP_INTMSK, 0x0);
+	cx_write(MO_GPHST_INTMSK, 0x0);
+
+	/* stop capturing */
+	cx_write(VID_CAPTURE_CONTROL, 0);
+}
+
+int cx88_reset(struct cx88_core *core)
+{
+	dprintk(1,"%s\n",__func__);
+	cx88_shutdown(core);
+
+	/* clear irq status */
+	cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
+	cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
+	cx_write(MO_INT1_STAT,   0xFFFFFFFF); // Clear RISC int
+
+	/* wait a bit */
+	msleep(100);
+
+	/* init sram */
+	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], 720*4, 0);
+	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH22], 128, 0);
+	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH23], 128, 0);
+	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH24], 128, 0);
+	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0);
+	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0);
+	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0);
+	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27], 128, 0);
+
+	/* misc init ... */
+	cx_write(MO_INPUT_FORMAT, ((1 << 13) |   // agc enable
+				   (1 << 12) |   // agc gain
+				   (1 << 11) |   // adaptibe agc
+				   (0 << 10) |   // chroma agc
+				   (0 <<  9) |   // ckillen
+				   (7)));
+
+	/* setup image format */
+	cx_andor(MO_COLOR_CTRL, 0x4000, 0x4000);
+
+	/* setup FIFO Thresholds */
+	cx_write(MO_PDMA_STHRSH,   0x0807);
+	cx_write(MO_PDMA_DTHRSH,   0x0807);
+
+	/* fixes flashing of image */
+	cx_write(MO_AGC_SYNC_TIP1, 0x0380000F);
+	cx_write(MO_AGC_BACK_VBI,  0x00E00555);
+
+	cx_write(MO_VID_INTSTAT,   0xFFFFFFFF); // Clear PIV int
+	cx_write(MO_PCI_INTSTAT,   0xFFFFFFFF); // Clear PCI int
+	cx_write(MO_INT1_STAT,     0xFFFFFFFF); // Clear RISC int
+
+	/* Reset on-board parts */
+	cx_write(MO_SRST_IO, 0);
+	msleep(10);
+	cx_write(MO_SRST_IO, 1);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int inline norm_swidth(v4l2_std_id norm)
+{
+	return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
+}
+
+static unsigned int inline norm_hdelay(v4l2_std_id norm)
+{
+	return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
+}
+
+static unsigned int inline norm_vdelay(v4l2_std_id norm)
+{
+	return (norm & V4L2_STD_625_50) ? 0x24 : 0x18;
+}
+
+static unsigned int inline norm_fsc8(v4l2_std_id norm)
+{
+	if (norm & V4L2_STD_PAL_M)
+		return 28604892;      // 3.575611 MHz
+
+	if (norm & (V4L2_STD_PAL_Nc))
+		return 28656448;      // 3.582056 MHz
+
+	if (norm & V4L2_STD_NTSC) // All NTSC/M and variants
+		return 28636360;      // 3.57954545 MHz +/- 10 Hz
+
+	/* SECAM have also different sub carrier for chroma,
+	   but step_db and step_dr, at cx88_set_tvnorm already handles that.
+
+	   The same FSC applies to PAL/BGDKIH, PAL/60, NTSC/4.43 and PAL/N
+	 */
+
+	return 35468950;      // 4.43361875 MHz +/- 5 Hz
+}
+
+static unsigned int inline norm_htotal(v4l2_std_id norm)
+{
+
+	unsigned int fsc4=norm_fsc8(norm)/2;
+
+	/* returns 4*FSC / vtotal / frames per seconds */
+	return (norm & V4L2_STD_625_50) ?
+				((fsc4+312)/625+12)/25 :
+				((fsc4+262)/525*1001+15000)/30000;
+}
+
+static unsigned int inline norm_vbipack(v4l2_std_id norm)
+{
+	return (norm & V4L2_STD_625_50) ? 511 : 400;
+}
+
+int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
+		   enum v4l2_field field)
+{
+	unsigned int swidth  = norm_swidth(core->tvnorm);
+	unsigned int sheight = norm_maxh(core->tvnorm);
+	u32 value;
+
+	dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
+		V4L2_FIELD_HAS_TOP(field)    ? "T" : "",
+		V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
+		v4l2_norm_to_name(core->tvnorm));
+	if (!V4L2_FIELD_HAS_BOTH(field))
+		height *= 2;
+
+	// recalc H delay and scale registers
+	value = (width * norm_hdelay(core->tvnorm)) / swidth;
+	value &= 0x3fe;
+	cx_write(MO_HDELAY_EVEN,  value);
+	cx_write(MO_HDELAY_ODD,   value);
+	dprintk(1,"set_scale: hdelay  0x%04x (width %d)\n", value,swidth);
+
+	value = (swidth * 4096 / width) - 4096;
+	cx_write(MO_HSCALE_EVEN,  value);
+	cx_write(MO_HSCALE_ODD,   value);
+	dprintk(1,"set_scale: hscale  0x%04x\n", value);
+
+	cx_write(MO_HACTIVE_EVEN, width);
+	cx_write(MO_HACTIVE_ODD,  width);
+	dprintk(1,"set_scale: hactive 0x%04x\n", width);
+
+	// recalc V scale Register (delay is constant)
+	cx_write(MO_VDELAY_EVEN, norm_vdelay(core->tvnorm));
+	cx_write(MO_VDELAY_ODD,  norm_vdelay(core->tvnorm));
+	dprintk(1,"set_scale: vdelay  0x%04x\n", norm_vdelay(core->tvnorm));
+
+	value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff;
+	cx_write(MO_VSCALE_EVEN,  value);
+	cx_write(MO_VSCALE_ODD,   value);
+	dprintk(1,"set_scale: vscale  0x%04x\n", value);
+
+	cx_write(MO_VACTIVE_EVEN, sheight);
+	cx_write(MO_VACTIVE_ODD,  sheight);
+	dprintk(1,"set_scale: vactive 0x%04x\n", sheight);
+
+	// setup filters
+	value = 0;
+	value |= (1 << 19);        // CFILT (default)
+	if (core->tvnorm & V4L2_STD_SECAM) {
+		value |= (1 << 15);
+		value |= (1 << 16);
+	}
+	if (INPUT(core->input).type == CX88_VMUX_SVIDEO)
+		value |= (1 << 13) | (1 << 5);
+	if (V4L2_FIELD_INTERLACED == field)
+		value |= (1 << 3); // VINT (interlaced vertical scaling)
+	if (width < 385)
+		value |= (1 << 0); // 3-tap interpolation
+	if (width < 193)
+		value |= (1 << 1); // 5-tap interpolation
+	if (nocomb)
+		value |= (3 << 5); // disable comb filter
+
+	cx_andor(MO_FILTER_EVEN,  0x7ffc7f, value); /* preserve PEAKEN, PSEL */
+	cx_andor(MO_FILTER_ODD,   0x7ffc7f, value);
+	dprintk(1,"set_scale: filter  0x%04x\n", value);
+
+	return 0;
+}
+
+static const u32 xtal = 28636363;
+
+static int set_pll(struct cx88_core *core, int prescale, u32 ofreq)
+{
+	static const u32 pre[] = { 0, 0, 0, 3, 2, 1 };
+	u64 pll;
+	u32 reg;
+	int i;
+
+	if (prescale < 2)
+		prescale = 2;
+	if (prescale > 5)
+		prescale = 5;
+
+	pll = ofreq * 8 * prescale * (u64)(1 << 20);
+	do_div(pll,xtal);
+	reg = (pll & 0x3ffffff) | (pre[prescale] << 26);
+	if (((reg >> 20) & 0x3f) < 14) {
+		printk("%s/0: pll out of range\n",core->name);
+		return -1;
+	}
+
+	dprintk(1,"set_pll:    MO_PLL_REG       0x%08x [old=0x%08x,freq=%d]\n",
+		reg, cx_read(MO_PLL_REG), ofreq);
+	cx_write(MO_PLL_REG, reg);
+	for (i = 0; i < 100; i++) {
+		reg = cx_read(MO_DEVICE_STATUS);
+		if (reg & (1<<2)) {
+			dprintk(1,"pll locked [pre=%d,ofreq=%d]\n",
+				prescale,ofreq);
+			return 0;
+		}
+		dprintk(1,"pll not locked yet, waiting ...\n");
+		msleep(10);
+	}
+	dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq);
+	return -1;
+}
+
+int cx88_start_audio_dma(struct cx88_core *core)
+{
+	/* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */
+	int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4;
+
+	int rds_bpl = cx88_sram_channels[SRAM_CH27].fifo_size/AUD_RDS_LINES;
+
+	/* If downstream RISC is enabled, bail out; ALSA is managing DMA */
+	if (cx_read(MO_AUD_DMACNTRL) & 0x10)
+		return 0;
+
+	/* setup fifo + format */
+	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0);
+	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0);
+	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27],
+				rds_bpl, 0);
+
+	cx_write(MO_AUDD_LNGTH, bpl); /* fifo bpl size */
+	cx_write(MO_AUDR_LNGTH, rds_bpl); /* fifo bpl size */
+
+	/* enable Up, Down and Audio RDS fifo */
+	cx_write(MO_AUD_DMACNTRL, 0x0007);
+
+	return 0;
+}
+
+int cx88_stop_audio_dma(struct cx88_core *core)
+{
+	/* If downstream RISC is enabled, bail out; ALSA is managing DMA */
+	if (cx_read(MO_AUD_DMACNTRL) & 0x10)
+		return 0;
+
+	/* stop dma */
+	cx_write(MO_AUD_DMACNTRL, 0x0000);
+
+	return 0;
+}
+
+static int set_tvaudio(struct cx88_core *core)
+{
+	v4l2_std_id norm = core->tvnorm;
+
+	if (CX88_VMUX_TELEVISION != INPUT(core->input).type &&
+	    CX88_VMUX_CABLE != INPUT(core->input).type)
+		return 0;
+
+	if (V4L2_STD_PAL_BG & norm) {
+		core->tvaudio = WW_BG;
+
+	} else if (V4L2_STD_PAL_DK & norm) {
+		core->tvaudio = WW_DK;
+
+	} else if (V4L2_STD_PAL_I & norm) {
+		core->tvaudio = WW_I;
+
+	} else if (V4L2_STD_SECAM_L & norm) {
+		core->tvaudio = WW_L;
+
+	} else if ((V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H) & norm) {
+		core->tvaudio = WW_BG;
+
+	} else if (V4L2_STD_SECAM_DK & norm) {
+		core->tvaudio = WW_DK;
+
+	} else if ((V4L2_STD_NTSC_M & norm) ||
+		   (V4L2_STD_PAL_M  & norm)) {
+		core->tvaudio = WW_BTSC;
+
+	} else if (V4L2_STD_NTSC_M_JP & norm) {
+		core->tvaudio = WW_EIAJ;
+
+	} else {
+		printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
+		       core->name, v4l2_norm_to_name(core->tvnorm));
+		core->tvaudio = WW_NONE;
+		return 0;
+	}
+
+	cx_andor(MO_AFECFG_IO, 0x1f, 0x0);
+	cx88_set_tvaudio(core);
+	/* cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); */
+
+/*
+   This should be needed only on cx88-alsa. It seems that some cx88 chips have
+   bugs and does require DMA enabled for it to work.
+ */
+	cx88_start_audio_dma(core);
+	return 0;
+}
+
+
+
+int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
+{
+	u32 fsc8;
+	u32 adc_clock;
+	u32 vdec_clock;
+	u32 step_db,step_dr;
+	u64 tmp64;
+	u32 bdelay,agcdelay,htotal;
+	u32 cxiformat, cxoformat;
+
+	core->tvnorm = norm;
+	fsc8       = norm_fsc8(norm);
+	adc_clock  = xtal;
+	vdec_clock = fsc8;
+	step_db    = fsc8;
+	step_dr    = fsc8;
+
+	if (norm & V4L2_STD_NTSC_M_JP) {
+		cxiformat = VideoFormatNTSCJapan;
+		cxoformat = 0x181f0008;
+	} else if (norm & V4L2_STD_NTSC_443) {
+		cxiformat = VideoFormatNTSC443;
+		cxoformat = 0x181f0008;
+	} else if (norm & V4L2_STD_PAL_M) {
+		cxiformat = VideoFormatPALM;
+		cxoformat = 0x1c1f0008;
+	} else if (norm & V4L2_STD_PAL_N) {
+		cxiformat = VideoFormatPALN;
+		cxoformat = 0x1c1f0008;
+	} else if (norm & V4L2_STD_PAL_Nc) {
+		cxiformat = VideoFormatPALNC;
+		cxoformat = 0x1c1f0008;
+	} else if (norm & V4L2_STD_PAL_60) {
+		cxiformat = VideoFormatPAL60;
+		cxoformat = 0x181f0008;
+	} else if (norm & V4L2_STD_NTSC) {
+		cxiformat = VideoFormatNTSC;
+		cxoformat = 0x181f0008;
+	} else if (norm & V4L2_STD_SECAM) {
+		step_db = 4250000 * 8;
+		step_dr = 4406250 * 8;
+
+		cxiformat = VideoFormatSECAM;
+		cxoformat = 0x181f0008;
+	} else { /* PAL */
+		cxiformat = VideoFormatPAL;
+		cxoformat = 0x181f0008;
+	}
+
+	dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
+		v4l2_norm_to_name(core->tvnorm), fsc8, adc_clock, vdec_clock,
+		step_db, step_dr);
+	set_pll(core,2,vdec_clock);
+
+	dprintk(1,"set_tvnorm: MO_INPUT_FORMAT  0x%08x [old=0x%08x]\n",
+		cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
+	/* Chroma AGC must be disabled if SECAM is used, we enable it
+	   by default on PAL and NTSC */
+	cx_andor(MO_INPUT_FORMAT, 0x40f,
+		 norm & V4L2_STD_SECAM ? cxiformat : cxiformat | 0x400);
+
+	// FIXME: as-is from DScaler
+	dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
+		cxoformat, cx_read(MO_OUTPUT_FORMAT));
+	cx_write(MO_OUTPUT_FORMAT, cxoformat);
+
+	// MO_SCONV_REG = adc clock / video dec clock * 2^17
+	tmp64  = adc_clock * (u64)(1 << 17);
+	do_div(tmp64, vdec_clock);
+	dprintk(1,"set_tvnorm: MO_SCONV_REG     0x%08x [old=0x%08x]\n",
+		(u32)tmp64, cx_read(MO_SCONV_REG));
+	cx_write(MO_SCONV_REG, (u32)tmp64);
+
+	// MO_SUB_STEP = 8 * fsc / video dec clock * 2^22
+	tmp64  = step_db * (u64)(1 << 22);
+	do_div(tmp64, vdec_clock);
+	dprintk(1,"set_tvnorm: MO_SUB_STEP      0x%08x [old=0x%08x]\n",
+		(u32)tmp64, cx_read(MO_SUB_STEP));
+	cx_write(MO_SUB_STEP, (u32)tmp64);
+
+	// MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22
+	tmp64  = step_dr * (u64)(1 << 22);
+	do_div(tmp64, vdec_clock);
+	dprintk(1,"set_tvnorm: MO_SUB_STEP_DR   0x%08x [old=0x%08x]\n",
+		(u32)tmp64, cx_read(MO_SUB_STEP_DR));
+	cx_write(MO_SUB_STEP_DR, (u32)tmp64);
+
+	// bdelay + agcdelay
+	bdelay   = vdec_clock * 65 / 20000000 + 21;
+	agcdelay = vdec_clock * 68 / 20000000 + 15;
+	dprintk(1,"set_tvnorm: MO_AGC_BURST     0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n",
+		(bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay);
+	cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay);
+
+	// htotal
+	tmp64 = norm_htotal(norm) * (u64)vdec_clock;
+	do_div(tmp64, fsc8);
+	htotal = (u32)tmp64;
+	dprintk(1,"set_tvnorm: MO_HTOTAL        0x%08x [old=0x%08x,htotal=%d]\n",
+		htotal, cx_read(MO_HTOTAL), (u32)tmp64);
+	cx_andor(MO_HTOTAL, 0x07ff, htotal);
+
+	// vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes
+	// the effective vbi offset ~244 samples, the same as the Bt8x8
+	cx_write(MO_VBI_PACKET, (10<<11) | norm_vbipack(norm));
+
+	// this is needed as well to set all tvnorm parameter
+	cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);
+
+	// audio
+	set_tvaudio(core);
+
+	// tell i2c chips
+	call_all(core, core, s_std, norm);
+
+	/* The chroma_agc control should be inaccessible if the video format is SECAM */
+	v4l2_ctrl_grab(core->chroma_agc, cxiformat == VideoFormatSECAM);
+
+	// done
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+struct video_device *cx88_vdev_init(struct cx88_core *core,
+				    struct pci_dev *pci,
+				    const struct video_device *template_,
+				    const char *type)
+{
+	struct video_device *vfd;
+
+	vfd = video_device_alloc();
+	if (NULL == vfd)
+		return NULL;
+	*vfd = *template_;
+	vfd->v4l2_dev = &core->v4l2_dev;
+	vfd->release = video_device_release;
+	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
+		 core->name, type, core->board.name);
+	set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+	return vfd;
+}
+
+struct cx88_core* cx88_core_get(struct pci_dev *pci)
+{
+	struct cx88_core *core;
+
+	mutex_lock(&devlist);
+	list_for_each_entry(core, &cx88_devlist, devlist) {
+		if (pci->bus->number != core->pci_bus)
+			continue;
+		if (PCI_SLOT(pci->devfn) != core->pci_slot)
+			continue;
+
+		if (0 != cx88_get_resources(core, pci)) {
+			mutex_unlock(&devlist);
+			return NULL;
+		}
+		atomic_inc(&core->refcount);
+		mutex_unlock(&devlist);
+		return core;
+	}
+
+	core = cx88_core_create(pci, cx88_devcount);
+	if (NULL != core) {
+		cx88_devcount++;
+		list_add_tail(&core->devlist, &cx88_devlist);
+	}
+
+	mutex_unlock(&devlist);
+	return core;
+}
+
+void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
+{
+	release_mem_region(pci_resource_start(pci,0),
+			   pci_resource_len(pci,0));
+
+	if (!atomic_dec_and_test(&core->refcount))
+		return;
+
+	mutex_lock(&devlist);
+	cx88_ir_fini(core);
+	if (0 == core->i2c_rc) {
+		if (core->i2c_rtc)
+			i2c_unregister_device(core->i2c_rtc);
+		i2c_del_adapter(&core->i2c_adap);
+	}
+	list_del(&core->devlist);
+	iounmap(core->lmmio);
+	cx88_devcount--;
+	mutex_unlock(&devlist);
+	v4l2_ctrl_handler_free(&core->video_hdl);
+	v4l2_ctrl_handler_free(&core->audio_hdl);
+	v4l2_device_unregister(&core->v4l2_dev);
+	kfree(core);
+}
+
+/* ------------------------------------------------------------------ */
+
+EXPORT_SYMBOL(cx88_print_irqbits);
+
+EXPORT_SYMBOL(cx88_core_irq);
+EXPORT_SYMBOL(cx88_wakeup);
+EXPORT_SYMBOL(cx88_reset);
+EXPORT_SYMBOL(cx88_shutdown);
+
+EXPORT_SYMBOL(cx88_risc_buffer);
+EXPORT_SYMBOL(cx88_risc_databuffer);
+EXPORT_SYMBOL(cx88_risc_stopper);
+EXPORT_SYMBOL(cx88_free_buffer);
+
+EXPORT_SYMBOL(cx88_sram_channels);
+EXPORT_SYMBOL(cx88_sram_channel_setup);
+EXPORT_SYMBOL(cx88_sram_channel_dump);
+
+EXPORT_SYMBOL(cx88_set_tvnorm);
+EXPORT_SYMBOL(cx88_set_scale);
+
+EXPORT_SYMBOL(cx88_vdev_init);
+EXPORT_SYMBOL(cx88_core_get);
+EXPORT_SYMBOL(cx88_core_put);
+
+EXPORT_SYMBOL(cx88_ir_start);
+EXPORT_SYMBOL(cx88_ir_stop);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
+ */
diff --git a/drivers/media/pci/cx88/cx88-dsp.c b/drivers/media/pci/cx88/cx88-dsp.c
new file mode 100644
index 0000000..a990726
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-dsp.c
@@ -0,0 +1,322 @@
+/*
+ *
+ *  Stereo and SAP detection for cx88
+ *
+ *  Copyright (c) 2009 Marton Balint <cus@fazekas.hu>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <asm/div64.h>
+
+#include "cx88.h"
+#include "cx88-reg.h"
+
+#define INT_PI			((s32)(3.141592653589 * 32768.0))
+
+#define compat_remainder(a, b) \
+	 ((float)(((s32)((a)*100))%((s32)((b)*100)))/100.0)
+
+#define baseband_freq(carrier, srate, tone) ((s32)( \
+	 (compat_remainder(carrier + tone, srate)) / srate * 2 * INT_PI))
+
+/* We calculate the baseband frequencies of the carrier and the pilot tones
+ * based on the the sampling rate of the audio rds fifo. */
+
+#define FREQ_A2_CARRIER         baseband_freq(54687.5, 2689.36, 0.0)
+#define FREQ_A2_DUAL            baseband_freq(54687.5, 2689.36, 274.1)
+#define FREQ_A2_STEREO          baseband_freq(54687.5, 2689.36, 117.5)
+
+/* The frequencies below are from the reference driver. They probably need
+ * further adjustments, because they are not tested at all. You may even need
+ * to play a bit with the registers of the chip to select the proper signal
+ * for the input of the audio rds fifo, and measure it's sampling rate to
+ * calculate the proper baseband frequencies... */
+
+#define FREQ_A2M_CARRIER	((s32)(2.114516 * 32768.0))
+#define FREQ_A2M_DUAL		((s32)(2.754916 * 32768.0))
+#define FREQ_A2M_STEREO		((s32)(2.462326 * 32768.0))
+
+#define FREQ_EIAJ_CARRIER	((s32)(1.963495 * 32768.0)) /* 5pi/8  */
+#define FREQ_EIAJ_DUAL		((s32)(2.562118 * 32768.0))
+#define FREQ_EIAJ_STEREO	((s32)(2.601053 * 32768.0))
+
+#define FREQ_BTSC_DUAL		((s32)(1.963495 * 32768.0)) /* 5pi/8  */
+#define FREQ_BTSC_DUAL_REF	((s32)(1.374446 * 32768.0)) /* 7pi/16 */
+
+#define FREQ_BTSC_SAP		((s32)(2.471532 * 32768.0))
+#define FREQ_BTSC_SAP_REF	((s32)(1.730072 * 32768.0))
+
+/* The spectrum of the signal should be empty between these frequencies. */
+#define FREQ_NOISE_START	((s32)(0.100000 * 32768.0))
+#define FREQ_NOISE_END		((s32)(1.200000 * 32768.0))
+
+static unsigned int dsp_debug;
+module_param(dsp_debug, int, 0644);
+MODULE_PARM_DESC(dsp_debug, "enable audio dsp debug messages");
+
+#define dprintk(level, fmt, arg...)	if (dsp_debug >= level) \
+	printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
+
+static s32 int_cos(u32 x)
+{
+	u32 t2, t4, t6, t8;
+	s32 ret;
+	u16 period = x / INT_PI;
+	if (period % 2)
+		return -int_cos(x - INT_PI);
+	x = x % INT_PI;
+	if (x > INT_PI/2)
+		return -int_cos(INT_PI/2 - (x % (INT_PI/2)));
+	/* Now x is between 0 and INT_PI/2.
+	 * To calculate cos(x) we use it's Taylor polinom. */
+	t2 = x*x/32768/2;
+	t4 = t2*x/32768*x/32768/3/4;
+	t6 = t4*x/32768*x/32768/5/6;
+	t8 = t6*x/32768*x/32768/7/8;
+	ret = 32768-t2+t4-t6+t8;
+	return ret;
+}
+
+static u32 int_goertzel(s16 x[], u32 N, u32 freq)
+{
+	/* We use the Goertzel algorithm to determine the power of the
+	 * given frequency in the signal */
+	s32 s_prev = 0;
+	s32 s_prev2 = 0;
+	s32 coeff = 2*int_cos(freq);
+	u32 i;
+
+	u64 tmp;
+	u32 divisor;
+
+	for (i = 0; i < N; i++) {
+		s32 s = x[i] + ((s64)coeff*s_prev/32768) - s_prev2;
+		s_prev2 = s_prev;
+		s_prev = s;
+	}
+
+	tmp = (s64)s_prev2 * s_prev2 + (s64)s_prev * s_prev -
+		      (s64)coeff * s_prev2 * s_prev / 32768;
+
+	/* XXX: N must be low enough so that N*N fits in s32.
+	 * Else we need two divisions. */
+	divisor = N * N;
+	do_div(tmp, divisor);
+
+	return (u32) tmp;
+}
+
+static u32 freq_magnitude(s16 x[], u32 N, u32 freq)
+{
+	u32 sum = int_goertzel(x, N, freq);
+	return (u32)int_sqrt(sum);
+}
+
+static u32 noise_magnitude(s16 x[], u32 N, u32 freq_start, u32 freq_end)
+{
+	int i;
+	u32 sum = 0;
+	u32 freq_step;
+	int samples = 5;
+
+	if (N > 192) {
+		/* The last 192 samples are enough for noise detection */
+		x += (N-192);
+		N = 192;
+	}
+
+	freq_step = (freq_end - freq_start) / (samples - 1);
+
+	for (i = 0; i < samples; i++) {
+		sum += int_goertzel(x, N, freq_start);
+		freq_start += freq_step;
+	}
+
+	return (u32)int_sqrt(sum / samples);
+}
+
+static s32 detect_a2_a2m_eiaj(struct cx88_core *core, s16 x[], u32 N)
+{
+	s32 carrier, stereo, dual, noise;
+	s32 carrier_freq, stereo_freq, dual_freq;
+	s32 ret;
+
+	switch (core->tvaudio) {
+	case WW_BG:
+	case WW_DK:
+		carrier_freq = FREQ_A2_CARRIER;
+		stereo_freq = FREQ_A2_STEREO;
+		dual_freq = FREQ_A2_DUAL;
+		break;
+	case WW_M:
+		carrier_freq = FREQ_A2M_CARRIER;
+		stereo_freq = FREQ_A2M_STEREO;
+		dual_freq = FREQ_A2M_DUAL;
+		break;
+	case WW_EIAJ:
+		carrier_freq = FREQ_EIAJ_CARRIER;
+		stereo_freq = FREQ_EIAJ_STEREO;
+		dual_freq = FREQ_EIAJ_DUAL;
+		break;
+	default:
+		printk(KERN_WARNING "%s/0: unsupported audio mode %d for %s\n",
+		       core->name, core->tvaudio, __func__);
+		return UNSET;
+	}
+
+	carrier = freq_magnitude(x, N, carrier_freq);
+	stereo  = freq_magnitude(x, N, stereo_freq);
+	dual    = freq_magnitude(x, N, dual_freq);
+	noise   = noise_magnitude(x, N, FREQ_NOISE_START, FREQ_NOISE_END);
+
+	dprintk(1, "detect a2/a2m/eiaj: carrier=%d, stereo=%d, dual=%d, "
+		   "noise=%d\n", carrier, stereo, dual, noise);
+
+	if (stereo > dual)
+		ret = V4L2_TUNER_SUB_STEREO;
+	else
+		ret = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+
+	if (core->tvaudio == WW_EIAJ) {
+		/* EIAJ checks may need adjustments */
+		if ((carrier > max(stereo, dual)*2) &&
+		    (carrier < max(stereo, dual)*6) &&
+		    (carrier > 20 && carrier < 200) &&
+		    (max(stereo, dual) > min(stereo, dual))) {
+			/* For EIAJ the carrier is always present,
+			   so we probably don't need noise detection */
+			return ret;
+		}
+	} else {
+		if ((carrier > max(stereo, dual)*2) &&
+		    (carrier < max(stereo, dual)*8) &&
+		    (carrier > 20 && carrier < 200) &&
+		    (noise < 10) &&
+		    (max(stereo, dual) > min(stereo, dual)*2)) {
+			return ret;
+		}
+	}
+	return V4L2_TUNER_SUB_MONO;
+}
+
+static s32 detect_btsc(struct cx88_core *core, s16 x[], u32 N)
+{
+	s32 sap_ref = freq_magnitude(x, N, FREQ_BTSC_SAP_REF);
+	s32 sap = freq_magnitude(x, N, FREQ_BTSC_SAP);
+	s32 dual_ref = freq_magnitude(x, N, FREQ_BTSC_DUAL_REF);
+	s32 dual = freq_magnitude(x, N, FREQ_BTSC_DUAL);
+	dprintk(1, "detect btsc: dual_ref=%d, dual=%d, sap_ref=%d, sap=%d"
+		   "\n", dual_ref, dual, sap_ref, sap);
+	/* FIXME: Currently not supported */
+	return UNSET;
+}
+
+static s16 *read_rds_samples(struct cx88_core *core, u32 *N)
+{
+	const struct sram_channel *srch = &cx88_sram_channels[SRAM_CH27];
+	s16 *samples;
+
+	unsigned int i;
+	unsigned int bpl = srch->fifo_size/AUD_RDS_LINES;
+	unsigned int spl = bpl/4;
+	unsigned int sample_count = spl*(AUD_RDS_LINES-1);
+
+	u32 current_address = cx_read(srch->ptr1_reg);
+	u32 offset = (current_address - srch->fifo_start + bpl);
+
+	dprintk(1, "read RDS samples: current_address=%08x (offset=%08x), "
+		"sample_count=%d, aud_intstat=%08x\n", current_address,
+		current_address - srch->fifo_start, sample_count,
+		cx_read(MO_AUD_INTSTAT));
+
+	samples = kmalloc(sizeof(s16)*sample_count, GFP_KERNEL);
+	if (!samples)
+		return NULL;
+
+	*N = sample_count;
+
+	for (i = 0; i < sample_count; i++)  {
+		offset = offset % (AUD_RDS_LINES*bpl);
+		samples[i] = cx_read(srch->fifo_start + offset);
+		offset += 4;
+	}
+
+	if (dsp_debug >= 2) {
+		dprintk(2, "RDS samples dump: ");
+		for (i = 0; i < sample_count; i++)
+			printk("%hd ", samples[i]);
+		printk(".\n");
+	}
+
+	return samples;
+}
+
+s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core)
+{
+	s16 *samples;
+	u32 N = 0;
+	s32 ret = UNSET;
+
+	/* If audio RDS fifo is disabled, we can't read the samples */
+	if (!(cx_read(MO_AUD_DMACNTRL) & 0x04))
+		return ret;
+	if (!(cx_read(AUD_CTL) & EN_FMRADIO_EN_RDS))
+		return ret;
+
+	/* Wait at least 500 ms after an audio standard change */
+	if (time_before(jiffies, core->last_change + msecs_to_jiffies(500)))
+		return ret;
+
+	samples = read_rds_samples(core, &N);
+
+	if (!samples)
+		return ret;
+
+	switch (core->tvaudio) {
+	case WW_BG:
+	case WW_DK:
+	case WW_EIAJ:
+	case WW_M:
+		ret = detect_a2_a2m_eiaj(core, samples, N);
+		break;
+	case WW_BTSC:
+		ret = detect_btsc(core, samples, N);
+		break;
+	case WW_NONE:
+	case WW_I:
+	case WW_L:
+	case WW_I2SPT:
+	case WW_FM:
+	case WW_I2SADC:
+		break;
+	}
+
+	kfree(samples);
+
+	if (UNSET != ret)
+		dprintk(1, "stereo/sap detection result:%s%s%s\n",
+			   (ret & V4L2_TUNER_SUB_MONO) ? " mono" : "",
+			   (ret & V4L2_TUNER_SUB_STEREO) ? " stereo" : "",
+			   (ret & V4L2_TUNER_SUB_LANG2) ? " dual" : "");
+
+	return ret;
+}
+EXPORT_SYMBOL(cx88_dsp_detect_stereo_sap);
+
diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c
new file mode 100644
index 0000000..d803bba
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-dvb.c
@@ -0,0 +1,1778 @@
+/*
+ *
+ * device driver for Conexant 2388x based TV cards
+ * MPEG Transport Stream (DVB) routines
+ *
+ * (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/file.h>
+#include <linux/suspend.h>
+
+#include "cx88.h"
+#include "dvb-pll.h"
+#include <media/v4l2-common.h>
+
+#include "mt352.h"
+#include "mt352_priv.h"
+#include "cx88-vp3054-i2c.h"
+#include "zl10353.h"
+#include "cx22702.h"
+#include "or51132.h"
+#include "lgdt330x.h"
+#include "s5h1409.h"
+#include "xc4000.h"
+#include "xc5000.h"
+#include "nxt200x.h"
+#include "cx24123.h"
+#include "isl6421.h"
+#include "tuner-simple.h"
+#include "tda9887.h"
+#include "s5h1411.h"
+#include "stv0299.h"
+#include "z0194a.h"
+#include "stv0288.h"
+#include "stb6000.h"
+#include "cx24116.h"
+#include "stv0900.h"
+#include "stb6100.h"
+#include "stb6100_proc.h"
+#include "mb86a16.h"
+#include "ds3000.h"
+
+MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
+MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CX88_VERSION);
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages [dvb]");
+
+static unsigned int dvb_buf_tscnt = 32;
+module_param(dvb_buf_tscnt, int, 0644);
+MODULE_PARM_DESC(dvb_buf_tscnt, "DVB Buffer TS count [dvb]");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define dprintk(level,fmt, arg...)	if (debug >= level) \
+	printk(KERN_DEBUG "%s/2-dvb: " fmt, core->name, ## arg)
+
+/* ------------------------------------------------------------------ */
+
+static int dvb_buf_setup(struct videobuf_queue *q,
+			 unsigned int *count, unsigned int *size)
+{
+	struct cx8802_dev *dev = q->priv_data;
+
+	dev->ts_packet_size  = 188 * 4;
+	dev->ts_packet_count = dvb_buf_tscnt;
+
+	*size  = dev->ts_packet_size * dev->ts_packet_count;
+	*count = dvb_buf_tscnt;
+	return 0;
+}
+
+static int dvb_buf_prepare(struct videobuf_queue *q,
+			   struct videobuf_buffer *vb, enum v4l2_field field)
+{
+	struct cx8802_dev *dev = q->priv_data;
+	return cx8802_buf_prepare(q, dev, (struct cx88_buffer*)vb,field);
+}
+
+static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct cx8802_dev *dev = q->priv_data;
+	cx8802_buf_queue(dev, (struct cx88_buffer*)vb);
+}
+
+static void dvb_buf_release(struct videobuf_queue *q,
+			    struct videobuf_buffer *vb)
+{
+	cx88_free_buffer(q, (struct cx88_buffer*)vb);
+}
+
+static const struct videobuf_queue_ops dvb_qops = {
+	.buf_setup    = dvb_buf_setup,
+	.buf_prepare  = dvb_buf_prepare,
+	.buf_queue    = dvb_buf_queue,
+	.buf_release  = dvb_buf_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx8802_driver *drv = NULL;
+	int ret = 0;
+	int fe_id;
+
+	fe_id = videobuf_dvb_find_frontend(&dev->frontends, fe);
+	if (!fe_id) {
+		printk(KERN_ERR "%s() No frontend found\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&dev->core->lock);
+	drv = cx8802_get_driver(dev, CX88_MPEG_DVB);
+	if (drv) {
+		if (acquire){
+			dev->frontends.active_fe_id = fe_id;
+			ret = drv->request_acquire(drv);
+		} else {
+			ret = drv->request_release(drv);
+			dev->frontends.active_fe_id = 0;
+		}
+	}
+	mutex_unlock(&dev->core->lock);
+
+	return ret;
+}
+
+static void cx88_dvb_gate_ctrl(struct cx88_core  *core, int open)
+{
+	struct videobuf_dvb_frontends *f;
+	struct videobuf_dvb_frontend *fe;
+
+	if (!core->dvbdev)
+		return;
+
+	f = &core->dvbdev->frontends;
+
+	if (!f)
+		return;
+
+	if (f->gate <= 1) /* undefined or fe0 */
+		fe = videobuf_dvb_get_frontend(f, 1);
+	else
+		fe = videobuf_dvb_get_frontend(f, f->gate);
+
+	if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
+		fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open);
+}
+
+/* ------------------------------------------------------------------ */
+
+static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
+{
+	static const u8 clock_config []  = { CLOCK_CTL,  0x38, 0x39 };
+	static const u8 reset []         = { RESET,      0x80 };
+	static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+	static const u8 agc_cfg []       = { AGC_TARGET, 0x24, 0x20 };
+	static const u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
+	static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(200);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+	return 0;
+}
+
+static int dvico_dual_demod_init(struct dvb_frontend *fe)
+{
+	static const u8 clock_config []  = { CLOCK_CTL,  0x38, 0x38 };
+	static const u8 reset []         = { RESET,      0x80 };
+	static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+	static const u8 agc_cfg []       = { AGC_TARGET, 0x28, 0x20 };
+	static const u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
+	static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(200);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+	return 0;
+}
+
+static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
+{
+	static const u8 clock_config []  = { 0x89, 0x38, 0x39 };
+	static const u8 reset []         = { 0x50, 0x80 };
+	static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+	static const u8 agc_cfg []       = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
+				       0x00, 0xFF, 0x00, 0x40, 0x40 };
+	static const u8 dntv_extra[]     = { 0xB5, 0x7A };
+	static const u8 capt_range_cfg[] = { 0x75, 0x32 };
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(2000);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	udelay(2000);
+	mt352_write(fe, dntv_extra,     sizeof(dntv_extra));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+	return 0;
+}
+
+static const struct mt352_config dvico_fusionhdtv = {
+	.demod_address = 0x0f,
+	.demod_init    = dvico_fusionhdtv_demod_init,
+};
+
+static const struct mt352_config dntv_live_dvbt_config = {
+	.demod_address = 0x0f,
+	.demod_init    = dntv_live_dvbt_demod_init,
+};
+
+static const struct mt352_config dvico_fusionhdtv_dual = {
+	.demod_address = 0x0f,
+	.demod_init    = dvico_dual_demod_init,
+};
+
+static const struct zl10353_config cx88_terratec_cinergy_ht_pci_mkii_config = {
+	.demod_address = (0x1e >> 1),
+	.no_tuner      = 1,
+	.if2           = 45600,
+};
+
+static struct mb86a16_config twinhan_vp1027 = {
+	.demod_address  = 0x08,
+};
+
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
+static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
+{
+	static const u8 clock_config []  = { 0x89, 0x38, 0x38 };
+	static const u8 reset []         = { 0x50, 0x80 };
+	static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+	static const u8 agc_cfg []       = { 0x67, 0x10, 0x20, 0x00, 0xFF, 0xFF,
+				       0x00, 0xFF, 0x00, 0x40, 0x40 };
+	static const u8 dntv_extra[]     = { 0xB5, 0x7A };
+	static const u8 capt_range_cfg[] = { 0x75, 0x32 };
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(2000);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	udelay(2000);
+	mt352_write(fe, dntv_extra,     sizeof(dntv_extra));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+	return 0;
+}
+
+static const struct mt352_config dntv_live_dvbt_pro_config = {
+	.demod_address = 0x0f,
+	.no_tuner      = 1,
+	.demod_init    = dntv_live_dvbt_pro_demod_init,
+};
+#endif
+
+static const struct zl10353_config dvico_fusionhdtv_hybrid = {
+	.demod_address = 0x0f,
+	.no_tuner      = 1,
+};
+
+static const struct zl10353_config dvico_fusionhdtv_xc3028 = {
+	.demod_address = 0x0f,
+	.if2           = 45600,
+	.no_tuner      = 1,
+};
+
+static const struct mt352_config dvico_fusionhdtv_mt352_xc3028 = {
+	.demod_address = 0x0f,
+	.if2 = 4560,
+	.no_tuner = 1,
+	.demod_init = dvico_fusionhdtv_demod_init,
+};
+
+static const struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
+	.demod_address = 0x0f,
+};
+
+static const struct cx22702_config connexant_refboard_config = {
+	.demod_address = 0x43,
+	.output_mode   = CX22702_SERIAL_OUTPUT,
+};
+
+static const struct cx22702_config hauppauge_hvr_config = {
+	.demod_address = 0x63,
+	.output_mode   = CX22702_SERIAL_OUTPUT,
+};
+
+static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
+	return 0;
+}
+
+static const struct or51132_config pchdtv_hd3000 = {
+	.demod_address = 0x15,
+	.set_ts_params = or51132_set_ts_param,
+};
+
+static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx88_core *core = dev->core;
+
+	dprintk(1, "%s: index = %d\n", __func__, index);
+	if (index == 0)
+		cx_clear(MO_GP0_IO, 8);
+	else
+		cx_set(MO_GP0_IO, 8);
+	return 0;
+}
+
+static int lgdt330x_set_ts_param(struct dvb_frontend* fe, int is_punctured)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	if (is_punctured)
+		dev->ts_gen_cntrl |= 0x04;
+	else
+		dev->ts_gen_cntrl &= ~0x04;
+	return 0;
+}
+
+static struct lgdt330x_config fusionhdtv_3_gold = {
+	.demod_address = 0x0e,
+	.demod_chip    = LGDT3302,
+	.serial_mpeg   = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */
+	.set_ts_params = lgdt330x_set_ts_param,
+};
+
+static const struct lgdt330x_config fusionhdtv_5_gold = {
+	.demod_address = 0x0e,
+	.demod_chip    = LGDT3303,
+	.serial_mpeg   = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
+	.set_ts_params = lgdt330x_set_ts_param,
+};
+
+static const struct lgdt330x_config pchdtv_hd5500 = {
+	.demod_address = 0x59,
+	.demod_chip    = LGDT3303,
+	.serial_mpeg   = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
+	.set_ts_params = lgdt330x_set_ts_param,
+};
+
+static int nxt200x_set_ts_param(struct dvb_frontend* fe, int is_punctured)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
+	return 0;
+}
+
+static const struct nxt200x_config ati_hdtvwonder = {
+	.demod_address = 0x0a,
+	.set_ts_params = nxt200x_set_ts_param,
+};
+
+static int cx24123_set_ts_param(struct dvb_frontend* fe,
+	int is_punctured)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	dev->ts_gen_cntrl = 0x02;
+	return 0;
+}
+
+static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe,
+				       fe_sec_voltage_t voltage)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx88_core *core = dev->core;
+
+	if (voltage == SEC_VOLTAGE_OFF)
+		cx_write(MO_GP0_IO, 0x000006fb);
+	else
+		cx_write(MO_GP0_IO, 0x000006f9);
+
+	if (core->prev_set_voltage)
+		return core->prev_set_voltage(fe, voltage);
+	return 0;
+}
+
+static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe,
+				      fe_sec_voltage_t voltage)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx88_core *core = dev->core;
+
+	if (voltage == SEC_VOLTAGE_OFF) {
+		dprintk(1,"LNB Voltage OFF\n");
+		cx_write(MO_GP0_IO, 0x0000efff);
+	}
+
+	if (core->prev_set_voltage)
+		return core->prev_set_voltage(fe, voltage);
+	return 0;
+}
+
+static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
+				      fe_sec_voltage_t voltage)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx88_core *core = dev->core;
+
+	cx_set(MO_GP0_IO, 0x6040);
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		cx_clear(MO_GP0_IO, 0x20);
+		break;
+	case SEC_VOLTAGE_18:
+		cx_set(MO_GP0_IO, 0x20);
+		break;
+	case SEC_VOLTAGE_OFF:
+		cx_clear(MO_GP0_IO, 0x20);
+		break;
+	}
+
+	if (core->prev_set_voltage)
+		return core->prev_set_voltage(fe, voltage);
+	return 0;
+}
+
+static int vp1027_set_voltage(struct dvb_frontend *fe,
+				    fe_sec_voltage_t voltage)
+{
+	struct cx8802_dev *dev = fe->dvb->priv;
+	struct cx88_core *core = dev->core;
+
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		dprintk(1, "LNB SEC Voltage=13\n");
+		cx_write(MO_GP0_IO, 0x00001220);
+		break;
+	case SEC_VOLTAGE_18:
+		dprintk(1, "LNB SEC Voltage=18\n");
+		cx_write(MO_GP0_IO, 0x00001222);
+		break;
+	case SEC_VOLTAGE_OFF:
+		dprintk(1, "LNB Voltage OFF\n");
+		cx_write(MO_GP0_IO, 0x00001230);
+		break;
+	}
+
+	if (core->prev_set_voltage)
+		return core->prev_set_voltage(fe, voltage);
+	return 0;
+}
+
+static const struct cx24123_config geniatech_dvbs_config = {
+	.demod_address = 0x55,
+	.set_ts_params = cx24123_set_ts_param,
+};
+
+static const struct cx24123_config hauppauge_novas_config = {
+	.demod_address = 0x55,
+	.set_ts_params = cx24123_set_ts_param,
+};
+
+static const struct cx24123_config kworld_dvbs_100_config = {
+	.demod_address = 0x15,
+	.set_ts_params = cx24123_set_ts_param,
+	.lnb_polarity  = 1,
+};
+
+static const struct s5h1409_config pinnacle_pctv_hd_800i_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_PARALLEL_OUTPUT,
+	.gpio	       = S5H1409_GPIO_ON,
+	.qam_if	       = 44000,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK,
+};
+
+static const struct s5h1409_config dvico_hdtv5_pci_nano_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_SERIAL_OUTPUT,
+	.gpio          = S5H1409_GPIO_OFF,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static const struct s5h1409_config kworld_atsc_120_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_SERIAL_OUTPUT,
+	.gpio	       = S5H1409_GPIO_OFF,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static const struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
+	.i2c_address	= 0x64,
+	.if_khz		= 5380,
+};
+
+static const struct zl10353_config cx88_pinnacle_hybrid_pctv = {
+	.demod_address = (0x1e >> 1),
+	.no_tuner      = 1,
+	.if2           = 45600,
+};
+
+static const struct zl10353_config cx88_geniatech_x8000_mt = {
+	.demod_address = (0x1e >> 1),
+	.no_tuner = 1,
+	.disable_i2c_gate_ctrl = 1,
+};
+
+static const struct s5h1411_config dvico_fusionhdtv7_config = {
+	.output_mode   = S5H1411_SERIAL_OUTPUT,
+	.gpio          = S5H1411_GPIO_ON,
+	.mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+	.qam_if        = S5H1411_IF_44000,
+	.vsb_if        = S5H1411_IF_44000,
+	.inversion     = S5H1411_INVERSION_OFF,
+	.status_mode   = S5H1411_DEMODLOCKING
+};
+
+static const struct xc5000_config dvico_fusionhdtv7_tuner_config = {
+	.i2c_address    = 0xc2 >> 1,
+	.if_khz         = 5380,
+};
+
+static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
+{
+	struct dvb_frontend *fe;
+	struct videobuf_dvb_frontend *fe0 = NULL;
+	struct xc2028_ctrl ctl;
+	struct xc2028_config cfg = {
+		.i2c_adap  = &dev->core->i2c_adap,
+		.i2c_addr  = addr,
+		.ctrl      = &ctl,
+	};
+
+	/* Get the first frontend */
+	fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+	if (!fe0)
+		return -EINVAL;
+
+	if (!fe0->dvb.frontend) {
+		printk(KERN_ERR "%s/2: dvb frontend not attached. "
+				"Can't attach xc3028\n",
+		       dev->core->name);
+		return -EINVAL;
+	}
+
+	/*
+	 * Some xc3028 devices may be hidden by an I2C gate. This is known
+	 * to happen with some s5h1409-based devices.
+	 * Now that I2C gate is open, sets up xc3028 configuration
+	 */
+	cx88_setup_xc3028(dev->core, &ctl);
+
+	fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
+	if (!fe) {
+		printk(KERN_ERR "%s/2: xc3028 attach failed\n",
+		       dev->core->name);
+		dvb_frontend_detach(fe0->dvb.frontend);
+		dvb_unregister_frontend(fe0->dvb.frontend);
+		fe0->dvb.frontend = NULL;
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "%s/2: xc3028 attached\n",
+	       dev->core->name);
+
+	return 0;
+}
+
+static int attach_xc4000(struct cx8802_dev *dev, struct xc4000_config *cfg)
+{
+	struct dvb_frontend *fe;
+	struct videobuf_dvb_frontend *fe0 = NULL;
+
+	/* Get the first frontend */
+	fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+	if (!fe0)
+		return -EINVAL;
+
+	if (!fe0->dvb.frontend) {
+		printk(KERN_ERR "%s/2: dvb frontend not attached. "
+				"Can't attach xc4000\n",
+		       dev->core->name);
+		return -EINVAL;
+	}
+
+	fe = dvb_attach(xc4000_attach, fe0->dvb.frontend, &dev->core->i2c_adap,
+			cfg);
+	if (!fe) {
+		printk(KERN_ERR "%s/2: xc4000 attach failed\n",
+		       dev->core->name);
+		dvb_frontend_detach(fe0->dvb.frontend);
+		dvb_unregister_frontend(fe0->dvb.frontend);
+		fe0->dvb.frontend = NULL;
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "%s/2: xc4000 attached\n", dev->core->name);
+
+	return 0;
+}
+
+static int cx24116_set_ts_param(struct dvb_frontend *fe,
+	int is_punctured)
+{
+	struct cx8802_dev *dev = fe->dvb->priv;
+	dev->ts_gen_cntrl = 0x2;
+
+	return 0;
+}
+
+static int stv0900_set_ts_param(struct dvb_frontend *fe,
+	int is_punctured)
+{
+	struct cx8802_dev *dev = fe->dvb->priv;
+	dev->ts_gen_cntrl = 0;
+
+	return 0;
+}
+
+static int cx24116_reset_device(struct dvb_frontend *fe)
+{
+	struct cx8802_dev *dev = fe->dvb->priv;
+	struct cx88_core *core = dev->core;
+
+	/* Reset the part */
+	/* Put the cx24116 into reset */
+	cx_write(MO_SRST_IO, 0);
+	msleep(10);
+	/* Take the cx24116 out of reset */
+	cx_write(MO_SRST_IO, 1);
+	msleep(10);
+
+	return 0;
+}
+
+static const struct cx24116_config hauppauge_hvr4000_config = {
+	.demod_address          = 0x05,
+	.set_ts_params          = cx24116_set_ts_param,
+	.reset_device           = cx24116_reset_device,
+};
+
+static const struct cx24116_config tevii_s460_config = {
+	.demod_address = 0x55,
+	.set_ts_params = cx24116_set_ts_param,
+	.reset_device  = cx24116_reset_device,
+};
+
+static int ds3000_set_ts_param(struct dvb_frontend *fe,
+	int is_punctured)
+{
+	struct cx8802_dev *dev = fe->dvb->priv;
+	dev->ts_gen_cntrl = 4;
+
+	return 0;
+}
+
+static struct ds3000_config tevii_ds3000_config = {
+	.demod_address = 0x68,
+	.set_ts_params = ds3000_set_ts_param,
+};
+
+static const struct stv0900_config prof_7301_stv0900_config = {
+	.demod_address = 0x6a,
+/*	demod_mode = 0,*/
+	.xtal = 27000000,
+	.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
+	.diseqc_mode = 2,/* 2/3 PWM */
+	.tun1_maddress = 0,/* 0x60 */
+	.tun1_adc = 0,/* 2 Vpp */
+	.path1_mode = 3,
+	.set_ts_params = stv0900_set_ts_param,
+};
+
+static const struct stb6100_config prof_7301_stb6100_config = {
+	.tuner_address = 0x60,
+	.refclock = 27000000,
+};
+
+static const struct stv0299_config tevii_tuner_sharp_config = {
+	.demod_address = 0x68,
+	.inittab = sharp_z0194a_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.skip_reinit = 0,
+	.lock_output = 1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = sharp_z0194a_set_symbol_rate,
+	.set_ts_params = cx24116_set_ts_param,
+};
+
+static const struct stv0288_config tevii_tuner_earda_config = {
+	.demod_address = 0x68,
+	.min_delay_ms = 100,
+	.set_ts_params = cx24116_set_ts_param,
+};
+
+static int cx8802_alloc_frontends(struct cx8802_dev *dev)
+{
+	struct cx88_core *core = dev->core;
+	struct videobuf_dvb_frontend *fe = NULL;
+	int i;
+
+	mutex_init(&dev->frontends.lock);
+	INIT_LIST_HEAD(&dev->frontends.felist);
+
+	if (!core->board.num_frontends)
+		return -ENODEV;
+
+	printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__,
+			 core->board.num_frontends);
+	for (i = 1; i <= core->board.num_frontends; i++) {
+		fe = videobuf_dvb_alloc_frontend(&dev->frontends, i);
+		if (!fe) {
+			printk(KERN_ERR "%s() failed to alloc\n", __func__);
+			videobuf_dvb_dealloc_frontends(&dev->frontends);
+			return -ENOMEM;
+		}
+	}
+	return 0;
+}
+
+
+
+static const u8 samsung_smt_7020_inittab[] = {
+	     0x01, 0x15,
+	     0x02, 0x00,
+	     0x03, 0x00,
+	     0x04, 0x7D,
+	     0x05, 0x0F,
+	     0x06, 0x02,
+	     0x07, 0x00,
+	     0x08, 0x60,
+
+	     0x0A, 0xC2,
+	     0x0B, 0x00,
+	     0x0C, 0x01,
+	     0x0D, 0x81,
+	     0x0E, 0x44,
+	     0x0F, 0x09,
+	     0x10, 0x3C,
+	     0x11, 0x84,
+	     0x12, 0xDA,
+	     0x13, 0x99,
+	     0x14, 0x8D,
+	     0x15, 0xCE,
+	     0x16, 0xE8,
+	     0x17, 0x43,
+	     0x18, 0x1C,
+	     0x19, 0x1B,
+	     0x1A, 0x1D,
+
+	     0x1C, 0x12,
+	     0x1D, 0x00,
+	     0x1E, 0x00,
+	     0x1F, 0x00,
+	     0x20, 0x00,
+	     0x21, 0x00,
+	     0x22, 0x00,
+	     0x23, 0x00,
+
+	     0x28, 0x02,
+	     0x29, 0x28,
+	     0x2A, 0x14,
+	     0x2B, 0x0F,
+	     0x2C, 0x09,
+	     0x2D, 0x05,
+
+	     0x31, 0x1F,
+	     0x32, 0x19,
+	     0x33, 0xFC,
+	     0x34, 0x13,
+	     0xff, 0xff,
+};
+
+
+static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct cx8802_dev *dev = fe->dvb->priv;
+	u8 buf[4];
+	u32 div;
+	struct i2c_msg msg = {
+		.addr = 0x61,
+		.flags = 0,
+		.buf = buf,
+		.len = sizeof(buf) };
+
+	div = c->frequency / 125;
+
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = 0x84;  /* 0xC4 */
+	buf[3] = 0x00;
+
+	if (c->frequency < 1500000)
+		buf[3] |= 0x10;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	if (i2c_transfer(&dev->core->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+
+	return 0;
+}
+
+static int samsung_smt_7020_set_tone(struct dvb_frontend *fe,
+	fe_sec_tone_mode_t tone)
+{
+	struct cx8802_dev *dev = fe->dvb->priv;
+	struct cx88_core *core = dev->core;
+
+	cx_set(MO_GP0_IO, 0x0800);
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		cx_set(MO_GP0_IO, 0x08);
+		break;
+	case SEC_TONE_OFF:
+		cx_clear(MO_GP0_IO, 0x08);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int samsung_smt_7020_set_voltage(struct dvb_frontend *fe,
+	fe_sec_voltage_t voltage)
+{
+	struct cx8802_dev *dev = fe->dvb->priv;
+	struct cx88_core *core = dev->core;
+
+	u8 data;
+	struct i2c_msg msg = {
+		.addr = 8,
+		.flags = 0,
+		.buf = &data,
+		.len = sizeof(data) };
+
+	cx_set(MO_GP0_IO, 0x8000);
+
+	switch (voltage) {
+	case SEC_VOLTAGE_OFF:
+		break;
+	case SEC_VOLTAGE_13:
+		data = ISL6421_EN1 | ISL6421_LLC1;
+		cx_clear(MO_GP0_IO, 0x80);
+		break;
+	case SEC_VOLTAGE_18:
+		data = ISL6421_EN1 | ISL6421_LLC1 | ISL6421_VSEL1;
+		cx_clear(MO_GP0_IO, 0x80);
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	return (i2c_transfer(&dev->core->i2c_adap, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int samsung_smt_7020_stv0299_set_symbol_rate(struct dvb_frontend *fe,
+	u32 srate, u32 ratio)
+{
+	u8 aclk = 0;
+	u8 bclk = 0;
+
+	if (srate < 1500000) {
+		aclk = 0xb7;
+		bclk = 0x47;
+	} else if (srate < 3000000) {
+		aclk = 0xb7;
+		bclk = 0x4b;
+	} else if (srate < 7000000) {
+		aclk = 0xb7;
+		bclk = 0x4f;
+	} else if (srate < 14000000) {
+		aclk = 0xb7;
+		bclk = 0x53;
+	} else if (srate < 30000000) {
+		aclk = 0xb6;
+		bclk = 0x53;
+	} else if (srate < 45000000) {
+		aclk = 0xb4;
+		bclk = 0x51;
+	}
+
+	stv0299_writereg(fe, 0x13, aclk);
+	stv0299_writereg(fe, 0x14, bclk);
+	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+	stv0299_writereg(fe, 0x20, (ratio >>  8) & 0xff);
+	stv0299_writereg(fe, 0x21, ratio & 0xf0);
+
+	return 0;
+}
+
+
+static const struct stv0299_config samsung_stv0299_config = {
+	.demod_address = 0x68,
+	.inittab = samsung_smt_7020_inittab,
+	.mclk = 88000000UL,
+	.invert = 0,
+	.skip_reinit = 0,
+	.lock_output = STV0299_LOCKOUTPUT_LK,
+	.volt13_op0_op1 = STV0299_VOLT13_OP1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = samsung_smt_7020_stv0299_set_symbol_rate,
+};
+
+static int dvb_register(struct cx8802_dev *dev)
+{
+	struct cx88_core *core = dev->core;
+	struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
+	int mfe_shared = 0; /* bus not shared by default */
+	int res = -EINVAL;
+
+	if (0 != core->i2c_rc) {
+		printk(KERN_ERR "%s/2: no i2c-bus available, cannot attach dvb drivers\n", core->name);
+		goto frontend_detach;
+	}
+
+	/* Get the first frontend */
+	fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+	if (!fe0)
+		goto frontend_detach;
+
+	/* multi-frontend gate control is undefined or defaults to fe0 */
+	dev->frontends.gate = 0;
+
+	/* Sets the gate control callback to be used by i2c command calls */
+	core->gate_ctrl = cx88_dvb_gate_ctrl;
+
+	/* init frontend(s) */
+	switch (core->boardnr) {
+	case CX88_BOARD_HAUPPAUGE_DVB_T1:
+		fe0->dvb.frontend = dvb_attach(cx22702_attach,
+					       &connexant_refboard_config,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
+					0x61, &core->i2c_adap,
+					DVB_PLL_THOMSON_DTT759X))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
+	case CX88_BOARD_CONEXANT_DVB_T1:
+	case CX88_BOARD_KWORLD_DVB_T_CX22702:
+	case CX88_BOARD_WINFAST_DTV1000:
+		fe0->dvb.frontend = dvb_attach(cx22702_attach,
+					       &connexant_refboard_config,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
+					0x60, &core->i2c_adap,
+					DVB_PLL_THOMSON_DTT7579))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_WINFAST_DTV2000H:
+	case CX88_BOARD_HAUPPAUGE_HVR1100:
+	case CX88_BOARD_HAUPPAUGE_HVR1100LP:
+	case CX88_BOARD_HAUPPAUGE_HVR1300:
+		fe0->dvb.frontend = dvb_attach(cx22702_attach,
+					       &hauppauge_hvr_config,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+				   &core->i2c_adap, 0x61,
+				   TUNER_PHILIPS_FMD1216ME_MK3))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_WINFAST_DTV2000H_J:
+		fe0->dvb.frontend = dvb_attach(cx22702_attach,
+					       &hauppauge_hvr_config,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+				   &core->i2c_adap, 0x61,
+				   TUNER_PHILIPS_FMD1216MEX_MK3))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_HAUPPAUGE_HVR3000:
+		/* MFE frontend 1 */
+		mfe_shared = 1;
+		dev->frontends.gate = 2;
+		/* DVB-S init */
+		fe0->dvb.frontend = dvb_attach(cx24123_attach,
+					&hauppauge_novas_config,
+					&dev->core->i2c_adap);
+		if (fe0->dvb.frontend) {
+			if (!dvb_attach(isl6421_attach,
+					fe0->dvb.frontend,
+					&dev->core->i2c_adap,
+					0x08, ISL6421_DCL, 0x00))
+				goto frontend_detach;
+		}
+		/* MFE frontend 2 */
+		fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
+		if (!fe1)
+			goto frontend_detach;
+		/* DVB-T init */
+		fe1->dvb.frontend = dvb_attach(cx22702_attach,
+					&hauppauge_hvr_config,
+					&dev->core->i2c_adap);
+		if (fe1->dvb.frontend) {
+			fe1->dvb.frontend->id = 1;
+			if (!dvb_attach(simple_tuner_attach,
+					fe1->dvb.frontend,
+					&dev->core->i2c_adap,
+					0x61, TUNER_PHILIPS_FMD1216ME_MK3))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
+		fe0->dvb.frontend = dvb_attach(mt352_attach,
+					       &dvico_fusionhdtv,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
+					0x60, NULL, DVB_PLL_THOMSON_DTT7579))
+				goto frontend_detach;
+			break;
+		}
+		/* ZL10353 replaces MT352 on later cards */
+		fe0->dvb.frontend = dvb_attach(zl10353_attach,
+					       &dvico_fusionhdtv_plus_v1_1,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
+					0x60, NULL, DVB_PLL_THOMSON_DTT7579))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+		/* The tin box says DEE1601, but it seems to be DTT7579
+		 * compatible, with a slightly different MT352 AGC gain. */
+		fe0->dvb.frontend = dvb_attach(mt352_attach,
+					       &dvico_fusionhdtv_dual,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
+					0x61, NULL, DVB_PLL_THOMSON_DTT7579))
+				goto frontend_detach;
+			break;
+		}
+		/* ZL10353 replaces MT352 on later cards */
+		fe0->dvb.frontend = dvb_attach(zl10353_attach,
+					       &dvico_fusionhdtv_plus_v1_1,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
+					0x61, NULL, DVB_PLL_THOMSON_DTT7579))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
+		fe0->dvb.frontend = dvb_attach(mt352_attach,
+					       &dvico_fusionhdtv,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
+					0x61, NULL, DVB_PLL_LG_Z201))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_KWORLD_DVB_T:
+	case CX88_BOARD_DNTV_LIVE_DVB_T:
+	case CX88_BOARD_ADSTECH_DVB_T_PCI:
+		fe0->dvb.frontend = dvb_attach(mt352_attach,
+					       &dntv_live_dvbt_config,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
+					0x61, NULL, DVB_PLL_UNKNOWN_1))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
+		/* MT352 is on a secondary I2C bus made from some GPIO lines */
+		fe0->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
+					       &dev->vp3054->adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+					&core->i2c_adap, 0x61,
+					TUNER_PHILIPS_FMD1216ME_MK3))
+				goto frontend_detach;
+		}
+#else
+		printk(KERN_ERR "%s/2: built without vp3054 support\n",
+				core->name);
+#endif
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
+		fe0->dvb.frontend = dvb_attach(zl10353_attach,
+					       &dvico_fusionhdtv_hybrid,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+				   &core->i2c_adap, 0x61,
+				   TUNER_THOMSON_FE6600))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+		fe0->dvb.frontend = dvb_attach(zl10353_attach,
+					       &dvico_fusionhdtv_xc3028,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend == NULL)
+			fe0->dvb.frontend = dvb_attach(mt352_attach,
+						&dvico_fusionhdtv_mt352_xc3028,
+						&core->i2c_adap);
+		/*
+		 * On this board, the demod provides the I2C bus pullup.
+		 * We must not permit gate_ctrl to be performed, or
+		 * the xc3028 cannot communicate on the bus.
+		 */
+		if (fe0->dvb.frontend)
+			fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+		if (attach_xc3028(0x61, dev) < 0)
+			goto frontend_detach;
+		break;
+	case CX88_BOARD_PCHDTV_HD3000:
+		fe0->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+					&core->i2c_adap, 0x61,
+					TUNER_THOMSON_DTT761X))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
+		dev->ts_gen_cntrl = 0x08;
+
+		/* Do a hardware reset of chip before using it. */
+		cx_clear(MO_GP0_IO, 1);
+		mdelay(100);
+		cx_set(MO_GP0_IO, 1);
+		mdelay(200);
+
+		/* Select RF connector callback */
+		fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set;
+		fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
+					       &fusionhdtv_3_gold,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+					&core->i2c_adap, 0x61,
+					TUNER_MICROTUNE_4042FI5))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
+		dev->ts_gen_cntrl = 0x08;
+
+		/* Do a hardware reset of chip before using it. */
+		cx_clear(MO_GP0_IO, 1);
+		mdelay(100);
+		cx_set(MO_GP0_IO, 9);
+		mdelay(200);
+		fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
+					       &fusionhdtv_3_gold,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+					&core->i2c_adap, 0x61,
+					TUNER_THOMSON_DTT761X))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
+		dev->ts_gen_cntrl = 0x08;
+
+		/* Do a hardware reset of chip before using it. */
+		cx_clear(MO_GP0_IO, 1);
+		mdelay(100);
+		cx_set(MO_GP0_IO, 1);
+		mdelay(200);
+		fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
+					       &fusionhdtv_5_gold,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+					&core->i2c_adap, 0x61,
+					TUNER_LG_TDVS_H06XF))
+				goto frontend_detach;
+			if (!dvb_attach(tda9887_attach, fe0->dvb.frontend,
+				   &core->i2c_adap, 0x43))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_PCHDTV_HD5500:
+		dev->ts_gen_cntrl = 0x08;
+
+		/* Do a hardware reset of chip before using it. */
+		cx_clear(MO_GP0_IO, 1);
+		mdelay(100);
+		cx_set(MO_GP0_IO, 1);
+		mdelay(200);
+		fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
+					       &pchdtv_hd5500,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+					&core->i2c_adap, 0x61,
+					TUNER_LG_TDVS_H06XF))
+				goto frontend_detach;
+			if (!dvb_attach(tda9887_attach, fe0->dvb.frontend,
+				   &core->i2c_adap, 0x43))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_ATI_HDTVWONDER:
+		fe0->dvb.frontend = dvb_attach(nxt200x_attach,
+					       &ati_hdtvwonder,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+					&core->i2c_adap, 0x61,
+					TUNER_PHILIPS_TUV1236D))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+	case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+		fe0->dvb.frontend = dvb_attach(cx24123_attach,
+					       &hauppauge_novas_config,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend) {
+			if (!dvb_attach(isl6421_attach, fe0->dvb.frontend,
+					&core->i2c_adap, 0x08, ISL6421_DCL, 0x00))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_KWORLD_DVBS_100:
+		fe0->dvb.frontend = dvb_attach(cx24123_attach,
+					       &kworld_dvbs_100_config,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend) {
+			core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+			fe0->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
+		}
+		break;
+	case CX88_BOARD_GENIATECH_DVBS:
+		fe0->dvb.frontend = dvb_attach(cx24123_attach,
+					       &geniatech_dvbs_config,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend) {
+			core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+			fe0->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
+		}
+		break;
+	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
+		fe0->dvb.frontend = dvb_attach(s5h1409_attach,
+					       &pinnacle_pctv_hd_800i_config,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(xc5000_attach, fe0->dvb.frontend,
+					&core->i2c_adap,
+					&pinnacle_pctv_hd_800i_tuner_config))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
+		fe0->dvb.frontend = dvb_attach(s5h1409_attach,
+						&dvico_hdtv5_pci_nano_config,
+						&core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			struct dvb_frontend *fe;
+			struct xc2028_config cfg = {
+				.i2c_adap  = &core->i2c_adap,
+				.i2c_addr  = 0x61,
+			};
+			static struct xc2028_ctrl ctl = {
+				.fname       = XC2028_DEFAULT_FIRMWARE,
+				.max_len     = 64,
+				.scode_table = XC3028_FE_OREN538,
+			};
+
+			fe = dvb_attach(xc2028_attach,
+					fe0->dvb.frontend, &cfg);
+			if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+				fe->ops.tuner_ops.set_config(fe, &ctl);
+		}
+		break;
+	case CX88_BOARD_PINNACLE_HYBRID_PCTV:
+	case CX88_BOARD_WINFAST_DTV1800H:
+		fe0->dvb.frontend = dvb_attach(zl10353_attach,
+					       &cx88_pinnacle_hybrid_pctv,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend) {
+			fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+			if (attach_xc3028(0x61, dev) < 0)
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_WINFAST_DTV1800H_XC4000:
+	case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+		fe0->dvb.frontend = dvb_attach(zl10353_attach,
+					       &cx88_pinnacle_hybrid_pctv,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend) {
+			struct xc4000_config cfg = {
+				.i2c_address	  = 0x61,
+				.default_pm	  = 0,
+				.dvb_amplitude	  = 134,
+				.set_smoothedcvbs = 1,
+				.if_khz		  = 4560
+			};
+			fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+			if (attach_xc4000(dev, &cfg) < 0)
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_GENIATECH_X8000_MT:
+		dev->ts_gen_cntrl = 0x00;
+
+		fe0->dvb.frontend = dvb_attach(zl10353_attach,
+					       &cx88_geniatech_x8000_mt,
+					       &core->i2c_adap);
+		if (attach_xc3028(0x61, dev) < 0)
+			goto frontend_detach;
+		break;
+	 case CX88_BOARD_KWORLD_ATSC_120:
+		fe0->dvb.frontend = dvb_attach(s5h1409_attach,
+					       &kworld_atsc_120_config,
+					       &core->i2c_adap);
+		if (attach_xc3028(0x61, dev) < 0)
+			goto frontend_detach;
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
+		fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+					       &dvico_fusionhdtv7_config,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(xc5000_attach, fe0->dvb.frontend,
+					&core->i2c_adap,
+					&dvico_fusionhdtv7_tuner_config))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_HAUPPAUGE_HVR4000:
+		/* MFE frontend 1 */
+		mfe_shared = 1;
+		dev->frontends.gate = 2;
+		/* DVB-S/S2 Init */
+		fe0->dvb.frontend = dvb_attach(cx24116_attach,
+					&hauppauge_hvr4000_config,
+					&dev->core->i2c_adap);
+		if (fe0->dvb.frontend) {
+			if (!dvb_attach(isl6421_attach,
+					fe0->dvb.frontend,
+					&dev->core->i2c_adap,
+					0x08, ISL6421_DCL, 0x00))
+				goto frontend_detach;
+		}
+		/* MFE frontend 2 */
+		fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
+		if (!fe1)
+			goto frontend_detach;
+		/* DVB-T Init */
+		fe1->dvb.frontend = dvb_attach(cx22702_attach,
+					&hauppauge_hvr_config,
+					&dev->core->i2c_adap);
+		if (fe1->dvb.frontend) {
+			fe1->dvb.frontend->id = 1;
+			if (!dvb_attach(simple_tuner_attach,
+					fe1->dvb.frontend,
+					&dev->core->i2c_adap,
+					0x61, TUNER_PHILIPS_FMD1216ME_MK3))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+		fe0->dvb.frontend = dvb_attach(cx24116_attach,
+					&hauppauge_hvr4000_config,
+					&dev->core->i2c_adap);
+		if (fe0->dvb.frontend) {
+			if (!dvb_attach(isl6421_attach,
+					fe0->dvb.frontend,
+					&dev->core->i2c_adap,
+					0x08, ISL6421_DCL, 0x00))
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_PROF_6200:
+	case CX88_BOARD_TBS_8910:
+	case CX88_BOARD_TEVII_S420:
+		fe0->dvb.frontend = dvb_attach(stv0299_attach,
+						&tevii_tuner_sharp_config,
+						&core->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60,
+					&core->i2c_adap, DVB_PLL_OPERA1))
+				goto frontend_detach;
+			core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+			fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+
+		} else {
+			fe0->dvb.frontend = dvb_attach(stv0288_attach,
+							    &tevii_tuner_earda_config,
+							    &core->i2c_adap);
+				if (fe0->dvb.frontend != NULL) {
+					if (!dvb_attach(stb6000_attach, fe0->dvb.frontend, 0x61,
+						&core->i2c_adap))
+					goto frontend_detach;
+				core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+				fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+			}
+		}
+		break;
+	case CX88_BOARD_TEVII_S460:
+		fe0->dvb.frontend = dvb_attach(cx24116_attach,
+					       &tevii_s460_config,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL)
+			fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+		break;
+	case CX88_BOARD_TEVII_S464:
+		fe0->dvb.frontend = dvb_attach(ds3000_attach,
+						&tevii_ds3000_config,
+						&core->i2c_adap);
+		if (fe0->dvb.frontend != NULL)
+			fe0->dvb.frontend->ops.set_voltage =
+							tevii_dvbs_set_voltage;
+		break;
+	case CX88_BOARD_OMICOM_SS4_PCI:
+	case CX88_BOARD_TBS_8920:
+	case CX88_BOARD_PROF_7300:
+	case CX88_BOARD_SATTRADE_ST4200:
+		fe0->dvb.frontend = dvb_attach(cx24116_attach,
+					       &hauppauge_hvr4000_config,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend != NULL)
+			fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+		break;
+	case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII:
+		fe0->dvb.frontend = dvb_attach(zl10353_attach,
+					       &cx88_terratec_cinergy_ht_pci_mkii_config,
+					       &core->i2c_adap);
+		if (fe0->dvb.frontend) {
+			fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+			if (attach_xc3028(0x61, dev) < 0)
+				goto frontend_detach;
+		}
+		break;
+	case CX88_BOARD_PROF_7301:{
+		struct dvb_tuner_ops *tuner_ops = NULL;
+
+		fe0->dvb.frontend = dvb_attach(stv0900_attach,
+						&prof_7301_stv0900_config,
+						&core->i2c_adap, 0);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(stb6100_attach, fe0->dvb.frontend,
+					&prof_7301_stb6100_config,
+					&core->i2c_adap))
+				goto frontend_detach;
+
+			tuner_ops = &fe0->dvb.frontend->ops.tuner_ops;
+			tuner_ops->set_frequency = stb6100_set_freq;
+			tuner_ops->get_frequency = stb6100_get_freq;
+			tuner_ops->set_bandwidth = stb6100_set_bandw;
+			tuner_ops->get_bandwidth = stb6100_get_bandw;
+
+			core->prev_set_voltage =
+					fe0->dvb.frontend->ops.set_voltage;
+			fe0->dvb.frontend->ops.set_voltage =
+					tevii_dvbs_set_voltage;
+		}
+		break;
+		}
+	case CX88_BOARD_SAMSUNG_SMT_7020:
+		dev->ts_gen_cntrl = 0x08;
+
+		cx_set(MO_GP0_IO, 0x0101);
+
+		cx_clear(MO_GP0_IO, 0x01);
+		mdelay(100);
+		cx_set(MO_GP0_IO, 0x01);
+		mdelay(200);
+
+		fe0->dvb.frontend = dvb_attach(stv0299_attach,
+					&samsung_stv0299_config,
+					&dev->core->i2c_adap);
+		if (fe0->dvb.frontend) {
+			fe0->dvb.frontend->ops.tuner_ops.set_params =
+				samsung_smt_7020_tuner_set_params;
+			fe0->dvb.frontend->tuner_priv =
+				&dev->core->i2c_adap;
+			fe0->dvb.frontend->ops.set_voltage =
+				samsung_smt_7020_set_voltage;
+			fe0->dvb.frontend->ops.set_tone =
+				samsung_smt_7020_set_tone;
+		}
+
+		break;
+	case CX88_BOARD_TWINHAN_VP1027_DVBS:
+		dev->ts_gen_cntrl = 0x00;
+		fe0->dvb.frontend = dvb_attach(mb86a16_attach,
+						&twinhan_vp1027,
+						&core->i2c_adap);
+		if (fe0->dvb.frontend) {
+			core->prev_set_voltage =
+					fe0->dvb.frontend->ops.set_voltage;
+			fe0->dvb.frontend->ops.set_voltage =
+					vp1027_set_voltage;
+		}
+		break;
+
+	default:
+		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
+		       core->name);
+		break;
+	}
+
+	if ( (NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend) ) {
+		printk(KERN_ERR
+		       "%s/2: frontend initialization failed\n",
+		       core->name);
+		goto frontend_detach;
+	}
+	/* define general-purpose callback pointer */
+	fe0->dvb.frontend->callback = cx88_tuner_callback;
+
+	/* Ensure all frontends negotiate bus access */
+	fe0->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
+	if (fe1)
+		fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
+
+	/* Put the analog decoder in standby to keep it quiet */
+	call_all(core, core, s_power, 0);
+
+	/* register everything */
+	res = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
+		&dev->pci->dev, adapter_nr, mfe_shared);
+	if (res)
+		goto frontend_detach;
+	return res;
+
+frontend_detach:
+	core->gate_ctrl = NULL;
+	videobuf_dvb_dealloc_frontends(&dev->frontends);
+	return res;
+}
+
+/* ----------------------------------------------------------- */
+
+/* CX8802 MPEG -> mini driver - We have been given the hardware */
+static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
+{
+	struct cx88_core *core = drv->core;
+	int err = 0;
+	dprintk( 1, "%s\n", __func__);
+
+	switch (core->boardnr) {
+	case CX88_BOARD_HAUPPAUGE_HVR1300:
+		/* We arrive here with either the cx23416 or the cx22702
+		 * on the bus. Take the bus from the cx23416 and enable the
+		 * cx22702 demod
+		 */
+		/* Toggle reset on cx22702 leaving i2c active */
+		cx_set(MO_GP0_IO, 0x00000080);
+		udelay(1000);
+		cx_clear(MO_GP0_IO, 0x00000080);
+		udelay(50);
+		cx_set(MO_GP0_IO, 0x00000080);
+		udelay(1000);
+		/* enable the cx22702 pins */
+		cx_clear(MO_GP0_IO, 0x00000004);
+		udelay(1000);
+		break;
+
+	case CX88_BOARD_HAUPPAUGE_HVR3000:
+	case CX88_BOARD_HAUPPAUGE_HVR4000:
+		/* Toggle reset on cx22702 leaving i2c active */
+		cx_set(MO_GP0_IO, 0x00000080);
+		udelay(1000);
+		cx_clear(MO_GP0_IO, 0x00000080);
+		udelay(50);
+		cx_set(MO_GP0_IO, 0x00000080);
+		udelay(1000);
+		switch (core->dvbdev->frontends.active_fe_id) {
+		case 1: /* DVB-S/S2 Enabled */
+			/* tri-state the cx22702 pins */
+			cx_set(MO_GP0_IO, 0x00000004);
+			/* Take the cx24116/cx24123 out of reset */
+			cx_write(MO_SRST_IO, 1);
+			core->dvbdev->ts_gen_cntrl = 0x02; /* Parallel IO */
+			break;
+		case 2: /* DVB-T Enabled */
+			/* Put the cx24116/cx24123 into reset */
+			cx_write(MO_SRST_IO, 0);
+			/* enable the cx22702 pins */
+			cx_clear(MO_GP0_IO, 0x00000004);
+			core->dvbdev->ts_gen_cntrl = 0x0c; /* Serial IO */
+			break;
+		}
+		udelay(1000);
+		break;
+
+	case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+		/* set RF input to AIR for DVB-T (GPIO 16) */
+		cx_write(MO_GP2_IO, 0x0101);
+		break;
+
+	default:
+		err = -ENODEV;
+	}
+	return err;
+}
+
+/* CX8802 MPEG -> mini driver - We no longer have the hardware */
+static int cx8802_dvb_advise_release(struct cx8802_driver *drv)
+{
+	struct cx88_core *core = drv->core;
+	int err = 0;
+	dprintk( 1, "%s\n", __func__);
+
+	switch (core->boardnr) {
+	case CX88_BOARD_HAUPPAUGE_HVR1300:
+		/* Do Nothing, leave the cx22702 on the bus. */
+		break;
+	case CX88_BOARD_HAUPPAUGE_HVR3000:
+	case CX88_BOARD_HAUPPAUGE_HVR4000:
+		break;
+	default:
+		err = -ENODEV;
+	}
+	return err;
+}
+
+static int cx8802_dvb_probe(struct cx8802_driver *drv)
+{
+	struct cx88_core *core = drv->core;
+	struct cx8802_dev *dev = drv->core->dvbdev;
+	int err;
+	struct videobuf_dvb_frontend *fe;
+	int i;
+
+	dprintk( 1, "%s\n", __func__);
+	dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
+		core->boardnr,
+		core->name,
+		core->pci_bus,
+		core->pci_slot);
+
+	err = -ENODEV;
+	if (!(core->board.mpeg & CX88_MPEG_DVB))
+		goto fail_core;
+
+	/* If vp3054 isn't enabled, a stub will just return 0 */
+	err = vp3054_i2c_probe(dev);
+	if (0 != err)
+		goto fail_core;
+
+	/* dvb stuff */
+	printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name);
+	dev->ts_gen_cntrl = 0x0c;
+
+	err = cx8802_alloc_frontends(dev);
+	if (err)
+		goto fail_core;
+
+	err = -ENODEV;
+	for (i = 1; i <= core->board.num_frontends; i++) {
+		fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i);
+		if (fe == NULL) {
+			printk(KERN_ERR "%s() failed to get frontend(%d)\n",
+					__func__, i);
+			goto fail_probe;
+		}
+		videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops,
+				    &dev->pci->dev, &dev->slock,
+				    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+				    V4L2_FIELD_TOP,
+				    sizeof(struct cx88_buffer),
+				    dev, NULL);
+		/* init struct videobuf_dvb */
+		fe->dvb.name = dev->core->name;
+	}
+
+	err = dvb_register(dev);
+	if (err)
+		/* frontends/adapter de-allocated in dvb_register */
+		printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n",
+		       core->name, err);
+	return err;
+fail_probe:
+	videobuf_dvb_dealloc_frontends(&core->dvbdev->frontends);
+fail_core:
+	return err;
+}
+
+static int cx8802_dvb_remove(struct cx8802_driver *drv)
+{
+	struct cx88_core *core = drv->core;
+	struct cx8802_dev *dev = drv->core->dvbdev;
+
+	dprintk( 1, "%s\n", __func__);
+
+	videobuf_dvb_unregister_bus(&dev->frontends);
+
+	vp3054_i2c_remove(dev);
+
+	core->gate_ctrl = NULL;
+
+	return 0;
+}
+
+static struct cx8802_driver cx8802_dvb_driver = {
+	.type_id        = CX88_MPEG_DVB,
+	.hw_access      = CX8802_DRVCTL_SHARED,
+	.probe          = cx8802_dvb_probe,
+	.remove         = cx8802_dvb_remove,
+	.advise_acquire = cx8802_dvb_advise_acquire,
+	.advise_release = cx8802_dvb_advise_release,
+};
+
+static int __init dvb_init(void)
+{
+	printk(KERN_INFO "cx88/2: cx2388x dvb driver version %s loaded\n",
+	       CX88_VERSION);
+	return cx8802_register_driver(&cx8802_dvb_driver);
+}
+
+static void __exit dvb_fini(void)
+{
+	cx8802_unregister_driver(&cx8802_dvb_driver);
+}
+
+module_init(dvb_init);
+module_exit(dvb_fini);
diff --git a/drivers/media/pci/cx88/cx88-i2c.c b/drivers/media/pci/cx88/cx88-i2c.c
new file mode 100644
index 0000000..de0f1af
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-i2c.c
@@ -0,0 +1,184 @@
+
+/*
+
+    cx88-i2c.c  --  all the i2c code is here
+
+    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+			   & Marcus Metzler (mocm@thp.uni-koeln.de)
+    (c) 2002 Yurij Sysoev <yurij@naturesoft.net>
+    (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
+
+    (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
+	- Multituner support and i2c address binding
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "cx88.h"
+#include <media/v4l2-common.h>
+
+static unsigned int i2c_debug;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]");
+
+static unsigned int i2c_scan;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
+
+static unsigned int i2c_udelay = 5;
+module_param(i2c_udelay, int, 0644);
+MODULE_PARM_DESC(i2c_udelay,"i2c delay at insmod time, in usecs "
+		"(should be 5 or higher). Lower value means higher bus speed.");
+
+#define dprintk(level,fmt, arg...)	if (i2c_debug >= level) \
+	printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
+
+/* ----------------------------------------------------------------------- */
+
+static void cx8800_bit_setscl(void *data, int state)
+{
+	struct cx88_core *core = data;
+
+	if (state)
+		core->i2c_state |= 0x02;
+	else
+		core->i2c_state &= ~0x02;
+	cx_write(MO_I2C, core->i2c_state);
+	cx_read(MO_I2C);
+}
+
+static void cx8800_bit_setsda(void *data, int state)
+{
+	struct cx88_core *core = data;
+
+	if (state)
+		core->i2c_state |= 0x01;
+	else
+		core->i2c_state &= ~0x01;
+	cx_write(MO_I2C, core->i2c_state);
+	cx_read(MO_I2C);
+}
+
+static int cx8800_bit_getscl(void *data)
+{
+	struct cx88_core *core = data;
+	u32 state;
+
+	state = cx_read(MO_I2C);
+	return state & 0x02 ? 1 : 0;
+}
+
+static int cx8800_bit_getsda(void *data)
+{
+	struct cx88_core *core = data;
+	u32 state;
+
+	state = cx_read(MO_I2C);
+	return state & 0x01;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_algo_bit_data cx8800_i2c_algo_template = {
+	.setsda  = cx8800_bit_setsda,
+	.setscl  = cx8800_bit_setscl,
+	.getsda  = cx8800_bit_getsda,
+	.getscl  = cx8800_bit_getscl,
+	.udelay  = 16,
+	.timeout = 200,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static const char * const i2c_devs[128] = {
+	[ 0x1c >> 1 ] = "lgdt330x",
+	[ 0x86 >> 1 ] = "tda9887/cx22702",
+	[ 0xa0 >> 1 ] = "eeprom",
+	[ 0xc0 >> 1 ] = "tuner (analog)",
+	[ 0xc2 >> 1 ] = "tuner (analog/dvb)",
+	[ 0xc8 >> 1 ] = "xc5000",
+};
+
+static void do_i2c_scan(const char *name, struct i2c_client *c)
+{
+	unsigned char buf;
+	int i,rc;
+
+	for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
+		c->addr = i;
+		rc = i2c_master_recv(c,&buf,0);
+		if (rc < 0)
+			continue;
+		printk("%s: i2c scan: found device @ 0x%x  [%s]\n",
+		       name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+	}
+}
+
+/* init + register i2c adapter */
+int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
+{
+	/* Prevents usage of invalid delay values */
+	if (i2c_udelay<5)
+		i2c_udelay=5;
+
+	memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
+	       sizeof(core->i2c_algo));
+
+
+	core->i2c_adap.dev.parent = &pci->dev;
+	strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
+	core->i2c_adap.owner = THIS_MODULE;
+	core->i2c_algo.udelay = i2c_udelay;
+	core->i2c_algo.data = core;
+	i2c_set_adapdata(&core->i2c_adap, &core->v4l2_dev);
+	core->i2c_adap.algo_data = &core->i2c_algo;
+	core->i2c_client.adapter = &core->i2c_adap;
+	strlcpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE);
+
+	cx8800_bit_setscl(core,1);
+	cx8800_bit_setsda(core,1);
+
+	core->i2c_rc = i2c_bit_add_bus(&core->i2c_adap);
+	if (0 == core->i2c_rc) {
+		static u8 tuner_data[] =
+			{ 0x0b, 0xdc, 0x86, 0x52 };
+		static struct i2c_msg tuner_msg =
+			{ .flags = 0, .addr = 0xc2 >> 1, .buf = tuner_data, .len = 4 };
+
+		dprintk(1, "i2c register ok\n");
+		switch( core->boardnr ) {
+			case CX88_BOARD_HAUPPAUGE_HVR1300:
+			case CX88_BOARD_HAUPPAUGE_HVR3000:
+			case CX88_BOARD_HAUPPAUGE_HVR4000:
+				printk("%s: i2c init: enabling analog demod on HVR1300/3000/4000 tuner\n",
+					core->name);
+				i2c_transfer(core->i2c_client.adapter, &tuner_msg, 1);
+				break;
+			default:
+				break;
+		}
+		if (i2c_scan)
+			do_i2c_scan(core->name,&core->i2c_client);
+	} else
+		printk("%s: i2c register FAILED\n", core->name);
+
+	return core->i2c_rc;
+}
diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
new file mode 100644
index 0000000..ebf448c
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-input.c
@@ -0,0 +1,635 @@
+/*
+ *
+ * Device driver for GPIO attached remote control interfaces
+ * on Conexant 2388x based TV/DVB cards.
+ *
+ * Copyright (c) 2003 Pavel Machek
+ * Copyright (c) 2004 Gerd Knorr
+ * Copyright (c) 2004, 2005 Chris Pascoe
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/hrtimer.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include "cx88.h"
+#include <media/rc-core.h>
+
+#define MODULE_NAME "cx88xx"
+
+/* ---------------------------------------------------------------------- */
+
+struct cx88_IR {
+	struct cx88_core *core;
+	struct rc_dev *dev;
+
+	int users;
+
+	char name[32];
+	char phys[32];
+
+	/* sample from gpio pin 16 */
+	u32 sampling;
+
+	/* poll external decoder */
+	int polling;
+	struct hrtimer timer;
+	u32 gpio_addr;
+	u32 last_gpio;
+	u32 mask_keycode;
+	u32 mask_keydown;
+	u32 mask_keyup;
+};
+
+static unsigned ir_samplerate = 4;
+module_param(ir_samplerate, uint, 0444);
+MODULE_PARM_DESC(ir_samplerate, "IR samplerate in kHz, 1 - 20, default 4");
+
+static int ir_debug;
+module_param(ir_debug, int, 0644);	/* debug level [IR] */
+MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
+
+#define ir_dprintk(fmt, arg...)	if (ir_debug) \
+	printk(KERN_DEBUG "%s IR: " fmt , ir->core->name , ##arg)
+
+#define dprintk(fmt, arg...)	if (ir_debug) \
+	printk(KERN_DEBUG "cx88 IR: " fmt , ##arg)
+
+/* ---------------------------------------------------------------------- */
+
+static void cx88_ir_handle_key(struct cx88_IR *ir)
+{
+	struct cx88_core *core = ir->core;
+	u32 gpio, data, auxgpio;
+
+	/* read gpio value */
+	gpio = cx_read(ir->gpio_addr);
+	switch (core->boardnr) {
+	case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
+		/* This board apparently uses a combination of 2 GPIO
+		   to represent the keys. Additionally, the second GPIO
+		   can be used for parity.
+
+		   Example:
+
+		   for key "5"
+			gpio = 0x758, auxgpio = 0xe5 or 0xf5
+		   for key "Power"
+			gpio = 0x758, auxgpio = 0xed or 0xfd
+		 */
+
+		auxgpio = cx_read(MO_GP1_IO);
+		/* Take out the parity part */
+		gpio=(gpio & 0x7fd) + (auxgpio & 0xef);
+		break;
+	case CX88_BOARD_WINFAST_DTV1000:
+	case CX88_BOARD_WINFAST_DTV1800H:
+	case CX88_BOARD_WINFAST_DTV1800H_XC4000:
+	case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
+	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36:
+	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43:
+		gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
+		auxgpio = gpio;
+		break;
+	default:
+		auxgpio = gpio;
+	}
+	if (ir->polling) {
+		if (ir->last_gpio == auxgpio)
+			return;
+		ir->last_gpio = auxgpio;
+	}
+
+	/* extract data */
+	data = ir_extract_bits(gpio, ir->mask_keycode);
+	ir_dprintk("irq gpio=0x%x code=%d | %s%s%s\n",
+		   gpio, data,
+		   ir->polling ? "poll" : "irq",
+		   (gpio & ir->mask_keydown) ? " down" : "",
+		   (gpio & ir->mask_keyup) ? " up" : "");
+
+	if (ir->core->boardnr == CX88_BOARD_NORWOOD_MICRO) {
+		u32 gpio_key = cx_read(MO_GP0_IO);
+
+		data = (data << 4) | ((gpio_key & 0xf0) >> 4);
+
+		rc_keydown(ir->dev, data, 0);
+
+	} else if (ir->mask_keydown) {
+		/* bit set on keydown */
+		if (gpio & ir->mask_keydown)
+			rc_keydown_notimeout(ir->dev, data, 0);
+		else
+			rc_keyup(ir->dev);
+
+	} else if (ir->mask_keyup) {
+		/* bit cleared on keydown */
+		if (0 == (gpio & ir->mask_keyup))
+			rc_keydown_notimeout(ir->dev, data, 0);
+		else
+			rc_keyup(ir->dev);
+
+	} else {
+		/* can't distinguish keydown/up :-/ */
+		rc_keydown_notimeout(ir->dev, data, 0);
+		rc_keyup(ir->dev);
+	}
+}
+
+static enum hrtimer_restart cx88_ir_work(struct hrtimer *timer)
+{
+	unsigned long missed;
+	struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer);
+
+	cx88_ir_handle_key(ir);
+	missed = hrtimer_forward_now(&ir->timer,
+				     ktime_set(0, ir->polling * 1000000));
+	if (missed > 1)
+		ir_dprintk("Missed ticks %ld\n", missed - 1);
+
+	return HRTIMER_RESTART;
+}
+
+static int __cx88_ir_start(void *priv)
+{
+	struct cx88_core *core = priv;
+	struct cx88_IR *ir;
+
+	if (!core || !core->ir)
+		return -EINVAL;
+
+	ir = core->ir;
+
+	if (ir->polling) {
+		hrtimer_init(&ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+		ir->timer.function = cx88_ir_work;
+		hrtimer_start(&ir->timer,
+			      ktime_set(0, ir->polling * 1000000),
+			      HRTIMER_MODE_REL);
+	}
+	if (ir->sampling) {
+		core->pci_irqmask |= PCI_INT_IR_SMPINT;
+		cx_write(MO_DDS_IO, 0x33F286 * ir_samplerate); /* samplerate */
+		cx_write(MO_DDSCFG_IO, 0x5); /* enable */
+	}
+	return 0;
+}
+
+static void __cx88_ir_stop(void *priv)
+{
+	struct cx88_core *core = priv;
+	struct cx88_IR *ir;
+
+	if (!core || !core->ir)
+		return;
+
+	ir = core->ir;
+	if (ir->sampling) {
+		cx_write(MO_DDSCFG_IO, 0x0);
+		core->pci_irqmask &= ~PCI_INT_IR_SMPINT;
+	}
+
+	if (ir->polling)
+		hrtimer_cancel(&ir->timer);
+}
+
+int cx88_ir_start(struct cx88_core *core)
+{
+	if (core->ir->users)
+		return __cx88_ir_start(core);
+
+	return 0;
+}
+
+void cx88_ir_stop(struct cx88_core *core)
+{
+	if (core->ir->users)
+		__cx88_ir_stop(core);
+}
+
+static int cx88_ir_open(struct rc_dev *rc)
+{
+	struct cx88_core *core = rc->priv;
+
+	core->ir->users++;
+	return __cx88_ir_start(core);
+}
+
+static void cx88_ir_close(struct rc_dev *rc)
+{
+	struct cx88_core *core = rc->priv;
+
+	core->ir->users--;
+	if (!core->ir->users)
+		__cx88_ir_stop(core);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
+{
+	struct cx88_IR *ir;
+	struct rc_dev *dev;
+	char *ir_codes = NULL;
+	u64 rc_type = RC_TYPE_OTHER;
+	int err = -ENOMEM;
+	u32 hardware_mask = 0;	/* For devices with a hardware mask, when
+				 * used with a full-code IR table
+				 */
+
+	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+	dev = rc_allocate_device();
+	if (!ir || !dev)
+		goto err_out_free;
+
+	ir->dev = dev;
+
+	/* detect & configure */
+	switch (core->boardnr) {
+	case CX88_BOARD_DNTV_LIVE_DVB_T:
+	case CX88_BOARD_KWORLD_DVB_T:
+	case CX88_BOARD_KWORLD_DVB_T_CX22702:
+		ir_codes = RC_MAP_DNTV_LIVE_DVB_T;
+		ir->gpio_addr = MO_GP1_IO;
+		ir->mask_keycode = 0x1f;
+		ir->mask_keyup = 0x60;
+		ir->polling = 50; /* ms */
+		break;
+	case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
+		ir_codes = RC_MAP_CINERGY_1400;
+		ir->sampling = 0xeb04; /* address */
+		break;
+	case CX88_BOARD_HAUPPAUGE:
+	case CX88_BOARD_HAUPPAUGE_DVB_T1:
+	case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+	case CX88_BOARD_HAUPPAUGE_HVR1100:
+	case CX88_BOARD_HAUPPAUGE_HVR3000:
+	case CX88_BOARD_HAUPPAUGE_HVR4000:
+	case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+	case CX88_BOARD_PCHDTV_HD3000:
+	case CX88_BOARD_PCHDTV_HD5500:
+	case CX88_BOARD_HAUPPAUGE_IRONLY:
+		ir_codes = RC_MAP_HAUPPAUGE;
+		ir->sampling = 1;
+		break;
+	case CX88_BOARD_WINFAST_DTV2000H:
+	case CX88_BOARD_WINFAST_DTV2000H_J:
+	case CX88_BOARD_WINFAST_DTV1800H:
+	case CX88_BOARD_WINFAST_DTV1800H_XC4000:
+	case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+		ir_codes = RC_MAP_WINFAST;
+		ir->gpio_addr = MO_GP0_IO;
+		ir->mask_keycode = 0x8f8;
+		ir->mask_keyup = 0x100;
+		ir->polling = 50; /* ms */
+		break;
+	case CX88_BOARD_WINFAST2000XP_EXPERT:
+	case CX88_BOARD_WINFAST_DTV1000:
+	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
+	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36:
+	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43:
+		ir_codes = RC_MAP_WINFAST;
+		ir->gpio_addr = MO_GP0_IO;
+		ir->mask_keycode = 0x8f8;
+		ir->mask_keyup = 0x100;
+		ir->polling = 1; /* ms */
+		break;
+	case CX88_BOARD_IODATA_GVBCTV7E:
+		ir_codes = RC_MAP_IODATA_BCTV7E;
+		ir->gpio_addr = MO_GP0_IO;
+		ir->mask_keycode = 0xfd;
+		ir->mask_keydown = 0x02;
+		ir->polling = 5; /* ms */
+		break;
+	case CX88_BOARD_PROLINK_PLAYTVPVR:
+	case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO:
+		/*
+		 * It seems that this hardware is paired with NEC extended
+		 * address 0x866b. So, unfortunately, its usage with other
+		 * IR's with different address won't work. Still, there are
+		 * other IR's from the same manufacturer that works, like the
+		 * 002-T mini RC, provided with newer PV hardware
+		 */
+		ir_codes = RC_MAP_PIXELVIEW_MK12;
+		ir->gpio_addr = MO_GP1_IO;
+		ir->mask_keyup = 0x80;
+		ir->polling = 10; /* ms */
+		hardware_mask = 0x3f;	/* Hardware returns only 6 bits from command part */
+		break;
+	case CX88_BOARD_PROLINK_PV_8000GT:
+	case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
+		ir_codes = RC_MAP_PIXELVIEW_NEW;
+		ir->gpio_addr = MO_GP1_IO;
+		ir->mask_keycode = 0x3f;
+		ir->mask_keyup = 0x80;
+		ir->polling = 1; /* ms */
+		break;
+	case CX88_BOARD_KWORLD_LTV883:
+		ir_codes = RC_MAP_PIXELVIEW;
+		ir->gpio_addr = MO_GP1_IO;
+		ir->mask_keycode = 0x1f;
+		ir->mask_keyup = 0x60;
+		ir->polling = 1; /* ms */
+		break;
+	case CX88_BOARD_ADSTECH_DVB_T_PCI:
+		ir_codes = RC_MAP_ADSTECH_DVB_T_PCI;
+		ir->gpio_addr = MO_GP1_IO;
+		ir->mask_keycode = 0xbf;
+		ir->mask_keyup = 0x40;
+		ir->polling = 50; /* ms */
+		break;
+	case CX88_BOARD_MSI_TVANYWHERE_MASTER:
+		ir_codes = RC_MAP_MSI_TVANYWHERE;
+		ir->gpio_addr = MO_GP1_IO;
+		ir->mask_keycode = 0x1f;
+		ir->mask_keyup = 0x40;
+		ir->polling = 1; /* ms */
+		break;
+	case CX88_BOARD_AVERTV_303:
+	case CX88_BOARD_AVERTV_STUDIO_303:
+		ir_codes         = RC_MAP_AVERTV_303;
+		ir->gpio_addr    = MO_GP2_IO;
+		ir->mask_keycode = 0xfb;
+		ir->mask_keydown = 0x02;
+		ir->polling      = 50; /* ms */
+		break;
+	case CX88_BOARD_OMICOM_SS4_PCI:
+	case CX88_BOARD_SATTRADE_ST4200:
+	case CX88_BOARD_TBS_8920:
+	case CX88_BOARD_TBS_8910:
+	case CX88_BOARD_PROF_7300:
+	case CX88_BOARD_PROF_7301:
+	case CX88_BOARD_PROF_6200:
+		ir_codes = RC_MAP_TBS_NEC;
+		ir->sampling = 0xff00; /* address */
+		break;
+	case CX88_BOARD_TEVII_S464:
+	case CX88_BOARD_TEVII_S460:
+	case CX88_BOARD_TEVII_S420:
+		ir_codes = RC_MAP_TEVII_NEC;
+		ir->sampling = 0xff00; /* address */
+		break;
+	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
+		ir_codes         = RC_MAP_DNTV_LIVE_DVBT_PRO;
+		ir->sampling     = 0xff00; /* address */
+		break;
+	case CX88_BOARD_NORWOOD_MICRO:
+		ir_codes         = RC_MAP_NORWOOD;
+		ir->gpio_addr    = MO_GP1_IO;
+		ir->mask_keycode = 0x0e;
+		ir->mask_keyup   = 0x80;
+		ir->polling      = 50; /* ms */
+		break;
+	case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
+		ir_codes         = RC_MAP_NPGTECH;
+		ir->gpio_addr    = MO_GP0_IO;
+		ir->mask_keycode = 0xfa;
+		ir->polling      = 50; /* ms */
+		break;
+	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
+		ir_codes         = RC_MAP_PINNACLE_PCTV_HD;
+		ir->sampling     = 1;
+		break;
+	case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
+		ir_codes         = RC_MAP_POWERCOLOR_REAL_ANGEL;
+		ir->gpio_addr    = MO_GP2_IO;
+		ir->mask_keycode = 0x7e;
+		ir->polling      = 100; /* ms */
+		break;
+	case CX88_BOARD_TWINHAN_VP1027_DVBS:
+		ir_codes         = RC_MAP_TWINHAN_VP1027_DVBS;
+		rc_type          = RC_TYPE_NEC;
+		ir->sampling     = 0xff00; /* address */
+		break;
+	}
+
+	if (!ir_codes) {
+		err = -ENODEV;
+		goto err_out_free;
+	}
+
+	/*
+	 * The usage of mask_keycode were very convenient, due to several
+	 * reasons. Among others, the scancode tables were using the scancode
+	 * as the index elements. So, the less bits it was used, the smaller
+	 * the table were stored. After the input changes, the better is to use
+	 * the full scancodes, since it allows replacing the IR remote by
+	 * another one. Unfortunately, there are still some hardware, like
+	 * Pixelview Ultra Pro, where only part of the scancode is sent via
+	 * GPIO. So, there's no way to get the full scancode. Due to that,
+	 * hardware_mask were introduced here: it represents those hardware
+	 * that has such limits.
+	 */
+	if (hardware_mask && !ir->mask_keycode)
+		ir->mask_keycode = hardware_mask;
+
+	/* init input device */
+	snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name);
+	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci));
+
+	dev->input_name = ir->name;
+	dev->input_phys = ir->phys;
+	dev->input_id.bustype = BUS_PCI;
+	dev->input_id.version = 1;
+	if (pci->subsystem_vendor) {
+		dev->input_id.vendor = pci->subsystem_vendor;
+		dev->input_id.product = pci->subsystem_device;
+	} else {
+		dev->input_id.vendor = pci->vendor;
+		dev->input_id.product = pci->device;
+	}
+	dev->dev.parent = &pci->dev;
+	dev->map_name = ir_codes;
+	dev->driver_name = MODULE_NAME;
+	dev->priv = core;
+	dev->open = cx88_ir_open;
+	dev->close = cx88_ir_close;
+	dev->scanmask = hardware_mask;
+
+	if (ir->sampling) {
+		dev->driver_type = RC_DRIVER_IR_RAW;
+		dev->timeout = 10 * 1000 * 1000; /* 10 ms */
+	} else {
+		dev->driver_type = RC_DRIVER_SCANCODE;
+		dev->allowed_protos = rc_type;
+	}
+
+	ir->core = core;
+	core->ir = ir;
+
+	/* all done */
+	err = rc_register_device(dev);
+	if (err)
+		goto err_out_free;
+
+	return 0;
+
+err_out_free:
+	rc_free_device(dev);
+	core->ir = NULL;
+	kfree(ir);
+	return err;
+}
+
+int cx88_ir_fini(struct cx88_core *core)
+{
+	struct cx88_IR *ir = core->ir;
+
+	/* skip detach on non attached boards */
+	if (NULL == ir)
+		return 0;
+
+	cx88_ir_stop(core);
+	rc_unregister_device(ir->dev);
+	kfree(ir);
+
+	/* done */
+	core->ir = NULL;
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void cx88_ir_irq(struct cx88_core *core)
+{
+	struct cx88_IR *ir = core->ir;
+	u32 samples;
+	unsigned todo, bits;
+	struct ir_raw_event ev;
+
+	if (!ir || !ir->sampling)
+		return;
+
+	/*
+	 * Samples are stored in a 32 bit register, oldest sample in
+	 * the msb. A set bit represents space and an unset bit
+	 * represents a pulse.
+	 */
+	samples = cx_read(MO_SAMPLE_IO);
+
+	if (samples == 0xff && ir->dev->idle)
+		return;
+
+	init_ir_raw_event(&ev);
+	for (todo = 32; todo > 0; todo -= bits) {
+		ev.pulse = samples & 0x80000000 ? false : true;
+		bits = min(todo, 32U - fls(ev.pulse ? samples : ~samples));
+		ev.duration = (bits * (NSEC_PER_SEC / 1000)) / ir_samplerate;
+		ir_raw_event_store_with_filter(ir->dev, &ev);
+		samples <<= bits;
+	}
+	ir_raw_event_handle(ir->dev);
+}
+
+static int get_key_pvr2000(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	int flags, code;
+
+	/* poll IR chip */
+	flags = i2c_smbus_read_byte_data(ir->c, 0x10);
+	if (flags < 0) {
+		dprintk("read error\n");
+		return 0;
+	}
+	/* key pressed ? */
+	if (0 == (flags & 0x80))
+		return 0;
+
+	/* read actual key code */
+	code = i2c_smbus_read_byte_data(ir->c, 0x00);
+	if (code < 0) {
+		dprintk("read error\n");
+		return 0;
+	}
+
+	dprintk("IR Key/Flags: (0x%02x/0x%02x)\n",
+		   code & 0xff, flags & 0xff);
+
+	*ir_key = code & 0xff;
+	*ir_raw = code;
+	return 1;
+}
+
+void cx88_i2c_init_ir(struct cx88_core *core)
+{
+	struct i2c_board_info info;
+	const unsigned short default_addr_list[] = {
+		0x18, 0x6b, 0x71,
+		I2C_CLIENT_END
+	};
+	const unsigned short pvr2000_addr_list[] = {
+		0x18, 0x1a,
+		I2C_CLIENT_END
+	};
+	const unsigned short *addr_list = default_addr_list;
+	const unsigned short *addrp;
+	/* Instantiate the IR receiver device, if present */
+	if (0 != core->i2c_rc)
+		return;
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+
+	switch (core->boardnr) {
+	case CX88_BOARD_LEADTEK_PVR2000:
+		addr_list = pvr2000_addr_list;
+		core->init_data.name = "cx88 Leadtek PVR 2000 remote";
+		core->init_data.type = RC_TYPE_UNKNOWN;
+		core->init_data.get_key = get_key_pvr2000;
+		core->init_data.ir_codes = RC_MAP_EMPTY;
+		break;
+	}
+
+	/*
+	 * We can't call i2c_new_probed_device() because it uses
+	 * quick writes for probing and at least some RC receiver
+	 * devices only reply to reads.
+	 * Also, Hauppauge XVR needs to be specified, as address 0x71
+	 * conflicts with another remote type used with saa7134
+	 */
+	for (addrp = addr_list; *addrp != I2C_CLIENT_END; addrp++) {
+		info.platform_data = NULL;
+		memset(&core->init_data, 0, sizeof(core->init_data));
+
+		if (*addrp == 0x71) {
+			/* Hauppauge XVR */
+			core->init_data.name = "cx88 Hauppauge XVR remote";
+			core->init_data.ir_codes = RC_MAP_HAUPPAUGE;
+			core->init_data.type = RC_TYPE_RC5;
+			core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+
+			info.platform_data = &core->init_data;
+		}
+		if (i2c_smbus_xfer(&core->i2c_adap, *addrp, 0,
+					I2C_SMBUS_READ, 0,
+					I2C_SMBUS_QUICK, NULL) >= 0) {
+			info.addr = *addrp;
+			i2c_new_device(&core->i2c_adap, &info);
+			break;
+		}
+	}
+}
+
+/* ---------------------------------------------------------------------- */
+
+MODULE_AUTHOR("Gerd Knorr, Pavel Machek, Chris Pascoe");
+MODULE_DESCRIPTION("input driver for cx88 GPIO-based IR remote controls");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c
new file mode 100644
index 0000000..cd5386e
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-mpeg.c
@@ -0,0 +1,929 @@
+/*
+ *
+ *  Support for the mpeg transport stream transfers
+ *  PCI function #2 of the cx2388x.
+ *
+ *    (c) 2004 Jelle Foks <jelle@foks.us>
+ *    (c) 2004 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+ *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <asm/delay.h>
+
+#include "cx88.h"
+
+/* ------------------------------------------------------------------ */
+
+MODULE_DESCRIPTION("mpeg driver for cx2388x based TV cards");
+MODULE_AUTHOR("Jelle Foks <jelle@foks.us>");
+MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CX88_VERSION);
+
+static unsigned int debug;
+module_param(debug,int,0644);
+MODULE_PARM_DESC(debug,"enable debug messages [mpeg]");
+
+#define dprintk(level,fmt, arg...)	if (debug >= level) \
+	printk(KERN_DEBUG "%s/2-mpeg: " fmt, dev->core->name, ## arg)
+
+#define mpeg_dbg(level,fmt, arg...)	if (debug >= level) \
+	printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg)
+
+#if defined(CONFIG_MODULES) && defined(MODULE)
+static void request_module_async(struct work_struct *work)
+{
+	struct cx8802_dev *dev=container_of(work, struct cx8802_dev, request_module_wk);
+
+	if (dev->core->board.mpeg & CX88_MPEG_DVB)
+		request_module("cx88-dvb");
+	if (dev->core->board.mpeg & CX88_MPEG_BLACKBIRD)
+		request_module("cx88-blackbird");
+}
+
+static void request_modules(struct cx8802_dev *dev)
+{
+	INIT_WORK(&dev->request_module_wk, request_module_async);
+	schedule_work(&dev->request_module_wk);
+}
+
+static void flush_request_modules(struct cx8802_dev *dev)
+{
+	flush_work_sync(&dev->request_module_wk);
+}
+#else
+#define request_modules(dev)
+#define flush_request_modules(dev)
+#endif /* CONFIG_MODULES */
+
+
+static LIST_HEAD(cx8802_devlist);
+static DEFINE_MUTEX(cx8802_mutex);
+/* ------------------------------------------------------------------ */
+
+static int cx8802_start_dma(struct cx8802_dev    *dev,
+			    struct cx88_dmaqueue *q,
+			    struct cx88_buffer   *buf)
+{
+	struct cx88_core *core = dev->core;
+
+	dprintk(1, "cx8802_start_dma w: %d, h: %d, f: %d\n",
+		buf->vb.width, buf->vb.height, buf->vb.field);
+
+	/* setup fifo + format */
+	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28],
+				dev->ts_packet_size, buf->risc.dma);
+
+	/* write TS length to chip */
+	cx_write(MO_TS_LNGTH, buf->vb.width);
+
+	/* FIXME: this needs a review.
+	 * also: move to cx88-blackbird + cx88-dvb source files? */
+
+	dprintk( 1, "core->active_type_id = 0x%08x\n", core->active_type_id);
+
+	if ( (core->active_type_id == CX88_MPEG_DVB) &&
+		(core->board.mpeg & CX88_MPEG_DVB) ) {
+
+		dprintk( 1, "cx8802_start_dma doing .dvb\n");
+		/* negedge driven & software reset */
+		cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl);
+		udelay(100);
+		cx_write(MO_PINMUX_IO, 0x00);
+		cx_write(TS_HW_SOP_CNTRL, 0x47<<16|188<<4|0x01);
+		switch (core->boardnr) {
+		case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
+		case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
+		case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
+		case CX88_BOARD_PCHDTV_HD5500:
+			cx_write(TS_SOP_STAT, 1<<13);
+			break;
+		case CX88_BOARD_SAMSUNG_SMT_7020:
+			cx_write(TS_SOP_STAT, 0x00);
+			break;
+		case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+		case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+			cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */
+			udelay(100);
+			break;
+		case CX88_BOARD_HAUPPAUGE_HVR1300:
+			/* Enable MPEG parallel IO and video signal pins */
+			cx_write(MO_PINMUX_IO, 0x88);
+			cx_write(TS_SOP_STAT, 0);
+			cx_write(TS_VALERR_CNTRL, 0);
+			break;
+		case CX88_BOARD_PINNACLE_PCTV_HD_800i:
+			/* Enable MPEG parallel IO and video signal pins */
+			cx_write(MO_PINMUX_IO, 0x88);
+			cx_write(TS_HW_SOP_CNTRL, (0x47 << 16) | (188 << 4));
+			dev->ts_gen_cntrl = 5;
+			cx_write(TS_SOP_STAT, 0);
+			cx_write(TS_VALERR_CNTRL, 0);
+			udelay(100);
+			break;
+		default:
+			cx_write(TS_SOP_STAT, 0x00);
+			break;
+		}
+		cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl);
+		udelay(100);
+	} else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) &&
+		(core->board.mpeg & CX88_MPEG_BLACKBIRD) ) {
+		dprintk( 1, "cx8802_start_dma doing .blackbird\n");
+		cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */
+
+		cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */
+		udelay(100);
+
+		cx_write(TS_HW_SOP_CNTRL, 0x408); /* mpeg start byte */
+		cx_write(TS_VALERR_CNTRL, 0x2000);
+
+		cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */
+		udelay(100);
+	} else {
+		printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __func__,
+			core->board.mpeg );
+		return -EINVAL;
+	}
+
+	/* reset counter */
+	cx_write(MO_TS_GPCNTRL, GP_COUNT_CONTROL_RESET);
+	q->count = 1;
+
+	/* enable irqs */
+	dprintk( 1, "setting the interrupt mask\n" );
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_TSINT);
+	cx_set(MO_TS_INTMSK,  0x1f0011);
+
+	/* start dma */
+	cx_set(MO_DEV_CNTRL2, (1<<5));
+	cx_set(MO_TS_DMACNTRL, 0x11);
+	return 0;
+}
+
+static int cx8802_stop_dma(struct cx8802_dev *dev)
+{
+	struct cx88_core *core = dev->core;
+	dprintk( 1, "cx8802_stop_dma\n" );
+
+	/* stop dma */
+	cx_clear(MO_TS_DMACNTRL, 0x11);
+
+	/* disable irqs */
+	cx_clear(MO_PCI_INTMSK, PCI_INT_TSINT);
+	cx_clear(MO_TS_INTMSK, 0x1f0011);
+
+	/* Reset the controller */
+	cx_write(TS_GEN_CNTRL, 0xcd);
+	return 0;
+}
+
+static int cx8802_restart_queue(struct cx8802_dev    *dev,
+				struct cx88_dmaqueue *q)
+{
+	struct cx88_buffer *buf;
+
+	dprintk( 1, "cx8802_restart_queue\n" );
+	if (list_empty(&q->active))
+	{
+		struct cx88_buffer *prev;
+		prev = NULL;
+
+		dprintk(1, "cx8802_restart_queue: queue is empty\n" );
+
+		for (;;) {
+			if (list_empty(&q->queued))
+				return 0;
+			buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
+			if (NULL == prev) {
+				list_del(&buf->vb.queue);
+				list_add_tail(&buf->vb.queue,&q->active);
+				cx8802_start_dma(dev, q, buf);
+				buf->vb.state = VIDEOBUF_ACTIVE;
+				buf->count    = q->count++;
+				mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+				dprintk(1,"[%p/%d] restart_queue - first active\n",
+					buf,buf->vb.i);
+
+			} else if (prev->vb.width  == buf->vb.width  &&
+				   prev->vb.height == buf->vb.height &&
+				   prev->fmt       == buf->fmt) {
+				list_del(&buf->vb.queue);
+				list_add_tail(&buf->vb.queue,&q->active);
+				buf->vb.state = VIDEOBUF_ACTIVE;
+				buf->count    = q->count++;
+				prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+				dprintk(1,"[%p/%d] restart_queue - move to active\n",
+					buf,buf->vb.i);
+			} else {
+				return 0;
+			}
+			prev = buf;
+		}
+		return 0;
+	}
+
+	buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+	dprintk(2,"restart_queue [%p/%d]: restart dma\n",
+		buf, buf->vb.i);
+	cx8802_start_dma(dev, q, buf);
+	list_for_each_entry(buf, &q->active, vb.queue)
+		buf->count = q->count++;
+	mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
+			struct cx88_buffer *buf, enum v4l2_field field)
+{
+	int size = dev->ts_packet_size * dev->ts_packet_count;
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+	int rc;
+
+	dprintk(1, "%s: %p\n", __func__, buf);
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+		return -EINVAL;
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		buf->vb.width  = dev->ts_packet_size;
+		buf->vb.height = dev->ts_packet_count;
+		buf->vb.size   = size;
+		buf->vb.field  = field /*V4L2_FIELD_TOP*/;
+
+		if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
+			goto fail;
+		cx88_risc_databuffer(dev->pci, &buf->risc,
+				     dma->sglist,
+				     buf->vb.width, buf->vb.height, 0);
+	}
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+ fail:
+	cx88_free_buffer(q,buf);
+	return rc;
+}
+
+void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
+{
+	struct cx88_buffer    *prev;
+	struct cx88_dmaqueue  *cx88q = &dev->mpegq;
+
+	dprintk( 1, "cx8802_buf_queue\n" );
+	/* add jump to stopper */
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+	buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma);
+
+	if (list_empty(&cx88q->active)) {
+		dprintk( 1, "queue is empty - first active\n" );
+		list_add_tail(&buf->vb.queue,&cx88q->active);
+		cx8802_start_dma(dev, cx88q, buf);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		buf->count    = cx88q->count++;
+		mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT);
+		dprintk(1,"[%p/%d] %s - first active\n",
+			buf, buf->vb.i, __func__);
+
+	} else {
+		dprintk( 1, "queue is not empty - append to active\n" );
+		prev = list_entry(cx88q->active.prev, struct cx88_buffer, vb.queue);
+		list_add_tail(&buf->vb.queue,&cx88q->active);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		buf->count    = cx88q->count++;
+		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+		dprintk( 1, "[%p/%d] %s - append to active\n",
+			buf, buf->vb.i, __func__);
+	}
+}
+
+/* ----------------------------------------------------------- */
+
+static void do_cancel_buffers(struct cx8802_dev *dev, const char *reason, int restart)
+{
+	struct cx88_dmaqueue *q = &dev->mpegq;
+	struct cx88_buffer *buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->slock,flags);
+	while (!list_empty(&q->active)) {
+		buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+		list_del(&buf->vb.queue);
+		buf->vb.state = VIDEOBUF_ERROR;
+		wake_up(&buf->vb.done);
+		dprintk(1,"[%p/%d] %s - dma=0x%08lx\n",
+			buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
+	}
+	if (restart)
+	{
+		dprintk(1, "restarting queue\n" );
+		cx8802_restart_queue(dev,q);
+	}
+	spin_unlock_irqrestore(&dev->slock,flags);
+}
+
+void cx8802_cancel_buffers(struct cx8802_dev *dev)
+{
+	struct cx88_dmaqueue *q = &dev->mpegq;
+
+	dprintk( 1, "cx8802_cancel_buffers" );
+	del_timer_sync(&q->timeout);
+	cx8802_stop_dma(dev);
+	do_cancel_buffers(dev,"cancel",0);
+}
+
+static void cx8802_timeout(unsigned long data)
+{
+	struct cx8802_dev *dev = (struct cx8802_dev*)data;
+
+	dprintk(1, "%s\n",__func__);
+
+	if (debug)
+		cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
+	cx8802_stop_dma(dev);
+	do_cancel_buffers(dev,"timeout",1);
+}
+
+static const char * cx88_mpeg_irqs[32] = {
+	"ts_risci1", NULL, NULL, NULL,
+	"ts_risci2", NULL, NULL, NULL,
+	"ts_oflow",  NULL, NULL, NULL,
+	"ts_sync",   NULL, NULL, NULL,
+	"opc_err", "par_err", "rip_err", "pci_abort",
+	"ts_err?",
+};
+
+static void cx8802_mpeg_irq(struct cx8802_dev *dev)
+{
+	struct cx88_core *core = dev->core;
+	u32 status, mask, count;
+
+	dprintk( 1, "cx8802_mpeg_irq\n" );
+	status = cx_read(MO_TS_INTSTAT);
+	mask   = cx_read(MO_TS_INTMSK);
+	if (0 == (status & mask))
+		return;
+
+	cx_write(MO_TS_INTSTAT, status);
+
+	if (debug || (status & mask & ~0xff))
+		cx88_print_irqbits(core->name, "irq mpeg ",
+				   cx88_mpeg_irqs, ARRAY_SIZE(cx88_mpeg_irqs),
+				   status, mask);
+
+	/* risc op code error */
+	if (status & (1 << 16)) {
+		printk(KERN_WARNING "%s: mpeg risc op code error\n",core->name);
+		cx_clear(MO_TS_DMACNTRL, 0x11);
+		cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
+	}
+
+	/* risc1 y */
+	if (status & 0x01) {
+		dprintk( 1, "wake up\n" );
+		spin_lock(&dev->slock);
+		count = cx_read(MO_TS_GPCNT);
+		cx88_wakeup(dev->core, &dev->mpegq, count);
+		spin_unlock(&dev->slock);
+	}
+
+	/* risc2 y */
+	if (status & 0x10) {
+		spin_lock(&dev->slock);
+		cx8802_restart_queue(dev,&dev->mpegq);
+		spin_unlock(&dev->slock);
+	}
+
+	/* other general errors */
+	if (status & 0x1f0100) {
+		dprintk( 0, "general errors: 0x%08x\n", status & 0x1f0100 );
+		spin_lock(&dev->slock);
+		cx8802_stop_dma(dev);
+		cx8802_restart_queue(dev,&dev->mpegq);
+		spin_unlock(&dev->slock);
+	}
+}
+
+#define MAX_IRQ_LOOP 10
+
+static irqreturn_t cx8802_irq(int irq, void *dev_id)
+{
+	struct cx8802_dev *dev = dev_id;
+	struct cx88_core *core = dev->core;
+	u32 status;
+	int loop, handled = 0;
+
+	for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
+		status = cx_read(MO_PCI_INTSTAT) &
+			(core->pci_irqmask | PCI_INT_TSINT);
+		if (0 == status)
+			goto out;
+		dprintk( 1, "cx8802_irq\n" );
+		dprintk( 1, "    loop: %d/%d\n", loop, MAX_IRQ_LOOP );
+		dprintk( 1, "    status: %d\n", status );
+		handled = 1;
+		cx_write(MO_PCI_INTSTAT, status);
+
+		if (status & core->pci_irqmask)
+			cx88_core_irq(core,status);
+		if (status & PCI_INT_TSINT)
+			cx8802_mpeg_irq(dev);
+	};
+	if (MAX_IRQ_LOOP == loop) {
+		dprintk( 0, "clearing mask\n" );
+		printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n",
+		       core->name);
+		cx_write(MO_PCI_INTMSK,0);
+	}
+
+ out:
+	return IRQ_RETVAL(handled);
+}
+
+static int cx8802_init_common(struct cx8802_dev *dev)
+{
+	struct cx88_core *core = dev->core;
+	int err;
+
+	/* pci init */
+	if (pci_enable_device(dev->pci))
+		return -EIO;
+	pci_set_master(dev->pci);
+	if (!pci_dma_supported(dev->pci,DMA_BIT_MASK(32))) {
+		printk("%s/2: Oops: no 32bit PCI DMA ???\n",dev->core->name);
+		return -EIO;
+	}
+
+	dev->pci_rev = dev->pci->revision;
+	pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER,  &dev->pci_lat);
+	printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, "
+	       "latency: %d, mmio: 0x%llx\n", dev->core->name,
+	       pci_name(dev->pci), dev->pci_rev, dev->pci->irq,
+	       dev->pci_lat,(unsigned long long)pci_resource_start(dev->pci,0));
+
+	/* initialize driver struct */
+	spin_lock_init(&dev->slock);
+
+	/* init dma queue */
+	INIT_LIST_HEAD(&dev->mpegq.active);
+	INIT_LIST_HEAD(&dev->mpegq.queued);
+	dev->mpegq.timeout.function = cx8802_timeout;
+	dev->mpegq.timeout.data     = (unsigned long)dev;
+	init_timer(&dev->mpegq.timeout);
+	cx88_risc_stopper(dev->pci,&dev->mpegq.stopper,
+			  MO_TS_DMACNTRL,0x11,0x00);
+
+	/* get irq */
+	err = request_irq(dev->pci->irq, cx8802_irq,
+			  IRQF_SHARED | IRQF_DISABLED, dev->core->name, dev);
+	if (err < 0) {
+		printk(KERN_ERR "%s: can't get IRQ %d\n",
+		       dev->core->name, dev->pci->irq);
+		return err;
+	}
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask);
+
+	/* everything worked */
+	pci_set_drvdata(dev->pci,dev);
+	return 0;
+}
+
+static void cx8802_fini_common(struct cx8802_dev *dev)
+{
+	dprintk( 2, "cx8802_fini_common\n" );
+	cx8802_stop_dma(dev);
+	pci_disable_device(dev->pci);
+
+	/* unregister stuff */
+	free_irq(dev->pci->irq, dev);
+	pci_set_drvdata(dev->pci, NULL);
+
+	/* free memory */
+	btcx_riscmem_free(dev->pci,&dev->mpegq.stopper);
+}
+
+/* ----------------------------------------------------------- */
+
+static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
+{
+	struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+	struct cx88_core *core = dev->core;
+
+	/* stop mpeg dma */
+	spin_lock(&dev->slock);
+	if (!list_empty(&dev->mpegq.active)) {
+		dprintk( 2, "suspend\n" );
+		printk("%s: suspend mpeg\n", core->name);
+		cx8802_stop_dma(dev);
+		del_timer(&dev->mpegq.timeout);
+	}
+	spin_unlock(&dev->slock);
+
+	/* FIXME -- shutdown device */
+	cx88_shutdown(dev->core);
+
+	pci_save_state(pci_dev);
+	if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
+		pci_disable_device(pci_dev);
+		dev->state.disabled = 1;
+	}
+	return 0;
+}
+
+static int cx8802_resume_common(struct pci_dev *pci_dev)
+{
+	struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+	struct cx88_core *core = dev->core;
+	int err;
+
+	if (dev->state.disabled) {
+		err=pci_enable_device(pci_dev);
+		if (err) {
+			printk(KERN_ERR "%s: can't enable device\n",
+					       dev->core->name);
+			return err;
+		}
+		dev->state.disabled = 0;
+	}
+	err=pci_set_power_state(pci_dev, PCI_D0);
+	if (err) {
+		printk(KERN_ERR "%s: can't enable device\n",
+					       dev->core->name);
+		pci_disable_device(pci_dev);
+		dev->state.disabled = 1;
+
+		return err;
+	}
+	pci_restore_state(pci_dev);
+
+	/* FIXME: re-initialize hardware */
+	cx88_reset(dev->core);
+
+	/* restart video+vbi capture */
+	spin_lock(&dev->slock);
+	if (!list_empty(&dev->mpegq.active)) {
+		printk("%s: resume mpeg\n", core->name);
+		cx8802_restart_queue(dev,&dev->mpegq);
+	}
+	spin_unlock(&dev->slock);
+
+	return 0;
+}
+
+struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype)
+{
+	struct cx8802_driver *d;
+
+	list_for_each_entry(d, &dev->drvlist, drvlist)
+		if (d->type_id == btype)
+			return d;
+
+	return NULL;
+}
+
+/* Driver asked for hardware access. */
+static int cx8802_request_acquire(struct cx8802_driver *drv)
+{
+	struct cx88_core *core = drv->core;
+	unsigned int	i;
+
+	/* Fail a request for hardware if the device is busy. */
+	if (core->active_type_id != CX88_BOARD_NONE &&
+	    core->active_type_id != drv->type_id)
+		return -EBUSY;
+
+	if (drv->type_id == CX88_MPEG_DVB) {
+		/* When switching to DVB, always set the input to the tuner */
+		core->last_analog_input = core->input;
+		core->input = 0;
+		for (i = 0;
+		     i < (sizeof(core->board.input) / sizeof(struct cx88_input));
+		     i++) {
+			if (core->board.input[i].type == CX88_VMUX_DVB) {
+				core->input = i;
+				break;
+			}
+		}
+	}
+
+	if (drv->advise_acquire)
+	{
+		core->active_ref++;
+		if (core->active_type_id == CX88_BOARD_NONE) {
+			core->active_type_id = drv->type_id;
+			drv->advise_acquire(drv);
+		}
+
+		mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
+	}
+
+	return 0;
+}
+
+/* Driver asked to release hardware. */
+static int cx8802_request_release(struct cx8802_driver *drv)
+{
+	struct cx88_core *core = drv->core;
+
+	if (drv->advise_release && --core->active_ref == 0)
+	{
+		if (drv->type_id == CX88_MPEG_DVB) {
+			/* If the DVB driver is releasing, reset the input
+			   state to the last configured analog input */
+			core->input = core->last_analog_input;
+		}
+
+		drv->advise_release(drv);
+		core->active_type_id = CX88_BOARD_NONE;
+		mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
+	}
+
+	return 0;
+}
+
+static int cx8802_check_driver(struct cx8802_driver *drv)
+{
+	if (drv == NULL)
+		return -ENODEV;
+
+	if ((drv->type_id != CX88_MPEG_DVB) &&
+		(drv->type_id != CX88_MPEG_BLACKBIRD))
+		return -EINVAL;
+
+	if ((drv->hw_access != CX8802_DRVCTL_SHARED) &&
+		(drv->hw_access != CX8802_DRVCTL_EXCLUSIVE))
+		return -EINVAL;
+
+	if ((drv->probe == NULL) ||
+		(drv->remove == NULL) ||
+		(drv->advise_acquire == NULL) ||
+		(drv->advise_release == NULL))
+		return -EINVAL;
+
+	return 0;
+}
+
+int cx8802_register_driver(struct cx8802_driver *drv)
+{
+	struct cx8802_dev *dev;
+	struct cx8802_driver *driver;
+	int err, i = 0;
+
+	printk(KERN_INFO
+	       "cx88/2: registering cx8802 driver, type: %s access: %s\n",
+	       drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
+	       drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
+
+	if ((err = cx8802_check_driver(drv)) != 0) {
+		printk(KERN_ERR "cx88/2: cx8802_driver is invalid\n");
+		return err;
+	}
+
+	mutex_lock(&cx8802_mutex);
+
+	list_for_each_entry(dev, &cx8802_devlist, devlist) {
+		printk(KERN_INFO
+		       "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
+		       dev->core->name, dev->pci->subsystem_vendor,
+		       dev->pci->subsystem_device, dev->core->board.name,
+		       dev->core->boardnr);
+
+		/* Bring up a new struct for each driver instance */
+		driver = kzalloc(sizeof(*drv),GFP_KERNEL);
+		if (driver == NULL) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		/* Snapshot of the driver registration data */
+		drv->core = dev->core;
+		drv->suspend = cx8802_suspend_common;
+		drv->resume = cx8802_resume_common;
+		drv->request_acquire = cx8802_request_acquire;
+		drv->request_release = cx8802_request_release;
+		memcpy(driver, drv, sizeof(*driver));
+
+		mutex_lock(&drv->core->lock);
+		err = drv->probe(driver);
+		if (err == 0) {
+			i++;
+			list_add_tail(&driver->drvlist, &dev->drvlist);
+		} else {
+			printk(KERN_ERR
+			       "%s/2: cx8802 probe failed, err = %d\n",
+			       dev->core->name, err);
+		}
+		mutex_unlock(&drv->core->lock);
+	}
+
+	err = i ? 0 : -ENODEV;
+out:
+	mutex_unlock(&cx8802_mutex);
+	return err;
+}
+
+int cx8802_unregister_driver(struct cx8802_driver *drv)
+{
+	struct cx8802_dev *dev;
+	struct cx8802_driver *d, *dtmp;
+	int err = 0;
+
+	printk(KERN_INFO
+	       "cx88/2: unregistering cx8802 driver, type: %s access: %s\n",
+	       drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
+	       drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
+
+	mutex_lock(&cx8802_mutex);
+
+	list_for_each_entry(dev, &cx8802_devlist, devlist) {
+		printk(KERN_INFO
+		       "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
+		       dev->core->name, dev->pci->subsystem_vendor,
+		       dev->pci->subsystem_device, dev->core->board.name,
+		       dev->core->boardnr);
+
+		mutex_lock(&dev->core->lock);
+
+		list_for_each_entry_safe(d, dtmp, &dev->drvlist, drvlist) {
+			/* only unregister the correct driver type */
+			if (d->type_id != drv->type_id)
+				continue;
+
+			err = d->remove(d);
+			if (err == 0) {
+				list_del(&d->drvlist);
+				kfree(d);
+			} else
+				printk(KERN_ERR "%s/2: cx8802 driver remove "
+				       "failed (%d)\n", dev->core->name, err);
+		}
+
+		mutex_unlock(&dev->core->lock);
+	}
+
+	mutex_unlock(&cx8802_mutex);
+
+	return err;
+}
+
+/* ----------------------------------------------------------- */
+static int __devinit cx8802_probe(struct pci_dev *pci_dev,
+			       const struct pci_device_id *pci_id)
+{
+	struct cx8802_dev *dev;
+	struct cx88_core  *core;
+	int err;
+
+	/* general setup */
+	core = cx88_core_get(pci_dev);
+	if (NULL == core)
+		return -EINVAL;
+
+	printk("%s/2: cx2388x 8802 Driver Manager\n", core->name);
+
+	err = -ENODEV;
+	if (!core->board.mpeg)
+		goto fail_core;
+
+	err = -ENOMEM;
+	dev = kzalloc(sizeof(*dev),GFP_KERNEL);
+	if (NULL == dev)
+		goto fail_core;
+	dev->pci = pci_dev;
+	dev->core = core;
+
+	/* Maintain a reference so cx88-video can query the 8802 device. */
+	core->dvbdev = dev;
+
+	err = cx8802_init_common(dev);
+	if (err != 0)
+		goto fail_free;
+
+	INIT_LIST_HEAD(&dev->drvlist);
+	mutex_lock(&cx8802_mutex);
+	list_add_tail(&dev->devlist,&cx8802_devlist);
+	mutex_unlock(&cx8802_mutex);
+
+	/* now autoload cx88-dvb or cx88-blackbird */
+	request_modules(dev);
+	return 0;
+
+ fail_free:
+	kfree(dev);
+ fail_core:
+	core->dvbdev = NULL;
+	cx88_core_put(core,pci_dev);
+	return err;
+}
+
+static void __devexit cx8802_remove(struct pci_dev *pci_dev)
+{
+	struct cx8802_dev *dev;
+
+	dev = pci_get_drvdata(pci_dev);
+
+	dprintk( 1, "%s\n", __func__);
+
+	flush_request_modules(dev);
+
+	mutex_lock(&dev->core->lock);
+
+	if (!list_empty(&dev->drvlist)) {
+		struct cx8802_driver *drv, *tmp;
+		int err;
+
+		printk(KERN_WARNING "%s/2: Trying to remove cx8802 driver "
+		       "while cx8802 sub-drivers still loaded?!\n",
+		       dev->core->name);
+
+		list_for_each_entry_safe(drv, tmp, &dev->drvlist, drvlist) {
+			err = drv->remove(drv);
+			if (err == 0) {
+				list_del(&drv->drvlist);
+			} else
+				printk(KERN_ERR "%s/2: cx8802 driver remove "
+				       "failed (%d)\n", dev->core->name, err);
+			kfree(drv);
+		}
+	}
+
+	mutex_unlock(&dev->core->lock);
+
+	/* Destroy any 8802 reference. */
+	dev->core->dvbdev = NULL;
+
+	/* common */
+	cx8802_fini_common(dev);
+	cx88_core_put(dev->core,dev->pci);
+	kfree(dev);
+}
+
+static const struct pci_device_id cx8802_pci_tbl[] = {
+	{
+		.vendor       = 0x14f1,
+		.device       = 0x8802,
+		.subvendor    = PCI_ANY_ID,
+		.subdevice    = PCI_ANY_ID,
+	},{
+		/* --- end of list --- */
+	}
+};
+MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
+
+static struct pci_driver cx8802_pci_driver = {
+	.name     = "cx88-mpeg driver manager",
+	.id_table = cx8802_pci_tbl,
+	.probe    = cx8802_probe,
+	.remove   = __devexit_p(cx8802_remove),
+};
+
+static int __init cx8802_init(void)
+{
+	printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %s loaded\n",
+	       CX88_VERSION);
+	return pci_register_driver(&cx8802_pci_driver);
+}
+
+static void __exit cx8802_fini(void)
+{
+	pci_unregister_driver(&cx8802_pci_driver);
+}
+
+module_init(cx8802_init);
+module_exit(cx8802_fini);
+EXPORT_SYMBOL(cx8802_buf_prepare);
+EXPORT_SYMBOL(cx8802_buf_queue);
+EXPORT_SYMBOL(cx8802_cancel_buffers);
+
+EXPORT_SYMBOL(cx8802_register_driver);
+EXPORT_SYMBOL(cx8802_unregister_driver);
+EXPORT_SYMBOL(cx8802_get_driver);
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
+ */
diff --git a/drivers/media/pci/cx88/cx88-reg.h b/drivers/media/pci/cx88/cx88-reg.h
new file mode 100644
index 0000000..2ec52d1
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-reg.h
@@ -0,0 +1,836 @@
+/*
+
+    cx88x-hw.h - CX2388x register offsets
+
+    Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
+		  2001 Michael Eskin
+		  2002 Yurij Sysoev <yurij@naturesoft.net>
+		  2003 Gerd Knorr <kraxel@bytesex.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _CX88_REG_H_
+#define _CX88_REG_H_
+
+/* ---------------------------------------------------------------------- */
+/* PCI IDs and config space                                               */
+
+#ifndef PCI_VENDOR_ID_CONEXANT
+# define PCI_VENDOR_ID_CONEXANT		0x14F1
+#endif
+#ifndef PCI_DEVICE_ID_CX2300_VID
+# define PCI_DEVICE_ID_CX2300_VID	0x8800
+#endif
+
+#define CX88X_DEVCTRL 0x40
+#define CX88X_EN_TBFX 0x02
+#define CX88X_EN_VSFX 0x04
+
+/* ---------------------------------------------------------------------- */
+/* PCI controller registers                                               */
+
+/* Command and Status Register */
+#define F0_CMD_STAT_MM      0x2f0004
+#define F1_CMD_STAT_MM      0x2f0104
+#define F2_CMD_STAT_MM      0x2f0204
+#define F3_CMD_STAT_MM      0x2f0304
+#define F4_CMD_STAT_MM      0x2f0404
+
+/* Device Control #1 */
+#define F0_DEV_CNTRL1_MM    0x2f0040
+#define F1_DEV_CNTRL1_MM    0x2f0140
+#define F2_DEV_CNTRL1_MM    0x2f0240
+#define F3_DEV_CNTRL1_MM    0x2f0340
+#define F4_DEV_CNTRL1_MM    0x2f0440
+
+/* Device Control #1 */
+#define F0_BAR0_MM          0x2f0010
+#define F1_BAR0_MM          0x2f0110
+#define F2_BAR0_MM          0x2f0210
+#define F3_BAR0_MM          0x2f0310
+#define F4_BAR0_MM          0x2f0410
+
+/* ---------------------------------------------------------------------- */
+/* DMA Controller registers                                               */
+
+#define MO_PDMA_STHRSH      0x200000 // Source threshold
+#define MO_PDMA_STADRS      0x200004 // Source target address
+#define MO_PDMA_SIADRS      0x200008 // Source internal address
+#define MO_PDMA_SCNTRL      0x20000C // Source control
+#define MO_PDMA_DTHRSH      0x200010 // Destination threshold
+#define MO_PDMA_DTADRS      0x200014 // Destination target address
+#define MO_PDMA_DIADRS      0x200018 // Destination internal address
+#define MO_PDMA_DCNTRL      0x20001C // Destination control
+#define MO_LD_SSID          0x200030 // Load subsystem ID
+#define MO_DEV_CNTRL2       0x200034 // Device control
+#define MO_PCI_INTMSK       0x200040 // PCI interrupt mask
+#define MO_PCI_INTSTAT      0x200044 // PCI interrupt status
+#define MO_PCI_INTMSTAT     0x200048 // PCI interrupt masked status
+#define MO_VID_INTMSK       0x200050 // Video interrupt mask
+#define MO_VID_INTSTAT      0x200054 // Video interrupt status
+#define MO_VID_INTMSTAT     0x200058 // Video interrupt masked status
+#define MO_VID_INTSSTAT     0x20005C // Video interrupt set status
+#define MO_AUD_INTMSK       0x200060 // Audio interrupt mask
+#define MO_AUD_INTSTAT      0x200064 // Audio interrupt status
+#define MO_AUD_INTMSTAT     0x200068 // Audio interrupt masked status
+#define MO_AUD_INTSSTAT     0x20006C // Audio interrupt set status
+#define MO_TS_INTMSK        0x200070 // Transport stream interrupt mask
+#define MO_TS_INTSTAT       0x200074 // Transport stream interrupt status
+#define MO_TS_INTMSTAT      0x200078 // Transport stream interrupt mask status
+#define MO_TS_INTSSTAT      0x20007C // Transport stream interrupt set status
+#define MO_VIP_INTMSK       0x200080 // VIP interrupt mask
+#define MO_VIP_INTSTAT      0x200084 // VIP interrupt status
+#define MO_VIP_INTMSTAT     0x200088 // VIP interrupt masked status
+#define MO_VIP_INTSSTAT     0x20008C // VIP interrupt set status
+#define MO_GPHST_INTMSK     0x200090 // Host interrupt mask
+#define MO_GPHST_INTSTAT    0x200094 // Host interrupt status
+#define MO_GPHST_INTMSTAT   0x200098 // Host interrupt masked status
+#define MO_GPHST_INTSSTAT   0x20009C // Host interrupt set status
+
+// DMA Channels 1-6 belong to SPIPE
+#define MO_DMA7_PTR1        0x300018 // {24}RW* DMA Current Ptr : Ch#7
+#define MO_DMA8_PTR1        0x30001C // {24}RW* DMA Current Ptr : Ch#8
+
+// DMA Channels 9-20 belong to SPIPE
+#define MO_DMA21_PTR1       0x300080 // {24}R0* DMA Current Ptr : Ch#21
+#define MO_DMA22_PTR1       0x300084 // {24}R0* DMA Current Ptr : Ch#22
+#define MO_DMA23_PTR1       0x300088 // {24}R0* DMA Current Ptr : Ch#23
+#define MO_DMA24_PTR1       0x30008C // {24}R0* DMA Current Ptr : Ch#24
+#define MO_DMA25_PTR1       0x300090 // {24}R0* DMA Current Ptr : Ch#25
+#define MO_DMA26_PTR1       0x300094 // {24}R0* DMA Current Ptr : Ch#26
+#define MO_DMA27_PTR1       0x300098 // {24}R0* DMA Current Ptr : Ch#27
+#define MO_DMA28_PTR1       0x30009C // {24}R0* DMA Current Ptr : Ch#28
+#define MO_DMA29_PTR1       0x3000A0 // {24}R0* DMA Current Ptr : Ch#29
+#define MO_DMA30_PTR1       0x3000A4 // {24}R0* DMA Current Ptr : Ch#30
+#define MO_DMA31_PTR1       0x3000A8 // {24}R0* DMA Current Ptr : Ch#31
+#define MO_DMA32_PTR1       0x3000AC // {24}R0* DMA Current Ptr : Ch#32
+
+#define MO_DMA21_PTR2       0x3000C0 // {24}RW* DMA Tab Ptr : Ch#21
+#define MO_DMA22_PTR2       0x3000C4 // {24}RW* DMA Tab Ptr : Ch#22
+#define MO_DMA23_PTR2       0x3000C8 // {24}RW* DMA Tab Ptr : Ch#23
+#define MO_DMA24_PTR2       0x3000CC // {24}RW* DMA Tab Ptr : Ch#24
+#define MO_DMA25_PTR2       0x3000D0 // {24}RW* DMA Tab Ptr : Ch#25
+#define MO_DMA26_PTR2       0x3000D4 // {24}RW* DMA Tab Ptr : Ch#26
+#define MO_DMA27_PTR2       0x3000D8 // {24}RW* DMA Tab Ptr : Ch#27
+#define MO_DMA28_PTR2       0x3000DC // {24}RW* DMA Tab Ptr : Ch#28
+#define MO_DMA29_PTR2       0x3000E0 // {24}RW* DMA Tab Ptr : Ch#29
+#define MO_DMA30_PTR2       0x3000E4 // {24}RW* DMA Tab Ptr : Ch#30
+#define MO_DMA31_PTR2       0x3000E8 // {24}RW* DMA Tab Ptr : Ch#31
+#define MO_DMA32_PTR2       0x3000EC // {24}RW* DMA Tab Ptr : Ch#32
+
+#define MO_DMA21_CNT1       0x300100 // {11}RW* DMA Buffer Size : Ch#21
+#define MO_DMA22_CNT1       0x300104 // {11}RW* DMA Buffer Size : Ch#22
+#define MO_DMA23_CNT1       0x300108 // {11}RW* DMA Buffer Size : Ch#23
+#define MO_DMA24_CNT1       0x30010C // {11}RW* DMA Buffer Size : Ch#24
+#define MO_DMA25_CNT1       0x300110 // {11}RW* DMA Buffer Size : Ch#25
+#define MO_DMA26_CNT1       0x300114 // {11}RW* DMA Buffer Size : Ch#26
+#define MO_DMA27_CNT1       0x300118 // {11}RW* DMA Buffer Size : Ch#27
+#define MO_DMA28_CNT1       0x30011C // {11}RW* DMA Buffer Size : Ch#28
+#define MO_DMA29_CNT1       0x300120 // {11}RW* DMA Buffer Size : Ch#29
+#define MO_DMA30_CNT1       0x300124 // {11}RW* DMA Buffer Size : Ch#30
+#define MO_DMA31_CNT1       0x300128 // {11}RW* DMA Buffer Size : Ch#31
+#define MO_DMA32_CNT1       0x30012C // {11}RW* DMA Buffer Size : Ch#32
+
+#define MO_DMA21_CNT2       0x300140 // {11}RW* DMA Table Size : Ch#21
+#define MO_DMA22_CNT2       0x300144 // {11}RW* DMA Table Size : Ch#22
+#define MO_DMA23_CNT2       0x300148 // {11}RW* DMA Table Size : Ch#23
+#define MO_DMA24_CNT2       0x30014C // {11}RW* DMA Table Size : Ch#24
+#define MO_DMA25_CNT2       0x300150 // {11}RW* DMA Table Size : Ch#25
+#define MO_DMA26_CNT2       0x300154 // {11}RW* DMA Table Size : Ch#26
+#define MO_DMA27_CNT2       0x300158 // {11}RW* DMA Table Size : Ch#27
+#define MO_DMA28_CNT2       0x30015C // {11}RW* DMA Table Size : Ch#28
+#define MO_DMA29_CNT2       0x300160 // {11}RW* DMA Table Size : Ch#29
+#define MO_DMA30_CNT2       0x300164 // {11}RW* DMA Table Size : Ch#30
+#define MO_DMA31_CNT2       0x300168 // {11}RW* DMA Table Size : Ch#31
+#define MO_DMA32_CNT2       0x30016C // {11}RW* DMA Table Size : Ch#32
+
+
+/* ---------------------------------------------------------------------- */
+/* Video registers                                                        */
+
+#define MO_VIDY_DMA         0x310000 // {64}RWp Video Y
+#define MO_VIDU_DMA         0x310008 // {64}RWp Video U
+#define MO_VIDV_DMA         0x310010 // {64}RWp Video V
+#define MO_VBI_DMA          0x310018 // {64}RWp VBI (Vertical blanking interval)
+
+#define MO_DEVICE_STATUS    0x310100
+#define MO_INPUT_FORMAT     0x310104
+#define MO_AGC_BURST        0x31010c
+#define MO_CONTR_BRIGHT     0x310110
+#define MO_UV_SATURATION    0x310114
+#define MO_HUE              0x310118
+#define MO_HTOTAL           0x310120
+#define MO_HDELAY_EVEN      0x310124
+#define MO_HDELAY_ODD       0x310128
+#define MO_VDELAY_ODD       0x31012c
+#define MO_VDELAY_EVEN      0x310130
+#define MO_HACTIVE_EVEN     0x31013c
+#define MO_HACTIVE_ODD      0x310140
+#define MO_VACTIVE_EVEN     0x310144
+#define MO_VACTIVE_ODD      0x310148
+#define MO_HSCALE_EVEN      0x31014c
+#define MO_HSCALE_ODD       0x310150
+#define MO_VSCALE_EVEN      0x310154
+#define MO_FILTER_EVEN      0x31015c
+#define MO_VSCALE_ODD       0x310158
+#define MO_FILTER_ODD       0x310160
+#define MO_OUTPUT_FORMAT    0x310164
+
+#define MO_PLL_REG          0x310168 // PLL register
+#define MO_PLL_ADJ_CTRL     0x31016c // PLL adjust control register
+#define MO_SCONV_REG        0x310170 // sample rate conversion register
+#define MO_SCONV_FIFO       0x310174 // sample rate conversion fifo
+#define MO_SUB_STEP         0x310178 // subcarrier step size
+#define MO_SUB_STEP_DR      0x31017c // subcarrier step size for DR line
+
+#define MO_CAPTURE_CTRL     0x310180 // capture control
+#define MO_COLOR_CTRL       0x310184
+#define MO_VBI_PACKET       0x310188 // vbi packet size / delay
+#define MO_FIELD_COUNT      0x310190 // field counter
+#define MO_VIP_CONFIG       0x310194
+#define MO_VBOS_CONTROL	    0x3101a8
+
+#define MO_AGC_BACK_VBI     0x310200
+#define MO_AGC_SYNC_TIP1    0x310208
+
+#define MO_VIDY_GPCNT       0x31C020 // {16}RO Video Y general purpose counter
+#define MO_VIDU_GPCNT       0x31C024 // {16}RO Video U general purpose counter
+#define MO_VIDV_GPCNT       0x31C028 // {16}RO Video V general purpose counter
+#define MO_VBI_GPCNT        0x31C02C // {16}RO VBI general purpose counter
+#define MO_VIDY_GPCNTRL     0x31C030 // {2}WO Video Y general purpose control
+#define MO_VIDU_GPCNTRL     0x31C034 // {2}WO Video U general purpose control
+#define MO_VIDV_GPCNTRL     0x31C038 // {2}WO Video V general purpose control
+#define MO_VBI_GPCNTRL      0x31C03C // {2}WO VBI general purpose counter
+#define MO_VID_DMACNTRL     0x31C040 // {8}RW Video DMA control
+#define MO_VID_XFR_STAT     0x31C044 // {1}RO Video transfer status
+
+
+/* ---------------------------------------------------------------------- */
+/* audio registers                                                        */
+
+#define MO_AUDD_DMA         0x320000 // {64}RWp Audio downstream
+#define MO_AUDU_DMA         0x320008 // {64}RWp Audio upstream
+#define MO_AUDR_DMA         0x320010 // {64}RWp Audio RDS (downstream)
+#define MO_AUDD_GPCNT       0x32C020 // {16}RO Audio down general purpose counter
+#define MO_AUDU_GPCNT       0x32C024 // {16}RO Audio up general purpose counter
+#define MO_AUDR_GPCNT       0x32C028 // {16}RO Audio RDS general purpose counter
+#define MO_AUDD_GPCNTRL     0x32C030 // {2}WO Audio down general purpose control
+#define MO_AUDU_GPCNTRL     0x32C034 // {2}WO Audio up general purpose control
+#define MO_AUDR_GPCNTRL     0x32C038 // {2}WO Audio RDS general purpose control
+#define MO_AUD_DMACNTRL     0x32C040 // {6}RW Audio DMA control
+#define MO_AUD_XFR_STAT     0x32C044 // {1}RO Audio transfer status
+#define MO_AUDD_LNGTH       0x32C048 // {12}RW Audio down line length
+#define MO_AUDR_LNGTH       0x32C04C // {12}RW Audio RDS line length
+
+#define AUD_INIT                 0x320100
+#define AUD_INIT_LD              0x320104
+#define AUD_SOFT_RESET           0x320108
+#define AUD_I2SINPUTCNTL         0x320120
+#define AUD_BAUDRATE             0x320124
+#define AUD_I2SOUTPUTCNTL        0x320128
+#define AAGC_HYST                0x320134
+#define AAGC_GAIN                0x320138
+#define AAGC_DEF                 0x32013c
+#define AUD_IIR1_0_SEL           0x320150
+#define AUD_IIR1_0_SHIFT         0x320154
+#define AUD_IIR1_1_SEL           0x320158
+#define AUD_IIR1_1_SHIFT         0x32015c
+#define AUD_IIR1_2_SEL           0x320160
+#define AUD_IIR1_2_SHIFT         0x320164
+#define AUD_IIR1_3_SEL           0x320168
+#define AUD_IIR1_3_SHIFT         0x32016c
+#define AUD_IIR1_4_SEL           0x320170
+#define AUD_IIR1_4_SHIFT         0x32017c
+#define AUD_IIR1_5_SEL           0x320180
+#define AUD_IIR1_5_SHIFT         0x320184
+#define AUD_IIR2_0_SEL           0x320190
+#define AUD_IIR2_0_SHIFT         0x320194
+#define AUD_IIR2_1_SEL           0x320198
+#define AUD_IIR2_1_SHIFT         0x32019c
+#define AUD_IIR2_2_SEL           0x3201a0
+#define AUD_IIR2_2_SHIFT         0x3201a4
+#define AUD_IIR2_3_SEL           0x3201a8
+#define AUD_IIR2_3_SHIFT         0x3201ac
+#define AUD_IIR3_0_SEL           0x3201c0
+#define AUD_IIR3_0_SHIFT         0x3201c4
+#define AUD_IIR3_1_SEL           0x3201c8
+#define AUD_IIR3_1_SHIFT         0x3201cc
+#define AUD_IIR3_2_SEL           0x3201d0
+#define AUD_IIR3_2_SHIFT         0x3201d4
+#define AUD_IIR4_0_SEL           0x3201e0
+#define AUD_IIR4_0_SHIFT         0x3201e4
+#define AUD_IIR4_1_SEL           0x3201e8
+#define AUD_IIR4_1_SHIFT         0x3201ec
+#define AUD_IIR4_2_SEL           0x3201f0
+#define AUD_IIR4_2_SHIFT         0x3201f4
+#define AUD_IIR4_0_CA0           0x320200
+#define AUD_IIR4_0_CA1           0x320204
+#define AUD_IIR4_0_CA2           0x320208
+#define AUD_IIR4_0_CB0           0x32020c
+#define AUD_IIR4_0_CB1           0x320210
+#define AUD_IIR4_1_CA0           0x320214
+#define AUD_IIR4_1_CA1           0x320218
+#define AUD_IIR4_1_CA2           0x32021c
+#define AUD_IIR4_1_CB0           0x320220
+#define AUD_IIR4_1_CB1           0x320224
+#define AUD_IIR4_2_CA0           0x320228
+#define AUD_IIR4_2_CA1           0x32022c
+#define AUD_IIR4_2_CA2           0x320230
+#define AUD_IIR4_2_CB0           0x320234
+#define AUD_IIR4_2_CB1           0x320238
+#define AUD_HP_MD_IIR4_1         0x320250
+#define AUD_HP_PROG_IIR4_1       0x320254
+#define AUD_FM_MODE_ENABLE       0x320258
+#define AUD_POLY0_DDS_CONSTANT   0x320270
+#define AUD_DN0_FREQ             0x320274
+#define AUD_DN1_FREQ             0x320278
+#define AUD_DN1_FREQ_SHIFT       0x32027c
+#define AUD_DN1_AFC              0x320280
+#define AUD_DN1_SRC_SEL          0x320284
+#define AUD_DN1_SHFT             0x320288
+#define AUD_DN2_FREQ             0x32028c
+#define AUD_DN2_FREQ_SHIFT       0x320290
+#define AUD_DN2_AFC              0x320294
+#define AUD_DN2_SRC_SEL          0x320298
+#define AUD_DN2_SHFT             0x32029c
+#define AUD_CRDC0_SRC_SEL        0x320300
+#define AUD_CRDC0_SHIFT          0x320304
+#define AUD_CORDIC_SHIFT_0       0x320308
+#define AUD_CRDC1_SRC_SEL        0x32030c
+#define AUD_CRDC1_SHIFT          0x320310
+#define AUD_CORDIC_SHIFT_1       0x320314
+#define AUD_DCOC_0_SRC           0x320320
+#define AUD_DCOC0_SHIFT          0x320324
+#define AUD_DCOC_0_SHIFT_IN0     0x320328
+#define AUD_DCOC_0_SHIFT_IN1     0x32032c
+#define AUD_DCOC_1_SRC           0x320330
+#define AUD_DCOC1_SHIFT          0x320334
+#define AUD_DCOC_1_SHIFT_IN0     0x320338
+#define AUD_DCOC_1_SHIFT_IN1     0x32033c
+#define AUD_DCOC_2_SRC           0x320340
+#define AUD_DCOC2_SHIFT          0x320344
+#define AUD_DCOC_2_SHIFT_IN0     0x320348
+#define AUD_DCOC_2_SHIFT_IN1     0x32034c
+#define AUD_DCOC_PASS_IN         0x320350
+#define AUD_PDET_SRC             0x320370
+#define AUD_PDET_SHIFT           0x320374
+#define AUD_PILOT_BQD_1_K0       0x320380
+#define AUD_PILOT_BQD_1_K1       0x320384
+#define AUD_PILOT_BQD_1_K2       0x320388
+#define AUD_PILOT_BQD_1_K3       0x32038c
+#define AUD_PILOT_BQD_1_K4       0x320390
+#define AUD_PILOT_BQD_2_K0       0x320394
+#define AUD_PILOT_BQD_2_K1       0x320398
+#define AUD_PILOT_BQD_2_K2       0x32039c
+#define AUD_PILOT_BQD_2_K3       0x3203a0
+#define AUD_PILOT_BQD_2_K4       0x3203a4
+#define AUD_THR_FR               0x3203c0
+#define AUD_X_PROG               0x3203c4
+#define AUD_Y_PROG               0x3203c8
+#define AUD_HARMONIC_MULT        0x3203cc
+#define AUD_C1_UP_THR            0x3203d0
+#define AUD_C1_LO_THR            0x3203d4
+#define AUD_C2_UP_THR            0x3203d8
+#define AUD_C2_LO_THR            0x3203dc
+#define AUD_PLL_EN               0x320400
+#define AUD_PLL_SRC              0x320404
+#define AUD_PLL_SHIFT            0x320408
+#define AUD_PLL_IF_SEL           0x32040c
+#define AUD_PLL_IF_SHIFT         0x320410
+#define AUD_BIQUAD_PLL_K0        0x320414
+#define AUD_BIQUAD_PLL_K1        0x320418
+#define AUD_BIQUAD_PLL_K2        0x32041c
+#define AUD_BIQUAD_PLL_K3        0x320420
+#define AUD_BIQUAD_PLL_K4        0x320424
+#define AUD_DEEMPH0_SRC_SEL      0x320440
+#define AUD_DEEMPH0_SHIFT        0x320444
+#define AUD_DEEMPH0_G0           0x320448
+#define AUD_DEEMPH0_A0           0x32044c
+#define AUD_DEEMPH0_B0           0x320450
+#define AUD_DEEMPH0_A1           0x320454
+#define AUD_DEEMPH0_B1           0x320458
+#define AUD_DEEMPH1_SRC_SEL      0x32045c
+#define AUD_DEEMPH1_SHIFT        0x320460
+#define AUD_DEEMPH1_G0           0x320464
+#define AUD_DEEMPH1_A0           0x320468
+#define AUD_DEEMPH1_B0           0x32046c
+#define AUD_DEEMPH1_A1           0x320470
+#define AUD_DEEMPH1_B1           0x320474
+#define AUD_OUT0_SEL             0x320490
+#define AUD_OUT0_SHIFT           0x320494
+#define AUD_OUT1_SEL             0x320498
+#define AUD_OUT1_SHIFT           0x32049c
+#define AUD_RDSI_SEL             0x3204a0
+#define AUD_RDSI_SHIFT           0x3204a4
+#define AUD_RDSQ_SEL             0x3204a8
+#define AUD_RDSQ_SHIFT           0x3204ac
+#define AUD_DBX_IN_GAIN          0x320500
+#define AUD_DBX_WBE_GAIN         0x320504
+#define AUD_DBX_SE_GAIN          0x320508
+#define AUD_DBX_RMS_WBE          0x32050c
+#define AUD_DBX_RMS_SE           0x320510
+#define AUD_DBX_SE_BYPASS        0x320514
+#define AUD_FAWDETCTL            0x320530
+#define AUD_FAWDETWINCTL         0x320534
+#define AUD_DEEMPHGAIN_R         0x320538
+#define AUD_DEEMPHNUMER1_R       0x32053c
+#define AUD_DEEMPHNUMER2_R       0x320540
+#define AUD_DEEMPHDENOM1_R       0x320544
+#define AUD_DEEMPHDENOM2_R       0x320548
+#define AUD_ERRLOGPERIOD_R       0x32054c
+#define AUD_ERRINTRPTTHSHLD1_R   0x320550
+#define AUD_ERRINTRPTTHSHLD2_R   0x320554
+#define AUD_ERRINTRPTTHSHLD3_R   0x320558
+#define AUD_NICAM_STATUS1        0x32055c
+#define AUD_NICAM_STATUS2        0x320560
+#define AUD_ERRLOG1              0x320564
+#define AUD_ERRLOG2              0x320568
+#define AUD_ERRLOG3              0x32056c
+#define AUD_DAC_BYPASS_L         0x320580
+#define AUD_DAC_BYPASS_R         0x320584
+#define AUD_DAC_BYPASS_CTL       0x320588
+#define AUD_CTL                  0x32058c
+#define AUD_STATUS               0x320590
+#define AUD_VOL_CTL              0x320594
+#define AUD_BAL_CTL              0x320598
+#define AUD_START_TIMER          0x3205b0
+#define AUD_MODE_CHG_TIMER       0x3205b4
+#define AUD_POLYPH80SCALEFAC     0x3205b8
+#define AUD_DMD_RA_DDS           0x3205bc
+#define AUD_I2S_RA_DDS           0x3205c0
+#define AUD_RATE_THRES_DMD       0x3205d0
+#define AUD_RATE_THRES_I2S       0x3205d4
+#define AUD_RATE_ADJ1            0x3205d8
+#define AUD_RATE_ADJ2            0x3205dc
+#define AUD_RATE_ADJ3            0x3205e0
+#define AUD_RATE_ADJ4            0x3205e4
+#define AUD_RATE_ADJ5            0x3205e8
+#define AUD_APB_IN_RATE_ADJ      0x3205ec
+#define AUD_I2SCNTL              0x3205ec
+#define AUD_PHASE_FIX_CTL        0x3205f0
+#define AUD_PLL_PRESCALE         0x320600
+#define AUD_PLL_DDS              0x320604
+#define AUD_PLL_INT              0x320608
+#define AUD_PLL_FRAC             0x32060c
+#define AUD_PLL_JTAG             0x320620
+#define AUD_PLL_SPMP             0x320624
+#define AUD_AFE_12DB_EN          0x320628
+
+// Audio QAM Register Addresses
+#define AUD_PDF_DDS_CNST_BYTE2   0x320d01
+#define AUD_PDF_DDS_CNST_BYTE1   0x320d02
+#define AUD_PDF_DDS_CNST_BYTE0   0x320d03
+#define AUD_PHACC_FREQ_8MSB      0x320d2a
+#define AUD_PHACC_FREQ_8LSB      0x320d2b
+#define AUD_QAM_MODE             0x320d04
+
+
+/* ---------------------------------------------------------------------- */
+/* transport stream registers                                             */
+
+#define MO_TS_DMA           0x330000 // {64}RWp Transport stream downstream
+#define MO_TS_GPCNT         0x33C020 // {16}RO TS general purpose counter
+#define MO_TS_GPCNTRL       0x33C030 // {2}WO TS general purpose control
+#define MO_TS_DMACNTRL      0x33C040 // {6}RW TS DMA control
+#define MO_TS_XFR_STAT      0x33C044 // {1}RO TS transfer status
+#define MO_TS_LNGTH         0x33C048 // {12}RW TS line length
+
+#define TS_HW_SOP_CNTRL     0x33C04C
+#define TS_GEN_CNTRL        0x33C050
+#define TS_BD_PKT_STAT      0x33C054
+#define TS_SOP_STAT         0x33C058
+#define TS_FIFO_OVFL_STAT   0x33C05C
+#define TS_VALERR_CNTRL     0x33C060
+
+
+/* ---------------------------------------------------------------------- */
+/* VIP registers                                                          */
+
+#define MO_VIPD_DMA         0x340000 // {64}RWp VIP downstream
+#define MO_VIPU_DMA         0x340008 // {64}RWp VIP upstream
+#define MO_VIPD_GPCNT       0x34C020 // {16}RO VIP down general purpose counter
+#define MO_VIPU_GPCNT       0x34C024 // {16}RO VIP up general purpose counter
+#define MO_VIPD_GPCNTRL     0x34C030 // {2}WO VIP down general purpose control
+#define MO_VIPU_GPCNTRL     0x34C034 // {2}WO VIP up general purpose control
+#define MO_VIP_DMACNTRL     0x34C040 // {6}RW VIP DMA control
+#define MO_VIP_XFR_STAT     0x34C044 // {1}RO VIP transfer status
+#define MO_VIP_CFG          0x340048 // VIP configuration
+#define MO_VIPU_CNTRL       0x34004C // VIP upstream control #1
+#define MO_VIPD_CNTRL       0x340050 // VIP downstream control #2
+#define MO_VIPD_LNGTH       0x340054 // VIP downstream line length
+#define MO_VIP_BRSTLN       0x340058 // VIP burst length
+#define MO_VIP_INTCNTRL     0x34C05C // VIP Interrupt Control
+#define MO_VIP_XFTERM       0x340060 // VIP transfer terminate
+
+
+/* ---------------------------------------------------------------------- */
+/* misc registers                                                         */
+
+#define MO_M2M_DMA          0x350000 // {64}RWp Mem2Mem DMA Bfr
+#define MO_GP0_IO           0x350010 // {32}RW* GPIOoutput enablesdata I/O
+#define MO_GP1_IO           0x350014 // {32}RW* GPIOoutput enablesdata I/O
+#define MO_GP2_IO           0x350018 // {32}RW* GPIOoutput enablesdata I/O
+#define MO_GP3_IO           0x35001C // {32}RW* GPIO Mode/Ctrloutput enables
+#define MO_GPIO             0x350020 // {32}RW* GPIO I2C Ctrldata I/O
+#define MO_GPOE             0x350024 // {32}RW  GPIO I2C Ctrloutput enables
+#define MO_GP_ISM           0x350028 // {16}WO  GPIO Intr Sens/Pol
+
+#define MO_PLL_B            0x35C008 // {32}RW* PLL Control for ASB bus clks
+#define MO_M2M_CNT          0x35C024 // {32}RW  Mem2Mem DMA Cnt
+#define MO_M2M_XSUM         0x35C028 // {32}RO  M2M XOR-Checksum
+#define MO_CRC              0x35C02C // {16}RW  CRC16 init/result
+#define MO_CRC_D            0x35C030 // {32}WO  CRC16 new data in
+#define MO_TM_CNT_LDW       0x35C034 // {32}RO  Timer : Counter low dword
+#define MO_TM_CNT_UW        0x35C038 // {16}RO  Timer : Counter high word
+#define MO_TM_LMT_LDW       0x35C03C // {32}RW  Timer : Limit low dword
+#define MO_TM_LMT_UW        0x35C040 // {32}RW  Timer : Limit high word
+#define MO_PINMUX_IO        0x35C044 // {8}RW  Pin Mux Control
+#define MO_TSTSEL_IO        0x35C048 // {2}RW  Pin Mux Control
+#define MO_AFECFG_IO        0x35C04C // AFE configuration reg
+#define MO_DDS_IO           0x35C050 // DDS Increment reg
+#define MO_DDSCFG_IO        0x35C054 // DDS Configuration reg
+#define MO_SAMPLE_IO        0x35C058 // IRIn sample reg
+#define MO_SRST_IO          0x35C05C // Output system reset reg
+
+#define MO_INT1_MSK         0x35C060 // DMA RISC interrupt mask
+#define MO_INT1_STAT        0x35C064 // DMA RISC interrupt status
+#define MO_INT1_MSTAT       0x35C068 // DMA RISC interrupt masked status
+
+
+/* ---------------------------------------------------------------------- */
+/* i2c bus registers                                                      */
+
+#define MO_I2C              0x368000 // I2C data/control
+#define MO_I2C_DIV          (0xf<<4)
+#define MO_I2C_SYNC         (1<<3)
+#define MO_I2C_W3B          (1<<2)
+#define MO_I2C_SCL          (1<<1)
+#define MO_I2C_SDA          (1<<0)
+
+
+/* ---------------------------------------------------------------------- */
+/* general purpose host registers                                         */
+/* FIXME: tyops?  s/0x35/0x38/ ??                                         */
+
+#define MO_GPHSTD_DMA       0x350000 // {64}RWp Host downstream
+#define MO_GPHSTU_DMA       0x350008 // {64}RWp Host upstream
+#define MO_GPHSTU_CNTRL     0x380048 // Host upstream control #1
+#define MO_GPHSTD_CNTRL     0x38004C // Host downstream control #2
+#define MO_GPHSTD_LNGTH     0x380050 // Host downstream line length
+#define MO_GPHST_WSC        0x380054 // Host wait state control
+#define MO_GPHST_XFR        0x380058 // Host transfer control
+#define MO_GPHST_WDTH       0x38005C // Host interface width
+#define MO_GPHST_HDSHK      0x380060 // Host peripheral handshake
+#define MO_GPHST_MUX16      0x380064 // Host muxed 16-bit transfer parameters
+#define MO_GPHST_MODE       0x380068 // Host mode select
+
+#define MO_GPHSTD_GPCNT     0x35C020 // Host down general purpose counter
+#define MO_GPHSTU_GPCNT     0x35C024 // Host up general purpose counter
+#define MO_GPHSTD_GPCNTRL   0x38C030 // Host down general purpose control
+#define MO_GPHSTU_GPCNTRL   0x38C034 // Host up general purpose control
+#define MO_GPHST_DMACNTRL   0x38C040 // Host DMA control
+#define MO_GPHST_XFR_STAT   0x38C044 // Host transfer status
+#define MO_GPHST_SOFT_RST   0x38C06C // Host software reset
+
+
+/* ---------------------------------------------------------------------- */
+/* RISC instructions                                                      */
+
+#define RISC_SYNC		 0x80000000
+#define RISC_SYNC_ODD		 0x80000000
+#define RISC_SYNC_EVEN		 0x80000200
+#define RISC_RESYNC		 0x80008000
+#define RISC_RESYNC_ODD		 0x80008000
+#define RISC_RESYNC_EVEN	 0x80008200
+#define RISC_WRITE		 0x10000000
+#define RISC_WRITEC		 0x50000000
+#define RISC_READ		 0x90000000
+#define RISC_READC		 0xA0000000
+#define RISC_JUMP		 0x70000000
+#define RISC_SKIP		 0x20000000
+#define RISC_WRITERM		 0xB0000000
+#define RISC_WRITECM		 0xC0000000
+#define RISC_WRITECR		 0xD0000000
+#define RISC_IMM		 0x00000001
+
+#define RISC_SOL		 0x08000000
+#define RISC_EOL		 0x04000000
+
+#define RISC_IRQ2		 0x02000000
+#define RISC_IRQ1		 0x01000000
+
+#define RISC_CNT_NONE		 0x00000000
+#define RISC_CNT_INC		 0x00010000
+#define RISC_CNT_RSVR		 0x00020000
+#define RISC_CNT_RESET		 0x00030000
+#define RISC_JMP_SRP         	 0x01
+
+
+/* ---------------------------------------------------------------------- */
+/* various constants                                                      */
+
+// DMA
+/* Interrupt mask/status */
+#define PCI_INT_VIDINT		(1 <<  0)
+#define PCI_INT_AUDINT		(1 <<  1)
+#define PCI_INT_TSINT		(1 <<  2)
+#define PCI_INT_VIPINT		(1 <<  3)
+#define PCI_INT_HSTINT		(1 <<  4)
+#define PCI_INT_TM1INT		(1 <<  5)
+#define PCI_INT_SRCDMAINT	(1 <<  6)
+#define PCI_INT_DSTDMAINT	(1 <<  7)
+#define PCI_INT_RISC_RD_BERRINT	(1 << 10)
+#define PCI_INT_RISC_WR_BERRINT	(1 << 11)
+#define PCI_INT_BRDG_BERRINT	(1 << 12)
+#define PCI_INT_SRC_DMA_BERRINT	(1 << 13)
+#define PCI_INT_DST_DMA_BERRINT	(1 << 14)
+#define PCI_INT_IPB_DMA_BERRINT	(1 << 15)
+#define PCI_INT_I2CDONE		(1 << 16)
+#define PCI_INT_I2CRACK		(1 << 17)
+#define PCI_INT_IR_SMPINT	(1 << 18)
+#define PCI_INT_GPIO_INT0	(1 << 19)
+#define PCI_INT_GPIO_INT1	(1 << 20)
+
+#define SEL_BTSC     0x01
+#define SEL_EIAJ     0x02
+#define SEL_A2       0x04
+#define SEL_SAP      0x08
+#define SEL_NICAM    0x10
+#define SEL_FMRADIO  0x20
+
+// AUD_CTL
+#define AUD_INT_DN_RISCI1	(1 <<  0)
+#define AUD_INT_UP_RISCI1	(1 <<  1)
+#define AUD_INT_RDS_DN_RISCI1	(1 <<  2)
+#define AUD_INT_DN_RISCI2	(1 <<  4) /* yes, 3 is skipped */
+#define AUD_INT_UP_RISCI2	(1 <<  5)
+#define AUD_INT_RDS_DN_RISCI2	(1 <<  6)
+#define AUD_INT_DN_SYNC		(1 << 12)
+#define AUD_INT_UP_SYNC		(1 << 13)
+#define AUD_INT_RDS_DN_SYNC	(1 << 14)
+#define AUD_INT_OPC_ERR		(1 << 16)
+#define AUD_INT_BER_IRQ		(1 << 20)
+#define AUD_INT_MCHG_IRQ	(1 << 21)
+
+#define EN_BTSC_FORCE_MONO      0
+#define EN_BTSC_FORCE_STEREO    1
+#define EN_BTSC_FORCE_SAP       2
+#define EN_BTSC_AUTO_STEREO     3
+#define EN_BTSC_AUTO_SAP        4
+
+#define EN_A2_FORCE_MONO1       8
+#define EN_A2_FORCE_MONO2       9
+#define EN_A2_FORCE_STEREO      10
+#define EN_A2_AUTO_MONO2        11
+#define EN_A2_AUTO_STEREO       12
+
+#define EN_EIAJ_FORCE_MONO1     16
+#define EN_EIAJ_FORCE_MONO2     17
+#define EN_EIAJ_FORCE_STEREO    18
+#define EN_EIAJ_AUTO_MONO2      19
+#define EN_EIAJ_AUTO_STEREO     20
+
+#define EN_NICAM_FORCE_MONO1    32
+#define EN_NICAM_FORCE_MONO2    33
+#define EN_NICAM_FORCE_STEREO   34
+#define EN_NICAM_AUTO_MONO2     35
+#define EN_NICAM_AUTO_STEREO    36
+
+#define EN_FMRADIO_FORCE_MONO   24
+#define EN_FMRADIO_FORCE_STEREO 25
+#define EN_FMRADIO_AUTO_STEREO  26
+
+#define EN_NICAM_AUTO_FALLBACK  0x00000040
+#define EN_FMRADIO_EN_RDS       0x00000200
+#define EN_NICAM_TRY_AGAIN_BIT  0x00000400
+#define EN_DAC_ENABLE           0x00001000
+#define EN_I2SOUT_ENABLE        0x00002000
+#define EN_I2SIN_STR2DAC        0x00004000
+#define EN_I2SIN_ENABLE         0x00008000
+
+#define EN_DMTRX_SUMDIFF        (0 << 7)
+#define EN_DMTRX_SUMR           (1 << 7)
+#define EN_DMTRX_LR             (2 << 7)
+#define EN_DMTRX_MONO           (3 << 7)
+#define EN_DMTRX_BYPASS         (1 << 11)
+
+// Video
+#define VID_CAPTURE_CONTROL		0x310180
+
+#define CX23880_CAP_CTL_CAPTURE_VBI_ODD  (1<<3)
+#define CX23880_CAP_CTL_CAPTURE_VBI_EVEN (1<<2)
+#define CX23880_CAP_CTL_CAPTURE_ODD      (1<<1)
+#define CX23880_CAP_CTL_CAPTURE_EVEN     (1<<0)
+
+#define VideoInputMux0		 0x0
+#define VideoInputMux1		 0x1
+#define VideoInputMux2		 0x2
+#define VideoInputMux3		 0x3
+#define VideoInputTuner		 0x0
+#define VideoInputComposite	 0x1
+#define VideoInputSVideo	 0x2
+#define VideoInputOther		 0x3
+
+#define Xtal0		 0x1
+#define Xtal1		 0x2
+#define XtalAuto	 0x3
+
+#define VideoFormatAuto		 0x0
+#define VideoFormatNTSC		 0x1
+#define VideoFormatNTSCJapan	 0x2
+#define VideoFormatNTSC443	 0x3
+#define VideoFormatPAL		 0x4
+#define VideoFormatPALB		 0x4
+#define VideoFormatPALD		 0x4
+#define VideoFormatPALG		 0x4
+#define VideoFormatPALH		 0x4
+#define VideoFormatPALI		 0x4
+#define VideoFormatPALBDGHI	 0x4
+#define VideoFormatPALM		 0x5
+#define VideoFormatPALN		 0x6
+#define VideoFormatPALNC	 0x7
+#define VideoFormatPAL60	 0x8
+#define VideoFormatSECAM	 0x9
+
+#define VideoFormatAuto27MHz		 0x10
+#define VideoFormatNTSC27MHz		 0x11
+#define VideoFormatNTSCJapan27MHz	 0x12
+#define VideoFormatNTSC44327MHz		 0x13
+#define VideoFormatPAL27MHz		 0x14
+#define VideoFormatPALB27MHz		 0x14
+#define VideoFormatPALD27MHz		 0x14
+#define VideoFormatPALG27MHz		 0x14
+#define VideoFormatPALH27MHz		 0x14
+#define VideoFormatPALI27MHz		 0x14
+#define VideoFormatPALBDGHI27MHz	 0x14
+#define VideoFormatPALM27MHz		 0x15
+#define VideoFormatPALN27MHz		 0x16
+#define VideoFormatPALNC27MHz		 0x17
+#define VideoFormatPAL6027MHz		 0x18
+#define VideoFormatSECAM27MHz		 0x19
+
+#define NominalUSECAM	 0x87
+#define NominalVSECAM	 0x85
+#define NominalUNTSC	 0xFE
+#define NominalVNTSC	 0xB4
+
+#define NominalContrast  0xD8
+
+#define HFilterAutoFormat	 0x0
+#define HFilterCIF		 0x1
+#define HFilterQCIF		 0x2
+#define HFilterICON		 0x3
+
+#define VFilter2TapInterpolate  0
+#define VFilter3TapInterpolate  1
+#define VFilter4TapInterpolate  2
+#define VFilter5TapInterpolate  3
+#define VFilter2TapNoInterpolate  4
+#define VFilter3TapNoInterpolate  5
+#define VFilter4TapNoInterpolate  6
+#define VFilter5TapNoInterpolate  7
+
+#define ColorFormatRGB32	 0x0000
+#define ColorFormatRGB24	 0x0011
+#define ColorFormatRGB16	 0x0022
+#define ColorFormatRGB15	 0x0033
+#define ColorFormatYUY2		 0x0044
+#define ColorFormatBTYUV	 0x0055
+#define ColorFormatY8		 0x0066
+#define ColorFormatRGB8		 0x0077
+#define ColorFormatPL422	 0x0088
+#define ColorFormatPL411	 0x0099
+#define ColorFormatYUV12	 0x00AA
+#define ColorFormatYUV9		 0x00BB
+#define ColorFormatRAW		 0x00EE
+#define ColorFormatBSWAP         0x0300
+#define ColorFormatWSWAP         0x0c00
+#define ColorFormatEvenMask      0x050f
+#define ColorFormatOddMask       0x0af0
+#define ColorFormatGamma         0x1000
+
+#define Interlaced		 0x1
+#define NonInterlaced		 0x0
+
+#define FieldEven		 0x1
+#define FieldOdd		 0x0
+
+#define TGReadWriteMode		 0x0
+#define TGEnableMode		 0x1
+
+#define DV_CbAlign		 0x0
+#define DV_Y0Align		 0x1
+#define DV_CrAlign		 0x2
+#define DV_Y1Align		 0x3
+
+#define DVF_Analog		 0x0
+#define DVF_CCIR656		 0x1
+#define DVF_ByteStream		 0x2
+#define DVF_ExtVSYNC		 0x4
+#define DVF_ExtField		 0x5
+
+#define CHANNEL_VID_Y		 0x1
+#define CHANNEL_VID_U		 0x2
+#define CHANNEL_VID_V		 0x3
+#define CHANNEL_VID_VBI		 0x4
+#define CHANNEL_AUD_DN		 0x5
+#define CHANNEL_AUD_UP		 0x6
+#define CHANNEL_AUD_RDS_DN	 0x7
+#define CHANNEL_MPEG_DN		 0x8
+#define CHANNEL_VIP_DN		 0x9
+#define CHANNEL_VIP_UP		 0xA
+#define CHANNEL_HOST_DN		 0xB
+#define CHANNEL_HOST_UP		 0xC
+#define CHANNEL_FIRST		 0x1
+#define CHANNEL_LAST		 0xC
+
+#define GP_COUNT_CONTROL_NONE		 0x0
+#define GP_COUNT_CONTROL_INC		 0x1
+#define GP_COUNT_CONTROL_RESERVED	 0x2
+#define GP_COUNT_CONTROL_RESET		 0x3
+
+#define PLL_PRESCALE_BY_2  2
+#define PLL_PRESCALE_BY_3  3
+#define PLL_PRESCALE_BY_4  4
+#define PLL_PRESCALE_BY_5  5
+
+#define HLNotchFilter4xFsc	 0
+#define HLNotchFilterSquare	 1
+#define HLNotchFilter135NTSC	 2
+#define HLNotchFilter135PAL	 3
+
+#define NTSC_8x_SUB_CARRIER  28.63636E6
+#define PAL_8x_SUB_CARRIER  35.46895E6
+
+// Default analog settings
+#define DEFAULT_HUE_NTSC			0x00
+#define DEFAULT_BRIGHTNESS_NTSC			0x00
+#define DEFAULT_CONTRAST_NTSC			0x39
+#define DEFAULT_SAT_U_NTSC			0x7F
+#define DEFAULT_SAT_V_NTSC			0x5A
+
+typedef enum
+{
+	SOURCE_TUNER = 0,
+	SOURCE_COMPOSITE,
+	SOURCE_SVIDEO,
+	SOURCE_OTHER1,
+	SOURCE_OTHER2,
+	SOURCE_COMPVIASVIDEO,
+	SOURCE_CCIR656
+} VIDEOSOURCETYPE;
+
+#endif /* _CX88_REG_H_ */
diff --git a/drivers/media/pci/cx88/cx88-tvaudio.c b/drivers/media/pci/cx88/cx88-tvaudio.c
new file mode 100644
index 0000000..770ec05
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-tvaudio.c
@@ -0,0 +1,1059 @@
+/*
+
+    cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver
+
+     (c) 2001 Michael Eskin, Tom Zakrajsek [Windows version]
+     (c) 2002 Yurij Sysoev <yurij@naturesoft.net>
+     (c) 2003 Gerd Knorr <kraxel@bytesex.org>
+
+    -----------------------------------------------------------------------
+
+    Lot of voodoo here.  Even the data sheet doesn't help to
+    understand what is going on here, the documentation for the audio
+    part of the cx2388x chip is *very* bad.
+
+    Some of this comes from party done linux driver sources I got from
+    [undocumented].
+
+    Some comes from the dscaler sources, one of the dscaler driver guy works
+    for Conexant ...
+
+    -----------------------------------------------------------------------
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/freezer.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/signal.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+
+#include "cx88.h"
+
+static unsigned int audio_debug;
+module_param(audio_debug, int, 0644);
+MODULE_PARM_DESC(audio_debug, "enable debug messages [audio]");
+
+static unsigned int always_analog;
+module_param(always_analog,int,0644);
+MODULE_PARM_DESC(always_analog,"force analog audio out");
+
+static unsigned int radio_deemphasis;
+module_param(radio_deemphasis,int,0644);
+MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, "
+		 "0=None, 1=50us (elsewhere), 2=75us (USA)");
+
+#define dprintk(fmt, arg...)	if (audio_debug) \
+	printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
+
+/* ----------------------------------------------------------- */
+
+static const char * const aud_ctl_names[64] = {
+	[EN_BTSC_FORCE_MONO] = "BTSC_FORCE_MONO",
+	[EN_BTSC_FORCE_STEREO] = "BTSC_FORCE_STEREO",
+	[EN_BTSC_FORCE_SAP] = "BTSC_FORCE_SAP",
+	[EN_BTSC_AUTO_STEREO] = "BTSC_AUTO_STEREO",
+	[EN_BTSC_AUTO_SAP] = "BTSC_AUTO_SAP",
+	[EN_A2_FORCE_MONO1] = "A2_FORCE_MONO1",
+	[EN_A2_FORCE_MONO2] = "A2_FORCE_MONO2",
+	[EN_A2_FORCE_STEREO] = "A2_FORCE_STEREO",
+	[EN_A2_AUTO_MONO2] = "A2_AUTO_MONO2",
+	[EN_A2_AUTO_STEREO] = "A2_AUTO_STEREO",
+	[EN_EIAJ_FORCE_MONO1] = "EIAJ_FORCE_MONO1",
+	[EN_EIAJ_FORCE_MONO2] = "EIAJ_FORCE_MONO2",
+	[EN_EIAJ_FORCE_STEREO] = "EIAJ_FORCE_STEREO",
+	[EN_EIAJ_AUTO_MONO2] = "EIAJ_AUTO_MONO2",
+	[EN_EIAJ_AUTO_STEREO] = "EIAJ_AUTO_STEREO",
+	[EN_NICAM_FORCE_MONO1] = "NICAM_FORCE_MONO1",
+	[EN_NICAM_FORCE_MONO2] = "NICAM_FORCE_MONO2",
+	[EN_NICAM_FORCE_STEREO] = "NICAM_FORCE_STEREO",
+	[EN_NICAM_AUTO_MONO2] = "NICAM_AUTO_MONO2",
+	[EN_NICAM_AUTO_STEREO] = "NICAM_AUTO_STEREO",
+	[EN_FMRADIO_FORCE_MONO] = "FMRADIO_FORCE_MONO",
+	[EN_FMRADIO_FORCE_STEREO] = "FMRADIO_FORCE_STEREO",
+	[EN_FMRADIO_AUTO_STEREO] = "FMRADIO_AUTO_STEREO",
+};
+
+struct rlist {
+	u32 reg;
+	u32 val;
+};
+
+static void set_audio_registers(struct cx88_core *core, const struct rlist *l)
+{
+	int i;
+
+	for (i = 0; l[i].reg; i++) {
+		switch (l[i].reg) {
+		case AUD_PDF_DDS_CNST_BYTE2:
+		case AUD_PDF_DDS_CNST_BYTE1:
+		case AUD_PDF_DDS_CNST_BYTE0:
+		case AUD_QAM_MODE:
+		case AUD_PHACC_FREQ_8MSB:
+		case AUD_PHACC_FREQ_8LSB:
+			cx_writeb(l[i].reg, l[i].val);
+			break;
+		default:
+			cx_write(l[i].reg, l[i].val);
+			break;
+		}
+	}
+}
+
+static void set_audio_start(struct cx88_core *core, u32 mode)
+{
+	/* mute */
+	cx_write(AUD_VOL_CTL, (1 << 6));
+
+	/* start programming */
+	cx_write(AUD_INIT, mode);
+	cx_write(AUD_INIT_LD, 0x0001);
+	cx_write(AUD_SOFT_RESET, 0x0001);
+}
+
+static void set_audio_finish(struct cx88_core *core, u32 ctl)
+{
+	u32 volume;
+
+	/* restart dma; This avoids buzz in NICAM and is good in others  */
+	cx88_stop_audio_dma(core);
+	cx_write(AUD_RATE_THRES_DMD, 0x000000C0);
+	cx88_start_audio_dma(core);
+
+	if (core->board.mpeg & CX88_MPEG_BLACKBIRD) {
+		cx_write(AUD_I2SINPUTCNTL, 4);
+		cx_write(AUD_BAUDRATE, 1);
+		/* 'pass-thru mode': this enables the i2s output to the mpeg encoder */
+		cx_set(AUD_CTL, EN_I2SOUT_ENABLE);
+		cx_write(AUD_I2SOUTPUTCNTL, 1);
+		cx_write(AUD_I2SCNTL, 0);
+		/* cx_write(AUD_APB_IN_RATE_ADJ, 0); */
+	}
+	if ((always_analog) || (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))) {
+		ctl |= EN_DAC_ENABLE;
+		cx_write(AUD_CTL, ctl);
+	}
+
+	/* finish programming */
+	cx_write(AUD_SOFT_RESET, 0x0000);
+
+	/* unmute */
+	volume = cx_sread(SHADOW_AUD_VOL_CTL);
+	cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, volume);
+
+	core->last_change = jiffies;
+}
+
+/* ----------------------------------------------------------- */
+
+static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap,
+				    u32 mode)
+{
+	static const struct rlist btsc[] = {
+		{AUD_AFE_12DB_EN, 0x00000001},
+		{AUD_OUT1_SEL, 0x00000013},
+		{AUD_OUT1_SHIFT, 0x00000000},
+		{AUD_POLY0_DDS_CONSTANT, 0x0012010c},
+		{AUD_DMD_RA_DDS, 0x00c3e7aa},
+		{AUD_DBX_IN_GAIN, 0x00004734},
+		{AUD_DBX_WBE_GAIN, 0x00004640},
+		{AUD_DBX_SE_GAIN, 0x00008d31},
+		{AUD_DCOC_0_SRC, 0x0000001a},
+		{AUD_IIR1_4_SEL, 0x00000021},
+		{AUD_DCOC_PASS_IN, 0x00000003},
+		{AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+		{AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+		{AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+		{AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+		{AUD_DN0_FREQ, 0x0000283b},
+		{AUD_DN2_SRC_SEL, 0x00000008},
+		{AUD_DN2_FREQ, 0x00003000},
+		{AUD_DN2_AFC, 0x00000002},
+		{AUD_DN2_SHFT, 0x00000000},
+		{AUD_IIR2_2_SEL, 0x00000020},
+		{AUD_IIR2_2_SHIFT, 0x00000000},
+		{AUD_IIR2_3_SEL, 0x0000001f},
+		{AUD_IIR2_3_SHIFT, 0x00000000},
+		{AUD_CRDC1_SRC_SEL, 0x000003ce},
+		{AUD_CRDC1_SHIFT, 0x00000000},
+		{AUD_CORDIC_SHIFT_1, 0x00000007},
+		{AUD_DCOC_1_SRC, 0x0000001b},
+		{AUD_DCOC1_SHIFT, 0x00000000},
+		{AUD_RDSI_SEL, 0x00000008},
+		{AUD_RDSQ_SEL, 0x00000008},
+		{AUD_RDSI_SHIFT, 0x00000000},
+		{AUD_RDSQ_SHIFT, 0x00000000},
+		{AUD_POLYPH80SCALEFAC, 0x00000003},
+		{ /* end of list */ },
+	};
+	static const struct rlist btsc_sap[] = {
+		{AUD_AFE_12DB_EN, 0x00000001},
+		{AUD_DBX_IN_GAIN, 0x00007200},
+		{AUD_DBX_WBE_GAIN, 0x00006200},
+		{AUD_DBX_SE_GAIN, 0x00006200},
+		{AUD_IIR1_1_SEL, 0x00000000},
+		{AUD_IIR1_3_SEL, 0x00000001},
+		{AUD_DN1_SRC_SEL, 0x00000007},
+		{AUD_IIR1_4_SHIFT, 0x00000006},
+		{AUD_IIR2_1_SHIFT, 0x00000000},
+		{AUD_IIR2_2_SHIFT, 0x00000000},
+		{AUD_IIR3_0_SHIFT, 0x00000000},
+		{AUD_IIR3_1_SHIFT, 0x00000000},
+		{AUD_IIR3_0_SEL, 0x0000000d},
+		{AUD_IIR3_1_SEL, 0x0000000e},
+		{AUD_DEEMPH1_SRC_SEL, 0x00000014},
+		{AUD_DEEMPH1_SHIFT, 0x00000000},
+		{AUD_DEEMPH1_G0, 0x00004000},
+		{AUD_DEEMPH1_A0, 0x00000000},
+		{AUD_DEEMPH1_B0, 0x00000000},
+		{AUD_DEEMPH1_A1, 0x00000000},
+		{AUD_DEEMPH1_B1, 0x00000000},
+		{AUD_OUT0_SEL, 0x0000003f},
+		{AUD_OUT1_SEL, 0x0000003f},
+		{AUD_DN1_AFC, 0x00000002},
+		{AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+		{AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+		{AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+		{AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+		{AUD_IIR1_0_SEL, 0x0000001d},
+		{AUD_IIR1_2_SEL, 0x0000001e},
+		{AUD_IIR2_1_SEL, 0x00000002},
+		{AUD_IIR2_2_SEL, 0x00000004},
+		{AUD_IIR3_2_SEL, 0x0000000f},
+		{AUD_DCOC2_SHIFT, 0x00000001},
+		{AUD_IIR3_2_SHIFT, 0x00000001},
+		{AUD_DEEMPH0_SRC_SEL, 0x00000014},
+		{AUD_CORDIC_SHIFT_1, 0x00000006},
+		{AUD_POLY0_DDS_CONSTANT, 0x000e4db2},
+		{AUD_DMD_RA_DDS, 0x00f696e6},
+		{AUD_IIR2_3_SEL, 0x00000025},
+		{AUD_IIR1_4_SEL, 0x00000021},
+		{AUD_DN1_FREQ, 0x0000c965},
+		{AUD_DCOC_PASS_IN, 0x00000003},
+		{AUD_DCOC_0_SRC, 0x0000001a},
+		{AUD_DCOC_1_SRC, 0x0000001b},
+		{AUD_DCOC1_SHIFT, 0x00000000},
+		{AUD_RDSI_SEL, 0x00000009},
+		{AUD_RDSQ_SEL, 0x00000009},
+		{AUD_RDSI_SHIFT, 0x00000000},
+		{AUD_RDSQ_SHIFT, 0x00000000},
+		{AUD_POLYPH80SCALEFAC, 0x00000003},
+		{ /* end of list */ },
+	};
+
+	mode |= EN_FMRADIO_EN_RDS;
+
+	if (sap) {
+		dprintk("%s SAP (status: unknown)\n", __func__);
+		set_audio_start(core, SEL_SAP);
+		set_audio_registers(core, btsc_sap);
+		set_audio_finish(core, mode);
+	} else {
+		dprintk("%s (status: known-good)\n", __func__);
+		set_audio_start(core, SEL_BTSC);
+		set_audio_registers(core, btsc);
+		set_audio_finish(core, mode);
+	}
+}
+
+static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode)
+{
+	static const struct rlist nicam_l[] = {
+		{AUD_AFE_12DB_EN, 0x00000001},
+		{AUD_RATE_ADJ1, 0x00000060},
+		{AUD_RATE_ADJ2, 0x000000F9},
+		{AUD_RATE_ADJ3, 0x000001CC},
+		{AUD_RATE_ADJ4, 0x000002B3},
+		{AUD_RATE_ADJ5, 0x00000726},
+		{AUD_DEEMPHDENOM1_R, 0x0000F3D0},
+		{AUD_DEEMPHDENOM2_R, 0x00000000},
+		{AUD_ERRLOGPERIOD_R, 0x00000064},
+		{AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF},
+		{AUD_ERRINTRPTTHSHLD2_R, 0x0000001F},
+		{AUD_ERRINTRPTTHSHLD3_R, 0x0000000F},
+		{AUD_POLYPH80SCALEFAC, 0x00000003},
+		{AUD_DMD_RA_DDS, 0x00C00000},
+		{AUD_PLL_INT, 0x0000001E},
+		{AUD_PLL_DDS, 0x00000000},
+		{AUD_PLL_FRAC, 0x0000E542},
+		{AUD_START_TIMER, 0x00000000},
+		{AUD_DEEMPHNUMER1_R, 0x000353DE},
+		{AUD_DEEMPHNUMER2_R, 0x000001B1},
+		{AUD_PDF_DDS_CNST_BYTE2, 0x06},
+		{AUD_PDF_DDS_CNST_BYTE1, 0x82},
+		{AUD_PDF_DDS_CNST_BYTE0, 0x12},
+		{AUD_QAM_MODE, 0x05},
+		{AUD_PHACC_FREQ_8MSB, 0x34},
+		{AUD_PHACC_FREQ_8LSB, 0x4C},
+		{AUD_DEEMPHGAIN_R, 0x00006680},
+		{AUD_RATE_THRES_DMD, 0x000000C0},
+		{ /* end of list */ },
+	};
+
+	static const struct rlist nicam_bgdki_common[] = {
+		{AUD_AFE_12DB_EN, 0x00000001},
+		{AUD_RATE_ADJ1, 0x00000010},
+		{AUD_RATE_ADJ2, 0x00000040},
+		{AUD_RATE_ADJ3, 0x00000100},
+		{AUD_RATE_ADJ4, 0x00000400},
+		{AUD_RATE_ADJ5, 0x00001000},
+		{AUD_ERRLOGPERIOD_R, 0x00000fff},
+		{AUD_ERRINTRPTTHSHLD1_R, 0x000003ff},
+		{AUD_ERRINTRPTTHSHLD2_R, 0x000000ff},
+		{AUD_ERRINTRPTTHSHLD3_R, 0x0000003f},
+		{AUD_POLYPH80SCALEFAC, 0x00000003},
+		{AUD_DEEMPHGAIN_R, 0x000023c2},
+		{AUD_DEEMPHNUMER1_R, 0x0002a7bc},
+		{AUD_DEEMPHNUMER2_R, 0x0003023e},
+		{AUD_DEEMPHDENOM1_R, 0x0000f3d0},
+		{AUD_DEEMPHDENOM2_R, 0x00000000},
+		{AUD_PDF_DDS_CNST_BYTE2, 0x06},
+		{AUD_PDF_DDS_CNST_BYTE1, 0x82},
+		{AUD_QAM_MODE, 0x05},
+		{ /* end of list */ },
+	};
+
+	static const struct rlist nicam_i[] = {
+		{AUD_PDF_DDS_CNST_BYTE0, 0x12},
+		{AUD_PHACC_FREQ_8MSB, 0x3a},
+		{AUD_PHACC_FREQ_8LSB, 0x93},
+		{ /* end of list */ },
+	};
+
+	static const struct rlist nicam_default[] = {
+		{AUD_PDF_DDS_CNST_BYTE0, 0x16},
+		{AUD_PHACC_FREQ_8MSB, 0x34},
+		{AUD_PHACC_FREQ_8LSB, 0x4c},
+		{ /* end of list */ },
+	};
+
+	set_audio_start(core,SEL_NICAM);
+	switch (core->tvaudio) {
+	case WW_L:
+		dprintk("%s SECAM-L NICAM (status: devel)\n", __func__);
+		set_audio_registers(core, nicam_l);
+		break;
+	case WW_I:
+		dprintk("%s PAL-I NICAM (status: known-good)\n", __func__);
+		set_audio_registers(core, nicam_bgdki_common);
+		set_audio_registers(core, nicam_i);
+		break;
+	case WW_NONE:
+	case WW_BTSC:
+	case WW_BG:
+	case WW_DK:
+	case WW_EIAJ:
+	case WW_I2SPT:
+	case WW_FM:
+	case WW_I2SADC:
+	case WW_M:
+		dprintk("%s PAL-BGDK NICAM (status: known-good)\n", __func__);
+		set_audio_registers(core, nicam_bgdki_common);
+		set_audio_registers(core, nicam_default);
+		break;
+	};
+
+	mode |= EN_DMTRX_LR | EN_DMTRX_BYPASS;
+	set_audio_finish(core, mode);
+}
+
+static void set_audio_standard_A2(struct cx88_core *core, u32 mode)
+{
+	static const struct rlist a2_bgdk_common[] = {
+		{AUD_ERRLOGPERIOD_R, 0x00000064},
+		{AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
+		{AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
+		{AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
+		{AUD_PDF_DDS_CNST_BYTE2, 0x06},
+		{AUD_PDF_DDS_CNST_BYTE1, 0x82},
+		{AUD_PDF_DDS_CNST_BYTE0, 0x12},
+		{AUD_QAM_MODE, 0x05},
+		{AUD_PHACC_FREQ_8MSB, 0x34},
+		{AUD_PHACC_FREQ_8LSB, 0x4c},
+		{AUD_RATE_ADJ1, 0x00000100},
+		{AUD_RATE_ADJ2, 0x00000200},
+		{AUD_RATE_ADJ3, 0x00000300},
+		{AUD_RATE_ADJ4, 0x00000400},
+		{AUD_RATE_ADJ5, 0x00000500},
+		{AUD_THR_FR, 0x00000000},
+		{AAGC_HYST, 0x0000001a},
+		{AUD_PILOT_BQD_1_K0, 0x0000755b},
+		{AUD_PILOT_BQD_1_K1, 0x00551340},
+		{AUD_PILOT_BQD_1_K2, 0x006d30be},
+		{AUD_PILOT_BQD_1_K3, 0xffd394af},
+		{AUD_PILOT_BQD_1_K4, 0x00400000},
+		{AUD_PILOT_BQD_2_K0, 0x00040000},
+		{AUD_PILOT_BQD_2_K1, 0x002a4841},
+		{AUD_PILOT_BQD_2_K2, 0x00400000},
+		{AUD_PILOT_BQD_2_K3, 0x00000000},
+		{AUD_PILOT_BQD_2_K4, 0x00000000},
+		{AUD_MODE_CHG_TIMER, 0x00000040},
+		{AUD_AFE_12DB_EN, 0x00000001},
+		{AUD_CORDIC_SHIFT_0, 0x00000007},
+		{AUD_CORDIC_SHIFT_1, 0x00000007},
+		{AUD_DEEMPH0_G0, 0x00000380},
+		{AUD_DEEMPH1_G0, 0x00000380},
+		{AUD_DCOC_0_SRC, 0x0000001a},
+		{AUD_DCOC0_SHIFT, 0x00000000},
+		{AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+		{AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+		{AUD_DCOC_PASS_IN, 0x00000003},
+		{AUD_IIR3_0_SEL, 0x00000021},
+		{AUD_DN2_AFC, 0x00000002},
+		{AUD_DCOC_1_SRC, 0x0000001b},
+		{AUD_DCOC1_SHIFT, 0x00000000},
+		{AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+		{AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+		{AUD_IIR3_1_SEL, 0x00000023},
+		{AUD_RDSI_SEL, 0x00000017},
+		{AUD_RDSI_SHIFT, 0x00000000},
+		{AUD_RDSQ_SEL, 0x00000017},
+		{AUD_RDSQ_SHIFT, 0x00000000},
+		{AUD_PLL_INT, 0x0000001e},
+		{AUD_PLL_DDS, 0x00000000},
+		{AUD_PLL_FRAC, 0x0000e542},
+		{AUD_POLYPH80SCALEFAC, 0x00000001},
+		{AUD_START_TIMER, 0x00000000},
+		{ /* end of list */ },
+	};
+
+	static const struct rlist a2_bg[] = {
+		{AUD_DMD_RA_DDS, 0x002a4f2f},
+		{AUD_C1_UP_THR, 0x00007000},
+		{AUD_C1_LO_THR, 0x00005400},
+		{AUD_C2_UP_THR, 0x00005400},
+		{AUD_C2_LO_THR, 0x00003000},
+		{ /* end of list */ },
+	};
+
+	static const struct rlist a2_dk[] = {
+		{AUD_DMD_RA_DDS, 0x002a4f2f},
+		{AUD_C1_UP_THR, 0x00007000},
+		{AUD_C1_LO_THR, 0x00005400},
+		{AUD_C2_UP_THR, 0x00005400},
+		{AUD_C2_LO_THR, 0x00003000},
+		{AUD_DN0_FREQ, 0x00003a1c},
+		{AUD_DN2_FREQ, 0x0000d2e0},
+		{ /* end of list */ },
+	};
+
+	static const struct rlist a1_i[] = {
+		{AUD_ERRLOGPERIOD_R, 0x00000064},
+		{AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
+		{AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
+		{AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
+		{AUD_PDF_DDS_CNST_BYTE2, 0x06},
+		{AUD_PDF_DDS_CNST_BYTE1, 0x82},
+		{AUD_PDF_DDS_CNST_BYTE0, 0x12},
+		{AUD_QAM_MODE, 0x05},
+		{AUD_PHACC_FREQ_8MSB, 0x3a},
+		{AUD_PHACC_FREQ_8LSB, 0x93},
+		{AUD_DMD_RA_DDS, 0x002a4f2f},
+		{AUD_PLL_INT, 0x0000001e},
+		{AUD_PLL_DDS, 0x00000004},
+		{AUD_PLL_FRAC, 0x0000e542},
+		{AUD_RATE_ADJ1, 0x00000100},
+		{AUD_RATE_ADJ2, 0x00000200},
+		{AUD_RATE_ADJ3, 0x00000300},
+		{AUD_RATE_ADJ4, 0x00000400},
+		{AUD_RATE_ADJ5, 0x00000500},
+		{AUD_THR_FR, 0x00000000},
+		{AUD_PILOT_BQD_1_K0, 0x0000755b},
+		{AUD_PILOT_BQD_1_K1, 0x00551340},
+		{AUD_PILOT_BQD_1_K2, 0x006d30be},
+		{AUD_PILOT_BQD_1_K3, 0xffd394af},
+		{AUD_PILOT_BQD_1_K4, 0x00400000},
+		{AUD_PILOT_BQD_2_K0, 0x00040000},
+		{AUD_PILOT_BQD_2_K1, 0x002a4841},
+		{AUD_PILOT_BQD_2_K2, 0x00400000},
+		{AUD_PILOT_BQD_2_K3, 0x00000000},
+		{AUD_PILOT_BQD_2_K4, 0x00000000},
+		{AUD_MODE_CHG_TIMER, 0x00000060},
+		{AUD_AFE_12DB_EN, 0x00000001},
+		{AAGC_HYST, 0x0000000a},
+		{AUD_CORDIC_SHIFT_0, 0x00000007},
+		{AUD_CORDIC_SHIFT_1, 0x00000007},
+		{AUD_C1_UP_THR, 0x00007000},
+		{AUD_C1_LO_THR, 0x00005400},
+		{AUD_C2_UP_THR, 0x00005400},
+		{AUD_C2_LO_THR, 0x00003000},
+		{AUD_DCOC_0_SRC, 0x0000001a},
+		{AUD_DCOC0_SHIFT, 0x00000000},
+		{AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+		{AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+		{AUD_DCOC_PASS_IN, 0x00000003},
+		{AUD_IIR3_0_SEL, 0x00000021},
+		{AUD_DN2_AFC, 0x00000002},
+		{AUD_DCOC_1_SRC, 0x0000001b},
+		{AUD_DCOC1_SHIFT, 0x00000000},
+		{AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+		{AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+		{AUD_IIR3_1_SEL, 0x00000023},
+		{AUD_DN0_FREQ, 0x000035a3},
+		{AUD_DN2_FREQ, 0x000029c7},
+		{AUD_CRDC0_SRC_SEL, 0x00000511},
+		{AUD_IIR1_0_SEL, 0x00000001},
+		{AUD_IIR1_1_SEL, 0x00000000},
+		{AUD_IIR3_2_SEL, 0x00000003},
+		{AUD_IIR3_2_SHIFT, 0x00000000},
+		{AUD_IIR3_0_SEL, 0x00000002},
+		{AUD_IIR2_0_SEL, 0x00000021},
+		{AUD_IIR2_0_SHIFT, 0x00000002},
+		{AUD_DEEMPH0_SRC_SEL, 0x0000000b},
+		{AUD_DEEMPH1_SRC_SEL, 0x0000000b},
+		{AUD_POLYPH80SCALEFAC, 0x00000001},
+		{AUD_START_TIMER, 0x00000000},
+		{ /* end of list */ },
+	};
+
+	static const struct rlist am_l[] = {
+		{AUD_ERRLOGPERIOD_R, 0x00000064},
+		{AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF},
+		{AUD_ERRINTRPTTHSHLD2_R, 0x0000001F},
+		{AUD_ERRINTRPTTHSHLD3_R, 0x0000000F},
+		{AUD_PDF_DDS_CNST_BYTE2, 0x48},
+		{AUD_PDF_DDS_CNST_BYTE1, 0x3D},
+		{AUD_QAM_MODE, 0x00},
+		{AUD_PDF_DDS_CNST_BYTE0, 0xf5},
+		{AUD_PHACC_FREQ_8MSB, 0x3a},
+		{AUD_PHACC_FREQ_8LSB, 0x4a},
+		{AUD_DEEMPHGAIN_R, 0x00006680},
+		{AUD_DEEMPHNUMER1_R, 0x000353DE},
+		{AUD_DEEMPHNUMER2_R, 0x000001B1},
+		{AUD_DEEMPHDENOM1_R, 0x0000F3D0},
+		{AUD_DEEMPHDENOM2_R, 0x00000000},
+		{AUD_FM_MODE_ENABLE, 0x00000007},
+		{AUD_POLYPH80SCALEFAC, 0x00000003},
+		{AUD_AFE_12DB_EN, 0x00000001},
+		{AAGC_GAIN, 0x00000000},
+		{AAGC_HYST, 0x00000018},
+		{AAGC_DEF, 0x00000020},
+		{AUD_DN0_FREQ, 0x00000000},
+		{AUD_POLY0_DDS_CONSTANT, 0x000E4DB2},
+		{AUD_DCOC_0_SRC, 0x00000021},
+		{AUD_IIR1_0_SEL, 0x00000000},
+		{AUD_IIR1_0_SHIFT, 0x00000007},
+		{AUD_IIR1_1_SEL, 0x00000002},
+		{AUD_IIR1_1_SHIFT, 0x00000000},
+		{AUD_DCOC_1_SRC, 0x00000003},
+		{AUD_DCOC1_SHIFT, 0x00000000},
+		{AUD_DCOC_PASS_IN, 0x00000000},
+		{AUD_IIR1_2_SEL, 0x00000023},
+		{AUD_IIR1_2_SHIFT, 0x00000000},
+		{AUD_IIR1_3_SEL, 0x00000004},
+		{AUD_IIR1_3_SHIFT, 0x00000007},
+		{AUD_IIR1_4_SEL, 0x00000005},
+		{AUD_IIR1_4_SHIFT, 0x00000007},
+		{AUD_IIR3_0_SEL, 0x00000007},
+		{AUD_IIR3_0_SHIFT, 0x00000000},
+		{AUD_DEEMPH0_SRC_SEL, 0x00000011},
+		{AUD_DEEMPH0_SHIFT, 0x00000000},
+		{AUD_DEEMPH0_G0, 0x00007000},
+		{AUD_DEEMPH0_A0, 0x00000000},
+		{AUD_DEEMPH0_B0, 0x00000000},
+		{AUD_DEEMPH0_A1, 0x00000000},
+		{AUD_DEEMPH0_B1, 0x00000000},
+		{AUD_DEEMPH1_SRC_SEL, 0x00000011},
+		{AUD_DEEMPH1_SHIFT, 0x00000000},
+		{AUD_DEEMPH1_G0, 0x00007000},
+		{AUD_DEEMPH1_A0, 0x00000000},
+		{AUD_DEEMPH1_B0, 0x00000000},
+		{AUD_DEEMPH1_A1, 0x00000000},
+		{AUD_DEEMPH1_B1, 0x00000000},
+		{AUD_OUT0_SEL, 0x0000003F},
+		{AUD_OUT1_SEL, 0x0000003F},
+		{AUD_DMD_RA_DDS, 0x00F5C285},
+		{AUD_PLL_INT, 0x0000001E},
+		{AUD_PLL_DDS, 0x00000000},
+		{AUD_PLL_FRAC, 0x0000E542},
+		{AUD_RATE_ADJ1, 0x00000100},
+		{AUD_RATE_ADJ2, 0x00000200},
+		{AUD_RATE_ADJ3, 0x00000300},
+		{AUD_RATE_ADJ4, 0x00000400},
+		{AUD_RATE_ADJ5, 0x00000500},
+		{AUD_RATE_THRES_DMD, 0x000000C0},
+		{ /* end of list */ },
+	};
+
+	static const struct rlist a2_deemph50[] = {
+		{AUD_DEEMPH0_G0, 0x00000380},
+		{AUD_DEEMPH1_G0, 0x00000380},
+		{AUD_DEEMPHGAIN_R, 0x000011e1},
+		{AUD_DEEMPHNUMER1_R, 0x0002a7bc},
+		{AUD_DEEMPHNUMER2_R, 0x0003023c},
+		{ /* end of list */ },
+	};
+
+	set_audio_start(core, SEL_A2);
+	switch (core->tvaudio) {
+	case WW_BG:
+		dprintk("%s PAL-BG A1/2 (status: known-good)\n", __func__);
+		set_audio_registers(core, a2_bgdk_common);
+		set_audio_registers(core, a2_bg);
+		set_audio_registers(core, a2_deemph50);
+		break;
+	case WW_DK:
+		dprintk("%s PAL-DK A1/2 (status: known-good)\n", __func__);
+		set_audio_registers(core, a2_bgdk_common);
+		set_audio_registers(core, a2_dk);
+		set_audio_registers(core, a2_deemph50);
+		break;
+	case WW_I:
+		dprintk("%s PAL-I A1 (status: known-good)\n", __func__);
+		set_audio_registers(core, a1_i);
+		set_audio_registers(core, a2_deemph50);
+		break;
+	case WW_L:
+		dprintk("%s AM-L (status: devel)\n", __func__);
+		set_audio_registers(core, am_l);
+		break;
+	case WW_NONE:
+	case WW_BTSC:
+	case WW_EIAJ:
+	case WW_I2SPT:
+	case WW_FM:
+	case WW_I2SADC:
+	case WW_M:
+		dprintk("%s Warning: wrong value\n", __func__);
+		return;
+		break;
+	};
+
+	mode |= EN_FMRADIO_EN_RDS | EN_DMTRX_SUMDIFF;
+	set_audio_finish(core, mode);
+}
+
+static void set_audio_standard_EIAJ(struct cx88_core *core)
+{
+	static const struct rlist eiaj[] = {
+		/* TODO: eiaj register settings are not there yet ... */
+
+		{ /* end of list */ },
+	};
+	dprintk("%s (status: unknown)\n", __func__);
+
+	set_audio_start(core, SEL_EIAJ);
+	set_audio_registers(core, eiaj);
+	set_audio_finish(core, EN_EIAJ_AUTO_STEREO);
+}
+
+static void set_audio_standard_FM(struct cx88_core *core,
+				  enum cx88_deemph_type deemph)
+{
+	static const struct rlist fm_deemph_50[] = {
+		{AUD_DEEMPH0_G0, 0x0C45},
+		{AUD_DEEMPH0_A0, 0x6262},
+		{AUD_DEEMPH0_B0, 0x1C29},
+		{AUD_DEEMPH0_A1, 0x3FC66},
+		{AUD_DEEMPH0_B1, 0x399A},
+
+		{AUD_DEEMPH1_G0, 0x0D80},
+		{AUD_DEEMPH1_A0, 0x6262},
+		{AUD_DEEMPH1_B0, 0x1C29},
+		{AUD_DEEMPH1_A1, 0x3FC66},
+		{AUD_DEEMPH1_B1, 0x399A},
+
+		{AUD_POLYPH80SCALEFAC, 0x0003},
+		{ /* end of list */ },
+	};
+	static const struct rlist fm_deemph_75[] = {
+		{AUD_DEEMPH0_G0, 0x091B},
+		{AUD_DEEMPH0_A0, 0x6B68},
+		{AUD_DEEMPH0_B0, 0x11EC},
+		{AUD_DEEMPH0_A1, 0x3FC66},
+		{AUD_DEEMPH0_B1, 0x399A},
+
+		{AUD_DEEMPH1_G0, 0x0AA0},
+		{AUD_DEEMPH1_A0, 0x6B68},
+		{AUD_DEEMPH1_B0, 0x11EC},
+		{AUD_DEEMPH1_A1, 0x3FC66},
+		{AUD_DEEMPH1_B1, 0x399A},
+
+		{AUD_POLYPH80SCALEFAC, 0x0003},
+		{ /* end of list */ },
+	};
+
+	/* It is enough to leave default values? */
+	/* No, it's not!  The deemphasis registers are reset to the 75us
+	 * values by default.  Analyzing the spectrum of the decoded audio
+	 * reveals that "no deemphasis" is the same as 75 us, while the 50 us
+	 * setting results in less deemphasis.  */
+	static const struct rlist fm_no_deemph[] = {
+
+		{AUD_POLYPH80SCALEFAC, 0x0003},
+		{ /* end of list */ },
+	};
+
+	dprintk("%s (status: unknown)\n", __func__);
+	set_audio_start(core, SEL_FMRADIO);
+
+	switch (deemph) {
+	default:
+	case FM_NO_DEEMPH:
+		set_audio_registers(core, fm_no_deemph);
+		break;
+
+	case FM_DEEMPH_50:
+		set_audio_registers(core, fm_deemph_50);
+		break;
+
+	case FM_DEEMPH_75:
+		set_audio_registers(core, fm_deemph_75);
+		break;
+	}
+
+	set_audio_finish(core, EN_FMRADIO_AUTO_STEREO);
+}
+
+/* ----------------------------------------------------------- */
+
+static int cx88_detect_nicam(struct cx88_core *core)
+{
+	int i, j = 0;
+
+	dprintk("start nicam autodetect.\n");
+
+	for (i = 0; i < 6; i++) {
+		/* if bit1=1 then nicam is detected */
+		j += ((cx_read(AUD_NICAM_STATUS2) & 0x02) >> 1);
+
+		if (j == 1) {
+			dprintk("nicam is detected.\n");
+			return 1;
+		}
+
+		/* wait a little bit for next reading status */
+		msleep(10);
+	}
+
+	dprintk("nicam is not detected.\n");
+	return 0;
+}
+
+void cx88_set_tvaudio(struct cx88_core *core)
+{
+	switch (core->tvaudio) {
+	case WW_BTSC:
+		set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO);
+		break;
+	case WW_BG:
+	case WW_DK:
+	case WW_M:
+	case WW_I:
+	case WW_L:
+		/* prepare all dsp registers */
+		set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+
+		/* set nicam mode - otherwise
+		   AUD_NICAM_STATUS2 contains wrong values */
+		set_audio_standard_NICAM(core, EN_NICAM_AUTO_STEREO);
+		if (0 == cx88_detect_nicam(core)) {
+			/* fall back to fm / am mono */
+			set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+			core->audiomode_current = V4L2_TUNER_MODE_MONO;
+			core->use_nicam = 0;
+		} else {
+			core->use_nicam = 1;
+		}
+		break;
+	case WW_EIAJ:
+		set_audio_standard_EIAJ(core);
+		break;
+	case WW_FM:
+		set_audio_standard_FM(core, radio_deemphasis);
+		break;
+	case WW_I2SADC:
+		set_audio_start(core, 0x01);
+		/*
+		 * Slave/Philips/Autobaud
+		 * NB on Nova-S bit1 NPhilipsSony appears to be inverted:
+		 *	0= Sony, 1=Philips
+		 */
+		cx_write(AUD_I2SINPUTCNTL, core->board.i2sinputcntl);
+		/* Switch to "I2S ADC mode" */
+		cx_write(AUD_I2SCNTL, 0x1);
+		set_audio_finish(core, EN_I2SIN_ENABLE);
+		break;
+	case WW_NONE:
+	case WW_I2SPT:
+		printk("%s/0: unknown tv audio mode [%d]\n",
+		       core->name, core->tvaudio);
+		break;
+	}
+	return;
+}
+
+void cx88_newstation(struct cx88_core *core)
+{
+	core->audiomode_manual = UNSET;
+	core->last_change = jiffies;
+}
+
+void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
+{
+	static const char * const m[] = { "stereo", "dual mono", "mono", "sap" };
+	static const char * const p[] = { "no pilot", "pilot c1", "pilot c2", "?" };
+	u32 reg, mode, pilot;
+
+	reg = cx_read(AUD_STATUS);
+	mode = reg & 0x03;
+	pilot = (reg >> 2) & 0x03;
+
+	if (core->astat != reg)
+		dprintk("AUD_STATUS: 0x%x [%s/%s] ctl=%s\n",
+			reg, m[mode], p[pilot],
+			aud_ctl_names[cx_read(AUD_CTL) & 63]);
+	core->astat = reg;
+
+	t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
+	    V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+	t->rxsubchans = UNSET;
+	t->audmode = V4L2_TUNER_MODE_MONO;
+
+	switch (mode) {
+	case 0:
+		t->audmode = V4L2_TUNER_MODE_STEREO;
+		break;
+	case 1:
+		t->audmode = V4L2_TUNER_MODE_LANG2;
+		break;
+	case 2:
+		t->audmode = V4L2_TUNER_MODE_MONO;
+		break;
+	case 3:
+		t->audmode = V4L2_TUNER_MODE_SAP;
+		break;
+	}
+
+	switch (core->tvaudio) {
+	case WW_BTSC:
+	case WW_BG:
+	case WW_DK:
+	case WW_M:
+	case WW_EIAJ:
+		if (!core->use_nicam) {
+			t->rxsubchans = cx88_dsp_detect_stereo_sap(core);
+			break;
+		}
+		break;
+	case WW_NONE:
+	case WW_I:
+	case WW_L:
+	case WW_I2SPT:
+	case WW_FM:
+	case WW_I2SADC:
+		/* nothing */
+		break;
+	}
+
+	/* If software stereo detection is not supported... */
+	if (UNSET == t->rxsubchans) {
+		t->rxsubchans = V4L2_TUNER_SUB_MONO;
+		/* If the hardware itself detected stereo, also return
+		   stereo as an available subchannel */
+		if (V4L2_TUNER_MODE_STEREO == t->audmode)
+			t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+	}
+	return;
+}
+
+void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
+{
+	u32 ctl = UNSET;
+	u32 mask = UNSET;
+
+	if (manual) {
+		core->audiomode_manual = mode;
+	} else {
+		if (UNSET != core->audiomode_manual)
+			return;
+	}
+	core->audiomode_current = mode;
+
+	switch (core->tvaudio) {
+	case WW_BTSC:
+		switch (mode) {
+		case V4L2_TUNER_MODE_MONO:
+			set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_MONO);
+			break;
+		case V4L2_TUNER_MODE_LANG1:
+			set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO);
+			break;
+		case V4L2_TUNER_MODE_LANG2:
+			set_audio_standard_BTSC(core, 1, EN_BTSC_FORCE_SAP);
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+		case V4L2_TUNER_MODE_LANG1_LANG2:
+			set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_STEREO);
+			break;
+		}
+		break;
+	case WW_BG:
+	case WW_DK:
+	case WW_M:
+	case WW_I:
+	case WW_L:
+		if (1 == core->use_nicam) {
+			switch (mode) {
+			case V4L2_TUNER_MODE_MONO:
+			case V4L2_TUNER_MODE_LANG1:
+				set_audio_standard_NICAM(core,
+							 EN_NICAM_FORCE_MONO1);
+				break;
+			case V4L2_TUNER_MODE_LANG2:
+				set_audio_standard_NICAM(core,
+							 EN_NICAM_FORCE_MONO2);
+				break;
+			case V4L2_TUNER_MODE_STEREO:
+			case V4L2_TUNER_MODE_LANG1_LANG2:
+				set_audio_standard_NICAM(core,
+							 EN_NICAM_FORCE_STEREO);
+				break;
+			}
+		} else {
+			if ((core->tvaudio == WW_I) || (core->tvaudio == WW_L)) {
+				/* fall back to fm / am mono */
+				set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+			} else {
+				/* TODO: Add A2 autodection */
+				mask = 0x3f;
+				switch (mode) {
+				case V4L2_TUNER_MODE_MONO:
+				case V4L2_TUNER_MODE_LANG1:
+					ctl = EN_A2_FORCE_MONO1;
+					break;
+				case V4L2_TUNER_MODE_LANG2:
+					ctl = EN_A2_FORCE_MONO2;
+					break;
+				case V4L2_TUNER_MODE_STEREO:
+				case V4L2_TUNER_MODE_LANG1_LANG2:
+					ctl = EN_A2_FORCE_STEREO;
+					break;
+				}
+			}
+		}
+		break;
+	case WW_FM:
+		switch (mode) {
+		case V4L2_TUNER_MODE_MONO:
+			ctl = EN_FMRADIO_FORCE_MONO;
+			mask = 0x3f;
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+			ctl = EN_FMRADIO_AUTO_STEREO;
+			mask = 0x3f;
+			break;
+		}
+		break;
+	case WW_I2SADC:
+	case WW_NONE:
+	case WW_EIAJ:
+	case WW_I2SPT:
+		/* DO NOTHING */
+		break;
+	}
+
+	if (UNSET != ctl) {
+		dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x "
+			"[status=0x%x,ctl=0x%x,vol=0x%x]\n",
+			mask, ctl, cx_read(AUD_STATUS),
+			cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL));
+		cx_andor(AUD_CTL, mask, ctl);
+	}
+	return;
+}
+
+int cx88_audio_thread(void *data)
+{
+	struct cx88_core *core = data;
+	struct v4l2_tuner t;
+	u32 mode = 0;
+
+	dprintk("cx88: tvaudio thread started\n");
+	set_freezable();
+	for (;;) {
+		msleep_interruptible(1000);
+		if (kthread_should_stop())
+			break;
+		try_to_freeze();
+
+		switch (core->tvaudio) {
+		case WW_BG:
+		case WW_DK:
+		case WW_M:
+		case WW_I:
+		case WW_L:
+			if (core->use_nicam)
+				goto hw_autodetect;
+
+			/* just monitor the audio status for now ... */
+			memset(&t, 0, sizeof(t));
+			cx88_get_stereo(core, &t);
+
+			if (UNSET != core->audiomode_manual)
+				/* manually set, don't do anything. */
+				continue;
+
+			/* monitor signal and set stereo if available */
+			if (t.rxsubchans & V4L2_TUNER_SUB_STEREO)
+				mode = V4L2_TUNER_MODE_STEREO;
+			else
+				mode = V4L2_TUNER_MODE_MONO;
+			if (mode == core->audiomode_current)
+				continue;
+			/* automatically switch to best available mode */
+			cx88_set_stereo(core, mode, 0);
+			break;
+		case WW_NONE:
+		case WW_BTSC:
+		case WW_EIAJ:
+		case WW_I2SPT:
+		case WW_FM:
+		case WW_I2SADC:
+hw_autodetect:
+			/* stereo autodetection is supported by hardware so
+			   we don't need to do it manually. Do nothing. */
+			break;
+		}
+	}
+
+	dprintk("cx88: tvaudio thread exiting\n");
+	return 0;
+}
+
+/* ----------------------------------------------------------- */
+
+EXPORT_SYMBOL(cx88_set_tvaudio);
+EXPORT_SYMBOL(cx88_newstation);
+EXPORT_SYMBOL(cx88_set_stereo);
+EXPORT_SYMBOL(cx88_get_stereo);
+EXPORT_SYMBOL(cx88_audio_thread);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
+ */
diff --git a/drivers/media/pci/cx88/cx88-vbi.c b/drivers/media/pci/cx88/cx88-vbi.c
new file mode 100644
index 0000000..f8f8389
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-vbi.c
@@ -0,0 +1,245 @@
+/*
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "cx88.h"
+
+static unsigned int vbibufs = 4;
+module_param(vbibufs,int,0644);
+MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32");
+
+static unsigned int vbi_debug;
+module_param(vbi_debug,int,0644);
+MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
+
+#define dprintk(level,fmt, arg...)	if (vbi_debug >= level) \
+	printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg)
+
+/* ------------------------------------------------------------------ */
+
+int cx8800_vbi_fmt (struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct cx8800_fh  *fh   = priv;
+	struct cx8800_dev *dev  = fh->dev;
+
+	f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
+	f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+	f->fmt.vbi.offset = 244;
+	f->fmt.vbi.count[0] = VBI_LINE_COUNT;
+	f->fmt.vbi.count[1] = VBI_LINE_COUNT;
+
+	if (dev->core->tvnorm & V4L2_STD_525_60) {
+		/* ntsc */
+		f->fmt.vbi.sampling_rate = 28636363;
+		f->fmt.vbi.start[0] = 10;
+		f->fmt.vbi.start[1] = 273;
+
+	} else if (dev->core->tvnorm & V4L2_STD_625_50) {
+		/* pal */
+		f->fmt.vbi.sampling_rate = 35468950;
+		f->fmt.vbi.start[0] = 7 -1;
+		f->fmt.vbi.start[1] = 319 -1;
+	}
+	return 0;
+}
+
+static int cx8800_start_vbi_dma(struct cx8800_dev    *dev,
+			 struct cx88_dmaqueue *q,
+			 struct cx88_buffer   *buf)
+{
+	struct cx88_core *core = dev->core;
+
+	/* setup fifo + format */
+	cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH24],
+				buf->vb.width, buf->risc.dma);
+
+	cx_write(MO_VBOS_CONTROL, ( (1 << 18) |  // comb filter delay fixup
+				    (1 << 15) |  // enable vbi capture
+				    (1 << 11) ));
+
+	/* reset counter */
+	cx_write(MO_VBI_GPCNTRL, GP_COUNT_CONTROL_RESET);
+	q->count = 1;
+
+	/* enable irqs */
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT);
+	cx_set(MO_VID_INTMSK, 0x0f0088);
+
+	/* enable capture */
+	cx_set(VID_CAPTURE_CONTROL,0x18);
+
+	/* start dma */
+	cx_set(MO_DEV_CNTRL2, (1<<5));
+	cx_set(MO_VID_DMACNTRL, 0x88);
+
+	return 0;
+}
+
+int cx8800_stop_vbi_dma(struct cx8800_dev *dev)
+{
+	struct cx88_core *core = dev->core;
+
+	/* stop dma */
+	cx_clear(MO_VID_DMACNTRL, 0x88);
+
+	/* disable capture */
+	cx_clear(VID_CAPTURE_CONTROL,0x18);
+
+	/* disable irqs */
+	cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT);
+	cx_clear(MO_VID_INTMSK, 0x0f0088);
+	return 0;
+}
+
+int cx8800_restart_vbi_queue(struct cx8800_dev    *dev,
+			     struct cx88_dmaqueue *q)
+{
+	struct cx88_buffer *buf;
+
+	if (list_empty(&q->active))
+		return 0;
+
+	buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+	dprintk(2,"restart_queue [%p/%d]: restart dma\n",
+		buf, buf->vb.i);
+	cx8800_start_vbi_dma(dev, q, buf);
+	list_for_each_entry(buf, &q->active, vb.queue)
+		buf->count = q->count++;
+	mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+	return 0;
+}
+
+void cx8800_vbi_timeout(unsigned long data)
+{
+	struct cx8800_dev *dev = (struct cx8800_dev*)data;
+	struct cx88_core *core = dev->core;
+	struct cx88_dmaqueue *q = &dev->vbiq;
+	struct cx88_buffer *buf;
+	unsigned long flags;
+
+	cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH24]);
+
+	cx_clear(MO_VID_DMACNTRL, 0x88);
+	cx_clear(VID_CAPTURE_CONTROL, 0x18);
+
+	spin_lock_irqsave(&dev->slock,flags);
+	while (!list_empty(&q->active)) {
+		buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+		list_del(&buf->vb.queue);
+		buf->vb.state = VIDEOBUF_ERROR;
+		wake_up(&buf->vb.done);
+		printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->core->name,
+		       buf, buf->vb.i, (unsigned long)buf->risc.dma);
+	}
+	cx8800_restart_vbi_queue(dev,q);
+	spin_unlock_irqrestore(&dev->slock,flags);
+}
+
+/* ------------------------------------------------------------------ */
+
+static int
+vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+	*size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
+	if (0 == *count)
+		*count = vbibufs;
+	if (*count < 2)
+		*count = 2;
+	if (*count > 32)
+		*count = 32;
+	return 0;
+}
+
+static int
+vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+	    enum v4l2_field field)
+{
+	struct cx8800_fh   *fh  = q->priv_data;
+	struct cx8800_dev  *dev = fh->dev;
+	struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
+	unsigned int size;
+	int rc;
+
+	size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+		return -EINVAL;
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+		buf->vb.width  = VBI_LINE_LENGTH;
+		buf->vb.height = VBI_LINE_COUNT;
+		buf->vb.size   = size;
+		buf->vb.field  = V4L2_FIELD_SEQ_TB;
+
+		if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
+			goto fail;
+		cx88_risc_buffer(dev->pci, &buf->risc,
+				 dma->sglist,
+				 0, buf->vb.width * buf->vb.height,
+				 buf->vb.width, 0,
+				 buf->vb.height);
+	}
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+ fail:
+	cx88_free_buffer(q,buf);
+	return rc;
+}
+
+static void
+vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct cx88_buffer    *buf = container_of(vb,struct cx88_buffer,vb);
+	struct cx88_buffer    *prev;
+	struct cx8800_fh      *fh   = vq->priv_data;
+	struct cx8800_dev     *dev  = fh->dev;
+	struct cx88_dmaqueue  *q    = &dev->vbiq;
+
+	/* add jump to stopper */
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+
+	if (list_empty(&q->active)) {
+		list_add_tail(&buf->vb.queue,&q->active);
+		cx8800_start_vbi_dma(dev, q, buf);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		buf->count    = q->count++;
+		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+		dprintk(2,"[%p/%d] vbi_queue - first active\n",
+			buf, buf->vb.i);
+
+	} else {
+		prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue);
+		list_add_tail(&buf->vb.queue,&q->active);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		buf->count    = q->count++;
+		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+		dprintk(2,"[%p/%d] buffer_queue - append to active\n",
+			buf, buf->vb.i);
+	}
+}
+
+static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
+
+	cx88_free_buffer(q,buf);
+}
+
+const struct videobuf_queue_ops cx8800_vbi_qops = {
+	.buf_setup    = vbi_setup,
+	.buf_prepare  = vbi_prepare,
+	.buf_queue    = vbi_queue,
+	.buf_release  = vbi_release,
+};
+
+/* ------------------------------------------------------------------ */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
new file mode 100644
index 0000000..f6fcc7e
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -0,0 +1,2075 @@
+/*
+ *
+ * device driver for Conexant 2388x based TV cards
+ * video4linux video interface
+ *
+ * (c) 2003-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *	- Multituner support
+ *	- video_ioctl2 conversion
+ *	- PAL/M fixes
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <asm/div64.h>
+
+#include "cx88.h"
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/wm8775.h>
+
+MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CX88_VERSION);
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int video_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+static unsigned int vbi_nr[]   = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(video_nr, int, NULL, 0444);
+module_param_array(vbi_nr,   int, NULL, 0444);
+module_param_array(radio_nr, int, NULL, 0444);
+
+MODULE_PARM_DESC(video_nr,"video device numbers");
+MODULE_PARM_DESC(vbi_nr,"vbi device numbers");
+MODULE_PARM_DESC(radio_nr,"radio device numbers");
+
+static unsigned int video_debug;
+module_param(video_debug,int,0644);
+MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
+
+static unsigned int irq_debug;
+module_param(irq_debug,int,0644);
+MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]");
+
+static unsigned int vid_limit = 16;
+module_param(vid_limit,int,0644);
+MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+
+#define dprintk(level,fmt, arg...)	if (video_debug >= level) \
+	printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
+
+/* ------------------------------------------------------------------- */
+/* static data                                                         */
+
+static const struct cx8800_fmt formats[] = {
+	{
+		.name     = "8 bpp, gray",
+		.fourcc   = V4L2_PIX_FMT_GREY,
+		.cxformat = ColorFormatY8,
+		.depth    = 8,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "15 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_RGB555,
+		.cxformat = ColorFormatRGB15,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "15 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB555X,
+		.cxformat = ColorFormatRGB15 | ColorFormatBSWAP,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "16 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_RGB565,
+		.cxformat = ColorFormatRGB16,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "16 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB565X,
+		.cxformat = ColorFormatRGB16 | ColorFormatBSWAP,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "24 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_BGR24,
+		.cxformat = ColorFormatRGB24,
+		.depth    = 24,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "32 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_BGR32,
+		.cxformat = ColorFormatRGB32,
+		.depth    = 32,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "32 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB32,
+		.cxformat = ColorFormatRGB32 | ColorFormatBSWAP | ColorFormatWSWAP,
+		.depth    = 32,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "4:2:2, packed, YUYV",
+		.fourcc   = V4L2_PIX_FMT_YUYV,
+		.cxformat = ColorFormatYUY2,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},{
+		.name     = "4:2:2, packed, UYVY",
+		.fourcc   = V4L2_PIX_FMT_UYVY,
+		.cxformat = ColorFormatYUY2 | ColorFormatBSWAP,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},
+};
+
+static const struct cx8800_fmt* format_by_fourcc(unsigned int fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++)
+		if (formats[i].fourcc == fourcc)
+			return formats+i;
+	return NULL;
+}
+
+/* ------------------------------------------------------------------- */
+
+struct cx88_ctrl {
+	/* control information */
+	u32 id;
+	s32 minimum;
+	s32 maximum;
+	u32 step;
+	s32 default_value;
+
+	/* control register information */
+	u32 off;
+	u32 reg;
+	u32 sreg;
+	u32 mask;
+	u32 shift;
+};
+
+static const struct cx88_ctrl cx8800_vid_ctls[] = {
+	/* --- video --- */
+	{
+		.id            = V4L2_CID_BRIGHTNESS,
+		.minimum       = 0x00,
+		.maximum       = 0xff,
+		.step          = 1,
+		.default_value = 0x7f,
+		.off           = 128,
+		.reg           = MO_CONTR_BRIGHT,
+		.mask          = 0x00ff,
+		.shift         = 0,
+	},{
+		.id            = V4L2_CID_CONTRAST,
+		.minimum       = 0,
+		.maximum       = 0xff,
+		.step          = 1,
+		.default_value = 0x3f,
+		.off           = 0,
+		.reg           = MO_CONTR_BRIGHT,
+		.mask          = 0xff00,
+		.shift         = 8,
+	},{
+		.id            = V4L2_CID_HUE,
+		.minimum       = 0,
+		.maximum       = 0xff,
+		.step          = 1,
+		.default_value = 0x7f,
+		.off           = 128,
+		.reg           = MO_HUE,
+		.mask          = 0x00ff,
+		.shift         = 0,
+	},{
+		/* strictly, this only describes only U saturation.
+		 * V saturation is handled specially through code.
+		 */
+		.id            = V4L2_CID_SATURATION,
+		.minimum       = 0,
+		.maximum       = 0xff,
+		.step          = 1,
+		.default_value = 0x7f,
+		.off           = 0,
+		.reg           = MO_UV_SATURATION,
+		.mask          = 0x00ff,
+		.shift         = 0,
+	}, {
+		.id            = V4L2_CID_SHARPNESS,
+		.minimum       = 0,
+		.maximum       = 4,
+		.step          = 1,
+		.default_value = 0x0,
+		.off           = 0,
+		/* NOTE: the value is converted and written to both even
+		   and odd registers in the code */
+		.reg           = MO_FILTER_ODD,
+		.mask          = 7 << 7,
+		.shift         = 7,
+	}, {
+		.id            = V4L2_CID_CHROMA_AGC,
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 0x1,
+		.reg           = MO_INPUT_FORMAT,
+		.mask          = 1 << 10,
+		.shift         = 10,
+	}, {
+		.id            = V4L2_CID_COLOR_KILLER,
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 0x1,
+		.reg           = MO_INPUT_FORMAT,
+		.mask          = 1 << 9,
+		.shift         = 9,
+	}, {
+		.id            = V4L2_CID_BAND_STOP_FILTER,
+		.minimum       = 0,
+		.maximum       = 1,
+		.step          = 1,
+		.default_value = 0x0,
+		.off           = 0,
+		.reg           = MO_HTOTAL,
+		.mask          = 3 << 11,
+		.shift         = 11,
+	}
+};
+
+static const struct cx88_ctrl cx8800_aud_ctls[] = {
+	{
+		/* --- audio --- */
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 1,
+		.reg           = AUD_VOL_CTL,
+		.sreg          = SHADOW_AUD_VOL_CTL,
+		.mask          = (1 << 6),
+		.shift         = 6,
+	},{
+		.id            = V4L2_CID_AUDIO_VOLUME,
+		.minimum       = 0,
+		.maximum       = 0x3f,
+		.step          = 1,
+		.default_value = 0x3f,
+		.reg           = AUD_VOL_CTL,
+		.sreg          = SHADOW_AUD_VOL_CTL,
+		.mask          = 0x3f,
+		.shift         = 0,
+	},{
+		.id            = V4L2_CID_AUDIO_BALANCE,
+		.minimum       = 0,
+		.maximum       = 0x7f,
+		.step          = 1,
+		.default_value = 0x40,
+		.reg           = AUD_BAL_CTL,
+		.sreg          = SHADOW_AUD_BAL_CTL,
+		.mask          = 0x7f,
+		.shift         = 0,
+	}
+};
+
+enum {
+	CX8800_VID_CTLS = ARRAY_SIZE(cx8800_vid_ctls),
+	CX8800_AUD_CTLS = ARRAY_SIZE(cx8800_aud_ctls),
+};
+
+/* ------------------------------------------------------------------- */
+/* resource management                                                 */
+
+static int res_get(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bit)
+{
+	struct cx88_core *core = dev->core;
+	if (fh->resources & bit)
+		/* have it already allocated */
+		return 1;
+
+	/* is it free? */
+	mutex_lock(&core->lock);
+	if (dev->resources & bit) {
+		/* no, someone else uses it */
+		mutex_unlock(&core->lock);
+		return 0;
+	}
+	/* it's free, grab it */
+	fh->resources  |= bit;
+	dev->resources |= bit;
+	dprintk(1,"res: get %d\n",bit);
+	mutex_unlock(&core->lock);
+	return 1;
+}
+
+static
+int res_check(struct cx8800_fh *fh, unsigned int bit)
+{
+	return (fh->resources & bit);
+}
+
+static
+int res_locked(struct cx8800_dev *dev, unsigned int bit)
+{
+	return (dev->resources & bit);
+}
+
+static
+void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits)
+{
+	struct cx88_core *core = dev->core;
+	BUG_ON((fh->resources & bits) != bits);
+
+	mutex_lock(&core->lock);
+	fh->resources  &= ~bits;
+	dev->resources &= ~bits;
+	dprintk(1,"res: put %d\n",bits);
+	mutex_unlock(&core->lock);
+}
+
+/* ------------------------------------------------------------------ */
+
+int cx88_video_mux(struct cx88_core *core, unsigned int input)
+{
+	/* struct cx88_core *core = dev->core; */
+
+	dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n",
+		input, INPUT(input).vmux,
+		INPUT(input).gpio0,INPUT(input).gpio1,
+		INPUT(input).gpio2,INPUT(input).gpio3);
+	core->input = input;
+	cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input).vmux << 14);
+	cx_write(MO_GP3_IO, INPUT(input).gpio3);
+	cx_write(MO_GP0_IO, INPUT(input).gpio0);
+	cx_write(MO_GP1_IO, INPUT(input).gpio1);
+	cx_write(MO_GP2_IO, INPUT(input).gpio2);
+
+	switch (INPUT(input).type) {
+	case CX88_VMUX_SVIDEO:
+		cx_set(MO_AFECFG_IO,    0x00000001);
+		cx_set(MO_INPUT_FORMAT, 0x00010010);
+		cx_set(MO_FILTER_EVEN,  0x00002020);
+		cx_set(MO_FILTER_ODD,   0x00002020);
+		break;
+	default:
+		cx_clear(MO_AFECFG_IO,    0x00000001);
+		cx_clear(MO_INPUT_FORMAT, 0x00010010);
+		cx_clear(MO_FILTER_EVEN,  0x00002020);
+		cx_clear(MO_FILTER_ODD,   0x00002020);
+		break;
+	}
+
+	/* if there are audioroutes defined, we have an external
+	   ADC to deal with audio */
+	if (INPUT(input).audioroute) {
+		/* The wm8775 module has the "2" route hardwired into
+		   the initialization. Some boards may use different
+		   routes for different inputs. HVR-1300 surely does */
+		if (core->board.audio_chip &&
+		    core->board.audio_chip == V4L2_IDENT_WM8775) {
+			call_all(core, audio, s_routing,
+				 INPUT(input).audioroute, 0, 0);
+		}
+		/* cx2388's C-ADC is connected to the tuner only.
+		   When used with S-Video, that ADC is busy dealing with
+		   chroma, so an external must be used for baseband audio */
+		if (INPUT(input).type != CX88_VMUX_TELEVISION &&
+		    INPUT(input).type != CX88_VMUX_CABLE) {
+			/* "I2S ADC mode" */
+			core->tvaudio = WW_I2SADC;
+			cx88_set_tvaudio(core);
+		} else {
+			/* Normal mode */
+			cx_write(AUD_I2SCNTL, 0x0);
+			cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(cx88_video_mux);
+
+/* ------------------------------------------------------------------ */
+
+static int start_video_dma(struct cx8800_dev    *dev,
+			   struct cx88_dmaqueue *q,
+			   struct cx88_buffer   *buf)
+{
+	struct cx88_core *core = dev->core;
+
+	/* setup fifo + format */
+	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21],
+				buf->bpl, buf->risc.dma);
+	cx88_set_scale(core, buf->vb.width, buf->vb.height, buf->vb.field);
+	cx_write(MO_COLOR_CTRL, buf->fmt->cxformat | ColorFormatGamma);
+
+	/* reset counter */
+	cx_write(MO_VIDY_GPCNTRL,GP_COUNT_CONTROL_RESET);
+	q->count = 1;
+
+	/* enable irqs */
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT);
+
+	/* Enables corresponding bits at PCI_INT_STAT:
+		bits 0 to 4: video, audio, transport stream, VIP, Host
+		bit 7: timer
+		bits 8 and 9: DMA complete for: SRC, DST
+		bits 10 and 11: BERR signal asserted for RISC: RD, WR
+		bits 12 to 15: BERR signal asserted for: BRDG, SRC, DST, IPB
+	 */
+	cx_set(MO_VID_INTMSK, 0x0f0011);
+
+	/* enable capture */
+	cx_set(VID_CAPTURE_CONTROL,0x06);
+
+	/* start dma */
+	cx_set(MO_DEV_CNTRL2, (1<<5));
+	cx_set(MO_VID_DMACNTRL, 0x11); /* Planar Y and packed FIFO and RISC enable */
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int stop_video_dma(struct cx8800_dev    *dev)
+{
+	struct cx88_core *core = dev->core;
+
+	/* stop dma */
+	cx_clear(MO_VID_DMACNTRL, 0x11);
+
+	/* disable capture */
+	cx_clear(VID_CAPTURE_CONTROL,0x06);
+
+	/* disable irqs */
+	cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT);
+	cx_clear(MO_VID_INTMSK, 0x0f0011);
+	return 0;
+}
+#endif
+
+static int restart_video_queue(struct cx8800_dev    *dev,
+			       struct cx88_dmaqueue *q)
+{
+	struct cx88_core *core = dev->core;
+	struct cx88_buffer *buf, *prev;
+
+	if (!list_empty(&q->active)) {
+		buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+		dprintk(2,"restart_queue [%p/%d]: restart dma\n",
+			buf, buf->vb.i);
+		start_video_dma(dev, q, buf);
+		list_for_each_entry(buf, &q->active, vb.queue)
+			buf->count = q->count++;
+		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+		return 0;
+	}
+
+	prev = NULL;
+	for (;;) {
+		if (list_empty(&q->queued))
+			return 0;
+		buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
+		if (NULL == prev) {
+			list_move_tail(&buf->vb.queue, &q->active);
+			start_video_dma(dev, q, buf);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			buf->count    = q->count++;
+			mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+			dprintk(2,"[%p/%d] restart_queue - first active\n",
+				buf,buf->vb.i);
+
+		} else if (prev->vb.width  == buf->vb.width  &&
+			   prev->vb.height == buf->vb.height &&
+			   prev->fmt       == buf->fmt) {
+			list_move_tail(&buf->vb.queue, &q->active);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			buf->count    = q->count++;
+			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+			dprintk(2,"[%p/%d] restart_queue - move to active\n",
+				buf,buf->vb.i);
+		} else {
+			return 0;
+		}
+		prev = buf;
+	}
+}
+
+/* ------------------------------------------------------------------ */
+
+static int
+buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+	struct cx8800_fh *fh = q->priv_data;
+	struct cx8800_dev  *dev = fh->dev;
+
+	*size = dev->fmt->depth * dev->width * dev->height >> 3;
+	if (0 == *count)
+		*count = 32;
+	if (*size * *count > vid_limit * 1024 * 1024)
+		*count = (vid_limit * 1024 * 1024) / *size;
+	return 0;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+	       enum v4l2_field field)
+{
+	struct cx8800_fh   *fh  = q->priv_data;
+	struct cx8800_dev  *dev = fh->dev;
+	struct cx88_core *core = dev->core;
+	struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+	int rc, init_buffer = 0;
+
+	BUG_ON(NULL == dev->fmt);
+	if (dev->width  < 48 || dev->width  > norm_maxw(core->tvnorm) ||
+	    dev->height < 32 || dev->height > norm_maxh(core->tvnorm))
+		return -EINVAL;
+	buf->vb.size = (dev->width * dev->height * dev->fmt->depth) >> 3;
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+		return -EINVAL;
+
+	if (buf->fmt       != dev->fmt    ||
+	    buf->vb.width  != dev->width  ||
+	    buf->vb.height != dev->height ||
+	    buf->vb.field  != field) {
+		buf->fmt       = dev->fmt;
+		buf->vb.width  = dev->width;
+		buf->vb.height = dev->height;
+		buf->vb.field  = field;
+		init_buffer = 1;
+	}
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		init_buffer = 1;
+		if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
+			goto fail;
+	}
+
+	if (init_buffer) {
+		buf->bpl = buf->vb.width * buf->fmt->depth >> 3;
+		switch (buf->vb.field) {
+		case V4L2_FIELD_TOP:
+			cx88_risc_buffer(dev->pci, &buf->risc,
+					 dma->sglist, 0, UNSET,
+					 buf->bpl, 0, buf->vb.height);
+			break;
+		case V4L2_FIELD_BOTTOM:
+			cx88_risc_buffer(dev->pci, &buf->risc,
+					 dma->sglist, UNSET, 0,
+					 buf->bpl, 0, buf->vb.height);
+			break;
+		case V4L2_FIELD_INTERLACED:
+			cx88_risc_buffer(dev->pci, &buf->risc,
+					 dma->sglist, 0, buf->bpl,
+					 buf->bpl, buf->bpl,
+					 buf->vb.height >> 1);
+			break;
+		case V4L2_FIELD_SEQ_TB:
+			cx88_risc_buffer(dev->pci, &buf->risc,
+					 dma->sglist,
+					 0, buf->bpl * (buf->vb.height >> 1),
+					 buf->bpl, 0,
+					 buf->vb.height >> 1);
+			break;
+		case V4L2_FIELD_SEQ_BT:
+			cx88_risc_buffer(dev->pci, &buf->risc,
+					 dma->sglist,
+					 buf->bpl * (buf->vb.height >> 1), 0,
+					 buf->bpl, 0,
+					 buf->vb.height >> 1);
+			break;
+		default:
+			BUG();
+		}
+	}
+	dprintk(2,"[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
+		buf, buf->vb.i,
+		dev->width, dev->height, dev->fmt->depth, dev->fmt->name,
+		(unsigned long)buf->risc.dma);
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+ fail:
+	cx88_free_buffer(q,buf);
+	return rc;
+}
+
+static void
+buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct cx88_buffer    *buf = container_of(vb,struct cx88_buffer,vb);
+	struct cx88_buffer    *prev;
+	struct cx8800_fh      *fh   = vq->priv_data;
+	struct cx8800_dev     *dev  = fh->dev;
+	struct cx88_core      *core = dev->core;
+	struct cx88_dmaqueue  *q    = &dev->vidq;
+
+	/* add jump to stopper */
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+
+	if (!list_empty(&q->queued)) {
+		list_add_tail(&buf->vb.queue,&q->queued);
+		buf->vb.state = VIDEOBUF_QUEUED;
+		dprintk(2,"[%p/%d] buffer_queue - append to queued\n",
+			buf, buf->vb.i);
+
+	} else if (list_empty(&q->active)) {
+		list_add_tail(&buf->vb.queue,&q->active);
+		start_video_dma(dev, q, buf);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		buf->count    = q->count++;
+		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+		dprintk(2,"[%p/%d] buffer_queue - first active\n",
+			buf, buf->vb.i);
+
+	} else {
+		prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue);
+		if (prev->vb.width  == buf->vb.width  &&
+		    prev->vb.height == buf->vb.height &&
+		    prev->fmt       == buf->fmt) {
+			list_add_tail(&buf->vb.queue,&q->active);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			buf->count    = q->count++;
+			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+			dprintk(2,"[%p/%d] buffer_queue - append to active\n",
+				buf, buf->vb.i);
+
+		} else {
+			list_add_tail(&buf->vb.queue,&q->queued);
+			buf->vb.state = VIDEOBUF_QUEUED;
+			dprintk(2,"[%p/%d] buffer_queue - first queued\n",
+				buf, buf->vb.i);
+		}
+	}
+}
+
+static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
+
+	cx88_free_buffer(q,buf);
+}
+
+static const struct videobuf_queue_ops cx8800_video_qops = {
+	.buf_setup    = buffer_setup,
+	.buf_prepare  = buffer_prepare,
+	.buf_queue    = buffer_queue,
+	.buf_release  = buffer_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+
+/* ------------------------------------------------------------------ */
+
+static struct videobuf_queue *get_queue(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct cx8800_fh *fh = file->private_data;
+
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_GRABBER:
+		return &fh->vidq;
+	case VFL_TYPE_VBI:
+		return &fh->vbiq;
+	default:
+		BUG();
+		return NULL;
+	}
+}
+
+static int get_resource(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_GRABBER:
+		return RESOURCE_VIDEO;
+	case VFL_TYPE_VBI:
+		return RESOURCE_VBI;
+	default:
+		BUG();
+		return 0;
+	}
+}
+
+static int video_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct cx8800_dev *dev = video_drvdata(file);
+	struct cx88_core *core = dev->core;
+	struct cx8800_fh *fh;
+	enum v4l2_buf_type type = 0;
+	int radio = 0;
+
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_GRABBER:
+		type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		break;
+	case VFL_TYPE_VBI:
+		type = V4L2_BUF_TYPE_VBI_CAPTURE;
+		break;
+	case VFL_TYPE_RADIO:
+		radio = 1;
+		break;
+	}
+
+	dprintk(1, "open dev=%s radio=%d type=%s\n",
+		video_device_node_name(vdev), radio, v4l2_type_names[type]);
+
+	/* allocate + initialize per filehandle data */
+	fh = kzalloc(sizeof(*fh),GFP_KERNEL);
+	if (unlikely(!fh))
+		return -ENOMEM;
+
+	v4l2_fh_init(&fh->fh, vdev);
+	file->private_data = fh;
+	fh->dev      = dev;
+
+	mutex_lock(&core->lock);
+
+	videobuf_queue_sg_init(&fh->vidq, &cx8800_video_qops,
+			    &dev->pci->dev, &dev->slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			    V4L2_FIELD_INTERLACED,
+			    sizeof(struct cx88_buffer),
+			    fh, NULL);
+	videobuf_queue_sg_init(&fh->vbiq, &cx8800_vbi_qops,
+			    &dev->pci->dev, &dev->slock,
+			    V4L2_BUF_TYPE_VBI_CAPTURE,
+			    V4L2_FIELD_SEQ_TB,
+			    sizeof(struct cx88_buffer),
+			    fh, NULL);
+
+	if (vdev->vfl_type == VFL_TYPE_RADIO) {
+		dprintk(1,"video_open: setting radio device\n");
+		cx_write(MO_GP3_IO, core->board.radio.gpio3);
+		cx_write(MO_GP0_IO, core->board.radio.gpio0);
+		cx_write(MO_GP1_IO, core->board.radio.gpio1);
+		cx_write(MO_GP2_IO, core->board.radio.gpio2);
+		if (core->board.radio.audioroute) {
+			if(core->board.audio_chip &&
+				core->board.audio_chip == V4L2_IDENT_WM8775) {
+				call_all(core, audio, s_routing,
+					core->board.radio.audioroute, 0, 0);
+			}
+			/* "I2S ADC mode" */
+			core->tvaudio = WW_I2SADC;
+			cx88_set_tvaudio(core);
+		} else {
+			/* FM Mode */
+			core->tvaudio = WW_FM;
+			cx88_set_tvaudio(core);
+			cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1);
+		}
+		call_all(core, tuner, s_radio);
+	}
+
+	core->users++;
+	mutex_unlock(&core->lock);
+	v4l2_fh_add(&fh->fh);
+
+	return 0;
+}
+
+static ssize_t
+video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct cx8800_fh *fh = file->private_data;
+
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_GRABBER:
+		if (res_locked(fh->dev,RESOURCE_VIDEO))
+			return -EBUSY;
+		return videobuf_read_one(&fh->vidq, data, count, ppos,
+					 file->f_flags & O_NONBLOCK);
+	case VFL_TYPE_VBI:
+		if (!res_get(fh->dev,fh,RESOURCE_VBI))
+			return -EBUSY;
+		return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1,
+					    file->f_flags & O_NONBLOCK);
+	default:
+		BUG();
+		return 0;
+	}
+}
+
+static unsigned int
+video_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct cx8800_fh *fh = file->private_data;
+	struct cx88_buffer *buf;
+	unsigned int rc = v4l2_ctrl_poll(file, wait);
+
+	if (vdev->vfl_type == VFL_TYPE_VBI) {
+		if (!res_get(fh->dev,fh,RESOURCE_VBI))
+			return rc | POLLERR;
+		return rc | videobuf_poll_stream(file, &fh->vbiq, wait);
+	}
+	mutex_lock(&fh->vidq.vb_lock);
+	if (res_check(fh,RESOURCE_VIDEO)) {
+		/* streaming capture */
+		if (list_empty(&fh->vidq.stream))
+			goto done;
+		buf = list_entry(fh->vidq.stream.next,struct cx88_buffer,vb.stream);
+	} else {
+		/* read() capture */
+		buf = (struct cx88_buffer*)fh->vidq.read_buf;
+		if (NULL == buf)
+			goto done;
+	}
+	poll_wait(file, &buf->vb.done, wait);
+	if (buf->vb.state == VIDEOBUF_DONE ||
+	    buf->vb.state == VIDEOBUF_ERROR)
+		rc |= POLLIN|POLLRDNORM;
+done:
+	mutex_unlock(&fh->vidq.vb_lock);
+	return rc;
+}
+
+static int video_release(struct file *file)
+{
+	struct cx8800_fh  *fh  = file->private_data;
+	struct cx8800_dev *dev = fh->dev;
+
+	/* turn off overlay */
+	if (res_check(fh, RESOURCE_OVERLAY)) {
+		/* FIXME */
+		res_free(dev,fh,RESOURCE_OVERLAY);
+	}
+
+	/* stop video capture */
+	if (res_check(fh, RESOURCE_VIDEO)) {
+		videobuf_queue_cancel(&fh->vidq);
+		res_free(dev,fh,RESOURCE_VIDEO);
+	}
+	if (fh->vidq.read_buf) {
+		buffer_release(&fh->vidq,fh->vidq.read_buf);
+		kfree(fh->vidq.read_buf);
+	}
+
+	/* stop vbi capture */
+	if (res_check(fh, RESOURCE_VBI)) {
+		videobuf_stop(&fh->vbiq);
+		res_free(dev,fh,RESOURCE_VBI);
+	}
+
+	videobuf_mmap_free(&fh->vidq);
+	videobuf_mmap_free(&fh->vbiq);
+
+	mutex_lock(&dev->core->lock);
+	v4l2_fh_del(&fh->fh);
+	v4l2_fh_exit(&fh->fh);
+	file->private_data = NULL;
+	kfree(fh);
+
+	dev->core->users--;
+	if (!dev->core->users)
+		call_all(dev->core, core, s_power, 0);
+	mutex_unlock(&dev->core->lock);
+
+	return 0;
+}
+
+static int
+video_mmap(struct file *file, struct vm_area_struct * vma)
+{
+	return videobuf_mmap_mapper(get_queue(file), vma);
+}
+
+/* ------------------------------------------------------------------ */
+/* VIDEO CTRL IOCTLS                                                  */
+
+static int cx8800_s_vid_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct cx88_core *core =
+		container_of(ctrl->handler, struct cx88_core, video_hdl);
+	const struct cx88_ctrl *cc = ctrl->priv;
+	u32 value, mask;
+
+	mask = cc->mask;
+	switch (ctrl->id) {
+	case V4L2_CID_SATURATION:
+		/* special v_sat handling */
+
+		value = ((ctrl->val - cc->off) << cc->shift) & cc->mask;
+
+		if (core->tvnorm & V4L2_STD_SECAM) {
+			/* For SECAM, both U and V sat should be equal */
+			value = value << 8 | value;
+		} else {
+			/* Keeps U Saturation proportional to V Sat */
+			value = (value * 0x5a) / 0x7f << 8 | value;
+		}
+		mask = 0xffff;
+		break;
+	case V4L2_CID_SHARPNESS:
+		/* 0b000, 0b100, 0b101, 0b110, or 0b111 */
+		value = (ctrl->val < 1 ? 0 : ((ctrl->val + 3) << 7));
+		/* needs to be set for both fields */
+		cx_andor(MO_FILTER_EVEN, mask, value);
+		break;
+	case V4L2_CID_CHROMA_AGC:
+		value = ((ctrl->val - cc->off) << cc->shift) & cc->mask;
+		break;
+	default:
+		value = ((ctrl->val - cc->off) << cc->shift) & cc->mask;
+		break;
+	}
+	dprintk(1, "set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
+				ctrl->id, ctrl->name, ctrl->val, cc->reg, value,
+				mask, cc->sreg ? " [shadowed]" : "");
+	if (cc->sreg)
+		cx_sandor(cc->sreg, cc->reg, mask, value);
+	else
+		cx_andor(cc->reg, mask, value);
+	return 0;
+}
+
+static int cx8800_s_aud_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct cx88_core *core =
+		container_of(ctrl->handler, struct cx88_core, audio_hdl);
+	const struct cx88_ctrl *cc = ctrl->priv;
+	u32 value,mask;
+
+	/* Pass changes onto any WM8775 */
+	if (core->board.audio_chip == V4L2_IDENT_WM8775) {
+		switch (ctrl->id) {
+		case V4L2_CID_AUDIO_MUTE:
+			wm8775_s_ctrl(core, ctrl->id, ctrl->val);
+			break;
+		case V4L2_CID_AUDIO_VOLUME:
+			wm8775_s_ctrl(core, ctrl->id, (ctrl->val) ?
+						(0x90 + ctrl->val) << 8 : 0);
+			break;
+		case V4L2_CID_AUDIO_BALANCE:
+			wm8775_s_ctrl(core, ctrl->id, ctrl->val << 9);
+			break;
+		default:
+			break;
+		}
+	}
+
+	mask = cc->mask;
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_BALANCE:
+		value = (ctrl->val < 0x40) ? (0x7f - ctrl->val) : (ctrl->val - 0x40);
+		break;
+	case V4L2_CID_AUDIO_VOLUME:
+		value = 0x3f - (ctrl->val & 0x3f);
+		break;
+	default:
+		value = ((ctrl->val - cc->off) << cc->shift) & cc->mask;
+		break;
+	}
+	dprintk(1,"set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
+				ctrl->id, ctrl->name, ctrl->val, cc->reg, value,
+				mask, cc->sreg ? " [shadowed]" : "");
+	if (cc->sreg)
+		cx_sandor(cc->sreg, cc->reg, mask, value);
+	else
+		cx_andor(cc->reg, mask, value);
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* VIDEO IOCTLS                                                       */
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct cx8800_fh  *fh   = priv;
+	struct cx8800_dev *dev = fh->dev;
+
+	f->fmt.pix.width        = dev->width;
+	f->fmt.pix.height       = dev->height;
+	f->fmt.pix.field        = fh->vidq.field;
+	f->fmt.pix.pixelformat  = dev->fmt->fourcc;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * dev->fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
+	const struct cx8800_fmt *fmt;
+	enum v4l2_field   field;
+	unsigned int      maxw, maxh;
+
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	if (NULL == fmt)
+		return -EINVAL;
+
+	field = f->fmt.pix.field;
+	maxw  = norm_maxw(core->tvnorm);
+	maxh  = norm_maxh(core->tvnorm);
+
+	if (V4L2_FIELD_ANY == field) {
+		field = (f->fmt.pix.height > maxh/2)
+			? V4L2_FIELD_INTERLACED
+			: V4L2_FIELD_BOTTOM;
+	}
+
+	switch (field) {
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+		maxh = maxh / 2;
+		break;
+	case V4L2_FIELD_INTERLACED:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	f->fmt.pix.field = field;
+	v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
+			      &f->fmt.pix.height, 32, maxh, 0, 0);
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct cx8800_fh  *fh   = priv;
+	struct cx8800_dev *dev = fh->dev;
+	int err = vidioc_try_fmt_vid_cap (file,priv,f);
+
+	if (0 != err)
+		return err;
+	dev->fmt        = format_by_fourcc(f->fmt.pix.pixelformat);
+	dev->width      = f->fmt.pix.width;
+	dev->height     = f->fmt.pix.height;
+	fh->vidq.field = f->fmt.pix.field;
+	return 0;
+}
+
+void cx88_querycap(struct file *file, struct cx88_core *core,
+		struct v4l2_capability *cap)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	strlcpy(cap->card, core->board.name, sizeof(cap->card));
+	cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+	if (UNSET != core->board.tuner_type)
+		cap->device_caps |= V4L2_CAP_TUNER;
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_RADIO:
+		cap->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
+		break;
+	case VFL_TYPE_GRABBER:
+		cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
+		break;
+	case VFL_TYPE_VBI:
+		cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
+		break;
+	}
+	cap->capabilities = cap->device_caps | V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS;
+	if (core->board.radio.type == CX88_RADIO)
+		cap->capabilities |= V4L2_CAP_RADIO;
+}
+EXPORT_SYMBOL(cx88_querycap);
+
+static int vidioc_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *cap)
+{
+	struct cx8800_dev *dev  = ((struct cx8800_fh *)priv)->dev;
+	struct cx88_core  *core = dev->core;
+
+	strcpy(cap->driver, "cx8800");
+	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+	cx88_querycap(file, core, cap);
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap (struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	if (unlikely(f->index >= ARRAY_SIZE(formats)))
+		return -EINVAL;
+
+	strlcpy(f->description,formats[f->index].name,sizeof(f->description));
+	f->pixelformat = formats[f->index].fourcc;
+
+	return 0;
+}
+
+static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
+{
+	return videobuf_reqbufs(get_queue(file), p);
+}
+
+static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	return videobuf_querybuf(get_queue(file), p);
+}
+
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	return videobuf_qbuf(get_queue(file), p);
+}
+
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	return videobuf_dqbuf(get_queue(file), p,
+				file->f_flags & O_NONBLOCK);
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct cx8800_fh  *fh   = priv;
+	struct cx8800_dev *dev  = fh->dev;
+
+	if ((vdev->vfl_type == VFL_TYPE_GRABBER && i != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
+	    (vdev->vfl_type == VFL_TYPE_VBI && i != V4L2_BUF_TYPE_VBI_CAPTURE))
+		return -EINVAL;
+
+	if (unlikely(!res_get(dev, fh, get_resource(file))))
+		return -EBUSY;
+	return videobuf_streamon(get_queue(file));
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct cx8800_fh  *fh   = priv;
+	struct cx8800_dev *dev  = fh->dev;
+	int               err, res;
+
+	if ((vdev->vfl_type == VFL_TYPE_GRABBER && i != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
+	    (vdev->vfl_type == VFL_TYPE_VBI && i != V4L2_BUF_TYPE_VBI_CAPTURE))
+		return -EINVAL;
+
+	res = get_resource(file);
+	err = videobuf_streamoff(get_queue(file));
+	if (err < 0)
+		return err;
+	res_free(dev,fh,res);
+	return 0;
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm)
+{
+	struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+
+	*tvnorm = core->tvnorm;
+	return 0;
+}
+
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms)
+{
+	struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
+
+	mutex_lock(&core->lock);
+	cx88_set_tvnorm(core,*tvnorms);
+	mutex_unlock(&core->lock);
+
+	return 0;
+}
+
+/* only one input in this sample driver */
+int cx88_enum_input (struct cx88_core  *core,struct v4l2_input *i)
+{
+	static const char * const iname[] = {
+		[ CX88_VMUX_COMPOSITE1 ] = "Composite1",
+		[ CX88_VMUX_COMPOSITE2 ] = "Composite2",
+		[ CX88_VMUX_COMPOSITE3 ] = "Composite3",
+		[ CX88_VMUX_COMPOSITE4 ] = "Composite4",
+		[ CX88_VMUX_SVIDEO     ] = "S-Video",
+		[ CX88_VMUX_TELEVISION ] = "Television",
+		[ CX88_VMUX_CABLE      ] = "Cable TV",
+		[ CX88_VMUX_DVB        ] = "DVB",
+		[ CX88_VMUX_DEBUG      ] = "for debug only",
+	};
+	unsigned int n = i->index;
+
+	if (n >= 4)
+		return -EINVAL;
+	if (0 == INPUT(n).type)
+		return -EINVAL;
+	i->type  = V4L2_INPUT_TYPE_CAMERA;
+	strcpy(i->name,iname[INPUT(n).type]);
+	if ((CX88_VMUX_TELEVISION == INPUT(n).type) ||
+	    (CX88_VMUX_CABLE      == INPUT(n).type)) {
+		i->type = V4L2_INPUT_TYPE_TUNER;
+	}
+	i->std = CX88_NORMS;
+	return 0;
+}
+EXPORT_SYMBOL(cx88_enum_input);
+
+static int vidioc_enum_input (struct file *file, void *priv,
+				struct v4l2_input *i)
+{
+	struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
+	return cx88_enum_input (core,i);
+}
+
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+	struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
+
+	*i = core->input;
+	return 0;
+}
+
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+	struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
+
+	if (i >= 4)
+		return -EINVAL;
+	if (0 == INPUT(i).type)
+		return -EINVAL;
+
+	mutex_lock(&core->lock);
+	cx88_newstation(core);
+	cx88_video_mux(core,i);
+	mutex_unlock(&core->lock);
+	return 0;
+}
+
+static int vidioc_g_tuner (struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
+	u32 reg;
+
+	if (unlikely(UNSET == core->board.tuner_type))
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+
+	strcpy(t->name, "Television");
+	t->capability = V4L2_TUNER_CAP_NORM;
+	t->rangehigh  = 0xffffffffUL;
+	call_all(core, tuner, g_tuner, t);
+
+	cx88_get_stereo(core ,t);
+	reg = cx_read(MO_DEVICE_STATUS);
+	t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
+	return 0;
+}
+
+static int vidioc_s_tuner (struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
+
+	if (UNSET == core->board.tuner_type)
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+
+	cx88_set_stereo(core, t->audmode, 1);
+	return 0;
+}
+
+static int vidioc_g_frequency (struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct cx8800_fh  *fh   = priv;
+	struct cx88_core  *core = fh->dev->core;
+
+	if (unlikely(UNSET == core->board.tuner_type))
+		return -EINVAL;
+	if (f->tuner)
+		return -EINVAL;
+
+	f->frequency = core->freq;
+
+	call_all(core, tuner, g_frequency, f);
+
+	return 0;
+}
+
+int cx88_set_freq (struct cx88_core  *core,
+				struct v4l2_frequency *f)
+{
+	if (unlikely(UNSET == core->board.tuner_type))
+		return -EINVAL;
+	if (unlikely(f->tuner != 0))
+		return -EINVAL;
+
+	mutex_lock(&core->lock);
+	cx88_newstation(core);
+	call_all(core, tuner, s_frequency, f);
+	call_all(core, tuner, g_frequency, f);
+	core->freq = f->frequency;
+
+	/* When changing channels it is required to reset TVAUDIO */
+	msleep (10);
+	cx88_set_tvaudio(core);
+
+	mutex_unlock(&core->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cx88_set_freq);
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct cx8800_fh  *fh   = priv;
+	struct cx88_core  *core = fh->dev->core;
+
+	return cx88_set_freq(core, f);
+}
+
+static int vidioc_g_chip_ident(struct file *file, void *priv,
+				struct v4l2_dbg_chip_ident *chip)
+{
+	if (!v4l2_chip_match_host(&chip->match))
+		return -EINVAL;
+	chip->revision = 0;
+	chip->ident = V4L2_IDENT_UNKNOWN;
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register (struct file *file, void *fh,
+				struct v4l2_dbg_register *reg)
+{
+	struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
+
+	if (!v4l2_chip_match_host(&reg->match))
+		return -EINVAL;
+	/* cx2388x has a 24-bit register space */
+	reg->val = cx_read(reg->reg & 0xffffff);
+	reg->size = 4;
+	return 0;
+}
+
+static int vidioc_s_register (struct file *file, void *fh,
+				struct v4l2_dbg_register *reg)
+{
+	struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
+
+	if (!v4l2_chip_match_host(&reg->match))
+		return -EINVAL;
+	cx_write(reg->reg & 0xffffff, reg->val);
+	return 0;
+}
+#endif
+
+/* ----------------------------------------------------------- */
+/* RADIO ESPECIFIC IOCTLS                                      */
+/* ----------------------------------------------------------- */
+
+static int radio_g_tuner (struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
+
+	if (unlikely(t->index > 0))
+		return -EINVAL;
+
+	strcpy(t->name, "Radio");
+
+	call_all(core, tuner, g_tuner, t);
+	return 0;
+}
+
+/* FIXME: Should add a standard for radio */
+
+static int radio_s_tuner (struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
+
+	if (0 != t->index)
+		return -EINVAL;
+	if (t->audmode > V4L2_TUNER_MODE_STEREO)
+		t->audmode = V4L2_TUNER_MODE_STEREO;
+
+	call_all(core, tuner, s_tuner, t);
+
+	return 0;
+}
+
+/* ----------------------------------------------------------- */
+
+static void cx8800_vid_timeout(unsigned long data)
+{
+	struct cx8800_dev *dev = (struct cx8800_dev*)data;
+	struct cx88_core *core = dev->core;
+	struct cx88_dmaqueue *q = &dev->vidq;
+	struct cx88_buffer *buf;
+	unsigned long flags;
+
+	cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]);
+
+	cx_clear(MO_VID_DMACNTRL, 0x11);
+	cx_clear(VID_CAPTURE_CONTROL, 0x06);
+
+	spin_lock_irqsave(&dev->slock,flags);
+	while (!list_empty(&q->active)) {
+		buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+		list_del(&buf->vb.queue);
+		buf->vb.state = VIDEOBUF_ERROR;
+		wake_up(&buf->vb.done);
+		printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", core->name,
+		       buf, buf->vb.i, (unsigned long)buf->risc.dma);
+	}
+	restart_video_queue(dev,q);
+	spin_unlock_irqrestore(&dev->slock,flags);
+}
+
+static const char *cx88_vid_irqs[32] = {
+	"y_risci1", "u_risci1", "v_risci1", "vbi_risc1",
+	"y_risci2", "u_risci2", "v_risci2", "vbi_risc2",
+	"y_oflow",  "u_oflow",  "v_oflow",  "vbi_oflow",
+	"y_sync",   "u_sync",   "v_sync",   "vbi_sync",
+	"opc_err",  "par_err",  "rip_err",  "pci_abort",
+};
+
+static void cx8800_vid_irq(struct cx8800_dev *dev)
+{
+	struct cx88_core *core = dev->core;
+	u32 status, mask, count;
+
+	status = cx_read(MO_VID_INTSTAT);
+	mask   = cx_read(MO_VID_INTMSK);
+	if (0 == (status & mask))
+		return;
+	cx_write(MO_VID_INTSTAT, status);
+	if (irq_debug  ||  (status & mask & ~0xff))
+		cx88_print_irqbits(core->name, "irq vid",
+				   cx88_vid_irqs, ARRAY_SIZE(cx88_vid_irqs),
+				   status, mask);
+
+	/* risc op code error */
+	if (status & (1 << 16)) {
+		printk(KERN_WARNING "%s/0: video risc op code error\n",core->name);
+		cx_clear(MO_VID_DMACNTRL, 0x11);
+		cx_clear(VID_CAPTURE_CONTROL, 0x06);
+		cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]);
+	}
+
+	/* risc1 y */
+	if (status & 0x01) {
+		spin_lock(&dev->slock);
+		count = cx_read(MO_VIDY_GPCNT);
+		cx88_wakeup(core, &dev->vidq, count);
+		spin_unlock(&dev->slock);
+	}
+
+	/* risc1 vbi */
+	if (status & 0x08) {
+		spin_lock(&dev->slock);
+		count = cx_read(MO_VBI_GPCNT);
+		cx88_wakeup(core, &dev->vbiq, count);
+		spin_unlock(&dev->slock);
+	}
+
+	/* risc2 y */
+	if (status & 0x10) {
+		dprintk(2,"stopper video\n");
+		spin_lock(&dev->slock);
+		restart_video_queue(dev,&dev->vidq);
+		spin_unlock(&dev->slock);
+	}
+
+	/* risc2 vbi */
+	if (status & 0x80) {
+		dprintk(2,"stopper vbi\n");
+		spin_lock(&dev->slock);
+		cx8800_restart_vbi_queue(dev,&dev->vbiq);
+		spin_unlock(&dev->slock);
+	}
+}
+
+static irqreturn_t cx8800_irq(int irq, void *dev_id)
+{
+	struct cx8800_dev *dev = dev_id;
+	struct cx88_core *core = dev->core;
+	u32 status;
+	int loop, handled = 0;
+
+	for (loop = 0; loop < 10; loop++) {
+		status = cx_read(MO_PCI_INTSTAT) &
+			(core->pci_irqmask | PCI_INT_VIDINT);
+		if (0 == status)
+			goto out;
+		cx_write(MO_PCI_INTSTAT, status);
+		handled = 1;
+
+		if (status & core->pci_irqmask)
+			cx88_core_irq(core,status);
+		if (status & PCI_INT_VIDINT)
+			cx8800_vid_irq(dev);
+	};
+	if (10 == loop) {
+		printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n",
+		       core->name);
+		cx_write(MO_PCI_INTMSK,0);
+	}
+
+ out:
+	return IRQ_RETVAL(handled);
+}
+
+/* ----------------------------------------------------------- */
+/* exported stuff                                              */
+
+static const struct v4l2_file_operations video_fops =
+{
+	.owner	       = THIS_MODULE,
+	.open	       = video_open,
+	.release       = video_release,
+	.read	       = video_read,
+	.poll          = video_poll,
+	.mmap	       = video_mmap,
+	.unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+	.vidioc_querycap      = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
+	.vidioc_reqbufs       = vidioc_reqbufs,
+	.vidioc_querybuf      = vidioc_querybuf,
+	.vidioc_qbuf          = vidioc_qbuf,
+	.vidioc_dqbuf         = vidioc_dqbuf,
+	.vidioc_g_std         = vidioc_g_std,
+	.vidioc_s_std         = vidioc_s_std,
+	.vidioc_enum_input    = vidioc_enum_input,
+	.vidioc_g_input       = vidioc_g_input,
+	.vidioc_s_input       = vidioc_s_input,
+	.vidioc_streamon      = vidioc_streamon,
+	.vidioc_streamoff     = vidioc_streamoff,
+	.vidioc_g_tuner       = vidioc_g_tuner,
+	.vidioc_s_tuner       = vidioc_s_tuner,
+	.vidioc_g_frequency   = vidioc_g_frequency,
+	.vidioc_s_frequency   = vidioc_s_frequency,
+	.vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
+	.vidioc_g_chip_ident  = vidioc_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register    = vidioc_g_register,
+	.vidioc_s_register    = vidioc_s_register,
+#endif
+};
+
+static const struct video_device cx8800_video_template = {
+	.name                 = "cx8800-video",
+	.fops                 = &video_fops,
+	.ioctl_ops 	      = &video_ioctl_ops,
+	.tvnorms              = CX88_NORMS,
+};
+
+static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
+	.vidioc_querycap      = vidioc_querycap,
+	.vidioc_g_fmt_vbi_cap     = cx8800_vbi_fmt,
+	.vidioc_try_fmt_vbi_cap   = cx8800_vbi_fmt,
+	.vidioc_s_fmt_vbi_cap     = cx8800_vbi_fmt,
+	.vidioc_reqbufs       = vidioc_reqbufs,
+	.vidioc_querybuf      = vidioc_querybuf,
+	.vidioc_qbuf          = vidioc_qbuf,
+	.vidioc_dqbuf         = vidioc_dqbuf,
+	.vidioc_g_std         = vidioc_g_std,
+	.vidioc_s_std         = vidioc_s_std,
+	.vidioc_enum_input    = vidioc_enum_input,
+	.vidioc_g_input       = vidioc_g_input,
+	.vidioc_s_input       = vidioc_s_input,
+	.vidioc_streamon      = vidioc_streamon,
+	.vidioc_streamoff     = vidioc_streamoff,
+	.vidioc_g_tuner       = vidioc_g_tuner,
+	.vidioc_s_tuner       = vidioc_s_tuner,
+	.vidioc_g_frequency   = vidioc_g_frequency,
+	.vidioc_s_frequency   = vidioc_s_frequency,
+	.vidioc_g_chip_ident  = vidioc_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register    = vidioc_g_register,
+	.vidioc_s_register    = vidioc_s_register,
+#endif
+};
+
+static const struct video_device cx8800_vbi_template = {
+	.name                 = "cx8800-vbi",
+	.fops                 = &video_fops,
+	.ioctl_ops	      = &vbi_ioctl_ops,
+	.tvnorms              = CX88_NORMS,
+};
+
+static const struct v4l2_file_operations radio_fops =
+{
+	.owner         = THIS_MODULE,
+	.open          = video_open,
+	.poll          = v4l2_ctrl_poll,
+	.release       = video_release,
+	.unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops radio_ioctl_ops = {
+	.vidioc_querycap      = vidioc_querycap,
+	.vidioc_g_tuner       = radio_g_tuner,
+	.vidioc_s_tuner       = radio_s_tuner,
+	.vidioc_g_frequency   = vidioc_g_frequency,
+	.vidioc_s_frequency   = vidioc_s_frequency,
+	.vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
+	.vidioc_g_chip_ident  = vidioc_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register    = vidioc_g_register,
+	.vidioc_s_register    = vidioc_s_register,
+#endif
+};
+
+static const struct video_device cx8800_radio_template = {
+	.name                 = "cx8800-radio",
+	.fops                 = &radio_fops,
+	.ioctl_ops 	      = &radio_ioctl_ops,
+};
+
+static const struct v4l2_ctrl_ops cx8800_ctrl_vid_ops = {
+	.s_ctrl = cx8800_s_vid_ctrl,
+};
+
+static const struct v4l2_ctrl_ops cx8800_ctrl_aud_ops = {
+	.s_ctrl = cx8800_s_aud_ctrl,
+};
+
+/* ----------------------------------------------------------- */
+
+static void cx8800_unregister_video(struct cx8800_dev *dev)
+{
+	if (dev->radio_dev) {
+		if (video_is_registered(dev->radio_dev))
+			video_unregister_device(dev->radio_dev);
+		else
+			video_device_release(dev->radio_dev);
+		dev->radio_dev = NULL;
+	}
+	if (dev->vbi_dev) {
+		if (video_is_registered(dev->vbi_dev))
+			video_unregister_device(dev->vbi_dev);
+		else
+			video_device_release(dev->vbi_dev);
+		dev->vbi_dev = NULL;
+	}
+	if (dev->video_dev) {
+		if (video_is_registered(dev->video_dev))
+			video_unregister_device(dev->video_dev);
+		else
+			video_device_release(dev->video_dev);
+		dev->video_dev = NULL;
+	}
+}
+
+static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
+				    const struct pci_device_id *pci_id)
+{
+	struct cx8800_dev *dev;
+	struct cx88_core *core;
+	int err;
+	int i;
+
+	dev = kzalloc(sizeof(*dev),GFP_KERNEL);
+	if (NULL == dev)
+		return -ENOMEM;
+
+	/* pci init */
+	dev->pci = pci_dev;
+	if (pci_enable_device(pci_dev)) {
+		err = -EIO;
+		goto fail_free;
+	}
+	core = cx88_core_get(dev->pci);
+	if (NULL == core) {
+		err = -EINVAL;
+		goto fail_free;
+	}
+	dev->core = core;
+
+	/* print pci info */
+	dev->pci_rev = pci_dev->revision;
+	pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
+	printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
+	       "latency: %d, mmio: 0x%llx\n", core->name,
+	       pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
+	       dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0));
+
+	pci_set_master(pci_dev);
+	if (!pci_dma_supported(pci_dev,DMA_BIT_MASK(32))) {
+		printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name);
+		err = -EIO;
+		goto fail_core;
+	}
+
+	/* initialize driver struct */
+	spin_lock_init(&dev->slock);
+	core->tvnorm = V4L2_STD_NTSC_M;
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&dev->vidq.active);
+	INIT_LIST_HEAD(&dev->vidq.queued);
+	dev->vidq.timeout.function = cx8800_vid_timeout;
+	dev->vidq.timeout.data     = (unsigned long)dev;
+	init_timer(&dev->vidq.timeout);
+	cx88_risc_stopper(dev->pci,&dev->vidq.stopper,
+			  MO_VID_DMACNTRL,0x11,0x00);
+
+	/* init vbi dma queues */
+	INIT_LIST_HEAD(&dev->vbiq.active);
+	INIT_LIST_HEAD(&dev->vbiq.queued);
+	dev->vbiq.timeout.function = cx8800_vbi_timeout;
+	dev->vbiq.timeout.data     = (unsigned long)dev;
+	init_timer(&dev->vbiq.timeout);
+	cx88_risc_stopper(dev->pci,&dev->vbiq.stopper,
+			  MO_VID_DMACNTRL,0x88,0x00);
+
+	/* get irq */
+	err = request_irq(pci_dev->irq, cx8800_irq,
+			  IRQF_SHARED | IRQF_DISABLED, core->name, dev);
+	if (err < 0) {
+		printk(KERN_ERR "%s/0: can't get IRQ %d\n",
+		       core->name,pci_dev->irq);
+		goto fail_core;
+	}
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask);
+
+	for (i = 0; i < CX8800_AUD_CTLS; i++) {
+		const struct cx88_ctrl *cc = &cx8800_aud_ctls[i];
+		struct v4l2_ctrl *vc;
+
+		vc = v4l2_ctrl_new_std(&core->audio_hdl, &cx8800_ctrl_aud_ops,
+			cc->id, cc->minimum, cc->maximum, cc->step, cc->default_value);
+		if (vc == NULL) {
+			err = core->audio_hdl.error;
+			goto fail_core;
+		}
+		vc->priv = (void *)cc;
+	}
+
+	for (i = 0; i < CX8800_VID_CTLS; i++) {
+		const struct cx88_ctrl *cc = &cx8800_vid_ctls[i];
+		struct v4l2_ctrl *vc;
+
+		vc = v4l2_ctrl_new_std(&core->video_hdl, &cx8800_ctrl_vid_ops,
+			cc->id, cc->minimum, cc->maximum, cc->step, cc->default_value);
+		if (vc == NULL) {
+			err = core->video_hdl.error;
+			goto fail_core;
+		}
+		vc->priv = (void *)cc;
+		if (vc->id == V4L2_CID_CHROMA_AGC)
+			core->chroma_agc = vc;
+	}
+	v4l2_ctrl_add_handler(&core->video_hdl, &core->audio_hdl);
+
+	/* load and configure helper modules */
+
+	if (core->board.audio_chip == V4L2_IDENT_WM8775) {
+		struct i2c_board_info wm8775_info = {
+			.type = "wm8775",
+			.addr = 0x36 >> 1,
+			.platform_data = &core->wm8775_data,
+		};
+		struct v4l2_subdev *sd;
+
+		if (core->boardnr == CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1)
+			core->wm8775_data.is_nova_s = true;
+		else
+			core->wm8775_data.is_nova_s = false;
+
+		sd = v4l2_i2c_new_subdev_board(&core->v4l2_dev, &core->i2c_adap,
+				&wm8775_info, NULL);
+		if (sd != NULL) {
+			core->sd_wm8775 = sd;
+			sd->grp_id = WM8775_GID;
+		}
+	}
+
+	if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
+		/* This probes for a tda9874 as is used on some
+		   Pixelview Ultra boards. */
+		v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
+				"tvaudio", 0, I2C_ADDRS(0xb0 >> 1));
+	}
+
+	switch (core->boardnr) {
+	case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
+	case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: {
+		static const struct i2c_board_info rtc_info = {
+			I2C_BOARD_INFO("isl1208", 0x6f)
+		};
+
+		request_module("rtc-isl1208");
+		core->i2c_rtc = i2c_new_device(&core->i2c_adap, &rtc_info);
+	}
+		/* break intentionally omitted */
+	case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
+		request_module("ir-kbd-i2c");
+	}
+
+	/* Sets device info at pci_dev */
+	pci_set_drvdata(pci_dev, dev);
+
+	dev->width   = 320;
+	dev->height  = 240;
+	dev->fmt     = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+
+	/* initial device configuration */
+	mutex_lock(&core->lock);
+	cx88_set_tvnorm(core, core->tvnorm);
+	v4l2_ctrl_handler_setup(&core->video_hdl);
+	v4l2_ctrl_handler_setup(&core->audio_hdl);
+	cx88_video_mux(core, 0);
+
+	/* register v4l devices */
+	dev->video_dev = cx88_vdev_init(core,dev->pci,
+					&cx8800_video_template,"video");
+	video_set_drvdata(dev->video_dev, dev);
+	dev->video_dev->ctrl_handler = &core->video_hdl;
+	err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
+				    video_nr[core->nr]);
+	if (err < 0) {
+		printk(KERN_ERR "%s/0: can't register video device\n",
+		       core->name);
+		goto fail_unreg;
+	}
+	printk(KERN_INFO "%s/0: registered device %s [v4l2]\n",
+	       core->name, video_device_node_name(dev->video_dev));
+
+	dev->vbi_dev = cx88_vdev_init(core,dev->pci,&cx8800_vbi_template,"vbi");
+	video_set_drvdata(dev->vbi_dev, dev);
+	err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
+				    vbi_nr[core->nr]);
+	if (err < 0) {
+		printk(KERN_ERR "%s/0: can't register vbi device\n",
+		       core->name);
+		goto fail_unreg;
+	}
+	printk(KERN_INFO "%s/0: registered device %s\n",
+	       core->name, video_device_node_name(dev->vbi_dev));
+
+	if (core->board.radio.type == CX88_RADIO) {
+		dev->radio_dev = cx88_vdev_init(core,dev->pci,
+						&cx8800_radio_template,"radio");
+		video_set_drvdata(dev->radio_dev, dev);
+		dev->radio_dev->ctrl_handler = &core->audio_hdl;
+		err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
+					    radio_nr[core->nr]);
+		if (err < 0) {
+			printk(KERN_ERR "%s/0: can't register radio device\n",
+			       core->name);
+			goto fail_unreg;
+		}
+		printk(KERN_INFO "%s/0: registered device %s\n",
+		       core->name, video_device_node_name(dev->radio_dev));
+	}
+
+	/* start tvaudio thread */
+	if (core->board.tuner_type != TUNER_ABSENT) {
+		core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio");
+		if (IS_ERR(core->kthread)) {
+			err = PTR_ERR(core->kthread);
+			printk(KERN_ERR "%s/0: failed to create cx88 audio thread, err=%d\n",
+			       core->name, err);
+		}
+	}
+	mutex_unlock(&core->lock);
+
+	return 0;
+
+fail_unreg:
+	cx8800_unregister_video(dev);
+	free_irq(pci_dev->irq, dev);
+	mutex_unlock(&core->lock);
+fail_core:
+	cx88_core_put(core,dev->pci);
+fail_free:
+	kfree(dev);
+	return err;
+}
+
+static void __devexit cx8800_finidev(struct pci_dev *pci_dev)
+{
+	struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
+	struct cx88_core *core = dev->core;
+
+	/* stop thread */
+	if (core->kthread) {
+		kthread_stop(core->kthread);
+		core->kthread = NULL;
+	}
+
+	if (core->ir)
+		cx88_ir_stop(core);
+
+	cx88_shutdown(core); /* FIXME */
+	pci_disable_device(pci_dev);
+
+	/* unregister stuff */
+
+	free_irq(pci_dev->irq, dev);
+	cx8800_unregister_video(dev);
+	pci_set_drvdata(pci_dev, NULL);
+
+	/* free memory */
+	btcx_riscmem_free(dev->pci,&dev->vidq.stopper);
+	cx88_core_put(core,dev->pci);
+	kfree(dev);
+}
+
+#ifdef CONFIG_PM
+static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
+{
+	struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
+	struct cx88_core *core = dev->core;
+
+	/* stop video+vbi capture */
+	spin_lock(&dev->slock);
+	if (!list_empty(&dev->vidq.active)) {
+		printk("%s/0: suspend video\n", core->name);
+		stop_video_dma(dev);
+		del_timer(&dev->vidq.timeout);
+	}
+	if (!list_empty(&dev->vbiq.active)) {
+		printk("%s/0: suspend vbi\n", core->name);
+		cx8800_stop_vbi_dma(dev);
+		del_timer(&dev->vbiq.timeout);
+	}
+	spin_unlock(&dev->slock);
+
+	if (core->ir)
+		cx88_ir_stop(core);
+	/* FIXME -- shutdown device */
+	cx88_shutdown(core);
+
+	pci_save_state(pci_dev);
+	if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
+		pci_disable_device(pci_dev);
+		dev->state.disabled = 1;
+	}
+	return 0;
+}
+
+static int cx8800_resume(struct pci_dev *pci_dev)
+{
+	struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
+	struct cx88_core *core = dev->core;
+	int err;
+
+	if (dev->state.disabled) {
+		err=pci_enable_device(pci_dev);
+		if (err) {
+			printk(KERN_ERR "%s/0: can't enable device\n",
+			       core->name);
+			return err;
+		}
+
+		dev->state.disabled = 0;
+	}
+	err= pci_set_power_state(pci_dev, PCI_D0);
+	if (err) {
+		printk(KERN_ERR "%s/0: can't set power state\n", core->name);
+		pci_disable_device(pci_dev);
+		dev->state.disabled = 1;
+
+		return err;
+	}
+	pci_restore_state(pci_dev);
+
+	/* FIXME: re-initialize hardware */
+	cx88_reset(core);
+	if (core->ir)
+		cx88_ir_start(core);
+
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask);
+
+	/* restart video+vbi capture */
+	spin_lock(&dev->slock);
+	if (!list_empty(&dev->vidq.active)) {
+		printk("%s/0: resume video\n", core->name);
+		restart_video_queue(dev,&dev->vidq);
+	}
+	if (!list_empty(&dev->vbiq.active)) {
+		printk("%s/0: resume vbi\n", core->name);
+		cx8800_restart_vbi_queue(dev,&dev->vbiq);
+	}
+	spin_unlock(&dev->slock);
+
+	return 0;
+}
+#endif
+
+/* ----------------------------------------------------------- */
+
+static const struct pci_device_id cx8800_pci_tbl[] = {
+	{
+		.vendor       = 0x14f1,
+		.device       = 0x8800,
+		.subvendor    = PCI_ANY_ID,
+		.subdevice    = PCI_ANY_ID,
+	},{
+		/* --- end of list --- */
+	}
+};
+MODULE_DEVICE_TABLE(pci, cx8800_pci_tbl);
+
+static struct pci_driver cx8800_pci_driver = {
+	.name     = "cx8800",
+	.id_table = cx8800_pci_tbl,
+	.probe    = cx8800_initdev,
+	.remove   = __devexit_p(cx8800_finidev),
+#ifdef CONFIG_PM
+	.suspend  = cx8800_suspend,
+	.resume   = cx8800_resume,
+#endif
+};
+
+static int __init cx8800_init(void)
+{
+	printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %s loaded\n",
+	       CX88_VERSION);
+	return pci_register_driver(&cx8800_pci_driver);
+}
+
+static void __exit cx8800_fini(void)
+{
+	pci_unregister_driver(&cx8800_pci_driver);
+}
+
+module_init(cx8800_init);
+module_exit(cx8800_fini);
diff --git a/drivers/media/pci/cx88/cx88-vp3054-i2c.c b/drivers/media/pci/cx88/cx88-vp3054-i2c.c
new file mode 100644
index 0000000..d77f8ec
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-vp3054-i2c.c
@@ -0,0 +1,159 @@
+/*
+
+    cx88-vp3054-i2c.c  --  support for the secondary I2C bus of the
+			   DNTV Live! DVB-T Pro (VP-3054), wired as:
+			   GPIO[0] -> SCL, GPIO[1] -> SDA
+
+    (c) 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "cx88.h"
+#include "cx88-vp3054-i2c.h"
+
+MODULE_DESCRIPTION("driver for cx2388x VP3054 design");
+MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
+MODULE_LICENSE("GPL");
+
+/* ----------------------------------------------------------------------- */
+
+static void vp3054_bit_setscl(void *data, int state)
+{
+	struct cx8802_dev *dev = data;
+	struct cx88_core *core = dev->core;
+	struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
+
+	if (state) {
+		vp3054_i2c->state |=  0x0001;	/* SCL high */
+		vp3054_i2c->state &= ~0x0100;	/* external pullup */
+	} else {
+		vp3054_i2c->state &= ~0x0001;	/* SCL low */
+		vp3054_i2c->state |=  0x0100;	/* drive pin */
+	}
+	cx_write(MO_GP0_IO, 0x010000 | vp3054_i2c->state);
+	cx_read(MO_GP0_IO);
+}
+
+static void vp3054_bit_setsda(void *data, int state)
+{
+	struct cx8802_dev *dev = data;
+	struct cx88_core *core = dev->core;
+	struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
+
+	if (state) {
+		vp3054_i2c->state |=  0x0002;	/* SDA high */
+		vp3054_i2c->state &= ~0x0200;	/* tristate pin */
+	} else {
+		vp3054_i2c->state &= ~0x0002;	/* SDA low */
+		vp3054_i2c->state |=  0x0200;	/* drive pin */
+	}
+	cx_write(MO_GP0_IO, 0x020000 | vp3054_i2c->state);
+	cx_read(MO_GP0_IO);
+}
+
+static int vp3054_bit_getscl(void *data)
+{
+	struct cx8802_dev *dev = data;
+	struct cx88_core *core = dev->core;
+	u32 state;
+
+	state = cx_read(MO_GP0_IO);
+	return (state & 0x01) ? 1 : 0;
+}
+
+static int vp3054_bit_getsda(void *data)
+{
+	struct cx8802_dev *dev = data;
+	struct cx88_core *core = dev->core;
+	u32 state;
+
+	state = cx_read(MO_GP0_IO);
+	return (state & 0x02) ? 1 : 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_algo_bit_data vp3054_i2c_algo_template = {
+	.setsda  = vp3054_bit_setsda,
+	.setscl  = vp3054_bit_setscl,
+	.getsda  = vp3054_bit_getsda,
+	.getscl  = vp3054_bit_getscl,
+	.udelay  = 16,
+	.timeout = 200,
+};
+
+/* ----------------------------------------------------------------------- */
+
+int vp3054_i2c_probe(struct cx8802_dev *dev)
+{
+	struct cx88_core *core = dev->core;
+	struct vp3054_i2c_state *vp3054_i2c;
+	int rc;
+
+	if (core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
+		return 0;
+
+	vp3054_i2c = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL);
+	if (vp3054_i2c == NULL)
+		return -ENOMEM;
+	dev->vp3054 = vp3054_i2c;
+
+	memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template,
+	       sizeof(vp3054_i2c->algo));
+
+	vp3054_i2c->adap.dev.parent = &dev->pci->dev;
+	strlcpy(vp3054_i2c->adap.name, core->name,
+		sizeof(vp3054_i2c->adap.name));
+	vp3054_i2c->adap.owner = THIS_MODULE;
+	vp3054_i2c->algo.data = dev;
+	i2c_set_adapdata(&vp3054_i2c->adap, dev);
+	vp3054_i2c->adap.algo_data = &vp3054_i2c->algo;
+
+	vp3054_bit_setscl(dev,1);
+	vp3054_bit_setsda(dev,1);
+
+	rc = i2c_bit_add_bus(&vp3054_i2c->adap);
+	if (0 != rc) {
+		printk("%s: vp3054_i2c register FAILED\n", core->name);
+
+		kfree(dev->vp3054);
+		dev->vp3054 = NULL;
+	}
+
+	return rc;
+}
+
+void vp3054_i2c_remove(struct cx8802_dev *dev)
+{
+	struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
+
+	if (vp3054_i2c == NULL ||
+	    dev->core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
+		return;
+
+	i2c_del_adapter(&vp3054_i2c->adap);
+	kfree(vp3054_i2c);
+}
+
+EXPORT_SYMBOL(vp3054_i2c_probe);
+EXPORT_SYMBOL(vp3054_i2c_remove);
diff --git a/drivers/media/pci/cx88/cx88-vp3054-i2c.h b/drivers/media/pci/cx88/cx88-vp3054-i2c.h
new file mode 100644
index 0000000..be99c93
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-vp3054-i2c.h
@@ -0,0 +1,41 @@
+/*
+
+    cx88-vp3054-i2c.h  --  support for the secondary I2C bus of the
+			   DNTV Live! DVB-T Pro (VP-3054), wired as:
+			   GPIO[0] -> SCL, GPIO[1] -> SDA
+
+    (c) 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/* ----------------------------------------------------------------------- */
+struct vp3054_i2c_state {
+	struct i2c_adapter         adap;
+	struct i2c_algo_bit_data   algo;
+	u32                        state;
+};
+
+/* ----------------------------------------------------------------------- */
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
+int  vp3054_i2c_probe(struct cx8802_dev *dev);
+void vp3054_i2c_remove(struct cx8802_dev *dev);
+#else
+static inline int  vp3054_i2c_probe(struct cx8802_dev *dev)
+{ return 0; }
+static inline void vp3054_i2c_remove(struct cx8802_dev *dev)
+{ }
+#endif
diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h
new file mode 100644
index 0000000..44ffc8b
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88.h
@@ -0,0 +1,748 @@
+/*
+ *
+ * v4l2 device driver for cx2388x based TV cards
+ *
+ * (c) 2003,04 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/videodev2.h>
+#include <linux/kdev_t.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/tuner.h>
+#include <media/tveeprom.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/cx2341x.h>
+#include <media/videobuf-dvb.h>
+#include <media/ir-kbd-i2c.h>
+#include <media/wm8775.h>
+
+#include "btcx-risc.h"
+#include "cx88-reg.h"
+#include "tuner-xc2028.h"
+
+#include <linux/mutex.h>
+
+#define CX88_VERSION "0.0.9"
+
+#define UNSET (-1U)
+
+#define CX88_MAXBOARDS 8
+
+/* Max number of inputs by card */
+#define MAX_CX88_INPUT 8
+
+/* ----------------------------------------------------------- */
+/* defines and enums                                           */
+
+/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM/LC */
+#define CX88_NORMS (V4L2_STD_ALL 		\
+		    & ~V4L2_STD_PAL_H		\
+		    & ~V4L2_STD_NTSC_M_KR	\
+		    & ~V4L2_STD_SECAM_LC)
+
+#define FORMAT_FLAGS_PACKED       0x01
+#define FORMAT_FLAGS_PLANAR       0x02
+
+#define VBI_LINE_COUNT              17
+#define VBI_LINE_LENGTH           2048
+
+#define AUD_RDS_LINES		     4
+
+/* need "shadow" registers for some write-only ones ... */
+#define SHADOW_AUD_VOL_CTL           1
+#define SHADOW_AUD_BAL_CTL           2
+#define SHADOW_MAX                   3
+
+/* FM Radio deemphasis type */
+enum cx88_deemph_type {
+	FM_NO_DEEMPH = 0,
+	FM_DEEMPH_50,
+	FM_DEEMPH_75
+};
+
+enum cx88_board_type {
+	CX88_BOARD_NONE = 0,
+	CX88_MPEG_DVB,
+	CX88_MPEG_BLACKBIRD
+};
+
+enum cx8802_board_access {
+	CX8802_DRVCTL_SHARED    = 1,
+	CX8802_DRVCTL_EXCLUSIVE = 2,
+};
+
+/* ----------------------------------------------------------- */
+/* tv norms                                                    */
+
+static unsigned int inline norm_maxw(v4l2_std_id norm)
+{
+	return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
+}
+
+
+static unsigned int inline norm_maxh(v4l2_std_id norm)
+{
+	return (norm & V4L2_STD_625_50) ? 576 : 480;
+}
+
+/* ----------------------------------------------------------- */
+/* static data                                                 */
+
+struct cx8800_fmt {
+	const char  *name;
+	u32   fourcc;          /* v4l2 format id */
+	int   depth;
+	int   flags;
+	u32   cxformat;
+};
+
+/* ----------------------------------------------------------- */
+/* SRAM memory management data (see cx88-core.c)               */
+
+#define SRAM_CH21 0   /* video */
+#define SRAM_CH22 1
+#define SRAM_CH23 2
+#define SRAM_CH24 3   /* vbi   */
+#define SRAM_CH25 4   /* audio */
+#define SRAM_CH26 5
+#define SRAM_CH28 6   /* mpeg */
+#define SRAM_CH27 7   /* audio rds */
+/* more */
+
+struct sram_channel {
+	const char *name;
+	u32  cmds_start;
+	u32  ctrl_start;
+	u32  cdt;
+	u32  fifo_start;
+	u32  fifo_size;
+	u32  ptr1_reg;
+	u32  ptr2_reg;
+	u32  cnt1_reg;
+	u32  cnt2_reg;
+};
+extern const struct sram_channel cx88_sram_channels[];
+
+/* ----------------------------------------------------------- */
+/* card configuration                                          */
+
+#define CX88_BOARD_NOAUTO               UNSET
+#define CX88_BOARD_UNKNOWN                  0
+#define CX88_BOARD_HAUPPAUGE                1
+#define CX88_BOARD_GDI                      2
+#define CX88_BOARD_PIXELVIEW                3
+#define CX88_BOARD_ATI_WONDER_PRO           4
+#define CX88_BOARD_WINFAST2000XP_EXPERT     5
+#define CX88_BOARD_AVERTV_STUDIO_303        6
+#define CX88_BOARD_MSI_TVANYWHERE_MASTER    7
+#define CX88_BOARD_WINFAST_DV2000           8
+#define CX88_BOARD_LEADTEK_PVR2000          9
+#define CX88_BOARD_IODATA_GVVCP3PCI        10
+#define CX88_BOARD_PROLINK_PLAYTVPVR       11
+#define CX88_BOARD_ASUS_PVR_416            12
+#define CX88_BOARD_MSI_TVANYWHERE          13
+#define CX88_BOARD_KWORLD_DVB_T            14
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1 15
+#define CX88_BOARD_KWORLD_LTV883           16
+#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q  17
+#define CX88_BOARD_HAUPPAUGE_DVB_T1        18
+#define CX88_BOARD_CONEXANT_DVB_T1         19
+#define CX88_BOARD_PROVIDEO_PV259          20
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS 21
+#define CX88_BOARD_PCHDTV_HD3000           22
+#define CX88_BOARD_DNTV_LIVE_DVB_T         23
+#define CX88_BOARD_HAUPPAUGE_ROSLYN        24
+#define CX88_BOARD_DIGITALLOGIC_MEC        25
+#define CX88_BOARD_IODATA_GVBCTV7E         26
+#define CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO 27
+#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T  28
+#define CX88_BOARD_ADSTECH_DVB_T_PCI          29
+#define CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1  30
+#define CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD 31
+#define CX88_BOARD_AVERMEDIA_ULTRATV_MC_550 32
+#define CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD 33
+#define CX88_BOARD_ATI_HDTVWONDER          34
+#define CX88_BOARD_WINFAST_DTV1000         35
+#define CX88_BOARD_AVERTV_303              36
+#define CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1  37
+#define CX88_BOARD_HAUPPAUGE_NOVASE2_S1    38
+#define CX88_BOARD_KWORLD_DVBS_100         39
+#define CX88_BOARD_HAUPPAUGE_HVR1100       40
+#define CX88_BOARD_HAUPPAUGE_HVR1100LP     41
+#define CX88_BOARD_DNTV_LIVE_DVB_T_PRO     42
+#define CX88_BOARD_KWORLD_DVB_T_CX22702    43
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44
+#define CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT 45
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID 46
+#define CX88_BOARD_PCHDTV_HD5500           47
+#define CX88_BOARD_KWORLD_MCE200_DELUXE    48
+#define CX88_BOARD_PIXELVIEW_PLAYTV_P7000  49
+#define CX88_BOARD_NPGTECH_REALTV_TOP10FM  50
+#define CX88_BOARD_WINFAST_DTV2000H        51
+#define CX88_BOARD_GENIATECH_DVBS          52
+#define CX88_BOARD_HAUPPAUGE_HVR3000       53
+#define CX88_BOARD_NORWOOD_MICRO           54
+#define CX88_BOARD_TE_DTV_250_OEM_SWANN    55
+#define CX88_BOARD_HAUPPAUGE_HVR1300       56
+#define CX88_BOARD_ADSTECH_PTV_390         57
+#define CX88_BOARD_PINNACLE_PCTV_HD_800i   58
+#define CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO 59
+#define CX88_BOARD_PINNACLE_HYBRID_PCTV    60
+#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL 61
+#define CX88_BOARD_POWERCOLOR_REAL_ANGEL   62
+#define CX88_BOARD_GENIATECH_X8000_MT      63
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO 64
+#define CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD 65
+#define CX88_BOARD_PROLINK_PV_8000GT       66
+#define CX88_BOARD_KWORLD_ATSC_120         67
+#define CX88_BOARD_HAUPPAUGE_HVR4000       68
+#define CX88_BOARD_HAUPPAUGE_HVR4000LITE   69
+#define CX88_BOARD_TEVII_S460              70
+#define CX88_BOARD_OMICOM_SS4_PCI          71
+#define CX88_BOARD_TBS_8920                72
+#define CX88_BOARD_TEVII_S420              73
+#define CX88_BOARD_PROLINK_PV_GLOBAL_XTREME 74
+#define CX88_BOARD_PROF_7300               75
+#define CX88_BOARD_SATTRADE_ST4200         76
+#define CX88_BOARD_TBS_8910                77
+#define CX88_BOARD_PROF_6200               78
+#define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79
+#define CX88_BOARD_HAUPPAUGE_IRONLY        80
+#define CX88_BOARD_WINFAST_DTV1800H        81
+#define CX88_BOARD_WINFAST_DTV2000H_J      82
+#define CX88_BOARD_PROF_7301               83
+#define CX88_BOARD_SAMSUNG_SMT_7020        84
+#define CX88_BOARD_TWINHAN_VP1027_DVBS     85
+#define CX88_BOARD_TEVII_S464              86
+#define CX88_BOARD_WINFAST_DTV2000H_PLUS   87
+#define CX88_BOARD_WINFAST_DTV1800H_XC4000 88
+#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36 89
+#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43 90
+
+enum cx88_itype {
+	CX88_VMUX_COMPOSITE1 = 1,
+	CX88_VMUX_COMPOSITE2,
+	CX88_VMUX_COMPOSITE3,
+	CX88_VMUX_COMPOSITE4,
+	CX88_VMUX_SVIDEO,
+	CX88_VMUX_TELEVISION,
+	CX88_VMUX_CABLE,
+	CX88_VMUX_DVB,
+	CX88_VMUX_DEBUG,
+	CX88_RADIO,
+};
+
+struct cx88_input {
+	enum cx88_itype type;
+	u32             gpio0, gpio1, gpio2, gpio3;
+	unsigned int    vmux:2;
+	unsigned int    audioroute:4;
+};
+
+struct cx88_board {
+	const char              *name;
+	unsigned int            tuner_type;
+	unsigned int		radio_type;
+	unsigned char		tuner_addr;
+	unsigned char		radio_addr;
+	int                     tda9887_conf;
+	struct cx88_input       input[MAX_CX88_INPUT];
+	struct cx88_input       radio;
+	enum cx88_board_type    mpeg;
+	unsigned int            audio_chip;
+	int			num_frontends;
+
+	/* Used for I2S devices */
+	int			i2sinputcntl;
+};
+
+struct cx88_subid {
+	u16     subvendor;
+	u16     subdevice;
+	u32     card;
+};
+
+enum cx88_tvaudio {
+	WW_NONE = 1,
+	WW_BTSC,
+	WW_BG,
+	WW_DK,
+	WW_I,
+	WW_L,
+	WW_EIAJ,
+	WW_I2SPT,
+	WW_FM,
+	WW_I2SADC,
+	WW_M
+};
+
+#define INPUT(nr) (core->board.input[nr])
+
+/* ----------------------------------------------------------- */
+/* device / file handle status                                 */
+
+#define RESOURCE_OVERLAY       1
+#define RESOURCE_VIDEO         2
+#define RESOURCE_VBI           4
+
+#define BUFFER_TIMEOUT     msecs_to_jiffies(2000)
+
+/* buffer for one video frame */
+struct cx88_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+
+	/* cx88 specific */
+	unsigned int           bpl;
+	struct btcx_riscmem    risc;
+	const struct cx8800_fmt *fmt;
+	u32                    count;
+};
+
+struct cx88_dmaqueue {
+	struct list_head       active;
+	struct list_head       queued;
+	struct timer_list      timeout;
+	struct btcx_riscmem    stopper;
+	u32                    count;
+};
+
+struct cx88_core {
+	struct list_head           devlist;
+	atomic_t                   refcount;
+
+	/* board name */
+	int                        nr;
+	char                       name[32];
+
+	/* pci stuff */
+	int                        pci_bus;
+	int                        pci_slot;
+	u32                        __iomem *lmmio;
+	u8                         __iomem *bmmio;
+	u32                        shadow[SHADOW_MAX];
+	int                        pci_irqmask;
+
+	/* i2c i/o */
+	struct i2c_adapter         i2c_adap;
+	struct i2c_algo_bit_data   i2c_algo;
+	struct i2c_client          i2c_client;
+	u32                        i2c_state, i2c_rc;
+
+	/* config info -- analog */
+	struct v4l2_device 	   v4l2_dev;
+	struct v4l2_ctrl_handler   video_hdl;
+	struct v4l2_ctrl	   *chroma_agc;
+	struct v4l2_ctrl_handler   audio_hdl;
+	struct v4l2_subdev	   *sd_wm8775;
+	struct i2c_client 	   *i2c_rtc;
+	unsigned int               boardnr;
+	struct cx88_board	   board;
+
+	/* Supported V4L _STD_ tuner formats */
+	unsigned int               tuner_formats;
+
+	/* config info -- dvb */
+#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
+	int 			   (*prev_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+#endif
+	void			   (*gate_ctrl)(struct cx88_core  *core, int open);
+
+	/* state info */
+	struct task_struct         *kthread;
+	v4l2_std_id                tvnorm;
+	enum cx88_tvaudio          tvaudio;
+	u32                        audiomode_manual;
+	u32                        audiomode_current;
+	u32                        input;
+	u32                        last_analog_input;
+	u32                        astat;
+	u32			   use_nicam;
+	unsigned long		   last_change;
+
+	/* IR remote control state */
+	struct cx88_IR             *ir;
+
+	/* I2C remote data */
+	struct IR_i2c_init_data    init_data;
+	struct wm8775_platform_data wm8775_data;
+
+	struct mutex               lock;
+	/* various v4l controls */
+	u32                        freq;
+	int                        users;
+	int                        mpeg_users;
+
+	/* cx88-video needs to access cx8802 for hybrid tuner pll access. */
+	struct cx8802_dev          *dvbdev;
+	enum cx88_board_type       active_type_id;
+	int			   active_ref;
+	int			   active_fe_id;
+};
+
+static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
+{
+	return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
+}
+
+#define call_hw(core, grpid, o, f, args...) \
+	do {							\
+		if (!core->i2c_rc) {				\
+			if (core->gate_ctrl)			\
+				core->gate_ctrl(core, 1);	\
+			v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \
+			if (core->gate_ctrl)			\
+				core->gate_ctrl(core, 0);	\
+		}						\
+	} while (0)
+
+#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args)
+
+#define WM8775_GID      (1 << 0)
+
+#define wm8775_s_ctrl(core, id, val) \
+	do {									\
+		struct v4l2_ctrl *ctrl_ =					\
+			v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id);	\
+		if (ctrl_ && !core->i2c_rc) {					\
+			if (core->gate_ctrl)					\
+				core->gate_ctrl(core, 1);			\
+			v4l2_ctrl_s_ctrl(ctrl_, val);				\
+			if (core->gate_ctrl)					\
+				core->gate_ctrl(core, 0);			\
+		}								\
+	} while (0)
+
+#define wm8775_g_ctrl(core, id) \
+	({									\
+		struct v4l2_ctrl *ctrl_ =					\
+			v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id);	\
+		s32 val = 0;							\
+		if (ctrl_ && !core->i2c_rc) {					\
+			if (core->gate_ctrl)					\
+				core->gate_ctrl(core, 1);			\
+			val = v4l2_ctrl_g_ctrl(ctrl_);				\
+			if (core->gate_ctrl)					\
+				core->gate_ctrl(core, 0);			\
+		}								\
+		val;								\
+	})
+
+struct cx8800_dev;
+struct cx8802_dev;
+
+/* ----------------------------------------------------------- */
+/* function 0: video stuff                                     */
+
+struct cx8800_fh {
+	struct v4l2_fh		   fh;
+	struct cx8800_dev          *dev;
+	unsigned int               resources;
+
+	/* video capture */
+	struct videobuf_queue      vidq;
+
+	/* vbi capture */
+	struct videobuf_queue      vbiq;
+};
+
+struct cx8800_suspend_state {
+	int                        disabled;
+};
+
+struct cx8800_dev {
+	struct cx88_core           *core;
+	spinlock_t                 slock;
+
+	/* various device info */
+	unsigned int               resources;
+	struct video_device        *video_dev;
+	struct video_device        *vbi_dev;
+	struct video_device        *radio_dev;
+
+	/* pci i/o */
+	struct pci_dev             *pci;
+	unsigned char              pci_rev,pci_lat;
+
+	const struct cx8800_fmt    *fmt;
+	unsigned int               width, height;
+
+	/* capture queues */
+	struct cx88_dmaqueue       vidq;
+	struct cx88_dmaqueue       vbiq;
+
+	/* various v4l controls */
+
+	/* other global state info */
+	struct cx8800_suspend_state state;
+};
+
+/* ----------------------------------------------------------- */
+/* function 1: audio/alsa stuff                                */
+/* =============> moved to cx88-alsa.c <====================== */
+
+
+/* ----------------------------------------------------------- */
+/* function 2: mpeg stuff                                      */
+
+struct cx8802_fh {
+	struct v4l2_fh		   fh;
+	struct cx8802_dev          *dev;
+	struct videobuf_queue      mpegq;
+};
+
+struct cx8802_suspend_state {
+	int                        disabled;
+};
+
+struct cx8802_driver {
+	struct cx88_core *core;
+
+	/* List of drivers attached to device */
+	struct list_head drvlist;
+
+	/* Type of driver and access required */
+	enum cx88_board_type type_id;
+	enum cx8802_board_access hw_access;
+
+	/* MPEG 8802 internal only */
+	int (*suspend)(struct pci_dev *pci_dev, pm_message_t state);
+	int (*resume)(struct pci_dev *pci_dev);
+
+	/* Callers to the following functions must hold core->lock */
+
+	/* MPEG 8802 -> mini driver - Driver probe and configuration */
+	int (*probe)(struct cx8802_driver *drv);
+	int (*remove)(struct cx8802_driver *drv);
+
+	/* MPEG 8802 -> mini driver - Access for hardware control */
+	int (*advise_acquire)(struct cx8802_driver *drv);
+	int (*advise_release)(struct cx8802_driver *drv);
+
+	/* MPEG 8802 <- mini driver - Access for hardware control */
+	int (*request_acquire)(struct cx8802_driver *drv);
+	int (*request_release)(struct cx8802_driver *drv);
+};
+
+struct cx8802_dev {
+	struct cx88_core           *core;
+	spinlock_t                 slock;
+
+	/* pci i/o */
+	struct pci_dev             *pci;
+	unsigned char              pci_rev,pci_lat;
+
+	/* dma queues */
+	struct cx88_dmaqueue       mpegq;
+	u32                        ts_packet_size;
+	u32                        ts_packet_count;
+
+	/* other global state info */
+	struct cx8802_suspend_state state;
+
+	/* for blackbird only */
+	struct list_head           devlist;
+#if defined(CONFIG_VIDEO_CX88_BLACKBIRD) || \
+    defined(CONFIG_VIDEO_CX88_BLACKBIRD_MODULE)
+	struct video_device        *mpeg_dev;
+	u32                        mailbox;
+	int                        width;
+	int                        height;
+	unsigned char              mpeg_active; /* nonzero if mpeg encoder is active */
+
+	/* mpeg params */
+	struct cx2341x_handler     cxhdl;
+#endif
+
+#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
+	/* for dvb only */
+	struct videobuf_dvb_frontends frontends;
+#endif
+
+#if defined(CONFIG_VIDEO_CX88_VP3054) || \
+    defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
+	/* For VP3045 secondary I2C bus support */
+	struct vp3054_i2c_state	   *vp3054;
+#endif
+	/* for switching modulation types */
+	unsigned char              ts_gen_cntrl;
+
+	/* List of attached drivers; must hold core->lock to access */
+	struct list_head	   drvlist;
+
+	struct work_struct	   request_module_wk;
+};
+
+/* ----------------------------------------------------------- */
+
+#define cx_read(reg)             readl(core->lmmio + ((reg)>>2))
+#define cx_write(reg,value)      writel((value), core->lmmio + ((reg)>>2))
+#define cx_writeb(reg,value)     writeb((value), core->bmmio + (reg))
+
+#define cx_andor(reg,mask,value) \
+  writel((readl(core->lmmio+((reg)>>2)) & ~(mask)) |\
+  ((value) & (mask)), core->lmmio+((reg)>>2))
+#define cx_set(reg,bit)          cx_andor((reg),(bit),(bit))
+#define cx_clear(reg,bit)        cx_andor((reg),(bit),0)
+
+#define cx_wait(d) { if (need_resched()) schedule(); else udelay(d); }
+
+/* shadow registers */
+#define cx_sread(sreg)		    (core->shadow[sreg])
+#define cx_swrite(sreg,reg,value) \
+  (core->shadow[sreg] = value, \
+   writel(core->shadow[sreg], core->lmmio + ((reg)>>2)))
+#define cx_sandor(sreg,reg,mask,value) \
+  (core->shadow[sreg] = (core->shadow[sreg] & ~(mask)) | ((value) & (mask)), \
+   writel(core->shadow[sreg], core->lmmio + ((reg)>>2)))
+
+/* ----------------------------------------------------------- */
+/* cx88-core.c                                                 */
+
+extern void cx88_print_irqbits(const char *name, const char *tag, const char *strings[],
+			       int len, u32 bits, u32 mask);
+
+extern int cx88_core_irq(struct cx88_core *core, u32 status);
+extern void cx88_wakeup(struct cx88_core *core,
+			struct cx88_dmaqueue *q, u32 count);
+extern void cx88_shutdown(struct cx88_core *core);
+extern int cx88_reset(struct cx88_core *core);
+
+extern int
+cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+		 struct scatterlist *sglist,
+		 unsigned int top_offset, unsigned int bottom_offset,
+		 unsigned int bpl, unsigned int padding, unsigned int lines);
+extern int
+cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+		     struct scatterlist *sglist, unsigned int bpl,
+		     unsigned int lines, unsigned int lpi);
+extern int
+cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+		  u32 reg, u32 mask, u32 value);
+extern void
+cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf);
+
+extern void cx88_risc_disasm(struct cx88_core *core,
+			     struct btcx_riscmem *risc);
+extern int cx88_sram_channel_setup(struct cx88_core *core,
+				   const struct sram_channel *ch,
+				   unsigned int bpl, u32 risc);
+extern void cx88_sram_channel_dump(struct cx88_core *core,
+				   const struct sram_channel *ch);
+
+extern int cx88_set_scale(struct cx88_core *core, unsigned int width,
+			  unsigned int height, enum v4l2_field field);
+extern int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm);
+
+extern struct video_device *cx88_vdev_init(struct cx88_core *core,
+					   struct pci_dev *pci,
+					   const struct video_device *template_,
+					   const char *type);
+extern struct cx88_core* cx88_core_get(struct pci_dev *pci);
+extern void cx88_core_put(struct cx88_core *core,
+			  struct pci_dev *pci);
+
+extern int cx88_start_audio_dma(struct cx88_core *core);
+extern int cx88_stop_audio_dma(struct cx88_core *core);
+
+
+/* ----------------------------------------------------------- */
+/* cx88-vbi.c                                                  */
+
+/* Can be used as g_vbi_fmt, try_vbi_fmt and s_vbi_fmt */
+int cx8800_vbi_fmt (struct file *file, void *priv,
+					struct v4l2_format *f);
+
+/*
+int cx8800_start_vbi_dma(struct cx8800_dev    *dev,
+			 struct cx88_dmaqueue *q,
+			 struct cx88_buffer   *buf);
+*/
+int cx8800_stop_vbi_dma(struct cx8800_dev *dev);
+int cx8800_restart_vbi_queue(struct cx8800_dev    *dev,
+			     struct cx88_dmaqueue *q);
+void cx8800_vbi_timeout(unsigned long data);
+
+extern const struct videobuf_queue_ops cx8800_vbi_qops;
+
+/* ----------------------------------------------------------- */
+/* cx88-i2c.c                                                  */
+
+extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci);
+
+
+/* ----------------------------------------------------------- */
+/* cx88-cards.c                                                */
+
+extern int cx88_tuner_callback(void *dev, int component, int command, int arg);
+extern int cx88_get_resources(const struct cx88_core *core,
+			      struct pci_dev *pci);
+extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr);
+extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl);
+
+/* ----------------------------------------------------------- */
+/* cx88-tvaudio.c                                              */
+
+void cx88_set_tvaudio(struct cx88_core *core);
+void cx88_newstation(struct cx88_core *core);
+void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t);
+void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual);
+int cx88_audio_thread(void *data);
+
+int cx8802_register_driver(struct cx8802_driver *drv);
+int cx8802_unregister_driver(struct cx8802_driver *drv);
+
+/* Caller must hold core->lock */
+struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype);
+
+/* ----------------------------------------------------------- */
+/* cx88-dsp.c                                                  */
+
+s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core);
+
+/* ----------------------------------------------------------- */
+/* cx88-input.c                                                */
+
+int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci);
+int cx88_ir_fini(struct cx88_core *core);
+void cx88_ir_irq(struct cx88_core *core);
+int cx88_ir_start(struct cx88_core *core);
+void cx88_ir_stop(struct cx88_core *core);
+extern void cx88_i2c_init_ir(struct cx88_core *core);
+
+/* ----------------------------------------------------------- */
+/* cx88-mpeg.c                                                 */
+
+int cx8802_buf_prepare(struct videobuf_queue *q,struct cx8802_dev *dev,
+			struct cx88_buffer *buf, enum v4l2_field field);
+void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf);
+void cx8802_cancel_buffers(struct cx8802_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* cx88-video.c*/
+int cx88_enum_input (struct cx88_core  *core,struct v4l2_input *i);
+int cx88_set_freq (struct cx88_core  *core,struct v4l2_frequency *f);
+int cx88_video_mux(struct cx88_core *core, unsigned int input);
+void cx88_querycap(struct file *file, struct cx88_core *core,
+		struct v4l2_capability *cap);
diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig
new file mode 100644
index 0000000..d099e1a
--- /dev/null
+++ b/drivers/media/pci/ddbridge/Kconfig
@@ -0,0 +1,18 @@
+config DVB_DDBRIDGE
+	tristate "Digital Devices bridge support"
+	depends on DVB_CORE && PCI && I2C
+	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+	select DVB_STV6110x if !DVB_FE_CUSTOMISE
+	select DVB_STV090x if !DVB_FE_CUSTOMISE
+	select DVB_DRXK if !DVB_FE_CUSTOMISE
+	select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE
+	---help---
+	  Support for cards with the Digital Devices PCI express bridge:
+	  - Octopus PCIe Bridge
+	  - Octopus mini PCIe Bridge
+	  - Octopus LE
+	  - DuoFlex S2 Octopus
+	  - DuoFlex CT Octopus
+	  - cineS2(v6)
+
+	  Say Y if you own such a card and want to use it.
diff --git a/drivers/media/pci/ddbridge/Makefile b/drivers/media/pci/ddbridge/Makefile
new file mode 100644
index 0000000..7446c8b
--- /dev/null
+++ b/drivers/media/pci/ddbridge/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for the ddbridge device driver
+#
+
+ddbridge-objs := ddbridge-core.o
+
+obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
+
+ccflags-y += -Idrivers/media/dvb-core/
+ccflags-y += -Idrivers/media/dvb-frontends/
+ccflags-y += -Idrivers/media/tuners/
+
+# For the staging CI driver cxd2099
+ccflags-y += -Idrivers/staging/media/cxd2099/
diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
new file mode 100644
index 0000000..ebf3f05
--- /dev/null
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -0,0 +1,1723 @@
+/*
+ * ddbridge.c: Digital Devices PCIe bridge driver
+ *
+ * Copyright (C) 2010-2011 Digital Devices GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/io.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/timer.h>
+#include <linux/i2c.h>
+#include <linux/swab.h>
+#include <linux/vmalloc.h>
+#include "ddbridge.h"
+
+#include "ddbridge-regs.h"
+
+#include "tda18271c2dd.h"
+#include "stv6110x.h"
+#include "stv090x.h"
+#include "lnbh24.h"
+#include "drxk.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* MSI had problems with lost interrupts, fixed but needs testing */
+#undef CONFIG_PCI_MSI
+
+/******************************************************************************/
+
+static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
+{
+	struct i2c_msg msgs[1] = {{.addr = adr,  .flags = I2C_M_RD,
+				   .buf  = val,  .len   = 1 } };
+	return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
+}
+
+static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val)
+{
+	struct i2c_msg msgs[2] = {{.addr = adr,  .flags = 0,
+				   .buf  = &reg, .len   = 1 },
+				  {.addr = adr,  .flags = I2C_M_RD,
+				   .buf  = val,  .len   = 1 } };
+	return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
+}
+
+static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
+			  u16 reg, u8 *val)
+{
+	u8 msg[2] = {reg>>8, reg&0xff};
+	struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
+				   .buf  = msg, .len   = 2},
+				  {.addr = adr, .flags = I2C_M_RD,
+				   .buf  = val, .len   = 1} };
+	return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
+}
+
+static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
+{
+	struct ddb *dev = i2c->dev;
+	int stat;
+	u32 val;
+
+	i2c->done = 0;
+	ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND);
+	stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ);
+	if (stat <= 0) {
+		printk(KERN_ERR "I2C timeout\n");
+		{ /* MSI debugging*/
+			u32 istat = ddbreadl(INTERRUPT_STATUS);
+			printk(KERN_ERR "IRS %08x\n", istat);
+			ddbwritel(istat, INTERRUPT_ACK);
+		}
+		return -EIO;
+	}
+	val = ddbreadl(i2c->regs+I2C_COMMAND);
+	if (val & 0x70000)
+		return -EIO;
+	return 0;
+}
+
+static int ddb_i2c_master_xfer(struct i2c_adapter *adapter,
+			       struct i2c_msg msg[], int num)
+{
+	struct ddb_i2c *i2c = (struct ddb_i2c *)i2c_get_adapdata(adapter);
+	struct ddb *dev = i2c->dev;
+	u8 addr = 0;
+
+	if (num)
+		addr = msg[0].addr;
+
+	if (num == 2 && msg[1].flags & I2C_M_RD &&
+	    !(msg[0].flags & I2C_M_RD)) {
+		memcpy_toio(dev->regs + I2C_TASKMEM_BASE + i2c->wbuf,
+			    msg[0].buf, msg[0].len);
+		ddbwritel(msg[0].len|(msg[1].len << 16),
+			  i2c->regs+I2C_TASKLENGTH);
+		if (!ddb_i2c_cmd(i2c, addr, 1)) {
+			memcpy_fromio(msg[1].buf,
+				      dev->regs + I2C_TASKMEM_BASE + i2c->rbuf,
+				      msg[1].len);
+			return num;
+		}
+	}
+
+	if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
+		ddbcpyto(I2C_TASKMEM_BASE + i2c->wbuf, msg[0].buf, msg[0].len);
+		ddbwritel(msg[0].len, i2c->regs + I2C_TASKLENGTH);
+		if (!ddb_i2c_cmd(i2c, addr, 2))
+			return num;
+	}
+	if (num == 1 && (msg[0].flags & I2C_M_RD)) {
+		ddbwritel(msg[0].len << 16, i2c->regs + I2C_TASKLENGTH);
+		if (!ddb_i2c_cmd(i2c, addr, 3)) {
+			ddbcpyfrom(msg[0].buf,
+				   I2C_TASKMEM_BASE + i2c->rbuf, msg[0].len);
+			return num;
+		}
+	}
+	return -EIO;
+}
+
+
+static u32 ddb_i2c_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL;
+}
+
+struct i2c_algorithm ddb_i2c_algo = {
+	.master_xfer   = ddb_i2c_master_xfer,
+	.functionality = ddb_i2c_functionality,
+};
+
+static void ddb_i2c_release(struct ddb *dev)
+{
+	int i;
+	struct ddb_i2c *i2c;
+	struct i2c_adapter *adap;
+
+	for (i = 0; i < dev->info->port_num; i++) {
+		i2c = &dev->i2c[i];
+		adap = &i2c->adap;
+		i2c_del_adapter(adap);
+	}
+}
+
+static int ddb_i2c_init(struct ddb *dev)
+{
+	int i, j, stat = 0;
+	struct ddb_i2c *i2c;
+	struct i2c_adapter *adap;
+
+	for (i = 0; i < dev->info->port_num; i++) {
+		i2c = &dev->i2c[i];
+		i2c->dev = dev;
+		i2c->nr = i;
+		i2c->wbuf = i * (I2C_TASKMEM_SIZE / 4);
+		i2c->rbuf = i2c->wbuf + (I2C_TASKMEM_SIZE / 8);
+		i2c->regs = 0x80 + i * 0x20;
+		ddbwritel(I2C_SPEED_100, i2c->regs + I2C_TIMING);
+		ddbwritel((i2c->rbuf << 16) | i2c->wbuf,
+			  i2c->regs + I2C_TASKADDRESS);
+		init_waitqueue_head(&i2c->wq);
+
+		adap = &i2c->adap;
+		i2c_set_adapdata(adap, i2c);
+#ifdef I2C_ADAP_CLASS_TV_DIGITAL
+		adap->class = I2C_ADAP_CLASS_TV_DIGITAL|I2C_CLASS_TV_ANALOG;
+#else
+#ifdef I2C_CLASS_TV_ANALOG
+		adap->class = I2C_CLASS_TV_ANALOG;
+#endif
+#endif
+		strcpy(adap->name, "ddbridge");
+		adap->algo = &ddb_i2c_algo;
+		adap->algo_data = (void *)i2c;
+		adap->dev.parent = &dev->pdev->dev;
+		stat = i2c_add_adapter(adap);
+		if (stat)
+			break;
+	}
+	if (stat)
+		for (j = 0; j < i; j++) {
+			i2c = &dev->i2c[j];
+			adap = &i2c->adap;
+			i2c_del_adapter(adap);
+		}
+	return stat;
+}
+
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+
+#if 0
+static void set_table(struct ddb *dev, u32 off,
+		      dma_addr_t *pbuf, u32 num)
+{
+	u32 i, base;
+	u64 mem;
+
+	base = DMA_BASE_ADDRESS_TABLE + off;
+	for (i = 0; i < num; i++) {
+		mem = pbuf[i];
+		ddbwritel(mem & 0xffffffff, base + i * 8);
+		ddbwritel(mem >> 32, base + i * 8 + 4);
+	}
+}
+#endif
+
+static void ddb_address_table(struct ddb *dev)
+{
+	u32 i, j, base;
+	u64 mem;
+	dma_addr_t *pbuf;
+
+	for (i = 0; i < dev->info->port_num * 2; i++) {
+		base = DMA_BASE_ADDRESS_TABLE + i * 0x100;
+		pbuf = dev->input[i].pbuf;
+		for (j = 0; j < dev->input[i].dma_buf_num; j++) {
+			mem = pbuf[j];
+			ddbwritel(mem & 0xffffffff, base + j * 8);
+			ddbwritel(mem >> 32, base + j * 8 + 4);
+		}
+	}
+	for (i = 0; i < dev->info->port_num; i++) {
+		base = DMA_BASE_ADDRESS_TABLE + 0x800 + i * 0x100;
+		pbuf = dev->output[i].pbuf;
+		for (j = 0; j < dev->output[i].dma_buf_num; j++) {
+			mem = pbuf[j];
+			ddbwritel(mem & 0xffffffff, base + j * 8);
+			ddbwritel(mem >> 32, base + j * 8 + 4);
+		}
+	}
+}
+
+static void io_free(struct pci_dev *pdev, u8 **vbuf,
+		    dma_addr_t *pbuf, u32 size, int num)
+{
+	int i;
+
+	for (i = 0; i < num; i++) {
+		if (vbuf[i]) {
+			pci_free_consistent(pdev, size, vbuf[i], pbuf[i]);
+			vbuf[i] = 0;
+		}
+	}
+}
+
+static int io_alloc(struct pci_dev *pdev, u8 **vbuf,
+		    dma_addr_t *pbuf, u32 size, int num)
+{
+	int i;
+
+	for (i = 0; i < num; i++) {
+		vbuf[i] = pci_alloc_consistent(pdev, size, &pbuf[i]);
+		if (!vbuf[i])
+			return -ENOMEM;
+	}
+	return 0;
+}
+
+static int ddb_buffers_alloc(struct ddb *dev)
+{
+	int i;
+	struct ddb_port *port;
+
+	for (i = 0; i < dev->info->port_num; i++) {
+		port = &dev->port[i];
+		switch (port->class) {
+		case DDB_PORT_TUNER:
+			if (io_alloc(dev->pdev, port->input[0]->vbuf,
+				     port->input[0]->pbuf,
+				     port->input[0]->dma_buf_size,
+				     port->input[0]->dma_buf_num) < 0)
+				return -1;
+			if (io_alloc(dev->pdev, port->input[1]->vbuf,
+				     port->input[1]->pbuf,
+				     port->input[1]->dma_buf_size,
+				     port->input[1]->dma_buf_num) < 0)
+				return -1;
+			break;
+		case DDB_PORT_CI:
+			if (io_alloc(dev->pdev, port->input[0]->vbuf,
+				     port->input[0]->pbuf,
+				     port->input[0]->dma_buf_size,
+				     port->input[0]->dma_buf_num) < 0)
+				return -1;
+			if (io_alloc(dev->pdev, port->output->vbuf,
+				     port->output->pbuf,
+				     port->output->dma_buf_size,
+				     port->output->dma_buf_num) < 0)
+				return -1;
+			break;
+		default:
+			break;
+		}
+	}
+	ddb_address_table(dev);
+	return 0;
+}
+
+static void ddb_buffers_free(struct ddb *dev)
+{
+	int i;
+	struct ddb_port *port;
+
+	for (i = 0; i < dev->info->port_num; i++) {
+		port = &dev->port[i];
+		io_free(dev->pdev, port->input[0]->vbuf,
+			port->input[0]->pbuf,
+			port->input[0]->dma_buf_size,
+			port->input[0]->dma_buf_num);
+		io_free(dev->pdev, port->input[1]->vbuf,
+			port->input[1]->pbuf,
+			port->input[1]->dma_buf_size,
+			port->input[1]->dma_buf_num);
+		io_free(dev->pdev, port->output->vbuf,
+			port->output->pbuf,
+			port->output->dma_buf_size,
+			port->output->dma_buf_num);
+	}
+}
+
+static void ddb_input_start(struct ddb_input *input)
+{
+	struct ddb *dev = input->port->dev;
+
+	spin_lock_irq(&input->lock);
+	input->cbuf = 0;
+	input->coff = 0;
+
+	/* reset */
+	ddbwritel(0, TS_INPUT_CONTROL(input->nr));
+	ddbwritel(2, TS_INPUT_CONTROL(input->nr));
+	ddbwritel(0, TS_INPUT_CONTROL(input->nr));
+
+	ddbwritel((1 << 16) |
+		  (input->dma_buf_num << 11) |
+		  (input->dma_buf_size >> 7),
+		  DMA_BUFFER_SIZE(input->nr));
+	ddbwritel(0, DMA_BUFFER_ACK(input->nr));
+
+	ddbwritel(1, DMA_BASE_WRITE);
+	ddbwritel(3, DMA_BUFFER_CONTROL(input->nr));
+	ddbwritel(9, TS_INPUT_CONTROL(input->nr));
+	input->running = 1;
+	spin_unlock_irq(&input->lock);
+}
+
+static void ddb_input_stop(struct ddb_input *input)
+{
+	struct ddb *dev = input->port->dev;
+
+	spin_lock_irq(&input->lock);
+	ddbwritel(0, TS_INPUT_CONTROL(input->nr));
+	ddbwritel(0, DMA_BUFFER_CONTROL(input->nr));
+	input->running = 0;
+	spin_unlock_irq(&input->lock);
+}
+
+static void ddb_output_start(struct ddb_output *output)
+{
+	struct ddb *dev = output->port->dev;
+
+	spin_lock_irq(&output->lock);
+	output->cbuf = 0;
+	output->coff = 0;
+	ddbwritel(0, TS_OUTPUT_CONTROL(output->nr));
+	ddbwritel(2, TS_OUTPUT_CONTROL(output->nr));
+	ddbwritel(0, TS_OUTPUT_CONTROL(output->nr));
+	ddbwritel(0x3c, TS_OUTPUT_CONTROL(output->nr));
+	ddbwritel((1 << 16) |
+		  (output->dma_buf_num << 11) |
+		  (output->dma_buf_size >> 7),
+		  DMA_BUFFER_SIZE(output->nr + 8));
+	ddbwritel(0, DMA_BUFFER_ACK(output->nr + 8));
+
+	ddbwritel(1, DMA_BASE_READ);
+	ddbwritel(3, DMA_BUFFER_CONTROL(output->nr + 8));
+	/* ddbwritel(0xbd, TS_OUTPUT_CONTROL(output->nr)); */
+	ddbwritel(0x1d, TS_OUTPUT_CONTROL(output->nr));
+	output->running = 1;
+	spin_unlock_irq(&output->lock);
+}
+
+static void ddb_output_stop(struct ddb_output *output)
+{
+	struct ddb *dev = output->port->dev;
+
+	spin_lock_irq(&output->lock);
+	ddbwritel(0, TS_OUTPUT_CONTROL(output->nr));
+	ddbwritel(0, DMA_BUFFER_CONTROL(output->nr + 8));
+	output->running = 0;
+	spin_unlock_irq(&output->lock);
+}
+
+static u32 ddb_output_free(struct ddb_output *output)
+{
+	u32 idx, off, stat = output->stat;
+	s32 diff;
+
+	idx = (stat >> 11) & 0x1f;
+	off = (stat & 0x7ff) << 7;
+
+	if (output->cbuf != idx) {
+		if ((((output->cbuf + 1) % output->dma_buf_num) == idx) &&
+		    (output->dma_buf_size - output->coff <= 188))
+			return 0;
+		return 188;
+	}
+	diff = off - output->coff;
+	if (diff <= 0 || diff > 188)
+		return 188;
+	return 0;
+}
+
+static ssize_t ddb_output_write(struct ddb_output *output,
+				const u8 *buf, size_t count)
+{
+	struct ddb *dev = output->port->dev;
+	u32 idx, off, stat = output->stat;
+	u32 left = count, len;
+
+	idx = (stat >> 11) & 0x1f;
+	off = (stat & 0x7ff) << 7;
+
+	while (left) {
+		len = output->dma_buf_size - output->coff;
+		if ((((output->cbuf + 1) % output->dma_buf_num) == idx) &&
+		    (off == 0)) {
+			if (len <= 188)
+				break;
+			len -= 188;
+		}
+		if (output->cbuf == idx) {
+			if (off > output->coff) {
+#if 1
+				len = off - output->coff;
+				len -= (len % 188);
+				if (len <= 188)
+
+#endif
+					break;
+				len -= 188;
+			}
+		}
+		if (len > left)
+			len = left;
+		if (copy_from_user(output->vbuf[output->cbuf] + output->coff,
+				   buf, len))
+			return -EIO;
+		left -= len;
+		buf += len;
+		output->coff += len;
+		if (output->coff == output->dma_buf_size) {
+			output->coff = 0;
+			output->cbuf = ((output->cbuf + 1) % output->dma_buf_num);
+		}
+		ddbwritel((output->cbuf << 11) | (output->coff >> 7),
+			  DMA_BUFFER_ACK(output->nr + 8));
+	}
+	return count - left;
+}
+
+static u32 ddb_input_avail(struct ddb_input *input)
+{
+	struct ddb *dev = input->port->dev;
+	u32 idx, off, stat = input->stat;
+	u32 ctrl = ddbreadl(DMA_BUFFER_CONTROL(input->nr));
+
+	idx = (stat >> 11) & 0x1f;
+	off = (stat & 0x7ff) << 7;
+
+	if (ctrl & 4) {
+		printk(KERN_ERR "IA %d %d %08x\n", idx, off, ctrl);
+		ddbwritel(input->stat, DMA_BUFFER_ACK(input->nr));
+		return 0;
+	}
+	if (input->cbuf != idx)
+		return 188;
+	return 0;
+}
+
+static ssize_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count)
+{
+	struct ddb *dev = input->port->dev;
+	u32 left = count;
+	u32 idx, free, stat = input->stat;
+	int ret;
+
+	idx = (stat >> 11) & 0x1f;
+
+	while (left) {
+		if (input->cbuf == idx)
+			return count - left;
+		free = input->dma_buf_size - input->coff;
+		if (free > left)
+			free = left;
+		ret = copy_to_user(buf, input->vbuf[input->cbuf] +
+				   input->coff, free);
+		if (ret)
+			return -EFAULT;
+		input->coff += free;
+		if (input->coff == input->dma_buf_size) {
+			input->coff = 0;
+			input->cbuf = (input->cbuf+1) % input->dma_buf_num;
+		}
+		left -= free;
+		ddbwritel((input->cbuf << 11) | (input->coff >> 7),
+			  DMA_BUFFER_ACK(input->nr));
+	}
+	return count;
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+
+#if 0
+static struct ddb_input *fe2input(struct ddb *dev, struct dvb_frontend *fe)
+{
+	int i;
+
+	for (i = 0; i < dev->info->port_num * 2; i++) {
+		if (dev->input[i].fe == fe)
+			return &dev->input[i];
+	}
+	return NULL;
+}
+#endif
+
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct ddb_input *input = fe->sec_priv;
+	struct ddb_port *port = input->port;
+	int status;
+
+	if (enable) {
+		mutex_lock(&port->i2c_gate_lock);
+		status = input->gate_ctrl(fe, 1);
+	} else {
+		status = input->gate_ctrl(fe, 0);
+		mutex_unlock(&port->i2c_gate_lock);
+	}
+	return status;
+}
+
+static int demod_attach_drxk(struct ddb_input *input)
+{
+	struct i2c_adapter *i2c = &input->port->i2c->adap;
+	struct dvb_frontend *fe;
+	struct drxk_config config;
+
+	memset(&config, 0, sizeof(config));
+	config.microcode_name = "drxk_a3.mc";
+	config.qam_demod_parameter_count = 4;
+	config.adr = 0x29 + (input->nr & 1);
+
+	fe = input->fe = dvb_attach(drxk_attach, &config, i2c);
+	if (!input->fe) {
+		printk(KERN_ERR "No DRXK found!\n");
+		return -ENODEV;
+	}
+	fe->sec_priv = input;
+	input->gate_ctrl = fe->ops.i2c_gate_ctrl;
+	fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+	return 0;
+}
+
+static int tuner_attach_tda18271(struct ddb_input *input)
+{
+	struct i2c_adapter *i2c = &input->port->i2c->adap;
+	struct dvb_frontend *fe;
+
+	if (input->fe->ops.i2c_gate_ctrl)
+		input->fe->ops.i2c_gate_ctrl(input->fe, 1);
+	fe = dvb_attach(tda18271c2dd_attach, input->fe, i2c, 0x60);
+	if (!fe) {
+		printk(KERN_ERR "No TDA18271 found!\n");
+		return -ENODEV;
+	}
+	if (input->fe->ops.i2c_gate_ctrl)
+		input->fe->ops.i2c_gate_ctrl(input->fe, 0);
+	return 0;
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+
+static struct stv090x_config stv0900 = {
+	.device         = STV0900,
+	.demod_mode     = STV090x_DUAL,
+	.clk_mode       = STV090x_CLK_EXT,
+
+	.xtal           = 27000000,
+	.address        = 0x69,
+
+	.ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+	.ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+
+	.repeater_level = STV090x_RPTLEVEL_16,
+
+	.adc1_range	= STV090x_ADC_1Vpp,
+	.adc2_range	= STV090x_ADC_1Vpp,
+
+	.diseqc_envelope_mode = true,
+};
+
+static struct stv090x_config stv0900_aa = {
+	.device         = STV0900,
+	.demod_mode     = STV090x_DUAL,
+	.clk_mode       = STV090x_CLK_EXT,
+
+	.xtal           = 27000000,
+	.address        = 0x68,
+
+	.ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+	.ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+
+	.repeater_level = STV090x_RPTLEVEL_16,
+
+	.adc1_range	= STV090x_ADC_1Vpp,
+	.adc2_range	= STV090x_ADC_1Vpp,
+
+	.diseqc_envelope_mode = true,
+};
+
+static struct stv6110x_config stv6110a = {
+	.addr    = 0x60,
+	.refclk	 = 27000000,
+	.clk_div = 1,
+};
+
+static struct stv6110x_config stv6110b = {
+	.addr    = 0x63,
+	.refclk	 = 27000000,
+	.clk_div = 1,
+};
+
+static int demod_attach_stv0900(struct ddb_input *input, int type)
+{
+	struct i2c_adapter *i2c = &input->port->i2c->adap;
+	struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900;
+
+	input->fe = dvb_attach(stv090x_attach, feconf, i2c,
+			       (input->nr & 1) ? STV090x_DEMODULATOR_1
+			       : STV090x_DEMODULATOR_0);
+	if (!input->fe) {
+		printk(KERN_ERR "No STV0900 found!\n");
+		return -ENODEV;
+	}
+	if (!dvb_attach(lnbh24_attach, input->fe, i2c, 0,
+			0, (input->nr & 1) ?
+			(0x09 - type) : (0x0b - type))) {
+		printk(KERN_ERR "No LNBH24 found!\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int tuner_attach_stv6110(struct ddb_input *input, int type)
+{
+	struct i2c_adapter *i2c = &input->port->i2c->adap;
+	struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900;
+	struct stv6110x_config *tunerconf = (input->nr & 1) ?
+		&stv6110b : &stv6110a;
+	struct stv6110x_devctl *ctl;
+
+	ctl = dvb_attach(stv6110x_attach, input->fe, tunerconf, i2c);
+	if (!ctl) {
+		printk(KERN_ERR "No STV6110X found!\n");
+		return -ENODEV;
+	}
+	printk(KERN_INFO "attach tuner input %d adr %02x\n",
+			 input->nr, tunerconf->addr);
+
+	feconf->tuner_init          = ctl->tuner_init;
+	feconf->tuner_sleep         = ctl->tuner_sleep;
+	feconf->tuner_set_mode      = ctl->tuner_set_mode;
+	feconf->tuner_set_frequency = ctl->tuner_set_frequency;
+	feconf->tuner_get_frequency = ctl->tuner_get_frequency;
+	feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+	feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+	feconf->tuner_set_bbgain    = ctl->tuner_set_bbgain;
+	feconf->tuner_get_bbgain    = ctl->tuner_get_bbgain;
+	feconf->tuner_set_refclk    = ctl->tuner_set_refclk;
+	feconf->tuner_get_status    = ctl->tuner_get_status;
+
+	return 0;
+}
+
+static int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
+			    int (*start_feed)(struct dvb_demux_feed *),
+			    int (*stop_feed)(struct dvb_demux_feed *),
+			    void *priv)
+{
+	dvbdemux->priv = priv;
+
+	dvbdemux->filternum = 256;
+	dvbdemux->feednum = 256;
+	dvbdemux->start_feed = start_feed;
+	dvbdemux->stop_feed = stop_feed;
+	dvbdemux->write_to_decoder = NULL;
+	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+				      DMX_SECTION_FILTERING |
+				      DMX_MEMORY_BASED_FILTERING);
+	return dvb_dmx_init(dvbdemux);
+}
+
+static int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
+			       struct dvb_demux *dvbdemux,
+			       struct dmx_frontend *hw_frontend,
+			       struct dmx_frontend *mem_frontend,
+			       struct dvb_adapter *dvb_adapter)
+{
+	int ret;
+
+	dmxdev->filternum = 256;
+	dmxdev->demux = &dvbdemux->dmx;
+	dmxdev->capabilities = 0;
+	ret = dvb_dmxdev_init(dmxdev, dvb_adapter);
+	if (ret < 0)
+		return ret;
+
+	hw_frontend->source = DMX_FRONTEND_0;
+	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend);
+	mem_frontend->source = DMX_MEMORY_FE;
+	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend);
+	return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend);
+}
+
+static int start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct ddb_input *input = dvbdmx->priv;
+
+	if (!input->users)
+		ddb_input_start(input);
+
+	return ++input->users;
+}
+
+static int stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct ddb_input *input = dvbdmx->priv;
+
+	if (--input->users)
+		return input->users;
+
+	ddb_input_stop(input);
+	return 0;
+}
+
+
+static void dvb_input_detach(struct ddb_input *input)
+{
+	struct dvb_adapter *adap = &input->adap;
+	struct dvb_demux *dvbdemux = &input->demux;
+
+	switch (input->attached) {
+	case 5:
+		if (input->fe2)
+			dvb_unregister_frontend(input->fe2);
+		if (input->fe) {
+			dvb_unregister_frontend(input->fe);
+			dvb_frontend_detach(input->fe);
+			input->fe = NULL;
+		}
+	case 4:
+		dvb_net_release(&input->dvbnet);
+
+	case 3:
+		dvbdemux->dmx.close(&dvbdemux->dmx);
+		dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
+					      &input->hw_frontend);
+		dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
+					      &input->mem_frontend);
+		dvb_dmxdev_release(&input->dmxdev);
+
+	case 2:
+		dvb_dmx_release(&input->demux);
+
+	case 1:
+		dvb_unregister_adapter(adap);
+	}
+	input->attached = 0;
+}
+
+static int dvb_input_attach(struct ddb_input *input)
+{
+	int ret;
+	struct ddb_port *port = input->port;
+	struct dvb_adapter *adap = &input->adap;
+	struct dvb_demux *dvbdemux = &input->demux;
+
+	ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE,
+				   &input->port->dev->pdev->dev,
+				   adapter_nr);
+	if (ret < 0) {
+		printk(KERN_ERR "ddbridge: Could not register adapter."
+		       "Check if you enabled enough adapters in dvb-core!\n");
+		return ret;
+	}
+	input->attached = 1;
+
+	ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux",
+				      start_feed,
+				      stop_feed, input);
+	if (ret < 0)
+		return ret;
+	input->attached = 2;
+
+	ret = my_dvb_dmxdev_ts_card_init(&input->dmxdev, &input->demux,
+					 &input->hw_frontend,
+					 &input->mem_frontend, adap);
+	if (ret < 0)
+		return ret;
+	input->attached = 3;
+
+	ret = dvb_net_init(adap, &input->dvbnet, input->dmxdev.demux);
+	if (ret < 0)
+		return ret;
+	input->attached = 4;
+
+	input->fe = 0;
+	switch (port->type) {
+	case DDB_TUNER_DVBS_ST:
+		if (demod_attach_stv0900(input, 0) < 0)
+			return -ENODEV;
+		if (tuner_attach_stv6110(input, 0) < 0)
+			return -ENODEV;
+		if (input->fe) {
+			if (dvb_register_frontend(adap, input->fe) < 0)
+				return -ENODEV;
+		}
+		break;
+	case DDB_TUNER_DVBS_ST_AA:
+		if (demod_attach_stv0900(input, 1) < 0)
+			return -ENODEV;
+		if (tuner_attach_stv6110(input, 1) < 0)
+			return -ENODEV;
+		if (input->fe) {
+			if (dvb_register_frontend(adap, input->fe) < 0)
+				return -ENODEV;
+		}
+		break;
+	case DDB_TUNER_DVBCT_TR:
+		if (demod_attach_drxk(input) < 0)
+			return -ENODEV;
+		if (tuner_attach_tda18271(input) < 0)
+			return -ENODEV;
+		if (input->fe) {
+			if (dvb_register_frontend(adap, input->fe) < 0)
+				return -ENODEV;
+		}
+		if (input->fe2) {
+			if (dvb_register_frontend(adap, input->fe2) < 0)
+				return -ENODEV;
+			input->fe2->tuner_priv = input->fe->tuner_priv;
+			memcpy(&input->fe2->ops.tuner_ops,
+			       &input->fe->ops.tuner_ops,
+			       sizeof(struct dvb_tuner_ops));
+		}
+		break;
+	}
+	input->attached = 5;
+	return 0;
+}
+
+/****************************************************************************/
+/****************************************************************************/
+
+static ssize_t ts_write(struct file *file, const char *buf,
+			size_t count, loff_t *ppos)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct ddb_output *output = dvbdev->priv;
+	size_t left = count;
+	int stat;
+
+	while (left) {
+		if (ddb_output_free(output) < 188) {
+			if (file->f_flags & O_NONBLOCK)
+				break;
+			if (wait_event_interruptible(
+				    output->wq, ddb_output_free(output) >= 188) < 0)
+				break;
+		}
+		stat = ddb_output_write(output, buf, left);
+		if (stat < 0)
+			break;
+		buf += stat;
+		left -= stat;
+	}
+	return (left == count) ? -EAGAIN : (count - left);
+}
+
+static ssize_t ts_read(struct file *file, char *buf,
+		       size_t count, loff_t *ppos)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct ddb_output *output = dvbdev->priv;
+	struct ddb_input *input = output->port->input[0];
+	int left, read;
+
+	count -= count % 188;
+	left = count;
+	while (left) {
+		if (ddb_input_avail(input) < 188) {
+			if (file->f_flags & O_NONBLOCK)
+				break;
+			if (wait_event_interruptible(
+				    input->wq, ddb_input_avail(input) >= 188) < 0)
+				break;
+		}
+		read = ddb_input_read(input, buf, left);
+		if (read < 0)
+			return read;
+		left -= read;
+		buf += read;
+	}
+	return (left == count) ? -EAGAIN : (count - left);
+}
+
+static unsigned int ts_poll(struct file *file, poll_table *wait)
+{
+	/*
+	struct dvb_device *dvbdev = file->private_data;
+	struct ddb_output *output = dvbdev->priv;
+	struct ddb_input *input = output->port->input[0];
+	*/
+	unsigned int mask = 0;
+
+#if 0
+	if (data_avail_to_read)
+		mask |= POLLIN | POLLRDNORM;
+	if (data_avail_to_write)
+		mask |= POLLOUT | POLLWRNORM;
+
+	poll_wait(file, &read_queue, wait);
+	poll_wait(file, &write_queue, wait);
+#endif
+	return mask;
+}
+
+static const struct file_operations ci_fops = {
+	.owner   = THIS_MODULE,
+	.read    = ts_read,
+	.write   = ts_write,
+	.open    = dvb_generic_open,
+	.release = dvb_generic_release,
+	.poll    = ts_poll,
+	.mmap    = 0,
+};
+
+static struct dvb_device dvbdev_ci = {
+	.priv    = 0,
+	.readers = -1,
+	.writers = -1,
+	.users   = -1,
+	.fops    = &ci_fops,
+};
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static void input_tasklet(unsigned long data)
+{
+	struct ddb_input *input = (struct ddb_input *) data;
+	struct ddb *dev = input->port->dev;
+
+	spin_lock(&input->lock);
+	if (!input->running) {
+		spin_unlock(&input->lock);
+		return;
+	}
+	input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr));
+
+	if (input->port->class == DDB_PORT_TUNER) {
+		if (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr)))
+			printk(KERN_ERR "Overflow input %d\n", input->nr);
+		while (input->cbuf != ((input->stat >> 11) & 0x1f)
+		       || (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr)))) {
+			dvb_dmx_swfilter_packets(&input->demux,
+						 input->vbuf[input->cbuf],
+						 input->dma_buf_size / 188);
+
+			input->cbuf = (input->cbuf + 1) % input->dma_buf_num;
+			ddbwritel((input->cbuf << 11),
+				  DMA_BUFFER_ACK(input->nr));
+			input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr));
+		       }
+	}
+	if (input->port->class == DDB_PORT_CI)
+		wake_up(&input->wq);
+	spin_unlock(&input->lock);
+}
+
+static void output_tasklet(unsigned long data)
+{
+	struct ddb_output *output = (struct ddb_output *) data;
+	struct ddb *dev = output->port->dev;
+
+	spin_lock(&output->lock);
+	if (!output->running) {
+		spin_unlock(&output->lock);
+		return;
+	}
+	output->stat = ddbreadl(DMA_BUFFER_CURRENT(output->nr + 8));
+	wake_up(&output->wq);
+	spin_unlock(&output->lock);
+}
+
+
+struct cxd2099_cfg cxd_cfg = {
+	.bitrate =  62000,
+	.adr     =  0x40,
+	.polarity = 1,
+	.clock_mode = 1,
+};
+
+static int ddb_ci_attach(struct ddb_port *port)
+{
+	int ret;
+
+	ret = dvb_register_adapter(&port->output->adap,
+				   "DDBridge",
+				   THIS_MODULE,
+				   &port->dev->pdev->dev,
+				   adapter_nr);
+	if (ret < 0)
+		return ret;
+	port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap);
+	if (!port->en) {
+		dvb_unregister_adapter(&port->output->adap);
+		return -ENODEV;
+	}
+	ddb_input_start(port->input[0]);
+	ddb_output_start(port->output);
+	dvb_ca_en50221_init(&port->output->adap,
+			    port->en, 0, 1);
+	ret = dvb_register_device(&port->output->adap, &port->output->dev,
+				  &dvbdev_ci, (void *) port->output,
+				  DVB_DEVICE_SEC);
+	return ret;
+}
+
+static int ddb_port_attach(struct ddb_port *port)
+{
+	int ret = 0;
+
+	switch (port->class) {
+	case DDB_PORT_TUNER:
+		ret = dvb_input_attach(port->input[0]);
+		if (ret < 0)
+			break;
+		ret = dvb_input_attach(port->input[1]);
+		break;
+	case DDB_PORT_CI:
+		ret = ddb_ci_attach(port);
+		break;
+	default:
+		break;
+	}
+	if (ret < 0)
+		printk(KERN_ERR "port_attach on port %d failed\n", port->nr);
+	return ret;
+}
+
+static int ddb_ports_attach(struct ddb *dev)
+{
+	int i, ret = 0;
+	struct ddb_port *port;
+
+	for (i = 0; i < dev->info->port_num; i++) {
+		port = &dev->port[i];
+		ret = ddb_port_attach(port);
+		if (ret < 0)
+			break;
+	}
+	return ret;
+}
+
+static void ddb_ports_detach(struct ddb *dev)
+{
+	int i;
+	struct ddb_port *port;
+
+	for (i = 0; i < dev->info->port_num; i++) {
+		port = &dev->port[i];
+		switch (port->class) {
+		case DDB_PORT_TUNER:
+			dvb_input_detach(port->input[0]);
+			dvb_input_detach(port->input[1]);
+			break;
+		case DDB_PORT_CI:
+			if (port->output->dev)
+				dvb_unregister_device(port->output->dev);
+			if (port->en) {
+				ddb_input_stop(port->input[0]);
+				ddb_output_stop(port->output);
+				dvb_ca_en50221_release(port->en);
+				kfree(port->en);
+				port->en = 0;
+				dvb_unregister_adapter(&port->output->adap);
+			}
+			break;
+		}
+	}
+}
+
+/****************************************************************************/
+/****************************************************************************/
+
+static int port_has_ci(struct ddb_port *port)
+{
+	u8 val;
+	return i2c_read_reg(&port->i2c->adap, 0x40, 0, &val) ? 0 : 1;
+}
+
+static int port_has_stv0900(struct ddb_port *port)
+{
+	u8 val;
+	if (i2c_read_reg16(&port->i2c->adap, 0x69, 0xf100, &val) < 0)
+		return 0;
+	return 1;
+}
+
+static int port_has_stv0900_aa(struct ddb_port *port)
+{
+	u8 val;
+	if (i2c_read_reg16(&port->i2c->adap, 0x68, 0xf100, &val) < 0)
+		return 0;
+	return 1;
+}
+
+static int port_has_drxks(struct ddb_port *port)
+{
+	u8 val;
+	if (i2c_read(&port->i2c->adap, 0x29, &val) < 0)
+		return 0;
+	if (i2c_read(&port->i2c->adap, 0x2a, &val) < 0)
+		return 0;
+	return 1;
+}
+
+static void ddb_port_probe(struct ddb_port *port)
+{
+	struct ddb *dev = port->dev;
+	char *modname = "NO MODULE";
+
+	port->class = DDB_PORT_NONE;
+
+	if (port_has_ci(port)) {
+		modname = "CI";
+		port->class = DDB_PORT_CI;
+		ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
+	} else if (port_has_stv0900(port)) {
+		modname = "DUAL DVB-S2";
+		port->class = DDB_PORT_TUNER;
+		port->type = DDB_TUNER_DVBS_ST;
+		ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING);
+	} else if (port_has_stv0900_aa(port)) {
+		modname = "DUAL DVB-S2";
+		port->class = DDB_PORT_TUNER;
+		port->type = DDB_TUNER_DVBS_ST_AA;
+		ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING);
+	} else if (port_has_drxks(port)) {
+		modname = "DUAL DVB-C/T";
+		port->class = DDB_PORT_TUNER;
+		port->type = DDB_TUNER_DVBCT_TR;
+		ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
+	}
+	printk(KERN_INFO "Port %d (TAB %d): %s\n",
+			 port->nr, port->nr+1, modname);
+}
+
+static void ddb_input_init(struct ddb_port *port, int nr)
+{
+	struct ddb *dev = port->dev;
+	struct ddb_input *input = &dev->input[nr];
+
+	input->nr = nr;
+	input->port = port;
+	input->dma_buf_num = INPUT_DMA_BUFS;
+	input->dma_buf_size = INPUT_DMA_SIZE;
+	ddbwritel(0, TS_INPUT_CONTROL(nr));
+	ddbwritel(2, TS_INPUT_CONTROL(nr));
+	ddbwritel(0, TS_INPUT_CONTROL(nr));
+	ddbwritel(0, DMA_BUFFER_ACK(nr));
+	tasklet_init(&input->tasklet, input_tasklet, (unsigned long) input);
+	spin_lock_init(&input->lock);
+	init_waitqueue_head(&input->wq);
+}
+
+static void ddb_output_init(struct ddb_port *port, int nr)
+{
+	struct ddb *dev = port->dev;
+	struct ddb_output *output = &dev->output[nr];
+	output->nr = nr;
+	output->port = port;
+	output->dma_buf_num = OUTPUT_DMA_BUFS;
+	output->dma_buf_size = OUTPUT_DMA_SIZE;
+
+	ddbwritel(0, TS_OUTPUT_CONTROL(nr));
+	ddbwritel(2, TS_OUTPUT_CONTROL(nr));
+	ddbwritel(0, TS_OUTPUT_CONTROL(nr));
+	tasklet_init(&output->tasklet, output_tasklet, (unsigned long) output);
+	init_waitqueue_head(&output->wq);
+}
+
+static void ddb_ports_init(struct ddb *dev)
+{
+	int i;
+	struct ddb_port *port;
+
+	for (i = 0; i < dev->info->port_num; i++) {
+		port = &dev->port[i];
+		port->dev = dev;
+		port->nr = i;
+		port->i2c = &dev->i2c[i];
+		port->input[0] = &dev->input[2 * i];
+		port->input[1] = &dev->input[2 * i + 1];
+		port->output = &dev->output[i];
+
+		mutex_init(&port->i2c_gate_lock);
+		ddb_port_probe(port);
+		ddb_input_init(port, 2 * i);
+		ddb_input_init(port, 2 * i + 1);
+		ddb_output_init(port, i);
+	}
+}
+
+static void ddb_ports_release(struct ddb *dev)
+{
+	int i;
+	struct ddb_port *port;
+
+	for (i = 0; i < dev->info->port_num; i++) {
+		port = &dev->port[i];
+		port->dev = dev;
+		tasklet_kill(&port->input[0]->tasklet);
+		tasklet_kill(&port->input[1]->tasklet);
+		tasklet_kill(&port->output->tasklet);
+	}
+}
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static void irq_handle_i2c(struct ddb *dev, int n)
+{
+	struct ddb_i2c *i2c = &dev->i2c[n];
+
+	i2c->done = 1;
+	wake_up(&i2c->wq);
+}
+
+static irqreturn_t irq_handler(int irq, void *dev_id)
+{
+	struct ddb *dev = (struct ddb *) dev_id;
+	u32 s = ddbreadl(INTERRUPT_STATUS);
+
+	if (!s)
+		return IRQ_NONE;
+
+	do {
+		ddbwritel(s, INTERRUPT_ACK);
+
+		if (s & 0x00000001)
+			irq_handle_i2c(dev, 0);
+		if (s & 0x00000002)
+			irq_handle_i2c(dev, 1);
+		if (s & 0x00000004)
+			irq_handle_i2c(dev, 2);
+		if (s & 0x00000008)
+			irq_handle_i2c(dev, 3);
+
+		if (s & 0x00000100)
+			tasklet_schedule(&dev->input[0].tasklet);
+		if (s & 0x00000200)
+			tasklet_schedule(&dev->input[1].tasklet);
+		if (s & 0x00000400)
+			tasklet_schedule(&dev->input[2].tasklet);
+		if (s & 0x00000800)
+			tasklet_schedule(&dev->input[3].tasklet);
+		if (s & 0x00001000)
+			tasklet_schedule(&dev->input[4].tasklet);
+		if (s & 0x00002000)
+			tasklet_schedule(&dev->input[5].tasklet);
+		if (s & 0x00004000)
+			tasklet_schedule(&dev->input[6].tasklet);
+		if (s & 0x00008000)
+			tasklet_schedule(&dev->input[7].tasklet);
+
+		if (s & 0x00010000)
+			tasklet_schedule(&dev->output[0].tasklet);
+		if (s & 0x00020000)
+			tasklet_schedule(&dev->output[1].tasklet);
+		if (s & 0x00040000)
+			tasklet_schedule(&dev->output[2].tasklet);
+		if (s & 0x00080000)
+			tasklet_schedule(&dev->output[3].tasklet);
+
+		/* if (s & 0x000f0000)	printk(KERN_DEBUG "%08x\n", istat); */
+	} while ((s = ddbreadl(INTERRUPT_STATUS)));
+
+	return IRQ_HANDLED;
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+
+static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen)
+{
+	u32 data, shift;
+
+	if (wlen > 4)
+		ddbwritel(1, SPI_CONTROL);
+	while (wlen > 4) {
+		/* FIXME: check for big-endian */
+		data = swab32(*(u32 *)wbuf);
+		wbuf += 4;
+		wlen -= 4;
+		ddbwritel(data, SPI_DATA);
+		while (ddbreadl(SPI_CONTROL) & 0x0004)
+			;
+	}
+
+	if (rlen)
+		ddbwritel(0x0001 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL);
+	else
+		ddbwritel(0x0003 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL);
+
+	data = 0;
+	shift = ((4 - wlen) * 8);
+	while (wlen) {
+		data <<= 8;
+		data |= *wbuf;
+		wlen--;
+		wbuf++;
+	}
+	if (shift)
+		data <<= shift;
+	ddbwritel(data, SPI_DATA);
+	while (ddbreadl(SPI_CONTROL) & 0x0004)
+		;
+
+	if (!rlen) {
+		ddbwritel(0, SPI_CONTROL);
+		return 0;
+	}
+	if (rlen > 4)
+		ddbwritel(1, SPI_CONTROL);
+
+	while (rlen > 4) {
+		ddbwritel(0xffffffff, SPI_DATA);
+		while (ddbreadl(SPI_CONTROL) & 0x0004)
+			;
+		data = ddbreadl(SPI_DATA);
+		*(u32 *) rbuf = swab32(data);
+		rbuf += 4;
+		rlen -= 4;
+	}
+	ddbwritel(0x0003 | ((rlen << (8 + 3)) & 0x1F00), SPI_CONTROL);
+	ddbwritel(0xffffffff, SPI_DATA);
+	while (ddbreadl(SPI_CONTROL) & 0x0004)
+		;
+
+	data = ddbreadl(SPI_DATA);
+	ddbwritel(0, SPI_CONTROL);
+
+	if (rlen < 4)
+		data <<= ((4 - rlen) * 8);
+
+	while (rlen > 0) {
+		*rbuf = ((data >> 24) & 0xff);
+		data <<= 8;
+		rbuf++;
+		rlen--;
+	}
+	return 0;
+}
+
+#define DDB_MAGIC 'd'
+
+struct ddb_flashio {
+	__u8 *write_buf;
+	__u32 write_len;
+	__u8 *read_buf;
+	__u32 read_len;
+};
+
+#define IOCTL_DDB_FLASHIO  _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio)
+
+#define DDB_NAME "ddbridge"
+
+static u32 ddb_num;
+static struct ddb *ddbs[32];
+static struct class *ddb_class;
+static int ddb_major;
+
+static int ddb_open(struct inode *inode, struct file *file)
+{
+	struct ddb *dev = ddbs[iminor(inode)];
+
+	file->private_data = dev;
+	return 0;
+}
+
+static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct ddb *dev = file->private_data;
+	void *parg = (void *)arg;
+	int res;
+
+	switch (cmd) {
+	case IOCTL_DDB_FLASHIO:
+	{
+		struct ddb_flashio fio;
+		u8 *rbuf, *wbuf;
+
+		if (copy_from_user(&fio, parg, sizeof(fio)))
+			return -EFAULT;
+
+		if (fio.write_len > 1028 || fio.read_len > 1028)
+			return -EINVAL;
+		if (fio.write_len + fio.read_len > 1028)
+			return -EINVAL;
+
+		wbuf = &dev->iobuf[0];
+		rbuf = wbuf + fio.write_len;
+
+		if (copy_from_user(wbuf, fio.write_buf, fio.write_len))
+			return -EFAULT;
+		res = flashio(dev, wbuf, fio.write_len, rbuf, fio.read_len);
+		if (res)
+			return res;
+		if (copy_to_user(fio.read_buf, rbuf, fio.read_len))
+			return -EFAULT;
+		break;
+	}
+	default:
+		return -ENOTTY;
+	}
+	return 0;
+}
+
+static const struct file_operations ddb_fops = {
+	.unlocked_ioctl = ddb_ioctl,
+	.open           = ddb_open,
+};
+
+static char *ddb_devnode(struct device *device, umode_t *mode)
+{
+	struct ddb *dev = dev_get_drvdata(device);
+
+	return kasprintf(GFP_KERNEL, "ddbridge/card%d", dev->nr);
+}
+
+static int ddb_class_create(void)
+{
+	ddb_major = register_chrdev(0, DDB_NAME, &ddb_fops);
+	if (ddb_major < 0)
+		return ddb_major;
+
+	ddb_class = class_create(THIS_MODULE, DDB_NAME);
+	if (IS_ERR(ddb_class)) {
+		unregister_chrdev(ddb_major, DDB_NAME);
+		return -1;
+	}
+	ddb_class->devnode = ddb_devnode;
+	return 0;
+}
+
+static void ddb_class_destroy(void)
+{
+	class_destroy(ddb_class);
+	unregister_chrdev(ddb_major, DDB_NAME);
+}
+
+static int ddb_device_create(struct ddb *dev)
+{
+	dev->nr = ddb_num++;
+	dev->ddb_dev = device_create(ddb_class, NULL,
+				     MKDEV(ddb_major, dev->nr),
+				     dev, "ddbridge%d", dev->nr);
+	ddbs[dev->nr] = dev;
+	if (IS_ERR(dev->ddb_dev))
+		return -1;
+	return 0;
+}
+
+static void ddb_device_destroy(struct ddb *dev)
+{
+	ddb_num--;
+	if (IS_ERR(dev->ddb_dev))
+		return;
+	device_destroy(ddb_class, MKDEV(ddb_major, 0));
+}
+
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static void ddb_unmap(struct ddb *dev)
+{
+	if (dev->regs)
+		iounmap(dev->regs);
+	vfree(dev);
+}
+
+
+static void __devexit ddb_remove(struct pci_dev *pdev)
+{
+	struct ddb *dev = (struct ddb *) pci_get_drvdata(pdev);
+
+	ddb_ports_detach(dev);
+	ddb_i2c_release(dev);
+
+	ddbwritel(0, INTERRUPT_ENABLE);
+	free_irq(dev->pdev->irq, dev);
+#ifdef CONFIG_PCI_MSI
+	if (dev->msi)
+		pci_disable_msi(dev->pdev);
+#endif
+	ddb_ports_release(dev);
+	ddb_buffers_free(dev);
+	ddb_device_destroy(dev);
+
+	ddb_unmap(dev);
+	pci_set_drvdata(pdev, 0);
+	pci_disable_device(pdev);
+}
+
+
+static int __devinit ddb_probe(struct pci_dev *pdev,
+			       const struct pci_device_id *id)
+{
+	struct ddb *dev;
+	int stat = 0;
+	int irq_flag = IRQF_SHARED;
+
+	if (pci_enable_device(pdev) < 0)
+		return -ENODEV;
+
+	dev = vmalloc(sizeof(struct ddb));
+	if (dev == NULL)
+		return -ENOMEM;
+	memset(dev, 0, sizeof(struct ddb));
+
+	dev->pdev = pdev;
+	pci_set_drvdata(pdev, dev);
+	dev->info = (struct ddb_info *) id->driver_data;
+	printk(KERN_INFO "DDBridge driver detected: %s\n", dev->info->name);
+
+	dev->regs = ioremap(pci_resource_start(dev->pdev, 0),
+			    pci_resource_len(dev->pdev, 0));
+	if (!dev->regs) {
+		stat = -ENOMEM;
+		goto fail;
+	}
+	printk(KERN_INFO "HW %08x FW %08x\n", ddbreadl(0), ddbreadl(4));
+
+#ifdef CONFIG_PCI_MSI
+	if (pci_msi_enabled())
+		stat = pci_enable_msi(dev->pdev);
+	if (stat) {
+		printk(KERN_INFO ": MSI not available.\n");
+	} else {
+		irq_flag = 0;
+		dev->msi = 1;
+	}
+#endif
+	stat = request_irq(dev->pdev->irq, irq_handler,
+			   irq_flag, "DDBridge", (void *) dev);
+	if (stat < 0)
+		goto fail1;
+	ddbwritel(0, DMA_BASE_WRITE);
+	ddbwritel(0, DMA_BASE_READ);
+	ddbwritel(0xffffffff, INTERRUPT_ACK);
+	ddbwritel(0xfff0f, INTERRUPT_ENABLE);
+	ddbwritel(0, MSI1_ENABLE);
+
+	if (ddb_i2c_init(dev) < 0)
+		goto fail1;
+	ddb_ports_init(dev);
+	if (ddb_buffers_alloc(dev) < 0) {
+		printk(KERN_INFO ": Could not allocate buffer memory\n");
+		goto fail2;
+	}
+	if (ddb_ports_attach(dev) < 0)
+		goto fail3;
+	ddb_device_create(dev);
+	return 0;
+
+fail3:
+	ddb_ports_detach(dev);
+	printk(KERN_ERR "fail3\n");
+	ddb_ports_release(dev);
+fail2:
+	printk(KERN_ERR "fail2\n");
+	ddb_buffers_free(dev);
+fail1:
+	printk(KERN_ERR "fail1\n");
+	if (dev->msi)
+		pci_disable_msi(dev->pdev);
+	free_irq(dev->pdev->irq, dev);
+fail:
+	printk(KERN_ERR "fail\n");
+	ddb_unmap(dev);
+	pci_set_drvdata(pdev, 0);
+	pci_disable_device(pdev);
+	return -1;
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+
+static struct ddb_info ddb_none = {
+	.type     = DDB_NONE,
+	.name     = "Digital Devices PCIe bridge",
+};
+
+static struct ddb_info ddb_octopus = {
+	.type     = DDB_OCTOPUS,
+	.name     = "Digital Devices Octopus DVB adapter",
+	.port_num = 4,
+};
+
+static struct ddb_info ddb_octopus_le = {
+	.type     = DDB_OCTOPUS,
+	.name     = "Digital Devices Octopus LE DVB adapter",
+	.port_num = 2,
+};
+
+static struct ddb_info ddb_v6 = {
+	.type     = DDB_OCTOPUS,
+	.name     = "Digital Devices Cine S2 V6 DVB adapter",
+	.port_num = 3,
+};
+
+#define DDVID 0xdd01 /* Digital Devices Vendor ID */
+
+#define DDB_ID(_vend, _dev, _subvend, _subdev, _driverdata) {	\
+	.vendor      = _vend,    .device    = _dev, \
+	.subvendor   = _subvend, .subdevice = _subdev, \
+	.driver_data = (unsigned long)&_driverdata }
+
+static const struct pci_device_id ddb_id_tbl[] __devinitdata = {
+	DDB_ID(DDVID, 0x0002, DDVID, 0x0001, ddb_octopus),
+	DDB_ID(DDVID, 0x0003, DDVID, 0x0001, ddb_octopus),
+	DDB_ID(DDVID, 0x0003, DDVID, 0x0002, ddb_octopus_le),
+	DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus),
+	DDB_ID(DDVID, 0x0003, DDVID, 0x0020, ddb_v6),
+	/* in case sub-ids got deleted in flash */
+	DDB_ID(DDVID, 0x0003, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
+	{0}
+};
+MODULE_DEVICE_TABLE(pci, ddb_id_tbl);
+
+
+static struct pci_driver ddb_pci_driver = {
+	.name        = "DDBridge",
+	.id_table    = ddb_id_tbl,
+	.probe       = ddb_probe,
+	.remove      = __devexit_p(ddb_remove),
+};
+
+static __init int module_init_ddbridge(void)
+{
+	printk(KERN_INFO "Digital Devices PCIE bridge driver, "
+	       "Copyright (C) 2010-11 Digital Devices GmbH\n");
+	if (ddb_class_create())
+		return -1;
+	return pci_register_driver(&ddb_pci_driver);
+}
+
+static __exit void module_exit_ddbridge(void)
+{
+	pci_unregister_driver(&ddb_pci_driver);
+	ddb_class_destroy();
+}
+
+module_init(module_init_ddbridge);
+module_exit(module_exit_ddbridge);
+
+MODULE_DESCRIPTION("Digital Devices PCIe Bridge");
+MODULE_AUTHOR("Ralph Metzler");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.5");
diff --git a/drivers/media/pci/ddbridge/ddbridge-regs.h b/drivers/media/pci/ddbridge/ddbridge-regs.h
new file mode 100644
index 0000000..a3ccb31
--- /dev/null
+++ b/drivers/media/pci/ddbridge/ddbridge-regs.h
@@ -0,0 +1,151 @@
+/*
+ * ddbridge-regs.h: Digital Devices PCIe bridge driver
+ *
+ * Copyright (C) 2010-2011 Digital Devices GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+/* DD-DVBBridgeV1.h 273 2010-09-17 05:03:16Z manfred */
+
+/* Register Definitions */
+
+#define CUR_REGISTERMAP_VERSION 0x10000
+
+#define HARDWARE_VERSION       0x00
+#define REGISTERMAP_VERSION    0x04
+
+/* ------------------------------------------------------------------------- */
+/* SPI Controller */
+
+#define SPI_CONTROL     0x10
+#define SPI_DATA        0x14
+
+/* ------------------------------------------------------------------------- */
+
+/* Interrupt controller                                     */
+/* How many MSI's are available depends on HW (Min 2 max 8) */
+/* How many are usable also depends on Host platform        */
+
+#define INTERRUPT_BASE   (0x40)
+
+#define INTERRUPT_ENABLE (INTERRUPT_BASE + 0x00)
+#define MSI0_ENABLE      (INTERRUPT_BASE + 0x00)
+#define MSI1_ENABLE      (INTERRUPT_BASE + 0x04)
+#define MSI2_ENABLE      (INTERRUPT_BASE + 0x08)
+#define MSI3_ENABLE      (INTERRUPT_BASE + 0x0C)
+#define MSI4_ENABLE      (INTERRUPT_BASE + 0x10)
+#define MSI5_ENABLE      (INTERRUPT_BASE + 0x14)
+#define MSI6_ENABLE      (INTERRUPT_BASE + 0x18)
+#define MSI7_ENABLE      (INTERRUPT_BASE + 0x1C)
+
+#define INTERRUPT_STATUS (INTERRUPT_BASE + 0x20)
+#define INTERRUPT_ACK    (INTERRUPT_BASE + 0x20)
+
+#define INTMASK_I2C1        (0x00000001)
+#define INTMASK_I2C2        (0x00000002)
+#define INTMASK_I2C3        (0x00000004)
+#define INTMASK_I2C4        (0x00000008)
+
+#define INTMASK_CIRQ1       (0x00000010)
+#define INTMASK_CIRQ2       (0x00000020)
+#define INTMASK_CIRQ3       (0x00000040)
+#define INTMASK_CIRQ4       (0x00000080)
+
+#define INTMASK_TSINPUT1    (0x00000100)
+#define INTMASK_TSINPUT2    (0x00000200)
+#define INTMASK_TSINPUT3    (0x00000400)
+#define INTMASK_TSINPUT4    (0x00000800)
+#define INTMASK_TSINPUT5    (0x00001000)
+#define INTMASK_TSINPUT6    (0x00002000)
+#define INTMASK_TSINPUT7    (0x00004000)
+#define INTMASK_TSINPUT8    (0x00008000)
+
+#define INTMASK_TSOUTPUT1   (0x00010000)
+#define INTMASK_TSOUTPUT2   (0x00020000)
+#define INTMASK_TSOUTPUT3   (0x00040000)
+#define INTMASK_TSOUTPUT4   (0x00080000)
+
+/* ------------------------------------------------------------------------- */
+/* I2C Master Controller */
+
+#define I2C_BASE        (0x80)  /* Byte offset */
+
+#define I2C_COMMAND     (0x00)
+#define I2C_TIMING      (0x04)
+#define I2C_TASKLENGTH  (0x08)     /* High read, low write */
+#define I2C_TASKADDRESS (0x0C)     /* High read, low write */
+
+#define I2C_MONITOR     (0x1C)
+
+#define I2C_BASE_1      (I2C_BASE + 0x00)
+#define I2C_BASE_2      (I2C_BASE + 0x20)
+#define I2C_BASE_3      (I2C_BASE + 0x40)
+#define I2C_BASE_4      (I2C_BASE + 0x60)
+
+#define I2C_BASE_N(i)   (I2C_BASE + (i) * 0x20)
+
+#define I2C_TASKMEM_BASE    (0x1000)    /* Byte offset */
+#define I2C_TASKMEM_SIZE    (0x1000)
+
+#define I2C_SPEED_400   (0x04030404)
+#define I2C_SPEED_200   (0x09080909)
+#define I2C_SPEED_154   (0x0C0B0C0C)
+#define I2C_SPEED_100   (0x13121313)
+#define I2C_SPEED_77    (0x19181919)
+#define I2C_SPEED_50    (0x27262727)
+
+
+/* ------------------------------------------------------------------------- */
+/* DMA  Controller */
+
+#define DMA_BASE_WRITE        (0x100)
+#define DMA_BASE_READ         (0x140)
+
+#define DMA_CONTROL     (0x00)                  /* 64 */
+#define DMA_ERROR       (0x04)                  /* 65 ( only read instance ) */
+
+#define DMA_DIAG_CONTROL                (0x1C)  /* 71 */
+#define DMA_DIAG_PACKETCOUNTER_LOW      (0x20)  /* 72 */
+#define DMA_DIAG_PACKETCOUNTER_HIGH     (0x24)  /* 73 */
+#define DMA_DIAG_TIMECOUNTER_LOW        (0x28)  /* 74 */
+#define DMA_DIAG_TIMECOUNTER_HIGH       (0x2C)  /* 75 */
+#define DMA_DIAG_RECHECKCOUNTER         (0x30)  /* 76  ( Split completions on read ) */
+#define DMA_DIAG_WAITTIMEOUTINIT        (0x34)  /* 77 */
+#define DMA_DIAG_WAITOVERFLOWCOUNTER    (0x38)  /* 78 */
+#define DMA_DIAG_WAITCOUNTER            (0x3C)  /* 79 */
+
+/* ------------------------------------------------------------------------- */
+/* DMA  Buffer */
+
+#define TS_INPUT_BASE       (0x200)
+#define TS_INPUT_CONTROL(i)         (TS_INPUT_BASE + (i) * 16 + 0x00)
+
+#define TS_OUTPUT_BASE       (0x280)
+#define TS_OUTPUT_CONTROL(i)         (TS_OUTPUT_BASE + (i) * 16 + 0x00)
+
+#define DMA_BUFFER_BASE     (0x300)
+
+#define DMA_BUFFER_CONTROL(i)       (DMA_BUFFER_BASE + (i) * 16 + 0x00)
+#define DMA_BUFFER_ACK(i)           (DMA_BUFFER_BASE + (i) * 16 + 0x04)
+#define DMA_BUFFER_CURRENT(i)       (DMA_BUFFER_BASE + (i) * 16 + 0x08)
+#define DMA_BUFFER_SIZE(i)          (DMA_BUFFER_BASE + (i) * 16 + 0x0c)
+
+#define DMA_BASE_ADDRESS_TABLE  (0x2000)
+#define DMA_BASE_ADDRESS_TABLE_ENTRIES (512)
+
diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
new file mode 100644
index 0000000..8b1b41d
--- /dev/null
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -0,0 +1,185 @@
+/*
+ * ddbridge.h: Digital Devices PCIe bridge driver
+ *
+ * Copyright (C) 2010-2011 Digital Devices GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _DDBRIDGE_H_
+#define _DDBRIDGE_H_
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <asm/dma.h>
+#include <linux/dvb/frontend.h>
+#include <linux/dvb/ca.h>
+#include <linux/socket.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_ringbuffer.h"
+#include "dvb_ca_en50221.h"
+#include "dvb_net.h"
+#include "cxd2099.h"
+
+#define DDB_MAX_I2C     4
+#define DDB_MAX_PORT    4
+#define DDB_MAX_INPUT   8
+#define DDB_MAX_OUTPUT  4
+
+struct ddb_info {
+	int   type;
+#define DDB_NONE         0
+#define DDB_OCTOPUS      1
+	char *name;
+	int   port_num;
+	u32   port_type[DDB_MAX_PORT];
+};
+
+/* DMA_SIZE MUST be divisible by 188 and 128 !!! */
+
+#define INPUT_DMA_MAX_BUFS 32      /* hardware table limit */
+#define INPUT_DMA_BUFS 8
+#define INPUT_DMA_SIZE (128*47*21)
+
+#define OUTPUT_DMA_MAX_BUFS 32
+#define OUTPUT_DMA_BUFS 8
+#define OUTPUT_DMA_SIZE (128*47*21)
+
+struct ddb;
+struct ddb_port;
+
+struct ddb_input {
+	struct ddb_port       *port;
+	u32                    nr;
+	int                    attached;
+
+	dma_addr_t             pbuf[INPUT_DMA_MAX_BUFS];
+	u8                    *vbuf[INPUT_DMA_MAX_BUFS];
+	u32                    dma_buf_num;
+	u32                    dma_buf_size;
+
+	struct tasklet_struct  tasklet;
+	spinlock_t             lock;
+	wait_queue_head_t      wq;
+	int                    running;
+	u32                    stat;
+	u32                    cbuf;
+	u32                    coff;
+
+	struct dvb_adapter     adap;
+	struct dvb_device     *dev;
+	struct dvb_frontend   *fe;
+	struct dvb_frontend   *fe2;
+	struct dmxdev          dmxdev;
+	struct dvb_demux       demux;
+	struct dvb_net         dvbnet;
+	struct dmx_frontend    hw_frontend;
+	struct dmx_frontend    mem_frontend;
+	int                    users;
+	int (*gate_ctrl)(struct dvb_frontend *, int);
+};
+
+struct ddb_output {
+	struct ddb_port       *port;
+	u32                    nr;
+	dma_addr_t             pbuf[OUTPUT_DMA_MAX_BUFS];
+	u8                    *vbuf[OUTPUT_DMA_MAX_BUFS];
+	u32                    dma_buf_num;
+	u32                    dma_buf_size;
+	struct tasklet_struct  tasklet;
+	spinlock_t             lock;
+	wait_queue_head_t      wq;
+	int                    running;
+	u32                    stat;
+	u32                    cbuf;
+	u32                    coff;
+
+	struct dvb_adapter     adap;
+	struct dvb_device     *dev;
+};
+
+struct ddb_i2c {
+	struct ddb            *dev;
+	u32                    nr;
+	struct i2c_adapter     adap;
+	struct i2c_adapter     adap2;
+	u32                    regs;
+	u32                    rbuf;
+	u32                    wbuf;
+	int                    done;
+	wait_queue_head_t      wq;
+};
+
+struct ddb_port {
+	struct ddb            *dev;
+	u32                    nr;
+	struct ddb_i2c        *i2c;
+	struct mutex           i2c_gate_lock;
+	u32                    class;
+#define DDB_PORT_NONE           0
+#define DDB_PORT_CI             1
+#define DDB_PORT_TUNER          2
+	u32                    type;
+#define DDB_TUNER_NONE          0
+#define DDB_TUNER_DVBS_ST       1
+#define DDB_TUNER_DVBS_ST_AA    2
+#define DDB_TUNER_DVBCT_TR     16
+#define DDB_TUNER_DVBCT_ST     17
+	u32                    adr;
+
+	struct ddb_input      *input[2];
+	struct ddb_output     *output;
+	struct dvb_ca_en50221 *en;
+};
+
+struct ddb {
+	struct pci_dev        *pdev;
+	unsigned char         *regs;
+	struct ddb_port        port[DDB_MAX_PORT];
+	struct ddb_i2c         i2c[DDB_MAX_I2C];
+	struct ddb_input       input[DDB_MAX_INPUT];
+	struct ddb_output      output[DDB_MAX_OUTPUT];
+
+	struct device         *ddb_dev;
+	int                    nr;
+	u8                     iobuf[1028];
+
+	struct ddb_info       *info;
+	int                    msi;
+};
+
+/****************************************************************************/
+
+#define ddbwritel(_val, _adr)        writel((_val), \
+				     (char *) (dev->regs+(_adr)))
+#define ddbreadl(_adr)               readl((char *) (dev->regs+(_adr)))
+#define ddbcpyto(_adr, _src, _count) memcpy_toio((char *)	\
+				     (dev->regs+(_adr)), (_src), (_count))
+#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), (char *) \
+				       (dev->regs+(_adr)), (_count))
+
+/****************************************************************************/
+
+#endif
diff --git a/drivers/media/pci/dm1105/Kconfig b/drivers/media/pci/dm1105/Kconfig
new file mode 100644
index 0000000..f3de0a4
--- /dev/null
+++ b/drivers/media/pci/dm1105/Kconfig
@@ -0,0 +1,20 @@
+config DVB_DM1105
+	tristate "SDMC DM1105 based PCI cards"
+	depends on DVB_CORE && PCI && I2C
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_STV0288 if !DVB_FE_CUSTOMISE
+	select DVB_STB6000 if !DVB_FE_CUSTOMISE
+	select DVB_CX24116 if !DVB_FE_CUSTOMISE
+	select DVB_SI21XX if !DVB_FE_CUSTOMISE
+	select DVB_DS3000 if !DVB_FE_CUSTOMISE
+	depends on RC_CORE
+	help
+	  Support for cards based on the SDMC DM1105 PCI chip like
+	  DvbWorld 2002
+
+	  Since these cards have no MPEG decoder onboard, they transmit
+	  only compressed MPEG data over the PCI bus, so you need
+	  an external software decoder to watch TV on your computer.
+
+	  Say Y or M if you own such a device and want to use it.
diff --git a/drivers/media/pci/dm1105/Makefile b/drivers/media/pci/dm1105/Makefile
new file mode 100644
index 0000000..3275851
--- /dev/null
+++ b/drivers/media/pci/dm1105/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DVB_DM1105) += dm1105.o
+
+ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends
diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c
new file mode 100644
index 0000000..a609b3a
--- /dev/null
+++ b/drivers/media/pci/dm1105/dm1105.c
@@ -0,0 +1,1248 @@
+/*
+ * dm1105.c - driver for DVB cards based on SDMC DM1105 PCI chip
+ *
+ * Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <media/rc-core.h>
+
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+#include "dvb-pll.h"
+
+#include "stv0299.h"
+#include "stv0288.h"
+#include "stb6000.h"
+#include "si21xx.h"
+#include "cx24116.h"
+#include "z0194a.h"
+#include "ds3000.h"
+
+#define MODULE_NAME "dm1105"
+
+#define UNSET (-1U)
+
+#define DM1105_BOARD_NOAUTO			UNSET
+#define DM1105_BOARD_UNKNOWN			0
+#define DM1105_BOARD_DVBWORLD_2002		1
+#define DM1105_BOARD_DVBWORLD_2004		2
+#define DM1105_BOARD_AXESS_DM05			3
+#define DM1105_BOARD_UNBRANDED_I2C_ON_GPIO	4
+
+/* ----------------------------------------------- */
+/*
+ * PCI ID's
+ */
+#ifndef PCI_VENDOR_ID_TRIGEM
+#define PCI_VENDOR_ID_TRIGEM	0x109f
+#endif
+#ifndef PCI_VENDOR_ID_AXESS
+#define PCI_VENDOR_ID_AXESS	0x195d
+#endif
+#ifndef PCI_DEVICE_ID_DM1105
+#define PCI_DEVICE_ID_DM1105	0x036f
+#endif
+#ifndef PCI_DEVICE_ID_DW2002
+#define PCI_DEVICE_ID_DW2002	0x2002
+#endif
+#ifndef PCI_DEVICE_ID_DW2004
+#define PCI_DEVICE_ID_DW2004	0x2004
+#endif
+#ifndef PCI_DEVICE_ID_DM05
+#define PCI_DEVICE_ID_DM05	0x1105
+#endif
+/* ----------------------------------------------- */
+/* sdmc dm1105 registers */
+
+/* TS Control */
+#define DM1105_TSCTR				0x00
+#define DM1105_DTALENTH				0x04
+
+/* GPIO Interface */
+#define DM1105_GPIOVAL				0x08
+#define DM1105_GPIOCTR				0x0c
+
+/* PID serial number */
+#define DM1105_PIDN				0x10
+
+/* Odd-even secret key select */
+#define DM1105_CWSEL				0x14
+
+/* Host Command Interface */
+#define DM1105_HOST_CTR				0x18
+#define DM1105_HOST_AD				0x1c
+
+/* PCI Interface */
+#define DM1105_CR				0x30
+#define DM1105_RST				0x34
+#define DM1105_STADR				0x38
+#define DM1105_RLEN				0x3c
+#define DM1105_WRP				0x40
+#define DM1105_INTCNT				0x44
+#define DM1105_INTMAK				0x48
+#define DM1105_INTSTS				0x4c
+
+/* CW Value */
+#define DM1105_ODD				0x50
+#define DM1105_EVEN				0x58
+
+/* PID Value */
+#define DM1105_PID				0x60
+
+/* IR Control */
+#define DM1105_IRCTR				0x64
+#define DM1105_IRMODE				0x68
+#define DM1105_SYSTEMCODE			0x6c
+#define DM1105_IRCODE				0x70
+
+/* Unknown Values */
+#define DM1105_ENCRYPT				0x74
+#define DM1105_VER				0x7c
+
+/* I2C Interface */
+#define DM1105_I2CCTR				0x80
+#define DM1105_I2CSTS				0x81
+#define DM1105_I2CDAT				0x82
+#define DM1105_I2C_RA				0x83
+/* ----------------------------------------------- */
+/* Interrupt Mask Bits */
+
+#define INTMAK_TSIRQM				0x01
+#define INTMAK_HIRQM				0x04
+#define INTMAK_IRM				0x08
+#define INTMAK_ALLMASK				(INTMAK_TSIRQM | \
+						INTMAK_HIRQM | \
+						INTMAK_IRM)
+#define INTMAK_NONEMASK				0x00
+
+/* Interrupt Status Bits */
+#define INTSTS_TSIRQ				0x01
+#define INTSTS_HIRQ				0x04
+#define INTSTS_IR				0x08
+
+/* IR Control Bits */
+#define DM1105_IR_EN				0x01
+#define DM1105_SYS_CHK				0x02
+#define DM1105_REP_FLG				0x08
+
+/* EEPROM addr */
+#define IIC_24C01_addr				0xa0
+/* Max board count */
+#define DM1105_MAX				0x04
+
+#define DRIVER_NAME				"dm1105"
+#define DM1105_I2C_GPIO_NAME			"dm1105-gpio"
+
+#define DM1105_DMA_PACKETS			47
+#define DM1105_DMA_PACKET_LENGTH		(128*4)
+#define DM1105_DMA_BYTES			(128 * 4 * DM1105_DMA_PACKETS)
+
+/*  */
+#define GPIO08					(1 << 8)
+#define GPIO13					(1 << 13)
+#define GPIO14					(1 << 14)
+#define GPIO15					(1 << 15)
+#define GPIO16					(1 << 16)
+#define GPIO17					(1 << 17)
+#define GPIO_ALL				0x03ffff
+
+/* GPIO's for LNB power control */
+#define DM1105_LNB_MASK				(GPIO_ALL & ~(GPIO14 | GPIO13))
+#define DM1105_LNB_OFF				GPIO17
+#define DM1105_LNB_13V				(GPIO16 | GPIO08)
+#define DM1105_LNB_18V				GPIO08
+
+/* GPIO's for LNB power control for Axess DM05 */
+#define DM05_LNB_MASK				(GPIO_ALL & ~(GPIO14 | GPIO13))
+#define DM05_LNB_OFF				GPIO17/* actually 13v */
+#define DM05_LNB_13V				GPIO17
+#define DM05_LNB_18V				(GPIO17 | GPIO16)
+
+/* GPIO's for LNB power control for unbranded with I2C on GPIO */
+#define UNBR_LNB_MASK				(GPIO17 | GPIO16)
+#define UNBR_LNB_OFF				0
+#define UNBR_LNB_13V				GPIO17
+#define UNBR_LNB_18V				(GPIO17 | GPIO16)
+
+static unsigned int card[]  = {[0 ... 3] = UNSET };
+module_param_array(card,  int, NULL, 0444);
+MODULE_PARM_DESC(card, "card type");
+
+static int ir_debug;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
+
+static unsigned int dm1105_devcount;
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct dm1105_board {
+	char	*name;
+	struct	{
+		u32	mask, off, v13, v18;
+	} lnb;
+	u32	gpio_scl, gpio_sda;
+};
+
+struct dm1105_subid {
+	u16     subvendor;
+	u16     subdevice;
+	u32     card;
+};
+
+static const struct dm1105_board dm1105_boards[] = {
+	[DM1105_BOARD_UNKNOWN] = {
+		.name		= "UNKNOWN/GENERIC",
+		.lnb = {
+			.mask = DM1105_LNB_MASK,
+			.off = DM1105_LNB_OFF,
+			.v13 = DM1105_LNB_13V,
+			.v18 = DM1105_LNB_18V,
+		},
+	},
+	[DM1105_BOARD_DVBWORLD_2002] = {
+		.name		= "DVBWorld PCI 2002",
+		.lnb = {
+			.mask = DM1105_LNB_MASK,
+			.off = DM1105_LNB_OFF,
+			.v13 = DM1105_LNB_13V,
+			.v18 = DM1105_LNB_18V,
+		},
+	},
+	[DM1105_BOARD_DVBWORLD_2004] = {
+		.name		= "DVBWorld PCI 2004",
+		.lnb = {
+			.mask = DM1105_LNB_MASK,
+			.off = DM1105_LNB_OFF,
+			.v13 = DM1105_LNB_13V,
+			.v18 = DM1105_LNB_18V,
+		},
+	},
+	[DM1105_BOARD_AXESS_DM05] = {
+		.name		= "Axess/EasyTv DM05",
+		.lnb = {
+			.mask = DM05_LNB_MASK,
+			.off = DM05_LNB_OFF,
+			.v13 = DM05_LNB_13V,
+			.v18 = DM05_LNB_18V,
+		},
+	},
+	[DM1105_BOARD_UNBRANDED_I2C_ON_GPIO] = {
+		.name		= "Unbranded DM1105 with i2c on GPIOs",
+		.lnb = {
+			.mask = UNBR_LNB_MASK,
+			.off = UNBR_LNB_OFF,
+			.v13 = UNBR_LNB_13V,
+			.v18 = UNBR_LNB_18V,
+		},
+		.gpio_scl	= GPIO14,
+		.gpio_sda	= GPIO13,
+	},
+};
+
+static const struct dm1105_subid dm1105_subids[] = {
+	{
+		.subvendor = 0x0000,
+		.subdevice = 0x2002,
+		.card      = DM1105_BOARD_DVBWORLD_2002,
+	}, {
+		.subvendor = 0x0001,
+		.subdevice = 0x2002,
+		.card      = DM1105_BOARD_DVBWORLD_2002,
+	}, {
+		.subvendor = 0x0000,
+		.subdevice = 0x2004,
+		.card      = DM1105_BOARD_DVBWORLD_2004,
+	}, {
+		.subvendor = 0x0001,
+		.subdevice = 0x2004,
+		.card      = DM1105_BOARD_DVBWORLD_2004,
+	}, {
+		.subvendor = 0x195d,
+		.subdevice = 0x1105,
+		.card      = DM1105_BOARD_AXESS_DM05,
+	},
+};
+
+static void dm1105_card_list(struct pci_dev *pci)
+{
+	int i;
+
+	if (0 == pci->subsystem_vendor &&
+			0 == pci->subsystem_device) {
+		printk(KERN_ERR
+			"dm1105: Your board has no valid PCI Subsystem ID\n"
+			"dm1105: and thus can't be autodetected\n"
+			"dm1105: Please pass card=<n> insmod option to\n"
+			"dm1105: workaround that.  Redirect complaints to\n"
+			"dm1105: the vendor of the TV card.  Best regards,\n"
+			"dm1105: -- tux\n");
+	} else {
+		printk(KERN_ERR
+			"dm1105: Your board isn't known (yet) to the driver.\n"
+			"dm1105: You can try to pick one of the existing\n"
+			"dm1105: card configs via card=<n> insmod option.\n"
+			"dm1105: Updating to the latest version might help\n"
+			"dm1105: as well.\n");
+	}
+	printk(KERN_ERR "Here is a list of valid choices for the card=<n> "
+		   "insmod option:\n");
+	for (i = 0; i < ARRAY_SIZE(dm1105_boards); i++)
+		printk(KERN_ERR "dm1105:    card=%d -> %s\n",
+				i, dm1105_boards[i].name);
+}
+
+/* infrared remote control */
+struct infrared {
+	struct rc_dev		*dev;
+	char			input_phys[32];
+	struct work_struct	work;
+	u32			ir_command;
+};
+
+struct dm1105_dev {
+	/* pci */
+	struct pci_dev *pdev;
+	u8 __iomem *io_mem;
+
+	/* ir */
+	struct infrared ir;
+
+	/* dvb */
+	struct dmx_frontend hw_frontend;
+	struct dmx_frontend mem_frontend;
+	struct dmxdev dmxdev;
+	struct dvb_adapter dvb_adapter;
+	struct dvb_demux demux;
+	struct dvb_frontend *fe;
+	struct dvb_net dvbnet;
+	unsigned int full_ts_users;
+	unsigned int boardnr;
+	int nr;
+
+	/* i2c */
+	struct i2c_adapter i2c_adap;
+	struct i2c_adapter i2c_bb_adap;
+	struct i2c_algo_bit_data i2c_bit;
+
+	/* irq */
+	struct work_struct work;
+	struct workqueue_struct *wq;
+	char wqn[16];
+
+	/* dma */
+	dma_addr_t dma_addr;
+	unsigned char *ts_buf;
+	u32 wrp;
+	u32 nextwrp;
+	u32 buffer_size;
+	unsigned int	PacketErrorCount;
+	unsigned int dmarst;
+	spinlock_t lock;
+};
+
+#define dm_io_mem(reg)	((unsigned long)(&dev->io_mem[reg]))
+
+#define dm_readb(reg)		inb(dm_io_mem(reg))
+#define dm_writeb(reg, value)	outb((value), (dm_io_mem(reg)))
+
+#define dm_readw(reg)		inw(dm_io_mem(reg))
+#define dm_writew(reg, value)	outw((value), (dm_io_mem(reg)))
+
+#define dm_readl(reg)		inl(dm_io_mem(reg))
+#define dm_writel(reg, value)	outl((value), (dm_io_mem(reg)))
+
+#define dm_andorl(reg, mask, value) \
+	outl((inl(dm_io_mem(reg)) & ~(mask)) |\
+		((value) & (mask)), (dm_io_mem(reg)))
+
+#define dm_setl(reg, bit)	dm_andorl((reg), (bit), (bit))
+#define dm_clearl(reg, bit)	dm_andorl((reg), (bit), 0)
+
+/* The chip has 18 GPIOs. In HOST mode GPIO's used as 15 bit address lines,
+ so we can use only 3 GPIO's from GPIO15 to GPIO17.
+ Here I don't check whether HOST is enebled as it is not implemented yet.
+ */
+static void dm1105_gpio_set(struct dm1105_dev *dev, u32 mask)
+{
+	if (mask & 0xfffc0000)
+		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
+
+	if (mask & 0x0003ffff)
+		dm_setl(DM1105_GPIOVAL, mask & 0x0003ffff);
+
+}
+
+static void dm1105_gpio_clear(struct dm1105_dev *dev, u32 mask)
+{
+	if (mask & 0xfffc0000)
+		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
+
+	if (mask & 0x0003ffff)
+		dm_clearl(DM1105_GPIOVAL, mask & 0x0003ffff);
+
+}
+
+static void dm1105_gpio_andor(struct dm1105_dev *dev, u32 mask, u32 val)
+{
+	if (mask & 0xfffc0000)
+		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
+
+	if (mask & 0x0003ffff)
+		dm_andorl(DM1105_GPIOVAL, mask & 0x0003ffff, val);
+
+}
+
+static u32 dm1105_gpio_get(struct dm1105_dev *dev, u32 mask)
+{
+	if (mask & 0xfffc0000)
+		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
+
+	if (mask & 0x0003ffff)
+		return dm_readl(DM1105_GPIOVAL) & mask & 0x0003ffff;
+
+	return 0;
+}
+
+static void dm1105_gpio_enable(struct dm1105_dev *dev, u32 mask, int asoutput)
+{
+	if (mask & 0xfffc0000)
+		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
+
+	if ((mask & 0x0003ffff) && asoutput)
+		dm_clearl(DM1105_GPIOCTR, mask & 0x0003ffff);
+	else if ((mask & 0x0003ffff) && !asoutput)
+		dm_setl(DM1105_GPIOCTR, mask & 0x0003ffff);
+
+}
+
+static void dm1105_setline(struct dm1105_dev *dev, u32 line, int state)
+{
+	if (state)
+		dm1105_gpio_enable(dev, line, 0);
+	else {
+		dm1105_gpio_enable(dev, line, 1);
+		dm1105_gpio_clear(dev, line);
+	}
+}
+
+static void dm1105_setsda(void *data, int state)
+{
+	struct dm1105_dev *dev = data;
+
+	dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_sda, state);
+}
+
+static void dm1105_setscl(void *data, int state)
+{
+	struct dm1105_dev *dev = data;
+
+	dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_scl, state);
+}
+
+static int dm1105_getsda(void *data)
+{
+	struct dm1105_dev *dev = data;
+
+	return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_sda)
+									? 1 : 0;
+}
+
+static int dm1105_getscl(void *data)
+{
+	struct dm1105_dev *dev = data;
+
+	return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_scl)
+									? 1 : 0;
+}
+
+static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
+			    struct i2c_msg *msgs, int num)
+{
+	struct dm1105_dev *dev ;
+
+	int addr, rc, i, j, k, len, byte, data;
+	u8 status;
+
+	dev = i2c_adap->algo_data;
+	for (i = 0; i < num; i++) {
+		dm_writeb(DM1105_I2CCTR, 0x00);
+		if (msgs[i].flags & I2C_M_RD) {
+			/* read bytes */
+			addr  = msgs[i].addr << 1;
+			addr |= 1;
+			dm_writeb(DM1105_I2CDAT, addr);
+			for (byte = 0; byte < msgs[i].len; byte++)
+				dm_writeb(DM1105_I2CDAT + byte + 1, 0);
+
+			dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len);
+			for (j = 0; j < 55; j++) {
+				mdelay(10);
+				status = dm_readb(DM1105_I2CSTS);
+				if ((status & 0xc0) == 0x40)
+					break;
+			}
+			if (j >= 55)
+				return -1;
+
+			for (byte = 0; byte < msgs[i].len; byte++) {
+				rc = dm_readb(DM1105_I2CDAT + byte + 1);
+				if (rc < 0)
+					goto err;
+				msgs[i].buf[byte] = rc;
+			}
+		} else if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) {
+			/* prepaired for cx24116 firmware */
+			/* Write in small blocks */
+			len = msgs[i].len - 1;
+			k = 1;
+			do {
+				dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1);
+				dm_writeb(DM1105_I2CDAT + 1, 0xf7);
+				for (byte = 0; byte < (len > 48 ? 48 : len); byte++) {
+					data = msgs[i].buf[k + byte];
+					dm_writeb(DM1105_I2CDAT + byte + 2, data);
+				}
+				dm_writeb(DM1105_I2CCTR, 0x82 + (len > 48 ? 48 : len));
+				for (j = 0; j < 25; j++) {
+					mdelay(10);
+					status = dm_readb(DM1105_I2CSTS);
+					if ((status & 0xc0) == 0x40)
+						break;
+				}
+
+				if (j >= 25)
+					return -1;
+
+				k += 48;
+				len -= 48;
+			} while (len > 0);
+		} else {
+			/* write bytes */
+			dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1);
+			for (byte = 0; byte < msgs[i].len; byte++) {
+				data = msgs[i].buf[byte];
+				dm_writeb(DM1105_I2CDAT + byte + 1, data);
+			}
+			dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len);
+			for (j = 0; j < 25; j++) {
+				mdelay(10);
+				status = dm_readb(DM1105_I2CSTS);
+				if ((status & 0xc0) == 0x40)
+					break;
+			}
+
+			if (j >= 25)
+				return -1;
+		}
+	}
+	return num;
+ err:
+	return rc;
+}
+
+static u32 functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dm1105_algo = {
+	.master_xfer   = dm1105_i2c_xfer,
+	.functionality = functionality,
+};
+
+static inline struct dm1105_dev *feed_to_dm1105_dev(struct dvb_demux_feed *feed)
+{
+	return container_of(feed->demux, struct dm1105_dev, demux);
+}
+
+static inline struct dm1105_dev *frontend_to_dm1105_dev(struct dvb_frontend *fe)
+{
+	return container_of(fe->dvb, struct dm1105_dev, dvb_adapter);
+}
+
+static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct dm1105_dev *dev = frontend_to_dm1105_dev(fe);
+
+	dm1105_gpio_enable(dev, dm1105_boards[dev->boardnr].lnb.mask, 1);
+	if (voltage == SEC_VOLTAGE_18)
+		dm1105_gpio_andor(dev,
+				dm1105_boards[dev->boardnr].lnb.mask,
+				dm1105_boards[dev->boardnr].lnb.v18);
+	else if (voltage == SEC_VOLTAGE_13)
+		dm1105_gpio_andor(dev,
+				dm1105_boards[dev->boardnr].lnb.mask,
+				dm1105_boards[dev->boardnr].lnb.v13);
+	else
+		dm1105_gpio_andor(dev,
+				dm1105_boards[dev->boardnr].lnb.mask,
+				dm1105_boards[dev->boardnr].lnb.off);
+
+	return 0;
+}
+
+static void dm1105_set_dma_addr(struct dm1105_dev *dev)
+{
+	dm_writel(DM1105_STADR, cpu_to_le32(dev->dma_addr));
+}
+
+static int __devinit dm1105_dma_map(struct dm1105_dev *dev)
+{
+	dev->ts_buf = pci_alloc_consistent(dev->pdev,
+					6 * DM1105_DMA_BYTES,
+					&dev->dma_addr);
+
+	return !dev->ts_buf;
+}
+
+static void dm1105_dma_unmap(struct dm1105_dev *dev)
+{
+	pci_free_consistent(dev->pdev,
+			6 * DM1105_DMA_BYTES,
+			dev->ts_buf,
+			dev->dma_addr);
+}
+
+static void dm1105_enable_irqs(struct dm1105_dev *dev)
+{
+	dm_writeb(DM1105_INTMAK, INTMAK_ALLMASK);
+	dm_writeb(DM1105_CR, 1);
+}
+
+static void dm1105_disable_irqs(struct dm1105_dev *dev)
+{
+	dm_writeb(DM1105_INTMAK, INTMAK_IRM);
+	dm_writeb(DM1105_CR, 0);
+}
+
+static int dm1105_start_feed(struct dvb_demux_feed *f)
+{
+	struct dm1105_dev *dev = feed_to_dm1105_dev(f);
+
+	if (dev->full_ts_users++ == 0)
+		dm1105_enable_irqs(dev);
+
+	return 0;
+}
+
+static int dm1105_stop_feed(struct dvb_demux_feed *f)
+{
+	struct dm1105_dev *dev = feed_to_dm1105_dev(f);
+
+	if (--dev->full_ts_users == 0)
+		dm1105_disable_irqs(dev);
+
+	return 0;
+}
+
+/* ir work handler */
+static void dm1105_emit_key(struct work_struct *work)
+{
+	struct infrared *ir = container_of(work, struct infrared, work);
+	u32 ircom = ir->ir_command;
+	u8 data;
+
+	if (ir_debug)
+		printk(KERN_INFO "%s: received byte 0x%04x\n", __func__, ircom);
+
+	data = (ircom >> 8) & 0x7f;
+
+	rc_keydown(ir->dev, data, 0);
+}
+
+/* work handler */
+static void dm1105_dmx_buffer(struct work_struct *work)
+{
+	struct dm1105_dev *dev = container_of(work, struct dm1105_dev, work);
+	unsigned int nbpackets;
+	u32 oldwrp = dev->wrp;
+	u32 nextwrp = dev->nextwrp;
+
+	if (!((dev->ts_buf[oldwrp] == 0x47) &&
+			(dev->ts_buf[oldwrp + 188] == 0x47) &&
+			(dev->ts_buf[oldwrp + 188 * 2] == 0x47))) {
+		dev->PacketErrorCount++;
+		/* bad packet found */
+		if ((dev->PacketErrorCount >= 2) &&
+				(dev->dmarst == 0)) {
+			dm_writeb(DM1105_RST, 1);
+			dev->wrp = 0;
+			dev->PacketErrorCount = 0;
+			dev->dmarst = 0;
+			return;
+		}
+	}
+
+	if (nextwrp < oldwrp) {
+		memcpy(dev->ts_buf + dev->buffer_size, dev->ts_buf, nextwrp);
+		nbpackets = ((dev->buffer_size - oldwrp) + nextwrp) / 188;
+	} else
+		nbpackets = (nextwrp - oldwrp) / 188;
+
+	dev->wrp = nextwrp;
+	dvb_dmx_swfilter_packets(&dev->demux, &dev->ts_buf[oldwrp], nbpackets);
+}
+
+static irqreturn_t dm1105_irq(int irq, void *dev_id)
+{
+	struct dm1105_dev *dev = dev_id;
+
+	/* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */
+	unsigned int intsts = dm_readb(DM1105_INTSTS);
+	dm_writeb(DM1105_INTSTS, intsts);
+
+	switch (intsts) {
+	case INTSTS_TSIRQ:
+	case (INTSTS_TSIRQ | INTSTS_IR):
+		dev->nextwrp = dm_readl(DM1105_WRP) - dm_readl(DM1105_STADR);
+		queue_work(dev->wq, &dev->work);
+		break;
+	case INTSTS_IR:
+		dev->ir.ir_command = dm_readl(DM1105_IRCODE);
+		schedule_work(&dev->ir.work);
+		break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+int __devinit dm1105_ir_init(struct dm1105_dev *dm1105)
+{
+	struct rc_dev *dev;
+	int err = -ENOMEM;
+
+	dev = rc_allocate_device();
+	if (!dev)
+		return -ENOMEM;
+
+	snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys),
+		"pci-%s/ir0", pci_name(dm1105->pdev));
+
+	dev->driver_name = MODULE_NAME;
+	dev->map_name = RC_MAP_DM1105_NEC;
+	dev->driver_type = RC_DRIVER_SCANCODE;
+	dev->input_name = "DVB on-card IR receiver";
+	dev->input_phys = dm1105->ir.input_phys;
+	dev->input_id.bustype = BUS_PCI;
+	dev->input_id.version = 1;
+	if (dm1105->pdev->subsystem_vendor) {
+		dev->input_id.vendor = dm1105->pdev->subsystem_vendor;
+		dev->input_id.product = dm1105->pdev->subsystem_device;
+	} else {
+		dev->input_id.vendor = dm1105->pdev->vendor;
+		dev->input_id.product = dm1105->pdev->device;
+	}
+	dev->dev.parent = &dm1105->pdev->dev;
+
+	INIT_WORK(&dm1105->ir.work, dm1105_emit_key);
+
+	err = rc_register_device(dev);
+	if (err < 0) {
+		rc_free_device(dev);
+		return err;
+	}
+
+	dm1105->ir.dev = dev;
+	return 0;
+}
+
+void __devexit dm1105_ir_exit(struct dm1105_dev *dm1105)
+{
+	rc_unregister_device(dm1105->ir.dev);
+}
+
+static int __devinit dm1105_hw_init(struct dm1105_dev *dev)
+{
+	dm1105_disable_irqs(dev);
+
+	dm_writeb(DM1105_HOST_CTR, 0);
+
+	/*DATALEN 188,*/
+	dm_writeb(DM1105_DTALENTH, 188);
+	/*TS_STRT TS_VALP MSBFIRST TS_MODE ALPAS TSPES*/
+	dm_writew(DM1105_TSCTR, 0xc10a);
+
+	/* map DMA and set address */
+	dm1105_dma_map(dev);
+	dm1105_set_dma_addr(dev);
+	/* big buffer */
+	dm_writel(DM1105_RLEN, 5 * DM1105_DMA_BYTES);
+	dm_writeb(DM1105_INTCNT, 47);
+
+	/* IR NEC mode enable */
+	dm_writeb(DM1105_IRCTR, (DM1105_IR_EN | DM1105_SYS_CHK));
+	dm_writeb(DM1105_IRMODE, 0);
+	dm_writew(DM1105_SYSTEMCODE, 0);
+
+	return 0;
+}
+
+static void dm1105_hw_exit(struct dm1105_dev *dev)
+{
+	dm1105_disable_irqs(dev);
+
+	/* IR disable */
+	dm_writeb(DM1105_IRCTR, 0);
+	dm_writeb(DM1105_INTMAK, INTMAK_NONEMASK);
+
+	dm1105_dma_unmap(dev);
+}
+
+static struct stv0299_config sharp_z0194a_config = {
+	.demod_address = 0x68,
+	.inittab = sharp_z0194a_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.skip_reinit = 0,
+	.lock_output = STV0299_LOCKOUTPUT_1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = sharp_z0194a_set_symbol_rate,
+};
+
+static struct stv0288_config earda_config = {
+	.demod_address = 0x68,
+	.min_delay_ms = 100,
+};
+
+static struct si21xx_config serit_config = {
+	.demod_address = 0x68,
+	.min_delay_ms = 100,
+
+};
+
+static struct cx24116_config serit_sp2633_config = {
+	.demod_address = 0x55,
+};
+
+static struct ds3000_config dvbworld_ds3000_config = {
+	.demod_address = 0x68,
+};
+
+static int __devinit frontend_init(struct dm1105_dev *dev)
+{
+	int ret;
+
+	switch (dev->boardnr) {
+	case DM1105_BOARD_UNBRANDED_I2C_ON_GPIO:
+		dm1105_gpio_enable(dev, GPIO15, 1);
+		dm1105_gpio_clear(dev, GPIO15);
+		msleep(100);
+		dm1105_gpio_set(dev, GPIO15);
+		msleep(200);
+		dev->fe = dvb_attach(
+			stv0299_attach, &sharp_z0194a_config,
+			&dev->i2c_bb_adap);
+		if (dev->fe) {
+			dev->fe->ops.set_voltage = dm1105_set_voltage;
+			dvb_attach(dvb_pll_attach, dev->fe, 0x60,
+					&dev->i2c_bb_adap, DVB_PLL_OPERA1);
+			break;
+		}
+
+		dev->fe = dvb_attach(
+			stv0288_attach, &earda_config,
+			&dev->i2c_bb_adap);
+		if (dev->fe) {
+			dev->fe->ops.set_voltage = dm1105_set_voltage;
+			dvb_attach(stb6000_attach, dev->fe, 0x61,
+					&dev->i2c_bb_adap);
+			break;
+		}
+
+		dev->fe = dvb_attach(
+			si21xx_attach, &serit_config,
+			&dev->i2c_bb_adap);
+		if (dev->fe)
+			dev->fe->ops.set_voltage = dm1105_set_voltage;
+		break;
+	case DM1105_BOARD_DVBWORLD_2004:
+		dev->fe = dvb_attach(
+			cx24116_attach, &serit_sp2633_config,
+			&dev->i2c_adap);
+		if (dev->fe) {
+			dev->fe->ops.set_voltage = dm1105_set_voltage;
+			break;
+		}
+
+		dev->fe = dvb_attach(
+			ds3000_attach, &dvbworld_ds3000_config,
+			&dev->i2c_adap);
+		if (dev->fe)
+			dev->fe->ops.set_voltage = dm1105_set_voltage;
+
+		break;
+	case DM1105_BOARD_DVBWORLD_2002:
+	case DM1105_BOARD_AXESS_DM05:
+	default:
+		dev->fe = dvb_attach(
+			stv0299_attach, &sharp_z0194a_config,
+			&dev->i2c_adap);
+		if (dev->fe) {
+			dev->fe->ops.set_voltage = dm1105_set_voltage;
+			dvb_attach(dvb_pll_attach, dev->fe, 0x60,
+					&dev->i2c_adap, DVB_PLL_OPERA1);
+			break;
+		}
+
+		dev->fe = dvb_attach(
+			stv0288_attach, &earda_config,
+			&dev->i2c_adap);
+		if (dev->fe) {
+			dev->fe->ops.set_voltage = dm1105_set_voltage;
+			dvb_attach(stb6000_attach, dev->fe, 0x61,
+					&dev->i2c_adap);
+			break;
+		}
+
+		dev->fe = dvb_attach(
+			si21xx_attach, &serit_config,
+			&dev->i2c_adap);
+		if (dev->fe)
+			dev->fe->ops.set_voltage = dm1105_set_voltage;
+
+	}
+
+	if (!dev->fe) {
+		dev_err(&dev->pdev->dev, "could not attach frontend\n");
+		return -ENODEV;
+	}
+
+	ret = dvb_register_frontend(&dev->dvb_adapter, dev->fe);
+	if (ret < 0) {
+		if (dev->fe->ops.release)
+			dev->fe->ops.release(dev->fe);
+		dev->fe = NULL;
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __devinit dm1105_read_mac(struct dm1105_dev *dev, u8 *mac)
+{
+	static u8 command[1] = { 0x28 };
+
+	struct i2c_msg msg[] = {
+		{
+			.addr = IIC_24C01_addr >> 1,
+			.flags = 0,
+			.buf = command,
+			.len = 1
+		}, {
+			.addr = IIC_24C01_addr >> 1,
+			.flags = I2C_M_RD,
+			.buf = mac,
+			.len = 6
+		},
+	};
+
+	dm1105_i2c_xfer(&dev->i2c_adap, msg , 2);
+	dev_info(&dev->pdev->dev, "MAC %pM\n", mac);
+}
+
+static int __devinit dm1105_probe(struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+	struct dm1105_dev *dev;
+	struct dvb_adapter *dvb_adapter;
+	struct dvb_demux *dvbdemux;
+	struct dmx_demux *dmx;
+	int ret = -ENOMEM;
+	int i;
+
+	dev = kzalloc(sizeof(struct dm1105_dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	/* board config */
+	dev->nr = dm1105_devcount;
+	dev->boardnr = UNSET;
+	if (card[dev->nr] < ARRAY_SIZE(dm1105_boards))
+		dev->boardnr = card[dev->nr];
+	for (i = 0; UNSET == dev->boardnr &&
+				i < ARRAY_SIZE(dm1105_subids); i++)
+		if (pdev->subsystem_vendor ==
+			dm1105_subids[i].subvendor &&
+				pdev->subsystem_device ==
+					dm1105_subids[i].subdevice)
+			dev->boardnr = dm1105_subids[i].card;
+
+	if (UNSET == dev->boardnr) {
+		dev->boardnr = DM1105_BOARD_UNKNOWN;
+		dm1105_card_list(pdev);
+	}
+
+	dm1105_devcount++;
+	dev->pdev = pdev;
+	dev->buffer_size = 5 * DM1105_DMA_BYTES;
+	dev->PacketErrorCount = 0;
+	dev->dmarst = 0;
+
+	ret = pci_enable_device(pdev);
+	if (ret < 0)
+		goto err_kfree;
+
+	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+	if (ret < 0)
+		goto err_pci_disable_device;
+
+	pci_set_master(pdev);
+
+	ret = pci_request_regions(pdev, DRIVER_NAME);
+	if (ret < 0)
+		goto err_pci_disable_device;
+
+	dev->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
+	if (!dev->io_mem) {
+		ret = -EIO;
+		goto err_pci_release_regions;
+	}
+
+	spin_lock_init(&dev->lock);
+	pci_set_drvdata(pdev, dev);
+
+	ret = dm1105_hw_init(dev);
+	if (ret < 0)
+		goto err_pci_iounmap;
+
+	/* i2c */
+	i2c_set_adapdata(&dev->i2c_adap, dev);
+	strcpy(dev->i2c_adap.name, DRIVER_NAME);
+	dev->i2c_adap.owner = THIS_MODULE;
+	dev->i2c_adap.dev.parent = &pdev->dev;
+	dev->i2c_adap.algo = &dm1105_algo;
+	dev->i2c_adap.algo_data = dev;
+	ret = i2c_add_adapter(&dev->i2c_adap);
+
+	if (ret < 0)
+		goto err_dm1105_hw_exit;
+
+	i2c_set_adapdata(&dev->i2c_bb_adap, dev);
+	strcpy(dev->i2c_bb_adap.name, DM1105_I2C_GPIO_NAME);
+	dev->i2c_bb_adap.owner = THIS_MODULE;
+	dev->i2c_bb_adap.dev.parent = &pdev->dev;
+	dev->i2c_bb_adap.algo_data = &dev->i2c_bit;
+	dev->i2c_bit.data = dev;
+	dev->i2c_bit.setsda = dm1105_setsda;
+	dev->i2c_bit.setscl = dm1105_setscl;
+	dev->i2c_bit.getsda = dm1105_getsda;
+	dev->i2c_bit.getscl = dm1105_getscl;
+	dev->i2c_bit.udelay = 10;
+	dev->i2c_bit.timeout = 10;
+
+	/* Raise SCL and SDA */
+	dm1105_setsda(dev, 1);
+	dm1105_setscl(dev, 1);
+
+	ret = i2c_bit_add_bus(&dev->i2c_bb_adap);
+	if (ret < 0)
+		goto err_i2c_del_adapter;
+
+	/* dvb */
+	ret = dvb_register_adapter(&dev->dvb_adapter, DRIVER_NAME,
+					THIS_MODULE, &pdev->dev, adapter_nr);
+	if (ret < 0)
+		goto err_i2c_del_adapters;
+
+	dvb_adapter = &dev->dvb_adapter;
+
+	dm1105_read_mac(dev, dvb_adapter->proposed_mac);
+
+	dvbdemux = &dev->demux;
+	dvbdemux->filternum = 256;
+	dvbdemux->feednum = 256;
+	dvbdemux->start_feed = dm1105_start_feed;
+	dvbdemux->stop_feed = dm1105_stop_feed;
+	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+			DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
+	ret = dvb_dmx_init(dvbdemux);
+	if (ret < 0)
+		goto err_dvb_unregister_adapter;
+
+	dmx = &dvbdemux->dmx;
+	dev->dmxdev.filternum = 256;
+	dev->dmxdev.demux = dmx;
+	dev->dmxdev.capabilities = 0;
+
+	ret = dvb_dmxdev_init(&dev->dmxdev, dvb_adapter);
+	if (ret < 0)
+		goto err_dvb_dmx_release;
+
+	dev->hw_frontend.source = DMX_FRONTEND_0;
+
+	ret = dmx->add_frontend(dmx, &dev->hw_frontend);
+	if (ret < 0)
+		goto err_dvb_dmxdev_release;
+
+	dev->mem_frontend.source = DMX_MEMORY_FE;
+
+	ret = dmx->add_frontend(dmx, &dev->mem_frontend);
+	if (ret < 0)
+		goto err_remove_hw_frontend;
+
+	ret = dmx->connect_frontend(dmx, &dev->hw_frontend);
+	if (ret < 0)
+		goto err_remove_mem_frontend;
+
+	ret = dvb_net_init(dvb_adapter, &dev->dvbnet, dmx);
+	if (ret < 0)
+		goto err_disconnect_frontend;
+
+	ret = frontend_init(dev);
+	if (ret < 0)
+		goto err_dvb_net;
+
+	dm1105_ir_init(dev);
+
+	INIT_WORK(&dev->work, dm1105_dmx_buffer);
+	sprintf(dev->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num);
+	dev->wq = create_singlethread_workqueue(dev->wqn);
+	if (!dev->wq)
+		goto err_dvb_net;
+
+	ret = request_irq(pdev->irq, dm1105_irq, IRQF_SHARED,
+						DRIVER_NAME, dev);
+	if (ret < 0)
+		goto err_workqueue;
+
+	return 0;
+
+err_workqueue:
+	destroy_workqueue(dev->wq);
+err_dvb_net:
+	dvb_net_release(&dev->dvbnet);
+err_disconnect_frontend:
+	dmx->disconnect_frontend(dmx);
+err_remove_mem_frontend:
+	dmx->remove_frontend(dmx, &dev->mem_frontend);
+err_remove_hw_frontend:
+	dmx->remove_frontend(dmx, &dev->hw_frontend);
+err_dvb_dmxdev_release:
+	dvb_dmxdev_release(&dev->dmxdev);
+err_dvb_dmx_release:
+	dvb_dmx_release(dvbdemux);
+err_dvb_unregister_adapter:
+	dvb_unregister_adapter(dvb_adapter);
+err_i2c_del_adapters:
+	i2c_del_adapter(&dev->i2c_bb_adap);
+err_i2c_del_adapter:
+	i2c_del_adapter(&dev->i2c_adap);
+err_dm1105_hw_exit:
+	dm1105_hw_exit(dev);
+err_pci_iounmap:
+	pci_iounmap(pdev, dev->io_mem);
+err_pci_release_regions:
+	pci_release_regions(pdev);
+err_pci_disable_device:
+	pci_disable_device(pdev);
+err_kfree:
+	pci_set_drvdata(pdev, NULL);
+	kfree(dev);
+	return ret;
+}
+
+static void __devexit dm1105_remove(struct pci_dev *pdev)
+{
+	struct dm1105_dev *dev = pci_get_drvdata(pdev);
+	struct dvb_adapter *dvb_adapter = &dev->dvb_adapter;
+	struct dvb_demux *dvbdemux = &dev->demux;
+	struct dmx_demux *dmx = &dvbdemux->dmx;
+
+	dm1105_ir_exit(dev);
+	dmx->close(dmx);
+	dvb_net_release(&dev->dvbnet);
+	if (dev->fe)
+		dvb_unregister_frontend(dev->fe);
+
+	dmx->disconnect_frontend(dmx);
+	dmx->remove_frontend(dmx, &dev->mem_frontend);
+	dmx->remove_frontend(dmx, &dev->hw_frontend);
+	dvb_dmxdev_release(&dev->dmxdev);
+	dvb_dmx_release(dvbdemux);
+	dvb_unregister_adapter(dvb_adapter);
+	if (&dev->i2c_adap)
+		i2c_del_adapter(&dev->i2c_adap);
+
+	dm1105_hw_exit(dev);
+	synchronize_irq(pdev->irq);
+	free_irq(pdev->irq, dev);
+	pci_iounmap(pdev, dev->io_mem);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	dm1105_devcount--;
+	kfree(dev);
+}
+
+static struct pci_device_id dm1105_id_table[] __devinitdata = {
+	{
+		.vendor = PCI_VENDOR_ID_TRIGEM,
+		.device = PCI_DEVICE_ID_DM1105,
+		.subvendor = PCI_ANY_ID,
+		.subdevice = PCI_ANY_ID,
+	}, {
+		.vendor = PCI_VENDOR_ID_AXESS,
+		.device = PCI_DEVICE_ID_DM05,
+		.subvendor = PCI_ANY_ID,
+		.subdevice = PCI_ANY_ID,
+	}, {
+		/* empty */
+	},
+};
+
+MODULE_DEVICE_TABLE(pci, dm1105_id_table);
+
+static struct pci_driver dm1105_driver = {
+	.name = DRIVER_NAME,
+	.id_table = dm1105_id_table,
+	.probe = dm1105_probe,
+	.remove = __devexit_p(dm1105_remove),
+};
+
+static int __init dm1105_init(void)
+{
+	return pci_register_driver(&dm1105_driver);
+}
+
+static void __exit dm1105_exit(void)
+{
+	pci_unregister_driver(&dm1105_driver);
+}
+
+module_init(dm1105_init);
+module_exit(dm1105_exit);
+
+MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>");
+MODULE_DESCRIPTION("SDMC DM1105 DVB driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/ivtv/Kconfig b/drivers/media/pci/ivtv/Kconfig
new file mode 100644
index 0000000..89f6591
--- /dev/null
+++ b/drivers/media/pci/ivtv/Kconfig
@@ -0,0 +1,45 @@
+config VIDEO_IVTV
+	tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support"
+	depends on VIDEO_V4L2 && PCI && I2C
+	select I2C_ALGOBIT
+	depends on RC_CORE
+	select VIDEO_TUNER
+	select VIDEO_TVEEPROM
+	select VIDEO_CX2341X
+	select VIDEO_CX25840
+	select VIDEO_MSP3400
+	select VIDEO_SAA711X
+	select VIDEO_SAA717X
+	select VIDEO_SAA7127
+	select VIDEO_CS53L32A
+	select VIDEO_M52790
+	select VIDEO_WM8775
+	select VIDEO_WM8739
+	select VIDEO_VP27SMPX
+	select VIDEO_UPD64031A
+	select VIDEO_UPD64083
+	---help---
+	  This is a video4linux driver for Conexant cx23416 or cx23415 based
+	  PCI personal video recorder devices.
+
+	  This is used in devices such as the Hauppauge PVR-150/250/350/500
+	  cards. There is a driver homepage at <http://www.ivtvdriver.org>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ivtv.
+
+config VIDEO_FB_IVTV
+	tristate "Conexant cx23415 framebuffer support"
+	depends on VIDEO_IVTV && FB
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	---help---
+	  This is a framebuffer driver for the Conexant cx23415 MPEG
+	  encoder/decoder.
+
+	  This is used in the Hauppauge PVR-350 card. There is a driver
+	  homepage at <http://www.ivtvdriver.org>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ivtvfb.
diff --git a/drivers/media/pci/ivtv/Makefile b/drivers/media/pci/ivtv/Makefile
new file mode 100644
index 0000000..1408c9f
--- /dev/null
+++ b/drivers/media/pci/ivtv/Makefile
@@ -0,0 +1,14 @@
+ivtv-objs	:= ivtv-routing.o ivtv-cards.o ivtv-controls.o \
+		   ivtv-driver.o ivtv-fileops.o ivtv-firmware.o \
+		   ivtv-gpio.o ivtv-i2c.o ivtv-ioctl.o ivtv-irq.o \
+		   ivtv-mailbox.o ivtv-queue.o ivtv-streams.o ivtv-udma.o \
+		   ivtv-vbi.o ivtv-yuv.o
+
+obj-$(CONFIG_VIDEO_IVTV) += ivtv.o
+obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
+
+ccflags-y += -I$(srctree)/drivers/media/i2c
+ccflags-y += -I$(srctree)/drivers/media/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
+
diff --git a/drivers/media/pci/ivtv/ivtv-cards.c b/drivers/media/pci/ivtv/ivtv-cards.c
new file mode 100644
index 0000000..145e474
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-cards.c
@@ -0,0 +1,1370 @@
+/*
+    Functions to query card hardware
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-cards.h"
+#include "ivtv-i2c.h"
+
+#include <media/msp3400.h>
+#include <media/m52790.h>
+#include <media/wm8775.h>
+#include <media/cs53l32a.h>
+#include <media/cx25840.h>
+#include <media/upd64031a.h>
+
+#define MSP_TUNER  MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \
+				MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER)
+#define MSP_SCART1 MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \
+				MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
+#define MSP_SCART2 MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, \
+				MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
+#define MSP_SCART3 MSP_INPUT(MSP_IN_SCART3, MSP_IN_TUNER1, \
+				MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
+#define MSP_MONO   MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \
+				MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
+
+#define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM)
+
+/* usual i2c tuner addresses to probe */
+static struct ivtv_card_tuner_i2c ivtv_i2c_std = {
+	.radio = { I2C_CLIENT_END },
+	.demod = { 0x43, I2C_CLIENT_END },
+	.tv    = { 0x61, 0x60, I2C_CLIENT_END },
+};
+
+/* as above, but with possible radio tuner */
+static struct ivtv_card_tuner_i2c ivtv_i2c_radio = {
+	.radio = { 0x60, I2C_CLIENT_END },
+	.demod = { 0x43, I2C_CLIENT_END },
+	.tv    = { 0x61, I2C_CLIENT_END },
+};
+
+/* using the tda8290+75a combo */
+static struct ivtv_card_tuner_i2c ivtv_i2c_tda8290 = {
+	.radio = { I2C_CLIENT_END },
+	.demod = { I2C_CLIENT_END },
+	.tv    = { 0x4b, I2C_CLIENT_END },
+};
+
+/********************** card configuration *******************************/
+
+/* Please add new PCI IDs to: http://pci-ids.ucw.cz/ 
+   This keeps the PCI ID database up to date. Note that the entries
+   must be added under vendor 0x4444 (Conexant) as subsystem IDs.
+   New vendor IDs should still be added to the vendor ID list. */
+
+/* Hauppauge PVR-250 cards */
+
+/* Note: for Hauppauge cards the tveeprom information is used instead of PCI IDs */
+static const struct ivtv_card ivtv_card_pvr250 = {
+	.type = IVTV_CARD_PVR_250,
+	.name = "Hauppauge WinTV PVR-250",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7115,
+	.hw_audio = IVTV_HW_MSP34XX,
+	.hw_audio_ctrl = IVTV_HW_MSP34XX,
+	.hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 |
+		  IVTV_HW_TVEEPROM | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 },
+		{ IVTV_CARD_INPUT_SVIDEO2,    2, IVTV_SAA71XX_SVIDEO1    },
+		{ IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 },
+		{ IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  MSP_TUNER  },
+		{ IVTV_CARD_INPUT_LINE_IN1,   MSP_SCART1 },
+		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Hauppauge PVR-350 cards */
+
+/* Outputs for Hauppauge PVR350 cards */
+static struct ivtv_card_output ivtv_pvr350_outputs[] = {
+	{
+		.name = "S-Video + Composite",
+		.video_output = 0,
+	}, {
+		.name = "Composite",
+		.video_output = 1,
+	}, {
+		.name = "S-Video",
+		.video_output = 2,
+	}, {
+		.name = "RGB",
+		.video_output = 3,
+	}, {
+		.name = "YUV C",
+		.video_output = 4,
+	}, {
+		.name = "YUV V",
+		.video_output = 5,
+	}
+};
+
+static const struct ivtv_card ivtv_card_pvr350 = {
+	.type = IVTV_CARD_PVR_350,
+	.name = "Hauppauge WinTV PVR-350",
+	.v4l2_capabilities = IVTV_CAP_ENCODER | IVTV_CAP_DECODER,
+	.video_outputs = ivtv_pvr350_outputs,
+	.nof_outputs = ARRAY_SIZE(ivtv_pvr350_outputs),
+	.hw_video = IVTV_HW_SAA7115,
+	.hw_audio = IVTV_HW_MSP34XX,
+	.hw_audio_ctrl = IVTV_HW_MSP34XX,
+	.hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 |
+		  IVTV_HW_SAA7127 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER |
+		  IVTV_HW_I2C_IR_RX_HAUP_EXT | IVTV_HW_I2C_IR_RX_HAUP_INT,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 },
+		{ IVTV_CARD_INPUT_SVIDEO2,    2, IVTV_SAA71XX_SVIDEO1    },
+		{ IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 },
+		{ IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  MSP_TUNER  },
+		{ IVTV_CARD_INPUT_LINE_IN1,   MSP_SCART1 },
+		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
+	.i2c = &ivtv_i2c_std,
+};
+
+/* PVR-350 V1 boards have a different audio tuner input and use a
+   saa7114 instead of a saa7115.
+   Note that the info below comes from a pre-production model so it may
+   not be correct. Especially the audio behaves strangely (mono only it seems) */
+static const struct ivtv_card ivtv_card_pvr350_v1 = {
+	.type = IVTV_CARD_PVR_350_V1,
+	.name = "Hauppauge WinTV PVR-350 (V1)",
+	.v4l2_capabilities = IVTV_CAP_ENCODER | IVTV_CAP_DECODER,
+	.video_outputs = ivtv_pvr350_outputs,
+	.nof_outputs = ARRAY_SIZE(ivtv_pvr350_outputs),
+	.hw_video = IVTV_HW_SAA7114,
+	.hw_audio = IVTV_HW_MSP34XX,
+	.hw_audio_ctrl = IVTV_HW_MSP34XX,
+	.hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7114 |
+		  IVTV_HW_SAA7127 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 },
+		{ IVTV_CARD_INPUT_SVIDEO2,    2, IVTV_SAA71XX_SVIDEO1    },
+		{ IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 },
+		{ IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  MSP_MONO   },
+		{ IVTV_CARD_INPUT_LINE_IN1,   MSP_SCART1 },
+		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Hauppauge PVR-150/PVR-500 cards */
+
+static const struct ivtv_card ivtv_card_pvr150 = {
+	.type = IVTV_CARD_PVR_150,
+	.name = "Hauppauge WinTV PVR-150",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_muxer = IVTV_HW_WM8775,
+	.hw_all = IVTV_HW_WM8775 | IVTV_HW_CX25840 |
+		  IVTV_HW_TVEEPROM | IVTV_HW_TUNER |
+		  IVTV_HW_I2C_IR_RX_HAUP_EXT | IVTV_HW_I2C_IR_RX_HAUP_INT |
+		  IVTV_HW_Z8F0811_IR_HAUP,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE7 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, CX25840_SVIDEO1    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE3 },
+		{ IVTV_CARD_INPUT_SVIDEO2,    2, CX25840_SVIDEO2    },
+		{ IVTV_CARD_INPUT_COMPOSITE2, 2, CX25840_COMPOSITE4 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,
+		  CX25840_AUDIO8, WM8775_AIN2 },
+		{ IVTV_CARD_INPUT_LINE_IN1,
+		  CX25840_AUDIO_SERIAL, WM8775_AIN2 },
+		{ IVTV_CARD_INPUT_LINE_IN2,
+		  CX25840_AUDIO_SERIAL, WM8775_AIN3 },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER,
+			 CX25840_AUDIO_SERIAL, WM8775_AIN4 },
+	/* apparently needed for the IR blaster */
+	.gpio_init = { .direction = 0x1f01, .initial_value = 0x26f3 },
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* AVerMedia M179 cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_m179[] = {
+	{ PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_AVERMEDIA, 0xa3cf },
+	{ PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_AVERMEDIA, 0xa3ce },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_m179 = {
+	.type = IVTV_CARD_M179,
+	.name = "AVerMedia M179",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7114,
+	.hw_audio = IVTV_HW_GPIO,
+	.hw_audio_ctrl = IVTV_HW_GPIO,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_GPIO_TUNER   },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_GPIO_LINE_IN },
+	},
+	.gpio_init = { .direction = 0xe380, .initial_value = 0x8290 },
+	.gpio_audio_input  = { .mask = 0x8040, .tuner  = 0x8000, .linein = 0x0000 },
+	.gpio_audio_mute   = { .mask = 0x2000, .mute   = 0x2000 },
+	.gpio_audio_mode   = { .mask = 0x4300, .mono   = 0x4000, .stereo = 0x0200,
+			      .lang1 = 0x0200, .lang2  = 0x0100, .both   = 0x0000 },
+	.gpio_audio_freq   = { .mask = 0x0018, .f32000 = 0x0000,
+			     .f44100 = 0x0008, .f48000 = 0x0010 },
+	.gpio_audio_detect = { .mask = 0x4000, .stereo = 0x0000 },
+	.tuners = {
+		/* As far as we know all M179 cards use this tuner */
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_NTSC },
+	},
+	.pci_list = ivtv_pci_m179,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Yuan MPG600/Kuroutoshikou ITVC16-STVLP cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_mpg600[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0xfff3 },
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0xffff },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_mpg600 = {
+	.type = IVTV_CARD_MPG600,
+	.name = "Yuan MPG600, Kuroutoshikou ITVC16-STVLP",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7115,
+	.hw_audio = IVTV_HW_GPIO,
+	.hw_audio_ctrl = IVTV_HW_GPIO,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_GPIO_TUNER   },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_GPIO_LINE_IN },
+	},
+	.gpio_init = { .direction = 0x3080, .initial_value = 0x0004 },
+	.gpio_audio_input  = { .mask = 0x3000, .tuner  = 0x0000, .linein = 0x2000 },
+	.gpio_audio_mute   = { .mask = 0x0001, .mute   = 0x0001 },
+	.gpio_audio_mode   = { .mask = 0x000e, .mono   = 0x0006, .stereo = 0x0004,
+			      .lang1 = 0x0004, .lang2  = 0x0000, .both   = 0x0008 },
+	.gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 },
+	.tuners = {
+		/* The PAL tuner is confirmed */
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME },
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
+	},
+	.pci_list = ivtv_pci_mpg600,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Yuan MPG160/Kuroutoshikou ITVC15-STVLP cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_mpg160[] = {
+	{ PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_YUAN1, 0 },
+	{ PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_IODATA, 0x40a0 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_mpg160 = {
+	.type = IVTV_CARD_MPG160,
+	.name = "YUAN MPG160, Kuroutoshikou ITVC15-STVLP, I/O Data GV-M2TV/PCI",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7114,
+	.hw_audio = IVTV_HW_GPIO,
+	.hw_audio_ctrl = IVTV_HW_GPIO,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_GPIO_TUNER   },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_GPIO_LINE_IN },
+	},
+	.gpio_init = { .direction = 0x7080, .initial_value = 0x400c },
+	.gpio_audio_input  = { .mask = 0x3000, .tuner  = 0x0000, .linein = 0x2000 },
+	.gpio_audio_mute   = { .mask = 0x0001, .mute   = 0x0001 },
+	.gpio_audio_mode   = { .mask = 0x000e, .mono   = 0x0006, .stereo = 0x0004,
+			      .lang1 = 0x0004, .lang2  = 0x0000, .both   = 0x0008 },
+	.gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 },
+	.tuners = {
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME },
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
+	},
+	.pci_list = ivtv_pci_mpg160,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Yuan PG600/Diamond PVR-550 cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_pg600[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_DIAMONDMM, 0x0070 },
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3,     0x0600 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_pg600 = {
+	.type = IVTV_CARD_PG600,
+	.name = "Yuan PG600, Diamond PVR-550",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1,
+		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
+	},
+	.tuners = {
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME },
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
+	},
+	.pci_list = ivtv_pci_pg600,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Adaptec VideOh! AVC-2410 card */
+
+static const struct ivtv_card_pci_info ivtv_pci_avc2410[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ADAPTEC, 0x0093 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_avc2410 = {
+	.type = IVTV_CARD_AVC2410,
+	.name = "Adaptec VideOh! AVC-2410",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7115,
+	.hw_audio = IVTV_HW_MSP34XX,
+	.hw_audio_ctrl = IVTV_HW_MSP34XX,
+	.hw_muxer = IVTV_HW_CS53L32A,
+	.hw_all = IVTV_HW_MSP34XX | IVTV_HW_CS53L32A |
+		  IVTV_HW_SAA7115 | IVTV_HW_TUNER |
+		  IVTV_HW_I2C_IR_RX_ADAPTEC,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,
+		  MSP_TUNER, CS53L32A_IN0 },
+		{ IVTV_CARD_INPUT_LINE_IN1,
+		  MSP_SCART1, CS53L32A_IN2 },
+	},
+	/* This card has no eeprom and in fact the Windows driver relies
+	   on the country/region setting of the user to decide which tuner
+	   is available. */
+	.tuners = {
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+		{ .std = V4L2_STD_ALL - V4L2_STD_NTSC_M_JP,
+			.tuner = TUNER_PHILIPS_FM1236_MK3 },
+		{ .std = V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FQ1286 },
+	},
+	.pci_list = ivtv_pci_avc2410,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Adaptec VideOh! AVC-2010 card */
+
+static const struct ivtv_card_pci_info ivtv_pci_avc2010[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ADAPTEC, 0x0092 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_avc2010 = {
+	.type = IVTV_CARD_AVC2010,
+	.name = "Adaptec VideOh! AVC-2010",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7115,
+	.hw_audio = IVTV_HW_CS53L32A,
+	.hw_audio_ctrl = IVTV_HW_CS53L32A,
+	.hw_all = IVTV_HW_CS53L32A | IVTV_HW_SAA7115,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_SVIDEO1,    0, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 0, IVTV_SAA71XX_COMPOSITE3 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_LINE_IN1,   CS53L32A_IN2 },
+	},
+	/* Does not have a tuner */
+	.pci_list = ivtv_pci_avc2010,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Nagase Transgear 5000TV card */
+
+static const struct ivtv_card_pci_info ivtv_pci_tg5000tv[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xbfff },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_tg5000tv = {
+	.type = IVTV_CARD_TG5000TV,
+	.name = "Nagase Transgear 5000TV",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7114 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X |
+	IVTV_HW_GPIO,
+	.hw_audio = IVTV_HW_GPIO,
+	.hw_audio_ctrl = IVTV_HW_GPIO,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER |
+		  IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_SVIDEO0 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO2 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_GPIO_TUNER   },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_GPIO_LINE_IN },
+	},
+	.gr_config = UPD64031A_VERTICAL_EXTERNAL,
+	.gpio_init = { .direction = 0xe080, .initial_value = 0x8000 },
+	.gpio_audio_input  = { .mask = 0x8080, .tuner  = 0x8000, .linein = 0x0080 },
+	.gpio_audio_mute   = { .mask = 0x6000, .mute   = 0x6000 },
+	.gpio_audio_mode   = { .mask = 0x4300, .mono   = 0x4000, .stereo = 0x0200,
+			      .lang1 = 0x0300, .lang2  = 0x0000, .both   = 0x0200 },
+	.gpio_video_input  = { .mask = 0x0030, .tuner  = 0x0000,
+			  .composite = 0x0010, .svideo = 0x0020 },
+	.tuners = {
+		{ .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
+	},
+	.pci_list = ivtv_pci_tg5000tv,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* AOpen VA2000MAX-SNT6 card */
+
+static const struct ivtv_card_pci_info ivtv_pci_va2000[] = {
+	{ PCI_DEVICE_ID_IVTV16, 0, 0xff5f },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_va2000 = {
+	.type = IVTV_CARD_VA2000MAX_SNT6,
+	.name = "AOpen VA2000MAX-SNT6",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD6408X,
+	.hw_audio = IVTV_HW_MSP34XX,
+	.hw_audio_ctrl = IVTV_HW_MSP34XX,
+	.hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 |
+		  IVTV_HW_UPD6408X | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER },
+	},
+	.tuners = {
+		{ .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
+	},
+	.pci_list = ivtv_pci_va2000,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Yuan MPG600GR/Kuroutoshikou CX23416GYC-STVLP cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_cx23416gyc[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0x0600 },
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN4, 0x0600 },
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_MELCO, 0x0523 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_cx23416gyc = {
+	.type = IVTV_CARD_CX23416GYC,
+	.name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO |
+		IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
+	.hw_audio = IVTV_HW_SAA717X,
+	.hw_audio_ctrl = IVTV_HW_SAA717X,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER |
+		  IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_SVIDEO3 |
+						 IVTV_SAA717X_TUNER_FLAG },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO3 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_SAA717X_IN2 },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_SAA717X_IN0 },
+	},
+	.gr_config = UPD64031A_VERTICAL_EXTERNAL,
+	.gpio_init = { .direction = 0xf880, .initial_value = 0x8800 },
+	.gpio_video_input  = { .mask = 0x0020, .tuner  = 0x0000,
+			       .composite = 0x0020, .svideo = 0x0020 },
+	.gpio_audio_freq   = { .mask = 0xc000, .f32000 = 0x0000,
+			     .f44100 = 0x4000, .f48000 = 0x8000 },
+	.tuners = {
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+	},
+	.pci_list = ivtv_pci_cx23416gyc,
+	.i2c = &ivtv_i2c_std,
+};
+
+static const struct ivtv_card ivtv_card_cx23416gyc_nogr = {
+	.type = IVTV_CARD_CX23416GYC_NOGR,
+	.name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP (no GR)",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO | IVTV_HW_UPD6408X,
+	.hw_audio = IVTV_HW_SAA717X,
+	.hw_audio_ctrl = IVTV_HW_SAA717X,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER |
+		  IVTV_HW_UPD6408X,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 |
+						 IVTV_SAA717X_TUNER_FLAG },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_SAA717X_IN2 },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_SAA717X_IN0 },
+	},
+	.gpio_init = { .direction = 0xf880, .initial_value = 0x8800 },
+	.gpio_video_input  = { .mask = 0x0020, .tuner  = 0x0000,
+			       .composite = 0x0020, .svideo = 0x0020 },
+	.gpio_audio_freq   = { .mask = 0xc000, .f32000 = 0x0000,
+			     .f44100 = 0x4000, .f48000 = 0x8000 },
+	.tuners = {
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+	},
+	.i2c = &ivtv_i2c_std,
+};
+
+static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = {
+	.type = IVTV_CARD_CX23416GYC_NOGRYCS,
+	.name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP (no GR/YCS)",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO,
+	.hw_audio = IVTV_HW_SAA717X,
+	.hw_audio_ctrl = IVTV_HW_SAA717X,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 |
+						 IVTV_SAA717X_TUNER_FLAG },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_SAA717X_IN2 },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_SAA717X_IN0 },
+	},
+	.gpio_init = { .direction = 0xf880, .initial_value = 0x8800 },
+	.gpio_video_input  = { .mask = 0x0020, .tuner  = 0x0000,
+			       .composite = 0x0020, .svideo = 0x0020 },
+	.gpio_audio_freq   = { .mask = 0xc000, .f32000 = 0x0000,
+			     .f44100 = 0x4000, .f48000 = 0x8000 },
+	.tuners = {
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+	},
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* I/O Data GV-MVP/RX & GV-MVP/RX2W (dual tuner) cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_gv_mvprx[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd01e },
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd038 }, /* 2W unit #1 */
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd039 }, /* 2W unit #2 */
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_gv_mvprx = {
+	.type = IVTV_CARD_GV_MVPRX,
+	.name = "I/O Data GV-MVP/RX, GV-MVP/RX2W (dual tuner)",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
+	.hw_audio = IVTV_HW_GPIO,
+	.hw_audio_ctrl = IVTV_HW_WM8739,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_VP27SMPX |
+		  IVTV_HW_TUNER | IVTV_HW_WM8739 |
+		  IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO1    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2    },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_GPIO_TUNER   },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_GPIO_LINE_IN },
+	},
+	.gpio_init = { .direction = 0xc301, .initial_value = 0x0200 },
+	.gpio_audio_input  = { .mask = 0xffff, .tuner  = 0x0200, .linein = 0x0300 },
+	.tuners = {
+		/* This card has the Panasonic VP27 tuner */
+		{ .std = V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 },
+	},
+	.pci_list = ivtv_pci_gv_mvprx,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* I/O Data GV-MVP/RX2E card */
+
+static const struct ivtv_card_pci_info ivtv_pci_gv_mvprx2e[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd025 },
+	{0, 0, 0}
+};
+
+static const struct ivtv_card ivtv_card_gv_mvprx2e = {
+	.type = IVTV_CARD_GV_MVPRX2E,
+	.name = "I/O Data GV-MVP/RX2E",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7115,
+	.hw_audio = IVTV_HW_GPIO,
+	.hw_audio_ctrl = IVTV_HW_WM8739,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER |
+		  IVTV_HW_VP27SMPX | IVTV_HW_WM8739,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_GPIO_TUNER   },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_GPIO_LINE_IN },
+	},
+	.gpio_init = { .direction = 0xc301, .initial_value = 0x0200 },
+	.gpio_audio_input  = { .mask = 0xffff, .tuner  = 0x0200, .linein = 0x0300 },
+	.tuners = {
+		/* This card has the Panasonic VP27 tuner */
+		{ .std = V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 },
+	},
+	.pci_list = ivtv_pci_gv_mvprx2e,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* GotVIEW PCI DVD card */
+
+static const struct ivtv_card_pci_info ivtv_pci_gotview_pci_dvd[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0x0600 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_gotview_pci_dvd = {
+	.type = IVTV_CARD_GOTVIEW_PCI_DVD,
+	.name = "GotView PCI DVD",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA717X,
+	.hw_audio = IVTV_HW_SAA717X,
+	.hw_audio_ctrl = IVTV_HW_SAA717X,
+	.hw_all = IVTV_HW_SAA717X | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE1 },  /* pin 116 */
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0 },     /* pin 114/109 */
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 },  /* pin 118 */
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_SAA717X_IN0 },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_SAA717X_IN2 },
+	},
+	.gpio_init = { .direction = 0xf000, .initial_value = 0xA000 },
+	.tuners = {
+		/* This card has a Philips FQ1216ME MK3 tuner */
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+	},
+	.pci_list = ivtv_pci_gotview_pci_dvd,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* GotVIEW PCI DVD2 Deluxe card */
+
+static const struct ivtv_card_pci_info ivtv_pci_gotview_pci_dvd2[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_GOTVIEW1, 0x0600 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = {
+	.type = IVTV_CARD_GOTVIEW_PCI_DVD2,
+	.name = "GotView PCI DVD2 Deluxe",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_muxer = IVTV_HW_GPIO,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1,
+		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5,       0 },
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
+	.gpio_init = { .direction = 0x0800, .initial_value = 0 },
+	.gpio_audio_input  = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
+	.tuners = {
+		/* This card has a Philips FQ1216ME MK5 tuner */
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+	},
+	.pci_list = ivtv_pci_gotview_pci_dvd2,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Yuan MPC622 miniPCI card */
+
+static const struct ivtv_card_pci_info ivtv_pci_yuan_mpc622[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN2, 0xd998 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_yuan_mpc622 = {
+	.type = IVTV_CARD_YUAN_MPC622,
+	.name = "Yuan MPC622",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1,
+		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
+	},
+	.gpio_init = { .direction = 0x00ff, .initial_value = 0x0002 },
+	.tuners = {
+		/* This card has the TDA8290/TDA8275 tuner chips */
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_TDA8290 },
+	},
+	.pci_list = ivtv_pci_yuan_mpc622,
+	.i2c = &ivtv_i2c_tda8290,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* DIGITAL COWBOY DCT-MTVP1 card */
+
+static const struct ivtv_card_pci_info ivtv_pci_dctmvtvp1[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xbfff },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_dctmvtvp1 = {
+	.type = IVTV_CARD_DCTMTVP1,
+	.name = "Digital Cowboy DCT-MTVP1",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X |
+		IVTV_HW_GPIO,
+	.hw_audio = IVTV_HW_GPIO,
+	.hw_audio_ctrl = IVTV_HW_GPIO,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER |
+		IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO2    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_GPIO_TUNER   },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_GPIO_LINE_IN },
+	},
+	.gpio_init = { .direction = 0xe080, .initial_value = 0x8000 },
+	.gpio_audio_input  = { .mask = 0x8080, .tuner  = 0x8000, .linein = 0x0080 },
+	.gpio_audio_mute   = { .mask = 0x6000, .mute   = 0x6000 },
+	.gpio_audio_mode   = { .mask = 0x4300, .mono   = 0x4000, .stereo = 0x0200,
+			      .lang1 = 0x0300, .lang2  = 0x0000, .both   = 0x0200 },
+	.gpio_video_input  = { .mask = 0x0030, .tuner  = 0x0000,
+			       .composite = 0x0010, .svideo = 0x0020},
+	.tuners = {
+		{ .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
+	},
+	.pci_list = ivtv_pci_dctmvtvp1,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Yuan PG600-2/GotView PCI DVD Lite cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3,     0x0600 },
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_GOTVIEW2,  0x0600 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_pg600v2 = {
+	.type = IVTV_CARD_PG600V2,
+	.name = "Yuan PG600-2, GotView PCI DVD Lite",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+	/* XC2028 support apparently works for the Yuan, it's still
+	   uncertain whether it also works with the GotView. */
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1,
+		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
+	.xceive_pin = 12,
+	.tuners = {
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+	},
+	.pci_list = ivtv_pci_pg600v2,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Club3D ZAP-TV1x01 cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_club3d[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3,     0x0600 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_club3d = {
+	.type = IVTV_CARD_CLUB3D,
+	.name = "Club3D ZAP-TV1x01",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1,
+		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE3 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
+	.xceive_pin = 12,
+	.tuners = {
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+	},
+	.pci_list = ivtv_pci_club3d,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* AVerTV MCE 116 Plus (M116) card */
+
+static const struct ivtv_card_pci_info ivtv_pci_avertv_mce116[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc439 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_avertv_mce116 = {
+	.type = IVTV_CARD_AVERTV_MCE116,
+	.name = "AVerTV MCE 116 Plus",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739 |
+		  IVTV_HW_I2C_IR_RX_AVER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, CX25840_SVIDEO3    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5 },
+	/* enable line-in */
+	.gpio_init = { .direction = 0xe000, .initial_value = 0x4000 },
+	.xceive_pin = 10,
+	.tuners = {
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+	},
+	.pci_list = ivtv_pci_avertv_mce116,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* AVerMedia PVR-150 Plus / AVerTV M113 cards with a Daewoo/Partsnic Tuner */
+
+static const struct ivtv_card_pci_info ivtv_pci_aver_pvr150[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc034 }, /* NTSC */
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc035 }, /* NTSC FM */
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_aver_pvr150 = {
+	.type = IVTV_CARD_AVER_PVR150PLUS,
+	.name = "AVerMedia PVR-150 Plus / AVerTV M113 Partsnic (Daewoo) Tuner",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_muxer = IVTV_HW_GPIO,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER |
+		  IVTV_HW_WM8739 | IVTV_HW_GPIO,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, CX25840_SVIDEO3    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5,       0 },
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
+	/* The 74HC4052 Dual 4:1 multiplexer is controlled by 2 GPIO lines */
+	.gpio_init = { .direction = 0xc000, .initial_value = 0 },
+	.gpio_audio_input  = { .mask   = 0xc000,
+			       .tuner  = 0x0000,
+			       .linein = 0x4000,
+			       .radio  = 0x8000 },
+	.tuners = {
+		/* Subsystem ID's 0xc03[45] have a Partsnic PTI-5NF05 tuner */
+		{ .std = V4L2_STD_MN, .tuner = TUNER_PARTSNIC_PTI_5NF05 },
+	},
+	.pci_list = ivtv_pci_aver_pvr150,
+	/* Subsystem ID 0xc035 has a TEA5767(?) FM tuner, 0xc034 does not */
+	.i2c = &ivtv_i2c_radio,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* AVerMedia UltraTV 1500 MCE (newer non-cx88 version, M113 variant) card */
+
+static const struct ivtv_card_pci_info ivtv_pci_aver_ultra1500mce[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc019 }, /* NTSC */
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc01b }, /* PAL/SECAM */
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_aver_ultra1500mce = {
+	.type = IVTV_CARD_AVER_ULTRA1500MCE,
+	.name = "AVerMedia UltraTV 1500 MCE / AVerTV M113 Philips Tuner",
+	.comment = "For non-NTSC tuners, use the pal= or secam= module options",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_muxer = IVTV_HW_GPIO,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER |
+		  IVTV_HW_WM8739 | IVTV_HW_GPIO,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, CX25840_SVIDEO3    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5,       0 },
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
+	/* The 74HC4052 Dual 4:1 multiplexer is controlled by 2 GPIO lines */
+	.gpio_init = { .direction = 0xc000, .initial_value = 0 },
+	.gpio_audio_input  = { .mask   = 0xc000,
+			       .tuner  = 0x0000,
+			       .linein = 0x4000,
+			       .radio  = 0x8000 },
+	.tuners = {
+		/* The UltraTV 1500 MCE has a Philips FM1236 MK5 TV/FM tuner */
+		{ .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216MK5 },
+	},
+	.pci_list = ivtv_pci_aver_ultra1500mce,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* AVerMedia EZMaker PCI Deluxe card */
+
+static const struct ivtv_card_pci_info ivtv_pci_aver_ezmaker[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc03f },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_aver_ezmaker = {
+	.type = IVTV_CARD_AVER_EZMAKER,
+	.name = "AVerMedia EZMaker PCI Deluxe",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_SVIDEO1,    0, CX25840_SVIDEO3 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 0 },
+	},
+	.gpio_init = { .direction = 0x4000, .initial_value = 0x4000 },
+	/* Does not have a tuner */
+	.pci_list = ivtv_pci_aver_ezmaker,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* ASUS Falcon2 */
+
+static const struct ivtv_card_pci_info ivtv_pci_asus_falcon2[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b66 },
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x462e },
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b2e },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_asus_falcon2 = {
+	.type = IVTV_CARD_ASUS_FALCON2,
+	.name = "ASUS Falcon2",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_muxer = IVTV_HW_M52790,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_M52790 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, CX25840_SVIDEO3    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 2, CX25840_COMPOSITE2 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, M52790_IN_TUNER },
+		{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL,
+			M52790_IN_V2 | M52790_SW1_YCMIX | M52790_SW2_YCMIX },
+		{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, M52790_IN_V2 },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER },
+	.tuners = {
+		{ .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+	},
+	.pci_list = ivtv_pci_asus_falcon2,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* AVerMedia M104 miniPCI card */
+
+static const struct ivtv_card_pci_info ivtv_pci_aver_m104[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc136 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_aver_m104 = {
+	.type = IVTV_CARD_AVER_M104,
+	.name = "AVerMedia M104",
+	.comment = "Not yet supported!\n",
+	.v4l2_capabilities = 0, /*IVTV_CAP_ENCODER,*/
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_SVIDEO1,    0, CX25840_SVIDEO3    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
+	/* enable line-in + reset tuner */
+	.gpio_init = { .direction = 0xe000, .initial_value = 0x4000 },
+	.xceive_pin = 10,
+	.tuners = {
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+	},
+	.pci_list = ivtv_pci_aver_m104,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Buffalo PC-MV5L/PCI cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_buffalo[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_MELCO, 0x052b },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_buffalo = {
+	.type = IVTV_CARD_BUFFALO_MV5L,
+	.name = "Buffalo PC-MV5L/PCI",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1,
+			CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
+	},
+	.xceive_pin = 12,
+	.tuners = {
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+	},
+	.pci_list = ivtv_pci_buffalo,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+/* Sony Kikyou */
+
+static const struct ivtv_card_pci_info ivtv_pci_kikyou[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_SONY, 0x813d },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_kikyou = {
+	.type = IVTV_CARD_KIKYOU,
+	.name = "Sony VAIO Giga Pocket (ENX Kikyou)",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7115,
+	.hw_audio = IVTV_HW_GPIO,
+	.hw_audio_ctrl = IVTV_HW_GPIO,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER,
+	.video_inputs = {
+	{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE1 },
+	{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE1 },
+	{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO1 },
+	},
+	.audio_inputs = {
+	     { IVTV_CARD_INPUT_AUD_TUNER,  IVTV_GPIO_TUNER },
+	     { IVTV_CARD_INPUT_LINE_IN1,   IVTV_GPIO_LINE_IN },
+	     { IVTV_CARD_INPUT_LINE_IN2,   IVTV_GPIO_LINE_IN },
+	},
+	.gpio_init = { .direction = 0x03e1, .initial_value = 0x0320 },
+	.gpio_audio_input = { .mask   = 0x0060,
+			      .tuner  = 0x0020,
+			      .linein = 0x0000,
+			      .radio  = 0x0060 },
+	.gpio_audio_mute  = { .mask = 0x0000,
+			      .mute = 0x0000 }, /* 0x200? Disable for now. */
+	.gpio_audio_mode  = { .mask   = 0x0080,
+			      .mono   = 0x0000,
+			      .stereo = 0x0000, /* SAP */
+			      .lang1  = 0x0080,
+			      .lang2  = 0x0000,
+			      .both   = 0x0080 },
+	.tuners = {
+	     { .std = V4L2_STD_ALL, .tuner = TUNER_SONY_BTF_PXN01Z },
+	},
+	.pci_list = ivtv_pci_kikyou,
+	.i2c = &ivtv_i2c_std,
+};
+
+
+static const struct ivtv_card *ivtv_card_list[] = {
+	&ivtv_card_pvr250,
+	&ivtv_card_pvr350,
+	&ivtv_card_pvr150,
+	&ivtv_card_m179,
+	&ivtv_card_mpg600,
+	&ivtv_card_mpg160,
+	&ivtv_card_pg600,
+	&ivtv_card_avc2410,
+	&ivtv_card_avc2010,
+	&ivtv_card_tg5000tv,
+	&ivtv_card_va2000,
+	&ivtv_card_cx23416gyc,
+	&ivtv_card_gv_mvprx,
+	&ivtv_card_gv_mvprx2e,
+	&ivtv_card_gotview_pci_dvd,
+	&ivtv_card_gotview_pci_dvd2,
+	&ivtv_card_yuan_mpc622,
+	&ivtv_card_dctmvtvp1,
+	&ivtv_card_pg600v2,
+	&ivtv_card_club3d,
+	&ivtv_card_avertv_mce116,
+	&ivtv_card_asus_falcon2,
+	&ivtv_card_aver_pvr150,
+	&ivtv_card_aver_ezmaker,
+	&ivtv_card_aver_m104,
+	&ivtv_card_buffalo,
+	&ivtv_card_aver_ultra1500mce,
+	&ivtv_card_kikyou,
+
+	/* Variations of standard cards but with the same PCI IDs.
+	   These cards must come last in this list. */
+	&ivtv_card_pvr350_v1,
+	&ivtv_card_cx23416gyc_nogr,
+	&ivtv_card_cx23416gyc_nogrycs,
+};
+
+const struct ivtv_card *ivtv_get_card(u16 index)
+{
+	if (index >= ARRAY_SIZE(ivtv_card_list))
+		return NULL;
+	return ivtv_card_list[index];
+}
+
+int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input)
+{
+	const struct ivtv_card_video_input *card_input = itv->card->video_inputs + index;
+	static const char * const input_strs[] = {
+		"Tuner 1",
+		"S-Video 1",
+		"S-Video 2",
+		"Composite 1",
+		"Composite 2",
+		"Composite 3"
+	};
+
+	if (index >= itv->nof_inputs)
+		return -EINVAL;
+	input->index = index;
+	strlcpy(input->name, input_strs[card_input->video_type - 1],
+			sizeof(input->name));
+	input->type = (card_input->video_type == IVTV_CARD_INPUT_VID_TUNER ?
+			V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA);
+	input->audioset = (1 << itv->nof_audio_inputs) - 1;
+	input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ?
+				itv->tuner_std : V4L2_STD_ALL;
+	return 0;
+}
+
+int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output)
+{
+	const struct ivtv_card_output *card_output = itv->card->video_outputs + index;
+
+	if (index >= itv->card->nof_outputs)
+		return -EINVAL;
+	output->index = index;
+	strlcpy(output->name, card_output->name, sizeof(output->name));
+	output->type = V4L2_OUTPUT_TYPE_ANALOG;
+	output->audioset = 1;
+	output->std = V4L2_STD_ALL;
+	return 0;
+}
+
+int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *audio)
+{
+	const struct ivtv_card_audio_input *aud_input = itv->card->audio_inputs + index;
+	static const char * const input_strs[] = {
+		"Tuner 1",
+		"Line In 1",
+		"Line In 2"
+	};
+
+	memset(audio, 0, sizeof(*audio));
+	if (index >= itv->nof_audio_inputs)
+		return -EINVAL;
+	strlcpy(audio->name, input_strs[aud_input->audio_type - 1],
+			sizeof(audio->name));
+	audio->index = index;
+	audio->capability = V4L2_AUDCAP_STEREO;
+	return 0;
+}
+
+int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *aud_output)
+{
+	memset(aud_output, 0, sizeof(*aud_output));
+	if (itv->card->video_outputs == NULL || index != 0)
+		return -EINVAL;
+	strlcpy(aud_output->name, "A/V Audio Out", sizeof(aud_output->name));
+	return 0;
+}
diff --git a/drivers/media/pci/ivtv/ivtv-cards.h b/drivers/media/pci/ivtv/ivtv-cards.h
new file mode 100644
index 0000000..e6f5c02
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-cards.h
@@ -0,0 +1,309 @@
+/*
+    Functions to query card hardware
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef IVTV_CARDS_H
+#define IVTV_CARDS_H
+
+/* Supported cards */
+#define IVTV_CARD_PVR_250 	      0	/* WinTV PVR 250 */
+#define IVTV_CARD_PVR_350 	      1	/* encoder, decoder, tv-out */
+#define IVTV_CARD_PVR_150 	      2	/* WinTV PVR 150 and PVR 500 (really just two
+					   PVR150s on one PCI board) */
+#define IVTV_CARD_M179    	      3	/* AVerMedia M179 (encoder only) */
+#define IVTV_CARD_MPG600  	      4	/* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */
+#define IVTV_CARD_MPG160  	      5	/* Kuroutoshikou ITVC15-STVLP/YUAN MPG160
+					   cx23415 based, but does not have tv-out */
+#define IVTV_CARD_PG600 	      6	/* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */
+#define IVTV_CARD_AVC2410 	      7	/* Adaptec AVC-2410 */
+#define IVTV_CARD_AVC2010 	      8	/* Adaptec AVD-2010 (No Tuner) */
+#define IVTV_CARD_TG5000TV   	      9 /* NAGASE TRANSGEAR 5000TV, encoder only */
+#define IVTV_CARD_VA2000MAX_SNT6     10 /* VA2000MAX-STN6 */
+#define IVTV_CARD_CX23416GYC 	     11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */
+#define IVTV_CARD_GV_MVPRX   	     12 /* I/O Data GV-MVP/RX, RX2, RX2W */
+#define IVTV_CARD_GV_MVPRX2E 	     13 /* I/O Data GV-MVP/RX2E */
+#define IVTV_CARD_GOTVIEW_PCI_DVD    14	/* GotView PCI DVD */
+#define IVTV_CARD_GOTVIEW_PCI_DVD2   15	/* GotView PCI DVD2 */
+#define IVTV_CARD_YUAN_MPC622        16	/* Yuan MPC622 miniPCI */
+#define IVTV_CARD_DCTMTVP1 	     17 /* DIGITAL COWBOY DCT-MTVP1 */
+#define IVTV_CARD_PG600V2	     18 /* Yuan PG600V2/GotView PCI DVD Lite */
+#define IVTV_CARD_CLUB3D	     19 /* Club3D ZAP-TV1x01 */
+#define IVTV_CARD_AVERTV_MCE116	     20 /* AVerTV MCE 116 Plus */
+#define IVTV_CARD_ASUS_FALCON2	     21 /* ASUS Falcon2 */
+#define IVTV_CARD_AVER_PVR150PLUS    22 /* AVerMedia PVR-150 Plus */
+#define IVTV_CARD_AVER_EZMAKER       23 /* AVerMedia EZMaker PCI Deluxe */
+#define IVTV_CARD_AVER_M104          24 /* AverMedia M104 miniPCI card */
+#define IVTV_CARD_BUFFALO_MV5L       25 /* Buffalo PC-MV5L/PCI card */
+#define IVTV_CARD_AVER_ULTRA1500MCE  26 /* AVerMedia UltraTV 1500 MCE */
+#define IVTV_CARD_KIKYOU             27 /* Sony VAIO Giga Pocket (ENX Kikyou) */
+#define IVTV_CARD_LAST 		     27
+
+/* Variants of existing cards but with the same PCI IDs. The driver
+   detects these based on other device information.
+   These cards must always come last.
+   New cards must be inserted above, and the indices of the cards below
+   must be adjusted accordingly. */
+
+/* PVR-350 V1 (uses saa7114) */
+#define IVTV_CARD_PVR_350_V1 	     (IVTV_CARD_LAST+1)
+/* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */
+#define IVTV_CARD_CX23416GYC_NOGR    (IVTV_CARD_LAST+2)
+#define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3)
+
+/* system vendor and device IDs */
+#define PCI_VENDOR_ID_ICOMP  0x4444
+#define PCI_DEVICE_ID_IVTV15 0x0803
+#define PCI_DEVICE_ID_IVTV16 0x0016
+
+/* subsystem vendor ID */
+#define IVTV_PCI_ID_HAUPPAUGE 		0x0070
+#define IVTV_PCI_ID_HAUPPAUGE_ALT1 	0x0270
+#define IVTV_PCI_ID_HAUPPAUGE_ALT2 	0x4070
+#define IVTV_PCI_ID_ADAPTEC 		0x9005
+#define IVTV_PCI_ID_ASUSTEK 		0x1043
+#define IVTV_PCI_ID_AVERMEDIA 		0x1461
+#define IVTV_PCI_ID_YUAN1		0x12ab
+#define IVTV_PCI_ID_YUAN2 		0xff01
+#define IVTV_PCI_ID_YUAN3 		0xffab
+#define IVTV_PCI_ID_YUAN4 		0xfbab
+#define IVTV_PCI_ID_DIAMONDMM 		0xff92
+#define IVTV_PCI_ID_IODATA 		0x10fc
+#define IVTV_PCI_ID_MELCO 		0x1154
+#define IVTV_PCI_ID_GOTVIEW1		0xffac
+#define IVTV_PCI_ID_GOTVIEW2 		0xffad
+#define IVTV_PCI_ID_SONY 		0x104d
+
+/* hardware flags, no gaps allowed */
+#define IVTV_HW_CX25840			(1 << 0)
+#define IVTV_HW_SAA7115			(1 << 1)
+#define IVTV_HW_SAA7127			(1 << 2)
+#define IVTV_HW_MSP34XX			(1 << 3)
+#define IVTV_HW_TUNER			(1 << 4)
+#define IVTV_HW_WM8775			(1 << 5)
+#define IVTV_HW_CS53L32A		(1 << 6)
+#define IVTV_HW_TVEEPROM		(1 << 7)
+#define IVTV_HW_SAA7114			(1 << 8)
+#define IVTV_HW_UPD64031A		(1 << 9)
+#define IVTV_HW_UPD6408X		(1 << 10)
+#define IVTV_HW_SAA717X			(1 << 11)
+#define IVTV_HW_WM8739			(1 << 12)
+#define IVTV_HW_VP27SMPX		(1 << 13)
+#define IVTV_HW_M52790			(1 << 14)
+#define IVTV_HW_GPIO			(1 << 15)
+#define IVTV_HW_I2C_IR_RX_AVER		(1 << 16)
+#define IVTV_HW_I2C_IR_RX_HAUP_EXT	(1 << 17) /* External before internal */
+#define IVTV_HW_I2C_IR_RX_HAUP_INT	(1 << 18)
+#define IVTV_HW_Z8F0811_IR_TX_HAUP	(1 << 19)
+#define IVTV_HW_Z8F0811_IR_RX_HAUP	(1 << 20)
+#define IVTV_HW_I2C_IR_RX_ADAPTEC	(1 << 21)
+
+#define IVTV_HW_Z8F0811_IR_HAUP	(IVTV_HW_Z8F0811_IR_RX_HAUP | \
+				 IVTV_HW_Z8F0811_IR_TX_HAUP)
+
+#define IVTV_HW_SAA711X   (IVTV_HW_SAA7115 | IVTV_HW_SAA7114)
+
+#define IVTV_HW_IR_RX_ANY (IVTV_HW_I2C_IR_RX_AVER | \
+			   IVTV_HW_I2C_IR_RX_HAUP_EXT | \
+			   IVTV_HW_I2C_IR_RX_HAUP_INT | \
+			   IVTV_HW_Z8F0811_IR_RX_HAUP | \
+			   IVTV_HW_I2C_IR_RX_ADAPTEC)
+
+#define IVTV_HW_IR_TX_ANY (IVTV_HW_Z8F0811_IR_TX_HAUP)
+
+#define IVTV_HW_IR_ANY	  (IVTV_HW_IR_RX_ANY | IVTV_HW_IR_TX_ANY)
+
+/* video inputs */
+#define	IVTV_CARD_INPUT_VID_TUNER	1
+#define	IVTV_CARD_INPUT_SVIDEO1 	2
+#define	IVTV_CARD_INPUT_SVIDEO2 	3
+#define	IVTV_CARD_INPUT_COMPOSITE1 	4
+#define	IVTV_CARD_INPUT_COMPOSITE2 	5
+#define	IVTV_CARD_INPUT_COMPOSITE3 	6
+
+/* audio inputs */
+#define	IVTV_CARD_INPUT_AUD_TUNER	1
+#define	IVTV_CARD_INPUT_LINE_IN1 	2
+#define	IVTV_CARD_INPUT_LINE_IN2 	3
+
+#define IVTV_CARD_MAX_VIDEO_INPUTS 6
+#define IVTV_CARD_MAX_AUDIO_INPUTS 3
+#define IVTV_CARD_MAX_TUNERS  	   3
+
+/* SAA71XX HW inputs */
+#define IVTV_SAA71XX_COMPOSITE0 0
+#define IVTV_SAA71XX_COMPOSITE1 1
+#define IVTV_SAA71XX_COMPOSITE2 2
+#define IVTV_SAA71XX_COMPOSITE3 3
+#define IVTV_SAA71XX_COMPOSITE4 4
+#define IVTV_SAA71XX_COMPOSITE5 5
+#define IVTV_SAA71XX_SVIDEO0    6
+#define IVTV_SAA71XX_SVIDEO1    7
+#define IVTV_SAA71XX_SVIDEO2    8
+#define IVTV_SAA71XX_SVIDEO3    9
+
+/* SAA717X needs to mark the tuner input by ORing with this flag */
+#define IVTV_SAA717X_TUNER_FLAG 0x80
+
+/* Dummy HW input */
+#define IVTV_DUMMY_AUDIO        0
+
+/* GPIO HW inputs */
+#define IVTV_GPIO_TUNER   0
+#define IVTV_GPIO_LINE_IN 1
+
+/* SAA717X HW inputs */
+#define IVTV_SAA717X_IN0 0
+#define IVTV_SAA717X_IN1 1
+#define IVTV_SAA717X_IN2 2
+
+/* V4L2 capability aliases */
+#define IVTV_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
+			  V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE | \
+			  V4L2_CAP_SLICED_VBI_CAPTURE)
+#define IVTV_CAP_DECODER (V4L2_CAP_VIDEO_OUTPUT | \
+			  V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_OVERLAY)
+
+struct ivtv_card_video_input {
+	u8  video_type; 	/* video input type */
+	u8  audio_index;	/* index in ivtv_card_audio_input array */
+	u16 video_input;	/* hardware video input */
+};
+
+struct ivtv_card_audio_input {
+	u8  audio_type;		/* audio input type */
+	u32 audio_input;	/* hardware audio input */
+	u16 muxer_input;	/* hardware muxer input for boards with a
+				   multiplexer chip */
+};
+
+struct ivtv_card_output {
+	u8  name[32];
+	u16 video_output;  /* hardware video output */
+};
+
+struct ivtv_card_pci_info {
+	u16 device;
+	u16 subsystem_vendor;
+	u16 subsystem_device;
+};
+
+/* GPIO definitions */
+
+/* The mask is the set of bits used by the operation */
+
+struct ivtv_gpio_init { 	/* set initial GPIO DIR and OUT values */
+	u16 direction; 		/* DIR setting. Leave to 0 if no init is needed */
+	u16 initial_value;
+};
+
+struct ivtv_gpio_video_input { 	/* select tuner/line in input */
+	u16 mask; 		/* leave to 0 if not supported */
+	u16 tuner;
+	u16 composite;
+	u16 svideo;
+};
+
+struct ivtv_gpio_audio_input { 	/* select tuner/line in input */
+	u16 mask; 		/* leave to 0 if not supported */
+	u16 tuner;
+	u16 linein;
+	u16 radio;
+};
+
+struct ivtv_gpio_audio_mute {
+	u16 mask; 		/* leave to 0 if not supported */
+	u16 mute;		/* set this value to mute, 0 to unmute */
+};
+
+struct ivtv_gpio_audio_mode {
+	u16 mask; 		/* leave to 0 if not supported */
+	u16 mono; 		/* set audio to mono */
+	u16 stereo; 		/* set audio to stereo */
+	u16 lang1;		/* set audio to the first language */
+	u16 lang2;		/* set audio to the second language */
+	u16 both; 		/* both languages are output */
+};
+
+struct ivtv_gpio_audio_freq {
+	u16 mask; 		/* leave to 0 if not supported */
+	u16 f32000;
+	u16 f44100;
+	u16 f48000;
+};
+
+struct ivtv_gpio_audio_detect {
+	u16 mask; 		/* leave to 0 if not supported */
+	u16 stereo; 		/* if the input matches this value then
+				   stereo is detected */
+};
+
+struct ivtv_card_tuner {
+	v4l2_std_id std; 	/* standard for which the tuner is suitable */
+	int 	    tuner; 	/* tuner ID (from tuner.h) */
+};
+
+struct ivtv_card_tuner_i2c {
+	unsigned short radio[2];/* radio tuner i2c address to probe */
+	unsigned short demod[2];/* demodulator i2c address to probe */
+	unsigned short tv[4];	/* tv tuner i2c addresses to probe */
+};
+
+/* for card information/parameters */
+struct ivtv_card {
+	int type;
+	char *name;
+	char *comment;
+	u32 v4l2_capabilities;
+	u32 hw_video;		/* hardware used to process video */
+	u32 hw_audio;		/* hardware used to process audio */
+	u32 hw_audio_ctrl;	/* hardware used for the V4L2 controls (only 1 dev allowed) */
+	u32 hw_muxer;		/* hardware used to multiplex audio input */
+	u32 hw_all;		/* all hardware used by the board */
+	struct ivtv_card_video_input video_inputs[IVTV_CARD_MAX_VIDEO_INPUTS];
+	struct ivtv_card_audio_input audio_inputs[IVTV_CARD_MAX_AUDIO_INPUTS];
+	struct ivtv_card_audio_input radio_input;
+	int nof_outputs;
+	const struct ivtv_card_output *video_outputs;
+	u8 gr_config; 		/* config byte for the ghost reduction device */
+	u8 xceive_pin; 		/* XCeive tuner GPIO reset pin */
+
+	/* GPIO card-specific settings */
+	struct ivtv_gpio_init 		gpio_init;
+	struct ivtv_gpio_video_input	gpio_video_input;
+	struct ivtv_gpio_audio_input 	gpio_audio_input;
+	struct ivtv_gpio_audio_mute 	gpio_audio_mute;
+	struct ivtv_gpio_audio_mode 	gpio_audio_mode;
+	struct ivtv_gpio_audio_freq 	gpio_audio_freq;
+	struct ivtv_gpio_audio_detect 	gpio_audio_detect;
+
+	struct ivtv_card_tuner tuners[IVTV_CARD_MAX_TUNERS];
+	struct ivtv_card_tuner_i2c *i2c;
+
+	/* list of device and subsystem vendor/devices that
+	   correspond to this card type. */
+	const struct ivtv_card_pci_info *pci_list;
+};
+
+int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input);
+int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output);
+int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *input);
+int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *output);
+const struct ivtv_card *ivtv_get_card(u16 index);
+
+#endif
diff --git a/drivers/media/pci/ivtv/ivtv-controls.c b/drivers/media/pci/ivtv/ivtv-controls.c
new file mode 100644
index 0000000..c604246
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-controls.c
@@ -0,0 +1,163 @@
+/*
+    ioctl control functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-controls.h"
+#include "ivtv-mailbox.h"
+
+static int ivtv_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt)
+{
+	struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl);
+
+	/* First try to allocate sliced VBI buffers if needed. */
+	if (fmt && itv->vbi.sliced_mpeg_data[0] == NULL) {
+		int i;
+
+		for (i = 0; i < IVTV_VBI_FRAMES; i++) {
+			/* Yuck, hardcoded. Needs to be a define */
+			itv->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL);
+			if (itv->vbi.sliced_mpeg_data[i] == NULL) {
+				while (--i >= 0) {
+					kfree(itv->vbi.sliced_mpeg_data[i]);
+					itv->vbi.sliced_mpeg_data[i] = NULL;
+				}
+				return -ENOMEM;
+			}
+		}
+	}
+
+	itv->vbi.insert_mpeg = fmt;
+
+	if (itv->vbi.insert_mpeg == 0) {
+		return 0;
+	}
+	/* Need sliced data for mpeg insertion */
+	if (ivtv_get_service_set(itv->vbi.sliced_in) == 0) {
+		if (itv->is_60hz)
+			itv->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525;
+		else
+			itv->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
+		ivtv_expand_service_set(itv->vbi.sliced_in, itv->is_50hz);
+	}
+	return 0;
+}
+
+static int ivtv_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val)
+{
+	struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl);
+	int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+	struct v4l2_mbus_framefmt fmt;
+
+	/* fix videodecoder resolution */
+	fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1);
+	fmt.height = cxhdl->height;
+	fmt.code = V4L2_MBUS_FMT_FIXED;
+	v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &fmt);
+	return 0;
+}
+
+static int ivtv_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx)
+{
+	static const u32 freqs[3] = { 44100, 48000, 32000 };
+	struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl);
+
+	/* The audio clock of the digitizer must match the codec sample
+	   rate otherwise you get some very strange effects. */
+	if (idx < ARRAY_SIZE(freqs))
+		ivtv_call_all(itv, audio, s_clock_freq, freqs[idx]);
+	return 0;
+}
+
+static int ivtv_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val)
+{
+	struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl);
+
+	itv->dualwatch_stereo_mode = val;
+	return 0;
+}
+
+struct cx2341x_handler_ops ivtv_cxhdl_ops = {
+	.s_audio_mode = ivtv_s_audio_mode,
+	.s_audio_sampling_freq = ivtv_s_audio_sampling_freq,
+	.s_video_encoding = ivtv_s_video_encoding,
+	.s_stream_vbi_fmt = ivtv_s_stream_vbi_fmt,
+};
+
+int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+
+	if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) {
+		*pts = (s64)((u64)itv->last_dec_timing[2] << 32) |
+			(u64)itv->last_dec_timing[1];
+		*frame = itv->last_dec_timing[0];
+		return 0;
+	}
+	*pts = 0;
+	*frame = 0;
+	if (atomic_read(&itv->decoding)) {
+		if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) {
+			IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n");
+			return -EIO;
+		}
+		memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing));
+		set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
+		*pts = (s64)((u64) data[2] << 32) | (u64) data[1];
+		*frame = data[0];
+		/*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/
+	}
+	return 0;
+}
+
+static int ivtv_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ivtv *itv = container_of(ctrl->handler, struct ivtv, cxhdl.hdl);
+
+	switch (ctrl->id) {
+	/* V4L2_CID_MPEG_VIDEO_DEC_PTS and V4L2_CID_MPEG_VIDEO_DEC_FRAME
+	   control cluster */
+	case V4L2_CID_MPEG_VIDEO_DEC_PTS:
+		return ivtv_g_pts_frame(itv, &itv->ctrl_pts->val64,
+					     &itv->ctrl_frame->val64);
+	}
+	return 0;
+}
+
+static int ivtv_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ivtv *itv = container_of(ctrl->handler, struct ivtv, cxhdl.hdl);
+
+	switch (ctrl->id) {
+	/* V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK and MULTILINGUAL_PLAYBACK
+	   control cluster */
+	case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
+		itv->audio_stereo_mode = itv->ctrl_audio_playback->val - 1;
+		itv->audio_bilingual_mode = itv->ctrl_audio_multilingual_playback->val - 1;
+		ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
+		break;
+	}
+	return 0;
+}
+
+const struct v4l2_ctrl_ops ivtv_hdl_out_ops = {
+	.s_ctrl = ivtv_s_ctrl,
+	.g_volatile_ctrl = ivtv_g_volatile_ctrl,
+};
diff --git a/drivers/media/pci/ivtv/ivtv-controls.h b/drivers/media/pci/ivtv/ivtv-controls.h
new file mode 100644
index 0000000..3999e63
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-controls.h
@@ -0,0 +1,28 @@
+/*
+    ioctl control functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef IVTV_CONTROLS_H
+#define IVTV_CONTROLS_H
+
+extern struct cx2341x_handler_ops ivtv_cxhdl_ops;
+extern const struct v4l2_ctrl_ops ivtv_hdl_out_ops;
+int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame);
+
+#endif
diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c
new file mode 100644
index 0000000..5462ce2
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-driver.c
@@ -0,0 +1,1498 @@
+/*
+    ivtv driver initialization and card probing
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* Main Driver file for the ivtv project:
+ * Driver for the Conexant CX23415/CX23416 chip.
+ * Author: Kevin Thayer (nufan_wfk at yahoo.com)
+ * License: GPL
+ * http://www.ivtvdriver.org
+ *
+ * -----
+ * MPG600/MPG160 support by  T.Adachi <tadachi@tadachi-net.com>
+ *                      and Takeru KOMORIYA<komoriya@paken.org>
+ *
+ * AVerMedia M179 GPIO info by Chris Pinkham <cpinkham@bc2va.org>
+ *                using information provided by Jiun-Kuei Jung @ AVerMedia.
+ *
+ * Kurouto Sikou CX23416GYC-STVLP tested by K.Ohta <alpha292@bremen.or.jp>
+ *                using information from T.Adachi,Takeru KOMORIYA and others :-)
+ *
+ * Nagase TRANSGEAR 5000TV, Aopen VA2000MAX-STN6 and I/O data GV-MVP/RX
+ *                version by T.Adachi. Special thanks  Mr.Suzuki
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-version.h"
+#include "ivtv-fileops.h"
+#include "ivtv-i2c.h"
+#include "ivtv-firmware.h"
+#include "ivtv-queue.h"
+#include "ivtv-udma.h"
+#include "ivtv-irq.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-streams.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-cards.h"
+#include "ivtv-vbi.h"
+#include "ivtv-routing.h"
+#include "ivtv-controls.h"
+#include "ivtv-gpio.h"
+#include <linux/dma-mapping.h>
+#include <media/tveeprom.h>
+#include <media/saa7115.h>
+#include <media/v4l2-chip-ident.h>
+#include "tuner-xc2028.h"
+
+/* If you have already X v4l cards, then set this to X. This way
+   the device numbers stay matched. Example: you have a WinTV card
+   without radio and a PVR-350 with. Normally this would give a
+   video1 device together with a radio0 device for the PVR. By
+   setting this to 1 you ensure that radio0 is now also radio1. */
+int ivtv_first_minor;
+
+/* add your revision and whatnot here */
+static struct pci_device_id ivtv_pci_tbl[] __devinitdata = {
+	{PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV16,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl);
+
+/* ivtv instance counter */
+static atomic_t ivtv_instance = ATOMIC_INIT(0);
+
+/* Parameter declarations */
+static int cardtype[IVTV_MAX_CARDS];
+static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1 };
+static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1 };
+static int i2c_clock_period[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+					       -1, -1, -1, -1, -1, -1, -1, -1,
+					       -1, -1, -1, -1, -1, -1, -1, -1,
+					       -1, -1, -1, -1, -1, -1, -1, -1 };
+
+static unsigned int cardtype_c = 1;
+static unsigned int tuner_c = 1;
+static int radio_c = 1;
+static unsigned int i2c_clock_period_c = 1;
+static char pal[] = "---";
+static char secam[] = "--";
+static char ntsc[] = "-";
+
+/* Buffers */
+
+/* DMA Buffers, Default size in MB allocated */
+#define IVTV_DEFAULT_ENC_MPG_BUFFERS 4
+#define IVTV_DEFAULT_ENC_YUV_BUFFERS 2
+#define IVTV_DEFAULT_ENC_VBI_BUFFERS 1
+/* Exception: size in kB for this stream (MB is overkill) */
+#define IVTV_DEFAULT_ENC_PCM_BUFFERS 320
+#define IVTV_DEFAULT_DEC_MPG_BUFFERS 1
+#define IVTV_DEFAULT_DEC_YUV_BUFFERS 1
+/* Exception: size in kB for this stream (MB is way overkill) */
+#define IVTV_DEFAULT_DEC_VBI_BUFFERS 64
+
+static int enc_mpg_buffers = IVTV_DEFAULT_ENC_MPG_BUFFERS;
+static int enc_yuv_buffers = IVTV_DEFAULT_ENC_YUV_BUFFERS;
+static int enc_vbi_buffers = IVTV_DEFAULT_ENC_VBI_BUFFERS;
+static int enc_pcm_buffers = IVTV_DEFAULT_ENC_PCM_BUFFERS;
+static int dec_mpg_buffers = IVTV_DEFAULT_DEC_MPG_BUFFERS;
+static int dec_yuv_buffers = IVTV_DEFAULT_DEC_YUV_BUFFERS;
+static int dec_vbi_buffers = IVTV_DEFAULT_DEC_VBI_BUFFERS;
+
+static int ivtv_yuv_mode;
+static int ivtv_yuv_threshold = -1;
+static int ivtv_pci_latency = 1;
+
+int ivtv_debug;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+int ivtv_fw_debug;
+#endif
+
+static int tunertype = -1;
+static int newi2c = -1;
+
+module_param_array(tuner, int, &tuner_c, 0644);
+module_param_array(radio, int, &radio_c, 0644);
+module_param_array(cardtype, int, &cardtype_c, 0644);
+module_param_string(pal, pal, sizeof(pal), 0644);
+module_param_string(secam, secam, sizeof(secam), 0644);
+module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
+module_param_named(debug,ivtv_debug, int, 0644);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+module_param_named(fw_debug, ivtv_fw_debug, int, 0644);
+#endif
+module_param(ivtv_pci_latency, int, 0644);
+module_param(ivtv_yuv_mode, int, 0644);
+module_param(ivtv_yuv_threshold, int, 0644);
+module_param(ivtv_first_minor, int, 0644);
+
+module_param(enc_mpg_buffers, int, 0644);
+module_param(enc_yuv_buffers, int, 0644);
+module_param(enc_vbi_buffers, int, 0644);
+module_param(enc_pcm_buffers, int, 0644);
+module_param(dec_mpg_buffers, int, 0644);
+module_param(dec_yuv_buffers, int, 0644);
+module_param(dec_vbi_buffers, int, 0644);
+
+module_param(tunertype, int, 0644);
+module_param(newi2c, int, 0644);
+module_param_array(i2c_clock_period, int, &i2c_clock_period_c, 0644);
+
+MODULE_PARM_DESC(tuner, "Tuner type selection,\n"
+			"\t\t\tsee tuner.h for values");
+MODULE_PARM_DESC(radio,
+		 "Enable or disable the radio. Use only if autodetection\n"
+		 "\t\t\tfails. 0 = disable, 1 = enable");
+MODULE_PARM_DESC(cardtype,
+		 "Only use this option if your card is not detected properly.\n"
+		 "\t\tSpecify card type:\n"
+		 "\t\t\t 1 = WinTV PVR 250\n"
+		 "\t\t\t 2 = WinTV PVR 350\n"
+		 "\t\t\t 3 = WinTV PVR-150 or PVR-500\n"
+		 "\t\t\t 4 = AVerMedia M179\n"
+		 "\t\t\t 5 = YUAN MPG600/Kuroutoshikou iTVC16-STVLP\n"
+		 "\t\t\t 6 = YUAN MPG160/Kuroutoshikou iTVC15-STVLP\n"
+		 "\t\t\t 7 = YUAN PG600/DIAMONDMM PVR-550 (CX Falcon 2)\n"
+		 "\t\t\t 8 = Adaptec AVC-2410\n"
+		 "\t\t\t 9 = Adaptec AVC-2010\n"
+		 "\t\t\t10 = NAGASE TRANSGEAR 5000TV\n"
+		 "\t\t\t11 = AOpen VA2000MAX-STN6\n"
+		 "\t\t\t12 = YUAN MPG600GR/Kuroutoshikou CX23416GYC-STVLP\n"
+		 "\t\t\t13 = I/O Data GV-MVP/RX\n"
+		 "\t\t\t14 = I/O Data GV-MVP/RX2E\n"
+		 "\t\t\t15 = GOTVIEW PCI DVD\n"
+		 "\t\t\t16 = GOTVIEW PCI DVD2 Deluxe\n"
+		 "\t\t\t17 = Yuan MPC622\n"
+		 "\t\t\t18 = Digital Cowboy DCT-MTVP1\n"
+		 "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite\n"
+		 "\t\t\t20 = Club3D ZAP-TV1x01\n"
+		 "\t\t\t21 = AverTV MCE 116 Plus\n"
+		 "\t\t\t22 = ASUS Falcon2\n"
+		 "\t\t\t23 = AverMedia PVR-150 Plus\n"
+		 "\t\t\t24 = AverMedia EZMaker PCI Deluxe\n"
+		 "\t\t\t25 = AverMedia M104 (not yet working)\n"
+		 "\t\t\t26 = Buffalo PC-MV5L/PCI\n"
+		 "\t\t\t27 = AVerMedia UltraTV 1500 MCE\n"
+		 "\t\t\t28 = Sony VAIO Giga Pocket (ENX Kikyou)\n"
+		 "\t\t\t 0 = Autodetect (default)\n"
+		 "\t\t\t-1 = Ignore this card\n\t\t");
+MODULE_PARM_DESC(pal, "Set PAL standard: BGH, DK, I, M, N, Nc, 60");
+MODULE_PARM_DESC(secam, "Set SECAM standard: BGH, DK, L, LC");
+MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J (Japan), K (South Korea)");
+MODULE_PARM_DESC(tunertype,
+		"Specify tuner type:\n"
+		"\t\t\t 0 = tuner for PAL-B/G/H/D/K/I, SECAM-B/G/H/D/K/L/Lc\n"
+		"\t\t\t 1 = tuner for NTSC-M/J/K, PAL-M/N/Nc\n"
+		"\t\t\t-1 = Autodetect (default)\n");
+MODULE_PARM_DESC(debug,
+		 "Debug level (bitmask). Default: 0\n"
+		 "\t\t\t   1/0x0001: warning\n"
+		 "\t\t\t   2/0x0002: info\n"
+		 "\t\t\t   4/0x0004: mailbox\n"
+		 "\t\t\t   8/0x0008: ioctl\n"
+		 "\t\t\t  16/0x0010: file\n"
+		 "\t\t\t  32/0x0020: dma\n"
+		 "\t\t\t  64/0x0040: irq\n"
+		 "\t\t\t 128/0x0080: decoder\n"
+		 "\t\t\t 256/0x0100: yuv\n"
+		 "\t\t\t 512/0x0200: i2c\n"
+		 "\t\t\t1024/0x0400: high volume\n");
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+MODULE_PARM_DESC(fw_debug,
+		 "Enable code for debugging firmware problems.  Default: 0\n");
+#endif
+MODULE_PARM_DESC(ivtv_pci_latency,
+		 "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
+		 "\t\t\tDefault: Yes");
+MODULE_PARM_DESC(ivtv_yuv_mode,
+		 "Specify the yuv playback mode:\n"
+		 "\t\t\t0 = interlaced\n\t\t\t1 = progressive\n\t\t\t2 = auto\n"
+		 "\t\t\tDefault: 0 (interlaced)");
+MODULE_PARM_DESC(ivtv_yuv_threshold,
+		 "If ivtv_yuv_mode is 2 (auto) then playback content as\n\t\tprogressive if src height <= ivtv_yuvthreshold\n"
+		 "\t\t\tDefault: 480");
+MODULE_PARM_DESC(enc_mpg_buffers,
+		 "Encoder MPG Buffers (in MB)\n"
+		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_MPG_BUFFERS));
+MODULE_PARM_DESC(enc_yuv_buffers,
+		 "Encoder YUV Buffers (in MB)\n"
+		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_YUV_BUFFERS));
+MODULE_PARM_DESC(enc_vbi_buffers,
+		 "Encoder VBI Buffers (in MB)\n"
+		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_VBI_BUFFERS));
+MODULE_PARM_DESC(enc_pcm_buffers,
+		 "Encoder PCM buffers (in kB)\n"
+		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_PCM_BUFFERS));
+MODULE_PARM_DESC(dec_mpg_buffers,
+		 "Decoder MPG buffers (in MB)\n"
+		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_MPG_BUFFERS));
+MODULE_PARM_DESC(dec_yuv_buffers,
+		 "Decoder YUV buffers (in MB)\n"
+		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_YUV_BUFFERS));
+MODULE_PARM_DESC(dec_vbi_buffers,
+		 "Decoder VBI buffers (in kB)\n"
+		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_VBI_BUFFERS));
+MODULE_PARM_DESC(newi2c,
+		 "Use new I2C implementation\n"
+		 "\t\t\t-1 is autodetect, 0 is off, 1 is on\n"
+		 "\t\t\tDefault is autodetect");
+MODULE_PARM_DESC(i2c_clock_period,
+		 "Period of SCL for the I2C bus controlled by the CX23415/6\n"
+		 "\t\t\tMin: 10 usec (100 kHz), Max: 4500 usec (222 Hz)\n"
+		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_I2C_CLOCK_PERIOD));
+
+MODULE_PARM_DESC(ivtv_first_minor, "Set device node number assigned to first card");
+
+MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
+MODULE_DESCRIPTION("CX23415/CX23416 driver");
+MODULE_SUPPORTED_DEVICE
+    ("CX23415/CX23416 MPEG2 encoder (WinTV PVR-150/250/350/500,\n"
+		"\t\t\tYuan MPG series and similar)");
+MODULE_LICENSE("GPL");
+
+MODULE_VERSION(IVTV_VERSION);
+
+void ivtv_clear_irq_mask(struct ivtv *itv, u32 mask)
+{
+	itv->irqmask &= ~mask;
+	write_reg_sync(itv->irqmask, IVTV_REG_IRQMASK);
+}
+
+void ivtv_set_irq_mask(struct ivtv *itv, u32 mask)
+{
+	itv->irqmask |= mask;
+	write_reg_sync(itv->irqmask, IVTV_REG_IRQMASK);
+}
+
+int ivtv_set_output_mode(struct ivtv *itv, int mode)
+{
+    int old_mode;
+
+    spin_lock(&itv->lock);
+    old_mode = itv->output_mode;
+    if (old_mode == 0)
+	itv->output_mode = old_mode = mode;
+    spin_unlock(&itv->lock);
+    return old_mode;
+}
+
+struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv)
+{
+	switch (itv->output_mode) {
+	case OUT_MPG:
+		return &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
+	case OUT_YUV:
+		return &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
+	default:
+		return NULL;
+	}
+}
+
+int ivtv_waitq(wait_queue_head_t *waitq)
+{
+	DEFINE_WAIT(wait);
+
+	prepare_to_wait(waitq, &wait, TASK_INTERRUPTIBLE);
+	schedule();
+	finish_wait(waitq, &wait);
+	return signal_pending(current) ? -EINTR : 0;
+}
+
+/* Generic utility functions */
+int ivtv_msleep_timeout(unsigned int msecs, int intr)
+{
+	int timeout = msecs_to_jiffies(msecs);
+
+	do {
+		set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+		timeout = schedule_timeout(timeout);
+		if (intr) {
+			int ret = signal_pending(current);
+
+			if (ret)
+				return ret;
+		}
+	} while (timeout);
+	return 0;
+}
+
+/* Release ioremapped memory */
+static void ivtv_iounmap(struct ivtv *itv)
+{
+	if (itv == NULL)
+		return;
+
+	/* Release registers memory */
+	if (itv->reg_mem != NULL) {
+		IVTV_DEBUG_INFO("releasing reg_mem\n");
+		iounmap(itv->reg_mem);
+		itv->reg_mem = NULL;
+	}
+	/* Release io memory */
+	if (itv->has_cx23415 && itv->dec_mem != NULL) {
+		IVTV_DEBUG_INFO("releasing dec_mem\n");
+		iounmap(itv->dec_mem);
+	}
+	itv->dec_mem = NULL;
+
+	/* Release io memory */
+	if (itv->enc_mem != NULL) {
+		IVTV_DEBUG_INFO("releasing enc_mem\n");
+		iounmap(itv->enc_mem);
+		itv->enc_mem = NULL;
+	}
+}
+
+/* Hauppauge card? get values from tveeprom */
+void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv)
+{
+	u8 eedata[256];
+
+	itv->i2c_client.addr = 0xA0 >> 1;
+	tveeprom_read(&itv->i2c_client, eedata, sizeof(eedata));
+	tveeprom_hauppauge_analog(&itv->i2c_client, tv, eedata);
+}
+
+static void ivtv_process_eeprom(struct ivtv *itv)
+{
+	struct tveeprom tv;
+	int pci_slot = PCI_SLOT(itv->pdev->devfn);
+
+	ivtv_read_eeprom(itv, &tv);
+
+	/* Many thanks to Steven Toth from Hauppauge for providing the
+	   model numbers */
+	switch (tv.model) {
+		/* In a few cases the PCI subsystem IDs do not correctly
+		   identify the card. A better method is to check the
+		   model number from the eeprom instead. */
+		case 30012 ... 30039:  /* Low profile PVR250 */
+		case 32000 ... 32999:
+		case 48000 ... 48099:  /* 48??? range are PVR250s with a cx23415 */
+		case 48400 ... 48599:
+			itv->card = ivtv_get_card(IVTV_CARD_PVR_250);
+			break;
+		case 48100 ... 48399:
+		case 48600 ... 48999:
+			itv->card = ivtv_get_card(IVTV_CARD_PVR_350);
+			break;
+		case 23000 ... 23999:  /* PVR500 */
+		case 25000 ... 25999:  /* Low profile PVR150 */
+		case 26000 ... 26999:  /* Regular PVR150 */
+			itv->card = ivtv_get_card(IVTV_CARD_PVR_150);
+			break;
+		case 0:
+			IVTV_ERR("Invalid EEPROM\n");
+			return;
+		default:
+			IVTV_ERR("Unknown model %d, defaulting to PVR-150\n", tv.model);
+			itv->card = ivtv_get_card(IVTV_CARD_PVR_150);
+			break;
+	}
+
+	switch (tv.model) {
+		/* Old style PVR350 (with an saa7114) uses this input for
+		   the tuner. */
+		case 48254:
+			itv->card = ivtv_get_card(IVTV_CARD_PVR_350_V1);
+			break;
+		default:
+			break;
+	}
+
+	itv->v4l2_cap = itv->card->v4l2_capabilities;
+	itv->card_name = itv->card->name;
+	itv->card_i2c = itv->card->i2c;
+
+	/* If this is a PVR500 then it should be possible to detect whether it is the
+	   first or second unit by looking at the subsystem device ID: is bit 4 is
+	   set, then it is the second unit (according to info from Hauppauge).
+
+	   However, while this works for most cards, I have seen a few PVR500 cards
+	   where both units have the same subsystem ID.
+
+	   So instead I look at the reported 'PCI slot' (which is the slot on the PVR500
+	   PCI bridge) and if it is 8, then it is assumed to be the first unit, otherwise
+	   it is the second unit. It is possible that it is a different slot when ivtv is
+	   used in Xen, in that case I ignore this card here. The worst that can happen
+	   is that the card presents itself with a non-working radio device.
+
+	   This detection is needed since the eeprom reports incorrectly that a radio is
+	   present on the second unit. */
+	if (tv.model / 1000 == 23) {
+		static const struct ivtv_card_tuner_i2c ivtv_i2c_radio = {
+			.radio = { 0x60, I2C_CLIENT_END },
+			.demod = { 0x43, I2C_CLIENT_END },
+			.tv = { 0x61, I2C_CLIENT_END },
+		};
+
+		itv->card_name = "WinTV PVR 500";
+		itv->card_i2c = &ivtv_i2c_radio;
+		if (pci_slot == 8 || pci_slot == 9) {
+			int is_first = (pci_slot & 1) == 0;
+
+			itv->card_name = is_first ? "WinTV PVR 500 (unit #1)" :
+						    "WinTV PVR 500 (unit #2)";
+			if (!is_first) {
+				IVTV_INFO("Correcting tveeprom data: no radio present on second unit\n");
+				tv.has_radio = 0;
+			}
+		}
+	}
+	IVTV_INFO("Autodetected %s\n", itv->card_name);
+
+	switch (tv.tuner_hauppauge_model) {
+		case 85:
+		case 99:
+		case 112:
+			itv->pvr150_workaround = 1;
+			break;
+		default:
+			break;
+	}
+	if (tv.tuner_type == TUNER_ABSENT)
+		IVTV_ERR("tveeprom cannot autodetect tuner!\n");
+
+	if (itv->options.tuner == -1)
+		itv->options.tuner = tv.tuner_type;
+	if (itv->options.radio == -1)
+		itv->options.radio = (tv.has_radio != 0);
+	/* only enable newi2c if an IR blaster is present */
+	if (itv->options.newi2c == -1 && tv.has_ir) {
+		itv->options.newi2c = (tv.has_ir & 4) ? 1 : 0;
+		if (itv->options.newi2c) {
+		    IVTV_INFO("Reopen i2c bus for IR-blaster support\n");
+		    exit_ivtv_i2c(itv);
+		    init_ivtv_i2c(itv);
+		}
+	}
+
+	if (itv->std != 0)
+		/* user specified tuner standard */
+		return;
+
+	/* autodetect tuner standard */
+	if (tv.tuner_formats & V4L2_STD_PAL) {
+		IVTV_DEBUG_INFO("PAL tuner detected\n");
+		itv->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
+	} else if (tv.tuner_formats & V4L2_STD_NTSC) {
+		IVTV_DEBUG_INFO("NTSC tuner detected\n");
+		itv->std |= V4L2_STD_NTSC_M;
+	} else if (tv.tuner_formats & V4L2_STD_SECAM) {
+		IVTV_DEBUG_INFO("SECAM tuner detected\n");
+		itv->std |= V4L2_STD_SECAM_L;
+	} else {
+		IVTV_INFO("No tuner detected, default to NTSC-M\n");
+		itv->std |= V4L2_STD_NTSC_M;
+	}
+}
+
+static v4l2_std_id ivtv_parse_std(struct ivtv *itv)
+{
+	switch (pal[0]) {
+		case '6':
+			tunertype = 0;
+			return V4L2_STD_PAL_60;
+		case 'b':
+		case 'B':
+		case 'g':
+		case 'G':
+		case 'h':
+		case 'H':
+			tunertype = 0;
+			return V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
+		case 'n':
+		case 'N':
+			tunertype = 1;
+			if (pal[1] == 'c' || pal[1] == 'C')
+				return V4L2_STD_PAL_Nc;
+			return V4L2_STD_PAL_N;
+		case 'i':
+		case 'I':
+			tunertype = 0;
+			return V4L2_STD_PAL_I;
+		case 'd':
+		case 'D':
+		case 'k':
+		case 'K':
+			tunertype = 0;
+			return V4L2_STD_PAL_DK;
+		case 'M':
+		case 'm':
+			tunertype = 1;
+			return V4L2_STD_PAL_M;
+		case '-':
+			break;
+		default:
+			IVTV_WARN("pal= argument not recognised\n");
+			return 0;
+	}
+
+	switch (secam[0]) {
+		case 'b':
+		case 'B':
+		case 'g':
+		case 'G':
+		case 'h':
+		case 'H':
+			tunertype = 0;
+			return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
+		case 'd':
+		case 'D':
+		case 'k':
+		case 'K':
+			tunertype = 0;
+			return V4L2_STD_SECAM_DK;
+		case 'l':
+		case 'L':
+			tunertype = 0;
+			if (secam[1] == 'C' || secam[1] == 'c')
+				return V4L2_STD_SECAM_LC;
+			return V4L2_STD_SECAM_L;
+		case '-':
+			break;
+		default:
+			IVTV_WARN("secam= argument not recognised\n");
+			return 0;
+	}
+
+	switch (ntsc[0]) {
+		case 'm':
+		case 'M':
+			tunertype = 1;
+			return V4L2_STD_NTSC_M;
+		case 'j':
+		case 'J':
+			tunertype = 1;
+			return V4L2_STD_NTSC_M_JP;
+		case 'k':
+		case 'K':
+			tunertype = 1;
+			return V4L2_STD_NTSC_M_KR;
+		case '-':
+			break;
+		default:
+			IVTV_WARN("ntsc= argument not recognised\n");
+			return 0;
+	}
+
+	/* no match found */
+	return 0;
+}
+
+static void ivtv_process_options(struct ivtv *itv)
+{
+	const char *chipname;
+	int i, j;
+
+	itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers * 1024;
+	itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers * 1024;
+	itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers * 1024;
+	itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
+	itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers * 1024;
+	itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers * 1024;
+	itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers;
+	itv->options.cardtype = cardtype[itv->instance];
+	itv->options.tuner = tuner[itv->instance];
+	itv->options.radio = radio[itv->instance];
+
+	itv->options.i2c_clock_period = i2c_clock_period[itv->instance];
+	if (itv->options.i2c_clock_period == -1)
+		itv->options.i2c_clock_period = IVTV_DEFAULT_I2C_CLOCK_PERIOD;
+	else if (itv->options.i2c_clock_period < 10)
+		itv->options.i2c_clock_period = 10;
+	else if (itv->options.i2c_clock_period > 4500)
+		itv->options.i2c_clock_period = 4500;
+
+	itv->options.newi2c = newi2c;
+	if (tunertype < -1 || tunertype > 1) {
+		IVTV_WARN("Invalid tunertype argument, will autodetect instead\n");
+		tunertype = -1;
+	}
+	itv->std = ivtv_parse_std(itv);
+	if (itv->std == 0 && tunertype >= 0)
+		itv->std = tunertype ? V4L2_STD_MN : (V4L2_STD_ALL & ~V4L2_STD_MN);
+	itv->has_cx23415 = (itv->pdev->device == PCI_DEVICE_ID_IVTV15);
+	chipname = itv->has_cx23415 ? "cx23415" : "cx23416";
+	if (itv->options.cardtype == -1) {
+		IVTV_INFO("Ignore card (detected %s based chip)\n", chipname);
+		return;
+	}
+	if ((itv->card = ivtv_get_card(itv->options.cardtype - 1))) {
+		IVTV_INFO("User specified %s card (detected %s based chip)\n",
+				itv->card->name, chipname);
+	} else if (itv->options.cardtype != 0) {
+		IVTV_ERR("Unknown user specified type, trying to autodetect card\n");
+	}
+	if (itv->card == NULL) {
+		if (itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE ||
+		    itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT1 ||
+		    itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT2) {
+			itv->card = ivtv_get_card(itv->has_cx23415 ? IVTV_CARD_PVR_350 : IVTV_CARD_PVR_150);
+			IVTV_INFO("Autodetected Hauppauge card (%s based)\n",
+					chipname);
+		}
+	}
+	if (itv->card == NULL) {
+		for (i = 0; (itv->card = ivtv_get_card(i)); i++) {
+			if (itv->card->pci_list == NULL)
+				continue;
+			for (j = 0; itv->card->pci_list[j].device; j++) {
+				if (itv->pdev->device !=
+				    itv->card->pci_list[j].device)
+					continue;
+				if (itv->pdev->subsystem_vendor !=
+				    itv->card->pci_list[j].subsystem_vendor)
+					continue;
+				if (itv->pdev->subsystem_device !=
+				    itv->card->pci_list[j].subsystem_device)
+					continue;
+				IVTV_INFO("Autodetected %s card (%s based)\n",
+						itv->card->name, chipname);
+				goto done;
+			}
+		}
+	}
+done:
+
+	if (itv->card == NULL) {
+		itv->card = ivtv_get_card(IVTV_CARD_PVR_150);
+		IVTV_ERR("Unknown card: vendor/device: [%04x:%04x]\n",
+		     itv->pdev->vendor, itv->pdev->device);
+		IVTV_ERR("              subsystem vendor/device: [%04x:%04x]\n",
+		     itv->pdev->subsystem_vendor, itv->pdev->subsystem_device);
+		IVTV_ERR("              %s based\n", chipname);
+		IVTV_ERR("Defaulting to %s card\n", itv->card->name);
+		IVTV_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
+		IVTV_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n");
+		IVTV_ERR("Prefix your subject line with [UNKNOWN IVTV CARD].\n");
+	}
+	itv->v4l2_cap = itv->card->v4l2_capabilities;
+	itv->card_name = itv->card->name;
+	itv->card_i2c = itv->card->i2c;
+}
+
+/* Precondition: the ivtv structure has been memset to 0. Only
+   the dev and num fields have been filled in.
+   No assumptions on the card type may be made here (see ivtv_init_struct2
+   for that).
+ */
+static int __devinit ivtv_init_struct1(struct ivtv *itv)
+{
+	struct sched_param param = { .sched_priority = 99 };
+
+	itv->base_addr = pci_resource_start(itv->pdev, 0);
+	itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */
+	itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */
+
+	mutex_init(&itv->serialize_lock);
+	mutex_init(&itv->i2c_bus_lock);
+	mutex_init(&itv->udma.lock);
+
+	spin_lock_init(&itv->lock);
+	spin_lock_init(&itv->dma_reg_lock);
+
+	init_kthread_worker(&itv->irq_worker);
+	itv->irq_worker_task = kthread_run(kthread_worker_fn, &itv->irq_worker,
+					   itv->v4l2_dev.name);
+	if (IS_ERR(itv->irq_worker_task)) {
+		IVTV_ERR("Could not create ivtv task\n");
+		return -1;
+	}
+	/* must use the FIFO scheduler as it is realtime sensitive */
+	sched_setscheduler(itv->irq_worker_task, SCHED_FIFO, &param);
+
+	init_kthread_work(&itv->irq_work, ivtv_irq_work_handler);
+
+	/* Initial settings */
+	itv->cxhdl.port = CX2341X_PORT_MEMORY;
+	itv->cxhdl.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
+	init_waitqueue_head(&itv->eos_waitq);
+	init_waitqueue_head(&itv->event_waitq);
+	init_waitqueue_head(&itv->vsync_waitq);
+	init_waitqueue_head(&itv->dma_waitq);
+	init_timer(&itv->dma_timer);
+	itv->dma_timer.function = ivtv_unfinished_dma;
+	itv->dma_timer.data = (unsigned long)itv;
+
+	itv->cur_dma_stream = -1;
+	itv->cur_pio_stream = -1;
+
+	/* Ctrls */
+	itv->speed = 1000;
+
+	/* VBI */
+	itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
+	itv->vbi.sliced_in = &itv->vbi.in.fmt.sliced;
+
+	/* Init the sg table for osd/yuv output */
+	sg_init_table(itv->udma.SGlist, IVTV_DMA_SG_OSD_ENT);
+
+	/* OSD */
+	itv->osd_global_alpha_state = 1;
+	itv->osd_global_alpha = 255;
+
+	/* YUV */
+	atomic_set(&itv->yuv_info.next_dma_frame, -1);
+	itv->yuv_info.lace_mode = ivtv_yuv_mode;
+	itv->yuv_info.lace_threshold = ivtv_yuv_threshold;
+	itv->yuv_info.max_frames_buffered = 3;
+	itv->yuv_info.track_osd = 1;
+	return 0;
+}
+
+/* Second initialization part. Here the card type has been
+   autodetected. */
+static void __devinit ivtv_init_struct2(struct ivtv *itv)
+{
+	int i;
+
+	for (i = 0; i < IVTV_CARD_MAX_VIDEO_INPUTS; i++)
+		if (itv->card->video_inputs[i].video_type == 0)
+			break;
+	itv->nof_inputs = i;
+	for (i = 0; i < IVTV_CARD_MAX_AUDIO_INPUTS; i++)
+		if (itv->card->audio_inputs[i].audio_type == 0)
+			break;
+	itv->nof_audio_inputs = i;
+
+	if (itv->card->hw_all & IVTV_HW_CX25840) {
+		itv->vbi.sliced_size = 288;  /* multiple of 16, real size = 284 */
+	} else {
+		itv->vbi.sliced_size = 64;   /* multiple of 16, real size = 52 */
+	}
+
+	/* Find tuner input */
+	for (i = 0; i < itv->nof_inputs; i++) {
+		if (itv->card->video_inputs[i].video_type ==
+				IVTV_CARD_INPUT_VID_TUNER)
+			break;
+	}
+	if (i == itv->nof_inputs)
+		i = 0;
+	itv->active_input = i;
+	itv->audio_input = itv->card->video_inputs[i].audio_index;
+}
+
+static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
+			  const struct pci_device_id *pci_id)
+{
+	u16 cmd;
+	unsigned char pci_latency;
+
+	IVTV_DEBUG_INFO("Enabling pci device\n");
+
+	if (pci_enable_device(pdev)) {
+		IVTV_ERR("Can't enable device!\n");
+		return -EIO;
+	}
+	if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+		IVTV_ERR("No suitable DMA available.\n");
+		return -EIO;
+	}
+	if (!request_mem_region(itv->base_addr, IVTV_ENCODER_SIZE, "ivtv encoder")) {
+		IVTV_ERR("Cannot request encoder memory region.\n");
+		return -EIO;
+	}
+
+	if (!request_mem_region(itv->base_addr + IVTV_REG_OFFSET,
+				IVTV_REG_SIZE, "ivtv registers")) {
+		IVTV_ERR("Cannot request register memory region.\n");
+		release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
+		return -EIO;
+	}
+
+	if (itv->has_cx23415 &&
+	    !request_mem_region(itv->base_addr + IVTV_DECODER_OFFSET,
+				IVTV_DECODER_SIZE, "ivtv decoder")) {
+		IVTV_ERR("Cannot request decoder memory region.\n");
+		release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
+		release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
+		return -EIO;
+	}
+
+	/* Check for bus mastering */
+	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+	if (!(cmd & PCI_COMMAND_MASTER)) {
+		IVTV_DEBUG_INFO("Attempting to enable Bus Mastering\n");
+		pci_set_master(pdev);
+		pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+		if (!(cmd & PCI_COMMAND_MASTER)) {
+			IVTV_ERR("Bus Mastering is not enabled\n");
+			return -ENXIO;
+		}
+	}
+	IVTV_DEBUG_INFO("Bus Mastering Enabled.\n");
+
+	pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
+
+	if (pci_latency < 64 && ivtv_pci_latency) {
+		IVTV_INFO("Unreasonably low latency timer, "
+			       "setting to 64 (was %d)\n", pci_latency);
+		pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
+		pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
+	}
+	/* This config space value relates to DMA latencies. The
+	   default value 0x8080 is too low however and will lead
+	   to DMA errors. 0xffff is the max value which solves
+	   these problems. */
+	pci_write_config_dword(pdev, 0x40, 0xffff);
+
+	IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, "
+		   "irq: %d, latency: %d, memory: 0x%llx\n",
+		   pdev->device, pdev->revision, pdev->bus->number,
+		   PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+		   pdev->irq, pci_latency, (u64)itv->base_addr);
+
+	return 0;
+}
+
+static void ivtv_load_and_init_modules(struct ivtv *itv)
+{
+	u32 hw = itv->card->hw_all;
+	unsigned i;
+
+	/* check which i2c devices are actually found */
+	for (i = 0; i < 32; i++) {
+		u32 device = 1 << i;
+
+		if (!(device & hw))
+			continue;
+		if (device == IVTV_HW_GPIO || device == IVTV_HW_TVEEPROM) {
+			/* GPIO and TVEEPROM do not use i2c probing */
+			itv->hw_flags |= device;
+			continue;
+		}
+		if (ivtv_i2c_register(itv, i) == 0)
+			itv->hw_flags |= device;
+	}
+
+	/* probe for legacy IR controllers that aren't in card definitions */
+	if ((itv->hw_flags & IVTV_HW_IR_ANY) == 0)
+		ivtv_i2c_new_ir_legacy(itv);
+
+	if (itv->card->hw_all & IVTV_HW_CX25840)
+		itv->sd_video = ivtv_find_hw(itv, IVTV_HW_CX25840);
+	else if (itv->card->hw_all & IVTV_HW_SAA717X)
+		itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA717X);
+	else if (itv->card->hw_all & IVTV_HW_SAA7114)
+		itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA7114);
+	else
+		itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA7115);
+	itv->sd_audio = ivtv_find_hw(itv, itv->card->hw_audio_ctrl);
+	itv->sd_muxer = ivtv_find_hw(itv, itv->card->hw_muxer);
+
+	hw = itv->hw_flags;
+
+	if (itv->card->type == IVTV_CARD_CX23416GYC) {
+		/* Several variations of this card exist, detect which card
+		   type should be used. */
+		if ((hw & (IVTV_HW_UPD64031A | IVTV_HW_UPD6408X)) == 0)
+			itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGRYCS);
+		else if ((hw & IVTV_HW_UPD64031A) == 0)
+			itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGR);
+	}
+	else if (itv->card->type == IVTV_CARD_GV_MVPRX ||
+		 itv->card->type == IVTV_CARD_GV_MVPRX2E) {
+		/* The crystal frequency of GVMVPRX is 24.576MHz */
+		v4l2_subdev_call(itv->sd_video, video, s_crystal_freq,
+			SAA7115_FREQ_24_576_MHZ, SAA7115_FREQ_FL_UCGC);
+	}
+
+	if (hw & IVTV_HW_CX25840) {
+		itv->vbi.raw_decoder_line_size = 1444;
+		itv->vbi.raw_decoder_sav_odd_field = 0x20;
+		itv->vbi.raw_decoder_sav_even_field = 0x60;
+		itv->vbi.sliced_decoder_line_size = 272;
+		itv->vbi.sliced_decoder_sav_odd_field = 0xB0;
+		itv->vbi.sliced_decoder_sav_even_field = 0xF0;
+	}
+
+	if (hw & IVTV_HW_SAA711X) {
+		struct v4l2_dbg_chip_ident v;
+
+		/* determine the exact saa711x model */
+		itv->hw_flags &= ~IVTV_HW_SAA711X;
+
+		v.match.type = V4L2_CHIP_MATCH_I2C_DRIVER;
+		strlcpy(v.match.name, "saa7115", sizeof(v.match.name));
+		ivtv_call_hw(itv, IVTV_HW_SAA711X, core, g_chip_ident, &v);
+		if (v.ident == V4L2_IDENT_SAA7114) {
+			itv->hw_flags |= IVTV_HW_SAA7114;
+			/* VBI is not yet supported by the saa7114 driver. */
+			itv->v4l2_cap &= ~(V4L2_CAP_SLICED_VBI_CAPTURE|V4L2_CAP_VBI_CAPTURE);
+		} else {
+			itv->hw_flags |= IVTV_HW_SAA7115;
+		}
+		itv->vbi.raw_decoder_line_size = 1443;
+		itv->vbi.raw_decoder_sav_odd_field = 0x25;
+		itv->vbi.raw_decoder_sav_even_field = 0x62;
+		itv->vbi.sliced_decoder_line_size = 51;
+		itv->vbi.sliced_decoder_sav_odd_field = 0xAB;
+		itv->vbi.sliced_decoder_sav_even_field = 0xEC;
+	}
+
+	if (hw & IVTV_HW_SAA717X) {
+		itv->vbi.raw_decoder_line_size = 1443;
+		itv->vbi.raw_decoder_sav_odd_field = 0x25;
+		itv->vbi.raw_decoder_sav_even_field = 0x62;
+		itv->vbi.sliced_decoder_line_size = 51;
+		itv->vbi.sliced_decoder_sav_odd_field = 0xAB;
+		itv->vbi.sliced_decoder_sav_even_field = 0xEC;
+	}
+}
+
+static int __devinit ivtv_probe(struct pci_dev *pdev,
+				const struct pci_device_id *pci_id)
+{
+	int retval = 0;
+	int vbi_buf_size;
+	struct ivtv *itv;
+
+	itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC);
+	if (itv == NULL)
+		return -ENOMEM;
+	itv->pdev = pdev;
+	itv->instance = v4l2_device_set_name(&itv->v4l2_dev, "ivtv",
+						&ivtv_instance);
+
+	retval = v4l2_device_register(&pdev->dev, &itv->v4l2_dev);
+	if (retval) {
+		kfree(itv);
+		return retval;
+	}
+	IVTV_INFO("Initializing card %d\n", itv->instance);
+
+	ivtv_process_options(itv);
+	if (itv->options.cardtype == -1) {
+		retval = -ENODEV;
+		goto err;
+	}
+	if (ivtv_init_struct1(itv)) {
+		retval = -ENOMEM;
+		goto err;
+	}
+	retval = cx2341x_handler_init(&itv->cxhdl, 50);
+	if (retval)
+		goto err;
+	itv->v4l2_dev.ctrl_handler = &itv->cxhdl.hdl;
+	itv->cxhdl.ops = &ivtv_cxhdl_ops;
+	itv->cxhdl.priv = itv;
+	itv->cxhdl.func = ivtv_api_func;
+
+	IVTV_DEBUG_INFO("base addr: 0x%llx\n", (u64)itv->base_addr);
+
+	/* PCI Device Setup */
+	retval = ivtv_setup_pci(itv, pdev, pci_id);
+	if (retval == -EIO)
+		goto free_worker;
+	if (retval == -ENXIO)
+		goto free_mem;
+
+	/* map io memory */
+	IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n",
+		   (u64)itv->base_addr + IVTV_ENCODER_OFFSET, IVTV_ENCODER_SIZE);
+	itv->enc_mem = ioremap_nocache(itv->base_addr + IVTV_ENCODER_OFFSET,
+				       IVTV_ENCODER_SIZE);
+	if (!itv->enc_mem) {
+		IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 "
+			 "encoder memory\n");
+		IVTV_ERR("Each capture card with a CX23415/6 needs 8 MB of "
+			 "vmalloc address space for this window\n");
+		IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
+		IVTV_ERR("Use the vmalloc= kernel command line option to set "
+			 "VmallocTotal to a larger value\n");
+		retval = -ENOMEM;
+		goto free_mem;
+	}
+
+	if (itv->has_cx23415) {
+		IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n",
+				(u64)itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
+		itv->dec_mem = ioremap_nocache(itv->base_addr + IVTV_DECODER_OFFSET,
+				IVTV_DECODER_SIZE);
+		if (!itv->dec_mem) {
+			IVTV_ERR("ioremap failed. Can't get a window into "
+				 "CX23415 decoder memory\n");
+			IVTV_ERR("Each capture card with a CX23415 needs 8 MB "
+				 "of vmalloc address space for this window\n");
+			IVTV_ERR("Check the output of 'grep Vmalloc "
+				 "/proc/meminfo'\n");
+			IVTV_ERR("Use the vmalloc= kernel command line option "
+				 "to set VmallocTotal to a larger value\n");
+			retval = -ENOMEM;
+			goto free_mem;
+		}
+	}
+	else {
+		itv->dec_mem = itv->enc_mem;
+	}
+
+	/* map registers memory */
+	IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n",
+		   (u64)itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
+	itv->reg_mem =
+	    ioremap_nocache(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
+	if (!itv->reg_mem) {
+		IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 "
+			 "register space\n");
+		IVTV_ERR("Each capture card with a CX23415/6 needs 64 kB of "
+			 "vmalloc address space for this window\n");
+		IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
+		IVTV_ERR("Use the vmalloc= kernel command line option to set "
+			 "VmallocTotal to a larger value\n");
+		retval = -ENOMEM;
+		goto free_io;
+	}
+
+	retval = ivtv_gpio_init(itv);
+	if (retval)
+		goto free_io;
+
+	/* active i2c  */
+	IVTV_DEBUG_INFO("activating i2c...\n");
+	if (init_ivtv_i2c(itv)) {
+		IVTV_ERR("Could not initialize i2c\n");
+		goto free_io;
+	}
+
+	if (itv->card->hw_all & IVTV_HW_TVEEPROM) {
+		/* Based on the model number the cardtype may be changed.
+		   The PCI IDs are not always reliable. */
+		ivtv_process_eeprom(itv);
+	}
+	if (itv->card->comment)
+		IVTV_INFO("%s", itv->card->comment);
+	if (itv->card->v4l2_capabilities == 0) {
+		/* card was detected but is not supported */
+		retval = -ENODEV;
+		goto free_i2c;
+	}
+
+	if (itv->std == 0) {
+		itv->std = V4L2_STD_NTSC_M;
+	}
+
+	if (itv->options.tuner == -1) {
+		int i;
+
+		for (i = 0; i < IVTV_CARD_MAX_TUNERS; i++) {
+			if ((itv->std & itv->card->tuners[i].std) == 0)
+				continue;
+			itv->options.tuner = itv->card->tuners[i].tuner;
+			break;
+		}
+	}
+	/* if no tuner was found, then pick the first tuner in the card list */
+	if (itv->options.tuner == -1 && itv->card->tuners[0].std) {
+		itv->std = itv->card->tuners[0].std;
+		if (itv->std & V4L2_STD_PAL)
+			itv->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
+		else if (itv->std & V4L2_STD_NTSC)
+			itv->std = V4L2_STD_NTSC_M;
+		else if (itv->std & V4L2_STD_SECAM)
+			itv->std = V4L2_STD_SECAM_L;
+		itv->options.tuner = itv->card->tuners[0].tuner;
+	}
+	if (itv->options.radio == -1)
+		itv->options.radio = (itv->card->radio_input.audio_type != 0);
+
+	/* The card is now fully identified, continue with card-specific
+	   initialization. */
+	ivtv_init_struct2(itv);
+
+	ivtv_load_and_init_modules(itv);
+
+	if (itv->std & V4L2_STD_525_60) {
+		itv->is_60hz = 1;
+		itv->is_out_60hz = 1;
+	} else {
+		itv->is_50hz = 1;
+		itv->is_out_50hz = 1;
+	}
+
+	itv->yuv_info.osd_full_w = 720;
+	itv->yuv_info.osd_full_h = itv->is_out_50hz ? 576 : 480;
+	itv->yuv_info.v4l2_src_w = itv->yuv_info.osd_full_w;
+	itv->yuv_info.v4l2_src_h = itv->yuv_info.osd_full_h;
+
+	cx2341x_handler_set_50hz(&itv->cxhdl, itv->is_50hz);
+
+	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000;
+	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_PCM] = 0x01200;
+	itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_MPG] = 0x10000;
+	itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = 0x10000;
+	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = 0x08000;
+
+	/* Setup VBI Raw Size. Should be big enough to hold PAL.
+	   It is possible to switch between PAL and NTSC, so we need to
+	   take the largest size here. */
+	/* 1456 is multiple of 16, real size = 1444 */
+	itv->vbi.raw_size = 1456;
+	/* We use a buffer size of 1/2 of the total size needed for a
+	   frame. This is actually very useful, since we now receive
+	   a field at a time and that makes 'compressing' the raw data
+	   down to size by stripping off the SAV codes a lot easier.
+	   Note: having two different buffer sizes prevents standard
+	   switching on the fly. We need to find a better solution... */
+	vbi_buf_size = itv->vbi.raw_size * (itv->is_60hz ? 24 : 36) / 2;
+	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_VBI] = vbi_buf_size;
+	itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_VBI] = sizeof(struct v4l2_sliced_vbi_data) * 36;
+
+	if (itv->options.radio > 0)
+		itv->v4l2_cap |= V4L2_CAP_RADIO;
+
+	if (itv->options.tuner > -1) {
+		struct tuner_setup setup;
+
+		setup.addr = ADDR_UNSET;
+		setup.type = itv->options.tuner;
+		setup.mode_mask = T_ANALOG_TV;  /* matches TV tuners */
+		if (itv->options.radio > 0)
+			setup.mode_mask |= T_RADIO;
+		setup.tuner_callback = (setup.type == TUNER_XC2028) ?
+			ivtv_reset_tuner_gpio : NULL;
+		ivtv_call_all(itv, tuner, s_type_addr, &setup);
+		if (setup.type == TUNER_XC2028) {
+			static struct xc2028_ctrl ctrl = {
+				.fname = XC2028_DEFAULT_FIRMWARE,
+				.max_len = 64,
+			};
+			struct v4l2_priv_tun_config cfg = {
+				.tuner = itv->options.tuner,
+				.priv = &ctrl,
+			};
+			ivtv_call_all(itv, tuner, s_config, &cfg);
+		}
+	}
+
+	/* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
+	   are not. */
+	itv->tuner_std = itv->std;
+
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+		struct v4l2_ctrl_handler *hdl = itv->v4l2_dev.ctrl_handler;
+
+		itv->ctrl_pts = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops,
+				V4L2_CID_MPEG_VIDEO_DEC_PTS, 0, 0, 0, 0);
+		itv->ctrl_frame = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops,
+				V4L2_CID_MPEG_VIDEO_DEC_FRAME, 0, 0, 0, 0);
+		/* Note: V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO is not supported,
+		   mask that menu item. */
+		itv->ctrl_audio_playback =
+			v4l2_ctrl_new_std_menu(hdl, &ivtv_hdl_out_ops,
+				V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK,
+				V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO,
+				1 << V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO,
+				V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO);
+		itv->ctrl_audio_multilingual_playback =
+			v4l2_ctrl_new_std_menu(hdl, &ivtv_hdl_out_ops,
+				V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK,
+				V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO,
+				1 << V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO,
+				V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT);
+		if (hdl->error) {
+			retval = hdl->error;
+			goto free_i2c;
+		}
+		v4l2_ctrl_cluster(2, &itv->ctrl_pts);
+		v4l2_ctrl_cluster(2, &itv->ctrl_audio_playback);
+		ivtv_call_all(itv, video, s_std_output, itv->std);
+		/* Turn off the output signal. The mpeg decoder is not yet
+		   active so without this you would get a green image until the
+		   mpeg decoder becomes active. */
+		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0);
+	}
+
+	/* clear interrupt mask, effectively disabling interrupts */
+	ivtv_set_irq_mask(itv, 0xffffffff);
+
+	/* Register IRQ */
+	retval = request_irq(itv->pdev->irq, ivtv_irq_handler,
+	     IRQF_SHARED | IRQF_DISABLED, itv->v4l2_dev.name, (void *)itv);
+	if (retval) {
+		IVTV_ERR("Failed to register irq %d\n", retval);
+		goto free_i2c;
+	}
+
+	retval = ivtv_streams_setup(itv);
+	if (retval) {
+		IVTV_ERR("Error %d setting up streams\n", retval);
+		goto free_irq;
+	}
+	retval = ivtv_streams_register(itv);
+	if (retval) {
+		IVTV_ERR("Error %d registering devices\n", retval);
+		goto free_streams;
+	}
+	IVTV_INFO("Initialized card: %s\n", itv->card_name);
+	return 0;
+
+free_streams:
+	ivtv_streams_cleanup(itv, 1);
+free_irq:
+	free_irq(itv->pdev->irq, (void *)itv);
+free_i2c:
+	v4l2_ctrl_handler_free(&itv->cxhdl.hdl);
+	exit_ivtv_i2c(itv);
+free_io:
+	ivtv_iounmap(itv);
+free_mem:
+	release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
+	release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
+	if (itv->has_cx23415)
+		release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
+free_worker:
+	kthread_stop(itv->irq_worker_task);
+err:
+	if (retval == 0)
+		retval = -ENODEV;
+	IVTV_ERR("Error %d on initialization\n", retval);
+
+	v4l2_device_unregister(&itv->v4l2_dev);
+	kfree(itv);
+	return retval;
+}
+
+int ivtv_init_on_first_open(struct ivtv *itv)
+{
+	struct v4l2_frequency vf;
+	/* Needed to call ioctls later */
+	struct ivtv_open_id fh;
+	int fw_retry_count = 3;
+	int video_input;
+
+	fh.itv = itv;
+
+	if (test_bit(IVTV_F_I_FAILED, &itv->i_flags))
+		return -ENXIO;
+
+	if (test_and_set_bit(IVTV_F_I_INITED, &itv->i_flags))
+		return 0;
+
+	while (--fw_retry_count > 0) {
+		/* load firmware */
+		if (ivtv_firmware_init(itv) == 0)
+			break;
+		if (fw_retry_count > 1)
+			IVTV_WARN("Retry loading firmware\n");
+	}
+
+	if (fw_retry_count == 0) {
+		set_bit(IVTV_F_I_FAILED, &itv->i_flags);
+		return -ENXIO;
+	}
+
+	/* Try and get firmware versions */
+	IVTV_DEBUG_INFO("Getting firmware version..\n");
+	ivtv_firmware_versions(itv);
+
+	if (itv->card->hw_all & IVTV_HW_CX25840)
+		v4l2_subdev_call(itv->sd_video, core, load_fw);
+
+	vf.tuner = 0;
+	vf.type = V4L2_TUNER_ANALOG_TV;
+	vf.frequency = 6400; /* the tuner 'baseline' frequency */
+
+	/* Set initial frequency. For PAL/SECAM broadcasts no
+	   'default' channel exists AFAIK. */
+	if (itv->std == V4L2_STD_NTSC_M_JP) {
+		vf.frequency = 1460;	/* ch. 1 91250*16/1000 */
+	}
+	else if (itv->std & V4L2_STD_NTSC_M) {
+		vf.frequency = 1076;	/* ch. 4 67250*16/1000 */
+	}
+
+	video_input = itv->active_input;
+	itv->active_input++;	/* Force update of input */
+	ivtv_s_input(NULL, &fh, video_input);
+
+	/* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
+	   in one place. */
+	itv->std++;		/* Force full standard initialization */
+	itv->std_out = itv->std;
+	ivtv_s_frequency(NULL, &fh, &vf);
+
+	if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) {
+		/* Turn on the TV-out: ivtv_init_mpeg_decoder() initializes
+		   the mpeg decoder so now the saa7127 receives a proper
+		   signal. */
+		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
+		ivtv_init_mpeg_decoder(itv);
+	}
+
+	/* On a cx23416 this seems to be able to enable DMA to the chip? */
+	if (!itv->has_cx23415)
+		write_reg_sync(0x03, IVTV_REG_DMACONTROL);
+
+	ivtv_s_std_enc(itv, &itv->tuner_std);
+
+	/* Default interrupts enabled. For the PVR350 this includes the
+	   decoder VSYNC interrupt, which is always on. It is not only used
+	   during decoding but also by the OSD.
+	   Some old PVR250 cards had a cx23415, so testing for that is too
+	   general. Instead test if the card has video output capability. */
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+		ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC);
+		ivtv_set_osd_alpha(itv);
+		ivtv_s_std_dec(itv, &itv->tuner_std);
+	} else {
+		ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT);
+	}
+
+	/* Setup initial controls */
+	cx2341x_handler_setup(&itv->cxhdl);
+	return 0;
+}
+
+static void ivtv_remove(struct pci_dev *pdev)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+	struct ivtv *itv = to_ivtv(v4l2_dev);
+	int i;
+
+	IVTV_DEBUG_INFO("Removing card\n");
+
+	if (test_bit(IVTV_F_I_INITED, &itv->i_flags)) {
+		/* Stop all captures */
+		IVTV_DEBUG_INFO("Stopping all streams\n");
+		if (atomic_read(&itv->capturing) > 0)
+			ivtv_stop_all_captures(itv);
+
+		/* Stop all decoding */
+		IVTV_DEBUG_INFO("Stopping decoding\n");
+
+		/* Turn off the TV-out */
+		if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
+			ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0);
+		if (atomic_read(&itv->decoding) > 0) {
+			int type;
+
+			if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
+				type = IVTV_DEC_STREAM_TYPE_YUV;
+			else
+				type = IVTV_DEC_STREAM_TYPE_MPG;
+			ivtv_stop_v4l2_decode_stream(&itv->streams[type],
+				V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY, 0);
+		}
+		ivtv_halt_firmware(itv);
+	}
+
+	/* Interrupts */
+	ivtv_set_irq_mask(itv, 0xffffffff);
+	del_timer_sync(&itv->dma_timer);
+
+	/* Kill irq worker */
+	flush_kthread_worker(&itv->irq_worker);
+	kthread_stop(itv->irq_worker_task);
+
+	ivtv_streams_cleanup(itv, 1);
+	ivtv_udma_free(itv);
+
+	v4l2_ctrl_handler_free(&itv->cxhdl.hdl);
+
+	exit_ivtv_i2c(itv);
+
+	free_irq(itv->pdev->irq, (void *)itv);
+	ivtv_iounmap(itv);
+
+	release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
+	release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
+	if (itv->has_cx23415)
+		release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
+
+	pci_disable_device(itv->pdev);
+	for (i = 0; i < IVTV_VBI_FRAMES; i++)
+		kfree(itv->vbi.sliced_mpeg_data[i]);
+
+	printk(KERN_INFO "ivtv: Removed %s\n", itv->card_name);
+
+	v4l2_device_unregister(&itv->v4l2_dev);
+	kfree(itv);
+}
+
+/* define a pci_driver for card detection */
+static struct pci_driver ivtv_pci_driver = {
+      .name =     "ivtv",
+      .id_table = ivtv_pci_tbl,
+      .probe =    ivtv_probe,
+      .remove =   ivtv_remove,
+};
+
+static int __init module_start(void)
+{
+	printk(KERN_INFO "ivtv: Start initialization, version %s\n", IVTV_VERSION);
+
+	/* Validate parameters */
+	if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) {
+		printk(KERN_ERR "ivtv: Exiting, ivtv_first_minor must be between 0 and %d\n",
+		     IVTV_MAX_CARDS - 1);
+		return -1;
+	}
+
+	if (ivtv_debug < 0 || ivtv_debug > 2047) {
+		ivtv_debug = 0;
+		printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 2047\n");
+	}
+
+	if (pci_register_driver(&ivtv_pci_driver)) {
+		printk(KERN_ERR "ivtv: Error detecting PCI card\n");
+		return -ENODEV;
+	}
+	printk(KERN_INFO "ivtv: End initialization\n");
+	return 0;
+}
+
+static void __exit module_cleanup(void)
+{
+	pci_unregister_driver(&ivtv_pci_driver);
+}
+
+/* Note: These symbols are exported because they are used by the ivtvfb
+   framebuffer module and an infrared module for the IR-blaster. */
+EXPORT_SYMBOL(ivtv_set_irq_mask);
+EXPORT_SYMBOL(ivtv_api);
+EXPORT_SYMBOL(ivtv_vapi);
+EXPORT_SYMBOL(ivtv_vapi_result);
+EXPORT_SYMBOL(ivtv_clear_irq_mask);
+EXPORT_SYMBOL(ivtv_debug);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+EXPORT_SYMBOL(ivtv_fw_debug);
+#endif
+EXPORT_SYMBOL(ivtv_reset_ir_gpio);
+EXPORT_SYMBOL(ivtv_udma_setup);
+EXPORT_SYMBOL(ivtv_udma_unmap);
+EXPORT_SYMBOL(ivtv_udma_alloc);
+EXPORT_SYMBOL(ivtv_udma_prepare);
+EXPORT_SYMBOL(ivtv_init_on_first_open);
+EXPORT_SYMBOL(ivtv_firmware_check);
+
+module_init(module_start);
+module_exit(module_cleanup);
diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h
new file mode 100644
index 0000000..a7e00f8
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-driver.h
@@ -0,0 +1,839 @@
+/*
+    ivtv driver internal defines and structures
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef IVTV_DRIVER_H
+#define IVTV_DRIVER_H
+
+/* Internal header for ivtv project:
+ * Driver for the cx23415/6 chip.
+ * Author: Kevin Thayer (nufan_wfk at yahoo.com)
+ * License: GPL
+ * http://www.ivtvdriver.org
+ *
+ * -----
+ * MPG600/MPG160 support by  T.Adachi <tadachi@tadachi-net.com>
+ *                      and Takeru KOMORIYA<komoriya@paken.org>
+ *
+ * AVerMedia M179 GPIO info by Chris Pinkham <cpinkham@bc2va.org>
+ *                using information provided by Jiun-Kuei Jung @ AVerMedia.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/list.h>
+#include <linux/unistd.h>
+#include <linux/pagemap.h>
+#include <linux/scatterlist.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+#include <linux/dvb/video.h>
+#include <linux/dvb/audio.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/tuner.h>
+#include <media/cx2341x.h>
+#include <media/ir-kbd-i2c.h>
+
+#include <linux/ivtv.h>
+
+/* Memory layout */
+#define IVTV_ENCODER_OFFSET	0x00000000
+#define IVTV_ENCODER_SIZE	0x00800000	/* Total size is 0x01000000, but only first half is used */
+#define IVTV_DECODER_OFFSET	0x01000000
+#define IVTV_DECODER_SIZE	0x00800000	/* Total size is 0x01000000, but only first half is used */
+#define IVTV_REG_OFFSET 	0x02000000
+#define IVTV_REG_SIZE		0x00010000
+
+/* Maximum ivtv driver instances. Some people have a huge number of
+   capture cards, so set this to a high value. */
+#define IVTV_MAX_CARDS 32
+
+#define IVTV_ENC_STREAM_TYPE_MPG  0
+#define IVTV_ENC_STREAM_TYPE_YUV  1
+#define IVTV_ENC_STREAM_TYPE_VBI  2
+#define IVTV_ENC_STREAM_TYPE_PCM  3
+#define IVTV_ENC_STREAM_TYPE_RAD  4
+#define IVTV_DEC_STREAM_TYPE_MPG  5
+#define IVTV_DEC_STREAM_TYPE_VBI  6
+#define IVTV_DEC_STREAM_TYPE_VOUT 7
+#define IVTV_DEC_STREAM_TYPE_YUV  8
+#define IVTV_MAX_STREAMS	  9
+
+#define IVTV_DMA_SG_OSD_ENT	(2883584/PAGE_SIZE)	/* sg entities */
+
+/* DMA Registers */
+#define IVTV_REG_DMAXFER 	(0x0000)
+#define IVTV_REG_DMASTATUS 	(0x0004)
+#define IVTV_REG_DECDMAADDR 	(0x0008)
+#define IVTV_REG_ENCDMAADDR 	(0x000c)
+#define IVTV_REG_DMACONTROL 	(0x0010)
+#define IVTV_REG_IRQSTATUS 	(0x0040)
+#define IVTV_REG_IRQMASK 	(0x0048)
+
+/* Setup Registers */
+#define IVTV_REG_ENC_SDRAM_REFRESH 	(0x07F8)
+#define IVTV_REG_ENC_SDRAM_PRECHARGE 	(0x07FC)
+#define IVTV_REG_DEC_SDRAM_REFRESH 	(0x08F8)
+#define IVTV_REG_DEC_SDRAM_PRECHARGE 	(0x08FC)
+#define IVTV_REG_VDM 			(0x2800)
+#define IVTV_REG_AO 			(0x2D00)
+#define IVTV_REG_BYTEFLUSH 		(0x2D24)
+#define IVTV_REG_SPU 			(0x9050)
+#define IVTV_REG_HW_BLOCKS 		(0x9054)
+#define IVTV_REG_VPU 			(0x9058)
+#define IVTV_REG_APU 			(0xA064)
+
+/* Other registers */
+#define IVTV_REG_DEC_LINE_FIELD		(0x28C0)
+
+/* debugging */
+extern int ivtv_debug;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+extern int ivtv_fw_debug;
+#endif
+
+#define IVTV_DBGFLG_WARN    (1 << 0)
+#define IVTV_DBGFLG_INFO    (1 << 1)
+#define IVTV_DBGFLG_MB      (1 << 2)
+#define IVTV_DBGFLG_IOCTL   (1 << 3)
+#define IVTV_DBGFLG_FILE    (1 << 4)
+#define IVTV_DBGFLG_DMA     (1 << 5)
+#define IVTV_DBGFLG_IRQ     (1 << 6)
+#define IVTV_DBGFLG_DEC     (1 << 7)
+#define IVTV_DBGFLG_YUV     (1 << 8)
+#define IVTV_DBGFLG_I2C     (1 << 9)
+/* Flag to turn on high volume debugging */
+#define IVTV_DBGFLG_HIGHVOL (1 << 10)
+
+#define IVTV_DEBUG(x, type, fmt, args...) \
+	do { \
+		if ((x) & ivtv_debug) \
+			v4l2_info(&itv->v4l2_dev, " " type ": " fmt , ##args);	\
+	} while (0)
+#define IVTV_DEBUG_WARN(fmt, args...)  IVTV_DEBUG(IVTV_DBGFLG_WARN,  "warn",  fmt , ## args)
+#define IVTV_DEBUG_INFO(fmt, args...)  IVTV_DEBUG(IVTV_DBGFLG_INFO,  "info",  fmt , ## args)
+#define IVTV_DEBUG_MB(fmt, args...)    IVTV_DEBUG(IVTV_DBGFLG_MB,    "mb",    fmt , ## args)
+#define IVTV_DEBUG_DMA(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_DMA,   "dma",   fmt , ## args)
+#define IVTV_DEBUG_IOCTL(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define IVTV_DEBUG_FILE(fmt, args...)  IVTV_DEBUG(IVTV_DBGFLG_FILE,  "file",  fmt , ## args)
+#define IVTV_DEBUG_I2C(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_I2C,   "i2c",   fmt , ## args)
+#define IVTV_DEBUG_IRQ(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_IRQ,   "irq",   fmt , ## args)
+#define IVTV_DEBUG_DEC(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_DEC,   "dec",   fmt , ## args)
+#define IVTV_DEBUG_YUV(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_YUV,   "yuv",   fmt , ## args)
+
+#define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \
+	do { \
+		if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) 	\
+			v4l2_info(&itv->v4l2_dev, " " type ": " fmt , ##args);	\
+	} while (0)
+#define IVTV_DEBUG_HI_WARN(fmt, args...)  IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN,  "warn",  fmt , ## args)
+#define IVTV_DEBUG_HI_INFO(fmt, args...)  IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO,  "info",  fmt , ## args)
+#define IVTV_DEBUG_HI_MB(fmt, args...)    IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_MB,    "mb",    fmt , ## args)
+#define IVTV_DEBUG_HI_DMA(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA,   "dma",   fmt , ## args)
+#define IVTV_DEBUG_HI_IOCTL(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define IVTV_DEBUG_HI_FILE(fmt, args...)  IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_FILE,  "file",  fmt , ## args)
+#define IVTV_DEBUG_HI_I2C(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C,   "i2c",   fmt , ## args)
+#define IVTV_DEBUG_HI_IRQ(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ,   "irq",   fmt , ## args)
+#define IVTV_DEBUG_HI_DEC(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC,   "dec",   fmt , ## args)
+#define IVTV_DEBUG_HI_YUV(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV,   "yuv",   fmt , ## args)
+
+/* Standard kernel messages */
+#define IVTV_ERR(fmt, args...)      v4l2_err(&itv->v4l2_dev, fmt , ## args)
+#define IVTV_WARN(fmt, args...)     v4l2_warn(&itv->v4l2_dev, fmt , ## args)
+#define IVTV_INFO(fmt, args...)     v4l2_info(&itv->v4l2_dev, fmt , ## args)
+
+/* output modes (cx23415 only) */
+#define OUT_NONE        0
+#define OUT_MPG         1
+#define OUT_YUV         2
+#define OUT_UDMA_YUV    3
+#define OUT_PASSTHROUGH 4
+
+#define IVTV_MAX_PGM_INDEX (400)
+
+/* Default I2C SCL period in microseconds */
+#define IVTV_DEFAULT_I2C_CLOCK_PERIOD	20
+
+struct ivtv_options {
+	int kilobytes[IVTV_MAX_STREAMS];        /* size in kilobytes of each stream */
+	int cardtype;				/* force card type on load */
+	int tuner;				/* set tuner on load */
+	int radio;				/* enable/disable radio */
+	int newi2c;				/* new I2C algorithm */
+	int i2c_clock_period;			/* period of SCL for I2C bus */
+};
+
+/* ivtv-specific mailbox template */
+struct ivtv_mailbox {
+	u32 flags;
+	u32 cmd;
+	u32 retval;
+	u32 timeout;
+	u32 data[CX2341X_MBOX_MAX_DATA];
+};
+
+struct ivtv_api_cache {
+	unsigned long last_jiffies;		/* when last command was issued */
+	u32 data[CX2341X_MBOX_MAX_DATA];	/* last sent api data */
+};
+
+struct ivtv_mailbox_data {
+	volatile struct ivtv_mailbox __iomem *mbox;
+	/* Bits 0-2 are for the encoder mailboxes, 0-1 are for the decoder mailboxes.
+	   If the bit is set, then the corresponding mailbox is in use by the driver. */
+	unsigned long busy;
+	u8 max_mbox;
+};
+
+/* per-buffer bit flags */
+#define IVTV_F_B_NEED_BUF_SWAP  (1 << 0)	/* this buffer should be byte swapped */
+
+/* per-stream, s_flags */
+#define IVTV_F_S_DMA_PENDING	0	/* this stream has pending DMA */
+#define IVTV_F_S_DMA_HAS_VBI	1       /* the current DMA request also requests VBI data */
+#define IVTV_F_S_NEEDS_DATA	2 	/* this decoding stream needs more data */
+
+#define IVTV_F_S_CLAIMED 	3	/* this stream is claimed */
+#define IVTV_F_S_STREAMING      4	/* the fw is decoding/encoding this stream */
+#define IVTV_F_S_INTERNAL_USE	5	/* this stream is used internally (sliced VBI processing) */
+#define IVTV_F_S_PASSTHROUGH	6	/* this stream is in passthrough mode */
+#define IVTV_F_S_STREAMOFF	7	/* signal end of stream EOS */
+#define IVTV_F_S_APPL_IO        8	/* this stream is used read/written by an application */
+
+#define IVTV_F_S_PIO_PENDING	9	/* this stream has pending PIO */
+#define IVTV_F_S_PIO_HAS_VBI	1       /* the current PIO request also requests VBI data */
+
+/* per-ivtv, i_flags */
+#define IVTV_F_I_DMA		   0 	/* DMA in progress */
+#define IVTV_F_I_UDMA		   1 	/* UDMA in progress */
+#define IVTV_F_I_UDMA_PENDING	   2 	/* UDMA pending */
+#define IVTV_F_I_SPEED_CHANGE	   3 	/* a speed change is in progress */
+#define IVTV_F_I_EOS		   4 	/* end of encoder stream reached */
+#define IVTV_F_I_RADIO_USER	   5 	/* the radio tuner is selected */
+#define IVTV_F_I_DIG_RST	   6 	/* reset digitizer */
+#define IVTV_F_I_DEC_YUV	   7 	/* YUV instead of MPG is being decoded */
+#define IVTV_F_I_UPDATE_CC	   9  	/* CC should be updated */
+#define IVTV_F_I_UPDATE_WSS	   10 	/* WSS should be updated */
+#define IVTV_F_I_UPDATE_VPS	   11 	/* VPS should be updated */
+#define IVTV_F_I_DECODING_YUV	   12 	/* this stream is YUV frame decoding */
+#define IVTV_F_I_ENC_PAUSED	   13 	/* the encoder is paused */
+#define IVTV_F_I_VALID_DEC_TIMINGS 14 	/* last_dec_timing is valid */
+#define IVTV_F_I_HAVE_WORK  	   15	/* used in the interrupt handler: there is work to be done */
+#define IVTV_F_I_WORK_HANDLER_VBI  16	/* there is work to be done for VBI */
+#define IVTV_F_I_WORK_HANDLER_YUV  17	/* there is work to be done for YUV */
+#define IVTV_F_I_WORK_HANDLER_PIO  18	/* there is work to be done for PIO */
+#define IVTV_F_I_PIO		   19	/* PIO in progress */
+#define IVTV_F_I_DEC_PAUSED	   20 	/* the decoder is paused */
+#define IVTV_F_I_INITED		   21 	/* set after first open */
+#define IVTV_F_I_FAILED		   22 	/* set if first open failed */
+
+/* Event notifications */
+#define IVTV_F_I_EV_DEC_STOPPED	   28	/* decoder stopped event */
+#define IVTV_F_I_EV_VSYNC	   29 	/* VSYNC event */
+#define IVTV_F_I_EV_VSYNC_FIELD    30 	/* VSYNC event field (0 = first, 1 = second field) */
+#define IVTV_F_I_EV_VSYNC_ENABLED  31 	/* VSYNC event enabled */
+
+/* Scatter-Gather array element, used in DMA transfers */
+struct ivtv_sg_element {
+	__le32 src;
+	__le32 dst;
+	__le32 size;
+};
+
+struct ivtv_sg_host_element {
+	u32 src;
+	u32 dst;
+	u32 size;
+};
+
+struct ivtv_user_dma {
+	struct mutex lock;
+	int page_count;
+	struct page *map[IVTV_DMA_SG_OSD_ENT];
+	/* Needed when dealing with highmem userspace buffers */
+	struct page *bouncemap[IVTV_DMA_SG_OSD_ENT];
+
+	/* Base Dev SG Array for cx23415/6 */
+	struct ivtv_sg_element SGarray[IVTV_DMA_SG_OSD_ENT];
+	dma_addr_t SG_handle;
+	int SG_length;
+
+	/* SG List of Buffers */
+	struct scatterlist SGlist[IVTV_DMA_SG_OSD_ENT];
+};
+
+struct ivtv_dma_page_info {
+	unsigned long uaddr;
+	unsigned long first;
+	unsigned long last;
+	unsigned int offset;
+	unsigned int tail;
+	int page_count;
+};
+
+struct ivtv_buffer {
+	struct list_head list;
+	dma_addr_t dma_handle;
+	unsigned short b_flags;
+	unsigned short dma_xfer_cnt;
+	char *buf;
+	u32 bytesused;
+	u32 readpos;
+};
+
+struct ivtv_queue {
+	struct list_head list;          /* the list of buffers in this queue */
+	u32 buffers;                    /* number of buffers in this queue */
+	u32 length;                     /* total number of bytes of available buffer space */
+	u32 bytesused;                  /* total number of bytes used in this queue */
+};
+
+struct ivtv;				/* forward reference */
+
+struct ivtv_stream {
+	/* These first four fields are always set, even if the stream
+	   is not actually created. */
+	struct video_device *vdev;	/* NULL when stream not created */
+	struct ivtv *itv; 		/* for ease of use */
+	const char *name;		/* name of the stream */
+	int type;			/* stream type */
+	u32 caps;			/* V4L2 capabilities */
+
+	struct v4l2_fh *fh;		/* pointer to the streaming filehandle */
+	spinlock_t qlock; 		/* locks access to the queues */
+	unsigned long s_flags;		/* status flags, see above */
+	int dma;			/* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */
+	u32 pending_offset;
+	u32 pending_backup;
+	u64 pending_pts;
+
+	u32 dma_offset;
+	u32 dma_backup;
+	u64 dma_pts;
+
+	int subtype;
+	wait_queue_head_t waitq;
+	u32 dma_last_offset;
+
+	/* Buffer Stats */
+	u32 buffers;
+	u32 buf_size;
+	u32 buffers_stolen;
+
+	/* Buffer Queues */
+	struct ivtv_queue q_free;	/* free buffers */
+	struct ivtv_queue q_full;	/* full buffers */
+	struct ivtv_queue q_io;		/* waiting for I/O */
+	struct ivtv_queue q_dma;	/* waiting for DMA */
+	struct ivtv_queue q_predma;	/* waiting for DMA */
+
+	/* DMA xfer counter, buffers belonging to the same DMA
+	   xfer will have the same dma_xfer_cnt. */
+	u16 dma_xfer_cnt;
+
+	/* Base Dev SG Array for cx23415/6 */
+	struct ivtv_sg_host_element *sg_pending;
+	struct ivtv_sg_host_element *sg_processing;
+	struct ivtv_sg_element *sg_dma;
+	dma_addr_t sg_handle;
+	int sg_pending_size;
+	int sg_processing_size;
+	int sg_processed;
+
+	/* SG List of Buffers */
+	struct scatterlist *SGlist;
+};
+
+struct ivtv_open_id {
+	struct v4l2_fh fh;
+	int type;                       /* stream type */
+	int yuv_frames;                 /* 1: started OUT_UDMA_YUV output mode */
+	struct ivtv *itv;
+};
+
+static inline struct ivtv_open_id *fh2id(struct v4l2_fh *fh)
+{
+	return container_of(fh, struct ivtv_open_id, fh);
+}
+
+struct yuv_frame_info
+{
+	u32 update;
+	s32 src_x;
+	s32 src_y;
+	u32 src_w;
+	u32 src_h;
+	s32 dst_x;
+	s32 dst_y;
+	u32 dst_w;
+	u32 dst_h;
+	s32 pan_x;
+	s32 pan_y;
+	u32 vis_w;
+	u32 vis_h;
+	u32 interlaced_y;
+	u32 interlaced_uv;
+	s32 tru_x;
+	u32 tru_w;
+	u32 tru_h;
+	u32 offset_y;
+	s32 lace_mode;
+	u32 sync_field;
+	u32 delay;
+	u32 interlaced;
+};
+
+#define IVTV_YUV_MODE_INTERLACED	0x00
+#define IVTV_YUV_MODE_PROGRESSIVE	0x01
+#define IVTV_YUV_MODE_AUTO		0x02
+#define IVTV_YUV_MODE_MASK		0x03
+
+#define IVTV_YUV_SYNC_EVEN		0x00
+#define IVTV_YUV_SYNC_ODD		0x04
+#define IVTV_YUV_SYNC_MASK		0x04
+
+#define IVTV_YUV_BUFFERS 8
+
+struct yuv_playback_info
+{
+	u32 reg_2834;
+	u32 reg_2838;
+	u32 reg_283c;
+	u32 reg_2840;
+	u32 reg_2844;
+	u32 reg_2848;
+	u32 reg_2854;
+	u32 reg_285c;
+	u32 reg_2864;
+
+	u32 reg_2870;
+	u32 reg_2874;
+	u32 reg_2890;
+	u32 reg_2898;
+	u32 reg_289c;
+
+	u32 reg_2918;
+	u32 reg_291c;
+	u32 reg_2920;
+	u32 reg_2924;
+	u32 reg_2928;
+	u32 reg_292c;
+	u32 reg_2930;
+
+	u32 reg_2934;
+
+	u32 reg_2938;
+	u32 reg_293c;
+	u32 reg_2940;
+	u32 reg_2944;
+	u32 reg_2948;
+	u32 reg_294c;
+	u32 reg_2950;
+	u32 reg_2954;
+	u32 reg_2958;
+	u32 reg_295c;
+	u32 reg_2960;
+	u32 reg_2964;
+	u32 reg_2968;
+	u32 reg_296c;
+
+	u32 reg_2970;
+
+	int v_filter_1;
+	int v_filter_2;
+	int h_filter;
+
+	u8 track_osd; /* Should yuv output track the OSD size & position */
+
+	u32 osd_x_offset;
+	u32 osd_y_offset;
+
+	u32 osd_x_pan;
+	u32 osd_y_pan;
+
+	u32 osd_vis_w;
+	u32 osd_vis_h;
+
+	u32 osd_full_w;
+	u32 osd_full_h;
+
+	int decode_height;
+
+	int lace_mode;
+	int lace_threshold;
+	int lace_sync_field;
+
+	atomic_t next_dma_frame;
+	atomic_t next_fill_frame;
+
+	u32 yuv_forced_update;
+	int update_frame;
+
+	u8 fields_lapsed;   /* Counter used when delaying a frame */
+
+	struct yuv_frame_info new_frame_info[IVTV_YUV_BUFFERS];
+	struct yuv_frame_info old_frame_info;
+	struct yuv_frame_info old_frame_info_args;
+
+	void *blanking_ptr;
+	dma_addr_t blanking_dmaptr;
+
+	int stream_size;
+
+	u8 draw_frame; /* PVR350 buffer to draw into */
+	u8 max_frames_buffered; /* Maximum number of frames to buffer */
+
+	struct v4l2_rect main_rect;
+	u32 v4l2_src_w;
+	u32 v4l2_src_h;
+
+	u8 running; /* Have any frames been displayed */
+};
+
+#define IVTV_VBI_FRAMES 32
+
+/* VBI data */
+struct vbi_cc {
+	u8 odd[2];	/* two-byte payload of odd field */
+	u8 even[2];	/* two-byte payload of even field */;
+};
+
+struct vbi_vps {
+	u8 data[5];	/* five-byte VPS payload */
+};
+
+struct vbi_info {
+	/* VBI general data, does not change during streaming */
+
+	u32 raw_decoder_line_size;              /* raw VBI line size from digitizer */
+	u8 raw_decoder_sav_odd_field;           /* raw VBI Start Active Video digitizer code of odd field */
+	u8 raw_decoder_sav_even_field;          /* raw VBI Start Active Video digitizer code of even field */
+	u32 sliced_decoder_line_size;           /* sliced VBI line size from digitizer */
+	u8 sliced_decoder_sav_odd_field;        /* sliced VBI Start Active Video digitizer code of odd field */
+	u8 sliced_decoder_sav_even_field;       /* sliced VBI Start Active Video digitizer code of even field */
+
+	u32 start[2];				/* start of first VBI line in the odd/even fields */
+	u32 count;				/* number of VBI lines per field */
+	u32 raw_size;				/* size of raw VBI line from the digitizer */
+	u32 sliced_size;			/* size of sliced VBI line from the digitizer */
+
+	u32 dec_start;				/* start in decoder memory of VBI re-insertion buffers */
+	u32 enc_start;				/* start in encoder memory of VBI capture buffers */
+	u32 enc_size;				/* size of VBI capture area */
+	int fpi;				/* number of VBI frames per interrupt */
+
+	struct v4l2_format in;			/* current VBI capture format */
+	struct v4l2_sliced_vbi_format *sliced_in; /* convenience pointer to sliced struct in vbi.in union */
+	int insert_mpeg;			/* if non-zero, then embed VBI data in MPEG stream */
+
+	/* Raw VBI compatibility hack */
+
+	u32 frame; 				/* frame counter hack needed for backwards compatibility
+						   of old VBI software */
+
+	/* Sliced VBI output data */
+
+	struct vbi_cc cc_payload[256];		/* sliced VBI CC payload array: it is an array to
+						   prevent dropping CC data if they couldn't be
+						   processed fast enough */
+	int cc_payload_idx;			/* index in cc_payload */
+	u8 cc_missing_cnt;			/* counts number of frames without CC for passthrough mode */
+	int wss_payload;			/* sliced VBI WSS payload */
+	u8 wss_missing_cnt;			/* counts number of frames without WSS for passthrough mode */
+	struct vbi_vps vps_payload;		/* sliced VBI VPS payload */
+
+	/* Sliced VBI capture data */
+
+	struct v4l2_sliced_vbi_data sliced_data[36];	/* sliced VBI storage for VBI encoder stream */
+	struct v4l2_sliced_vbi_data sliced_dec_data[36];/* sliced VBI storage for VBI decoder stream */
+
+	/* VBI Embedding data */
+
+	/* Buffer for VBI data inserted into MPEG stream.
+	   The first byte is a dummy byte that's never used.
+	   The next 16 bytes contain the MPEG header for the VBI data,
+	   the remainder is the actual VBI data.
+	   The max size accepted by the MPEG VBI reinsertion turns out
+	   to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes,
+	   where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is
+	   a single line header byte and 2 * 18 is the number of VBI lines per frame.
+
+	   However, it seems that the data must be 1K aligned, so we have to
+	   pad the data until the 1 or 2 K boundary.
+
+	   This pointer array will allocate 2049 bytes to store each VBI frame. */
+	u8 *sliced_mpeg_data[IVTV_VBI_FRAMES];
+	u32 sliced_mpeg_size[IVTV_VBI_FRAMES];
+	struct ivtv_buffer sliced_mpeg_buf;	/* temporary buffer holding data from sliced_mpeg_data */
+	u32 inserted_frame;			/* index in sliced_mpeg_size of next sliced data
+						   to be inserted in the MPEG stream */
+};
+
+/* forward declaration of struct defined in ivtv-cards.h */
+struct ivtv_card;
+
+/* Struct to hold info about ivtv cards */
+struct ivtv {
+	/* General fixed card data */
+	struct pci_dev *pdev;		/* PCI device */
+	const struct ivtv_card *card;	/* card information */
+	const char *card_name;          /* full name of the card */
+	const struct ivtv_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */
+	u8 has_cx23415;			/* 1 if it is a cx23415 based card, 0 for cx23416 */
+	u8 pvr150_workaround;           /* 1 if the cx25840 needs to workaround a PVR150 bug */
+	u8 nof_inputs;			/* number of video inputs */
+	u8 nof_audio_inputs;		/* number of audio inputs */
+	u32 v4l2_cap;			/* V4L2 capabilities of card */
+	u32 hw_flags; 			/* hardware description of the board */
+	v4l2_std_id tuner_std;		/* the norm of the card's tuner (fixed) */
+	struct v4l2_subdev *sd_video;	/* controlling video decoder subdev */
+	struct v4l2_subdev *sd_audio;	/* controlling audio subdev */
+	struct v4l2_subdev *sd_muxer;	/* controlling audio muxer subdev */
+	resource_size_t base_addr;      /* PCI resource base address */
+	volatile void __iomem *enc_mem; /* pointer to mapped encoder memory */
+	volatile void __iomem *dec_mem; /* pointer to mapped decoder memory */
+	volatile void __iomem *reg_mem; /* pointer to mapped registers */
+	struct ivtv_options options; 	/* user options */
+
+	struct v4l2_device v4l2_dev;
+	struct cx2341x_handler cxhdl;
+	struct {
+		/* PTS/Frame count control cluster */
+		struct v4l2_ctrl *ctrl_pts;
+		struct v4l2_ctrl *ctrl_frame;
+	};
+	struct {
+		/* Audio Playback control cluster */
+		struct v4l2_ctrl *ctrl_audio_playback;
+		struct v4l2_ctrl *ctrl_audio_multilingual_playback;
+	};
+	struct v4l2_ctrl_handler hdl_gpio;
+	struct v4l2_subdev sd_gpio;	/* GPIO sub-device */
+	u16 instance;
+
+	/* High-level state info */
+	unsigned long i_flags;          /* global ivtv flags */
+	u8 is_50hz;                     /* 1 if the current capture standard is 50 Hz */
+	u8 is_60hz                      /* 1 if the current capture standard is 60 Hz */;
+	u8 is_out_50hz                  /* 1 if the current TV output standard is 50 Hz */;
+	u8 is_out_60hz                  /* 1 if the current TV output standard is 60 Hz */;
+	int output_mode;                /* decoder output mode: NONE, MPG, YUV, UDMA YUV, passthrough */
+	u32 audio_input;                /* current audio input */
+	u32 active_input;               /* current video input */
+	u32 active_output;              /* current video output */
+	v4l2_std_id std;                /* current capture TV standard */
+	v4l2_std_id std_out;            /* current TV output standard */
+	u8 audio_stereo_mode;           /* decoder setting how to handle stereo MPEG audio */
+	u8 audio_bilingual_mode;        /* decoder setting how to handle bilingual MPEG audio */
+
+	/* Locking */
+	spinlock_t lock;                /* lock access to this struct */
+	struct mutex serialize_lock;    /* mutex used to serialize open/close/start/stop/ioctl operations */
+
+	/* Streams */
+	int stream_buf_size[IVTV_MAX_STREAMS];          /* stream buffer size */
+	struct ivtv_stream streams[IVTV_MAX_STREAMS]; 	/* stream data */
+	atomic_t capturing;		/* count number of active capture streams */
+	atomic_t decoding;		/* count number of active decoding streams */
+
+
+	/* Interrupts & DMA */
+	u32 irqmask;                    /* active interrupts */
+	u32 irq_rr_idx;                 /* round-robin stream index */
+	struct kthread_worker irq_worker;		/* kthread worker for PIO/YUV/VBI actions */
+	struct task_struct *irq_worker_task;		/* task for irq_worker */
+	struct kthread_work irq_work;	/* kthread work entry */
+	spinlock_t dma_reg_lock;        /* lock access to DMA engine registers */
+	int cur_dma_stream;		/* index of current stream doing DMA (-1 if none) */
+	int cur_pio_stream;		/* index of current stream doing PIO (-1 if none) */
+	u32 dma_data_req_offset;        /* store offset in decoder memory of current DMA request */
+	u32 dma_data_req_size;          /* store size of current DMA request */
+	int dma_retries;                /* current DMA retry attempt */
+	struct ivtv_user_dma udma;      /* user based DMA for OSD */
+	struct timer_list dma_timer;    /* timer used to catch unfinished DMAs */
+	u32 last_vsync_field;           /* last seen vsync field */
+	wait_queue_head_t dma_waitq;    /* wake up when the current DMA is finished */
+	wait_queue_head_t eos_waitq;    /* wake up when EOS arrives */
+	wait_queue_head_t event_waitq;  /* wake up when the next decoder event arrives */
+	wait_queue_head_t vsync_waitq;  /* wake up when the next decoder vsync arrives */
+
+
+	/* Mailbox */
+	struct ivtv_mailbox_data enc_mbox;              /* encoder mailboxes */
+	struct ivtv_mailbox_data dec_mbox;              /* decoder mailboxes */
+	struct ivtv_api_cache api_cache[256]; 		/* cached API commands */
+
+
+	/* I2C */
+	struct i2c_adapter i2c_adap;
+	struct i2c_algo_bit_data i2c_algo;
+	struct i2c_client i2c_client;
+	int i2c_state;                  /* i2c bit state */
+	struct mutex i2c_bus_lock;      /* lock i2c bus */
+
+	struct IR_i2c_init_data ir_i2c_init_data;
+
+	/* Program Index information */
+	u32 pgm_info_offset;            /* start of pgm info in encoder memory */
+	u32 pgm_info_num;               /* number of elements in the pgm cyclic buffer in encoder memory */
+	u32 pgm_info_write_idx;         /* last index written by the card that was transferred to pgm_info[] */
+	u32 pgm_info_read_idx;          /* last index in pgm_info read by the application */
+	struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX]; /* filled from the pgm cyclic buffer on the card */
+
+
+	/* Miscellaneous */
+	u32 open_id;			/* incremented each time an open occurs, is >= 1 */
+	int search_pack_header;         /* 1 if ivtv_copy_buf_to_user() is scanning for a pack header (0xba) */
+	int speed;                      /* current playback speed setting */
+	u8 speed_mute_audio;            /* 1 if audio should be muted when fast forward */
+	u64 mpg_data_received;          /* number of bytes received from the MPEG stream */
+	u64 vbi_data_inserted;          /* number of VBI bytes inserted into the MPEG stream */
+	u32 last_dec_timing[3];         /* cache last retrieved pts/scr/frame values */
+	unsigned long dualwatch_jiffies;/* jiffies value of the previous dualwatch check */
+	u32 dualwatch_stereo_mode;      /* current detected dualwatch stereo mode */
+
+
+	/* VBI state info */
+	struct vbi_info vbi;            /* VBI-specific data */
+
+
+	/* YUV playback */
+	struct yuv_playback_info yuv_info;              /* YUV playback data */
+
+
+	/* OSD support */
+	unsigned long osd_video_pbase;
+	int osd_global_alpha_state;     /* 1 = global alpha is on */
+	int osd_local_alpha_state;      /* 1 = local alpha is on */
+	int osd_chroma_key_state;       /* 1 = chroma-keying is on */
+	u8  osd_global_alpha;           /* current global alpha */
+	u32 osd_chroma_key;             /* current chroma key */
+	struct v4l2_rect osd_rect;      /* current OSD position and size */
+	struct v4l2_rect main_rect;     /* current Main window position and size */
+	struct osd_info *osd_info;      /* ivtvfb private OSD info */
+	void (*ivtvfb_restore)(struct ivtv *itv); /* Used for a warm start */
+};
+
+static inline struct ivtv *to_ivtv(struct v4l2_device *v4l2_dev)
+{
+	return container_of(v4l2_dev, struct ivtv, v4l2_dev);
+}
+
+/* Globals */
+extern int ivtv_first_minor;
+
+/*==============Prototypes==================*/
+
+/* Hardware/IRQ */
+void ivtv_set_irq_mask(struct ivtv *itv, u32 mask);
+void ivtv_clear_irq_mask(struct ivtv *itv, u32 mask);
+
+/* try to set output mode, return current mode. */
+int ivtv_set_output_mode(struct ivtv *itv, int mode);
+
+/* return current output stream based on current mode */
+struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv);
+
+/* Return non-zero if a signal is pending */
+int ivtv_msleep_timeout(unsigned int msecs, int intr);
+
+/* Wait on queue, returns -EINTR if interrupted */
+int ivtv_waitq(wait_queue_head_t *waitq);
+
+/* Read Hauppauge eeprom */
+struct tveeprom; /* forward reference */
+void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv);
+
+/* First-open initialization: load firmware, init cx25840, etc. */
+int ivtv_init_on_first_open(struct ivtv *itv);
+
+/* Test if the current VBI mode is raw (1) or sliced (0) */
+static inline int ivtv_raw_vbi(const struct ivtv *itv)
+{
+	return itv->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE;
+}
+
+/* This is a PCI post thing, where if the pci register is not read, then
+   the write doesn't always take effect right away. By reading back the
+   register any pending PCI writes will be performed (in order), and so
+   you can be sure that the writes are guaranteed to be done.
+
+   Rarely needed, only in some timing sensitive cases.
+   Apparently if this is not done some motherboards seem
+   to kill the firmware and get into the broken state until computer is
+   rebooted. */
+#define write_sync(val, reg) \
+	do { writel(val, reg); readl(reg); } while (0)
+
+#define read_reg(reg) readl(itv->reg_mem + (reg))
+#define write_reg(val, reg) writel(val, itv->reg_mem + (reg))
+#define write_reg_sync(val, reg) \
+	do { write_reg(val, reg); read_reg(reg); } while (0)
+
+#define read_enc(addr) readl(itv->enc_mem + (u32)(addr))
+#define write_enc(val, addr) writel(val, itv->enc_mem + (u32)(addr))
+#define write_enc_sync(val, addr) \
+	do { write_enc(val, addr); read_enc(addr); } while (0)
+
+#define read_dec(addr) readl(itv->dec_mem + (u32)(addr))
+#define write_dec(val, addr) writel(val, itv->dec_mem + (u32)(addr))
+#define write_dec_sync(val, addr) \
+	do { write_dec(val, addr); read_dec(addr); } while (0)
+
+/* Call the specified callback for all subdevs matching hw (if 0, then
+   match them all). Ignore any errors. */
+#define ivtv_call_hw(itv, hw, o, f, args...) 				\
+	do {								\
+		struct v4l2_subdev *__sd;				\
+		__v4l2_device_call_subdevs_p(&(itv)->v4l2_dev, __sd,	\
+			!(hw) || (__sd->grp_id & (hw)), o, f , ##args);	\
+	} while (0)
+
+#define ivtv_call_all(itv, o, f, args...) ivtv_call_hw(itv, 0, o, f , ##args)
+
+/* Call the specified callback for all subdevs matching hw (if 0, then
+   match them all). If the callback returns an error other than 0 or
+   -ENOIOCTLCMD, then return with that error code. */
+#define ivtv_call_hw_err(itv, hw, o, f, args...)			\
+({									\
+	struct v4l2_subdev *__sd;					\
+	__v4l2_device_call_subdevs_until_err_p(&(itv)->v4l2_dev, __sd,	\
+		!(hw) || (__sd->grp_id & (hw)), o, f , ##args);		\
+})
+
+#define ivtv_call_all_err(itv, o, f, args...) ivtv_call_hw_err(itv, 0, o, f , ##args)
+
+#endif
diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c
new file mode 100644
index 0000000..88bce90
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-fileops.c
@@ -0,0 +1,1070 @@
+/*
+    file operation functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-fileops.h"
+#include "ivtv-i2c.h"
+#include "ivtv-queue.h"
+#include "ivtv-udma.h"
+#include "ivtv-irq.h"
+#include "ivtv-vbi.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-routing.h"
+#include "ivtv-streams.h"
+#include "ivtv-yuv.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-cards.h"
+#include "ivtv-firmware.h"
+#include <media/v4l2-event.h>
+#include <media/saa7115.h>
+
+/* This function tries to claim the stream for a specific file descriptor.
+   If no one else is using this stream then the stream is claimed and
+   associated VBI streams are also automatically claimed.
+   Possible error returns: -EBUSY if someone else has claimed
+   the stream or 0 on success. */
+static int ivtv_claim_stream(struct ivtv_open_id *id, int type)
+{
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[type];
+	struct ivtv_stream *s_vbi;
+	int vbi_type;
+
+	if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) {
+		/* someone already claimed this stream */
+		if (s->fh == &id->fh) {
+			/* yes, this file descriptor did. So that's OK. */
+			return 0;
+		}
+		if (s->fh == NULL && (type == IVTV_DEC_STREAM_TYPE_VBI ||
+					 type == IVTV_ENC_STREAM_TYPE_VBI)) {
+			/* VBI is handled already internally, now also assign
+			   the file descriptor to this stream for external
+			   reading of the stream. */
+			s->fh = &id->fh;
+			IVTV_DEBUG_INFO("Start Read VBI\n");
+			return 0;
+		}
+		/* someone else is using this stream already */
+		IVTV_DEBUG_INFO("Stream %d is busy\n", type);
+		return -EBUSY;
+	}
+	s->fh = &id->fh;
+	if (type == IVTV_DEC_STREAM_TYPE_VBI) {
+		/* Enable reinsertion interrupt */
+		ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
+	}
+
+	/* IVTV_DEC_STREAM_TYPE_MPG needs to claim IVTV_DEC_STREAM_TYPE_VBI,
+	   IVTV_ENC_STREAM_TYPE_MPG needs to claim IVTV_ENC_STREAM_TYPE_VBI
+	   (provided VBI insertion is on and sliced VBI is selected), for all
+	   other streams we're done */
+	if (type == IVTV_DEC_STREAM_TYPE_MPG) {
+		vbi_type = IVTV_DEC_STREAM_TYPE_VBI;
+	} else if (type == IVTV_ENC_STREAM_TYPE_MPG &&
+		   itv->vbi.insert_mpeg && !ivtv_raw_vbi(itv)) {
+		vbi_type = IVTV_ENC_STREAM_TYPE_VBI;
+	} else {
+		return 0;
+	}
+	s_vbi = &itv->streams[vbi_type];
+
+	if (!test_and_set_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags)) {
+		/* Enable reinsertion interrupt */
+		if (vbi_type == IVTV_DEC_STREAM_TYPE_VBI)
+			ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
+	}
+	/* mark that it is used internally */
+	set_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags);
+	return 0;
+}
+
+/* This function releases a previously claimed stream. It will take into
+   account associated VBI streams. */
+void ivtv_release_stream(struct ivtv_stream *s)
+{
+	struct ivtv *itv = s->itv;
+	struct ivtv_stream *s_vbi;
+
+	s->fh = NULL;
+	if ((s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type == IVTV_ENC_STREAM_TYPE_VBI) &&
+		test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) {
+		/* this stream is still in use internally */
+		return;
+	}
+	if (!test_and_clear_bit(IVTV_F_S_CLAIMED, &s->s_flags)) {
+		IVTV_DEBUG_WARN("Release stream %s not in use!\n", s->name);
+		return;
+	}
+
+	ivtv_flush_queues(s);
+
+	/* disable reinsertion interrupt */
+	if (s->type == IVTV_DEC_STREAM_TYPE_VBI)
+		ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
+
+	/* IVTV_DEC_STREAM_TYPE_MPG needs to release IVTV_DEC_STREAM_TYPE_VBI,
+	   IVTV_ENC_STREAM_TYPE_MPG needs to release IVTV_ENC_STREAM_TYPE_VBI,
+	   for all other streams we're done */
+	if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
+		s_vbi = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI];
+	else if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
+		s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+	else
+		return;
+
+	/* clear internal use flag */
+	if (!test_and_clear_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags)) {
+		/* was already cleared */
+		return;
+	}
+	if (s_vbi->fh) {
+		/* VBI stream still claimed by a file descriptor */
+		return;
+	}
+	/* disable reinsertion interrupt */
+	if (s_vbi->type == IVTV_DEC_STREAM_TYPE_VBI)
+		ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
+	clear_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags);
+	ivtv_flush_queues(s_vbi);
+}
+
+static void ivtv_dualwatch(struct ivtv *itv)
+{
+	struct v4l2_tuner vt;
+	u32 new_stereo_mode;
+	const u32 dual = 0x02;
+
+	new_stereo_mode = v4l2_ctrl_g_ctrl(itv->cxhdl.audio_mode);
+	memset(&vt, 0, sizeof(vt));
+	ivtv_call_all(itv, tuner, g_tuner, &vt);
+	if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && (vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
+		new_stereo_mode = dual;
+
+	if (new_stereo_mode == itv->dualwatch_stereo_mode)
+		return;
+
+	IVTV_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n",
+			   itv->dualwatch_stereo_mode, new_stereo_mode);
+	if (v4l2_ctrl_s_ctrl(itv->cxhdl.audio_mode, new_stereo_mode))
+		IVTV_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
+}
+
+static void ivtv_update_pgm_info(struct ivtv *itv)
+{
+	u32 wr_idx = (read_enc(itv->pgm_info_offset) - itv->pgm_info_offset - 4) / 24;
+	int cnt;
+	int i = 0;
+
+	if (wr_idx >= itv->pgm_info_num) {
+		IVTV_DEBUG_WARN("Invalid PGM index %d (>= %d)\n", wr_idx, itv->pgm_info_num);
+		return;
+	}
+	cnt = (wr_idx + itv->pgm_info_num - itv->pgm_info_write_idx) % itv->pgm_info_num;
+	while (i < cnt) {
+		int idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
+		struct v4l2_enc_idx_entry *e = itv->pgm_info + idx;
+		u32 addr = itv->pgm_info_offset + 4 + idx * 24;
+		const int mapping[8] = { -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, -1,
+			V4L2_ENC_IDX_FRAME_B, -1, -1, -1 };
+					// 1=I, 2=P, 4=B
+
+		e->offset = read_enc(addr + 4) + ((u64)read_enc(addr + 8) << 32);
+		if (e->offset > itv->mpg_data_received) {
+			break;
+		}
+		e->offset += itv->vbi_data_inserted;
+		e->length = read_enc(addr);
+		e->pts = read_enc(addr + 16) + ((u64)(read_enc(addr + 20) & 1) << 32);
+		e->flags = mapping[read_enc(addr + 12) & 7];
+		i++;
+	}
+	itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
+}
+
+static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, int *err)
+{
+	struct ivtv *itv = s->itv;
+	struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+	struct ivtv_buffer *buf;
+	DEFINE_WAIT(wait);
+
+	*err = 0;
+	while (1) {
+		if (s->type == IVTV_ENC_STREAM_TYPE_MPG) {
+			/* Process pending program info updates and pending VBI data */
+			ivtv_update_pgm_info(itv);
+
+			if (time_after(jiffies,
+				       itv->dualwatch_jiffies +
+				       msecs_to_jiffies(1000))) {
+				itv->dualwatch_jiffies = jiffies;
+				ivtv_dualwatch(itv);
+			}
+
+			if (test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
+			    !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) {
+				while ((buf = ivtv_dequeue(s_vbi, &s_vbi->q_full))) {
+					/* byteswap and process VBI data */
+					ivtv_process_vbi_data(itv, buf, s_vbi->dma_pts, s_vbi->type);
+					ivtv_enqueue(s_vbi, buf, &s_vbi->q_free);
+				}
+			}
+			buf = &itv->vbi.sliced_mpeg_buf;
+			if (buf->readpos != buf->bytesused) {
+				return buf;
+			}
+		}
+
+		/* do we have leftover data? */
+		buf = ivtv_dequeue(s, &s->q_io);
+		if (buf)
+			return buf;
+
+		/* do we have new data? */
+		buf = ivtv_dequeue(s, &s->q_full);
+		if (buf) {
+			if ((buf->b_flags & IVTV_F_B_NEED_BUF_SWAP) == 0)
+				return buf;
+			buf->b_flags &= ~IVTV_F_B_NEED_BUF_SWAP;
+			if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
+				/* byteswap MPG data */
+				ivtv_buf_swap(buf);
+			else if (s->type != IVTV_DEC_STREAM_TYPE_VBI) {
+				/* byteswap and process VBI data */
+				ivtv_process_vbi_data(itv, buf, s->dma_pts, s->type);
+			}
+			return buf;
+		}
+
+		/* return if end of stream */
+		if (s->type != IVTV_DEC_STREAM_TYPE_VBI && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+			IVTV_DEBUG_INFO("EOS %s\n", s->name);
+			return NULL;
+		}
+
+		/* return if file was opened with O_NONBLOCK */
+		if (non_block) {
+			*err = -EAGAIN;
+			return NULL;
+		}
+
+		/* wait for more data to arrive */
+		mutex_unlock(&itv->serialize_lock);
+		prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
+		/* New buffers might have become available before we were added to the waitqueue */
+		if (!s->q_full.buffers)
+			schedule();
+		finish_wait(&s->waitq, &wait);
+		mutex_lock(&itv->serialize_lock);
+		if (signal_pending(current)) {
+			/* return if a signal was received */
+			IVTV_DEBUG_INFO("User stopped %s\n", s->name);
+			*err = -EINTR;
+			return NULL;
+		}
+	}
+}
+
+static void ivtv_setup_sliced_vbi_buf(struct ivtv *itv)
+{
+	int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES;
+
+	itv->vbi.sliced_mpeg_buf.buf = itv->vbi.sliced_mpeg_data[idx];
+	itv->vbi.sliced_mpeg_buf.bytesused = itv->vbi.sliced_mpeg_size[idx];
+	itv->vbi.sliced_mpeg_buf.readpos = 0;
+}
+
+static size_t ivtv_copy_buf_to_user(struct ivtv_stream *s, struct ivtv_buffer *buf,
+		char __user *ubuf, size_t ucount)
+{
+	struct ivtv *itv = s->itv;
+	size_t len = buf->bytesused - buf->readpos;
+
+	if (len > ucount) len = ucount;
+	if (itv->vbi.insert_mpeg && s->type == IVTV_ENC_STREAM_TYPE_MPG &&
+	    !ivtv_raw_vbi(itv) && buf != &itv->vbi.sliced_mpeg_buf) {
+		const char *start = buf->buf + buf->readpos;
+		const char *p = start + 1;
+		const u8 *q;
+		u8 ch = itv->search_pack_header ? 0xba : 0xe0;
+		int stuffing, i;
+
+		while (start + len > p && (q = memchr(p, 0, start + len - p))) {
+			p = q + 1;
+			if ((char *)q + 15 >= buf->buf + buf->bytesused ||
+			    q[1] != 0 || q[2] != 1 || q[3] != ch) {
+				continue;
+			}
+			if (!itv->search_pack_header) {
+				if ((q[6] & 0xc0) != 0x80)
+					continue;
+				if (((q[7] & 0xc0) == 0x80 && (q[9] & 0xf0) == 0x20) ||
+				    ((q[7] & 0xc0) == 0xc0 && (q[9] & 0xf0) == 0x30)) {
+					ch = 0xba;
+					itv->search_pack_header = 1;
+					p = q + 9;
+				}
+				continue;
+			}
+			stuffing = q[13] & 7;
+			/* all stuffing bytes must be 0xff */
+			for (i = 0; i < stuffing; i++)
+				if (q[14 + i] != 0xff)
+					break;
+			if (i == stuffing && (q[4] & 0xc4) == 0x44 && (q[12] & 3) == 3 &&
+					q[14 + stuffing] == 0 && q[15 + stuffing] == 0 &&
+					q[16 + stuffing] == 1) {
+				itv->search_pack_header = 0;
+				len = (char *)q - start;
+				ivtv_setup_sliced_vbi_buf(itv);
+				break;
+			}
+		}
+	}
+	if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) {
+		IVTV_DEBUG_WARN("copy %zd bytes to user failed for %s\n", len, s->name);
+		return -EFAULT;
+	}
+	/*IVTV_INFO("copied %lld %d %d %d %d %d vbi %d\n", itv->mpg_data_received, len, ucount,
+			buf->readpos, buf->bytesused, buf->bytesused - buf->readpos - len,
+			buf == &itv->vbi.sliced_mpeg_buf); */
+	buf->readpos += len;
+	if (s->type == IVTV_ENC_STREAM_TYPE_MPG && buf != &itv->vbi.sliced_mpeg_buf)
+		itv->mpg_data_received += len;
+	return len;
+}
+
+static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_count, int non_block)
+{
+	struct ivtv *itv = s->itv;
+	size_t tot_written = 0;
+	int single_frame = 0;
+
+	if (atomic_read(&itv->capturing) == 0 && s->fh == NULL) {
+		/* shouldn't happen */
+		IVTV_DEBUG_WARN("Stream %s not initialized before read\n", s->name);
+		return -EIO;
+	}
+
+	/* Each VBI buffer is one frame, the v4l2 API says that for VBI the frames should
+	   arrive one-by-one, so make sure we never output more than one VBI frame at a time */
+	if (s->type == IVTV_DEC_STREAM_TYPE_VBI ||
+	    (s->type == IVTV_ENC_STREAM_TYPE_VBI && !ivtv_raw_vbi(itv)))
+		single_frame = 1;
+
+	for (;;) {
+		struct ivtv_buffer *buf;
+		int rc;
+
+		buf = ivtv_get_buffer(s, non_block, &rc);
+		/* if there is no data available... */
+		if (buf == NULL) {
+			/* if we got data, then return that regardless */
+			if (tot_written)
+				break;
+			/* EOS condition */
+			if (rc == 0) {
+				clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+				clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+				ivtv_release_stream(s);
+			}
+			/* set errno */
+			return rc;
+		}
+		rc = ivtv_copy_buf_to_user(s, buf, ubuf + tot_written, tot_count - tot_written);
+		if (buf != &itv->vbi.sliced_mpeg_buf) {
+			ivtv_enqueue(s, buf, (buf->readpos == buf->bytesused) ? &s->q_free : &s->q_io);
+		}
+		else if (buf->readpos == buf->bytesused) {
+			int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES;
+			itv->vbi.sliced_mpeg_size[idx] = 0;
+			itv->vbi.inserted_frame++;
+			itv->vbi_data_inserted += buf->bytesused;
+		}
+		if (rc < 0)
+			return rc;
+		tot_written += rc;
+
+		if (tot_written == tot_count || single_frame)
+			break;
+	}
+	return tot_written;
+}
+
+static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t count,
+			loff_t *pos, int non_block)
+{
+	ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0;
+	struct ivtv *itv = s->itv;
+
+	IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc);
+	if (rc > 0)
+		pos += rc;
+	return rc;
+}
+
+int ivtv_start_capture(struct ivtv_open_id *id)
+{
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+	struct ivtv_stream *s_vbi;
+
+	if (s->type == IVTV_ENC_STREAM_TYPE_RAD ||
+	    s->type == IVTV_DEC_STREAM_TYPE_MPG ||
+	    s->type == IVTV_DEC_STREAM_TYPE_YUV ||
+	    s->type == IVTV_DEC_STREAM_TYPE_VOUT) {
+		/* you cannot read from these stream types. */
+		return -EPERM;
+	}
+
+	/* Try to claim this stream. */
+	if (ivtv_claim_stream(id, s->type))
+		return -EBUSY;
+
+	/* This stream does not need to start capturing */
+	if (s->type == IVTV_DEC_STREAM_TYPE_VBI) {
+		set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+		return 0;
+	}
+
+	/* If capture is already in progress, then we also have to
+	   do nothing extra. */
+	if (test_bit(IVTV_F_S_STREAMOFF, &s->s_flags) || test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+		set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+		return 0;
+	}
+
+	/* Start VBI capture if required */
+	s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+	if (s->type == IVTV_ENC_STREAM_TYPE_MPG &&
+	    test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
+	    !test_and_set_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) {
+		/* Note: the IVTV_ENC_STREAM_TYPE_VBI is claimed
+		   automatically when the MPG stream is claimed.
+		   We only need to start the VBI capturing. */
+		if (ivtv_start_v4l2_encode_stream(s_vbi)) {
+			IVTV_DEBUG_WARN("VBI capture start failed\n");
+
+			/* Failure, clean up and return an error */
+			clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags);
+			clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+			/* also releases the associated VBI stream */
+			ivtv_release_stream(s);
+			return -EIO;
+		}
+		IVTV_DEBUG_INFO("VBI insertion started\n");
+	}
+
+	/* Tell the card to start capturing */
+	if (!ivtv_start_v4l2_encode_stream(s)) {
+		/* We're done */
+		set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+		/* Resume a possibly paused encoder */
+		if (test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
+			ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1);
+		return 0;
+	}
+
+	/* failure, clean up */
+	IVTV_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name);
+
+	/* Note: the IVTV_ENC_STREAM_TYPE_VBI is released
+	   automatically when the MPG stream is released.
+	   We only need to stop the VBI capturing. */
+	if (s->type == IVTV_ENC_STREAM_TYPE_MPG &&
+	    test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) {
+		ivtv_stop_v4l2_encode_stream(s_vbi, 0);
+		clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags);
+	}
+	clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+	ivtv_release_stream(s);
+	return -EIO;
+}
+
+ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_t * pos)
+{
+	struct ivtv_open_id *id = fh2id(filp->private_data);
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+	ssize_t rc;
+
+	IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);
+
+	if (mutex_lock_interruptible(&itv->serialize_lock))
+		return -ERESTARTSYS;
+	rc = ivtv_start_capture(id);
+	if (!rc)
+		rc = ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
+	mutex_unlock(&itv->serialize_lock);
+	return rc;
+}
+
+int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
+{
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+	int rc;
+
+	if (atomic_read(&itv->decoding) == 0) {
+		if (ivtv_claim_stream(id, s->type)) {
+			/* someone else is using this stream already */
+			IVTV_DEBUG_WARN("start decode, stream already claimed\n");
+			return -EBUSY;
+		}
+		rc = ivtv_start_v4l2_decode_stream(s, 0);
+		if (rc < 0) {
+			if (rc == -EAGAIN)
+				rc = ivtv_start_v4l2_decode_stream(s, 0);
+			if (rc < 0)
+				return rc;
+		}
+	}
+	if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
+		return ivtv_set_speed(itv, speed);
+	return 0;
+}
+
+static ssize_t ivtv_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos)
+{
+	struct ivtv_open_id *id = fh2id(filp->private_data);
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	struct ivtv_buffer *buf;
+	struct ivtv_queue q;
+	int bytes_written = 0;
+	int mode;
+	int rc;
+	DEFINE_WAIT(wait);
+
+	IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name);
+
+	if (s->type != IVTV_DEC_STREAM_TYPE_MPG &&
+	    s->type != IVTV_DEC_STREAM_TYPE_YUV &&
+	    s->type != IVTV_DEC_STREAM_TYPE_VOUT)
+		/* not decoder streams */
+		return -EPERM;
+
+	/* Try to claim this stream */
+	if (ivtv_claim_stream(id, s->type))
+		return -EBUSY;
+
+	/* This stream does not need to start any decoding */
+	if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) {
+		int elems = count / sizeof(struct v4l2_sliced_vbi_data);
+
+		set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+		return ivtv_write_vbi_from_user(itv,
+		   (const struct v4l2_sliced_vbi_data __user *)user_buf, elems);
+	}
+
+	mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV;
+
+	if (ivtv_set_output_mode(itv, mode) != mode) {
+	    ivtv_release_stream(s);
+	    return -EBUSY;
+	}
+	ivtv_queue_init(&q);
+	set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+
+	/* Start decoder (returns 0 if already started) */
+	rc = ivtv_start_decoding(id, itv->speed);
+	if (rc) {
+		IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name);
+
+		/* failure, clean up */
+		clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+		clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+		return rc;
+	}
+
+retry:
+	/* If possible, just DMA the entire frame - Check the data transfer size
+	since we may get here before the stream has been fully set-up */
+	if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) {
+		while (count >= itv->dma_data_req_size) {
+			rc = ivtv_yuv_udma_stream_frame(itv, (void __user *)user_buf);
+
+			if (rc < 0)
+				return rc;
+
+			bytes_written += itv->dma_data_req_size;
+			user_buf += itv->dma_data_req_size;
+			count -= itv->dma_data_req_size;
+		}
+		if (count == 0) {
+			IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
+			return bytes_written;
+		}
+	}
+
+	for (;;) {
+		/* Gather buffers */
+		while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io)))
+			ivtv_enqueue(s, buf, &q);
+		while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_free))) {
+			ivtv_enqueue(s, buf, &q);
+		}
+		if (q.buffers)
+			break;
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		mutex_unlock(&itv->serialize_lock);
+		prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
+		/* New buffers might have become free before we were added to the waitqueue */
+		if (!s->q_free.buffers)
+			schedule();
+		finish_wait(&s->waitq, &wait);
+		mutex_lock(&itv->serialize_lock);
+		if (signal_pending(current)) {
+			IVTV_DEBUG_INFO("User stopped %s\n", s->name);
+			return -EINTR;
+		}
+	}
+
+	/* copy user data into buffers */
+	while ((buf = ivtv_dequeue(s, &q))) {
+		/* yuv is a pain. Don't copy more data than needed for a single
+		   frame, otherwise we lose sync with the incoming stream */
+		if (s->type == IVTV_DEC_STREAM_TYPE_YUV &&
+		    yi->stream_size + count > itv->dma_data_req_size)
+			rc  = ivtv_buf_copy_from_user(s, buf, user_buf,
+				itv->dma_data_req_size - yi->stream_size);
+		else
+			rc = ivtv_buf_copy_from_user(s, buf, user_buf, count);
+
+		/* Make sure we really got all the user data */
+		if (rc < 0) {
+			ivtv_queue_move(s, &q, NULL, &s->q_free, 0);
+			return rc;
+		}
+		user_buf += rc;
+		count -= rc;
+		bytes_written += rc;
+
+		if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
+			yi->stream_size += rc;
+			/* If we have a complete yuv frame, break loop now */
+			if (yi->stream_size == itv->dma_data_req_size) {
+				ivtv_enqueue(s, buf, &s->q_full);
+				yi->stream_size = 0;
+				break;
+			}
+		}
+
+		if (buf->bytesused != s->buf_size) {
+			/* incomplete, leave in q_io for next time */
+			ivtv_enqueue(s, buf, &s->q_io);
+			break;
+		}
+		/* Byteswap MPEG buffer */
+		if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
+			ivtv_buf_swap(buf);
+		ivtv_enqueue(s, buf, &s->q_full);
+	}
+
+	if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) {
+		if (s->q_full.length >= itv->dma_data_req_size) {
+			int got_sig;
+
+			if (mode == OUT_YUV)
+				ivtv_yuv_setup_stream_frame(itv);
+
+			mutex_unlock(&itv->serialize_lock);
+			prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
+			while (!(got_sig = signal_pending(current)) &&
+					test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) {
+				schedule();
+			}
+			finish_wait(&itv->dma_waitq, &wait);
+			mutex_lock(&itv->serialize_lock);
+			if (got_sig) {
+				IVTV_DEBUG_INFO("User interrupted %s\n", s->name);
+				return -EINTR;
+			}
+
+			clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
+			ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size);
+			ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 1);
+		}
+	}
+	/* more user data is available, wait until buffers become free
+	   to transfer the rest. */
+	if (count && !(filp->f_flags & O_NONBLOCK))
+		goto retry;
+	IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
+	return bytes_written;
+}
+
+ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos)
+{
+	struct ivtv_open_id *id = fh2id(filp->private_data);
+	struct ivtv *itv = id->itv;
+	ssize_t res;
+
+	if (mutex_lock_interruptible(&itv->serialize_lock))
+		return -ERESTARTSYS;
+	res = ivtv_write(filp, user_buf, count, pos);
+	mutex_unlock(&itv->serialize_lock);
+	return res;
+}
+
+unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait)
+{
+	struct ivtv_open_id *id = fh2id(filp->private_data);
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+	int res = 0;
+
+	/* add stream's waitq to the poll list */
+	IVTV_DEBUG_HI_FILE("Decoder poll\n");
+
+	/* If there are subscribed events, then only use the new event
+	   API instead of the old video.h based API. */
+	if (!list_empty(&id->fh.subscribed)) {
+		poll_wait(filp, &id->fh.wait, wait);
+		/* Turn off the old-style vsync events */
+		clear_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
+		if (v4l2_event_pending(&id->fh))
+			res = POLLPRI;
+	} else {
+		/* This is the old-style API which is here only for backwards
+		   compatibility. */
+		poll_wait(filp, &s->waitq, wait);
+		set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
+		if (test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags) ||
+		    test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags))
+			res = POLLPRI;
+	}
+
+	/* Allow write if buffers are available for writing */
+	if (s->q_free.buffers)
+		res |= POLLOUT | POLLWRNORM;
+	return res;
+}
+
+unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table *wait)
+{
+	unsigned long req_events = poll_requested_events(wait);
+	struct ivtv_open_id *id = fh2id(filp->private_data);
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+	int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+	unsigned res = 0;
+
+	/* Start a capture if there is none */
+	if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags) &&
+			(req_events & (POLLIN | POLLRDNORM))) {
+		int rc;
+
+		mutex_lock(&itv->serialize_lock);
+		rc = ivtv_start_capture(id);
+		mutex_unlock(&itv->serialize_lock);
+		if (rc) {
+			IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n",
+					s->name, rc);
+			return POLLERR;
+		}
+		IVTV_DEBUG_FILE("Encoder poll started capture\n");
+	}
+
+	/* add stream's waitq to the poll list */
+	IVTV_DEBUG_HI_FILE("Encoder poll\n");
+	poll_wait(filp, &s->waitq, wait);
+	if (v4l2_event_pending(&id->fh))
+		res |= POLLPRI;
+	else
+		poll_wait(filp, &id->fh.wait, wait);
+
+	if (s->q_full.length || s->q_io.length)
+		return res | POLLIN | POLLRDNORM;
+	if (eof)
+		return res | POLLHUP;
+	return res;
+}
+
+void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end)
+{
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+
+	IVTV_DEBUG_FILE("close() of %s\n", s->name);
+
+	/* 'Unclaim' this stream */
+
+	/* Stop capturing */
+	if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+		struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+
+		IVTV_DEBUG_INFO("close stopping capture\n");
+		/* Special case: a running VBI capture for VBI insertion
+		   in the mpeg stream. Need to stop that too. */
+		if (id->type == IVTV_ENC_STREAM_TYPE_MPG &&
+		    test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags) &&
+		    !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) {
+			IVTV_DEBUG_INFO("close stopping embedded VBI capture\n");
+			ivtv_stop_v4l2_encode_stream(s_vbi, 0);
+		}
+		if ((id->type == IVTV_DEC_STREAM_TYPE_VBI ||
+		     id->type == IVTV_ENC_STREAM_TYPE_VBI) &&
+		    test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) {
+			/* Also used internally, don't stop capturing */
+			s->fh = NULL;
+		}
+		else {
+			ivtv_stop_v4l2_encode_stream(s, gop_end);
+		}
+	}
+	if (!gop_end) {
+		clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+		clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+		ivtv_release_stream(s);
+	}
+}
+
+static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts)
+{
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+
+	IVTV_DEBUG_FILE("close() of %s\n", s->name);
+
+	if (id->type == IVTV_DEC_STREAM_TYPE_YUV &&
+		test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) {
+		/* Restore registers we've changed & clean up any mess */
+		ivtv_yuv_close(itv);
+	}
+
+	/* Stop decoding */
+	if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+		IVTV_DEBUG_INFO("close stopping decode\n");
+
+		ivtv_stop_v4l2_decode_stream(s, flags, pts);
+		itv->output_mode = OUT_NONE;
+	}
+	clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+	clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+
+	if (itv->output_mode == OUT_UDMA_YUV && id->yuv_frames)
+		itv->output_mode = OUT_NONE;
+
+	itv->speed = 0;
+	clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags);
+	ivtv_release_stream(s);
+}
+
+int ivtv_v4l2_close(struct file *filp)
+{
+	struct v4l2_fh *fh = filp->private_data;
+	struct ivtv_open_id *id = fh2id(fh);
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+
+	IVTV_DEBUG_FILE("close %s\n", s->name);
+
+	mutex_lock(&itv->serialize_lock);
+
+	/* Stop radio */
+	if (id->type == IVTV_ENC_STREAM_TYPE_RAD &&
+			v4l2_fh_is_singular_file(filp)) {
+		/* Closing radio device, return to TV mode */
+		ivtv_mute(itv);
+		/* Mark that the radio is no longer in use */
+		clear_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
+		/* Switch tuner to TV */
+		ivtv_call_all(itv, core, s_std, itv->std);
+		/* Select correct audio input (i.e. TV tuner or Line in) */
+		ivtv_audio_set_io(itv);
+		if (itv->hw_flags & IVTV_HW_SAA711X) {
+			ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq,
+					SAA7115_FREQ_32_11_MHZ, 0);
+		}
+		if (atomic_read(&itv->capturing) > 0) {
+			/* Undo video mute */
+			ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1,
+					v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute) |
+					(v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8));
+		}
+		/* Done! Unmute and continue. */
+		ivtv_unmute(itv);
+	}
+
+	v4l2_fh_del(fh);
+	v4l2_fh_exit(fh);
+
+	/* Easy case first: this stream was never claimed by us */
+	if (s->fh != &id->fh)
+		goto close_done;
+
+	/* 'Unclaim' this stream */
+
+	if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {
+		struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT];
+
+		ivtv_stop_decoding(id, V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY, 0);
+
+		/* If all output streams are closed, and if the user doesn't have
+		   IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */
+		if (itv->output_mode == OUT_NONE && !test_bit(IVTV_F_S_APPL_IO, &s_vout->s_flags)) {
+			/* disable CC on TV-out */
+			ivtv_disable_cc(itv);
+		}
+	} else {
+		ivtv_stop_capture(id, 0);
+	}
+close_done:
+	kfree(id);
+	mutex_unlock(&itv->serialize_lock);
+	return 0;
+}
+
+static int ivtv_open(struct file *filp)
+{
+	struct video_device *vdev = video_devdata(filp);
+	struct ivtv_stream *s = video_get_drvdata(vdev);
+	struct ivtv *itv = s->itv;
+	struct ivtv_open_id *item;
+	int res = 0;
+
+	IVTV_DEBUG_FILE("open %s\n", s->name);
+
+	if (ivtv_init_on_first_open(itv)) {
+		IVTV_ERR("Failed to initialize on device %s\n",
+			 video_device_node_name(vdev));
+		return -ENXIO;
+	}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	/* Unless ivtv_fw_debug is set, error out if firmware dead. */
+	if (ivtv_fw_debug) {
+		IVTV_WARN("Opening %s with dead firmware lockout disabled\n",
+			  video_device_node_name(vdev));
+		IVTV_WARN("Selected firmware errors will be ignored\n");
+	} else {
+#else
+	if (1) {
+#endif
+		res = ivtv_firmware_check(itv, "ivtv_serialized_open");
+		if (res == -EAGAIN)
+			res = ivtv_firmware_check(itv, "ivtv_serialized_open");
+		if (res < 0)
+			return -EIO;
+	}
+
+	if (s->type == IVTV_DEC_STREAM_TYPE_MPG &&
+		test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
+		return -EBUSY;
+
+	if (s->type == IVTV_DEC_STREAM_TYPE_YUV &&
+		test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags))
+		return -EBUSY;
+
+	if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
+		if (read_reg(0x82c) == 0) {
+			IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n");
+			/* return -ENODEV; */
+		}
+		ivtv_udma_alloc(itv);
+	}
+
+	/* Allocate memory */
+	item = kzalloc(sizeof(struct ivtv_open_id), GFP_KERNEL);
+	if (NULL == item) {
+		IVTV_DEBUG_WARN("nomem on v4l2 open\n");
+		return -ENOMEM;
+	}
+	v4l2_fh_init(&item->fh, s->vdev);
+	item->itv = itv;
+	item->type = s->type;
+
+	filp->private_data = &item->fh;
+	v4l2_fh_add(&item->fh);
+
+	if (item->type == IVTV_ENC_STREAM_TYPE_RAD &&
+			v4l2_fh_is_singular_file(filp)) {
+		if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
+			if (atomic_read(&itv->capturing) > 0) {
+				/* switching to radio while capture is
+				   in progress is not polite */
+				v4l2_fh_del(&item->fh);
+				v4l2_fh_exit(&item->fh);
+				kfree(item);
+				return -EBUSY;
+			}
+		}
+		/* Mark that the radio is being used. */
+		set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
+		/* We have the radio */
+		ivtv_mute(itv);
+		/* Switch tuner to radio */
+		ivtv_call_all(itv, tuner, s_radio);
+		/* Select the correct audio input (i.e. radio tuner) */
+		ivtv_audio_set_io(itv);
+		if (itv->hw_flags & IVTV_HW_SAA711X) {
+			ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq,
+				SAA7115_FREQ_32_11_MHZ, SAA7115_FREQ_FL_APLL);
+		}
+		/* Done! Unmute and continue. */
+		ivtv_unmute(itv);
+	}
+
+	/* YUV or MPG Decoding Mode? */
+	if (s->type == IVTV_DEC_STREAM_TYPE_MPG) {
+		clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
+	} else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
+		set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
+		/* For yuv, we need to know the dma size before we start */
+		itv->dma_data_req_size =
+				1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
+		itv->yuv_info.stream_size = 0;
+	}
+	return 0;
+}
+
+int ivtv_v4l2_open(struct file *filp)
+{
+	struct video_device *vdev = video_devdata(filp);
+	int res;
+
+	if (mutex_lock_interruptible(vdev->lock))
+		return -ERESTARTSYS;
+	res = ivtv_open(filp);
+	mutex_unlock(vdev->lock);
+	return res;
+}
+
+void ivtv_mute(struct ivtv *itv)
+{
+	if (atomic_read(&itv->capturing))
+		ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 1);
+	IVTV_DEBUG_INFO("Mute\n");
+}
+
+void ivtv_unmute(struct ivtv *itv)
+{
+	if (atomic_read(&itv->capturing)) {
+		ivtv_msleep_timeout(100, 0);
+		ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
+		ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0);
+	}
+	IVTV_DEBUG_INFO("Unmute\n");
+}
diff --git a/drivers/media/pci/ivtv/ivtv-fileops.h b/drivers/media/pci/ivtv/ivtv-fileops.h
new file mode 100644
index 0000000..049a292
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-fileops.h
@@ -0,0 +1,44 @@
+/*
+    file operation functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef IVTV_FILEOPS_H
+#define IVTV_FILEOPS_H
+
+/* Testing/Debugging */
+int ivtv_v4l2_open(struct file *filp);
+ssize_t ivtv_v4l2_read(struct file *filp, char __user *buf, size_t count,
+		      loff_t * pos);
+ssize_t ivtv_v4l2_write(struct file *filp, const char __user *buf, size_t count,
+		       loff_t * pos);
+int ivtv_v4l2_close(struct file *filp);
+unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait);
+unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table * wait);
+int ivtv_start_capture(struct ivtv_open_id *id);
+void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end);
+int ivtv_start_decoding(struct ivtv_open_id *id, int speed);
+void ivtv_mute(struct ivtv *itv);
+void ivtv_unmute(struct ivtv *itv);
+
+/* Utilities */
+
+/* Release a previously claimed stream. */
+void ivtv_release_stream(struct ivtv_stream *s);
+
+#endif
diff --git a/drivers/media/pci/ivtv/ivtv-firmware.c b/drivers/media/pci/ivtv/ivtv-firmware.c
new file mode 100644
index 0000000..6ec7705
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-firmware.c
@@ -0,0 +1,402 @@
+/*
+    ivtv firmware functions.
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-firmware.h"
+#include "ivtv-yuv.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-cards.h"
+#include <linux/firmware.h>
+#include <media/saa7127.h>
+
+#define IVTV_MASK_SPU_ENABLE 		0xFFFFFFFE
+#define IVTV_MASK_VPU_ENABLE15 		0xFFFFFFF6
+#define IVTV_MASK_VPU_ENABLE16 		0xFFFFFFFB
+#define IVTV_CMD_VDM_STOP 		0x00000000
+#define IVTV_CMD_AO_STOP 		0x00000005
+#define IVTV_CMD_APU_PING 		0x00000000
+#define IVTV_CMD_VPU_STOP15 		0xFFFFFFFE
+#define IVTV_CMD_VPU_STOP16 		0xFFFFFFEE
+#define IVTV_CMD_HW_BLOCKS_RST 		0xFFFFFFFF
+#define IVTV_CMD_SPU_STOP 		0x00000001
+#define IVTV_CMD_SDRAM_PRECHARGE_INIT 	0x0000001A
+#define IVTV_CMD_SDRAM_REFRESH_INIT 	0x80000640
+#define IVTV_SDRAM_SLEEPTIME 		600
+
+#define IVTV_DECODE_INIT_MPEG_FILENAME 	"v4l-cx2341x-init.mpg"
+#define IVTV_DECODE_INIT_MPEG_SIZE 	(152*1024)
+
+/* Encoder/decoder firmware sizes */
+#define IVTV_FW_ENC_SIZE 		(376836)
+#define IVTV_FW_DEC_SIZE 		(256*1024)
+
+static int load_fw_direct(const char *fn, volatile u8 __iomem *mem, struct ivtv *itv, long size)
+{
+	const struct firmware *fw = NULL;
+	int retries = 3;
+
+retry:
+	if (retries && request_firmware(&fw, fn, &itv->pdev->dev) == 0) {
+		int i;
+		volatile u32 __iomem *dst = (volatile u32 __iomem *)mem;
+		const u32 *src = (const u32 *)fw->data;
+
+		if (fw->size != size) {
+			/* Due to race conditions in firmware loading (esp. with udev <0.95)
+			   the wrong file was sometimes loaded. So we check filesizes to
+			   see if at least the right-sized file was loaded. If not, then we
+			   retry. */
+			IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
+			release_firmware(fw);
+			retries--;
+			goto retry;
+		}
+		for (i = 0; i < fw->size; i += 4) {
+			/* no need for endianness conversion on the ppc */
+			__raw_writel(*src, dst);
+			dst++;
+			src++;
+		}
+		IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size);
+		release_firmware(fw);
+		return size;
+	}
+	IVTV_ERR("Unable to open firmware %s (must be %ld bytes)\n", fn, size);
+	IVTV_ERR("Did you put the firmware in the hotplug firmware directory?\n");
+	return -ENOMEM;
+}
+
+void ivtv_halt_firmware(struct ivtv *itv)
+{
+	IVTV_DEBUG_INFO("Preparing for firmware halt.\n");
+	if (itv->has_cx23415 && itv->dec_mbox.mbox)
+		ivtv_vapi(itv, CX2341X_DEC_HALT_FW, 0);
+	if (itv->enc_mbox.mbox)
+		ivtv_vapi(itv, CX2341X_ENC_HALT_FW, 0);
+
+	ivtv_msleep_timeout(10, 0);
+	itv->enc_mbox.mbox = itv->dec_mbox.mbox = NULL;
+
+	IVTV_DEBUG_INFO("Stopping VDM\n");
+	write_reg(IVTV_CMD_VDM_STOP, IVTV_REG_VDM);
+
+	IVTV_DEBUG_INFO("Stopping AO\n");
+	write_reg(IVTV_CMD_AO_STOP, IVTV_REG_AO);
+
+	IVTV_DEBUG_INFO("pinging (?) APU\n");
+	write_reg(IVTV_CMD_APU_PING, IVTV_REG_APU);
+
+	IVTV_DEBUG_INFO("Stopping VPU\n");
+	if (!itv->has_cx23415)
+		write_reg(IVTV_CMD_VPU_STOP16, IVTV_REG_VPU);
+	else
+		write_reg(IVTV_CMD_VPU_STOP15, IVTV_REG_VPU);
+
+	IVTV_DEBUG_INFO("Resetting Hw Blocks\n");
+	write_reg(IVTV_CMD_HW_BLOCKS_RST, IVTV_REG_HW_BLOCKS);
+
+	IVTV_DEBUG_INFO("Stopping SPU\n");
+	write_reg(IVTV_CMD_SPU_STOP, IVTV_REG_SPU);
+
+	ivtv_msleep_timeout(10, 0);
+
+	IVTV_DEBUG_INFO("init Encoder SDRAM pre-charge\n");
+	write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_ENC_SDRAM_PRECHARGE);
+
+	IVTV_DEBUG_INFO("init Encoder SDRAM refresh to 1us\n");
+	write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_ENC_SDRAM_REFRESH);
+
+	if (itv->has_cx23415) {
+		IVTV_DEBUG_INFO("init Decoder SDRAM pre-charge\n");
+		write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_DEC_SDRAM_PRECHARGE);
+
+		IVTV_DEBUG_INFO("init Decoder SDRAM refresh to 1us\n");
+		write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_DEC_SDRAM_REFRESH);
+	}
+
+	IVTV_DEBUG_INFO("Sleeping for %dms\n", IVTV_SDRAM_SLEEPTIME);
+	ivtv_msleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
+}
+
+void ivtv_firmware_versions(struct ivtv *itv)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+
+	/* Encoder */
+	ivtv_vapi_result(itv, data, CX2341X_ENC_GET_VERSION, 0);
+	IVTV_INFO("Encoder revision: 0x%08x\n", data[0]);
+
+	if (data[0] != 0x02060039)
+		IVTV_WARN("Recommended firmware version is 0x02060039.\n");
+
+	if (itv->has_cx23415) {
+		/* Decoder */
+		ivtv_vapi_result(itv, data, CX2341X_DEC_GET_VERSION, 0);
+		IVTV_INFO("Decoder revision: 0x%08x\n", data[0]);
+	}
+}
+
+static int ivtv_firmware_copy(struct ivtv *itv)
+{
+	IVTV_DEBUG_INFO("Loading encoder image\n");
+	if (load_fw_direct(CX2341X_FIRM_ENC_FILENAME,
+		   itv->enc_mem, itv, IVTV_FW_ENC_SIZE) != IVTV_FW_ENC_SIZE) {
+		IVTV_DEBUG_WARN("failed loading encoder firmware\n");
+		return -3;
+	}
+	if (!itv->has_cx23415)
+		return 0;
+
+	IVTV_DEBUG_INFO("Loading decoder image\n");
+	if (load_fw_direct(CX2341X_FIRM_DEC_FILENAME,
+		   itv->dec_mem, itv, IVTV_FW_DEC_SIZE) != IVTV_FW_DEC_SIZE) {
+		IVTV_DEBUG_WARN("failed loading decoder firmware\n");
+		return -1;
+	}
+	return 0;
+}
+
+static volatile struct ivtv_mailbox __iomem *ivtv_search_mailbox(const volatile u8 __iomem *mem, u32 size)
+{
+	int i;
+
+	/* mailbox is preceded by a 16 byte 'magic cookie' starting at a 256-byte
+	   address boundary */
+	for (i = 0; i < size; i += 0x100) {
+		if (readl(mem + i)      == 0x12345678 &&
+		    readl(mem + i + 4)  == 0x34567812 &&
+		    readl(mem + i + 8)  == 0x56781234 &&
+		    readl(mem + i + 12) == 0x78123456) {
+			return (volatile struct ivtv_mailbox __iomem *)(mem + i + 16);
+		}
+	}
+	return NULL;
+}
+
+int ivtv_firmware_init(struct ivtv *itv)
+{
+	int err;
+
+	ivtv_halt_firmware(itv);
+
+	/* load firmware */
+	err = ivtv_firmware_copy(itv);
+	if (err) {
+		IVTV_DEBUG_WARN("Error %d loading firmware\n", err);
+		return err;
+	}
+
+	/* start firmware */
+	write_reg(read_reg(IVTV_REG_SPU) & IVTV_MASK_SPU_ENABLE, IVTV_REG_SPU);
+	ivtv_msleep_timeout(100, 0);
+	if (itv->has_cx23415)
+		write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE15, IVTV_REG_VPU);
+	else
+		write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE16, IVTV_REG_VPU);
+	ivtv_msleep_timeout(100, 0);
+
+	/* find mailboxes and ping firmware */
+	itv->enc_mbox.mbox = ivtv_search_mailbox(itv->enc_mem, IVTV_ENCODER_SIZE);
+	if (itv->enc_mbox.mbox == NULL)
+		IVTV_ERR("Encoder mailbox not found\n");
+	else if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0)) {
+		IVTV_ERR("Encoder firmware dead!\n");
+		itv->enc_mbox.mbox = NULL;
+	}
+	if (itv->enc_mbox.mbox == NULL)
+		return -ENODEV;
+
+	if (!itv->has_cx23415)
+		return 0;
+
+	itv->dec_mbox.mbox = ivtv_search_mailbox(itv->dec_mem, IVTV_DECODER_SIZE);
+	if (itv->dec_mbox.mbox == NULL) {
+		IVTV_ERR("Decoder mailbox not found\n");
+	} else if (itv->has_cx23415 && ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0)) {
+		IVTV_ERR("Decoder firmware dead!\n");
+		itv->dec_mbox.mbox = NULL;
+	} else {
+		/* Firmware okay, so check yuv output filter table */
+		ivtv_yuv_filter_check(itv);
+	}
+	return itv->dec_mbox.mbox ? 0 : -ENODEV;
+}
+
+void ivtv_init_mpeg_decoder(struct ivtv *itv)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	long readbytes;
+	volatile u8 __iomem *mem_offset;
+
+	data[0] = 0;
+	data[1] = itv->cxhdl.width;	/* YUV source width */
+	data[2] = itv->cxhdl.height;
+	data[3] = itv->cxhdl.audio_properties;	/* Audio settings to use,
+							   bitmap. see docs. */
+	if (ivtv_api(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, data)) {
+		IVTV_ERR("ivtv_init_mpeg_decoder failed to set decoder source\n");
+		return;
+	}
+
+	if (ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1) != 0) {
+		IVTV_ERR("ivtv_init_mpeg_decoder failed to start playback\n");
+		return;
+	}
+	ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 2, data);
+	mem_offset = itv->dec_mem + data[1];
+
+	if ((readbytes = load_fw_direct(IVTV_DECODE_INIT_MPEG_FILENAME,
+		mem_offset, itv, IVTV_DECODE_INIT_MPEG_SIZE)) <= 0) {
+		IVTV_DEBUG_WARN("failed to read mpeg decoder initialisation file %s\n",
+				IVTV_DECODE_INIT_MPEG_FILENAME);
+	} else {
+		ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, readbytes, 0);
+		ivtv_msleep_timeout(100, 0);
+	}
+	ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
+}
+
+/* Try to restart the card & restore previous settings */
+int ivtv_firmware_restart(struct ivtv *itv)
+{
+	int rc = 0;
+	v4l2_std_id std;
+
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
+		/* Display test image during restart */
+		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
+		    SAA7127_INPUT_TYPE_TEST_IMAGE,
+		    itv->card->video_outputs[itv->active_output].video_output,
+		    0);
+
+	mutex_lock(&itv->udma.lock);
+
+	rc = ivtv_firmware_init(itv);
+	if (rc) {
+		mutex_unlock(&itv->udma.lock);
+		return rc;
+	}
+
+	/* Allow settings to reload */
+	ivtv_mailbox_cache_invalidate(itv);
+
+	/* Restore encoder video standard */
+	std = itv->std;
+	itv->std = 0;
+	ivtv_s_std_enc(itv, &std);
+
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+		ivtv_init_mpeg_decoder(itv);
+
+		/* Restore decoder video standard */
+		std = itv->std_out;
+		itv->std_out = 0;
+		ivtv_s_std_dec(itv, &std);
+
+		/* Restore framebuffer if active */
+		if (itv->ivtvfb_restore)
+			itv->ivtvfb_restore(itv);
+
+		/* Restore alpha settings */
+		ivtv_set_osd_alpha(itv);
+
+		/* Restore normal output */
+		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
+		    SAA7127_INPUT_TYPE_NORMAL,
+		    itv->card->video_outputs[itv->active_output].video_output,
+		    0);
+	}
+
+	mutex_unlock(&itv->udma.lock);
+	return rc;
+}
+
+/* Check firmware running state. The checks fall through
+   allowing multiple failures to be logged. */
+int ivtv_firmware_check(struct ivtv *itv, char *where)
+{
+	int res = 0;
+
+	/* Check encoder is still running */
+	if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0) < 0) {
+		IVTV_WARN("Encoder has died : %s\n", where);
+		res = -1;
+	}
+
+	/* Also check audio. Only check if not in use & encoder is okay */
+	if (!res && !atomic_read(&itv->capturing) &&
+	    (!atomic_read(&itv->decoding) ||
+	     (atomic_read(&itv->decoding) < 2 && test_bit(IVTV_F_I_DEC_YUV,
+							     &itv->i_flags)))) {
+
+		if (ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12) < 0) {
+			IVTV_WARN("Audio has died (Encoder OK) : %s\n", where);
+			res = -2;
+		}
+	}
+
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+		/* Second audio check. Skip if audio already failed */
+		if (res != -2 && read_dec(0x100) != read_dec(0x104)) {
+			/* Wait & try again to be certain. */
+			ivtv_msleep_timeout(14, 0);
+			if (read_dec(0x100) != read_dec(0x104)) {
+				IVTV_WARN("Audio has died (Decoder) : %s\n",
+					  where);
+				res = -1;
+			}
+		}
+
+		/* Check decoder is still running */
+		if (ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0) < 0) {
+			IVTV_WARN("Decoder has died : %s\n", where);
+			res = -1;
+		}
+	}
+
+	/* If something failed & currently idle, try to reload */
+	if (res && !atomic_read(&itv->capturing) &&
+						!atomic_read(&itv->decoding)) {
+		IVTV_INFO("Detected in %s that firmware had failed - "
+			  "Reloading\n", where);
+		res = ivtv_firmware_restart(itv);
+		/*
+		 * Even if restarted ok, still signal a problem had occurred.
+		 * The caller can come through this function again to check
+		 * if things are really ok after the restart.
+		 */
+		if (!res) {
+			IVTV_INFO("Firmware restart okay\n");
+			res = -EAGAIN;
+		} else {
+			IVTV_INFO("Firmware restart failed\n");
+		}
+	} else if (res) {
+		res = -EIO;
+	}
+
+	return res;
+}
+
+MODULE_FIRMWARE(CX2341X_FIRM_ENC_FILENAME);
+MODULE_FIRMWARE(CX2341X_FIRM_DEC_FILENAME);
+MODULE_FIRMWARE(IVTV_DECODE_INIT_MPEG_FILENAME);
diff --git a/drivers/media/pci/ivtv/ivtv-firmware.h b/drivers/media/pci/ivtv/ivtv-firmware.h
new file mode 100644
index 0000000..52bb4e5
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-firmware.h
@@ -0,0 +1,31 @@
+/*
+    ivtv firmware functions.
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef IVTV_FIRMWARE_H
+#define IVTV_FIRMWARE_H
+
+int ivtv_firmware_init(struct ivtv *itv);
+void ivtv_firmware_versions(struct ivtv *itv);
+void ivtv_halt_firmware(struct ivtv *itv);
+void ivtv_init_mpeg_decoder(struct ivtv *itv);
+int ivtv_firmware_check(struct ivtv *itv, char *where);
+
+#endif
diff --git a/drivers/media/pci/ivtv/ivtv-gpio.c b/drivers/media/pci/ivtv/ivtv-gpio.c
new file mode 100644
index 0000000..8f0d077
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-gpio.c
@@ -0,0 +1,374 @@
+/*
+    gpio functions.
+    Merging GPIO support into driver:
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-cards.h"
+#include "ivtv-gpio.h"
+#include "tuner-xc2028.h"
+#include <media/tuner.h>
+#include <media/v4l2-ctrls.h>
+
+/*
+ * GPIO assignment of Yuan MPG600/MPG160
+ *
+ *    bit 15  14  13  12 |  11  10   9   8 |   7   6   5   4 |   3   2   1   0
+ * OUTPUT         IN1 IN0                                       AM3 AM2 AM1 AM0
+ *  INPUT                   DM1         DM0
+ *
+ *   IN* : Input selection
+ *          IN1 IN0
+ *           1   1  N/A
+ *           1   0  Line
+ *           0   1  N/A
+ *           0   0  Tuner
+ *
+ *   AM* : Audio Mode
+ *          AM3  0: Normal        1: Mixed(Sub+Main channel)
+ *          AM2  0: Subchannel    1: Main channel
+ *          AM1  0: Stereo        1: Mono
+ *          AM0  0: Normal        1: Mute
+ *
+ *   DM* : Detected tuner audio Mode
+ *          DM1  0: Stereo        1: Mono
+ *          DM0  0: Multiplex     1: Normal
+ *
+ * GPIO Initial Settings
+ *           MPG600   MPG160
+ *     DIR   0x3080   0x7080
+ *  OUTPUT   0x000C   0x400C
+ *
+ *  Special thanks to Makoto Iguchi <iguchi@tahoo.org> and Mr. Anonymous
+ *  for analyzing GPIO of MPG160.
+ *
+ *****************************************************************************
+ *
+ * GPIO assignment of Avermedia M179 (per information direct from AVerMedia)
+ *
+ *    bit 15  14  13  12 |  11  10   9   8 |   7   6   5   4 |   3   2   1   0
+ * OUTPUT IN0 AM0 IN1               AM1 AM2       IN2     BR0   BR1
+ *  INPUT
+ *
+ *   IN* : Input selection
+ *          IN0 IN1 IN2
+ *           *   1   *  Mute
+ *           0   0   0  Line-In
+ *           1   0   0  TV Tuner Audio
+ *           0   0   1  FM Audio
+ *           1   0   1  Mute
+ *
+ *   AM* : Audio Mode
+ *          AM0 AM1 AM2
+ *           0   0   0  TV Tuner Audio: L_OUT=(L+R)/2, R_OUT=SAP
+ *           0   0   1  TV Tuner Audio: L_OUT=R_OUT=SAP   (SAP)
+ *           0   1   0  TV Tuner Audio: L_OUT=L, R_OUT=R   (stereo)
+ *           0   1   1  TV Tuner Audio: mute
+ *           1   *   *  TV Tuner Audio: L_OUT=R_OUT=(L+R)/2   (mono)
+ *
+ *   BR* : Audio Sample Rate (BR stands for bitrate for some reason)
+ *          BR0 BR1
+ *           0   0   32 kHz
+ *           0   1   44.1 kHz
+ *           1   0   48 kHz
+ *
+ *   DM* : Detected tuner audio Mode
+ *         Unknown currently
+ *
+ * Special thanks to AVerMedia Technologies, Inc. and Jiun-Kuei Jung at
+ * AVerMedia for providing the GPIO information used to add support
+ * for the M179 cards.
+ */
+
+/********************* GPIO stuffs *********************/
+
+/* GPIO registers */
+#define IVTV_REG_GPIO_IN    0x9008
+#define IVTV_REG_GPIO_OUT   0x900c
+#define IVTV_REG_GPIO_DIR   0x9020
+
+void ivtv_reset_ir_gpio(struct ivtv *itv)
+{
+	int curdir, curout;
+
+	if (itv->card->type != IVTV_CARD_PVR_150)
+		return;
+	IVTV_DEBUG_INFO("Resetting PVR150 IR\n");
+	curout = read_reg(IVTV_REG_GPIO_OUT);
+	curdir = read_reg(IVTV_REG_GPIO_DIR);
+	curdir |= 0x80;
+	write_reg(curdir, IVTV_REG_GPIO_DIR);
+	curout = (curout & ~0xF) | 1;
+	write_reg(curout, IVTV_REG_GPIO_OUT);
+	/* We could use something else for smaller time */
+	schedule_timeout_interruptible(msecs_to_jiffies(1));
+	curout |= 2;
+	write_reg(curout, IVTV_REG_GPIO_OUT);
+	curdir &= ~0x80;
+	write_reg(curdir, IVTV_REG_GPIO_DIR);
+}
+
+/* Xceive tuner reset function */
+int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value)
+{
+	struct i2c_algo_bit_data *algo = dev;
+	struct ivtv *itv = algo->data;
+	u32 curout;
+
+	if (cmd != XC2028_TUNER_RESET)
+		return 0;
+	IVTV_DEBUG_INFO("Resetting tuner\n");
+	curout = read_reg(IVTV_REG_GPIO_OUT);
+	curout &= ~(1 << itv->card->xceive_pin);
+	write_reg(curout, IVTV_REG_GPIO_OUT);
+	schedule_timeout_interruptible(msecs_to_jiffies(1));
+
+	curout |= 1 << itv->card->xceive_pin;
+	write_reg(curout, IVTV_REG_GPIO_OUT);
+	schedule_timeout_interruptible(msecs_to_jiffies(1));
+	return 0;
+}
+
+static inline struct ivtv *sd_to_ivtv(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct ivtv, sd_gpio);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct ivtv, hdl_gpio)->sd_gpio;
+}
+
+static int subdev_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
+{
+	struct ivtv *itv = sd_to_ivtv(sd);
+	u16 mask, data;
+
+	mask = itv->card->gpio_audio_freq.mask;
+	switch (freq) {
+	case 32000:
+		data = itv->card->gpio_audio_freq.f32000;
+		break;
+	case 44100:
+		data = itv->card->gpio_audio_freq.f44100;
+		break;
+	case 48000:
+	default:
+		data = itv->card->gpio_audio_freq.f48000;
+		break;
+	}
+	if (mask)
+		write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+	return 0;
+}
+
+static int subdev_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct ivtv *itv = sd_to_ivtv(sd);
+	u16 mask;
+
+	mask = itv->card->gpio_audio_detect.mask;
+	if (mask == 0 || (read_reg(IVTV_REG_GPIO_IN) & mask))
+		vt->rxsubchans = V4L2_TUNER_SUB_STEREO |
+			V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+	else
+		vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+	return 0;
+}
+
+static int subdev_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct ivtv *itv = sd_to_ivtv(sd);
+	u16 mask, data;
+
+	mask = itv->card->gpio_audio_mode.mask;
+	switch (vt->audmode) {
+	case V4L2_TUNER_MODE_LANG1:
+		data = itv->card->gpio_audio_mode.lang1;
+		break;
+	case V4L2_TUNER_MODE_LANG2:
+		data = itv->card->gpio_audio_mode.lang2;
+		break;
+	case V4L2_TUNER_MODE_MONO:
+		data = itv->card->gpio_audio_mode.mono;
+		break;
+	case V4L2_TUNER_MODE_STEREO:
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+	default:
+		data = itv->card->gpio_audio_mode.stereo;
+		break;
+	}
+	if (mask)
+		write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+	return 0;
+}
+
+static int subdev_s_radio(struct v4l2_subdev *sd)
+{
+	struct ivtv *itv = sd_to_ivtv(sd);
+	u16 mask, data;
+
+	mask = itv->card->gpio_audio_input.mask;
+	data = itv->card->gpio_audio_input.radio;
+	if (mask)
+		write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+	return 0;
+}
+
+static int subdev_s_audio_routing(struct v4l2_subdev *sd,
+				  u32 input, u32 output, u32 config)
+{
+	struct ivtv *itv = sd_to_ivtv(sd);
+	u16 mask, data;
+
+	if (input > 2)
+		return -EINVAL;
+	mask = itv->card->gpio_audio_input.mask;
+	switch (input) {
+	case 0:
+		data = itv->card->gpio_audio_input.tuner;
+		break;
+	case 1:
+		data = itv->card->gpio_audio_input.linein;
+		break;
+	case 2:
+	default:
+		data = itv->card->gpio_audio_input.radio;
+		break;
+	}
+	if (mask)
+		write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+	return 0;
+}
+
+static int subdev_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct ivtv *itv = sd_to_ivtv(sd);
+	u16 mask, data;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		mask = itv->card->gpio_audio_mute.mask;
+		data = ctrl->val ? itv->card->gpio_audio_mute.mute : 0;
+		if (mask)
+			write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) |
+					(data & mask), IVTV_REG_GPIO_OUT);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+
+static int subdev_log_status(struct v4l2_subdev *sd)
+{
+	struct ivtv *itv = sd_to_ivtv(sd);
+
+	IVTV_INFO("GPIO status: DIR=0x%04x OUT=0x%04x IN=0x%04x\n",
+			read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT),
+			read_reg(IVTV_REG_GPIO_IN));
+	v4l2_ctrl_handler_log_status(&itv->hdl_gpio, sd->name);
+	return 0;
+}
+
+static int subdev_s_video_routing(struct v4l2_subdev *sd,
+				  u32 input, u32 output, u32 config)
+{
+	struct ivtv *itv = sd_to_ivtv(sd);
+	u16 mask, data;
+
+	if (input > 2) /* 0:Tuner 1:Composite 2:S-Video */
+		return -EINVAL;
+	mask = itv->card->gpio_video_input.mask;
+	if (input == 0)
+		data = itv->card->gpio_video_input.tuner;
+	else if (input == 1)
+		data = itv->card->gpio_video_input.composite;
+	else
+		data = itv->card->gpio_video_input.svideo;
+	if (mask)
+		write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops gpio_ctrl_ops = {
+	.s_ctrl = subdev_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops subdev_core_ops = {
+	.log_status = subdev_log_status,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+};
+
+static const struct v4l2_subdev_tuner_ops subdev_tuner_ops = {
+	.s_radio = subdev_s_radio,
+	.g_tuner = subdev_g_tuner,
+	.s_tuner = subdev_s_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops subdev_audio_ops = {
+	.s_clock_freq = subdev_s_clock_freq,
+	.s_routing = subdev_s_audio_routing,
+};
+
+static const struct v4l2_subdev_video_ops subdev_video_ops = {
+	.s_routing = subdev_s_video_routing,
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+	.core = &subdev_core_ops,
+	.tuner = &subdev_tuner_ops,
+	.audio = &subdev_audio_ops,
+	.video = &subdev_video_ops,
+};
+
+int ivtv_gpio_init(struct ivtv *itv)
+{
+	u16 pin = 0;
+
+	if (itv->card->xceive_pin)
+		pin = 1 << itv->card->xceive_pin;
+
+	if ((itv->card->gpio_init.direction | pin) == 0)
+		return 0;
+
+	IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n",
+		   read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT));
+
+	/* init output data then direction */
+	write_reg(itv->card->gpio_init.initial_value | pin, IVTV_REG_GPIO_OUT);
+	write_reg(itv->card->gpio_init.direction | pin, IVTV_REG_GPIO_DIR);
+	v4l2_subdev_init(&itv->sd_gpio, &subdev_ops);
+	snprintf(itv->sd_gpio.name, sizeof(itv->sd_gpio.name), "%s-gpio", itv->v4l2_dev.name);
+	itv->sd_gpio.grp_id = IVTV_HW_GPIO;
+	v4l2_ctrl_handler_init(&itv->hdl_gpio, 1);
+	v4l2_ctrl_new_std(&itv->hdl_gpio, &gpio_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+	if (itv->hdl_gpio.error)
+		return itv->hdl_gpio.error;
+	itv->sd_gpio.ctrl_handler = &itv->hdl_gpio;
+	v4l2_ctrl_handler_setup(&itv->hdl_gpio);
+	return v4l2_device_register_subdev(&itv->v4l2_dev, &itv->sd_gpio);
+}
diff --git a/drivers/media/pci/ivtv/ivtv-gpio.h b/drivers/media/pci/ivtv/ivtv-gpio.h
new file mode 100644
index 0000000..0b5d19c
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-gpio.h
@@ -0,0 +1,29 @@
+/*
+    gpio functions.
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef IVTV_GPIO_H
+#define IVTV_GPIO_H
+
+/* GPIO stuff */
+int ivtv_gpio_init(struct ivtv *itv);
+void ivtv_reset_ir_gpio(struct ivtv *itv);
+int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value);
+
+#endif
diff --git a/drivers/media/pci/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c
new file mode 100644
index 0000000..d47f41a
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-i2c.c
@@ -0,0 +1,760 @@
+/*
+    I2C functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+    This file includes an i2c implementation that was reverse engineered
+    from the Hauppauge windows driver.  Older ivtv versions used i2c-algo-bit,
+    which whilst fine under most circumstances, had trouble with the Zilog
+    CPU on the PVR-150 which handles IR functions (occasional inability to
+    communicate with the chip until it was reset) and also with the i2c
+    bus being completely unreachable when multiple PVR cards were present.
+
+    The implementation is very similar to i2c-algo-bit, but there are enough
+    subtle differences that the two are hard to merge.  The general strategy
+    employed by i2c-algo-bit is to use udelay() to implement the timing
+    when putting out bits on the scl/sda lines.  The general strategy taken
+    here is to poll the lines for state changes (see ivtv_waitscl and
+    ivtv_waitsda).  In addition there are small delays at various locations
+    which poll the SCL line 5 times (ivtv_scldelay).  I would guess that
+    since this is memory mapped I/O that the length of those delays is tied
+    to the PCI bus clock.  There is some extra code to do with recovery
+    and retries.  Since it is not known what causes the actual i2c problems
+    in the first place, the only goal if one was to attempt to use
+    i2c-algo-bit would be to try to make it follow the same code path.
+    This would be a lot of work, and I'm also not convinced that it would
+    provide a generic benefit to i2c-algo-bit.  Therefore consider this
+    an engineering solution -- not pretty, but it works.
+
+    Some more general comments about what we are doing:
+
+    The i2c bus is a 2 wire serial bus, with clock (SCL) and data (SDA)
+    lines.  To communicate on the bus (as a master, we don't act as a slave),
+    we first initiate a start condition (ivtv_start).  We then write the
+    address of the device that we want to communicate with, along with a flag
+    that indicates whether this is a read or a write.  The slave then issues
+    an ACK signal (ivtv_ack), which tells us that it is ready for reading /
+    writing.  We then proceed with reading or writing (ivtv_read/ivtv_write),
+    and finally issue a stop condition (ivtv_stop) to make the bus available
+    to other masters.
+
+    There is an additional form of transaction where a write may be
+    immediately followed by a read.  In this case, there is no intervening
+    stop condition.  (Only the msp3400 chip uses this method of data transfer).
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-cards.h"
+#include "ivtv-gpio.h"
+#include "ivtv-i2c.h"
+#include <media/cx25840.h>
+
+/* i2c implementation for cx23415/6 chip, ivtv project.
+ * Author: Kevin Thayer (nufan_wfk at yahoo.com)
+ */
+/* i2c stuff */
+#define IVTV_REG_I2C_SETSCL_OFFSET 0x7000
+#define IVTV_REG_I2C_SETSDA_OFFSET 0x7004
+#define IVTV_REG_I2C_GETSCL_OFFSET 0x7008
+#define IVTV_REG_I2C_GETSDA_OFFSET 0x700c
+
+#define IVTV_CS53L32A_I2C_ADDR		0x11
+#define IVTV_M52790_I2C_ADDR		0x48
+#define IVTV_CX25840_I2C_ADDR 		0x44
+#define IVTV_SAA7115_I2C_ADDR 		0x21
+#define IVTV_SAA7127_I2C_ADDR 		0x44
+#define IVTV_SAA717x_I2C_ADDR 		0x21
+#define IVTV_MSP3400_I2C_ADDR 		0x40
+#define IVTV_HAUPPAUGE_I2C_ADDR 	0x50
+#define IVTV_WM8739_I2C_ADDR 		0x1a
+#define IVTV_WM8775_I2C_ADDR		0x1b
+#define IVTV_TEA5767_I2C_ADDR		0x60
+#define IVTV_UPD64031A_I2C_ADDR 	0x12
+#define IVTV_UPD64083_I2C_ADDR 		0x5c
+#define IVTV_VP27SMPX_I2C_ADDR      	0x5b
+#define IVTV_M52790_I2C_ADDR      	0x48
+#define IVTV_AVERMEDIA_IR_RX_I2C_ADDR	0x40
+#define IVTV_HAUP_EXT_IR_RX_I2C_ADDR 	0x1a
+#define IVTV_HAUP_INT_IR_RX_I2C_ADDR 	0x18
+#define IVTV_Z8F0811_IR_TX_I2C_ADDR	0x70
+#define IVTV_Z8F0811_IR_RX_I2C_ADDR	0x71
+#define IVTV_ADAPTEC_IR_ADDR		0x6b
+
+/* This array should match the IVTV_HW_ defines */
+static const u8 hw_addrs[] = {
+	IVTV_CX25840_I2C_ADDR,
+	IVTV_SAA7115_I2C_ADDR,
+	IVTV_SAA7127_I2C_ADDR,
+	IVTV_MSP3400_I2C_ADDR,
+	0,
+	IVTV_WM8775_I2C_ADDR,
+	IVTV_CS53L32A_I2C_ADDR,
+	0,
+	IVTV_SAA7115_I2C_ADDR,
+	IVTV_UPD64031A_I2C_ADDR,
+	IVTV_UPD64083_I2C_ADDR,
+	IVTV_SAA717x_I2C_ADDR,
+	IVTV_WM8739_I2C_ADDR,
+	IVTV_VP27SMPX_I2C_ADDR,
+	IVTV_M52790_I2C_ADDR,
+	0,				/* IVTV_HW_GPIO dummy driver ID */
+	IVTV_AVERMEDIA_IR_RX_I2C_ADDR,	/* IVTV_HW_I2C_IR_RX_AVER */
+	IVTV_HAUP_EXT_IR_RX_I2C_ADDR,	/* IVTV_HW_I2C_IR_RX_HAUP_EXT */
+	IVTV_HAUP_INT_IR_RX_I2C_ADDR,	/* IVTV_HW_I2C_IR_RX_HAUP_INT */
+	IVTV_Z8F0811_IR_TX_I2C_ADDR,	/* IVTV_HW_Z8F0811_IR_TX_HAUP */
+	IVTV_Z8F0811_IR_RX_I2C_ADDR,	/* IVTV_HW_Z8F0811_IR_RX_HAUP */
+	IVTV_ADAPTEC_IR_ADDR,		/* IVTV_HW_I2C_IR_RX_ADAPTEC */
+};
+
+/* This array should match the IVTV_HW_ defines */
+static const char * const hw_devicenames[] = {
+	"cx25840",
+	"saa7115",
+	"saa7127_auto",	/* saa7127 or saa7129 */
+	"msp3400",
+	"tuner",
+	"wm8775",
+	"cs53l32a",
+	"tveeprom",
+	"saa7114",
+	"upd64031a",
+	"upd64083",
+	"saa717x",
+	"wm8739",
+	"vp27smpx",
+	"m52790",
+	"gpio",
+	"ir_video",		/* IVTV_HW_I2C_IR_RX_AVER */
+	"ir_video",		/* IVTV_HW_I2C_IR_RX_HAUP_EXT */
+	"ir_video",		/* IVTV_HW_I2C_IR_RX_HAUP_INT */
+	"ir_tx_z8f0811_haup",	/* IVTV_HW_Z8F0811_IR_TX_HAUP */
+	"ir_rx_z8f0811_haup",	/* IVTV_HW_Z8F0811_IR_RX_HAUP */
+	"ir_video",		/* IVTV_HW_I2C_IR_RX_ADAPTEC */
+};
+
+static int get_key_adaptec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char keybuf[4];
+
+	keybuf[0] = 0x00;
+	i2c_master_send(ir->c, keybuf, 1);
+	/* poll IR chip */
+	if (i2c_master_recv(ir->c, keybuf, sizeof(keybuf)) != sizeof(keybuf)) {
+		return 0;
+	}
+
+	/* key pressed ? */
+	if (keybuf[2] == 0xff)
+		return 0;
+
+	/* remove repeat bit */
+	keybuf[2] &= 0x7f;
+	keybuf[3] |= 0x80;
+
+	*ir_key = keybuf[3] | keybuf[2] << 8 | keybuf[1] << 16 |keybuf[0] << 24;
+	*ir_raw = *ir_key;
+
+	return 1;
+}
+
+static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)
+{
+	struct i2c_board_info info;
+	struct i2c_adapter *adap = &itv->i2c_adap;
+	struct IR_i2c_init_data *init_data = &itv->ir_i2c_init_data;
+	unsigned short addr_list[2] = { addr, I2C_CLIENT_END };
+
+	/* Only allow one IR transmitter to be registered per board */
+	if (hw & IVTV_HW_IR_TX_ANY) {
+		if (itv->hw_flags & IVTV_HW_IR_TX_ANY)
+			return -1;
+		memset(&info, 0, sizeof(struct i2c_board_info));
+		strlcpy(info.type, type, I2C_NAME_SIZE);
+		return i2c_new_probed_device(adap, &info, addr_list, NULL)
+							   == NULL ? -1 : 0;
+	}
+
+	/* Only allow one IR receiver to be registered per board */
+	if (itv->hw_flags & IVTV_HW_IR_RX_ANY)
+		return -1;
+
+	/* Our default information for ir-kbd-i2c.c to use */
+	switch (hw) {
+	case IVTV_HW_I2C_IR_RX_AVER:
+		init_data->ir_codes = RC_MAP_AVERMEDIA_CARDBUS;
+		init_data->internal_get_key_func =
+					IR_KBD_GET_KEY_AVERMEDIA_CARDBUS;
+		init_data->type = RC_TYPE_OTHER;
+		init_data->name = "AVerMedia AVerTV card";
+		break;
+	case IVTV_HW_I2C_IR_RX_HAUP_EXT:
+	case IVTV_HW_I2C_IR_RX_HAUP_INT:
+		init_data->ir_codes = RC_MAP_HAUPPAUGE;
+		init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP;
+		init_data->type = RC_TYPE_RC5;
+		init_data->name = itv->card_name;
+		break;
+	case IVTV_HW_Z8F0811_IR_RX_HAUP:
+		/* Default to grey remote */
+		init_data->ir_codes = RC_MAP_HAUPPAUGE;
+		init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+		init_data->type = RC_TYPE_RC5;
+		init_data->name = itv->card_name;
+		break;
+	case IVTV_HW_I2C_IR_RX_ADAPTEC:
+		init_data->get_key = get_key_adaptec;
+		init_data->name = itv->card_name;
+		/* FIXME: The protocol and RC_MAP needs to be corrected */
+		init_data->ir_codes = RC_MAP_EMPTY;
+		init_data->type = RC_TYPE_UNKNOWN;
+		break;
+	}
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	info.platform_data = init_data;
+	strlcpy(info.type, type, I2C_NAME_SIZE);
+
+	return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ?
+	       -1 : 0;
+}
+
+/* Instantiate the IR receiver device using probing -- undesirable */
+struct i2c_client *ivtv_i2c_new_ir_legacy(struct ivtv *itv)
+{
+	struct i2c_board_info info;
+	/*
+	 * The external IR receiver is at i2c address 0x34.
+	 * The internal IR receiver is at i2c address 0x30.
+	 *
+	 * In theory, both can be fitted, and Hauppauge suggests an external
+	 * overrides an internal.  That's why we probe 0x1a (~0x34) first. CB
+	 *
+	 * Some of these addresses we probe may collide with other i2c address
+	 * allocations, so this function must be called after all other i2c
+	 * devices we care about are registered.
+	 */
+	const unsigned short addr_list[] = {
+		0x1a,	/* Hauppauge IR external - collides with WM8739 */
+		0x18,	/* Hauppauge IR internal */
+		I2C_CLIENT_END
+	};
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+	return i2c_new_probed_device(&itv->i2c_adap, &info, addr_list, NULL);
+}
+
+int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
+{
+	struct v4l2_subdev *sd;
+	struct i2c_adapter *adap = &itv->i2c_adap;
+	const char *type = hw_devicenames[idx];
+	u32 hw = 1 << idx;
+
+	if (idx >= ARRAY_SIZE(hw_addrs))
+		return -1;
+	if (hw == IVTV_HW_TUNER) {
+		/* special tuner handling */
+		sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0,
+				itv->card_i2c->radio);
+		if (sd)
+			sd->grp_id = 1 << idx;
+		sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0,
+				itv->card_i2c->demod);
+		if (sd)
+			sd->grp_id = 1 << idx;
+		sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0,
+				itv->card_i2c->tv);
+		if (sd)
+			sd->grp_id = 1 << idx;
+		return sd ? 0 : -1;
+	}
+
+	if (hw & IVTV_HW_IR_ANY)
+		return ivtv_i2c_new_ir(itv, hw, type, hw_addrs[idx]);
+
+	/* Is it not an I2C device or one we do not wish to register? */
+	if (!hw_addrs[idx])
+		return -1;
+
+	/* It's an I2C device other than an analog tuner or IR chip */
+	if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) {
+		sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
+				adap, type, 0, I2C_ADDRS(hw_addrs[idx]));
+	} else if (hw == IVTV_HW_CX25840) {
+		struct cx25840_platform_data pdata;
+		struct i2c_board_info cx25840_info = {
+			.type = "cx25840",
+			.addr = hw_addrs[idx],
+			.platform_data = &pdata,
+		};
+
+		pdata.pvr150_workaround = itv->pvr150_workaround;
+		sd = v4l2_i2c_new_subdev_board(&itv->v4l2_dev, adap,
+				&cx25840_info, NULL);
+	} else {
+		sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
+				adap, type, hw_addrs[idx], NULL);
+	}
+	if (sd)
+		sd->grp_id = 1 << idx;
+	return sd ? 0 : -1;
+}
+
+struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw)
+{
+	struct v4l2_subdev *result = NULL;
+	struct v4l2_subdev *sd;
+
+	spin_lock(&itv->v4l2_dev.lock);
+	v4l2_device_for_each_subdev(sd, &itv->v4l2_dev) {
+		if (sd->grp_id == hw) {
+			result = sd;
+			break;
+		}
+	}
+	spin_unlock(&itv->v4l2_dev.lock);
+	return result;
+}
+
+/* Set the serial clock line to the desired state */
+static void ivtv_setscl(struct ivtv *itv, int state)
+{
+	/* write them out */
+	/* write bits are inverted */
+	write_reg(~state, IVTV_REG_I2C_SETSCL_OFFSET);
+}
+
+/* Set the serial data line to the desired state */
+static void ivtv_setsda(struct ivtv *itv, int state)
+{
+	/* write them out */
+	/* write bits are inverted */
+	write_reg(~state & 1, IVTV_REG_I2C_SETSDA_OFFSET);
+}
+
+/* Read the serial clock line */
+static int ivtv_getscl(struct ivtv *itv)
+{
+	return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1;
+}
+
+/* Read the serial data line */
+static int ivtv_getsda(struct ivtv *itv)
+{
+	return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1;
+}
+
+/* Implement a short delay by polling the serial clock line */
+static void ivtv_scldelay(struct ivtv *itv)
+{
+	int i;
+
+	for (i = 0; i < 5; ++i)
+		ivtv_getscl(itv);
+}
+
+/* Wait for the serial clock line to become set to a specific value */
+static int ivtv_waitscl(struct ivtv *itv, int val)
+{
+	int i;
+
+	ivtv_scldelay(itv);
+	for (i = 0; i < 1000; ++i) {
+		if (ivtv_getscl(itv) == val)
+			return 1;
+	}
+	return 0;
+}
+
+/* Wait for the serial data line to become set to a specific value */
+static int ivtv_waitsda(struct ivtv *itv, int val)
+{
+	int i;
+
+	ivtv_scldelay(itv);
+	for (i = 0; i < 1000; ++i) {
+		if (ivtv_getsda(itv) == val)
+			return 1;
+	}
+	return 0;
+}
+
+/* Wait for the slave to issue an ACK */
+static int ivtv_ack(struct ivtv *itv)
+{
+	int ret = 0;
+
+	if (ivtv_getscl(itv) == 1) {
+		IVTV_DEBUG_HI_I2C("SCL was high starting an ack\n");
+		ivtv_setscl(itv, 0);
+		if (!ivtv_waitscl(itv, 0)) {
+			IVTV_DEBUG_I2C("Could not set SCL low starting an ack\n");
+			return -EREMOTEIO;
+		}
+	}
+	ivtv_setsda(itv, 1);
+	ivtv_scldelay(itv);
+	ivtv_setscl(itv, 1);
+	if (!ivtv_waitsda(itv, 0)) {
+		IVTV_DEBUG_I2C("Slave did not ack\n");
+		ret = -EREMOTEIO;
+	}
+	ivtv_setscl(itv, 0);
+	if (!ivtv_waitscl(itv, 0)) {
+		IVTV_DEBUG_I2C("Failed to set SCL low after ACK\n");
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+/* Write a single byte to the i2c bus and wait for the slave to ACK */
+static int ivtv_sendbyte(struct ivtv *itv, unsigned char byte)
+{
+	int i, bit;
+
+	IVTV_DEBUG_HI_I2C("write %x\n",byte);
+	for (i = 0; i < 8; ++i, byte<<=1) {
+		ivtv_setscl(itv, 0);
+		if (!ivtv_waitscl(itv, 0)) {
+			IVTV_DEBUG_I2C("Error setting SCL low\n");
+			return -EREMOTEIO;
+		}
+		bit = (byte>>7)&1;
+		ivtv_setsda(itv, bit);
+		if (!ivtv_waitsda(itv, bit)) {
+			IVTV_DEBUG_I2C("Error setting SDA\n");
+			return -EREMOTEIO;
+		}
+		ivtv_setscl(itv, 1);
+		if (!ivtv_waitscl(itv, 1)) {
+			IVTV_DEBUG_I2C("Slave not ready for bit\n");
+			return -EREMOTEIO;
+		}
+	}
+	ivtv_setscl(itv, 0);
+	if (!ivtv_waitscl(itv, 0)) {
+		IVTV_DEBUG_I2C("Error setting SCL low\n");
+		return -EREMOTEIO;
+	}
+	return ivtv_ack(itv);
+}
+
+/* Read a byte from the i2c bus and send a NACK if applicable (i.e. for the
+   final byte) */
+static int ivtv_readbyte(struct ivtv *itv, unsigned char *byte, int nack)
+{
+	int i;
+
+	*byte = 0;
+
+	ivtv_setsda(itv, 1);
+	ivtv_scldelay(itv);
+	for (i = 0; i < 8; ++i) {
+		ivtv_setscl(itv, 0);
+		ivtv_scldelay(itv);
+		ivtv_setscl(itv, 1);
+		if (!ivtv_waitscl(itv, 1)) {
+			IVTV_DEBUG_I2C("Error setting SCL high\n");
+			return -EREMOTEIO;
+		}
+		*byte = ((*byte)<<1)|ivtv_getsda(itv);
+	}
+	ivtv_setscl(itv, 0);
+	ivtv_scldelay(itv);
+	ivtv_setsda(itv, nack);
+	ivtv_scldelay(itv);
+	ivtv_setscl(itv, 1);
+	ivtv_scldelay(itv);
+	ivtv_setscl(itv, 0);
+	ivtv_scldelay(itv);
+	IVTV_DEBUG_HI_I2C("read %x\n",*byte);
+	return 0;
+}
+
+/* Issue a start condition on the i2c bus to alert slaves to prepare for
+   an address write */
+static int ivtv_start(struct ivtv *itv)
+{
+	int sda;
+
+	sda = ivtv_getsda(itv);
+	if (sda != 1) {
+		IVTV_DEBUG_HI_I2C("SDA was low at start\n");
+		ivtv_setsda(itv, 1);
+		if (!ivtv_waitsda(itv, 1)) {
+			IVTV_DEBUG_I2C("SDA stuck low\n");
+			return -EREMOTEIO;
+		}
+	}
+	if (ivtv_getscl(itv) != 1) {
+		ivtv_setscl(itv, 1);
+		if (!ivtv_waitscl(itv, 1)) {
+			IVTV_DEBUG_I2C("SCL stuck low at start\n");
+			return -EREMOTEIO;
+		}
+	}
+	ivtv_setsda(itv, 0);
+	ivtv_scldelay(itv);
+	return 0;
+}
+
+/* Issue a stop condition on the i2c bus to release it */
+static int ivtv_stop(struct ivtv *itv)
+{
+	int i;
+
+	if (ivtv_getscl(itv) != 0) {
+		IVTV_DEBUG_HI_I2C("SCL not low when stopping\n");
+		ivtv_setscl(itv, 0);
+		if (!ivtv_waitscl(itv, 0)) {
+			IVTV_DEBUG_I2C("SCL could not be set low\n");
+		}
+	}
+	ivtv_setsda(itv, 0);
+	ivtv_scldelay(itv);
+	ivtv_setscl(itv, 1);
+	if (!ivtv_waitscl(itv, 1)) {
+		IVTV_DEBUG_I2C("SCL could not be set high\n");
+		return -EREMOTEIO;
+	}
+	ivtv_scldelay(itv);
+	ivtv_setsda(itv, 1);
+	if (!ivtv_waitsda(itv, 1)) {
+		IVTV_DEBUG_I2C("resetting I2C\n");
+		for (i = 0; i < 16; ++i) {
+			ivtv_setscl(itv, 0);
+			ivtv_scldelay(itv);
+			ivtv_setscl(itv, 1);
+			ivtv_scldelay(itv);
+			ivtv_setsda(itv, 1);
+		}
+		ivtv_waitsda(itv, 1);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+/* Write a message to the given i2c slave.  do_stop may be 0 to prevent
+   issuing the i2c stop condition (when following with a read) */
+static int ivtv_write(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len, int do_stop)
+{
+	int retry, ret = -EREMOTEIO;
+	u32 i;
+
+	for (retry = 0; ret != 0 && retry < 8; ++retry) {
+		ret = ivtv_start(itv);
+
+		if (ret == 0) {
+			ret = ivtv_sendbyte(itv, addr<<1);
+			for (i = 0; ret == 0 && i < len; ++i)
+				ret = ivtv_sendbyte(itv, data[i]);
+		}
+		if (ret != 0 || do_stop) {
+			ivtv_stop(itv);
+		}
+	}
+	if (ret)
+		IVTV_DEBUG_I2C("i2c write to %x failed\n", addr);
+	return ret;
+}
+
+/* Read data from the given i2c slave.  A stop condition is always issued. */
+static int ivtv_read(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len)
+{
+	int retry, ret = -EREMOTEIO;
+	u32 i;
+
+	for (retry = 0; ret != 0 && retry < 8; ++retry) {
+		ret = ivtv_start(itv);
+		if (ret == 0)
+			ret = ivtv_sendbyte(itv, (addr << 1) | 1);
+		for (i = 0; ret == 0 && i < len; ++i) {
+			ret = ivtv_readbyte(itv, &data[i], i == len - 1);
+		}
+		ivtv_stop(itv);
+	}
+	if (ret)
+		IVTV_DEBUG_I2C("i2c read from %x failed\n", addr);
+	return ret;
+}
+
+/* Kernel i2c transfer implementation.  Takes a number of messages to be read
+   or written.  If a read follows a write, this will occur without an
+   intervening stop condition */
+static int ivtv_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
+{
+	struct v4l2_device *v4l2_dev = i2c_get_adapdata(i2c_adap);
+	struct ivtv *itv = to_ivtv(v4l2_dev);
+	int retval;
+	int i;
+
+	mutex_lock(&itv->i2c_bus_lock);
+	for (i = retval = 0; retval == 0 && i < num; i++) {
+		if (msgs[i].flags & I2C_M_RD)
+			retval = ivtv_read(itv, msgs[i].addr, msgs[i].buf, msgs[i].len);
+		else {
+			/* if followed by a read, don't stop */
+			int stop = !(i + 1 < num && msgs[i + 1].flags == I2C_M_RD);
+
+			retval = ivtv_write(itv, msgs[i].addr, msgs[i].buf, msgs[i].len, stop);
+		}
+	}
+	mutex_unlock(&itv->i2c_bus_lock);
+	return retval ? retval : num;
+}
+
+/* Kernel i2c capabilities */
+static u32 ivtv_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm ivtv_algo = {
+	.master_xfer   = ivtv_xfer,
+	.functionality = ivtv_functionality,
+};
+
+/* template for our-bit banger */
+static struct i2c_adapter ivtv_i2c_adap_hw_template = {
+	.name = "ivtv i2c driver",
+	.algo = &ivtv_algo,
+	.algo_data = NULL,			/* filled from template */
+	.owner = THIS_MODULE,
+};
+
+static void ivtv_setscl_old(void *data, int state)
+{
+	struct ivtv *itv = (struct ivtv *)data;
+
+	if (state)
+		itv->i2c_state |= 0x01;
+	else
+		itv->i2c_state &= ~0x01;
+
+	/* write them out */
+	/* write bits are inverted */
+	write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSCL_OFFSET);
+}
+
+static void ivtv_setsda_old(void *data, int state)
+{
+	struct ivtv *itv = (struct ivtv *)data;
+
+	if (state)
+		itv->i2c_state |= 0x01;
+	else
+		itv->i2c_state &= ~0x01;
+
+	/* write them out */
+	/* write bits are inverted */
+	write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSDA_OFFSET);
+}
+
+static int ivtv_getscl_old(void *data)
+{
+	struct ivtv *itv = (struct ivtv *)data;
+
+	return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1;
+}
+
+static int ivtv_getsda_old(void *data)
+{
+	struct ivtv *itv = (struct ivtv *)data;
+
+	return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1;
+}
+
+/* template for i2c-bit-algo */
+static struct i2c_adapter ivtv_i2c_adap_template = {
+	.name = "ivtv i2c driver",
+	.algo = NULL,                   /* set by i2c-algo-bit */
+	.algo_data = NULL,              /* filled from template */
+	.owner = THIS_MODULE,
+};
+
+#define IVTV_ALGO_BIT_TIMEOUT	(2)	/* seconds */
+
+static const struct i2c_algo_bit_data ivtv_i2c_algo_template = {
+	.setsda		= ivtv_setsda_old,
+	.setscl		= ivtv_setscl_old,
+	.getsda		= ivtv_getsda_old,
+	.getscl		= ivtv_getscl_old,
+	.udelay		= IVTV_DEFAULT_I2C_CLOCK_PERIOD / 2,  /* microseconds */
+	.timeout	= IVTV_ALGO_BIT_TIMEOUT * HZ,         /* jiffies */
+};
+
+static struct i2c_client ivtv_i2c_client_template = {
+	.name = "ivtv internal",
+};
+
+/* init + register i2c adapter */
+int init_ivtv_i2c(struct ivtv *itv)
+{
+	int retval;
+
+	IVTV_DEBUG_I2C("i2c init\n");
+
+	/* Sanity checks for the I2C hardware arrays. They must be the
+	 * same size.
+	 */
+	if (ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs)) {
+		IVTV_ERR("Mismatched I2C hardware arrays\n");
+		return -ENODEV;
+	}
+	if (itv->options.newi2c > 0) {
+		memcpy(&itv->i2c_adap, &ivtv_i2c_adap_hw_template,
+		       sizeof(struct i2c_adapter));
+	} else {
+		memcpy(&itv->i2c_adap, &ivtv_i2c_adap_template,
+		       sizeof(struct i2c_adapter));
+		memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template,
+		       sizeof(struct i2c_algo_bit_data));
+	}
+	itv->i2c_algo.udelay = itv->options.i2c_clock_period / 2;
+	itv->i2c_algo.data = itv;
+	itv->i2c_adap.algo_data = &itv->i2c_algo;
+
+	sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d",
+		itv->instance);
+	i2c_set_adapdata(&itv->i2c_adap, &itv->v4l2_dev);
+
+	memcpy(&itv->i2c_client, &ivtv_i2c_client_template,
+	       sizeof(struct i2c_client));
+	itv->i2c_client.adapter = &itv->i2c_adap;
+	itv->i2c_adap.dev.parent = &itv->pdev->dev;
+
+	IVTV_DEBUG_I2C("setting scl and sda to 1\n");
+	ivtv_setscl(itv, 1);
+	ivtv_setsda(itv, 1);
+
+	if (itv->options.newi2c > 0)
+		retval = i2c_add_adapter(&itv->i2c_adap);
+	else
+		retval = i2c_bit_add_bus(&itv->i2c_adap);
+
+	return retval;
+}
+
+void exit_ivtv_i2c(struct ivtv *itv)
+{
+	IVTV_DEBUG_I2C("i2c exit\n");
+
+	i2c_del_adapter(&itv->i2c_adap);
+}
diff --git a/drivers/media/pci/ivtv/ivtv-i2c.h b/drivers/media/pci/ivtv/ivtv-i2c.h
new file mode 100644
index 0000000..7b9ec1c
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-i2c.h
@@ -0,0 +1,32 @@
+/*
+    I2C functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef IVTV_I2C_H
+#define IVTV_I2C_H
+
+struct i2c_client *ivtv_i2c_new_ir_legacy(struct ivtv *itv);
+int ivtv_i2c_register(struct ivtv *itv, unsigned idx);
+struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw);
+
+/* init + register i2c adapter */
+int init_ivtv_i2c(struct ivtv *itv);
+void exit_ivtv_i2c(struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c
new file mode 100644
index 0000000..32a5910
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-ioctl.c
@@ -0,0 +1,1899 @@
+/*
+    ioctl system call
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-version.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-i2c.h"
+#include "ivtv-queue.h"
+#include "ivtv-fileops.h"
+#include "ivtv-vbi.h"
+#include "ivtv-routing.h"
+#include "ivtv-streams.h"
+#include "ivtv-yuv.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-gpio.h"
+#include "ivtv-controls.h"
+#include "ivtv-cards.h"
+#include <media/saa7127.h>
+#include <media/tveeprom.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-event.h>
+#include <linux/dvb/audio.h>
+
+u16 ivtv_service2vbi(int type)
+{
+	switch (type) {
+		case V4L2_SLICED_TELETEXT_B:
+			return IVTV_SLICED_TYPE_TELETEXT_B;
+		case V4L2_SLICED_CAPTION_525:
+			return IVTV_SLICED_TYPE_CAPTION_525;
+		case V4L2_SLICED_WSS_625:
+			return IVTV_SLICED_TYPE_WSS_625;
+		case V4L2_SLICED_VPS:
+			return IVTV_SLICED_TYPE_VPS;
+		default:
+			return 0;
+	}
+}
+
+static int valid_service_line(int field, int line, int is_pal)
+{
+	return (is_pal && line >= 6 && (line != 23 || field == 0)) ||
+	       (!is_pal && line >= 10 && line < 22);
+}
+
+static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
+{
+	u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
+	int i;
+
+	set = set & valid_set;
+	if (set == 0 || !valid_service_line(field, line, is_pal)) {
+		return 0;
+	}
+	if (!is_pal) {
+		if (line == 21 && (set & V4L2_SLICED_CAPTION_525))
+			return V4L2_SLICED_CAPTION_525;
+	}
+	else {
+		if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS))
+			return V4L2_SLICED_VPS;
+		if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625))
+			return V4L2_SLICED_WSS_625;
+		if (line == 23)
+			return 0;
+	}
+	for (i = 0; i < 32; i++) {
+		if ((1 << i) & set)
+			return 1 << i;
+	}
+	return 0;
+}
+
+void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+{
+	u16 set = fmt->service_set;
+	int f, l;
+
+	fmt->service_set = 0;
+	for (f = 0; f < 2; f++) {
+		for (l = 0; l < 24; l++) {
+			fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal);
+		}
+	}
+}
+
+static void check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+{
+	int f, l;
+
+	for (f = 0; f < 2; f++) {
+		for (l = 0; l < 24; l++) {
+			fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
+		}
+	}
+}
+
+u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt)
+{
+	int f, l;
+	u16 set = 0;
+
+	for (f = 0; f < 2; f++) {
+		for (l = 0; l < 24; l++) {
+			set |= fmt->service_lines[f][l];
+		}
+	}
+	return set;
+}
+
+void ivtv_set_osd_alpha(struct ivtv *itv)
+{
+	ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3,
+		itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state);
+	ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_chroma_key_state, itv->osd_chroma_key);
+}
+
+int ivtv_set_speed(struct ivtv *itv, int speed)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	int single_step = (speed == 1 || speed == -1);
+	DEFINE_WAIT(wait);
+
+	if (speed == 0) speed = 1000;
+
+	/* No change? */
+	if (speed == itv->speed && !single_step)
+		return 0;
+
+	if (single_step && (speed < 0) == (itv->speed < 0)) {
+		/* Single step video and no need to change direction */
+		ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0);
+		itv->speed = speed;
+		return 0;
+	}
+	if (single_step)
+		/* Need to change direction */
+		speed = speed < 0 ? -1000 : 1000;
+
+	data[0] = (speed > 1000 || speed < -1000) ? 0x80000000 : 0;
+	data[0] |= (speed > 1000 || speed < -1500) ? 0x40000000 : 0;
+	data[1] = (speed < 0);
+	data[2] = speed < 0 ? 3 : 7;
+	data[3] = v4l2_ctrl_g_ctrl(itv->cxhdl.video_b_frames);
+	data[4] = (speed == 1500 || speed == 500) ? itv->speed_mute_audio : 0;
+	data[5] = 0;
+	data[6] = 0;
+
+	if (speed == 1500 || speed == -1500) data[0] |= 1;
+	else if (speed == 2000 || speed == -2000) data[0] |= 2;
+	else if (speed > -1000 && speed < 0) data[0] |= (-1000 / speed);
+	else if (speed < 1000 && speed > 0) data[0] |= (1000 / speed);
+
+	/* If not decoding, just change speed setting */
+	if (atomic_read(&itv->decoding) > 0) {
+		int got_sig = 0;
+
+		/* Stop all DMA and decoding activity */
+		ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, 0);
+
+		/* Wait for any DMA to finish */
+		mutex_unlock(&itv->serialize_lock);
+		prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
+		while (test_bit(IVTV_F_I_DMA, &itv->i_flags)) {
+			got_sig = signal_pending(current);
+			if (got_sig)
+				break;
+			got_sig = 0;
+			schedule();
+		}
+		finish_wait(&itv->dma_waitq, &wait);
+		mutex_lock(&itv->serialize_lock);
+		if (got_sig)
+			return -EINTR;
+
+		/* Change Speed safely */
+		ivtv_api(itv, CX2341X_DEC_SET_PLAYBACK_SPEED, 7, data);
+		IVTV_DEBUG_INFO("Setting Speed to 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+				data[0], data[1], data[2], data[3], data[4], data[5], data[6]);
+	}
+	if (single_step) {
+		speed = (speed < 0) ? -1 : 1;
+		ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0);
+	}
+	itv->speed = speed;
+	return 0;
+}
+
+static int ivtv_validate_speed(int cur_speed, int new_speed)
+{
+	int fact = new_speed < 0 ? -1 : 1;
+	int s;
+
+	if (cur_speed == 0)
+		cur_speed = 1000;
+	if (new_speed < 0)
+		new_speed = -new_speed;
+	if (cur_speed < 0)
+		cur_speed = -cur_speed;
+
+	if (cur_speed <= new_speed) {
+		if (new_speed > 1500)
+			return fact * 2000;
+		if (new_speed > 1000)
+			return fact * 1500;
+	}
+	else {
+		if (new_speed >= 2000)
+			return fact * 2000;
+		if (new_speed >= 1500)
+			return fact * 1500;
+		if (new_speed >= 1000)
+			return fact * 1000;
+	}
+	if (new_speed == 0)
+		return 1000;
+	if (new_speed == 1 || new_speed == 1000)
+		return fact * new_speed;
+
+	s = new_speed;
+	new_speed = 1000 / new_speed;
+	if (1000 / cur_speed == new_speed)
+		new_speed += (cur_speed < s) ? -1 : 1;
+	if (new_speed > 60) return 1000 / (fact * 60);
+	return 1000 / (fact * new_speed);
+}
+
+static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,
+		struct v4l2_decoder_cmd *dc, int try)
+{
+	struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	switch (dc->cmd) {
+	case V4L2_DEC_CMD_START: {
+		dc->flags &= V4L2_DEC_CMD_START_MUTE_AUDIO;
+		dc->start.speed = ivtv_validate_speed(itv->speed, dc->start.speed);
+		if (dc->start.speed < 0)
+			dc->start.format = V4L2_DEC_START_FMT_GOP;
+		else
+			dc->start.format = V4L2_DEC_START_FMT_NONE;
+		if (dc->start.speed != 500 && dc->start.speed != 1500)
+			dc->flags = dc->start.speed == 1000 ? 0 :
+					V4L2_DEC_CMD_START_MUTE_AUDIO;
+		if (try) break;
+
+		itv->speed_mute_audio = dc->flags & V4L2_DEC_CMD_START_MUTE_AUDIO;
+		if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG)
+			return -EBUSY;
+		if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) {
+			/* forces ivtv_set_speed to be called */
+			itv->speed = 0;
+		}
+		return ivtv_start_decoding(id, dc->start.speed);
+	}
+
+	case V4L2_DEC_CMD_STOP:
+		dc->flags &= V4L2_DEC_CMD_STOP_IMMEDIATELY | V4L2_DEC_CMD_STOP_TO_BLACK;
+		if (dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY)
+			dc->stop.pts = 0;
+		if (try) break;
+		if (atomic_read(&itv->decoding) == 0)
+			return 0;
+		if (itv->output_mode != OUT_MPG)
+			return -EBUSY;
+
+		itv->output_mode = OUT_NONE;
+		return ivtv_stop_v4l2_decode_stream(s, dc->flags, dc->stop.pts);
+
+	case V4L2_DEC_CMD_PAUSE:
+		dc->flags &= V4L2_DEC_CMD_PAUSE_TO_BLACK;
+		if (try) break;
+		if (itv->output_mode != OUT_MPG)
+			return -EBUSY;
+		if (atomic_read(&itv->decoding) > 0) {
+			ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1,
+				(dc->flags & V4L2_DEC_CMD_PAUSE_TO_BLACK) ? 1 : 0);
+			set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags);
+		}
+		break;
+
+	case V4L2_DEC_CMD_RESUME:
+		dc->flags = 0;
+		if (try) break;
+		if (itv->output_mode != OUT_MPG)
+			return -EBUSY;
+		if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) {
+			int speed = itv->speed;
+			itv->speed = 0;
+			return ivtv_start_decoding(id, speed);
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+	vbifmt->reserved[0] = 0;
+	vbifmt->reserved[1] = 0;
+	if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
+		return -EINVAL;
+	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+	if (itv->is_60hz) {
+		vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+		vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+	} else {
+		vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
+		vbifmt->service_lines[0][16] = V4L2_SLICED_VPS;
+	}
+	vbifmt->service_set = ivtv_get_service_set(vbifmt);
+	return 0;
+}
+
+static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv_open_id *id = fh2id(fh);
+	struct ivtv *itv = id->itv;
+	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+	pixfmt->width = itv->cxhdl.width;
+	pixfmt->height = itv->cxhdl.height;
+	pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	pixfmt->field = V4L2_FIELD_INTERLACED;
+	pixfmt->priv = 0;
+	if (id->type == IVTV_ENC_STREAM_TYPE_YUV) {
+		pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
+		/* YUV size is (Y=(h*720) + UV=(h*(720/2))) */
+		pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
+		pixfmt->bytesperline = 720;
+	} else {
+		pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
+		pixfmt->sizeimage = 128 * 1024;
+		pixfmt->bytesperline = 0;
+	}
+	return 0;
+}
+
+static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+	struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
+
+	vbifmt->sampling_rate = 27000000;
+	vbifmt->offset = 248;
+	vbifmt->samples_per_line = itv->vbi.raw_decoder_line_size - 4;
+	vbifmt->sample_format = V4L2_PIX_FMT_GREY;
+	vbifmt->start[0] = itv->vbi.start[0];
+	vbifmt->start[1] = itv->vbi.start[1];
+	vbifmt->count[0] = vbifmt->count[1] = itv->vbi.count;
+	vbifmt->flags = 0;
+	vbifmt->reserved[0] = 0;
+	vbifmt->reserved[1] = 0;
+	return 0;
+}
+
+static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+	struct ivtv_open_id *id = fh2id(fh);
+	struct ivtv *itv = id->itv;
+
+	vbifmt->reserved[0] = 0;
+	vbifmt->reserved[1] = 0;
+	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+
+	if (id->type == IVTV_DEC_STREAM_TYPE_VBI) {
+		vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 :
+			V4L2_SLICED_VBI_525;
+		ivtv_expand_service_set(vbifmt, itv->is_50hz);
+		return 0;
+	}
+
+	v4l2_subdev_call(itv->sd_video, vbi, g_sliced_fmt, vbifmt);
+	vbifmt->service_set = ivtv_get_service_set(vbifmt);
+	return 0;
+}
+
+static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv_open_id *id = fh2id(fh);
+	struct ivtv *itv = id->itv;
+	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return -EINVAL;
+	pixfmt->width = itv->main_rect.width;
+	pixfmt->height = itv->main_rect.height;
+	pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	pixfmt->field = V4L2_FIELD_INTERLACED;
+	pixfmt->priv = 0;
+	if (id->type == IVTV_DEC_STREAM_TYPE_YUV) {
+		switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
+		case IVTV_YUV_MODE_INTERLACED:
+			pixfmt->field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
+				V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB;
+			break;
+		case IVTV_YUV_MODE_PROGRESSIVE:
+			pixfmt->field = V4L2_FIELD_NONE;
+			break;
+		default:
+			pixfmt->field = V4L2_FIELD_ANY;
+			break;
+		}
+		pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
+		pixfmt->bytesperline = 720;
+		pixfmt->width = itv->yuv_info.v4l2_src_w;
+		pixfmt->height = itv->yuv_info.v4l2_src_h;
+		/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+		pixfmt->sizeimage =
+			1080 * ((pixfmt->height + 31) & ~31);
+	} else {
+		pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
+		pixfmt->sizeimage = 128 * 1024;
+		pixfmt->bytesperline = 0;
+	}
+	return 0;
+}
+
+static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+	struct v4l2_window *winfmt = &fmt->fmt.win;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return -EINVAL;
+	winfmt->chromakey = itv->osd_chroma_key;
+	winfmt->global_alpha = itv->osd_global_alpha;
+	winfmt->field = V4L2_FIELD_INTERLACED;
+	winfmt->clips = NULL;
+	winfmt->clipcount = 0;
+	winfmt->bitmap = NULL;
+	winfmt->w.top = winfmt->w.left = 0;
+	winfmt->w.width = itv->osd_rect.width;
+	winfmt->w.height = itv->osd_rect.height;
+	return 0;
+}
+
+static int ivtv_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt);
+}
+
+static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv_open_id *id = fh2id(fh);
+	struct ivtv *itv = id->itv;
+	int w = fmt->fmt.pix.width;
+	int h = fmt->fmt.pix.height;
+	int min_h = 2;
+
+	w = min(w, 720);
+	w = max(w, 2);
+	if (id->type == IVTV_ENC_STREAM_TYPE_YUV) {
+		/* YUV height must be a multiple of 32 */
+		h &= ~0x1f;
+		min_h = 32;
+	}
+	h = min(h, itv->is_50hz ? 576 : 480);
+	h = max(h, min_h);
+	ivtv_g_fmt_vid_cap(file, fh, fmt);
+	fmt->fmt.pix.width = w;
+	fmt->fmt.pix.height = h;
+	return 0;
+}
+
+static int ivtv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	return ivtv_g_fmt_vbi_cap(file, fh, fmt);
+}
+
+static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+	struct ivtv_open_id *id = fh2id(fh);
+	struct ivtv *itv = id->itv;
+
+	if (id->type == IVTV_DEC_STREAM_TYPE_VBI)
+		return ivtv_g_fmt_sliced_vbi_cap(file, fh, fmt);
+
+	/* set sliced VBI capture format */
+	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+	vbifmt->reserved[0] = 0;
+	vbifmt->reserved[1] = 0;
+
+	if (vbifmt->service_set)
+		ivtv_expand_service_set(vbifmt, itv->is_50hz);
+	check_service_set(vbifmt, itv->is_50hz);
+	vbifmt->service_set = ivtv_get_service_set(vbifmt);
+	return 0;
+}
+
+static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv_open_id *id = fh2id(fh);
+	s32 w = fmt->fmt.pix.width;
+	s32 h = fmt->fmt.pix.height;
+	int field = fmt->fmt.pix.field;
+	int ret = ivtv_g_fmt_vid_out(file, fh, fmt);
+
+	w = min(w, 720);
+	w = max(w, 2);
+	/* Why can the height be 576 even when the output is NTSC?
+
+	   Internally the buffers of the PVR350 are always set to 720x576. The
+	   decoded video frame will always be placed in the top left corner of
+	   this buffer. For any video which is not 720x576, the buffer will
+	   then be cropped to remove the unused right and lower areas, with
+	   the remaining image being scaled by the hardware to fit the display
+	   area. The video can be scaled both up and down, so a 720x480 video
+	   can be displayed full-screen on PAL and a 720x576 video can be
+	   displayed without cropping on NTSC.
+
+	   Note that the scaling only occurs on the video stream, the osd
+	   resolution is locked to the broadcast standard and not scaled.
+
+	   Thanks to Ian Armstrong for this explanation. */
+	h = min(h, 576);
+	h = max(h, 2);
+	if (id->type == IVTV_DEC_STREAM_TYPE_YUV)
+		fmt->fmt.pix.field = field;
+	fmt->fmt.pix.width = w;
+	fmt->fmt.pix.height = h;
+	return ret;
+}
+
+static int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+	u32 chromakey = fmt->fmt.win.chromakey;
+	u8 global_alpha = fmt->fmt.win.global_alpha;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return -EINVAL;
+	ivtv_g_fmt_vid_out_overlay(file, fh, fmt);
+	fmt->fmt.win.chromakey = chromakey;
+	fmt->fmt.win.global_alpha = global_alpha;
+	return 0;
+}
+
+static int ivtv_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt);
+}
+
+static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv_open_id *id = fh2id(fh);
+	struct ivtv *itv = id->itv;
+	struct v4l2_mbus_framefmt mbus_fmt;
+	int ret = ivtv_try_fmt_vid_cap(file, fh, fmt);
+	int w = fmt->fmt.pix.width;
+	int h = fmt->fmt.pix.height;
+
+	if (ret)
+		return ret;
+
+	if (itv->cxhdl.width == w && itv->cxhdl.height == h)
+		return 0;
+
+	if (atomic_read(&itv->capturing) > 0)
+		return -EBUSY;
+
+	itv->cxhdl.width = w;
+	itv->cxhdl.height = h;
+	if (v4l2_ctrl_g_ctrl(itv->cxhdl.video_encoding) == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+		fmt->fmt.pix.width /= 2;
+	mbus_fmt.width = fmt->fmt.pix.width;
+	mbus_fmt.height = h;
+	mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
+	v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &mbus_fmt);
+	return ivtv_g_fmt_vid_cap(file, fh, fmt);
+}
+
+static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	if (!ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0)
+		return -EBUSY;
+	itv->vbi.sliced_in->service_set = 0;
+	itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
+	v4l2_subdev_call(itv->sd_video, vbi, s_raw_fmt, &fmt->fmt.vbi);
+	return ivtv_g_fmt_vbi_cap(file, fh, fmt);
+}
+
+static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+	struct ivtv_open_id *id = fh2id(fh);
+	struct ivtv *itv = id->itv;
+	int ret = ivtv_try_fmt_sliced_vbi_cap(file, fh, fmt);
+
+	if (ret || id->type == IVTV_DEC_STREAM_TYPE_VBI)
+		return ret;
+
+	check_service_set(vbifmt, itv->is_50hz);
+	if (ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0)
+		return -EBUSY;
+	itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+	v4l2_subdev_call(itv->sd_video, vbi, s_sliced_fmt, vbifmt);
+	memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in));
+	return 0;
+}
+
+static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv_open_id *id = fh2id(fh);
+	struct ivtv *itv = id->itv;
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	int ret = ivtv_try_fmt_vid_out(file, fh, fmt);
+
+	if (ret)
+		return ret;
+
+	if (id->type != IVTV_DEC_STREAM_TYPE_YUV)
+		return 0;
+
+	/* Return now if we already have some frame data */
+	if (yi->stream_size)
+		return -EBUSY;
+
+	yi->v4l2_src_w = fmt->fmt.pix.width;
+	yi->v4l2_src_h = fmt->fmt.pix.height;
+
+	switch (fmt->fmt.pix.field) {
+	case V4L2_FIELD_NONE:
+		yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
+		break;
+	case V4L2_FIELD_ANY:
+		yi->lace_mode = IVTV_YUV_MODE_AUTO;
+		break;
+	case V4L2_FIELD_INTERLACED_BT:
+		yi->lace_mode =
+			IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
+		break;
+	case V4L2_FIELD_INTERLACED_TB:
+	default:
+		yi->lace_mode = IVTV_YUV_MODE_INTERLACED;
+		break;
+	}
+	yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
+
+	if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
+		itv->dma_data_req_size =
+			1080 * ((yi->v4l2_src_h + 31) & ~31);
+
+	return 0;
+}
+
+static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+	int ret = ivtv_try_fmt_vid_out_overlay(file, fh, fmt);
+
+	if (ret == 0) {
+		itv->osd_chroma_key = fmt->fmt.win.chromakey;
+		itv->osd_global_alpha = fmt->fmt.win.global_alpha;
+		ivtv_set_osd_alpha(itv);
+	}
+	return ret;
+}
+
+static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	chip->ident = V4L2_IDENT_NONE;
+	chip->revision = 0;
+	if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
+		if (v4l2_chip_match_host(&chip->match))
+			chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
+		return 0;
+	}
+	if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+	    chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+	/* TODO: is this correct? */
+	return ivtv_call_all_err(itv, core, g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
+{
+	struct v4l2_dbg_register *regs = arg;
+	volatile u8 __iomem *reg_start;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (regs->reg >= IVTV_REG_OFFSET && regs->reg < IVTV_REG_OFFSET + IVTV_REG_SIZE)
+		reg_start = itv->reg_mem - IVTV_REG_OFFSET;
+	else if (itv->has_cx23415 && regs->reg >= IVTV_DECODER_OFFSET &&
+			regs->reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE)
+		reg_start = itv->dec_mem - IVTV_DECODER_OFFSET;
+	else if (regs->reg < IVTV_ENCODER_SIZE)
+		reg_start = itv->enc_mem;
+	else
+		return -EINVAL;
+
+	regs->size = 4;
+	if (cmd == VIDIOC_DBG_G_REGISTER)
+		regs->val = readl(regs->reg + reg_start);
+	else
+		writel(regs->val, regs->reg + reg_start);
+	return 0;
+}
+
+static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	if (v4l2_chip_match_host(&reg->match))
+		return ivtv_itvc(itv, VIDIOC_DBG_G_REGISTER, reg);
+	/* TODO: subdev errors should not be ignored, this should become a
+	   subdev helper function. */
+	ivtv_call_all(itv, core, g_register, reg);
+	return 0;
+}
+
+static int ivtv_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	if (v4l2_chip_match_host(&reg->match))
+		return ivtv_itvc(itv, VIDIOC_DBG_S_REGISTER, reg);
+	/* TODO: subdev errors should not be ignored, this should become a
+	   subdev helper function. */
+	ivtv_call_all(itv, core, s_register, reg);
+	return 0;
+}
+#endif
+
+static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap)
+{
+	struct ivtv_open_id *id = fh2id(file->private_data);
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+
+	strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
+	strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
+	snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev));
+	vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS;
+	vcap->device_caps = s->caps;
+	return 0;
+}
+
+static int ivtv_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	return ivtv_get_audio_input(itv, vin->index, vin);
+}
+
+static int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	vin->index = itv->audio_input;
+	return ivtv_get_audio_input(itv, vin->index, vin);
+}
+
+static int ivtv_s_audio(struct file *file, void *fh, struct v4l2_audio *vout)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	if (vout->index >= itv->nof_audio_inputs)
+		return -EINVAL;
+
+	itv->audio_input = vout->index;
+	ivtv_audio_set_io(itv);
+
+	return 0;
+}
+
+static int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vin)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	/* set it to defaults from our table */
+	return ivtv_get_audio_output(itv, vin->index, vin);
+}
+
+static int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	vin->index = 0;
+	return ivtv_get_audio_output(itv, vin->index, vin);
+}
+
+static int ivtv_s_audout(struct file *file, void *fh, struct v4l2_audioout *vout)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	return ivtv_get_audio_output(itv, vout->index, vout);
+}
+
+static int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	/* set it to defaults from our table */
+	return ivtv_get_input(itv, vin->index, vin);
+}
+
+static int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vout)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	return ivtv_get_output(itv, vout->index, vout);
+}
+
+static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap)
+{
+	struct ivtv_open_id *id = fh2id(fh);
+	struct ivtv *itv = id->itv;
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	int streamtype;
+
+	streamtype = id->type;
+
+	if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+	cropcap->bounds.top = cropcap->bounds.left = 0;
+	cropcap->bounds.width = 720;
+	if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		cropcap->bounds.height = itv->is_50hz ? 576 : 480;
+		cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
+		cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
+	} else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+		if (yi->track_osd) {
+			cropcap->bounds.width = yi->osd_full_w;
+			cropcap->bounds.height = yi->osd_full_h;
+		} else {
+			cropcap->bounds.width = 720;
+			cropcap->bounds.height =
+					itv->is_out_50hz ? 576 : 480;
+		}
+		cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
+		cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
+	} else {
+		cropcap->bounds.height = itv->is_out_50hz ? 576 : 480;
+		cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
+		cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
+	}
+	cropcap->defrect = cropcap->bounds;
+	return 0;
+}
+
+static int ivtv_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+	struct ivtv_open_id *id = fh2id(fh);
+	struct ivtv *itv = id->itv;
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	int streamtype;
+
+	streamtype = id->type;
+
+	if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+	    (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+		if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+			yi->main_rect = crop->c;
+			return 0;
+		} else {
+			if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
+				crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
+				itv->main_rect = crop->c;
+				return 0;
+			}
+		}
+		return -EINVAL;
+	}
+	return -EINVAL;
+}
+
+static int ivtv_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+	struct ivtv_open_id *id = fh2id(fh);
+	struct ivtv *itv = id->itv;
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	int streamtype;
+
+	streamtype = id->type;
+
+	if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+	    (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+		if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
+			crop->c = yi->main_rect;
+		else
+			crop->c = itv->main_rect;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int ivtv_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
+{
+	static struct v4l2_fmtdesc formats[] = {
+		{ 0, 0, 0,
+		  "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
+		  { 0, 0, 0, 0 }
+		},
+		{ 1, 0, V4L2_FMT_FLAG_COMPRESSED,
+		  "MPEG", V4L2_PIX_FMT_MPEG,
+		  { 0, 0, 0, 0 }
+		}
+	};
+	enum v4l2_buf_type type = fmt->type;
+
+	if (fmt->index > 1)
+		return -EINVAL;
+
+	*fmt = formats[fmt->index];
+	fmt->type = type;
+	return 0;
+}
+
+static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	static struct v4l2_fmtdesc formats[] = {
+		{ 0, 0, 0,
+		  "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
+		  { 0, 0, 0, 0 }
+		},
+		{ 1, 0, V4L2_FMT_FLAG_COMPRESSED,
+		  "MPEG", V4L2_PIX_FMT_MPEG,
+		  { 0, 0, 0, 0 }
+		}
+	};
+	enum v4l2_buf_type type = fmt->type;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	if (fmt->index > 1)
+		return -EINVAL;
+
+	*fmt = formats[fmt->index];
+	fmt->type = type;
+
+	return 0;
+}
+
+static int ivtv_g_input(struct file *file, void *fh, unsigned int *i)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	*i = itv->active_input;
+
+	return 0;
+}
+
+int ivtv_s_input(struct file *file, void *fh, unsigned int inp)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	if (inp < 0 || inp >= itv->nof_inputs)
+		return -EINVAL;
+
+	if (inp == itv->active_input) {
+		IVTV_DEBUG_INFO("Input unchanged\n");
+		return 0;
+	}
+
+	if (atomic_read(&itv->capturing) > 0) {
+		return -EBUSY;
+	}
+
+	IVTV_DEBUG_INFO("Changing input from %d to %d\n",
+			itv->active_input, inp);
+
+	itv->active_input = inp;
+	/* Set the audio input to whatever is appropriate for the
+	   input type. */
+	itv->audio_input = itv->card->video_inputs[inp].audio_index;
+
+	/* prevent others from messing with the streams until
+	   we're finished changing inputs. */
+	ivtv_mute(itv);
+	ivtv_video_set_io(itv);
+	ivtv_audio_set_io(itv);
+	ivtv_unmute(itv);
+
+	return 0;
+}
+
+static int ivtv_g_output(struct file *file, void *fh, unsigned int *i)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	*i = itv->active_output;
+
+	return 0;
+}
+
+static int ivtv_s_output(struct file *file, void *fh, unsigned int outp)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	if (outp >= itv->card->nof_outputs)
+		return -EINVAL;
+
+	if (outp == itv->active_output) {
+		IVTV_DEBUG_INFO("Output unchanged\n");
+		return 0;
+	}
+	IVTV_DEBUG_INFO("Changing output from %d to %d\n",
+		   itv->active_output, outp);
+
+	itv->active_output = outp;
+	ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
+			SAA7127_INPUT_TYPE_NORMAL,
+			itv->card->video_outputs[outp].video_output, 0);
+
+	return 0;
+}
+
+static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	if (vf->tuner != 0)
+		return -EINVAL;
+
+	ivtv_call_all(itv, tuner, g_frequency, vf);
+	return 0;
+}
+
+int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	if (vf->tuner != 0)
+		return -EINVAL;
+
+	ivtv_mute(itv);
+	IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
+	ivtv_call_all(itv, tuner, s_frequency, vf);
+	ivtv_unmute(itv);
+	return 0;
+}
+
+static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	*std = itv->std;
+	return 0;
+}
+
+void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std)
+{
+	itv->std = *std;
+	itv->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
+	itv->is_50hz = !itv->is_60hz;
+	cx2341x_handler_set_50hz(&itv->cxhdl, itv->is_50hz);
+	itv->cxhdl.width = 720;
+	itv->cxhdl.height = itv->is_50hz ? 576 : 480;
+	itv->vbi.count = itv->is_50hz ? 18 : 12;
+	itv->vbi.start[0] = itv->is_50hz ? 6 : 10;
+	itv->vbi.start[1] = itv->is_50hz ? 318 : 273;
+
+	if (itv->hw_flags & IVTV_HW_CX25840)
+		itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284;
+
+	/* Tuner */
+	ivtv_call_all(itv, core, s_std, itv->std);
+}
+
+void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std)
+{
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	DEFINE_WAIT(wait);
+	int f;
+
+	/* set display standard */
+	itv->std_out = *std;
+	itv->is_out_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
+	itv->is_out_50hz = !itv->is_out_60hz;
+	ivtv_call_all(itv, video, s_std_output, itv->std_out);
+
+	/*
+	 * The next firmware call is time sensitive. Time it to
+	 * avoid risk of a hard lock, by trying to ensure the call
+	 * happens within the first 100 lines of the top field.
+	 * Make 4 attempts to sync to the decoder before giving up.
+	 */
+	mutex_unlock(&itv->serialize_lock);
+	for (f = 0; f < 4; f++) {
+		prepare_to_wait(&itv->vsync_waitq, &wait,
+				TASK_UNINTERRUPTIBLE);
+		if ((read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16) < 100)
+			break;
+		schedule_timeout(msecs_to_jiffies(25));
+	}
+	finish_wait(&itv->vsync_waitq, &wait);
+	mutex_lock(&itv->serialize_lock);
+
+	if (f == 4)
+		IVTV_WARN("Mode change failed to sync to decoder\n");
+
+	ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
+	itv->main_rect.left = 0;
+	itv->main_rect.top = 0;
+	itv->main_rect.width = 720;
+	itv->main_rect.height = itv->is_out_50hz ? 576 : 480;
+	ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
+		720, itv->main_rect.height, 0, 0);
+	yi->main_rect = itv->main_rect;
+	if (!itv->osd_info) {
+		yi->osd_full_w = 720;
+		yi->osd_full_h = itv->is_out_50hz ? 576 : 480;
+	}
+}
+
+int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	if ((*std & V4L2_STD_ALL) == 0)
+		return -EINVAL;
+
+	if (*std == itv->std)
+		return 0;
+
+	if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ||
+	    atomic_read(&itv->capturing) > 0 ||
+	    atomic_read(&itv->decoding) > 0) {
+		/* Switching standard would mess with already running
+		   streams, prevent that by returning EBUSY. */
+		return -EBUSY;
+	}
+
+	IVTV_DEBUG_INFO("Switching standard to %llx.\n",
+		(unsigned long long)itv->std);
+
+	ivtv_s_std_enc(itv, std);
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
+		ivtv_s_std_dec(itv, std);
+
+	return 0;
+}
+
+static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+	struct ivtv_open_id *id = fh2id(fh);
+	struct ivtv *itv = id->itv;
+
+	if (vt->index != 0)
+		return -EINVAL;
+
+	ivtv_call_all(itv, tuner, s_tuner, vt);
+
+	return 0;
+}
+
+static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	if (vt->index != 0)
+		return -EINVAL;
+
+	ivtv_call_all(itv, tuner, g_tuner, vt);
+
+	if (vt->type == V4L2_TUNER_RADIO)
+		strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
+	else
+		strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name));
+	return 0;
+}
+
+static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+	int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
+	int f, l;
+
+	if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+		for (f = 0; f < 2; f++) {
+			for (l = 0; l < 24; l++) {
+				if (valid_service_line(f, l, itv->is_50hz))
+					cap->service_lines[f][l] = set;
+			}
+		}
+	} else if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
+		if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
+			return -EINVAL;
+		if (itv->is_60hz) {
+			cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+			cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+		} else {
+			cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
+			cap->service_lines[0][16] = V4L2_SLICED_VPS;
+		}
+	} else {
+		return -EINVAL;
+	}
+
+	set = 0;
+	for (f = 0; f < 2; f++)
+		for (l = 0; l < 24; l++)
+			set |= cap->service_lines[f][l];
+	cap->service_set = set;
+	return 0;
+}
+
+static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+	struct v4l2_enc_idx_entry *e = idx->entry;
+	int entries;
+	int i;
+
+	entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
+				IVTV_MAX_PGM_INDEX;
+	if (entries > V4L2_ENC_IDX_ENTRIES)
+		entries = V4L2_ENC_IDX_ENTRIES;
+	idx->entries = 0;
+	for (i = 0; i < entries; i++) {
+		*e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
+		if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) {
+			idx->entries++;
+			e++;
+		}
+	}
+	itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX;
+	return 0;
+}
+
+static int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc)
+{
+	struct ivtv_open_id *id = fh2id(fh);
+	struct ivtv *itv = id->itv;
+
+
+	switch (enc->cmd) {
+	case V4L2_ENC_CMD_START:
+		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+		enc->flags = 0;
+		return ivtv_start_capture(id);
+
+	case V4L2_ENC_CMD_STOP:
+		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+		ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
+		return 0;
+
+	case V4L2_ENC_CMD_PAUSE:
+		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+		enc->flags = 0;
+
+		if (!atomic_read(&itv->capturing))
+			return -EPERM;
+		if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
+			return 0;
+
+		ivtv_mute(itv);
+		ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0);
+		break;
+
+	case V4L2_ENC_CMD_RESUME:
+		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+		enc->flags = 0;
+
+		if (!atomic_read(&itv->capturing))
+			return -EPERM;
+
+		if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
+			return 0;
+
+		ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1);
+		ivtv_unmute(itv);
+		break;
+	default:
+		IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	switch (enc->cmd) {
+	case V4L2_ENC_CMD_START:
+		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+		enc->flags = 0;
+		return 0;
+
+	case V4L2_ENC_CMD_STOP:
+		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+		return 0;
+
+	case V4L2_ENC_CMD_PAUSE:
+		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+		enc->flags = 0;
+		return 0;
+
+	case V4L2_ENC_CMD_RESUME:
+		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+		enc->flags = 0;
+		return 0;
+	default:
+		IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
+		return -EINVAL;
+	}
+}
+
+static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	struct yuv_playback_info *yi = &itv->yuv_info;
+
+	int pixfmt;
+	static u32 pixel_format[16] = {
+		V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */
+		V4L2_PIX_FMT_RGB565,
+		V4L2_PIX_FMT_RGB555,
+		V4L2_PIX_FMT_RGB444,
+		V4L2_PIX_FMT_RGB32,
+		0,
+		0,
+		0,
+		V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */
+		V4L2_PIX_FMT_YUV565,
+		V4L2_PIX_FMT_YUV555,
+		V4L2_PIX_FMT_YUV444,
+		V4L2_PIX_FMT_YUV32,
+		0,
+		0,
+		0,
+	};
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+		return -EINVAL;
+	if (!itv->osd_video_pbase)
+		return -EINVAL;
+
+	fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
+		V4L2_FBUF_CAP_GLOBAL_ALPHA;
+
+	ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
+	data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
+	pixfmt = (data[0] >> 3) & 0xf;
+
+	fb->fmt.pixelformat = pixel_format[pixfmt];
+	fb->fmt.width = itv->osd_rect.width;
+	fb->fmt.height = itv->osd_rect.height;
+	fb->fmt.field = V4L2_FIELD_INTERLACED;
+	fb->fmt.bytesperline = fb->fmt.width;
+	fb->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	fb->fmt.field = V4L2_FIELD_INTERLACED;
+	fb->fmt.priv = 0;
+	if (fb->fmt.pixelformat != V4L2_PIX_FMT_PAL8)
+		fb->fmt.bytesperline *= 2;
+	if (fb->fmt.pixelformat == V4L2_PIX_FMT_RGB32 ||
+	    fb->fmt.pixelformat == V4L2_PIX_FMT_YUV32)
+		fb->fmt.bytesperline *= 2;
+	fb->fmt.sizeimage = fb->fmt.bytesperline * fb->fmt.height;
+	fb->base = (void *)itv->osd_video_pbase;
+	fb->flags = 0;
+
+	if (itv->osd_chroma_key_state)
+		fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+
+	if (itv->osd_global_alpha_state)
+		fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
+
+	if (yi->track_osd)
+		fb->flags |= V4L2_FBUF_FLAG_OVERLAY;
+
+	pixfmt &= 7;
+
+	/* no local alpha for RGB565 or unknown formats */
+	if (pixfmt == 1 || pixfmt > 4)
+		return 0;
+
+	/* 16-bit formats have inverted local alpha */
+	if (pixfmt == 2 || pixfmt == 3)
+		fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA;
+	else
+		fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA;
+
+	if (itv->osd_local_alpha_state) {
+		/* 16-bit formats have inverted local alpha */
+		if (pixfmt == 2 || pixfmt == 3)
+			fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA;
+		else
+			fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
+	}
+
+	return 0;
+}
+
+static int ivtv_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
+{
+	struct ivtv_open_id *id = fh2id(fh);
+	struct ivtv *itv = id->itv;
+	struct yuv_playback_info *yi = &itv->yuv_info;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+		return -EINVAL;
+	if (!itv->osd_video_pbase)
+		return -EINVAL;
+
+	itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
+	itv->osd_local_alpha_state =
+		(fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0;
+	itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
+	ivtv_set_osd_alpha(itv);
+	yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0;
+	return ivtv_g_fbuf(file, fh, fb);
+}
+
+static int ivtv_overlay(struct file *file, void *fh, unsigned int on)
+{
+	struct ivtv_open_id *id = fh2id(fh);
+	struct ivtv *itv = id->itv;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+		return -EINVAL;
+
+	ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, on != 0);
+
+	return 0;
+}
+
+static int ivtv_subscribe_event(struct v4l2_fh *fh, struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_VSYNC:
+	case V4L2_EVENT_EOS:
+		return v4l2_event_subscribe(fh, sub, 0, NULL);
+	case V4L2_EVENT_CTRL:
+		return v4l2_event_subscribe(fh, sub, 0, &v4l2_ctrl_sub_ev_ops);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int ivtv_log_status(struct file *file, void *fh)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+	u32 data[CX2341X_MBOX_MAX_DATA];
+
+	int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT;
+	struct v4l2_input vidin;
+	struct v4l2_audio audin;
+	int i;
+
+	IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
+	if (itv->hw_flags & IVTV_HW_TVEEPROM) {
+		struct tveeprom tv;
+
+		ivtv_read_eeprom(itv, &tv);
+	}
+	ivtv_call_all(itv, core, log_status);
+	ivtv_get_input(itv, itv->active_input, &vidin);
+	ivtv_get_audio_input(itv, itv->audio_input, &audin);
+	IVTV_INFO("Video Input:  %s\n", vidin.name);
+	IVTV_INFO("Audio Input:  %s%s\n", audin.name,
+		(itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : "");
+	if (has_output) {
+		struct v4l2_output vidout;
+		struct v4l2_audioout audout;
+		int mode = itv->output_mode;
+		static const char * const output_modes[5] = {
+			"None",
+			"MPEG Streaming",
+			"YUV Streaming",
+			"YUV Frames",
+			"Passthrough",
+		};
+		static const char * const alpha_mode[4] = {
+			"None",
+			"Global",
+			"Local",
+			"Global and Local"
+		};
+		static const char * const pixel_format[16] = {
+			"ARGB Indexed",
+			"RGB 5:6:5",
+			"ARGB 1:5:5:5",
+			"ARGB 1:4:4:4",
+			"ARGB 8:8:8:8",
+			"5",
+			"6",
+			"7",
+			"AYUV Indexed",
+			"YUV 5:6:5",
+			"AYUV 1:5:5:5",
+			"AYUV 1:4:4:4",
+			"AYUV 8:8:8:8",
+			"13",
+			"14",
+			"15",
+		};
+
+		ivtv_get_output(itv, itv->active_output, &vidout);
+		ivtv_get_audio_output(itv, 0, &audout);
+		IVTV_INFO("Video Output: %s\n", vidout.name);
+		if (mode < 0 || mode > OUT_PASSTHROUGH)
+			mode = OUT_NONE;
+		IVTV_INFO("Output Mode:  %s\n", output_modes[mode]);
+		ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
+		data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
+		IVTV_INFO("Overlay:      %s, Alpha: %s, Pixel Format: %s\n",
+			data[0] & 1 ? "On" : "Off",
+			alpha_mode[(data[0] >> 1) & 0x3],
+			pixel_format[(data[0] >> 3) & 0xf]);
+	}
+	IVTV_INFO("Tuner:  %s\n",
+		test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
+	v4l2_ctrl_handler_log_status(&itv->cxhdl.hdl, itv->v4l2_dev.name);
+	IVTV_INFO("Status flags:    0x%08lx\n", itv->i_flags);
+	for (i = 0; i < IVTV_MAX_STREAMS; i++) {
+		struct ivtv_stream *s = &itv->streams[i];
+
+		if (s->vdev == NULL || s->buffers == 0)
+			continue;
+		IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags,
+				(s->buffers - s->q_free.buffers) * 100 / s->buffers,
+				(s->buffers * s->buf_size) / 1024, s->buffers);
+	}
+
+	IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n",
+			(long long)itv->mpg_data_received,
+			(long long)itv->vbi_data_inserted);
+	return 0;
+}
+
+static int ivtv_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec)
+{
+	struct ivtv_open_id *id = fh2id(file->private_data);
+	struct ivtv *itv = id->itv;
+
+	IVTV_DEBUG_IOCTL("VIDIOC_DECODER_CMD %d\n", dec->cmd);
+	return ivtv_video_command(itv, id, dec, false);
+}
+
+static int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec)
+{
+	struct ivtv_open_id *id = fh2id(file->private_data);
+	struct ivtv *itv = id->itv;
+
+	IVTV_DEBUG_IOCTL("VIDIOC_TRY_DECODER_CMD %d\n", dec->cmd);
+	return ivtv_video_command(itv, id, dec, true);
+}
+
+static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
+{
+	struct ivtv_open_id *id = fh2id(filp->private_data);
+	struct ivtv *itv = id->itv;
+	int nonblocking = filp->f_flags & O_NONBLOCK;
+	struct ivtv_stream *s = &itv->streams[id->type];
+	unsigned long iarg = (unsigned long)arg;
+
+	switch (cmd) {
+	case IVTV_IOC_DMA_FRAME: {
+		struct ivtv_dma_frame *args = arg;
+
+		IVTV_DEBUG_IOCTL("IVTV_IOC_DMA_FRAME\n");
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+		if (args->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			return -EINVAL;
+		if (itv->output_mode == OUT_UDMA_YUV && args->y_source == NULL)
+			return 0;
+		if (ivtv_start_decoding(id, id->type)) {
+			return -EBUSY;
+		}
+		if (ivtv_set_output_mode(itv, OUT_UDMA_YUV) != OUT_UDMA_YUV) {
+			ivtv_release_stream(s);
+			return -EBUSY;
+		}
+		/* Mark that this file handle started the UDMA_YUV mode */
+		id->yuv_frames = 1;
+		if (args->y_source == NULL)
+			return 0;
+		return ivtv_yuv_prep_frame(itv, args);
+	}
+
+	case IVTV_IOC_PASSTHROUGH_MODE:
+		IVTV_DEBUG_IOCTL("IVTV_IOC_PASSTHROUGH_MODE\n");
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+		return ivtv_passthrough_mode(itv, *(int *)arg != 0);
+
+	case VIDEO_GET_PTS: {
+		s64 *pts = arg;
+		s64 frame;
+
+		IVTV_DEBUG_IOCTL("VIDEO_GET_PTS\n");
+		if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
+			*pts = s->dma_pts;
+			break;
+		}
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+		return ivtv_g_pts_frame(itv, pts, &frame);
+	}
+
+	case VIDEO_GET_FRAME_COUNT: {
+		s64 *frame = arg;
+		s64 pts;
+
+		IVTV_DEBUG_IOCTL("VIDEO_GET_FRAME_COUNT\n");
+		if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
+			*frame = 0;
+			break;
+		}
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+		return ivtv_g_pts_frame(itv, &pts, frame);
+	}
+
+	case VIDEO_PLAY: {
+		struct v4l2_decoder_cmd dc;
+
+		IVTV_DEBUG_IOCTL("VIDEO_PLAY\n");
+		memset(&dc, 0, sizeof(dc));
+		dc.cmd = V4L2_DEC_CMD_START;
+		return ivtv_video_command(itv, id, &dc, 0);
+	}
+
+	case VIDEO_STOP: {
+		struct v4l2_decoder_cmd dc;
+
+		IVTV_DEBUG_IOCTL("VIDEO_STOP\n");
+		memset(&dc, 0, sizeof(dc));
+		dc.cmd = V4L2_DEC_CMD_STOP;
+		dc.flags = V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY;
+		return ivtv_video_command(itv, id, &dc, 0);
+	}
+
+	case VIDEO_FREEZE: {
+		struct v4l2_decoder_cmd dc;
+
+		IVTV_DEBUG_IOCTL("VIDEO_FREEZE\n");
+		memset(&dc, 0, sizeof(dc));
+		dc.cmd = V4L2_DEC_CMD_PAUSE;
+		return ivtv_video_command(itv, id, &dc, 0);
+	}
+
+	case VIDEO_CONTINUE: {
+		struct v4l2_decoder_cmd dc;
+
+		IVTV_DEBUG_IOCTL("VIDEO_CONTINUE\n");
+		memset(&dc, 0, sizeof(dc));
+		dc.cmd = V4L2_DEC_CMD_RESUME;
+		return ivtv_video_command(itv, id, &dc, 0);
+	}
+
+	case VIDEO_COMMAND:
+	case VIDEO_TRY_COMMAND: {
+		/* Note: struct v4l2_decoder_cmd has the same layout as
+		   struct video_command */
+		struct v4l2_decoder_cmd *dc = arg;
+		int try = (cmd == VIDEO_TRY_COMMAND);
+
+		if (try)
+			IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", dc->cmd);
+		else
+			IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", dc->cmd);
+		return ivtv_video_command(itv, id, dc, try);
+	}
+
+	case VIDEO_GET_EVENT: {
+		struct video_event *ev = arg;
+		DEFINE_WAIT(wait);
+
+		IVTV_DEBUG_IOCTL("VIDEO_GET_EVENT\n");
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+		memset(ev, 0, sizeof(*ev));
+		set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
+
+		while (1) {
+			if (test_and_clear_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags))
+				ev->type = VIDEO_EVENT_DECODER_STOPPED;
+			else if (test_and_clear_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags)) {
+				ev->type = VIDEO_EVENT_VSYNC;
+				ev->u.vsync_field = test_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags) ?
+					VIDEO_VSYNC_FIELD_ODD : VIDEO_VSYNC_FIELD_EVEN;
+				if (itv->output_mode == OUT_UDMA_YUV &&
+					(itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) ==
+								IVTV_YUV_MODE_PROGRESSIVE) {
+					ev->u.vsync_field = VIDEO_VSYNC_FIELD_PROGRESSIVE;
+				}
+			}
+			if (ev->type)
+				return 0;
+			if (nonblocking)
+				return -EAGAIN;
+			/* Wait for event. Note that serialize_lock is locked,
+			   so to allow other processes to access the driver while
+			   we are waiting unlock first and later lock again. */
+			mutex_unlock(&itv->serialize_lock);
+			prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE);
+			if (!test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags) &&
+			    !test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags))
+				schedule();
+			finish_wait(&itv->event_waitq, &wait);
+			mutex_lock(&itv->serialize_lock);
+			if (signal_pending(current)) {
+				/* return if a signal was received */
+				IVTV_DEBUG_INFO("User stopped wait for event\n");
+				return -EINTR;
+			}
+		}
+		break;
+	}
+
+	case VIDEO_SELECT_SOURCE:
+		IVTV_DEBUG_IOCTL("VIDEO_SELECT_SOURCE\n");
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+		return ivtv_passthrough_mode(itv, iarg == VIDEO_SOURCE_DEMUX);
+
+	case AUDIO_SET_MUTE:
+		IVTV_DEBUG_IOCTL("AUDIO_SET_MUTE\n");
+		itv->speed_mute_audio = iarg;
+		return 0;
+
+	case AUDIO_CHANNEL_SELECT:
+		IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n");
+		if (iarg > AUDIO_STEREO_SWAPPED)
+			return -EINVAL;
+		return v4l2_ctrl_s_ctrl(itv->ctrl_audio_playback, iarg + 1);
+
+	case AUDIO_BILINGUAL_CHANNEL_SELECT:
+		IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n");
+		if (iarg > AUDIO_STEREO_SWAPPED)
+			return -EINVAL;
+		return v4l2_ctrl_s_ctrl(itv->ctrl_audio_multilingual_playback, iarg + 1);
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static long ivtv_default(struct file *file, void *fh, bool valid_prio,
+			 int cmd, void *arg)
+{
+	struct ivtv *itv = fh2id(fh)->itv;
+
+	if (!valid_prio) {
+		switch (cmd) {
+		case IVTV_IOC_PASSTHROUGH_MODE:
+		case VIDEO_PLAY:
+		case VIDEO_STOP:
+		case VIDEO_FREEZE:
+		case VIDEO_CONTINUE:
+		case VIDEO_COMMAND:
+		case VIDEO_SELECT_SOURCE:
+		case AUDIO_SET_MUTE:
+		case AUDIO_CHANNEL_SELECT:
+		case AUDIO_BILINGUAL_CHANNEL_SELECT:
+			return -EBUSY;
+		}
+	}
+
+	switch (cmd) {
+	case VIDIOC_INT_RESET: {
+		u32 val = *(u32 *)arg;
+
+		if ((val == 0 && itv->options.newi2c) || (val & 0x01))
+			ivtv_reset_ir_gpio(itv);
+		if (val & 0x02)
+			v4l2_subdev_call(itv->sd_video, core, reset, 0);
+		break;
+	}
+
+	case IVTV_IOC_DMA_FRAME:
+	case IVTV_IOC_PASSTHROUGH_MODE:
+	case VIDEO_GET_PTS:
+	case VIDEO_GET_FRAME_COUNT:
+	case VIDEO_GET_EVENT:
+	case VIDEO_PLAY:
+	case VIDEO_STOP:
+	case VIDEO_FREEZE:
+	case VIDEO_CONTINUE:
+	case VIDEO_COMMAND:
+	case VIDEO_TRY_COMMAND:
+	case VIDEO_SELECT_SOURCE:
+	case AUDIO_SET_MUTE:
+	case AUDIO_CHANNEL_SELECT:
+	case AUDIO_BILINGUAL_CHANNEL_SELECT:
+		return ivtv_decoder_ioctls(file, cmd, (void *)arg);
+
+	default:
+		return -ENOTTY;
+	}
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops ivtv_ioctl_ops = {
+	.vidioc_querycap    		    = ivtv_querycap,
+	.vidioc_s_audio     		    = ivtv_s_audio,
+	.vidioc_g_audio     		    = ivtv_g_audio,
+	.vidioc_enumaudio   		    = ivtv_enumaudio,
+	.vidioc_s_audout     		    = ivtv_s_audout,
+	.vidioc_g_audout     		    = ivtv_g_audout,
+	.vidioc_enum_input   		    = ivtv_enum_input,
+	.vidioc_enum_output   		    = ivtv_enum_output,
+	.vidioc_enumaudout   		    = ivtv_enumaudout,
+	.vidioc_cropcap       		    = ivtv_cropcap,
+	.vidioc_s_crop       		    = ivtv_s_crop,
+	.vidioc_g_crop       		    = ivtv_g_crop,
+	.vidioc_g_input      		    = ivtv_g_input,
+	.vidioc_s_input      		    = ivtv_s_input,
+	.vidioc_g_output     		    = ivtv_g_output,
+	.vidioc_s_output     		    = ivtv_s_output,
+	.vidioc_g_frequency 		    = ivtv_g_frequency,
+	.vidioc_s_frequency  		    = ivtv_s_frequency,
+	.vidioc_s_tuner      		    = ivtv_s_tuner,
+	.vidioc_g_tuner      		    = ivtv_g_tuner,
+	.vidioc_g_enc_index 		    = ivtv_g_enc_index,
+	.vidioc_g_fbuf			    = ivtv_g_fbuf,
+	.vidioc_s_fbuf			    = ivtv_s_fbuf,
+	.vidioc_g_std 			    = ivtv_g_std,
+	.vidioc_s_std 			    = ivtv_s_std,
+	.vidioc_overlay			    = ivtv_overlay,
+	.vidioc_log_status		    = ivtv_log_status,
+	.vidioc_enum_fmt_vid_cap 	    = ivtv_enum_fmt_vid_cap,
+	.vidioc_encoder_cmd  		    = ivtv_encoder_cmd,
+	.vidioc_try_encoder_cmd 	    = ivtv_try_encoder_cmd,
+	.vidioc_decoder_cmd		    = ivtv_decoder_cmd,
+	.vidioc_try_decoder_cmd		    = ivtv_try_decoder_cmd,
+	.vidioc_enum_fmt_vid_out 	    = ivtv_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_cap 		    = ivtv_g_fmt_vid_cap,
+	.vidioc_g_fmt_vbi_cap		    = ivtv_g_fmt_vbi_cap,
+	.vidioc_g_fmt_sliced_vbi_cap        = ivtv_g_fmt_sliced_vbi_cap,
+	.vidioc_g_fmt_vid_out               = ivtv_g_fmt_vid_out,
+	.vidioc_g_fmt_vid_out_overlay       = ivtv_g_fmt_vid_out_overlay,
+	.vidioc_g_fmt_sliced_vbi_out        = ivtv_g_fmt_sliced_vbi_out,
+	.vidioc_s_fmt_vid_cap  		    = ivtv_s_fmt_vid_cap,
+	.vidioc_s_fmt_vbi_cap 		    = ivtv_s_fmt_vbi_cap,
+	.vidioc_s_fmt_sliced_vbi_cap        = ivtv_s_fmt_sliced_vbi_cap,
+	.vidioc_s_fmt_vid_out               = ivtv_s_fmt_vid_out,
+	.vidioc_s_fmt_vid_out_overlay       = ivtv_s_fmt_vid_out_overlay,
+	.vidioc_s_fmt_sliced_vbi_out        = ivtv_s_fmt_sliced_vbi_out,
+	.vidioc_try_fmt_vid_cap  	    = ivtv_try_fmt_vid_cap,
+	.vidioc_try_fmt_vbi_cap		    = ivtv_try_fmt_vbi_cap,
+	.vidioc_try_fmt_sliced_vbi_cap      = ivtv_try_fmt_sliced_vbi_cap,
+	.vidioc_try_fmt_vid_out 	    = ivtv_try_fmt_vid_out,
+	.vidioc_try_fmt_vid_out_overlay     = ivtv_try_fmt_vid_out_overlay,
+	.vidioc_try_fmt_sliced_vbi_out 	    = ivtv_try_fmt_sliced_vbi_out,
+	.vidioc_g_sliced_vbi_cap 	    = ivtv_g_sliced_vbi_cap,
+	.vidioc_g_chip_ident 		    = ivtv_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register 		    = ivtv_g_register,
+	.vidioc_s_register 		    = ivtv_s_register,
+#endif
+	.vidioc_default 		    = ivtv_default,
+	.vidioc_subscribe_event 	    = ivtv_subscribe_event,
+	.vidioc_unsubscribe_event 	    = v4l2_event_unsubscribe,
+};
+
+void ivtv_set_funcs(struct video_device *vdev)
+{
+	vdev->ioctl_ops = &ivtv_ioctl_ops;
+}
diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.h b/drivers/media/pci/ivtv/ivtv-ioctl.h
new file mode 100644
index 0000000..7c553d1
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-ioctl.h
@@ -0,0 +1,35 @@
+/*
+    ioctl system call
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef IVTV_IOCTL_H
+#define IVTV_IOCTL_H
+
+u16 ivtv_service2vbi(int type);
+void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
+u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt);
+void ivtv_set_osd_alpha(struct ivtv *itv);
+int ivtv_set_speed(struct ivtv *itv, int speed);
+void ivtv_set_funcs(struct video_device *vdev);
+void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std);
+void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std);
+int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+int ivtv_s_input(struct file *file, void *fh, unsigned int inp);
+
+#endif
diff --git a/drivers/media/pci/ivtv/ivtv-irq.c b/drivers/media/pci/ivtv/ivtv-irq.c
new file mode 100644
index 0000000..1b3b957
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-irq.c
@@ -0,0 +1,1038 @@
+/* interrupt handling
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-queue.h"
+#include "ivtv-udma.h"
+#include "ivtv-irq.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-vbi.h"
+#include "ivtv-yuv.h"
+#include <media/v4l2-event.h>
+
+#define DMA_MAGIC_COOKIE 0x000001fe
+
+static void ivtv_dma_dec_start(struct ivtv_stream *s);
+
+static const int ivtv_stream_map[] = {
+	IVTV_ENC_STREAM_TYPE_MPG,
+	IVTV_ENC_STREAM_TYPE_YUV,
+	IVTV_ENC_STREAM_TYPE_PCM,
+	IVTV_ENC_STREAM_TYPE_VBI,
+};
+
+
+static void ivtv_pio_work_handler(struct ivtv *itv)
+{
+	struct ivtv_stream *s = &itv->streams[itv->cur_pio_stream];
+	struct ivtv_buffer *buf;
+	int i = 0;
+
+	IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n");
+	if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS ||
+			s->vdev == NULL || !ivtv_use_pio(s)) {
+		itv->cur_pio_stream = -1;
+		/* trigger PIO complete user interrupt */
+		write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
+		return;
+	}
+	IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name);
+	list_for_each_entry(buf, &s->q_dma.list, list) {
+		u32 size = s->sg_processing[i].size & 0x3ffff;
+
+		/* Copy the data from the card to the buffer */
+		if (s->type == IVTV_DEC_STREAM_TYPE_VBI) {
+			memcpy_fromio(buf->buf, itv->dec_mem + s->sg_processing[i].src - IVTV_DECODER_OFFSET, size);
+		}
+		else {
+			memcpy_fromio(buf->buf, itv->enc_mem + s->sg_processing[i].src, size);
+		}
+		i++;
+		if (i == s->sg_processing_size)
+			break;
+	}
+	write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
+}
+
+void ivtv_irq_work_handler(struct kthread_work *work)
+{
+	struct ivtv *itv = container_of(work, struct ivtv, irq_work);
+
+	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags))
+		ivtv_pio_work_handler(itv);
+
+	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags))
+		ivtv_vbi_work_handler(itv);
+
+	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags))
+		ivtv_yuv_work_handler(itv);
+}
+
+/* Determine the required DMA size, setup enough buffers in the predma queue and
+   actually copy the data from the card to the buffers in case a PIO transfer is
+   required for this stream.
+ */
+static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MAX_DATA])
+{
+	struct ivtv *itv = s->itv;
+	struct ivtv_buffer *buf;
+	u32 bytes_needed = 0;
+	u32 offset, size;
+	u32 UVoffset = 0, UVsize = 0;
+	int skip_bufs = s->q_predma.buffers;
+	int idx = s->sg_pending_size;
+	int rc;
+
+	/* sanity checks */
+	if (s->vdev == NULL) {
+		IVTV_DEBUG_WARN("Stream %s not started\n", s->name);
+		return -1;
+	}
+	if (!test_bit(IVTV_F_S_CLAIMED, &s->s_flags)) {
+		IVTV_DEBUG_WARN("Stream %s not open\n", s->name);
+		return -1;
+	}
+
+	/* determine offset, size and PTS for the various streams */
+	switch (s->type) {
+		case IVTV_ENC_STREAM_TYPE_MPG:
+			offset = data[1];
+			size = data[2];
+			s->pending_pts = 0;
+			break;
+
+		case IVTV_ENC_STREAM_TYPE_YUV:
+			offset = data[1];
+			size = data[2];
+			UVoffset = data[3];
+			UVsize = data[4];
+			s->pending_pts = ((u64) data[5] << 32) | data[6];
+			break;
+
+		case IVTV_ENC_STREAM_TYPE_PCM:
+			offset = data[1] + 12;
+			size = data[2] - 12;
+			s->pending_pts = read_dec(offset - 8) |
+				((u64)(read_dec(offset - 12)) << 32);
+			if (itv->has_cx23415)
+				offset += IVTV_DECODER_OFFSET;
+			break;
+
+		case IVTV_ENC_STREAM_TYPE_VBI:
+			size = itv->vbi.enc_size * itv->vbi.fpi;
+			offset = read_enc(itv->vbi.enc_start - 4) + 12;
+			if (offset == 12) {
+				IVTV_DEBUG_INFO("VBI offset == 0\n");
+				return -1;
+			}
+			s->pending_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32);
+			break;
+
+		case IVTV_DEC_STREAM_TYPE_VBI:
+			size = read_dec(itv->vbi.dec_start + 4) + 8;
+			offset = read_dec(itv->vbi.dec_start) + itv->vbi.dec_start;
+			s->pending_pts = 0;
+			offset += IVTV_DECODER_OFFSET;
+			break;
+		default:
+			/* shouldn't happen */
+			return -1;
+	}
+
+	/* if this is the start of the DMA then fill in the magic cookie */
+	if (s->sg_pending_size == 0 && ivtv_use_dma(s)) {
+		if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM ||
+		    s->type == IVTV_DEC_STREAM_TYPE_VBI)) {
+			s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET);
+			write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET);
+		}
+		else {
+			s->pending_backup = read_enc(offset);
+			write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset);
+		}
+		s->pending_offset = offset;
+	}
+
+	bytes_needed = size;
+	if (s->type == IVTV_ENC_STREAM_TYPE_YUV) {
+		/* The size for the Y samples needs to be rounded upwards to a
+		   multiple of the buf_size. The UV samples then start in the
+		   next buffer. */
+		bytes_needed = s->buf_size * ((bytes_needed + s->buf_size - 1) / s->buf_size);
+		bytes_needed += UVsize;
+	}
+
+	IVTV_DEBUG_HI_DMA("%s %s: 0x%08x bytes at 0x%08x\n",
+		ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset);
+
+	rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed);
+	if (rc < 0) { /* Insufficient buffers */
+		IVTV_DEBUG_WARN("Cannot obtain %d bytes for %s data transfer\n",
+				bytes_needed, s->name);
+		return -1;
+	}
+	if (rc && !s->buffers_stolen && test_bit(IVTV_F_S_APPL_IO, &s->s_flags)) {
+		IVTV_WARN("All %s stream buffers are full. Dropping data.\n", s->name);
+		IVTV_WARN("Cause: the application is not reading fast enough.\n");
+	}
+	s->buffers_stolen = rc;
+
+	/* got the buffers, now fill in sg_pending */
+	buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list);
+	memset(buf->buf, 0, 128);
+	list_for_each_entry(buf, &s->q_predma.list, list) {
+		if (skip_bufs-- > 0)
+			continue;
+		s->sg_pending[idx].dst = buf->dma_handle;
+		s->sg_pending[idx].src = offset;
+		s->sg_pending[idx].size = s->buf_size;
+		buf->bytesused = min(size, s->buf_size);
+		buf->dma_xfer_cnt = s->dma_xfer_cnt;
+
+		s->q_predma.bytesused += buf->bytesused;
+		size -= buf->bytesused;
+		offset += s->buf_size;
+
+		/* Sync SG buffers */
+		ivtv_buf_sync_for_device(s, buf);
+
+		if (size == 0) {	/* YUV */
+			/* process the UV section */
+			offset = UVoffset;
+			size = UVsize;
+		}
+		idx++;
+	}
+	s->sg_pending_size = idx;
+	return 0;
+}
+
+static void dma_post(struct ivtv_stream *s)
+{
+	struct ivtv *itv = s->itv;
+	struct ivtv_buffer *buf = NULL;
+	struct list_head *p;
+	u32 offset;
+	__le32 *u32buf;
+	int x = 0;
+
+	IVTV_DEBUG_HI_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
+			s->name, s->dma_offset);
+	list_for_each(p, &s->q_dma.list) {
+		buf = list_entry(p, struct ivtv_buffer, list);
+		u32buf = (__le32 *)buf->buf;
+
+		/* Sync Buffer */
+		ivtv_buf_sync_for_cpu(s, buf);
+
+		if (x == 0 && ivtv_use_dma(s)) {
+			offset = s->dma_last_offset;
+			if (u32buf[offset / 4] != DMA_MAGIC_COOKIE)
+			{
+				for (offset = 0; offset < 64; offset++) {
+					if (u32buf[offset] == DMA_MAGIC_COOKIE) {
+						break;
+					}
+				}
+				offset *= 4;
+				if (offset == 256) {
+					IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name);
+					offset = s->dma_last_offset;
+				}
+				if (s->dma_last_offset != offset)
+					IVTV_DEBUG_WARN("%s: offset %d -> %d\n", s->name, s->dma_last_offset, offset);
+				s->dma_last_offset = offset;
+			}
+			if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM ||
+						s->type == IVTV_DEC_STREAM_TYPE_VBI)) {
+				write_dec_sync(0, s->dma_offset - IVTV_DECODER_OFFSET);
+			}
+			else {
+				write_enc_sync(0, s->dma_offset);
+			}
+			if (offset) {
+				buf->bytesused -= offset;
+				memcpy(buf->buf, buf->buf + offset, buf->bytesused + offset);
+			}
+			*u32buf = cpu_to_le32(s->dma_backup);
+		}
+		x++;
+		/* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */
+		if (s->type == IVTV_ENC_STREAM_TYPE_MPG ||
+		    s->type == IVTV_ENC_STREAM_TYPE_VBI)
+			buf->b_flags |= IVTV_F_B_NEED_BUF_SWAP;
+	}
+	if (buf)
+		buf->bytesused += s->dma_last_offset;
+	if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) {
+		list_for_each_entry(buf, &s->q_dma.list, list) {
+			/* Parse and Groom VBI Data */
+			s->q_dma.bytesused -= buf->bytesused;
+			ivtv_process_vbi_data(itv, buf, 0, s->type);
+			s->q_dma.bytesused += buf->bytesused;
+		}
+		if (s->fh == NULL) {
+			ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0);
+			return;
+		}
+	}
+	ivtv_queue_move(s, &s->q_dma, NULL, &s->q_full, s->q_dma.bytesused);
+	if (s->fh)
+		wake_up(&s->waitq);
+}
+
+void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
+{
+	struct ivtv *itv = s->itv;
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	u8 frame = yi->draw_frame;
+	struct yuv_frame_info *f = &yi->new_frame_info[frame];
+	struct ivtv_buffer *buf;
+	u32 y_size = 720 * ((f->src_h + 31) & ~31);
+	u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET;
+	int y_done = 0;
+	int bytes_written = 0;
+	unsigned long flags = 0;
+	int idx = 0;
+
+	IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
+
+	/* Insert buffer block for YUV if needed */
+	if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) {
+		if (yi->blanking_dmaptr) {
+			s->sg_pending[idx].src = yi->blanking_dmaptr;
+			s->sg_pending[idx].dst = offset;
+			s->sg_pending[idx].size = 720 * 16;
+		}
+		offset += 720 * 16;
+		idx++;
+	}
+
+	list_for_each_entry(buf, &s->q_predma.list, list) {
+		/* YUV UV Offset from Y Buffer */
+		if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done &&
+				(bytes_written + buf->bytesused) >= y_size) {
+			s->sg_pending[idx].src = buf->dma_handle;
+			s->sg_pending[idx].dst = offset;
+			s->sg_pending[idx].size = y_size - bytes_written;
+			offset = uv_offset;
+			if (s->sg_pending[idx].size != buf->bytesused) {
+				idx++;
+				s->sg_pending[idx].src =
+				  buf->dma_handle + s->sg_pending[idx - 1].size;
+				s->sg_pending[idx].dst = offset;
+				s->sg_pending[idx].size =
+				   buf->bytesused - s->sg_pending[idx - 1].size;
+				offset += s->sg_pending[idx].size;
+			}
+			y_done = 1;
+		} else {
+			s->sg_pending[idx].src = buf->dma_handle;
+			s->sg_pending[idx].dst = offset;
+			s->sg_pending[idx].size = buf->bytesused;
+			offset += buf->bytesused;
+		}
+		bytes_written += buf->bytesused;
+
+		/* Sync SG buffers */
+		ivtv_buf_sync_for_device(s, buf);
+		idx++;
+	}
+	s->sg_pending_size = idx;
+
+	/* Sync Hardware SG List of buffers */
+	ivtv_stream_sync_for_device(s);
+	if (lock)
+		spin_lock_irqsave(&itv->dma_reg_lock, flags);
+	if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) {
+		ivtv_dma_dec_start(s);
+	}
+	else {
+		set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags);
+	}
+	if (lock)
+		spin_unlock_irqrestore(&itv->dma_reg_lock, flags);
+}
+
+static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s)
+{
+	struct ivtv *itv = s->itv;
+
+	s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src);
+	s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst);
+	s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000);
+	s->sg_processed++;
+	/* Sync Hardware SG List of buffers */
+	ivtv_stream_sync_for_device(s);
+	write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR);
+	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
+	itv->dma_timer.expires = jiffies + msecs_to_jiffies(300);
+	add_timer(&itv->dma_timer);
+}
+
+static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s)
+{
+	struct ivtv *itv = s->itv;
+
+	s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src);
+	s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst);
+	s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000);
+	s->sg_processed++;
+	/* Sync Hardware SG List of buffers */
+	ivtv_stream_sync_for_device(s);
+	write_reg(s->sg_handle, IVTV_REG_DECDMAADDR);
+	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
+	itv->dma_timer.expires = jiffies + msecs_to_jiffies(300);
+	add_timer(&itv->dma_timer);
+}
+
+/* start the encoder DMA */
+static void ivtv_dma_enc_start(struct ivtv_stream *s)
+{
+	struct ivtv *itv = s->itv;
+	struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+	int i;
+
+	IVTV_DEBUG_HI_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name);
+
+	if (s->q_predma.bytesused)
+		ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
+
+	if (ivtv_use_dma(s))
+		s->sg_pending[s->sg_pending_size - 1].size += 256;
+
+	/* If this is an MPEG stream, and VBI data is also pending, then append the
+	   VBI DMA to the MPEG DMA and transfer both sets of data at once.
+
+	   VBI DMA is a second class citizen compared to MPEG and mixing them together
+	   will confuse the firmware (the end of a VBI DMA is seen as the end of a
+	   MPEG DMA, thus effectively dropping an MPEG frame). So instead we make
+	   sure we only use the MPEG DMA to transfer the VBI DMA if both are in
+	   use. This way no conflicts occur. */
+	clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
+	if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->sg_pending_size &&
+			s->sg_pending_size + s_vbi->sg_pending_size <= s->buffers) {
+		ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused);
+		if (ivtv_use_dma(s_vbi))
+			s_vbi->sg_pending[s_vbi->sg_pending_size - 1].size += 256;
+		for (i = 0; i < s_vbi->sg_pending_size; i++) {
+			s->sg_pending[s->sg_pending_size++] = s_vbi->sg_pending[i];
+		}
+		s_vbi->dma_offset = s_vbi->pending_offset;
+		s_vbi->sg_pending_size = 0;
+		s_vbi->dma_xfer_cnt++;
+		set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
+		IVTV_DEBUG_HI_DMA("include DMA for %s\n", s_vbi->name);
+	}
+
+	s->dma_xfer_cnt++;
+	memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size);
+	s->sg_processing_size = s->sg_pending_size;
+	s->sg_pending_size = 0;
+	s->sg_processed = 0;
+	s->dma_offset = s->pending_offset;
+	s->dma_backup = s->pending_backup;
+	s->dma_pts = s->pending_pts;
+
+	if (ivtv_use_pio(s)) {
+		set_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags);
+		set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
+		set_bit(IVTV_F_I_PIO, &itv->i_flags);
+		itv->cur_pio_stream = s->type;
+	}
+	else {
+		itv->dma_retries = 0;
+		ivtv_dma_enc_start_xfer(s);
+		set_bit(IVTV_F_I_DMA, &itv->i_flags);
+		itv->cur_dma_stream = s->type;
+	}
+}
+
+static void ivtv_dma_dec_start(struct ivtv_stream *s)
+{
+	struct ivtv *itv = s->itv;
+
+	if (s->q_predma.bytesused)
+		ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
+	s->dma_xfer_cnt++;
+	memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size);
+	s->sg_processing_size = s->sg_pending_size;
+	s->sg_pending_size = 0;
+	s->sg_processed = 0;
+
+	IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name);
+	itv->dma_retries = 0;
+	ivtv_dma_dec_start_xfer(s);
+	set_bit(IVTV_F_I_DMA, &itv->i_flags);
+	itv->cur_dma_stream = s->type;
+}
+
+static void ivtv_irq_dma_read(struct ivtv *itv)
+{
+	struct ivtv_stream *s = NULL;
+	struct ivtv_buffer *buf;
+	int hw_stream_type = 0;
+
+	IVTV_DEBUG_HI_IRQ("DEC DMA READ\n");
+
+	del_timer(&itv->dma_timer);
+
+	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0)
+		return;
+
+	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
+		s = &itv->streams[itv->cur_dma_stream];
+		ivtv_stream_sync_for_cpu(s);
+
+		if (read_reg(IVTV_REG_DMASTATUS) & 0x14) {
+			IVTV_DEBUG_WARN("DEC DMA ERROR %x (xfer %d of %d, retry %d)\n",
+					read_reg(IVTV_REG_DMASTATUS),
+					s->sg_processed, s->sg_processing_size, itv->dma_retries);
+			write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
+			if (itv->dma_retries == 3) {
+				/* Too many retries, give up on this frame */
+				itv->dma_retries = 0;
+				s->sg_processed = s->sg_processing_size;
+			}
+			else {
+				/* Retry, starting with the first xfer segment.
+				   Just retrying the current segment is not sufficient. */
+				s->sg_processed = 0;
+				itv->dma_retries++;
+			}
+		}
+		if (s->sg_processed < s->sg_processing_size) {
+			/* DMA next buffer */
+			ivtv_dma_dec_start_xfer(s);
+			return;
+		}
+		if (s->type == IVTV_DEC_STREAM_TYPE_YUV)
+			hw_stream_type = 2;
+		IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
+
+		/* For some reason must kick the firmware, like PIO mode,
+		   I think this tells the firmware we are done and the size
+		   of the xfer so it can calculate what we need next.
+		   I think we can do this part ourselves but would have to
+		   fully calculate xfer info ourselves and not use interrupts
+		 */
+		ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, s->q_dma.bytesused,
+				hw_stream_type);
+
+		/* Free last DMA call */
+		while ((buf = ivtv_dequeue(s, &s->q_dma)) != NULL) {
+			ivtv_buf_sync_for_cpu(s, buf);
+			ivtv_enqueue(s, buf, &s->q_free);
+		}
+		wake_up(&s->waitq);
+	}
+	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
+	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
+	itv->cur_dma_stream = -1;
+	wake_up(&itv->dma_waitq);
+}
+
+static void ivtv_irq_enc_dma_complete(struct ivtv *itv)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	struct ivtv_stream *s;
+
+	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data);
+	IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream);
+
+	del_timer(&itv->dma_timer);
+
+	if (itv->cur_dma_stream < 0)
+		return;
+
+	s = &itv->streams[itv->cur_dma_stream];
+	ivtv_stream_sync_for_cpu(s);
+
+	if (data[0] & 0x18) {
+		IVTV_DEBUG_WARN("ENC DMA ERROR %x (offset %08x, xfer %d of %d, retry %d)\n", data[0],
+			s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries);
+		write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
+		if (itv->dma_retries == 3) {
+			/* Too many retries, give up on this frame */
+			itv->dma_retries = 0;
+			s->sg_processed = s->sg_processing_size;
+		}
+		else {
+			/* Retry, starting with the first xfer segment.
+			   Just retrying the current segment is not sufficient. */
+			s->sg_processed = 0;
+			itv->dma_retries++;
+		}
+	}
+	if (s->sg_processed < s->sg_processing_size) {
+		/* DMA next buffer */
+		ivtv_dma_enc_start_xfer(s);
+		return;
+	}
+	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
+	itv->cur_dma_stream = -1;
+	dma_post(s);
+	if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) {
+		s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+		dma_post(s);
+	}
+	s->sg_processing_size = 0;
+	s->sg_processed = 0;
+	wake_up(&itv->dma_waitq);
+}
+
+static void ivtv_irq_enc_pio_complete(struct ivtv *itv)
+{
+	struct ivtv_stream *s;
+
+	if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS) {
+		itv->cur_pio_stream = -1;
+		return;
+	}
+	s = &itv->streams[itv->cur_pio_stream];
+	IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name);
+	clear_bit(IVTV_F_I_PIO, &itv->i_flags);
+	itv->cur_pio_stream = -1;
+	dma_post(s);
+	if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
+		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 0);
+	else if (s->type == IVTV_ENC_STREAM_TYPE_YUV)
+		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 1);
+	else if (s->type == IVTV_ENC_STREAM_TYPE_PCM)
+		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 2);
+	clear_bit(IVTV_F_I_PIO, &itv->i_flags);
+	if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) {
+		s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+		dma_post(s);
+	}
+	wake_up(&itv->dma_waitq);
+}
+
+static void ivtv_irq_dma_err(struct ivtv *itv)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	u32 status;
+
+	del_timer(&itv->dma_timer);
+
+	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data);
+	status = read_reg(IVTV_REG_DMASTATUS);
+	IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1],
+				status, itv->cur_dma_stream);
+	/*
+	 * We do *not* write back to the IVTV_REG_DMASTATUS register to
+	 * clear the error status, if either the encoder write (0x02) or
+	 * decoder read (0x01) bus master DMA operation do not indicate
+	 * completed.  We can race with the DMA engine, which may have
+	 * transitioned to completed status *after* we read the register.
+	 * Setting a IVTV_REG_DMASTATUS flag back to "busy" status, after the
+	 * DMA engine has completed, will cause the DMA engine to stop working.
+	 */
+	status &= 0x3;
+	if (status == 0x3)
+		write_reg(status, IVTV_REG_DMASTATUS);
+
+	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) &&
+	    itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) {
+		struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream];
+
+		if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {
+			/* retry */
+			/*
+			 * FIXME - handle cases of DMA error similar to
+			 * encoder below, except conditioned on status & 0x1
+			 */
+			ivtv_dma_dec_start(s);
+			return;
+		} else {
+			if ((status & 0x2) == 0) {
+				/*
+				 * CX2341x Bus Master DMA write is ongoing.
+				 * Reset the timer and let it complete.
+				 */
+				itv->dma_timer.expires =
+						jiffies + msecs_to_jiffies(600);
+				add_timer(&itv->dma_timer);
+				return;
+			}
+
+			if (itv->dma_retries < 3) {
+				/*
+				 * CX2341x Bus Master DMA write has ended.
+				 * Retry the write, starting with the first
+				 * xfer segment. Just retrying the current
+				 * segment is not sufficient.
+				 */
+				s->sg_processed = 0;
+				itv->dma_retries++;
+				ivtv_dma_enc_start_xfer(s);
+				return;
+			}
+			/* Too many retries, give up on this one */
+		}
+
+	}
+	if (test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
+		ivtv_udma_start(itv);
+		return;
+	}
+	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
+	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
+	itv->cur_dma_stream = -1;
+	wake_up(&itv->dma_waitq);
+}
+
+static void ivtv_irq_enc_start_cap(struct ivtv *itv)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	struct ivtv_stream *s;
+
+	/* Get DMA destination and size arguments from card */
+	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, 7, data);
+	IVTV_DEBUG_HI_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
+
+	if (data[0] > 2 || data[1] == 0 || data[2] == 0) {
+		IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n",
+				data[0], data[1], data[2]);
+		return;
+	}
+	s = &itv->streams[ivtv_stream_map[data[0]]];
+	if (!stream_enc_dma_append(s, data)) {
+		set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
+	}
+}
+
+static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	struct ivtv_stream *s;
+
+	IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n");
+	s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+
+	if (!stream_enc_dma_append(s, data))
+		set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
+}
+
+static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI];
+
+	IVTV_DEBUG_HI_IRQ("DEC VBI REINSERT\n");
+	if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) &&
+			!stream_enc_dma_append(s, data)) {
+		set_bit(IVTV_F_S_PIO_PENDING, &s->s_flags);
+	}
+}
+
+static void ivtv_irq_dec_data_req(struct ivtv *itv)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	struct ivtv_stream *s;
+
+	/* YUV or MPG */
+
+	if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) {
+		ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 2, data);
+		itv->dma_data_req_size =
+				 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
+		itv->dma_data_req_offset = data[1];
+		if (atomic_read(&itv->yuv_info.next_dma_frame) >= 0)
+			ivtv_yuv_frame_complete(itv);
+		s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
+	}
+	else {
+		ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 3, data);
+		itv->dma_data_req_size = min_t(u32, data[2], 0x10000);
+		itv->dma_data_req_offset = data[1];
+		s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
+	}
+	IVTV_DEBUG_HI_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused,
+		       itv->dma_data_req_offset, itv->dma_data_req_size);
+	if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) {
+		set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
+	}
+	else {
+		if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
+			ivtv_yuv_setup_stream_frame(itv);
+		clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
+		ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size);
+		ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0);
+	}
+}
+
+static void ivtv_irq_vsync(struct ivtv *itv)
+{
+	/* The vsync interrupt is unusual in that it won't clear until
+	 * the end of the first line for the current field, at which
+	 * point it clears itself. This can result in repeated vsync
+	 * interrupts, or a missed vsync. Read some of the registers
+	 * to determine the line being displayed and ensure we handle
+	 * one vsync per frame.
+	 */
+	unsigned int frame = read_reg(IVTV_REG_DEC_LINE_FIELD) & 1;
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	int last_dma_frame = atomic_read(&yi->next_dma_frame);
+	struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame];
+
+	if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
+
+	if (((frame ^ f->sync_field) == 0 &&
+		((itv->last_vsync_field & 1) ^ f->sync_field)) ||
+			(frame != (itv->last_vsync_field & 1) && !f->interlaced)) {
+		int next_dma_frame = last_dma_frame;
+
+		if (!(f->interlaced && f->delay && yi->fields_lapsed < 1)) {
+			if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&yi->next_fill_frame)) {
+				write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
+				write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
+				write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
+				write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
+				next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS;
+				atomic_set(&yi->next_dma_frame, next_dma_frame);
+				yi->fields_lapsed = -1;
+				yi->running = 1;
+			}
+		}
+	}
+	if (frame != (itv->last_vsync_field & 1)) {
+		static const struct v4l2_event evtop = {
+			.type = V4L2_EVENT_VSYNC,
+			.u.vsync.field = V4L2_FIELD_TOP,
+		};
+		static const struct v4l2_event evbottom = {
+			.type = V4L2_EVENT_VSYNC,
+			.u.vsync.field = V4L2_FIELD_BOTTOM,
+		};
+		struct ivtv_stream *s = ivtv_get_output_stream(itv);
+
+		itv->last_vsync_field += 1;
+		if (frame == 0) {
+			clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
+			clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags);
+		}
+		else {
+			set_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags);
+		}
+		if (test_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags)) {
+			set_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags);
+			wake_up(&itv->event_waitq);
+			if (s)
+				wake_up(&s->waitq);
+		}
+		if (s && s->vdev)
+			v4l2_event_queue(s->vdev, frame ? &evtop : &evbottom);
+		wake_up(&itv->vsync_waitq);
+
+		/* Send VBI to saa7127 */
+		if (frame && (itv->output_mode == OUT_PASSTHROUGH ||
+			test_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags) ||
+			test_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags) ||
+			test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags))) {
+			set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags);
+			set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
+		}
+
+		/* Check if we need to update the yuv registers */
+		if (yi->running && (yi->yuv_forced_update || f->update)) {
+			if (!f->update) {
+				last_dma_frame =
+					(u8)(atomic_read(&yi->next_dma_frame) -
+						 1) % IVTV_YUV_BUFFERS;
+				f = &yi->new_frame_info[last_dma_frame];
+			}
+
+			if (f->src_w) {
+				yi->update_frame = last_dma_frame;
+				f->update = 0;
+				yi->yuv_forced_update = 0;
+				set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags);
+				set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
+			}
+		}
+
+		yi->fields_lapsed++;
+	}
+}
+
+#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ | IVTV_IRQ_DEC_VBI_RE_INSERT)
+
+irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
+{
+	struct ivtv *itv = (struct ivtv *)dev_id;
+	u32 combo;
+	u32 stat;
+	int i;
+	u8 vsync_force = 0;
+
+	spin_lock(&itv->dma_reg_lock);
+	/* get contents of irq status register */
+	stat = read_reg(IVTV_REG_IRQSTATUS);
+
+	combo = ~itv->irqmask & stat;
+
+	/* Clear out IRQ */
+	if (combo) write_reg(combo, IVTV_REG_IRQSTATUS);
+
+	if (0 == combo) {
+		/* The vsync interrupt is unusual and clears itself. If we
+		 * took too long, we may have missed it. Do some checks
+		 */
+		if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) {
+			/* vsync is enabled, see if we're in a new field */
+			if ((itv->last_vsync_field & 1) !=
+			    (read_reg(IVTV_REG_DEC_LINE_FIELD) & 1)) {
+				/* New field, looks like we missed it */
+				IVTV_DEBUG_YUV("VSync interrupt missed %d\n",
+				       read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16);
+				vsync_force = 1;
+			}
+		}
+
+		if (!vsync_force) {
+			/* No Vsync expected, wasn't for us */
+			spin_unlock(&itv->dma_reg_lock);
+			return IRQ_NONE;
+		}
+	}
+
+	/* Exclude interrupts noted below from the output, otherwise the log is flooded with
+	   these messages */
+	if (combo & ~0xff6d0400)
+		IVTV_DEBUG_HI_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo);
+
+	if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) {
+		IVTV_DEBUG_HI_IRQ("DEC DMA COMPLETE\n");
+	}
+
+	if (combo & IVTV_IRQ_DMA_READ) {
+		ivtv_irq_dma_read(itv);
+	}
+
+	if (combo & IVTV_IRQ_ENC_DMA_COMPLETE) {
+		ivtv_irq_enc_dma_complete(itv);
+	}
+
+	if (combo & IVTV_IRQ_ENC_PIO_COMPLETE) {
+		ivtv_irq_enc_pio_complete(itv);
+	}
+
+	if (combo & IVTV_IRQ_DMA_ERR) {
+		ivtv_irq_dma_err(itv);
+	}
+
+	if (combo & IVTV_IRQ_ENC_START_CAP) {
+		ivtv_irq_enc_start_cap(itv);
+	}
+
+	if (combo & IVTV_IRQ_ENC_VBI_CAP) {
+		ivtv_irq_enc_vbi_cap(itv);
+	}
+
+	if (combo & IVTV_IRQ_DEC_VBI_RE_INSERT) {
+		ivtv_irq_dec_vbi_reinsert(itv);
+	}
+
+	if (combo & IVTV_IRQ_ENC_EOS) {
+		IVTV_DEBUG_IRQ("ENC EOS\n");
+		set_bit(IVTV_F_I_EOS, &itv->i_flags);
+		wake_up(&itv->eos_waitq);
+	}
+
+	if (combo & IVTV_IRQ_DEC_DATA_REQ) {
+		ivtv_irq_dec_data_req(itv);
+	}
+
+	/* Decoder Vertical Sync - We can't rely on 'combo', so check if vsync enabled */
+	if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) {
+		ivtv_irq_vsync(itv);
+	}
+
+	if (combo & IVTV_IRQ_ENC_VIM_RST) {
+		IVTV_DEBUG_IRQ("VIM RST\n");
+		/*ivtv_vapi(itv, CX2341X_ENC_REFRESH_INPUT, 0); */
+	}
+
+	if (combo & IVTV_IRQ_DEC_AUD_MODE_CHG) {
+		IVTV_DEBUG_INFO("Stereo mode changed\n");
+	}
+
+	if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) {
+		itv->irq_rr_idx++;
+		for (i = 0; i < IVTV_MAX_STREAMS; i++) {
+			int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS;
+			struct ivtv_stream *s = &itv->streams[idx];
+
+			if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags))
+				continue;
+			if (s->type >= IVTV_DEC_STREAM_TYPE_MPG)
+				ivtv_dma_dec_start(s);
+			else
+				ivtv_dma_enc_start(s);
+			break;
+		}
+
+		if (i == IVTV_MAX_STREAMS &&
+		    test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
+			ivtv_udma_start(itv);
+	}
+
+	if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) {
+		itv->irq_rr_idx++;
+		for (i = 0; i < IVTV_MAX_STREAMS; i++) {
+			int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS;
+			struct ivtv_stream *s = &itv->streams[idx];
+
+			if (!test_and_clear_bit(IVTV_F_S_PIO_PENDING, &s->s_flags))
+				continue;
+			if (s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type < IVTV_DEC_STREAM_TYPE_MPG)
+				ivtv_dma_enc_start(s);
+			break;
+		}
+	}
+
+	if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) {
+		queue_kthread_work(&itv->irq_worker, &itv->irq_work);
+	}
+
+	spin_unlock(&itv->dma_reg_lock);
+
+	/* If we've just handled a 'forced' vsync, it's safest to say it
+	 * wasn't ours. Another device may have triggered it at just
+	 * the right time.
+	 */
+	return vsync_force ? IRQ_NONE : IRQ_HANDLED;
+}
+
+void ivtv_unfinished_dma(unsigned long arg)
+{
+	struct ivtv *itv = (struct ivtv *)arg;
+
+	if (!test_bit(IVTV_F_I_DMA, &itv->i_flags))
+		return;
+	IVTV_ERR("DMA TIMEOUT %08x %d\n", read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream);
+
+	write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
+	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
+	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
+	itv->cur_dma_stream = -1;
+	wake_up(&itv->dma_waitq);
+}
diff --git a/drivers/media/pci/ivtv/ivtv-irq.h b/drivers/media/pci/ivtv/ivtv-irq.h
new file mode 100644
index 0000000..1e84433
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-irq.h
@@ -0,0 +1,53 @@
+/*
+    interrupt handling
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef IVTV_IRQ_H
+#define IVTV_IRQ_H
+
+#define IVTV_IRQ_ENC_START_CAP		(0x1 << 31)
+#define IVTV_IRQ_ENC_EOS		(0x1 << 30)
+#define IVTV_IRQ_ENC_VBI_CAP		(0x1 << 29)
+#define IVTV_IRQ_ENC_VIM_RST		(0x1 << 28)
+#define IVTV_IRQ_ENC_DMA_COMPLETE	(0x1 << 27)
+#define IVTV_IRQ_ENC_PIO_COMPLETE	(0x1 << 25)
+#define IVTV_IRQ_DEC_AUD_MODE_CHG	(0x1 << 24)
+#define IVTV_IRQ_DEC_DATA_REQ		(0x1 << 22)
+#define IVTV_IRQ_DEC_DMA_COMPLETE	(0x1 << 20)
+#define IVTV_IRQ_DEC_VBI_RE_INSERT	(0x1 << 19)
+#define IVTV_IRQ_DMA_ERR		(0x1 << 18)
+#define IVTV_IRQ_DMA_WRITE		(0x1 << 17)
+#define IVTV_IRQ_DMA_READ		(0x1 << 16)
+#define IVTV_IRQ_DEC_VSYNC		(0x1 << 10)
+
+/* IRQ Masks */
+#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\
+		IVTV_IRQ_DMA_READ|IVTV_IRQ_ENC_PIO_COMPLETE)
+
+#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS)
+#define IVTV_IRQ_MASK_DECODE  (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG)
+
+irqreturn_t ivtv_irq_handler(int irq, void *dev_id);
+
+void ivtv_irq_work_handler(struct kthread_work *work);
+void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock);
+void ivtv_unfinished_dma(unsigned long arg);
+
+#endif
diff --git a/drivers/media/pci/ivtv/ivtv-mailbox.c b/drivers/media/pci/ivtv/ivtv-mailbox.c
new file mode 100644
index 0000000..e3ce967
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-mailbox.c
@@ -0,0 +1,387 @@
+/*
+    mailbox functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdarg.h>
+
+#include "ivtv-driver.h"
+#include "ivtv-mailbox.h"
+
+/* Firmware mailbox flags*/
+#define IVTV_MBOX_FIRMWARE_DONE 0x00000004
+#define IVTV_MBOX_DRIVER_DONE   0x00000002
+#define IVTV_MBOX_DRIVER_BUSY   0x00000001
+#define IVTV_MBOX_FREE 		0x00000000
+
+/* Firmware mailbox standard timeout */
+#define IVTV_API_STD_TIMEOUT 	0x02000000
+
+#define API_CACHE 	 (1 << 0) 	/* Allow the command to be stored in the cache */
+#define API_RESULT	 (1 << 1) 	/* Allow 1 second for this cmd to end */
+#define API_FAST_RESULT	 (3 << 1)	/* Allow 0.1 second for this cmd to end */
+#define API_DMA 	 (1 << 3)	/* DMA mailbox, has special handling */
+#define API_HIGH_VOL 	 (1 << 5)	/* High volume command (i.e. called during encoding or decoding) */
+#define API_NO_WAIT_MB 	 (1 << 4)	/* Command may not wait for a free mailbox */
+#define API_NO_WAIT_RES	 (1 << 5)	/* Command may not wait for the result */
+#define API_NO_POLL	 (1 << 6)	/* Avoid pointless polling */
+
+struct ivtv_api_info {
+	int flags;		/* Flags, see above */
+	const char *name; 	/* The name of the command */
+};
+
+#define API_ENTRY(x, f) [x] = { (f), #x }
+
+static const struct ivtv_api_info api_info[256] = {
+	/* MPEG encoder API */
+	API_ENTRY(CX2341X_ENC_PING_FW, 			API_FAST_RESULT),
+	API_ENTRY(CX2341X_ENC_START_CAPTURE, 		API_RESULT | API_NO_POLL),
+	API_ENTRY(CX2341X_ENC_STOP_CAPTURE, 		API_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_AUDIO_ID, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_VIDEO_ID, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_PCR_ID, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_FRAME_RATE, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_FRAME_SIZE, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_BIT_RATE, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_GOP_PROPERTIES, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_ASPECT_RATIO, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_MODE, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_PROPS, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_CORING_LEVELS, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_VBI_LINE, 		API_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_STREAM_TYPE, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_OUTPUT_PORT, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_AUDIO_PROPERTIES, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_HALT_FW, 			API_FAST_RESULT),
+	API_ENTRY(CX2341X_ENC_GET_VERSION, 		API_FAST_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_GOP_CLOSURE, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_GET_SEQ_END, 		API_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_PGM_INDEX_INFO, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_VBI_CONFIG, 		API_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_DMA_BLOCK_SIZE, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_10, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_9, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, 	API_DMA | API_HIGH_VOL),
+	API_ENTRY(CX2341X_ENC_INITIALIZE_INPUT, 	API_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_FRAME_DROP_RATE, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_PAUSE_ENCODER, 		API_RESULT),
+	API_ENTRY(CX2341X_ENC_REFRESH_INPUT, 		API_NO_WAIT_MB | API_HIGH_VOL),
+	API_ENTRY(CX2341X_ENC_SET_COPYRIGHT, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_EVENT_NOTIFICATION, 	API_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_NUM_VSYNC_LINES, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_PLACEHOLDER, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_MUTE_VIDEO, 		API_RESULT),
+	API_ENTRY(CX2341X_ENC_MUTE_AUDIO, 		API_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_VERT_CROP_LINE,	API_FAST_RESULT),
+	API_ENTRY(CX2341X_ENC_MISC, 			API_FAST_RESULT),
+	/* Obsolete PULLDOWN API command */
+	API_ENTRY(0xb1, 				API_CACHE),
+
+	/* MPEG decoder API */
+	API_ENTRY(CX2341X_DEC_PING_FW, 			API_FAST_RESULT),
+	API_ENTRY(CX2341X_DEC_START_PLAYBACK, 		API_RESULT | API_NO_POLL),
+	API_ENTRY(CX2341X_DEC_STOP_PLAYBACK, 		API_RESULT),
+	API_ENTRY(CX2341X_DEC_SET_PLAYBACK_SPEED, 	API_RESULT),
+	API_ENTRY(CX2341X_DEC_STEP_VIDEO, 		API_RESULT),
+	API_ENTRY(CX2341X_DEC_SET_DMA_BLOCK_SIZE, 	API_CACHE),
+	API_ENTRY(CX2341X_DEC_GET_XFER_INFO, 		API_FAST_RESULT),
+	API_ENTRY(CX2341X_DEC_GET_DMA_STATUS, 		API_FAST_RESULT),
+	API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, 	API_DMA | API_HIGH_VOL),
+	API_ENTRY(CX2341X_DEC_PAUSE_PLAYBACK, 		API_RESULT),
+	API_ENTRY(CX2341X_DEC_HALT_FW, 			API_FAST_RESULT),
+	API_ENTRY(CX2341X_DEC_SET_STANDARD, 		API_CACHE),
+	API_ENTRY(CX2341X_DEC_GET_VERSION, 		API_FAST_RESULT),
+	API_ENTRY(CX2341X_DEC_SET_STREAM_INPUT, 	API_CACHE),
+	API_ENTRY(CX2341X_DEC_GET_TIMING_INFO, 		API_RESULT /*| API_NO_WAIT_RES*/),
+	API_ENTRY(CX2341X_DEC_SET_AUDIO_MODE, 		API_CACHE),
+	API_ENTRY(CX2341X_DEC_SET_EVENT_NOTIFICATION, 	API_RESULT),
+	API_ENTRY(CX2341X_DEC_SET_DISPLAY_BUFFERS, 	API_CACHE),
+	API_ENTRY(CX2341X_DEC_EXTRACT_VBI, 		API_RESULT),
+	API_ENTRY(CX2341X_DEC_SET_DECODER_SOURCE, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_DEC_SET_PREBUFFERING, 	API_CACHE),
+
+	/* OSD API */
+	API_ENTRY(CX2341X_OSD_GET_FRAMEBUFFER, 		API_FAST_RESULT),
+	API_ENTRY(CX2341X_OSD_GET_PIXEL_FORMAT, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_OSD_SET_PIXEL_FORMAT, 	API_CACHE),
+	API_ENTRY(CX2341X_OSD_GET_STATE, 		API_FAST_RESULT),
+	API_ENTRY(CX2341X_OSD_SET_STATE, 		API_CACHE),
+	API_ENTRY(CX2341X_OSD_GET_OSD_COORDS, 		API_FAST_RESULT),
+	API_ENTRY(CX2341X_OSD_SET_OSD_COORDS, 		API_CACHE),
+	API_ENTRY(CX2341X_OSD_GET_SCREEN_COORDS, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_OSD_SET_SCREEN_COORDS, 	API_CACHE),
+	API_ENTRY(CX2341X_OSD_GET_GLOBAL_ALPHA, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_OSD_SET_GLOBAL_ALPHA, 	API_CACHE),
+	API_ENTRY(CX2341X_OSD_SET_BLEND_COORDS, 	API_CACHE),
+	API_ENTRY(CX2341X_OSD_GET_FLICKER_STATE, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_OSD_SET_FLICKER_STATE, 	API_CACHE),
+	API_ENTRY(CX2341X_OSD_BLT_COPY, 		API_RESULT),
+	API_ENTRY(CX2341X_OSD_BLT_FILL, 		API_RESULT),
+	API_ENTRY(CX2341X_OSD_BLT_TEXT, 		API_RESULT),
+	API_ENTRY(CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 	API_CACHE),
+	API_ENTRY(CX2341X_OSD_SET_CHROMA_KEY, 		API_CACHE),
+	API_ENTRY(CX2341X_OSD_GET_ALPHA_CONTENT_INDEX, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_OSD_SET_ALPHA_CONTENT_INDEX, 	API_CACHE)
+};
+
+static int try_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int mb)
+{
+	u32 flags = readl(&mbdata->mbox[mb].flags);
+	int is_free = flags == IVTV_MBOX_FREE || (flags & IVTV_MBOX_FIRMWARE_DONE);
+
+	/* if the mailbox is free, then try to claim it */
+	if (is_free && !test_and_set_bit(mb, &mbdata->busy)) {
+		write_sync(IVTV_MBOX_DRIVER_BUSY, &mbdata->mbox[mb].flags);
+		return 1;
+	}
+	return 0;
+}
+
+/* Try to find a free mailbox. Note mailbox 0 is reserved for DMA and so is not
+   attempted here. */
+static int get_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int flags)
+{
+	unsigned long then = jiffies;
+	int i, mb;
+	int max_mbox = mbdata->max_mbox;
+	int retries = 100;
+
+	/* All slow commands use the same mailbox, serializing them and also
+	   leaving the other mailbox free for simple fast commands. */
+	if ((flags & API_FAST_RESULT) == API_RESULT)
+		max_mbox = 1;
+
+	/* find free non-DMA mailbox */
+	for (i = 0; i < retries; i++) {
+		for (mb = 1; mb <= max_mbox; mb++)
+			if (try_mailbox(itv, mbdata, mb))
+				return mb;
+
+		/* Sleep before a retry, if not atomic */
+		if (!(flags & API_NO_WAIT_MB)) {
+			if (time_after(jiffies,
+				       then + msecs_to_jiffies(10*retries)))
+			       break;
+			ivtv_msleep_timeout(10, 0);
+		}
+	}
+	return -ENODEV;
+}
+
+static void write_mailbox(volatile struct ivtv_mailbox __iomem *mbox, int cmd, int args, u32 data[])
+{
+	int i;
+
+	write_sync(cmd, &mbox->cmd);
+	write_sync(IVTV_API_STD_TIMEOUT, &mbox->timeout);
+
+	for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++)
+		write_sync(data[i], &mbox->data[i]);
+
+	write_sync(IVTV_MBOX_DRIVER_DONE | IVTV_MBOX_DRIVER_BUSY, &mbox->flags);
+}
+
+static void clear_all_mailboxes(struct ivtv *itv, struct ivtv_mailbox_data *mbdata)
+{
+	int i;
+
+	for (i = 0; i <= mbdata->max_mbox; i++) {
+		IVTV_DEBUG_WARN("Clearing mailbox %d: cmd 0x%08x flags 0x%08x\n",
+			i, readl(&mbdata->mbox[i].cmd), readl(&mbdata->mbox[i].flags));
+		write_sync(0, &mbdata->mbox[i].flags);
+		clear_bit(i, &mbdata->busy);
+	}
+}
+
+static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
+{
+	struct ivtv_mailbox_data *mbdata = (cmd >= 128) ? &itv->enc_mbox : &itv->dec_mbox;
+	volatile struct ivtv_mailbox __iomem *mbox;
+	int api_timeout = msecs_to_jiffies(1000);
+	int flags, mb, i;
+	unsigned long then;
+
+	/* sanity checks */
+	if (NULL == mbdata) {
+		IVTV_ERR("No mailbox allocated\n");
+		return -ENODEV;
+	}
+	if (args < 0 || args > CX2341X_MBOX_MAX_DATA ||
+	    cmd < 0 || cmd > 255 || api_info[cmd].name == NULL) {
+		IVTV_ERR("Invalid MB call: cmd = 0x%02x, args = %d\n", cmd, args);
+		return -EINVAL;
+	}
+
+	if (api_info[cmd].flags & API_HIGH_VOL) {
+	    IVTV_DEBUG_HI_MB("MB Call: %s\n", api_info[cmd].name);
+	}
+	else {
+	    IVTV_DEBUG_MB("MB Call: %s\n", api_info[cmd].name);
+	}
+
+	/* clear possibly uninitialized part of data array */
+	for (i = args; i < CX2341X_MBOX_MAX_DATA; i++)
+		data[i] = 0;
+
+	/* If this command was issued within the last 30 minutes and with identical
+	   data, then just return 0 as there is no need to issue this command again.
+	   Just an optimization to prevent unnecessary use of mailboxes. */
+	if (itv->api_cache[cmd].last_jiffies &&
+	    time_before(jiffies,
+			itv->api_cache[cmd].last_jiffies +
+			msecs_to_jiffies(1800000)) &&
+	    !memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) {
+		itv->api_cache[cmd].last_jiffies = jiffies;
+		return 0;
+	}
+
+	flags = api_info[cmd].flags;
+
+	if (flags & API_DMA) {
+		for (i = 0; i < 100; i++) {
+			mb = i % (mbdata->max_mbox + 1);
+			if (try_mailbox(itv, mbdata, mb)) {
+				write_mailbox(&mbdata->mbox[mb], cmd, args, data);
+				clear_bit(mb, &mbdata->busy);
+				return 0;
+			}
+			IVTV_DEBUG_WARN("%s: mailbox %d not free %08x\n",
+					api_info[cmd].name, mb, readl(&mbdata->mbox[mb].flags));
+		}
+		IVTV_WARN("Could not find free DMA mailbox for %s\n", api_info[cmd].name);
+		clear_all_mailboxes(itv, mbdata);
+		return -EBUSY;
+	}
+
+	if ((flags & API_FAST_RESULT) == API_FAST_RESULT)
+		api_timeout = msecs_to_jiffies(100);
+
+	mb = get_mailbox(itv, mbdata, flags);
+	if (mb < 0) {
+		IVTV_DEBUG_WARN("No free mailbox found (%s)\n", api_info[cmd].name);
+		clear_all_mailboxes(itv, mbdata);
+		return -EBUSY;
+	}
+	mbox = &mbdata->mbox[mb];
+	write_mailbox(mbox, cmd, args, data);
+	if (flags & API_CACHE) {
+		memcpy(itv->api_cache[cmd].data, data, sizeof(itv->api_cache[cmd].data));
+		itv->api_cache[cmd].last_jiffies = jiffies;
+	}
+	if ((flags & API_RESULT) == 0) {
+		clear_bit(mb, &mbdata->busy);
+		return 0;
+	}
+
+	/* Get results */
+	then = jiffies;
+
+	if (!(flags & API_NO_POLL)) {
+		/* First try to poll, then switch to delays */
+		for (i = 0; i < 100; i++) {
+			if (readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)
+				break;
+		}
+	}
+	while (!(readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)) {
+		if (time_after(jiffies, then + api_timeout)) {
+			IVTV_DEBUG_WARN("Could not get result (%s)\n", api_info[cmd].name);
+			/* reset the mailbox, but it is likely too late already */
+			write_sync(0, &mbox->flags);
+			clear_bit(mb, &mbdata->busy);
+			return -EIO;
+		}
+		if (flags & API_NO_WAIT_RES)
+			mdelay(1);
+		else
+			ivtv_msleep_timeout(1, 0);
+	}
+	if (time_after(jiffies, then + msecs_to_jiffies(100)))
+		IVTV_DEBUG_WARN("%s took %u jiffies\n",
+				api_info[cmd].name,
+				jiffies_to_msecs(jiffies - then));
+
+	for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++)
+		data[i] = readl(&mbox->data[i]);
+	write_sync(0, &mbox->flags);
+	clear_bit(mb, &mbdata->busy);
+	return 0;
+}
+
+int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[])
+{
+	int res = ivtv_api_call(itv, cmd, args, data);
+
+	/* Allow a single retry, probably already too late though.
+	   If there is no free mailbox then that is usually an indication
+	   of a more serious problem. */
+	return (res == -EBUSY) ? ivtv_api_call(itv, cmd, args, data) : res;
+}
+
+int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
+{
+	return ivtv_api(priv, cmd, in, data);
+}
+
+int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...)
+{
+	va_list ap;
+	int i;
+
+	va_start(ap, args);
+	for (i = 0; i < args; i++) {
+		data[i] = va_arg(ap, u32);
+	}
+	va_end(ap);
+	return ivtv_api(itv, cmd, args, data);
+}
+
+int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	va_list ap;
+	int i;
+
+	va_start(ap, args);
+	for (i = 0; i < args; i++) {
+		data[i] = va_arg(ap, u32);
+	}
+	va_end(ap);
+	return ivtv_api(itv, cmd, args, data);
+}
+
+/* This one is for stuff that can't sleep.. irq handlers, etc.. */
+void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb,
+		       int argc, u32 data[])
+{
+	volatile u32 __iomem *p = mbdata->mbox[mb].data;
+	int i;
+	for (i = 0; i < argc; i++, p++)
+		data[i] = readl(p);
+}
+
+/* Wipe api cache */
+void ivtv_mailbox_cache_invalidate(struct ivtv *itv)
+{
+	int i;
+	for (i = 0; i < 256; i++)
+		itv->api_cache[i].last_jiffies = 0;
+}
diff --git a/drivers/media/pci/ivtv/ivtv-mailbox.h b/drivers/media/pci/ivtv/ivtv-mailbox.h
new file mode 100644
index 0000000..2c834d2
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-mailbox.h
@@ -0,0 +1,35 @@
+/*
+    mailbox functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef IVTV_MAILBOX_H
+#define IVTV_MAILBOX_H
+
+#define IVTV_MBOX_DMA_END         8
+#define IVTV_MBOX_DMA             9
+
+void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb,
+		       int argc, u32 data[]);
+int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]);
+int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...);
+int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...);
+int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
+void ivtv_mailbox_cache_invalidate(struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/pci/ivtv/ivtv-queue.c b/drivers/media/pci/ivtv/ivtv-queue.c
new file mode 100644
index 0000000..7fde36e
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-queue.c
@@ -0,0 +1,297 @@
+/*
+    buffer queues.
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-queue.h"
+
+int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes)
+{
+	if (s->buf_size - buf->bytesused < copybytes)
+		copybytes = s->buf_size - buf->bytesused;
+	if (copy_from_user(buf->buf + buf->bytesused, src, copybytes)) {
+		return -EFAULT;
+	}
+	buf->bytesused += copybytes;
+	return copybytes;
+}
+
+void ivtv_buf_swap(struct ivtv_buffer *buf)
+{
+	int i;
+
+	for (i = 0; i < buf->bytesused; i += 4)
+		swab32s((u32 *)(buf->buf + i));
+}
+
+void ivtv_queue_init(struct ivtv_queue *q)
+{
+	INIT_LIST_HEAD(&q->list);
+	q->buffers = 0;
+	q->length = 0;
+	q->bytesused = 0;
+}
+
+void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q)
+{
+	unsigned long flags;
+
+	/* clear the buffer if it is going to be enqueued to the free queue */
+	if (q == &s->q_free) {
+		buf->bytesused = 0;
+		buf->readpos = 0;
+		buf->b_flags = 0;
+		buf->dma_xfer_cnt = 0;
+	}
+	spin_lock_irqsave(&s->qlock, flags);
+	list_add_tail(&buf->list, &q->list);
+	q->buffers++;
+	q->length += s->buf_size;
+	q->bytesused += buf->bytesused - buf->readpos;
+	spin_unlock_irqrestore(&s->qlock, flags);
+}
+
+struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q)
+{
+	struct ivtv_buffer *buf = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&s->qlock, flags);
+	if (!list_empty(&q->list)) {
+		buf = list_entry(q->list.next, struct ivtv_buffer, list);
+		list_del_init(q->list.next);
+		q->buffers--;
+		q->length -= s->buf_size;
+		q->bytesused -= buf->bytesused - buf->readpos;
+	}
+	spin_unlock_irqrestore(&s->qlock, flags);
+	return buf;
+}
+
+static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from,
+		struct ivtv_queue *to, int clear)
+{
+	struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list);
+
+	list_move_tail(from->list.next, &to->list);
+	from->buffers--;
+	from->length -= s->buf_size;
+	from->bytesused -= buf->bytesused - buf->readpos;
+	/* special handling for q_free */
+	if (clear)
+		buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0;
+	to->buffers++;
+	to->length += s->buf_size;
+	to->bytesused += buf->bytesused - buf->readpos;
+}
+
+/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'.
+   If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'.
+   If 'steal' != NULL, then buffers may also taken from that queue if
+   needed, but only if 'from' is the free queue.
+
+   The buffer is automatically cleared if it goes to the free queue. It is
+   also cleared if buffers need to be taken from the 'steal' queue and
+   the 'from' queue is the free queue.
+
+   When 'from' is q_free, then needed_bytes is compared to the total
+   available buffer length, otherwise needed_bytes is compared to the
+   bytesused value. For the 'steal' queue the total available buffer
+   length is always used.
+
+   -ENOMEM is returned if the buffers could not be obtained, 0 if all
+   buffers where obtained from the 'from' list and if non-zero then
+   the number of stolen buffers is returned. */
+int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal,
+		    struct ivtv_queue *to, int needed_bytes)
+{
+	unsigned long flags;
+	int rc = 0;
+	int from_free = from == &s->q_free;
+	int to_free = to == &s->q_free;
+	int bytes_available, bytes_steal;
+
+	spin_lock_irqsave(&s->qlock, flags);
+	if (needed_bytes == 0) {
+		from_free = 1;
+		needed_bytes = from->length;
+	}
+
+	bytes_available = from_free ? from->length : from->bytesused;
+	bytes_steal = (from_free && steal) ? steal->length : 0;
+
+	if (bytes_available + bytes_steal < needed_bytes) {
+		spin_unlock_irqrestore(&s->qlock, flags);
+		return -ENOMEM;
+	}
+	while (bytes_available < needed_bytes) {
+		struct ivtv_buffer *buf = list_entry(steal->list.prev, struct ivtv_buffer, list);
+		u16 dma_xfer_cnt = buf->dma_xfer_cnt;
+
+		/* move buffers from the tail of the 'steal' queue to the tail of the
+		   'from' queue. Always copy all the buffers with the same dma_xfer_cnt
+		   value, this ensures that you do not end up with partial frame data
+		   if one frame is stored in multiple buffers. */
+		while (dma_xfer_cnt == buf->dma_xfer_cnt) {
+			list_move_tail(steal->list.prev, &from->list);
+			rc++;
+			steal->buffers--;
+			steal->length -= s->buf_size;
+			steal->bytesused -= buf->bytesused - buf->readpos;
+			buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0;
+			from->buffers++;
+			from->length += s->buf_size;
+			bytes_available += s->buf_size;
+			if (list_empty(&steal->list))
+				break;
+			buf = list_entry(steal->list.prev, struct ivtv_buffer, list);
+		}
+	}
+	if (from_free) {
+		u32 old_length = to->length;
+
+		while (to->length - old_length < needed_bytes) {
+			ivtv_queue_move_buf(s, from, to, 1);
+		}
+	}
+	else {
+		u32 old_bytesused = to->bytesused;
+
+		while (to->bytesused - old_bytesused < needed_bytes) {
+			ivtv_queue_move_buf(s, from, to, to_free);
+		}
+	}
+	spin_unlock_irqrestore(&s->qlock, flags);
+	return rc;
+}
+
+void ivtv_flush_queues(struct ivtv_stream *s)
+{
+	ivtv_queue_move(s, &s->q_io, NULL, &s->q_free, 0);
+	ivtv_queue_move(s, &s->q_full, NULL, &s->q_free, 0);
+	ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0);
+	ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0);
+}
+
+int ivtv_stream_alloc(struct ivtv_stream *s)
+{
+	struct ivtv *itv = s->itv;
+	int SGsize = sizeof(struct ivtv_sg_host_element) * s->buffers;
+	int i;
+
+	if (s->buffers == 0)
+		return 0;
+
+	IVTV_DEBUG_INFO("Allocate %s%s stream: %d x %d buffers (%dkB total)\n",
+		s->dma != PCI_DMA_NONE ? "DMA " : "",
+		s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024);
+
+	s->sg_pending = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN);
+	if (s->sg_pending == NULL) {
+		IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name);
+		return -ENOMEM;
+	}
+	s->sg_pending_size = 0;
+
+	s->sg_processing = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN);
+	if (s->sg_processing == NULL) {
+		IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name);
+		kfree(s->sg_pending);
+		s->sg_pending = NULL;
+		return -ENOMEM;
+	}
+	s->sg_processing_size = 0;
+
+	s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element),
+					GFP_KERNEL|__GFP_NOWARN);
+	if (s->sg_dma == NULL) {
+		IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name);
+		kfree(s->sg_pending);
+		s->sg_pending = NULL;
+		kfree(s->sg_processing);
+		s->sg_processing = NULL;
+		return -ENOMEM;
+	}
+	if (ivtv_might_use_dma(s)) {
+		s->sg_handle = pci_map_single(itv->pdev, s->sg_dma,
+				sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
+		ivtv_stream_sync_for_cpu(s);
+	}
+
+	/* allocate stream buffers. Initially all buffers are in q_free. */
+	for (i = 0; i < s->buffers; i++) {
+		struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer),
+						GFP_KERNEL|__GFP_NOWARN);
+
+		if (buf == NULL)
+			break;
+		buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL|__GFP_NOWARN);
+		if (buf->buf == NULL) {
+			kfree(buf);
+			break;
+		}
+		INIT_LIST_HEAD(&buf->list);
+		if (ivtv_might_use_dma(s)) {
+			buf->dma_handle = pci_map_single(s->itv->pdev,
+				buf->buf, s->buf_size + 256, s->dma);
+			ivtv_buf_sync_for_cpu(s, buf);
+		}
+		ivtv_enqueue(s, buf, &s->q_free);
+	}
+	if (i == s->buffers)
+		return 0;
+	IVTV_ERR("Couldn't allocate buffers for %s stream\n", s->name);
+	ivtv_stream_free(s);
+	return -ENOMEM;
+}
+
+void ivtv_stream_free(struct ivtv_stream *s)
+{
+	struct ivtv_buffer *buf;
+
+	/* move all buffers to q_free */
+	ivtv_flush_queues(s);
+
+	/* empty q_free */
+	while ((buf = ivtv_dequeue(s, &s->q_free))) {
+		if (ivtv_might_use_dma(s))
+			pci_unmap_single(s->itv->pdev, buf->dma_handle,
+				s->buf_size + 256, s->dma);
+		kfree(buf->buf);
+		kfree(buf);
+	}
+
+	/* Free SG Array/Lists */
+	if (s->sg_dma != NULL) {
+		if (s->sg_handle != IVTV_DMA_UNMAPPED) {
+			pci_unmap_single(s->itv->pdev, s->sg_handle,
+				 sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
+			s->sg_handle = IVTV_DMA_UNMAPPED;
+		}
+		kfree(s->sg_pending);
+		kfree(s->sg_processing);
+		kfree(s->sg_dma);
+		s->sg_pending = NULL;
+		s->sg_processing = NULL;
+		s->sg_dma = NULL;
+		s->sg_pending_size = 0;
+		s->sg_processing_size = 0;
+	}
+}
diff --git a/drivers/media/pci/ivtv/ivtv-queue.h b/drivers/media/pci/ivtv/ivtv-queue.h
new file mode 100644
index 0000000..9123383
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-queue.h
@@ -0,0 +1,96 @@
+/*
+    buffer queues.
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef IVTV_QUEUE_H
+#define IVTV_QUEUE_H
+
+#define IVTV_DMA_UNMAPPED	((u32) -1)
+#define SLICED_VBI_PIO 0
+
+/* ivtv_buffer utility functions */
+
+static inline int ivtv_might_use_pio(struct ivtv_stream *s)
+{
+	return s->dma == PCI_DMA_NONE || (SLICED_VBI_PIO && s->type == IVTV_ENC_STREAM_TYPE_VBI);
+}
+
+static inline int ivtv_use_pio(struct ivtv_stream *s)
+{
+	struct ivtv *itv = s->itv;
+
+	return s->dma == PCI_DMA_NONE ||
+	    (SLICED_VBI_PIO && s->type == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set);
+}
+
+static inline int ivtv_might_use_dma(struct ivtv_stream *s)
+{
+	return s->dma != PCI_DMA_NONE;
+}
+
+static inline int ivtv_use_dma(struct ivtv_stream *s)
+{
+	return !ivtv_use_pio(s);
+}
+
+static inline void ivtv_buf_sync_for_cpu(struct ivtv_stream *s, struct ivtv_buffer *buf)
+{
+	if (ivtv_use_dma(s))
+		pci_dma_sync_single_for_cpu(s->itv->pdev, buf->dma_handle,
+				s->buf_size + 256, s->dma);
+}
+
+static inline void ivtv_buf_sync_for_device(struct ivtv_stream *s, struct ivtv_buffer *buf)
+{
+	if (ivtv_use_dma(s))
+		pci_dma_sync_single_for_device(s->itv->pdev, buf->dma_handle,
+				s->buf_size + 256, s->dma);
+}
+
+int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes);
+void ivtv_buf_swap(struct ivtv_buffer *buf);
+
+/* ivtv_queue utility functions */
+void ivtv_queue_init(struct ivtv_queue *q);
+void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q);
+struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q);
+int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal,
+		    struct ivtv_queue *to, int needed_bytes);
+void ivtv_flush_queues(struct ivtv_stream *s);
+
+/* ivtv_stream utility functions */
+int ivtv_stream_alloc(struct ivtv_stream *s);
+void ivtv_stream_free(struct ivtv_stream *s);
+
+static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s)
+{
+	if (ivtv_use_dma(s))
+		pci_dma_sync_single_for_cpu(s->itv->pdev, s->sg_handle,
+			sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
+}
+
+static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s)
+{
+	if (ivtv_use_dma(s))
+		pci_dma_sync_single_for_device(s->itv->pdev, s->sg_handle,
+			sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
+}
+
+#endif
diff --git a/drivers/media/pci/ivtv/ivtv-routing.c b/drivers/media/pci/ivtv/ivtv-routing.c
new file mode 100644
index 0000000..8898c56
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-routing.c
@@ -0,0 +1,119 @@
+/*
+    Audio/video-routing-related ivtv functions.
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-i2c.h"
+#include "ivtv-cards.h"
+#include "ivtv-gpio.h"
+#include "ivtv-routing.h"
+
+#include <media/msp3400.h>
+#include <media/m52790.h>
+#include <media/upd64031a.h>
+#include <media/upd64083.h>
+
+/* Selects the audio input and output according to the current
+   settings. */
+void ivtv_audio_set_io(struct ivtv *itv)
+{
+	const struct ivtv_card_audio_input *in;
+	u32 input, output = 0;
+
+	/* Determine which input to use */
+	if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags))
+		in = &itv->card->radio_input;
+	else
+		in = &itv->card->audio_inputs[itv->audio_input];
+
+	/* handle muxer chips */
+	input = in->muxer_input;
+	if (itv->card->hw_muxer & IVTV_HW_M52790)
+		output = M52790_OUT_STEREO;
+	v4l2_subdev_call(itv->sd_muxer, audio, s_routing,
+			input, output, 0);
+
+	input = in->audio_input;
+	output = 0;
+	if (itv->card->hw_audio & IVTV_HW_MSP34XX)
+		output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
+	ivtv_call_hw(itv, itv->card->hw_audio, audio, s_routing,
+			input, output, 0);
+}
+
+/* Selects the video input and output according to the current
+   settings. */
+void ivtv_video_set_io(struct ivtv *itv)
+{
+	int inp = itv->active_input;
+	u32 input;
+	u32 type;
+
+	v4l2_subdev_call(itv->sd_video, video, s_routing,
+		itv->card->video_inputs[inp].video_input, 0, 0);
+
+	type = itv->card->video_inputs[inp].video_type;
+
+	if (type == IVTV_CARD_INPUT_VID_TUNER) {
+		input = 0;  /* Tuner */
+	} else if (type < IVTV_CARD_INPUT_COMPOSITE1) {
+		input = 2;  /* S-Video */
+	} else {
+		input = 1;  /* Composite */
+	}
+
+	if (itv->card->hw_video & IVTV_HW_GPIO)
+		ivtv_call_hw(itv, IVTV_HW_GPIO, video, s_routing,
+				input, 0, 0);
+
+	if (itv->card->hw_video & IVTV_HW_UPD64031A) {
+		if (type == IVTV_CARD_INPUT_VID_TUNER ||
+		    type >= IVTV_CARD_INPUT_COMPOSITE1) {
+			/* Composite: GR on, connect to 3DYCS */
+			input = UPD64031A_GR_ON | UPD64031A_3DYCS_COMPOSITE;
+		} else {
+			/* S-Video: GR bypassed, turn it off */
+			input = UPD64031A_GR_OFF | UPD64031A_3DYCS_DISABLE;
+		}
+		input |= itv->card->gr_config;
+
+		ivtv_call_hw(itv, IVTV_HW_UPD64031A, video, s_routing,
+				input, 0, 0);
+	}
+
+	if (itv->card->hw_video & IVTV_HW_UPD6408X) {
+		input = UPD64083_YCS_MODE;
+		if (type > IVTV_CARD_INPUT_VID_TUNER &&
+		    type < IVTV_CARD_INPUT_COMPOSITE1) {
+			/* S-Video uses YCNR mode and internal Y-ADC, the
+			   upd64031a is not used. */
+			input |= UPD64083_YCNR_MODE;
+		}
+		else if (itv->card->hw_video & IVTV_HW_UPD64031A) {
+			/* Use upd64031a output for tuner and
+			   composite(CX23416GYC only) inputs */
+			if (type == IVTV_CARD_INPUT_VID_TUNER ||
+			    itv->card->type == IVTV_CARD_CX23416GYC) {
+				input |= UPD64083_EXT_Y_ADC;
+			}
+		}
+		ivtv_call_hw(itv, IVTV_HW_UPD6408X, video, s_routing,
+				input, 0, 0);
+	}
+}
diff --git a/drivers/media/pci/ivtv/ivtv-routing.h b/drivers/media/pci/ivtv/ivtv-routing.h
new file mode 100644
index 0000000..c72a973
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-routing.h
@@ -0,0 +1,27 @@
+/*
+    Audio/video-routing-related ivtv functions.
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef IVTV_ROUTING_H
+#define IVTV_ROUTING_H
+
+void ivtv_audio_set_io(struct ivtv *itv);
+void ivtv_video_set_io(struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/pci/ivtv/ivtv-streams.c b/drivers/media/pci/ivtv/ivtv-streams.c
new file mode 100644
index 0000000..f08ec17
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-streams.c
@@ -0,0 +1,1014 @@
+/*
+    init/start/stop/exit stream functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* License: GPL
+ * Author: Kevin Thayer <nufan_wfk at yahoo dot com>
+ *
+ * This file will hold API related functions, both internal (firmware api)
+ * and external (v4l2, etc)
+ *
+ * -----
+ * MPG600/MPG160 support by  T.Adachi <tadachi@tadachi-net.com>
+ *                      and Takeru KOMORIYA<komoriya@paken.org>
+ *
+ * AVerMedia M179 GPIO info by Chris Pinkham <cpinkham@bc2va.org>
+ *                using information provided by Jiun-Kuei Jung @ AVerMedia.
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-fileops.h"
+#include "ivtv-queue.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-irq.h"
+#include "ivtv-yuv.h"
+#include "ivtv-cards.h"
+#include "ivtv-streams.h"
+#include "ivtv-firmware.h"
+#include <media/v4l2-event.h>
+
+static const struct v4l2_file_operations ivtv_v4l2_enc_fops = {
+	.owner = THIS_MODULE,
+	.read = ivtv_v4l2_read,
+	.write = ivtv_v4l2_write,
+	.open = ivtv_v4l2_open,
+	.unlocked_ioctl = video_ioctl2,
+	.release = ivtv_v4l2_close,
+	.poll = ivtv_v4l2_enc_poll,
+};
+
+static const struct v4l2_file_operations ivtv_v4l2_dec_fops = {
+	.owner = THIS_MODULE,
+	.read = ivtv_v4l2_read,
+	.write = ivtv_v4l2_write,
+	.open = ivtv_v4l2_open,
+	.unlocked_ioctl = video_ioctl2,
+	.release = ivtv_v4l2_close,
+	.poll = ivtv_v4l2_dec_poll,
+};
+
+#define IVTV_V4L2_DEC_MPG_OFFSET  16	/* offset from 0 to register decoder mpg v4l2 minors on */
+#define IVTV_V4L2_ENC_PCM_OFFSET  24	/* offset from 0 to register pcm v4l2 minors on */
+#define IVTV_V4L2_ENC_YUV_OFFSET  32	/* offset from 0 to register yuv v4l2 minors on */
+#define IVTV_V4L2_DEC_YUV_OFFSET  48	/* offset from 0 to register decoder yuv v4l2 minors on */
+#define IVTV_V4L2_DEC_VBI_OFFSET   8	/* offset from 0 to register decoder vbi input v4l2 minors on */
+#define IVTV_V4L2_DEC_VOUT_OFFSET 16	/* offset from 0 to register vbi output v4l2 minors on */
+
+static struct {
+	const char *name;
+	int vfl_type;
+	int num_offset;
+	int dma, pio;
+	enum v4l2_buf_type buf_type;
+	u32 v4l2_caps;
+	const struct v4l2_file_operations *fops;
+} ivtv_stream_info[] = {
+	{	/* IVTV_ENC_STREAM_TYPE_MPG */
+		"encoder MPG",
+		VFL_TYPE_GRABBER, 0,
+		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+		V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
+			V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
+		&ivtv_v4l2_enc_fops
+	},
+	{	/* IVTV_ENC_STREAM_TYPE_YUV */
+		"encoder YUV",
+		VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET,
+		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+		V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
+			V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
+		&ivtv_v4l2_enc_fops
+	},
+	{	/* IVTV_ENC_STREAM_TYPE_VBI */
+		"encoder VBI",
+		VFL_TYPE_VBI, 0,
+		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VBI_CAPTURE,
+		V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_TUNER |
+			V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
+		&ivtv_v4l2_enc_fops
+	},
+	{	/* IVTV_ENC_STREAM_TYPE_PCM */
+		"encoder PCM",
+		VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET,
+		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE,
+		V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
+		&ivtv_v4l2_enc_fops
+	},
+	{	/* IVTV_ENC_STREAM_TYPE_RAD */
+		"encoder radio",
+		VFL_TYPE_RADIO, 0,
+		PCI_DMA_NONE, 1, V4L2_BUF_TYPE_PRIVATE,
+		V4L2_CAP_RADIO | V4L2_CAP_TUNER,
+		&ivtv_v4l2_enc_fops
+	},
+	{	/* IVTV_DEC_STREAM_TYPE_MPG */
+		"decoder MPG",
+		VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET,
+		PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+		V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
+		&ivtv_v4l2_dec_fops
+	},
+	{	/* IVTV_DEC_STREAM_TYPE_VBI */
+		"decoder VBI",
+		VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET,
+		PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_CAPTURE,
+		V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_READWRITE,
+		&ivtv_v4l2_enc_fops
+	},
+	{	/* IVTV_DEC_STREAM_TYPE_VOUT */
+		"decoder VOUT",
+		VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET,
+		PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_OUTPUT,
+		V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
+		&ivtv_v4l2_dec_fops
+	},
+	{	/* IVTV_DEC_STREAM_TYPE_YUV */
+		"decoder YUV",
+		VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET,
+		PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+		V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
+		&ivtv_v4l2_dec_fops
+	}
+};
+
+static void ivtv_stream_init(struct ivtv *itv, int type)
+{
+	struct ivtv_stream *s = &itv->streams[type];
+	struct video_device *vdev = s->vdev;
+
+	/* we need to keep vdev, so restore it afterwards */
+	memset(s, 0, sizeof(*s));
+	s->vdev = vdev;
+
+	/* initialize ivtv_stream fields */
+	s->itv = itv;
+	s->type = type;
+	s->name = ivtv_stream_info[type].name;
+	s->caps = ivtv_stream_info[type].v4l2_caps;
+
+	if (ivtv_stream_info[type].pio)
+		s->dma = PCI_DMA_NONE;
+	else
+		s->dma = ivtv_stream_info[type].dma;
+	s->buf_size = itv->stream_buf_size[type];
+	if (s->buf_size)
+		s->buffers = (itv->options.kilobytes[type] * 1024 + s->buf_size - 1) / s->buf_size;
+	spin_lock_init(&s->qlock);
+	init_waitqueue_head(&s->waitq);
+	s->sg_handle = IVTV_DMA_UNMAPPED;
+	ivtv_queue_init(&s->q_free);
+	ivtv_queue_init(&s->q_full);
+	ivtv_queue_init(&s->q_dma);
+	ivtv_queue_init(&s->q_predma);
+	ivtv_queue_init(&s->q_io);
+}
+
+static int ivtv_prep_dev(struct ivtv *itv, int type)
+{
+	struct ivtv_stream *s = &itv->streams[type];
+	int num_offset = ivtv_stream_info[type].num_offset;
+	int num = itv->instance + ivtv_first_minor + num_offset;
+
+	/* These four fields are always initialized. If vdev == NULL, then
+	   this stream is not in use. In that case no other fields but these
+	   four can be used. */
+	s->vdev = NULL;
+	s->itv = itv;
+	s->type = type;
+	s->name = ivtv_stream_info[type].name;
+
+	/* Check whether the radio is supported */
+	if (type == IVTV_ENC_STREAM_TYPE_RAD && !(itv->v4l2_cap & V4L2_CAP_RADIO))
+		return 0;
+	if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return 0;
+
+	/* User explicitly selected 0 buffers for these streams, so don't
+	   create them. */
+	if (ivtv_stream_info[type].dma != PCI_DMA_NONE &&
+	    itv->options.kilobytes[type] == 0) {
+		IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name);
+		return 0;
+	}
+
+	ivtv_stream_init(itv, type);
+
+	/* allocate and initialize the v4l2 video device structure */
+	s->vdev = video_device_alloc();
+	if (s->vdev == NULL) {
+		IVTV_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name);
+		return -ENOMEM;
+	}
+
+	snprintf(s->vdev->name, sizeof(s->vdev->name), "%s %s",
+			itv->v4l2_dev.name, s->name);
+
+	s->vdev->num = num;
+	s->vdev->v4l2_dev = &itv->v4l2_dev;
+	s->vdev->fops = ivtv_stream_info[type].fops;
+	s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler;
+	s->vdev->release = video_device_release;
+	s->vdev->tvnorms = V4L2_STD_ALL;
+	s->vdev->lock = &itv->serialize_lock;
+	set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev->flags);
+	ivtv_set_funcs(s->vdev);
+	return 0;
+}
+
+/* Initialize v4l2 variables and prepare v4l2 devices */
+int ivtv_streams_setup(struct ivtv *itv)
+{
+	int type;
+
+	/* Setup V4L2 Devices */
+	for (type = 0; type < IVTV_MAX_STREAMS; type++) {
+		/* Prepare device */
+		if (ivtv_prep_dev(itv, type))
+			break;
+
+		if (itv->streams[type].vdev == NULL)
+			continue;
+
+		/* Allocate Stream */
+		if (ivtv_stream_alloc(&itv->streams[type]))
+			break;
+	}
+	if (type == IVTV_MAX_STREAMS)
+		return 0;
+
+	/* One or more streams could not be initialized. Clean 'em all up. */
+	ivtv_streams_cleanup(itv, 0);
+	return -ENOMEM;
+}
+
+static int ivtv_reg_dev(struct ivtv *itv, int type)
+{
+	struct ivtv_stream *s = &itv->streams[type];
+	int vfl_type = ivtv_stream_info[type].vfl_type;
+	const char *name;
+	int num;
+
+	if (s->vdev == NULL)
+		return 0;
+
+	num = s->vdev->num;
+	/* card number + user defined offset + device offset */
+	if (type != IVTV_ENC_STREAM_TYPE_MPG) {
+		struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];
+
+		if (s_mpg->vdev)
+			num = s_mpg->vdev->num + ivtv_stream_info[type].num_offset;
+	}
+	video_set_drvdata(s->vdev, s);
+
+	/* Register device. First try the desired minor, then any free one. */
+	if (video_register_device_no_warn(s->vdev, vfl_type, num)) {
+		IVTV_ERR("Couldn't register v4l2 device for %s (device node number %d)\n",
+				s->name, num);
+		video_device_release(s->vdev);
+		s->vdev = NULL;
+		return -ENOMEM;
+	}
+	name = video_device_node_name(s->vdev);
+
+	switch (vfl_type) {
+	case VFL_TYPE_GRABBER:
+		IVTV_INFO("Registered device %s for %s (%d kB)\n",
+			name, s->name, itv->options.kilobytes[type]);
+		break;
+	case VFL_TYPE_RADIO:
+		IVTV_INFO("Registered device %s for %s\n",
+			name, s->name);
+		break;
+	case VFL_TYPE_VBI:
+		if (itv->options.kilobytes[type])
+			IVTV_INFO("Registered device %s for %s (%d kB)\n",
+				name, s->name, itv->options.kilobytes[type]);
+		else
+			IVTV_INFO("Registered device %s for %s\n",
+				name, s->name);
+		break;
+	}
+	return 0;
+}
+
+/* Register v4l2 devices */
+int ivtv_streams_register(struct ivtv *itv)
+{
+	int type;
+	int err = 0;
+
+	/* Register V4L2 devices */
+	for (type = 0; type < IVTV_MAX_STREAMS; type++)
+		err |= ivtv_reg_dev(itv, type);
+
+	if (err == 0)
+		return 0;
+
+	/* One or more streams could not be initialized. Clean 'em all up. */
+	ivtv_streams_cleanup(itv, 1);
+	return -ENOMEM;
+}
+
+/* Unregister v4l2 devices */
+void ivtv_streams_cleanup(struct ivtv *itv, int unregister)
+{
+	int type;
+
+	/* Teardown all streams */
+	for (type = 0; type < IVTV_MAX_STREAMS; type++) {
+		struct video_device *vdev = itv->streams[type].vdev;
+
+		itv->streams[type].vdev = NULL;
+		if (vdev == NULL)
+			continue;
+
+		ivtv_stream_free(&itv->streams[type]);
+		/* Unregister or release device */
+		if (unregister)
+			video_unregister_device(vdev);
+		else
+			video_device_release(vdev);
+	}
+}
+
+static void ivtv_vbi_setup(struct ivtv *itv)
+{
+	int raw = ivtv_raw_vbi(itv);
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	int lines;
+	int i;
+
+	/* Reset VBI */
+	ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0);
+
+	/* setup VBI registers */
+	if (raw)
+		v4l2_subdev_call(itv->sd_video, vbi, s_raw_fmt, &itv->vbi.in.fmt.vbi);
+	else
+		v4l2_subdev_call(itv->sd_video, vbi, s_sliced_fmt, &itv->vbi.in.fmt.sliced);
+
+	/* determine number of lines and total number of VBI bytes.
+	   A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1
+	   The '- 1' byte is probably an unused U or V byte. Or something...
+	   A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal
+	   header, 42 data bytes + checksum (to be confirmed) */
+	if (raw) {
+		lines = itv->vbi.count * 2;
+	} else {
+		lines = itv->is_60hz ? 24 : 38;
+		if (itv->is_60hz && (itv->hw_flags & IVTV_HW_CX25840))
+			lines += 2;
+	}
+
+	itv->vbi.enc_size = lines * (raw ? itv->vbi.raw_size : itv->vbi.sliced_size);
+
+	/* Note: sliced vs raw flag doesn't seem to have any effect
+	   TODO: check mode (0x02) value with older ivtv versions. */
+	data[0] = raw | 0x02 | (0xbd << 8);
+
+	/* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */
+	data[1] = 1;
+	/* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */
+	data[2] = raw ? 4 : 4 * (itv->vbi.raw_size / itv->vbi.enc_size);
+	/* The start/stop codes determine which VBI lines end up in the raw VBI data area.
+	   The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line
+	   is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video)
+	   code. These values for raw VBI are obtained from a driver disassembly. The sliced
+	   start/stop codes was deduced from this, but they do not appear in the driver.
+	   Other code pairs that I found are: 0x250E6249/0x13545454 and 0x25256262/0x38137F54.
+	   However, I have no idea what these values are for. */
+	if (itv->hw_flags & IVTV_HW_CX25840) {
+		/* Setup VBI for the cx25840 digitizer */
+		if (raw) {
+			data[3] = 0x20602060;
+			data[4] = 0x30703070;
+		} else {
+			data[3] = 0xB0F0B0F0;
+			data[4] = 0xA0E0A0E0;
+		}
+		/* Lines per frame */
+		data[5] = lines;
+		/* bytes per line */
+		data[6] = (raw ? itv->vbi.raw_size : itv->vbi.sliced_size);
+	} else {
+		/* Setup VBI for the saa7115 digitizer */
+		if (raw) {
+			data[3] = 0x25256262;
+			data[4] = 0x387F7F7F;
+		} else {
+			data[3] = 0xABABECEC;
+			data[4] = 0xB6F1F1F1;
+		}
+		/* Lines per frame */
+		data[5] = lines;
+		/* bytes per line */
+		data[6] = itv->vbi.enc_size / lines;
+	}
+
+	IVTV_DEBUG_INFO(
+		"Setup VBI API header 0x%08x pkts %d buffs %d ln %d sz %d\n",
+			data[0], data[1], data[2], data[5], data[6]);
+
+	ivtv_api(itv, CX2341X_ENC_SET_VBI_CONFIG, 7, data);
+
+	/* returns the VBI encoder memory area. */
+	itv->vbi.enc_start = data[2];
+	itv->vbi.fpi = data[0];
+	if (!itv->vbi.fpi)
+		itv->vbi.fpi = 1;
+
+	IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d\n",
+		itv->vbi.enc_start, data[1], itv->vbi.fpi);
+
+	/* select VBI lines.
+	   Note that the sliced argument seems to have no effect. */
+	for (i = 2; i <= 24; i++) {
+		int valid;
+
+		if (itv->is_60hz) {
+			valid = i >= 10 && i < 22;
+		} else {
+			valid = i >= 6 && i < 24;
+		}
+		ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, i - 1,
+				valid, 0 , 0, 0);
+		ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, (i - 1) | 0x80000000,
+				valid, 0, 0, 0);
+	}
+
+	/* Remaining VBI questions:
+	   - Is it possible to select particular VBI lines only for inclusion in the MPEG
+	   stream? Currently you can only get the first X lines.
+	   - Is mixed raw and sliced VBI possible?
+	   - What's the meaning of the raw/sliced flag?
+	   - What's the meaning of params 2, 3 & 4 of the Select VBI command? */
+}
+
+int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	struct ivtv *itv = s->itv;
+	int captype = 0, subtype = 0;
+	int enable_passthrough = 0;
+
+	if (s->vdev == NULL)
+		return -EINVAL;
+
+	IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);
+
+	switch (s->type) {
+	case IVTV_ENC_STREAM_TYPE_MPG:
+		captype = 0;
+		subtype = 3;
+
+		/* Stop Passthrough */
+		if (itv->output_mode == OUT_PASSTHROUGH) {
+			ivtv_passthrough_mode(itv, 0);
+			enable_passthrough = 1;
+		}
+		itv->mpg_data_received = itv->vbi_data_inserted = 0;
+		itv->dualwatch_jiffies = jiffies;
+		itv->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(itv->cxhdl.audio_mode);
+		itv->search_pack_header = 0;
+		break;
+
+	case IVTV_ENC_STREAM_TYPE_YUV:
+		if (itv->output_mode == OUT_PASSTHROUGH) {
+			captype = 2;
+			subtype = 11;	/* video+audio+decoder */
+			break;
+		}
+		captype = 1;
+		subtype = 1;
+		break;
+	case IVTV_ENC_STREAM_TYPE_PCM:
+		captype = 1;
+		subtype = 2;
+		break;
+	case IVTV_ENC_STREAM_TYPE_VBI:
+		captype = 1;
+		subtype = 4;
+
+		itv->vbi.frame = 0;
+		itv->vbi.inserted_frame = 0;
+		memset(itv->vbi.sliced_mpeg_size,
+			0, sizeof(itv->vbi.sliced_mpeg_size));
+		break;
+	default:
+		return -EINVAL;
+	}
+	s->subtype = subtype;
+	s->buffers_stolen = 0;
+
+	/* Clear Streamoff flags in case left from last capture */
+	clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+
+	if (atomic_read(&itv->capturing) == 0) {
+		int digitizer;
+
+		/* Always use frame based mode. Experiments have demonstrated that byte
+		   stream based mode results in dropped frames and corruption. Not often,
+		   but occasionally. Many thanks go to Leonard Orb who spent a lot of
+		   effort and time trying to trace the cause of the drop outs. */
+		/* 1 frame per DMA */
+		/*ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 128, 0); */
+		ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 1, 1);
+
+		/* Stuff from Windows, we don't know what it is */
+		ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1, 0);
+		/* According to the docs, this should be correct. However, this is
+		   untested. I don't dare enable this without having tested it.
+		   Only very few old cards actually have this hardware combination.
+		ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1,
+			((itv->hw_flags & IVTV_HW_SAA7114) && itv->is_60hz) ? 10001 : 0);
+		*/
+		ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 3, !itv->has_cx23415);
+		ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 8, 0);
+		ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 4, 1);
+		ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
+
+		/* assign placeholder */
+		ivtv_vapi(itv, CX2341X_ENC_SET_PLACEHOLDER, 12,
+			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+		if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X))
+		    digitizer = 0xF1;
+		else if (itv->card->hw_all & IVTV_HW_SAA7114)
+		    digitizer = 0xEF;
+		else /* cx25840 */
+		    digitizer = 0x140;
+
+		ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, digitizer, digitizer);
+
+		/* Setup VBI */
+		if (itv->v4l2_cap & V4L2_CAP_VBI_CAPTURE) {
+			ivtv_vbi_setup(itv);
+		}
+
+		/* assign program index info. Mask 7: select I/P/B, Num_req: 400 max */
+		ivtv_vapi_result(itv, data, CX2341X_ENC_SET_PGM_INDEX_INFO, 2, 7, 400);
+		itv->pgm_info_offset = data[0];
+		itv->pgm_info_num = data[1];
+		itv->pgm_info_write_idx = 0;
+		itv->pgm_info_read_idx = 0;
+
+		IVTV_DEBUG_INFO("PGM Index at 0x%08x with %d elements\n",
+				itv->pgm_info_offset, itv->pgm_info_num);
+
+		/* Setup API for Stream */
+		cx2341x_handler_setup(&itv->cxhdl);
+
+		/* mute if capturing radio */
+		if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags))
+			ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1,
+				1 | (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8));
+	}
+
+	/* Vsync Setup */
+	if (itv->has_cx23415 && !test_and_set_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
+		/* event notification (on) */
+		ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_ENC_VIM_RST, -1);
+		ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
+	}
+
+	if (atomic_read(&itv->capturing) == 0) {
+		/* Clear all Pending Interrupts */
+		ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
+
+		clear_bit(IVTV_F_I_EOS, &itv->i_flags);
+
+		cx2341x_handler_set_busy(&itv->cxhdl, 1);
+
+		/* Initialize Digitizer for Capture */
+		/* Avoid tinny audio problem - ensure audio clocks are going */
+		v4l2_subdev_call(itv->sd_audio, audio, s_stream, 1);
+		/* Avoid unpredictable PCI bus hang - disable video clocks */
+		v4l2_subdev_call(itv->sd_video, video, s_stream, 0);
+		ivtv_msleep_timeout(300, 0);
+		ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
+		v4l2_subdev_call(itv->sd_video, video, s_stream, 1);
+	}
+
+	/* begin_capture */
+	if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype))
+	{
+		IVTV_DEBUG_WARN( "Error starting capture!\n");
+		return -EINVAL;
+	}
+
+	/* Start Passthrough */
+	if (enable_passthrough) {
+		ivtv_passthrough_mode(itv, 1);
+	}
+
+	if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
+		ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
+	else
+		ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
+
+	/* you're live! sit back and await interrupts :) */
+	atomic_inc(&itv->capturing);
+	return 0;
+}
+
+static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	struct ivtv *itv = s->itv;
+	int datatype;
+	u16 width;
+	u16 height;
+
+	if (s->vdev == NULL)
+		return -EINVAL;
+
+	IVTV_DEBUG_INFO("Setting some initial decoder settings\n");
+
+	width = itv->cxhdl.width;
+	height = itv->cxhdl.height;
+
+	/* set audio mode to left/stereo  for dual/stereo mode. */
+	ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
+
+	/* set number of internal decoder buffers */
+	ivtv_vapi(itv, CX2341X_DEC_SET_DISPLAY_BUFFERS, 1, 0);
+
+	/* prebuffering */
+	ivtv_vapi(itv, CX2341X_DEC_SET_PREBUFFERING, 1, 1);
+
+	/* extract from user packets */
+	ivtv_vapi_result(itv, data, CX2341X_DEC_EXTRACT_VBI, 1, 1);
+	itv->vbi.dec_start = data[0];
+
+	IVTV_DEBUG_INFO("Decoder VBI RE-Insert start 0x%08x size 0x%08x\n",
+		itv->vbi.dec_start, data[1]);
+
+	/* set decoder source settings */
+	/* Data type: 0 = mpeg from host,
+	   1 = yuv from encoder,
+	   2 = yuv_from_host */
+	switch (s->type) {
+	case IVTV_DEC_STREAM_TYPE_YUV:
+		if (itv->output_mode == OUT_PASSTHROUGH) {
+			datatype = 1;
+		} else {
+			/* Fake size to avoid switching video standard */
+			datatype = 2;
+			width = 720;
+			height = itv->is_out_50hz ? 576 : 480;
+		}
+		IVTV_DEBUG_INFO("Setup DEC YUV Stream data[0] = %d\n", datatype);
+		break;
+	case IVTV_DEC_STREAM_TYPE_MPG:
+	default:
+		datatype = 0;
+		break;
+	}
+	if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype,
+			width, height, itv->cxhdl.audio_properties)) {
+		IVTV_DEBUG_WARN("Couldn't initialize decoder source\n");
+	}
+
+	/* Decoder sometimes dies here, so wait a moment */
+	ivtv_msleep_timeout(10, 0);
+
+	/* Known failure point for firmware, so check */
+	return ivtv_firmware_check(itv, "ivtv_setup_v4l2_decode_stream");
+}
+
+int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
+{
+	struct ivtv *itv = s->itv;
+	int rc;
+
+	if (s->vdev == NULL)
+		return -EINVAL;
+
+	if (test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags))
+		return 0;	/* already started */
+
+	IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset);
+
+	rc = ivtv_setup_v4l2_decode_stream(s);
+	if (rc < 0) {
+		clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+		return rc;
+	}
+
+	/* set dma size to 65536 bytes */
+	ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536);
+
+	/* Clear Streamoff */
+	clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+
+	/* Zero out decoder counters */
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[0]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[1]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[2]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[3]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[0]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[1]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[2]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[3]);
+
+	/* turn on notification of dual/stereo mode change */
+	ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_DEC_AUD_MODE_CHG, -1);
+
+	/* start playback */
+	ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, gop_offset, 0);
+
+	/* Let things settle before we actually start */
+	ivtv_msleep_timeout(10, 0);
+
+	/* Clear the following Interrupt mask bits for decoding */
+	ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
+	IVTV_DEBUG_IRQ("IRQ Mask is now: 0x%08x\n", itv->irqmask);
+
+	/* you're live! sit back and await interrupts :) */
+	atomic_inc(&itv->decoding);
+	return 0;
+}
+
+void ivtv_stop_all_captures(struct ivtv *itv)
+{
+	int i;
+
+	for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) {
+		struct ivtv_stream *s = &itv->streams[i];
+
+		if (s->vdev == NULL)
+			continue;
+		if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+			ivtv_stop_v4l2_encode_stream(s, 0);
+		}
+	}
+}
+
+int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
+{
+	struct ivtv *itv = s->itv;
+	DECLARE_WAITQUEUE(wait, current);
+	int cap_type;
+	int stopmode;
+
+	if (s->vdev == NULL)
+		return -EINVAL;
+
+	/* This function assumes that you are allowed to stop the capture
+	   and that we are actually capturing */
+
+	IVTV_DEBUG_INFO("Stop Capture\n");
+
+	if (s->type == IVTV_DEC_STREAM_TYPE_VOUT)
+		return 0;
+	if (atomic_read(&itv->capturing) == 0)
+		return 0;
+
+	switch (s->type) {
+	case IVTV_ENC_STREAM_TYPE_YUV:
+		cap_type = 1;
+		break;
+	case IVTV_ENC_STREAM_TYPE_PCM:
+		cap_type = 1;
+		break;
+	case IVTV_ENC_STREAM_TYPE_VBI:
+		cap_type = 1;
+		break;
+	case IVTV_ENC_STREAM_TYPE_MPG:
+	default:
+		cap_type = 0;
+		break;
+	}
+
+	/* Stop Capture Mode */
+	if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) {
+		stopmode = 0;
+	} else {
+		stopmode = 1;
+	}
+
+	/* end_capture */
+	/* when: 0 =  end of GOP  1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */
+	ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype);
+
+	if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) {
+		if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) {
+			/* only run these if we're shutting down the last cap */
+			unsigned long duration;
+			unsigned long then = jiffies;
+
+			add_wait_queue(&itv->eos_waitq, &wait);
+
+			set_current_state(TASK_INTERRUPTIBLE);
+
+			/* wait 2s for EOS interrupt */
+			while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) &&
+				time_before(jiffies,
+					    then + msecs_to_jiffies(2000))) {
+				schedule_timeout(msecs_to_jiffies(10));
+			}
+
+			/* To convert jiffies to ms, we must multiply by 1000
+			 * and divide by HZ.  To avoid runtime division, we
+			 * convert this to multiplication by 1000/HZ.
+			 * Since integer division truncates, we get the best
+			 * accuracy if we do a rounding calculation of the constant.
+			 * Think of the case where HZ is 1024.
+			 */
+			duration = ((1000 + HZ / 2) / HZ) * (jiffies - then);
+
+			if (!test_bit(IVTV_F_I_EOS, &itv->i_flags)) {
+				IVTV_DEBUG_WARN("%s: EOS interrupt not received! stopping anyway.\n", s->name);
+				IVTV_DEBUG_WARN("%s: waited %lu ms.\n", s->name, duration);
+			} else {
+				IVTV_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration);
+			}
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&itv->eos_waitq, &wait);
+			set_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+		}
+
+		/* Handle any pending interrupts */
+		ivtv_msleep_timeout(100, 0);
+	}
+
+	atomic_dec(&itv->capturing);
+
+	/* Clear capture and no-read bits */
+	clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+
+	if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
+		ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
+
+	if (atomic_read(&itv->capturing) > 0) {
+		return 0;
+	}
+
+	cx2341x_handler_set_busy(&itv->cxhdl, 0);
+
+	/* Set the following Interrupt mask bits for capture */
+	ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
+	del_timer(&itv->dma_timer);
+
+	/* event notification (off) */
+	if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
+		/* type: 0 = refresh */
+		/* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
+		ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
+		ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
+	}
+
+	/* Raw-passthrough is implied on start. Make sure it's stopped so
+	   the encoder will re-initialize when next started */
+	ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 7);
+
+	wake_up(&s->waitq);
+
+	return 0;
+}
+
+int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
+{
+	static const struct v4l2_event ev = {
+		.type = V4L2_EVENT_EOS,
+	};
+	struct ivtv *itv = s->itv;
+
+	if (s->vdev == NULL)
+		return -EINVAL;
+
+	if (s->type != IVTV_DEC_STREAM_TYPE_YUV && s->type != IVTV_DEC_STREAM_TYPE_MPG)
+		return -EINVAL;
+
+	if (!test_bit(IVTV_F_S_STREAMING, &s->s_flags))
+		return 0;
+
+	IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", (unsigned long long)pts, flags);
+
+	/* Stop Decoder */
+	if (!(flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) || pts) {
+		u32 tmp = 0;
+
+		/* Wait until the decoder is no longer running */
+		if (pts) {
+			ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3,
+				0, (u32)(pts & 0xffffffff), (u32)(pts >> 32));
+		}
+		while (1) {
+			u32 data[CX2341X_MBOX_MAX_DATA];
+			ivtv_vapi_result(itv, data, CX2341X_DEC_GET_XFER_INFO, 0);
+			if (s->q_full.buffers + s->q_dma.buffers == 0) {
+				if (tmp == data[3])
+					break;
+				tmp = data[3];
+			}
+			if (ivtv_msleep_timeout(100, 1))
+				break;
+		}
+	}
+	ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & V4L2_DEC_CMD_STOP_TO_BLACK, 0, 0);
+
+	/* turn off notification of dual/stereo mode change */
+	ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1);
+
+	ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
+	del_timer(&itv->dma_timer);
+
+	clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
+	clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+	ivtv_flush_queues(s);
+
+	/* decoder needs time to settle */
+	ivtv_msleep_timeout(40, 0);
+
+	/* decrement decoding */
+	atomic_dec(&itv->decoding);
+
+	set_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags);
+	wake_up(&itv->event_waitq);
+	v4l2_event_queue(s->vdev, &ev);
+
+	/* wake up wait queues */
+	wake_up(&s->waitq);
+
+	return 0;
+}
+
+int ivtv_passthrough_mode(struct ivtv *itv, int enable)
+{
+	struct ivtv_stream *yuv_stream = &itv->streams[IVTV_ENC_STREAM_TYPE_YUV];
+	struct ivtv_stream *dec_stream = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
+
+	if (yuv_stream->vdev == NULL || dec_stream->vdev == NULL)
+		return -EINVAL;
+
+	IVTV_DEBUG_INFO("ivtv ioctl: Select passthrough mode\n");
+
+	/* Prevent others from starting/stopping streams while we
+	   initiate/terminate passthrough mode */
+	if (enable) {
+		if (itv->output_mode == OUT_PASSTHROUGH) {
+			return 0;
+		}
+		if (ivtv_set_output_mode(itv, OUT_PASSTHROUGH) != OUT_PASSTHROUGH)
+			return -EBUSY;
+
+		/* Fully initialize stream, and then unflag init */
+		set_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags);
+		set_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags);
+
+		/* Setup YUV Decoder */
+		ivtv_setup_v4l2_decode_stream(dec_stream);
+
+		/* Start Decoder */
+		ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1);
+		atomic_inc(&itv->decoding);
+
+		/* Setup capture if not already done */
+		if (atomic_read(&itv->capturing) == 0) {
+			cx2341x_handler_setup(&itv->cxhdl);
+			cx2341x_handler_set_busy(&itv->cxhdl, 1);
+		}
+
+		/* Start Passthrough Mode */
+		ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, 2, 11);
+		atomic_inc(&itv->capturing);
+		return 0;
+	}
+
+	if (itv->output_mode != OUT_PASSTHROUGH)
+		return 0;
+
+	/* Stop Passthrough Mode */
+	ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 11);
+	ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, 1, 0, 0);
+
+	atomic_dec(&itv->capturing);
+	atomic_dec(&itv->decoding);
+	clear_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags);
+	clear_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags);
+	itv->output_mode = OUT_NONE;
+	if (atomic_read(&itv->capturing) == 0)
+		cx2341x_handler_set_busy(&itv->cxhdl, 0);
+
+	return 0;
+}
diff --git a/drivers/media/pci/ivtv/ivtv-streams.h b/drivers/media/pci/ivtv/ivtv-streams.h
new file mode 100644
index 0000000..a653a51
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-streams.h
@@ -0,0 +1,37 @@
+/*
+    init/start/stop/exit stream functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef IVTV_STREAMS_H
+#define IVTV_STREAMS_H
+
+int ivtv_streams_setup(struct ivtv *itv);
+int ivtv_streams_register(struct ivtv *itv);
+void ivtv_streams_cleanup(struct ivtv *itv, int unregister);
+
+/* Capture related */
+int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s);
+int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end);
+int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset);
+int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts);
+
+void ivtv_stop_all_captures(struct ivtv *itv);
+int ivtv_passthrough_mode(struct ivtv *itv, int enable);
+
+#endif
diff --git a/drivers/media/pci/ivtv/ivtv-udma.c b/drivers/media/pci/ivtv/ivtv-udma.c
new file mode 100644
index 0000000..7338cb2
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-udma.c
@@ -0,0 +1,234 @@
+/*
+    User DMA
+
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-udma.h"
+
+void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size)
+{
+	dma_page->uaddr = first & PAGE_MASK;
+	dma_page->offset = first & ~PAGE_MASK;
+	dma_page->tail = 1 + ((first+size-1) & ~PAGE_MASK);
+	dma_page->first = (first & PAGE_MASK) >> PAGE_SHIFT;
+	dma_page->last = ((first+size-1) & PAGE_MASK) >> PAGE_SHIFT;
+	dma_page->page_count = dma_page->last - dma_page->first + 1;
+	if (dma_page->page_count == 1) dma_page->tail -= dma_page->offset;
+}
+
+int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset)
+{
+	int i, offset;
+	unsigned long flags;
+
+	if (map_offset < 0)
+		return map_offset;
+
+	offset = dma_page->offset;
+
+	/* Fill SG Array with new values */
+	for (i = 0; i < dma_page->page_count; i++) {
+		unsigned int len = (i == dma_page->page_count - 1) ?
+			dma_page->tail : PAGE_SIZE - offset;
+
+		if (PageHighMem(dma->map[map_offset])) {
+			void *src;
+
+			if (dma->bouncemap[map_offset] == NULL)
+				dma->bouncemap[map_offset] = alloc_page(GFP_KERNEL);
+			if (dma->bouncemap[map_offset] == NULL)
+				return -1;
+			local_irq_save(flags);
+			src = kmap_atomic(dma->map[map_offset]) + offset;
+			memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len);
+			kunmap_atomic(src);
+			local_irq_restore(flags);
+			sg_set_page(&dma->SGlist[map_offset], dma->bouncemap[map_offset], len, offset);
+		}
+		else {
+			sg_set_page(&dma->SGlist[map_offset], dma->map[map_offset], len, offset);
+		}
+		offset = 0;
+		map_offset++;
+	}
+	return map_offset;
+}
+
+void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) {
+	int i;
+	struct scatterlist *sg;
+
+	for (i = 0, sg = dma->SGlist; i < dma->SG_length; i++, sg++) {
+		dma->SGarray[i].size = cpu_to_le32(sg_dma_len(sg));
+		dma->SGarray[i].src = cpu_to_le32(sg_dma_address(sg));
+		dma->SGarray[i].dst = cpu_to_le32(buffer_offset);
+		buffer_offset += sg_dma_len(sg);
+
+		split -= sg_dma_len(sg);
+		if (split == 0)
+			buffer_offset = buffer_offset_2;
+	}
+}
+
+/* User DMA Buffers */
+void ivtv_udma_alloc(struct ivtv *itv)
+{
+	if (itv->udma.SG_handle == 0) {
+		/* Map DMA Page Array Buffer */
+		itv->udma.SG_handle = pci_map_single(itv->pdev, itv->udma.SGarray,
+			   sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
+		ivtv_udma_sync_for_cpu(itv);
+	}
+}
+
+int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
+		       void __user *userbuf, int size_in_bytes)
+{
+	struct ivtv_dma_page_info user_dma;
+	struct ivtv_user_dma *dma = &itv->udma;
+	int i, err;
+
+	IVTV_DEBUG_DMA("ivtv_udma_setup, dst: 0x%08x\n", (unsigned int)ivtv_dest_addr);
+
+	/* Still in USE */
+	if (dma->SG_length || dma->page_count) {
+		IVTV_DEBUG_WARN("ivtv_udma_setup: SG_length %d page_count %d still full?\n",
+			   dma->SG_length, dma->page_count);
+		return -EBUSY;
+	}
+
+	ivtv_udma_get_page_info(&user_dma, (unsigned long)userbuf, size_in_bytes);
+
+	if (user_dma.page_count <= 0) {
+		IVTV_DEBUG_WARN("ivtv_udma_setup: Error %d page_count from %d bytes %d offset\n",
+			   user_dma.page_count, size_in_bytes, user_dma.offset);
+		return -EINVAL;
+	}
+
+	/* Get user pages for DMA Xfer */
+	down_read(&current->mm->mmap_sem);
+	err = get_user_pages(current, current->mm,
+			user_dma.uaddr, user_dma.page_count, 0, 1, dma->map, NULL);
+	up_read(&current->mm->mmap_sem);
+
+	if (user_dma.page_count != err) {
+		IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
+			   err, user_dma.page_count);
+		if (err >= 0) {
+			for (i = 0; i < err; i++)
+				put_page(dma->map[i]);
+			return -EINVAL;
+		}
+		return err;
+	}
+
+	dma->page_count = user_dma.page_count;
+
+	/* Fill SG List with new values */
+	if (ivtv_udma_fill_sg_list(dma, &user_dma, 0) < 0) {
+		for (i = 0; i < dma->page_count; i++) {
+			put_page(dma->map[i]);
+		}
+		dma->page_count = 0;
+		return -ENOMEM;
+	}
+
+	/* Map SG List */
+	dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
+
+	/* Fill SG Array with new values */
+	ivtv_udma_fill_sg_array (dma, ivtv_dest_addr, 0, -1);
+
+	/* Tag SG Array with Interrupt Bit */
+	dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);
+
+	ivtv_udma_sync_for_device(itv);
+	return dma->page_count;
+}
+
+void ivtv_udma_unmap(struct ivtv *itv)
+{
+	struct ivtv_user_dma *dma = &itv->udma;
+	int i;
+
+	IVTV_DEBUG_INFO("ivtv_unmap_user_dma\n");
+
+	/* Nothing to free */
+	if (dma->page_count == 0)
+		return;
+
+	/* Unmap Scatterlist */
+	if (dma->SG_length) {
+		pci_unmap_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
+		dma->SG_length = 0;
+	}
+	/* sync DMA */
+	ivtv_udma_sync_for_cpu(itv);
+
+	/* Release User Pages */
+	for (i = 0; i < dma->page_count; i++) {
+		put_page(dma->map[i]);
+	}
+	dma->page_count = 0;
+}
+
+void ivtv_udma_free(struct ivtv *itv)
+{
+	int i;
+
+	/* Unmap SG Array */
+	if (itv->udma.SG_handle) {
+		pci_unmap_single(itv->pdev, itv->udma.SG_handle,
+			 sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
+	}
+
+	/* Unmap Scatterlist */
+	if (itv->udma.SG_length) {
+		pci_unmap_sg(itv->pdev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE);
+	}
+
+	for (i = 0; i < IVTV_DMA_SG_OSD_ENT; i++) {
+		if (itv->udma.bouncemap[i])
+			__free_page(itv->udma.bouncemap[i]);
+	}
+}
+
+void ivtv_udma_start(struct ivtv *itv)
+{
+	IVTV_DEBUG_DMA("start UDMA\n");
+	write_reg(itv->udma.SG_handle, IVTV_REG_DECDMAADDR);
+	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
+	set_bit(IVTV_F_I_DMA, &itv->i_flags);
+	set_bit(IVTV_F_I_UDMA, &itv->i_flags);
+	clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags);
+}
+
+void ivtv_udma_prepare(struct ivtv *itv)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&itv->dma_reg_lock, flags);
+	if (!test_bit(IVTV_F_I_DMA, &itv->i_flags))
+		ivtv_udma_start(itv);
+	else
+		set_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags);
+	spin_unlock_irqrestore(&itv->dma_reg_lock, flags);
+}
diff --git a/drivers/media/pci/ivtv/ivtv-udma.h b/drivers/media/pci/ivtv/ivtv-udma.h
new file mode 100644
index 0000000..ee3c9ef
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-udma.h
@@ -0,0 +1,48 @@
+/*
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2006-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef IVTV_UDMA_H
+#define IVTV_UDMA_H
+
+/* User DMA functions */
+void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size);
+int ivtv_udma_fill_sg_list(struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset);
+void ivtv_udma_fill_sg_array(struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split);
+int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
+		       void __user *userbuf, int size_in_bytes);
+void ivtv_udma_unmap(struct ivtv *itv);
+void ivtv_udma_free(struct ivtv *itv);
+void ivtv_udma_alloc(struct ivtv *itv);
+void ivtv_udma_prepare(struct ivtv *itv);
+void ivtv_udma_start(struct ivtv *itv);
+
+static inline void ivtv_udma_sync_for_device(struct ivtv *itv)
+{
+	pci_dma_sync_single_for_device(itv->pdev, itv->udma.SG_handle,
+		sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
+}
+
+static inline void ivtv_udma_sync_for_cpu(struct ivtv *itv)
+{
+	pci_dma_sync_single_for_cpu(itv->pdev, itv->udma.SG_handle,
+		sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
+}
+
+#endif
diff --git a/drivers/media/pci/ivtv/ivtv-vbi.c b/drivers/media/pci/ivtv/ivtv-vbi.c
new file mode 100644
index 0000000..293db80
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-vbi.c
@@ -0,0 +1,549 @@
+/*
+    Vertical Blank Interval support functions
+    Copyright (C) 2004-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-i2c.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-queue.h"
+#include "ivtv-cards.h"
+#include "ivtv-vbi.h"
+
+static void ivtv_set_vps(struct ivtv *itv, int enabled)
+{
+	struct v4l2_sliced_vbi_data data;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return;
+	data.id = V4L2_SLICED_VPS;
+	data.field = 0;
+	data.line = enabled ? 16 : 0;
+	data.data[2] = itv->vbi.vps_payload.data[0];
+	data.data[8] = itv->vbi.vps_payload.data[1];
+	data.data[9] = itv->vbi.vps_payload.data[2];
+	data.data[10] = itv->vbi.vps_payload.data[3];
+	data.data[11] = itv->vbi.vps_payload.data[4];
+	ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data);
+}
+
+static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc)
+{
+	struct v4l2_sliced_vbi_data data;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return;
+	data.id = V4L2_SLICED_CAPTION_525;
+	data.field = 0;
+	data.line = (mode & 1) ? 21 : 0;
+	data.data[0] = cc->odd[0];
+	data.data[1] = cc->odd[1];
+	ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data);
+	data.field = 1;
+	data.line = (mode & 2) ? 21 : 0;
+	data.data[0] = cc->even[0];
+	data.data[1] = cc->even[1];
+	ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data);
+}
+
+static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
+{
+	struct v4l2_sliced_vbi_data data;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return;
+	/* When using a 50 Hz system, always turn on the
+	   wide screen signal with 4x3 ratio as the default.
+	   Turning this signal on and off can confuse certain
+	   TVs. As far as I can tell there is no reason not to
+	   transmit this signal. */
+	if ((itv->std_out & V4L2_STD_625_50) && !enabled) {
+		enabled = 1;
+		mode = 0x08;  /* 4x3 full format */
+	}
+	data.id = V4L2_SLICED_WSS_625;
+	data.field = 0;
+	data.line = enabled ? 23 : 0;
+	data.data[0] = mode & 0xff;
+	data.data[1] = (mode >> 8) & 0xff;
+	ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data);
+}
+
+static int odd_parity(u8 c)
+{
+	c ^= (c >> 4);
+	c ^= (c >> 2);
+	c ^= (c >> 1);
+
+	return c & 1;
+}
+
+static void ivtv_write_vbi_line(struct ivtv *itv,
+				const struct v4l2_sliced_vbi_data *d,
+				struct vbi_cc *cc, int *found_cc)
+{
+	struct vbi_info *vi = &itv->vbi;
+
+	if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) {
+		if (d->field) {
+			cc->even[0] = d->data[0];
+			cc->even[1] = d->data[1];
+		} else {
+			cc->odd[0] = d->data[0];
+			cc->odd[1] = d->data[1];
+		}
+		*found_cc = 1;
+	} else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) {
+		struct vbi_vps vps;
+
+		vps.data[0] = d->data[2];
+		vps.data[1] = d->data[8];
+		vps.data[2] = d->data[9];
+		vps.data[3] = d->data[10];
+		vps.data[4] = d->data[11];
+		if (memcmp(&vps, &vi->vps_payload, sizeof(vps))) {
+			vi->vps_payload = vps;
+			set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
+		}
+	} else if (d->id == V4L2_SLICED_WSS_625 &&
+		   d->line == 23 && d->field == 0) {
+		int wss = d->data[0] | d->data[1] << 8;
+
+		if (vi->wss_payload != wss) {
+			vi->wss_payload = wss;
+			set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
+		}
+	}
+}
+
+static void ivtv_write_vbi_cc_lines(struct ivtv *itv, const struct vbi_cc *cc)
+{
+	struct vbi_info *vi = &itv->vbi;
+
+	if (vi->cc_payload_idx < ARRAY_SIZE(vi->cc_payload)) {
+		memcpy(&vi->cc_payload[vi->cc_payload_idx], cc,
+		       sizeof(struct vbi_cc));
+		vi->cc_payload_idx++;
+		set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
+	}
+}
+
+static void ivtv_write_vbi(struct ivtv *itv,
+			   const struct v4l2_sliced_vbi_data *sliced,
+			   size_t cnt)
+{
+	struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
+	int found_cc = 0;
+	size_t i;
+
+	for (i = 0; i < cnt; i++)
+		ivtv_write_vbi_line(itv, sliced + i, &cc, &found_cc);
+
+	if (found_cc)
+		ivtv_write_vbi_cc_lines(itv, &cc);
+}
+
+ssize_t
+ivtv_write_vbi_from_user(struct ivtv *itv,
+			 const struct v4l2_sliced_vbi_data __user *sliced,
+			 size_t cnt)
+{
+	struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
+	int found_cc = 0;
+	size_t i;
+	struct v4l2_sliced_vbi_data d;
+	ssize_t ret = cnt * sizeof(struct v4l2_sliced_vbi_data);
+
+	for (i = 0; i < cnt; i++) {
+		if (copy_from_user(&d, sliced + i,
+				   sizeof(struct v4l2_sliced_vbi_data))) {
+			ret = -EFAULT;
+			break;
+		}
+		ivtv_write_vbi_line(itv, &d, &cc, &found_cc);
+	}
+
+	if (found_cc)
+		ivtv_write_vbi_cc_lines(itv, &cc);
+
+	return ret;
+}
+
+static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp)
+{
+	int line = 0;
+	int i;
+	u32 linemask[2] = { 0, 0 };
+	unsigned short size;
+	static const u8 mpeg_hdr_data[] = {
+		0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66,
+		0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff,
+		0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80,
+		0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff
+	};
+	const int sd = sizeof(mpeg_hdr_data);	/* start of vbi data */
+	int idx = itv->vbi.frame % IVTV_VBI_FRAMES;
+	u8 *dst = &itv->vbi.sliced_mpeg_data[idx][0];
+
+	for (i = 0; i < lines; i++) {
+		int f, l;
+
+		if (itv->vbi.sliced_data[i].id == 0)
+			continue;
+
+		l = itv->vbi.sliced_data[i].line - 6;
+		f = itv->vbi.sliced_data[i].field;
+		if (f)
+			l += 18;
+		if (l < 32)
+			linemask[0] |= (1 << l);
+		else
+			linemask[1] |= (1 << (l - 32));
+		dst[sd + 12 + line * 43] =
+			ivtv_service2vbi(itv->vbi.sliced_data[i].id);
+		memcpy(dst + sd + 12 + line * 43 + 1, itv->vbi.sliced_data[i].data, 42);
+		line++;
+	}
+	memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data));
+	if (line == 36) {
+		/* All lines are used, so there is no space for the linemask
+		   (the max size of the VBI data is 36 * 43 + 4 bytes).
+		   So in this case we use the magic number 'ITV0'. */
+		memcpy(dst + sd, "ITV0", 4);
+		memcpy(dst + sd + 4, dst + sd + 12, line * 43);
+		size = 4 + ((43 * line + 3) & ~3);
+	} else {
+		memcpy(dst + sd, "itv0", 4);
+		cpu_to_le32s(&linemask[0]);
+		cpu_to_le32s(&linemask[1]);
+		memcpy(dst + sd + 4, &linemask[0], 8);
+		size = 12 + ((43 * line + 3) & ~3);
+	}
+	dst[4+16] = (size + 10) >> 8;
+	dst[5+16] = (size + 10) & 0xff;
+	dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6);
+	dst[10+16] = (pts_stamp >> 22) & 0xff;
+	dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff);
+	dst[12+16] = (pts_stamp >> 7) & 0xff;
+	dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1);
+	itv->vbi.sliced_mpeg_size[idx] = sd + size;
+}
+
+static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p)
+{
+	u32 linemask[2];
+	int i, l, id2;
+	int line = 0;
+
+	if (!memcmp(p, "itv0", 4)) {
+		memcpy(linemask, p + 4, 8);
+		p += 12;
+	} else if (!memcmp(p, "ITV0", 4)) {
+		linemask[0] = 0xffffffff;
+		linemask[1] = 0xf;
+		p += 4;
+	} else {
+		/* unknown VBI data, convert to empty VBI frame */
+		linemask[0] = linemask[1] = 0;
+	}
+	for (i = 0; i < 36; i++) {
+		int err = 0;
+
+		if (i < 32 && !(linemask[0] & (1 << i)))
+			continue;
+		if (i >= 32 && !(linemask[1] & (1 << (i - 32))))
+			continue;
+		id2 = *p & 0xf;
+		switch (id2) {
+		case IVTV_SLICED_TYPE_TELETEXT_B:
+			id2 = V4L2_SLICED_TELETEXT_B;
+			break;
+		case IVTV_SLICED_TYPE_CAPTION_525:
+			id2 = V4L2_SLICED_CAPTION_525;
+			err = !odd_parity(p[1]) || !odd_parity(p[2]);
+			break;
+		case IVTV_SLICED_TYPE_VPS:
+			id2 = V4L2_SLICED_VPS;
+			break;
+		case IVTV_SLICED_TYPE_WSS_625:
+			id2 = V4L2_SLICED_WSS_625;
+			break;
+		default:
+			id2 = 0;
+			break;
+		}
+		if (err == 0) {
+			l = (i < 18) ? i + 6 : i - 18 + 6;
+			itv->vbi.sliced_dec_data[line].line = l;
+			itv->vbi.sliced_dec_data[line].field = i >= 18;
+			itv->vbi.sliced_dec_data[line].id = id2;
+			memcpy(itv->vbi.sliced_dec_data[line].data, p + 1, 42);
+			line++;
+		}
+		p += 43;
+	}
+	while (line < 36) {
+		itv->vbi.sliced_dec_data[line].id = 0;
+		itv->vbi.sliced_dec_data[line].line = 0;
+		itv->vbi.sliced_dec_data[line].field = 0;
+		line++;
+	}
+	return line * sizeof(itv->vbi.sliced_dec_data[0]);
+}
+
+/* Compress raw VBI format, removes leading SAV codes and surplus space after the
+   field.
+   Returns new compressed size. */
+static u32 compress_raw_buf(struct ivtv *itv, u8 *buf, u32 size)
+{
+	u32 line_size = itv->vbi.raw_decoder_line_size;
+	u32 lines = itv->vbi.count;
+	u8 sav1 = itv->vbi.raw_decoder_sav_odd_field;
+	u8 sav2 = itv->vbi.raw_decoder_sav_even_field;
+	u8 *q = buf;
+	u8 *p;
+	int i;
+
+	for (i = 0; i < lines; i++) {
+		p = buf + i * line_size;
+
+		/* Look for SAV code */
+		if (p[0] != 0xff || p[1] || p[2] || (p[3] != sav1 && p[3] != sav2)) {
+			break;
+		}
+		memcpy(q, p + 4, line_size - 4);
+		q += line_size - 4;
+	}
+	return lines * (line_size - 4);
+}
+
+
+/* Compressed VBI format, all found sliced blocks put next to one another
+   Returns new compressed size */
+static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 sav)
+{
+	u32 line_size = itv->vbi.sliced_decoder_line_size;
+	struct v4l2_decode_vbi_line vbi;
+	int i;
+	unsigned lines = 0;
+
+	/* find the first valid line */
+	for (i = 0; i < size; i++, buf++) {
+		if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav)
+			break;
+	}
+
+	size -= i;
+	if (size < line_size) {
+		return line;
+	}
+	for (i = 0; i < size / line_size; i++) {
+		u8 *p = buf + i * line_size;
+
+		/* Look for SAV code  */
+		if (p[0] != 0xff || p[1] || p[2] || p[3] != sav) {
+			continue;
+		}
+		vbi.p = p + 4;
+		v4l2_subdev_call(itv->sd_video, vbi, decode_vbi_line, &vbi);
+		if (vbi.type && !(lines & (1 << vbi.line))) {
+			lines |= 1 << vbi.line;
+			itv->vbi.sliced_data[line].id = vbi.type;
+			itv->vbi.sliced_data[line].field = vbi.is_second_field;
+			itv->vbi.sliced_data[line].line = vbi.line;
+			memcpy(itv->vbi.sliced_data[line].data, vbi.p, 42);
+			line++;
+		}
+	}
+	return line;
+}
+
+void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf,
+			   u64 pts_stamp, int streamtype)
+{
+	u8 *p = (u8 *) buf->buf;
+	u32 size = buf->bytesused;
+	int y;
+
+	/* Raw VBI data */
+	if (streamtype == IVTV_ENC_STREAM_TYPE_VBI && ivtv_raw_vbi(itv)) {
+		u8 type;
+
+		ivtv_buf_swap(buf);
+
+		type = p[3];
+
+		size = buf->bytesused = compress_raw_buf(itv, p, size);
+
+		/* second field of the frame? */
+		if (type == itv->vbi.raw_decoder_sav_even_field) {
+			/* Dirty hack needed for backwards
+			   compatibility of old VBI software. */
+			p += size - 4;
+			memcpy(p, &itv->vbi.frame, 4);
+			itv->vbi.frame++;
+		}
+		return;
+	}
+
+	/* Sliced VBI data with data insertion */
+	if (streamtype == IVTV_ENC_STREAM_TYPE_VBI) {
+		int lines;
+
+		ivtv_buf_swap(buf);
+
+		/* first field */
+		lines = compress_sliced_buf(itv, 0, p, size / 2,
+			itv->vbi.sliced_decoder_sav_odd_field);
+		/* second field */
+		/* experimentation shows that the second half does not always begin
+		   at the exact address. So start a bit earlier (hence 32). */
+		lines = compress_sliced_buf(itv, lines, p + size / 2 - 32, size / 2 + 32,
+			itv->vbi.sliced_decoder_sav_even_field);
+		/* always return at least one empty line */
+		if (lines == 0) {
+			itv->vbi.sliced_data[0].id = 0;
+			itv->vbi.sliced_data[0].line = 0;
+			itv->vbi.sliced_data[0].field = 0;
+			lines = 1;
+		}
+		buf->bytesused = size = lines * sizeof(itv->vbi.sliced_data[0]);
+		memcpy(p, &itv->vbi.sliced_data[0], size);
+
+		if (itv->vbi.insert_mpeg) {
+			copy_vbi_data(itv, lines, pts_stamp);
+		}
+		itv->vbi.frame++;
+		return;
+	}
+
+	/* Sliced VBI re-inserted from an MPEG stream */
+	if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) {
+		/* If the size is not 4-byte aligned, then the starting address
+		   for the swapping is also shifted. After swapping the data the
+		   real start address of the VBI data is exactly 4 bytes after the
+		   original start. It's a bit fiddly but it works like a charm.
+		   Non-4-byte alignment happens when an lseek is done on the input
+		   mpeg file to a non-4-byte aligned position. So on arrival here
+		   the VBI data is also non-4-byte aligned. */
+		int offset = size & 3;
+		int cnt;
+
+		if (offset) {
+			p += 4 - offset;
+		}
+		/* Swap Buffer */
+		for (y = 0; y < size; y += 4) {
+		       swab32s((u32 *)(p + y));
+		}
+
+		cnt = ivtv_convert_ivtv_vbi(itv, p + offset);
+		memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt);
+		buf->bytesused = cnt;
+
+		ivtv_write_vbi(itv, itv->vbi.sliced_dec_data,
+			       cnt / sizeof(itv->vbi.sliced_dec_data[0]));
+		return;
+	}
+}
+
+void ivtv_disable_cc(struct ivtv *itv)
+{
+	struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
+
+	clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
+	ivtv_set_cc(itv, 0, &cc);
+	itv->vbi.cc_payload_idx = 0;
+}
+
+
+void ivtv_vbi_work_handler(struct ivtv *itv)
+{
+	struct vbi_info *vi = &itv->vbi;
+	struct v4l2_sliced_vbi_data data;
+	struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
+
+	/* Lock */
+	if (itv->output_mode == OUT_PASSTHROUGH) {
+		if (itv->is_50hz) {
+			data.id = V4L2_SLICED_WSS_625;
+			data.field = 0;
+
+			if (v4l2_subdev_call(itv->sd_video, vbi, g_vbi_data, &data) == 0) {
+				ivtv_set_wss(itv, 1, data.data[0] & 0xf);
+				vi->wss_missing_cnt = 0;
+			} else if (vi->wss_missing_cnt == 4) {
+				ivtv_set_wss(itv, 1, 0x8);  /* 4x3 full format */
+			} else {
+				vi->wss_missing_cnt++;
+			}
+		}
+		else {
+			int mode = 0;
+
+			data.id = V4L2_SLICED_CAPTION_525;
+			data.field = 0;
+			if (v4l2_subdev_call(itv->sd_video, vbi, g_vbi_data, &data) == 0) {
+				mode |= 1;
+				cc.odd[0] = data.data[0];
+				cc.odd[1] = data.data[1];
+			}
+			data.field = 1;
+			if (v4l2_subdev_call(itv->sd_video, vbi, g_vbi_data, &data) == 0) {
+				mode |= 2;
+				cc.even[0] = data.data[0];
+				cc.even[1] = data.data[1];
+			}
+			if (mode) {
+				vi->cc_missing_cnt = 0;
+				ivtv_set_cc(itv, mode, &cc);
+			} else if (vi->cc_missing_cnt == 4) {
+				ivtv_set_cc(itv, 0, &cc);
+			} else {
+				vi->cc_missing_cnt++;
+			}
+		}
+		return;
+	}
+
+	if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) {
+		ivtv_set_wss(itv, 1, vi->wss_payload & 0xf);
+	}
+
+	if (test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) {
+		if (vi->cc_payload_idx == 0) {
+			clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
+			ivtv_set_cc(itv, 3, &cc);
+		}
+		while (vi->cc_payload_idx) {
+			cc = vi->cc_payload[0];
+
+			memcpy(vi->cc_payload, vi->cc_payload + 1,
+					sizeof(vi->cc_payload) - sizeof(vi->cc_payload[0]));
+			vi->cc_payload_idx--;
+			if (vi->cc_payload_idx && cc.odd[0] == 0x80 && cc.odd[1] == 0x80)
+				continue;
+
+			ivtv_set_cc(itv, 3, &cc);
+			break;
+		}
+	}
+
+	if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) {
+		ivtv_set_vps(itv, 1);
+	}
+}
diff --git a/drivers/media/pci/ivtv/ivtv-vbi.h b/drivers/media/pci/ivtv/ivtv-vbi.h
new file mode 100644
index 0000000..166dd0b
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-vbi.h
@@ -0,0 +1,34 @@
+/*
+    Vertical Blank Interval support functions
+    Copyright (C) 2004-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef IVTV_VBI_H
+#define IVTV_VBI_H
+
+ssize_t
+ivtv_write_vbi_from_user(struct ivtv *itv,
+			 const struct v4l2_sliced_vbi_data __user *sliced,
+			 size_t count);
+void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf,
+			   u64 pts_stamp, int streamtype);
+int ivtv_used_line(struct ivtv *itv, int line, int field);
+void ivtv_disable_cc(struct ivtv *itv);
+void ivtv_set_vbi(unsigned long arg);
+void ivtv_vbi_work_handler(struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/pci/ivtv/ivtv-version.h b/drivers/media/pci/ivtv/ivtv-version.h
new file mode 100644
index 0000000..a20f346
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-version.h
@@ -0,0 +1,26 @@
+/*
+    ivtv driver version information
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef IVTV_VERSION_H
+#define IVTV_VERSION_H
+
+#define IVTV_DRIVER_NAME "ivtv"
+#define IVTV_VERSION "1.4.3"
+
+#endif
diff --git a/drivers/media/pci/ivtv/ivtv-yuv.c b/drivers/media/pci/ivtv/ivtv-yuv.c
new file mode 100644
index 0000000..2ad65eb
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-yuv.c
@@ -0,0 +1,1296 @@
+/*
+    yuv support
+
+    Copyright (C) 2007  Ian Armstrong <ian@iarmst.demon.co.uk>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-udma.h"
+#include "ivtv-yuv.h"
+
+/* YUV buffer offsets */
+const u32 yuv_offset[IVTV_YUV_BUFFERS] = {
+	0x001a8600,
+	0x00240400,
+	0x002d8200,
+	0x00370000,
+	0x00029000,
+	0x000C0E00,
+	0x006B0400,
+	0x00748200
+};
+
+static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
+				  struct ivtv_dma_frame *args)
+{
+	struct ivtv_dma_page_info y_dma;
+	struct ivtv_dma_page_info uv_dma;
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	u8 frame = yi->draw_frame;
+	struct yuv_frame_info *f = &yi->new_frame_info[frame];
+	int i;
+	int y_pages, uv_pages;
+	unsigned long y_buffer_offset, uv_buffer_offset;
+	int y_decode_height, uv_decode_height, y_size;
+
+	y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
+	uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
+
+	y_decode_height = uv_decode_height = f->src_h + f->src_y;
+
+	if (f->offset_y)
+		y_buffer_offset += 720 * 16;
+
+	if (y_decode_height & 15)
+		y_decode_height = (y_decode_height + 16) & ~15;
+
+	if (uv_decode_height & 31)
+		uv_decode_height = (uv_decode_height + 32) & ~31;
+
+	y_size = 720 * y_decode_height;
+
+	/* Still in USE */
+	if (dma->SG_length || dma->page_count) {
+		IVTV_DEBUG_WARN
+		    ("prep_user_dma: SG_length %d page_count %d still full?\n",
+		     dma->SG_length, dma->page_count);
+		return -EBUSY;
+	}
+
+	ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height);
+	ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height);
+
+	/* Get user pages for DMA Xfer */
+	down_read(&current->mm->mmap_sem);
+	y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL);
+	uv_pages = 0; /* silence gcc. value is set and consumed only if: */
+	if (y_pages == y_dma.page_count) {
+		uv_pages = get_user_pages(current, current->mm,
+					  uv_dma.uaddr, uv_dma.page_count, 0, 1,
+					  &dma->map[y_pages], NULL);
+	}
+	up_read(&current->mm->mmap_sem);
+
+	if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) {
+		int rc = -EFAULT;
+
+		if (y_pages == y_dma.page_count) {
+			IVTV_DEBUG_WARN
+				("failed to map uv user pages, returned %d "
+				 "expecting %d\n", uv_pages, uv_dma.page_count);
+
+			if (uv_pages >= 0) {
+				for (i = 0; i < uv_pages; i++)
+					put_page(dma->map[y_pages + i]);
+				rc = -EFAULT;
+			} else {
+				rc = uv_pages;
+			}
+		} else {
+			IVTV_DEBUG_WARN
+				("failed to map y user pages, returned %d "
+				 "expecting %d\n", y_pages, y_dma.page_count);
+		}
+		if (y_pages >= 0) {
+			for (i = 0; i < y_pages; i++)
+				put_page(dma->map[i]);
+			/*
+			 * Inherit the -EFAULT from rc's
+			 * initialization, but allow it to be
+			 * overriden by uv_pages above if it was an
+			 * actual errno.
+			 */
+		} else {
+			rc = y_pages;
+		}
+		return rc;
+	}
+
+	dma->page_count = y_pages + uv_pages;
+
+	/* Fill & map SG List */
+	if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
+		IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
+		for (i = 0; i < dma->page_count; i++) {
+			put_page(dma->map[i]);
+		}
+		dma->page_count = 0;
+		return -ENOMEM;
+	}
+	dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
+
+	/* Fill SG Array with new values */
+	ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
+
+	/* If we've offset the y plane, ensure top area is blanked */
+	if (f->offset_y && yi->blanking_dmaptr) {
+		dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
+		dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr);
+		dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
+		dma->SG_length++;
+	}
+
+	/* Tag SG Array with Interrupt Bit */
+	dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);
+
+	ivtv_udma_sync_for_device(itv);
+	return 0;
+}
+
+/* We rely on a table held in the firmware - Quick check. */
+int ivtv_yuv_filter_check(struct ivtv *itv)
+{
+	int i, y, uv;
+
+	for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) {
+		if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) ||
+		    (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) {
+			IVTV_WARN ("YUV filter table not found in firmware.\n");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
+{
+	u32 i, line;
+
+	/* If any filter is -1, then don't update it */
+	if (h_filter > -1) {
+		if (h_filter > 4)
+			h_filter = 4;
+		i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384);
+		for (line = 0; line < 16; line++) {
+			write_reg(read_dec(i), 0x02804);
+			write_reg(read_dec(i), 0x0281c);
+			i += 4;
+			write_reg(read_dec(i), 0x02808);
+			write_reg(read_dec(i), 0x02820);
+			i += 4;
+			write_reg(read_dec(i), 0x0280c);
+			write_reg(read_dec(i), 0x02824);
+			i += 4;
+			write_reg(read_dec(i), 0x02810);
+			write_reg(read_dec(i), 0x02828);
+			i += 4;
+			write_reg(read_dec(i), 0x02814);
+			write_reg(read_dec(i), 0x0282c);
+			i += 8;
+			write_reg(0, 0x02818);
+			write_reg(0, 0x02830);
+		}
+		IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter);
+	}
+
+	if (v_filter_1 > -1) {
+		if (v_filter_1 > 4)
+			v_filter_1 = 4;
+		i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192);
+		for (line = 0; line < 16; line++) {
+			write_reg(read_dec(i), 0x02900);
+			i += 4;
+			write_reg(read_dec(i), 0x02904);
+			i += 8;
+			write_reg(0, 0x02908);
+		}
+		IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1);
+	}
+
+	if (v_filter_2 > -1) {
+		if (v_filter_2 > 4)
+			v_filter_2 = 4;
+		i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192);
+		for (line = 0; line < 16; line++) {
+			write_reg(read_dec(i), 0x0290c);
+			i += 4;
+			write_reg(read_dec(i), 0x02910);
+			i += 8;
+			write_reg(0, 0x02914);
+		}
+		IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2);
+	}
+}
+
+static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f)
+{
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	u32 reg_2834, reg_2838, reg_283c;
+	u32 reg_2844, reg_2854, reg_285c;
+	u32 reg_2864, reg_2874, reg_2890;
+	u32 reg_2870, reg_2870_base, reg_2870_offset;
+	int x_cutoff;
+	int h_filter;
+	u32 master_width;
+
+	IVTV_DEBUG_WARN
+	    ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
+	     f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x);
+
+	/* How wide is the src image */
+	x_cutoff = f->src_w + f->src_x;
+
+	/* Set the display width */
+	reg_2834 = f->dst_w;
+	reg_2838 = reg_2834;
+
+	/* Set the display position */
+	reg_2890 = f->dst_x;
+
+	/* Index into the image horizontally */
+	reg_2870 = 0;
+
+	/* 2870 is normally fudged to align video coords with osd coords.
+	   If running full screen, it causes an unwanted left shift
+	   Remove the fudge if we almost fill the screen.
+	   Gradually adjust the offset to avoid the video 'snapping'
+	   left/right if it gets dragged through this region.
+	   Only do this if osd is full width. */
+	if (f->vis_w == 720) {
+		if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680))
+			reg_2870 = 10 - (f->tru_x - f->pan_x) / 4;
+		else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660))
+			reg_2870 = (10 + (f->tru_x - f->pan_x) / 2);
+
+		if (f->dst_w >= f->src_w)
+			reg_2870 = reg_2870 << 16 | reg_2870;
+		else
+			reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
+	}
+
+	if (f->dst_w < f->src_w)
+		reg_2870 = 0x000d000e - reg_2870;
+	else
+		reg_2870 = 0x0012000e - reg_2870;
+
+	/* We're also using 2870 to shift the image left (src_x & negative dst_x) */
+	reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19;
+
+	if (f->dst_w >= f->src_w) {
+		x_cutoff &= ~1;
+		master_width = (f->src_w * 0x00200000) / (f->dst_w);
+		if (master_width * f->dst_w != f->src_w * 0x00200000)
+			master_width++;
+		reg_2834 = (reg_2834 << 16) | x_cutoff;
+		reg_2838 = (reg_2838 << 16) | x_cutoff;
+		reg_283c = master_width >> 2;
+		reg_2844 = master_width >> 2;
+		reg_2854 = master_width;
+		reg_285c = master_width >> 1;
+		reg_2864 = master_width >> 1;
+
+		/* We also need to factor in the scaling
+		   (src_w - dst_w) / (src_w / 4) */
+		if (f->dst_w > f->src_w)
+			reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14);
+		else
+			reg_2870_base = 0;
+
+		reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
+		reg_2874 = 0;
+	} else if (f->dst_w < f->src_w / 2) {
+		master_width = (f->src_w * 0x00080000) / f->dst_w;
+		if (master_width * f->dst_w != f->src_w * 0x00080000)
+			master_width++;
+		reg_2834 = (reg_2834 << 16) | x_cutoff;
+		reg_2838 = (reg_2838 << 16) | x_cutoff;
+		reg_283c = master_width >> 2;
+		reg_2844 = master_width >> 1;
+		reg_2854 = master_width;
+		reg_285c = master_width >> 1;
+		reg_2864 = master_width >> 1;
+		reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset;
+		reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16;
+		reg_2874 = 0x00000012;
+	} else {
+		master_width = (f->src_w * 0x00100000) / f->dst_w;
+		if (master_width * f->dst_w != f->src_w * 0x00100000)
+			master_width++;
+		reg_2834 = (reg_2834 << 16) | x_cutoff;
+		reg_2838 = (reg_2838 << 16) | x_cutoff;
+		reg_283c = master_width >> 2;
+		reg_2844 = master_width >> 1;
+		reg_2854 = master_width;
+		reg_285c = master_width >> 1;
+		reg_2864 = master_width >> 1;
+		reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1;
+		reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16;
+		reg_2874 = 0x00000001;
+	}
+
+	/* Select the horizontal filter */
+	if (f->src_w == f->dst_w) {
+		/* An exact size match uses filter 0 */
+		h_filter = 0;
+	} else {
+		/* Figure out which filter to use */
+		h_filter = ((f->src_w << 16) / f->dst_w) >> 15;
+		h_filter = (h_filter >> 1) + (h_filter & 1);
+		/* Only an exact size match can use filter 0 */
+		h_filter += !h_filter;
+	}
+
+	write_reg(reg_2834, 0x02834);
+	write_reg(reg_2838, 0x02838);
+	IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",
+		       yi->reg_2834, reg_2834, yi->reg_2838, reg_2838);
+
+	write_reg(reg_283c, 0x0283c);
+	write_reg(reg_2844, 0x02844);
+
+	IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",
+		       yi->reg_283c, reg_283c, yi->reg_2844, reg_2844);
+
+	write_reg(0x00080514, 0x02840);
+	write_reg(0x00100514, 0x02848);
+	IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",
+		       yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514);
+
+	write_reg(reg_2854, 0x02854);
+	IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",
+		       yi->reg_2854, reg_2854);
+
+	write_reg(reg_285c, 0x0285c);
+	write_reg(reg_2864, 0x02864);
+	IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",
+		       yi->reg_285c, reg_285c, yi->reg_2864, reg_2864);
+
+	write_reg(reg_2874, 0x02874);
+	IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",
+		       yi->reg_2874, reg_2874);
+
+	write_reg(reg_2870, 0x02870);
+	IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",
+		       yi->reg_2870, reg_2870);
+
+	write_reg(reg_2890, 0x02890);
+	IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",
+		       yi->reg_2890, reg_2890);
+
+	/* Only update the filter if we really need to */
+	if (h_filter != yi->h_filter) {
+		ivtv_yuv_filter(itv, h_filter, -1, -1);
+		yi->h_filter = h_filter;
+	}
+}
+
+static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f)
+{
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	u32 master_height;
+	u32 reg_2918, reg_291c, reg_2920, reg_2928;
+	u32 reg_2930, reg_2934, reg_293c;
+	u32 reg_2940, reg_2944, reg_294c;
+	u32 reg_2950, reg_2954, reg_2958, reg_295c;
+	u32 reg_2960, reg_2964, reg_2968, reg_296c;
+	u32 reg_289c;
+	u32 src_major_y, src_minor_y;
+	u32 src_major_uv, src_minor_uv;
+	u32 reg_2964_base, reg_2968_base;
+	int v_filter_1, v_filter_2;
+
+	IVTV_DEBUG_WARN
+	    ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
+	     f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y);
+
+	/* What scaling mode is being used... */
+	IVTV_DEBUG_YUV("Scaling mode Y: %s\n",
+		       f->interlaced_y ? "Interlaced" : "Progressive");
+
+	IVTV_DEBUG_YUV("Scaling mode UV: %s\n",
+		       f->interlaced_uv ? "Interlaced" : "Progressive");
+
+	/* What is the source video being treated as... */
+	IVTV_DEBUG_WARN("Source video: %s\n",
+			f->interlaced ? "Interlaced" : "Progressive");
+
+	/* We offset into the image using two different index methods, so split
+	   the y source coord into two parts. */
+	if (f->src_y < 8) {
+		src_minor_uv = f->src_y;
+		src_major_uv = 0;
+	} else {
+		src_minor_uv = 8;
+		src_major_uv = f->src_y - 8;
+	}
+
+	src_minor_y = src_minor_uv;
+	src_major_y = src_major_uv;
+
+	if (f->offset_y)
+		src_minor_y += 16;
+
+	if (f->interlaced_y)
+		reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y);
+	else
+		reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1);
+
+	if (f->interlaced_uv)
+		reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1);
+	else
+		reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv);
+
+	reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14;
+	reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14;
+
+	if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) {
+		master_height = (f->src_h * 0x00400000) / f->dst_h;
+		if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2)
+			master_height++;
+		reg_2920 = master_height >> 2;
+		reg_2928 = master_height >> 3;
+		reg_2930 = master_height;
+		reg_2940 = master_height >> 1;
+		reg_2964_base >>= 3;
+		reg_2968_base >>= 3;
+		reg_296c = 0x00000000;
+	} else if (f->dst_h >= f->src_h) {
+		master_height = (f->src_h * 0x00400000) / f->dst_h;
+		master_height = (master_height >> 1) + (master_height & 1);
+		reg_2920 = master_height >> 2;
+		reg_2928 = master_height >> 2;
+		reg_2930 = master_height;
+		reg_2940 = master_height >> 1;
+		reg_296c = 0x00000000;
+		if (f->interlaced_y) {
+			reg_2964_base >>= 3;
+		} else {
+			reg_296c++;
+			reg_2964_base >>= 2;
+		}
+		if (f->interlaced_uv)
+			reg_2928 >>= 1;
+		reg_2968_base >>= 3;
+	} else if (f->dst_h >= f->src_h / 2) {
+		master_height = (f->src_h * 0x00200000) / f->dst_h;
+		master_height = (master_height >> 1) + (master_height & 1);
+		reg_2920 = master_height >> 2;
+		reg_2928 = master_height >> 2;
+		reg_2930 = master_height;
+		reg_2940 = master_height;
+		reg_296c = 0x00000101;
+		if (f->interlaced_y) {
+			reg_2964_base >>= 2;
+		} else {
+			reg_296c++;
+			reg_2964_base >>= 1;
+		}
+		if (f->interlaced_uv)
+			reg_2928 >>= 1;
+		reg_2968_base >>= 2;
+	} else {
+		master_height = (f->src_h * 0x00100000) / f->dst_h;
+		master_height = (master_height >> 1) + (master_height & 1);
+		reg_2920 = master_height >> 2;
+		reg_2928 = master_height >> 2;
+		reg_2930 = master_height;
+		reg_2940 = master_height;
+		reg_2964_base >>= 1;
+		reg_2968_base >>= 2;
+		reg_296c = 0x00000102;
+	}
+
+	/* FIXME These registers change depending on scaled / unscaled output
+	   We really need to work out what they should be */
+	if (f->src_h == f->dst_h) {
+		reg_2934 = 0x00020000;
+		reg_293c = 0x00100000;
+		reg_2944 = 0x00040000;
+		reg_294c = 0x000b0000;
+	} else {
+		reg_2934 = 0x00000FF0;
+		reg_293c = 0x00000FF0;
+		reg_2944 = 0x00000FF0;
+		reg_294c = 0x00000FF0;
+	}
+
+	/* The first line to be displayed */
+	reg_2950 = 0x00010000 + src_major_y;
+	if (f->interlaced_y)
+		reg_2950 += 0x00010000;
+	reg_2954 = reg_2950 + 1;
+
+	reg_2958 = 0x00010000 + (src_major_y >> 1);
+	if (f->interlaced_uv)
+		reg_2958 += 0x00010000;
+	reg_295c = reg_2958 + 1;
+
+	if (yi->decode_height == 480)
+		reg_289c = 0x011e0017;
+	else
+		reg_289c = 0x01500017;
+
+	if (f->dst_y < 0)
+		reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1);
+	else
+		reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1);
+
+	/* How much of the source to decode.
+	   Take into account the source offset */
+	reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) |
+		(((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15);
+
+	/* Calculate correct value for register 2964 */
+	if (f->src_h == f->dst_h) {
+		reg_2964 = 1;
+	} else {
+		reg_2964 = 2 + ((f->dst_h << 1) / f->src_h);
+		reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
+	}
+	reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
+	reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);
+
+	/* Okay, we've wasted time working out the correct value,
+	   but if we use it, it fouls the the window alignment.
+	   Fudge it to what we want... */
+	reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16));
+	reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16));
+
+	/* Deviate further from what it should be. I find the flicker headache
+	   inducing so try to reduce it slightly. Leave 2968 as-is otherwise
+	   colours foul. */
+	if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h))
+		reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2);
+
+	if (!f->interlaced_y)
+		reg_2964 -= 0x00010001;
+	if (!f->interlaced_uv)
+		reg_2968 -= 0x00010001;
+
+	reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
+	reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
+
+	/* Select the vertical filter */
+	if (f->src_h == f->dst_h) {
+		/* An exact size match uses filter 0/1 */
+		v_filter_1 = 0;
+		v_filter_2 = 1;
+	} else {
+		/* Figure out which filter to use */
+		v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15;
+		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
+		/* Only an exact size match can use filter 0 */
+		v_filter_1 += !v_filter_1;
+		v_filter_2 = v_filter_1;
+	}
+
+	write_reg(reg_2934, 0x02934);
+	write_reg(reg_293c, 0x0293c);
+	IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",
+		       yi->reg_2934, reg_2934, yi->reg_293c, reg_293c);
+	write_reg(reg_2944, 0x02944);
+	write_reg(reg_294c, 0x0294c);
+	IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",
+		       yi->reg_2944, reg_2944, yi->reg_294c, reg_294c);
+
+	/* Ensure 2970 is 0 (does it ever change ?) */
+/*	write_reg(0,0x02970); */
+/*	IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */
+
+	write_reg(reg_2930, 0x02938);
+	write_reg(reg_2930, 0x02930);
+	IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",
+		       yi->reg_2930, reg_2930, yi->reg_2938, reg_2930);
+
+	write_reg(reg_2928, 0x02928);
+	write_reg(reg_2928 + 0x514, 0x0292C);
+	IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",
+		       yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514);
+
+	write_reg(reg_2920, 0x02920);
+	write_reg(reg_2920 + 0x514, 0x02924);
+	IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",
+		       yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514);
+
+	write_reg(reg_2918, 0x02918);
+	write_reg(reg_291c, 0x0291C);
+	IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",
+		       yi->reg_2918, reg_2918, yi->reg_291c, reg_291c);
+
+	write_reg(reg_296c, 0x0296c);
+	IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",
+		       yi->reg_296c, reg_296c);
+
+	write_reg(reg_2940, 0x02948);
+	write_reg(reg_2940, 0x02940);
+	IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",
+		       yi->reg_2940, reg_2940, yi->reg_2948, reg_2940);
+
+	write_reg(reg_2950, 0x02950);
+	write_reg(reg_2954, 0x02954);
+	IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",
+		       yi->reg_2950, reg_2950, yi->reg_2954, reg_2954);
+
+	write_reg(reg_2958, 0x02958);
+	write_reg(reg_295c, 0x0295C);
+	IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",
+		       yi->reg_2958, reg_2958, yi->reg_295c, reg_295c);
+
+	write_reg(reg_2960, 0x02960);
+	IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",
+		       yi->reg_2960, reg_2960);
+
+	write_reg(reg_2964, 0x02964);
+	write_reg(reg_2968, 0x02968);
+	IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",
+		       yi->reg_2964, reg_2964, yi->reg_2968, reg_2968);
+
+	write_reg(reg_289c, 0x0289c);
+	IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",
+		       yi->reg_289c, reg_289c);
+
+	/* Only update filter 1 if we really need to */
+	if (v_filter_1 != yi->v_filter_1) {
+		ivtv_yuv_filter(itv, -1, v_filter_1, -1);
+		yi->v_filter_1 = v_filter_1;
+	}
+
+	/* Only update filter 2 if we really need to */
+	if (v_filter_2 != yi->v_filter_2) {
+		ivtv_yuv_filter(itv, -1, -1, v_filter_2);
+		yi->v_filter_2 = v_filter_2;
+	}
+}
+
+/* Modify the supplied coordinate information to fit the visible osd area */
+static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f)
+{
+	struct yuv_frame_info *of = &itv->yuv_info.old_frame_info;
+	int osd_crop;
+	u32 osd_scale;
+	u32 yuv_update = 0;
+
+	/* Sorry, but no negative coords for src */
+	if (f->src_x < 0)
+		f->src_x = 0;
+	if (f->src_y < 0)
+		f->src_y = 0;
+
+	/* Can only reduce width down to 1/4 original size */
+	if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) {
+		f->src_x += osd_crop / 2;
+		f->src_w = (f->src_w - osd_crop) & ~3;
+		f->dst_w = f->src_w / 4;
+		f->dst_w += f->dst_w & 1;
+	}
+
+	/* Can only reduce height down to 1/4 original size */
+	if (f->src_h / f->dst_h >= 2) {
+		/* Overflow may be because we're running progressive,
+		   so force mode switch */
+		f->interlaced_y = 1;
+		/* Make sure we're still within limits for interlace */
+		if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) {
+			/* If we reach here we'll have to force the height. */
+			f->src_y += osd_crop / 2;
+			f->src_h = (f->src_h - osd_crop) & ~3;
+			f->dst_h = f->src_h / 4;
+			f->dst_h += f->dst_h & 1;
+		}
+	}
+
+	/* If there's nothing to safe to display, we may as well stop now */
+	if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
+	    (int)f->src_w <= 2 || (int)f->src_h <= 2) {
+		return IVTV_YUV_UPDATE_INVALID;
+	}
+
+	/* Ensure video remains inside OSD area */
+	osd_scale = (f->src_h << 16) / f->dst_h;
+
+	if ((osd_crop = f->pan_y - f->dst_y) > 0) {
+		/* Falls off the upper edge - crop */
+		f->src_y += (osd_scale * osd_crop) >> 16;
+		f->src_h -= (osd_scale * osd_crop) >> 16;
+		f->dst_h -= osd_crop;
+		f->dst_y = 0;
+	} else {
+		f->dst_y -= f->pan_y;
+	}
+
+	if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) {
+		/* Falls off the lower edge - crop */
+		f->dst_h -= osd_crop;
+		f->src_h -= (osd_scale * osd_crop) >> 16;
+	}
+
+	osd_scale = (f->src_w << 16) / f->dst_w;
+
+	if ((osd_crop = f->pan_x - f->dst_x) > 0) {
+		/* Fall off the left edge - crop */
+		f->src_x += (osd_scale * osd_crop) >> 16;
+		f->src_w -= (osd_scale * osd_crop) >> 16;
+		f->dst_w -= osd_crop;
+		f->dst_x = 0;
+	} else {
+		f->dst_x -= f->pan_x;
+	}
+
+	if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) {
+		/* Falls off the right edge - crop */
+		f->dst_w -= osd_crop;
+		f->src_w -= (osd_scale * osd_crop) >> 16;
+	}
+
+	if (itv->yuv_info.track_osd) {
+		/* The OSD can be moved. Track to it */
+		f->dst_x += itv->yuv_info.osd_x_offset;
+		f->dst_y += itv->yuv_info.osd_y_offset;
+	}
+
+	/* Width & height for both src & dst must be even.
+	   Same for coordinates. */
+	f->dst_w &= ~1;
+	f->dst_x &= ~1;
+
+	f->src_w += f->src_x & 1;
+	f->src_x &= ~1;
+
+	f->src_w &= ~1;
+	f->dst_w &= ~1;
+
+	f->dst_h &= ~1;
+	f->dst_y &= ~1;
+
+	f->src_h += f->src_y & 1;
+	f->src_y &= ~1;
+
+	f->src_h &= ~1;
+	f->dst_h &= ~1;
+
+	/* Due to rounding, we may have reduced the output size to <1/4 of
+	   the source. Check again, but this time just resize. Don't change
+	   source coordinates */
+	if (f->dst_w < f->src_w / 4) {
+		f->src_w &= ~3;
+		f->dst_w = f->src_w / 4;
+		f->dst_w += f->dst_w & 1;
+	}
+	if (f->dst_h < f->src_h / 4) {
+		f->src_h &= ~3;
+		f->dst_h = f->src_h / 4;
+		f->dst_h += f->dst_h & 1;
+	}
+
+	/* Check again. If there's nothing to safe to display, stop now */
+	if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
+	    (int)f->src_w <= 2 || (int)f->src_h <= 2) {
+		return IVTV_YUV_UPDATE_INVALID;
+	}
+
+	/* Both x offset & width are linked, so they have to be done together */
+	if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) ||
+	    (of->dst_x != f->dst_x) || (of->src_x != f->src_x) ||
+	    (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) {
+		yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
+	}
+
+	if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) ||
+	    (of->dst_y != f->dst_y) || (of->src_y != f->src_y) ||
+	    (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) ||
+	    (of->lace_mode != f->lace_mode) ||
+	    (of->interlaced_y != f->interlaced_y) ||
+	    (of->interlaced_uv != f->interlaced_uv)) {
+		yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
+	}
+
+	return yuv_update;
+}
+
+/* Update the scaling register to the requested value */
+void ivtv_yuv_work_handler(struct ivtv *itv)
+{
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	struct yuv_frame_info f;
+	int frame = yi->update_frame;
+	u32 yuv_update;
+
+	IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame);
+	f = yi->new_frame_info[frame];
+
+	if (yi->track_osd) {
+		/* Snapshot the osd pan info */
+		f.pan_x = yi->osd_x_pan;
+		f.pan_y = yi->osd_y_pan;
+		f.vis_w = yi->osd_vis_w;
+		f.vis_h = yi->osd_vis_h;
+	} else {
+		/* Not tracking the osd, so assume full screen */
+		f.pan_x = 0;
+		f.pan_y = 0;
+		f.vis_w = 720;
+		f.vis_h = yi->decode_height;
+	}
+
+	/* Calculate the display window coordinates. Exit if nothing left */
+	if (!(yuv_update = ivtv_yuv_window_setup(itv, &f)))
+		return;
+
+	if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
+		write_reg(0x01008080, 0x2898);
+	} else if (yuv_update) {
+		write_reg(0x00108080, 0x2898);
+
+		if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
+			ivtv_yuv_handle_horizontal(itv, &f);
+
+		if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
+			ivtv_yuv_handle_vertical(itv, &f);
+	}
+	yi->old_frame_info = f;
+}
+
+static void ivtv_yuv_init(struct ivtv *itv)
+{
+	struct yuv_playback_info *yi = &itv->yuv_info;
+
+	IVTV_DEBUG_YUV("ivtv_yuv_init\n");
+
+	/* Take a snapshot of the current register settings */
+	yi->reg_2834 = read_reg(0x02834);
+	yi->reg_2838 = read_reg(0x02838);
+	yi->reg_283c = read_reg(0x0283c);
+	yi->reg_2840 = read_reg(0x02840);
+	yi->reg_2844 = read_reg(0x02844);
+	yi->reg_2848 = read_reg(0x02848);
+	yi->reg_2854 = read_reg(0x02854);
+	yi->reg_285c = read_reg(0x0285c);
+	yi->reg_2864 = read_reg(0x02864);
+	yi->reg_2870 = read_reg(0x02870);
+	yi->reg_2874 = read_reg(0x02874);
+	yi->reg_2898 = read_reg(0x02898);
+	yi->reg_2890 = read_reg(0x02890);
+
+	yi->reg_289c = read_reg(0x0289c);
+	yi->reg_2918 = read_reg(0x02918);
+	yi->reg_291c = read_reg(0x0291c);
+	yi->reg_2920 = read_reg(0x02920);
+	yi->reg_2924 = read_reg(0x02924);
+	yi->reg_2928 = read_reg(0x02928);
+	yi->reg_292c = read_reg(0x0292c);
+	yi->reg_2930 = read_reg(0x02930);
+	yi->reg_2934 = read_reg(0x02934);
+	yi->reg_2938 = read_reg(0x02938);
+	yi->reg_293c = read_reg(0x0293c);
+	yi->reg_2940 = read_reg(0x02940);
+	yi->reg_2944 = read_reg(0x02944);
+	yi->reg_2948 = read_reg(0x02948);
+	yi->reg_294c = read_reg(0x0294c);
+	yi->reg_2950 = read_reg(0x02950);
+	yi->reg_2954 = read_reg(0x02954);
+	yi->reg_2958 = read_reg(0x02958);
+	yi->reg_295c = read_reg(0x0295c);
+	yi->reg_2960 = read_reg(0x02960);
+	yi->reg_2964 = read_reg(0x02964);
+	yi->reg_2968 = read_reg(0x02968);
+	yi->reg_296c = read_reg(0x0296c);
+	yi->reg_2970 = read_reg(0x02970);
+
+	yi->v_filter_1 = -1;
+	yi->v_filter_2 = -1;
+	yi->h_filter = -1;
+
+	/* Set some valid size info */
+	yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
+	yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
+
+	/* Bit 2 of reg 2878 indicates current decoder output format
+	   0 : NTSC    1 : PAL */
+	if (read_reg(0x2878) & 4)
+		yi->decode_height = 576;
+	else
+		yi->decode_height = 480;
+
+	if (!itv->osd_info) {
+		yi->osd_vis_w = 720 - yi->osd_x_offset;
+		yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
+	} else {
+		/* If no visible size set, assume full size */
+		if (!yi->osd_vis_w)
+			yi->osd_vis_w = 720 - yi->osd_x_offset;
+
+		if (!yi->osd_vis_h) {
+			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
+		} else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
+			/* If output video standard has changed, requested height may
+			   not be legal */
+			IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
+					yi->osd_vis_h + yi->osd_y_offset,
+					yi->decode_height);
+			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
+		}
+	}
+
+	/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
+	yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);
+	if (yi->blanking_ptr) {
+		yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
+	} else {
+		yi->blanking_dmaptr = 0;
+		IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
+	}
+
+	/* Enable YUV decoder output */
+	write_reg_sync(0x01, IVTV_REG_VDM);
+
+	set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
+	atomic_set(&yi->next_dma_frame, 0);
+}
+
+/* Get next available yuv buffer on PVR350 */
+static void ivtv_yuv_next_free(struct ivtv *itv)
+{
+	int draw, display;
+	struct yuv_playback_info *yi = &itv->yuv_info;
+
+	if (atomic_read(&yi->next_dma_frame) == -1)
+		ivtv_yuv_init(itv);
+
+	draw = atomic_read(&yi->next_fill_frame);
+	display = atomic_read(&yi->next_dma_frame);
+
+	if (display > draw)
+		display -= IVTV_YUV_BUFFERS;
+
+	if (draw - display >= yi->max_frames_buffered)
+		draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;
+	else
+		yi->new_frame_info[draw].update = 0;
+
+	yi->draw_frame = draw;
+}
+
+/* Set up frame according to ivtv_dma_frame parameters */
+static void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+{
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	u8 frame = yi->draw_frame;
+	u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS;
+	struct yuv_frame_info *nf = &yi->new_frame_info[frame];
+	struct yuv_frame_info *of = &yi->new_frame_info[last_frame];
+	int lace_threshold = yi->lace_threshold;
+
+	/* Preserve old update flag in case we're overwriting a queued frame */
+	int update = nf->update;
+
+	/* Take a snapshot of the yuv coordinate information */
+	nf->src_x = args->src.left;
+	nf->src_y = args->src.top;
+	nf->src_w = args->src.width;
+	nf->src_h = args->src.height;
+	nf->dst_x = args->dst.left;
+	nf->dst_y = args->dst.top;
+	nf->dst_w = args->dst.width;
+	nf->dst_h = args->dst.height;
+	nf->tru_x = args->dst.left;
+	nf->tru_w = args->src_width;
+	nf->tru_h = args->src_height;
+
+	/* Are we going to offset the Y plane */
+	nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;
+
+	nf->update = 0;
+	nf->interlaced_y = 0;
+	nf->interlaced_uv = 0;
+	nf->delay = 0;
+	nf->sync_field = 0;
+	nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK;
+
+	if (lace_threshold < 0)
+		lace_threshold = yi->decode_height - 1;
+
+	/* Work out the lace settings */
+	switch (nf->lace_mode) {
+	case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
+		nf->interlaced = 0;
+		if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021))
+			nf->interlaced_y = 0;
+		else
+			nf->interlaced_y = 1;
+
+		if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
+			nf->interlaced_uv = 0;
+		else
+			nf->interlaced_uv = 1;
+		break;
+
+	case IVTV_YUV_MODE_AUTO:
+		if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) {
+			nf->interlaced = 0;
+			if ((nf->tru_h < 512) ||
+			    (nf->tru_h > 576 && nf->tru_h < 1021) ||
+			    (nf->tru_w > 720 && nf->tru_h < 1021))
+				nf->interlaced_y = 0;
+			else
+				nf->interlaced_y = 1;
+			if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
+				nf->interlaced_uv = 0;
+			else
+				nf->interlaced_uv = 1;
+		} else {
+			nf->interlaced = 1;
+			nf->interlaced_y = 1;
+			nf->interlaced_uv = 1;
+		}
+		break;
+
+	case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
+	default:
+		nf->interlaced = 1;
+		nf->interlaced_y = 1;
+		nf->interlaced_uv = 1;
+		break;
+	}
+
+	if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) {
+		yi->old_frame_info_args = *nf;
+		nf->update = 1;
+		IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame);
+	}
+
+	nf->update |= update;
+	nf->sync_field = yi->lace_sync_field;
+	nf->delay = nf->sync_field != of->sync_field;
+}
+
+/* Frame is complete & ready for display */
+void ivtv_yuv_frame_complete(struct ivtv *itv)
+{
+	atomic_set(&itv->yuv_info.next_fill_frame,
+			(itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
+}
+
+static int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+{
+	DEFINE_WAIT(wait);
+	int rc = 0;
+	int got_sig = 0;
+	/* DMA the frame */
+	mutex_lock(&itv->udma.lock);
+
+	if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {
+		mutex_unlock(&itv->udma.lock);
+		return rc;
+	}
+
+	ivtv_udma_prepare(itv);
+	prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
+	/* if no UDMA is pending and no UDMA is in progress, then the DMA
+	   is finished */
+	while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) ||
+	       test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
+		/* don't interrupt if the DMA is in progress but break off
+		   a still pending DMA. */
+		got_sig = signal_pending(current);
+		if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
+			break;
+		got_sig = 0;
+		schedule();
+	}
+	finish_wait(&itv->dma_waitq, &wait);
+
+	/* Unmap Last DMA Xfer */
+	ivtv_udma_unmap(itv);
+
+	if (got_sig) {
+		IVTV_DEBUG_INFO("User stopped YUV UDMA\n");
+		mutex_unlock(&itv->udma.lock);
+		return -EINTR;
+	}
+
+	ivtv_yuv_frame_complete(itv);
+
+	mutex_unlock(&itv->udma.lock);
+	return rc;
+}
+
+/* Setup frame according to V4L2 parameters */
+void ivtv_yuv_setup_stream_frame(struct ivtv *itv)
+{
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	struct ivtv_dma_frame dma_args;
+
+	ivtv_yuv_next_free(itv);
+
+	/* Copy V4L2 parameters to an ivtv_dma_frame struct... */
+	dma_args.y_source = NULL;
+	dma_args.uv_source = NULL;
+	dma_args.src.left = 0;
+	dma_args.src.top = 0;
+	dma_args.src.width = yi->v4l2_src_w;
+	dma_args.src.height = yi->v4l2_src_h;
+	dma_args.dst = yi->main_rect;
+	dma_args.src_width = yi->v4l2_src_w;
+	dma_args.src_height = yi->v4l2_src_h;
+
+	/* ... and use the same setup routine as ivtv_yuv_prep_frame */
+	ivtv_yuv_setup_frame(itv, &dma_args);
+
+	if (!itv->dma_data_req_offset)
+		itv->dma_data_req_offset = yuv_offset[yi->draw_frame];
+}
+
+/* Attempt to dma a frame from a user buffer */
+int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src)
+{
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	struct ivtv_dma_frame dma_args;
+	int res;
+
+	ivtv_yuv_setup_stream_frame(itv);
+
+	/* We only need to supply source addresses for this */
+	dma_args.y_source = src;
+	dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);
+	/* Wait for frame DMA. Note that serialize_lock is locked,
+	   so to allow other processes to access the driver while
+	   we are waiting unlock first and later lock again. */
+	mutex_unlock(&itv->serialize_lock);
+	res = ivtv_yuv_udma_frame(itv, &dma_args);
+	mutex_lock(&itv->serialize_lock);
+	return res;
+}
+
+/* IVTV_IOC_DMA_FRAME ioctl handler */
+int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+{
+	int res;
+
+/*	IVTV_DEBUG_INFO("yuv_prep_frame\n"); */
+	ivtv_yuv_next_free(itv);
+	ivtv_yuv_setup_frame(itv, args);
+	/* Wait for frame DMA. Note that serialize_lock is locked,
+	   so to allow other processes to access the driver while
+	   we are waiting unlock first and later lock again. */
+	mutex_unlock(&itv->serialize_lock);
+	res = ivtv_yuv_udma_frame(itv, args);
+	mutex_lock(&itv->serialize_lock);
+	return res;
+}
+
+void ivtv_yuv_close(struct ivtv *itv)
+{
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	int h_filter, v_filter_1, v_filter_2;
+
+	IVTV_DEBUG_YUV("ivtv_yuv_close\n");
+	mutex_unlock(&itv->serialize_lock);
+	ivtv_waitq(&itv->vsync_waitq);
+	mutex_lock(&itv->serialize_lock);
+
+	yi->running = 0;
+	atomic_set(&yi->next_dma_frame, -1);
+	atomic_set(&yi->next_fill_frame, 0);
+
+	/* Reset registers we have changed so mpeg playback works */
+
+	/* If we fully restore this register, the display may remain active.
+	   Restore, but set one bit to blank the video. Firmware will always
+	   clear this bit when needed, so not a problem. */
+	write_reg(yi->reg_2898 | 0x01000000, 0x2898);
+
+	write_reg(yi->reg_2834, 0x02834);
+	write_reg(yi->reg_2838, 0x02838);
+	write_reg(yi->reg_283c, 0x0283c);
+	write_reg(yi->reg_2840, 0x02840);
+	write_reg(yi->reg_2844, 0x02844);
+	write_reg(yi->reg_2848, 0x02848);
+	write_reg(yi->reg_2854, 0x02854);
+	write_reg(yi->reg_285c, 0x0285c);
+	write_reg(yi->reg_2864, 0x02864);
+	write_reg(yi->reg_2870, 0x02870);
+	write_reg(yi->reg_2874, 0x02874);
+	write_reg(yi->reg_2890, 0x02890);
+	write_reg(yi->reg_289c, 0x0289c);
+
+	write_reg(yi->reg_2918, 0x02918);
+	write_reg(yi->reg_291c, 0x0291c);
+	write_reg(yi->reg_2920, 0x02920);
+	write_reg(yi->reg_2924, 0x02924);
+	write_reg(yi->reg_2928, 0x02928);
+	write_reg(yi->reg_292c, 0x0292c);
+	write_reg(yi->reg_2930, 0x02930);
+	write_reg(yi->reg_2934, 0x02934);
+	write_reg(yi->reg_2938, 0x02938);
+	write_reg(yi->reg_293c, 0x0293c);
+	write_reg(yi->reg_2940, 0x02940);
+	write_reg(yi->reg_2944, 0x02944);
+	write_reg(yi->reg_2948, 0x02948);
+	write_reg(yi->reg_294c, 0x0294c);
+	write_reg(yi->reg_2950, 0x02950);
+	write_reg(yi->reg_2954, 0x02954);
+	write_reg(yi->reg_2958, 0x02958);
+	write_reg(yi->reg_295c, 0x0295c);
+	write_reg(yi->reg_2960, 0x02960);
+	write_reg(yi->reg_2964, 0x02964);
+	write_reg(yi->reg_2968, 0x02968);
+	write_reg(yi->reg_296c, 0x0296c);
+	write_reg(yi->reg_2970, 0x02970);
+
+	/* Prepare to restore filters */
+
+	/* First the horizontal filter */
+	if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) {
+		/* An exact size match uses filter 0 */
+		h_filter = 0;
+	} else {
+		/* Figure out which filter to use */
+		h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15;
+		h_filter = (h_filter >> 1) + (h_filter & 1);
+		/* Only an exact size match can use filter 0. */
+		h_filter += !h_filter;
+	}
+
+	/* Now the vertical filter */
+	if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) {
+		/* An exact size match uses filter 0/1 */
+		v_filter_1 = 0;
+		v_filter_2 = 1;
+	} else {
+		/* Figure out which filter to use */
+		v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15;
+		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
+		/* Only an exact size match can use filter 0 */
+		v_filter_1 += !v_filter_1;
+		v_filter_2 = v_filter_1;
+	}
+
+	/* Now restore the filters */
+	ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2);
+
+	/* and clear a few registers */
+	write_reg(0, 0x02814);
+	write_reg(0, 0x0282c);
+	write_reg(0, 0x02904);
+	write_reg(0, 0x02910);
+
+	/* Release the blanking buffer */
+	if (yi->blanking_ptr) {
+		kfree(yi->blanking_ptr);
+		yi->blanking_ptr = NULL;
+		pci_unmap_single(itv->pdev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
+	}
+
+	/* Invalidate the old dimension information */
+	yi->old_frame_info.src_w = 0;
+	yi->old_frame_info.src_h = 0;
+	yi->old_frame_info_args.src_w = 0;
+	yi->old_frame_info_args.src_h = 0;
+
+	/* All done. */
+	clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
+}
diff --git a/drivers/media/pci/ivtv/ivtv-yuv.h b/drivers/media/pci/ivtv/ivtv-yuv.h
new file mode 100644
index 0000000..ca5173f
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-yuv.h
@@ -0,0 +1,44 @@
+/*
+    yuv support
+
+    Copyright (C) 2007  Ian Armstrong <ian@iarmst.demon.co.uk>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef IVTV_YUV_H
+#define IVTV_YUV_H
+
+#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400	/* Offset to UV Buffer */
+
+/* Offset to filter table in firmware */
+#define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8
+#define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358
+
+#define IVTV_YUV_UPDATE_HORIZONTAL  0x01
+#define IVTV_YUV_UPDATE_VERTICAL    0x02
+#define IVTV_YUV_UPDATE_INVALID     0x04
+
+extern const u32 yuv_offset[IVTV_YUV_BUFFERS];
+
+int ivtv_yuv_filter_check(struct ivtv *itv);
+void ivtv_yuv_setup_stream_frame(struct ivtv *itv);
+int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src);
+void ivtv_yuv_frame_complete(struct ivtv *itv);
+int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args);
+void ivtv_yuv_close(struct ivtv *itv);
+void ivtv_yuv_work_handler(struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c
new file mode 100644
index 0000000..05b94aa
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtvfb.c
@@ -0,0 +1,1317 @@
+/*
+    On Screen Display cx23415 Framebuffer driver
+
+    This module presents the cx23415 OSD (onscreen display) framebuffer memory
+    as a standard Linux /dev/fb style framebuffer device. The framebuffer has
+    support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp
+    mode, there is a choice of a three color depths (12, 15 or 16 bits), but no
+    local alpha. The colorspace is selectable between rgb & yuv.
+    Depending on the TV standard configured in the ivtv module at load time,
+    the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp.
+    Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL)
+    or 59.94 (NTSC)
+
+    Copyright (c) 2003 Matt T. Yourst <yourst@yourst.com>
+
+    Derived from drivers/video/vesafb.c
+    Portions (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+
+    2.6 kernel port:
+    Copyright (C) 2004 Matthias Badaire
+
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+
+    Copyright (C) 2006  Ian Armstrong <ian@iarmst.demon.co.uk>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fb.h>
+#include <linux/ivtvfb.h>
+#include <linux/slab.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "ivtv-driver.h"
+#include "ivtv-cards.h"
+#include "ivtv-i2c.h"
+#include "ivtv-udma.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-firmware.h"
+
+/* card parameters */
+static int ivtvfb_card_id = -1;
+static int ivtvfb_debug = 0;
+static bool osd_laced;
+static int osd_depth;
+static int osd_upper;
+static int osd_left;
+static int osd_yres;
+static int osd_xres;
+
+module_param(ivtvfb_card_id, int, 0444);
+module_param_named(debug,ivtvfb_debug, int, 0644);
+module_param(osd_laced, bool, 0444);
+module_param(osd_depth, int, 0444);
+module_param(osd_upper, int, 0444);
+module_param(osd_left, int, 0444);
+module_param(osd_yres, int, 0444);
+module_param(osd_xres, int, 0444);
+
+MODULE_PARM_DESC(ivtvfb_card_id,
+		 "Only use framebuffer of the specified ivtv card (0-31)\n"
+		 "\t\t\tdefault -1: initialize all available framebuffers");
+
+MODULE_PARM_DESC(debug,
+		 "Debug level (bitmask). Default: errors only\n"
+		 "\t\t\t(debug = 3 gives full debugging)");
+
+/* Why upper, left, xres, yres, depth, laced ? To match terminology used
+   by fbset.
+   Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */
+
+MODULE_PARM_DESC(osd_laced,
+		 "Interlaced mode\n"
+		 "\t\t\t0=off\n"
+		 "\t\t\t1=on\n"
+		 "\t\t\tdefault off");
+
+MODULE_PARM_DESC(osd_depth,
+		 "Bits per pixel - 8, 16, 32\n"
+		 "\t\t\tdefault 8");
+
+MODULE_PARM_DESC(osd_upper,
+		 "Vertical start position\n"
+		 "\t\t\tdefault 0 (Centered)");
+
+MODULE_PARM_DESC(osd_left,
+		 "Horizontal start position\n"
+		 "\t\t\tdefault 0 (Centered)");
+
+MODULE_PARM_DESC(osd_yres,
+		 "Display height\n"
+		 "\t\t\tdefault 480 (PAL)\n"
+		 "\t\t\t        400 (NTSC)");
+
+MODULE_PARM_DESC(osd_xres,
+		 "Display width\n"
+		 "\t\t\tdefault 640");
+
+MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
+MODULE_LICENSE("GPL");
+
+/* --------------------------------------------------------------------- */
+
+#define IVTVFB_DBGFLG_WARN  (1 << 0)
+#define IVTVFB_DBGFLG_INFO  (1 << 1)
+
+#define IVTVFB_DEBUG(x, type, fmt, args...) \
+	do { \
+		if ((x) & ivtvfb_debug) \
+			printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->instance , ## args); \
+	} while (0)
+#define IVTVFB_DEBUG_WARN(fmt, args...)  IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args)
+#define IVTVFB_DEBUG_INFO(fmt, args...)  IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args)
+
+/* Standard kernel messages */
+#define IVTVFB_ERR(fmt, args...)   printk(KERN_ERR  "ivtvfb%d: " fmt, itv->instance , ## args)
+#define IVTVFB_WARN(fmt, args...)  printk(KERN_WARNING  "ivtvfb%d: " fmt, itv->instance , ## args)
+#define IVTVFB_INFO(fmt, args...)  printk(KERN_INFO "ivtvfb%d: " fmt, itv->instance , ## args)
+
+/* --------------------------------------------------------------------- */
+
+#define IVTV_OSD_MAX_WIDTH  720
+#define IVTV_OSD_MAX_HEIGHT 576
+
+#define IVTV_OSD_BPP_8      0x00
+#define IVTV_OSD_BPP_16_444 0x03
+#define IVTV_OSD_BPP_16_555 0x02
+#define IVTV_OSD_BPP_16_565 0x01
+#define IVTV_OSD_BPP_32     0x04
+
+struct osd_info {
+	/* Physical base address */
+	unsigned long video_pbase;
+	/* Relative base address (relative to start of decoder memory) */
+	u32 video_rbase;
+	/* Mapped base address */
+	volatile char __iomem *video_vbase;
+	/* Buffer size */
+	u32 video_buffer_size;
+
+#ifdef CONFIG_MTRR
+	/* video_base rounded down as required by hardware MTRRs */
+	unsigned long fb_start_aligned_physaddr;
+	/* video_base rounded up as required by hardware MTRRs */
+	unsigned long fb_end_aligned_physaddr;
+#endif
+
+	/* Store the buffer offset */
+	int set_osd_coords_x;
+	int set_osd_coords_y;
+
+	/* Current dimensions (NOT VISIBLE SIZE!) */
+	int display_width;
+	int display_height;
+	int display_byte_stride;
+
+	/* Current bits per pixel */
+	int bits_per_pixel;
+	int bytes_per_pixel;
+
+	/* Frame buffer stuff */
+	struct fb_info ivtvfb_info;
+	struct fb_var_screeninfo ivtvfb_defined;
+	struct fb_fix_screeninfo ivtvfb_fix;
+
+	/* Used for a warm start */
+	struct fb_var_screeninfo fbvar_cur;
+	int blank_cur;
+	u32 palette_cur[256];
+	u32 pan_cur;
+};
+
+struct ivtv_osd_coords {
+	unsigned long offset;
+	unsigned long max_offset;
+	int pixel_stride;
+	int lines;
+	int x;
+	int y;
+};
+
+/* --------------------------------------------------------------------- */
+
+/* ivtv API calls for framebuffer related support */
+
+static int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
+				       u32 *fblength)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	int rc;
+
+	ivtv_firmware_check(itv, "ivtvfb_get_framebuffer");
+	rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
+	*fbbase = data[0];
+	*fblength = data[1];
+	return rc;
+}
+
+static int ivtvfb_get_osd_coords(struct ivtv *itv,
+				      struct ivtv_osd_coords *osd)
+{
+	struct osd_info *oi = itv->osd_info;
+	u32 data[CX2341X_MBOX_MAX_DATA];
+
+	ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0);
+
+	osd->offset = data[0] - oi->video_rbase;
+	osd->max_offset = oi->display_width * oi->display_height * 4;
+	osd->pixel_stride = data[1];
+	osd->lines = data[2];
+	osd->x = data[3];
+	osd->y = data[4];
+	return 0;
+}
+
+static int ivtvfb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd)
+{
+	struct osd_info *oi = itv->osd_info;
+
+	oi->display_width = osd->pixel_stride;
+	oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel;
+	oi->set_osd_coords_x += osd->x;
+	oi->set_osd_coords_y = osd->y;
+
+	return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5,
+			osd->offset + oi->video_rbase,
+			osd->pixel_stride,
+			osd->lines, osd->x, osd->y);
+}
+
+static int ivtvfb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
+{
+	int osd_height_limit = itv->is_out_50hz ? 576 : 480;
+
+	/* Only fail if resolution too high, otherwise fudge the start coords. */
+	if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
+		return -EINVAL;
+
+	/* Ensure we don't exceed display limits */
+	if (ivtv_window->top + ivtv_window->height > osd_height_limit) {
+		IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n",
+			ivtv_window->top, ivtv_window->height);
+		ivtv_window->top = osd_height_limit - ivtv_window->height;
+	}
+
+	if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) {
+		IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n",
+			ivtv_window->left, ivtv_window->width);
+		ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width;
+	}
+
+	/* Set the OSD origin */
+	write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04);
+
+	/* How much to display */
+	write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08);
+
+	/* Pass this info back the yuv handler */
+	itv->yuv_info.osd_vis_w = ivtv_window->width;
+	itv->yuv_info.osd_vis_h = ivtv_window->height;
+	itv->yuv_info.osd_x_offset = ivtv_window->left;
+	itv->yuv_info.osd_y_offset = ivtv_window->top;
+
+	return 0;
+}
+
+static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
+				  unsigned long ivtv_dest_addr, void __user *userbuf,
+				  int size_in_bytes)
+{
+	DEFINE_WAIT(wait);
+	int got_sig = 0;
+
+	mutex_lock(&itv->udma.lock);
+	/* Map User DMA */
+	if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
+		mutex_unlock(&itv->udma.lock);
+		IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, "
+			       "Error with get_user_pages: %d bytes, %d pages returned\n",
+			       size_in_bytes, itv->udma.page_count);
+
+		/* get_user_pages must have failed completely */
+		return -EIO;
+	}
+
+	IVTVFB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n",
+		       size_in_bytes, itv->udma.page_count);
+
+	ivtv_udma_prepare(itv);
+	prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
+	/* if no UDMA is pending and no UDMA is in progress, then the DMA
+	   is finished */
+	while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) ||
+	       test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
+		/* don't interrupt if the DMA is in progress but break off
+		   a still pending DMA. */
+		got_sig = signal_pending(current);
+		if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
+			break;
+		got_sig = 0;
+		schedule();
+	}
+	finish_wait(&itv->dma_waitq, &wait);
+
+	/* Unmap Last DMA Xfer */
+	ivtv_udma_unmap(itv);
+	mutex_unlock(&itv->udma.lock);
+	if (got_sig) {
+		IVTV_DEBUG_INFO("User stopped OSD\n");
+		return -EINTR;
+	}
+
+	return 0;
+}
+
+static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
+			      unsigned long dest_offset, int count)
+{
+	DEFINE_WAIT(wait);
+	struct osd_info *oi = itv->osd_info;
+
+	/* Nothing to do */
+	if (count == 0) {
+		IVTVFB_DEBUG_WARN("ivtvfb_prep_frame: Nothing to do. count = 0\n");
+		return -EINVAL;
+	}
+
+	/* Check Total FB Size */
+	if ((dest_offset + count) > oi->video_buffer_size) {
+		IVTVFB_WARN("ivtvfb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
+			dest_offset + count, oi->video_buffer_size);
+		return -E2BIG;
+	}
+
+	/* Not fatal, but will have undesirable results */
+	if ((unsigned long)source & 3)
+		IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
+			(unsigned long)source);
+
+	if (dest_offset & 3)
+		IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
+
+	if (count & 3)
+		IVTVFB_WARN("ivtvfb_prep_frame: Count not a multiple of 4 (%d)\n", count);
+
+	/* Check Source */
+	if (!access_ok(VERIFY_READ, source + dest_offset, count)) {
+		IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n",
+			(unsigned long)source);
+
+		IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
+			dest_offset, (unsigned long)source,
+			count);
+		return -EINVAL;
+	}
+
+	/* OSD Address to send DMA to */
+	dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase;
+
+	/* Fill Buffers */
+	return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count);
+}
+
+static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
+						size_t count, loff_t *ppos)
+{
+	unsigned long p = *ppos;
+	void *dst;
+	int err = 0;
+	int dma_err;
+	unsigned long total_size;
+	struct ivtv *itv = (struct ivtv *) info->par;
+	unsigned long dma_offset =
+			IVTV_DECODER_OFFSET + itv->osd_info->video_rbase;
+	unsigned long dma_size;
+	u16 lead = 0, tail = 0;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return -EPERM;
+
+	total_size = info->screen_size;
+
+	if (total_size == 0)
+		total_size = info->fix.smem_len;
+
+	if (p > total_size)
+		return -EFBIG;
+
+	if (count > total_size) {
+		err = -EFBIG;
+		count = total_size;
+	}
+
+	if (count + p > total_size) {
+		if (!err)
+			err = -ENOSPC;
+		count = total_size - p;
+	}
+
+	dst = (void __force *) (info->screen_base + p);
+
+	if (info->fbops->fb_sync)
+		info->fbops->fb_sync(info);
+
+	/* If transfer size > threshold and both src/dst
+	addresses are aligned, use DMA */
+	if (count >= 4096 &&
+	    ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) {
+		/* Odd address = can't DMA. Align */
+		if ((unsigned long)dst & 3) {
+			lead = 4 - ((unsigned long)dst & 3);
+			if (copy_from_user(dst, buf, lead))
+				return -EFAULT;
+			buf += lead;
+			dst += lead;
+		}
+		/* DMA resolution is 32 bits */
+		if ((count - lead) & 3)
+			tail = (count - lead) & 3;
+		/* DMA the data */
+		dma_size = count - lead - tail;
+		dma_err = ivtvfb_prep_dec_dma_to_device(itv,
+		       p + lead + dma_offset, (void __user *)buf, dma_size);
+		if (dma_err)
+			return dma_err;
+		dst += dma_size;
+		buf += dma_size;
+		/* Copy any leftover data */
+		if (tail && copy_from_user(dst, buf, tail))
+			return -EFAULT;
+	} else if (copy_from_user(dst, buf, count)) {
+		return -EFAULT;
+	}
+
+	if  (!err)
+		*ppos += count;
+
+	return (err) ? err : count;
+}
+
+static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+{
+	DEFINE_WAIT(wait);
+	struct ivtv *itv = (struct ivtv *)info->par;
+	int rc = 0;
+
+	switch (cmd) {
+		case FBIOGET_VBLANK: {
+			struct fb_vblank vblank;
+			u32 trace;
+
+			memset(&vblank, 0, sizeof(struct fb_vblank));
+
+			vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
+					FB_VBLANK_HAVE_VSYNC;
+			trace = read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16;
+			if (itv->is_out_50hz && trace > 312)
+				trace -= 312;
+			else if (itv->is_out_60hz && trace > 262)
+				trace -= 262;
+			if (trace == 1)
+				vblank.flags |= FB_VBLANK_VSYNCING;
+			vblank.count = itv->last_vsync_field;
+			vblank.vcount = trace;
+			vblank.hcount = 0;
+			if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
+				return -EFAULT;
+			return 0;
+		}
+
+		case FBIO_WAITFORVSYNC:
+			prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
+			if (!schedule_timeout(msecs_to_jiffies(50)))
+				rc = -ETIMEDOUT;
+			finish_wait(&itv->vsync_waitq, &wait);
+			return rc;
+
+		case IVTVFB_IOC_DMA_FRAME: {
+			struct ivtvfb_dma_frame args;
+
+			IVTVFB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");
+			if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
+				return -EFAULT;
+
+			return ivtvfb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);
+		}
+
+		default:
+			IVTVFB_DEBUG_INFO("Unknown ioctl %08x\n", cmd);
+			return -EINVAL;
+	}
+	return 0;
+}
+
+/* Framebuffer device handling */
+
+static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
+{
+	struct osd_info *oi = itv->osd_info;
+	struct ivtv_osd_coords ivtv_osd;
+	struct v4l2_rect ivtv_window;
+	int osd_mode = -1;
+
+	IVTVFB_DEBUG_INFO("ivtvfb_set_var\n");
+
+	/* Select color space */
+	if (var->nonstd) /* YUV */
+		write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);
+	else /* RGB  */
+		write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
+
+	/* Set the color mode */
+	switch (var->bits_per_pixel) {
+		case 8:
+			osd_mode = IVTV_OSD_BPP_8;
+			break;
+		case 32:
+			osd_mode = IVTV_OSD_BPP_32;
+			break;
+		case 16:
+			switch (var->green.length) {
+			case 4:
+				osd_mode = IVTV_OSD_BPP_16_444;
+				break;
+			case 5:
+				osd_mode = IVTV_OSD_BPP_16_555;
+				break;
+			case 6:
+				osd_mode = IVTV_OSD_BPP_16_565;
+				break;
+			default:
+				IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
+			}
+			break;
+		default:
+			IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
+	}
+
+	/* Set video mode. Although rare, the display can become scrambled even
+	   if we don't change mode. Always 'bounce' to osd_mode via mode 0 */
+	if (osd_mode != -1) {
+		ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
+		ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
+	}
+
+	oi->bits_per_pixel = var->bits_per_pixel;
+	oi->bytes_per_pixel = var->bits_per_pixel / 8;
+
+	/* Set the flicker filter */
+	switch (var->vmode & FB_VMODE_MASK) {
+		case FB_VMODE_NONINTERLACED: /* Filter on */
+			ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);
+			break;
+		case FB_VMODE_INTERLACED: /* Filter off */
+			ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);
+			break;
+		default:
+			IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
+	}
+
+	/* Read the current osd info */
+	ivtvfb_get_osd_coords(itv, &ivtv_osd);
+
+	/* Now set the OSD to the size we want */
+	ivtv_osd.pixel_stride = var->xres_virtual;
+	ivtv_osd.lines = var->yres_virtual;
+	ivtv_osd.x = 0;
+	ivtv_osd.y = 0;
+	ivtvfb_set_osd_coords(itv, &ivtv_osd);
+
+	/* Can't seem to find the right API combo for this.
+	   Use another function which does what we need through direct register access. */
+	ivtv_window.width = var->xres;
+	ivtv_window.height = var->yres;
+
+	/* Minimum margin cannot be 0, as X won't allow such a mode */
+	if (!var->upper_margin)
+		var->upper_margin++;
+	if (!var->left_margin)
+		var->left_margin++;
+	ivtv_window.top = var->upper_margin - 1;
+	ivtv_window.left = var->left_margin - 1;
+
+	ivtvfb_set_display_window(itv, &ivtv_window);
+
+	/* Pass screen size back to yuv handler */
+	itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride;
+	itv->yuv_info.osd_full_h = ivtv_osd.lines;
+
+	/* Force update of yuv registers */
+	itv->yuv_info.yuv_forced_update = 1;
+
+	/* Keep a copy of these settings */
+	memcpy(&oi->fbvar_cur, var, sizeof(oi->fbvar_cur));
+
+	IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
+		      var->xres, var->yres,
+		      var->xres_virtual, var->yres_virtual,
+		      var->bits_per_pixel);
+
+	IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
+		      var->left_margin, var->upper_margin);
+
+	IVTVFB_DEBUG_INFO("Display filter: %s\n",
+			(var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
+	IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
+
+	return 0;
+}
+
+static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
+{
+	struct osd_info *oi = itv->osd_info;
+
+	IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n");
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strlcpy(fix->id, "cx23415 TV out", sizeof(fix->id));
+	fix->smem_start = oi->video_pbase;
+	fix->smem_len = oi->video_buffer_size;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+	fix->xpanstep = 1;
+	fix->ypanstep = 1;
+	fix->ywrapstep = 0;
+	fix->line_length = oi->display_byte_stride;
+	fix->accel = FB_ACCEL_NONE;
+	return 0;
+}
+
+/* Check the requested display mode, returning -EINVAL if we can't
+   handle it. */
+
+static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
+{
+	struct osd_info *oi = itv->osd_info;
+	int osd_height_limit;
+	u32 pixclock, hlimit, vlimit;
+
+	IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
+
+	/* Set base references for mode calcs. */
+	if (itv->is_out_50hz) {
+		pixclock = 84316;
+		hlimit = 776;
+		vlimit = 591;
+		osd_height_limit = 576;
+	}
+	else {
+		pixclock = 83926;
+		hlimit = 776;
+		vlimit = 495;
+		osd_height_limit = 480;
+	}
+
+	if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+	}
+	else if (var->bits_per_pixel == 16) {
+		/* To find out the true mode, check green length */
+		switch (var->green.length) {
+			case 4:
+				var->red.offset = 8;
+				var->red.length = 4;
+				var->green.offset = 4;
+				var->green.length = 4;
+				var->blue.offset = 0;
+				var->blue.length = 4;
+				var->transp.offset = 12;
+				var->transp.length = 1;
+				break;
+			case 5:
+				var->red.offset = 10;
+				var->red.length = 5;
+				var->green.offset = 5;
+				var->green.length = 5;
+				var->blue.offset = 0;
+				var->blue.length = 5;
+				var->transp.offset = 15;
+				var->transp.length = 1;
+				break;
+			default:
+				var->red.offset = 11;
+				var->red.length = 5;
+				var->green.offset = 5;
+				var->green.length = 6;
+				var->blue.offset = 0;
+				var->blue.length = 5;
+				var->transp.offset = 0;
+				var->transp.length = 0;
+				break;
+		}
+	}
+	else {
+		IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	/* Check the resolution */
+	if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
+		IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n",
+				var->xres, var->yres);
+		return -EINVAL;
+	}
+
+	/* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
+	if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
+	    var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
+	    var->xres_virtual < var->xres ||
+	    var->yres_virtual < var->yres) {
+		IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
+			var->xres_virtual, var->yres_virtual);
+		return -EINVAL;
+	}
+
+	/* Some extra checks if in 8 bit mode */
+	if (var->bits_per_pixel == 8) {
+		/* Width must be a multiple of 4 */
+		if (var->xres & 3) {
+			IVTVFB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
+			return -EINVAL;
+		}
+		if (var->xres_virtual & 3) {
+			IVTVFB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
+			return -EINVAL;
+		}
+	}
+	else if (var->bits_per_pixel == 16) {
+		/* Width must be a multiple of 2 */
+		if (var->xres & 1) {
+			IVTVFB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
+			return -EINVAL;
+		}
+		if (var->xres_virtual & 1) {
+			IVTVFB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
+			return -EINVAL;
+		}
+	}
+
+	/* Now check the offsets */
+	if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
+		IVTVFB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
+			var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
+		return -EINVAL;
+	}
+
+	/* Check pixel format */
+	if (var->nonstd > 1) {
+		IVTVFB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
+		return -EINVAL;
+	}
+
+	/* Check video mode */
+	if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
+		((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
+		IVTVFB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
+		return -EINVAL;
+	}
+
+	/* Check the left & upper margins
+	   If the margins are too large, just center the screen
+	   (enforcing margins causes too many problems) */
+
+	if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1)
+		var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
+
+	if (var->upper_margin + var->yres > (itv->is_out_50hz ? 577 : 481))
+		var->upper_margin = 1 + (((itv->is_out_50hz ? 576 : 480) -
+			var->yres) / 2);
+
+	/* Maintain overall 'size' for a constant refresh rate */
+	var->right_margin = hlimit - var->left_margin - var->xres;
+	var->lower_margin = vlimit - var->upper_margin - var->yres;
+
+	/* Fixed sync times */
+	var->hsync_len = 24;
+	var->vsync_len = 2;
+
+	/* Non-interlaced / interlaced mode is used to switch the OSD filter
+	   on or off. Adjust the clock timings to maintain a constant
+	   vertical refresh rate. */
+	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
+		var->pixclock = pixclock / 2;
+	else
+		var->pixclock = pixclock;
+
+	itv->osd_rect.width = var->xres;
+	itv->osd_rect.height = var->yres;
+
+	IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
+		      var->xres, var->yres,
+		      var->xres_virtual, var->yres_virtual,
+		      var->bits_per_pixel);
+
+	IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
+		      var->left_margin, var->upper_margin);
+
+	IVTVFB_DEBUG_INFO("Display filter: %s\n",
+			(var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
+	IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
+	return 0;
+}
+
+static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct ivtv *itv = (struct ivtv *) info->par;
+	IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
+	return _ivtvfb_check_var(var, itv);
+}
+
+static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	u32 osd_pan_index;
+	struct ivtv *itv = (struct ivtv *) info->par;
+
+	if (var->yoffset + info->var.yres > info->var.yres_virtual ||
+	    var->xoffset + info->var.xres > info->var.xres_virtual)
+		return -EINVAL;
+
+	osd_pan_index = var->yoffset * info->fix.line_length
+		      + var->xoffset * info->var.bits_per_pixel / 8;
+	write_reg(osd_pan_index, 0x02A0C);
+
+	/* Pass this info back the yuv handler */
+	itv->yuv_info.osd_x_pan = var->xoffset;
+	itv->yuv_info.osd_y_pan = var->yoffset;
+	/* Force update of yuv registers */
+	itv->yuv_info.yuv_forced_update = 1;
+	/* Remember this value */
+	itv->osd_info->pan_cur = osd_pan_index;
+	return 0;
+}
+
+static int ivtvfb_set_par(struct fb_info *info)
+{
+	int rc = 0;
+	struct ivtv *itv = (struct ivtv *) info->par;
+
+	IVTVFB_DEBUG_INFO("ivtvfb_set_par\n");
+
+	rc = ivtvfb_set_var(itv, &info->var);
+	ivtvfb_pan_display(&info->var, info);
+	ivtvfb_get_fix(itv, &info->fix);
+	ivtv_firmware_check(itv, "ivtvfb_set_par");
+	return rc;
+}
+
+static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+				unsigned blue, unsigned transp,
+				struct fb_info *info)
+{
+	u32 color, *palette;
+	struct ivtv *itv = (struct ivtv *)info->par;
+
+	if (regno >= info->cmap.len)
+		return -EINVAL;
+
+	color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
+	if (info->var.bits_per_pixel <= 8) {
+		write_reg(regno, 0x02a30);
+		write_reg(color, 0x02a34);
+		itv->osd_info->palette_cur[regno] = color;
+		return 0;
+	}
+	if (regno >= 16)
+		return -EINVAL;
+
+	palette = info->pseudo_palette;
+	if (info->var.bits_per_pixel == 16) {
+		switch (info->var.green.length) {
+			case 4:
+				color = ((red & 0xf000) >> 4) |
+					((green & 0xf000) >> 8) |
+					((blue & 0xf000) >> 12);
+				break;
+			case 5:
+				color = ((red & 0xf800) >> 1) |
+					((green & 0xf800) >> 6) |
+					((blue & 0xf800) >> 11);
+				break;
+			case 6:
+				color = (red & 0xf800 ) |
+					((green & 0xfc00) >> 5) |
+					((blue & 0xf800) >> 11);
+				break;
+		}
+	}
+	palette[regno] = color;
+	return 0;
+}
+
+/* We don't really support blanking. All this does is enable or
+   disable the OSD. */
+static int ivtvfb_blank(int blank_mode, struct fb_info *info)
+{
+	struct ivtv *itv = (struct ivtv *)info->par;
+
+	IVTVFB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode);
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
+		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
+		break;
+	case FB_BLANK_NORMAL:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_VSYNC_SUSPEND:
+		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
+		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
+		break;
+	case FB_BLANK_POWERDOWN:
+		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0);
+		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
+		break;
+	}
+	itv->osd_info->blank_cur = blank_mode;
+	return 0;
+}
+
+static struct fb_ops ivtvfb_ops = {
+	.owner = THIS_MODULE,
+	.fb_write       = ivtvfb_write,
+	.fb_check_var   = ivtvfb_check_var,
+	.fb_set_par     = ivtvfb_set_par,
+	.fb_setcolreg   = ivtvfb_setcolreg,
+	.fb_fillrect    = cfb_fillrect,
+	.fb_copyarea    = cfb_copyarea,
+	.fb_imageblit   = cfb_imageblit,
+	.fb_cursor      = NULL,
+	.fb_ioctl       = ivtvfb_ioctl,
+	.fb_pan_display = ivtvfb_pan_display,
+	.fb_blank       = ivtvfb_blank,
+};
+
+/* Restore hardware after firmware restart */
+static void ivtvfb_restore(struct ivtv *itv)
+{
+	struct osd_info *oi = itv->osd_info;
+	int i;
+
+	ivtvfb_set_var(itv, &oi->fbvar_cur);
+	ivtvfb_blank(oi->blank_cur, &oi->ivtvfb_info);
+	for (i = 0; i < 256; i++) {
+		write_reg(i, 0x02a30);
+		write_reg(oi->palette_cur[i], 0x02a34);
+	}
+	write_reg(oi->pan_cur, 0x02a0c);
+}
+
+/* Initialization */
+
+
+/* Setup our initial video mode */
+static int ivtvfb_init_vidmode(struct ivtv *itv)
+{
+	struct osd_info *oi = itv->osd_info;
+	struct v4l2_rect start_window;
+	int max_height;
+
+	/* Color mode */
+
+	if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32)
+		osd_depth = 8;
+	oi->bits_per_pixel = osd_depth;
+	oi->bytes_per_pixel = oi->bits_per_pixel / 8;
+
+	/* Horizontal size & position */
+
+	if (osd_xres > 720)
+		osd_xres = 720;
+
+	/* Must be a multiple of 4 for 8bpp & 2 for 16bpp */
+	if (osd_depth == 8)
+		osd_xres &= ~3;
+	else if (osd_depth == 16)
+		osd_xres &= ~1;
+
+	start_window.width = osd_xres ? osd_xres : 640;
+
+	/* Check horizontal start (osd_left). */
+	if (osd_left && osd_left + start_window.width > 721) {
+		IVTVFB_ERR("Invalid osd_left - assuming default\n");
+		osd_left = 0;
+	}
+
+	/* Hardware coords start at 0, user coords start at 1. */
+	osd_left--;
+
+	start_window.left = osd_left >= 0 ?
+		 osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
+
+	oi->display_byte_stride =
+			start_window.width * oi->bytes_per_pixel;
+
+	/* Vertical size & position */
+
+	max_height = itv->is_out_50hz ? 576 : 480;
+
+	if (osd_yres > max_height)
+		osd_yres = max_height;
+
+	start_window.height = osd_yres ?
+		osd_yres : itv->is_out_50hz ? 480 : 400;
+
+	/* Check vertical start (osd_upper). */
+	if (osd_upper + start_window.height > max_height + 1) {
+		IVTVFB_ERR("Invalid osd_upper - assuming default\n");
+		osd_upper = 0;
+	}
+
+	/* Hardware coords start at 0, user coords start at 1. */
+	osd_upper--;
+
+	start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
+
+	oi->display_width = start_window.width;
+	oi->display_height = start_window.height;
+
+	/* Generate a valid fb_var_screeninfo */
+
+	oi->ivtvfb_defined.xres = oi->display_width;
+	oi->ivtvfb_defined.yres = oi->display_height;
+	oi->ivtvfb_defined.xres_virtual = oi->display_width;
+	oi->ivtvfb_defined.yres_virtual = oi->display_height;
+	oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
+	oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
+	oi->ivtvfb_defined.left_margin = start_window.left + 1;
+	oi->ivtvfb_defined.upper_margin = start_window.top + 1;
+	oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
+	oi->ivtvfb_defined.nonstd = 0;
+
+	/* We've filled in the most data, let the usual mode check
+	   routine fill in the rest. */
+	_ivtvfb_check_var(&oi->ivtvfb_defined, itv);
+
+	/* Generate valid fb_fix_screeninfo */
+
+	ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
+
+	/* Generate valid fb_info */
+
+	oi->ivtvfb_info.node = -1;
+	oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
+	oi->ivtvfb_info.fbops = &ivtvfb_ops;
+	oi->ivtvfb_info.par = itv;
+	oi->ivtvfb_info.var = oi->ivtvfb_defined;
+	oi->ivtvfb_info.fix = oi->ivtvfb_fix;
+	oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
+	oi->ivtvfb_info.fbops = &ivtvfb_ops;
+
+	/* Supply some monitor specs. Bogus values will do for now */
+	oi->ivtvfb_info.monspecs.hfmin = 8000;
+	oi->ivtvfb_info.monspecs.hfmax = 70000;
+	oi->ivtvfb_info.monspecs.vfmin = 10;
+	oi->ivtvfb_info.monspecs.vfmax = 100;
+
+	/* Allocate color map */
+	if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
+		IVTVFB_ERR("abort, unable to alloc cmap\n");
+		return -ENOMEM;
+	}
+
+	/* Allocate the pseudo palette */
+	oi->ivtvfb_info.pseudo_palette =
+		kmalloc(sizeof(u32) * 16, GFP_KERNEL|__GFP_NOWARN);
+
+	if (!oi->ivtvfb_info.pseudo_palette) {
+		IVTVFB_ERR("abort, unable to alloc pseudo palette\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */
+
+static int ivtvfb_init_io(struct ivtv *itv)
+{
+	struct osd_info *oi = itv->osd_info;
+
+	mutex_lock(&itv->serialize_lock);
+	if (ivtv_init_on_first_open(itv)) {
+		mutex_unlock(&itv->serialize_lock);
+		IVTVFB_ERR("Failed to initialize ivtv\n");
+		return -ENXIO;
+	}
+	mutex_unlock(&itv->serialize_lock);
+
+	if (ivtvfb_get_framebuffer(itv, &oi->video_rbase,
+					&oi->video_buffer_size) < 0) {
+		IVTVFB_ERR("Firmware failed to respond\n");
+		return -EIO;
+	}
+
+	/* The osd buffer size depends on the number of video buffers allocated
+	   on the PVR350 itself. For now we'll hardcode the smallest osd buffer
+	   size to prevent any overlap. */
+	oi->video_buffer_size = 1704960;
+
+	oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
+	oi->video_vbase = itv->dec_mem + oi->video_rbase;
+
+	if (!oi->video_vbase) {
+		IVTVFB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
+		     oi->video_buffer_size, oi->video_pbase);
+		return -EIO;
+	}
+
+	IVTVFB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
+			oi->video_pbase, oi->video_vbase,
+			oi->video_buffer_size / 1024);
+
+#ifdef CONFIG_MTRR
+	{
+		/* Find the largest power of two that maps the whole buffer */
+		int size_shift = 31;
+
+		while (!(oi->video_buffer_size & (1 << size_shift))) {
+			size_shift--;
+		}
+		size_shift++;
+		oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
+		oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
+		oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
+		oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
+		if (mtrr_add(oi->fb_start_aligned_physaddr,
+			oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr,
+			     MTRR_TYPE_WRCOMB, 1) < 0) {
+			IVTVFB_INFO("disabled mttr\n");
+			oi->fb_start_aligned_physaddr = 0;
+			oi->fb_end_aligned_physaddr = 0;
+		}
+	}
+#endif
+
+	/* Blank the entire osd. */
+	memset_io(oi->video_vbase, 0, oi->video_buffer_size);
+
+	return 0;
+}
+
+/* Release any memory we've grabbed & remove mtrr entry */
+static void ivtvfb_release_buffers (struct ivtv *itv)
+{
+	struct osd_info *oi = itv->osd_info;
+
+	/* Release cmap */
+	if (oi->ivtvfb_info.cmap.len)
+		fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
+
+	/* Release pseudo palette */
+	if (oi->ivtvfb_info.pseudo_palette)
+		kfree(oi->ivtvfb_info.pseudo_palette);
+
+#ifdef CONFIG_MTRR
+	if (oi->fb_end_aligned_physaddr) {
+		mtrr_del(-1, oi->fb_start_aligned_physaddr,
+			oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr);
+	}
+#endif
+
+	kfree(oi);
+	itv->osd_info = NULL;
+}
+
+/* Initialize the specified card */
+
+static int ivtvfb_init_card(struct ivtv *itv)
+{
+	int rc;
+
+	if (itv->osd_info) {
+		IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id);
+		return -EBUSY;
+	}
+
+	itv->osd_info = kzalloc(sizeof(struct osd_info),
+					GFP_ATOMIC|__GFP_NOWARN);
+	if (itv->osd_info == NULL) {
+		IVTVFB_ERR("Failed to allocate memory for osd_info\n");
+		return -ENOMEM;
+	}
+
+	/* Find & setup the OSD buffer */
+	rc = ivtvfb_init_io(itv);
+	if (rc) {
+		ivtvfb_release_buffers(itv);
+		return rc;
+	}
+
+	/* Set the startup video mode information */
+	if ((rc = ivtvfb_init_vidmode(itv))) {
+		ivtvfb_release_buffers(itv);
+		return rc;
+	}
+
+	/* Register the framebuffer */
+	if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
+		ivtvfb_release_buffers(itv);
+		return -EINVAL;
+	}
+
+	itv->osd_video_pbase = itv->osd_info->video_pbase;
+
+	/* Set the card to the requested mode */
+	ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
+
+	/* Set color 0 to black */
+	write_reg(0, 0x02a30);
+	write_reg(0, 0x02a34);
+
+	/* Enable the osd */
+	ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
+
+	/* Enable restart */
+	itv->ivtvfb_restore = ivtvfb_restore;
+
+	/* Allocate DMA */
+	ivtv_udma_alloc(itv);
+	return 0;
+
+}
+
+static int __init ivtvfb_callback_init(struct device *dev, void *p)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+	struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
+
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+		if (ivtvfb_init_card(itv) == 0) {
+			IVTVFB_INFO("Framebuffer registered on %s\n",
+					itv->v4l2_dev.name);
+			(*(int *)p)++;
+		}
+	}
+	return 0;
+}
+
+static int ivtvfb_callback_cleanup(struct device *dev, void *p)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+	struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
+	struct osd_info *oi = itv->osd_info;
+
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+		if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
+			IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n",
+				       itv->instance);
+			return 0;
+		}
+		IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance);
+		itv->ivtvfb_restore = NULL;
+		ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info);
+		ivtvfb_release_buffers(itv);
+		itv->osd_video_pbase = 0;
+	}
+	return 0;
+}
+
+static int __init ivtvfb_init(void)
+{
+	struct device_driver *drv;
+	int registered = 0;
+	int err;
+
+	if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) {
+		printk(KERN_ERR "ivtvfb:  ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n",
+		     IVTV_MAX_CARDS - 1);
+		return -EINVAL;
+	}
+
+	drv = driver_find("ivtv", &pci_bus_type);
+	err = driver_for_each_device(drv, NULL, &registered, ivtvfb_callback_init);
+	(void)err;	/* suppress compiler warning */
+	if (!registered) {
+		printk(KERN_ERR "ivtvfb:  no cards found\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static void ivtvfb_cleanup(void)
+{
+	struct device_driver *drv;
+	int err;
+
+	printk(KERN_INFO "ivtvfb:  Unloading framebuffer module\n");
+
+	drv = driver_find("ivtv", &pci_bus_type);
+	err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup);
+	(void)err;	/* suppress compiler warning */
+}
+
+module_init(ivtvfb_init);
+module_exit(ivtvfb_cleanup);
diff --git a/drivers/media/pci/mantis/Kconfig b/drivers/media/pci/mantis/Kconfig
new file mode 100644
index 0000000..a13a505
--- /dev/null
+++ b/drivers/media/pci/mantis/Kconfig
@@ -0,0 +1,38 @@
+config MANTIS_CORE
+	tristate "Mantis/Hopper PCI bridge based devices"
+	depends on PCI && I2C && INPUT && RC_CORE
+
+	help
+	  Support for PCI cards based on the Mantis and Hopper PCi bridge.
+
+	  Say Y if you own such a device and want to use it.
+
+config DVB_MANTIS
+	tristate "MANTIS based cards"
+	depends on MANTIS_CORE && DVB_CORE && PCI && I2C
+	select DVB_MB86A16 if !DVB_FE_CUSTOMISE
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+	select DVB_STB0899 if !DVB_FE_CUSTOMISE
+	select DVB_STB6100 if !DVB_FE_CUSTOMISE
+	select DVB_TDA665x if !DVB_FE_CUSTOMISE
+	select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+	select DVB_PLL
+	help
+	  Support for PCI cards based on the Mantis PCI bridge.
+	  Say Y when you have a Mantis based DVB card and want to use it.
+
+	  If unsure say N.
+
+config DVB_HOPPER
+	tristate "HOPPER based cards"
+	depends on MANTIS_CORE && DVB_CORE && PCI && I2C
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select DVB_PLL
+	help
+	  Support for PCI cards based on the Hopper  PCI bridge.
+	  Say Y when you have a Hopper based DVB card and want to use it.
+
+	  If unsure say N
diff --git a/drivers/media/pci/mantis/Makefile b/drivers/media/pci/mantis/Makefile
new file mode 100644
index 0000000..f715051
--- /dev/null
+++ b/drivers/media/pci/mantis/Makefile
@@ -0,0 +1,28 @@
+mantis_core-objs :=	mantis_ioc.o	\
+			mantis_uart.o	\
+			mantis_dma.o	\
+			mantis_pci.o	\
+			mantis_i2c.o	\
+			mantis_dvb.o	\
+			mantis_evm.o	\
+			mantis_hif.o	\
+			mantis_ca.o	\
+			mantis_pcmcia.o	\
+			mantis_input.o
+
+mantis-objs	:=	mantis_cards.o	\
+			mantis_vp1033.o	\
+			mantis_vp1034.o	\
+			mantis_vp1041.o	\
+			mantis_vp2033.o	\
+			mantis_vp2040.o	\
+			mantis_vp3030.o
+
+hopper-objs	:=	hopper_cards.o	\
+			hopper_vp3028.o
+
+obj-$(CONFIG_MANTIS_CORE)	+= mantis_core.o
+obj-$(CONFIG_DVB_MANTIS)	+= mantis.o
+obj-$(CONFIG_DVB_HOPPER)	+= hopper.o
+
+ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/
diff --git a/drivers/media/pci/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c
new file mode 100644
index 0000000..cc0251e
--- /dev/null
+++ b/drivers/media/pci/mantis/hopper_cards.c
@@ -0,0 +1,277 @@
+/*
+	Hopper PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <asm/irq.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "hopper_vp3028.h"
+#include "mantis_dma.h"
+#include "mantis_dvb.h"
+#include "mantis_uart.h"
+#include "mantis_ioc.h"
+#include "mantis_pci.h"
+#include "mantis_i2c.h"
+#include "mantis_reg.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)");
+
+#define DRIVER_NAME	"Hopper"
+
+static char *label[10] = {
+	"DMA",
+	"IRQ-0",
+	"IRQ-1",
+	"OCERR",
+	"PABRT",
+	"RIPRR",
+	"PPERR",
+	"FTRGT",
+	"RISCI",
+	"RACK"
+};
+
+static int devs;
+
+static irqreturn_t hopper_irq_handler(int irq, void *dev_id)
+{
+	u32 stat = 0, mask = 0;
+	u32 rst_stat = 0, rst_mask = 0;
+
+	struct mantis_pci *mantis;
+	struct mantis_ca *ca;
+
+	mantis = (struct mantis_pci *) dev_id;
+	if (unlikely(mantis == NULL)) {
+		dprintk(MANTIS_ERROR, 1, "Mantis == NULL");
+		return IRQ_NONE;
+	}
+	ca = mantis->mantis_ca;
+
+	stat = mmread(MANTIS_INT_STAT);
+	mask = mmread(MANTIS_INT_MASK);
+	if (!(stat & mask))
+		return IRQ_NONE;
+
+	rst_mask  = MANTIS_GPIF_WRACK  |
+		    MANTIS_GPIF_OTHERR |
+		    MANTIS_SBUF_WSTO   |
+		    MANTIS_GPIF_EXTIRQ;
+
+	rst_stat  = mmread(MANTIS_GPIF_STATUS);
+	rst_stat &= rst_mask;
+	mmwrite(rst_stat, MANTIS_GPIF_STATUS);
+
+	mantis->mantis_int_stat = stat;
+	mantis->mantis_int_mask = mask;
+	dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask);
+	if (stat & MANTIS_INT_RISCEN) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]);
+	}
+	if (stat & MANTIS_INT_IRQ0) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]);
+		mantis->gpif_status = rst_stat;
+		wake_up(&ca->hif_write_wq);
+		schedule_work(&ca->hif_evm_work);
+	}
+	if (stat & MANTIS_INT_IRQ1) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]);
+		schedule_work(&mantis->uart_work);
+	}
+	if (stat & MANTIS_INT_OCERR) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]);
+	}
+	if (stat & MANTIS_INT_PABORT) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]);
+	}
+	if (stat & MANTIS_INT_RIPERR) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]);
+	}
+	if (stat & MANTIS_INT_PPERR) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]);
+	}
+	if (stat & MANTIS_INT_FTRGT) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]);
+	}
+	if (stat & MANTIS_INT_RISCI) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
+		mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
+		tasklet_schedule(&mantis->tasklet);
+	}
+	if (stat & MANTIS_INT_I2CDONE) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
+		wake_up(&mantis->i2c_wq);
+	}
+	mmwrite(stat, MANTIS_INT_STAT);
+	stat &= ~(MANTIS_INT_RISCEN   | MANTIS_INT_I2CDONE |
+		  MANTIS_INT_I2CRACK  | MANTIS_INT_PCMCIA7 |
+		  MANTIS_INT_PCMCIA6  | MANTIS_INT_PCMCIA5 |
+		  MANTIS_INT_PCMCIA4  | MANTIS_INT_PCMCIA3 |
+		  MANTIS_INT_PCMCIA2  | MANTIS_INT_PCMCIA1 |
+		  MANTIS_INT_PCMCIA0  | MANTIS_INT_IRQ1	   |
+		  MANTIS_INT_IRQ0     | MANTIS_INT_OCERR   |
+		  MANTIS_INT_PABORT   | MANTIS_INT_RIPERR  |
+		  MANTIS_INT_PPERR    | MANTIS_INT_FTRGT   |
+		  MANTIS_INT_RISCI);
+
+	if (stat)
+		dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask);
+
+	dprintk(MANTIS_DEBUG, 0, "\n");
+	return IRQ_HANDLED;
+}
+
+static int __devinit hopper_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+	struct mantis_pci *mantis;
+	struct mantis_hwconfig *config;
+	int err = 0;
+
+	mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL);
+	if (mantis == NULL) {
+		printk(KERN_ERR "%s ERROR: Out of memory\n", __func__);
+		err = -ENOMEM;
+		goto fail0;
+	}
+
+	mantis->num		= devs;
+	mantis->verbose		= verbose;
+	mantis->pdev		= pdev;
+	config			= (struct mantis_hwconfig *) pci_id->driver_data;
+	config->irq_handler	= &hopper_irq_handler;
+	mantis->hwconfig	= config;
+
+	err = mantis_pci_init(mantis);
+	if (err) {
+		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err);
+		goto fail1;
+	}
+
+	err = mantis_stream_control(mantis, STREAM_TO_HIF);
+	if (err < 0) {
+		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err);
+		goto fail1;
+	}
+
+	err = mantis_i2c_init(mantis);
+	if (err < 0) {
+		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err);
+		goto fail2;
+	}
+
+	err = mantis_get_mac(mantis);
+	if (err < 0) {
+		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err);
+		goto fail2;
+	}
+
+	err = mantis_dma_init(mantis);
+	if (err < 0) {
+		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err);
+		goto fail3;
+	}
+
+	err = mantis_dvb_init(mantis);
+	if (err < 0) {
+		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err);
+		goto fail4;
+	}
+	devs++;
+
+	return err;
+
+fail4:
+	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err);
+	mantis_dma_exit(mantis);
+
+fail3:
+	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err);
+	mantis_i2c_exit(mantis);
+
+fail2:
+	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err);
+	mantis_pci_exit(mantis);
+
+fail1:
+	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err);
+	kfree(mantis);
+
+fail0:
+	return err;
+}
+
+static void __devexit hopper_pci_remove(struct pci_dev *pdev)
+{
+	struct mantis_pci *mantis = pci_get_drvdata(pdev);
+
+	if (mantis) {
+		mantis_dvb_exit(mantis);
+		mantis_dma_exit(mantis);
+		mantis_i2c_exit(mantis);
+		mantis_pci_exit(mantis);
+		kfree(mantis);
+	}
+	return;
+
+}
+
+static struct pci_device_id hopper_pci_table[] = {
+	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config),
+	{ }
+};
+
+MODULE_DEVICE_TABLE(pci, hopper_pci_table);
+
+static struct pci_driver hopper_pci_driver = {
+	.name		= DRIVER_NAME,
+	.id_table	= hopper_pci_table,
+	.probe		= hopper_pci_probe,
+	.remove		= hopper_pci_remove,
+};
+
+static int __devinit hopper_init(void)
+{
+	return pci_register_driver(&hopper_pci_driver);
+}
+
+static void __devexit hopper_exit(void)
+{
+	return pci_unregister_driver(&hopper_pci_driver);
+}
+
+module_init(hopper_init);
+module_exit(hopper_exit);
+
+MODULE_DESCRIPTION("HOPPER driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/mantis/hopper_vp3028.c b/drivers/media/pci/mantis/hopper_vp3028.c
new file mode 100644
index 0000000..68a29f8
--- /dev/null
+++ b/drivers/media/pci/mantis/hopper_vp3028.c
@@ -0,0 +1,88 @@
+/*
+	Hopper VP-3028 driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "zl10353.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "hopper_vp3028.h"
+
+struct zl10353_config hopper_vp3028_config = {
+	.demod_address	= 0x0f,
+};
+
+#define MANTIS_MODEL_NAME	"VP-3028"
+#define MANTIS_DEV_TYPE		"DVB-T"
+
+static int vp3028_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+	struct i2c_adapter *adapter	= &mantis->adapter;
+	struct mantis_hwconfig *config	= mantis->hwconfig;
+	int err = 0;
+
+	mantis_gpio_set_bits(mantis, config->reset, 0);
+	msleep(100);
+	err = mantis_frontend_power(mantis, POWER_ON);
+	msleep(100);
+	mantis_gpio_set_bits(mantis, config->reset, 1);
+
+	err = mantis_frontend_power(mantis, POWER_ON);
+	if (err == 0) {
+		msleep(250);
+		dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)");
+		fe = dvb_attach(zl10353_attach, &hopper_vp3028_config, adapter);
+
+		if (!fe)
+			return -1;
+	} else {
+		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+			adapter->name,
+			err);
+
+		return -EIO;
+	}
+	dprintk(MANTIS_ERROR, 1, "Done!");
+
+	return 0;
+}
+
+struct mantis_hwconfig vp3028_config = {
+	.model_name	= MANTIS_MODEL_NAME,
+	.dev_type	= MANTIS_DEV_TYPE,
+	.ts_size	= MANTIS_TS_188,
+
+	.baud_rate	= MANTIS_BAUD_9600,
+	.parity		= MANTIS_PARITY_NONE,
+	.bytes		= 0,
+
+	.frontend_init	= vp3028_frontend_init,
+	.power		= GPIF_A00,
+	.reset		= GPIF_A03,
+};
diff --git a/drivers/media/pci/mantis/hopper_vp3028.h b/drivers/media/pci/mantis/hopper_vp3028.h
new file mode 100644
index 0000000..5723949
--- /dev/null
+++ b/drivers/media/pci/mantis/hopper_vp3028.h
@@ -0,0 +1,30 @@
+/*
+	Hopper VP-3028 driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP3028_H
+#define __MANTIS_VP3028_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_3028_DVB_T	0x0028
+
+extern struct mantis_hwconfig vp3028_config;
+
+#endif /* __MANTIS_VP3028_H */
diff --git a/drivers/media/pci/mantis/mantis_ca.c b/drivers/media/pci/mantis/mantis_ca.c
new file mode 100644
index 0000000..3d70469
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_ca.c
@@ -0,0 +1,209 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_link.h"
+#include "mantis_hif.h"
+#include "mantis_reg.h"
+
+#include "mantis_ca.h"
+
+static int mantis_ca_read_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr)
+{
+	struct mantis_ca *ca = en50221->data;
+	struct mantis_pci *mantis = ca->ca_priv;
+
+	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Read", slot);
+
+	if (slot != 0)
+		return -EINVAL;
+
+	return mantis_hif_read_mem(ca, addr);
+}
+
+static int mantis_ca_write_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr, u8 data)
+{
+	struct mantis_ca *ca = en50221->data;
+	struct mantis_pci *mantis = ca->ca_priv;
+
+	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Write", slot);
+
+	if (slot != 0)
+		return -EINVAL;
+
+	return mantis_hif_write_mem(ca, addr, data);
+}
+
+static int mantis_ca_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr)
+{
+	struct mantis_ca *ca = en50221->data;
+	struct mantis_pci *mantis = ca->ca_priv;
+
+	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Read", slot);
+
+	if (slot != 0)
+		return -EINVAL;
+
+	return mantis_hif_read_iom(ca, addr);
+}
+
+static int mantis_ca_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr, u8 data)
+{
+	struct mantis_ca *ca = en50221->data;
+	struct mantis_pci *mantis = ca->ca_priv;
+
+	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Write", slot);
+
+	if (slot != 0)
+		return -EINVAL;
+
+	return mantis_hif_write_iom(ca, addr, data);
+}
+
+static int mantis_ca_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
+{
+	struct mantis_ca *ca = en50221->data;
+	struct mantis_pci *mantis = ca->ca_priv;
+
+	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot RESET", slot);
+	udelay(500); /* Wait.. */
+	mmwrite(0xda, MANTIS_PCMCIA_RESET); /* Leading edge assert */
+	udelay(500);
+	mmwrite(0x00, MANTIS_PCMCIA_RESET); /* Trailing edge deassert */
+	msleep(1000);
+	dvb_ca_en50221_camready_irq(&ca->en50221, 0);
+
+	return 0;
+}
+
+static int mantis_ca_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
+{
+	struct mantis_ca *ca = en50221->data;
+	struct mantis_pci *mantis = ca->ca_priv;
+
+	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot shutdown", slot);
+
+	return 0;
+}
+
+static int mantis_ts_control(struct dvb_ca_en50221 *en50221, int slot)
+{
+	struct mantis_ca *ca = en50221->data;
+	struct mantis_pci *mantis = ca->ca_priv;
+
+	dprintk(MANTIS_DEBUG, 1, "Slot(%d): TS control", slot);
+/*	mantis_set_direction(mantis, 1); */ /* Enable TS through CAM */
+
+	return 0;
+}
+
+static int mantis_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open)
+{
+	struct mantis_ca *ca = en50221->data;
+	struct mantis_pci *mantis = ca->ca_priv;
+
+	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Poll Slot status", slot);
+
+	if (ca->slot_state == MODULE_INSERTED) {
+		dprintk(MANTIS_DEBUG, 1, "CA Module present and ready");
+		return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
+	} else {
+		dprintk(MANTIS_DEBUG, 1, "CA Module not present or not ready");
+	}
+
+	return 0;
+}
+
+int mantis_ca_init(struct mantis_pci *mantis)
+{
+	struct dvb_adapter *dvb_adapter	= &mantis->dvb_adapter;
+	struct mantis_ca *ca;
+	int ca_flags = 0, result;
+
+	dprintk(MANTIS_DEBUG, 1, "Initializing Mantis CA");
+	ca = kzalloc(sizeof(struct mantis_ca), GFP_KERNEL);
+	if (!ca) {
+		dprintk(MANTIS_ERROR, 1, "Out of memory!, exiting ..");
+		result = -ENOMEM;
+		goto err;
+	}
+
+	ca->ca_priv		= mantis;
+	mantis->mantis_ca	= ca;
+	ca_flags		= DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE;
+	/* register CA interface */
+	ca->en50221.owner		= THIS_MODULE;
+	ca->en50221.read_attribute_mem	= mantis_ca_read_attr_mem;
+	ca->en50221.write_attribute_mem	= mantis_ca_write_attr_mem;
+	ca->en50221.read_cam_control	= mantis_ca_read_cam_ctl;
+	ca->en50221.write_cam_control	= mantis_ca_write_cam_ctl;
+	ca->en50221.slot_reset		= mantis_ca_slot_reset;
+	ca->en50221.slot_shutdown	= mantis_ca_slot_shutdown;
+	ca->en50221.slot_ts_enable	= mantis_ts_control;
+	ca->en50221.poll_slot_status	= mantis_slot_status;
+	ca->en50221.data		= ca;
+
+	mutex_init(&ca->ca_lock);
+
+	init_waitqueue_head(&ca->hif_data_wq);
+	init_waitqueue_head(&ca->hif_opdone_wq);
+	init_waitqueue_head(&ca->hif_write_wq);
+
+	dprintk(MANTIS_ERROR, 1, "Registering EN50221 device");
+	result = dvb_ca_en50221_init(dvb_adapter, &ca->en50221, ca_flags, 1);
+	if (result != 0) {
+		dprintk(MANTIS_ERROR, 1, "EN50221: Initialization failed <%d>", result);
+		goto err;
+	}
+	dprintk(MANTIS_ERROR, 1, "Registered EN50221 device");
+	mantis_evmgr_init(ca);
+	return 0;
+err:
+	kfree(ca);
+	return result;
+}
+EXPORT_SYMBOL_GPL(mantis_ca_init);
+
+void mantis_ca_exit(struct mantis_pci *mantis)
+{
+	struct mantis_ca *ca = mantis->mantis_ca;
+
+	dprintk(MANTIS_DEBUG, 1, "Mantis CA exit");
+
+	mantis_evmgr_exit(ca);
+	dprintk(MANTIS_ERROR, 1, "Unregistering EN50221 device");
+	if (ca)
+		dvb_ca_en50221_release(&ca->en50221);
+
+	kfree(ca);
+}
+EXPORT_SYMBOL_GPL(mantis_ca_exit);
diff --git a/drivers/media/pci/mantis/mantis_ca.h b/drivers/media/pci/mantis/mantis_ca.h
new file mode 100644
index 0000000..dc63e55
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_ca.h
@@ -0,0 +1,27 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_CA_H
+#define __MANTIS_CA_H
+
+extern int mantis_ca_init(struct mantis_pci *mantis);
+extern void mantis_ca_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_CA_H */
diff --git a/drivers/media/pci/mantis/mantis_cards.c b/drivers/media/pci/mantis/mantis_cards.c
new file mode 100644
index 0000000..0207d1f
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_cards.c
@@ -0,0 +1,307 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <asm/irq.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+
+#include "mantis_vp1033.h"
+#include "mantis_vp1034.h"
+#include "mantis_vp1041.h"
+#include "mantis_vp2033.h"
+#include "mantis_vp2040.h"
+#include "mantis_vp3030.h"
+
+#include "mantis_dma.h"
+#include "mantis_ca.h"
+#include "mantis_dvb.h"
+#include "mantis_uart.h"
+#include "mantis_ioc.h"
+#include "mantis_pci.h"
+#include "mantis_i2c.h"
+#include "mantis_reg.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)");
+
+static int devs;
+
+#define DRIVER_NAME	"Mantis"
+
+static char *label[10] = {
+	"DMA",
+	"IRQ-0",
+	"IRQ-1",
+	"OCERR",
+	"PABRT",
+	"RIPRR",
+	"PPERR",
+	"FTRGT",
+	"RISCI",
+	"RACK"
+};
+
+static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
+{
+	u32 stat = 0, mask = 0;
+	u32 rst_stat = 0, rst_mask = 0;
+
+	struct mantis_pci *mantis;
+	struct mantis_ca *ca;
+
+	mantis = (struct mantis_pci *) dev_id;
+	if (unlikely(mantis == NULL)) {
+		dprintk(MANTIS_ERROR, 1, "Mantis == NULL");
+		return IRQ_NONE;
+	}
+	ca = mantis->mantis_ca;
+
+	stat = mmread(MANTIS_INT_STAT);
+	mask = mmread(MANTIS_INT_MASK);
+	if (!(stat & mask))
+		return IRQ_NONE;
+
+	rst_mask  = MANTIS_GPIF_WRACK  |
+		    MANTIS_GPIF_OTHERR |
+		    MANTIS_SBUF_WSTO   |
+		    MANTIS_GPIF_EXTIRQ;
+
+	rst_stat  = mmread(MANTIS_GPIF_STATUS);
+	rst_stat &= rst_mask;
+	mmwrite(rst_stat, MANTIS_GPIF_STATUS);
+
+	mantis->mantis_int_stat = stat;
+	mantis->mantis_int_mask = mask;
+	dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask);
+	if (stat & MANTIS_INT_RISCEN) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]);
+	}
+	if (stat & MANTIS_INT_IRQ0) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]);
+		mantis->gpif_status = rst_stat;
+		wake_up(&ca->hif_write_wq);
+		schedule_work(&ca->hif_evm_work);
+	}
+	if (stat & MANTIS_INT_IRQ1) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]);
+		schedule_work(&mantis->uart_work);
+	}
+	if (stat & MANTIS_INT_OCERR) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]);
+	}
+	if (stat & MANTIS_INT_PABORT) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]);
+	}
+	if (stat & MANTIS_INT_RIPERR) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]);
+	}
+	if (stat & MANTIS_INT_PPERR) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]);
+	}
+	if (stat & MANTIS_INT_FTRGT) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]);
+	}
+	if (stat & MANTIS_INT_RISCI) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
+		mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
+		tasklet_schedule(&mantis->tasklet);
+	}
+	if (stat & MANTIS_INT_I2CDONE) {
+		dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
+		wake_up(&mantis->i2c_wq);
+	}
+	mmwrite(stat, MANTIS_INT_STAT);
+	stat &= ~(MANTIS_INT_RISCEN   | MANTIS_INT_I2CDONE |
+		  MANTIS_INT_I2CRACK  | MANTIS_INT_PCMCIA7 |
+		  MANTIS_INT_PCMCIA6  | MANTIS_INT_PCMCIA5 |
+		  MANTIS_INT_PCMCIA4  | MANTIS_INT_PCMCIA3 |
+		  MANTIS_INT_PCMCIA2  | MANTIS_INT_PCMCIA1 |
+		  MANTIS_INT_PCMCIA0  | MANTIS_INT_IRQ1	   |
+		  MANTIS_INT_IRQ0     | MANTIS_INT_OCERR   |
+		  MANTIS_INT_PABORT   | MANTIS_INT_RIPERR  |
+		  MANTIS_INT_PPERR    | MANTIS_INT_FTRGT   |
+		  MANTIS_INT_RISCI);
+
+	if (stat)
+		dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask);
+
+	dprintk(MANTIS_DEBUG, 0, "\n");
+	return IRQ_HANDLED;
+}
+
+static int __devinit mantis_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+	struct mantis_pci *mantis;
+	struct mantis_hwconfig *config;
+	int err = 0;
+
+	mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL);
+	if (mantis == NULL) {
+		printk(KERN_ERR "%s ERROR: Out of memory\n", __func__);
+		err = -ENOMEM;
+		goto fail0;
+	}
+
+	mantis->num		= devs;
+	mantis->verbose		= verbose;
+	mantis->pdev		= pdev;
+	config			= (struct mantis_hwconfig *) pci_id->driver_data;
+	config->irq_handler	= &mantis_irq_handler;
+	mantis->hwconfig	= config;
+
+	err = mantis_pci_init(mantis);
+	if (err) {
+		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err);
+		goto fail1;
+	}
+
+	err = mantis_stream_control(mantis, STREAM_TO_HIF);
+	if (err < 0) {
+		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err);
+		goto fail1;
+	}
+
+	err = mantis_i2c_init(mantis);
+	if (err < 0) {
+		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err);
+		goto fail2;
+	}
+
+	err = mantis_get_mac(mantis);
+	if (err < 0) {
+		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err);
+		goto fail2;
+	}
+
+	err = mantis_dma_init(mantis);
+	if (err < 0) {
+		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err);
+		goto fail3;
+	}
+
+	err = mantis_dvb_init(mantis);
+	if (err < 0) {
+		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err);
+		goto fail4;
+	}
+	err = mantis_uart_init(mantis);
+	if (err < 0) {
+		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART initialization failed <%d>", err);
+		goto fail6;
+	}
+
+	devs++;
+
+	return err;
+
+
+	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART exit! <%d>", err);
+	mantis_uart_exit(mantis);
+
+fail6:
+fail4:
+	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err);
+	mantis_dma_exit(mantis);
+
+fail3:
+	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err);
+	mantis_i2c_exit(mantis);
+
+fail2:
+	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err);
+	mantis_pci_exit(mantis);
+
+fail1:
+	dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err);
+	kfree(mantis);
+
+fail0:
+	return err;
+}
+
+static void __devexit mantis_pci_remove(struct pci_dev *pdev)
+{
+	struct mantis_pci *mantis = pci_get_drvdata(pdev);
+
+	if (mantis) {
+
+		mantis_uart_exit(mantis);
+		mantis_dvb_exit(mantis);
+		mantis_dma_exit(mantis);
+		mantis_i2c_exit(mantis);
+		mantis_pci_exit(mantis);
+		kfree(mantis);
+	}
+	return;
+}
+
+static struct pci_device_id mantis_pci_table[] = {
+	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config),
+	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config),
+	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config),
+	MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config),
+	MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config),
+	MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config),
+	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config),
+	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config),
+	MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config),
+	MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2040_config),
+	MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config),
+	{ }
+};
+
+MODULE_DEVICE_TABLE(pci, mantis_pci_table);
+
+static struct pci_driver mantis_pci_driver = {
+	.name		= DRIVER_NAME,
+	.id_table	= mantis_pci_table,
+	.probe		= mantis_pci_probe,
+	.remove		= mantis_pci_remove,
+};
+
+static int __devinit mantis_init(void)
+{
+	return pci_register_driver(&mantis_pci_driver);
+}
+
+static void __devexit mantis_exit(void)
+{
+	return pci_unregister_driver(&mantis_pci_driver);
+}
+
+module_init(mantis_init);
+module_exit(mantis_exit);
+
+MODULE_DESCRIPTION("MANTIS driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/mantis/mantis_common.h b/drivers/media/pci/mantis/mantis_common.h
new file mode 100644
index 0000000..f2410cf
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_common.h
@@ -0,0 +1,179 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_COMMON_H
+#define __MANTIS_COMMON_H
+
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+#include "mantis_uart.h"
+
+#include "mantis_link.h"
+
+#define MANTIS_ERROR		0
+#define MANTIS_NOTICE		1
+#define MANTIS_INFO		2
+#define MANTIS_DEBUG		3
+#define MANTIS_TMG		9
+
+#define dprintk(y, z, format, arg...) do {								\
+	if (z) {											\
+		if	((mantis->verbose > MANTIS_ERROR) && (mantis->verbose > y))			\
+			printk(KERN_ERR "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);	\
+		else if	((mantis->verbose > MANTIS_NOTICE) && (mantis->verbose > y))			\
+			printk(KERN_NOTICE "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);	\
+		else if ((mantis->verbose > MANTIS_INFO) && (mantis->verbose > y))			\
+			printk(KERN_INFO "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);	\
+		else if ((mantis->verbose > MANTIS_DEBUG) && (mantis->verbose > y))			\
+			printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);	\
+		else if ((mantis->verbose > MANTIS_TMG) && (mantis->verbose > y))			\
+			printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);	\
+	} else {											\
+		if (mantis->verbose > y)								\
+			printk(format , ##arg);								\
+	}												\
+} while(0)
+
+#define mwrite(dat, addr)	writel((dat), addr)
+#define mread(addr)		readl(addr)
+
+#define mmwrite(dat, addr)	mwrite((dat), (mantis->mmio + (addr)))
+#define mmread(addr)		mread(mantis->mmio + (addr))
+
+#define MANTIS_TS_188		0
+#define MANTIS_TS_204		1
+
+#define TWINHAN_TECHNOLOGIES	0x1822
+#define MANTIS			0x4e35
+
+#define TECHNISAT		0x1ae4
+#define TERRATEC		0x153b
+
+#define MAKE_ENTRY(__subven, __subdev, __configptr) {			\
+		.vendor		= TWINHAN_TECHNOLOGIES,			\
+		.device		= MANTIS,				\
+		.subvendor	= (__subven),				\
+		.subdevice	= (__subdev),				\
+		.driver_data	= (unsigned long) (__configptr)		\
+}
+
+enum mantis_i2c_mode {
+	MANTIS_PAGE_MODE = 0,
+	MANTIS_BYTE_MODE,
+};
+
+struct mantis_pci;
+
+struct mantis_hwconfig {
+	char			*model_name;
+	char			*dev_type;
+	u32			ts_size;
+
+	enum mantis_baud	baud_rate;
+	enum mantis_parity	parity;
+	u32			bytes;
+
+	irqreturn_t (*irq_handler)(int irq, void *dev_id);
+	int (*frontend_init)(struct mantis_pci *mantis, struct dvb_frontend *fe);
+
+	u8			power;
+	u8			reset;
+
+	enum mantis_i2c_mode	i2c_mode;
+};
+
+struct mantis_pci {
+	unsigned int		verbose;
+
+	/*	PCI stuff		*/
+	u16			vendor_id;
+	u16			device_id;
+	u16			subsystem_vendor;
+	u16			subsystem_device;
+
+	u8			latency;
+
+	struct pci_dev		*pdev;
+
+	unsigned long		mantis_addr;
+	void __iomem		*mmio;
+
+	u8			irq;
+	u8			revision;
+
+	unsigned int		num;
+
+	/*	RISC Core		*/
+	u32			busy_block;
+	u32			last_block;
+	u8			*buf_cpu;
+	dma_addr_t		buf_dma;
+	u32			*risc_cpu;
+	dma_addr_t		risc_dma;
+
+	struct tasklet_struct	tasklet;
+
+	struct i2c_adapter	adapter;
+	int			i2c_rc;
+	wait_queue_head_t	i2c_wq;
+	struct mutex		i2c_lock;
+
+	/*	DVB stuff		*/
+	struct dvb_adapter	dvb_adapter;
+	struct dvb_frontend	*fe;
+	struct dvb_demux	demux;
+	struct dmxdev		dmxdev;
+	struct dmx_frontend	fe_hw;
+	struct dmx_frontend	fe_mem;
+	struct dvb_net		dvbnet;
+
+	u8			feeds;
+
+	struct mantis_hwconfig	*hwconfig;
+
+	u32			mantis_int_stat;
+	u32			mantis_int_mask;
+
+	/*	board specific		*/
+	u8			mac_address[8];
+	u32			sub_vendor_id;
+	u32			sub_device_id;
+
+	 /*	A12 A13 A14		*/
+	u32			gpio_status;
+
+	u32			gpif_status;
+
+	struct mantis_ca	*mantis_ca;
+
+	wait_queue_head_t	uart_wq;
+	struct work_struct	uart_work;
+	spinlock_t		uart_lock;
+
+	struct rc_dev		*rc;
+	char			input_name[80];
+	char			input_phys[80];
+};
+
+#define MANTIS_HIF_STATUS	(mantis->gpio_status)
+
+#endif /* __MANTIS_COMMON_H */
diff --git a/drivers/media/pci/mantis/mantis_core.c b/drivers/media/pci/mantis/mantis_core.c
new file mode 100644
index 0000000..684d906
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_core.c
@@ -0,0 +1,235 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "mantis_common.h"
+#include "mantis_core.h"
+#include "mantis_vp1033.h"
+#include "mantis_vp1034.h"
+#include "mantis_vp1041.h"
+#include "mantis_vp2033.h"
+#include "mantis_vp2040.h"
+#include "mantis_vp3030.h"
+
+static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
+{
+	int err;
+	struct i2c_msg msg[] = {
+		{
+			.addr = 0x50,
+			.flags = 0,
+			.buf = data,
+			.len = 1
+		}, {
+			.addr = 0x50,
+			.flags = I2C_M_RD,
+			.buf = data,
+			.len = length
+		},
+	};
+
+	err = i2c_transfer(&mantis->adapter, msg, 2);
+	if (err < 0) {
+		dprintk(verbose, MANTIS_ERROR, 1,
+			"ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >",
+			err, data[0], data[1]);
+
+		return err;
+	}
+
+	return 0;
+}
+
+static int write_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
+{
+	int err;
+
+	struct i2c_msg msg = {
+		.addr = 0x50,
+		.flags = 0,
+		.buf = data,
+		.len = length
+	};
+
+	err = i2c_transfer(&mantis->adapter, &msg, 1);
+	if (err < 0) {
+		dprintk(verbose, MANTIS_ERROR, 1,
+			"ERROR: i2c write: < err=%i length=0x%02x d0=0x%02x, d1=0x%02x >",
+			err, length, data[0], data[1]);
+
+		return err;
+	}
+
+	return 0;
+}
+
+static int get_mac_address(struct mantis_pci *mantis)
+{
+	int err;
+
+	mantis->mac_address[0] = 0x08;
+	err = read_eeprom_byte(mantis, &mantis->mac_address[0], 6);
+	if (err < 0) {
+		dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error");
+
+		return err;
+	}
+	dprintk(verbose, MANTIS_ERROR, 0,
+		"    MAC Address=[%pM]\n", mantis->mac_address);
+
+	return 0;
+}
+
+#define MANTIS_MODEL_UNKNOWN	"UNKNOWN"
+#define MANTIS_DEV_UNKNOWN	"UNKNOWN"
+
+struct mantis_hwconfig unknown_device = {
+	.model_name	= MANTIS_MODEL_UNKNOWN,
+	.dev_type	= MANTIS_DEV_UNKNOWN,
+};
+
+static void mantis_load_config(struct mantis_pci *mantis)
+{
+	switch (mantis->subsystem_device) {
+	case MANTIS_VP_1033_DVB_S:	/* VP-1033 */
+		mantis->hwconfig = &vp1033_mantis_config;
+		break;
+	case MANTIS_VP_1034_DVB_S:	/* VP-1034 */
+		mantis->hwconfig = &vp1034_mantis_config;
+		break;
+	case MANTIS_VP_1041_DVB_S2:	/* VP-1041 */
+	case TECHNISAT_SKYSTAR_HD2:
+		mantis->hwconfig = &vp1041_mantis_config;
+		break;
+	case MANTIS_VP_2033_DVB_C:	/* VP-2033 */
+		mantis->hwconfig = &vp2033_mantis_config;
+		break;
+	case MANTIS_VP_2040_DVB_C:	/* VP-2040 */
+	case CINERGY_C:	/* VP-2040 clone */
+	case TECHNISAT_CABLESTAR_HD2:
+		mantis->hwconfig = &vp2040_mantis_config;
+		break;
+	case MANTIS_VP_3030_DVB_T:	/* VP-3030 */
+		mantis->hwconfig = &vp3030_mantis_config;
+		break;
+	default:
+		mantis->hwconfig = &unknown_device;
+		break;
+	}
+}
+
+int mantis_core_init(struct mantis_pci *mantis)
+{
+	int err = 0;
+
+	mantis_load_config(mantis);
+	dprintk(verbose, MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n",
+		mantis->hwconfig->model_name, mantis->hwconfig->dev_type,
+		mantis->pdev->bus->number, PCI_SLOT(mantis->pdev->devfn), PCI_FUNC(mantis->pdev->devfn));
+	dprintk(verbose, MANTIS_ERROR, 0, "    Mantis Rev %d [%04x:%04x], ",
+		mantis->revision,
+		mantis->subsystem_vendor, mantis->subsystem_device);
+	dprintk(verbose, MANTIS_ERROR, 0,
+		"irq: %d, latency: %d\n    memory: 0x%lx, mmio: 0x%p\n",
+		mantis->pdev->irq, mantis->latency,
+		mantis->mantis_addr, mantis->mantis_mmio);
+
+	err = mantis_i2c_init(mantis);
+	if (err < 0) {
+		dprintk(verbose, MANTIS_ERROR, 1, "Mantis I2C init failed");
+		return err;
+	}
+	err = get_mac_address(mantis);
+	if (err < 0) {
+		dprintk(verbose, MANTIS_ERROR, 1, "get MAC address failed");
+		return err;
+	}
+	err = mantis_dma_init(mantis);
+	if (err < 0) {
+		dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA init failed");
+		return err;
+	}
+	err = mantis_dvb_init(mantis);
+	if (err < 0) {
+		dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB init failed");
+		return err;
+	}
+	err = mantis_uart_init(mantis);
+	if (err < 0) {
+		dprintk(verbose, MANTIS_DEBUG, 1, "Mantis UART init failed");
+		return err;
+	}
+
+	return 0;
+}
+
+int mantis_core_exit(struct mantis_pci *mantis)
+{
+	mantis_dma_stop(mantis);
+	dprintk(verbose, MANTIS_ERROR, 1, "DMA engine stopping");
+
+	mantis_uart_exit(mantis);
+	dprintk(verbose, MANTIS_ERROR, 1, "UART exit failed");
+
+	if (mantis_dma_exit(mantis) < 0)
+		dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed");
+	if (mantis_dvb_exit(mantis) < 0)
+		dprintk(verbose, MANTIS_ERROR, 1, "DVB exit failed");
+	if (mantis_i2c_exit(mantis) < 0)
+		dprintk(verbose, MANTIS_ERROR, 1, "I2C adapter delete.. failed");
+
+	return 0;
+}
+
+/* Turn the given bit on or off. */
+void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
+{
+	u32 cur;
+
+	cur = mmread(MANTIS_GPIF_ADDR);
+	if (value)
+		mantis->gpio_status = cur | (1 << bitpos);
+	else
+		mantis->gpio_status = cur & (~(1 << bitpos));
+
+	mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR);
+	mmwrite(0x00, MANTIS_GPIF_DOUT);
+	udelay(100);
+}
+
+/* direction = 0 , no CI passthrough ; 1 , CI passthrough */
+void mantis_set_direction(struct mantis_pci *mantis, int direction)
+{
+	u32 reg;
+
+	reg = mmread(0x28);
+	dprintk(verbose, MANTIS_DEBUG, 1, "TS direction setup");
+	if (direction == 0x01) {
+		/* to CI */
+		reg |= 0x04;
+		mmwrite(reg, 0x28);
+		reg &= 0xff - 0x04;
+		mmwrite(reg, 0x28);
+	} else {
+		reg &= 0xff - 0x04;
+		mmwrite(reg, 0x28);
+		reg |= 0x04;
+		mmwrite(reg, 0x28);
+	}
+}
diff --git a/drivers/media/pci/mantis/mantis_core.h b/drivers/media/pci/mantis/mantis_core.h
new file mode 100644
index 0000000..833ee42
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_core.h
@@ -0,0 +1,57 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_CORE_H
+#define __MANTIS_CORE_H
+
+#include "mantis_common.h"
+
+
+#define FE_TYPE_SAT	0
+#define FE_TYPE_CAB	1
+#define FE_TYPE_TER	2
+
+#define FE_TYPE_TS204	0
+#define FE_TYPE_TS188	1
+
+
+struct vendorname {
+	u8  *sub_vendor_name;
+	u32 sub_vendor_id;
+};
+
+struct devicetype {
+	u8  *sub_device_name;
+	u32 sub_device_id;
+	u8  device_type;
+	u32 type_flags;
+};
+
+
+extern int mantis_dma_init(struct mantis_pci *mantis);
+extern int mantis_dma_exit(struct mantis_pci *mantis);
+extern void mantis_dma_start(struct mantis_pci *mantis);
+extern void mantis_dma_stop(struct mantis_pci *mantis);
+extern int mantis_i2c_init(struct mantis_pci *mantis);
+extern int mantis_i2c_exit(struct mantis_pci *mantis);
+extern int mantis_core_init(struct mantis_pci *mantis);
+extern int mantis_core_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_CORE_H */
diff --git a/drivers/media/pci/mantis/mantis_dma.c b/drivers/media/pci/mantis/mantis_dma.c
new file mode 100644
index 0000000..566c407
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_dma.c
@@ -0,0 +1,230 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <asm/page.h>
+#include <linux/vmalloc.h>
+#include <linux/pci.h>
+
+#include <asm/irq.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_dma.h"
+
+#define RISC_WRITE		(0x01 << 28)
+#define RISC_JUMP		(0x07 << 28)
+#define RISC_IRQ		(0x01 << 24)
+
+#define RISC_STATUS(status)	((((~status) & 0x0f) << 20) | ((status & 0x0f) << 16))
+#define RISC_FLUSH(risc_pos)		(risc_pos = 0)
+#define RISC_INSTR(risc_pos, opcode)	(mantis->risc_cpu[risc_pos++] = cpu_to_le32(opcode))
+
+#define MANTIS_BUF_SIZE		(64 * 1024)
+#define MANTIS_BLOCK_BYTES      (MANTIS_BUF_SIZE / 4)
+#define MANTIS_DMA_TR_BYTES     (2 * 1024) /* upper limit: 4095 bytes. */
+#define MANTIS_BLOCK_COUNT	(MANTIS_BUF_SIZE / MANTIS_BLOCK_BYTES)
+
+#define MANTIS_DMA_TR_UNITS     (MANTIS_BLOCK_BYTES / MANTIS_DMA_TR_BYTES)
+/* MANTIS_BUF_SIZE / MANTIS_DMA_TR_UNITS must not exceed MANTIS_RISC_SIZE (4k RISC cmd buffer) */
+#define MANTIS_RISC_SIZE	PAGE_SIZE /* RISC program must fit here. */
+
+int mantis_dma_exit(struct mantis_pci *mantis)
+{
+	if (mantis->buf_cpu) {
+		dprintk(MANTIS_ERROR, 1,
+			"DMA=0x%lx cpu=0x%p size=%d",
+			(unsigned long) mantis->buf_dma,
+			 mantis->buf_cpu,
+			 MANTIS_BUF_SIZE);
+
+		pci_free_consistent(mantis->pdev, MANTIS_BUF_SIZE,
+				    mantis->buf_cpu, mantis->buf_dma);
+
+		mantis->buf_cpu = NULL;
+	}
+	if (mantis->risc_cpu) {
+		dprintk(MANTIS_ERROR, 1,
+			"RISC=0x%lx cpu=0x%p size=%lx",
+			(unsigned long) mantis->risc_dma,
+			mantis->risc_cpu,
+			MANTIS_RISC_SIZE);
+
+		pci_free_consistent(mantis->pdev, MANTIS_RISC_SIZE,
+				    mantis->risc_cpu, mantis->risc_dma);
+
+		mantis->risc_cpu = NULL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_dma_exit);
+
+static inline int mantis_alloc_buffers(struct mantis_pci *mantis)
+{
+	if (!mantis->buf_cpu) {
+		mantis->buf_cpu = pci_alloc_consistent(mantis->pdev,
+						       MANTIS_BUF_SIZE,
+						       &mantis->buf_dma);
+		if (!mantis->buf_cpu) {
+			dprintk(MANTIS_ERROR, 1,
+				"DMA buffer allocation failed");
+
+			goto err;
+		}
+		dprintk(MANTIS_ERROR, 1,
+			"DMA=0x%lx cpu=0x%p size=%d",
+			(unsigned long) mantis->buf_dma,
+			mantis->buf_cpu, MANTIS_BUF_SIZE);
+	}
+	if (!mantis->risc_cpu) {
+		mantis->risc_cpu = pci_alloc_consistent(mantis->pdev,
+							MANTIS_RISC_SIZE,
+							&mantis->risc_dma);
+
+		if (!mantis->risc_cpu) {
+			dprintk(MANTIS_ERROR, 1,
+				"RISC program allocation failed");
+
+			mantis_dma_exit(mantis);
+
+			goto err;
+		}
+		dprintk(MANTIS_ERROR, 1,
+			"RISC=0x%lx cpu=0x%p size=%lx",
+			(unsigned long) mantis->risc_dma,
+			mantis->risc_cpu, MANTIS_RISC_SIZE);
+	}
+
+	return 0;
+err:
+	dprintk(MANTIS_ERROR, 1, "Out of memory (?) .....");
+	return -ENOMEM;
+}
+
+int mantis_dma_init(struct mantis_pci *mantis)
+{
+	int err = 0;
+
+	dprintk(MANTIS_DEBUG, 1, "Mantis DMA init");
+	if (mantis_alloc_buffers(mantis) < 0) {
+		dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer");
+
+		/* Stop RISC Engine */
+		mmwrite(0, MANTIS_DMA_CTL);
+
+		goto err;
+	}
+
+	return 0;
+err:
+	return err;
+}
+EXPORT_SYMBOL_GPL(mantis_dma_init);
+
+static inline void mantis_risc_program(struct mantis_pci *mantis)
+{
+	u32 buf_pos = 0;
+	u32 line, step;
+	u32 risc_pos;
+
+	dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program");
+	RISC_FLUSH(risc_pos);
+
+	dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u, bytes per DMA tr %u",
+		MANTIS_BLOCK_COUNT, MANTIS_BLOCK_BYTES, MANTIS_DMA_TR_BYTES);
+
+	for (line = 0; line < MANTIS_BLOCK_COUNT; line++) {
+		for (step = 0; step < MANTIS_DMA_TR_UNITS; step++) {
+			dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d], step=[%d]", line, step);
+			if (step == 0) {
+				RISC_INSTR(risc_pos, RISC_WRITE	|
+					   RISC_IRQ	|
+					   RISC_STATUS(line) |
+					   MANTIS_DMA_TR_BYTES);
+			} else {
+				RISC_INSTR(risc_pos, RISC_WRITE | MANTIS_DMA_TR_BYTES);
+			}
+			RISC_INSTR(risc_pos, mantis->buf_dma + buf_pos);
+			buf_pos += MANTIS_DMA_TR_BYTES;
+		  }
+	}
+	RISC_INSTR(risc_pos, RISC_JUMP);
+	RISC_INSTR(risc_pos, mantis->risc_dma);
+}
+
+void mantis_dma_start(struct mantis_pci *mantis)
+{
+	dprintk(MANTIS_DEBUG, 1, "Mantis Start DMA engine");
+
+	mantis_risc_program(mantis);
+	mmwrite(mantis->risc_dma, MANTIS_RISC_START);
+	mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
+
+	mmwrite(0, MANTIS_DMA_CTL);
+	mantis->last_block = mantis->busy_block = 0;
+
+	mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK);
+
+	mmwrite(MANTIS_FIFO_EN | MANTIS_DCAP_EN
+			       | MANTIS_RISC_EN, MANTIS_DMA_CTL);
+
+}
+
+void mantis_dma_stop(struct mantis_pci *mantis)
+{
+	dprintk(MANTIS_DEBUG, 1, "Mantis Stop DMA engine");
+
+	mmwrite((mmread(MANTIS_GPIF_ADDR) & (~(MANTIS_GPIF_HIFRDWRN))), MANTIS_GPIF_ADDR);
+
+	mmwrite((mmread(MANTIS_DMA_CTL) & ~(MANTIS_FIFO_EN |
+					    MANTIS_DCAP_EN |
+					    MANTIS_RISC_EN)), MANTIS_DMA_CTL);
+
+	mmwrite(mmread(MANTIS_INT_STAT), MANTIS_INT_STAT);
+
+	mmwrite(mmread(MANTIS_INT_MASK) & ~(MANTIS_INT_RISCI |
+					    MANTIS_INT_RISCEN), MANTIS_INT_MASK);
+}
+
+
+void mantis_dma_xfer(unsigned long data)
+{
+	struct mantis_pci *mantis = (struct mantis_pci *) data;
+	struct mantis_hwconfig *config = mantis->hwconfig;
+
+	while (mantis->last_block != mantis->busy_block) {
+		dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]",
+			mantis->last_block, mantis->busy_block);
+
+		(config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter)
+		(&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES);
+		mantis->last_block = (mantis->last_block + 1) % MANTIS_BLOCK_COUNT;
+	}
+}
diff --git a/drivers/media/pci/mantis/mantis_dma.h b/drivers/media/pci/mantis/mantis_dma.h
new file mode 100644
index 0000000..6be00fa
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_dma.h
@@ -0,0 +1,30 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_DMA_H
+#define __MANTIS_DMA_H
+
+extern int mantis_dma_init(struct mantis_pci *mantis);
+extern int mantis_dma_exit(struct mantis_pci *mantis);
+extern void mantis_dma_start(struct mantis_pci *mantis);
+extern void mantis_dma_stop(struct mantis_pci *mantis);
+extern void mantis_dma_xfer(unsigned long data);
+
+#endif /* __MANTIS_DMA_H */
diff --git a/drivers/media/pci/mantis/mantis_dvb.c b/drivers/media/pci/mantis/mantis_dvb.c
new file mode 100644
index 0000000..5d15c6b
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_dvb.c
@@ -0,0 +1,301 @@
+/*
+	Mantis PCI bridge driver
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_dma.h"
+#include "mantis_ca.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power)
+{
+	struct mantis_hwconfig *config = mantis->hwconfig;
+
+	switch (power) {
+	case POWER_ON:
+		dprintk(MANTIS_DEBUG, 1, "Power ON");
+		mantis_gpio_set_bits(mantis, config->power, POWER_ON);
+		msleep(100);
+		mantis_gpio_set_bits(mantis, config->power, POWER_ON);
+		msleep(100);
+		break;
+
+	case POWER_OFF:
+		dprintk(MANTIS_DEBUG, 1, "Power OFF");
+		mantis_gpio_set_bits(mantis, config->power, POWER_OFF);
+		msleep(100);
+		break;
+
+	default:
+		dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power);
+		return -1;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_frontend_power);
+
+void mantis_frontend_soft_reset(struct mantis_pci *mantis)
+{
+	struct mantis_hwconfig *config = mantis->hwconfig;
+
+	dprintk(MANTIS_DEBUG, 1, "Frontend RESET");
+	mantis_gpio_set_bits(mantis, config->reset, 0);
+	msleep(100);
+	mantis_gpio_set_bits(mantis, config->reset, 0);
+	msleep(100);
+	mantis_gpio_set_bits(mantis, config->reset, 1);
+	msleep(100);
+	mantis_gpio_set_bits(mantis, config->reset, 1);
+	msleep(100);
+
+	return;
+}
+EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset);
+
+static int mantis_frontend_shutdown(struct mantis_pci *mantis)
+{
+	int err;
+
+	mantis_frontend_soft_reset(mantis);
+	err = mantis_frontend_power(mantis, POWER_OFF);
+	if (err != 0) {
+		dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct mantis_pci *mantis = dvbdmx->priv;
+
+	dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed");
+	if (!dvbdmx->dmx.frontend) {
+		dprintk(MANTIS_DEBUG, 1, "no frontend ?");
+		return -EINVAL;
+	}
+
+	mantis->feeds++;
+	dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d",	mantis->feeds);
+
+	if (mantis->feeds == 1)	 {
+		dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma");
+		mantis_dma_start(mantis);
+		tasklet_enable(&mantis->tasklet);
+	}
+
+	return mantis->feeds;
+}
+
+static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct mantis_pci *mantis = dvbdmx->priv;
+
+	dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed");
+	if (!dvbdmx->dmx.frontend) {
+		dprintk(MANTIS_DEBUG, 1, "no frontend ?");
+		return -EINVAL;
+	}
+
+	mantis->feeds--;
+	if (mantis->feeds == 0) {
+		dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma");
+		tasklet_disable(&mantis->tasklet);
+		mantis_dma_stop(mantis);
+	}
+
+	return 0;
+}
+
+int __devinit mantis_dvb_init(struct mantis_pci *mantis)
+{
+	struct mantis_hwconfig *config = mantis->hwconfig;
+	int result = -1;
+
+	dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter");
+
+	result = dvb_register_adapter(&mantis->dvb_adapter,
+				      "Mantis DVB adapter",
+				      THIS_MODULE,
+				      &mantis->pdev->dev,
+				      adapter_nr);
+
+	if (result < 0) {
+
+		dprintk(MANTIS_ERROR, 1, "Error registering adapter");
+		return -ENODEV;
+	}
+
+	mantis->dvb_adapter.priv	= mantis;
+	mantis->demux.dmx.capabilities	= DMX_TS_FILTERING	|
+					 DMX_SECTION_FILTERING	|
+					 DMX_MEMORY_BASED_FILTERING;
+
+	mantis->demux.priv		= mantis;
+	mantis->demux.filternum		= 256;
+	mantis->demux.feednum		= 256;
+	mantis->demux.start_feed	= mantis_dvb_start_feed;
+	mantis->demux.stop_feed		= mantis_dvb_stop_feed;
+	mantis->demux.write_to_decoder	= NULL;
+
+	dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init");
+	result = dvb_dmx_init(&mantis->demux);
+	if (result < 0) {
+		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+
+		goto err0;
+	}
+
+	mantis->dmxdev.filternum	= 256;
+	mantis->dmxdev.demux		= &mantis->demux.dmx;
+	mantis->dmxdev.capabilities	= 0;
+	dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init");
+
+	result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter);
+	if (result < 0) {
+
+		dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result);
+		goto err1;
+	}
+
+	mantis->fe_hw.source		= DMX_FRONTEND_0;
+	result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+	if (result < 0) {
+
+		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+		goto err2;
+	}
+
+	mantis->fe_mem.source		= DMX_MEMORY_FE;
+	result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+	if (result < 0) {
+		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+		goto err3;
+	}
+
+	result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+	if (result < 0) {
+		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+		goto err4;
+	}
+
+	dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);
+	tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis);
+	tasklet_disable(&mantis->tasklet);
+	if (mantis->hwconfig) {
+		result = config->frontend_init(mantis, mantis->fe);
+		if (result < 0) {
+			dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!");
+			goto err5;
+		} else {
+			if (mantis->fe == NULL) {
+				dprintk(MANTIS_ERROR, 1, "FE <NULL>");
+				goto err5;
+			}
+
+			if (dvb_register_frontend(&mantis->dvb_adapter, mantis->fe)) {
+				dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed");
+
+				if (mantis->fe->ops.release)
+					mantis->fe->ops.release(mantis->fe);
+
+				mantis->fe = NULL;
+				goto err5;
+			}
+		}
+	}
+
+	return 0;
+
+	/* Error conditions ..	*/
+err5:
+	tasklet_kill(&mantis->tasklet);
+	dvb_net_release(&mantis->dvbnet);
+	if (mantis->fe) {
+		dvb_unregister_frontend(mantis->fe);
+		dvb_frontend_detach(mantis->fe);
+	}
+err4:
+	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+
+err3:
+	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+
+err2:
+	dvb_dmxdev_release(&mantis->dmxdev);
+
+err1:
+	dvb_dmx_release(&mantis->demux);
+
+err0:
+	dvb_unregister_adapter(&mantis->dvb_adapter);
+
+	return result;
+}
+EXPORT_SYMBOL_GPL(mantis_dvb_init);
+
+int __devexit mantis_dvb_exit(struct mantis_pci *mantis)
+{
+	int err;
+
+	if (mantis->fe) {
+		/* mantis_ca_exit(mantis); */
+		err = mantis_frontend_shutdown(mantis);
+		if (err != 0)
+			dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err);
+		dvb_unregister_frontend(mantis->fe);
+		dvb_frontend_detach(mantis->fe);
+	}
+
+	tasklet_kill(&mantis->tasklet);
+	dvb_net_release(&mantis->dvbnet);
+
+	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+
+	dvb_dmxdev_release(&mantis->dmxdev);
+	dvb_dmx_release(&mantis->demux);
+
+	dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter");
+	dvb_unregister_adapter(&mantis->dvb_adapter);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_dvb_exit);
diff --git a/drivers/media/pci/mantis/mantis_dvb.h b/drivers/media/pci/mantis/mantis_dvb.h
new file mode 100644
index 0000000..464199d
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_dvb.h
@@ -0,0 +1,35 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_DVB_H
+#define __MANTIS_DVB_H
+
+enum mantis_power {
+	POWER_OFF	= 0,
+	POWER_ON	= 1
+};
+
+extern int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power);
+extern void mantis_frontend_soft_reset(struct mantis_pci *mantis);
+
+extern int mantis_dvb_init(struct mantis_pci *mantis);
+extern int mantis_dvb_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_DVB_H */
diff --git a/drivers/media/pci/mantis/mantis_evm.c b/drivers/media/pci/mantis/mantis_evm.c
new file mode 100644
index 0000000..71ce528
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_evm.c
@@ -0,0 +1,117 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_link.h"
+#include "mantis_hif.h"
+#include "mantis_reg.h"
+
+static void mantis_hifevm_work(struct work_struct *work)
+{
+	struct mantis_ca *ca = container_of(work, struct mantis_ca, hif_evm_work);
+	struct mantis_pci *mantis = ca->ca_priv;
+
+	u32 gpif_stat;
+
+	gpif_stat = mmread(MANTIS_GPIF_STATUS);
+
+	if (gpif_stat & MANTIS_GPIF_DETSTAT) {
+		if (gpif_stat & MANTIS_CARD_PLUGIN) {
+			dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Plugin", mantis->num);
+			mmwrite(0xdada0000, MANTIS_CARD_RESET);
+			mantis_event_cam_plugin(ca);
+			dvb_ca_en50221_camchange_irq(&ca->en50221,
+						     0,
+						     DVB_CA_EN50221_CAMCHANGE_INSERTED);
+		}
+	} else {
+		if (gpif_stat & MANTIS_CARD_PLUGOUT) {
+			dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Unplug", mantis->num);
+			mmwrite(0xdada0000, MANTIS_CARD_RESET);
+			mantis_event_cam_unplug(ca);
+			dvb_ca_en50221_camchange_irq(&ca->en50221,
+						     0,
+						     DVB_CA_EN50221_CAMCHANGE_REMOVED);
+		}
+	}
+
+	if (mantis->gpif_status & MANTIS_GPIF_EXTIRQ)
+		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Ext IRQ", mantis->num);
+
+	if (mantis->gpif_status & MANTIS_SBUF_WSTO)
+		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Timeout", mantis->num);
+
+	if (mantis->gpif_status & MANTIS_GPIF_OTHERR)
+		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Alignment Error", mantis->num);
+
+	if (gpif_stat & MANTIS_SBUF_OVFLW)
+		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Overflow", mantis->num);
+
+	if (gpif_stat & MANTIS_GPIF_BRRDY)
+		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Read Ready", mantis->num);
+
+	if (gpif_stat & MANTIS_GPIF_INTSTAT)
+		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): GPIF IRQ", mantis->num);
+
+	if (gpif_stat & MANTIS_SBUF_EMPTY)
+		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Empty", mantis->num);
+
+	if (gpif_stat & MANTIS_SBUF_OPDONE) {
+		dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer operation complete", mantis->num);
+		ca->sbuf_status = MANTIS_SBUF_DATA_AVAIL;
+		ca->hif_event = MANTIS_SBUF_OPDONE;
+		wake_up(&ca->hif_opdone_wq);
+	}
+}
+
+int mantis_evmgr_init(struct mantis_ca *ca)
+{
+	struct mantis_pci *mantis = ca->ca_priv;
+
+	dprintk(MANTIS_DEBUG, 1, "Initializing Mantis Host I/F Event manager");
+	INIT_WORK(&ca->hif_evm_work, mantis_hifevm_work);
+	mantis_pcmcia_init(ca);
+	schedule_work(&ca->hif_evm_work);
+	mantis_hif_init(ca);
+	return 0;
+}
+
+void mantis_evmgr_exit(struct mantis_ca *ca)
+{
+	struct mantis_pci *mantis = ca->ca_priv;
+
+	dprintk(MANTIS_DEBUG, 1, "Mantis Host I/F Event manager exiting");
+	flush_work_sync(&ca->hif_evm_work);
+	mantis_hif_exit(ca);
+	mantis_pcmcia_exit(ca);
+}
diff --git a/drivers/media/pci/mantis/mantis_hif.c b/drivers/media/pci/mantis/mantis_hif.c
new file mode 100644
index 0000000..10c68df
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_hif.c
@@ -0,0 +1,239 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+
+#include <linux/interrupt.h>
+#include <asm/io.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+
+#include "mantis_hif.h"
+#include "mantis_link.h" /* temporary due to physical layer stuff */
+
+#include "mantis_reg.h"
+
+
+static int mantis_hif_sbuf_opdone_wait(struct mantis_ca *ca)
+{
+	struct mantis_pci *mantis = ca->ca_priv;
+	int rc = 0;
+
+	if (wait_event_timeout(ca->hif_opdone_wq,
+			       ca->hif_event & MANTIS_SBUF_OPDONE,
+			       msecs_to_jiffies(500)) == -ERESTARTSYS) {
+
+		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Smart buffer operation timeout !", mantis->num);
+		rc = -EREMOTEIO;
+	}
+	dprintk(MANTIS_DEBUG, 1, "Smart Buffer Operation complete");
+	ca->hif_event &= ~MANTIS_SBUF_OPDONE;
+	return rc;
+}
+
+static int mantis_hif_write_wait(struct mantis_ca *ca)
+{
+	struct mantis_pci *mantis = ca->ca_priv;
+	u32 opdone = 0, timeout = 0;
+	int rc = 0;
+
+	if (wait_event_timeout(ca->hif_write_wq,
+			       mantis->gpif_status & MANTIS_GPIF_WRACK,
+			       msecs_to_jiffies(500)) == -ERESTARTSYS) {
+
+		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write ACK timed out !", mantis->num);
+		rc = -EREMOTEIO;
+	}
+	dprintk(MANTIS_DEBUG, 1, "Write Acknowledged");
+	mantis->gpif_status &= ~MANTIS_GPIF_WRACK;
+	while (!opdone) {
+		opdone = (mmread(MANTIS_GPIF_STATUS) & MANTIS_SBUF_OPDONE);
+		udelay(500);
+		timeout++;
+		if (timeout > 100) {
+			dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write operation timed out!", mantis->num);
+			rc = -ETIMEDOUT;
+			break;
+		}
+	}
+	dprintk(MANTIS_DEBUG, 1, "HIF Write success");
+	return rc;
+}
+
+
+int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr)
+{
+	struct mantis_pci *mantis = ca->ca_priv;
+	u32 hif_addr = 0, data, count = 4;
+
+	dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Read", mantis->num);
+	mutex_lock(&ca->ca_lock);
+	hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+	hif_addr &= ~MANTIS_GPIF_PCMCIAIOM;
+	hif_addr |=  MANTIS_HIF_STATUS;
+	hif_addr |=  addr;
+
+	mmwrite(hif_addr, MANTIS_GPIF_BRADDR);
+	mmwrite(count, MANTIS_GPIF_BRBYTES);
+	udelay(20);
+	mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
+
+	if (mantis_hif_sbuf_opdone_wait(ca) != 0) {
+		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): GPIF Smart Buffer operation failed", mantis->num);
+		mutex_unlock(&ca->ca_lock);
+		return -EREMOTEIO;
+	}
+	data = mmread(MANTIS_GPIF_DIN);
+	mutex_unlock(&ca->ca_lock);
+	dprintk(MANTIS_DEBUG, 1, "Mem Read: 0x%02x", data);
+	return (data >> 24) & 0xff;
+}
+
+int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data)
+{
+	struct mantis_slot *slot = ca->slot;
+	struct mantis_pci *mantis = ca->ca_priv;
+	u32 hif_addr = 0;
+
+	dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Write", mantis->num);
+	mutex_lock(&ca->ca_lock);
+	hif_addr &= ~MANTIS_GPIF_HIFRDWRN;
+	hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+	hif_addr &= ~MANTIS_GPIF_PCMCIAIOM;
+	hif_addr |=  MANTIS_HIF_STATUS;
+	hif_addr |=  addr;
+
+	mmwrite(slot->slave_cfg, MANTIS_GPIF_CFGSLA); /* Slot0 alone for now */
+	mmwrite(hif_addr, MANTIS_GPIF_ADDR);
+	mmwrite(data, MANTIS_GPIF_DOUT);
+
+	if (mantis_hif_write_wait(ca) != 0) {
+		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
+		mutex_unlock(&ca->ca_lock);
+		return -EREMOTEIO;
+	}
+	dprintk(MANTIS_DEBUG, 1, "Mem Write: (0x%02x to 0x%02x)", data, addr);
+	mutex_unlock(&ca->ca_lock);
+
+	return 0;
+}
+
+int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr)
+{
+	struct mantis_pci *mantis = ca->ca_priv;
+	u32 data, hif_addr = 0;
+
+	dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Read", mantis->num);
+	mutex_lock(&ca->ca_lock);
+	hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+	hif_addr |=  MANTIS_GPIF_PCMCIAIOM;
+	hif_addr |=  MANTIS_HIF_STATUS;
+	hif_addr |=  addr;
+
+	mmwrite(hif_addr, MANTIS_GPIF_BRADDR);
+	mmwrite(1, MANTIS_GPIF_BRBYTES);
+	udelay(20);
+	mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
+
+	if (mantis_hif_sbuf_opdone_wait(ca) != 0) {
+		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
+		mutex_unlock(&ca->ca_lock);
+		return -EREMOTEIO;
+	}
+	data = mmread(MANTIS_GPIF_DIN);
+	dprintk(MANTIS_DEBUG, 1, "I/O Read: 0x%02x", data);
+	udelay(50);
+	mutex_unlock(&ca->ca_lock);
+
+	return (u8) data;
+}
+
+int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data)
+{
+	struct mantis_pci *mantis = ca->ca_priv;
+	u32 hif_addr = 0;
+
+	dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Write", mantis->num);
+	mutex_lock(&ca->ca_lock);
+	hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+	hif_addr &= ~MANTIS_GPIF_HIFRDWRN;
+	hif_addr |=  MANTIS_GPIF_PCMCIAIOM;
+	hif_addr |=  MANTIS_HIF_STATUS;
+	hif_addr |=  addr;
+
+	mmwrite(hif_addr, MANTIS_GPIF_ADDR);
+	mmwrite(data, MANTIS_GPIF_DOUT);
+
+	if (mantis_hif_write_wait(ca) != 0) {
+		dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
+		mutex_unlock(&ca->ca_lock);
+		return -EREMOTEIO;
+	}
+	dprintk(MANTIS_DEBUG, 1, "I/O Write: (0x%02x to 0x%02x)", data, addr);
+	mutex_unlock(&ca->ca_lock);
+	udelay(50);
+
+	return 0;
+}
+
+int mantis_hif_init(struct mantis_ca *ca)
+{
+	struct mantis_slot *slot = ca->slot;
+	struct mantis_pci *mantis = ca->ca_priv;
+	u32 irqcfg;
+
+	slot[0].slave_cfg = 0x70773028;
+	dprintk(MANTIS_ERROR, 1, "Adapter(%d) Initializing Mantis Host Interface", mantis->num);
+
+	mutex_lock(&ca->ca_lock);
+	irqcfg = mmread(MANTIS_GPIF_IRQCFG);
+	irqcfg = MANTIS_MASK_BRRDY	|
+		 MANTIS_MASK_WRACK	|
+		 MANTIS_MASK_EXTIRQ	|
+		 MANTIS_MASK_WSTO	|
+		 MANTIS_MASK_OTHERR	|
+		 MANTIS_MASK_OVFLW;
+
+	mmwrite(irqcfg, MANTIS_GPIF_IRQCFG);
+	mutex_unlock(&ca->ca_lock);
+
+	return 0;
+}
+
+void mantis_hif_exit(struct mantis_ca *ca)
+{
+	struct mantis_pci *mantis = ca->ca_priv;
+	u32 irqcfg;
+
+	dprintk(MANTIS_ERROR, 1, "Adapter(%d) Exiting Mantis Host Interface", mantis->num);
+	mutex_lock(&ca->ca_lock);
+	irqcfg = mmread(MANTIS_GPIF_IRQCFG);
+	irqcfg &= ~MANTIS_MASK_BRRDY;
+	mmwrite(irqcfg, MANTIS_GPIF_IRQCFG);
+	mutex_unlock(&ca->ca_lock);
+}
diff --git a/drivers/media/pci/mantis/mantis_hif.h b/drivers/media/pci/mantis/mantis_hif.h
new file mode 100644
index 0000000..9094f9e
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_hif.h
@@ -0,0 +1,29 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_HIF_H
+#define __MANTIS_HIF_H
+
+#define MANTIS_HIF_MEMRD		1
+#define MANTIS_HIF_MEMWR		2
+#define MANTIS_HIF_IOMRD		3
+#define MANTIS_HIF_IOMWR		4
+
+#endif /* __MANTIS_HIF_H */
diff --git a/drivers/media/pci/mantis/mantis_i2c.c b/drivers/media/pci/mantis/mantis_i2c.c
new file mode 100644
index 0000000..e779451
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_i2c.c
@@ -0,0 +1,266 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <asm/io.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_i2c.h"
+
+#define TRIALS			10000
+
+static int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg)
+{
+	u32 rxd, i, stat, trials;
+
+	dprintk(MANTIS_INFO, 0, "        %s:  Address=[0x%02x] <R>[ ",
+		__func__, msg->addr);
+
+	for (i = 0; i < msg->len; i++) {
+		rxd = (msg->addr << 25) | (1 << 24)
+					| MANTIS_I2C_RATE_3
+					| MANTIS_I2C_STOP
+					| MANTIS_I2C_PGMODE;
+
+		if (i == (msg->len - 1))
+			rxd &= ~MANTIS_I2C_STOP;
+
+		mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
+		mmwrite(rxd, MANTIS_I2CDATA_CTL);
+
+		/* wait for xfer completion */
+		for (trials = 0; trials < TRIALS; trials++) {
+			stat = mmread(MANTIS_INT_STAT);
+			if (stat & MANTIS_INT_I2CDONE)
+				break;
+		}
+
+		dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
+
+		/* wait for xfer completion */
+		for (trials = 0; trials < TRIALS; trials++) {
+			stat = mmread(MANTIS_INT_STAT);
+			if (stat & MANTIS_INT_I2CRACK)
+				break;
+		}
+
+		dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
+
+		rxd = mmread(MANTIS_I2CDATA_CTL);
+		msg->buf[i] = (u8)((rxd >> 8) & 0xFF);
+		dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
+	}
+	dprintk(MANTIS_INFO, 0, "]\n");
+
+	return 0;
+}
+
+static int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg)
+{
+	int i;
+	u32 txd = 0, stat, trials;
+
+	dprintk(MANTIS_INFO, 0, "        %s: Address=[0x%02x] <W>[ ",
+		__func__, msg->addr);
+
+	for (i = 0; i < msg->len; i++) {
+		dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
+		txd = (msg->addr << 25) | (msg->buf[i] << 8)
+					| MANTIS_I2C_RATE_3
+					| MANTIS_I2C_STOP
+					| MANTIS_I2C_PGMODE;
+
+		if (i == (msg->len - 1))
+			txd &= ~MANTIS_I2C_STOP;
+
+		mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
+		mmwrite(txd, MANTIS_I2CDATA_CTL);
+
+		/* wait for xfer completion */
+		for (trials = 0; trials < TRIALS; trials++) {
+			stat = mmread(MANTIS_INT_STAT);
+			if (stat & MANTIS_INT_I2CDONE)
+				break;
+		}
+
+		dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
+
+		/* wait for xfer completion */
+		for (trials = 0; trials < TRIALS; trials++) {
+			stat = mmread(MANTIS_INT_STAT);
+			if (stat & MANTIS_INT_I2CRACK)
+				break;
+		}
+
+		dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
+	}
+	dprintk(MANTIS_INFO, 0, "]\n");
+
+	return 0;
+}
+
+static int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
+{
+	int ret = 0, i = 0, trials;
+	u32 stat, data, txd;
+	struct mantis_pci *mantis;
+	struct mantis_hwconfig *config;
+
+	mantis = i2c_get_adapdata(adapter);
+	BUG_ON(!mantis);
+	config = mantis->hwconfig;
+	BUG_ON(!config);
+
+	dprintk(MANTIS_DEBUG, 1, "Messages:%d", num);
+	mutex_lock(&mantis->i2c_lock);
+
+	while (i < num) {
+		/* Byte MODE */
+		if ((config->i2c_mode & MANTIS_BYTE_MODE) &&
+		    ((i + 1) < num)			&&
+		    (msgs[i].len < 2)			&&
+		    (msgs[i + 1].len < 2)		&&
+		    (msgs[i + 1].flags & I2C_M_RD)) {
+
+			dprintk(MANTIS_DEBUG, 0, "        Byte MODE:\n");
+
+			/* Read operation */
+			txd = msgs[i].addr << 25 | (0x1 << 24)
+						 | (msgs[i].buf[0] << 16)
+						 | MANTIS_I2C_RATE_3;
+
+			mmwrite(txd, MANTIS_I2CDATA_CTL);
+			/* wait for xfer completion */
+			for (trials = 0; trials < TRIALS; trials++) {
+				stat = mmread(MANTIS_INT_STAT);
+				if (stat & MANTIS_INT_I2CDONE)
+					break;
+			}
+
+			/* check for xfer completion */
+			if (stat & MANTIS_INT_I2CDONE) {
+				/* check xfer was acknowledged */
+				if (stat & MANTIS_INT_I2CRACK) {
+					data = mmread(MANTIS_I2CDATA_CTL);
+					msgs[i + 1].buf[0] = (data >> 8) & 0xff;
+					dprintk(MANTIS_DEBUG, 0, "        Byte <%d> RXD=0x%02x  [%02x]\n", 0x0, data, msgs[i + 1].buf[0]);
+				} else {
+					/* I/O error */
+					dprintk(MANTIS_ERROR, 1, "        I/O error, LINE:%d", __LINE__);
+					ret = -EIO;
+					break;
+				}
+			} else {
+				/* I/O error */
+				dprintk(MANTIS_ERROR, 1, "        I/O error, LINE:%d", __LINE__);
+				ret = -EIO;
+				break;
+			}
+			i += 2; /* Write/Read operation in one go */
+		}
+
+		if (i < num) {
+			if (msgs[i].flags & I2C_M_RD)
+				ret = mantis_i2c_read(mantis, &msgs[i]);
+			else
+				ret = mantis_i2c_write(mantis, &msgs[i]);
+
+			i++;
+			if (ret < 0)
+				goto bail_out;
+		}
+
+	}
+
+	mutex_unlock(&mantis->i2c_lock);
+
+	return num;
+
+bail_out:
+	mutex_unlock(&mantis->i2c_lock);
+	return ret;
+}
+
+static u32 mantis_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm mantis_algo = {
+	.master_xfer		= mantis_i2c_xfer,
+	.functionality		= mantis_i2c_func,
+};
+
+int __devinit mantis_i2c_init(struct mantis_pci *mantis)
+{
+	u32 intstat, intmask;
+	struct i2c_adapter *i2c_adapter = &mantis->adapter;
+	struct pci_dev *pdev		= mantis->pdev;
+
+	init_waitqueue_head(&mantis->i2c_wq);
+	mutex_init(&mantis->i2c_lock);
+	strncpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name));
+	i2c_set_adapdata(i2c_adapter, mantis);
+
+	i2c_adapter->owner	= THIS_MODULE;
+	i2c_adapter->algo	= &mantis_algo;
+	i2c_adapter->algo_data	= NULL;
+	i2c_adapter->timeout	= 500;
+	i2c_adapter->retries	= 3;
+	i2c_adapter->dev.parent	= &pdev->dev;
+
+	mantis->i2c_rc		= i2c_add_adapter(i2c_adapter);
+	if (mantis->i2c_rc < 0)
+		return mantis->i2c_rc;
+
+	dprintk(MANTIS_DEBUG, 1, "Initializing I2C ..");
+
+	intstat = mmread(MANTIS_INT_STAT);
+	intmask = mmread(MANTIS_INT_MASK);
+	mmwrite(intstat, MANTIS_INT_STAT);
+	dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
+	intmask = mmread(MANTIS_INT_MASK);
+	mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_i2c_init);
+
+int mantis_i2c_exit(struct mantis_pci *mantis)
+{
+	u32 intmask;
+
+	dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
+	intmask = mmread(MANTIS_INT_MASK);
+	mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK);
+
+	dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter");
+	return i2c_del_adapter(&mantis->adapter);
+}
+EXPORT_SYMBOL_GPL(mantis_i2c_exit);
diff --git a/drivers/media/pci/mantis/mantis_i2c.h b/drivers/media/pci/mantis/mantis_i2c.h
new file mode 100644
index 0000000..1342df2
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_i2c.h
@@ -0,0 +1,30 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_I2C_H
+#define __MANTIS_I2C_H
+
+#define I2C_STOP		(1 <<  0)
+#define I2C_READ		(1 <<  1)
+
+extern int mantis_i2c_init(struct mantis_pci *mantis);
+extern int mantis_i2c_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_I2C_H */
diff --git a/drivers/media/pci/mantis/mantis_input.c b/drivers/media/pci/mantis/mantis_input.c
new file mode 100644
index 0000000..db6d54d
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_input.c
@@ -0,0 +1,159 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <media/rc-core.h>
+#include <linux/pci.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_uart.h"
+
+#define MODULE_NAME "mantis_core"
+#define RC_MAP_MANTIS "rc-mantis"
+
+static struct rc_map_table mantis_ir_table[] = {
+	{ 0x29, KEY_POWER	},
+	{ 0x28, KEY_FAVORITES	},
+	{ 0x30, KEY_TEXT	},
+	{ 0x17, KEY_INFO	}, /* Preview */
+	{ 0x23, KEY_EPG		},
+	{ 0x3b, KEY_F22		}, /* Record List */
+	{ 0x3c, KEY_1		},
+	{ 0x3e, KEY_2		},
+	{ 0x39, KEY_3		},
+	{ 0x36, KEY_4		},
+	{ 0x22, KEY_5		},
+	{ 0x20, KEY_6		},
+	{ 0x32, KEY_7		},
+	{ 0x26, KEY_8		},
+	{ 0x24, KEY_9		},
+	{ 0x2a, KEY_0		},
+
+	{ 0x33, KEY_CANCEL	},
+	{ 0x2c, KEY_BACK	},
+	{ 0x15, KEY_CLEAR	},
+	{ 0x3f, KEY_TAB		},
+	{ 0x10, KEY_ENTER	},
+	{ 0x14, KEY_UP		},
+	{ 0x0d, KEY_RIGHT	},
+	{ 0x0e, KEY_DOWN	},
+	{ 0x11, KEY_LEFT	},
+
+	{ 0x21, KEY_VOLUMEUP	},
+	{ 0x35, KEY_VOLUMEDOWN	},
+	{ 0x3d, KEY_CHANNELDOWN	},
+	{ 0x3a, KEY_CHANNELUP	},
+	{ 0x2e, KEY_RECORD	},
+	{ 0x2b, KEY_PLAY	},
+	{ 0x13, KEY_PAUSE	},
+	{ 0x25, KEY_STOP	},
+
+	{ 0x1f, KEY_REWIND	},
+	{ 0x2d, KEY_FASTFORWARD	},
+	{ 0x1e, KEY_PREVIOUS	}, /* Replay |< */
+	{ 0x1d, KEY_NEXT	}, /* Skip   >| */
+
+	{ 0x0b, KEY_CAMERA	}, /* Capture */
+	{ 0x0f, KEY_LANGUAGE	}, /* SAP */
+	{ 0x18, KEY_MODE	}, /* PIP */
+	{ 0x12, KEY_ZOOM	}, /* Full screen */
+	{ 0x1c, KEY_SUBTITLE	},
+	{ 0x2f, KEY_MUTE	},
+	{ 0x16, KEY_F20		}, /* L/R */
+	{ 0x38, KEY_F21		}, /* Hibernate */
+
+	{ 0x37, KEY_SWITCHVIDEOMODE }, /* A/V */
+	{ 0x31, KEY_AGAIN	}, /* Recall */
+	{ 0x1a, KEY_KPPLUS	}, /* Zoom+ */
+	{ 0x19, KEY_KPMINUS	}, /* Zoom- */
+	{ 0x27, KEY_RED		},
+	{ 0x0C, KEY_GREEN	},
+	{ 0x01, KEY_YELLOW	},
+	{ 0x00, KEY_BLUE	},
+};
+
+static struct rc_map_list ir_mantis_map = {
+	.map = {
+		.scan = mantis_ir_table,
+		.size = ARRAY_SIZE(mantis_ir_table),
+		.rc_type = RC_TYPE_UNKNOWN,
+		.name = RC_MAP_MANTIS,
+	}
+};
+
+int mantis_input_init(struct mantis_pci *mantis)
+{
+	struct rc_dev *dev;
+	int err;
+
+	err = rc_map_register(&ir_mantis_map);
+	if (err)
+		goto out;
+
+	dev = rc_allocate_device();
+	if (!dev) {
+		dprintk(MANTIS_ERROR, 1, "Remote device allocation failed");
+		err = -ENOMEM;
+		goto out_map;
+	}
+
+	sprintf(mantis->input_name, "Mantis %s IR receiver", mantis->hwconfig->model_name);
+	sprintf(mantis->input_phys, "pci-%s/ir0", pci_name(mantis->pdev));
+
+	dev->input_name         = mantis->input_name;
+	dev->input_phys         = mantis->input_phys;
+	dev->input_id.bustype   = BUS_PCI;
+	dev->input_id.vendor    = mantis->vendor_id;
+	dev->input_id.product   = mantis->device_id;
+	dev->input_id.version   = 1;
+	dev->driver_name        = MODULE_NAME;
+	dev->map_name           = RC_MAP_MANTIS;
+	dev->dev.parent         = &mantis->pdev->dev;
+
+	err = rc_register_device(dev);
+	if (err) {
+		dprintk(MANTIS_ERROR, 1, "IR device registration failed, ret = %d", err);
+		goto out_dev;
+	}
+
+	mantis->rc = dev;
+	return 0;
+
+out_dev:
+	rc_free_device(dev);
+out_map:
+	rc_map_unregister(&ir_mantis_map);
+out:
+	return err;
+}
+
+int mantis_exit(struct mantis_pci *mantis)
+{
+	rc_unregister_device(mantis->rc);
+	rc_map_unregister(&ir_mantis_map);
+	return 0;
+}
+
diff --git a/drivers/media/pci/mantis/mantis_ioc.c b/drivers/media/pci/mantis/mantis_ioc.c
new file mode 100644
index 0000000..24fcdc6
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_ioc.c
@@ -0,0 +1,124 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_ioc.h"
+
+static int read_eeprom_bytes(struct mantis_pci *mantis, u8 reg, u8 *data, u8 length)
+{
+	struct i2c_adapter *adapter = &mantis->adapter;
+	int err;
+	u8 buf = reg;
+
+	struct i2c_msg msg[] = {
+		{ .addr = 0x50, .flags = 0, .buf = &buf, .len = 1 },
+		{ .addr = 0x50, .flags = I2C_M_RD, .buf = data, .len = length },
+	};
+
+	err = i2c_transfer(adapter, msg, 2);
+	if (err < 0) {
+		dprintk(MANTIS_ERROR, 1, "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >",
+			err, data[0], data[1]);
+
+		return err;
+	}
+
+	return 0;
+}
+int mantis_get_mac(struct mantis_pci *mantis)
+{
+	int err;
+	u8 mac_addr[6] = {0};
+
+	err = read_eeprom_bytes(mantis, 0x08, mac_addr, 6);
+	if (err < 0) {
+		dprintk(MANTIS_ERROR, 1, "ERROR: Mantis EEPROM read error <%d>", err);
+
+		return err;
+	}
+
+	dprintk(MANTIS_ERROR, 0, "    MAC Address=[%pM]\n", mac_addr);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_get_mac);
+
+/* Turn the given bit on or off. */
+void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
+{
+	u32 cur;
+
+	dprintk(MANTIS_DEBUG, 1, "Set Bit <%d> to <%d>", bitpos, value);
+	cur = mmread(MANTIS_GPIF_ADDR);
+	if (value)
+		mantis->gpio_status = cur | (1 << bitpos);
+	else
+		mantis->gpio_status = cur & (~(1 << bitpos));
+
+	dprintk(MANTIS_DEBUG, 1, "GPIO Value <%02x>", mantis->gpio_status);
+	mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR);
+	mmwrite(0x00, MANTIS_GPIF_DOUT);
+}
+EXPORT_SYMBOL_GPL(mantis_gpio_set_bits);
+
+int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl)
+{
+	u32 reg;
+
+	reg = mmread(MANTIS_CONTROL);
+	switch (stream_ctl) {
+	case STREAM_TO_HIF:
+		dprintk(MANTIS_DEBUG, 1, "Set stream to HIF");
+		reg &= 0xff - MANTIS_BYPASS;
+		mmwrite(reg, MANTIS_CONTROL);
+		reg |= MANTIS_BYPASS;
+		mmwrite(reg, MANTIS_CONTROL);
+		break;
+
+	case STREAM_TO_CAM:
+		dprintk(MANTIS_DEBUG, 1, "Set stream to CAM");
+		reg |= MANTIS_BYPASS;
+		mmwrite(reg, MANTIS_CONTROL);
+		reg &= 0xff - MANTIS_BYPASS;
+		mmwrite(reg, MANTIS_CONTROL);
+		break;
+	default:
+		dprintk(MANTIS_ERROR, 1, "Unknown MODE <%02x>", stream_ctl);
+		return -1;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_stream_control);
diff --git a/drivers/media/pci/mantis/mantis_ioc.h b/drivers/media/pci/mantis/mantis_ioc.h
new file mode 100644
index 0000000..d56e002
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_ioc.h
@@ -0,0 +1,51 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_IOC_H
+#define __MANTIS_IOC_H
+
+#define GPIF_A00		0x00
+#define GPIF_A01		0x01
+#define GPIF_A02		0x02
+#define GPIF_A03		0x03
+#define GPIF_A04		0x04
+#define GPIF_A05		0x05
+#define GPIF_A06		0x06
+#define GPIF_A07		0x07
+#define GPIF_A08		0x08
+#define GPIF_A09		0x09
+#define GPIF_A10		0x0a
+#define GPIF_A11		0x0b
+
+#define GPIF_A12		0x0c
+#define GPIF_A13		0x0d
+#define GPIF_A14		0x0e
+
+enum mantis_stream_control {
+	STREAM_TO_HIF = 0,
+	STREAM_TO_CAM
+};
+
+extern int mantis_get_mac(struct mantis_pci *mantis);
+extern void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value);
+
+extern int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl);
+
+#endif /* __MANTIS_IOC_H */
diff --git a/drivers/media/pci/mantis/mantis_link.h b/drivers/media/pci/mantis/mantis_link.h
new file mode 100644
index 0000000..2a81477
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_link.h
@@ -0,0 +1,83 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_LINK_H
+#define __MANTIS_LINK_H
+
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include "dvb_ca_en50221.h"
+
+enum mantis_sbuf_status {
+	MANTIS_SBUF_DATA_AVAIL		= 1,
+	MANTIS_SBUF_DATA_EMPTY		= 2,
+	MANTIS_SBUF_DATA_OVFLW		= 3
+};
+
+struct mantis_slot {
+	u32				timeout;
+	u32				slave_cfg;
+	u32				bar;
+};
+
+/* Physical layer */
+enum mantis_slot_state {
+	MODULE_INSERTED			= 3,
+	MODULE_XTRACTED			= 4
+};
+
+struct mantis_ca {
+	struct mantis_slot		slot[4];
+
+	struct work_struct		hif_evm_work;
+
+	u32				hif_event;
+	wait_queue_head_t		hif_opdone_wq;
+	wait_queue_head_t		hif_brrdyw_wq;
+	wait_queue_head_t		hif_data_wq;
+	wait_queue_head_t		hif_write_wq; /* HIF Write op */
+
+	enum mantis_sbuf_status		sbuf_status;
+
+	enum mantis_slot_state		slot_state;
+
+	void				*ca_priv;
+
+	struct dvb_ca_en50221		en50221;
+	struct mutex			ca_lock;
+};
+
+/* CA */
+extern void mantis_event_cam_plugin(struct mantis_ca *ca);
+extern void mantis_event_cam_unplug(struct mantis_ca *ca);
+extern int mantis_pcmcia_init(struct mantis_ca *ca);
+extern void mantis_pcmcia_exit(struct mantis_ca *ca);
+extern int mantis_evmgr_init(struct mantis_ca *ca);
+extern void mantis_evmgr_exit(struct mantis_ca *ca);
+
+/* HIF */
+extern int mantis_hif_init(struct mantis_ca *ca);
+extern void mantis_hif_exit(struct mantis_ca *ca);
+extern int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr);
+extern int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data);
+extern int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr);
+extern int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data);
+
+#endif /* __MANTIS_LINK_H */
diff --git a/drivers/media/pci/mantis/mantis_pci.c b/drivers/media/pci/mantis/mantis_pci.c
new file mode 100644
index 0000000..371558a
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_pci.c
@@ -0,0 +1,170 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <linux/kmod.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+
+#include <asm/irq.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_pci.h"
+
+#define DRIVER_NAME		"Mantis Core"
+
+int __devinit mantis_pci_init(struct mantis_pci *mantis)
+{
+	u8 latency;
+	struct mantis_hwconfig *config	= mantis->hwconfig;
+	struct pci_dev *pdev		= mantis->pdev;
+	int err, ret = 0;
+
+	dprintk(MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n",
+		config->model_name,
+		config->dev_type,
+		mantis->pdev->bus->number,
+		PCI_SLOT(mantis->pdev->devfn),
+		PCI_FUNC(mantis->pdev->devfn));
+
+	err = pci_enable_device(pdev);
+	if (err != 0) {
+		ret = -ENODEV;
+		dprintk(MANTIS_ERROR, 1, "ERROR: PCI enable failed <%i>", err);
+		goto fail0;
+	}
+
+	err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+	if (err != 0) {
+		dprintk(MANTIS_ERROR, 1, "ERROR: Unable to obtain 32 bit DMA <%i>", err);
+		ret = -ENOMEM;
+		goto fail1;
+	}
+
+	pci_set_master(pdev);
+
+	if (!request_mem_region(pci_resource_start(pdev, 0),
+				pci_resource_len(pdev, 0),
+				DRIVER_NAME)) {
+
+		dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 Request failed !");
+		ret = -ENODEV;
+		goto fail1;
+	}
+
+	mantis->mmio = ioremap(pci_resource_start(pdev, 0),
+			       pci_resource_len(pdev, 0));
+
+	if (!mantis->mmio) {
+		dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 remap failed !");
+		ret = -ENODEV;
+		goto fail2;
+	}
+
+	pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
+	mantis->latency = latency;
+	mantis->revision = pdev->revision;
+
+	dprintk(MANTIS_ERROR, 0, "    Mantis Rev %d [%04x:%04x], ",
+		mantis->revision,
+		mantis->pdev->subsystem_vendor,
+		mantis->pdev->subsystem_device);
+
+	dprintk(MANTIS_ERROR, 0,
+		"irq: %d, latency: %d\n    memory: 0x%lx, mmio: 0x%p\n",
+		mantis->pdev->irq,
+		mantis->latency,
+		mantis->mantis_addr,
+		mantis->mmio);
+
+	err = request_irq(pdev->irq,
+			  config->irq_handler,
+			  IRQF_SHARED,
+			  DRIVER_NAME,
+			  mantis);
+
+	if (err != 0) {
+
+		dprintk(MANTIS_ERROR, 1, "ERROR: IRQ registration failed ! <%d>", err);
+		ret = -ENODEV;
+		goto fail3;
+	}
+
+	pci_set_drvdata(pdev, mantis);
+	return ret;
+
+	/* Error conditions */
+fail3:
+	dprintk(MANTIS_ERROR, 1, "ERROR: <%d> I/O unmap", ret);
+	if (mantis->mmio)
+		iounmap(mantis->mmio);
+
+fail2:
+	dprintk(MANTIS_ERROR, 1, "ERROR: <%d> releasing regions", ret);
+	release_mem_region(pci_resource_start(pdev, 0),
+			   pci_resource_len(pdev, 0));
+
+fail1:
+	dprintk(MANTIS_ERROR, 1, "ERROR: <%d> disabling device", ret);
+	pci_disable_device(pdev);
+
+fail0:
+	dprintk(MANTIS_ERROR, 1, "ERROR: <%d> exiting", ret);
+	pci_set_drvdata(pdev, NULL);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(mantis_pci_init);
+
+void mantis_pci_exit(struct mantis_pci *mantis)
+{
+	struct pci_dev *pdev = mantis->pdev;
+
+	dprintk(MANTIS_NOTICE, 1, " mem: 0x%p", mantis->mmio);
+	free_irq(pdev->irq, mantis);
+	if (mantis->mmio) {
+		iounmap(mantis->mmio);
+		release_mem_region(pci_resource_start(pdev, 0),
+				   pci_resource_len(pdev, 0));
+	}
+
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+}
+EXPORT_SYMBOL_GPL(mantis_pci_exit);
+
+MODULE_DESCRIPTION("Mantis PCI DTV bridge driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/mantis/mantis_pci.h b/drivers/media/pci/mantis/mantis_pci.h
new file mode 100644
index 0000000..65f0045
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_pci.h
@@ -0,0 +1,27 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_PCI_H
+#define __MANTIS_PCI_H
+
+extern int mantis_pci_init(struct mantis_pci *mantis);
+extern void mantis_pci_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_PCI_H */
diff --git a/drivers/media/pci/mantis/mantis_pcmcia.c b/drivers/media/pci/mantis/mantis_pcmcia.c
new file mode 100644
index 0000000..2f188c0
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_pcmcia.c
@@ -0,0 +1,121 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_link.h" /* temporary due to physical layer stuff */
+#include "mantis_reg.h"
+
+/*
+ * If Slot state is already PLUG_IN event and we are called
+ * again, definitely it is jitter alone
+ */
+void mantis_event_cam_plugin(struct mantis_ca *ca)
+{
+	struct mantis_pci *mantis = ca->ca_priv;
+
+	u32 gpif_irqcfg;
+
+	if (ca->slot_state == MODULE_XTRACTED) {
+		dprintk(MANTIS_DEBUG, 1, "Event: CAM Plugged IN: Adapter(%d) Slot(0)", mantis->num);
+		udelay(50);
+		mmwrite(0xda000000, MANTIS_CARD_RESET);
+		gpif_irqcfg  = mmread(MANTIS_GPIF_IRQCFG);
+		gpif_irqcfg |= MANTIS_MASK_PLUGOUT;
+		gpif_irqcfg &= ~MANTIS_MASK_PLUGIN;
+		mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG);
+		udelay(500);
+		ca->slot_state = MODULE_INSERTED;
+	}
+	udelay(100);
+}
+
+/*
+ * If Slot state is already UN_PLUG event and we are called
+ * again, definitely it is jitter alone
+ */
+void mantis_event_cam_unplug(struct mantis_ca *ca)
+{
+	struct mantis_pci *mantis = ca->ca_priv;
+
+	u32 gpif_irqcfg;
+
+	if (ca->slot_state == MODULE_INSERTED) {
+		dprintk(MANTIS_DEBUG, 1, "Event: CAM Unplugged: Adapter(%d) Slot(0)", mantis->num);
+		udelay(50);
+		mmwrite(0x00da0000, MANTIS_CARD_RESET);
+		gpif_irqcfg  = mmread(MANTIS_GPIF_IRQCFG);
+		gpif_irqcfg |= MANTIS_MASK_PLUGIN;
+		gpif_irqcfg &= ~MANTIS_MASK_PLUGOUT;
+		mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG);
+		udelay(500);
+		ca->slot_state = MODULE_XTRACTED;
+	}
+	udelay(100);
+}
+
+int mantis_pcmcia_init(struct mantis_ca *ca)
+{
+	struct mantis_pci *mantis = ca->ca_priv;
+
+	u32 gpif_stat, card_stat;
+
+	mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_IRQ0, MANTIS_INT_MASK);
+	gpif_stat = mmread(MANTIS_GPIF_STATUS);
+	card_stat = mmread(MANTIS_GPIF_IRQCFG);
+
+	if (gpif_stat & MANTIS_GPIF_DETSTAT) {
+		dprintk(MANTIS_DEBUG, 1, "CAM found on Adapter(%d) Slot(0)", mantis->num);
+		mmwrite(card_stat | MANTIS_MASK_PLUGOUT, MANTIS_GPIF_IRQCFG);
+		ca->slot_state = MODULE_INSERTED;
+		dvb_ca_en50221_camchange_irq(&ca->en50221,
+					     0,
+					     DVB_CA_EN50221_CAMCHANGE_INSERTED);
+	} else {
+		dprintk(MANTIS_DEBUG, 1, "Empty Slot on Adapter(%d) Slot(0)", mantis->num);
+		mmwrite(card_stat | MANTIS_MASK_PLUGIN, MANTIS_GPIF_IRQCFG);
+		ca->slot_state = MODULE_XTRACTED;
+		dvb_ca_en50221_camchange_irq(&ca->en50221,
+					     0,
+					     DVB_CA_EN50221_CAMCHANGE_REMOVED);
+	}
+
+	return 0;
+}
+
+void mantis_pcmcia_exit(struct mantis_ca *ca)
+{
+	struct mantis_pci *mantis = ca->ca_priv;
+
+	mmwrite(mmread(MANTIS_GPIF_STATUS) & (~MANTIS_CARD_PLUGOUT | ~MANTIS_CARD_PLUGIN), MANTIS_GPIF_STATUS);
+	mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ0, MANTIS_INT_MASK);
+}
diff --git a/drivers/media/pci/mantis/mantis_reg.h b/drivers/media/pci/mantis/mantis_reg.h
new file mode 100644
index 0000000..7761f9d
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_reg.h
@@ -0,0 +1,197 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_REG_H
+#define __MANTIS_REG_H
+
+/* Interrupts */
+#define MANTIS_INT_STAT			0x00
+#define MANTIS_INT_MASK			0x04
+
+#define MANTIS_INT_RISCSTAT		(0x0f << 28)
+#define MANTIS_INT_RISCEN		(0x01 << 27)
+#define MANTIS_INT_I2CRACK		(0x01 << 26)
+
+/* #define MANTIS_INT_GPIF			(0xff << 12) */
+
+#define MANTIS_INT_PCMCIA7		(0x01 << 19)
+#define MANTIS_INT_PCMCIA6		(0x01 << 18)
+#define MANTIS_INT_PCMCIA5		(0x01 << 17)
+#define MANTIS_INT_PCMCIA4		(0x01 << 16)
+#define MANTIS_INT_PCMCIA3		(0x01 << 15)
+#define MANTIS_INT_PCMCIA2		(0x01 << 14)
+#define MANTIS_INT_PCMCIA1		(0x01 << 13)
+#define MANTIS_INT_PCMCIA0		(0x01 << 12)
+#define MANTIS_INT_IRQ1			(0x01 << 11)
+#define MANTIS_INT_IRQ0			(0x01 << 10)
+#define MANTIS_INT_OCERR		(0x01 <<  8)
+#define MANTIS_INT_PABORT		(0x01 <<  7)
+#define MANTIS_INT_RIPERR		(0x01 <<  6)
+#define MANTIS_INT_PPERR		(0x01 <<  5)
+#define MANTIS_INT_FTRGT		(0x01 <<  3)
+#define MANTIS_INT_RISCI		(0x01 <<  1)
+#define MANTIS_INT_I2CDONE		(0x01 <<  0)
+
+/* DMA */
+#define MANTIS_DMA_CTL			0x08
+#define MANTIS_GPIF_RD			(0xff << 24)
+#define MANTIS_GPIF_WR			(0xff << 16)
+#define MANTIS_CPU_DO			(0x01 << 10)
+#define MANTIS_DRV_DO			(0x01 <<  9)
+#define	MANTIS_I2C_RD			(0x01 <<  7)
+#define MANTIS_I2C_WR			(0x01 <<  6)
+#define MANTIS_DCAP_MODE		(0x01 <<  5)
+#define MANTIS_FIFO_TP_4		(0x00 <<  3)
+#define MANTIS_FIFO_TP_8		(0x01 <<  3)
+#define MANTIS_FIFO_TP_16		(0x02 <<  3)
+#define MANTIS_FIFO_EN			(0x01 <<  2)
+#define MANTIS_DCAP_EN			(0x01 <<  1)
+#define MANTIS_RISC_EN			(0x01 <<  0)
+
+/* DEBUG */
+#define MANTIS_DEBUGREG			0x0c
+#define MANTIS_DATINV			(0x0e <<  7)
+#define MANTIS_TOP_DEBUGSEL		(0x07 <<  4)
+#define MANTIS_PCMCIA_DEBUGSEL		(0x0f <<  0)
+
+#define MANTIS_RISC_START		0x10
+#define MANTIS_RISC_PC			0x14
+
+/* I2C */
+#define MANTIS_I2CDATA_CTL		0x18
+#define MANTIS_I2C_RATE_1		(0x00 <<  6)
+#define MANTIS_I2C_RATE_2		(0x01 <<  6)
+#define MANTIS_I2C_RATE_3		(0x02 <<  6)
+#define MANTIS_I2C_RATE_4		(0x03 <<  6)
+#define MANTIS_I2C_STOP			(0x01 <<  5)
+#define MANTIS_I2C_PGMODE		(0x01 <<  3)
+
+/* DATA */
+#define MANTIS_CMD_DATA_R1		0x20
+#define MANTIS_CMD_DATA_3		(0xff << 24)
+#define MANTIS_CMD_DATA_2		(0xff << 16)
+#define MANTIS_CMD_DATA_1		(0xff <<  8)
+#define MANTIS_CMD_DATA_0		(0xff <<  0)
+
+#define MANTIS_CMD_DATA_R2		0x24
+#define MANTIS_CMD_DATA_7		(0xff << 24)
+#define MANTIS_CMD_DATA_6		(0xff << 16)
+#define MANTIS_CMD_DATA_5		(0xff <<  8)
+#define MANTIS_CMD_DATA_4		(0xff <<  0)
+
+#define MANTIS_CONTROL			0x28
+#define MANTIS_DET			(0x01 <<  7)
+#define MANTIS_DAT_CF_EN		(0x01 <<  6)
+#define MANTIS_ACS			(0x03 <<  4)
+#define MANTIS_VCCEN			(0x01 <<  3)
+#define MANTIS_BYPASS			(0x01 <<  2)
+#define MANTIS_MRST			(0x01 <<  1)
+#define MANTIS_CRST_INT			(0x01 <<  0)
+
+#define MANTIS_GPIF_CFGSLA		0x84
+#define MANTIS_GPIF_WAITSMPL		(0x07 << 28)
+#define MANTIS_GPIF_BYTEADDRSUB		(0x01 << 25)
+#define MANTIS_GPIF_WAITPOL		(0x01 << 24)
+#define MANTIS_GPIF_NCDELAY		(0x07 << 20)
+#define MANTIS_GPIF_RW2CSDELAY		(0x07 << 16)
+#define MANTIS_GPIF_SLFTIMEDMODE	(0x01 << 15)
+#define MANTIS_GPIF_SLFTIMEDDELY	(0x7f <<  8)
+#define MANTIS_GPIF_DEVTYPE		(0x07 <<  4)
+#define MANTIS_GPIF_BIGENDIAN		(0x01 <<  3)
+#define MANTIS_GPIF_FETCHCMD		(0x03 <<  1)
+#define MANTIS_GPIF_HWORDDEV		(0x01 <<  0)
+
+#define MANTIS_GPIF_WSTOPER		0x90
+#define MANTIS_GPIF_WSTOPERWREN3	(0x01 << 31)
+#define MANTIS_GPIF_PARBOOTN		(0x01 << 29)
+#define MANTIS_GPIF_WSTOPERSLID3	(0x1f << 24)
+#define MANTIS_GPIF_WSTOPERWREN2	(0x01 << 23)
+#define MANTIS_GPIF_WSTOPERSLID2	(0x1f << 16)
+#define MANTIS_GPIF_WSTOPERWREN1	(0x01 << 15)
+#define MANTIS_GPIF_WSTOPERSLID1	(0x1f <<  8)
+#define MANTIS_GPIF_WSTOPERWREN0	(0x01 <<  7)
+#define MANTIS_GPIF_WSTOPERSLID0	(0x1f <<  0)
+
+#define MANTIS_GPIF_CS2RW		0x94
+#define MANTIS_GPIF_CS2RWWREN3		(0x01 << 31)
+#define MANTIS_GPIF_CS2RWDELY3		(0x3f << 24)
+#define MANTIS_GPIF_CS2RWWREN2		(0x01 << 23)
+#define MANTIS_GPIF_CS2RWDELY2		(0x3f << 16)
+#define MANTIS_GPIF_CS2RWWREN1		(0x01 << 15)
+#define MANTIS_GPIF_CS2RWDELY1		(0x3f <<  8)
+#define MANTIS_GPIF_CS2RWWREN0		(0x01 <<  7)
+#define MANTIS_GPIF_CS2RWDELY0		(0x3f <<  0)
+
+#define MANTIS_GPIF_IRQCFG		0x98
+#define MANTIS_GPIF_IRQPOL		(0x01 <<  8)
+#define MANTIS_MASK_WRACK		(0x01 <<  7)
+#define MANTIS_MASK_BRRDY		(0x01 <<  6)
+#define MANTIS_MASK_OVFLW		(0x01 <<  5)
+#define MANTIS_MASK_OTHERR		(0x01 <<  4)
+#define MANTIS_MASK_WSTO		(0x01 <<  3)
+#define MANTIS_MASK_EXTIRQ		(0x01 <<  2)
+#define MANTIS_MASK_PLUGIN		(0x01 <<  1)
+#define MANTIS_MASK_PLUGOUT		(0x01 <<  0)
+
+#define MANTIS_GPIF_STATUS		0x9c
+#define MANTIS_SBUF_KILLOP		(0x01 << 15)
+#define MANTIS_SBUF_OPDONE		(0x01 << 14)
+#define MANTIS_SBUF_EMPTY		(0x01 << 13)
+#define MANTIS_GPIF_DETSTAT		(0x01 <<  9)
+#define MANTIS_GPIF_INTSTAT		(0x01 <<  8)
+#define MANTIS_GPIF_WRACK		(0x01 <<  7)
+#define MANTIS_GPIF_BRRDY		(0x01 <<  6)
+#define MANTIS_SBUF_OVFLW		(0x01 <<  5)
+#define MANTIS_GPIF_OTHERR		(0x01 <<  4)
+#define MANTIS_SBUF_WSTO		(0x01 <<  3)
+#define MANTIS_GPIF_EXTIRQ		(0x01 <<  2)
+#define MANTIS_CARD_PLUGIN		(0x01 <<  1)
+#define MANTIS_CARD_PLUGOUT		(0x01 <<  0)
+
+#define MANTIS_GPIF_BRADDR		0xa0
+#define MANTIS_GPIF_PCMCIAREG		(0x01 		<< 27)
+#define MANTIS_GPIF_PCMCIAIOM		(0x01 		<< 26)
+#define MANTIS_GPIF_BR_ADDR		(0xfffffff	<<  0)
+
+#define MANTIS_GPIF_BRBYTES		0xa4
+#define MANTIS_GPIF_BRCNT		(0xfff 		<<  0)
+
+#define MANTIS_PCMCIA_RESET		0xa8
+#define MANTIS_PCMCIA_RSTVAL		(0xff << 0)
+
+#define MANTIS_CARD_RESET		0xac
+
+#define MANTIS_GPIF_ADDR		0xb0
+#define MANTIS_GPIF_HIFRDWRN		(0x01		<< 31)
+#define MANTIS_GPIF_PCMCIAREG		(0x01		<< 27)
+#define MANTIS_GPIF_PCMCIAIOM		(0x01		<< 26)
+#define MANTIS_GPIF_HIFADDR		(0xfffffff	<<  0)
+
+#define MANTIS_GPIF_DOUT		0xb4
+#define MANTIS_GPIF_HIFDOUT		(0xfffffff	<<  0)
+
+#define MANTIS_GPIF_DIN			0xb8
+#define MANTIS_GPIF_HIFDIN		(0xfffffff	<<  0)
+
+#define MANTIS_GPIF_SPARE		0xbc
+#define MANTIS_GPIF_LOGICRD		(0xffff		<< 16)
+#define MANTIS_GPIF_LOGICRW		(0xffff		<<  0)
+
+#endif /* __MANTIS_REG_H */
diff --git a/drivers/media/pci/mantis/mantis_uart.c b/drivers/media/pci/mantis/mantis_uart.c
new file mode 100644
index 0000000..18340da
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_uart.c
@@ -0,0 +1,188 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_uart.h"
+
+struct mantis_uart_params {
+	enum mantis_baud	baud_rate;
+	enum mantis_parity	parity;
+};
+
+static struct {
+	char string[7];
+} rates[5] = {
+	{ "9600" },
+	{ "19200" },
+	{ "38400" },
+	{ "57600" },
+	{ "115200" }
+};
+
+static struct {
+	char string[5];
+} parity[3] = {
+	{ "NONE" },
+	{ "ODD" },
+	{ "EVEN" }
+};
+
+#define UART_MAX_BUF			16
+
+int mantis_uart_read(struct mantis_pci *mantis, u8 *data)
+{
+	struct mantis_hwconfig *config = mantis->hwconfig;
+	u32 stat = 0, i;
+
+	/* get data */
+	for (i = 0; i < (config->bytes + 1); i++) {
+
+		stat = mmread(MANTIS_UART_STAT);
+
+		if (stat & MANTIS_UART_RXFIFO_FULL) {
+			dprintk(MANTIS_ERROR, 1, "RX Fifo FULL");
+		}
+		data[i] = mmread(MANTIS_UART_RXD) & 0x3f;
+
+		dprintk(MANTIS_DEBUG, 1, "Reading ... <%02x>", data[i] & 0x3f);
+
+		if (data[i] & (1 << 7)) {
+			dprintk(MANTIS_ERROR, 1, "UART framing error");
+			return -EINVAL;
+		}
+		if (data[i] & (1 << 6)) {
+			dprintk(MANTIS_ERROR, 1, "UART parity error");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static void mantis_uart_work(struct work_struct *work)
+{
+	struct mantis_pci *mantis = container_of(work, struct mantis_pci, uart_work);
+	struct mantis_hwconfig *config = mantis->hwconfig;
+	u8 buf[16];
+	int i;
+
+	mantis_uart_read(mantis, buf);
+
+	for (i = 0; i < (config->bytes + 1); i++)
+		dprintk(MANTIS_INFO, 1, "UART BUF:%d <%02x> ", i, buf[i]);
+
+	dprintk(MANTIS_DEBUG, 0, "\n");
+}
+
+static int mantis_uart_setup(struct mantis_pci *mantis,
+			     struct mantis_uart_params *params)
+{
+	u32 reg;
+
+	mmwrite((mmread(MANTIS_UART_CTL) | (params->parity & 0x3)), MANTIS_UART_CTL);
+
+	reg = mmread(MANTIS_UART_BAUD);
+
+	switch (params->baud_rate) {
+	case MANTIS_BAUD_9600:
+		reg |= 0xd8;
+		break;
+	case MANTIS_BAUD_19200:
+		reg |= 0x6c;
+		break;
+	case MANTIS_BAUD_38400:
+		reg |= 0x36;
+		break;
+	case MANTIS_BAUD_57600:
+		reg |= 0x23;
+		break;
+	case MANTIS_BAUD_115200:
+		reg |= 0x11;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mmwrite(reg, MANTIS_UART_BAUD);
+
+	return 0;
+}
+
+int mantis_uart_init(struct mantis_pci *mantis)
+{
+	struct mantis_hwconfig *config = mantis->hwconfig;
+	struct mantis_uart_params params;
+
+	/* default parity: */
+	params.baud_rate = config->baud_rate;
+	params.parity = config->parity;
+	dprintk(MANTIS_INFO, 1, "Initializing UART @ %sbps parity:%s",
+		rates[params.baud_rate].string,
+		parity[params.parity].string);
+
+	init_waitqueue_head(&mantis->uart_wq);
+	spin_lock_init(&mantis->uart_lock);
+
+	INIT_WORK(&mantis->uart_work, mantis_uart_work);
+
+	/* disable interrupt */
+	mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL);
+
+	mantis_uart_setup(mantis, &params);
+
+	/* default 1 byte */
+	mmwrite((mmread(MANTIS_UART_BAUD) | (config->bytes << 8)), MANTIS_UART_BAUD);
+
+	/* flush buffer */
+	mmwrite((mmread(MANTIS_UART_CTL) | MANTIS_UART_RXFLUSH), MANTIS_UART_CTL);
+
+	/* enable interrupt */
+	mmwrite(mmread(MANTIS_INT_MASK) | 0x800, MANTIS_INT_MASK);
+	mmwrite(mmread(MANTIS_UART_CTL) | MANTIS_UART_RXINT, MANTIS_UART_CTL);
+
+	schedule_work(&mantis->uart_work);
+	dprintk(MANTIS_DEBUG, 1, "UART successfully initialized");
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_uart_init);
+
+void mantis_uart_exit(struct mantis_pci *mantis)
+{
+	/* disable interrupt */
+	mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL);
+	flush_work_sync(&mantis->uart_work);
+}
+EXPORT_SYMBOL_GPL(mantis_uart_exit);
diff --git a/drivers/media/pci/mantis/mantis_uart.h b/drivers/media/pci/mantis/mantis_uart.h
new file mode 100644
index 0000000..ffb62a0
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_uart.h
@@ -0,0 +1,58 @@
+/*
+	Mantis PCI bridge driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_UART_H
+#define __MANTIS_UART_H
+
+#define MANTIS_UART_CTL			0xe0
+#define MANTIS_UART_RXINT		(1 << 4)
+#define MANTIS_UART_RXFLUSH		(1 << 2)
+
+#define MANTIS_UART_RXD			0xe8
+#define MANTIS_UART_BAUD		0xec
+
+#define MANTIS_UART_STAT		0xf0
+#define MANTIS_UART_RXFIFO_DATA		(1 << 7)
+#define MANTIS_UART_RXFIFO_EMPTY	(1 << 6)
+#define MANTIS_UART_RXFIFO_FULL		(1 << 3)
+#define MANTIS_UART_FRAME_ERR		(1 << 2)
+#define MANTIS_UART_PARITY_ERR		(1 << 1)
+#define MANTIS_UART_RXTHRESH_INT	(1 << 0)
+
+enum mantis_baud {
+	MANTIS_BAUD_9600	= 0,
+	MANTIS_BAUD_19200,
+	MANTIS_BAUD_38400,
+	MANTIS_BAUD_57600,
+	MANTIS_BAUD_115200
+};
+
+enum mantis_parity {
+	MANTIS_PARITY_NONE	= 0,
+	MANTIS_PARITY_EVEN,
+	MANTIS_PARITY_ODD,
+};
+
+struct mantis_pci;
+
+extern int mantis_uart_init(struct mantis_pci *mantis);
+extern void mantis_uart_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_UART_H */
diff --git a/drivers/media/pci/mantis/mantis_vp1033.c b/drivers/media/pci/mantis/mantis_vp1033.c
new file mode 100644
index 0000000..ad013e9
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_vp1033.c
@@ -0,0 +1,212 @@
+/*
+	Mantis VP-1033 driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "stv0299.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp1033.h"
+#include "mantis_reg.h"
+
+u8 lgtdqcs001f_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x30,
+	0x03, 0x00,
+	0x04, 0x2a,
+	0x05, 0x85,
+	0x06, 0x02,
+	0x07, 0x00,
+	0x08, 0x00,
+	0x0c, 0x01,
+	0x0d, 0x81,
+	0x0e, 0x44,
+	0x0f, 0x94,
+	0x10, 0x3c,
+	0x11, 0x84,
+	0x12, 0xb9,
+	0x13, 0xb5,
+	0x14, 0x4f,
+	0x15, 0xc9,
+	0x16, 0x80,
+	0x17, 0x36,
+	0x18, 0xfb,
+	0x19, 0xcf,
+	0x1a, 0xbc,
+	0x1c, 0x2b,
+	0x1d, 0x27,
+	0x1e, 0x00,
+	0x1f, 0x0b,
+	0x20, 0xa1,
+	0x21, 0x60,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x28, 0x00,
+	0x29, 0x28,
+	0x2a, 0x14,
+	0x2b, 0x0f,
+	0x2c, 0x09,
+	0x2d, 0x05,
+	0x31, 0x1f,
+	0x32, 0x19,
+	0x33, 0xfc,
+	0x34, 0x13,
+	0xff, 0xff,
+};
+
+#define MANTIS_MODEL_NAME	"VP-1033"
+#define MANTIS_DEV_TYPE		"DVB-S/DSS"
+
+int lgtdqcs001f_tuner_set(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct mantis_pci *mantis	= fe->dvb->priv;
+	struct i2c_adapter *adapter	= &mantis->adapter;
+
+	u8 buf[4];
+	u32 div;
+
+
+	struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf)};
+
+	div = p->frequency / 250;
+
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] =  div & 0xff;
+	buf[2] =  0x83;
+	buf[3] =  0xc0;
+
+	if (p->frequency < 1531000)
+		buf[3] |= 0x04;
+	else
+		buf[3] &= ~0x04;
+	if (i2c_transfer(adapter, &msg, 1) < 0) {
+		dprintk(MANTIS_ERROR, 1, "Write: I2C Transfer failed");
+		return -EIO;
+	}
+	msleep_interruptible(100);
+
+	return 0;
+}
+
+int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe,
+				u32 srate, u32 ratio)
+{
+	u8 aclk = 0;
+	u8 bclk = 0;
+
+	if (srate < 1500000) {
+		aclk = 0xb7;
+		bclk = 0x47;
+	} else if (srate < 3000000) {
+		aclk = 0xb7;
+		bclk = 0x4b;
+	} else if (srate < 7000000) {
+		aclk = 0xb7;
+		bclk = 0x4f;
+	} else if (srate < 14000000) {
+		aclk = 0xb7;
+		bclk = 0x53;
+	} else if (srate < 30000000) {
+		aclk = 0xb6;
+		bclk = 0x53;
+	} else if (srate < 45000000) {
+		aclk = 0xb4;
+		bclk = 0x51;
+	}
+	stv0299_writereg(fe, 0x13, aclk);
+	stv0299_writereg(fe, 0x14, bclk);
+
+	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+	stv0299_writereg(fe, 0x20, (ratio >>  8) & 0xff);
+	stv0299_writereg(fe, 0x21,  ratio & 0xf0);
+
+	return 0;
+}
+
+struct stv0299_config lgtdqcs001f_config = {
+	.demod_address		= 0x68,
+	.inittab		= lgtdqcs001f_inittab,
+	.mclk			= 88000000UL,
+	.invert			= 0,
+	.skip_reinit		= 0,
+	.volt13_op0_op1		= STV0299_VOLT13_OP0,
+	.min_delay_ms		= 100,
+	.set_symbol_rate	= lgtdqcs001f_set_symbol_rate,
+};
+
+static int vp1033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+	struct i2c_adapter *adapter	= &mantis->adapter;
+
+	int err = 0;
+
+	err = mantis_frontend_power(mantis, POWER_ON);
+	if (err == 0) {
+		mantis_frontend_soft_reset(mantis);
+		msleep(250);
+
+		dprintk(MANTIS_ERROR, 1, "Probing for STV0299 (DVB-S)");
+		fe = dvb_attach(stv0299_attach, &lgtdqcs001f_config, adapter);
+
+		if (fe) {
+			fe->ops.tuner_ops.set_params = lgtdqcs001f_tuner_set;
+			dprintk(MANTIS_ERROR, 1, "found STV0299 DVB-S frontend @ 0x%02x",
+				lgtdqcs001f_config.demod_address);
+
+			dprintk(MANTIS_ERROR, 1, "Mantis DVB-S STV0299 frontend attach success");
+		} else {
+			return -1;
+		}
+	} else {
+		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+			adapter->name,
+			err);
+
+		return -EIO;
+	}
+	mantis->fe = fe;
+	dprintk(MANTIS_ERROR, 1, "Done!");
+
+	return 0;
+}
+
+struct mantis_hwconfig vp1033_config = {
+	.model_name		= MANTIS_MODEL_NAME,
+	.dev_type		= MANTIS_DEV_TYPE,
+	.ts_size		= MANTIS_TS_204,
+
+	.baud_rate		= MANTIS_BAUD_9600,
+	.parity			= MANTIS_PARITY_NONE,
+	.bytes			= 0,
+
+	.frontend_init		= vp1033_frontend_init,
+	.power			= GPIF_A12,
+	.reset			= GPIF_A13,
+};
diff --git a/drivers/media/pci/mantis/mantis_vp1033.h b/drivers/media/pci/mantis/mantis_vp1033.h
new file mode 100644
index 0000000..7daaa1b
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_vp1033.h
@@ -0,0 +1,30 @@
+/*
+	Mantis VP-1033 driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP1033_H
+#define __MANTIS_VP1033_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_1033_DVB_S	0x0016
+
+extern struct mantis_hwconfig vp1033_config;
+
+#endif /* __MANTIS_VP1033_H */
diff --git a/drivers/media/pci/mantis/mantis_vp1034.c b/drivers/media/pci/mantis/mantis_vp1034.c
new file mode 100644
index 0000000..430ae84
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_vp1034.c
@@ -0,0 +1,120 @@
+/*
+	Mantis VP-1034 driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mb86a16.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp1034.h"
+#include "mantis_reg.h"
+
+struct mb86a16_config vp1034_mb86a16_config = {
+	.demod_address	= 0x08,
+	.set_voltage	= vp1034_set_voltage,
+};
+
+#define MANTIS_MODEL_NAME	"VP-1034"
+#define MANTIS_DEV_TYPE		"DVB-S/DSS"
+
+int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct mantis_pci *mantis = fe->dvb->priv;
+
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		dprintk(MANTIS_ERROR, 1, "Polarization=[13V]");
+		mantis_gpio_set_bits(mantis, 13, 1);
+		mantis_gpio_set_bits(mantis, 14, 0);
+		break;
+	case SEC_VOLTAGE_18:
+		dprintk(MANTIS_ERROR, 1, "Polarization=[18V]");
+		mantis_gpio_set_bits(mantis, 13, 1);
+		mantis_gpio_set_bits(mantis, 14, 1);
+		break;
+	case SEC_VOLTAGE_OFF:
+		dprintk(MANTIS_ERROR, 1, "Frontend (dummy) POWERDOWN");
+		break;
+	default:
+		dprintk(MANTIS_ERROR, 1, "Invalid = (%d)", (u32) voltage);
+		return -EINVAL;
+	}
+	mmwrite(0x00, MANTIS_GPIF_DOUT);
+
+	return 0;
+}
+
+static int vp1034_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+	struct i2c_adapter *adapter	= &mantis->adapter;
+
+	int err = 0;
+
+	err = mantis_frontend_power(mantis, POWER_ON);
+	if (err == 0) {
+		mantis_frontend_soft_reset(mantis);
+		msleep(250);
+
+		dprintk(MANTIS_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)");
+		fe = dvb_attach(mb86a16_attach, &vp1034_mb86a16_config, adapter);
+		if (fe) {
+			dprintk(MANTIS_ERROR, 1,
+			"found MB86A16 DVB-S/DSS frontend @0x%02x",
+			vp1034_mb86a16_config.demod_address);
+
+		} else {
+			return -1;
+		}
+	} else {
+		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+			adapter->name,
+			err);
+
+		return -EIO;
+	}
+	mantis->fe = fe;
+	dprintk(MANTIS_ERROR, 1, "Done!");
+
+	return 0;
+}
+
+struct mantis_hwconfig vp1034_config = {
+	.model_name	= MANTIS_MODEL_NAME,
+	.dev_type	= MANTIS_DEV_TYPE,
+	.ts_size	= MANTIS_TS_204,
+
+	.baud_rate	= MANTIS_BAUD_9600,
+	.parity		= MANTIS_PARITY_NONE,
+	.bytes		= 0,
+
+	.frontend_init	= vp1034_frontend_init,
+	.power		= GPIF_A12,
+	.reset		= GPIF_A13,
+};
diff --git a/drivers/media/pci/mantis/mantis_vp1034.h b/drivers/media/pci/mantis/mantis_vp1034.h
new file mode 100644
index 0000000..323f38e
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_vp1034.h
@@ -0,0 +1,33 @@
+/*
+	Mantis VP-1034 driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP1034_H
+#define __MANTIS_VP1034_H
+
+#include "dvb_frontend.h"
+#include "mantis_common.h"
+
+
+#define MANTIS_VP_1034_DVB_S	0x0014
+
+extern struct mantis_hwconfig vp1034_config;
+extern int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+
+#endif /* __MANTIS_VP1034_H */
diff --git a/drivers/media/pci/mantis/mantis_vp1041.c b/drivers/media/pci/mantis/mantis_vp1041.c
new file mode 100644
index 0000000..07aa887
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_vp1041.c
@@ -0,0 +1,357 @@
+/*
+	Mantis VP-1041 driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp1041.h"
+#include "stb0899_reg.h"
+#include "stb0899_drv.h"
+#include "stb0899_cfg.h"
+#include "stb6100_cfg.h"
+#include "stb6100.h"
+#include "lnbp21.h"
+
+#define MANTIS_MODEL_NAME	"VP-1041"
+#define MANTIS_DEV_TYPE		"DSS/DVB-S/DVB-S2"
+
+static const struct stb0899_s1_reg vp1041_stb0899_s1_init_1[] = {
+
+	/* 0x0000000b, *//* SYSREG */
+	{ STB0899_DEV_ID		, 0x30 },
+	{ STB0899_DISCNTRL1		, 0x32 },
+	{ STB0899_DISCNTRL2     	, 0x80 },
+	{ STB0899_DISRX_ST0     	, 0x04 },
+	{ STB0899_DISRX_ST1     	, 0x00 },
+	{ STB0899_DISPARITY     	, 0x00 },
+	{ STB0899_DISSTATUS		, 0x20 },
+	{ STB0899_DISF22        	, 0x99 },
+	{ STB0899_DISF22RX      	, 0xa8 },
+	/* SYSREG ? */
+	{ STB0899_ACRPRESC      	, 0x11 },
+	{ STB0899_ACRDIV1       	, 0x0a },
+	{ STB0899_ACRDIV2       	, 0x05 },
+	{ STB0899_DACR1         	, 0x00 },
+	{ STB0899_DACR2         	, 0x00 },
+	{ STB0899_OUTCFG        	, 0x00 },
+	{ STB0899_MODECFG       	, 0x00 },
+	{ STB0899_IRQSTATUS_3		, 0xfe },
+	{ STB0899_IRQSTATUS_2		, 0x03 },
+	{ STB0899_IRQSTATUS_1		, 0x7c },
+	{ STB0899_IRQSTATUS_0		, 0xf4 },
+	{ STB0899_IRQMSK_3      	, 0xf3 },
+	{ STB0899_IRQMSK_2      	, 0xfc },
+	{ STB0899_IRQMSK_1      	, 0xff },
+	{ STB0899_IRQMSK_0		, 0xff },
+	{ STB0899_IRQCFG		, 0x00 },
+	{ STB0899_I2CCFG        	, 0x88 },
+	{ STB0899_I2CRPT        	, 0x58 },
+	{ STB0899_IOPVALUE5		, 0x00 },
+	{ STB0899_IOPVALUE4		, 0x33 },
+	{ STB0899_IOPVALUE3		, 0x6d },
+	{ STB0899_IOPVALUE2		, 0x90 },
+	{ STB0899_IOPVALUE1		, 0x60 },
+	{ STB0899_IOPVALUE0		, 0x00 },
+	{ STB0899_GPIO00CFG     	, 0x82 },
+	{ STB0899_GPIO01CFG     	, 0x82 },
+	{ STB0899_GPIO02CFG     	, 0x82 },
+	{ STB0899_GPIO03CFG     	, 0x82 },
+	{ STB0899_GPIO04CFG     	, 0x82 },
+	{ STB0899_GPIO05CFG     	, 0x82 },
+	{ STB0899_GPIO06CFG     	, 0x82 },
+	{ STB0899_GPIO07CFG     	, 0x82 },
+	{ STB0899_GPIO08CFG     	, 0x82 },
+	{ STB0899_GPIO09CFG     	, 0x82 },
+	{ STB0899_GPIO10CFG     	, 0x82 },
+	{ STB0899_GPIO11CFG     	, 0x82 },
+	{ STB0899_GPIO12CFG     	, 0x82 },
+	{ STB0899_GPIO13CFG     	, 0x82 },
+	{ STB0899_GPIO14CFG     	, 0x82 },
+	{ STB0899_GPIO15CFG     	, 0x82 },
+	{ STB0899_GPIO16CFG     	, 0x82 },
+	{ STB0899_GPIO17CFG     	, 0x82 },
+	{ STB0899_GPIO18CFG     	, 0x82 },
+	{ STB0899_GPIO19CFG     	, 0x82 },
+	{ STB0899_GPIO20CFG     	, 0x82 },
+	{ STB0899_SDATCFG       	, 0xb8 },
+	{ STB0899_SCLTCFG       	, 0xba },
+	{ STB0899_AGCRFCFG      	, 0x1c }, /* 0x11 */
+	{ STB0899_GPIO22        	, 0x82 }, /* AGCBB2CFG */
+	{ STB0899_GPIO21        	, 0x91 }, /* AGCBB1CFG */
+	{ STB0899_DIRCLKCFG     	, 0x82 },
+	{ STB0899_CLKOUT27CFG   	, 0x7e },
+	{ STB0899_STDBYCFG      	, 0x82 },
+	{ STB0899_CS0CFG        	, 0x82 },
+	{ STB0899_CS1CFG        	, 0x82 },
+	{ STB0899_DISEQCOCFG    	, 0x20 },
+	{ STB0899_GPIO32CFG		, 0x82 },
+	{ STB0899_GPIO33CFG		, 0x82 },
+	{ STB0899_GPIO34CFG		, 0x82 },
+	{ STB0899_GPIO35CFG		, 0x82 },
+	{ STB0899_GPIO36CFG		, 0x82 },
+	{ STB0899_GPIO37CFG		, 0x82 },
+	{ STB0899_GPIO38CFG		, 0x82 },
+	{ STB0899_GPIO39CFG		, 0x82 },
+	{ STB0899_NCOARSE       	, 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
+	{ STB0899_SYNTCTRL      	, 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
+	{ STB0899_FILTCTRL      	, 0x00 },
+	{ STB0899_SYSCTRL       	, 0x01 },
+	{ STB0899_STOPCLK1      	, 0x20 },
+	{ STB0899_STOPCLK2      	, 0x00 },
+	{ STB0899_INTBUFSTATUS		, 0x00 },
+	{ STB0899_INTBUFCTRL    	, 0x0a },
+	{ 0xffff			, 0xff },
+};
+
+static const struct stb0899_s1_reg vp1041_stb0899_s1_init_3[] = {
+	{ STB0899_DEMOD         	, 0x00 },
+	{ STB0899_RCOMPC        	, 0xc9 },
+	{ STB0899_AGC1CN        	, 0x01 },
+	{ STB0899_AGC1REF       	, 0x10 },
+	{ STB0899_RTC			, 0x23 },
+	{ STB0899_TMGCFG        	, 0x4e },
+	{ STB0899_AGC2REF       	, 0x34 },
+	{ STB0899_TLSR          	, 0x84 },
+	{ STB0899_CFD           	, 0xf7 },
+	{ STB0899_ACLC			, 0x87 },
+	{ STB0899_BCLC          	, 0x94 },
+	{ STB0899_EQON          	, 0x41 },
+	{ STB0899_LDT           	, 0xf1 },
+	{ STB0899_LDT2          	, 0xe3 },
+	{ STB0899_EQUALREF      	, 0xb4 },
+	{ STB0899_TMGRAMP       	, 0x10 },
+	{ STB0899_TMGTHD        	, 0x30 },
+	{ STB0899_IDCCOMP		, 0xfd },
+	{ STB0899_QDCCOMP		, 0xff },
+	{ STB0899_POWERI		, 0x0c },
+	{ STB0899_POWERQ		, 0x0f },
+	{ STB0899_RCOMP			, 0x6c },
+	{ STB0899_AGCIQIN		, 0x80 },
+	{ STB0899_AGC2I1		, 0x06 },
+	{ STB0899_AGC2I2		, 0x00 },
+	{ STB0899_TLIR			, 0x30 },
+	{ STB0899_RTF			, 0x7f },
+	{ STB0899_DSTATUS		, 0x00 },
+	{ STB0899_LDI			, 0xbc },
+	{ STB0899_CFRM			, 0xea },
+	{ STB0899_CFRL			, 0x31 },
+	{ STB0899_NIRM			, 0x2b },
+	{ STB0899_NIRL			, 0x80 },
+	{ STB0899_ISYMB			, 0x1d },
+	{ STB0899_QSYMB			, 0xa6 },
+	{ STB0899_SFRH          	, 0x2f },
+	{ STB0899_SFRM          	, 0x68 },
+	{ STB0899_SFRL          	, 0x40 },
+	{ STB0899_SFRUPH        	, 0x2f },
+	{ STB0899_SFRUPM        	, 0x68 },
+	{ STB0899_SFRUPL        	, 0x40 },
+	{ STB0899_EQUAI1		, 0x02 },
+	{ STB0899_EQUAQ1		, 0xff },
+	{ STB0899_EQUAI2		, 0x04 },
+	{ STB0899_EQUAQ2		, 0x05 },
+	{ STB0899_EQUAI3		, 0x02 },
+	{ STB0899_EQUAQ3		, 0xfd },
+	{ STB0899_EQUAI4		, 0x03 },
+	{ STB0899_EQUAQ4		, 0x07 },
+	{ STB0899_EQUAI5		, 0x08 },
+	{ STB0899_EQUAQ5		, 0xf5 },
+	{ STB0899_DSTATUS2		, 0x00 },
+	{ STB0899_VSTATUS       	, 0x00 },
+	{ STB0899_VERROR		, 0x86 },
+	{ STB0899_IQSWAP		, 0x2a },
+	{ STB0899_ECNT1M		, 0x00 },
+	{ STB0899_ECNT1L		, 0x00 },
+	{ STB0899_ECNT2M		, 0x00 },
+	{ STB0899_ECNT2L		, 0x00 },
+	{ STB0899_ECNT3M		, 0x0a },
+	{ STB0899_ECNT3L		, 0xad },
+	{ STB0899_FECAUTO1      	, 0x06 },
+	{ STB0899_FECM			, 0x01 },
+	{ STB0899_VTH12         	, 0xb0 },
+	{ STB0899_VTH23         	, 0x7a },
+	{ STB0899_VTH34			, 0x58 },
+	{ STB0899_VTH56         	, 0x38 },
+	{ STB0899_VTH67         	, 0x34 },
+	{ STB0899_VTH78         	, 0x24 },
+	{ STB0899_PRVIT         	, 0xff },
+	{ STB0899_VITSYNC       	, 0x19 },
+	{ STB0899_RSULC         	, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+	{ STB0899_TSULC         	, 0x42 },
+	{ STB0899_RSLLC         	, 0x41 },
+	{ STB0899_TSLPL			, 0x12 },
+	{ STB0899_TSCFGH        	, 0x0c },
+	{ STB0899_TSCFGM        	, 0x00 },
+	{ STB0899_TSCFGL        	, 0x00 },
+	{ STB0899_TSOUT			, 0x69 }, /* 0x0d for CAM */
+	{ STB0899_RSSYNCDEL     	, 0x00 },
+	{ STB0899_TSINHDELH     	, 0x02 },
+	{ STB0899_TSINHDELM		, 0x00 },
+	{ STB0899_TSINHDELL		, 0x00 },
+	{ STB0899_TSLLSTKM		, 0x1b },
+	{ STB0899_TSLLSTKL		, 0xb3 },
+	{ STB0899_TSULSTKM		, 0x00 },
+	{ STB0899_TSULSTKL		, 0x00 },
+	{ STB0899_PCKLENUL		, 0xbc },
+	{ STB0899_PCKLENLL		, 0xcc },
+	{ STB0899_RSPCKLEN		, 0xbd },
+	{ STB0899_TSSTATUS		, 0x90 },
+	{ STB0899_ERRCTRL1      	, 0xb6 },
+	{ STB0899_ERRCTRL2      	, 0x95 },
+	{ STB0899_ERRCTRL3      	, 0x8d },
+	{ STB0899_DMONMSK1		, 0x27 },
+	{ STB0899_DMONMSK0		, 0x03 },
+	{ STB0899_DEMAPVIT      	, 0x5c },
+	{ STB0899_PLPARM		, 0x19 },
+	{ STB0899_PDELCTRL      	, 0x48 },
+	{ STB0899_PDELCTRL2     	, 0x00 },
+	{ STB0899_BBHCTRL1      	, 0x00 },
+	{ STB0899_BBHCTRL2      	, 0x00 },
+	{ STB0899_HYSTTHRESH    	, 0x77 },
+	{ STB0899_MATCSTM		, 0x00 },
+	{ STB0899_MATCSTL		, 0x00 },
+	{ STB0899_UPLCSTM		, 0x00 },
+	{ STB0899_UPLCSTL		, 0x00 },
+	{ STB0899_DFLCSTM		, 0x00 },
+	{ STB0899_DFLCSTL		, 0x00 },
+	{ STB0899_SYNCCST		, 0x00 },
+	{ STB0899_SYNCDCSTM		, 0x00 },
+	{ STB0899_SYNCDCSTL		, 0x00 },
+	{ STB0899_ISI_ENTRY		, 0x00 },
+	{ STB0899_ISI_BIT_EN		, 0x00 },
+	{ STB0899_MATSTRM		, 0xf0 },
+	{ STB0899_MATSTRL		, 0x02 },
+	{ STB0899_UPLSTRM		, 0x45 },
+	{ STB0899_UPLSTRL		, 0x60 },
+	{ STB0899_DFLSTRM		, 0xe3 },
+	{ STB0899_DFLSTRL		, 0x00 },
+	{ STB0899_SYNCSTR		, 0x47 },
+	{ STB0899_SYNCDSTRM		, 0x05 },
+	{ STB0899_SYNCDSTRL		, 0x18 },
+	{ STB0899_CFGPDELSTATUS1	, 0x19 },
+	{ STB0899_CFGPDELSTATUS2	, 0x2b },
+	{ STB0899_BBFERRORM		, 0x00 },
+	{ STB0899_BBFERRORL		, 0x01 },
+	{ STB0899_UPKTERRORM		, 0x00 },
+	{ STB0899_UPKTERRORL		, 0x00 },
+	{ 0xffff			, 0xff },
+};
+
+struct stb0899_config vp1041_stb0899_config = {
+	.init_dev		= vp1041_stb0899_s1_init_1,
+	.init_s2_demod		= stb0899_s2_init_2,
+	.init_s1_demod		= vp1041_stb0899_s1_init_3,
+	.init_s2_fec		= stb0899_s2_init_4,
+	.init_tst		= stb0899_s1_init_5,
+
+	.demod_address 		= 0x68, /*  0xd0 >> 1 */
+
+	.xtal_freq		= 27000000,
+	.inversion		= IQ_SWAP_ON, /* 1 */
+
+	.lo_clk			= 76500000,
+	.hi_clk			= 99000000,
+
+	.esno_ave		= STB0899_DVBS2_ESNO_AVE,
+	.esno_quant		= STB0899_DVBS2_ESNO_QUANT,
+	.avframes_coarse	= STB0899_DVBS2_AVFRAMES_COARSE,
+	.avframes_fine		= STB0899_DVBS2_AVFRAMES_FINE,
+	.miss_threshold		= STB0899_DVBS2_MISS_THRESHOLD,
+	.uwp_threshold_acq	= STB0899_DVBS2_UWP_THRESHOLD_ACQ,
+	.uwp_threshold_track	= STB0899_DVBS2_UWP_THRESHOLD_TRACK,
+	.uwp_threshold_sof	= STB0899_DVBS2_UWP_THRESHOLD_SOF,
+	.sof_search_timeout	= STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
+
+	.btr_nco_bits		= STB0899_DVBS2_BTR_NCO_BITS,
+	.btr_gain_shift_offset	= STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+	.crl_nco_bits		= STB0899_DVBS2_CRL_NCO_BITS,
+	.ldpc_max_iter		= STB0899_DVBS2_LDPC_MAX_ITER,
+
+	.tuner_get_frequency	= stb6100_get_frequency,
+	.tuner_set_frequency	= stb6100_set_frequency,
+	.tuner_set_bandwidth	= stb6100_set_bandwidth,
+	.tuner_get_bandwidth	= stb6100_get_bandwidth,
+	.tuner_set_rfsiggain	= NULL,
+};
+
+struct stb6100_config vp1041_stb6100_config = {
+	.tuner_address	= 0x60,
+	.refclock	= 27000000,
+};
+
+static int vp1041_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+	struct i2c_adapter *adapter	= &mantis->adapter;
+
+	int err = 0;
+
+	err = mantis_frontend_power(mantis, POWER_ON);
+	if (err == 0) {
+		mantis_frontend_soft_reset(mantis);
+		msleep(250);
+		mantis->fe = dvb_attach(stb0899_attach, &vp1041_stb0899_config, adapter);
+		if (mantis->fe) {
+			dprintk(MANTIS_ERROR, 1,
+				"found STB0899 DVB-S/DVB-S2 frontend @0x%02x",
+				vp1041_stb0899_config.demod_address);
+
+			if (dvb_attach(stb6100_attach, mantis->fe, &vp1041_stb6100_config, adapter)) {
+				if (!dvb_attach(lnbp21_attach, mantis->fe, adapter, 0, 0))
+					dprintk(MANTIS_ERROR, 1, "No LNBP21 found!");
+			}
+		} else {
+			return -EREMOTEIO;
+		}
+	} else {
+		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+			adapter->name,
+			err);
+
+		return -EIO;
+	}
+
+
+	dprintk(MANTIS_ERROR, 1, "Done!");
+
+	return 0;
+}
+
+struct mantis_hwconfig vp1041_config = {
+	.model_name	= MANTIS_MODEL_NAME,
+	.dev_type	= MANTIS_DEV_TYPE,
+	.ts_size	= MANTIS_TS_188,
+
+	.baud_rate	= MANTIS_BAUD_9600,
+	.parity		= MANTIS_PARITY_NONE,
+	.bytes		= 0,
+
+	.frontend_init	= vp1041_frontend_init,
+	.power		= GPIF_A12,
+	.reset		= GPIF_A13,
+};
diff --git a/drivers/media/pci/mantis/mantis_vp1041.h b/drivers/media/pci/mantis/mantis_vp1041.h
new file mode 100644
index 0000000..1ae5b3d
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_vp1041.h
@@ -0,0 +1,33 @@
+/*
+	Mantis VP-1041 driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP1041_H
+#define __MANTIS_VP1041_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_1041_DVB_S2	0x0031
+#define SKYSTAR_HD2_10		0x0001
+#define SKYSTAR_HD2_20		0x0003
+#define CINERGY_S2_PCI_HD	0x1179
+
+extern struct mantis_hwconfig vp1041_config;
+
+#endif /* __MANTIS_VP1041_H */
diff --git a/drivers/media/pci/mantis/mantis_vp2033.c b/drivers/media/pci/mantis/mantis_vp2033.c
new file mode 100644
index 0000000..1ca6837
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_vp2033.c
@@ -0,0 +1,188 @@
+/*
+	Mantis VP-2033 driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "tda1002x.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp2033.h"
+
+#define MANTIS_MODEL_NAME	"VP-2033"
+#define MANTIS_DEV_TYPE		"DVB-C"
+
+struct tda1002x_config vp2033_tda1002x_cu1216_config = {
+	.demod_address = 0x18 >> 1,
+	.invert = 1,
+};
+
+struct tda10023_config vp2033_tda10023_cu1216_config = {
+	.demod_address = 0x18 >> 1,
+	.invert = 1,
+};
+
+static u8 read_pwm(struct mantis_pci *mantis)
+{
+	struct i2c_adapter *adapter = &mantis->adapter;
+
+	u8 b = 0xff;
+	u8 pwm;
+	struct i2c_msg msg[] = {
+		{.addr = 0x50, .flags = 0, .buf = &b, .len = 1},
+		{.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1}
+	};
+
+	if ((i2c_transfer(adapter, msg, 2) != 2)
+	    || (pwm == 0xff))
+		pwm = 0x48;
+
+	return pwm;
+}
+
+static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct mantis_pci *mantis = fe->dvb->priv;
+	struct i2c_adapter *adapter = &mantis->adapter;
+
+	u8 buf[6];
+	struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)};
+	int i;
+
+#define CU1216_IF 36125000
+#define TUNER_MUL 62500
+
+	u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
+
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = 0xce;
+	buf[3] = (p->frequency < 150000000 ? 0x01 :
+		  p->frequency < 445000000 ? 0x02 : 0x04);
+	buf[4] = 0xde;
+	buf[5] = 0x20;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	if (i2c_transfer(adapter, &msg, 1) != 1)
+		return -EIO;
+
+	/* wait for the pll lock */
+	msg.flags = I2C_M_RD;
+	msg.len = 1;
+	for (i = 0; i < 20; i++) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40))
+			break;
+
+		msleep(10);
+	}
+
+	/* switch the charge pump to the lower current */
+	msg.flags = 0;
+	msg.len = 2;
+	msg.buf = &buf[2];
+	buf[2] &= ~0x40;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	if (i2c_transfer(adapter, &msg, 1) != 1)
+		return -EIO;
+
+	return 0;
+}
+
+static int vp2033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+	struct i2c_adapter *adapter = &mantis->adapter;
+
+	int err = 0;
+
+	err = mantis_frontend_power(mantis, POWER_ON);
+	if (err == 0) {
+		mantis_frontend_soft_reset(mantis);
+		msleep(250);
+
+		dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)");
+		fe = dvb_attach(tda10021_attach, &vp2033_tda1002x_cu1216_config,
+				     adapter,
+				     read_pwm(mantis));
+
+		if (fe) {
+			dprintk(MANTIS_ERROR, 1,
+				"found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x",
+				vp2033_tda1002x_cu1216_config.demod_address);
+		} else {
+			fe = dvb_attach(tda10023_attach, &vp2033_tda10023_cu1216_config,
+					     adapter,
+					     read_pwm(mantis));
+
+			if (fe) {
+				dprintk(MANTIS_ERROR, 1,
+					"found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x",
+					vp2033_tda1002x_cu1216_config.demod_address);
+			}
+		}
+
+		if (fe) {
+			fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set;
+			dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success");
+		} else {
+			return -1;
+		}
+	} else {
+		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+			adapter->name,
+			err);
+
+		return -EIO;
+	}
+
+	mantis->fe = fe;
+	dprintk(MANTIS_DEBUG, 1, "Done!");
+
+	return 0;
+}
+
+struct mantis_hwconfig vp2033_config = {
+	.model_name	= MANTIS_MODEL_NAME,
+	.dev_type	= MANTIS_DEV_TYPE,
+	.ts_size	= MANTIS_TS_204,
+
+	.baud_rate	= MANTIS_BAUD_9600,
+	.parity		= MANTIS_PARITY_NONE,
+	.bytes		= 0,
+
+	.frontend_init	= vp2033_frontend_init,
+	.power		= GPIF_A12,
+	.reset		= GPIF_A13,
+};
diff --git a/drivers/media/pci/mantis/mantis_vp2033.h b/drivers/media/pci/mantis/mantis_vp2033.h
new file mode 100644
index 0000000..c55242b
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_vp2033.h
@@ -0,0 +1,30 @@
+/*
+	Mantis VP-2033 driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP2033_H
+#define __MANTIS_VP2033_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_2033_DVB_C	0x0008
+
+extern struct mantis_hwconfig vp2033_config;
+
+#endif /* __MANTIS_VP2033_H */
diff --git a/drivers/media/pci/mantis/mantis_vp2040.c b/drivers/media/pci/mantis/mantis_vp2040.c
new file mode 100644
index 0000000..d480741
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_vp2040.c
@@ -0,0 +1,187 @@
+/*
+	Mantis VP-2040 driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "tda1002x.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp2040.h"
+
+#define MANTIS_MODEL_NAME	"VP-2040"
+#define MANTIS_DEV_TYPE		"DVB-C"
+
+struct tda1002x_config vp2040_tda1002x_cu1216_config = {
+	.demod_address	= 0x18 >> 1,
+	.invert		= 1,
+};
+
+struct tda10023_config vp2040_tda10023_cu1216_config = {
+	.demod_address	= 0x18 >> 1,
+	.invert		= 1,
+};
+
+static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct mantis_pci *mantis	= fe->dvb->priv;
+	struct i2c_adapter *adapter	= &mantis->adapter;
+
+	u8 buf[6];
+	struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)};
+	int i;
+
+#define CU1216_IF 36125000
+#define TUNER_MUL 62500
+
+	u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
+
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = 0xce;
+	buf[3] = (p->frequency < 150000000 ? 0x01 :
+		  p->frequency < 445000000 ? 0x02 : 0x04);
+	buf[4] = 0xde;
+	buf[5] = 0x20;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	if (i2c_transfer(adapter, &msg, 1) != 1)
+		return -EIO;
+
+	/* wait for the pll lock */
+	msg.flags = I2C_M_RD;
+	msg.len = 1;
+	for (i = 0; i < 20; i++) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40))
+			break;
+
+		msleep(10);
+	}
+
+	/* switch the charge pump to the lower current */
+	msg.flags = 0;
+	msg.len = 2;
+	msg.buf = &buf[2];
+	buf[2] &= ~0x40;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	if (i2c_transfer(adapter, &msg, 1) != 1)
+		return -EIO;
+
+	return 0;
+}
+
+static u8 read_pwm(struct mantis_pci *mantis)
+{
+	struct i2c_adapter *adapter = &mantis->adapter;
+
+	u8 b = 0xff;
+	u8 pwm;
+	struct i2c_msg msg[] = {
+		{.addr = 0x50, .flags = 0, .buf = &b, .len = 1},
+		{.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1}
+	};
+
+	if ((i2c_transfer(adapter, msg, 2) != 2)
+	    || (pwm == 0xff))
+		pwm = 0x48;
+
+	return pwm;
+}
+
+static int vp2040_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+	struct i2c_adapter *adapter = &mantis->adapter;
+
+	int err = 0;
+
+	err = mantis_frontend_power(mantis, POWER_ON);
+	if (err == 0) {
+		mantis_frontend_soft_reset(mantis);
+		msleep(250);
+
+		dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)");
+		fe = dvb_attach(tda10021_attach, &vp2040_tda1002x_cu1216_config,
+				     adapter,
+				     read_pwm(mantis));
+
+		if (fe) {
+			dprintk(MANTIS_ERROR, 1,
+				"found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x",
+				vp2040_tda1002x_cu1216_config.demod_address);
+		} else {
+			fe = dvb_attach(tda10023_attach, &vp2040_tda10023_cu1216_config,
+					     adapter,
+					     read_pwm(mantis));
+
+			if (fe) {
+				dprintk(MANTIS_ERROR, 1,
+					"found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x",
+					vp2040_tda1002x_cu1216_config.demod_address);
+			}
+		}
+
+		if (fe) {
+			fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set;
+			dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success");
+		} else {
+			return -1;
+		}
+	} else {
+		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+			adapter->name,
+			err);
+
+		return -EIO;
+	}
+	mantis->fe = fe;
+	dprintk(MANTIS_DEBUG, 1, "Done!");
+
+	return 0;
+}
+
+struct mantis_hwconfig vp2040_config = {
+	.model_name	= MANTIS_MODEL_NAME,
+	.dev_type	= MANTIS_DEV_TYPE,
+	.ts_size	= MANTIS_TS_204,
+
+	.baud_rate	= MANTIS_BAUD_9600,
+	.parity		= MANTIS_PARITY_NONE,
+	.bytes		= 0,
+
+	.frontend_init	= vp2040_frontend_init,
+	.power		= GPIF_A12,
+	.reset		= GPIF_A13,
+};
diff --git a/drivers/media/pci/mantis/mantis_vp2040.h b/drivers/media/pci/mantis/mantis_vp2040.h
new file mode 100644
index 0000000..d125e21
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_vp2040.h
@@ -0,0 +1,32 @@
+/*
+	Mantis VP-2040 driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP2040_H
+#define __MANTIS_VP2040_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_2040_DVB_C	0x0043
+#define CINERGY_C		0x1178
+#define CABLESTAR_HD2		0x0002
+
+extern struct mantis_hwconfig vp2040_config;
+
+#endif /* __MANTIS_VP2040_H */
diff --git a/drivers/media/pci/mantis/mantis_vp3028.c b/drivers/media/pci/mantis/mantis_vp3028.c
new file mode 100644
index 0000000..4155c83
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_vp3028.c
@@ -0,0 +1,38 @@
+/*
+	Mantis VP-3028 driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "mantis_common.h"
+#include "mantis_vp3028.h"
+
+struct zl10353_config mantis_vp3028_config = {
+	.demod_address	= 0x0f,
+};
+
+#define MANTIS_MODEL_NAME	"VP-3028"
+#define MANTIS_DEV_TYPE		"DVB-T"
+
+struct mantis_hwconfig vp3028_mantis_config = {
+	.model_name	= MANTIS_MODEL_NAME,
+	.dev_type	= MANTIS_DEV_TYPE,
+	.ts_size	= MANTIS_TS_188,
+	.baud_rate	= MANTIS_BAUD_9600,
+	.parity		= MANTIS_PARITY_NONE,
+	.bytes		= 0,
+};
diff --git a/drivers/media/pci/mantis/mantis_vp3028.h b/drivers/media/pci/mantis/mantis_vp3028.h
new file mode 100644
index 0000000..b07be6a
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_vp3028.h
@@ -0,0 +1,33 @@
+/*
+	Mantis VP-3028 driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP3028_H
+#define __MANTIS_VP3028_H
+
+#include "dvb_frontend.h"
+#include "mantis_common.h"
+#include "zl10353.h"
+
+#define MANTIS_VP_3028_DVB_T	0x0028
+
+extern struct zl10353_config mantis_vp3028_config;
+extern struct mantis_hwconfig vp3028_mantis_config;
+
+#endif /* __MANTIS_VP3028_H */
diff --git a/drivers/media/pci/mantis/mantis_vp3030.c b/drivers/media/pci/mantis/mantis_vp3030.c
new file mode 100644
index 0000000..c09308cd
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_vp3030.c
@@ -0,0 +1,105 @@
+/*
+	Mantis VP-3030 driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "zl10353.h"
+#include "tda665x.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp3030.h"
+
+struct zl10353_config mantis_vp3030_config = {
+	.demod_address		= 0x0f,
+};
+
+struct tda665x_config env57h12d5_config = {
+	.name			= "ENV57H12D5 (ET-50DT)",
+	.addr			= 0x60,
+	.frequency_min		=  47000000,
+	.frequency_max		= 862000000,
+	.frequency_offst	=   3616667,
+	.ref_multiplier		= 6, /* 1/6 MHz */
+	.ref_divider		= 100000, /* 1/6 MHz */
+};
+
+#define MANTIS_MODEL_NAME	"VP-3030"
+#define MANTIS_DEV_TYPE		"DVB-T"
+
+
+static int vp3030_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+	struct i2c_adapter *adapter	= &mantis->adapter;
+	struct mantis_hwconfig *config	= mantis->hwconfig;
+	int err = 0;
+
+	mantis_gpio_set_bits(mantis, config->reset, 0);
+	msleep(100);
+	err = mantis_frontend_power(mantis, POWER_ON);
+	msleep(100);
+	mantis_gpio_set_bits(mantis, config->reset, 1);
+
+	if (err == 0) {
+		msleep(250);
+		dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)");
+		fe = dvb_attach(zl10353_attach, &mantis_vp3030_config, adapter);
+
+		if (!fe)
+			return -1;
+
+		dvb_attach(tda665x_attach, fe, &env57h12d5_config, adapter);
+	} else {
+		dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+			adapter->name,
+			err);
+
+		return -EIO;
+
+	}
+	mantis->fe = fe;
+	dprintk(MANTIS_ERROR, 1, "Done!");
+
+	return 0;
+}
+
+struct mantis_hwconfig vp3030_config = {
+	.model_name	= MANTIS_MODEL_NAME,
+	.dev_type	= MANTIS_DEV_TYPE,
+	.ts_size	= MANTIS_TS_188,
+
+	.baud_rate	= MANTIS_BAUD_9600,
+	.parity		= MANTIS_PARITY_NONE,
+	.bytes		= 0,
+
+	.frontend_init	= vp3030_frontend_init,
+	.power		= GPIF_A12,
+	.reset		= GPIF_A13,
+
+	.i2c_mode	= MANTIS_BYTE_MODE
+};
diff --git a/drivers/media/pci/mantis/mantis_vp3030.h b/drivers/media/pci/mantis/mantis_vp3030.h
new file mode 100644
index 0000000..5f12c42
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_vp3030.h
@@ -0,0 +1,30 @@
+/*
+	Mantis VP-3030 driver
+
+	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP3030_H
+#define __MANTIS_VP3030_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_3030_DVB_T	0x0024
+
+extern struct mantis_hwconfig vp3030_config;
+
+#endif /* __MANTIS_VP3030_H */
diff --git a/drivers/media/pci/meye/Kconfig b/drivers/media/pci/meye/Kconfig
new file mode 100644
index 0000000..b4bf848
--- /dev/null
+++ b/drivers/media/pci/meye/Kconfig
@@ -0,0 +1,13 @@
+config VIDEO_MEYE
+	tristate "Sony Vaio Picturebook Motion Eye Video For Linux"
+	depends on PCI && SONY_LAPTOP && VIDEO_V4L2
+	---help---
+	  This is the video4linux driver for the Motion Eye camera found
+	  in the Vaio Picturebook laptops. Please read the material in
+	  <file:Documentation/video4linux/meye.txt> for more information.
+
+	  If you say Y or M here, you need to say Y or M to "Sony Laptop
+	  Extras" in the misc device section.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called meye.
diff --git a/drivers/media/pci/meye/Makefile b/drivers/media/pci/meye/Makefile
new file mode 100644
index 0000000..4938851
--- /dev/null
+++ b/drivers/media/pci/meye/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_MEYE) += meye.o
diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c
new file mode 100644
index 0000000..e5a76da
--- /dev/null
+++ b/drivers/media/pci/meye/meye.c
@@ -0,0 +1,1964 @@
+/*
+ * Motion Eye video4linux driver for Sony Vaio PictureBook
+ *
+ * Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ *
+ * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
+ *
+ * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
+ *
+ * Some parts borrowed from various video4linux drivers, especially
+ * bttv-driver.c and zoran.c, see original files for credits.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/gfp.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
+
+#include "meye.h"
+#include <linux/meye.h>
+
+MODULE_AUTHOR("Stelian Pop <stelian@popies.net>");
+MODULE_DESCRIPTION("v4l2 driver for the MotionEye camera");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(MEYE_DRIVER_VERSION);
+
+/* number of grab buffers */
+static unsigned int gbuffers = 2;
+module_param(gbuffers, int, 0444);
+MODULE_PARM_DESC(gbuffers, "number of capture buffers, default is 2 (32 max)");
+
+/* size of a grab buffer */
+static unsigned int gbufsize = MEYE_MAX_BUFSIZE;
+module_param(gbufsize, int, 0444);
+MODULE_PARM_DESC(gbufsize, "size of the capture buffers, default is 614400"
+		 " (will be rounded up to a page multiple)");
+
+/* /dev/videoX registration number */
+static int video_nr = -1;
+module_param(video_nr, int, 0444);
+MODULE_PARM_DESC(video_nr, "video device to register (0=/dev/video0, etc)");
+
+/* driver structure - only one possible */
+static struct meye meye;
+
+/****************************************************************************/
+/* Memory allocation routines (stolen from bttv-driver.c)                   */
+/****************************************************************************/
+static void *rvmalloc(unsigned long size)
+{
+	void *mem;
+	unsigned long adr;
+
+	size = PAGE_ALIGN(size);
+	mem = vmalloc_32(size);
+	if (mem) {
+		memset(mem, 0, size);
+		adr = (unsigned long) mem;
+		while (size > 0) {
+			SetPageReserved(vmalloc_to_page((void *)adr));
+			adr += PAGE_SIZE;
+			size -= PAGE_SIZE;
+		}
+	}
+	return mem;
+}
+
+static void rvfree(void * mem, unsigned long size)
+{
+	unsigned long adr;
+
+	if (mem) {
+		adr = (unsigned long) mem;
+		while ((long) size > 0) {
+			ClearPageReserved(vmalloc_to_page((void *)adr));
+			adr += PAGE_SIZE;
+			size -= PAGE_SIZE;
+		}
+		vfree(mem);
+	}
+}
+
+/*
+ * return a page table pointing to N pages of locked memory
+ *
+ * NOTE: The meye device expects DMA addresses on 32 bits, we build
+ * a table of 1024 entries = 4 bytes * 1024 = 4096 bytes.
+ */
+static int ptable_alloc(void)
+{
+	u32 *pt;
+	int i;
+
+	memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable));
+
+	/* give only 32 bit DMA addresses */
+	if (dma_set_mask(&meye.mchip_dev->dev, DMA_BIT_MASK(32)))
+		return -1;
+
+	meye.mchip_ptable_toc = dma_alloc_coherent(&meye.mchip_dev->dev,
+						   PAGE_SIZE,
+						   &meye.mchip_dmahandle,
+						   GFP_KERNEL);
+	if (!meye.mchip_ptable_toc) {
+		meye.mchip_dmahandle = 0;
+		return -1;
+	}
+
+	pt = meye.mchip_ptable_toc;
+	for (i = 0; i < MCHIP_NB_PAGES; i++) {
+		dma_addr_t dma;
+		meye.mchip_ptable[i] = dma_alloc_coherent(&meye.mchip_dev->dev,
+							  PAGE_SIZE,
+							  &dma,
+							  GFP_KERNEL);
+		if (!meye.mchip_ptable[i]) {
+			int j;
+			pt = meye.mchip_ptable_toc;
+			for (j = 0; j < i; ++j) {
+				dma = (dma_addr_t) *pt;
+				dma_free_coherent(&meye.mchip_dev->dev,
+						  PAGE_SIZE,
+						  meye.mchip_ptable[j], dma);
+				pt++;
+			}
+			dma_free_coherent(&meye.mchip_dev->dev,
+					  PAGE_SIZE,
+					  meye.mchip_ptable_toc,
+					  meye.mchip_dmahandle);
+			meye.mchip_ptable_toc = NULL;
+			meye.mchip_dmahandle = 0;
+			return -1;
+		}
+		*pt = (u32) dma;
+		pt++;
+	}
+	return 0;
+}
+
+static void ptable_free(void)
+{
+	u32 *pt;
+	int i;
+
+	pt = meye.mchip_ptable_toc;
+	for (i = 0; i < MCHIP_NB_PAGES; i++) {
+		dma_addr_t dma = (dma_addr_t) *pt;
+		if (meye.mchip_ptable[i])
+			dma_free_coherent(&meye.mchip_dev->dev,
+					  PAGE_SIZE,
+					  meye.mchip_ptable[i], dma);
+		pt++;
+	}
+
+	if (meye.mchip_ptable_toc)
+		dma_free_coherent(&meye.mchip_dev->dev,
+				  PAGE_SIZE,
+				  meye.mchip_ptable_toc,
+				  meye.mchip_dmahandle);
+
+	memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable));
+	meye.mchip_ptable_toc = NULL;
+	meye.mchip_dmahandle = 0;
+}
+
+/* copy data from ptable into buf */
+static void ptable_copy(u8 *buf, int start, int size, int pt_pages)
+{
+	int i;
+
+	for (i = 0; i < (size / PAGE_SIZE) * PAGE_SIZE; i += PAGE_SIZE) {
+		memcpy(buf + i, meye.mchip_ptable[start++], PAGE_SIZE);
+		if (start >= pt_pages)
+			start = 0;
+	}
+	memcpy(buf + i, meye.mchip_ptable[start], size % PAGE_SIZE);
+}
+
+/****************************************************************************/
+/* JPEG tables at different qualities to load into the VRJ chip             */
+/****************************************************************************/
+
+/* return a set of quantisation tables based on a quality from 1 to 10 */
+static u16 *jpeg_quantisation_tables(int *length, int quality)
+{
+	static u16 jpeg_tables[][70] = { {
+		0xdbff, 0x4300, 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+		0xffff, 0xffff, 0xffff,
+		0xdbff, 0x4300, 0xff01, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+		0xffff, 0xffff, 0xffff,
+	},
+	{
+		0xdbff, 0x4300, 0x5000, 0x3c37, 0x3c46, 0x5032, 0x4146, 0x5a46,
+		0x5055, 0x785f, 0x82c8, 0x6e78, 0x786e, 0xaff5, 0x91b9, 0xffc8,
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+		0xffff, 0xffff, 0xffff,
+		0xdbff, 0x4300, 0x5501, 0x5a5a, 0x6978, 0xeb78, 0x8282, 0xffeb,
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+		0xffff, 0xffff, 0xffff,
+	},
+	{
+		0xdbff, 0x4300, 0x2800, 0x1e1c, 0x1e23, 0x2819, 0x2123, 0x2d23,
+		0x282b, 0x3c30, 0x4164, 0x373c, 0x3c37, 0x587b, 0x495d, 0x9164,
+		0x9980, 0x8f96, 0x8c80, 0xa08a, 0xe6b4, 0xa0c3, 0xdaaa, 0x8aad,
+		0xc88c, 0xcbff, 0xeeda, 0xfff5, 0xffff, 0xc19b, 0xffff, 0xfaff,
+		0xe6ff, 0xfffd, 0xfff8,
+		0xdbff, 0x4300, 0x2b01, 0x2d2d, 0x353c, 0x763c, 0x4141, 0xf876,
+		0x8ca5, 0xf8a5, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8,
+		0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8,
+		0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8,
+		0xf8f8, 0xf8f8, 0xfff8,
+	},
+	{
+		0xdbff, 0x4300, 0x1b00, 0x1412, 0x1417, 0x1b11, 0x1617, 0x1e17,
+		0x1b1c, 0x2820, 0x2b42, 0x2528, 0x2825, 0x3a51, 0x303d, 0x6042,
+		0x6555, 0x5f64, 0x5d55, 0x6a5b, 0x9978, 0x6a81, 0x9071, 0x5b73,
+		0x855d, 0x86b5, 0x9e90, 0xaba3, 0xabad, 0x8067, 0xc9bc, 0xa6ba,
+		0x99c7, 0xaba8, 0xffa4,
+		0xdbff, 0x4300, 0x1c01, 0x1e1e, 0x2328, 0x4e28, 0x2b2b, 0xa44e,
+		0x5d6e, 0xa46e, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
+		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
+		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
+		0xa4a4, 0xa4a4, 0xffa4,
+	},
+	{
+		0xdbff, 0x4300, 0x1400, 0x0f0e, 0x0f12, 0x140d, 0x1012, 0x1712,
+		0x1415, 0x1e18, 0x2132, 0x1c1e, 0x1e1c, 0x2c3d, 0x242e, 0x4932,
+		0x4c40, 0x474b, 0x4640, 0x5045, 0x735a, 0x5062, 0x6d55, 0x4556,
+		0x6446, 0x6588, 0x776d, 0x817b, 0x8182, 0x604e, 0x978d, 0x7d8c,
+		0x7396, 0x817e, 0xff7c,
+		0xdbff, 0x4300, 0x1501, 0x1717, 0x1a1e, 0x3b1e, 0x2121, 0x7c3b,
+		0x4653, 0x7c53, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c,
+		0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c,
+		0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c,
+		0x7c7c, 0x7c7c, 0xff7c,
+	},
+	{
+		0xdbff, 0x4300, 0x1000, 0x0c0b, 0x0c0e, 0x100a, 0x0d0e, 0x120e,
+		0x1011, 0x1813, 0x1a28, 0x1618, 0x1816, 0x2331, 0x1d25, 0x3a28,
+		0x3d33, 0x393c, 0x3833, 0x4037, 0x5c48, 0x404e, 0x5744, 0x3745,
+		0x5038, 0x516d, 0x5f57, 0x6762, 0x6768, 0x4d3e, 0x7971, 0x6470,
+		0x5c78, 0x6765, 0xff63,
+		0xdbff, 0x4300, 0x1101, 0x1212, 0x1518, 0x2f18, 0x1a1a, 0x632f,
+		0x3842, 0x6342, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363,
+		0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363,
+		0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363,
+		0x6363, 0x6363, 0xff63,
+	},
+	{
+		0xdbff, 0x4300, 0x0d00, 0x0a09, 0x0a0b, 0x0d08, 0x0a0b, 0x0e0b,
+		0x0d0e, 0x130f, 0x1520, 0x1213, 0x1312, 0x1c27, 0x171e, 0x2e20,
+		0x3129, 0x2e30, 0x2d29, 0x332c, 0x4a3a, 0x333e, 0x4636, 0x2c37,
+		0x402d, 0x4157, 0x4c46, 0x524e, 0x5253, 0x3e32, 0x615a, 0x505a,
+		0x4a60, 0x5251, 0xff4f,
+		0xdbff, 0x4300, 0x0e01, 0x0e0e, 0x1113, 0x2613, 0x1515, 0x4f26,
+		0x2d35, 0x4f35, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f,
+		0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f,
+		0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f,
+		0x4f4f, 0x4f4f, 0xff4f,
+	},
+	{
+		0xdbff, 0x4300, 0x0a00, 0x0707, 0x0708, 0x0a06, 0x0808, 0x0b08,
+		0x0a0a, 0x0e0b, 0x1018, 0x0d0e, 0x0e0d, 0x151d, 0x1116, 0x2318,
+		0x251f, 0x2224, 0x221f, 0x2621, 0x372b, 0x262f, 0x3429, 0x2129,
+		0x3022, 0x3141, 0x3934, 0x3e3b, 0x3e3e, 0x2e25, 0x4944, 0x3c43,
+		0x3748, 0x3e3d, 0xff3b,
+		0xdbff, 0x4300, 0x0a01, 0x0b0b, 0x0d0e, 0x1c0e, 0x1010, 0x3b1c,
+		0x2228, 0x3b28, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b,
+		0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b,
+		0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b,
+		0x3b3b, 0x3b3b, 0xff3b,
+	},
+	{
+		0xdbff, 0x4300, 0x0600, 0x0504, 0x0506, 0x0604, 0x0506, 0x0706,
+		0x0607, 0x0a08, 0x0a10, 0x090a, 0x0a09, 0x0e14, 0x0c0f, 0x1710,
+		0x1814, 0x1718, 0x1614, 0x1a16, 0x251d, 0x1a1f, 0x231b, 0x161c,
+		0x2016, 0x202c, 0x2623, 0x2927, 0x292a, 0x1f19, 0x302d, 0x282d,
+		0x2530, 0x2928, 0xff28,
+		0xdbff, 0x4300, 0x0701, 0x0707, 0x080a, 0x130a, 0x0a0a, 0x2813,
+		0x161a, 0x281a, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828,
+		0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828,
+		0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828,
+		0x2828, 0x2828, 0xff28,
+	},
+	{
+		0xdbff, 0x4300, 0x0300, 0x0202, 0x0203, 0x0302, 0x0303, 0x0403,
+		0x0303, 0x0504, 0x0508, 0x0405, 0x0504, 0x070a, 0x0607, 0x0c08,
+		0x0c0a, 0x0b0c, 0x0b0a, 0x0d0b, 0x120e, 0x0d10, 0x110e, 0x0b0e,
+		0x100b, 0x1016, 0x1311, 0x1514, 0x1515, 0x0f0c, 0x1817, 0x1416,
+		0x1218, 0x1514, 0xff14,
+		0xdbff, 0x4300, 0x0301, 0x0404, 0x0405, 0x0905, 0x0505, 0x1409,
+		0x0b0d, 0x140d, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414,
+		0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414,
+		0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414,
+		0x1414, 0x1414, 0xff14,
+	},
+	{
+		0xdbff, 0x4300, 0x0100, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
+		0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
+		0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
+		0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
+		0x0101, 0x0101, 0xff01,
+		0xdbff, 0x4300, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
+		0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
+		0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
+		0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
+		0x0101, 0x0101, 0xff01,
+	} };
+
+	if (quality < 0 || quality > 10) {
+		printk(KERN_WARNING
+		       "meye: invalid quality level %d - using 8\n", quality);
+		quality = 8;
+	}
+
+	*length = ARRAY_SIZE(jpeg_tables[quality]);
+	return jpeg_tables[quality];
+}
+
+/* return a generic set of huffman tables */
+static u16 *jpeg_huffman_tables(int *length)
+{
+	static u16 tables[] = {
+		0xC4FF, 0xB500, 0x0010, 0x0102, 0x0303, 0x0402, 0x0503, 0x0405,
+		0x0004, 0x0100, 0x017D, 0x0302, 0x0400, 0x0511, 0x2112, 0x4131,
+		0x1306, 0x6151, 0x2207, 0x1471, 0x8132, 0xA191, 0x2308, 0xB142,
+		0x15C1, 0xD152, 0x24F0, 0x6233, 0x8272, 0x0A09, 0x1716, 0x1918,
+		0x251A, 0x2726, 0x2928, 0x342A, 0x3635, 0x3837, 0x3A39, 0x4443,
+		0x4645, 0x4847, 0x4A49, 0x5453, 0x5655, 0x5857, 0x5A59, 0x6463,
+		0x6665, 0x6867, 0x6A69, 0x7473, 0x7675, 0x7877, 0x7A79, 0x8483,
+		0x8685, 0x8887, 0x8A89, 0x9392, 0x9594, 0x9796, 0x9998, 0xA29A,
+		0xA4A3, 0xA6A5, 0xA8A7, 0xAAA9, 0xB3B2, 0xB5B4, 0xB7B6, 0xB9B8,
+		0xC2BA, 0xC4C3, 0xC6C5, 0xC8C7, 0xCAC9, 0xD3D2, 0xD5D4, 0xD7D6,
+		0xD9D8, 0xE1DA, 0xE3E2, 0xE5E4, 0xE7E6, 0xE9E8, 0xF1EA, 0xF3F2,
+		0xF5F4, 0xF7F6, 0xF9F8, 0xFFFA,
+		0xC4FF, 0xB500, 0x0011, 0x0102, 0x0402, 0x0304, 0x0704, 0x0405,
+		0x0004, 0x0201, 0x0077, 0x0201, 0x1103, 0x0504, 0x3121, 0x1206,
+		0x5141, 0x6107, 0x1371, 0x3222, 0x0881, 0x4214, 0xA191, 0xC1B1,
+		0x2309, 0x5233, 0x15F0, 0x7262, 0x0AD1, 0x2416, 0xE134, 0xF125,
+		0x1817, 0x1A19, 0x2726, 0x2928, 0x352A, 0x3736, 0x3938, 0x433A,
+		0x4544, 0x4746, 0x4948, 0x534A, 0x5554, 0x5756, 0x5958, 0x635A,
+		0x6564, 0x6766, 0x6968, 0x736A, 0x7574, 0x7776, 0x7978, 0x827A,
+		0x8483, 0x8685, 0x8887, 0x8A89, 0x9392, 0x9594, 0x9796, 0x9998,
+		0xA29A, 0xA4A3, 0xA6A5, 0xA8A7, 0xAAA9, 0xB3B2, 0xB5B4, 0xB7B6,
+		0xB9B8, 0xC2BA, 0xC4C3, 0xC6C5, 0xC8C7, 0xCAC9, 0xD3D2, 0xD5D4,
+		0xD7D6, 0xD9D8, 0xE2DA, 0xE4E3, 0xE6E5, 0xE8E7, 0xEAE9, 0xF3F2,
+		0xF5F4, 0xF7F6, 0xF9F8, 0xFFFA,
+		0xC4FF, 0x1F00, 0x0000, 0x0501, 0x0101, 0x0101, 0x0101, 0x0000,
+		0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0A09,
+		0xFF0B,
+		0xC4FF, 0x1F00, 0x0001, 0x0103, 0x0101, 0x0101, 0x0101, 0x0101,
+		0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0A09,
+		0xFF0B
+	};
+
+	*length = ARRAY_SIZE(tables);
+	return tables;
+}
+
+/****************************************************************************/
+/* MCHIP low-level functions                                                */
+/****************************************************************************/
+
+/* returns the horizontal capture size */
+static inline int mchip_hsize(void)
+{
+	return meye.params.subsample ? 320 : 640;
+}
+
+/* returns the vertical capture size */
+static inline int mchip_vsize(void)
+{
+	return meye.params.subsample ? 240 : 480;
+}
+
+/* waits for a register to be available */
+static void mchip_sync(int reg)
+{
+	u32 status;
+	int i;
+
+	if (reg == MCHIP_MM_FIFO_DATA) {
+		for (i = 0; i < MCHIP_REG_TIMEOUT; i++) {
+			status = readl(meye.mchip_mmregs +
+				       MCHIP_MM_FIFO_STATUS);
+			if (!(status & MCHIP_MM_FIFO_WAIT)) {
+				printk(KERN_WARNING "meye: fifo not ready\n");
+				return;
+			}
+			if (status & MCHIP_MM_FIFO_READY)
+				return;
+			udelay(1);
+		}
+	} else if (reg > 0x80) {
+		u32 mask = (reg < 0x100) ? MCHIP_HIC_STATUS_MCC_RDY
+					 : MCHIP_HIC_STATUS_VRJ_RDY;
+		for (i = 0; i < MCHIP_REG_TIMEOUT; i++) {
+			status = readl(meye.mchip_mmregs + MCHIP_HIC_STATUS);
+			if (status & mask)
+				return;
+			udelay(1);
+		}
+	} else
+		return;
+	printk(KERN_WARNING
+	       "meye: mchip_sync() timeout on reg 0x%x status=0x%x\n",
+	       reg, status);
+}
+
+/* sets a value into the register */
+static inline void mchip_set(int reg, u32 v)
+{
+	mchip_sync(reg);
+	writel(v, meye.mchip_mmregs + reg);
+}
+
+/* get the register value */
+static inline u32 mchip_read(int reg)
+{
+	mchip_sync(reg);
+	return readl(meye.mchip_mmregs + reg);
+}
+
+/* wait for a register to become a particular value */
+static inline int mchip_delay(u32 reg, u32 v)
+{
+	int n = 10;
+	while (--n && mchip_read(reg) != v)
+		udelay(1);
+	return n;
+}
+
+/* setup subsampling */
+static void mchip_subsample(void)
+{
+	mchip_set(MCHIP_MCC_R_SAMPLING, meye.params.subsample);
+	mchip_set(MCHIP_MCC_R_XRANGE, mchip_hsize());
+	mchip_set(MCHIP_MCC_R_YRANGE, mchip_vsize());
+	mchip_set(MCHIP_MCC_B_XRANGE, mchip_hsize());
+	mchip_set(MCHIP_MCC_B_YRANGE, mchip_vsize());
+	mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE);
+}
+
+/* set the framerate into the mchip */
+static void mchip_set_framerate(void)
+{
+	mchip_set(MCHIP_HIC_S_RATE, meye.params.framerate);
+}
+
+/* load some huffman and quantisation tables into the VRJ chip ready
+   for JPEG compression */
+static void mchip_load_tables(void)
+{
+	int i;
+	int length;
+	u16 *tables;
+
+	tables = jpeg_huffman_tables(&length);
+	for (i = 0; i < length; i++)
+		writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA);
+
+	tables = jpeg_quantisation_tables(&length, meye.params.quality);
+	for (i = 0; i < length; i++)
+		writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA);
+}
+
+/* setup the VRJ parameters in the chip */
+static void mchip_vrj_setup(u8 mode)
+{
+	mchip_set(MCHIP_VRJ_BUS_MODE, 5);
+	mchip_set(MCHIP_VRJ_SIGNAL_ACTIVE_LEVEL, 0x1f);
+	mchip_set(MCHIP_VRJ_PDAT_USE, 1);
+	mchip_set(MCHIP_VRJ_IRQ_FLAG, 0xa0);
+	mchip_set(MCHIP_VRJ_MODE_SPECIFY, mode);
+	mchip_set(MCHIP_VRJ_NUM_LINES, mchip_vsize());
+	mchip_set(MCHIP_VRJ_NUM_PIXELS, mchip_hsize());
+	mchip_set(MCHIP_VRJ_NUM_COMPONENTS, 0x1b);
+	mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_LO, 0xFFFF);
+	mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_HI, 0xFFFF);
+	mchip_set(MCHIP_VRJ_COMP_DATA_FORMAT, 0xC);
+	mchip_set(MCHIP_VRJ_RESTART_INTERVAL, 0);
+	mchip_set(MCHIP_VRJ_SOF1, 0x601);
+	mchip_set(MCHIP_VRJ_SOF2, 0x1502);
+	mchip_set(MCHIP_VRJ_SOF3, 0x1503);
+	mchip_set(MCHIP_VRJ_SOF4, 0x1596);
+	mchip_set(MCHIP_VRJ_SOS, 0x0ed0);
+
+	mchip_load_tables();
+}
+
+/* sets the DMA parameters into the chip */
+static void mchip_dma_setup(dma_addr_t dma_addr)
+{
+	int i;
+
+	mchip_set(MCHIP_MM_PT_ADDR, (u32)dma_addr);
+	for (i = 0; i < 4; i++)
+		mchip_set(MCHIP_MM_FIR(i), 0);
+	meye.mchip_fnum = 0;
+}
+
+/* setup for DMA transfers - also zeros the framebuffer */
+static int mchip_dma_alloc(void)
+{
+	if (!meye.mchip_dmahandle)
+		if (ptable_alloc())
+			return -1;
+	return 0;
+}
+
+/* frees the DMA buffer */
+static void mchip_dma_free(void)
+{
+	if (meye.mchip_dmahandle) {
+		mchip_dma_setup(0);
+		ptable_free();
+	}
+}
+
+/* stop any existing HIC action and wait for any dma to complete then
+   reset the dma engine */
+static void mchip_hic_stop(void)
+{
+	int i, j;
+
+	meye.mchip_mode = MCHIP_HIC_MODE_NOOP;
+	if (!(mchip_read(MCHIP_HIC_STATUS) & MCHIP_HIC_STATUS_BUSY))
+		return;
+	for (i = 0; i < 20; ++i) {
+		mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_STOP);
+		mchip_delay(MCHIP_HIC_CMD, 0);
+		for (j = 0; j < 100; ++j) {
+			if (mchip_delay(MCHIP_HIC_STATUS,
+					MCHIP_HIC_STATUS_IDLE))
+				return;
+			msleep(1);
+		}
+		printk(KERN_ERR "meye: need to reset HIC!\n");
+
+		mchip_set(MCHIP_HIC_CTL, MCHIP_HIC_CTL_SOFT_RESET);
+		msleep(250);
+	}
+	printk(KERN_ERR "meye: resetting HIC hanged!\n");
+}
+
+/****************************************************************************/
+/* MCHIP frame processing functions                                         */
+/****************************************************************************/
+
+/* get the next ready frame from the dma engine */
+static u32 mchip_get_frame(void)
+{
+	u32 v;
+
+	v = mchip_read(MCHIP_MM_FIR(meye.mchip_fnum));
+	return v;
+}
+
+/* frees the current frame from the dma engine */
+static void mchip_free_frame(void)
+{
+	mchip_set(MCHIP_MM_FIR(meye.mchip_fnum), 0);
+	meye.mchip_fnum++;
+	meye.mchip_fnum %= 4;
+}
+
+/* read one frame from the framebuffer assuming it was captured using
+   a uncompressed transfer */
+static void mchip_cont_read_frame(u32 v, u8 *buf, int size)
+{
+	int pt_id;
+
+	pt_id = (v >> 17) & 0x3FF;
+
+	ptable_copy(buf, pt_id, size, MCHIP_NB_PAGES);
+}
+
+/* read a compressed frame from the framebuffer */
+static int mchip_comp_read_frame(u32 v, u8 *buf, int size)
+{
+	int pt_start, pt_end, trailer;
+	int fsize;
+	int i;
+
+	pt_start = (v >> 19) & 0xFF;
+	pt_end = (v >> 11) & 0xFF;
+	trailer = (v >> 1) & 0x3FF;
+
+	if (pt_end < pt_start)
+		fsize = (MCHIP_NB_PAGES_MJPEG - pt_start) * PAGE_SIZE +
+			pt_end * PAGE_SIZE + trailer * 4;
+	else
+		fsize = (pt_end - pt_start) * PAGE_SIZE + trailer * 4;
+
+	if (fsize > size) {
+		printk(KERN_WARNING "meye: oversized compressed frame %d\n",
+		       fsize);
+		return -1;
+	}
+
+	ptable_copy(buf, pt_start, fsize, MCHIP_NB_PAGES_MJPEG);
+
+#ifdef MEYE_JPEG_CORRECTION
+
+	/* Some mchip generated jpeg frames are incorrect. In most
+	 * (all ?) of those cases, the final EOI (0xff 0xd9) marker
+	 * is not present at the end of the frame.
+	 *
+	 * Since adding the final marker is not enough to restore
+	 * the jpeg integrity, we drop the frame.
+	 */
+
+	for (i = fsize - 1; i > 0 && buf[i] == 0xff; i--) ;
+
+	if (i < 2 || buf[i - 1] != 0xff || buf[i] != 0xd9)
+		return -1;
+
+#endif
+
+	return fsize;
+}
+
+/* take a picture into SDRAM */
+static void mchip_take_picture(void)
+{
+	int i;
+
+	mchip_hic_stop();
+	mchip_subsample();
+	mchip_dma_setup(meye.mchip_dmahandle);
+
+	mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_CAP);
+	mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
+
+	mchip_delay(MCHIP_HIC_CMD, 0);
+
+	for (i = 0; i < 100; ++i) {
+		if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE))
+			break;
+		msleep(1);
+	}
+}
+
+/* dma a previously taken picture into a buffer */
+static void mchip_get_picture(u8 *buf, int bufsize)
+{
+	u32 v;
+	int i;
+
+	mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_OUT);
+	mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
+
+	mchip_delay(MCHIP_HIC_CMD, 0);
+	for (i = 0; i < 100; ++i) {
+		if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE))
+			break;
+		msleep(1);
+	}
+	for (i = 0; i < 4; ++i) {
+		v = mchip_get_frame();
+		if (v & MCHIP_MM_FIR_RDY) {
+			mchip_cont_read_frame(v, buf, bufsize);
+			break;
+		}
+		mchip_free_frame();
+	}
+}
+
+/* start continuous dma capture */
+static void mchip_continuous_start(void)
+{
+	mchip_hic_stop();
+	mchip_subsample();
+	mchip_set_framerate();
+	mchip_dma_setup(meye.mchip_dmahandle);
+
+	meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT;
+
+	mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_OUT);
+	mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
+
+	mchip_delay(MCHIP_HIC_CMD, 0);
+}
+
+/* compress one frame into a buffer */
+static int mchip_compress_frame(u8 *buf, int bufsize)
+{
+	u32 v;
+	int len = -1, i;
+
+	mchip_vrj_setup(0x3f);
+	udelay(50);
+
+	mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_COMP);
+	mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
+
+	mchip_delay(MCHIP_HIC_CMD, 0);
+	for (i = 0; i < 100; ++i) {
+		if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE))
+			break;
+		msleep(1);
+	}
+
+	for (i = 0; i < 4; ++i) {
+		v = mchip_get_frame();
+		if (v & MCHIP_MM_FIR_RDY) {
+			len = mchip_comp_read_frame(v, buf, bufsize);
+			break;
+		}
+		mchip_free_frame();
+	}
+	return len;
+}
+
+#if 0
+/* uncompress one image into a buffer */
+static int mchip_uncompress_frame(u8 *img, int imgsize, u8 *buf, int bufsize)
+{
+	mchip_vrj_setup(0x3f);
+	udelay(50);
+
+	mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_DECOMP);
+	mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
+
+	mchip_delay(MCHIP_HIC_CMD, 0);
+
+	return mchip_comp_read_frame(buf, bufsize);
+}
+#endif
+
+/* start continuous compressed capture */
+static void mchip_cont_compression_start(void)
+{
+	mchip_hic_stop();
+	mchip_vrj_setup(0x3f);
+	mchip_subsample();
+	mchip_set_framerate();
+	mchip_dma_setup(meye.mchip_dmahandle);
+
+	meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
+
+	mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_COMP);
+	mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
+
+	mchip_delay(MCHIP_HIC_CMD, 0);
+}
+
+/****************************************************************************/
+/* Interrupt handling                                                       */
+/****************************************************************************/
+
+static irqreturn_t meye_irq(int irq, void *dev_id)
+{
+	u32 v;
+	int reqnr;
+	static int sequence;
+
+	v = mchip_read(MCHIP_MM_INTA);
+
+	if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_OUT &&
+	    meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP)
+		return IRQ_NONE;
+
+again:
+	v = mchip_get_frame();
+	if (!(v & MCHIP_MM_FIR_RDY))
+		return IRQ_HANDLED;
+
+	if (meye.mchip_mode == MCHIP_HIC_MODE_CONT_OUT) {
+		if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr,
+			      sizeof(int), &meye.grabq_lock) != sizeof(int)) {
+			mchip_free_frame();
+			return IRQ_HANDLED;
+		}
+		mchip_cont_read_frame(v, meye.grab_fbuffer + gbufsize * reqnr,
+				      mchip_hsize() * mchip_vsize() * 2);
+		meye.grab_buffer[reqnr].size = mchip_hsize() * mchip_vsize() * 2;
+		meye.grab_buffer[reqnr].state = MEYE_BUF_DONE;
+		do_gettimeofday(&meye.grab_buffer[reqnr].timestamp);
+		meye.grab_buffer[reqnr].sequence = sequence++;
+		kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr,
+				sizeof(int), &meye.doneq_lock);
+		wake_up_interruptible(&meye.proc_list);
+	} else {
+		int size;
+		size = mchip_comp_read_frame(v, meye.grab_temp, gbufsize);
+		if (size == -1) {
+			mchip_free_frame();
+			goto again;
+		}
+		if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr,
+			      sizeof(int), &meye.grabq_lock) != sizeof(int)) {
+			mchip_free_frame();
+			goto again;
+		}
+		memcpy(meye.grab_fbuffer + gbufsize * reqnr, meye.grab_temp,
+		       size);
+		meye.grab_buffer[reqnr].size = size;
+		meye.grab_buffer[reqnr].state = MEYE_BUF_DONE;
+		do_gettimeofday(&meye.grab_buffer[reqnr].timestamp);
+		meye.grab_buffer[reqnr].sequence = sequence++;
+		kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr,
+				sizeof(int), &meye.doneq_lock);
+		wake_up_interruptible(&meye.proc_list);
+	}
+	mchip_free_frame();
+	goto again;
+}
+
+/****************************************************************************/
+/* video4linux integration                                                  */
+/****************************************************************************/
+
+static int meye_open(struct file *file)
+{
+	int i;
+
+	if (test_and_set_bit(0, &meye.in_use))
+		return -EBUSY;
+
+	mchip_hic_stop();
+
+	if (mchip_dma_alloc()) {
+		printk(KERN_ERR "meye: mchip framebuffer allocation failed\n");
+		clear_bit(0, &meye.in_use);
+		return -ENOBUFS;
+	}
+
+	for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
+		meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
+	kfifo_reset(&meye.grabq);
+	kfifo_reset(&meye.doneq);
+	return 0;
+}
+
+static int meye_release(struct file *file)
+{
+	mchip_hic_stop();
+	mchip_dma_free();
+	clear_bit(0, &meye.in_use);
+	return 0;
+}
+
+static int meyeioc_g_params(struct meye_params *p)
+{
+	*p = meye.params;
+	return 0;
+}
+
+static int meyeioc_s_params(struct meye_params *jp)
+{
+	if (jp->subsample > 1)
+		return -EINVAL;
+
+	if (jp->quality > 10)
+		return -EINVAL;
+
+	if (jp->sharpness > 63 || jp->agc > 63 || jp->picture > 63)
+		return -EINVAL;
+
+	if (jp->framerate > 31)
+		return -EINVAL;
+
+	mutex_lock(&meye.lock);
+
+	if (meye.params.subsample != jp->subsample ||
+	    meye.params.quality != jp->quality)
+		mchip_hic_stop();	/* need restart */
+
+	meye.params = *jp;
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS,
+			      meye.params.sharpness);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC,
+			      meye.params.agc);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE,
+			      meye.params.picture);
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int meyeioc_qbuf_capt(int *nb)
+{
+	if (!meye.grab_fbuffer)
+		return -EINVAL;
+
+	if (*nb >= gbuffers)
+		return -EINVAL;
+
+	if (*nb < 0) {
+		/* stop capture */
+		mchip_hic_stop();
+		return 0;
+	}
+
+	if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED)
+		return -EBUSY;
+
+	mutex_lock(&meye.lock);
+
+	if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP)
+		mchip_cont_compression_start();
+
+	meye.grab_buffer[*nb].state = MEYE_BUF_USING;
+	kfifo_in_locked(&meye.grabq, (unsigned char *)nb, sizeof(int),
+			 &meye.grabq_lock);
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int meyeioc_sync(struct file *file, void *fh, int *i)
+{
+	int unused;
+
+	if (*i < 0 || *i >= gbuffers)
+		return -EINVAL;
+
+	mutex_lock(&meye.lock);
+	switch (meye.grab_buffer[*i].state) {
+
+	case MEYE_BUF_UNUSED:
+		mutex_unlock(&meye.lock);
+		return -EINVAL;
+	case MEYE_BUF_USING:
+		if (file->f_flags & O_NONBLOCK) {
+			mutex_unlock(&meye.lock);
+			return -EAGAIN;
+		}
+		if (wait_event_interruptible(meye.proc_list,
+			(meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
+			mutex_unlock(&meye.lock);
+			return -EINTR;
+		}
+		/* fall through */
+	case MEYE_BUF_DONE:
+		meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
+		if (kfifo_out_locked(&meye.doneq, (unsigned char *)&unused,
+				sizeof(int), &meye.doneq_lock) != sizeof(int))
+					break;
+	}
+	*i = meye.grab_buffer[*i].size;
+	mutex_unlock(&meye.lock);
+	return 0;
+}
+
+static int meyeioc_stillcapt(void)
+{
+	if (!meye.grab_fbuffer)
+		return -EINVAL;
+
+	if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
+		return -EBUSY;
+
+	mutex_lock(&meye.lock);
+	meye.grab_buffer[0].state = MEYE_BUF_USING;
+	mchip_take_picture();
+
+	mchip_get_picture(meye.grab_fbuffer,
+			mchip_hsize() * mchip_vsize() * 2);
+
+	meye.grab_buffer[0].state = MEYE_BUF_DONE;
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int meyeioc_stilljcapt(int *len)
+{
+	if (!meye.grab_fbuffer)
+		return -EINVAL;
+
+	if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
+		return -EBUSY;
+
+	mutex_lock(&meye.lock);
+	meye.grab_buffer[0].state = MEYE_BUF_USING;
+	*len = -1;
+
+	while (*len == -1) {
+		mchip_take_picture();
+		*len = mchip_compress_frame(meye.grab_fbuffer, gbufsize);
+	}
+
+	meye.grab_buffer[0].state = MEYE_BUF_DONE;
+	mutex_unlock(&meye.lock);
+	return 0;
+}
+
+static int vidioc_querycap(struct file *file, void *fh,
+				struct v4l2_capability *cap)
+{
+	strcpy(cap->driver, "meye");
+	strcpy(cap->card, "meye");
+	sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev));
+
+	cap->version = (MEYE_DRIVER_MAJORVERSION << 8) +
+		       MEYE_DRIVER_MINORVERSION;
+
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+			    V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+	if (i->index != 0)
+		return -EINVAL;
+
+	strcpy(i->name, "Camera");
+	i->type = V4L2_INPUT_TYPE_CAMERA;
+
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh,
+				struct v4l2_queryctrl *c)
+{
+	switch (c->id) {
+
+	case V4L2_CID_BRIGHTNESS:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "Brightness");
+		c->minimum = 0;
+		c->maximum = 63;
+		c->step = 1;
+		c->default_value = 32;
+		c->flags = 0;
+		break;
+	case V4L2_CID_HUE:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "Hue");
+		c->minimum = 0;
+		c->maximum = 63;
+		c->step = 1;
+		c->default_value = 32;
+		c->flags = 0;
+		break;
+	case V4L2_CID_CONTRAST:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "Contrast");
+		c->minimum = 0;
+		c->maximum = 63;
+		c->step = 1;
+		c->default_value = 32;
+		c->flags = 0;
+		break;
+	case V4L2_CID_SATURATION:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "Saturation");
+		c->minimum = 0;
+		c->maximum = 63;
+		c->step = 1;
+		c->default_value = 32;
+		c->flags = 0;
+		break;
+	case V4L2_CID_AGC:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "Agc");
+		c->minimum = 0;
+		c->maximum = 63;
+		c->step = 1;
+		c->default_value = 48;
+		c->flags = 0;
+		break;
+	case V4L2_CID_MEYE_SHARPNESS:
+	case V4L2_CID_SHARPNESS:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "Sharpness");
+		c->minimum = 0;
+		c->maximum = 63;
+		c->step = 1;
+		c->default_value = 32;
+
+		/* Continue to report legacy private SHARPNESS ctrl but
+		 * say it is disabled in preference to ctrl in the spec
+		 */
+		c->flags = (c->id == V4L2_CID_SHARPNESS) ? 0 :
+						V4L2_CTRL_FLAG_DISABLED;
+		break;
+	case V4L2_CID_PICTURE:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "Picture");
+		c->minimum = 0;
+		c->maximum = 63;
+		c->step = 1;
+		c->default_value = 0;
+		c->flags = 0;
+		break;
+	case V4L2_CID_JPEGQUAL:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "JPEG quality");
+		c->minimum = 0;
+		c->maximum = 10;
+		c->step = 1;
+		c->default_value = 8;
+		c->flags = 0;
+		break;
+	case V4L2_CID_FRAMERATE:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "Framerate");
+		c->minimum = 0;
+		c->maximum = 31;
+		c->step = 1;
+		c->default_value = 0;
+		c->flags = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+{
+	mutex_lock(&meye.lock);
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		sony_pic_camera_command(
+			SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, c->value);
+		meye.brightness = c->value << 10;
+		break;
+	case V4L2_CID_HUE:
+		sony_pic_camera_command(
+			SONY_PIC_COMMAND_SETCAMERAHUE, c->value);
+		meye.hue = c->value << 10;
+		break;
+	case V4L2_CID_CONTRAST:
+		sony_pic_camera_command(
+			SONY_PIC_COMMAND_SETCAMERACONTRAST, c->value);
+		meye.contrast = c->value << 10;
+		break;
+	case V4L2_CID_SATURATION:
+		sony_pic_camera_command(
+			SONY_PIC_COMMAND_SETCAMERACOLOR, c->value);
+		meye.colour = c->value << 10;
+		break;
+	case V4L2_CID_AGC:
+		sony_pic_camera_command(
+			SONY_PIC_COMMAND_SETCAMERAAGC, c->value);
+		meye.params.agc = c->value;
+		break;
+	case V4L2_CID_SHARPNESS:
+	case V4L2_CID_MEYE_SHARPNESS:
+		sony_pic_camera_command(
+			SONY_PIC_COMMAND_SETCAMERASHARPNESS, c->value);
+		meye.params.sharpness = c->value;
+		break;
+	case V4L2_CID_PICTURE:
+		sony_pic_camera_command(
+			SONY_PIC_COMMAND_SETCAMERAPICTURE, c->value);
+		meye.params.picture = c->value;
+		break;
+	case V4L2_CID_JPEGQUAL:
+		meye.params.quality = c->value;
+		break;
+	case V4L2_CID_FRAMERATE:
+		meye.params.framerate = c->value;
+		break;
+	default:
+		mutex_unlock(&meye.lock);
+		return -EINVAL;
+	}
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+{
+	mutex_lock(&meye.lock);
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		c->value = meye.brightness >> 10;
+		break;
+	case V4L2_CID_HUE:
+		c->value = meye.hue >> 10;
+		break;
+	case V4L2_CID_CONTRAST:
+		c->value = meye.contrast >> 10;
+		break;
+	case V4L2_CID_SATURATION:
+		c->value = meye.colour >> 10;
+		break;
+	case V4L2_CID_AGC:
+		c->value = meye.params.agc;
+		break;
+	case V4L2_CID_SHARPNESS:
+	case V4L2_CID_MEYE_SHARPNESS:
+		c->value = meye.params.sharpness;
+		break;
+	case V4L2_CID_PICTURE:
+		c->value = meye.params.picture;
+		break;
+	case V4L2_CID_JPEGQUAL:
+		c->value = meye.params.quality;
+		break;
+	case V4L2_CID_FRAMERATE:
+		c->value = meye.params.framerate;
+		break;
+	default:
+		mutex_unlock(&meye.lock);
+		return -EINVAL;
+	}
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
+				struct v4l2_fmtdesc *f)
+{
+	if (f->index > 1)
+		return -EINVAL;
+
+	if (f->index == 0) {
+		/* standard YUV 422 capture */
+		f->flags = 0;
+		strcpy(f->description, "YUV422");
+		f->pixelformat = V4L2_PIX_FMT_YUYV;
+	} else {
+		/* compressed MJPEG capture */
+		f->flags = V4L2_FMT_FLAG_COMPRESSED;
+		strcpy(f->description, "MJPEG");
+		f->pixelformat = V4L2_PIX_FMT_MJPEG;
+	}
+
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
+				struct v4l2_format *f)
+{
+	if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
+	    f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
+		return -EINVAL;
+
+	if (f->fmt.pix.field != V4L2_FIELD_ANY &&
+	    f->fmt.pix.field != V4L2_FIELD_NONE)
+		return -EINVAL;
+
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+
+	if (f->fmt.pix.width <= 320) {
+		f->fmt.pix.width = 320;
+		f->fmt.pix.height = 240;
+	} else {
+		f->fmt.pix.width = 640;
+		f->fmt.pix.height = 480;
+	}
+
+	f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+	f->fmt.pix.sizeimage = f->fmt.pix.height *
+			       f->fmt.pix.bytesperline;
+	f->fmt.pix.colorspace = 0;
+	f->fmt.pix.priv = 0;
+
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
+				    struct v4l2_format *f)
+{
+	switch (meye.mchip_mode) {
+	case MCHIP_HIC_MODE_CONT_OUT:
+	default:
+		f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+		break;
+	case MCHIP_HIC_MODE_CONT_COMP:
+		f->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
+		break;
+	}
+
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.width = mchip_hsize();
+	f->fmt.pix.height = mchip_vsize();
+	f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+	f->fmt.pix.sizeimage = f->fmt.pix.height *
+			       f->fmt.pix.bytesperline;
+
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
+				    struct v4l2_format *f)
+{
+	if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
+	    f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
+		return -EINVAL;
+
+	if (f->fmt.pix.field != V4L2_FIELD_ANY &&
+	    f->fmt.pix.field != V4L2_FIELD_NONE)
+		return -EINVAL;
+
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	mutex_lock(&meye.lock);
+
+	if (f->fmt.pix.width <= 320) {
+		f->fmt.pix.width = 320;
+		f->fmt.pix.height = 240;
+		meye.params.subsample = 1;
+	} else {
+		f->fmt.pix.width = 640;
+		f->fmt.pix.height = 480;
+		meye.params.subsample = 0;
+	}
+
+	switch (f->fmt.pix.pixelformat) {
+	case V4L2_PIX_FMT_YUYV:
+		meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT;
+		break;
+	case V4L2_PIX_FMT_MJPEG:
+		meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
+		break;
+	}
+
+	mutex_unlock(&meye.lock);
+	f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+	f->fmt.pix.sizeimage = f->fmt.pix.height *
+			       f->fmt.pix.bytesperline;
+	f->fmt.pix.colorspace = 0;
+	f->fmt.pix.priv = 0;
+
+	return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *fh,
+				struct v4l2_requestbuffers *req)
+{
+	int i;
+
+	if (req->memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+
+	if (meye.grab_fbuffer && req->count == gbuffers) {
+		/* already allocated, no modifications */
+		return 0;
+	}
+
+	mutex_lock(&meye.lock);
+	if (meye.grab_fbuffer) {
+		for (i = 0; i < gbuffers; i++)
+			if (meye.vma_use_count[i]) {
+				mutex_unlock(&meye.lock);
+				return -EINVAL;
+			}
+		rvfree(meye.grab_fbuffer, gbuffers * gbufsize);
+		meye.grab_fbuffer = NULL;
+	}
+
+	gbuffers = max(2, min((int)req->count, MEYE_MAX_BUFNBRS));
+	req->count = gbuffers;
+	meye.grab_fbuffer = rvmalloc(gbuffers * gbufsize);
+
+	if (!meye.grab_fbuffer) {
+		printk(KERN_ERR "meye: v4l framebuffer allocation"
+				" failed\n");
+		mutex_unlock(&meye.lock);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < gbuffers; i++)
+		meye.vma_use_count[i] = 0;
+
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+	unsigned int index = buf->index;
+
+	if (index >= gbuffers)
+		return -EINVAL;
+
+	buf->bytesused = meye.grab_buffer[index].size;
+	buf->flags = V4L2_BUF_FLAG_MAPPED;
+
+	if (meye.grab_buffer[index].state == MEYE_BUF_USING)
+		buf->flags |= V4L2_BUF_FLAG_QUEUED;
+
+	if (meye.grab_buffer[index].state == MEYE_BUF_DONE)
+		buf->flags |= V4L2_BUF_FLAG_DONE;
+
+	buf->field = V4L2_FIELD_NONE;
+	buf->timestamp = meye.grab_buffer[index].timestamp;
+	buf->sequence = meye.grab_buffer[index].sequence;
+	buf->memory = V4L2_MEMORY_MMAP;
+	buf->m.offset = index * gbufsize;
+	buf->length = gbufsize;
+
+	return 0;
+}
+
+static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+	if (buf->memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+
+	if (buf->index >= gbuffers)
+		return -EINVAL;
+
+	if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED)
+		return -EINVAL;
+
+	mutex_lock(&meye.lock);
+	buf->flags |= V4L2_BUF_FLAG_QUEUED;
+	buf->flags &= ~V4L2_BUF_FLAG_DONE;
+	meye.grab_buffer[buf->index].state = MEYE_BUF_USING;
+	kfifo_in_locked(&meye.grabq, (unsigned char *)&buf->index,
+			sizeof(int), &meye.grabq_lock);
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+	int reqnr;
+
+	if (buf->memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+
+	mutex_lock(&meye.lock);
+
+	if (kfifo_len(&meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {
+		mutex_unlock(&meye.lock);
+		return -EAGAIN;
+	}
+
+	if (wait_event_interruptible(meye.proc_list,
+				     kfifo_len(&meye.doneq) != 0) < 0) {
+		mutex_unlock(&meye.lock);
+		return -EINTR;
+	}
+
+	if (!kfifo_out_locked(&meye.doneq, (unsigned char *)&reqnr,
+		       sizeof(int), &meye.doneq_lock)) {
+		mutex_unlock(&meye.lock);
+		return -EBUSY;
+	}
+
+	if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) {
+		mutex_unlock(&meye.lock);
+		return -EINVAL;
+	}
+
+	buf->index = reqnr;
+	buf->bytesused = meye.grab_buffer[reqnr].size;
+	buf->flags = V4L2_BUF_FLAG_MAPPED;
+	buf->field = V4L2_FIELD_NONE;
+	buf->timestamp = meye.grab_buffer[reqnr].timestamp;
+	buf->sequence = meye.grab_buffer[reqnr].sequence;
+	buf->memory = V4L2_MEMORY_MMAP;
+	buf->m.offset = reqnr * gbufsize;
+	buf->length = gbufsize;
+	meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED;
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+	mutex_lock(&meye.lock);
+
+	switch (meye.mchip_mode) {
+	case MCHIP_HIC_MODE_CONT_OUT:
+		mchip_continuous_start();
+		break;
+	case MCHIP_HIC_MODE_CONT_COMP:
+		mchip_cont_compression_start();
+		break;
+	default:
+		mutex_unlock(&meye.lock);
+		return -EINVAL;
+	}
+
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+	mutex_lock(&meye.lock);
+	mchip_hic_stop();
+	kfifo_reset(&meye.grabq);
+	kfifo_reset(&meye.doneq);
+
+	for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
+		meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
+
+	mutex_unlock(&meye.lock);
+	return 0;
+}
+
+static long vidioc_default(struct file *file, void *fh, bool valid_prio,
+						int cmd, void *arg)
+{
+	switch (cmd) {
+	case MEYEIOC_G_PARAMS:
+		return meyeioc_g_params((struct meye_params *) arg);
+
+	case MEYEIOC_S_PARAMS:
+		return meyeioc_s_params((struct meye_params *) arg);
+
+	case MEYEIOC_QBUF_CAPT:
+		return meyeioc_qbuf_capt((int *) arg);
+
+	case MEYEIOC_SYNC:
+		return meyeioc_sync(file, fh, (int *) arg);
+
+	case MEYEIOC_STILLCAPT:
+		return meyeioc_stillcapt();
+
+	case MEYEIOC_STILLJCAPT:
+		return meyeioc_stilljcapt((int *) arg);
+
+	default:
+		return -ENOTTY;
+	}
+
+}
+
+static unsigned int meye_poll(struct file *file, poll_table *wait)
+{
+	unsigned int res = 0;
+
+	mutex_lock(&meye.lock);
+	poll_wait(file, &meye.proc_list, wait);
+	if (kfifo_len(&meye.doneq))
+		res = POLLIN | POLLRDNORM;
+	mutex_unlock(&meye.lock);
+	return res;
+}
+
+static void meye_vm_open(struct vm_area_struct *vma)
+{
+	long idx = (long)vma->vm_private_data;
+	meye.vma_use_count[idx]++;
+}
+
+static void meye_vm_close(struct vm_area_struct *vma)
+{
+	long idx = (long)vma->vm_private_data;
+	meye.vma_use_count[idx]--;
+}
+
+static const struct vm_operations_struct meye_vm_ops = {
+	.open		= meye_vm_open,
+	.close		= meye_vm_close,
+};
+
+static int meye_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	unsigned long start = vma->vm_start;
+	unsigned long size = vma->vm_end - vma->vm_start;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	unsigned long page, pos;
+
+	mutex_lock(&meye.lock);
+	if (size > gbuffers * gbufsize) {
+		mutex_unlock(&meye.lock);
+		return -EINVAL;
+	}
+	if (!meye.grab_fbuffer) {
+		int i;
+
+		/* lazy allocation */
+		meye.grab_fbuffer = rvmalloc(gbuffers*gbufsize);
+		if (!meye.grab_fbuffer) {
+			printk(KERN_ERR "meye: v4l framebuffer allocation failed\n");
+			mutex_unlock(&meye.lock);
+			return -ENOMEM;
+		}
+		for (i = 0; i < gbuffers; i++)
+			meye.vma_use_count[i] = 0;
+	}
+	pos = (unsigned long)meye.grab_fbuffer + offset;
+
+	while (size > 0) {
+		page = vmalloc_to_pfn((void *)pos);
+		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
+			mutex_unlock(&meye.lock);
+			return -EAGAIN;
+		}
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+
+	vma->vm_ops = &meye_vm_ops;
+	vma->vm_flags &= ~VM_IO;	/* not I/O memory */
+	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+	vma->vm_private_data = (void *) (offset / gbufsize);
+	meye_vm_open(vma);
+
+	mutex_unlock(&meye.lock);
+	return 0;
+}
+
+static const struct v4l2_file_operations meye_fops = {
+	.owner		= THIS_MODULE,
+	.open		= meye_open,
+	.release	= meye_release,
+	.mmap		= meye_mmap,
+	.unlocked_ioctl	= video_ioctl2,
+	.poll		= meye_poll,
+};
+
+static const struct v4l2_ioctl_ops meye_ioctl_ops = {
+	.vidioc_querycap	= vidioc_querycap,
+	.vidioc_enum_input	= vidioc_enum_input,
+	.vidioc_g_input		= vidioc_g_input,
+	.vidioc_s_input		= vidioc_s_input,
+	.vidioc_queryctrl	= vidioc_queryctrl,
+	.vidioc_s_ctrl		= vidioc_s_ctrl,
+	.vidioc_g_ctrl		= vidioc_g_ctrl,
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,
+	.vidioc_reqbufs		= vidioc_reqbufs,
+	.vidioc_querybuf	= vidioc_querybuf,
+	.vidioc_qbuf		= vidioc_qbuf,
+	.vidioc_dqbuf		= vidioc_dqbuf,
+	.vidioc_streamon	= vidioc_streamon,
+	.vidioc_streamoff	= vidioc_streamoff,
+	.vidioc_default		= vidioc_default,
+};
+
+static struct video_device meye_template = {
+	.name		= "meye",
+	.fops		= &meye_fops,
+	.ioctl_ops 	= &meye_ioctl_ops,
+	.release	= video_device_release,
+};
+
+#ifdef CONFIG_PM
+static int meye_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	pci_save_state(pdev);
+	meye.pm_mchip_mode = meye.mchip_mode;
+	mchip_hic_stop();
+	mchip_set(MCHIP_MM_INTA, 0x0);
+	return 0;
+}
+
+static int meye_resume(struct pci_dev *pdev)
+{
+	pci_restore_state(pdev);
+	pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1);
+
+	mchip_delay(MCHIP_HIC_CMD, 0);
+	mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE);
+	msleep(1);
+	mchip_set(MCHIP_VRJ_SOFT_RESET, 1);
+	msleep(1);
+	mchip_set(MCHIP_MM_PCI_MODE, 5);
+	msleep(1);
+	mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK);
+
+	switch (meye.pm_mchip_mode) {
+	case MCHIP_HIC_MODE_CONT_OUT:
+		mchip_continuous_start();
+		break;
+	case MCHIP_HIC_MODE_CONT_COMP:
+		mchip_cont_compression_start();
+		break;
+	}
+	return 0;
+}
+#endif
+
+static int __devinit meye_probe(struct pci_dev *pcidev,
+				const struct pci_device_id *ent)
+{
+	struct v4l2_device *v4l2_dev = &meye.v4l2_dev;
+	int ret = -EBUSY;
+	unsigned long mchip_adr;
+
+	if (meye.mchip_dev != NULL) {
+		printk(KERN_ERR "meye: only one device allowed!\n");
+		goto outnotdev;
+	}
+
+	ret = v4l2_device_register(&pcidev->dev, v4l2_dev);
+	if (ret < 0) {
+		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+		return ret;
+	}
+	ret = -ENOMEM;
+	meye.mchip_dev = pcidev;
+	meye.vdev = video_device_alloc();
+	if (!meye.vdev) {
+		v4l2_err(v4l2_dev, "video_device_alloc() failed!\n");
+		goto outnotdev;
+	}
+
+	meye.grab_temp = vmalloc(MCHIP_NB_PAGES_MJPEG * PAGE_SIZE);
+	if (!meye.grab_temp) {
+		v4l2_err(v4l2_dev, "grab buffer allocation failed\n");
+		goto outvmalloc;
+	}
+
+	spin_lock_init(&meye.grabq_lock);
+	if (kfifo_alloc(&meye.grabq, sizeof(int) * MEYE_MAX_BUFNBRS,
+				GFP_KERNEL)) {
+		v4l2_err(v4l2_dev, "fifo allocation failed\n");
+		goto outkfifoalloc1;
+	}
+	spin_lock_init(&meye.doneq_lock);
+	if (kfifo_alloc(&meye.doneq, sizeof(int) * MEYE_MAX_BUFNBRS,
+				GFP_KERNEL)) {
+		v4l2_err(v4l2_dev, "fifo allocation failed\n");
+		goto outkfifoalloc2;
+	}
+
+	memcpy(meye.vdev, &meye_template, sizeof(meye_template));
+	meye.vdev->v4l2_dev = &meye.v4l2_dev;
+
+	ret = -EIO;
+	if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) {
+		v4l2_err(v4l2_dev, "meye: unable to power on the camera\n");
+		v4l2_err(v4l2_dev, "meye: did you enable the camera in "
+				"sonypi using the module options ?\n");
+		goto outsonypienable;
+	}
+
+	if ((ret = pci_enable_device(meye.mchip_dev))) {
+		v4l2_err(v4l2_dev, "meye: pci_enable_device failed\n");
+		goto outenabledev;
+	}
+
+	mchip_adr = pci_resource_start(meye.mchip_dev,0);
+	if (!mchip_adr) {
+		v4l2_err(v4l2_dev, "meye: mchip has no device base address\n");
+		goto outregions;
+	}
+	if (!request_mem_region(pci_resource_start(meye.mchip_dev, 0),
+				pci_resource_len(meye.mchip_dev, 0),
+				"meye")) {
+		v4l2_err(v4l2_dev, "meye: request_mem_region failed\n");
+		goto outregions;
+	}
+	meye.mchip_mmregs = ioremap(mchip_adr, MCHIP_MM_REGS);
+	if (!meye.mchip_mmregs) {
+		v4l2_err(v4l2_dev, "meye: ioremap failed\n");
+		goto outremap;
+	}
+
+	meye.mchip_irq = pcidev->irq;
+	if (request_irq(meye.mchip_irq, meye_irq,
+			IRQF_DISABLED | IRQF_SHARED, "meye", meye_irq)) {
+		v4l2_err(v4l2_dev, "request_irq failed\n");
+		goto outreqirq;
+	}
+
+	pci_write_config_byte(meye.mchip_dev, PCI_CACHE_LINE_SIZE, 8);
+	pci_write_config_byte(meye.mchip_dev, PCI_LATENCY_TIMER, 64);
+
+	pci_set_master(meye.mchip_dev);
+
+	/* Ask the camera to perform a soft reset. */
+	pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1);
+
+	mchip_delay(MCHIP_HIC_CMD, 0);
+	mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE);
+
+	msleep(1);
+	mchip_set(MCHIP_VRJ_SOFT_RESET, 1);
+
+	msleep(1);
+	mchip_set(MCHIP_MM_PCI_MODE, 5);
+
+	msleep(1);
+	mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK);
+
+	mutex_init(&meye.lock);
+	init_waitqueue_head(&meye.proc_list);
+	meye.brightness = 32 << 10;
+	meye.hue = 32 << 10;
+	meye.colour = 32 << 10;
+	meye.contrast = 32 << 10;
+	meye.params.subsample = 0;
+	meye.params.quality = 8;
+	meye.params.sharpness = 32;
+	meye.params.agc = 48;
+	meye.params.picture = 0;
+	meye.params.framerate = 0;
+
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, 32);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE, 32);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR, 32);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST, 32);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS, 32);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48);
+
+	if (video_register_device(meye.vdev, VFL_TYPE_GRABBER,
+				  video_nr) < 0) {
+		v4l2_err(v4l2_dev, "video_register_device failed\n");
+		goto outvideoreg;
+	}
+
+	v4l2_info(v4l2_dev, "Motion Eye Camera Driver v%s.\n",
+	       MEYE_DRIVER_VERSION);
+	v4l2_info(v4l2_dev, "mchip KL5A72002 rev. %d, base %lx, irq %d\n",
+	       meye.mchip_dev->revision, mchip_adr, meye.mchip_irq);
+
+	return 0;
+
+outvideoreg:
+	free_irq(meye.mchip_irq, meye_irq);
+outreqirq:
+	iounmap(meye.mchip_mmregs);
+outremap:
+	release_mem_region(pci_resource_start(meye.mchip_dev, 0),
+			   pci_resource_len(meye.mchip_dev, 0));
+outregions:
+	pci_disable_device(meye.mchip_dev);
+outenabledev:
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);
+outsonypienable:
+	kfifo_free(&meye.doneq);
+outkfifoalloc2:
+	kfifo_free(&meye.grabq);
+outkfifoalloc1:
+	vfree(meye.grab_temp);
+outvmalloc:
+	video_device_release(meye.vdev);
+outnotdev:
+	return ret;
+}
+
+static void __devexit meye_remove(struct pci_dev *pcidev)
+{
+	video_unregister_device(meye.vdev);
+
+	mchip_hic_stop();
+
+	mchip_dma_free();
+
+	/* disable interrupts */
+	mchip_set(MCHIP_MM_INTA, 0x0);
+
+	free_irq(meye.mchip_irq, meye_irq);
+
+	iounmap(meye.mchip_mmregs);
+
+	release_mem_region(pci_resource_start(meye.mchip_dev, 0),
+			   pci_resource_len(meye.mchip_dev, 0));
+
+	pci_disable_device(meye.mchip_dev);
+
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);
+
+	kfifo_free(&meye.doneq);
+	kfifo_free(&meye.grabq);
+
+	vfree(meye.grab_temp);
+
+	if (meye.grab_fbuffer) {
+		rvfree(meye.grab_fbuffer, gbuffers*gbufsize);
+		meye.grab_fbuffer = NULL;
+	}
+
+	printk(KERN_INFO "meye: removed\n");
+}
+
+static struct pci_device_id meye_pci_tbl[] = {
+	{ PCI_VDEVICE(KAWASAKI, PCI_DEVICE_ID_MCHIP_KL5A72002), 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(pci, meye_pci_tbl);
+
+static struct pci_driver meye_driver = {
+	.name		= "meye",
+	.id_table	= meye_pci_tbl,
+	.probe		= meye_probe,
+	.remove		= __devexit_p(meye_remove),
+#ifdef CONFIG_PM
+	.suspend	= meye_suspend,
+	.resume		= meye_resume,
+#endif
+};
+
+static int __init meye_init(void)
+{
+	gbuffers = max(2, min((int)gbuffers, MEYE_MAX_BUFNBRS));
+	if (gbufsize < 0 || gbufsize > MEYE_MAX_BUFSIZE)
+		gbufsize = MEYE_MAX_BUFSIZE;
+	gbufsize = PAGE_ALIGN(gbufsize);
+	printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) "
+			 "for capture\n",
+			 gbuffers,
+			 gbufsize / 1024, gbuffers * gbufsize / 1024);
+	return pci_register_driver(&meye_driver);
+}
+
+static void __exit meye_exit(void)
+{
+	pci_unregister_driver(&meye_driver);
+}
+
+module_init(meye_init);
+module_exit(meye_exit);
diff --git a/drivers/media/pci/meye/meye.h b/drivers/media/pci/meye/meye.h
new file mode 100644
index 0000000..4bdeb03
--- /dev/null
+++ b/drivers/media/pci/meye/meye.h
@@ -0,0 +1,324 @@
+/*
+ * Motion Eye video4linux driver for Sony Vaio PictureBook
+ *
+ * Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ *
+ * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
+ *
+ * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
+ *
+ * Some parts borrowed from various video4linux drivers, especially
+ * bttv-driver.c and zoran.c, see original files for credits.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _MEYE_PRIV_H_
+#define _MEYE_PRIV_H_
+
+#define MEYE_DRIVER_MAJORVERSION	 1
+#define MEYE_DRIVER_MINORVERSION	14
+
+#define MEYE_DRIVER_VERSION __stringify(MEYE_DRIVER_MAJORVERSION) "." \
+			    __stringify(MEYE_DRIVER_MINORVERSION)
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kfifo.h>
+
+/****************************************************************************/
+/* Motion JPEG chip registers                                               */
+/****************************************************************************/
+
+/* Motion JPEG chip PCI configuration registers */
+#define MCHIP_PCI_POWER_CSR		0x54
+#define MCHIP_PCI_MCORE_STATUS		0x60		/* see HIC_STATUS   */
+#define MCHIP_PCI_HOSTUSEREQ_SET	0x64
+#define MCHIP_PCI_HOSTUSEREQ_CLR	0x68
+#define MCHIP_PCI_LOWPOWER_SET		0x6c
+#define MCHIP_PCI_LOWPOWER_CLR		0x70
+#define MCHIP_PCI_SOFTRESET_SET		0x74
+
+/* Motion JPEG chip memory mapped registers */
+#define MCHIP_MM_REGS			0x200		/* 512 bytes        */
+#define MCHIP_REG_TIMEOUT		1000		/* reg access, ~us  */
+#define MCHIP_MCC_VRJ_TIMEOUT		1000		/* MCC & VRJ access */
+
+#define MCHIP_MM_PCI_MODE		0x00		/* PCI access mode */
+#define MCHIP_MM_PCI_MODE_RETRY		0x00000001	/* retry mode */
+#define MCHIP_MM_PCI_MODE_MASTER	0x00000002	/* master access */
+#define MCHIP_MM_PCI_MODE_READ_LINE	0x00000004	/* read line */
+
+#define MCHIP_MM_INTA			0x04		/* Int status/mask */
+#define MCHIP_MM_INTA_MCC		0x00000001	/* MCC interrupt */
+#define MCHIP_MM_INTA_VRJ		0x00000002	/* VRJ interrupt */
+#define MCHIP_MM_INTA_HIC_1		0x00000004	/* one frame done */
+#define MCHIP_MM_INTA_HIC_1_MASK	0x00000400	/* 1: enable */
+#define MCHIP_MM_INTA_HIC_END		0x00000008	/* all frames done */
+#define MCHIP_MM_INTA_HIC_END_MASK	0x00000800
+#define MCHIP_MM_INTA_JPEG		0x00000010	/* decompress. error */
+#define MCHIP_MM_INTA_JPEG_MASK		0x00001000
+#define MCHIP_MM_INTA_CAPTURE		0x00000020	/* capture end */
+#define MCHIP_MM_INTA_PCI_ERR		0x00000040	/* PCI error */
+#define MCHIP_MM_INTA_PCI_ERR_MASK	0x00004000
+
+#define MCHIP_MM_PT_ADDR		0x08		/* page table address*/
+							/* n*4kB */
+#define MCHIP_NB_PAGES			1024		/* pages for display */
+#define MCHIP_NB_PAGES_MJPEG		256		/* pages for mjpeg */
+
+#define MCHIP_MM_FIR(n)			(0x0c+(n)*4)	/* Frame info 0-3 */
+#define MCHIP_MM_FIR_RDY		0x00000001	/* frame ready */
+#define MCHIP_MM_FIR_FAILFR_MASK	0xf8000000	/* # of failed frames */
+#define MCHIP_MM_FIR_FAILFR_SHIFT	27
+
+	/* continuous comp/decomp mode */
+#define MCHIP_MM_FIR_C_ENDL_MASK	0x000007fe	/* end DW [10] */
+#define MCHIP_MM_FIR_C_ENDL_SHIFT	1
+#define MCHIP_MM_FIR_C_ENDP_MASK	0x0007f800	/* end page [8] */
+#define MCHIP_MM_FIR_C_ENDP_SHIFT	11
+#define MCHIP_MM_FIR_C_STARTP_MASK	0x07f80000	/* start page [8] */
+#define MCHIP_MM_FIR_C_STARTP_SHIFT	19
+
+	/* continuous picture output mode */
+#define MCHIP_MM_FIR_O_STARTP_MASK	0x7ffe0000	/* start page [10] */
+#define MCHIP_MM_FIR_O_STARTP_SHIFT	17
+
+#define MCHIP_MM_FIFO_DATA		0x1c		/* PCI TGT FIFO data */
+#define MCHIP_MM_FIFO_STATUS		0x20		/* PCI TGT FIFO stat */
+#define MCHIP_MM_FIFO_MASK		0x00000003
+#define MCHIP_MM_FIFO_WAIT_OR_READY	0x00000002      /* Bits common to WAIT & READY*/
+#define MCHIP_MM_FIFO_IDLE		0x0		/* HIC idle */
+#define MCHIP_MM_FIFO_IDLE1		0x1		/* idem ??? */
+#define	MCHIP_MM_FIFO_WAIT		0x2		/* wait request */
+#define MCHIP_MM_FIFO_READY		0x3		/* data ready */
+
+#define MCHIP_HIC_HOST_USEREQ		0x40		/* host uses MCORE */
+
+#define MCHIP_HIC_TP_BUSY		0x44		/* taking picture */
+
+#define MCHIP_HIC_PIC_SAVED		0x48		/* pic in SDRAM */
+
+#define MCHIP_HIC_LOWPOWER		0x4c		/* clock stopped */
+
+#define MCHIP_HIC_CTL			0x50		/* HIC control */
+#define MCHIP_HIC_CTL_SOFT_RESET	0x00000001	/* MCORE reset */
+#define MCHIP_HIC_CTL_MCORE_RDY		0x00000002	/* MCORE ready */
+
+#define MCHIP_HIC_CMD			0x54		/* HIC command */
+#define MCHIP_HIC_CMD_BITS		0x00000003      /* cmd width=[1:0]*/
+#define MCHIP_HIC_CMD_NOOP		0x0
+#define MCHIP_HIC_CMD_START		0x1
+#define MCHIP_HIC_CMD_STOP		0x2
+
+#define MCHIP_HIC_MODE			0x58
+#define MCHIP_HIC_MODE_NOOP		0x0
+#define MCHIP_HIC_MODE_STILL_CAP	0x1		/* still pic capt */
+#define MCHIP_HIC_MODE_DISPLAY		0x2		/* display */
+#define MCHIP_HIC_MODE_STILL_COMP	0x3		/* still pic comp. */
+#define MCHIP_HIC_MODE_STILL_DECOMP	0x4		/* still pic decomp. */
+#define MCHIP_HIC_MODE_CONT_COMP	0x5		/* cont capt+comp */
+#define MCHIP_HIC_MODE_CONT_DECOMP	0x6		/* cont decomp+disp */
+#define MCHIP_HIC_MODE_STILL_OUT	0x7		/* still pic output */
+#define MCHIP_HIC_MODE_CONT_OUT		0x8		/* cont output */
+
+#define MCHIP_HIC_STATUS		0x5c
+#define MCHIP_HIC_STATUS_MCC_RDY	0x00000001	/* MCC reg acc ok */
+#define MCHIP_HIC_STATUS_VRJ_RDY	0x00000002	/* VRJ reg acc ok */
+#define MCHIP_HIC_STATUS_IDLE           0x00000003
+#define MCHIP_HIC_STATUS_CAPDIS		0x00000004	/* cap/disp in prog */
+#define MCHIP_HIC_STATUS_COMPDEC	0x00000008	/* (de)comp in prog */
+#define MCHIP_HIC_STATUS_BUSY		0x00000010	/* HIC busy */
+
+#define MCHIP_HIC_S_RATE		0x60		/* MJPEG # frames */
+
+#define MCHIP_HIC_PCI_VFMT		0x64		/* video format */
+#define MCHIP_HIC_PCI_VFMT_YVYU		0x00000001	/* 0: V Y' U Y */
+							/* 1: Y' V Y U */
+
+#define MCHIP_MCC_CMD			0x80		/* MCC commands */
+#define MCHIP_MCC_CMD_INITIAL		0x0		/* idle ? */
+#define MCHIP_MCC_CMD_IIC_START_SET	0x1
+#define MCHIP_MCC_CMD_IIC_END_SET	0x2
+#define MCHIP_MCC_CMD_FM_WRITE		0x3		/* frame memory */
+#define MCHIP_MCC_CMD_FM_READ		0x4
+#define MCHIP_MCC_CMD_FM_STOP		0x5
+#define MCHIP_MCC_CMD_CAPTURE		0x6
+#define MCHIP_MCC_CMD_DISPLAY		0x7
+#define MCHIP_MCC_CMD_END_DISP		0x8
+#define MCHIP_MCC_CMD_STILL_COMP	0x9
+#define MCHIP_MCC_CMD_STILL_DECOMP	0xa
+#define MCHIP_MCC_CMD_STILL_OUTPUT	0xb
+#define MCHIP_MCC_CMD_CONT_OUTPUT	0xc
+#define MCHIP_MCC_CMD_CONT_COMP		0xd
+#define MCHIP_MCC_CMD_CONT_DECOMP	0xe
+#define MCHIP_MCC_CMD_RESET		0xf		/* MCC reset */
+
+#define MCHIP_MCC_IIC_WR		0x84
+
+#define MCHIP_MCC_MCC_WR		0x88
+
+#define MCHIP_MCC_MCC_RD		0x8c
+
+#define MCHIP_MCC_STATUS		0x90
+#define MCHIP_MCC_STATUS_CAPT		0x00000001	/* capturing */
+#define MCHIP_MCC_STATUS_DISP		0x00000002	/* displaying */
+#define MCHIP_MCC_STATUS_COMP		0x00000004	/* compressing */
+#define MCHIP_MCC_STATUS_DECOMP		0x00000008	/* decompressing */
+#define MCHIP_MCC_STATUS_MCC_WR		0x00000010	/* register ready */
+#define MCHIP_MCC_STATUS_MCC_RD		0x00000020	/* register ready */
+#define MCHIP_MCC_STATUS_IIC_WR		0x00000040	/* register ready */
+#define MCHIP_MCC_STATUS_OUTPUT		0x00000080	/* output in prog */
+
+#define MCHIP_MCC_SIG_POLARITY		0x94
+#define MCHIP_MCC_SIG_POL_VS_H		0x00000001	/* VS active-high */
+#define MCHIP_MCC_SIG_POL_HS_H		0x00000002	/* HS active-high */
+#define MCHIP_MCC_SIG_POL_DOE_H		0x00000004	/* DOE active-high */
+
+#define MCHIP_MCC_IRQ			0x98
+#define MCHIP_MCC_IRQ_CAPDIS_STRT	0x00000001	/* cap/disp started */
+#define MCHIP_MCC_IRQ_CAPDIS_STRT_MASK	0x00000010
+#define MCHIP_MCC_IRQ_CAPDIS_END	0x00000002	/* cap/disp ended */
+#define MCHIP_MCC_IRQ_CAPDIS_END_MASK	0x00000020
+#define MCHIP_MCC_IRQ_COMPDEC_STRT	0x00000004	/* (de)comp started */
+#define MCHIP_MCC_IRQ_COMPDEC_STRT_MASK	0x00000040
+#define MCHIP_MCC_IRQ_COMPDEC_END	0x00000008	/* (de)comp ended */
+#define MCHIP_MCC_IRQ_COMPDEC_END_MASK	0x00000080
+
+#define MCHIP_MCC_HSTART		0x9c		/* video in */
+#define MCHIP_MCC_VSTART		0xa0
+#define MCHIP_MCC_HCOUNT		0xa4
+#define MCHIP_MCC_VCOUNT		0xa8
+#define MCHIP_MCC_R_XBASE		0xac		/* capt/disp */
+#define MCHIP_MCC_R_YBASE		0xb0
+#define MCHIP_MCC_R_XRANGE		0xb4
+#define MCHIP_MCC_R_YRANGE		0xb8
+#define MCHIP_MCC_B_XBASE		0xbc		/* comp/decomp */
+#define MCHIP_MCC_B_YBASE		0xc0
+#define MCHIP_MCC_B_XRANGE		0xc4
+#define MCHIP_MCC_B_YRANGE		0xc8
+
+#define MCHIP_MCC_R_SAMPLING		0xcc		/* 1: 1:4 */
+
+#define MCHIP_VRJ_CMD			0x100		/* VRJ commands */
+
+/* VRJ registers (see table 12.2.4) */
+#define MCHIP_VRJ_COMPRESSED_DATA	0x1b0
+#define MCHIP_VRJ_PIXEL_DATA		0x1b8
+
+#define MCHIP_VRJ_BUS_MODE		0x100
+#define MCHIP_VRJ_SIGNAL_ACTIVE_LEVEL	0x108
+#define MCHIP_VRJ_PDAT_USE		0x110
+#define MCHIP_VRJ_MODE_SPECIFY		0x118
+#define MCHIP_VRJ_LIMIT_COMPRESSED_LO	0x120
+#define MCHIP_VRJ_LIMIT_COMPRESSED_HI	0x124
+#define MCHIP_VRJ_COMP_DATA_FORMAT	0x128
+#define MCHIP_VRJ_TABLE_DATA		0x140
+#define MCHIP_VRJ_RESTART_INTERVAL	0x148
+#define MCHIP_VRJ_NUM_LINES		0x150
+#define MCHIP_VRJ_NUM_PIXELS		0x158
+#define MCHIP_VRJ_NUM_COMPONENTS	0x160
+#define MCHIP_VRJ_SOF1			0x168
+#define MCHIP_VRJ_SOF2			0x170
+#define MCHIP_VRJ_SOF3			0x178
+#define MCHIP_VRJ_SOF4			0x180
+#define MCHIP_VRJ_SOS			0x188
+#define MCHIP_VRJ_SOFT_RESET		0x190
+
+#define MCHIP_VRJ_STATUS		0x1c0
+#define MCHIP_VRJ_STATUS_BUSY		0x00001
+#define MCHIP_VRJ_STATUS_COMP_ACCESS	0x00002
+#define MCHIP_VRJ_STATUS_PIXEL_ACCESS	0x00004
+#define MCHIP_VRJ_STATUS_ERROR		0x00008
+
+#define MCHIP_VRJ_IRQ_FLAG		0x1c8
+#define MCHIP_VRJ_ERROR_REPORT		0x1d8
+
+#define MCHIP_VRJ_START_COMMAND		0x1a0
+
+/****************************************************************************/
+/* Driver definitions.                                                      */
+/****************************************************************************/
+
+/* Sony Programmable I/O Controller for accessing the camera commands */
+#include <linux/sony-laptop.h>
+
+/* private API definitions */
+#include <linux/meye.h>
+#include <linux/mutex.h>
+
+
+/* Enable jpg software correction */
+#define MEYE_JPEG_CORRECTION	1
+
+/* Maximum size of a buffer */
+#define MEYE_MAX_BUFSIZE	614400	/* 640 * 480 * 2 */
+
+/* Maximum number of buffers */
+#define MEYE_MAX_BUFNBRS	32
+
+/* State of a buffer */
+#define MEYE_BUF_UNUSED	0	/* not used */
+#define MEYE_BUF_USING	1	/* currently grabbing / playing */
+#define MEYE_BUF_DONE	2	/* done */
+
+/* grab buffer */
+struct meye_grab_buffer {
+	int state;			/* state of buffer */
+	unsigned long size;		/* size of jpg frame */
+	struct timeval timestamp;	/* timestamp */
+	unsigned long sequence;		/* sequence number */
+};
+
+/* size of kfifos containings buffer indices */
+#define MEYE_QUEUE_SIZE	MEYE_MAX_BUFNBRS
+
+/* Motion Eye device structure */
+struct meye {
+	struct v4l2_device v4l2_dev;	/* Main v4l2_device struct */
+	struct pci_dev *mchip_dev;	/* pci device */
+	u8 mchip_irq;			/* irq */
+	u8 mchip_mode;			/* actual mchip mode: HIC_MODE... */
+	u8 mchip_fnum;			/* current mchip frame number */
+	unsigned char __iomem *mchip_mmregs;/* mchip: memory mapped registers */
+	u8 *mchip_ptable[MCHIP_NB_PAGES];/* mchip: ptable */
+	void *mchip_ptable_toc;		/* mchip: ptable toc */
+	dma_addr_t mchip_dmahandle;	/* mchip: dma handle to ptable toc */
+	unsigned char *grab_fbuffer;	/* capture framebuffer */
+	unsigned char *grab_temp;	/* temporary buffer */
+					/* list of buffers */
+	struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS];
+	int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */
+	struct mutex lock;		/* mutex for open/mmap... */
+	struct kfifo grabq;		/* queue for buffers to be grabbed */
+	spinlock_t grabq_lock;		/* lock protecting the queue */
+	struct kfifo doneq;		/* queue for grabbed buffers */
+	spinlock_t doneq_lock;		/* lock protecting the queue */
+	wait_queue_head_t proc_list;	/* wait queue */
+	struct video_device *vdev;	/* video device parameters */
+	u16 brightness;
+	u16 hue;
+	u16 contrast;
+	u16 colour;
+	struct meye_params params;	/* additional parameters */
+	unsigned long in_use;		/* set to 1 if the device is in use */
+#ifdef CONFIG_PM
+	u8 pm_mchip_mode;		/* old mchip mode */
+#endif
+};
+
+#endif
diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig
new file mode 100644
index 0000000..64c8470
--- /dev/null
+++ b/drivers/media/pci/ngene/Kconfig
@@ -0,0 +1,13 @@
+config DVB_NGENE
+	tristate "Micronas nGene support"
+	depends on DVB_CORE && PCI && I2C
+	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+	select DVB_STV6110x if !DVB_FE_CUSTOMISE
+	select DVB_STV090x if !DVB_FE_CUSTOMISE
+	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+	select DVB_DRXK if !DVB_FE_CUSTOMISE
+	select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE
+	---help---
+	  Support for Micronas PCI express cards with nGene bridge.
+
diff --git a/drivers/media/pci/ngene/Makefile b/drivers/media/pci/ngene/Makefile
new file mode 100644
index 0000000..5c0b5d6
--- /dev/null
+++ b/drivers/media/pci/ngene/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for the nGene device driver
+#
+
+ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o
+
+obj-$(CONFIG_DVB_NGENE) += ngene.o
+
+ccflags-y += -Idrivers/media/dvb-core/
+ccflags-y += -Idrivers/media/dvb-frontends/
+ccflags-y += -Idrivers/media/tuners/
+
+# For the staging CI driver cxd2099
+ccflags-y += -Idrivers/staging/media/cxd2099/
diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c
new file mode 100644
index 0000000..a6cd695
--- /dev/null
+++ b/drivers/media/pci/ngene/ngene-cards.c
@@ -0,0 +1,823 @@
+/*
+ * ngene-cards.c: nGene PCIe bridge driver - card specific info
+ *
+ * Copyright (C) 2005-2007 Micronas
+ *
+ * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
+ *                         Modifications for new nGene firmware,
+ *                         support for EEPROM-copying,
+ *                         support for new dual DVB-S2 card prototype
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#include "ngene.h"
+
+/* demods/tuners */
+#include "stv6110x.h"
+#include "stv090x.h"
+#include "lnbh24.h"
+#include "lgdt330x.h"
+#include "mt2131.h"
+#include "tda18271c2dd.h"
+#include "drxk.h"
+#include "drxd.h"
+#include "dvb-pll.h"
+
+
+/****************************************************************************/
+/* Demod/tuner attachment ***************************************************/
+/****************************************************************************/
+
+static int tuner_attach_stv6110(struct ngene_channel *chan)
+{
+	struct i2c_adapter *i2c;
+	struct stv090x_config *feconf = (struct stv090x_config *)
+		chan->dev->card_info->fe_config[chan->number];
+	struct stv6110x_config *tunerconf = (struct stv6110x_config *)
+		chan->dev->card_info->tuner_config[chan->number];
+	struct stv6110x_devctl *ctl;
+
+	/* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
+	if (chan->number < 2)
+		i2c = &chan->dev->channel[0].i2c_adapter;
+	else
+		i2c = &chan->dev->channel[1].i2c_adapter;
+
+	ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c);
+	if (ctl == NULL) {
+		printk(KERN_ERR	DEVICE_NAME ": No STV6110X found!\n");
+		return -ENODEV;
+	}
+
+	feconf->tuner_init          = ctl->tuner_init;
+	feconf->tuner_sleep         = ctl->tuner_sleep;
+	feconf->tuner_set_mode      = ctl->tuner_set_mode;
+	feconf->tuner_set_frequency = ctl->tuner_set_frequency;
+	feconf->tuner_get_frequency = ctl->tuner_get_frequency;
+	feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+	feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+	feconf->tuner_set_bbgain    = ctl->tuner_set_bbgain;
+	feconf->tuner_get_bbgain    = ctl->tuner_get_bbgain;
+	feconf->tuner_set_refclk    = ctl->tuner_set_refclk;
+	feconf->tuner_get_status    = ctl->tuner_get_status;
+
+	return 0;
+}
+
+
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct ngene_channel *chan = fe->sec_priv;
+	int status;
+
+	if (enable) {
+		down(&chan->dev->pll_mutex);
+		status = chan->gate_ctrl(fe, 1);
+	} else {
+		status = chan->gate_ctrl(fe, 0);
+		up(&chan->dev->pll_mutex);
+	}
+	return status;
+}
+
+static int tuner_attach_tda18271(struct ngene_channel *chan)
+{
+	struct i2c_adapter *i2c;
+	struct dvb_frontend *fe;
+
+	i2c = &chan->dev->channel[0].i2c_adapter;
+	if (chan->fe->ops.i2c_gate_ctrl)
+		chan->fe->ops.i2c_gate_ctrl(chan->fe, 1);
+	fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60);
+	if (chan->fe->ops.i2c_gate_ctrl)
+		chan->fe->ops.i2c_gate_ctrl(chan->fe, 0);
+	if (!fe) {
+		printk(KERN_ERR "No TDA18271 found!\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int tuner_attach_probe(struct ngene_channel *chan)
+{
+	if (chan->demod_type == 0)
+		return tuner_attach_stv6110(chan);
+	if (chan->demod_type == 1)
+		return tuner_attach_tda18271(chan);
+	return -EINVAL;
+}
+
+static int demod_attach_stv0900(struct ngene_channel *chan)
+{
+	struct i2c_adapter *i2c;
+	struct stv090x_config *feconf = (struct stv090x_config *)
+		chan->dev->card_info->fe_config[chan->number];
+
+	/* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
+	/* Note: Both adapters share the same i2c bus, but the demod     */
+	/*       driver requires that each demod has its own i2c adapter */
+	if (chan->number < 2)
+		i2c = &chan->dev->channel[0].i2c_adapter;
+	else
+		i2c = &chan->dev->channel[1].i2c_adapter;
+
+	chan->fe = dvb_attach(stv090x_attach, feconf, i2c,
+			(chan->number & 1) == 0 ? STV090x_DEMODULATOR_0
+						: STV090x_DEMODULATOR_1);
+	if (chan->fe == NULL) {
+		printk(KERN_ERR	DEVICE_NAME ": No STV0900 found!\n");
+		return -ENODEV;
+	}
+
+	/* store channel info */
+	if (feconf->tuner_i2c_lock)
+		chan->fe->analog_demod_priv = chan;
+
+	if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0,
+			0, chan->dev->card_info->lnb[chan->number])) {
+		printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n");
+		dvb_frontend_detach(chan->fe);
+		chan->fe = NULL;
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock)
+{
+	struct ngene_channel *chan = fe->analog_demod_priv;
+
+	if (lock)
+		down(&chan->dev->pll_mutex);
+	else
+		up(&chan->dev->pll_mutex);
+}
+
+static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
+{
+	struct i2c_msg msgs[1] = {{.addr = adr,  .flags = I2C_M_RD,
+				   .buf  = val,  .len   = 1 } };
+	return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
+}
+
+static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
+			  u16 reg, u8 *val)
+{
+	u8 msg[2] = {reg>>8, reg&0xff};
+	struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
+				   .buf  = msg, .len   = 2},
+				  {.addr = adr, .flags = I2C_M_RD,
+				   .buf  = val, .len   = 1} };
+	return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
+}
+
+static int port_has_stv0900(struct i2c_adapter *i2c, int port)
+{
+	u8 val;
+	if (i2c_read_reg16(i2c, 0x68+port/2, 0xf100, &val) < 0)
+		return 0;
+	return 1;
+}
+
+static int port_has_drxk(struct i2c_adapter *i2c, int port)
+{
+	u8 val;
+
+	if (i2c_read(i2c, 0x29+port, &val) < 0)
+		return 0;
+	return 1;
+}
+
+static int demod_attach_drxk(struct ngene_channel *chan,
+			     struct i2c_adapter *i2c)
+{
+	struct drxk_config config;
+
+	memset(&config, 0, sizeof(config));
+	config.microcode_name = "drxk_a3.mc";
+	config.qam_demod_parameter_count = 4;
+	config.adr = 0x29 + (chan->number ^ 2);
+
+	chan->fe = dvb_attach(drxk_attach, &config, i2c);
+	if (!chan->fe) {
+		printk(KERN_ERR "No DRXK found!\n");
+		return -ENODEV;
+	}
+	chan->fe->sec_priv = chan;
+	chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl;
+	chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+	return 0;
+}
+
+static int cineS2_probe(struct ngene_channel *chan)
+{
+	struct i2c_adapter *i2c;
+	struct stv090x_config *fe_conf;
+	u8 buf[3];
+	struct i2c_msg i2c_msg = { .flags = 0, .buf = buf };
+	int rc;
+
+	/* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
+	if (chan->number < 2)
+		i2c = &chan->dev->channel[0].i2c_adapter;
+	else
+		i2c = &chan->dev->channel[1].i2c_adapter;
+
+	if (port_has_stv0900(i2c, chan->number)) {
+		chan->demod_type = 0;
+		fe_conf = chan->dev->card_info->fe_config[chan->number];
+		/* demod found, attach it */
+		rc = demod_attach_stv0900(chan);
+		if (rc < 0 || chan->number < 2)
+			return rc;
+
+		/* demod #2: reprogram outputs DPN1 & DPN2 */
+		i2c_msg.addr = fe_conf->address;
+		i2c_msg.len = 3;
+		buf[0] = 0xf1;
+		switch (chan->number) {
+		case 2:
+			buf[1] = 0x5c;
+			buf[2] = 0xc2;
+			break;
+		case 3:
+			buf[1] = 0x61;
+			buf[2] = 0xcc;
+			break;
+		default:
+			return -ENODEV;
+		}
+		rc = i2c_transfer(i2c, &i2c_msg, 1);
+		if (rc != 1) {
+			printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n");
+			return -EIO;
+		}
+	} else if (port_has_drxk(i2c, chan->number^2)) {
+		chan->demod_type = 1;
+		demod_attach_drxk(chan, i2c);
+	} else {
+		printk(KERN_ERR "No demod found on chan %d\n", chan->number);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+
+static struct lgdt330x_config aver_m780 = {
+	.demod_address = 0xb2 >> 1,
+	.demod_chip    = LGDT3303,
+	.serial_mpeg   = 0x00, /* PARALLEL */
+	.clock_polarity_flip = 1,
+};
+
+static struct mt2131_config m780_tunerconfig = {
+	0xc0 >> 1
+};
+
+/* A single func to attach the demo and tuner, rather than
+ * use two sep funcs like the current design mandates.
+ */
+static int demod_attach_lg330x(struct ngene_channel *chan)
+{
+	chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, &chan->i2c_adapter);
+	if (chan->fe == NULL) {
+		printk(KERN_ERR	DEVICE_NAME ": No LGDT330x found!\n");
+		return -ENODEV;
+	}
+
+	dvb_attach(mt2131_attach, chan->fe, &chan->i2c_adapter,
+		   &m780_tunerconfig, 0);
+
+	return (chan->fe) ? 0 : -ENODEV;
+}
+
+static int demod_attach_drxd(struct ngene_channel *chan)
+{
+	struct drxd_config *feconf;
+
+	feconf = chan->dev->card_info->fe_config[chan->number];
+
+	chan->fe = dvb_attach(drxd_attach, feconf, chan,
+			&chan->i2c_adapter, &chan->dev->pci_dev->dev);
+	if (!chan->fe) {
+		pr_err("No DRXD found!\n");
+		return -ENODEV;
+	}
+
+	if (!dvb_attach(dvb_pll_attach, chan->fe, feconf->pll_address,
+			&chan->i2c_adapter,
+			feconf->pll_type)) {
+		pr_err("No pll(%d) found!\n", feconf->pll_type);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+/****************************************************************************/
+/* EEPROM TAGS **************************************************************/
+/****************************************************************************/
+
+#define MICNG_EE_START      0x0100
+#define MICNG_EE_END        0x0FF0
+
+#define MICNG_EETAG_END0    0x0000
+#define MICNG_EETAG_END1    0xFFFF
+
+/* 0x0001 - 0x000F reserved for housekeeping */
+/* 0xFFFF - 0xFFFE reserved for housekeeping */
+
+/* Micronas assigned tags
+   EEProm tags for hardware support */
+
+#define MICNG_EETAG_DRXD1_OSCDEVIATION  0x1000  /* 2 Bytes data */
+#define MICNG_EETAG_DRXD2_OSCDEVIATION  0x1001  /* 2 Bytes data */
+
+#define MICNG_EETAG_MT2060_1_1STIF      0x1100  /* 2 Bytes data */
+#define MICNG_EETAG_MT2060_2_1STIF      0x1101  /* 2 Bytes data */
+
+/* Tag range for OEMs */
+
+#define MICNG_EETAG_OEM_FIRST  0xC000
+#define MICNG_EETAG_OEM_LAST   0xFFEF
+
+static int i2c_write_eeprom(struct i2c_adapter *adapter,
+			    u8 adr, u16 reg, u8 data)
+{
+	u8 m[3] = {(reg >> 8), (reg & 0xff), data};
+	struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m,
+			      .len = sizeof(m)};
+
+	if (i2c_transfer(adapter, &msg, 1) != 1) {
+		pr_err(DEVICE_NAME ": Error writing EEPROM!\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static int i2c_read_eeprom(struct i2c_adapter *adapter,
+			   u8 adr, u16 reg, u8 *data, int len)
+{
+	u8 msg[2] = {(reg >> 8), (reg & 0xff)};
+	struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
+				   .buf = msg, .len = 2 },
+				  {.addr = adr, .flags = I2C_M_RD,
+				   .buf = data, .len = len} };
+
+	if (i2c_transfer(adapter, msgs, 2) != 2) {
+		pr_err(DEVICE_NAME ": Error reading EEPROM\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static int ReadEEProm(struct i2c_adapter *adapter,
+		      u16 Tag, u32 MaxLen, u8 *data, u32 *pLength)
+{
+	int status = 0;
+	u16 Addr = MICNG_EE_START, Length, tag = 0;
+	u8  EETag[3];
+
+	while (Addr + sizeof(u16) + 1 < MICNG_EE_END) {
+		if (i2c_read_eeprom(adapter, 0x50, Addr, EETag, sizeof(EETag)))
+			return -1;
+		tag = (EETag[0] << 8) | EETag[1];
+		if (tag == MICNG_EETAG_END0 || tag == MICNG_EETAG_END1)
+			return -1;
+		if (tag == Tag)
+			break;
+		Addr += sizeof(u16) + 1 + EETag[2];
+	}
+	if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) {
+		pr_err(DEVICE_NAME
+		       ": Reached EOEE @ Tag = %04x Length = %3d\n",
+		       tag, EETag[2]);
+		return -1;
+	}
+	Length = EETag[2];
+	if (Length > MaxLen)
+		Length = (u16) MaxLen;
+	if (Length > 0) {
+		Addr += sizeof(u16) + 1;
+		status = i2c_read_eeprom(adapter, 0x50, Addr, data, Length);
+		if (!status) {
+			*pLength = EETag[2];
+			if (Length < EETag[2])
+				; /*status=STATUS_BUFFER_OVERFLOW; */
+		}
+	}
+	return status;
+}
+
+static int WriteEEProm(struct i2c_adapter *adapter,
+		       u16 Tag, u32 Length, u8 *data)
+{
+	int status = 0;
+	u16 Addr = MICNG_EE_START;
+	u8 EETag[3];
+	u16 tag = 0;
+	int retry, i;
+
+	while (Addr + sizeof(u16) + 1 < MICNG_EE_END) {
+		if (i2c_read_eeprom(adapter, 0x50, Addr, EETag, sizeof(EETag)))
+			return -1;
+		tag = (EETag[0] << 8) | EETag[1];
+		if (tag == MICNG_EETAG_END0 || tag == MICNG_EETAG_END1)
+			return -1;
+		if (tag == Tag)
+			break;
+		Addr += sizeof(u16) + 1 + EETag[2];
+	}
+	if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) {
+		pr_err(DEVICE_NAME
+		       ": Reached EOEE @ Tag = %04x Length = %3d\n",
+		       tag, EETag[2]);
+		return -1;
+	}
+
+	if (Length > EETag[2])
+		return -EINVAL;
+	/* Note: We write the data one byte at a time to avoid
+	   issues with page sizes. (which are different for
+	   each manufacture and eeprom size)
+	 */
+	Addr += sizeof(u16) + 1;
+	for (i = 0; i < Length; i++, Addr++) {
+		status = i2c_write_eeprom(adapter, 0x50, Addr, data[i]);
+
+		if (status)
+			break;
+
+		/* Poll for finishing write cycle */
+		retry = 10;
+		while (retry) {
+			u8 Tmp;
+
+			msleep(50);
+			status = i2c_read_eeprom(adapter, 0x50, Addr, &Tmp, 1);
+			if (status)
+				break;
+			if (Tmp != data[i])
+				pr_err(DEVICE_NAME
+				       "eeprom write error\n");
+			retry -= 1;
+		}
+		if (status) {
+			pr_err(DEVICE_NAME
+			       ": Timeout polling eeprom\n");
+			break;
+		}
+	}
+	return status;
+}
+
+static int eeprom_read_ushort(struct i2c_adapter *adapter, u16 tag, u16 *data)
+{
+	int stat;
+	u8 buf[2];
+	u32 len = 0;
+
+	stat = ReadEEProm(adapter, tag, 2, buf, &len);
+	if (stat)
+		return stat;
+	if (len != 2)
+		return -EINVAL;
+
+	*data = (buf[0] << 8) | buf[1];
+	return 0;
+}
+
+static int eeprom_write_ushort(struct i2c_adapter *adapter, u16 tag, u16 data)
+{
+	int stat;
+	u8 buf[2];
+
+	buf[0] = data >> 8;
+	buf[1] = data & 0xff;
+	stat = WriteEEProm(adapter, tag, 2, buf);
+	if (stat)
+		return stat;
+	return 0;
+}
+
+static s16 osc_deviation(void *priv, s16 deviation, int flag)
+{
+	struct ngene_channel *chan = priv;
+	struct i2c_adapter *adap = &chan->i2c_adapter;
+	u16 data = 0;
+
+	if (flag) {
+		data = (u16) deviation;
+		pr_info(DEVICE_NAME ": write deviation %d\n",
+		       deviation);
+		eeprom_write_ushort(adap, 0x1000 + chan->number, data);
+	} else {
+		if (eeprom_read_ushort(adap, 0x1000 + chan->number, &data))
+			data = 0;
+		pr_info(DEVICE_NAME ": read deviation %d\n",
+		       (s16) data);
+	}
+
+	return (s16) data;
+}
+
+/****************************************************************************/
+/* Switch control (I2C gates, etc.) *****************************************/
+/****************************************************************************/
+
+
+static struct stv090x_config fe_cineS2 = {
+	.device         = STV0900,
+	.demod_mode     = STV090x_DUAL,
+	.clk_mode       = STV090x_CLK_EXT,
+
+	.xtal           = 27000000,
+	.address        = 0x68,
+
+	.ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+	.ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+
+	.repeater_level = STV090x_RPTLEVEL_16,
+
+	.adc1_range	= STV090x_ADC_1Vpp,
+	.adc2_range	= STV090x_ADC_1Vpp,
+
+	.diseqc_envelope_mode = true,
+
+	.tuner_i2c_lock = cineS2_tuner_i2c_lock,
+};
+
+static struct stv090x_config fe_cineS2_2 = {
+	.device         = STV0900,
+	.demod_mode     = STV090x_DUAL,
+	.clk_mode       = STV090x_CLK_EXT,
+
+	.xtal           = 27000000,
+	.address        = 0x69,
+
+	.ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+	.ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+
+	.repeater_level = STV090x_RPTLEVEL_16,
+
+	.adc1_range	= STV090x_ADC_1Vpp,
+	.adc2_range	= STV090x_ADC_1Vpp,
+
+	.diseqc_envelope_mode = true,
+
+	.tuner_i2c_lock = cineS2_tuner_i2c_lock,
+};
+
+static struct stv6110x_config tuner_cineS2_0 = {
+	.addr	= 0x60,
+	.refclk	= 27000000,
+	.clk_div = 1,
+};
+
+static struct stv6110x_config tuner_cineS2_1 = {
+	.addr	= 0x63,
+	.refclk	= 27000000,
+	.clk_div = 1,
+};
+
+static struct ngene_info ngene_info_cineS2 = {
+	.type		= NGENE_SIDEWINDER,
+	.name		= "Linux4Media cineS2 DVB-S2 Twin Tuner",
+	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN},
+	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900},
+	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110},
+	.fe_config	= {&fe_cineS2, &fe_cineS2},
+	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1},
+	.lnb		= {0x0b, 0x08},
+	.tsf		= {3, 3},
+	.fw_version	= 18,
+	.msi_supported	= true,
+};
+
+static struct ngene_info ngene_info_satixS2 = {
+	.type		= NGENE_SIDEWINDER,
+	.name		= "Mystique SaTiX-S2 Dual",
+	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN},
+	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900},
+	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110},
+	.fe_config	= {&fe_cineS2, &fe_cineS2},
+	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1},
+	.lnb		= {0x0b, 0x08},
+	.tsf		= {3, 3},
+	.fw_version	= 18,
+	.msi_supported	= true,
+};
+
+static struct ngene_info ngene_info_satixS2v2 = {
+	.type		= NGENE_SIDEWINDER,
+	.name		= "Mystique SaTiX-S2 Dual (v2)",
+	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
+			   NGENE_IO_TSOUT},
+	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},
+	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe},
+	.fe_config	= {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
+	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
+	.lnb		= {0x0a, 0x08, 0x0b, 0x09},
+	.tsf		= {3, 3},
+	.fw_version	= 18,
+	.msi_supported	= true,
+};
+
+static struct ngene_info ngene_info_cineS2v5 = {
+	.type		= NGENE_SIDEWINDER,
+	.name		= "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)",
+	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
+			   NGENE_IO_TSOUT},
+	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},
+	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe},
+	.fe_config	= {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
+	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
+	.lnb		= {0x0a, 0x08, 0x0b, 0x09},
+	.tsf		= {3, 3},
+	.fw_version	= 18,
+	.msi_supported	= true,
+};
+
+
+static struct ngene_info ngene_info_duoFlex = {
+	.type           = NGENE_SIDEWINDER,
+	.name           = "Digital Devices DuoFlex PCIe or miniPCIe",
+	.io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
+			   NGENE_IO_TSOUT},
+	.demod_attach   = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe},
+	.tuner_attach   = {tuner_attach_probe, tuner_attach_probe, tuner_attach_probe, tuner_attach_probe},
+	.fe_config      = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
+	.tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
+	.lnb            = {0x0a, 0x08, 0x0b, 0x09},
+	.tsf            = {3, 3},
+	.fw_version     = 18,
+	.msi_supported	= true,
+};
+
+static struct ngene_info ngene_info_m780 = {
+	.type           = NGENE_APP,
+	.name           = "Aver M780 ATSC/QAM-B",
+
+	/* Channel 0 is analog, which is currently unsupported */
+	.io_type        = { NGENE_IO_NONE, NGENE_IO_TSIN },
+	.demod_attach   = { NULL, demod_attach_lg330x },
+
+	/* Ensure these are NULL else the frame will call them (as funcs) */
+	.tuner_attach   = { 0, 0, 0, 0 },
+	.fe_config      = { NULL, &aver_m780 },
+	.avf            = { 0 },
+
+	/* A custom electrical interface config for the demod to bridge */
+	.tsf		= { 4, 4 },
+	.fw_version	= 15,
+};
+
+static struct drxd_config fe_terratec_dvbt_0 = {
+	.index          = 0,
+	.demod_address  = 0x70,
+	.demod_revision = 0xa2,
+	.demoda_address = 0x00,
+	.pll_address    = 0x60,
+	.pll_type       = DVB_PLL_THOMSON_DTT7520X,
+	.clock          = 20000,
+	.osc_deviation  = osc_deviation,
+};
+
+static struct drxd_config fe_terratec_dvbt_1 = {
+	.index          = 1,
+	.demod_address  = 0x71,
+	.demod_revision = 0xa2,
+	.demoda_address = 0x00,
+	.pll_address    = 0x60,
+	.pll_type       = DVB_PLL_THOMSON_DTT7520X,
+	.clock          = 20000,
+	.osc_deviation  = osc_deviation,
+};
+
+static struct ngene_info ngene_info_terratec = {
+	.type           = NGENE_TERRATEC,
+	.name           = "Terratec Integra/Cinergy2400i Dual DVB-T",
+	.io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN},
+	.demod_attach   = {demod_attach_drxd, demod_attach_drxd},
+	.fe_config      = {&fe_terratec_dvbt_0, &fe_terratec_dvbt_1},
+	.i2c_access     = 1,
+};
+
+/****************************************************************************/
+
+
+
+/****************************************************************************/
+/* PCI Subsystem ID *********************************************************/
+/****************************************************************************/
+
+#define NGENE_ID(_subvend, _subdev, _driverdata) { \
+	.vendor = NGENE_VID, .device = NGENE_PID, \
+	.subvendor = _subvend, .subdevice = _subdev, \
+	.driver_data = (unsigned long) &_driverdata }
+
+/****************************************************************************/
+
+static const struct pci_device_id ngene_id_tbl[] __devinitdata = {
+	NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2),
+	NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2),
+	NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2),
+	NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2),
+	NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5),
+	NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlex),
+	NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlex),
+	NGENE_ID(0x1461, 0x062e, ngene_info_m780),
+	NGENE_ID(0x153b, 0x1167, ngene_info_terratec),
+	{0}
+};
+MODULE_DEVICE_TABLE(pci, ngene_id_tbl);
+
+/****************************************************************************/
+/* Init/Exit ****************************************************************/
+/****************************************************************************/
+
+static pci_ers_result_t ngene_error_detected(struct pci_dev *dev,
+					     enum pci_channel_state state)
+{
+	printk(KERN_ERR DEVICE_NAME ": PCI error\n");
+	if (state == pci_channel_io_perm_failure)
+		return PCI_ERS_RESULT_DISCONNECT;
+	if (state == pci_channel_io_frozen)
+		return PCI_ERS_RESULT_NEED_RESET;
+	return PCI_ERS_RESULT_CAN_RECOVER;
+}
+
+static pci_ers_result_t ngene_link_reset(struct pci_dev *dev)
+{
+	printk(KERN_INFO DEVICE_NAME ": link reset\n");
+	return 0;
+}
+
+static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev)
+{
+	printk(KERN_INFO DEVICE_NAME ": slot reset\n");
+	return 0;
+}
+
+static void ngene_resume(struct pci_dev *dev)
+{
+	printk(KERN_INFO DEVICE_NAME ": resume\n");
+}
+
+static struct pci_error_handlers ngene_errors = {
+	.error_detected = ngene_error_detected,
+	.link_reset = ngene_link_reset,
+	.slot_reset = ngene_slot_reset,
+	.resume = ngene_resume,
+};
+
+static struct pci_driver ngene_pci_driver = {
+	.name        = "ngene",
+	.id_table    = ngene_id_tbl,
+	.probe       = ngene_probe,
+	.remove      = __devexit_p(ngene_remove),
+	.err_handler = &ngene_errors,
+	.shutdown    = ngene_shutdown,
+};
+
+static __init int module_init_ngene(void)
+{
+	printk(KERN_INFO
+	       "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n");
+	return pci_register_driver(&ngene_pci_driver);
+}
+
+static __exit void module_exit_ngene(void)
+{
+	pci_unregister_driver(&ngene_pci_driver);
+}
+
+module_init(module_init_ngene);
+module_exit(module_exit_ngene);
+
+MODULE_DESCRIPTION("nGene");
+MODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c
new file mode 100644
index 0000000..c8e0d5b
--- /dev/null
+++ b/drivers/media/pci/ngene/ngene-core.c
@@ -0,0 +1,1707 @@
+/*
+ * ngene.c: nGene PCIe bridge driver
+ *
+ * Copyright (C) 2005-2007 Micronas
+ *
+ * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
+ *                         Modifications for new nGene firmware,
+ *                         support for EEPROM-copying,
+ *                         support for new dual DVB-S2 card prototype
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/io.h>
+#include <asm/div64.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+#include <linux/byteorder/generic.h>
+#include <linux/firmware.h>
+#include <linux/vmalloc.h>
+
+#include "ngene.h"
+
+static int one_adapter;
+module_param(one_adapter, int, 0444);
+MODULE_PARM_DESC(one_adapter, "Use only one adapter.");
+
+static int shutdown_workaround;
+module_param(shutdown_workaround, int, 0644);
+MODULE_PARM_DESC(shutdown_workaround, "Activate workaround for shutdown problem with some chipsets.");
+
+static int debug;
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "Print debugging information.");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define dprintk	if (debug) printk
+
+#define ngwriteb(dat, adr)         writeb((dat), (char *)(dev->iomem + (adr)))
+#define ngwritel(dat, adr)         writel((dat), (char *)(dev->iomem + (adr)))
+#define ngwriteb(dat, adr)         writeb((dat), (char *)(dev->iomem + (adr)))
+#define ngreadl(adr)               readl(dev->iomem + (adr))
+#define ngreadb(adr)               readb(dev->iomem + (adr))
+#define ngcpyto(adr, src, count)   memcpy_toio((char *) \
+				   (dev->iomem + (adr)), (src), (count))
+#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \
+				   (dev->iomem + (adr)), (count))
+
+/****************************************************************************/
+/* nGene interrupt handler **************************************************/
+/****************************************************************************/
+
+static void event_tasklet(unsigned long data)
+{
+	struct ngene *dev = (struct ngene *)data;
+
+	while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) {
+		struct EVENT_BUFFER Event =
+			dev->EventQueue[dev->EventQueueReadIndex];
+		dev->EventQueueReadIndex =
+			(dev->EventQueueReadIndex + 1) & (EVENT_QUEUE_SIZE - 1);
+
+		if ((Event.UARTStatus & 0x01) && (dev->TxEventNotify))
+			dev->TxEventNotify(dev, Event.TimeStamp);
+		if ((Event.UARTStatus & 0x02) && (dev->RxEventNotify))
+			dev->RxEventNotify(dev, Event.TimeStamp,
+					   Event.RXCharacter);
+	}
+}
+
+static void demux_tasklet(unsigned long data)
+{
+	struct ngene_channel *chan = (struct ngene_channel *)data;
+	struct SBufferHeader *Cur = chan->nextBuffer;
+
+	spin_lock_irq(&chan->state_lock);
+
+	while (Cur->ngeneBuffer.SR.Flags & 0x80) {
+		if (chan->mode & NGENE_IO_TSOUT) {
+			u32 Flags = chan->DataFormatFlags;
+			if (Cur->ngeneBuffer.SR.Flags & 0x20)
+				Flags |= BEF_OVERFLOW;
+			if (chan->pBufferExchange) {
+				if (!chan->pBufferExchange(chan,
+							   Cur->Buffer1,
+							   chan->Capture1Length,
+							   Cur->ngeneBuffer.SR.
+							   Clock, Flags)) {
+					/*
+					   We didn't get data
+					   Clear in service flag to make sure we
+					   get called on next interrupt again.
+					   leave fill/empty (0x80) flag alone
+					   to avoid hardware running out of
+					   buffers during startup, we hold only
+					   in run state ( the source may be late
+					   delivering data )
+					*/
+
+					if (chan->HWState == HWSTATE_RUN) {
+						Cur->ngeneBuffer.SR.Flags &=
+							~0x40;
+						break;
+						/* Stop processing stream */
+					}
+				} else {
+					/* We got a valid buffer,
+					   so switch to run state */
+					chan->HWState = HWSTATE_RUN;
+				}
+			} else {
+				printk(KERN_ERR DEVICE_NAME ": OOPS\n");
+				if (chan->HWState == HWSTATE_RUN) {
+					Cur->ngeneBuffer.SR.Flags &= ~0x40;
+					break;	/* Stop processing stream */
+				}
+			}
+			if (chan->AudioDTOUpdated) {
+				printk(KERN_INFO DEVICE_NAME
+				       ": Update AudioDTO = %d\n",
+				       chan->AudioDTOValue);
+				Cur->ngeneBuffer.SR.DTOUpdate =
+					chan->AudioDTOValue;
+				chan->AudioDTOUpdated = 0;
+			}
+		} else {
+			if (chan->HWState == HWSTATE_RUN) {
+				u32 Flags = chan->DataFormatFlags;
+				IBufferExchange *exch1 = chan->pBufferExchange;
+				IBufferExchange *exch2 = chan->pBufferExchange2;
+				if (Cur->ngeneBuffer.SR.Flags & 0x01)
+					Flags |= BEF_EVEN_FIELD;
+				if (Cur->ngeneBuffer.SR.Flags & 0x20)
+					Flags |= BEF_OVERFLOW;
+				spin_unlock_irq(&chan->state_lock);
+				if (exch1)
+					exch1(chan, Cur->Buffer1,
+						chan->Capture1Length,
+						Cur->ngeneBuffer.SR.Clock,
+						Flags);
+				if (exch2)
+					exch2(chan, Cur->Buffer2,
+						chan->Capture2Length,
+						Cur->ngeneBuffer.SR.Clock,
+						Flags);
+				spin_lock_irq(&chan->state_lock);
+			} else if (chan->HWState != HWSTATE_STOP)
+				chan->HWState = HWSTATE_RUN;
+		}
+		Cur->ngeneBuffer.SR.Flags = 0x00;
+		Cur = Cur->Next;
+	}
+	chan->nextBuffer = Cur;
+
+	spin_unlock_irq(&chan->state_lock);
+}
+
+static irqreturn_t irq_handler(int irq, void *dev_id)
+{
+	struct ngene *dev = (struct ngene *)dev_id;
+	u32 icounts = 0;
+	irqreturn_t rc = IRQ_NONE;
+	u32 i = MAX_STREAM;
+	u8 *tmpCmdDoneByte;
+
+	if (dev->BootFirmware) {
+		icounts = ngreadl(NGENE_INT_COUNTS);
+		if (icounts != dev->icounts) {
+			ngwritel(0, FORCE_NMI);
+			dev->cmd_done = 1;
+			wake_up(&dev->cmd_wq);
+			dev->icounts = icounts;
+			rc = IRQ_HANDLED;
+		}
+		return rc;
+	}
+
+	ngwritel(0, FORCE_NMI);
+
+	spin_lock(&dev->cmd_lock);
+	tmpCmdDoneByte = dev->CmdDoneByte;
+	if (tmpCmdDoneByte &&
+	    (*tmpCmdDoneByte ||
+	    (dev->ngenetohost[0] == 1 && dev->ngenetohost[1] != 0))) {
+		dev->CmdDoneByte = NULL;
+		dev->cmd_done = 1;
+		wake_up(&dev->cmd_wq);
+		rc = IRQ_HANDLED;
+	}
+	spin_unlock(&dev->cmd_lock);
+
+	if (dev->EventBuffer->EventStatus & 0x80) {
+		u8 nextWriteIndex =
+			(dev->EventQueueWriteIndex + 1) &
+			(EVENT_QUEUE_SIZE - 1);
+		if (nextWriteIndex != dev->EventQueueReadIndex) {
+			dev->EventQueue[dev->EventQueueWriteIndex] =
+				*(dev->EventBuffer);
+			dev->EventQueueWriteIndex = nextWriteIndex;
+		} else {
+			printk(KERN_ERR DEVICE_NAME ": event overflow\n");
+			dev->EventQueueOverflowCount += 1;
+			dev->EventQueueOverflowFlag = 1;
+		}
+		dev->EventBuffer->EventStatus &= ~0x80;
+		tasklet_schedule(&dev->event_tasklet);
+		rc = IRQ_HANDLED;
+	}
+
+	while (i > 0) {
+		i--;
+		spin_lock(&dev->channel[i].state_lock);
+		/* if (dev->channel[i].State>=KSSTATE_RUN) { */
+		if (dev->channel[i].nextBuffer) {
+			if ((dev->channel[i].nextBuffer->
+			     ngeneBuffer.SR.Flags & 0xC0) == 0x80) {
+				dev->channel[i].nextBuffer->
+					ngeneBuffer.SR.Flags |= 0x40;
+				tasklet_schedule(
+					&dev->channel[i].demux_tasklet);
+				rc = IRQ_HANDLED;
+			}
+		}
+		spin_unlock(&dev->channel[i].state_lock);
+	}
+
+	/* Request might have been processed by a previous call. */
+	return IRQ_HANDLED;
+}
+
+/****************************************************************************/
+/* nGene command interface **************************************************/
+/****************************************************************************/
+
+static void dump_command_io(struct ngene *dev)
+{
+	u8 buf[8], *b;
+
+	ngcpyfrom(buf, HOST_TO_NGENE, 8);
+	printk(KERN_ERR "host_to_ngene (%04x): %*ph\n", HOST_TO_NGENE, 8, buf);
+
+	ngcpyfrom(buf, NGENE_TO_HOST, 8);
+	printk(KERN_ERR "ngene_to_host (%04x): %*ph\n", NGENE_TO_HOST, 8, buf);
+
+	b = dev->hosttongene;
+	printk(KERN_ERR "dev->hosttongene (%p): %*ph\n", b, 8, b);
+
+	b = dev->ngenetohost;
+	printk(KERN_ERR "dev->ngenetohost (%p): %*ph\n", b, 8, b);
+}
+
+static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com)
+{
+	int ret;
+	u8 *tmpCmdDoneByte;
+
+	dev->cmd_done = 0;
+
+	if (com->cmd.hdr.Opcode == CMD_FWLOAD_PREPARE) {
+		dev->BootFirmware = 1;
+		dev->icounts = ngreadl(NGENE_INT_COUNTS);
+		ngwritel(0, NGENE_COMMAND);
+		ngwritel(0, NGENE_COMMAND_HI);
+		ngwritel(0, NGENE_STATUS);
+		ngwritel(0, NGENE_STATUS_HI);
+		ngwritel(0, NGENE_EVENT);
+		ngwritel(0, NGENE_EVENT_HI);
+	} else if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) {
+		u64 fwio = dev->PAFWInterfaceBuffer;
+
+		ngwritel(fwio & 0xffffffff, NGENE_COMMAND);
+		ngwritel(fwio >> 32, NGENE_COMMAND_HI);
+		ngwritel((fwio + 256) & 0xffffffff, NGENE_STATUS);
+		ngwritel((fwio + 256) >> 32, NGENE_STATUS_HI);
+		ngwritel((fwio + 512) & 0xffffffff, NGENE_EVENT);
+		ngwritel((fwio + 512) >> 32, NGENE_EVENT_HI);
+	}
+
+	memcpy(dev->FWInterfaceBuffer, com->cmd.raw8, com->in_len + 2);
+
+	if (dev->BootFirmware)
+		ngcpyto(HOST_TO_NGENE, com->cmd.raw8, com->in_len + 2);
+
+	spin_lock_irq(&dev->cmd_lock);
+	tmpCmdDoneByte = dev->ngenetohost + com->out_len;
+	if (!com->out_len)
+		tmpCmdDoneByte++;
+	*tmpCmdDoneByte = 0;
+	dev->ngenetohost[0] = 0;
+	dev->ngenetohost[1] = 0;
+	dev->CmdDoneByte = tmpCmdDoneByte;
+	spin_unlock_irq(&dev->cmd_lock);
+
+	/* Notify 8051. */
+	ngwritel(1, FORCE_INT);
+
+	ret = wait_event_timeout(dev->cmd_wq, dev->cmd_done == 1, 2 * HZ);
+	if (!ret) {
+		/*ngwritel(0, FORCE_NMI);*/
+
+		printk(KERN_ERR DEVICE_NAME
+		       ": Command timeout cmd=%02x prev=%02x\n",
+		       com->cmd.hdr.Opcode, dev->prev_cmd);
+		dump_command_io(dev);
+		return -1;
+	}
+	if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH)
+		dev->BootFirmware = 0;
+
+	dev->prev_cmd = com->cmd.hdr.Opcode;
+
+	if (!com->out_len)
+		return 0;
+
+	memcpy(com->cmd.raw8, dev->ngenetohost, com->out_len);
+
+	return 0;
+}
+
+int ngene_command(struct ngene *dev, struct ngene_command *com)
+{
+	int result;
+
+	down(&dev->cmd_mutex);
+	result = ngene_command_mutex(dev, com);
+	up(&dev->cmd_mutex);
+	return result;
+}
+
+
+static int ngene_command_load_firmware(struct ngene *dev,
+				       u8 *ngene_fw, u32 size)
+{
+#define FIRSTCHUNK (1024)
+	u32 cleft;
+	struct ngene_command com;
+
+	com.cmd.hdr.Opcode = CMD_FWLOAD_PREPARE;
+	com.cmd.hdr.Length = 0;
+	com.in_len = 0;
+	com.out_len = 0;
+
+	ngene_command(dev, &com);
+
+	cleft = (size + 3) & ~3;
+	if (cleft > FIRSTCHUNK) {
+		ngcpyto(PROGRAM_SRAM + FIRSTCHUNK, ngene_fw + FIRSTCHUNK,
+			cleft - FIRSTCHUNK);
+		cleft = FIRSTCHUNK;
+	}
+	ngcpyto(DATA_FIFO_AREA, ngene_fw, cleft);
+
+	memset(&com, 0, sizeof(struct ngene_command));
+	com.cmd.hdr.Opcode = CMD_FWLOAD_FINISH;
+	com.cmd.hdr.Length = 4;
+	com.cmd.FWLoadFinish.Address = DATA_FIFO_AREA;
+	com.cmd.FWLoadFinish.Length = (unsigned short)cleft;
+	com.in_len = 4;
+	com.out_len = 0;
+
+	return ngene_command(dev, &com);
+}
+
+
+static int ngene_command_config_buf(struct ngene *dev, u8 config)
+{
+	struct ngene_command com;
+
+	com.cmd.hdr.Opcode = CMD_CONFIGURE_BUFFER;
+	com.cmd.hdr.Length = 1;
+	com.cmd.ConfigureBuffers.config = config;
+	com.in_len = 1;
+	com.out_len = 0;
+
+	if (ngene_command(dev, &com) < 0)
+		return -EIO;
+	return 0;
+}
+
+static int ngene_command_config_free_buf(struct ngene *dev, u8 *config)
+{
+	struct ngene_command com;
+
+	com.cmd.hdr.Opcode = CMD_CONFIGURE_FREE_BUFFER;
+	com.cmd.hdr.Length = 6;
+	memcpy(&com.cmd.ConfigureBuffers.config, config, 6);
+	com.in_len = 6;
+	com.out_len = 0;
+
+	if (ngene_command(dev, &com) < 0)
+		return -EIO;
+
+	return 0;
+}
+
+int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level)
+{
+	struct ngene_command com;
+
+	com.cmd.hdr.Opcode = CMD_SET_GPIO_PIN;
+	com.cmd.hdr.Length = 1;
+	com.cmd.SetGpioPin.select = select | (level << 7);
+	com.in_len = 1;
+	com.out_len = 0;
+
+	return ngene_command(dev, &com);
+}
+
+
+/*
+ 02000640 is sample on rising edge.
+ 02000740 is sample on falling edge.
+ 02000040 is ignore "valid" signal
+
+ 0: FD_CTL1 Bit 7,6 must be 0,1
+    7   disable(fw controlled)
+    6   0-AUX,1-TS
+    5   0-par,1-ser
+    4   0-lsb/1-msb
+    3,2 reserved
+    1,0 0-no sync, 1-use ext. start, 2-use 0x47, 3-both
+ 1: FD_CTL2 has 3-valid must be hi, 2-use valid, 1-edge
+ 2: FD_STA is read-only. 0-sync
+ 3: FD_INSYNC is number of 47s to trigger "in sync".
+ 4: FD_OUTSYNC is number of 47s to trigger "out of sync".
+ 5: FD_MAXBYTE1 is low-order of bytes per packet.
+ 6: FD_MAXBYTE2 is high-order of bytes per packet.
+ 7: Top byte is unused.
+*/
+
+/****************************************************************************/
+
+static u8 TSFeatureDecoderSetup[8 * 5] = {
+	0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,
+	0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,	/* DRXH */
+	0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,	/* DRXHser */
+	0x72, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,	/* S2ser */
+	0x40, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* LGDT3303 */
+};
+
+/* Set NGENE I2S Config to 16 bit packed */
+static u8 I2SConfiguration[] = {
+	0x00, 0x10, 0x00, 0x00,
+	0x80, 0x10, 0x00, 0x00,
+};
+
+static u8 SPDIFConfiguration[10] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* Set NGENE I2S Config to transport stream compatible mode */
+
+static u8 TS_I2SConfiguration[4] = { 0x3E, 0x18, 0x00, 0x00 };
+
+static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x04, 0x00, 0x00 };
+
+static u8 ITUDecoderSetup[4][16] = {
+	{0x1c, 0x13, 0x01, 0x68, 0x3d, 0x90, 0x14, 0x20,  /* SDTV */
+	 0x00, 0x00, 0x01, 0xb0, 0x9c, 0x00, 0x00, 0x00},
+	{0x9c, 0x03, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00,
+	 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
+	{0x9f, 0x00, 0x23, 0xC0, 0x60, 0x0F, 0x13, 0x00,  /* HDTV 1080i50 */
+	 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
+	{0x9c, 0x01, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00,  /* HDTV 1080i60 */
+	 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
+};
+
+/*
+ * 50 48 60 gleich
+ * 27p50 9f 00 22 80 42 69 18 ...
+ * 27p60 93 00 22 80 82 69 1c ...
+ */
+
+/* Maxbyte to 1144 (for raw data) */
+static u8 ITUFeatureDecoderSetup[8] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x00
+};
+
+void FillTSBuffer(void *Buffer, int Length, u32 Flags)
+{
+	u32 *ptr = Buffer;
+
+	memset(Buffer, TS_FILLER, Length);
+	while (Length > 0) {
+		if (Flags & DF_SWAP32)
+			*ptr = 0x471FFF10;
+		else
+			*ptr = 0x10FF1F47;
+		ptr += (188 / 4);
+		Length -= 188;
+	}
+}
+
+
+static void flush_buffers(struct ngene_channel *chan)
+{
+	u8 val;
+
+	do {
+		msleep(1);
+		spin_lock_irq(&chan->state_lock);
+		val = chan->nextBuffer->ngeneBuffer.SR.Flags & 0x80;
+		spin_unlock_irq(&chan->state_lock);
+	} while (val);
+}
+
+static void clear_buffers(struct ngene_channel *chan)
+{
+	struct SBufferHeader *Cur = chan->nextBuffer;
+
+	do {
+		memset(&Cur->ngeneBuffer.SR, 0, sizeof(Cur->ngeneBuffer.SR));
+		if (chan->mode & NGENE_IO_TSOUT)
+			FillTSBuffer(Cur->Buffer1,
+				     chan->Capture1Length,
+				     chan->DataFormatFlags);
+		Cur = Cur->Next;
+	} while (Cur != chan->nextBuffer);
+
+	if (chan->mode & NGENE_IO_TSOUT) {
+		chan->nextBuffer->ngeneBuffer.SR.DTOUpdate =
+			chan->AudioDTOValue;
+		chan->AudioDTOUpdated = 0;
+
+		Cur = chan->TSIdleBuffer.Head;
+
+		do {
+			memset(&Cur->ngeneBuffer.SR, 0,
+			       sizeof(Cur->ngeneBuffer.SR));
+			FillTSBuffer(Cur->Buffer1,
+				     chan->Capture1Length,
+				     chan->DataFormatFlags);
+			Cur = Cur->Next;
+		} while (Cur != chan->TSIdleBuffer.Head);
+	}
+}
+
+static int ngene_command_stream_control(struct ngene *dev, u8 stream,
+					u8 control, u8 mode, u8 flags)
+{
+	struct ngene_channel *chan = &dev->channel[stream];
+	struct ngene_command com;
+	u16 BsUVI = ((stream & 1) ? 0x9400 : 0x9300);
+	u16 BsSDI = ((stream & 1) ? 0x9600 : 0x9500);
+	u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700);
+	u16 BsSDO = 0x9B00;
+
+	down(&dev->stream_mutex);
+	memset(&com, 0, sizeof(com));
+	com.cmd.hdr.Opcode = CMD_CONTROL;
+	com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2;
+	com.cmd.StreamControl.Stream = stream | (control ? 8 : 0);
+	if (chan->mode & NGENE_IO_TSOUT)
+		com.cmd.StreamControl.Stream |= 0x07;
+	com.cmd.StreamControl.Control = control |
+		(flags & SFLAG_ORDER_LUMA_CHROMA);
+	com.cmd.StreamControl.Mode = mode;
+	com.in_len = sizeof(struct FW_STREAM_CONTROL);
+	com.out_len = 0;
+
+	dprintk(KERN_INFO DEVICE_NAME
+		": Stream=%02x, Control=%02x, Mode=%02x\n",
+		com.cmd.StreamControl.Stream, com.cmd.StreamControl.Control,
+		com.cmd.StreamControl.Mode);
+
+	chan->Mode = mode;
+
+	if (!(control & 0x80)) {
+		spin_lock_irq(&chan->state_lock);
+		if (chan->State == KSSTATE_RUN) {
+			chan->State = KSSTATE_ACQUIRE;
+			chan->HWState = HWSTATE_STOP;
+			spin_unlock_irq(&chan->state_lock);
+			if (ngene_command(dev, &com) < 0) {
+				up(&dev->stream_mutex);
+				return -1;
+			}
+			/* clear_buffers(chan); */
+			flush_buffers(chan);
+			up(&dev->stream_mutex);
+			return 0;
+		}
+		spin_unlock_irq(&chan->state_lock);
+		up(&dev->stream_mutex);
+		return 0;
+	}
+
+	if (mode & SMODE_AUDIO_CAPTURE) {
+		com.cmd.StreamControl.CaptureBlockCount =
+			chan->Capture1Length / AUDIO_BLOCK_SIZE;
+		com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead;
+	} else if (mode & SMODE_TRANSPORT_STREAM) {
+		com.cmd.StreamControl.CaptureBlockCount =
+			chan->Capture1Length / TS_BLOCK_SIZE;
+		com.cmd.StreamControl.MaxLinesPerField =
+			chan->Capture1Length / TS_BLOCK_SIZE;
+		com.cmd.StreamControl.Buffer_Address =
+			chan->TSRingBuffer.PAHead;
+		if (chan->mode & NGENE_IO_TSOUT) {
+			com.cmd.StreamControl.BytesPerVBILine =
+				chan->Capture1Length / TS_BLOCK_SIZE;
+			com.cmd.StreamControl.Stream |= 0x07;
+		}
+	} else {
+		com.cmd.StreamControl.BytesPerVideoLine = chan->nBytesPerLine;
+		com.cmd.StreamControl.MaxLinesPerField = chan->nLines;
+		com.cmd.StreamControl.MinLinesPerField = 100;
+		com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead;
+
+		if (mode & SMODE_VBI_CAPTURE) {
+			com.cmd.StreamControl.MaxVBILinesPerField =
+				chan->nVBILines;
+			com.cmd.StreamControl.MinVBILinesPerField = 0;
+			com.cmd.StreamControl.BytesPerVBILine =
+				chan->nBytesPerVBILine;
+		}
+		if (flags & SFLAG_COLORBAR)
+			com.cmd.StreamControl.Stream |= 0x04;
+	}
+
+	spin_lock_irq(&chan->state_lock);
+	if (mode & SMODE_AUDIO_CAPTURE) {
+		chan->nextBuffer = chan->RingBuffer.Head;
+		if (mode & SMODE_AUDIO_SPDIF) {
+			com.cmd.StreamControl.SetupDataLen =
+				sizeof(SPDIFConfiguration);
+			com.cmd.StreamControl.SetupDataAddr = BsSPI;
+			memcpy(com.cmd.StreamControl.SetupData,
+			       SPDIFConfiguration, sizeof(SPDIFConfiguration));
+		} else {
+			com.cmd.StreamControl.SetupDataLen = 4;
+			com.cmd.StreamControl.SetupDataAddr = BsSDI;
+			memcpy(com.cmd.StreamControl.SetupData,
+			       I2SConfiguration +
+			       4 * dev->card_info->i2s[stream], 4);
+		}
+	} else if (mode & SMODE_TRANSPORT_STREAM) {
+		chan->nextBuffer = chan->TSRingBuffer.Head;
+		if (stream >= STREAM_AUDIOIN1) {
+			if (chan->mode & NGENE_IO_TSOUT) {
+				com.cmd.StreamControl.SetupDataLen =
+					sizeof(TS_I2SOutConfiguration);
+				com.cmd.StreamControl.SetupDataAddr = BsSDO;
+				memcpy(com.cmd.StreamControl.SetupData,
+				       TS_I2SOutConfiguration,
+				       sizeof(TS_I2SOutConfiguration));
+			} else {
+				com.cmd.StreamControl.SetupDataLen =
+					sizeof(TS_I2SConfiguration);
+				com.cmd.StreamControl.SetupDataAddr = BsSDI;
+				memcpy(com.cmd.StreamControl.SetupData,
+				       TS_I2SConfiguration,
+				       sizeof(TS_I2SConfiguration));
+			}
+		} else {
+			com.cmd.StreamControl.SetupDataLen = 8;
+			com.cmd.StreamControl.SetupDataAddr = BsUVI + 0x10;
+			memcpy(com.cmd.StreamControl.SetupData,
+			       TSFeatureDecoderSetup +
+			       8 * dev->card_info->tsf[stream], 8);
+		}
+	} else {
+		chan->nextBuffer = chan->RingBuffer.Head;
+		com.cmd.StreamControl.SetupDataLen =
+			16 + sizeof(ITUFeatureDecoderSetup);
+		com.cmd.StreamControl.SetupDataAddr = BsUVI;
+		memcpy(com.cmd.StreamControl.SetupData,
+		       ITUDecoderSetup[chan->itumode], 16);
+		memcpy(com.cmd.StreamControl.SetupData + 16,
+		       ITUFeatureDecoderSetup, sizeof(ITUFeatureDecoderSetup));
+	}
+	clear_buffers(chan);
+	chan->State = KSSTATE_RUN;
+	if (mode & SMODE_TRANSPORT_STREAM)
+		chan->HWState = HWSTATE_RUN;
+	else
+		chan->HWState = HWSTATE_STARTUP;
+	spin_unlock_irq(&chan->state_lock);
+
+	if (ngene_command(dev, &com) < 0) {
+		up(&dev->stream_mutex);
+		return -1;
+	}
+	up(&dev->stream_mutex);
+	return 0;
+}
+
+void set_transfer(struct ngene_channel *chan, int state)
+{
+	u8 control = 0, mode = 0, flags = 0;
+	struct ngene *dev = chan->dev;
+	int ret;
+
+	/*
+	printk(KERN_INFO DEVICE_NAME ": st %d\n", state);
+	msleep(100);
+	*/
+
+	if (state) {
+		if (chan->running) {
+			printk(KERN_INFO DEVICE_NAME ": already running\n");
+			return;
+		}
+	} else {
+		if (!chan->running) {
+			printk(KERN_INFO DEVICE_NAME ": already stopped\n");
+			return;
+		}
+	}
+
+	if (dev->card_info->switch_ctrl)
+		dev->card_info->switch_ctrl(chan, 1, state ^ 1);
+
+	if (state) {
+		spin_lock_irq(&chan->state_lock);
+
+		/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n",
+			  ngreadl(0x9310)); */
+		dvb_ringbuffer_flush(&dev->tsout_rbuf);
+		control = 0x80;
+		if (chan->mode & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
+			chan->Capture1Length = 512 * 188;
+			mode = SMODE_TRANSPORT_STREAM;
+		}
+		if (chan->mode & NGENE_IO_TSOUT) {
+			chan->pBufferExchange = tsout_exchange;
+			/* 0x66666666 = 50MHz *2^33 /250MHz */
+			chan->AudioDTOValue = 0x80000000;
+			chan->AudioDTOUpdated = 1;
+		}
+		if (chan->mode & NGENE_IO_TSIN)
+			chan->pBufferExchange = tsin_exchange;
+		spin_unlock_irq(&chan->state_lock);
+	} else
+		;/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n",
+			   ngreadl(0x9310)); */
+
+	ret = ngene_command_stream_control(dev, chan->number,
+					   control, mode, flags);
+	if (!ret)
+		chan->running = state;
+	else
+		printk(KERN_ERR DEVICE_NAME ": set_transfer %d failed\n",
+		       state);
+	if (!state) {
+		spin_lock_irq(&chan->state_lock);
+		chan->pBufferExchange = NULL;
+		dvb_ringbuffer_flush(&dev->tsout_rbuf);
+		spin_unlock_irq(&chan->state_lock);
+	}
+}
+
+
+/****************************************************************************/
+/* nGene hardware init and release functions ********************************/
+/****************************************************************************/
+
+static void free_ringbuffer(struct ngene *dev, struct SRingBufferDescriptor *rb)
+{
+	struct SBufferHeader *Cur = rb->Head;
+	u32 j;
+
+	if (!Cur)
+		return;
+
+	for (j = 0; j < rb->NumBuffers; j++, Cur = Cur->Next) {
+		if (Cur->Buffer1)
+			pci_free_consistent(dev->pci_dev,
+					    rb->Buffer1Length,
+					    Cur->Buffer1,
+					    Cur->scList1->Address);
+
+		if (Cur->Buffer2)
+			pci_free_consistent(dev->pci_dev,
+					    rb->Buffer2Length,
+					    Cur->Buffer2,
+					    Cur->scList2->Address);
+	}
+
+	if (rb->SCListMem)
+		pci_free_consistent(dev->pci_dev, rb->SCListMemSize,
+				    rb->SCListMem, rb->PASCListMem);
+
+	pci_free_consistent(dev->pci_dev, rb->MemSize, rb->Head, rb->PAHead);
+}
+
+static void free_idlebuffer(struct ngene *dev,
+		     struct SRingBufferDescriptor *rb,
+		     struct SRingBufferDescriptor *tb)
+{
+	int j;
+	struct SBufferHeader *Cur = tb->Head;
+
+	if (!rb->Head)
+		return;
+	free_ringbuffer(dev, rb);
+	for (j = 0; j < tb->NumBuffers; j++, Cur = Cur->Next) {
+		Cur->Buffer2 = NULL;
+		Cur->scList2 = NULL;
+		Cur->ngeneBuffer.Address_of_first_entry_2 = 0;
+		Cur->ngeneBuffer.Number_of_entries_2 = 0;
+	}
+}
+
+static void free_common_buffers(struct ngene *dev)
+{
+	u32 i;
+	struct ngene_channel *chan;
+
+	for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) {
+		chan = &dev->channel[i];
+		free_idlebuffer(dev, &chan->TSIdleBuffer, &chan->TSRingBuffer);
+		free_ringbuffer(dev, &chan->RingBuffer);
+		free_ringbuffer(dev, &chan->TSRingBuffer);
+	}
+
+	if (dev->OverflowBuffer)
+		pci_free_consistent(dev->pci_dev,
+				    OVERFLOW_BUFFER_SIZE,
+				    dev->OverflowBuffer, dev->PAOverflowBuffer);
+
+	if (dev->FWInterfaceBuffer)
+		pci_free_consistent(dev->pci_dev,
+				    4096,
+				    dev->FWInterfaceBuffer,
+				    dev->PAFWInterfaceBuffer);
+}
+
+/****************************************************************************/
+/* Ring buffer handling *****************************************************/
+/****************************************************************************/
+
+static int create_ring_buffer(struct pci_dev *pci_dev,
+		       struct SRingBufferDescriptor *descr, u32 NumBuffers)
+{
+	dma_addr_t tmp;
+	struct SBufferHeader *Head;
+	u32 i;
+	u32 MemSize = SIZEOF_SBufferHeader * NumBuffers;
+	u64 PARingBufferHead;
+	u64 PARingBufferCur;
+	u64 PARingBufferNext;
+	struct SBufferHeader *Cur, *Next;
+
+	descr->Head = NULL;
+	descr->MemSize = 0;
+	descr->PAHead = 0;
+	descr->NumBuffers = 0;
+
+	if (MemSize < 4096)
+		MemSize = 4096;
+
+	Head = pci_alloc_consistent(pci_dev, MemSize, &tmp);
+	PARingBufferHead = tmp;
+
+	if (!Head)
+		return -ENOMEM;
+
+	memset(Head, 0, MemSize);
+
+	PARingBufferCur = PARingBufferHead;
+	Cur = Head;
+
+	for (i = 0; i < NumBuffers - 1; i++) {
+		Next = (struct SBufferHeader *)
+			(((u8 *) Cur) + SIZEOF_SBufferHeader);
+		PARingBufferNext = PARingBufferCur + SIZEOF_SBufferHeader;
+		Cur->Next = Next;
+		Cur->ngeneBuffer.Next = PARingBufferNext;
+		Cur = Next;
+		PARingBufferCur = PARingBufferNext;
+	}
+	/* Last Buffer points back to first one */
+	Cur->Next = Head;
+	Cur->ngeneBuffer.Next = PARingBufferHead;
+
+	descr->Head       = Head;
+	descr->MemSize    = MemSize;
+	descr->PAHead     = PARingBufferHead;
+	descr->NumBuffers = NumBuffers;
+
+	return 0;
+}
+
+static int AllocateRingBuffers(struct pci_dev *pci_dev,
+			       dma_addr_t of,
+			       struct SRingBufferDescriptor *pRingBuffer,
+			       u32 Buffer1Length, u32 Buffer2Length)
+{
+	dma_addr_t tmp;
+	u32 i, j;
+	int status = 0;
+	u32 SCListMemSize = pRingBuffer->NumBuffers
+		* ((Buffer2Length != 0) ? (NUM_SCATTER_GATHER_ENTRIES * 2) :
+		    NUM_SCATTER_GATHER_ENTRIES)
+		* sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+
+	u64 PASCListMem;
+	struct HW_SCATTER_GATHER_ELEMENT *SCListEntry;
+	u64 PASCListEntry;
+	struct SBufferHeader *Cur;
+	void *SCListMem;
+
+	if (SCListMemSize < 4096)
+		SCListMemSize = 4096;
+
+	SCListMem = pci_alloc_consistent(pci_dev, SCListMemSize, &tmp);
+
+	PASCListMem = tmp;
+	if (SCListMem == NULL)
+		return -ENOMEM;
+
+	memset(SCListMem, 0, SCListMemSize);
+
+	pRingBuffer->SCListMem = SCListMem;
+	pRingBuffer->PASCListMem = PASCListMem;
+	pRingBuffer->SCListMemSize = SCListMemSize;
+	pRingBuffer->Buffer1Length = Buffer1Length;
+	pRingBuffer->Buffer2Length = Buffer2Length;
+
+	SCListEntry = SCListMem;
+	PASCListEntry = PASCListMem;
+	Cur = pRingBuffer->Head;
+
+	for (i = 0; i < pRingBuffer->NumBuffers; i += 1, Cur = Cur->Next) {
+		u64 PABuffer;
+
+		void *Buffer = pci_alloc_consistent(pci_dev, Buffer1Length,
+						    &tmp);
+		PABuffer = tmp;
+
+		if (Buffer == NULL)
+			return -ENOMEM;
+
+		Cur->Buffer1 = Buffer;
+
+		SCListEntry->Address = PABuffer;
+		SCListEntry->Length  = Buffer1Length;
+
+		Cur->scList1 = SCListEntry;
+		Cur->ngeneBuffer.Address_of_first_entry_1 = PASCListEntry;
+		Cur->ngeneBuffer.Number_of_entries_1 =
+			NUM_SCATTER_GATHER_ENTRIES;
+
+		SCListEntry += 1;
+		PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+
+#if NUM_SCATTER_GATHER_ENTRIES > 1
+		for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j += 1) {
+			SCListEntry->Address = of;
+			SCListEntry->Length = OVERFLOW_BUFFER_SIZE;
+			SCListEntry += 1;
+			PASCListEntry +=
+				sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+		}
+#endif
+
+		if (!Buffer2Length)
+			continue;
+
+		Buffer = pci_alloc_consistent(pci_dev, Buffer2Length, &tmp);
+		PABuffer = tmp;
+
+		if (Buffer == NULL)
+			return -ENOMEM;
+
+		Cur->Buffer2 = Buffer;
+
+		SCListEntry->Address = PABuffer;
+		SCListEntry->Length  = Buffer2Length;
+
+		Cur->scList2 = SCListEntry;
+		Cur->ngeneBuffer.Address_of_first_entry_2 = PASCListEntry;
+		Cur->ngeneBuffer.Number_of_entries_2 =
+			NUM_SCATTER_GATHER_ENTRIES;
+
+		SCListEntry   += 1;
+		PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+
+#if NUM_SCATTER_GATHER_ENTRIES > 1
+		for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j++) {
+			SCListEntry->Address = of;
+			SCListEntry->Length = OVERFLOW_BUFFER_SIZE;
+			SCListEntry += 1;
+			PASCListEntry +=
+				sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+		}
+#endif
+
+	}
+
+	return status;
+}
+
+static int FillTSIdleBuffer(struct SRingBufferDescriptor *pIdleBuffer,
+			    struct SRingBufferDescriptor *pRingBuffer)
+{
+	int status = 0;
+
+	/* Copy pointer to scatter gather list in TSRingbuffer
+	   structure for buffer 2
+	   Load number of buffer
+	*/
+	u32 n = pRingBuffer->NumBuffers;
+
+	/* Point to first buffer entry */
+	struct SBufferHeader *Cur = pRingBuffer->Head;
+	int i;
+	/* Loop thru all buffer and set Buffer 2 pointers to TSIdlebuffer */
+	for (i = 0; i < n; i++) {
+		Cur->Buffer2 = pIdleBuffer->Head->Buffer1;
+		Cur->scList2 = pIdleBuffer->Head->scList1;
+		Cur->ngeneBuffer.Address_of_first_entry_2 =
+			pIdleBuffer->Head->ngeneBuffer.
+			Address_of_first_entry_1;
+		Cur->ngeneBuffer.Number_of_entries_2 =
+			pIdleBuffer->Head->ngeneBuffer.Number_of_entries_1;
+		Cur = Cur->Next;
+	}
+	return status;
+}
+
+static u32 RingBufferSizes[MAX_STREAM] = {
+	RING_SIZE_VIDEO,
+	RING_SIZE_VIDEO,
+	RING_SIZE_AUDIO,
+	RING_SIZE_AUDIO,
+	RING_SIZE_AUDIO,
+};
+
+static u32 Buffer1Sizes[MAX_STREAM] = {
+	MAX_VIDEO_BUFFER_SIZE,
+	MAX_VIDEO_BUFFER_SIZE,
+	MAX_AUDIO_BUFFER_SIZE,
+	MAX_AUDIO_BUFFER_SIZE,
+	MAX_AUDIO_BUFFER_SIZE
+};
+
+static u32 Buffer2Sizes[MAX_STREAM] = {
+	MAX_VBI_BUFFER_SIZE,
+	MAX_VBI_BUFFER_SIZE,
+	0,
+	0,
+	0
+};
+
+
+static int AllocCommonBuffers(struct ngene *dev)
+{
+	int status = 0, i;
+
+	dev->FWInterfaceBuffer = pci_alloc_consistent(dev->pci_dev, 4096,
+						     &dev->PAFWInterfaceBuffer);
+	if (!dev->FWInterfaceBuffer)
+		return -ENOMEM;
+	dev->hosttongene = dev->FWInterfaceBuffer;
+	dev->ngenetohost = dev->FWInterfaceBuffer + 256;
+	dev->EventBuffer = dev->FWInterfaceBuffer + 512;
+
+	dev->OverflowBuffer = pci_alloc_consistent(dev->pci_dev,
+						   OVERFLOW_BUFFER_SIZE,
+						   &dev->PAOverflowBuffer);
+	if (!dev->OverflowBuffer)
+		return -ENOMEM;
+	memset(dev->OverflowBuffer, 0, OVERFLOW_BUFFER_SIZE);
+
+	for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) {
+		int type = dev->card_info->io_type[i];
+
+		dev->channel[i].State = KSSTATE_STOP;
+
+		if (type & (NGENE_IO_TV | NGENE_IO_HDTV | NGENE_IO_AIN)) {
+			status = create_ring_buffer(dev->pci_dev,
+						    &dev->channel[i].RingBuffer,
+						    RingBufferSizes[i]);
+			if (status < 0)
+				break;
+
+			if (type & (NGENE_IO_TV | NGENE_IO_AIN)) {
+				status = AllocateRingBuffers(dev->pci_dev,
+							     dev->
+							     PAOverflowBuffer,
+							     &dev->channel[i].
+							     RingBuffer,
+							     Buffer1Sizes[i],
+							     Buffer2Sizes[i]);
+				if (status < 0)
+					break;
+			} else if (type & NGENE_IO_HDTV) {
+				status = AllocateRingBuffers(dev->pci_dev,
+							     dev->
+							     PAOverflowBuffer,
+							     &dev->channel[i].
+							     RingBuffer,
+							   MAX_HDTV_BUFFER_SIZE,
+							     0);
+				if (status < 0)
+					break;
+			}
+		}
+
+		if (type & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
+
+			status = create_ring_buffer(dev->pci_dev,
+						    &dev->channel[i].
+						    TSRingBuffer, RING_SIZE_TS);
+			if (status < 0)
+				break;
+
+			status = AllocateRingBuffers(dev->pci_dev,
+						     dev->PAOverflowBuffer,
+						     &dev->channel[i].
+						     TSRingBuffer,
+						     MAX_TS_BUFFER_SIZE, 0);
+			if (status)
+				break;
+		}
+
+		if (type & NGENE_IO_TSOUT) {
+			status = create_ring_buffer(dev->pci_dev,
+						    &dev->channel[i].
+						    TSIdleBuffer, 1);
+			if (status < 0)
+				break;
+			status = AllocateRingBuffers(dev->pci_dev,
+						     dev->PAOverflowBuffer,
+						     &dev->channel[i].
+						     TSIdleBuffer,
+						     MAX_TS_BUFFER_SIZE, 0);
+			if (status)
+				break;
+			FillTSIdleBuffer(&dev->channel[i].TSIdleBuffer,
+					 &dev->channel[i].TSRingBuffer);
+		}
+	}
+	return status;
+}
+
+static void ngene_release_buffers(struct ngene *dev)
+{
+	if (dev->iomem)
+		iounmap(dev->iomem);
+	free_common_buffers(dev);
+	vfree(dev->tsout_buf);
+	vfree(dev->tsin_buf);
+	vfree(dev->ain_buf);
+	vfree(dev->vin_buf);
+	vfree(dev);
+}
+
+static int ngene_get_buffers(struct ngene *dev)
+{
+	if (AllocCommonBuffers(dev))
+		return -ENOMEM;
+	if (dev->card_info->io_type[4] & NGENE_IO_TSOUT) {
+		dev->tsout_buf = vmalloc(TSOUT_BUF_SIZE);
+		if (!dev->tsout_buf)
+			return -ENOMEM;
+		dvb_ringbuffer_init(&dev->tsout_rbuf,
+				    dev->tsout_buf, TSOUT_BUF_SIZE);
+	}
+	if (dev->card_info->io_type[2]&NGENE_IO_TSIN) {
+		dev->tsin_buf = vmalloc(TSIN_BUF_SIZE);
+		if (!dev->tsin_buf)
+			return -ENOMEM;
+		dvb_ringbuffer_init(&dev->tsin_rbuf,
+				    dev->tsin_buf, TSIN_BUF_SIZE);
+	}
+	if (dev->card_info->io_type[2] & NGENE_IO_AIN) {
+		dev->ain_buf = vmalloc(AIN_BUF_SIZE);
+		if (!dev->ain_buf)
+			return -ENOMEM;
+		dvb_ringbuffer_init(&dev->ain_rbuf, dev->ain_buf, AIN_BUF_SIZE);
+	}
+	if (dev->card_info->io_type[0] & NGENE_IO_HDTV) {
+		dev->vin_buf = vmalloc(VIN_BUF_SIZE);
+		if (!dev->vin_buf)
+			return -ENOMEM;
+		dvb_ringbuffer_init(&dev->vin_rbuf, dev->vin_buf, VIN_BUF_SIZE);
+	}
+	dev->iomem = ioremap(pci_resource_start(dev->pci_dev, 0),
+			     pci_resource_len(dev->pci_dev, 0));
+	if (!dev->iomem)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void ngene_init(struct ngene *dev)
+{
+	int i;
+
+	tasklet_init(&dev->event_tasklet, event_tasklet, (unsigned long)dev);
+
+	memset_io(dev->iomem + 0xc000, 0x00, 0x220);
+	memset_io(dev->iomem + 0xc400, 0x00, 0x100);
+
+	for (i = 0; i < MAX_STREAM; i++) {
+		dev->channel[i].dev = dev;
+		dev->channel[i].number = i;
+	}
+
+	dev->fw_interface_version = 0;
+
+	ngwritel(0, NGENE_INT_ENABLE);
+
+	dev->icounts = ngreadl(NGENE_INT_COUNTS);
+
+	dev->device_version = ngreadl(DEV_VER) & 0x0f;
+	printk(KERN_INFO DEVICE_NAME ": Device version %d\n",
+	       dev->device_version);
+}
+
+static int ngene_load_firm(struct ngene *dev)
+{
+	u32 size;
+	const struct firmware *fw = NULL;
+	u8 *ngene_fw;
+	char *fw_name;
+	int err, version;
+
+	version = dev->card_info->fw_version;
+
+	switch (version) {
+	default:
+	case 15:
+		version = 15;
+		size = 23466;
+		fw_name = "ngene_15.fw";
+		dev->cmd_timeout_workaround = true;
+		break;
+	case 16:
+		size = 23498;
+		fw_name = "ngene_16.fw";
+		dev->cmd_timeout_workaround = true;
+		break;
+	case 17:
+		size = 24446;
+		fw_name = "ngene_17.fw";
+		dev->cmd_timeout_workaround = true;
+		break;
+	case 18:
+		size = 0;
+		fw_name = "ngene_18.fw";
+		break;
+	}
+
+	if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) {
+		printk(KERN_ERR DEVICE_NAME
+			": Could not load firmware file %s.\n", fw_name);
+		printk(KERN_INFO DEVICE_NAME
+			": Copy %s to your hotplug directory!\n", fw_name);
+		return -1;
+	}
+	if (size == 0)
+		size = fw->size;
+	if (size != fw->size) {
+		printk(KERN_ERR DEVICE_NAME
+			": Firmware %s has invalid size!", fw_name);
+		err = -1;
+	} else {
+		printk(KERN_INFO DEVICE_NAME
+			": Loading firmware file %s.\n", fw_name);
+		ngene_fw = (u8 *) fw->data;
+		err = ngene_command_load_firmware(dev, ngene_fw, size);
+	}
+
+	release_firmware(fw);
+
+	return err;
+}
+
+static void ngene_stop(struct ngene *dev)
+{
+	down(&dev->cmd_mutex);
+	i2c_del_adapter(&(dev->channel[0].i2c_adapter));
+	i2c_del_adapter(&(dev->channel[1].i2c_adapter));
+	ngwritel(0, NGENE_INT_ENABLE);
+	ngwritel(0, NGENE_COMMAND);
+	ngwritel(0, NGENE_COMMAND_HI);
+	ngwritel(0, NGENE_STATUS);
+	ngwritel(0, NGENE_STATUS_HI);
+	ngwritel(0, NGENE_EVENT);
+	ngwritel(0, NGENE_EVENT_HI);
+	free_irq(dev->pci_dev->irq, dev);
+#ifdef CONFIG_PCI_MSI
+	if (dev->msi_enabled)
+		pci_disable_msi(dev->pci_dev);
+#endif
+}
+
+static int ngene_buffer_config(struct ngene *dev)
+{
+	int stat;
+
+	if (dev->card_info->fw_version >= 17) {
+		u8 tsin12_config[6]   = { 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 };
+		u8 tsin1234_config[6] = { 0x30, 0x30, 0x00, 0x30, 0x30, 0x00 };
+		u8 tsio1235_config[6] = { 0x30, 0x30, 0x00, 0x28, 0x00, 0x38 };
+		u8 *bconf = tsin12_config;
+
+		if (dev->card_info->io_type[2]&NGENE_IO_TSIN &&
+		    dev->card_info->io_type[3]&NGENE_IO_TSIN) {
+			bconf = tsin1234_config;
+			if (dev->card_info->io_type[4]&NGENE_IO_TSOUT &&
+			    dev->ci.en)
+				bconf = tsio1235_config;
+		}
+		stat = ngene_command_config_free_buf(dev, bconf);
+	} else {
+		int bconf = BUFFER_CONFIG_4422;
+
+		if (dev->card_info->io_type[3] == NGENE_IO_TSIN)
+			bconf = BUFFER_CONFIG_3333;
+		stat = ngene_command_config_buf(dev, bconf);
+	}
+	return stat;
+}
+
+
+static int ngene_start(struct ngene *dev)
+{
+	int stat;
+	int i;
+
+	pci_set_master(dev->pci_dev);
+	ngene_init(dev);
+
+	stat = request_irq(dev->pci_dev->irq, irq_handler,
+			   IRQF_SHARED, "nGene",
+			   (void *)dev);
+	if (stat < 0)
+		return stat;
+
+	init_waitqueue_head(&dev->cmd_wq);
+	init_waitqueue_head(&dev->tx_wq);
+	init_waitqueue_head(&dev->rx_wq);
+	sema_init(&dev->cmd_mutex, 1);
+	sema_init(&dev->stream_mutex, 1);
+	sema_init(&dev->pll_mutex, 1);
+	sema_init(&dev->i2c_switch_mutex, 1);
+	spin_lock_init(&dev->cmd_lock);
+	for (i = 0; i < MAX_STREAM; i++)
+		spin_lock_init(&dev->channel[i].state_lock);
+	ngwritel(1, TIMESTAMPS);
+
+	ngwritel(1, NGENE_INT_ENABLE);
+
+	stat = ngene_load_firm(dev);
+	if (stat < 0)
+		goto fail;
+
+#ifdef CONFIG_PCI_MSI
+	/* enable MSI if kernel and card support it */
+	if (pci_msi_enabled() && dev->card_info->msi_supported) {
+		unsigned long flags;
+
+		ngwritel(0, NGENE_INT_ENABLE);
+		free_irq(dev->pci_dev->irq, dev);
+		stat = pci_enable_msi(dev->pci_dev);
+		if (stat) {
+			printk(KERN_INFO DEVICE_NAME
+				": MSI not available\n");
+			flags = IRQF_SHARED;
+		} else {
+			flags = 0;
+			dev->msi_enabled = true;
+		}
+		stat = request_irq(dev->pci_dev->irq, irq_handler,
+					flags, "nGene", dev);
+		if (stat < 0)
+			goto fail2;
+		ngwritel(1, NGENE_INT_ENABLE);
+	}
+#endif
+
+	stat = ngene_i2c_init(dev, 0);
+	if (stat < 0)
+		goto fail;
+
+	stat = ngene_i2c_init(dev, 1);
+	if (stat < 0)
+		goto fail;
+
+	return 0;
+
+fail:
+	ngwritel(0, NGENE_INT_ENABLE);
+	free_irq(dev->pci_dev->irq, dev);
+#ifdef CONFIG_PCI_MSI
+fail2:
+	if (dev->msi_enabled)
+		pci_disable_msi(dev->pci_dev);
+#endif
+	return stat;
+}
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static void release_channel(struct ngene_channel *chan)
+{
+	struct dvb_demux *dvbdemux = &chan->demux;
+	struct ngene *dev = chan->dev;
+
+	if (chan->running)
+		set_transfer(chan, 0);
+
+	tasklet_kill(&chan->demux_tasklet);
+
+	if (chan->ci_dev) {
+		dvb_unregister_device(chan->ci_dev);
+		chan->ci_dev = NULL;
+	}
+
+	if (chan->fe2)
+		dvb_unregister_frontend(chan->fe2);
+
+	if (chan->fe) {
+		dvb_unregister_frontend(chan->fe);
+		dvb_frontend_detach(chan->fe);
+		chan->fe = NULL;
+	}
+
+	if (chan->has_demux) {
+		dvb_net_release(&chan->dvbnet);
+		dvbdemux->dmx.close(&dvbdemux->dmx);
+		dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
+					      &chan->hw_frontend);
+		dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
+					      &chan->mem_frontend);
+		dvb_dmxdev_release(&chan->dmxdev);
+		dvb_dmx_release(&chan->demux);
+		chan->has_demux = false;
+	}
+
+	if (chan->has_adapter) {
+		dvb_unregister_adapter(&dev->adapter[chan->number]);
+		chan->has_adapter = false;
+	}
+}
+
+static int init_channel(struct ngene_channel *chan)
+{
+	int ret = 0, nr = chan->number;
+	struct dvb_adapter *adapter = NULL;
+	struct dvb_demux *dvbdemux = &chan->demux;
+	struct ngene *dev = chan->dev;
+	struct ngene_info *ni = dev->card_info;
+	int io = ni->io_type[nr];
+
+	tasklet_init(&chan->demux_tasklet, demux_tasklet, (unsigned long)chan);
+	chan->users = 0;
+	chan->type = io;
+	chan->mode = chan->type;	/* for now only one mode */
+
+	if (io & NGENE_IO_TSIN) {
+		chan->fe = NULL;
+		if (ni->demod_attach[nr]) {
+			ret = ni->demod_attach[nr](chan);
+			if (ret < 0)
+				goto err;
+		}
+		if (chan->fe && ni->tuner_attach[nr]) {
+			ret = ni->tuner_attach[nr](chan);
+			if (ret < 0)
+				goto err;
+		}
+	}
+
+	if (!dev->ci.en && (io & NGENE_IO_TSOUT))
+		return 0;
+
+	if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
+		if (nr >= STREAM_AUDIOIN1)
+			chan->DataFormatFlags = DF_SWAP32;
+
+		if (nr == 0 || !one_adapter || dev->first_adapter == NULL) {
+			adapter = &dev->adapter[nr];
+			ret = dvb_register_adapter(adapter, "nGene",
+						   THIS_MODULE,
+						   &chan->dev->pci_dev->dev,
+						   adapter_nr);
+			if (ret < 0)
+				goto err;
+			if (dev->first_adapter == NULL)
+				dev->first_adapter = adapter;
+			chan->has_adapter = true;
+		} else
+			adapter = dev->first_adapter;
+	}
+
+	if (dev->ci.en && (io & NGENE_IO_TSOUT)) {
+		dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1);
+		set_transfer(chan, 1);
+		chan->dev->channel[2].DataFormatFlags = DF_SWAP32;
+		set_transfer(&chan->dev->channel[2], 1);
+		dvb_register_device(adapter, &chan->ci_dev,
+				    &ngene_dvbdev_ci, (void *) chan,
+				    DVB_DEVICE_SEC);
+		if (!chan->ci_dev)
+			goto err;
+	}
+
+	if (chan->fe) {
+		if (dvb_register_frontend(adapter, chan->fe) < 0)
+			goto err;
+		chan->has_demux = true;
+	}
+	if (chan->fe2) {
+		if (dvb_register_frontend(adapter, chan->fe2) < 0)
+			goto err;
+		chan->fe2->tuner_priv = chan->fe->tuner_priv;
+		memcpy(&chan->fe2->ops.tuner_ops,
+		       &chan->fe->ops.tuner_ops,
+		       sizeof(struct dvb_tuner_ops));
+	}
+
+	if (chan->has_demux) {
+		ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux",
+					      ngene_start_feed,
+					      ngene_stop_feed, chan);
+		ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux,
+						 &chan->hw_frontend,
+						 &chan->mem_frontend, adapter);
+		ret = dvb_net_init(adapter, &chan->dvbnet, &chan->demux.dmx);
+	}
+
+	return ret;
+
+err:
+	if (chan->fe) {
+		dvb_frontend_detach(chan->fe);
+		chan->fe = NULL;
+	}
+	release_channel(chan);
+	return 0;
+}
+
+static int init_channels(struct ngene *dev)
+{
+	int i, j;
+
+	for (i = 0; i < MAX_STREAM; i++) {
+		dev->channel[i].number = i;
+		if (init_channel(&dev->channel[i]) < 0) {
+			for (j = i - 1; j >= 0; j--)
+				release_channel(&dev->channel[j]);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static struct cxd2099_cfg cxd_cfg = {
+	.bitrate = 62000,
+	.adr = 0x40,
+	.polarity = 0,
+	.clock_mode = 0,
+};
+
+static void cxd_attach(struct ngene *dev)
+{
+	struct ngene_ci *ci = &dev->ci;
+
+	ci->en = cxd2099_attach(&cxd_cfg, dev, &dev->channel[0].i2c_adapter);
+	ci->dev = dev;
+	return;
+}
+
+static void cxd_detach(struct ngene *dev)
+{
+	struct ngene_ci *ci = &dev->ci;
+
+	dvb_ca_en50221_release(ci->en);
+	kfree(ci->en);
+	ci->en = 0;
+}
+
+/***********************************/
+/* workaround for shutdown failure */
+/***********************************/
+
+static void ngene_unlink(struct ngene *dev)
+{
+	struct ngene_command com;
+
+	com.cmd.hdr.Opcode = CMD_MEM_WRITE;
+	com.cmd.hdr.Length = 3;
+	com.cmd.MemoryWrite.address = 0x910c;
+	com.cmd.MemoryWrite.data = 0xff;
+	com.in_len = 3;
+	com.out_len = 1;
+
+	down(&dev->cmd_mutex);
+	ngwritel(0, NGENE_INT_ENABLE);
+	ngene_command_mutex(dev, &com);
+	up(&dev->cmd_mutex);
+}
+
+void ngene_shutdown(struct pci_dev *pdev)
+{
+	struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev);
+
+	if (!dev || !shutdown_workaround)
+		return;
+
+	printk(KERN_INFO DEVICE_NAME ": shutdown workaround...\n");
+	ngene_unlink(dev);
+	pci_disable_device(pdev);
+}
+
+/****************************************************************************/
+/* device probe/remove calls ************************************************/
+/****************************************************************************/
+
+void __devexit ngene_remove(struct pci_dev *pdev)
+{
+	struct ngene *dev = pci_get_drvdata(pdev);
+	int i;
+
+	tasklet_kill(&dev->event_tasklet);
+	for (i = MAX_STREAM - 1; i >= 0; i--)
+		release_channel(&dev->channel[i]);
+	if (dev->ci.en)
+		cxd_detach(dev);
+	ngene_stop(dev);
+	ngene_release_buffers(dev);
+	pci_set_drvdata(pdev, NULL);
+	pci_disable_device(pdev);
+}
+
+int __devinit ngene_probe(struct pci_dev *pci_dev,
+			  const struct pci_device_id *id)
+{
+	struct ngene *dev;
+	int stat = 0;
+
+	if (pci_enable_device(pci_dev) < 0)
+		return -ENODEV;
+
+	dev = vzalloc(sizeof(struct ngene));
+	if (dev == NULL) {
+		stat = -ENOMEM;
+		goto fail0;
+	}
+
+	dev->pci_dev = pci_dev;
+	dev->card_info = (struct ngene_info *)id->driver_data;
+	printk(KERN_INFO DEVICE_NAME ": Found %s\n", dev->card_info->name);
+
+	pci_set_drvdata(pci_dev, dev);
+
+	/* Alloc buffers and start nGene */
+	stat = ngene_get_buffers(dev);
+	if (stat < 0)
+		goto fail1;
+	stat = ngene_start(dev);
+	if (stat < 0)
+		goto fail1;
+
+	cxd_attach(dev);
+
+	stat = ngene_buffer_config(dev);
+	if (stat < 0)
+		goto fail1;
+
+
+	dev->i2c_current_bus = -1;
+
+	/* Register DVB adapters and devices for both channels */
+	if (init_channels(dev) < 0)
+		goto fail2;
+
+	return 0;
+
+fail2:
+	ngene_stop(dev);
+fail1:
+	ngene_release_buffers(dev);
+fail0:
+	pci_disable_device(pci_dev);
+	pci_set_drvdata(pci_dev, NULL);
+	return stat;
+}
diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c
new file mode 100644
index 0000000..fcb16a6
--- /dev/null
+++ b/drivers/media/pci/ngene/ngene-dvb.c
@@ -0,0 +1,261 @@
+/*
+ * ngene-dvb.c: nGene PCIe bridge driver - DVB functions
+ *
+ * Copyright (C) 2005-2007 Micronas
+ *
+ * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
+ *                         Modifications for new nGene firmware,
+ *                         support for EEPROM-copying,
+ *                         support for new dual DVB-S2 card prototype
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/io.h>
+#include <asm/div64.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+#include <linux/byteorder/generic.h>
+#include <linux/firmware.h>
+#include <linux/vmalloc.h>
+
+#include "ngene.h"
+
+
+/****************************************************************************/
+/* COMMAND API interface ****************************************************/
+/****************************************************************************/
+
+static ssize_t ts_write(struct file *file, const char *buf,
+			size_t count, loff_t *ppos)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct ngene_channel *chan = dvbdev->priv;
+	struct ngene *dev = chan->dev;
+
+	if (wait_event_interruptible(dev->tsout_rbuf.queue,
+				     dvb_ringbuffer_free
+				     (&dev->tsout_rbuf) >= count) < 0)
+		return 0;
+
+	dvb_ringbuffer_write(&dev->tsout_rbuf, buf, count);
+
+	return count;
+}
+
+static ssize_t ts_read(struct file *file, char *buf,
+		       size_t count, loff_t *ppos)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct ngene_channel *chan = dvbdev->priv;
+	struct ngene *dev = chan->dev;
+	int left, avail;
+
+	left = count;
+	while (left) {
+		if (wait_event_interruptible(
+			    dev->tsin_rbuf.queue,
+			    dvb_ringbuffer_avail(&dev->tsin_rbuf) > 0) < 0)
+			return -EAGAIN;
+		avail = dvb_ringbuffer_avail(&dev->tsin_rbuf);
+		if (avail > left)
+			avail = left;
+		dvb_ringbuffer_read_user(&dev->tsin_rbuf, buf, avail);
+		left -= avail;
+		buf += avail;
+	}
+	return count;
+}
+
+static const struct file_operations ci_fops = {
+	.owner   = THIS_MODULE,
+	.read    = ts_read,
+	.write   = ts_write,
+	.open    = dvb_generic_open,
+	.release = dvb_generic_release,
+};
+
+struct dvb_device ngene_dvbdev_ci = {
+	.priv    = 0,
+	.readers = -1,
+	.writers = -1,
+	.users   = -1,
+	.fops    = &ci_fops,
+};
+
+
+/****************************************************************************/
+/* DVB functions and API interface ******************************************/
+/****************************************************************************/
+
+static void swap_buffer(u32 *p, u32 len)
+{
+	while (len) {
+		*p = swab32(*p);
+		p++;
+		len -= 4;
+	}
+}
+
+/* start of filler packet */
+static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER };
+
+/* #define DEBUG_CI_XFER */
+#ifdef DEBUG_CI_XFER
+static u32 ok;
+static u32 overflow;
+static u32 stripped;
+#endif
+
+void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
+{
+	struct ngene_channel *chan = priv;
+	struct ngene *dev = chan->dev;
+
+
+	if (flags & DF_SWAP32)
+		swap_buffer(buf, len);
+
+	if (dev->ci.en && chan->number == 2) {
+		while (len >= 188) {
+			if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) {
+				if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) {
+					dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188);
+					wake_up(&dev->tsin_rbuf.queue);
+#ifdef DEBUG_CI_XFER
+					ok++;
+#endif
+				}
+#ifdef DEBUG_CI_XFER
+				else
+					overflow++;
+#endif
+			}
+#ifdef DEBUG_CI_XFER
+			else
+				stripped++;
+
+			if (ok % 100 == 0 && overflow)
+				printk(KERN_WARNING "%s: ok %u overflow %u dropped %u\n", __func__, ok, overflow, stripped);
+#endif
+			buf += 188;
+			len -= 188;
+		}
+		return NULL;
+	}
+
+	if (chan->users > 0)
+		dvb_dmx_swfilter(&chan->demux, buf, len);
+
+	return NULL;
+}
+
+void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
+{
+	struct ngene_channel *chan = priv;
+	struct ngene *dev = chan->dev;
+	u32 alen;
+
+	alen = dvb_ringbuffer_avail(&dev->tsout_rbuf);
+	alen -= alen % 188;
+
+	if (alen < len)
+		FillTSBuffer(buf + alen, len - alen, flags);
+	else
+		alen = len;
+	dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen);
+	if (flags & DF_SWAP32)
+		swap_buffer((u32 *)buf, alen);
+	wake_up_interruptible(&dev->tsout_rbuf.queue);
+	return buf;
+}
+
+
+
+int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct ngene_channel *chan = dvbdmx->priv;
+
+	if (chan->users == 0) {
+		if (!chan->dev->cmd_timeout_workaround || !chan->running)
+			set_transfer(chan, 1);
+	}
+
+	return ++chan->users;
+}
+
+int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct ngene_channel *chan = dvbdmx->priv;
+
+	if (--chan->users)
+		return chan->users;
+
+	if (!chan->dev->cmd_timeout_workaround)
+		set_transfer(chan, 0);
+
+	return 0;
+}
+
+int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
+			    int (*start_feed)(struct dvb_demux_feed *),
+			    int (*stop_feed)(struct dvb_demux_feed *),
+			    void *priv)
+{
+	dvbdemux->priv = priv;
+
+	dvbdemux->filternum = 256;
+	dvbdemux->feednum = 256;
+	dvbdemux->start_feed = start_feed;
+	dvbdemux->stop_feed = stop_feed;
+	dvbdemux->write_to_decoder = NULL;
+	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+				      DMX_SECTION_FILTERING |
+				      DMX_MEMORY_BASED_FILTERING);
+	return dvb_dmx_init(dvbdemux);
+}
+
+int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
+			       struct dvb_demux *dvbdemux,
+			       struct dmx_frontend *hw_frontend,
+			       struct dmx_frontend *mem_frontend,
+			       struct dvb_adapter *dvb_adapter)
+{
+	int ret;
+
+	dmxdev->filternum = 256;
+	dmxdev->demux = &dvbdemux->dmx;
+	dmxdev->capabilities = 0;
+	ret = dvb_dmxdev_init(dmxdev, dvb_adapter);
+	if (ret < 0)
+		return ret;
+
+	hw_frontend->source = DMX_FRONTEND_0;
+	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend);
+	mem_frontend->source = DMX_MEMORY_FE;
+	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend);
+	return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend);
+}
diff --git a/drivers/media/pci/ngene/ngene-i2c.c b/drivers/media/pci/ngene/ngene-i2c.c
new file mode 100644
index 0000000..d28554f
--- /dev/null
+++ b/drivers/media/pci/ngene/ngene-i2c.c
@@ -0,0 +1,176 @@
+/*
+ * ngene-i2c.c: nGene PCIe bridge driver i2c functions
+ *
+ * Copyright (C) 2005-2007 Micronas
+ *
+ * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
+ *                         Modifications for new nGene firmware,
+ *                         support for EEPROM-copying,
+ *                         support for new dual DVB-S2 card prototype
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+/* FIXME - some of these can probably be removed */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/io.h>
+#include <asm/div64.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/timer.h>
+#include <linux/byteorder/generic.h>
+#include <linux/firmware.h>
+#include <linux/vmalloc.h>
+
+#include "ngene.h"
+
+/* Firmware command for i2c operations */
+static int ngene_command_i2c_read(struct ngene *dev, u8 adr,
+			   u8 *out, u8 outlen, u8 *in, u8 inlen, int flag)
+{
+	struct ngene_command com;
+
+	com.cmd.hdr.Opcode = CMD_I2C_READ;
+	com.cmd.hdr.Length = outlen + 3;
+	com.cmd.I2CRead.Device = adr << 1;
+	memcpy(com.cmd.I2CRead.Data, out, outlen);
+	com.cmd.I2CRead.Data[outlen] = inlen;
+	com.cmd.I2CRead.Data[outlen + 1] = 0;
+	com.in_len = outlen + 3;
+	com.out_len = inlen + 1;
+
+	if (ngene_command(dev, &com) < 0)
+		return -EIO;
+
+	if ((com.cmd.raw8[0] >> 1) != adr)
+		return -EIO;
+
+	if (flag)
+		memcpy(in, com.cmd.raw8, inlen + 1);
+	else
+		memcpy(in, com.cmd.raw8 + 1, inlen);
+	return 0;
+}
+
+static int ngene_command_i2c_write(struct ngene *dev, u8 adr,
+				   u8 *out, u8 outlen)
+{
+	struct ngene_command com;
+
+
+	com.cmd.hdr.Opcode = CMD_I2C_WRITE;
+	com.cmd.hdr.Length = outlen + 1;
+	com.cmd.I2CRead.Device = adr << 1;
+	memcpy(com.cmd.I2CRead.Data, out, outlen);
+	com.in_len = outlen + 1;
+	com.out_len = 1;
+
+	if (ngene_command(dev, &com) < 0)
+		return -EIO;
+
+	if (com.cmd.raw8[0] == 1)
+		return -EIO;
+
+	return 0;
+}
+
+static void ngene_i2c_set_bus(struct ngene *dev, int bus)
+{
+	if (!(dev->card_info->i2c_access & 2))
+		return;
+	if (dev->i2c_current_bus == bus)
+		return;
+
+	switch (bus) {
+	case 0:
+		ngene_command_gpio_set(dev, 3, 0);
+		ngene_command_gpio_set(dev, 2, 1);
+		break;
+
+	case 1:
+		ngene_command_gpio_set(dev, 2, 0);
+		ngene_command_gpio_set(dev, 3, 1);
+		break;
+	}
+	dev->i2c_current_bus = bus;
+}
+
+static int ngene_i2c_master_xfer(struct i2c_adapter *adapter,
+				 struct i2c_msg msg[], int num)
+{
+	struct ngene_channel *chan =
+		(struct ngene_channel *)i2c_get_adapdata(adapter);
+	struct ngene *dev = chan->dev;
+
+	down(&dev->i2c_switch_mutex);
+	ngene_i2c_set_bus(dev, chan->number);
+
+	if (num == 2 && msg[1].flags & I2C_M_RD && !(msg[0].flags & I2C_M_RD))
+		if (!ngene_command_i2c_read(dev, msg[0].addr,
+					    msg[0].buf, msg[0].len,
+					    msg[1].buf, msg[1].len, 0))
+			goto done;
+
+	if (num == 1 && !(msg[0].flags & I2C_M_RD))
+		if (!ngene_command_i2c_write(dev, msg[0].addr,
+					     msg[0].buf, msg[0].len))
+			goto done;
+	if (num == 1 && (msg[0].flags & I2C_M_RD))
+		if (!ngene_command_i2c_read(dev, msg[0].addr, NULL, 0,
+					    msg[0].buf, msg[0].len, 0))
+			goto done;
+
+	up(&dev->i2c_switch_mutex);
+	return -EIO;
+
+done:
+	up(&dev->i2c_switch_mutex);
+	return num;
+}
+
+
+static u32 ngene_i2c_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm ngene_i2c_algo = {
+	.master_xfer = ngene_i2c_master_xfer,
+	.functionality = ngene_i2c_functionality,
+};
+
+int ngene_i2c_init(struct ngene *dev, int dev_nr)
+{
+	struct i2c_adapter *adap = &(dev->channel[dev_nr].i2c_adapter);
+
+	i2c_set_adapdata(adap, &(dev->channel[dev_nr]));
+
+	strcpy(adap->name, "nGene");
+
+	adap->algo = &ngene_i2c_algo;
+	adap->algo_data = (void *)&(dev->channel[dev_nr]);
+	adap->dev.parent = &dev->pci_dev->dev;
+
+	return i2c_add_adapter(adap);
+}
+
diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h
new file mode 100644
index 0000000..5443dc0
--- /dev/null
+++ b/drivers/media/pci/ngene/ngene.h
@@ -0,0 +1,921 @@
+/*
+ * ngene.h: nGene PCIe bridge driver
+ *
+ * Copyright (C) 2005-2007 Micronas
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _NGENE_H_
+#define _NGENE_H_
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <asm/dma.h>
+#include <linux/scatterlist.h>
+
+#include <linux/dvb/frontend.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_ca_en50221.h"
+#include "dvb_frontend.h"
+#include "dvb_ringbuffer.h"
+#include "dvb_net.h"
+#include "cxd2099.h"
+
+#define DEVICE_NAME "ngene"
+
+#define NGENE_VID       0x18c3
+#define NGENE_PID       0x0720
+
+#ifndef VIDEO_CAP_VC1
+#define VIDEO_CAP_AVC   128
+#define VIDEO_CAP_H264  128
+#define VIDEO_CAP_VC1   256
+#define VIDEO_CAP_WMV9  256
+#define VIDEO_CAP_MPEG4 512
+#endif
+
+enum STREAM {
+	STREAM_VIDEOIN1 = 0,        /* ITU656 or TS Input */
+	STREAM_VIDEOIN2,
+	STREAM_AUDIOIN1,            /* I2S or SPI Input */
+	STREAM_AUDIOIN2,
+	STREAM_AUDIOOUT,
+	MAX_STREAM
+};
+
+enum SMODE_BITS {
+	SMODE_AUDIO_SPDIF = 0x20,
+	SMODE_AVSYNC = 0x10,
+	SMODE_TRANSPORT_STREAM = 0x08,
+	SMODE_AUDIO_CAPTURE = 0x04,
+	SMODE_VBI_CAPTURE = 0x02,
+	SMODE_VIDEO_CAPTURE = 0x01
+};
+
+enum STREAM_FLAG_BITS {
+	SFLAG_CHROMA_FORMAT_2COMP  = 0x01, /* Chroma Format : 2's complement */
+	SFLAG_CHROMA_FORMAT_OFFSET = 0x00, /* Chroma Format : Binary offset */
+	SFLAG_ORDER_LUMA_CHROMA    = 0x02, /* Byte order: Y,Cb,Y,Cr */
+	SFLAG_ORDER_CHROMA_LUMA    = 0x00, /* Byte order: Cb,Y,Cr,Y */
+	SFLAG_COLORBAR             = 0x04, /* Select colorbar */
+};
+
+#define PROGRAM_ROM     0x0000
+#define PROGRAM_SRAM    0x1000
+#define PERIPHERALS0    0x8000
+#define PERIPHERALS1    0x9000
+#define SHARED_BUFFER   0xC000
+
+#define HOST_TO_NGENE    (SHARED_BUFFER+0x0000)
+#define NGENE_TO_HOST    (SHARED_BUFFER+0x0100)
+#define NGENE_COMMAND    (SHARED_BUFFER+0x0200)
+#define NGENE_COMMAND_HI (SHARED_BUFFER+0x0204)
+#define NGENE_STATUS     (SHARED_BUFFER+0x0208)
+#define NGENE_STATUS_HI  (SHARED_BUFFER+0x020C)
+#define NGENE_EVENT      (SHARED_BUFFER+0x0210)
+#define NGENE_EVENT_HI   (SHARED_BUFFER+0x0214)
+#define VARIABLES        (SHARED_BUFFER+0x0210)
+
+#define NGENE_INT_COUNTS       (SHARED_BUFFER+0x0260)
+#define NGENE_INT_ENABLE       (SHARED_BUFFER+0x0264)
+#define NGENE_VBI_LINE_COUNT   (SHARED_BUFFER+0x0268)
+
+#define BUFFER_GP_XMIT  (SHARED_BUFFER+0x0800)
+#define BUFFER_GP_RECV  (SHARED_BUFFER+0x0900)
+#define EEPROM_AREA     (SHARED_BUFFER+0x0A00)
+
+#define SG_V_IN_1       (SHARED_BUFFER+0x0A80)
+#define SG_VBI_1        (SHARED_BUFFER+0x0B00)
+#define SG_A_IN_1       (SHARED_BUFFER+0x0B80)
+#define SG_V_IN_2       (SHARED_BUFFER+0x0C00)
+#define SG_VBI_2        (SHARED_BUFFER+0x0C80)
+#define SG_A_IN_2       (SHARED_BUFFER+0x0D00)
+#define SG_V_OUT        (SHARED_BUFFER+0x0D80)
+#define SG_A_OUT2       (SHARED_BUFFER+0x0E00)
+
+#define DATA_A_IN_1     (SHARED_BUFFER+0x0E80)
+#define DATA_A_IN_2     (SHARED_BUFFER+0x0F00)
+#define DATA_A_OUT      (SHARED_BUFFER+0x0F80)
+#define DATA_V_IN_1     (SHARED_BUFFER+0x1000)
+#define DATA_V_IN_2     (SHARED_BUFFER+0x2000)
+#define DATA_V_OUT      (SHARED_BUFFER+0x3000)
+
+#define DATA_FIFO_AREA  (SHARED_BUFFER+0x1000)
+
+#define TIMESTAMPS      0xA000
+#define SCRATCHPAD      0xA080
+#define FORCE_INT       0xA088
+#define FORCE_NMI       0xA090
+#define INT_STATUS      0xA0A0
+
+#define DEV_VER         0x9004
+
+#define FW_DEBUG_DEFAULT (PROGRAM_SRAM+0x00FF)
+
+struct SG_ADDR {
+	u64 start;
+	u64 curr;
+	u16 curr_ptr;
+	u16 elements;
+	u32 pad[3];
+} __attribute__ ((__packed__));
+
+struct SHARED_MEMORY {
+	/* C000 */
+	u32 HostToNgene[64];
+
+	/* C100 */
+	u32 NgeneToHost[64];
+
+	/* C200 */
+	u64 NgeneCommand;
+	u64 NgeneStatus;
+	u64 NgeneEvent;
+
+	/* C210 */
+	u8 pad1[0xc260 - 0xc218];
+
+	/* C260 */
+	u32 IntCounts;
+	u32 IntEnable;
+
+	/* C268 */
+	u8 pad2[0xd000 - 0xc268];
+
+} __attribute__ ((__packed__));
+
+struct BUFFER_STREAM_RESULTS {
+	u32 Clock;           /* Stream time in 100ns units */
+	u16 RemainingLines;  /* Remaining lines in this field.
+				0 for complete field */
+	u8  FieldCount;      /* Video field number */
+	u8  Flags;           /* Bit 7 = Done, Bit 6 = seen, Bit 5 = overflow,
+				Bit 0 = FieldID */
+	u16 BlockCount;      /* Audio block count (unused) */
+	u8  Reserved[2];
+	u32 DTOUpdate;
+} __attribute__ ((__packed__));
+
+struct HW_SCATTER_GATHER_ELEMENT {
+	u64 Address;
+	u32 Length;
+	u32 Reserved;
+} __attribute__ ((__packed__));
+
+struct BUFFER_HEADER {
+	u64    Next;
+	struct BUFFER_STREAM_RESULTS SR;
+
+	u32    Number_of_entries_1;
+	u32    Reserved5;
+	u64    Address_of_first_entry_1;
+
+	u32    Number_of_entries_2;
+	u32    Reserved7;
+	u64    Address_of_first_entry_2;
+} __attribute__ ((__packed__));
+
+struct EVENT_BUFFER {
+	u32    TimeStamp;
+	u8     GPIOStatus;
+	u8     UARTStatus;
+	u8     RXCharacter;
+	u8     EventStatus;
+	u32    Reserved[2];
+} __attribute__ ((__packed__));
+
+/* Firmware commands. */
+
+enum OPCODES {
+	CMD_NOP = 0,
+	CMD_FWLOAD_PREPARE  = 0x01,
+	CMD_FWLOAD_FINISH   = 0x02,
+	CMD_I2C_READ        = 0x03,
+	CMD_I2C_WRITE       = 0x04,
+
+	CMD_I2C_WRITE_NOSTOP = 0x05,
+	CMD_I2C_CONTINUE_WRITE = 0x06,
+	CMD_I2C_CONTINUE_WRITE_NOSTOP = 0x07,
+
+	CMD_DEBUG_OUTPUT    = 0x09,
+
+	CMD_CONTROL         = 0x10,
+	CMD_CONFIGURE_BUFFER = 0x11,
+	CMD_CONFIGURE_FREE_BUFFER = 0x12,
+
+	CMD_SPI_READ        = 0x13,
+	CMD_SPI_WRITE       = 0x14,
+
+	CMD_MEM_READ        = 0x20,
+	CMD_MEM_WRITE	    = 0x21,
+	CMD_SFR_READ	    = 0x22,
+	CMD_SFR_WRITE	    = 0x23,
+	CMD_IRAM_READ	    = 0x24,
+	CMD_IRAM_WRITE	    = 0x25,
+	CMD_SET_GPIO_PIN    = 0x26,
+	CMD_SET_GPIO_INT    = 0x27,
+	CMD_CONFIGURE_UART  = 0x28,
+	CMD_WRITE_UART      = 0x29,
+	MAX_CMD
+};
+
+enum RESPONSES {
+	OK = 0,
+	ERROR = 1
+};
+
+struct FW_HEADER {
+	u8 Opcode;
+	u8 Length;
+} __attribute__ ((__packed__));
+
+struct FW_I2C_WRITE {
+	struct FW_HEADER hdr;
+	u8 Device;
+	u8 Data[250];
+} __attribute__ ((__packed__));
+
+struct FW_I2C_CONTINUE_WRITE {
+	struct FW_HEADER hdr;
+	u8 Data[250];
+} __attribute__ ((__packed__));
+
+struct FW_I2C_READ {
+	struct FW_HEADER hdr;
+	u8 Device;
+	u8 Data[252];    /* followed by two bytes of read data count */
+} __attribute__ ((__packed__));
+
+struct FW_SPI_WRITE {
+	struct FW_HEADER hdr;
+	u8 ModeSelect;
+	u8 Data[250];
+} __attribute__ ((__packed__));
+
+struct FW_SPI_READ {
+	struct FW_HEADER hdr;
+	u8 ModeSelect;
+	u8 Data[252];    /* followed by two bytes of read data count */
+} __attribute__ ((__packed__));
+
+struct FW_FWLOAD_PREPARE {
+	struct FW_HEADER hdr;
+} __attribute__ ((__packed__));
+
+struct FW_FWLOAD_FINISH {
+	struct FW_HEADER hdr;
+	u16 Address;     /* address of final block */
+	u16 Length;
+} __attribute__ ((__packed__));
+
+/*
+ * Meaning of FW_STREAM_CONTROL::Mode bits:
+ *  Bit 7: Loopback PEXin to PEXout using TVOut channel
+ *  Bit 6: AVLOOP
+ *  Bit 5: Audio select; 0=I2S, 1=SPDIF
+ *  Bit 4: AVSYNC
+ *  Bit 3: Enable transport stream
+ *  Bit 2: Enable audio capture
+ *  Bit 1: Enable ITU-Video VBI capture
+ *  Bit 0: Enable ITU-Video capture
+ *
+ * Meaning of FW_STREAM_CONTROL::Control bits (see UVI1_CTL)
+ *  Bit 7: continuous capture
+ *  Bit 6: capture one field
+ *  Bit 5: capture one frame
+ *  Bit 4: unused
+ *  Bit 3: starting field; 0=odd, 1=even
+ *  Bit 2: sample size; 0=8-bit, 1=10-bit
+ *  Bit 1: data format; 0=UYVY, 1=YUY2
+ *  Bit 0: resets buffer pointers
+*/
+
+enum FSC_MODE_BITS {
+	SMODE_LOOPBACK          = 0x80,
+	SMODE_AVLOOP            = 0x40,
+	_SMODE_AUDIO_SPDIF      = 0x20,
+	_SMODE_AVSYNC           = 0x10,
+	_SMODE_TRANSPORT_STREAM = 0x08,
+	_SMODE_AUDIO_CAPTURE    = 0x04,
+	_SMODE_VBI_CAPTURE      = 0x02,
+	_SMODE_VIDEO_CAPTURE    = 0x01
+};
+
+
+/* Meaning of FW_STREAM_CONTROL::Stream bits:
+ * Bit 3: Audio sample count:  0 = relative, 1 = absolute
+ * Bit 2: color bar select; 1=color bars, 0=CV3 decoder
+ * Bits 1-0: stream select, UVI1, UVI2, TVOUT
+ */
+
+struct FW_STREAM_CONTROL {
+	struct FW_HEADER hdr;
+	u8     Stream;             /* Stream number (UVI1, UVI2, TVOUT) */
+	u8     Control;            /* Value written to UVI1_CTL */
+	u8     Mode;               /* Controls clock source */
+	u8     SetupDataLen;	   /* Length of setup data, MSB=1 write
+				      backwards */
+	u16    CaptureBlockCount;  /* Blocks (a 256 Bytes) to capture per buffer
+				      for TS and Audio */
+	u64    Buffer_Address;	   /* Address of first buffer header */
+	u16    BytesPerVideoLine;
+	u16    MaxLinesPerField;
+	u16    MinLinesPerField;
+	u16    Reserved_1;
+	u16    BytesPerVBILine;
+	u16    MaxVBILinesPerField;
+	u16    MinVBILinesPerField;
+	u16    SetupDataAddr;      /* ngene relative address of setup data */
+	u8     SetupData[32];      /* setup data */
+} __attribute__((__packed__));
+
+#define AUDIO_BLOCK_SIZE    256
+#define TS_BLOCK_SIZE       256
+
+struct FW_MEM_READ {
+	struct FW_HEADER hdr;
+	u16   address;
+} __attribute__ ((__packed__));
+
+struct FW_MEM_WRITE {
+	struct FW_HEADER hdr;
+	u16   address;
+	u8    data;
+} __attribute__ ((__packed__));
+
+struct FW_SFR_IRAM_READ {
+	struct FW_HEADER hdr;
+	u8    address;
+} __attribute__ ((__packed__));
+
+struct FW_SFR_IRAM_WRITE {
+	struct FW_HEADER hdr;
+	u8    address;
+	u8    data;
+} __attribute__ ((__packed__));
+
+struct FW_SET_GPIO_PIN {
+	struct FW_HEADER hdr;
+	u8    select;
+} __attribute__ ((__packed__));
+
+struct FW_SET_GPIO_INT {
+	struct FW_HEADER hdr;
+	u8    select;
+} __attribute__ ((__packed__));
+
+struct FW_SET_DEBUGMODE {
+	struct FW_HEADER hdr;
+	u8   debug_flags;
+} __attribute__ ((__packed__));
+
+struct FW_CONFIGURE_BUFFERS {
+	struct FW_HEADER hdr;
+	u8   config;
+} __attribute__ ((__packed__));
+
+enum _BUFFER_CONFIGS {
+	/* 4k UVI1, 4k UVI2, 2k AUD1, 2k AUD2  (standard usage) */
+	BUFFER_CONFIG_4422 = 0,
+	/* 3k UVI1, 3k UVI2, 3k AUD1, 3k AUD2  (4x TS input usage) */
+	BUFFER_CONFIG_3333 = 1,
+	/* 8k UVI1, 0k UVI2, 2k AUD1, 2k I2SOut  (HDTV decoder usage) */
+	BUFFER_CONFIG_8022 = 2,
+	BUFFER_CONFIG_FW17 = 255, /* Use new FW 17 command */
+};
+
+struct FW_CONFIGURE_FREE_BUFFERS {
+	struct FW_HEADER hdr;
+	u8   UVI1_BufferLength;
+	u8   UVI2_BufferLength;
+	u8   TVO_BufferLength;
+	u8   AUD1_BufferLength;
+	u8   AUD2_BufferLength;
+	u8   TVA_BufferLength;
+} __attribute__ ((__packed__));
+
+struct FW_CONFIGURE_UART {
+	struct FW_HEADER hdr;
+	u8 UartControl;
+} __attribute__ ((__packed__));
+
+enum _UART_CONFIG {
+	_UART_BAUDRATE_19200 = 0,
+	_UART_BAUDRATE_9600  = 1,
+	_UART_BAUDRATE_4800  = 2,
+	_UART_BAUDRATE_2400  = 3,
+	_UART_RX_ENABLE      = 0x40,
+	_UART_TX_ENABLE      = 0x80,
+};
+
+struct FW_WRITE_UART {
+	struct FW_HEADER hdr;
+	u8 Data[252];
+} __attribute__ ((__packed__));
+
+
+struct ngene_command {
+	u32 in_len;
+	u32 out_len;
+	union {
+		u32                              raw[64];
+		u8                               raw8[256];
+		struct FW_HEADER                 hdr;
+		struct FW_I2C_WRITE              I2CWrite;
+		struct FW_I2C_CONTINUE_WRITE     I2CContinueWrite;
+		struct FW_I2C_READ               I2CRead;
+		struct FW_STREAM_CONTROL         StreamControl;
+		struct FW_FWLOAD_PREPARE         FWLoadPrepare;
+		struct FW_FWLOAD_FINISH          FWLoadFinish;
+		struct FW_MEM_READ		 MemoryRead;
+		struct FW_MEM_WRITE		 MemoryWrite;
+		struct FW_SFR_IRAM_READ		 SfrIramRead;
+		struct FW_SFR_IRAM_WRITE         SfrIramWrite;
+		struct FW_SPI_WRITE              SPIWrite;
+		struct FW_SPI_READ               SPIRead;
+		struct FW_SET_GPIO_PIN           SetGpioPin;
+		struct FW_SET_GPIO_INT           SetGpioInt;
+		struct FW_SET_DEBUGMODE          SetDebugMode;
+		struct FW_CONFIGURE_BUFFERS      ConfigureBuffers;
+		struct FW_CONFIGURE_FREE_BUFFERS ConfigureFreeBuffers;
+		struct FW_CONFIGURE_UART         ConfigureUart;
+		struct FW_WRITE_UART             WriteUart;
+	} cmd;
+} __attribute__ ((__packed__));
+
+#define NGENE_INTERFACE_VERSION 0x103
+#define MAX_VIDEO_BUFFER_SIZE   (417792) /* 288*1440 rounded up to next page */
+#define MAX_AUDIO_BUFFER_SIZE     (8192) /* Gives room for about 23msec@48KHz */
+#define MAX_VBI_BUFFER_SIZE      (28672) /* 1144*18 rounded up to next page */
+#define MAX_TS_BUFFER_SIZE       (98304) /* 512*188 rounded up to next page */
+#define MAX_HDTV_BUFFER_SIZE   (2080768) /* 541*1920*2 rounded up to next page
+					    Max: (1920x1080i60) */
+
+#define OVERFLOW_BUFFER_SIZE    (8192)
+
+#define RING_SIZE_VIDEO     4
+#define RING_SIZE_AUDIO     8
+#define RING_SIZE_TS        8
+
+#define NUM_SCATTER_GATHER_ENTRIES  8
+
+#define MAX_DMA_LENGTH (((MAX_VIDEO_BUFFER_SIZE + MAX_VBI_BUFFER_SIZE) * \
+			RING_SIZE_VIDEO * 2) + \
+			(MAX_AUDIO_BUFFER_SIZE * RING_SIZE_AUDIO * 2) + \
+			(MAX_TS_BUFFER_SIZE * RING_SIZE_TS * 4) + \
+			(RING_SIZE_VIDEO * PAGE_SIZE * 2) + \
+			(RING_SIZE_AUDIO * PAGE_SIZE * 2) + \
+			(RING_SIZE_TS    * PAGE_SIZE * 4) + \
+			 8 * PAGE_SIZE + OVERFLOW_BUFFER_SIZE + PAGE_SIZE)
+
+#define EVENT_QUEUE_SIZE    16
+
+/* Gathers the current state of a single channel. */
+
+struct SBufferHeader {
+	struct BUFFER_HEADER   ngeneBuffer; /* Physical descriptor */
+	struct SBufferHeader  *Next;
+	void                  *Buffer1;
+	struct HW_SCATTER_GATHER_ELEMENT *scList1;
+	void                  *Buffer2;
+	struct HW_SCATTER_GATHER_ELEMENT *scList2;
+};
+
+/* Sizeof SBufferHeader aligned to next 64 Bit boundary (hw restriction) */
+#define SIZEOF_SBufferHeader ((sizeof(struct SBufferHeader) + 63) & ~63)
+
+enum HWSTATE {
+	HWSTATE_STOP,
+	HWSTATE_STARTUP,
+	HWSTATE_RUN,
+	HWSTATE_PAUSE,
+};
+
+enum KSSTATE {
+	KSSTATE_STOP,
+	KSSTATE_ACQUIRE,
+	KSSTATE_PAUSE,
+	KSSTATE_RUN,
+};
+
+struct SRingBufferDescriptor {
+	struct SBufferHeader *Head; /* Points to first buffer in ring buffer
+				       structure*/
+	u64   PAHead;         /* Physical address of first buffer */
+	u32   MemSize;        /* Memory size of allocated ring buffers
+				 (needed for freeing) */
+	u32   NumBuffers;     /* Number of buffers in the ring */
+	u32   Buffer1Length;  /* Allocated length of Buffer 1 */
+	u32   Buffer2Length;  /* Allocated length of Buffer 2 */
+	void *SCListMem;      /* Memory to hold scatter gather lists for this
+				 ring */
+	u64   PASCListMem;    /* Physical address  .. */
+	u32   SCListMemSize;  /* Size of this memory */
+};
+
+enum STREAMMODEFLAGS {
+	StreamMode_NONE   = 0, /* Stream not used */
+	StreamMode_ANALOG = 1, /* Analog: Stream 0,1 = Video, 2,3 = Audio */
+	StreamMode_TSIN   = 2, /* Transport stream input (all) */
+	StreamMode_HDTV   = 4, /* HDTV: Maximum 1920x1080p30,1920x1080i60
+				  (only stream 0) */
+	StreamMode_TSOUT  = 8, /* Transport stream output (only stream 3) */
+};
+
+
+enum BufferExchangeFlags {
+	BEF_EVEN_FIELD   = 0x00000001,
+	BEF_CONTINUATION = 0x00000002,
+	BEF_MORE_DATA    = 0x00000004,
+	BEF_OVERFLOW     = 0x00000008,
+	DF_SWAP32        = 0x00010000,
+};
+
+typedef void *(IBufferExchange)(void *, void *, u32, u32, u32);
+
+struct MICI_STREAMINFO {
+	IBufferExchange    *pExchange;
+	IBufferExchange    *pExchangeVBI;     /* Secondary (VBI, ancillary) */
+	u8  Stream;
+	u8  Flags;
+	u8  Mode;
+	u8  Reserved;
+	u16 nLinesVideo;
+	u16 nBytesPerLineVideo;
+	u16 nLinesVBI;
+	u16 nBytesPerLineVBI;
+	u32 CaptureLength;    /* Used for audio and transport stream */
+};
+
+/****************************************************************************/
+/* STRUCTS ******************************************************************/
+/****************************************************************************/
+
+/* sound hardware definition */
+#define MIXER_ADDR_TVTUNER      0
+#define MIXER_ADDR_LAST         0
+
+struct ngene_channel;
+
+/*struct sound chip*/
+
+struct mychip {
+	struct ngene_channel *chan;
+	struct snd_card *card;
+	struct pci_dev *pci;
+	struct snd_pcm_substream *substream;
+	struct snd_pcm *pcm;
+	unsigned long port;
+	int irq;
+	spinlock_t mixer_lock;
+	spinlock_t lock;
+	int mixer_volume[MIXER_ADDR_LAST + 1][2];
+	int capture_source[MIXER_ADDR_LAST + 1][2];
+};
+
+#ifdef NGENE_V4L
+struct ngene_overlay {
+	int                    tvnorm;
+	struct v4l2_rect       w;
+	enum v4l2_field        field;
+	struct v4l2_clip       *clips;
+	int                    nclips;
+	int                    setup_ok;
+};
+
+struct ngene_tvnorm {
+	int   v4l2_id;
+	char  *name;
+	u16   swidth, sheight; /* scaled standard width, height */
+	int   tuner_norm;
+	int   soundstd;
+};
+
+struct ngene_vopen {
+	struct ngene_channel      *ch;
+	enum v4l2_priority         prio;
+	int                        width;
+	int                        height;
+	int                        depth;
+	struct videobuf_queue      vbuf_q;
+	struct videobuf_queue      vbi;
+	int                        fourcc;
+	int                        picxcount;
+	int                        resources;
+	enum v4l2_buf_type         type;
+	const struct ngene_format *fmt;
+
+	const struct ngene_format *ovfmt;
+	struct ngene_overlay       ov;
+};
+#endif
+
+struct ngene_channel {
+	struct device         device;
+	struct i2c_adapter    i2c_adapter;
+
+	struct ngene         *dev;
+	int                   number;
+	int                   type;
+	int                   mode;
+	bool                  has_adapter;
+	bool                  has_demux;
+	int                   demod_type;
+	int (*gate_ctrl)(struct dvb_frontend *, int);
+
+	struct dvb_frontend  *fe;
+	struct dvb_frontend  *fe2;
+	struct dmxdev         dmxdev;
+	struct dvb_demux      demux;
+	struct dvb_net        dvbnet;
+	struct dmx_frontend   hw_frontend;
+	struct dmx_frontend   mem_frontend;
+	int                   users;
+	struct video_device  *v4l_dev;
+	struct dvb_device    *ci_dev;
+	struct tasklet_struct demux_tasklet;
+
+	struct SBufferHeader *nextBuffer;
+	enum KSSTATE          State;
+	enum HWSTATE          HWState;
+	u8                    Stream;
+	u8                    Flags;
+	u8                    Mode;
+	IBufferExchange      *pBufferExchange;
+	IBufferExchange      *pBufferExchange2;
+
+	spinlock_t            state_lock;
+	u16                   nLines;
+	u16                   nBytesPerLine;
+	u16                   nVBILines;
+	u16                   nBytesPerVBILine;
+	u16                   itumode;
+	u32                   Capture1Length;
+	u32                   Capture2Length;
+	struct SRingBufferDescriptor RingBuffer;
+	struct SRingBufferDescriptor TSRingBuffer;
+	struct SRingBufferDescriptor TSIdleBuffer;
+
+	u32                   DataFormatFlags;
+
+	int                   AudioDTOUpdated;
+	u32                   AudioDTOValue;
+
+	int (*set_tone)(struct dvb_frontend *, fe_sec_tone_mode_t);
+	u8 lnbh;
+
+	/* stuff from analog driver */
+
+	int minor;
+	struct mychip        *mychip;
+	struct snd_card      *soundcard;
+	u8                   *evenbuffer;
+	u8                    dma_on;
+	int                   soundstreamon;
+	int                   audiomute;
+	int                   soundbuffisallocated;
+	int                   sndbuffflag;
+	int                   tun_rdy;
+	int                   dec_rdy;
+	int                   tun_dec_rdy;
+	int                   lastbufferflag;
+
+	struct ngene_tvnorm  *tvnorms;
+	int                   tvnorm_num;
+	int                   tvnorm;
+
+#ifdef NGENE_V4L
+	int                   videousers;
+	struct v4l2_prio_state prio;
+	struct ngene_vopen    init;
+	int                   resources;
+	struct v4l2_framebuffer fbuf;
+	struct ngene_buffer  *screen;     /* overlay             */
+	struct list_head      capture;    /* video capture queue */
+	spinlock_t s_lock;
+	struct semaphore reslock;
+#endif
+
+	int running;
+};
+
+
+struct ngene_ci {
+	struct device         device;
+	struct i2c_adapter    i2c_adapter;
+
+	struct ngene         *dev;
+	struct dvb_ca_en50221 *en;
+};
+
+struct ngene;
+
+typedef void (rx_cb_t)(struct ngene *, u32, u8);
+typedef void (tx_cb_t)(struct ngene *, u32);
+
+struct ngene {
+	int                   nr;
+	struct pci_dev       *pci_dev;
+	unsigned char        *iomem;
+
+	/*struct i2c_adapter  i2c_adapter;*/
+
+	u32                   device_version;
+	u32                   fw_interface_version;
+	u32                   icounts;
+	bool                  msi_enabled;
+	bool                  cmd_timeout_workaround;
+
+	u8                   *CmdDoneByte;
+	int                   BootFirmware;
+	void                 *OverflowBuffer;
+	dma_addr_t            PAOverflowBuffer;
+	void                 *FWInterfaceBuffer;
+	dma_addr_t            PAFWInterfaceBuffer;
+	u8                   *ngenetohost;
+	u8                   *hosttongene;
+
+	struct EVENT_BUFFER   EventQueue[EVENT_QUEUE_SIZE];
+	int                   EventQueueOverflowCount;
+	int                   EventQueueOverflowFlag;
+	struct tasklet_struct event_tasklet;
+	struct EVENT_BUFFER  *EventBuffer;
+	int                   EventQueueWriteIndex;
+	int                   EventQueueReadIndex;
+
+	wait_queue_head_t     cmd_wq;
+	int                   cmd_done;
+	struct semaphore      cmd_mutex;
+	struct semaphore      stream_mutex;
+	struct semaphore      pll_mutex;
+	struct semaphore      i2c_switch_mutex;
+	int                   i2c_current_channel;
+	int                   i2c_current_bus;
+	spinlock_t            cmd_lock;
+
+	struct dvb_adapter    adapter[MAX_STREAM];
+	struct dvb_adapter    *first_adapter; /* "one_adapter" modprobe opt */
+	struct ngene_channel  channel[MAX_STREAM];
+
+	struct ngene_info    *card_info;
+
+	tx_cb_t              *TxEventNotify;
+	rx_cb_t              *RxEventNotify;
+	int                   tx_busy;
+	wait_queue_head_t     tx_wq;
+	wait_queue_head_t     rx_wq;
+#define UART_RBUF_LEN 4096
+	u8                    uart_rbuf[UART_RBUF_LEN];
+	int                   uart_rp, uart_wp;
+
+#define TS_FILLER  0x6f
+
+	u8                   *tsout_buf;
+#define TSOUT_BUF_SIZE (512*188*8)
+	struct dvb_ringbuffer tsout_rbuf;
+
+	u8                   *tsin_buf;
+#define TSIN_BUF_SIZE (512*188*8)
+	struct dvb_ringbuffer tsin_rbuf;
+
+	u8                   *ain_buf;
+#define AIN_BUF_SIZE (128*1024)
+	struct dvb_ringbuffer ain_rbuf;
+
+
+	u8                   *vin_buf;
+#define VIN_BUF_SIZE (4*1920*1080)
+	struct dvb_ringbuffer vin_rbuf;
+
+	unsigned long         exp_val;
+	int prev_cmd;
+
+	struct ngene_ci       ci;
+};
+
+struct ngene_info {
+	int   type;
+#define NGENE_APP        0
+#define NGENE_TERRATEC   1
+#define NGENE_SIDEWINDER 2
+#define NGENE_RACER      3
+#define NGENE_VIPER      4
+#define NGENE_PYTHON     5
+#define NGENE_VBOX_V1	 6
+#define NGENE_VBOX_V2	 7
+
+	int   fw_version;
+	bool  msi_supported;
+	char *name;
+
+	int   io_type[MAX_STREAM];
+#define NGENE_IO_NONE    0
+#define NGENE_IO_TV      1
+#define NGENE_IO_HDTV    2
+#define NGENE_IO_TSIN    4
+#define NGENE_IO_TSOUT   8
+#define NGENE_IO_AIN     16
+
+	void *fe_config[4];
+	void *tuner_config[4];
+
+	int (*demod_attach[4])(struct ngene_channel *);
+	int (*tuner_attach[4])(struct ngene_channel *);
+
+	u8    avf[4];
+	u8    msp[4];
+	u8    demoda[4];
+	u8    lnb[4];
+	int   i2c_access;
+	u8    ntsc;
+	u8    tsf[4];
+	u8    i2s[4];
+
+	int (*gate_ctrl)(struct dvb_frontend *, int);
+	int (*switch_ctrl)(struct ngene_channel *, int, int);
+};
+
+#ifdef NGENE_V4L
+struct ngene_format {
+	char *name;
+	int   fourcc;          /* video4linux 2      */
+	int   btformat;        /* BT848_COLOR_FMT_*  */
+	int   format;
+	int   btswap;          /* BT848_COLOR_CTL_*  */
+	int   depth;           /* bit/pixel          */
+	int   flags;
+	int   hshift, vshift;  /* for planar modes   */
+	int   palette;
+};
+
+#define RESOURCE_OVERLAY       1
+#define RESOURCE_VIDEO         2
+#define RESOURCE_VBI           4
+
+struct ngene_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer     vb;
+
+	/* ngene specific */
+	const struct ngene_format *fmt;
+	int                        tvnorm;
+	int                        btformat;
+	int                        btswap;
+};
+#endif
+
+
+/* Provided by ngene-core.c */
+int __devinit ngene_probe(struct pci_dev *pci_dev,
+			  const struct pci_device_id *id);
+void __devexit ngene_remove(struct pci_dev *pdev);
+void ngene_shutdown(struct pci_dev *pdev);
+int ngene_command(struct ngene *dev, struct ngene_command *com);
+int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level);
+void set_transfer(struct ngene_channel *chan, int state);
+void FillTSBuffer(void *Buffer, int Length, u32 Flags);
+
+/* Provided by ngene-i2c.c */
+int ngene_i2c_init(struct ngene *dev, int dev_nr);
+
+/* Provided by ngene-dvb.c */
+extern struct dvb_device ngene_dvbdev_ci;
+void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags);
+void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags);
+int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed);
+int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed);
+int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
+			    int (*start_feed)(struct dvb_demux_feed *),
+			    int (*stop_feed)(struct dvb_demux_feed *),
+			    void *priv);
+int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
+			       struct dvb_demux *dvbdemux,
+			       struct dmx_frontend *hw_frontend,
+			       struct dmx_frontend *mem_frontend,
+			       struct dvb_adapter *dvb_adapter);
+
+#endif
+
+/*  LocalWords:  Endif
+ */
diff --git a/drivers/media/pci/pluto2/Kconfig b/drivers/media/pci/pluto2/Kconfig
new file mode 100644
index 0000000..7d8e6e8
--- /dev/null
+++ b/drivers/media/pci/pluto2/Kconfig
@@ -0,0 +1,15 @@
+config DVB_PLUTO2
+	tristate "Pluto2 cards"
+	depends on DVB_CORE && PCI && I2C
+	select I2C_ALGOBIT
+	select DVB_TDA1004X
+	help
+	  Support for PCI cards based on the Pluto2 FPGA like the Satelco
+	  Easywatch Mobile Terrestrial DVB-T Receiver.
+
+	  Since these cards have no MPEG decoder onboard, they transmit
+	  only compressed MPEG data over the PCI bus, so you need
+	  an external software decoder to watch TV on your computer.
+
+	  Say Y or M if you own such a device and want to use it.
+
diff --git a/drivers/media/pci/pluto2/Makefile b/drivers/media/pci/pluto2/Makefile
new file mode 100644
index 0000000..524bf84
--- /dev/null
+++ b/drivers/media/pci/pluto2/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DVB_PLUTO2) += pluto2.o
+
+ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/
diff --git a/drivers/media/pci/pluto2/pluto2.c b/drivers/media/pci/pluto2/pluto2.c
new file mode 100644
index 0000000..f148b19
--- /dev/null
+++ b/drivers/media/pci/pluto2/pluto2.c
@@ -0,0 +1,815 @@
+/*
+ * pluto2.c - Satelco Easywatch Mobile Terrestrial Receiver [DVB-T]
+ *
+ * Copyright (C) 2005 Andreas Oberritter <obi@linuxtv.org>
+ *
+ * based on pluto2.c 1.10 - http://instinct-wp8.no-ip.org/pluto/
+ * 	by Dany Salman <salmandany@yahoo.fr>
+ *	Copyright (c) 2004 TDF
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+#include "tda1004x.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define DRIVER_NAME		"pluto2"
+
+#define REG_PIDn(n)		((n) << 2)	/* PID n pattern registers */
+#define REG_PCAR		0x0020		/* PC address register */
+#define REG_TSCR		0x0024		/* TS ctrl & status */
+#define REG_MISC		0x0028		/* miscellaneous */
+#define REG_MMAC		0x002c		/* MSB MAC address */
+#define REG_IMAC		0x0030		/* ISB MAC address */
+#define REG_LMAC		0x0034		/* LSB MAC address */
+#define REG_SPID		0x0038		/* SPI data */
+#define REG_SLCS		0x003c		/* serial links ctrl/status */
+
+#define PID0_NOFIL		(0x0001 << 16)
+#define PIDn_ENP		(0x0001 << 15)
+#define PID0_END		(0x0001 << 14)
+#define PID0_AFIL		(0x0001 << 13)
+#define PIDn_PID		(0x1fff <<  0)
+
+#define TSCR_NBPACKETS		(0x00ff << 24)
+#define TSCR_DEM		(0x0001 << 17)
+#define TSCR_DE			(0x0001 << 16)
+#define TSCR_RSTN		(0x0001 << 15)
+#define TSCR_MSKO		(0x0001 << 14)
+#define TSCR_MSKA		(0x0001 << 13)
+#define TSCR_MSKL		(0x0001 << 12)
+#define TSCR_OVR		(0x0001 << 11)
+#define TSCR_AFUL		(0x0001 << 10)
+#define TSCR_LOCK		(0x0001 <<  9)
+#define TSCR_IACK		(0x0001 <<  8)
+#define TSCR_ADEF		(0x007f <<  0)
+
+#define MISC_DVR		(0x0fff <<  4)
+#define MISC_ALED		(0x0001 <<  3)
+#define MISC_FRST		(0x0001 <<  2)
+#define MISC_LED1		(0x0001 <<  1)
+#define MISC_LED0		(0x0001 <<  0)
+
+#define SPID_SPIDR		(0x00ff <<  0)
+
+#define SLCS_SCL		(0x0001 <<  7)
+#define SLCS_SDA		(0x0001 <<  6)
+#define SLCS_CSN		(0x0001 <<  2)
+#define SLCS_OVR		(0x0001 <<  1)
+#define SLCS_SWC		(0x0001 <<  0)
+
+#define TS_DMA_PACKETS		(8)
+#define TS_DMA_BYTES		(188 * TS_DMA_PACKETS)
+
+#define I2C_ADDR_TDA10046	0x10
+#define I2C_ADDR_TUA6034	0xc2
+#define NHWFILTERS		8
+
+struct pluto {
+	/* pci */
+	struct pci_dev *pdev;
+	u8 __iomem *io_mem;
+
+	/* dvb */
+	struct dmx_frontend hw_frontend;
+	struct dmx_frontend mem_frontend;
+	struct dmxdev dmxdev;
+	struct dvb_adapter dvb_adapter;
+	struct dvb_demux demux;
+	struct dvb_frontend *fe;
+	struct dvb_net dvbnet;
+	unsigned int full_ts_users;
+	unsigned int users;
+
+	/* i2c */
+	struct i2c_algo_bit_data i2c_bit;
+	struct i2c_adapter i2c_adap;
+	unsigned int i2cbug;
+
+	/* irq */
+	unsigned int overflow;
+	unsigned int dead;
+
+	/* dma */
+	dma_addr_t dma_addr;
+	u8 dma_buf[TS_DMA_BYTES];
+	u8 dummy[4096];
+};
+
+static inline struct pluto *feed_to_pluto(struct dvb_demux_feed *feed)
+{
+	return container_of(feed->demux, struct pluto, demux);
+}
+
+static inline struct pluto *frontend_to_pluto(struct dvb_frontend *fe)
+{
+	return container_of(fe->dvb, struct pluto, dvb_adapter);
+}
+
+static inline u32 pluto_readreg(struct pluto *pluto, u32 reg)
+{
+	return readl(&pluto->io_mem[reg]);
+}
+
+static inline void pluto_writereg(struct pluto *pluto, u32 reg, u32 val)
+{
+	writel(val, &pluto->io_mem[reg]);
+}
+
+static inline void pluto_rw(struct pluto *pluto, u32 reg, u32 mask, u32 bits)
+{
+	u32 val = readl(&pluto->io_mem[reg]);
+	val &= ~mask;
+	val |= bits;
+	writel(val, &pluto->io_mem[reg]);
+}
+
+static void pluto_write_tscr(struct pluto *pluto, u32 val)
+{
+	/* set the number of packets */
+	val &= ~TSCR_ADEF;
+	val |= TS_DMA_PACKETS / 2;
+
+	pluto_writereg(pluto, REG_TSCR, val);
+}
+
+static void pluto_setsda(void *data, int state)
+{
+	struct pluto *pluto = data;
+
+	if (state)
+		pluto_rw(pluto, REG_SLCS, SLCS_SDA, SLCS_SDA);
+	else
+		pluto_rw(pluto, REG_SLCS, SLCS_SDA, 0);
+}
+
+static void pluto_setscl(void *data, int state)
+{
+	struct pluto *pluto = data;
+
+	if (state)
+		pluto_rw(pluto, REG_SLCS, SLCS_SCL, SLCS_SCL);
+	else
+		pluto_rw(pluto, REG_SLCS, SLCS_SCL, 0);
+
+	/* try to detect i2c_inb() to workaround hardware bug:
+	 * reset SDA to high after SCL has been set to low */
+	if ((state) && (pluto->i2cbug == 0)) {
+		pluto->i2cbug = 1;
+	} else {
+		if ((!state) && (pluto->i2cbug == 1))
+			pluto_setsda(pluto, 1);
+		pluto->i2cbug = 0;
+	}
+}
+
+static int pluto_getsda(void *data)
+{
+	struct pluto *pluto = data;
+
+	return pluto_readreg(pluto, REG_SLCS) & SLCS_SDA;
+}
+
+static int pluto_getscl(void *data)
+{
+	struct pluto *pluto = data;
+
+	return pluto_readreg(pluto, REG_SLCS) & SLCS_SCL;
+}
+
+static void pluto_reset_frontend(struct pluto *pluto, int reenable)
+{
+	u32 val = pluto_readreg(pluto, REG_MISC);
+
+	if (val & MISC_FRST) {
+		val &= ~MISC_FRST;
+		pluto_writereg(pluto, REG_MISC, val);
+	}
+	if (reenable) {
+		val |= MISC_FRST;
+		pluto_writereg(pluto, REG_MISC, val);
+	}
+}
+
+static void pluto_reset_ts(struct pluto *pluto, int reenable)
+{
+	u32 val = pluto_readreg(pluto, REG_TSCR);
+
+	if (val & TSCR_RSTN) {
+		val &= ~TSCR_RSTN;
+		pluto_write_tscr(pluto, val);
+	}
+	if (reenable) {
+		val |= TSCR_RSTN;
+		pluto_write_tscr(pluto, val);
+	}
+}
+
+static void pluto_set_dma_addr(struct pluto *pluto)
+{
+	pluto_writereg(pluto, REG_PCAR, pluto->dma_addr);
+}
+
+static int __devinit pluto_dma_map(struct pluto *pluto)
+{
+	pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf,
+			TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+
+	return pci_dma_mapping_error(pluto->pdev, pluto->dma_addr);
+}
+
+static void pluto_dma_unmap(struct pluto *pluto)
+{
+	pci_unmap_single(pluto->pdev, pluto->dma_addr,
+			TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+}
+
+static int pluto_start_feed(struct dvb_demux_feed *f)
+{
+	struct pluto *pluto = feed_to_pluto(f);
+
+	/* enable PID filtering */
+	if (pluto->users++ == 0)
+		pluto_rw(pluto, REG_PIDn(0), PID0_AFIL | PID0_NOFIL, 0);
+
+	if ((f->pid < 0x2000) && (f->index < NHWFILTERS))
+		pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, PIDn_ENP | f->pid);
+	else if (pluto->full_ts_users++ == 0)
+		pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, PID0_NOFIL);
+
+	return 0;
+}
+
+static int pluto_stop_feed(struct dvb_demux_feed *f)
+{
+	struct pluto *pluto = feed_to_pluto(f);
+
+	/* disable PID filtering */
+	if (--pluto->users == 0)
+		pluto_rw(pluto, REG_PIDn(0), PID0_AFIL, PID0_AFIL);
+
+	if ((f->pid < 0x2000) && (f->index < NHWFILTERS))
+		pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, 0x1fff);
+	else if (--pluto->full_ts_users == 0)
+		pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, 0);
+
+	return 0;
+}
+
+static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets)
+{
+	/* synchronize the DMA transfer with the CPU
+	 * first so that we see updated contents. */
+	pci_dma_sync_single_for_cpu(pluto->pdev, pluto->dma_addr,
+			TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+
+	/* Workaround for broken hardware:
+	 * [1] On startup NBPACKETS seems to contain an uninitialized value,
+	 *     but no packets have been transferred.
+	 * [2] Sometimes (actually very often) NBPACKETS stays at zero
+	 *     although one packet has been transferred.
+	 * [3] Sometimes (actually rarely), the card gets into an erroneous
+	 *     mode where it continuously generates interrupts, claiming it
+	 *     has received nbpackets>TS_DMA_PACKETS packets, but no packet
+	 *     has been transferred. Only a reset seems to solve this
+	 */
+	if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) {
+		unsigned int i = 0;
+		while (pluto->dma_buf[i] == 0x47)
+			i += 188;
+		nbpackets = i / 188;
+		if (i == 0) {
+			pluto_reset_ts(pluto, 1);
+			dev_printk(KERN_DEBUG, &pluto->pdev->dev, "resetting TS because of invalid packet counter\n");
+		}
+	}
+
+	dvb_dmx_swfilter_packets(&pluto->demux, pluto->dma_buf, nbpackets);
+
+	/* clear the dma buffer. this is needed to be able to identify
+	 * new valid ts packets above */
+	memset(pluto->dma_buf, 0, nbpackets * 188);
+
+	/* reset the dma address */
+	pluto_set_dma_addr(pluto);
+
+	/* sync the buffer and give it back to the card */
+	pci_dma_sync_single_for_device(pluto->pdev, pluto->dma_addr,
+			TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+}
+
+static irqreturn_t pluto_irq(int irq, void *dev_id)
+{
+	struct pluto *pluto = dev_id;
+	u32 tscr;
+
+	/* check whether an interrupt occurred on this device */
+	tscr = pluto_readreg(pluto, REG_TSCR);
+	if (!(tscr & (TSCR_DE | TSCR_OVR)))
+		return IRQ_NONE;
+
+	if (tscr == 0xffffffff) {
+		if (pluto->dead == 0)
+			dev_err(&pluto->pdev->dev, "card has hung or been ejected.\n");
+		/* It's dead Jim */
+		pluto->dead = 1;
+		return IRQ_HANDLED;
+	}
+
+	/* dma end interrupt */
+	if (tscr & TSCR_DE) {
+		pluto_dma_end(pluto, (tscr & TSCR_NBPACKETS) >> 24);
+		/* overflow interrupt */
+		if (tscr & TSCR_OVR)
+			pluto->overflow++;
+		if (pluto->overflow) {
+			dev_err(&pluto->pdev->dev, "overflow irq (%d)\n",
+					pluto->overflow);
+			pluto_reset_ts(pluto, 1);
+			pluto->overflow = 0;
+		}
+	} else if (tscr & TSCR_OVR) {
+		pluto->overflow++;
+	}
+
+	/* ACK the interrupt */
+	pluto_write_tscr(pluto, tscr | TSCR_IACK);
+
+	return IRQ_HANDLED;
+}
+
+static void __devinit pluto_enable_irqs(struct pluto *pluto)
+{
+	u32 val = pluto_readreg(pluto, REG_TSCR);
+
+	/* disable AFUL and LOCK interrupts */
+	val |= (TSCR_MSKA | TSCR_MSKL);
+	/* enable DMA and OVERFLOW interrupts */
+	val &= ~(TSCR_DEM | TSCR_MSKO);
+	/* clear pending interrupts */
+	val |= TSCR_IACK;
+
+	pluto_write_tscr(pluto, val);
+}
+
+static void pluto_disable_irqs(struct pluto *pluto)
+{
+	u32 val = pluto_readreg(pluto, REG_TSCR);
+
+	/* disable all interrupts */
+	val |= (TSCR_DEM | TSCR_MSKO | TSCR_MSKA | TSCR_MSKL);
+	/* clear pending interrupts */
+	val |= TSCR_IACK;
+
+	pluto_write_tscr(pluto, val);
+}
+
+static int __devinit pluto_hw_init(struct pluto *pluto)
+{
+	pluto_reset_frontend(pluto, 1);
+
+	/* set automatic LED control by FPGA */
+	pluto_rw(pluto, REG_MISC, MISC_ALED, MISC_ALED);
+
+	/* set data endianess */
+#ifdef __LITTLE_ENDIAN
+	pluto_rw(pluto, REG_PIDn(0), PID0_END, PID0_END);
+#else
+	pluto_rw(pluto, REG_PIDn(0), PID0_END, 0);
+#endif
+	/* map DMA and set address */
+	pluto_dma_map(pluto);
+	pluto_set_dma_addr(pluto);
+
+	/* enable interrupts */
+	pluto_enable_irqs(pluto);
+
+	/* reset TS logic */
+	pluto_reset_ts(pluto, 1);
+
+	return 0;
+}
+
+static void pluto_hw_exit(struct pluto *pluto)
+{
+	/* disable interrupts */
+	pluto_disable_irqs(pluto);
+
+	pluto_reset_ts(pluto, 0);
+
+	/* LED: disable automatic control, enable yellow, disable green */
+	pluto_rw(pluto, REG_MISC, MISC_ALED | MISC_LED1 | MISC_LED0, MISC_LED1);
+
+	/* unmap DMA */
+	pluto_dma_unmap(pluto);
+
+	pluto_reset_frontend(pluto, 0);
+}
+
+static inline u32 divide(u32 numerator, u32 denominator)
+{
+	if (denominator == 0)
+		return ~0;
+
+	return DIV_ROUND_CLOSEST(numerator, denominator);
+}
+
+/* LG Innotek TDTE-E001P (Infineon TUA6034) */
+static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct pluto *pluto = frontend_to_pluto(fe);
+	struct i2c_msg msg;
+	int ret;
+	u8 buf[4];
+	u32 div;
+
+	// Fref = 166.667 Hz
+	// Fref * 3 = 500.000 Hz
+	// IF = 36166667
+	// IF / Fref = 217
+	//div = divide(p->frequency + 36166667, 166667);
+	div = divide(p->frequency * 3, 500000) + 217;
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = (div >> 0) & 0xff;
+
+	if (p->frequency < 611000000)
+		buf[2] = 0xb4;
+	else if (p->frequency < 811000000)
+		buf[2] = 0xbc;
+	else
+		buf[2] = 0xf4;
+
+	// VHF: 174-230 MHz
+	// center: 350 MHz
+	// UHF: 470-862 MHz
+	if (p->frequency < 350000000)
+		buf[3] = 0x02;
+	else
+		buf[3] = 0x04;
+
+	if (p->bandwidth_hz == 8000000)
+		buf[3] |= 0x08;
+
+	msg.addr = I2C_ADDR_TUA6034 >> 1;
+	msg.flags = 0;
+	msg.buf = buf;
+	msg.len = sizeof(buf);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	ret = i2c_transfer(&pluto->i2c_adap, &msg, 1);
+	if (ret < 0)
+		return ret;
+	else if (ret == 0)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int pluto2_request_firmware(struct dvb_frontend *fe,
+				   const struct firmware **fw, char *name)
+{
+	struct pluto *pluto = frontend_to_pluto(fe);
+
+	return request_firmware(fw, name, &pluto->pdev->dev);
+}
+
+static struct tda1004x_config pluto2_fe_config __devinitdata = {
+	.demod_address = I2C_ADDR_TDA10046 >> 1,
+	.invert = 1,
+	.invert_oclk = 0,
+	.xtal_freq = TDA10046_XTAL_16M,
+	.agc_config = TDA10046_AGC_DEFAULT,
+	.if_freq = TDA10046_FREQ_3617,
+	.request_firmware = pluto2_request_firmware,
+};
+
+static int __devinit frontend_init(struct pluto *pluto)
+{
+	int ret;
+
+	pluto->fe = tda10046_attach(&pluto2_fe_config, &pluto->i2c_adap);
+	if (!pluto->fe) {
+		dev_err(&pluto->pdev->dev, "could not attach frontend\n");
+		return -ENODEV;
+	}
+	pluto->fe->ops.tuner_ops.set_params = lg_tdtpe001p_tuner_set_params;
+
+	ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe);
+	if (ret < 0) {
+		if (pluto->fe->ops.release)
+			pluto->fe->ops.release(pluto->fe);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __devinit pluto_read_rev(struct pluto *pluto)
+{
+	u32 val = pluto_readreg(pluto, REG_MISC) & MISC_DVR;
+	dev_info(&pluto->pdev->dev, "board revision %d.%d\n",
+			(val >> 12) & 0x0f, (val >> 4) & 0xff);
+}
+
+static void __devinit pluto_read_mac(struct pluto *pluto, u8 *mac)
+{
+	u32 val = pluto_readreg(pluto, REG_MMAC);
+	mac[0] = (val >> 8) & 0xff;
+	mac[1] = (val >> 0) & 0xff;
+
+	val = pluto_readreg(pluto, REG_IMAC);
+	mac[2] = (val >> 8) & 0xff;
+	mac[3] = (val >> 0) & 0xff;
+
+	val = pluto_readreg(pluto, REG_LMAC);
+	mac[4] = (val >> 8) & 0xff;
+	mac[5] = (val >> 0) & 0xff;
+
+	dev_info(&pluto->pdev->dev, "MAC %pM\n", mac);
+}
+
+static int __devinit pluto_read_serial(struct pluto *pluto)
+{
+	struct pci_dev *pdev = pluto->pdev;
+	unsigned int i, j;
+	u8 __iomem *cis;
+
+	cis = pci_iomap(pdev, 1, 0);
+	if (!cis)
+		return -EIO;
+
+	dev_info(&pdev->dev, "S/N ");
+
+	for (i = 0xe0; i < 0x100; i += 4) {
+		u32 val = readl(&cis[i]);
+		for (j = 0; j < 32; j += 8) {
+			if ((val & 0xff) == 0xff)
+				goto out;
+			printk("%c", val & 0xff);
+			val >>= 8;
+		}
+	}
+out:
+	printk("\n");
+	pci_iounmap(pdev, cis);
+
+	return 0;
+}
+
+static int __devinit pluto2_probe(struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+	struct pluto *pluto;
+	struct dvb_adapter *dvb_adapter;
+	struct dvb_demux *dvbdemux;
+	struct dmx_demux *dmx;
+	int ret = -ENOMEM;
+
+	pluto = kzalloc(sizeof(struct pluto), GFP_KERNEL);
+	if (!pluto)
+		goto out;
+
+	pluto->pdev = pdev;
+
+	ret = pci_enable_device(pdev);
+	if (ret < 0)
+		goto err_kfree;
+
+	/* enable interrupts */
+	pci_write_config_dword(pdev, 0x6c, 0x8000);
+
+	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+	if (ret < 0)
+		goto err_pci_disable_device;
+
+	pci_set_master(pdev);
+
+	ret = pci_request_regions(pdev, DRIVER_NAME);
+	if (ret < 0)
+		goto err_pci_disable_device;
+
+	pluto->io_mem = pci_iomap(pdev, 0, 0x40);
+	if (!pluto->io_mem) {
+		ret = -EIO;
+		goto err_pci_release_regions;
+	}
+
+	pci_set_drvdata(pdev, pluto);
+
+	ret = request_irq(pdev->irq, pluto_irq, IRQF_SHARED, DRIVER_NAME, pluto);
+	if (ret < 0)
+		goto err_pci_iounmap;
+
+	ret = pluto_hw_init(pluto);
+	if (ret < 0)
+		goto err_free_irq;
+
+	/* i2c */
+	i2c_set_adapdata(&pluto->i2c_adap, pluto);
+	strcpy(pluto->i2c_adap.name, DRIVER_NAME);
+	pluto->i2c_adap.owner = THIS_MODULE;
+	pluto->i2c_adap.dev.parent = &pdev->dev;
+	pluto->i2c_adap.algo_data = &pluto->i2c_bit;
+	pluto->i2c_bit.data = pluto;
+	pluto->i2c_bit.setsda = pluto_setsda;
+	pluto->i2c_bit.setscl = pluto_setscl;
+	pluto->i2c_bit.getsda = pluto_getsda;
+	pluto->i2c_bit.getscl = pluto_getscl;
+	pluto->i2c_bit.udelay = 10;
+	pluto->i2c_bit.timeout = 10;
+
+	/* Raise SCL and SDA */
+	pluto_setsda(pluto, 1);
+	pluto_setscl(pluto, 1);
+
+	ret = i2c_bit_add_bus(&pluto->i2c_adap);
+	if (ret < 0)
+		goto err_pluto_hw_exit;
+
+	/* dvb */
+	ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME,
+				   THIS_MODULE, &pdev->dev, adapter_nr);
+	if (ret < 0)
+		goto err_i2c_del_adapter;
+
+	dvb_adapter = &pluto->dvb_adapter;
+
+	pluto_read_rev(pluto);
+	pluto_read_serial(pluto);
+	pluto_read_mac(pluto, dvb_adapter->proposed_mac);
+
+	dvbdemux = &pluto->demux;
+	dvbdemux->filternum = 256;
+	dvbdemux->feednum = 256;
+	dvbdemux->start_feed = pluto_start_feed;
+	dvbdemux->stop_feed = pluto_stop_feed;
+	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+			DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
+	ret = dvb_dmx_init(dvbdemux);
+	if (ret < 0)
+		goto err_dvb_unregister_adapter;
+
+	dmx = &dvbdemux->dmx;
+
+	pluto->hw_frontend.source = DMX_FRONTEND_0;
+	pluto->mem_frontend.source = DMX_MEMORY_FE;
+	pluto->dmxdev.filternum = NHWFILTERS;
+	pluto->dmxdev.demux = dmx;
+
+	ret = dvb_dmxdev_init(&pluto->dmxdev, dvb_adapter);
+	if (ret < 0)
+		goto err_dvb_dmx_release;
+
+	ret = dmx->add_frontend(dmx, &pluto->hw_frontend);
+	if (ret < 0)
+		goto err_dvb_dmxdev_release;
+
+	ret = dmx->add_frontend(dmx, &pluto->mem_frontend);
+	if (ret < 0)
+		goto err_remove_hw_frontend;
+
+	ret = dmx->connect_frontend(dmx, &pluto->hw_frontend);
+	if (ret < 0)
+		goto err_remove_mem_frontend;
+
+	ret = frontend_init(pluto);
+	if (ret < 0)
+		goto err_disconnect_frontend;
+
+	dvb_net_init(dvb_adapter, &pluto->dvbnet, dmx);
+out:
+	return ret;
+
+err_disconnect_frontend:
+	dmx->disconnect_frontend(dmx);
+err_remove_mem_frontend:
+	dmx->remove_frontend(dmx, &pluto->mem_frontend);
+err_remove_hw_frontend:
+	dmx->remove_frontend(dmx, &pluto->hw_frontend);
+err_dvb_dmxdev_release:
+	dvb_dmxdev_release(&pluto->dmxdev);
+err_dvb_dmx_release:
+	dvb_dmx_release(dvbdemux);
+err_dvb_unregister_adapter:
+	dvb_unregister_adapter(dvb_adapter);
+err_i2c_del_adapter:
+	i2c_del_adapter(&pluto->i2c_adap);
+err_pluto_hw_exit:
+	pluto_hw_exit(pluto);
+err_free_irq:
+	free_irq(pdev->irq, pluto);
+err_pci_iounmap:
+	pci_iounmap(pdev, pluto->io_mem);
+err_pci_release_regions:
+	pci_release_regions(pdev);
+err_pci_disable_device:
+	pci_disable_device(pdev);
+err_kfree:
+	pci_set_drvdata(pdev, NULL);
+	kfree(pluto);
+	goto out;
+}
+
+static void __devexit pluto2_remove(struct pci_dev *pdev)
+{
+	struct pluto *pluto = pci_get_drvdata(pdev);
+	struct dvb_adapter *dvb_adapter = &pluto->dvb_adapter;
+	struct dvb_demux *dvbdemux = &pluto->demux;
+	struct dmx_demux *dmx = &dvbdemux->dmx;
+
+	dmx->close(dmx);
+	dvb_net_release(&pluto->dvbnet);
+	if (pluto->fe)
+		dvb_unregister_frontend(pluto->fe);
+
+	dmx->disconnect_frontend(dmx);
+	dmx->remove_frontend(dmx, &pluto->mem_frontend);
+	dmx->remove_frontend(dmx, &pluto->hw_frontend);
+	dvb_dmxdev_release(&pluto->dmxdev);
+	dvb_dmx_release(dvbdemux);
+	dvb_unregister_adapter(dvb_adapter);
+	i2c_del_adapter(&pluto->i2c_adap);
+	pluto_hw_exit(pluto);
+	free_irq(pdev->irq, pluto);
+	pci_iounmap(pdev, pluto->io_mem);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	kfree(pluto);
+}
+
+#ifndef PCI_VENDOR_ID_SCM
+#define PCI_VENDOR_ID_SCM	0x0432
+#endif
+#ifndef PCI_DEVICE_ID_PLUTO2
+#define PCI_DEVICE_ID_PLUTO2	0x0001
+#endif
+
+static struct pci_device_id pluto2_id_table[] __devinitdata = {
+	{
+		.vendor = PCI_VENDOR_ID_SCM,
+		.device = PCI_DEVICE_ID_PLUTO2,
+		.subvendor = PCI_ANY_ID,
+		.subdevice = PCI_ANY_ID,
+	}, {
+		/* empty */
+	},
+};
+
+MODULE_DEVICE_TABLE(pci, pluto2_id_table);
+
+static struct pci_driver pluto2_driver = {
+	.name = DRIVER_NAME,
+	.id_table = pluto2_id_table,
+	.probe = pluto2_probe,
+	.remove = __devexit_p(pluto2_remove),
+};
+
+static int __init pluto2_init(void)
+{
+	return pci_register_driver(&pluto2_driver);
+}
+
+static void __exit pluto2_exit(void)
+{
+	pci_unregister_driver(&pluto2_driver);
+}
+
+module_init(pluto2_init);
+module_exit(pluto2_exit);
+
+MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
+MODULE_DESCRIPTION("Pluto2 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/pt1/Kconfig b/drivers/media/pci/pt1/Kconfig
new file mode 100644
index 0000000..24501d5
--- /dev/null
+++ b/drivers/media/pci/pt1/Kconfig
@@ -0,0 +1,12 @@
+config DVB_PT1
+	tristate "PT1 cards"
+	depends on DVB_CORE && PCI && I2C
+	help
+	  Support for Earthsoft PT1 PCI cards.
+
+	  Since these cards have no MPEG decoder onboard, they transmit
+	  only compressed MPEG data over the PCI bus, so you need
+	  an external software decoder to watch TV on your computer.
+
+	  Say Y or M if you own such a device and want to use it.
+
diff --git a/drivers/media/pci/pt1/Makefile b/drivers/media/pci/pt1/Makefile
new file mode 100644
index 0000000..98e3912
--- /dev/null
+++ b/drivers/media/pci/pt1/Makefile
@@ -0,0 +1,5 @@
+earth-pt1-objs := pt1.o va1j5jf8007s.o va1j5jf8007t.o
+
+obj-$(CONFIG_DVB_PT1) += earth-pt1.o
+
+ccflags-y += -Idrivers/media/dvb-core -Idrivers/media/dvb-frontends
diff --git a/drivers/media/pci/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c
new file mode 100644
index 0000000..15b35c4
--- /dev/null
+++ b/drivers/media/pci/pt1/pt1.c
@@ -0,0 +1,1246 @@
+/*
+ * driver for Earthsoft PT1/PT2
+ *
+ * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
+ *
+ * based on pt1dvr - http://pt1dvr.sourceforge.jp/
+ * 	by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/pci.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/ratelimit.h>
+
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dmxdev.h"
+#include "dvb_net.h"
+#include "dvb_frontend.h"
+
+#include "va1j5jf8007t.h"
+#include "va1j5jf8007s.h"
+
+#define DRIVER_NAME "earth-pt1"
+
+#define PT1_PAGE_SHIFT 12
+#define PT1_PAGE_SIZE (1 << PT1_PAGE_SHIFT)
+#define PT1_NR_UPACKETS 1024
+#define PT1_NR_BUFS 511
+
+struct pt1_buffer_page {
+	__le32 upackets[PT1_NR_UPACKETS];
+};
+
+struct pt1_table_page {
+	__le32 next_pfn;
+	__le32 buf_pfns[PT1_NR_BUFS];
+};
+
+struct pt1_buffer {
+	struct pt1_buffer_page *page;
+	dma_addr_t addr;
+};
+
+struct pt1_table {
+	struct pt1_table_page *page;
+	dma_addr_t addr;
+	struct pt1_buffer bufs[PT1_NR_BUFS];
+};
+
+#define PT1_NR_ADAPS 4
+
+struct pt1_adapter;
+
+struct pt1 {
+	struct pci_dev *pdev;
+	void __iomem *regs;
+	struct i2c_adapter i2c_adap;
+	int i2c_running;
+	struct pt1_adapter *adaps[PT1_NR_ADAPS];
+	struct pt1_table *tables;
+	struct task_struct *kthread;
+	int table_index;
+	int buf_index;
+
+	struct mutex lock;
+	int power;
+	int reset;
+};
+
+struct pt1_adapter {
+	struct pt1 *pt1;
+	int index;
+
+	u8 *buf;
+	int upacket_count;
+	int packet_count;
+	int st_count;
+
+	struct dvb_adapter adap;
+	struct dvb_demux demux;
+	int users;
+	struct dmxdev dmxdev;
+	struct dvb_frontend *fe;
+	int (*orig_set_voltage)(struct dvb_frontend *fe,
+				fe_sec_voltage_t voltage);
+	int (*orig_sleep)(struct dvb_frontend *fe);
+	int (*orig_init)(struct dvb_frontend *fe);
+
+	fe_sec_voltage_t voltage;
+	int sleep;
+};
+
+#define pt1_printk(level, pt1, format, arg...)	\
+	dev_printk(level, &(pt1)->pdev->dev, format, ##arg)
+
+static void pt1_write_reg(struct pt1 *pt1, int reg, u32 data)
+{
+	writel(data, pt1->regs + reg * 4);
+}
+
+static u32 pt1_read_reg(struct pt1 *pt1, int reg)
+{
+	return readl(pt1->regs + reg * 4);
+}
+
+static int pt1_nr_tables = 8;
+module_param_named(nr_tables, pt1_nr_tables, int, 0);
+
+static void pt1_increment_table_count(struct pt1 *pt1)
+{
+	pt1_write_reg(pt1, 0, 0x00000020);
+}
+
+static void pt1_init_table_count(struct pt1 *pt1)
+{
+	pt1_write_reg(pt1, 0, 0x00000010);
+}
+
+static void pt1_register_tables(struct pt1 *pt1, u32 first_pfn)
+{
+	pt1_write_reg(pt1, 5, first_pfn);
+	pt1_write_reg(pt1, 0, 0x0c000040);
+}
+
+static void pt1_unregister_tables(struct pt1 *pt1)
+{
+	pt1_write_reg(pt1, 0, 0x08080000);
+}
+
+static int pt1_sync(struct pt1 *pt1)
+{
+	int i;
+	for (i = 0; i < 57; i++) {
+		if (pt1_read_reg(pt1, 0) & 0x20000000)
+			return 0;
+		pt1_write_reg(pt1, 0, 0x00000008);
+	}
+	pt1_printk(KERN_ERR, pt1, "could not sync\n");
+	return -EIO;
+}
+
+static u64 pt1_identify(struct pt1 *pt1)
+{
+	int i;
+	u64 id;
+	id = 0;
+	for (i = 0; i < 57; i++) {
+		id |= (u64)(pt1_read_reg(pt1, 0) >> 30 & 1) << i;
+		pt1_write_reg(pt1, 0, 0x00000008);
+	}
+	return id;
+}
+
+static int pt1_unlock(struct pt1 *pt1)
+{
+	int i;
+	pt1_write_reg(pt1, 0, 0x00000008);
+	for (i = 0; i < 3; i++) {
+		if (pt1_read_reg(pt1, 0) & 0x80000000)
+			return 0;
+		schedule_timeout_uninterruptible((HZ + 999) / 1000);
+	}
+	pt1_printk(KERN_ERR, pt1, "could not unlock\n");
+	return -EIO;
+}
+
+static int pt1_reset_pci(struct pt1 *pt1)
+{
+	int i;
+	pt1_write_reg(pt1, 0, 0x01010000);
+	pt1_write_reg(pt1, 0, 0x01000000);
+	for (i = 0; i < 10; i++) {
+		if (pt1_read_reg(pt1, 0) & 0x00000001)
+			return 0;
+		schedule_timeout_uninterruptible((HZ + 999) / 1000);
+	}
+	pt1_printk(KERN_ERR, pt1, "could not reset PCI\n");
+	return -EIO;
+}
+
+static int pt1_reset_ram(struct pt1 *pt1)
+{
+	int i;
+	pt1_write_reg(pt1, 0, 0x02020000);
+	pt1_write_reg(pt1, 0, 0x02000000);
+	for (i = 0; i < 10; i++) {
+		if (pt1_read_reg(pt1, 0) & 0x00000002)
+			return 0;
+		schedule_timeout_uninterruptible((HZ + 999) / 1000);
+	}
+	pt1_printk(KERN_ERR, pt1, "could not reset RAM\n");
+	return -EIO;
+}
+
+static int pt1_do_enable_ram(struct pt1 *pt1)
+{
+	int i, j;
+	u32 status;
+	status = pt1_read_reg(pt1, 0) & 0x00000004;
+	pt1_write_reg(pt1, 0, 0x00000002);
+	for (i = 0; i < 10; i++) {
+		for (j = 0; j < 1024; j++) {
+			if ((pt1_read_reg(pt1, 0) & 0x00000004) != status)
+				return 0;
+		}
+		schedule_timeout_uninterruptible((HZ + 999) / 1000);
+	}
+	pt1_printk(KERN_ERR, pt1, "could not enable RAM\n");
+	return -EIO;
+}
+
+static int pt1_enable_ram(struct pt1 *pt1)
+{
+	int i, ret;
+	int phase;
+	schedule_timeout_uninterruptible((HZ + 999) / 1000);
+	phase = pt1->pdev->device == 0x211a ? 128 : 166;
+	for (i = 0; i < phase; i++) {
+		ret = pt1_do_enable_ram(pt1);
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+static void pt1_disable_ram(struct pt1 *pt1)
+{
+	pt1_write_reg(pt1, 0, 0x0b0b0000);
+}
+
+static void pt1_set_stream(struct pt1 *pt1, int index, int enabled)
+{
+	pt1_write_reg(pt1, 2, 1 << (index + 8) | enabled << index);
+}
+
+static void pt1_init_streams(struct pt1 *pt1)
+{
+	int i;
+	for (i = 0; i < PT1_NR_ADAPS; i++)
+		pt1_set_stream(pt1, i, 0);
+}
+
+static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page)
+{
+	u32 upacket;
+	int i;
+	int index;
+	struct pt1_adapter *adap;
+	int offset;
+	u8 *buf;
+	int sc;
+
+	if (!page->upackets[PT1_NR_UPACKETS - 1])
+		return 0;
+
+	for (i = 0; i < PT1_NR_UPACKETS; i++) {
+		upacket = le32_to_cpu(page->upackets[i]);
+		index = (upacket >> 29) - 1;
+		if (index < 0 || index >=  PT1_NR_ADAPS)
+			continue;
+
+		adap = pt1->adaps[index];
+		if (upacket >> 25 & 1)
+			adap->upacket_count = 0;
+		else if (!adap->upacket_count)
+			continue;
+
+		if (upacket >> 24 & 1)
+			printk_ratelimited(KERN_INFO "earth-pt1: device "
+				"buffer overflowing. table[%d] buf[%d]\n",
+				pt1->table_index, pt1->buf_index);
+		sc = upacket >> 26 & 0x7;
+		if (adap->st_count != -1 && sc != ((adap->st_count + 1) & 0x7))
+			printk_ratelimited(KERN_INFO "earth-pt1: data loss"
+				" in streamID(adapter)[%d]\n", index);
+		adap->st_count = sc;
+
+		buf = adap->buf;
+		offset = adap->packet_count * 188 + adap->upacket_count * 3;
+		buf[offset] = upacket >> 16;
+		buf[offset + 1] = upacket >> 8;
+		if (adap->upacket_count != 62)
+			buf[offset + 2] = upacket;
+
+		if (++adap->upacket_count >= 63) {
+			adap->upacket_count = 0;
+			if (++adap->packet_count >= 21) {
+				dvb_dmx_swfilter_packets(&adap->demux, buf, 21);
+				adap->packet_count = 0;
+			}
+		}
+	}
+
+	page->upackets[PT1_NR_UPACKETS - 1] = 0;
+	return 1;
+}
+
+static int pt1_thread(void *data)
+{
+	struct pt1 *pt1;
+	struct pt1_buffer_page *page;
+
+	pt1 = data;
+	set_freezable();
+
+	while (!kthread_should_stop()) {
+		try_to_freeze();
+
+		page = pt1->tables[pt1->table_index].bufs[pt1->buf_index].page;
+		if (!pt1_filter(pt1, page)) {
+			schedule_timeout_interruptible((HZ + 999) / 1000);
+			continue;
+		}
+
+		if (++pt1->buf_index >= PT1_NR_BUFS) {
+			pt1_increment_table_count(pt1);
+			pt1->buf_index = 0;
+			if (++pt1->table_index >= pt1_nr_tables)
+				pt1->table_index = 0;
+		}
+	}
+
+	return 0;
+}
+
+static void pt1_free_page(struct pt1 *pt1, void *page, dma_addr_t addr)
+{
+	dma_free_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, page, addr);
+}
+
+static void *pt1_alloc_page(struct pt1 *pt1, dma_addr_t *addrp, u32 *pfnp)
+{
+	void *page;
+	dma_addr_t addr;
+
+	page = dma_alloc_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, &addr,
+				  GFP_KERNEL);
+	if (page == NULL)
+		return NULL;
+
+	BUG_ON(addr & (PT1_PAGE_SIZE - 1));
+	BUG_ON(addr >> PT1_PAGE_SHIFT >> 31 >> 1);
+
+	*addrp = addr;
+	*pfnp = addr >> PT1_PAGE_SHIFT;
+	return page;
+}
+
+static void pt1_cleanup_buffer(struct pt1 *pt1, struct pt1_buffer *buf)
+{
+	pt1_free_page(pt1, buf->page, buf->addr);
+}
+
+static int
+pt1_init_buffer(struct pt1 *pt1, struct pt1_buffer *buf,  u32 *pfnp)
+{
+	struct pt1_buffer_page *page;
+	dma_addr_t addr;
+
+	page = pt1_alloc_page(pt1, &addr, pfnp);
+	if (page == NULL)
+		return -ENOMEM;
+
+	page->upackets[PT1_NR_UPACKETS - 1] = 0;
+
+	buf->page = page;
+	buf->addr = addr;
+	return 0;
+}
+
+static void pt1_cleanup_table(struct pt1 *pt1, struct pt1_table *table)
+{
+	int i;
+
+	for (i = 0; i < PT1_NR_BUFS; i++)
+		pt1_cleanup_buffer(pt1, &table->bufs[i]);
+
+	pt1_free_page(pt1, table->page, table->addr);
+}
+
+static int
+pt1_init_table(struct pt1 *pt1, struct pt1_table *table, u32 *pfnp)
+{
+	struct pt1_table_page *page;
+	dma_addr_t addr;
+	int i, ret;
+	u32 buf_pfn;
+
+	page = pt1_alloc_page(pt1, &addr, pfnp);
+	if (page == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < PT1_NR_BUFS; i++) {
+		ret = pt1_init_buffer(pt1, &table->bufs[i], &buf_pfn);
+		if (ret < 0)
+			goto err;
+
+		page->buf_pfns[i] = cpu_to_le32(buf_pfn);
+	}
+
+	pt1_increment_table_count(pt1);
+	table->page = page;
+	table->addr = addr;
+	return 0;
+
+err:
+	while (i--)
+		pt1_cleanup_buffer(pt1, &table->bufs[i]);
+
+	pt1_free_page(pt1, page, addr);
+	return ret;
+}
+
+static void pt1_cleanup_tables(struct pt1 *pt1)
+{
+	struct pt1_table *tables;
+	int i;
+
+	tables = pt1->tables;
+	pt1_unregister_tables(pt1);
+
+	for (i = 0; i < pt1_nr_tables; i++)
+		pt1_cleanup_table(pt1, &tables[i]);
+
+	vfree(tables);
+}
+
+static int pt1_init_tables(struct pt1 *pt1)
+{
+	struct pt1_table *tables;
+	int i, ret;
+	u32 first_pfn, pfn;
+
+	tables = vmalloc(sizeof(struct pt1_table) * pt1_nr_tables);
+	if (tables == NULL)
+		return -ENOMEM;
+
+	pt1_init_table_count(pt1);
+
+	i = 0;
+	if (pt1_nr_tables) {
+		ret = pt1_init_table(pt1, &tables[0], &first_pfn);
+		if (ret)
+			goto err;
+		i++;
+	}
+
+	while (i < pt1_nr_tables) {
+		ret = pt1_init_table(pt1, &tables[i], &pfn);
+		if (ret)
+			goto err;
+		tables[i - 1].page->next_pfn = cpu_to_le32(pfn);
+		i++;
+	}
+
+	tables[pt1_nr_tables - 1].page->next_pfn = cpu_to_le32(first_pfn);
+
+	pt1_register_tables(pt1, first_pfn);
+	pt1->tables = tables;
+	return 0;
+
+err:
+	while (i--)
+		pt1_cleanup_table(pt1, &tables[i]);
+
+	vfree(tables);
+	return ret;
+}
+
+static int pt1_start_polling(struct pt1 *pt1)
+{
+	int ret = 0;
+
+	mutex_lock(&pt1->lock);
+	if (!pt1->kthread) {
+		pt1->kthread = kthread_run(pt1_thread, pt1, "earth-pt1");
+		if (IS_ERR(pt1->kthread)) {
+			ret = PTR_ERR(pt1->kthread);
+			pt1->kthread = NULL;
+		}
+	}
+	mutex_unlock(&pt1->lock);
+	return ret;
+}
+
+static int pt1_start_feed(struct dvb_demux_feed *feed)
+{
+	struct pt1_adapter *adap;
+	adap = container_of(feed->demux, struct pt1_adapter, demux);
+	if (!adap->users++) {
+		int ret;
+
+		ret = pt1_start_polling(adap->pt1);
+		if (ret)
+			return ret;
+		pt1_set_stream(adap->pt1, adap->index, 1);
+	}
+	return 0;
+}
+
+static void pt1_stop_polling(struct pt1 *pt1)
+{
+	int i, count;
+
+	mutex_lock(&pt1->lock);
+	for (i = 0, count = 0; i < PT1_NR_ADAPS; i++)
+		count += pt1->adaps[i]->users;
+
+	if (count == 0 && pt1->kthread) {
+		kthread_stop(pt1->kthread);
+		pt1->kthread = NULL;
+	}
+	mutex_unlock(&pt1->lock);
+}
+
+static int pt1_stop_feed(struct dvb_demux_feed *feed)
+{
+	struct pt1_adapter *adap;
+	adap = container_of(feed->demux, struct pt1_adapter, demux);
+	if (!--adap->users) {
+		pt1_set_stream(adap->pt1, adap->index, 0);
+		pt1_stop_polling(adap->pt1);
+	}
+	return 0;
+}
+
+static void
+pt1_update_power(struct pt1 *pt1)
+{
+	int bits;
+	int i;
+	struct pt1_adapter *adap;
+	static const int sleep_bits[] = {
+		1 << 4,
+		1 << 6 | 1 << 7,
+		1 << 5,
+		1 << 6 | 1 << 8,
+	};
+
+	bits = pt1->power | !pt1->reset << 3;
+	mutex_lock(&pt1->lock);
+	for (i = 0; i < PT1_NR_ADAPS; i++) {
+		adap = pt1->adaps[i];
+		switch (adap->voltage) {
+		case SEC_VOLTAGE_13: /* actually 11V */
+			bits |= 1 << 1;
+			break;
+		case SEC_VOLTAGE_18: /* actually 15V */
+			bits |= 1 << 1 | 1 << 2;
+			break;
+		default:
+			break;
+		}
+
+		/* XXX: The bits should be changed depending on adap->sleep. */
+		bits |= sleep_bits[i];
+	}
+	pt1_write_reg(pt1, 1, bits);
+	mutex_unlock(&pt1->lock);
+}
+
+static int pt1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct pt1_adapter *adap;
+
+	adap = container_of(fe->dvb, struct pt1_adapter, adap);
+	adap->voltage = voltage;
+	pt1_update_power(adap->pt1);
+
+	if (adap->orig_set_voltage)
+		return adap->orig_set_voltage(fe, voltage);
+	else
+		return 0;
+}
+
+static int pt1_sleep(struct dvb_frontend *fe)
+{
+	struct pt1_adapter *adap;
+
+	adap = container_of(fe->dvb, struct pt1_adapter, adap);
+	adap->sleep = 1;
+	pt1_update_power(adap->pt1);
+
+	if (adap->orig_sleep)
+		return adap->orig_sleep(fe);
+	else
+		return 0;
+}
+
+static int pt1_wakeup(struct dvb_frontend *fe)
+{
+	struct pt1_adapter *adap;
+
+	adap = container_of(fe->dvb, struct pt1_adapter, adap);
+	adap->sleep = 0;
+	pt1_update_power(adap->pt1);
+	schedule_timeout_uninterruptible((HZ + 999) / 1000);
+
+	if (adap->orig_init)
+		return adap->orig_init(fe);
+	else
+		return 0;
+}
+
+static void pt1_free_adapter(struct pt1_adapter *adap)
+{
+	adap->demux.dmx.close(&adap->demux.dmx);
+	dvb_dmxdev_release(&adap->dmxdev);
+	dvb_dmx_release(&adap->demux);
+	dvb_unregister_adapter(&adap->adap);
+	free_page((unsigned long)adap->buf);
+	kfree(adap);
+}
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static struct pt1_adapter *
+pt1_alloc_adapter(struct pt1 *pt1)
+{
+	struct pt1_adapter *adap;
+	void *buf;
+	struct dvb_adapter *dvb_adap;
+	struct dvb_demux *demux;
+	struct dmxdev *dmxdev;
+	int ret;
+
+	adap = kzalloc(sizeof(struct pt1_adapter), GFP_KERNEL);
+	if (!adap) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	adap->pt1 = pt1;
+
+	adap->voltage = SEC_VOLTAGE_OFF;
+	adap->sleep = 1;
+
+	buf = (u8 *)__get_free_page(GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err_kfree;
+	}
+
+	adap->buf = buf;
+	adap->upacket_count = 0;
+	adap->packet_count = 0;
+	adap->st_count = -1;
+
+	dvb_adap = &adap->adap;
+	dvb_adap->priv = adap;
+	ret = dvb_register_adapter(dvb_adap, DRIVER_NAME, THIS_MODULE,
+				   &pt1->pdev->dev, adapter_nr);
+	if (ret < 0)
+		goto err_free_page;
+
+	demux = &adap->demux;
+	demux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+	demux->priv = adap;
+	demux->feednum = 256;
+	demux->filternum = 256;
+	demux->start_feed = pt1_start_feed;
+	demux->stop_feed = pt1_stop_feed;
+	demux->write_to_decoder = NULL;
+	ret = dvb_dmx_init(demux);
+	if (ret < 0)
+		goto err_unregister_adapter;
+
+	dmxdev = &adap->dmxdev;
+	dmxdev->filternum = 256;
+	dmxdev->demux = &demux->dmx;
+	dmxdev->capabilities = 0;
+	ret = dvb_dmxdev_init(dmxdev, dvb_adap);
+	if (ret < 0)
+		goto err_dmx_release;
+
+	return adap;
+
+err_dmx_release:
+	dvb_dmx_release(demux);
+err_unregister_adapter:
+	dvb_unregister_adapter(dvb_adap);
+err_free_page:
+	free_page((unsigned long)buf);
+err_kfree:
+	kfree(adap);
+err:
+	return ERR_PTR(ret);
+}
+
+static void pt1_cleanup_adapters(struct pt1 *pt1)
+{
+	int i;
+	for (i = 0; i < PT1_NR_ADAPS; i++)
+		pt1_free_adapter(pt1->adaps[i]);
+}
+
+static int pt1_init_adapters(struct pt1 *pt1)
+{
+	int i;
+	struct pt1_adapter *adap;
+	int ret;
+
+	for (i = 0; i < PT1_NR_ADAPS; i++) {
+		adap = pt1_alloc_adapter(pt1);
+		if (IS_ERR(adap)) {
+			ret = PTR_ERR(adap);
+			goto err;
+		}
+
+		adap->index = i;
+		pt1->adaps[i] = adap;
+	}
+	return 0;
+
+err:
+	while (i--)
+		pt1_free_adapter(pt1->adaps[i]);
+
+	return ret;
+}
+
+static void pt1_cleanup_frontend(struct pt1_adapter *adap)
+{
+	dvb_unregister_frontend(adap->fe);
+}
+
+static int pt1_init_frontend(struct pt1_adapter *adap, struct dvb_frontend *fe)
+{
+	int ret;
+
+	adap->orig_set_voltage = fe->ops.set_voltage;
+	adap->orig_sleep = fe->ops.sleep;
+	adap->orig_init = fe->ops.init;
+	fe->ops.set_voltage = pt1_set_voltage;
+	fe->ops.sleep = pt1_sleep;
+	fe->ops.init = pt1_wakeup;
+
+	ret = dvb_register_frontend(&adap->adap, fe);
+	if (ret < 0)
+		return ret;
+
+	adap->fe = fe;
+	return 0;
+}
+
+static void pt1_cleanup_frontends(struct pt1 *pt1)
+{
+	int i;
+	for (i = 0; i < PT1_NR_ADAPS; i++)
+		pt1_cleanup_frontend(pt1->adaps[i]);
+}
+
+struct pt1_config {
+	struct va1j5jf8007s_config va1j5jf8007s_config;
+	struct va1j5jf8007t_config va1j5jf8007t_config;
+};
+
+static const struct pt1_config pt1_configs[2] = {
+	{
+		{
+			.demod_address = 0x1b,
+			.frequency = VA1J5JF8007S_20MHZ,
+		},
+		{
+			.demod_address = 0x1a,
+			.frequency = VA1J5JF8007T_20MHZ,
+		},
+	}, {
+		{
+			.demod_address = 0x19,
+			.frequency = VA1J5JF8007S_20MHZ,
+		},
+		{
+			.demod_address = 0x18,
+			.frequency = VA1J5JF8007T_20MHZ,
+		},
+	},
+};
+
+static const struct pt1_config pt2_configs[2] = {
+	{
+		{
+			.demod_address = 0x1b,
+			.frequency = VA1J5JF8007S_25MHZ,
+		},
+		{
+			.demod_address = 0x1a,
+			.frequency = VA1J5JF8007T_25MHZ,
+		},
+	}, {
+		{
+			.demod_address = 0x19,
+			.frequency = VA1J5JF8007S_25MHZ,
+		},
+		{
+			.demod_address = 0x18,
+			.frequency = VA1J5JF8007T_25MHZ,
+		},
+	},
+};
+
+static int pt1_init_frontends(struct pt1 *pt1)
+{
+	int i, j;
+	struct i2c_adapter *i2c_adap;
+	const struct pt1_config *configs, *config;
+	struct dvb_frontend *fe[4];
+	int ret;
+
+	i = 0;
+	j = 0;
+
+	i2c_adap = &pt1->i2c_adap;
+	configs = pt1->pdev->device == 0x211a ? pt1_configs : pt2_configs;
+	do {
+		config = &configs[i / 2];
+
+		fe[i] = va1j5jf8007s_attach(&config->va1j5jf8007s_config,
+					    i2c_adap);
+		if (!fe[i]) {
+			ret = -ENODEV; /* This does not sound nice... */
+			goto err;
+		}
+		i++;
+
+		fe[i] = va1j5jf8007t_attach(&config->va1j5jf8007t_config,
+					    i2c_adap);
+		if (!fe[i]) {
+			ret = -ENODEV;
+			goto err;
+		}
+		i++;
+
+		ret = va1j5jf8007s_prepare(fe[i - 2]);
+		if (ret < 0)
+			goto err;
+
+		ret = va1j5jf8007t_prepare(fe[i - 1]);
+		if (ret < 0)
+			goto err;
+
+	} while (i < 4);
+
+	do {
+		ret = pt1_init_frontend(pt1->adaps[j], fe[j]);
+		if (ret < 0)
+			goto err;
+	} while (++j < 4);
+
+	return 0;
+
+err:
+	while (i-- > j)
+		fe[i]->ops.release(fe[i]);
+
+	while (j--)
+		dvb_unregister_frontend(fe[j]);
+
+	return ret;
+}
+
+static void pt1_i2c_emit(struct pt1 *pt1, int addr, int busy, int read_enable,
+			 int clock, int data, int next_addr)
+{
+	pt1_write_reg(pt1, 4, addr << 18 | busy << 13 | read_enable << 12 |
+		      !clock << 11 | !data << 10 | next_addr);
+}
+
+static void pt1_i2c_write_bit(struct pt1 *pt1, int addr, int *addrp, int data)
+{
+	pt1_i2c_emit(pt1, addr,     1, 0, 0, data, addr + 1);
+	pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, data, addr + 2);
+	pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, data, addr + 3);
+	*addrp = addr + 3;
+}
+
+static void pt1_i2c_read_bit(struct pt1 *pt1, int addr, int *addrp)
+{
+	pt1_i2c_emit(pt1, addr,     1, 0, 0, 1, addr + 1);
+	pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 1, addr + 2);
+	pt1_i2c_emit(pt1, addr + 2, 1, 1, 1, 1, addr + 3);
+	pt1_i2c_emit(pt1, addr + 3, 1, 0, 0, 1, addr + 4);
+	*addrp = addr + 4;
+}
+
+static void pt1_i2c_write_byte(struct pt1 *pt1, int addr, int *addrp, int data)
+{
+	int i;
+	for (i = 0; i < 8; i++)
+		pt1_i2c_write_bit(pt1, addr, &addr, data >> (7 - i) & 1);
+	pt1_i2c_write_bit(pt1, addr, &addr, 1);
+	*addrp = addr;
+}
+
+static void pt1_i2c_read_byte(struct pt1 *pt1, int addr, int *addrp, int last)
+{
+	int i;
+	for (i = 0; i < 8; i++)
+		pt1_i2c_read_bit(pt1, addr, &addr);
+	pt1_i2c_write_bit(pt1, addr, &addr, last);
+	*addrp = addr;
+}
+
+static void pt1_i2c_prepare(struct pt1 *pt1, int addr, int *addrp)
+{
+	pt1_i2c_emit(pt1, addr,     1, 0, 1, 1, addr + 1);
+	pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2);
+	pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, 0, addr + 3);
+	*addrp = addr + 3;
+}
+
+static void
+pt1_i2c_write_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg)
+{
+	int i;
+	pt1_i2c_prepare(pt1, addr, &addr);
+	pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1);
+	for (i = 0; i < msg->len; i++)
+		pt1_i2c_write_byte(pt1, addr, &addr, msg->buf[i]);
+	*addrp = addr;
+}
+
+static void
+pt1_i2c_read_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg)
+{
+	int i;
+	pt1_i2c_prepare(pt1, addr, &addr);
+	pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1 | 1);
+	for (i = 0; i < msg->len; i++)
+		pt1_i2c_read_byte(pt1, addr, &addr, i == msg->len - 1);
+	*addrp = addr;
+}
+
+static int pt1_i2c_end(struct pt1 *pt1, int addr)
+{
+	pt1_i2c_emit(pt1, addr,     1, 0, 0, 0, addr + 1);
+	pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2);
+	pt1_i2c_emit(pt1, addr + 2, 1, 0, 1, 1, 0);
+
+	pt1_write_reg(pt1, 0, 0x00000004);
+	do {
+		if (signal_pending(current))
+			return -EINTR;
+		schedule_timeout_interruptible((HZ + 999) / 1000);
+	} while (pt1_read_reg(pt1, 0) & 0x00000080);
+	return 0;
+}
+
+static void pt1_i2c_begin(struct pt1 *pt1, int *addrp)
+{
+	int addr;
+	addr = 0;
+
+	pt1_i2c_emit(pt1, addr,     0, 0, 1, 1, addr /* itself */);
+	addr = addr + 1;
+
+	if (!pt1->i2c_running) {
+		pt1_i2c_emit(pt1, addr,     1, 0, 1, 1, addr + 1);
+		pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2);
+		addr = addr + 2;
+		pt1->i2c_running = 1;
+	}
+	*addrp = addr;
+}
+
+static int pt1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct pt1 *pt1;
+	int i;
+	struct i2c_msg *msg, *next_msg;
+	int addr, ret;
+	u16 len;
+	u32 word;
+
+	pt1 = i2c_get_adapdata(adap);
+
+	for (i = 0; i < num; i++) {
+		msg = &msgs[i];
+		if (msg->flags & I2C_M_RD)
+			return -ENOTSUPP;
+
+		if (i + 1 < num)
+			next_msg = &msgs[i + 1];
+		else
+			next_msg = NULL;
+
+		if (next_msg && next_msg->flags & I2C_M_RD) {
+			i++;
+
+			len = next_msg->len;
+			if (len > 4)
+				return -ENOTSUPP;
+
+			pt1_i2c_begin(pt1, &addr);
+			pt1_i2c_write_msg(pt1, addr, &addr, msg);
+			pt1_i2c_read_msg(pt1, addr, &addr, next_msg);
+			ret = pt1_i2c_end(pt1, addr);
+			if (ret < 0)
+				return ret;
+
+			word = pt1_read_reg(pt1, 2);
+			while (len--) {
+				next_msg->buf[len] = word;
+				word >>= 8;
+			}
+		} else {
+			pt1_i2c_begin(pt1, &addr);
+			pt1_i2c_write_msg(pt1, addr, &addr, msg);
+			ret = pt1_i2c_end(pt1, addr);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return num;
+}
+
+static u32 pt1_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm pt1_i2c_algo = {
+	.master_xfer = pt1_i2c_xfer,
+	.functionality = pt1_i2c_func,
+};
+
+static void pt1_i2c_wait(struct pt1 *pt1)
+{
+	int i;
+	for (i = 0; i < 128; i++)
+		pt1_i2c_emit(pt1, 0, 0, 0, 1, 1, 0);
+}
+
+static void pt1_i2c_init(struct pt1 *pt1)
+{
+	int i;
+	for (i = 0; i < 1024; i++)
+		pt1_i2c_emit(pt1, i, 0, 0, 1, 1, 0);
+}
+
+static void __devexit pt1_remove(struct pci_dev *pdev)
+{
+	struct pt1 *pt1;
+	void __iomem *regs;
+
+	pt1 = pci_get_drvdata(pdev);
+	regs = pt1->regs;
+
+	if (pt1->kthread)
+		kthread_stop(pt1->kthread);
+	pt1_cleanup_tables(pt1);
+	pt1_cleanup_frontends(pt1);
+	pt1_disable_ram(pt1);
+	pt1->power = 0;
+	pt1->reset = 1;
+	pt1_update_power(pt1);
+	pt1_cleanup_adapters(pt1);
+	i2c_del_adapter(&pt1->i2c_adap);
+	pci_set_drvdata(pdev, NULL);
+	kfree(pt1);
+	pci_iounmap(pdev, regs);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+}
+
+static int __devinit
+pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int ret;
+	void __iomem *regs;
+	struct pt1 *pt1;
+	struct i2c_adapter *i2c_adap;
+
+	ret = pci_enable_device(pdev);
+	if (ret < 0)
+		goto err;
+
+	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+	if (ret < 0)
+		goto err_pci_disable_device;
+
+	pci_set_master(pdev);
+
+	ret = pci_request_regions(pdev, DRIVER_NAME);
+	if (ret < 0)
+		goto err_pci_disable_device;
+
+	regs = pci_iomap(pdev, 0, 0);
+	if (!regs) {
+		ret = -EIO;
+		goto err_pci_release_regions;
+	}
+
+	pt1 = kzalloc(sizeof(struct pt1), GFP_KERNEL);
+	if (!pt1) {
+		ret = -ENOMEM;
+		goto err_pci_iounmap;
+	}
+
+	mutex_init(&pt1->lock);
+	pt1->pdev = pdev;
+	pt1->regs = regs;
+	pci_set_drvdata(pdev, pt1);
+
+	ret = pt1_init_adapters(pt1);
+	if (ret < 0)
+		goto err_kfree;
+
+	mutex_init(&pt1->lock);
+
+	pt1->power = 0;
+	pt1->reset = 1;
+	pt1_update_power(pt1);
+
+	i2c_adap = &pt1->i2c_adap;
+	i2c_adap->algo = &pt1_i2c_algo;
+	i2c_adap->algo_data = NULL;
+	i2c_adap->dev.parent = &pdev->dev;
+	strcpy(i2c_adap->name, DRIVER_NAME);
+	i2c_set_adapdata(i2c_adap, pt1);
+	ret = i2c_add_adapter(i2c_adap);
+	if (ret < 0)
+		goto err_pt1_cleanup_adapters;
+
+	pt1_i2c_init(pt1);
+	pt1_i2c_wait(pt1);
+
+	ret = pt1_sync(pt1);
+	if (ret < 0)
+		goto err_i2c_del_adapter;
+
+	pt1_identify(pt1);
+
+	ret = pt1_unlock(pt1);
+	if (ret < 0)
+		goto err_i2c_del_adapter;
+
+	ret = pt1_reset_pci(pt1);
+	if (ret < 0)
+		goto err_i2c_del_adapter;
+
+	ret = pt1_reset_ram(pt1);
+	if (ret < 0)
+		goto err_i2c_del_adapter;
+
+	ret = pt1_enable_ram(pt1);
+	if (ret < 0)
+		goto err_i2c_del_adapter;
+
+	pt1_init_streams(pt1);
+
+	pt1->power = 1;
+	pt1_update_power(pt1);
+	schedule_timeout_uninterruptible((HZ + 49) / 50);
+
+	pt1->reset = 0;
+	pt1_update_power(pt1);
+	schedule_timeout_uninterruptible((HZ + 999) / 1000);
+
+	ret = pt1_init_frontends(pt1);
+	if (ret < 0)
+		goto err_pt1_disable_ram;
+
+	ret = pt1_init_tables(pt1);
+	if (ret < 0)
+		goto err_pt1_cleanup_frontends;
+
+	return 0;
+
+err_pt1_cleanup_frontends:
+	pt1_cleanup_frontends(pt1);
+err_pt1_disable_ram:
+	pt1_disable_ram(pt1);
+	pt1->power = 0;
+	pt1->reset = 1;
+	pt1_update_power(pt1);
+err_i2c_del_adapter:
+	i2c_del_adapter(i2c_adap);
+err_pt1_cleanup_adapters:
+	pt1_cleanup_adapters(pt1);
+err_kfree:
+	pci_set_drvdata(pdev, NULL);
+	kfree(pt1);
+err_pci_iounmap:
+	pci_iounmap(pdev, regs);
+err_pci_release_regions:
+	pci_release_regions(pdev);
+err_pci_disable_device:
+	pci_disable_device(pdev);
+err:
+	return ret;
+
+}
+
+static struct pci_device_id pt1_id_table[] = {
+	{ PCI_DEVICE(0x10ee, 0x211a) },
+	{ PCI_DEVICE(0x10ee, 0x222a) },
+	{ },
+};
+MODULE_DEVICE_TABLE(pci, pt1_id_table);
+
+static struct pci_driver pt1_driver = {
+	.name		= DRIVER_NAME,
+	.probe		= pt1_probe,
+	.remove		= __devexit_p(pt1_remove),
+	.id_table	= pt1_id_table,
+};
+
+
+static int __init pt1_init(void)
+{
+	return pci_register_driver(&pt1_driver);
+}
+
+
+static void __exit pt1_cleanup(void)
+{
+	pci_unregister_driver(&pt1_driver);
+}
+
+module_init(pt1_init);
+module_exit(pt1_cleanup);
+
+MODULE_AUTHOR("Takahito HIRANO <hiranotaka@zng.info>");
+MODULE_DESCRIPTION("Earthsoft PT1/PT2 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/pt1/va1j5jf8007s.c b/drivers/media/pci/pt1/va1j5jf8007s.c
new file mode 100644
index 0000000..d980dfb
--- /dev/null
+++ b/drivers/media/pci/pt1/va1j5jf8007s.c
@@ -0,0 +1,735 @@
+/*
+ * ISDB-S driver for VA1J5JF8007/VA1J5JF8011
+ *
+ * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
+ *
+ * based on pt1dvr - http://pt1dvr.sourceforge.jp/
+ * 	by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+#include "va1j5jf8007s.h"
+
+enum va1j5jf8007s_tune_state {
+	VA1J5JF8007S_IDLE,
+	VA1J5JF8007S_SET_FREQUENCY_1,
+	VA1J5JF8007S_SET_FREQUENCY_2,
+	VA1J5JF8007S_SET_FREQUENCY_3,
+	VA1J5JF8007S_CHECK_FREQUENCY,
+	VA1J5JF8007S_SET_MODULATION,
+	VA1J5JF8007S_CHECK_MODULATION,
+	VA1J5JF8007S_SET_TS_ID,
+	VA1J5JF8007S_CHECK_TS_ID,
+	VA1J5JF8007S_TRACK,
+};
+
+struct va1j5jf8007s_state {
+	const struct va1j5jf8007s_config *config;
+	struct i2c_adapter *adap;
+	struct dvb_frontend fe;
+	enum va1j5jf8007s_tune_state tune_state;
+};
+
+static int va1j5jf8007s_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct va1j5jf8007s_state *state;
+	u8 addr;
+	int i;
+	u8 write_buf[1], read_buf[1];
+	struct i2c_msg msgs[2];
+	s32 word, x1, x2, x3, x4, x5, y;
+
+	state = fe->demodulator_priv;
+	addr = state->config->demod_address;
+
+	word = 0;
+	for (i = 0; i < 2; i++) {
+		write_buf[0] = 0xbc + i;
+
+		msgs[0].addr = addr;
+		msgs[0].flags = 0;
+		msgs[0].len = sizeof(write_buf);
+		msgs[0].buf = write_buf;
+
+		msgs[1].addr = addr;
+		msgs[1].flags = I2C_M_RD;
+		msgs[1].len = sizeof(read_buf);
+		msgs[1].buf = read_buf;
+
+		if (i2c_transfer(state->adap, msgs, 2) != 2)
+			return -EREMOTEIO;
+
+		word <<= 8;
+		word |= read_buf[0];
+	}
+
+	word -= 3000;
+	if (word < 0)
+		word = 0;
+
+	x1 = int_sqrt(word << 16) * ((15625ll << 21) / 1000000);
+	x2 = (s64)x1 * x1 >> 31;
+	x3 = (s64)x2 * x1 >> 31;
+	x4 = (s64)x2 * x2 >> 31;
+	x5 = (s64)x4 * x1 >> 31;
+
+	y = (58857ll << 23) / 1000;
+	y -= (s64)x1 * ((89565ll << 24) / 1000) >> 30;
+	y += (s64)x2 * ((88977ll << 24) / 1000) >> 28;
+	y -= (s64)x3 * ((50259ll << 25) / 1000) >> 27;
+	y += (s64)x4 * ((14341ll << 27) / 1000) >> 27;
+	y -= (s64)x5 * ((16346ll << 30) / 10000) >> 28;
+
+	*snr = y < 0 ? 0 : y >> 15;
+	return 0;
+}
+
+static int va1j5jf8007s_get_frontend_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_HW;
+}
+
+static int
+va1j5jf8007s_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct va1j5jf8007s_state *state;
+
+	state = fe->demodulator_priv;
+
+	switch (state->tune_state) {
+	case VA1J5JF8007S_IDLE:
+	case VA1J5JF8007S_SET_FREQUENCY_1:
+	case VA1J5JF8007S_SET_FREQUENCY_2:
+	case VA1J5JF8007S_SET_FREQUENCY_3:
+	case VA1J5JF8007S_CHECK_FREQUENCY:
+		*status = 0;
+		return 0;
+
+
+	case VA1J5JF8007S_SET_MODULATION:
+	case VA1J5JF8007S_CHECK_MODULATION:
+		*status |= FE_HAS_SIGNAL;
+		return 0;
+
+	case VA1J5JF8007S_SET_TS_ID:
+	case VA1J5JF8007S_CHECK_TS_ID:
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+		return 0;
+
+	case VA1J5JF8007S_TRACK:
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
+		return 0;
+	}
+
+	BUG();
+}
+
+struct va1j5jf8007s_cb_map {
+	u32 frequency;
+	u8 cb;
+};
+
+static const struct va1j5jf8007s_cb_map va1j5jf8007s_cb_maps[] = {
+	{  986000, 0xb2 },
+	{ 1072000, 0xd2 },
+	{ 1154000, 0xe2 },
+	{ 1291000, 0x20 },
+	{ 1447000, 0x40 },
+	{ 1615000, 0x60 },
+	{ 1791000, 0x80 },
+	{ 1972000, 0xa0 },
+};
+
+static u8 va1j5jf8007s_lookup_cb(u32 frequency)
+{
+	int i;
+	const struct va1j5jf8007s_cb_map *map;
+
+	for (i = 0; i < ARRAY_SIZE(va1j5jf8007s_cb_maps); i++) {
+		map = &va1j5jf8007s_cb_maps[i];
+		if (frequency < map->frequency)
+			return map->cb;
+	}
+	return 0xc0;
+}
+
+static int va1j5jf8007s_set_frequency_1(struct va1j5jf8007s_state *state)
+{
+	u32 frequency;
+	u16 word;
+	u8 buf[6];
+	struct i2c_msg msg;
+
+	frequency = state->fe.dtv_property_cache.frequency;
+
+	word = (frequency + 500) / 1000;
+	if (frequency < 1072000)
+		word = (word << 1 & ~0x1f) | (word & 0x0f);
+
+	buf[0] = 0xfe;
+	buf[1] = 0xc0;
+	buf[2] = 0x40 | word >> 8;
+	buf[3] = word;
+	buf[4] = 0xe0;
+	buf[5] = va1j5jf8007s_lookup_cb(frequency);
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.len = sizeof(buf);
+	msg.buf = buf;
+
+	if (i2c_transfer(state->adap, &msg, 1) != 1)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int va1j5jf8007s_set_frequency_2(struct va1j5jf8007s_state *state)
+{
+	u8 buf[3];
+	struct i2c_msg msg;
+
+	buf[0] = 0xfe;
+	buf[1] = 0xc0;
+	buf[2] = 0xe4;
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.len = sizeof(buf);
+	msg.buf = buf;
+
+	if (i2c_transfer(state->adap, &msg, 1) != 1)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int va1j5jf8007s_set_frequency_3(struct va1j5jf8007s_state *state)
+{
+	u32 frequency;
+	u8 buf[4];
+	struct i2c_msg msg;
+
+	frequency = state->fe.dtv_property_cache.frequency;
+
+	buf[0] = 0xfe;
+	buf[1] = 0xc0;
+	buf[2] = 0xf4;
+	buf[3] = va1j5jf8007s_lookup_cb(frequency) | 0x4;
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.len = sizeof(buf);
+	msg.buf = buf;
+
+	if (i2c_transfer(state->adap, &msg, 1) != 1)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int
+va1j5jf8007s_check_frequency(struct va1j5jf8007s_state *state, int *lock)
+{
+	u8 addr;
+	u8 write_buf[2], read_buf[1];
+	struct i2c_msg msgs[2];
+
+	addr = state->config->demod_address;
+
+	write_buf[0] = 0xfe;
+	write_buf[1] = 0xc1;
+
+	msgs[0].addr = addr;
+	msgs[0].flags = 0;
+	msgs[0].len = sizeof(write_buf);
+	msgs[0].buf = write_buf;
+
+	msgs[1].addr = addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = sizeof(read_buf);
+	msgs[1].buf = read_buf;
+
+	if (i2c_transfer(state->adap, msgs, 2) != 2)
+		return -EREMOTEIO;
+
+	*lock = read_buf[0] & 0x40;
+	return 0;
+}
+
+static int va1j5jf8007s_set_modulation(struct va1j5jf8007s_state *state)
+{
+	u8 buf[2];
+	struct i2c_msg msg;
+
+	buf[0] = 0x03;
+	buf[1] = 0x01;
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.len = sizeof(buf);
+	msg.buf = buf;
+
+	if (i2c_transfer(state->adap, &msg, 1) != 1)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int
+va1j5jf8007s_check_modulation(struct va1j5jf8007s_state *state, int *lock)
+{
+	u8 addr;
+	u8 write_buf[1], read_buf[1];
+	struct i2c_msg msgs[2];
+
+	addr = state->config->demod_address;
+
+	write_buf[0] = 0xc3;
+
+	msgs[0].addr = addr;
+	msgs[0].flags = 0;
+	msgs[0].len = sizeof(write_buf);
+	msgs[0].buf = write_buf;
+
+	msgs[1].addr = addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = sizeof(read_buf);
+	msgs[1].buf = read_buf;
+
+	if (i2c_transfer(state->adap, msgs, 2) != 2)
+		return -EREMOTEIO;
+
+	*lock = !(read_buf[0] & 0x10);
+	return 0;
+}
+
+static int
+va1j5jf8007s_set_ts_id(struct va1j5jf8007s_state *state)
+{
+	u32 ts_id;
+	u8 buf[3];
+	struct i2c_msg msg;
+
+	ts_id = state->fe.dtv_property_cache.isdbs_ts_id;
+	if (!ts_id)
+		return 0;
+
+	buf[0] = 0x8f;
+	buf[1] = ts_id >> 8;
+	buf[2] = ts_id;
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.len = sizeof(buf);
+	msg.buf = buf;
+
+	if (i2c_transfer(state->adap, &msg, 1) != 1)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int
+va1j5jf8007s_check_ts_id(struct va1j5jf8007s_state *state, int *lock)
+{
+	u8 addr;
+	u8 write_buf[1], read_buf[2];
+	struct i2c_msg msgs[2];
+	u32 ts_id;
+
+	ts_id = state->fe.dtv_property_cache.isdbs_ts_id;
+	if (!ts_id) {
+		*lock = 1;
+		return 0;
+	}
+
+	addr = state->config->demod_address;
+
+	write_buf[0] = 0xe6;
+
+	msgs[0].addr = addr;
+	msgs[0].flags = 0;
+	msgs[0].len = sizeof(write_buf);
+	msgs[0].buf = write_buf;
+
+	msgs[1].addr = addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = sizeof(read_buf);
+	msgs[1].buf = read_buf;
+
+	if (i2c_transfer(state->adap, msgs, 2) != 2)
+		return -EREMOTEIO;
+
+	*lock = (read_buf[0] << 8 | read_buf[1]) == ts_id;
+	return 0;
+}
+
+static int
+va1j5jf8007s_tune(struct dvb_frontend *fe,
+		  bool re_tune,
+		  unsigned int mode_flags,  unsigned int *delay,
+		  fe_status_t *status)
+{
+	struct va1j5jf8007s_state *state;
+	int ret;
+	int lock = 0;
+
+	state = fe->demodulator_priv;
+
+	if (re_tune)
+		state->tune_state = VA1J5JF8007S_SET_FREQUENCY_1;
+
+	switch (state->tune_state) {
+	case VA1J5JF8007S_IDLE:
+		*delay = 3 * HZ;
+		*status = 0;
+		return 0;
+
+	case VA1J5JF8007S_SET_FREQUENCY_1:
+		ret = va1j5jf8007s_set_frequency_1(state);
+		if (ret < 0)
+			return ret;
+
+		state->tune_state = VA1J5JF8007S_SET_FREQUENCY_2;
+		*delay = 0;
+		*status = 0;
+		return 0;
+
+	case VA1J5JF8007S_SET_FREQUENCY_2:
+		ret = va1j5jf8007s_set_frequency_2(state);
+		if (ret < 0)
+			return ret;
+
+		state->tune_state = VA1J5JF8007S_SET_FREQUENCY_3;
+		*delay = (HZ + 99) / 100;
+		*status = 0;
+		return 0;
+
+	case VA1J5JF8007S_SET_FREQUENCY_3:
+		ret = va1j5jf8007s_set_frequency_3(state);
+		if (ret < 0)
+			return ret;
+
+		state->tune_state = VA1J5JF8007S_CHECK_FREQUENCY;
+		*delay = 0;
+		*status = 0;
+		return 0;
+
+	case VA1J5JF8007S_CHECK_FREQUENCY:
+		ret = va1j5jf8007s_check_frequency(state, &lock);
+		if (ret < 0)
+			return ret;
+
+		if (!lock)  {
+			*delay = (HZ + 999) / 1000;
+			*status = 0;
+			return 0;
+		}
+
+		state->tune_state = VA1J5JF8007S_SET_MODULATION;
+		*delay = 0;
+		*status = FE_HAS_SIGNAL;
+		return 0;
+
+	case VA1J5JF8007S_SET_MODULATION:
+		ret = va1j5jf8007s_set_modulation(state);
+		if (ret < 0)
+			return ret;
+
+		state->tune_state = VA1J5JF8007S_CHECK_MODULATION;
+		*delay = 0;
+		*status = FE_HAS_SIGNAL;
+		return 0;
+
+	case VA1J5JF8007S_CHECK_MODULATION:
+		ret = va1j5jf8007s_check_modulation(state, &lock);
+		if (ret < 0)
+			return ret;
+
+		if (!lock)  {
+			*delay = (HZ + 49) / 50;
+			*status = FE_HAS_SIGNAL;
+			return 0;
+		}
+
+		state->tune_state = VA1J5JF8007S_SET_TS_ID;
+		*delay = 0;
+		*status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
+		return 0;
+
+	case VA1J5JF8007S_SET_TS_ID:
+		ret = va1j5jf8007s_set_ts_id(state);
+		if (ret < 0)
+			return ret;
+
+		state->tune_state = VA1J5JF8007S_CHECK_TS_ID;
+		return 0;
+
+	case VA1J5JF8007S_CHECK_TS_ID:
+		ret = va1j5jf8007s_check_ts_id(state, &lock);
+		if (ret < 0)
+			return ret;
+
+		if (!lock)  {
+			*delay = (HZ + 99) / 100;
+			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
+			return 0;
+		}
+
+		state->tune_state = VA1J5JF8007S_TRACK;
+		/* fall through */
+
+	case VA1J5JF8007S_TRACK:
+		*delay = 3 * HZ;
+		*status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
+		return 0;
+	}
+
+	BUG();
+}
+
+static int va1j5jf8007s_init_frequency(struct va1j5jf8007s_state *state)
+{
+	u8 buf[4];
+	struct i2c_msg msg;
+
+	buf[0] = 0xfe;
+	buf[1] = 0xc0;
+	buf[2] = 0xf0;
+	buf[3] = 0x04;
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.len = sizeof(buf);
+	msg.buf = buf;
+
+	if (i2c_transfer(state->adap, &msg, 1) != 1)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int va1j5jf8007s_set_sleep(struct va1j5jf8007s_state *state, int sleep)
+{
+	u8 buf[2];
+	struct i2c_msg msg;
+
+	buf[0] = 0x17;
+	buf[1] = sleep ? 0x01 : 0x00;
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.len = sizeof(buf);
+	msg.buf = buf;
+
+	if (i2c_transfer(state->adap, &msg, 1) != 1)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int va1j5jf8007s_sleep(struct dvb_frontend *fe)
+{
+	struct va1j5jf8007s_state *state;
+	int ret;
+
+	state = fe->demodulator_priv;
+
+	ret = va1j5jf8007s_init_frequency(state);
+	if (ret < 0)
+		return ret;
+
+	return va1j5jf8007s_set_sleep(state, 1);
+}
+
+static int va1j5jf8007s_init(struct dvb_frontend *fe)
+{
+	struct va1j5jf8007s_state *state;
+
+	state = fe->demodulator_priv;
+	state->tune_state = VA1J5JF8007S_IDLE;
+
+	return va1j5jf8007s_set_sleep(state, 0);
+}
+
+static void va1j5jf8007s_release(struct dvb_frontend *fe)
+{
+	struct va1j5jf8007s_state *state;
+	state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops va1j5jf8007s_ops = {
+	.delsys = { SYS_ISDBS },
+	.info = {
+		.name = "VA1J5JF8007/VA1J5JF8011 ISDB-S",
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		.frequency_stepsize = 1000,
+		.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO |
+			FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.read_snr = va1j5jf8007s_read_snr,
+	.get_frontend_algo = va1j5jf8007s_get_frontend_algo,
+	.read_status = va1j5jf8007s_read_status,
+	.tune = va1j5jf8007s_tune,
+	.sleep = va1j5jf8007s_sleep,
+	.init = va1j5jf8007s_init,
+	.release = va1j5jf8007s_release,
+};
+
+static int va1j5jf8007s_prepare_1(struct va1j5jf8007s_state *state)
+{
+	u8 addr;
+	u8 write_buf[1], read_buf[1];
+	struct i2c_msg msgs[2];
+
+	addr = state->config->demod_address;
+
+	write_buf[0] = 0x07;
+
+	msgs[0].addr = addr;
+	msgs[0].flags = 0;
+	msgs[0].len = sizeof(write_buf);
+	msgs[0].buf = write_buf;
+
+	msgs[1].addr = addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = sizeof(read_buf);
+	msgs[1].buf = read_buf;
+
+	if (i2c_transfer(state->adap, msgs, 2) != 2)
+		return -EREMOTEIO;
+
+	if (read_buf[0] != 0x41)
+		return -EIO;
+
+	return 0;
+}
+
+static const u8 va1j5jf8007s_20mhz_prepare_bufs[][2] = {
+	{0x04, 0x02}, {0x0d, 0x55}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01},
+	{0x1c, 0x0a}, {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0},
+	{0x52, 0x89}, {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69},
+	{0x87, 0x04}, {0x8e, 0x02}, {0xa3, 0xf7}, {0xa5, 0xc0},
+};
+
+static const u8 va1j5jf8007s_25mhz_prepare_bufs[][2] = {
+	{0x04, 0x02}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, {0x1c, 0x0a},
+	{0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, {0x52, 0x89},
+	{0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, {0x87, 0x04},
+	{0x8e, 0x26}, {0xa3, 0xf7}, {0xa5, 0xc0},
+};
+
+static int va1j5jf8007s_prepare_2(struct va1j5jf8007s_state *state)
+{
+	const u8 (*bufs)[2];
+	int size;
+	u8 addr;
+	u8 buf[2];
+	struct i2c_msg msg;
+	int i;
+
+	switch (state->config->frequency) {
+	case VA1J5JF8007S_20MHZ:
+		bufs = va1j5jf8007s_20mhz_prepare_bufs;
+		size = ARRAY_SIZE(va1j5jf8007s_20mhz_prepare_bufs);
+		break;
+	case VA1J5JF8007S_25MHZ:
+		bufs = va1j5jf8007s_25mhz_prepare_bufs;
+		size = ARRAY_SIZE(va1j5jf8007s_25mhz_prepare_bufs);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	addr = state->config->demod_address;
+
+	msg.addr = addr;
+	msg.flags = 0;
+	msg.len = 2;
+	msg.buf = buf;
+	for (i = 0; i < size; i++) {
+		memcpy(buf, bufs[i], sizeof(buf));
+		if (i2c_transfer(state->adap, &msg, 1) != 1)
+			return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+/* must be called after va1j5jf8007t_attach */
+int va1j5jf8007s_prepare(struct dvb_frontend *fe)
+{
+	struct va1j5jf8007s_state *state;
+	int ret;
+
+	state = fe->demodulator_priv;
+
+	ret = va1j5jf8007s_prepare_1(state);
+	if (ret < 0)
+		return ret;
+
+	ret = va1j5jf8007s_prepare_2(state);
+	if (ret < 0)
+		return ret;
+
+	return va1j5jf8007s_init_frequency(state);
+}
+
+struct dvb_frontend *
+va1j5jf8007s_attach(const struct va1j5jf8007s_config *config,
+		    struct i2c_adapter *adap)
+{
+	struct va1j5jf8007s_state *state;
+	struct dvb_frontend *fe;
+	u8 buf[2];
+	struct i2c_msg msg;
+
+	state = kzalloc(sizeof(struct va1j5jf8007s_state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	state->config = config;
+	state->adap = adap;
+
+	fe = &state->fe;
+	memcpy(&fe->ops, &va1j5jf8007s_ops, sizeof(struct dvb_frontend_ops));
+	fe->demodulator_priv = state;
+
+	buf[0] = 0x01;
+	buf[1] = 0x80;
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.len = sizeof(buf);
+	msg.buf = buf;
+
+	if (i2c_transfer(state->adap, &msg, 1) != 1) {
+		kfree(state);
+		return NULL;
+	}
+
+	return fe;
+}
diff --git a/drivers/media/pci/pt1/va1j5jf8007s.h b/drivers/media/pci/pt1/va1j5jf8007s.h
new file mode 100644
index 0000000..b7d6f05
--- /dev/null
+++ b/drivers/media/pci/pt1/va1j5jf8007s.h
@@ -0,0 +1,46 @@
+/*
+ * ISDB-S driver for VA1J5JF8007/VA1J5JF8011
+ *
+ * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
+ *
+ * based on pt1dvr - http://pt1dvr.sourceforge.jp/
+ * 	by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef VA1J5JF8007S_H
+#define VA1J5JF8007S_H
+
+enum va1j5jf8007s_frequency {
+	VA1J5JF8007S_20MHZ,
+	VA1J5JF8007S_25MHZ,
+};
+
+struct va1j5jf8007s_config {
+	u8 demod_address;
+	enum va1j5jf8007s_frequency frequency;
+};
+
+struct i2c_adapter;
+
+struct dvb_frontend *
+va1j5jf8007s_attach(const struct va1j5jf8007s_config *config,
+		    struct i2c_adapter *adap);
+
+/* must be called after va1j5jf8007t_attach */
+int va1j5jf8007s_prepare(struct dvb_frontend *fe);
+
+#endif
diff --git a/drivers/media/pci/pt1/va1j5jf8007t.c b/drivers/media/pci/pt1/va1j5jf8007t.c
new file mode 100644
index 0000000..2db15159
--- /dev/null
+++ b/drivers/media/pci/pt1/va1j5jf8007t.c
@@ -0,0 +1,536 @@
+/*
+ * ISDB-T driver for VA1J5JF8007/VA1J5JF8011
+ *
+ * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
+ *
+ * based on pt1dvr - http://pt1dvr.sourceforge.jp/
+ * 	by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+#include "dvb_math.h"
+#include "va1j5jf8007t.h"
+
+enum va1j5jf8007t_tune_state {
+	VA1J5JF8007T_IDLE,
+	VA1J5JF8007T_SET_FREQUENCY,
+	VA1J5JF8007T_CHECK_FREQUENCY,
+	VA1J5JF8007T_SET_MODULATION,
+	VA1J5JF8007T_CHECK_MODULATION,
+	VA1J5JF8007T_TRACK,
+	VA1J5JF8007T_ABORT,
+};
+
+struct va1j5jf8007t_state {
+	const struct va1j5jf8007t_config *config;
+	struct i2c_adapter *adap;
+	struct dvb_frontend fe;
+	enum va1j5jf8007t_tune_state tune_state;
+};
+
+static int va1j5jf8007t_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct va1j5jf8007t_state *state;
+	u8 addr;
+	int i;
+	u8 write_buf[1], read_buf[1];
+	struct i2c_msg msgs[2];
+	s32 word, x, y;
+
+	state = fe->demodulator_priv;
+	addr = state->config->demod_address;
+
+	word = 0;
+	for (i = 0; i < 3; i++) {
+		write_buf[0] = 0x8b + i;
+
+		msgs[0].addr = addr;
+		msgs[0].flags = 0;
+		msgs[0].len = sizeof(write_buf);
+		msgs[0].buf = write_buf;
+
+		msgs[1].addr = addr;
+		msgs[1].flags = I2C_M_RD;
+		msgs[1].len = sizeof(read_buf);
+		msgs[1].buf = read_buf;
+
+		if (i2c_transfer(state->adap, msgs, 2) != 2)
+			return -EREMOTEIO;
+
+		word <<= 8;
+		word |= read_buf[0];
+	}
+
+	if (!word)
+		return -EIO;
+
+	x = 10 * (intlog10(0x540000 * 100 / word) - (2 << 24));
+	y = (24ll << 46) / 1000000;
+	y = ((s64)y * x >> 30) - (16ll << 40) / 10000;
+	y = ((s64)y * x >> 29) + (398ll << 35) / 10000;
+	y = ((s64)y * x >> 30) + (5491ll << 29) / 10000;
+	y = ((s64)y * x >> 30) + (30965ll << 23) / 10000;
+	*snr = y >> 15;
+	return 0;
+}
+
+static int va1j5jf8007t_get_frontend_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_HW;
+}
+
+static int
+va1j5jf8007t_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct va1j5jf8007t_state *state;
+
+	state = fe->demodulator_priv;
+
+	switch (state->tune_state) {
+	case VA1J5JF8007T_IDLE:
+	case VA1J5JF8007T_SET_FREQUENCY:
+	case VA1J5JF8007T_CHECK_FREQUENCY:
+		*status = 0;
+		return 0;
+
+
+	case VA1J5JF8007T_SET_MODULATION:
+	case VA1J5JF8007T_CHECK_MODULATION:
+	case VA1J5JF8007T_ABORT:
+		*status |= FE_HAS_SIGNAL;
+		return 0;
+
+	case VA1J5JF8007T_TRACK:
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
+		return 0;
+	}
+
+	BUG();
+}
+
+struct va1j5jf8007t_cb_map {
+	u32 frequency;
+	u8 cb;
+};
+
+static const struct va1j5jf8007t_cb_map va1j5jf8007t_cb_maps[] = {
+	{  90000000, 0x80 },
+	{ 140000000, 0x81 },
+	{ 170000000, 0xa1 },
+	{ 220000000, 0x62 },
+	{ 330000000, 0xa2 },
+	{ 402000000, 0xe2 },
+	{ 450000000, 0x64 },
+	{ 550000000, 0x84 },
+	{ 600000000, 0xa4 },
+	{ 700000000, 0xc4 },
+};
+
+static u8 va1j5jf8007t_lookup_cb(u32 frequency)
+{
+	int i;
+	const struct va1j5jf8007t_cb_map *map;
+
+	for (i = 0; i < ARRAY_SIZE(va1j5jf8007t_cb_maps); i++) {
+		map = &va1j5jf8007t_cb_maps[i];
+		if (frequency < map->frequency)
+			return map->cb;
+	}
+	return 0xe4;
+}
+
+static int va1j5jf8007t_set_frequency(struct va1j5jf8007t_state *state)
+{
+	u32 frequency;
+	u16 word;
+	u8 buf[6];
+	struct i2c_msg msg;
+
+	frequency = state->fe.dtv_property_cache.frequency;
+
+	word = (frequency + 71428) / 142857 + 399;
+	buf[0] = 0xfe;
+	buf[1] = 0xc2;
+	buf[2] = word >> 8;
+	buf[3] = word;
+	buf[4] = 0x80;
+	buf[5] = va1j5jf8007t_lookup_cb(frequency);
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.len = sizeof(buf);
+	msg.buf = buf;
+
+	if (i2c_transfer(state->adap, &msg, 1) != 1)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int
+va1j5jf8007t_check_frequency(struct va1j5jf8007t_state *state, int *lock)
+{
+	u8 addr;
+	u8 write_buf[2], read_buf[1];
+	struct i2c_msg msgs[2];
+
+	addr = state->config->demod_address;
+
+	write_buf[0] = 0xfe;
+	write_buf[1] = 0xc3;
+
+	msgs[0].addr = addr;
+	msgs[0].flags = 0;
+	msgs[0].len = sizeof(write_buf);
+	msgs[0].buf = write_buf;
+
+	msgs[1].addr = addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = sizeof(read_buf);
+	msgs[1].buf = read_buf;
+
+	if (i2c_transfer(state->adap, msgs, 2) != 2)
+		return -EREMOTEIO;
+
+	*lock = read_buf[0] & 0x40;
+	return 0;
+}
+
+static int va1j5jf8007t_set_modulation(struct va1j5jf8007t_state *state)
+{
+	u8 buf[2];
+	struct i2c_msg msg;
+
+	buf[0] = 0x01;
+	buf[1] = 0x40;
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.len = sizeof(buf);
+	msg.buf = buf;
+
+	if (i2c_transfer(state->adap, &msg, 1) != 1)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int va1j5jf8007t_check_modulation(struct va1j5jf8007t_state *state,
+					 int *lock, int *retry)
+{
+	u8 addr;
+	u8 write_buf[1], read_buf[1];
+	struct i2c_msg msgs[2];
+
+	addr = state->config->demod_address;
+
+	write_buf[0] = 0x80;
+
+	msgs[0].addr = addr;
+	msgs[0].flags = 0;
+	msgs[0].len = sizeof(write_buf);
+	msgs[0].buf = write_buf;
+
+	msgs[1].addr = addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = sizeof(read_buf);
+	msgs[1].buf = read_buf;
+
+	if (i2c_transfer(state->adap, msgs, 2) != 2)
+		return -EREMOTEIO;
+
+	*lock = !(read_buf[0] & 0x10);
+	*retry = read_buf[0] & 0x80;
+	return 0;
+}
+
+static int
+va1j5jf8007t_tune(struct dvb_frontend *fe,
+		  bool re_tune,
+		  unsigned int mode_flags,  unsigned int *delay,
+		  fe_status_t *status)
+{
+	struct va1j5jf8007t_state *state;
+	int ret;
+	int lock = 0, retry = 0;
+
+	state = fe->demodulator_priv;
+
+	if (re_tune)
+		state->tune_state = VA1J5JF8007T_SET_FREQUENCY;
+
+	switch (state->tune_state) {
+	case VA1J5JF8007T_IDLE:
+		*delay = 3 * HZ;
+		*status = 0;
+		return 0;
+
+	case VA1J5JF8007T_SET_FREQUENCY:
+		ret = va1j5jf8007t_set_frequency(state);
+		if (ret < 0)
+			return ret;
+
+		state->tune_state = VA1J5JF8007T_CHECK_FREQUENCY;
+		*delay = 0;
+		*status = 0;
+		return 0;
+
+	case VA1J5JF8007T_CHECK_FREQUENCY:
+		ret = va1j5jf8007t_check_frequency(state, &lock);
+		if (ret < 0)
+			return ret;
+
+		if (!lock)  {
+			*delay = (HZ + 999) / 1000;
+			*status = 0;
+			return 0;
+		}
+
+		state->tune_state = VA1J5JF8007T_SET_MODULATION;
+		*delay = 0;
+		*status = FE_HAS_SIGNAL;
+		return 0;
+
+	case VA1J5JF8007T_SET_MODULATION:
+		ret = va1j5jf8007t_set_modulation(state);
+		if (ret < 0)
+			return ret;
+
+		state->tune_state = VA1J5JF8007T_CHECK_MODULATION;
+		*delay = 0;
+		*status = FE_HAS_SIGNAL;
+		return 0;
+
+	case VA1J5JF8007T_CHECK_MODULATION:
+		ret = va1j5jf8007t_check_modulation(state, &lock, &retry);
+		if (ret < 0)
+			return ret;
+
+		if (!lock)  {
+			if (!retry)  {
+				state->tune_state = VA1J5JF8007T_ABORT;
+				*delay = 3 * HZ;
+				*status = FE_HAS_SIGNAL;
+				return 0;
+			}
+			*delay = (HZ + 999) / 1000;
+			*status = FE_HAS_SIGNAL;
+			return 0;
+		}
+
+		state->tune_state = VA1J5JF8007T_TRACK;
+		/* fall through */
+
+	case VA1J5JF8007T_TRACK:
+		*delay = 3 * HZ;
+		*status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
+		return 0;
+
+	case VA1J5JF8007T_ABORT:
+		*delay = 3 * HZ;
+		*status = FE_HAS_SIGNAL;
+		return 0;
+	}
+
+	BUG();
+}
+
+static int va1j5jf8007t_init_frequency(struct va1j5jf8007t_state *state)
+{
+	u8 buf[7];
+	struct i2c_msg msg;
+
+	buf[0] = 0xfe;
+	buf[1] = 0xc2;
+	buf[2] = 0x01;
+	buf[3] = 0x8f;
+	buf[4] = 0xc1;
+	buf[5] = 0x80;
+	buf[6] = 0x80;
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.len = sizeof(buf);
+	msg.buf = buf;
+
+	if (i2c_transfer(state->adap, &msg, 1) != 1)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int va1j5jf8007t_set_sleep(struct va1j5jf8007t_state *state, int sleep)
+{
+	u8 buf[2];
+	struct i2c_msg msg;
+
+	buf[0] = 0x03;
+	buf[1] = sleep ? 0x90 : 0x80;
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.len = sizeof(buf);
+	msg.buf = buf;
+
+	if (i2c_transfer(state->adap, &msg, 1) != 1)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int va1j5jf8007t_sleep(struct dvb_frontend *fe)
+{
+	struct va1j5jf8007t_state *state;
+	int ret;
+
+	state = fe->demodulator_priv;
+
+	ret = va1j5jf8007t_init_frequency(state);
+	if (ret < 0)
+		return ret;
+
+	return va1j5jf8007t_set_sleep(state, 1);
+}
+
+static int va1j5jf8007t_init(struct dvb_frontend *fe)
+{
+	struct va1j5jf8007t_state *state;
+
+	state = fe->demodulator_priv;
+	state->tune_state = VA1J5JF8007T_IDLE;
+
+	return va1j5jf8007t_set_sleep(state, 0);
+}
+
+static void va1j5jf8007t_release(struct dvb_frontend *fe)
+{
+	struct va1j5jf8007t_state *state;
+	state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops va1j5jf8007t_ops = {
+	.delsys = { SYS_ISDBT },
+	.info = {
+		.name = "VA1J5JF8007/VA1J5JF8011 ISDB-T",
+		.frequency_min = 90000000,
+		.frequency_max = 770000000,
+		.frequency_stepsize = 142857,
+		.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO |
+			FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.read_snr = va1j5jf8007t_read_snr,
+	.get_frontend_algo = va1j5jf8007t_get_frontend_algo,
+	.read_status = va1j5jf8007t_read_status,
+	.tune = va1j5jf8007t_tune,
+	.sleep = va1j5jf8007t_sleep,
+	.init = va1j5jf8007t_init,
+	.release = va1j5jf8007t_release,
+};
+
+static const u8 va1j5jf8007t_20mhz_prepare_bufs[][2] = {
+	{0x03, 0x90}, {0x14, 0x8f}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2},
+	{0x22, 0x83}, {0x31, 0x0d}, {0x32, 0xe0}, {0x39, 0xd3}, {0x3a, 0x00},
+	{0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x02}, {0x76, 0x4e}, {0x77, 0x03},
+	{0xef, 0x01}
+};
+
+static const u8 va1j5jf8007t_25mhz_prepare_bufs[][2] = {
+	{0x03, 0x90}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, {0x22, 0x83},
+	{0x3a, 0x00}, {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x0a}, {0x76, 0x4c},
+	{0x77, 0x03}, {0xef, 0x01}
+};
+
+int va1j5jf8007t_prepare(struct dvb_frontend *fe)
+{
+	struct va1j5jf8007t_state *state;
+	const u8 (*bufs)[2];
+	int size;
+	u8 buf[2];
+	struct i2c_msg msg;
+	int i;
+
+	state = fe->demodulator_priv;
+
+	switch (state->config->frequency) {
+	case VA1J5JF8007T_20MHZ:
+		bufs = va1j5jf8007t_20mhz_prepare_bufs;
+		size = ARRAY_SIZE(va1j5jf8007t_20mhz_prepare_bufs);
+		break;
+	case VA1J5JF8007T_25MHZ:
+		bufs = va1j5jf8007t_25mhz_prepare_bufs;
+		size = ARRAY_SIZE(va1j5jf8007t_25mhz_prepare_bufs);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.len = sizeof(buf);
+	msg.buf = buf;
+
+	for (i = 0; i < size; i++) {
+		memcpy(buf, bufs[i], sizeof(buf));
+		if (i2c_transfer(state->adap, &msg, 1) != 1)
+			return -EREMOTEIO;
+	}
+
+	return va1j5jf8007t_init_frequency(state);
+}
+
+struct dvb_frontend *
+va1j5jf8007t_attach(const struct va1j5jf8007t_config *config,
+		    struct i2c_adapter *adap)
+{
+	struct va1j5jf8007t_state *state;
+	struct dvb_frontend *fe;
+	u8 buf[2];
+	struct i2c_msg msg;
+
+	state = kzalloc(sizeof(struct va1j5jf8007t_state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	state->config = config;
+	state->adap = adap;
+
+	fe = &state->fe;
+	memcpy(&fe->ops, &va1j5jf8007t_ops, sizeof(struct dvb_frontend_ops));
+	fe->demodulator_priv = state;
+
+	buf[0] = 0x01;
+	buf[1] = 0x80;
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.len = sizeof(buf);
+	msg.buf = buf;
+
+	if (i2c_transfer(state->adap, &msg, 1) != 1) {
+		kfree(state);
+		return NULL;
+	}
+
+	return fe;
+}
diff --git a/drivers/media/pci/pt1/va1j5jf8007t.h b/drivers/media/pci/pt1/va1j5jf8007t.h
new file mode 100644
index 0000000..2903be5
--- /dev/null
+++ b/drivers/media/pci/pt1/va1j5jf8007t.h
@@ -0,0 +1,46 @@
+/*
+ * ISDB-T driver for VA1J5JF8007/VA1J5JF8011
+ *
+ * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
+ *
+ * based on pt1dvr - http://pt1dvr.sourceforge.jp/
+ * 	by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef VA1J5JF8007T_H
+#define VA1J5JF8007T_H
+
+enum va1j5jf8007t_frequency {
+	VA1J5JF8007T_20MHZ,
+	VA1J5JF8007T_25MHZ,
+};
+
+struct va1j5jf8007t_config {
+	u8 demod_address;
+	enum va1j5jf8007t_frequency frequency;
+};
+
+struct i2c_adapter;
+
+struct dvb_frontend *
+va1j5jf8007t_attach(const struct va1j5jf8007t_config *config,
+		    struct i2c_adapter *adap);
+
+/* must be called after va1j5jf8007s_attach */
+int va1j5jf8007t_prepare(struct dvb_frontend *fe);
+
+#endif
diff --git a/drivers/media/pci/saa7134/Kconfig b/drivers/media/pci/saa7134/Kconfig
new file mode 100644
index 0000000..39fc018
--- /dev/null
+++ b/drivers/media/pci/saa7134/Kconfig
@@ -0,0 +1,64 @@
+config VIDEO_SAA7134
+	tristate "Philips SAA7134 support"
+	depends on VIDEO_DEV && PCI && I2C
+	select VIDEOBUF_DMA_SG
+	select VIDEO_TUNER
+	select VIDEO_TVEEPROM
+	select CRC32
+	select VIDEO_SAA6588 if VIDEO_HELPER_CHIPS_AUTO
+	---help---
+	  This is a video4linux driver for Philips SAA713x based
+	  TV cards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7134.
+
+config VIDEO_SAA7134_ALSA
+	tristate "Philips SAA7134 DMA audio support"
+	depends on VIDEO_SAA7134 && SND
+	select SND_PCM
+	---help---
+	  This is a video4linux driver for direct (DMA) audio in
+	  Philips SAA713x based TV cards using ALSA
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7134-alsa.
+
+config VIDEO_SAA7134_RC
+	bool "Philips SAA7134 Remote Controller support"
+	depends on RC_CORE
+	depends on VIDEO_SAA7134
+	depends on !(RC_CORE=m && VIDEO_SAA7134=y)
+	default y
+	---help---
+	  Enables Remote Controller support on saa7134 driver.
+
+config VIDEO_SAA7134_DVB
+	tristate "DVB/ATSC Support for saa7134 based TV cards"
+	depends on VIDEO_SAA7134 && DVB_CORE
+	select VIDEOBUF_DVB
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select DVB_MT352 if !DVB_FE_CUSTOMISE
+	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+	select DVB_NXT200X if !DVB_FE_CUSTOMISE
+	select DVB_TDA10086 if !DVB_FE_CUSTOMISE
+	select DVB_TDA826X if !DVB_FE_CUSTOMISE
+	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
+	select DVB_ISL6405 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
+	select DVB_ZL10036 if !DVB_FE_CUSTOMISE
+	select DVB_MT312 if !DVB_FE_CUSTOMISE
+	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10048 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
+	select DVB_ZL10039 if !DVB_FE_CUSTOMISE
+	---help---
+	  This adds support for DVB cards based on the
+	  Philips saa7134 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7134-dvb.
diff --git a/drivers/media/pci/saa7134/Makefile b/drivers/media/pci/saa7134/Makefile
new file mode 100644
index 0000000..3537548
--- /dev/null
+++ b/drivers/media/pci/saa7134/Makefile
@@ -0,0 +1,16 @@
+
+saa7134-y +=	saa7134-cards.o saa7134-core.o saa7134-i2c.o
+saa7134-y +=	saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o
+saa7134-y +=	saa7134-video.o
+saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o
+
+obj-$(CONFIG_VIDEO_SAA7134) +=  saa6752hs.o saa7134.o saa7134-empress.o
+
+obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
+
+obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
+
+ccflags-y += -I$(srctree)/drivers/media/i2c
+ccflags-y += -I$(srctree)/drivers/media/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
diff --git a/drivers/media/pci/saa7134/saa6752hs.c b/drivers/media/pci/saa7134/saa6752hs.c
new file mode 100644
index 0000000..f147b05
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa6752hs.c
@@ -0,0 +1,1012 @@
+ /*
+    saa6752hs - i2c-driver for the saa6752hs by Philips
+
+    Copyright (C) 2004 Andrew de Quincey
+
+    AC-3 support:
+
+    Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License vs published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mvss Ave, Cambridge, MA 02139, USA.
+  */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+
+#define MPEG_VIDEO_TARGET_BITRATE_MAX  27000
+#define MPEG_VIDEO_MAX_BITRATE_MAX     27000
+#define MPEG_TOTAL_TARGET_BITRATE_MAX  27000
+#define MPEG_PID_MAX ((1 << 14) - 1)
+
+
+MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder");
+MODULE_AUTHOR("Andrew de Quincey");
+MODULE_LICENSE("GPL");
+
+enum saa6752hs_videoformat {
+	SAA6752HS_VF_D1 = 0,    /* standard D1 video format: 720x576 */
+	SAA6752HS_VF_2_3_D1 = 1,/* 2/3D1 video format: 480x576 */
+	SAA6752HS_VF_1_2_D1 = 2,/* 1/2D1 video format: 352x576 */
+	SAA6752HS_VF_SIF = 3,   /* SIF video format: 352x288 */
+	SAA6752HS_VF_UNKNOWN,
+};
+
+struct saa6752hs_mpeg_params {
+	/* transport streams */
+	__u16				ts_pid_pmt;
+	__u16				ts_pid_audio;
+	__u16				ts_pid_video;
+	__u16				ts_pid_pcr;
+
+	/* audio */
+	enum v4l2_mpeg_audio_encoding    au_encoding;
+	enum v4l2_mpeg_audio_l2_bitrate  au_l2_bitrate;
+	enum v4l2_mpeg_audio_ac3_bitrate au_ac3_bitrate;
+
+	/* video */
+	enum v4l2_mpeg_video_aspect	vi_aspect;
+	enum v4l2_mpeg_video_bitrate_mode vi_bitrate_mode;
+	__u32 				vi_bitrate;
+	__u32 				vi_bitrate_peak;
+};
+
+static const struct v4l2_format v4l2_format_table[] =
+{
+	[SAA6752HS_VF_D1] =
+		{ .fmt = { .pix = { .width = 720, .height = 576 }}},
+	[SAA6752HS_VF_2_3_D1] =
+		{ .fmt = { .pix = { .width = 480, .height = 576 }}},
+	[SAA6752HS_VF_1_2_D1] =
+		{ .fmt = { .pix = { .width = 352, .height = 576 }}},
+	[SAA6752HS_VF_SIF] =
+		{ .fmt = { .pix = { .width = 352, .height = 288 }}},
+	[SAA6752HS_VF_UNKNOWN] =
+		{ .fmt = { .pix = { .width = 0, .height = 0}}},
+};
+
+struct saa6752hs_state {
+	struct v4l2_subdev            sd;
+	int 			      chip;
+	u32 			      revision;
+	int 			      has_ac3;
+	struct saa6752hs_mpeg_params  params;
+	enum saa6752hs_videoformat    video_format;
+	v4l2_std_id                   standard;
+};
+
+enum saa6752hs_command {
+	SAA6752HS_COMMAND_RESET = 0,
+	SAA6752HS_COMMAND_STOP = 1,
+	SAA6752HS_COMMAND_START = 2,
+	SAA6752HS_COMMAND_PAUSE = 3,
+	SAA6752HS_COMMAND_RECONFIGURE = 4,
+	SAA6752HS_COMMAND_SLEEP = 5,
+	SAA6752HS_COMMAND_RECONFIGURE_FORCE = 6,
+
+	SAA6752HS_COMMAND_MAX
+};
+
+static inline struct saa6752hs_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct saa6752hs_state, sd);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static u8 PAT[] = {
+	0xc2, /* i2c register */
+	0x00, /* table number for encoder */
+
+	0x47, /* sync */
+	0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0) */
+	0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
+
+	0x00, /* PSI pointer to start of table */
+
+	0x00, /* tid(0) */
+	0xb0, 0x0d, /* section_syntax_indicator(1), section_length(13) */
+
+	0x00, 0x01, /* transport_stream_id(1) */
+
+	0xc1, /* version_number(0), current_next_indicator(1) */
+
+	0x00, 0x00, /* section_number(0), last_section_number(0) */
+
+	0x00, 0x01, /* program_number(1) */
+
+	0xe0, 0x00, /* PMT PID */
+
+	0x00, 0x00, 0x00, 0x00 /* CRC32 */
+};
+
+static u8 PMT[] = {
+	0xc2, /* i2c register */
+	0x01, /* table number for encoder */
+
+	0x47, /* sync */
+	0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid */
+	0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
+
+	0x00, /* PSI pointer to start of table */
+
+	0x02, /* tid(2) */
+	0xb0, 0x17, /* section_syntax_indicator(1), section_length(23) */
+
+	0x00, 0x01, /* program_number(1) */
+
+	0xc1, /* version_number(0), current_next_indicator(1) */
+
+	0x00, 0x00, /* section_number(0), last_section_number(0) */
+
+	0xe0, 0x00, /* PCR_PID */
+
+	0xf0, 0x00, /* program_info_length(0) */
+
+	0x02, 0xe0, 0x00, 0xf0, 0x00, /* video stream type(2), pid */
+	0x04, 0xe0, 0x00, 0xf0, 0x00, /* audio stream type(4), pid */
+
+	0x00, 0x00, 0x00, 0x00 /* CRC32 */
+};
+
+static u8 PMT_AC3[] = {
+	0xc2, /* i2c register */
+	0x01, /* table number for encoder(1) */
+	0x47, /* sync */
+
+	0x40, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0) */
+	0x10, /* PMT PID (0x0010) */
+	0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
+
+	0x00, /* PSI pointer to start of table */
+
+	0x02, /* TID (2) */
+	0xb0, 0x1a, /* section_syntax_indicator(1), section_length(26) */
+
+	0x00, 0x01, /* program_number(1) */
+
+	0xc1, /* version_number(0), current_next_indicator(1) */
+
+	0x00, 0x00, /* section_number(0), last_section_number(0) */
+
+	0xe1, 0x04, /* PCR_PID (0x0104) */
+
+	0xf0, 0x00, /* program_info_length(0) */
+
+	0x02, 0xe1, 0x00, 0xf0, 0x00, /* video stream type(2), pid */
+	0x06, 0xe1, 0x03, 0xf0, 0x03, /* audio stream type(6), pid */
+	0x6a, /* AC3 */
+	0x01, /* Descriptor_length(1) */
+	0x00, /* component_type_flag(0), bsid_flag(0), mainid_flag(0), asvc_flag(0), reserved flags(0) */
+
+	0xED, 0xDE, 0x2D, 0xF3 /* CRC32 BE */
+};
+
+static struct saa6752hs_mpeg_params param_defaults =
+{
+	.ts_pid_pmt      = 16,
+	.ts_pid_video    = 260,
+	.ts_pid_audio    = 256,
+	.ts_pid_pcr      = 259,
+
+	.vi_aspect       = V4L2_MPEG_VIDEO_ASPECT_4x3,
+	.vi_bitrate      = 4000,
+	.vi_bitrate_peak = 6000,
+	.vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+
+	.au_encoding     = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+	.au_l2_bitrate   = V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+	.au_ac3_bitrate  = V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
+};
+
+/* ---------------------------------------------------------------------- */
+
+static int saa6752hs_chip_command(struct i2c_client *client,
+				  enum saa6752hs_command command)
+{
+	unsigned char buf[3];
+	unsigned long timeout;
+	int status = 0;
+
+	/* execute the command */
+	switch(command) {
+	case SAA6752HS_COMMAND_RESET:
+		buf[0] = 0x00;
+		break;
+
+	case SAA6752HS_COMMAND_STOP:
+		buf[0] = 0x03;
+		break;
+
+	case SAA6752HS_COMMAND_START:
+		buf[0] = 0x02;
+		break;
+
+	case SAA6752HS_COMMAND_PAUSE:
+		buf[0] = 0x04;
+		break;
+
+	case SAA6752HS_COMMAND_RECONFIGURE:
+		buf[0] = 0x05;
+		break;
+
+	case SAA6752HS_COMMAND_SLEEP:
+		buf[0] = 0x06;
+		break;
+
+	case SAA6752HS_COMMAND_RECONFIGURE_FORCE:
+		buf[0] = 0x07;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* set it and wait for it to be so */
+	i2c_master_send(client, buf, 1);
+	timeout = jiffies + HZ * 3;
+	for (;;) {
+		/* get the current status */
+		buf[0] = 0x10;
+		i2c_master_send(client, buf, 1);
+		i2c_master_recv(client, buf, 1);
+
+		if (!(buf[0] & 0x20))
+			break;
+		if (time_after(jiffies,timeout)) {
+			status = -ETIMEDOUT;
+			break;
+		}
+
+		msleep(10);
+	}
+
+	/* delay a bit to let encoder settle */
+	msleep(50);
+
+	return status;
+}
+
+
+static inline void set_reg8(struct i2c_client *client, uint8_t reg, uint8_t val)
+{
+	u8 buf[2];
+
+	buf[0] = reg;
+	buf[1] = val;
+	i2c_master_send(client, buf, 2);
+}
+
+static inline void set_reg16(struct i2c_client *client, uint8_t reg, uint16_t val)
+{
+	u8 buf[3];
+
+	buf[0] = reg;
+	buf[1] = val >> 8;
+	buf[2] = val & 0xff;
+	i2c_master_send(client, buf, 3);
+}
+
+static int saa6752hs_set_bitrate(struct i2c_client *client,
+				 struct saa6752hs_state *h)
+{
+	struct saa6752hs_mpeg_params *params = &h->params;
+	int tot_bitrate;
+	int is_384k;
+
+	/* set the bitrate mode */
+	set_reg8(client, 0x71,
+		params->vi_bitrate_mode != V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+
+	/* set the video bitrate */
+	if (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
+		/* set the target bitrate */
+		set_reg16(client, 0x80, params->vi_bitrate);
+
+		/* set the max bitrate */
+		set_reg16(client, 0x81, params->vi_bitrate_peak);
+		tot_bitrate = params->vi_bitrate_peak;
+	} else {
+		/* set the target bitrate (no max bitrate for CBR) */
+		set_reg16(client, 0x81, params->vi_bitrate);
+		tot_bitrate = params->vi_bitrate;
+	}
+
+	/* set the audio encoding */
+	set_reg8(client, 0x93,
+			params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3);
+
+	/* set the audio bitrate */
+	if (params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3)
+		is_384k = V4L2_MPEG_AUDIO_AC3_BITRATE_384K == params->au_ac3_bitrate;
+	else
+		is_384k = V4L2_MPEG_AUDIO_L2_BITRATE_384K == params->au_l2_bitrate;
+	set_reg8(client, 0x94, is_384k);
+	tot_bitrate += is_384k ? 384 : 256;
+
+	/* Note: the total max bitrate is determined by adding the video and audio
+	   bitrates together and also adding an extra 768kbit/s to stay on the
+	   safe side. If more control should be required, then an extra MPEG control
+	   should be added. */
+	tot_bitrate += 768;
+	if (tot_bitrate > MPEG_TOTAL_TARGET_BITRATE_MAX)
+		tot_bitrate = MPEG_TOTAL_TARGET_BITRATE_MAX;
+
+	/* set the total bitrate */
+	set_reg16(client, 0xb1, tot_bitrate);
+	return 0;
+}
+
+
+static int get_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
+		struct v4l2_ext_control *ctrl)
+{
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
+		break;
+	case V4L2_CID_MPEG_STREAM_PID_PMT:
+		ctrl->value = params->ts_pid_pmt;
+		break;
+	case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+		ctrl->value = params->ts_pid_audio;
+		break;
+	case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+		ctrl->value = params->ts_pid_video;
+		break;
+	case V4L2_CID_MPEG_STREAM_PID_PCR:
+		ctrl->value = params->ts_pid_pcr;
+		break;
+	case V4L2_CID_MPEG_AUDIO_ENCODING:
+		ctrl->value = params->au_encoding;
+		break;
+	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+		ctrl->value = params->au_l2_bitrate;
+		break;
+	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+		if (!has_ac3)
+			return -EINVAL;
+		ctrl->value = params->au_ac3_bitrate;
+		break;
+	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+		ctrl->value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
+		break;
+	case V4L2_CID_MPEG_VIDEO_ENCODING:
+		ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+		break;
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		ctrl->value = params->vi_aspect;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		ctrl->value = params->vi_bitrate * 1000;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+		ctrl->value = params->vi_bitrate_peak * 1000;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		ctrl->value = params->vi_bitrate_mode;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
+		struct v4l2_ext_control *ctrl, int set)
+{
+	int old = 0, new;
+
+	new = ctrl->value;
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
+		if (set && new != old)
+			return -ERANGE;
+		new = old;
+		break;
+	case V4L2_CID_MPEG_STREAM_PID_PMT:
+		old = params->ts_pid_pmt;
+		if (set && new > MPEG_PID_MAX)
+			return -ERANGE;
+		if (new > MPEG_PID_MAX)
+			new = MPEG_PID_MAX;
+		params->ts_pid_pmt = new;
+		break;
+	case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+		old = params->ts_pid_audio;
+		if (set && new > MPEG_PID_MAX)
+			return -ERANGE;
+		if (new > MPEG_PID_MAX)
+			new = MPEG_PID_MAX;
+		params->ts_pid_audio = new;
+		break;
+	case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+		old = params->ts_pid_video;
+		if (set && new > MPEG_PID_MAX)
+			return -ERANGE;
+		if (new > MPEG_PID_MAX)
+			new = MPEG_PID_MAX;
+		params->ts_pid_video = new;
+		break;
+	case V4L2_CID_MPEG_STREAM_PID_PCR:
+		old = params->ts_pid_pcr;
+		if (set && new > MPEG_PID_MAX)
+			return -ERANGE;
+		if (new > MPEG_PID_MAX)
+			new = MPEG_PID_MAX;
+		params->ts_pid_pcr = new;
+		break;
+	case V4L2_CID_MPEG_AUDIO_ENCODING:
+		old = params->au_encoding;
+		if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
+		    (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3))
+			return -ERANGE;
+		params->au_encoding = new;
+		break;
+	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+		old = params->au_l2_bitrate;
+		if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K &&
+			   new != V4L2_MPEG_AUDIO_L2_BITRATE_384K)
+			return -ERANGE;
+		if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K)
+			new = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
+		else
+			new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
+		params->au_l2_bitrate = new;
+		break;
+	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+		if (!has_ac3)
+			return -EINVAL;
+		old = params->au_ac3_bitrate;
+		if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K &&
+			   new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K)
+			return -ERANGE;
+		if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K)
+			new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K;
+		else
+			new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K;
+		params->au_ac3_bitrate = new;
+		break;
+	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+		old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
+		if (set && new != old)
+			return -ERANGE;
+		new = old;
+		break;
+	case V4L2_CID_MPEG_VIDEO_ENCODING:
+		old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+		if (set && new != old)
+			return -ERANGE;
+		new = old;
+		break;
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		old = params->vi_aspect;
+		if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 &&
+			   new != V4L2_MPEG_VIDEO_ASPECT_4x3)
+			return -ERANGE;
+		if (new != V4L2_MPEG_VIDEO_ASPECT_16x9)
+			new = V4L2_MPEG_VIDEO_ASPECT_4x3;
+		params->vi_aspect = new;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		old = params->vi_bitrate * 1000;
+		new = 1000 * (new / 1000);
+		if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+			return -ERANGE;
+		if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+			new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
+		params->vi_bitrate = new / 1000;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+		old = params->vi_bitrate_peak * 1000;
+		new = 1000 * (new / 1000);
+		if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+			return -ERANGE;
+		if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+			new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
+		params->vi_bitrate_peak = new / 1000;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		old = params->vi_bitrate_mode;
+		params->vi_bitrate_mode = new;
+		break;
+	default:
+		return -EINVAL;
+	}
+	ctrl->value = new;
+	return 0;
+}
+
+
+static int saa6752hs_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
+{
+	struct saa6752hs_state *h = to_state(sd);
+	struct saa6752hs_mpeg_params *params = &h->params;
+	int err;
+
+	switch (qctrl->id) {
+	case V4L2_CID_MPEG_AUDIO_ENCODING:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+				h->has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 :
+					V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+				1, V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+
+	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+				V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+				V4L2_MPEG_AUDIO_L2_BITRATE_256K);
+
+	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+		if (!h->has_ac3)
+			return -EINVAL;
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
+				V4L2_MPEG_AUDIO_AC3_BITRATE_384K, 1,
+				V4L2_MPEG_AUDIO_AC3_BITRATE_256K);
+
+	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+				V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, 1,
+				V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+
+	case V4L2_CID_MPEG_VIDEO_ENCODING:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
+				V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
+				V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_VIDEO_ASPECT_4x3,
+				V4L2_MPEG_VIDEO_ASPECT_16x9, 1,
+				V4L2_MPEG_VIDEO_ASPECT_4x3);
+
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+		err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
+		if (err == 0 &&
+		    params->vi_bitrate_mode ==
+				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return err;
+
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
+				V4L2_MPEG_STREAM_TYPE_MPEG2_TS, 1,
+				V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
+
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
+				V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
+	case V4L2_CID_MPEG_STREAM_PID_PMT:
+		return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16);
+	case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+		return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260);
+	case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+		return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256);
+	case V4L2_CID_MPEG_STREAM_PID_PCR:
+		return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259);
+
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int saa6752hs_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qmenu)
+{
+	static const u32 mpeg_audio_encoding[] = {
+		V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+		V4L2_CTRL_MENU_IDS_END
+	};
+	static const u32 mpeg_audio_ac3_encoding[] = {
+		V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+		V4L2_MPEG_AUDIO_ENCODING_AC3,
+		V4L2_CTRL_MENU_IDS_END
+	};
+	static u32 mpeg_audio_l2_bitrate[] = {
+		V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+		V4L2_MPEG_AUDIO_L2_BITRATE_384K,
+		V4L2_CTRL_MENU_IDS_END
+	};
+	static u32 mpeg_audio_ac3_bitrate[] = {
+		V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
+		V4L2_MPEG_AUDIO_AC3_BITRATE_384K,
+		V4L2_CTRL_MENU_IDS_END
+	};
+	struct saa6752hs_state *h = to_state(sd);
+	struct v4l2_queryctrl qctrl;
+	int err;
+
+	qctrl.id = qmenu->id;
+	err = saa6752hs_queryctrl(sd, &qctrl);
+	if (err)
+		return err;
+	switch (qmenu->id) {
+	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+		return v4l2_ctrl_query_menu_valid_items(qmenu,
+				mpeg_audio_l2_bitrate);
+	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+		if (!h->has_ac3)
+			return -EINVAL;
+		return v4l2_ctrl_query_menu_valid_items(qmenu,
+				mpeg_audio_ac3_bitrate);
+	case V4L2_CID_MPEG_AUDIO_ENCODING:
+		return v4l2_ctrl_query_menu_valid_items(qmenu,
+			h->has_ac3 ? mpeg_audio_ac3_encoding :
+				mpeg_audio_encoding);
+	}
+	return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
+}
+
+static int saa6752hs_init(struct v4l2_subdev *sd, u32 leading_null_bytes)
+{
+	unsigned char buf[9], buf2[4];
+	struct saa6752hs_state *h = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	unsigned size;
+	u32 crc;
+	unsigned char localPAT[256];
+	unsigned char localPMT[256];
+
+	/* Set video format - must be done first as it resets other settings */
+	set_reg8(client, 0x41, h->video_format);
+
+	/* Set number of lines in input signal */
+	set_reg8(client, 0x40, (h->standard & V4L2_STD_525_60) ? 1 : 0);
+
+	/* set bitrate */
+	saa6752hs_set_bitrate(client, h);
+
+	/* Set GOP structure {3, 13} */
+	set_reg16(client, 0x72, 0x030d);
+
+	/* Set minimum Q-scale {4} */
+	set_reg8(client, 0x82, 0x04);
+
+	/* Set maximum Q-scale {12} */
+	set_reg8(client, 0x83, 0x0c);
+
+	/* Set Output Protocol */
+	set_reg8(client, 0xd0, 0x81);
+
+	/* Set video output stream format {TS} */
+	set_reg8(client, 0xb0, 0x05);
+
+	/* Set leading null byte for TS */
+	set_reg16(client, 0xf6, leading_null_bytes);
+
+	/* compute PAT */
+	memcpy(localPAT, PAT, sizeof(PAT));
+	localPAT[17] = 0xe0 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
+	localPAT[18] = h->params.ts_pid_pmt & 0xff;
+	crc = crc32_be(~0, &localPAT[7], sizeof(PAT) - 7 - 4);
+	localPAT[sizeof(PAT) - 4] = (crc >> 24) & 0xFF;
+	localPAT[sizeof(PAT) - 3] = (crc >> 16) & 0xFF;
+	localPAT[sizeof(PAT) - 2] = (crc >> 8) & 0xFF;
+	localPAT[sizeof(PAT) - 1] = crc & 0xFF;
+
+	/* compute PMT */
+	if (h->params.au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) {
+		size = sizeof(PMT_AC3);
+		memcpy(localPMT, PMT_AC3, size);
+	} else {
+		size = sizeof(PMT);
+		memcpy(localPMT, PMT, size);
+	}
+	localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
+	localPMT[4] = h->params.ts_pid_pmt & 0xff;
+	localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F);
+	localPMT[16] = h->params.ts_pid_pcr & 0xFF;
+	localPMT[20] = 0xE0 | ((h->params.ts_pid_video >> 8) & 0x0F);
+	localPMT[21] = h->params.ts_pid_video & 0xFF;
+	localPMT[25] = 0xE0 | ((h->params.ts_pid_audio >> 8) & 0x0F);
+	localPMT[26] = h->params.ts_pid_audio & 0xFF;
+	crc = crc32_be(~0, &localPMT[7], size - 7 - 4);
+	localPMT[size - 4] = (crc >> 24) & 0xFF;
+	localPMT[size - 3] = (crc >> 16) & 0xFF;
+	localPMT[size - 2] = (crc >> 8) & 0xFF;
+	localPMT[size - 1] = crc & 0xFF;
+
+	/* Set Audio PID */
+	set_reg16(client, 0xc1, h->params.ts_pid_audio);
+
+	/* Set Video PID */
+	set_reg16(client, 0xc0, h->params.ts_pid_video);
+
+	/* Set PCR PID */
+	set_reg16(client, 0xc4, h->params.ts_pid_pcr);
+
+	/* Send SI tables */
+	i2c_master_send(client, localPAT, sizeof(PAT));
+	i2c_master_send(client, localPMT, size);
+
+	/* mute then unmute audio. This removes buzzing artefacts */
+	set_reg8(client, 0xa4, 1);
+	set_reg8(client, 0xa4, 0);
+
+	/* start it going */
+	saa6752hs_chip_command(client, SAA6752HS_COMMAND_START);
+
+	/* readout current state */
+	buf[0] = 0xE1;
+	buf[1] = 0xA7;
+	buf[2] = 0xFE;
+	buf[3] = 0x82;
+	buf[4] = 0xB0;
+	i2c_master_send(client, buf, 5);
+	i2c_master_recv(client, buf2, 4);
+
+	/* change aspect ratio */
+	buf[0] = 0xE0;
+	buf[1] = 0xA7;
+	buf[2] = 0xFE;
+	buf[3] = 0x82;
+	buf[4] = 0xB0;
+	buf[5] = buf2[0];
+	switch (h->params.vi_aspect) {
+	case V4L2_MPEG_VIDEO_ASPECT_16x9:
+		buf[6] = buf2[1] | 0x40;
+		break;
+	case V4L2_MPEG_VIDEO_ASPECT_4x3:
+	default:
+		buf[6] = buf2[1] & 0xBF;
+		break;
+	}
+	buf[7] = buf2[2];
+	buf[8] = buf2[3];
+	i2c_master_send(client, buf, 9);
+
+	return 0;
+}
+
+static int saa6752hs_do_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls, int set)
+{
+	struct saa6752hs_state *h = to_state(sd);
+	struct saa6752hs_mpeg_params params;
+	int i;
+
+	if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+		return -EINVAL;
+
+	params = h->params;
+	for (i = 0; i < ctrls->count; i++) {
+		int err = handle_ctrl(h->has_ac3, &params, ctrls->controls + i, set);
+
+		if (err) {
+			ctrls->error_idx = i;
+			return err;
+		}
+	}
+	if (set)
+		h->params = params;
+	return 0;
+}
+
+static int saa6752hs_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
+{
+	return saa6752hs_do_ext_ctrls(sd, ctrls, 1);
+}
+
+static int saa6752hs_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
+{
+	return saa6752hs_do_ext_ctrls(sd, ctrls, 0);
+}
+
+static int saa6752hs_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
+{
+	struct saa6752hs_state *h = to_state(sd);
+	int i;
+
+	if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+		return -EINVAL;
+
+	for (i = 0; i < ctrls->count; i++) {
+		int err = get_ctrl(h->has_ac3, &h->params, ctrls->controls + i);
+
+		if (err) {
+			ctrls->error_idx = i;
+			return err;
+		}
+	}
+	return 0;
+}
+
+static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
+{
+	struct saa6752hs_state *h = to_state(sd);
+
+	if (h->video_format == SAA6752HS_VF_UNKNOWN)
+		h->video_format = SAA6752HS_VF_D1;
+	f->width = v4l2_format_table[h->video_format].fmt.pix.width;
+	f->height = v4l2_format_table[h->video_format].fmt.pix.height;
+	f->code = V4L2_MBUS_FMT_FIXED;
+	f->field = V4L2_FIELD_INTERLACED;
+	f->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	return 0;
+}
+
+static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
+{
+	struct saa6752hs_state *h = to_state(sd);
+	int dist_352, dist_480, dist_720;
+
+	if (f->code != V4L2_MBUS_FMT_FIXED)
+		return -EINVAL;
+
+	/*
+	  FIXME: translate and round width/height into EMPRESS
+	  subsample type:
+
+	  type   |   PAL   |  NTSC
+	  ---------------------------
+	  SIF    | 352x288 | 352x240
+	  1/2 D1 | 352x576 | 352x480
+	  2/3 D1 | 480x576 | 480x480
+	  D1     | 720x576 | 720x480
+	*/
+
+	dist_352 = abs(f->width - 352);
+	dist_480 = abs(f->width - 480);
+	dist_720 = abs(f->width - 720);
+	if (dist_720 < dist_480) {
+		f->width = 720;
+		f->height = 576;
+		h->video_format = SAA6752HS_VF_D1;
+	} else if (dist_480 < dist_352) {
+		f->width = 480;
+		f->height = 576;
+		h->video_format = SAA6752HS_VF_2_3_D1;
+	} else {
+		f->width = 352;
+		if (abs(f->height - 576) <
+		    abs(f->height - 288)) {
+			f->height = 576;
+			h->video_format = SAA6752HS_VF_1_2_D1;
+		} else {
+			f->height = 288;
+			h->video_format = SAA6752HS_VF_SIF;
+		}
+	}
+	f->field = V4L2_FIELD_INTERLACED;
+	f->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	return 0;
+}
+
+static int saa6752hs_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct saa6752hs_state *h = to_state(sd);
+
+	h->standard = std;
+	return 0;
+}
+
+static int saa6752hs_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct saa6752hs_state *h = to_state(sd);
+
+	return v4l2_chip_ident_i2c_client(client,
+			chip, h->chip, h->revision);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops saa6752hs_core_ops = {
+	.g_chip_ident = saa6752hs_g_chip_ident,
+	.init = saa6752hs_init,
+	.queryctrl = saa6752hs_queryctrl,
+	.querymenu = saa6752hs_querymenu,
+	.g_ext_ctrls = saa6752hs_g_ext_ctrls,
+	.s_ext_ctrls = saa6752hs_s_ext_ctrls,
+	.try_ext_ctrls = saa6752hs_try_ext_ctrls,
+	.s_std = saa6752hs_s_std,
+};
+
+static const struct v4l2_subdev_video_ops saa6752hs_video_ops = {
+	.s_mbus_fmt = saa6752hs_s_mbus_fmt,
+	.g_mbus_fmt = saa6752hs_g_mbus_fmt,
+};
+
+static const struct v4l2_subdev_ops saa6752hs_ops = {
+	.core = &saa6752hs_core_ops,
+	.video = &saa6752hs_video_ops,
+};
+
+static int saa6752hs_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL);
+	struct v4l2_subdev *sd;
+	u8 addr = 0x13;
+	u8 data[12];
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+	if (h == NULL)
+		return -ENOMEM;
+	sd = &h->sd;
+	v4l2_i2c_subdev_init(sd, client, &saa6752hs_ops);
+
+	i2c_master_send(client, &addr, 1);
+	i2c_master_recv(client, data, sizeof(data));
+	h->chip = V4L2_IDENT_SAA6752HS;
+	h->revision = (data[8] << 8) | data[9];
+	h->has_ac3 = 0;
+	if (h->revision == 0x0206) {
+		h->chip = V4L2_IDENT_SAA6752HS_AC3;
+		h->has_ac3 = 1;
+		v4l_info(client, "support AC-3\n");
+	}
+	h->params = param_defaults;
+	h->standard = 0; /* Assume 625 input lines */
+	return 0;
+}
+
+static int saa6752hs_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_state(sd));
+	return 0;
+}
+
+static const struct i2c_device_id saa6752hs_id[] = {
+	{ "saa6752hs", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, saa6752hs_id);
+
+static struct i2c_driver saa6752hs_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "saa6752hs",
+	},
+	.probe		= saa6752hs_probe,
+	.remove		= saa6752hs_remove,
+	.id_table	= saa6752hs_id,
+};
+
+module_i2c_driver(saa6752hs_driver);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c
new file mode 100644
index 0000000..10460fd
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-alsa.c
@@ -0,0 +1,1209 @@
+/*
+ *   SAA713x ALSA support for V4L
+ *
+ *   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, version 2
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <linux/interrupt.h>
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages [alsa]");
+
+/*
+ * Configuration macros
+ */
+
+/* defaults */
+#define MIXER_ADDR_UNSELECTED	-1
+#define MIXER_ADDR_TVTUNER	0
+#define MIXER_ADDR_LINE1	1
+#define MIXER_ADDR_LINE2	2
+#define MIXER_ADDR_LAST		2
+
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
+static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
+
+module_param_array(index, int, NULL, 0444);
+module_param_array(enable, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for SAA7134 capture interface(s).");
+MODULE_PARM_DESC(enable, "Enable (or not) the SAA7134 capture interface(s).");
+
+#define dprintk(fmt, arg...)    if (debug) \
+	printk(KERN_DEBUG "%s/alsa: " fmt, dev->name , ##arg)
+
+
+
+/*
+ * Main chip structure
+ */
+
+typedef struct snd_card_saa7134 {
+	struct snd_card *card;
+	spinlock_t mixer_lock;
+	int mixer_volume[MIXER_ADDR_LAST+1][2];
+	int capture_source_addr;
+	int capture_source[2];
+	struct snd_kcontrol *capture_ctl[MIXER_ADDR_LAST+1];
+	struct pci_dev *pci;
+	struct saa7134_dev *dev;
+
+	unsigned long iobase;
+	s16 irq;
+	u16 mute_was_on;
+
+	spinlock_t lock;
+} snd_card_saa7134_t;
+
+
+/*
+ * PCM structure
+ */
+
+typedef struct snd_card_saa7134_pcm {
+	struct saa7134_dev *dev;
+
+	spinlock_t lock;
+
+	struct snd_pcm_substream *substream;
+} snd_card_saa7134_pcm_t;
+
+static struct snd_card *snd_saa7134_cards[SNDRV_CARDS];
+
+
+/*
+ * saa7134 DMA audio stop
+ *
+ *   Called when the capture device is released or the buffer overflows
+ *
+ *   - Copied verbatim from saa7134-oss's dsp_dma_stop.
+ *
+ */
+
+static void saa7134_dma_stop(struct saa7134_dev *dev)
+{
+	dev->dmasound.dma_blk     = -1;
+	dev->dmasound.dma_running = 0;
+	saa7134_set_dmabits(dev);
+}
+
+/*
+ * saa7134 DMA audio start
+ *
+ *   Called when preparing the capture device for use
+ *
+ *   - Copied verbatim from saa7134-oss's dsp_dma_start.
+ *
+ */
+
+static void saa7134_dma_start(struct saa7134_dev *dev)
+{
+	dev->dmasound.dma_blk     = 0;
+	dev->dmasound.dma_running = 1;
+	saa7134_set_dmabits(dev);
+}
+
+/*
+ * saa7134 audio DMA IRQ handler
+ *
+ *   Called whenever we get an SAA7134_IRQ_REPORT_DONE_RA3 interrupt
+ *   Handles shifting between the 2 buffers, manages the read counters,
+ *  and notifies ALSA when periods elapse
+ *
+ *   - Mostly copied from saa7134-oss's saa7134_irq_oss_done.
+ *
+ */
+
+static void saa7134_irq_alsa_done(struct saa7134_dev *dev,
+				  unsigned long status)
+{
+	int next_blk, reg = 0;
+
+	spin_lock(&dev->slock);
+	if (UNSET == dev->dmasound.dma_blk) {
+		dprintk("irq: recording stopped\n");
+		goto done;
+	}
+	if (0 != (status & 0x0f000000))
+		dprintk("irq: lost %ld\n", (status >> 24) & 0x0f);
+	if (0 == (status & 0x10000000)) {
+		/* odd */
+		if (0 == (dev->dmasound.dma_blk & 0x01))
+			reg = SAA7134_RS_BA1(6);
+	} else {
+		/* even */
+		if (1 == (dev->dmasound.dma_blk & 0x01))
+			reg = SAA7134_RS_BA2(6);
+	}
+	if (0 == reg) {
+		dprintk("irq: field oops [%s]\n",
+			(status & 0x10000000) ? "even" : "odd");
+		goto done;
+	}
+
+	if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) {
+		dprintk("irq: overrun [full=%d/%d] - Blocks in %d\n",dev->dmasound.read_count,
+			dev->dmasound.bufsize, dev->dmasound.blocks);
+		spin_unlock(&dev->slock);
+		snd_pcm_stop(dev->dmasound.substream,SNDRV_PCM_STATE_XRUN);
+		return;
+	}
+
+	/* next block addr */
+	next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks;
+	saa_writel(reg,next_blk * dev->dmasound.blksize);
+	if (debug > 2)
+		dprintk("irq: ok, %s, next_blk=%d, addr=%x, blocks=%u, size=%u, read=%u\n",
+			(status & 0x10000000) ? "even" : "odd ", next_blk,
+			next_blk * dev->dmasound.blksize, dev->dmasound.blocks, dev->dmasound.blksize, dev->dmasound.read_count);
+
+	/* update status & wake waiting readers */
+	dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks;
+	dev->dmasound.read_count += dev->dmasound.blksize;
+
+	dev->dmasound.recording_on = reg;
+
+	if (dev->dmasound.read_count >= snd_pcm_lib_period_bytes(dev->dmasound.substream)) {
+		spin_unlock(&dev->slock);
+		snd_pcm_period_elapsed(dev->dmasound.substream);
+		spin_lock(&dev->slock);
+	}
+
+ done:
+	spin_unlock(&dev->slock);
+
+}
+
+/*
+ * IRQ request handler
+ *
+ *   Runs along with saa7134's IRQ handler, discards anything that isn't
+ *   DMA sound
+ *
+ */
+
+static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id)
+{
+	struct saa7134_dmasound *dmasound = dev_id;
+	struct saa7134_dev *dev = dmasound->priv_data;
+
+	unsigned long report, status;
+	int loop, handled = 0;
+
+	for (loop = 0; loop < 10; loop++) {
+		report = saa_readl(SAA7134_IRQ_REPORT);
+		status = saa_readl(SAA7134_IRQ_STATUS);
+
+		if (report & SAA7134_IRQ_REPORT_DONE_RA3) {
+			handled = 1;
+			saa_writel(SAA7134_IRQ_REPORT,
+				   SAA7134_IRQ_REPORT_DONE_RA3);
+			saa7134_irq_alsa_done(dev, status);
+		} else {
+			goto out;
+		}
+	}
+
+	if (loop == 10) {
+		dprintk("error! looping IRQ!");
+	}
+
+out:
+	return IRQ_RETVAL(handled);
+}
+
+/*
+ * ALSA capture trigger
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called whenever a capture is started or stopped. Must be defined,
+ *   but there's nothing we want to do here
+ *
+ */
+
+static int snd_card_saa7134_capture_trigger(struct snd_pcm_substream * substream,
+					  int cmd)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	snd_card_saa7134_pcm_t *pcm = runtime->private_data;
+	struct saa7134_dev *dev=pcm->dev;
+	int err = 0;
+
+	spin_lock(&dev->slock);
+	if (cmd == SNDRV_PCM_TRIGGER_START) {
+		/* start dma */
+		saa7134_dma_start(dev);
+	} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+		/* stop dma */
+		saa7134_dma_stop(dev);
+	} else {
+		err = -EINVAL;
+	}
+	spin_unlock(&dev->slock);
+
+	return err;
+}
+
+/*
+ * DMA buffer initialization
+ *
+ *   Uses V4L functions to initialize the DMA. Shouldn't be necessary in
+ *  ALSA, but I was unable to use ALSA's own DMA, and had to force the
+ *  usage of V4L's
+ *
+ *   - Copied verbatim from saa7134-oss.
+ *
+ */
+
+static int dsp_buffer_init(struct saa7134_dev *dev)
+{
+	int err;
+
+	BUG_ON(!dev->dmasound.bufsize);
+
+	videobuf_dma_init(&dev->dmasound.dma);
+	err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE,
+				       (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
+	if (0 != err)
+		return err;
+	return 0;
+}
+
+/*
+ * DMA buffer release
+ *
+ *   Called after closing the device, during snd_card_saa7134_capture_close
+ *
+ */
+
+static int dsp_buffer_free(struct saa7134_dev *dev)
+{
+	BUG_ON(!dev->dmasound.blksize);
+
+	videobuf_dma_free(&dev->dmasound.dma);
+
+	dev->dmasound.blocks  = 0;
+	dev->dmasound.blksize = 0;
+	dev->dmasound.bufsize = 0;
+
+	return 0;
+}
+
+/*
+ * Setting the capture source and updating the ALSA controls
+ */
+static int snd_saa7134_capsrc_set(struct snd_kcontrol *kcontrol,
+				  int left, int right, bool force_notify)
+{
+	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+	int change = 0, addr = kcontrol->private_value;
+	int active, old_addr;
+	u32 anabar, xbarin;
+	int analog_io, rate;
+	struct saa7134_dev *dev;
+
+	dev = chip->dev;
+
+	spin_lock_irq(&chip->mixer_lock);
+
+	active = left != 0 || right != 0;
+	old_addr = chip->capture_source_addr;
+
+	/* The active capture source cannot be deactivated */
+	if (active) {
+		change = old_addr != addr ||
+			 chip->capture_source[0] != left ||
+			 chip->capture_source[1] != right;
+
+		chip->capture_source[0] = left;
+		chip->capture_source[1] = right;
+		chip->capture_source_addr = addr;
+		dev->dmasound.input = addr;
+	}
+	spin_unlock_irq(&chip->mixer_lock);
+
+	if (change) {
+		switch (dev->pci->device) {
+
+		case PCI_DEVICE_ID_PHILIPS_SAA7134:
+			switch (addr) {
+			case MIXER_ADDR_TVTUNER:
+				saa_andorb(SAA7134_AUDIO_FORMAT_CTRL,
+					   0xc0, 0xc0);
+				saa_andorb(SAA7134_SIF_SAMPLE_FREQ,
+					   0x03, 0x00);
+				break;
+			case MIXER_ADDR_LINE1:
+			case MIXER_ADDR_LINE2:
+				analog_io = (MIXER_ADDR_LINE1 == addr) ?
+					     0x00 : 0x08;
+				rate = (32000 == dev->dmasound.rate) ?
+					0x01 : 0x03;
+				saa_andorb(SAA7134_ANALOG_IO_SELECT,
+					   0x08, analog_io);
+				saa_andorb(SAA7134_AUDIO_FORMAT_CTRL,
+					   0xc0, 0x80);
+				saa_andorb(SAA7134_SIF_SAMPLE_FREQ,
+					   0x03, rate);
+				break;
+			}
+
+			break;
+		case PCI_DEVICE_ID_PHILIPS_SAA7133:
+		case PCI_DEVICE_ID_PHILIPS_SAA7135:
+			xbarin = 0x03; /* adc */
+			anabar = 0;
+			switch (addr) {
+			case MIXER_ADDR_TVTUNER:
+				xbarin = 0; /* Demodulator */
+				anabar = 2; /* DACs */
+				break;
+			case MIXER_ADDR_LINE1:
+				anabar = 0;  /* aux1, aux1 */
+				break;
+			case MIXER_ADDR_LINE2:
+				anabar = 9;  /* aux2, aux2 */
+				break;
+			}
+
+			/* output xbar always main channel */
+			saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1,
+				       0xbbbb10);
+
+			if (left || right) {
+				/* We've got data, turn the input on */
+				saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1,
+					       xbarin);
+				saa_writel(SAA7133_ANALOG_IO_SELECT, anabar);
+			} else {
+				saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1,
+					       0);
+				saa_writel(SAA7133_ANALOG_IO_SELECT, 0);
+			}
+			break;
+		}
+	}
+
+	if (change) {
+		if (force_notify)
+			snd_ctl_notify(chip->card,
+				       SNDRV_CTL_EVENT_MASK_VALUE,
+				       &chip->capture_ctl[addr]->id);
+
+		if (old_addr != MIXER_ADDR_UNSELECTED && old_addr != addr)
+			snd_ctl_notify(chip->card,
+				       SNDRV_CTL_EVENT_MASK_VALUE,
+				       &chip->capture_ctl[old_addr]->id);
+	}
+
+	return change;
+}
+
+/*
+ * ALSA PCM preparation
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called right after the capture device is opened, this function configures
+ *  the buffer using the previously defined functions, allocates the memory,
+ *  sets up the hardware registers, and then starts the DMA. When this function
+ *  returns, the audio should be flowing.
+ *
+ */
+
+static int snd_card_saa7134_capture_prepare(struct snd_pcm_substream * substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int bswap, sign;
+	u32 fmt, control;
+	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+	struct saa7134_dev *dev;
+	snd_card_saa7134_pcm_t *pcm = runtime->private_data;
+
+	pcm->dev->dmasound.substream = substream;
+
+	dev = saa7134->dev;
+
+	if (snd_pcm_format_width(runtime->format) == 8)
+		fmt = 0x00;
+	else
+		fmt = 0x01;
+
+	if (snd_pcm_format_signed(runtime->format))
+		sign = 1;
+	else
+		sign = 0;
+
+	if (snd_pcm_format_big_endian(runtime->format))
+		bswap = 1;
+	else
+		bswap = 0;
+
+	switch (dev->pci->device) {
+	  case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		if (1 == runtime->channels)
+			fmt |= (1 << 3);
+		if (2 == runtime->channels)
+			fmt |= (3 << 3);
+		if (sign)
+			fmt |= 0x04;
+
+		fmt |= (MIXER_ADDR_TVTUNER == dev->dmasound.input) ? 0xc0 : 0x80;
+		saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff));
+		saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >>  8);
+		saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16);
+		saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
+
+		break;
+	  case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	  case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		if (1 == runtime->channels)
+			fmt |= (1 << 4);
+		if (2 == runtime->channels)
+			fmt |= (2 << 4);
+		if (!sign)
+			fmt |= 0x04;
+		saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -1);
+		saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24));
+		break;
+	}
+
+	dprintk("rec_start: afmt=%d ch=%d  =>  fmt=0x%x swap=%c\n",
+		runtime->format, runtime->channels, fmt,
+		bswap ? 'b' : '-');
+	/* dma: setup channel 6 (= AUDIO) */
+	control = SAA7134_RS_CONTROL_BURST_16 |
+		SAA7134_RS_CONTROL_ME |
+		(dev->dmasound.pt.dma >> 12);
+	if (bswap)
+		control |= SAA7134_RS_CONTROL_BSWAP;
+
+	saa_writel(SAA7134_RS_BA1(6),0);
+	saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize);
+	saa_writel(SAA7134_RS_PITCH(6),0);
+	saa_writel(SAA7134_RS_CONTROL(6),control);
+
+	dev->dmasound.rate = runtime->rate;
+
+	/* Setup and update the card/ALSA controls */
+	snd_saa7134_capsrc_set(saa7134->capture_ctl[dev->dmasound.input], 1, 1,
+			       true);
+
+	return 0;
+
+}
+
+/*
+ * ALSA pointer fetching
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called whenever a period elapses, it must return the current hardware
+ *  position of the buffer.
+ *   Also resets the read counter used to prevent overruns
+ *
+ */
+
+static snd_pcm_uframes_t
+snd_card_saa7134_capture_pointer(struct snd_pcm_substream * substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	snd_card_saa7134_pcm_t *pcm = runtime->private_data;
+	struct saa7134_dev *dev=pcm->dev;
+
+	if (dev->dmasound.read_count) {
+		dev->dmasound.read_count  -= snd_pcm_lib_period_bytes(substream);
+		dev->dmasound.read_offset += snd_pcm_lib_period_bytes(substream);
+		if (dev->dmasound.read_offset == dev->dmasound.bufsize)
+			dev->dmasound.read_offset = 0;
+	}
+
+	return bytes_to_frames(runtime, dev->dmasound.read_offset);
+}
+
+/*
+ * ALSA hardware capabilities definition
+ *
+ *  Report only 32kHz for ALSA:
+ *
+ *  - SAA7133/35 uses DDEP (DemDec Easy Programming mode), which works in 32kHz
+ *    only
+ *  - SAA7134 for TV mode uses DemDec mode (32kHz)
+ *  - Radio works in 32kHz only
+ *  - When recording 48kHz from Line1/Line2, switching of capture source to TV
+ *    means
+ *    switching to 32kHz without any frequency translation
+ */
+
+static struct snd_pcm_hardware snd_card_saa7134_capture =
+{
+	.info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID),
+	.formats =		SNDRV_PCM_FMTBIT_S16_LE | \
+				SNDRV_PCM_FMTBIT_S16_BE | \
+				SNDRV_PCM_FMTBIT_S8 | \
+				SNDRV_PCM_FMTBIT_U8 | \
+				SNDRV_PCM_FMTBIT_U16_LE | \
+				SNDRV_PCM_FMTBIT_U16_BE,
+	.rates =		SNDRV_PCM_RATE_32000,
+	.rate_min =		32000,
+	.rate_max =		32000,
+	.channels_min =		1,
+	.channels_max =		2,
+	.buffer_bytes_max =	(256*1024),
+	.period_bytes_min =	64,
+	.period_bytes_max =	(256*1024),
+	.periods_min =		4,
+	.periods_max =		1024,
+};
+
+static void snd_card_saa7134_runtime_free(struct snd_pcm_runtime *runtime)
+{
+	snd_card_saa7134_pcm_t *pcm = runtime->private_data;
+
+	kfree(pcm);
+}
+
+
+/*
+ * ALSA hardware params
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called on initialization, right before the PCM preparation
+ *
+ */
+
+static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
+				      struct snd_pcm_hw_params * hw_params)
+{
+	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+	struct saa7134_dev *dev;
+	unsigned int period_size, periods;
+	int err;
+
+	period_size = params_period_bytes(hw_params);
+	periods = params_periods(hw_params);
+
+	if (period_size < 0x100 || period_size > 0x10000)
+		return -EINVAL;
+	if (periods < 4)
+		return -EINVAL;
+	if (period_size * periods > 1024 * 1024)
+		return -EINVAL;
+
+	dev = saa7134->dev;
+
+	if (dev->dmasound.blocks == periods &&
+	    dev->dmasound.blksize == period_size)
+		return 0;
+
+	/* release the old buffer */
+	if (substream->runtime->dma_area) {
+		saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
+		videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+		dsp_buffer_free(dev);
+		substream->runtime->dma_area = NULL;
+	}
+	dev->dmasound.blocks  = periods;
+	dev->dmasound.blksize = period_size;
+	dev->dmasound.bufsize = period_size * periods;
+
+	err = dsp_buffer_init(dev);
+	if (0 != err) {
+		dev->dmasound.blocks  = 0;
+		dev->dmasound.blksize = 0;
+		dev->dmasound.bufsize = 0;
+		return err;
+	}
+
+	if (0 != (err = videobuf_dma_map(&dev->pci->dev, &dev->dmasound.dma))) {
+		dsp_buffer_free(dev);
+		return err;
+	}
+	if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) {
+		videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+		dsp_buffer_free(dev);
+		return err;
+	}
+	if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt,
+						dev->dmasound.dma.sglist,
+						dev->dmasound.dma.sglen,
+						0))) {
+		saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
+		videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+		dsp_buffer_free(dev);
+		return err;
+	}
+
+	/* I should be able to use runtime->dma_addr in the control
+	   byte, but it doesn't work. So I allocate the DMA using the
+	   V4L functions, and force ALSA to use that as the DMA area */
+
+	substream->runtime->dma_area = dev->dmasound.dma.vaddr;
+	substream->runtime->dma_bytes = dev->dmasound.bufsize;
+	substream->runtime->dma_addr = 0;
+
+	return 0;
+
+}
+
+/*
+ * ALSA hardware release
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called after closing the device, but before snd_card_saa7134_capture_close
+ *   It stops the DMA audio and releases the buffers.
+ *
+ */
+
+static int snd_card_saa7134_hw_free(struct snd_pcm_substream * substream)
+{
+	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+	struct saa7134_dev *dev;
+
+	dev = saa7134->dev;
+
+	if (substream->runtime->dma_area) {
+		saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
+		videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+		dsp_buffer_free(dev);
+		substream->runtime->dma_area = NULL;
+	}
+
+	return 0;
+}
+
+/*
+ * ALSA capture finish
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called after closing the device.
+ *
+ */
+
+static int snd_card_saa7134_capture_close(struct snd_pcm_substream * substream)
+{
+	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+	struct saa7134_dev *dev = saa7134->dev;
+
+	if (saa7134->mute_was_on) {
+		dev->ctl_mute = 1;
+		saa7134_tvaudio_setmute(dev);
+	}
+	return 0;
+}
+
+/*
+ * ALSA capture start
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called when opening the device. It creates and populates the PCM
+ *  structure
+ *
+ */
+
+static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	snd_card_saa7134_pcm_t *pcm;
+	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+	struct saa7134_dev *dev;
+	int amux, err;
+
+	if (!saa7134) {
+		printk(KERN_ERR "BUG: saa7134 can't find device struct."
+				" Can't proceed with open\n");
+		return -ENODEV;
+	}
+	dev = saa7134->dev;
+	mutex_lock(&dev->dmasound.lock);
+
+	dev->dmasound.read_count  = 0;
+	dev->dmasound.read_offset = 0;
+
+	amux = dev->input->amux;
+	if ((amux < 1) || (amux > 3))
+		amux = 1;
+	dev->dmasound.input  =  amux - 1;
+
+	mutex_unlock(&dev->dmasound.lock);
+
+	pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
+	if (pcm == NULL)
+		return -ENOMEM;
+
+	pcm->dev=saa7134->dev;
+
+	spin_lock_init(&pcm->lock);
+
+	pcm->substream = substream;
+	runtime->private_data = pcm;
+	runtime->private_free = snd_card_saa7134_runtime_free;
+	runtime->hw = snd_card_saa7134_capture;
+
+	if (dev->ctl_mute != 0) {
+		saa7134->mute_was_on = 1;
+		dev->ctl_mute = 0;
+		saa7134_tvaudio_setmute(dev);
+	}
+
+	err = snd_pcm_hw_constraint_integer(runtime,
+						SNDRV_PCM_HW_PARAM_PERIODS);
+	if (err < 0)
+		return err;
+
+	err = snd_pcm_hw_constraint_step(runtime, 0,
+						SNDRV_PCM_HW_PARAM_PERIODS, 2);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/*
+ * page callback (needed for mmap)
+ */
+
+static struct page *snd_card_saa7134_page(struct snd_pcm_substream *substream,
+					unsigned long offset)
+{
+	void *pageptr = substream->runtime->dma_area + offset;
+	return vmalloc_to_page(pageptr);
+}
+
+/*
+ * ALSA capture callbacks definition
+ */
+
+static struct snd_pcm_ops snd_card_saa7134_capture_ops = {
+	.open =			snd_card_saa7134_capture_open,
+	.close =		snd_card_saa7134_capture_close,
+	.ioctl =		snd_pcm_lib_ioctl,
+	.hw_params =		snd_card_saa7134_hw_params,
+	.hw_free =		snd_card_saa7134_hw_free,
+	.prepare =		snd_card_saa7134_capture_prepare,
+	.trigger =		snd_card_saa7134_capture_trigger,
+	.pointer =		snd_card_saa7134_capture_pointer,
+	.page =			snd_card_saa7134_page,
+};
+
+/*
+ * ALSA PCM setup
+ *
+ *   Called when initializing the board. Sets up the name and hooks up
+ *  the callbacks
+ *
+ */
+
+static int snd_card_saa7134_pcm(snd_card_saa7134_t *saa7134, int device)
+{
+	struct snd_pcm *pcm;
+	int err;
+
+	if ((err = snd_pcm_new(saa7134->card, "SAA7134 PCM", device, 0, 1, &pcm)) < 0)
+		return err;
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_saa7134_capture_ops);
+	pcm->private_data = saa7134;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "SAA7134 PCM");
+	return 0;
+}
+
+#define SAA713x_VOLUME(xname, xindex, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .info = snd_saa7134_volume_info, \
+  .get = snd_saa7134_volume_get, .put = snd_saa7134_volume_put, \
+  .private_value = addr }
+
+static int snd_saa7134_volume_info(struct snd_kcontrol * kcontrol,
+				   struct snd_ctl_elem_info * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 20;
+	return 0;
+}
+
+static int snd_saa7134_volume_get(struct snd_kcontrol * kcontrol,
+				  struct snd_ctl_elem_value * ucontrol)
+{
+	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+	int addr = kcontrol->private_value;
+
+	ucontrol->value.integer.value[0] = chip->mixer_volume[addr][0];
+	ucontrol->value.integer.value[1] = chip->mixer_volume[addr][1];
+	return 0;
+}
+
+static int snd_saa7134_volume_put(struct snd_kcontrol * kcontrol,
+				  struct snd_ctl_elem_value * ucontrol)
+{
+	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+	struct saa7134_dev *dev = chip->dev;
+
+	int change, addr = kcontrol->private_value;
+	int left, right;
+
+	left = ucontrol->value.integer.value[0];
+	if (left < 0)
+		left = 0;
+	if (left > 20)
+		left = 20;
+	right = ucontrol->value.integer.value[1];
+	if (right < 0)
+		right = 0;
+	if (right > 20)
+		right = 20;
+	spin_lock_irq(&chip->mixer_lock);
+	change = 0;
+	if (chip->mixer_volume[addr][0] != left) {
+		change = 1;
+		right = left;
+	}
+	if (chip->mixer_volume[addr][1] != right) {
+		change = 1;
+		left = right;
+	}
+	if (change) {
+		switch (dev->pci->device) {
+			case PCI_DEVICE_ID_PHILIPS_SAA7134:
+				switch (addr) {
+					case MIXER_ADDR_TVTUNER:
+						left = 20;
+						break;
+					case MIXER_ADDR_LINE1:
+						saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x10,
+							   (left > 10) ? 0x00 : 0x10);
+						break;
+					case MIXER_ADDR_LINE2:
+						saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x20,
+							   (left > 10) ? 0x00 : 0x20);
+						break;
+				}
+				break;
+			case PCI_DEVICE_ID_PHILIPS_SAA7133:
+			case PCI_DEVICE_ID_PHILIPS_SAA7135:
+				switch (addr) {
+					case MIXER_ADDR_TVTUNER:
+						left = 20;
+						break;
+					case MIXER_ADDR_LINE1:
+						saa_andorb(0x0594,  0x10,
+							   (left > 10) ? 0x00 : 0x10);
+						break;
+					case MIXER_ADDR_LINE2:
+						saa_andorb(0x0594,  0x20,
+							   (left > 10) ? 0x00 : 0x20);
+						break;
+				}
+				break;
+		}
+		chip->mixer_volume[addr][0] = left;
+		chip->mixer_volume[addr][1] = right;
+	}
+	spin_unlock_irq(&chip->mixer_lock);
+	return change;
+}
+
+#define SAA713x_CAPSRC(xname, xindex, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .info = snd_saa7134_capsrc_info, \
+  .get = snd_saa7134_capsrc_get, .put = snd_saa7134_capsrc_put, \
+  .private_value = addr }
+
+static int snd_saa7134_capsrc_info(struct snd_kcontrol * kcontrol,
+				   struct snd_ctl_elem_info * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_saa7134_capsrc_get(struct snd_kcontrol * kcontrol,
+				  struct snd_ctl_elem_value * ucontrol)
+{
+	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+	int addr = kcontrol->private_value;
+
+	spin_lock_irq(&chip->mixer_lock);
+	if (chip->capture_source_addr == addr) {
+		ucontrol->value.integer.value[0] = chip->capture_source[0];
+		ucontrol->value.integer.value[1] = chip->capture_source[1];
+	} else {
+		ucontrol->value.integer.value[0] = 0;
+		ucontrol->value.integer.value[1] = 0;
+	}
+	spin_unlock_irq(&chip->mixer_lock);
+
+	return 0;
+}
+
+static int snd_saa7134_capsrc_put(struct snd_kcontrol * kcontrol,
+				  struct snd_ctl_elem_value * ucontrol)
+{
+	int left, right;
+	left = ucontrol->value.integer.value[0] & 1;
+	right = ucontrol->value.integer.value[1] & 1;
+
+	return snd_saa7134_capsrc_set(kcontrol, left, right, false);
+}
+
+static struct snd_kcontrol_new snd_saa7134_volume_controls[] = {
+SAA713x_VOLUME("Video Volume", 0, MIXER_ADDR_TVTUNER),
+SAA713x_VOLUME("Line Volume", 1, MIXER_ADDR_LINE1),
+SAA713x_VOLUME("Line Volume", 2, MIXER_ADDR_LINE2),
+};
+
+static struct snd_kcontrol_new snd_saa7134_capture_controls[] = {
+SAA713x_CAPSRC("Video Capture Switch", 0, MIXER_ADDR_TVTUNER),
+SAA713x_CAPSRC("Line Capture Switch", 1, MIXER_ADDR_LINE1),
+SAA713x_CAPSRC("Line Capture Switch", 2, MIXER_ADDR_LINE2),
+};
+
+/*
+ * ALSA mixer setup
+ *
+ *   Called when initializing the board. Sets up the name and hooks up
+ *  the callbacks
+ *
+ */
+
+static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip)
+{
+	struct snd_card *card = chip->card;
+	struct snd_kcontrol *kcontrol;
+	unsigned int idx;
+	int err, addr;
+
+	strcpy(card->mixername, "SAA7134 Mixer");
+
+	for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_volume_controls); idx++) {
+		kcontrol = snd_ctl_new1(&snd_saa7134_volume_controls[idx],
+					chip);
+		err = snd_ctl_add(card, kcontrol);
+		if (err < 0)
+			return err;
+	}
+
+	for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_capture_controls); idx++) {
+		kcontrol = snd_ctl_new1(&snd_saa7134_capture_controls[idx],
+					chip);
+		addr = snd_saa7134_capture_controls[idx].private_value;
+		chip->capture_ctl[addr] = kcontrol;
+		err = snd_ctl_add(card, kcontrol);
+		if (err < 0)
+			return err;
+	}
+
+	chip->capture_source_addr = MIXER_ADDR_UNSELECTED;
+	return 0;
+}
+
+static void snd_saa7134_free(struct snd_card * card)
+{
+	snd_card_saa7134_t *chip = card->private_data;
+
+	if (chip->dev->dmasound.priv_data == NULL)
+		return;
+
+	if (chip->irq >= 0)
+		free_irq(chip->irq, &chip->dev->dmasound);
+
+	chip->dev->dmasound.priv_data = NULL;
+
+}
+
+/*
+ * ALSA initialization
+ *
+ *   Called by the init routine, once for each saa7134 device present,
+ *  it creates the basic structures and registers the ALSA devices
+ *
+ */
+
+static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
+{
+
+	struct snd_card *card;
+	snd_card_saa7134_t *chip;
+	int err;
+
+
+	if (devnum >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[devnum])
+		return -ENODEV;
+
+	err = snd_card_create(index[devnum], id[devnum], THIS_MODULE,
+			      sizeof(snd_card_saa7134_t), &card);
+	if (err < 0)
+		return err;
+
+	strcpy(card->driver, "SAA7134");
+
+	/* Card "creation" */
+
+	card->private_free = snd_saa7134_free;
+	chip = card->private_data;
+
+	spin_lock_init(&chip->lock);
+	spin_lock_init(&chip->mixer_lock);
+
+	chip->dev = dev;
+
+	chip->card = card;
+
+	chip->pci = dev->pci;
+	chip->iobase = pci_resource_start(dev->pci, 0);
+
+
+	err = request_irq(dev->pci->irq, saa7134_alsa_irq,
+				IRQF_SHARED | IRQF_DISABLED, dev->name,
+				(void*) &dev->dmasound);
+
+	if (err < 0) {
+		printk(KERN_ERR "%s: can't get IRQ %d for ALSA\n",
+			dev->name, dev->pci->irq);
+		goto __nodev;
+	}
+
+	chip->irq = dev->pci->irq;
+
+	mutex_init(&dev->dmasound.lock);
+
+	if ((err = snd_card_saa7134_new_mixer(chip)) < 0)
+		goto __nodev;
+
+	if ((err = snd_card_saa7134_pcm(chip, 0)) < 0)
+		goto __nodev;
+
+	snd_card_set_dev(card, &chip->pci->dev);
+
+	/* End of "creation" */
+
+	strcpy(card->shortname, "SAA7134");
+	sprintf(card->longname, "%s at 0x%lx irq %d",
+		chip->dev->name, chip->iobase, chip->irq);
+
+	printk(KERN_INFO "%s/alsa: %s registered as card %d\n",dev->name,card->longname,index[devnum]);
+
+	if ((err = snd_card_register(card)) == 0) {
+		snd_saa7134_cards[devnum] = card;
+		return 0;
+	}
+
+__nodev:
+	snd_card_free(card);
+	return err;
+}
+
+
+static int alsa_device_init(struct saa7134_dev *dev)
+{
+	dev->dmasound.priv_data = dev;
+	alsa_card_saa7134_create(dev,dev->nr);
+	return 1;
+}
+
+static int alsa_device_exit(struct saa7134_dev *dev)
+{
+
+	snd_card_free(snd_saa7134_cards[dev->nr]);
+	snd_saa7134_cards[dev->nr] = NULL;
+	return 1;
+}
+
+/*
+ * Module initializer
+ *
+ * Loops through present saa7134 cards, and assigns an ALSA device
+ * to each one
+ *
+ */
+
+static int saa7134_alsa_init(void)
+{
+	struct saa7134_dev *dev = NULL;
+	struct list_head *list;
+
+	saa7134_dmasound_init = alsa_device_init;
+	saa7134_dmasound_exit = alsa_device_exit;
+
+	printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n");
+
+	list_for_each(list,&saa7134_devlist) {
+		dev = list_entry(list, struct saa7134_dev, devlist);
+		if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130)
+			printk(KERN_INFO "%s/alsa: %s doesn't support digital audio\n",
+				dev->name, saa7134_boards[dev->board].name);
+		else
+			alsa_device_init(dev);
+	}
+
+	if (dev == NULL)
+		printk(KERN_INFO "saa7134 ALSA: no saa7134 cards found\n");
+
+	return 0;
+
+}
+
+/*
+ * Module destructor
+ */
+
+static void saa7134_alsa_exit(void)
+{
+	int idx;
+
+	for (idx = 0; idx < SNDRV_CARDS; idx++) {
+		snd_card_free(snd_saa7134_cards[idx]);
+	}
+
+	saa7134_dmasound_init = NULL;
+	saa7134_dmasound_exit = NULL;
+	printk(KERN_INFO "saa7134 ALSA driver for DMA sound unloaded\n");
+
+	return;
+}
+
+/* We initialize this late, to make sure the sound system is up and running */
+late_initcall(saa7134_alsa_init);
+module_exit(saa7134_alsa_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ricardo Cerqueira");
diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c
new file mode 100644
index 0000000..bc08f1d
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-cards.c
@@ -0,0 +1,8026 @@
+/*
+ *
+ * device driver for philips saa7134 based TV cards
+ * card-specific stuff.
+ *
+ * (c) 2001-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+#include "tuner-xc2028.h"
+#include <media/v4l2-common.h>
+#include <media/tveeprom.h>
+#include "tea5767.h"
+#include "tda18271.h"
+#include "xc5000.h"
+#include "s5h1411.h"
+
+/* commly used strings */
+static char name_mute[]    = "mute";
+static char name_radio[]   = "Radio";
+static char name_tv[]      = "Television";
+static char name_tv_mono[] = "TV (mono only)";
+static char name_comp[]    = "Composite";
+static char name_comp1[]   = "Composite1";
+static char name_comp2[]   = "Composite2";
+static char name_comp3[]   = "Composite3";
+static char name_comp4[]   = "Composite4";
+static char name_svideo[]  = "S-Video";
+
+/* ------------------------------------------------------------------ */
+/* board config info                                                  */
+
+/* If radio_type !=UNSET, radio_addr should be specified
+ */
+
+struct saa7134_board saa7134_boards[] = {
+	[SAA7134_BOARD_UNKNOWN] = {
+		.name		= "UNKNOWN/GENERIC",
+		.audio_clock	= 0x00187de7,
+		.tuner_type	= TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+
+		.inputs         = {{
+			.name = "default",
+			.vmux = 0,
+			.amux = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_PROTEUS_PRO] = {
+		/* /me */
+		.name		= "Proteus Pro [philips reference design]",
+		.audio_clock	= 0x00187de7,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_FLYVIDEO3000] = {
+		/* "Marco d'Itri" <md@Linux.IT> */
+		.name		= "LifeView FlyVIDEO3000",
+		.audio_clock	= 0x00200000,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+
+		.gpiomask       = 0xe000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.gpio = 0x8000,
+			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x0000,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x2000,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = TV,
+			.gpio = 0x8000,
+		},
+	},
+	[SAA7134_BOARD_FLYVIDEO2000] = {
+		/* "TC Wan" <tcwan@cs.usm.my> */
+		.name           = "LifeView/Typhoon FlyVIDEO2000",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_LG_PAL_NEW_TAPC,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+
+		.gpiomask       = 0xe000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x0000,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x2000,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE2,
+			.gpio = 0x8000,
+		},
+	},
+	[SAA7134_BOARD_FLYTVPLATINUM_MINI] = {
+		/* "Arnaud Quette" <aquette@free.fr> */
+		.name           = "LifeView FlyTV Platinum Mini",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,     /* Composite signal on S-Video input */
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_FLYTVPLATINUM_FM] = {
+		/* LifeView FlyTV Platinum FM (LR214WF) */
+		/* "Peter Missel <peter.missel@onlinehome.de> */
+		.name           = "LifeView FlyTV Platinum FM / Gold",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+
+		.gpiomask       = 0x1E000,	/* Set GP16 and unused 15,14,13 to Output */
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.gpio = 0x10000,	/* GP16=1 selects TV input */
+			.tv   = 1,
+		},{
+/*			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x0000,
+			.tv   = 1,
+		},{
+*/			.name = name_comp1,	/* Composite signal on S-Video input */
+			.vmux = 0,
+			.amux = LINE2,
+/*			.gpio = 0x4000,         */
+		},{
+			.name = name_comp2,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE2,
+/*			.gpio = 0x4000,         */
+		},{
+			.name = name_svideo,	/* S-Video signal on S-Video input */
+			.vmux = 8,
+			.amux = LINE2,
+/*			.gpio = 0x4000,         */
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x00000,	/* GP16=0 selects FM radio antenna */
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = TV,
+			.gpio = 0x10000,
+		},
+	},
+	[SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM] = {
+		/* RoverMedia TV Link Pro FM (LR138 REV:I) */
+		/* Eugene Yudin <Eugene.Yudin@gmail.com> */
+		.name		= "RoverMedia TV Link Pro FM",
+		.audio_clock	= 0x00200000,
+		.tuner_type	= TUNER_PHILIPS_FM1216ME_MK3, /* TCL MFPE05 2 */
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0xe000,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.gpio = 0x8000,
+			.tv   = 1,
+		}, {
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x0000,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		}, {
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x2000,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = TV,
+			.gpio = 0x8000,
+		},
+	},
+	[SAA7134_BOARD_EMPRESS] = {
+		/* "Gert Vervoort" <gert.vervoort@philips.com> */
+		.name		= "EMPRESS",
+		.audio_clock	= 0x00187de7,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.empress_addr 	= 0x20,
+
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+		.mpeg      = SAA7134_MPEG_EMPRESS,
+		.video_out = CCIR656,
+	},
+	[SAA7134_BOARD_MONSTERTV] = {
+		/* "K.Ohta" <alpha292@bremen.or.jp> */
+		.name           = "SKNet Monster TV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_NTSC_M,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_MD9717] = {
+		.name		= "Tevion MD 9717",
+		.audio_clock	= 0x00200000,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			/* workaround for problems with normal TV sound */
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	       .mute = {
+		       .name = name_mute,
+		       .amux = TV,
+	       },
+	},
+	[SAA7134_BOARD_TVSTATION_RDS] = {
+		/* Typhoon TV Tuner RDS: Art.Nr. 50694 */
+		.name		= "KNC One TV-Station RDS / Typhoon TV Tuner RDS",
+		.audio_clock	= 0x00200000,
+		.tuner_type	= TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux   = LINE2,
+			.tv   = 1,
+		},{
+
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+
+			.name = "CVid over SVid",
+			.vmux = 0,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_TVSTATION_DVR] = {
+		.name		= "KNC One TV-Station DVR",
+		.audio_clock	= 0x00200000,
+		.tuner_type	= TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.empress_addr 	= 0x20,
+		.tda9887_conf	= TDA9887_PRESENT,
+		.gpiomask	= 0x820000,
+		.inputs		= {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x20000,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0x20000,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x20000,
+		}},
+		.radio		= {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x20000,
+		},
+		.mpeg           = SAA7134_MPEG_EMPRESS,
+		.video_out	= CCIR656,
+	},
+	[SAA7134_BOARD_CINERGY400] = {
+		.name           = "Terratec Cinergy 400 TV",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 4,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp2, /* CVideo over SVideo Connector */
+			.vmux = 0,
+			.amux = LINE1,
+		}}
+	},
+	[SAA7134_BOARD_MD5044] = {
+		.name           = "Medion 5044",
+		.audio_clock    = 0x00187de7, /* was: 0x00200000, */
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			/* workaround for problems with normal TV sound */
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_KWORLD] = {
+		.name           = "Kworld/KuroutoShikou SAA7130-TVPCI",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_NTSC_M,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+	},
+	[SAA7134_BOARD_CINERGY600] = {
+		.name           = "Terratec Cinergy 600 TV",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 4,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp2, /* CVideo over SVideo Connector */
+			.vmux = 0,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_MD7134] = {
+		.name           = "Medion 7134",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = LINE2,
+	       },
+	       .mute = {
+		       .name = name_mute,
+		       .amux = TV,
+		},
+	},
+	[SAA7134_BOARD_TYPHOON_90031] = {
+		/* aka Typhoon "TV+Radio", Art.Nr 90031 */
+		/* Tom Zoerner <tomzo at users sourceforge net> */
+		.name           = "Typhoon TV+Radio 90031",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = LINE2,
+		},
+	},
+	[SAA7134_BOARD_ELSA] = {
+		.name           = "ELSA EX-VISION 300TV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_HITACHI_NTSC,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 4,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+	},
+	[SAA7134_BOARD_ELSA_500TV] = {
+		.name           = "ELSA EX-VISION 500TV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_HITACHI_NTSC,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 7,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 8,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+			.vmux = 8,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+	},
+	[SAA7134_BOARD_ELSA_700TV] = {
+		.name           = "ELSA EX-VISION 700TV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_HITACHI_NTSC,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 4,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 6,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 7,
+			.amux = LINE1,
+		}},
+		.mute           = {
+			.name = name_mute,
+			.amux = TV,
+		},
+	},
+	[SAA7134_BOARD_ASUSTeK_TVFM7134] = {
+		.name           = "ASUS TV-FM 7134",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 4,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 6,
+			.amux = LINE2,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_ASUSTeK_TVFM7135] = {
+		.name           = "ASUS TV-FM 7135",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 0x200000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.gpio = 0x0000,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 4,
+			.amux = LINE2,
+			.gpio = 0x0000,
+		},{
+			.name = name_svideo,
+			.vmux = 6,
+			.amux = LINE2,
+			.gpio = 0x0000,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x200000,
+		},
+		.mute  = {
+			.name = name_mute,
+			.gpio = 0x0000,
+		},
+
+	},
+	[SAA7134_BOARD_VA1000POWER] = {
+		.name           = "AOPEN VA1000 POWER",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_NTSC,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+	},
+	[SAA7134_BOARD_10MOONSTVMASTER] = {
+		/* "lilicheng" <llc@linuxfans.org> */
+		.name           = "10MOONS PCI TV CAPTURE CARD",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_LG_PAL_NEW_TAPC,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 0xe000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x0000,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x2000,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE2,
+			.gpio = 0x8000,
+		},
+	},
+	[SAA7134_BOARD_BMK_MPEX_NOTUNER] = {
+		/* "Andrew de Quincey" <adq@lidskialf.net> */
+		.name		= "BMK MPEX No Tuner",
+		.audio_clock	= 0x200000,
+		.tuner_type	= TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.empress_addr 	= 0x20,
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 4,
+			.amux = LINE1,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_comp3,
+			.vmux = 0,
+			.amux = LINE1,
+		},{
+			.name = name_comp4,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.mpeg      = SAA7134_MPEG_EMPRESS,
+		.video_out = CCIR656,
+	},
+	[SAA7134_BOARD_VIDEOMATE_TV] = {
+		.name           = "Compro VideoMate TV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_NTSC_M,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+	},
+	[SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS] = {
+		.name           = "Compro VideoMate TV Gold+",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_NTSC_M,
+		.gpiomask       = 0x800c0000,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0x06c00012,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x0ac20012,
+		},{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x08c20012,
+			.tv   = 1,
+		}},				/* radio and probably mute is missing */
+	},
+	[SAA7134_BOARD_CRONOS_PLUS] = {
+		/*
+		gpio pins:
+			0  .. 3   BASE_ID
+			4  .. 7   PROTECT_ID
+			8  .. 11  USER_OUT
+			12 .. 13  USER_IN
+			14 .. 15  VIDIN_SEL
+		*/
+		.name           = "Matrox CronosPlus",
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 0xcf00,
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 0,
+			.gpio = 2 << 14,
+		},{
+			.name = name_comp2,
+			.vmux = 0,
+			.gpio = 1 << 14,
+		},{
+			.name = name_comp3,
+			.vmux = 0,
+			.gpio = 0 << 14,
+		},{
+			.name = name_comp4,
+			.vmux = 0,
+			.gpio = 3 << 14,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.gpio = 2 << 14,
+		}},
+	},
+	[SAA7134_BOARD_MD2819] = {
+		.name           = "AverMedia M156 / Medion 2819",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask	= 0x03,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x00,
+		}, {
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x02,
+		}, {
+			.name = name_comp2,
+			.vmux = 0,
+			.amux = LINE1,
+			.gpio = 0x02,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0x02,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE1,
+			.gpio = 0x01,
+		},
+		.mute  = {
+			.name = name_mute,
+			.amux = TV,
+			.gpio = 0x00,
+		},
+	},
+	[SAA7134_BOARD_BMK_MPEX_TUNER] = {
+		/* "Greg Wickham <greg.wickham@grangenet.net> */
+		.name           = "BMK MPEX Tuner",
+		.audio_clock    = 0x200000,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.empress_addr 	= 0x20,
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}},
+		.mpeg      = SAA7134_MPEG_EMPRESS,
+		.video_out = CCIR656,
+	},
+	[SAA7134_BOARD_ASUSTEK_TVFM7133] = {
+		.name           = "ASUS TV-FM 7133",
+		.audio_clock    = 0x00187de7,
+		/* probably wrong, the 7133 one is the NTSC version ...
+		* .tuner_type  = TUNER_PHILIPS_FM1236_MK3 */
+		.tuner_type     = TUNER_LG_NTSC_NEW_TAPC,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+
+		},{
+			.name = name_comp1,
+			.vmux = 4,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 6,
+			.amux = LINE2,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_PINNACLE_PCTV_STEREO] = {
+		.name           = "Pinnacle PCTV Stereo (saa7134)",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_MT2032,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT | TDA9887_INTERCARRIER | TDA9887_PORT2_INACTIVE,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,
+			.vmux = 1,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_MANLI_MTV002] = {
+		/* Ognjen Nastic <ognjen@logosoft.ba> */
+		.name           = "Manli MuchTV M-TV002",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 1,
+			.amux   = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_MANLI_MTV001] = {
+		/* Ognjen Nastic <ognjen@logosoft.ba> UNTESTED */
+		.name           = "Manli MuchTV M-TV001",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_TG3000TV] = {
+		/* TransGear 3000TV */
+		.name           = "Nagase Sangyo TransGear 3000TV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_NTSC_M,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_ECS_TVP3XP] = {
+		.name           = "Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM) ",
+		.audio_clock    = 0x187de7,  /* xtal 32.1 MHz */
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_tv_mono,
+			.vmux   = 1,
+			.amux   = LINE2,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		},{
+			.name   = "CVid over SVid",
+			.vmux   = 0,
+			.amux   = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = LINE2,
+		},
+	},
+	[SAA7134_BOARD_ECS_TVP3XP_4CB5] = {
+		.name           = "Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM)",
+		.audio_clock    = 0x187de7,
+		.tuner_type     = TUNER_PHILIPS_NTSC,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_tv_mono,
+			.vmux   = 1,
+			.amux   = LINE2,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		},{
+			.name   = "CVid over SVid",
+			.vmux   = 0,
+			.amux   = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = LINE2,
+		},
+	},
+    [SAA7134_BOARD_ECS_TVP3XP_4CB6] = {
+		/* Barry Scott <barry.scott@onelan.co.uk> */
+		.name		= "Elitegroup ECS TVP3XP FM1246 Tuner Card (PAL,FM)",
+		.audio_clock    = 0x187de7,
+		.tuner_type     = TUNER_PHILIPS_PAL_I,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_tv_mono,
+			.vmux   = 1,
+			.amux   = LINE2,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		},{
+			.name   = "CVid over SVid",
+			.vmux   = 0,
+			.amux   = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = LINE2,
+		},
+	},
+	[SAA7134_BOARD_AVACSSMARTTV] = {
+		/* Roman Pszonczenko <romka@kolos.math.uni.lodz.pl> */
+		.name           = "AVACS SmartTV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x200000,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER] = {
+		/* Michael Smith <msmith@cbnco.com> */
+		.name           = "AVerMedia DVD EZMaker",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 3,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+		}},
+	},
+	[SAA7134_BOARD_AVERMEDIA_M103] = {
+		/* Massimo Piccioni <dafastidio@libero.it> */
+		.name           = "AVerMedia MiniPCI DVB-T Hybrid M103",
+		.audio_clock    = 0x187de7,
+		.tuner_type     = TUNER_XC2028,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		 .mpeg           = SAA7134_MPEG_DVB,
+		 .inputs         = {{
+			 .name = name_tv,
+			 .vmux = 1,
+			 .amux = TV,
+			 .tv   = 1,
+		 } },
+	},
+	[SAA7134_BOARD_NOVAC_PRIMETV7133] = {
+		/* toshii@netbsd.org */
+		.name           = "Noval Prime TV 7133",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_ALPS_TSBH1_NTSC,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 3,
+		},{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+		}},
+	},
+	[SAA7134_BOARD_AVERMEDIA_STUDIO_305] = {
+		.name           = "AverMedia AverTV Studio 305",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1256_IH3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_STUDIO_505] = {
+		/* Vasiliy Temnikov <vaka@newmail.ru> */
+		.name           = "AverMedia AverTV Studio 505",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		}, {
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_UPMOST_PURPLE_TV] = {
+		.name           = "UPMOST PURPLE TV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1236_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 7,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_svideo,
+			.vmux = 7,
+			.amux = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_ITEMS_MTV005] = {
+		/* Norman Jonas <normanjonas@arcor.de> */
+		.name           = "Items MuchTV Plus / IT-005",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 1,
+			.amux   = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_CINERGY200] = {
+		.name           = "Terratec Cinergy 200 TV",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 4,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp2, /* CVideo over SVideo Connector */
+			.vmux = 0,
+			.amux = LINE1,
+		}},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_VIDEOMATE_TV_PVR] = {
+		/* Alain St-Denis <alain@topaze.homeip.net> */
+		.name           = "Compro VideoMate TV PVR/FM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_NTSC_M,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask	= 0x808c0080,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0x00080,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x00080,
+		},{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2_LEFT,
+			.tv   = 1,
+			.gpio = 0x00080,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x80000,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE2,
+			.gpio = 0x40000,
+		},
+	},
+	[SAA7134_BOARD_SABRENT_SBTTVFM] = {
+		/* Michael Rodriguez-Torrent <mrtorrent@asu.edu> */
+		.name           = "Sabrent SBT-TVFM (saa7130)",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_NTSC_M,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = LINE2,
+		},
+	},
+	[SAA7134_BOARD_ZOLID_XPERT_TV7134] = {
+		/* Helge Jensen <helge.jensen@slog.dk> */
+		.name           = ":Zolid Xpert TV7134",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_NTSC,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+	},
+	[SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE] = {
+		/* "Matteo Az" <matte.az@nospam.libero.it> ;-) */
+		.name           = "Empire PCI TV-Radio LE",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 0x4000,
+		.inputs         = {{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x8000,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x8000,
+		},{
+			.name = name_svideo,
+			.vmux = 6,
+			.amux = LINE1,
+			.gpio = 0x8000,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE1,
+			.gpio = 0x8000,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = TV,
+			.gpio =0x8000,
+		}
+	},
+	[SAA7134_BOARD_AVERMEDIA_STUDIO_307] = {
+		/*
+		Nickolay V. Shmyrev <nshmyrev@yandex.ru>
+		Lots of thanks to Andrey Zolotarev <zolotarev_andrey@mail.ru>
+		*/
+		.name           = "Avermedia AVerTV Studio 307",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1256_IH3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x03,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x00,
+		},{
+			.name = name_comp,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x02,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0x02,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE1,
+			.gpio = 0x01,
+		},
+		.mute  = {
+			.name = name_mute,
+			.amux = LINE1,
+			.gpio = 0x00,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_GO_007_FM] = {
+		.name           = "Avermedia AVerTV GO 007 FM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 0x00300003,
+		/* .gpiomask       = 0x8c240003, */
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x01,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+			.gpio = 0x02,
+		},{
+			.name = name_svideo,
+			.vmux = 6,
+			.amux = LINE1,
+			.gpio = 0x02,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x00300001,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = TV,
+			.gpio = 0x01,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_CARDBUS] = {
+		/* Kees.Blom@cwi.nl */
+		.name           = "AVerMedia Cardbus TV/Radio (E500)",
+		.audio_clock    = 0x187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_CARDBUS_501] = {
+		/* Oldrich Jedlicka <oldium.pro@seznam.cz> */
+		.name           = "AVerMedia Cardbus TV/Radio (E501R)",
+		.audio_clock    = 0x187de7,
+		.tuner_type     = TUNER_ALPS_TSBE5_PAL,
+		.radio_type     = TUNER_TEA5767,
+		.tuner_addr	= 0x61,
+		.radio_addr	= 0x60,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x08000000,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x08000000,
+		}, {
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x08000000,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0x08000000,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x00000000,
+		},
+	},
+	[SAA7134_BOARD_CINERGY400_CARDBUS] = {
+		.name           = "Terratec Cinergy 400 mobile",
+		.audio_clock    = 0x187de7,
+		.tuner_type     = TUNER_ALPS_TSBE5_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_CINERGY600_MK3] = {
+		.name           = "Terratec Cinergy 600 TV MK3",
+		.audio_clock    = 0x00200000,
+		.tuner_type	= TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.rds_addr 	= 0x10,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 4,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp2, /* CVideo over SVideo Connector */
+			.vmux = 0,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_VIDEOMATE_GOLD_PLUS] = {
+		/* Dylan Walkden <dylan_walkden@hotmail.com> */
+		.name		= "Compro VideoMate Gold+ Pal",
+		.audio_clock	= 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask	= 0x1ce780,
+		.inputs		= {{
+			.name = name_svideo,
+			.vmux = 0,		/* CVideo over SVideo Connector - ok? */
+			.amux = LINE1,
+			.gpio = 0x008080,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x008080,
+		},{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x008080,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x80000,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE2,
+			.gpio = 0x0c8000,
+		},
+	},
+	[SAA7134_BOARD_PINNACLE_300I_DVBT_PAL] = {
+		.name           = "Pinnacle PCTV 300i DVB-T + PAL",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_MT2032,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT | TDA9887_INTERCARRIER | TDA9887_PORT2_INACTIVE,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,
+			.vmux = 1,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_PROVIDEO_PV952] = {
+		/* andreas.kretschmer@web.de */
+		.name		= "ProVideo PV952",
+		.audio_clock	= 0x00187de7,
+		.tuner_type	= TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_305] = {
+		/* much like the "studio" version but without radio
+		* and another tuner (sirspiritus@yandex.ru) */
+		.name           = "AverMedia AverTV/305",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_FLYDVBTDUO] = {
+		/* LifeView FlyDVB-T DUO */
+		/* "Nico Sabbi <nsabbi@tiscali.it>  Hartmut Hackmann hartmut.hackmann@t-online.de*/
+		.name           = "LifeView FlyDVB-T DUO / MSI TV@nywhere Duo",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask	= 0x00200000,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.gpio = 0x200000,	/* GPIO21=High for TV input */
+			.tv   = 1,
+		},{
+			.name = name_comp1,	/* Composite signal on S-Video input */
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,	/* S-Video signal on S-Video input */
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x000000,	/* GPIO21=Low for FM radio antenna */
+		},
+	},
+	[SAA7134_BOARD_PHILIPS_TOUGH] = {
+		.name           = "Philips TOUGH DVB-T reference design",
+		.tuner_type	= TUNER_ABSENT,
+		.audio_clock    = 0x00187de7,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_AVERMEDIA_307] = {
+		/*
+		Davydov Vladimir <vladimir@iqmedia.com>
+		*/
+		.name           = "Avermedia AVerTV 307",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_ADS_INSTANT_TV] = {
+		.name           = "ADS Tech Instant TV (saa7135)",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_KWORLD_VSTREAM_XPERT] = {
+		.name           = "Kworld/Tevion V-Stream Xpert TV PVR7134",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_PAL_I,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask	= 0x0700,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+			.gpio   = 0x000,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+			.gpio   = 0x200,		/* gpio by DScaler */
+		},{
+			.name   = name_svideo,
+			.vmux   = 0,
+			.amux   = LINE1,
+			.gpio   = 0x200,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = LINE1,
+			.gpio   = 0x100,
+		},
+		.mute  = {
+			.name = name_mute,
+			.amux = TV,
+			.gpio = 0x000,
+		},
+	},
+	[SAA7134_BOARD_FLYDVBT_DUO_CARDBUS] = {
+		.name		= "LifeView/Typhoon/Genius FlyDVB-T Duo Cardbus",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask	= 0x00200000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.gpio = 0x200000,	/* GPIO21=High for TV input */
+			.tv   = 1,
+		},{
+			.name = name_svideo,	/* S-Video signal on S-Video input */
+			.vmux = 8,
+			.amux = LINE2,
+		},{
+			.name = name_comp1,	/* Composite signal on S-Video input */
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE2,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x000000,	/* GPIO21=Low for FM radio antenna */
+		},
+	},
+	[SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII] = {
+		.name           = "Compro VideoMate TV Gold+II",
+		.audio_clock    = 0x002187de7,
+		.tuner_type     = TUNER_LG_PAL_NEW_TAPC,
+		.radio_type     = TUNER_TEA5767,
+		.tuner_addr     = 0x63,
+		.radio_addr     = 0x60,
+		.gpiomask       = 0x8c1880,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 0,
+			.amux = LINE1,
+			.gpio = 0x800800,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x801000,
+		},{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x800000,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x880000,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE2,
+			.gpio = 0x840000,
+		},
+	},
+	[SAA7134_BOARD_KWORLD_XPERT] = {
+		/*
+		FIXME:
+		- Remote control doesn't initialize properly.
+		- Audio volume starts muted,
+		then gradually increases after channel change.
+		- Overlay scaling problems (application error?)
+		- Composite S-Video untested.
+		From: Konrad Rzepecki <hannibal@megapolis.pl>
+		*/
+		.name           = "Kworld Xpert TV PVR7134",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_TENA_9533_DI,
+		.radio_type     = TUNER_TEA5767,
+		.tuner_addr	= 0x61,
+		.radio_addr	= 0x60,
+		.gpiomask	= 0x0700,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+			.gpio   = 0x000,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+			.gpio   = 0x200,		/* gpio by DScaler */
+		},{
+			.name   = name_svideo,
+			.vmux   = 0,
+			.amux   = LINE1,
+			.gpio   = 0x200,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = LINE1,
+			.gpio   = 0x100,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = TV,
+			.gpio = 0x000,
+		},
+	},
+	[SAA7134_BOARD_FLYTV_DIGIMATRIX] = {
+		.name		= "FlyTV mini Asus Digimatrix",
+		.audio_clock	= 0x00200000,
+		.tuner_type	= TUNER_LG_TALN,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+		.radio = {
+			.name = name_radio,		/* radio unconfirmed */
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_KWORLD_TERMINATOR] = {
+		/* Kworld V-Stream Studio TV Terminator */
+		/* "James Webb <jrwebb@qwest.net> */
+		.name           = "V-Stream Studio TV Terminator",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.gpiomask       = 1 << 21,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.gpio = 0x0000000,
+			.tv   = 1,
+		},{
+			.name = name_comp1,     /* Composite input */
+			.vmux = 3,
+			.amux = LINE2,
+			.gpio = 0x0000000,
+		},{
+			.name = name_svideo,    /* S-Video input */
+			.vmux = 8,
+			.amux = LINE2,
+			.gpio = 0x0000000,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_YUAN_TUN900] = {
+		/* FIXME:
+		 * S-Video and composite sources untested.
+		 * Radio not working.
+		 * Remote control not yet implemented.
+		 * From : codemaster@webgeeks.be */
+		.name           = "Yuan TUN-900 (saa7135)",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr= ADDR_UNSET,
+		.radio_addr= ADDR_UNSET,
+		.gpiomask       = 0x00010003,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x01,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+			.gpio = 0x02,
+		},{
+			.name = name_svideo,
+			.vmux = 6,
+			.amux = LINE2,
+			.gpio = 0x02,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE1,
+			.gpio = 0x00010003,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = TV,
+			.gpio = 0x01,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_409FM] = {
+		/* <http://tuner.beholder.ru>, Sergey <skiv@orel.ru> */
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV 409 FM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
+		.inputs         = {{
+			  .name = name_tv,
+			  .vmux = 3,
+			  .amux = TV,
+			  .tv   = 1,
+		},{
+			  .name = name_comp1,
+			  .vmux = 1,
+			  .amux = LINE1,
+		},{
+			  .name = name_svideo,
+			  .vmux = 8,
+			  .amux = LINE1,
+		}},
+		.radio = {
+			  .name = name_radio,
+			  .amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_GOTVIEW_7135] = {
+		/* Mike Baikov <mike@baikov.com> */
+		/* Andrey Cvetcov <ays14@yandex.ru> */
+		.name            = "GoTView 7135 PCI",
+		.audio_clock     = 0x00187de7,
+		.tuner_type      = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type      = UNSET,
+		.tuner_addr      = ADDR_UNSET,
+		.radio_addr      = ADDR_UNSET,
+		.tda9887_conf    = TDA9887_PRESENT,
+		.gpiomask        = 0x00200003,
+		.inputs          = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x00200003,
+		},{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x00200003,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x00200003,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0x00200003,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x00200003,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = TV,
+			.gpio = 0x00200003,
+		},
+	},
+	[SAA7134_BOARD_PHILIPS_EUROPA] = {
+		.name           = "Philips EUROPA V3 reference design",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TD1316,
+		.radio_type     = UNSET,
+		.tuner_addr	= 0x61,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 3,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE2,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_VIDEOMATE_DVBT_300] = {
+		.name           = "Compro Videomate DVB-T300",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TD1316,
+		.radio_type     = UNSET,
+		.tuner_addr	= 0x61,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 3,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 1,
+			.amux   = LINE2,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_VIDEOMATE_DVBT_200] = {
+		.name           = "Compro Videomate DVB-T200",
+		.tuner_type	= TUNER_ABSENT,
+		.audio_clock    = 0x00187de7,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_RTD_VFG7350] = {
+		.name		= "RTD Embedded Technologies VFG7350",
+		.audio_clock	= 0x00200000,
+		.tuner_type	= TUNER_ABSENT,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.empress_addr 	= 0x21,
+		.inputs		= {{
+			.name   = "Composite 0",
+			.vmux   = 0,
+			.amux   = LINE1,
+		},{
+			.name   = "Composite 1",
+			.vmux   = 1,
+			.amux   = LINE2,
+		},{
+			.name   = "Composite 2",
+			.vmux   = 2,
+			.amux   = LINE1,
+		},{
+			.name   = "Composite 3",
+			.vmux   = 3,
+			.amux   = LINE2,
+		},{
+			.name   = "S-Video 0",
+			.vmux   = 8,
+			.amux   = LINE1,
+		},{
+			.name   = "S-Video 1",
+			.vmux   = 9,
+			.amux   = LINE2,
+		}},
+		.mpeg           = SAA7134_MPEG_EMPRESS,
+		.video_out      = CCIR656,
+		.vid_port_opts  = ( SET_T_CODE_POLARITY_NON_INVERTED |
+				    SET_CLOCK_NOT_DELAYED |
+				    SET_CLOCK_INVERTED |
+				    SET_VSYNC_OFF ),
+	},
+	[SAA7134_BOARD_RTD_VFG7330] = {
+		.name		= "RTD Embedded Technologies VFG7330",
+		.audio_clock	= 0x00200000,
+		.tuner_type	= TUNER_ABSENT,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs		= {{
+			.name   = "Composite 0",
+			.vmux   = 0,
+			.amux   = LINE1,
+		},{
+			.name   = "Composite 1",
+			.vmux   = 1,
+			.amux   = LINE2,
+		},{
+			.name   = "Composite 2",
+			.vmux   = 2,
+			.amux   = LINE1,
+		},{
+			.name   = "Composite 3",
+			.vmux   = 3,
+			.amux   = LINE2,
+		},{
+			.name   = "S-Video 0",
+			.vmux   = 8,
+			.amux   = LINE1,
+		},{
+			.name   = "S-Video 1",
+			.vmux   = 9,
+			.amux   = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_FLYTVPLATINUM_MINI2] = {
+		.name           = "LifeView FlyTV Platinum Mini2",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,     /* Composite signal on S-Video input */
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180] = {
+		/* Michael Krufky <mkrufky@m1k.net>
+		 * Uses Alps Electric TDHU2, containing NXT2004 ATSC Decoder
+		 * AFAIK, there is no analog demod, thus,
+		 * no support for analog television.
+		 */
+		.name           = "AVerMedia AVerTVHD MCE A180",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_MONSTERTV_MOBILE] = {
+		.name           = "SKNet MonsterTV Mobile",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+
+		.inputs         = {{
+			  .name = name_tv,
+			  .vmux = 1,
+			  .amux = TV,
+			  .tv   = 1,
+		},{
+			  .name = name_comp1,
+			  .vmux = 3,
+			  .amux = LINE1,
+		},{
+			  .name = name_svideo,
+			  .vmux = 6,
+			  .amux = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_PINNACLE_PCTV_110i] = {
+	       .name           = "Pinnacle PCTV 40i/50i/110i (saa7133)",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.gpiomask       = 0x080200000,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 4,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE2,
+		}, {
+			.name = name_comp2,
+			.vmux = 0,
+			.amux = LINE2,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_ASUSTeK_P7131_DUAL] = {
+		.name           = "ASUSTeK P7131 Dual",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask	= 1 << 21,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x0000000,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE2,
+			.gpio = 0x0200000,
+		},{
+			.name = name_comp2,
+			.vmux = 0,
+			.amux = LINE2,
+			.gpio = 0x0200000,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+			.gpio = 0x0200000,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_SEDNA_PC_TV_CARDBUS] = {
+		/* Paul Tom Zalac <pzalac@gmail.com> */
+		/* Pavel Mihaylov <bin@bash.info> */
+		.name           = "Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)",
+				/* Sedna/MuchTV (OEM) Cardbus TV Tuner */
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.gpiomask       = 0xe880c0,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 6,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV] = {
+		/* "Cyril Lacoux (Yack)" <clacoux@ifeelgood.org> */
+		.name           = "ASUS Digimatrix TV",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_PHILIPS_TIGER] = {
+		.name           = "Philips Tiger reference design",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tuner_config   = 0,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 0x0200000,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = TV,
+			.gpio   = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_MSI_TVATANYWHERE_PLUS] = {
+		.name           = "MSI TV@Anywhere plus",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 1 << 21,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE2,	/* unconfirmed, taken from Philips driver */
+		},{
+			.name   = name_comp2,
+			.vmux   = 0,		/* untested, Composite over S-Video */
+			.amux   = LINE2,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = TV,
+			.gpio   = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_CINERGY250PCI] = {
+		/* remote-control does not work. The signal about a
+		   key press comes in via gpio, but the key code
+		   doesn't. Neither does it have an i2c remote control
+		   interface. */
+		.name           = "Terratec Cinergy 250 PCI TV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 0x80200000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_svideo,  /* NOT tested */
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = TV,
+			.gpio   = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_FLYDVB_TRIO] = {
+		/* LifeView LR319 FlyDVB Trio */
+		/* Peter Missel <peter.missel@onlinehome.de> */
+		.name           = "LifeView FlyDVB Trio",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask	= 0x00200000,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_tv,	/* Analog broadcast/cable TV */
+			.vmux = 1,
+			.amux = TV,
+			.gpio = 0x200000,	/* GPIO21=High for TV input */
+			.tv   = 1,
+		},{
+			.name = name_svideo,	/* S-Video signal on S-Video input */
+			.vmux = 8,
+			.amux = LINE2,
+		},{
+			.name = name_comp1,	/* Composite signal on S-Video input */
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE2,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x000000,	/* GPIO21=Low for FM radio antenna */
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_777] = {
+		.name           = "AverTV DVB-T 777",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_comp1,
+			.vmux   = 1,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_FLYDVBT_LR301] = {
+		/* LifeView FlyDVB-T */
+		/* Giampiero Giancipoli <gianci@libero.it> */
+		.name           = "LifeView FlyDVB-T / Genius VideoWonder DVB-T",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_comp1,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,	/* S-Video signal on S-Video input */
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331] = {
+		.name           = "ADS Instant TV Duo Cardbus PTV331",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 0x00600000, /* Bit 21 0=Radio, Bit 22 0=TV */
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+			.gpio   = 0x00200000,
+		}},
+	},
+	[SAA7134_BOARD_TEVION_DVBT_220RF] = {
+		.name           = "Tevion/KWorld DVB-T 220RF",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 1 << 21,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		},{
+			.name   = name_comp2,
+			.vmux   = 0,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = TV,
+			.gpio   = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_KWORLD_DVBT_210] = {
+		.name           = "KWorld DVB-T 210",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 1 << 21,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = TV,
+			.gpio   = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_KWORLD_ATSC110] = {
+		.name           = "Kworld ATSC110/115",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TUV1236D,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_AVERMEDIA_A169_B] = {
+		/* AVerMedia A169  */
+		/* Rickard Osser <ricky@osser.se>  */
+		/* This card has two saa7134 chips on it,
+		   but only one of them is currently working. */
+		.name		= "AVerMedia A169 B",
+		.audio_clock    = 0x02187de7,
+		.tuner_type	= TUNER_LG_TALN,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x0a60000,
+	},
+	[SAA7134_BOARD_AVERMEDIA_A169_B1] = {
+		/* AVerMedia A169 */
+		/* Rickard Osser <ricky@osser.se> */
+		.name		= "AVerMedia A169 B1",
+		.audio_clock    = 0x02187de7,
+		.tuner_type	= TUNER_LG_TALN,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0xca60000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 4,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x04a61000,
+		},{
+			.name = name_comp2,  /*  Composite SVIDEO (B/W if signal is carried with SVIDEO) */
+			.vmux = 1,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 9,           /* 9 is correct as S-VIDEO1 according to a169.inf! */
+			.amux = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_MD7134_BRIDGE_2] = {
+		/* The second saa7134 on this card only serves as DVB-S host bridge */
+		.name           = "Medion 7134 Bridge #2",
+		.audio_clock    = 0x00187de7,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+	},
+	[SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS] = {
+		.name		= "LifeView FlyDVB-T Hybrid Cardbus/MSI TV @nywhere A/D NB",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 0x00600000, /* Bit 21 0=Radio, Bit 22 0=TV */
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.gpio = 0x200000,	/* GPIO21=High for TV input */
+			.tv   = 1,
+		},{
+			.name = name_svideo,	/* S-Video signal on S-Video input */
+			.vmux = 8,
+			.amux = LINE2,
+		},{
+			.name = name_comp1,	/* Composite signal on S-Video input */
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE2,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x000000,	/* GPIO21=Low for FM radio antenna */
+		},
+	},
+	[SAA7134_BOARD_FLYVIDEO3000_NTSC] = {
+		/* "Zac Bowling" <zac@zacbowling.com> */
+		.name           = "LifeView FlyVIDEO3000 (NTSC)",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_NTSC,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+
+		.gpiomask       = 0xe000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.gpio = 0x8000,
+			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x0000,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x2000,
+		},
+			.mute = {
+			.name = name_mute,
+			.amux = TV,
+			.gpio = 0x8000,
+		},
+	},
+	[SAA7134_BOARD_MEDION_MD8800_QUADRO] = {
+		.name           = "Medion Md8800 Quadro",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_FLYDVBS_LR300] = {
+		/* LifeView FlyDVB-s */
+		/* Igor M. Liplianin <liplianin@tut.by> */
+		.name           = "LifeView FlyDVB-S /Acorp TV134DS",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_comp1,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,	/* S-Video signal on S-Video input */
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_PROTEUS_2309] = {
+		.name           = "Proteus Pro 2309",
+		.audio_clock    = 0x00187de7,
+		.tuner_type	= TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_A16AR] = {
+		/* Petr Baudis <pasky@ucw.cz> */
+		.name           = "AVerMedia TV Hybrid A16AR",
+		.audio_clock    = 0x187de7,
+		.tuner_type     = TUNER_PHILIPS_TD1316, /* untested */
+		.radio_type     = TUNER_TEA5767, /* untested */
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = 0x60,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_ASUS_EUROPA2_HYBRID] = {
+		.name           = "Asus Europa2 OEM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT| TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 3,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 4,
+			.amux   = LINE2,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = LINE1,
+		},
+	},
+	[SAA7134_BOARD_PINNACLE_PCTV_310i] = {
+		.name           = "Pinnacle PCTV 310i",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tuner_config   = 1,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 0x000200000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 4,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux   = TV,
+			.gpio   = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_STUDIO_507] = {
+		/* Mikhail Fedotov <mo_fedotov@mail.ru> */
+		.name           = "Avermedia AVerTV Studio 507",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1256_IH3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x03,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x00,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+			.gpio = 0x00,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+			.gpio = 0x00,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+			.gpio = 0x00,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x01,
+		},
+		.mute  = {
+			.name = name_mute,
+			.amux = LINE1,
+			.gpio = 0x00,
+		},
+	},
+	[SAA7134_BOARD_VIDEOMATE_DVBT_200A] = {
+		/* Francis Barber <fedora@barber-family.id.au> */
+		.name           = "Compro Videomate DVB-T200A",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 3,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 1,
+			.amux   = LINE2,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_HAUPPAUGE_HVR1110] = {
+		/* Thomas Genty <tomlohave@gmail.com> */
+		/* David Bentham <db260179@hotmail.com> */
+		.name           = "Hauppauge WinTV-HVR1110 DVB-T/Hybrid",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tuner_config   = 1,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 0x0200100,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x0000100,
+		}, {
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x0200100,
+		},
+	},
+	[SAA7134_BOARD_HAUPPAUGE_HVR1150] = {
+		.name           = "Hauppauge WinTV-HVR1150 ATSC/QAM-Hybrid",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tuner_config   = 3,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.ts_type	= SAA7134_MPEG_TS_SERIAL,
+		.ts_force_val   = 1,
+		.gpiomask       = 0x0800100, /* GPIO 21 is an INPUT */
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x0000100,
+		}, {
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x0800100, /* GPIO 23 HI for FM */
+		},
+	},
+	[SAA7134_BOARD_HAUPPAUGE_HVR1120] = {
+		.name           = "Hauppauge WinTV-HVR1120 DVB-T/Hybrid",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tuner_config   = 3,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.ts_type	= SAA7134_MPEG_TS_SERIAL,
+		.gpiomask       = 0x0800100, /* GPIO 21 is an INPUT */
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x0000100,
+		}, {
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x0800100, /* GPIO 23 HI for FM */
+		},
+	},
+	[SAA7134_BOARD_CINERGY_HT_PCMCIA] = {
+		.name           = "Terratec Cinergy HT PCMCIA",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 6,
+			.amux   = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_ENCORE_ENLTV] = {
+	/* Steven Walter <stevenrwalter@gmail.com>
+	   Juan Pablo Sormani <sorman@gmail.com> */
+		.name           = "Encore ENLTV",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_TNF_5335MF,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = 3,
+			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+			.vmux = 7,
+			.amux = 4,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = 2,
+		},{
+			.name = name_svideo,
+			.vmux = 0,
+			.amux = 2,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+/*			.gpio = 0x00300001,*/
+			.gpio = 0x20000,
+
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = 0,
+		},
+	},
+	[SAA7134_BOARD_ENCORE_ENLTV_FM] = {
+  /*	Juan Pablo Sormani <sorman@gmail.com> */
+		.name           = "Encore ENLTV-FM",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_FCV1236D,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = 3,
+			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+			.vmux = 7,
+			.amux = 4,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = 2,
+		},{
+			.name = name_svideo,
+			.vmux = 0,
+			.amux = 2,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x20000,
+
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = 0,
+		},
+	},
+	[SAA7134_BOARD_ENCORE_ENLTV_FM53] = {
+		.name           = "Encore ENLTV-FM v5.3",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_TNF_5335MF,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask	= 0x7000,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 1,
+			.amux = 1,
+			.tv   = 1,
+			.gpio = 0x50000,
+		}, {
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = 2,
+			.gpio = 0x2000,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = 2,
+			.gpio = 0x2000,
+		} },
+		.radio = {
+			.name = name_radio,
+			.vmux = 1,
+			.amux = 1,
+		},
+		.mute = {
+			.name = name_mute,
+			.gpio = 0xf000,
+			.amux = 0,
+		},
+	},
+	[SAA7134_BOARD_ENCORE_ENLTV_FM3] = {
+		.name           = "Encore ENLTV-FM 3",
+		.audio_clock    = 0x02187de7,
+		.tuner_type     = TUNER_TENA_TNF_5337,
+		.radio_type     = TUNER_TEA5767,
+		.tuner_addr	= 0x61,
+		.radio_addr	= 0x60,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.vmux = 1,
+			.amux = LINE1,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE1,
+			.gpio = 0x43000,
+		},
+	},
+	[SAA7134_BOARD_CINERGY_HT_PCI] = {
+		.name           = "Terratec Cinergy HT PCI",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 6,
+			.amux   = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_PHILIPS_TIGER_S] = {
+		.name           = "Philips Tiger - S Reference design",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tuner_config   = 2,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 0x0200000,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = TV,
+			.gpio   = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_M102] = {
+		.name           = "Avermedia M102",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 1<<21,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 6,
+			.amux = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_ASUS_P7131_4871] = {
+		.name           = "ASUS P7131 4871",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tuner_config   = 2,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 0x0200000,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+			.gpio   = 0x0200000,
+		}},
+	},
+	[SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA] = {
+		.name           = "ASUSTeK P7131 Hybrid",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tuner_config   = 2,
+		.gpiomask	= 1 << 21,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x0000000,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE2,
+			.gpio = 0x0200000,
+		},{
+			.name = name_comp2,
+			.vmux = 0,
+			.amux = LINE2,
+			.gpio = 0x0200000,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+			.gpio = 0x0200000,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_ASUSTeK_P7131_ANALOG] = {
+	       .name           = "ASUSTeK P7131 Analog",
+	       .audio_clock    = 0x00187de7,
+	       .tuner_type     = TUNER_PHILIPS_TDA8290,
+	       .radio_type     = UNSET,
+	       .tuner_addr     = ADDR_UNSET,
+	       .radio_addr     = ADDR_UNSET,
+	       .gpiomask       = 1 << 21,
+	       .inputs         = {{
+		       .name = name_tv,
+		       .vmux = 1,
+		       .amux = TV,
+		       .tv   = 1,
+		       .gpio = 0x0000000,
+	       }, {
+		       .name = name_comp1,
+		       .vmux = 3,
+		       .amux = LINE2,
+	       }, {
+		       .name = name_comp2,
+		       .vmux = 0,
+		       .amux = LINE2,
+	       }, {
+		       .name = name_svideo,
+		       .vmux = 8,
+		       .amux = LINE2,
+	       } },
+	       .radio = {
+		       .name = name_radio,
+		       .amux = TV,
+		       .gpio = 0x0200000,
+	       },
+	},
+	[SAA7134_BOARD_SABRENT_TV_PCB05] = {
+		.name           = "Sabrent PCMCIA TV-PCB05",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_comp2,
+			.vmux = 0,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.mute = {
+			.name = name_mute,
+			.amux = TV,
+		},
+	},
+	[SAA7134_BOARD_10MOONSTVMASTER3] = {
+		/* Tony Wan <aloha_cn@hotmail.com> */
+		.name           = "10MOONS TM300 TV Card",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_LG_PAL_NEW_TAPC,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.gpiomask       = 0x7000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x0000,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x2000,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0x2000,
+		}},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE2,
+			.gpio = 0x3000,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_SUPER_007] = {
+		.name           = "Avermedia Super 007",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tuner_config   = 0,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv, /* FIXME: analog tv untested */
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		}},
+	},
+	[SAA7134_BOARD_AVERMEDIA_M135A] = {
+		.name           = "Avermedia PCI pure analog (M135A)",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tuner_config   = 2,
+		.gpiomask       = 0x020200000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x00200000,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = TV,
+			.gpio = 0x01,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_M733A] = {
+		.name		= "Avermedia PCI M733A",
+		.audio_clock	= 0x00187de7,
+		.tuner_type	= TUNER_PHILIPS_TDA8290,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tuner_config	= 0,
+		.gpiomask	= 0x020200000,
+		.inputs		= {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x00200000,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = TV,
+			.gpio = 0x01,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_401] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV 401",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 0x00008000,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_403] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV 403",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 0x00008000,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 1,
+			.amux   = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+	},
+	[SAA7134_BOARD_BEHOLD_403FM] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV 403 FM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 0x00008000,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 1,
+			.amux   = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_405] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV 405",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+	},
+	[SAA7134_BOARD_BEHOLD_405FM] = {
+		/* Sergey <skiv@orel.ru> */
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV 405 FM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_407] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
+		.name 		= "Beholder BeholdTV 407",
+		.audio_clock 	= 0x00187de7,
+		.tuner_type 	= TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type 	= UNSET,
+		.tuner_addr 	= ADDR_UNSET,
+		.radio_addr 	= ADDR_UNSET,
+		.tda9887_conf 	= TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
+		.inputs = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0xc0c000,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+			.gpio = 0xc0c000,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv = 1,
+			.gpio = 0xc0c000,
+		}},
+	},
+	[SAA7134_BOARD_BEHOLD_407FM] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
+		.name 		= "Beholder BeholdTV 407 FM",
+		.audio_clock 	= 0x00187de7,
+		.tuner_type 	= TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type 	= UNSET,
+		.tuner_addr 	= ADDR_UNSET,
+		.radio_addr 	= ADDR_UNSET,
+		.tda9887_conf 	= TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
+		.inputs = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0xc0c000,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+			.gpio = 0xc0c000,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv = 1,
+			.gpio = 0xc0c000,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0xc0c000,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_409] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV 409",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_BEHOLD_505FM] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV 505 FM",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.mute = {
+			.name = name_mute,
+			.amux = LINE1,
+		},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_505RDS_MK5] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV 505 RDS",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_FM1216MK5,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.rds_addr 	= 0x10,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE1,
+		},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_507_9FM] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV 507 FM / BeholdTV 509 FM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+			.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_507RDS_MK5] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV 507 RDS",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216MK5,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.rds_addr 	= 0x10,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+			.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_507RDS_MK3] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV 507 RDS",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.rds_addr 	= 0x10,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+			.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/* Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV Columbus TV/FM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_ALPS_TSBE5_PAL,
+		.radio_type     = TUNER_TEA5767,
+		.tuner_addr     = 0xc2 >> 1,
+		.radio_addr     = 0xc0 >> 1,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x000A8004,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x000A8004,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+			.gpio = 0x000A8000,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0x000A8000,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x000A8000,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_607FM_MK3] = {
+		/* Andrey Melnikoff <temnota@kmv.ru> */
+		.name           = "Beholder BeholdTV 607 FM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_609FM_MK3] = {
+		/* Andrey Melnikoff <temnota@kmv.ru> */
+		.name           = "Beholder BeholdTV 609 FM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_607FM_MK5] = {
+		/* Andrey Melnikoff <temnota@kmv.ru> */
+		.name           = "Beholder BeholdTV 607 FM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216MK5,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_609FM_MK5] = {
+		/* Andrey Melnikoff <temnota@kmv.ru> */
+		.name           = "Beholder BeholdTV 609 FM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216MK5,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_607RDS_MK3] = {
+		/* Andrey Melnikoff <temnota@kmv.ru> */
+		.name           = "Beholder BeholdTV 607 RDS",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.rds_addr 	= 0x10,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_609RDS_MK3] = {
+		/* Andrey Melnikoff <temnota@kmv.ru> */
+		.name           = "Beholder BeholdTV 609 RDS",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.rds_addr 	= 0x10,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_607RDS_MK5] = {
+		/* Andrey Melnikoff <temnota@kmv.ru> */
+		.name           = "Beholder BeholdTV 607 RDS",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216MK5,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.rds_addr 	= 0x10,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_609RDS_MK5] = {
+		/* Andrey Melnikoff <temnota@kmv.ru> */
+		.name           = "Beholder BeholdTV 609 RDS",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216MK5,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.rds_addr 	= 0x10,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_M6] = {
+		/* Igor Kuznetsov <igk@igk.ru> */
+		/* Andrey Melnikoff <temnota@kmv.ru> */
+		/* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+		/* Alexey Osipov <lion-simba@pridelands.ru> */
+		.name           = "Beholder BeholdTV M6",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.empress_addr 	= 0x20,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+		.mpeg  = SAA7134_MPEG_EMPRESS,
+		.video_out = CCIR656,
+		.vid_port_opts  = (SET_T_CODE_POLARITY_NON_INVERTED |
+					SET_CLOCK_NOT_DELAYED |
+					SET_CLOCK_INVERTED |
+					SET_VSYNC_OFF),
+	},
+	[SAA7134_BOARD_BEHOLD_M63] = {
+		/* Igor Kuznetsov <igk@igk.ru> */
+		/* Andrey Melnikoff <temnota@kmv.ru> */
+		/* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV M63",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.empress_addr 	= 0x20,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+		.mpeg  = SAA7134_MPEG_EMPRESS,
+		.video_out = CCIR656,
+		.vid_port_opts  = (SET_T_CODE_POLARITY_NON_INVERTED |
+					SET_CLOCK_NOT_DELAYED |
+					SET_CLOCK_INVERTED |
+					SET_VSYNC_OFF),
+	},
+	[SAA7134_BOARD_BEHOLD_M6_EXTRA] = {
+		/* Igor Kuznetsov <igk@igk.ru> */
+		/* Andrey Melnikoff <temnota@kmv.ru> */
+		/* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+		/* Alexey Osipov <lion-simba@pridelands.ru> */
+		.name           = "Beholder BeholdTV M6 Extra",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216MK5,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.rds_addr 	= 0x10,
+		.empress_addr 	= 0x20,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+		.mpeg  = SAA7134_MPEG_EMPRESS,
+		.video_out = CCIR656,
+		.vid_port_opts  = (SET_T_CODE_POLARITY_NON_INVERTED |
+					SET_CLOCK_NOT_DELAYED |
+					SET_CLOCK_INVERTED |
+					SET_VSYNC_OFF),
+	},
+	[SAA7134_BOARD_TWINHAN_DTV_DVB_3056] = {
+		.name           = "Twinhan Hybrid DTV-DVB 3056 PCI",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tuner_config   = 2,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 0x0200000,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		}, {
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,		/* untested */
+			.amux   = LINE1,
+		} },
+		.radio = {
+			.name   = name_radio,
+			.amux   = TV,
+			.gpio   = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_GENIUS_TVGO_A11MCE] = {
+		/* Adrian Pardini <pardo.bsso@gmail.com> */
+		.name		= "Genius TVGO AM11MCE",
+		.audio_clock	= 0x00200000,
+		.tuner_type	= TUNER_TNF_5335MF,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 0xf000,
+		.inputs         = {{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x0000,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x2000,
+			.tv = 1
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0x2000,
+	} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x1000,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE2,
+			.gpio = 0x6000,
+		},
+	},
+	[SAA7134_BOARD_PHILIPS_SNAKE] = {
+		.name           = "NXP Snake DVB-S reference design",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		} },
+	},
+	[SAA7134_BOARD_CREATIX_CTX953] = {
+		.name         = "Medion/Creatix CTX953 Hybrid",
+		.audio_clock  = 0x00187de7,
+		.tuner_type   = TUNER_PHILIPS_TDA8290,
+		.radio_type   = UNSET,
+		.tuner_addr   = ADDR_UNSET,
+		.radio_addr   = ADDR_UNSET,
+		.tuner_config = 0,
+		.mpeg         = SAA7134_MPEG_DVB,
+		.inputs       = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+	},
+	[SAA7134_BOARD_MSI_TVANYWHERE_AD11] = {
+		.name           = "MSI TV@nywhere A/D v1.1",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tuner_config   = 2,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 0x0200000,
+		.inputs = { {
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		}, {
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		} },
+		.radio = {
+			.name   = name_radio,
+			.amux   = TV,
+			.gpio   = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_CARDBUS_506] = {
+		.name           = "AVerMedia Cardbus TV/Radio (E506R)",
+		.audio_clock    = 0x187de7,
+		.tuner_type     = TUNER_XC2028,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		 .mpeg           = SAA7134_MPEG_DVB,
+		 .inputs         = {{
+			 .name = name_tv,
+			 .vmux = 1,
+			 .amux = TV,
+			 .tv   = 1,
+		 }, {
+			 .name = name_comp1,
+			 .vmux = 3,
+			 .amux = LINE1,
+		 }, {
+			 .name = name_svideo,
+			 .vmux = 8,
+			 .amux = LINE2,
+		 } },
+		 .radio = {
+			 .name = name_radio,
+			 .amux = TV,
+		 },
+	},
+	[SAA7134_BOARD_AVERMEDIA_A16D] = {
+		.name           = "AVerMedia Hybrid TV/Radio (A16D)",
+		.audio_clock    = 0x187de7,
+		.tuner_type     = TUNER_XC2028,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}, {
+			.name = name_comp,
+			.vmux = 0,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_M115] = {
+		.name           = "Avermedia M115",
+		.audio_clock    = 0x187de7,
+		.tuner_type     = TUNER_XC2028,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		} },
+	},
+	[SAA7134_BOARD_VIDEOMATE_T750] = {
+		/* John Newbigin <jn@it.swin.edu.au> */
+		.name           = "Compro VideoMate T750",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_XC2028,
+		.radio_type     = UNSET,
+		.tuner_addr	= 0x61,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 3,
+			.amux   = TV,
+			.tv     = 1,
+		}, {
+			.name   = name_comp1,
+			.vmux   = 1,
+			.amux   = LINE2,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+		}
+	},
+	[SAA7134_BOARD_AVERMEDIA_A700_PRO] = {
+		/* Matthias Schwarzott <zzam@gentoo.org> */
+		.name           = "Avermedia DVB-S Pro A700",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = { {
+			.name = name_comp,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 6,
+			.amux = LINE1,
+		} },
+	},
+	[SAA7134_BOARD_AVERMEDIA_A700_HYBRID] = {
+		/* Matthias Schwarzott <zzam@gentoo.org> */
+		.name           = "Avermedia DVB-S Hybrid+FM A700",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_XC2028,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = { {
+			.name   = name_tv,
+			.vmux   = 4,
+			.amux   = TV,
+			.tv     = 1,
+		}, {
+			.name = name_comp,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 6,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_H6] = {
+		/* Igor Kuznetsov <igk@igk.ru> */
+		.name           = "Beholder BeholdTV H6",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FMD1216MEX_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_ASUSTeK_TIGER_3IN1] = {
+		.name           = "Asus Tiger 3in1",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tuner_config   = 2,
+		.gpiomask       = 1 << 21,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp,
+			.vmux = 0,
+			.amux = LINE2,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_ASUSTeK_PS3_100] = {
+		.name           = "Asus My Cinema PS3-100",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tuner_config   = 2,
+		.gpiomask       = 1 << 21,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp,
+			.vmux = 0,
+			.amux = LINE2,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_REAL_ANGEL_220] = {
+		.name           = "Zogis Real Angel 220",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_TNF_5335MF,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.gpiomask       = 0x801a8087,
+		.inputs = { {
+			.name   = name_tv,
+			.vmux   = 3,
+			.amux   = LINE2,
+			.tv     = 1,
+			.gpio   = 0x624000,
+		}, {
+			.name   = name_comp1,
+			.vmux   = 1,
+			.amux   = LINE1,
+			.gpio   = 0x624000,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 1,
+			.amux   = LINE1,
+			.gpio   = 0x624000,
+		} },
+		.radio = {
+			.name   = name_radio,
+			.amux   = LINE2,
+			.gpio   = 0x624001,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = TV,
+		},
+	},
+	[SAA7134_BOARD_ADS_INSTANT_HDTV_PCI] = {
+		.name           = "ADS Tech Instant HDTV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TUV1236D,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp,
+			.vmux = 4,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+	},
+	[SAA7134_BOARD_ASUSTeK_TIGER] = {
+		.name           = "Asus Tiger Rev:1.00",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tuner_config   = 0,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 0x0200000,
+		.inputs = { {
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		}, {
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE2,
+		}, {
+			.name   = name_comp2,
+			.vmux   = 0,
+			.amux   = LINE2,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		} },
+		.radio = {
+			.name   = name_radio,
+			.amux   = TV,
+			.gpio   = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG] = {
+		.name           = "Kworld Plus TV Analog Lite PCI",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_YMEC_TVF_5533MF,
+		.radio_type     = TUNER_TEA5767,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = 0x60,
+		.gpiomask       = 0x80000700,
+		.inputs = { {
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = LINE2,
+			.tv     = 1,
+			.gpio   = 0x100,
+		}, {
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+			.gpio   = 0x200,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+			.gpio   = 0x200,
+		} },
+		.radio = {
+			.name   = name_radio,
+			.vmux   = 1,
+			.amux   = LINE1,
+			.gpio   = 0x100,
+		},
+		.mute = {
+			.name = name_mute,
+			.vmux = 8,
+			.amux = 2,
+		},
+	},
+	[SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG] = {
+		.name           = "Kworld PCI SBTVD/ISDB-T Full-Seg Hybrid",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_type     = UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 0x8e054000,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.ts_type	= SAA7134_MPEG_TS_PARALLEL,
+		.inputs = { {
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+#if 0	/* FIXME */
+		}, {
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+			.gpio   = 0x200,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+			.gpio   = 0x200,
+#endif
+		} },
+#if 0
+		.radio = {
+			.name   = name_radio,
+			.vmux   = 1,
+			.amux   = LINE1,
+			.gpio   = 0x100,
+		},
+#endif
+		.mute = {
+			.name = name_mute,
+			.vmux = 0,
+			.amux = TV,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS] = {
+		.name           = "Avermedia AVerTV GO 007 FM Plus",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 0x00300003,
+		/* .gpiomask       = 0x8c240003, */
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x01,
+		}, {
+			.name = name_svideo,
+			.vmux = 6,
+			.amux = LINE1,
+			.gpio = 0x02,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x00300001,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = TV,
+			.gpio = 0x01,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_STUDIO_507UA] = {
+		/* Andy Shevchenko <andy@smile.org.ua> */
+		.name           = "Avermedia AVerTV Studio 507UA",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* Should be MK5 */
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x03,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x00,
+		}, {
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x00,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0x00,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x01,
+		},
+		.mute  = {
+			.name = name_mute,
+			.amux = LINE1,
+			.gpio = 0x00,
+		},
+	},
+	[SAA7134_BOARD_VIDEOMATE_S350] = {
+		/* Jan D. Louw <jd.louw@mweb.co.za */
+		.name		= "Compro VideoMate S350/S300",
+		.audio_clock	= 0x00187de7,
+		.tuner_type	= TUNER_ABSENT,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg		= SAA7134_MPEG_DVB,
+		.inputs = { {
+			.name	= name_comp1,
+			.vmux	= 0,
+			.amux	= LINE1,
+		}, {
+			.name	= name_svideo,
+			.vmux	= 8, /* Not tested */
+			.amux	= LINE1
+		} },
+	},
+	[SAA7134_BOARD_BEHOLD_X7] = {
+		/* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV X7",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_XC5000,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 2,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 9,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+		},
+	},
+	[SAA7134_BOARD_ZOLID_HYBRID_PCI] = {
+		.name           = "Zolid Hybrid TV Tuner PCI",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tuner_config   = 0,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.ts_type	= SAA7134_MPEG_TS_PARALLEL,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		} },
+		.radio = {	/* untested */
+			.name = name_radio,
+			.amux = TV,
+		},
+	},
+	[SAA7134_BOARD_ASUS_EUROPA_HYBRID] = {
+		.name           = "Asus Europa Hybrid OEM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TD1316,
+		.radio_type     = UNSET,
+		.tuner_addr	= 0x61,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = { {
+			.name   = name_tv,
+			.vmux   = 3,
+			.amux   = TV,
+			.tv     = 1,
+		}, {
+			.name   = name_comp1,
+			.vmux   = 4,
+			.amux   = LINE2,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		} },
+	},
+	[SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S] = {
+		.name           = "Leadtek Winfast DTV1000S",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = { {
+			.name = name_comp1,
+			.vmux = 3,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+		} },
+	},
+	[SAA7134_BOARD_BEHOLD_505RDS_MK3] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV 505 RDS",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.rds_addr 	= 0x10,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.mute = {
+			.name = name_mute,
+			.amux = LINE1,
+		},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_HAWELL_HW_404M7] = {
+		/* Hawell HW-404M7 & Hawell HW-808M7  */
+		/* Bogoslovskiy Viktor <bogovic@bk.ru> */
+		.name         = "Hawell HW-404M7",
+		.audio_clock   = 0x00200000,
+		.tuner_type    = UNSET,
+		.radio_type    = UNSET,
+		.tuner_addr   = ADDR_UNSET,
+		.radio_addr   = ADDR_UNSET,
+		.gpiomask      = 0x389c00,
+		.inputs       = {{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x01fc00,
+		} },
+	},
+	[SAA7134_BOARD_BEHOLD_H7] = {
+		/* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV H7",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_XC5000,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.ts_type	= SAA7134_MPEG_TS_PARALLEL,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 2,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 9,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_A7] = {
+		/* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV A7",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_XC5000,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 2,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 9,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+		},
+	},
+	[SAA7134_BOARD_TECHNOTREND_BUDGET_T3000] = {
+		.name           = "TechoTrend TT-budget T-3000",
+		.tuner_type     = TUNER_PHILIPS_TD1316,
+		.audio_clock    = 0x00187de7,
+		.radio_type     = UNSET,
+		.tuner_addr     = 0x63,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 3,
+			.amux   = TV,
+			.tv     = 1,
+		}, {
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE2,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		} },
+	},
+	[SAA7134_BOARD_VIDEOMATE_M1F] = {
+		/* Pavel Osnova <pvosnova@gmail.com> */
+		.name           = "Compro VideoMate Vista M1F",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_LG_PAL_NEW_TAPC,
+		.radio_type     = TUNER_TEA5767,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = 0x60,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE2,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE1,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = TV,
+		},
+	},
+	[SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2] = {
+		/* Timothy Lee <timothy.lee@siriushk.com> */
+		.name		= "MagicPro ProHDTV Pro2 DMB-TH/Hybrid",
+		.audio_clock	= 0x00187de7,
+		.tuner_type	= TUNER_PHILIPS_TDA8290,
+		.radio_type	= UNSET,
+		.tuner_config	= 3,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask	= 0x02050000,
+		.mpeg		= SAA7134_MPEG_DVB,
+		.ts_type	= SAA7134_MPEG_TS_PARALLEL,
+		.inputs		= { {
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+			.gpio   = 0x00050000,
+		}, {
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+			.gpio   = 0x00050000,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+			.gpio   = 0x00050000,
+		} },
+		.radio = {
+			.name   = name_radio,
+			.amux   = TV,
+			.gpio   = 0x00050000,
+		},
+		.mute = {
+			.name   = name_mute,
+			.vmux   = 0,
+			.amux   = TV,
+			.gpio   = 0x00050000,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_501] = {
+		/*       Beholder Intl. Ltd. 2010       */
+		/* Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV 501",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.gpiomask       = 0x00008000,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.mute = {
+			.name = name_mute,
+			.amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_503FM] = {
+		/*       Beholder Intl. Ltd. 2010       */
+		/* Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV 503 FM",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.gpiomask       = 0x00008000,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.mute = {
+			.name = name_mute,
+			.amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_SENSORAY811_911] = {
+		.name		= "Sensoray 811/911",
+		.audio_clock	= 0x00200000,
+		.tuner_type	= TUNER_ABSENT,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs		= {{
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE1,
+		}, {
+			.name   = name_comp3,
+			.vmux   = 2,
+			.amux   = LINE1,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		} },
+	},
+	[SAA7134_BOARD_KWORLD_PC150U] = {
+		.name           = "Kworld PC150-U",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 1 << 21,
+		.ts_type	= SAA7134_MPEG_TS_PARALLEL,
+		.inputs = { {
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		}, {
+			.name   = name_comp,
+			.vmux   = 3,
+			.amux   = LINE1,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		} },
+		.radio = {
+			.name   = name_radio,
+			.amux   = TV,
+			.gpio	= 0x0000000,
+		},
+	},
+
+};
+
+const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
+
+/* ------------------------------------------------------------------ */
+/* PCI ids + subsystem IDs                                            */
+
+struct pci_device_id saa7134_pci_tbl[] = {
+	{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0x2001,
+		.driver_data  = SAA7134_BOARD_PROTEUS_PRO,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0x2001,
+		.driver_data  = SAA7134_BOARD_PROTEUS_PRO,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0x6752,
+		.driver_data  = SAA7134_BOARD_EMPRESS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1131,
+		.subdevice    = 0x4e85,
+		.driver_data  = SAA7134_BOARD_MONSTERTV,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x153b,
+		.subdevice    = 0x1142,
+		.driver_data  = SAA7134_BOARD_CINERGY400,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x153b,
+		.subdevice    = 0x1143,
+		.driver_data  = SAA7134_BOARD_CINERGY600,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x153b,
+		.subdevice    = 0x1158,
+		.driver_data  = SAA7134_BOARD_CINERGY600_MK3,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x153b,
+		.subdevice    = 0x1162,
+		.driver_data  = SAA7134_BOARD_CINERGY400_CARDBUS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5169,
+		.subdevice    = 0x0138,
+		.driver_data  = SAA7134_BOARD_FLYVIDEO3000_NTSC,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0138,
+		.driver_data  = SAA7134_BOARD_FLYVIDEO3000,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x4e42,				/* "Typhoon PCI Capture TV Card" Art.No. 50673 */
+		.subdevice    = 0x0138,
+		.driver_data  = SAA7134_BOARD_FLYVIDEO3000,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0138,
+		.driver_data  = SAA7134_BOARD_FLYVIDEO2000,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x4e42,		/* Typhoon */
+		.subdevice    = 0x0138,		/* LifeView FlyTV Prime30 OEM */
+		.driver_data  = SAA7134_BOARD_FLYVIDEO2000,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0212, /* minipci, LR212 */
+		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM_MINI,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x14c0,
+		.subdevice    = 0x1212, /* minipci, LR1212 */
+		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM_MINI2,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x4e42,
+		.subdevice    = 0x0212, /* OEM minipci, LR212 */
+		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM_MINI,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5168,	/* Animation Technologies (LifeView) */
+		.subdevice    = 0x0214, /* Standard PCI, LR214 Rev E and earlier (SAA7135) */
+		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM_FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5168,	/* Animation Technologies (LifeView) */
+		.subdevice    = 0x5214, /* Standard PCI, LR214 Rev F onwards (SAA7131) */
+		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM_FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1489, /* KYE */
+		.subdevice    = 0x0214, /* Genius VideoWonder ProTV */
+		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM_FM, /* is an LR214WF actually */
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x16be,
+		.subdevice    = 0x0003,
+		.driver_data  = SAA7134_BOARD_MD7134,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x16be, /* CTX946 analog TV, HW mpeg, DVB-T */
+		.subdevice    = 0x5000, /* only analog TV and DVB-T for now */
+		.driver_data  = SAA7134_BOARD_MD7134,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x1048,
+		.subdevice    = 0x226b,
+		.driver_data  = SAA7134_BOARD_ELSA,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x1048,
+		.subdevice    = 0x226a,
+		.driver_data  = SAA7134_BOARD_ELSA_500TV,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x1048,
+		.subdevice    = 0x226c,
+		.driver_data  = SAA7134_BOARD_ELSA_700TV,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = PCI_VENDOR_ID_ASUSTEK,
+		.subdevice    = 0x4842,
+		.driver_data  = SAA7134_BOARD_ASUSTeK_TVFM7134,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = PCI_VENDOR_ID_ASUSTEK,
+		.subdevice    = 0x4845,
+		.driver_data  = SAA7134_BOARD_ASUSTeK_TVFM7135,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = PCI_VENDOR_ID_ASUSTEK,
+		.subdevice    = 0x4830,
+		.driver_data  = SAA7134_BOARD_ASUSTeK_TVFM7134,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = PCI_VENDOR_ID_ASUSTEK,
+		.subdevice    = 0x4843,
+		.driver_data  = SAA7134_BOARD_ASUSTEK_TVFM7133,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = PCI_VENDOR_ID_ASUSTEK,
+		.subdevice    = 0x4840,
+		.driver_data  = SAA7134_BOARD_ASUSTeK_TVFM7134,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0xfe01,
+		.driver_data  = SAA7134_BOARD_TVSTATION_RDS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1894,
+		.subdevice    = 0xfe01,
+		.driver_data  = SAA7134_BOARD_TVSTATION_RDS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1894,
+		.subdevice    = 0xa006,
+		.driver_data  = SAA7134_BOARD_TVSTATION_DVR,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1131,
+		.subdevice    = 0x7133,
+		.driver_data  = SAA7134_BOARD_VA1000POWER,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0x2001,
+		.driver_data  = SAA7134_BOARD_10MOONSTVMASTER,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x185b,
+		.subdevice    = 0xc100,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_TV,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x185b,
+		.subdevice    = 0xc100,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = PCI_VENDOR_ID_MATROX,
+		.subdevice    = 0x48d0,
+		.driver_data  = SAA7134_BOARD_CRONOS_PLUS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xa70b,
+		.driver_data  = SAA7134_BOARD_MD2819,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xa7a1,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_A700_PRO,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xa7a2,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_A700_HYBRID,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0x2115,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_STUDIO_305,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xa115,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_STUDIO_505,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0x2108,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_305,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0x10ff,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER,
+	},{
+		/* AVerMedia CardBus */
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xd6ee,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_CARDBUS,
+	},{
+		/* AVerMedia CardBus */
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xb7e9,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_CARDBUS_501,
+	}, {
+		/* TransGear 3000TV */
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0x050c,
+		.driver_data  = SAA7134_BOARD_TG3000TV,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x11bd,
+		.subdevice    = 0x002b,
+		.driver_data  = SAA7134_BOARD_PINNACLE_PCTV_STEREO,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x11bd,
+		.subdevice    = 0x002d,
+		.driver_data  = SAA7134_BOARD_PINNACLE_300I_DVBT_PAL,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1019,
+		.subdevice    = 0x4cb4,
+		.driver_data  = SAA7134_BOARD_ECS_TVP3XP,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1019,
+		.subdevice    = 0x4cb5,
+		.driver_data  = SAA7134_BOARD_ECS_TVP3XP_4CB5,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1019,
+		.subdevice    = 0x4cb6,
+		.driver_data  = SAA7134_BOARD_ECS_TVP3XP_4CB6,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x12ab,
+		.subdevice    = 0x0800,
+		.driver_data  = SAA7134_BOARD_UPMOST_PURPLE_TV,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x153b,
+		.subdevice    = 0x1152,
+		.driver_data  = SAA7134_BOARD_CINERGY200,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x185b,
+		.subdevice    = 0xc100,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_TV_PVR,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0x9715,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_STUDIO_307,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xa70a,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_307,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x185b,
+		.subdevice    = 0xc200,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_GOLD_PLUS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1540,
+		.subdevice    = 0x9524,
+		.driver_data  = SAA7134_BOARD_PROVIDEO_PV952,
+
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0502,                /* Cardbus version */
+		.driver_data  = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0306,                /* PCI version */
+		.driver_data  = SAA7134_BOARD_FLYDVBTDUO,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xf31f,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_GO_007_FM,
+
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xf11d,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_M135A,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0x4155,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_M733A,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0x4255,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_M733A,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0x2004,
+		.driver_data  = SAA7134_BOARD_PHILIPS_TOUGH,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1421,
+		.subdevice    = 0x0350,		/* PCI version */
+		.driver_data  = SAA7134_BOARD_ADS_INSTANT_TV,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1421,
+		.subdevice    = 0x0351,		/* PCI version, new revision */
+		.driver_data  = SAA7134_BOARD_ADS_INSTANT_TV,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1421,
+		.subdevice    = 0x0370,		/* cardbus version */
+		.driver_data  = SAA7134_BOARD_ADS_INSTANT_TV,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1421,
+		.subdevice    = 0x1370,        /* cardbus version */
+		.driver_data  = SAA7134_BOARD_ADS_INSTANT_TV,
+
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x4e42,		/* Typhoon */
+		.subdevice    = 0x0502,		/* LifeView LR502 OEM */
+		.driver_data  = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1043,
+		.subdevice    = 0x0210,		/* mini pci NTSC version */
+		.driver_data  = SAA7134_BOARD_FLYTV_DIGIMATRIX,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1043,
+		.subdevice    = 0x0210,		/* mini pci PAL/SECAM version */
+		.driver_data  = SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV,
+
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0000, /* It shouldn't break anything, since subdevice id seems unique */
+		.subdevice    = 0x4091,
+		.driver_data  = SAA7134_BOARD_BEHOLD_409FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5456, /* GoTView */
+		.subdevice    = 0x7135,
+		.driver_data  = SAA7134_BOARD_GOTVIEW_7135,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0x2004,
+		.driver_data  = SAA7134_BOARD_PHILIPS_EUROPA,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x185b,
+		.subdevice    = 0xc900,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_DVBT_300,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x185b,
+		.subdevice    = 0xc901,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_DVBT_200,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1435,
+		.subdevice    = 0x7350,
+		.driver_data  = SAA7134_BOARD_RTD_VFG7350,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1435,
+		.subdevice    = 0x7330,
+		.driver_data  = SAA7134_BOARD_RTD_VFG7330,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461,
+		.subdevice    = 0x1044,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1131,
+		.subdevice    = 0x4ee9,
+		.driver_data  = SAA7134_BOARD_MONSTERTV_MOBILE,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x11bd,
+		.subdevice    = 0x002e,
+		.driver_data  = SAA7134_BOARD_PINNACLE_PCTV_110i,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1043,
+		.subdevice    = 0x4862,
+		.driver_data  = SAA7134_BOARD_ASUSTeK_P7131_DUAL,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0x2018,
+		.driver_data  = SAA7134_BOARD_PHILIPS_TIGER,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1462,
+		.subdevice    = 0x6231, /* tda8275a, ks003 IR */
+		.driver_data  = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1462,
+		.subdevice    = 0x8624, /* tda8275, ks003 IR */
+		.driver_data  = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x153b,
+		.subdevice    = 0x1160,
+		.driver_data  = SAA7134_BOARD_CINERGY250PCI,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,	/* SAA 7131E */
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0319,
+		.driver_data  = SAA7134_BOARD_FLYDVB_TRIO,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1461,
+		.subdevice    = 0x2c05,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_777,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0301,
+		.driver_data  = SAA7134_BOARD_FLYDVBT_LR301,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0331,
+		.subdevice    = 0x1421,
+		.driver_data  = SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x17de,
+		.subdevice    = 0x7201,
+		.driver_data  = SAA7134_BOARD_TEVION_DVBT_220RF,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x17de,
+		.subdevice    = 0x7250,
+		.driver_data  = SAA7134_BOARD_KWORLD_DVBT_210,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+		.subvendor    = 0x17de,
+		.subdevice    = 0x7350,
+		.driver_data  = SAA7134_BOARD_KWORLD_ATSC110,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+		.subvendor    = 0x17de,
+		.subdevice    = 0x7352,
+		.driver_data  = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+		.subvendor    = 0x17de,
+		.subdevice    = 0xa134,
+		.driver_data  = SAA7134_BOARD_KWORLD_PC150U,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1461,
+		.subdevice    = 0x7360,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_A169_B,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1461,
+		.subdevice    = 0x6360,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_A169_B1,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x16be,
+		.subdevice    = 0x0005,
+		.driver_data  = SAA7134_BOARD_MD7134_BRIDGE_2,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0300,
+		.driver_data  = SAA7134_BOARD_FLYDVBS_LR300,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x4e42,
+		.subdevice    = 0x0300,/* LR300 */
+		.driver_data  = SAA7134_BOARD_FLYDVBS_LR300,
+	},{
+		.vendor = PCI_VENDOR_ID_PHILIPS,
+		.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor = 0x1489,
+		.subdevice = 0x0301,
+		.driver_data = SAA7134_BOARD_FLYDVBT_LR301,
+	},{
+		.vendor = PCI_VENDOR_ID_PHILIPS,
+		.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor = 0x5168, /* Animation Technologies (LifeView) */
+		.subdevice = 0x0304,
+		.driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x3306,
+		.driver_data  = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x3502,  /* whats the difference to 0x3306 ?*/
+		.driver_data  = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x3307, /* FlyDVB-T Hybrid Mini PCI */
+		.driver_data  = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x16be,
+		.subdevice    = 0x0007,
+		.driver_data  = SAA7134_BOARD_MEDION_MD8800_QUADRO,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x16be,
+		.subdevice    = 0x0008,
+		.driver_data  = SAA7134_BOARD_MEDION_MD8800_QUADRO,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x16be,
+		.subdevice    = 0x000d, /* triple CTX948_V1.1.1 */
+		.driver_data  = SAA7134_BOARD_MEDION_MD8800_QUADRO,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461,
+		.subdevice    = 0x2c05,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_777,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1489,
+		.subdevice    = 0x0502,                /* Cardbus version */
+		.driver_data  = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x0919, /* Philips Proteus PRO 2309 */
+		.subdevice    = 0x2003,
+		.driver_data  = SAA7134_BOARD_PROTEUS_2309,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1461,
+		.subdevice    = 0x2c00,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_A16AR,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1043,
+		.subdevice    = 0x4860,
+		.driver_data  = SAA7134_BOARD_ASUS_EUROPA2_HYBRID,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x11bd,
+		.subdevice    = 0x002f,
+		.driver_data  = SAA7134_BOARD_PINNACLE_PCTV_310i,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0x9715,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_STUDIO_507,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xa11b,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_STUDIO_507UA,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1043,
+		.subdevice    = 0x4876,
+		.driver_data  = SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0070,
+		.subdevice    = 0x6700,
+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0070,
+		.subdevice    = 0x6701,
+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0070,
+		.subdevice    = 0x6702,
+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0070,
+		.subdevice    = 0x6703,
+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0070,
+		.subdevice    = 0x6704,
+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0070,
+		.subdevice    = 0x6705,
+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0070,
+		.subdevice    = 0x6706,
+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1150,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0070,
+		.subdevice    = 0x6707,
+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1120,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0070,
+		.subdevice    = 0x6708,
+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1150,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0070,
+		.subdevice    = 0x6709,
+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1120,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0070,
+		.subdevice    = 0x670a,
+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1120,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x153b,
+		.subdevice    = 0x1172,
+		.driver_data  = SAA7134_BOARD_CINERGY_HT_PCMCIA,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0x2342,
+		.driver_data  = SAA7134_BOARD_ENCORE_ENLTV,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x1131,
+		.subdevice    = 0x2341,
+		.driver_data  = SAA7134_BOARD_ENCORE_ENLTV,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x3016,
+		.subdevice    = 0x2344,
+		.driver_data  = SAA7134_BOARD_ENCORE_ENLTV,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x1131,
+		.subdevice    = 0x230f,
+		.driver_data  = SAA7134_BOARD_ENCORE_ENLTV_FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x1a7f,
+		.subdevice    = 0x2008,
+		.driver_data  = SAA7134_BOARD_ENCORE_ENLTV_FM53,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1a7f,
+		.subdevice    = 0x2108,
+		.driver_data  = SAA7134_BOARD_ENCORE_ENLTV_FM3,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x153b,
+		.subdevice    = 0x1175,
+		.driver_data  = SAA7134_BOARD_CINERGY_HT_PCI,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xf31e,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_M102,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x4E42,         /* MSI */
+		.subdevice    = 0x0306,         /* TV@nywhere DUO */
+		.driver_data  = SAA7134_BOARD_FLYDVBTDUO,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1043,
+		.subdevice    = 0x4871,
+		.driver_data  = SAA7134_BOARD_ASUS_P7131_4871,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1043,
+		.subdevice    = 0x4857,		/* REV:1.00 */
+		.driver_data  = SAA7134_BOARD_ASUSTeK_TIGER,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x0919, /* SinoVideo PCI 2309 Proteus (7134) */
+		.subdevice    = 0x2003, /* OEM cardbus */
+		.driver_data  = SAA7134_BOARD_SABRENT_TV_PCB05,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0x2304,
+		.driver_data  = SAA7134_BOARD_10MOONSTVMASTER3,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xf01d, /* AVerTV DVB-T Super 007 */
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_SUPER_007,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x4016,
+		.driver_data  = SAA7134_BOARD_BEHOLD_401,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x4036,
+		.driver_data  = SAA7134_BOARD_BEHOLD_403,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x4037,
+		.driver_data  = SAA7134_BOARD_BEHOLD_403FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x4050,
+		.driver_data  = SAA7134_BOARD_BEHOLD_405,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x4051,
+		.driver_data  = SAA7134_BOARD_BEHOLD_405FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x4070,
+		.driver_data  = SAA7134_BOARD_BEHOLD_407,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x4071,
+		.driver_data  = SAA7134_BOARD_BEHOLD_407FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x4090,
+		.driver_data  = SAA7134_BOARD_BEHOLD_409,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x505B,
+		.driver_data  = SAA7134_BOARD_BEHOLD_505RDS_MK5,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x5051,
+		.driver_data  = SAA7134_BOARD_BEHOLD_505RDS_MK3,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x5050,
+		.driver_data  = SAA7134_BOARD_BEHOLD_505FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x5071,
+		.driver_data  = SAA7134_BOARD_BEHOLD_507RDS_MK3,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x507B,
+		.driver_data  = SAA7134_BOARD_BEHOLD_507RDS_MK5,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x5070,
+		.driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x5090,
+		.driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x5201,
+		.driver_data  = SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6070,
+		.driver_data  = SAA7134_BOARD_BEHOLD_607FM_MK3,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6071,
+		.driver_data  = SAA7134_BOARD_BEHOLD_607FM_MK5,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6072,
+		.driver_data  = SAA7134_BOARD_BEHOLD_607RDS_MK3,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6073,
+		.driver_data  = SAA7134_BOARD_BEHOLD_607RDS_MK5,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6090,
+		.driver_data  = SAA7134_BOARD_BEHOLD_609FM_MK3,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6091,
+		.driver_data  = SAA7134_BOARD_BEHOLD_609FM_MK5,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6092,
+		.driver_data  = SAA7134_BOARD_BEHOLD_609RDS_MK3,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6093,
+		.driver_data  = SAA7134_BOARD_BEHOLD_609RDS_MK5,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6190,
+		.driver_data  = SAA7134_BOARD_BEHOLD_M6,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6193,
+		.driver_data  = SAA7134_BOARD_BEHOLD_M6_EXTRA,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6191,
+		.driver_data  = SAA7134_BOARD_BEHOLD_M63,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x4e42,
+		.subdevice    = 0x3502,
+		.driver_data  = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1822, /*Twinhan Technology Co. Ltd*/
+		.subdevice    = 0x0022,
+		.driver_data  = SAA7134_BOARD_TWINHAN_DTV_DVB_3056,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x16be,
+		.subdevice    = 0x0010, /* Medion version CTX953_V.1.4.3 */
+		.driver_data  = SAA7134_BOARD_CREATIX_CTX953,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1462, /* MSI */
+		.subdevice    = 0x8625, /* TV@nywhere A/D v1.1 */
+		.driver_data  = SAA7134_BOARD_MSI_TVANYWHERE_AD11,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xf436,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_CARDBUS_506,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xf936,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_A16D,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xa836,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_M115,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x185b,
+		.subdevice    = 0xc900,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_T750,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+		.subvendor    = 0x1421,
+		.subdevice    = 0x0380,
+		.driver_data  = SAA7134_BOARD_ADS_INSTANT_HDTV_PCI,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5169,
+		.subdevice    = 0x1502,
+		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM_MINI,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6290,
+		.driver_data  = SAA7134_BOARD_BEHOLD_H6,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xf636,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_M103,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xf736,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_M103,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1043,
+		.subdevice    = 0x4878, /* REV:1.02G */
+		.driver_data  = SAA7134_BOARD_ASUSTeK_TIGER_3IN1,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1043,
+		.subdevice    = 0x48cd,
+		.driver_data  = SAA7134_BOARD_ASUSTeK_PS3_100,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x17de,
+		.subdevice    = 0x7128,
+		.driver_data  = SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x17de,
+		.subdevice    = 0xb136,
+		.driver_data  = SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xf31d,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x185b,
+		.subdevice    = 0xc900,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_S350,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace, /* Beholder Intl. Ltd. */
+		.subdevice    = 0x7595,
+		.driver_data  = SAA7134_BOARD_BEHOLD_X7,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x19d1, /* RoverMedia */
+		.subdevice    = 0x0138, /* LifeView FlyTV Prime30 OEM */
+		.driver_data  = SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0x2004,
+		.driver_data  = SAA7134_BOARD_ZOLID_HYBRID_PCI,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1043,
+		.subdevice    = 0x4847,
+		.driver_data  = SAA7134_BOARD_ASUS_EUROPA_HYBRID,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x107d,
+		.subdevice    = 0x6655,
+		.driver_data  = SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x13c2,
+		.subdevice    = 0x2804,
+		.driver_data  = SAA7134_BOARD_TECHNOTREND_BUDGET_T3000,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace, /* Beholder Intl. Ltd. */
+		.subdevice    = 0x7190,
+		.driver_data  = SAA7134_BOARD_BEHOLD_H7,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace, /* Beholder Intl. Ltd. */
+		.subdevice    = 0x7090,
+		.driver_data  = SAA7134_BOARD_BEHOLD_A7,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7135,
+		.subvendor    = 0x185b,
+		.subdevice    = 0xc900,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_M1F,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x5030,
+		.driver_data  = SAA7134_BOARD_BEHOLD_503FM,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x5010,
+		.driver_data  = SAA7134_BOARD_BEHOLD_501,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x17de,
+		.subdevice    = 0xd136,
+		.driver_data  = SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x6000,
+		.subdevice    = 0x0811,
+		.driver_data  = SAA7134_BOARD_SENSORAY811_911,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x6000,
+		.subdevice    = 0x0911,
+		.driver_data  = SAA7134_BOARD_SENSORAY811_911,
+	}, {
+		/* --- boards without eeprom + subsystem ID --- */
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0,
+		.driver_data  = SAA7134_BOARD_NOAUTO,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0,
+		.driver_data  = SAA7134_BOARD_NOAUTO,
+	},{
+		/* --- default catch --- */
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = PCI_ANY_ID,
+		.subdevice    = PCI_ANY_ID,
+		.driver_data  = SAA7134_BOARD_UNKNOWN,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = PCI_ANY_ID,
+		.subdevice    = PCI_ANY_ID,
+		.driver_data  = SAA7134_BOARD_UNKNOWN,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = PCI_ANY_ID,
+		.subdevice    = PCI_ANY_ID,
+		.driver_data  = SAA7134_BOARD_UNKNOWN,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7135,
+		.subvendor    = PCI_ANY_ID,
+		.subdevice    = PCI_ANY_ID,
+		.driver_data  = SAA7134_BOARD_UNKNOWN,
+	},{
+		/* --- end of list --- */
+	}
+};
+MODULE_DEVICE_TABLE(pci, saa7134_pci_tbl);
+
+/* ----------------------------------------------------------- */
+/* flyvideo tweaks                                             */
+
+
+static void board_flyvideo(struct saa7134_dev *dev)
+{
+	printk("%s: there are different flyvideo cards with different tuners\n"
+	       "%s: out there, you might have to use the tuner=<nr> insmod\n"
+	       "%s: option to override the default value.\n",
+	       dev->name, dev->name, dev->name);
+}
+
+static int saa7134_xc2028_callback(struct saa7134_dev *dev,
+				   int command, int arg)
+{
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00000000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000);
+		switch (dev->board) {
+		case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+		case SAA7134_BOARD_AVERMEDIA_M103:
+			saa7134_set_gpio(dev, 23, 0);
+			msleep(10);
+			saa7134_set_gpio(dev, 23, 1);
+		break;
+		case SAA7134_BOARD_AVERMEDIA_A16D:
+			saa7134_set_gpio(dev, 21, 0);
+			msleep(10);
+			saa7134_set_gpio(dev, 21, 1);
+		break;
+		case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
+			saa7134_set_gpio(dev, 18, 0);
+			msleep(10);
+			saa7134_set_gpio(dev, 18, 1);
+		break;
+		case SAA7134_BOARD_VIDEOMATE_T750:
+			saa7134_set_gpio(dev, 20, 0);
+			msleep(10);
+			saa7134_set_gpio(dev, 20, 1);
+		break;
+		}
+	return 0;
+	}
+	return -EINVAL;
+}
+
+static int saa7134_xc5000_callback(struct saa7134_dev *dev,
+				   int command, int arg)
+{
+	switch (dev->board) {
+	case SAA7134_BOARD_BEHOLD_X7:
+	case SAA7134_BOARD_BEHOLD_H7:
+	case SAA7134_BOARD_BEHOLD_A7:
+		if (command == XC5000_TUNER_RESET) {
+		/* Down and UP pheripherial RESET pin for reset all chips */
+			saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
+			msleep(10);
+			saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+			msleep(10);
+		}
+		break;
+	default:
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0x06e20000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0x06a20000);
+		saa_andorl(SAA7133_ANALOG_IO_SELECT >> 2, 0x02, 0x02);
+		saa_andorl(SAA7134_ANALOG_IN_CTRL1 >> 2, 0x81, 0x81);
+		saa_andorl(SAA7134_AUDIO_CLOCK0 >> 2, 0x03187de7, 0x03187de7);
+		saa_andorl(SAA7134_AUDIO_PLL_CTRL >> 2, 0x03, 0x03);
+		saa_andorl(SAA7134_AUDIO_CLOCKS_PER_FIELD0 >> 2,
+			   0x0001e000, 0x0001e000);
+		break;
+	}
+	return 0;
+}
+
+static int saa7134_tda8290_827x_callback(struct saa7134_dev *dev,
+					 int command, int arg)
+{
+	u8 sync_control;
+
+	switch (command) {
+	case 0: /* switch LNA gain through GPIO 22*/
+		saa7134_set_gpio(dev, 22, arg) ;
+		break;
+	case 1: /* vsync output at GPIO22. 50 / 60Hz */
+		saa_andorb(SAA7134_VIDEO_PORT_CTRL3, 0x80, 0x80);
+		saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x03);
+		if (arg == 1)
+			sync_control = 11;
+		else
+			sync_control = 17;
+		saa_writeb(SAA7134_VGATE_START, sync_control);
+		saa_writeb(SAA7134_VGATE_STOP, sync_control + 1);
+		saa_andorb(SAA7134_MISC_VGATE_MSB, 0x03, 0x00);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static inline int saa7134_tda18271_hvr11x0_toggle_agc(struct saa7134_dev *dev,
+						      enum tda18271_mode mode)
+{
+	/* toggle AGC switch through GPIO 26 */
+	switch (mode) {
+	case TDA18271_ANALOG:
+		saa7134_set_gpio(dev, 26, 0);
+		break;
+	case TDA18271_DIGITAL:
+		saa7134_set_gpio(dev, 26, 1);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static inline int saa7134_kworld_sbtvd_toggle_agc(struct saa7134_dev *dev,
+						  enum tda18271_mode mode)
+{
+	/* toggle AGC switch through GPIO 27 */
+	switch (mode) {
+	case TDA18271_ANALOG:
+		saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x4000);
+		saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x4000);
+		msleep(20);
+		break;
+	case TDA18271_DIGITAL:
+		saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x14000);
+		saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x14000);
+		msleep(20);
+		saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x54000);
+		saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x54000);
+		msleep(30);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int saa7134_kworld_pc150u_toggle_agc(struct saa7134_dev *dev,
+					    enum tda18271_mode mode)
+{
+	switch (mode) {
+	case TDA18271_ANALOG:
+		saa7134_set_gpio(dev, 18, 0);
+		break;
+	case TDA18271_DIGITAL:
+		saa7134_set_gpio(dev, 18, 1);
+		msleep(30);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
+					  int command, int arg)
+{
+	int ret = 0;
+
+	switch (command) {
+	case TDA18271_CALLBACK_CMD_AGC_ENABLE: /* 0 */
+		switch (dev->board) {
+		case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+		case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+		case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
+			ret = saa7134_tda18271_hvr11x0_toggle_agc(dev, arg);
+			break;
+		case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+			ret = saa7134_kworld_sbtvd_toggle_agc(dev, arg);
+			break;
+		case SAA7134_BOARD_KWORLD_PC150U:
+			ret = saa7134_kworld_pc150u_toggle_agc(dev, arg);
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int saa7134_tda8290_callback(struct saa7134_dev *dev,
+				    int command, int arg)
+{
+	int ret;
+
+	switch (dev->board) {
+	case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+	case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+	case SAA7134_BOARD_AVERMEDIA_M733A:
+	case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+	case SAA7134_BOARD_KWORLD_PC150U:
+	case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
+		/* tda8290 + tda18271 */
+		ret = saa7134_tda8290_18271_callback(dev, command, arg);
+		break;
+	default:
+		/* tda8290 + tda827x */
+		ret = saa7134_tda8290_827x_callback(dev, command, arg);
+		break;
+	}
+	return ret;
+}
+
+int saa7134_tuner_callback(void *priv, int component, int command, int arg)
+{
+	struct saa7134_dev *dev = priv;
+
+	if (dev != NULL) {
+		switch (dev->tuner_type) {
+		case TUNER_PHILIPS_TDA8290:
+			return saa7134_tda8290_callback(dev, command, arg);
+		case TUNER_XC2028:
+			return saa7134_xc2028_callback(dev, command, arg);
+		case TUNER_XC5000:
+			return saa7134_xc5000_callback(dev, command, arg);
+		}
+	} else {
+		printk(KERN_ERR "saa7134: Error - device struct undefined.\n");
+		return -EINVAL;
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL(saa7134_tuner_callback);
+
+/* ----------------------------------------------------------- */
+
+static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data)
+{
+	struct tveeprom tv;
+
+	tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
+
+	/* Make sure we support the board model */
+	switch (tv.model) {
+	case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */
+	case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */
+	case 67201: /* WinTV-HVR1150 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */
+	case 67301: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */
+	case 67209: /* WinTV-HVR1110 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */
+	case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
+	case 67569: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM) */
+	case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */
+	case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
+	case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
+	case 67651: /* WinTV-HVR1150 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
+	case 67659: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
+		break;
+	default:
+		printk(KERN_WARNING "%s: warning: "
+		       "unknown hauppauge model #%d\n", dev->name, tv.model);
+		break;
+	}
+
+	printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+	       dev->name, tv.model);
+}
+
+/* ----------------------------------------------------------- */
+
+int saa7134_board_init1(struct saa7134_dev *dev)
+{
+	/* Always print gpio, often manufacturers encode tuner type and other info. */
+	saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0);
+	dev->gpio_value = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+	printk(KERN_INFO "%s: board init: gpio is %x\n", dev->name, dev->gpio_value);
+
+	switch (dev->board) {
+	case SAA7134_BOARD_FLYVIDEO2000:
+	case SAA7134_BOARD_FLYVIDEO3000:
+	case SAA7134_BOARD_FLYVIDEO3000_NTSC:
+		dev->has_remote = SAA7134_REMOTE_GPIO;
+		board_flyvideo(dev);
+		break;
+	case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
+	case SAA7134_BOARD_FLYTVPLATINUM_FM:
+	case SAA7134_BOARD_CINERGY400:
+	case SAA7134_BOARD_CINERGY600:
+	case SAA7134_BOARD_CINERGY600_MK3:
+	case SAA7134_BOARD_ECS_TVP3XP:
+	case SAA7134_BOARD_ECS_TVP3XP_4CB5:
+	case SAA7134_BOARD_ECS_TVP3XP_4CB6:
+	case SAA7134_BOARD_MD2819:
+	case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
+	case SAA7134_BOARD_KWORLD_XPERT:
+	case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+	case SAA7134_BOARD_AVERMEDIA_STUDIO_505:
+	case SAA7134_BOARD_AVERMEDIA_305:
+	case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
+	case SAA7134_BOARD_AVERMEDIA_307:
+	case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
+	case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
+	case SAA7134_BOARD_AVERMEDIA_777:
+	case SAA7134_BOARD_AVERMEDIA_M135A:
+/*      case SAA7134_BOARD_SABRENT_SBTTVFM:  */ /* not finished yet */
+	case SAA7134_BOARD_VIDEOMATE_TV_PVR:
+	case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
+	case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
+	case SAA7134_BOARD_VIDEOMATE_M1F:
+	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+	case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+	case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
+	case SAA7134_BOARD_MANLI_MTV001:
+	case SAA7134_BOARD_MANLI_MTV002:
+	case SAA7134_BOARD_BEHOLD_409FM:
+	case SAA7134_BOARD_AVACSSMARTTV:
+	case SAA7134_BOARD_GOTVIEW_7135:
+	case SAA7134_BOARD_KWORLD_TERMINATOR:
+	case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
+	case SAA7134_BOARD_FLYDVBT_LR301:
+	case SAA7134_BOARD_ASUSTeK_PS3_100:
+	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
+	case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
+	case SAA7134_BOARD_FLYDVBTDUO:
+	case SAA7134_BOARD_PROTEUS_2309:
+	case SAA7134_BOARD_AVERMEDIA_A16AR:
+	case SAA7134_BOARD_ENCORE_ENLTV:
+	case SAA7134_BOARD_ENCORE_ENLTV_FM:
+	case SAA7134_BOARD_ENCORE_ENLTV_FM53:
+	case SAA7134_BOARD_ENCORE_ENLTV_FM3:
+	case SAA7134_BOARD_10MOONSTVMASTER3:
+	case SAA7134_BOARD_BEHOLD_401:
+	case SAA7134_BOARD_BEHOLD_403:
+	case SAA7134_BOARD_BEHOLD_403FM:
+	case SAA7134_BOARD_BEHOLD_405:
+	case SAA7134_BOARD_BEHOLD_405FM:
+	case SAA7134_BOARD_BEHOLD_407:
+	case SAA7134_BOARD_BEHOLD_407FM:
+	case SAA7134_BOARD_BEHOLD_409:
+	case SAA7134_BOARD_BEHOLD_505FM:
+	case SAA7134_BOARD_BEHOLD_505RDS_MK5:
+	case SAA7134_BOARD_BEHOLD_505RDS_MK3:
+	case SAA7134_BOARD_BEHOLD_507_9FM:
+	case SAA7134_BOARD_BEHOLD_507RDS_MK3:
+	case SAA7134_BOARD_BEHOLD_507RDS_MK5:
+	case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
+	case SAA7134_BOARD_REAL_ANGEL_220:
+	case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
+	case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
+	case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM:
+	case SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S:
+		dev->has_remote = SAA7134_REMOTE_GPIO;
+		break;
+	case SAA7134_BOARD_FLYDVBS_LR300:
+		saa_writeb(SAA7134_GPIO_GPMODE3, 0x80);
+		saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x40);
+		dev->has_remote = SAA7134_REMOTE_GPIO;
+		break;
+	case SAA7134_BOARD_MD5044:
+		printk("%s: seems there are two different versions of the MD5044\n"
+		       "%s: (with the same ID) out there.  If sound doesn't work for\n"
+		       "%s: you try the audio_clock_override=0x200000 insmod option.\n",
+		       dev->name,dev->name,dev->name);
+		break;
+	case SAA7134_BOARD_CINERGY400_CARDBUS:
+		/* power-up tuner chip */
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x00040000, 0x00040000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000000);
+		break;
+	case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
+		/* this turns the remote control chip off to work around a bug in it */
+		saa_writeb(SAA7134_GPIO_GPMODE1, 0x80);
+		saa_writeb(SAA7134_GPIO_GPSTATUS1, 0x80);
+		break;
+	case SAA7134_BOARD_MONSTERTV_MOBILE:
+		/* power-up tuner chip */
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x00040000, 0x00040000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000004);
+		break;
+	case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
+		/* turn the fan on */
+		saa_writeb(SAA7134_GPIO_GPMODE3, 0x08);
+		saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x06);
+		break;
+	case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+	case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x08000000, 0x08000000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000);
+		break;
+	case SAA7134_BOARD_AVERMEDIA_CARDBUS:
+	case SAA7134_BOARD_AVERMEDIA_M115:
+		/* power-down tuner chip */
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0xffffffff, 0);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0);
+		msleep(10);
+		/* power-up tuner chip */
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0xffffffff, 0xffffffff);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
+		msleep(10);
+		break;
+	case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
+		/* power-down tuner chip */
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x08400000, 0x08400000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08400000, 0);
+		msleep(10);
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x08400000, 0x08400000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08400000, 0x08400000);
+		msleep(10);
+		dev->has_remote = SAA7134_REMOTE_I2C;
+		break;
+	case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+		saa7134_set_gpio(dev, 23, 0);
+		msleep(10);
+		saa7134_set_gpio(dev, 23, 1);
+		dev->has_remote = SAA7134_REMOTE_I2C;
+		break;
+	case SAA7134_BOARD_AVERMEDIA_M103:
+		saa7134_set_gpio(dev, 23, 0);
+		msleep(10);
+		saa7134_set_gpio(dev, 23, 1);
+		break;
+	case SAA7134_BOARD_AVERMEDIA_A16D:
+		saa7134_set_gpio(dev, 21, 0);
+		msleep(10);
+		saa7134_set_gpio(dev, 21, 1);
+		msleep(1);
+		dev->has_remote = SAA7134_REMOTE_GPIO;
+		break;
+	case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+		/* power-down tuner chip */
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x000A8004, 0x000A8004);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x000A8004, 0);
+		msleep(10);
+		/* power-up tuner chip */
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x000A8004, 0x000A8004);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x000A8004, 0x000A8004);
+		msleep(10);
+		/* remote via GPIO */
+		dev->has_remote = SAA7134_REMOTE_GPIO;
+		break;
+	case SAA7134_BOARD_RTD_VFG7350:
+
+		/*
+		 * Make sure Production Test Register at offset 0x1D1 is cleared
+		 * to take chip out of test mode.  Clearing bit 4 (TST_EN_AOUT)
+		 * prevents pin 105 from remaining low; keeping pin 105 low
+		 * continually resets the SAA6752 chip.
+		 */
+
+		saa_writeb (SAA7134_PRODUCTION_TEST_MODE, 0x00);
+		break;
+	case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+	case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+		dev->has_remote = SAA7134_REMOTE_GPIO;
+		/* GPIO 26 high for digital, low for analog */
+		saa7134_set_gpio(dev, 26, 0);
+		msleep(1);
+
+		saa7134_set_gpio(dev, 22, 0);
+		msleep(10);
+		saa7134_set_gpio(dev, 22, 1);
+		break;
+	/* i2c remotes */
+	case SAA7134_BOARD_PINNACLE_PCTV_110i:
+	case SAA7134_BOARD_PINNACLE_PCTV_310i:
+	case SAA7134_BOARD_UPMOST_PURPLE_TV:
+	case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
+	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+	case SAA7134_BOARD_BEHOLD_607FM_MK3:
+	case SAA7134_BOARD_BEHOLD_607FM_MK5:
+	case SAA7134_BOARD_BEHOLD_609FM_MK3:
+	case SAA7134_BOARD_BEHOLD_609FM_MK5:
+	case SAA7134_BOARD_BEHOLD_607RDS_MK3:
+	case SAA7134_BOARD_BEHOLD_607RDS_MK5:
+	case SAA7134_BOARD_BEHOLD_609RDS_MK3:
+	case SAA7134_BOARD_BEHOLD_609RDS_MK5:
+	case SAA7134_BOARD_BEHOLD_M6:
+	case SAA7134_BOARD_BEHOLD_M63:
+	case SAA7134_BOARD_BEHOLD_M6_EXTRA:
+	case SAA7134_BOARD_BEHOLD_H6:
+	case SAA7134_BOARD_BEHOLD_X7:
+	case SAA7134_BOARD_BEHOLD_H7:
+	case SAA7134_BOARD_BEHOLD_A7:
+	case SAA7134_BOARD_KWORLD_PC150U:
+		dev->has_remote = SAA7134_REMOTE_I2C;
+		break;
+	case SAA7134_BOARD_AVERMEDIA_A169_B:
+		printk("%s: %s: dual saa713x broadcast decoders\n"
+		       "%s: Sorry, none of the inputs to this chip are supported yet.\n"
+		       "%s: Dual decoder functionality is disabled for now, use the other chip.\n",
+		       dev->name,card(dev).name,dev->name,dev->name);
+		break;
+	case SAA7134_BOARD_AVERMEDIA_M102:
+		/* enable tuner */
+	       dev->has_remote = SAA7134_REMOTE_GPIO;
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x8c040007, 0x8c040007);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd);
+		break;
+	case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
+	case SAA7134_BOARD_AVERMEDIA_A700_PRO:
+		/* write windows gpio values */
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x80040100, 0x80040100);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
+		break;
+	case SAA7134_BOARD_VIDEOMATE_S350:
+		dev->has_remote = SAA7134_REMOTE_GPIO;
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x0000C000, 0x0000C000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0000C000, 0x0000C000);
+		break;
+	case SAA7134_BOARD_AVERMEDIA_M733A:
+		saa7134_set_gpio(dev, 1, 1);
+		msleep(10);
+		saa7134_set_gpio(dev, 1, 0);
+		msleep(10);
+		saa7134_set_gpio(dev, 1, 1);
+		dev->has_remote = SAA7134_REMOTE_GPIO;
+		break;
+	case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
+		/* enable LGS-8G75 */
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x0e050000, 0x0c050000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0e050000, 0x0c050000);
+		break;
+	case SAA7134_BOARD_VIDEOMATE_T750:
+		/* enable the analog tuner */
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x00008000, 0x00008000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000);
+		break;
+	}
+	return 0;
+}
+
+static void saa7134_tuner_setup(struct saa7134_dev *dev)
+{
+	struct tuner_setup tun_setup;
+	unsigned int mode_mask = T_RADIO | T_ANALOG_TV;
+
+	memset(&tun_setup, 0, sizeof(tun_setup));
+	tun_setup.tuner_callback = saa7134_tuner_callback;
+
+	if (saa7134_boards[dev->board].radio_type != UNSET) {
+		tun_setup.type = saa7134_boards[dev->board].radio_type;
+		tun_setup.addr = saa7134_boards[dev->board].radio_addr;
+
+		tun_setup.mode_mask = T_RADIO;
+
+		saa_call_all(dev, tuner, s_type_addr, &tun_setup);
+		mode_mask &= ~T_RADIO;
+	}
+
+	if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type != UNSET)) {
+		tun_setup.type = dev->tuner_type;
+		tun_setup.addr = dev->tuner_addr;
+		tun_setup.config = saa7134_boards[dev->board].tuner_config;
+		tun_setup.tuner_callback = saa7134_tuner_callback;
+
+		tun_setup.mode_mask = mode_mask;
+
+		saa_call_all(dev, tuner, s_type_addr, &tun_setup);
+	}
+
+	if (dev->tda9887_conf) {
+		struct v4l2_priv_tun_config tda9887_cfg;
+
+		tda9887_cfg.tuner = TUNER_TDA9887;
+		tda9887_cfg.priv = &dev->tda9887_conf;
+
+		saa_call_all(dev, tuner, s_config, &tda9887_cfg);
+	}
+
+	if (dev->tuner_type == TUNER_XC2028) {
+		struct v4l2_priv_tun_config  xc2028_cfg;
+		struct xc2028_ctrl           ctl;
+
+		memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
+		memset(&ctl, 0, sizeof(ctl));
+
+		ctl.fname   = XC2028_DEFAULT_FIRMWARE;
+		ctl.max_len = 64;
+
+		switch (dev->board) {
+		case SAA7134_BOARD_AVERMEDIA_A16D:
+		case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+		case SAA7134_BOARD_AVERMEDIA_M103:
+		case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
+			ctl.demod = XC3028_FE_ZARLINK456;
+			break;
+		default:
+			ctl.demod = XC3028_FE_OREN538;
+			ctl.mts = 1;
+		}
+
+		xc2028_cfg.tuner = TUNER_XC2028;
+		xc2028_cfg.priv  = &ctl;
+
+		saa_call_all(dev, tuner, s_config, &xc2028_cfg);
+	}
+}
+
+/* stuff which needs working i2c */
+int saa7134_board_init2(struct saa7134_dev *dev)
+{
+	unsigned char buf;
+	int board;
+
+	/* Put here the code that enables the chips that are needed
+	   for analog mode and doesn't depend on the tuner attachment.
+	   It is also a good idea to get tuner type from eeprom, etc before
+	   initializing tuner, since we can avoid loading tuner driver
+	   on devices that has TUNER_ABSENT
+	 */
+	switch (dev->board) {
+	case SAA7134_BOARD_BMK_MPEX_NOTUNER:
+	case SAA7134_BOARD_BMK_MPEX_TUNER:
+		/* Checks if the device has a tuner at 0x60 addr
+		   If the device doesn't have a tuner, TUNER_ABSENT
+		   will be used at tuner_type, avoiding loading tuner
+		   without needing it
+		 */
+		dev->i2c_client.addr = 0x60;
+		board = (i2c_master_recv(&dev->i2c_client, &buf, 0) < 0)
+			? SAA7134_BOARD_BMK_MPEX_NOTUNER
+			: SAA7134_BOARD_BMK_MPEX_TUNER;
+		if (board == dev->board)
+			break;
+		dev->board = board;
+		printk("%s: board type fixup: %s\n", dev->name,
+		saa7134_boards[dev->board].name);
+		dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+
+		break;
+	case SAA7134_BOARD_MD7134:
+	{
+		u8 subaddr;
+		u8 data[3];
+		int ret, tuner_t;
+		struct i2c_msg msg[] = {{.addr=0x50, .flags=0, .buf=&subaddr, .len = 1},
+					{.addr=0x50, .flags=I2C_M_RD, .buf=data, .len = 3}};
+
+		subaddr= 0x14;
+		tuner_t = 0;
+
+		/* Retrieve device data from eeprom, checking for the
+		   proper tuner_type.
+		 */
+		ret = i2c_transfer(&dev->i2c_adap, msg, 2);
+		if (ret != 2) {
+			printk(KERN_ERR "EEPROM read failure\n");
+		} else if ((data[0] != 0) && (data[0] != 0xff)) {
+			/* old config structure */
+			subaddr = data[0] + 2;
+			msg[1].len = 2;
+			i2c_transfer(&dev->i2c_adap, msg, 2);
+			tuner_t = (data[0] << 8) + data[1];
+			switch (tuner_t){
+			case 0x0103:
+				dev->tuner_type = TUNER_PHILIPS_PAL;
+				break;
+			case 0x010C:
+				dev->tuner_type = TUNER_PHILIPS_FM1216ME_MK3;
+				break;
+			default:
+				printk(KERN_ERR "%s Can't determine tuner type %x from EEPROM\n", dev->name, tuner_t);
+			}
+		} else if ((data[1] != 0) && (data[1] != 0xff)) {
+			/* new config structure */
+			subaddr = data[1] + 1;
+			msg[1].len = 1;
+			i2c_transfer(&dev->i2c_adap, msg, 2);
+			subaddr = data[0] + 1;
+			msg[1].len = 2;
+			i2c_transfer(&dev->i2c_adap, msg, 2);
+			tuner_t = (data[1] << 8) + data[0];
+			switch (tuner_t) {
+			case 0x0005:
+				dev->tuner_type = TUNER_PHILIPS_FM1216ME_MK3;
+				break;
+			case 0x001d:
+				dev->tuner_type = TUNER_PHILIPS_FMD1216ME_MK3;
+					printk(KERN_INFO "%s Board has DVB-T\n", dev->name);
+				break;
+			default:
+				printk(KERN_ERR "%s Can't determine tuner type %x from EEPROM\n", dev->name, tuner_t);
+			}
+		} else {
+			printk(KERN_ERR "%s unexpected config structure\n", dev->name);
+		}
+
+		printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type);
+		break;
+	}
+	case SAA7134_BOARD_PHILIPS_EUROPA:
+		if (dev->autodetected && (dev->eedata[0x41] == 0x1c)) {
+			/* Reconfigure board as Snake reference design */
+			dev->board = SAA7134_BOARD_PHILIPS_SNAKE;
+			dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+			printk(KERN_INFO "%s: Reconfigured board as %s\n",
+				dev->name, saa7134_boards[dev->board].name);
+			break;
+		}
+		/* break intentionally omitted */
+	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+	case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
+	case SAA7134_BOARD_ASUS_EUROPA_HYBRID:
+	case SAA7134_BOARD_TECHNOTREND_BUDGET_T3000:
+	{
+
+		/* The Philips EUROPA based hybrid boards have the tuner
+		   connected through the channel decoder. We have to make it
+		   transparent to find it
+		 */
+		u8 data[] = { 0x07, 0x02};
+		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+		break;
+	}
+	case SAA7134_BOARD_PHILIPS_TIGER:
+	case SAA7134_BOARD_PHILIPS_TIGER_S:
+	{
+		u8 data[] = { 0x3c, 0x33, 0x60};
+		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+		if (dev->autodetected && (dev->eedata[0x49] == 0x50)) {
+			dev->board = SAA7134_BOARD_PHILIPS_TIGER_S;
+			printk(KERN_INFO "%s: Reconfigured board as %s\n",
+				dev->name, saa7134_boards[dev->board].name);
+		}
+		if (dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) {
+			dev->tuner_type = TUNER_PHILIPS_TDA8290;
+
+			data[2] = 0x68;
+			i2c_transfer(&dev->i2c_adap, &msg, 1);
+			break;
+		}
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+		break;
+	}
+	case SAA7134_BOARD_ASUSTeK_TVFM7135:
+	/* The card below is detected as card=53, but is different */
+	       if (dev->autodetected && (dev->eedata[0x27] == 0x03)) {
+		       dev->board = SAA7134_BOARD_ASUSTeK_P7131_ANALOG;
+		       printk(KERN_INFO "%s: P7131 analog only, using "
+						       "entry of %s\n",
+		       dev->name, saa7134_boards[dev->board].name);
+
+			/* IR init has already happened for other cards, so
+			 * we have to catch up. */
+			dev->has_remote = SAA7134_REMOTE_GPIO;
+			saa7134_input_init1(dev);
+	       }
+	       break;
+	case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+	case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+		hauppauge_eeprom(dev, dev->eedata+0x80);
+		break;
+	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+		hauppauge_eeprom(dev, dev->eedata+0x80);
+		/* break intentionally omitted */
+	case SAA7134_BOARD_PINNACLE_PCTV_310i:
+	case SAA7134_BOARD_KWORLD_DVBT_210:
+	case SAA7134_BOARD_TEVION_DVBT_220RF:
+	case SAA7134_BOARD_ASUSTeK_TIGER:
+	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
+	case SAA7134_BOARD_MEDION_MD8800_QUADRO:
+	case SAA7134_BOARD_AVERMEDIA_SUPER_007:
+	case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
+	case SAA7134_BOARD_CREATIX_CTX953:
+	{
+		/* this is a hybrid board, initialize to analog mode
+		 * and configure firmware eeprom address
+		 */
+		u8 data[] = { 0x3c, 0x33, 0x60};
+		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+		break;
+	}
+	case SAA7134_BOARD_ASUSTeK_TIGER_3IN1:
+	{
+		u8 data[] = { 0x3c, 0x33, 0x60};
+		struct i2c_msg msg = {.addr = 0x0b, .flags = 0, .buf = data,
+							.len = sizeof(data)};
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+		break;
+	}
+	case SAA7134_BOARD_ASUSTeK_PS3_100:
+	{
+		u8 data[] = { 0x3c, 0x33, 0x60};
+		struct i2c_msg msg = {.addr = 0x0b, .flags = 0, .buf = data,
+						       .len = sizeof(data)};
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+		break;
+	}
+	case SAA7134_BOARD_FLYDVB_TRIO:
+	{
+		u8 temp = 0;
+		int rc;
+		u8 data[] = { 0x3c, 0x33, 0x62};
+		struct i2c_msg msg = {.addr=0x09, .flags=0, .buf=data, .len = sizeof(data)};
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+		/*
+		 * send weak up message to pic16C505 chip
+		 * @ LifeView FlyDVB Trio
+		 */
+		msg.buf = &temp;
+		msg.addr = 0x0b;
+		msg.len = 1;
+		if (1 != i2c_transfer(&dev->i2c_adap, &msg, 1)) {
+			printk(KERN_WARNING "%s: send wake up byte to pic16C505"
+					"(IR chip) failed\n", dev->name);
+		} else {
+			msg.flags = I2C_M_RD;
+			rc = i2c_transfer(&dev->i2c_adap, &msg, 1);
+			printk(KERN_INFO "%s: probe IR chip @ i2c 0x%02x: %s\n",
+				   dev->name, msg.addr,
+				   (1 == rc) ? "yes" : "no");
+			if (rc == 1)
+				dev->has_remote = SAA7134_REMOTE_I2C;
+		}
+		break;
+	}
+	case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+	case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
+	{
+		/* initialize analog mode  */
+		u8 data[] = { 0x3c, 0x33, 0x6a};
+		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+		break;
+	}
+	case SAA7134_BOARD_CINERGY_HT_PCMCIA:
+	case SAA7134_BOARD_CINERGY_HT_PCI:
+	{
+		/* initialize analog mode */
+		u8 data[] = { 0x3c, 0x33, 0x68};
+		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+		break;
+	}
+	case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+	case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
+		/* The T200 and the T200A share the same pci id.  Consequently,
+		 * we are going to query eeprom to try to find out which one we
+		 * are actually looking at. */
+
+		/* Don't do this if the board was specifically selected with an
+		 * insmod option or if we have the default configuration T200*/
+		if (!dev->autodetected || (dev->eedata[0x41] == 0xd0))
+			break;
+		if (dev->eedata[0x41] == 0x02) {
+			/* Reconfigure board  as T200A */
+			dev->board = SAA7134_BOARD_VIDEOMATE_DVBT_200A;
+			dev->tuner_type   = saa7134_boards[dev->board].tuner_type;
+			dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf;
+			printk(KERN_INFO "%s: Reconfigured board as %s\n",
+				dev->name, saa7134_boards[dev->board].name);
+		} else {
+			printk(KERN_WARNING "%s: Unexpected tuner type info: %x in eeprom\n",
+				dev->name, dev->eedata[0x41]);
+			break;
+		}
+		break;
+	case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
+	case SAA7134_BOARD_KWORLD_ATSC110:
+	{
+		struct i2c_msg msg = { .addr = 0x0a, .flags = 0 };
+		int i;
+		static u8 buffer[][2] = {
+			{ 0x10, 0x12 },
+			{ 0x13, 0x04 },
+			{ 0x16, 0x00 },
+			{ 0x14, 0x04 },
+			{ 0x17, 0x00 },
+		};
+
+		for (i = 0; i < ARRAY_SIZE(buffer); i++) {
+			msg.buf = &buffer[i][0];
+			msg.len = ARRAY_SIZE(buffer[0]);
+			if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+				printk(KERN_WARNING
+				       "%s: Unable to enable tuner(%i).\n",
+				       dev->name, i);
+		}
+		break;
+	}
+	case SAA7134_BOARD_BEHOLD_H6:
+	{
+		u8 data[] = { 0x09, 0x9f, 0x86, 0x11};
+		struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = data,
+							.len = sizeof(data)};
+
+		/* The tuner TUNER_PHILIPS_FMD1216MEX_MK3 after hardware    */
+		/* start has disabled IF and enabled DVB-T. When saa7134    */
+		/* scan I2C devices it not detect IF tda9887 and can`t      */
+		/* watch TV without software reboot. For solve this problem */
+		/* switch the tuner to analog TV mode manually.             */
+		if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+				printk(KERN_WARNING
+				      "%s: Unable to enable IF of the tuner.\n",
+				       dev->name);
+		break;
+	}
+	case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+		saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x4000);
+		saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x4000);
+
+		saa7134_set_gpio(dev, 27, 0);
+		break;
+	} /* switch() */
+
+	/* initialize tuner */
+	if (TUNER_ABSENT != dev->tuner_type) {
+		int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
+
+		/* Note: radio tuner address is always filled in,
+		   so we do not need to probe for a radio tuner device. */
+		if (dev->radio_type != UNSET)
+			v4l2_i2c_new_subdev(&dev->v4l2_dev,
+				&dev->i2c_adap, "tuner",
+				dev->radio_addr, NULL);
+		if (has_demod)
+			v4l2_i2c_new_subdev(&dev->v4l2_dev,
+				&dev->i2c_adap, "tuner",
+				0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+		if (dev->tuner_addr == ADDR_UNSET) {
+			enum v4l2_i2c_tuner_type type =
+				has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
+
+			v4l2_i2c_new_subdev(&dev->v4l2_dev,
+				&dev->i2c_adap, "tuner",
+				0, v4l2_i2c_tuner_addrs(type));
+		} else {
+			v4l2_i2c_new_subdev(&dev->v4l2_dev,
+				&dev->i2c_adap, "tuner",
+				dev->tuner_addr, NULL);
+		}
+	}
+
+	saa7134_tuner_setup(dev);
+
+	switch (dev->board) {
+	case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+	case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
+	{
+		struct v4l2_priv_tun_config tea5767_cfg;
+		struct tea5767_ctrl ctl;
+
+		dev->i2c_client.addr = 0xC0;
+		/* set TEA5767(analog FM) defines */
+		memset(&ctl, 0, sizeof(ctl));
+		ctl.xtal_freq = TEA5767_HIGH_LO_13MHz;
+		tea5767_cfg.tuner = TUNER_TEA5767;
+		tea5767_cfg.priv  = &ctl;
+		saa_call_all(dev, tuner, s_config, &tea5767_cfg);
+		break;
+	}
+	} /* switch() */
+
+	return 0;
+}
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
new file mode 100644
index 0000000..5fbb4e4
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -0,0 +1,1368 @@
+/*
+ *
+ * device driver for philips saa7134 based TV cards
+ * driver core
+ *
+ * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/kmod.h>
+#include <linux/sound.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+MODULE_DESCRIPTION("v4l2 driver module for saa7130/34 based TV cards");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(SAA7134_VERSION);
+
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int irq_debug;
+module_param(irq_debug, int, 0644);
+MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]");
+
+static unsigned int core_debug;
+module_param(core_debug, int, 0644);
+MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+
+static unsigned int gpio_tracking;
+module_param(gpio_tracking, int, 0644);
+MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]");
+
+static unsigned int alsa = 1;
+module_param(alsa, int, 0644);
+MODULE_PARM_DESC(alsa,"enable/disable ALSA DMA sound [dmasound]");
+
+static unsigned int latency = UNSET;
+module_param(latency, int, 0444);
+MODULE_PARM_DESC(latency,"pci latency timer");
+
+int saa7134_no_overlay=-1;
+module_param_named(no_overlay, saa7134_no_overlay, int, 0444);
+MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)"
+		" [some VIA/SIS chipsets are known to have problem with overlay]");
+
+static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+static unsigned int vbi_nr[]   = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+static unsigned int tuner[]    = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+static unsigned int card[]     = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+
+
+module_param_array(video_nr, int, NULL, 0444);
+module_param_array(vbi_nr,   int, NULL, 0444);
+module_param_array(radio_nr, int, NULL, 0444);
+module_param_array(tuner,    int, NULL, 0444);
+module_param_array(card,     int, NULL, 0444);
+
+MODULE_PARM_DESC(video_nr, "video device number");
+MODULE_PARM_DESC(vbi_nr,   "vbi device number");
+MODULE_PARM_DESC(radio_nr, "radio device number");
+MODULE_PARM_DESC(tuner,    "tuner type");
+MODULE_PARM_DESC(card,     "card type");
+
+DEFINE_MUTEX(saa7134_devlist_lock);
+EXPORT_SYMBOL(saa7134_devlist_lock);
+LIST_HEAD(saa7134_devlist);
+EXPORT_SYMBOL(saa7134_devlist);
+static LIST_HEAD(mops_list);
+static unsigned int saa7134_devcount;
+
+int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
+int (*saa7134_dmasound_exit)(struct saa7134_dev *dev);
+
+#define dprintk(fmt, arg...)	if (core_debug) \
+	printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg)
+
+void saa7134_track_gpio(struct saa7134_dev *dev, char *msg)
+{
+	unsigned long mode,status;
+
+	if (!gpio_tracking)
+		return;
+	/* rising SAA7134_GPIO_GPRESCAN reads the status */
+	saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,0);
+	saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,SAA7134_GPIO_GPRESCAN);
+	mode   = saa_readl(SAA7134_GPIO_GPMODE0   >> 2) & 0xfffffff;
+	status = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & 0xfffffff;
+	printk(KERN_DEBUG
+	       "%s: gpio: mode=0x%07lx in=0x%07lx out=0x%07lx [%s]\n",
+	       dev->name, mode, (~mode) & status, mode & status, msg);
+}
+
+void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value)
+{
+	u32 index, bitval;
+
+	index = 1 << bit_no;
+	switch (value) {
+	case 0: /* static value */
+	case 1:	dprintk("setting GPIO%d to static %d\n", bit_no, value);
+		/* turn sync mode off if necessary */
+		if (index & 0x00c00000)
+			saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x00);
+		if (value)
+			bitval = index;
+		else
+			bitval = 0;
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, index);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, index, bitval);
+		break;
+	case 3:	/* tristate */
+		dprintk("setting GPIO%d to tristate\n", bit_no);
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, 0);
+		break;
+	}
+}
+
+/* ------------------------------------------------------------------ */
+
+
+/* ----------------------------------------------------------- */
+/* delayed request_module                                      */
+
+#if defined(CONFIG_MODULES) && defined(MODULE)
+
+static void request_module_async(struct work_struct *work){
+	struct saa7134_dev* dev = container_of(work, struct saa7134_dev, request_module_wk);
+	if (card_is_empress(dev))
+		request_module("saa7134-empress");
+	if (card_is_dvb(dev))
+		request_module("saa7134-dvb");
+	if (alsa) {
+		if (dev->pci->device != PCI_DEVICE_ID_PHILIPS_SAA7130)
+			request_module("saa7134-alsa");
+	}
+}
+
+static void request_submodules(struct saa7134_dev *dev)
+{
+	INIT_WORK(&dev->request_module_wk, request_module_async);
+	schedule_work(&dev->request_module_wk);
+}
+
+static void flush_request_submodules(struct saa7134_dev *dev)
+{
+	flush_work_sync(&dev->request_module_wk);
+}
+
+#else
+#define request_submodules(dev)
+#define flush_request_submodules(dev)
+#endif /* CONFIG_MODULES */
+
+/* ------------------------------------------------------------------ */
+
+/* nr of (saa7134-)pages for the given buffer size */
+static int saa7134_buffer_pages(int size)
+{
+	size  = PAGE_ALIGN(size);
+	size += PAGE_SIZE; /* for non-page-aligned buffers */
+	size /= 4096;
+	return size;
+}
+
+/* calc max # of buffers from size (must not exceed the 4MB virtual
+ * address space per DMA channel) */
+int saa7134_buffer_count(unsigned int size, unsigned int count)
+{
+	unsigned int maxcount;
+
+	maxcount = 1024 / saa7134_buffer_pages(size);
+	if (count > maxcount)
+		count = maxcount;
+	return count;
+}
+
+int saa7134_buffer_startpage(struct saa7134_buf *buf)
+{
+	return saa7134_buffer_pages(buf->vb.bsize) * buf->vb.i;
+}
+
+unsigned long saa7134_buffer_base(struct saa7134_buf *buf)
+{
+	unsigned long base;
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
+	base  = saa7134_buffer_startpage(buf) * 4096;
+	base += dma->sglist[0].offset;
+	return base;
+}
+
+/* ------------------------------------------------------------------ */
+
+int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt)
+{
+	__le32       *cpu;
+	dma_addr_t   dma_addr = 0;
+
+	cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr);
+	if (NULL == cpu)
+		return -ENOMEM;
+	pt->size = SAA7134_PGTABLE_SIZE;
+	pt->cpu  = cpu;
+	pt->dma  = dma_addr;
+	return 0;
+}
+
+int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,
+			  struct scatterlist *list, unsigned int length,
+			  unsigned int startpage)
+{
+	__le32        *ptr;
+	unsigned int  i,p;
+
+	BUG_ON(NULL == pt || NULL == pt->cpu);
+
+	ptr = pt->cpu + startpage;
+	for (i = 0; i < length; i++, list++)
+		for (p = 0; p * 4096 < list->length; p++, ptr++)
+			*ptr = cpu_to_le32(sg_dma_address(list) - list->offset);
+	return 0;
+}
+
+void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt)
+{
+	if (NULL == pt->cpu)
+		return;
+	pci_free_consistent(pci, pt->size, pt->cpu, pt->dma);
+	pt->cpu = NULL;
+}
+
+/* ------------------------------------------------------------------ */
+
+void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf)
+{
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+	BUG_ON(in_interrupt());
+
+	videobuf_waiton(q, &buf->vb, 0, 0);
+	videobuf_dma_unmap(q->dev, dma);
+	videobuf_dma_free(dma);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+/* ------------------------------------------------------------------ */
+
+int saa7134_buffer_queue(struct saa7134_dev *dev,
+			 struct saa7134_dmaqueue *q,
+			 struct saa7134_buf *buf)
+{
+	struct saa7134_buf *next = NULL;
+
+	assert_spin_locked(&dev->slock);
+	dprintk("buffer_queue %p\n",buf);
+	if (NULL == q->curr) {
+		if (!q->need_two) {
+			q->curr = buf;
+			buf->activate(dev,buf,NULL);
+		} else if (list_empty(&q->queue)) {
+			list_add_tail(&buf->vb.queue,&q->queue);
+			buf->vb.state = VIDEOBUF_QUEUED;
+		} else {
+			next = list_entry(q->queue.next,struct saa7134_buf,
+					  vb.queue);
+			q->curr = buf;
+			buf->activate(dev,buf,next);
+		}
+	} else {
+		list_add_tail(&buf->vb.queue,&q->queue);
+		buf->vb.state = VIDEOBUF_QUEUED;
+	}
+	return 0;
+}
+
+void saa7134_buffer_finish(struct saa7134_dev *dev,
+			   struct saa7134_dmaqueue *q,
+			   unsigned int state)
+{
+	assert_spin_locked(&dev->slock);
+	dprintk("buffer_finish %p\n",q->curr);
+
+	/* finish current buffer */
+	q->curr->vb.state = state;
+	do_gettimeofday(&q->curr->vb.ts);
+	wake_up(&q->curr->vb.done);
+	q->curr = NULL;
+}
+
+void saa7134_buffer_next(struct saa7134_dev *dev,
+			 struct saa7134_dmaqueue *q)
+{
+	struct saa7134_buf *buf,*next = NULL;
+
+	assert_spin_locked(&dev->slock);
+	BUG_ON(NULL != q->curr);
+
+	if (!list_empty(&q->queue)) {
+		/* activate next one from queue */
+		buf = list_entry(q->queue.next,struct saa7134_buf,vb.queue);
+		dprintk("buffer_next %p [prev=%p/next=%p]\n",
+			buf,q->queue.prev,q->queue.next);
+		list_del(&buf->vb.queue);
+		if (!list_empty(&q->queue))
+			next = list_entry(q->queue.next,struct saa7134_buf,
+					  vb.queue);
+		q->curr = buf;
+		buf->activate(dev,buf,next);
+		dprintk("buffer_next #2 prev=%p/next=%p\n",
+			q->queue.prev,q->queue.next);
+	} else {
+		/* nothing to do -- just stop DMA */
+		dprintk("buffer_next %p\n",NULL);
+		saa7134_set_dmabits(dev);
+		del_timer(&q->timeout);
+
+		if (card_has_mpeg(dev))
+			if (dev->ts_started)
+				saa7134_ts_stop(dev);
+	}
+}
+
+void saa7134_buffer_timeout(unsigned long data)
+{
+	struct saa7134_dmaqueue *q = (struct saa7134_dmaqueue*)data;
+	struct saa7134_dev *dev = q->dev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->slock,flags);
+
+	/* try to reset the hardware (SWRST) */
+	saa_writeb(SAA7134_REGION_ENABLE, 0x00);
+	saa_writeb(SAA7134_REGION_ENABLE, 0x80);
+	saa_writeb(SAA7134_REGION_ENABLE, 0x00);
+
+	/* flag current buffer as failed,
+	   try to start over with the next one. */
+	if (q->curr) {
+		dprintk("timeout on %p\n",q->curr);
+		saa7134_buffer_finish(dev,q,VIDEOBUF_ERROR);
+	}
+	saa7134_buffer_next(dev,q);
+	spin_unlock_irqrestore(&dev->slock,flags);
+}
+
+/* ------------------------------------------------------------------ */
+
+int saa7134_set_dmabits(struct saa7134_dev *dev)
+{
+	u32 split, task=0, ctrl=0, irq=0;
+	enum v4l2_field cap = V4L2_FIELD_ANY;
+	enum v4l2_field ov  = V4L2_FIELD_ANY;
+
+	assert_spin_locked(&dev->slock);
+
+	if (dev->insuspend)
+		return 0;
+
+	/* video capture -- dma 0 + video task A */
+	if (dev->video_q.curr) {
+		task |= 0x01;
+		ctrl |= SAA7134_MAIN_CTRL_TE0;
+		irq  |= SAA7134_IRQ1_INTE_RA0_1 |
+			SAA7134_IRQ1_INTE_RA0_0;
+		cap = dev->video_q.curr->vb.field;
+	}
+
+	/* video capture -- dma 1+2 (planar modes) */
+	if (dev->video_q.curr &&
+	    dev->video_q.curr->fmt->planar) {
+		ctrl |= SAA7134_MAIN_CTRL_TE4 |
+			SAA7134_MAIN_CTRL_TE5;
+	}
+
+	/* screen overlay -- dma 0 + video task B */
+	if (dev->ovenable) {
+		task |= 0x10;
+		ctrl |= SAA7134_MAIN_CTRL_TE1;
+		ov = dev->ovfield;
+	}
+
+	/* vbi capture -- dma 0 + vbi task A+B */
+	if (dev->vbi_q.curr) {
+		task |= 0x22;
+		ctrl |= SAA7134_MAIN_CTRL_TE2 |
+			SAA7134_MAIN_CTRL_TE3;
+		irq  |= SAA7134_IRQ1_INTE_RA0_7 |
+			SAA7134_IRQ1_INTE_RA0_6 |
+			SAA7134_IRQ1_INTE_RA0_5 |
+			SAA7134_IRQ1_INTE_RA0_4;
+	}
+
+	/* audio capture -- dma 3 */
+	if (dev->dmasound.dma_running) {
+		ctrl |= SAA7134_MAIN_CTRL_TE6;
+		irq  |= SAA7134_IRQ1_INTE_RA3_1 |
+			SAA7134_IRQ1_INTE_RA3_0;
+	}
+
+	/* TS capture -- dma 5 */
+	if (dev->ts_q.curr) {
+		ctrl |= SAA7134_MAIN_CTRL_TE5;
+		irq  |= SAA7134_IRQ1_INTE_RA2_1 |
+			SAA7134_IRQ1_INTE_RA2_0;
+	}
+
+	/* set task conditions + field handling */
+	if (V4L2_FIELD_HAS_BOTH(cap) || V4L2_FIELD_HAS_BOTH(ov) || cap == ov) {
+		/* default config -- use full frames */
+		saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0d);
+		saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0d);
+		saa_writeb(SAA7134_FIELD_HANDLING(TASK_A),  0x02);
+		saa_writeb(SAA7134_FIELD_HANDLING(TASK_B),  0x02);
+		split = 0;
+	} else {
+		/* split fields between tasks */
+		if (V4L2_FIELD_TOP == cap) {
+			/* odd A, even B, repeat */
+			saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0d);
+			saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0e);
+		} else {
+			/* odd B, even A, repeat */
+			saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0e);
+			saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0d);
+		}
+		saa_writeb(SAA7134_FIELD_HANDLING(TASK_A),  0x01);
+		saa_writeb(SAA7134_FIELD_HANDLING(TASK_B),  0x01);
+		split = 1;
+	}
+
+	/* irqs */
+	saa_writeb(SAA7134_REGION_ENABLE, task);
+	saa_writel(SAA7134_IRQ1,          irq);
+	saa_andorl(SAA7134_MAIN_CTRL,
+		   SAA7134_MAIN_CTRL_TE0 |
+		   SAA7134_MAIN_CTRL_TE1 |
+		   SAA7134_MAIN_CTRL_TE2 |
+		   SAA7134_MAIN_CTRL_TE3 |
+		   SAA7134_MAIN_CTRL_TE4 |
+		   SAA7134_MAIN_CTRL_TE5 |
+		   SAA7134_MAIN_CTRL_TE6,
+		   ctrl);
+	dprintk("dmabits: task=0x%02x ctrl=0x%02x irq=0x%x split=%s\n",
+		task, ctrl, irq, split ? "no" : "yes");
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* IRQ handler + helpers                                              */
+
+static char *irqbits[] = {
+	"DONE_RA0", "DONE_RA1", "DONE_RA2", "DONE_RA3",
+	"AR", "PE", "PWR_ON", "RDCAP", "INTL", "FIDT", "MMC",
+	"TRIG_ERR", "CONF_ERR", "LOAD_ERR",
+	"GPIO16", "GPIO18", "GPIO22", "GPIO23"
+};
+#define IRQBITS ARRAY_SIZE(irqbits)
+
+static void print_irqstatus(struct saa7134_dev *dev, int loop,
+			    unsigned long report, unsigned long status)
+{
+	unsigned int i;
+
+	printk(KERN_DEBUG "%s/irq[%d,%ld]: r=0x%lx s=0x%02lx",
+	       dev->name,loop,jiffies,report,status);
+	for (i = 0; i < IRQBITS; i++) {
+		if (!(report & (1 << i)))
+			continue;
+		printk(" %s",irqbits[i]);
+	}
+	if (report & SAA7134_IRQ_REPORT_DONE_RA0) {
+		printk(" | RA0=%s,%s,%s,%ld",
+		       (status & 0x40) ? "vbi"  : "video",
+		       (status & 0x20) ? "b"    : "a",
+		       (status & 0x10) ? "odd"  : "even",
+		       (status & 0x0f));
+	}
+	printk("\n");
+}
+
+static irqreturn_t saa7134_irq(int irq, void *dev_id)
+{
+	struct saa7134_dev *dev = (struct saa7134_dev*) dev_id;
+	unsigned long report,status;
+	int loop, handled = 0;
+
+	if (dev->insuspend)
+		goto out;
+
+	for (loop = 0; loop < 10; loop++) {
+		report = saa_readl(SAA7134_IRQ_REPORT);
+		status = saa_readl(SAA7134_IRQ_STATUS);
+
+		/* If dmasound support is active and we get a sound report,
+		 * mask out the report and let the saa7134-alsa module deal
+		 * with it */
+		if ((report & SAA7134_IRQ_REPORT_DONE_RA3) &&
+			(dev->dmasound.priv_data != NULL) )
+		{
+			if (irq_debug > 1)
+				printk(KERN_DEBUG "%s/irq: preserving DMA sound interrupt\n",
+				       dev->name);
+			report &= ~SAA7134_IRQ_REPORT_DONE_RA3;
+		}
+
+		if (0 == report) {
+			if (irq_debug > 1)
+				printk(KERN_DEBUG "%s/irq: no (more) work\n",
+				       dev->name);
+			goto out;
+		}
+
+		handled = 1;
+		saa_writel(SAA7134_IRQ_REPORT,report);
+		if (irq_debug)
+			print_irqstatus(dev,loop,report,status);
+
+
+		if ((report & SAA7134_IRQ_REPORT_RDCAP) ||
+			(report & SAA7134_IRQ_REPORT_INTL))
+				saa7134_irq_video_signalchange(dev);
+
+
+		if ((report & SAA7134_IRQ_REPORT_DONE_RA0) &&
+		    (status & 0x60) == 0)
+			saa7134_irq_video_done(dev,status);
+
+		if ((report & SAA7134_IRQ_REPORT_DONE_RA0) &&
+		    (status & 0x40) == 0x40)
+			saa7134_irq_vbi_done(dev,status);
+
+		if ((report & SAA7134_IRQ_REPORT_DONE_RA2) &&
+		    card_has_mpeg(dev))
+			saa7134_irq_ts_done(dev,status);
+
+		if (report & SAA7134_IRQ_REPORT_GPIO16) {
+			switch (dev->has_remote) {
+				case SAA7134_REMOTE_GPIO:
+					if (!dev->remote)
+						break;
+					if  (dev->remote->mask_keydown & 0x10000) {
+						saa7134_input_irq(dev);
+					}
+					break;
+
+				case SAA7134_REMOTE_I2C:
+					break;			/* FIXME: invoke I2C get_key() */
+
+				default:			/* GPIO16 not used by IR remote */
+					break;
+			}
+		}
+
+		if (report & SAA7134_IRQ_REPORT_GPIO18) {
+			switch (dev->has_remote) {
+				case SAA7134_REMOTE_GPIO:
+					if (!dev->remote)
+						break;
+					if ((dev->remote->mask_keydown & 0x40000) ||
+					    (dev->remote->mask_keyup & 0x40000)) {
+						saa7134_input_irq(dev);
+					}
+					break;
+
+				case SAA7134_REMOTE_I2C:
+					break;			/* FIXME: invoke I2C get_key() */
+
+				default:			/* GPIO18 not used by IR remote */
+					break;
+			}
+		}
+	}
+
+	if (10 == loop) {
+		print_irqstatus(dev,loop,report,status);
+		if (report & SAA7134_IRQ_REPORT_PE) {
+			/* disable all parity error */
+			printk(KERN_WARNING "%s/irq: looping -- "
+			       "clearing PE (parity error!) enable bit\n",dev->name);
+			saa_clearl(SAA7134_IRQ2,SAA7134_IRQ2_INTE_PE);
+		} else if (report & SAA7134_IRQ_REPORT_GPIO16) {
+			/* disable gpio16 IRQ */
+			printk(KERN_WARNING "%s/irq: looping -- "
+			       "clearing GPIO16 enable bit\n",dev->name);
+			saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16_P);
+			saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16_N);
+		} else if (report & SAA7134_IRQ_REPORT_GPIO18) {
+			/* disable gpio18 IRQs */
+			printk(KERN_WARNING "%s/irq: looping -- "
+			       "clearing GPIO18 enable bit\n",dev->name);
+			saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_P);
+			saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_N);
+		} else {
+			/* disable all irqs */
+			printk(KERN_WARNING "%s/irq: looping -- "
+			       "clearing all enable bits\n",dev->name);
+			saa_writel(SAA7134_IRQ1,0);
+			saa_writel(SAA7134_IRQ2,0);
+		}
+	}
+
+ out:
+	return IRQ_RETVAL(handled);
+}
+
+/* ------------------------------------------------------------------ */
+
+/* early init (no i2c, no irq) */
+
+static int saa7134_hw_enable1(struct saa7134_dev *dev)
+{
+	/* RAM FIFO config */
+	saa_writel(SAA7134_FIFO_SIZE, 0x08070503);
+	saa_writel(SAA7134_THRESHOULD, 0x02020202);
+
+	/* enable audio + video processing */
+	saa_writel(SAA7134_MAIN_CTRL,
+			SAA7134_MAIN_CTRL_VPLLE |
+			SAA7134_MAIN_CTRL_APLLE |
+			SAA7134_MAIN_CTRL_EXOSC |
+			SAA7134_MAIN_CTRL_EVFE1 |
+			SAA7134_MAIN_CTRL_EVFE2 |
+			SAA7134_MAIN_CTRL_ESFE  |
+			SAA7134_MAIN_CTRL_EBDAC);
+
+	/*
+	* Initialize OSS _after_ enabling audio clock PLL and audio processing.
+	* OSS initialization writes to registers via the audio DSP; these
+	* writes will fail unless the audio clock has been started.  At worst,
+	* audio will not work.
+	*/
+
+	/* enable peripheral devices */
+	saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+
+	/* set vertical line numbering start (vbi needs this) */
+	saa_writeb(SAA7134_SOURCE_TIMING2, 0x20);
+
+	return 0;
+}
+
+static int saa7134_hwinit1(struct saa7134_dev *dev)
+{
+	dprintk("hwinit1\n");
+
+	saa_writel(SAA7134_IRQ1, 0);
+	saa_writel(SAA7134_IRQ2, 0);
+
+	/* Clear any stale IRQ reports */
+	saa_writel(SAA7134_IRQ_REPORT, saa_readl(SAA7134_IRQ_REPORT));
+
+	mutex_init(&dev->lock);
+	spin_lock_init(&dev->slock);
+
+	saa7134_track_gpio(dev,"pre-init");
+	saa7134_video_init1(dev);
+	saa7134_vbi_init1(dev);
+	if (card_has_mpeg(dev))
+		saa7134_ts_init1(dev);
+	saa7134_input_init1(dev);
+
+	saa7134_hw_enable1(dev);
+
+	return 0;
+}
+
+/* late init (with i2c + irq) */
+static int saa7134_hw_enable2(struct saa7134_dev *dev)
+{
+
+	unsigned int irq2_mask;
+
+	/* enable IRQ's */
+	irq2_mask =
+		SAA7134_IRQ2_INTE_DEC3    |
+		SAA7134_IRQ2_INTE_DEC2    |
+		SAA7134_IRQ2_INTE_DEC1    |
+		SAA7134_IRQ2_INTE_DEC0    |
+		SAA7134_IRQ2_INTE_PE      |
+		SAA7134_IRQ2_INTE_AR;
+
+	if (dev->has_remote == SAA7134_REMOTE_GPIO && dev->remote) {
+		if (dev->remote->mask_keydown & 0x10000)
+			irq2_mask |= SAA7134_IRQ2_INTE_GPIO16_N;
+		else {		/* Allow enabling both IRQ edge triggers */
+			if (dev->remote->mask_keydown & 0x40000)
+				irq2_mask |= SAA7134_IRQ2_INTE_GPIO18_P;
+			if (dev->remote->mask_keyup & 0x40000)
+				irq2_mask |= SAA7134_IRQ2_INTE_GPIO18_N;
+		}
+	}
+
+	if (dev->has_remote == SAA7134_REMOTE_I2C) {
+		request_module("ir-kbd-i2c");
+	}
+
+	saa_writel(SAA7134_IRQ1, 0);
+	saa_writel(SAA7134_IRQ2, irq2_mask);
+
+	return 0;
+}
+
+static int saa7134_hwinit2(struct saa7134_dev *dev)
+{
+
+	dprintk("hwinit2\n");
+
+	saa7134_video_init2(dev);
+	saa7134_tvaudio_init2(dev);
+
+	saa7134_hw_enable2(dev);
+
+	return 0;
+}
+
+
+/* shutdown */
+static int saa7134_hwfini(struct saa7134_dev *dev)
+{
+	dprintk("hwfini\n");
+
+	if (card_has_mpeg(dev))
+		saa7134_ts_fini(dev);
+	saa7134_input_fini(dev);
+	saa7134_vbi_fini(dev);
+	saa7134_tvaudio_fini(dev);
+	return 0;
+}
+
+static void __devinit must_configure_manually(int has_eeprom)
+{
+	unsigned int i,p;
+
+	if (!has_eeprom)
+		printk(KERN_WARNING
+		       "saa7134: <rant>\n"
+		       "saa7134:  Congratulations!  Your TV card vendor saved a few\n"
+		       "saa7134:  cents for a eeprom, thus your pci board has no\n"
+		       "saa7134:  subsystem ID and I can't identify it automatically\n"
+		       "saa7134: </rant>\n"
+		       "saa7134: I feel better now.  Ok, here are the good news:\n"
+		       "saa7134: You can use the card=<nr> insmod option to specify\n"
+		       "saa7134: which board do you have.  The list:\n");
+	else
+		printk(KERN_WARNING
+		       "saa7134: Board is currently unknown. You might try to use the card=<nr>\n"
+		       "saa7134: insmod option to specify which board do you have, but this is\n"
+		       "saa7134: somewhat risky, as might damage your card. It is better to ask\n"
+		       "saa7134: for support at linux-media@vger.kernel.org.\n"
+		       "saa7134: The supported cards are:\n");
+
+	for (i = 0; i < saa7134_bcount; i++) {
+		printk(KERN_WARNING "saa7134:   card=%d -> %-40.40s",
+		       i,saa7134_boards[i].name);
+		for (p = 0; saa7134_pci_tbl[p].driver_data; p++) {
+			if (saa7134_pci_tbl[p].driver_data != i)
+				continue;
+			printk(" %04x:%04x",
+			       saa7134_pci_tbl[p].subvendor,
+			       saa7134_pci_tbl[p].subdevice);
+		}
+		printk("\n");
+	}
+}
+
+static struct video_device *vdev_init(struct saa7134_dev *dev,
+				      struct video_device *template,
+				      char *type)
+{
+	struct video_device *vfd;
+
+	vfd = video_device_alloc();
+	if (NULL == vfd)
+		return NULL;
+	*vfd = *template;
+	vfd->v4l2_dev  = &dev->v4l2_dev;
+	vfd->release = video_device_release;
+	vfd->debug   = video_debug;
+	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
+		 dev->name, type, saa7134_boards[dev->board].name);
+	video_set_drvdata(vfd, dev);
+	return vfd;
+}
+
+static void saa7134_unregister_video(struct saa7134_dev *dev)
+{
+	if (dev->video_dev) {
+		if (video_is_registered(dev->video_dev))
+			video_unregister_device(dev->video_dev);
+		else
+			video_device_release(dev->video_dev);
+		dev->video_dev = NULL;
+	}
+	if (dev->vbi_dev) {
+		if (video_is_registered(dev->vbi_dev))
+			video_unregister_device(dev->vbi_dev);
+		else
+			video_device_release(dev->vbi_dev);
+		dev->vbi_dev = NULL;
+	}
+	if (dev->radio_dev) {
+		if (video_is_registered(dev->radio_dev))
+			video_unregister_device(dev->radio_dev);
+		else
+			video_device_release(dev->radio_dev);
+		dev->radio_dev = NULL;
+	}
+}
+
+static void mpeg_ops_attach(struct saa7134_mpeg_ops *ops,
+			    struct saa7134_dev *dev)
+{
+	int err;
+
+	if (NULL != dev->mops)
+		return;
+	if (saa7134_boards[dev->board].mpeg != ops->type)
+		return;
+	err = ops->init(dev);
+	if (0 != err)
+		return;
+	dev->mops = ops;
+}
+
+static void mpeg_ops_detach(struct saa7134_mpeg_ops *ops,
+			    struct saa7134_dev *dev)
+{
+	if (NULL == dev->mops)
+		return;
+	if (dev->mops != ops)
+		return;
+	dev->mops->fini(dev);
+	dev->mops = NULL;
+}
+
+static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
+				     const struct pci_device_id *pci_id)
+{
+	struct saa7134_dev *dev;
+	struct saa7134_mpeg_ops *mops;
+	int err;
+
+	if (saa7134_devcount == SAA7134_MAXBOARDS)
+		return -ENOMEM;
+
+	dev = kzalloc(sizeof(*dev),GFP_KERNEL);
+	if (NULL == dev)
+		return -ENOMEM;
+
+	err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
+	if (err)
+		goto fail0;
+
+	/* pci init */
+	dev->pci = pci_dev;
+	if (pci_enable_device(pci_dev)) {
+		err = -EIO;
+		goto fail1;
+	}
+
+	dev->nr = saa7134_devcount;
+	sprintf(dev->name,"saa%x[%d]",pci_dev->device,dev->nr);
+
+	/* pci quirks */
+	if (pci_pci_problems) {
+		if (pci_pci_problems & PCIPCI_TRITON)
+			printk(KERN_INFO "%s: quirk: PCIPCI_TRITON\n", dev->name);
+		if (pci_pci_problems & PCIPCI_NATOMA)
+			printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA\n", dev->name);
+		if (pci_pci_problems & PCIPCI_VIAETBF)
+			printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF\n", dev->name);
+		if (pci_pci_problems & PCIPCI_VSFX)
+			printk(KERN_INFO "%s: quirk: PCIPCI_VSFX\n",dev->name);
+#ifdef PCIPCI_ALIMAGIK
+		if (pci_pci_problems & PCIPCI_ALIMAGIK) {
+			printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
+			       dev->name);
+			latency = 0x0A;
+		}
+#endif
+		if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) {
+			printk(KERN_INFO "%s: quirk: this driver and your "
+					"chipset may not work together"
+					" in overlay mode.\n",dev->name);
+			if (!saa7134_no_overlay) {
+				printk(KERN_INFO "%s: quirk: overlay "
+						"mode will be disabled.\n",
+						dev->name);
+				saa7134_no_overlay = 1;
+			} else {
+				printk(KERN_INFO "%s: quirk: overlay "
+						"mode will be forced. Use this"
+						" option at your own risk.\n",
+						dev->name);
+			}
+		}
+	}
+	if (UNSET != latency) {
+		printk(KERN_INFO "%s: setting pci latency timer to %d\n",
+		       dev->name,latency);
+		pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
+	}
+
+	/* print pci info */
+	dev->pci_rev = pci_dev->revision;
+	pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
+	printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
+	       "latency: %d, mmio: 0x%llx\n", dev->name,
+	       pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
+	       dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0));
+	pci_set_master(pci_dev);
+	if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) {
+		printk("%s: Oops: no 32bit PCI DMA ???\n",dev->name);
+		err = -EIO;
+		goto fail1;
+	}
+
+	/* board config */
+	dev->board = pci_id->driver_data;
+	if (card[dev->nr] >= 0 &&
+	    card[dev->nr] < saa7134_bcount)
+		dev->board = card[dev->nr];
+	if (SAA7134_BOARD_UNKNOWN == dev->board)
+		must_configure_manually(0);
+	else if (SAA7134_BOARD_NOAUTO == dev->board) {
+		must_configure_manually(1);
+		dev->board = SAA7134_BOARD_UNKNOWN;
+	}
+	dev->autodetected = card[dev->nr] != dev->board;
+	dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+	dev->tuner_addr = saa7134_boards[dev->board].tuner_addr;
+	dev->radio_type = saa7134_boards[dev->board].radio_type;
+	dev->radio_addr = saa7134_boards[dev->board].radio_addr;
+	dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf;
+	if (UNSET != tuner[dev->nr])
+		dev->tuner_type = tuner[dev->nr];
+	printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+		dev->name,pci_dev->subsystem_vendor,
+		pci_dev->subsystem_device,saa7134_boards[dev->board].name,
+		dev->board, dev->autodetected ?
+		"autodetected" : "insmod option");
+
+	/* get mmio */
+	if (!request_mem_region(pci_resource_start(pci_dev,0),
+				pci_resource_len(pci_dev,0),
+				dev->name)) {
+		err = -EBUSY;
+		printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
+		       dev->name,(unsigned long long)pci_resource_start(pci_dev,0));
+		goto fail1;
+	}
+	dev->lmmio = ioremap(pci_resource_start(pci_dev, 0),
+			     pci_resource_len(pci_dev, 0));
+	dev->bmmio = (__u8 __iomem *)dev->lmmio;
+	if (NULL == dev->lmmio) {
+		err = -EIO;
+		printk(KERN_ERR "%s: can't ioremap() MMIO memory\n",
+		       dev->name);
+		goto fail2;
+	}
+
+	/* initialize hardware #1 */
+	saa7134_board_init1(dev);
+	saa7134_hwinit1(dev);
+
+	/* get irq */
+	err = request_irq(pci_dev->irq, saa7134_irq,
+			  IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+	if (err < 0) {
+		printk(KERN_ERR "%s: can't get IRQ %d\n",
+		       dev->name,pci_dev->irq);
+		goto fail3;
+	}
+
+	/* wait a bit, register i2c bus */
+	msleep(100);
+	saa7134_i2c_register(dev);
+	saa7134_board_init2(dev);
+
+	saa7134_hwinit2(dev);
+
+	/* load i2c helpers */
+	if (card_is_empress(dev)) {
+		struct v4l2_subdev *sd =
+			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+				"saa6752hs",
+				saa7134_boards[dev->board].empress_addr, NULL);
+
+		if (sd)
+			sd->grp_id = GRP_EMPRESS;
+	}
+
+	if (saa7134_boards[dev->board].rds_addr) {
+		struct v4l2_subdev *sd;
+
+		sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+				&dev->i2c_adap, "saa6588",
+				0, I2C_ADDRS(saa7134_boards[dev->board].rds_addr));
+		if (sd) {
+			printk(KERN_INFO "%s: found RDS decoder\n", dev->name);
+			dev->has_rds = 1;
+		}
+	}
+
+	v4l2_prio_init(&dev->prio);
+
+	mutex_lock(&saa7134_devlist_lock);
+	list_for_each_entry(mops, &mops_list, next)
+		mpeg_ops_attach(mops, dev);
+	list_add_tail(&dev->devlist, &saa7134_devlist);
+	mutex_unlock(&saa7134_devlist_lock);
+
+	/* check for signal */
+	saa7134_irq_video_signalchange(dev);
+
+	if (TUNER_ABSENT != dev->tuner_type)
+		saa_call_all(dev, core, s_power, 0);
+
+	/* register v4l devices */
+	if (saa7134_no_overlay > 0)
+		printk(KERN_INFO "%s: Overlay support disabled.\n", dev->name);
+
+	dev->video_dev = vdev_init(dev,&saa7134_video_template,"video");
+	err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
+				    video_nr[dev->nr]);
+	if (err < 0) {
+		printk(KERN_INFO "%s: can't register video device\n",
+		       dev->name);
+		goto fail4;
+	}
+	printk(KERN_INFO "%s: registered device %s [v4l2]\n",
+	       dev->name, video_device_node_name(dev->video_dev));
+
+	dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi");
+
+	err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
+				    vbi_nr[dev->nr]);
+	if (err < 0)
+		goto fail4;
+	printk(KERN_INFO "%s: registered device %s\n",
+	       dev->name, video_device_node_name(dev->vbi_dev));
+
+	if (card_has_radio(dev)) {
+		dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio");
+		err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
+					    radio_nr[dev->nr]);
+		if (err < 0)
+			goto fail4;
+		printk(KERN_INFO "%s: registered device %s\n",
+		       dev->name, video_device_node_name(dev->radio_dev));
+	}
+
+	/* everything worked */
+	saa7134_devcount++;
+
+	if (saa7134_dmasound_init && !dev->dmasound.priv_data)
+		saa7134_dmasound_init(dev);
+
+	request_submodules(dev);
+	return 0;
+
+ fail4:
+	saa7134_unregister_video(dev);
+	saa7134_i2c_unregister(dev);
+	free_irq(pci_dev->irq, dev);
+ fail3:
+	saa7134_hwfini(dev);
+	iounmap(dev->lmmio);
+ fail2:
+	release_mem_region(pci_resource_start(pci_dev,0),
+			   pci_resource_len(pci_dev,0));
+ fail1:
+	v4l2_device_unregister(&dev->v4l2_dev);
+ fail0:
+	kfree(dev);
+	return err;
+}
+
+static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+	struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
+	struct saa7134_mpeg_ops *mops;
+
+	flush_request_submodules(dev);
+
+	/* Release DMA sound modules if present */
+	if (saa7134_dmasound_exit && dev->dmasound.priv_data) {
+		saa7134_dmasound_exit(dev);
+	}
+
+	/* debugging ... */
+	if (irq_debug) {
+		u32 report = saa_readl(SAA7134_IRQ_REPORT);
+		u32 status = saa_readl(SAA7134_IRQ_STATUS);
+		print_irqstatus(dev,42,report,status);
+	}
+
+	/* disable peripheral devices */
+	saa_writeb(SAA7134_SPECIAL_MODE,0);
+
+	/* shutdown hardware */
+	saa_writel(SAA7134_IRQ1,0);
+	saa_writel(SAA7134_IRQ2,0);
+	saa_writel(SAA7134_MAIN_CTRL,0);
+
+	/* shutdown subsystems */
+	saa7134_hwfini(dev);
+
+	/* unregister */
+	mutex_lock(&saa7134_devlist_lock);
+	list_del(&dev->devlist);
+	list_for_each_entry(mops, &mops_list, next)
+		mpeg_ops_detach(mops, dev);
+	mutex_unlock(&saa7134_devlist_lock);
+	saa7134_devcount--;
+
+	saa7134_i2c_unregister(dev);
+	saa7134_unregister_video(dev);
+
+
+	/* the DMA sound modules should be unloaded before reaching
+	   this, but just in case they are still present... */
+	if (dev->dmasound.priv_data != NULL) {
+		free_irq(pci_dev->irq, &dev->dmasound);
+		dev->dmasound.priv_data = NULL;
+	}
+
+
+	/* release resources */
+	free_irq(pci_dev->irq, dev);
+	iounmap(dev->lmmio);
+	release_mem_region(pci_resource_start(pci_dev,0),
+			   pci_resource_len(pci_dev,0));
+
+
+	v4l2_device_unregister(&dev->v4l2_dev);
+
+	/* free memory */
+	kfree(dev);
+}
+
+#ifdef CONFIG_PM
+
+/* resends a current buffer in queue after resume */
+static int saa7134_buffer_requeue(struct saa7134_dev *dev,
+				  struct saa7134_dmaqueue *q)
+{
+	struct saa7134_buf *buf, *next;
+
+	assert_spin_locked(&dev->slock);
+
+	buf  = q->curr;
+	next = buf;
+	dprintk("buffer_requeue\n");
+
+	if (!buf)
+		return 0;
+
+	dprintk("buffer_requeue : resending active buffers \n");
+
+	if (!list_empty(&q->queue))
+		next = list_entry(q->queue.next, struct saa7134_buf,
+					  vb.queue);
+	buf->activate(dev, buf, next);
+
+	return 0;
+}
+
+static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+	struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
+
+	/* disable overlay - apps should enable it explicitly on resume*/
+	dev->ovenable = 0;
+
+	/* Disable interrupts, DMA, and rest of the chip*/
+	saa_writel(SAA7134_IRQ1, 0);
+	saa_writel(SAA7134_IRQ2, 0);
+	saa_writel(SAA7134_MAIN_CTRL, 0);
+
+	dev->insuspend = 1;
+	synchronize_irq(pci_dev->irq);
+
+	/* ACK interrupts once more, just in case,
+		since the IRQ handler won't ack them anymore*/
+
+	saa_writel(SAA7134_IRQ_REPORT, saa_readl(SAA7134_IRQ_REPORT));
+
+	/* Disable timeout timers - if we have active buffers, we will
+	   fill them on resume*/
+
+	del_timer(&dev->video_q.timeout);
+	del_timer(&dev->vbi_q.timeout);
+	del_timer(&dev->ts_q.timeout);
+
+	if (dev->remote)
+		saa7134_ir_stop(dev);
+
+	pci_save_state(pci_dev);
+	pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
+
+	return 0;
+}
+
+static int saa7134_resume(struct pci_dev *pci_dev)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+	struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
+	unsigned long flags;
+
+	pci_set_power_state(pci_dev, PCI_D0);
+	pci_restore_state(pci_dev);
+
+	/* Do things that are done in saa7134_initdev ,
+		except of initializing memory structures.*/
+
+	saa7134_board_init1(dev);
+
+	/* saa7134_hwinit1 */
+	if (saa7134_boards[dev->board].video_out)
+		saa7134_videoport_init(dev);
+	if (card_has_mpeg(dev))
+		saa7134_ts_init_hw(dev);
+	if (dev->remote)
+		saa7134_ir_start(dev);
+	saa7134_hw_enable1(dev);
+
+	msleep(100);
+
+	saa7134_board_init2(dev);
+
+	/*saa7134_hwinit2*/
+	saa7134_set_tvnorm_hw(dev);
+	saa7134_tvaudio_setmute(dev);
+	saa7134_tvaudio_setvolume(dev, dev->ctl_volume);
+	saa7134_tvaudio_init(dev);
+	saa7134_enable_i2s(dev);
+	saa7134_hw_enable2(dev);
+
+	saa7134_irq_video_signalchange(dev);
+
+	/*resume unfinished buffer(s)*/
+	spin_lock_irqsave(&dev->slock, flags);
+	saa7134_buffer_requeue(dev, &dev->video_q);
+	saa7134_buffer_requeue(dev, &dev->vbi_q);
+	saa7134_buffer_requeue(dev, &dev->ts_q);
+
+	/* FIXME: Disable DMA audio sound - temporary till proper support
+		  is implemented*/
+
+	dev->dmasound.dma_running = 0;
+
+	/* start DMA now*/
+	dev->insuspend = 0;
+	smp_wmb();
+	saa7134_set_dmabits(dev);
+	spin_unlock_irqrestore(&dev->slock, flags);
+
+	return 0;
+}
+#endif
+
+/* ----------------------------------------------------------- */
+
+int saa7134_ts_register(struct saa7134_mpeg_ops *ops)
+{
+	struct saa7134_dev *dev;
+
+	mutex_lock(&saa7134_devlist_lock);
+	list_for_each_entry(dev, &saa7134_devlist, devlist)
+		mpeg_ops_attach(ops, dev);
+	list_add_tail(&ops->next,&mops_list);
+	mutex_unlock(&saa7134_devlist_lock);
+	return 0;
+}
+
+void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops)
+{
+	struct saa7134_dev *dev;
+
+	mutex_lock(&saa7134_devlist_lock);
+	list_del(&ops->next);
+	list_for_each_entry(dev, &saa7134_devlist, devlist)
+		mpeg_ops_detach(ops, dev);
+	mutex_unlock(&saa7134_devlist_lock);
+}
+
+EXPORT_SYMBOL(saa7134_ts_register);
+EXPORT_SYMBOL(saa7134_ts_unregister);
+
+/* ----------------------------------------------------------- */
+
+static struct pci_driver saa7134_pci_driver = {
+	.name     = "saa7134",
+	.id_table = saa7134_pci_tbl,
+	.probe    = saa7134_initdev,
+	.remove   = __devexit_p(saa7134_finidev),
+#ifdef CONFIG_PM
+	.suspend  = saa7134_suspend,
+	.resume   = saa7134_resume
+#endif
+};
+
+static int __init saa7134_init(void)
+{
+	INIT_LIST_HEAD(&saa7134_devlist);
+	printk(KERN_INFO "saa7130/34: v4l2 driver version %s loaded\n",
+	       SAA7134_VERSION);
+	return pci_register_driver(&saa7134_pci_driver);
+}
+
+static void __exit saa7134_fini(void)
+{
+	pci_unregister_driver(&saa7134_pci_driver);
+}
+
+module_init(saa7134_init);
+module_exit(saa7134_fini);
+
+/* ----------------------------------------------------------- */
+
+EXPORT_SYMBOL(saa7134_set_gpio);
+EXPORT_SYMBOL(saa7134_boards);
+
+/* ----------------- for the DMA sound modules --------------- */
+
+EXPORT_SYMBOL(saa7134_dmasound_init);
+EXPORT_SYMBOL(saa7134_dmasound_exit);
+EXPORT_SYMBOL(saa7134_pgtable_free);
+EXPORT_SYMBOL(saa7134_pgtable_build);
+EXPORT_SYMBOL(saa7134_pgtable_alloc);
+EXPORT_SYMBOL(saa7134_set_dmabits);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c
new file mode 100644
index 0000000..b209de4
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-dvb.c
@@ -0,0 +1,1936 @@
+/*
+ *
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  Extended 3 / 2005 by Hartmut Hackmann to support various
+ *  cards with the tda10046 DVB-T channel decoder
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/suspend.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+#include <media/v4l2-common.h>
+#include "dvb-pll.h"
+#include <dvb_frontend.h>
+
+#include "mt352.h"
+#include "mt352_priv.h" /* FIXME */
+#include "tda1004x.h"
+#include "nxt200x.h"
+#include "tuner-xc2028.h"
+#include "xc5000.h"
+
+#include "tda10086.h"
+#include "tda826x.h"
+#include "tda827x.h"
+#include "isl6421.h"
+#include "isl6405.h"
+#include "lnbp21.h"
+#include "tuner-simple.h"
+#include "tda10048.h"
+#include "tda18271.h"
+#include "lgdt3305.h"
+#include "tda8290.h"
+#include "mb86a20s.h"
+#include "lgs8gxx.h"
+
+#include "zl10353.h"
+#include "qt1010.h"
+
+#include "zl10036.h"
+#include "zl10039.h"
+#include "mt312.h"
+#include "s5h1411.h"
+
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+static unsigned int antenna_pwr;
+
+module_param(antenna_pwr, int, 0444);
+MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)");
+
+static int use_frontend;
+module_param(use_frontend, int, 0644);
+MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off module debugging (default:off).");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define dprintk(fmt, arg...)	do { if (debug) \
+	printk(KERN_DEBUG "%s/dvb: " fmt, dev->name , ## arg); } while(0)
+
+/* Print a warning */
+#define wprintk(fmt, arg...) \
+	printk(KERN_WARNING "%s/dvb: " fmt, dev->name, ## arg)
+
+/* ------------------------------------------------------------------
+ * mt352 based DVB-T cards
+ */
+
+static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on)
+{
+	u32 ok;
+
+	if (!on) {
+		saa_setl(SAA7134_GPIO_GPMODE0 >> 2,     (1 << 26));
+		saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26));
+		return 0;
+	}
+
+	saa_setl(SAA7134_GPIO_GPMODE0 >> 2,     (1 << 26));
+	saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2,   (1 << 26));
+	udelay(10);
+
+	saa_setl(SAA7134_GPIO_GPMODE0 >> 2,     (1 << 28));
+	saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28));
+	udelay(10);
+	saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2,   (1 << 28));
+	udelay(10);
+	ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27);
+	dprintk("%s %s\n", __func__, ok ? "on" : "off");
+
+	if (!ok)
+		saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2,   (1 << 26));
+	return ok;
+}
+
+static int mt352_pinnacle_init(struct dvb_frontend* fe)
+{
+	static u8 clock_config []  = { CLOCK_CTL,  0x3d, 0x28 };
+	static u8 reset []         = { RESET,      0x80 };
+	static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+	static u8 agc_cfg []       = { AGC_TARGET, 0x28, 0xa0 };
+	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x31 };
+	static u8 fsm_ctl_cfg[]    = { 0x7b,       0x04 };
+	static u8 gpp_ctl_cfg []   = { GPP_CTL,    0x0f };
+	static u8 scan_ctl_cfg []  = { SCAN_CTL,   0x0d };
+	static u8 irq_cfg []       = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 };
+	struct saa7134_dev *dev= fe->dvb->priv;
+
+	dprintk("%s called\n", __func__);
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(200);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
+
+	mt352_write(fe, fsm_ctl_cfg,    sizeof(fsm_ctl_cfg));
+	mt352_write(fe, scan_ctl_cfg,   sizeof(scan_ctl_cfg));
+	mt352_write(fe, irq_cfg,        sizeof(irq_cfg));
+
+	return 0;
+}
+
+static int mt352_aver777_init(struct dvb_frontend* fe)
+{
+	static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x2d };
+	static u8 reset []         = { RESET,      0x80 };
+	static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+	static u8 agc_cfg []       = { AGC_TARGET, 0x28, 0xa0 };
+	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 };
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(200);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+	return 0;
+}
+
+static int mt352_avermedia_xc3028_init(struct dvb_frontend *fe)
+{
+	static u8 clock_config []  = { CLOCK_CTL, 0x38, 0x2d };
+	static u8 reset []         = { RESET, 0x80 };
+	static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+	static u8 agc_cfg []       = { AGC_TARGET, 0xe };
+	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 };
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(200);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+	return 0;
+}
+
+static int mt352_pinnacle_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u8 off[] = { 0x00, 0xf1};
+	u8 on[]  = { 0x00, 0x71};
+	struct i2c_msg msg = {.addr=0x43, .flags=0, .buf=off, .len = sizeof(off)};
+
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct v4l2_frequency f;
+
+	/* set frequency (mt2050) */
+	f.tuner     = 0;
+	f.type      = V4L2_TUNER_DIGITAL_TV;
+	f.frequency = c->frequency / 1000 * 16 / 1000;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(&dev->i2c_adap, &msg, 1);
+	saa_call_all(dev, tuner, s_frequency, &f);
+	msg.buf = on;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+	pinnacle_antenna_pwr(dev, antenna_pwr);
+
+	/* mt352 setup */
+	return mt352_pinnacle_init(fe);
+}
+
+static struct mt352_config pinnacle_300i = {
+	.demod_address = 0x3c >> 1,
+	.adc_clock     = 20333,
+	.if2           = 36150,
+	.no_tuner      = 1,
+	.demod_init    = mt352_pinnacle_init,
+};
+
+static struct mt352_config avermedia_777 = {
+	.demod_address = 0xf,
+	.demod_init    = mt352_aver777_init,
+};
+
+static struct mt352_config avermedia_xc3028_mt352_dev = {
+	.demod_address   = (0x1e >> 1),
+	.no_tuner        = 1,
+	.demod_init      = mt352_avermedia_xc3028_init,
+};
+
+static struct tda18271_std_map mb86a20s_tda18271_std_map = {
+	.dvbt_6   = { .if_freq = 3300, .agc_mode = 3, .std = 4,
+		      .if_lvl = 7, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config kworld_tda18271_config = {
+	.std_map = &mb86a20s_tda18271_std_map,
+	.gate    = TDA18271_GATE_DIGITAL,
+	.config  = 3,	/* Use tuner callback for AGC */
+
+};
+
+static const struct mb86a20s_config kworld_mb86a20s_config = {
+	.demod_address = 0x10,
+};
+
+static int kworld_sbtvd_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+
+	unsigned char initmsg[] = {0x45, 0x97};
+	unsigned char msg_enable[] = {0x45, 0xc1};
+	unsigned char msg_disable[] = {0x45, 0x81};
+	struct i2c_msg msg = {.addr = 0x4b, .flags = 0, .buf = initmsg, .len = 2};
+
+	if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
+		wprintk("could not access the I2C gate\n");
+		return -EIO;
+	}
+	if (enable)
+		msg.buf = msg_enable;
+	else
+		msg.buf = msg_disable;
+	if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
+		wprintk("could not access the I2C gate\n");
+		return -EIO;
+	}
+	msleep(20);
+	return 0;
+}
+
+/* ==================================================================
+ * tda1004x based DVB-T cards, helper functions
+ */
+
+static int philips_tda1004x_request_firmware(struct dvb_frontend *fe,
+					   const struct firmware **fw, char *name)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	return request_firmware(fw, name, &dev->pci->dev);
+}
+
+/* ------------------------------------------------------------------
+ * these tuners are tu1216, td1316(a)
+ */
+
+static int philips_tda6651_pll_set(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
+	u8 tuner_buf[4];
+	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
+			sizeof(tuner_buf) };
+	int tuner_frequency = 0;
+	u8 band, cp, filter;
+
+	/* determine charge pump */
+	tuner_frequency = c->frequency + 36166000;
+	if (tuner_frequency < 87000000)
+		return -EINVAL;
+	else if (tuner_frequency < 130000000)
+		cp = 3;
+	else if (tuner_frequency < 160000000)
+		cp = 5;
+	else if (tuner_frequency < 200000000)
+		cp = 6;
+	else if (tuner_frequency < 290000000)
+		cp = 3;
+	else if (tuner_frequency < 420000000)
+		cp = 5;
+	else if (tuner_frequency < 480000000)
+		cp = 6;
+	else if (tuner_frequency < 620000000)
+		cp = 3;
+	else if (tuner_frequency < 830000000)
+		cp = 5;
+	else if (tuner_frequency < 895000000)
+		cp = 7;
+	else
+		return -EINVAL;
+
+	/* determine band */
+	if (c->frequency < 49000000)
+		return -EINVAL;
+	else if (c->frequency < 161000000)
+		band = 1;
+	else if (c->frequency < 444000000)
+		band = 2;
+	else if (c->frequency < 861000000)
+		band = 4;
+	else
+		return -EINVAL;
+
+	/* setup PLL filter */
+	switch (c->bandwidth_hz) {
+	case 6000000:
+		filter = 0;
+		break;
+
+	case 7000000:
+		filter = 0;
+		break;
+
+	case 8000000:
+		filter = 1;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* calculate divisor
+	 * ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
+	 */
+	tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000;
+
+	/* setup tuner buffer */
+	tuner_buf[0] = (tuner_frequency >> 8) & 0x7f;
+	tuner_buf[1] = tuner_frequency & 0xff;
+	tuner_buf[2] = 0xca;
+	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) {
+		wprintk("could not write to tuner at addr: 0x%02x\n",
+			addr << 1);
+		return -EIO;
+	}
+	msleep(1);
+	return 0;
+}
+
+static int philips_tu1216_init(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
+	static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
+
+	/* setup PLL configuration */
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
+		return -EIO;
+	msleep(1);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct tda1004x_config philips_tu1216_60_config = {
+	.demod_address = 0x8,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_4M,
+	.agc_config    = TDA10046_AGC_DEFAULT,
+	.if_freq       = TDA10046_FREQ_3617,
+	.tuner_address = 0x60,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config philips_tu1216_61_config = {
+
+	.demod_address = 0x8,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_4M,
+	.agc_config    = TDA10046_AGC_DEFAULT,
+	.if_freq       = TDA10046_FREQ_3617,
+	.tuner_address = 0x61,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+/* ------------------------------------------------------------------ */
+
+static int philips_td1316_tuner_init(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
+	static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab };
+	struct i2c_msg init_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+	/* setup PLL configuration */
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static int philips_td1316_tuner_set_params(struct dvb_frontend *fe)
+{
+	return philips_tda6651_pll_set(fe);
+}
+
+static int philips_td1316_tuner_sleep(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
+	static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 };
+	struct i2c_msg analog_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+	/* switch the tuner to analog mode */
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&dev->i2c_adap, &analog_msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int philips_europa_tuner_init(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	static u8 msg[] = { 0x00, 0x40};
+	struct i2c_msg init_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+
+	if (philips_td1316_tuner_init(fe))
+		return -EIO;
+	msleep(1);
+	if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
+		return -EIO;
+
+	return 0;
+}
+
+static int philips_europa_tuner_sleep(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+
+	static u8 msg[] = { 0x00, 0x14 };
+	struct i2c_msg analog_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+	if (philips_td1316_tuner_sleep(fe))
+		return -EIO;
+
+	/* switch the board to analog mode */
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
+	return 0;
+}
+
+static int philips_europa_demod_sleep(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+
+	if (dev->original_demod_sleep)
+		dev->original_demod_sleep(fe);
+	fe->ops.i2c_gate_ctrl(fe, 1);
+	return 0;
+}
+
+static struct tda1004x_config philips_europa_config = {
+
+	.demod_address = 0x8,
+	.invert        = 0,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_4M,
+	.agc_config    = TDA10046_AGC_IFO_AUTO_POS,
+	.if_freq       = TDA10046_FREQ_052,
+	.tuner_address = 0x61,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config medion_cardbus = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_IFO_AUTO_NEG,
+	.if_freq       = TDA10046_FREQ_3613,
+	.tuner_address = 0x61,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config technotrend_budget_t3000_config = {
+	.demod_address = 0x8,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_4M,
+	.agc_config    = TDA10046_AGC_DEFAULT,
+	.if_freq       = TDA10046_FREQ_3617,
+	.tuner_address = 0x63,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+/* ------------------------------------------------------------------
+ * tda 1004x based cards with philips silicon tuner
+ */
+
+static int tda8290_i2c_gate_ctrl( struct dvb_frontend* fe, int enable)
+{
+	struct tda1004x_state *state = fe->demodulator_priv;
+
+	u8 addr = state->config->i2c_gate;
+	static u8 tda8290_close[] = { 0x21, 0xc0};
+	static u8 tda8290_open[]  = { 0x21, 0x80};
+	struct i2c_msg tda8290_msg = {.addr = addr,.flags = 0, .len = 2};
+	if (enable) {
+		tda8290_msg.buf = tda8290_close;
+	} else {
+		tda8290_msg.buf = tda8290_open;
+	}
+	if (i2c_transfer(state->i2c, &tda8290_msg, 1) != 1) {
+		struct saa7134_dev *dev = fe->dvb->priv;
+		wprintk("could not access tda8290 I2C gate\n");
+		return -EIO;
+	}
+	msleep(20);
+	return 0;
+}
+
+static int philips_tda827x_tuner_init(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+
+	switch (state->config->antenna_switch) {
+	case 0: break;
+	case 1:	dprintk("setting GPIO21 to 0 (TV antenna?)\n");
+		saa7134_set_gpio(dev, 21, 0);
+		break;
+	case 2: dprintk("setting GPIO21 to 1 (Radio antenna?)\n");
+		saa7134_set_gpio(dev, 21, 1);
+		break;
+	}
+	return 0;
+}
+
+static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+
+	switch (state->config->antenna_switch) {
+	case 0: break;
+	case 1: dprintk("setting GPIO21 to 1 (Radio antenna?)\n");
+		saa7134_set_gpio(dev, 21, 1);
+		break;
+	case 2:	dprintk("setting GPIO21 to 0 (TV antenna?)\n");
+		saa7134_set_gpio(dev, 21, 0);
+		break;
+	}
+	return 0;
+}
+
+static int configure_tda827x_fe(struct saa7134_dev *dev,
+				struct tda1004x_config *cdec_conf,
+				struct tda827x_config *tuner_conf)
+{
+	struct videobuf_dvb_frontend *fe0;
+
+	/* Get the first frontend */
+	fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+
+	fe0->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
+	if (fe0->dvb.frontend) {
+		if (cdec_conf->i2c_gate)
+			fe0->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
+		if (dvb_attach(tda827x_attach, fe0->dvb.frontend,
+			       cdec_conf->tuner_address,
+			       &dev->i2c_adap, tuner_conf))
+			return 0;
+
+		wprintk("no tda827x tuner found at addr: %02x\n",
+				cdec_conf->tuner_address);
+	}
+	return -EINVAL;
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct tda827x_config tda827x_cfg_0 = {
+	.init = philips_tda827x_tuner_init,
+	.sleep = philips_tda827x_tuner_sleep,
+	.config = 0,
+	.switch_addr = 0
+};
+
+static struct tda827x_config tda827x_cfg_1 = {
+	.init = philips_tda827x_tuner_init,
+	.sleep = philips_tda827x_tuner_sleep,
+	.config = 1,
+	.switch_addr = 0x4b
+};
+
+static struct tda827x_config tda827x_cfg_2 = {
+	.init = philips_tda827x_tuner_init,
+	.sleep = philips_tda827x_tuner_sleep,
+	.config = 2,
+	.switch_addr = 0x4b
+};
+
+static struct tda827x_config tda827x_cfg_2_sw42 = {
+	.init = philips_tda827x_tuner_init,
+	.sleep = philips_tda827x_tuner_sleep,
+	.config = 2,
+	.switch_addr = 0x42
+};
+
+/* ------------------------------------------------------------------ */
+
+static struct tda1004x_config tda827x_lifeview_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.tuner_address = 0x60,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config philips_tiger_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.antenna_switch= 1,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config cinergy_ht_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP01_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config cinergy_ht_pci_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP01_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x60,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config philips_tiger_s_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP01_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.antenna_switch= 1,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config pinnacle_pctv_310i_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config hauppauge_hvr_1110_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config asus_p7131_dual_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.antenna_switch= 2,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config lifeview_trio_config = {
+	.demod_address = 0x09,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP00_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.tuner_address = 0x60,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config tevion_dvbt220rf_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.tuner_address = 0x60,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config md8800_dvbt_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP01_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x60,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config asus_p7131_4871_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP01_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.antenna_switch= 2,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config asus_p7131_hybrid_lna_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.antenna_switch= 2,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config kworld_dvb_t_210_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.antenna_switch= 1,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config avermedia_super_007_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP01_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x60,
+	.antenna_switch= 1,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config twinhan_dtv_dvb_3056_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP01_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x42,
+	.tuner_address = 0x61,
+	.antenna_switch = 1,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config asus_tiger_3in1_config = {
+	.demod_address = 0x0b,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.antenna_switch = 1,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config asus_ps3_100_config = {
+	.demod_address = 0x0b,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.antenna_switch = 1,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+/* ------------------------------------------------------------------
+ * special case: this card uses saa713x GPIO22 for the mode switch
+ */
+
+static int ads_duo_tuner_init(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	philips_tda827x_tuner_init(fe);
+	/* route TDA8275a AGC input to the channel decoder */
+	saa7134_set_gpio(dev, 22, 1);
+	return 0;
+}
+
+static int ads_duo_tuner_sleep(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	/* route TDA8275a AGC input to the analog IF chip*/
+	saa7134_set_gpio(dev, 22, 0);
+	philips_tda827x_tuner_sleep(fe);
+	return 0;
+}
+
+static struct tda827x_config ads_duo_cfg = {
+	.init = ads_duo_tuner_init,
+	.sleep = ads_duo_tuner_sleep,
+	.config = 0
+};
+
+static struct tda1004x_config ads_tech_duo_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP00_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.tuner_address = 0x61,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct zl10353_config behold_h6_config = {
+	.demod_address = 0x1e>>1,
+	.no_tuner      = 1,
+	.parallel_ts   = 1,
+	.disable_i2c_gate_ctrl = 1,
+};
+
+static struct xc5000_config behold_x7_tunerconfig = {
+	.i2c_address      = 0xc2>>1,
+	.if_khz           = 4560,
+	.radio_input      = XC5000_RADIO_FM1,
+};
+
+static struct zl10353_config behold_x7_config = {
+	.demod_address = 0x1e>>1,
+	.if2           = 45600,
+	.no_tuner      = 1,
+	.parallel_ts   = 1,
+	.disable_i2c_gate_ctrl = 1,
+};
+
+static struct zl10353_config videomate_t750_zl10353_config = {
+	.demod_address         = 0x0f,
+	.no_tuner              = 1,
+	.parallel_ts           = 1,
+	.disable_i2c_gate_ctrl = 1,
+};
+
+static struct qt1010_config videomate_t750_qt1010_config = {
+	.i2c_address = 0x62
+};
+
+
+/* ==================================================================
+ * tda10086 based DVB-S cards, helper functions
+ */
+
+static struct tda10086_config flydvbs = {
+	.demod_address = 0x0e,
+	.invert = 0,
+	.diseqc_tone = 0,
+	.xtal_freq = TDA10086_XTAL_16M,
+};
+
+static struct tda10086_config sd1878_4m = {
+	.demod_address = 0x0e,
+	.invert = 0,
+	.diseqc_tone = 0,
+	.xtal_freq = TDA10086_XTAL_4M,
+};
+
+/* ------------------------------------------------------------------
+ * special case: lnb supply is connected to the gated i2c
+ */
+
+static int md8800_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	int res = -EIO;
+	struct saa7134_dev *dev = fe->dvb->priv;
+	if (fe->ops.i2c_gate_ctrl) {
+		fe->ops.i2c_gate_ctrl(fe, 1);
+		if (dev->original_set_voltage)
+			res = dev->original_set_voltage(fe, voltage);
+		fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+	return res;
+};
+
+static int md8800_set_high_voltage(struct dvb_frontend *fe, long arg)
+{
+	int res = -EIO;
+	struct saa7134_dev *dev = fe->dvb->priv;
+	if (fe->ops.i2c_gate_ctrl) {
+		fe->ops.i2c_gate_ctrl(fe, 1);
+		if (dev->original_set_high_voltage)
+			res = dev->original_set_high_voltage(fe, arg);
+		fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+	return res;
+};
+
+static int md8800_set_voltage2(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	u8 wbuf[2] = { 0x1f, 00 };
+	u8 rbuf;
+	struct i2c_msg msg[] = { { .addr = 0x08, .flags = 0, .buf = wbuf, .len = 1 },
+				 { .addr = 0x08, .flags = I2C_M_RD, .buf = &rbuf, .len = 1 } };
+
+	if (i2c_transfer(&dev->i2c_adap, msg, 2) != 2)
+		return -EIO;
+	/* NOTE: this assumes that gpo1 is used, it might be bit 5 (gpo2) */
+	if (voltage == SEC_VOLTAGE_18)
+		wbuf[1] = rbuf | 0x10;
+	else
+		wbuf[1] = rbuf & 0xef;
+	msg[0].len = 2;
+	i2c_transfer(&dev->i2c_adap, msg, 1);
+	return 0;
+}
+
+static int md8800_set_high_voltage2(struct dvb_frontend *fe, long arg)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	wprintk("%s: sorry can't set high LNB supply voltage from here\n", __func__);
+	return -EIO;
+}
+
+/* ==================================================================
+ * nxt200x based ATSC cards, helper functions
+ */
+
+static struct nxt200x_config avertvhda180 = {
+	.demod_address    = 0x0a,
+};
+
+static struct nxt200x_config kworldatsc110 = {
+	.demod_address    = 0x0a,
+};
+
+/* ------------------------------------------------------------------ */
+
+static struct mt312_config avertv_a700_mt312 = {
+	.demod_address = 0x0e,
+	.voltage_inverted = 1,
+};
+
+static struct zl10036_config avertv_a700_tuner = {
+	.tuner_address = 0x60,
+};
+
+static struct mt312_config zl10313_compro_s350_config = {
+	.demod_address = 0x0e,
+};
+
+static struct lgdt3305_config hcw_lgdt3305_config = {
+	.i2c_addr           = 0x0e,
+	.mpeg_mode          = LGDT3305_MPEG_SERIAL,
+	.tpclk_edge         = LGDT3305_TPCLK_RISING_EDGE,
+	.tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
+	.deny_i2c_rptr      = 1,
+	.spectral_inversion = 1,
+	.qam_if_khz         = 4000,
+	.vsb_if_khz         = 3250,
+};
+
+static struct tda10048_config hcw_tda10048_config = {
+	.demod_address    = 0x10 >> 1,
+	.output_mode      = TDA10048_SERIAL_OUTPUT,
+	.fwbulkwritelen   = TDA10048_BULKWRITE_200,
+	.inversion        = TDA10048_INVERSION_ON,
+	.dtv6_if_freq_khz = TDA10048_IF_3300,
+	.dtv7_if_freq_khz = TDA10048_IF_3500,
+	.dtv8_if_freq_khz = TDA10048_IF_4000,
+	.clk_freq_khz     = TDA10048_CLK_16000,
+	.disable_gate_access = 1,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+	.atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 4,
+		      .if_lvl = 1, .rfagc_top = 0x58, },
+	.qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 5,
+		      .if_lvl = 1, .rfagc_top = 0x58, },
+};
+
+static struct tda18271_config hcw_tda18271_config = {
+	.std_map = &hauppauge_tda18271_std_map,
+	.gate    = TDA18271_GATE_ANALOG,
+	.config  = 3,
+	.output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
+static struct tda829x_config tda829x_no_probe = {
+	.probe_tuner = TDA829X_DONT_PROBE,
+};
+
+static struct tda10048_config zolid_tda10048_config = {
+	.demod_address    = 0x10 >> 1,
+	.output_mode      = TDA10048_PARALLEL_OUTPUT,
+	.fwbulkwritelen   = TDA10048_BULKWRITE_200,
+	.inversion        = TDA10048_INVERSION_ON,
+	.dtv6_if_freq_khz = TDA10048_IF_3300,
+	.dtv7_if_freq_khz = TDA10048_IF_3500,
+	.dtv8_if_freq_khz = TDA10048_IF_4000,
+	.clk_freq_khz     = TDA10048_CLK_16000,
+	.disable_gate_access = 1,
+};
+
+static struct tda18271_config zolid_tda18271_config = {
+	.gate    = TDA18271_GATE_ANALOG,
+};
+
+static struct tda10048_config dtv1000s_tda10048_config = {
+	.demod_address    = 0x10 >> 1,
+	.output_mode      = TDA10048_PARALLEL_OUTPUT,
+	.fwbulkwritelen   = TDA10048_BULKWRITE_200,
+	.inversion        = TDA10048_INVERSION_ON,
+	.dtv6_if_freq_khz = TDA10048_IF_3300,
+	.dtv7_if_freq_khz = TDA10048_IF_3800,
+	.dtv8_if_freq_khz = TDA10048_IF_4300,
+	.clk_freq_khz     = TDA10048_CLK_16000,
+	.disable_gate_access = 1,
+};
+
+static struct tda18271_std_map dtv1000s_tda18271_std_map = {
+	.dvbt_6   = { .if_freq = 3300, .agc_mode = 3, .std = 4,
+		      .if_lvl = 1, .rfagc_top = 0x37, },
+	.dvbt_7   = { .if_freq = 3800, .agc_mode = 3, .std = 5,
+		      .if_lvl = 1, .rfagc_top = 0x37, },
+	.dvbt_8   = { .if_freq = 4300, .agc_mode = 3, .std = 6,
+		      .if_lvl = 1, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config dtv1000s_tda18271_config = {
+	.std_map = &dtv1000s_tda18271_std_map,
+	.gate    = TDA18271_GATE_ANALOG,
+};
+
+static struct lgs8gxx_config prohdtv_pro2_lgs8g75_config = {
+	.prod = LGS8GXX_PROD_LGS8G75,
+	.demod_address = 0x1d,
+	.serial_ts = 0,
+	.ts_clk_pol = 1,
+	.ts_clk_gated = 0,
+	.if_clk_freq = 30400, /* 30.4 MHz */
+	.if_freq = 4000, /* 4.00 MHz */
+	.if_neg_center = 0,
+	.ext_adc = 0,
+	.adc_signed = 1,
+	.adc_vpp = 3, /* 2.0 Vpp */
+	.if_neg_edge = 1,
+};
+
+static struct tda18271_config prohdtv_pro2_tda18271_config = {
+	.gate = TDA18271_GATE_ANALOG,
+	.output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
+static struct tda18271_std_map kworld_tda18271_std_map = {
+	.atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 3,
+		      .if_lvl = 6, .rfagc_top = 0x37 },
+	.qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 0,
+		      .if_lvl = 6, .rfagc_top = 0x37 },
+};
+
+static struct tda18271_config kworld_pc150u_tda18271_config = {
+	.std_map = &kworld_tda18271_std_map,
+	.gate    = TDA18271_GATE_ANALOG,
+	.output_opt = TDA18271_OUTPUT_LT_OFF,
+	.config  = 3,	/* Use tuner callback for AGC */
+	.rf_cal_on_startup = 1
+};
+
+static struct s5h1411_config kworld_s5h1411_config = {
+	.output_mode   = S5H1411_PARALLEL_OUTPUT,
+	.gpio          = S5H1411_GPIO_OFF,
+	.qam_if        = S5H1411_IF_4000,
+	.vsb_if        = S5H1411_IF_3250,
+	.inversion     = S5H1411_INVERSION_ON,
+	.status_mode   = S5H1411_DEMODLOCKING,
+	.mpeg_timing   =
+		S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+
+/* ==================================================================
+ * Core code
+ */
+
+static int dvb_init(struct saa7134_dev *dev)
+{
+	int ret;
+	int attach_xc3028 = 0;
+	struct videobuf_dvb_frontend *fe0;
+
+	/* FIXME: add support for multi-frontend */
+	mutex_init(&dev->frontends.lock);
+	INIT_LIST_HEAD(&dev->frontends.felist);
+
+	printk(KERN_INFO "%s() allocating 1 frontend\n", __func__);
+	fe0 = videobuf_dvb_alloc_frontend(&dev->frontends, 1);
+	if (!fe0) {
+		printk(KERN_ERR "%s() failed to alloc\n", __func__);
+		return -ENOMEM;
+	}
+
+	/* init struct videobuf_dvb */
+	dev->ts.nr_bufs    = 32;
+	dev->ts.nr_packets = 32*4;
+	fe0->dvb.name = dev->name;
+	videobuf_queue_sg_init(&fe0->dvb.dvbq, &saa7134_ts_qops,
+			    &dev->pci->dev, &dev->slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			    V4L2_FIELD_ALTERNATE,
+			    sizeof(struct saa7134_buf),
+			    dev, NULL);
+
+	switch (dev->board) {
+	case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
+		dprintk("pinnacle 300i dvb setup\n");
+		fe0->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			fe0->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
+		}
+		break;
+	case SAA7134_BOARD_AVERMEDIA_777:
+	case SAA7134_BOARD_AVERMEDIA_A16AR:
+		dprintk("avertv 777 dvb setup\n");
+		fe0->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+				   &dev->i2c_adap, 0x61,
+				   TUNER_PHILIPS_TD1316);
+		}
+		break;
+	case SAA7134_BOARD_AVERMEDIA_A16D:
+		dprintk("AverMedia A16D dvb setup\n");
+		fe0->dvb.frontend = dvb_attach(mt352_attach,
+						&avermedia_xc3028_mt352_dev,
+						&dev->i2c_adap);
+		attach_xc3028 = 1;
+		break;
+	case SAA7134_BOARD_MD7134:
+		fe0->dvb.frontend = dvb_attach(tda10046_attach,
+					       &medion_cardbus,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+				   &dev->i2c_adap, medion_cardbus.tuner_address,
+				   TUNER_PHILIPS_FMD1216ME_MK3);
+		}
+		break;
+	case SAA7134_BOARD_PHILIPS_TOUGH:
+		fe0->dvb.frontend = dvb_attach(tda10046_attach,
+					       &philips_tu1216_60_config,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
+			fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
+		}
+		break;
+	case SAA7134_BOARD_FLYDVBTDUO:
+	case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
+		if (configure_tda827x_fe(dev, &tda827x_lifeview_config,
+					 &tda827x_cfg_0) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_PHILIPS_EUROPA:
+	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+	case SAA7134_BOARD_ASUS_EUROPA_HYBRID:
+		fe0->dvb.frontend = dvb_attach(tda10046_attach,
+					       &philips_europa_config,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
+			fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+			fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+			fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+			fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+		}
+		break;
+	case SAA7134_BOARD_TECHNOTREND_BUDGET_T3000:
+		fe0->dvb.frontend = dvb_attach(tda10046_attach,
+					       &technotrend_budget_t3000_config,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
+			fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+			fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+			fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+			fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+		}
+		break;
+	case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+		fe0->dvb.frontend = dvb_attach(tda10046_attach,
+					       &philips_tu1216_61_config,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
+			fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
+		}
+		break;
+	case SAA7134_BOARD_KWORLD_DVBT_210:
+		if (configure_tda827x_fe(dev, &kworld_dvb_t_210_config,
+					 &tda827x_cfg_2) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+		fe0->dvb.frontend = dvb_attach(tda10048_attach,
+					       &hcw_tda10048_config,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			dvb_attach(tda829x_attach, fe0->dvb.frontend,
+				   &dev->i2c_adap, 0x4b,
+				   &tda829x_no_probe);
+			dvb_attach(tda18271_attach, fe0->dvb.frontend,
+				   0x60, &dev->i2c_adap,
+				   &hcw_tda18271_config);
+		}
+		break;
+	case SAA7134_BOARD_PHILIPS_TIGER:
+		if (configure_tda827x_fe(dev, &philips_tiger_config,
+					 &tda827x_cfg_0) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_PINNACLE_PCTV_310i:
+		if (configure_tda827x_fe(dev, &pinnacle_pctv_310i_config,
+					 &tda827x_cfg_1) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+		if (configure_tda827x_fe(dev, &hauppauge_hvr_1110_config,
+					 &tda827x_cfg_1) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+		fe0->dvb.frontend = dvb_attach(lgdt3305_attach,
+					       &hcw_lgdt3305_config,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			dvb_attach(tda829x_attach, fe0->dvb.frontend,
+				   &dev->i2c_adap, 0x4b,
+				   &tda829x_no_probe);
+			dvb_attach(tda18271_attach, fe0->dvb.frontend,
+				   0x60, &dev->i2c_adap,
+				   &hcw_tda18271_config);
+		}
+		break;
+	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+		if (configure_tda827x_fe(dev, &asus_p7131_dual_config,
+					 &tda827x_cfg_0) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_FLYDVBT_LR301:
+		if (configure_tda827x_fe(dev, &tda827x_lifeview_config,
+					 &tda827x_cfg_0) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_FLYDVB_TRIO:
+		if (!use_frontend) {	/* terrestrial */
+			if (configure_tda827x_fe(dev, &lifeview_trio_config,
+						 &tda827x_cfg_0) < 0)
+				goto detach_frontend;
+		} else {  		/* satellite */
+			fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
+			if (fe0->dvb.frontend) {
+				if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x63,
+									&dev->i2c_adap, 0) == NULL) {
+					wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__);
+					goto detach_frontend;
+				}
+				if (dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->i2c_adap,
+										0x08, 0, 0) == NULL) {
+					wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__);
+					goto detach_frontend;
+				}
+			}
+		}
+		break;
+	case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+	case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
+		fe0->dvb.frontend = dvb_attach(tda10046_attach,
+					       &ads_tech_duo_config,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			if (dvb_attach(tda827x_attach,fe0->dvb.frontend,
+				   ads_tech_duo_config.tuner_address, &dev->i2c_adap,
+								&ads_duo_cfg) == NULL) {
+				wprintk("no tda827x tuner found at addr: %02x\n",
+					ads_tech_duo_config.tuner_address);
+				goto detach_frontend;
+			}
+		} else
+			wprintk("failed to attach tda10046\n");
+		break;
+	case SAA7134_BOARD_TEVION_DVBT_220RF:
+		if (configure_tda827x_fe(dev, &tevion_dvbt220rf_config,
+					 &tda827x_cfg_0) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_MEDION_MD8800_QUADRO:
+		if (!use_frontend) {     /* terrestrial */
+			if (configure_tda827x_fe(dev, &md8800_dvbt_config,
+						 &tda827x_cfg_0) < 0)
+				goto detach_frontend;
+		} else {        /* satellite */
+			fe0->dvb.frontend = dvb_attach(tda10086_attach,
+							&flydvbs, &dev->i2c_adap);
+			if (fe0->dvb.frontend) {
+				struct dvb_frontend *fe = fe0->dvb.frontend;
+				u8 dev_id = dev->eedata[2];
+				u8 data = 0xc4;
+				struct i2c_msg msg = {.addr = 0x08, .flags = 0, .len = 1};
+
+				if (dvb_attach(tda826x_attach, fe0->dvb.frontend,
+						0x60, &dev->i2c_adap, 0) == NULL) {
+					wprintk("%s: Medion Quadro, no tda826x "
+						"found !\n", __func__);
+					goto detach_frontend;
+				}
+				if (dev_id != 0x08) {
+					/* we need to open the i2c gate (we know it exists) */
+					fe->ops.i2c_gate_ctrl(fe, 1);
+					if (dvb_attach(isl6405_attach, fe,
+							&dev->i2c_adap, 0x08, 0, 0) == NULL) {
+						wprintk("%s: Medion Quadro, no ISL6405 "
+							"found !\n", __func__);
+						goto detach_frontend;
+					}
+					if (dev_id == 0x07) {
+						/* fire up the 2nd section of the LNB supply since
+						   we can't do this from the other section */
+						msg.buf = &data;
+						i2c_transfer(&dev->i2c_adap, &msg, 1);
+					}
+					fe->ops.i2c_gate_ctrl(fe, 0);
+					dev->original_set_voltage = fe->ops.set_voltage;
+					fe->ops.set_voltage = md8800_set_voltage;
+					dev->original_set_high_voltage = fe->ops.enable_high_lnb_voltage;
+					fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage;
+				} else {
+					fe->ops.set_voltage = md8800_set_voltage2;
+					fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage2;
+				}
+			}
+		}
+		break;
+	case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
+		fe0->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend)
+			dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x61,
+				   NULL, DVB_PLL_TDHU2);
+		break;
+	case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
+	case SAA7134_BOARD_KWORLD_ATSC110:
+		fe0->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend)
+			dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+				   &dev->i2c_adap, 0x61,
+				   TUNER_PHILIPS_TUV1236D);
+		break;
+	case SAA7134_BOARD_KWORLD_PC150U:
+		saa7134_set_gpio(dev, 18, 1); /* Switch to digital mode */
+		saa7134_tuner_callback(dev, 0,
+				       TDA18271_CALLBACK_CMD_AGC_ENABLE, 1);
+		fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+					       &kworld_s5h1411_config,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			dvb_attach(tda829x_attach, fe0->dvb.frontend,
+				   &dev->i2c_adap, 0x4b,
+				   &tda829x_no_probe);
+			dvb_attach(tda18271_attach, fe0->dvb.frontend,
+				   0x60, &dev->i2c_adap,
+				   &kworld_pc150u_tda18271_config);
+		}
+		break;
+	case SAA7134_BOARD_FLYDVBS_LR300:
+		fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
+				       &dev->i2c_adap, 0) == NULL) {
+				wprintk("%s: No tda826x found!\n", __func__);
+				goto detach_frontend;
+			}
+			if (dvb_attach(isl6421_attach, fe0->dvb.frontend,
+				       &dev->i2c_adap, 0x08, 0, 0) == NULL) {
+				wprintk("%s: No ISL6421 found!\n", __func__);
+				goto detach_frontend;
+			}
+		}
+		break;
+	case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
+		fe0->dvb.frontend = dvb_attach(tda10046_attach,
+					       &medion_cardbus,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
+			fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+
+			dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+				   &dev->i2c_adap, medion_cardbus.tuner_address,
+				   TUNER_PHILIPS_FMD1216ME_MK3);
+		}
+		break;
+	case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
+		fe0->dvb.frontend = dvb_attach(tda10046_attach,
+				&philips_europa_config,
+				&dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			fe0->dvb.frontend->ops.tuner_ops.init = philips_td1316_tuner_init;
+			fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+		}
+		break;
+	case SAA7134_BOARD_CINERGY_HT_PCMCIA:
+		if (configure_tda827x_fe(dev, &cinergy_ht_config,
+					 &tda827x_cfg_0) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_CINERGY_HT_PCI:
+		if (configure_tda827x_fe(dev, &cinergy_ht_pci_config,
+					 &tda827x_cfg_0) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_PHILIPS_TIGER_S:
+		if (configure_tda827x_fe(dev, &philips_tiger_s_config,
+					 &tda827x_cfg_2) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_ASUS_P7131_4871:
+		if (configure_tda827x_fe(dev, &asus_p7131_4871_config,
+					 &tda827x_cfg_2) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
+		if (configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config,
+					 &tda827x_cfg_2) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_AVERMEDIA_SUPER_007:
+		if (configure_tda827x_fe(dev, &avermedia_super_007_config,
+					 &tda827x_cfg_0) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
+		if (configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config,
+					 &tda827x_cfg_2_sw42) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_PHILIPS_SNAKE:
+		fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
+						&dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
+					&dev->i2c_adap, 0) == NULL) {
+				wprintk("%s: No tda826x found!\n", __func__);
+				goto detach_frontend;
+			}
+			if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
+					&dev->i2c_adap, 0, 0) == NULL) {
+				wprintk("%s: No lnbp21 found!\n", __func__);
+				goto detach_frontend;
+			}
+		}
+		break;
+	case SAA7134_BOARD_CREATIX_CTX953:
+		if (configure_tda827x_fe(dev, &md8800_dvbt_config,
+					 &tda827x_cfg_0) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_MSI_TVANYWHERE_AD11:
+		if (configure_tda827x_fe(dev, &philips_tiger_s_config,
+					 &tda827x_cfg_2) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+		dprintk("AverMedia E506R dvb setup\n");
+		saa7134_set_gpio(dev, 25, 0);
+		msleep(10);
+		saa7134_set_gpio(dev, 25, 1);
+		fe0->dvb.frontend = dvb_attach(mt352_attach,
+						&avermedia_xc3028_mt352_dev,
+						&dev->i2c_adap);
+		attach_xc3028 = 1;
+		break;
+	case SAA7134_BOARD_MD7134_BRIDGE_2:
+		fe0->dvb.frontend = dvb_attach(tda10086_attach,
+						&sd1878_4m, &dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			struct dvb_frontend *fe;
+			if (dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60,
+				  &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) {
+				wprintk("%s: MD7134 DVB-S, no SD1878 "
+					"found !\n", __func__);
+				goto detach_frontend;
+			}
+			/* we need to open the i2c gate (we know it exists) */
+			fe = fe0->dvb.frontend;
+			fe->ops.i2c_gate_ctrl(fe, 1);
+			if (dvb_attach(isl6405_attach, fe,
+					&dev->i2c_adap, 0x08, 0, 0) == NULL) {
+				wprintk("%s: MD7134 DVB-S, no ISL6405 "
+					"found !\n", __func__);
+				goto detach_frontend;
+			}
+			fe->ops.i2c_gate_ctrl(fe, 0);
+			dev->original_set_voltage = fe->ops.set_voltage;
+			fe->ops.set_voltage = md8800_set_voltage;
+			dev->original_set_high_voltage = fe->ops.enable_high_lnb_voltage;
+			fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage;
+		}
+		break;
+	case SAA7134_BOARD_AVERMEDIA_M103:
+		saa7134_set_gpio(dev, 25, 0);
+		msleep(10);
+		saa7134_set_gpio(dev, 25, 1);
+		fe0->dvb.frontend = dvb_attach(mt352_attach,
+						&avermedia_xc3028_mt352_dev,
+						&dev->i2c_adap);
+		attach_xc3028 = 1;
+		break;
+	case SAA7134_BOARD_ASUSTeK_TIGER_3IN1:
+		if (!use_frontend) {     /* terrestrial */
+			if (configure_tda827x_fe(dev, &asus_tiger_3in1_config,
+							&tda827x_cfg_2) < 0)
+				goto detach_frontend;
+		} else {  		/* satellite */
+			fe0->dvb.frontend = dvb_attach(tda10086_attach,
+						&flydvbs, &dev->i2c_adap);
+			if (fe0->dvb.frontend) {
+				if (dvb_attach(tda826x_attach,
+						fe0->dvb.frontend, 0x60,
+						&dev->i2c_adap, 0) == NULL) {
+					wprintk("%s: Asus Tiger 3in1, no "
+						"tda826x found!\n", __func__);
+					goto detach_frontend;
+				}
+				if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
+						&dev->i2c_adap, 0, 0) == NULL) {
+					wprintk("%s: Asus Tiger 3in1, no lnbp21"
+						" found!\n", __func__);
+				       goto detach_frontend;
+			       }
+		       }
+	       }
+	       break;
+	case SAA7134_BOARD_ASUSTeK_PS3_100:
+		if (!use_frontend) {     /* terrestrial */
+			if (configure_tda827x_fe(dev, &asus_ps3_100_config,
+						 &tda827x_cfg_2) < 0)
+				goto detach_frontend;
+	       } else {                /* satellite */
+			fe0->dvb.frontend = dvb_attach(tda10086_attach,
+						       &flydvbs, &dev->i2c_adap);
+			if (fe0->dvb.frontend) {
+				if (dvb_attach(tda826x_attach,
+					       fe0->dvb.frontend, 0x60,
+					       &dev->i2c_adap, 0) == NULL) {
+					wprintk("%s: Asus My Cinema PS3-100, no "
+						"tda826x found!\n", __func__);
+					goto detach_frontend;
+				}
+				if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
+					       &dev->i2c_adap, 0, 0) == NULL) {
+					wprintk("%s: Asus My Cinema PS3-100, no lnbp21"
+						" found!\n", __func__);
+					goto detach_frontend;
+				}
+			}
+		}
+		break;
+	case SAA7134_BOARD_ASUSTeK_TIGER:
+		if (configure_tda827x_fe(dev, &philips_tiger_config,
+					 &tda827x_cfg_0) < 0)
+			goto detach_frontend;
+		break;
+	case SAA7134_BOARD_BEHOLD_H6:
+		fe0->dvb.frontend = dvb_attach(zl10353_attach,
+						&behold_h6_config,
+						&dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+				   &dev->i2c_adap, 0x61,
+				   TUNER_PHILIPS_FMD1216MEX_MK3);
+		}
+		break;
+	case SAA7134_BOARD_BEHOLD_X7:
+		fe0->dvb.frontend = dvb_attach(zl10353_attach,
+						&behold_x7_config,
+						&dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			dvb_attach(xc5000_attach, fe0->dvb.frontend,
+				   &dev->i2c_adap, &behold_x7_tunerconfig);
+		}
+		break;
+	case SAA7134_BOARD_BEHOLD_H7:
+		fe0->dvb.frontend = dvb_attach(zl10353_attach,
+						&behold_x7_config,
+						&dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			dvb_attach(xc5000_attach, fe0->dvb.frontend,
+				   &dev->i2c_adap, &behold_x7_tunerconfig);
+		}
+		break;
+	case SAA7134_BOARD_AVERMEDIA_A700_PRO:
+	case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
+		/* Zarlink ZL10313 */
+		fe0->dvb.frontend = dvb_attach(mt312_attach,
+			&avertv_a700_mt312, &dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			if (dvb_attach(zl10036_attach, fe0->dvb.frontend,
+					&avertv_a700_tuner, &dev->i2c_adap) == NULL) {
+				wprintk("%s: No zl10036 found!\n",
+					__func__);
+			}
+		}
+		break;
+	case SAA7134_BOARD_VIDEOMATE_S350:
+		fe0->dvb.frontend = dvb_attach(mt312_attach,
+				&zl10313_compro_s350_config, &dev->i2c_adap);
+		if (fe0->dvb.frontend)
+			if (dvb_attach(zl10039_attach, fe0->dvb.frontend,
+					0x60, &dev->i2c_adap) == NULL)
+				wprintk("%s: No zl10039 found!\n",
+					__func__);
+
+		break;
+	case SAA7134_BOARD_VIDEOMATE_T750:
+		fe0->dvb.frontend = dvb_attach(zl10353_attach,
+						&videomate_t750_zl10353_config,
+						&dev->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			if (dvb_attach(qt1010_attach,
+					fe0->dvb.frontend,
+					&dev->i2c_adap,
+					&videomate_t750_qt1010_config) == NULL)
+				wprintk("error attaching QT1010\n");
+		}
+		break;
+	case SAA7134_BOARD_ZOLID_HYBRID_PCI:
+		fe0->dvb.frontend = dvb_attach(tda10048_attach,
+					       &zolid_tda10048_config,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			dvb_attach(tda829x_attach, fe0->dvb.frontend,
+				   &dev->i2c_adap, 0x4b,
+				   &tda829x_no_probe);
+			dvb_attach(tda18271_attach, fe0->dvb.frontend,
+				   0x60, &dev->i2c_adap,
+				   &zolid_tda18271_config);
+		}
+		break;
+	case SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S:
+		fe0->dvb.frontend = dvb_attach(tda10048_attach,
+					       &dtv1000s_tda10048_config,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			dvb_attach(tda829x_attach, fe0->dvb.frontend,
+				   &dev->i2c_adap, 0x4b,
+				   &tda829x_no_probe);
+			dvb_attach(tda18271_attach, fe0->dvb.frontend,
+				   0x60, &dev->i2c_adap,
+				   &dtv1000s_tda18271_config);
+		}
+		break;
+	case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+		/* Switch to digital mode */
+		saa7134_tuner_callback(dev, 0,
+				       TDA18271_CALLBACK_CMD_AGC_ENABLE, 1);
+		fe0->dvb.frontend = dvb_attach(mb86a20s_attach,
+					       &kworld_mb86a20s_config,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			dvb_attach(tda829x_attach, fe0->dvb.frontend,
+				   &dev->i2c_adap, 0x4b,
+				   &tda829x_no_probe);
+			fe0->dvb.frontend->ops.i2c_gate_ctrl = kworld_sbtvd_gate_ctrl;
+			dvb_attach(tda18271_attach, fe0->dvb.frontend,
+				   0x60, &dev->i2c_adap,
+				   &kworld_tda18271_config);
+		}
+
+		/* mb86a20s need to use the I2C gateway */
+		break;
+	case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
+		fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
+					       &prohdtv_pro2_lgs8g75_config,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			dvb_attach(tda829x_attach, fe0->dvb.frontend,
+				   &dev->i2c_adap, 0x4b,
+				   &tda829x_no_probe);
+			dvb_attach(tda18271_attach, fe0->dvb.frontend,
+				   0x60, &dev->i2c_adap,
+				   &prohdtv_pro2_tda18271_config);
+		}
+		break;
+	default:
+		wprintk("Huh? unknown DVB card?\n");
+		break;
+	}
+
+	if (attach_xc3028) {
+		struct dvb_frontend *fe;
+		struct xc2028_config cfg = {
+			.i2c_adap  = &dev->i2c_adap,
+			.i2c_addr  = 0x61,
+		};
+
+		if (!fe0->dvb.frontend)
+			goto detach_frontend;
+
+		fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
+		if (!fe) {
+			printk(KERN_ERR "%s/2: xc3028 attach failed\n",
+			       dev->name);
+			goto detach_frontend;
+		}
+	}
+
+	if (NULL == fe0->dvb.frontend) {
+		printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name);
+		goto detach_frontend;
+	}
+	/* define general-purpose callback pointer */
+	fe0->dvb.frontend->callback = saa7134_tuner_callback;
+
+	/* register everything else */
+	ret = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
+					&dev->pci->dev, adapter_nr, 0);
+
+	/* this sequence is necessary to make the tda1004x load its firmware
+	 * and to enter analog mode of hybrid boards
+	 */
+	if (!ret) {
+		if (fe0->dvb.frontend->ops.init)
+			fe0->dvb.frontend->ops.init(fe0->dvb.frontend);
+		if (fe0->dvb.frontend->ops.sleep)
+			fe0->dvb.frontend->ops.sleep(fe0->dvb.frontend);
+		if (fe0->dvb.frontend->ops.tuner_ops.sleep)
+			fe0->dvb.frontend->ops.tuner_ops.sleep(fe0->dvb.frontend);
+	}
+	return ret;
+
+detach_frontend:
+	videobuf_dvb_dealloc_frontends(&dev->frontends);
+	return -EINVAL;
+}
+
+static int dvb_fini(struct saa7134_dev *dev)
+{
+	struct videobuf_dvb_frontend *fe0;
+
+	/* Get the first frontend */
+	fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+	if (!fe0)
+		return -EINVAL;
+
+	/* FIXME: I suspect that this code is bogus, since the entry for
+	   Pinnacle 300I DVB-T PAL already defines the proper init to allow
+	   the detection of mt2032 (TDA9887_PORT2_INACTIVE)
+	 */
+	if (dev->board == SAA7134_BOARD_PINNACLE_300I_DVBT_PAL) {
+		struct v4l2_priv_tun_config tda9887_cfg;
+		static int on  = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE;
+
+		tda9887_cfg.tuner = TUNER_TDA9887;
+		tda9887_cfg.priv  = &on;
+
+		/* otherwise we don't detect the tuner on next insmod */
+		saa_call_all(dev, tuner, s_config, &tda9887_cfg);
+	} else if (dev->board == SAA7134_BOARD_MEDION_MD8800_QUADRO) {
+		if ((dev->eedata[2] == 0x07) && use_frontend) {
+			/* turn off the 2nd lnb supply */
+			u8 data = 0x80;
+			struct i2c_msg msg = {.addr = 0x08, .buf = &data, .flags = 0, .len = 1};
+			struct dvb_frontend *fe;
+			fe = fe0->dvb.frontend;
+			if (fe->ops.i2c_gate_ctrl) {
+				fe->ops.i2c_gate_ctrl(fe, 1);
+				i2c_transfer(&dev->i2c_adap, &msg, 1);
+				fe->ops.i2c_gate_ctrl(fe, 0);
+			}
+		}
+	}
+	videobuf_dvb_unregister_bus(&dev->frontends);
+	return 0;
+}
+
+static struct saa7134_mpeg_ops dvb_ops = {
+	.type          = SAA7134_MPEG_DVB,
+	.init          = dvb_init,
+	.fini          = dvb_fini,
+};
+
+static int __init dvb_register(void)
+{
+	return saa7134_ts_register(&dvb_ops);
+}
+
+static void __exit dvb_unregister(void)
+{
+	saa7134_ts_unregister(&dvb_ops);
+}
+
+module_init(dvb_register);
+module_exit(dvb_unregister);
+
+/* ------------------------------------------------------------------ */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
new file mode 100644
index 0000000..dde361a
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
@@ -0,0 +1,590 @@
+/*
+ *
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+#include <media/saa6752hs.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+
+/* ------------------------------------------------------------------ */
+
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+static unsigned int empress_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(empress_nr, int, NULL, 0444);
+MODULE_PARM_DESC(empress_nr,"ts device number");
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages");
+
+#define dprintk(fmt, arg...)	if (debug)			\
+	printk(KERN_DEBUG "%s/empress: " fmt, dev->name , ## arg)
+
+/* ------------------------------------------------------------------ */
+
+static void ts_reset_encoder(struct saa7134_dev* dev)
+{
+	if (!dev->empress_started)
+		return;
+
+	saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
+	msleep(10);
+	saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+	msleep(100);
+	dev->empress_started = 0;
+}
+
+static int ts_init_encoder(struct saa7134_dev* dev)
+{
+	u32 leading_null_bytes = 0;
+
+	/* If more cards start to need this, then this
+	   should probably be added to the card definitions. */
+	switch (dev->board) {
+	case SAA7134_BOARD_BEHOLD_M6:
+	case SAA7134_BOARD_BEHOLD_M63:
+	case SAA7134_BOARD_BEHOLD_M6_EXTRA:
+		leading_null_bytes = 1;
+		break;
+	}
+	ts_reset_encoder(dev);
+	saa_call_all(dev, core, init, leading_null_bytes);
+	dev->empress_started = 1;
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int ts_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct saa7134_dev *dev = video_drvdata(file);
+	int err;
+
+	dprintk("open dev=%s\n", video_device_node_name(vdev));
+	err = -EBUSY;
+	if (!mutex_trylock(&dev->empress_tsq.vb_lock))
+		return err;
+	if (atomic_read(&dev->empress_users))
+		goto done;
+
+	/* Unmute audio */
+	saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+		saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
+
+	atomic_inc(&dev->empress_users);
+	file->private_data = dev;
+	err = 0;
+
+done:
+	mutex_unlock(&dev->empress_tsq.vb_lock);
+	return err;
+}
+
+static int ts_release(struct file *file)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	videobuf_stop(&dev->empress_tsq);
+	videobuf_mmap_free(&dev->empress_tsq);
+
+	/* stop the encoder */
+	ts_reset_encoder(dev);
+
+	/* Mute audio */
+	saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+		saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
+
+	atomic_dec(&dev->empress_users);
+
+	return 0;
+}
+
+static ssize_t
+ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	if (!dev->empress_started)
+		ts_init_encoder(dev);
+
+	return videobuf_read_stream(&dev->empress_tsq,
+				    data, count, ppos, 0,
+				    file->f_flags & O_NONBLOCK);
+}
+
+static unsigned int
+ts_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	return videobuf_poll_stream(file, &dev->empress_tsq, wait);
+}
+
+
+static int
+ts_mmap(struct file *file, struct vm_area_struct * vma)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	return videobuf_mmap_mapper(&dev->empress_tsq, vma);
+}
+
+/*
+ * This function is _not_ called directly, but from
+ * video_generic_ioctl (and maybe others).  userspace
+ * copying is done already, arg is a kernel pointer.
+ */
+
+static int empress_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *cap)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	strcpy(cap->driver, "saa7134");
+	strlcpy(cap->card, saa7134_boards[dev->board].name,
+		sizeof(cap->card));
+	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+	cap->capabilities =
+		V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_READWRITE |
+		V4L2_CAP_STREAMING;
+	return 0;
+}
+
+static int empress_enum_input(struct file *file, void *priv,
+					struct v4l2_input *i)
+{
+	if (i->index != 0)
+		return -EINVAL;
+
+	i->type = V4L2_INPUT_TYPE_CAMERA;
+	strcpy(i->name, "CCIR656");
+
+	return 0;
+}
+
+static int empress_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int empress_s_input(struct file *file, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int empress_enum_fmt_vid_cap(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	if (f->index != 0)
+		return -EINVAL;
+
+	strlcpy(f->description, "MPEG TS", sizeof(f->description));
+	f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+	return 0;
+}
+
+static int empress_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct saa7134_dev *dev = file->private_data;
+	struct v4l2_mbus_framefmt mbus_fmt;
+
+	saa_call_all(dev, video, g_mbus_fmt, &mbus_fmt);
+
+	v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
+
+	return 0;
+}
+
+static int empress_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct saa7134_dev *dev = file->private_data;
+	struct v4l2_mbus_framefmt mbus_fmt;
+
+	v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+	saa_call_all(dev, video, s_mbus_fmt, &mbus_fmt);
+	v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
+
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
+
+	return 0;
+}
+
+static int empress_try_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
+
+	return 0;
+}
+
+static int empress_reqbufs(struct file *file, void *priv,
+					struct v4l2_requestbuffers *p)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	return videobuf_reqbufs(&dev->empress_tsq, p);
+}
+
+static int empress_querybuf(struct file *file, void *priv,
+					struct v4l2_buffer *b)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	return videobuf_querybuf(&dev->empress_tsq, b);
+}
+
+static int empress_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	return videobuf_qbuf(&dev->empress_tsq, b);
+}
+
+static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	return videobuf_dqbuf(&dev->empress_tsq, b,
+				file->f_flags & O_NONBLOCK);
+}
+
+static int empress_streamon(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	return videobuf_streamon(&dev->empress_tsq);
+}
+
+static int empress_streamoff(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	return videobuf_streamoff(&dev->empress_tsq);
+}
+
+static int empress_s_ext_ctrls(struct file *file, void *priv,
+			       struct v4l2_ext_controls *ctrls)
+{
+	struct saa7134_dev *dev = file->private_data;
+	int err;
+
+	/* count == 0 is abused in saa6752hs.c, so that special
+		case is handled here explicitly. */
+	if (ctrls->count == 0)
+		return 0;
+
+	if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+		return -EINVAL;
+
+	err = saa_call_empress(dev, core, s_ext_ctrls, ctrls);
+	ts_init_encoder(dev);
+
+	return err;
+}
+
+static int empress_g_ext_ctrls(struct file *file, void *priv,
+			       struct v4l2_ext_controls *ctrls)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+		return -EINVAL;
+	return saa_call_empress(dev, core, g_ext_ctrls, ctrls);
+}
+
+static int empress_g_ctrl(struct file *file, void *priv,
+					struct v4l2_control *c)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	return saa7134_g_ctrl_internal(dev, NULL, c);
+}
+
+static int empress_s_ctrl(struct file *file, void *priv,
+					struct v4l2_control *c)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	return saa7134_s_ctrl_internal(dev, NULL, c);
+}
+
+static int empress_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *c)
+{
+	/* Must be sorted from low to high control ID! */
+	static const u32 user_ctrls[] = {
+		V4L2_CID_USER_CLASS,
+		V4L2_CID_BRIGHTNESS,
+		V4L2_CID_CONTRAST,
+		V4L2_CID_SATURATION,
+		V4L2_CID_HUE,
+		V4L2_CID_AUDIO_VOLUME,
+		V4L2_CID_AUDIO_MUTE,
+		V4L2_CID_HFLIP,
+		0
+	};
+
+	/* Must be sorted from low to high control ID! */
+	static const u32 mpeg_ctrls[] = {
+		V4L2_CID_MPEG_CLASS,
+		V4L2_CID_MPEG_STREAM_TYPE,
+		V4L2_CID_MPEG_STREAM_PID_PMT,
+		V4L2_CID_MPEG_STREAM_PID_AUDIO,
+		V4L2_CID_MPEG_STREAM_PID_VIDEO,
+		V4L2_CID_MPEG_STREAM_PID_PCR,
+		V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+		V4L2_CID_MPEG_AUDIO_ENCODING,
+		V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+		V4L2_CID_MPEG_VIDEO_ENCODING,
+		V4L2_CID_MPEG_VIDEO_ASPECT,
+		V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+		V4L2_CID_MPEG_VIDEO_BITRATE,
+		V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+		0
+	};
+	static const u32 *ctrl_classes[] = {
+		user_ctrls,
+		mpeg_ctrls,
+		NULL
+	};
+	struct saa7134_dev *dev = file->private_data;
+
+	c->id = v4l2_ctrl_next(ctrl_classes, c->id);
+	if (c->id == 0)
+		return -EINVAL;
+	if (c->id == V4L2_CID_USER_CLASS || c->id == V4L2_CID_MPEG_CLASS)
+		return v4l2_ctrl_query_fill(c, 0, 0, 0, 0);
+	if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG)
+		return saa7134_queryctrl(file, priv, c);
+	return saa_call_empress(dev, core, queryctrl, c);
+}
+
+static int empress_querymenu(struct file *file, void *priv,
+					struct v4l2_querymenu *c)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG)
+		return -EINVAL;
+	return saa_call_empress(dev, core, querymenu, c);
+}
+
+static int empress_g_chip_ident(struct file *file, void *fh,
+	       struct v4l2_dbg_chip_ident *chip)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	chip->ident = V4L2_IDENT_NONE;
+	chip->revision = 0;
+	if (chip->match.type == V4L2_CHIP_MATCH_I2C_DRIVER &&
+	    !strcmp(chip->match.name, "saa6752hs"))
+		return saa_call_empress(dev, core, g_chip_ident, chip);
+	if (chip->match.type == V4L2_CHIP_MATCH_I2C_ADDR)
+		return saa_call_empress(dev, core, g_chip_ident, chip);
+	return -EINVAL;
+}
+
+static int empress_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	return saa7134_s_std_internal(dev, NULL, id);
+}
+
+static int empress_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	*id = dev->tvnorm->id;
+	return 0;
+}
+
+static const struct v4l2_file_operations ts_fops =
+{
+	.owner	  = THIS_MODULE,
+	.open	  = ts_open,
+	.release  = ts_release,
+	.read	  = ts_read,
+	.poll	  = ts_poll,
+	.mmap	  = ts_mmap,
+	.ioctl	  = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops ts_ioctl_ops = {
+	.vidioc_querycap		= empress_querycap,
+	.vidioc_enum_fmt_vid_cap	= empress_enum_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap		= empress_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap		= empress_s_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap		= empress_g_fmt_vid_cap,
+	.vidioc_reqbufs			= empress_reqbufs,
+	.vidioc_querybuf		= empress_querybuf,
+	.vidioc_qbuf			= empress_qbuf,
+	.vidioc_dqbuf			= empress_dqbuf,
+	.vidioc_streamon		= empress_streamon,
+	.vidioc_streamoff		= empress_streamoff,
+	.vidioc_s_ext_ctrls		= empress_s_ext_ctrls,
+	.vidioc_g_ext_ctrls		= empress_g_ext_ctrls,
+	.vidioc_enum_input		= empress_enum_input,
+	.vidioc_g_input			= empress_g_input,
+	.vidioc_s_input			= empress_s_input,
+	.vidioc_queryctrl		= empress_queryctrl,
+	.vidioc_querymenu		= empress_querymenu,
+	.vidioc_g_ctrl			= empress_g_ctrl,
+	.vidioc_s_ctrl			= empress_s_ctrl,
+	.vidioc_g_chip_ident 		= empress_g_chip_ident,
+	.vidioc_s_std			= empress_s_std,
+	.vidioc_g_std			= empress_g_std,
+};
+
+/* ----------------------------------------------------------- */
+
+static struct video_device saa7134_empress_template = {
+	.name          = "saa7134-empress",
+	.fops          = &ts_fops,
+	.ioctl_ops     = &ts_ioctl_ops,
+
+	.tvnorms			= SAA7134_NORMS,
+	.current_norm			= V4L2_STD_PAL,
+};
+
+static void empress_signal_update(struct work_struct *work)
+{
+	struct saa7134_dev* dev =
+		container_of(work, struct saa7134_dev, empress_workqueue);
+
+	if (dev->nosignal) {
+		dprintk("no video signal\n");
+	} else {
+		dprintk("video signal acquired\n");
+	}
+}
+
+static void empress_signal_change(struct saa7134_dev *dev)
+{
+	schedule_work(&dev->empress_workqueue);
+}
+
+
+static int empress_init(struct saa7134_dev *dev)
+{
+	int err;
+
+	dprintk("%s: %s\n",dev->name,__func__);
+	dev->empress_dev = video_device_alloc();
+	if (NULL == dev->empress_dev)
+		return -ENOMEM;
+	*(dev->empress_dev) = saa7134_empress_template;
+	dev->empress_dev->parent  = &dev->pci->dev;
+	dev->empress_dev->release = video_device_release;
+	snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name),
+		 "%s empress (%s)", dev->name,
+		 saa7134_boards[dev->board].name);
+
+	INIT_WORK(&dev->empress_workqueue, empress_signal_update);
+
+	video_set_drvdata(dev->empress_dev, dev);
+	err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER,
+				    empress_nr[dev->nr]);
+	if (err < 0) {
+		printk(KERN_INFO "%s: can't register video device\n",
+		       dev->name);
+		video_device_release(dev->empress_dev);
+		dev->empress_dev = NULL;
+		return err;
+	}
+	printk(KERN_INFO "%s: registered device %s [mpeg]\n",
+	       dev->name, video_device_node_name(dev->empress_dev));
+
+	videobuf_queue_sg_init(&dev->empress_tsq, &saa7134_ts_qops,
+			    &dev->pci->dev, &dev->slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			    V4L2_FIELD_ALTERNATE,
+			    sizeof(struct saa7134_buf),
+			    dev, NULL);
+
+	empress_signal_update(&dev->empress_workqueue);
+	return 0;
+}
+
+static int empress_fini(struct saa7134_dev *dev)
+{
+	dprintk("%s: %s\n",dev->name,__func__);
+
+	if (NULL == dev->empress_dev)
+		return 0;
+	flush_work_sync(&dev->empress_workqueue);
+	video_unregister_device(dev->empress_dev);
+	dev->empress_dev = NULL;
+	return 0;
+}
+
+static struct saa7134_mpeg_ops empress_ops = {
+	.type          = SAA7134_MPEG_EMPRESS,
+	.init          = empress_init,
+	.fini          = empress_fini,
+	.signal_change = empress_signal_change,
+};
+
+static int __init empress_register(void)
+{
+	return saa7134_ts_register(&empress_ops);
+}
+
+static void __exit empress_unregister(void)
+{
+	saa7134_ts_unregister(&empress_ops);
+}
+
+module_init(empress_register);
+module_exit(empress_unregister);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c
new file mode 100644
index 0000000..a176ec3
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-i2c.c
@@ -0,0 +1,435 @@
+/*
+ *
+ * device driver for philips saa7134 based TV cards
+ * i2c interface support
+ *
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+#include <media/v4l2-common.h>
+
+/* ----------------------------------------------------------- */
+
+static unsigned int i2c_debug;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]");
+
+static unsigned int i2c_scan;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
+
+#define d1printk if (1 == i2c_debug) printk
+#define d2printk if (2 == i2c_debug) printk
+
+#define I2C_WAIT_DELAY  32
+#define I2C_WAIT_RETRY  16
+
+/* ----------------------------------------------------------- */
+
+static char *str_i2c_status[] = {
+	"IDLE", "DONE_STOP", "BUSY", "TO_SCL", "TO_ARB", "DONE_WRITE",
+	"DONE_READ", "DONE_WRITE_TO", "DONE_READ_TO", "NO_DEVICE",
+	"NO_ACKN", "BUS_ERR", "ARB_LOST", "SEQ_ERR", "ST_ERR", "SW_ERR"
+};
+
+enum i2c_status {
+	IDLE          = 0,  // no I2C command pending
+	DONE_STOP     = 1,  // I2C command done and STOP executed
+	BUSY          = 2,  // executing I2C command
+	TO_SCL        = 3,  // executing I2C command, time out on clock stretching
+	TO_ARB        = 4,  // time out on arbitration trial, still trying
+	DONE_WRITE    = 5,  // I2C command done and awaiting next write command
+	DONE_READ     = 6,  // I2C command done and awaiting next read command
+	DONE_WRITE_TO = 7,  // see 5, and time out on status echo
+	DONE_READ_TO  = 8,  // see 6, and time out on status echo
+	NO_DEVICE     = 9,  // no acknowledge on device slave address
+	NO_ACKN       = 10, // no acknowledge after data byte transfer
+	BUS_ERR       = 11, // bus error
+	ARB_LOST      = 12, // arbitration lost during transfer
+	SEQ_ERR       = 13, // erroneous programming sequence
+	ST_ERR        = 14, // wrong status echoing
+	SW_ERR        = 15  // software error
+};
+
+static char *str_i2c_attr[] = {
+	"NOP", "STOP", "CONTINUE", "START"
+};
+
+enum i2c_attr {
+	NOP           = 0,  // no operation on I2C bus
+	STOP          = 1,  // stop condition, no associated byte transfer
+	CONTINUE      = 2,  // continue with byte transfer
+	START         = 3   // start condition with byte transfer
+};
+
+static inline enum i2c_status i2c_get_status(struct saa7134_dev *dev)
+{
+	enum i2c_status status;
+
+	status = saa_readb(SAA7134_I2C_ATTR_STATUS) & 0x0f;
+	d2printk(KERN_DEBUG "%s: i2c stat <= %s\n",dev->name,
+		 str_i2c_status[status]);
+	return status;
+}
+
+static inline void i2c_set_status(struct saa7134_dev *dev,
+				  enum i2c_status status)
+{
+	d2printk(KERN_DEBUG "%s: i2c stat => %s\n",dev->name,
+		 str_i2c_status[status]);
+	saa_andorb(SAA7134_I2C_ATTR_STATUS,0x0f,status);
+}
+
+static inline void i2c_set_attr(struct saa7134_dev *dev, enum i2c_attr attr)
+{
+	d2printk(KERN_DEBUG "%s: i2c attr => %s\n",dev->name,
+		 str_i2c_attr[attr]);
+	saa_andorb(SAA7134_I2C_ATTR_STATUS,0xc0,attr << 6);
+}
+
+static inline int i2c_is_error(enum i2c_status status)
+{
+	switch (status) {
+	case NO_DEVICE:
+	case NO_ACKN:
+	case BUS_ERR:
+	case ARB_LOST:
+	case SEQ_ERR:
+	case ST_ERR:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static inline int i2c_is_idle(enum i2c_status status)
+{
+	switch (status) {
+	case IDLE:
+	case DONE_STOP:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static inline int i2c_is_busy(enum i2c_status status)
+{
+	switch (status) {
+	case BUSY:
+	case TO_SCL:
+	case TO_ARB:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int i2c_is_busy_wait(struct saa7134_dev *dev)
+{
+	enum i2c_status status;
+	int count;
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		status = i2c_get_status(dev);
+		if (!i2c_is_busy(status))
+			break;
+		saa_wait(I2C_WAIT_DELAY);
+	}
+	if (I2C_WAIT_RETRY == count)
+		return false;
+	return true;
+}
+
+static int i2c_reset(struct saa7134_dev *dev)
+{
+	enum i2c_status status;
+	int count;
+
+	d2printk(KERN_DEBUG "%s: i2c reset\n",dev->name);
+	status = i2c_get_status(dev);
+	if (!i2c_is_error(status))
+		return true;
+	i2c_set_status(dev,status);
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		status = i2c_get_status(dev);
+		if (!i2c_is_error(status))
+			break;
+		udelay(I2C_WAIT_DELAY);
+	}
+	if (I2C_WAIT_RETRY == count)
+		return false;
+
+	if (!i2c_is_idle(status))
+		return false;
+
+	i2c_set_attr(dev,NOP);
+	return true;
+}
+
+static inline int i2c_send_byte(struct saa7134_dev *dev,
+				enum i2c_attr attr,
+				unsigned char data)
+{
+	enum i2c_status status;
+	__u32 dword;
+
+	/* have to write both attr + data in one 32bit word */
+	dword  = saa_readl(SAA7134_I2C_ATTR_STATUS >> 2);
+	dword &= 0x0f;
+	dword |= (attr << 6);
+	dword |= ((__u32)data << 8);
+	dword |= 0x00 << 16;  /* 100 kHz */
+//	dword |= 0x40 << 16;  /* 400 kHz */
+	dword |= 0xf0 << 24;
+	saa_writel(SAA7134_I2C_ATTR_STATUS >> 2, dword);
+	d2printk(KERN_DEBUG "%s: i2c data => 0x%x\n",dev->name,data);
+
+	if (!i2c_is_busy_wait(dev))
+		return -EIO;
+	status = i2c_get_status(dev);
+	if (i2c_is_error(status))
+		return -EIO;
+	return 0;
+}
+
+static inline int i2c_recv_byte(struct saa7134_dev *dev)
+{
+	enum i2c_status status;
+	unsigned char data;
+
+	i2c_set_attr(dev,CONTINUE);
+	if (!i2c_is_busy_wait(dev))
+		return -EIO;
+	status = i2c_get_status(dev);
+	if (i2c_is_error(status))
+		return -EIO;
+	data = saa_readb(SAA7134_I2C_DATA);
+	d2printk(KERN_DEBUG "%s: i2c data <= 0x%x\n",dev->name,data);
+	return data;
+}
+
+static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
+			    struct i2c_msg *msgs, int num)
+{
+	struct saa7134_dev *dev = i2c_adap->algo_data;
+	enum i2c_status status;
+	unsigned char data;
+	int addr,rc,i,byte;
+
+	status = i2c_get_status(dev);
+	if (!i2c_is_idle(status))
+		if (!i2c_reset(dev))
+			return -EIO;
+
+	d2printk("start xfer\n");
+	d1printk(KERN_DEBUG "%s: i2c xfer:",dev->name);
+	for (i = 0; i < num; i++) {
+		if (!(msgs[i].flags & I2C_M_NOSTART) || 0 == i) {
+			/* send address */
+			d2printk("send address\n");
+			addr  = msgs[i].addr << 1;
+			if (msgs[i].flags & I2C_M_RD)
+				addr |= 1;
+			if (i > 0 && msgs[i].flags &
+			    I2C_M_RD && msgs[i].addr != 0x40 &&
+			    msgs[i].addr != 0x19) {
+				/* workaround for a saa7134 i2c bug
+				 * needed to talk to the mt352 demux
+				 * thanks to pinnacle for the hint */
+				int quirk = 0xfe;
+				d1printk(" [%02x quirk]",quirk);
+				i2c_send_byte(dev,START,quirk);
+				i2c_recv_byte(dev);
+			}
+			d1printk(" < %02x", addr);
+			rc = i2c_send_byte(dev,START,addr);
+			if (rc < 0)
+				 goto err;
+		}
+		if (msgs[i].flags & I2C_M_RD) {
+			/* read bytes */
+			d2printk("read bytes\n");
+			for (byte = 0; byte < msgs[i].len; byte++) {
+				d1printk(" =");
+				rc = i2c_recv_byte(dev);
+				if (rc < 0)
+					goto err;
+				d1printk("%02x", rc);
+				msgs[i].buf[byte] = rc;
+			}
+			/* discard mysterious extra byte when reading
+			   from Samsung S5H1411.  i2c bus gets error
+			   if we do not. */
+			if (0x19 == msgs[i].addr) {
+				d1printk(" ?");
+				rc = i2c_recv_byte(dev);
+				if (rc < 0)
+					goto err;
+				d1printk("%02x", rc);
+			}
+		} else {
+			/* write bytes */
+			d2printk("write bytes\n");
+			for (byte = 0; byte < msgs[i].len; byte++) {
+				data = msgs[i].buf[byte];
+				d1printk(" %02x", data);
+				rc = i2c_send_byte(dev,CONTINUE,data);
+				if (rc < 0)
+					goto err;
+			}
+		}
+	}
+	d2printk("xfer done\n");
+	d1printk(" >");
+	i2c_set_attr(dev,STOP);
+	rc = -EIO;
+	if (!i2c_is_busy_wait(dev))
+		goto err;
+	status = i2c_get_status(dev);
+	if (i2c_is_error(status))
+		goto err;
+	/* ensure that the bus is idle for at least one bit slot */
+	msleep(1);
+
+	d1printk("\n");
+	return num;
+ err:
+	if (1 == i2c_debug) {
+		status = i2c_get_status(dev);
+		printk(" ERROR: %s\n",str_i2c_status[status]);
+	}
+	return rc;
+}
+
+/* ----------------------------------------------------------- */
+
+static u32 functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm saa7134_algo = {
+	.master_xfer   = saa7134_i2c_xfer,
+	.functionality = functionality,
+};
+
+static struct i2c_adapter saa7134_adap_template = {
+	.owner         = THIS_MODULE,
+	.name          = "saa7134",
+	.algo          = &saa7134_algo,
+};
+
+static struct i2c_client saa7134_client_template = {
+	.name	= "saa7134 internal",
+};
+
+/* ----------------------------------------------------------- */
+
+static int
+saa7134_i2c_eeprom(struct saa7134_dev *dev, unsigned char *eedata, int len)
+{
+	unsigned char buf;
+	int i,err;
+
+	dev->i2c_client.addr = 0xa0 >> 1;
+	buf = 0;
+	if (1 != (err = i2c_master_send(&dev->i2c_client,&buf,1))) {
+		printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
+		       dev->name,err);
+		return -1;
+	}
+	if (len != (err = i2c_master_recv(&dev->i2c_client,eedata,len))) {
+		printk(KERN_WARNING "%s: i2c eeprom read error (err=%d)\n",
+		       dev->name,err);
+		return -1;
+	}
+	for (i = 0; i < len; i++) {
+		if (0 == (i % 16))
+			printk(KERN_INFO "%s: i2c eeprom %02x:",dev->name,i);
+		printk(" %02x",eedata[i]);
+		if (15 == (i % 16))
+			printk("\n");
+	}
+	return 0;
+}
+
+static char *i2c_devs[128] = {
+	[ 0x20      ] = "mpeg encoder (saa6752hs)",
+	[ 0xa0 >> 1 ] = "eeprom",
+	[ 0xc0 >> 1 ] = "tuner (analog)",
+	[ 0x86 >> 1 ] = "tda9887",
+	[ 0x5a >> 1 ] = "remote control",
+};
+
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+	unsigned char buf;
+	int i,rc;
+
+	for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
+		c->addr = i;
+		rc = i2c_master_recv(c,&buf,0);
+		if (rc < 0)
+			continue;
+		printk("%s: i2c scan: found device @ 0x%x  [%s]\n",
+		       name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+	}
+}
+
+int saa7134_i2c_register(struct saa7134_dev *dev)
+{
+	dev->i2c_adap = saa7134_adap_template;
+	dev->i2c_adap.dev.parent = &dev->pci->dev;
+	strcpy(dev->i2c_adap.name,dev->name);
+	dev->i2c_adap.algo_data = dev;
+	i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
+	i2c_add_adapter(&dev->i2c_adap);
+
+	dev->i2c_client = saa7134_client_template;
+	dev->i2c_client.adapter = &dev->i2c_adap;
+
+	saa7134_i2c_eeprom(dev,dev->eedata,sizeof(dev->eedata));
+	if (i2c_scan)
+		do_i2c_scan(dev->name,&dev->i2c_client);
+
+	/* Instantiate the IR receiver device, if present */
+	saa7134_probe_i2c_ir(dev);
+	return 0;
+}
+
+int saa7134_i2c_unregister(struct saa7134_dev *dev)
+{
+	i2c_del_adapter(&dev->i2c_adap);
+	return 0;
+}
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c
new file mode 100644
index 0000000..0f78f5e
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-input.c
@@ -0,0 +1,1041 @@
+/*
+ *
+ * handle saa7134 IR remotes via linux kernel input layer.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+#define MODULE_NAME "saa7134"
+
+static unsigned int disable_ir;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
+
+static unsigned int ir_debug;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+
+static int pinnacle_remote;
+module_param(pinnacle_remote, int, 0644);    /* Choose Pinnacle PCTV remote */
+MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)");
+
+#define dprintk(fmt, arg...)	if (ir_debug) \
+	printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
+#define i2cdprintk(fmt, arg...)    if (ir_debug) \
+	printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg)
+
+/* Helper function for raw decoding at GPIO16 or GPIO18 */
+static int saa7134_raw_decode_irq(struct saa7134_dev *dev);
+
+/* -------------------- GPIO generic keycode builder -------------------- */
+
+static int build_key(struct saa7134_dev *dev)
+{
+	struct saa7134_card_ir *ir = dev->remote;
+	u32 gpio, data;
+
+	/* here comes the additional handshake steps for some cards */
+	switch (dev->board) {
+	case SAA7134_BOARD_GOTVIEW_7135:
+		saa_setb(SAA7134_GPIO_GPSTATUS1, 0x80);
+		saa_clearb(SAA7134_GPIO_GPSTATUS1, 0x80);
+		break;
+	}
+	/* rising SAA7134_GPIO_GPRESCAN reads the status */
+	saa_clearb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
+	saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
+
+	gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+	if (ir->polling) {
+		if (ir->last_gpio == gpio)
+			return 0;
+		ir->last_gpio = gpio;
+	}
+
+	data = ir_extract_bits(gpio, ir->mask_keycode);
+	dprintk("build_key gpio=0x%x mask=0x%x data=%d\n",
+		gpio, ir->mask_keycode, data);
+
+	switch (dev->board) {
+	case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
+		if (data == ir->mask_keycode)
+			rc_keyup(ir->dev);
+		else
+			rc_keydown_notimeout(ir->dev, data, 0);
+		return 0;
+	}
+
+	if (ir->polling) {
+		if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
+		    (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
+			rc_keydown_notimeout(ir->dev, data, 0);
+		} else {
+			rc_keyup(ir->dev);
+		}
+	}
+	else {	/* IRQ driven mode - handle key press and release in one go */
+		if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
+		    (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
+			rc_keydown_notimeout(ir->dev, data, 0);
+			rc_keyup(ir->dev);
+		}
+	}
+
+	return 0;
+}
+
+/* --------------------- Chip specific I2C key builders ----------------- */
+
+static int get_key_flydvb_trio(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	int gpio;
+	int attempt = 0;
+	unsigned char b;
+
+	/* We need this to access GPI Used by the saa_readl macro. */
+	struct saa7134_dev *dev = ir->c->adapter->algo_data;
+
+	if (dev == NULL) {
+		i2cdprintk("get_key_flydvb_trio: "
+			   "ir->c->adapter->algo_data is NULL!\n");
+		return -EIO;
+	}
+
+	/* rising SAA7134_GPIGPRESCAN reads the status */
+	saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+	saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+	gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+
+	if (0x40000 & ~gpio)
+		return 0; /* No button press */
+
+	/* No button press - only before first key pressed */
+	if (b == 0xFF)
+		return 0;
+
+	/* poll IR chip */
+	/* weak up the IR chip */
+	b = 0;
+
+	while (1 != i2c_master_send(ir->c, &b, 1)) {
+		if ((attempt++) < 10) {
+			/*
+			 * wait a bit for next attempt -
+			 * I don't know how make it better
+			 */
+			msleep(10);
+			continue;
+		}
+		i2cdprintk("send wake up byte to pic16C505 (IR chip)"
+			   "failed %dx\n", attempt);
+		return -EIO;
+	}
+	if (1 != i2c_master_recv(ir->c, &b, 1)) {
+		i2cdprintk("read error\n");
+		return -EIO;
+	}
+
+	*ir_key = b;
+	*ir_raw = b;
+	return 1;
+}
+
+static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
+				       u32 *ir_raw)
+{
+	unsigned char b;
+	int gpio;
+
+	/* <dev> is needed to access GPIO. Used by the saa_readl macro. */
+	struct saa7134_dev *dev = ir->c->adapter->algo_data;
+	if (dev == NULL) {
+		i2cdprintk("get_key_msi_tvanywhere_plus: "
+			   "ir->c->adapter->algo_data is NULL!\n");
+		return -EIO;
+	}
+
+	/* rising SAA7134_GPIO_GPRESCAN reads the status */
+
+	saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+	saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+	gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+
+	/* GPIO&0x40 is pulsed low when a button is pressed. Don't do
+	   I2C receive if gpio&0x40 is not low. */
+
+	if (gpio & 0x40)
+		return 0;       /* No button press */
+
+	/* GPIO says there is a button press. Get it. */
+
+	if (1 != i2c_master_recv(ir->c, &b, 1)) {
+		i2cdprintk("read error\n");
+		return -EIO;
+	}
+
+	/* No button press */
+
+	if (b == 0xff)
+		return 0;
+
+	/* Button pressed */
+
+	dprintk("get_key_msi_tvanywhere_plus: Key = 0x%02X\n", b);
+	*ir_key = b;
+	*ir_raw = b;
+	return 1;
+}
+
+/* copied and modified from get_key_msi_tvanywhere_plus() */
+static int get_key_kworld_pc150u(struct IR_i2c *ir, u32 *ir_key,
+					u32 *ir_raw)
+{
+	unsigned char b;
+	unsigned int gpio;
+
+	/* <dev> is needed to access GPIO. Used by the saa_readl macro. */
+	struct saa7134_dev *dev = ir->c->adapter->algo_data;
+	if (dev == NULL) {
+		i2cdprintk("get_key_kworld_pc150u: "
+			   "ir->c->adapter->algo_data is NULL!\n");
+		return -EIO;
+	}
+
+	/* rising SAA7134_GPIO_GPRESCAN reads the status */
+
+	saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+	saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+	gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+
+	/* GPIO&0x100 is pulsed low when a button is pressed. Don't do
+	   I2C receive if gpio&0x100 is not low. */
+
+	if (gpio & 0x100)
+		return 0;       /* No button press */
+
+	/* GPIO says there is a button press. Get it. */
+
+	if (1 != i2c_master_recv(ir->c, &b, 1)) {
+		i2cdprintk("read error\n");
+		return -EIO;
+	}
+
+	/* No button press */
+
+	if (b == 0xff)
+		return 0;
+
+	/* Button pressed */
+
+	dprintk("get_key_kworld_pc150u: Key = 0x%02X\n", b);
+	*ir_key = b;
+	*ir_raw = b;
+	return 1;
+}
+
+static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char b;
+
+	/* poll IR chip */
+	if (1 != i2c_master_recv(ir->c, &b, 1)) {
+		i2cdprintk("read error\n");
+		return -EIO;
+	}
+
+	/* no button press */
+	if (b==0)
+		return 0;
+
+	/* repeating */
+	if (b & 0x80)
+		return 1;
+
+	*ir_key = b;
+	*ir_raw = b;
+	return 1;
+}
+
+static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char buf[5];
+
+	/* poll IR chip */
+	if (5 != i2c_master_recv(ir->c, buf, 5))
+		return -EIO;
+
+	/* Check if some key were pressed */
+	if (!(buf[0] & 0x80))
+		return 0;
+
+	/*
+	 * buf[3] & 0x80 is always high.
+	 * buf[3] & 0x40 is a parity bit. A repeat event is marked
+	 * by preserving it into two separate readings
+	 * buf[4] bits 0 and 1, and buf[1] and buf[2] are always
+	 * zero.
+	 */
+	*ir_key = 0x1fff & ((buf[3] << 8) | (buf[4] >> 2));
+	*ir_raw = *ir_key;
+	return 1;
+}
+
+
+static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char data[12];
+	u32 gpio;
+
+	struct saa7134_dev *dev = ir->c->adapter->algo_data;
+
+	/* rising SAA7134_GPIO_GPRESCAN reads the status */
+	saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+	saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+	gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+
+	if (0x400000 & ~gpio)
+		return 0; /* No button press */
+
+	ir->c->addr = 0x5a >> 1;
+
+	if (12 != i2c_master_recv(ir->c, data, 12)) {
+		i2cdprintk("read error\n");
+		return -EIO;
+	}
+
+	if (data[9] != (unsigned char)(~data[8]))
+		return 0;
+
+	*ir_raw = ((data[10] << 16) | (data[11] << 8) | (data[9] << 0));
+	*ir_key = *ir_raw;
+
+	return 1;
+}
+
+/* Common (grey or coloured) pinnacle PCTV remote handling
+ *
+ */
+static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
+			    int parity_offset, int marker, int code_modulo)
+{
+	unsigned char b[4];
+	unsigned int start = 0,parity = 0,code = 0;
+
+	/* poll IR chip */
+	if (4 != i2c_master_recv(ir->c, b, 4)) {
+		i2cdprintk("read error\n");
+		return -EIO;
+	}
+
+	for (start = 0; start < ARRAY_SIZE(b); start++) {
+		if (b[start] == marker) {
+			code=b[(start+parity_offset + 1) % 4];
+			parity=b[(start+parity_offset) % 4];
+		}
+	}
+
+	/* Empty Request */
+	if (parity == 0)
+		return 0;
+
+	/* Repeating... */
+	if (ir->old == parity)
+		return 0;
+
+	ir->old = parity;
+
+	/* drop special codes when a key is held down a long time for the grey controller
+	   In this case, the second bit of the code is asserted */
+	if (marker == 0xfe && (code & 0x40))
+		return 0;
+
+	code %= code_modulo;
+
+	*ir_raw = code;
+	*ir_key = code;
+
+	i2cdprintk("Pinnacle PCTV key %02x\n", code);
+
+	return 1;
+}
+
+/* The grey pinnacle PCTV remote
+ *
+ *  There are one issue with this remote:
+ *   - I2c packet does not change when the same key is pressed quickly. The workaround
+ *     is to hold down each key for about half a second, so that another code is generated
+ *     in the i2c packet, and the function can distinguish key presses.
+ *
+ * Sylvain Pasche <sylvain.pasche@gmail.com>
+ */
+static int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+
+	return get_key_pinnacle(ir, ir_key, ir_raw, 1, 0xfe, 0xff);
+}
+
+
+/* The new pinnacle PCTV remote (with the colored buttons)
+ *
+ * Ricardo Cerqueira <v4l@cerqueira.org>
+ */
+static int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	/* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE
+	 *
+	 * this is the only value that results in 42 unique
+	 * codes < 128
+	 */
+
+	return get_key_pinnacle(ir, ir_key, ir_raw, 2, 0x80, 0x88);
+}
+
+void saa7134_input_irq(struct saa7134_dev *dev)
+{
+	struct saa7134_card_ir *ir;
+
+	if (!dev || !dev->remote)
+		return;
+
+	ir = dev->remote;
+	if (!ir->running)
+		return;
+
+	if (!ir->polling && !ir->raw_decode) {
+		build_key(dev);
+	} else if (ir->raw_decode) {
+		saa7134_raw_decode_irq(dev);
+	}
+}
+
+static void saa7134_input_timer(unsigned long data)
+{
+	struct saa7134_dev *dev = (struct saa7134_dev *)data;
+	struct saa7134_card_ir *ir = dev->remote;
+
+	build_key(dev);
+	mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
+}
+
+static void ir_raw_decode_timer_end(unsigned long data)
+{
+	struct saa7134_dev *dev = (struct saa7134_dev *)data;
+
+	ir_raw_event_handle(dev->remote->dev);
+}
+
+static int __saa7134_ir_start(void *priv)
+{
+	struct saa7134_dev *dev = priv;
+	struct saa7134_card_ir *ir;
+
+	if (!dev || !dev->remote)
+		return -EINVAL;
+
+	ir  = dev->remote;
+	if (ir->running)
+		return 0;
+
+	/* Moved here from saa7134_input_init1() because the latter
+	 * is not called on device resume */
+	switch (dev->board) {
+	case SAA7134_BOARD_MD2819:
+	case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
+	case SAA7134_BOARD_AVERMEDIA_305:
+	case SAA7134_BOARD_AVERMEDIA_307:
+	case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+	case SAA7134_BOARD_AVERMEDIA_STUDIO_505:
+	case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
+	case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
+	case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA:
+	case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
+	case SAA7134_BOARD_AVERMEDIA_M102:
+	case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
+		/* Without this we won't receive key up events */
+		saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
+		saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
+		break;
+	case SAA7134_BOARD_AVERMEDIA_777:
+	case SAA7134_BOARD_AVERMEDIA_A16AR:
+		/* Without this we won't receive key up events */
+		saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
+		saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
+		break;
+	case SAA7134_BOARD_AVERMEDIA_A16D:
+		/* Without this we won't receive key up events */
+		saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
+		saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
+		break;
+	case SAA7134_BOARD_GOTVIEW_7135:
+		saa_setb(SAA7134_GPIO_GPMODE1, 0x80);
+		break;
+	}
+
+	ir->running = true;
+
+	if (ir->polling) {
+		setup_timer(&ir->timer, saa7134_input_timer,
+			    (unsigned long)dev);
+		ir->timer.expires = jiffies + HZ;
+		add_timer(&ir->timer);
+	} else if (ir->raw_decode) {
+		/* set timer_end for code completion */
+		setup_timer(&ir->timer, ir_raw_decode_timer_end,
+			    (unsigned long)dev);
+	}
+
+	return 0;
+}
+
+static void __saa7134_ir_stop(void *priv)
+{
+	struct saa7134_dev *dev = priv;
+	struct saa7134_card_ir *ir;
+
+	if (!dev || !dev->remote)
+		return;
+
+	ir  = dev->remote;
+	if (!ir->running)
+		return;
+
+	if (ir->polling || ir->raw_decode)
+		del_timer_sync(&ir->timer);
+
+	ir->running = false;
+
+	return;
+}
+
+int saa7134_ir_start(struct saa7134_dev *dev)
+{
+	if (dev->remote->users)
+		return __saa7134_ir_start(dev);
+
+	return 0;
+}
+
+void saa7134_ir_stop(struct saa7134_dev *dev)
+{
+	if (dev->remote->users)
+		__saa7134_ir_stop(dev);
+}
+
+static int saa7134_ir_open(struct rc_dev *rc)
+{
+	struct saa7134_dev *dev = rc->priv;
+
+	dev->remote->users++;
+	return __saa7134_ir_start(dev);
+}
+
+static void saa7134_ir_close(struct rc_dev *rc)
+{
+	struct saa7134_dev *dev = rc->priv;
+
+	dev->remote->users--;
+	if (!dev->remote->users)
+		__saa7134_ir_stop(dev);
+}
+
+int saa7134_input_init1(struct saa7134_dev *dev)
+{
+	struct saa7134_card_ir *ir;
+	struct rc_dev *rc;
+	char *ir_codes = NULL;
+	u32 mask_keycode = 0;
+	u32 mask_keydown = 0;
+	u32 mask_keyup   = 0;
+	unsigned polling = 0;
+	bool raw_decode  = false;
+	int err;
+
+	if (dev->has_remote != SAA7134_REMOTE_GPIO)
+		return -ENODEV;
+	if (disable_ir)
+		return -ENODEV;
+
+	/* detect & configure */
+	switch (dev->board) {
+	case SAA7134_BOARD_FLYVIDEO2000:
+	case SAA7134_BOARD_FLYVIDEO3000:
+	case SAA7134_BOARD_FLYTVPLATINUM_FM:
+	case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
+	case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM:
+		ir_codes     = RC_MAP_FLYVIDEO;
+		mask_keycode = 0xEC00000;
+		mask_keydown = 0x0040000;
+		break;
+	case SAA7134_BOARD_CINERGY400:
+	case SAA7134_BOARD_CINERGY600:
+	case SAA7134_BOARD_CINERGY600_MK3:
+		ir_codes     = RC_MAP_CINERGY;
+		mask_keycode = 0x00003f;
+		mask_keyup   = 0x040000;
+		break;
+	case SAA7134_BOARD_ECS_TVP3XP:
+	case SAA7134_BOARD_ECS_TVP3XP_4CB5:
+		ir_codes     = RC_MAP_EZTV;
+		mask_keycode = 0x00017c;
+		mask_keyup   = 0x000002;
+		polling      = 50; // ms
+		break;
+	case SAA7134_BOARD_KWORLD_XPERT:
+	case SAA7134_BOARD_AVACSSMARTTV:
+		ir_codes     = RC_MAP_PIXELVIEW;
+		mask_keycode = 0x00001F;
+		mask_keyup   = 0x000020;
+		polling      = 50; // ms
+		break;
+	case SAA7134_BOARD_MD2819:
+	case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
+	case SAA7134_BOARD_AVERMEDIA_305:
+	case SAA7134_BOARD_AVERMEDIA_307:
+	case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+	case SAA7134_BOARD_AVERMEDIA_STUDIO_505:
+	case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
+	case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
+	case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA:
+	case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
+	case SAA7134_BOARD_AVERMEDIA_M102:
+	case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
+		ir_codes     = RC_MAP_AVERMEDIA;
+		mask_keycode = 0x0007C8;
+		mask_keydown = 0x000010;
+		polling      = 50; // ms
+		/* GPIO stuff moved to __saa7134_ir_start() */
+		break;
+	case SAA7134_BOARD_AVERMEDIA_M135A:
+		ir_codes     = RC_MAP_AVERMEDIA_M135A;
+		mask_keydown = 0x0040000;	/* Enable GPIO18 line on both edges */
+		mask_keyup   = 0x0040000;
+		mask_keycode = 0xffff;
+		raw_decode   = true;
+		break;
+	case SAA7134_BOARD_AVERMEDIA_M733A:
+		ir_codes     = RC_MAP_AVERMEDIA_M733A_RM_K6;
+		mask_keydown = 0x0040000;
+		mask_keyup   = 0x0040000;
+		mask_keycode = 0xffff;
+		raw_decode   = true;
+		break;
+	case SAA7134_BOARD_AVERMEDIA_777:
+	case SAA7134_BOARD_AVERMEDIA_A16AR:
+		ir_codes     = RC_MAP_AVERMEDIA;
+		mask_keycode = 0x02F200;
+		mask_keydown = 0x000400;
+		polling      = 50; // ms
+		/* GPIO stuff moved to __saa7134_ir_start() */
+		break;
+	case SAA7134_BOARD_AVERMEDIA_A16D:
+		ir_codes     = RC_MAP_AVERMEDIA_A16D;
+		mask_keycode = 0x02F200;
+		mask_keydown = 0x000400;
+		polling      = 50; /* ms */
+		/* GPIO stuff moved to __saa7134_ir_start() */
+		break;
+	case SAA7134_BOARD_KWORLD_TERMINATOR:
+		ir_codes     = RC_MAP_PIXELVIEW;
+		mask_keycode = 0x00001f;
+		mask_keyup   = 0x000060;
+		polling      = 50; // ms
+		break;
+	case SAA7134_BOARD_MANLI_MTV001:
+	case SAA7134_BOARD_MANLI_MTV002:
+		ir_codes     = RC_MAP_MANLI;
+		mask_keycode = 0x001f00;
+		mask_keyup   = 0x004000;
+		polling      = 50; /* ms */
+		break;
+	case SAA7134_BOARD_BEHOLD_409FM:
+	case SAA7134_BOARD_BEHOLD_401:
+	case SAA7134_BOARD_BEHOLD_403:
+	case SAA7134_BOARD_BEHOLD_403FM:
+	case SAA7134_BOARD_BEHOLD_405:
+	case SAA7134_BOARD_BEHOLD_405FM:
+	case SAA7134_BOARD_BEHOLD_407:
+	case SAA7134_BOARD_BEHOLD_407FM:
+	case SAA7134_BOARD_BEHOLD_409:
+	case SAA7134_BOARD_BEHOLD_505FM:
+	case SAA7134_BOARD_BEHOLD_505RDS_MK5:
+	case SAA7134_BOARD_BEHOLD_505RDS_MK3:
+	case SAA7134_BOARD_BEHOLD_507_9FM:
+	case SAA7134_BOARD_BEHOLD_507RDS_MK3:
+	case SAA7134_BOARD_BEHOLD_507RDS_MK5:
+		ir_codes     = RC_MAP_MANLI;
+		mask_keycode = 0x003f00;
+		mask_keyup   = 0x004000;
+		polling      = 50; /* ms */
+		break;
+	case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+		ir_codes     = RC_MAP_BEHOLD_COLUMBUS;
+		mask_keycode = 0x003f00;
+		mask_keyup   = 0x004000;
+		polling      = 50; // ms
+		break;
+	case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
+		ir_codes     = RC_MAP_PCTV_SEDNA;
+		mask_keycode = 0x001f00;
+		mask_keyup   = 0x004000;
+		polling      = 50; // ms
+		break;
+	case SAA7134_BOARD_GOTVIEW_7135:
+		ir_codes     = RC_MAP_GOTVIEW7135;
+		mask_keycode = 0x0003CC;
+		mask_keydown = 0x000010;
+		polling	     = 5; /* ms */
+		/* GPIO stuff moved to __saa7134_ir_start() */
+		break;
+	case SAA7134_BOARD_VIDEOMATE_TV_PVR:
+	case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
+	case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
+		ir_codes     = RC_MAP_VIDEOMATE_TV_PVR;
+		mask_keycode = 0x00003F;
+		mask_keyup   = 0x400000;
+		polling      = 50; // ms
+		break;
+	case SAA7134_BOARD_PROTEUS_2309:
+		ir_codes     = RC_MAP_PROTEUS_2309;
+		mask_keycode = 0x00007F;
+		mask_keyup   = 0x000080;
+		polling      = 50; // ms
+		break;
+	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+	case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+		ir_codes     = RC_MAP_VIDEOMATE_TV_PVR;
+		mask_keycode = 0x003F00;
+		mask_keyup   = 0x040000;
+		break;
+	case SAA7134_BOARD_FLYDVBS_LR300:
+	case SAA7134_BOARD_FLYDVBT_LR301:
+	case SAA7134_BOARD_FLYDVBTDUO:
+		ir_codes     = RC_MAP_FLYDVB;
+		mask_keycode = 0x0001F00;
+		mask_keydown = 0x0040000;
+		break;
+	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
+	case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
+		ir_codes     = RC_MAP_ASUS_PC39;
+		mask_keydown = 0x0040000;	/* Enable GPIO18 line on both edges */
+		mask_keyup   = 0x0040000;
+		mask_keycode = 0xffff;
+		raw_decode   = true;
+		break;
+	case SAA7134_BOARD_ASUSTeK_PS3_100:
+		ir_codes     = RC_MAP_ASUS_PS3_100;
+		mask_keydown = 0x0040000;
+		mask_keyup   = 0x0040000;
+		mask_keycode = 0xffff;
+		raw_decode   = true;
+		break;
+	case SAA7134_BOARD_ENCORE_ENLTV:
+	case SAA7134_BOARD_ENCORE_ENLTV_FM:
+		ir_codes     = RC_MAP_ENCORE_ENLTV;
+		mask_keycode = 0x00007f;
+		mask_keyup   = 0x040000;
+		polling      = 50; // ms
+		break;
+	case SAA7134_BOARD_ENCORE_ENLTV_FM53:
+	case SAA7134_BOARD_ENCORE_ENLTV_FM3:
+		ir_codes     = RC_MAP_ENCORE_ENLTV_FM53;
+		mask_keydown = 0x0040000;	/* Enable GPIO18 line on both edges */
+		mask_keyup   = 0x0040000;
+		mask_keycode = 0xffff;
+		raw_decode   = true;
+		break;
+	case SAA7134_BOARD_10MOONSTVMASTER3:
+		ir_codes     = RC_MAP_ENCORE_ENLTV;
+		mask_keycode = 0x5f80000;
+		mask_keyup   = 0x8000000;
+		polling      = 50; //ms
+		break;
+	case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
+		ir_codes     = RC_MAP_GENIUS_TVGO_A11MCE;
+		mask_keycode = 0xff;
+		mask_keydown = 0xf00000;
+		polling = 50; /* ms */
+		break;
+	case SAA7134_BOARD_REAL_ANGEL_220:
+		ir_codes     = RC_MAP_REAL_AUDIO_220_32_KEYS;
+		mask_keycode = 0x3f00;
+		mask_keyup   = 0x4000;
+		polling = 50; /* ms */
+		break;
+	case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
+		ir_codes     = RC_MAP_KWORLD_PLUS_TV_ANALOG;
+		mask_keycode = 0x7f;
+		polling = 40; /* ms */
+		break;
+	case SAA7134_BOARD_VIDEOMATE_S350:
+		ir_codes     = RC_MAP_VIDEOMATE_S350;
+		mask_keycode = 0x003f00;
+		mask_keydown = 0x040000;
+		break;
+	case SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S:
+		ir_codes     = RC_MAP_WINFAST;
+		mask_keycode = 0x5f00;
+		mask_keyup   = 0x020000;
+		polling      = 50; /* ms */
+		break;
+	case SAA7134_BOARD_VIDEOMATE_M1F:
+		ir_codes     = RC_MAP_VIDEOMATE_K100;
+		mask_keycode = 0x0ff00;
+		mask_keyup   = 0x040000;
+		break;
+	case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+	case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+		ir_codes     = RC_MAP_HAUPPAUGE;
+		mask_keydown = 0x0040000;	/* Enable GPIO18 line on both edges */
+		mask_keyup   = 0x0040000;
+		mask_keycode = 0xffff;
+		raw_decode   = true;
+		break;
+	}
+	if (NULL == ir_codes) {
+		printk("%s: Oops: IR config error [card=%d]\n",
+		       dev->name, dev->board);
+		return -ENODEV;
+	}
+
+	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+	rc = rc_allocate_device();
+	if (!ir || !rc) {
+		err = -ENOMEM;
+		goto err_out_free;
+	}
+
+	ir->dev = rc;
+	dev->remote = ir;
+
+	/* init hardware-specific stuff */
+	ir->mask_keycode = mask_keycode;
+	ir->mask_keydown = mask_keydown;
+	ir->mask_keyup   = mask_keyup;
+	ir->polling      = polling;
+	ir->raw_decode	 = raw_decode;
+
+	/* init input device */
+	snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
+		 saa7134_boards[dev->board].name);
+	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
+		 pci_name(dev->pci));
+
+	rc->priv = dev;
+	rc->open = saa7134_ir_open;
+	rc->close = saa7134_ir_close;
+	if (raw_decode)
+		rc->driver_type = RC_DRIVER_IR_RAW;
+
+	rc->input_name = ir->name;
+	rc->input_phys = ir->phys;
+	rc->input_id.bustype = BUS_PCI;
+	rc->input_id.version = 1;
+	if (dev->pci->subsystem_vendor) {
+		rc->input_id.vendor  = dev->pci->subsystem_vendor;
+		rc->input_id.product = dev->pci->subsystem_device;
+	} else {
+		rc->input_id.vendor  = dev->pci->vendor;
+		rc->input_id.product = dev->pci->device;
+	}
+	rc->dev.parent = &dev->pci->dev;
+	rc->map_name = ir_codes;
+	rc->driver_name = MODULE_NAME;
+
+	err = rc_register_device(rc);
+	if (err)
+		goto err_out_free;
+
+	return 0;
+
+err_out_free:
+	rc_free_device(rc);
+	dev->remote = NULL;
+	kfree(ir);
+	return err;
+}
+
+void saa7134_input_fini(struct saa7134_dev *dev)
+{
+	if (NULL == dev->remote)
+		return;
+
+	saa7134_ir_stop(dev);
+	rc_unregister_device(dev->remote->dev);
+	kfree(dev->remote);
+	dev->remote = NULL;
+}
+
+void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
+{
+	struct i2c_board_info info;
+	struct i2c_msg msg_msi = {
+		.addr = 0x50,
+		.flags = I2C_M_RD,
+		.len = 0,
+		.buf = NULL,
+	};
+	int rc;
+
+	if (disable_ir) {
+		dprintk("IR has been disabled, not probing for i2c remote\n");
+		return;
+	}
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	memset(&dev->init_data, 0, sizeof(dev->init_data));
+	strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+
+	switch (dev->board) {
+	case SAA7134_BOARD_PINNACLE_PCTV_110i:
+	case SAA7134_BOARD_PINNACLE_PCTV_310i:
+		dev->init_data.name = "Pinnacle PCTV";
+		if (pinnacle_remote == 0) {
+			dev->init_data.get_key = get_key_pinnacle_color;
+			dev->init_data.ir_codes = RC_MAP_PINNACLE_COLOR;
+			info.addr = 0x47;
+		} else {
+			dev->init_data.get_key = get_key_pinnacle_grey;
+			dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY;
+			info.addr = 0x47;
+		}
+		break;
+	case SAA7134_BOARD_UPMOST_PURPLE_TV:
+		dev->init_data.name = "Purple TV";
+		dev->init_data.get_key = get_key_purpletv;
+		dev->init_data.ir_codes = RC_MAP_PURPLETV;
+		info.addr = 0x7a;
+		break;
+	case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
+		dev->init_data.name = "MSI TV@nywhere Plus";
+		dev->init_data.get_key = get_key_msi_tvanywhere_plus;
+		dev->init_data.ir_codes = RC_MAP_MSI_TVANYWHERE_PLUS;
+		/*
+		 * MSI TV@nyware Plus requires more frequent polling
+		 * otherwise it will miss some keypresses
+		 */
+		dev->init_data.polling_interval = 50;
+		info.addr = 0x30;
+		/* MSI TV@nywhere Plus controller doesn't seem to
+		   respond to probes unless we read something from
+		   an existing device. Weird...
+		   REVISIT: might no longer be needed */
+		rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1);
+		dprintk("probe 0x%02x @ %s: %s\n",
+			msg_msi.addr, dev->i2c_adap.name,
+			(1 == rc) ? "yes" : "no");
+		break;
+	case SAA7134_BOARD_KWORLD_PC150U:
+		/* copied and modified from MSI TV@nywhere Plus */
+		dev->init_data.name = "Kworld PC150-U";
+		dev->init_data.get_key = get_key_kworld_pc150u;
+		dev->init_data.ir_codes = RC_MAP_KWORLD_PC150U;
+		info.addr = 0x30;
+		/* MSI TV@nywhere Plus controller doesn't seem to
+		   respond to probes unless we read something from
+		   an existing device. Weird...
+		   REVISIT: might no longer be needed */
+		rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1);
+		dprintk("probe 0x%02x @ %s: %s\n",
+			msg_msi.addr, dev->i2c_adap.name,
+			(1 == rc) ? "yes" : "no");
+		break;
+	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+		dev->init_data.name = "HVR 1110";
+		dev->init_data.get_key = get_key_hvr1110;
+		dev->init_data.ir_codes = RC_MAP_HAUPPAUGE;
+		info.addr = 0x71;
+		break;
+	case SAA7134_BOARD_BEHOLD_607FM_MK3:
+	case SAA7134_BOARD_BEHOLD_607FM_MK5:
+	case SAA7134_BOARD_BEHOLD_609FM_MK3:
+	case SAA7134_BOARD_BEHOLD_609FM_MK5:
+	case SAA7134_BOARD_BEHOLD_607RDS_MK3:
+	case SAA7134_BOARD_BEHOLD_607RDS_MK5:
+	case SAA7134_BOARD_BEHOLD_609RDS_MK3:
+	case SAA7134_BOARD_BEHOLD_609RDS_MK5:
+	case SAA7134_BOARD_BEHOLD_M6:
+	case SAA7134_BOARD_BEHOLD_M63:
+	case SAA7134_BOARD_BEHOLD_M6_EXTRA:
+	case SAA7134_BOARD_BEHOLD_H6:
+	case SAA7134_BOARD_BEHOLD_X7:
+	case SAA7134_BOARD_BEHOLD_H7:
+	case SAA7134_BOARD_BEHOLD_A7:
+		dev->init_data.name = "BeholdTV";
+		dev->init_data.get_key = get_key_beholdm6xx;
+		dev->init_data.ir_codes = RC_MAP_BEHOLD;
+		dev->init_data.type = RC_TYPE_NEC;
+		info.addr = 0x2d;
+		break;
+	case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
+	case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+		info.addr = 0x40;
+		break;
+	case SAA7134_BOARD_FLYDVB_TRIO:
+		dev->init_data.name = "FlyDVB Trio";
+		dev->init_data.get_key = get_key_flydvb_trio;
+		dev->init_data.ir_codes = RC_MAP_FLYDVB;
+		info.addr = 0x0b;
+		break;
+	default:
+		dprintk("No I2C IR support for board %x\n", dev->board);
+		return;
+	}
+
+	if (dev->init_data.name)
+		info.platform_data = &dev->init_data;
+	i2c_new_device(&dev->i2c_adap, &info);
+}
+
+static int saa7134_raw_decode_irq(struct saa7134_dev *dev)
+{
+	struct saa7134_card_ir *ir = dev->remote;
+	unsigned long timeout;
+	int space;
+
+	/* Generate initial event */
+	saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+	saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+	space = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown;
+	ir_raw_event_store_edge(dev->remote->dev, space ? IR_SPACE : IR_PULSE);
+
+	/*
+	 * Wait 15 ms from the start of the first IR event before processing
+	 * the event. This time is enough for NEC protocol. May need adjustments
+	 * to work with other protocols.
+	 */
+	smp_mb();
+
+	if (!timer_pending(&ir->timer)) {
+		timeout = jiffies + msecs_to_jiffies(15);
+		mod_timer(&ir->timer, timeout);
+	}
+
+	return 1;
+}
diff --git a/drivers/media/pci/saa7134/saa7134-reg.h b/drivers/media/pci/saa7134/saa7134-reg.h
new file mode 100644
index 0000000..e7e0af1
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-reg.h
@@ -0,0 +1,378 @@
+/*
+ *
+ * philips saa7134 registers
+ */
+
+/* ------------------------------------------------------------------ */
+/*
+ * PCI ID's
+ */
+#ifndef PCI_DEVICE_ID_PHILIPS_SAA7130
+# define PCI_DEVICE_ID_PHILIPS_SAA7130 0x7130
+#endif
+#ifndef PCI_DEVICE_ID_PHILIPS_SAA7133
+# define PCI_DEVICE_ID_PHILIPS_SAA7133 0x7133
+#endif
+#ifndef PCI_DEVICE_ID_PHILIPS_SAA7134
+# define PCI_DEVICE_ID_PHILIPS_SAA7134 0x7134
+#endif
+#ifndef PCI_DEVICE_ID_PHILIPS_SAA7135
+# define PCI_DEVICE_ID_PHILIPS_SAA7135 0x7135
+#endif
+
+/* ------------------------------------------------------------------ */
+/*
+ *  registers -- 32 bit
+ */
+
+/* DMA channels, n = 0 ... 6 */
+#define SAA7134_RS_BA1(n)			((0x200 >> 2) + 4*n)
+#define SAA7134_RS_BA2(n)			((0x204 >> 2) + 4*n)
+#define SAA7134_RS_PITCH(n)			((0x208 >> 2) + 4*n)
+#define SAA7134_RS_CONTROL(n)			((0x20c >> 2) + 4*n)
+#define   SAA7134_RS_CONTROL_WSWAP		(0x01 << 25)
+#define   SAA7134_RS_CONTROL_BSWAP		(0x01 << 24)
+#define   SAA7134_RS_CONTROL_BURST_2		(0x01 << 21)
+#define   SAA7134_RS_CONTROL_BURST_4		(0x02 << 21)
+#define   SAA7134_RS_CONTROL_BURST_8		(0x03 << 21)
+#define   SAA7134_RS_CONTROL_BURST_16		(0x04 << 21)
+#define   SAA7134_RS_CONTROL_BURST_32		(0x05 << 21)
+#define   SAA7134_RS_CONTROL_BURST_64		(0x06 << 21)
+#define   SAA7134_RS_CONTROL_BURST_MAX		(0x07 << 21)
+#define   SAA7134_RS_CONTROL_ME			(0x01 << 20)
+#define SAA7134_FIFO_SIZE                       (0x2a0 >> 2)
+#define SAA7134_THRESHOULD                      (0x2a4 >> 2)
+
+#define SAA7133_NUM_SAMPLES			(0x588 >> 2)
+#define SAA7133_AUDIO_CHANNEL			(0x58c >> 2)
+#define SAA7133_AUDIO_FORMAT			(0x58f >> 2)
+#define SAA7133_DIGITAL_OUTPUT_SEL1		(0x46c >> 2)
+#define SAA7133_DIGITAL_OUTPUT_SEL2		(0x470 >> 2)
+#define SAA7133_DIGITAL_INPUT_XBAR1		(0x464 >> 2)
+#define SAA7133_ANALOG_IO_SELECT                (0x594 >> 2)
+
+/* main control */
+#define SAA7134_MAIN_CTRL                       (0x2a8 >> 2)
+#define   SAA7134_MAIN_CTRL_VPLLE		(1 << 15)
+#define   SAA7134_MAIN_CTRL_APLLE		(1 << 14)
+#define   SAA7134_MAIN_CTRL_EXOSC		(1 << 13)
+#define   SAA7134_MAIN_CTRL_EVFE1		(1 << 12)
+#define   SAA7134_MAIN_CTRL_EVFE2		(1 << 11)
+#define   SAA7134_MAIN_CTRL_ESFE		(1 << 10)
+#define   SAA7134_MAIN_CTRL_EBADC		(1 << 9)
+#define   SAA7134_MAIN_CTRL_EBDAC		(1 << 8)
+#define   SAA7134_MAIN_CTRL_TE6			(1 << 6)
+#define   SAA7134_MAIN_CTRL_TE5			(1 << 5)
+#define   SAA7134_MAIN_CTRL_TE4			(1 << 4)
+#define   SAA7134_MAIN_CTRL_TE3			(1 << 3)
+#define   SAA7134_MAIN_CTRL_TE2			(1 << 2)
+#define   SAA7134_MAIN_CTRL_TE1			(1 << 1)
+#define   SAA7134_MAIN_CTRL_TE0			(1 << 0)
+
+/* DMA status */
+#define SAA7134_DMA_STATUS                      (0x2ac >> 2)
+
+/* audio / video status */
+#define SAA7134_AV_STATUS			(0x2c0 >> 2)
+#define   SAA7134_AV_STATUS_STEREO		(1 << 17)
+#define   SAA7134_AV_STATUS_DUAL                (1 << 16)
+#define   SAA7134_AV_STATUS_PILOT               (1 << 15)
+#define   SAA7134_AV_STATUS_SMB                 (1 << 14)
+#define   SAA7134_AV_STATUS_DMB                 (1 << 13)
+#define   SAA7134_AV_STATUS_VDSP                (1 << 12)
+#define   SAA7134_AV_STATUS_IIC_STATUS          (3 << 10)
+#define   SAA7134_AV_STATUS_MVM                 (7 << 7)
+#define   SAA7134_AV_STATUS_FIDT                (1 << 6)
+#define   SAA7134_AV_STATUS_INTL                (1 << 5)
+#define   SAA7134_AV_STATUS_RDCAP               (1 << 4)
+#define   SAA7134_AV_STATUS_PWR_ON              (1 << 3)
+#define   SAA7134_AV_STATUS_LOAD_ERR            (1 << 2)
+#define   SAA7134_AV_STATUS_TRIG_ERR            (1 << 1)
+#define   SAA7134_AV_STATUS_CONF_ERR            (1 << 0)
+
+/* interrupt */
+#define SAA7134_IRQ1                            (0x2c4 >> 2)
+#define   SAA7134_IRQ1_INTE_RA3_1               (1 << 25)
+#define   SAA7134_IRQ1_INTE_RA3_0               (1 << 24)
+#define   SAA7134_IRQ1_INTE_RA2_3               (1 << 19)
+#define   SAA7134_IRQ1_INTE_RA2_2               (1 << 18)
+#define   SAA7134_IRQ1_INTE_RA2_1               (1 << 17)
+#define   SAA7134_IRQ1_INTE_RA2_0               (1 << 16)
+#define   SAA7134_IRQ1_INTE_RA1_3               (1 << 11)
+#define   SAA7134_IRQ1_INTE_RA1_2               (1 << 10)
+#define   SAA7134_IRQ1_INTE_RA1_1               (1 <<  9)
+#define   SAA7134_IRQ1_INTE_RA1_0               (1 <<  8)
+#define   SAA7134_IRQ1_INTE_RA0_7               (1 <<  7)
+#define   SAA7134_IRQ1_INTE_RA0_6               (1 <<  6)
+#define   SAA7134_IRQ1_INTE_RA0_5               (1 <<  5)
+#define   SAA7134_IRQ1_INTE_RA0_4               (1 <<  4)
+#define   SAA7134_IRQ1_INTE_RA0_3               (1 <<  3)
+#define   SAA7134_IRQ1_INTE_RA0_2               (1 <<  2)
+#define   SAA7134_IRQ1_INTE_RA0_1               (1 <<  1)
+#define   SAA7134_IRQ1_INTE_RA0_0               (1 <<  0)
+
+#define SAA7134_IRQ2                            (0x2c8 >> 2)
+#define   SAA7134_IRQ2_INTE_GPIO23_N             (1 << 17)	/* negative edge */
+#define   SAA7134_IRQ2_INTE_GPIO23_P             (1 << 16)	/* positive edge */
+#define   SAA7134_IRQ2_INTE_GPIO22_N             (1 << 15)	/* negative edge */
+#define   SAA7134_IRQ2_INTE_GPIO22_P             (1 << 14)	/* positive edge */
+#define   SAA7134_IRQ2_INTE_GPIO18_N             (1 << 13)	/* negative edge */
+#define   SAA7134_IRQ2_INTE_GPIO18_P             (1 << 12)	/* positive edge */
+#define   SAA7134_IRQ2_INTE_GPIO16_N             (1 << 11)	/* negative edge */
+#define   SAA7134_IRQ2_INTE_GPIO16_P             (1 << 10)	/* positive edge */
+#define   SAA7134_IRQ2_INTE_SC2                 (1 <<  9)
+#define   SAA7134_IRQ2_INTE_SC1                 (1 <<  8)
+#define   SAA7134_IRQ2_INTE_SC0                 (1 <<  7)
+#define   SAA7134_IRQ2_INTE_DEC4                (1 <<  6)
+#define   SAA7134_IRQ2_INTE_DEC3                (1 <<  5)
+#define   SAA7134_IRQ2_INTE_DEC2                (1 <<  4)
+#define   SAA7134_IRQ2_INTE_DEC1                (1 <<  3)
+#define   SAA7134_IRQ2_INTE_DEC0                (1 <<  2)
+#define   SAA7134_IRQ2_INTE_PE                  (1 <<  1)
+#define   SAA7134_IRQ2_INTE_AR                  (1 <<  0)
+
+#define SAA7134_IRQ_REPORT                      (0x2cc >> 2)
+#define   SAA7134_IRQ_REPORT_GPIO23             (1 << 17)
+#define   SAA7134_IRQ_REPORT_GPIO22             (1 << 16)
+#define   SAA7134_IRQ_REPORT_GPIO18             (1 << 15)
+#define   SAA7134_IRQ_REPORT_GPIO16             (1 << 14)
+#define   SAA7134_IRQ_REPORT_LOAD_ERR           (1 << 13)
+#define   SAA7134_IRQ_REPORT_CONF_ERR           (1 << 12)
+#define   SAA7134_IRQ_REPORT_TRIG_ERR           (1 << 11)
+#define   SAA7134_IRQ_REPORT_MMC                (1 << 10)
+#define   SAA7134_IRQ_REPORT_FIDT               (1 <<  9)
+#define   SAA7134_IRQ_REPORT_INTL               (1 <<  8)
+#define   SAA7134_IRQ_REPORT_RDCAP              (1 <<  7)
+#define   SAA7134_IRQ_REPORT_PWR_ON             (1 <<  6)
+#define   SAA7134_IRQ_REPORT_PE                 (1 <<  5)
+#define   SAA7134_IRQ_REPORT_AR                 (1 <<  4)
+#define   SAA7134_IRQ_REPORT_DONE_RA3           (1 <<  3)
+#define   SAA7134_IRQ_REPORT_DONE_RA2           (1 <<  2)
+#define   SAA7134_IRQ_REPORT_DONE_RA1           (1 <<  1)
+#define   SAA7134_IRQ_REPORT_DONE_RA0           (1 <<  0)
+#define SAA7134_IRQ_STATUS                      (0x2d0 >> 2)
+
+
+/* ------------------------------------------------------------------ */
+/*
+ *  registers -- 8 bit
+ */
+
+/* video decoder */
+#define SAA7134_INCR_DELAY                      0x101
+#define SAA7134_ANALOG_IN_CTRL1                 0x102
+#define SAA7134_ANALOG_IN_CTRL2                 0x103
+#define SAA7134_ANALOG_IN_CTRL3                 0x104
+#define SAA7134_ANALOG_IN_CTRL4                 0x105
+#define SAA7134_HSYNC_START                     0x106
+#define SAA7134_HSYNC_STOP                      0x107
+#define SAA7134_SYNC_CTRL                       0x108
+#define SAA7134_LUMA_CTRL                       0x109
+#define SAA7134_DEC_LUMA_BRIGHT                 0x10a
+#define SAA7134_DEC_LUMA_CONTRAST               0x10b
+#define SAA7134_DEC_CHROMA_SATURATION           0x10c
+#define SAA7134_DEC_CHROMA_HUE                  0x10d
+#define SAA7134_CHROMA_CTRL1                    0x10e
+#define SAA7134_CHROMA_GAIN                     0x10f
+#define SAA7134_CHROMA_CTRL2                    0x110
+#define SAA7134_MODE_DELAY_CTRL                 0x111
+
+#define SAA7134_ANALOG_ADC                      0x114
+#define SAA7134_VGATE_START                     0x115
+#define SAA7134_VGATE_STOP                      0x116
+#define SAA7134_MISC_VGATE_MSB                  0x117
+#define SAA7134_RAW_DATA_GAIN                   0x118
+#define SAA7134_RAW_DATA_OFFSET                 0x119
+#define SAA7134_STATUS_VIDEO1                   0x11e
+#define SAA7134_STATUS_VIDEO2                   0x11f
+
+/* video scaler */
+#define SAA7134_SOURCE_TIMING1                  0x000
+#define SAA7134_SOURCE_TIMING2                  0x001
+#define SAA7134_REGION_ENABLE                   0x004
+#define SAA7134_SCALER_STATUS0                  0x006
+#define SAA7134_SCALER_STATUS1                  0x007
+#define SAA7134_START_GREEN                     0x00c
+#define SAA7134_START_BLUE                      0x00d
+#define SAA7134_START_RED                       0x00e
+#define SAA7134_GREEN_PATH(x)                   (0x010 +x)
+#define SAA7134_BLUE_PATH(x)                    (0x020 +x)
+#define SAA7134_RED_PATH(x)                     (0x030 +x)
+
+#define TASK_A                                  0x040
+#define TASK_B                                  0x080
+#define SAA7134_TASK_CONDITIONS(t)              (0x000 +t)
+#define SAA7134_FIELD_HANDLING(t)               (0x001 +t)
+#define SAA7134_DATA_PATH(t)                    (0x002 +t)
+#define SAA7134_VBI_H_START1(t)                 (0x004 +t)
+#define SAA7134_VBI_H_START2(t)                 (0x005 +t)
+#define SAA7134_VBI_H_STOP1(t)                  (0x006 +t)
+#define SAA7134_VBI_H_STOP2(t)                  (0x007 +t)
+#define SAA7134_VBI_V_START1(t)                 (0x008 +t)
+#define SAA7134_VBI_V_START2(t)                 (0x009 +t)
+#define SAA7134_VBI_V_STOP1(t)                  (0x00a +t)
+#define SAA7134_VBI_V_STOP2(t)                  (0x00b +t)
+#define SAA7134_VBI_H_LEN1(t)                   (0x00c +t)
+#define SAA7134_VBI_H_LEN2(t)                   (0x00d +t)
+#define SAA7134_VBI_V_LEN1(t)                   (0x00e +t)
+#define SAA7134_VBI_V_LEN2(t)                   (0x00f +t)
+
+#define SAA7134_VIDEO_H_START1(t)               (0x014 +t)
+#define SAA7134_VIDEO_H_START2(t)               (0x015 +t)
+#define SAA7134_VIDEO_H_STOP1(t)                (0x016 +t)
+#define SAA7134_VIDEO_H_STOP2(t)                (0x017 +t)
+#define SAA7134_VIDEO_V_START1(t)               (0x018 +t)
+#define SAA7134_VIDEO_V_START2(t)               (0x019 +t)
+#define SAA7134_VIDEO_V_STOP1(t)                (0x01a +t)
+#define SAA7134_VIDEO_V_STOP2(t)                (0x01b +t)
+#define SAA7134_VIDEO_PIXELS1(t)                (0x01c +t)
+#define SAA7134_VIDEO_PIXELS2(t)                (0x01d +t)
+#define SAA7134_VIDEO_LINES1(t)                 (0x01e +t)
+#define SAA7134_VIDEO_LINES2(t)                 (0x01f +t)
+
+#define SAA7134_H_PRESCALE(t)                   (0x020 +t)
+#define SAA7134_ACC_LENGTH(t)                   (0x021 +t)
+#define SAA7134_LEVEL_CTRL(t)                   (0x022 +t)
+#define SAA7134_FIR_PREFILTER_CTRL(t)           (0x023 +t)
+#define SAA7134_LUMA_BRIGHT(t)                  (0x024 +t)
+#define SAA7134_LUMA_CONTRAST(t)                (0x025 +t)
+#define SAA7134_CHROMA_SATURATION(t)            (0x026 +t)
+#define SAA7134_VBI_H_SCALE_INC1(t)             (0x028 +t)
+#define SAA7134_VBI_H_SCALE_INC2(t)             (0x029 +t)
+#define SAA7134_VBI_PHASE_OFFSET_LUMA(t)        (0x02a +t)
+#define SAA7134_VBI_PHASE_OFFSET_CHROMA(t)      (0x02b +t)
+#define SAA7134_H_SCALE_INC1(t)                 (0x02c +t)
+#define SAA7134_H_SCALE_INC2(t)                 (0x02d +t)
+#define SAA7134_H_PHASE_OFF_LUMA(t)             (0x02e +t)
+#define SAA7134_H_PHASE_OFF_CHROMA(t)           (0x02f +t)
+#define SAA7134_V_SCALE_RATIO1(t)               (0x030 +t)
+#define SAA7134_V_SCALE_RATIO2(t)               (0x031 +t)
+#define SAA7134_V_FILTER(t)                     (0x032 +t)
+#define SAA7134_V_PHASE_OFFSET0(t)              (0x034 +t)
+#define SAA7134_V_PHASE_OFFSET1(t)              (0x035 +t)
+#define SAA7134_V_PHASE_OFFSET2(t)              (0x036 +t)
+#define SAA7134_V_PHASE_OFFSET3(t)              (0x037 +t)
+
+/* clipping & dma */
+#define SAA7134_OFMT_VIDEO_A                    0x300
+#define SAA7134_OFMT_DATA_A                     0x301
+#define SAA7134_OFMT_VIDEO_B                    0x302
+#define SAA7134_OFMT_DATA_B                     0x303
+#define SAA7134_ALPHA_NOCLIP                    0x304
+#define SAA7134_ALPHA_CLIP                      0x305
+#define SAA7134_UV_PIXEL                        0x308
+#define SAA7134_CLIP_RED                        0x309
+#define SAA7134_CLIP_GREEN                      0x30a
+#define SAA7134_CLIP_BLUE                       0x30b
+
+/* i2c bus */
+#define SAA7134_I2C_ATTR_STATUS                 0x180
+#define SAA7134_I2C_DATA                        0x181
+#define SAA7134_I2C_CLOCK_SELECT                0x182
+#define SAA7134_I2C_TIMER                       0x183
+
+/* audio */
+#define SAA7134_NICAM_ADD_DATA1                 0x140
+#define SAA7134_NICAM_ADD_DATA2                 0x141
+#define SAA7134_NICAM_STATUS                    0x142
+#define SAA7134_AUDIO_STATUS                    0x143
+#define SAA7134_NICAM_ERROR_COUNT               0x144
+#define SAA7134_IDENT_SIF                       0x145
+#define SAA7134_LEVEL_READOUT1                  0x146
+#define SAA7134_LEVEL_READOUT2                  0x147
+#define SAA7134_NICAM_ERROR_LOW                 0x148
+#define SAA7134_NICAM_ERROR_HIGH                0x149
+#define SAA7134_DCXO_IDENT_CTRL                 0x14a
+#define SAA7134_DEMODULATOR                     0x14b
+#define SAA7134_AGC_GAIN_SELECT                 0x14c
+#define SAA7134_CARRIER1_FREQ0                  0x150
+#define SAA7134_CARRIER1_FREQ1                  0x151
+#define SAA7134_CARRIER1_FREQ2                  0x152
+#define SAA7134_CARRIER2_FREQ0                  0x154
+#define SAA7134_CARRIER2_FREQ1                  0x155
+#define SAA7134_CARRIER2_FREQ2                  0x156
+#define SAA7134_NUM_SAMPLES0                    0x158
+#define SAA7134_NUM_SAMPLES1                    0x159
+#define SAA7134_NUM_SAMPLES2                    0x15a
+#define SAA7134_AUDIO_FORMAT_CTRL               0x15b
+#define SAA7134_MONITOR_SELECT                  0x160
+#define SAA7134_FM_DEEMPHASIS                   0x161
+#define SAA7134_FM_DEMATRIX                     0x162
+#define SAA7134_CHANNEL1_LEVEL                  0x163
+#define SAA7134_CHANNEL2_LEVEL                  0x164
+#define SAA7134_NICAM_CONFIG                    0x165
+#define SAA7134_NICAM_LEVEL_ADJUST              0x166
+#define SAA7134_STEREO_DAC_OUTPUT_SELECT        0x167
+#define SAA7134_I2S_OUTPUT_FORMAT               0x168
+#define SAA7134_I2S_OUTPUT_SELECT               0x169
+#define SAA7134_I2S_OUTPUT_LEVEL                0x16a
+#define SAA7134_DSP_OUTPUT_SELECT               0x16b
+#define SAA7134_AUDIO_MUTE_CTRL                 0x16c
+#define SAA7134_SIF_SAMPLE_FREQ                 0x16d
+#define SAA7134_ANALOG_IO_SELECT                0x16e
+#define SAA7134_AUDIO_CLOCK0                    0x170
+#define SAA7134_AUDIO_CLOCK1                    0x171
+#define SAA7134_AUDIO_CLOCK2                    0x172
+#define SAA7134_AUDIO_PLL_CTRL                  0x173
+#define SAA7134_AUDIO_CLOCKS_PER_FIELD0         0x174
+#define SAA7134_AUDIO_CLOCKS_PER_FIELD1         0x175
+#define SAA7134_AUDIO_CLOCKS_PER_FIELD2         0x176
+
+/* video port output */
+#define SAA7134_VIDEO_PORT_CTRL0                0x190
+#define SAA7134_VIDEO_PORT_CTRL1                0x191
+#define SAA7134_VIDEO_PORT_CTRL2                0x192
+#define SAA7134_VIDEO_PORT_CTRL3                0x193
+#define SAA7134_VIDEO_PORT_CTRL4                0x194
+#define SAA7134_VIDEO_PORT_CTRL5                0x195
+#define SAA7134_VIDEO_PORT_CTRL6                0x196
+#define SAA7134_VIDEO_PORT_CTRL7                0x197
+#define SAA7134_VIDEO_PORT_CTRL8                0x198
+
+/* transport stream interface */
+#define SAA7134_TS_PARALLEL                     0x1a0
+#define SAA7134_TS_PARALLEL_SERIAL              0x1a1
+#define SAA7134_TS_SERIAL0                      0x1a2
+#define SAA7134_TS_SERIAL1                      0x1a3
+#define SAA7134_TS_DMA0                         0x1a4
+#define SAA7134_TS_DMA1                         0x1a5
+#define SAA7134_TS_DMA2                         0x1a6
+
+/* GPIO Controls */
+#define SAA7134_GPIO_GPRESCAN                   0x80
+#define SAA7134_GPIO_27_25                      0x0E
+
+#define SAA7134_GPIO_GPMODE0                    0x1B0
+#define SAA7134_GPIO_GPMODE1                    0x1B1
+#define SAA7134_GPIO_GPMODE2                    0x1B2
+#define SAA7134_GPIO_GPMODE3                    0x1B3
+#define SAA7134_GPIO_GPSTATUS0                  0x1B4
+#define SAA7134_GPIO_GPSTATUS1                  0x1B5
+#define SAA7134_GPIO_GPSTATUS2                  0x1B6
+#define SAA7134_GPIO_GPSTATUS3                  0x1B7
+
+/* I2S output */
+#define SAA7134_I2S_AUDIO_OUTPUT                0x1c0
+
+/* test modes */
+#define SAA7134_SPECIAL_MODE                    0x1d0
+#define SAA7134_PRODUCTION_TEST_MODE            0x1d1
+
+/* audio -- saa7133 + saa7135 only */
+#define SAA7135_DSP_RWSTATE                     0x580
+#define SAA7135_DSP_RWSTATE_ERR                 (1 << 3)
+#define SAA7135_DSP_RWSTATE_IDA                 (1 << 2)
+#define SAA7135_DSP_RWSTATE_RDB                 (1 << 1)
+#define SAA7135_DSP_RWSTATE_WRR                 (1 << 0)
+
+#define SAA7135_DSP_RWCLEAR			0x586
+#define SAA7135_DSP_RWCLEAR_RERR		    1
+
+#define SAA7133_I2S_AUDIO_CONTROL               0x591
+/* ------------------------------------------------------------------ */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/drivers/media/pci/saa7134/saa7134-ts.c b/drivers/media/pci/saa7134/saa7134-ts.c
new file mode 100644
index 0000000..2e3f4b4
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-ts.c
@@ -0,0 +1,327 @@
+/*
+ *
+ * device driver for philips saa7134 based TV cards
+ * video4linux video interface
+ *
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int ts_debug;
+module_param(ts_debug, int, 0644);
+MODULE_PARM_DESC(ts_debug,"enable debug messages [ts]");
+
+#define dprintk(fmt, arg...)	if (ts_debug) \
+	printk(KERN_DEBUG "%s/ts: " fmt, dev->name , ## arg)
+
+/* ------------------------------------------------------------------ */
+
+static int buffer_activate(struct saa7134_dev *dev,
+			   struct saa7134_buf *buf,
+			   struct saa7134_buf *next)
+{
+
+	dprintk("buffer_activate [%p]",buf);
+	buf->vb.state = VIDEOBUF_ACTIVE;
+	buf->top_seen = 0;
+
+	if (NULL == next)
+		next = buf;
+	if (V4L2_FIELD_TOP == buf->vb.field) {
+		dprintk("- [top]     buf=%p next=%p\n",buf,next);
+		saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(buf));
+		saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(next));
+	} else {
+		dprintk("- [bottom]  buf=%p next=%p\n",buf,next);
+		saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next));
+		saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf));
+	}
+
+	/* start DMA */
+	saa7134_set_dmabits(dev);
+
+	mod_timer(&dev->ts_q.timeout, jiffies+TS_BUFFER_TIMEOUT);
+
+	if (!dev->ts_started)
+		saa7134_ts_start(dev);
+
+	return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+		enum v4l2_field field)
+{
+	struct saa7134_dev *dev = q->priv_data;
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+	unsigned int lines, llength, size;
+	int err;
+
+	dprintk("buffer_prepare [%p,%s]\n",buf,v4l2_field_names[field]);
+
+	llength = TS_PACKET_SIZE;
+	lines = dev->ts.nr_packets;
+
+	size = lines * llength;
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+		return -EINVAL;
+
+	if (buf->vb.size != size) {
+		saa7134_dma_free(q,buf);
+	}
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+
+		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
+		dprintk("buffer_prepare: needs_init\n");
+
+		buf->vb.width  = llength;
+		buf->vb.height = lines;
+		buf->vb.size   = size;
+		buf->pt        = &dev->ts.pt_ts;
+
+		err = videobuf_iolock(q,&buf->vb,NULL);
+		if (err)
+			goto oops;
+		err = saa7134_pgtable_build(dev->pci,buf->pt,
+					    dma->sglist,
+					    dma->sglen,
+					    saa7134_buffer_startpage(buf));
+		if (err)
+			goto oops;
+	}
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	buf->activate = buffer_activate;
+	buf->vb.field = field;
+	return 0;
+
+ oops:
+	saa7134_dma_free(q,buf);
+	return err;
+}
+
+static int
+buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+	struct saa7134_dev *dev = q->priv_data;
+
+	*size = TS_PACKET_SIZE * dev->ts.nr_packets;
+	if (0 == *count)
+		*count = dev->ts.nr_bufs;
+	*count = saa7134_buffer_count(*size,*count);
+
+	return 0;
+}
+
+static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct saa7134_dev *dev = q->priv_data;
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+
+	saa7134_buffer_queue(dev,&dev->ts_q,buf);
+}
+
+static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+	struct saa7134_dev *dev = q->priv_data;
+
+	if (dev->ts_started)
+		saa7134_ts_stop(dev);
+
+	saa7134_dma_free(q,buf);
+}
+
+struct videobuf_queue_ops saa7134_ts_qops = {
+	.buf_setup    = buffer_setup,
+	.buf_prepare  = buffer_prepare,
+	.buf_queue    = buffer_queue,
+	.buf_release  = buffer_release,
+};
+EXPORT_SYMBOL_GPL(saa7134_ts_qops);
+
+/* ----------------------------------------------------------- */
+/* exported stuff                                              */
+
+static unsigned int tsbufs = 8;
+module_param(tsbufs, int, 0444);
+MODULE_PARM_DESC(tsbufs, "number of ts buffers for read/write IO, range 2-32");
+
+static unsigned int ts_nr_packets = 64;
+module_param(ts_nr_packets, int, 0444);
+MODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)");
+
+int saa7134_ts_init_hw(struct saa7134_dev *dev)
+{
+	/* deactivate TS softreset */
+	saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+	/* TSSOP high active, TSVAL high active, TSLOCK ignored */
+	saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
+	saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1));
+	saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff));
+	saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff));
+	/* TSNOPIT=0, TSCOLAP=0 */
+	saa_writeb(SAA7134_TS_DMA2,
+		((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00));
+
+	return 0;
+}
+
+int saa7134_ts_init1(struct saa7134_dev *dev)
+{
+	/* sanitycheck insmod options */
+	if (tsbufs < 2)
+		tsbufs = 2;
+	if (tsbufs > VIDEO_MAX_FRAME)
+		tsbufs = VIDEO_MAX_FRAME;
+	if (ts_nr_packets < 4)
+		ts_nr_packets = 4;
+	if (ts_nr_packets > 312)
+		ts_nr_packets = 312;
+	dev->ts.nr_bufs    = tsbufs;
+	dev->ts.nr_packets = ts_nr_packets;
+
+	INIT_LIST_HEAD(&dev->ts_q.queue);
+	init_timer(&dev->ts_q.timeout);
+	dev->ts_q.timeout.function = saa7134_buffer_timeout;
+	dev->ts_q.timeout.data     = (unsigned long)(&dev->ts_q);
+	dev->ts_q.dev              = dev;
+	dev->ts_q.need_two         = 1;
+	dev->ts_started            = 0;
+	saa7134_pgtable_alloc(dev->pci,&dev->ts.pt_ts);
+
+	/* init TS hw */
+	saa7134_ts_init_hw(dev);
+
+	return 0;
+}
+
+/* Function for stop TS */
+int saa7134_ts_stop(struct saa7134_dev *dev)
+{
+	dprintk("TS stop\n");
+
+	BUG_ON(!dev->ts_started);
+
+	/* Stop TS stream */
+	switch (saa7134_boards[dev->board].ts_type) {
+	case SAA7134_MPEG_TS_PARALLEL:
+		saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
+		dev->ts_started = 0;
+		break;
+	case SAA7134_MPEG_TS_SERIAL:
+		saa_writeb(SAA7134_TS_SERIAL0, 0x40);
+		dev->ts_started = 0;
+		break;
+	}
+	return 0;
+}
+
+/* Function for start TS */
+int saa7134_ts_start(struct saa7134_dev *dev)
+{
+	dprintk("TS start\n");
+
+	BUG_ON(dev->ts_started);
+
+	/* dma: setup channel 5 (= TS) */
+	saa_writeb(SAA7134_TS_DMA0, (dev->ts.nr_packets - 1) & 0xff);
+	saa_writeb(SAA7134_TS_DMA1,
+		((dev->ts.nr_packets - 1) >> 8) & 0xff);
+	/* TSNOPIT=0, TSCOLAP=0 */
+	saa_writeb(SAA7134_TS_DMA2,
+		(((dev->ts.nr_packets - 1) >> 16) & 0x3f) | 0x00);
+	saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE);
+	saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_16 |
+					  SAA7134_RS_CONTROL_ME |
+					  (dev->ts.pt_ts.dma >> 12));
+
+	/* reset hardware TS buffers */
+	saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+	saa_writeb(SAA7134_TS_SERIAL1, 0x03);
+	saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+	saa_writeb(SAA7134_TS_SERIAL1, 0x01);
+
+	/* TS clock non-inverted */
+	saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+
+	/* Start TS stream */
+	switch (saa7134_boards[dev->board].ts_type) {
+	case SAA7134_MPEG_TS_PARALLEL:
+		saa_writeb(SAA7134_TS_SERIAL0, 0x40);
+		saa_writeb(SAA7134_TS_PARALLEL, 0xec |
+			(saa7134_boards[dev->board].ts_force_val << 4));
+		break;
+	case SAA7134_MPEG_TS_SERIAL:
+		saa_writeb(SAA7134_TS_SERIAL0, 0xd8);
+		saa_writeb(SAA7134_TS_PARALLEL, 0x6c |
+			(saa7134_boards[dev->board].ts_force_val << 4));
+		saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 0xbc);
+		saa_writeb(SAA7134_TS_SERIAL1, 0x02);
+		break;
+	}
+
+	dev->ts_started = 1;
+
+	return 0;
+}
+
+int saa7134_ts_fini(struct saa7134_dev *dev)
+{
+	saa7134_pgtable_free(dev->pci,&dev->ts.pt_ts);
+	return 0;
+}
+
+void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)
+{
+	enum v4l2_field field;
+
+	spin_lock(&dev->slock);
+	if (dev->ts_q.curr) {
+		field = dev->ts_q.curr->vb.field;
+		if (field == V4L2_FIELD_TOP) {
+			if ((status & 0x100000) != 0x000000)
+				goto done;
+		} else {
+			if ((status & 0x100000) != 0x100000)
+				goto done;
+		}
+		saa7134_buffer_finish(dev,&dev->ts_q,VIDEOBUF_DONE);
+	}
+	saa7134_buffer_next(dev,&dev->ts_q);
+
+ done:
+	spin_unlock(&dev->slock);
+}
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/saa7134/saa7134-tvaudio.c b/drivers/media/pci/saa7134/saa7134-tvaudio.c
new file mode 100644
index 0000000..b7a99be
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-tvaudio.c
@@ -0,0 +1,1087 @@
+/*
+ *
+ * device driver for philips saa7134 based TV cards
+ * tv audio decoder (fm stereo, nicam, ...)
+ *
+ * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/freezer.h>
+#include <asm/div64.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int audio_debug;
+module_param(audio_debug, int, 0644);
+MODULE_PARM_DESC(audio_debug,"enable debug messages [tv audio]");
+
+static unsigned int audio_ddep;
+module_param(audio_ddep, int, 0644);
+MODULE_PARM_DESC(audio_ddep,"audio ddep overwrite");
+
+static int audio_clock_override = UNSET;
+module_param(audio_clock_override, int, 0644);
+
+static int audio_clock_tweak;
+module_param(audio_clock_tweak, int, 0644);
+MODULE_PARM_DESC(audio_clock_tweak, "Audio clock tick fine tuning for cards with audio crystal that's slightly off (range [-1024 .. 1024])");
+
+#define dprintk(fmt, arg...)	if (audio_debug) \
+	printk(KERN_DEBUG "%s/audio: " fmt, dev->name , ## arg)
+#define d2printk(fmt, arg...)	if (audio_debug > 1) \
+	printk(KERN_DEBUG "%s/audio: " fmt, dev->name, ## arg)
+
+#define print_regb(reg) printk("%s:   reg 0x%03x [%-16s]: 0x%02x\n", \
+		dev->name,(SAA7134_##reg),(#reg),saa_readb((SAA7134_##reg)))
+
+/* msecs */
+#define SCAN_INITIAL_DELAY     1000
+#define SCAN_SAMPLE_DELAY       200
+#define SCAN_SUBCARRIER_DELAY  2000
+
+/* ------------------------------------------------------------------ */
+/* saa7134 code                                                       */
+
+static struct mainscan {
+	char         *name;
+	v4l2_std_id  std;
+	int          carr;
+} mainscan[] = {
+	{
+		.name = "MN",
+		.std  = V4L2_STD_MN,
+		.carr = 4500,
+	},{
+		.name = "BGH",
+		.std  = V4L2_STD_B | V4L2_STD_GH,
+		.carr = 5500,
+	},{
+		.name = "I",
+		.std  = V4L2_STD_PAL_I,
+		.carr = 6000,
+	},{
+		.name = "DKL",
+		.std  = V4L2_STD_DK | V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC,
+		.carr = 6500,
+	}
+};
+
+static struct saa7134_tvaudio tvaudio[] = {
+	{
+		.name          = "PAL-B/G FM-stereo",
+		.std           = V4L2_STD_PAL_BG,
+		.mode          = TVAUDIO_FM_BG_STEREO,
+		.carr1         = 5500,
+		.carr2         = 5742,
+	},{
+		.name          = "PAL-D/K1 FM-stereo",
+		.std           = V4L2_STD_PAL_DK,
+		.carr1         = 6500,
+		.carr2         = 6258,
+		.mode          = TVAUDIO_FM_BG_STEREO,
+	},{
+		.name          = "PAL-D/K2 FM-stereo",
+		.std           = V4L2_STD_PAL_DK,
+		.carr1         = 6500,
+		.carr2         = 6742,
+		.mode          = TVAUDIO_FM_BG_STEREO,
+	},{
+		.name          = "PAL-D/K3 FM-stereo",
+		.std           = V4L2_STD_PAL_DK,
+		.carr1         = 6500,
+		.carr2         = 5742,
+		.mode          = TVAUDIO_FM_BG_STEREO,
+	},{
+		.name          = "PAL-B/G NICAM",
+		.std           = V4L2_STD_PAL_BG,
+		.carr1         = 5500,
+		.carr2         = 5850,
+		.mode          = TVAUDIO_NICAM_FM,
+	},{
+		.name          = "PAL-I NICAM",
+		.std           = V4L2_STD_PAL_I,
+		.carr1         = 6000,
+		.carr2         = 6552,
+		.mode          = TVAUDIO_NICAM_FM,
+	},{
+		.name          = "PAL-D/K NICAM",
+		.std           = V4L2_STD_PAL_DK,
+		.carr1         = 6500,
+		.carr2         = 5850,
+		.mode          = TVAUDIO_NICAM_FM,
+	},{
+		.name          = "SECAM-L NICAM",
+		.std           = V4L2_STD_SECAM_L,
+		.carr1         = 6500,
+		.carr2         = 5850,
+		.mode          = TVAUDIO_NICAM_AM,
+	},{
+		.name          = "SECAM-D/K NICAM",
+		.std           = V4L2_STD_SECAM_DK,
+		.carr1         = 6500,
+		.carr2         = 5850,
+		.mode          = TVAUDIO_NICAM_FM,
+	},{
+		.name          = "NTSC-A2 FM-stereo",
+		.std           = V4L2_STD_NTSC,
+		.carr1         = 4500,
+		.carr2         = 4724,
+		.mode          = TVAUDIO_FM_K_STEREO,
+	},{
+		.name          = "NTSC-M",
+		.std           = V4L2_STD_NTSC,
+		.carr1         = 4500,
+		.carr2         = -1,
+		.mode          = TVAUDIO_FM_MONO,
+	}
+};
+#define TVAUDIO ARRAY_SIZE(tvaudio)
+
+/* ------------------------------------------------------------------ */
+
+static u32 tvaudio_carr2reg(u32 carrier)
+{
+	u64 a = carrier;
+
+	a <<= 24;
+	do_div(a,12288);
+	return a;
+}
+
+static void tvaudio_setcarrier(struct saa7134_dev *dev,
+			       int primary, int secondary)
+{
+	if (-1 == secondary)
+		secondary = primary;
+	saa_writel(SAA7134_CARRIER1_FREQ0 >> 2, tvaudio_carr2reg(primary));
+	saa_writel(SAA7134_CARRIER2_FREQ0 >> 2, tvaudio_carr2reg(secondary));
+}
+
+#define SAA7134_MUTE_MASK 0xbb
+#define SAA7134_MUTE_ANALOG 0x04
+#define SAA7134_MUTE_I2S 0x40
+
+static void mute_input_7134(struct saa7134_dev *dev)
+{
+	unsigned int mute;
+	struct saa7134_input *in;
+	int ausel=0, ics=0, ocs=0;
+	int mask;
+
+	/* look what is to do ... */
+	in   = dev->input;
+	mute = (dev->ctl_mute ||
+		(dev->automute  &&  (&card(dev).radio) != in));
+	if (card(dev).mute.name) {
+		/*
+		 * 7130 - we'll mute using some unconnected audio input
+		 * 7134 - we'll probably should switch external mux with gpio
+		 */
+		if (mute)
+			in = &card(dev).mute;
+	}
+
+	if (dev->hw_mute  == mute &&
+		dev->hw_input == in && !dev->insuspend) {
+		dprintk("mute/input: nothing to do [mute=%d,input=%s]\n",
+			mute,in->name);
+		return;
+	}
+
+	dprintk("ctl_mute=%d automute=%d input=%s  =>  mute=%d input=%s\n",
+		dev->ctl_mute,dev->automute,dev->input->name,mute,in->name);
+	dev->hw_mute  = mute;
+	dev->hw_input = in;
+
+	if (PCI_DEVICE_ID_PHILIPS_SAA7134 == dev->pci->device)
+		/* 7134 mute */
+		saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ?
+						    SAA7134_MUTE_MASK |
+						    SAA7134_MUTE_ANALOG |
+						    SAA7134_MUTE_I2S :
+						    SAA7134_MUTE_MASK);
+
+	/* switch internal audio mux */
+	switch (in->amux) {
+	case TV:         ausel=0xc0; ics=0x00; ocs=0x02; break;
+	case LINE1:      ausel=0x80; ics=0x00; ocs=0x00; break;
+	case LINE2:      ausel=0x80; ics=0x08; ocs=0x01; break;
+	case LINE2_LEFT: ausel=0x80; ics=0x08; ocs=0x05; break;
+	}
+	saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, ausel);
+	saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, ics);
+	saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, ocs);
+	// for oss, we need to change the clock configuration
+	if (in->amux == TV)
+		saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, 0x00);
+	else
+		saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, 0x01);
+
+	/* switch gpio-connected external audio mux */
+	if (0 == card(dev).gpiomask)
+		return;
+
+	mask = card(dev).gpiomask;
+	saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   mask, mask);
+	saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);
+	saa7134_track_gpio(dev,in->name);
+}
+
+static void tvaudio_setmode(struct saa7134_dev *dev,
+			    struct saa7134_tvaudio *audio,
+			    char *note)
+{
+	int acpf, tweak = 0;
+
+	if (dev->tvnorm->id == V4L2_STD_NTSC) {
+		acpf = 0x19066;
+	} else {
+		acpf = 0x1e000;
+	}
+	if (audio_clock_tweak > -1024 && audio_clock_tweak < 1024)
+		tweak = audio_clock_tweak;
+
+	if (note)
+		dprintk("tvaudio_setmode: %s %s [%d.%03d/%d.%03d MHz] acpf=%d%+d\n",
+			note,audio->name,
+			audio->carr1 / 1000, audio->carr1 % 1000,
+			audio->carr2 / 1000, audio->carr2 % 1000,
+			acpf, tweak);
+
+	acpf += tweak;
+	saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD0, (acpf & 0x0000ff) >> 0);
+	saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD1, (acpf & 0x00ff00) >> 8);
+	saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD2, (acpf & 0x030000) >> 16);
+	tvaudio_setcarrier(dev,audio->carr1,audio->carr2);
+
+	switch (audio->mode) {
+	case TVAUDIO_FM_MONO:
+	case TVAUDIO_FM_BG_STEREO:
+		saa_writeb(SAA7134_DEMODULATOR,               0x00);
+		saa_writeb(SAA7134_DCXO_IDENT_CTRL,           0x00);
+		saa_writeb(SAA7134_FM_DEEMPHASIS,             0x22);
+		saa_writeb(SAA7134_FM_DEMATRIX,               0x80);
+		saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT,  0xa0);
+		break;
+	case TVAUDIO_FM_K_STEREO:
+		saa_writeb(SAA7134_DEMODULATOR,               0x00);
+		saa_writeb(SAA7134_DCXO_IDENT_CTRL,           0x01);
+		saa_writeb(SAA7134_FM_DEEMPHASIS,             0x22);
+		saa_writeb(SAA7134_FM_DEMATRIX,               0x80);
+		saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT,  0xa0);
+		break;
+	case TVAUDIO_NICAM_FM:
+		saa_writeb(SAA7134_DEMODULATOR,               0x10);
+		saa_writeb(SAA7134_DCXO_IDENT_CTRL,           0x00);
+		saa_writeb(SAA7134_FM_DEEMPHASIS,             0x44);
+		saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT,  0xa1);
+		saa_writeb(SAA7134_NICAM_CONFIG,              0x00);
+		break;
+	case TVAUDIO_NICAM_AM:
+		saa_writeb(SAA7134_DEMODULATOR,               0x12);
+		saa_writeb(SAA7134_DCXO_IDENT_CTRL,           0x00);
+		saa_writeb(SAA7134_FM_DEEMPHASIS,             0x44);
+		saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT,  0xa1);
+		saa_writeb(SAA7134_NICAM_CONFIG,              0x00);
+		break;
+	case TVAUDIO_FM_SAT_STEREO:
+		/* not implemented (yet) */
+		break;
+	}
+}
+
+static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
+{
+	if (dev->thread.scan1 == dev->thread.scan2 &&
+	    !kthread_should_stop()) {
+		if (timeout < 0) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+		} else {
+			schedule_timeout_interruptible
+						(msecs_to_jiffies(timeout));
+		}
+	}
+	return dev->thread.scan1 != dev->thread.scan2;
+}
+
+static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan)
+{
+	__s32 left,right,value;
+
+	if (!(dev->tvnorm->id & scan->std)) {
+		value = 0;
+		dprintk("skipping %d.%03d MHz [%4s]\n",
+			scan->carr / 1000, scan->carr % 1000, scan->name);
+		return 0;
+	}
+
+	if (audio_debug > 1) {
+		int i;
+		dprintk("debug %d:",scan->carr);
+		for (i = -150; i <= 150; i += 30) {
+			tvaudio_setcarrier(dev,scan->carr+i,scan->carr+i);
+			saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+			if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
+				return -1;
+			value = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+			if (0 == i)
+				printk("  #  %6d  # ",value >> 16);
+			else
+				printk(" %6d",value >> 16);
+		}
+		printk("\n");
+	}
+
+	tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90);
+	saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+	if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
+		return -1;
+	left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+
+	tvaudio_setcarrier(dev,scan->carr+90,scan->carr+90);
+	saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+	if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
+		return -1;
+	right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+
+	left >>= 16;
+	right >>= 16;
+	value = left > right ? left - right : right - left;
+	dprintk("scanning %d.%03d MHz [%4s] =>  dc is %5d [%d/%d]\n",
+		scan->carr / 1000, scan->carr % 1000,
+		scan->name, value, left, right);
+	return value;
+}
+
+
+static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *audio)
+{
+	__u32 idp, nicam, nicam_status;
+	int retval = -1;
+
+	switch (audio->mode) {
+	case TVAUDIO_FM_MONO:
+		return V4L2_TUNER_SUB_MONO;
+	case TVAUDIO_FM_K_STEREO:
+	case TVAUDIO_FM_BG_STEREO:
+		idp = (saa_readb(SAA7134_IDENT_SIF) & 0xe0) >> 5;
+		dprintk("getstereo: fm/stereo: idp=0x%x\n",idp);
+		if (0x03 == (idp & 0x03))
+			retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+		else if (0x05 == (idp & 0x05))
+			retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+		else if (0x01 == (idp & 0x01))
+			retval = V4L2_TUNER_SUB_MONO;
+		break;
+	case TVAUDIO_FM_SAT_STEREO:
+		/* not implemented (yet) */
+		break;
+	case TVAUDIO_NICAM_FM:
+	case TVAUDIO_NICAM_AM:
+		nicam = saa_readb(SAA7134_AUDIO_STATUS);
+		dprintk("getstereo: nicam=0x%x\n",nicam);
+		if (nicam & 0x1) {
+			nicam_status = saa_readb(SAA7134_NICAM_STATUS);
+			dprintk("getstereo: nicam_status=0x%x\n", nicam_status);
+
+			switch (nicam_status & 0x03) {
+			    case 0x01:
+				retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+				break;
+			    case 0x02:
+				retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+				break;
+			    default:
+				retval = V4L2_TUNER_SUB_MONO;
+			}
+		} else {
+			/* No nicam detected */
+		}
+		break;
+	}
+	if (retval != -1)
+		dprintk("found audio subchannels:%s%s%s%s\n",
+			(retval & V4L2_TUNER_SUB_MONO)   ? " mono"   : "",
+			(retval & V4L2_TUNER_SUB_STEREO) ? " stereo" : "",
+			(retval & V4L2_TUNER_SUB_LANG1)  ? " lang1"  : "",
+			(retval & V4L2_TUNER_SUB_LANG2)  ? " lang2"  : "");
+	return retval;
+}
+
+static int tvaudio_setstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *audio,
+			     u32 mode)
+{
+	static char *name[] = {
+		[ V4L2_TUNER_MODE_MONO   ] = "mono",
+		[ V4L2_TUNER_MODE_STEREO ] = "stereo",
+		[ V4L2_TUNER_MODE_LANG1  ] = "lang1",
+		[ V4L2_TUNER_MODE_LANG2  ] = "lang2",
+		[ V4L2_TUNER_MODE_LANG1_LANG2  ] = "lang1+lang2",
+	};
+	static u32 fm[] = {
+		[ V4L2_TUNER_MODE_MONO   ] = 0x00,  /* ch1  */
+		[ V4L2_TUNER_MODE_STEREO ] = 0x80,  /* auto */
+		[ V4L2_TUNER_MODE_LANG1  ] = 0x00,  /* ch1  */
+		[ V4L2_TUNER_MODE_LANG2  ] = 0x01,  /* ch2  */
+		[ V4L2_TUNER_MODE_LANG1_LANG2 ] = 0x80,  /* auto */
+	};
+	u32 reg;
+
+	switch (audio->mode) {
+	case TVAUDIO_FM_MONO:
+		/* nothing to do ... */
+		break;
+	case TVAUDIO_FM_K_STEREO:
+	case TVAUDIO_FM_BG_STEREO:
+	case TVAUDIO_NICAM_AM:
+	case TVAUDIO_NICAM_FM:
+		dprintk("setstereo [fm] => %s\n",
+			name[ mode % ARRAY_SIZE(name) ]);
+		reg = fm[ mode % ARRAY_SIZE(fm) ];
+		saa_writeb(SAA7134_FM_DEMATRIX, reg);
+		break;
+	case TVAUDIO_FM_SAT_STEREO:
+		/* Not implemented */
+		break;
+	}
+	return 0;
+}
+
+static int tvaudio_thread(void *data)
+{
+	struct saa7134_dev *dev = data;
+	int carr_vals[ARRAY_SIZE(mainscan)];
+	unsigned int i, audio, nscan;
+	int max1,max2,carrier,rx,mode,lastmode,default_carrier;
+
+	set_freezable();
+
+	for (;;) {
+		tvaudio_sleep(dev,-1);
+		if (kthread_should_stop())
+			goto done;
+
+	restart:
+		try_to_freeze();
+
+		dev->thread.scan1 = dev->thread.scan2;
+		dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1);
+		dev->tvaudio  = NULL;
+
+		saa_writeb(SAA7134_MONITOR_SELECT,   0xa0);
+		saa_writeb(SAA7134_FM_DEMATRIX,      0x80);
+
+		if (dev->ctl_automute)
+			dev->automute = 1;
+
+		mute_input_7134(dev);
+
+		/* give the tuner some time */
+		if (tvaudio_sleep(dev,SCAN_INITIAL_DELAY))
+			goto restart;
+
+		max1 = 0;
+		max2 = 0;
+		nscan = 0;
+		carrier = 0;
+		default_carrier = 0;
+		for (i = 0; i < ARRAY_SIZE(mainscan); i++) {
+			if (!(dev->tvnorm->id & mainscan[i].std))
+				continue;
+			if (!default_carrier)
+				default_carrier = mainscan[i].carr;
+			nscan++;
+		}
+
+		if (1 == nscan) {
+			/* only one candidate -- skip scan ;) */
+			dprintk("only one main carrier candidate - skipping scan\n");
+			max1 = 12345;
+			carrier = default_carrier;
+		} else {
+			/* scan for the main carrier */
+			saa_writeb(SAA7134_MONITOR_SELECT,0x00);
+			tvaudio_setmode(dev,&tvaudio[0],NULL);
+			for (i = 0; i < ARRAY_SIZE(mainscan); i++) {
+				carr_vals[i] = tvaudio_checkcarrier(dev, mainscan+i);
+				if (dev->thread.scan1 != dev->thread.scan2)
+					goto restart;
+			}
+			for (max1 = 0, max2 = 0, i = 0; i < ARRAY_SIZE(mainscan); i++) {
+				if (max1 < carr_vals[i]) {
+					max2 = max1;
+					max1 = carr_vals[i];
+					carrier = mainscan[i].carr;
+				} else if (max2 < carr_vals[i]) {
+					max2 = carr_vals[i];
+				}
+			}
+		}
+
+		if (0 != carrier && max1 > 2000 && max1 > max2*3) {
+			/* found good carrier */
+			dprintk("found %s main sound carrier @ %d.%03d MHz [%d/%d]\n",
+				dev->tvnorm->name, carrier/1000, carrier%1000,
+				max1, max2);
+			dev->last_carrier = carrier;
+			dev->automute = 0;
+
+		} else if (0 != dev->last_carrier) {
+			/* no carrier -- try last detected one as fallback */
+			carrier = dev->last_carrier;
+			dprintk("audio carrier scan failed, "
+				"using %d.%03d MHz [last detected]\n",
+				carrier/1000, carrier%1000);
+			dev->automute = 1;
+
+		} else {
+			/* no carrier + no fallback -- use default */
+			carrier = default_carrier;
+			dprintk("audio carrier scan failed, "
+				"using %d.%03d MHz [default]\n",
+				carrier/1000, carrier%1000);
+			dev->automute = 1;
+		}
+		tvaudio_setcarrier(dev,carrier,carrier);
+		saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x00);
+		saa7134_tvaudio_setmute(dev);
+		/* find the exact tv audio norm */
+		for (audio = UNSET, i = 0; i < TVAUDIO; i++) {
+			if (dev->tvnorm->id != UNSET &&
+				!(dev->tvnorm->id & tvaudio[i].std))
+				continue;
+			if (tvaudio[i].carr1 != carrier)
+				continue;
+			/* Note: at least the primary carrier is right here */
+			if (UNSET == audio)
+				audio = i;
+			tvaudio_setmode(dev,&tvaudio[i],"trying");
+			if (tvaudio_sleep(dev,SCAN_SUBCARRIER_DELAY))
+				goto restart;
+			if (-1 != tvaudio_getstereo(dev,&tvaudio[i])) {
+				audio = i;
+				break;
+			}
+		}
+		saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x30);
+		if (UNSET == audio)
+			continue;
+		tvaudio_setmode(dev,&tvaudio[audio],"using");
+
+		tvaudio_setstereo(dev,&tvaudio[audio],V4L2_TUNER_MODE_MONO);
+		dev->tvaudio = &tvaudio[audio];
+
+		lastmode = 42;
+		for (;;) {
+
+			try_to_freeze();
+
+			if (tvaudio_sleep(dev,5000))
+				goto restart;
+			if (kthread_should_stop())
+				break;
+			if (UNSET == dev->thread.mode) {
+				rx = tvaudio_getstereo(dev, &tvaudio[audio]);
+				mode = saa7134_tvaudio_rx2mode(rx);
+			} else {
+				mode = dev->thread.mode;
+			}
+			if (lastmode != mode) {
+				tvaudio_setstereo(dev,&tvaudio[audio],mode);
+				lastmode = mode;
+			}
+		}
+	}
+
+ done:
+	dev->thread.stopped = 1;
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* saa7133 / saa7135 code                                             */
+
+static char *stdres[0x20] = {
+	[0x00] = "no standard detected",
+	[0x01] = "B/G (in progress)",
+	[0x02] = "D/K (in progress)",
+	[0x03] = "M (in progress)",
+
+	[0x04] = "B/G A2",
+	[0x05] = "B/G NICAM",
+	[0x06] = "D/K A2 (1)",
+	[0x07] = "D/K A2 (2)",
+	[0x08] = "D/K A2 (3)",
+	[0x09] = "D/K NICAM",
+	[0x0a] = "L NICAM",
+	[0x0b] = "I NICAM",
+
+	[0x0c] = "M Korea",
+	[0x0d] = "M BTSC ",
+	[0x0e] = "M EIAJ",
+
+	[0x0f] = "FM radio / IF 10.7 / 50 deemp",
+	[0x10] = "FM radio / IF 10.7 / 75 deemp",
+	[0x11] = "FM radio / IF sel / 50 deemp",
+	[0x12] = "FM radio / IF sel / 75 deemp",
+
+	[0x13 ... 0x1e ] = "unknown",
+	[0x1f] = "??? [in progress]",
+};
+
+#define DSP_RETRY 32
+#define DSP_DELAY 16
+#define SAA7135_DSP_RWCLEAR_RERR 1
+
+static inline int saa_dsp_reset_error_bit(struct saa7134_dev *dev)
+{
+	int state = saa_readb(SAA7135_DSP_RWSTATE);
+	if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) {
+		d2printk("%s: resetting error bit\n", dev->name);
+		saa_writeb(SAA7135_DSP_RWCLEAR, SAA7135_DSP_RWCLEAR_RERR);
+	}
+	return 0;
+}
+
+static inline int saa_dsp_wait_bit(struct saa7134_dev *dev, int bit)
+{
+	int state, count = DSP_RETRY;
+
+	state = saa_readb(SAA7135_DSP_RWSTATE);
+	if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) {
+		printk(KERN_WARNING "%s: dsp access error\n", dev->name);
+		saa_dsp_reset_error_bit(dev);
+		return -EIO;
+	}
+	while (0 == (state & bit)) {
+		if (unlikely(0 == count)) {
+			printk("%s: dsp access wait timeout [bit=%s]\n",
+			       dev->name,
+			       (bit & SAA7135_DSP_RWSTATE_WRR) ? "WRR" :
+			       (bit & SAA7135_DSP_RWSTATE_RDB) ? "RDB" :
+			       (bit & SAA7135_DSP_RWSTATE_IDA) ? "IDA" :
+			       "???");
+			return -EIO;
+		}
+		saa_wait(DSP_DELAY);
+		state = saa_readb(SAA7135_DSP_RWSTATE);
+		count--;
+	}
+	return 0;
+}
+
+
+int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value)
+{
+	int err;
+
+	d2printk("dsp write reg 0x%x = 0x%06x\n",reg<<2,value);
+	err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR);
+	if (err < 0)
+		return err;
+	saa_writel(reg,value);
+	err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static int getstereo_7133(struct saa7134_dev *dev)
+{
+	int retval = V4L2_TUNER_SUB_MONO;
+	u32 value;
+
+	value = saa_readl(0x528 >> 2);
+	if (value & 0x20)
+		retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+	if (value & 0x40)
+		retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+	return retval;
+}
+
+static int mute_input_7133(struct saa7134_dev *dev)
+{
+	u32 reg = 0;
+	u32 xbarin, xbarout;
+	int mask;
+	struct saa7134_input *in;
+
+	xbarin = 0x03;
+	switch (dev->input->amux) {
+	case TV:
+		reg = 0x02;
+		xbarin = 0;
+		break;
+	case LINE1:
+		reg = 0x00;
+		break;
+	case LINE2:
+	case LINE2_LEFT:
+		reg = 0x09;
+		break;
+	}
+	saa_dsp_writel(dev, 0x464 >> 2, xbarin);
+	if (dev->ctl_mute) {
+		reg = 0x07;
+		xbarout = 0xbbbbbb;
+	} else
+		xbarout = 0xbbbb10;
+	saa_dsp_writel(dev, 0x46c >> 2, xbarout);
+
+	saa_writel(0x594 >> 2, reg);
+
+
+	/* switch gpio-connected external audio mux */
+	if (0 != card(dev).gpiomask) {
+		mask = card(dev).gpiomask;
+
+		if (card(dev).mute.name && dev->ctl_mute)
+			in = &card(dev).mute;
+		else
+			in = dev->input;
+
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   mask, mask);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);
+		saa7134_track_gpio(dev,in->name);
+	}
+
+	return 0;
+}
+
+static int tvaudio_thread_ddep(void *data)
+{
+	struct saa7134_dev *dev = data;
+	u32 value, norms;
+
+	set_freezable();
+	for (;;) {
+		tvaudio_sleep(dev,-1);
+		if (kthread_should_stop())
+			goto done;
+	restart:
+		try_to_freeze();
+
+		dev->thread.scan1 = dev->thread.scan2;
+		dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1);
+
+		if (audio_ddep >= 0x04 && audio_ddep <= 0x0e) {
+			/* insmod option override */
+			norms = (audio_ddep << 2) | 0x01;
+			dprintk("ddep override: %s\n",stdres[audio_ddep]);
+		} else if (&card(dev).radio == dev->input) {
+			dprintk("FM Radio\n");
+			if (dev->tuner_type == TUNER_PHILIPS_TDA8290) {
+				norms = (0x11 << 2) | 0x01;
+				saa_dsp_writel(dev, 0x42c >> 2, 0x729555);
+			} else {
+				norms = (0x0f << 2) | 0x01;
+			}
+		} else {
+			/* (let chip) scan for sound carrier */
+			norms = 0;
+			if (dev->tvnorm->id & (V4L2_STD_B | V4L2_STD_GH))
+				norms |= 0x04;
+			if (dev->tvnorm->id & V4L2_STD_PAL_I)
+				norms |= 0x20;
+			if (dev->tvnorm->id & V4L2_STD_DK)
+				norms |= 0x08;
+			if (dev->tvnorm->id & V4L2_STD_MN)
+				norms |= 0x40;
+			if (dev->tvnorm->id & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))
+				norms |= 0x10;
+			if (0 == norms)
+				norms = 0x7c; /* all */
+			dprintk("scanning:%s%s%s%s%s\n",
+				(norms & 0x04) ? " B/G"  : "",
+				(norms & 0x08) ? " D/K"  : "",
+				(norms & 0x10) ? " L/L'" : "",
+				(norms & 0x20) ? " I"    : "",
+				(norms & 0x40) ? " M"    : "");
+		}
+
+		/* kick automatic standard detection */
+		saa_dsp_writel(dev, 0x454 >> 2, 0);
+		saa_dsp_writel(dev, 0x454 >> 2, norms | 0x80);
+
+		/* setup crossbars */
+		saa_dsp_writel(dev, 0x464 >> 2, 0x000000);
+		saa_dsp_writel(dev, 0x470 >> 2, 0x101010);
+
+		if (tvaudio_sleep(dev,3000))
+			goto restart;
+		value = saa_readl(0x528 >> 2) & 0xffffff;
+
+		dprintk("tvaudio thread status: 0x%x [%s%s%s]\n",
+			value, stdres[value & 0x1f],
+			(value & 0x000020) ? ",stereo" : "",
+			(value & 0x000040) ? ",dual"   : "");
+		dprintk("detailed status: "
+			"%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
+			(value & 0x000080) ? " A2/EIAJ pilot tone "     : "",
+			(value & 0x000100) ? " A2/EIAJ dual "           : "",
+			(value & 0x000200) ? " A2/EIAJ stereo "         : "",
+			(value & 0x000400) ? " A2/EIAJ noise mute "     : "",
+
+			(value & 0x000800) ? " BTSC/FM radio pilot "    : "",
+			(value & 0x001000) ? " SAP carrier "            : "",
+			(value & 0x002000) ? " BTSC stereo noise mute " : "",
+			(value & 0x004000) ? " SAP noise mute "         : "",
+			(value & 0x008000) ? " VDSP "                   : "",
+
+			(value & 0x010000) ? " NICST "                  : "",
+			(value & 0x020000) ? " NICDU "                  : "",
+			(value & 0x040000) ? " NICAM muted "            : "",
+			(value & 0x080000) ? " NICAM reserve sound "    : "",
+
+			(value & 0x100000) ? " init done "              : "");
+	}
+
+ done:
+	dev->thread.stopped = 1;
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* common stuff + external entry points                               */
+
+void saa7134_enable_i2s(struct saa7134_dev *dev)
+{
+	int i2s_format;
+
+	if (!card_is_empress(dev))
+		return;
+
+	if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130)
+		return;
+
+	/* configure GPIO for out */
+	saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0E000000, 0x00000000);
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+	    /* Set I2S format (SONY)  */
+	    saa_writeb(SAA7133_I2S_AUDIO_CONTROL, 0x00);
+	    /* Start I2S */
+	    saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x11);
+	    break;
+
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+	    i2s_format = (dev->input->amux == TV) ? 0x00 : 0x01;
+
+	    /* enable I2S audio output for the mpeg encoder */
+	    saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80);
+	    saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, i2s_format);
+	    saa_writeb(SAA7134_I2S_OUTPUT_LEVEL,  0x0F);
+	    saa_writeb(SAA7134_I2S_AUDIO_OUTPUT,  0x01);
+
+	default:
+	    break;
+	}
+}
+
+int saa7134_tvaudio_rx2mode(u32 rx)
+{
+	u32 mode;
+
+	mode = V4L2_TUNER_MODE_MONO;
+	if (rx & V4L2_TUNER_SUB_STEREO)
+		mode = V4L2_TUNER_MODE_STEREO;
+	else if (rx & V4L2_TUNER_SUB_LANG1)
+		mode = V4L2_TUNER_MODE_LANG1;
+	else if (rx & V4L2_TUNER_SUB_LANG2)
+		mode = V4L2_TUNER_MODE_LANG2;
+	return mode;
+}
+
+void saa7134_tvaudio_setmute(struct saa7134_dev *dev)
+{
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7130:
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		mute_input_7134(dev);
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		mute_input_7133(dev);
+		break;
+	}
+}
+
+void saa7134_tvaudio_setinput(struct saa7134_dev *dev,
+			      struct saa7134_input *in)
+{
+	dev->input = in;
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7130:
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		mute_input_7134(dev);
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		mute_input_7133(dev);
+		break;
+	}
+	saa7134_enable_i2s(dev);
+}
+
+void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level)
+{
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		saa_writeb(SAA7134_CHANNEL1_LEVEL,     level & 0x1f);
+		saa_writeb(SAA7134_CHANNEL2_LEVEL,     level & 0x1f);
+		saa_writeb(SAA7134_NICAM_LEVEL_ADJUST, level & 0x1f);
+		break;
+	}
+}
+
+int saa7134_tvaudio_getstereo(struct saa7134_dev *dev)
+{
+	int retval = V4L2_TUNER_SUB_MONO;
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		if (dev->tvaudio)
+			retval = tvaudio_getstereo(dev,dev->tvaudio);
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		retval = getstereo_7133(dev);
+		break;
+	}
+	return retval;
+}
+
+void saa7134_tvaudio_init(struct saa7134_dev *dev)
+{
+	int clock = saa7134_boards[dev->board].audio_clock;
+
+	if (UNSET != audio_clock_override)
+		clock = audio_clock_override;
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		/* init all audio registers */
+		saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x00);
+		if (need_resched())
+			schedule();
+		else
+			udelay(10);
+
+		saa_writeb(SAA7134_AUDIO_CLOCK0,      clock        & 0xff);
+		saa_writeb(SAA7134_AUDIO_CLOCK1,     (clock >>  8) & 0xff);
+		saa_writeb(SAA7134_AUDIO_CLOCK2,     (clock >> 16) & 0xff);
+		/* frame locked audio is mandatory for NICAM */
+		saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x01);
+		saa_writeb(SAA7134_NICAM_ERROR_LOW,  0x14);
+		saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50);
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		saa_writel(0x598 >> 2, clock);
+		saa_dsp_writel(dev, 0x474 >> 2, 0x00);
+		saa_dsp_writel(dev, 0x450 >> 2, 0x00);
+	}
+}
+
+int saa7134_tvaudio_init2(struct saa7134_dev *dev)
+{
+	int (*my_thread)(void *data) = NULL;
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		my_thread = tvaudio_thread;
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		my_thread = tvaudio_thread_ddep;
+		break;
+	}
+
+	dev->thread.thread = NULL;
+	dev->thread.scan1 = dev->thread.scan2 = 0;
+	if (my_thread) {
+		saa7134_tvaudio_init(dev);
+		/* start tvaudio thread */
+		dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name);
+		if (IS_ERR(dev->thread.thread)) {
+			printk(KERN_WARNING "%s: kernel_thread() failed\n",
+			       dev->name);
+			/* XXX: missing error handling here */
+		}
+	}
+
+	saa7134_enable_i2s(dev);
+	return 0;
+}
+
+int saa7134_tvaudio_close(struct saa7134_dev *dev)
+{
+	dev->automute = 1;
+	/* anything else to undo? */
+	return 0;
+}
+
+int saa7134_tvaudio_fini(struct saa7134_dev *dev)
+{
+	/* shutdown tvaudio thread */
+	if (dev->thread.thread && !dev->thread.stopped)
+		kthread_stop(dev->thread.thread);
+
+	saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */
+	return 0;
+}
+
+int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
+{
+	if (dev->input->amux != TV) {
+		dprintk("sound IF not in use, skipping scan\n");
+		dev->automute = 0;
+		saa7134_tvaudio_setmute(dev);
+	} else if (dev->thread.thread) {
+		dev->thread.mode = UNSET;
+		dev->thread.scan2++;
+
+		if (!dev->insuspend && !dev->thread.stopped)
+			wake_up_process(dev->thread.thread);
+	} else {
+		dev->automute = 0;
+		saa7134_tvaudio_setmute(dev);
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(saa_dsp_writel);
+EXPORT_SYMBOL(saa7134_tvaudio_setmute);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c
new file mode 100644
index 0000000..e9aa94b
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-vbi.c
@@ -0,0 +1,255 @@
+/*
+ *
+ * device driver for philips saa7134 based TV cards
+ * video4linux video interface
+ *
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int vbi_debug;
+module_param(vbi_debug, int, 0644);
+MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
+
+static unsigned int vbibufs = 4;
+module_param(vbibufs, int, 0444);
+MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32");
+
+#define dprintk(fmt, arg...)	if (vbi_debug) \
+	printk(KERN_DEBUG "%s/vbi: " fmt, dev->name , ## arg)
+
+/* ------------------------------------------------------------------ */
+
+#define VBI_LINE_COUNT     16
+#define VBI_LINE_LENGTH  2048
+#define VBI_SCALE       0x200
+
+static void task_init(struct saa7134_dev *dev, struct saa7134_buf *buf,
+		      int task)
+{
+	struct saa7134_tvnorm *norm = dev->tvnorm;
+
+	/* setup video scaler */
+	saa_writeb(SAA7134_VBI_H_START1(task), norm->h_start     &  0xff);
+	saa_writeb(SAA7134_VBI_H_START2(task), norm->h_start     >> 8);
+	saa_writeb(SAA7134_VBI_H_STOP1(task),  norm->h_stop      &  0xff);
+	saa_writeb(SAA7134_VBI_H_STOP2(task),  norm->h_stop      >> 8);
+	saa_writeb(SAA7134_VBI_V_START1(task), norm->vbi_v_start_0 &  0xff);
+	saa_writeb(SAA7134_VBI_V_START2(task), norm->vbi_v_start_0 >> 8);
+	saa_writeb(SAA7134_VBI_V_STOP1(task),  norm->vbi_v_stop_0  &  0xff);
+	saa_writeb(SAA7134_VBI_V_STOP2(task),  norm->vbi_v_stop_0  >> 8);
+
+	saa_writeb(SAA7134_VBI_H_SCALE_INC1(task),        VBI_SCALE & 0xff);
+	saa_writeb(SAA7134_VBI_H_SCALE_INC2(task),        VBI_SCALE >> 8);
+	saa_writeb(SAA7134_VBI_PHASE_OFFSET_LUMA(task),   0x00);
+	saa_writeb(SAA7134_VBI_PHASE_OFFSET_CHROMA(task), 0x00);
+
+	saa_writeb(SAA7134_VBI_H_LEN1(task), buf->vb.width   & 0xff);
+	saa_writeb(SAA7134_VBI_H_LEN2(task), buf->vb.width   >> 8);
+	saa_writeb(SAA7134_VBI_V_LEN1(task), buf->vb.height  & 0xff);
+	saa_writeb(SAA7134_VBI_V_LEN2(task), buf->vb.height  >> 8);
+
+	saa_andorb(SAA7134_DATA_PATH(task), 0xc0, 0x00);
+}
+
+/* ------------------------------------------------------------------ */
+
+static int buffer_activate(struct saa7134_dev *dev,
+			   struct saa7134_buf *buf,
+			   struct saa7134_buf *next)
+{
+	unsigned long control,base;
+
+	dprintk("buffer_activate [%p]\n",buf);
+	buf->vb.state = VIDEOBUF_ACTIVE;
+	buf->top_seen = 0;
+
+	task_init(dev,buf,TASK_A);
+	task_init(dev,buf,TASK_B);
+	saa_writeb(SAA7134_OFMT_DATA_A, 0x06);
+	saa_writeb(SAA7134_OFMT_DATA_B, 0x06);
+
+	/* DMA: setup channel 2+3 (= VBI Task A+B) */
+	base    = saa7134_buffer_base(buf);
+	control = SAA7134_RS_CONTROL_BURST_16 |
+		SAA7134_RS_CONTROL_ME |
+		(buf->pt->dma >> 12);
+	saa_writel(SAA7134_RS_BA1(2),base);
+	saa_writel(SAA7134_RS_BA2(2),base + buf->vb.size/2);
+	saa_writel(SAA7134_RS_PITCH(2),buf->vb.width);
+	saa_writel(SAA7134_RS_CONTROL(2),control);
+	saa_writel(SAA7134_RS_BA1(3),base);
+	saa_writel(SAA7134_RS_BA2(3),base + buf->vb.size/2);
+	saa_writel(SAA7134_RS_PITCH(3),buf->vb.width);
+	saa_writel(SAA7134_RS_CONTROL(3),control);
+
+	/* start DMA */
+	saa7134_set_dmabits(dev);
+	mod_timer(&dev->vbi_q.timeout, jiffies+BUFFER_TIMEOUT);
+
+	return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *q,
+			  struct videobuf_buffer *vb,
+			  enum v4l2_field field)
+{
+	struct saa7134_fh *fh   = q->priv_data;
+	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+	struct saa7134_tvnorm *norm = dev->tvnorm;
+	unsigned int lines, llength, size;
+	int err;
+
+	lines   = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1;
+	if (lines > VBI_LINE_COUNT)
+		lines = VBI_LINE_COUNT;
+	llength = VBI_LINE_LENGTH;
+	size = lines * llength * 2;
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+		return -EINVAL;
+
+	if (buf->vb.size != size)
+		saa7134_dma_free(q,buf);
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
+		buf->vb.width  = llength;
+		buf->vb.height = lines;
+		buf->vb.size   = size;
+		buf->pt        = &fh->pt_vbi;
+
+		err = videobuf_iolock(q,&buf->vb,NULL);
+		if (err)
+			goto oops;
+		err = saa7134_pgtable_build(dev->pci,buf->pt,
+					    dma->sglist,
+					    dma->sglen,
+					    saa7134_buffer_startpage(buf));
+		if (err)
+			goto oops;
+	}
+	buf->vb.state = VIDEOBUF_PREPARED;
+	buf->activate = buffer_activate;
+	buf->vb.field = field;
+	return 0;
+
+ oops:
+	saa7134_dma_free(q,buf);
+	return err;
+}
+
+static int
+buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+	struct saa7134_fh *fh   = q->priv_data;
+	struct saa7134_dev *dev = fh->dev;
+	int llength,lines;
+
+	lines   = dev->tvnorm->vbi_v_stop_0 - dev->tvnorm->vbi_v_start_0 +1;
+	llength = VBI_LINE_LENGTH;
+	*size = lines * llength * 2;
+	if (0 == *count)
+		*count = vbibufs;
+	*count = saa7134_buffer_count(*size,*count);
+	return 0;
+}
+
+static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct saa7134_fh *fh = q->priv_data;
+	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+
+	saa7134_buffer_queue(dev,&dev->vbi_q,buf);
+}
+
+static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+
+	saa7134_dma_free(q,buf);
+}
+
+struct videobuf_queue_ops saa7134_vbi_qops = {
+	.buf_setup    = buffer_setup,
+	.buf_prepare  = buffer_prepare,
+	.buf_queue    = buffer_queue,
+	.buf_release  = buffer_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+int saa7134_vbi_init1(struct saa7134_dev *dev)
+{
+	INIT_LIST_HEAD(&dev->vbi_q.queue);
+	init_timer(&dev->vbi_q.timeout);
+	dev->vbi_q.timeout.function = saa7134_buffer_timeout;
+	dev->vbi_q.timeout.data     = (unsigned long)(&dev->vbi_q);
+	dev->vbi_q.dev              = dev;
+
+	if (vbibufs < 2)
+		vbibufs = 2;
+	if (vbibufs > VIDEO_MAX_FRAME)
+		vbibufs = VIDEO_MAX_FRAME;
+	return 0;
+}
+
+int saa7134_vbi_fini(struct saa7134_dev *dev)
+{
+	/* nothing */
+	return 0;
+}
+
+void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status)
+{
+	spin_lock(&dev->slock);
+	if (dev->vbi_q.curr) {
+		dev->vbi_fieldcount++;
+		/* make sure we have seen both fields */
+		if ((status & 0x10) == 0x00) {
+			dev->vbi_q.curr->top_seen = 1;
+			goto done;
+		}
+		if (!dev->vbi_q.curr->top_seen)
+			goto done;
+
+		dev->vbi_q.curr->vb.field_count = dev->vbi_fieldcount;
+		saa7134_buffer_finish(dev,&dev->vbi_q,VIDEOBUF_DONE);
+	}
+	saa7134_buffer_next(dev,&dev->vbi_q);
+
+ done:
+	spin_unlock(&dev->slock);
+}
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
new file mode 100644
index 0000000..6de10b1
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -0,0 +1,2661 @@
+/*
+ *
+ * device driver for philips saa7134 based TV cards
+ * video4linux video interface
+ *
+ * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+#include <media/v4l2-common.h>
+#include <media/saa6588.h>
+
+/* ------------------------------------------------------------------ */
+
+unsigned int video_debug;
+static unsigned int gbuffers      = 8;
+static unsigned int noninterlaced; /* 0 */
+static unsigned int gbufsize      = 720*576*4;
+static unsigned int gbufsize_max  = 720*576*4;
+static char secam[] = "--";
+module_param(video_debug, int, 0644);
+MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
+module_param(gbuffers, int, 0444);
+MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32");
+module_param(noninterlaced, int, 0644);
+MODULE_PARM_DESC(noninterlaced,"capture non interlaced video");
+module_param_string(secam, secam, sizeof(secam), 0644);
+MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc");
+
+
+#define dprintk(fmt, arg...)	if (video_debug&0x04) \
+	printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg)
+
+/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x191            */
+
+/* Bit 0: VIP code T bit polarity */
+
+#define VP_T_CODE_P_NON_INVERTED	0x00
+#define VP_T_CODE_P_INVERTED		0x01
+
+/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x195            */
+
+/* Bit 2: Video output clock delay control */
+
+#define VP_CLK_CTRL2_NOT_DELAYED	0x00
+#define VP_CLK_CTRL2_DELAYED		0x04
+
+/* Bit 1: Video output clock invert control */
+
+#define VP_CLK_CTRL1_NON_INVERTED	0x00
+#define VP_CLK_CTRL1_INVERTED		0x02
+
+/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x196            */
+
+/* Bits 2 to 0: VSYNC pin video vertical sync type */
+
+#define VP_VS_TYPE_MASK			0x07
+
+#define VP_VS_TYPE_OFF			0x00
+#define VP_VS_TYPE_V123			0x01
+#define VP_VS_TYPE_V_ITU		0x02
+#define VP_VS_TYPE_VGATE_L		0x03
+#define VP_VS_TYPE_RESERVED1		0x04
+#define VP_VS_TYPE_RESERVED2		0x05
+#define VP_VS_TYPE_F_ITU		0x06
+#define VP_VS_TYPE_SC_FID		0x07
+
+/* ------------------------------------------------------------------ */
+/* data structs for video                                             */
+
+static int video_out[][9] = {
+	[CCIR656] = { 0x00, 0xb1, 0x00, 0xa1, 0x00, 0x04, 0x06, 0x00, 0x00 },
+};
+
+static struct saa7134_format formats[] = {
+	{
+		.name     = "8 bpp gray",
+		.fourcc   = V4L2_PIX_FMT_GREY,
+		.depth    = 8,
+		.pm       = 0x06,
+	},{
+		.name     = "15 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_RGB555,
+		.depth    = 16,
+		.pm       = 0x13 | 0x80,
+	},{
+		.name     = "15 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB555X,
+		.depth    = 16,
+		.pm       = 0x13 | 0x80,
+		.bswap    = 1,
+	},{
+		.name     = "16 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_RGB565,
+		.depth    = 16,
+		.pm       = 0x10 | 0x80,
+	},{
+		.name     = "16 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB565X,
+		.depth    = 16,
+		.pm       = 0x10 | 0x80,
+		.bswap    = 1,
+	},{
+		.name     = "24 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_BGR24,
+		.depth    = 24,
+		.pm       = 0x11,
+	},{
+		.name     = "24 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB24,
+		.depth    = 24,
+		.pm       = 0x11,
+		.bswap    = 1,
+	},{
+		.name     = "32 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_BGR32,
+		.depth    = 32,
+		.pm       = 0x12,
+	},{
+		.name     = "32 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB32,
+		.depth    = 32,
+		.pm       = 0x12,
+		.bswap    = 1,
+		.wswap    = 1,
+	},{
+		.name     = "4:2:2 packed, YUYV",
+		.fourcc   = V4L2_PIX_FMT_YUYV,
+		.depth    = 16,
+		.pm       = 0x00,
+		.bswap    = 1,
+		.yuv      = 1,
+	},{
+		.name     = "4:2:2 packed, UYVY",
+		.fourcc   = V4L2_PIX_FMT_UYVY,
+		.depth    = 16,
+		.pm       = 0x00,
+		.yuv      = 1,
+	},{
+		.name     = "4:2:2 planar, Y-Cb-Cr",
+		.fourcc   = V4L2_PIX_FMT_YUV422P,
+		.depth    = 16,
+		.pm       = 0x09,
+		.yuv      = 1,
+		.planar   = 1,
+		.hshift   = 1,
+		.vshift   = 0,
+	},{
+		.name     = "4:2:0 planar, Y-Cb-Cr",
+		.fourcc   = V4L2_PIX_FMT_YUV420,
+		.depth    = 12,
+		.pm       = 0x0a,
+		.yuv      = 1,
+		.planar   = 1,
+		.hshift   = 1,
+		.vshift   = 1,
+	},{
+		.name     = "4:2:0 planar, Y-Cb-Cr",
+		.fourcc   = V4L2_PIX_FMT_YVU420,
+		.depth    = 12,
+		.pm       = 0x0a,
+		.yuv      = 1,
+		.planar   = 1,
+		.uvswap   = 1,
+		.hshift   = 1,
+		.vshift   = 1,
+	}
+};
+#define FORMATS ARRAY_SIZE(formats)
+
+#define NORM_625_50			\
+		.h_start       = 0,	\
+		.h_stop        = 719,	\
+		.video_v_start = 24,	\
+		.video_v_stop  = 311,	\
+		.vbi_v_start_0 = 7,	\
+		.vbi_v_stop_0  = 22,	\
+		.vbi_v_start_1 = 319,   \
+		.src_timing    = 4
+
+#define NORM_525_60			\
+		.h_start       = 0,	\
+		.h_stop        = 719,	\
+		.video_v_start = 23,	\
+		.video_v_stop  = 262,	\
+		.vbi_v_start_0 = 10,	\
+		.vbi_v_stop_0  = 21,	\
+		.vbi_v_start_1 = 273,	\
+		.src_timing    = 7
+
+static struct saa7134_tvnorm tvnorms[] = {
+	{
+		.name          = "PAL", /* autodetect */
+		.id            = V4L2_STD_PAL,
+		NORM_625_50,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0x81,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x06,
+		.vgate_misc    = 0x1c,
+
+	},{
+		.name          = "PAL-BG",
+		.id            = V4L2_STD_PAL_BG,
+		NORM_625_50,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0x81,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x06,
+		.vgate_misc    = 0x1c,
+
+	},{
+		.name          = "PAL-I",
+		.id            = V4L2_STD_PAL_I,
+		NORM_625_50,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0x81,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x06,
+		.vgate_misc    = 0x1c,
+
+	},{
+		.name          = "PAL-DK",
+		.id            = V4L2_STD_PAL_DK,
+		NORM_625_50,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0x81,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x06,
+		.vgate_misc    = 0x1c,
+
+	},{
+		.name          = "NTSC",
+		.id            = V4L2_STD_NTSC,
+		NORM_525_60,
+
+		.sync_control  = 0x59,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0x89,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x0e,
+		.vgate_misc    = 0x18,
+
+	},{
+		.name          = "SECAM",
+		.id            = V4L2_STD_SECAM,
+		NORM_625_50,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x1b,
+		.chroma_ctrl1  = 0xd1,
+		.chroma_gain   = 0x80,
+		.chroma_ctrl2  = 0x00,
+		.vgate_misc    = 0x1c,
+
+	},{
+		.name          = "SECAM-DK",
+		.id            = V4L2_STD_SECAM_DK,
+		NORM_625_50,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x1b,
+		.chroma_ctrl1  = 0xd1,
+		.chroma_gain   = 0x80,
+		.chroma_ctrl2  = 0x00,
+		.vgate_misc    = 0x1c,
+
+	},{
+		.name          = "SECAM-L",
+		.id            = V4L2_STD_SECAM_L,
+		NORM_625_50,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x1b,
+		.chroma_ctrl1  = 0xd1,
+		.chroma_gain   = 0x80,
+		.chroma_ctrl2  = 0x00,
+		.vgate_misc    = 0x1c,
+
+	},{
+		.name          = "SECAM-Lc",
+		.id            = V4L2_STD_SECAM_LC,
+		NORM_625_50,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x1b,
+		.chroma_ctrl1  = 0xd1,
+		.chroma_gain   = 0x80,
+		.chroma_ctrl2  = 0x00,
+		.vgate_misc    = 0x1c,
+
+	},{
+		.name          = "PAL-M",
+		.id            = V4L2_STD_PAL_M,
+		NORM_525_60,
+
+		.sync_control  = 0x59,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0xb9,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x0e,
+		.vgate_misc    = 0x18,
+
+	},{
+		.name          = "PAL-Nc",
+		.id            = V4L2_STD_PAL_Nc,
+		NORM_625_50,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0xa1,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x06,
+		.vgate_misc    = 0x1c,
+
+	},{
+		.name          = "PAL-60",
+		.id            = V4L2_STD_PAL_60,
+
+		.h_start       = 0,
+		.h_stop        = 719,
+		.video_v_start = 23,
+		.video_v_stop  = 262,
+		.vbi_v_start_0 = 10,
+		.vbi_v_stop_0  = 21,
+		.vbi_v_start_1 = 273,
+		.src_timing    = 7,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0x81,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x06,
+		.vgate_misc    = 0x1c,
+	}
+};
+#define TVNORMS ARRAY_SIZE(tvnorms)
+
+#define V4L2_CID_PRIVATE_INVERT      (V4L2_CID_PRIVATE_BASE + 0)
+#define V4L2_CID_PRIVATE_Y_ODD       (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_PRIVATE_Y_EVEN      (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_PRIVATE_AUTOMUTE    (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_PRIVATE_LASTP1      (V4L2_CID_PRIVATE_BASE + 4)
+
+static const struct v4l2_queryctrl no_ctrl = {
+	.name  = "42",
+	.flags = V4L2_CTRL_FLAG_DISABLED,
+};
+static const struct v4l2_queryctrl video_ctrls[] = {
+	/* --- video --- */
+	{
+		.id            = V4L2_CID_BRIGHTNESS,
+		.name          = "Brightness",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = 128,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_CONTRAST,
+		.name          = "Contrast",
+		.minimum       = 0,
+		.maximum       = 127,
+		.step          = 1,
+		.default_value = 68,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_SATURATION,
+		.name          = "Saturation",
+		.minimum       = 0,
+		.maximum       = 127,
+		.step          = 1,
+		.default_value = 64,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_HUE,
+		.name          = "Hue",
+		.minimum       = -128,
+		.maximum       = 127,
+		.step          = 1,
+		.default_value = 0,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_HFLIP,
+		.name          = "Mirror",
+		.minimum       = 0,
+		.maximum       = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},
+	/* --- audio --- */
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_AUDIO_VOLUME,
+		.name          = "Volume",
+		.minimum       = -15,
+		.maximum       = 15,
+		.step          = 1,
+		.default_value = 0,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},
+	/* --- private --- */
+	{
+		.id            = V4L2_CID_PRIVATE_INVERT,
+		.name          = "Invert",
+		.minimum       = 0,
+		.maximum       = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_PRIVATE_Y_ODD,
+		.name          = "y offset odd field",
+		.minimum       = 0,
+		.maximum       = 128,
+		.step          = 1,
+		.default_value = 0,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_PRIVATE_Y_EVEN,
+		.name          = "y offset even field",
+		.minimum       = 0,
+		.maximum       = 128,
+		.step          = 1,
+		.default_value = 0,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_PRIVATE_AUTOMUTE,
+		.name          = "automute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	}
+};
+static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls);
+
+static const struct v4l2_queryctrl* ctrl_by_id(unsigned int id)
+{
+	unsigned int i;
+
+	for (i = 0; i < CTRLS; i++)
+		if (video_ctrls[i].id == id)
+			return video_ctrls+i;
+	return NULL;
+}
+
+static struct saa7134_format* format_by_fourcc(unsigned int fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < FORMATS; i++)
+		if (formats[i].fourcc == fourcc)
+			return formats+i;
+	return NULL;
+}
+
+/* ----------------------------------------------------------------------- */
+/* resource management                                                     */
+
+static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bit)
+{
+	if (fh->resources & bit)
+		/* have it already allocated */
+		return 1;
+
+	/* is it free? */
+	mutex_lock(&dev->lock);
+	if (dev->resources & bit) {
+		/* no, someone else uses it */
+		mutex_unlock(&dev->lock);
+		return 0;
+	}
+	/* it's free, grab it */
+	fh->resources  |= bit;
+	dev->resources |= bit;
+	dprintk("res: get %d\n",bit);
+	mutex_unlock(&dev->lock);
+	return 1;
+}
+
+static int res_check(struct saa7134_fh *fh, unsigned int bit)
+{
+	return (fh->resources & bit);
+}
+
+static int res_locked(struct saa7134_dev *dev, unsigned int bit)
+{
+	return (dev->resources & bit);
+}
+
+static
+void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)
+{
+	BUG_ON((fh->resources & bits) != bits);
+
+	mutex_lock(&dev->lock);
+	fh->resources  &= ~bits;
+	dev->resources &= ~bits;
+	dprintk("res: put %d\n",bits);
+	mutex_unlock(&dev->lock);
+}
+
+/* ------------------------------------------------------------------ */
+
+static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
+{
+	dprintk("set tv norm = %s\n",norm->name);
+	dev->tvnorm = norm;
+
+	/* setup cropping */
+	dev->crop_bounds.left    = norm->h_start;
+	dev->crop_defrect.left   = norm->h_start;
+	dev->crop_bounds.width   = norm->h_stop - norm->h_start +1;
+	dev->crop_defrect.width  = norm->h_stop - norm->h_start +1;
+
+	dev->crop_bounds.top     = (norm->vbi_v_stop_0+1)*2;
+	dev->crop_defrect.top    = norm->video_v_start*2;
+	dev->crop_bounds.height  = ((norm->id & V4L2_STD_525_60) ? 524 : 624)
+		- dev->crop_bounds.top;
+	dev->crop_defrect.height = (norm->video_v_stop - norm->video_v_start +1)*2;
+
+	dev->crop_current = dev->crop_defrect;
+
+	saa7134_set_tvnorm_hw(dev);
+}
+
+static void video_mux(struct saa7134_dev *dev, int input)
+{
+	dprintk("video input = %d [%s]\n", input, card_in(dev, input).name);
+	dev->ctl_input = input;
+	set_tvnorm(dev, dev->tvnorm);
+	saa7134_tvaudio_setinput(dev, &card_in(dev, input));
+}
+
+
+static void saa7134_set_decoder(struct saa7134_dev *dev)
+{
+	int luma_control, sync_control, mux;
+
+	struct saa7134_tvnorm *norm = dev->tvnorm;
+	mux = card_in(dev, dev->ctl_input).vmux;
+
+	luma_control = norm->luma_control;
+	sync_control = norm->sync_control;
+
+	if (mux > 5)
+		luma_control |= 0x80; /* svideo */
+	if (noninterlaced || dev->nosignal)
+		sync_control |= 0x20;
+
+	/* setup video decoder */
+	saa_writeb(SAA7134_INCR_DELAY,            0x08);
+	saa_writeb(SAA7134_ANALOG_IN_CTRL1,       0xc0 | mux);
+	saa_writeb(SAA7134_ANALOG_IN_CTRL2,       0x00);
+
+	saa_writeb(SAA7134_ANALOG_IN_CTRL3,       0x90);
+	saa_writeb(SAA7134_ANALOG_IN_CTRL4,       0x90);
+	saa_writeb(SAA7134_HSYNC_START,           0xeb);
+	saa_writeb(SAA7134_HSYNC_STOP,            0xe0);
+	saa_writeb(SAA7134_SOURCE_TIMING1,        norm->src_timing);
+
+	saa_writeb(SAA7134_SYNC_CTRL,             sync_control);
+	saa_writeb(SAA7134_LUMA_CTRL,             luma_control);
+	saa_writeb(SAA7134_DEC_LUMA_BRIGHT,       dev->ctl_bright);
+
+	saa_writeb(SAA7134_DEC_LUMA_CONTRAST,
+		dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);
+
+	saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
+		dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
+
+	saa_writeb(SAA7134_DEC_CHROMA_HUE,        dev->ctl_hue);
+	saa_writeb(SAA7134_CHROMA_CTRL1,          norm->chroma_ctrl1);
+	saa_writeb(SAA7134_CHROMA_GAIN,           norm->chroma_gain);
+
+	saa_writeb(SAA7134_CHROMA_CTRL2,          norm->chroma_ctrl2);
+	saa_writeb(SAA7134_MODE_DELAY_CTRL,       0x00);
+
+	saa_writeb(SAA7134_ANALOG_ADC,            0x01);
+	saa_writeb(SAA7134_VGATE_START,           0x11);
+	saa_writeb(SAA7134_VGATE_STOP,            0xfe);
+	saa_writeb(SAA7134_MISC_VGATE_MSB,        norm->vgate_misc);
+	saa_writeb(SAA7134_RAW_DATA_GAIN,         0x40);
+	saa_writeb(SAA7134_RAW_DATA_OFFSET,       0x80);
+}
+
+void saa7134_set_tvnorm_hw(struct saa7134_dev *dev)
+{
+	saa7134_set_decoder(dev);
+
+	if (card_in(dev, dev->ctl_input).tv)
+		saa_call_all(dev, core, s_std, dev->tvnorm->id);
+	/* Set the correct norm for the saa6752hs. This function
+	   does nothing if there is no saa6752hs. */
+	saa_call_empress(dev, core, s_std, dev->tvnorm->id);
+}
+
+static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
+{
+	static const struct {
+		int xpsc;
+		int xacl;
+		int xc2_1;
+		int xdcg;
+		int vpfy;
+	} vals[] = {
+		/* XPSC XACL XC2_1 XDCG VPFY */
+		{    1,   0,    0,    0,   0 },
+		{    2,   2,    1,    2,   2 },
+		{    3,   4,    1,    3,   2 },
+		{    4,   8,    1,    4,   2 },
+		{    5,   8,    1,    4,   2 },
+		{    6,   8,    1,    4,   3 },
+		{    7,   8,    1,    4,   3 },
+		{    8,  15,    0,    4,   3 },
+		{    9,  15,    0,    4,   3 },
+		{   10,  16,    1,    5,   3 },
+	};
+	static const int count = ARRAY_SIZE(vals);
+	int i;
+
+	for (i = 0; i < count; i++)
+		if (vals[i].xpsc == prescale)
+			break;
+	if (i == count)
+		return;
+
+	saa_writeb(SAA7134_H_PRESCALE(task), vals[i].xpsc);
+	saa_writeb(SAA7134_ACC_LENGTH(task), vals[i].xacl);
+	saa_writeb(SAA7134_LEVEL_CTRL(task),
+		   (vals[i].xc2_1 << 3) | (vals[i].xdcg));
+	saa_andorb(SAA7134_FIR_PREFILTER_CTRL(task), 0x0f,
+		   (vals[i].vpfy << 2) | vals[i].vpfy);
+}
+
+static void set_v_scale(struct saa7134_dev *dev, int task, int yscale)
+{
+	int val,mirror;
+
+	saa_writeb(SAA7134_V_SCALE_RATIO1(task), yscale &  0xff);
+	saa_writeb(SAA7134_V_SCALE_RATIO2(task), yscale >> 8);
+
+	mirror = (dev->ctl_mirror) ? 0x02 : 0x00;
+	if (yscale < 2048) {
+		/* LPI */
+		dprintk("yscale LPI yscale=%d\n",yscale);
+		saa_writeb(SAA7134_V_FILTER(task), 0x00 | mirror);
+		saa_writeb(SAA7134_LUMA_CONTRAST(task), 0x40);
+		saa_writeb(SAA7134_CHROMA_SATURATION(task), 0x40);
+	} else {
+		/* ACM */
+		val = 0x40 * 1024 / yscale;
+		dprintk("yscale ACM yscale=%d val=0x%x\n",yscale,val);
+		saa_writeb(SAA7134_V_FILTER(task), 0x01 | mirror);
+		saa_writeb(SAA7134_LUMA_CONTRAST(task), val);
+		saa_writeb(SAA7134_CHROMA_SATURATION(task), val);
+	}
+	saa_writeb(SAA7134_LUMA_BRIGHT(task),       0x80);
+}
+
+static void set_size(struct saa7134_dev *dev, int task,
+		     int width, int height, int interlace)
+{
+	int prescale,xscale,yscale,y_even,y_odd;
+	int h_start, h_stop, v_start, v_stop;
+	int div = interlace ? 2 : 1;
+
+	/* setup video scaler */
+	h_start = dev->crop_current.left;
+	v_start = dev->crop_current.top/2;
+	h_stop  = (dev->crop_current.left + dev->crop_current.width -1);
+	v_stop  = (dev->crop_current.top + dev->crop_current.height -1)/2;
+
+	saa_writeb(SAA7134_VIDEO_H_START1(task), h_start &  0xff);
+	saa_writeb(SAA7134_VIDEO_H_START2(task), h_start >> 8);
+	saa_writeb(SAA7134_VIDEO_H_STOP1(task),  h_stop  &  0xff);
+	saa_writeb(SAA7134_VIDEO_H_STOP2(task),  h_stop  >> 8);
+	saa_writeb(SAA7134_VIDEO_V_START1(task), v_start &  0xff);
+	saa_writeb(SAA7134_VIDEO_V_START2(task), v_start >> 8);
+	saa_writeb(SAA7134_VIDEO_V_STOP1(task),  v_stop  &  0xff);
+	saa_writeb(SAA7134_VIDEO_V_STOP2(task),  v_stop  >> 8);
+
+	prescale = dev->crop_current.width / width;
+	if (0 == prescale)
+		prescale = 1;
+	xscale = 1024 * dev->crop_current.width / prescale / width;
+	yscale = 512 * div * dev->crop_current.height / height;
+	dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale);
+	set_h_prescale(dev,task,prescale);
+	saa_writeb(SAA7134_H_SCALE_INC1(task),      xscale &  0xff);
+	saa_writeb(SAA7134_H_SCALE_INC2(task),      xscale >> 8);
+	set_v_scale(dev,task,yscale);
+
+	saa_writeb(SAA7134_VIDEO_PIXELS1(task),     width  & 0xff);
+	saa_writeb(SAA7134_VIDEO_PIXELS2(task),     width  >> 8);
+	saa_writeb(SAA7134_VIDEO_LINES1(task),      height/div & 0xff);
+	saa_writeb(SAA7134_VIDEO_LINES2(task),      height/div >> 8);
+
+	/* deinterlace y offsets */
+	y_odd  = dev->ctl_y_odd;
+	y_even = dev->ctl_y_even;
+	saa_writeb(SAA7134_V_PHASE_OFFSET0(task), y_odd);
+	saa_writeb(SAA7134_V_PHASE_OFFSET1(task), y_even);
+	saa_writeb(SAA7134_V_PHASE_OFFSET2(task), y_odd);
+	saa_writeb(SAA7134_V_PHASE_OFFSET3(task), y_even);
+}
+
+/* ------------------------------------------------------------------ */
+
+struct cliplist {
+	__u16 position;
+	__u8  enable;
+	__u8  disable;
+};
+
+static void set_cliplist(struct saa7134_dev *dev, int reg,
+			struct cliplist *cl, int entries, char *name)
+{
+	__u8 winbits = 0;
+	int i;
+
+	for (i = 0; i < entries; i++) {
+		winbits |= cl[i].enable;
+		winbits &= ~cl[i].disable;
+		if (i < 15 && cl[i].position == cl[i+1].position)
+			continue;
+		saa_writeb(reg + 0, winbits);
+		saa_writeb(reg + 2, cl[i].position & 0xff);
+		saa_writeb(reg + 3, cl[i].position >> 8);
+		dprintk("clip: %s winbits=%02x pos=%d\n",
+			name,winbits,cl[i].position);
+		reg += 8;
+	}
+	for (; reg < 0x400; reg += 8) {
+		saa_writeb(reg+ 0, 0);
+		saa_writeb(reg + 1, 0);
+		saa_writeb(reg + 2, 0);
+		saa_writeb(reg + 3, 0);
+	}
+}
+
+static int clip_range(int val)
+{
+	if (val < 0)
+		val = 0;
+	return val;
+}
+
+/* Sort into smallest position first order */
+static int cliplist_cmp(const void *a, const void *b)
+{
+	const struct cliplist *cla = a;
+	const struct cliplist *clb = b;
+	if (cla->position < clb->position)
+		return -1;
+	if (cla->position > clb->position)
+		return 1;
+	return 0;
+}
+
+static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips,
+			  int nclips, int interlace)
+{
+	struct cliplist col[16], row[16];
+	int cols = 0, rows = 0, i;
+	int div = interlace ? 2 : 1;
+
+	memset(col, 0, sizeof(col));
+	memset(row, 0, sizeof(row));
+	for (i = 0; i < nclips && i < 8; i++) {
+		col[cols].position = clip_range(clips[i].c.left);
+		col[cols].enable   = (1 << i);
+		cols++;
+		col[cols].position = clip_range(clips[i].c.left+clips[i].c.width);
+		col[cols].disable  = (1 << i);
+		cols++;
+		row[rows].position = clip_range(clips[i].c.top / div);
+		row[rows].enable   = (1 << i);
+		rows++;
+		row[rows].position = clip_range((clips[i].c.top + clips[i].c.height)
+						/ div);
+		row[rows].disable  = (1 << i);
+		rows++;
+	}
+	sort(col, cols, sizeof col[0], cliplist_cmp, NULL);
+	sort(row, rows, sizeof row[0], cliplist_cmp, NULL);
+	set_cliplist(dev,0x380,col,cols,"cols");
+	set_cliplist(dev,0x384,row,rows,"rows");
+	return 0;
+}
+
+static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win)
+{
+	enum v4l2_field field;
+	int maxw, maxh;
+
+	if (NULL == dev->ovbuf.base)
+		return -EINVAL;
+	if (NULL == dev->ovfmt)
+		return -EINVAL;
+	if (win->w.width < 48 || win->w.height <  32)
+		return -EINVAL;
+	if (win->clipcount > 2048)
+		return -EINVAL;
+
+	field = win->field;
+	maxw  = dev->crop_current.width;
+	maxh  = dev->crop_current.height;
+
+	if (V4L2_FIELD_ANY == field) {
+		field = (win->w.height > maxh/2)
+			? V4L2_FIELD_INTERLACED
+			: V4L2_FIELD_TOP;
+	}
+	switch (field) {
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+		maxh = maxh / 2;
+		break;
+	case V4L2_FIELD_INTERLACED:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	win->field = field;
+	if (win->w.width > maxw)
+		win->w.width = maxw;
+	if (win->w.height > maxh)
+		win->w.height = maxh;
+	return 0;
+}
+
+static int start_preview(struct saa7134_dev *dev, struct saa7134_fh *fh)
+{
+	unsigned long base,control,bpl;
+	int err;
+
+	err = verify_preview(dev,&fh->win);
+	if (0 != err)
+		return err;
+
+	dev->ovfield = fh->win.field;
+	dprintk("start_preview %dx%d+%d+%d %s field=%s\n",
+		fh->win.w.width,fh->win.w.height,
+		fh->win.w.left,fh->win.w.top,
+		dev->ovfmt->name,v4l2_field_names[dev->ovfield]);
+
+	/* setup window + clipping */
+	set_size(dev,TASK_B,fh->win.w.width,fh->win.w.height,
+		 V4L2_FIELD_HAS_BOTH(dev->ovfield));
+	setup_clipping(dev,fh->clips,fh->nclips,
+		       V4L2_FIELD_HAS_BOTH(dev->ovfield));
+	if (dev->ovfmt->yuv)
+		saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x03);
+	else
+		saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x01);
+	saa_writeb(SAA7134_OFMT_VIDEO_B, dev->ovfmt->pm | 0x20);
+
+	/* dma: setup channel 1 (= Video Task B) */
+	base  = (unsigned long)dev->ovbuf.base;
+	base += dev->ovbuf.fmt.bytesperline * fh->win.w.top;
+	base += dev->ovfmt->depth/8         * fh->win.w.left;
+	bpl   = dev->ovbuf.fmt.bytesperline;
+	control = SAA7134_RS_CONTROL_BURST_16;
+	if (dev->ovfmt->bswap)
+		control |= SAA7134_RS_CONTROL_BSWAP;
+	if (dev->ovfmt->wswap)
+		control |= SAA7134_RS_CONTROL_WSWAP;
+	if (V4L2_FIELD_HAS_BOTH(dev->ovfield)) {
+		saa_writel(SAA7134_RS_BA1(1),base);
+		saa_writel(SAA7134_RS_BA2(1),base+bpl);
+		saa_writel(SAA7134_RS_PITCH(1),bpl*2);
+		saa_writel(SAA7134_RS_CONTROL(1),control);
+	} else {
+		saa_writel(SAA7134_RS_BA1(1),base);
+		saa_writel(SAA7134_RS_BA2(1),base);
+		saa_writel(SAA7134_RS_PITCH(1),bpl);
+		saa_writel(SAA7134_RS_CONTROL(1),control);
+	}
+
+	/* start dma */
+	dev->ovenable = 1;
+	saa7134_set_dmabits(dev);
+
+	return 0;
+}
+
+static int stop_preview(struct saa7134_dev *dev, struct saa7134_fh *fh)
+{
+	dev->ovenable = 0;
+	saa7134_set_dmabits(dev);
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int buffer_activate(struct saa7134_dev *dev,
+			   struct saa7134_buf *buf,
+			   struct saa7134_buf *next)
+{
+	unsigned long base,control,bpl;
+	unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */
+
+	dprintk("buffer_activate buf=%p\n",buf);
+	buf->vb.state = VIDEOBUF_ACTIVE;
+	buf->top_seen = 0;
+
+	set_size(dev,TASK_A,buf->vb.width,buf->vb.height,
+		 V4L2_FIELD_HAS_BOTH(buf->vb.field));
+	if (buf->fmt->yuv)
+		saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x03);
+	else
+		saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x01);
+	saa_writeb(SAA7134_OFMT_VIDEO_A, buf->fmt->pm);
+
+	/* DMA: setup channel 0 (= Video Task A0) */
+	base  = saa7134_buffer_base(buf);
+	if (buf->fmt->planar)
+		bpl = buf->vb.width;
+	else
+		bpl = (buf->vb.width * buf->fmt->depth) / 8;
+	control = SAA7134_RS_CONTROL_BURST_16 |
+		SAA7134_RS_CONTROL_ME |
+		(buf->pt->dma >> 12);
+	if (buf->fmt->bswap)
+		control |= SAA7134_RS_CONTROL_BSWAP;
+	if (buf->fmt->wswap)
+		control |= SAA7134_RS_CONTROL_WSWAP;
+	if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) {
+		/* interlaced */
+		saa_writel(SAA7134_RS_BA1(0),base);
+		saa_writel(SAA7134_RS_BA2(0),base+bpl);
+		saa_writel(SAA7134_RS_PITCH(0),bpl*2);
+	} else {
+		/* non-interlaced */
+		saa_writel(SAA7134_RS_BA1(0),base);
+		saa_writel(SAA7134_RS_BA2(0),base);
+		saa_writel(SAA7134_RS_PITCH(0),bpl);
+	}
+	saa_writel(SAA7134_RS_CONTROL(0),control);
+
+	if (buf->fmt->planar) {
+		/* DMA: setup channel 4+5 (= planar task A) */
+		bpl_uv   = bpl >> buf->fmt->hshift;
+		lines_uv = buf->vb.height >> buf->fmt->vshift;
+		base2    = base + bpl * buf->vb.height;
+		base3    = base2 + bpl_uv * lines_uv;
+		if (buf->fmt->uvswap)
+			tmp = base2, base2 = base3, base3 = tmp;
+		dprintk("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n",
+			bpl_uv,lines_uv,base2,base3);
+		if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) {
+			/* interlaced */
+			saa_writel(SAA7134_RS_BA1(4),base2);
+			saa_writel(SAA7134_RS_BA2(4),base2+bpl_uv);
+			saa_writel(SAA7134_RS_PITCH(4),bpl_uv*2);
+			saa_writel(SAA7134_RS_BA1(5),base3);
+			saa_writel(SAA7134_RS_BA2(5),base3+bpl_uv);
+			saa_writel(SAA7134_RS_PITCH(5),bpl_uv*2);
+		} else {
+			/* non-interlaced */
+			saa_writel(SAA7134_RS_BA1(4),base2);
+			saa_writel(SAA7134_RS_BA2(4),base2);
+			saa_writel(SAA7134_RS_PITCH(4),bpl_uv);
+			saa_writel(SAA7134_RS_BA1(5),base3);
+			saa_writel(SAA7134_RS_BA2(5),base3);
+			saa_writel(SAA7134_RS_PITCH(5),bpl_uv);
+		}
+		saa_writel(SAA7134_RS_CONTROL(4),control);
+		saa_writel(SAA7134_RS_CONTROL(5),control);
+	}
+
+	/* start DMA */
+	saa7134_set_dmabits(dev);
+	mod_timer(&dev->video_q.timeout, jiffies+BUFFER_TIMEOUT);
+	return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *q,
+			  struct videobuf_buffer *vb,
+			  enum v4l2_field field)
+{
+	struct saa7134_fh *fh = q->priv_data;
+	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+	unsigned int size;
+	int err;
+
+	/* sanity checks */
+	if (NULL == fh->fmt)
+		return -EINVAL;
+	if (fh->width    < 48 ||
+	    fh->height   < 32 ||
+	    fh->width/4  > dev->crop_current.width  ||
+	    fh->height/4 > dev->crop_current.height ||
+	    fh->width    > dev->crop_bounds.width  ||
+	    fh->height   > dev->crop_bounds.height)
+		return -EINVAL;
+	size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+		return -EINVAL;
+
+	dprintk("buffer_prepare [%d,size=%dx%d,bytes=%d,fields=%s,%s]\n",
+		vb->i,fh->width,fh->height,size,v4l2_field_names[field],
+		fh->fmt->name);
+	if (buf->vb.width  != fh->width  ||
+	    buf->vb.height != fh->height ||
+	    buf->vb.size   != size       ||
+	    buf->vb.field  != field      ||
+	    buf->fmt       != fh->fmt) {
+		saa7134_dma_free(q,buf);
+	}
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
+		buf->vb.width  = fh->width;
+		buf->vb.height = fh->height;
+		buf->vb.size   = size;
+		buf->vb.field  = field;
+		buf->fmt       = fh->fmt;
+		buf->pt        = &fh->pt_cap;
+		dev->video_q.curr = NULL;
+
+		err = videobuf_iolock(q,&buf->vb,&dev->ovbuf);
+		if (err)
+			goto oops;
+		err = saa7134_pgtable_build(dev->pci,buf->pt,
+					    dma->sglist,
+					    dma->sglen,
+					    saa7134_buffer_startpage(buf));
+		if (err)
+			goto oops;
+	}
+	buf->vb.state = VIDEOBUF_PREPARED;
+	buf->activate = buffer_activate;
+	return 0;
+
+ oops:
+	saa7134_dma_free(q,buf);
+	return err;
+}
+
+static int
+buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+	struct saa7134_fh *fh = q->priv_data;
+
+	*size = fh->fmt->depth * fh->width * fh->height >> 3;
+	if (0 == *count)
+		*count = gbuffers;
+	*count = saa7134_buffer_count(*size,*count);
+	return 0;
+}
+
+static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct saa7134_fh *fh = q->priv_data;
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+
+	saa7134_buffer_queue(fh->dev,&fh->dev->video_q,buf);
+}
+
+static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+
+	saa7134_dma_free(q,buf);
+}
+
+static struct videobuf_queue_ops video_qops = {
+	.buf_setup    = buffer_setup,
+	.buf_prepare  = buffer_prepare,
+	.buf_queue    = buffer_queue,
+	.buf_release  = buffer_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c)
+{
+	const struct v4l2_queryctrl* ctrl;
+
+	ctrl = ctrl_by_id(c->id);
+	if (NULL == ctrl)
+		return -EINVAL;
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		c->value = dev->ctl_bright;
+		break;
+	case V4L2_CID_HUE:
+		c->value = dev->ctl_hue;
+		break;
+	case V4L2_CID_CONTRAST:
+		c->value = dev->ctl_contrast;
+		break;
+	case V4L2_CID_SATURATION:
+		c->value = dev->ctl_saturation;
+		break;
+	case V4L2_CID_AUDIO_MUTE:
+		c->value = dev->ctl_mute;
+		break;
+	case V4L2_CID_AUDIO_VOLUME:
+		c->value = dev->ctl_volume;
+		break;
+	case V4L2_CID_PRIVATE_INVERT:
+		c->value = dev->ctl_invert;
+		break;
+	case V4L2_CID_HFLIP:
+		c->value = dev->ctl_mirror;
+		break;
+	case V4L2_CID_PRIVATE_Y_EVEN:
+		c->value = dev->ctl_y_even;
+		break;
+	case V4L2_CID_PRIVATE_Y_ODD:
+		c->value = dev->ctl_y_odd;
+		break;
+	case V4L2_CID_PRIVATE_AUTOMUTE:
+		c->value = dev->ctl_automute;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_g_ctrl_internal);
+
+static int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c)
+{
+	struct saa7134_fh *fh = priv;
+
+	return saa7134_g_ctrl_internal(fh->dev, fh, c);
+}
+
+int saa7134_s_ctrl_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, struct v4l2_control *c)
+{
+	const struct v4l2_queryctrl* ctrl;
+	unsigned long flags;
+	int restart_overlay = 0;
+	int err;
+
+	/* When called from the empress code fh == NULL.
+	   That needs to be fixed somehow, but for now this is
+	   good enough. */
+	if (fh) {
+		err = v4l2_prio_check(&dev->prio, fh->prio);
+		if (0 != err)
+			return err;
+	}
+	err = -EINVAL;
+
+	mutex_lock(&dev->lock);
+
+	ctrl = ctrl_by_id(c->id);
+	if (NULL == ctrl)
+		goto error;
+
+	dprintk("set_control name=%s val=%d\n",ctrl->name,c->value);
+	switch (ctrl->type) {
+	case V4L2_CTRL_TYPE_BOOLEAN:
+	case V4L2_CTRL_TYPE_MENU:
+	case V4L2_CTRL_TYPE_INTEGER:
+		if (c->value < ctrl->minimum)
+			c->value = ctrl->minimum;
+		if (c->value > ctrl->maximum)
+			c->value = ctrl->maximum;
+		break;
+	default:
+		/* nothing */;
+	};
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		dev->ctl_bright = c->value;
+		saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright);
+		break;
+	case V4L2_CID_HUE:
+		dev->ctl_hue = c->value;
+		saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue);
+		break;
+	case V4L2_CID_CONTRAST:
+		dev->ctl_contrast = c->value;
+		saa_writeb(SAA7134_DEC_LUMA_CONTRAST,
+			   dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);
+		break;
+	case V4L2_CID_SATURATION:
+		dev->ctl_saturation = c->value;
+		saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
+			   dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
+		break;
+	case V4L2_CID_AUDIO_MUTE:
+		dev->ctl_mute = c->value;
+		saa7134_tvaudio_setmute(dev);
+		break;
+	case V4L2_CID_AUDIO_VOLUME:
+		dev->ctl_volume = c->value;
+		saa7134_tvaudio_setvolume(dev,dev->ctl_volume);
+		break;
+	case V4L2_CID_PRIVATE_INVERT:
+		dev->ctl_invert = c->value;
+		saa_writeb(SAA7134_DEC_LUMA_CONTRAST,
+			   dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);
+		saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
+			   dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
+		break;
+	case V4L2_CID_HFLIP:
+		dev->ctl_mirror = c->value;
+		restart_overlay = 1;
+		break;
+	case V4L2_CID_PRIVATE_Y_EVEN:
+		dev->ctl_y_even = c->value;
+		restart_overlay = 1;
+		break;
+	case V4L2_CID_PRIVATE_Y_ODD:
+		dev->ctl_y_odd = c->value;
+		restart_overlay = 1;
+		break;
+	case V4L2_CID_PRIVATE_AUTOMUTE:
+	{
+		struct v4l2_priv_tun_config tda9887_cfg;
+
+		tda9887_cfg.tuner = TUNER_TDA9887;
+		tda9887_cfg.priv = &dev->tda9887_conf;
+
+		dev->ctl_automute = c->value;
+		if (dev->tda9887_conf) {
+			if (dev->ctl_automute)
+				dev->tda9887_conf |= TDA9887_AUTOMUTE;
+			else
+				dev->tda9887_conf &= ~TDA9887_AUTOMUTE;
+
+			saa_call_all(dev, tuner, s_config, &tda9887_cfg);
+		}
+		break;
+	}
+	default:
+		goto error;
+	}
+	if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) {
+		spin_lock_irqsave(&dev->slock,flags);
+		stop_preview(dev,fh);
+		start_preview(dev,fh);
+		spin_unlock_irqrestore(&dev->slock,flags);
+	}
+	err = 0;
+
+error:
+	mutex_unlock(&dev->lock);
+	return err;
+}
+EXPORT_SYMBOL_GPL(saa7134_s_ctrl_internal);
+
+static int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c)
+{
+	struct saa7134_fh *fh = f;
+
+	return saa7134_s_ctrl_internal(fh->dev, fh, c);
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh)
+{
+	struct videobuf_queue* q = NULL;
+
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		q = &fh->cap;
+		break;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		q = &fh->vbi;
+		break;
+	default:
+		BUG();
+	}
+	return q;
+}
+
+static int saa7134_resource(struct saa7134_fh *fh)
+{
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return RESOURCE_VIDEO;
+
+	if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		return RESOURCE_VBI;
+
+	BUG();
+	return 0;
+}
+
+static int video_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct saa7134_dev *dev = video_drvdata(file);
+	struct saa7134_fh *fh;
+	enum v4l2_buf_type type = 0;
+	int radio = 0;
+
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_GRABBER:
+		type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		break;
+	case VFL_TYPE_VBI:
+		type = V4L2_BUF_TYPE_VBI_CAPTURE;
+		break;
+	case VFL_TYPE_RADIO:
+		radio = 1;
+		break;
+	}
+
+	dprintk("open dev=%s radio=%d type=%s\n", video_device_node_name(vdev),
+		radio, v4l2_type_names[type]);
+
+	/* allocate + initialize per filehandle data */
+	fh = kzalloc(sizeof(*fh),GFP_KERNEL);
+	if (NULL == fh)
+		return -ENOMEM;
+
+	file->private_data = fh;
+	fh->dev      = dev;
+	fh->radio    = radio;
+	fh->type     = type;
+	fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+	fh->width    = 720;
+	fh->height   = 576;
+	v4l2_prio_open(&dev->prio, &fh->prio);
+
+	videobuf_queue_sg_init(&fh->cap, &video_qops,
+			    &dev->pci->dev, &dev->slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			    V4L2_FIELD_INTERLACED,
+			    sizeof(struct saa7134_buf),
+			    fh, NULL);
+	videobuf_queue_sg_init(&fh->vbi, &saa7134_vbi_qops,
+			    &dev->pci->dev, &dev->slock,
+			    V4L2_BUF_TYPE_VBI_CAPTURE,
+			    V4L2_FIELD_SEQ_TB,
+			    sizeof(struct saa7134_buf),
+			    fh, NULL);
+	saa7134_pgtable_alloc(dev->pci,&fh->pt_cap);
+	saa7134_pgtable_alloc(dev->pci,&fh->pt_vbi);
+
+	if (fh->radio) {
+		/* switch to radio mode */
+		saa7134_tvaudio_setinput(dev,&card(dev).radio);
+		saa_call_all(dev, tuner, s_radio);
+	} else {
+		/* switch to video/vbi mode */
+		video_mux(dev,dev->ctl_input);
+	}
+	return 0;
+}
+
+static ssize_t
+video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+{
+	struct saa7134_fh *fh = file->private_data;
+
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		if (res_locked(fh->dev,RESOURCE_VIDEO))
+			return -EBUSY;
+		return videobuf_read_one(saa7134_queue(fh),
+					 data, count, ppos,
+					 file->f_flags & O_NONBLOCK);
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		if (!res_get(fh->dev,fh,RESOURCE_VBI))
+			return -EBUSY;
+		return videobuf_read_stream(saa7134_queue(fh),
+					    data, count, ppos, 1,
+					    file->f_flags & O_NONBLOCK);
+		break;
+	default:
+		BUG();
+		return 0;
+	}
+}
+
+static unsigned int
+video_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct saa7134_fh *fh = file->private_data;
+	struct videobuf_buffer *buf = NULL;
+	unsigned int rc = 0;
+
+	if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
+		return videobuf_poll_stream(file, &fh->vbi, wait);
+
+	if (res_check(fh,RESOURCE_VIDEO)) {
+		mutex_lock(&fh->cap.vb_lock);
+		if (!list_empty(&fh->cap.stream))
+			buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream);
+	} else {
+		mutex_lock(&fh->cap.vb_lock);
+		if (UNSET == fh->cap.read_off) {
+			/* need to capture a new frame */
+			if (res_locked(fh->dev,RESOURCE_VIDEO))
+				goto err;
+			if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field))
+				goto err;
+			fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
+			fh->cap.read_off = 0;
+		}
+		buf = fh->cap.read_buf;
+	}
+
+	if (!buf)
+		goto err;
+
+	poll_wait(file, &buf->done, wait);
+	if (buf->state == VIDEOBUF_DONE ||
+	    buf->state == VIDEOBUF_ERROR)
+		rc = POLLIN|POLLRDNORM;
+	mutex_unlock(&fh->cap.vb_lock);
+	return rc;
+
+err:
+	mutex_unlock(&fh->cap.vb_lock);
+	return POLLERR;
+}
+
+static int video_release(struct file *file)
+{
+	struct saa7134_fh  *fh  = file->private_data;
+	struct saa7134_dev *dev = fh->dev;
+	struct saa6588_command cmd;
+	unsigned long flags;
+
+	saa7134_tvaudio_close(dev);
+
+	/* turn off overlay */
+	if (res_check(fh, RESOURCE_OVERLAY)) {
+		spin_lock_irqsave(&dev->slock,flags);
+		stop_preview(dev,fh);
+		spin_unlock_irqrestore(&dev->slock,flags);
+		res_free(dev,fh,RESOURCE_OVERLAY);
+	}
+
+	/* stop video capture */
+	if (res_check(fh, RESOURCE_VIDEO)) {
+		videobuf_streamoff(&fh->cap);
+		res_free(dev,fh,RESOURCE_VIDEO);
+	}
+	if (fh->cap.read_buf) {
+		buffer_release(&fh->cap,fh->cap.read_buf);
+		kfree(fh->cap.read_buf);
+	}
+
+	/* stop vbi capture */
+	if (res_check(fh, RESOURCE_VBI)) {
+		videobuf_stop(&fh->vbi);
+		res_free(dev,fh,RESOURCE_VBI);
+	}
+
+	/* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/
+	saa_andorb(SAA7134_OFMT_VIDEO_A, 0x1f, 0);
+	saa_andorb(SAA7134_OFMT_VIDEO_B, 0x1f, 0);
+	saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0);
+	saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0);
+
+	saa_call_all(dev, core, s_power, 0);
+	if (fh->radio)
+		saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
+
+	/* free stuff */
+	videobuf_mmap_free(&fh->cap);
+	videobuf_mmap_free(&fh->vbi);
+	saa7134_pgtable_free(dev->pci,&fh->pt_cap);
+	saa7134_pgtable_free(dev->pci,&fh->pt_vbi);
+
+	v4l2_prio_close(&dev->prio, fh->prio);
+	file->private_data = NULL;
+	kfree(fh);
+	return 0;
+}
+
+static int video_mmap(struct file *file, struct vm_area_struct * vma)
+{
+	struct saa7134_fh *fh = file->private_data;
+
+	return videobuf_mmap_mapper(saa7134_queue(fh), vma);
+}
+
+static ssize_t radio_read(struct file *file, char __user *data,
+			 size_t count, loff_t *ppos)
+{
+	struct saa7134_fh *fh = file->private_data;
+	struct saa7134_dev *dev = fh->dev;
+	struct saa6588_command cmd;
+
+	cmd.block_count = count/3;
+	cmd.buffer = data;
+	cmd.instance = file;
+	cmd.result = -ENODEV;
+
+	saa_call_all(dev, core, ioctl, SAA6588_CMD_READ, &cmd);
+
+	return cmd.result;
+}
+
+static unsigned int radio_poll(struct file *file, poll_table *wait)
+{
+	struct saa7134_fh *fh = file->private_data;
+	struct saa7134_dev *dev = fh->dev;
+	struct saa6588_command cmd;
+
+	cmd.instance = file;
+	cmd.event_list = wait;
+	cmd.result = -ENODEV;
+	saa_call_all(dev, core, ioctl, SAA6588_CMD_POLL, &cmd);
+
+	return cmd.result;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv,
+						struct v4l2_format *f)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_tvnorm *norm = dev->tvnorm;
+
+	f->fmt.vbi.sampling_rate = 6750000 * 4;
+	f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */;
+	f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+	f->fmt.vbi.offset = 64 * 4;
+	f->fmt.vbi.start[0] = norm->vbi_v_start_0;
+	f->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1;
+	f->fmt.vbi.start[1] = norm->vbi_v_start_1;
+	f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
+	f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */
+
+	return 0;
+}
+
+static int saa7134_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct saa7134_fh *fh = priv;
+
+	f->fmt.pix.width        = fh->width;
+	f->fmt.pix.height       = fh->height;
+	f->fmt.pix.field        = fh->cap.field;
+	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * fh->fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+	return 0;
+}
+
+static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct saa7134_fh *fh = priv;
+
+	if (saa7134_no_overlay > 0) {
+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+		return -EINVAL;
+	}
+	f->fmt.win = fh->win;
+
+	return 0;
+}
+
+static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
+						struct v4l2_format *f)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_format *fmt;
+	enum v4l2_field field;
+	unsigned int maxw, maxh;
+
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	if (NULL == fmt)
+		return -EINVAL;
+
+	field = f->fmt.pix.field;
+	maxw  = min(dev->crop_current.width*4,  dev->crop_bounds.width);
+	maxh  = min(dev->crop_current.height*4, dev->crop_bounds.height);
+
+	if (V4L2_FIELD_ANY == field) {
+		field = (f->fmt.pix.height > maxh/2)
+			? V4L2_FIELD_INTERLACED
+			: V4L2_FIELD_BOTTOM;
+	}
+	switch (field) {
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+		maxh = maxh / 2;
+		break;
+	case V4L2_FIELD_INTERLACED:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	f->fmt.pix.field = field;
+	if (f->fmt.pix.width  < 48)
+		f->fmt.pix.width  = 48;
+	if (f->fmt.pix.height < 32)
+		f->fmt.pix.height = 32;
+	if (f->fmt.pix.width > maxw)
+		f->fmt.pix.width = maxw;
+	if (f->fmt.pix.height > maxh)
+		f->fmt.pix.height = maxh;
+	f->fmt.pix.width &= ~0x03;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return 0;
+}
+
+static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv,
+						struct v4l2_format *f)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	if (saa7134_no_overlay > 0) {
+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+		return -EINVAL;
+	}
+
+	return verify_preview(dev, &f->fmt.win);
+}
+
+static int saa7134_s_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct saa7134_fh *fh = priv;
+	int err;
+
+	err = saa7134_try_fmt_vid_cap(file, priv, f);
+	if (0 != err)
+		return err;
+
+	fh->fmt       = format_by_fourcc(f->fmt.pix.pixelformat);
+	fh->width     = f->fmt.pix.width;
+	fh->height    = f->fmt.pix.height;
+	fh->cap.field = f->fmt.pix.field;
+	return 0;
+}
+
+static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	int err;
+	unsigned long flags;
+
+	if (saa7134_no_overlay > 0) {
+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+		return -EINVAL;
+	}
+	err = verify_preview(dev, &f->fmt.win);
+	if (0 != err)
+		return err;
+
+	mutex_lock(&dev->lock);
+
+	fh->win    = f->fmt.win;
+	fh->nclips = f->fmt.win.clipcount;
+
+	if (fh->nclips > 8)
+		fh->nclips = 8;
+
+	if (copy_from_user(fh->clips, f->fmt.win.clips,
+			   sizeof(struct v4l2_clip)*fh->nclips)) {
+		mutex_unlock(&dev->lock);
+		return -EFAULT;
+	}
+
+	if (res_check(fh, RESOURCE_OVERLAY)) {
+		spin_lock_irqsave(&dev->slock, flags);
+		stop_preview(dev, fh);
+		start_preview(dev, fh);
+		spin_unlock_irqrestore(&dev->slock, flags);
+	}
+
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c)
+{
+	const struct v4l2_queryctrl *ctrl;
+
+	if ((c->id <  V4L2_CID_BASE ||
+	     c->id >= V4L2_CID_LASTP1) &&
+	    (c->id <  V4L2_CID_PRIVATE_BASE ||
+	     c->id >= V4L2_CID_PRIVATE_LASTP1))
+		return -EINVAL;
+	ctrl = ctrl_by_id(c->id);
+	*c = (NULL != ctrl) ? *ctrl : no_ctrl;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_queryctrl);
+
+static int saa7134_enum_input(struct file *file, void *priv,
+					struct v4l2_input *i)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	unsigned int n;
+
+	n = i->index;
+	if (n >= SAA7134_INPUT_MAX)
+		return -EINVAL;
+	if (NULL == card_in(dev, i->index).name)
+		return -EINVAL;
+	i->index = n;
+	i->type  = V4L2_INPUT_TYPE_CAMERA;
+	strcpy(i->name, card_in(dev, n).name);
+	if (card_in(dev, n).tv)
+		i->type = V4L2_INPUT_TYPE_TUNER;
+	i->audioset = 1;
+	if (n == dev->ctl_input) {
+		int v1 = saa_readb(SAA7134_STATUS_VIDEO1);
+		int v2 = saa_readb(SAA7134_STATUS_VIDEO2);
+
+		if (0 != (v1 & 0x40))
+			i->status |= V4L2_IN_ST_NO_H_LOCK;
+		if (0 != (v2 & 0x40))
+			i->status |= V4L2_IN_ST_NO_SYNC;
+		if (0 != (v2 & 0x0e))
+			i->status |= V4L2_IN_ST_MACROVISION;
+	}
+	i->std = SAA7134_NORMS;
+	return 0;
+}
+
+static int saa7134_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	*i = dev->ctl_input;
+	return 0;
+}
+
+static int saa7134_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	int err;
+
+	err = v4l2_prio_check(&dev->prio, fh->prio);
+	if (0 != err)
+		return err;
+
+	if (i >= SAA7134_INPUT_MAX)
+		return -EINVAL;
+	if (NULL == card_in(dev, i).name)
+		return -EINVAL;
+	mutex_lock(&dev->lock);
+	video_mux(dev, i);
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int saa7134_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *cap)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	unsigned int tuner_type = dev->tuner_type;
+
+	strcpy(cap->driver, "saa7134");
+	strlcpy(cap->card, saa7134_boards[dev->board].name,
+		sizeof(cap->card));
+	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+	cap->capabilities =
+		V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_VBI_CAPTURE |
+		V4L2_CAP_READWRITE |
+		V4L2_CAP_STREAMING |
+		V4L2_CAP_TUNER;
+	if (dev->has_rds)
+		cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
+	if (saa7134_no_overlay <= 0)
+		cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+
+	if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
+		cap->capabilities &= ~V4L2_CAP_TUNER;
+	return 0;
+}
+
+int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id)
+{
+	unsigned long flags;
+	unsigned int i;
+	v4l2_std_id fixup;
+	int err;
+
+	/* When called from the empress code fh == NULL.
+	   That needs to be fixed somehow, but for now this is
+	   good enough. */
+	if (fh) {
+		err = v4l2_prio_check(&dev->prio, fh->prio);
+		if (0 != err)
+			return err;
+	} else if (res_locked(dev, RESOURCE_OVERLAY)) {
+		/* Don't change the std from the mpeg device
+		   if overlay is active. */
+		return -EBUSY;
+	}
+
+	for (i = 0; i < TVNORMS; i++)
+		if (*id == tvnorms[i].id)
+			break;
+
+	if (i == TVNORMS)
+		for (i = 0; i < TVNORMS; i++)
+			if (*id & tvnorms[i].id)
+				break;
+	if (i == TVNORMS)
+		return -EINVAL;
+
+	if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) {
+		if (secam[0] == 'L' || secam[0] == 'l') {
+			if (secam[1] == 'C' || secam[1] == 'c')
+				fixup = V4L2_STD_SECAM_LC;
+			else
+				fixup = V4L2_STD_SECAM_L;
+		} else {
+			if (secam[0] == 'D' || secam[0] == 'd')
+				fixup = V4L2_STD_SECAM_DK;
+			else
+				fixup = V4L2_STD_SECAM;
+		}
+		for (i = 0; i < TVNORMS; i++) {
+			if (fixup == tvnorms[i].id)
+				break;
+		}
+		if (i == TVNORMS)
+			return -EINVAL;
+	}
+
+	*id = tvnorms[i].id;
+
+	mutex_lock(&dev->lock);
+	if (fh && res_check(fh, RESOURCE_OVERLAY)) {
+		spin_lock_irqsave(&dev->slock, flags);
+		stop_preview(dev, fh);
+		spin_unlock_irqrestore(&dev->slock, flags);
+
+		set_tvnorm(dev, &tvnorms[i]);
+
+		spin_lock_irqsave(&dev->slock, flags);
+		start_preview(dev, fh);
+		spin_unlock_irqrestore(&dev->slock, flags);
+	} else
+		set_tvnorm(dev, &tvnorms[i]);
+
+	saa7134_tvaudio_do_scan(dev);
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_s_std_internal);
+
+static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct saa7134_fh *fh = priv;
+
+	return saa7134_s_std_internal(fh->dev, fh, id);
+}
+
+static int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	*id = dev->tvnorm->id;
+	return 0;
+}
+
+static int saa7134_cropcap(struct file *file, void *priv,
+					struct v4l2_cropcap *cap)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
+	cap->bounds  = dev->crop_bounds;
+	cap->defrect = dev->crop_defrect;
+	cap->pixelaspect.numerator   = 1;
+	cap->pixelaspect.denominator = 1;
+	if (dev->tvnorm->id & V4L2_STD_525_60) {
+		cap->pixelaspect.numerator   = 11;
+		cap->pixelaspect.denominator = 10;
+	}
+	if (dev->tvnorm->id & V4L2_STD_625_50) {
+		cap->pixelaspect.numerator   = 54;
+		cap->pixelaspect.denominator = 59;
+	}
+	return 0;
+}
+
+static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
+{
+	struct saa7134_fh *fh = f;
+	struct saa7134_dev *dev = fh->dev;
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
+	crop->c = dev->crop_current;
+	return 0;
+}
+
+static int saa7134_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
+{
+	struct saa7134_fh *fh = f;
+	struct saa7134_dev *dev = fh->dev;
+	struct v4l2_rect *b = &dev->crop_bounds;
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
+	if (crop->c.height < 0)
+		return -EINVAL;
+	if (crop->c.width < 0)
+		return -EINVAL;
+
+	if (res_locked(fh->dev, RESOURCE_OVERLAY))
+		return -EBUSY;
+	if (res_locked(fh->dev, RESOURCE_VIDEO))
+		return -EBUSY;
+
+	if (crop->c.top < b->top)
+		crop->c.top = b->top;
+	if (crop->c.top > b->top + b->height)
+		crop->c.top = b->top + b->height;
+	if (crop->c.height > b->top - crop->c.top + b->height)
+		crop->c.height = b->top - crop->c.top + b->height;
+
+	if (crop->c.left < b->left)
+		crop->c.left = b->left;
+	if (crop->c.left > b->left + b->width)
+		crop->c.left = b->left + b->width;
+	if (crop->c.width > b->left - crop->c.left + b->width)
+		crop->c.width = b->left - crop->c.left + b->width;
+
+	dev->crop_current = crop->c;
+	return 0;
+}
+
+static int saa7134_g_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *t)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	int n;
+
+	if (0 != t->index)
+		return -EINVAL;
+	memset(t, 0, sizeof(*t));
+	for (n = 0; n < SAA7134_INPUT_MAX; n++) {
+		if (card_in(dev, n).tv)
+			break;
+	}
+	if (n == SAA7134_INPUT_MAX)
+		return -EINVAL;
+	if (NULL != card_in(dev, n).name) {
+		strcpy(t->name, "Television");
+		t->type = V4L2_TUNER_ANALOG_TV;
+		t->capability = V4L2_TUNER_CAP_NORM |
+			V4L2_TUNER_CAP_STEREO |
+			V4L2_TUNER_CAP_LANG1 |
+			V4L2_TUNER_CAP_LANG2;
+		t->rangehigh = 0xffffffffUL;
+		t->rxsubchans = saa7134_tvaudio_getstereo(dev);
+		t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);
+	}
+	if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03))
+		t->signal = 0xffff;
+	return 0;
+}
+
+static int saa7134_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *t)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	int rx, mode, err;
+
+	err = v4l2_prio_check(&dev->prio, fh->prio);
+	if (0 != err)
+		return err;
+
+	mode = dev->thread.mode;
+	if (UNSET == mode) {
+		rx   = saa7134_tvaudio_getstereo(dev);
+		mode = saa7134_tvaudio_rx2mode(rx);
+	}
+	if (mode != t->audmode)
+		dev->thread.mode = t->audmode;
+
+	return 0;
+}
+
+static int saa7134_g_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+	f->frequency = dev->ctl_freq;
+
+	return 0;
+}
+
+static int saa7134_s_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	int err;
+
+	err = v4l2_prio_check(&dev->prio, fh->prio);
+	if (0 != err)
+		return err;
+
+	if (0 != f->tuner)
+		return -EINVAL;
+	if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
+		return -EINVAL;
+	if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
+		return -EINVAL;
+	mutex_lock(&dev->lock);
+	dev->ctl_freq = f->frequency;
+
+	saa_call_all(dev, tuner, s_frequency, f);
+
+	saa7134_tvaudio_do_scan(dev);
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int saa7134_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	strcpy(a->name, "audio");
+	return 0;
+}
+
+static int saa7134_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	return 0;
+}
+
+static int saa7134_g_priority(struct file *file, void *f, enum v4l2_priority *p)
+{
+	struct saa7134_fh *fh = f;
+	struct saa7134_dev *dev = fh->dev;
+
+	*p = v4l2_prio_max(&dev->prio);
+	return 0;
+}
+
+static int saa7134_s_priority(struct file *file, void *f,
+					enum v4l2_priority prio)
+{
+	struct saa7134_fh *fh = f;
+	struct saa7134_dev *dev = fh->dev;
+
+	return v4l2_prio_change(&dev->prio, &fh->prio, prio);
+}
+
+static int saa7134_enum_fmt_vid_cap(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	if (f->index >= FORMATS)
+		return -EINVAL;
+
+	strlcpy(f->description, formats[f->index].name,
+		sizeof(f->description));
+
+	f->pixelformat = formats[f->index].fourcc;
+
+	return 0;
+}
+
+static int saa7134_enum_fmt_vid_overlay(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	if (saa7134_no_overlay > 0) {
+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+		return -EINVAL;
+	}
+
+	if ((f->index >= FORMATS) || formats[f->index].planar)
+		return -EINVAL;
+
+	strlcpy(f->description, formats[f->index].name,
+		sizeof(f->description));
+
+	f->pixelformat = formats[f->index].fourcc;
+
+	return 0;
+}
+
+static int saa7134_g_fbuf(struct file *file, void *f,
+				struct v4l2_framebuffer *fb)
+{
+	struct saa7134_fh *fh = f;
+	struct saa7134_dev *dev = fh->dev;
+
+	*fb = dev->ovbuf;
+	fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+
+	return 0;
+}
+
+static int saa7134_s_fbuf(struct file *file, void *f,
+					struct v4l2_framebuffer *fb)
+{
+	struct saa7134_fh *fh = f;
+	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_format *fmt;
+
+	if (!capable(CAP_SYS_ADMIN) &&
+	   !capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	/* check args */
+	fmt = format_by_fourcc(fb->fmt.pixelformat);
+	if (NULL == fmt)
+		return -EINVAL;
+
+	/* ok, accept it */
+	dev->ovbuf = *fb;
+	dev->ovfmt = fmt;
+	if (0 == dev->ovbuf.fmt.bytesperline)
+		dev->ovbuf.fmt.bytesperline =
+			dev->ovbuf.fmt.width*fmt->depth/8;
+	return 0;
+}
+
+static int saa7134_overlay(struct file *file, void *f, unsigned int on)
+{
+	struct saa7134_fh *fh = f;
+	struct saa7134_dev *dev = fh->dev;
+	unsigned long flags;
+
+	if (on) {
+		if (saa7134_no_overlay > 0) {
+			dprintk("no_overlay\n");
+			return -EINVAL;
+		}
+
+		if (!res_get(dev, fh, RESOURCE_OVERLAY))
+			return -EBUSY;
+		spin_lock_irqsave(&dev->slock, flags);
+		start_preview(dev, fh);
+		spin_unlock_irqrestore(&dev->slock, flags);
+	}
+	if (!on) {
+		if (!res_check(fh, RESOURCE_OVERLAY))
+			return -EINVAL;
+		spin_lock_irqsave(&dev->slock, flags);
+		stop_preview(dev, fh);
+		spin_unlock_irqrestore(&dev->slock, flags);
+		res_free(dev, fh, RESOURCE_OVERLAY);
+	}
+	return 0;
+}
+
+static int saa7134_reqbufs(struct file *file, void *priv,
+					struct v4l2_requestbuffers *p)
+{
+	struct saa7134_fh *fh = priv;
+	return videobuf_reqbufs(saa7134_queue(fh), p);
+}
+
+static int saa7134_querybuf(struct file *file, void *priv,
+					struct v4l2_buffer *b)
+{
+	struct saa7134_fh *fh = priv;
+	return videobuf_querybuf(saa7134_queue(fh), b);
+}
+
+static int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct saa7134_fh *fh = priv;
+	return videobuf_qbuf(saa7134_queue(fh), b);
+}
+
+static int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct saa7134_fh *fh = priv;
+	return videobuf_dqbuf(saa7134_queue(fh), b,
+				file->f_flags & O_NONBLOCK);
+}
+
+static int saa7134_streamon(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	int res = saa7134_resource(fh);
+
+	if (!res_get(dev, fh, res))
+		return -EBUSY;
+
+	return videobuf_streamon(saa7134_queue(fh));
+}
+
+static int saa7134_streamoff(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	int err;
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	int res = saa7134_resource(fh);
+
+	err = videobuf_streamoff(saa7134_queue(fh));
+	if (err < 0)
+		return err;
+	res_free(dev, fh, res);
+	return 0;
+}
+
+static int saa7134_g_parm(struct file *file, void *fh,
+				struct v4l2_streamparm *parm)
+{
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register (struct file *file, void *priv,
+			      struct v4l2_dbg_register *reg)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	if (!v4l2_chip_match_host(&reg->match))
+		return -EINVAL;
+	reg->val = saa_readb(reg->reg);
+	reg->size = 1;
+	return 0;
+}
+
+static int vidioc_s_register (struct file *file, void *priv,
+				struct v4l2_dbg_register *reg)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	if (!v4l2_chip_match_host(&reg->match))
+		return -EINVAL;
+	saa_writeb(reg->reg&0xffffff, reg->val);
+	return 0;
+}
+#endif
+
+static int radio_querycap(struct file *file, void *priv,
+					struct v4l2_capability *cap)
+{
+	struct saa7134_fh *fh = file->private_data;
+	struct saa7134_dev *dev = fh->dev;
+
+	strcpy(cap->driver, "saa7134");
+	strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card));
+	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+	cap->capabilities = V4L2_CAP_TUNER;
+	return 0;
+}
+
+static int radio_g_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *t)
+{
+	struct saa7134_fh *fh = file->private_data;
+	struct saa7134_dev *dev = fh->dev;
+
+	if (0 != t->index)
+		return -EINVAL;
+
+	memset(t, 0, sizeof(*t));
+	strcpy(t->name, "Radio");
+	t->type = V4L2_TUNER_RADIO;
+
+	saa_call_all(dev, tuner, g_tuner, t);
+	if (dev->input->amux == TV) {
+		t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11);
+		t->rxsubchans = (saa_readb(0x529) & 0x08) ?
+				V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+	}
+	return 0;
+}
+static int radio_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *t)
+{
+	struct saa7134_fh *fh = file->private_data;
+	struct saa7134_dev *dev = fh->dev;
+
+	if (0 != t->index)
+		return -EINVAL;
+
+	saa_call_all(dev, tuner, s_tuner, t);
+	return 0;
+}
+
+static int radio_enum_input(struct file *file, void *priv,
+					struct v4l2_input *i)
+{
+	if (i->index != 0)
+		return -EINVAL;
+
+	strcpy(i->name, "Radio");
+	i->type = V4L2_INPUT_TYPE_TUNER;
+
+	return 0;
+}
+
+static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int radio_g_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	memset(a, 0, sizeof(*a));
+	strcpy(a->name, "Radio");
+	return 0;
+}
+
+static int radio_s_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	return 0;
+}
+
+static int radio_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	return 0;
+}
+
+static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+	return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *c)
+{
+	const struct v4l2_queryctrl *ctrl;
+
+	if (c->id <  V4L2_CID_BASE ||
+	    c->id >= V4L2_CID_LASTP1)
+		return -EINVAL;
+	if (c->id == V4L2_CID_AUDIO_MUTE) {
+		ctrl = ctrl_by_id(c->id);
+		*c = *ctrl;
+	} else
+		*c = no_ctrl;
+	return 0;
+}
+
+static const struct v4l2_file_operations video_fops =
+{
+	.owner	  = THIS_MODULE,
+	.open	  = video_open,
+	.release  = video_release,
+	.read	  = video_read,
+	.poll     = video_poll,
+	.mmap	  = video_mmap,
+	.ioctl	  = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+	.vidioc_querycap		= saa7134_querycap,
+	.vidioc_enum_fmt_vid_cap	= saa7134_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap		= saa7134_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap		= saa7134_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap		= saa7134_s_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_overlay	= saa7134_enum_fmt_vid_overlay,
+	.vidioc_g_fmt_vid_overlay	= saa7134_g_fmt_vid_overlay,
+	.vidioc_try_fmt_vid_overlay	= saa7134_try_fmt_vid_overlay,
+	.vidioc_s_fmt_vid_overlay	= saa7134_s_fmt_vid_overlay,
+	.vidioc_g_fmt_vbi_cap		= saa7134_try_get_set_fmt_vbi_cap,
+	.vidioc_try_fmt_vbi_cap		= saa7134_try_get_set_fmt_vbi_cap,
+	.vidioc_s_fmt_vbi_cap		= saa7134_try_get_set_fmt_vbi_cap,
+	.vidioc_g_audio			= saa7134_g_audio,
+	.vidioc_s_audio			= saa7134_s_audio,
+	.vidioc_cropcap			= saa7134_cropcap,
+	.vidioc_reqbufs			= saa7134_reqbufs,
+	.vidioc_querybuf		= saa7134_querybuf,
+	.vidioc_qbuf			= saa7134_qbuf,
+	.vidioc_dqbuf			= saa7134_dqbuf,
+	.vidioc_s_std			= saa7134_s_std,
+	.vidioc_g_std			= saa7134_g_std,
+	.vidioc_enum_input		= saa7134_enum_input,
+	.vidioc_g_input			= saa7134_g_input,
+	.vidioc_s_input			= saa7134_s_input,
+	.vidioc_queryctrl		= saa7134_queryctrl,
+	.vidioc_g_ctrl			= saa7134_g_ctrl,
+	.vidioc_s_ctrl			= saa7134_s_ctrl,
+	.vidioc_streamon		= saa7134_streamon,
+	.vidioc_streamoff		= saa7134_streamoff,
+	.vidioc_g_tuner			= saa7134_g_tuner,
+	.vidioc_s_tuner			= saa7134_s_tuner,
+	.vidioc_g_crop			= saa7134_g_crop,
+	.vidioc_s_crop			= saa7134_s_crop,
+	.vidioc_g_fbuf			= saa7134_g_fbuf,
+	.vidioc_s_fbuf			= saa7134_s_fbuf,
+	.vidioc_overlay			= saa7134_overlay,
+	.vidioc_g_priority		= saa7134_g_priority,
+	.vidioc_s_priority		= saa7134_s_priority,
+	.vidioc_g_parm			= saa7134_g_parm,
+	.vidioc_g_frequency		= saa7134_g_frequency,
+	.vidioc_s_frequency		= saa7134_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register              = vidioc_g_register,
+	.vidioc_s_register              = vidioc_s_register,
+#endif
+};
+
+static const struct v4l2_file_operations radio_fops = {
+	.owner	  = THIS_MODULE,
+	.open	  = video_open,
+	.read     = radio_read,
+	.release  = video_release,
+	.ioctl	  = video_ioctl2,
+	.poll     = radio_poll,
+};
+
+static const struct v4l2_ioctl_ops radio_ioctl_ops = {
+	.vidioc_querycap	= radio_querycap,
+	.vidioc_g_tuner		= radio_g_tuner,
+	.vidioc_enum_input	= radio_enum_input,
+	.vidioc_g_audio		= radio_g_audio,
+	.vidioc_s_tuner		= radio_s_tuner,
+	.vidioc_s_audio		= radio_s_audio,
+	.vidioc_s_input		= radio_s_input,
+	.vidioc_s_std		= radio_s_std,
+	.vidioc_queryctrl	= radio_queryctrl,
+	.vidioc_g_input		= radio_g_input,
+	.vidioc_g_ctrl		= saa7134_g_ctrl,
+	.vidioc_s_ctrl		= saa7134_s_ctrl,
+	.vidioc_g_frequency	= saa7134_g_frequency,
+	.vidioc_s_frequency	= saa7134_s_frequency,
+};
+
+/* ----------------------------------------------------------- */
+/* exported stuff                                              */
+
+struct video_device saa7134_video_template = {
+	.name				= "saa7134-video",
+	.fops				= &video_fops,
+	.ioctl_ops 			= &video_ioctl_ops,
+	.tvnorms			= SAA7134_NORMS,
+	.current_norm			= V4L2_STD_PAL,
+};
+
+struct video_device saa7134_radio_template = {
+	.name			= "saa7134-radio",
+	.fops			= &radio_fops,
+	.ioctl_ops 		= &radio_ioctl_ops,
+};
+
+int saa7134_video_init1(struct saa7134_dev *dev)
+{
+	/* sanitycheck insmod options */
+	if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
+		gbuffers = 2;
+	if (gbufsize < 0 || gbufsize > gbufsize_max)
+		gbufsize = gbufsize_max;
+	gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
+
+	/* put some sensible defaults into the data structures ... */
+	dev->ctl_bright     = ctrl_by_id(V4L2_CID_BRIGHTNESS)->default_value;
+	dev->ctl_contrast   = ctrl_by_id(V4L2_CID_CONTRAST)->default_value;
+	dev->ctl_hue        = ctrl_by_id(V4L2_CID_HUE)->default_value;
+	dev->ctl_saturation = ctrl_by_id(V4L2_CID_SATURATION)->default_value;
+	dev->ctl_volume     = ctrl_by_id(V4L2_CID_AUDIO_VOLUME)->default_value;
+	dev->ctl_mute       = 1; // ctrl_by_id(V4L2_CID_AUDIO_MUTE)->default_value;
+	dev->ctl_invert     = ctrl_by_id(V4L2_CID_PRIVATE_INVERT)->default_value;
+	dev->ctl_automute   = ctrl_by_id(V4L2_CID_PRIVATE_AUTOMUTE)->default_value;
+
+	if (dev->tda9887_conf && dev->ctl_automute)
+		dev->tda9887_conf |= TDA9887_AUTOMUTE;
+	dev->automute       = 0;
+
+	INIT_LIST_HEAD(&dev->video_q.queue);
+	init_timer(&dev->video_q.timeout);
+	dev->video_q.timeout.function = saa7134_buffer_timeout;
+	dev->video_q.timeout.data     = (unsigned long)(&dev->video_q);
+	dev->video_q.dev              = dev;
+
+	if (saa7134_boards[dev->board].video_out)
+		saa7134_videoport_init(dev);
+
+	return 0;
+}
+
+int saa7134_videoport_init(struct saa7134_dev *dev)
+{
+	/* enable video output */
+	int vo = saa7134_boards[dev->board].video_out;
+	int video_reg;
+	unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
+
+	/* Configure videoport */
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
+	video_reg = video_out[vo][1];
+	if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
+		video_reg &= ~VP_T_CODE_P_INVERTED;
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
+	video_reg = video_out[vo][5];
+	if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
+		video_reg &= ~VP_CLK_CTRL2_DELAYED;
+	if (vid_port_opts & SET_CLOCK_INVERTED)
+		video_reg |= VP_CLK_CTRL1_INVERTED;
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg);
+	video_reg = video_out[vo][6];
+	if (vid_port_opts & SET_VSYNC_OFF) {
+		video_reg &= ~VP_VS_TYPE_MASK;
+		video_reg |= VP_VS_TYPE_OFF;
+	}
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg);
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
+
+	/* Start videoport */
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
+
+	return 0;
+}
+
+int saa7134_video_init2(struct saa7134_dev *dev)
+{
+	/* init video hw */
+	set_tvnorm(dev,&tvnorms[0]);
+	video_mux(dev,0);
+	saa7134_tvaudio_setmute(dev);
+	saa7134_tvaudio_setvolume(dev,dev->ctl_volume);
+	return 0;
+}
+
+void saa7134_irq_video_signalchange(struct saa7134_dev *dev)
+{
+	static const char *st[] = {
+		"(no signal)", "NTSC", "PAL", "SECAM" };
+	u32 st1,st2;
+
+	st1 = saa_readb(SAA7134_STATUS_VIDEO1);
+	st2 = saa_readb(SAA7134_STATUS_VIDEO2);
+	dprintk("DCSDT: pll: %s, sync: %s, norm: %s\n",
+		(st1 & 0x40) ? "not locked" : "locked",
+		(st2 & 0x40) ? "no"         : "yes",
+		st[st1 & 0x03]);
+	dev->nosignal = (st1 & 0x40) || (st2 & 0x40)  || !(st2 & 0x1);
+
+	if (dev->nosignal) {
+		/* no video signal -> mute audio */
+		if (dev->ctl_automute)
+			dev->automute = 1;
+		saa7134_tvaudio_setmute(dev);
+	} else {
+		/* wake up tvaudio audio carrier scan thread */
+		saa7134_tvaudio_do_scan(dev);
+	}
+
+	if ((st2 & 0x80) && !noninterlaced && !dev->nosignal)
+		saa_clearb(SAA7134_SYNC_CTRL, 0x20);
+	else
+		saa_setb(SAA7134_SYNC_CTRL, 0x20);
+
+	if (dev->mops && dev->mops->signal_change)
+		dev->mops->signal_change(dev);
+}
+
+
+void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
+{
+	enum v4l2_field field;
+
+	spin_lock(&dev->slock);
+	if (dev->video_q.curr) {
+		dev->video_fieldcount++;
+		field = dev->video_q.curr->vb.field;
+		if (V4L2_FIELD_HAS_BOTH(field)) {
+			/* make sure we have seen both fields */
+			if ((status & 0x10) == 0x00) {
+				dev->video_q.curr->top_seen = 1;
+				goto done;
+			}
+			if (!dev->video_q.curr->top_seen)
+				goto done;
+		} else if (field == V4L2_FIELD_TOP) {
+			if ((status & 0x10) != 0x10)
+				goto done;
+		} else if (field == V4L2_FIELD_BOTTOM) {
+			if ((status & 0x10) != 0x00)
+				goto done;
+		}
+		dev->video_q.curr->vb.field_count = dev->video_fieldcount;
+		saa7134_buffer_finish(dev,&dev->video_q,VIDEOBUF_DONE);
+	}
+	saa7134_buffer_next(dev,&dev->video_q);
+
+ done:
+	spin_unlock(&dev->slock);
+}
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
new file mode 100644
index 0000000..c24b651
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134.h
@@ -0,0 +1,855 @@
+/*
+ *
+ * v4l2 device driver for philips saa7134 based TV cards
+ *
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define SAA7134_VERSION "0, 2, 17"
+
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/kdev_t.h>
+#include <linux/input.h>
+#include <linux/notifier.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+
+#include <asm/io.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/tuner.h>
+#include <media/rc-core.h>
+#include <media/ir-kbd-i2c.h>
+#include <media/videobuf-dma-sg.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
+#include <media/videobuf-dvb.h>
+#endif
+
+#define UNSET (-1U)
+
+/* ----------------------------------------------------------- */
+/* enums                                                       */
+
+enum saa7134_tvaudio_mode {
+	TVAUDIO_FM_MONO       = 1,
+	TVAUDIO_FM_BG_STEREO  = 2,
+	TVAUDIO_FM_SAT_STEREO = 3,
+	TVAUDIO_FM_K_STEREO   = 4,
+	TVAUDIO_NICAM_AM      = 5,
+	TVAUDIO_NICAM_FM      = 6,
+};
+
+enum saa7134_audio_in {
+	TV    = 1,
+	LINE1 = 2,
+	LINE2 = 3,
+	LINE2_LEFT,
+};
+
+enum saa7134_video_out {
+	CCIR656 = 1,
+};
+
+/* ----------------------------------------------------------- */
+/* static data                                                 */
+
+struct saa7134_tvnorm {
+	char          *name;
+	v4l2_std_id   id;
+
+	/* video decoder */
+	unsigned int  sync_control;
+	unsigned int  luma_control;
+	unsigned int  chroma_ctrl1;
+	unsigned int  chroma_gain;
+	unsigned int  chroma_ctrl2;
+	unsigned int  vgate_misc;
+
+	/* video scaler */
+	unsigned int  h_start;
+	unsigned int  h_stop;
+	unsigned int  video_v_start;
+	unsigned int  video_v_stop;
+	unsigned int  vbi_v_start_0;
+	unsigned int  vbi_v_stop_0;
+	unsigned int  src_timing;
+	unsigned int  vbi_v_start_1;
+};
+
+struct saa7134_tvaudio {
+	char         *name;
+	v4l2_std_id  std;
+	enum         saa7134_tvaudio_mode mode;
+	int          carr1;
+	int          carr2;
+};
+
+struct saa7134_format {
+	char           *name;
+	unsigned int   fourcc;
+	unsigned int   depth;
+	unsigned int   pm;
+	unsigned int   vshift;   /* vertical downsampling (for planar yuv) */
+	unsigned int   hshift;   /* horizontal downsampling (for planar yuv) */
+	unsigned int   bswap:1;
+	unsigned int   wswap:1;
+	unsigned int   yuv:1;
+	unsigned int   planar:1;
+	unsigned int   uvswap:1;
+};
+
+struct saa7134_card_ir {
+	struct rc_dev		*dev;
+
+	char                    name[32];
+	char                    phys[32];
+	unsigned                users;
+
+	u32			polling;
+	u32			last_gpio;
+	u32			mask_keycode, mask_keydown, mask_keyup;
+
+	bool                    running;
+
+	struct timer_list       timer;
+
+	/* IR core raw decoding */
+	u32                     raw_decode;
+};
+
+/* ----------------------------------------------------------- */
+/* card configuration                                          */
+
+#define SAA7134_BOARD_NOAUTO        UNSET
+#define SAA7134_BOARD_UNKNOWN           0
+#define SAA7134_BOARD_PROTEUS_PRO       1
+#define SAA7134_BOARD_FLYVIDEO3000      2
+#define SAA7134_BOARD_FLYVIDEO2000      3
+#define SAA7134_BOARD_EMPRESS           4
+#define SAA7134_BOARD_MONSTERTV         5
+#define SAA7134_BOARD_MD9717            6
+#define SAA7134_BOARD_TVSTATION_RDS     7
+#define SAA7134_BOARD_CINERGY400	8
+#define SAA7134_BOARD_MD5044		9
+#define SAA7134_BOARD_KWORLD           10
+#define SAA7134_BOARD_CINERGY600       11
+#define SAA7134_BOARD_MD7134           12
+#define SAA7134_BOARD_TYPHOON_90031    13
+#define SAA7134_BOARD_ELSA             14
+#define SAA7134_BOARD_ELSA_500TV       15
+#define SAA7134_BOARD_ASUSTeK_TVFM7134 16
+#define SAA7134_BOARD_VA1000POWER      17
+#define SAA7134_BOARD_BMK_MPEX_NOTUNER 18
+#define SAA7134_BOARD_VIDEOMATE_TV     19
+#define SAA7134_BOARD_CRONOS_PLUS      20
+#define SAA7134_BOARD_10MOONSTVMASTER  21
+#define SAA7134_BOARD_MD2819           22
+#define SAA7134_BOARD_BMK_MPEX_TUNER   23
+#define SAA7134_BOARD_TVSTATION_DVR    24
+#define SAA7134_BOARD_ASUSTEK_TVFM7133	25
+#define SAA7134_BOARD_PINNACLE_PCTV_STEREO 26
+#define SAA7134_BOARD_MANLI_MTV002     27
+#define SAA7134_BOARD_MANLI_MTV001     28
+#define SAA7134_BOARD_TG3000TV         29
+#define SAA7134_BOARD_ECS_TVP3XP       30
+#define SAA7134_BOARD_ECS_TVP3XP_4CB5  31
+#define SAA7134_BOARD_AVACSSMARTTV     32
+#define SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER 33
+#define SAA7134_BOARD_NOVAC_PRIMETV7133 34
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_305 35
+#define SAA7134_BOARD_UPMOST_PURPLE_TV 36
+#define SAA7134_BOARD_ITEMS_MTV005     37
+#define SAA7134_BOARD_CINERGY200       38
+#define SAA7134_BOARD_FLYTVPLATINUM_MINI 39
+#define SAA7134_BOARD_VIDEOMATE_TV_PVR 40
+#define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS 41
+#define SAA7134_BOARD_SABRENT_SBTTVFM  42
+#define SAA7134_BOARD_ZOLID_XPERT_TV7134 43
+#define SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE 44
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_307    45
+#define SAA7134_BOARD_AVERMEDIA_CARDBUS 46
+#define SAA7134_BOARD_CINERGY400_CARDBUS 47
+#define SAA7134_BOARD_CINERGY600_MK3   48
+#define SAA7134_BOARD_VIDEOMATE_GOLD_PLUS 49
+#define SAA7134_BOARD_PINNACLE_300I_DVBT_PAL 50
+#define SAA7134_BOARD_PROVIDEO_PV952   51
+#define SAA7134_BOARD_AVERMEDIA_305    52
+#define SAA7134_BOARD_ASUSTeK_TVFM7135 53
+#define SAA7134_BOARD_FLYTVPLATINUM_FM 54
+#define SAA7134_BOARD_FLYDVBTDUO 55
+#define SAA7134_BOARD_AVERMEDIA_307    56
+#define SAA7134_BOARD_AVERMEDIA_GO_007_FM 57
+#define SAA7134_BOARD_ADS_INSTANT_TV 58
+#define SAA7134_BOARD_KWORLD_VSTREAM_XPERT 59
+#define SAA7134_BOARD_FLYDVBT_DUO_CARDBUS 60
+#define SAA7134_BOARD_PHILIPS_TOUGH 61
+#define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII 62
+#define SAA7134_BOARD_KWORLD_XPERT 63
+#define SAA7134_BOARD_FLYTV_DIGIMATRIX 64
+#define SAA7134_BOARD_KWORLD_TERMINATOR 65
+#define SAA7134_BOARD_YUAN_TUN900 66
+#define SAA7134_BOARD_BEHOLD_409FM 67
+#define SAA7134_BOARD_GOTVIEW_7135 68
+#define SAA7134_BOARD_PHILIPS_EUROPA  69
+#define SAA7134_BOARD_VIDEOMATE_DVBT_300 70
+#define SAA7134_BOARD_VIDEOMATE_DVBT_200 71
+#define SAA7134_BOARD_RTD_VFG7350 72
+#define SAA7134_BOARD_RTD_VFG7330 73
+#define SAA7134_BOARD_FLYTVPLATINUM_MINI2 74
+#define SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180 75
+#define SAA7134_BOARD_MONSTERTV_MOBILE 76
+#define SAA7134_BOARD_PINNACLE_PCTV_110i 77
+#define SAA7134_BOARD_ASUSTeK_P7131_DUAL 78
+#define SAA7134_BOARD_SEDNA_PC_TV_CARDBUS     79
+#define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80
+#define SAA7134_BOARD_PHILIPS_TIGER  81
+#define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS  82
+#define SAA7134_BOARD_CINERGY250PCI 83
+#define SAA7134_BOARD_FLYDVB_TRIO 84
+#define SAA7134_BOARD_AVERMEDIA_777 85
+#define SAA7134_BOARD_FLYDVBT_LR301 86
+#define SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331 87
+#define SAA7134_BOARD_TEVION_DVBT_220RF 88
+#define SAA7134_BOARD_ELSA_700TV       89
+#define SAA7134_BOARD_KWORLD_ATSC110   90
+#define SAA7134_BOARD_AVERMEDIA_A169_B 91
+#define SAA7134_BOARD_AVERMEDIA_A169_B1 92
+#define SAA7134_BOARD_MD7134_BRIDGE_2     93
+#define SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS 94
+#define SAA7134_BOARD_FLYVIDEO3000_NTSC 95
+#define SAA7134_BOARD_MEDION_MD8800_QUADRO 96
+#define SAA7134_BOARD_FLYDVBS_LR300 97
+#define SAA7134_BOARD_PROTEUS_2309 98
+#define SAA7134_BOARD_AVERMEDIA_A16AR   99
+#define SAA7134_BOARD_ASUS_EUROPA2_HYBRID 100
+#define SAA7134_BOARD_PINNACLE_PCTV_310i  101
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_507 102
+#define SAA7134_BOARD_VIDEOMATE_DVBT_200A  103
+#define SAA7134_BOARD_HAUPPAUGE_HVR1110    104
+#define SAA7134_BOARD_CINERGY_HT_PCMCIA    105
+#define SAA7134_BOARD_ENCORE_ENLTV         106
+#define SAA7134_BOARD_ENCORE_ENLTV_FM      107
+#define SAA7134_BOARD_CINERGY_HT_PCI       108
+#define SAA7134_BOARD_PHILIPS_TIGER_S      109
+#define SAA7134_BOARD_AVERMEDIA_M102	   110
+#define SAA7134_BOARD_ASUS_P7131_4871	   111
+#define SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA 112
+#define SAA7134_BOARD_ECS_TVP3XP_4CB6  113
+#define SAA7134_BOARD_KWORLD_DVBT_210 114
+#define SAA7134_BOARD_SABRENT_TV_PCB05     115
+#define SAA7134_BOARD_10MOONSTVMASTER3     116
+#define SAA7134_BOARD_AVERMEDIA_SUPER_007  117
+#define SAA7134_BOARD_BEHOLD_401  	118
+#define SAA7134_BOARD_BEHOLD_403  	119
+#define SAA7134_BOARD_BEHOLD_403FM	120
+#define SAA7134_BOARD_BEHOLD_405	121
+#define SAA7134_BOARD_BEHOLD_405FM	122
+#define SAA7134_BOARD_BEHOLD_407	123
+#define SAA7134_BOARD_BEHOLD_407FM	124
+#define SAA7134_BOARD_BEHOLD_409	125
+#define SAA7134_BOARD_BEHOLD_505FM	126
+#define SAA7134_BOARD_BEHOLD_507_9FM	127
+#define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128
+#define SAA7134_BOARD_BEHOLD_607FM_MK3	129
+#define SAA7134_BOARD_BEHOLD_M6		130
+#define SAA7134_BOARD_TWINHAN_DTV_DVB_3056 131
+#define SAA7134_BOARD_GENIUS_TVGO_A11MCE   132
+#define SAA7134_BOARD_PHILIPS_SNAKE        133
+#define SAA7134_BOARD_CREATIX_CTX953       134
+#define SAA7134_BOARD_MSI_TVANYWHERE_AD11  135
+#define SAA7134_BOARD_AVERMEDIA_CARDBUS_506 136
+#define SAA7134_BOARD_AVERMEDIA_A16D       137
+#define SAA7134_BOARD_AVERMEDIA_M115       138
+#define SAA7134_BOARD_VIDEOMATE_T750       139
+#define SAA7134_BOARD_AVERMEDIA_A700_PRO    140
+#define SAA7134_BOARD_AVERMEDIA_A700_HYBRID 141
+#define SAA7134_BOARD_BEHOLD_H6      142
+#define SAA7134_BOARD_BEHOLD_M63      143
+#define SAA7134_BOARD_BEHOLD_M6_EXTRA    144
+#define SAA7134_BOARD_AVERMEDIA_M103    145
+#define SAA7134_BOARD_ASUSTeK_P7131_ANALOG 146
+#define SAA7134_BOARD_ASUSTeK_TIGER_3IN1   147
+#define SAA7134_BOARD_ENCORE_ENLTV_FM53 148
+#define SAA7134_BOARD_AVERMEDIA_M135A    149
+#define SAA7134_BOARD_REAL_ANGEL_220     150
+#define SAA7134_BOARD_ADS_INSTANT_HDTV_PCI  151
+#define SAA7134_BOARD_ASUSTeK_TIGER         152
+#define SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG 153
+#define SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS 154
+#define SAA7134_BOARD_HAUPPAUGE_HVR1150     155
+#define SAA7134_BOARD_HAUPPAUGE_HVR1120   156
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_507UA 157
+#define SAA7134_BOARD_AVERMEDIA_CARDBUS_501 158
+#define SAA7134_BOARD_BEHOLD_505RDS_MK5     159
+#define SAA7134_BOARD_BEHOLD_507RDS_MK3     160
+#define SAA7134_BOARD_BEHOLD_507RDS_MK5     161
+#define SAA7134_BOARD_BEHOLD_607FM_MK5      162
+#define SAA7134_BOARD_BEHOLD_609FM_MK3      163
+#define SAA7134_BOARD_BEHOLD_609FM_MK5      164
+#define SAA7134_BOARD_BEHOLD_607RDS_MK3     165
+#define SAA7134_BOARD_BEHOLD_607RDS_MK5     166
+#define SAA7134_BOARD_BEHOLD_609RDS_MK3     167
+#define SAA7134_BOARD_BEHOLD_609RDS_MK5     168
+#define SAA7134_BOARD_VIDEOMATE_S350        169
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_505  170
+#define SAA7134_BOARD_BEHOLD_X7             171
+#define SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM 172
+#define SAA7134_BOARD_ZOLID_HYBRID_PCI		173
+#define SAA7134_BOARD_ASUS_EUROPA_HYBRID	174
+#define SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S 175
+#define SAA7134_BOARD_BEHOLD_505RDS_MK3     176
+#define SAA7134_BOARD_HAWELL_HW_404M7		177
+#define SAA7134_BOARD_BEHOLD_H7             178
+#define SAA7134_BOARD_BEHOLD_A7             179
+#define SAA7134_BOARD_AVERMEDIA_M733A       180
+#define SAA7134_BOARD_TECHNOTREND_BUDGET_T3000 181
+#define SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG 182
+#define SAA7134_BOARD_VIDEOMATE_M1F         183
+#define SAA7134_BOARD_ENCORE_ENLTV_FM3      184
+#define SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2 185
+#define SAA7134_BOARD_BEHOLD_501            186
+#define SAA7134_BOARD_BEHOLD_503FM          187
+#define SAA7134_BOARD_SENSORAY811_911       188
+#define SAA7134_BOARD_KWORLD_PC150U         189
+#define SAA7134_BOARD_ASUSTeK_PS3_100      190
+
+#define SAA7134_MAXBOARDS 32
+#define SAA7134_INPUT_MAX 8
+
+/* ----------------------------------------------------------- */
+/* Since we support 2 remote types, lets tell them apart       */
+
+#define SAA7134_REMOTE_GPIO  1
+#define SAA7134_REMOTE_I2C   2
+
+/* ----------------------------------------------------------- */
+/* Video Output Port Register Initialization Options           */
+
+#define SET_T_CODE_POLARITY_NON_INVERTED	(1 << 0)
+#define SET_CLOCK_NOT_DELAYED			(1 << 1)
+#define SET_CLOCK_INVERTED			(1 << 2)
+#define SET_VSYNC_OFF				(1 << 3)
+
+struct saa7134_input {
+	char                    *name;
+	unsigned int            vmux;
+	enum saa7134_audio_in   amux;
+	unsigned int            gpio;
+	unsigned int            tv:1;
+};
+
+enum saa7134_mpeg_type {
+	SAA7134_MPEG_UNUSED,
+	SAA7134_MPEG_EMPRESS,
+	SAA7134_MPEG_DVB,
+};
+
+enum saa7134_mpeg_ts_type {
+	SAA7134_MPEG_TS_PARALLEL = 0,
+	SAA7134_MPEG_TS_SERIAL,
+};
+
+struct saa7134_board {
+	char                    *name;
+	unsigned int            audio_clock;
+
+	/* input switching */
+	unsigned int            gpiomask;
+	struct saa7134_input    inputs[SAA7134_INPUT_MAX];
+	struct saa7134_input    radio;
+	struct saa7134_input    mute;
+
+	/* i2c chip info */
+	unsigned int            tuner_type;
+	unsigned int		radio_type;
+	unsigned char		tuner_addr;
+	unsigned char		radio_addr;
+	unsigned char		empress_addr;
+	unsigned char		rds_addr;
+
+	unsigned int            tda9887_conf;
+	unsigned int            tuner_config;
+
+	/* peripheral I/O */
+	enum saa7134_video_out  video_out;
+	enum saa7134_mpeg_type  mpeg;
+	enum saa7134_mpeg_ts_type ts_type;
+	unsigned int            vid_port_opts;
+	unsigned int            ts_force_val:1;
+};
+
+#define card_has_radio(dev)   (NULL != saa7134_boards[dev->board].radio.name)
+#define card_is_empress(dev)  (SAA7134_MPEG_EMPRESS == saa7134_boards[dev->board].mpeg)
+#define card_is_dvb(dev)      (SAA7134_MPEG_DVB     == saa7134_boards[dev->board].mpeg)
+#define card_has_mpeg(dev)    (SAA7134_MPEG_UNUSED  != saa7134_boards[dev->board].mpeg)
+#define card(dev)             (saa7134_boards[dev->board])
+#define card_in(dev,n)        (saa7134_boards[dev->board].inputs[n])
+
+/* ----------------------------------------------------------- */
+/* device / file handle status                                 */
+
+#define RESOURCE_OVERLAY       1
+#define RESOURCE_VIDEO         2
+#define RESOURCE_VBI           4
+
+#define INTERLACE_AUTO         0
+#define INTERLACE_ON           1
+#define INTERLACE_OFF          2
+
+#define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
+#define TS_BUFFER_TIMEOUT  msecs_to_jiffies(1000)  /* 1 second */
+
+struct saa7134_dev;
+struct saa7134_dma;
+
+/* saa7134 page table */
+struct saa7134_pgtable {
+	unsigned int               size;
+	__le32                     *cpu;
+	dma_addr_t                 dma;
+};
+
+/* tvaudio thread status */
+struct saa7134_thread {
+	struct task_struct         *thread;
+	unsigned int               scan1;
+	unsigned int               scan2;
+	unsigned int               mode;
+	unsigned int		   stopped;
+};
+
+/* buffer for one video/vbi/ts frame */
+struct saa7134_buf {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+
+	/* saa7134 specific */
+	struct saa7134_format   *fmt;
+	unsigned int            top_seen;
+	int (*activate)(struct saa7134_dev *dev,
+			struct saa7134_buf *buf,
+			struct saa7134_buf *next);
+
+	/* page tables */
+	struct saa7134_pgtable  *pt;
+};
+
+struct saa7134_dmaqueue {
+	struct saa7134_dev         *dev;
+	struct saa7134_buf         *curr;
+	struct list_head           queue;
+	struct timer_list          timeout;
+	unsigned int               need_two;
+};
+
+/* video filehandle status */
+struct saa7134_fh {
+	struct saa7134_dev         *dev;
+	unsigned int               radio;
+	enum v4l2_buf_type         type;
+	unsigned int               resources;
+	enum v4l2_priority	   prio;
+
+	/* video overlay */
+	struct v4l2_window         win;
+	struct v4l2_clip           clips[8];
+	unsigned int               nclips;
+
+	/* video capture */
+	struct saa7134_format      *fmt;
+	unsigned int               width,height;
+	struct videobuf_queue      cap;
+	struct saa7134_pgtable     pt_cap;
+
+	/* vbi capture */
+	struct videobuf_queue      vbi;
+	struct saa7134_pgtable     pt_vbi;
+};
+
+/* dmasound dsp status */
+struct saa7134_dmasound {
+	struct mutex               lock;
+	int                        minor_mixer;
+	int                        minor_dsp;
+	unsigned int               users_dsp;
+
+	/* mixer */
+	enum saa7134_audio_in      input;
+	unsigned int               count;
+	unsigned int               line1;
+	unsigned int               line2;
+
+	/* dsp */
+	unsigned int               afmt;
+	unsigned int               rate;
+	unsigned int               channels;
+	unsigned int               recording_on;
+	unsigned int               dma_running;
+	unsigned int               blocks;
+	unsigned int               blksize;
+	unsigned int               bufsize;
+	struct saa7134_pgtable     pt;
+	struct videobuf_dmabuf     dma;
+	unsigned int               dma_blk;
+	unsigned int               read_offset;
+	unsigned int               read_count;
+	void *			   priv_data;
+	struct snd_pcm_substream   *substream;
+};
+
+/* ts/mpeg status */
+struct saa7134_ts {
+	/* TS capture */
+	struct saa7134_pgtable     pt_ts;
+	int                        nr_packets;
+	int                        nr_bufs;
+};
+
+/* ts/mpeg ops */
+struct saa7134_mpeg_ops {
+	enum saa7134_mpeg_type     type;
+	struct list_head           next;
+	int                        (*init)(struct saa7134_dev *dev);
+	int                        (*fini)(struct saa7134_dev *dev);
+	void                       (*signal_change)(struct saa7134_dev *dev);
+};
+
+/* global device status */
+struct saa7134_dev {
+	struct list_head           devlist;
+	struct mutex               lock;
+	spinlock_t                 slock;
+	struct v4l2_prio_state     prio;
+	struct v4l2_device         v4l2_dev;
+	/* workstruct for loading modules */
+	struct work_struct request_module_wk;
+
+	/* insmod option/autodetected */
+	int                        autodetected;
+
+	/* various device info */
+	unsigned int               resources;
+	struct video_device        *video_dev;
+	struct video_device        *radio_dev;
+	struct video_device        *vbi_dev;
+	struct saa7134_dmasound    dmasound;
+
+	/* infrared remote */
+	int                        has_remote;
+	struct saa7134_card_ir     *remote;
+
+	/* pci i/o */
+	char                       name[32];
+	int                        nr;
+	struct pci_dev             *pci;
+	unsigned char              pci_rev,pci_lat;
+	__u32                      __iomem *lmmio;
+	__u8                       __iomem *bmmio;
+
+	/* config info */
+	unsigned int               board;
+	unsigned int               tuner_type;
+	unsigned int 		   radio_type;
+	unsigned char		   tuner_addr;
+	unsigned char		   radio_addr;
+
+	unsigned int               tda9887_conf;
+	unsigned int               gpio_value;
+
+	/* i2c i/o */
+	struct i2c_adapter         i2c_adap;
+	struct i2c_client          i2c_client;
+	unsigned char              eedata[256];
+	int 			   has_rds;
+
+	/* video overlay */
+	struct v4l2_framebuffer    ovbuf;
+	struct saa7134_format      *ovfmt;
+	unsigned int               ovenable;
+	enum v4l2_field            ovfield;
+
+	/* video+ts+vbi capture */
+	struct saa7134_dmaqueue    video_q;
+	struct saa7134_dmaqueue    vbi_q;
+	unsigned int               video_fieldcount;
+	unsigned int               vbi_fieldcount;
+
+	/* various v4l controls */
+	struct saa7134_tvnorm      *tvnorm;              /* video */
+	struct saa7134_tvaudio     *tvaudio;
+	unsigned int               ctl_input;
+	int                        ctl_bright;
+	int                        ctl_contrast;
+	int                        ctl_hue;
+	int                        ctl_saturation;
+	int                        ctl_freq;
+	int                        ctl_mute;             /* audio */
+	int                        ctl_volume;
+	int                        ctl_invert;           /* private */
+	int                        ctl_mirror;
+	int                        ctl_y_odd;
+	int                        ctl_y_even;
+	int                        ctl_automute;
+
+	/* crop */
+	struct v4l2_rect           crop_bounds;
+	struct v4l2_rect           crop_defrect;
+	struct v4l2_rect           crop_current;
+
+	/* other global state info */
+	unsigned int               automute;
+	struct saa7134_thread      thread;
+	struct saa7134_input       *input;
+	struct saa7134_input       *hw_input;
+	unsigned int               hw_mute;
+	int                        last_carrier;
+	int                        nosignal;
+	unsigned int               insuspend;
+
+	/* I2C keyboard data */
+	struct IR_i2c_init_data    init_data;
+
+	/* SAA7134_MPEG_* */
+	struct saa7134_ts          ts;
+	struct saa7134_dmaqueue    ts_q;
+	int                        ts_started;
+	struct saa7134_mpeg_ops    *mops;
+
+	/* SAA7134_MPEG_EMPRESS only */
+	struct video_device        *empress_dev;
+	struct videobuf_queue      empress_tsq;
+	atomic_t 		   empress_users;
+	struct work_struct         empress_workqueue;
+	int                        empress_started;
+
+#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
+	/* SAA7134_MPEG_DVB only */
+	struct videobuf_dvb_frontends frontends;
+	int (*original_demod_sleep)(struct dvb_frontend *fe);
+	int (*original_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+	int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg);
+#endif
+	void (*gate_ctrl)(struct saa7134_dev *dev, int open);
+};
+
+/* ----------------------------------------------------------- */
+
+#define saa_readl(reg)             readl(dev->lmmio + (reg))
+#define saa_writel(reg,value)      writel((value), dev->lmmio + (reg));
+#define saa_andorl(reg,mask,value) \
+  writel((readl(dev->lmmio+(reg)) & ~(mask)) |\
+  ((value) & (mask)), dev->lmmio+(reg))
+#define saa_setl(reg,bit)          saa_andorl((reg),(bit),(bit))
+#define saa_clearl(reg,bit)        saa_andorl((reg),(bit),0)
+
+#define saa_readb(reg)             readb(dev->bmmio + (reg))
+#define saa_writeb(reg,value)      writeb((value), dev->bmmio + (reg));
+#define saa_andorb(reg,mask,value) \
+  writeb((readb(dev->bmmio+(reg)) & ~(mask)) |\
+  ((value) & (mask)), dev->bmmio+(reg))
+#define saa_setb(reg,bit)          saa_andorb((reg),(bit),(bit))
+#define saa_clearb(reg,bit)        saa_andorb((reg),(bit),0)
+
+#define saa_wait(us) { udelay(us); }
+
+#define SAA7134_NORMS	(\
+		V4L2_STD_PAL    | V4L2_STD_PAL_N | \
+		V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \
+		V4L2_STD_NTSC   | V4L2_STD_PAL_M | \
+		V4L2_STD_PAL_60)
+
+#define GRP_EMPRESS (1)
+#define saa_call_all(dev, o, f, args...) do {				\
+	if (dev->gate_ctrl)						\
+		dev->gate_ctrl(dev, 1);					\
+	v4l2_device_call_all(&(dev)->v4l2_dev, 0, o, f , ##args);	\
+	if (dev->gate_ctrl)						\
+		dev->gate_ctrl(dev, 0);					\
+} while (0)
+
+#define saa_call_empress(dev, o, f, args...) ({				\
+	long _rc;							\
+	if (dev->gate_ctrl)						\
+		dev->gate_ctrl(dev, 1);					\
+	_rc = v4l2_device_call_until_err(&(dev)->v4l2_dev,		\
+					 GRP_EMPRESS, o, f , ##args);	\
+	if (dev->gate_ctrl)						\
+		dev->gate_ctrl(dev, 0);					\
+	_rc;								\
+})
+
+/* ----------------------------------------------------------- */
+/* saa7134-core.c                                              */
+
+extern struct list_head  saa7134_devlist;
+extern struct mutex saa7134_devlist_lock;
+extern int saa7134_no_overlay;
+
+void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
+void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value);
+
+#define SAA7134_PGTABLE_SIZE 4096
+
+int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt);
+int  saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,
+			   struct scatterlist *list, unsigned int length,
+			   unsigned int startpage);
+void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt);
+
+int saa7134_buffer_count(unsigned int size, unsigned int count);
+int saa7134_buffer_startpage(struct saa7134_buf *buf);
+unsigned long saa7134_buffer_base(struct saa7134_buf *buf);
+
+int saa7134_buffer_queue(struct saa7134_dev *dev, struct saa7134_dmaqueue *q,
+			 struct saa7134_buf *buf);
+void saa7134_buffer_finish(struct saa7134_dev *dev, struct saa7134_dmaqueue *q,
+			   unsigned int state);
+void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
+void saa7134_buffer_timeout(unsigned long data);
+void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf);
+
+int saa7134_set_dmabits(struct saa7134_dev *dev);
+
+extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
+extern int (*saa7134_dmasound_exit)(struct saa7134_dev *dev);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-cards.c                                             */
+
+extern struct saa7134_board saa7134_boards[];
+extern const unsigned int saa7134_bcount;
+extern struct pci_device_id __devinitdata saa7134_pci_tbl[];
+
+extern int saa7134_board_init1(struct saa7134_dev *dev);
+extern int saa7134_board_init2(struct saa7134_dev *dev);
+int saa7134_tuner_callback(void *priv, int component, int command, int arg);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-i2c.c                                               */
+
+int saa7134_i2c_register(struct saa7134_dev *dev);
+int saa7134_i2c_unregister(struct saa7134_dev *dev);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-video.c                                             */
+
+extern unsigned int video_debug;
+extern struct video_device saa7134_video_template;
+extern struct video_device saa7134_radio_template;
+
+int saa7134_s_ctrl_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, struct v4l2_control *c);
+int saa7134_g_ctrl_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, struct v4l2_control *c);
+int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c);
+int saa7134_s_std_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, v4l2_std_id *id);
+
+int saa7134_videoport_init(struct saa7134_dev *dev);
+void saa7134_set_tvnorm_hw(struct saa7134_dev *dev);
+
+int saa7134_video_init1(struct saa7134_dev *dev);
+int saa7134_video_init2(struct saa7134_dev *dev);
+void saa7134_irq_video_signalchange(struct saa7134_dev *dev);
+void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-ts.c                                                */
+
+#define TS_PACKET_SIZE 188 /* TS packets 188 bytes */
+
+extern struct videobuf_queue_ops saa7134_ts_qops;
+
+int saa7134_ts_init1(struct saa7134_dev *dev);
+int saa7134_ts_fini(struct saa7134_dev *dev);
+void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status);
+
+int saa7134_ts_register(struct saa7134_mpeg_ops *ops);
+void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops);
+
+int saa7134_ts_init_hw(struct saa7134_dev *dev);
+
+int saa7134_ts_start(struct saa7134_dev *dev);
+int saa7134_ts_stop(struct saa7134_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* saa7134-vbi.c                                               */
+
+extern struct videobuf_queue_ops saa7134_vbi_qops;
+extern struct video_device saa7134_vbi_template;
+
+int saa7134_vbi_init1(struct saa7134_dev *dev);
+int saa7134_vbi_fini(struct saa7134_dev *dev);
+void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-tvaudio.c                                           */
+
+int saa7134_tvaudio_rx2mode(u32 rx);
+
+void saa7134_tvaudio_setmute(struct saa7134_dev *dev);
+void saa7134_tvaudio_setinput(struct saa7134_dev *dev,
+			      struct saa7134_input *in);
+void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level);
+int saa7134_tvaudio_getstereo(struct saa7134_dev *dev);
+
+void saa7134_tvaudio_init(struct saa7134_dev *dev);
+int saa7134_tvaudio_init2(struct saa7134_dev *dev);
+int saa7134_tvaudio_fini(struct saa7134_dev *dev);
+int saa7134_tvaudio_do_scan(struct saa7134_dev *dev);
+int saa7134_tvaudio_close(struct saa7134_dev *dev);
+
+int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value);
+
+void saa7134_enable_i2s(struct saa7134_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* saa7134-oss.c                                               */
+
+extern const struct file_operations saa7134_dsp_fops;
+extern const struct file_operations saa7134_mixer_fops;
+
+int saa7134_oss_init1(struct saa7134_dev *dev);
+int saa7134_oss_fini(struct saa7134_dev *dev);
+void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status);
+
+/* ----------------------------------------------------------- */
+/* saa7134-input.c                                             */
+
+#if defined(CONFIG_VIDEO_SAA7134_RC)
+int  saa7134_input_init1(struct saa7134_dev *dev);
+void saa7134_input_fini(struct saa7134_dev *dev);
+void saa7134_input_irq(struct saa7134_dev *dev);
+void saa7134_probe_i2c_ir(struct saa7134_dev *dev);
+int saa7134_ir_start(struct saa7134_dev *dev);
+void saa7134_ir_stop(struct saa7134_dev *dev);
+#else
+#define saa7134_input_init1(dev)	((void)0)
+#define saa7134_input_fini(dev)		((void)0)
+#define saa7134_input_irq(dev)		((void)0)
+#define saa7134_probe_i2c_ir(dev)	((void)0)
+#define saa7134_ir_start(dev)		((void)0)
+#define saa7134_ir_stop(dev)		((void)0)
+#endif
diff --git a/drivers/media/pci/saa7146/Kconfig b/drivers/media/pci/saa7146/Kconfig
new file mode 100644
index 0000000..8923b76
--- /dev/null
+++ b/drivers/media/pci/saa7146/Kconfig
@@ -0,0 +1,38 @@
+config VIDEO_HEXIUM_GEMINI
+	tristate "Hexium Gemini frame grabber"
+	depends on PCI && VIDEO_V4L2 && I2C
+	select VIDEO_SAA7146_VV
+	---help---
+	  This is a video4linux driver for the Hexium Gemini frame
+	  grabber card by Hexium. Please note that the Gemini Dual
+	  card is *not* fully supported.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called hexium_gemini.
+
+config VIDEO_HEXIUM_ORION
+	tristate "Hexium HV-PCI6 and Orion frame grabber"
+	depends on PCI && VIDEO_V4L2 && I2C
+	select VIDEO_SAA7146_VV
+	---help---
+	  This is a video4linux driver for the Hexium HV-PCI6 and
+	  Orion frame grabber cards by Hexium.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called hexium_orion.
+
+config VIDEO_MXB
+	tristate "Siemens-Nixdorf 'Multimedia eXtension Board'"
+	depends on PCI && VIDEO_V4L2 && I2C
+	select VIDEO_SAA7146_VV
+	select VIDEO_TUNER
+	select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_TEA6420 if VIDEO_HELPER_CHIPS_AUTO
+	---help---
+	  This is a video4linux driver for the 'Multimedia eXtension Board'
+	  TV card by Siemens-Nixdorf.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mxb.
diff --git a/drivers/media/pci/saa7146/Makefile b/drivers/media/pci/saa7146/Makefile
new file mode 100644
index 0000000..f3566a9
--- /dev/null
+++ b/drivers/media/pci/saa7146/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_VIDEO_MXB) += mxb.o
+obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
+obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
+
+ccflags-y += -I$(srctree)/drivers/media/i2c
diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c
new file mode 100644
index 0000000..366434f
--- /dev/null
+++ b/drivers/media/pci/saa7146/hexium_gemini.c
@@ -0,0 +1,430 @@
+/*
+    hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards
+
+    Visit http://www.mihu.de/linux/saa7146/ and follow the link
+    to "hexium" for further details about this card.
+
+    Copyright (C) 2003 Michael Hunold <michael@mihu.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define DEBUG_VARIABLE debug
+
+#include <media/saa7146_vv.h>
+#include <linux/module.h>
+
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "debug verbosity");
+
+/* global variables */
+static int hexium_num;
+
+#define HEXIUM_GEMINI			4
+#define HEXIUM_GEMINI_DUAL		5
+
+#define HEXIUM_INPUTS	9
+static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
+	{ 0, "CVBS 1",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 1, "CVBS 2",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 2, "CVBS 3",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 3, "CVBS 4",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 4, "CVBS 5",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 5, "CVBS 6",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 6, "Y/C 1",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 7, "Y/C 2",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 8, "Y/C 3",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+};
+
+#define HEXIUM_AUDIOS	0
+
+struct hexium_data
+{
+	s8 adr;
+	u8 byte;
+};
+
+#define HEXIUM_GEMINI_V_1_0		1
+#define HEXIUM_GEMINI_DUAL_V_1_0	2
+
+struct hexium
+{
+	int type;
+
+	struct video_device	*video_dev;
+	struct i2c_adapter	i2c_adapter;
+
+	int 		cur_input;	/* current input */
+	v4l2_std_id 	cur_std;	/* current standard */
+};
+
+/* Samsung KS0127B decoder default registers */
+static u8 hexium_ks0127b[0x100]={
+/*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10,
+/*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06,
+/*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00,
+/*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22,
+/*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00,
+/*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80,
+/*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00,
+/*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+
+static struct hexium_data hexium_pal[] = {
+	{ 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
+};
+
+static struct hexium_data hexium_ntsc[] = {
+	{ 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
+};
+
+static struct hexium_data hexium_secam[] = {
+	{ 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
+};
+
+static struct hexium_data hexium_input_select[] = {
+	{ 0x02, 0x60 },
+	{ 0x02, 0x64 },
+	{ 0x02, 0x61 },
+	{ 0x02, 0x65 },
+	{ 0x02, 0x62 },
+	{ 0x02, 0x66 },
+	{ 0x02, 0x68 },
+	{ 0x02, 0x69 },
+	{ 0x02, 0x6A },
+};
+
+/* fixme: h_offset = 0 for Hexium Gemini *Dual*, which
+   are currently *not* supported*/
+static struct saa7146_standard hexium_standards[] = {
+	{
+		.name	= "PAL", 	.id	= V4L2_STD_PAL,
+		.v_offset	= 28,	.v_field 	= 288,
+		.h_offset	= 1,	.h_pixels 	= 680,
+		.v_max_out	= 576,	.h_max_out	= 768,
+	}, {
+		.name	= "NTSC", 	.id	= V4L2_STD_NTSC,
+		.v_offset	= 28,	.v_field 	= 240,
+		.h_offset	= 1,	.h_pixels 	= 640,
+		.v_max_out	= 480,	.h_max_out	= 640,
+	}, {
+		.name	= "SECAM", 	.id	= V4L2_STD_SECAM,
+		.v_offset	= 28,	.v_field 	= 288,
+		.h_offset	= 1,	.h_pixels 	= 720,
+		.v_max_out	= 576,	.h_max_out	= 768,
+	}
+};
+
+/* bring hardware to a sane state. this has to be done, just in case someone
+   wants to capture from this device before it has been properly initialized.
+   the capture engine would badly fail, because no valid signal arrives on the
+   saa7146, thus leading to timeouts and stuff. */
+static int hexium_init_done(struct saa7146_dev *dev)
+{
+	struct hexium *hexium = (struct hexium *) dev->ext_priv;
+	union i2c_smbus_data data;
+	int i = 0;
+
+	DEB_D("hexium_init_done called\n");
+
+	/* initialize the helper ics to useful values */
+	for (i = 0; i < sizeof(hexium_ks0127b); i++) {
+		data.byte = hexium_ks0127b[i];
+		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
+			pr_err("hexium_init_done() failed for address 0x%02x\n",
+			       i);
+		}
+	}
+
+	return 0;
+}
+
+static int hexium_set_input(struct hexium *hexium, int input)
+{
+	union i2c_smbus_data data;
+
+	DEB_D("\n");
+
+	data.byte = hexium_input_select[input].byte;
+	if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
+{
+	union i2c_smbus_data data;
+	int i = 0;
+
+	DEB_D("\n");
+
+	while (vdec[i].adr != -1) {
+		data.byte = vdec[i].byte;
+		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) {
+			pr_err("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n",
+			       i);
+			return -1;
+		}
+		i++;
+	}
+	return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+	DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
+
+	if (i->index >= HEXIUM_INPUTS)
+		return -EINVAL;
+
+	memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
+
+	DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct hexium *hexium = (struct hexium *) dev->ext_priv;
+
+	*input = hexium->cur_input;
+
+	DEB_D("VIDIOC_G_INPUT: %d\n", *input);
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct hexium *hexium = (struct hexium *) dev->ext_priv;
+
+	DEB_EE("VIDIOC_S_INPUT %d\n", input);
+
+	if (input >= HEXIUM_INPUTS)
+		return -EINVAL;
+
+	hexium->cur_input = input;
+	hexium_set_input(hexium, input);
+	return 0;
+}
+
+static struct saa7146_ext_vv vv_data;
+
+/* this function only gets called when the probing was successful */
+static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
+{
+	struct hexium *hexium;
+	int ret;
+
+	DEB_EE("\n");
+
+	hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
+	if (NULL == hexium) {
+		pr_err("not enough kernel memory in hexium_attach()\n");
+		return -ENOMEM;
+	}
+	dev->ext_priv = hexium;
+
+	/* enable i2c-port pins */
+	saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
+
+	hexium->i2c_adapter = (struct i2c_adapter) {
+		.name = "hexium gemini",
+	};
+	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
+	if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
+		DEB_S("cannot register i2c-device. skipping.\n");
+		kfree(hexium);
+		return -EFAULT;
+	}
+
+	/*  set HWControl GPIO number 2 */
+	saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
+
+	saa7146_write(dev, DD1_INIT, 0x07000700);
+	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
+	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+
+	/* the rest */
+	hexium->cur_input = 0;
+	hexium_init_done(dev);
+
+	hexium_set_standard(hexium, hexium_pal);
+	hexium->cur_std = V4L2_STD_PAL;
+
+	hexium_set_input(hexium, 0);
+	hexium->cur_input = 0;
+
+	saa7146_vv_init(dev, &vv_data);
+
+	vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
+	vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
+	vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
+	ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER);
+	if (ret < 0) {
+		pr_err("cannot register capture v4l2 device. skipping.\n");
+		return ret;
+	}
+
+	pr_info("found 'hexium gemini' frame grabber-%d\n", hexium_num);
+	hexium_num++;
+
+	return 0;
+}
+
+static int hexium_detach(struct saa7146_dev *dev)
+{
+	struct hexium *hexium = (struct hexium *) dev->ext_priv;
+
+	DEB_EE("dev:%p\n", dev);
+
+	saa7146_unregister_device(&hexium->video_dev, dev);
+	saa7146_vv_release(dev);
+
+	hexium_num--;
+
+	i2c_del_adapter(&hexium->i2c_adapter);
+	kfree(hexium);
+	return 0;
+}
+
+static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
+{
+	struct hexium *hexium = (struct hexium *) dev->ext_priv;
+
+	if (V4L2_STD_PAL == std->id) {
+		hexium_set_standard(hexium, hexium_pal);
+		hexium->cur_std = V4L2_STD_PAL;
+		return 0;
+	} else if (V4L2_STD_NTSC == std->id) {
+		hexium_set_standard(hexium, hexium_ntsc);
+		hexium->cur_std = V4L2_STD_NTSC;
+		return 0;
+	} else if (V4L2_STD_SECAM == std->id) {
+		hexium_set_standard(hexium, hexium_secam);
+		hexium->cur_std = V4L2_STD_SECAM;
+		return 0;
+	}
+
+	return -1;
+}
+
+static struct saa7146_extension hexium_extension;
+
+static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
+	.ext_priv = "Hexium Gemini (4 BNC)",
+	.ext = &hexium_extension,
+};
+
+static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
+	.ext_priv = "Hexium Gemini Dual (4 BNC)",
+	.ext = &hexium_extension,
+};
+
+static struct pci_device_id pci_tbl[] = {
+	{
+	 .vendor = PCI_VENDOR_ID_PHILIPS,
+	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
+	 .subvendor = 0x17c8,
+	 .subdevice = 0x2401,
+	 .driver_data = (unsigned long) &hexium_gemini_4bnc,
+	 },
+	{
+	 .vendor = PCI_VENDOR_ID_PHILIPS,
+	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
+	 .subvendor = 0x17c8,
+	 .subdevice = 0x2402,
+	 .driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
+	 },
+	{
+	 .vendor = 0,
+	 }
+};
+
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+static struct saa7146_ext_vv vv_data = {
+	.inputs = HEXIUM_INPUTS,
+	.capabilities = 0,
+	.stds = &hexium_standards[0],
+	.num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
+	.std_callback = &std_callback,
+};
+
+static struct saa7146_extension hexium_extension = {
+	.name = "hexium gemini",
+	.flags = SAA7146_USE_I2C_IRQ,
+
+	.pci_tbl = &pci_tbl[0],
+	.module = THIS_MODULE,
+
+	.attach = hexium_attach,
+	.detach = hexium_detach,
+
+	.irq_mask = 0,
+	.irq_func = NULL,
+};
+
+static int __init hexium_init_module(void)
+{
+	if (0 != saa7146_register_extension(&hexium_extension)) {
+		DEB_S("failed to register extension\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void __exit hexium_cleanup_module(void)
+{
+	saa7146_unregister_extension(&hexium_extension);
+}
+
+module_init(hexium_init_module);
+module_exit(hexium_cleanup_module);
+
+MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c
new file mode 100644
index 0000000..a1eb26d
--- /dev/null
+++ b/drivers/media/pci/saa7146/hexium_orion.c
@@ -0,0 +1,502 @@
+/*
+    hexium_orion.c - v4l2 driver for the Hexium Orion frame grabber cards
+
+    Visit http://www.mihu.de/linux/saa7146/ and follow the link
+    to "hexium" for further details about this card.
+
+    Copyright (C) 2003 Michael Hunold <michael@mihu.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define DEBUG_VARIABLE debug
+
+#include <media/saa7146_vv.h>
+#include <linux/module.h>
+
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "debug verbosity");
+
+/* global variables */
+static int hexium_num;
+
+#define HEXIUM_HV_PCI6_ORION		1
+#define HEXIUM_ORION_1SVHS_3BNC		2
+#define HEXIUM_ORION_4BNC		3
+
+#define HEXIUM_INPUTS	9
+static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
+	{ 0, "CVBS 1",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 1, "CVBS 2",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 2, "CVBS 3",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 3, "CVBS 4",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 4, "CVBS 5",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 5, "CVBS 6",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 6, "Y/C 1",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 7, "Y/C 2",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ 8, "Y/C 3",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+};
+
+#define HEXIUM_AUDIOS	0
+
+struct hexium_data
+{
+	s8 adr;
+	u8 byte;
+};
+
+struct hexium
+{
+	int type;
+	struct video_device	*video_dev;
+	struct i2c_adapter	i2c_adapter;
+
+	int cur_input;	/* current input */
+};
+
+/* Philips SAA7110 decoder default registers */
+static u8 hexium_saa7110[53]={
+/*00*/ 0x4C,0x3C,0x0D,0xEF,0xBD,0xF0,0x00,0x00,
+/*08*/ 0xF8,0xF8,0x60,0x60,0x40,0x86,0x18,0x90,
+/*10*/ 0x00,0x2C,0x40,0x46,0x42,0x1A,0xFF,0xDA,
+/*18*/ 0xF0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00,
+/*20*/ 0xD9,0x17,0x40,0x41,0x80,0x41,0x80,0x4F,
+/*28*/ 0xFE,0x01,0x0F,0x0F,0x03,0x01,0x81,0x03,
+/*30*/ 0x44,0x75,0x01,0x8C,0x03
+};
+
+static struct {
+	struct hexium_data data[8];
+} hexium_input_select[] = {
+{
+	{ /* cvbs 1 */
+		{ 0x06, 0x00 },
+		{ 0x20, 0xD9 },
+		{ 0x21, 0x17 }, // 0x16,
+		{ 0x22, 0x40 },
+		{ 0x2C, 0x03 },
+		{ 0x30, 0x44 },
+		{ 0x31, 0x75 }, // ??
+		{ 0x21, 0x16 }, // 0x03,
+	}
+}, {
+	{ /* cvbs 2 */
+		{ 0x06, 0x00 },
+		{ 0x20, 0x78 },
+		{ 0x21, 0x07 }, // 0x03,
+		{ 0x22, 0xD2 },
+		{ 0x2C, 0x83 },
+		{ 0x30, 0x60 },
+		{ 0x31, 0xB5 }, // ?
+		{ 0x21, 0x03 },
+	}
+}, {
+	{ /* cvbs 3 */
+		{ 0x06, 0x00 },
+		{ 0x20, 0xBA },
+		{ 0x21, 0x07 }, // 0x05,
+		{ 0x22, 0x91 },
+		{ 0x2C, 0x03 },
+		{ 0x30, 0x60 },
+		{ 0x31, 0xB5 }, // ??
+		{ 0x21, 0x05 }, // 0x03,
+	}
+}, {
+	{ /* cvbs 4 */
+		{ 0x06, 0x00 },
+		{ 0x20, 0xD8 },
+		{ 0x21, 0x17 }, // 0x16,
+		{ 0x22, 0x40 },
+		{ 0x2C, 0x03 },
+		{ 0x30, 0x44 },
+		{ 0x31, 0x75 }, // ??
+		{ 0x21, 0x16 }, // 0x03,
+	}
+}, {
+	{ /* cvbs 5 */
+		{ 0x06, 0x00 },
+		{ 0x20, 0xB8 },
+		{ 0x21, 0x07 }, // 0x05,
+		{ 0x22, 0x91 },
+		{ 0x2C, 0x03 },
+		{ 0x30, 0x60 },
+		{ 0x31, 0xB5 }, // ??
+		{ 0x21, 0x05 }, // 0x03,
+	}
+}, {
+	{ /* cvbs 6 */
+		{ 0x06, 0x00 },
+		{ 0x20, 0x7C },
+		{ 0x21, 0x07 }, // 0x03
+		{ 0x22, 0xD2 },
+		{ 0x2C, 0x83 },
+		{ 0x30, 0x60 },
+		{ 0x31, 0xB5 }, // ??
+		{ 0x21, 0x03 },
+	}
+}, {
+	{ /* y/c 1 */
+		{ 0x06, 0x80 },
+		{ 0x20, 0x59 },
+		{ 0x21, 0x17 },
+		{ 0x22, 0x42 },
+		{ 0x2C, 0xA3 },
+		{ 0x30, 0x44 },
+		{ 0x31, 0x75 },
+		{ 0x21, 0x12 },
+	}
+}, {
+	{ /* y/c 2 */
+		{ 0x06, 0x80 },
+		{ 0x20, 0x9A },
+		{ 0x21, 0x17 },
+		{ 0x22, 0xB1 },
+		{ 0x2C, 0x13 },
+		{ 0x30, 0x60 },
+		{ 0x31, 0xB5 },
+		{ 0x21, 0x14 },
+	}
+}, {
+	{ /* y/c 3 */
+		{ 0x06, 0x80 },
+		{ 0x20, 0x3C },
+		{ 0x21, 0x27 },
+		{ 0x22, 0xC1 },
+		{ 0x2C, 0x23 },
+		{ 0x30, 0x44 },
+		{ 0x31, 0x75 },
+		{ 0x21, 0x21 },
+	}
+}
+};
+
+static struct saa7146_standard hexium_standards[] = {
+	{
+		.name	= "PAL", 	.id	= V4L2_STD_PAL,
+		.v_offset	= 16,	.v_field 	= 288,
+		.h_offset	= 1,	.h_pixels 	= 680,
+		.v_max_out	= 576,	.h_max_out	= 768,
+	}, {
+		.name	= "NTSC", 	.id	= V4L2_STD_NTSC,
+		.v_offset	= 16,	.v_field 	= 240,
+		.h_offset	= 1,	.h_pixels 	= 640,
+		.v_max_out	= 480,	.h_max_out	= 640,
+	}, {
+		.name	= "SECAM", 	.id	= V4L2_STD_SECAM,
+		.v_offset	= 16,	.v_field 	= 288,
+		.h_offset	= 1,	.h_pixels 	= 720,
+		.v_max_out	= 576,	.h_max_out	= 768,
+	}
+};
+
+/* this is only called for old HV-PCI6/Orion cards
+   without eeprom */
+static int hexium_probe(struct saa7146_dev *dev)
+{
+	struct hexium *hexium = NULL;
+	union i2c_smbus_data data;
+	int err = 0;
+
+	DEB_EE("\n");
+
+	/* there are no hexium orion cards with revision 0 saa7146s */
+	if (0 == dev->revision) {
+		return -EFAULT;
+	}
+
+	hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
+	if (NULL == hexium) {
+		pr_err("hexium_probe: not enough kernel memory\n");
+		return -ENOMEM;
+	}
+
+	/* enable i2c-port pins */
+	saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
+
+	saa7146_write(dev, DD1_INIT, 0x01000100);
+	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
+	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+
+	hexium->i2c_adapter = (struct i2c_adapter) {
+		.name = "hexium orion",
+	};
+	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
+	if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
+		DEB_S("cannot register i2c-device. skipping.\n");
+		kfree(hexium);
+		return -EFAULT;
+	}
+
+	/* set SAA7110 control GPIO 0 */
+	saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
+	/*  set HWControl GPIO number 2 */
+	saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
+
+	mdelay(10);
+
+	/* detect newer Hexium Orion cards by subsystem ids */
+	if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) {
+		pr_info("device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs\n");
+		/* we store the pointer in our private data field */
+		dev->ext_priv = hexium;
+		hexium->type = HEXIUM_ORION_1SVHS_3BNC;
+		return 0;
+	}
+
+	if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) {
+		pr_info("device is a Hexium Orion w/ 4 BNC inputs\n");
+		/* we store the pointer in our private data field */
+		dev->ext_priv = hexium;
+		hexium->type = HEXIUM_ORION_4BNC;
+		return 0;
+	}
+
+	/* check if this is an old hexium Orion card by looking at
+	   a saa7110 at address 0x4e */
+	if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) {
+		pr_info("device is a Hexium HV-PCI6/Orion (old)\n");
+		/* we store the pointer in our private data field */
+		dev->ext_priv = hexium;
+		hexium->type = HEXIUM_HV_PCI6_ORION;
+		return 0;
+	}
+
+	i2c_del_adapter(&hexium->i2c_adapter);
+	kfree(hexium);
+	return -EFAULT;
+}
+
+/* bring hardware to a sane state. this has to be done, just in case someone
+   wants to capture from this device before it has been properly initialized.
+   the capture engine would badly fail, because no valid signal arrives on the
+   saa7146, thus leading to timeouts and stuff. */
+static int hexium_init_done(struct saa7146_dev *dev)
+{
+	struct hexium *hexium = (struct hexium *) dev->ext_priv;
+	union i2c_smbus_data data;
+	int i = 0;
+
+	DEB_D("hexium_init_done called\n");
+
+	/* initialize the helper ics to useful values */
+	for (i = 0; i < sizeof(hexium_saa7110); i++) {
+		data.byte = hexium_saa7110[i];
+		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
+			pr_err("failed for address 0x%02x\n", i);
+		}
+	}
+
+	return 0;
+}
+
+static int hexium_set_input(struct hexium *hexium, int input)
+{
+	union i2c_smbus_data data;
+	int i = 0;
+
+	DEB_D("\n");
+
+	for (i = 0; i < 8; i++) {
+		int adr = hexium_input_select[input].data[i].adr;
+		data.byte = hexium_input_select[input].data[i].byte;
+		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) {
+			return -1;
+		}
+		pr_debug("%d: 0x%02x => 0x%02x\n", input, adr, data.byte);
+	}
+
+	return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+	DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
+
+	if (i->index >= HEXIUM_INPUTS)
+		return -EINVAL;
+
+	memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
+
+	DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct hexium *hexium = (struct hexium *) dev->ext_priv;
+
+	*input = hexium->cur_input;
+
+	DEB_D("VIDIOC_G_INPUT: %d\n", *input);
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct hexium *hexium = (struct hexium *) dev->ext_priv;
+
+	if (input >= HEXIUM_INPUTS)
+		return -EINVAL;
+
+	hexium->cur_input = input;
+	hexium_set_input(hexium, input);
+
+	return 0;
+}
+
+static struct saa7146_ext_vv vv_data;
+
+/* this function only gets called when the probing was successful */
+static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
+{
+	struct hexium *hexium = (struct hexium *) dev->ext_priv;
+
+	DEB_EE("\n");
+
+	saa7146_vv_init(dev, &vv_data);
+	vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
+	vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
+	vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
+	if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
+		pr_err("cannot register capture v4l2 device. skipping.\n");
+		return -1;
+	}
+
+	pr_err("found 'hexium orion' frame grabber-%d\n", hexium_num);
+	hexium_num++;
+
+	/* the rest */
+	hexium->cur_input = 0;
+	hexium_init_done(dev);
+
+	return 0;
+}
+
+static int hexium_detach(struct saa7146_dev *dev)
+{
+	struct hexium *hexium = (struct hexium *) dev->ext_priv;
+
+	DEB_EE("dev:%p\n", dev);
+
+	saa7146_unregister_device(&hexium->video_dev, dev);
+	saa7146_vv_release(dev);
+
+	hexium_num--;
+
+	i2c_del_adapter(&hexium->i2c_adapter);
+	kfree(hexium);
+	return 0;
+}
+
+static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
+{
+	return 0;
+}
+
+static struct saa7146_extension extension;
+
+static struct saa7146_pci_extension_data hexium_hv_pci6 = {
+	.ext_priv = "Hexium HV-PCI6 / Orion",
+	.ext = &extension,
+};
+
+static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = {
+	.ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)",
+	.ext = &extension,
+};
+
+static struct saa7146_pci_extension_data hexium_orion_4bnc = {
+	.ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)",
+	.ext = &extension,
+};
+
+static struct pci_device_id pci_tbl[] = {
+	{
+	 .vendor = PCI_VENDOR_ID_PHILIPS,
+	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
+	 .subvendor = 0x0000,
+	 .subdevice = 0x0000,
+	 .driver_data = (unsigned long) &hexium_hv_pci6,
+	 },
+	{
+	 .vendor = PCI_VENDOR_ID_PHILIPS,
+	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
+	 .subvendor = 0x17c8,
+	 .subdevice = 0x0101,
+	 .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc,
+	 },
+	{
+	 .vendor = PCI_VENDOR_ID_PHILIPS,
+	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
+	 .subvendor = 0x17c8,
+	 .subdevice = 0x2101,
+	 .driver_data = (unsigned long) &hexium_orion_4bnc,
+	 },
+	{
+	 .vendor = 0,
+	 }
+};
+
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+static struct saa7146_ext_vv vv_data = {
+	.inputs = HEXIUM_INPUTS,
+	.capabilities = 0,
+	.stds = &hexium_standards[0],
+	.num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
+	.std_callback = &std_callback,
+};
+
+static struct saa7146_extension extension = {
+	.name = "hexium HV-PCI6 Orion",
+	.flags = 0,		// SAA7146_USE_I2C_IRQ,
+
+	.pci_tbl = &pci_tbl[0],
+	.module = THIS_MODULE,
+
+	.probe = hexium_probe,
+	.attach = hexium_attach,
+	.detach = hexium_detach,
+
+	.irq_mask = 0,
+	.irq_func = NULL,
+};
+
+static int __init hexium_init_module(void)
+{
+	if (0 != saa7146_register_extension(&extension)) {
+		DEB_S("failed to register extension\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void __exit hexium_cleanup_module(void)
+{
+	saa7146_unregister_extension(&extension);
+}
+
+module_init(hexium_init_module);
+module_exit(hexium_cleanup_module);
+
+MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards");
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c
new file mode 100644
index 0000000..b520a45
--- /dev/null
+++ b/drivers/media/pci/saa7146/mxb.c
@@ -0,0 +1,886 @@
+/*
+    mxb - v4l2 driver for the Multimedia eXtension Board
+
+    Copyright (C) 1998-2006 Michael Hunold <michael@mihu.de>
+
+    Visit http://www.themm.net/~mihu/linux/saa7146/mxb.html 
+    for further details about this card.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define DEBUG_VARIABLE debug
+
+#include <media/saa7146_vv.h>
+#include <media/tuner.h>
+#include <media/v4l2-common.h>
+#include <media/saa7115.h>
+#include <linux/module.h>
+
+#include "tea6415c.h"
+#include "tea6420.h"
+
+#define MXB_AUDIOS	6
+
+#define I2C_SAA7111A  0x24
+#define	I2C_TDA9840   0x42
+#define	I2C_TEA6415C  0x43
+#define	I2C_TEA6420_1 0x4c
+#define	I2C_TEA6420_2 0x4d
+#define	I2C_TUNER     0x60
+
+#define MXB_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0)
+
+/* global variable */
+static int mxb_num;
+
+/* initial frequence the tuner will be tuned to.
+   in verden (lower saxony, germany) 4148 is a
+   channel called "phoenix" */
+static int freq = 4148;
+module_param(freq, int, 0644);
+MODULE_PARM_DESC(freq, "initial frequency the tuner will be tuned to while setup");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
+
+#define MXB_INPUTS 4
+enum { TUNER, AUX1, AUX3, AUX3_YC };
+
+static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
+	{ TUNER,   "Tuner",          V4L2_INPUT_TYPE_TUNER,  0x3f, 0,
+		V4L2_STD_PAL_BG | V4L2_STD_PAL_I, 0, V4L2_IN_CAP_STD },
+	{ AUX1,	   "AUX1",           V4L2_INPUT_TYPE_CAMERA, 0x3f, 0,
+		V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ AUX3,	   "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 0x3f, 0,
+		V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+	{ AUX3_YC, "AUX3 S-Video",   V4L2_INPUT_TYPE_CAMERA, 0x3f, 0,
+		V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+};
+
+/* this array holds the information, which port of the saa7146 each
+   input actually uses. the mxb uses port 0 for every input */
+static struct {
+	int hps_source;
+	int hps_sync;
+} input_port_selection[MXB_INPUTS] = {
+	{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
+	{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
+	{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
+	{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
+};
+
+/* this array holds the information of the audio source (mxb_audios),
+   which has to be switched corresponding to the video source (mxb_channels) */
+static int video_audio_connect[MXB_INPUTS] =
+	{ 0, 1, 3, 3 };
+
+struct mxb_routing {
+	u32 input;
+	u32 output;
+};
+
+/* these are the available audio sources, which can switched
+   to the line- and cd-output individually */
+static struct v4l2_audio mxb_audios[MXB_AUDIOS] = {
+	    {
+		.index	= 0,
+		.name	= "Tuner",
+		.capability = V4L2_AUDCAP_STEREO,
+	} , {
+		.index	= 1,
+		.name	= "AUX1",
+		.capability = V4L2_AUDCAP_STEREO,
+	} , {
+		.index	= 2,
+		.name	= "AUX2",
+		.capability = V4L2_AUDCAP_STEREO,
+	} , {
+		.index	= 3,
+		.name	= "AUX3",
+		.capability = V4L2_AUDCAP_STEREO,
+	} , {
+		.index	= 4,
+		.name	= "Radio (X9)",
+		.capability = V4L2_AUDCAP_STEREO,
+	} , {
+		.index	= 5,
+		.name	= "CD-ROM (X10)",
+		.capability = V4L2_AUDCAP_STEREO,
+	}
+};
+
+/* These are the necessary input-output-pins for bringing one audio source
+   (see above) to the CD-output. Note that gain is set to 0 in this table. */
+static struct mxb_routing TEA6420_cd[MXB_AUDIOS + 1][2] = {
+	{ { 1, 1 }, { 1, 1 } },	/* Tuner */
+	{ { 5, 1 }, { 6, 1 } },	/* AUX 1 */
+	{ { 4, 1 }, { 6, 1 } },	/* AUX 2 */
+	{ { 3, 1 }, { 6, 1 } },	/* AUX 3 */
+	{ { 1, 1 }, { 3, 1 } },	/* Radio */
+	{ { 1, 1 }, { 2, 1 } },	/* CD-Rom */
+	{ { 6, 1 }, { 6, 1 } }	/* Mute */
+};
+
+/* These are the necessary input-output-pins for bringing one audio source
+   (see above) to the line-output. Note that gain is set to 0 in this table. */
+static struct mxb_routing TEA6420_line[MXB_AUDIOS + 1][2] = {
+	{ { 2, 3 }, { 1, 2 } },
+	{ { 5, 3 }, { 6, 2 } },
+	{ { 4, 3 }, { 6, 2 } },
+	{ { 3, 3 }, { 6, 2 } },
+	{ { 2, 3 }, { 3, 2 } },
+	{ { 2, 3 }, { 2, 2 } },
+	{ { 6, 3 }, { 6, 2 } }	/* Mute */
+};
+
+struct mxb
+{
+	struct video_device	*video_dev;
+	struct video_device	*vbi_dev;
+
+	struct i2c_adapter	i2c_adapter;
+
+	struct v4l2_subdev	*saa7111a;
+	struct v4l2_subdev	*tda9840;
+	struct v4l2_subdev	*tea6415c;
+	struct v4l2_subdev	*tuner;
+	struct v4l2_subdev	*tea6420_1;
+	struct v4l2_subdev	*tea6420_2;
+
+	int	cur_mode;	/* current audio mode (mono, stereo, ...) */
+	int	cur_input;	/* current input */
+	int	cur_audinput;	/* current audio input */
+	int	cur_mute;	/* current mute status */
+	struct v4l2_frequency	cur_freq;	/* current frequency the tuner is tuned to */
+};
+
+#define saa7111a_call(mxb, o, f, args...) \
+	v4l2_subdev_call(mxb->saa7111a, o, f, ##args)
+#define tda9840_call(mxb, o, f, args...) \
+	v4l2_subdev_call(mxb->tda9840, o, f, ##args)
+#define tea6415c_call(mxb, o, f, args...) \
+	v4l2_subdev_call(mxb->tea6415c, o, f, ##args)
+#define tuner_call(mxb, o, f, args...) \
+	v4l2_subdev_call(mxb->tuner, o, f, ##args)
+#define call_all(dev, o, f, args...) \
+	v4l2_device_call_until_err(&dev->v4l2_dev, 0, o, f, ##args)
+
+static void mxb_update_audmode(struct mxb *mxb)
+{
+	struct v4l2_tuner t = {
+		.audmode = mxb->cur_mode,
+	};
+
+	tda9840_call(mxb, tuner, s_tuner, &t);
+}
+
+static inline void tea6420_route(struct mxb *mxb, int idx)
+{
+	v4l2_subdev_call(mxb->tea6420_1, audio, s_routing,
+		TEA6420_cd[idx][0].input, TEA6420_cd[idx][0].output, 0);
+	v4l2_subdev_call(mxb->tea6420_2, audio, s_routing,
+		TEA6420_cd[idx][1].input, TEA6420_cd[idx][1].output, 0);
+	v4l2_subdev_call(mxb->tea6420_1, audio, s_routing,
+		TEA6420_line[idx][0].input, TEA6420_line[idx][0].output, 0);
+	v4l2_subdev_call(mxb->tea6420_2, audio, s_routing,
+		TEA6420_line[idx][1].input, TEA6420_line[idx][1].output, 0);
+}
+
+static struct saa7146_extension extension;
+
+static int mxb_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct saa7146_dev *dev = container_of(ctrl->handler,
+				struct saa7146_dev, ctrl_handler);
+	struct mxb *mxb = dev->ext_priv;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		mxb->cur_mute = ctrl->val;
+		/* switch the audio-source */
+		tea6420_route(mxb, ctrl->val ? 6 :
+				video_audio_connect[mxb->cur_input]);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops mxb_ctrl_ops = {
+	.s_ctrl = mxb_s_ctrl,
+};
+
+static int mxb_probe(struct saa7146_dev *dev)
+{
+	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
+	struct mxb *mxb = NULL;
+
+	v4l2_ctrl_new_std(hdl, &mxb_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+	if (hdl->error)
+		return hdl->error;
+	mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
+	if (mxb == NULL) {
+		DEB_D("not enough kernel memory\n");
+		return -ENOMEM;
+	}
+
+
+	snprintf(mxb->i2c_adapter.name, sizeof(mxb->i2c_adapter.name), "mxb%d", mxb_num);
+
+	saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
+	if (i2c_add_adapter(&mxb->i2c_adapter) < 0) {
+		DEB_S("cannot register i2c-device. skipping.\n");
+		kfree(mxb);
+		return -EFAULT;
+	}
+
+	mxb->saa7111a = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
+			"saa7111", I2C_SAA7111A, NULL);
+	mxb->tea6420_1 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
+			"tea6420", I2C_TEA6420_1, NULL);
+	mxb->tea6420_2 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
+			"tea6420", I2C_TEA6420_2, NULL);
+	mxb->tea6415c = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
+			"tea6415c", I2C_TEA6415C, NULL);
+	mxb->tda9840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
+			"tda9840", I2C_TDA9840, NULL);
+	mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
+			"tuner", I2C_TUNER, NULL);
+
+	/* check if all devices are present */
+	if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
+	    !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) {
+		pr_err("did not find all i2c devices. aborting\n");
+		i2c_del_adapter(&mxb->i2c_adapter);
+		kfree(mxb);
+		return -ENODEV;
+	}
+
+	/* all devices are present, probe was successful */
+
+	/* we store the pointer in our private data field */
+	dev->ext_priv = mxb;
+
+	v4l2_ctrl_handler_setup(hdl);
+
+	return 0;
+}
+
+/* some init data for the saa7740, the so-called 'sound arena module'.
+   there are no specs available, so we simply use some init values */
+static struct {
+	int	length;
+	char	data[9];
+} mxb_saa7740_init[] = {
+	{ 3, { 0x80, 0x00, 0x00 } },{ 3, { 0x80, 0x89, 0x00 } },
+	{ 3, { 0x80, 0xb0, 0x0a } },{ 3, { 0x00, 0x00, 0x00 } },
+	{ 3, { 0x49, 0x00, 0x00 } },{ 3, { 0x4a, 0x00, 0x00 } },
+	{ 3, { 0x4b, 0x00, 0x00 } },{ 3, { 0x4c, 0x00, 0x00 } },
+	{ 3, { 0x4d, 0x00, 0x00 } },{ 3, { 0x4e, 0x00, 0x00 } },
+	{ 3, { 0x4f, 0x00, 0x00 } },{ 3, { 0x50, 0x00, 0x00 } },
+	{ 3, { 0x51, 0x00, 0x00 } },{ 3, { 0x52, 0x00, 0x00 } },
+	{ 3, { 0x53, 0x00, 0x00 } },{ 3, { 0x54, 0x00, 0x00 } },
+	{ 3, { 0x55, 0x00, 0x00 } },{ 3, { 0x56, 0x00, 0x00 } },
+	{ 3, { 0x57, 0x00, 0x00 } },{ 3, { 0x58, 0x00, 0x00 } },
+	{ 3, { 0x59, 0x00, 0x00 } },{ 3, { 0x5a, 0x00, 0x00 } },
+	{ 3, { 0x5b, 0x00, 0x00 } },{ 3, { 0x5c, 0x00, 0x00 } },
+	{ 3, { 0x5d, 0x00, 0x00 } },{ 3, { 0x5e, 0x00, 0x00 } },
+	{ 3, { 0x5f, 0x00, 0x00 } },{ 3, { 0x60, 0x00, 0x00 } },
+	{ 3, { 0x61, 0x00, 0x00 } },{ 3, { 0x62, 0x00, 0x00 } },
+	{ 3, { 0x63, 0x00, 0x00 } },{ 3, { 0x64, 0x00, 0x00 } },
+	{ 3, { 0x65, 0x00, 0x00 } },{ 3, { 0x66, 0x00, 0x00 } },
+	{ 3, { 0x67, 0x00, 0x00 } },{ 3, { 0x68, 0x00, 0x00 } },
+	{ 3, { 0x69, 0x00, 0x00 } },{ 3, { 0x6a, 0x00, 0x00 } },
+	{ 3, { 0x6b, 0x00, 0x00 } },{ 3, { 0x6c, 0x00, 0x00 } },
+	{ 3, { 0x6d, 0x00, 0x00 } },{ 3, { 0x6e, 0x00, 0x00 } },
+	{ 3, { 0x6f, 0x00, 0x00 } },{ 3, { 0x70, 0x00, 0x00 } },
+	{ 3, { 0x71, 0x00, 0x00 } },{ 3, { 0x72, 0x00, 0x00 } },
+	{ 3, { 0x73, 0x00, 0x00 } },{ 3, { 0x74, 0x00, 0x00 } },
+	{ 3, { 0x75, 0x00, 0x00 } },{ 3, { 0x76, 0x00, 0x00 } },
+	{ 3, { 0x77, 0x00, 0x00 } },{ 3, { 0x41, 0x00, 0x42 } },
+	{ 3, { 0x42, 0x10, 0x42 } },{ 3, { 0x43, 0x20, 0x42 } },
+	{ 3, { 0x44, 0x30, 0x42 } },{ 3, { 0x45, 0x00, 0x01 } },
+	{ 3, { 0x46, 0x00, 0x01 } },{ 3, { 0x47, 0x00, 0x01 } },
+	{ 3, { 0x48, 0x00, 0x01 } },
+	{ 9, { 0x01, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
+	{ 9, { 0x21, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
+	{ 9, { 0x09, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
+	{ 9, { 0x29, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
+	{ 9, { 0x11, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
+	{ 9, { 0x31, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
+	{ 9, { 0x19, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
+	{ 9, { 0x39, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
+	{ 9, { 0x05, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
+	{ 9, { 0x25, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
+	{ 9, { 0x0d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
+	{ 9, { 0x2d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
+	{ 9, { 0x15, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
+	{ 9, { 0x35, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
+	{ 9, { 0x1d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
+	{ 9, { 0x3d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
+	{ 3, { 0x80, 0xb3, 0x0a } },
+	{-1, { 0 } }
+};
+
+/* bring hardware to a sane state. this has to be done, just in case someone
+   wants to capture from this device before it has been properly initialized.
+   the capture engine would badly fail, because no valid signal arrives on the
+   saa7146, thus leading to timeouts and stuff. */
+static int mxb_init_done(struct saa7146_dev* dev)
+{
+	struct mxb* mxb = (struct mxb*)dev->ext_priv;
+	struct i2c_msg msg;
+	struct tuner_setup tun_setup;
+	v4l2_std_id std = V4L2_STD_PAL_BG;
+
+	int i = 0, err = 0;
+
+	/* mute audio on tea6420s */
+	tea6420_route(mxb, 6);
+
+	/* select video mode in saa7111a */
+	saa7111a_call(mxb, core, s_std, std);
+
+	/* select tuner-output on saa7111a */
+	i = 0;
+	saa7111a_call(mxb, video, s_routing, SAA7115_COMPOSITE0,
+		SAA7111_FMT_CCIR, 0);
+
+	/* select a tuner type */
+	tun_setup.mode_mask = T_ANALOG_TV;
+	tun_setup.addr = ADDR_UNSET;
+	tun_setup.type = TUNER_PHILIPS_PAL;
+	tuner_call(mxb, tuner, s_type_addr, &tun_setup);
+	/* tune in some frequency on tuner */
+	mxb->cur_freq.tuner = 0;
+	mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
+	mxb->cur_freq.frequency = freq;
+	tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq);
+
+	/* set a default video standard */
+	/* These two gpio calls set the GPIO pins that control the tda9820 */
+	saa7146_write(dev, GPIO_CTRL, 0x00404050);
+	saa7111a_call(mxb, core, s_gpio, 1);
+	saa7111a_call(mxb, core, s_std, std);
+	tuner_call(mxb, core, s_std, std);
+
+	/* switch to tuner-channel on tea6415c */
+	tea6415c_call(mxb, video, s_routing, 3, 17, 0);
+
+	/* select tuner-output on multicable on tea6415c */
+	tea6415c_call(mxb, video, s_routing, 3, 13, 0);
+
+	/* the rest for mxb */
+	mxb->cur_input = 0;
+	mxb->cur_audinput = video_audio_connect[mxb->cur_input];
+	mxb->cur_mute = 1;
+
+	mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
+	mxb_update_audmode(mxb);
+
+	/* check if the saa7740 (aka 'sound arena module') is present
+	   on the mxb. if so, we must initialize it. due to lack of
+	   informations about the saa7740, the values were reverse
+	   engineered. */
+	msg.addr = 0x1b;
+	msg.flags = 0;
+	msg.len = mxb_saa7740_init[0].length;
+	msg.buf = &mxb_saa7740_init[0].data[0];
+
+	err = i2c_transfer(&mxb->i2c_adapter, &msg, 1);
+	if (err == 1) {
+		/* the sound arena module is a pos, that's probably the reason
+		   philips refuses to hand out a datasheet for the saa7740...
+		   it seems to screw up the i2c bus, so we disable fast irq
+		   based i2c transactions here and rely on the slow and safe
+		   polling method ... */
+		extension.flags &= ~SAA7146_USE_I2C_IRQ;
+		for (i = 1; ; i++) {
+			if (-1 == mxb_saa7740_init[i].length)
+				break;
+
+			msg.len = mxb_saa7740_init[i].length;
+			msg.buf = &mxb_saa7740_init[i].data[0];
+			err = i2c_transfer(&mxb->i2c_adapter, &msg, 1);
+			if (err != 1) {
+				DEB_D("failed to initialize 'sound arena module'\n");
+				goto err;
+			}
+		}
+		pr_info("'sound arena module' detected\n");
+	}
+err:
+	/* the rest for saa7146: you should definitely set some basic values
+	   for the input-port handling of the saa7146. */
+
+	/* ext->saa has been filled by the core driver */
+
+	/* some stuff is done via variables */
+	saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source,
+			input_port_selection[mxb->cur_input].hps_sync);
+
+	/* some stuff is done via direct write to the registers */
+
+	/* this is ugly, but because of the fact that this is completely
+	   hardware dependend, it should be done directly... */
+	saa7146_write(dev, DD1_STREAM_B,	0x00000000);
+	saa7146_write(dev, DD1_INIT,		0x02000200);
+	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+
+	return 0;
+}
+
+/* interrupt-handler. this gets called when irq_mask is != 0.
+   it must clear the interrupt-bits in irq_mask it has handled */
+/*
+void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask)
+{
+	struct mxb* mxb = (struct mxb*)dev->ext_priv;
+}
+*/
+
+static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+	DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
+	if (i->index >= MXB_INPUTS)
+		return -EINVAL;
+	memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct mxb *mxb = (struct mxb *)dev->ext_priv;
+	*i = mxb->cur_input;
+
+	DEB_EE("VIDIOC_G_INPUT %d\n", *i);
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct mxb *mxb = (struct mxb *)dev->ext_priv;
+	int err = 0;
+	int i = 0;
+
+	DEB_EE("VIDIOC_S_INPUT %d\n", input);
+
+	if (input >= MXB_INPUTS)
+		return -EINVAL;
+
+	mxb->cur_input = input;
+
+	saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source,
+			input_port_selection[input].hps_sync);
+
+	/* prepare switching of tea6415c and saa7111a;
+	   have a look at the 'background'-file for further informations  */
+	switch (input) {
+	case TUNER:
+		i = SAA7115_COMPOSITE0;
+
+		err = tea6415c_call(mxb, video, s_routing, 3, 17, 0);
+
+		/* connect tuner-output always to multicable */
+		if (!err)
+			err = tea6415c_call(mxb, video, s_routing, 3, 13, 0);
+		break;
+	case AUX3_YC:
+		/* nothing to be done here. aux3_yc is
+		   directly connected to the saa711a */
+		i = SAA7115_SVIDEO1;
+		break;
+	case AUX3:
+		/* nothing to be done here. aux3 is
+		   directly connected to the saa711a */
+		i = SAA7115_COMPOSITE1;
+		break;
+	case AUX1:
+		i = SAA7115_COMPOSITE0;
+		err = tea6415c_call(mxb, video, s_routing, 1, 17, 0);
+		break;
+	}
+
+	if (err)
+		return err;
+
+	/* switch video in saa7111a */
+	if (saa7111a_call(mxb, video, s_routing, i, SAA7111_FMT_CCIR, 0))
+		pr_err("VIDIOC_S_INPUT: could not address saa7111a\n");
+
+	mxb->cur_audinput = video_audio_connect[input];
+	/* switch the audio-source only if necessary */
+	if (0 == mxb->cur_mute)
+		tea6420_route(mxb, mxb->cur_audinput);
+	if (mxb->cur_audinput == 0)
+		mxb_update_audmode(mxb);
+
+	return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct mxb *mxb = (struct mxb *)dev->ext_priv;
+
+	if (t->index) {
+		DEB_D("VIDIOC_G_TUNER: channel %d does not have a tuner attached\n",
+		      t->index);
+		return -EINVAL;
+	}
+
+	DEB_EE("VIDIOC_G_TUNER: %d\n", t->index);
+
+	memset(t, 0, sizeof(*t));
+	strlcpy(t->name, "TV Tuner", sizeof(t->name));
+	t->type = V4L2_TUNER_ANALOG_TV;
+	t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
+			V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+	t->audmode = mxb->cur_mode;
+	return call_all(dev, tuner, g_tuner, t);
+}
+
+static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct mxb *mxb = (struct mxb *)dev->ext_priv;
+
+	if (t->index) {
+		DEB_D("VIDIOC_S_TUNER: channel %d does not have a tuner attached\n",
+		      t->index);
+		return -EINVAL;
+	}
+
+	mxb->cur_mode = t->audmode;
+	return call_all(dev, tuner, s_tuner, t);
+}
+
+static int vidioc_querystd(struct file *file, void *fh, v4l2_std_id *norm)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+
+	return call_all(dev, video, querystd, norm);
+}
+
+static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct mxb *mxb = (struct mxb *)dev->ext_priv;
+
+	if (f->tuner)
+		return -EINVAL;
+	*f = mxb->cur_freq;
+
+	DEB_EE("VIDIOC_G_FREQ: freq:0x%08x\n", mxb->cur_freq.frequency);
+	return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct mxb *mxb = (struct mxb *)dev->ext_priv;
+	struct saa7146_vv *vv = dev->vv_data;
+
+	if (f->tuner)
+		return -EINVAL;
+
+	if (V4L2_TUNER_ANALOG_TV != f->type)
+		return -EINVAL;
+
+	DEB_EE("VIDIOC_S_FREQUENCY: freq:0x%08x\n", mxb->cur_freq.frequency);
+
+	/* tune in desired frequency */
+	tuner_call(mxb, tuner, s_frequency, f);
+	/* let the tuner subdev clamp the frequency to the tuner range */
+	tuner_call(mxb, tuner, g_frequency, f);
+	mxb->cur_freq = *f;
+	if (mxb->cur_audinput == 0)
+		mxb_update_audmode(mxb);
+
+	if (mxb->cur_input)
+		return 0;
+
+	/* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
+	spin_lock(&dev->slock);
+	vv->vbi_fieldcount = 0;
+	spin_unlock(&dev->slock);
+
+	return 0;
+}
+
+static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+	if (a->index >= MXB_AUDIOS)
+		return -EINVAL;
+	*a = mxb_audios[a->index];
+	return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct mxb *mxb = (struct mxb *)dev->ext_priv;
+
+	DEB_EE("VIDIOC_G_AUDIO\n");
+	*a = mxb_audios[mxb->cur_audinput];
+	return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct mxb *mxb = (struct mxb *)dev->ext_priv;
+
+	DEB_D("VIDIOC_S_AUDIO %d\n", a->index);
+	if (mxb_inputs[mxb->cur_input].audioset & (1 << a->index)) {
+		if (mxb->cur_audinput != a->index) {
+			mxb->cur_audinput = a->index;
+			tea6420_route(mxb, a->index);
+			if (mxb->cur_audinput == 0)
+				mxb_update_audmode(mxb);
+		}
+		return 0;
+	}
+	return -EINVAL;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (v4l2_chip_match_host(&reg->match)) {
+		reg->val = saa7146_read(dev, reg->reg);
+		reg->size = 4;
+		return 0;
+	}
+	call_all(dev, core, g_register, reg);
+	return 0;
+}
+
+static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (v4l2_chip_match_host(&reg->match)) {
+		saa7146_write(dev, reg->reg, reg->val);
+		reg->size = 4;
+		return 0;
+	}
+	return call_all(dev, core, s_register, reg);
+}
+#endif
+
+static struct saa7146_ext_vv vv_data;
+
+/* this function only gets called when the probing was successful */
+static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
+{
+	struct mxb *mxb;
+
+	DEB_EE("dev:%p\n", dev);
+
+	saa7146_vv_init(dev, &vv_data);
+	if (mxb_probe(dev)) {
+		saa7146_vv_release(dev);
+		return -1;
+	}
+	mxb = (struct mxb *)dev->ext_priv;
+
+	vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
+	vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
+	vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
+	vv_data.vid_ops.vidioc_querystd = vidioc_querystd;
+	vv_data.vid_ops.vidioc_g_tuner = vidioc_g_tuner;
+	vv_data.vid_ops.vidioc_s_tuner = vidioc_s_tuner;
+	vv_data.vid_ops.vidioc_g_frequency = vidioc_g_frequency;
+	vv_data.vid_ops.vidioc_s_frequency = vidioc_s_frequency;
+	vv_data.vid_ops.vidioc_enumaudio = vidioc_enumaudio;
+	vv_data.vid_ops.vidioc_g_audio = vidioc_g_audio;
+	vv_data.vid_ops.vidioc_s_audio = vidioc_s_audio;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	vv_data.vid_ops.vidioc_g_register = vidioc_g_register;
+	vv_data.vid_ops.vidioc_s_register = vidioc_s_register;
+#endif
+	if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
+		ERR("cannot register capture v4l2 device. skipping.\n");
+		saa7146_vv_release(dev);
+		return -1;
+	}
+
+	/* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
+	if (MXB_BOARD_CAN_DO_VBI(dev)) {
+		if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
+			ERR("cannot register vbi v4l2 device. skipping.\n");
+		}
+	}
+
+	pr_info("found Multimedia eXtension Board #%d\n", mxb_num);
+
+	mxb_num++;
+	mxb_init_done(dev);
+	return 0;
+}
+
+static int mxb_detach(struct saa7146_dev *dev)
+{
+	struct mxb *mxb = (struct mxb *)dev->ext_priv;
+
+	DEB_EE("dev:%p\n", dev);
+
+	/* mute audio on tea6420s */
+	tea6420_route(mxb, 6);
+
+	saa7146_unregister_device(&mxb->video_dev,dev);
+	if (MXB_BOARD_CAN_DO_VBI(dev))
+		saa7146_unregister_device(&mxb->vbi_dev, dev);
+	saa7146_vv_release(dev);
+
+	mxb_num--;
+
+	i2c_del_adapter(&mxb->i2c_adapter);
+	kfree(mxb);
+
+	return 0;
+}
+
+static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard)
+{
+	struct mxb *mxb = (struct mxb *)dev->ext_priv;
+
+	if (V4L2_STD_PAL_I == standard->id) {
+		v4l2_std_id std = V4L2_STD_PAL_I;
+
+		DEB_D("VIDIOC_S_STD: setting mxb for PAL_I\n");
+		/* These two gpio calls set the GPIO pins that control the tda9820 */
+		saa7146_write(dev, GPIO_CTRL, 0x00404050);
+		saa7111a_call(mxb, core, s_gpio, 0);
+		saa7111a_call(mxb, core, s_std, std);
+		if (mxb->cur_input == 0)
+			tuner_call(mxb, core, s_std, std);
+	} else {
+		v4l2_std_id std = V4L2_STD_PAL_BG;
+
+		if (mxb->cur_input)
+			std = standard->id;
+		DEB_D("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM\n");
+		/* These two gpio calls set the GPIO pins that control the tda9820 */
+		saa7146_write(dev, GPIO_CTRL, 0x00404050);
+		saa7111a_call(mxb, core, s_gpio, 1);
+		saa7111a_call(mxb, core, s_std, std);
+		if (mxb->cur_input == 0)
+			tuner_call(mxb, core, s_std, std);
+	}
+	return 0;
+}
+
+static struct saa7146_standard standard[] = {
+	{
+		.name	= "PAL-BG", 	.id	= V4L2_STD_PAL_BG,
+		.v_offset	= 0x17,	.v_field 	= 288,
+		.h_offset	= 0x14,	.h_pixels 	= 680,
+		.v_max_out	= 576,	.h_max_out	= 768,
+	}, {
+		.name	= "PAL-I", 	.id	= V4L2_STD_PAL_I,
+		.v_offset	= 0x17,	.v_field 	= 288,
+		.h_offset	= 0x14,	.h_pixels 	= 680,
+		.v_max_out	= 576,	.h_max_out	= 768,
+	}, {
+		.name	= "NTSC", 	.id	= V4L2_STD_NTSC,
+		.v_offset	= 0x16,	.v_field 	= 240,
+		.h_offset	= 0x06,	.h_pixels 	= 708,
+		.v_max_out	= 480,	.h_max_out	= 640,
+	}, {
+		.name	= "SECAM", 	.id	= V4L2_STD_SECAM,
+		.v_offset	= 0x14,	.v_field 	= 288,
+		.h_offset	= 0x14,	.h_pixels 	= 720,
+		.v_max_out	= 576,	.h_max_out	= 768,
+	}
+};
+
+static struct saa7146_pci_extension_data mxb = {
+	.ext_priv = "Multimedia eXtension Board",
+	.ext = &extension,
+};
+
+static struct pci_device_id pci_tbl[] = {
+	{
+		.vendor    = PCI_VENDOR_ID_PHILIPS,
+		.device	   = PCI_DEVICE_ID_PHILIPS_SAA7146,
+		.subvendor = 0x0000,
+		.subdevice = 0x0000,
+		.driver_data = (unsigned long)&mxb,
+	}, {
+		.vendor	= 0,
+	}
+};
+
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+static struct saa7146_ext_vv vv_data = {
+	.inputs		= MXB_INPUTS,
+	.capabilities	= V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_AUDIO,
+	.stds		= &standard[0],
+	.num_stds	= sizeof(standard)/sizeof(struct saa7146_standard),
+	.std_callback	= &std_callback,
+};
+
+static struct saa7146_extension extension = {
+	.name		= "Multimedia eXtension Board",
+	.flags		= SAA7146_USE_I2C_IRQ,
+
+	.pci_tbl	= &pci_tbl[0],
+	.module		= THIS_MODULE,
+
+	.attach		= mxb_attach,
+	.detach		= mxb_detach,
+
+	.irq_mask	= 0,
+	.irq_func	= NULL,
+};
+
+static int __init mxb_init_module(void)
+{
+	if (saa7146_register_extension(&extension)) {
+		DEB_S("failed to register extension\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void __exit mxb_cleanup_module(void)
+{
+	saa7146_unregister_extension(&extension);
+}
+
+module_init(mxb_init_module);
+module_exit(mxb_cleanup_module);
+
+MODULE_DESCRIPTION("video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board'");
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/saa7164/Kconfig b/drivers/media/pci/saa7164/Kconfig
new file mode 100644
index 0000000..3532637
--- /dev/null
+++ b/drivers/media/pci/saa7164/Kconfig
@@ -0,0 +1,18 @@
+config VIDEO_SAA7164
+	tristate "NXP SAA7164 support"
+	depends on DVB_CORE && PCI && I2C
+	select I2C_ALGOBIT
+	select FW_LOADER
+	select VIDEO_TUNER
+	select VIDEO_TVEEPROM
+	select VIDEOBUF_DVB
+	select DVB_TDA10048 if !DVB_FE_CUSTOMISE
+	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+	---help---
+	  This is a video4linux driver for NXP SAA7164 based
+	  TV cards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7164
+
diff --git a/drivers/media/pci/saa7164/Makefile b/drivers/media/pci/saa7164/Makefile
new file mode 100644
index 0000000..ba0e33a
--- /dev/null
+++ b/drivers/media/pci/saa7164/Makefile
@@ -0,0 +1,12 @@
+saa7164-objs	:= saa7164-cards.o saa7164-core.o saa7164-i2c.o saa7164-dvb.o \
+			saa7164-fw.o saa7164-bus.o saa7164-cmd.o saa7164-api.o \
+			saa7164-buffer.o saa7164-encoder.o saa7164-vbi.o
+
+obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o
+
+ccflags-y += -I$(srctree)/drivers/media/i2c
+ccflags-y += -I$(srctree)/drivers/media/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
+
+ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/pci/saa7164/saa7164-api.c b/drivers/media/pci/saa7164/saa7164-api.c
new file mode 100644
index 0000000..eff7135
--- /dev/null
+++ b/drivers/media/pci/saa7164/saa7164-api.c
@@ -0,0 +1,1524 @@
+/*
+ *  Driver for the NXP SAA7164 PCIe bridge
+ *
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/wait.h>
+#include <linux/slab.h>
+
+#include "saa7164.h"
+
+int saa7164_api_get_load_info(struct saa7164_dev *dev, struct tmFwInfoStruct *i)
+{
+	int ret;
+
+	if (!(saa_debug & DBGLVL_CPU))
+		return 0;
+
+	dprintk(DBGLVL_API, "%s()\n", __func__);
+
+	i->deviceinst = 0;
+	i->devicespec = 0;
+	i->mode = 0;
+	i->status = 0;
+
+	ret = saa7164_cmd_send(dev, 0, GET_CUR,
+		GET_FW_STATUS_CONTROL, sizeof(struct tmFwInfoStruct), i);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	printk(KERN_INFO "saa7164[%d]-CPU: %d percent", dev->nr, i->CPULoad);
+
+	return ret;
+}
+
+int saa7164_api_collect_debug(struct saa7164_dev *dev)
+{
+	struct tmComResDebugGetData d;
+	u8 more = 255;
+	int ret;
+
+	dprintk(DBGLVL_API, "%s()\n", __func__);
+
+	while (more--) {
+
+		memset(&d, 0, sizeof(d));
+
+		ret = saa7164_cmd_send(dev, 0, GET_CUR,
+			GET_DEBUG_DATA_CONTROL, sizeof(d), &d);
+		if (ret != SAA_OK)
+			printk(KERN_ERR "%s() error, ret = 0x%x\n",
+				__func__, ret);
+
+		if (d.dwResult != SAA_OK)
+			break;
+
+		printk(KERN_INFO "saa7164[%d]-FWMSG: %s", dev->nr,
+			d.ucDebugData);
+	}
+
+	return 0;
+}
+
+int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level)
+{
+	struct tmComResDebugSetLevel lvl;
+	int ret;
+
+	dprintk(DBGLVL_API, "%s(level=%d)\n", __func__, level);
+
+	/* Retrieve current state */
+	ret = saa7164_cmd_send(dev, 0, GET_CUR,
+		SET_DEBUG_LEVEL_CONTROL, sizeof(lvl), &lvl);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	dprintk(DBGLVL_API, "%s() Was %d\n", __func__, lvl.dwDebugLevel);
+
+	lvl.dwDebugLevel = level;
+
+	/* set new state */
+	ret = saa7164_cmd_send(dev, 0, SET_CUR,
+		SET_DEBUG_LEVEL_CONTROL, sizeof(lvl), &lvl);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	return ret;
+}
+
+int saa7164_api_set_vbi_format(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	struct tmComResProbeCommit fmt, rsp;
+	int ret;
+
+	dprintk(DBGLVL_API, "%s(nr=%d, unitid=0x%x)\n", __func__,
+		port->nr, port->hwcfg.unitid);
+
+	fmt.bmHint = 0;
+	fmt.bFormatIndex = 1;
+	fmt.bFrameIndex = 1;
+
+	/* Probe, see if it can support this format */
+	ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
+		SET_CUR, SAA_PROBE_CONTROL, sizeof(fmt), &fmt);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() set error, ret = 0x%x\n", __func__, ret);
+
+	/* See of the format change was successful */
+	ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
+		GET_CUR, SAA_PROBE_CONTROL, sizeof(rsp), &rsp);
+	if (ret != SAA_OK) {
+		printk(KERN_ERR "%s() get error, ret = 0x%x\n", __func__, ret);
+	} else {
+		/* Compare requested vs received, should be same */
+		if (memcmp(&fmt, &rsp, sizeof(rsp)) == 0) {
+			dprintk(DBGLVL_API, "SET/PROBE Verified\n");
+
+			/* Ask the device to select the negotiated format */
+			ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
+				SET_CUR, SAA_COMMIT_CONTROL, sizeof(fmt), &fmt);
+			if (ret != SAA_OK)
+				printk(KERN_ERR "%s() commit error, ret = 0x%x\n",
+					__func__, ret);
+
+			ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
+				GET_CUR, SAA_COMMIT_CONTROL, sizeof(rsp), &rsp);
+			if (ret != SAA_OK)
+				printk(KERN_ERR "%s() GET commit error, ret = 0x%x\n",
+					__func__, ret);
+
+			if (memcmp(&fmt, &rsp, sizeof(rsp)) != 0) {
+				printk(KERN_ERR "%s() memcmp error, ret = 0x%x\n",
+					__func__, ret);
+			} else
+				dprintk(DBGLVL_API, "SET/COMMIT Verified\n");
+
+			dprintk(DBGLVL_API, "rsp.bmHint = 0x%x\n", rsp.bmHint);
+			dprintk(DBGLVL_API, "rsp.bFormatIndex = 0x%x\n",
+				rsp.bFormatIndex);
+			dprintk(DBGLVL_API, "rsp.bFrameIndex = 0x%x\n",
+				rsp.bFrameIndex);
+		} else
+			printk(KERN_ERR "%s() compare failed\n", __func__);
+	}
+
+	if (ret == SAA_OK)
+		dprintk(DBGLVL_API, "%s(nr=%d) Success\n", __func__, port->nr);
+
+	return ret;
+}
+
+int saa7164_api_set_gop_size(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	struct tmComResEncVideoGopStructure gs;
+	int ret;
+
+	dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+	gs.ucRefFrameDist = port->encoder_params.refdist;
+	gs.ucGOPSize = port->encoder_params.gop_size;
+	ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+		EU_VIDEO_GOP_STRUCTURE_CONTROL,
+		sizeof(gs), &gs);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	return ret;
+}
+
+int saa7164_api_set_encoder(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	struct tmComResEncVideoBitRate vb;
+	struct tmComResEncAudioBitRate ab;
+	int ret;
+
+	dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n", __func__,
+		port->hwcfg.sourceid);
+
+	if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS)
+		port->encoder_profile = EU_PROFILE_PS_DVD;
+	else
+		port->encoder_profile = EU_PROFILE_TS_HQ;
+
+	ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+		EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	/* Resolution */
+	ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+		EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	/* Establish video bitrates */
+	if (port->encoder_params.bitrate_mode ==
+		V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+		vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_CONSTANT;
+	else
+		vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_VARIABLE_PEAK;
+	vb.dwVideoBitRate = port->encoder_params.bitrate;
+	vb.dwVideoBitRatePeak = port->encoder_params.bitrate_peak;
+	ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+		EU_VIDEO_BIT_RATE_CONTROL,
+		sizeof(struct tmComResEncVideoBitRate),
+		&vb);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	/* Establish audio bitrates */
+	ab.ucAudioBitRateMode = 0;
+	ab.dwAudioBitRate = 384000;
+	ab.dwAudioBitRatePeak = ab.dwAudioBitRate;
+	ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+		EU_AUDIO_BIT_RATE_CONTROL,
+		sizeof(struct tmComResEncAudioBitRate),
+		&ab);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
+			ret);
+
+	saa7164_api_set_aspect_ratio(port);
+	saa7164_api_set_gop_size(port);
+
+	return ret;
+}
+
+int saa7164_api_get_encoder(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	struct tmComResEncVideoBitRate v;
+	struct tmComResEncAudioBitRate a;
+	struct tmComResEncVideoInputAspectRatio ar;
+	int ret;
+
+	dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n", __func__,
+		port->hwcfg.sourceid);
+
+	port->encoder_profile = 0;
+	port->video_format = 0;
+	port->video_resolution = 0;
+	port->audio_format = 0;
+
+	ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+		EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+		EU_VIDEO_RESOLUTION_CONTROL, sizeof(u8),
+		&port->video_resolution);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+		EU_VIDEO_FORMAT_CONTROL, sizeof(u8), &port->video_format);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+		EU_VIDEO_BIT_RATE_CONTROL, sizeof(v), &v);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+		EU_AUDIO_FORMAT_CONTROL, sizeof(u8), &port->audio_format);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+		EU_AUDIO_BIT_RATE_CONTROL, sizeof(a), &a);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	/* Aspect Ratio */
+	ar.width = 0;
+	ar.height = 0;
+	ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+		EU_VIDEO_INPUT_ASPECT_CONTROL,
+		sizeof(struct tmComResEncVideoInputAspectRatio), &ar);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	dprintk(DBGLVL_ENC, "encoder_profile = %d\n", port->encoder_profile);
+	dprintk(DBGLVL_ENC, "video_format    = %d\n", port->video_format);
+	dprintk(DBGLVL_ENC, "audio_format    = %d\n", port->audio_format);
+	dprintk(DBGLVL_ENC, "video_resolution= %d\n", port->video_resolution);
+	dprintk(DBGLVL_ENC, "v.ucVideoBitRateMode = %d\n",
+		v.ucVideoBitRateMode);
+	dprintk(DBGLVL_ENC, "v.dwVideoBitRate     = %d\n",
+		v.dwVideoBitRate);
+	dprintk(DBGLVL_ENC, "v.dwVideoBitRatePeak = %d\n",
+		v.dwVideoBitRatePeak);
+	dprintk(DBGLVL_ENC, "a.ucVideoBitRateMode = %d\n",
+		a.ucAudioBitRateMode);
+	dprintk(DBGLVL_ENC, "a.dwVideoBitRate     = %d\n",
+		a.dwAudioBitRate);
+	dprintk(DBGLVL_ENC, "a.dwVideoBitRatePeak = %d\n",
+		a.dwAudioBitRatePeak);
+	dprintk(DBGLVL_ENC, "aspect.width / height = %d:%d\n",
+		ar.width, ar.height);
+
+	return ret;
+}
+
+int saa7164_api_set_aspect_ratio(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	struct tmComResEncVideoInputAspectRatio ar;
+	int ret;
+
+	dprintk(DBGLVL_ENC, "%s(%d)\n", __func__,
+		port->encoder_params.ctl_aspect);
+
+	switch (port->encoder_params.ctl_aspect) {
+	case V4L2_MPEG_VIDEO_ASPECT_1x1:
+		ar.width = 1;
+		ar.height = 1;
+		break;
+	case V4L2_MPEG_VIDEO_ASPECT_4x3:
+		ar.width = 4;
+		ar.height = 3;
+		break;
+	case V4L2_MPEG_VIDEO_ASPECT_16x9:
+		ar.width = 16;
+		ar.height = 9;
+		break;
+	case V4L2_MPEG_VIDEO_ASPECT_221x100:
+		ar.width = 221;
+		ar.height = 100;
+		break;
+	default:
+		BUG();
+	}
+
+	dprintk(DBGLVL_ENC, "%s(%d) now %d:%d\n", __func__,
+		port->encoder_params.ctl_aspect,
+		ar.width, ar.height);
+
+	/* Aspect Ratio */
+	ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+		EU_VIDEO_INPUT_ASPECT_CONTROL,
+		sizeof(struct tmComResEncVideoInputAspectRatio), &ar);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	return ret;
+}
+
+int saa7164_api_set_usercontrol(struct saa7164_port *port, u8 ctl)
+{
+	struct saa7164_dev *dev = port->dev;
+	int ret;
+	u16 val;
+
+	if (ctl == PU_BRIGHTNESS_CONTROL)
+		val = port->ctl_brightness;
+	else
+	if (ctl == PU_CONTRAST_CONTROL)
+		val = port->ctl_contrast;
+	else
+	if (ctl == PU_HUE_CONTROL)
+		val = port->ctl_hue;
+	else
+	if (ctl == PU_SATURATION_CONTROL)
+		val = port->ctl_saturation;
+	else
+	if (ctl == PU_SHARPNESS_CONTROL)
+		val = port->ctl_sharpness;
+	else
+		return -EINVAL;
+
+	dprintk(DBGLVL_ENC, "%s() unitid=0x%x ctl=%d, val=%d\n",
+		__func__, port->encunit.vsourceid, ctl, val);
+
+	ret = saa7164_cmd_send(port->dev, port->encunit.vsourceid, SET_CUR,
+		ctl, sizeof(u16), &val);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	return ret;
+}
+
+int saa7164_api_get_usercontrol(struct saa7164_port *port, u8 ctl)
+{
+	struct saa7164_dev *dev = port->dev;
+	int ret;
+	u16 val;
+
+	ret = saa7164_cmd_send(port->dev, port->encunit.vsourceid, GET_CUR,
+		ctl, sizeof(u16), &val);
+	if (ret != SAA_OK) {
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+		return ret;
+	}
+
+	dprintk(DBGLVL_ENC, "%s() ctl=%d, val=%d\n",
+		__func__, ctl, val);
+
+	if (ctl == PU_BRIGHTNESS_CONTROL)
+		port->ctl_brightness = val;
+	else
+	if (ctl == PU_CONTRAST_CONTROL)
+		port->ctl_contrast = val;
+	else
+	if (ctl == PU_HUE_CONTROL)
+		port->ctl_hue = val;
+	else
+	if (ctl == PU_SATURATION_CONTROL)
+		port->ctl_saturation = val;
+	else
+	if (ctl == PU_SHARPNESS_CONTROL)
+		port->ctl_sharpness = val;
+
+	return ret;
+}
+
+int saa7164_api_set_videomux(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	u8 inputs[] = { 1, 2, 2, 2, 5, 5, 5 };
+	int ret;
+
+	dprintk(DBGLVL_ENC, "%s() v_mux=%d a_mux=%d\n",
+		__func__, port->mux_input, inputs[port->mux_input - 1]);
+
+	/* Audio Mute */
+	ret = saa7164_api_audio_mute(port, 1);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	/* Video Mux */
+	ret = saa7164_cmd_send(port->dev, port->vidproc.sourceid, SET_CUR,
+		SU_INPUT_SELECT_CONTROL, sizeof(u8), &port->mux_input);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	/* Audio Mux */
+	ret = saa7164_cmd_send(port->dev, port->audfeat.sourceid, SET_CUR,
+		SU_INPUT_SELECT_CONTROL, sizeof(u8),
+		&inputs[port->mux_input - 1]);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	/* Audio UnMute */
+	ret = saa7164_api_audio_mute(port, 0);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	return ret;
+}
+
+int saa7164_api_audio_mute(struct saa7164_port *port, int mute)
+{
+	struct saa7164_dev *dev = port->dev;
+	u8 v = mute;
+	int ret;
+
+	dprintk(DBGLVL_API, "%s(%d)\n", __func__, mute);
+
+	ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
+		MUTE_CONTROL, sizeof(u8), &v);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	return ret;
+}
+
+/* 0 = silence, 0xff = full */
+int saa7164_api_set_audio_volume(struct saa7164_port *port, s8 level)
+{
+	struct saa7164_dev *dev = port->dev;
+	s16 v, min, max;
+	int ret;
+
+	dprintk(DBGLVL_API, "%s(%d)\n", __func__, level);
+
+	/* Obtain the min/max ranges */
+	ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_MIN,
+		VOLUME_CONTROL, sizeof(u16), &min);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_MAX,
+		VOLUME_CONTROL, sizeof(u16), &max);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_CUR,
+		(0x01 << 8) | VOLUME_CONTROL, sizeof(u16), &v);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__,
+		level, min, max, v);
+
+	v = level;
+	if (v < min)
+		v = min;
+	if (v > max)
+		v = max;
+
+	/* Left */
+	ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
+		(0x01 << 8) | VOLUME_CONTROL, sizeof(s16), &v);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	/* Right */
+	ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
+		(0x02 << 8) | VOLUME_CONTROL, sizeof(s16), &v);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_CUR,
+		(0x01 << 8) | VOLUME_CONTROL, sizeof(u16), &v);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__,
+		level, min, max, v);
+
+	return ret;
+}
+
+int saa7164_api_set_audio_std(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	struct tmComResAudioDefaults lvl;
+	struct tmComResTunerStandard tvaudio;
+	int ret;
+
+	dprintk(DBGLVL_API, "%s()\n", __func__);
+
+	/* Establish default levels */
+	lvl.ucDecoderLevel = TMHW_LEV_ADJ_DECLEV_DEFAULT;
+	lvl.ucDecoderFM_Level = TMHW_LEV_ADJ_DECLEV_DEFAULT;
+	lvl.ucMonoLevel = TMHW_LEV_ADJ_MONOLEV_DEFAULT;
+	lvl.ucNICAM_Level = TMHW_LEV_ADJ_NICLEV_DEFAULT;
+	lvl.ucSAP_Level = TMHW_LEV_ADJ_SAPLEV_DEFAULT;
+	lvl.ucADC_Level = TMHW_LEV_ADJ_ADCLEV_DEFAULT;
+	ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
+		AUDIO_DEFAULT_CONTROL, sizeof(struct tmComResAudioDefaults),
+		&lvl);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	/* Manually select the appropriate TV audio standard */
+	if (port->encodernorm.id & V4L2_STD_NTSC) {
+		tvaudio.std = TU_STANDARD_NTSC_M;
+		tvaudio.country = 1;
+	} else {
+		tvaudio.std = TU_STANDARD_PAL_I;
+		tvaudio.country = 44;
+	}
+
+	ret = saa7164_cmd_send(port->dev, port->tunerunit.unitid, SET_CUR,
+		TU_STANDARD_CONTROL, sizeof(tvaudio), &tvaudio);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() TU_STANDARD_CONTROL error, ret = 0x%x\n",
+			__func__, ret);
+	return ret;
+}
+
+int saa7164_api_set_audio_detection(struct saa7164_port *port, int autodetect)
+{
+	struct saa7164_dev *dev = port->dev;
+	struct tmComResTunerStandardAuto p;
+	int ret;
+
+	dprintk(DBGLVL_API, "%s(%d)\n", __func__, autodetect);
+
+	/* Disable TV Audio autodetect if not already set (buggy) */
+	if (autodetect)
+		p.mode = TU_STANDARD_AUTO;
+	else
+		p.mode = TU_STANDARD_MANUAL;
+	ret = saa7164_cmd_send(port->dev, port->tunerunit.unitid, SET_CUR,
+		TU_STANDARD_AUTO_CONTROL, sizeof(p), &p);
+	if (ret != SAA_OK)
+		printk(KERN_ERR
+			"%s() TU_STANDARD_AUTO_CONTROL error, ret = 0x%x\n",
+			__func__, ret);
+
+	return ret;
+}
+
+int saa7164_api_get_videomux(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	int ret;
+
+	ret = saa7164_cmd_send(port->dev, port->vidproc.sourceid, GET_CUR,
+		SU_INPUT_SELECT_CONTROL, sizeof(u8), &port->mux_input);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	dprintk(DBGLVL_ENC, "%s() v_mux=%d\n",
+		__func__, port->mux_input);
+
+	return ret;
+}
+
+int saa7164_api_set_dif(struct saa7164_port *port, u8 reg, u8 val)
+{
+	struct saa7164_dev *dev = port->dev;
+
+	u16 len = 0;
+	u8 buf[256];
+	int ret;
+	u8 mas;
+
+	dprintk(DBGLVL_API, "%s(nr=%d type=%d val=%x)\n", __func__,
+		port->nr, port->type, val);
+
+	if (port->nr == 0)
+		mas = 0xd0;
+	else
+		mas = 0xe0;
+
+	memset(buf, 0, sizeof(buf));
+
+	buf[0x00] = 0x04;
+	buf[0x01] = 0x00;
+	buf[0x02] = 0x00;
+	buf[0x03] = 0x00;
+
+	buf[0x04] = 0x04;
+	buf[0x05] = 0x00;
+	buf[0x06] = 0x00;
+	buf[0x07] = 0x00;
+
+	buf[0x08] = reg;
+	buf[0x09] = 0x26;
+	buf[0x0a] = mas;
+	buf[0x0b] = 0xb0;
+
+	buf[0x0c] = val;
+	buf[0x0d] = 0x00;
+	buf[0x0e] = 0x00;
+	buf[0x0f] = 0x00;
+
+	ret = saa7164_cmd_send(dev, port->ifunit.unitid, GET_LEN,
+		EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len);
+	if (ret != SAA_OK) {
+		printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret);
+		return -EIO;
+	}
+
+	ret = saa7164_cmd_send(dev, port->ifunit.unitid, SET_CUR,
+		EXU_REGISTER_ACCESS_CONTROL, len, &buf);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
+#if 0
+	print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, buf, 16,
+		       false);
+#endif
+	return ret == SAA_OK ? 0 : -EIO;
+}
+
+/* Disable the IF block AGC controls */
+int saa7164_api_configure_dif(struct saa7164_port *port, u32 std)
+{
+	struct saa7164_dev *dev = port->dev;
+	int ret = 0;
+	u8 agc_disable;
+
+	dprintk(DBGLVL_API, "%s(nr=%d, 0x%x)\n", __func__, port->nr, std);
+
+	if (std & V4L2_STD_NTSC) {
+		dprintk(DBGLVL_API, " NTSC\n");
+		saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
+		agc_disable = 0;
+	} else if (std & V4L2_STD_PAL_I) {
+		dprintk(DBGLVL_API, " PAL-I\n");
+		saa7164_api_set_dif(port, 0x00, 0x08); /* Video Standard */
+		agc_disable = 0;
+	} else if (std & V4L2_STD_PAL_M) {
+		dprintk(DBGLVL_API, " PAL-M\n");
+		saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
+		agc_disable = 0;
+	} else if (std & V4L2_STD_PAL_N) {
+		dprintk(DBGLVL_API, " PAL-N\n");
+		saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
+		agc_disable = 0;
+	} else if (std & V4L2_STD_PAL_Nc) {
+		dprintk(DBGLVL_API, " PAL-Nc\n");
+		saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
+		agc_disable = 0;
+	} else if (std & V4L2_STD_PAL_B) {
+		dprintk(DBGLVL_API, " PAL-B\n");
+		saa7164_api_set_dif(port, 0x00, 0x02); /* Video Standard */
+		agc_disable = 0;
+	} else if (std & V4L2_STD_PAL_DK) {
+		dprintk(DBGLVL_API, " PAL-DK\n");
+		saa7164_api_set_dif(port, 0x00, 0x10); /* Video Standard */
+		agc_disable = 0;
+	} else if (std & V4L2_STD_SECAM_L) {
+		dprintk(DBGLVL_API, " SECAM-L\n");
+		saa7164_api_set_dif(port, 0x00, 0x20); /* Video Standard */
+		agc_disable = 0;
+	} else {
+		/* Unknown standard, assume DTV */
+		dprintk(DBGLVL_API, " Unknown (assuming DTV)\n");
+		/* Undefinded Video Standard */
+		saa7164_api_set_dif(port, 0x00, 0x80);
+		agc_disable = 1;
+	}
+
+	saa7164_api_set_dif(port, 0x48, 0xa0); /* AGC Functions 1 */
+	saa7164_api_set_dif(port, 0xc0, agc_disable); /* AGC Output Disable */
+	saa7164_api_set_dif(port, 0x7c, 0x04); /* CVBS EQ */
+	saa7164_api_set_dif(port, 0x04, 0x01); /* Active */
+	msleep(100);
+	saa7164_api_set_dif(port, 0x04, 0x00); /* Active (again) */
+	msleep(100);
+
+	return ret;
+}
+
+/* Ensure the dif is in the correct state for the operating mode
+ * (analog / dtv). We only configure the diff through the analog encoder
+ * so when we're in digital mode we need to find the appropriate encoder
+ * and use it to configure the DIF.
+ */
+int saa7164_api_initialize_dif(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	struct saa7164_port *p = NULL;
+	int ret = -EINVAL;
+	u32 std = 0;
+
+	dprintk(DBGLVL_API, "%s(nr=%d type=%d)\n", __func__,
+		port->nr, port->type);
+
+	if (port->type == SAA7164_MPEG_ENCODER) {
+		/* Pick any analog standard to init the diff.
+		 * we'll come back during encoder_init'
+		 * and set the correct standard if requried.
+		 */
+		std = V4L2_STD_NTSC;
+	} else
+	if (port->type == SAA7164_MPEG_DVB) {
+		if (port->nr == SAA7164_PORT_TS1)
+			p = &dev->ports[SAA7164_PORT_ENC1];
+		else
+			p = &dev->ports[SAA7164_PORT_ENC2];
+	} else
+	if (port->type == SAA7164_MPEG_VBI) {
+		std = V4L2_STD_NTSC;
+		if (port->nr == SAA7164_PORT_VBI1)
+			p = &dev->ports[SAA7164_PORT_ENC1];
+		else
+			p = &dev->ports[SAA7164_PORT_ENC2];
+	} else
+		BUG();
+
+	if (p)
+		ret = saa7164_api_configure_dif(p, std);
+
+	return ret;
+}
+
+int saa7164_api_transition_port(struct saa7164_port *port, u8 mode)
+{
+	struct saa7164_dev *dev = port->dev;
+
+	int ret;
+
+	dprintk(DBGLVL_API, "%s(nr=%d unitid=0x%x,%d)\n",
+		__func__, port->nr, port->hwcfg.unitid, mode);
+
+	ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, SET_CUR,
+		SAA_STATE_CONTROL, sizeof(mode), &mode);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s(portnr %d unitid 0x%x) error, ret = 0x%x\n",
+			__func__, port->nr, port->hwcfg.unitid, ret);
+
+	return ret;
+}
+
+int saa7164_api_get_fw_version(struct saa7164_dev *dev, u32 *version)
+{
+	int ret;
+
+	ret = saa7164_cmd_send(dev, 0, GET_CUR,
+		GET_FW_VERSION_CONTROL, sizeof(u32), version);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	return ret;
+}
+
+int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen)
+{
+	u8 reg[] = { 0x0f, 0x00 };
+
+	if (buflen < 128)
+		return -ENOMEM;
+
+	/* Assumption: Hauppauge eeprom is at 0xa0 on on bus 0 */
+	/* TODO: Pull the details from the boards struct */
+	return saa7164_api_i2c_read(&dev->i2c_bus[0], 0xa0 >> 1, sizeof(reg),
+		&reg[0], 128, buf);
+}
+
+int saa7164_api_configure_port_vbi(struct saa7164_dev *dev,
+	struct saa7164_port *port)
+{
+	struct tmComResVBIFormatDescrHeader *fmt = &port->vbi_fmt_ntsc;
+
+	dprintk(DBGLVL_API, "    bFormatIndex  = 0x%x\n", fmt->bFormatIndex);
+	dprintk(DBGLVL_API, "    VideoStandard = 0x%x\n", fmt->VideoStandard);
+	dprintk(DBGLVL_API, "    StartLine     = %d\n", fmt->StartLine);
+	dprintk(DBGLVL_API, "    EndLine       = %d\n", fmt->EndLine);
+	dprintk(DBGLVL_API, "    FieldRate     = %d\n", fmt->FieldRate);
+	dprintk(DBGLVL_API, "    bNumLines     = %d\n", fmt->bNumLines);
+
+	/* Cache the hardware configuration in the port */
+
+	port->bufcounter = port->hwcfg.BARLocation;
+	port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32));
+	port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32));
+	port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32));
+	port->bufptr32l = port->hwcfg.BARLocation +
+		(4 * sizeof(u32)) +
+		(sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32);
+	port->bufptr32h = port->hwcfg.BARLocation +
+		(4 * sizeof(u32)) +
+		(sizeof(u32) * port->hwcfg.buffercount);
+	port->bufptr64 = port->hwcfg.BARLocation +
+		(4 * sizeof(u32)) +
+		(sizeof(u32) * port->hwcfg.buffercount);
+	dprintk(DBGLVL_API, "   = port->hwcfg.BARLocation = 0x%x\n",
+		port->hwcfg.BARLocation);
+
+	dprintk(DBGLVL_API, "   = VS_FORMAT_VBI (becomes dev->en[%d])\n",
+		port->nr);
+
+	return 0;
+}
+
+int saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev,
+	struct saa7164_port *port,
+	struct tmComResTSFormatDescrHeader *tsfmt)
+{
+	dprintk(DBGLVL_API, "    bFormatIndex = 0x%x\n", tsfmt->bFormatIndex);
+	dprintk(DBGLVL_API, "    bDataOffset  = 0x%x\n", tsfmt->bDataOffset);
+	dprintk(DBGLVL_API, "    bPacketLength= 0x%x\n", tsfmt->bPacketLength);
+	dprintk(DBGLVL_API, "    bStrideLength= 0x%x\n", tsfmt->bStrideLength);
+	dprintk(DBGLVL_API, "    bguid        = (....)\n");
+
+	/* Cache the hardware configuration in the port */
+
+	port->bufcounter = port->hwcfg.BARLocation;
+	port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32));
+	port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32));
+	port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32));
+	port->bufptr32l = port->hwcfg.BARLocation +
+		(4 * sizeof(u32)) +
+		(sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32);
+	port->bufptr32h = port->hwcfg.BARLocation +
+		(4 * sizeof(u32)) +
+		(sizeof(u32) * port->hwcfg.buffercount);
+	port->bufptr64 = port->hwcfg.BARLocation +
+		(4 * sizeof(u32)) +
+		(sizeof(u32) * port->hwcfg.buffercount);
+	dprintk(DBGLVL_API, "   = port->hwcfg.BARLocation = 0x%x\n",
+		port->hwcfg.BARLocation);
+
+	dprintk(DBGLVL_API, "   = VS_FORMAT_MPEGTS (becomes dev->ts[%d])\n",
+		port->nr);
+
+	return 0;
+}
+
+int saa7164_api_configure_port_mpeg2ps(struct saa7164_dev *dev,
+	struct saa7164_port *port,
+	struct tmComResPSFormatDescrHeader *fmt)
+{
+	dprintk(DBGLVL_API, "    bFormatIndex = 0x%x\n", fmt->bFormatIndex);
+	dprintk(DBGLVL_API, "    wPacketLength= 0x%x\n", fmt->wPacketLength);
+	dprintk(DBGLVL_API, "    wPackLength=   0x%x\n", fmt->wPackLength);
+	dprintk(DBGLVL_API, "    bPackDataType= 0x%x\n", fmt->bPackDataType);
+
+	/* Cache the hardware configuration in the port */
+	/* TODO: CHECK THIS in the port config */
+	port->bufcounter = port->hwcfg.BARLocation;
+	port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32));
+	port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32));
+	port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32));
+	port->bufptr32l = port->hwcfg.BARLocation +
+		(4 * sizeof(u32)) +
+		(sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32);
+	port->bufptr32h = port->hwcfg.BARLocation +
+		(4 * sizeof(u32)) +
+		(sizeof(u32) * port->hwcfg.buffercount);
+	port->bufptr64 = port->hwcfg.BARLocation +
+		(4 * sizeof(u32)) +
+		(sizeof(u32) * port->hwcfg.buffercount);
+	dprintk(DBGLVL_API, "   = port->hwcfg.BARLocation = 0x%x\n",
+		port->hwcfg.BARLocation);
+
+	dprintk(DBGLVL_API, "   = VS_FORMAT_MPEGPS (becomes dev->enc[%d])\n",
+		port->nr);
+
+	return 0;
+}
+
+int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
+{
+	struct saa7164_port *tsport = NULL;
+	struct saa7164_port *encport = NULL;
+	struct saa7164_port *vbiport = NULL;
+	u32 idx, next_offset;
+	int i;
+	struct tmComResDescrHeader *hdr, *t;
+	struct tmComResExtDevDescrHeader *exthdr;
+	struct tmComResPathDescrHeader *pathhdr;
+	struct tmComResAntTermDescrHeader *anttermhdr;
+	struct tmComResTunerDescrHeader *tunerunithdr;
+	struct tmComResDMATermDescrHeader *vcoutputtermhdr;
+	struct tmComResTSFormatDescrHeader *tsfmt;
+	struct tmComResPSFormatDescrHeader *psfmt;
+	struct tmComResSelDescrHeader *psel;
+	struct tmComResProcDescrHeader *pdh;
+	struct tmComResAFeatureDescrHeader *afd;
+	struct tmComResEncoderDescrHeader *edh;
+	struct tmComResVBIFormatDescrHeader *vbifmt;
+	u32 currpath = 0;
+
+	dprintk(DBGLVL_API,
+		"%s(?,?,%d) sizeof(struct tmComResDescrHeader) = %d bytes\n",
+		__func__, len, (u32)sizeof(struct tmComResDescrHeader));
+
+	for (idx = 0; idx < (len - sizeof(struct tmComResDescrHeader));) {
+
+		hdr = (struct tmComResDescrHeader *)(buf + idx);
+
+		if (hdr->type != CS_INTERFACE)
+			return SAA_ERR_NOT_SUPPORTED;
+
+		dprintk(DBGLVL_API, "@ 0x%x =\n", idx);
+		switch (hdr->subtype) {
+		case GENERAL_REQUEST:
+			dprintk(DBGLVL_API, " GENERAL_REQUEST\n");
+			break;
+		case VC_TUNER_PATH:
+			dprintk(DBGLVL_API, " VC_TUNER_PATH\n");
+			pathhdr = (struct tmComResPathDescrHeader *)(buf + idx);
+			dprintk(DBGLVL_API, "  pathid = 0x%x\n",
+				pathhdr->pathid);
+			currpath = pathhdr->pathid;
+			break;
+		case VC_INPUT_TERMINAL:
+			dprintk(DBGLVL_API, " VC_INPUT_TERMINAL\n");
+			anttermhdr =
+				(struct tmComResAntTermDescrHeader *)(buf + idx);
+			dprintk(DBGLVL_API, "  terminalid   = 0x%x\n",
+				anttermhdr->terminalid);
+			dprintk(DBGLVL_API, "  terminaltype = 0x%x\n",
+				anttermhdr->terminaltype);
+			switch (anttermhdr->terminaltype) {
+			case ITT_ANTENNA:
+				dprintk(DBGLVL_API, "   = ITT_ANTENNA\n");
+				break;
+			case LINE_CONNECTOR:
+				dprintk(DBGLVL_API, "   = LINE_CONNECTOR\n");
+				break;
+			case SPDIF_CONNECTOR:
+				dprintk(DBGLVL_API, "   = SPDIF_CONNECTOR\n");
+				break;
+			case COMPOSITE_CONNECTOR:
+				dprintk(DBGLVL_API,
+					"   = COMPOSITE_CONNECTOR\n");
+				break;
+			case SVIDEO_CONNECTOR:
+				dprintk(DBGLVL_API, "   = SVIDEO_CONNECTOR\n");
+				break;
+			case COMPONENT_CONNECTOR:
+				dprintk(DBGLVL_API,
+					"   = COMPONENT_CONNECTOR\n");
+				break;
+			case STANDARD_DMA:
+				dprintk(DBGLVL_API, "   = STANDARD_DMA\n");
+				break;
+			default:
+				dprintk(DBGLVL_API, "   = undefined (0x%x)\n",
+					anttermhdr->terminaltype);
+			}
+			dprintk(DBGLVL_API, "  assocterminal= 0x%x\n",
+				anttermhdr->assocterminal);
+			dprintk(DBGLVL_API, "  iterminal    = 0x%x\n",
+				anttermhdr->iterminal);
+			dprintk(DBGLVL_API, "  controlsize  = 0x%x\n",
+				anttermhdr->controlsize);
+			break;
+		case VC_OUTPUT_TERMINAL:
+			dprintk(DBGLVL_API, " VC_OUTPUT_TERMINAL\n");
+			vcoutputtermhdr =
+				(struct tmComResDMATermDescrHeader *)(buf + idx);
+			dprintk(DBGLVL_API, "  unitid = 0x%x\n",
+				vcoutputtermhdr->unitid);
+			dprintk(DBGLVL_API, "  terminaltype = 0x%x\n",
+				vcoutputtermhdr->terminaltype);
+			switch (vcoutputtermhdr->terminaltype) {
+			case ITT_ANTENNA:
+				dprintk(DBGLVL_API, "   = ITT_ANTENNA\n");
+				break;
+			case LINE_CONNECTOR:
+				dprintk(DBGLVL_API, "   = LINE_CONNECTOR\n");
+				break;
+			case SPDIF_CONNECTOR:
+				dprintk(DBGLVL_API, "   = SPDIF_CONNECTOR\n");
+				break;
+			case COMPOSITE_CONNECTOR:
+				dprintk(DBGLVL_API,
+					"   = COMPOSITE_CONNECTOR\n");
+				break;
+			case SVIDEO_CONNECTOR:
+				dprintk(DBGLVL_API, "   = SVIDEO_CONNECTOR\n");
+				break;
+			case COMPONENT_CONNECTOR:
+				dprintk(DBGLVL_API,
+					"   = COMPONENT_CONNECTOR\n");
+				break;
+			case STANDARD_DMA:
+				dprintk(DBGLVL_API, "   = STANDARD_DMA\n");
+				break;
+			default:
+				dprintk(DBGLVL_API, "   = undefined (0x%x)\n",
+					vcoutputtermhdr->terminaltype);
+			}
+			dprintk(DBGLVL_API, "  assocterminal= 0x%x\n",
+				vcoutputtermhdr->assocterminal);
+			dprintk(DBGLVL_API, "  sourceid     = 0x%x\n",
+				vcoutputtermhdr->sourceid);
+			dprintk(DBGLVL_API, "  iterminal    = 0x%x\n",
+				vcoutputtermhdr->iterminal);
+			dprintk(DBGLVL_API, "  BARLocation  = 0x%x\n",
+				vcoutputtermhdr->BARLocation);
+			dprintk(DBGLVL_API, "  flags        = 0x%x\n",
+				vcoutputtermhdr->flags);
+			dprintk(DBGLVL_API, "  interruptid  = 0x%x\n",
+				vcoutputtermhdr->interruptid);
+			dprintk(DBGLVL_API, "  buffercount  = 0x%x\n",
+				vcoutputtermhdr->buffercount);
+			dprintk(DBGLVL_API, "  metadatasize = 0x%x\n",
+				vcoutputtermhdr->metadatasize);
+			dprintk(DBGLVL_API, "  controlsize  = 0x%x\n",
+				vcoutputtermhdr->controlsize);
+			dprintk(DBGLVL_API, "  numformats   = 0x%x\n",
+				vcoutputtermhdr->numformats);
+
+			t = (struct tmComResDescrHeader *)
+				((struct tmComResDMATermDescrHeader *)(buf + idx));
+			next_offset = idx + (vcoutputtermhdr->len);
+			for (i = 0; i < vcoutputtermhdr->numformats; i++) {
+				t = (struct tmComResDescrHeader *)
+					(buf + next_offset);
+				switch (t->subtype) {
+				case VS_FORMAT_MPEG2TS:
+					tsfmt =
+					(struct tmComResTSFormatDescrHeader *)t;
+					if (currpath == 1)
+						tsport = &dev->ports[SAA7164_PORT_TS1];
+					else
+						tsport = &dev->ports[SAA7164_PORT_TS2];
+					memcpy(&tsport->hwcfg, vcoutputtermhdr,
+						sizeof(*vcoutputtermhdr));
+					saa7164_api_configure_port_mpeg2ts(dev,
+						tsport, tsfmt);
+					break;
+				case VS_FORMAT_MPEG2PS:
+					psfmt =
+					(struct tmComResPSFormatDescrHeader *)t;
+					if (currpath == 1)
+						encport = &dev->ports[SAA7164_PORT_ENC1];
+					else
+						encport = &dev->ports[SAA7164_PORT_ENC2];
+					memcpy(&encport->hwcfg, vcoutputtermhdr,
+						sizeof(*vcoutputtermhdr));
+					saa7164_api_configure_port_mpeg2ps(dev,
+						encport, psfmt);
+					break;
+				case VS_FORMAT_VBI:
+					vbifmt =
+					(struct tmComResVBIFormatDescrHeader *)t;
+					if (currpath == 1)
+						vbiport = &dev->ports[SAA7164_PORT_VBI1];
+					else
+						vbiport = &dev->ports[SAA7164_PORT_VBI2];
+					memcpy(&vbiport->hwcfg, vcoutputtermhdr,
+						sizeof(*vcoutputtermhdr));
+					memcpy(&vbiport->vbi_fmt_ntsc, vbifmt,
+						sizeof(*vbifmt));
+					saa7164_api_configure_port_vbi(dev,
+						vbiport);
+					break;
+				case VS_FORMAT_RDS:
+					dprintk(DBGLVL_API,
+						"   = VS_FORMAT_RDS\n");
+					break;
+				case VS_FORMAT_UNCOMPRESSED:
+					dprintk(DBGLVL_API,
+					"   = VS_FORMAT_UNCOMPRESSED\n");
+					break;
+				case VS_FORMAT_TYPE:
+					dprintk(DBGLVL_API,
+						"   = VS_FORMAT_TYPE\n");
+					break;
+				default:
+					dprintk(DBGLVL_API,
+						"   = undefined (0x%x)\n",
+						t->subtype);
+				}
+				next_offset += t->len;
+			}
+
+			break;
+		case TUNER_UNIT:
+			dprintk(DBGLVL_API, " TUNER_UNIT\n");
+			tunerunithdr =
+				(struct tmComResTunerDescrHeader *)(buf + idx);
+			dprintk(DBGLVL_API, "  unitid = 0x%x\n",
+				tunerunithdr->unitid);
+			dprintk(DBGLVL_API, "  sourceid = 0x%x\n",
+				tunerunithdr->sourceid);
+			dprintk(DBGLVL_API, "  iunit = 0x%x\n",
+				tunerunithdr->iunit);
+			dprintk(DBGLVL_API, "  tuningstandards = 0x%x\n",
+				tunerunithdr->tuningstandards);
+			dprintk(DBGLVL_API, "  controlsize = 0x%x\n",
+				tunerunithdr->controlsize);
+			dprintk(DBGLVL_API, "  controls = 0x%x\n",
+				tunerunithdr->controls);
+
+			if (tunerunithdr->unitid == tunerunithdr->iunit) {
+				if (currpath == 1)
+					encport = &dev->ports[SAA7164_PORT_ENC1];
+				else
+					encport = &dev->ports[SAA7164_PORT_ENC2];
+				memcpy(&encport->tunerunit, tunerunithdr,
+					sizeof(struct tmComResTunerDescrHeader));
+				dprintk(DBGLVL_API,
+					"  (becomes dev->enc[%d] tuner)\n",
+					encport->nr);
+			}
+			break;
+		case VC_SELECTOR_UNIT:
+			psel = (struct tmComResSelDescrHeader *)(buf + idx);
+			dprintk(DBGLVL_API, " VC_SELECTOR_UNIT\n");
+			dprintk(DBGLVL_API, "  unitid = 0x%x\n",
+				psel->unitid);
+			dprintk(DBGLVL_API, "  nrinpins = 0x%x\n",
+				psel->nrinpins);
+			dprintk(DBGLVL_API, "  sourceid = 0x%x\n",
+				psel->sourceid);
+			break;
+		case VC_PROCESSING_UNIT:
+			pdh = (struct tmComResProcDescrHeader *)(buf + idx);
+			dprintk(DBGLVL_API, " VC_PROCESSING_UNIT\n");
+			dprintk(DBGLVL_API, "  unitid = 0x%x\n",
+				pdh->unitid);
+			dprintk(DBGLVL_API, "  sourceid = 0x%x\n",
+				pdh->sourceid);
+			dprintk(DBGLVL_API, "  controlsize = 0x%x\n",
+				pdh->controlsize);
+			if (pdh->controlsize == 0x04) {
+				if (currpath == 1)
+					encport = &dev->ports[SAA7164_PORT_ENC1];
+				else
+					encport = &dev->ports[SAA7164_PORT_ENC2];
+				memcpy(&encport->vidproc, pdh,
+					sizeof(struct tmComResProcDescrHeader));
+				dprintk(DBGLVL_API, "  (becomes dev->enc[%d])\n",
+					encport->nr);
+			}
+			break;
+		case FEATURE_UNIT:
+			afd = (struct tmComResAFeatureDescrHeader *)(buf + idx);
+			dprintk(DBGLVL_API, " FEATURE_UNIT\n");
+			dprintk(DBGLVL_API, "  unitid = 0x%x\n",
+				afd->unitid);
+			dprintk(DBGLVL_API, "  sourceid = 0x%x\n",
+				afd->sourceid);
+			dprintk(DBGLVL_API, "  controlsize = 0x%x\n",
+				afd->controlsize);
+			if (currpath == 1)
+				encport = &dev->ports[SAA7164_PORT_ENC1];
+			else
+				encport = &dev->ports[SAA7164_PORT_ENC2];
+			memcpy(&encport->audfeat, afd,
+				sizeof(struct tmComResAFeatureDescrHeader));
+			dprintk(DBGLVL_API, "  (becomes dev->enc[%d])\n",
+				encport->nr);
+			break;
+		case ENCODER_UNIT:
+			edh = (struct tmComResEncoderDescrHeader *)(buf + idx);
+			dprintk(DBGLVL_API, " ENCODER_UNIT\n");
+			dprintk(DBGLVL_API, "  subtype = 0x%x\n", edh->subtype);
+			dprintk(DBGLVL_API, "  unitid = 0x%x\n", edh->unitid);
+			dprintk(DBGLVL_API, "  vsourceid = 0x%x\n",
+			edh->vsourceid);
+			dprintk(DBGLVL_API, "  asourceid = 0x%x\n",
+				edh->asourceid);
+			dprintk(DBGLVL_API, "  iunit = 0x%x\n", edh->iunit);
+			if (edh->iunit == edh->unitid) {
+				if (currpath == 1)
+					encport = &dev->ports[SAA7164_PORT_ENC1];
+				else
+					encport = &dev->ports[SAA7164_PORT_ENC2];
+				memcpy(&encport->encunit, edh,
+					sizeof(struct tmComResEncoderDescrHeader));
+				dprintk(DBGLVL_API,
+					"  (becomes dev->enc[%d])\n",
+					encport->nr);
+			}
+			break;
+		case EXTENSION_UNIT:
+			dprintk(DBGLVL_API, " EXTENSION_UNIT\n");
+			exthdr = (struct tmComResExtDevDescrHeader *)(buf + idx);
+			dprintk(DBGLVL_API, "  unitid = 0x%x\n",
+				exthdr->unitid);
+			dprintk(DBGLVL_API, "  deviceid = 0x%x\n",
+				exthdr->deviceid);
+			dprintk(DBGLVL_API, "  devicetype = 0x%x\n",
+				exthdr->devicetype);
+			if (exthdr->devicetype & 0x1)
+				dprintk(DBGLVL_API, "   = Decoder Device\n");
+			if (exthdr->devicetype & 0x2)
+				dprintk(DBGLVL_API, "   = GPIO Source\n");
+			if (exthdr->devicetype & 0x4)
+				dprintk(DBGLVL_API, "   = Video Decoder\n");
+			if (exthdr->devicetype & 0x8)
+				dprintk(DBGLVL_API, "   = Audio Decoder\n");
+			if (exthdr->devicetype & 0x20)
+				dprintk(DBGLVL_API, "   = Crossbar\n");
+			if (exthdr->devicetype & 0x40)
+				dprintk(DBGLVL_API, "   = Tuner\n");
+			if (exthdr->devicetype & 0x80)
+				dprintk(DBGLVL_API, "   = IF PLL\n");
+			if (exthdr->devicetype & 0x100)
+				dprintk(DBGLVL_API, "   = Demodulator\n");
+			if (exthdr->devicetype & 0x200)
+				dprintk(DBGLVL_API, "   = RDS Decoder\n");
+			if (exthdr->devicetype & 0x400)
+				dprintk(DBGLVL_API, "   = Encoder\n");
+			if (exthdr->devicetype & 0x800)
+				dprintk(DBGLVL_API, "   = IR Decoder\n");
+			if (exthdr->devicetype & 0x1000)
+				dprintk(DBGLVL_API, "   = EEPROM\n");
+			if (exthdr->devicetype & 0x2000)
+				dprintk(DBGLVL_API,
+					"   = VBI Decoder\n");
+			if (exthdr->devicetype & 0x10000)
+				dprintk(DBGLVL_API,
+					"   = Streaming Device\n");
+			if (exthdr->devicetype & 0x20000)
+				dprintk(DBGLVL_API,
+					"   = DRM Device\n");
+			if (exthdr->devicetype & 0x40000000)
+				dprintk(DBGLVL_API,
+					"   = Generic Device\n");
+			if (exthdr->devicetype & 0x80000000)
+				dprintk(DBGLVL_API,
+					"   = Config Space Device\n");
+			dprintk(DBGLVL_API, "  numgpiopins = 0x%x\n",
+				exthdr->numgpiopins);
+			dprintk(DBGLVL_API, "  numgpiogroups = 0x%x\n",
+				exthdr->numgpiogroups);
+			dprintk(DBGLVL_API, "  controlsize = 0x%x\n",
+				exthdr->controlsize);
+			if (exthdr->devicetype & 0x80) {
+				if (currpath == 1)
+					encport = &dev->ports[SAA7164_PORT_ENC1];
+				else
+					encport = &dev->ports[SAA7164_PORT_ENC2];
+				memcpy(&encport->ifunit, exthdr,
+					sizeof(struct tmComResExtDevDescrHeader));
+				dprintk(DBGLVL_API,
+					"  (becomes dev->enc[%d])\n",
+					encport->nr);
+			}
+			break;
+		case PVC_INFRARED_UNIT:
+			dprintk(DBGLVL_API, " PVC_INFRARED_UNIT\n");
+			break;
+		case DRM_UNIT:
+			dprintk(DBGLVL_API, " DRM_UNIT\n");
+			break;
+		default:
+			dprintk(DBGLVL_API, "default %d\n", hdr->subtype);
+		}
+
+		dprintk(DBGLVL_API, " 1.%x\n", hdr->len);
+		dprintk(DBGLVL_API, " 2.%x\n", hdr->type);
+		dprintk(DBGLVL_API, " 3.%x\n", hdr->subtype);
+		dprintk(DBGLVL_API, " 4.%x\n", hdr->unitid);
+
+		idx += hdr->len;
+	}
+
+	return 0;
+}
+
+int saa7164_api_enum_subdevs(struct saa7164_dev *dev)
+{
+	int ret;
+	u32 buflen = 0;
+	u8 *buf;
+
+	dprintk(DBGLVL_API, "%s()\n", __func__);
+
+	/* Get the total descriptor length */
+	ret = saa7164_cmd_send(dev, 0, GET_LEN,
+		GET_DESCRIPTORS_CONTROL, sizeof(buflen), &buflen);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+	dprintk(DBGLVL_API, "%s() total descriptor size = %d bytes.\n",
+		__func__, buflen);
+
+	/* Allocate enough storage for all of the descs */
+	buf = kzalloc(buflen, GFP_KERNEL);
+	if (!buf)
+		return SAA_ERR_NO_RESOURCES;
+
+	/* Retrieve them */
+	ret = saa7164_cmd_send(dev, 0, GET_CUR,
+		GET_DESCRIPTORS_CONTROL, buflen, buf);
+	if (ret != SAA_OK) {
+		printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+		goto out;
+	}
+
+	if (saa_debug & DBGLVL_API)
+		print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, buf,
+			       buflen & ~15, false);
+
+	saa7164_api_dump_subdevs(dev, buf, buflen);
+
+out:
+	kfree(buf);
+	return ret;
+}
+
+int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg,
+	u32 datalen, u8 *data)
+{
+	struct saa7164_dev *dev = bus->dev;
+	u16 len = 0;
+	int unitid;
+	u8 buf[256];
+	int ret;
+
+	dprintk(DBGLVL_API, "%s()\n", __func__);
+
+	if (reglen > 4)
+		return -EIO;
+
+	/* Prepare the send buffer */
+	/* Bytes 00-03 source register length
+	 *       04-07 source bytes to read
+	 *       08... register address
+	 */
+	memset(buf, 0, sizeof(buf));
+	memcpy((buf + 2 * sizeof(u32) + 0), reg, reglen);
+	*((u32 *)(buf + 0 * sizeof(u32))) = reglen;
+	*((u32 *)(buf + 1 * sizeof(u32))) = datalen;
+
+	unitid = saa7164_i2caddr_to_unitid(bus, addr);
+	if (unitid < 0) {
+		printk(KERN_ERR
+			"%s() error, cannot translate regaddr 0x%x to unitid\n",
+			__func__, addr);
+		return -EIO;
+	}
+
+	ret = saa7164_cmd_send(bus->dev, unitid, GET_LEN,
+		EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len);
+	if (ret != SAA_OK) {
+		printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret);
+		return -EIO;
+	}
+
+	dprintk(DBGLVL_API, "%s() len = %d bytes\n", __func__, len);
+
+	if (saa_debug & DBGLVL_I2C)
+		print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, buf,
+			       32, false);
+
+	ret = saa7164_cmd_send(bus->dev, unitid, GET_CUR,
+		EXU_REGISTER_ACCESS_CONTROL, len, &buf);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
+	else {
+		if (saa_debug & DBGLVL_I2C)
+			print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1,
+				       buf, sizeof(buf), false);
+		memcpy(data, (buf + 2 * sizeof(u32) + reglen), datalen);
+	}
+
+	return ret == SAA_OK ? 0 : -EIO;
+}
+
+/* For a given 8 bit i2c address device, write the buffer */
+int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen,
+	u8 *data)
+{
+	struct saa7164_dev *dev = bus->dev;
+	u16 len = 0;
+	int unitid;
+	int reglen;
+	u8 buf[256];
+	int ret;
+
+	dprintk(DBGLVL_API, "%s()\n", __func__);
+
+	if ((datalen == 0) || (datalen > 232))
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+
+	unitid = saa7164_i2caddr_to_unitid(bus, addr);
+	if (unitid < 0) {
+		printk(KERN_ERR
+			"%s() error, cannot translate regaddr 0x%x to unitid\n",
+			__func__, addr);
+		return -EIO;
+	}
+
+	reglen = saa7164_i2caddr_to_reglen(bus, addr);
+	if (reglen < 0) {
+		printk(KERN_ERR
+			"%s() error, cannot translate regaddr to reglen\n",
+			__func__);
+		return -EIO;
+	}
+
+	ret = saa7164_cmd_send(bus->dev, unitid, GET_LEN,
+		EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len);
+	if (ret != SAA_OK) {
+		printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret);
+		return -EIO;
+	}
+
+	dprintk(DBGLVL_API, "%s() len = %d bytes\n", __func__, len);
+
+	/* Prepare the send buffer */
+	/* Bytes 00-03 dest register length
+	 *       04-07 dest bytes to write
+	 *       08... register address
+	 */
+	*((u32 *)(buf + 0 * sizeof(u32))) = reglen;
+	*((u32 *)(buf + 1 * sizeof(u32))) = datalen - reglen;
+	memcpy((buf + 2 * sizeof(u32)), data, datalen);
+
+	if (saa_debug & DBGLVL_I2C)
+		print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1,
+			       buf, sizeof(buf), false);
+
+	ret = saa7164_cmd_send(bus->dev, unitid, SET_CUR,
+		EXU_REGISTER_ACCESS_CONTROL, len, &buf);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
+
+	return ret == SAA_OK ? 0 : -EIO;
+}
+
+int saa7164_api_modify_gpio(struct saa7164_dev *dev, u8 unitid,
+	u8 pin, u8 state)
+{
+	int ret;
+	struct tmComResGPIO t;
+
+	dprintk(DBGLVL_API, "%s(0x%x, %d, %d)\n",
+		__func__, unitid, pin, state);
+
+	if ((pin > 7) || (state > 2))
+		return SAA_ERR_BAD_PARAMETER;
+
+	t.pin = pin;
+	t.state = state;
+
+	ret = saa7164_cmd_send(dev, unitid, SET_CUR,
+		EXU_GPIO_CONTROL, sizeof(t), &t);
+	if (ret != SAA_OK)
+		printk(KERN_ERR "%s() error, ret = 0x%x\n",
+			__func__, ret);
+
+	return ret;
+}
+
+int saa7164_api_set_gpiobit(struct saa7164_dev *dev, u8 unitid,
+	u8 pin)
+{
+	return saa7164_api_modify_gpio(dev, unitid, pin, 1);
+}
+
+int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid,
+	u8 pin)
+{
+	return saa7164_api_modify_gpio(dev, unitid, pin, 0);
+}
+
diff --git a/drivers/media/pci/saa7164/saa7164-buffer.c b/drivers/media/pci/saa7164/saa7164-buffer.c
new file mode 100644
index 0000000..66696fa
--- /dev/null
+++ b/drivers/media/pci/saa7164/saa7164-buffer.c
@@ -0,0 +1,322 @@
+/*
+ *  Driver for the NXP SAA7164 PCIe bridge
+ *
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/slab.h>
+
+#include "saa7164.h"
+
+/* The PCI address space for buffer handling looks like this:
+ *
+ * +-u32 wide-------------+
+ * |                      +
+ * +-u64 wide------------------------------------+
+ * +                                             +
+ * +----------------------+
+ * | CurrentBufferPtr     + Pointer to current PCI buffer >-+
+ * +----------------------+                                 |
+ * | Unused               +                                 |
+ * +----------------------+                                 |
+ * | Pitch                + = 188 (bytes)                   |
+ * +----------------------+                                 |
+ * | PCI buffer size      + = pitch * number of lines (312) |
+ * +----------------------+                                 |
+ * |0| Buf0 Write Offset  +                                 |
+ * +----------------------+                                 v
+ * |1| Buf1 Write Offset  +                                 |
+ * +----------------------+                                 |
+ * |2| Buf2 Write Offset  +                                 |
+ * +----------------------+                                 |
+ * |3| Buf3 Write Offset  +                                 |
+ * +----------------------+                                 |
+ * ... More write offsets                                   |
+ * +---------------------------------------------+          |
+ * +0| set of ptrs to PCI pagetables             +          |
+ * +---------------------------------------------+          |
+ * +1| set of ptrs to PCI pagetables             + <--------+
+ * +---------------------------------------------+
+ * +2| set of ptrs to PCI pagetables             +
+ * +---------------------------------------------+
+ * +3| set of ptrs to PCI pagetables             + >--+
+ * +---------------------------------------------+    |
+ * ... More buffer pointers                           |  +----------------+
+ *						    +->| pt[0] TS data  |
+ *						    |  +----------------+
+ *						    |
+ *						    |  +----------------+
+ *						    +->| pt[1] TS data  |
+ *						    |  +----------------+
+ *						    | etc
+ */
+
+void saa7164_buffer_display(struct saa7164_buffer *buf)
+{
+	struct saa7164_dev *dev = buf->port->dev;
+	int i;
+
+	dprintk(DBGLVL_BUF, "%s()   buffer @ 0x%p nr=%d\n",
+		__func__, buf, buf->idx);
+	dprintk(DBGLVL_BUF, "  pci_cpu @ 0x%p    dma @ 0x%08llx len = 0x%x\n",
+		buf->cpu, (long long)buf->dma, buf->pci_size);
+	dprintk(DBGLVL_BUF, "   pt_cpu @ 0x%p pt_dma @ 0x%08llx len = 0x%x\n",
+		buf->pt_cpu, (long long)buf->pt_dma, buf->pt_size);
+
+	/* Format the Page Table Entries to point into the data buffer */
+	for (i = 0 ; i < SAA7164_PT_ENTRIES; i++) {
+
+		dprintk(DBGLVL_BUF, "    pt[%02d] = 0x%p -> 0x%llx\n",
+			i, buf->pt_cpu, (u64)*(buf->pt_cpu));
+
+	}
+}
+/* Allocate a new buffer structure and associated PCI space in bytes.
+ * len must be a multiple of sizeof(u64)
+ */
+struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port,
+	u32 len)
+{
+	struct tmHWStreamParameters *params = &port->hw_streamingparams;
+	struct saa7164_buffer *buf = NULL;
+	struct saa7164_dev *dev = port->dev;
+	int i;
+
+	if ((len == 0) || (len >= 65536) || (len % sizeof(u64))) {
+		log_warn("%s() SAA_ERR_BAD_PARAMETER\n", __func__);
+		goto ret;
+	}
+
+	buf = kzalloc(sizeof(struct saa7164_buffer), GFP_KERNEL);
+	if (!buf) {
+		log_warn("%s() SAA_ERR_NO_RESOURCES\n", __func__);
+		goto ret;
+	}
+
+	buf->idx = -1;
+	buf->port = port;
+	buf->flags = SAA7164_BUFFER_FREE;
+	buf->pos = 0;
+	buf->actual_size = params->pitch * params->numberoflines;
+	buf->crc = 0;
+	/* TODO: arg len is being ignored */
+	buf->pci_size = SAA7164_PT_ENTRIES * 0x1000;
+	buf->pt_size = (SAA7164_PT_ENTRIES * sizeof(u64)) + 0x1000;
+
+	/* Allocate contiguous memory */
+	buf->cpu = pci_alloc_consistent(port->dev->pci, buf->pci_size,
+		&buf->dma);
+	if (!buf->cpu)
+		goto fail1;
+
+	buf->pt_cpu = pci_alloc_consistent(port->dev->pci, buf->pt_size,
+		&buf->pt_dma);
+	if (!buf->pt_cpu)
+		goto fail2;
+
+	/* init the buffers to a known pattern, easier during debugging */
+	memset_io(buf->cpu, 0xff, buf->pci_size);
+	buf->crc = crc32(0, buf->cpu, buf->actual_size);
+	memset_io(buf->pt_cpu, 0xff, buf->pt_size);
+
+	dprintk(DBGLVL_BUF, "%s()   allocated buffer @ 0x%p (%d pageptrs)\n",
+		__func__, buf, params->numpagetables);
+	dprintk(DBGLVL_BUF, "  pci_cpu @ 0x%p    dma @ 0x%08lx len = 0x%x\n",
+		buf->cpu, (long)buf->dma, buf->pci_size);
+	dprintk(DBGLVL_BUF, "   pt_cpu @ 0x%p pt_dma @ 0x%08lx len = 0x%x\n",
+		buf->pt_cpu, (long)buf->pt_dma, buf->pt_size);
+
+	/* Format the Page Table Entries to point into the data buffer */
+	for (i = 0 ; i < params->numpagetables; i++) {
+
+		*(buf->pt_cpu + i) = buf->dma + (i * 0x1000); /* TODO */
+		dprintk(DBGLVL_BUF, "    pt[%02d] = 0x%p -> 0x%llx\n",
+			i, buf->pt_cpu, (u64)*(buf->pt_cpu));
+
+	}
+
+	goto ret;
+
+fail2:
+	pci_free_consistent(port->dev->pci, buf->pci_size, buf->cpu, buf->dma);
+fail1:
+	kfree(buf);
+
+	buf = NULL;
+ret:
+	return buf;
+}
+
+int saa7164_buffer_dealloc(struct saa7164_buffer *buf)
+{
+	struct saa7164_dev *dev;
+
+	if (!buf || !buf->port)
+		return SAA_ERR_BAD_PARAMETER;
+	dev = buf->port->dev;
+
+	dprintk(DBGLVL_BUF, "%s() deallocating buffer @ 0x%p\n",
+		__func__, buf);
+
+	if (buf->flags != SAA7164_BUFFER_FREE)
+		log_warn(" freeing a non-free buffer\n");
+
+	pci_free_consistent(dev->pci, buf->pci_size, buf->cpu, buf->dma);
+	pci_free_consistent(dev->pci, buf->pt_size, buf->pt_cpu, buf->pt_dma);
+
+	kfree(buf);
+
+	return SAA_OK;
+}
+
+int saa7164_buffer_zero_offsets(struct saa7164_port *port, int i)
+{
+	struct saa7164_dev *dev = port->dev;
+
+	if ((i < 0) || (i >= port->hwcfg.buffercount))
+		return -EINVAL;
+
+	dprintk(DBGLVL_BUF, "%s(idx = %d)\n", __func__, i);
+
+	saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0);
+
+	return 0;
+}
+
+/* Write a buffer into the hardware */
+int saa7164_buffer_activate(struct saa7164_buffer *buf, int i)
+{
+	struct saa7164_port *port = buf->port;
+	struct saa7164_dev *dev = port->dev;
+
+	if ((i < 0) || (i >= port->hwcfg.buffercount))
+		return -EINVAL;
+
+	dprintk(DBGLVL_BUF, "%s(idx = %d)\n", __func__, i);
+
+	buf->idx = i; /* Note of which buffer list index position we occupy */
+	buf->flags = SAA7164_BUFFER_BUSY;
+	buf->pos = 0;
+
+	/* TODO: Review this in light of 32v64 assignments */
+	saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0);
+	saa7164_writel(port->bufptr32h + ((sizeof(u32) * 2) * i), buf->pt_dma);
+	saa7164_writel(port->bufptr32l + ((sizeof(u32) * 2) * i), 0);
+
+	dprintk(DBGLVL_BUF, "   buf[%d] offset 0x%llx (0x%x) "
+		"buf 0x%llx/%llx (0x%x/%x) nr=%d\n",
+		buf->idx,
+		(u64)port->bufoffset + (i * sizeof(u32)),
+		saa7164_readl(port->bufoffset + (sizeof(u32) * i)),
+		(u64)port->bufptr32h + ((sizeof(u32) * 2) * i),
+		(u64)port->bufptr32l + ((sizeof(u32) * 2) * i),
+		saa7164_readl(port->bufptr32h + ((sizeof(u32) * i) * 2)),
+		saa7164_readl(port->bufptr32l + ((sizeof(u32) * i) * 2)),
+		buf->idx);
+
+	return 0;
+}
+
+int saa7164_buffer_cfg_port(struct saa7164_port *port)
+{
+	struct tmHWStreamParameters *params = &port->hw_streamingparams;
+	struct saa7164_dev *dev = port->dev;
+	struct saa7164_buffer *buf;
+	struct list_head *c, *n;
+	int i = 0;
+
+	dprintk(DBGLVL_BUF, "%s(port=%d)\n", __func__, port->nr);
+
+	saa7164_writel(port->bufcounter, 0);
+	saa7164_writel(port->pitch, params->pitch);
+	saa7164_writel(port->bufsize, params->pitch * params->numberoflines);
+
+	dprintk(DBGLVL_BUF, " configured:\n");
+	dprintk(DBGLVL_BUF, "   lmmio       0x%p\n", dev->lmmio);
+	dprintk(DBGLVL_BUF, "   bufcounter  0x%x = 0x%x\n", port->bufcounter,
+		saa7164_readl(port->bufcounter));
+
+	dprintk(DBGLVL_BUF, "   pitch       0x%x = %d\n", port->pitch,
+		saa7164_readl(port->pitch));
+
+	dprintk(DBGLVL_BUF, "   bufsize     0x%x = %d\n", port->bufsize,
+		saa7164_readl(port->bufsize));
+
+	dprintk(DBGLVL_BUF, "   buffercount = %d\n", port->hwcfg.buffercount);
+	dprintk(DBGLVL_BUF, "   bufoffset = 0x%x\n", port->bufoffset);
+	dprintk(DBGLVL_BUF, "   bufptr32h = 0x%x\n", port->bufptr32h);
+	dprintk(DBGLVL_BUF, "   bufptr32l = 0x%x\n", port->bufptr32l);
+
+	/* Poke the buffers and offsets into PCI space */
+	mutex_lock(&port->dmaqueue_lock);
+	list_for_each_safe(c, n, &port->dmaqueue.list) {
+		buf = list_entry(c, struct saa7164_buffer, list);
+
+		if (buf->flags != SAA7164_BUFFER_FREE)
+			BUG();
+
+		/* Place the buffer in the h/w queue */
+		saa7164_buffer_activate(buf, i);
+
+		/* Don't exceed the device maximum # bufs */
+		if (i++ > port->hwcfg.buffercount)
+			BUG();
+
+	}
+	mutex_unlock(&port->dmaqueue_lock);
+
+	return 0;
+}
+
+struct saa7164_user_buffer *saa7164_buffer_alloc_user(struct saa7164_dev *dev,
+	u32 len)
+{
+	struct saa7164_user_buffer *buf;
+
+	buf = kzalloc(sizeof(struct saa7164_user_buffer), GFP_KERNEL);
+	if (!buf)
+		return NULL;
+
+	buf->data = kzalloc(len, GFP_KERNEL);
+
+	if (!buf->data) {
+		kfree(buf);
+		return NULL;
+	}
+
+	buf->actual_size = len;
+	buf->pos = 0;
+	buf->crc = 0;
+
+	dprintk(DBGLVL_BUF, "%s()   allocated user buffer @ 0x%p\n",
+		__func__, buf);
+
+	return buf;
+}
+
+void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf)
+{
+	if (!buf)
+		return;
+
+	kfree(buf->data);
+	buf->data = NULL;
+
+	kfree(buf);
+}
+
diff --git a/drivers/media/pci/saa7164/saa7164-bus.c b/drivers/media/pci/saa7164/saa7164-bus.c
new file mode 100644
index 0000000..a7f58a9
--- /dev/null
+++ b/drivers/media/pci/saa7164/saa7164-bus.c
@@ -0,0 +1,475 @@
+/*
+ *  Driver for the NXP SAA7164 PCIe bridge
+ *
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "saa7164.h"
+
+/* The message bus to/from the firmware is a ring buffer in PCI address
+ * space. Establish the defaults.
+ */
+int saa7164_bus_setup(struct saa7164_dev *dev)
+{
+	struct tmComResBusInfo *b	= &dev->bus;
+
+	mutex_init(&b->lock);
+
+	b->Type			= TYPE_BUS_PCIe;
+	b->m_wMaxReqSize	= SAA_DEVICE_MAXREQUESTSIZE;
+
+	b->m_pdwSetRing		= (u8 *)(dev->bmmio +
+		((u32)dev->busdesc.CommandRing));
+
+	b->m_dwSizeSetRing	= SAA_DEVICE_BUFFERBLOCKSIZE;
+
+	b->m_pdwGetRing		= (u8 *)(dev->bmmio +
+		((u32)dev->busdesc.ResponseRing));
+
+	b->m_dwSizeGetRing	= SAA_DEVICE_BUFFERBLOCKSIZE;
+
+	b->m_dwSetWritePos	= ((u32)dev->intfdesc.BARLocation) +
+		(2 * sizeof(u64));
+	b->m_dwSetReadPos	= b->m_dwSetWritePos + (1 * sizeof(u32));
+
+	b->m_dwGetWritePos	= b->m_dwSetWritePos + (2 * sizeof(u32));
+	b->m_dwGetReadPos	= b->m_dwSetWritePos + (3 * sizeof(u32));
+
+	return 0;
+}
+
+void saa7164_bus_dump(struct saa7164_dev *dev)
+{
+	struct tmComResBusInfo *b = &dev->bus;
+
+	dprintk(DBGLVL_BUS, "Dumping the bus structure:\n");
+	dprintk(DBGLVL_BUS, " .type             = %d\n", b->Type);
+	dprintk(DBGLVL_BUS, " .dev->bmmio       = 0x%p\n", dev->bmmio);
+	dprintk(DBGLVL_BUS, " .m_wMaxReqSize    = 0x%x\n", b->m_wMaxReqSize);
+	dprintk(DBGLVL_BUS, " .m_pdwSetRing     = 0x%p\n", b->m_pdwSetRing);
+	dprintk(DBGLVL_BUS, " .m_dwSizeSetRing  = 0x%x\n", b->m_dwSizeSetRing);
+	dprintk(DBGLVL_BUS, " .m_pdwGetRing     = 0x%p\n", b->m_pdwGetRing);
+	dprintk(DBGLVL_BUS, " .m_dwSizeGetRing  = 0x%x\n", b->m_dwSizeGetRing);
+
+	dprintk(DBGLVL_BUS, " .m_dwSetReadPos   = 0x%x (0x%08x)\n",
+		b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos));
+
+	dprintk(DBGLVL_BUS, " .m_dwSetWritePos  = 0x%x (0x%08x)\n",
+		b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos));
+
+	dprintk(DBGLVL_BUS, " .m_dwGetReadPos   = 0x%x (0x%08x)\n",
+		b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos));
+
+	dprintk(DBGLVL_BUS, " .m_dwGetWritePos  = 0x%x (0x%08x)\n",
+		b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos));
+
+}
+
+/* Intensionally throw a BUG() if the state of the message bus looks corrupt */
+void saa7164_bus_verify(struct saa7164_dev *dev)
+{
+	struct tmComResBusInfo *b = &dev->bus;
+	int bug = 0;
+
+	if (saa7164_readl(b->m_dwSetReadPos) > b->m_dwSizeSetRing)
+		bug++;
+
+	if (saa7164_readl(b->m_dwSetWritePos) > b->m_dwSizeSetRing)
+		bug++;
+
+	if (saa7164_readl(b->m_dwGetReadPos) > b->m_dwSizeGetRing)
+		bug++;
+
+	if (saa7164_readl(b->m_dwGetWritePos) > b->m_dwSizeGetRing)
+		bug++;
+
+	if (bug) {
+		saa_debug = 0xffff; /* Ensure we get the bus dump */
+		saa7164_bus_dump(dev);
+		saa_debug = 1024; /* Ensure we get the bus dump */
+		BUG();
+	}
+}
+
+void saa7164_bus_dumpmsg(struct saa7164_dev *dev, struct tmComResInfo* m,
+	void *buf)
+{
+	dprintk(DBGLVL_BUS, "Dumping msg structure:\n");
+	dprintk(DBGLVL_BUS, " .id               = %d\n",   m->id);
+	dprintk(DBGLVL_BUS, " .flags            = 0x%x\n", m->flags);
+	dprintk(DBGLVL_BUS, " .size             = 0x%x\n", m->size);
+	dprintk(DBGLVL_BUS, " .command          = 0x%x\n", m->command);
+	dprintk(DBGLVL_BUS, " .controlselector  = 0x%x\n", m->controlselector);
+	dprintk(DBGLVL_BUS, " .seqno            = %d\n",   m->seqno);
+	if (buf)
+		dprintk(DBGLVL_BUS, " .buffer (ignored)\n");
+}
+
+/*
+ * Places a command or a response on the bus. The implementation does not
+ * know if it is a command or a response it just places the data on the
+ * bus depending on the bus information given in the struct tmComResBusInfo
+ * structure. If the command or response does not fit into the bus ring
+ * buffer it will be refused.
+ *
+ * Return Value:
+ *  SAA_OK     The function executed successfully.
+ *  < 0        One or more members are not initialized.
+ */
+int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
+	void *buf)
+{
+	struct tmComResBusInfo *bus = &dev->bus;
+	u32 bytes_to_write, free_write_space, timeout, curr_srp, curr_swp;
+	u32 new_swp, space_rem;
+	int ret = SAA_ERR_BAD_PARAMETER;
+
+	if (!msg) {
+		printk(KERN_ERR "%s() !msg\n", __func__);
+		return SAA_ERR_BAD_PARAMETER;
+	}
+
+	dprintk(DBGLVL_BUS, "%s()\n", __func__);
+
+	saa7164_bus_verify(dev);
+
+	msg->size = cpu_to_le16(msg->size);
+	msg->command = cpu_to_le32(msg->command);
+	msg->controlselector = cpu_to_le16(msg->controlselector);
+
+	if (msg->size > dev->bus.m_wMaxReqSize) {
+		printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
+			__func__);
+		return SAA_ERR_BAD_PARAMETER;
+	}
+
+	if ((msg->size > 0) && (buf == NULL)) {
+		printk(KERN_ERR "%s() Missing message buffer\n", __func__);
+		return SAA_ERR_BAD_PARAMETER;
+	}
+
+	/* Lock the bus from any other access */
+	mutex_lock(&bus->lock);
+
+	bytes_to_write = sizeof(*msg) + msg->size;
+	free_write_space = 0;
+	timeout = SAA_BUS_TIMEOUT;
+	curr_srp = le32_to_cpu(saa7164_readl(bus->m_dwSetReadPos));
+	curr_swp = le32_to_cpu(saa7164_readl(bus->m_dwSetWritePos));
+
+	/* Deal with ring wrapping issues */
+	if (curr_srp > curr_swp)
+		/* Deal with the wrapped ring */
+		free_write_space = curr_srp - curr_swp;
+	else
+		/* The ring has not wrapped yet */
+		free_write_space = (curr_srp + bus->m_dwSizeSetRing) - curr_swp;
+
+	dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__,
+		bytes_to_write);
+
+	dprintk(DBGLVL_BUS, "%s() free_write_space = %d\n", __func__,
+		free_write_space);
+
+	dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp);
+	dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp);
+
+	/* Process the msg and write the content onto the bus */
+	while (bytes_to_write >= free_write_space) {
+
+		if (timeout-- == 0) {
+			printk(KERN_ERR "%s() bus timeout\n", __func__);
+			ret = SAA_ERR_NO_RESOURCES;
+			goto out;
+		}
+
+		/* TODO: Review this delay, efficient? */
+		/* Wait, allowing the hardware fetch time */
+		mdelay(1);
+
+		/* Check the space usage again */
+		curr_srp = le32_to_cpu(saa7164_readl(bus->m_dwSetReadPos));
+
+		/* Deal with ring wrapping issues */
+		if (curr_srp > curr_swp)
+			/* Deal with the wrapped ring */
+			free_write_space = curr_srp - curr_swp;
+		else
+			/* Read didn't wrap around the buffer */
+			free_write_space = (curr_srp + bus->m_dwSizeSetRing) -
+				curr_swp;
+
+	}
+
+	/* Calculate the new write position */
+	new_swp = curr_swp + bytes_to_write;
+
+	dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
+	dprintk(DBGLVL_BUS, "%s() bus->m_dwSizeSetRing = %x\n", __func__,
+		bus->m_dwSizeSetRing);
+
+	/* Mental Note: line 462 tmmhComResBusPCIe.cpp */
+
+	/* Check if we're going to wrap again */
+	if (new_swp > bus->m_dwSizeSetRing) {
+
+		/* Ring wraps */
+		new_swp -= bus->m_dwSizeSetRing;
+
+		space_rem = bus->m_dwSizeSetRing - curr_swp;
+
+		dprintk(DBGLVL_BUS, "%s() space_rem = %x\n", __func__,
+			space_rem);
+
+		dprintk(DBGLVL_BUS, "%s() sizeof(*msg) = %d\n", __func__,
+			(u32)sizeof(*msg));
+
+		if (space_rem < sizeof(*msg)) {
+			dprintk(DBGLVL_BUS, "%s() tr4\n", __func__);
+
+			/* Split the msg into pieces as the ring wraps */
+			memcpy(bus->m_pdwSetRing + curr_swp, msg, space_rem);
+			memcpy(bus->m_pdwSetRing, (u8 *)msg + space_rem,
+				sizeof(*msg) - space_rem);
+
+			memcpy(bus->m_pdwSetRing + sizeof(*msg) - space_rem,
+				buf, msg->size);
+
+		} else if (space_rem == sizeof(*msg)) {
+			dprintk(DBGLVL_BUS, "%s() tr5\n", __func__);
+
+			/* Additional data at the beginning of the ring */
+			memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
+			memcpy(bus->m_pdwSetRing, buf, msg->size);
+
+		} else {
+			/* Additional data wraps around the ring */
+			memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
+			if (msg->size > 0) {
+				memcpy(bus->m_pdwSetRing + curr_swp +
+					sizeof(*msg), buf, space_rem -
+					sizeof(*msg));
+				memcpy(bus->m_pdwSetRing, (u8 *)buf +
+					space_rem - sizeof(*msg),
+					bytes_to_write - space_rem);
+			}
+
+		}
+
+	} /* (new_swp > bus->m_dwSizeSetRing) */
+	else {
+		dprintk(DBGLVL_BUS, "%s() tr6\n", __func__);
+
+		/* The ring buffer doesn't wrap, two simple copies */
+		memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
+		memcpy(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf,
+			msg->size);
+	}
+
+	dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
+
+	/* Update the bus write position */
+	saa7164_writel(bus->m_dwSetWritePos, cpu_to_le32(new_swp));
+	ret = SAA_OK;
+
+out:
+	saa7164_bus_dump(dev);
+	mutex_unlock(&bus->lock);
+	saa7164_bus_verify(dev);
+	return ret;
+}
+
+/*
+ * Receive a command or a response from the bus. The implementation does not
+ * know if it is a command or a response it simply dequeues the data,
+ * depending on the bus information given in the struct tmComResBusInfo
+ * structure.
+ *
+ * Return Value:
+ *  0          The function executed successfully.
+ *  < 0        One or more members are not initialized.
+ */
+int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
+	void *buf, int peekonly)
+{
+	struct tmComResBusInfo *bus = &dev->bus;
+	u32 bytes_to_read, write_distance, curr_grp, curr_gwp,
+		new_grp, buf_size, space_rem;
+	struct tmComResInfo msg_tmp;
+	int ret = SAA_ERR_BAD_PARAMETER;
+
+	saa7164_bus_verify(dev);
+
+	if (msg == NULL)
+		return ret;
+
+	if (msg->size > dev->bus.m_wMaxReqSize) {
+		printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
+			__func__);
+		return ret;
+	}
+
+	if ((peekonly == 0) && (msg->size > 0) && (buf == NULL)) {
+		printk(KERN_ERR
+			"%s() Missing msg buf, size should be %d bytes\n",
+			__func__, msg->size);
+		return ret;
+	}
+
+	mutex_lock(&bus->lock);
+
+	/* Peek the bus to see if a msg exists, if it's not what we're expecting
+	 * then return cleanly else read the message from the bus.
+	 */
+	curr_gwp = le32_to_cpu(saa7164_readl(bus->m_dwGetWritePos));
+	curr_grp = le32_to_cpu(saa7164_readl(bus->m_dwGetReadPos));
+
+	if (curr_gwp == curr_grp) {
+		ret = SAA_ERR_EMPTY;
+		goto out;
+	}
+
+	bytes_to_read = sizeof(*msg);
+
+	/* Calculate write distance to current read position */
+	write_distance = 0;
+	if (curr_gwp >= curr_grp)
+		/* Write doesn't wrap around the ring */
+		write_distance = curr_gwp - curr_grp;
+	else
+		/* Write wraps around the ring */
+		write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
+
+	if (bytes_to_read > write_distance) {
+		printk(KERN_ERR "%s() No message/response found\n", __func__);
+		ret = SAA_ERR_INVALID_COMMAND;
+		goto out;
+	}
+
+	/* Calculate the new read position */
+	new_grp = curr_grp + bytes_to_read;
+	if (new_grp > bus->m_dwSizeGetRing) {
+
+		/* Ring wraps */
+		new_grp -= bus->m_dwSizeGetRing;
+		space_rem = bus->m_dwSizeGetRing - curr_grp;
+
+		memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem);
+		memcpy((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing,
+			bytes_to_read - space_rem);
+
+	} else {
+		/* No wrapping */
+		memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read);
+	}
+
+	/* No need to update the read positions, because this was a peek */
+	/* If the caller specifically want to peek, return */
+	if (peekonly) {
+		memcpy(msg, &msg_tmp, sizeof(*msg));
+		goto peekout;
+	}
+
+	/* Check if the command/response matches what is expected */
+	if ((msg_tmp.id != msg->id) || (msg_tmp.command != msg->command) ||
+		(msg_tmp.controlselector != msg->controlselector) ||
+		(msg_tmp.seqno != msg->seqno) || (msg_tmp.size != msg->size)) {
+
+		printk(KERN_ERR "%s() Unexpected msg miss-match\n", __func__);
+		saa7164_bus_dumpmsg(dev, msg, buf);
+		saa7164_bus_dumpmsg(dev, &msg_tmp, NULL);
+		ret = SAA_ERR_INVALID_COMMAND;
+		goto out;
+	}
+
+	/* Get the actual command and response from the bus */
+	buf_size = msg->size;
+
+	bytes_to_read = sizeof(*msg) + msg->size;
+	/* Calculate write distance to current read position */
+	write_distance = 0;
+	if (curr_gwp >= curr_grp)
+		/* Write doesn't wrap around the ring */
+		write_distance = curr_gwp - curr_grp;
+	else
+		/* Write wraps around the ring */
+		write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
+
+	if (bytes_to_read > write_distance) {
+		printk(KERN_ERR "%s() Invalid bus state, missing msg "
+			"or mangled ring, faulty H/W / bad code?\n", __func__);
+		ret = SAA_ERR_INVALID_COMMAND;
+		goto out;
+	}
+
+	/* Calculate the new read position */
+	new_grp = curr_grp + bytes_to_read;
+	if (new_grp > bus->m_dwSizeGetRing) {
+
+		/* Ring wraps */
+		new_grp -= bus->m_dwSizeGetRing;
+		space_rem = bus->m_dwSizeGetRing - curr_grp;
+
+		if (space_rem < sizeof(*msg)) {
+			/* msg wraps around the ring */
+			memcpy(msg, bus->m_pdwGetRing + curr_grp, space_rem);
+			memcpy((u8 *)msg + space_rem, bus->m_pdwGetRing,
+				sizeof(*msg) - space_rem);
+			if (buf)
+				memcpy(buf, bus->m_pdwGetRing + sizeof(*msg) -
+					space_rem, buf_size);
+
+		} else if (space_rem == sizeof(*msg)) {
+			memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
+			if (buf)
+				memcpy(buf, bus->m_pdwGetRing, buf_size);
+		} else {
+			/* Additional data wraps around the ring */
+			memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
+			if (buf) {
+				memcpy(buf, bus->m_pdwGetRing + curr_grp +
+					sizeof(*msg), space_rem - sizeof(*msg));
+				memcpy(buf + space_rem - sizeof(*msg),
+					bus->m_pdwGetRing, bytes_to_read -
+					space_rem);
+			}
+
+		}
+
+	} else {
+		/* No wrapping */
+		memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
+		if (buf)
+			memcpy(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg),
+				buf_size);
+	}
+
+	/* Update the read positions, adjusting the ring */
+	saa7164_writel(bus->m_dwGetReadPos, cpu_to_le32(new_grp));
+
+peekout:
+	msg->size = le16_to_cpu(msg->size);
+	msg->command = le32_to_cpu(msg->command);
+	msg->controlselector = le16_to_cpu(msg->controlselector);
+	ret = SAA_OK;
+out:
+	mutex_unlock(&bus->lock);
+	saa7164_bus_verify(dev);
+	return ret;
+}
+
diff --git a/drivers/media/pci/saa7164/saa7164-cards.c b/drivers/media/pci/saa7164/saa7164-cards.c
new file mode 100644
index 0000000..5b72da5
--- /dev/null
+++ b/drivers/media/pci/saa7164/saa7164-cards.c
@@ -0,0 +1,773 @@
+/*
+ *  Driver for the NXP SAA7164 PCIe bridge
+ *
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "saa7164.h"
+
+/* The Bridge API needs to understand register widths (in bytes) for the
+ * attached I2C devices, so we can simplify the virtual i2c mechansms
+ * and keep the -i2c.c implementation clean.
+ */
+#define REGLEN_8bit	1
+#define REGLEN_16bit	2
+
+struct saa7164_board saa7164_boards[] = {
+	[SAA7164_BOARD_UNKNOWN] = {
+		/* Bridge will not load any firmware, without knowing
+		 * the rev this would be fatal. */
+		.name		= "Unknown",
+	},
+	[SAA7164_BOARD_UNKNOWN_REV2] = {
+		/* Bridge will load the v2 f/w and dump descriptors */
+		/* Required during new board bringup */
+		.name		= "Generic Rev2",
+		.chiprev	= SAA7164_CHIP_REV2,
+	},
+	[SAA7164_BOARD_UNKNOWN_REV3] = {
+		/* Bridge will load the v2 f/w and dump descriptors */
+		/* Required during new board bringup */
+		.name		= "Generic Rev3",
+		.chiprev	= SAA7164_CHIP_REV3,
+	},
+	[SAA7164_BOARD_HAUPPAUGE_HVR2200] = {
+		.name		= "Hauppauge WinTV-HVR2200",
+		.porta		= SAA7164_MPEG_DVB,
+		.portb		= SAA7164_MPEG_DVB,
+		.portc		= SAA7164_MPEG_ENCODER,
+		.portd		= SAA7164_MPEG_ENCODER,
+		.porte		= SAA7164_MPEG_VBI,
+		.portf		= SAA7164_MPEG_VBI,
+		.chiprev	= SAA7164_CHIP_REV3,
+		.unit		= {{
+			.id		= 0x1d,
+			.type		= SAA7164_UNIT_EEPROM,
+			.name		= "4K EEPROM",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_0,
+			.i2c_bus_addr	= 0xa0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x04,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1b,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1e,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "TDA10048-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0x10 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1f,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "TDA10048-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0x12 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		} },
+	},
+	[SAA7164_BOARD_HAUPPAUGE_HVR2200_2] = {
+		.name		= "Hauppauge WinTV-HVR2200",
+		.porta		= SAA7164_MPEG_DVB,
+		.portb		= SAA7164_MPEG_DVB,
+		.portc		= SAA7164_MPEG_ENCODER,
+		.portd		= SAA7164_MPEG_ENCODER,
+		.porte		= SAA7164_MPEG_VBI,
+		.portf		= SAA7164_MPEG_VBI,
+		.chiprev	= SAA7164_CHIP_REV2,
+		.unit		= {{
+			.id		= 0x06,
+			.type		= SAA7164_UNIT_EEPROM,
+			.name		= "4K EEPROM",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_0,
+			.i2c_bus_addr	= 0xa0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x04,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x05,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "TDA10048-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0x10 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1e,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1f,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "TDA10048-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0x12 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		} },
+	},
+	[SAA7164_BOARD_HAUPPAUGE_HVR2200_3] = {
+		.name		= "Hauppauge WinTV-HVR2200",
+		.porta		= SAA7164_MPEG_DVB,
+		.portb		= SAA7164_MPEG_DVB,
+		.portc		= SAA7164_MPEG_ENCODER,
+		.portd		= SAA7164_MPEG_ENCODER,
+		.porte		= SAA7164_MPEG_VBI,
+		.portf		= SAA7164_MPEG_VBI,
+		.chiprev	= SAA7164_CHIP_REV2,
+		.unit		= {{
+			.id		= 0x1d,
+			.type		= SAA7164_UNIT_EEPROM,
+			.name		= "4K EEPROM",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_0,
+			.i2c_bus_addr	= 0xa0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x04,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x05,
+			.type		= SAA7164_UNIT_ANALOG_DEMODULATOR,
+			.name		= "TDA8290-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0x84 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1b,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1c,
+			.type		= SAA7164_UNIT_ANALOG_DEMODULATOR,
+			.name		= "TDA8290-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0x84 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1e,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "TDA10048-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0x10 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1f,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "TDA10048-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0x12 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		} },
+	},
+	[SAA7164_BOARD_HAUPPAUGE_HVR2200_4] = {
+		.name		= "Hauppauge WinTV-HVR2200",
+		.porta		= SAA7164_MPEG_DVB,
+		.portb		= SAA7164_MPEG_DVB,
+		.portc		= SAA7164_MPEG_ENCODER,
+		.portd		= SAA7164_MPEG_ENCODER,
+		.porte		= SAA7164_MPEG_VBI,
+		.portf		= SAA7164_MPEG_VBI,
+		.chiprev	= SAA7164_CHIP_REV3,
+		.unit		= {{
+			.id		= 0x1d,
+			.type		= SAA7164_UNIT_EEPROM,
+			.name		= "4K EEPROM",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_0,
+			.i2c_bus_addr	= 0xa0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x04,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x05,
+			.type		= SAA7164_UNIT_ANALOG_DEMODULATOR,
+			.name		= "TDA8290-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0x84 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1b,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1c,
+			.type		= SAA7164_UNIT_ANALOG_DEMODULATOR,
+			.name		= "TDA8290-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0x84 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1e,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "TDA10048-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0x10 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1f,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "TDA10048-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0x12 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		} },
+	},
+	[SAA7164_BOARD_HAUPPAUGE_HVR2250] = {
+		.name		= "Hauppauge WinTV-HVR2250",
+		.porta		= SAA7164_MPEG_DVB,
+		.portb		= SAA7164_MPEG_DVB,
+		.portc		= SAA7164_MPEG_ENCODER,
+		.portd		= SAA7164_MPEG_ENCODER,
+		.porte		= SAA7164_MPEG_VBI,
+		.portf		= SAA7164_MPEG_VBI,
+		.chiprev	= SAA7164_CHIP_REV3,
+		.unit		= {{
+			.id		= 0x22,
+			.type		= SAA7164_UNIT_EEPROM,
+			.name		= "4K EEPROM",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_0,
+			.i2c_bus_addr	= 0xa0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x04,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x07,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "CX24228/S5H1411-1 (TOP)",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0x32 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x08,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "CX24228/S5H1411-1 (QAM)",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0x34 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x1e,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x20,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "CX24228/S5H1411-2 (TOP)",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0x32 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x23,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "CX24228/S5H1411-2 (QAM)",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0x34 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		} },
+	},
+	[SAA7164_BOARD_HAUPPAUGE_HVR2250_2] = {
+		.name		= "Hauppauge WinTV-HVR2250",
+		.porta		= SAA7164_MPEG_DVB,
+		.portb		= SAA7164_MPEG_DVB,
+		.portc		= SAA7164_MPEG_ENCODER,
+		.portd		= SAA7164_MPEG_ENCODER,
+		.porte		= SAA7164_MPEG_VBI,
+		.portf		= SAA7164_MPEG_VBI,
+		.chiprev	= SAA7164_CHIP_REV3,
+		.unit		= {{
+			.id		= 0x28,
+			.type		= SAA7164_UNIT_EEPROM,
+			.name		= "4K EEPROM",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_0,
+			.i2c_bus_addr	= 0xa0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x04,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x07,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "CX24228/S5H1411-1 (TOP)",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0x32 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x08,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "CX24228/S5H1411-1 (QAM)",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0x34 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x24,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x26,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "CX24228/S5H1411-2 (TOP)",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0x32 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x29,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "CX24228/S5H1411-2 (QAM)",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0x34 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		} },
+	},
+	[SAA7164_BOARD_HAUPPAUGE_HVR2250_3] = {
+		.name		= "Hauppauge WinTV-HVR2250",
+		.porta		= SAA7164_MPEG_DVB,
+		.portb		= SAA7164_MPEG_DVB,
+		.portc		= SAA7164_MPEG_ENCODER,
+		.portd		= SAA7164_MPEG_ENCODER,
+		.porte		= SAA7164_MPEG_VBI,
+		.portf		= SAA7164_MPEG_VBI,
+		.chiprev	= SAA7164_CHIP_REV3,
+		.unit		= {{
+			.id		= 0x26,
+			.type		= SAA7164_UNIT_EEPROM,
+			.name		= "4K EEPROM",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_0,
+			.i2c_bus_addr	= 0xa0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x04,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x07,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "CX24228/S5H1411-1 (TOP)",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0x32 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x08,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "CX24228/S5H1411-1 (QAM)",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0x34 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x22,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x24,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "CX24228/S5H1411-2 (TOP)",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0x32 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x27,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "CX24228/S5H1411-2 (QAM)",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0x34 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		} },
+	},
+	[SAA7164_BOARD_HAUPPAUGE_HVR2200_5] = {
+		.name		= "Hauppauge WinTV-HVR2200",
+		.porta		= SAA7164_MPEG_DVB,
+		.portb		= SAA7164_MPEG_DVB,
+		.chiprev	= SAA7164_CHIP_REV3,
+		.unit		= {{
+			.id		= 0x23,
+			.type		= SAA7164_UNIT_EEPROM,
+			.name		= "4K EEPROM",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_0,
+			.i2c_bus_addr	= 0xa0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x04,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x05,
+			.type		= SAA7164_UNIT_ANALOG_DEMODULATOR,
+			.name		= "TDA8290-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0x84 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x21,
+			.type		= SAA7164_UNIT_TUNER,
+			.name		= "TDA18271-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0xc0 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x22,
+			.type		= SAA7164_UNIT_ANALOG_DEMODULATOR,
+			.name		= "TDA8290-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0x84 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x24,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "TDA10048-1",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_1,
+			.i2c_bus_addr	= 0x10 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		}, {
+			.id		= 0x25,
+			.type		= SAA7164_UNIT_DIGITAL_DEMODULATOR,
+			.name		= "TDA10048-2",
+			.i2c_bus_nr	= SAA7164_I2C_BUS_2,
+			.i2c_bus_addr	= 0x12 >> 1,
+			.i2c_reg_len	= REGLEN_8bit,
+		} },
+	},
+};
+const unsigned int saa7164_bcount = ARRAY_SIZE(saa7164_boards);
+
+/* ------------------------------------------------------------------ */
+/* PCI subsystem IDs                                                  */
+
+struct saa7164_subid saa7164_subids[] = {
+	{
+		.subvendor = 0x0070,
+		.subdevice = 0x8880,
+		.card      = SAA7164_BOARD_HAUPPAUGE_HVR2250,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x8810,
+		.card      = SAA7164_BOARD_HAUPPAUGE_HVR2250,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x8980,
+		.card      = SAA7164_BOARD_HAUPPAUGE_HVR2200,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x8900,
+		.card      = SAA7164_BOARD_HAUPPAUGE_HVR2200_2,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x8901,
+		.card      = SAA7164_BOARD_HAUPPAUGE_HVR2200_3,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x88A1,
+		.card      = SAA7164_BOARD_HAUPPAUGE_HVR2250_3,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x8891,
+		.card      = SAA7164_BOARD_HAUPPAUGE_HVR2250_2,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x8851,
+		.card      = SAA7164_BOARD_HAUPPAUGE_HVR2250_2,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x8940,
+		.card      = SAA7164_BOARD_HAUPPAUGE_HVR2200_4,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x8953,
+		.card      = SAA7164_BOARD_HAUPPAUGE_HVR2200_5,
+	},
+};
+const unsigned int saa7164_idcount = ARRAY_SIZE(saa7164_subids);
+
+void saa7164_card_list(struct saa7164_dev *dev)
+{
+	int i;
+
+	if (0 == dev->pci->subsystem_vendor &&
+	    0 == dev->pci->subsystem_device) {
+		printk(KERN_ERR
+			"%s: Board has no valid PCIe Subsystem ID and can't\n"
+			"%s: be autodetected. Pass card=<n> insmod option to\n"
+			"%s: workaround that. Send complaints to the vendor\n"
+			"%s: of the TV card. Best regards,\n"
+			"%s:         -- tux\n",
+			dev->name, dev->name, dev->name, dev->name, dev->name);
+	} else {
+		printk(KERN_ERR
+			"%s: Your board isn't known (yet) to the driver.\n"
+			"%s: Try to pick one of the existing card configs via\n"
+			"%s: card=<n> insmod option.  Updating to the latest\n"
+			"%s: version might help as well.\n",
+			dev->name, dev->name, dev->name, dev->name);
+	}
+
+	printk(KERN_ERR "%s: Here are valid choices for the card=<n> insmod "
+		"option:\n", dev->name);
+
+	for (i = 0; i < saa7164_bcount; i++)
+		printk(KERN_ERR "%s:    card=%d -> %s\n",
+		       dev->name, i, saa7164_boards[i].name);
+}
+
+/* TODO: clean this define up into the -cards.c structs */
+#define PCIEBRIDGE_UNITID 2
+
+void saa7164_gpio_setup(struct saa7164_dev *dev)
+{
+	switch (dev->board) {
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200_2:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200_3:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200_4:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200_5:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2250:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2250_2:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2250_3:
+		/*
+		GPIO 2: s5h1411 / tda10048-1 demod reset
+		GPIO 3: s5h1411 / tda10048-2 demod reset
+		GPIO 7: IRBlaster Zilog reset
+		 */
+
+		/* Reset parts by going in and out of reset */
+		saa7164_api_clear_gpiobit(dev, PCIEBRIDGE_UNITID, 2);
+		saa7164_api_clear_gpiobit(dev, PCIEBRIDGE_UNITID, 3);
+
+		msleep(20);
+
+		saa7164_api_set_gpiobit(dev, PCIEBRIDGE_UNITID, 2);
+		saa7164_api_set_gpiobit(dev, PCIEBRIDGE_UNITID, 3);
+		break;
+	}
+}
+
+static void hauppauge_eeprom(struct saa7164_dev *dev, u8 *eeprom_data)
+{
+	struct tveeprom tv;
+
+	/* TODO: Assumption: eeprom on bus 0 */
+	tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv,
+		eeprom_data);
+
+	/* Make sure we support the board model */
+	switch (tv.model) {
+	case 88001:
+		/* Development board - Limit circulation */
+		/* WinTV-HVR2250 (PCIe, Retail, full-height bracket)
+		 * ATSC/QAM (TDA18271/S5H1411) and basic analog, no IR, FM */
+	case 88021:
+		/* WinTV-HVR2250 (PCIe, Retail, full-height bracket)
+		 * ATSC/QAM (TDA18271/S5H1411) and basic analog, MCE CIR, FM */
+		break;
+	case 88041:
+		/* WinTV-HVR2250 (PCIe, Retail, full-height bracket)
+		 * ATSC/QAM (TDA18271/S5H1411) and basic analog, no IR, FM */
+		break;
+	case 88061:
+		/* WinTV-HVR2250 (PCIe, Retail, full-height bracket)
+		 * ATSC/QAM (TDA18271/S5H1411) and basic analog, FM */
+		break;
+	case 89519:
+	case 89609:
+		/* WinTV-HVR2200 (PCIe, Retail, full-height)
+		 * DVB-T (TDA18271/TDA10048) and basic analog, no IR */
+		break;
+	case 89619:
+		/* WinTV-HVR2200 (PCIe, Retail, half-height)
+		 * DVB-T (TDA18271/TDA10048) and basic analog, no IR */
+		break;
+	default:
+		printk(KERN_ERR "%s: Warning: Unknown Hauppauge model #%d\n",
+			dev->name, tv.model);
+		break;
+	}
+
+	printk(KERN_INFO "%s: Hauppauge eeprom: model=%d\n", dev->name,
+		tv.model);
+}
+
+void saa7164_card_setup(struct saa7164_dev *dev)
+{
+	static u8 eeprom[256];
+
+	if (dev->i2c_bus[0].i2c_rc == 0) {
+		if (saa7164_api_read_eeprom(dev, &eeprom[0],
+			sizeof(eeprom)) < 0)
+			return;
+	}
+
+	switch (dev->board) {
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200_2:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200_3:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200_4:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200_5:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2250:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2250_2:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2250_3:
+		hauppauge_eeprom(dev, &eeprom[0]);
+		break;
+	}
+}
+
+/* With most other drivers, the kernel expects to communicate with subdrivers
+ * through i2c. This bridge does not allow that, it does not expose any direct
+ * access to I2C. Instead we have to communicate through the device f/w for
+ * register access to 'processing units'. Each unit has a unique
+ * id, regardless of how the physical implementation occurs across
+ * the three physical i2c busses. The being said if we want leverge of
+ * the existing kernel drivers for tuners and demods we have to 'speak i2c',
+ * to this bridge implements 3 virtual i2c buses. This is a helper function
+ * for those.
+ *
+ * Description: Translate the kernels notion of an i2c address and bus into
+ * the appropriate unitid.
+ */
+int saa7164_i2caddr_to_unitid(struct saa7164_i2c *bus, int addr)
+{
+	/* For a given bus and i2c device address, return the saa7164 unique
+	 * unitid. < 0 on error */
+
+	struct saa7164_dev *dev = bus->dev;
+	struct saa7164_unit *unit;
+	int i;
+
+	for (i = 0; i < SAA7164_MAX_UNITS; i++) {
+		unit = &saa7164_boards[dev->board].unit[i];
+
+		if (unit->type == SAA7164_UNIT_UNDEFINED)
+			continue;
+		if ((bus->nr == unit->i2c_bus_nr) &&
+			(addr == unit->i2c_bus_addr))
+			return unit->id;
+	}
+
+	return -1;
+}
+
+/* The 7164 API needs to know the i2c register length in advance.
+ * this is a helper function. Based on a specific chip addr and bus return the
+ * reg length.
+ */
+int saa7164_i2caddr_to_reglen(struct saa7164_i2c *bus, int addr)
+{
+	/* For a given bus and i2c device address, return the
+	 * saa7164 registry address width. < 0 on error
+	 */
+
+	struct saa7164_dev *dev = bus->dev;
+	struct saa7164_unit *unit;
+	int i;
+
+	for (i = 0; i < SAA7164_MAX_UNITS; i++) {
+		unit = &saa7164_boards[dev->board].unit[i];
+
+		if (unit->type == SAA7164_UNIT_UNDEFINED)
+			continue;
+
+		if ((bus->nr == unit->i2c_bus_nr) &&
+			(addr == unit->i2c_bus_addr))
+			return unit->i2c_reg_len;
+	}
+
+	return -1;
+}
+/* TODO: implement a 'findeeprom' functio like the above and fix any other
+ * eeprom related todo's in -api.c.
+ */
+
+/* Translate a unitid into a x readable device name, for display purposes.  */
+char *saa7164_unitid_name(struct saa7164_dev *dev, u8 unitid)
+{
+	char *undefed = "UNDEFINED";
+	char *bridge = "BRIDGE";
+	struct saa7164_unit *unit;
+	int i;
+
+	if (unitid == 0)
+		return bridge;
+
+	for (i = 0; i < SAA7164_MAX_UNITS; i++) {
+		unit = &saa7164_boards[dev->board].unit[i];
+
+		if (unit->type == SAA7164_UNIT_UNDEFINED)
+			continue;
+
+		if (unitid == unit->id)
+				return unit->name;
+	}
+
+	return undefed;
+}
+
diff --git a/drivers/media/pci/saa7164/saa7164-cmd.c b/drivers/media/pci/saa7164/saa7164-cmd.c
new file mode 100644
index 0000000..62fac7f
--- /dev/null
+++ b/drivers/media/pci/saa7164/saa7164-cmd.c
@@ -0,0 +1,589 @@
+/*
+ *  Driver for the NXP SAA7164 PCIe bridge
+ *
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/wait.h>
+
+#include "saa7164.h"
+
+int saa7164_cmd_alloc_seqno(struct saa7164_dev *dev)
+{
+	int i, ret = -1;
+
+	mutex_lock(&dev->lock);
+	for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) {
+		if (dev->cmds[i].inuse == 0) {
+			dev->cmds[i].inuse = 1;
+			dev->cmds[i].signalled = 0;
+			dev->cmds[i].timeout = 0;
+			ret = dev->cmds[i].seqno;
+			break;
+		}
+	}
+	mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+void saa7164_cmd_free_seqno(struct saa7164_dev *dev, u8 seqno)
+{
+	mutex_lock(&dev->lock);
+	if ((dev->cmds[seqno].inuse == 1) &&
+		(dev->cmds[seqno].seqno == seqno)) {
+		dev->cmds[seqno].inuse = 0;
+		dev->cmds[seqno].signalled = 0;
+		dev->cmds[seqno].timeout = 0;
+	}
+	mutex_unlock(&dev->lock);
+}
+
+void saa7164_cmd_timeout_seqno(struct saa7164_dev *dev, u8 seqno)
+{
+	mutex_lock(&dev->lock);
+	if ((dev->cmds[seqno].inuse == 1) &&
+		(dev->cmds[seqno].seqno == seqno)) {
+		dev->cmds[seqno].timeout = 1;
+	}
+	mutex_unlock(&dev->lock);
+}
+
+u32 saa7164_cmd_timeout_get(struct saa7164_dev *dev, u8 seqno)
+{
+	int ret = 0;
+
+	mutex_lock(&dev->lock);
+	if ((dev->cmds[seqno].inuse == 1) &&
+		(dev->cmds[seqno].seqno == seqno)) {
+		ret = dev->cmds[seqno].timeout;
+	}
+	mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/* Commands to the f/w get marshelled to/from this code then onto the PCI
+ * -bus/c running buffer. */
+int saa7164_irq_dequeue(struct saa7164_dev *dev)
+{
+	int ret = SAA_OK, i = 0;
+	u32 timeout;
+	wait_queue_head_t *q = NULL;
+	u8 tmp[512];
+	dprintk(DBGLVL_CMD, "%s()\n", __func__);
+
+	/* While any outstand message on the bus exists... */
+	do {
+
+		/* Peek the msg bus */
+		struct tmComResInfo tRsp = { 0, 0, 0, 0, 0, 0 };
+		ret = saa7164_bus_get(dev, &tRsp, NULL, 1);
+		if (ret != SAA_OK)
+			break;
+
+		q = &dev->cmds[tRsp.seqno].wait;
+		timeout = saa7164_cmd_timeout_get(dev, tRsp.seqno);
+		dprintk(DBGLVL_CMD, "%s() timeout = %d\n", __func__, timeout);
+		if (!timeout) {
+			dprintk(DBGLVL_CMD,
+				"%s() signalled seqno(%d) (for dequeue)\n",
+				__func__, tRsp.seqno);
+			dev->cmds[tRsp.seqno].signalled = 1;
+			wake_up(q);
+		} else {
+			printk(KERN_ERR
+				"%s() found timed out command on the bus\n",
+					__func__);
+
+			/* Clean the bus */
+			ret = saa7164_bus_get(dev, &tRsp, &tmp, 0);
+			printk(KERN_ERR "%s() ret = %x\n", __func__, ret);
+			if (ret == SAA_ERR_EMPTY)
+				/* Someone else already fetched the response */
+				return SAA_OK;
+
+			if (ret != SAA_OK)
+				return ret;
+		}
+
+		/* It's unlikely to have more than 4 or 5 pending messages,
+		 * ensure we exit at some point regardless.
+		 */
+	} while (i++ < 32);
+
+	return ret;
+}
+
+/* Commands to the f/w get marshelled to/from this code then onto the PCI
+ * -bus/c running buffer. */
+int saa7164_cmd_dequeue(struct saa7164_dev *dev)
+{
+	int loop = 1;
+	int ret;
+	u32 timeout;
+	wait_queue_head_t *q = NULL;
+	u8 tmp[512];
+	dprintk(DBGLVL_CMD, "%s()\n", __func__);
+
+	while (loop) {
+
+		struct tmComResInfo tRsp = { 0, 0, 0, 0, 0, 0 };
+		ret = saa7164_bus_get(dev, &tRsp, NULL, 1);
+		if (ret == SAA_ERR_EMPTY)
+			return SAA_OK;
+
+		if (ret != SAA_OK)
+			return ret;
+
+		q = &dev->cmds[tRsp.seqno].wait;
+		timeout = saa7164_cmd_timeout_get(dev, tRsp.seqno);
+		dprintk(DBGLVL_CMD, "%s() timeout = %d\n", __func__, timeout);
+		if (timeout) {
+			printk(KERN_ERR "found timed out command on the bus\n");
+
+			/* Clean the bus */
+			ret = saa7164_bus_get(dev, &tRsp, &tmp, 0);
+			printk(KERN_ERR "ret = %x\n", ret);
+			if (ret == SAA_ERR_EMPTY)
+				/* Someone else already fetched the response */
+				return SAA_OK;
+
+			if (ret != SAA_OK)
+				return ret;
+
+			if (tRsp.flags & PVC_CMDFLAG_CONTINUE)
+				printk(KERN_ERR "split response\n");
+			else
+				saa7164_cmd_free_seqno(dev, tRsp.seqno);
+
+			printk(KERN_ERR " timeout continue\n");
+			continue;
+		}
+
+		dprintk(DBGLVL_CMD, "%s() signalled seqno(%d) (for dequeue)\n",
+			__func__, tRsp.seqno);
+		dev->cmds[tRsp.seqno].signalled = 1;
+		wake_up(q);
+		return SAA_OK;
+	}
+
+	return SAA_OK;
+}
+
+int saa7164_cmd_set(struct saa7164_dev *dev, struct tmComResInfo *msg,
+	void *buf)
+{
+	struct tmComResBusInfo *bus = &dev->bus;
+	u8 cmd_sent;
+	u16 size, idx;
+	u32 cmds;
+	void *tmp;
+	int ret = -1;
+
+	if (!msg) {
+		printk(KERN_ERR "%s() !msg\n", __func__);
+		return SAA_ERR_BAD_PARAMETER;
+	}
+
+	mutex_lock(&dev->cmds[msg->id].lock);
+
+	size = msg->size;
+	idx = 0;
+	cmds = size / bus->m_wMaxReqSize;
+	if (size % bus->m_wMaxReqSize == 0)
+		cmds -= 1;
+
+	cmd_sent = 0;
+
+	/* Split the request into smaller chunks */
+	for (idx = 0; idx < cmds; idx++) {
+
+		msg->flags |= SAA_CMDFLAG_CONTINUE;
+		msg->size = bus->m_wMaxReqSize;
+		tmp = buf + idx * bus->m_wMaxReqSize;
+
+		ret = saa7164_bus_set(dev, msg, tmp);
+		if (ret != SAA_OK) {
+			printk(KERN_ERR "%s() set failed %d\n", __func__, ret);
+
+			if (cmd_sent) {
+				ret = SAA_ERR_BUSY;
+				goto out;
+			}
+			ret = SAA_ERR_OVERFLOW;
+			goto out;
+		}
+		cmd_sent = 1;
+	}
+
+	/* If not the last command... */
+	if (idx != 0)
+		msg->flags &= ~SAA_CMDFLAG_CONTINUE;
+
+	msg->size = size - idx * bus->m_wMaxReqSize;
+
+	ret = saa7164_bus_set(dev, msg, buf + idx * bus->m_wMaxReqSize);
+	if (ret != SAA_OK) {
+		printk(KERN_ERR "%s() set last failed %d\n", __func__, ret);
+
+		if (cmd_sent) {
+			ret = SAA_ERR_BUSY;
+			goto out;
+		}
+		ret = SAA_ERR_OVERFLOW;
+		goto out;
+	}
+	ret = SAA_OK;
+
+out:
+	mutex_unlock(&dev->cmds[msg->id].lock);
+	return ret;
+}
+
+/* Wait for a signal event, without holding a mutex. Either return TIMEOUT if
+ * the event never occurred, or SAA_OK if it was signaled during the wait.
+ */
+int saa7164_cmd_wait(struct saa7164_dev *dev, u8 seqno)
+{
+	wait_queue_head_t *q = NULL;
+	int ret = SAA_BUS_TIMEOUT;
+	unsigned long stamp;
+	int r;
+
+	if (saa_debug >= 4)
+		saa7164_bus_dump(dev);
+
+	dprintk(DBGLVL_CMD, "%s(seqno=%d)\n", __func__, seqno);
+
+	mutex_lock(&dev->lock);
+	if ((dev->cmds[seqno].inuse == 1) &&
+		(dev->cmds[seqno].seqno == seqno)) {
+		q = &dev->cmds[seqno].wait;
+	}
+	mutex_unlock(&dev->lock);
+
+	if (q) {
+		/* If we haven't been signalled we need to wait */
+		if (dev->cmds[seqno].signalled == 0) {
+			stamp = jiffies;
+			dprintk(DBGLVL_CMD,
+				"%s(seqno=%d) Waiting (signalled=%d)\n",
+				__func__, seqno, dev->cmds[seqno].signalled);
+
+			/* Wait for signalled to be flagged or timeout */
+			/* In a highly stressed system this can easily extend
+			 * into multiple seconds before the deferred worker
+			 * is scheduled, and we're woken up via signal.
+			 * We typically are signalled in < 50ms but it can
+			 * take MUCH longer.
+			 */
+			wait_event_timeout(*q, dev->cmds[seqno].signalled,
+				(HZ * waitsecs));
+			r = time_before(jiffies, stamp + (HZ * waitsecs));
+			if (r)
+				ret = SAA_OK;
+			else
+				saa7164_cmd_timeout_seqno(dev, seqno);
+
+			dprintk(DBGLVL_CMD, "%s(seqno=%d) Waiting res = %d "
+				"(signalled=%d)\n", __func__, seqno, r,
+				dev->cmds[seqno].signalled);
+		} else
+			ret = SAA_OK;
+	} else
+		printk(KERN_ERR "%s(seqno=%d) seqno is invalid\n",
+			__func__, seqno);
+
+	return ret;
+}
+
+void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno)
+{
+	int i;
+	dprintk(DBGLVL_CMD, "%s()\n", __func__);
+
+	mutex_lock(&dev->lock);
+	for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) {
+		if (dev->cmds[i].inuse == 1) {
+			dprintk(DBGLVL_CMD,
+				"seqno %d inuse, sig = %d, t/out = %d\n",
+				dev->cmds[i].seqno,
+				dev->cmds[i].signalled,
+				dev->cmds[i].timeout);
+		}
+	}
+
+	for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) {
+		if ((dev->cmds[i].inuse == 1) && ((i == 0) ||
+			(dev->cmds[i].signalled) || (dev->cmds[i].timeout))) {
+			dprintk(DBGLVL_CMD, "%s(seqno=%d) calling wake_up\n",
+				__func__, i);
+			dev->cmds[i].signalled = 1;
+			wake_up(&dev->cmds[i].wait);
+		}
+	}
+	mutex_unlock(&dev->lock);
+}
+
+int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command,
+	u16 controlselector, u16 size, void *buf)
+{
+	struct tmComResInfo command_t, *pcommand_t;
+	struct tmComResInfo response_t, *presponse_t;
+	u8 errdata[256];
+	u16 resp_dsize;
+	u16 data_recd;
+	u32 loop;
+	int ret;
+	int safety = 0;
+
+	dprintk(DBGLVL_CMD, "%s(unitid = %s (%d) , command = 0x%x, "
+		"sel = 0x%x)\n", __func__, saa7164_unitid_name(dev, id), id,
+		command, controlselector);
+
+	if ((size == 0) || (buf == NULL)) {
+		printk(KERN_ERR "%s() Invalid param\n", __func__);
+		return SAA_ERR_BAD_PARAMETER;
+	}
+
+	/* Prepare some basic command/response structures */
+	memset(&command_t, 0, sizeof(command_t));
+	memset(&response_t, 0, sizeof(response_t));
+	pcommand_t = &command_t;
+	presponse_t = &response_t;
+	command_t.id = id;
+	command_t.command = command;
+	command_t.controlselector = controlselector;
+	command_t.size = size;
+
+	/* Allocate a unique sequence number */
+	ret = saa7164_cmd_alloc_seqno(dev);
+	if (ret < 0) {
+		printk(KERN_ERR "%s() No free sequences\n", __func__);
+		ret = SAA_ERR_NO_RESOURCES;
+		goto out;
+	}
+
+	command_t.seqno = (u8)ret;
+
+	/* Send Command */
+	resp_dsize = size;
+	pcommand_t->size = size;
+
+	dprintk(DBGLVL_CMD, "%s() pcommand_t.seqno = %d\n",
+		__func__, pcommand_t->seqno);
+
+	dprintk(DBGLVL_CMD, "%s() pcommand_t.size = %d\n",
+		__func__, pcommand_t->size);
+
+	ret = saa7164_cmd_set(dev, pcommand_t, buf);
+	if (ret != SAA_OK) {
+		printk(KERN_ERR "%s() set command failed %d\n", __func__, ret);
+
+		if (ret != SAA_ERR_BUSY)
+			saa7164_cmd_free_seqno(dev, pcommand_t->seqno);
+		else
+			/* Flag a timeout, because at least one
+			 * command was sent */
+			saa7164_cmd_timeout_seqno(dev, pcommand_t->seqno);
+
+		goto out;
+	}
+
+	/* With split responses we have to collect the msgs piece by piece */
+	data_recd = 0;
+	loop = 1;
+	while (loop) {
+		dprintk(DBGLVL_CMD, "%s() loop\n", __func__);
+
+		ret = saa7164_cmd_wait(dev, pcommand_t->seqno);
+		dprintk(DBGLVL_CMD, "%s() loop ret = %d\n", __func__, ret);
+
+		/* if power is down and this is not a power command ... */
+
+		if (ret == SAA_BUS_TIMEOUT) {
+			printk(KERN_ERR "Event timed out\n");
+			saa7164_cmd_timeout_seqno(dev, pcommand_t->seqno);
+			return ret;
+		}
+
+		if (ret != SAA_OK) {
+			printk(KERN_ERR "spurious error\n");
+			return ret;
+		}
+
+		/* Peek response */
+		ret = saa7164_bus_get(dev, presponse_t, NULL, 1);
+		if (ret == SAA_ERR_EMPTY) {
+			dprintk(4, "%s() SAA_ERR_EMPTY\n", __func__);
+			continue;
+		}
+		if (ret != SAA_OK) {
+			printk(KERN_ERR "peek failed\n");
+			return ret;
+		}
+
+		dprintk(DBGLVL_CMD, "%s() presponse_t->seqno = %d\n",
+			__func__, presponse_t->seqno);
+
+		dprintk(DBGLVL_CMD, "%s() presponse_t->flags = 0x%x\n",
+			__func__, presponse_t->flags);
+
+		dprintk(DBGLVL_CMD, "%s() presponse_t->size = %d\n",
+			__func__, presponse_t->size);
+
+		/* Check if the response was for our command */
+		if (presponse_t->seqno != pcommand_t->seqno) {
+
+			dprintk(DBGLVL_CMD,
+				"wrong event: seqno = %d, "
+				"expected seqno = %d, "
+				"will dequeue regardless\n",
+				presponse_t->seqno, pcommand_t->seqno);
+
+			ret = saa7164_cmd_dequeue(dev);
+			if (ret != SAA_OK) {
+				printk(KERN_ERR "dequeue failed, ret = %d\n",
+					ret);
+				if (safety++ > 16) {
+					printk(KERN_ERR
+					"dequeue exceeded, safety exit\n");
+					return SAA_ERR_BUSY;
+				}
+			}
+
+			continue;
+		}
+
+		if ((presponse_t->flags & PVC_RESPONSEFLAG_ERROR) != 0) {
+
+			memset(&errdata[0], 0, sizeof(errdata));
+
+			ret = saa7164_bus_get(dev, presponse_t, &errdata[0], 0);
+			if (ret != SAA_OK) {
+				printk(KERN_ERR "get error(2)\n");
+				return ret;
+			}
+
+			saa7164_cmd_free_seqno(dev, pcommand_t->seqno);
+
+			dprintk(DBGLVL_CMD, "%s() errdata %02x%02x%02x%02x\n",
+				__func__, errdata[0], errdata[1], errdata[2],
+				errdata[3]);
+
+			/* Map error codes */
+			dprintk(DBGLVL_CMD, "%s() cmd, error code  = 0x%x\n",
+				__func__, errdata[0]);
+
+			switch (errdata[0]) {
+			case PVC_ERRORCODE_INVALID_COMMAND:
+				dprintk(DBGLVL_CMD, "%s() INVALID_COMMAND\n",
+					__func__);
+				ret = SAA_ERR_INVALID_COMMAND;
+				break;
+			case PVC_ERRORCODE_INVALID_DATA:
+				dprintk(DBGLVL_CMD, "%s() INVALID_DATA\n",
+					__func__);
+				ret = SAA_ERR_BAD_PARAMETER;
+				break;
+			case PVC_ERRORCODE_TIMEOUT:
+				dprintk(DBGLVL_CMD, "%s() TIMEOUT\n", __func__);
+				ret = SAA_ERR_TIMEOUT;
+				break;
+			case PVC_ERRORCODE_NAK:
+				dprintk(DBGLVL_CMD, "%s() NAK\n", __func__);
+				ret = SAA_ERR_NULL_PACKET;
+				break;
+			case PVC_ERRORCODE_UNKNOWN:
+			case PVC_ERRORCODE_INVALID_CONTROL:
+				dprintk(DBGLVL_CMD,
+					"%s() UNKNOWN OR INVALID CONTROL\n",
+					__func__);
+			default:
+				dprintk(DBGLVL_CMD, "%s() UNKNOWN\n", __func__);
+				ret = SAA_ERR_NOT_SUPPORTED;
+			}
+
+			/* See of other commands are on the bus */
+			if (saa7164_cmd_dequeue(dev) != SAA_OK)
+				printk(KERN_ERR "dequeue(2) failed\n");
+
+			return ret;
+		}
+
+		/* If response is invalid */
+		if ((presponse_t->id != pcommand_t->id) ||
+			(presponse_t->command != pcommand_t->command) ||
+			(presponse_t->controlselector !=
+				pcommand_t->controlselector) ||
+			(((resp_dsize - data_recd) != presponse_t->size) &&
+				!(presponse_t->flags & PVC_CMDFLAG_CONTINUE)) ||
+			((resp_dsize - data_recd) < presponse_t->size)) {
+
+			/* Invalid */
+			dprintk(DBGLVL_CMD, "%s() Invalid\n", __func__);
+			ret = saa7164_bus_get(dev, presponse_t, NULL, 0);
+			if (ret != SAA_OK) {
+				printk(KERN_ERR "get failed\n");
+				return ret;
+			}
+
+			/* See of other commands are on the bus */
+			if (saa7164_cmd_dequeue(dev) != SAA_OK)
+				printk(KERN_ERR "dequeue(3) failed\n");
+			continue;
+		}
+
+		/* OK, now we're actually getting out correct response */
+		ret = saa7164_bus_get(dev, presponse_t, buf + data_recd, 0);
+		if (ret != SAA_OK) {
+			printk(KERN_ERR "get failed\n");
+			return ret;
+		}
+
+		data_recd = presponse_t->size + data_recd;
+		if (resp_dsize == data_recd) {
+			dprintk(DBGLVL_CMD, "%s() Resp recd\n", __func__);
+			break;
+		}
+
+		/* See of other commands are on the bus */
+		if (saa7164_cmd_dequeue(dev) != SAA_OK)
+			printk(KERN_ERR "dequeue(3) failed\n");
+
+		continue;
+
+	} /* (loop) */
+
+	/* Release the sequence number allocation */
+	saa7164_cmd_free_seqno(dev, pcommand_t->seqno);
+
+	/* if powerdown signal all pending commands */
+
+	dprintk(DBGLVL_CMD, "%s() Calling dequeue then exit\n", __func__);
+
+	/* See of other commands are on the bus */
+	if (saa7164_cmd_dequeue(dev) != SAA_OK)
+		printk(KERN_ERR "dequeue(4) failed\n");
+
+	ret = SAA_OK;
+out:
+	return ret;
+}
+
diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c
new file mode 100644
index 0000000..2c9ad87
--- /dev/null
+++ b/drivers/media/pci/saa7164/saa7164-core.c
@@ -0,0 +1,1488 @@
+/*
+ *  Driver for the NXP SAA7164 PCIe bridge
+ *
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/div64.h>
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
+#include "saa7164.h"
+
+MODULE_DESCRIPTION("Driver for NXP SAA7164 based TV cards");
+MODULE_AUTHOR("Steven Toth <stoth@kernellabs.com>");
+MODULE_LICENSE("GPL");
+
+/*
+ *  1 Basic
+ *  2
+ *  4 i2c
+ *  8 api
+ * 16 cmd
+ * 32 bus
+ */
+
+unsigned int saa_debug;
+module_param_named(debug, saa_debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+unsigned int fw_debug;
+module_param(fw_debug, int, 0644);
+MODULE_PARM_DESC(fw_debug, "Firware debug level def:2");
+
+unsigned int encoder_buffers = SAA7164_MAX_ENCODER_BUFFERS;
+module_param(encoder_buffers, int, 0644);
+MODULE_PARM_DESC(encoder_buffers, "Total buffers in read queue 16-512 def:64");
+
+unsigned int vbi_buffers = SAA7164_MAX_VBI_BUFFERS;
+module_param(vbi_buffers, int, 0644);
+MODULE_PARM_DESC(vbi_buffers, "Total buffers in read queue 16-512 def:64");
+
+unsigned int waitsecs = 10;
+module_param(waitsecs, int, 0644);
+MODULE_PARM_DESC(waitsecs, "timeout on firmware messages");
+
+static unsigned int card[]  = {[0 ... (SAA7164_MAXBOARDS - 1)] = UNSET };
+module_param_array(card,  int, NULL, 0444);
+MODULE_PARM_DESC(card, "card type");
+
+unsigned int print_histogram = 64;
+module_param(print_histogram, int, 0644);
+MODULE_PARM_DESC(print_histogram, "print histogram values once");
+
+unsigned int crc_checking = 1;
+module_param(crc_checking, int, 0644);
+MODULE_PARM_DESC(crc_checking, "enable crc sanity checking on buffers");
+
+unsigned int guard_checking = 1;
+module_param(guard_checking, int, 0644);
+MODULE_PARM_DESC(guard_checking,
+	"enable dma sanity checking for buffer overruns");
+
+static unsigned int saa7164_devcount;
+
+static DEFINE_MUTEX(devlist);
+LIST_HEAD(saa7164_devlist);
+
+#define INT_SIZE 16
+
+static void saa7164_pack_verifier(struct saa7164_buffer *buf)
+{
+	u8 *p = (u8 *)buf->cpu;
+	int i;
+
+	for (i = 0; i < buf->actual_size; i += 2048) {
+
+		if ((*(p + i + 0) != 0x00) || (*(p + i + 1) != 0x00) ||
+			(*(p + i + 2) != 0x01) || (*(p + i + 3) != 0xBA)) {
+			printk(KERN_ERR "No pack at 0x%x\n", i);
+#if 0
+			print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1,
+				       p + 1, 32, false);
+#endif
+		}
+	}
+}
+
+#define FIXED_VIDEO_PID 0xf1
+#define FIXED_AUDIO_PID 0xf2
+
+static void saa7164_ts_verifier(struct saa7164_buffer *buf)
+{
+	struct saa7164_port *port = buf->port;
+	u32 i;
+	u8 cc, a;
+	u16 pid;
+	u8 __iomem *bufcpu = (u8 *)buf->cpu;
+
+	port->sync_errors = 0;
+	port->v_cc_errors = 0;
+	port->a_cc_errors = 0;
+
+	for (i = 0; i < buf->actual_size; i += 188) {
+		if (*(bufcpu + i) != 0x47)
+			port->sync_errors++;
+
+		/* TODO: Query pid lower 8 bits, ignoring upper bits intensionally */
+		pid = ((*(bufcpu + i + 1) & 0x1f) << 8) | *(bufcpu + i + 2);
+		cc = *(bufcpu + i + 3) & 0x0f;
+
+		if (pid == FIXED_VIDEO_PID) {
+			a = ((port->last_v_cc + 1) & 0x0f);
+			if (a != cc) {
+				printk(KERN_ERR "video cc last = %x current = %x i = %d\n",
+					port->last_v_cc, cc, i);
+				port->v_cc_errors++;
+			}
+
+			port->last_v_cc = cc;
+		} else
+		if (pid == FIXED_AUDIO_PID) {
+			a = ((port->last_a_cc + 1) & 0x0f);
+			if (a != cc) {
+				printk(KERN_ERR "audio cc last = %x current = %x i = %d\n",
+					port->last_a_cc, cc, i);
+				port->a_cc_errors++;
+			}
+
+			port->last_a_cc = cc;
+		}
+
+	}
+
+	/* Only report errors if we've been through this function atleast
+	 * once already and the cached cc values are primed. First time through
+	 * always generates errors.
+	 */
+	if (port->v_cc_errors && (port->done_first_interrupt > 1))
+		printk(KERN_ERR "video pid cc, %d errors\n", port->v_cc_errors);
+
+	if (port->a_cc_errors && (port->done_first_interrupt > 1))
+		printk(KERN_ERR "audio pid cc, %d errors\n", port->a_cc_errors);
+
+	if (port->sync_errors && (port->done_first_interrupt > 1))
+		printk(KERN_ERR "sync_errors = %d\n", port->sync_errors);
+
+	if (port->done_first_interrupt == 1)
+		port->done_first_interrupt++;
+}
+
+static void saa7164_histogram_reset(struct saa7164_histogram *hg, char *name)
+{
+	int i;
+
+	memset(hg, 0, sizeof(struct saa7164_histogram));
+	strcpy(hg->name, name);
+
+	/* First 30ms x 1ms */
+	for (i = 0; i < 30; i++)
+		hg->counter1[0 + i].val = i;
+
+	/* 30 - 200ms x 10ms  */
+	for (i = 0; i < 18; i++)
+		hg->counter1[30 + i].val = 30 + (i * 10);
+
+	/* 200 - 2000ms x 100ms  */
+	for (i = 0; i < 15; i++)
+		hg->counter1[48 + i].val = 200 + (i * 200);
+
+	/* Catch all massive value (2secs) */
+	hg->counter1[55].val = 2000;
+
+	/* Catch all massive value (4secs) */
+	hg->counter1[56].val = 4000;
+
+	/* Catch all massive value (8secs) */
+	hg->counter1[57].val = 8000;
+
+	/* Catch all massive value (15secs) */
+	hg->counter1[58].val = 15000;
+
+	/* Catch all massive value (30secs) */
+	hg->counter1[59].val = 30000;
+
+	/* Catch all massive value (60secs) */
+	hg->counter1[60].val = 60000;
+
+	/* Catch all massive value (5mins) */
+	hg->counter1[61].val = 300000;
+
+	/* Catch all massive value (15mins) */
+	hg->counter1[62].val = 900000;
+
+	/* Catch all massive values (1hr) */
+	hg->counter1[63].val = 3600000;
+}
+
+void saa7164_histogram_update(struct saa7164_histogram *hg, u32 val)
+{
+	int i;
+	for (i = 0; i < 64; i++) {
+		if (val <= hg->counter1[i].val) {
+			hg->counter1[i].count++;
+			hg->counter1[i].update_time = jiffies;
+			break;
+		}
+	}
+}
+
+static void saa7164_histogram_print(struct saa7164_port *port,
+	struct saa7164_histogram *hg)
+{
+	u32 entries = 0;
+	int i;
+
+	printk(KERN_ERR "Histogram named %s (ms, count, last_update_jiffy)\n", hg->name);
+	for (i = 0; i < 64; i++) {
+		if (hg->counter1[i].count == 0)
+			continue;
+
+		printk(KERN_ERR " %4d %12d %Ld\n",
+			hg->counter1[i].val,
+			hg->counter1[i].count,
+			hg->counter1[i].update_time);
+
+		entries++;
+	}
+	printk(KERN_ERR "Total: %d\n", entries);
+}
+
+static void saa7164_work_enchandler_helper(struct saa7164_port *port, int bufnr)
+{
+	struct saa7164_dev *dev = port->dev;
+	struct saa7164_buffer *buf = NULL;
+	struct saa7164_user_buffer *ubuf = NULL;
+	struct list_head *c, *n;
+	int i = 0;
+	u8 __iomem *p;
+
+	mutex_lock(&port->dmaqueue_lock);
+	list_for_each_safe(c, n, &port->dmaqueue.list) {
+
+		buf = list_entry(c, struct saa7164_buffer, list);
+		if (i++ > port->hwcfg.buffercount) {
+			printk(KERN_ERR "%s() illegal i count %d\n",
+				__func__, i);
+			break;
+		}
+
+		if (buf->idx == bufnr) {
+
+			/* Found the buffer, deal with it */
+			dprintk(DBGLVL_IRQ, "%s() bufnr: %d\n", __func__, bufnr);
+
+			if (crc_checking) {
+				/* Throw a new checksum on the dma buffer */
+				buf->crc = crc32(0, buf->cpu, buf->actual_size);
+			}
+
+			if (guard_checking) {
+				p = (u8 *)buf->cpu;
+				if ((*(p + buf->actual_size + 0) != 0xff) ||
+					(*(p + buf->actual_size + 1) != 0xff) ||
+					(*(p + buf->actual_size + 2) != 0xff) ||
+					(*(p + buf->actual_size + 3) != 0xff) ||
+					(*(p + buf->actual_size + 0x10) != 0xff) ||
+					(*(p + buf->actual_size + 0x11) != 0xff) ||
+					(*(p + buf->actual_size + 0x12) != 0xff) ||
+					(*(p + buf->actual_size + 0x13) != 0xff)) {
+						printk(KERN_ERR "%s() buf %p guard buffer breach\n",
+							__func__, buf);
+#if 0
+			print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1,
+				       p + buf->actual_size - 32, 64, false);
+#endif
+				}
+			}
+
+			if ((port->nr != SAA7164_PORT_VBI1) && (port->nr != SAA7164_PORT_VBI2)) {
+				/* Validate the incoming buffer content */
+				if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)
+					saa7164_ts_verifier(buf);
+				else if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS)
+					saa7164_pack_verifier(buf);
+			}
+
+			/* find a free user buffer and clone to it */
+			if (!list_empty(&port->list_buf_free.list)) {
+
+				/* Pull the first buffer from the used list */
+				ubuf = list_first_entry(&port->list_buf_free.list,
+					struct saa7164_user_buffer, list);
+
+				if (buf->actual_size <= ubuf->actual_size) {
+
+					memcpy_fromio(ubuf->data, buf->cpu,
+						ubuf->actual_size);
+
+					if (crc_checking) {
+						/* Throw a new checksum on the read buffer */
+						ubuf->crc = crc32(0, ubuf->data, ubuf->actual_size);
+					}
+
+					/* Requeue the buffer on the free list */
+					ubuf->pos = 0;
+
+					list_move_tail(&ubuf->list,
+						&port->list_buf_used.list);
+
+					/* Flag any userland waiters */
+					wake_up_interruptible(&port->wait_read);
+
+				} else {
+					printk(KERN_ERR "buf %p bufsize fails match\n", buf);
+				}
+
+			} else
+				printk(KERN_ERR "encirq no free buffers, increase param encoder_buffers\n");
+
+			/* Ensure offset into buffer remains 0, fill buffer
+			 * with known bad data. We check for this data at a later point
+			 * in time. */
+			saa7164_buffer_zero_offsets(port, bufnr);
+			memset_io(buf->cpu, 0xff, buf->pci_size);
+			if (crc_checking) {
+				/* Throw yet aanother new checksum on the dma buffer */
+				buf->crc = crc32(0, buf->cpu, buf->actual_size);
+			}
+
+			break;
+		}
+	}
+	mutex_unlock(&port->dmaqueue_lock);
+}
+
+static void saa7164_work_enchandler(struct work_struct *w)
+{
+	struct saa7164_port *port =
+		container_of(w, struct saa7164_port, workenc);
+	struct saa7164_dev *dev = port->dev;
+
+	u32 wp, mcb, rp, cnt = 0;
+
+	port->last_svc_msecs_diff = port->last_svc_msecs;
+	port->last_svc_msecs = jiffies_to_msecs(jiffies);
+
+	port->last_svc_msecs_diff = port->last_svc_msecs -
+		port->last_svc_msecs_diff;
+
+	saa7164_histogram_update(&port->svc_interval,
+		port->last_svc_msecs_diff);
+
+	port->last_irq_svc_msecs_diff = port->last_svc_msecs -
+		port->last_irq_msecs;
+
+	saa7164_histogram_update(&port->irq_svc_interval,
+		port->last_irq_svc_msecs_diff);
+
+	dprintk(DBGLVL_IRQ,
+		"%s() %Ldms elapsed irq->deferred %Ldms wp: %d rp: %d\n",
+		__func__,
+		port->last_svc_msecs_diff,
+		port->last_irq_svc_msecs_diff,
+		port->last_svc_wp,
+		port->last_svc_rp
+		);
+
+	/* Current write position */
+	wp = saa7164_readl(port->bufcounter);
+	if (wp > (port->hwcfg.buffercount - 1)) {
+		printk(KERN_ERR "%s() illegal buf count %d\n", __func__, wp);
+		return;
+	}
+
+	/* Most current complete buffer */
+	if (wp == 0)
+		mcb = (port->hwcfg.buffercount - 1);
+	else
+		mcb = wp - 1;
+
+	while (1) {
+		if (port->done_first_interrupt == 0) {
+			port->done_first_interrupt++;
+			rp = mcb;
+		} else
+			rp = (port->last_svc_rp + 1) % 8;
+
+		if ((rp < 0) || (rp > (port->hwcfg.buffercount - 1))) {
+			printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp);
+			break;
+		}
+
+		saa7164_work_enchandler_helper(port, rp);
+		port->last_svc_rp = rp;
+		cnt++;
+
+		if (rp == mcb)
+			break;
+	}
+
+	/* TODO: Convert this into a /proc/saa7164 style readable file */
+	if (print_histogram == port->nr) {
+		saa7164_histogram_print(port, &port->irq_interval);
+		saa7164_histogram_print(port, &port->svc_interval);
+		saa7164_histogram_print(port, &port->irq_svc_interval);
+		saa7164_histogram_print(port, &port->read_interval);
+		saa7164_histogram_print(port, &port->poll_interval);
+		/* TODO: fix this to preserve any previous state */
+		print_histogram = 64 + port->nr;
+	}
+}
+
+static void saa7164_work_vbihandler(struct work_struct *w)
+{
+	struct saa7164_port *port =
+		container_of(w, struct saa7164_port, workenc);
+	struct saa7164_dev *dev = port->dev;
+
+	u32 wp, mcb, rp, cnt = 0;
+
+	port->last_svc_msecs_diff = port->last_svc_msecs;
+	port->last_svc_msecs = jiffies_to_msecs(jiffies);
+	port->last_svc_msecs_diff = port->last_svc_msecs -
+		port->last_svc_msecs_diff;
+
+	saa7164_histogram_update(&port->svc_interval,
+		port->last_svc_msecs_diff);
+
+	port->last_irq_svc_msecs_diff = port->last_svc_msecs -
+		port->last_irq_msecs;
+
+	saa7164_histogram_update(&port->irq_svc_interval,
+		port->last_irq_svc_msecs_diff);
+
+	dprintk(DBGLVL_IRQ,
+		"%s() %Ldms elapsed irq->deferred %Ldms wp: %d rp: %d\n",
+		__func__,
+		port->last_svc_msecs_diff,
+		port->last_irq_svc_msecs_diff,
+		port->last_svc_wp,
+		port->last_svc_rp
+		);
+
+	/* Current write position */
+	wp = saa7164_readl(port->bufcounter);
+	if (wp > (port->hwcfg.buffercount - 1)) {
+		printk(KERN_ERR "%s() illegal buf count %d\n", __func__, wp);
+		return;
+	}
+
+	/* Most current complete buffer */
+	if (wp == 0)
+		mcb = (port->hwcfg.buffercount - 1);
+	else
+		mcb = wp - 1;
+
+	while (1) {
+		if (port->done_first_interrupt == 0) {
+			port->done_first_interrupt++;
+			rp = mcb;
+		} else
+			rp = (port->last_svc_rp + 1) % 8;
+
+		if ((rp < 0) || (rp > (port->hwcfg.buffercount - 1))) {
+			printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp);
+			break;
+		}
+
+		saa7164_work_enchandler_helper(port, rp);
+		port->last_svc_rp = rp;
+		cnt++;
+
+		if (rp == mcb)
+			break;
+	}
+
+	/* TODO: Convert this into a /proc/saa7164 style readable file */
+	if (print_histogram == port->nr) {
+		saa7164_histogram_print(port, &port->irq_interval);
+		saa7164_histogram_print(port, &port->svc_interval);
+		saa7164_histogram_print(port, &port->irq_svc_interval);
+		saa7164_histogram_print(port, &port->read_interval);
+		saa7164_histogram_print(port, &port->poll_interval);
+		/* TODO: fix this to preserve any previous state */
+		print_histogram = 64 + port->nr;
+	}
+}
+
+static void saa7164_work_cmdhandler(struct work_struct *w)
+{
+	struct saa7164_dev *dev = container_of(w, struct saa7164_dev, workcmd);
+
+	/* Wake up any complete commands */
+	saa7164_irq_dequeue(dev);
+}
+
+static void saa7164_buffer_deliver(struct saa7164_buffer *buf)
+{
+	struct saa7164_port *port = buf->port;
+
+	/* Feed the transport payload into the kernel demux */
+	dvb_dmx_swfilter_packets(&port->dvb.demux, (u8 *)buf->cpu,
+		SAA7164_TS_NUMBER_OF_LINES);
+
+}
+
+static irqreturn_t saa7164_irq_vbi(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+
+	/* Store old time */
+	port->last_irq_msecs_diff = port->last_irq_msecs;
+
+	/* Collect new stats */
+	port->last_irq_msecs = jiffies_to_msecs(jiffies);
+
+	/* Calculate stats */
+	port->last_irq_msecs_diff = port->last_irq_msecs -
+		port->last_irq_msecs_diff;
+
+	saa7164_histogram_update(&port->irq_interval,
+		port->last_irq_msecs_diff);
+
+	dprintk(DBGLVL_IRQ, "%s() %Ldms elapsed\n", __func__,
+		port->last_irq_msecs_diff);
+
+	/* Tis calls the vbi irq handler */
+	schedule_work(&port->workenc);
+	return 0;
+}
+
+static irqreturn_t saa7164_irq_encoder(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+
+	/* Store old time */
+	port->last_irq_msecs_diff = port->last_irq_msecs;
+
+	/* Collect new stats */
+	port->last_irq_msecs = jiffies_to_msecs(jiffies);
+
+	/* Calculate stats */
+	port->last_irq_msecs_diff = port->last_irq_msecs -
+		port->last_irq_msecs_diff;
+
+	saa7164_histogram_update(&port->irq_interval,
+		port->last_irq_msecs_diff);
+
+	dprintk(DBGLVL_IRQ, "%s() %Ldms elapsed\n", __func__,
+		port->last_irq_msecs_diff);
+
+	schedule_work(&port->workenc);
+	return 0;
+}
+
+static irqreturn_t saa7164_irq_ts(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	struct saa7164_buffer *buf;
+	struct list_head *c, *n;
+	int wp, i = 0, rp;
+
+	/* Find the current write point from the hardware */
+	wp = saa7164_readl(port->bufcounter);
+	if (wp > (port->hwcfg.buffercount - 1))
+		BUG();
+
+	/* Find the previous buffer to the current write point */
+	if (wp == 0)
+		rp = (port->hwcfg.buffercount - 1);
+	else
+		rp = wp - 1;
+
+	/* Lookup the WP in the buffer list */
+	/* TODO: turn this into a worker thread */
+	list_for_each_safe(c, n, &port->dmaqueue.list) {
+		buf = list_entry(c, struct saa7164_buffer, list);
+		if (i++ > port->hwcfg.buffercount)
+			BUG();
+
+		if (buf->idx == rp) {
+			/* Found the buffer, deal with it */
+			dprintk(DBGLVL_IRQ, "%s() wp: %d processing: %d\n",
+				__func__, wp, rp);
+			saa7164_buffer_deliver(buf);
+			break;
+		}
+
+	}
+	return 0;
+}
+
+/* Primary IRQ handler and dispatch mechanism */
+static irqreturn_t saa7164_irq(int irq, void *dev_id)
+{
+	struct saa7164_dev *dev = dev_id;
+	struct saa7164_port *porta = &dev->ports[SAA7164_PORT_TS1];
+	struct saa7164_port *portb = &dev->ports[SAA7164_PORT_TS2];
+	struct saa7164_port *portc = &dev->ports[SAA7164_PORT_ENC1];
+	struct saa7164_port *portd = &dev->ports[SAA7164_PORT_ENC2];
+	struct saa7164_port *porte = &dev->ports[SAA7164_PORT_VBI1];
+	struct saa7164_port *portf = &dev->ports[SAA7164_PORT_VBI2];
+
+	u32 intid, intstat[INT_SIZE/4];
+	int i, handled = 0, bit;
+
+	if (dev == NULL) {
+		printk(KERN_ERR "%s() No device specified\n", __func__);
+		handled = 0;
+		goto out;
+	}
+
+	/* Check that the hardware is accessible. If the status bytes are
+	 * 0xFF then the device is not accessible, the the IRQ belongs
+	 * to another driver.
+	 * 4 x u32 interrupt registers.
+	 */
+	for (i = 0; i < INT_SIZE/4; i++) {
+
+		/* TODO: Convert into saa7164_readl() */
+		/* Read the 4 hardware interrupt registers */
+		intstat[i] = saa7164_readl(dev->int_status + (i * 4));
+
+		if (intstat[i])
+			handled = 1;
+	}
+	if (handled == 0)
+		goto out;
+
+	/* For each of the HW interrupt registers */
+	for (i = 0; i < INT_SIZE/4; i++) {
+
+		if (intstat[i]) {
+			/* Each function of the board has it's own interruptid.
+			 * Find the function that triggered then call
+			 * it's handler.
+			 */
+			for (bit = 0; bit < 32; bit++) {
+
+				if (((intstat[i] >> bit) & 0x00000001) == 0)
+					continue;
+
+				/* Calculate the interrupt id (0x00 to 0x7f) */
+
+				intid = (i * 32) + bit;
+				if (intid == dev->intfdesc.bInterruptId) {
+					/* A response to an cmd/api call */
+					schedule_work(&dev->workcmd);
+				} else if (intid == porta->hwcfg.interruptid) {
+
+					/* Transport path 1 */
+					saa7164_irq_ts(porta);
+
+				} else if (intid == portb->hwcfg.interruptid) {
+
+					/* Transport path 2 */
+					saa7164_irq_ts(portb);
+
+				} else if (intid == portc->hwcfg.interruptid) {
+
+					/* Encoder path 1 */
+					saa7164_irq_encoder(portc);
+
+				} else if (intid == portd->hwcfg.interruptid) {
+
+					/* Encoder path 2 */
+					saa7164_irq_encoder(portd);
+
+				} else if (intid == porte->hwcfg.interruptid) {
+
+					/* VBI path 1 */
+					saa7164_irq_vbi(porte);
+
+				} else if (intid == portf->hwcfg.interruptid) {
+
+					/* VBI path 2 */
+					saa7164_irq_vbi(portf);
+
+				} else {
+					/* Find the function */
+					dprintk(DBGLVL_IRQ,
+						"%s() unhandled interrupt "
+						"reg 0x%x bit 0x%x "
+						"intid = 0x%x\n",
+						__func__, i, bit, intid);
+				}
+			}
+
+			/* Ack it */
+			saa7164_writel(dev->int_ack + (i * 4), intstat[i]);
+
+		}
+	}
+out:
+	return IRQ_RETVAL(handled);
+}
+
+void saa7164_getfirmwarestatus(struct saa7164_dev *dev)
+{
+	struct saa7164_fw_status *s = &dev->fw_status;
+
+	dev->fw_status.status = saa7164_readl(SAA_DEVICE_SYSINIT_STATUS);
+	dev->fw_status.mode = saa7164_readl(SAA_DEVICE_SYSINIT_MODE);
+	dev->fw_status.spec = saa7164_readl(SAA_DEVICE_SYSINIT_SPEC);
+	dev->fw_status.inst = saa7164_readl(SAA_DEVICE_SYSINIT_INST);
+	dev->fw_status.cpuload = saa7164_readl(SAA_DEVICE_SYSINIT_CPULOAD);
+	dev->fw_status.remainheap =
+		saa7164_readl(SAA_DEVICE_SYSINIT_REMAINHEAP);
+
+	dprintk(1, "Firmware status:\n");
+	dprintk(1, " .status     = 0x%08x\n", s->status);
+	dprintk(1, " .mode       = 0x%08x\n", s->mode);
+	dprintk(1, " .spec       = 0x%08x\n", s->spec);
+	dprintk(1, " .inst       = 0x%08x\n", s->inst);
+	dprintk(1, " .cpuload    = 0x%08x\n", s->cpuload);
+	dprintk(1, " .remainheap = 0x%08x\n", s->remainheap);
+}
+
+u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev)
+{
+	u32 reg;
+
+	reg = saa7164_readl(SAA_DEVICE_VERSION);
+	dprintk(1, "Device running firmware version %d.%d.%d.%d (0x%x)\n",
+		(reg & 0x0000fc00) >> 10,
+		(reg & 0x000003e0) >> 5,
+		(reg & 0x0000001f),
+		(reg & 0xffff0000) >> 16,
+		reg);
+
+	return reg;
+}
+
+/* TODO: Debugging func, remove */
+void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr)
+{
+	int i;
+
+	dprintk(1, "--------------------> "
+		"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
+
+	for (i = 0; i < 0x100; i += 16)
+		dprintk(1, "region0[0x%08x] = "
+			"%02x %02x %02x %02x %02x %02x %02x %02x"
+			" %02x %02x %02x %02x %02x %02x %02x %02x\n", i,
+			(u8)saa7164_readb(addr + i + 0),
+			(u8)saa7164_readb(addr + i + 1),
+			(u8)saa7164_readb(addr + i + 2),
+			(u8)saa7164_readb(addr + i + 3),
+			(u8)saa7164_readb(addr + i + 4),
+			(u8)saa7164_readb(addr + i + 5),
+			(u8)saa7164_readb(addr + i + 6),
+			(u8)saa7164_readb(addr + i + 7),
+			(u8)saa7164_readb(addr + i + 8),
+			(u8)saa7164_readb(addr + i + 9),
+			(u8)saa7164_readb(addr + i + 10),
+			(u8)saa7164_readb(addr + i + 11),
+			(u8)saa7164_readb(addr + i + 12),
+			(u8)saa7164_readb(addr + i + 13),
+			(u8)saa7164_readb(addr + i + 14),
+			(u8)saa7164_readb(addr + i + 15)
+			);
+}
+
+static void saa7164_dump_hwdesc(struct saa7164_dev *dev)
+{
+	dprintk(1, "@0x%p hwdesc sizeof(struct tmComResHWDescr) = %d bytes\n",
+		&dev->hwdesc, (u32)sizeof(struct tmComResHWDescr));
+
+	dprintk(1, " .bLength = 0x%x\n", dev->hwdesc.bLength);
+	dprintk(1, " .bDescriptorType = 0x%x\n", dev->hwdesc.bDescriptorType);
+	dprintk(1, " .bDescriptorSubtype = 0x%x\n",
+		dev->hwdesc.bDescriptorSubtype);
+
+	dprintk(1, " .bcdSpecVersion = 0x%x\n", dev->hwdesc.bcdSpecVersion);
+	dprintk(1, " .dwClockFrequency = 0x%x\n", dev->hwdesc.dwClockFrequency);
+	dprintk(1, " .dwClockUpdateRes = 0x%x\n", dev->hwdesc.dwClockUpdateRes);
+	dprintk(1, " .bCapabilities = 0x%x\n", dev->hwdesc.bCapabilities);
+	dprintk(1, " .dwDeviceRegistersLocation = 0x%x\n",
+		dev->hwdesc.dwDeviceRegistersLocation);
+
+	dprintk(1, " .dwHostMemoryRegion = 0x%x\n",
+		dev->hwdesc.dwHostMemoryRegion);
+
+	dprintk(1, " .dwHostMemoryRegionSize = 0x%x\n",
+		dev->hwdesc.dwHostMemoryRegionSize);
+
+	dprintk(1, " .dwHostHibernatMemRegion = 0x%x\n",
+		dev->hwdesc.dwHostHibernatMemRegion);
+
+	dprintk(1, " .dwHostHibernatMemRegionSize = 0x%x\n",
+		dev->hwdesc.dwHostHibernatMemRegionSize);
+}
+
+static void saa7164_dump_intfdesc(struct saa7164_dev *dev)
+{
+	dprintk(1, "@0x%p intfdesc "
+		"sizeof(struct tmComResInterfaceDescr) = %d bytes\n",
+		&dev->intfdesc, (u32)sizeof(struct tmComResInterfaceDescr));
+
+	dprintk(1, " .bLength = 0x%x\n", dev->intfdesc.bLength);
+	dprintk(1, " .bDescriptorType = 0x%x\n", dev->intfdesc.bDescriptorType);
+	dprintk(1, " .bDescriptorSubtype = 0x%x\n",
+		dev->intfdesc.bDescriptorSubtype);
+
+	dprintk(1, " .bFlags = 0x%x\n", dev->intfdesc.bFlags);
+	dprintk(1, " .bInterfaceType = 0x%x\n", dev->intfdesc.bInterfaceType);
+	dprintk(1, " .bInterfaceId = 0x%x\n", dev->intfdesc.bInterfaceId);
+	dprintk(1, " .bBaseInterface = 0x%x\n", dev->intfdesc.bBaseInterface);
+	dprintk(1, " .bInterruptId = 0x%x\n", dev->intfdesc.bInterruptId);
+	dprintk(1, " .bDebugInterruptId = 0x%x\n",
+		dev->intfdesc.bDebugInterruptId);
+
+	dprintk(1, " .BARLocation = 0x%x\n", dev->intfdesc.BARLocation);
+}
+
+static void saa7164_dump_busdesc(struct saa7164_dev *dev)
+{
+	dprintk(1, "@0x%p busdesc sizeof(struct tmComResBusDescr) = %d bytes\n",
+		&dev->busdesc, (u32)sizeof(struct tmComResBusDescr));
+
+	dprintk(1, " .CommandRing   = 0x%016Lx\n", dev->busdesc.CommandRing);
+	dprintk(1, " .ResponseRing  = 0x%016Lx\n", dev->busdesc.ResponseRing);
+	dprintk(1, " .CommandWrite  = 0x%x\n", dev->busdesc.CommandWrite);
+	dprintk(1, " .CommandRead   = 0x%x\n", dev->busdesc.CommandRead);
+	dprintk(1, " .ResponseWrite = 0x%x\n", dev->busdesc.ResponseWrite);
+	dprintk(1, " .ResponseRead  = 0x%x\n", dev->busdesc.ResponseRead);
+}
+
+/* Much of the hardware configuration and PCI registers are configured
+ * dynamically depending on firmware. We have to cache some initial
+ * structures then use these to locate other important structures
+ * from PCI space.
+ */
+static void saa7164_get_descriptors(struct saa7164_dev *dev)
+{
+	memcpy_fromio(&dev->hwdesc, dev->bmmio, sizeof(struct tmComResHWDescr));
+	memcpy_fromio(&dev->intfdesc, dev->bmmio + sizeof(struct tmComResHWDescr),
+		sizeof(struct tmComResInterfaceDescr));
+	memcpy_fromio(&dev->busdesc, dev->bmmio + dev->intfdesc.BARLocation,
+		sizeof(struct tmComResBusDescr));
+
+	if (dev->hwdesc.bLength != sizeof(struct tmComResHWDescr)) {
+		printk(KERN_ERR "Structure struct tmComResHWDescr is mangled\n");
+		printk(KERN_ERR "Need %x got %d\n", dev->hwdesc.bLength,
+			(u32)sizeof(struct tmComResHWDescr));
+	} else
+		saa7164_dump_hwdesc(dev);
+
+	if (dev->intfdesc.bLength != sizeof(struct tmComResInterfaceDescr)) {
+		printk(KERN_ERR "struct struct tmComResInterfaceDescr is mangled\n");
+		printk(KERN_ERR "Need %x got %d\n", dev->intfdesc.bLength,
+			(u32)sizeof(struct tmComResInterfaceDescr));
+	} else
+		saa7164_dump_intfdesc(dev);
+
+	saa7164_dump_busdesc(dev);
+}
+
+static int saa7164_pci_quirks(struct saa7164_dev *dev)
+{
+	return 0;
+}
+
+static int get_resources(struct saa7164_dev *dev)
+{
+	if (request_mem_region(pci_resource_start(dev->pci, 0),
+		pci_resource_len(dev->pci, 0), dev->name)) {
+
+		if (request_mem_region(pci_resource_start(dev->pci, 2),
+			pci_resource_len(dev->pci, 2), dev->name))
+			return 0;
+	}
+
+	printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx or 0x%llx\n",
+		dev->name,
+		(u64)pci_resource_start(dev->pci, 0),
+		(u64)pci_resource_start(dev->pci, 2));
+
+	return -EBUSY;
+}
+
+static int saa7164_port_init(struct saa7164_dev *dev, int portnr)
+{
+	struct saa7164_port *port = NULL;
+
+	if ((portnr < 0) || (portnr >= SAA7164_MAX_PORTS))
+		BUG();
+
+	port = &dev->ports[portnr];
+
+	port->dev = dev;
+	port->nr = portnr;
+
+	if ((portnr == SAA7164_PORT_TS1) || (portnr == SAA7164_PORT_TS2))
+		port->type = SAA7164_MPEG_DVB;
+	else
+	if ((portnr == SAA7164_PORT_ENC1) || (portnr == SAA7164_PORT_ENC2)) {
+		port->type = SAA7164_MPEG_ENCODER;
+
+		/* We need a deferred interrupt handler for cmd handling */
+		INIT_WORK(&port->workenc, saa7164_work_enchandler);
+	} else if ((portnr == SAA7164_PORT_VBI1) || (portnr == SAA7164_PORT_VBI2)) {
+		port->type = SAA7164_MPEG_VBI;
+
+		/* We need a deferred interrupt handler for cmd handling */
+		INIT_WORK(&port->workenc, saa7164_work_vbihandler);
+	} else
+		BUG();
+
+	/* Init all the critical resources */
+	mutex_init(&port->dvb.lock);
+	INIT_LIST_HEAD(&port->dmaqueue.list);
+	mutex_init(&port->dmaqueue_lock);
+
+	INIT_LIST_HEAD(&port->list_buf_used.list);
+	INIT_LIST_HEAD(&port->list_buf_free.list);
+	init_waitqueue_head(&port->wait_read);
+
+
+	saa7164_histogram_reset(&port->irq_interval, "irq intervals");
+	saa7164_histogram_reset(&port->svc_interval, "deferred intervals");
+	saa7164_histogram_reset(&port->irq_svc_interval,
+		"irq to deferred intervals");
+	saa7164_histogram_reset(&port->read_interval,
+		"encoder/vbi read() intervals");
+	saa7164_histogram_reset(&port->poll_interval,
+		"encoder/vbi poll() intervals");
+
+	return 0;
+}
+
+static int saa7164_dev_setup(struct saa7164_dev *dev)
+{
+	int i;
+
+	mutex_init(&dev->lock);
+	atomic_inc(&dev->refcount);
+	dev->nr = saa7164_devcount++;
+
+	snprintf(dev->name, sizeof(dev->name), "saa7164[%d]", dev->nr);
+
+	mutex_lock(&devlist);
+	list_add_tail(&dev->devlist, &saa7164_devlist);
+	mutex_unlock(&devlist);
+
+	/* board config */
+	dev->board = UNSET;
+	if (card[dev->nr] < saa7164_bcount)
+		dev->board = card[dev->nr];
+
+	for (i = 0; UNSET == dev->board  &&  i < saa7164_idcount; i++)
+		if (dev->pci->subsystem_vendor == saa7164_subids[i].subvendor &&
+			dev->pci->subsystem_device ==
+				saa7164_subids[i].subdevice)
+				dev->board = saa7164_subids[i].card;
+
+	if (UNSET == dev->board) {
+		dev->board = SAA7164_BOARD_UNKNOWN;
+		saa7164_card_list(dev);
+	}
+
+	dev->pci_bus  = dev->pci->bus->number;
+	dev->pci_slot = PCI_SLOT(dev->pci->devfn);
+
+	/* I2C Defaults / setup */
+	dev->i2c_bus[0].dev = dev;
+	dev->i2c_bus[0].nr = 0;
+	dev->i2c_bus[1].dev = dev;
+	dev->i2c_bus[1].nr = 1;
+	dev->i2c_bus[2].dev = dev;
+	dev->i2c_bus[2].nr = 2;
+
+	/* Transport + Encoder ports 1, 2, 3, 4 - Defaults / setup */
+	saa7164_port_init(dev, SAA7164_PORT_TS1);
+	saa7164_port_init(dev, SAA7164_PORT_TS2);
+	saa7164_port_init(dev, SAA7164_PORT_ENC1);
+	saa7164_port_init(dev, SAA7164_PORT_ENC2);
+	saa7164_port_init(dev, SAA7164_PORT_VBI1);
+	saa7164_port_init(dev, SAA7164_PORT_VBI2);
+
+	if (get_resources(dev) < 0) {
+		printk(KERN_ERR "CORE %s No more PCIe resources for "
+		       "subsystem: %04x:%04x\n",
+		       dev->name, dev->pci->subsystem_vendor,
+		       dev->pci->subsystem_device);
+
+		saa7164_devcount--;
+		return -ENODEV;
+	}
+
+	/* PCI/e allocations */
+	dev->lmmio = ioremap(pci_resource_start(dev->pci, 0),
+			     pci_resource_len(dev->pci, 0));
+
+	dev->lmmio2 = ioremap(pci_resource_start(dev->pci, 2),
+			     pci_resource_len(dev->pci, 2));
+
+	dev->bmmio = (u8 __iomem *)dev->lmmio;
+	dev->bmmio2 = (u8 __iomem *)dev->lmmio2;
+
+	/* Inerrupt and ack register locations offset of bmmio */
+	dev->int_status = 0x183000 + 0xf80;
+	dev->int_ack = 0x183000 + 0xf90;
+
+	printk(KERN_INFO
+		"CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+	       dev->name, dev->pci->subsystem_vendor,
+	       dev->pci->subsystem_device, saa7164_boards[dev->board].name,
+	       dev->board, card[dev->nr] == dev->board ?
+	       "insmod option" : "autodetected");
+
+	saa7164_pci_quirks(dev);
+
+	return 0;
+}
+
+static void saa7164_dev_unregister(struct saa7164_dev *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+
+	release_mem_region(pci_resource_start(dev->pci, 0),
+		pci_resource_len(dev->pci, 0));
+
+	release_mem_region(pci_resource_start(dev->pci, 2),
+		pci_resource_len(dev->pci, 2));
+
+	if (!atomic_dec_and_test(&dev->refcount))
+		return;
+
+	iounmap(dev->lmmio);
+	iounmap(dev->lmmio2);
+
+	return;
+}
+
+#ifdef CONFIG_PROC_FS
+static int saa7164_proc_show(struct seq_file *m, void *v)
+{
+	struct saa7164_dev *dev;
+	struct tmComResBusInfo *b;
+	struct list_head *list;
+	int i, c;
+
+	if (saa7164_devcount == 0)
+		return 0;
+
+	list_for_each(list, &saa7164_devlist) {
+		dev = list_entry(list, struct saa7164_dev, devlist);
+		seq_printf(m, "%s = %p\n", dev->name, dev);
+
+		/* Lock the bus from any other access */
+		b = &dev->bus;
+		mutex_lock(&b->lock);
+
+		seq_printf(m, " .m_pdwSetWritePos = 0x%x (0x%08x)\n",
+			b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos));
+
+		seq_printf(m, " .m_pdwSetReadPos  = 0x%x (0x%08x)\n",
+			b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos));
+
+		seq_printf(m, " .m_pdwGetWritePos = 0x%x (0x%08x)\n",
+			b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos));
+
+		seq_printf(m, " .m_pdwGetReadPos  = 0x%x (0x%08x)\n",
+			b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos));
+		c = 0;
+		seq_printf(m, "\n  Set Ring:\n");
+		seq_printf(m, "\n addr  00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
+		for (i = 0; i < b->m_dwSizeSetRing; i++) {
+			if (c == 0)
+				seq_printf(m, " %04x:", i);
+
+			seq_printf(m, " %02x", *(b->m_pdwSetRing + i));
+
+			if (++c == 16) {
+				seq_printf(m, "\n");
+				c = 0;
+			}
+		}
+
+		c = 0;
+		seq_printf(m, "\n  Get Ring:\n");
+		seq_printf(m, "\n addr  00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
+		for (i = 0; i < b->m_dwSizeGetRing; i++) {
+			if (c == 0)
+				seq_printf(m, " %04x:", i);
+
+			seq_printf(m, " %02x", *(b->m_pdwGetRing + i));
+
+			if (++c == 16) {
+				seq_printf(m, "\n");
+				c = 0;
+			}
+		}
+
+		mutex_unlock(&b->lock);
+
+	}
+
+	return 0;
+}
+
+static int saa7164_proc_open(struct inode *inode, struct file *filp)
+{
+	return single_open(filp, saa7164_proc_show, NULL);
+}
+
+static const struct file_operations saa7164_proc_fops = {
+	.open		= saa7164_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int saa7164_proc_create(void)
+{
+	struct proc_dir_entry *pe;
+
+	pe = proc_create("saa7164", S_IRUGO, NULL, &saa7164_proc_fops);
+	if (!pe)
+		return -ENOMEM;
+
+	return 0;
+}
+#endif
+
+static int saa7164_thread_function(void *data)
+{
+	struct saa7164_dev *dev = data;
+	struct tmFwInfoStruct fwinfo;
+	u64 last_poll_time = 0;
+
+	dprintk(DBGLVL_THR, "thread started\n");
+
+	set_freezable();
+
+	while (1) {
+		msleep_interruptible(100);
+		if (kthread_should_stop())
+			break;
+		try_to_freeze();
+
+		dprintk(DBGLVL_THR, "thread running\n");
+
+		/* Dump the firmware debug message to console */
+		/* Polling this costs us 1-2% of the arm CPU */
+		/* convert this into a respnde to interrupt 0x7a */
+		saa7164_api_collect_debug(dev);
+
+		/* Monitor CPU load every 1 second */
+		if ((last_poll_time + 1000 /* ms */) < jiffies_to_msecs(jiffies)) {
+			saa7164_api_get_load_info(dev, &fwinfo);
+			last_poll_time = jiffies_to_msecs(jiffies);
+		}
+
+	}
+
+	dprintk(DBGLVL_THR, "thread exiting\n");
+	return 0;
+}
+
+static int __devinit saa7164_initdev(struct pci_dev *pci_dev,
+				     const struct pci_device_id *pci_id)
+{
+	struct saa7164_dev *dev;
+	int err, i;
+	u32 version;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (NULL == dev)
+		return -ENOMEM;
+
+	/* pci init */
+	dev->pci = pci_dev;
+	if (pci_enable_device(pci_dev)) {
+		err = -EIO;
+		goto fail_free;
+	}
+
+	if (saa7164_dev_setup(dev) < 0) {
+		err = -EINVAL;
+		goto fail_free;
+	}
+
+	/* print pci info */
+	dev->pci_rev = pci_dev->revision;
+	pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
+	printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
+	       "latency: %d, mmio: 0x%llx\n", dev->name,
+	       pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
+	       dev->pci_lat,
+		(unsigned long long)pci_resource_start(pci_dev, 0));
+
+	pci_set_master(pci_dev);
+	/* TODO */
+	if (!pci_dma_supported(pci_dev, 0xffffffff)) {
+		printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
+		err = -EIO;
+		goto fail_irq;
+	}
+
+	err = request_irq(pci_dev->irq, saa7164_irq,
+		IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+	if (err < 0) {
+		printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name,
+			pci_dev->irq);
+		err = -EIO;
+		goto fail_irq;
+	}
+
+	pci_set_drvdata(pci_dev, dev);
+
+	/* Init the internal command list */
+	for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) {
+		dev->cmds[i].seqno = i;
+		dev->cmds[i].inuse = 0;
+		mutex_init(&dev->cmds[i].lock);
+		init_waitqueue_head(&dev->cmds[i].wait);
+	}
+
+	/* We need a deferred interrupt handler for cmd handling */
+	INIT_WORK(&dev->workcmd, saa7164_work_cmdhandler);
+
+	/* Only load the firmware if we know the board */
+	if (dev->board != SAA7164_BOARD_UNKNOWN) {
+
+		err = saa7164_downloadfirmware(dev);
+		if (err < 0) {
+			printk(KERN_ERR
+				"Failed to boot firmware, no features "
+				"registered\n");
+			goto fail_fw;
+		}
+
+		saa7164_get_descriptors(dev);
+		saa7164_dumpregs(dev, 0);
+		saa7164_getcurrentfirmwareversion(dev);
+		saa7164_getfirmwarestatus(dev);
+		err = saa7164_bus_setup(dev);
+		if (err < 0)
+			printk(KERN_ERR
+				"Failed to setup the bus, will continue\n");
+		saa7164_bus_dump(dev);
+
+		/* Ping the running firmware via the command bus and get the
+		 * firmware version, this checks the bus is running OK.
+		 */
+		version = 0;
+		if (saa7164_api_get_fw_version(dev, &version) == SAA_OK)
+			dprintk(1, "Bus is operating correctly using "
+				"version %d.%d.%d.%d (0x%x)\n",
+				(version & 0x0000fc00) >> 10,
+				(version & 0x000003e0) >> 5,
+				(version & 0x0000001f),
+				(version & 0xffff0000) >> 16,
+				version);
+		else
+			printk(KERN_ERR
+				"Failed to communicate with the firmware\n");
+
+		/* Bring up the I2C buses */
+		saa7164_i2c_register(&dev->i2c_bus[0]);
+		saa7164_i2c_register(&dev->i2c_bus[1]);
+		saa7164_i2c_register(&dev->i2c_bus[2]);
+		saa7164_gpio_setup(dev);
+		saa7164_card_setup(dev);
+
+		/* Parse the dynamic device configuration, find various
+		 * media endpoints (MPEG, WMV, PS, TS) and cache their
+		 * configuration details into the driver, so we can
+		 * reference them later during simething_register() func,
+		 * interrupt handlers, deferred work handlers etc.
+		 */
+		saa7164_api_enum_subdevs(dev);
+
+		/* Begin to create the video sub-systems and register funcs */
+		if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB) {
+			if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS1]) < 0) {
+				printk(KERN_ERR "%s() Failed to register "
+					"dvb adapters on porta\n",
+					__func__);
+			}
+		}
+
+		if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB) {
+			if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS2]) < 0) {
+				printk(KERN_ERR"%s() Failed to register "
+					"dvb adapters on portb\n",
+					__func__);
+			}
+		}
+
+		if (saa7164_boards[dev->board].portc == SAA7164_MPEG_ENCODER) {
+			if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC1]) < 0) {
+				printk(KERN_ERR"%s() Failed to register "
+					"mpeg encoder\n", __func__);
+			}
+		}
+
+		if (saa7164_boards[dev->board].portd == SAA7164_MPEG_ENCODER) {
+			if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC2]) < 0) {
+				printk(KERN_ERR"%s() Failed to register "
+					"mpeg encoder\n", __func__);
+			}
+		}
+
+		if (saa7164_boards[dev->board].porte == SAA7164_MPEG_VBI) {
+			if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI1]) < 0) {
+				printk(KERN_ERR"%s() Failed to register "
+					"vbi device\n", __func__);
+			}
+		}
+
+		if (saa7164_boards[dev->board].portf == SAA7164_MPEG_VBI) {
+			if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI2]) < 0) {
+				printk(KERN_ERR"%s() Failed to register "
+					"vbi device\n", __func__);
+			}
+		}
+		saa7164_api_set_debug(dev, fw_debug);
+
+		if (fw_debug) {
+			dev->kthread = kthread_run(saa7164_thread_function, dev,
+				"saa7164 debug");
+			if (!dev->kthread)
+				printk(KERN_ERR "%s() Failed to create "
+					"debug kernel thread\n", __func__);
+		}
+
+	} /* != BOARD_UNKNOWN */
+	else
+		printk(KERN_ERR "%s() Unsupported board detected, "
+			"registering without firmware\n", __func__);
+
+	dprintk(1, "%s() parameter debug = %d\n", __func__, saa_debug);
+	dprintk(1, "%s() parameter waitsecs = %d\n", __func__, waitsecs);
+
+fail_fw:
+	return 0;
+
+fail_irq:
+	saa7164_dev_unregister(dev);
+fail_free:
+	kfree(dev);
+	return err;
+}
+
+static void saa7164_shutdown(struct saa7164_dev *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+}
+
+static void __devexit saa7164_finidev(struct pci_dev *pci_dev)
+{
+	struct saa7164_dev *dev = pci_get_drvdata(pci_dev);
+
+	if (dev->board != SAA7164_BOARD_UNKNOWN) {
+		if (fw_debug && dev->kthread) {
+			kthread_stop(dev->kthread);
+			dev->kthread = NULL;
+		}
+		if (dev->firmwareloaded)
+			saa7164_api_set_debug(dev, 0x00);
+	}
+
+	saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+		&dev->ports[SAA7164_PORT_ENC1].irq_interval);
+	saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+		&dev->ports[SAA7164_PORT_ENC1].svc_interval);
+	saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+		&dev->ports[SAA7164_PORT_ENC1].irq_svc_interval);
+	saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+		&dev->ports[SAA7164_PORT_ENC1].read_interval);
+	saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+		&dev->ports[SAA7164_PORT_ENC1].poll_interval);
+	saa7164_histogram_print(&dev->ports[SAA7164_PORT_VBI1],
+		&dev->ports[SAA7164_PORT_VBI1].read_interval);
+	saa7164_histogram_print(&dev->ports[SAA7164_PORT_VBI2],
+		&dev->ports[SAA7164_PORT_VBI2].poll_interval);
+
+	saa7164_shutdown(dev);
+
+	if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB)
+		saa7164_dvb_unregister(&dev->ports[SAA7164_PORT_TS1]);
+
+	if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB)
+		saa7164_dvb_unregister(&dev->ports[SAA7164_PORT_TS2]);
+
+	if (saa7164_boards[dev->board].portc == SAA7164_MPEG_ENCODER)
+		saa7164_encoder_unregister(&dev->ports[SAA7164_PORT_ENC1]);
+
+	if (saa7164_boards[dev->board].portd == SAA7164_MPEG_ENCODER)
+		saa7164_encoder_unregister(&dev->ports[SAA7164_PORT_ENC2]);
+
+	if (saa7164_boards[dev->board].porte == SAA7164_MPEG_VBI)
+		saa7164_vbi_unregister(&dev->ports[SAA7164_PORT_VBI1]);
+
+	if (saa7164_boards[dev->board].portf == SAA7164_MPEG_VBI)
+		saa7164_vbi_unregister(&dev->ports[SAA7164_PORT_VBI2]);
+
+	saa7164_i2c_unregister(&dev->i2c_bus[0]);
+	saa7164_i2c_unregister(&dev->i2c_bus[1]);
+	saa7164_i2c_unregister(&dev->i2c_bus[2]);
+
+	pci_disable_device(pci_dev);
+
+	/* unregister stuff */
+	free_irq(pci_dev->irq, dev);
+	pci_set_drvdata(pci_dev, NULL);
+
+	mutex_lock(&devlist);
+	list_del(&dev->devlist);
+	mutex_unlock(&devlist);
+
+	saa7164_dev_unregister(dev);
+	kfree(dev);
+}
+
+static struct pci_device_id saa7164_pci_tbl[] = {
+	{
+		/* SAA7164 */
+		.vendor       = 0x1131,
+		.device       = 0x7164,
+		.subvendor    = PCI_ANY_ID,
+		.subdevice    = PCI_ANY_ID,
+	}, {
+		/* --- end of list --- */
+	}
+};
+MODULE_DEVICE_TABLE(pci, saa7164_pci_tbl);
+
+static struct pci_driver saa7164_pci_driver = {
+	.name     = "saa7164",
+	.id_table = saa7164_pci_tbl,
+	.probe    = saa7164_initdev,
+	.remove   = __devexit_p(saa7164_finidev),
+	/* TODO */
+	.suspend  = NULL,
+	.resume   = NULL,
+};
+
+static int __init saa7164_init(void)
+{
+	printk(KERN_INFO "saa7164 driver loaded\n");
+
+#ifdef CONFIG_PROC_FS
+	saa7164_proc_create();
+#endif
+	return pci_register_driver(&saa7164_pci_driver);
+}
+
+static void __exit saa7164_fini(void)
+{
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("saa7164", NULL);
+#endif
+	pci_unregister_driver(&saa7164_pci_driver);
+}
+
+module_init(saa7164_init);
+module_exit(saa7164_fini);
+
diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c b/drivers/media/pci/saa7164/saa7164-dvb.c
new file mode 100644
index 0000000..5c5cc3e
--- /dev/null
+++ b/drivers/media/pci/saa7164/saa7164-dvb.c
@@ -0,0 +1,556 @@
+/*
+ *  Driver for the NXP SAA7164 PCIe bridge
+ *
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "saa7164.h"
+
+#include "tda10048.h"
+#include "tda18271.h"
+#include "s5h1411.h"
+
+#define DRIVER_NAME "saa7164"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* addr is in the card struct, get it from there */
+static struct tda10048_config hauppauge_hvr2200_1_config = {
+	.demod_address    = 0x10 >> 1,
+	.output_mode      = TDA10048_SERIAL_OUTPUT,
+	.fwbulkwritelen   = TDA10048_BULKWRITE_200,
+	.inversion        = TDA10048_INVERSION_ON,
+	.dtv6_if_freq_khz = TDA10048_IF_3300,
+	.dtv7_if_freq_khz = TDA10048_IF_3500,
+	.dtv8_if_freq_khz = TDA10048_IF_4000,
+	.clk_freq_khz     = TDA10048_CLK_16000,
+};
+static struct tda10048_config hauppauge_hvr2200_2_config = {
+	.demod_address    = 0x12 >> 1,
+	.output_mode      = TDA10048_SERIAL_OUTPUT,
+	.fwbulkwritelen   = TDA10048_BULKWRITE_200,
+	.inversion        = TDA10048_INVERSION_ON,
+	.dtv6_if_freq_khz = TDA10048_IF_3300,
+	.dtv7_if_freq_khz = TDA10048_IF_3500,
+	.dtv8_if_freq_khz = TDA10048_IF_4000,
+	.clk_freq_khz     = TDA10048_CLK_16000,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+	.atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 3,
+		      .if_lvl = 6, .rfagc_top = 0x37 },
+	.qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 0,
+		      .if_lvl = 6, .rfagc_top = 0x37 },
+};
+
+static struct tda18271_config hauppauge_hvr22x0_tuner_config = {
+	.std_map	= &hauppauge_tda18271_std_map,
+	.gate		= TDA18271_GATE_ANALOG,
+	.role		= TDA18271_MASTER,
+};
+
+static struct tda18271_config hauppauge_hvr22x0s_tuner_config = {
+	.std_map	= &hauppauge_tda18271_std_map,
+	.gate		= TDA18271_GATE_ANALOG,
+	.role		= TDA18271_SLAVE,
+	.output_opt     = TDA18271_OUTPUT_LT_OFF,
+	.rf_cal_on_startup = 1
+};
+
+static struct s5h1411_config hauppauge_s5h1411_config = {
+	.output_mode   = S5H1411_SERIAL_OUTPUT,
+	.gpio          = S5H1411_GPIO_ON,
+	.qam_if        = S5H1411_IF_4000,
+	.vsb_if        = S5H1411_IF_3250,
+	.inversion     = S5H1411_INVERSION_ON,
+	.status_mode   = S5H1411_DEMODLOCKING,
+	.mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static int saa7164_dvb_stop_port(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	int ret;
+
+	ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n",
+			__func__, ret);
+		ret = -EIO;
+	} else {
+		dprintk(DBGLVL_DVB, "%s()    Stopped\n", __func__);
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static int saa7164_dvb_acquire_port(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	int ret;
+
+	ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
+	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n",
+			__func__, ret);
+		ret = -EIO;
+	} else {
+		dprintk(DBGLVL_DVB, "%s() Acquired\n", __func__);
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static int saa7164_dvb_pause_port(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	int ret;
+
+	ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
+	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n",
+			__func__, ret);
+		ret = -EIO;
+	} else {
+		dprintk(DBGLVL_DVB, "%s()   Paused\n", __func__);
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/* Firmware is very windows centric, meaning you have to transition
+ * the part through AVStream / KS Windows stages, forwards or backwards.
+ * States are: stopped, acquired (h/w), paused, started.
+ */
+static int saa7164_dvb_stop_streaming(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	struct saa7164_buffer *buf;
+	struct list_head *p, *q;
+	int ret;
+
+	dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
+
+	ret = saa7164_dvb_pause_port(port);
+	ret = saa7164_dvb_acquire_port(port);
+	ret = saa7164_dvb_stop_port(port);
+
+	/* Mark the hardware buffers as free */
+	mutex_lock(&port->dmaqueue_lock);
+	list_for_each_safe(p, q, &port->dmaqueue.list) {
+		buf = list_entry(p, struct saa7164_buffer, list);
+		buf->flags = SAA7164_BUFFER_FREE;
+	}
+	mutex_unlock(&port->dmaqueue_lock);
+
+	return ret;
+}
+
+static int saa7164_dvb_start_port(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	int ret = 0, result;
+
+	dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
+
+	saa7164_buffer_cfg_port(port);
+
+	/* Acquire the hardware */
+	result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
+	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n",
+			__func__, result);
+
+		/* Stop the hardware, regardless */
+		result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+		if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+			printk(KERN_ERR "%s() acquire/forced stop transition "
+				"failed, res = 0x%x\n", __func__, result);
+		}
+		ret = -EIO;
+		goto out;
+	} else
+		dprintk(DBGLVL_DVB, "%s()   Acquired\n", __func__);
+
+	/* Pause the hardware */
+	result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
+	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n",
+				__func__, result);
+
+		/* Stop the hardware, regardless */
+		result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+		if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+			printk(KERN_ERR "%s() pause/forced stop transition "
+				"failed, res = 0x%x\n", __func__, result);
+		}
+
+		ret = -EIO;
+		goto out;
+	} else
+		dprintk(DBGLVL_DVB, "%s()   Paused\n", __func__);
+
+	/* Start the hardware */
+	result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN);
+	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() run transition failed, result = 0x%x\n",
+				__func__, result);
+
+		/* Stop the hardware, regardless */
+		result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+		if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+			printk(KERN_ERR "%s() run/forced stop transition "
+				"failed, res = 0x%x\n", __func__, result);
+		}
+
+		ret = -EIO;
+	} else
+		dprintk(DBGLVL_DVB, "%s()   Running\n", __func__);
+
+out:
+	return ret;
+}
+
+static int saa7164_dvb_start_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct saa7164_port *port = (struct saa7164_port *) demux->priv;
+	struct saa7164_dvb *dvb = &port->dvb;
+	struct saa7164_dev *dev = port->dev;
+	int ret = 0;
+
+	dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
+
+	if (!demux->dmx.frontend)
+		return -EINVAL;
+
+	if (dvb) {
+		mutex_lock(&dvb->lock);
+		if (dvb->feeding++ == 0) {
+			/* Start transport */
+			ret = saa7164_dvb_start_port(port);
+		}
+		mutex_unlock(&dvb->lock);
+		dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n",
+			__func__, port->nr, dvb->feeding);
+	}
+
+	return ret;
+}
+
+static int saa7164_dvb_stop_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct saa7164_port *port = (struct saa7164_port *) demux->priv;
+	struct saa7164_dvb *dvb = &port->dvb;
+	struct saa7164_dev *dev = port->dev;
+	int ret = 0;
+
+	dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
+
+	if (dvb) {
+		mutex_lock(&dvb->lock);
+		if (--dvb->feeding == 0) {
+			/* Stop transport */
+			ret = saa7164_dvb_stop_streaming(port);
+		}
+		mutex_unlock(&dvb->lock);
+		dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n",
+			__func__, port->nr, dvb->feeding);
+	}
+
+	return ret;
+}
+
+static int dvb_register(struct saa7164_port *port)
+{
+	struct saa7164_dvb *dvb = &port->dvb;
+	struct saa7164_dev *dev = port->dev;
+	struct saa7164_buffer *buf;
+	int result, i;
+
+	dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
+
+	if (port->type != SAA7164_MPEG_DVB)
+		BUG();
+
+	/* Sanity check that the PCI configuration space is active */
+	if (port->hwcfg.BARLocation == 0) {
+		result = -ENOMEM;
+		printk(KERN_ERR "%s: dvb_register_adapter failed "
+		       "(errno = %d), NO PCI configuration\n",
+			DRIVER_NAME, result);
+		goto fail_adapter;
+	}
+
+	/* Init and establish defaults */
+	port->hw_streamingparams.bitspersample = 8;
+	port->hw_streamingparams.samplesperline = 188;
+	port->hw_streamingparams.numberoflines =
+		(SAA7164_TS_NUMBER_OF_LINES * 188) / 188;
+
+	port->hw_streamingparams.pitch = 188;
+	port->hw_streamingparams.linethreshold = 0;
+	port->hw_streamingparams.pagetablelistvirt = NULL;
+	port->hw_streamingparams.pagetablelistphys = NULL;
+	port->hw_streamingparams.numpagetables = 2 +
+		((SAA7164_TS_NUMBER_OF_LINES * 188) / PAGE_SIZE);
+
+	port->hw_streamingparams.numpagetableentries = port->hwcfg.buffercount;
+
+	/* Allocate the PCI resources */
+	for (i = 0; i < port->hwcfg.buffercount; i++) {
+		buf = saa7164_buffer_alloc(port,
+			port->hw_streamingparams.numberoflines *
+			port->hw_streamingparams.pitch);
+
+		if (!buf) {
+			result = -ENOMEM;
+			printk(KERN_ERR "%s: dvb_register_adapter failed "
+			       "(errno = %d), unable to allocate buffers\n",
+				DRIVER_NAME, result);
+			goto fail_adapter;
+		}
+
+		mutex_lock(&port->dmaqueue_lock);
+		list_add_tail(&buf->list, &port->dmaqueue.list);
+		mutex_unlock(&port->dmaqueue_lock);
+	}
+
+	/* register adapter */
+	result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE,
+			&dev->pci->dev, adapter_nr);
+	if (result < 0) {
+		printk(KERN_ERR "%s: dvb_register_adapter failed "
+		       "(errno = %d)\n", DRIVER_NAME, result);
+		goto fail_adapter;
+	}
+	dvb->adapter.priv = port;
+
+	/* register frontend */
+	result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+	if (result < 0) {
+		printk(KERN_ERR "%s: dvb_register_frontend failed "
+		       "(errno = %d)\n", DRIVER_NAME, result);
+		goto fail_frontend;
+	}
+
+	/* register demux stuff */
+	dvb->demux.dmx.capabilities =
+		DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+		DMX_MEMORY_BASED_FILTERING;
+	dvb->demux.priv       = port;
+	dvb->demux.filternum  = 256;
+	dvb->demux.feednum    = 256;
+	dvb->demux.start_feed = saa7164_dvb_start_feed;
+	dvb->demux.stop_feed  = saa7164_dvb_stop_feed;
+	result = dvb_dmx_init(&dvb->demux);
+	if (result < 0) {
+		printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n",
+		       DRIVER_NAME, result);
+		goto fail_dmx;
+	}
+
+	dvb->dmxdev.filternum    = 256;
+	dvb->dmxdev.demux        = &dvb->demux.dmx;
+	dvb->dmxdev.capabilities = 0;
+	result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+	if (result < 0) {
+		printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n",
+		       DRIVER_NAME, result);
+		goto fail_dmxdev;
+	}
+
+	dvb->fe_hw.source = DMX_FRONTEND_0;
+	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	if (result < 0) {
+		printk(KERN_ERR "%s: add_frontend failed "
+		       "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result);
+		goto fail_fe_hw;
+	}
+
+	dvb->fe_mem.source = DMX_MEMORY_FE;
+	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+	if (result < 0) {
+		printk(KERN_ERR "%s: add_frontend failed "
+		       "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result);
+		goto fail_fe_mem;
+	}
+
+	result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	if (result < 0) {
+		printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n",
+		       DRIVER_NAME, result);
+		goto fail_fe_conn;
+	}
+
+	/* register network adapter */
+	dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+	return 0;
+
+fail_fe_conn:
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+fail_fe_mem:
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+fail_fe_hw:
+	dvb_dmxdev_release(&dvb->dmxdev);
+fail_dmxdev:
+	dvb_dmx_release(&dvb->demux);
+fail_dmx:
+	dvb_unregister_frontend(dvb->frontend);
+fail_frontend:
+	dvb_frontend_detach(dvb->frontend);
+	dvb_unregister_adapter(&dvb->adapter);
+fail_adapter:
+	return result;
+}
+
+int saa7164_dvb_unregister(struct saa7164_port *port)
+{
+	struct saa7164_dvb *dvb = &port->dvb;
+	struct saa7164_dev *dev = port->dev;
+	struct saa7164_buffer *b;
+	struct list_head *c, *n;
+
+	dprintk(DBGLVL_DVB, "%s()\n", __func__);
+
+	if (port->type != SAA7164_MPEG_DVB)
+		BUG();
+
+	/* Remove any allocated buffers */
+	mutex_lock(&port->dmaqueue_lock);
+	list_for_each_safe(c, n, &port->dmaqueue.list) {
+		b = list_entry(c, struct saa7164_buffer, list);
+		list_del(c);
+		saa7164_buffer_dealloc(b);
+	}
+	mutex_unlock(&port->dmaqueue_lock);
+
+	if (dvb->frontend == NULL)
+		return 0;
+
+	dvb_net_release(&dvb->net);
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	dvb_dmxdev_release(&dvb->dmxdev);
+	dvb_dmx_release(&dvb->demux);
+	dvb_unregister_frontend(dvb->frontend);
+	dvb_frontend_detach(dvb->frontend);
+	dvb_unregister_adapter(&dvb->adapter);
+	return 0;
+}
+
+/* All the DVB attach calls go here, this function get's modified
+ * for each new card.
+ */
+int saa7164_dvb_register(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	struct saa7164_dvb *dvb = &port->dvb;
+	struct saa7164_i2c *i2c_bus = NULL;
+	int ret;
+
+	dprintk(DBGLVL_DVB, "%s()\n", __func__);
+
+	/* init frontend */
+	switch (dev->board) {
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200_2:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200_3:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200_4:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2200_5:
+		i2c_bus = &dev->i2c_bus[port->nr + 1];
+		switch (port->nr) {
+		case 0:
+			port->dvb.frontend = dvb_attach(tda10048_attach,
+				&hauppauge_hvr2200_1_config,
+				&i2c_bus->i2c_adap);
+
+			if (port->dvb.frontend != NULL) {
+				/* TODO: addr is in the card struct */
+				dvb_attach(tda18271_attach, port->dvb.frontend,
+					0xc0 >> 1, &i2c_bus->i2c_adap,
+					&hauppauge_hvr22x0_tuner_config);
+			}
+
+			break;
+		case 1:
+			port->dvb.frontend = dvb_attach(tda10048_attach,
+				&hauppauge_hvr2200_2_config,
+				&i2c_bus->i2c_adap);
+
+			if (port->dvb.frontend != NULL) {
+				/* TODO: addr is in the card struct */
+				dvb_attach(tda18271_attach, port->dvb.frontend,
+					0xc0 >> 1, &i2c_bus->i2c_adap,
+					&hauppauge_hvr22x0s_tuner_config);
+			}
+
+			break;
+		}
+		break;
+	case SAA7164_BOARD_HAUPPAUGE_HVR2250:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2250_2:
+	case SAA7164_BOARD_HAUPPAUGE_HVR2250_3:
+		i2c_bus = &dev->i2c_bus[port->nr + 1];
+
+		port->dvb.frontend = dvb_attach(s5h1411_attach,
+			&hauppauge_s5h1411_config,
+			&i2c_bus->i2c_adap);
+
+		if (port->dvb.frontend != NULL) {
+			if (port->nr == 0) {
+				/* Master TDA18271 */
+				/* TODO: addr is in the card struct */
+				dvb_attach(tda18271_attach, port->dvb.frontend,
+					0xc0 >> 1, &i2c_bus->i2c_adap,
+					&hauppauge_hvr22x0_tuner_config);
+			} else {
+				/* Slave TDA18271 */
+				dvb_attach(tda18271_attach, port->dvb.frontend,
+					0xc0 >> 1, &i2c_bus->i2c_adap,
+					&hauppauge_hvr22x0s_tuner_config);
+			}
+		}
+
+		break;
+	default:
+		printk(KERN_ERR "%s: The frontend isn't supported\n",
+		       dev->name);
+		break;
+	}
+	if (NULL == dvb->frontend) {
+		printk(KERN_ERR "%s() Frontend initialization failed\n",
+		       __func__);
+		return -1;
+	}
+
+	/* register everything */
+	ret = dvb_register(port);
+	if (ret < 0) {
+		if (dvb->frontend->ops.release)
+			dvb->frontend->ops.release(dvb->frontend);
+		return ret;
+	}
+
+	return 0;
+}
+
diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c
new file mode 100644
index 0000000..a9ed686
--- /dev/null
+++ b/drivers/media/pci/saa7164/saa7164-encoder.c
@@ -0,0 +1,1500 @@
+/*
+ *  Driver for the NXP SAA7164 PCIe bridge
+ *
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "saa7164.h"
+
+#define ENCODER_MAX_BITRATE 6500000
+#define ENCODER_MIN_BITRATE 1000000
+#define ENCODER_DEF_BITRATE 5000000
+
+static struct saa7164_tvnorm saa7164_tvnorms[] = {
+	{
+		.name      = "NTSC-M",
+		.id        = V4L2_STD_NTSC_M,
+	}, {
+		.name      = "NTSC-JP",
+		.id        = V4L2_STD_NTSC_M_JP,
+	}
+};
+
+static const u32 saa7164_v4l2_ctrls[] = {
+	V4L2_CID_BRIGHTNESS,
+	V4L2_CID_CONTRAST,
+	V4L2_CID_SATURATION,
+	V4L2_CID_HUE,
+	V4L2_CID_AUDIO_VOLUME,
+	V4L2_CID_SHARPNESS,
+	V4L2_CID_MPEG_STREAM_TYPE,
+	V4L2_CID_MPEG_VIDEO_ASPECT,
+	V4L2_CID_MPEG_VIDEO_B_FRAMES,
+	V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+	V4L2_CID_MPEG_AUDIO_MUTE,
+	V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+	V4L2_CID_MPEG_VIDEO_BITRATE,
+	V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+	0
+};
+
+/* Take the encoder configuration form the port struct and
+ * flush it to the hardware.
+ */
+static void saa7164_encoder_configure(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+	port->encoder_params.width = port->width;
+	port->encoder_params.height = port->height;
+	port->encoder_params.is_50hz =
+		(port->encodernorm.id & V4L2_STD_625_50) != 0;
+
+	/* Set up the DIF (enable it) for analog mode by default */
+	saa7164_api_initialize_dif(port);
+
+	/* Configure the correct video standard */
+	saa7164_api_configure_dif(port, port->encodernorm.id);
+
+	/* Ensure the audio decoder is correct configured */
+	saa7164_api_set_audio_std(port);
+}
+
+static int saa7164_encoder_buffers_dealloc(struct saa7164_port *port)
+{
+	struct list_head *c, *n, *p, *q, *l, *v;
+	struct saa7164_dev *dev = port->dev;
+	struct saa7164_buffer *buf;
+	struct saa7164_user_buffer *ubuf;
+
+	/* Remove any allocated buffers */
+	mutex_lock(&port->dmaqueue_lock);
+
+	dprintk(DBGLVL_ENC, "%s(port=%d) dmaqueue\n", __func__, port->nr);
+	list_for_each_safe(c, n, &port->dmaqueue.list) {
+		buf = list_entry(c, struct saa7164_buffer, list);
+		list_del(c);
+		saa7164_buffer_dealloc(buf);
+	}
+
+	dprintk(DBGLVL_ENC, "%s(port=%d) used\n", __func__, port->nr);
+	list_for_each_safe(p, q, &port->list_buf_used.list) {
+		ubuf = list_entry(p, struct saa7164_user_buffer, list);
+		list_del(p);
+		saa7164_buffer_dealloc_user(ubuf);
+	}
+
+	dprintk(DBGLVL_ENC, "%s(port=%d) free\n", __func__, port->nr);
+	list_for_each_safe(l, v, &port->list_buf_free.list) {
+		ubuf = list_entry(l, struct saa7164_user_buffer, list);
+		list_del(l);
+		saa7164_buffer_dealloc_user(ubuf);
+	}
+
+	mutex_unlock(&port->dmaqueue_lock);
+	dprintk(DBGLVL_ENC, "%s(port=%d) done\n", __func__, port->nr);
+
+	return 0;
+}
+
+/* Dynamic buffer switch at encoder start time */
+static int saa7164_encoder_buffers_alloc(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	struct saa7164_buffer *buf;
+	struct saa7164_user_buffer *ubuf;
+	struct tmHWStreamParameters *params = &port->hw_streamingparams;
+	int result = -ENODEV, i;
+	int len = 0;
+
+	dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+	if (port->encoder_params.stream_type ==
+		V4L2_MPEG_STREAM_TYPE_MPEG2_PS) {
+		dprintk(DBGLVL_ENC,
+			"%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_PS\n",
+			__func__);
+		params->samplesperline = 128;
+		params->numberoflines = 256;
+		params->pitch = 128;
+		params->numpagetables = 2 +
+			((SAA7164_PS_NUMBER_OF_LINES * 128) / PAGE_SIZE);
+	} else
+	if (port->encoder_params.stream_type ==
+		V4L2_MPEG_STREAM_TYPE_MPEG2_TS) {
+		dprintk(DBGLVL_ENC,
+			"%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_TS\n",
+			__func__);
+		params->samplesperline = 188;
+		params->numberoflines = 312;
+		params->pitch = 188;
+		params->numpagetables = 2 +
+			((SAA7164_TS_NUMBER_OF_LINES * 188) / PAGE_SIZE);
+	} else
+		BUG();
+
+	/* Init and establish defaults */
+	params->bitspersample = 8;
+	params->linethreshold = 0;
+	params->pagetablelistvirt = NULL;
+	params->pagetablelistphys = NULL;
+	params->numpagetableentries = port->hwcfg.buffercount;
+
+	/* Allocate the PCI resources, buffers (hard) */
+	for (i = 0; i < port->hwcfg.buffercount; i++) {
+		buf = saa7164_buffer_alloc(port,
+			params->numberoflines *
+			params->pitch);
+
+		if (!buf) {
+			printk(KERN_ERR "%s() failed "
+			       "(errno = %d), unable to allocate buffer\n",
+				__func__, result);
+			result = -ENOMEM;
+			goto failed;
+		} else {
+
+			mutex_lock(&port->dmaqueue_lock);
+			list_add_tail(&buf->list, &port->dmaqueue.list);
+			mutex_unlock(&port->dmaqueue_lock);
+
+		}
+	}
+
+	/* Allocate some kernel buffers for copying
+	 * to userpsace.
+	 */
+	len = params->numberoflines * params->pitch;
+
+	if (encoder_buffers < 16)
+		encoder_buffers = 16;
+	if (encoder_buffers > 512)
+		encoder_buffers = 512;
+
+	for (i = 0; i < encoder_buffers; i++) {
+
+		ubuf = saa7164_buffer_alloc_user(dev, len);
+		if (ubuf) {
+			mutex_lock(&port->dmaqueue_lock);
+			list_add_tail(&ubuf->list, &port->list_buf_free.list);
+			mutex_unlock(&port->dmaqueue_lock);
+		}
+
+	}
+
+	result = 0;
+
+failed:
+	return result;
+}
+
+static int saa7164_encoder_initialize(struct saa7164_port *port)
+{
+	saa7164_encoder_configure(port);
+	return 0;
+}
+
+/* -- V4L2 --------------------------------------------------------- */
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct saa7164_encoder_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+	unsigned int i;
+
+	dprintk(DBGLVL_ENC, "%s(id=0x%x)\n", __func__, (u32)*id);
+
+	for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) {
+		if (*id & saa7164_tvnorms[i].id)
+			break;
+	}
+	if (i == ARRAY_SIZE(saa7164_tvnorms))
+		return -EINVAL;
+
+	port->encodernorm = saa7164_tvnorms[i];
+
+	/* Update the audio decoder while is not running in
+	 * auto detect mode.
+	 */
+	saa7164_api_set_audio_std(port);
+
+	dprintk(DBGLVL_ENC, "%s(id=0x%x) OK\n", __func__, (u32)*id);
+
+	return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+	struct v4l2_input *i)
+{
+	int n;
+
+	char *inputs[] = { "tuner", "composite", "svideo", "aux",
+		"composite 2", "svideo 2", "aux 2" };
+
+	if (i->index >= 7)
+		return -EINVAL;
+
+	strcpy(i->name, inputs[i->index]);
+
+	if (i->index == 0)
+		i->type = V4L2_INPUT_TYPE_TUNER;
+	else
+		i->type  = V4L2_INPUT_TYPE_CAMERA;
+
+	for (n = 0; n < ARRAY_SIZE(saa7164_tvnorms); n++)
+		i->std |= saa7164_tvnorms[n].id;
+
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct saa7164_encoder_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	if (saa7164_api_get_videomux(port) != SAA_OK)
+		return -EIO;
+
+	*i = (port->mux_input - 1);
+
+	dprintk(DBGLVL_ENC, "%s() input=%d\n", __func__, *i);
+
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct saa7164_encoder_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	dprintk(DBGLVL_ENC, "%s() input=%d\n", __func__, i);
+
+	if (i >= 7)
+		return -EINVAL;
+
+	port->mux_input = i + 1;
+
+	if (saa7164_api_set_videomux(port) != SAA_OK)
+		return -EIO;
+
+	return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+	struct v4l2_tuner *t)
+{
+	struct saa7164_encoder_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	if (0 != t->index)
+		return -EINVAL;
+
+	strcpy(t->name, "tuner");
+	t->type = V4L2_TUNER_ANALOG_TV;
+	t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO;
+
+	dprintk(DBGLVL_ENC, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
+
+	return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+	struct v4l2_tuner *t)
+{
+	/* Update the A/V core */
+	return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+	struct v4l2_frequency *f)
+{
+	struct saa7164_encoder_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+
+	f->type = V4L2_TUNER_ANALOG_TV;
+	f->frequency = port->freq;
+
+	return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+	struct v4l2_frequency *f)
+{
+	struct saa7164_encoder_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+	struct saa7164_port *tsport;
+	struct dvb_frontend *fe;
+
+	/* TODO: Pull this for the std */
+	struct analog_parameters params = {
+		.mode      = V4L2_TUNER_ANALOG_TV,
+		.audmode   = V4L2_TUNER_MODE_STEREO,
+		.std       = port->encodernorm.id,
+		.frequency = f->frequency
+	};
+
+	/* Stop the encoder */
+	dprintk(DBGLVL_ENC, "%s() frequency=%d tuner=%d\n", __func__,
+		f->frequency, f->tuner);
+
+	if (f->tuner != 0)
+		return -EINVAL;
+
+	if (f->type != V4L2_TUNER_ANALOG_TV)
+		return -EINVAL;
+
+	port->freq = f->frequency;
+
+	/* Update the hardware */
+	if (port->nr == SAA7164_PORT_ENC1)
+		tsport = &dev->ports[SAA7164_PORT_TS1];
+	else
+	if (port->nr == SAA7164_PORT_ENC2)
+		tsport = &dev->ports[SAA7164_PORT_TS2];
+	else
+		BUG();
+
+	fe = tsport->dvb.frontend;
+
+	if (fe && fe->ops.tuner_ops.set_analog_params)
+		fe->ops.tuner_ops.set_analog_params(fe, &params);
+	else
+		printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__);
+
+	saa7164_encoder_initialize(port);
+
+	return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+	struct v4l2_control *ctl)
+{
+	struct saa7164_encoder_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	dprintk(DBGLVL_ENC, "%s(id=%d, value=%d)\n", __func__,
+		ctl->id, ctl->value);
+
+	switch (ctl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		ctl->value = port->ctl_brightness;
+		break;
+	case V4L2_CID_CONTRAST:
+		ctl->value = port->ctl_contrast;
+		break;
+	case V4L2_CID_SATURATION:
+		ctl->value = port->ctl_saturation;
+		break;
+	case V4L2_CID_HUE:
+		ctl->value = port->ctl_hue;
+		break;
+	case V4L2_CID_SHARPNESS:
+		ctl->value = port->ctl_sharpness;
+		break;
+	case V4L2_CID_AUDIO_VOLUME:
+		ctl->value = port->ctl_volume;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+	struct v4l2_control *ctl)
+{
+	struct saa7164_encoder_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+	int ret = 0;
+
+	dprintk(DBGLVL_ENC, "%s(id=%d, value=%d)\n", __func__,
+		ctl->id, ctl->value);
+
+	switch (ctl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		if ((ctl->value >= 0) && (ctl->value <= 255)) {
+			port->ctl_brightness = ctl->value;
+			saa7164_api_set_usercontrol(port,
+				PU_BRIGHTNESS_CONTROL);
+		} else
+			ret = -EINVAL;
+		break;
+	case V4L2_CID_CONTRAST:
+		if ((ctl->value >= 0) && (ctl->value <= 255)) {
+			port->ctl_contrast = ctl->value;
+			saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL);
+		} else
+			ret = -EINVAL;
+		break;
+	case V4L2_CID_SATURATION:
+		if ((ctl->value >= 0) && (ctl->value <= 255)) {
+			port->ctl_saturation = ctl->value;
+			saa7164_api_set_usercontrol(port,
+				PU_SATURATION_CONTROL);
+		} else
+			ret = -EINVAL;
+		break;
+	case V4L2_CID_HUE:
+		if ((ctl->value >= 0) && (ctl->value <= 255)) {
+			port->ctl_hue = ctl->value;
+			saa7164_api_set_usercontrol(port, PU_HUE_CONTROL);
+		} else
+			ret = -EINVAL;
+		break;
+	case V4L2_CID_SHARPNESS:
+		if ((ctl->value >= 0) && (ctl->value <= 255)) {
+			port->ctl_sharpness = ctl->value;
+			saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL);
+		} else
+			ret = -EINVAL;
+		break;
+	case V4L2_CID_AUDIO_VOLUME:
+		if ((ctl->value >= -83) && (ctl->value <= 24)) {
+			port->ctl_volume = ctl->value;
+			saa7164_api_set_audio_volume(port, port->ctl_volume);
+		} else
+			ret = -EINVAL;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int saa7164_get_ctrl(struct saa7164_port *port,
+	struct v4l2_ext_control *ctrl)
+{
+	struct saa7164_encoder_params *params = &port->encoder_params;
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		ctrl->value = params->bitrate;
+		break;
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		ctrl->value = params->stream_type;
+		break;
+	case V4L2_CID_MPEG_AUDIO_MUTE:
+		ctrl->value = params->ctl_mute;
+		break;
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		ctrl->value = params->ctl_aspect;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		ctrl->value = params->bitrate_mode;
+		break;
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+		ctrl->value = params->refdist;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+		ctrl->value = params->bitrate_peak;
+		break;
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+		ctrl->value = params->gop_size;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+	struct v4l2_ext_controls *ctrls)
+{
+	struct saa7164_encoder_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	int i, err = 0;
+
+	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+		for (i = 0; i < ctrls->count; i++) {
+			struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+			err = saa7164_get_ctrl(port, ctrl);
+			if (err) {
+				ctrls->error_idx = i;
+				break;
+			}
+		}
+		return err;
+
+	}
+
+	return -EINVAL;
+}
+
+static int saa7164_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
+{
+	int ret = -EINVAL;
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		if ((ctrl->value >= ENCODER_MIN_BITRATE) &&
+			(ctrl->value <= ENCODER_MAX_BITRATE))
+			ret = 0;
+		break;
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		if ((ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) ||
+			(ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS))
+			ret = 0;
+		break;
+	case V4L2_CID_MPEG_AUDIO_MUTE:
+		if ((ctrl->value >= 0) &&
+			(ctrl->value <= 1))
+			ret = 0;
+		break;
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		if ((ctrl->value >= V4L2_MPEG_VIDEO_ASPECT_1x1) &&
+			(ctrl->value <= V4L2_MPEG_VIDEO_ASPECT_221x100))
+			ret = 0;
+		break;
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+		if ((ctrl->value >= 0) &&
+			(ctrl->value <= 255))
+			ret = 0;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		if ((ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) ||
+			(ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR))
+			ret = 0;
+		break;
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+		if ((ctrl->value >= 1) &&
+			(ctrl->value <= 3))
+			ret = 0;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+		if ((ctrl->value >= ENCODER_MIN_BITRATE) &&
+			(ctrl->value <= ENCODER_MAX_BITRATE))
+			ret = 0;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+	struct v4l2_ext_controls *ctrls)
+{
+	int i, err = 0;
+
+	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+		for (i = 0; i < ctrls->count; i++) {
+			struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+			err = saa7164_try_ctrl(ctrl, 0);
+			if (err) {
+				ctrls->error_idx = i;
+				break;
+			}
+		}
+		return err;
+	}
+
+	return -EINVAL;
+}
+
+static int saa7164_set_ctrl(struct saa7164_port *port,
+	struct v4l2_ext_control *ctrl)
+{
+	struct saa7164_encoder_params *params = &port->encoder_params;
+	int ret = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		params->bitrate = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		params->stream_type = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_AUDIO_MUTE:
+		params->ctl_mute = ctrl->value;
+		ret = saa7164_api_audio_mute(port, params->ctl_mute);
+		if (ret != SAA_OK) {
+			printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
+				ret);
+			ret = -EIO;
+		}
+		break;
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		params->ctl_aspect = ctrl->value;
+		ret = saa7164_api_set_aspect_ratio(port);
+		if (ret != SAA_OK) {
+			printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
+				ret);
+			ret = -EIO;
+		}
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		params->bitrate_mode = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+		params->refdist = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+		params->bitrate_peak = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+		params->gop_size = ctrl->value;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* TODO: Update the hardware */
+
+	return ret;
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+	struct v4l2_ext_controls *ctrls)
+{
+	struct saa7164_encoder_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	int i, err = 0;
+
+	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+		for (i = 0; i < ctrls->count; i++) {
+			struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+			err = saa7164_try_ctrl(ctrl, 0);
+			if (err) {
+				ctrls->error_idx = i;
+				break;
+			}
+			err = saa7164_set_ctrl(port, ctrl);
+			if (err) {
+				ctrls->error_idx = i;
+				break;
+			}
+		}
+		return err;
+
+	}
+
+	return -EINVAL;
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+	struct v4l2_capability *cap)
+{
+	struct saa7164_encoder_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	strcpy(cap->driver, dev->name);
+	strlcpy(cap->card, saa7164_boards[dev->board].name,
+		sizeof(cap->card));
+	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+
+	cap->capabilities =
+		V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_READWRITE     |
+		0;
+
+	cap->capabilities |= V4L2_CAP_TUNER;
+	cap->version = 0;
+
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+	struct v4l2_fmtdesc *f)
+{
+	if (f->index != 0)
+		return -EINVAL;
+
+	strlcpy(f->description, "MPEG", sizeof(f->description));
+	f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct saa7164_encoder_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage    =
+		port->ts_packet_size * port->ts_packet_count;
+	f->fmt.pix.colorspace   = 0;
+	f->fmt.pix.width        = port->width;
+	f->fmt.pix.height       = port->height;
+
+	dprintk(DBGLVL_ENC, "VIDIOC_G_FMT: w: %d, h: %d\n",
+		port->width, port->height);
+
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct saa7164_encoder_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage    =
+		port->ts_packet_size * port->ts_packet_count;
+	f->fmt.pix.colorspace   = 0;
+	dprintk(DBGLVL_ENC, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
+		port->width, port->height);
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct saa7164_encoder_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage    =
+		port->ts_packet_size * port->ts_packet_count;
+	f->fmt.pix.colorspace   = 0;
+
+	dprintk(DBGLVL_ENC, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+		f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+
+	return 0;
+}
+
+static int fill_queryctrl(struct saa7164_encoder_params *params,
+	struct v4l2_queryctrl *c)
+{
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 127);
+	case V4L2_CID_CONTRAST:
+		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 66);
+	case V4L2_CID_SATURATION:
+		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 62);
+	case V4L2_CID_HUE:
+		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 128);
+	case V4L2_CID_SHARPNESS:
+		return v4l2_ctrl_query_fill(c, 0x0, 0x0f, 1, 8);
+	case V4L2_CID_MPEG_AUDIO_MUTE:
+		return v4l2_ctrl_query_fill(c, 0x0, 0x01, 1, 0);
+	case V4L2_CID_AUDIO_VOLUME:
+		return v4l2_ctrl_query_fill(c, -83, 24, 1, 20);
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		return v4l2_ctrl_query_fill(c,
+			ENCODER_MIN_BITRATE, ENCODER_MAX_BITRATE,
+			100000, ENCODER_DEF_BITRATE);
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		return v4l2_ctrl_query_fill(c,
+			V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+			V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
+			1, V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		return v4l2_ctrl_query_fill(c,
+			V4L2_MPEG_VIDEO_ASPECT_1x1,
+			V4L2_MPEG_VIDEO_ASPECT_221x100,
+			1, V4L2_MPEG_VIDEO_ASPECT_4x3);
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+		return v4l2_ctrl_query_fill(c, 1, 255, 1, 15);
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		return v4l2_ctrl_query_fill(c,
+			V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+			V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+			1, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+		return v4l2_ctrl_query_fill(c,
+			1, 3, 1, 1);
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+		return v4l2_ctrl_query_fill(c,
+			ENCODER_MIN_BITRATE, ENCODER_MAX_BITRATE,
+			100000, ENCODER_DEF_BITRATE);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+	struct v4l2_queryctrl *c)
+{
+	struct saa7164_encoder_fh *fh = priv;
+	struct saa7164_port *port = fh->port;
+	int i, next;
+	u32 id = c->id;
+
+	memset(c, 0, sizeof(*c));
+
+	next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL);
+	c->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
+
+	for (i = 0; i < ARRAY_SIZE(saa7164_v4l2_ctrls); i++) {
+		if (next) {
+			if (c->id < saa7164_v4l2_ctrls[i])
+				c->id = saa7164_v4l2_ctrls[i];
+			else
+				continue;
+		}
+
+		if (c->id == saa7164_v4l2_ctrls[i])
+			return fill_queryctrl(&port->encoder_params, c);
+
+		if (c->id < saa7164_v4l2_ctrls[i])
+			break;
+	}
+
+	return -EINVAL;
+}
+
+static int saa7164_encoder_stop_port(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	int ret;
+
+	ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n",
+			__func__, ret);
+		ret = -EIO;
+	} else {
+		dprintk(DBGLVL_ENC, "%s()    Stopped\n", __func__);
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static int saa7164_encoder_acquire_port(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	int ret;
+
+	ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
+	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n",
+			__func__, ret);
+		ret = -EIO;
+	} else {
+		dprintk(DBGLVL_ENC, "%s() Acquired\n", __func__);
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static int saa7164_encoder_pause_port(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	int ret;
+
+	ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
+	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n",
+			__func__, ret);
+		ret = -EIO;
+	} else {
+		dprintk(DBGLVL_ENC, "%s()   Paused\n", __func__);
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/* Firmware is very windows centric, meaning you have to transition
+ * the part through AVStream / KS Windows stages, forwards or backwards.
+ * States are: stopped, acquired (h/w), paused, started.
+ * We have to leave here will all of the soft buffers on the free list,
+ * else the cfg_post() func won't have soft buffers to correctly configure.
+ */
+static int saa7164_encoder_stop_streaming(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	struct saa7164_buffer *buf;
+	struct saa7164_user_buffer *ubuf;
+	struct list_head *c, *n;
+	int ret;
+
+	dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
+
+	ret = saa7164_encoder_pause_port(port);
+	ret = saa7164_encoder_acquire_port(port);
+	ret = saa7164_encoder_stop_port(port);
+
+	dprintk(DBGLVL_ENC, "%s(port=%d) Hardware stopped\n", __func__,
+		port->nr);
+
+	/* Reset the state of any allocated buffer resources */
+	mutex_lock(&port->dmaqueue_lock);
+
+	/* Reset the hard and soft buffer state */
+	list_for_each_safe(c, n, &port->dmaqueue.list) {
+		buf = list_entry(c, struct saa7164_buffer, list);
+		buf->flags = SAA7164_BUFFER_FREE;
+		buf->pos = 0;
+	}
+
+	list_for_each_safe(c, n, &port->list_buf_used.list) {
+		ubuf = list_entry(c, struct saa7164_user_buffer, list);
+		ubuf->pos = 0;
+		list_move_tail(&ubuf->list, &port->list_buf_free.list);
+	}
+
+	mutex_unlock(&port->dmaqueue_lock);
+
+	/* Free any allocated resources */
+	saa7164_encoder_buffers_dealloc(port);
+
+	dprintk(DBGLVL_ENC, "%s(port=%d) Released\n", __func__, port->nr);
+
+	return ret;
+}
+
+static int saa7164_encoder_start_streaming(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	int result, ret = 0;
+
+	dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
+
+	port->done_first_interrupt = 0;
+
+	/* allocate all of the PCIe DMA buffer resources on the fly,
+	 * allowing switching between TS and PS payloads without
+	 * requiring a complete driver reload.
+	 */
+	saa7164_encoder_buffers_alloc(port);
+
+	/* Configure the encoder with any cache values */
+	saa7164_api_set_encoder(port);
+	saa7164_api_get_encoder(port);
+
+	/* Place the empty buffers on the hardware */
+	saa7164_buffer_cfg_port(port);
+
+	/* Acquire the hardware */
+	result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
+	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n",
+			__func__, result);
+
+		/* Stop the hardware, regardless */
+		result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+		if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+			printk(KERN_ERR "%s() acquire/forced stop transition "
+				"failed, res = 0x%x\n", __func__, result);
+		}
+		ret = -EIO;
+		goto out;
+	} else
+		dprintk(DBGLVL_ENC, "%s()   Acquired\n", __func__);
+
+	/* Pause the hardware */
+	result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
+	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n",
+				__func__, result);
+
+		/* Stop the hardware, regardless */
+		result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+		if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+			printk(KERN_ERR "%s() pause/forced stop transition "
+				"failed, res = 0x%x\n", __func__, result);
+		}
+
+		ret = -EIO;
+		goto out;
+	} else
+		dprintk(DBGLVL_ENC, "%s()   Paused\n", __func__);
+
+	/* Start the hardware */
+	result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN);
+	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() run transition failed, result = 0x%x\n",
+				__func__, result);
+
+		/* Stop the hardware, regardless */
+		result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+		if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+			printk(KERN_ERR "%s() run/forced stop transition "
+				"failed, res = 0x%x\n", __func__, result);
+		}
+
+		ret = -EIO;
+	} else
+		dprintk(DBGLVL_ENC, "%s()   Running\n", __func__);
+
+out:
+	return ret;
+}
+
+static int fops_open(struct file *file)
+{
+	struct saa7164_dev *dev;
+	struct saa7164_port *port;
+	struct saa7164_encoder_fh *fh;
+
+	port = (struct saa7164_port *)video_get_drvdata(video_devdata(file));
+	if (!port)
+		return -ENODEV;
+
+	dev = port->dev;
+
+	dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+	/* allocate + initialize per filehandle data */
+	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+	if (NULL == fh)
+		return -ENOMEM;
+
+	file->private_data = fh;
+	fh->port = port;
+
+	return 0;
+}
+
+static int fops_release(struct file *file)
+{
+	struct saa7164_encoder_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+	/* Shut device down on last close */
+	if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
+		if (atomic_dec_return(&port->v4l_reader_count) == 0) {
+			/* stop mpeg capture then cancel buffers */
+			saa7164_encoder_stop_streaming(port);
+		}
+	}
+
+	file->private_data = NULL;
+	kfree(fh);
+
+	return 0;
+}
+
+struct saa7164_user_buffer *saa7164_enc_next_buf(struct saa7164_port *port)
+{
+	struct saa7164_user_buffer *ubuf = NULL;
+	struct saa7164_dev *dev = port->dev;
+	u32 crc;
+
+	mutex_lock(&port->dmaqueue_lock);
+	if (!list_empty(&port->list_buf_used.list)) {
+		ubuf = list_first_entry(&port->list_buf_used.list,
+			struct saa7164_user_buffer, list);
+
+		if (crc_checking) {
+			crc = crc32(0, ubuf->data, ubuf->actual_size);
+			if (crc != ubuf->crc) {
+				printk(KERN_ERR
+		"%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n",
+					__func__,
+					ubuf, ubuf->crc, crc);
+			}
+		}
+
+	}
+	mutex_unlock(&port->dmaqueue_lock);
+
+	dprintk(DBGLVL_ENC, "%s() returns %p\n", __func__, ubuf);
+
+	return ubuf;
+}
+
+static ssize_t fops_read(struct file *file, char __user *buffer,
+	size_t count, loff_t *pos)
+{
+	struct saa7164_encoder_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_user_buffer *ubuf = NULL;
+	struct saa7164_dev *dev = port->dev;
+	int ret = 0;
+	int rem, cnt;
+	u8 *p;
+
+	port->last_read_msecs_diff = port->last_read_msecs;
+	port->last_read_msecs = jiffies_to_msecs(jiffies);
+	port->last_read_msecs_diff = port->last_read_msecs -
+		port->last_read_msecs_diff;
+
+	saa7164_histogram_update(&port->read_interval,
+		port->last_read_msecs_diff);
+
+	if (*pos) {
+		printk(KERN_ERR "%s() ESPIPE\n", __func__);
+		return -ESPIPE;
+	}
+
+	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+		if (atomic_inc_return(&port->v4l_reader_count) == 1) {
+
+			if (saa7164_encoder_initialize(port) < 0) {
+				printk(KERN_ERR "%s() EINVAL\n", __func__);
+				return -EINVAL;
+			}
+
+			saa7164_encoder_start_streaming(port);
+			msleep(200);
+		}
+	}
+
+	/* blocking wait for buffer */
+	if ((file->f_flags & O_NONBLOCK) == 0) {
+		if (wait_event_interruptible(port->wait_read,
+			saa7164_enc_next_buf(port))) {
+				printk(KERN_ERR "%s() ERESTARTSYS\n", __func__);
+				return -ERESTARTSYS;
+		}
+	}
+
+	/* Pull the first buffer from the used list */
+	ubuf = saa7164_enc_next_buf(port);
+
+	while ((count > 0) && ubuf) {
+
+		/* set remaining bytes to copy */
+		rem = ubuf->actual_size - ubuf->pos;
+		cnt = rem > count ? count : rem;
+
+		p = ubuf->data + ubuf->pos;
+
+		dprintk(DBGLVL_ENC,
+			"%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n",
+			__func__, (int)count, cnt, rem, ubuf, ubuf->pos);
+
+		if (copy_to_user(buffer, p, cnt)) {
+			printk(KERN_ERR "%s() copy_to_user failed\n", __func__);
+			if (!ret) {
+				printk(KERN_ERR "%s() EFAULT\n", __func__);
+				ret = -EFAULT;
+			}
+			goto err;
+		}
+
+		ubuf->pos += cnt;
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+
+		if (ubuf->pos > ubuf->actual_size)
+			printk(KERN_ERR "read() pos > actual, huh?\n");
+
+		if (ubuf->pos == ubuf->actual_size) {
+
+			/* finished with current buffer, take next buffer */
+
+			/* Requeue the buffer on the free list */
+			ubuf->pos = 0;
+
+			mutex_lock(&port->dmaqueue_lock);
+			list_move_tail(&ubuf->list, &port->list_buf_free.list);
+			mutex_unlock(&port->dmaqueue_lock);
+
+			/* Dequeue next */
+			if ((file->f_flags & O_NONBLOCK) == 0) {
+				if (wait_event_interruptible(port->wait_read,
+					saa7164_enc_next_buf(port))) {
+						break;
+				}
+			}
+			ubuf = saa7164_enc_next_buf(port);
+		}
+	}
+err:
+	if (!ret && !ubuf)
+		ret = -EAGAIN;
+
+	return ret;
+}
+
+static unsigned int fops_poll(struct file *file, poll_table *wait)
+{
+	struct saa7164_encoder_fh *fh =
+		(struct saa7164_encoder_fh *)file->private_data;
+	struct saa7164_port *port = fh->port;
+	unsigned int mask = 0;
+
+	port->last_poll_msecs_diff = port->last_poll_msecs;
+	port->last_poll_msecs = jiffies_to_msecs(jiffies);
+	port->last_poll_msecs_diff = port->last_poll_msecs -
+		port->last_poll_msecs_diff;
+
+	saa7164_histogram_update(&port->poll_interval,
+		port->last_poll_msecs_diff);
+
+	if (!video_is_registered(port->v4l_device))
+		return -EIO;
+
+	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+		if (atomic_inc_return(&port->v4l_reader_count) == 1) {
+			if (saa7164_encoder_initialize(port) < 0)
+				return -EINVAL;
+			saa7164_encoder_start_streaming(port);
+			msleep(200);
+		}
+	}
+
+	/* blocking wait for buffer */
+	if ((file->f_flags & O_NONBLOCK) == 0) {
+		if (wait_event_interruptible(port->wait_read,
+			saa7164_enc_next_buf(port))) {
+				return -ERESTARTSYS;
+		}
+	}
+
+	/* Pull the first buffer from the used list */
+	if (!list_empty(&port->list_buf_used.list))
+		mask |= POLLIN | POLLRDNORM;
+
+	return mask;
+}
+
+static const struct v4l2_file_operations mpeg_fops = {
+	.owner		= THIS_MODULE,
+	.open		= fops_open,
+	.release	= fops_release,
+	.read		= fops_read,
+	.poll		= fops_poll,
+	.unlocked_ioctl	= video_ioctl2,
+};
+
+int saa7164_g_chip_ident(struct file *file, void *fh,
+	struct v4l2_dbg_chip_ident *chip)
+{
+	struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
+	struct saa7164_dev *dev = port->dev;
+	dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+	return 0;
+}
+
+int saa7164_g_register(struct file *file, void *fh,
+	struct v4l2_dbg_register *reg)
+{
+	struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
+	struct saa7164_dev *dev = port->dev;
+	dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	return 0;
+}
+
+int saa7164_s_register(struct file *file, void *fh,
+	struct v4l2_dbg_register *reg)
+{
+	struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
+	struct saa7164_dev *dev = port->dev;
+	dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
+	.vidioc_s_std		 = vidioc_s_std,
+	.vidioc_enum_input	 = vidioc_enum_input,
+	.vidioc_g_input		 = vidioc_g_input,
+	.vidioc_s_input		 = vidioc_s_input,
+	.vidioc_g_tuner		 = vidioc_g_tuner,
+	.vidioc_s_tuner		 = vidioc_s_tuner,
+	.vidioc_g_frequency	 = vidioc_g_frequency,
+	.vidioc_s_frequency	 = vidioc_s_frequency,
+	.vidioc_s_ctrl		 = vidioc_s_ctrl,
+	.vidioc_g_ctrl		 = vidioc_g_ctrl,
+	.vidioc_querycap	 = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	 = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	 = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	 = vidioc_s_fmt_vid_cap,
+	.vidioc_g_ext_ctrls	 = vidioc_g_ext_ctrls,
+	.vidioc_s_ext_ctrls	 = vidioc_s_ext_ctrls,
+	.vidioc_try_ext_ctrls	 = vidioc_try_ext_ctrls,
+	.vidioc_queryctrl	 = vidioc_queryctrl,
+	.vidioc_g_chip_ident	 = saa7164_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register	 = saa7164_g_register,
+	.vidioc_s_register	 = saa7164_s_register,
+#endif
+};
+
+static struct video_device saa7164_mpeg_template = {
+	.name          = "saa7164",
+	.fops          = &mpeg_fops,
+	.ioctl_ops     = &mpeg_ioctl_ops,
+	.minor         = -1,
+	.tvnorms       = SAA7164_NORMS,
+	.current_norm  = V4L2_STD_NTSC_M,
+};
+
+static struct video_device *saa7164_encoder_alloc(
+	struct saa7164_port *port,
+	struct pci_dev *pci,
+	struct video_device *template,
+	char *type)
+{
+	struct video_device *vfd;
+	struct saa7164_dev *dev = port->dev;
+
+	dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+	vfd = video_device_alloc();
+	if (NULL == vfd)
+		return NULL;
+
+	*vfd = *template;
+	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
+		type, saa7164_boards[dev->board].name);
+
+	vfd->parent  = &pci->dev;
+	vfd->release = video_device_release;
+	return vfd;
+}
+
+int saa7164_encoder_register(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	int result = -ENODEV;
+
+	dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+	if (port->type != SAA7164_MPEG_ENCODER)
+		BUG();
+
+	/* Sanity check that the PCI configuration space is active */
+	if (port->hwcfg.BARLocation == 0) {
+		printk(KERN_ERR "%s() failed "
+		       "(errno = %d), NO PCI configuration\n",
+			__func__, result);
+		result = -ENOMEM;
+		goto failed;
+	}
+
+	/* Establish encoder defaults here */
+	/* Set default TV standard */
+	port->encodernorm = saa7164_tvnorms[0];
+	port->width = 720;
+	port->mux_input = 1; /* Composite */
+	port->video_format = EU_VIDEO_FORMAT_MPEG_2;
+	port->audio_format = 0;
+	port->video_resolution = 0;
+	port->ctl_brightness = 127;
+	port->ctl_contrast = 66;
+	port->ctl_hue = 128;
+	port->ctl_saturation = 62;
+	port->ctl_sharpness = 8;
+	port->encoder_params.bitrate = ENCODER_DEF_BITRATE;
+	port->encoder_params.bitrate_peak = ENCODER_DEF_BITRATE;
+	port->encoder_params.bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+	port->encoder_params.stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS;
+	port->encoder_params.ctl_mute = 0;
+	port->encoder_params.ctl_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3;
+	port->encoder_params.refdist = 1;
+	port->encoder_params.gop_size = SAA7164_ENCODER_DEFAULT_GOP_SIZE;
+
+	if (port->encodernorm.id & V4L2_STD_525_60)
+		port->height = 480;
+	else
+		port->height = 576;
+
+	/* Allocate and register the video device node */
+	port->v4l_device = saa7164_encoder_alloc(port,
+		dev->pci, &saa7164_mpeg_template, "mpeg");
+
+	if (!port->v4l_device) {
+		printk(KERN_INFO "%s: can't allocate mpeg device\n",
+			dev->name);
+		result = -ENOMEM;
+		goto failed;
+	}
+
+	video_set_drvdata(port->v4l_device, port);
+	result = video_register_device(port->v4l_device,
+		VFL_TYPE_GRABBER, -1);
+	if (result < 0) {
+		printk(KERN_INFO "%s: can't register mpeg device\n",
+			dev->name);
+		/* TODO: We're going to leak here if we don't dealloc
+		 The buffers above. The unreg function can't deal wit it.
+		*/
+		goto failed;
+	}
+
+	printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
+		dev->name, port->v4l_device->num);
+
+	/* Configure the hardware defaults */
+	saa7164_api_set_videomux(port);
+	saa7164_api_set_usercontrol(port, PU_BRIGHTNESS_CONTROL);
+	saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL);
+	saa7164_api_set_usercontrol(port, PU_HUE_CONTROL);
+	saa7164_api_set_usercontrol(port, PU_SATURATION_CONTROL);
+	saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL);
+	saa7164_api_audio_mute(port, 0);
+	saa7164_api_set_audio_volume(port, 20);
+	saa7164_api_set_aspect_ratio(port);
+
+	/* Disable audio standard detection, it's buggy */
+	saa7164_api_set_audio_detection(port, 0);
+
+	saa7164_api_set_encoder(port);
+	saa7164_api_get_encoder(port);
+
+	result = 0;
+failed:
+	return result;
+}
+
+void saa7164_encoder_unregister(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+
+	dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
+
+	if (port->type != SAA7164_MPEG_ENCODER)
+		BUG();
+
+	if (port->v4l_device) {
+		if (port->v4l_device->minor != -1)
+			video_unregister_device(port->v4l_device);
+		else
+			video_device_release(port->v4l_device);
+
+		port->v4l_device = NULL;
+	}
+
+	dprintk(DBGLVL_ENC, "%s(port=%d) done\n", __func__, port->nr);
+}
+
diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c
new file mode 100644
index 0000000..a266bf0
--- /dev/null
+++ b/drivers/media/pci/saa7164/saa7164-fw.c
@@ -0,0 +1,613 @@
+/*
+ *  Driver for the NXP SAA7164 PCIe bridge
+ *
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/firmware.h>
+#include <linux/slab.h>
+
+#include "saa7164.h"
+
+#define SAA7164_REV2_FIRMWARE		"NXP7164-2010-03-10.1.fw"
+#define SAA7164_REV2_FIRMWARE_SIZE	4019072
+
+#define SAA7164_REV3_FIRMWARE		"NXP7164-2010-03-10.1.fw"
+#define SAA7164_REV3_FIRMWARE_SIZE	4019072
+
+struct fw_header {
+	u32	firmwaresize;
+	u32	bslsize;
+	u32	reserved;
+	u32	version;
+};
+
+int saa7164_dl_wait_ack(struct saa7164_dev *dev, u32 reg)
+{
+	u32 timeout = SAA_DEVICE_TIMEOUT;
+	while ((saa7164_readl(reg) & 0x01) == 0) {
+		timeout -= 10;
+		if (timeout == 0) {
+			printk(KERN_ERR "%s() timeout (no d/l ack)\n",
+				__func__);
+			return -EBUSY;
+		}
+		msleep(100);
+	}
+
+	return 0;
+}
+
+int saa7164_dl_wait_clr(struct saa7164_dev *dev, u32 reg)
+{
+	u32 timeout = SAA_DEVICE_TIMEOUT;
+	while (saa7164_readl(reg) & 0x01) {
+		timeout -= 10;
+		if (timeout == 0) {
+			printk(KERN_ERR "%s() timeout (no d/l clr)\n",
+				__func__);
+			return -EBUSY;
+		}
+		msleep(100);
+	}
+
+	return 0;
+}
+
+/* TODO: move dlflags into dev-> and change to write/readl/b */
+/* TODO: Excessive levels of debug */
+int saa7164_downloadimage(struct saa7164_dev *dev, u8 *src, u32 srcsize,
+	u32 dlflags, u8 *dst, u32 dstsize)
+{
+	u32 reg, timeout, offset;
+	u8 *srcbuf = NULL;
+	int ret;
+
+	u32 dlflag = dlflags;
+	u32 dlflag_ack = dlflag + 4;
+	u32 drflag = dlflag_ack + 4;
+	u32 drflag_ack = drflag + 4;
+	u32 bleflag = drflag_ack + 4;
+
+	dprintk(DBGLVL_FW,
+		"%s(image=%p, size=%d, flags=0x%x, dst=%p, dstsize=0x%x)\n",
+		__func__, src, srcsize, dlflags, dst, dstsize);
+
+	if ((src == NULL) || (dst == NULL)) {
+		ret = -EIO;
+		goto out;
+	}
+
+	srcbuf = kzalloc(4 * 1048576, GFP_KERNEL);
+	if (NULL == srcbuf) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (srcsize > (4*1048576)) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	memcpy(srcbuf, src, srcsize);
+
+	dprintk(DBGLVL_FW, "%s() dlflag = 0x%x\n", __func__, dlflag);
+	dprintk(DBGLVL_FW, "%s() dlflag_ack = 0x%x\n", __func__, dlflag_ack);
+	dprintk(DBGLVL_FW, "%s() drflag = 0x%x\n", __func__, drflag);
+	dprintk(DBGLVL_FW, "%s() drflag_ack = 0x%x\n", __func__, drflag_ack);
+	dprintk(DBGLVL_FW, "%s() bleflag = 0x%x\n", __func__, bleflag);
+
+	reg = saa7164_readl(dlflag);
+	dprintk(DBGLVL_FW, "%s() dlflag (0x%x)= 0x%x\n", __func__, dlflag, reg);
+	if (reg == 1)
+		dprintk(DBGLVL_FW,
+			"%s() Download flag already set, please reboot\n",
+			__func__);
+
+	/* Indicate download start */
+	saa7164_writel(dlflag, 1);
+	ret = saa7164_dl_wait_ack(dev, dlflag_ack);
+	if (ret < 0)
+		goto out;
+
+	/* Ack download start, then wait for wait */
+	saa7164_writel(dlflag, 0);
+	ret = saa7164_dl_wait_clr(dev, dlflag_ack);
+	if (ret < 0)
+		goto out;
+
+	/* Deal with the raw firmware, in the appropriate chunk size */
+	for (offset = 0; srcsize > dstsize;
+		srcsize -= dstsize, offset += dstsize) {
+
+		dprintk(DBGLVL_FW, "%s() memcpy %d\n", __func__, dstsize);
+		memcpy(dst, srcbuf + offset, dstsize);
+
+		/* Flag the data as ready */
+		saa7164_writel(drflag, 1);
+		ret = saa7164_dl_wait_ack(dev, drflag_ack);
+		if (ret < 0)
+			goto out;
+
+		/* Wait for indication data was received */
+		saa7164_writel(drflag, 0);
+		ret = saa7164_dl_wait_clr(dev, drflag_ack);
+		if (ret < 0)
+			goto out;
+
+	}
+
+	dprintk(DBGLVL_FW, "%s() memcpy(l) %d\n", __func__, dstsize);
+	/* Write last block to the device */
+	memcpy(dst, srcbuf+offset, srcsize);
+
+	/* Flag the data as ready */
+	saa7164_writel(drflag, 1);
+	ret = saa7164_dl_wait_ack(dev, drflag_ack);
+	if (ret < 0)
+		goto out;
+
+	saa7164_writel(drflag, 0);
+	timeout = 0;
+	while (saa7164_readl(bleflag) != SAA_DEVICE_IMAGE_BOOTING) {
+		if (saa7164_readl(bleflag) & SAA_DEVICE_IMAGE_CORRUPT) {
+			printk(KERN_ERR "%s() image corrupt\n", __func__);
+			ret = -EBUSY;
+			goto out;
+		}
+
+		if (saa7164_readl(bleflag) & SAA_DEVICE_MEMORY_CORRUPT) {
+			printk(KERN_ERR "%s() device memory corrupt\n",
+				__func__);
+			ret = -EBUSY;
+			goto out;
+		}
+
+		msleep(10); /* Checkpatch throws a < 20ms warning */
+		if (timeout++ > 60)
+			break;
+	}
+
+	printk(KERN_INFO "%s() Image downloaded, booting...\n", __func__);
+
+	ret = saa7164_dl_wait_clr(dev, drflag_ack);
+	if (ret < 0)
+		goto out;
+
+	printk(KERN_INFO "%s() Image booted successfully.\n", __func__);
+	ret = 0;
+
+out:
+	kfree(srcbuf);
+	return ret;
+}
+
+/* TODO: Excessive debug */
+/* Load the firmware. Optionally it can be in ROM or newer versions
+ * can be on disk, saving the expense of the ROM hardware. */
+int saa7164_downloadfirmware(struct saa7164_dev *dev)
+{
+	/* u32 second_timeout = 60 * SAA_DEVICE_TIMEOUT; */
+	u32 tmp, filesize, version, err_flags, first_timeout, fwlength;
+	u32 second_timeout, updatebootloader = 1, bootloadersize = 0;
+	const struct firmware *fw = NULL;
+	struct fw_header *hdr, *boothdr = NULL, *fwhdr;
+	u32 bootloaderversion = 0, fwloadersize;
+	u8 *bootloaderoffset = NULL, *fwloaderoffset;
+	char *fwname;
+	int ret;
+
+	dprintk(DBGLVL_FW, "%s()\n", __func__);
+
+	if (saa7164_boards[dev->board].chiprev == SAA7164_CHIP_REV2) {
+		fwname = SAA7164_REV2_FIRMWARE;
+		fwlength = SAA7164_REV2_FIRMWARE_SIZE;
+	} else {
+		fwname = SAA7164_REV3_FIRMWARE;
+		fwlength = SAA7164_REV3_FIRMWARE_SIZE;
+	}
+
+	version = saa7164_getcurrentfirmwareversion(dev);
+
+	if (version == 0x00) {
+
+		second_timeout = 100;
+		first_timeout = 100;
+		err_flags = saa7164_readl(SAA_BOOTLOADERERROR_FLAGS);
+		dprintk(DBGLVL_FW, "%s() err_flags = %x\n",
+			__func__, err_flags);
+
+		while (err_flags != SAA_DEVICE_IMAGE_BOOTING) {
+			dprintk(DBGLVL_FW, "%s() err_flags = %x\n",
+				__func__, err_flags);
+			msleep(10); /* Checkpatch throws a < 20ms warning */
+
+			if (err_flags & SAA_DEVICE_IMAGE_CORRUPT) {
+				printk(KERN_ERR "%s() firmware corrupt\n",
+					__func__);
+				break;
+			}
+			if (err_flags & SAA_DEVICE_MEMORY_CORRUPT) {
+				printk(KERN_ERR "%s() device memory corrupt\n",
+					__func__);
+				break;
+			}
+			if (err_flags & SAA_DEVICE_NO_IMAGE) {
+				printk(KERN_ERR "%s() no first image\n",
+				__func__);
+				break;
+			}
+			if (err_flags & SAA_DEVICE_IMAGE_SEARCHING) {
+				first_timeout -= 10;
+				if (first_timeout == 0) {
+					printk(KERN_ERR
+						"%s() no first image\n",
+						__func__);
+					break;
+				}
+			} else if (err_flags & SAA_DEVICE_IMAGE_LOADING) {
+				second_timeout -= 10;
+				if (second_timeout == 0) {
+					printk(KERN_ERR
+					"%s() FW load time exceeded\n",
+						__func__);
+					break;
+				}
+			} else {
+				second_timeout -= 10;
+				if (second_timeout == 0) {
+					printk(KERN_ERR
+					"%s() Unknown bootloader flags 0x%x\n",
+						__func__, err_flags);
+					break;
+				}
+			}
+
+			err_flags = saa7164_readl(SAA_BOOTLOADERERROR_FLAGS);
+		} /* While != Booting */
+
+		if (err_flags == SAA_DEVICE_IMAGE_BOOTING) {
+			dprintk(DBGLVL_FW, "%s() Loader 1 has loaded.\n",
+				__func__);
+			first_timeout = SAA_DEVICE_TIMEOUT;
+			second_timeout = 60 * SAA_DEVICE_TIMEOUT;
+			second_timeout = 100;
+
+			err_flags = saa7164_readl(SAA_SECONDSTAGEERROR_FLAGS);
+			dprintk(DBGLVL_FW, "%s() err_flags2 = %x\n",
+				__func__, err_flags);
+			while (err_flags != SAA_DEVICE_IMAGE_BOOTING) {
+				dprintk(DBGLVL_FW, "%s() err_flags2 = %x\n",
+					__func__, err_flags);
+				msleep(10); /* Checkpatch throws a < 20ms warning */
+
+				if (err_flags & SAA_DEVICE_IMAGE_CORRUPT) {
+					printk(KERN_ERR
+						"%s() firmware corrupt\n",
+						__func__);
+					break;
+				}
+				if (err_flags & SAA_DEVICE_MEMORY_CORRUPT) {
+					printk(KERN_ERR
+						"%s() device memory corrupt\n",
+						__func__);
+					break;
+				}
+				if (err_flags & SAA_DEVICE_NO_IMAGE) {
+					printk(KERN_ERR "%s() no first image\n",
+						__func__);
+					break;
+				}
+				if (err_flags & SAA_DEVICE_IMAGE_SEARCHING) {
+					first_timeout -= 10;
+					if (first_timeout == 0) {
+						printk(KERN_ERR
+						"%s() no second image\n",
+							__func__);
+						break;
+					}
+				} else if (err_flags &
+					SAA_DEVICE_IMAGE_LOADING) {
+					second_timeout -= 10;
+					if (second_timeout == 0) {
+						printk(KERN_ERR
+						"%s() FW load time exceeded\n",
+							__func__);
+						break;
+					}
+				} else {
+					second_timeout -= 10;
+					if (second_timeout == 0) {
+						printk(KERN_ERR
+					"%s() Unknown bootloader flags 0x%x\n",
+							__func__, err_flags);
+						break;
+					}
+				}
+
+				err_flags =
+				saa7164_readl(SAA_SECONDSTAGEERROR_FLAGS);
+			} /* err_flags != SAA_DEVICE_IMAGE_BOOTING */
+
+			dprintk(DBGLVL_FW, "%s() Loader flags 1:0x%x 2:0x%x.\n",
+				__func__,
+				saa7164_readl(SAA_BOOTLOADERERROR_FLAGS),
+				saa7164_readl(SAA_SECONDSTAGEERROR_FLAGS));
+
+		} /* err_flags == SAA_DEVICE_IMAGE_BOOTING */
+
+		/* It's possible for both firmwares to have booted,
+		 * but that doesn't mean they've finished booting yet.
+		 */
+		if ((saa7164_readl(SAA_BOOTLOADERERROR_FLAGS) ==
+			SAA_DEVICE_IMAGE_BOOTING) &&
+			(saa7164_readl(SAA_SECONDSTAGEERROR_FLAGS) ==
+			SAA_DEVICE_IMAGE_BOOTING)) {
+
+
+			dprintk(DBGLVL_FW, "%s() Loader 2 has loaded.\n",
+				__func__);
+
+			first_timeout = SAA_DEVICE_TIMEOUT;
+			while (first_timeout) {
+				msleep(10); /* Checkpatch throws a < 20ms warning */
+
+				version =
+					saa7164_getcurrentfirmwareversion(dev);
+				if (version) {
+					dprintk(DBGLVL_FW,
+					"%s() All f/w loaded successfully\n",
+						__func__);
+					break;
+				} else {
+					first_timeout -= 10;
+					if (first_timeout == 0) {
+						printk(KERN_ERR
+						"%s() FW did not boot\n",
+							__func__);
+						break;
+					}
+				}
+			}
+		}
+		version = saa7164_getcurrentfirmwareversion(dev);
+	} /* version == 0 */
+
+	/* Has the firmware really booted? */
+	if ((saa7164_readl(SAA_BOOTLOADERERROR_FLAGS) ==
+		SAA_DEVICE_IMAGE_BOOTING) &&
+		(saa7164_readl(SAA_SECONDSTAGEERROR_FLAGS) ==
+		SAA_DEVICE_IMAGE_BOOTING) && (version == 0)) {
+
+		printk(KERN_ERR
+			"%s() The firmware hung, probably bad firmware\n",
+			__func__);
+
+		/* Tell the second stage loader we have a deadlock */
+		saa7164_writel(SAA_DEVICE_DEADLOCK_DETECTED_OFFSET,
+			SAA_DEVICE_DEADLOCK_DETECTED);
+
+		saa7164_getfirmwarestatus(dev);
+
+		return -ENOMEM;
+	}
+
+	dprintk(DBGLVL_FW, "Device has Firmware Version %d.%d.%d.%d\n",
+		(version & 0x0000fc00) >> 10,
+		(version & 0x000003e0) >> 5,
+		(version & 0x0000001f),
+		(version & 0xffff0000) >> 16);
+
+	/* Load the firmwware from the disk if required */
+	if (version == 0) {
+
+		printk(KERN_INFO "%s() Waiting for firmware upload (%s)\n",
+			__func__, fwname);
+
+		ret = request_firmware(&fw, fwname, &dev->pci->dev);
+		if (ret) {
+			printk(KERN_ERR "%s() Upload failed. "
+				"(file not found?)\n", __func__);
+			return -ENOMEM;
+		}
+
+		printk(KERN_INFO "%s() firmware read %Zu bytes.\n",
+			__func__, fw->size);
+
+		if (fw->size != fwlength) {
+			printk(KERN_ERR "xc5000: firmware incorrect size\n");
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		printk(KERN_INFO "%s() firmware loaded.\n", __func__);
+
+		hdr = (struct fw_header *)fw->data;
+		printk(KERN_INFO "Firmware file header part 1:\n");
+		printk(KERN_INFO " .FirmwareSize = 0x%x\n", hdr->firmwaresize);
+		printk(KERN_INFO " .BSLSize = 0x%x\n", hdr->bslsize);
+		printk(KERN_INFO " .Reserved = 0x%x\n", hdr->reserved);
+		printk(KERN_INFO " .Version = 0x%x\n", hdr->version);
+
+		/* Retrieve bootloader if reqd */
+		if ((hdr->firmwaresize == 0) && (hdr->bslsize == 0))
+			/* Second bootloader in the firmware file */
+			filesize = hdr->reserved * 16;
+		else
+			filesize = (hdr->firmwaresize + hdr->bslsize) *
+				16 + sizeof(struct fw_header);
+
+		printk(KERN_INFO "%s() SecBootLoader.FileSize = %d\n",
+			__func__, filesize);
+
+		/* Get bootloader (if reqd) and firmware header */
+		if ((hdr->firmwaresize == 0) && (hdr->bslsize == 0)) {
+			/* Second boot loader is required */
+
+			/* Get the loader header */
+			boothdr = (struct fw_header *)(fw->data +
+				sizeof(struct fw_header));
+
+			bootloaderversion =
+				saa7164_readl(SAA_DEVICE_2ND_VERSION);
+			dprintk(DBGLVL_FW, "Onboard BootLoader:\n");
+			dprintk(DBGLVL_FW, "->Flag 0x%x\n",
+				saa7164_readl(SAA_BOOTLOADERERROR_FLAGS));
+			dprintk(DBGLVL_FW, "->Ack 0x%x\n",
+				saa7164_readl(SAA_DATAREADY_FLAG_ACK));
+			dprintk(DBGLVL_FW, "->FW Version 0x%x\n", version);
+			dprintk(DBGLVL_FW, "->Loader Version 0x%x\n",
+				bootloaderversion);
+
+			if ((saa7164_readl(SAA_BOOTLOADERERROR_FLAGS) ==
+				0x03) && (saa7164_readl(SAA_DATAREADY_FLAG_ACK)
+				== 0x00) && (version == 0x00)) {
+
+				dprintk(DBGLVL_FW, "BootLoader version in  "
+					"rom %d.%d.%d.%d\n",
+					(bootloaderversion & 0x0000fc00) >> 10,
+					(bootloaderversion & 0x000003e0) >> 5,
+					(bootloaderversion & 0x0000001f),
+					(bootloaderversion & 0xffff0000) >> 16
+					);
+				dprintk(DBGLVL_FW, "BootLoader version "
+					"in file %d.%d.%d.%d\n",
+					(boothdr->version & 0x0000fc00) >> 10,
+					(boothdr->version & 0x000003e0) >> 5,
+					(boothdr->version & 0x0000001f),
+					(boothdr->version & 0xffff0000) >> 16
+					);
+
+				if (bootloaderversion == boothdr->version)
+					updatebootloader = 0;
+			}
+
+			/* Calculate offset to firmware header */
+			tmp = (boothdr->firmwaresize + boothdr->bslsize) * 16 +
+				(sizeof(struct fw_header) +
+				sizeof(struct fw_header));
+
+			fwhdr = (struct fw_header *)(fw->data+tmp);
+		} else {
+			/* No second boot loader */
+			fwhdr = hdr;
+		}
+
+		dprintk(DBGLVL_FW, "Firmware version in file %d.%d.%d.%d\n",
+			(fwhdr->version & 0x0000fc00) >> 10,
+			(fwhdr->version & 0x000003e0) >> 5,
+			(fwhdr->version & 0x0000001f),
+			(fwhdr->version & 0xffff0000) >> 16
+			);
+
+		if (version == fwhdr->version) {
+			/* No download, firmware already on board */
+			ret = 0;
+			goto out;
+		}
+
+		if ((hdr->firmwaresize == 0) && (hdr->bslsize == 0)) {
+			if (updatebootloader) {
+				/* Get ready to upload the bootloader */
+				bootloadersize = (boothdr->firmwaresize +
+					boothdr->bslsize) * 16 +
+					sizeof(struct fw_header);
+
+				bootloaderoffset = (u8 *)(fw->data +
+					sizeof(struct fw_header));
+
+				dprintk(DBGLVL_FW, "bootloader d/l starts.\n");
+				printk(KERN_INFO "%s() FirmwareSize = 0x%x\n",
+					__func__, boothdr->firmwaresize);
+				printk(KERN_INFO "%s() BSLSize = 0x%x\n",
+					__func__, boothdr->bslsize);
+				printk(KERN_INFO "%s() Reserved = 0x%x\n",
+					__func__, boothdr->reserved);
+				printk(KERN_INFO "%s() Version = 0x%x\n",
+					__func__, boothdr->version);
+				ret = saa7164_downloadimage(
+					dev,
+					bootloaderoffset,
+					bootloadersize,
+					SAA_DOWNLOAD_FLAGS,
+					dev->bmmio + SAA_DEVICE_DOWNLOAD_OFFSET,
+					SAA_DEVICE_BUFFERBLOCKSIZE);
+				if (ret < 0) {
+					printk(KERN_ERR
+						"bootloader d/l has failed\n");
+					goto out;
+				}
+				dprintk(DBGLVL_FW,
+					"bootloader download complete.\n");
+
+			}
+
+			printk(KERN_ERR "starting firmware download(2)\n");
+			bootloadersize = (boothdr->firmwaresize +
+				boothdr->bslsize) * 16 +
+				sizeof(struct fw_header);
+
+			bootloaderoffset =
+				(u8 *)(fw->data + sizeof(struct fw_header));
+
+			fwloaderoffset = bootloaderoffset + bootloadersize;
+
+			/* TODO: fix this bounds overrun here with old f/ws */
+			fwloadersize = (fwhdr->firmwaresize + fwhdr->bslsize) *
+				16 + sizeof(struct fw_header);
+
+			ret = saa7164_downloadimage(
+				dev,
+				fwloaderoffset,
+				fwloadersize,
+				SAA_DEVICE_2ND_DOWNLOADFLAG_OFFSET,
+				dev->bmmio + SAA_DEVICE_2ND_DOWNLOAD_OFFSET,
+				SAA_DEVICE_2ND_BUFFERBLOCKSIZE);
+			if (ret < 0) {
+				printk(KERN_ERR "firmware download failed\n");
+				goto out;
+			}
+			printk(KERN_ERR "firmware download complete.\n");
+
+		} else {
+
+			/* No bootloader update reqd, download firmware only */
+			printk(KERN_ERR "starting firmware download(3)\n");
+
+			ret = saa7164_downloadimage(
+				dev,
+				(u8 *)fw->data,
+				fw->size,
+				SAA_DOWNLOAD_FLAGS,
+				dev->bmmio + SAA_DEVICE_DOWNLOAD_OFFSET,
+				SAA_DEVICE_BUFFERBLOCKSIZE);
+			if (ret < 0) {
+				printk(KERN_ERR "firmware download failed\n");
+				goto out;
+			}
+			printk(KERN_ERR "firmware download complete.\n");
+		}
+	}
+
+	dev->firmwareloaded = 1;
+	ret = 0;
+
+out:
+	release_firmware(fw);
+	return ret;
+}
diff --git a/drivers/media/pci/saa7164/saa7164-i2c.c b/drivers/media/pci/saa7164/saa7164-i2c.c
new file mode 100644
index 0000000..4f7e3b4
--- /dev/null
+++ b/drivers/media/pci/saa7164/saa7164-i2c.c
@@ -0,0 +1,125 @@
+/*
+ *  Driver for the NXP SAA7164 PCIe bridge
+ *
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "saa7164.h"
+
+static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
+{
+	struct saa7164_i2c *bus = i2c_adap->algo_data;
+	struct saa7164_dev *dev = bus->dev;
+	int i, retval = 0;
+
+	dprintk(DBGLVL_I2C, "%s(num = %d)\n", __func__, num);
+
+	for (i = 0 ; i < num; i++) {
+		dprintk(DBGLVL_I2C, "%s(num = %d) addr = 0x%02x  len = 0x%x\n",
+			__func__, num, msgs[i].addr, msgs[i].len);
+		if (msgs[i].flags & I2C_M_RD) {
+			/* Unsupported - Yet*/
+			printk(KERN_ERR "%s() Unsupported - Yet\n", __func__);
+			continue;
+		} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
+			   msgs[i].addr == msgs[i + 1].addr) {
+			/* write then read from same address */
+
+			retval = saa7164_api_i2c_read(bus, msgs[i].addr,
+				msgs[i].len, msgs[i].buf,
+				msgs[i+1].len, msgs[i+1].buf
+				);
+
+			i++;
+
+			if (retval < 0)
+				goto err;
+		} else {
+			/* write */
+			retval = saa7164_api_i2c_write(bus, msgs[i].addr,
+				msgs[i].len, msgs[i].buf);
+		}
+		if (retval < 0)
+			goto err;
+	}
+	return num;
+
+err:
+	return retval;
+}
+
+static u32 saa7164_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm saa7164_i2c_algo_template = {
+	.master_xfer	= i2c_xfer,
+	.functionality	= saa7164_functionality,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_adapter saa7164_i2c_adap_template = {
+	.name              = "saa7164",
+	.owner             = THIS_MODULE,
+	.algo              = &saa7164_i2c_algo_template,
+};
+
+static struct i2c_client saa7164_i2c_client_template = {
+	.name	= "saa7164 internal",
+};
+
+int saa7164_i2c_register(struct saa7164_i2c *bus)
+{
+	struct saa7164_dev *dev = bus->dev;
+
+	dprintk(DBGLVL_I2C, "%s(bus = %d)\n", __func__, bus->nr);
+
+	bus->i2c_adap = saa7164_i2c_adap_template;
+	bus->i2c_client = saa7164_i2c_client_template;
+
+	bus->i2c_adap.dev.parent = &dev->pci->dev;
+
+	strlcpy(bus->i2c_adap.name, bus->dev->name,
+		sizeof(bus->i2c_adap.name));
+
+	bus->i2c_adap.algo_data = bus;
+	i2c_set_adapdata(&bus->i2c_adap, bus);
+	i2c_add_adapter(&bus->i2c_adap);
+
+	bus->i2c_client.adapter = &bus->i2c_adap;
+
+	if (0 != bus->i2c_rc)
+		printk(KERN_ERR "%s: i2c bus %d register FAILED\n",
+			dev->name, bus->nr);
+
+	return bus->i2c_rc;
+}
+
+int saa7164_i2c_unregister(struct saa7164_i2c *bus)
+{
+	i2c_del_adapter(&bus->i2c_adap);
+	return 0;
+}
diff --git a/drivers/media/pci/saa7164/saa7164-reg.h b/drivers/media/pci/saa7164/saa7164-reg.h
new file mode 100644
index 0000000..2bbf815
--- /dev/null
+++ b/drivers/media/pci/saa7164/saa7164-reg.h
@@ -0,0 +1,219 @@
+/*
+ *  Driver for the NXP SAA7164 PCIe bridge
+ *
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* TODO: Retest the driver with errors expressed as negatives */
+
+/* Result codes */
+#define SAA_OK				0
+#define SAA_ERR_BAD_PARAMETER		0x09
+#define SAA_ERR_NO_RESOURCES		0x0c
+#define SAA_ERR_NOT_SUPPORTED		0x13
+#define SAA_ERR_BUSY			0x15
+#define SAA_ERR_READ			0x17
+#define SAA_ERR_TIMEOUT			0x1f
+#define SAA_ERR_OVERFLOW		0x20
+#define SAA_ERR_EMPTY			0x22
+#define SAA_ERR_NOT_STARTED		0x23
+#define SAA_ERR_ALREADY_STARTED		0x24
+#define SAA_ERR_NOT_STOPPED		0x25
+#define SAA_ERR_ALREADY_STOPPED		0x26
+#define SAA_ERR_INVALID_COMMAND		0x3e
+#define SAA_ERR_NULL_PACKET		0x59
+
+/* Errors and flags from the silicon */
+#define PVC_ERRORCODE_UNKNOWN		0x00
+#define PVC_ERRORCODE_INVALID_COMMAND	0x01
+#define PVC_ERRORCODE_INVALID_CONTROL	0x02
+#define PVC_ERRORCODE_INVALID_DATA	0x03
+#define PVC_ERRORCODE_TIMEOUT		0x04
+#define PVC_ERRORCODE_NAK		0x05
+#define PVC_RESPONSEFLAG_ERROR		0x01
+#define PVC_RESPONSEFLAG_OVERFLOW	0x02
+#define PVC_RESPONSEFLAG_RESET		0x04
+#define PVC_RESPONSEFLAG_INTERFACE	0x08
+#define PVC_RESPONSEFLAG_CONTINUED	0x10
+#define PVC_CMDFLAG_INTERRUPT		0x02
+#define PVC_CMDFLAG_INTERFACE		0x04
+#define PVC_CMDFLAG_SERIALIZE		0x08
+#define PVC_CMDFLAG_CONTINUE		0x10
+
+/* Silicon Commands */
+#define GET_DESCRIPTORS_CONTROL		0x01
+#define GET_STRING_CONTROL		0x03
+#define GET_LANGUAGE_CONTROL		0x05
+#define SET_POWER_CONTROL		0x07
+#define GET_FW_STATUS_CONTROL		0x08
+#define GET_FW_VERSION_CONTROL		0x09
+#define SET_DEBUG_LEVEL_CONTROL		0x0B
+#define GET_DEBUG_DATA_CONTROL		0x0C
+#define GET_PRODUCTION_INFO_CONTROL	0x0D
+
+/* cmd defines */
+#define SAA_CMDFLAG_CONTINUE		0x10
+#define SAA_CMD_MAX_MSG_UNITS		256
+
+/* Some defines */
+#define SAA_BUS_TIMEOUT			50
+#define SAA_DEVICE_TIMEOUT		5000
+#define SAA_DEVICE_MAXREQUESTSIZE	256
+
+/* Register addresses */
+#define SAA_DEVICE_VERSION		0x30
+#define SAA_DOWNLOAD_FLAGS		0x34
+#define SAA_DOWNLOAD_FLAG		0x34
+#define SAA_DOWNLOAD_FLAG_ACK		0x38
+#define SAA_DATAREADY_FLAG		0x3C
+#define SAA_DATAREADY_FLAG_ACK		0x40
+
+/* Boot loader register and bit definitions */
+#define SAA_BOOTLOADERERROR_FLAGS	0x44
+#define SAA_DEVICE_IMAGE_SEARCHING	0x01
+#define SAA_DEVICE_IMAGE_LOADING	0x02
+#define SAA_DEVICE_IMAGE_BOOTING	0x03
+#define SAA_DEVICE_IMAGE_CORRUPT	0x04
+#define SAA_DEVICE_MEMORY_CORRUPT	0x08
+#define SAA_DEVICE_NO_IMAGE		0x10
+
+/* Register addresses */
+#define SAA_DEVICE_2ND_VERSION			0x50
+#define SAA_DEVICE_2ND_DOWNLOADFLAG_OFFSET	0x54
+
+/* Register addresses */
+#define SAA_SECONDSTAGEERROR_FLAGS		0x64
+
+/* Bootloader regs and flags */
+#define SAA_DEVICE_DEADLOCK_DETECTED_OFFSET	0x6C
+#define SAA_DEVICE_DEADLOCK_DETECTED		0xDEADDEAD
+
+/* Basic firmware status registers */
+#define SAA_DEVICE_SYSINIT_STATUS_OFFSET	0x70
+#define SAA_DEVICE_SYSINIT_STATUS		0x70
+#define SAA_DEVICE_SYSINIT_MODE			0x74
+#define SAA_DEVICE_SYSINIT_SPEC			0x78
+#define SAA_DEVICE_SYSINIT_INST			0x7C
+#define SAA_DEVICE_SYSINIT_CPULOAD		0x80
+#define SAA_DEVICE_SYSINIT_REMAINHEAP		0x84
+
+#define SAA_DEVICE_DOWNLOAD_OFFSET		0x1000
+#define SAA_DEVICE_BUFFERBLOCKSIZE		0x1000
+
+#define SAA_DEVICE_2ND_BUFFERBLOCKSIZE		0x100000
+#define SAA_DEVICE_2ND_DOWNLOAD_OFFSET		0x200000
+
+/* Descriptors */
+#define CS_INTERFACE	0x24
+
+/* Descriptor subtypes */
+#define VC_INPUT_TERMINAL		0x02
+#define VC_OUTPUT_TERMINAL		0x03
+#define VC_SELECTOR_UNIT		0x04
+#define VC_PROCESSING_UNIT		0x05
+#define FEATURE_UNIT			0x06
+#define TUNER_UNIT			0x09
+#define ENCODER_UNIT			0x0A
+#define EXTENSION_UNIT			0x0B
+#define VC_TUNER_PATH			0xF0
+#define PVC_HARDWARE_DESCRIPTOR		0xF1
+#define PVC_INTERFACE_DESCRIPTOR	0xF2
+#define PVC_INFRARED_UNIT		0xF3
+#define DRM_UNIT			0xF4
+#define GENERAL_REQUEST			0xF5
+
+/* Format Types */
+#define VS_FORMAT_TYPE         0x02
+#define VS_FORMAT_TYPE_I       0x01
+#define VS_FORMAT_UNCOMPRESSED 0x04
+#define VS_FRAME_UNCOMPRESSED  0x05
+#define VS_FORMAT_MPEG2PS      0x09
+#define VS_FORMAT_MPEG2TS      0x0A
+#define VS_FORMAT_MPEG4SL      0x0B
+#define VS_FORMAT_WM9          0x0C
+#define VS_FORMAT_DIVX         0x0D
+#define VS_FORMAT_VBI          0x0E
+#define VS_FORMAT_RDS          0x0F
+
+/* Device extension commands */
+#define EXU_REGISTER_ACCESS_CONTROL	0x00
+#define EXU_GPIO_CONTROL		0x01
+#define EXU_GPIO_GROUP_CONTROL		0x02
+#define EXU_INTERRUPT_CONTROL		0x03
+
+/* State Transition and args */
+#define SAA_PROBE_CONTROL	0x01
+#define SAA_COMMIT_CONTROL	0x02
+#define SAA_STATE_CONTROL	0x03
+#define SAA_DMASTATE_STOP	0x00
+#define SAA_DMASTATE_ACQUIRE	0x01
+#define SAA_DMASTATE_PAUSE	0x02
+#define SAA_DMASTATE_RUN	0x03
+
+/* A/V Mux Input Selector */
+#define SU_INPUT_SELECT_CONTROL 0x01
+
+/* Encoder Profiles */
+#define EU_PROFILE_PS_DVD	0x06
+#define EU_PROFILE_TS_HQ	0x09
+#define EU_VIDEO_FORMAT_MPEG_2	0x02
+
+/* Tuner */
+#define TU_AUDIO_MODE_CONTROL  0x17
+
+/* Video Formats */
+#define TU_STANDARD_CONTROL		0x00
+#define TU_STANDARD_AUTO_CONTROL	0x01
+#define TU_STANDARD_NONE		0x00
+#define TU_STANDARD_NTSC_M		0x01
+#define TU_STANDARD_PAL_I		0x08
+#define TU_STANDARD_MANUAL		0x00
+#define TU_STANDARD_AUTO		0x01
+
+/* Video Controls */
+#define PU_BRIGHTNESS_CONTROL	0x02
+#define PU_CONTRAST_CONTROL	0x03
+#define PU_HUE_CONTROL		0x06
+#define PU_SATURATION_CONTROL	0x07
+#define PU_SHARPNESS_CONTROL	0x08
+
+/* Audio Controls */
+#define MUTE_CONTROL		0x01
+#define VOLUME_CONTROL		0x02
+#define AUDIO_DEFAULT_CONTROL	0x0D
+
+/* Default Volume Levels */
+#define TMHW_LEV_ADJ_DECLEV_DEFAULT     0x00
+#define TMHW_LEV_ADJ_MONOLEV_DEFAULT    0x00
+#define TMHW_LEV_ADJ_NICLEV_DEFAULT     0x00
+#define TMHW_LEV_ADJ_SAPLEV_DEFAULT     0x00
+#define TMHW_LEV_ADJ_ADCLEV_DEFAULT     0x00
+
+/* Encoder Related Commands */
+#define EU_PROFILE_CONTROL		0x00
+#define EU_VIDEO_FORMAT_CONTROL		0x01
+#define EU_VIDEO_BIT_RATE_CONTROL	0x02
+#define EU_VIDEO_RESOLUTION_CONTROL	0x03
+#define EU_VIDEO_GOP_STRUCTURE_CONTROL	0x04
+#define EU_VIDEO_INPUT_ASPECT_CONTROL	0x0A
+#define EU_AUDIO_FORMAT_CONTROL		0x0C
+#define EU_AUDIO_BIT_RATE_CONTROL	0x0D
+
+/* Firmware Debugging */
+#define SET_DEBUG_LEVEL_CONTROL	0x0B
+#define GET_DEBUG_DATA_CONTROL	0x0C
diff --git a/drivers/media/pci/saa7164/saa7164-types.h b/drivers/media/pci/saa7164/saa7164-types.h
new file mode 100644
index 0000000..1d2140a
--- /dev/null
+++ b/drivers/media/pci/saa7164/saa7164-types.h
@@ -0,0 +1,442 @@
+/*
+ *  Driver for the NXP SAA7164 PCIe bridge
+ *
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* TODO: Cleanup and shorten the namespace */
+
+/* Some structues are passed directly to/from the firmware and
+ * have strict alignment requirements. This is one of them.
+ */
+struct tmComResHWDescr {
+	u8	bLength;
+	u8	bDescriptorType;
+	u8	bDescriptorSubtype;
+	u16	bcdSpecVersion;
+	u32	dwClockFrequency;
+	u32	dwClockUpdateRes;
+	u8	bCapabilities;
+	u32	dwDeviceRegistersLocation;
+	u32	dwHostMemoryRegion;
+	u32	dwHostMemoryRegionSize;
+	u32	dwHostHibernatMemRegion;
+	u32	dwHostHibernatMemRegionSize;
+} __attribute__((packed));
+
+/* This is DWORD aligned on windows but I can't find the right
+ * gcc syntax to match the binary data from the device.
+ * I've manually padded with Reserved[3] bytes to match the hardware,
+ * but this could break if GCC decies to pack in a different way.
+ */
+struct tmComResInterfaceDescr {
+	u8	bLength;
+	u8	bDescriptorType;
+	u8	bDescriptorSubtype;
+	u8	bFlags;
+	u8	bInterfaceType;
+	u8	bInterfaceId;
+	u8	bBaseInterface;
+	u8	bInterruptId;
+	u8	bDebugInterruptId;
+	u8	BARLocation;
+	u8	Reserved[3];
+};
+
+struct tmComResBusDescr {
+	u64	CommandRing;
+	u64	ResponseRing;
+	u32	CommandWrite;
+	u32	CommandRead;
+	u32	ResponseWrite;
+	u32	ResponseRead;
+};
+
+enum tmBusType {
+	NONE		= 0,
+	TYPE_BUS_PCI	= 1,
+	TYPE_BUS_PCIe	= 2,
+	TYPE_BUS_USB	= 3,
+	TYPE_BUS_I2C	= 4
+};
+
+struct tmComResBusInfo {
+	enum tmBusType Type;
+	u16	m_wMaxReqSize;
+	u8	*m_pdwSetRing;
+	u32	m_dwSizeSetRing;
+	u8	*m_pdwGetRing;
+	u32	m_dwSizeGetRing;
+	u32	m_dwSetWritePos;
+	u32	m_dwSetReadPos;
+	u32	m_dwGetWritePos;
+	u32	m_dwGetReadPos;
+
+	/* All access is protected */
+	struct mutex lock;
+
+};
+
+struct tmComResInfo {
+	u8	id;
+	u8	flags;
+	u16	size;
+	u32	command;
+	u16	controlselector;
+	u8	seqno;
+} __attribute__((packed));
+
+enum tmComResCmd {
+	SET_CUR  = 0x01,
+	GET_CUR  = 0x81,
+	GET_MIN  = 0x82,
+	GET_MAX  = 0x83,
+	GET_RES  = 0x84,
+	GET_LEN  = 0x85,
+	GET_INFO = 0x86,
+	GET_DEF  = 0x87
+};
+
+struct cmd {
+	u8 seqno;
+	u32 inuse;
+	u32 timeout;
+	u32 signalled;
+	struct mutex lock;
+	wait_queue_head_t wait;
+};
+
+struct tmDescriptor {
+	u32	pathid;
+	u32	size;
+	void	*descriptor;
+};
+
+struct tmComResDescrHeader {
+	u8	len;
+	u8	type;
+	u8	subtype;
+	u8	unitid;
+} __attribute__((packed));
+
+struct tmComResExtDevDescrHeader {
+	u8	len;
+	u8	type;
+	u8	subtype;
+	u8	unitid;
+	u32	devicetype;
+	u16	deviceid;
+	u32	numgpiopins;
+	u8	numgpiogroups;
+	u8	controlsize;
+} __attribute__((packed));
+
+struct tmComResGPIO {
+	u32	pin;
+	u8	state;
+} __attribute__((packed));
+
+struct tmComResPathDescrHeader {
+	u8	len;
+	u8	type;
+	u8	subtype;
+	u8	pathid;
+} __attribute__((packed));
+
+/* terminaltype */
+enum tmComResTermType {
+	ITT_ANTENNA              = 0x0203,
+	LINE_CONNECTOR           = 0x0603,
+	SPDIF_CONNECTOR          = 0x0605,
+	COMPOSITE_CONNECTOR      = 0x0401,
+	SVIDEO_CONNECTOR         = 0x0402,
+	COMPONENT_CONNECTOR      = 0x0403,
+	STANDARD_DMA             = 0xF101
+};
+
+struct tmComResAntTermDescrHeader {
+	u8	len;
+	u8	type;
+	u8	subtype;
+	u8	terminalid;
+	u16	terminaltype;
+	u8	assocterminal;
+	u8	iterminal;
+	u8	controlsize;
+} __attribute__((packed));
+
+struct tmComResTunerDescrHeader {
+	u8	len;
+	u8	type;
+	u8	subtype;
+	u8	unitid;
+	u8	sourceid;
+	u8	iunit;
+	u32	tuningstandards;
+	u8	controlsize;
+	u32	controls;
+} __attribute__((packed));
+
+enum tmBufferFlag {
+	/* the buffer does not contain any valid data */
+	TM_BUFFER_FLAG_EMPTY,
+
+	/* the buffer is filled with valid data */
+	TM_BUFFER_FLAG_DONE,
+
+	/* the buffer is the dummy buffer - TODO??? */
+	TM_BUFFER_FLAG_DUMMY_BUFFER
+};
+
+struct tmBuffer {
+	u64		*pagetablevirt;
+	u64		pagetablephys;
+	u16		offset;
+	u8		*context;
+	u64		timestamp;
+	enum tmBufferFlag BufferFlag;
+	u32		lostbuffers;
+	u32		validbuffers;
+	u64		*dummypagevirt;
+	u64		dummypagephys;
+	u64		*addressvirt;
+};
+
+struct tmHWStreamParameters {
+	u32	bitspersample;
+	u32	samplesperline;
+	u32	numberoflines;
+	u32	pitch;
+	u32	linethreshold;
+	u64	**pagetablelistvirt;
+	u64	*pagetablelistphys;
+	u32	numpagetables;
+	u32	numpagetableentries;
+};
+
+struct tmStreamParameters {
+	struct tmHWStreamParameters	HWStreamParameters;
+	u64				qwDummyPageTablePhys;
+	u64				*pDummyPageTableVirt;
+};
+
+struct tmComResDMATermDescrHeader {
+	u8	len;
+	u8	type;
+	u8	subtyle;
+	u8	unitid;
+	u16	terminaltype;
+	u8	assocterminal;
+	u8	sourceid;
+	u8	iterminal;
+	u32	BARLocation;
+	u8	flags;
+	u8	interruptid;
+	u8	buffercount;
+	u8	metadatasize;
+	u8	numformats;
+	u8	controlsize;
+} __attribute__((packed));
+
+/*
+ *
+ * Description:
+ *  This is the transport stream format header.
+ *
+ * Settings:
+ *  bLength                 - The size of this descriptor in bytes.
+ *  bDescriptorType         - CS_INTERFACE.
+ *  bDescriptorSubtype      - VS_FORMAT_MPEG2TS descriptor subtype.
+ *  bFormatIndex            - A non-zero constant that uniquely identifies the
+ *                            format.
+ *  bDataOffset             - Offset to TSP packet within MPEG-2 TS transport
+ *                            stride, in bytes.
+ *  bPacketLength           - Length of TSP packet, in bytes (typically 188).
+ *  bStrideLength           - Length of MPEG-2 TS transport stride.
+ *  guidStrideFormat        - A Globally Unique Identifier indicating the
+ *                            format of the stride data (if any). Set to zeros
+ *                            if there is no Stride Data, or if the Stride
+ *                            Data is to be ignored by the application.
+ *
+ */
+struct tmComResTSFormatDescrHeader {
+	u8	len;
+	u8	type;
+	u8	subtype;
+	u8	bFormatIndex;
+	u8	bDataOffset;
+	u8	bPacketLength;
+	u8	bStrideLength;
+	u8	guidStrideFormat[16];
+} __attribute__((packed));
+
+/* Encoder related structures */
+
+/* A/V Mux Selector */
+struct tmComResSelDescrHeader {
+	u8	len;
+	u8	type;
+	u8	subtype;
+	u8	unitid;
+	u8	nrinpins;
+	u8	sourceid;
+} __attribute__((packed));
+
+/* A/V Audio processor definitions */
+struct tmComResProcDescrHeader {
+	u8	len;
+	u8	type;
+	u8	subtype;
+	u8	unitid;
+	u8	sourceid;
+	u16	wreserved;
+	u8	controlsize;
+} __attribute__((packed));
+
+/* Video bitrate control message */
+#define EU_VIDEO_BIT_RATE_MODE_CONSTANT		(0)
+#define EU_VIDEO_BIT_RATE_MODE_VARIABLE_AVERAGE (1)
+#define EU_VIDEO_BIT_RATE_MODE_VARIABLE_PEAK	(2)
+struct tmComResEncVideoBitRate {
+	u8	ucVideoBitRateMode;
+	u32	dwVideoBitRate;
+	u32	dwVideoBitRatePeak;
+} __attribute__((packed));
+
+/* Video Encoder Aspect Ratio message */
+struct tmComResEncVideoInputAspectRatio {
+	u8	width;
+	u8	height;
+} __attribute__((packed));
+
+/* Video Encoder GOP IBP message */
+/* 1. IPPPPPPPPPPPPPP */
+/* 2. IBPBPBPBPBPBPBP */
+/* 3. IBBPBBPBBPBBP   */
+#define SAA7164_ENCODER_DEFAULT_GOP_DIST (1)
+#define SAA7164_ENCODER_DEFAULT_GOP_SIZE (15)
+struct tmComResEncVideoGopStructure {
+	u8	ucGOPSize;	/* GOP Size 12, 15 */
+	u8	ucRefFrameDist; /* Reference Frame Distance */
+} __attribute__((packed));
+
+/* Encoder processor definition */
+struct tmComResEncoderDescrHeader {
+	u8	len;
+	u8	type;
+	u8	subtype;
+	u8	unitid;
+	u8	vsourceid;
+	u8	asourceid;
+	u8	iunit;
+	u32	dwmControlCap;
+	u32	dwmProfileCap;
+	u32	dwmVidFormatCap;
+	u8	bmVidBitrateCap;
+	u16	wmVidResolutionsCap;
+	u16	wmVidFrmRateCap;
+	u32	dwmAudFormatCap;
+	u8	bmAudBitrateCap;
+} __attribute__((packed));
+
+/* Audio processor definition */
+struct tmComResAFeatureDescrHeader {
+	u8	len;
+	u8	type;
+	u8	subtype;
+	u8	unitid;
+	u8	sourceid;
+	u8	controlsize;
+} __attribute__((packed));
+
+/* Audio control messages */
+struct tmComResAudioDefaults {
+	u8	ucDecoderLevel;
+	u8	ucDecoderFM_Level;
+	u8	ucMonoLevel;
+	u8	ucNICAM_Level;
+	u8	ucSAP_Level;
+	u8	ucADC_Level;
+} __attribute__((packed));
+
+/* Audio bitrate control message */
+struct tmComResEncAudioBitRate {
+	u8	ucAudioBitRateMode;
+	u32	dwAudioBitRate;
+	u32	dwAudioBitRatePeak;
+} __attribute__((packed));
+
+/* Tuner / AV Decoder messages */
+struct tmComResTunerStandard {
+	u8	std;
+	u32	country;
+} __attribute__((packed));
+
+struct tmComResTunerStandardAuto {
+	u8	mode;
+} __attribute__((packed));
+
+/* EEPROM definition for PS stream types */
+struct tmComResPSFormatDescrHeader {
+	u8	len;
+	u8	type;
+	u8	subtype;
+	u8	bFormatIndex;
+	u16	wPacketLength;
+	u16	wPackLength;
+	u8	bPackDataType;
+} __attribute__((packed));
+
+/* VBI control structure */
+struct tmComResVBIFormatDescrHeader {
+	u8	len;
+	u8	type;
+	u8	subtype; /* VS_FORMAT_VBI */
+	u8	bFormatIndex;
+	u32	VideoStandard; /* See KS_AnalogVideoStandard, NTSC = 1 */
+	u8	StartLine; /* NTSC Start = 10 */
+	u8	EndLine; /* NTSC = 21 */
+	u8	FieldRate; /* 60 for NTSC */
+	u8	bNumLines; /* Unused - scheduled for removal */
+} __attribute__((packed));
+
+struct tmComResProbeCommit {
+	u16	bmHint;
+	u8	bFormatIndex;
+	u8	bFrameIndex;
+} __attribute__((packed));
+
+struct tmComResDebugSetLevel {
+	u32	dwDebugLevel;
+} __attribute__((packed));
+
+struct tmComResDebugGetData {
+	u32	dwResult;
+	u8	ucDebugData[256];
+} __attribute__((packed));
+
+struct tmFwInfoStruct {
+	u32	status;
+	u32	mode;
+	u32	devicespec;
+	u32	deviceinst;
+	u32	CPULoad;
+	u32	RemainHeap;
+	u32	CPUClock;
+	u32	RAMSpeed;
+} __attribute__((packed));
diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c
new file mode 100644
index 0000000..d8e6c8f
--- /dev/null
+++ b/drivers/media/pci/saa7164/saa7164-vbi.c
@@ -0,0 +1,1374 @@
+/*
+ *  Driver for the NXP SAA7164 PCIe bridge
+ *
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "saa7164.h"
+
+static struct saa7164_tvnorm saa7164_tvnorms[] = {
+	{
+		.name      = "NTSC-M",
+		.id        = V4L2_STD_NTSC_M,
+	}, {
+		.name      = "NTSC-JP",
+		.id        = V4L2_STD_NTSC_M_JP,
+	}
+};
+
+static const u32 saa7164_v4l2_ctrls[] = {
+	0
+};
+
+/* Take the encoder configuration from the port struct and
+ * flush it to the hardware.
+ */
+static void saa7164_vbi_configure(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+	port->vbi_params.width = port->width;
+	port->vbi_params.height = port->height;
+	port->vbi_params.is_50hz =
+		(port->encodernorm.id & V4L2_STD_625_50) != 0;
+
+	/* Set up the DIF (enable it) for analog mode by default */
+	saa7164_api_initialize_dif(port);
+
+	/* Configure the correct video standard */
+#if 0
+	saa7164_api_configure_dif(port, port->encodernorm.id);
+#endif
+
+#if 0
+	/* Ensure the audio decoder is correct configured */
+	saa7164_api_set_audio_std(port);
+#endif
+	dprintk(DBGLVL_VBI, "%s() ends\n", __func__);
+}
+
+static int saa7164_vbi_buffers_dealloc(struct saa7164_port *port)
+{
+	struct list_head *c, *n, *p, *q, *l, *v;
+	struct saa7164_dev *dev = port->dev;
+	struct saa7164_buffer *buf;
+	struct saa7164_user_buffer *ubuf;
+
+	/* Remove any allocated buffers */
+	mutex_lock(&port->dmaqueue_lock);
+
+	dprintk(DBGLVL_VBI, "%s(port=%d) dmaqueue\n", __func__, port->nr);
+	list_for_each_safe(c, n, &port->dmaqueue.list) {
+		buf = list_entry(c, struct saa7164_buffer, list);
+		list_del(c);
+		saa7164_buffer_dealloc(buf);
+	}
+
+	dprintk(DBGLVL_VBI, "%s(port=%d) used\n", __func__, port->nr);
+	list_for_each_safe(p, q, &port->list_buf_used.list) {
+		ubuf = list_entry(p, struct saa7164_user_buffer, list);
+		list_del(p);
+		saa7164_buffer_dealloc_user(ubuf);
+	}
+
+	dprintk(DBGLVL_VBI, "%s(port=%d) free\n", __func__, port->nr);
+	list_for_each_safe(l, v, &port->list_buf_free.list) {
+		ubuf = list_entry(l, struct saa7164_user_buffer, list);
+		list_del(l);
+		saa7164_buffer_dealloc_user(ubuf);
+	}
+
+	mutex_unlock(&port->dmaqueue_lock);
+	dprintk(DBGLVL_VBI, "%s(port=%d) done\n", __func__, port->nr);
+
+	return 0;
+}
+
+/* Dynamic buffer switch at vbi start time */
+static int saa7164_vbi_buffers_alloc(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	struct saa7164_buffer *buf;
+	struct saa7164_user_buffer *ubuf;
+	struct tmHWStreamParameters *params = &port->hw_streamingparams;
+	int result = -ENODEV, i;
+	int len = 0;
+
+	dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+	/* TODO: NTSC SPECIFIC */
+	/* Init and establish defaults */
+	params->samplesperline = 1440;
+	params->numberoflines = 12;
+	params->numberoflines = 18;
+	params->pitch = 1600;
+	params->pitch = 1440;
+	params->numpagetables = 2 +
+		((params->numberoflines * params->pitch) / PAGE_SIZE);
+	params->bitspersample = 8;
+	params->linethreshold = 0;
+	params->pagetablelistvirt = NULL;
+	params->pagetablelistphys = NULL;
+	params->numpagetableentries = port->hwcfg.buffercount;
+
+	/* Allocate the PCI resources, buffers (hard) */
+	for (i = 0; i < port->hwcfg.buffercount; i++) {
+		buf = saa7164_buffer_alloc(port,
+			params->numberoflines *
+			params->pitch);
+
+		if (!buf) {
+			printk(KERN_ERR "%s() failed "
+			       "(errno = %d), unable to allocate buffer\n",
+				__func__, result);
+			result = -ENOMEM;
+			goto failed;
+		} else {
+
+			mutex_lock(&port->dmaqueue_lock);
+			list_add_tail(&buf->list, &port->dmaqueue.list);
+			mutex_unlock(&port->dmaqueue_lock);
+
+		}
+	}
+
+	/* Allocate some kernel buffers for copying
+	 * to userpsace.
+	 */
+	len = params->numberoflines * params->pitch;
+
+	if (vbi_buffers < 16)
+		vbi_buffers = 16;
+	if (vbi_buffers > 512)
+		vbi_buffers = 512;
+
+	for (i = 0; i < vbi_buffers; i++) {
+
+		ubuf = saa7164_buffer_alloc_user(dev, len);
+		if (ubuf) {
+			mutex_lock(&port->dmaqueue_lock);
+			list_add_tail(&ubuf->list, &port->list_buf_free.list);
+			mutex_unlock(&port->dmaqueue_lock);
+		}
+
+	}
+
+	result = 0;
+
+failed:
+	return result;
+}
+
+
+static int saa7164_vbi_initialize(struct saa7164_port *port)
+{
+	saa7164_vbi_configure(port);
+	return 0;
+}
+
+/* -- V4L2 --------------------------------------------------------- */
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct saa7164_vbi_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+	unsigned int i;
+
+	dprintk(DBGLVL_VBI, "%s(id=0x%x)\n", __func__, (u32)*id);
+
+	for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) {
+		if (*id & saa7164_tvnorms[i].id)
+			break;
+	}
+	if (i == ARRAY_SIZE(saa7164_tvnorms))
+		return -EINVAL;
+
+	port->encodernorm = saa7164_tvnorms[i];
+
+	/* Update the audio decoder while is not running in
+	 * auto detect mode.
+	 */
+	saa7164_api_set_audio_std(port);
+
+	dprintk(DBGLVL_VBI, "%s(id=0x%x) OK\n", __func__, (u32)*id);
+
+	return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+	struct v4l2_input *i)
+{
+	int n;
+
+	char *inputs[] = { "tuner", "composite", "svideo", "aux",
+		"composite 2", "svideo 2", "aux 2" };
+
+	if (i->index >= 7)
+		return -EINVAL;
+
+	strcpy(i->name, inputs[i->index]);
+
+	if (i->index == 0)
+		i->type = V4L2_INPUT_TYPE_TUNER;
+	else
+		i->type  = V4L2_INPUT_TYPE_CAMERA;
+
+	for (n = 0; n < ARRAY_SIZE(saa7164_tvnorms); n++)
+		i->std |= saa7164_tvnorms[n].id;
+
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct saa7164_vbi_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	if (saa7164_api_get_videomux(port) != SAA_OK)
+		return -EIO;
+
+	*i = (port->mux_input - 1);
+
+	dprintk(DBGLVL_VBI, "%s() input=%d\n", __func__, *i);
+
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct saa7164_vbi_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	dprintk(DBGLVL_VBI, "%s() input=%d\n", __func__, i);
+
+	if (i >= 7)
+		return -EINVAL;
+
+	port->mux_input = i + 1;
+
+	if (saa7164_api_set_videomux(port) != SAA_OK)
+		return -EIO;
+
+	return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+	struct v4l2_tuner *t)
+{
+	struct saa7164_vbi_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	if (0 != t->index)
+		return -EINVAL;
+
+	strcpy(t->name, "tuner");
+	t->type = V4L2_TUNER_ANALOG_TV;
+	t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO;
+
+	dprintk(DBGLVL_VBI, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
+
+	return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+	struct v4l2_tuner *t)
+{
+	/* Update the A/V core */
+	return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+	struct v4l2_frequency *f)
+{
+	struct saa7164_vbi_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+
+	f->type = V4L2_TUNER_ANALOG_TV;
+	f->frequency = port->freq;
+
+	return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+	struct v4l2_frequency *f)
+{
+	struct saa7164_vbi_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+	struct saa7164_port *tsport;
+	struct dvb_frontend *fe;
+
+	/* TODO: Pull this for the std */
+	struct analog_parameters params = {
+		.mode      = V4L2_TUNER_ANALOG_TV,
+		.audmode   = V4L2_TUNER_MODE_STEREO,
+		.std       = port->encodernorm.id,
+		.frequency = f->frequency
+	};
+
+	/* Stop the encoder */
+	dprintk(DBGLVL_VBI, "%s() frequency=%d tuner=%d\n", __func__,
+		f->frequency, f->tuner);
+
+	if (f->tuner != 0)
+		return -EINVAL;
+
+	if (f->type != V4L2_TUNER_ANALOG_TV)
+		return -EINVAL;
+
+	port->freq = f->frequency;
+
+	/* Update the hardware */
+	if (port->nr == SAA7164_PORT_VBI1)
+		tsport = &dev->ports[SAA7164_PORT_TS1];
+	else
+	if (port->nr == SAA7164_PORT_VBI2)
+		tsport = &dev->ports[SAA7164_PORT_TS2];
+	else
+		BUG();
+
+	fe = tsport->dvb.frontend;
+
+	if (fe && fe->ops.tuner_ops.set_analog_params)
+		fe->ops.tuner_ops.set_analog_params(fe, &params);
+	else
+		printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__);
+
+	saa7164_vbi_initialize(port);
+
+	return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+	struct v4l2_control *ctl)
+{
+	struct saa7164_vbi_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	dprintk(DBGLVL_VBI, "%s(id=%d, value=%d)\n", __func__,
+		ctl->id, ctl->value);
+
+	switch (ctl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		ctl->value = port->ctl_brightness;
+		break;
+	case V4L2_CID_CONTRAST:
+		ctl->value = port->ctl_contrast;
+		break;
+	case V4L2_CID_SATURATION:
+		ctl->value = port->ctl_saturation;
+		break;
+	case V4L2_CID_HUE:
+		ctl->value = port->ctl_hue;
+		break;
+	case V4L2_CID_SHARPNESS:
+		ctl->value = port->ctl_sharpness;
+		break;
+	case V4L2_CID_AUDIO_VOLUME:
+		ctl->value = port->ctl_volume;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+	struct v4l2_control *ctl)
+{
+	struct saa7164_vbi_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+	int ret = 0;
+
+	dprintk(DBGLVL_VBI, "%s(id=%d, value=%d)\n", __func__,
+		ctl->id, ctl->value);
+
+	switch (ctl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		if ((ctl->value >= 0) && (ctl->value <= 255)) {
+			port->ctl_brightness = ctl->value;
+			saa7164_api_set_usercontrol(port,
+				PU_BRIGHTNESS_CONTROL);
+		} else
+			ret = -EINVAL;
+		break;
+	case V4L2_CID_CONTRAST:
+		if ((ctl->value >= 0) && (ctl->value <= 255)) {
+			port->ctl_contrast = ctl->value;
+			saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL);
+		} else
+			ret = -EINVAL;
+		break;
+	case V4L2_CID_SATURATION:
+		if ((ctl->value >= 0) && (ctl->value <= 255)) {
+			port->ctl_saturation = ctl->value;
+			saa7164_api_set_usercontrol(port,
+				PU_SATURATION_CONTROL);
+		} else
+			ret = -EINVAL;
+		break;
+	case V4L2_CID_HUE:
+		if ((ctl->value >= 0) && (ctl->value <= 255)) {
+			port->ctl_hue = ctl->value;
+			saa7164_api_set_usercontrol(port, PU_HUE_CONTROL);
+		} else
+			ret = -EINVAL;
+		break;
+	case V4L2_CID_SHARPNESS:
+		if ((ctl->value >= 0) && (ctl->value <= 255)) {
+			port->ctl_sharpness = ctl->value;
+			saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL);
+		} else
+			ret = -EINVAL;
+		break;
+	case V4L2_CID_AUDIO_VOLUME:
+		if ((ctl->value >= -83) && (ctl->value <= 24)) {
+			port->ctl_volume = ctl->value;
+			saa7164_api_set_audio_volume(port, port->ctl_volume);
+		} else
+			ret = -EINVAL;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int saa7164_get_ctrl(struct saa7164_port *port,
+	struct v4l2_ext_control *ctrl)
+{
+	struct saa7164_vbi_params *params = &port->vbi_params;
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		ctrl->value = params->stream_type;
+		break;
+	case V4L2_CID_MPEG_AUDIO_MUTE:
+		ctrl->value = params->ctl_mute;
+		break;
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		ctrl->value = params->ctl_aspect;
+		break;
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+		ctrl->value = params->refdist;
+		break;
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+		ctrl->value = params->gop_size;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+	struct v4l2_ext_controls *ctrls)
+{
+	struct saa7164_vbi_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	int i, err = 0;
+
+	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+		for (i = 0; i < ctrls->count; i++) {
+			struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+			err = saa7164_get_ctrl(port, ctrl);
+			if (err) {
+				ctrls->error_idx = i;
+				break;
+			}
+		}
+		return err;
+
+	}
+
+	return -EINVAL;
+}
+
+static int saa7164_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
+{
+	int ret = -EINVAL;
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		if ((ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) ||
+			(ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS))
+			ret = 0;
+		break;
+	case V4L2_CID_MPEG_AUDIO_MUTE:
+		if ((ctrl->value >= 0) &&
+			(ctrl->value <= 1))
+			ret = 0;
+		break;
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		if ((ctrl->value >= V4L2_MPEG_VIDEO_ASPECT_1x1) &&
+			(ctrl->value <= V4L2_MPEG_VIDEO_ASPECT_221x100))
+			ret = 0;
+		break;
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+		if ((ctrl->value >= 0) &&
+			(ctrl->value <= 255))
+			ret = 0;
+		break;
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+		if ((ctrl->value >= 1) &&
+			(ctrl->value <= 3))
+			ret = 0;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+	struct v4l2_ext_controls *ctrls)
+{
+	int i, err = 0;
+
+	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+		for (i = 0; i < ctrls->count; i++) {
+			struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+			err = saa7164_try_ctrl(ctrl, 0);
+			if (err) {
+				ctrls->error_idx = i;
+				break;
+			}
+		}
+		return err;
+	}
+
+	return -EINVAL;
+}
+
+static int saa7164_set_ctrl(struct saa7164_port *port,
+	struct v4l2_ext_control *ctrl)
+{
+	struct saa7164_vbi_params *params = &port->vbi_params;
+	int ret = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		params->stream_type = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_AUDIO_MUTE:
+		params->ctl_mute = ctrl->value;
+		ret = saa7164_api_audio_mute(port, params->ctl_mute);
+		if (ret != SAA_OK) {
+			printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
+				ret);
+			ret = -EIO;
+		}
+		break;
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		params->ctl_aspect = ctrl->value;
+		ret = saa7164_api_set_aspect_ratio(port);
+		if (ret != SAA_OK) {
+			printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
+				ret);
+			ret = -EIO;
+		}
+		break;
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+		params->refdist = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+		params->gop_size = ctrl->value;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* TODO: Update the hardware */
+
+	return ret;
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+	struct v4l2_ext_controls *ctrls)
+{
+	struct saa7164_vbi_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	int i, err = 0;
+
+	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+		for (i = 0; i < ctrls->count; i++) {
+			struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+			err = saa7164_try_ctrl(ctrl, 0);
+			if (err) {
+				ctrls->error_idx = i;
+				break;
+			}
+			err = saa7164_set_ctrl(port, ctrl);
+			if (err) {
+				ctrls->error_idx = i;
+				break;
+			}
+		}
+		return err;
+
+	}
+
+	return -EINVAL;
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+	struct v4l2_capability *cap)
+{
+	struct saa7164_vbi_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	strcpy(cap->driver, dev->name);
+	strlcpy(cap->card, saa7164_boards[dev->board].name,
+		sizeof(cap->card));
+	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+
+	cap->capabilities =
+		V4L2_CAP_VBI_CAPTURE |
+		V4L2_CAP_READWRITE     |
+		0;
+
+	cap->capabilities |= V4L2_CAP_TUNER;
+	cap->version = 0;
+
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+	struct v4l2_fmtdesc *f)
+{
+	if (f->index != 0)
+		return -EINVAL;
+
+	strlcpy(f->description, "VBI", sizeof(f->description));
+	f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct saa7164_vbi_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage    =
+		port->ts_packet_size * port->ts_packet_count;
+	f->fmt.pix.colorspace   = 0;
+	f->fmt.pix.width        = port->width;
+	f->fmt.pix.height       = port->height;
+
+	dprintk(DBGLVL_VBI, "VIDIOC_G_FMT: w: %d, h: %d\n",
+		port->width, port->height);
+
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct saa7164_vbi_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage    =
+		port->ts_packet_size * port->ts_packet_count;
+	f->fmt.pix.colorspace   = 0;
+	dprintk(DBGLVL_VBI, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
+		port->width, port->height);
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct saa7164_vbi_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage    =
+		port->ts_packet_size * port->ts_packet_count;
+	f->fmt.pix.colorspace   = 0;
+
+	dprintk(DBGLVL_VBI, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+		f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+
+	return 0;
+}
+
+static int fill_queryctrl(struct saa7164_vbi_params *params,
+	struct v4l2_queryctrl *c)
+{
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 127);
+	case V4L2_CID_CONTRAST:
+		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 66);
+	case V4L2_CID_SATURATION:
+		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 62);
+	case V4L2_CID_HUE:
+		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 128);
+	case V4L2_CID_SHARPNESS:
+		return v4l2_ctrl_query_fill(c, 0x0, 0x0f, 1, 8);
+	case V4L2_CID_MPEG_AUDIO_MUTE:
+		return v4l2_ctrl_query_fill(c, 0x0, 0x01, 1, 0);
+	case V4L2_CID_AUDIO_VOLUME:
+		return v4l2_ctrl_query_fill(c, -83, 24, 1, 20);
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		return v4l2_ctrl_query_fill(c,
+			V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+			V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
+			1, V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		return v4l2_ctrl_query_fill(c,
+			V4L2_MPEG_VIDEO_ASPECT_1x1,
+			V4L2_MPEG_VIDEO_ASPECT_221x100,
+			1, V4L2_MPEG_VIDEO_ASPECT_4x3);
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+		return v4l2_ctrl_query_fill(c, 1, 255, 1, 15);
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+		return v4l2_ctrl_query_fill(c,
+			1, 3, 1, 1);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+	struct v4l2_queryctrl *c)
+{
+	struct saa7164_vbi_fh *fh = priv;
+	struct saa7164_port *port = fh->port;
+	int i, next;
+	u32 id = c->id;
+
+	memset(c, 0, sizeof(*c));
+
+	next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL);
+	c->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
+
+	for (i = 0; i < ARRAY_SIZE(saa7164_v4l2_ctrls); i++) {
+		if (next) {
+			if (c->id < saa7164_v4l2_ctrls[i])
+				c->id = saa7164_v4l2_ctrls[i];
+			else
+				continue;
+		}
+
+		if (c->id == saa7164_v4l2_ctrls[i])
+			return fill_queryctrl(&port->vbi_params, c);
+
+		if (c->id < saa7164_v4l2_ctrls[i])
+			break;
+	}
+
+	return -EINVAL;
+}
+
+static int saa7164_vbi_stop_port(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	int ret;
+
+	ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n",
+			__func__, ret);
+		ret = -EIO;
+	} else {
+		dprintk(DBGLVL_VBI, "%s()    Stopped\n", __func__);
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static int saa7164_vbi_acquire_port(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	int ret;
+
+	ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
+	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n",
+			__func__, ret);
+		ret = -EIO;
+	} else {
+		dprintk(DBGLVL_VBI, "%s() Acquired\n", __func__);
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static int saa7164_vbi_pause_port(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	int ret;
+
+	ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
+	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n",
+			__func__, ret);
+		ret = -EIO;
+	} else {
+		dprintk(DBGLVL_VBI, "%s()   Paused\n", __func__);
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/* Firmware is very windows centric, meaning you have to transition
+ * the part through AVStream / KS Windows stages, forwards or backwards.
+ * States are: stopped, acquired (h/w), paused, started.
+ * We have to leave here will all of the soft buffers on the free list,
+ * else the cfg_post() func won't have soft buffers to correctly configure.
+ */
+static int saa7164_vbi_stop_streaming(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	struct saa7164_buffer *buf;
+	struct saa7164_user_buffer *ubuf;
+	struct list_head *c, *n;
+	int ret;
+
+	dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);
+
+	ret = saa7164_vbi_pause_port(port);
+	ret = saa7164_vbi_acquire_port(port);
+	ret = saa7164_vbi_stop_port(port);
+
+	dprintk(DBGLVL_VBI, "%s(port=%d) Hardware stopped\n", __func__,
+		port->nr);
+
+	/* Reset the state of any allocated buffer resources */
+	mutex_lock(&port->dmaqueue_lock);
+
+	/* Reset the hard and soft buffer state */
+	list_for_each_safe(c, n, &port->dmaqueue.list) {
+		buf = list_entry(c, struct saa7164_buffer, list);
+		buf->flags = SAA7164_BUFFER_FREE;
+		buf->pos = 0;
+	}
+
+	list_for_each_safe(c, n, &port->list_buf_used.list) {
+		ubuf = list_entry(c, struct saa7164_user_buffer, list);
+		ubuf->pos = 0;
+		list_move_tail(&ubuf->list, &port->list_buf_free.list);
+	}
+
+	mutex_unlock(&port->dmaqueue_lock);
+
+	/* Free any allocated resources */
+	saa7164_vbi_buffers_dealloc(port);
+
+	dprintk(DBGLVL_VBI, "%s(port=%d) Released\n", __func__, port->nr);
+
+	return ret;
+}
+
+static int saa7164_vbi_start_streaming(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	int result, ret = 0;
+
+	dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);
+
+	port->done_first_interrupt = 0;
+
+	/* allocate all of the PCIe DMA buffer resources on the fly,
+	 * allowing switching between TS and PS payloads without
+	 * requiring a complete driver reload.
+	 */
+	saa7164_vbi_buffers_alloc(port);
+
+	/* Configure the encoder with any cache values */
+#if 0
+	saa7164_api_set_encoder(port);
+	saa7164_api_get_encoder(port);
+#endif
+
+	/* Place the empty buffers on the hardware */
+	saa7164_buffer_cfg_port(port);
+
+	/* Negotiate format */
+	if (saa7164_api_set_vbi_format(port) != SAA_OK) {
+		printk(KERN_ERR "%s() No supported VBI format\n", __func__);
+		ret = -EIO;
+		goto out;
+	}
+
+	/* Acquire the hardware */
+	result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
+	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n",
+			__func__, result);
+
+		ret = -EIO;
+		goto out;
+	} else
+		dprintk(DBGLVL_VBI, "%s()   Acquired\n", __func__);
+
+	/* Pause the hardware */
+	result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
+	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n",
+				__func__, result);
+
+		/* Stop the hardware, regardless */
+		result = saa7164_vbi_stop_port(port);
+		if (result != SAA_OK) {
+			printk(KERN_ERR "%s() pause/forced stop transition "
+				"failed, res = 0x%x\n", __func__, result);
+		}
+
+		ret = -EIO;
+		goto out;
+	} else
+		dprintk(DBGLVL_VBI, "%s()   Paused\n", __func__);
+
+	/* Start the hardware */
+	result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN);
+	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+		printk(KERN_ERR "%s() run transition failed, result = 0x%x\n",
+				__func__, result);
+
+		/* Stop the hardware, regardless */
+		result = saa7164_vbi_acquire_port(port);
+		result = saa7164_vbi_stop_port(port);
+		if (result != SAA_OK) {
+			printk(KERN_ERR "%s() run/forced stop transition "
+				"failed, res = 0x%x\n", __func__, result);
+		}
+
+		ret = -EIO;
+	} else
+		dprintk(DBGLVL_VBI, "%s()   Running\n", __func__);
+
+out:
+	return ret;
+}
+
+int saa7164_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+	/* ntsc */
+	f->fmt.vbi.samples_per_line = 1600;
+	f->fmt.vbi.samples_per_line = 1440;
+	f->fmt.vbi.sampling_rate = 27000000;
+	f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+	f->fmt.vbi.offset = 0;
+	f->fmt.vbi.flags = 0;
+	f->fmt.vbi.start[0] = 10;
+	f->fmt.vbi.count[0] = 18;
+	f->fmt.vbi.start[1] = 263 + 10 + 1;
+	f->fmt.vbi.count[1] = 18;
+	return 0;
+}
+
+static int fops_open(struct file *file)
+{
+	struct saa7164_dev *dev;
+	struct saa7164_port *port;
+	struct saa7164_vbi_fh *fh;
+
+	port = (struct saa7164_port *)video_get_drvdata(video_devdata(file));
+	if (!port)
+		return -ENODEV;
+
+	dev = port->dev;
+
+	dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+	/* allocate + initialize per filehandle data */
+	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+	if (NULL == fh)
+		return -ENOMEM;
+
+	file->private_data = fh;
+	fh->port = port;
+
+	return 0;
+}
+
+static int fops_release(struct file *file)
+{
+	struct saa7164_vbi_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_dev *dev = port->dev;
+
+	dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+	/* Shut device down on last close */
+	if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
+		if (atomic_dec_return(&port->v4l_reader_count) == 0) {
+			/* stop vbi capture then cancel buffers */
+			saa7164_vbi_stop_streaming(port);
+		}
+	}
+
+	file->private_data = NULL;
+	kfree(fh);
+
+	return 0;
+}
+
+struct saa7164_user_buffer *saa7164_vbi_next_buf(struct saa7164_port *port)
+{
+	struct saa7164_user_buffer *ubuf = NULL;
+	struct saa7164_dev *dev = port->dev;
+	u32 crc;
+
+	mutex_lock(&port->dmaqueue_lock);
+	if (!list_empty(&port->list_buf_used.list)) {
+		ubuf = list_first_entry(&port->list_buf_used.list,
+			struct saa7164_user_buffer, list);
+
+		if (crc_checking) {
+			crc = crc32(0, ubuf->data, ubuf->actual_size);
+			if (crc != ubuf->crc) {
+				printk(KERN_ERR "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n",
+					__func__,
+					ubuf, ubuf->crc, crc);
+			}
+		}
+
+	}
+	mutex_unlock(&port->dmaqueue_lock);
+
+	dprintk(DBGLVL_VBI, "%s() returns %p\n", __func__, ubuf);
+
+	return ubuf;
+}
+
+static ssize_t fops_read(struct file *file, char __user *buffer,
+	size_t count, loff_t *pos)
+{
+	struct saa7164_vbi_fh *fh = file->private_data;
+	struct saa7164_port *port = fh->port;
+	struct saa7164_user_buffer *ubuf = NULL;
+	struct saa7164_dev *dev = port->dev;
+	int ret = 0;
+	int rem, cnt;
+	u8 *p;
+
+	port->last_read_msecs_diff = port->last_read_msecs;
+	port->last_read_msecs = jiffies_to_msecs(jiffies);
+	port->last_read_msecs_diff = port->last_read_msecs -
+		port->last_read_msecs_diff;
+
+	saa7164_histogram_update(&port->read_interval,
+		port->last_read_msecs_diff);
+
+	if (*pos) {
+		printk(KERN_ERR "%s() ESPIPE\n", __func__);
+		return -ESPIPE;
+	}
+
+	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+		if (atomic_inc_return(&port->v4l_reader_count) == 1) {
+
+			if (saa7164_vbi_initialize(port) < 0) {
+				printk(KERN_ERR "%s() EINVAL\n", __func__);
+				return -EINVAL;
+			}
+
+			saa7164_vbi_start_streaming(port);
+			msleep(200);
+		}
+	}
+
+	/* blocking wait for buffer */
+	if ((file->f_flags & O_NONBLOCK) == 0) {
+		if (wait_event_interruptible(port->wait_read,
+			saa7164_vbi_next_buf(port))) {
+				printk(KERN_ERR "%s() ERESTARTSYS\n", __func__);
+				return -ERESTARTSYS;
+		}
+	}
+
+	/* Pull the first buffer from the used list */
+	ubuf = saa7164_vbi_next_buf(port);
+
+	while ((count > 0) && ubuf) {
+
+		/* set remaining bytes to copy */
+		rem = ubuf->actual_size - ubuf->pos;
+		cnt = rem > count ? count : rem;
+
+		p = ubuf->data + ubuf->pos;
+
+		dprintk(DBGLVL_VBI,
+			"%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n",
+			__func__, (int)count, cnt, rem, ubuf, ubuf->pos);
+
+		if (copy_to_user(buffer, p, cnt)) {
+			printk(KERN_ERR "%s() copy_to_user failed\n", __func__);
+			if (!ret) {
+				printk(KERN_ERR "%s() EFAULT\n", __func__);
+				ret = -EFAULT;
+			}
+			goto err;
+		}
+
+		ubuf->pos += cnt;
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+
+		if (ubuf->pos > ubuf->actual_size)
+			printk(KERN_ERR "read() pos > actual, huh?\n");
+
+		if (ubuf->pos == ubuf->actual_size) {
+
+			/* finished with current buffer, take next buffer */
+
+			/* Requeue the buffer on the free list */
+			ubuf->pos = 0;
+
+			mutex_lock(&port->dmaqueue_lock);
+			list_move_tail(&ubuf->list, &port->list_buf_free.list);
+			mutex_unlock(&port->dmaqueue_lock);
+
+			/* Dequeue next */
+			if ((file->f_flags & O_NONBLOCK) == 0) {
+				if (wait_event_interruptible(port->wait_read,
+					saa7164_vbi_next_buf(port))) {
+						break;
+				}
+			}
+			ubuf = saa7164_vbi_next_buf(port);
+		}
+	}
+err:
+	if (!ret && !ubuf) {
+		printk(KERN_ERR "%s() EAGAIN\n", __func__);
+		ret = -EAGAIN;
+	}
+
+	return ret;
+}
+
+static unsigned int fops_poll(struct file *file, poll_table *wait)
+{
+	struct saa7164_vbi_fh *fh = (struct saa7164_vbi_fh *)file->private_data;
+	struct saa7164_port *port = fh->port;
+	unsigned int mask = 0;
+
+	port->last_poll_msecs_diff = port->last_poll_msecs;
+	port->last_poll_msecs = jiffies_to_msecs(jiffies);
+	port->last_poll_msecs_diff = port->last_poll_msecs -
+		port->last_poll_msecs_diff;
+
+	saa7164_histogram_update(&port->poll_interval,
+		port->last_poll_msecs_diff);
+
+	if (!video_is_registered(port->v4l_device))
+		return -EIO;
+
+	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+		if (atomic_inc_return(&port->v4l_reader_count) == 1) {
+			if (saa7164_vbi_initialize(port) < 0)
+				return -EINVAL;
+			saa7164_vbi_start_streaming(port);
+			msleep(200);
+		}
+	}
+
+	/* blocking wait for buffer */
+	if ((file->f_flags & O_NONBLOCK) == 0) {
+		if (wait_event_interruptible(port->wait_read,
+			saa7164_vbi_next_buf(port))) {
+				return -ERESTARTSYS;
+		}
+	}
+
+	/* Pull the first buffer from the used list */
+	if (!list_empty(&port->list_buf_used.list))
+		mask |= POLLIN | POLLRDNORM;
+
+	return mask;
+}
+static const struct v4l2_file_operations vbi_fops = {
+	.owner		= THIS_MODULE,
+	.open		= fops_open,
+	.release	= fops_release,
+	.read		= fops_read,
+	.poll		= fops_poll,
+	.unlocked_ioctl	= video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
+	.vidioc_s_std		 = vidioc_s_std,
+	.vidioc_enum_input	 = vidioc_enum_input,
+	.vidioc_g_input		 = vidioc_g_input,
+	.vidioc_s_input		 = vidioc_s_input,
+	.vidioc_g_tuner		 = vidioc_g_tuner,
+	.vidioc_s_tuner		 = vidioc_s_tuner,
+	.vidioc_g_frequency	 = vidioc_g_frequency,
+	.vidioc_s_frequency	 = vidioc_s_frequency,
+	.vidioc_s_ctrl		 = vidioc_s_ctrl,
+	.vidioc_g_ctrl		 = vidioc_g_ctrl,
+	.vidioc_querycap	 = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	 = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	 = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	 = vidioc_s_fmt_vid_cap,
+	.vidioc_g_ext_ctrls	 = vidioc_g_ext_ctrls,
+	.vidioc_s_ext_ctrls	 = vidioc_s_ext_ctrls,
+	.vidioc_try_ext_ctrls	 = vidioc_try_ext_ctrls,
+	.vidioc_queryctrl	 = vidioc_queryctrl,
+#if 0
+	.vidioc_g_chip_ident	 = saa7164_g_chip_ident,
+#endif
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+#if 0
+	.vidioc_g_register	 = saa7164_g_register,
+	.vidioc_s_register	 = saa7164_s_register,
+#endif
+#endif
+	.vidioc_g_fmt_vbi_cap	 = saa7164_vbi_fmt,
+	.vidioc_try_fmt_vbi_cap	 = saa7164_vbi_fmt,
+	.vidioc_s_fmt_vbi_cap	 = saa7164_vbi_fmt,
+};
+
+static struct video_device saa7164_vbi_template = {
+	.name          = "saa7164",
+	.fops          = &vbi_fops,
+	.ioctl_ops     = &vbi_ioctl_ops,
+	.minor         = -1,
+	.tvnorms       = SAA7164_NORMS,
+	.current_norm  = V4L2_STD_NTSC_M,
+};
+
+static struct video_device *saa7164_vbi_alloc(
+	struct saa7164_port *port,
+	struct pci_dev *pci,
+	struct video_device *template,
+	char *type)
+{
+	struct video_device *vfd;
+	struct saa7164_dev *dev = port->dev;
+
+	dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+	vfd = video_device_alloc();
+	if (NULL == vfd)
+		return NULL;
+
+	*vfd = *template;
+	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
+		type, saa7164_boards[dev->board].name);
+
+	vfd->parent  = &pci->dev;
+	vfd->release = video_device_release;
+	return vfd;
+}
+
+int saa7164_vbi_register(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+	int result = -ENODEV;
+
+	dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+	if (port->type != SAA7164_MPEG_VBI)
+		BUG();
+
+	/* Sanity check that the PCI configuration space is active */
+	if (port->hwcfg.BARLocation == 0) {
+		printk(KERN_ERR "%s() failed "
+		       "(errno = %d), NO PCI configuration\n",
+			__func__, result);
+		result = -ENOMEM;
+		goto failed;
+	}
+
+	/* Establish VBI defaults here */
+
+	/* Allocate and register the video device node */
+	port->v4l_device = saa7164_vbi_alloc(port,
+		dev->pci, &saa7164_vbi_template, "vbi");
+
+	if (!port->v4l_device) {
+		printk(KERN_INFO "%s: can't allocate vbi device\n",
+			dev->name);
+		result = -ENOMEM;
+		goto failed;
+	}
+
+	video_set_drvdata(port->v4l_device, port);
+	result = video_register_device(port->v4l_device,
+		VFL_TYPE_VBI, -1);
+	if (result < 0) {
+		printk(KERN_INFO "%s: can't register vbi device\n",
+			dev->name);
+		/* TODO: We're going to leak here if we don't dealloc
+		 The buffers above. The unreg function can't deal wit it.
+		*/
+		goto failed;
+	}
+
+	printk(KERN_INFO "%s: registered device vbi%d [vbi]\n",
+		dev->name, port->v4l_device->num);
+
+	/* Configure the hardware defaults */
+
+	result = 0;
+failed:
+	return result;
+}
+
+void saa7164_vbi_unregister(struct saa7164_port *port)
+{
+	struct saa7164_dev *dev = port->dev;
+
+	dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);
+
+	if (port->type != SAA7164_MPEG_VBI)
+		BUG();
+
+	if (port->v4l_device) {
+		if (port->v4l_device->minor != -1)
+			video_unregister_device(port->v4l_device);
+		else
+			video_device_release(port->v4l_device);
+
+		port->v4l_device = NULL;
+	}
+
+}
diff --git a/drivers/media/pci/saa7164/saa7164.h b/drivers/media/pci/saa7164/saa7164.h
new file mode 100644
index 0000000..437284e
--- /dev/null
+++ b/drivers/media/pci/saa7164/saa7164.h
@@ -0,0 +1,616 @@
+/*
+ *  Driver for the NXP SAA7164 PCIe bridge
+ *
+ *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+	Driver architecture
+	*******************
+
+	saa7164_core.c/buffer.c/cards.c/i2c.c/dvb.c
+		|	: Standard Linux driver framework for creating
+		|	: exposing and managing interfaces to the rest
+		|	: of the kernel or userland. Also uses _fw.c to load
+		|	: firmware direct into the PCIe bus, bypassing layers.
+		V
+	saa7164_api..()	: Translate kernel specific functions/features
+		|	: into command buffers.
+		V
+	saa7164_cmd..()	: Manages the flow of command packets on/off,
+		|	: the bus. Deal with bus errors, timeouts etc.
+		V
+	saa7164_bus..() : Manage a read/write memory ring buffer in the
+		|	: PCIe Address space.
+		|
+		|		saa7164_fw...()	: Load any frimware
+		|			|	: direct into the device
+		V			V
+	<- ----------------- PCIe address space -------------------- ->
+*/
+
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/kdev_t.h>
+#include <linux/mutex.h>
+#include <linux/crc32.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+#include <media/tuner.h>
+#include <media/tveeprom.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/videobuf-dvb.h>
+#include <dvb_demux.h>
+#include <dvb_frontend.h>
+#include <dvb_net.h>
+#include <dvbdev.h>
+#include <dmxdev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "saa7164-reg.h"
+#include "saa7164-types.h"
+
+#define SAA7164_MAXBOARDS 8
+
+#define UNSET (-1U)
+#define SAA7164_BOARD_NOAUTO			UNSET
+#define SAA7164_BOARD_UNKNOWN			0
+#define SAA7164_BOARD_UNKNOWN_REV2		1
+#define SAA7164_BOARD_UNKNOWN_REV3		2
+#define SAA7164_BOARD_HAUPPAUGE_HVR2250		3
+#define SAA7164_BOARD_HAUPPAUGE_HVR2200		4
+#define SAA7164_BOARD_HAUPPAUGE_HVR2200_2	5
+#define SAA7164_BOARD_HAUPPAUGE_HVR2200_3	6
+#define SAA7164_BOARD_HAUPPAUGE_HVR2250_2	7
+#define SAA7164_BOARD_HAUPPAUGE_HVR2250_3	8
+#define SAA7164_BOARD_HAUPPAUGE_HVR2200_4	9
+#define SAA7164_BOARD_HAUPPAUGE_HVR2200_5	10
+
+#define SAA7164_MAX_UNITS		8
+#define SAA7164_TS_NUMBER_OF_LINES	312
+#define SAA7164_PS_NUMBER_OF_LINES	256
+#define SAA7164_PT_ENTRIES		16 /* (312 * 188) / 4096 */
+#define SAA7164_MAX_ENCODER_BUFFERS	64 /* max 5secs of latency at 6Mbps */
+#define SAA7164_MAX_VBI_BUFFERS		64
+
+/* Port related defines */
+#define SAA7164_PORT_TS1	(0)
+#define SAA7164_PORT_TS2	(SAA7164_PORT_TS1 + 1)
+#define SAA7164_PORT_ENC1	(SAA7164_PORT_TS2 + 1)
+#define SAA7164_PORT_ENC2	(SAA7164_PORT_ENC1 + 1)
+#define SAA7164_PORT_VBI1	(SAA7164_PORT_ENC2 + 1)
+#define SAA7164_PORT_VBI2	(SAA7164_PORT_VBI1 + 1)
+#define SAA7164_MAX_PORTS	(SAA7164_PORT_VBI2 + 1)
+
+#define DBGLVL_FW    4
+#define DBGLVL_DVB   8
+#define DBGLVL_I2C  16
+#define DBGLVL_API  32
+#define DBGLVL_CMD  64
+#define DBGLVL_BUS 128
+#define DBGLVL_IRQ 256
+#define DBGLVL_BUF 512
+#define DBGLVL_ENC 1024
+#define DBGLVL_VBI 2048
+#define DBGLVL_THR 4096
+#define DBGLVL_CPU 8192
+
+#define SAA7164_NORMS \
+	(V4L2_STD_NTSC_M |  V4L2_STD_NTSC_M_JP |  V4L2_STD_NTSC_443)
+
+enum port_t {
+	SAA7164_MPEG_UNDEFINED = 0,
+	SAA7164_MPEG_DVB,
+	SAA7164_MPEG_ENCODER,
+	SAA7164_MPEG_VBI,
+};
+
+enum saa7164_i2c_bus_nr {
+	SAA7164_I2C_BUS_0 = 0,
+	SAA7164_I2C_BUS_1,
+	SAA7164_I2C_BUS_2,
+};
+
+enum saa7164_buffer_flags {
+	SAA7164_BUFFER_UNDEFINED = 0,
+	SAA7164_BUFFER_FREE,
+	SAA7164_BUFFER_BUSY,
+	SAA7164_BUFFER_FULL
+};
+
+enum saa7164_unit_type {
+	SAA7164_UNIT_UNDEFINED = 0,
+	SAA7164_UNIT_DIGITAL_DEMODULATOR,
+	SAA7164_UNIT_ANALOG_DEMODULATOR,
+	SAA7164_UNIT_TUNER,
+	SAA7164_UNIT_EEPROM,
+	SAA7164_UNIT_ZILOG_IRBLASTER,
+	SAA7164_UNIT_ENCODER,
+};
+
+/* The PCIe bridge doesn't grant direct access to i2c.
+ * Instead, you address i2c devices using a uniqely
+ * allocated 'unitid' value via a messaging API. This
+ * is a problem. The kernel and existing demod/tuner
+ * drivers expect to talk 'i2c', so we have to maintain
+ * a translation layer, and a series of functions to
+ * convert i2c bus + device address into a unit id.
+ */
+struct saa7164_unit {
+	enum saa7164_unit_type type;
+	u8	id;
+	char	*name;
+	enum saa7164_i2c_bus_nr i2c_bus_nr;
+	u8	i2c_bus_addr;
+	u8	i2c_reg_len;
+};
+
+struct saa7164_board {
+	char	*name;
+	enum port_t porta, portb, portc,
+		portd, porte, portf;
+	enum {
+		SAA7164_CHIP_UNDEFINED = 0,
+		SAA7164_CHIP_REV2,
+		SAA7164_CHIP_REV3,
+	} chiprev;
+	struct	saa7164_unit unit[SAA7164_MAX_UNITS];
+};
+
+struct saa7164_subid {
+	u16     subvendor;
+	u16     subdevice;
+	u32     card;
+};
+
+struct saa7164_encoder_fh {
+	struct saa7164_port *port;
+	atomic_t v4l_reading;
+};
+
+struct saa7164_vbi_fh {
+	struct saa7164_port *port;
+	atomic_t v4l_reading;
+};
+
+struct saa7164_histogram_bucket {
+	u32 val;
+	u32 count;
+	u64 update_time;
+};
+
+struct saa7164_histogram {
+	char name[32];
+	struct saa7164_histogram_bucket counter1[64];
+};
+
+struct saa7164_user_buffer {
+	struct list_head list;
+
+	/* Attributes */
+	u8  *data;
+	u32 pos;
+	u32 actual_size;
+
+	u32 crc;
+};
+
+struct saa7164_fw_status {
+
+	/* RISC Core details */
+	u32	status;
+	u32	mode;
+	u32	spec;
+	u32	inst;
+	u32	cpuload;
+	u32	remainheap;
+
+	/* Firmware version */
+	u32	version;
+	u32	major;
+	u32	sub;
+	u32	rel;
+	u32	buildnr;
+};
+
+struct saa7164_dvb {
+	struct mutex lock;
+	struct dvb_adapter adapter;
+	struct dvb_frontend *frontend;
+	struct dvb_demux demux;
+	struct dmxdev dmxdev;
+	struct dmx_frontend fe_hw;
+	struct dmx_frontend fe_mem;
+	struct dvb_net net;
+	int feeding;
+};
+
+struct saa7164_i2c {
+	struct saa7164_dev		*dev;
+
+	enum saa7164_i2c_bus_nr		nr;
+
+	/* I2C I/O */
+	struct i2c_adapter		i2c_adap;
+	struct i2c_client		i2c_client;
+	u32				i2c_rc;
+};
+
+struct saa7164_ctrl {
+	struct v4l2_queryctrl v;
+};
+
+struct saa7164_tvnorm {
+	char		*name;
+	v4l2_std_id	id;
+};
+
+struct saa7164_encoder_params {
+	struct saa7164_tvnorm encodernorm;
+	u32 height;
+	u32 width;
+	u32 is_50hz;
+	u32 bitrate; /* bps */
+	u32 bitrate_peak; /* bps */
+	u32 bitrate_mode;
+	u32 stream_type; /* V4L2_MPEG_STREAM_TYPE_MPEG2_TS */
+
+	u32 audio_sampling_freq;
+	u32 ctl_mute;
+	u32 ctl_aspect;
+	u32 refdist;
+	u32 gop_size;
+};
+
+struct saa7164_vbi_params {
+	struct saa7164_tvnorm encodernorm;
+	u32 height;
+	u32 width;
+	u32 is_50hz;
+	u32 bitrate; /* bps */
+	u32 bitrate_peak; /* bps */
+	u32 bitrate_mode;
+	u32 stream_type; /* V4L2_MPEG_STREAM_TYPE_MPEG2_TS */
+
+	u32 audio_sampling_freq;
+	u32 ctl_mute;
+	u32 ctl_aspect;
+	u32 refdist;
+	u32 gop_size;
+};
+
+struct saa7164_port;
+
+struct saa7164_buffer {
+	struct list_head list;
+
+	/* Note of which h/w buffer list index position we occupy */
+	int idx;
+
+	struct saa7164_port *port;
+
+	/* Hardware Specific */
+	/* PCI Memory allocations */
+	enum saa7164_buffer_flags flags; /* Free, Busy, Full */
+
+	/* A block of page align PCI memory */
+	u32 pci_size;	/* PCI allocation size in bytes */
+	u64 __iomem *cpu;	/* Virtual address */
+	dma_addr_t dma;	/* Physical address */
+	u32 crc;	/* Checksum for the entire buffer data */
+
+	/* A page table that splits the block into a number of entries */
+	u32 pt_size;		/* PCI allocation size in bytes */
+	u64 __iomem *pt_cpu;		/* Virtual address */
+	dma_addr_t pt_dma;	/* Physical address */
+
+	/* Encoder fops */
+	u32 pos;
+	u32 actual_size;
+};
+
+struct saa7164_port {
+
+	struct saa7164_dev *dev;
+	enum port_t type;
+	int nr;
+
+	/* --- Generic port attributes --- */
+
+	/* HW stream parameters */
+	struct tmHWStreamParameters hw_streamingparams;
+
+	/* DMA configuration values, is seeded during initialization */
+	struct tmComResDMATermDescrHeader hwcfg;
+
+	/* hardware specific registers */
+	u32 bufcounter;
+	u32 pitch;
+	u32 bufsize;
+	u32 bufoffset;
+	u32 bufptr32l;
+	u32 bufptr32h;
+	u64 bufptr64;
+
+	u32 numpte;	/* Number of entries in array, only valid in head */
+
+	struct mutex dmaqueue_lock;
+	struct saa7164_buffer dmaqueue;
+
+	u64 last_irq_msecs, last_svc_msecs;
+	u64 last_irq_msecs_diff, last_svc_msecs_diff;
+	u32 last_svc_wp;
+	u32 last_svc_rp;
+	u64 last_irq_svc_msecs_diff;
+	u64 last_read_msecs, last_read_msecs_diff;
+	u64 last_poll_msecs, last_poll_msecs_diff;
+
+	struct saa7164_histogram irq_interval;
+	struct saa7164_histogram svc_interval;
+	struct saa7164_histogram irq_svc_interval;
+	struct saa7164_histogram read_interval;
+	struct saa7164_histogram poll_interval;
+
+	/* --- DVB Transport Specific --- */
+	struct saa7164_dvb dvb;
+
+	/* --- Encoder/V4L related attributes --- */
+	/* Encoder */
+	/* Defaults established in saa7164-encoder.c */
+	struct saa7164_tvnorm encodernorm;
+	u32 height;
+	u32 width;
+	u32 freq;
+	u32 ts_packet_size;
+	u32 ts_packet_count;
+	u8 mux_input;
+	u8 encoder_profile;
+	u8 video_format;
+	u8 audio_format;
+	u8 video_resolution;
+	u16 ctl_brightness;
+	u16 ctl_contrast;
+	u16 ctl_hue;
+	u16 ctl_saturation;
+	u16 ctl_sharpness;
+	s8 ctl_volume;
+
+	struct tmComResAFeatureDescrHeader audfeat;
+	struct tmComResEncoderDescrHeader encunit;
+	struct tmComResProcDescrHeader vidproc;
+	struct tmComResExtDevDescrHeader ifunit;
+	struct tmComResTunerDescrHeader tunerunit;
+
+	struct work_struct workenc;
+
+	/* V4L Encoder Video */
+	struct saa7164_encoder_params encoder_params;
+	struct video_device *v4l_device;
+	atomic_t v4l_reader_count;
+
+	struct saa7164_buffer list_buf_used;
+	struct saa7164_buffer list_buf_free;
+	wait_queue_head_t wait_read;
+
+	/* V4L VBI */
+	struct tmComResVBIFormatDescrHeader vbi_fmt_ntsc;
+	struct saa7164_vbi_params vbi_params;
+
+	/* Debug */
+	u32 sync_errors;
+	u32 v_cc_errors;
+	u32 a_cc_errors;
+	u8 last_v_cc;
+	u8 last_a_cc;
+	u32 done_first_interrupt;
+};
+
+struct saa7164_dev {
+	struct list_head	devlist;
+	atomic_t		refcount;
+
+	/* pci stuff */
+	struct pci_dev	*pci;
+	unsigned char	pci_rev, pci_lat;
+	int		pci_bus, pci_slot;
+	u32		__iomem *lmmio;
+	u8		__iomem *bmmio;
+	u32		__iomem *lmmio2;
+	u8		__iomem *bmmio2;
+	int		pci_irqmask;
+
+	/* board details */
+	int	nr;
+	int	hwrevision;
+	u32	board;
+	char	name[16];
+
+	/* firmware status */
+	struct saa7164_fw_status	fw_status;
+	u32				firmwareloaded;
+
+	struct tmComResHWDescr		hwdesc;
+	struct tmComResInterfaceDescr	intfdesc;
+	struct tmComResBusDescr		busdesc;
+
+	struct tmComResBusInfo		bus;
+
+	/* Interrupt status and ack registers */
+	u32 int_status;
+	u32 int_ack;
+
+	struct cmd			cmds[SAA_CMD_MAX_MSG_UNITS];
+	struct mutex			lock;
+
+	/* I2c related */
+	struct saa7164_i2c i2c_bus[3];
+
+	/* Transport related */
+	struct saa7164_port ports[SAA7164_MAX_PORTS];
+
+	/* Deferred command/api interrupts handling */
+	struct work_struct workcmd;
+
+	/* A kernel thread to monitor the firmware log, used
+	 * only in debug mode.
+	 */
+	struct task_struct *kthread;
+
+};
+
+extern struct list_head saa7164_devlist;
+extern unsigned int waitsecs;
+extern unsigned int encoder_buffers;
+extern unsigned int vbi_buffers;
+
+/* ----------------------------------------------------------- */
+/* saa7164-core.c                                              */
+void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr);
+void saa7164_getfirmwarestatus(struct saa7164_dev *dev);
+u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev);
+void saa7164_histogram_update(struct saa7164_histogram *hg, u32 val);
+
+/* ----------------------------------------------------------- */
+/* saa7164-fw.c                                                */
+int saa7164_downloadfirmware(struct saa7164_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* saa7164-i2c.c                                               */
+extern int saa7164_i2c_register(struct saa7164_i2c *bus);
+extern int saa7164_i2c_unregister(struct saa7164_i2c *bus);
+extern void saa7164_call_i2c_clients(struct saa7164_i2c *bus,
+	unsigned int cmd, void *arg);
+
+/* ----------------------------------------------------------- */
+/* saa7164-bus.c                                               */
+int saa7164_bus_setup(struct saa7164_dev *dev);
+void saa7164_bus_dump(struct saa7164_dev *dev);
+int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
+	void *buf);
+int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
+	void *buf, int peekonly);
+
+/* ----------------------------------------------------------- */
+/* saa7164-cmd.c                                               */
+int saa7164_cmd_send(struct saa7164_dev *dev,
+	u8 id, enum tmComResCmd command, u16 controlselector,
+	u16 size, void *buf);
+void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno);
+int saa7164_irq_dequeue(struct saa7164_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* saa7164-api.c                                               */
+int saa7164_api_get_fw_version(struct saa7164_dev *dev, u32 *version);
+int saa7164_api_enum_subdevs(struct saa7164_dev *dev);
+int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg,
+	u32 datalen, u8 *data);
+int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr,
+	u32 datalen, u8 *data);
+int saa7164_api_dif_write(struct saa7164_i2c *bus, u8 addr,
+	u32 datalen, u8 *data);
+int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen);
+int saa7164_api_set_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin);
+int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin);
+int saa7164_api_transition_port(struct saa7164_port *port, u8 mode);
+int saa7164_api_initialize_dif(struct saa7164_port *port);
+int saa7164_api_configure_dif(struct saa7164_port *port, u32 std);
+int saa7164_api_set_encoder(struct saa7164_port *port);
+int saa7164_api_get_encoder(struct saa7164_port *port);
+int saa7164_api_set_aspect_ratio(struct saa7164_port *port);
+int saa7164_api_set_usercontrol(struct saa7164_port *port, u8 ctl);
+int saa7164_api_get_usercontrol(struct saa7164_port *port, u8 ctl);
+int saa7164_api_set_videomux(struct saa7164_port *port);
+int saa7164_api_audio_mute(struct saa7164_port *port, int mute);
+int saa7164_api_set_audio_volume(struct saa7164_port *port, s8 level);
+int saa7164_api_set_audio_std(struct saa7164_port *port);
+int saa7164_api_set_audio_detection(struct saa7164_port *port, int autodetect);
+int saa7164_api_get_videomux(struct saa7164_port *port);
+int saa7164_api_set_vbi_format(struct saa7164_port *port);
+int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level);
+int saa7164_api_collect_debug(struct saa7164_dev *dev);
+int saa7164_api_get_load_info(struct saa7164_dev *dev,
+	struct tmFwInfoStruct *i);
+
+/* ----------------------------------------------------------- */
+/* saa7164-cards.c                                             */
+extern struct saa7164_board saa7164_boards[];
+extern const unsigned int saa7164_bcount;
+
+extern struct saa7164_subid saa7164_subids[];
+extern const unsigned int saa7164_idcount;
+
+extern void saa7164_card_list(struct saa7164_dev *dev);
+extern void saa7164_gpio_setup(struct saa7164_dev *dev);
+extern void saa7164_card_setup(struct saa7164_dev *dev);
+
+extern int saa7164_i2caddr_to_reglen(struct saa7164_i2c *bus, int addr);
+extern int saa7164_i2caddr_to_unitid(struct saa7164_i2c *bus, int addr);
+extern char *saa7164_unitid_name(struct saa7164_dev *dev, u8 unitid);
+
+/* ----------------------------------------------------------- */
+/* saa7164-dvb.c                                               */
+extern int saa7164_dvb_register(struct saa7164_port *port);
+extern int saa7164_dvb_unregister(struct saa7164_port *port);
+
+/* ----------------------------------------------------------- */
+/* saa7164-buffer.c                                            */
+extern struct saa7164_buffer *saa7164_buffer_alloc(
+	struct saa7164_port *port, u32 len);
+extern int saa7164_buffer_dealloc(struct saa7164_buffer *buf);
+extern void saa7164_buffer_display(struct saa7164_buffer *buf);
+extern int saa7164_buffer_activate(struct saa7164_buffer *buf, int i);
+extern int saa7164_buffer_cfg_port(struct saa7164_port *port);
+extern struct saa7164_user_buffer *saa7164_buffer_alloc_user(
+	struct saa7164_dev *dev, u32 len);
+extern void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf);
+extern int saa7164_buffer_zero_offsets(struct saa7164_port *port, int i);
+
+/* ----------------------------------------------------------- */
+/* saa7164-encoder.c                                            */
+int saa7164_encoder_register(struct saa7164_port *port);
+void saa7164_encoder_unregister(struct saa7164_port *port);
+
+/* ----------------------------------------------------------- */
+/* saa7164-vbi.c                                            */
+int saa7164_vbi_register(struct saa7164_port *port);
+void saa7164_vbi_unregister(struct saa7164_port *port);
+
+/* ----------------------------------------------------------- */
+
+extern unsigned int crc_checking;
+
+extern unsigned int saa_debug;
+#define dprintk(level, fmt, arg...)\
+	do { if (saa_debug & level)\
+		printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg);\
+	} while (0)
+
+#define log_warn(fmt, arg...)\
+	do { \
+		printk(KERN_WARNING "%s: " fmt, dev->name, ## arg);\
+	} while (0)
+
+#define saa7164_readl(reg) readl(dev->lmmio + ((reg) >> 2))
+#define saa7164_writel(reg, value) writel((value), dev->lmmio + ((reg) >> 2))
+
+#define saa7164_readb(reg)             readl(dev->bmmio + (reg))
+#define saa7164_writeb(reg, value)     writel((value), dev->bmmio + (reg))
+
diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig
new file mode 100644
index 0000000..04a82cb
--- /dev/null
+++ b/drivers/media/pci/sta2x11/Kconfig
@@ -0,0 +1,12 @@
+config STA2X11_VIP
+	tristate "STA2X11 VIP Video For Linux"
+	depends on STA2X11
+	select VIDEO_ADV7180 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEOBUF_DMA_CONTIG
+	depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS
+	help
+	  Say Y for support for STA2X11 VIP (Video Input Port) capture
+	  device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sta2x11_vip.
diff --git a/drivers/media/pci/sta2x11/Makefile b/drivers/media/pci/sta2x11/Makefile
new file mode 100644
index 0000000..d6c471d
--- /dev/null
+++ b/drivers/media/pci/sta2x11/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_STA2X11_VIP) += sta2x11_vip.o
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
new file mode 100644
index 0000000..4c10205
--- /dev/null
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
@@ -0,0 +1,1550 @@
+/*
+ * This is the driver for the STA2x11 Video Input Port.
+ *
+ * Copyright (C) 2010       WindRiver Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Author: Andreas Kies <andreas.kies@windriver.com>
+ *		Vlad Lungu <vlad.lungu@windriver.com>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+
+#include <linux/videodev2.h>
+
+#include <linux/kmod.h>
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf-dma-contig.h>
+
+#include "sta2x11_vip.h"
+
+#define DRV_NAME "sta2x11_vip"
+#define DRV_VERSION "1.3"
+
+#ifndef PCI_DEVICE_ID_STMICRO_VIP
+#define PCI_DEVICE_ID_STMICRO_VIP 0xCC0D
+#endif
+
+#define MAX_FRAMES 4
+
+/*Register offsets*/
+#define DVP_CTL		0x00
+#define DVP_TFO		0x04
+#define DVP_TFS		0x08
+#define DVP_BFO		0x0C
+#define DVP_BFS		0x10
+#define DVP_VTP         0x14
+#define DVP_VBP         0x18
+#define DVP_VMP		0x1C
+#define DVP_ITM		0x98
+#define DVP_ITS		0x9C
+#define DVP_STA		0xA0
+#define DVP_HLFLN	0xA8
+#define DVP_RGB		0xC0
+#define DVP_PKZ		0xF0
+
+/*Register fields*/
+#define DVP_CTL_ENA	0x00000001
+#define DVP_CTL_RST	0x80000000
+#define DVP_CTL_DIS	(~0x00040001)
+
+#define DVP_IT_VSB	0x00000008
+#define DVP_IT_VST	0x00000010
+#define DVP_IT_FIFO	0x00000020
+
+#define DVP_HLFLN_SD	0x00000001
+
+#define REG_WRITE(vip, reg, value) iowrite32((value), (vip->iomem)+(reg))
+#define REG_READ(vip, reg) ioread32((vip->iomem)+(reg))
+
+#define SAVE_COUNT 8
+#define AUX_COUNT 3
+#define IRQ_COUNT 1
+
+/**
+ * struct sta2x11_vip - All internal data for one instance of device
+ * @v4l2_dev: device registered in v4l layer
+ * @video_dev: properties of our device
+ * @pdev: PCI device
+ * @adapter: contains I2C adapter information
+ * @register_save_area: All relevant register are saved here during suspend
+ * @decoder: contains information about video DAC
+ * @format: pixel format, fixed UYVY
+ * @std: video standard (e.g. PAL/NTSC)
+ * @input: input line for video signal ( 0 or 1 )
+ * @users: Number of open of device ( max. 1 )
+ * @disabled: Device is in power down state
+ * @mutex: ensures exclusive opening of device
+ * @slock: for excluse acces of registers
+ * @vb_vidq: queue maintained by videobuf layer
+ * @capture: linked list of capture buffer
+ * @active: struct videobuf_buffer currently beingg filled
+ * @started: device is ready to capture frame
+ * @closing: device will be shut down
+ * @tcount: Number of top frames
+ * @bcount: Number of bottom frames
+ * @overflow: Number of FIFO overflows
+ * @mem_spare: small buffer of unused frame
+ * @dma_spare: dma addres of mem_spare
+ * @iomem: hardware base address
+ * @config: I2C and gpio config from platform
+ *
+ * All non-local data is accessed via this structure.
+ */
+
+struct sta2x11_vip {
+	struct v4l2_device v4l2_dev;
+	struct video_device *video_dev;
+	struct pci_dev *pdev;
+	struct i2c_adapter *adapter;
+	unsigned int register_save_area[IRQ_COUNT + SAVE_COUNT + AUX_COUNT];
+	struct v4l2_subdev *decoder;
+	struct v4l2_pix_format format;
+	v4l2_std_id std;
+	unsigned int input;
+	int users;
+	int disabled;
+	struct mutex mutex;	/* exclusive access during open */
+	spinlock_t slock;	/* spin lock for hardware and queue access */
+	struct videobuf_queue vb_vidq;
+	struct list_head capture;
+	struct videobuf_buffer *active;
+	int started, closing, tcount, bcount;
+	int overflow;
+	void *mem_spare;
+	dma_addr_t dma_spare;
+	void *iomem;
+	struct vip_config *config;
+};
+
+static const unsigned int registers_to_save[AUX_COUNT] = {
+	DVP_HLFLN, DVP_RGB, DVP_PKZ
+};
+
+static struct v4l2_pix_format formats_50[] = {
+	{			/*PAL interlaced */
+	 .width = 720,
+	 .height = 576,
+	 .pixelformat = V4L2_PIX_FMT_UYVY,
+	 .field = V4L2_FIELD_INTERLACED,
+	 .bytesperline = 720 * 2,
+	 .sizeimage = 720 * 2 * 576,
+	 .colorspace = V4L2_COLORSPACE_SMPTE170M},
+	{			/*PAL top */
+	 .width = 720,
+	 .height = 288,
+	 .pixelformat = V4L2_PIX_FMT_UYVY,
+	 .field = V4L2_FIELD_TOP,
+	 .bytesperline = 720 * 2,
+	 .sizeimage = 720 * 2 * 288,
+	 .colorspace = V4L2_COLORSPACE_SMPTE170M},
+	{			/*PAL bottom */
+	 .width = 720,
+	 .height = 288,
+	 .pixelformat = V4L2_PIX_FMT_UYVY,
+	 .field = V4L2_FIELD_BOTTOM,
+	 .bytesperline = 720 * 2,
+	 .sizeimage = 720 * 2 * 288,
+	 .colorspace = V4L2_COLORSPACE_SMPTE170M},
+
+};
+
+static struct v4l2_pix_format formats_60[] = {
+	{			/*NTSC interlaced */
+	 .width = 720,
+	 .height = 480,
+	 .pixelformat = V4L2_PIX_FMT_UYVY,
+	 .field = V4L2_FIELD_INTERLACED,
+	 .bytesperline = 720 * 2,
+	 .sizeimage = 720 * 2 * 480,
+	 .colorspace = V4L2_COLORSPACE_SMPTE170M},
+	{			/*NTSC top */
+	 .width = 720,
+	 .height = 240,
+	 .pixelformat = V4L2_PIX_FMT_UYVY,
+	 .field = V4L2_FIELD_TOP,
+	 .bytesperline = 720 * 2,
+	 .sizeimage = 720 * 2 * 240,
+	 .colorspace = V4L2_COLORSPACE_SMPTE170M},
+	{			/*NTSC bottom */
+	 .width = 720,
+	 .height = 240,
+	 .pixelformat = V4L2_PIX_FMT_UYVY,
+	 .field = V4L2_FIELD_BOTTOM,
+	 .bytesperline = 720 * 2,
+	 .sizeimage = 720 * 2 * 240,
+	 .colorspace = V4L2_COLORSPACE_SMPTE170M},
+};
+
+/**
+ * buf_setup - Get size and number of video buffer
+ * @vq: queue in videobuf
+ * @count: Number of buffers (1..MAX_FRAMES).
+ *		0 use default value.
+ * @size:  size of buffer in bytes
+ *
+ * returns size and number of buffers
+ * a preset value of 0 returns the default number.
+ * return value: 0, always succesfull.
+ */
+static int buf_setup(struct videobuf_queue *vq, unsigned int *count,
+		     unsigned int *size)
+{
+	struct sta2x11_vip *vip = vq->priv_data;
+
+	*size = vip->format.width * vip->format.height * 2;
+	if (0 == *count || MAX_FRAMES < *count)
+		*count = MAX_FRAMES;
+	return 0;
+};
+
+/**
+ * buf_prepare - prepare buffer for usage
+ * @vq: queue in videobuf layer
+ * @vb: buffer to be prepared
+ * @field: type of video data (interlaced/non-interlaced)
+ *
+ * Allocate or realloc buffer
+ * return value: 0, successful.
+ *
+ * -EINVAL, supplied buffer is too small.
+ *
+ *  other, buffer could not be locked.
+ */
+static int buf_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+		       enum v4l2_field field)
+{
+	struct sta2x11_vip *vip = vq->priv_data;
+	int ret;
+
+	vb->size = vip->format.width * vip->format.height * 2;
+	if ((0 != vb->baddr) && (vb->bsize < vb->size))
+		return -EINVAL;
+	vb->width = vip->format.width;
+	vb->height = vip->format.height;
+	vb->field = field;
+
+	if (VIDEOBUF_NEEDS_INIT == vb->state) {
+		ret = videobuf_iolock(vq, vb, NULL);
+		if (ret)
+			goto fail;
+	}
+	vb->state = VIDEOBUF_PREPARED;
+	return 0;
+fail:
+	videobuf_dma_contig_free(vq, vb);
+	vb->state = VIDEOBUF_NEEDS_INIT;
+	return ret;
+}
+
+/**
+ * buf_queu - queue buffer for filling
+ * @vq: queue in videobuf layer
+ * @vb: buffer to be queued
+ *
+ * if capturing is already running, the buffer will be queued. Otherwise
+ * capture is started and the buffer is used directly.
+ */
+static void buf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct sta2x11_vip *vip = vq->priv_data;
+	u32 dma;
+
+	vb->state = VIDEOBUF_QUEUED;
+
+	if (vip->active) {
+		list_add_tail(&vb->queue, &vip->capture);
+		return;
+	}
+
+	vip->started = 1;
+	vip->tcount = 0;
+	vip->bcount = 0;
+	vip->active = vb;
+	vb->state = VIDEOBUF_ACTIVE;
+
+	dma = videobuf_to_dma_contig(vb);
+
+	REG_WRITE(vip, DVP_TFO, (0 << 16) | (0));
+	/* despite of interlace mode, upper and lower frames start at zero */
+	REG_WRITE(vip, DVP_BFO, (0 << 16) | (0));
+
+	switch (vip->format.field) {
+	case V4L2_FIELD_INTERLACED:
+		REG_WRITE(vip, DVP_TFS,
+			  ((vip->format.height / 2 - 1) << 16) |
+			  (2 * vip->format.width - 1));
+		REG_WRITE(vip, DVP_BFS, ((vip->format.height / 2 - 1) << 16) |
+			  (2 * vip->format.width - 1));
+		REG_WRITE(vip, DVP_VTP, dma);
+		REG_WRITE(vip, DVP_VBP, dma + vip->format.width * 2);
+		REG_WRITE(vip, DVP_VMP, 4 * vip->format.width);
+		break;
+	case V4L2_FIELD_TOP:
+		REG_WRITE(vip, DVP_TFS,
+			  ((vip->format.height - 1) << 16) |
+			  (2 * vip->format.width - 1));
+		REG_WRITE(vip, DVP_BFS, ((0) << 16) |
+			  (2 * vip->format.width - 1));
+		REG_WRITE(vip, DVP_VTP, dma);
+		REG_WRITE(vip, DVP_VBP, dma);
+		REG_WRITE(vip, DVP_VMP, 2 * vip->format.width);
+		break;
+	case V4L2_FIELD_BOTTOM:
+		REG_WRITE(vip, DVP_TFS, ((0) << 16) |
+			  (2 * vip->format.width - 1));
+		REG_WRITE(vip, DVP_BFS,
+			  ((vip->format.height) << 16) |
+			  (2 * vip->format.width - 1));
+		REG_WRITE(vip, DVP_VTP, dma);
+		REG_WRITE(vip, DVP_VBP, dma);
+		REG_WRITE(vip, DVP_VMP, 2 * vip->format.width);
+		break;
+
+	default:
+		pr_warning("VIP: unknown field format\n");
+		return;
+	}
+
+	REG_WRITE(vip, DVP_CTL, DVP_CTL_ENA);
+}
+
+/**
+ * buff_release - release buffer
+ * @vq: queue in videobuf layer
+ * @vb: buffer to be released
+ *
+ * release buffer in videobuf layer
+ */
+static void buf_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+
+	videobuf_dma_contig_free(vq, vb);
+	vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops vip_qops = {
+	.buf_setup = buf_setup,
+	.buf_prepare = buf_prepare,
+	.buf_queue = buf_queue,
+	.buf_release = buf_release,
+};
+
+/**
+ * vip_open - open video device
+ * @file: descriptor of device
+ *
+ * open device, make sure it is only opened once.
+ * return value: 0, no error.
+ *
+ * -EBUSY, device is already opened
+ *
+ * -ENOMEM, no memory for auxiliary DMA buffer
+ */
+static int vip_open(struct file *file)
+{
+	struct video_device *dev = video_devdata(file);
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	mutex_lock(&vip->mutex);
+	vip->users++;
+
+	if (vip->users > 1) {
+		vip->users--;
+		mutex_unlock(&vip->mutex);
+		return -EBUSY;
+	}
+
+	file->private_data = dev;
+	vip->overflow = 0;
+	vip->started = 0;
+	vip->closing = 0;
+	vip->active = NULL;
+
+	INIT_LIST_HEAD(&vip->capture);
+	vip->mem_spare = dma_alloc_coherent(&vip->pdev->dev, 64,
+					    &vip->dma_spare, GFP_KERNEL);
+	if (!vip->mem_spare) {
+		vip->users--;
+		mutex_unlock(&vip->mutex);
+		return -ENOMEM;
+	}
+
+	mutex_unlock(&vip->mutex);
+	videobuf_queue_dma_contig_init_cached(&vip->vb_vidq,
+					      &vip_qops,
+					      &vip->pdev->dev,
+					      &vip->slock,
+					      V4L2_BUF_TYPE_VIDEO_CAPTURE,
+					      V4L2_FIELD_INTERLACED,
+					      sizeof(struct videobuf_buffer),
+					      vip, NULL);
+	REG_READ(vip, DVP_ITS);
+	REG_WRITE(vip, DVP_HLFLN, DVP_HLFLN_SD);
+	REG_WRITE(vip, DVP_ITM, DVP_IT_VSB | DVP_IT_VST);
+	REG_WRITE(vip, DVP_CTL, DVP_CTL_RST);
+	REG_WRITE(vip, DVP_CTL, 0);
+	REG_READ(vip, DVP_ITS);
+	return 0;
+}
+
+/**
+ * vip_close - close video device
+ * @file: descriptor of device
+ *
+ * close video device, wait until all pending operations are finished
+ * ( maximum FRAME_MAX buffers pending )
+ * Turn off interrupts.
+ *
+ * return value: 0, always succesful.
+ */
+static int vip_close(struct file *file)
+{
+	struct video_device *dev = video_devdata(file);
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	vip->closing = 1;
+	if (vip->active)
+		videobuf_waiton(&vip->vb_vidq, vip->active, 0, 0);
+	spin_lock_irq(&vip->slock);
+
+	REG_WRITE(vip, DVP_ITM, 0);
+	REG_WRITE(vip, DVP_CTL, DVP_CTL_RST);
+	REG_WRITE(vip, DVP_CTL, 0);
+	REG_READ(vip, DVP_ITS);
+
+	vip->started = 0;
+	vip->active = NULL;
+
+	spin_unlock_irq(&vip->slock);
+
+	videobuf_stop(&vip->vb_vidq);
+	videobuf_mmap_free(&vip->vb_vidq);
+
+	dma_free_coherent(&vip->pdev->dev, 64, vip->mem_spare, vip->dma_spare);
+	file->private_data = NULL;
+	mutex_lock(&vip->mutex);
+	vip->users--;
+	mutex_unlock(&vip->mutex);
+	return 0;
+}
+
+/**
+ * vip_read - read from video input
+ * @file: descriptor of device
+ * @data: user buffer
+ * @count: number of bytes to be read
+ * @ppos: position within stream
+ *
+ * read video data from video device.
+ * handling is done in generic videobuf layer
+ * return value: provided by videobuf layer
+ */
+static ssize_t vip_read(struct file *file, char __user *data,
+			size_t count, loff_t *ppos)
+{
+	struct video_device *dev = file->private_data;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_read_stream(&vip->vb_vidq, data, count, ppos, 0,
+				    file->f_flags & O_NONBLOCK);
+}
+
+/**
+ * vip_mmap - map user buffer
+ * @file: descriptor of device
+ * @vma: user buffer
+ *
+ * map user space buffer into kernel mode, including DMA address.
+ * handling is done in generic videobuf layer.
+ * return value: provided by videobuf layer
+ */
+static int vip_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct video_device *dev = file->private_data;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_mmap_mapper(&vip->vb_vidq, vma);
+}
+
+/**
+ * vip_poll - poll for event
+ * @file: descriptor of device
+ * @wait: contains events to be waited for
+ *
+ * wait for event related to video device.
+ * handling is done in generic videobuf layer.
+ * return value: provided by videobuf layer
+ */
+static unsigned int vip_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct video_device *dev = file->private_data;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_poll_stream(file, &vip->vb_vidq, wait);
+}
+
+/**
+ * vidioc_querycap - return capabilities of device
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @cap: contains return values
+ *
+ * the capabilities of the device are returned
+ *
+ * return value: 0, no error.
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	memset(cap, 0, sizeof(struct v4l2_capability));
+	strcpy(cap->driver, DRV_NAME);
+	strcpy(cap->card, DRV_NAME);
+	cap->version = 0;
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
+		 pci_name(vip->pdev));
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+	    V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+/**
+ * vidioc_s_std - set video standard
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @std: contains standard to be set
+ *
+ * the video standard is set
+ *
+ * return value: 0, no error.
+ *
+ * -EIO, no input signal detected
+ *
+ * other, returned from video DAC.
+ */
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+	v4l2_std_id oldstd = vip->std, newstd;
+	int status;
+
+	if (V4L2_STD_ALL == *std) {
+		v4l2_subdev_call(vip->decoder, core, s_std, *std);
+		ssleep(2);
+		v4l2_subdev_call(vip->decoder, video, querystd, &newstd);
+		v4l2_subdev_call(vip->decoder, video, g_input_status, &status);
+		if (status & V4L2_IN_ST_NO_SIGNAL)
+			return -EIO;
+		*std = vip->std = newstd;
+		if (oldstd != *std) {
+			if (V4L2_STD_525_60 & (*std))
+				vip->format = formats_60[0];
+			else
+				vip->format = formats_50[0];
+		}
+		return 0;
+	}
+
+	if (oldstd != *std) {
+		if (V4L2_STD_525_60 & (*std))
+			vip->format = formats_60[0];
+		else
+			vip->format = formats_50[0];
+	}
+
+	return v4l2_subdev_call(vip->decoder, core, s_std, *std);
+}
+
+/**
+ * vidioc_g_std - get video standard
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @std: contains return values
+ *
+ * the current video standard is returned
+ *
+ * return value: 0, no error.
+ */
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	*std = vip->std;
+	return 0;
+}
+
+/**
+ * vidioc_querystd - get possible video standards
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @std: contains return values
+ *
+ * all possible video standards are returned
+ *
+ * return value: delivered by video DAC routine.
+ */
+static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return v4l2_subdev_call(vip->decoder, video, querystd, std);
+
+}
+
+/**
+ * vidioc_queryctl - get possible control settings
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @ctrl: contains return values
+ *
+ * return possible values for a control
+ * return value: delivered by video DAC routine.
+ */
+static int vidioc_queryctrl(struct file *file, void *priv,
+			    struct v4l2_queryctrl *ctrl)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return v4l2_subdev_call(vip->decoder, core, queryctrl, ctrl);
+}
+
+/**
+ * vidioc_g_ctl - get control value
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @ctrl: contains return values
+ *
+ * return setting for a control value
+ * return value: delivered by video DAC routine.
+ */
+static int vidioc_g_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *ctrl)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return v4l2_subdev_call(vip->decoder, core, g_ctrl, ctrl);
+}
+
+/**
+ * vidioc_s_ctl - set control value
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @ctrl: contains value to be set
+ *
+ * set value for a specific control
+ * return value: delivered by video DAC routine.
+ */
+static int vidioc_s_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *ctrl)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return v4l2_subdev_call(vip->decoder, core, s_ctrl, ctrl);
+}
+
+/**
+ * vidioc_enum_input - return name of input line
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @inp: contains return values
+ *
+ * the user friendly name of the input line is returned
+ *
+ * return value: 0, no error.
+ *
+ * -EINVAL, input line number out of range
+ */
+static int vidioc_enum_input(struct file *file, void *priv,
+			     struct v4l2_input *inp)
+{
+	if (inp->index > 1)
+		return -EINVAL;
+
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+	inp->std = V4L2_STD_ALL;
+	sprintf(inp->name, "Camera %u", inp->index);
+
+	return 0;
+}
+
+/**
+ * vidioc_s_input - set input line
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @i: new input line number
+ *
+ * the current active input line is set
+ *
+ * return value: 0, no error.
+ *
+ * -EINVAL, line number out of range
+ */
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+	int ret;
+
+	if (i > 1)
+		return -EINVAL;
+	ret = v4l2_subdev_call(vip->decoder, video, s_routing, i, 0, 0);
+
+	if (!ret)
+		vip->input = i;
+
+	return 0;
+}
+
+/**
+ * vidioc_g_input - return input line
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @i: returned input line number
+ *
+ * the current active input line is returned
+ *
+ * return value: always 0.
+ */
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	*i = vip->input;
+	return 0;
+}
+
+/**
+ * vidioc_enum_fmt_vid_cap - return video capture format
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @f: returned format information
+ *
+ * returns name and format of video capture
+ * Only UYVY is supported by hardware.
+ *
+ * return value: always 0.
+ */
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+
+	if (f->index != 0)
+		return -EINVAL;
+
+	strcpy(f->description, "4:2:2, packed, UYVY");
+	f->pixelformat = V4L2_PIX_FMT_UYVY;
+	f->flags = 0;
+	return 0;
+}
+
+/**
+ * vidioc_try_fmt_vid_cap - set video capture format
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @f: new format
+ *
+ * new video format is set which includes width and
+ * field type. width is fixed to 720, no scaling.
+ * Only UYVY is supported by this hardware.
+ * the minimum height is 200, the maximum is 576 (PAL)
+ *
+ * return value: 0, no error
+ *
+ * -EINVAL, pixel or field format not supported
+ *
+ */
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+	int interlace_lim;
+
+	if (V4L2_PIX_FMT_UYVY != f->fmt.pix.pixelformat)
+		return -EINVAL;
+
+	if (V4L2_STD_525_60 & vip->std)
+		interlace_lim = 240;
+	else
+		interlace_lim = 288;
+
+	switch (f->fmt.pix.field) {
+	case V4L2_FIELD_ANY:
+		if (interlace_lim < f->fmt.pix.height)
+			f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+		else
+			f->fmt.pix.field = V4L2_FIELD_BOTTOM;
+		break;
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+		if (interlace_lim < f->fmt.pix.height)
+			f->fmt.pix.height = interlace_lim;
+		break;
+	case V4L2_FIELD_INTERLACED:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	f->fmt.pix.height &= ~1;
+	if (2 * interlace_lim < f->fmt.pix.height)
+		f->fmt.pix.height = 2 * interlace_lim;
+	if (200 > f->fmt.pix.height)
+		f->fmt.pix.height = 200;
+	f->fmt.pix.width = 720;
+	f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+	f->fmt.pix.sizeimage = f->fmt.pix.width * 2 * f->fmt.pix.height;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	f->fmt.pix.priv = 0;
+	return 0;
+}
+
+/**
+ * vidioc_s_fmt_vid_cap - set current video format parameters
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @f: returned format information
+ *
+ * set new capture format
+ * return value: 0, no error
+ *
+ * other, delivered by video DAC routine.
+ */
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+	int ret;
+
+	ret = vidioc_try_fmt_vid_cap(file, priv, f);
+	if (ret)
+		return ret;
+
+	memcpy(&vip->format, &f->fmt.pix, sizeof(struct v4l2_pix_format));
+	return 0;
+}
+
+/**
+ * vidioc_g_fmt_vid_cap - get current video format parameters
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @f: contains format information
+ *
+ * returns current video format parameters
+ *
+ * return value: 0, always successful
+ */
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	memcpy(&f->fmt.pix, &vip->format, sizeof(struct v4l2_pix_format));
+	return 0;
+}
+
+/**
+ * vidioc_reqfs - request buffer
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @p: video buffer
+ *
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *p)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_reqbufs(&vip->vb_vidq, p);
+}
+
+/**
+ * vidioc_querybuf - query buffer
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @p: video buffer
+ *
+ * query buffer state.
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_querybuf(&vip->vb_vidq, p);
+}
+
+/**
+ * vidioc_qbuf - queue a buffer
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @p: video buffer
+ *
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_qbuf(&vip->vb_vidq, p);
+}
+
+/**
+ * vidioc_dqbuf - dequeue a buffer
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @p: video buffer
+ *
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_dqbuf(&vip->vb_vidq, p, file->f_flags & O_NONBLOCK);
+}
+
+/**
+ * vidioc_streamon - turn on streaming
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @type: type of capture
+ *
+ * turn on streaming.
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type type)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_streamon(&vip->vb_vidq);
+}
+
+/**
+ * vidioc_streamoff - turn off streaming
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @type: type of capture
+ *
+ * turn off streaming.
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type type)
+{
+	struct video_device *dev = priv;
+	struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+	return videobuf_streamoff(&vip->vb_vidq);
+}
+
+static const struct v4l2_file_operations vip_fops = {
+	.owner = THIS_MODULE,
+	.open = vip_open,
+	.release = vip_close,
+	.ioctl = video_ioctl2,
+	.read = vip_read,
+	.mmap = vip_mmap,
+	.poll = vip_poll
+};
+
+static const struct v4l2_ioctl_ops vip_ioctl_ops = {
+	.vidioc_querycap = vidioc_querycap,
+	.vidioc_s_std = vidioc_s_std,
+	.vidioc_g_std = vidioc_g_std,
+	.vidioc_querystd = vidioc_querystd,
+	.vidioc_queryctrl = vidioc_queryctrl,
+	.vidioc_g_ctrl = vidioc_g_ctrl,
+	.vidioc_s_ctrl = vidioc_s_ctrl,
+	.vidioc_enum_input = vidioc_enum_input,
+	.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+	.vidioc_s_input = vidioc_s_input,
+	.vidioc_g_input = vidioc_g_input,
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+	.vidioc_reqbufs = vidioc_reqbufs,
+	.vidioc_querybuf = vidioc_querybuf,
+	.vidioc_qbuf = vidioc_qbuf,
+	.vidioc_dqbuf = vidioc_dqbuf,
+	.vidioc_streamon = vidioc_streamon,
+	.vidioc_streamoff = vidioc_streamoff,
+};
+
+static struct video_device video_dev_template = {
+	.name = DRV_NAME,
+	.release = video_device_release,
+	.fops = &vip_fops,
+	.ioctl_ops = &vip_ioctl_ops,
+	.tvnorms = V4L2_STD_ALL,
+};
+
+/**
+ * vip_irq - interrupt routine
+ * @irq: Number of interrupt ( not used, correct number is assumed )
+ * @vip: local data structure containing all information
+ *
+ * check for both frame interrupts set ( top and bottom ).
+ * check FIFO overflow, but limit number of log messages after open.
+ * signal a complete buffer if done.
+ * dequeue a new buffer if available.
+ * disable VIP if no buffer available.
+ *
+ * return value: IRQ_NONE, interrupt was not generated by VIP
+ *
+ * IRQ_HANDLED, interrupt done.
+ */
+static irqreturn_t vip_irq(int irq, struct sta2x11_vip *vip)
+{
+	u32 status, dma;
+	unsigned long flags;
+	struct videobuf_buffer *vb;
+
+	status = REG_READ(vip, DVP_ITS);
+
+	if (!status) {
+		pr_debug("VIP: irq ignored\n");
+		return IRQ_NONE;
+	}
+
+	if (!vip->started)
+		return IRQ_HANDLED;
+
+	if (status & DVP_IT_VSB)
+		vip->bcount++;
+
+	if (status & DVP_IT_VST)
+		vip->tcount++;
+
+	if ((DVP_IT_VSB | DVP_IT_VST) == (status & (DVP_IT_VST | DVP_IT_VSB))) {
+		/* this is bad, we are too slow, hope the condition is gone
+		 * on the next frame */
+		pr_info("VIP: both irqs\n");
+		return IRQ_HANDLED;
+	}
+
+	if (status & DVP_IT_FIFO) {
+		if (5 > vip->overflow++)
+			pr_info("VIP: fifo overflow\n");
+	}
+
+	if (2 > vip->tcount)
+		return IRQ_HANDLED;
+
+	if (status & DVP_IT_VSB)
+		return IRQ_HANDLED;
+
+	spin_lock_irqsave(&vip->slock, flags);
+
+	REG_WRITE(vip, DVP_CTL, REG_READ(vip, DVP_CTL) & ~DVP_CTL_ENA);
+	if (vip->active) {
+		do_gettimeofday(&vip->active->ts);
+		vip->active->field_count++;
+		vip->active->state = VIDEOBUF_DONE;
+		wake_up(&vip->active->done);
+		vip->active = NULL;
+	}
+	if (!vip->closing) {
+		if (list_empty(&vip->capture))
+			goto done;
+
+		vb = list_first_entry(&vip->capture, struct videobuf_buffer,
+				      queue);
+		if (NULL == vb) {
+			pr_info("VIP: no buffer\n");
+			goto done;
+		}
+		vb->state = VIDEOBUF_ACTIVE;
+		list_del(&vb->queue);
+		vip->active = vb;
+		dma = videobuf_to_dma_contig(vb);
+		switch (vip->format.field) {
+		case V4L2_FIELD_INTERLACED:
+			REG_WRITE(vip, DVP_VTP, dma);
+			REG_WRITE(vip, DVP_VBP, dma + vip->format.width * 2);
+			break;
+		case V4L2_FIELD_TOP:
+		case V4L2_FIELD_BOTTOM:
+			REG_WRITE(vip, DVP_VTP, dma);
+			REG_WRITE(vip, DVP_VBP, dma);
+			break;
+		default:
+			pr_warning("VIP: unknown field format\n");
+			goto done;
+			break;
+		}
+		REG_WRITE(vip, DVP_CTL, REG_READ(vip, DVP_CTL) | DVP_CTL_ENA);
+	}
+done:
+	spin_unlock_irqrestore(&vip->slock, flags);
+	return IRQ_HANDLED;
+}
+
+/**
+ * vip_gpio_reserve - reserve gpio pin
+ * @dev: device
+ * @pin: GPIO pin number
+ * @dir: direction, input or output
+ * @name: GPIO pin name
+ *
+ */
+static int vip_gpio_reserve(struct device *dev, int pin, int dir,
+			    const char *name)
+{
+	int ret;
+
+	if (pin == -1)
+		return 0;
+
+	ret = gpio_request(pin, name);
+	if (ret) {
+		dev_err(dev, "Failed to allocate pin %d (%s)\n", pin, name);
+		return ret;
+	}
+
+	ret = gpio_direction_output(pin, dir);
+	if (ret) {
+		dev_err(dev, "Failed to set direction for pin %d (%s)\n",
+			pin, name);
+		gpio_free(pin);
+		return ret;
+	}
+
+	ret = gpio_export(pin, false);
+	if (ret) {
+		dev_err(dev, "Failed to export pin %d (%s)\n", pin, name);
+		gpio_free(pin);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * vip_gpio_release - release gpio pin
+ * @dev: device
+ * @pin: GPIO pin number
+ * @name: GPIO pin name
+ *
+ */
+static void vip_gpio_release(struct device *dev, int pin, const char *name)
+{
+	if (pin != -1) {
+		dev_dbg(dev, "releasing pin %d (%s)\n",	pin, name);
+		gpio_unexport(pin);
+		gpio_free(pin);
+	}
+}
+
+/**
+ * sta2x11_vip_init_one - init one instance of video device
+ * @pdev: PCI device
+ * @ent: (not used)
+ *
+ * allocate reset pins for DAC.
+ * Reset video DAC, this is done via reset line.
+ * allocate memory for managing device
+ * request interrupt
+ * map IO region
+ * register device
+ * find and initialize video DAC
+ *
+ * return value: 0, no error
+ *
+ * -ENOMEM, no memory
+ *
+ * -ENODEV, device could not be detected or registered
+ */
+static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
+					  const struct pci_device_id *ent)
+{
+	int ret;
+	struct sta2x11_vip *vip;
+	struct vip_config *config;
+
+	ret = pci_enable_device(pdev);
+	if (ret)
+		return ret;
+
+	config = dev_get_platdata(&pdev->dev);
+	if (!config) {
+		dev_info(&pdev->dev, "VIP slot disabled\n");
+		ret = -EINVAL;
+		goto disable;
+	}
+
+	ret = vip_gpio_reserve(&pdev->dev, config->pwr_pin, 0,
+			       config->pwr_name);
+	if (ret)
+		goto disable;
+
+	if (config->reset_pin >= 0) {
+		ret = vip_gpio_reserve(&pdev->dev, config->reset_pin, 0,
+				       config->reset_name);
+		if (ret) {
+			vip_gpio_release(&pdev->dev, config->pwr_pin,
+					 config->pwr_name);
+			goto disable;
+		}
+	}
+
+	if (config->pwr_pin != -1) {
+		/* Datasheet says 5ms between PWR and RST */
+		usleep_range(5000, 25000);
+		ret = gpio_direction_output(config->pwr_pin, 1);
+	}
+
+	if (config->reset_pin != -1) {
+		/* Datasheet says 5ms between PWR and RST */
+		usleep_range(5000, 25000);
+		ret = gpio_direction_output(config->reset_pin, 1);
+	}
+	usleep_range(5000, 25000);
+
+	vip = kzalloc(sizeof(struct sta2x11_vip), GFP_KERNEL);
+	if (!vip) {
+		ret = -ENOMEM;
+		goto release_gpios;
+	}
+
+	vip->pdev = pdev;
+	vip->std = V4L2_STD_PAL;
+	vip->format = formats_50[0];
+	vip->config = config;
+
+	if (v4l2_device_register(&pdev->dev, &vip->v4l2_dev))
+		goto free_mem;
+
+	dev_dbg(&pdev->dev, "BAR #0 at 0x%lx 0x%lx irq %d\n",
+		(unsigned long)pci_resource_start(pdev, 0),
+		(unsigned long)pci_resource_len(pdev, 0), pdev->irq);
+
+	pci_set_master(pdev);
+
+	ret = pci_request_regions(pdev, DRV_NAME);
+	if (ret)
+		goto unreg;
+
+	vip->iomem = pci_iomap(pdev, 0, 0x100);
+	if (!vip->iomem) {
+		ret = -ENOMEM; /* FIXME */
+		goto release;
+	}
+
+	pci_enable_msi(pdev);
+
+	INIT_LIST_HEAD(&vip->capture);
+	spin_lock_init(&vip->slock);
+	mutex_init(&vip->mutex);
+	vip->started = 0;
+	vip->disabled = 0;
+
+	ret = request_irq(pdev->irq,
+			  (irq_handler_t) vip_irq,
+			  IRQF_SHARED, DRV_NAME, vip);
+	if (ret) {
+		dev_err(&pdev->dev, "request_irq failed\n");
+		ret = -ENODEV;
+		goto unmap;
+	}
+
+	vip->video_dev = video_device_alloc();
+	if (!vip->video_dev) {
+		ret = -ENOMEM;
+		goto release_irq;
+	}
+
+	*(vip->video_dev) = video_dev_template;
+	video_set_drvdata(vip->video_dev, vip);
+
+	ret = video_register_device(vip->video_dev, VFL_TYPE_GRABBER, -1);
+	if (ret)
+		goto vrelease;
+
+	vip->adapter = i2c_get_adapter(vip->config->i2c_id);
+	if (!vip->adapter) {
+		ret = -ENODEV;
+		dev_err(&pdev->dev, "no I2C adapter found\n");
+		goto vunreg;
+	}
+
+	vip->decoder = v4l2_i2c_new_subdev(&vip->v4l2_dev, vip->adapter,
+					   "adv7180", vip->config->i2c_addr,
+					   NULL);
+	if (!vip->decoder) {
+		ret = -ENODEV;
+		dev_err(&pdev->dev, "no decoder found\n");
+		goto vunreg;
+	}
+
+	i2c_put_adapter(vip->adapter);
+
+	v4l2_subdev_call(vip->decoder, core, init, 0);
+
+	pr_info("STA2X11 Video Input Port (VIP) loaded\n");
+	return 0;
+
+vunreg:
+	video_set_drvdata(vip->video_dev, NULL);
+vrelease:
+	if (video_is_registered(vip->video_dev))
+		video_unregister_device(vip->video_dev);
+	else
+		video_device_release(vip->video_dev);
+release_irq:
+	free_irq(pdev->irq, vip);
+	pci_disable_msi(pdev);
+unmap:
+	pci_iounmap(pdev, vip->iomem);
+	mutex_destroy(&vip->mutex);
+release:
+	pci_release_regions(pdev);
+unreg:
+	v4l2_device_unregister(&vip->v4l2_dev);
+free_mem:
+	kfree(vip);
+release_gpios:
+	vip_gpio_release(&pdev->dev, config->reset_pin, config->reset_name);
+	vip_gpio_release(&pdev->dev, config->pwr_pin, config->pwr_name);
+disable:
+	/*
+	 * do not call pci_disable_device on sta2x11 because it break all
+	 * other Bus masters on this EP
+	 */
+	return ret;
+}
+
+/**
+ * sta2x11_vip_remove_one - release device
+ * @pdev: PCI device
+ *
+ * Undo everything done in .._init_one
+ *
+ * unregister video device
+ * free interrupt
+ * unmap ioadresses
+ * free memory
+ * free GPIO pins
+ */
+static void __devexit sta2x11_vip_remove_one(struct pci_dev *pdev)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+	struct sta2x11_vip *vip =
+	    container_of(v4l2_dev, struct sta2x11_vip, v4l2_dev);
+
+	video_set_drvdata(vip->video_dev, NULL);
+	video_unregister_device(vip->video_dev);
+	/*do not call video_device_release() here, is already done */
+	free_irq(pdev->irq, vip);
+	pci_disable_msi(pdev);
+	pci_iounmap(pdev, vip->iomem);
+	pci_release_regions(pdev);
+
+	v4l2_device_unregister(&vip->v4l2_dev);
+	mutex_destroy(&vip->mutex);
+
+	vip_gpio_release(&pdev->dev, vip->config->pwr_pin,
+			 vip->config->pwr_name);
+	vip_gpio_release(&pdev->dev, vip->config->reset_pin,
+			 vip->config->reset_name);
+
+	kfree(vip);
+	/*
+	 * do not call pci_disable_device on sta2x11 because it break all
+	 * other Bus masters on this EP
+	 */
+}
+
+#ifdef CONFIG_PM
+
+/**
+ * sta2x11_vip_suspend - set device into power save mode
+ * @pdev: PCI device
+ * @state: new state of device
+ *
+ * all relevant registers are saved and an attempt to set a new state is made.
+ *
+ * return value: 0 always indicate success,
+ * even if device could not be disabled. (workaround for hardware problem)
+ *
+ * reurn value : 0, always succesful, even if hardware does not not support
+ * power down mode.
+ */
+static int sta2x11_vip_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+	struct sta2x11_vip *vip =
+	    container_of(v4l2_dev, struct sta2x11_vip, v4l2_dev);
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&vip->slock, flags);
+	vip->register_save_area[0] = REG_READ(vip, DVP_CTL);
+	REG_WRITE(vip, DVP_CTL, vip->register_save_area[0] & DVP_CTL_DIS);
+	vip->register_save_area[SAVE_COUNT] = REG_READ(vip, DVP_ITM);
+	REG_WRITE(vip, DVP_ITM, 0);
+	for (i = 1; i < SAVE_COUNT; i++)
+		vip->register_save_area[i] = REG_READ(vip, 4 * i);
+	for (i = 0; i < AUX_COUNT; i++)
+		vip->register_save_area[SAVE_COUNT + IRQ_COUNT + i] =
+		    REG_READ(vip, registers_to_save[i]);
+	spin_unlock_irqrestore(&vip->slock, flags);
+	/* save pci state */
+	pci_save_state(pdev);
+	if (pci_set_power_state(pdev, pci_choose_state(pdev, state))) {
+		/*
+		 * do not call pci_disable_device on sta2x11 because it
+		 * break all other Bus masters on this EP
+		 */
+		vip->disabled = 1;
+	}
+
+	pr_info("VIP: suspend\n");
+	return 0;
+}
+
+/**
+ * sta2x11_vip_resume - resume device operation
+ * @pdev : PCI device
+ *
+ * re-enable device, set PCI state to powered and restore registers.
+ * resume normal device operation afterwards.
+ *
+ * return value: 0, no error.
+ *
+ * other, could not set device to power on state.
+ */
+static int sta2x11_vip_resume(struct pci_dev *pdev)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+	struct sta2x11_vip *vip =
+	    container_of(v4l2_dev, struct sta2x11_vip, v4l2_dev);
+	unsigned long flags;
+	int ret, i;
+
+	pr_info("VIP: resume\n");
+	/* restore pci state */
+	if (vip->disabled) {
+		ret = pci_enable_device(pdev);
+		if (ret) {
+			pr_warning("VIP: Can't enable device.\n");
+			return ret;
+		}
+		vip->disabled = 0;
+	}
+	ret = pci_set_power_state(pdev, PCI_D0);
+	if (ret) {
+		/*
+		 * do not call pci_disable_device on sta2x11 because it
+		 * break all other Bus masters on this EP
+		 */
+		pr_warning("VIP: Can't enable device.\n");
+		vip->disabled = 1;
+		return ret;
+	}
+
+	pci_restore_state(pdev);
+
+	spin_lock_irqsave(&vip->slock, flags);
+	for (i = 1; i < SAVE_COUNT; i++)
+		REG_WRITE(vip, 4 * i, vip->register_save_area[i]);
+	for (i = 0; i < AUX_COUNT; i++)
+		REG_WRITE(vip, registers_to_save[i],
+			  vip->register_save_area[SAVE_COUNT + IRQ_COUNT + i]);
+	REG_WRITE(vip, DVP_CTL, vip->register_save_area[0]);
+	REG_WRITE(vip, DVP_ITM, vip->register_save_area[SAVE_COUNT]);
+	spin_unlock_irqrestore(&vip->slock, flags);
+	return 0;
+}
+
+#endif
+
+static DEFINE_PCI_DEVICE_TABLE(sta2x11_vip_pci_tbl) = {
+	{PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_VIP)},
+	{0,}
+};
+
+static struct pci_driver sta2x11_vip_driver = {
+	.name = DRV_NAME,
+	.probe = sta2x11_vip_init_one,
+	.remove = __devexit_p(sta2x11_vip_remove_one),
+	.id_table = sta2x11_vip_pci_tbl,
+#ifdef CONFIG_PM
+	.suspend = sta2x11_vip_suspend,
+	.resume = sta2x11_vip_resume,
+#endif
+};
+
+static int __init sta2x11_vip_init_module(void)
+{
+	return pci_register_driver(&sta2x11_vip_driver);
+}
+
+static void __exit sta2x11_vip_exit_module(void)
+{
+	pci_unregister_driver(&sta2x11_vip_driver);
+}
+
+#ifdef MODULE
+module_init(sta2x11_vip_init_module);
+module_exit(sta2x11_vip_exit_module);
+#else
+late_initcall_sync(sta2x11_vip_init_module);
+#endif
+
+MODULE_DESCRIPTION("STA2X11 Video Input Port driver");
+MODULE_AUTHOR("Wind River");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("sta2x11 video input");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, sta2x11_vip_pci_tbl);
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.h b/drivers/media/pci/sta2x11/sta2x11_vip.h
new file mode 100644
index 0000000..4f81a13
--- /dev/null
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2011 Wind River Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author:  Anders Wallin <anders.wallin@windriver.com>
+ *
+ */
+
+#ifndef __STA2X11_VIP_H
+#define __STA2X11_VIP_H
+
+/**
+ * struct vip_config - video input configuration data
+ * @pwr_name: ADV powerdown name
+ * @pwr_pin: ADV powerdown pin
+ * @reset_name: ADV reset name
+ * @reset_pin: ADV reset pin
+ */
+struct vip_config {
+	const char *pwr_name;
+	int pwr_pin;
+	const char *reset_name;
+	int reset_pin;
+	int i2c_id;
+	int i2c_addr;
+};
+
+#endif /* __STA2X11_VIP_H */
diff --git a/drivers/media/pci/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig
new file mode 100644
index 0000000..9d83ced
--- /dev/null
+++ b/drivers/media/pci/ttpci/Kconfig
@@ -0,0 +1,159 @@
+config TTPCI_EEPROM
+	tristate
+	depends on I2C
+	default n
+
+config DVB_AV7110
+	tristate "AV7110 cards"
+	depends on DVB_CORE && PCI && I2C
+	select TTPCI_EEPROM
+	select VIDEO_SAA7146_VV
+	depends on VIDEO_DEV	# dependencies of VIDEO_SAA7146_VV
+	select DVB_VES1820 if !DVB_FE_CUSTOMISE
+	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_TDA8083 if !DVB_FE_CUSTOMISE
+	select DVB_SP8870 if !DVB_FE_CUSTOMISE
+	select DVB_STV0297 if !DVB_FE_CUSTOMISE
+	select DVB_L64781 if !DVB_FE_CUSTOMISE
+	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+	help
+	  Support for SAA7146 and AV7110 based DVB cards as produced
+	  by Fujitsu-Siemens, Technotrend, Hauppauge and others.
+
+	  This driver only supports the fullfeatured cards with
+	  onboard MPEG2 decoder.
+
+	  This driver needs an external firmware. Please use the script
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to
+	  download/extract it, and then copy it to /usr/lib/hotplug/firmware
+	  or /lib/firmware (depending on configuration of firmware hotplug).
+
+	  Alternatively, you can download the file and use the kernel's
+	  EXTRA_FIRMWARE configuration option to build it into your
+	  kernel image by adding the filename to the EXTRA_FIRMWARE
+	  configuration option string.
+
+	  Say Y if you own such a card and want to use it.
+
+config DVB_AV7110_OSD
+	bool "AV7110 OSD support"
+	depends on DVB_AV7110
+	default y if DVB_AV7110=y || DVB_AV7110=m
+	help
+	  The AV7110 firmware provides some code to generate an OnScreenDisplay
+	  on the video output. This is kind of nonstandard and not guaranteed to
+	  be maintained.
+
+	  Anyway, some popular DVB software like VDR uses this OSD to render
+	  its menus, so say Y if you want to use this software.
+
+	  All other people say N.
+
+config DVB_BUDGET_CORE
+	tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)"
+	depends on DVB_CORE && PCI && I2C
+	select VIDEO_SAA7146
+	select TTPCI_EEPROM
+	help
+	  Support for simple SAA7146 based DVB cards
+	  (so called Budget- or Nova-PCI cards) without onboard
+	  MPEG2 decoder.
+
+config DVB_BUDGET
+	tristate "Budget cards"
+	depends on DVB_BUDGET_CORE && I2C
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
+	select DVB_VES1820 if !DVB_FE_CUSTOMISE
+	select DVB_L64781 if !DVB_FE_CUSTOMISE
+	select DVB_TDA8083 if !DVB_FE_CUSTOMISE
+	select DVB_S5H1420 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10086 if !DVB_FE_CUSTOMISE
+	select DVB_TDA826X if !DVB_FE_CUSTOMISE
+	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+	select DVB_ISL6423 if !DVB_FE_CUSTOMISE
+	select DVB_STV090x if !DVB_FE_CUSTOMISE
+	select DVB_STV6110x if !DVB_FE_CUSTOMISE
+	help
+	  Support for simple SAA7146 based DVB cards (so called Budget-
+	  or Nova-PCI cards) without onboard MPEG2 decoder, and without
+	  analog inputs or an onboard Common Interface connector.
+
+	  Say Y if you own such a card and want to use it.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called budget.
+
+config DVB_BUDGET_CI
+	tristate "Budget cards with onboard CI connector"
+	depends on DVB_BUDGET_CORE && I2C
+	select DVB_STV0297 if !DVB_FE_CUSTOMISE
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+	select DVB_STB0899 if !DVB_FE_CUSTOMISE
+	select DVB_STB6100 if !DVB_FE_CUSTOMISE
+	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+	select DVB_STV0288 if !DVB_FE_CUSTOMISE
+	select DVB_STB6000 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
+	depends on RC_CORE
+	help
+	  Support for simple SAA7146 based DVB cards
+	  (so called Budget- or Nova-PCI cards) without onboard
+	  MPEG2 decoder, but with onboard Common Interface connector.
+
+	  Note: The Common Interface is not yet supported by this driver
+	  due to lack of information from the vendor.
+
+	  Say Y if you own such a card and want to use it.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called budget-ci.
+
+config DVB_BUDGET_AV
+	tristate "Budget cards with analog video inputs"
+	depends on DVB_BUDGET_CORE && I2C
+	select VIDEO_SAA7146_VV
+	depends on VIDEO_DEV	# dependencies of VIDEO_SAA7146_VV
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+	select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+	select DVB_STB0899 if !DVB_FE_CUSTOMISE
+	select DVB_TDA8261 if !DVB_FE_CUSTOMISE
+	select DVB_TUA6100 if !DVB_FE_CUSTOMISE
+	help
+	  Support for simple SAA7146 based DVB cards
+	  (so called Budget- or Nova-PCI cards) without onboard
+	  MPEG2 decoder, but with one or more analog video inputs.
+
+	  Say Y if you own such a card and want to use it.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called budget-av.
+
+config DVB_BUDGET_PATCH
+	tristate "AV7110 cards with Budget Patch"
+	depends on DVB_BUDGET_CORE && I2C
+	depends on DVB_AV7110
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
+	select DVB_TDA8083 if !DVB_FE_CUSTOMISE
+	help
+	  Support for Budget Patch (full TS) modification on
+	  SAA7146+AV7110 based cards (DVB-S cards). This
+	  driver doesn't use onboard MPEG2 decoder. The
+	  card is driven in Budget-only mode. Card is
+	  required to have loaded firmware to tune properly.
+	  Firmware can be loaded by insertion and removal of
+	  standard AV7110 driver prior to loading this
+	  driver.
+
+	  Say Y if you own such a card and want to use it.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called budget-patch.
diff --git a/drivers/media/pci/ttpci/Makefile b/drivers/media/pci/ttpci/Makefile
new file mode 100644
index 0000000..9890596
--- /dev/null
+++ b/drivers/media/pci/ttpci/Makefile
@@ -0,0 +1,21 @@
+#
+# Makefile for the kernel SAA7146 FULL TS DVB device driver
+# and the AV7110 DVB device driver
+#
+
+dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o
+
+ifdef CONFIG_INPUT_EVDEV
+dvb-ttpci-objs += av7110_ir.o
+endif
+
+obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
+obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o
+obj-$(CONFIG_DVB_BUDGET) += budget.o
+obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o
+obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o
+obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
+obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
+
+ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/
+ccflags-y += -Idrivers/media/tuners
diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c
new file mode 100644
index 0000000..4bd8bd5
--- /dev/null
+++ b/drivers/media/pci/ttpci/av7110.c
@@ -0,0 +1,2939 @@
+/*
+ * driver for the SAA7146 based AV110 cards (like the Fujitsu-Siemens DVB)
+ * av7110.c: initialization and demux stuff
+ *
+ * Copyright (C) 1999-2002 Ralph  Metzler
+ *                       & Marcus Metzler for convergence integrated media GmbH
+ *
+ * originally based on code by:
+ * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org/ 
+ */
+
+
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/timer.h>
+#include <linux/poll.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+#include <linux/crc32.h>
+#include <linux/i2c.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+
+#include <linux/dvb/frontend.h>
+
+#include "dvb_frontend.h"
+
+#include "ttpci-eeprom.h"
+#include "av7110.h"
+#include "av7110_hw.h"
+#include "av7110_av.h"
+#include "av7110_ca.h"
+#include "av7110_ipack.h"
+
+#include "bsbe1.h"
+#include "lnbp21.h"
+#include "bsru6.h"
+
+#define TS_WIDTH  376
+#define TS_HEIGHT 512
+#define TS_BUFLEN (TS_WIDTH*TS_HEIGHT)
+#define TS_MAX_PACKETS (TS_BUFLEN/TS_SIZE)
+
+
+int av7110_debug;
+
+static int vidmode = CVBS_RGB_OUT;
+static int pids_off;
+static int adac = DVB_ADAC_TI;
+static int hw_sections;
+static int rgb_on;
+static int volume = 255;
+static int budgetpatch;
+static int wss_cfg_4_3 = 0x4008;
+static int wss_cfg_16_9 = 0x0007;
+static int tv_standard;
+static int full_ts;
+
+module_param_named(debug, av7110_debug, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)");
+module_param(vidmode, int, 0444);
+MODULE_PARM_DESC(vidmode,"analog video out: 0 off, 1 CVBS+RGB (default), 2 CVBS+YC, 3 YC");
+module_param(pids_off, int, 0444);
+MODULE_PARM_DESC(pids_off,"clear video/audio/PCR PID filters when demux is closed");
+module_param(adac, int, 0444);
+MODULE_PARM_DESC(adac,"audio DAC type: 0 TI, 1 CRYSTAL, 2 MSP (use if autodetection fails)");
+module_param(hw_sections, int, 0444);
+MODULE_PARM_DESC(hw_sections, "0 use software section filter, 1 use hardware");
+module_param(rgb_on, int, 0444);
+MODULE_PARM_DESC(rgb_on, "For Siemens DVB-C cards only: Enable RGB control"
+		" signal on SCART pin 16 to switch SCART video mode from CVBS to RGB");
+module_param(volume, int, 0444);
+MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)");
+module_param(budgetpatch, int, 0444);
+MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)");
+module_param(full_ts, int, 0444);
+MODULE_PARM_DESC(full_ts, "enable code for full-ts hardware modification: 0 disable (default), 1 enable");
+module_param(wss_cfg_4_3, int, 0444);
+MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data");
+module_param(wss_cfg_16_9, int, 0444);
+MODULE_PARM_DESC(wss_cfg_16_9, "WSS 16:9 - default 0x0007 - bit 15: disable, 14: burst mode, 13..0: wss data");
+module_param(tv_standard, int, 0444);
+MODULE_PARM_DESC(tv_standard, "TV standard: 0 PAL (default), 1 NTSC");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static void restart_feeds(struct av7110 *av7110);
+static int budget_start_feed(struct dvb_demux_feed *feed);
+static int budget_stop_feed(struct dvb_demux_feed *feed);
+
+static int av7110_num;
+
+#define FE_FUNC_OVERRIDE(fe_func, av7110_copy, av7110_func) \
+{\
+	if (fe_func != NULL) { \
+		av7110_copy = fe_func; \
+		fe_func = av7110_func; \
+	} \
+}
+
+
+static void init_av7110_av(struct av7110 *av7110)
+{
+	int ret;
+	struct saa7146_dev *dev = av7110->dev;
+
+	/* set internal volume control to maximum */
+	av7110->adac_type = DVB_ADAC_TI;
+	ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
+	if (ret < 0)
+		printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret);
+
+	ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType,
+			    1, (u16) av7110->display_ar);
+	if (ret < 0)
+		printk("dvb-ttpci: unable to set aspect ratio\n");
+	ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
+			    1, av7110->display_panscan);
+	if (ret < 0)
+		printk("dvb-ttpci: unable to set pan scan\n");
+
+	ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 2, wss_cfg_4_3);
+	if (ret < 0)
+		printk("dvb-ttpci: unable to configure 4:3 wss\n");
+	ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 3, wss_cfg_16_9);
+	if (ret < 0)
+		printk("dvb-ttpci: unable to configure 16:9 wss\n");
+
+	ret = av7710_set_video_mode(av7110, vidmode);
+	if (ret < 0)
+		printk("dvb-ttpci:cannot set video mode:%d\n",ret);
+
+	/* handle different card types */
+	/* remaining inits according to card and frontend type */
+	av7110->analog_tuner_flags = 0;
+	av7110->current_input = 0;
+	if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a)
+		av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on
+	if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
+		printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n",
+			av7110->dvb_adapter.num);
+		av7110->adac_type = DVB_ADAC_CRYSTAL;
+		i2c_writereg(av7110, 0x20, 0x01, 0xd2);
+		i2c_writereg(av7110, 0x20, 0x02, 0x49);
+		i2c_writereg(av7110, 0x20, 0x03, 0x00);
+		i2c_writereg(av7110, 0x20, 0x04, 0x00);
+
+		/**
+		 * some special handling for the Siemens DVB-C cards...
+		 */
+	} else if (0 == av7110_init_analog_module(av7110)) {
+		/* done. */
+	}
+	else if (dev->pci->subsystem_vendor == 0x110a) {
+		printk("dvb-ttpci: DVB-C w/o analog module @ card %d detected\n",
+			av7110->dvb_adapter.num);
+		av7110->adac_type = DVB_ADAC_NONE;
+	}
+	else {
+		av7110->adac_type = adac;
+		printk("dvb-ttpci: adac type set to %d @ card %d\n",
+			av7110->adac_type, av7110->dvb_adapter.num);
+	}
+
+	if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP34x0) {
+		// switch DVB SCART on
+		ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);
+		if (ret < 0)
+			printk("dvb-ttpci:cannot switch on SCART(Main):%d\n",ret);
+		ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1);
+		if (ret < 0)
+			printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret);
+		if (rgb_on &&
+		    ((av7110->dev->pci->subsystem_vendor == 0x110a) ||
+		     (av7110->dev->pci->subsystem_vendor == 0x13c2)) &&
+		     (av7110->dev->pci->subsystem_device == 0x0000)) {
+			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16
+			//saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // SCARTpin 8
+		}
+	}
+
+	if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000e)
+		av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, SpdifSwitch, 1, 0); // SPDIF on
+
+	ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
+	if (ret < 0)
+		printk("dvb-ttpci:cannot set volume :%d\n",ret);
+}
+
+static void recover_arm(struct av7110 *av7110)
+{
+	dprintk(4, "%p\n",av7110);
+
+	av7110_bootarm(av7110);
+	msleep(100);
+
+	init_av7110_av(av7110);
+
+	/* card-specific recovery */
+	if (av7110->recover)
+		av7110->recover(av7110);
+
+	restart_feeds(av7110);
+
+#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
+	av7110_check_ir_config(av7110, true);
+#endif
+}
+
+static void av7110_arm_sync(struct av7110 *av7110)
+{
+	if (av7110->arm_thread)
+		kthread_stop(av7110->arm_thread);
+
+	av7110->arm_thread = NULL;
+}
+
+static int arm_thread(void *data)
+{
+	struct av7110 *av7110 = data;
+	u16 newloops = 0;
+	int timeout;
+
+	dprintk(4, "%p\n",av7110);
+
+	for (;;) {
+		timeout = wait_event_interruptible_timeout(av7110->arm_wait,
+			kthread_should_stop(), 5 * HZ);
+
+		if (-ERESTARTSYS == timeout || kthread_should_stop()) {
+			/* got signal or told to quit*/
+			break;
+		}
+
+		if (!av7110->arm_ready)
+			continue;
+
+#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
+		av7110_check_ir_config(av7110, false);
+#endif
+
+		if (mutex_lock_interruptible(&av7110->dcomlock))
+			break;
+		newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
+		mutex_unlock(&av7110->dcomlock);
+
+		if (newloops == av7110->arm_loops || av7110->arm_errors > 3) {
+			printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n",
+			       av7110->dvb_adapter.num);
+
+			recover_arm(av7110);
+
+			if (mutex_lock_interruptible(&av7110->dcomlock))
+				break;
+			newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1;
+			mutex_unlock(&av7110->dcomlock);
+		}
+		av7110->arm_loops = newloops;
+		av7110->arm_errors = 0;
+	}
+
+	return 0;
+}
+
+
+/****************************************************************************
+ * IRQ handling
+ ****************************************************************************/
+
+static int DvbDmxFilterCallback(u8 *buffer1, size_t buffer1_len,
+				u8 *buffer2, size_t buffer2_len,
+				struct dvb_demux_filter *dvbdmxfilter,
+				enum dmx_success success,
+				struct av7110 *av7110)
+{
+	if (!dvbdmxfilter->feed->demux->dmx.frontend)
+		return 0;
+	if (dvbdmxfilter->feed->demux->dmx.frontend->source == DMX_MEMORY_FE)
+		return 0;
+
+	switch (dvbdmxfilter->type) {
+	case DMX_TYPE_SEC:
+		if ((((buffer1[1] << 8) | buffer1[2]) & 0xfff) + 3 != buffer1_len)
+			return 0;
+		if (dvbdmxfilter->doneq) {
+			struct dmx_section_filter *filter = &dvbdmxfilter->filter;
+			int i;
+			u8 xor, neq = 0;
+
+			for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
+				xor = filter->filter_value[i] ^ buffer1[i];
+				neq |= dvbdmxfilter->maskandnotmode[i] & xor;
+			}
+			if (!neq)
+				return 0;
+		}
+		return dvbdmxfilter->feed->cb.sec(buffer1, buffer1_len,
+						  buffer2, buffer2_len,
+						  &dvbdmxfilter->filter,
+						  DMX_OK);
+	case DMX_TYPE_TS:
+		if (!(dvbdmxfilter->feed->ts_type & TS_PACKET))
+			return 0;
+		if (dvbdmxfilter->feed->ts_type & TS_PAYLOAD_ONLY)
+			return dvbdmxfilter->feed->cb.ts(buffer1, buffer1_len,
+							 buffer2, buffer2_len,
+							 &dvbdmxfilter->feed->feed.ts,
+							 DMX_OK);
+		else
+			av7110_p2t_write(buffer1, buffer1_len,
+					 dvbdmxfilter->feed->pid,
+					 &av7110->p2t_filter[dvbdmxfilter->index]);
+	default:
+		return 0;
+	}
+}
+
+
+//#define DEBUG_TIMING
+static inline void print_time(char *s)
+{
+#ifdef DEBUG_TIMING
+	struct timeval tv;
+	do_gettimeofday(&tv);
+	printk("%s: %d.%d\n", s, (int)tv.tv_sec, (int)tv.tv_usec);
+#endif
+}
+
+#define DEBI_READ 0
+#define DEBI_WRITE 1
+static inline void start_debi_dma(struct av7110 *av7110, int dir,
+				  unsigned long addr, unsigned int len)
+{
+	dprintk(8, "%c %08lx %u\n", dir == DEBI_READ ? 'R' : 'W', addr, len);
+	if (saa7146_wait_for_debi_done(av7110->dev, 0)) {
+		printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__);
+		return;
+	}
+
+	SAA7146_ISR_CLEAR(av7110->dev, MASK_19); /* for good measure */
+	SAA7146_IER_ENABLE(av7110->dev, MASK_19);
+	if (len < 5)
+		len = 5; /* we want a real DEBI DMA */
+	if (dir == DEBI_WRITE)
+		iwdebi(av7110, DEBISWAB, addr, 0, (len + 3) & ~3);
+	else
+		irdebi(av7110, DEBISWAB, addr, 0, len);
+}
+
+static void debiirq(unsigned long cookie)
+{
+	struct av7110 *av7110 = (struct av7110 *)cookie;
+	int type = av7110->debitype;
+	int handle = (type >> 8) & 0x1f;
+	unsigned int xfer = 0;
+
+	print_time("debi");
+	dprintk(4, "type 0x%04x\n", type);
+
+	if (type == -1) {
+		printk("DEBI irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n",
+		       jiffies, saa7146_read(av7110->dev, PSR),
+		       saa7146_read(av7110->dev, SSR));
+		goto debi_done;
+	}
+	av7110->debitype = -1;
+
+	switch (type & 0xff) {
+
+	case DATA_TS_RECORD:
+		dvb_dmx_swfilter_packets(&av7110->demux,
+					 (const u8 *) av7110->debi_virt,
+					 av7110->debilen / 188);
+		xfer = RX_BUFF;
+		break;
+
+	case DATA_PES_RECORD:
+		if (av7110->demux.recording)
+			av7110_record_cb(&av7110->p2t[handle],
+					 (u8 *) av7110->debi_virt,
+					 av7110->debilen);
+		xfer = RX_BUFF;
+		break;
+
+	case DATA_IPMPE:
+	case DATA_FSECTION:
+	case DATA_PIPING:
+		if (av7110->handle2filter[handle])
+			DvbDmxFilterCallback((u8 *)av7110->debi_virt,
+					     av7110->debilen, NULL, 0,
+					     av7110->handle2filter[handle],
+					     DMX_OK, av7110);
+		xfer = RX_BUFF;
+		break;
+
+	case DATA_CI_GET:
+	{
+		u8 *data = av7110->debi_virt;
+
+		if ((data[0] < 2) && data[2] == 0xff) {
+			int flags = 0;
+			if (data[5] > 0)
+				flags |= CA_CI_MODULE_PRESENT;
+			if (data[5] > 5)
+				flags |= CA_CI_MODULE_READY;
+			av7110->ci_slot[data[0]].flags = flags;
+		} else
+			ci_get_data(&av7110->ci_rbuffer,
+				    av7110->debi_virt,
+				    av7110->debilen);
+		xfer = RX_BUFF;
+		break;
+	}
+
+	case DATA_COMMON_INTERFACE:
+		CI_handle(av7110, (u8 *)av7110->debi_virt, av7110->debilen);
+#if 0
+	{
+		int i;
+
+		printk("av7110%d: ", av7110->num);
+		printk("%02x ", *(u8 *)av7110->debi_virt);
+		printk("%02x ", *(1+(u8 *)av7110->debi_virt));
+		for (i = 2; i < av7110->debilen; i++)
+			printk("%02x ", (*(i+(unsigned char *)av7110->debi_virt)));
+		for (i = 2; i < av7110->debilen; i++)
+			printk("%c", chtrans(*(i+(unsigned char *)av7110->debi_virt)));
+
+		printk("\n");
+	}
+#endif
+		xfer = RX_BUFF;
+		break;
+
+	case DATA_DEBUG_MESSAGE:
+		((s8*)av7110->debi_virt)[Reserved_SIZE - 1] = 0;
+		printk("%s\n", (s8 *) av7110->debi_virt);
+		xfer = RX_BUFF;
+		break;
+
+	case DATA_CI_PUT:
+		dprintk(4, "debi DATA_CI_PUT\n");
+	case DATA_MPEG_PLAY:
+		dprintk(4, "debi DATA_MPEG_PLAY\n");
+	case DATA_BMP_LOAD:
+		dprintk(4, "debi DATA_BMP_LOAD\n");
+		xfer = TX_BUFF;
+		break;
+	default:
+		break;
+	}
+debi_done:
+	spin_lock(&av7110->debilock);
+	if (xfer)
+		iwdebi(av7110, DEBINOSWAP, xfer, 0, 2);
+	ARM_ClearMailBox(av7110);
+	spin_unlock(&av7110->debilock);
+}
+
+/* irq from av7110 firmware writing the mailbox register in the DPRAM */
+static void gpioirq(unsigned long cookie)
+{
+	struct av7110 *av7110 = (struct av7110 *)cookie;
+	u32 rxbuf, txbuf;
+	int len;
+
+	if (av7110->debitype != -1)
+		/* we shouldn't get any irq while a debi xfer is running */
+		printk("dvb-ttpci: GPIO0 irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n",
+		       jiffies, saa7146_read(av7110->dev, PSR),
+		       saa7146_read(av7110->dev, SSR));
+
+	if (saa7146_wait_for_debi_done(av7110->dev, 0)) {
+		printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__);
+		BUG(); /* maybe we should try resetting the debi? */
+	}
+
+	spin_lock(&av7110->debilock);
+	ARM_ClearIrq(av7110);
+
+	/* see what the av7110 wants */
+	av7110->debitype = irdebi(av7110, DEBINOSWAP, IRQ_STATE, 0, 2);
+	av7110->debilen  = irdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
+	rxbuf = irdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
+	txbuf = irdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
+	len = (av7110->debilen + 3) & ~3;
+
+	print_time("gpio");
+	dprintk(8, "GPIO0 irq 0x%04x %d\n", av7110->debitype, av7110->debilen);
+
+	switch (av7110->debitype & 0xff) {
+
+	case DATA_TS_PLAY:
+	case DATA_PES_PLAY:
+		break;
+
+	case DATA_MPEG_VIDEO_EVENT:
+	{
+		u32 h_ar;
+		struct video_event event;
+
+		av7110->video_size.w = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_WIDTH, 0, 2);
+		h_ar = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_HEIGHT_AR, 0, 2);
+
+		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
+		iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
+
+		av7110->video_size.h = h_ar & 0xfff;
+
+		event.type = VIDEO_EVENT_SIZE_CHANGED;
+		event.u.size.w = av7110->video_size.w;
+		event.u.size.h = av7110->video_size.h;
+		switch ((h_ar >> 12) & 0xf)
+		{
+		case 3:
+			av7110->video_size.aspect_ratio = VIDEO_FORMAT_16_9;
+			event.u.size.aspect_ratio = VIDEO_FORMAT_16_9;
+			av7110->videostate.video_format = VIDEO_FORMAT_16_9;
+			break;
+		case 4:
+			av7110->video_size.aspect_ratio = VIDEO_FORMAT_221_1;
+			event.u.size.aspect_ratio = VIDEO_FORMAT_221_1;
+			av7110->videostate.video_format = VIDEO_FORMAT_221_1;
+			break;
+		default:
+			av7110->video_size.aspect_ratio = VIDEO_FORMAT_4_3;
+			event.u.size.aspect_ratio = VIDEO_FORMAT_4_3;
+			av7110->videostate.video_format = VIDEO_FORMAT_4_3;
+		}
+
+		dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",
+			av7110->video_size.w, av7110->video_size.h,
+			av7110->video_size.aspect_ratio);
+
+		dvb_video_add_event(av7110, &event);
+		break;
+	}
+
+	case DATA_CI_PUT:
+	{
+		int avail;
+		struct dvb_ringbuffer *cibuf = &av7110->ci_wbuffer;
+
+		avail = dvb_ringbuffer_avail(cibuf);
+		if (avail <= 2) {
+			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
+			break;
+		}
+		len = DVB_RINGBUFFER_PEEK(cibuf, 0) << 8;
+		len |= DVB_RINGBUFFER_PEEK(cibuf, 1);
+		if (avail < len + 2) {
+			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
+			break;
+		}
+		DVB_RINGBUFFER_SKIP(cibuf, 2);
+
+		dvb_ringbuffer_read(cibuf, av7110->debi_virt, len);
+
+		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
+		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
+		dprintk(8, "DMA: CI\n");
+		start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len);
+		spin_unlock(&av7110->debilock);
+		wake_up(&cibuf->queue);
+		return;
+	}
+
+	case DATA_MPEG_PLAY:
+		if (!av7110->playing) {
+			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
+			break;
+		}
+		len = 0;
+		if (av7110->debitype & 0x100) {
+			spin_lock(&av7110->aout.lock);
+			len = av7110_pes_play(av7110->debi_virt, &av7110->aout, 2048);
+			spin_unlock(&av7110->aout.lock);
+		}
+		if (len <= 0 && (av7110->debitype & 0x200)
+		    &&av7110->videostate.play_state != VIDEO_FREEZED) {
+			spin_lock(&av7110->avout.lock);
+			len = av7110_pes_play(av7110->debi_virt, &av7110->avout, 2048);
+			spin_unlock(&av7110->avout.lock);
+		}
+		if (len <= 0) {
+			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
+			break;
+		}
+		dprintk(8, "GPIO0 PES_PLAY len=%04x\n", len);
+		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
+		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
+		dprintk(8, "DMA: MPEG_PLAY\n");
+		start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len);
+		spin_unlock(&av7110->debilock);
+		return;
+
+	case DATA_BMP_LOAD:
+		len = av7110->debilen;
+		dprintk(8, "gpio DATA_BMP_LOAD len %d\n", len);
+		if (!len) {
+			av7110->bmp_state = BMP_LOADED;
+			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
+			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
+			wake_up(&av7110->bmpq);
+			dprintk(8, "gpio DATA_BMP_LOAD done\n");
+			break;
+		}
+		if (len > av7110->bmplen)
+			len = av7110->bmplen;
+		if (len > 2 * 1024)
+			len = 2 * 1024;
+		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
+		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
+		memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len);
+		av7110->bmpp += len;
+		av7110->bmplen -= len;
+		dprintk(8, "gpio DATA_BMP_LOAD DMA len %d\n", len);
+		start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE+txbuf, len);
+		spin_unlock(&av7110->debilock);
+		return;
+
+	case DATA_CI_GET:
+	case DATA_COMMON_INTERFACE:
+	case DATA_FSECTION:
+	case DATA_IPMPE:
+	case DATA_PIPING:
+		if (!len || len > 4 * 1024) {
+			iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
+			break;
+		}
+		/* fall through */
+
+	case DATA_TS_RECORD:
+	case DATA_PES_RECORD:
+		dprintk(8, "DMA: TS_REC etc.\n");
+		start_debi_dma(av7110, DEBI_READ, DPRAM_BASE+rxbuf, len);
+		spin_unlock(&av7110->debilock);
+		return;
+
+	case DATA_DEBUG_MESSAGE:
+		if (!len || len > 0xff) {
+			iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
+			break;
+		}
+		start_debi_dma(av7110, DEBI_READ, Reserved, len);
+		spin_unlock(&av7110->debilock);
+		return;
+
+	case DATA_IRCOMMAND:
+		if (av7110->ir.ir_handler)
+			av7110->ir.ir_handler(av7110,
+				swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4)));
+		iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
+		break;
+
+	default:
+		printk("dvb-ttpci: gpioirq unknown type=%d len=%d\n",
+		       av7110->debitype, av7110->debilen);
+		break;
+	}
+	av7110->debitype = -1;
+	ARM_ClearMailBox(av7110);
+	spin_unlock(&av7110->debilock);
+}
+
+
+#ifdef CONFIG_DVB_AV7110_OSD
+static int dvb_osd_ioctl(struct file *file,
+			 unsigned int cmd, void *parg)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct av7110 *av7110 = dvbdev->priv;
+
+	dprintk(4, "%p\n", av7110);
+
+	if (cmd == OSD_SEND_CMD)
+		return av7110_osd_cmd(av7110, (osd_cmd_t *) parg);
+	if (cmd == OSD_GET_CAPABILITY)
+		return av7110_osd_capability(av7110, (osd_cap_t *) parg);
+
+	return -EINVAL;
+}
+
+
+static const struct file_operations dvb_osd_fops = {
+	.owner		= THIS_MODULE,
+	.unlocked_ioctl	= dvb_generic_ioctl,
+	.open		= dvb_generic_open,
+	.release	= dvb_generic_release,
+	.llseek		= noop_llseek,
+};
+
+static struct dvb_device dvbdev_osd = {
+	.priv		= NULL,
+	.users		= 1,
+	.writers	= 1,
+	.fops		= &dvb_osd_fops,
+	.kernel_ioctl	= dvb_osd_ioctl,
+};
+#endif /* CONFIG_DVB_AV7110_OSD */
+
+
+static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
+			  u16 subpid, u16 pcrpid)
+{
+	u16 aflags = 0;
+
+	dprintk(4, "%p\n", av7110);
+
+	if (vpid == 0x1fff || apid == 0x1fff ||
+	    ttpid == 0x1fff || subpid == 0x1fff || pcrpid == 0x1fff) {
+		vpid = apid = ttpid = subpid = pcrpid = 0;
+		av7110->pids[DMX_PES_VIDEO] = 0;
+		av7110->pids[DMX_PES_AUDIO] = 0;
+		av7110->pids[DMX_PES_TELETEXT] = 0;
+		av7110->pids[DMX_PES_PCR] = 0;
+	}
+
+	if (av7110->audiostate.bypass_mode)
+		aflags |= 0x8000;
+
+	return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 6,
+			     pcrpid, vpid, apid, ttpid, subpid, aflags);
+}
+
+int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
+		u16 subpid, u16 pcrpid)
+{
+	int ret = 0;
+	dprintk(4, "%p\n", av7110);
+
+	if (mutex_lock_interruptible(&av7110->pid_mutex))
+		return -ERESTARTSYS;
+
+	if (!(vpid & 0x8000))
+		av7110->pids[DMX_PES_VIDEO] = vpid;
+	if (!(apid & 0x8000))
+		av7110->pids[DMX_PES_AUDIO] = apid;
+	if (!(ttpid & 0x8000))
+		av7110->pids[DMX_PES_TELETEXT] = ttpid;
+	if (!(pcrpid & 0x8000))
+		av7110->pids[DMX_PES_PCR] = pcrpid;
+
+	av7110->pids[DMX_PES_SUBTITLE] = 0;
+
+	if (av7110->fe_synced) {
+		pcrpid = av7110->pids[DMX_PES_PCR];
+		ret = SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid);
+	}
+
+	mutex_unlock(&av7110->pid_mutex);
+	return ret;
+}
+
+
+/******************************************************************************
+ * hardware filter functions
+ ******************************************************************************/
+
+static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter)
+{
+	struct dvb_demux_feed *dvbdmxfeed = dvbdmxfilter->feed;
+	struct av7110 *av7110 = dvbdmxfeed->demux->priv;
+	u16 buf[20];
+	int ret, i;
+	u16 handle;
+//	u16 mode = 0x0320;
+	u16 mode = 0xb96a;
+
+	dprintk(4, "%p\n", av7110);
+
+	if (av7110->full_ts)
+		return 0;
+
+	if (dvbdmxfilter->type == DMX_TYPE_SEC) {
+		if (hw_sections) {
+			buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) |
+				dvbdmxfilter->maskandmode[0];
+			for (i = 3; i < 18; i++)
+				buf[i + 4 - 2] =
+					(dvbdmxfilter->filter.filter_value[i] << 8) |
+					dvbdmxfilter->maskandmode[i];
+			mode = 4;
+		}
+	} else if ((dvbdmxfeed->ts_type & TS_PACKET) &&
+		   !(dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)) {
+		av7110_p2t_init(&av7110->p2t_filter[dvbdmxfilter->index], dvbdmxfeed);
+	}
+
+	buf[0] = (COMTYPE_PID_FILTER << 8) + AddPIDFilter;
+	buf[1] = 16;
+	buf[2] = dvbdmxfeed->pid;
+	buf[3] = mode;
+
+	ret = av7110_fw_request(av7110, buf, 20, &handle, 1);
+	if (ret != 0 || handle >= 32) {
+		printk("dvb-ttpci: %s error  buf %04x %04x %04x %04x  "
+				"ret %d  handle %04x\n",
+				__func__, buf[0], buf[1], buf[2], buf[3],
+				ret, handle);
+		dvbdmxfilter->hw_handle = 0xffff;
+		if (!ret)
+			ret = -1;
+		return ret;
+	}
+
+	av7110->handle2filter[handle] = dvbdmxfilter;
+	dvbdmxfilter->hw_handle = handle;
+
+	return ret;
+}
+
+static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
+{
+	struct av7110 *av7110 = dvbdmxfilter->feed->demux->priv;
+	u16 buf[3];
+	u16 answ[2];
+	int ret;
+	u16 handle;
+
+	dprintk(4, "%p\n", av7110);
+
+	if (av7110->full_ts)
+		return 0;
+
+	handle = dvbdmxfilter->hw_handle;
+	if (handle >= 32) {
+		printk("%s tried to stop invalid filter %04x, filter type = %x\n",
+				__func__, handle, dvbdmxfilter->type);
+		return -EINVAL;
+	}
+
+	av7110->handle2filter[handle] = NULL;
+
+	buf[0] = (COMTYPE_PID_FILTER << 8) + DelPIDFilter;
+	buf[1] = 1;
+	buf[2] = handle;
+	ret = av7110_fw_request(av7110, buf, 3, answ, 2);
+	if (ret != 0 || answ[1] != handle) {
+		printk("dvb-ttpci: %s error  cmd %04x %04x %04x  ret %x  "
+				"resp %04x %04x  pid %d\n",
+				__func__, buf[0], buf[1], buf[2], ret,
+				answ[0], answ[1], dvbdmxfilter->feed->pid);
+		if (!ret)
+			ret = -1;
+	}
+	return ret;
+}
+
+
+static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct av7110 *av7110 = dvbdmx->priv;
+	u16 *pid = dvbdmx->pids, npids[5];
+	int i;
+	int ret = 0;
+
+	dprintk(4, "%p\n", av7110);
+
+	npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff;
+	i = dvbdmxfeed->pes_type;
+	npids[i] = (pid[i]&0x8000) ? 0 : pid[i];
+	if ((i == 2) && npids[i] && (dvbdmxfeed->ts_type & TS_PACKET)) {
+		npids[i] = 0;
+		ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
+		if (!ret)
+			ret = StartHWFilter(dvbdmxfeed->filter);
+		return ret;
+	}
+	if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4) {
+		ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
+		if (ret)
+			return ret;
+	}
+
+	if (dvbdmxfeed->pes_type < 2 && npids[0])
+		if (av7110->fe_synced)
+		{
+			ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+			if (ret)
+				return ret;
+		}
+
+	if ((dvbdmxfeed->ts_type & TS_PACKET) && !av7110->full_ts) {
+		if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000))
+			ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed);
+		if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000))
+			ret = av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed);
+	}
+	return ret;
+}
+
+static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct av7110 *av7110 = dvbdmx->priv;
+	u16 *pid = dvbdmx->pids, npids[5];
+	int i;
+
+	int ret = 0;
+
+	dprintk(4, "%p\n", av7110);
+
+	if (dvbdmxfeed->pes_type <= 1) {
+		ret = av7110_av_stop(av7110, dvbdmxfeed->pes_type ?  RP_VIDEO : RP_AUDIO);
+		if (ret)
+			return ret;
+		if (!av7110->rec_mode)
+			dvbdmx->recording = 0;
+		if (!av7110->playing)
+			dvbdmx->playing = 0;
+	}
+	npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff;
+	i = dvbdmxfeed->pes_type;
+	switch (i) {
+	case 2: //teletext
+		if (dvbdmxfeed->ts_type & TS_PACKET)
+			ret = StopHWFilter(dvbdmxfeed->filter);
+		npids[2] = 0;
+		break;
+	case 0:
+	case 1:
+	case 4:
+		if (!pids_off)
+			return 0;
+		npids[i] = (pid[i]&0x8000) ? 0 : pid[i];
+		break;
+	}
+	if (!ret)
+		ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
+	return ret;
+}
+
+static int av7110_start_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct av7110 *av7110 = demux->priv;
+	int ret = 0;
+
+	dprintk(4, "%p\n", av7110);
+
+	if (!demux->dmx.frontend)
+		return -EINVAL;
+
+	if (!av7110->full_ts && feed->pid > 0x1fff)
+		return -EINVAL;
+
+	if (feed->type == DMX_TYPE_TS) {
+		if ((feed->ts_type & TS_DECODER) &&
+		    (feed->pes_type <= DMX_TS_PES_PCR)) {
+			switch (demux->dmx.frontend->source) {
+			case DMX_MEMORY_FE:
+				if (feed->ts_type & TS_DECODER)
+				       if (feed->pes_type < 2 &&
+					   !(demux->pids[0] & 0x8000) &&
+					   !(demux->pids[1] & 0x8000)) {
+					       dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
+					       dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
+					       ret = av7110_av_start_play(av7110,RP_AV);
+					       if (!ret)
+						       demux->playing = 1;
+					}
+				break;
+			default:
+				ret = dvb_feed_start_pid(feed);
+				break;
+			}
+		} else if ((feed->ts_type & TS_PACKET) &&
+			   (demux->dmx.frontend->source != DMX_MEMORY_FE)) {
+			ret = StartHWFilter(feed->filter);
+		}
+	}
+
+	if (av7110->full_ts) {
+		budget_start_feed(feed);
+		return ret;
+	}
+
+	if (feed->type == DMX_TYPE_SEC) {
+		int i;
+
+		for (i = 0; i < demux->filternum; i++) {
+			if (demux->filter[i].state != DMX_STATE_READY)
+				continue;
+			if (demux->filter[i].type != DMX_TYPE_SEC)
+				continue;
+			if (demux->filter[i].filter.parent != &feed->feed.sec)
+				continue;
+			demux->filter[i].state = DMX_STATE_GO;
+			if (demux->dmx.frontend->source != DMX_MEMORY_FE) {
+				ret = StartHWFilter(&demux->filter[i]);
+				if (ret)
+					break;
+			}
+		}
+	}
+
+	return ret;
+}
+
+
+static int av7110_stop_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct av7110 *av7110 = demux->priv;
+	int i, rc, ret = 0;
+	dprintk(4, "%p\n", av7110);
+
+	if (feed->type == DMX_TYPE_TS) {
+		if (feed->ts_type & TS_DECODER) {
+			if (feed->pes_type >= DMX_TS_PES_OTHER ||
+			    !demux->pesfilter[feed->pes_type])
+				return -EINVAL;
+			demux->pids[feed->pes_type] |= 0x8000;
+			demux->pesfilter[feed->pes_type] = NULL;
+		}
+		if (feed->ts_type & TS_DECODER &&
+		    feed->pes_type < DMX_TS_PES_OTHER) {
+			ret = dvb_feed_stop_pid(feed);
+		} else
+			if ((feed->ts_type & TS_PACKET) &&
+			    (demux->dmx.frontend->source != DMX_MEMORY_FE))
+				ret = StopHWFilter(feed->filter);
+	}
+
+	if (av7110->full_ts) {
+		budget_stop_feed(feed);
+		return ret;
+	}
+
+	if (feed->type == DMX_TYPE_SEC) {
+		for (i = 0; i<demux->filternum; i++) {
+			if (demux->filter[i].state == DMX_STATE_GO &&
+			    demux->filter[i].filter.parent == &feed->feed.sec) {
+				demux->filter[i].state = DMX_STATE_READY;
+				if (demux->dmx.frontend->source != DMX_MEMORY_FE) {
+					rc = StopHWFilter(&demux->filter[i]);
+					if (!ret)
+						ret = rc;
+					/* keep going, stop as many filters as possible */
+				}
+			}
+		}
+	}
+
+	return ret;
+}
+
+
+static void restart_feeds(struct av7110 *av7110)
+{
+	struct dvb_demux *dvbdmx = &av7110->demux;
+	struct dvb_demux_feed *feed;
+	int mode;
+	int feeding;
+	int i, j;
+
+	dprintk(4, "%p\n", av7110);
+
+	mode = av7110->playing;
+	av7110->playing = 0;
+	av7110->rec_mode = 0;
+
+	feeding = av7110->feeding1; /* full_ts mod */
+
+	for (i = 0; i < dvbdmx->feednum; i++) {
+		feed = &dvbdmx->feed[i];
+		if (feed->state == DMX_STATE_GO) {
+			if (feed->type == DMX_TYPE_SEC) {
+				for (j = 0; j < dvbdmx->filternum; j++) {
+					if (dvbdmx->filter[j].type != DMX_TYPE_SEC)
+						continue;
+					if (dvbdmx->filter[j].filter.parent != &feed->feed.sec)
+						continue;
+					if (dvbdmx->filter[j].state == DMX_STATE_GO)
+						dvbdmx->filter[j].state = DMX_STATE_READY;
+				}
+			}
+			av7110_start_feed(feed);
+		}
+	}
+
+	av7110->feeding1 = feeding; /* full_ts mod */
+
+	if (mode)
+		av7110_av_start_play(av7110, mode);
+}
+
+static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
+		       uint64_t *stc, unsigned int *base)
+{
+	int ret;
+	u16 fwstc[4];
+	u16 tag = ((COMTYPE_REQUEST << 8) + ReqSTC);
+	struct dvb_demux *dvbdemux;
+	struct av7110 *av7110;
+
+	/* pointer casting paranoia... */
+	BUG_ON(!demux);
+	dvbdemux = demux->priv;
+	BUG_ON(!dvbdemux);
+	av7110 = dvbdemux->priv;
+
+	dprintk(4, "%p\n", av7110);
+
+	if (num != 0)
+		return -EINVAL;
+
+	ret = av7110_fw_request(av7110, &tag, 0, fwstc, 4);
+	if (ret) {
+		printk(KERN_ERR "%s: av7110_fw_request error\n", __func__);
+		return ret;
+	}
+	dprintk(2, "fwstc = %04hx %04hx %04hx %04hx\n",
+		fwstc[0], fwstc[1], fwstc[2], fwstc[3]);
+
+	*stc =	(((uint64_t) ((fwstc[3] & 0x8000) >> 15)) << 32) |
+		(((uint64_t)  fwstc[1]) << 16) | ((uint64_t) fwstc[0]);
+	*base = 1;
+
+	dprintk(4, "stc = %lu\n", (unsigned long)*stc);
+
+	return 0;
+}
+
+
+/******************************************************************************
+ * SEC device file operations
+ ******************************************************************************/
+
+
+static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct av7110* av7110 = fe->dvb->priv;
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		return Set22K(av7110, 1);
+
+	case SEC_TONE_OFF:
+		return Set22K(av7110, 0);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe,
+					 struct dvb_diseqc_master_cmd* cmd)
+{
+	struct av7110* av7110 = fe->dvb->priv;
+
+	return av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1);
+}
+
+static int av7110_diseqc_send_burst(struct dvb_frontend* fe,
+				    fe_sec_mini_cmd_t minicmd)
+{
+	struct av7110* av7110 = fe->dvb->priv;
+
+	return av7110_diseqc_send(av7110, 0, NULL, minicmd);
+}
+
+/* simplified code from budget-core.c */
+static int stop_ts_capture(struct av7110 *budget)
+{
+	dprintk(2, "budget: %p\n", budget);
+
+	if (--budget->feeding1)
+		return budget->feeding1;
+	saa7146_write(budget->dev, MC1, MASK_20);	/* DMA3 off */
+	SAA7146_IER_DISABLE(budget->dev, MASK_10);
+	SAA7146_ISR_CLEAR(budget->dev, MASK_10);
+	return 0;
+}
+
+static int start_ts_capture(struct av7110 *budget)
+{
+	dprintk(2, "budget: %p\n", budget);
+
+	if (budget->feeding1)
+		return ++budget->feeding1;
+	memset(budget->grabbing, 0x00, TS_BUFLEN);
+	budget->ttbp = 0;
+	SAA7146_ISR_CLEAR(budget->dev, MASK_10);  /* VPE */
+	SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */
+	saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */
+	return ++budget->feeding1;
+}
+
+static int budget_start_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct av7110 *budget = demux->priv;
+	int status;
+
+	dprintk(2, "av7110: %p\n", budget);
+
+	spin_lock(&budget->feedlock1);
+	feed->pusi_seen = 0; /* have a clean section start */
+	status = start_ts_capture(budget);
+	spin_unlock(&budget->feedlock1);
+	return status;
+}
+
+static int budget_stop_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct av7110 *budget = demux->priv;
+	int status;
+
+	dprintk(2, "budget: %p\n", budget);
+
+	spin_lock(&budget->feedlock1);
+	status = stop_ts_capture(budget);
+	spin_unlock(&budget->feedlock1);
+	return status;
+}
+
+static void vpeirq(unsigned long cookie)
+{
+	struct av7110 *budget = (struct av7110 *)cookie;
+	u8 *mem = (u8 *) (budget->grabbing);
+	u32 olddma = budget->ttbp;
+	u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
+	struct dvb_demux *demux = budget->full_ts ? &budget->demux : &budget->demux1;
+
+	/* nearest lower position divisible by 188 */
+	newdma -= newdma % 188;
+
+	if (newdma >= TS_BUFLEN)
+		return;
+
+	budget->ttbp = newdma;
+
+	if (!budget->feeding1 || (newdma == olddma))
+		return;
+
+	/* Ensure streamed PCI data is synced to CPU */
+	pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE);
+
+#if 0
+	/* track rps1 activity */
+	printk("vpeirq: %02x Event Counter 1 0x%04x\n",
+	       mem[olddma],
+	       saa7146_read(budget->dev, EC1R) & 0x3fff);
+#endif
+
+	if (newdma > olddma)
+		/* no wraparound, dump olddma..newdma */
+		dvb_dmx_swfilter_packets(demux, mem + olddma, (newdma - olddma) / 188);
+	else {
+		/* wraparound, dump olddma..buflen and 0..newdma */
+		dvb_dmx_swfilter_packets(demux, mem + olddma, (TS_BUFLEN - olddma) / 188);
+		dvb_dmx_swfilter_packets(demux, mem, newdma / 188);
+	}
+}
+
+static int av7110_register(struct av7110 *av7110)
+{
+	int ret, i;
+	struct dvb_demux *dvbdemux = &av7110->demux;
+	struct dvb_demux *dvbdemux1 = &av7110->demux1;
+
+	dprintk(4, "%p\n", av7110);
+
+	if (av7110->registered)
+		return -1;
+
+	av7110->registered = 1;
+
+	dvbdemux->priv = (void *) av7110;
+
+	for (i = 0; i < 32; i++)
+		av7110->handle2filter[i] = NULL;
+
+	dvbdemux->filternum = (av7110->full_ts) ? 256 : 32;
+	dvbdemux->feednum = (av7110->full_ts) ? 256 : 32;
+	dvbdemux->start_feed = av7110_start_feed;
+	dvbdemux->stop_feed = av7110_stop_feed;
+	dvbdemux->write_to_decoder = av7110_write_to_decoder;
+	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+				      DMX_MEMORY_BASED_FILTERING);
+
+	dvb_dmx_init(&av7110->demux);
+	av7110->demux.dmx.get_stc = dvb_get_stc;
+
+	av7110->dmxdev.filternum = (av7110->full_ts) ? 256 : 32;
+	av7110->dmxdev.demux = &dvbdemux->dmx;
+	av7110->dmxdev.capabilities = 0;
+
+	dvb_dmxdev_init(&av7110->dmxdev, &av7110->dvb_adapter);
+
+	av7110->hw_frontend.source = DMX_FRONTEND_0;
+
+	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &av7110->hw_frontend);
+
+	if (ret < 0)
+		return ret;
+
+	av7110->mem_frontend.source = DMX_MEMORY_FE;
+
+	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &av7110->mem_frontend);
+
+	if (ret < 0)
+		return ret;
+
+	ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx,
+					     &av7110->hw_frontend);
+	if (ret < 0)
+		return ret;
+
+	av7110_av_register(av7110);
+	av7110_ca_register(av7110);
+
+#ifdef CONFIG_DVB_AV7110_OSD
+	dvb_register_device(&av7110->dvb_adapter, &av7110->osd_dev,
+			    &dvbdev_osd, av7110, DVB_DEVICE_OSD);
+#endif
+
+	dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx);
+
+	if (budgetpatch) {
+		/* initialize software demux1 without its own frontend
+		 * demux1 hardware is connected to frontend0 of demux0
+		 */
+		dvbdemux1->priv = (void *) av7110;
+
+		dvbdemux1->filternum = 256;
+		dvbdemux1->feednum = 256;
+		dvbdemux1->start_feed = budget_start_feed;
+		dvbdemux1->stop_feed = budget_stop_feed;
+		dvbdemux1->write_to_decoder = NULL;
+
+		dvbdemux1->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+					       DMX_MEMORY_BASED_FILTERING);
+
+		dvb_dmx_init(&av7110->demux1);
+
+		av7110->dmxdev1.filternum = 256;
+		av7110->dmxdev1.demux = &dvbdemux1->dmx;
+		av7110->dmxdev1.capabilities = 0;
+
+		dvb_dmxdev_init(&av7110->dmxdev1, &av7110->dvb_adapter);
+
+		dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net1, &dvbdemux1->dmx);
+		printk("dvb-ttpci: additional demux1 for budget-patch registered\n");
+	}
+	return 0;
+}
+
+
+static void dvb_unregister(struct av7110 *av7110)
+{
+	struct dvb_demux *dvbdemux = &av7110->demux;
+	struct dvb_demux *dvbdemux1 = &av7110->demux1;
+
+	dprintk(4, "%p\n", av7110);
+
+	if (!av7110->registered)
+		return;
+
+	if (budgetpatch) {
+		dvb_net_release(&av7110->dvb_net1);
+		dvbdemux->dmx.close(&dvbdemux1->dmx);
+		dvb_dmxdev_release(&av7110->dmxdev1);
+		dvb_dmx_release(&av7110->demux1);
+	}
+
+	dvb_net_release(&av7110->dvb_net);
+
+	dvbdemux->dmx.close(&dvbdemux->dmx);
+	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->hw_frontend);
+	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->mem_frontend);
+
+	dvb_dmxdev_release(&av7110->dmxdev);
+	dvb_dmx_release(&av7110->demux);
+
+	if (av7110->fe != NULL) {
+		dvb_unregister_frontend(av7110->fe);
+		dvb_frontend_detach(av7110->fe);
+	}
+	dvb_unregister_device(av7110->osd_dev);
+	av7110_av_unregister(av7110);
+	av7110_ca_unregister(av7110);
+}
+
+
+/****************************************************************************
+ * I2C client commands
+ ****************************************************************************/
+
+int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val)
+{
+	u8 msg[2] = { reg, val };
+	struct i2c_msg msgs;
+
+	msgs.flags = 0;
+	msgs.addr = id / 2;
+	msgs.len = 2;
+	msgs.buf = msg;
+	return i2c_transfer(&av7110->i2c_adap, &msgs, 1);
+}
+
+u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg)
+{
+	u8 mm1[] = {0x00};
+	u8 mm2[] = {0x00};
+	struct i2c_msg msgs[2];
+
+	msgs[0].flags = 0;
+	msgs[1].flags = I2C_M_RD;
+	msgs[0].addr = msgs[1].addr = id / 2;
+	mm1[0] = reg;
+	msgs[0].len = 1; msgs[1].len = 1;
+	msgs[0].buf = mm1; msgs[1].buf = mm2;
+	i2c_transfer(&av7110->i2c_adap, msgs, 2);
+
+	return mm2[0];
+}
+
+/****************************************************************************
+ * INITIALIZATION
+ ****************************************************************************/
+
+
+static int check_firmware(struct av7110* av7110)
+{
+	u32 crc = 0, len = 0;
+	unsigned char *ptr;
+
+	/* check for firmware magic */
+	ptr = av7110->bin_fw;
+	if (ptr[0] != 'A' || ptr[1] != 'V' ||
+	    ptr[2] != 'F' || ptr[3] != 'W') {
+		printk("dvb-ttpci: this is not an av7110 firmware\n");
+		return -EINVAL;
+	}
+	ptr += 4;
+
+	/* check dpram file */
+	crc = get_unaligned_be32(ptr);
+	ptr += 4;
+	len = get_unaligned_be32(ptr);
+	ptr += 4;
+	if (len >= 512) {
+		printk("dvb-ttpci: dpram file is way too big.\n");
+		return -EINVAL;
+	}
+	if (crc != crc32_le(0, ptr, len)) {
+		printk("dvb-ttpci: crc32 of dpram file does not match.\n");
+		return -EINVAL;
+	}
+	av7110->bin_dpram = ptr;
+	av7110->size_dpram = len;
+	ptr += len;
+
+	/* check root file */
+	crc = get_unaligned_be32(ptr);
+	ptr += 4;
+	len = get_unaligned_be32(ptr);
+	ptr += 4;
+
+	if (len <= 200000 || len >= 300000 ||
+	    len > ((av7110->bin_fw + av7110->size_fw) - ptr)) {
+		printk("dvb-ttpci: root file has strange size (%d). aborting.\n", len);
+		return -EINVAL;
+	}
+	if( crc != crc32_le(0, ptr, len)) {
+		printk("dvb-ttpci: crc32 of root file does not match.\n");
+		return -EINVAL;
+	}
+	av7110->bin_root = ptr;
+	av7110->size_root = len;
+	return 0;
+}
+
+static void put_firmware(struct av7110* av7110)
+{
+	vfree(av7110->bin_fw);
+}
+
+static int get_firmware(struct av7110* av7110)
+{
+	int ret;
+	const struct firmware *fw;
+
+	/* request the av7110 firmware, this will block until someone uploads it */
+	ret = request_firmware(&fw, "dvb-ttpci-01.fw", &av7110->dev->pci->dev);
+	if (ret) {
+		if (ret == -ENOENT) {
+			printk(KERN_ERR "dvb-ttpci: could not load firmware,"
+			       " file not found: dvb-ttpci-01.fw\n");
+			printk(KERN_ERR "dvb-ttpci: usually this should be in "
+			       "/usr/lib/hotplug/firmware or /lib/firmware\n");
+			printk(KERN_ERR "dvb-ttpci: and can be downloaded from"
+			       " http://www.linuxtv.org/download/dvb/firmware/\n");
+		} else
+			printk(KERN_ERR "dvb-ttpci: cannot request firmware"
+			       " (error %i)\n", ret);
+		return -EINVAL;
+	}
+
+	if (fw->size <= 200000) {
+		printk("dvb-ttpci: this firmware is way too small.\n");
+		release_firmware(fw);
+		return -EINVAL;
+	}
+
+	/* check if the firmware is available */
+	av7110->bin_fw = vmalloc(fw->size);
+	if (NULL == av7110->bin_fw) {
+		dprintk(1, "out of memory\n");
+		release_firmware(fw);
+		return -ENOMEM;
+	}
+
+	memcpy(av7110->bin_fw, fw->data, fw->size);
+	av7110->size_fw = fw->size;
+	if ((ret = check_firmware(av7110)))
+		vfree(av7110->bin_fw);
+
+	release_firmware(fw);
+	return ret;
+}
+
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct av7110* av7110 = fe->dvb->priv;
+	u8 pwr = 0;
+	u8 buf[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	u32 div = (p->frequency + 479500) / 125;
+
+	if (p->frequency > 2000000)
+		pwr = 3;
+	else if (p->frequency > 1800000)
+		pwr = 2;
+	else if (p->frequency > 1600000)
+		pwr = 1;
+	else if (p->frequency > 1200000)
+		pwr = 0;
+	else if (p->frequency >= 1100000)
+		pwr = 1;
+	else
+		pwr = 2;
+
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = ((div & 0x18000) >> 10) | 0x95;
+	buf[3] = (pwr << 6) | 0x30;
+
+	// NOTE: since we're using a prescaler of 2, we set the
+	// divisor frequency to 62.5kHz and divide by 125 above
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static struct ves1x93_config alps_bsrv2_config = {
+	.demod_address = 0x08,
+	.xin = 90100000UL,
+	.invert_pwm = 0,
+};
+
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct av7110* av7110 = fe->dvb->priv;
+	u32 div;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = (p->frequency + 35937500 + 31250) / 62500;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x85 | ((div >> 10) & 0x60);
+	data[3] = (p->frequency < 174000000 ? 0x88 : p->frequency < 470000000 ? 0x84 : 0x81);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static struct ves1820_config alps_tdbe2_config = {
+	.demod_address = 0x09,
+	.xin = 57840000UL,
+	.invert = 1,
+	.selagc = VES1820_SELAGC_SIGNAMPERR,
+};
+
+
+
+
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct av7110* av7110 = fe->dvb->priv;
+	u32 div;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = p->frequency / 125;
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x8e;
+	data[3] = 0x00;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static struct tda8083_config grundig_29504_451_config = {
+	.demod_address = 0x68,
+};
+
+
+
+static int philips_cd1516_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct av7110* av7110 = fe->dvb->priv;
+	u32 div;
+	u32 f = p->frequency;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = (f + 36125000 + 31250) / 62500;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x8e;
+	data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static struct ves1820_config philips_cd1516_config = {
+	.demod_address = 0x09,
+	.xin = 57840000UL,
+	.invert = 1,
+	.selagc = VES1820_SELAGC_SIGNAMPERR,
+};
+
+
+
+static int alps_tdlb7_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct av7110* av7110 = fe->dvb->priv;
+	u32 div, pwr;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = (p->frequency + 36200000) / 166666;
+
+	if (p->frequency <= 782000000)
+		pwr = 1;
+	else
+		pwr = 2;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x85;
+	data[3] = pwr << 6;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+#if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE)
+	struct av7110* av7110 = fe->dvb->priv;
+
+	return request_firmware(fw, name, &av7110->dev->pci->dev);
+#else
+	return -EINVAL;
+#endif
+}
+
+static struct sp8870_config alps_tdlb7_config = {
+
+	.demod_address = 0x71,
+	.request_firmware = alps_tdlb7_request_firmware,
+};
+
+
+static u8 nexusca_stv0297_inittab[] = {
+	0x80, 0x01,
+	0x80, 0x00,
+	0x81, 0x01,
+	0x81, 0x00,
+	0x00, 0x09,
+	0x01, 0x69,
+	0x03, 0x00,
+	0x04, 0x00,
+	0x07, 0x00,
+	0x08, 0x00,
+	0x20, 0x00,
+	0x21, 0x40,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x24, 0x40,
+	0x25, 0x88,
+	0x30, 0xff,
+	0x31, 0x00,
+	0x32, 0xff,
+	0x33, 0x00,
+	0x34, 0x50,
+	0x35, 0x7f,
+	0x36, 0x00,
+	0x37, 0x20,
+	0x38, 0x00,
+	0x40, 0x1c,
+	0x41, 0xff,
+	0x42, 0x29,
+	0x43, 0x00,
+	0x44, 0xff,
+	0x45, 0x00,
+	0x46, 0x00,
+	0x49, 0x04,
+	0x4a, 0x00,
+	0x4b, 0x7b,
+	0x52, 0x30,
+	0x55, 0xae,
+	0x56, 0x47,
+	0x57, 0xe1,
+	0x58, 0x3a,
+	0x5a, 0x1e,
+	0x5b, 0x34,
+	0x60, 0x00,
+	0x63, 0x00,
+	0x64, 0x00,
+	0x65, 0x00,
+	0x66, 0x00,
+	0x67, 0x00,
+	0x68, 0x00,
+	0x69, 0x00,
+	0x6a, 0x02,
+	0x6b, 0x00,
+	0x70, 0xff,
+	0x71, 0x00,
+	0x72, 0x00,
+	0x73, 0x00,
+	0x74, 0x0c,
+	0x80, 0x00,
+	0x81, 0x00,
+	0x82, 0x00,
+	0x83, 0x00,
+	0x84, 0x04,
+	0x85, 0x80,
+	0x86, 0x24,
+	0x87, 0x78,
+	0x88, 0x10,
+	0x89, 0x00,
+	0x90, 0x01,
+	0x91, 0x01,
+	0xa0, 0x04,
+	0xa1, 0x00,
+	0xa2, 0x00,
+	0xb0, 0x91,
+	0xb1, 0x0b,
+	0xc0, 0x53,
+	0xc1, 0x70,
+	0xc2, 0x12,
+	0xd0, 0x00,
+	0xd1, 0x00,
+	0xd2, 0x00,
+	0xd3, 0x00,
+	0xd4, 0x00,
+	0xd5, 0x00,
+	0xde, 0x00,
+	0xdf, 0x00,
+	0x61, 0x49,
+	0x62, 0x0b,
+	0x53, 0x08,
+	0x59, 0x08,
+	0xff, 0xff,
+};
+
+static int nexusca_stv0297_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct av7110* av7110 = fe->dvb->priv;
+	u32 div;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x63, .flags = 0, .buf = data, .len = sizeof(data) };
+	struct i2c_msg readmsg = { .addr = 0x63, .flags = I2C_M_RD, .buf = data, .len = 1 };
+	int i;
+
+	div = (p->frequency + 36150000 + 31250) / 62500;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0xce;
+
+	if (p->frequency < 45000000)
+		return -EINVAL;
+	else if (p->frequency < 137000000)
+		data[3] = 0x01;
+	else if (p->frequency < 403000000)
+		data[3] = 0x02;
+	else if (p->frequency < 860000000)
+		data[3] = 0x04;
+	else
+		return -EINVAL;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) {
+		printk("nexusca: pll transfer failed!\n");
+		return -EIO;
+	}
+
+	// wait for PLL lock
+	for(i = 0; i < 20; i++) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		if (i2c_transfer(&av7110->i2c_adap, &readmsg, 1) == 1)
+			if (data[0] & 0x40) break;
+		msleep(10);
+	}
+
+	return 0;
+}
+
+static struct stv0297_config nexusca_stv0297_config = {
+
+	.demod_address = 0x1C,
+	.inittab = nexusca_stv0297_inittab,
+	.invert = 1,
+	.stop_during_read = 1,
+};
+
+
+
+static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct av7110* av7110 = fe->dvb->priv;
+	u32 div;
+	u8 cfg, cpump, band_select;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = (36125000 + p->frequency) / 166666;
+
+	cfg = 0x88;
+
+	if (p->frequency < 175000000)
+		cpump = 2;
+	else if (p->frequency < 390000000)
+		cpump = 1;
+	else if (p->frequency < 470000000)
+		cpump = 2;
+	else if (p->frequency < 750000000)
+		cpump = 1;
+	else
+		cpump = 3;
+
+	if (p->frequency < 175000000)
+		band_select = 0x0e;
+	else if (p->frequency < 470000000)
+		band_select = 0x05;
+	else
+		band_select = 0x03;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = ((div >> 10) & 0x60) | cfg;
+	data[3] = (cpump << 6) | band_select;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) return -EIO;
+	return 0;
+}
+
+static struct l64781_config grundig_29504_401_config = {
+	.demod_address = 0x55,
+};
+
+
+
+static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
+{
+	int ret = 0;
+	int synced = (status & FE_HAS_LOCK) ? 1 : 0;
+
+	av7110->fe_status = status;
+
+	if (av7110->fe_synced == synced)
+		return 0;
+
+	if (av7110->playing) {
+		av7110->fe_synced = synced;
+		return 0;
+	}
+
+	if (mutex_lock_interruptible(&av7110->pid_mutex))
+		return -ERESTARTSYS;
+
+	if (synced) {
+		ret = SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO],
+			av7110->pids[DMX_PES_AUDIO],
+			av7110->pids[DMX_PES_TELETEXT], 0,
+			av7110->pids[DMX_PES_PCR]);
+		if (!ret)
+			ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+	} else {
+		ret = SetPIDs(av7110, 0, 0, 0, 0, 0);
+		if (!ret) {
+			ret = av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0);
+			if (!ret)
+				ret = av7110_wait_msgstate(av7110, GPMQBusy);
+		}
+	}
+
+	if (!ret)
+		av7110->fe_synced = synced;
+
+	mutex_unlock(&av7110->pid_mutex);
+	return ret;
+}
+
+static int av7110_fe_set_frontend(struct dvb_frontend *fe)
+{
+	struct av7110* av7110 = fe->dvb->priv;
+
+	int ret = av7110_fe_lock_fix(av7110, 0);
+	if (!ret)
+		ret = av7110->fe_set_frontend(fe);
+
+	return ret;
+}
+
+static int av7110_fe_init(struct dvb_frontend* fe)
+{
+	struct av7110* av7110 = fe->dvb->priv;
+
+	int ret = av7110_fe_lock_fix(av7110, 0);
+	if (!ret)
+		ret = av7110->fe_init(fe);
+	return ret;
+}
+
+static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct av7110* av7110 = fe->dvb->priv;
+
+	/* call the real implementation */
+	int ret = av7110->fe_read_status(fe, status);
+	if (!ret)
+		if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK))
+			ret = av7110_fe_lock_fix(av7110, *status);
+	return ret;
+}
+
+static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe)
+{
+	struct av7110* av7110 = fe->dvb->priv;
+
+	int ret = av7110_fe_lock_fix(av7110, 0);
+	if (!ret)
+		ret = av7110->fe_diseqc_reset_overload(fe);
+	return ret;
+}
+
+static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe,
+					    struct dvb_diseqc_master_cmd* cmd)
+{
+	struct av7110* av7110 = fe->dvb->priv;
+
+	int ret = av7110_fe_lock_fix(av7110, 0);
+	if (!ret) {
+		av7110->saved_master_cmd = *cmd;
+		ret = av7110->fe_diseqc_send_master_cmd(fe, cmd);
+	}
+	return ret;
+}
+
+static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+	struct av7110* av7110 = fe->dvb->priv;
+
+	int ret = av7110_fe_lock_fix(av7110, 0);
+	if (!ret) {
+		av7110->saved_minicmd = minicmd;
+		ret = av7110->fe_diseqc_send_burst(fe, minicmd);
+	}
+	return ret;
+}
+
+static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct av7110* av7110 = fe->dvb->priv;
+
+	int ret = av7110_fe_lock_fix(av7110, 0);
+	if (!ret) {
+		av7110->saved_tone = tone;
+		ret = av7110->fe_set_tone(fe, tone);
+	}
+	return ret;
+}
+
+static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	struct av7110* av7110 = fe->dvb->priv;
+
+	int ret = av7110_fe_lock_fix(av7110, 0);
+	if (!ret) {
+		av7110->saved_voltage = voltage;
+		ret = av7110->fe_set_voltage(fe, voltage);
+	}
+	return ret;
+}
+
+static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned long cmd)
+{
+	struct av7110* av7110 = fe->dvb->priv;
+
+	int ret = av7110_fe_lock_fix(av7110, 0);
+	if (!ret)
+		ret = av7110->fe_dishnetwork_send_legacy_command(fe, cmd);
+	return ret;
+}
+
+static void dvb_s_recover(struct av7110* av7110)
+{
+	av7110_fe_init(av7110->fe);
+
+	av7110_fe_set_voltage(av7110->fe, av7110->saved_voltage);
+	if (av7110->saved_master_cmd.msg_len) {
+		msleep(20);
+		av7110_fe_diseqc_send_master_cmd(av7110->fe, &av7110->saved_master_cmd);
+	}
+	msleep(20);
+	av7110_fe_diseqc_send_burst(av7110->fe, av7110->saved_minicmd);
+	msleep(20);
+	av7110_fe_set_tone(av7110->fe, av7110->saved_tone);
+
+	av7110_fe_set_frontend(av7110->fe);
+}
+
+static u8 read_pwm(struct av7110* av7110)
+{
+	u8 b = 0xff;
+	u8 pwm;
+	struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
+				 { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
+
+	if ((i2c_transfer(&av7110->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
+		pwm = 0x48;
+
+	return pwm;
+}
+
+static int frontend_init(struct av7110 *av7110)
+{
+	int ret;
+
+	if (av7110->dev->pci->subsystem_vendor == 0x110a) {
+		switch(av7110->dev->pci->subsystem_device) {
+		case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??))
+			av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config,
+						    &av7110->i2c_adap, read_pwm(av7110));
+			if (av7110->fe) {
+				av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
+			}
+			break;
+		}
+
+	} else if (av7110->dev->pci->subsystem_vendor == 0x13c2) {
+		switch(av7110->dev->pci->subsystem_device) {
+		case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X
+		case 0x0003: // Hauppauge/TT WinTV Nexus-S Rev 2.X
+		case 0x1002: // Hauppauge/TT WinTV DVB-S rev1.3SE
+
+			// try the ALPS BSRV2 first of all
+			av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap);
+			if (av7110->fe) {
+				av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+				av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+				av7110->fe->ops.set_tone = av7110_set_tone;
+				av7110->recover = dvb_s_recover;
+				break;
+			}
+
+			// try the ALPS BSRU6 now
+			av7110->fe = dvb_attach(stv0299_attach, &alps_bsru6_config, &av7110->i2c_adap);
+			if (av7110->fe) {
+				av7110->fe->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+				av7110->fe->tuner_priv = &av7110->i2c_adap;
+
+				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+				av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+				av7110->fe->ops.set_tone = av7110_set_tone;
+				av7110->recover = dvb_s_recover;
+				break;
+			}
+
+			// Try the grundig 29504-451
+			av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap);
+			if (av7110->fe) {
+				av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+				av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+				av7110->fe->ops.set_tone = av7110_set_tone;
+				av7110->recover = dvb_s_recover;
+				break;
+			}
+
+			/* Try DVB-C cards */
+			switch(av7110->dev->pci->subsystem_device) {
+			case 0x0000:
+				/* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */
+				av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, &av7110->i2c_adap,
+							read_pwm(av7110));
+				if (av7110->fe) {
+					av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
+				}
+				break;
+			case 0x0003:
+				/* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */
+				av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap,
+							read_pwm(av7110));
+				if (av7110->fe) {
+					av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+				}
+				break;
+			}
+			break;
+
+		case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X
+			// try ALPS TDLB7 first, then Grundig 29504-401
+			av7110->fe = dvb_attach(sp8870_attach, &alps_tdlb7_config, &av7110->i2c_adap);
+			if (av7110->fe) {
+				av7110->fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params;
+				break;
+			}
+			/* fall-thru */
+
+		case 0x0008: // Hauppauge/TT DVB-T
+			// Grundig 29504-401
+			av7110->fe = dvb_attach(l64781_attach, &grundig_29504_401_config, &av7110->i2c_adap);
+			if (av7110->fe)
+				av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+			break;
+
+		case 0x0002: // Hauppauge/TT DVB-C premium rev2.X
+
+			av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
+			if (av7110->fe) {
+				av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+			}
+			break;
+
+		case 0x0004: // Galaxis DVB-S rev1.3
+			/* ALPS BSRV2 */
+			av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap);
+			if (av7110->fe) {
+				av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+				av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+				av7110->fe->ops.set_tone = av7110_set_tone;
+				av7110->recover = dvb_s_recover;
+			}
+			break;
+
+		case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */
+			/* Grundig 29504-451 */
+			av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap);
+			if (av7110->fe) {
+				av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+				av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+				av7110->fe->ops.set_tone = av7110_set_tone;
+				av7110->recover = dvb_s_recover;
+			}
+			break;
+
+		case 0x000A: // Hauppauge/TT Nexus-CA rev1.X
+
+			av7110->fe = dvb_attach(stv0297_attach, &nexusca_stv0297_config, &av7110->i2c_adap);
+			if (av7110->fe) {
+				av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params;
+
+				/* set TDA9819 into DVB mode */
+				saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
+				saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
+
+				/* tuner on this needs a slower i2c bus speed */
+				av7110->dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
+				break;
+			}
+			break;
+
+		case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */
+			/* ALPS BSBE1 */
+			av7110->fe = dvb_attach(stv0299_attach, &alps_bsbe1_config, &av7110->i2c_adap);
+			if (av7110->fe) {
+				av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
+				av7110->fe->tuner_priv = &av7110->i2c_adap;
+
+				if (dvb_attach(lnbp21_attach, av7110->fe, &av7110->i2c_adap, 0, 0) == NULL) {
+					printk("dvb-ttpci: LNBP21 not found!\n");
+					if (av7110->fe->ops.release)
+						av7110->fe->ops.release(av7110->fe);
+					av7110->fe = NULL;
+				} else {
+					av7110->fe->ops.dishnetwork_send_legacy_command = NULL;
+					av7110->recover = dvb_s_recover;
+				}
+			}
+			break;
+		}
+	}
+
+	if (!av7110->fe) {
+		/* FIXME: propagate the failure code from the lower layers */
+		ret = -ENOMEM;
+		printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
+		       av7110->dev->pci->vendor,
+		       av7110->dev->pci->device,
+		       av7110->dev->pci->subsystem_vendor,
+		       av7110->dev->pci->subsystem_device);
+	} else {
+		FE_FUNC_OVERRIDE(av7110->fe->ops.init, av7110->fe_init, av7110_fe_init);
+		FE_FUNC_OVERRIDE(av7110->fe->ops.read_status, av7110->fe_read_status, av7110_fe_read_status);
+		FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload);
+		FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
+		FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
+		FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
+		FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage);
+		FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
+		FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
+
+		ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe);
+		if (ret < 0) {
+			printk("av7110: Frontend registration failed!\n");
+			dvb_frontend_detach(av7110->fe);
+			av7110->fe = NULL;
+		}
+	}
+	return ret;
+}
+
+/* Budgetpatch note:
+ * Original hardware design by Roberto Deza:
+ * There is a DVB_Wiki at
+ * http://www.linuxtv.org/
+ *
+ * New software triggering design by Emard that works on
+ * original Roberto Deza's hardware:
+ *
+ * rps1 code for budgetpatch will copy internal HS event to GPIO3 pin.
+ * GPIO3 is in budget-patch hardware connectd to port B VSYNC
+ * HS is an internal event of 7146, accessible with RPS
+ * and temporarily raised high every n lines
+ * (n in defined in the RPS_THRESH1 counter threshold)
+ * I think HS is raised high on the beginning of the n-th line
+ * and remains high until this n-th line that triggered
+ * it is completely received. When the receiption of n-th line
+ * ends, HS is lowered.
+ *
+ * To transmit data over DMA, 7146 needs changing state at
+ * port B VSYNC pin. Any changing of port B VSYNC will
+ * cause some DMA data transfer, with more or less packets loss.
+ * It depends on the phase and frequency of VSYNC and
+ * the way of 7146 is instructed to trigger on port B (defined
+ * in DD1_INIT register, 3rd nibble from the right valid
+ * numbers are 0-7, see datasheet)
+ *
+ * The correct triggering can minimize packet loss,
+ * dvbtraffic should give this stable bandwidths:
+ *   22k transponder = 33814 kbit/s
+ * 27.5k transponder = 38045 kbit/s
+ * by experiment it is found that the best results
+ * (stable bandwidths and almost no packet loss)
+ * are obtained using DD1_INIT triggering number 2
+ * (Va at rising edge of VS Fa = HS x VS-failing forced toggle)
+ * and a VSYNC phase that occurs in the middle of DMA transfer
+ * (about byte 188*512=96256 in the DMA window).
+ *
+ * Phase of HS is still not clear to me how to control,
+ * It just happens to be so. It can be seen if one enables
+ * RPS_IRQ and print Event Counter 1 in vpeirq(). Every
+ * time RPS_INTERRUPT is called, the Event Counter 1 will
+ * increment. That's how the 7146 is programmed to do event
+ * counting in this budget-patch.c
+ * I *think* HPS setting has something to do with the phase
+ * of HS but I can't be 100% sure in that.
+ *
+ * hardware debug note: a working budget card (including budget patch)
+ * with vpeirq() interrupt setup in mode "0x90" (every 64K) will
+ * generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes
+ * and that means 3*25=75 Hz of interrupt freqency, as seen by
+ * watch cat /proc/interrupts
+ *
+ * If this frequency is 3x lower (and data received in the DMA
+ * buffer don't start with 0x47, but in the middle of packets,
+ * whose lengths appear to be like 188 292 188 104 etc.
+ * this means VSYNC line is not connected in the hardware.
+ * (check soldering pcb and pins)
+ * The same behaviour of missing VSYNC can be duplicated on budget
+ * cards, by seting DD1_INIT trigger mode 7 in 3rd nibble.
+ */
+static int __devinit av7110_attach(struct saa7146_dev* dev,
+				   struct saa7146_pci_extension_data *pci_ext)
+{
+	const int length = TS_WIDTH * TS_HEIGHT;
+	struct pci_dev *pdev = dev->pci;
+	struct av7110 *av7110;
+	struct task_struct *thread;
+	int ret, count = 0;
+
+	dprintk(4, "dev: %p\n", dev);
+
+	/* Set RPS_IRQ to 1 to track rps1 activity.
+	 * Enabling this won't send any interrupt to PC CPU.
+	 */
+#define RPS_IRQ 0
+
+	if (budgetpatch == 1) {
+		budgetpatch = 0;
+		/* autodetect the presence of budget patch
+		 * this only works if saa7146 has been recently
+		 * reset with with MASK_31 to MC1
+		 *
+		 * will wait for VBI_B event (vertical blank at port B)
+		 * and will reset GPIO3 after VBI_B is detected.
+		 * (GPIO3 should be raised high by CPU to
+		 * test if GPIO3 will generate vertical blank signal
+		 * in budget patch GPIO3 is connected to VSYNC_B
+		 */
+
+		/* RESET SAA7146 */
+		saa7146_write(dev, MC1, MASK_31);
+		/* autodetection success seems to be time-dependend after reset */
+
+		/* Fix VSYNC level */
+		saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+		/* set vsync_b triggering */
+		saa7146_write(dev, DD1_STREAM_B, 0);
+		/* port B VSYNC at rising edge */
+		saa7146_write(dev, DD1_INIT, 0x00000200);
+		saa7146_write(dev, BRS_CTRL, 0x00000000);  // VBI
+		saa7146_write(dev, MC2,
+			      1 * (MASK_08 | MASK_24)  |   // BRS control
+			      0 * (MASK_09 | MASK_25)  |   // a
+			      1 * (MASK_10 | MASK_26)  |   // b
+			      0 * (MASK_06 | MASK_22)  |   // HPS_CTRL1
+			      0 * (MASK_05 | MASK_21)  |   // HPS_CTRL2
+			      0 * (MASK_01 | MASK_15)      // DEBI
+		);
+
+		/* start writing RPS1 code from beginning */
+		count = 0;
+		/* Disable RPS1 */
+		saa7146_write(dev, MC1, MASK_29);
+		/* RPS1 timeout disable */
+		saa7146_write(dev, RPS_TOV1, 0);
+		WRITE_RPS1(CMD_PAUSE | EVT_VBI_B);
+		WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+		WRITE_RPS1(GPIO3_MSK);
+		WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
+#if RPS_IRQ
+		/* issue RPS1 interrupt to increment counter */
+		WRITE_RPS1(CMD_INTERRUPT);
+#endif
+		WRITE_RPS1(CMD_STOP);
+		/* Jump to begin of RPS program as safety measure               (p37) */
+		WRITE_RPS1(CMD_JUMP);
+		WRITE_RPS1(dev->d_rps1.dma_handle);
+
+#if RPS_IRQ
+		/* set event counter 1 source as RPS1 interrupt (0x03)          (rE4 p53)
+		 * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
+		 * use 0x15 to track VPE  interrupts - increase by 1 every vpeirq() is called
+		 */
+		saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
+		/* set event counter 1 threshold to maximum allowed value        (rEC p55) */
+		saa7146_write(dev, ECT1R,  0x3fff );
+#endif
+		/* Set RPS1 Address register to point to RPS code               (r108 p42) */
+		saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
+		/* Enable RPS1,                                                 (rFC p33) */
+		saa7146_write(dev, MC1, (MASK_13 | MASK_29 ));
+
+		mdelay(10);
+		/* now send VSYNC_B to rps1 by rising GPIO3 */
+		saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
+		mdelay(10);
+		/* if rps1 responded by lowering the GPIO3,
+		 * then we have budgetpatch hardware
+		 */
+		if ((saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0) {
+			budgetpatch = 1;
+			printk("dvb-ttpci: BUDGET-PATCH DETECTED.\n");
+		}
+		/* Disable RPS1 */
+		saa7146_write(dev, MC1, ( MASK_29 ));
+#if RPS_IRQ
+		printk("dvb-ttpci: Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff );
+#endif
+	}
+
+	/* prepare the av7110 device struct */
+	av7110 = kzalloc(sizeof(struct av7110), GFP_KERNEL);
+	if (!av7110) {
+		dprintk(1, "out of memory\n");
+		return -ENOMEM;
+	}
+
+	av7110->card_name = (char*) pci_ext->ext_priv;
+	av7110->dev = dev;
+	dev->ext_priv = av7110;
+
+	ret = get_firmware(av7110);
+	if (ret < 0)
+		goto err_kfree_0;
+
+	ret = dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name,
+				   THIS_MODULE, &dev->pci->dev, adapter_nr);
+	if (ret < 0)
+		goto err_put_firmware_1;
+
+	/* the Siemens DVB needs this if you want to have the i2c chips
+	   get recognized before the main driver is fully loaded */
+	saa7146_write(dev, GPIO_CTRL, 0x500000);
+
+	strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name));
+
+	saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
+
+	ret = i2c_add_adapter(&av7110->i2c_adap);
+	if (ret < 0)
+		goto err_dvb_unregister_adapter_2;
+
+	ttpci_eeprom_parse_mac(&av7110->i2c_adap,
+			       av7110->dvb_adapter.proposed_mac);
+	ret = -ENOMEM;
+
+	/* full-ts mod? */
+	if (full_ts)
+		av7110->full_ts = true;
+
+	/* check for full-ts flag in eeprom */
+	if (i2c_readreg(av7110, 0xaa, 0) == 0x4f && i2c_readreg(av7110, 0xaa, 1) == 0x45) {
+		u8 flags = i2c_readreg(av7110, 0xaa, 2);
+		if (flags != 0xff && (flags & 0x01))
+			av7110->full_ts = true;
+	}
+
+	if (av7110->full_ts) {
+		printk(KERN_INFO "dvb-ttpci: full-ts mode enabled for saa7146 port B\n");
+		spin_lock_init(&av7110->feedlock1);
+		av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length,
+								 &av7110->pt);
+		if (!av7110->grabbing)
+			goto err_i2c_del_3;
+
+		saa7146_write(dev, DD1_STREAM_B, 0x00000000);
+		saa7146_write(dev, MC2, (MASK_10 | MASK_26));
+
+		saa7146_write(dev, DD1_INIT, 0x00000600);
+		saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+
+		saa7146_write(dev, BRS_CTRL, 0x60000000);
+		saa7146_write(dev, MC2, MASK_08 | MASK_24);
+
+		/* dma3 */
+		saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000));
+		saa7146_write(dev, BASE_ODD3, 0);
+		saa7146_write(dev, BASE_EVEN3, 0);
+		saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT);
+		saa7146_write(dev, PITCH3, TS_WIDTH);
+		saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90);
+		saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH);
+		saa7146_write(dev, MC2, MASK_04 | MASK_20);
+
+		tasklet_init(&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110);
+
+	} else if (budgetpatch) {
+		spin_lock_init(&av7110->feedlock1);
+		av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length,
+								 &av7110->pt);
+		if (!av7110->grabbing)
+			goto err_i2c_del_3;
+
+		saa7146_write(dev, PCI_BT_V1, 0x1c1f101f);
+		saa7146_write(dev, BCS_CTRL, 0x80400040);
+		/* set dd1 stream a & b */
+		saa7146_write(dev, DD1_STREAM_B, 0x00000000);
+		saa7146_write(dev, DD1_INIT, 0x03000200);
+		saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+		saa7146_write(dev, BRS_CTRL, 0x60000000);
+		saa7146_write(dev, BASE_ODD3, 0);
+		saa7146_write(dev, BASE_EVEN3, 0);
+		saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT);
+		saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90);
+
+		saa7146_write(dev, PITCH3, TS_WIDTH);
+		saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH);
+
+		/* upload all */
+		saa7146_write(dev, MC2, 0x077c077c);
+		saa7146_write(dev, GPIO_CTRL, 0x000000);
+#if RPS_IRQ
+		/* set event counter 1 source as RPS1 interrupt (0x03)          (rE4 p53)
+		 * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
+		 * use 0x15 to track VPE  interrupts - increase by 1 every vpeirq() is called
+		 */
+		saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
+		/* set event counter 1 threshold to maximum allowed value        (rEC p55) */
+		saa7146_write(dev, ECT1R,  0x3fff );
+#endif
+		/* Setup BUDGETPATCH MAIN RPS1 "program" (p35) */
+		count = 0;
+
+		/* Wait Source Line Counter Threshold                           (p36) */
+		WRITE_RPS1(CMD_PAUSE | EVT_HS);
+		/* Set GPIO3=1                                                  (p42) */
+		WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+		WRITE_RPS1(GPIO3_MSK);
+		WRITE_RPS1(SAA7146_GPIO_OUTHI<<24);
+#if RPS_IRQ
+		/* issue RPS1 interrupt */
+		WRITE_RPS1(CMD_INTERRUPT);
+#endif
+		/* Wait reset Source Line Counter Threshold                     (p36) */
+		WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS);
+		/* Set GPIO3=0                                                  (p42) */
+		WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+		WRITE_RPS1(GPIO3_MSK);
+		WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
+#if RPS_IRQ
+		/* issue RPS1 interrupt */
+		WRITE_RPS1(CMD_INTERRUPT);
+#endif
+		/* Jump to begin of RPS program                                 (p37) */
+		WRITE_RPS1(CMD_JUMP);
+		WRITE_RPS1(dev->d_rps1.dma_handle);
+
+		/* Fix VSYNC level */
+		saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+		/* Set RPS1 Address register to point to RPS code               (r108 p42) */
+		saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
+		/* Set Source Line Counter Threshold, using BRS                 (rCC p43)
+		 * It generates HS event every TS_HEIGHT lines
+		 * this is related to TS_WIDTH set in register
+		 * NUM_LINE_BYTE3. If NUM_LINE_BYTE low 16 bits
+		 * are set to TS_WIDTH bytes (TS_WIDTH=2*188),
+		 * then RPS_THRESH1 should be set to trigger
+		 * every TS_HEIGHT (512) lines.
+		 */
+		saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 );
+
+		/* Enable RPS1                                                  (rFC p33) */
+		saa7146_write(dev, MC1, (MASK_13 | MASK_29));
+
+		/* end of budgetpatch register initialization */
+		tasklet_init (&av7110->vpe_tasklet,  vpeirq,  (unsigned long) av7110);
+	} else {
+		saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
+		saa7146_write(dev, BCS_CTRL, 0x80400040);
+
+		/* set dd1 stream a & b */
+		saa7146_write(dev, DD1_STREAM_B, 0x00000000);
+		saa7146_write(dev, DD1_INIT, 0x03000000);
+		saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+
+		/* upload all */
+		saa7146_write(dev, MC2, 0x077c077c);
+		saa7146_write(dev, GPIO_CTRL, 0x000000);
+	}
+
+	tasklet_init (&av7110->debi_tasklet, debiirq, (unsigned long) av7110);
+	tasklet_init (&av7110->gpio_tasklet, gpioirq, (unsigned long) av7110);
+
+	mutex_init(&av7110->pid_mutex);
+
+	/* locks for data transfers from/to AV7110 */
+	spin_lock_init(&av7110->debilock);
+	mutex_init(&av7110->dcomlock);
+	av7110->debitype = -1;
+
+	/* default OSD window */
+	av7110->osdwin = 1;
+	mutex_init(&av7110->osd_mutex);
+
+	/* TV standard */
+	av7110->vidmode = tv_standard == 1 ? AV7110_VIDEO_MODE_NTSC
+					   : AV7110_VIDEO_MODE_PAL;
+
+	/* ARM "watchdog" */
+	init_waitqueue_head(&av7110->arm_wait);
+	av7110->arm_thread = NULL;
+
+	/* allocate and init buffers */
+	av7110->debi_virt = pci_alloc_consistent(pdev, 8192, &av7110->debi_bus);
+	if (!av7110->debi_virt)
+		goto err_saa71466_vfree_4;
+
+
+	av7110->iobuf = vmalloc(AVOUTLEN+AOUTLEN+BMPLEN+4*IPACKS);
+	if (!av7110->iobuf)
+		goto err_pci_free_5;
+
+	ret = av7110_av_init(av7110);
+	if (ret < 0)
+		goto err_iobuf_vfree_6;
+
+	/* init BMP buffer */
+	av7110->bmpbuf = av7110->iobuf+AVOUTLEN+AOUTLEN;
+	init_waitqueue_head(&av7110->bmpq);
+
+	ret = av7110_ca_init(av7110);
+	if (ret < 0)
+		goto err_av7110_av_exit_7;
+
+	/* load firmware into AV7110 cards */
+	ret = av7110_bootarm(av7110);
+	if (ret < 0)
+		goto err_av7110_ca_exit_8;
+
+	ret = av7110_firmversion(av7110);
+	if (ret < 0)
+		goto err_stop_arm_9;
+
+	if (FW_VERSION(av7110->arm_app)<0x2501)
+		printk ("dvb-ttpci: Warning, firmware version 0x%04x is too old. "
+			"System might be unstable!\n", FW_VERSION(av7110->arm_app));
+
+	thread = kthread_run(arm_thread, (void *) av7110, "arm_mon");
+	if (IS_ERR(thread)) {
+		ret = PTR_ERR(thread);
+		goto err_stop_arm_9;
+	}
+	av7110->arm_thread = thread;
+
+	/* set initial volume in mixer struct */
+	av7110->mixer.volume_left  = volume;
+	av7110->mixer.volume_right = volume;
+
+	ret = av7110_register(av7110);
+	if (ret < 0)
+		goto err_arm_thread_stop_10;
+
+	init_av7110_av(av7110);
+
+	/* special case DVB-C: these cards have an analog tuner
+	   plus need some special handling, so we have separate
+	   saa7146_ext_vv data for these... */
+	ret = av7110_init_v4l(av7110);
+	if (ret < 0)
+		goto err_av7110_unregister_11;
+
+	av7110->dvb_adapter.priv = av7110;
+	ret = frontend_init(av7110);
+	if (ret < 0)
+		goto err_av7110_exit_v4l_12;
+
+#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
+	av7110_ir_init(av7110);
+#endif
+	printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num);
+	av7110_num++;
+out:
+	return ret;
+
+err_av7110_exit_v4l_12:
+	av7110_exit_v4l(av7110);
+err_av7110_unregister_11:
+	dvb_unregister(av7110);
+err_arm_thread_stop_10:
+	av7110_arm_sync(av7110);
+err_stop_arm_9:
+	/* Nothing to do. Rejoice. */
+err_av7110_ca_exit_8:
+	av7110_ca_exit(av7110);
+err_av7110_av_exit_7:
+	av7110_av_exit(av7110);
+err_iobuf_vfree_6:
+	vfree(av7110->iobuf);
+err_pci_free_5:
+	pci_free_consistent(pdev, 8192, av7110->debi_virt, av7110->debi_bus);
+err_saa71466_vfree_4:
+	if (av7110->grabbing)
+		saa7146_vfree_destroy_pgtable(pdev, av7110->grabbing, &av7110->pt);
+err_i2c_del_3:
+	i2c_del_adapter(&av7110->i2c_adap);
+err_dvb_unregister_adapter_2:
+	dvb_unregister_adapter(&av7110->dvb_adapter);
+err_put_firmware_1:
+	put_firmware(av7110);
+err_kfree_0:
+	kfree(av7110);
+	goto out;
+}
+
+static int __devexit av7110_detach(struct saa7146_dev* saa)
+{
+	struct av7110 *av7110 = saa->ext_priv;
+	dprintk(4, "%p\n", av7110);
+
+#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
+	av7110_ir_exit(av7110);
+#endif
+	if (budgetpatch || av7110->full_ts) {
+		if (budgetpatch) {
+			/* Disable RPS1 */
+			saa7146_write(saa, MC1, MASK_29);
+			/* VSYNC LOW (inactive) */
+			saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+		}
+		saa7146_write(saa, MC1, MASK_20);	/* DMA3 off */
+		SAA7146_IER_DISABLE(saa, MASK_10);
+		SAA7146_ISR_CLEAR(saa, MASK_10);
+		msleep(50);
+		tasklet_kill(&av7110->vpe_tasklet);
+		saa7146_vfree_destroy_pgtable(saa->pci, av7110->grabbing, &av7110->pt);
+	}
+	av7110_exit_v4l(av7110);
+
+	av7110_arm_sync(av7110);
+
+	tasklet_kill(&av7110->debi_tasklet);
+	tasklet_kill(&av7110->gpio_tasklet);
+
+	dvb_unregister(av7110);
+
+	SAA7146_IER_DISABLE(saa, MASK_19 | MASK_03);
+	SAA7146_ISR_CLEAR(saa, MASK_19 | MASK_03);
+
+	av7110_ca_exit(av7110);
+	av7110_av_exit(av7110);
+
+	vfree(av7110->iobuf);
+	pci_free_consistent(saa->pci, 8192, av7110->debi_virt,
+			    av7110->debi_bus);
+
+	i2c_del_adapter(&av7110->i2c_adap);
+
+	dvb_unregister_adapter (&av7110->dvb_adapter);
+
+	av7110_num--;
+
+	put_firmware(av7110);
+
+	kfree(av7110);
+
+	saa->ext_priv = NULL;
+
+	return 0;
+}
+
+
+static void av7110_irq(struct saa7146_dev* dev, u32 *isr)
+{
+	struct av7110 *av7110 = dev->ext_priv;
+
+	//print_time("av7110_irq");
+
+	/* Note: Don't try to handle the DEBI error irq (MASK_18), in
+	 * intel mode the timeout is asserted all the time...
+	 */
+
+	if (*isr & MASK_19) {
+		//printk("av7110_irq: DEBI\n");
+		/* Note 1: The DEBI irq is level triggered: We must enable it
+		 * only after we started a DMA xfer, and disable it here
+		 * immediately, or it will be signalled all the time while
+		 * DEBI is idle.
+		 * Note 2: You would think that an irq which is masked is
+		 * not signalled by the hardware. Not so for the SAA7146:
+		 * An irq is signalled as long as the corresponding bit
+		 * in the ISR is set, and disabling irqs just prevents the
+		 * hardware from setting the ISR bit. This means a) that we
+		 * must clear the ISR *after* disabling the irq (which is why
+		 * we must do it here even though saa7146_core did it already),
+		 * and b) that if we were to disable an edge triggered irq
+		 * (like the gpio irqs sadly are) temporarily we would likely
+		 * loose some. This sucks :-(
+		 */
+		SAA7146_IER_DISABLE(av7110->dev, MASK_19);
+		SAA7146_ISR_CLEAR(av7110->dev, MASK_19);
+		tasklet_schedule(&av7110->debi_tasklet);
+	}
+
+	if (*isr & MASK_03) {
+		//printk("av7110_irq: GPIO\n");
+		tasklet_schedule(&av7110->gpio_tasklet);
+	}
+
+	if (*isr & MASK_10)
+		tasklet_schedule(&av7110->vpe_tasklet);
+}
+
+
+static struct saa7146_extension av7110_extension_driver;
+
+#define MAKE_AV7110_INFO(x_var,x_name) \
+static struct saa7146_pci_extension_data x_var = { \
+	.ext_priv = x_name, \
+	.ext = &av7110_extension_driver }
+
+MAKE_AV7110_INFO(tts_1_X_fsc,"Technotrend/Hauppauge WinTV DVB-S rev1.X or Fujitsu Siemens DVB-C");
+MAKE_AV7110_INFO(ttt_1_X,    "Technotrend/Hauppauge WinTV DVB-T rev1.X");
+MAKE_AV7110_INFO(ttc_1_X,    "Technotrend/Hauppauge WinTV Nexus-CA rev1.X");
+MAKE_AV7110_INFO(ttc_2_X,    "Technotrend/Hauppauge WinTV DVB-C rev2.X");
+MAKE_AV7110_INFO(tts_2_X,    "Technotrend/Hauppauge WinTV Nexus-S rev2.X");
+MAKE_AV7110_INFO(tts_2_3,    "Technotrend/Hauppauge WinTV Nexus-S rev2.3");
+MAKE_AV7110_INFO(tts_1_3se,  "Technotrend/Hauppauge WinTV DVB-S rev1.3 SE");
+MAKE_AV7110_INFO(ttt,        "Technotrend/Hauppauge DVB-T");
+MAKE_AV7110_INFO(fsc,        "Fujitsu Siemens DVB-C");
+MAKE_AV7110_INFO(fss,        "Fujitsu Siemens DVB-S rev1.6");
+MAKE_AV7110_INFO(gxs_1_3,    "Galaxis DVB-S rev1.3");
+
+static struct pci_device_id pci_tbl[] = {
+	MAKE_EXTENSION_PCI(fsc,         0x110a, 0x0000),
+	MAKE_EXTENSION_PCI(tts_1_X_fsc, 0x13c2, 0x0000),
+	MAKE_EXTENSION_PCI(ttt_1_X,     0x13c2, 0x0001),
+	MAKE_EXTENSION_PCI(ttc_2_X,     0x13c2, 0x0002),
+	MAKE_EXTENSION_PCI(tts_2_X,     0x13c2, 0x0003),
+	MAKE_EXTENSION_PCI(gxs_1_3,     0x13c2, 0x0004),
+	MAKE_EXTENSION_PCI(fss,         0x13c2, 0x0006),
+	MAKE_EXTENSION_PCI(ttt,         0x13c2, 0x0008),
+	MAKE_EXTENSION_PCI(ttc_1_X,     0x13c2, 0x000a),
+	MAKE_EXTENSION_PCI(tts_2_3,     0x13c2, 0x000e),
+	MAKE_EXTENSION_PCI(tts_1_3se,   0x13c2, 0x1002),
+
+/*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1
+/*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v????
+
+	{
+		.vendor    = 0,
+	}
+};
+
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+
+static struct saa7146_extension av7110_extension_driver = {
+	.name		= "av7110",
+	.flags		= SAA7146_USE_I2C_IRQ,
+
+	.module		= THIS_MODULE,
+	.pci_tbl	= &pci_tbl[0],
+	.attach		= av7110_attach,
+	.detach		= __devexit_p(av7110_detach),
+
+	.irq_mask	= MASK_19 | MASK_03 | MASK_10,
+	.irq_func	= av7110_irq,
+};
+
+
+static int __init av7110_init(void)
+{
+	int retval;
+	retval = saa7146_register_extension(&av7110_extension_driver);
+	return retval;
+}
+
+
+static void __exit av7110_exit(void)
+{
+	saa7146_unregister_extension(&av7110_extension_driver);
+}
+
+module_init(av7110_init);
+module_exit(av7110_exit);
+
+MODULE_DESCRIPTION("driver for the SAA7146 based AV110 PCI DVB cards by "
+		   "Siemens, Technotrend, Hauppauge");
+MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h
new file mode 100644
index 0000000..88b3b2d
--- /dev/null
+++ b/drivers/media/pci/ttpci/av7110.h
@@ -0,0 +1,314 @@
+#ifndef _AV7110_H_
+#define _AV7110_H_
+
+#include <linux/interrupt.h>
+#include <linux/socket.h>
+#include <linux/netdevice.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+
+#include <linux/dvb/video.h>
+#include <linux/dvb/audio.h>
+#include <linux/dvb/dmx.h>
+#include <linux/dvb/ca.h>
+#include <linux/dvb/osd.h>
+#include <linux/dvb/net.h>
+#include <linux/mutex.h>
+
+#include "dvbdev.h"
+#include "demux.h"
+#include "dvb_demux.h"
+#include "dmxdev.h"
+#include "dvb_filter.h"
+#include "dvb_net.h"
+#include "dvb_ringbuffer.h"
+#include "dvb_frontend.h"
+#include "ves1820.h"
+#include "ves1x93.h"
+#include "stv0299.h"
+#include "tda8083.h"
+#include "sp8870.h"
+#include "stv0297.h"
+#include "l64781.h"
+
+#include <media/saa7146_vv.h>
+
+
+#define ANALOG_TUNER_VES1820 1
+#define ANALOG_TUNER_STV0297 2
+
+extern int av7110_debug;
+
+#define dprintk(level,args...) \
+	    do { if ((av7110_debug & level)) { printk("dvb-ttpci: %s(): ", __func__); printk(args); } } while (0)
+
+#define MAXFILT 32
+
+enum {AV_PES_STREAM, PS_STREAM, TS_STREAM, PES_STREAM};
+
+enum av7110_video_mode {
+	AV7110_VIDEO_MODE_PAL 	= 0,
+	AV7110_VIDEO_MODE_NTSC	= 1
+};
+
+struct av7110_p2t {
+	u8		  pes[TS_SIZE];
+	u8		  counter;
+	long int	  pos;
+	int		  frags;
+	struct dvb_demux_feed *feed;
+};
+
+/* video MPEG decoder events: */
+/* (code copied from dvb_frontend.c, should maybe be factored out...) */
+#define MAX_VIDEO_EVENT 8
+struct dvb_video_events {
+	struct video_event	  events[MAX_VIDEO_EVENT];
+	int			  eventw;
+	int			  eventr;
+	int			  overflow;
+	wait_queue_head_t	  wait_queue;
+	spinlock_t		  lock;
+};
+
+
+struct av7110;
+
+/* infrared remote control */
+struct infrared {
+	u16	key_map[256];
+	struct input_dev	*input_dev;
+	char			input_phys[32];
+	struct timer_list	keyup_timer;
+	struct tasklet_struct	ir_tasklet;
+	void			(*ir_handler)(struct av7110 *av7110, u32 ircom);
+	u32			ir_command;
+	u32			ir_config;
+	u32			device_mask;
+	u8			protocol;
+	u8			inversion;
+	u16			last_key;
+	u16			last_toggle;
+	u8			delay_timer_finished;
+};
+
+
+/* place to store all the necessary device information */
+struct av7110 {
+
+	/* devices */
+
+	struct dvb_device	dvb_dev;
+	struct dvb_net		dvb_net;
+
+	struct video_device	*v4l_dev;
+	struct video_device	*vbi_dev;
+
+	struct saa7146_dev	*dev;
+
+	struct i2c_adapter	i2c_adap;
+
+	char			*card_name;
+
+	/* support for analog module of dvb-c */
+	int			analog_tuner_flags;
+	int			current_input;
+	u32			current_freq;
+
+	struct tasklet_struct	debi_tasklet;
+	struct tasklet_struct	gpio_tasklet;
+
+	int adac_type;	       /* audio DAC type */
+#define DVB_ADAC_TI	  0
+#define DVB_ADAC_CRYSTAL  1
+#define DVB_ADAC_MSP34x0  2
+#define DVB_ADAC_MSP34x5  3
+#define DVB_ADAC_NONE	 -1
+
+
+	/* buffers */
+
+	void		       *iobuf;	 /* memory for all buffers */
+	struct dvb_ringbuffer	avout;   /* buffer for video or A/V mux */
+#define AVOUTLEN (128*1024)
+	struct dvb_ringbuffer	aout;    /* buffer for audio */
+#define AOUTLEN (64*1024)
+	void		       *bmpbuf;
+#define BMPLEN (8*32768+1024)
+
+	/* bitmap buffers and states */
+
+	int			bmpp;
+	int			bmplen;
+	volatile int		bmp_state;
+#define BMP_NONE     0
+#define BMP_LOADING  1
+#define BMP_LOADED   2
+	wait_queue_head_t	bmpq;
+
+
+	/* DEBI and polled command interface */
+
+	spinlock_t		debilock;
+	struct mutex		dcomlock;
+	volatile int		debitype;
+	volatile int		debilen;
+
+
+	/* Recording and playback flags */
+
+	int			rec_mode;
+	int			playing;
+#define RP_NONE  0
+#define RP_VIDEO 1
+#define RP_AUDIO 2
+#define RP_AV	 3
+
+
+	/* OSD */
+
+	int			osdwin;      /* currently active window */
+	u16			osdbpp[8];
+	struct mutex		osd_mutex;
+
+	/* CA */
+
+	ca_slot_info_t		ci_slot[2];
+
+	enum av7110_video_mode	vidmode;
+	struct dmxdev		dmxdev;
+	struct dvb_demux	demux;
+
+	struct dmx_frontend	hw_frontend;
+	struct dmx_frontend	mem_frontend;
+
+	/* for budget mode demux1 */
+	struct dmxdev		dmxdev1;
+	struct dvb_demux	demux1;
+	struct dvb_net		dvb_net1;
+	spinlock_t		feedlock1;
+	int			feeding1;
+	u32			ttbp;
+	unsigned char           *grabbing;
+	struct saa7146_pgtable  pt;
+	struct tasklet_struct   vpe_tasklet;
+	bool			full_ts;
+
+	int			fe_synced;
+	struct mutex		pid_mutex;
+
+	int			video_blank;
+	struct video_status	videostate;
+	u16			display_panscan;
+	int			display_ar;
+	int			trickmode;
+#define TRICK_NONE   0
+#define TRICK_FAST   1
+#define TRICK_SLOW   2
+#define TRICK_FREEZE 3
+	struct audio_status	audiostate;
+
+	struct dvb_demux_filter *handle2filter[32];
+	struct av7110_p2t	 p2t_filter[MAXFILT];
+	struct dvb_filter_pes2ts p2t[2];
+	struct ipack		 ipack[2];
+	u8			*kbuf[2];
+
+	int sinfo;
+	int feeding;
+
+	int arm_errors;
+	int registered;
+
+
+	/* AV711X */
+
+	u32		    arm_fw;
+	u32		    arm_rtsl;
+	u32		    arm_vid;
+	u32		    arm_app;
+	u32		    avtype;
+	int		    arm_ready;
+	struct task_struct *arm_thread;
+	wait_queue_head_t   arm_wait;
+	u16		    arm_loops;
+
+	void		   *debi_virt;
+	dma_addr_t	    debi_bus;
+
+	u16		    pids[DMX_PES_OTHER];
+
+	struct dvb_ringbuffer	 ci_rbuffer;
+	struct dvb_ringbuffer	 ci_wbuffer;
+
+	struct audio_mixer	mixer;
+
+	struct dvb_adapter	 dvb_adapter;
+	struct dvb_device	 *video_dev;
+	struct dvb_device	 *audio_dev;
+	struct dvb_device	 *ca_dev;
+	struct dvb_device	 *osd_dev;
+
+	struct dvb_video_events  video_events;
+	video_size_t		 video_size;
+
+	u16			wssMode;
+	u16			wssData;
+
+	struct infrared		ir;
+
+	/* firmware stuff */
+	unsigned char *bin_fw;
+	unsigned long size_fw;
+
+	unsigned char *bin_dpram;
+	unsigned long size_dpram;
+
+	unsigned char *bin_root;
+	unsigned long size_root;
+
+	struct dvb_frontend* fe;
+	fe_status_t fe_status;
+
+	/* crash recovery */
+	void				(*recover)(struct av7110* av7110);
+	fe_sec_voltage_t		saved_voltage;
+	fe_sec_tone_mode_t		saved_tone;
+	struct dvb_diseqc_master_cmd	saved_master_cmd;
+	fe_sec_mini_cmd_t		saved_minicmd;
+
+	int (*fe_init)(struct dvb_frontend* fe);
+	int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status);
+	int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe);
+	int (*fe_diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
+	int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
+	int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
+	int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+	int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
+	int (*fe_set_frontend)(struct dvb_frontend *fe);
+};
+
+
+extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
+		       u16 subpid, u16 pcrpid);
+
+extern int av7110_check_ir_config(struct av7110 *av7110, int force);
+extern int av7110_ir_init(struct av7110 *av7110);
+extern void av7110_ir_exit(struct av7110 *av7110);
+
+/* msp3400 i2c subaddresses */
+#define MSP_WR_DEM 0x10
+#define MSP_RD_DEM 0x11
+#define MSP_WR_DSP 0x12
+#define MSP_RD_DSP 0x13
+
+extern int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val);
+extern u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg);
+extern int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val);
+
+
+extern int av7110_init_analog_module(struct av7110 *av7110);
+extern int av7110_init_v4l(struct av7110 *av7110);
+extern int av7110_exit_v4l(struct av7110 *av7110);
+
+#endif /* _AV7110_H_ */
diff --git a/drivers/media/pci/ttpci/av7110_av.c b/drivers/media/pci/ttpci/av7110_av.c
new file mode 100644
index 0000000..952b33d
--- /dev/null
+++ b/drivers/media/pci/ttpci/av7110_av.c
@@ -0,0 +1,1626 @@
+/*
+ * av7110_av.c: audio and video MPEG decoder stuff
+ *
+ * Copyright (C) 1999-2002 Ralph  Metzler
+ *                       & Marcus Metzler for convergence integrated media GmbH
+ *
+ * originally based on code by:
+ * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org/ 
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+
+#include "av7110.h"
+#include "av7110_hw.h"
+#include "av7110_av.h"
+#include "av7110_ipack.h"
+
+/* MPEG-2 (ISO 13818 / H.222.0) stream types */
+#define PROG_STREAM_MAP  0xBC
+#define PRIVATE_STREAM1  0xBD
+#define PADDING_STREAM	 0xBE
+#define PRIVATE_STREAM2  0xBF
+#define AUDIO_STREAM_S	 0xC0
+#define AUDIO_STREAM_E	 0xDF
+#define VIDEO_STREAM_S	 0xE0
+#define VIDEO_STREAM_E	 0xEF
+#define ECM_STREAM	 0xF0
+#define EMM_STREAM	 0xF1
+#define DSM_CC_STREAM	 0xF2
+#define ISO13522_STREAM  0xF3
+#define PROG_STREAM_DIR  0xFF
+
+#define PTS_DTS_FLAGS	 0xC0
+
+//pts_dts flags
+#define PTS_ONLY	 0x80
+#define PTS_DTS		 0xC0
+#define TS_SIZE		 188
+#define TRANS_ERROR	 0x80
+#define PAY_START	 0x40
+#define TRANS_PRIO	 0x20
+#define PID_MASK_HI	 0x1F
+//flags
+#define TRANS_SCRMBL1	 0x80
+#define TRANS_SCRMBL2	 0x40
+#define ADAPT_FIELD	 0x20
+#define PAYLOAD		 0x10
+#define COUNT_MASK	 0x0F
+
+// adaptation flags
+#define DISCON_IND	 0x80
+#define RAND_ACC_IND	 0x40
+#define ES_PRI_IND	 0x20
+#define PCR_FLAG	 0x10
+#define OPCR_FLAG	 0x08
+#define SPLICE_FLAG	 0x04
+#define TRANS_PRIV	 0x02
+#define ADAP_EXT_FLAG	 0x01
+
+// adaptation extension flags
+#define LTW_FLAG	 0x80
+#define PIECE_RATE	 0x40
+#define SEAM_SPLICE	 0x20
+
+
+static void p_to_t(u8 const *buf, long int length, u16 pid,
+		   u8 *counter, struct dvb_demux_feed *feed);
+static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len);
+
+
+int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len)
+{
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) p2t->priv;
+
+	if (!(dvbdmxfeed->ts_type & TS_PACKET))
+		return 0;
+	if (buf[3] == 0xe0)	 // video PES do not have a length in TS
+		buf[4] = buf[5] = 0;
+	if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)
+		return dvbdmxfeed->cb.ts(buf, len, NULL, 0,
+					 &dvbdmxfeed->feed.ts, DMX_OK);
+	else
+		return dvb_filter_pes2ts(p2t, buf, len, 1);
+}
+
+static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data)
+{
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv;
+
+	dvbdmxfeed->cb.ts(data, 188, NULL, 0,
+			  &dvbdmxfeed->feed.ts, DMX_OK);
+	return 0;
+}
+
+int av7110_av_start_record(struct av7110 *av7110, int av,
+			   struct dvb_demux_feed *dvbdmxfeed)
+{
+	int ret = 0;
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+
+	dprintk(2, "av7110:%p, , dvb_demux_feed:%p\n", av7110, dvbdmxfeed);
+
+	if (av7110->playing || (av7110->rec_mode & av))
+		return -EBUSY;
+	av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
+	dvbdmx->recording = 1;
+	av7110->rec_mode |= av;
+
+	switch (av7110->rec_mode) {
+	case RP_AUDIO:
+		dvb_filter_pes2ts_init(&av7110->p2t[0],
+				       dvbdmx->pesfilter[0]->pid,
+				       dvb_filter_pes2ts_cb,
+				       (void *) dvbdmx->pesfilter[0]);
+		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
+		break;
+
+	case RP_VIDEO:
+		dvb_filter_pes2ts_init(&av7110->p2t[1],
+				       dvbdmx->pesfilter[1]->pid,
+				       dvb_filter_pes2ts_cb,
+				       (void *) dvbdmx->pesfilter[1]);
+		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
+		break;
+
+	case RP_AV:
+		dvb_filter_pes2ts_init(&av7110->p2t[0],
+				       dvbdmx->pesfilter[0]->pid,
+				       dvb_filter_pes2ts_cb,
+				       (void *) dvbdmx->pesfilter[0]);
+		dvb_filter_pes2ts_init(&av7110->p2t[1],
+				       dvbdmx->pesfilter[1]->pid,
+				       dvb_filter_pes2ts_cb,
+				       (void *) dvbdmx->pesfilter[1]);
+		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0);
+		break;
+	}
+	return ret;
+}
+
+int av7110_av_start_play(struct av7110 *av7110, int av)
+{
+	int ret = 0;
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	if (av7110->rec_mode)
+		return -EBUSY;
+	if (av7110->playing & av)
+		return -EBUSY;
+
+	av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
+
+	if (av7110->playing == RP_NONE) {
+		av7110_ipack_reset(&av7110->ipack[0]);
+		av7110_ipack_reset(&av7110->ipack[1]);
+	}
+
+	av7110->playing |= av;
+	switch (av7110->playing) {
+	case RP_AUDIO:
+		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
+		break;
+	case RP_VIDEO:
+		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
+		av7110->sinfo = 0;
+		break;
+	case RP_AV:
+		av7110->sinfo = 0;
+		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0);
+		break;
+	}
+	return ret;
+}
+
+int av7110_av_stop(struct av7110 *av7110, int av)
+{
+	int ret = 0;
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	if (!(av7110->playing & av) && !(av7110->rec_mode & av))
+		return 0;
+	av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
+	if (av7110->playing) {
+		av7110->playing &= ~av;
+		switch (av7110->playing) {
+		case RP_AUDIO:
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
+			break;
+		case RP_VIDEO:
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
+			break;
+		case RP_NONE:
+			ret = av7110_set_vidmode(av7110, av7110->vidmode);
+			break;
+		}
+	} else {
+		av7110->rec_mode &= ~av;
+		switch (av7110->rec_mode) {
+		case RP_AUDIO:
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
+			break;
+		case RP_VIDEO:
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
+			break;
+		case RP_NONE:
+			break;
+		}
+	}
+	return ret;
+}
+
+
+int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen)
+{
+	int len;
+	u32 sync;
+	u16 blen;
+
+	if (!dlen) {
+		wake_up(&buf->queue);
+		return -1;
+	}
+	while (1) {
+		len = dvb_ringbuffer_avail(buf);
+		if (len < 6) {
+			wake_up(&buf->queue);
+			return -1;
+		}
+		sync =  DVB_RINGBUFFER_PEEK(buf, 0) << 24;
+		sync |= DVB_RINGBUFFER_PEEK(buf, 1) << 16;
+		sync |= DVB_RINGBUFFER_PEEK(buf, 2) << 8;
+		sync |= DVB_RINGBUFFER_PEEK(buf, 3);
+
+		if (((sync &~ 0x0f) == 0x000001e0) ||
+		    ((sync &~ 0x1f) == 0x000001c0) ||
+		    (sync == 0x000001bd))
+			break;
+		printk("resync\n");
+		DVB_RINGBUFFER_SKIP(buf, 1);
+	}
+	blen =  DVB_RINGBUFFER_PEEK(buf, 4) << 8;
+	blen |= DVB_RINGBUFFER_PEEK(buf, 5);
+	blen += 6;
+	if (len < blen || blen > dlen) {
+		//printk("buffer empty - avail %d blen %u dlen %d\n", len, blen, dlen);
+		wake_up(&buf->queue);
+		return -1;
+	}
+
+	dvb_ringbuffer_read(buf, dest, (size_t) blen);
+
+	dprintk(2, "pread=0x%08lx, pwrite=0x%08lx\n",
+	       (unsigned long) buf->pread, (unsigned long) buf->pwrite);
+	wake_up(&buf->queue);
+	return blen;
+}
+
+
+int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
+{
+	int err, vol, val, balance = 0;
+
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	av7110->mixer.volume_left = volleft;
+	av7110->mixer.volume_right = volright;
+
+	switch (av7110->adac_type) {
+	case DVB_ADAC_TI:
+		volleft = (volleft * 256) / 1036;
+		volright = (volright * 256) / 1036;
+		if (volleft > 0x3f)
+			volleft = 0x3f;
+		if (volright > 0x3f)
+			volright = 0x3f;
+		if ((err = SendDAC(av7110, 3, 0x80 + volleft)))
+			return err;
+		return SendDAC(av7110, 4, volright);
+
+	case DVB_ADAC_CRYSTAL:
+		volleft = 127 - volleft / 2;
+		volright = 127 - volright / 2;
+		i2c_writereg(av7110, 0x20, 0x03, volleft);
+		i2c_writereg(av7110, 0x20, 0x04, volright);
+		return 0;
+
+	case DVB_ADAC_MSP34x0:
+		vol  = (volleft > volright) ? volleft : volright;
+		val	= (vol * 0x73 / 255) << 8;
+		if (vol > 0)
+		       balance = ((volright - volleft) * 127) / vol;
+		msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8);
+		msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */
+		msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */
+		return 0;
+
+	case DVB_ADAC_MSP34x5:
+		vol = (volleft > volright) ? volleft : volright;
+		val = (vol * 0x73 / 255) << 8;
+		if (vol > 0)
+			balance = ((volright - volleft) * 127) / vol;
+		msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8);
+		msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */
+		return 0;
+	}
+
+	return 0;
+}
+
+int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode)
+{
+	int ret;
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode);
+
+	if (!ret && !av7110->playing) {
+		ret = ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO],
+			   av7110->pids[DMX_PES_AUDIO],
+			   av7110->pids[DMX_PES_TELETEXT],
+			   0, av7110->pids[DMX_PES_PCR]);
+		if (!ret)
+			ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+	}
+	return ret;
+}
+
+
+static enum av7110_video_mode sw2mode[16] = {
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,
+	AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL,
+	AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC,
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
+};
+
+static int get_video_format(struct av7110 *av7110, u8 *buf, int count)
+{
+	int i;
+	int hsize, vsize;
+	int sw;
+	u8 *p;
+	int ret = 0;
+
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	if (av7110->sinfo)
+		return 0;
+	for (i = 7; i < count - 10; i++) {
+		p = buf + i;
+		if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3)
+			continue;
+		p += 4;
+		hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4);
+		vsize = ((p[1] &0x0F) << 8) | (p[2]);
+		sw = (p[3] & 0x0F);
+		ret = av7110_set_vidmode(av7110, sw2mode[sw]);
+		if (!ret) {
+			dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw);
+			av7110->sinfo = 1;
+		}
+		break;
+	}
+	return ret;
+}
+
+
+/****************************************************************************
+ * I/O buffer management and control
+ ****************************************************************************/
+
+static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf,
+					 const u8 *buf, unsigned long count)
+{
+	unsigned long todo = count;
+	int free;
+
+	while (todo > 0) {
+		if (dvb_ringbuffer_free(rbuf) < 2048) {
+			if (wait_event_interruptible(rbuf->queue,
+						     (dvb_ringbuffer_free(rbuf) >= 2048)))
+				return count - todo;
+		}
+		free = dvb_ringbuffer_free(rbuf);
+		if (free > todo)
+			free = todo;
+		dvb_ringbuffer_write(rbuf, buf, free);
+		todo -= free;
+		buf += free;
+	}
+
+	return count - todo;
+}
+
+static void play_video_cb(u8 *buf, int count, void *priv)
+{
+	struct av7110 *av7110 = (struct av7110 *) priv;
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	if ((buf[3] & 0xe0) == 0xe0) {
+		get_video_format(av7110, buf, count);
+		aux_ring_buffer_write(&av7110->avout, buf, count);
+	} else
+		aux_ring_buffer_write(&av7110->aout, buf, count);
+}
+
+static void play_audio_cb(u8 *buf, int count, void *priv)
+{
+	struct av7110 *av7110 = (struct av7110 *) priv;
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	aux_ring_buffer_write(&av7110->aout, buf, count);
+}
+
+
+#define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096)
+
+static ssize_t ts_play(struct av7110 *av7110, const char __user *buf,
+		       unsigned long count, int nonblock, int type)
+{
+	struct dvb_ringbuffer *rb;
+	u8 *kb;
+	unsigned long todo = count;
+
+	dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count);
+
+	rb = (type) ? &av7110->avout : &av7110->aout;
+	kb = av7110->kbuf[type];
+
+	if (!kb)
+		return -ENOBUFS;
+
+	if (nonblock && !FREE_COND_TS)
+		return -EWOULDBLOCK;
+
+	while (todo >= TS_SIZE) {
+		if (!FREE_COND_TS) {
+			if (nonblock)
+				return count - todo;
+			if (wait_event_interruptible(rb->queue, FREE_COND_TS))
+				return count - todo;
+		}
+		if (copy_from_user(kb, buf, TS_SIZE))
+			return -EFAULT;
+		write_ts_to_decoder(av7110, type, kb, TS_SIZE);
+		todo -= TS_SIZE;
+		buf += TS_SIZE;
+	}
+
+	return count - todo;
+}
+
+
+#define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
+		   dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
+
+static ssize_t dvb_play(struct av7110 *av7110, const char __user *buf,
+			unsigned long count, int nonblock, int type)
+{
+	unsigned long todo = count, n;
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	if (!av7110->kbuf[type])
+		return -ENOBUFS;
+
+	if (nonblock && !FREE_COND)
+		return -EWOULDBLOCK;
+
+	while (todo > 0) {
+		if (!FREE_COND) {
+			if (nonblock)
+				return count - todo;
+			if (wait_event_interruptible(av7110->avout.queue,
+						     FREE_COND))
+				return count - todo;
+		}
+		n = todo;
+		if (n > IPACKS * 2)
+			n = IPACKS * 2;
+		if (copy_from_user(av7110->kbuf[type], buf, n))
+			return -EFAULT;
+		av7110_ipack_instant_repack(av7110->kbuf[type], n,
+					    &av7110->ipack[type]);
+		todo -= n;
+		buf += n;
+	}
+	return count - todo;
+}
+
+static ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf,
+			unsigned long count, int nonblock, int type)
+{
+	unsigned long todo = count, n;
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	if (!av7110->kbuf[type])
+		return -ENOBUFS;
+
+	if (nonblock && !FREE_COND)
+		return -EWOULDBLOCK;
+
+	while (todo > 0) {
+		if (!FREE_COND) {
+			if (nonblock)
+				return count - todo;
+			if (wait_event_interruptible(av7110->avout.queue,
+						     FREE_COND))
+				return count - todo;
+		}
+		n = todo;
+		if (n > IPACKS * 2)
+			n = IPACKS * 2;
+		av7110_ipack_instant_repack(buf, n, &av7110->ipack[type]);
+		todo -= n;
+		buf += n;
+	}
+	return count - todo;
+}
+
+static ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf,
+			 unsigned long count, int nonblock, int type)
+{
+	unsigned long todo = count, n;
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	if (!av7110->kbuf[type])
+		return -ENOBUFS;
+	if (nonblock && dvb_ringbuffer_free(&av7110->aout) < 20 * 1024)
+		return -EWOULDBLOCK;
+
+	while (todo > 0) {
+		if (dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) {
+			if (nonblock)
+				return count - todo;
+			if (wait_event_interruptible(av7110->aout.queue,
+					(dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)))
+				return count-todo;
+		}
+		n = todo;
+		if (n > IPACKS * 2)
+			n = IPACKS * 2;
+		if (copy_from_user(av7110->kbuf[type], buf, n))
+			return -EFAULT;
+		av7110_ipack_instant_repack(av7110->kbuf[type], n,
+					    &av7110->ipack[type]);
+		todo -= n;
+		buf += n;
+	}
+	return count - todo;
+}
+
+void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed)
+{
+	memset(p->pes, 0, TS_SIZE);
+	p->counter = 0;
+	p->pos = 0;
+	p->frags = 0;
+	if (feed)
+		p->feed = feed;
+}
+
+static void clear_p2t(struct av7110_p2t *p)
+{
+	memset(p->pes, 0, TS_SIZE);
+//	p->counter = 0;
+	p->pos = 0;
+	p->frags = 0;
+}
+
+
+static int find_pes_header(u8 const *buf, long int length, int *frags)
+{
+	int c = 0;
+	int found = 0;
+
+	*frags = 0;
+
+	while (c < length - 3 && !found) {
+		if (buf[c] == 0x00 && buf[c + 1] == 0x00 &&
+		    buf[c + 2] == 0x01) {
+			switch ( buf[c + 3] ) {
+			case PROG_STREAM_MAP:
+			case PRIVATE_STREAM2:
+			case PROG_STREAM_DIR:
+			case ECM_STREAM     :
+			case EMM_STREAM     :
+			case PADDING_STREAM :
+			case DSM_CC_STREAM  :
+			case ISO13522_STREAM:
+			case PRIVATE_STREAM1:
+			case AUDIO_STREAM_S ... AUDIO_STREAM_E:
+			case VIDEO_STREAM_S ... VIDEO_STREAM_E:
+				found = 1;
+				break;
+
+			default:
+				c++;
+				break;
+			}
+		} else
+			c++;
+	}
+	if (c == length - 3 && !found) {
+		if (buf[length - 1] == 0x00)
+			*frags = 1;
+		if (buf[length - 2] == 0x00 &&
+		    buf[length - 1] == 0x00)
+			*frags = 2;
+		if (buf[length - 3] == 0x00 &&
+		    buf[length - 2] == 0x00 &&
+		    buf[length - 1] == 0x01)
+			*frags = 3;
+		return -1;
+	}
+
+	return c;
+}
+
+void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p)
+{
+	int c, c2, l, add;
+	int check, rest;
+
+	c = 0;
+	c2 = 0;
+	if (p->frags){
+		check = 0;
+		switch(p->frags) {
+		case 1:
+			if (buf[c] == 0x00 && buf[c + 1] == 0x01) {
+				check = 1;
+				c += 2;
+			}
+			break;
+		case 2:
+			if (buf[c] == 0x01) {
+				check = 1;
+				c++;
+			}
+			break;
+		case 3:
+			check = 1;
+		}
+		if (check) {
+			switch (buf[c]) {
+			case PROG_STREAM_MAP:
+			case PRIVATE_STREAM2:
+			case PROG_STREAM_DIR:
+			case ECM_STREAM     :
+			case EMM_STREAM     :
+			case PADDING_STREAM :
+			case DSM_CC_STREAM  :
+			case ISO13522_STREAM:
+			case PRIVATE_STREAM1:
+			case AUDIO_STREAM_S ... AUDIO_STREAM_E:
+			case VIDEO_STREAM_S ... VIDEO_STREAM_E:
+				p->pes[0] = 0x00;
+				p->pes[1] = 0x00;
+				p->pes[2] = 0x01;
+				p->pes[3] = buf[c];
+				p->pos = 4;
+				memcpy(p->pes + p->pos, buf + c, (TS_SIZE - 4) - p->pos);
+				c += (TS_SIZE - 4) - p->pos;
+				p_to_t(p->pes, (TS_SIZE - 4), pid, &p->counter, p->feed);
+				clear_p2t(p);
+				break;
+
+			default:
+				c = 0;
+				break;
+			}
+		}
+		p->frags = 0;
+	}
+
+	if (p->pos) {
+		c2 = find_pes_header(buf + c, length - c, &p->frags);
+		if (c2 >= 0 && c2 < (TS_SIZE - 4) - p->pos)
+			l = c2+c;
+		else
+			l = (TS_SIZE - 4) - p->pos;
+		memcpy(p->pes + p->pos, buf, l);
+		c += l;
+		p->pos += l;
+		p_to_t(p->pes, p->pos, pid, &p->counter, p->feed);
+		clear_p2t(p);
+	}
+
+	add = 0;
+	while (c < length) {
+		c2 = find_pes_header(buf + c + add, length - c - add, &p->frags);
+		if (c2 >= 0) {
+			c2 += c + add;
+			if (c2 > c){
+				p_to_t(buf + c, c2 - c, pid, &p->counter, p->feed);
+				c = c2;
+				clear_p2t(p);
+				add = 0;
+			} else
+				add = 1;
+		} else {
+			l = length - c;
+			rest = l % (TS_SIZE - 4);
+			l -= rest;
+			p_to_t(buf + c, l, pid, &p->counter, p->feed);
+			memcpy(p->pes, buf + c + l, rest);
+			p->pos = rest;
+			c = length;
+		}
+	}
+}
+
+
+static int write_ts_header2(u16 pid, u8 *counter, int pes_start, u8 *buf, u8 length)
+{
+	int i;
+	int c = 0;
+	int fill;
+	u8 tshead[4] = { 0x47, 0x00, 0x00, 0x10 };
+
+	fill = (TS_SIZE - 4) - length;
+	if (pes_start)
+		tshead[1] = 0x40;
+	if (fill)
+		tshead[3] = 0x30;
+	tshead[1] |= (u8)((pid & 0x1F00) >> 8);
+	tshead[2] |= (u8)(pid & 0x00FF);
+	tshead[3] |= ((*counter)++ & 0x0F);
+	memcpy(buf, tshead, 4);
+	c += 4;
+
+	if (fill) {
+		buf[4] = fill - 1;
+		c++;
+		if (fill > 1) {
+			buf[5] = 0x00;
+			c++;
+		}
+		for (i = 6; i < fill + 4; i++) {
+			buf[i] = 0xFF;
+			c++;
+		}
+	}
+
+	return c;
+}
+
+
+static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter,
+		   struct dvb_demux_feed *feed)
+{
+	int l, pes_start;
+	u8 obuf[TS_SIZE];
+	long c = 0;
+
+	pes_start = 0;
+	if (length > 3 &&
+	     buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01)
+		switch (buf[3]) {
+			case PROG_STREAM_MAP:
+			case PRIVATE_STREAM2:
+			case PROG_STREAM_DIR:
+			case ECM_STREAM     :
+			case EMM_STREAM     :
+			case PADDING_STREAM :
+			case DSM_CC_STREAM  :
+			case ISO13522_STREAM:
+			case PRIVATE_STREAM1:
+			case AUDIO_STREAM_S ... AUDIO_STREAM_E:
+			case VIDEO_STREAM_S ... VIDEO_STREAM_E:
+				pes_start = 1;
+				break;
+
+			default:
+				break;
+		}
+
+	while (c < length) {
+		memset(obuf, 0, TS_SIZE);
+		if (length - c >= (TS_SIZE - 4)){
+			l = write_ts_header2(pid, counter, pes_start,
+					     obuf, (TS_SIZE - 4));
+			memcpy(obuf + l, buf + c, TS_SIZE - l);
+			c += TS_SIZE - l;
+		} else {
+			l = write_ts_header2(pid, counter, pes_start,
+					     obuf, length - c);
+			memcpy(obuf + l, buf + c, TS_SIZE - l);
+			c = length;
+		}
+		feed->cb.ts(obuf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
+		pes_start = 0;
+	}
+}
+
+
+static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len)
+{
+	struct ipack *ipack = &av7110->ipack[type];
+
+	if (buf[1] & TRANS_ERROR) {
+		av7110_ipack_reset(ipack);
+		return -1;
+	}
+
+	if (!(buf[3] & PAYLOAD))
+		return -1;
+
+	if (buf[1] & PAY_START)
+		av7110_ipack_flush(ipack);
+
+	if (buf[3] & ADAPT_FIELD) {
+		len -= buf[4] + 1;
+		buf += buf[4] + 1;
+		if (!len)
+			return 0;
+	}
+
+	av7110_ipack_instant_repack(buf + 4, len - 4, ipack);
+	return 0;
+}
+
+
+int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct av7110 *av7110 = (struct av7110 *) demux->priv;
+
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE)
+		return 0;
+
+	switch (feed->pes_type) {
+	case 0:
+		if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
+			return -EINVAL;
+		break;
+	case 1:
+		if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY)
+			return -EINVAL;
+		break;
+	default:
+		return -1;
+	}
+
+	return write_ts_to_decoder(av7110, feed->pes_type, buf, len);
+}
+
+
+
+/******************************************************************************
+ * Video MPEG decoder events
+ ******************************************************************************/
+void dvb_video_add_event(struct av7110 *av7110, struct video_event *event)
+{
+	struct dvb_video_events *events = &av7110->video_events;
+	int wp;
+
+	spin_lock_bh(&events->lock);
+
+	wp = (events->eventw + 1) % MAX_VIDEO_EVENT;
+	if (wp == events->eventr) {
+		events->overflow = 1;
+		events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT;
+	}
+
+	//FIXME: timestamp?
+	memcpy(&events->events[events->eventw], event, sizeof(struct video_event));
+	events->eventw = wp;
+
+	spin_unlock_bh(&events->lock);
+
+	wake_up_interruptible(&events->wait_queue);
+}
+
+
+static int dvb_video_get_event (struct av7110 *av7110, struct video_event *event, int flags)
+{
+	struct dvb_video_events *events = &av7110->video_events;
+
+	if (events->overflow) {
+		events->overflow = 0;
+		return -EOVERFLOW;
+	}
+	if (events->eventw == events->eventr) {
+		int ret;
+
+		if (flags & O_NONBLOCK)
+			return -EWOULDBLOCK;
+
+		ret = wait_event_interruptible(events->wait_queue,
+					       events->eventw != events->eventr);
+		if (ret < 0)
+			return ret;
+	}
+
+	spin_lock_bh(&events->lock);
+
+	memcpy(event, &events->events[events->eventr],
+	       sizeof(struct video_event));
+	events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT;
+
+	spin_unlock_bh(&events->lock);
+
+	return 0;
+}
+
+
+/******************************************************************************
+ * DVB device file operations
+ ******************************************************************************/
+
+static unsigned int dvb_video_poll(struct file *file, poll_table *wait)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct av7110 *av7110 = dvbdev->priv;
+	unsigned int mask = 0;
+
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	if ((file->f_flags & O_ACCMODE) != O_RDONLY)
+		poll_wait(file, &av7110->avout.queue, wait);
+
+	poll_wait(file, &av7110->video_events.wait_queue, wait);
+
+	if (av7110->video_events.eventw != av7110->video_events.eventr)
+		mask = POLLPRI;
+
+	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+		if (av7110->playing) {
+			if (FREE_COND)
+				mask |= (POLLOUT | POLLWRNORM);
+			} else /* if not playing: may play if asked for */
+				mask |= (POLLOUT | POLLWRNORM);
+	}
+
+	return mask;
+}
+
+static ssize_t dvb_video_write(struct file *file, const char __user *buf,
+			       size_t count, loff_t *ppos)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct av7110 *av7110 = dvbdev->priv;
+	unsigned char c;
+
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+		return -EPERM;
+
+	if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY)
+		return -EPERM;
+
+	if (get_user(c, buf))
+		return -EFAULT;
+	if (c == 0x47 && count % TS_SIZE == 0)
+		return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
+	else
+		return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
+}
+
+static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct av7110 *av7110 = dvbdev->priv;
+	unsigned int mask = 0;
+
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	poll_wait(file, &av7110->aout.queue, wait);
+
+	if (av7110->playing) {
+		if (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
+			mask |= (POLLOUT | POLLWRNORM);
+	} else /* if not playing: may play if asked for */
+		mask = (POLLOUT | POLLWRNORM);
+
+	return mask;
+}
+
+static ssize_t dvb_audio_write(struct file *file, const char __user *buf,
+			       size_t count, loff_t *ppos)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct av7110 *av7110 = dvbdev->priv;
+	unsigned char c;
+
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	if (av7110->audiostate.stream_source != AUDIO_SOURCE_MEMORY) {
+		printk(KERN_ERR "not audio source memory\n");
+		return -EPERM;
+	}
+
+	if (get_user(c, buf))
+		return -EFAULT;
+	if (c == 0x47 && count % TS_SIZE == 0)
+		return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
+	else
+		return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
+}
+
+static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 };
+
+#define MIN_IFRAME 400000
+
+static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock)
+{
+	unsigned i, n;
+	int progressive = 0;
+	int match = 0;
+
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	if (!(av7110->playing & RP_VIDEO)) {
+		if (av7110_av_start_play(av7110, RP_VIDEO) < 0)
+			return -EBUSY;
+	}
+
+	/* search in buf for instances of 00 00 01 b5 1? */
+	for (i = 0; i < len; i++) {
+		unsigned char c;
+		if (get_user(c, buf + i))
+			return -EFAULT;
+		if (match == 5) {
+			progressive = c & 0x08;
+			match = 0;
+		}
+		if (c == 0x00) {
+			match = (match == 1 || match == 2) ? 2 : 1;
+			continue;
+		}
+		switch (match++) {
+		case 2: if (c == 0x01)
+				continue;
+			break;
+		case 3: if (c == 0xb5)
+				continue;
+			break;
+		case 4: if ((c & 0xf0) == 0x10)
+				continue;
+			break;
+		}
+		match = 0;
+	}
+
+	/* setting n always > 1, fixes problems when playing stillframes
+	   consisting of I- and P-Frames */
+	n = MIN_IFRAME / len + 1;
+
+	/* FIXME: nonblock? */
+	dvb_play_kernel(av7110, iframe_header, sizeof(iframe_header), 0, 1);
+
+	for (i = 0; i < n; i++)
+		dvb_play(av7110, buf, len, 0, 1);
+
+	av7110_ipack_flush(&av7110->ipack[1]);
+
+	if (progressive)
+		return vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1);
+	else
+		return 0;
+}
+
+
+static int dvb_video_ioctl(struct file *file,
+			   unsigned int cmd, void *parg)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct av7110 *av7110 = dvbdev->priv;
+	unsigned long arg = (unsigned long) parg;
+	int ret = 0;
+
+	dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd);
+
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+		if ( cmd != VIDEO_GET_STATUS && cmd != VIDEO_GET_EVENT &&
+		     cmd != VIDEO_GET_SIZE ) {
+			return -EPERM;
+		}
+	}
+
+	switch (cmd) {
+	case VIDEO_STOP:
+		av7110->videostate.play_state = VIDEO_STOPPED;
+		if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY)
+			ret = av7110_av_stop(av7110, RP_VIDEO);
+		else
+			ret = vidcom(av7110, AV_VIDEO_CMD_STOP,
+			       av7110->videostate.video_blank ? 0 : 1);
+		if (!ret)
+			av7110->trickmode = TRICK_NONE;
+		break;
+
+	case VIDEO_PLAY:
+		av7110->trickmode = TRICK_NONE;
+		if (av7110->videostate.play_state == VIDEO_FREEZED) {
+			av7110->videostate.play_state = VIDEO_PLAYING;
+			ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
+			if (ret)
+				break;
+		}
+		if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) {
+			if (av7110->playing == RP_AV) {
+				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
+				if (ret)
+					break;
+				av7110->playing &= ~RP_VIDEO;
+			}
+			ret = av7110_av_start_play(av7110, RP_VIDEO);
+		}
+		if (!ret)
+			ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
+		if (!ret)
+			av7110->videostate.play_state = VIDEO_PLAYING;
+		break;
+
+	case VIDEO_FREEZE:
+		av7110->videostate.play_state = VIDEO_FREEZED;
+		if (av7110->playing & RP_VIDEO)
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0);
+		else
+			ret = vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1);
+		if (!ret)
+			av7110->trickmode = TRICK_FREEZE;
+		break;
+
+	case VIDEO_CONTINUE:
+		if (av7110->playing & RP_VIDEO)
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0);
+		if (!ret)
+			ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
+		if (!ret) {
+			av7110->videostate.play_state = VIDEO_PLAYING;
+			av7110->trickmode = TRICK_NONE;
+		}
+		break;
+
+	case VIDEO_SELECT_SOURCE:
+		av7110->videostate.stream_source = (video_stream_source_t) arg;
+		break;
+
+	case VIDEO_SET_BLANK:
+		av7110->videostate.video_blank = (int) arg;
+		break;
+
+	case VIDEO_GET_STATUS:
+		memcpy(parg, &av7110->videostate, sizeof(struct video_status));
+		break;
+
+	case VIDEO_GET_EVENT:
+		ret = dvb_video_get_event(av7110, parg, file->f_flags);
+		break;
+
+	case VIDEO_GET_SIZE:
+		memcpy(parg, &av7110->video_size, sizeof(video_size_t));
+		break;
+
+	case VIDEO_SET_DISPLAY_FORMAT:
+	{
+		video_displayformat_t format = (video_displayformat_t) arg;
+		switch (format) {
+		case VIDEO_PAN_SCAN:
+			av7110->display_panscan = VID_PAN_SCAN_PREF;
+			break;
+		case VIDEO_LETTER_BOX:
+			av7110->display_panscan = VID_VC_AND_PS_PREF;
+			break;
+		case VIDEO_CENTER_CUT_OUT:
+			av7110->display_panscan = VID_CENTRE_CUT_PREF;
+			break;
+		default:
+			ret = -EINVAL;
+		}
+		if (ret < 0)
+			break;
+		av7110->videostate.display_format = format;
+		ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
+				    1, av7110->display_panscan);
+		break;
+	}
+
+	case VIDEO_SET_FORMAT:
+		if (arg > 1) {
+			ret = -EINVAL;
+			break;
+		}
+		av7110->display_ar = arg;
+		ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType,
+				    1, (u16) arg);
+		break;
+
+	case VIDEO_STILLPICTURE:
+	{
+		struct video_still_picture *pic =
+			(struct video_still_picture *) parg;
+		av7110->videostate.stream_source = VIDEO_SOURCE_MEMORY;
+		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
+		ret = play_iframe(av7110, pic->iFrame, pic->size,
+				  file->f_flags & O_NONBLOCK);
+		break;
+	}
+
+	case VIDEO_FAST_FORWARD:
+		//note: arg is ignored by firmware
+		if (av7110->playing & RP_VIDEO)
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+					    __Scan_I, 2, AV_PES, 0);
+		else
+			ret = vidcom(av7110, AV_VIDEO_CMD_FFWD, arg);
+		if (!ret) {
+			av7110->trickmode = TRICK_FAST;
+			av7110->videostate.play_state = VIDEO_PLAYING;
+		}
+		break;
+
+	case VIDEO_SLOWMOTION:
+		if (av7110->playing&RP_VIDEO) {
+			if (av7110->trickmode != TRICK_SLOW)
+				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
+			if (!ret)
+				ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
+		} else {
+			ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
+			if (!ret)
+				ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 0);
+			if (!ret)
+				ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
+		}
+		if (!ret) {
+			av7110->trickmode = TRICK_SLOW;
+			av7110->videostate.play_state = VIDEO_PLAYING;
+		}
+		break;
+
+	case VIDEO_GET_CAPABILITIES:
+		*(int *)parg = VIDEO_CAP_MPEG1 | VIDEO_CAP_MPEG2 |
+			VIDEO_CAP_SYS | VIDEO_CAP_PROG;
+		break;
+
+	case VIDEO_CLEAR_BUFFER:
+		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
+		av7110_ipack_reset(&av7110->ipack[1]);
+		if (av7110->playing == RP_AV) {
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+					    __Play, 2, AV_PES, 0);
+			if (ret)
+				break;
+			if (av7110->trickmode == TRICK_FAST)
+				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+						    __Scan_I, 2, AV_PES, 0);
+			if (av7110->trickmode == TRICK_SLOW) {
+				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+						    __Slow, 2, 0, 0);
+				if (!ret)
+					ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
+			}
+			if (av7110->trickmode == TRICK_FREEZE)
+				ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 1);
+		}
+		break;
+
+	case VIDEO_SET_STREAMTYPE:
+		break;
+
+	default:
+		ret = -ENOIOCTLCMD;
+		break;
+	}
+
+	return ret;
+}
+
+static int dvb_audio_ioctl(struct file *file,
+			   unsigned int cmd, void *parg)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct av7110 *av7110 = dvbdev->priv;
+	unsigned long arg = (unsigned long) parg;
+	int ret = 0;
+
+	dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd);
+
+	if (((file->f_flags & O_ACCMODE) == O_RDONLY) &&
+	    (cmd != AUDIO_GET_STATUS))
+		return -EPERM;
+
+	switch (cmd) {
+	case AUDIO_STOP:
+		if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
+			ret = av7110_av_stop(av7110, RP_AUDIO);
+		else
+			ret = audcom(av7110, AUDIO_CMD_MUTE);
+		if (!ret)
+			av7110->audiostate.play_state = AUDIO_STOPPED;
+		break;
+
+	case AUDIO_PLAY:
+		if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
+			ret = av7110_av_start_play(av7110, RP_AUDIO);
+		if (!ret)
+			ret = audcom(av7110, AUDIO_CMD_UNMUTE);
+		if (!ret)
+			av7110->audiostate.play_state = AUDIO_PLAYING;
+		break;
+
+	case AUDIO_PAUSE:
+		ret = audcom(av7110, AUDIO_CMD_MUTE);
+		if (!ret)
+			av7110->audiostate.play_state = AUDIO_PAUSED;
+		break;
+
+	case AUDIO_CONTINUE:
+		if (av7110->audiostate.play_state == AUDIO_PAUSED) {
+			av7110->audiostate.play_state = AUDIO_PLAYING;
+			ret = audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16);
+		}
+		break;
+
+	case AUDIO_SELECT_SOURCE:
+		av7110->audiostate.stream_source = (audio_stream_source_t) arg;
+		break;
+
+	case AUDIO_SET_MUTE:
+	{
+		ret = audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE);
+		if (!ret)
+			av7110->audiostate.mute_state = (int) arg;
+		break;
+	}
+
+	case AUDIO_SET_AV_SYNC:
+		av7110->audiostate.AV_sync_state = (int) arg;
+		ret = audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF);
+		break;
+
+	case AUDIO_SET_BYPASS_MODE:
+		if (FW_VERSION(av7110->arm_app) < 0x2621)
+			ret = -EINVAL;
+		av7110->audiostate.bypass_mode = (int)arg;
+		break;
+
+	case AUDIO_CHANNEL_SELECT:
+		av7110->audiostate.channel_select = (audio_channel_select_t) arg;
+		switch(av7110->audiostate.channel_select) {
+		case AUDIO_STEREO:
+			ret = audcom(av7110, AUDIO_CMD_STEREO);
+			if (!ret) {
+				if (av7110->adac_type == DVB_ADAC_CRYSTAL)
+					i2c_writereg(av7110, 0x20, 0x02, 0x49);
+				else if (av7110->adac_type == DVB_ADAC_MSP34x5)
+					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220);
+			}
+			break;
+		case AUDIO_MONO_LEFT:
+			ret = audcom(av7110, AUDIO_CMD_MONO_L);
+			if (!ret) {
+				if (av7110->adac_type == DVB_ADAC_CRYSTAL)
+					i2c_writereg(av7110, 0x20, 0x02, 0x4a);
+				else if (av7110->adac_type == DVB_ADAC_MSP34x5)
+					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200);
+			}
+			break;
+		case AUDIO_MONO_RIGHT:
+			ret = audcom(av7110, AUDIO_CMD_MONO_R);
+			if (!ret) {
+				if (av7110->adac_type == DVB_ADAC_CRYSTAL)
+					i2c_writereg(av7110, 0x20, 0x02, 0x45);
+				else if (av7110->adac_type == DVB_ADAC_MSP34x5)
+					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210);
+			}
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		break;
+
+	case AUDIO_GET_STATUS:
+		memcpy(parg, &av7110->audiostate, sizeof(struct audio_status));
+		break;
+
+	case AUDIO_GET_CAPABILITIES:
+		if (FW_VERSION(av7110->arm_app) < 0x2621)
+			*(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
+		else
+			*(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_DTS | AUDIO_CAP_AC3 |
+						AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
+		break;
+
+	case AUDIO_CLEAR_BUFFER:
+		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
+		av7110_ipack_reset(&av7110->ipack[0]);
+		if (av7110->playing == RP_AV)
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+					    __Play, 2, AV_PES, 0);
+		break;
+
+	case AUDIO_SET_ID:
+		break;
+
+	case AUDIO_SET_MIXER:
+	{
+		struct audio_mixer *amix = (struct audio_mixer *)parg;
+		ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right);
+		break;
+	}
+
+	case AUDIO_SET_STREAMTYPE:
+		break;
+
+	default:
+		ret = -ENOIOCTLCMD;
+	}
+
+	return ret;
+}
+
+
+static int dvb_video_open(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct av7110 *av7110 = dvbdev->priv;
+	int err;
+
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	if ((err = dvb_generic_open(inode, file)) < 0)
+		return err;
+
+	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
+		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
+		av7110->video_blank = 1;
+		av7110->audiostate.AV_sync_state = 1;
+		av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX;
+
+		/*  empty event queue */
+		av7110->video_events.eventr = av7110->video_events.eventw = 0;
+	}
+
+	return 0;
+}
+
+static int dvb_video_release(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct av7110 *av7110 = dvbdev->priv;
+
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+		av7110_av_stop(av7110, RP_VIDEO);
+	}
+
+	return dvb_generic_release(inode, file);
+}
+
+static int dvb_audio_open(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct av7110 *av7110 = dvbdev->priv;
+	int err = dvb_generic_open(inode, file);
+
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	if (err < 0)
+		return err;
+	dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
+	av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX;
+	return 0;
+}
+
+static int dvb_audio_release(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct av7110 *av7110 = dvbdev->priv;
+
+	dprintk(2, "av7110:%p, \n", av7110);
+
+	av7110_av_stop(av7110, RP_AUDIO);
+	return dvb_generic_release(inode, file);
+}
+
+
+
+/******************************************************************************
+ * driver registration
+ ******************************************************************************/
+
+static const struct file_operations dvb_video_fops = {
+	.owner		= THIS_MODULE,
+	.write		= dvb_video_write,
+	.unlocked_ioctl	= dvb_generic_ioctl,
+	.open		= dvb_video_open,
+	.release	= dvb_video_release,
+	.poll		= dvb_video_poll,
+	.llseek		= noop_llseek,
+};
+
+static struct dvb_device dvbdev_video = {
+	.priv		= NULL,
+	.users		= 6,
+	.readers	= 5,	/* arbitrary */
+	.writers	= 1,
+	.fops		= &dvb_video_fops,
+	.kernel_ioctl	= dvb_video_ioctl,
+};
+
+static const struct file_operations dvb_audio_fops = {
+	.owner		= THIS_MODULE,
+	.write		= dvb_audio_write,
+	.unlocked_ioctl	= dvb_generic_ioctl,
+	.open		= dvb_audio_open,
+	.release	= dvb_audio_release,
+	.poll		= dvb_audio_poll,
+	.llseek		= noop_llseek,
+};
+
+static struct dvb_device dvbdev_audio = {
+	.priv		= NULL,
+	.users		= 1,
+	.writers	= 1,
+	.fops		= &dvb_audio_fops,
+	.kernel_ioctl	= dvb_audio_ioctl,
+};
+
+
+int av7110_av_register(struct av7110 *av7110)
+{
+	av7110->audiostate.AV_sync_state = 0;
+	av7110->audiostate.mute_state = 0;
+	av7110->audiostate.play_state = AUDIO_STOPPED;
+	av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX;
+	av7110->audiostate.channel_select = AUDIO_STEREO;
+	av7110->audiostate.bypass_mode = 0;
+
+	av7110->videostate.video_blank = 0;
+	av7110->videostate.play_state = VIDEO_STOPPED;
+	av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX;
+	av7110->videostate.video_format = VIDEO_FORMAT_4_3;
+	av7110->videostate.display_format = VIDEO_LETTER_BOX;
+	av7110->display_ar = VIDEO_FORMAT_4_3;
+	av7110->display_panscan = VID_VC_AND_PS_PREF;
+
+	init_waitqueue_head(&av7110->video_events.wait_queue);
+	spin_lock_init(&av7110->video_events.lock);
+	av7110->video_events.eventw = av7110->video_events.eventr = 0;
+	av7110->video_events.overflow = 0;
+	memset(&av7110->video_size, 0, sizeof (video_size_t));
+
+	dvb_register_device(&av7110->dvb_adapter, &av7110->video_dev,
+			    &dvbdev_video, av7110, DVB_DEVICE_VIDEO);
+
+	dvb_register_device(&av7110->dvb_adapter, &av7110->audio_dev,
+			    &dvbdev_audio, av7110, DVB_DEVICE_AUDIO);
+
+	return 0;
+}
+
+void av7110_av_unregister(struct av7110 *av7110)
+{
+	dvb_unregister_device(av7110->audio_dev);
+	dvb_unregister_device(av7110->video_dev);
+}
+
+int av7110_av_init(struct av7110 *av7110)
+{
+	void (*play[])(u8 *, int, void *) = { play_audio_cb, play_video_cb };
+	int i, ret;
+
+	for (i = 0; i < 2; i++) {
+		struct ipack *ipack = av7110->ipack + i;
+
+		ret = av7110_ipack_init(ipack, IPACKS, play[i]);
+		if (ret < 0) {
+			if (i)
+				av7110_ipack_free(--ipack);
+			goto out;
+		}
+		ipack->data = av7110;
+	}
+
+	dvb_ringbuffer_init(&av7110->avout, av7110->iobuf, AVOUTLEN);
+	dvb_ringbuffer_init(&av7110->aout, av7110->iobuf + AVOUTLEN, AOUTLEN);
+
+	av7110->kbuf[0] = (u8 *)(av7110->iobuf + AVOUTLEN + AOUTLEN + BMPLEN);
+	av7110->kbuf[1] = av7110->kbuf[0] + 2 * IPACKS;
+out:
+	return ret;
+}
+
+void av7110_av_exit(struct av7110 *av7110)
+{
+	av7110_ipack_free(&av7110->ipack[0]);
+	av7110_ipack_free(&av7110->ipack[1]);
+}
diff --git a/drivers/media/pci/ttpci/av7110_av.h b/drivers/media/pci/ttpci/av7110_av.h
new file mode 100644
index 0000000..5f02ef8
--- /dev/null
+++ b/drivers/media/pci/ttpci/av7110_av.h
@@ -0,0 +1,30 @@
+#ifndef _AV7110_AV_H_
+#define _AV7110_AV_H_
+
+struct av7110;
+
+extern int av7110_set_vidmode(struct av7110 *av7110,
+			      enum av7110_video_mode mode);
+
+extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len);
+extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen);
+extern int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len);
+
+extern int av7110_set_volume(struct av7110 *av7110, int volleft, int volright);
+extern int av7110_av_stop(struct av7110 *av7110, int av);
+extern int av7110_av_start_record(struct av7110 *av7110, int av,
+			  struct dvb_demux_feed *dvbdmxfeed);
+extern int av7110_av_start_play(struct av7110 *av7110, int av);
+
+extern void dvb_video_add_event(struct av7110 *av7110, struct video_event *event);
+
+extern void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed);
+extern void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p);
+
+extern int av7110_av_register(struct av7110 *av7110);
+extern void av7110_av_unregister(struct av7110 *av7110);
+extern int av7110_av_init(struct av7110 *av7110);
+extern void av7110_av_exit(struct av7110 *av7110);
+
+
+#endif /* _AV7110_AV_H_ */
diff --git a/drivers/media/pci/ttpci/av7110_ca.c b/drivers/media/pci/ttpci/av7110_ca.c
new file mode 100644
index 0000000..9fc1dd0
--- /dev/null
+++ b/drivers/media/pci/ttpci/av7110_ca.c
@@ -0,0 +1,387 @@
+/*
+ * av7110_ca.c: CA and CI stuff
+ *
+ * Copyright (C) 1999-2002 Ralph  Metzler
+ *                       & Marcus Metzler for convergence integrated media GmbH
+ *
+ * originally based on code by:
+ * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org/ 
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/timer.h>
+#include <linux/poll.h>
+#include <linux/gfp.h>
+
+#include "av7110.h"
+#include "av7110_hw.h"
+#include "av7110_ca.h"
+
+
+void CI_handle(struct av7110 *av7110, u8 *data, u16 len)
+{
+	dprintk(8, "av7110:%p\n",av7110);
+
+	if (len < 3)
+		return;
+	switch (data[0]) {
+	case CI_MSG_CI_INFO:
+		if (data[2] != 1 && data[2] != 2)
+			break;
+		switch (data[1]) {
+		case 0:
+			av7110->ci_slot[data[2] - 1].flags = 0;
+			break;
+		case 1:
+			av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_PRESENT;
+			break;
+		case 2:
+			av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_READY;
+			break;
+		}
+		break;
+	case CI_SWITCH_PRG_REPLY:
+		//av7110->ci_stat=data[1];
+		break;
+	default:
+		break;
+	}
+}
+
+
+void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len)
+{
+	if (dvb_ringbuffer_free(cibuf) < len + 2)
+		return;
+
+	DVB_RINGBUFFER_WRITE_BYTE(cibuf, len >> 8);
+	DVB_RINGBUFFER_WRITE_BYTE(cibuf, len & 0xff);
+	dvb_ringbuffer_write(cibuf, data, len);
+	wake_up_interruptible(&cibuf->queue);
+}
+
+
+/******************************************************************************
+ * CI link layer file ops
+ ******************************************************************************/
+
+static int ci_ll_init(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf, int size)
+{
+	struct dvb_ringbuffer *tab[] = { cirbuf, ciwbuf, NULL }, **p;
+	void *data;
+
+	for (p = tab; *p; p++) {
+		data = vmalloc(size);
+		if (!data) {
+			while (p-- != tab) {
+				vfree(p[0]->data);
+				p[0]->data = NULL;
+			}
+			return -ENOMEM;
+		}
+		dvb_ringbuffer_init(*p, data, size);
+	}
+	return 0;
+}
+
+static void ci_ll_flush(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf)
+{
+	dvb_ringbuffer_flush_spinlock_wakeup(cirbuf);
+	dvb_ringbuffer_flush_spinlock_wakeup(ciwbuf);
+}
+
+static void ci_ll_release(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf)
+{
+	vfree(cirbuf->data);
+	cirbuf->data = NULL;
+	vfree(ciwbuf->data);
+	ciwbuf->data = NULL;
+}
+
+static int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file,
+		       int slots, ca_slot_info_t *slot)
+{
+	int i;
+	int len = 0;
+	u8 msg[8] = { 0x00, 0x06, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00 };
+
+	for (i = 0; i < 2; i++) {
+		if (slots & (1 << i))
+			len += 8;
+	}
+
+	if (dvb_ringbuffer_free(cibuf) < len)
+		return -EBUSY;
+
+	for (i = 0; i < 2; i++) {
+		if (slots & (1 << i)) {
+			msg[2] = i;
+			dvb_ringbuffer_write(cibuf, msg, 8);
+			slot[i].flags = 0;
+		}
+	}
+
+	return 0;
+}
+
+static ssize_t ci_ll_write(struct dvb_ringbuffer *cibuf, struct file *file,
+			   const char __user *buf, size_t count, loff_t *ppos)
+{
+	int free;
+	int non_blocking = file->f_flags & O_NONBLOCK;
+	u8 *page = (u8 *)__get_free_page(GFP_USER);
+	int res;
+
+	if (!page)
+		return -ENOMEM;
+
+	res = -EINVAL;
+	if (count > 2048)
+		goto out;
+
+	res = -EFAULT;
+	if (copy_from_user(page, buf, count))
+		goto out;
+
+	free = dvb_ringbuffer_free(cibuf);
+	if (count + 2 > free) {
+		res = -EWOULDBLOCK;
+		if (non_blocking)
+			goto out;
+		res = -ERESTARTSYS;
+		if (wait_event_interruptible(cibuf->queue,
+					     (dvb_ringbuffer_free(cibuf) >= count + 2)))
+			goto out;
+	}
+
+	DVB_RINGBUFFER_WRITE_BYTE(cibuf, count >> 8);
+	DVB_RINGBUFFER_WRITE_BYTE(cibuf, count & 0xff);
+
+	res = dvb_ringbuffer_write(cibuf, page, count);
+out:
+	free_page((unsigned long)page);
+	return res;
+}
+
+static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file,
+			  char __user *buf, size_t count, loff_t *ppos)
+{
+	int avail;
+	int non_blocking = file->f_flags & O_NONBLOCK;
+	ssize_t len;
+
+	if (!cibuf->data || !count)
+		return 0;
+	if (non_blocking && (dvb_ringbuffer_empty(cibuf)))
+		return -EWOULDBLOCK;
+	if (wait_event_interruptible(cibuf->queue,
+				     !dvb_ringbuffer_empty(cibuf)))
+		return -ERESTARTSYS;
+	avail = dvb_ringbuffer_avail(cibuf);
+	if (avail < 4)
+		return 0;
+	len = DVB_RINGBUFFER_PEEK(cibuf, 0) << 8;
+	len |= DVB_RINGBUFFER_PEEK(cibuf, 1);
+	if (avail < len + 2 || count < len)
+		return -EINVAL;
+	DVB_RINGBUFFER_SKIP(cibuf, 2);
+
+	return dvb_ringbuffer_read_user(cibuf, buf, len);
+}
+
+static int dvb_ca_open(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct av7110 *av7110 = dvbdev->priv;
+	int err = dvb_generic_open(inode, file);
+
+	dprintk(8, "av7110:%p\n",av7110);
+
+	if (err < 0)
+		return err;
+	ci_ll_flush(&av7110->ci_rbuffer, &av7110->ci_wbuffer);
+	return 0;
+}
+
+static unsigned int dvb_ca_poll (struct file *file, poll_table *wait)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct av7110 *av7110 = dvbdev->priv;
+	struct dvb_ringbuffer *rbuf = &av7110->ci_rbuffer;
+	struct dvb_ringbuffer *wbuf = &av7110->ci_wbuffer;
+	unsigned int mask = 0;
+
+	dprintk(8, "av7110:%p\n",av7110);
+
+	poll_wait(file, &rbuf->queue, wait);
+	poll_wait(file, &wbuf->queue, wait);
+
+	if (!dvb_ringbuffer_empty(rbuf))
+		mask |= (POLLIN | POLLRDNORM);
+
+	if (dvb_ringbuffer_free(wbuf) > 1024)
+		mask |= (POLLOUT | POLLWRNORM);
+
+	return mask;
+}
+
+static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct av7110 *av7110 = dvbdev->priv;
+	unsigned long arg = (unsigned long) parg;
+
+	dprintk(8, "av7110:%p\n",av7110);
+
+	switch (cmd) {
+	case CA_RESET:
+		return ci_ll_reset(&av7110->ci_wbuffer, file, arg, &av7110->ci_slot[0]);
+		break;
+	case CA_GET_CAP:
+	{
+		ca_caps_t cap;
+
+		cap.slot_num = 2;
+		cap.slot_type = (FW_CI_LL_SUPPORT(av7110->arm_app) ?
+				 CA_CI_LINK : CA_CI) | CA_DESCR;
+		cap.descr_num = 16;
+		cap.descr_type = CA_ECD;
+		memcpy(parg, &cap, sizeof(cap));
+		break;
+	}
+
+	case CA_GET_SLOT_INFO:
+	{
+		ca_slot_info_t *info=(ca_slot_info_t *)parg;
+
+		if (info->num < 0 || info->num > 1)
+			return -EINVAL;
+		av7110->ci_slot[info->num].num = info->num;
+		av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
+							CA_CI_LINK : CA_CI;
+		memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t));
+		break;
+	}
+
+	case CA_GET_MSG:
+		break;
+
+	case CA_SEND_MSG:
+		break;
+
+	case CA_GET_DESCR_INFO:
+	{
+		ca_descr_info_t info;
+
+		info.num = 16;
+		info.type = CA_ECD;
+		memcpy(parg, &info, sizeof (info));
+		break;
+	}
+
+	case CA_SET_DESCR:
+	{
+		ca_descr_t *descr = (ca_descr_t*) parg;
+
+		if (descr->index >= 16)
+			return -EINVAL;
+		if (descr->parity > 1)
+			return -EINVAL;
+		av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetDescr, 5,
+			      (descr->index<<8)|descr->parity,
+			      (descr->cw[0]<<8)|descr->cw[1],
+			      (descr->cw[2]<<8)|descr->cw[3],
+			      (descr->cw[4]<<8)|descr->cw[5],
+			      (descr->cw[6]<<8)|descr->cw[7]);
+		break;
+	}
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static ssize_t dvb_ca_write(struct file *file, const char __user *buf,
+			    size_t count, loff_t *ppos)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct av7110 *av7110 = dvbdev->priv;
+
+	dprintk(8, "av7110:%p\n",av7110);
+	return ci_ll_write(&av7110->ci_wbuffer, file, buf, count, ppos);
+}
+
+static ssize_t dvb_ca_read(struct file *file, char __user *buf,
+			   size_t count, loff_t *ppos)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct av7110 *av7110 = dvbdev->priv;
+
+	dprintk(8, "av7110:%p\n",av7110);
+	return ci_ll_read(&av7110->ci_rbuffer, file, buf, count, ppos);
+}
+
+static const struct file_operations dvb_ca_fops = {
+	.owner		= THIS_MODULE,
+	.read		= dvb_ca_read,
+	.write		= dvb_ca_write,
+	.unlocked_ioctl	= dvb_generic_ioctl,
+	.open		= dvb_ca_open,
+	.release	= dvb_generic_release,
+	.poll		= dvb_ca_poll,
+	.llseek		= default_llseek,
+};
+
+static struct dvb_device dvbdev_ca = {
+	.priv		= NULL,
+	.users		= 1,
+	.writers	= 1,
+	.fops		= &dvb_ca_fops,
+	.kernel_ioctl	= dvb_ca_ioctl,
+};
+
+
+int av7110_ca_register(struct av7110 *av7110)
+{
+	return dvb_register_device(&av7110->dvb_adapter, &av7110->ca_dev,
+				   &dvbdev_ca, av7110, DVB_DEVICE_CA);
+}
+
+void av7110_ca_unregister(struct av7110 *av7110)
+{
+	dvb_unregister_device(av7110->ca_dev);
+}
+
+int av7110_ca_init(struct av7110* av7110)
+{
+	return ci_ll_init(&av7110->ci_rbuffer, &av7110->ci_wbuffer, 8192);
+}
+
+void av7110_ca_exit(struct av7110* av7110)
+{
+	ci_ll_release(&av7110->ci_rbuffer, &av7110->ci_wbuffer);
+}
diff --git a/drivers/media/pci/ttpci/av7110_ca.h b/drivers/media/pci/ttpci/av7110_ca.h
new file mode 100644
index 0000000..70ee855
--- /dev/null
+++ b/drivers/media/pci/ttpci/av7110_ca.h
@@ -0,0 +1,14 @@
+#ifndef _AV7110_CA_H_
+#define _AV7110_CA_H_
+
+struct av7110;
+
+extern void CI_handle(struct av7110 *av7110, u8 *data, u16 len);
+extern void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len);
+
+extern int av7110_ca_register(struct av7110 *av7110);
+extern void av7110_ca_unregister(struct av7110 *av7110);
+extern int av7110_ca_init(struct av7110* av7110);
+extern void av7110_ca_exit(struct av7110* av7110);
+
+#endif /* _AV7110_CA_H_ */
diff --git a/drivers/media/pci/ttpci/av7110_hw.c b/drivers/media/pci/ttpci/av7110_hw.c
new file mode 100644
index 0000000..f1cbfe5
--- /dev/null
+++ b/drivers/media/pci/ttpci/av7110_hw.c
@@ -0,0 +1,1208 @@
+/*
+ * av7110_hw.c: av7110 low level hardware access and firmware interface
+ *
+ * Copyright (C) 1999-2002 Ralph  Metzler
+ *                       & Marcus Metzler for convergence integrated media GmbH
+ *
+ * originally based on code by:
+ * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ * the project's page is at http://www.linuxtv.org/ 
+ */
+
+/* for debugging ARM communication: */
+//#define COM_DEBUG
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+
+#include "av7110.h"
+#include "av7110_hw.h"
+
+#define _NOHANDSHAKE
+
+/****************************************************************************
+ * DEBI functions
+ ****************************************************************************/
+
+/* This DEBI code is based on the Stradis driver
+   by Nathan Laredo <laredo@gnu.org> */
+
+int av7110_debiwrite(struct av7110 *av7110, u32 config,
+		     int addr, u32 val, int count)
+{
+	struct saa7146_dev *dev = av7110->dev;
+
+	if (count <= 0 || count > 32764) {
+		printk("%s: invalid count %d\n", __func__, count);
+		return -1;
+	}
+	if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
+		printk("%s: wait_for_debi_done failed\n", __func__);
+		return -1;
+	}
+	saa7146_write(dev, DEBI_CONFIG, config);
+	if (count <= 4)		/* immediate transfer */
+		saa7146_write(dev, DEBI_AD, val);
+	else			/* block transfer */
+		saa7146_write(dev, DEBI_AD, av7110->debi_bus);
+	saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff));
+	saa7146_write(dev, MC2, (2 << 16) | 2);
+	return 0;
+}
+
+u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
+{
+	struct saa7146_dev *dev = av7110->dev;
+	u32 result = 0;
+
+	if (count > 32764 || count <= 0) {
+		printk("%s: invalid count %d\n", __func__, count);
+		return 0;
+	}
+	if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
+		printk("%s: wait_for_debi_done #1 failed\n", __func__);
+		return 0;
+	}
+	saa7146_write(dev, DEBI_AD, av7110->debi_bus);
+	saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
+
+	saa7146_write(dev, DEBI_CONFIG, config);
+	saa7146_write(dev, MC2, (2 << 16) | 2);
+	if (count > 4)
+		return count;
+	if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
+		printk("%s: wait_for_debi_done #2 failed\n", __func__);
+		return 0;
+	}
+
+	result = saa7146_read(dev, DEBI_AD);
+	result &= (0xffffffffUL >> ((4 - count) * 8));
+	return result;
+}
+
+
+
+/* av7110 ARM core boot stuff */
+#if 0
+void av7110_reset_arm(struct av7110 *av7110)
+{
+	saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO);
+
+	/* Disable DEBI and GPIO irq */
+	SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03);
+	SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
+
+	saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI);
+	msleep(30);	/* the firmware needs some time to initialize */
+
+	ARM_ResetMailBox(av7110);
+
+	SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
+	SAA7146_IER_ENABLE(av7110->dev, MASK_03);
+
+	av7110->arm_ready = 1;
+	dprintk(1, "reset ARM\n");
+}
+#endif  /*  0  */
+
+static int waitdebi(struct av7110 *av7110, int adr, int state)
+{
+	int k;
+
+	dprintk(4, "%p\n", av7110);
+
+	for (k = 0; k < 100; k++) {
+		if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state)
+			return 0;
+		udelay(5);
+	}
+	return -ETIMEDOUT;
+}
+
+static int load_dram(struct av7110 *av7110, u32 *data, int len)
+{
+	int i;
+	int blocks, rest;
+	u32 base, bootblock = AV7110_BOOT_BLOCK;
+
+	dprintk(4, "%p\n", av7110);
+
+	blocks = len / AV7110_BOOT_MAX_SIZE;
+	rest = len % AV7110_BOOT_MAX_SIZE;
+	base = DRAM_START_CODE;
+
+	for (i = 0; i < blocks; i++) {
+		if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
+			printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
+			return -ETIMEDOUT;
+		}
+		dprintk(4, "writing DRAM block %d\n", i);
+		mwdebi(av7110, DEBISWAB, bootblock,
+		       ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
+		bootblock ^= 0x1400;
+		iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
+		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
+		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
+		base += AV7110_BOOT_MAX_SIZE;
+	}
+
+	if (rest > 0) {
+		if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
+			printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
+			return -ETIMEDOUT;
+		}
+		if (rest > 4)
+			mwdebi(av7110, DEBISWAB, bootblock,
+			       ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest);
+		else
+			mwdebi(av7110, DEBISWAB, bootblock,
+			       ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
+
+		iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
+		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
+		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
+	}
+	if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
+		printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
+		return -ETIMEDOUT;
+	}
+	iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2);
+	iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
+	if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) {
+		printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+
+/* we cannot write av7110 DRAM directly, so load a bootloader into
+ * the DPRAM which implements a simple boot protocol */
+int av7110_bootarm(struct av7110 *av7110)
+{
+	const struct firmware *fw;
+	const char *fw_name = "av7110/bootcode.bin";
+	struct saa7146_dev *dev = av7110->dev;
+	u32 ret;
+	int i;
+
+	dprintk(4, "%p\n", av7110);
+
+	av7110->arm_ready = 0;
+
+	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
+
+	/* Disable DEBI and GPIO irq */
+	SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19);
+	SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
+
+	/* enable DEBI */
+	saa7146_write(av7110->dev, MC1, 0x08800880);
+	saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
+	saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+
+	/* test DEBI */
+	iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
+	/* FIXME: Why does Nexus CA require 2x iwdebi for first init? */
+	iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
+
+	if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) {
+		printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: "
+		       "%08x != %08x (check your BIOS 'Plug&Play OS' settings)\n",
+		       ret, 0x10325476);
+		return -1;
+	}
+	for (i = 0; i < 8192; i += 4)
+		iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4);
+	dprintk(2, "debi test OK\n");
+
+	/* boot */
+	dprintk(1, "load boot code\n");
+	saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO);
+	//saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT);
+	//saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT);
+
+	ret = request_firmware(&fw, fw_name, &dev->pci->dev);
+	if (ret) {
+		printk(KERN_ERR "dvb-ttpci: Failed to load firmware \"%s\"\n",
+			fw_name);
+		return ret;
+	}
+
+	mwdebi(av7110, DEBISWAB, DPRAM_BASE, fw->data, fw->size);
+	release_firmware(fw);
+	iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
+
+	if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
+		printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
+		       "saa7146_wait_for_debi_done() timed out\n");
+		return -ETIMEDOUT;
+	}
+	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
+	mdelay(1);
+
+	dprintk(1, "load dram code\n");
+	if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) {
+		printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
+		       "load_dram() failed\n");
+		return -1;
+	}
+
+	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
+	mdelay(1);
+
+	dprintk(1, "load dpram code\n");
+	mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
+
+	if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
+		printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
+		       "saa7146_wait_for_debi_done() timed out after loading DRAM\n");
+		return -ETIMEDOUT;
+	}
+	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
+	msleep(30);	/* the firmware needs some time to initialize */
+
+	//ARM_ClearIrq(av7110);
+	ARM_ResetMailBox(av7110);
+	SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
+	SAA7146_IER_ENABLE(av7110->dev, MASK_03);
+
+	av7110->arm_errors = 0;
+	av7110->arm_ready = 1;
+	return 0;
+}
+MODULE_FIRMWARE("av7110/bootcode.bin");
+
+/****************************************************************************
+ * DEBI command polling
+ ****************************************************************************/
+
+int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
+{
+	unsigned long start;
+	u32 stat;
+	int err;
+
+	if (FW_VERSION(av7110->arm_app) <= 0x261c) {
+		/* not supported by old firmware */
+		msleep(50);
+		return 0;
+	}
+
+	/* new firmware */
+	start = jiffies;
+	for (;;) {
+		err = time_after(jiffies, start + ARM_WAIT_FREE);
+		if (mutex_lock_interruptible(&av7110->dcomlock))
+			return -ERESTARTSYS;
+		stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
+		mutex_unlock(&av7110->dcomlock);
+		if ((stat & flags) == 0)
+			break;
+		if (err) {
+			printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
+				__func__, stat & flags);
+			return -ETIMEDOUT;
+		}
+		msleep(1);
+	}
+	return 0;
+}
+
+static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
+{
+	int i;
+	unsigned long start;
+	char *type = NULL;
+	u16 flags[2] = {0, 0};
+	u32 stat;
+	int err;
+
+//	dprintk(4, "%p\n", av7110);
+
+	if (!av7110->arm_ready) {
+		dprintk(1, "arm not ready.\n");
+		return -ENXIO;
+	}
+
+	start = jiffies;
+	while (1) {
+		err = time_after(jiffies, start + ARM_WAIT_FREE);
+		if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
+			break;
+		if (err) {
+			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __func__);
+			av7110->arm_errors++;
+			return -ETIMEDOUT;
+		}
+		msleep(1);
+	}
+
+	if (FW_VERSION(av7110->arm_app) <= 0x261f)
+		wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
+
+#ifndef _NOHANDSHAKE
+	start = jiffies;
+	while (1) {
+		err = time_after(jiffies, start + ARM_WAIT_SHAKE);
+		if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
+			break;
+		if (err) {
+			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __func__);
+			return -ETIMEDOUT;
+		}
+		msleep(1);
+	}
+#endif
+
+	switch ((buf[0] >> 8) & 0xff) {
+	case COMTYPE_PIDFILTER:
+	case COMTYPE_ENCODER:
+	case COMTYPE_REC_PLAY:
+	case COMTYPE_MPEGDECODER:
+		type = "MSG";
+		flags[0] = GPMQOver;
+		flags[1] = GPMQFull;
+		break;
+	case COMTYPE_OSD:
+		type = "OSD";
+		flags[0] = OSDQOver;
+		flags[1] = OSDQFull;
+		break;
+	case COMTYPE_MISC:
+		if (FW_VERSION(av7110->arm_app) >= 0x261d) {
+			type = "MSG";
+			flags[0] = GPMQOver;
+			flags[1] = GPMQBusy;
+		}
+		break;
+	default:
+		break;
+	}
+
+	if (type != NULL) {
+		/* non-immediate COMMAND type */
+		start = jiffies;
+		for (;;) {
+			err = time_after(jiffies, start + ARM_WAIT_FREE);
+			stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
+			if (stat & flags[0]) {
+				printk(KERN_ERR "%s: %s QUEUE overflow\n",
+					__func__, type);
+				return -1;
+			}
+			if ((stat & flags[1]) == 0)
+				break;
+			if (err) {
+				printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
+					__func__, type);
+				av7110->arm_errors++;
+				return -ETIMEDOUT;
+			}
+			msleep(1);
+		}
+	}
+
+	for (i = 2; i < length; i++)
+		wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2);
+
+	if (length)
+		wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2);
+	else
+		wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2);
+
+	wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2);
+
+	if (FW_VERSION(av7110->arm_app) <= 0x261f)
+		wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
+
+#ifdef COM_DEBUG
+	start = jiffies;
+	while (1) {
+		err = time_after(jiffies, start + ARM_WAIT_FREE);
+		if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
+			break;
+		if (err) {
+			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
+			       __func__, (buf[0] >> 8) & 0xff);
+			return -ETIMEDOUT;
+		}
+		msleep(1);
+	}
+
+	stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
+	if (stat & GPMQOver) {
+		printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __func__);
+		return -ENOSPC;
+	}
+	else if (stat & OSDQOver) {
+		printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __func__);
+		return -ENOSPC;
+	}
+#endif
+
+	return 0;
+}
+
+static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
+{
+	int ret;
+
+//	dprintk(4, "%p\n", av7110);
+
+	if (!av7110->arm_ready) {
+		dprintk(1, "arm not ready.\n");
+		return -1;
+	}
+	if (mutex_lock_interruptible(&av7110->dcomlock))
+		return -ERESTARTSYS;
+
+	ret = __av7110_send_fw_cmd(av7110, buf, length);
+	mutex_unlock(&av7110->dcomlock);
+	if (ret && ret!=-ERESTARTSYS)
+		printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
+		       __func__, ret);
+	return ret;
+}
+
+int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
+{
+	va_list args;
+	u16 buf[num + 2];
+	int i, ret;
+
+//	dprintk(4, "%p\n", av7110);
+
+	buf[0] = ((type << 8) | com);
+	buf[1] = num;
+
+	if (num) {
+		va_start(args, num);
+		for (i = 0; i < num; i++)
+			buf[i + 2] = va_arg(args, u32);
+		va_end(args);
+	}
+
+	ret = av7110_send_fw_cmd(av7110, buf, num + 2);
+	if (ret && ret != -ERESTARTSYS)
+		printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
+	return ret;
+}
+
+#if 0
+int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
+{
+	int i, ret;
+	u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom),
+		16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+	dprintk(4, "%p\n", av7110);
+
+	for(i = 0; i < len && i < 32; i++)
+	{
+		if(i % 2 == 0)
+			cmd[(i / 2) + 2] = (u16)(buf[i]) << 8;
+		else
+			cmd[(i / 2) + 2] |= buf[i];
+	}
+
+	ret = av7110_send_fw_cmd(av7110, cmd, 18);
+	if (ret && ret != -ERESTARTSYS)
+		printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
+	return ret;
+}
+#endif  /*  0  */
+
+int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
+		      int request_buf_len, u16 *reply_buf, int reply_buf_len)
+{
+	int err;
+	s16 i;
+	unsigned long start;
+#ifdef COM_DEBUG
+	u32 stat;
+#endif
+
+	dprintk(4, "%p\n", av7110);
+
+	if (!av7110->arm_ready) {
+		dprintk(1, "arm not ready.\n");
+		return -1;
+	}
+
+	if (mutex_lock_interruptible(&av7110->dcomlock))
+		return -ERESTARTSYS;
+
+	if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
+		mutex_unlock(&av7110->dcomlock);
+		printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
+		return err;
+	}
+
+	start = jiffies;
+	while (1) {
+		err = time_after(jiffies, start + ARM_WAIT_FREE);
+		if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
+			break;
+		if (err) {
+			printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __func__);
+			mutex_unlock(&av7110->dcomlock);
+			return -ETIMEDOUT;
+		}
+#ifdef _NOHANDSHAKE
+		msleep(1);
+#endif
+	}
+
+#ifndef _NOHANDSHAKE
+	start = jiffies;
+	while (1) {
+		err = time_after(jiffies, start + ARM_WAIT_SHAKE);
+		if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
+			break;
+		if (err) {
+			printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __func__);
+			mutex_unlock(&av7110->dcomlock);
+			return -ETIMEDOUT;
+		}
+		msleep(1);
+	}
+#endif
+
+#ifdef COM_DEBUG
+	stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
+	if (stat & GPMQOver) {
+		printk(KERN_ERR "%s: GPMQOver\n", __func__);
+		mutex_unlock(&av7110->dcomlock);
+		return -1;
+	}
+	else if (stat & OSDQOver) {
+		printk(KERN_ERR "%s: OSDQOver\n", __func__);
+		mutex_unlock(&av7110->dcomlock);
+		return -1;
+	}
+#endif
+
+	for (i = 0; i < reply_buf_len; i++)
+		reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
+
+	mutex_unlock(&av7110->dcomlock);
+	return 0;
+}
+
+static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
+{
+	int ret;
+	ret = av7110_fw_request(av7110, &tag, 0, buf, length);
+	if (ret)
+		printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret);
+	return ret;
+}
+
+
+/****************************************************************************
+ * Firmware commands
+ ****************************************************************************/
+
+/* get version of the firmware ROM, RTSL, video ucode and ARM application  */
+int av7110_firmversion(struct av7110 *av7110)
+{
+	u16 buf[20];
+	u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion);
+
+	dprintk(4, "%p\n", av7110);
+
+	if (av7110_fw_query(av7110, tag, buf, 16)) {
+		printk("dvb-ttpci: failed to boot firmware @ card %d\n",
+		       av7110->dvb_adapter.num);
+		return -EIO;
+	}
+
+	av7110->arm_fw = (buf[0] << 16) + buf[1];
+	av7110->arm_rtsl = (buf[2] << 16) + buf[3];
+	av7110->arm_vid = (buf[4] << 16) + buf[5];
+	av7110->arm_app = (buf[6] << 16) + buf[7];
+	av7110->avtype = (buf[8] << 16) + buf[9];
+
+	printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n",
+	       av7110->dvb_adapter.num, av7110->arm_fw,
+	       av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
+
+	/* print firmware capabilities */
+	if (FW_CI_LL_SUPPORT(av7110->arm_app))
+		printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n",
+		       av7110->dvb_adapter.num);
+	else
+		printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
+		       av7110->dvb_adapter.num);
+
+	return 0;
+}
+
+
+int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
+{
+	int i, ret;
+	u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC),
+			16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+	dprintk(4, "%p\n", av7110);
+
+	if (len > 10)
+		len = 10;
+
+	buf[1] = len + 2;
+	buf[2] = len;
+
+	if (burst != -1)
+		buf[3] = burst ? 0x01 : 0x00;
+	else
+		buf[3] = 0xffff;
+
+	for (i = 0; i < len; i++)
+		buf[i + 4] = msg[i];
+
+	ret = av7110_send_fw_cmd(av7110, buf, 18);
+	if (ret && ret!=-ERESTARTSYS)
+		printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
+	return ret;
+}
+
+
+#ifdef CONFIG_DVB_AV7110_OSD
+
+static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
+{
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
+}
+
+static inline int SetBlend_(struct av7110 *av7110, u8 windownr,
+		     enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
+{
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4,
+			     windownr, colordepth, index, blending);
+}
+
+static inline int SetColor_(struct av7110 *av7110, u8 windownr,
+		     enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo)
+{
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5,
+			     windownr, colordepth, index, colorhi, colorlo);
+}
+
+static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
+			  u16 colorfg, u16 colorbg)
+{
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4,
+			     windownr, fontsize, colorfg, colorbg);
+}
+
+static int FlushText(struct av7110 *av7110)
+{
+	unsigned long start;
+	int err;
+
+	if (mutex_lock_interruptible(&av7110->dcomlock))
+		return -ERESTARTSYS;
+	start = jiffies;
+	while (1) {
+		err = time_after(jiffies, start + ARM_WAIT_OSD);
+		if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
+			break;
+		if (err) {
+			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
+			       __func__);
+			mutex_unlock(&av7110->dcomlock);
+			return -ETIMEDOUT;
+		}
+		msleep(1);
+	}
+	mutex_unlock(&av7110->dcomlock);
+	return 0;
+}
+
+static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf)
+{
+	int i, ret;
+	unsigned long start;
+	int length = strlen(buf) + 1;
+	u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
+
+	if (mutex_lock_interruptible(&av7110->dcomlock))
+		return -ERESTARTSYS;
+
+	start = jiffies;
+	while (1) {
+		ret = time_after(jiffies, start + ARM_WAIT_OSD);
+		if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
+			break;
+		if (ret) {
+			printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
+			       __func__);
+			mutex_unlock(&av7110->dcomlock);
+			return -ETIMEDOUT;
+		}
+		msleep(1);
+	}
+#ifndef _NOHANDSHAKE
+	start = jiffies;
+	while (1) {
+		ret = time_after(jiffies, start + ARM_WAIT_SHAKE);
+		if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
+			break;
+		if (ret) {
+			printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
+			       __func__);
+			mutex_unlock(&av7110->dcomlock);
+			return -ETIMEDOUT;
+		}
+		msleep(1);
+	}
+#endif
+	for (i = 0; i < length / 2; i++)
+		wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2,
+		      swab16(*(u16 *)(buf + 2 * i)), 2);
+	if (length & 1)
+		wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
+	ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
+	mutex_unlock(&av7110->dcomlock);
+	if (ret && ret!=-ERESTARTSYS)
+		printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
+	return ret;
+}
+
+static inline int DrawLine(struct av7110 *av7110, u8 windownr,
+			   u16 x, u16 y, u16 dx, u16 dy, u16 color)
+{
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6,
+			     windownr, x, y, dx, dy, color);
+}
+
+static inline int DrawBlock(struct av7110 *av7110, u8 windownr,
+			    u16 x, u16 y, u16 dx, u16 dy, u16 color)
+{
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6,
+			     windownr, x, y, dx, dy, color);
+}
+
+static inline int HideWindow(struct av7110 *av7110, u8 windownr)
+{
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr);
+}
+
+static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
+{
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y);
+}
+
+static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
+{
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y);
+}
+
+static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
+{
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr);
+}
+
+static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
+				  osd_raw_window_t disptype,
+				  u16 width, u16 height)
+{
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4,
+			     windownr, disptype, width, height);
+}
+
+
+static enum av7110_osd_palette_type bpp2pal[8] = {
+	Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
+};
+static osd_raw_window_t bpp2bit[8] = {
+	OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
+};
+
+static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
+{
+	int ret = wait_event_timeout(av7110->bmpq,
+				av7110->bmp_state != BMP_LOADING, 10*HZ);
+	if (ret == 0) {
+		printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
+		       ret, av7110->bmp_state);
+		av7110->bmp_state = BMP_NONE;
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+static inline int LoadBitmap(struct av7110 *av7110,
+			     u16 dx, u16 dy, int inc, u8 __user * data)
+{
+	u16 format;
+	int bpp;
+	int i;
+	int d, delta;
+	u8 c;
+	int ret;
+
+	dprintk(4, "%p\n", av7110);
+
+	format = bpp2bit[av7110->osdbpp[av7110->osdwin]];
+
+	av7110->bmp_state = BMP_LOADING;
+	if	(format == OSD_BITMAP8) {
+		bpp=8; delta = 1;
+	} else if (format == OSD_BITMAP4) {
+		bpp=4; delta = 2;
+	} else if (format == OSD_BITMAP2) {
+		bpp=2; delta = 4;
+	} else if (format == OSD_BITMAP1) {
+		bpp=1; delta = 8;
+	} else {
+		av7110->bmp_state = BMP_NONE;
+		return -EINVAL;
+	}
+	av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
+	av7110->bmpp = 0;
+	if (av7110->bmplen > 32768) {
+		av7110->bmp_state = BMP_NONE;
+		return -EINVAL;
+	}
+	for (i = 0; i < dy; i++) {
+		if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
+			av7110->bmp_state = BMP_NONE;
+			return -EINVAL;
+		}
+	}
+	if (format != OSD_BITMAP8) {
+		for (i = 0; i < dx * dy / delta; i++) {
+			c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1];
+			for (d = delta - 2; d >= 0; d--) {
+				c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d]
+				      << ((delta - d - 1) * bpp));
+				((u8 *)av7110->bmpbuf)[1024 + i] = c;
+			}
+		}
+	}
+	av7110->bmplen += 1024;
+	dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
+	ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
+	if (!ret)
+		ret = WaitUntilBmpLoaded(av7110);
+	return ret;
+}
+
+static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y)
+{
+	dprintk(4, "%p\n", av7110);
+
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0);
+}
+
+static inline int ReleaseBitmap(struct av7110 *av7110)
+{
+	dprintk(4, "%p\n", av7110);
+
+	if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
+		return -1;
+	if (av7110->bmp_state == BMP_LOADING)
+		dprintk(1,"ReleaseBitmap called while BMP_LOADING\n");
+	av7110->bmp_state = BMP_NONE;
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
+}
+
+static u32 RGB2YUV(u16 R, u16 G, u16 B)
+{
+	u16 y, u, v;
+	u16 Y, Cr, Cb;
+
+	y = R * 77 + G * 150 + B * 29;	/* Luma=0.299R+0.587G+0.114B 0..65535 */
+	u = 2048 + B * 8 -(y >> 5);	/* Cr 0..4095 */
+	v = 2048 + R * 8 -(y >> 5);	/* Cb 0..4095 */
+
+	Y = y / 256;
+	Cb = u / 16;
+	Cr = v / 16;
+
+	return Cr | (Cb << 16) | (Y << 8);
+}
+
+static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
+{
+	int ret;
+
+	u16 ch, cl;
+	u32 yuv;
+
+	yuv = blend ? RGB2YUV(r,g,b) : 0;
+	cl = (yuv & 0xffff);
+	ch = ((yuv >> 16) & 0xffff);
+	ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
+			color, ch, cl);
+	if (!ret)
+		ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
+				color, ((blend >> 4) & 0x0f));
+	return ret;
+}
+
+static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
+{
+	int i;
+	int length = last - first + 1;
+
+	if (length * 4 > DATA_BUFF3_SIZE)
+		return -EINVAL;
+
+	for (i = 0; i < length; i++) {
+		u32 color, blend, yuv;
+
+		if (get_user(color, colors + i))
+			return -EFAULT;
+		blend = (color & 0xF0000000) >> 4;
+		yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
+				     (color >> 16) & 0xFF) | blend : 0;
+		yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
+		wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
+	}
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
+			    av7110->osdwin,
+			    bpp2pal[av7110->osdbpp[av7110->osdwin]],
+			    first, last);
+}
+
+static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
+		       int x1, int y1, int inc, u8 __user * data)
+{
+	uint w, h, bpp, bpl, size, lpb, bnum, brest;
+	int i;
+	int rc,release_rc;
+
+	w = x1 - x0 + 1;
+	h = y1 - y0 + 1;
+	if (inc <= 0)
+		inc = w;
+	if (w <= 0 || w > 720 || h <= 0 || h > 576)
+		return -EINVAL;
+	bpp = av7110->osdbpp[av7110->osdwin] + 1;
+	bpl = ((w * bpp + 7) & ~7) / 8;
+	size = h * bpl;
+	lpb = (32 * 1024) / bpl;
+	bnum = size / (lpb * bpl);
+	brest = size - bnum * lpb * bpl;
+
+	if (av7110->bmp_state == BMP_LOADING) {
+		/* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */
+		BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e);
+		rc = WaitUntilBmpLoaded(av7110);
+		if (rc)
+			return rc;
+		/* just continue. This should work for all fw versions
+		 * if bnum==1 && !brest && LoadBitmap was successful
+		 */
+	}
+
+	rc = 0;
+	for (i = 0; i < bnum; i++) {
+		rc = LoadBitmap(av7110, w, lpb, inc, data);
+		if (rc)
+			break;
+		rc = BlitBitmap(av7110, x0, y0 + i * lpb);
+		if (rc)
+			break;
+		data += lpb * inc;
+	}
+	if (!rc && brest) {
+		rc = LoadBitmap(av7110, w, brest / bpl, inc, data);
+		if (!rc)
+			rc = BlitBitmap(av7110, x0, y0 + bnum * lpb);
+	}
+	release_rc = ReleaseBitmap(av7110);
+	if (!rc)
+		rc = release_rc;
+	if (rc)
+		dprintk(1,"returns %d\n",rc);
+	return rc;
+}
+
+int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
+{
+	int ret;
+
+	if (mutex_lock_interruptible(&av7110->osd_mutex))
+		return -ERESTARTSYS;
+
+	switch (dc->cmd) {
+	case OSD_Close:
+		ret = DestroyOSDWindow(av7110, av7110->osdwin);
+		break;
+	case OSD_Open:
+		av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
+		ret = CreateOSDWindow(av7110, av7110->osdwin,
+				bpp2bit[av7110->osdbpp[av7110->osdwin]],
+				dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
+		if (ret)
+			break;
+		if (!dc->data) {
+			ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
+			if (ret)
+				break;
+			ret = SetColorBlend(av7110, av7110->osdwin);
+		}
+		break;
+	case OSD_Show:
+		ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0);
+		break;
+	case OSD_Hide:
+		ret = HideWindow(av7110, av7110->osdwin);
+		break;
+	case OSD_Clear:
+		ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
+		break;
+	case OSD_Fill:
+		ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
+		break;
+	case OSD_SetColor:
+		ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
+		break;
+	case OSD_SetPalette:
+		if (FW_VERSION(av7110->arm_app) >= 0x2618)
+			ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
+		else {
+			int i, len = dc->x0-dc->color+1;
+			u8 __user *colors = (u8 __user *)dc->data;
+			u8 r, g = 0, b = 0, blend = 0;
+			ret = 0;
+			for (i = 0; i<len; i++) {
+				if (get_user(r, colors + i * 4) ||
+				    get_user(g, colors + i * 4 + 1) ||
+				    get_user(b, colors + i * 4 + 2) ||
+				    get_user(blend, colors + i * 4 + 3)) {
+					ret = -EFAULT;
+					break;
+				    }
+				ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
+				if (ret)
+					break;
+			}
+		}
+		break;
+	case OSD_SetPixel:
+		ret = DrawLine(av7110, av7110->osdwin,
+			 dc->x0, dc->y0, 0, 0, dc->color);
+		break;
+	case OSD_SetRow:
+		dc->y1 = dc->y0;
+		/* fall through */
+	case OSD_SetBlock:
+		ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
+		break;
+	case OSD_FillRow:
+		ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
+			  dc->x1-dc->x0+1, dc->y1, dc->color);
+		break;
+	case OSD_FillBlock:
+		ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
+			  dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
+		break;
+	case OSD_Line:
+		ret = DrawLine(av7110, av7110->osdwin,
+			 dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
+		break;
+	case OSD_Text:
+	{
+		char textbuf[240];
+
+		if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
+			ret = -EFAULT;
+			break;
+		}
+		textbuf[239] = 0;
+		if (dc->x1 > 3)
+			dc->x1 = 3;
+		ret = SetFont(av7110, av7110->osdwin, dc->x1,
+			(u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
+		if (!ret)
+			ret = FlushText(av7110);
+		if (!ret)
+			ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
+		break;
+	}
+	case OSD_SetWindow:
+		if (dc->x0 < 1 || dc->x0 > 7)
+			ret = -EINVAL;
+		else {
+			av7110->osdwin = dc->x0;
+			ret = 0;
+		}
+		break;
+	case OSD_MoveWindow:
+		ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
+		if (!ret)
+			ret = SetColorBlend(av7110, av7110->osdwin);
+		break;
+	case OSD_OpenRaw:
+		if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
+			ret = -EINVAL;
+			break;
+		}
+		if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR)
+			av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
+		else
+			av7110->osdbpp[av7110->osdwin] = 0;
+		ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
+				dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
+		if (ret)
+			break;
+		if (!dc->data) {
+			ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
+			if (!ret)
+				ret = SetColorBlend(av7110, av7110->osdwin);
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	mutex_unlock(&av7110->osd_mutex);
+	if (ret==-ERESTARTSYS)
+		dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
+	else if (ret)
+		dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret);
+
+	return ret;
+}
+
+int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
+{
+	switch (cap->cmd) {
+	case OSD_CAP_MEMSIZE:
+		if (FW_4M_SDRAM(av7110->arm_app))
+			cap->val = 1000000;
+		else
+			cap->val = 92000;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+#endif /* CONFIG_DVB_AV7110_OSD */
diff --git a/drivers/media/pci/ttpci/av7110_hw.h b/drivers/media/pci/ttpci/av7110_hw.h
new file mode 100644
index 0000000..1634aba
--- /dev/null
+++ b/drivers/media/pci/ttpci/av7110_hw.h
@@ -0,0 +1,495 @@
+#ifndef _AV7110_HW_H_
+#define _AV7110_HW_H_
+
+#include "av7110.h"
+
+/* DEBI transfer mode defs */
+
+#define DEBINOSWAP 0x000e0000
+#define DEBISWAB   0x001e0000
+#define DEBISWAP   0x002e0000
+
+#define ARM_WAIT_FREE  (HZ)
+#define ARM_WAIT_SHAKE (HZ/5)
+#define ARM_WAIT_OSD (HZ)
+
+
+enum av7110_bootstate
+{
+	BOOTSTATE_BUFFER_EMPTY	= 0,
+	BOOTSTATE_BUFFER_FULL	= 1,
+	BOOTSTATE_AV7110_BOOT_COMPLETE	= 2
+};
+
+enum av7110_type_rec_play_format
+{	RP_None,
+	AudioPES,
+	AudioMp2,
+	AudioPCM,
+	VideoPES,
+	AV_PES
+};
+
+enum av7110_osd_palette_type
+{
+	NoPalet =  0,	   /* No palette */
+	Pal1Bit =  2,	   /* 2 colors for 1 Bit Palette    */
+	Pal2Bit =  4,	   /* 4 colors for 2 bit palette    */
+	Pal4Bit =  16,	   /* 16 colors for 4 bit palette   */
+	Pal8Bit =  256	   /* 256 colors for 16 bit palette */
+};
+
+/* switch defines */
+#define SB_GPIO 3
+#define SB_OFF	SAA7146_GPIO_OUTLO  /* SlowBlank off (TV-Mode) */
+#define SB_ON	SAA7146_GPIO_INPUT  /* SlowBlank on  (AV-Mode) */
+#define SB_WIDE SAA7146_GPIO_OUTHI  /* SlowBlank 6V  (16/9-Mode) (not implemented) */
+
+#define FB_GPIO 1
+#define FB_OFF	SAA7146_GPIO_LO     /* FastBlank off (CVBS-Mode) */
+#define FB_ON	SAA7146_GPIO_OUTHI  /* FastBlank on  (RGB-Mode) */
+#define FB_LOOP	SAA7146_GPIO_INPUT  /* FastBlank loop-through (PC graphics ???) */
+
+enum av7110_video_output_mode
+{
+	NO_OUT	     = 0,		/* disable analog output */
+	CVBS_RGB_OUT = 1,
+	CVBS_YC_OUT  = 2,
+	YC_OUT	     = 3
+};
+
+/* firmware internal msg q status: */
+#define GPMQFull	0x0001		/* Main Message Queue Full */
+#define GPMQOver	0x0002		/* Main Message Queue Overflow */
+#define HPQFull		0x0004		/* High Priority Msg Queue Full */
+#define HPQOver		0x0008
+#define OSDQFull	0x0010		/* OSD Queue Full */
+#define OSDQOver	0x0020
+#define GPMQBusy	0x0040		/* Queue not empty, FW >= 261d */
+#define HPQBusy		0x0080
+#define OSDQBusy	0x0100
+
+/* hw section filter flags */
+#define	SECTION_EIT		0x01
+#define	SECTION_SINGLE		0x00
+#define	SECTION_CYCLE		0x02
+#define	SECTION_CONTINUOS	0x04
+#define	SECTION_MODE		0x06
+#define SECTION_IPMPE		0x0C	/* size up to 4k */
+#define SECTION_HIGH_SPEED	0x1C	/* larger buffer */
+#define DATA_PIPING_FLAG	0x20	/* for Data Piping Filter */
+
+#define	PBUFSIZE_NONE 0x0000
+#define	PBUFSIZE_1P   0x0100
+#define	PBUFSIZE_2P   0x0200
+#define	PBUFSIZE_1K   0x0300
+#define	PBUFSIZE_2K   0x0400
+#define	PBUFSIZE_4K   0x0500
+#define	PBUFSIZE_8K   0x0600
+#define PBUFSIZE_16K  0x0700
+#define PBUFSIZE_32K  0x0800
+
+
+/* firmware command codes */
+enum av7110_osd_command {
+	WCreate,
+	WDestroy,
+	WMoveD,
+	WMoveA,
+	WHide,
+	WTop,
+	DBox,
+	DLine,
+	DText,
+	Set_Font,
+	SetColor,
+	SetBlend,
+	SetWBlend,
+	SetCBlend,
+	SetNonBlend,
+	LoadBmp,
+	BlitBmp,
+	ReleaseBmp,
+	SetWTrans,
+	SetWNoTrans,
+	Set_Palette
+};
+
+enum av7110_pid_command {
+	MultiPID,
+	VideoPID,
+	AudioPID,
+	InitFilt,
+	FiltError,
+	NewVersion,
+	CacheError,
+	AddPIDFilter,
+	DelPIDFilter,
+	Scan,
+	SetDescr,
+	SetIR,
+	FlushTSQueue
+};
+
+enum av7110_mpeg_command {
+	SelAudChannels
+};
+
+enum av7110_audio_command {
+	AudioDAC,
+	CabADAC,
+	ON22K,
+	OFF22K,
+	MainSwitch,
+	ADSwitch,
+	SendDiSEqC,
+	SetRegister,
+	SpdifSwitch
+};
+
+enum av7110_request_command {
+	AudioState,
+	AudioBuffState,
+	VideoState1,
+	VideoState2,
+	VideoState3,
+	CrashCounter,
+	ReqVersion,
+	ReqVCXO,
+	ReqRegister,
+	ReqSecFilterError,
+	ReqSTC
+};
+
+enum av7110_encoder_command {
+	SetVidMode,
+	SetTestMode,
+	LoadVidCode,
+	SetMonitorType,
+	SetPanScanType,
+	SetFreezeMode,
+	SetWSSConfig
+};
+
+enum av7110_rec_play_state {
+	__Record,
+	__Stop,
+	__Play,
+	__Pause,
+	__Slow,
+	__FF_IP,
+	__Scan_I,
+	__Continue
+};
+
+enum av7110_fw_cmd_misc {
+	AV7110_FW_VIDEO_ZOOM = 1,
+	AV7110_FW_VIDEO_COMMAND,
+	AV7110_FW_AUDIO_COMMAND
+};
+
+enum av7110_command_type {
+	COMTYPE_NOCOM,
+	COMTYPE_PIDFILTER,
+	COMTYPE_MPEGDECODER,
+	COMTYPE_OSD,
+	COMTYPE_BMP,
+	COMTYPE_ENCODER,
+	COMTYPE_AUDIODAC,
+	COMTYPE_REQUEST,
+	COMTYPE_SYSTEM,
+	COMTYPE_REC_PLAY,
+	COMTYPE_COMMON_IF,
+	COMTYPE_PID_FILTER,
+	COMTYPE_PES,
+	COMTYPE_TS,
+	COMTYPE_VIDEO,
+	COMTYPE_AUDIO,
+	COMTYPE_CI_LL,
+	COMTYPE_MISC = 0x80
+};
+
+#define VID_NONE_PREF		0x00	/* No aspect ration processing preferred */
+#define VID_PAN_SCAN_PREF	0x01	/* Pan and Scan Display preferred */
+#define VID_VERT_COMP_PREF	0x02	/* Vertical compression display preferred */
+#define VID_VC_AND_PS_PREF	0x03	/* PanScan and vertical Compression if allowed */
+#define VID_CENTRE_CUT_PREF	0x05	/* PanScan with zero vector */
+
+/* MPEG video decoder commands */
+#define AV_VIDEO_CMD_STOP	0x000e
+#define AV_VIDEO_CMD_PLAY	0x000d
+#define AV_VIDEO_CMD_FREEZE	0x0102
+#define AV_VIDEO_CMD_FFWD	0x0016
+#define AV_VIDEO_CMD_SLOW	0x0022
+
+/* MPEG audio decoder commands */
+#define AUDIO_CMD_MUTE		0x0001
+#define AUDIO_CMD_UNMUTE	0x0002
+#define AUDIO_CMD_PCM16		0x0010
+#define AUDIO_CMD_STEREO	0x0080
+#define AUDIO_CMD_MONO_L	0x0100
+#define AUDIO_CMD_MONO_R	0x0200
+#define AUDIO_CMD_SYNC_OFF	0x000e
+#define AUDIO_CMD_SYNC_ON	0x000f
+
+/* firmware data interface codes */
+#define DATA_NONE		 0x00
+#define DATA_FSECTION		 0x01
+#define DATA_IPMPE		 0x02
+#define DATA_MPEG_RECORD	 0x03
+#define DATA_DEBUG_MESSAGE	 0x04
+#define DATA_COMMON_INTERFACE	 0x05
+#define DATA_MPEG_PLAY		 0x06
+#define DATA_BMP_LOAD		 0x07
+#define DATA_IRCOMMAND		 0x08
+#define DATA_PIPING		 0x09
+#define DATA_STREAMING		 0x0a
+#define DATA_CI_GET		 0x0b
+#define DATA_CI_PUT		 0x0c
+#define DATA_MPEG_VIDEO_EVENT	 0x0d
+
+#define DATA_PES_RECORD		 0x10
+#define DATA_PES_PLAY		 0x11
+#define DATA_TS_RECORD		 0x12
+#define DATA_TS_PLAY		 0x13
+
+/* ancient CI command codes, only two are actually still used
+ * by the link level CI firmware */
+#define CI_CMD_ERROR		 0x00
+#define CI_CMD_ACK		 0x01
+#define CI_CMD_SYSTEM_READY	 0x02
+#define CI_CMD_KEYPRESS		 0x03
+#define CI_CMD_ON_TUNED		 0x04
+#define CI_CMD_ON_SWITCH_PROGRAM 0x05
+#define CI_CMD_SECTION_ARRIVED	 0x06
+#define CI_CMD_SECTION_TIMEOUT	 0x07
+#define CI_CMD_TIME		 0x08
+#define CI_CMD_ENTER_MENU	 0x09
+#define CI_CMD_FAST_PSI		 0x0a
+#define CI_CMD_GET_SLOT_INFO	 0x0b
+
+#define CI_MSG_NONE		 0x00
+#define CI_MSG_CI_INFO		 0x01
+#define CI_MSG_MENU		 0x02
+#define CI_MSG_LIST		 0x03
+#define CI_MSG_TEXT		 0x04
+#define CI_MSG_REQUEST_INPUT	 0x05
+#define CI_MSG_INPUT_COMPLETE	 0x06
+#define CI_MSG_LIST_MORE	 0x07
+#define CI_MSG_MENU_MORE	 0x08
+#define CI_MSG_CLOSE_MMI_IMM	 0x09
+#define CI_MSG_SECTION_REQUEST	 0x0a
+#define CI_MSG_CLOSE_FILTER	 0x0b
+#define CI_PSI_COMPLETE		 0x0c
+#define CI_MODULE_READY		 0x0d
+#define CI_SWITCH_PRG_REPLY	 0x0e
+#define CI_MSG_TEXT_MORE	 0x0f
+
+#define CI_MSG_CA_PMT		 0xe0
+#define CI_MSG_ERROR		 0xf0
+
+
+/* base address of the dual ported RAM which serves as communication
+ * area between PCI bus and av7110,
+ * as seen by the DEBI bus of the saa7146 */
+#define	DPRAM_BASE 0x4000
+
+/* boot protocol area */
+#define AV7110_BOOT_STATE	(DPRAM_BASE + 0x3F8)
+#define AV7110_BOOT_SIZE	(DPRAM_BASE + 0x3FA)
+#define AV7110_BOOT_BASE	(DPRAM_BASE + 0x3FC)
+#define AV7110_BOOT_BLOCK	(DPRAM_BASE + 0x400)
+#define AV7110_BOOT_MAX_SIZE	0xc00
+
+/* firmware command protocol area */
+#define IRQ_STATE	(DPRAM_BASE + 0x0F4)
+#define IRQ_STATE_EXT	(DPRAM_BASE + 0x0F6)
+#define MSGSTATE	(DPRAM_BASE + 0x0F8)
+#define COMMAND		(DPRAM_BASE + 0x0FC)
+#define COM_BUFF	(DPRAM_BASE + 0x100)
+#define COM_BUFF_SIZE	0x20
+
+/* various data buffers */
+#define BUFF1_BASE	(DPRAM_BASE + 0x120)
+#define BUFF1_SIZE	0xE0
+
+#define DATA_BUFF0_BASE	(DPRAM_BASE + 0x200)
+#define DATA_BUFF0_SIZE	0x0800
+
+#define DATA_BUFF1_BASE	(DATA_BUFF0_BASE+DATA_BUFF0_SIZE)
+#define DATA_BUFF1_SIZE	0x0800
+
+#define DATA_BUFF2_BASE	(DATA_BUFF1_BASE+DATA_BUFF1_SIZE)
+#define DATA_BUFF2_SIZE	0x0800
+
+#define DATA_BUFF3_BASE (DATA_BUFF2_BASE+DATA_BUFF2_SIZE)
+#define DATA_BUFF3_SIZE 0x0400
+
+#define Reserved	(DPRAM_BASE + 0x1E00)
+#define Reserved_SIZE	0x1C0
+
+
+/* firmware status area */
+#define STATUS_BASE	(DPRAM_BASE + 0x1FC0)
+#define STATUS_LOOPS	(STATUS_BASE + 0x08)
+
+#define STATUS_MPEG_WIDTH     (STATUS_BASE + 0x0C)
+/* ((aspect_ratio & 0xf) << 12) | (height & 0xfff) */
+#define STATUS_MPEG_HEIGHT_AR (STATUS_BASE + 0x0E)
+
+/* firmware data protocol area */
+#define RX_TYPE		(DPRAM_BASE + 0x1FE8)
+#define RX_LEN		(DPRAM_BASE + 0x1FEA)
+#define TX_TYPE		(DPRAM_BASE + 0x1FEC)
+#define TX_LEN		(DPRAM_BASE + 0x1FEE)
+
+#define RX_BUFF		(DPRAM_BASE + 0x1FF4)
+#define TX_BUFF		(DPRAM_BASE + 0x1FF6)
+
+#define HANDSHAKE_REG	(DPRAM_BASE + 0x1FF8)
+#define COM_IF_LOCK	(DPRAM_BASE + 0x1FFA)
+
+#define IRQ_RX		(DPRAM_BASE + 0x1FFC)
+#define IRQ_TX		(DPRAM_BASE + 0x1FFE)
+
+/* used by boot protocol to load firmware into av7110 DRAM */
+#define DRAM_START_CODE		0x2e000404
+#define DRAM_MAX_CODE_SIZE	0x00100000
+
+/* saa7146 gpio lines */
+#define RESET_LINE		2
+#define DEBI_DONE_LINE		1
+#define ARM_IRQ_LINE		0
+
+
+
+extern int av7110_bootarm(struct av7110 *av7110);
+extern int av7110_firmversion(struct av7110 *av7110);
+#define FW_CI_LL_SUPPORT(arm_app) ((arm_app) & 0x80000000)
+#define FW_4M_SDRAM(arm_app)      ((arm_app) & 0x40000000)
+#define FW_VERSION(arm_app)	  ((arm_app) & 0x0000FFFF)
+
+extern int av7110_wait_msgstate(struct av7110 *av7110, u16 flags);
+extern int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...);
+extern int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
+			     int request_buf_len, u16 *reply_buf, int reply_buf_len);
+
+
+/* DEBI (saa7146 data extension bus interface) access */
+extern int av7110_debiwrite(struct av7110 *av7110, u32 config,
+			    int addr, u32 val, int count);
+extern u32 av7110_debiread(struct av7110 *av7110, u32 config,
+			   int addr, int count);
+
+
+/* DEBI during interrupt */
+/* single word writes */
+static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count)
+{
+	av7110_debiwrite(av7110, config, addr, val, count);
+}
+
+/* buffer writes */
+static inline void mwdebi(struct av7110 *av7110, u32 config, int addr,
+			  const u8 *val, int count)
+{
+	memcpy(av7110->debi_virt, val, count);
+	av7110_debiwrite(av7110, config, addr, 0, count);
+}
+
+static inline u32 irdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count)
+{
+	u32 res;
+
+	res=av7110_debiread(av7110, config, addr, count);
+	if (count<=4)
+		memcpy(av7110->debi_virt, (char *) &res, count);
+	return res;
+}
+
+/* DEBI outside interrupts, only for count <= 4! */
+static inline void wdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&av7110->debilock, flags);
+	av7110_debiwrite(av7110, config, addr, val, count);
+	spin_unlock_irqrestore(&av7110->debilock, flags);
+}
+
+static inline u32 rdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count)
+{
+	unsigned long flags;
+	u32 res;
+
+	spin_lock_irqsave(&av7110->debilock, flags);
+	res=av7110_debiread(av7110, config, addr, count);
+	spin_unlock_irqrestore(&av7110->debilock, flags);
+	return res;
+}
+
+/* handle mailbox registers of the dual ported RAM */
+static inline void ARM_ResetMailBox(struct av7110 *av7110)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&av7110->debilock, flags);
+	av7110_debiread(av7110, DEBINOSWAP, IRQ_RX, 2);
+	av7110_debiwrite(av7110, DEBINOSWAP, IRQ_RX, 0, 2);
+	spin_unlock_irqrestore(&av7110->debilock, flags);
+}
+
+static inline void ARM_ClearMailBox(struct av7110 *av7110)
+{
+	iwdebi(av7110, DEBINOSWAP, IRQ_RX, 0, 2);
+}
+
+static inline void ARM_ClearIrq(struct av7110 *av7110)
+{
+	irdebi(av7110, DEBINOSWAP, IRQ_RX, 0, 2);
+}
+
+/****************************************************************************
+ * Firmware commands
+ ****************************************************************************/
+
+static inline int SendDAC(struct av7110 *av7110, u8 addr, u8 data)
+{
+	return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, AudioDAC, 2, addr, data);
+}
+
+static inline int av7710_set_video_mode(struct av7110 *av7110, int mode)
+{
+	return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode);
+}
+
+static inline int vidcom(struct av7110 *av7110, u32 com, u32 arg)
+{
+	return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_VIDEO_COMMAND, 4,
+			     (com>>16), (com&0xffff),
+			     (arg>>16), (arg&0xffff));
+}
+
+static inline int audcom(struct av7110 *av7110, u32 com)
+{
+	return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 2,
+			     (com>>16), (com&0xffff));
+}
+
+static inline int Set22K(struct av7110 *av7110, int state)
+{
+	return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0);
+}
+
+
+extern int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst);
+
+
+#ifdef CONFIG_DVB_AV7110_OSD
+extern int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc);
+extern int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap);
+#endif /* CONFIG_DVB_AV7110_OSD */
+
+
+
+#endif /* _AV7110_HW_H_ */
diff --git a/drivers/media/pci/ttpci/av7110_ipack.c b/drivers/media/pci/ttpci/av7110_ipack.c
new file mode 100644
index 0000000..699ef8b
--- /dev/null
+++ b/drivers/media/pci/ttpci/av7110_ipack.c
@@ -0,0 +1,403 @@
+#include "dvb_filter.h"
+#include "av7110_ipack.h"
+#include <linux/string.h>	/* for memcpy() */
+#include <linux/vmalloc.h>
+
+
+void av7110_ipack_reset(struct ipack *p)
+{
+	p->found = 0;
+	p->cid = 0;
+	p->plength = 0;
+	p->flag1 = 0;
+	p->flag2 = 0;
+	p->hlength = 0;
+	p->mpeg = 0;
+	p->check = 0;
+	p->which = 0;
+	p->done = 0;
+	p->count = 0;
+}
+
+
+int av7110_ipack_init(struct ipack *p, int size,
+		      void (*func)(u8 *buf, int size, void *priv))
+{
+	if (!(p->buf = vmalloc(size*sizeof(u8)))) {
+		printk(KERN_WARNING "Couldn't allocate memory for ipack\n");
+		return -ENOMEM;
+	}
+	p->size = size;
+	p->func = func;
+	p->repack_subids = 0;
+	av7110_ipack_reset(p);
+	return 0;
+}
+
+
+void av7110_ipack_free(struct ipack *p)
+{
+	vfree(p->buf);
+}
+
+
+static void send_ipack(struct ipack *p)
+{
+	int off;
+	struct dvb_audio_info ai;
+	int ac3_off = 0;
+	int streamid = 0;
+	int nframes = 0;
+	int f = 0;
+
+	switch (p->mpeg) {
+	case 2:
+		if (p->count < 10)
+			return;
+		p->buf[3] = p->cid;
+		p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8);
+		p->buf[5] = (u8)((p->count - 6) & 0x00ff);
+		if (p->repack_subids && p->cid == PRIVATE_STREAM1) {
+			off = 9 + p->buf[8];
+			streamid = p->buf[off];
+			if ((streamid & 0xf8) == 0x80) {
+				ai.off = 0;
+				ac3_off = ((p->buf[off + 2] << 8)|
+					   p->buf[off + 3]);
+				if (ac3_off < p->count)
+					f = dvb_filter_get_ac3info(p->buf + off + 3 + ac3_off,
+								   p->count - ac3_off, &ai, 0);
+				if (!f) {
+					nframes = (p->count - off - 3 - ac3_off) /
+						ai.framesize + 1;
+					p->buf[off + 2] = (ac3_off >> 8) & 0xff;
+					p->buf[off + 3] = (ac3_off) & 0xff;
+					p->buf[off + 1] = nframes;
+					ac3_off +=  nframes * ai.framesize - p->count;
+				}
+			}
+		}
+		p->func(p->buf, p->count, p->data);
+
+		p->buf[6] = 0x80;
+		p->buf[7] = 0x00;
+		p->buf[8] = 0x00;
+		p->count = 9;
+		if (p->repack_subids && p->cid == PRIVATE_STREAM1
+		    && (streamid & 0xf8) == 0x80) {
+			p->count += 4;
+			p->buf[9] = streamid;
+			p->buf[10] = (ac3_off >> 8) & 0xff;
+			p->buf[11] = (ac3_off) & 0xff;
+			p->buf[12] = 0;
+		}
+		break;
+
+	case 1:
+		if (p->count < 8)
+			return;
+		p->buf[3] = p->cid;
+		p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8);
+		p->buf[5] = (u8)((p->count - 6) & 0x00ff);
+		p->func(p->buf, p->count, p->data);
+
+		p->buf[6] = 0x0f;
+		p->count = 7;
+		break;
+	}
+}
+
+
+void av7110_ipack_flush(struct ipack *p)
+{
+	if (p->plength != MMAX_PLENGTH - 6 || p->found <= 6)
+		return;
+	p->plength = p->found - 6;
+	p->found = 0;
+	send_ipack(p);
+	av7110_ipack_reset(p);
+}
+
+
+static void write_ipack(struct ipack *p, const u8 *data, int count)
+{
+	u8 headr[3] = { 0x00, 0x00, 0x01 };
+
+	if (p->count < 6) {
+		memcpy(p->buf, headr, 3);
+		p->count = 6;
+	}
+
+	if (p->count + count < p->size){
+		memcpy(p->buf+p->count, data, count);
+		p->count += count;
+	} else {
+		int rest = p->size - p->count;
+		memcpy(p->buf+p->count, data, rest);
+		p->count += rest;
+		send_ipack(p);
+		if (count - rest > 0)
+			write_ipack(p, data + rest, count - rest);
+	}
+}
+
+
+int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p)
+{
+	int l;
+	int c = 0;
+
+	while (c < count && (p->mpeg == 0 ||
+			     (p->mpeg == 1 && p->found < 7) ||
+			     (p->mpeg == 2 && p->found < 9))
+	       &&  (p->found < 5 || !p->done)) {
+		switch (p->found) {
+		case 0:
+		case 1:
+			if (buf[c] == 0x00)
+				p->found++;
+			else
+				p->found = 0;
+			c++;
+			break;
+		case 2:
+			if (buf[c] == 0x01)
+				p->found++;
+			else if (buf[c] == 0)
+				p->found = 2;
+			else
+				p->found = 0;
+			c++;
+			break;
+		case 3:
+			p->cid = 0;
+			switch (buf[c]) {
+			case PROG_STREAM_MAP:
+			case PRIVATE_STREAM2:
+			case PROG_STREAM_DIR:
+			case ECM_STREAM     :
+			case EMM_STREAM     :
+			case PADDING_STREAM :
+			case DSM_CC_STREAM  :
+			case ISO13522_STREAM:
+				p->done = 1;
+				/* fall through */
+			case PRIVATE_STREAM1:
+			case VIDEO_STREAM_S ... VIDEO_STREAM_E:
+			case AUDIO_STREAM_S ... AUDIO_STREAM_E:
+				p->found++;
+				p->cid = buf[c];
+				c++;
+				break;
+			default:
+				p->found = 0;
+				break;
+			}
+			break;
+
+		case 4:
+			if (count-c > 1) {
+				p->plen[0] = buf[c];
+				c++;
+				p->plen[1] = buf[c];
+				c++;
+				p->found += 2;
+				p->plength = (p->plen[0] << 8) | p->plen[1];
+			} else {
+				p->plen[0] = buf[c];
+				p->found++;
+				return count;
+			}
+			break;
+		case 5:
+			p->plen[1] = buf[c];
+			c++;
+			p->found++;
+			p->plength = (p->plen[0] << 8) | p->plen[1];
+			break;
+		case 6:
+			if (!p->done) {
+				p->flag1 = buf[c];
+				c++;
+				p->found++;
+				if ((p->flag1 & 0xc0) == 0x80)
+					p->mpeg = 2;
+				else {
+					p->hlength = 0;
+					p->which = 0;
+					p->mpeg = 1;
+					p->flag2 = 0;
+				}
+			}
+			break;
+
+		case 7:
+			if (!p->done && p->mpeg == 2) {
+				p->flag2 = buf[c];
+				c++;
+				p->found++;
+			}
+			break;
+
+		case 8:
+			if (!p->done && p->mpeg == 2) {
+				p->hlength = buf[c];
+				c++;
+				p->found++;
+			}
+			break;
+		}
+	}
+
+	if (c == count)
+		return count;
+
+	if (!p->plength)
+		p->plength = MMAX_PLENGTH - 6;
+
+	if (p->done || ((p->mpeg == 2 && p->found >= 9) ||
+			(p->mpeg == 1 && p->found >= 7))) {
+		switch (p->cid) {
+		case AUDIO_STREAM_S ... AUDIO_STREAM_E:
+		case VIDEO_STREAM_S ... VIDEO_STREAM_E:
+		case PRIVATE_STREAM1:
+			if (p->mpeg == 2 && p->found == 9) {
+				write_ipack(p, &p->flag1, 1);
+				write_ipack(p, &p->flag2, 1);
+				write_ipack(p, &p->hlength, 1);
+			}
+
+			if (p->mpeg == 1 && p->found == 7)
+				write_ipack(p, &p->flag1, 1);
+
+			if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) &&
+			    p->found < 14) {
+				while (c < count && p->found < 14) {
+					p->pts[p->found - 9] = buf[c];
+					write_ipack(p, buf + c, 1);
+					c++;
+					p->found++;
+				}
+				if (c == count)
+					return count;
+			}
+
+			if (p->mpeg == 1 && p->which < 2000) {
+
+				if (p->found == 7) {
+					p->check = p->flag1;
+					p->hlength = 1;
+				}
+
+				while (!p->which && c < count &&
+				       p->check == 0xff){
+					p->check = buf[c];
+					write_ipack(p, buf + c, 1);
+					c++;
+					p->found++;
+					p->hlength++;
+				}
+
+				if (c == count)
+					return count;
+
+				if ((p->check & 0xc0) == 0x40 && !p->which) {
+					p->check = buf[c];
+					write_ipack(p, buf + c, 1);
+					c++;
+					p->found++;
+					p->hlength++;
+
+					p->which = 1;
+					if (c == count)
+						return count;
+					p->check = buf[c];
+					write_ipack(p, buf + c, 1);
+					c++;
+					p->found++;
+					p->hlength++;
+					p->which = 2;
+					if (c == count)
+						return count;
+				}
+
+				if (p->which == 1) {
+					p->check = buf[c];
+					write_ipack(p, buf + c, 1);
+					c++;
+					p->found++;
+					p->hlength++;
+					p->which = 2;
+					if (c == count)
+						return count;
+				}
+
+				if ((p->check & 0x30) && p->check != 0xff) {
+					p->flag2 = (p->check & 0xf0) << 2;
+					p->pts[0] = p->check;
+					p->which = 3;
+				}
+
+				if (c == count)
+					return count;
+				if (p->which > 2){
+					if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY) {
+						while (c < count && p->which < 7) {
+							p->pts[p->which - 2] = buf[c];
+							write_ipack(p, buf + c, 1);
+							c++;
+							p->found++;
+							p->which++;
+							p->hlength++;
+						}
+						if (c == count)
+							return count;
+					} else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS) {
+						while (c < count && p->which < 12) {
+							if (p->which < 7)
+								p->pts[p->which - 2] = buf[c];
+							write_ipack(p, buf + c, 1);
+							c++;
+							p->found++;
+							p->which++;
+							p->hlength++;
+						}
+						if (c == count)
+							return count;
+					}
+					p->which = 2000;
+				}
+
+			}
+
+			while (c < count && p->found < p->plength + 6) {
+				l = count - c;
+				if (l + p->found > p->plength + 6)
+					l = p->plength + 6 - p->found;
+				write_ipack(p, buf + c, l);
+				p->found += l;
+				c += l;
+			}
+			break;
+		}
+
+
+		if (p->done) {
+			if (p->found + count - c < p->plength + 6) {
+				p->found += count - c;
+				c = count;
+			} else {
+				c += p->plength + 6 - p->found;
+				p->found = p->plength + 6;
+			}
+		}
+
+		if (p->plength && p->found == p->plength + 6) {
+			send_ipack(p);
+			av7110_ipack_reset(p);
+			if (c < count)
+				av7110_ipack_instant_repack(buf + c, count - c, p);
+		}
+	}
+	return count;
+}
diff --git a/drivers/media/pci/ttpci/av7110_ipack.h b/drivers/media/pci/ttpci/av7110_ipack.h
new file mode 100644
index 0000000..becf94d
--- /dev/null
+++ b/drivers/media/pci/ttpci/av7110_ipack.h
@@ -0,0 +1,12 @@
+#ifndef _AV7110_IPACK_H_
+#define _AV7110_IPACK_H_
+
+extern int av7110_ipack_init(struct ipack *p, int size,
+			     void (*func)(u8 *buf,  int size, void *priv));
+
+extern void av7110_ipack_reset(struct ipack *p);
+extern int  av7110_ipack_instant_repack(const u8 *buf, int count, struct ipack *p);
+extern void av7110_ipack_free(struct ipack * p);
+extern void av7110_ipack_flush(struct ipack *p);
+
+#endif
diff --git a/drivers/media/pci/ttpci/av7110_ir.c b/drivers/media/pci/ttpci/av7110_ir.c
new file mode 100644
index 0000000..908f272
--- /dev/null
+++ b/drivers/media/pci/ttpci/av7110_ir.c
@@ -0,0 +1,415 @@
+/*
+ * Driver for the remote control of SAA7146 based AV7110 cards
+ *
+ * Copyright (C) 1999-2003 Holger Waechtler <holger@convergence.de>
+ * Copyright (C) 2003-2007 Oliver Endriss <o.endriss@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+
+#include "av7110.h"
+#include "av7110_hw.h"
+
+
+#define AV_CNT		4
+
+#define IR_RC5		0
+#define IR_RCMM		1
+#define IR_RC5_EXT	2 /* internal only */
+
+#define IR_ALL		0xffffffff
+
+#define UP_TIMEOUT	(HZ*7/25)
+
+
+/* Note: enable ir debugging by or'ing debug with 16 */
+
+static int ir_protocol[AV_CNT] = { IR_RCMM, IR_RCMM, IR_RCMM, IR_RCMM};
+module_param_array(ir_protocol, int, NULL, 0644);
+MODULE_PARM_DESC(ir_protocol, "Infrared protocol: 0 RC5, 1 RCMM (default)");
+
+static int ir_inversion[AV_CNT];
+module_param_array(ir_inversion, int, NULL, 0644);
+MODULE_PARM_DESC(ir_inversion, "Inversion of infrared signal: 0 not inverted (default), 1 inverted");
+
+static uint ir_device_mask[AV_CNT] = { IR_ALL, IR_ALL, IR_ALL, IR_ALL };
+module_param_array(ir_device_mask, uint, NULL, 0644);
+MODULE_PARM_DESC(ir_device_mask, "Bitmask of infrared devices: bit 0..31 = device 0..31 (default: all)");
+
+
+static int av_cnt;
+static struct av7110 *av_list[AV_CNT];
+
+static u16 default_key_map [256] = {
+	KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
+	KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO,
+	KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	KEY_CHANNELUP, KEY_CHANNELDOWN, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, KEY_TEXT, 0, 0, KEY_TV, 0, 0, 0, 0, 0, KEY_SETUP, 0, 0,
+	0, 0, 0, KEY_SUBTITLE, 0, 0, KEY_LANGUAGE, 0,
+	KEY_RADIO, 0, 0, 0, 0, KEY_EXIT, 0, 0,
+	KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_OK, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RED, KEY_GREEN, KEY_YELLOW,
+	KEY_BLUE, 0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_LIST, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, KEY_UP, KEY_UP, KEY_DOWN, KEY_DOWN,
+	0, 0, 0, 0, KEY_EPG, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_VCR
+};
+
+
+/* key-up timer */
+static void av7110_emit_keyup(unsigned long parm)
+{
+	struct infrared *ir = (struct infrared *) parm;
+
+	if (!ir || !test_bit(ir->last_key, ir->input_dev->key))
+		return;
+
+	input_report_key(ir->input_dev, ir->last_key, 0);
+	input_sync(ir->input_dev);
+}
+
+
+/* tasklet */
+static void av7110_emit_key(unsigned long parm)
+{
+	struct infrared *ir = (struct infrared *) parm;
+	u32 ircom = ir->ir_command;
+	u8 data;
+	u8 addr;
+	u16 toggle;
+	u16 keycode;
+
+	/* extract device address and data */
+	switch (ir->protocol) {
+	case IR_RC5: /* RC5: 5 bits device address, 6 bits data */
+		data = ircom & 0x3f;
+		addr = (ircom >> 6) & 0x1f;
+		toggle = ircom & 0x0800;
+		break;
+
+	case IR_RCMM: /* RCMM: ? bits device address, ? bits data */
+		data = ircom & 0xff;
+		addr = (ircom >> 8) & 0x1f;
+		toggle = ircom & 0x8000;
+		break;
+
+	case IR_RC5_EXT: /* extended RC5: 5 bits device address, 7 bits data */
+		data = ircom & 0x3f;
+		addr = (ircom >> 6) & 0x1f;
+		/* invert 7th data bit for backward compatibility with RC5 keymaps */
+		if (!(ircom & 0x1000))
+			data |= 0x40;
+		toggle = ircom & 0x0800;
+		break;
+
+	default:
+		printk("%s invalid protocol %x\n", __func__, ir->protocol);
+		return;
+	}
+
+	input_event(ir->input_dev, EV_MSC, MSC_RAW, (addr << 16) | data);
+	input_event(ir->input_dev, EV_MSC, MSC_SCAN, data);
+
+	keycode = ir->key_map[data];
+
+	dprintk(16, "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n",
+		__func__, ircom, addr, data, keycode);
+
+	/* check device address */
+	if (!(ir->device_mask & (1 << addr)))
+		return;
+
+	if (!keycode) {
+		printk ("%s: code %08x -> addr %i data 0x%02x -> unknown key!\n",
+			__func__, ircom, addr, data);
+		return;
+	}
+
+	if (timer_pending(&ir->keyup_timer)) {
+		del_timer(&ir->keyup_timer);
+		if (ir->last_key != keycode || toggle != ir->last_toggle) {
+			ir->delay_timer_finished = 0;
+			input_event(ir->input_dev, EV_KEY, ir->last_key, 0);
+			input_event(ir->input_dev, EV_KEY, keycode, 1);
+			input_sync(ir->input_dev);
+		} else if (ir->delay_timer_finished) {
+			input_event(ir->input_dev, EV_KEY, keycode, 2);
+			input_sync(ir->input_dev);
+		}
+	} else {
+		ir->delay_timer_finished = 0;
+		input_event(ir->input_dev, EV_KEY, keycode, 1);
+		input_sync(ir->input_dev);
+	}
+
+	ir->last_key = keycode;
+	ir->last_toggle = toggle;
+
+	ir->keyup_timer.expires = jiffies + UP_TIMEOUT;
+	add_timer(&ir->keyup_timer);
+
+}
+
+
+/* register with input layer */
+static void input_register_keys(struct infrared *ir)
+{
+	int i;
+
+	set_bit(EV_KEY, ir->input_dev->evbit);
+	set_bit(EV_REP, ir->input_dev->evbit);
+	set_bit(EV_MSC, ir->input_dev->evbit);
+
+	set_bit(MSC_RAW, ir->input_dev->mscbit);
+	set_bit(MSC_SCAN, ir->input_dev->mscbit);
+
+	memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit));
+
+	for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) {
+		if (ir->key_map[i] > KEY_MAX)
+			ir->key_map[i] = 0;
+		else if (ir->key_map[i] > KEY_RESERVED)
+			set_bit(ir->key_map[i], ir->input_dev->keybit);
+	}
+
+	ir->input_dev->keycode = ir->key_map;
+	ir->input_dev->keycodesize = sizeof(ir->key_map[0]);
+	ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map);
+}
+
+
+/* called by the input driver after rep[REP_DELAY] ms */
+static void input_repeat_key(unsigned long parm)
+{
+	struct infrared *ir = (struct infrared *) parm;
+
+	ir->delay_timer_finished = 1;
+}
+
+
+/* check for configuration changes */
+int av7110_check_ir_config(struct av7110 *av7110, int force)
+{
+	int i;
+	int modified = force;
+	int ret = -ENODEV;
+
+	for (i = 0; i < av_cnt; i++)
+		if (av7110 == av_list[i])
+			break;
+
+	if (i < av_cnt && av7110) {
+		if ((av7110->ir.protocol & 1) != ir_protocol[i] ||
+		    av7110->ir.inversion != ir_inversion[i])
+			modified = true;
+
+		if (modified) {
+			/* protocol */
+			if (ir_protocol[i]) {
+				ir_protocol[i] = 1;
+				av7110->ir.protocol = IR_RCMM;
+				av7110->ir.ir_config = 0x0001;
+			} else if (FW_VERSION(av7110->arm_app) >= 0x2620) {
+				av7110->ir.protocol = IR_RC5_EXT;
+				av7110->ir.ir_config = 0x0002;
+			} else {
+				av7110->ir.protocol = IR_RC5;
+				av7110->ir.ir_config = 0x0000;
+			}
+			/* inversion */
+			if (ir_inversion[i]) {
+				ir_inversion[i] = 1;
+				av7110->ir.ir_config |= 0x8000;
+			}
+			av7110->ir.inversion = ir_inversion[i];
+			/* update ARM */
+			ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1,
+						av7110->ir.ir_config);
+		} else
+			ret = 0;
+
+		/* address */
+		if (av7110->ir.device_mask != ir_device_mask[i])
+			av7110->ir.device_mask = ir_device_mask[i];
+	}
+
+	return ret;
+}
+
+
+/* /proc/av7110_ir interface */
+static ssize_t av7110_ir_proc_write(struct file *file, const char __user *buffer,
+				    size_t count, loff_t *pos)
+{
+	char *page;
+	u32 ir_config;
+	int size = sizeof ir_config + sizeof av_list[0]->ir.key_map;
+	int i;
+
+	if (count < size)
+		return -EINVAL;
+
+	page = vmalloc(size);
+	if (!page)
+		return -ENOMEM;
+
+	if (copy_from_user(page, buffer, size)) {
+		vfree(page);
+		return -EFAULT;
+	}
+
+	memcpy(&ir_config, page, sizeof ir_config);
+
+	for (i = 0; i < av_cnt; i++) {
+		/* keymap */
+		memcpy(av_list[i]->ir.key_map, page + sizeof ir_config,
+			sizeof(av_list[i]->ir.key_map));
+		/* protocol, inversion, address */
+		ir_protocol[i] = ir_config & 0x0001;
+		ir_inversion[i] = ir_config & 0x8000 ? 1 : 0;
+		if (ir_config & 0x4000)
+			ir_device_mask[i] = 1 << ((ir_config >> 16) & 0x1f);
+		else
+			ir_device_mask[i] = IR_ALL;
+		/* update configuration */
+		av7110_check_ir_config(av_list[i], false);
+		input_register_keys(&av_list[i]->ir);
+	}
+	vfree(page);
+	return count;
+}
+
+static const struct file_operations av7110_ir_proc_fops = {
+	.owner		= THIS_MODULE,
+	.write		= av7110_ir_proc_write,
+	.llseek		= noop_llseek,
+};
+
+/* interrupt handler */
+static void ir_handler(struct av7110 *av7110, u32 ircom)
+{
+	dprintk(4, "ir command = %08x\n", ircom);
+	av7110->ir.ir_command = ircom;
+	tasklet_schedule(&av7110->ir.ir_tasklet);
+}
+
+
+int __devinit av7110_ir_init(struct av7110 *av7110)
+{
+	struct input_dev *input_dev;
+	static struct proc_dir_entry *e;
+	int err;
+
+	if (av_cnt >= ARRAY_SIZE(av_list))
+		return -ENOSPC;
+
+	av_list[av_cnt++] = av7110;
+	av7110_check_ir_config(av7110, true);
+
+	init_timer(&av7110->ir.keyup_timer);
+	av7110->ir.keyup_timer.function = av7110_emit_keyup;
+	av7110->ir.keyup_timer.data = (unsigned long) &av7110->ir;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		return -ENOMEM;
+
+	av7110->ir.input_dev = input_dev;
+	snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys),
+		"pci-%s/ir0", pci_name(av7110->dev->pci));
+
+	input_dev->name = "DVB on-card IR receiver";
+
+	input_dev->phys = av7110->ir.input_phys;
+	input_dev->id.bustype = BUS_PCI;
+	input_dev->id.version = 2;
+	if (av7110->dev->pci->subsystem_vendor) {
+		input_dev->id.vendor = av7110->dev->pci->subsystem_vendor;
+		input_dev->id.product = av7110->dev->pci->subsystem_device;
+	} else {
+		input_dev->id.vendor = av7110->dev->pci->vendor;
+		input_dev->id.product = av7110->dev->pci->device;
+	}
+	input_dev->dev.parent = &av7110->dev->pci->dev;
+	/* initial keymap */
+	memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map);
+	input_register_keys(&av7110->ir);
+	err = input_register_device(input_dev);
+	if (err) {
+		input_free_device(input_dev);
+		return err;
+	}
+	input_dev->timer.function = input_repeat_key;
+	input_dev->timer.data = (unsigned long) &av7110->ir;
+
+	if (av_cnt == 1) {
+		e = proc_create("av7110_ir", S_IWUSR, NULL, &av7110_ir_proc_fops);
+		if (e)
+			e->size = 4 + 256 * sizeof(u16);
+	}
+
+	tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir);
+	av7110->ir.ir_handler = ir_handler;
+
+	return 0;
+}
+
+
+void __devexit av7110_ir_exit(struct av7110 *av7110)
+{
+	int i;
+
+	if (av_cnt == 0)
+		return;
+
+	del_timer_sync(&av7110->ir.keyup_timer);
+	av7110->ir.ir_handler = NULL;
+	tasklet_kill(&av7110->ir.ir_tasklet);
+
+	for (i = 0; i < av_cnt; i++)
+		if (av_list[i] == av7110) {
+			av_list[i] = av_list[av_cnt-1];
+			av_list[av_cnt-1] = NULL;
+			break;
+		}
+
+	if (av_cnt == 1)
+		remove_proc_entry("av7110_ir", NULL);
+
+	input_unregister_device(av7110->ir.input_dev);
+
+	av_cnt--;
+}
+
+//MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>, Oliver Endriss <o.endriss@gmx.de>");
+//MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/ttpci/av7110_v4l.c b/drivers/media/pci/ttpci/av7110_v4l.c
new file mode 100644
index 0000000..1b2d151
--- /dev/null
+++ b/drivers/media/pci/ttpci/av7110_v4l.c
@@ -0,0 +1,966 @@
+/*
+ * av7110_v4l.c: av7110 video4linux interface for DVB and Siemens DVB-C analog module
+ *
+ * Copyright (C) 1999-2002 Ralph  Metzler
+ *                       & Marcus Metzler for convergence integrated media GmbH
+ *
+ * originally based on code by:
+ * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ * the project's page is at http://www.linuxtv.org/ 
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/timer.h>
+#include <linux/poll.h>
+
+#include "av7110.h"
+#include "av7110_hw.h"
+#include "av7110_av.h"
+
+int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val)
+{
+	u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff };
+	struct i2c_msg msgs = { .flags = 0, .len = 5, .buf = msg };
+
+	switch (av7110->adac_type) {
+	case DVB_ADAC_MSP34x0:
+		msgs.addr = 0x40;
+		break;
+	case DVB_ADAC_MSP34x5:
+		msgs.addr = 0x42;
+		break;
+	default:
+		return 0;
+	}
+
+	if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) {
+		dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n",
+		       av7110->dvb_adapter.num, reg, val);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val)
+{
+	u8 msg1[3] = { dev, reg >> 8, reg & 0xff };
+	u8 msg2[2];
+	struct i2c_msg msgs[2] = {
+		{ .flags = 0	   , .len = 3, .buf = msg1 },
+		{ .flags = I2C_M_RD, .len = 2, .buf = msg2 }
+	};
+
+	switch (av7110->adac_type) {
+	case DVB_ADAC_MSP34x0:
+		msgs[0].addr = 0x40;
+		msgs[1].addr = 0x40;
+		break;
+	case DVB_ADAC_MSP34x5:
+		msgs[0].addr = 0x42;
+		msgs[1].addr = 0x42;
+		break;
+	default:
+		return 0;
+	}
+
+	if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) {
+		dprintk(1, "dvb-ttpci: failed @ card %d, %u\n",
+		       av7110->dvb_adapter.num, reg);
+		return -EIO;
+	}
+	*val = (msg2[0] << 8) | msg2[1];
+	return 0;
+}
+
+static struct v4l2_input inputs[4] = {
+	{
+		.index		= 0,
+		.name		= "DVB",
+		.type		= V4L2_INPUT_TYPE_CAMERA,
+		.audioset	= 1,
+		.tuner		= 0, /* ignored */
+		.std		= V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
+		.status		= 0,
+		.capabilities	= V4L2_IN_CAP_STD,
+	}, {
+		.index		= 1,
+		.name		= "Television",
+		.type		= V4L2_INPUT_TYPE_TUNER,
+		.audioset	= 1,
+		.tuner		= 0,
+		.std		= V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
+		.status		= 0,
+		.capabilities	= V4L2_IN_CAP_STD,
+	}, {
+		.index		= 2,
+		.name		= "Video",
+		.type		= V4L2_INPUT_TYPE_CAMERA,
+		.audioset	= 0,
+		.tuner		= 0,
+		.std		= V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
+		.status		= 0,
+		.capabilities	= V4L2_IN_CAP_STD,
+	}, {
+		.index		= 3,
+		.name		= "Y/C",
+		.type		= V4L2_INPUT_TYPE_CAMERA,
+		.audioset	= 0,
+		.tuner		= 0,
+		.std		= V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
+		.status		= 0,
+		.capabilities	= V4L2_IN_CAP_STD,
+	}
+};
+
+static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
+{
+	struct av7110 *av7110 = dev->ext_priv;
+	u8 buf[] = { 0x00, reg, data };
+	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
+
+	dprintk(4, "dev: %p\n", dev);
+
+	if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
+		return -1;
+	return 0;
+}
+
+static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4])
+{
+	struct av7110 *av7110 = dev->ext_priv;
+	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
+
+	dprintk(4, "dev: %p\n", dev);
+
+	if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
+		return -1;
+	return 0;
+}
+
+static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq)
+{
+	u32 div;
+	u8 config;
+	u8 buf[4];
+
+	dprintk(4, "freq: 0x%08x\n", freq);
+
+	/* magic number: 614. tuning with the frequency given by v4l2
+	   is always off by 614*62.5 = 38375 kHz...*/
+	div = freq + 614;
+
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = 0x8e;
+
+	if (freq < (u32) (16 * 168.25))
+		config = 0xa0;
+	else if (freq < (u32) (16 * 447.25))
+		config = 0x90;
+	else
+		config = 0x30;
+	config &= ~0x02;
+
+	buf[3] = config;
+
+	return tuner_write(dev, 0x61, buf);
+}
+
+static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq)
+{
+	struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
+	u32 div;
+	u8 data[4];
+
+	div = (freq + 38900000 + 31250) / 62500;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0xce;
+
+	if (freq < 45000000)
+		return -EINVAL;
+	else if (freq < 137000000)
+		data[3] = 0x01;
+	else if (freq < 403000000)
+		data[3] = 0x02;
+	else if (freq < 860000000)
+		data[3] = 0x04;
+	else
+		return -EINVAL;
+
+	if (av7110->fe->ops.i2c_gate_ctrl)
+		av7110->fe->ops.i2c_gate_ctrl(av7110->fe, 1);
+	return tuner_write(dev, 0x63, data);
+}
+
+
+
+static struct saa7146_standard analog_standard[];
+static struct saa7146_standard dvb_standard[];
+static struct saa7146_standard standard[];
+
+static struct v4l2_audio msp3400_v4l2_audio = {
+	.index = 0,
+	.name = "Television",
+	.capability = V4L2_AUDCAP_STEREO
+};
+
+static int av7110_dvb_c_switch(struct saa7146_fh *fh)
+{
+	struct saa7146_dev *dev = fh->dev;
+	struct saa7146_vv *vv = dev->vv_data;
+	struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
+	u16 adswitch;
+	int source, sync, err;
+
+	dprintk(4, "%p\n", av7110);
+
+	if ((vv->video_status & STATUS_OVERLAY) != 0) {
+		vv->ov_suspend = vv->video_fh;
+		err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
+		if (err != 0) {
+			dprintk(2, "suspending video failed\n");
+			vv->ov_suspend = NULL;
+		}
+	}
+
+	if (0 != av7110->current_input) {
+		dprintk(1, "switching to analog TV:\n");
+		adswitch = 1;
+		source = SAA7146_HPS_SOURCE_PORT_B;
+		sync = SAA7146_HPS_SYNC_PORT_B;
+		memcpy(standard, analog_standard, sizeof(struct saa7146_standard) * 2);
+
+		switch (av7110->current_input) {
+		case 1:
+			dprintk(1, "switching SAA7113 to Analog Tuner Input\n");
+			msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source
+			msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source
+			msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source
+			msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono
+			msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone
+			msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume
+
+			if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
+				if (ves1820_writereg(dev, 0x09, 0x0f, 0x60))
+					dprintk(1, "setting band in demodulator failed\n");
+			} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
+				saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9819 pin9(STD)
+				saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9819 pin30(VIF)
+			}
+			if (i2c_writereg(av7110, 0x48, 0x02, 0xd0) != 1)
+				dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
+			break;
+		case 2:
+			dprintk(1, "switching SAA7113 to Video AV CVBS Input\n");
+			if (i2c_writereg(av7110, 0x48, 0x02, 0xd2) != 1)
+				dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
+			break;
+		case 3:
+			dprintk(1, "switching SAA7113 to Video AV Y/C Input\n");
+			if (i2c_writereg(av7110, 0x48, 0x02, 0xd9) != 1)
+				dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
+			break;
+		default:
+			dprintk(1, "switching SAA7113 to Input: AV7110: SAA7113: invalid input\n");
+		}
+	} else {
+		adswitch = 0;
+		source = SAA7146_HPS_SOURCE_PORT_A;
+		sync = SAA7146_HPS_SYNC_PORT_A;
+		memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2);
+		dprintk(1, "switching DVB mode\n");
+		msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source
+		msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source
+		msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source
+		msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono
+		msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
+		msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume
+
+		if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
+			if (ves1820_writereg(dev, 0x09, 0x0f, 0x20))
+				dprintk(1, "setting band in demodulator failed\n");
+		} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
+			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
+			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
+		}
+	}
+
+	/* hmm, this does not do anything!? */
+	if (av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, adswitch))
+		dprintk(1, "ADSwitch error\n");
+
+	saa7146_set_hps_source_and_sync(dev, source, sync);
+
+	if (vv->ov_suspend != NULL) {
+		saa7146_start_preview(vv->ov_suspend);
+		vv->ov_suspend = NULL;
+	}
+
+	return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+	u16 stereo_det;
+	s8 stereo;
+
+	dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index);
+
+	if (!av7110->analog_tuner_flags || t->index != 0)
+		return -EINVAL;
+
+	memset(t, 0, sizeof(*t));
+	strcpy((char *)t->name, "Television");
+
+	t->type = V4L2_TUNER_ANALOG_TV;
+	t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
+		V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+	t->rangelow = 772;	/* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
+	t->rangehigh = 13684;	/* 855.25 MHz / 62.5 kHz = 13684 */
+	/* FIXME: add the real signal strength here */
+	t->signal = 0xffff;
+	t->afc = 0;
+
+	/* FIXME: standard / stereo detection is still broken */
+	msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det);
+	dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
+	msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det);
+	dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det);
+	stereo = (s8)(stereo_det >> 8);
+	if (stereo > 0x10) {
+		/* stereo */
+		t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
+		t->audmode = V4L2_TUNER_MODE_STEREO;
+	} else if (stereo < -0x10) {
+		/* bilingual */
+		t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+		t->audmode = V4L2_TUNER_MODE_LANG1;
+	} else /* mono */
+		t->rxsubchans = V4L2_TUNER_SUB_MONO;
+
+	return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+	u16 fm_matrix, src;
+	dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index);
+
+	if (!av7110->analog_tuner_flags || av7110->current_input != 1)
+		return -EINVAL;
+
+	switch (t->audmode) {
+	case V4L2_TUNER_MODE_STEREO:
+		dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n");
+		fm_matrix = 0x3001; /* stereo */
+		src = 0x0020;
+		break;
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+		dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n");
+		fm_matrix = 0x3000; /* bilingual */
+		src = 0x0020;
+		break;
+	case V4L2_TUNER_MODE_LANG1:
+		dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n");
+		fm_matrix = 0x3000; /* mono */
+		src = 0x0000;
+		break;
+	case V4L2_TUNER_MODE_LANG2:
+		dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n");
+		fm_matrix = 0x3000; /* mono */
+		src = 0x0010;
+		break;
+	default: /* case V4L2_TUNER_MODE_MONO: */
+		dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n");
+		fm_matrix = 0x3000; /* mono */
+		src = 0x0030;
+		break;
+	}
+	msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix);
+	msp_writereg(av7110, MSP_WR_DSP, 0x0008, src);
+	msp_writereg(av7110, MSP_WR_DSP, 0x0009, src);
+	msp_writereg(av7110, MSP_WR_DSP, 0x000a, src);
+	return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+	dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x\n", f->frequency);
+
+	if (!av7110->analog_tuner_flags || av7110->current_input != 1)
+		return -EINVAL;
+
+	memset(f, 0, sizeof(*f));
+	f->type = V4L2_TUNER_ANALOG_TV;
+	f->frequency =	av7110->current_freq;
+	return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+	dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x\n", f->frequency);
+
+	if (!av7110->analog_tuner_flags || av7110->current_input != 1)
+		return -EINVAL;
+
+	if (V4L2_TUNER_ANALOG_TV != f->type)
+		return -EINVAL;
+
+	msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); /* fast mute */
+	msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0);
+
+	/* tune in desired frequency */
+	if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820)
+		ves1820_set_tv_freq(dev, f->frequency);
+	else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297)
+		stv0297_set_tv_freq(dev, f->frequency);
+	av7110->current_freq = f->frequency;
+
+	msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); /* start stereo detection */
+	msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000);
+	msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); /* loudspeaker + headphone */
+	msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); /* SCART 1 volume */
+	return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+	dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
+
+	if (av7110->analog_tuner_flags) {
+		if (i->index >= 4)
+			return -EINVAL;
+	} else {
+		if (i->index != 0)
+			return -EINVAL;
+	}
+
+	memcpy(i, &inputs[i->index], sizeof(struct v4l2_input));
+
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+	*input = av7110->current_input;
+	dprintk(2, "VIDIOC_G_INPUT: %d\n", *input);
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+	dprintk(2, "VIDIOC_S_INPUT: %d\n", input);
+
+	if (!av7110->analog_tuner_flags)
+		return input ? -EINVAL : 0;
+
+	if (input >= 4)
+		return -EINVAL;
+
+	av7110->current_input = input;
+	return av7110_dvb_c_switch(fh);
+}
+
+static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+	dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
+	if (a->index != 0)
+		return -EINVAL;
+	*a = msp3400_v4l2_audio;
+	return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+	dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
+	if (a->index != 0)
+		return -EINVAL;
+	if (av7110->current_input >= 2)
+		return -EINVAL;
+	*a = msp3400_v4l2_audio;
+	return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+	dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
+	if (av7110->current_input >= 2)
+		return -EINVAL;
+	return a->index ? -EINVAL : 0;
+}
+
+static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh,
+					struct v4l2_sliced_vbi_cap *cap)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+	dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
+	if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
+		return -EINVAL;
+	if (FW_VERSION(av7110->arm_app) >= 0x2623) {
+		cap->service_set = V4L2_SLICED_WSS_625;
+		cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
+	}
+	return 0;
+}
+
+static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh,
+					struct v4l2_format *f)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+	dprintk(2, "VIDIOC_G_FMT:\n");
+	if (FW_VERSION(av7110->arm_app) < 0x2623)
+		return -EINVAL;
+	memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+	if (av7110->wssMode) {
+		f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
+		f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+		f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data);
+	}
+	return 0;
+}
+
+static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh,
+					struct v4l2_format *f)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+	dprintk(2, "VIDIOC_S_FMT\n");
+	if (FW_VERSION(av7110->arm_app) < 0x2623)
+		return -EINVAL;
+	if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
+	    f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
+		memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
+		/* WSS controlled by firmware */
+		av7110->wssMode = 0;
+		av7110->wssData = 0;
+		return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
+				     SetWSSConfig, 1, 0);
+	} else {
+		memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
+		f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
+		f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+		f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data);
+		/* WSS controlled by userspace */
+		av7110->wssMode = 1;
+		av7110->wssData = 0;
+	}
+	return 0;
+}
+
+static int av7110_vbi_reset(struct file *file)
+{
+	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_dev *dev = fh->dev;
+	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+
+	dprintk(2, "%s\n", __func__);
+	av7110->wssMode = 0;
+	av7110->wssData = 0;
+	if (FW_VERSION(av7110->arm_app) < 0x2623)
+		return 0;
+	else
+		return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
+}
+
+static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
+{
+	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_dev *dev = fh->dev;
+	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+	struct v4l2_sliced_vbi_data d;
+	int rc;
+
+	dprintk(2, "%s\n", __func__);
+	if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d)
+		return -EINVAL;
+	if (copy_from_user(&d, data, count))
+		return -EFAULT;
+	if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23)
+		return -EINVAL;
+	if (d.id)
+		av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0];
+	else
+		av7110->wssData = 0x8000;
+	rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 1, av7110->wssData);
+	return (rc < 0) ? rc : count;
+}
+
+/****************************************************************************
+ * INITIALIZATION
+ ****************************************************************************/
+
+static u8 saa7113_init_regs[] = {
+	0x02, 0xd0,
+	0x03, 0x23,
+	0x04, 0x00,
+	0x05, 0x00,
+	0x06, 0xe9,
+	0x07, 0x0d,
+	0x08, 0x98,
+	0x09, 0x02,
+	0x0a, 0x80,
+	0x0b, 0x40,
+	0x0c, 0x40,
+	0x0d, 0x00,
+	0x0e, 0x01,
+	0x0f, 0x7c,
+	0x10, 0x48,
+	0x11, 0x0c,
+	0x12, 0x8b,
+	0x13, 0x1a,
+	0x14, 0x00,
+	0x15, 0x00,
+	0x16, 0x00,
+	0x17, 0x00,
+	0x18, 0x00,
+	0x19, 0x00,
+	0x1a, 0x00,
+	0x1b, 0x00,
+	0x1c, 0x00,
+	0x1d, 0x00,
+	0x1e, 0x00,
+
+	0x41, 0x77,
+	0x42, 0x77,
+	0x43, 0x77,
+	0x44, 0x77,
+	0x45, 0x77,
+	0x46, 0x77,
+	0x47, 0x77,
+	0x48, 0x77,
+	0x49, 0x77,
+	0x4a, 0x77,
+	0x4b, 0x77,
+	0x4c, 0x77,
+	0x4d, 0x77,
+	0x4e, 0x77,
+	0x4f, 0x77,
+	0x50, 0x77,
+	0x51, 0x77,
+	0x52, 0x77,
+	0x53, 0x77,
+	0x54, 0x77,
+	0x55, 0x77,
+	0x56, 0x77,
+	0x57, 0xff,
+
+	0xff
+};
+
+
+static struct saa7146_ext_vv av7110_vv_data_st;
+static struct saa7146_ext_vv av7110_vv_data_c;
+
+int av7110_init_analog_module(struct av7110 *av7110)
+{
+	u16 version1, version2;
+
+	if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 &&
+	    i2c_writereg(av7110, 0x80, 0x0, 0) == 1) {
+		pr_info("DVB-C analog module @ card %d detected, initializing MSP3400\n",
+			av7110->dvb_adapter.num);
+		av7110->adac_type = DVB_ADAC_MSP34x0;
+	} else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 &&
+		   i2c_writereg(av7110, 0x84, 0x0, 0) == 1) {
+		pr_info("DVB-C analog module @ card %d detected, initializing MSP3415\n",
+			av7110->dvb_adapter.num);
+		av7110->adac_type = DVB_ADAC_MSP34x5;
+	} else
+		return -ENODEV;
+
+	msleep(100); // the probing above resets the msp...
+	msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
+	msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
+	dprintk(1, "dvb-ttpci: @ card %d MSP34xx version 0x%04x 0x%04x\n",
+		av7110->dvb_adapter.num, version1, version2);
+	msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00);
+	msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
+	msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source
+	msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source
+	msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume
+	msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source
+	msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume
+	msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART
+
+	if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) {
+		pr_info("saa7113 not accessible\n");
+	} else {
+		u8 *i = saa7113_init_regs;
+
+		if ((av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) {
+			/* Fujitsu/Siemens DVB-Cable */
+			av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820;
+		} else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x0002)) {
+			/* Hauppauge/TT DVB-C premium */
+			av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820;
+		} else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x000A)) {
+			/* Hauppauge/TT DVB-C premium */
+			av7110->analog_tuner_flags |= ANALOG_TUNER_STV0297;
+		}
+
+		/* setup for DVB by default */
+		if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
+			if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20))
+				dprintk(1, "setting band in demodulator failed\n");
+		} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
+			saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
+			saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
+		}
+
+		/* init the saa7113 */
+		while (*i != 0xff) {
+			if (i2c_writereg(av7110, 0x48, i[0], i[1]) != 1) {
+				dprintk(1, "saa7113 initialization failed @ card %d", av7110->dvb_adapter.num);
+				break;
+			}
+			i += 2;
+		}
+		/* setup msp for analog sound: B/G Dual-FM */
+		msp_writereg(av7110, MSP_WR_DEM, 0x00bb, 0x02d0); // AD_CV
+		msp_writereg(av7110, MSP_WR_DEM, 0x0001,  3); // FIR1
+		msp_writereg(av7110, MSP_WR_DEM, 0x0001, 18); // FIR1
+		msp_writereg(av7110, MSP_WR_DEM, 0x0001, 27); // FIR1
+		msp_writereg(av7110, MSP_WR_DEM, 0x0001, 48); // FIR1
+		msp_writereg(av7110, MSP_WR_DEM, 0x0001, 66); // FIR1
+		msp_writereg(av7110, MSP_WR_DEM, 0x0001, 72); // FIR1
+		msp_writereg(av7110, MSP_WR_DEM, 0x0005,  4); // FIR2
+		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 64); // FIR2
+		msp_writereg(av7110, MSP_WR_DEM, 0x0005,  0); // FIR2
+		msp_writereg(av7110, MSP_WR_DEM, 0x0005,  3); // FIR2
+		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 18); // FIR2
+		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 27); // FIR2
+		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 48); // FIR2
+		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 66); // FIR2
+		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 72); // FIR2
+		msp_writereg(av7110, MSP_WR_DEM, 0x0083, 0xa000); // MODE_REG
+		msp_writereg(av7110, MSP_WR_DEM, 0x0093, 0x00aa); // DCO1_LO 5.74MHz
+		msp_writereg(av7110, MSP_WR_DEM, 0x009b, 0x04fc); // DCO1_HI
+		msp_writereg(av7110, MSP_WR_DEM, 0x00a3, 0x038e); // DCO2_LO 5.5MHz
+		msp_writereg(av7110, MSP_WR_DEM, 0x00ab, 0x04c6); // DCO2_HI
+		msp_writereg(av7110, MSP_WR_DEM, 0x0056, 0); // LOAD_REG 1/2
+	}
+
+	memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2);
+	/* set dd1 stream a & b */
+	saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
+	saa7146_write(av7110->dev, DD1_INIT, 0x03000700);
+	saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+
+	return 0;
+}
+
+int av7110_init_v4l(struct av7110 *av7110)
+{
+	struct saa7146_dev* dev = av7110->dev;
+	struct saa7146_ext_vv *vv_data;
+	int ret;
+
+	/* special case DVB-C: these cards have an analog tuner
+	   plus need some special handling, so we have separate
+	   saa7146_ext_vv data for these... */
+	if (av7110->analog_tuner_flags)
+		vv_data = &av7110_vv_data_c;
+	else
+		vv_data = &av7110_vv_data_st;
+	ret = saa7146_vv_init(dev, vv_data);
+
+	if (ret) {
+		ERR("cannot init capture device. skipping\n");
+		return -ENODEV;
+	}
+	vv_data->vid_ops.vidioc_enum_input = vidioc_enum_input;
+	vv_data->vid_ops.vidioc_g_input = vidioc_g_input;
+	vv_data->vid_ops.vidioc_s_input = vidioc_s_input;
+	vv_data->vid_ops.vidioc_g_tuner = vidioc_g_tuner;
+	vv_data->vid_ops.vidioc_s_tuner = vidioc_s_tuner;
+	vv_data->vid_ops.vidioc_g_frequency = vidioc_g_frequency;
+	vv_data->vid_ops.vidioc_s_frequency = vidioc_s_frequency;
+	vv_data->vid_ops.vidioc_enumaudio = vidioc_enumaudio;
+	vv_data->vid_ops.vidioc_g_audio = vidioc_g_audio;
+	vv_data->vid_ops.vidioc_s_audio = vidioc_s_audio;
+	vv_data->vid_ops.vidioc_g_fmt_vbi_cap = NULL;
+
+	vv_data->vbi_ops.vidioc_g_tuner = vidioc_g_tuner;
+	vv_data->vbi_ops.vidioc_s_tuner = vidioc_s_tuner;
+	vv_data->vbi_ops.vidioc_g_frequency = vidioc_g_frequency;
+	vv_data->vbi_ops.vidioc_s_frequency = vidioc_s_frequency;
+	vv_data->vbi_ops.vidioc_g_fmt_vbi_cap = NULL;
+	vv_data->vbi_ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap;
+	vv_data->vbi_ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out;
+	vv_data->vbi_ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out;
+
+	if (FW_VERSION(av7110->arm_app) < 0x2623)
+		vv_data->capabilities &= ~V4L2_CAP_SLICED_VBI_OUTPUT;
+
+	if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) {
+		ERR("cannot register capture device. skipping\n");
+		saa7146_vv_release(dev);
+		return -ENODEV;
+	}
+	if (FW_VERSION(av7110->arm_app) >= 0x2623) {
+		if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI))
+			ERR("cannot register vbi v4l2 device. skipping\n");
+	}
+	return 0;
+}
+
+int av7110_exit_v4l(struct av7110 *av7110)
+{
+	struct saa7146_dev* dev = av7110->dev;
+
+	saa7146_unregister_device(&av7110->v4l_dev, av7110->dev);
+	saa7146_unregister_device(&av7110->vbi_dev, av7110->dev);
+
+	saa7146_vv_release(dev);
+
+	return 0;
+}
+
+
+
+/* FIXME: these values are experimental values that look better than the
+   values from the latest "official" driver -- at least for me... (MiHu) */
+static struct saa7146_standard standard[] = {
+	{
+		.name	= "PAL",	.id		= V4L2_STD_PAL_BG,
+		.v_offset	= 0x15,	.v_field	= 288,
+		.h_offset	= 0x48,	.h_pixels	= 708,
+		.v_max_out	= 576,	.h_max_out	= 768,
+	}, {
+		.name	= "NTSC",	.id		= V4L2_STD_NTSC,
+		.v_offset	= 0x10,	.v_field	= 244,
+		.h_offset	= 0x40,	.h_pixels	= 708,
+		.v_max_out	= 480,	.h_max_out	= 640,
+	}
+};
+
+static struct saa7146_standard analog_standard[] = {
+	{
+		.name	= "PAL",	.id		= V4L2_STD_PAL_BG,
+		.v_offset	= 0x1b,	.v_field	= 288,
+		.h_offset	= 0x08,	.h_pixels	= 708,
+		.v_max_out	= 576,	.h_max_out	= 768,
+	}, {
+		.name	= "NTSC",	.id		= V4L2_STD_NTSC,
+		.v_offset	= 0x10,	.v_field	= 244,
+		.h_offset	= 0x40,	.h_pixels	= 708,
+		.v_max_out	= 480,	.h_max_out	= 640,
+	}
+};
+
+static struct saa7146_standard dvb_standard[] = {
+	{
+		.name	= "PAL",	.id		= V4L2_STD_PAL_BG,
+		.v_offset	= 0x14,	.v_field	= 288,
+		.h_offset	= 0x48,	.h_pixels	= 708,
+		.v_max_out	= 576,	.h_max_out	= 768,
+	}, {
+		.name	= "NTSC",	.id		= V4L2_STD_NTSC,
+		.v_offset	= 0x10,	.v_field	= 244,
+		.h_offset	= 0x40,	.h_pixels	= 708,
+		.v_max_out	= 480,	.h_max_out	= 640,
+	}
+};
+
+static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
+{
+	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+
+	if (std->id & V4L2_STD_PAL) {
+		av7110->vidmode = AV7110_VIDEO_MODE_PAL;
+		av7110_set_vidmode(av7110, av7110->vidmode);
+	}
+	else if (std->id & V4L2_STD_NTSC) {
+		av7110->vidmode = AV7110_VIDEO_MODE_NTSC;
+		av7110_set_vidmode(av7110, av7110->vidmode);
+	}
+	else
+		return -1;
+
+	return 0;
+}
+
+
+static struct saa7146_ext_vv av7110_vv_data_st = {
+	.inputs		= 1,
+	.audios		= 1,
+	.capabilities	= V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO,
+	.flags		= 0,
+
+	.stds		= &standard[0],
+	.num_stds	= ARRAY_SIZE(standard),
+	.std_callback	= &std_callback,
+
+	.vbi_fops.open	= av7110_vbi_reset,
+	.vbi_fops.release = av7110_vbi_reset,
+	.vbi_fops.write	= av7110_vbi_write,
+};
+
+static struct saa7146_ext_vv av7110_vv_data_c = {
+	.inputs		= 1,
+	.audios		= 1,
+	.capabilities	= V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO,
+	.flags		= SAA7146_USE_PORT_B_FOR_VBI,
+
+	.stds		= &standard[0],
+	.num_stds	= ARRAY_SIZE(standard),
+	.std_callback	= &std_callback,
+
+	.vbi_fops.open	= av7110_vbi_reset,
+	.vbi_fops.release = av7110_vbi_reset,
+	.vbi_fops.write	= av7110_vbi_write,
+};
+
diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c
new file mode 100644
index 0000000..12ddb53
--- /dev/null
+++ b/drivers/media/pci/ttpci/budget-av.c
@@ -0,0 +1,1640 @@
+/*
+ * budget-av.c: driver for the SAA7146 based Budget DVB cards
+ *              with analog video in
+ *
+ * Compiled from various sources by Michael Hunold <michael@mihu.de>
+ *
+ * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> &
+ *                               Andrew de Quincey <adq_dvb@lidskialf.net>
+ *
+ * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
+ *
+ * Copyright (C) 1999-2002 Ralph  Metzler
+ *                       & Marcus Metzler for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org/ 
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "budget.h"
+#include "stv0299.h"
+#include "stb0899_drv.h"
+#include "stb0899_reg.h"
+#include "stb0899_cfg.h"
+#include "tda8261.h"
+#include "tda8261_cfg.h"
+#include "tda1002x.h"
+#include "tda1004x.h"
+#include "tua6100.h"
+#include "dvb-pll.h"
+#include <media/saa7146_vv.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/spinlock.h>
+
+#include "dvb_ca_en50221.h"
+
+#define DEBICICAM		0x02420000
+
+#define SLOTSTATUS_NONE         1
+#define SLOTSTATUS_PRESENT      2
+#define SLOTSTATUS_RESET        4
+#define SLOTSTATUS_READY        8
+#define SLOTSTATUS_OCCUPIED     (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct budget_av {
+	struct budget budget;
+	struct video_device *vd;
+	int cur_input;
+	int has_saa7113;
+	struct tasklet_struct ciintf_irq_tasklet;
+	int slot_status;
+	struct dvb_ca_en50221 ca;
+	u8 reinitialise_demod:1;
+};
+
+static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot);
+
+
+/* GPIO Connections:
+ * 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*!
+ * 1 - CI memory select 0=>IO memory, 1=>Attribute Memory
+ * 2 - CI Card Enable (Active Low)
+ * 3 - CI Card Detect
+ */
+
+/****************************************************************************
+ * INITIALIZATION
+ ****************************************************************************/
+
+static u8 i2c_readreg(struct i2c_adapter *i2c, u8 id, u8 reg)
+{
+	u8 mm1[] = { 0x00 };
+	u8 mm2[] = { 0x00 };
+	struct i2c_msg msgs[2];
+
+	msgs[0].flags = 0;
+	msgs[1].flags = I2C_M_RD;
+	msgs[0].addr = msgs[1].addr = id / 2;
+	mm1[0] = reg;
+	msgs[0].len = 1;
+	msgs[1].len = 1;
+	msgs[0].buf = mm1;
+	msgs[1].buf = mm2;
+
+	i2c_transfer(i2c, msgs, 2);
+
+	return mm2[0];
+}
+
+static int i2c_readregs(struct i2c_adapter *i2c, u8 id, u8 reg, u8 * buf, u8 len)
+{
+	u8 mm1[] = { reg };
+	struct i2c_msg msgs[2] = {
+		{.addr = id / 2,.flags = 0,.buf = mm1,.len = 1},
+		{.addr = id / 2,.flags = I2C_M_RD,.buf = buf,.len = len}
+	};
+
+	if (i2c_transfer(i2c, msgs, 2) != 2)
+		return -EIO;
+
+	return 0;
+}
+
+static int i2c_writereg(struct i2c_adapter *i2c, u8 id, u8 reg, u8 val)
+{
+	u8 msg[2] = { reg, val };
+	struct i2c_msg msgs;
+
+	msgs.flags = 0;
+	msgs.addr = id / 2;
+	msgs.len = 2;
+	msgs.buf = msg;
+	return i2c_transfer(i2c, &msgs, 1);
+}
+
+static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
+{
+	struct budget_av *budget_av = (struct budget_av *) ca->data;
+	int result;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
+	udelay(1);
+
+	result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1);
+	if (result == -ETIMEDOUT) {
+		ciintf_slot_shutdown(ca, slot);
+		pr_info("cam ejected 1\n");
+	}
+	return result;
+}
+
+static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
+{
+	struct budget_av *budget_av = (struct budget_av *) ca->data;
+	int result;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
+	udelay(1);
+
+	result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1);
+	if (result == -ETIMEDOUT) {
+		ciintf_slot_shutdown(ca, slot);
+		pr_info("cam ejected 2\n");
+	}
+	return result;
+}
+
+static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
+{
+	struct budget_av *budget_av = (struct budget_av *) ca->data;
+	int result;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+	udelay(1);
+
+	result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0);
+	if (result == -ETIMEDOUT) {
+		ciintf_slot_shutdown(ca, slot);
+		pr_info("cam ejected 3\n");
+		return -ETIMEDOUT;
+	}
+	return result;
+}
+
+static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
+{
+	struct budget_av *budget_av = (struct budget_av *) ca->data;
+	int result;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+	udelay(1);
+
+	result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0);
+	if (result == -ETIMEDOUT) {
+		ciintf_slot_shutdown(ca, slot);
+		pr_info("cam ejected 5\n");
+	}
+	return result;
+}
+
+static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct budget_av *budget_av = (struct budget_av *) ca->data;
+	struct saa7146_dev *saa = budget_av->budget.dev;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	dprintk(1, "ciintf_slot_reset\n");
+	budget_av->slot_status = SLOTSTATUS_RESET;
+
+	saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
+
+	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */
+	msleep(2);
+	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); /* Vcc on */
+	msleep(20); /* 20 ms Vcc settling time */
+
+	saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */
+	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
+	msleep(20);
+
+	/* reinitialise the frontend if necessary */
+	if (budget_av->reinitialise_demod)
+		dvb_frontend_reinitialise(budget_av->budget.dvb_frontend);
+
+	return 0;
+}
+
+static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct budget_av *budget_av = (struct budget_av *) ca->data;
+	struct saa7146_dev *saa = budget_av->budget.dev;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	dprintk(1, "ciintf_slot_shutdown\n");
+
+	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
+	budget_av->slot_status = SLOTSTATUS_NONE;
+
+	return 0;
+}
+
+static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct budget_av *budget_av = (struct budget_av *) ca->data;
+	struct saa7146_dev *saa = budget_av->budget.dev;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status);
+
+	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
+
+	return 0;
+}
+
+static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
+{
+	struct budget_av *budget_av = (struct budget_av *) ca->data;
+	struct saa7146_dev *saa = budget_av->budget.dev;
+	int result;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	/* test the card detect line - needs to be done carefully
+	 * since it never goes high for some CAMs on this interface (e.g. topuptv) */
+	if (budget_av->slot_status == SLOTSTATUS_NONE) {
+		saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
+		udelay(1);
+		if (saa7146_read(saa, PSR) & MASK_06) {
+			if (budget_av->slot_status == SLOTSTATUS_NONE) {
+				budget_av->slot_status = SLOTSTATUS_PRESENT;
+				pr_info("cam inserted A\n");
+			}
+		}
+		saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+	}
+
+	/* We also try and read from IO memory to work round the above detection bug. If
+	 * there is no CAM, we will get a timeout. Only done if there is no cam
+	 * present, since this test actually breaks some cams :(
+	 *
+	 * if the CI interface is not open, we also do the above test since we
+	 * don't care if the cam has problems - we'll be resetting it on open() anyway */
+	if ((budget_av->slot_status == SLOTSTATUS_NONE) || (!open)) {
+		saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+		result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1);
+		if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) {
+			budget_av->slot_status = SLOTSTATUS_PRESENT;
+			pr_info("cam inserted B\n");
+		} else if (result < 0) {
+			if (budget_av->slot_status != SLOTSTATUS_NONE) {
+				ciintf_slot_shutdown(ca, slot);
+				pr_info("cam ejected 5\n");
+				return 0;
+			}
+		}
+	}
+
+	/* read from attribute memory in reset/ready state to know when the CAM is ready */
+	if (budget_av->slot_status == SLOTSTATUS_RESET) {
+		result = ciintf_read_attribute_mem(ca, slot, 0);
+		if (result == 0x1d) {
+			budget_av->slot_status = SLOTSTATUS_READY;
+		}
+	}
+
+	/* work out correct return code */
+	if (budget_av->slot_status != SLOTSTATUS_NONE) {
+		if (budget_av->slot_status & SLOTSTATUS_READY) {
+			return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
+		}
+		return DVB_CA_EN50221_POLL_CAM_PRESENT;
+	}
+	return 0;
+}
+
+static int ciintf_init(struct budget_av *budget_av)
+{
+	struct saa7146_dev *saa = budget_av->budget.dev;
+	int result;
+
+	memset(&budget_av->ca, 0, sizeof(struct dvb_ca_en50221));
+
+	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
+	saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
+	saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO);
+	saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+
+	/* Enable DEBI pins */
+	saa7146_write(saa, MC1, MASK_27 | MASK_11);
+
+	/* register CI interface */
+	budget_av->ca.owner = THIS_MODULE;
+	budget_av->ca.read_attribute_mem = ciintf_read_attribute_mem;
+	budget_av->ca.write_attribute_mem = ciintf_write_attribute_mem;
+	budget_av->ca.read_cam_control = ciintf_read_cam_control;
+	budget_av->ca.write_cam_control = ciintf_write_cam_control;
+	budget_av->ca.slot_reset = ciintf_slot_reset;
+	budget_av->ca.slot_shutdown = ciintf_slot_shutdown;
+	budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable;
+	budget_av->ca.poll_slot_status = ciintf_poll_slot_status;
+	budget_av->ca.data = budget_av;
+	budget_av->budget.ci_present = 1;
+	budget_av->slot_status = SLOTSTATUS_NONE;
+
+	if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter,
+					  &budget_av->ca, 0, 1)) != 0) {
+		pr_err("ci initialisation failed\n");
+		goto error;
+	}
+
+	pr_info("ci interface initialised\n");
+	return 0;
+
+error:
+	saa7146_write(saa, MC1, MASK_27);
+	return result;
+}
+
+static void ciintf_deinit(struct budget_av *budget_av)
+{
+	struct saa7146_dev *saa = budget_av->budget.dev;
+
+	saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
+	saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
+	saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
+	saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
+
+	/* release the CA device */
+	dvb_ca_en50221_release(&budget_av->ca);
+
+	/* disable DEBI pins */
+	saa7146_write(saa, MC1, MASK_27);
+}
+
+
+static const u8 saa7113_tab[] = {
+	0x01, 0x08,
+	0x02, 0xc0,
+	0x03, 0x33,
+	0x04, 0x00,
+	0x05, 0x00,
+	0x06, 0xeb,
+	0x07, 0xe0,
+	0x08, 0x28,
+	0x09, 0x00,
+	0x0a, 0x80,
+	0x0b, 0x47,
+	0x0c, 0x40,
+	0x0d, 0x00,
+	0x0e, 0x01,
+	0x0f, 0x44,
+
+	0x10, 0x08,
+	0x11, 0x0c,
+	0x12, 0x7b,
+	0x13, 0x00,
+	0x15, 0x00, 0x16, 0x00, 0x17, 0x00,
+
+	0x57, 0xff,
+	0x40, 0x82, 0x58, 0x00, 0x59, 0x54, 0x5a, 0x07,
+	0x5b, 0x83, 0x5e, 0x00,
+	0xff
+};
+
+static int saa7113_init(struct budget_av *budget_av)
+{
+	struct budget *budget = &budget_av->budget;
+	struct saa7146_dev *saa = budget->dev;
+	const u8 *data = saa7113_tab;
+
+	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI);
+	msleep(200);
+
+	if (i2c_writereg(&budget->i2c_adap, 0x4a, 0x01, 0x08) != 1) {
+		dprintk(1, "saa7113 not found on KNC card\n");
+		return -ENODEV;
+	}
+
+	dprintk(1, "saa7113 detected and initializing\n");
+
+	while (*data != 0xff) {
+		i2c_writereg(&budget->i2c_adap, 0x4a, *data, *(data + 1));
+		data += 2;
+	}
+
+	dprintk(1, "saa7113  status=%02x\n", i2c_readreg(&budget->i2c_adap, 0x4a, 0x1f));
+
+	return 0;
+}
+
+static int saa7113_setinput(struct budget_av *budget_av, int input)
+{
+	struct budget *budget = &budget_av->budget;
+
+	if (1 != budget_av->has_saa7113)
+		return -ENODEV;
+
+	if (input == 1) {
+		i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc7);
+		i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x80);
+	} else if (input == 0) {
+		i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc0);
+		i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x00);
+	} else
+		return -EINVAL;
+
+	budget_av->cur_input = input;
+	return 0;
+}
+
+
+static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
+{
+	u8 aclk = 0;
+	u8 bclk = 0;
+	u8 m1;
+
+	aclk = 0xb5;
+	if (srate < 2000000)
+		bclk = 0x86;
+	else if (srate < 5000000)
+		bclk = 0x89;
+	else if (srate < 15000000)
+		bclk = 0x8f;
+	else if (srate < 45000000)
+		bclk = 0x95;
+
+	m1 = 0x14;
+	if (srate < 4000000)
+		m1 = 0x10;
+
+	stv0299_writereg(fe, 0x13, aclk);
+	stv0299_writereg(fe, 0x14, bclk);
+	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+	stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+	stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
+	stv0299_writereg(fe, 0x0f, 0x80 | m1);
+
+	return 0;
+}
+
+static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 div;
+	u8 buf[4];
+	struct budget *budget = (struct budget *) fe->dvb->priv;
+	struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
+
+	if ((c->frequency < 950000) || (c->frequency > 2150000))
+		return -EINVAL;
+
+	div = (c->frequency + (125 - 1)) / 125;	/* round correctly */
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+	buf[3] = 0x20;
+
+	if (c->symbol_rate < 4000000)
+		buf[3] |= 1;
+
+	if (c->frequency < 1250000)
+		buf[3] |= 0;
+	else if (c->frequency < 1550000)
+		buf[3] |= 0x40;
+	else if (c->frequency < 2050000)
+		buf[3] |= 0x80;
+	else if (c->frequency < 2150000)
+		buf[3] |= 0xC0;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static u8 typhoon_cinergy1200s_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x30,
+	0x03, 0x00,
+	0x04, 0x7d,		/* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+	0x05, 0x35,		/* I2CT = 0, SCLT = 1, SDAT = 1 */
+	0x06, 0x40,		/* DAC not used, set to high impendance mode */
+	0x07, 0x00,		/* DAC LSB */
+	0x08, 0x40,		/* DiSEqC off */
+	0x09, 0x00,		/* FIFO */
+	0x0c, 0x51,		/* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+	0x0d, 0x82,		/* DC offset compensation = ON, beta_agc1 = 2 */
+	0x0e, 0x23,		/* alpha_tmg = 2, beta_tmg = 3 */
+	0x10, 0x3f,		// AGC2  0x3d
+	0x11, 0x84,
+	0x12, 0xb9,
+	0x15, 0xc9,		// lock detector threshold
+	0x16, 0x00,
+	0x17, 0x00,
+	0x18, 0x00,
+	0x19, 0x00,
+	0x1a, 0x00,
+	0x1f, 0x50,
+	0x20, 0x00,
+	0x21, 0x00,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x28, 0x00,		// out imp: normal  out type: parallel FEC mode:0
+	0x29, 0x1e,		// 1/2 threshold
+	0x2a, 0x14,		// 2/3 threshold
+	0x2b, 0x0f,		// 3/4 threshold
+	0x2c, 0x09,		// 5/6 threshold
+	0x2d, 0x05,		// 7/8 threshold
+	0x2e, 0x01,
+	0x31, 0x1f,		// test all FECs
+	0x32, 0x19,		// viterbi and synchro search
+	0x33, 0xfc,		// rs control
+	0x34, 0x93,		// error control
+	0x0f, 0x92,
+	0xff, 0xff
+};
+
+static struct stv0299_config typhoon_config = {
+	.demod_address = 0x68,
+	.inittab = typhoon_cinergy1200s_inittab,
+	.mclk = 88000000UL,
+	.invert = 0,
+	.skip_reinit = 0,
+	.lock_output = STV0299_LOCKOUTPUT_1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP0,
+	.min_delay_ms = 100,
+	.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
+};
+
+
+static struct stv0299_config cinergy_1200s_config = {
+	.demod_address = 0x68,
+	.inittab = typhoon_cinergy1200s_inittab,
+	.mclk = 88000000UL,
+	.invert = 0,
+	.skip_reinit = 0,
+	.lock_output = STV0299_LOCKOUTPUT_0,
+	.volt13_op0_op1 = STV0299_VOLT13_OP0,
+	.min_delay_ms = 100,
+	.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
+};
+
+static struct stv0299_config cinergy_1200s_1894_0010_config = {
+	.demod_address = 0x68,
+	.inittab = typhoon_cinergy1200s_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.skip_reinit = 0,
+	.lock_output = STV0299_LOCKOUTPUT_1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP0,
+	.min_delay_ms = 100,
+	.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
+};
+
+static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct budget *budget = (struct budget *) fe->dvb->priv;
+	u8 buf[6];
+	struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
+	int i;
+
+#define CU1216_IF 36125000
+#define TUNER_MUL 62500
+
+	u32 div = (c->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
+
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = 0xce;
+	buf[3] = (c->frequency < 150000000 ? 0x01 :
+		  c->frequency < 445000000 ? 0x02 : 0x04);
+	buf[4] = 0xde;
+	buf[5] = 0x20;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+
+	/* wait for the pll lock */
+	msg.flags = I2C_M_RD;
+	msg.len = 1;
+	for (i = 0; i < 20; i++) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		if (i2c_transfer(&budget->i2c_adap, &msg, 1) == 1 && (buf[0] & 0x40))
+			break;
+		msleep(10);
+	}
+
+	/* switch the charge pump to the lower current */
+	msg.flags = 0;
+	msg.len = 2;
+	msg.buf = &buf[2];
+	buf[2] &= ~0x40;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+
+	return 0;
+}
+
+static struct tda1002x_config philips_cu1216_config = {
+	.demod_address = 0x0c,
+	.invert = 1,
+};
+
+static struct tda1002x_config philips_cu1216_config_altaddress = {
+	.demod_address = 0x0d,
+	.invert = 0,
+};
+
+static struct tda10023_config philips_cu1216_tda10023_config = {
+	.demod_address = 0x0c,
+	.invert = 1,
+};
+
+static int philips_tu1216_tuner_init(struct dvb_frontend *fe)
+{
+	struct budget *budget = (struct budget *) fe->dvb->priv;
+	static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+	struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
+
+	// setup PLL configuration
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
+		return -EIO;
+	msleep(1);
+
+	return 0;
+}
+
+static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct budget *budget = (struct budget *) fe->dvb->priv;
+	u8 tuner_buf[4];
+	struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len =
+			sizeof(tuner_buf) };
+	int tuner_frequency = 0;
+	u8 band, cp, filter;
+
+	// determine charge pump
+	tuner_frequency = c->frequency + 36166000;
+	if (tuner_frequency < 87000000)
+		return -EINVAL;
+	else if (tuner_frequency < 130000000)
+		cp = 3;
+	else if (tuner_frequency < 160000000)
+		cp = 5;
+	else if (tuner_frequency < 200000000)
+		cp = 6;
+	else if (tuner_frequency < 290000000)
+		cp = 3;
+	else if (tuner_frequency < 420000000)
+		cp = 5;
+	else if (tuner_frequency < 480000000)
+		cp = 6;
+	else if (tuner_frequency < 620000000)
+		cp = 3;
+	else if (tuner_frequency < 830000000)
+		cp = 5;
+	else if (tuner_frequency < 895000000)
+		cp = 7;
+	else
+		return -EINVAL;
+
+	// determine band
+	if (c->frequency < 49000000)
+		return -EINVAL;
+	else if (c->frequency < 161000000)
+		band = 1;
+	else if (c->frequency < 444000000)
+		band = 2;
+	else if (c->frequency < 861000000)
+		band = 4;
+	else
+		return -EINVAL;
+
+	// setup PLL filter
+	switch (c->bandwidth_hz) {
+	case 6000000:
+		filter = 0;
+		break;
+
+	case 7000000:
+		filter = 0;
+		break;
+
+	case 8000000:
+		filter = 1;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	// calculate divisor
+	// ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
+	tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000;
+
+	// setup tuner buffer
+	tuner_buf[0] = (tuner_frequency >> 8) & 0x7f;
+	tuner_buf[1] = tuner_frequency & 0xff;
+	tuner_buf[2] = 0xca;
+	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
+		return -EIO;
+
+	msleep(1);
+	return 0;
+}
+
+static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
+					   const struct firmware **fw, char *name)
+{
+	struct budget *budget = (struct budget *) fe->dvb->priv;
+
+	return request_firmware(fw, name, &budget->dev->pci->dev);
+}
+
+static struct tda1004x_config philips_tu1216_config = {
+
+	.demod_address = 0x8,
+	.invert = 1,
+	.invert_oclk = 1,
+	.xtal_freq = TDA10046_XTAL_4M,
+	.agc_config = TDA10046_AGC_DEFAULT,
+	.if_freq = TDA10046_FREQ_3617,
+	.request_firmware = philips_tu1216_request_firmware,
+};
+
+static u8 philips_sd1878_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x30,
+	0x03, 0x00,
+	0x04, 0x7d,
+	0x05, 0x35,
+	0x06, 0x40,
+	0x07, 0x00,
+	0x08, 0x43,
+	0x09, 0x02,
+	0x0C, 0x51,
+	0x0D, 0x82,
+	0x0E, 0x23,
+	0x10, 0x3f,
+	0x11, 0x84,
+	0x12, 0xb9,
+	0x15, 0xc9,
+	0x16, 0x19,
+	0x17, 0x8c,
+	0x18, 0x59,
+	0x19, 0xf8,
+	0x1a, 0xfe,
+	0x1c, 0x7f,
+	0x1d, 0x00,
+	0x1e, 0x00,
+	0x1f, 0x50,
+	0x20, 0x00,
+	0x21, 0x00,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x28, 0x00,
+	0x29, 0x28,
+	0x2a, 0x14,
+	0x2b, 0x0f,
+	0x2c, 0x09,
+	0x2d, 0x09,
+	0x31, 0x1f,
+	0x32, 0x19,
+	0x33, 0xfc,
+	0x34, 0x93,
+	0xff, 0xff
+};
+
+static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe,
+		u32 srate, u32 ratio)
+{
+	u8 aclk = 0;
+	u8 bclk = 0;
+	u8 m1;
+
+	aclk = 0xb5;
+	if (srate < 2000000)
+		bclk = 0x86;
+	else if (srate < 5000000)
+		bclk = 0x89;
+	else if (srate < 15000000)
+		bclk = 0x8f;
+	else if (srate < 45000000)
+		bclk = 0x95;
+
+	m1 = 0x14;
+	if (srate < 4000000)
+		m1 = 0x10;
+
+	stv0299_writereg(fe, 0x0e, 0x23);
+	stv0299_writereg(fe, 0x0f, 0x94);
+	stv0299_writereg(fe, 0x10, 0x39);
+	stv0299_writereg(fe, 0x13, aclk);
+	stv0299_writereg(fe, 0x14, bclk);
+	stv0299_writereg(fe, 0x15, 0xc9);
+	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+	stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+	stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
+	stv0299_writereg(fe, 0x0f, 0x80 | m1);
+
+	return 0;
+}
+
+static struct stv0299_config philips_sd1878_config = {
+	.demod_address = 0x68,
+     .inittab = philips_sd1878_inittab,
+	.mclk = 88000000UL,
+	.invert = 0,
+	.skip_reinit = 0,
+	.lock_output = STV0299_LOCKOUTPUT_1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP0,
+	.min_delay_ms = 100,
+	.set_symbol_rate = philips_sd1878_ci_set_symbol_rate,
+};
+
+/* KNC1 DVB-S (STB0899) Inittab	*/
+static const struct stb0899_s1_reg knc1_stb0899_s1_init_1[] = {
+
+	{ STB0899_DEV_ID		, 0x81 },
+	{ STB0899_DISCNTRL1		, 0x32 },
+	{ STB0899_DISCNTRL2		, 0x80 },
+	{ STB0899_DISRX_ST0		, 0x04 },
+	{ STB0899_DISRX_ST1		, 0x00 },
+	{ STB0899_DISPARITY		, 0x00 },
+	{ STB0899_DISSTATUS		, 0x20 },
+	{ STB0899_DISF22		, 0x8c },
+	{ STB0899_DISF22RX		, 0x9a },
+	{ STB0899_SYSREG		, 0x0b },
+	{ STB0899_ACRPRESC		, 0x11 },
+	{ STB0899_ACRDIV1		, 0x0a },
+	{ STB0899_ACRDIV2		, 0x05 },
+	{ STB0899_DACR1			, 0x00 },
+	{ STB0899_DACR2			, 0x00 },
+	{ STB0899_OUTCFG		, 0x00 },
+	{ STB0899_MODECFG		, 0x00 },
+	{ STB0899_IRQSTATUS_3		, 0x30 },
+	{ STB0899_IRQSTATUS_2		, 0x00 },
+	{ STB0899_IRQSTATUS_1		, 0x00 },
+	{ STB0899_IRQSTATUS_0		, 0x00 },
+	{ STB0899_IRQMSK_3		, 0xf3 },
+	{ STB0899_IRQMSK_2		, 0xfc },
+	{ STB0899_IRQMSK_1		, 0xff },
+	{ STB0899_IRQMSK_0		, 0xff },
+	{ STB0899_IRQCFG		, 0x00 },
+	{ STB0899_I2CCFG		, 0x88 },
+	{ STB0899_I2CRPT		, 0x58 }, /* Repeater=8, Stop=disabled */
+	{ STB0899_IOPVALUE5		, 0x00 },
+	{ STB0899_IOPVALUE4		, 0x20 },
+	{ STB0899_IOPVALUE3		, 0xc9 },
+	{ STB0899_IOPVALUE2		, 0x90 },
+	{ STB0899_IOPVALUE1		, 0x40 },
+	{ STB0899_IOPVALUE0		, 0x00 },
+	{ STB0899_GPIO00CFG		, 0x82 },
+	{ STB0899_GPIO01CFG		, 0x82 },
+	{ STB0899_GPIO02CFG		, 0x82 },
+	{ STB0899_GPIO03CFG		, 0x82 },
+	{ STB0899_GPIO04CFG		, 0x82 },
+	{ STB0899_GPIO05CFG		, 0x82 },
+	{ STB0899_GPIO06CFG		, 0x82 },
+	{ STB0899_GPIO07CFG		, 0x82 },
+	{ STB0899_GPIO08CFG		, 0x82 },
+	{ STB0899_GPIO09CFG		, 0x82 },
+	{ STB0899_GPIO10CFG		, 0x82 },
+	{ STB0899_GPIO11CFG		, 0x82 },
+	{ STB0899_GPIO12CFG		, 0x82 },
+	{ STB0899_GPIO13CFG		, 0x82 },
+	{ STB0899_GPIO14CFG		, 0x82 },
+	{ STB0899_GPIO15CFG		, 0x82 },
+	{ STB0899_GPIO16CFG		, 0x82 },
+	{ STB0899_GPIO17CFG		, 0x82 },
+	{ STB0899_GPIO18CFG		, 0x82 },
+	{ STB0899_GPIO19CFG		, 0x82 },
+	{ STB0899_GPIO20CFG		, 0x82 },
+	{ STB0899_SDATCFG		, 0xb8 },
+	{ STB0899_SCLTCFG		, 0xba },
+	{ STB0899_AGCRFCFG		, 0x08 }, /* 0x1c */
+	{ STB0899_GPIO22		, 0x82 }, /* AGCBB2CFG */
+	{ STB0899_GPIO21		, 0x91 }, /* AGCBB1CFG */
+	{ STB0899_DIRCLKCFG		, 0x82 },
+	{ STB0899_CLKOUT27CFG		, 0x7e },
+	{ STB0899_STDBYCFG		, 0x82 },
+	{ STB0899_CS0CFG		, 0x82 },
+	{ STB0899_CS1CFG		, 0x82 },
+	{ STB0899_DISEQCOCFG		, 0x20 },
+	{ STB0899_GPIO32CFG		, 0x82 },
+	{ STB0899_GPIO33CFG		, 0x82 },
+	{ STB0899_GPIO34CFG		, 0x82 },
+	{ STB0899_GPIO35CFG		, 0x82 },
+	{ STB0899_GPIO36CFG		, 0x82 },
+	{ STB0899_GPIO37CFG		, 0x82 },
+	{ STB0899_GPIO38CFG		, 0x82 },
+	{ STB0899_GPIO39CFG		, 0x82 },
+	{ STB0899_NCOARSE		, 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
+	{ STB0899_SYNTCTRL		, 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
+	{ STB0899_FILTCTRL		, 0x00 },
+	{ STB0899_SYSCTRL		, 0x00 },
+	{ STB0899_STOPCLK1		, 0x20 },
+	{ STB0899_STOPCLK2		, 0x00 },
+	{ STB0899_INTBUFSTATUS		, 0x00 },
+	{ STB0899_INTBUFCTRL		, 0x0a },
+	{ 0xffff			, 0xff },
+};
+
+static const struct stb0899_s1_reg knc1_stb0899_s1_init_3[] = {
+	{ STB0899_DEMOD			, 0x00 },
+	{ STB0899_RCOMPC		, 0xc9 },
+	{ STB0899_AGC1CN		, 0x41 },
+	{ STB0899_AGC1REF		, 0x08 },
+	{ STB0899_RTC			, 0x7a },
+	{ STB0899_TMGCFG		, 0x4e },
+	{ STB0899_AGC2REF		, 0x33 },
+	{ STB0899_TLSR			, 0x84 },
+	{ STB0899_CFD			, 0xee },
+	{ STB0899_ACLC			, 0x87 },
+	{ STB0899_BCLC			, 0x94 },
+	{ STB0899_EQON			, 0x41 },
+	{ STB0899_LDT			, 0xdd },
+	{ STB0899_LDT2			, 0xc9 },
+	{ STB0899_EQUALREF		, 0xb4 },
+	{ STB0899_TMGRAMP		, 0x10 },
+	{ STB0899_TMGTHD		, 0x30 },
+	{ STB0899_IDCCOMP		, 0xfb },
+	{ STB0899_QDCCOMP		, 0x03 },
+	{ STB0899_POWERI		, 0x3b },
+	{ STB0899_POWERQ		, 0x3d },
+	{ STB0899_RCOMP			, 0x81 },
+	{ STB0899_AGCIQIN		, 0x80 },
+	{ STB0899_AGC2I1		, 0x04 },
+	{ STB0899_AGC2I2		, 0xf5 },
+	{ STB0899_TLIR			, 0x25 },
+	{ STB0899_RTF			, 0x80 },
+	{ STB0899_DSTATUS		, 0x00 },
+	{ STB0899_LDI			, 0xca },
+	{ STB0899_CFRM			, 0xf1 },
+	{ STB0899_CFRL			, 0xf3 },
+	{ STB0899_NIRM			, 0x2a },
+	{ STB0899_NIRL			, 0x05 },
+	{ STB0899_ISYMB			, 0x17 },
+	{ STB0899_QSYMB			, 0xfa },
+	{ STB0899_SFRH			, 0x2f },
+	{ STB0899_SFRM			, 0x68 },
+	{ STB0899_SFRL			, 0x40 },
+	{ STB0899_SFRUPH		, 0x2f },
+	{ STB0899_SFRUPM		, 0x68 },
+	{ STB0899_SFRUPL		, 0x40 },
+	{ STB0899_EQUAI1		, 0xfd },
+	{ STB0899_EQUAQ1		, 0x04 },
+	{ STB0899_EQUAI2		, 0x0f },
+	{ STB0899_EQUAQ2		, 0xff },
+	{ STB0899_EQUAI3		, 0xdf },
+	{ STB0899_EQUAQ3		, 0xfa },
+	{ STB0899_EQUAI4		, 0x37 },
+	{ STB0899_EQUAQ4		, 0x0d },
+	{ STB0899_EQUAI5		, 0xbd },
+	{ STB0899_EQUAQ5		, 0xf7 },
+	{ STB0899_DSTATUS2		, 0x00 },
+	{ STB0899_VSTATUS		, 0x00 },
+	{ STB0899_VERROR		, 0xff },
+	{ STB0899_IQSWAP		, 0x2a },
+	{ STB0899_ECNT1M		, 0x00 },
+	{ STB0899_ECNT1L		, 0x00 },
+	{ STB0899_ECNT2M		, 0x00 },
+	{ STB0899_ECNT2L		, 0x00 },
+	{ STB0899_ECNT3M		, 0x00 },
+	{ STB0899_ECNT3L		, 0x00 },
+	{ STB0899_FECAUTO1		, 0x06 },
+	{ STB0899_FECM			, 0x01 },
+	{ STB0899_VTH12			, 0xf0 },
+	{ STB0899_VTH23			, 0xa0 },
+	{ STB0899_VTH34			, 0x78 },
+	{ STB0899_VTH56			, 0x4e },
+	{ STB0899_VTH67			, 0x48 },
+	{ STB0899_VTH78			, 0x38 },
+	{ STB0899_PRVIT			, 0xff },
+	{ STB0899_VITSYNC		, 0x19 },
+	{ STB0899_RSULC			, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+	{ STB0899_TSULC			, 0x42 },
+	{ STB0899_RSLLC			, 0x40 },
+	{ STB0899_TSLPL			, 0x12 },
+	{ STB0899_TSCFGH		, 0x0c },
+	{ STB0899_TSCFGM		, 0x00 },
+	{ STB0899_TSCFGL		, 0x0c },
+	{ STB0899_TSOUT			, 0x4d }, /* 0x0d for CAM */
+	{ STB0899_RSSYNCDEL		, 0x00 },
+	{ STB0899_TSINHDELH		, 0x02 },
+	{ STB0899_TSINHDELM		, 0x00 },
+	{ STB0899_TSINHDELL		, 0x00 },
+	{ STB0899_TSLLSTKM		, 0x00 },
+	{ STB0899_TSLLSTKL		, 0x00 },
+	{ STB0899_TSULSTKM		, 0x00 },
+	{ STB0899_TSULSTKL		, 0xab },
+	{ STB0899_PCKLENUL		, 0x00 },
+	{ STB0899_PCKLENLL		, 0xcc },
+	{ STB0899_RSPCKLEN		, 0xcc },
+	{ STB0899_TSSTATUS		, 0x80 },
+	{ STB0899_ERRCTRL1		, 0xb6 },
+	{ STB0899_ERRCTRL2		, 0x96 },
+	{ STB0899_ERRCTRL3		, 0x89 },
+	{ STB0899_DMONMSK1		, 0x27 },
+	{ STB0899_DMONMSK0		, 0x03 },
+	{ STB0899_DEMAPVIT		, 0x5c },
+	{ STB0899_PLPARM		, 0x1f },
+	{ STB0899_PDELCTRL		, 0x48 },
+	{ STB0899_PDELCTRL2		, 0x00 },
+	{ STB0899_BBHCTRL1		, 0x00 },
+	{ STB0899_BBHCTRL2		, 0x00 },
+	{ STB0899_HYSTTHRESH		, 0x77 },
+	{ STB0899_MATCSTM		, 0x00 },
+	{ STB0899_MATCSTL		, 0x00 },
+	{ STB0899_UPLCSTM		, 0x00 },
+	{ STB0899_UPLCSTL		, 0x00 },
+	{ STB0899_DFLCSTM		, 0x00 },
+	{ STB0899_DFLCSTL		, 0x00 },
+	{ STB0899_SYNCCST		, 0x00 },
+	{ STB0899_SYNCDCSTM		, 0x00 },
+	{ STB0899_SYNCDCSTL		, 0x00 },
+	{ STB0899_ISI_ENTRY		, 0x00 },
+	{ STB0899_ISI_BIT_EN		, 0x00 },
+	{ STB0899_MATSTRM		, 0x00 },
+	{ STB0899_MATSTRL		, 0x00 },
+	{ STB0899_UPLSTRM		, 0x00 },
+	{ STB0899_UPLSTRL		, 0x00 },
+	{ STB0899_DFLSTRM		, 0x00 },
+	{ STB0899_DFLSTRL		, 0x00 },
+	{ STB0899_SYNCSTR		, 0x00 },
+	{ STB0899_SYNCDSTRM		, 0x00 },
+	{ STB0899_SYNCDSTRL		, 0x00 },
+	{ STB0899_CFGPDELSTATUS1	, 0x10 },
+	{ STB0899_CFGPDELSTATUS2	, 0x00 },
+	{ STB0899_BBFERRORM		, 0x00 },
+	{ STB0899_BBFERRORL		, 0x00 },
+	{ STB0899_UPKTERRORM		, 0x00 },
+	{ STB0899_UPKTERRORL		, 0x00 },
+	{ 0xffff			, 0xff },
+};
+
+/* STB0899 demodulator config for the KNC1 and clones */
+static struct stb0899_config knc1_dvbs2_config = {
+	.init_dev		= knc1_stb0899_s1_init_1,
+	.init_s2_demod		= stb0899_s2_init_2,
+	.init_s1_demod		= knc1_stb0899_s1_init_3,
+	.init_s2_fec		= stb0899_s2_init_4,
+	.init_tst		= stb0899_s1_init_5,
+
+	.postproc		= NULL,
+
+	.demod_address		= 0x68,
+//	.ts_output_mode		= STB0899_OUT_PARALLEL,	/* types = SERIAL/PARALLEL	*/
+	.block_sync_mode	= STB0899_SYNC_FORCED,	/* DSS, SYNC_FORCED/UNSYNCED	*/
+//	.ts_pfbit_toggle	= STB0899_MPEG_NORMAL,	/* DirecTV, MPEG toggling seq	*/
+
+	.xtal_freq		= 27000000,
+	.inversion		= IQ_SWAP_OFF, /* 1 */
+
+	.lo_clk			= 76500000,
+	.hi_clk			= 90000000,
+
+	.esno_ave		= STB0899_DVBS2_ESNO_AVE,
+	.esno_quant		= STB0899_DVBS2_ESNO_QUANT,
+	.avframes_coarse	= STB0899_DVBS2_AVFRAMES_COARSE,
+	.avframes_fine		= STB0899_DVBS2_AVFRAMES_FINE,
+	.miss_threshold		= STB0899_DVBS2_MISS_THRESHOLD,
+	.uwp_threshold_acq	= STB0899_DVBS2_UWP_THRESHOLD_ACQ,
+	.uwp_threshold_track	= STB0899_DVBS2_UWP_THRESHOLD_TRACK,
+	.uwp_threshold_sof	= STB0899_DVBS2_UWP_THRESHOLD_SOF,
+	.sof_search_timeout	= STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
+
+	.btr_nco_bits		= STB0899_DVBS2_BTR_NCO_BITS,
+	.btr_gain_shift_offset	= STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+	.crl_nco_bits		= STB0899_DVBS2_CRL_NCO_BITS,
+	.ldpc_max_iter		= STB0899_DVBS2_LDPC_MAX_ITER,
+
+	.tuner_get_frequency	= tda8261_get_frequency,
+	.tuner_set_frequency	= tda8261_set_frequency,
+	.tuner_set_bandwidth	= NULL,
+	.tuner_get_bandwidth	= tda8261_get_bandwidth,
+	.tuner_set_rfsiggain	= NULL
+};
+
+/*
+ * SD1878/SHA tuner config
+ * 1F, Single I/P, Horizontal mount, High Sensitivity
+ */
+static const struct tda8261_config sd1878c_config = {
+//	.name		= "SD1878/SHA",
+	.addr		= 0x60,
+	.step_size	= TDA8261_STEP_1000 /* kHz */
+};
+
+static u8 read_pwm(struct budget_av *budget_av)
+{
+	u8 b = 0xff;
+	u8 pwm;
+	struct i2c_msg msg[] = { {.addr = 0x50,.flags = 0,.buf = &b,.len = 1},
+	{.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1}
+	};
+
+	if ((i2c_transfer(&budget_av->budget.i2c_adap, msg, 2) != 2)
+	    || (pwm == 0xff))
+		pwm = 0x48;
+
+	return pwm;
+}
+
+#define SUBID_DVBS_KNC1			0x0010
+#define SUBID_DVBS_KNC1_PLUS		0x0011
+#define SUBID_DVBS_TYPHOON		0x4f56
+#define SUBID_DVBS_CINERGY1200		0x1154
+#define SUBID_DVBS_CYNERGY1200N 	0x1155
+#define SUBID_DVBS_TV_STAR		0x0014
+#define SUBID_DVBS_TV_STAR_PLUS_X4	0x0015
+#define SUBID_DVBS_TV_STAR_CI		0x0016
+#define SUBID_DVBS2_KNC1		0x0018
+#define SUBID_DVBS2_KNC1_OEM		0x0019
+#define SUBID_DVBS_EASYWATCH_1  	0x001a
+#define SUBID_DVBS_EASYWATCH_2  	0x001b
+#define SUBID_DVBS2_EASYWATCH		0x001d
+#define SUBID_DVBS_EASYWATCH		0x001e
+
+#define SUBID_DVBC_EASYWATCH		0x002a
+#define SUBID_DVBC_EASYWATCH_MK3	0x002c
+#define SUBID_DVBC_KNC1			0x0020
+#define SUBID_DVBC_KNC1_PLUS		0x0021
+#define SUBID_DVBC_KNC1_MK3		0x0022
+#define SUBID_DVBC_KNC1_TDA10024	0x0028
+#define SUBID_DVBC_KNC1_PLUS_MK3	0x0023
+#define SUBID_DVBC_CINERGY1200		0x1156
+#define SUBID_DVBC_CINERGY1200_MK3	0x1176
+
+#define SUBID_DVBT_EASYWATCH		0x003a
+#define SUBID_DVBT_KNC1_PLUS		0x0031
+#define SUBID_DVBT_KNC1			0x0030
+#define SUBID_DVBT_CINERGY1200		0x1157
+
+static void frontend_init(struct budget_av *budget_av)
+{
+	struct saa7146_dev * saa = budget_av->budget.dev;
+	struct dvb_frontend * fe = NULL;
+
+	/* Enable / PowerON Frontend */
+	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
+
+	/* Wait for PowerON */
+	msleep(100);
+
+	/* additional setup necessary for the PLUS cards */
+	switch (saa->pci->subsystem_device) {
+		case SUBID_DVBS_KNC1_PLUS:
+		case SUBID_DVBC_KNC1_PLUS:
+		case SUBID_DVBT_KNC1_PLUS:
+		case SUBID_DVBC_EASYWATCH:
+		case SUBID_DVBC_KNC1_PLUS_MK3:
+		case SUBID_DVBS2_KNC1:
+		case SUBID_DVBS2_KNC1_OEM:
+		case SUBID_DVBS2_EASYWATCH:
+			saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
+			break;
+	}
+
+	switch (saa->pci->subsystem_device) {
+
+	case SUBID_DVBS_KNC1:
+		/*
+		 * maybe that setting is needed for other dvb-s cards as well,
+		 * but so far it has been only confirmed for this type
+		 */
+		budget_av->reinitialise_demod = 1;
+		/* fall through */
+	case SUBID_DVBS_KNC1_PLUS:
+	case SUBID_DVBS_EASYWATCH_1:
+		if (saa->pci->subsystem_vendor == 0x1894) {
+			fe = dvb_attach(stv0299_attach, &cinergy_1200s_1894_0010_config,
+					     &budget_av->budget.i2c_adap);
+			if (fe) {
+				dvb_attach(tua6100_attach, fe, 0x60, &budget_av->budget.i2c_adap);
+			}
+		} else {
+			fe = dvb_attach(stv0299_attach, &typhoon_config,
+					     &budget_av->budget.i2c_adap);
+			if (fe) {
+				fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+			}
+		}
+		break;
+
+	case SUBID_DVBS_TV_STAR:
+	case SUBID_DVBS_TV_STAR_PLUS_X4:
+	case SUBID_DVBS_TV_STAR_CI:
+	case SUBID_DVBS_CYNERGY1200N:
+	case SUBID_DVBS_EASYWATCH:
+	case SUBID_DVBS_EASYWATCH_2:
+		fe = dvb_attach(stv0299_attach, &philips_sd1878_config,
+				&budget_av->budget.i2c_adap);
+		if (fe) {
+			dvb_attach(dvb_pll_attach, fe, 0x60,
+				   &budget_av->budget.i2c_adap,
+				   DVB_PLL_PHILIPS_SD1878_TDA8261);
+		}
+		break;
+
+	case SUBID_DVBS_TYPHOON:
+		fe = dvb_attach(stv0299_attach, &typhoon_config,
+				    &budget_av->budget.i2c_adap);
+		if (fe) {
+			fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+		}
+		break;
+	case SUBID_DVBS2_KNC1:
+	case SUBID_DVBS2_KNC1_OEM:
+	case SUBID_DVBS2_EASYWATCH:
+		budget_av->reinitialise_demod = 1;
+		if ((fe = dvb_attach(stb0899_attach, &knc1_dvbs2_config, &budget_av->budget.i2c_adap)))
+			dvb_attach(tda8261_attach, fe, &sd1878c_config, &budget_av->budget.i2c_adap);
+
+		break;
+	case SUBID_DVBS_CINERGY1200:
+		fe = dvb_attach(stv0299_attach, &cinergy_1200s_config,
+				    &budget_av->budget.i2c_adap);
+		if (fe) {
+			fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+		}
+		break;
+
+	case SUBID_DVBC_KNC1:
+	case SUBID_DVBC_KNC1_PLUS:
+	case SUBID_DVBC_CINERGY1200:
+	case SUBID_DVBC_EASYWATCH:
+		budget_av->reinitialise_demod = 1;
+		budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
+		fe = dvb_attach(tda10021_attach, &philips_cu1216_config,
+				     &budget_av->budget.i2c_adap,
+				     read_pwm(budget_av));
+		if (fe == NULL)
+			fe = dvb_attach(tda10021_attach, &philips_cu1216_config_altaddress,
+					     &budget_av->budget.i2c_adap,
+					     read_pwm(budget_av));
+		if (fe) {
+			fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
+		}
+		break;
+
+	case SUBID_DVBC_EASYWATCH_MK3:
+	case SUBID_DVBC_CINERGY1200_MK3:
+	case SUBID_DVBC_KNC1_MK3:
+	case SUBID_DVBC_KNC1_TDA10024:
+	case SUBID_DVBC_KNC1_PLUS_MK3:
+		budget_av->reinitialise_demod = 1;
+		budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
+		fe = dvb_attach(tda10023_attach,
+			&philips_cu1216_tda10023_config,
+			&budget_av->budget.i2c_adap,
+			read_pwm(budget_av));
+		if (fe) {
+			fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
+		}
+		break;
+
+	case SUBID_DVBT_EASYWATCH:
+	case SUBID_DVBT_KNC1:
+	case SUBID_DVBT_KNC1_PLUS:
+	case SUBID_DVBT_CINERGY1200:
+		budget_av->reinitialise_demod = 1;
+		fe = dvb_attach(tda10046_attach, &philips_tu1216_config,
+				     &budget_av->budget.i2c_adap);
+		if (fe) {
+			fe->ops.tuner_ops.init = philips_tu1216_tuner_init;
+			fe->ops.tuner_ops.set_params = philips_tu1216_tuner_set_params;
+		}
+		break;
+	}
+
+	if (fe == NULL) {
+		pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
+		       saa->pci->vendor,
+		       saa->pci->device,
+		       saa->pci->subsystem_vendor,
+		       saa->pci->subsystem_device);
+		return;
+	}
+
+	budget_av->budget.dvb_frontend = fe;
+
+	if (dvb_register_frontend(&budget_av->budget.dvb_adapter,
+				  budget_av->budget.dvb_frontend)) {
+		pr_err("Frontend registration failed!\n");
+		dvb_frontend_detach(budget_av->budget.dvb_frontend);
+		budget_av->budget.dvb_frontend = NULL;
+	}
+}
+
+
+static void budget_av_irq(struct saa7146_dev *dev, u32 * isr)
+{
+	struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
+
+	dprintk(8, "dev: %p, budget_av: %p\n", dev, budget_av);
+
+	if (*isr & MASK_10)
+		ttpci_budget_irq10_handler(dev, isr);
+}
+
+static int budget_av_detach(struct saa7146_dev *dev)
+{
+	struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
+	int err;
+
+	dprintk(2, "dev: %p\n", dev);
+
+	if (1 == budget_av->has_saa7113) {
+		saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO);
+
+		msleep(200);
+
+		saa7146_unregister_device(&budget_av->vd, dev);
+
+		saa7146_vv_release(dev);
+	}
+
+	if (budget_av->budget.ci_present)
+		ciintf_deinit(budget_av);
+
+	if (budget_av->budget.dvb_frontend != NULL) {
+		dvb_unregister_frontend(budget_av->budget.dvb_frontend);
+		dvb_frontend_detach(budget_av->budget.dvb_frontend);
+	}
+	err = ttpci_budget_deinit(&budget_av->budget);
+
+	kfree(budget_av);
+
+	return err;
+}
+
+#define KNC1_INPUTS 2
+static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
+	{ 0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0,
+		V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0,
+		V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+};
+
+static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+	dprintk(1, "VIDIOC_ENUMINPUT %d\n", i->index);
+	if (i->index >= KNC1_INPUTS)
+		return -EINVAL;
+	memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct budget_av *budget_av = (struct budget_av *)dev->ext_priv;
+
+	*i = budget_av->cur_input;
+
+	dprintk(1, "VIDIOC_G_INPUT %d\n", *i);
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
+{
+	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+	struct budget_av *budget_av = (struct budget_av *)dev->ext_priv;
+
+	dprintk(1, "VIDIOC_S_INPUT %d\n", input);
+	return saa7113_setinput(budget_av, input);
+}
+
+static struct saa7146_ext_vv vv_data;
+
+static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
+{
+	struct budget_av *budget_av;
+	u8 *mac;
+	int err;
+
+	dprintk(2, "dev: %p\n", dev);
+
+	if (!(budget_av = kzalloc(sizeof(struct budget_av), GFP_KERNEL)))
+		return -ENOMEM;
+
+	budget_av->has_saa7113 = 0;
+	budget_av->budget.ci_present = 0;
+
+	dev->ext_priv = budget_av;
+
+	err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE,
+				adapter_nr);
+	if (err) {
+		kfree(budget_av);
+		return err;
+	}
+
+	/* knc1 initialization */
+	saa7146_write(dev, DD1_STREAM_B, 0x04000000);
+	saa7146_write(dev, DD1_INIT, 0x07000600);
+	saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26);
+
+	if (saa7113_init(budget_av) == 0) {
+		budget_av->has_saa7113 = 1;
+
+		if (0 != saa7146_vv_init(dev, &vv_data)) {
+			/* fixme: proper cleanup here */
+			ERR("cannot init vv subsystem\n");
+			return err;
+		}
+		vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
+		vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
+		vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
+
+		if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
+			/* fixme: proper cleanup here */
+			ERR("cannot register capture v4l2 device\n");
+			saa7146_vv_release(dev);
+			return err;
+		}
+
+		/* beware: this modifies dev->vv ... */
+		saa7146_set_hps_source_and_sync(dev, SAA7146_HPS_SOURCE_PORT_A,
+						SAA7146_HPS_SYNC_PORT_A);
+
+		saa7113_setinput(budget_av, 0);
+	}
+
+	/* fixme: find some sane values here... */
+	saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
+
+	mac = budget_av->budget.dvb_adapter.proposed_mac;
+	if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) {
+		pr_err("KNC1-%d: Could not read MAC from KNC1 card\n",
+		       budget_av->budget.dvb_adapter.num);
+		memset(mac, 0, 6);
+	} else {
+		pr_info("KNC1-%d: MAC addr = %pM\n",
+			budget_av->budget.dvb_adapter.num, mac);
+	}
+
+	budget_av->budget.dvb_adapter.priv = budget_av;
+	frontend_init(budget_av);
+	ciintf_init(budget_av);
+
+	ttpci_budget_init_hooks(&budget_av->budget);
+
+	return 0;
+}
+
+static struct saa7146_standard standard[] = {
+	{.name = "PAL",.id = V4L2_STD_PAL,
+	 .v_offset = 0x17,.v_field = 288,
+	 .h_offset = 0x14,.h_pixels = 680,
+	 .v_max_out = 576,.h_max_out = 768 },
+
+	{.name = "NTSC",.id = V4L2_STD_NTSC,
+	 .v_offset = 0x16,.v_field = 240,
+	 .h_offset = 0x06,.h_pixels = 708,
+	 .v_max_out = 480,.h_max_out = 640, },
+};
+
+static struct saa7146_ext_vv vv_data = {
+	.inputs = 2,
+	.capabilities = 0,	// perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113
+	.flags = 0,
+	.stds = &standard[0],
+	.num_stds = ARRAY_SIZE(standard),
+};
+
+static struct saa7146_extension budget_extension;
+
+MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S);
+MAKE_BUDGET_INFO(knc1s2,"KNC1 DVB-S2", BUDGET_KNC1S2);
+MAKE_BUDGET_INFO(sates2,"Satelco EasyWatch DVB-S2", BUDGET_KNC1S2);
+MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);
+MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
+MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
+MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
+MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
+MAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S);
+MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP);
+MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3);
+MAKE_BUDGET_INFO(satewt, "Satelco EasyWatch DVB-T", BUDGET_KNC1T);
+MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
+MAKE_BUDGET_INFO(knc1spx4, "KNC1 DVB-S Plus X4", BUDGET_KNC1SP);
+MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
+MAKE_BUDGET_INFO(knc1cmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3);
+MAKE_BUDGET_INFO(knc1ctda10024, "KNC1 DVB-C TDA10024", BUDGET_KNC1C_TDA10024);
+MAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C Plus MK3", BUDGET_KNC1CP_MK3);
+MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
+MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
+MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
+MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C);
+MAKE_BUDGET_INFO(cin1200cmk3, "Terratec Cinergy 1200 DVB-C MK3", BUDGET_CIN1200C_MK3);
+MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);
+
+static struct pci_device_id pci_tbl[] = {
+	MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56),
+	MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010),
+	MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010),
+	MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),
+	MAKE_EXTENSION_PCI(knc1sp, 0x1894, 0x0011),
+	MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
+	MAKE_EXTENSION_PCI(knc1spx4, 0x1894, 0x0015),
+	MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
+	MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0018),
+	MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0019),
+	MAKE_EXTENSION_PCI(sates2, 0x1894, 0x001d),
+	MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
+	MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
+	MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b),
+	MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a),
+	MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c),
+	MAKE_EXTENSION_PCI(satewt, 0x1894, 0x003a),
+	MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
+	MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
+	MAKE_EXTENSION_PCI(knc1cmk3, 0x1894, 0x0022),
+	MAKE_EXTENSION_PCI(knc1ctda10024, 0x1894, 0x0028),
+	MAKE_EXTENSION_PCI(knc1cpmk3, 0x1894, 0x0023),
+	MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
+	MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031),
+	MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154),
+	MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155),
+	MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156),
+	MAKE_EXTENSION_PCI(cin1200cmk3, 0x153b, 0x1176),
+	MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157),
+	{
+	 .vendor = 0,
+	}
+};
+
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+static struct saa7146_extension budget_extension = {
+	.name = "budget_av",
+	.flags = SAA7146_USE_I2C_IRQ,
+
+	.pci_tbl = pci_tbl,
+
+	.module = THIS_MODULE,
+	.attach = budget_av_attach,
+	.detach = budget_av_detach,
+
+	.irq_mask = MASK_10,
+	.irq_func = budget_av_irq,
+};
+
+static int __init budget_av_init(void)
+{
+	return saa7146_register_extension(&budget_extension);
+}
+
+static void __exit budget_av_exit(void)
+{
+	saa7146_unregister_extension(&budget_extension);
+}
+
+module_init(budget_av_init);
+module_exit(budget_av_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others");
+MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
+		   "budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)");
diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c
new file mode 100644
index 0000000..98e5241
--- /dev/null
+++ b/drivers/media/pci/ttpci/budget-ci.c
@@ -0,0 +1,1591 @@
+/*
+ * budget-ci.c: driver for the SAA7146 based Budget DVB cards
+ *
+ * Compiled from various sources by Michael Hunold <michael@mihu.de>
+ *
+ *     msp430 IR support contributed by Jack Thomasson <jkt@Helius.COM>
+ *     partially based on the Siemens DVB driver by Ralph+Marcus Metzler
+ *
+ * CI interface support (c) 2004 Andrew de Quincey <adq_dvb@lidskialf.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.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org/
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <media/rc-core.h>
+
+#include "budget.h"
+
+#include "dvb_ca_en50221.h"
+#include "stv0299.h"
+#include "stv0297.h"
+#include "tda1004x.h"
+#include "stb0899_drv.h"
+#include "stb0899_reg.h"
+#include "stb0899_cfg.h"
+#include "stb6100.h"
+#include "stb6100_cfg.h"
+#include "lnbp21.h"
+#include "bsbe1.h"
+#include "bsru6.h"
+#include "tda1002x.h"
+#include "tda827x.h"
+#include "bsbe1-d01a.h"
+
+#define MODULE_NAME "budget_ci"
+
+/*
+ * Regarding DEBIADDR_IR:
+ * Some CI modules hang if random addresses are read.
+ * Using address 0x4000 for the IR read means that we
+ * use the same address as for CI version, which should
+ * be a safe default.
+ */
+#define DEBIADDR_IR		0x4000
+#define DEBIADDR_CICONTROL	0x0000
+#define DEBIADDR_CIVERSION	0x4000
+#define DEBIADDR_IO		0x1000
+#define DEBIADDR_ATTR		0x3000
+
+#define CICONTROL_RESET		0x01
+#define CICONTROL_ENABLETS	0x02
+#define CICONTROL_CAMDETECT	0x08
+
+#define DEBICICTL		0x00420000
+#define DEBICICAM		0x02420000
+
+#define SLOTSTATUS_NONE		1
+#define SLOTSTATUS_PRESENT	2
+#define SLOTSTATUS_RESET	4
+#define SLOTSTATUS_READY	8
+#define SLOTSTATUS_OCCUPIED	(SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
+
+/* RC5 device wildcard */
+#define IR_DEVICE_ANY		255
+
+static int rc5_device = -1;
+module_param(rc5_device, int, 0644);
+MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)");
+
+static int ir_debug;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct budget_ci_ir {
+	struct rc_dev *dev;
+	struct tasklet_struct msp430_irq_tasklet;
+	char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
+	char phys[32];
+	int rc5_device;
+	u32 ir_key;
+	bool have_command;
+	bool full_rc5;		/* Outputs a full RC5 code */
+};
+
+struct budget_ci {
+	struct budget budget;
+	struct tasklet_struct ciintf_irq_tasklet;
+	int slot_status;
+	int ci_irq;
+	struct dvb_ca_en50221 ca;
+	struct budget_ci_ir ir;
+	u8 tuner_pll_address; /* used for philips_tdm1316l configs */
+};
+
+static void msp430_ir_interrupt(unsigned long data)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) data;
+	struct rc_dev *dev = budget_ci->ir.dev;
+	u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
+
+	/*
+	 * The msp430 chip can generate two different bytes, command and device
+	 *
+	 * type1: X1CCCCCC, C = command bits (0 - 63)
+	 * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
+	 *
+	 * Each signal from the remote control can generate one or more command
+	 * bytes and one or more device bytes. For the repeated bytes, the
+	 * highest bit (X) is set. The first command byte is always generated
+	 * before the first device byte. Other than that, no specific order
+	 * seems to apply. To make life interesting, bytes can also be lost.
+	 *
+	 * Only when we have a command and device byte, a keypress is
+	 * generated.
+	 */
+
+	if (ir_debug)
+		printk("budget_ci: received byte 0x%02x\n", command);
+
+	/* Remove repeat bit, we use every command */
+	command = command & 0x7f;
+
+	/* Is this a RC5 command byte? */
+	if (command & 0x40) {
+		budget_ci->ir.have_command = true;
+		budget_ci->ir.ir_key = command & 0x3f;
+		return;
+	}
+
+	/* It's a RC5 device byte */
+	if (!budget_ci->ir.have_command)
+		return;
+	budget_ci->ir.have_command = false;
+
+	if (budget_ci->ir.rc5_device != IR_DEVICE_ANY &&
+	    budget_ci->ir.rc5_device != (command & 0x1f))
+		return;
+
+	if (budget_ci->ir.full_rc5) {
+		rc_keydown(dev,
+			   budget_ci->ir.rc5_device <<8 | budget_ci->ir.ir_key,
+			   (command & 0x20) ? 1 : 0);
+		return;
+	}
+
+	/* FIXME: We should generate complete scancodes for all devices */
+	rc_keydown(dev, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0);
+}
+
+static int msp430_ir_init(struct budget_ci *budget_ci)
+{
+	struct saa7146_dev *saa = budget_ci->budget.dev;
+	struct rc_dev *dev;
+	int error;
+
+	dev = rc_allocate_device();
+	if (!dev) {
+		printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
+		return -ENOMEM;
+	}
+
+	snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
+		 "Budget-CI dvb ir receiver %s", saa->name);
+	snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
+		 "pci-%s/ir0", pci_name(saa->pci));
+
+	dev->driver_name = MODULE_NAME;
+	dev->input_name = budget_ci->ir.name;
+	dev->input_phys = budget_ci->ir.phys;
+	dev->input_id.bustype = BUS_PCI;
+	dev->input_id.version = 1;
+	if (saa->pci->subsystem_vendor) {
+		dev->input_id.vendor = saa->pci->subsystem_vendor;
+		dev->input_id.product = saa->pci->subsystem_device;
+	} else {
+		dev->input_id.vendor = saa->pci->vendor;
+		dev->input_id.product = saa->pci->device;
+	}
+	dev->dev.parent = &saa->pci->dev;
+
+	if (rc5_device < 0)
+		budget_ci->ir.rc5_device = IR_DEVICE_ANY;
+	else
+		budget_ci->ir.rc5_device = rc5_device;
+
+	/* Select keymap and address */
+	switch (budget_ci->budget.dev->pci->subsystem_device) {
+	case 0x100c:
+	case 0x100f:
+	case 0x1011:
+	case 0x1012:
+		/* The hauppauge keymap is a superset of these remotes */
+		dev->map_name = RC_MAP_HAUPPAUGE;
+		budget_ci->ir.full_rc5 = true;
+
+		if (rc5_device < 0)
+			budget_ci->ir.rc5_device = 0x1f;
+		break;
+	case 0x1010:
+	case 0x1017:
+	case 0x1019:
+	case 0x101a:
+	case 0x101b:
+		/* for the Technotrend 1500 bundled remote */
+		dev->map_name = RC_MAP_TT_1500;
+		break;
+	default:
+		/* unknown remote */
+		dev->map_name = RC_MAP_BUDGET_CI_OLD;
+		break;
+	}
+	if (!budget_ci->ir.full_rc5)
+		dev->scanmask = 0xff;
+
+	error = rc_register_device(dev);
+	if (error) {
+		printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
+		rc_free_device(dev);
+		return error;
+	}
+
+	budget_ci->ir.dev = dev;
+
+	tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
+		     (unsigned long) budget_ci);
+
+	SAA7146_IER_ENABLE(saa, MASK_06);
+	saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
+
+	return 0;
+}
+
+static void msp430_ir_deinit(struct budget_ci *budget_ci)
+{
+	struct saa7146_dev *saa = budget_ci->budget.dev;
+
+	SAA7146_IER_DISABLE(saa, MASK_06);
+	saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
+	tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
+
+	rc_unregister_device(budget_ci->ir.dev);
+}
+
+static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
+				     DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
+}
+
+static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
+				      DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
+}
+
+static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
+				     DEBIADDR_IO | (address & 3), 1, 1, 0);
+}
+
+static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
+				      DEBIADDR_IO | (address & 3), 1, value, 1, 0);
+}
+
+static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
+	struct saa7146_dev *saa = budget_ci->budget.dev;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	if (budget_ci->ci_irq) {
+		// trigger on RISING edge during reset so we know when READY is re-asserted
+		saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
+	}
+	budget_ci->slot_status = SLOTSTATUS_RESET;
+	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
+	msleep(1);
+	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
+			       CICONTROL_RESET, 1, 0);
+
+	saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
+	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
+	return 0;
+}
+
+static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
+	struct saa7146_dev *saa = budget_ci->budget.dev;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
+	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
+	return 0;
+}
+
+static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
+	struct saa7146_dev *saa = budget_ci->budget.dev;
+	int tmp;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
+
+	tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
+	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
+			       tmp | CICONTROL_ENABLETS, 1, 0);
+
+	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
+	return 0;
+}
+
+static void ciintf_interrupt(unsigned long data)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) data;
+	struct saa7146_dev *saa = budget_ci->budget.dev;
+	unsigned int flags;
+
+	// ensure we don't get spurious IRQs during initialisation
+	if (!budget_ci->budget.ci_present)
+		return;
+
+	// read the CAM status
+	flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
+	if (flags & CICONTROL_CAMDETECT) {
+
+		// GPIO should be set to trigger on falling edge if a CAM is present
+		saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
+
+		if (budget_ci->slot_status & SLOTSTATUS_NONE) {
+			// CAM insertion IRQ
+			budget_ci->slot_status = SLOTSTATUS_PRESENT;
+			dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
+						     DVB_CA_EN50221_CAMCHANGE_INSERTED);
+
+		} else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
+			// CAM ready (reset completed)
+			budget_ci->slot_status = SLOTSTATUS_READY;
+			dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
+
+		} else if (budget_ci->slot_status & SLOTSTATUS_READY) {
+			// FR/DA IRQ
+			dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
+		}
+	} else {
+
+		// trigger on rising edge if a CAM is not present - when a CAM is inserted, we
+		// only want to get the IRQ when it sets READY. If we trigger on the falling edge,
+		// the CAM might not actually be ready yet.
+		saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
+
+		// generate a CAM removal IRQ if we haven't already
+		if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
+			// CAM removal IRQ
+			budget_ci->slot_status = SLOTSTATUS_NONE;
+			dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
+						     DVB_CA_EN50221_CAMCHANGE_REMOVED);
+		}
+	}
+}
+
+static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
+	unsigned int flags;
+
+	// ensure we don't get spurious IRQs during initialisation
+	if (!budget_ci->budget.ci_present)
+		return -EINVAL;
+
+	// read the CAM status
+	flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
+	if (flags & CICONTROL_CAMDETECT) {
+		// mark it as present if it wasn't before
+		if (budget_ci->slot_status & SLOTSTATUS_NONE) {
+			budget_ci->slot_status = SLOTSTATUS_PRESENT;
+		}
+
+		// during a RESET, we check if we can read from IO memory to see when CAM is ready
+		if (budget_ci->slot_status & SLOTSTATUS_RESET) {
+			if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
+				budget_ci->slot_status = SLOTSTATUS_READY;
+			}
+		}
+	} else {
+		budget_ci->slot_status = SLOTSTATUS_NONE;
+	}
+
+	if (budget_ci->slot_status != SLOTSTATUS_NONE) {
+		if (budget_ci->slot_status & SLOTSTATUS_READY) {
+			return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
+		}
+		return DVB_CA_EN50221_POLL_CAM_PRESENT;
+	}
+
+	return 0;
+}
+
+static int ciintf_init(struct budget_ci *budget_ci)
+{
+	struct saa7146_dev *saa = budget_ci->budget.dev;
+	int flags;
+	int result;
+	int ci_version;
+	int ca_flags;
+
+	memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
+
+	// enable DEBI pins
+	saa7146_write(saa, MC1, MASK_27 | MASK_11);
+
+	// test if it is there
+	ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
+	if ((ci_version & 0xa0) != 0xa0) {
+		result = -ENODEV;
+		goto error;
+	}
+
+	// determine whether a CAM is present or not
+	flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
+	budget_ci->slot_status = SLOTSTATUS_NONE;
+	if (flags & CICONTROL_CAMDETECT)
+		budget_ci->slot_status = SLOTSTATUS_PRESENT;
+
+	// version 0xa2 of the CI firmware doesn't generate interrupts
+	if (ci_version == 0xa2) {
+		ca_flags = 0;
+		budget_ci->ci_irq = 0;
+	} else {
+		ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
+				DVB_CA_EN50221_FLAG_IRQ_FR |
+				DVB_CA_EN50221_FLAG_IRQ_DA;
+		budget_ci->ci_irq = 1;
+	}
+
+	// register CI interface
+	budget_ci->ca.owner = THIS_MODULE;
+	budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
+	budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
+	budget_ci->ca.read_cam_control = ciintf_read_cam_control;
+	budget_ci->ca.write_cam_control = ciintf_write_cam_control;
+	budget_ci->ca.slot_reset = ciintf_slot_reset;
+	budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
+	budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
+	budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
+	budget_ci->ca.data = budget_ci;
+	if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
+					  &budget_ci->ca,
+					  ca_flags, 1)) != 0) {
+		printk("budget_ci: CI interface detected, but initialisation failed.\n");
+		goto error;
+	}
+
+	// Setup CI slot IRQ
+	if (budget_ci->ci_irq) {
+		tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
+		if (budget_ci->slot_status != SLOTSTATUS_NONE) {
+			saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
+		} else {
+			saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
+		}
+		SAA7146_IER_ENABLE(saa, MASK_03);
+	}
+
+	// enable interface
+	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
+			       CICONTROL_RESET, 1, 0);
+
+	// success!
+	printk("budget_ci: CI interface initialised\n");
+	budget_ci->budget.ci_present = 1;
+
+	// forge a fake CI IRQ so the CAM state is setup correctly
+	if (budget_ci->ci_irq) {
+		flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
+		if (budget_ci->slot_status != SLOTSTATUS_NONE)
+			flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
+		dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
+	}
+
+	return 0;
+
+error:
+	saa7146_write(saa, MC1, MASK_27);
+	return result;
+}
+
+static void ciintf_deinit(struct budget_ci *budget_ci)
+{
+	struct saa7146_dev *saa = budget_ci->budget.dev;
+
+	// disable CI interrupts
+	if (budget_ci->ci_irq) {
+		SAA7146_IER_DISABLE(saa, MASK_03);
+		saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
+		tasklet_kill(&budget_ci->ciintf_irq_tasklet);
+	}
+
+	// reset interface
+	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
+	msleep(1);
+	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
+			       CICONTROL_RESET, 1, 0);
+
+	// disable TS data stream to CI interface
+	saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
+
+	// release the CA device
+	dvb_ca_en50221_release(&budget_ci->ca);
+
+	// disable DEBI pins
+	saa7146_write(saa, MC1, MASK_27);
+}
+
+static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
+
+	dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
+
+	if (*isr & MASK_06)
+		tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
+
+	if (*isr & MASK_10)
+		ttpci_budget_irq10_handler(dev, isr);
+
+	if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
+		tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
+}
+
+static u8 philips_su1278_tt_inittab[] = {
+	0x01, 0x0f,
+	0x02, 0x30,
+	0x03, 0x00,
+	0x04, 0x5b,
+	0x05, 0x85,
+	0x06, 0x02,
+	0x07, 0x00,
+	0x08, 0x02,
+	0x09, 0x00,
+	0x0C, 0x01,
+	0x0D, 0x81,
+	0x0E, 0x44,
+	0x0f, 0x14,
+	0x10, 0x3c,
+	0x11, 0x84,
+	0x12, 0xda,
+	0x13, 0x97,
+	0x14, 0x95,
+	0x15, 0xc9,
+	0x16, 0x19,
+	0x17, 0x8c,
+	0x18, 0x59,
+	0x19, 0xf8,
+	0x1a, 0xfe,
+	0x1c, 0x7f,
+	0x1d, 0x00,
+	0x1e, 0x00,
+	0x1f, 0x50,
+	0x20, 0x00,
+	0x21, 0x00,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x28, 0x00,
+	0x29, 0x28,
+	0x2a, 0x14,
+	0x2b, 0x0f,
+	0x2c, 0x09,
+	0x2d, 0x09,
+	0x31, 0x1f,
+	0x32, 0x19,
+	0x33, 0xfc,
+	0x34, 0x93,
+	0xff, 0xff
+};
+
+static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
+{
+	stv0299_writereg(fe, 0x0e, 0x44);
+	if (srate >= 10000000) {
+		stv0299_writereg(fe, 0x13, 0x97);
+		stv0299_writereg(fe, 0x14, 0x95);
+		stv0299_writereg(fe, 0x15, 0xc9);
+		stv0299_writereg(fe, 0x17, 0x8c);
+		stv0299_writereg(fe, 0x1a, 0xfe);
+		stv0299_writereg(fe, 0x1c, 0x7f);
+		stv0299_writereg(fe, 0x2d, 0x09);
+	} else {
+		stv0299_writereg(fe, 0x13, 0x99);
+		stv0299_writereg(fe, 0x14, 0x8d);
+		stv0299_writereg(fe, 0x15, 0xce);
+		stv0299_writereg(fe, 0x17, 0x43);
+		stv0299_writereg(fe, 0x1a, 0x1d);
+		stv0299_writereg(fe, 0x1c, 0x12);
+		stv0299_writereg(fe, 0x2d, 0x05);
+	}
+	stv0299_writereg(fe, 0x0e, 0x23);
+	stv0299_writereg(fe, 0x0f, 0x94);
+	stv0299_writereg(fe, 0x10, 0x39);
+	stv0299_writereg(fe, 0x15, 0xc9);
+
+	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+	stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+	stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
+
+	return 0;
+}
+
+static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
+	u32 div;
+	u8 buf[4];
+	struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
+
+	if ((p->frequency < 950000) || (p->frequency > 2150000))
+		return -EINVAL;
+
+	div = (p->frequency + (500 - 1)) / 500;	/* round correctly */
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
+	buf[3] = 0x20;
+
+	if (p->symbol_rate < 4000000)
+		buf[3] |= 1;
+
+	if (p->frequency < 1250000)
+		buf[3] |= 0;
+	else if (p->frequency < 1550000)
+		buf[3] |= 0x40;
+	else if (p->frequency < 2050000)
+		buf[3] |= 0x80;
+	else if (p->frequency < 2150000)
+		buf[3] |= 0xC0;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static struct stv0299_config philips_su1278_tt_config = {
+
+	.demod_address = 0x68,
+	.inittab = philips_su1278_tt_inittab,
+	.mclk = 64000000UL,
+	.invert = 0,
+	.skip_reinit = 1,
+	.lock_output = STV0299_LOCKOUTPUT_1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP1,
+	.min_delay_ms = 50,
+	.set_symbol_rate = philips_su1278_tt_set_symbol_rate,
+};
+
+
+
+static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
+	static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+	static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
+	struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
+			sizeof(td1316_init) };
+
+	// setup PLL configuration
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
+		return -EIO;
+	msleep(1);
+
+	// disable the mc44BC374c (do not check for errors)
+	tuner_msg.addr = 0x65;
+	tuner_msg.buf = disable_mc44BC374c;
+	tuner_msg.len = sizeof(disable_mc44BC374c);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
+	}
+
+	return 0;
+}
+
+static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
+	u8 tuner_buf[4];
+	struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) };
+	int tuner_frequency = 0;
+	u8 band, cp, filter;
+
+	// determine charge pump
+	tuner_frequency = p->frequency + 36130000;
+	if (tuner_frequency < 87000000)
+		return -EINVAL;
+	else if (tuner_frequency < 130000000)
+		cp = 3;
+	else if (tuner_frequency < 160000000)
+		cp = 5;
+	else if (tuner_frequency < 200000000)
+		cp = 6;
+	else if (tuner_frequency < 290000000)
+		cp = 3;
+	else if (tuner_frequency < 420000000)
+		cp = 5;
+	else if (tuner_frequency < 480000000)
+		cp = 6;
+	else if (tuner_frequency < 620000000)
+		cp = 3;
+	else if (tuner_frequency < 830000000)
+		cp = 5;
+	else if (tuner_frequency < 895000000)
+		cp = 7;
+	else
+		return -EINVAL;
+
+	// determine band
+	if (p->frequency < 49000000)
+		return -EINVAL;
+	else if (p->frequency < 159000000)
+		band = 1;
+	else if (p->frequency < 444000000)
+		band = 2;
+	else if (p->frequency < 861000000)
+		band = 4;
+	else
+		return -EINVAL;
+
+	// setup PLL filter and TDA9889
+	switch (p->bandwidth_hz) {
+	case 6000000:
+		tda1004x_writereg(fe, 0x0C, 0x14);
+		filter = 0;
+		break;
+
+	case 7000000:
+		tda1004x_writereg(fe, 0x0C, 0x80);
+		filter = 0;
+		break;
+
+	case 8000000:
+		tda1004x_writereg(fe, 0x0C, 0x14);
+		filter = 1;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	// calculate divisor
+	// ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
+	tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000;
+
+	// setup tuner buffer
+	tuner_buf[0] = tuner_frequency >> 8;
+	tuner_buf[1] = tuner_frequency & 0xff;
+	tuner_buf[2] = 0xca;
+	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
+		return -EIO;
+
+	msleep(1);
+	return 0;
+}
+
+static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
+					     const struct firmware **fw, char *name)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
+
+	return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
+}
+
+static struct tda1004x_config philips_tdm1316l_config = {
+
+	.demod_address = 0x8,
+	.invert = 0,
+	.invert_oclk = 0,
+	.xtal_freq = TDA10046_XTAL_4M,
+	.agc_config = TDA10046_AGC_DEFAULT,
+	.if_freq = TDA10046_FREQ_3617,
+	.request_firmware = philips_tdm1316l_request_firmware,
+};
+
+static struct tda1004x_config philips_tdm1316l_config_invert = {
+
+	.demod_address = 0x8,
+	.invert = 1,
+	.invert_oclk = 0,
+	.xtal_freq = TDA10046_XTAL_4M,
+	.agc_config = TDA10046_AGC_DEFAULT,
+	.if_freq = TDA10046_FREQ_3617,
+	.request_firmware = philips_tdm1316l_request_firmware,
+};
+
+static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
+	u8 tuner_buf[5];
+	struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
+				    .flags = 0,
+				    .buf = tuner_buf,
+				    .len = sizeof(tuner_buf) };
+	int tuner_frequency = 0;
+	u8 band, cp, filter;
+
+	// determine charge pump
+	tuner_frequency = p->frequency + 36125000;
+	if (tuner_frequency < 87000000)
+		return -EINVAL;
+	else if (tuner_frequency < 130000000) {
+		cp = 3;
+		band = 1;
+	} else if (tuner_frequency < 160000000) {
+		cp = 5;
+		band = 1;
+	} else if (tuner_frequency < 200000000) {
+		cp = 6;
+		band = 1;
+	} else if (tuner_frequency < 290000000) {
+		cp = 3;
+		band = 2;
+	} else if (tuner_frequency < 420000000) {
+		cp = 5;
+		band = 2;
+	} else if (tuner_frequency < 480000000) {
+		cp = 6;
+		band = 2;
+	} else if (tuner_frequency < 620000000) {
+		cp = 3;
+		band = 4;
+	} else if (tuner_frequency < 830000000) {
+		cp = 5;
+		band = 4;
+	} else if (tuner_frequency < 895000000) {
+		cp = 7;
+		band = 4;
+	} else
+		return -EINVAL;
+
+	// assume PLL filter should always be 8MHz for the moment.
+	filter = 1;
+
+	// calculate divisor
+	tuner_frequency = (p->frequency + 36125000 + (62500/2)) / 62500;
+
+	// setup tuner buffer
+	tuner_buf[0] = tuner_frequency >> 8;
+	tuner_buf[1] = tuner_frequency & 0xff;
+	tuner_buf[2] = 0xc8;
+	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+	tuner_buf[4] = 0x80;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
+		return -EIO;
+
+	msleep(50);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
+		return -EIO;
+
+	msleep(1);
+
+	return 0;
+}
+
+static u8 dvbc_philips_tdm1316l_inittab[] = {
+	0x80, 0x01,
+	0x80, 0x00,
+	0x81, 0x01,
+	0x81, 0x00,
+	0x00, 0x09,
+	0x01, 0x69,
+	0x03, 0x00,
+	0x04, 0x00,
+	0x07, 0x00,
+	0x08, 0x00,
+	0x20, 0x00,
+	0x21, 0x40,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x24, 0x40,
+	0x25, 0x88,
+	0x30, 0xff,
+	0x31, 0x00,
+	0x32, 0xff,
+	0x33, 0x00,
+	0x34, 0x50,
+	0x35, 0x7f,
+	0x36, 0x00,
+	0x37, 0x20,
+	0x38, 0x00,
+	0x40, 0x1c,
+	0x41, 0xff,
+	0x42, 0x29,
+	0x43, 0x20,
+	0x44, 0xff,
+	0x45, 0x00,
+	0x46, 0x00,
+	0x49, 0x04,
+	0x4a, 0x00,
+	0x4b, 0x7b,
+	0x52, 0x30,
+	0x55, 0xae,
+	0x56, 0x47,
+	0x57, 0xe1,
+	0x58, 0x3a,
+	0x5a, 0x1e,
+	0x5b, 0x34,
+	0x60, 0x00,
+	0x63, 0x00,
+	0x64, 0x00,
+	0x65, 0x00,
+	0x66, 0x00,
+	0x67, 0x00,
+	0x68, 0x00,
+	0x69, 0x00,
+	0x6a, 0x02,
+	0x6b, 0x00,
+	0x70, 0xff,
+	0x71, 0x00,
+	0x72, 0x00,
+	0x73, 0x00,
+	0x74, 0x0c,
+	0x80, 0x00,
+	0x81, 0x00,
+	0x82, 0x00,
+	0x83, 0x00,
+	0x84, 0x04,
+	0x85, 0x80,
+	0x86, 0x24,
+	0x87, 0x78,
+	0x88, 0x10,
+	0x89, 0x00,
+	0x90, 0x01,
+	0x91, 0x01,
+	0xa0, 0x04,
+	0xa1, 0x00,
+	0xa2, 0x00,
+	0xb0, 0x91,
+	0xb1, 0x0b,
+	0xc0, 0x53,
+	0xc1, 0x70,
+	0xc2, 0x12,
+	0xd0, 0x00,
+	0xd1, 0x00,
+	0xd2, 0x00,
+	0xd3, 0x00,
+	0xd4, 0x00,
+	0xd5, 0x00,
+	0xde, 0x00,
+	0xdf, 0x00,
+	0x61, 0x38,
+	0x62, 0x0a,
+	0x53, 0x13,
+	0x59, 0x08,
+	0xff, 0xff,
+};
+
+static struct stv0297_config dvbc_philips_tdm1316l_config = {
+	.demod_address = 0x1c,
+	.inittab = dvbc_philips_tdm1316l_inittab,
+	.invert = 0,
+	.stop_during_read = 1,
+};
+
+static struct tda10023_config tda10023_config = {
+	.demod_address = 0xc,
+	.invert = 0,
+	.xtal = 16000000,
+	.pll_m = 11,
+	.pll_p = 3,
+	.pll_n = 1,
+	.deltaf = 0xa511,
+};
+
+static struct tda827x_config tda827x_config = {
+	.config = 0,
+};
+
+/* TT S2-3200 DVB-S (STB0899) Inittab */
+static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = {
+
+	{ STB0899_DEV_ID		, 0x81 },
+	{ STB0899_DISCNTRL1		, 0x32 },
+	{ STB0899_DISCNTRL2     	, 0x80 },
+	{ STB0899_DISRX_ST0     	, 0x04 },
+	{ STB0899_DISRX_ST1     	, 0x00 },
+	{ STB0899_DISPARITY     	, 0x00 },
+	{ STB0899_DISSTATUS		, 0x20 },
+	{ STB0899_DISF22        	, 0x8c },
+	{ STB0899_DISF22RX      	, 0x9a },
+	{ STB0899_SYSREG		, 0x0b },
+	{ STB0899_ACRPRESC      	, 0x11 },
+	{ STB0899_ACRDIV1       	, 0x0a },
+	{ STB0899_ACRDIV2       	, 0x05 },
+	{ STB0899_DACR1         	, 0x00 },
+	{ STB0899_DACR2         	, 0x00 },
+	{ STB0899_OUTCFG        	, 0x00 },
+	{ STB0899_MODECFG       	, 0x00 },
+	{ STB0899_IRQSTATUS_3		, 0x30 },
+	{ STB0899_IRQSTATUS_2		, 0x00 },
+	{ STB0899_IRQSTATUS_1		, 0x00 },
+	{ STB0899_IRQSTATUS_0		, 0x00 },
+	{ STB0899_IRQMSK_3      	, 0xf3 },
+	{ STB0899_IRQMSK_2      	, 0xfc },
+	{ STB0899_IRQMSK_1      	, 0xff },
+	{ STB0899_IRQMSK_0		, 0xff },
+	{ STB0899_IRQCFG		, 0x00 },
+	{ STB0899_I2CCFG        	, 0x88 },
+	{ STB0899_I2CRPT        	, 0x48 }, /* 12k Pullup, Repeater=16, Stop=disabled */
+	{ STB0899_IOPVALUE5		, 0x00 },
+	{ STB0899_IOPVALUE4		, 0x20 },
+	{ STB0899_IOPVALUE3		, 0xc9 },
+	{ STB0899_IOPVALUE2		, 0x90 },
+	{ STB0899_IOPVALUE1		, 0x40 },
+	{ STB0899_IOPVALUE0		, 0x00 },
+	{ STB0899_GPIO00CFG     	, 0x82 },
+	{ STB0899_GPIO01CFG     	, 0x82 },
+	{ STB0899_GPIO02CFG     	, 0x82 },
+	{ STB0899_GPIO03CFG     	, 0x82 },
+	{ STB0899_GPIO04CFG     	, 0x82 },
+	{ STB0899_GPIO05CFG     	, 0x82 },
+	{ STB0899_GPIO06CFG     	, 0x82 },
+	{ STB0899_GPIO07CFG     	, 0x82 },
+	{ STB0899_GPIO08CFG     	, 0x82 },
+	{ STB0899_GPIO09CFG     	, 0x82 },
+	{ STB0899_GPIO10CFG     	, 0x82 },
+	{ STB0899_GPIO11CFG     	, 0x82 },
+	{ STB0899_GPIO12CFG     	, 0x82 },
+	{ STB0899_GPIO13CFG     	, 0x82 },
+	{ STB0899_GPIO14CFG     	, 0x82 },
+	{ STB0899_GPIO15CFG     	, 0x82 },
+	{ STB0899_GPIO16CFG     	, 0x82 },
+	{ STB0899_GPIO17CFG     	, 0x82 },
+	{ STB0899_GPIO18CFG     	, 0x82 },
+	{ STB0899_GPIO19CFG     	, 0x82 },
+	{ STB0899_GPIO20CFG     	, 0x82 },
+	{ STB0899_SDATCFG       	, 0xb8 },
+	{ STB0899_SCLTCFG       	, 0xba },
+	{ STB0899_AGCRFCFG      	, 0x1c }, /* 0x11 */
+	{ STB0899_GPIO22        	, 0x82 }, /* AGCBB2CFG */
+	{ STB0899_GPIO21        	, 0x91 }, /* AGCBB1CFG */
+	{ STB0899_DIRCLKCFG     	, 0x82 },
+	{ STB0899_CLKOUT27CFG   	, 0x7e },
+	{ STB0899_STDBYCFG      	, 0x82 },
+	{ STB0899_CS0CFG        	, 0x82 },
+	{ STB0899_CS1CFG        	, 0x82 },
+	{ STB0899_DISEQCOCFG    	, 0x20 },
+	{ STB0899_GPIO32CFG		, 0x82 },
+	{ STB0899_GPIO33CFG		, 0x82 },
+	{ STB0899_GPIO34CFG		, 0x82 },
+	{ STB0899_GPIO35CFG		, 0x82 },
+	{ STB0899_GPIO36CFG		, 0x82 },
+	{ STB0899_GPIO37CFG		, 0x82 },
+	{ STB0899_GPIO38CFG		, 0x82 },
+	{ STB0899_GPIO39CFG		, 0x82 },
+	{ STB0899_NCOARSE       	, 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
+	{ STB0899_SYNTCTRL      	, 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
+	{ STB0899_FILTCTRL      	, 0x00 },
+	{ STB0899_SYSCTRL       	, 0x00 },
+	{ STB0899_STOPCLK1      	, 0x20 },
+	{ STB0899_STOPCLK2      	, 0x00 },
+	{ STB0899_INTBUFSTATUS		, 0x00 },
+	{ STB0899_INTBUFCTRL    	, 0x0a },
+	{ 0xffff			, 0xff },
+};
+
+static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = {
+	{ STB0899_DEMOD         	, 0x00 },
+	{ STB0899_RCOMPC        	, 0xc9 },
+	{ STB0899_AGC1CN        	, 0x41 },
+	{ STB0899_AGC1REF       	, 0x10 },
+	{ STB0899_RTC			, 0x7a },
+	{ STB0899_TMGCFG        	, 0x4e },
+	{ STB0899_AGC2REF       	, 0x34 },
+	{ STB0899_TLSR          	, 0x84 },
+	{ STB0899_CFD           	, 0xc7 },
+	{ STB0899_ACLC			, 0x87 },
+	{ STB0899_BCLC          	, 0x94 },
+	{ STB0899_EQON          	, 0x41 },
+	{ STB0899_LDT           	, 0xdd },
+	{ STB0899_LDT2          	, 0xc9 },
+	{ STB0899_EQUALREF      	, 0xb4 },
+	{ STB0899_TMGRAMP       	, 0x10 },
+	{ STB0899_TMGTHD        	, 0x30 },
+	{ STB0899_IDCCOMP		, 0xfb },
+	{ STB0899_QDCCOMP		, 0x03 },
+	{ STB0899_POWERI		, 0x3b },
+	{ STB0899_POWERQ		, 0x3d },
+	{ STB0899_RCOMP			, 0x81 },
+	{ STB0899_AGCIQIN		, 0x80 },
+	{ STB0899_AGC2I1		, 0x04 },
+	{ STB0899_AGC2I2		, 0xf5 },
+	{ STB0899_TLIR			, 0x25 },
+	{ STB0899_RTF			, 0x80 },
+	{ STB0899_DSTATUS		, 0x00 },
+	{ STB0899_LDI			, 0xca },
+	{ STB0899_CFRM			, 0xf1 },
+	{ STB0899_CFRL			, 0xf3 },
+	{ STB0899_NIRM			, 0x2a },
+	{ STB0899_NIRL			, 0x05 },
+	{ STB0899_ISYMB			, 0x17 },
+	{ STB0899_QSYMB			, 0xfa },
+	{ STB0899_SFRH          	, 0x2f },
+	{ STB0899_SFRM          	, 0x68 },
+	{ STB0899_SFRL          	, 0x40 },
+	{ STB0899_SFRUPH        	, 0x2f },
+	{ STB0899_SFRUPM        	, 0x68 },
+	{ STB0899_SFRUPL        	, 0x40 },
+	{ STB0899_EQUAI1		, 0xfd },
+	{ STB0899_EQUAQ1		, 0x04 },
+	{ STB0899_EQUAI2		, 0x0f },
+	{ STB0899_EQUAQ2		, 0xff },
+	{ STB0899_EQUAI3		, 0xdf },
+	{ STB0899_EQUAQ3		, 0xfa },
+	{ STB0899_EQUAI4		, 0x37 },
+	{ STB0899_EQUAQ4		, 0x0d },
+	{ STB0899_EQUAI5		, 0xbd },
+	{ STB0899_EQUAQ5		, 0xf7 },
+	{ STB0899_DSTATUS2		, 0x00 },
+	{ STB0899_VSTATUS       	, 0x00 },
+	{ STB0899_VERROR		, 0xff },
+	{ STB0899_IQSWAP		, 0x2a },
+	{ STB0899_ECNT1M		, 0x00 },
+	{ STB0899_ECNT1L		, 0x00 },
+	{ STB0899_ECNT2M		, 0x00 },
+	{ STB0899_ECNT2L		, 0x00 },
+	{ STB0899_ECNT3M		, 0x00 },
+	{ STB0899_ECNT3L		, 0x00 },
+	{ STB0899_FECAUTO1      	, 0x06 },
+	{ STB0899_FECM			, 0x01 },
+	{ STB0899_VTH12         	, 0xf0 },
+	{ STB0899_VTH23         	, 0xa0 },
+	{ STB0899_VTH34			, 0x78 },
+	{ STB0899_VTH56         	, 0x4e },
+	{ STB0899_VTH67         	, 0x48 },
+	{ STB0899_VTH78         	, 0x38 },
+	{ STB0899_PRVIT         	, 0xff },
+	{ STB0899_VITSYNC       	, 0x19 },
+	{ STB0899_RSULC         	, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+	{ STB0899_TSULC         	, 0x42 },
+	{ STB0899_RSLLC         	, 0x40 },
+	{ STB0899_TSLPL			, 0x12 },
+	{ STB0899_TSCFGH        	, 0x0c },
+	{ STB0899_TSCFGM        	, 0x00 },
+	{ STB0899_TSCFGL        	, 0x0c },
+	{ STB0899_TSOUT			, 0x4d }, /* 0x0d for CAM */
+	{ STB0899_RSSYNCDEL     	, 0x00 },
+	{ STB0899_TSINHDELH     	, 0x02 },
+	{ STB0899_TSINHDELM		, 0x00 },
+	{ STB0899_TSINHDELL		, 0x00 },
+	{ STB0899_TSLLSTKM		, 0x00 },
+	{ STB0899_TSLLSTKL		, 0x00 },
+	{ STB0899_TSULSTKM		, 0x00 },
+	{ STB0899_TSULSTKL		, 0xab },
+	{ STB0899_PCKLENUL		, 0x00 },
+	{ STB0899_PCKLENLL		, 0xcc },
+	{ STB0899_RSPCKLEN		, 0xcc },
+	{ STB0899_TSSTATUS		, 0x80 },
+	{ STB0899_ERRCTRL1      	, 0xb6 },
+	{ STB0899_ERRCTRL2      	, 0x96 },
+	{ STB0899_ERRCTRL3      	, 0x89 },
+	{ STB0899_DMONMSK1		, 0x27 },
+	{ STB0899_DMONMSK0		, 0x03 },
+	{ STB0899_DEMAPVIT      	, 0x5c },
+	{ STB0899_PLPARM		, 0x1f },
+	{ STB0899_PDELCTRL      	, 0x48 },
+	{ STB0899_PDELCTRL2     	, 0x00 },
+	{ STB0899_BBHCTRL1      	, 0x00 },
+	{ STB0899_BBHCTRL2      	, 0x00 },
+	{ STB0899_HYSTTHRESH    	, 0x77 },
+	{ STB0899_MATCSTM		, 0x00 },
+	{ STB0899_MATCSTL		, 0x00 },
+	{ STB0899_UPLCSTM		, 0x00 },
+	{ STB0899_UPLCSTL		, 0x00 },
+	{ STB0899_DFLCSTM		, 0x00 },
+	{ STB0899_DFLCSTL		, 0x00 },
+	{ STB0899_SYNCCST		, 0x00 },
+	{ STB0899_SYNCDCSTM		, 0x00 },
+	{ STB0899_SYNCDCSTL		, 0x00 },
+	{ STB0899_ISI_ENTRY		, 0x00 },
+	{ STB0899_ISI_BIT_EN		, 0x00 },
+	{ STB0899_MATSTRM		, 0x00 },
+	{ STB0899_MATSTRL		, 0x00 },
+	{ STB0899_UPLSTRM		, 0x00 },
+	{ STB0899_UPLSTRL		, 0x00 },
+	{ STB0899_DFLSTRM		, 0x00 },
+	{ STB0899_DFLSTRL		, 0x00 },
+	{ STB0899_SYNCSTR		, 0x00 },
+	{ STB0899_SYNCDSTRM		, 0x00 },
+	{ STB0899_SYNCDSTRL		, 0x00 },
+	{ STB0899_CFGPDELSTATUS1	, 0x10 },
+	{ STB0899_CFGPDELSTATUS2	, 0x00 },
+	{ STB0899_BBFERRORM		, 0x00 },
+	{ STB0899_BBFERRORL		, 0x00 },
+	{ STB0899_UPKTERRORM		, 0x00 },
+	{ STB0899_UPKTERRORL		, 0x00 },
+	{ 0xffff			, 0xff },
+};
+
+static struct stb0899_config tt3200_config = {
+	.init_dev		= tt3200_stb0899_s1_init_1,
+	.init_s2_demod		= stb0899_s2_init_2,
+	.init_s1_demod		= tt3200_stb0899_s1_init_3,
+	.init_s2_fec		= stb0899_s2_init_4,
+	.init_tst		= stb0899_s1_init_5,
+
+	.postproc		= NULL,
+
+	.demod_address 		= 0x68,
+
+	.xtal_freq		= 27000000,
+	.inversion		= IQ_SWAP_ON, /* 1 */
+
+	.lo_clk			= 76500000,
+	.hi_clk			= 99000000,
+
+	.esno_ave		= STB0899_DVBS2_ESNO_AVE,
+	.esno_quant		= STB0899_DVBS2_ESNO_QUANT,
+	.avframes_coarse	= STB0899_DVBS2_AVFRAMES_COARSE,
+	.avframes_fine		= STB0899_DVBS2_AVFRAMES_FINE,
+	.miss_threshold		= STB0899_DVBS2_MISS_THRESHOLD,
+	.uwp_threshold_acq	= STB0899_DVBS2_UWP_THRESHOLD_ACQ,
+	.uwp_threshold_track	= STB0899_DVBS2_UWP_THRESHOLD_TRACK,
+	.uwp_threshold_sof	= STB0899_DVBS2_UWP_THRESHOLD_SOF,
+	.sof_search_timeout	= STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
+
+	.btr_nco_bits		= STB0899_DVBS2_BTR_NCO_BITS,
+	.btr_gain_shift_offset	= STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+	.crl_nco_bits		= STB0899_DVBS2_CRL_NCO_BITS,
+	.ldpc_max_iter		= STB0899_DVBS2_LDPC_MAX_ITER,
+
+	.tuner_get_frequency	= stb6100_get_frequency,
+	.tuner_set_frequency	= stb6100_set_frequency,
+	.tuner_set_bandwidth	= stb6100_set_bandwidth,
+	.tuner_get_bandwidth	= stb6100_get_bandwidth,
+	.tuner_set_rfsiggain	= NULL
+};
+
+static struct stb6100_config tt3200_stb6100_config = {
+	.tuner_address	= 0x60,
+	.refclock	= 27000000,
+};
+
+static void frontend_init(struct budget_ci *budget_ci)
+{
+	switch (budget_ci->budget.dev->pci->subsystem_device) {
+	case 0x100c:		// Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
+		budget_ci->budget.dvb_frontend =
+			dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
+		if (budget_ci->budget.dvb_frontend) {
+			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+			budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
+			break;
+		}
+		break;
+
+	case 0x100f:		// Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
+		budget_ci->budget.dvb_frontend =
+			dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
+		if (budget_ci->budget.dvb_frontend) {
+			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
+			break;
+		}
+		break;
+
+	case 0x1010:		// TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
+		budget_ci->tuner_pll_address = 0x61;
+		budget_ci->budget.dvb_frontend =
+			dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+		if (budget_ci->budget.dvb_frontend) {
+			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
+			break;
+		}
+		break;
+
+	case 0x1011:		// Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
+		budget_ci->tuner_pll_address = 0x63;
+		budget_ci->budget.dvb_frontend =
+			dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+		if (budget_ci->budget.dvb_frontend) {
+			budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
+			break;
+		}
+		break;
+
+	case 0x1012:		// TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
+		budget_ci->tuner_pll_address = 0x60;
+		budget_ci->budget.dvb_frontend =
+			dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap);
+		if (budget_ci->budget.dvb_frontend) {
+			budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
+			break;
+		}
+		break;
+
+	case 0x1017:		// TT S-1500 PCI
+		budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
+		if (budget_ci->budget.dvb_frontend) {
+			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
+			budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
+
+			budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
+			if (dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0) == NULL) {
+				printk("%s: No LNBP21 found!\n", __func__);
+				dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+				budget_ci->budget.dvb_frontend = NULL;
+			}
+		}
+		break;
+
+	case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */
+		budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48);
+		if (budget_ci->budget.dvb_frontend) {
+			if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, &tda827x_config) == NULL) {
+				printk(KERN_ERR "%s: No tda827x found!\n", __func__);
+				dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+				budget_ci->budget.dvb_frontend = NULL;
+			}
+		}
+		break;
+
+	case 0x101b: /* TT S-1500B (BSBE1-D01A - STV0288/STB6000/LNBP21) */
+		budget_ci->budget.dvb_frontend = dvb_attach(stv0288_attach, &stv0288_bsbe1_d01a_config, &budget_ci->budget.i2c_adap);
+		if (budget_ci->budget.dvb_frontend) {
+			if (dvb_attach(stb6000_attach, budget_ci->budget.dvb_frontend, 0x63, &budget_ci->budget.i2c_adap)) {
+				if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) {
+					printk(KERN_ERR "%s: No LNBP21 found!\n", __func__);
+					dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+					budget_ci->budget.dvb_frontend = NULL;
+				}
+			} else {
+				printk(KERN_ERR "%s: No STB6000 found!\n", __func__);
+				dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+				budget_ci->budget.dvb_frontend = NULL;
+			}
+		}
+		break;
+
+	case 0x1019:		// TT S2-3200 PCI
+		/*
+		 * NOTE! on some STB0899 versions, the internal PLL takes a longer time
+		 * to settle, aka LOCK. On the older revisions of the chip, we don't see
+		 * this, as a result on the newer chips the entire clock tree, will not
+		 * be stable after a freshly POWER 'ed up situation.
+		 * In this case, we should RESET the STB0899 (Active LOW) and wait for
+		 * PLL stabilization.
+		 *
+		 * On the TT S2 3200 and clones, the STB0899 demodulator's RESETB is
+		 * connected to the SAA7146 GPIO, GPIO2, Pin 142
+		 */
+		/* Reset Demodulator */
+		saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTLO);
+		/* Wait for everything to die */
+		msleep(50);
+		/* Pull it up out of Reset state */
+		saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTHI);
+		/* Wait for PLL to stabilize */
+		msleep(250);
+		/*
+		 * PLL state should be stable now. Ideally, we should check
+		 * for PLL LOCK status. But well, never mind!
+		 */
+		budget_ci->budget.dvb_frontend = dvb_attach(stb0899_attach, &tt3200_config, &budget_ci->budget.i2c_adap);
+		if (budget_ci->budget.dvb_frontend) {
+			if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) {
+				if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) {
+					printk("%s: No LNBP21 found!\n", __func__);
+					dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+					budget_ci->budget.dvb_frontend = NULL;
+				}
+			} else {
+					dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+					budget_ci->budget.dvb_frontend = NULL;
+			}
+		}
+		break;
+
+	}
+
+	if (budget_ci->budget.dvb_frontend == NULL) {
+		printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
+		       budget_ci->budget.dev->pci->vendor,
+		       budget_ci->budget.dev->pci->device,
+		       budget_ci->budget.dev->pci->subsystem_vendor,
+		       budget_ci->budget.dev->pci->subsystem_device);
+	} else {
+		if (dvb_register_frontend
+		    (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
+			printk("budget-ci: Frontend registration failed!\n");
+			dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+			budget_ci->budget.dvb_frontend = NULL;
+		}
+	}
+}
+
+static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
+{
+	struct budget_ci *budget_ci;
+	int err;
+
+	budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL);
+	if (!budget_ci) {
+		err = -ENOMEM;
+		goto out1;
+	}
+
+	dprintk(2, "budget_ci: %p\n", budget_ci);
+
+	dev->ext_priv = budget_ci;
+
+	err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE,
+				adapter_nr);
+	if (err)
+		goto out2;
+
+	err = msp430_ir_init(budget_ci);
+	if (err)
+		goto out3;
+
+	ciintf_init(budget_ci);
+
+	budget_ci->budget.dvb_adapter.priv = budget_ci;
+	frontend_init(budget_ci);
+
+	ttpci_budget_init_hooks(&budget_ci->budget);
+
+	return 0;
+
+out3:
+	ttpci_budget_deinit(&budget_ci->budget);
+out2:
+	kfree(budget_ci);
+out1:
+	return err;
+}
+
+static int budget_ci_detach(struct saa7146_dev *dev)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
+	struct saa7146_dev *saa = budget_ci->budget.dev;
+	int err;
+
+	if (budget_ci->budget.ci_present)
+		ciintf_deinit(budget_ci);
+	msp430_ir_deinit(budget_ci);
+	if (budget_ci->budget.dvb_frontend) {
+		dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
+		dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+	}
+	err = ttpci_budget_deinit(&budget_ci->budget);
+
+	// disable frontend and CI interface
+	saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
+
+	kfree(budget_ci);
+
+	return err;
+}
+
+static struct saa7146_extension budget_extension;
+
+MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
+MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T	 PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(ttbs1500b, "TT-Budget S-1500B PCI", BUDGET_TT);
+
+static struct pci_device_id pci_tbl[] = {
+	MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
+	MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
+	MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
+	MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
+	MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
+	MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
+	MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a),
+	MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019),
+	MAKE_EXTENSION_PCI(ttbs1500b, 0x13c2, 0x101b),
+	{
+	 .vendor = 0,
+	 }
+};
+
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+static struct saa7146_extension budget_extension = {
+	.name = "budget_ci dvb",
+	.flags = SAA7146_USE_I2C_IRQ,
+
+	.module = THIS_MODULE,
+	.pci_tbl = &pci_tbl[0],
+	.attach = budget_ci_attach,
+	.detach = budget_ci_detach,
+
+	.irq_mask = MASK_03 | MASK_06 | MASK_10,
+	.irq_func = budget_ci_irq,
+};
+
+static int __init budget_ci_init(void)
+{
+	return saa7146_register_extension(&budget_extension);
+}
+
+static void __exit budget_ci_exit(void)
+{
+	saa7146_unregister_extension(&budget_extension);
+}
+
+module_init(budget_ci_init);
+module_exit(budget_ci_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
+MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
+		   "budget PCI DVB cards w/ CI-module produced by "
+		   "Siemens, Technotrend, Hauppauge");
diff --git a/drivers/media/pci/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c
new file mode 100644
index 0000000..37d02fe
--- /dev/null
+++ b/drivers/media/pci/ttpci/budget-core.c
@@ -0,0 +1,602 @@
+/*
+ * budget-core.c: driver for the SAA7146 based Budget DVB cards
+ *
+ * Compiled from various sources by Michael Hunold <michael@mihu.de>
+ *
+ * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
+ *
+ * Copyright (C) 1999-2002 Ralph  Metzler
+ *			 & Marcus Metzler for convergence integrated media GmbH
+ *
+ * 26feb2004 Support for FS Activy Card (Grundig tuner) by
+ *	     Michael Dreher <michael@5dot1.de>,
+ *	     Oliver Endriss <o.endriss@gmx.de>,
+ *	     Andreas 'randy' Weinberger
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org/ 
+ */
+
+
+#include "budget.h"
+#include "ttpci-eeprom.h"
+
+#define TS_WIDTH		(2 * TS_SIZE)
+#define TS_WIDTH_ACTIVY		TS_SIZE
+#define TS_WIDTH_DVBC		TS_SIZE
+#define TS_HEIGHT_MASK		0xf00
+#define TS_HEIGHT_MASK_ACTIVY	0xc00
+#define TS_HEIGHT_MASK_DVBC	0xe00
+#define TS_MIN_BUFSIZE_K	188
+#define TS_MAX_BUFSIZE_K	1410
+#define TS_MAX_BUFSIZE_K_ACTIVY	564
+#define TS_MAX_BUFSIZE_K_DVBC	1316
+#define BUFFER_WARNING_WAIT	(30*HZ)
+
+int budget_debug;
+static int dma_buffer_size = TS_MIN_BUFSIZE_K;
+module_param_named(debug, budget_debug, int, 0644);
+module_param_named(bufsize, dma_buffer_size, int, 0444);
+MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off).");
+MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)");
+
+/****************************************************************************
+ * TT budget / WinTV Nova
+ ****************************************************************************/
+
+static int stop_ts_capture(struct budget *budget)
+{
+	dprintk(2, "budget: %p\n", budget);
+
+	saa7146_write(budget->dev, MC1, MASK_20);	// DMA3 off
+	SAA7146_IER_DISABLE(budget->dev, MASK_10);
+	return 0;
+}
+
+static int start_ts_capture(struct budget *budget)
+{
+	struct saa7146_dev *dev = budget->dev;
+
+	dprintk(2, "budget: %p\n", budget);
+
+	if (!budget->feeding || !budget->fe_synced)
+		return 0;
+
+	saa7146_write(dev, MC1, MASK_20);	// DMA3 off
+
+	memset(budget->grabbing, 0x00, budget->buffer_size);
+
+	saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000));
+
+	budget->ttbp = 0;
+
+	/*
+	 *  Signal path on the Activy:
+	 *
+	 *  tuner -> SAA7146 port A -> SAA7146 BRS -> SAA7146 DMA3 -> memory
+	 *
+	 *  Since the tuner feeds 204 bytes packets into the SAA7146,
+	 *  DMA3 is configured to strip the trailing 16 FEC bytes:
+	 *      Pitch: 188, NumBytes3: 188, NumLines3: 1024
+	 */
+
+	switch(budget->card->type) {
+	case BUDGET_FS_ACTIVY:
+		saa7146_write(dev, DD1_INIT, 0x04000000);
+		saa7146_write(dev, MC2, (MASK_09 | MASK_25));
+		saa7146_write(dev, BRS_CTRL, 0x00000000);
+		break;
+	case BUDGET_PATCH:
+		saa7146_write(dev, DD1_INIT, 0x00000200);
+		saa7146_write(dev, MC2, (MASK_10 | MASK_26));
+		saa7146_write(dev, BRS_CTRL, 0x60000000);
+		break;
+	case BUDGET_CIN1200C_MK3:
+	case BUDGET_KNC1C_MK3:
+	case BUDGET_KNC1C_TDA10024:
+	case BUDGET_KNC1CP_MK3:
+		if (budget->video_port == BUDGET_VIDEO_PORTA) {
+			saa7146_write(dev, DD1_INIT, 0x06000200);
+			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+			saa7146_write(dev, BRS_CTRL, 0x00000000);
+		} else {
+			saa7146_write(dev, DD1_INIT, 0x00000600);
+			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+			saa7146_write(dev, BRS_CTRL, 0x60000000);
+		}
+		break;
+	default:
+		if (budget->video_port == BUDGET_VIDEO_PORTA) {
+			saa7146_write(dev, DD1_INIT, 0x06000200);
+			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+			saa7146_write(dev, BRS_CTRL, 0x00000000);
+		} else {
+			saa7146_write(dev, DD1_INIT, 0x02000600);
+			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+			saa7146_write(dev, BRS_CTRL, 0x60000000);
+		}
+	}
+
+	saa7146_write(dev, MC2, (MASK_08 | MASK_24));
+	mdelay(10);
+
+	saa7146_write(dev, BASE_ODD3, 0);
+	if (budget->buffer_size > budget->buffer_height * budget->buffer_width) {
+		// using odd/even buffers
+		saa7146_write(dev, BASE_EVEN3, budget->buffer_height * budget->buffer_width);
+	} else {
+		// using a single buffer
+		saa7146_write(dev, BASE_EVEN3, 0);
+	}
+	saa7146_write(dev, PROT_ADDR3, budget->buffer_size);
+	saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90);
+
+	saa7146_write(dev, PITCH3, budget->buffer_width);
+	saa7146_write(dev, NUM_LINE_BYTE3,
+			(budget->buffer_height << 16) | budget->buffer_width);
+
+	saa7146_write(dev, MC2, (MASK_04 | MASK_20));
+
+	SAA7146_ISR_CLEAR(budget->dev, MASK_10);	/* VPE */
+	SAA7146_IER_ENABLE(budget->dev, MASK_10);	/* VPE */
+	saa7146_write(dev, MC1, (MASK_04 | MASK_20));	/* DMA3 on */
+
+	return 0;
+}
+
+static int budget_read_fe_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct budget *budget = (struct budget *) fe->dvb->priv;
+	int synced;
+	int ret;
+
+	if (budget->read_fe_status)
+		ret = budget->read_fe_status(fe, status);
+	else
+		ret = -EINVAL;
+
+	if (!ret) {
+		synced = (*status & FE_HAS_LOCK);
+		if (synced != budget->fe_synced) {
+			budget->fe_synced = synced;
+			spin_lock(&budget->feedlock);
+			if (synced)
+				start_ts_capture(budget);
+			else
+				stop_ts_capture(budget);
+			spin_unlock(&budget->feedlock);
+		}
+	}
+	return ret;
+}
+
+static void vpeirq(unsigned long data)
+{
+	struct budget *budget = (struct budget *) data;
+	u8 *mem = (u8 *) (budget->grabbing);
+	u32 olddma = budget->ttbp;
+	u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
+	u32 count;
+
+	/* Ensure streamed PCI data is synced to CPU */
+	pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE);
+
+	/* nearest lower position divisible by 188 */
+	newdma -= newdma % 188;
+
+	if (newdma >= budget->buffer_size)
+		return;
+
+	budget->ttbp = newdma;
+
+	if (budget->feeding == 0 || newdma == olddma)
+		return;
+
+	if (newdma > olddma) {	/* no wraparound, dump olddma..newdma */
+		count = newdma - olddma;
+		dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188);
+	} else {		/* wraparound, dump olddma..buflen and 0..newdma */
+		count = budget->buffer_size - olddma;
+		dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188);
+		count += newdma;
+		dvb_dmx_swfilter_packets(&budget->demux, mem, newdma / 188);
+	}
+
+	if (count > budget->buffer_warning_threshold)
+		budget->buffer_warnings++;
+
+	if (budget->buffer_warnings && time_after(jiffies, budget->buffer_warning_time)) {
+		printk("%s %s: used %d times >80%% of buffer (%u bytes now)\n",
+			budget->dev->name, __func__, budget->buffer_warnings, count);
+		budget->buffer_warning_time = jiffies + BUFFER_WARNING_WAIT;
+		budget->buffer_warnings = 0;
+	}
+}
+
+
+int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count,
+			  int uselocks, int nobusyloop)
+{
+	struct saa7146_dev *saa = budget->dev;
+	int result = 0;
+	unsigned long flags = 0;
+
+	if (count > 4 || count <= 0)
+		return 0;
+
+	if (uselocks)
+		spin_lock_irqsave(&budget->debilock, flags);
+
+	if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
+		if (uselocks)
+			spin_unlock_irqrestore(&budget->debilock, flags);
+		return result;
+	}
+
+	saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
+	saa7146_write(saa, DEBI_CONFIG, config);
+	saa7146_write(saa, DEBI_PAGE, 0);
+	saa7146_write(saa, MC2, (2 << 16) | 2);
+
+	if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
+		if (uselocks)
+			spin_unlock_irqrestore(&budget->debilock, flags);
+		return result;
+	}
+
+	result = saa7146_read(saa, DEBI_AD);
+	result &= (0xffffffffUL >> ((4 - count) * 8));
+
+	if (uselocks)
+		spin_unlock_irqrestore(&budget->debilock, flags);
+
+	return result;
+}
+
+int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr,
+			   int count, u32 value, int uselocks, int nobusyloop)
+{
+	struct saa7146_dev *saa = budget->dev;
+	unsigned long flags = 0;
+	int result;
+
+	if (count > 4 || count <= 0)
+		return 0;
+
+	if (uselocks)
+		spin_lock_irqsave(&budget->debilock, flags);
+
+	if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
+		if (uselocks)
+			spin_unlock_irqrestore(&budget->debilock, flags);
+		return result;
+	}
+
+	saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x00000 | (addr & 0xffff));
+	saa7146_write(saa, DEBI_CONFIG, config);
+	saa7146_write(saa, DEBI_PAGE, 0);
+	saa7146_write(saa, DEBI_AD, value);
+	saa7146_write(saa, MC2, (2 << 16) | 2);
+
+	if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
+		if (uselocks)
+			spin_unlock_irqrestore(&budget->debilock, flags);
+		return result;
+	}
+
+	if (uselocks)
+		spin_unlock_irqrestore(&budget->debilock, flags);
+	return 0;
+}
+
+
+/****************************************************************************
+ * DVB API SECTION
+ ****************************************************************************/
+
+static int budget_start_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct budget *budget = (struct budget *) demux->priv;
+	int status = 0;
+
+	dprintk(2, "budget: %p\n", budget);
+
+	if (!demux->dmx.frontend)
+		return -EINVAL;
+
+	spin_lock(&budget->feedlock);
+	feed->pusi_seen = 0; /* have a clean section start */
+	if (budget->feeding++ == 0)
+		status = start_ts_capture(budget);
+	spin_unlock(&budget->feedlock);
+	return status;
+}
+
+static int budget_stop_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct budget *budget = (struct budget *) demux->priv;
+	int status = 0;
+
+	dprintk(2, "budget: %p\n", budget);
+
+	spin_lock(&budget->feedlock);
+	if (--budget->feeding == 0)
+		status = stop_ts_capture(budget);
+	spin_unlock(&budget->feedlock);
+	return status;
+}
+
+static int budget_register(struct budget *budget)
+{
+	struct dvb_demux *dvbdemux = &budget->demux;
+	int ret;
+
+	dprintk(2, "budget: %p\n", budget);
+
+	dvbdemux->priv = (void *) budget;
+
+	dvbdemux->filternum = 256;
+	dvbdemux->feednum = 256;
+	dvbdemux->start_feed = budget_start_feed;
+	dvbdemux->stop_feed = budget_stop_feed;
+	dvbdemux->write_to_decoder = NULL;
+
+	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+				      DMX_MEMORY_BASED_FILTERING);
+
+	dvb_dmx_init(&budget->demux);
+
+	budget->dmxdev.filternum = 256;
+	budget->dmxdev.demux = &dvbdemux->dmx;
+	budget->dmxdev.capabilities = 0;
+
+	dvb_dmxdev_init(&budget->dmxdev, &budget->dvb_adapter);
+
+	budget->hw_frontend.source = DMX_FRONTEND_0;
+
+	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->hw_frontend);
+
+	if (ret < 0)
+		return ret;
+
+	budget->mem_frontend.source = DMX_MEMORY_FE;
+	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->mem_frontend);
+	if (ret < 0)
+		return ret;
+
+	ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &budget->hw_frontend);
+	if (ret < 0)
+		return ret;
+
+	dvb_net_init(&budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx);
+
+	return 0;
+}
+
+static void budget_unregister(struct budget *budget)
+{
+	struct dvb_demux *dvbdemux = &budget->demux;
+
+	dprintk(2, "budget: %p\n", budget);
+
+	dvb_net_release(&budget->dvb_net);
+
+	dvbdemux->dmx.close(&dvbdemux->dmx);
+	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->hw_frontend);
+	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->mem_frontend);
+
+	dvb_dmxdev_release(&budget->dmxdev);
+	dvb_dmx_release(&budget->demux);
+}
+
+int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
+		      struct saa7146_pci_extension_data *info,
+		      struct module *owner, short *adapter_nums)
+{
+	int ret = 0;
+	struct budget_info *bi = info->ext_priv;
+	int max_bufsize;
+	int height_mask;
+
+	memset(budget, 0, sizeof(struct budget));
+
+	dprintk(2, "dev: %p, budget: %p\n", dev, budget);
+
+	budget->card = bi;
+	budget->dev = (struct saa7146_dev *) dev;
+
+	switch(budget->card->type) {
+	case BUDGET_FS_ACTIVY:
+		budget->buffer_width = TS_WIDTH_ACTIVY;
+		max_bufsize = TS_MAX_BUFSIZE_K_ACTIVY;
+		height_mask = TS_HEIGHT_MASK_ACTIVY;
+		break;
+
+	case BUDGET_KNC1C:
+	case BUDGET_KNC1CP:
+	case BUDGET_CIN1200C:
+	case BUDGET_KNC1C_MK3:
+	case BUDGET_KNC1C_TDA10024:
+	case BUDGET_KNC1CP_MK3:
+	case BUDGET_CIN1200C_MK3:
+		budget->buffer_width = TS_WIDTH_DVBC;
+		max_bufsize = TS_MAX_BUFSIZE_K_DVBC;
+		height_mask = TS_HEIGHT_MASK_DVBC;
+		break;
+
+	default:
+		budget->buffer_width = TS_WIDTH;
+		max_bufsize = TS_MAX_BUFSIZE_K;
+		height_mask = TS_HEIGHT_MASK;
+	}
+
+	if (dma_buffer_size < TS_MIN_BUFSIZE_K)
+		dma_buffer_size = TS_MIN_BUFSIZE_K;
+	else if (dma_buffer_size > max_bufsize)
+		dma_buffer_size = max_bufsize;
+
+	budget->buffer_height = dma_buffer_size * 1024 / budget->buffer_width;
+	if (budget->buffer_height > 0xfff) {
+		budget->buffer_height /= 2;
+		budget->buffer_height &= height_mask;
+		budget->buffer_size = 2 * budget->buffer_height * budget->buffer_width;
+	} else {
+		budget->buffer_height &= height_mask;
+		budget->buffer_size = budget->buffer_height * budget->buffer_width;
+	}
+	budget->buffer_warning_threshold = budget->buffer_size * 80/100;
+	budget->buffer_warnings = 0;
+	budget->buffer_warning_time = jiffies;
+
+	dprintk(2, "%s: buffer type = %s, width = %d, height = %d\n",
+		budget->dev->name,
+		budget->buffer_size > budget->buffer_width * budget->buffer_height ? "odd/even" : "single",
+		budget->buffer_width, budget->buffer_height);
+	printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size);
+
+	ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name,
+				   owner, &budget->dev->pci->dev, adapter_nums);
+	if (ret < 0)
+		return ret;
+
+	/* set dd1 stream a & b */
+	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
+	saa7146_write(dev, MC2, (MASK_09 | MASK_25));
+	saa7146_write(dev, MC2, (MASK_10 | MASK_26));
+	saa7146_write(dev, DD1_INIT, 0x02000000);
+	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+
+	if (bi->type != BUDGET_FS_ACTIVY)
+		budget->video_port = BUDGET_VIDEO_PORTB;
+	else
+		budget->video_port = BUDGET_VIDEO_PORTA;
+	spin_lock_init(&budget->feedlock);
+	spin_lock_init(&budget->debilock);
+
+	/* the Siemens DVB needs this if you want to have the i2c chips
+	   get recognized before the main driver is loaded */
+	if (bi->type != BUDGET_FS_ACTIVY)
+		saa7146_write(dev, GPIO_CTRL, 0x500000);	/* GPIO 3 = 1 */
+
+	strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name));
+
+	saa7146_i2c_adapter_prepare(dev, &budget->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120);
+	strcpy(budget->i2c_adap.name, budget->card->name);
+
+	if (i2c_add_adapter(&budget->i2c_adap) < 0) {
+		ret = -ENOMEM;
+		goto err_dvb_unregister;
+	}
+
+	ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac);
+
+	budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, budget->buffer_size, &budget->pt);
+	if (NULL == budget->grabbing) {
+		ret = -ENOMEM;
+		goto err_del_i2c;
+	}
+
+	saa7146_write(dev, PCI_BT_V1, 0x001c0000);
+	/* upload all */
+	saa7146_write(dev, GPIO_CTRL, 0x000000);
+
+	tasklet_init(&budget->vpe_tasklet, vpeirq, (unsigned long) budget);
+
+	/* frontend power on */
+	if (bi->type != BUDGET_FS_ACTIVY)
+		saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
+
+	if ((ret = budget_register(budget)) == 0)
+		return 0; /* Everything OK */
+
+	/* An error occurred, cleanup resources */
+	saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt);
+
+err_del_i2c:
+	i2c_del_adapter(&budget->i2c_adap);
+
+err_dvb_unregister:
+	dvb_unregister_adapter(&budget->dvb_adapter);
+
+	return ret;
+}
+
+void ttpci_budget_init_hooks(struct budget *budget)
+{
+	if (budget->dvb_frontend && !budget->read_fe_status) {
+		budget->read_fe_status = budget->dvb_frontend->ops.read_status;
+		budget->dvb_frontend->ops.read_status = budget_read_fe_status;
+	}
+}
+
+int ttpci_budget_deinit(struct budget *budget)
+{
+	struct saa7146_dev *dev = budget->dev;
+
+	dprintk(2, "budget: %p\n", budget);
+
+	budget_unregister(budget);
+
+	tasklet_kill(&budget->vpe_tasklet);
+
+	saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt);
+
+	i2c_del_adapter(&budget->i2c_adap);
+
+	dvb_unregister_adapter(&budget->dvb_adapter);
+
+	return 0;
+}
+
+void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr)
+{
+	struct budget *budget = (struct budget *) dev->ext_priv;
+
+	dprintk(8, "dev: %p, budget: %p\n", dev, budget);
+
+	if (*isr & MASK_10)
+		tasklet_schedule(&budget->vpe_tasklet);
+}
+
+void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port)
+{
+	struct budget *budget = (struct budget *) dev->ext_priv;
+
+	spin_lock(&budget->feedlock);
+	budget->video_port = video_port;
+	if (budget->feeding) {
+		stop_ts_capture(budget);
+		start_ts_capture(budget);
+	}
+	spin_unlock(&budget->feedlock);
+}
+
+EXPORT_SYMBOL_GPL(ttpci_budget_debiread);
+EXPORT_SYMBOL_GPL(ttpci_budget_debiwrite);
+EXPORT_SYMBOL_GPL(ttpci_budget_init);
+EXPORT_SYMBOL_GPL(ttpci_budget_init_hooks);
+EXPORT_SYMBOL_GPL(ttpci_budget_deinit);
+EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler);
+EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port);
+EXPORT_SYMBOL_GPL(budget_debug);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/ttpci/budget-patch.c b/drivers/media/pci/ttpci/budget-patch.c
new file mode 100644
index 0000000..2cb35c2
--- /dev/null
+++ b/drivers/media/pci/ttpci/budget-patch.c
@@ -0,0 +1,680 @@
+/*
+ * budget-patch.c: driver for Budget Patch,
+ * hardware modification of DVB-S cards enabling full TS
+ *
+ * Written by Emard <emard@softhome.net>
+ *
+ * Original idea by Roberto Deza <rdeza@unav.es>
+ *
+ * Special thanks to Holger Waechtler, Michael Hunold, Marian Durkovic
+ * and Metzlerbros
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org/ 
+ */
+
+#include "av7110.h"
+#include "av7110_hw.h"
+#include "budget.h"
+#include "stv0299.h"
+#include "ves1x93.h"
+#include "tda8083.h"
+
+#include "bsru6.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define budget_patch budget
+
+static struct saa7146_extension budget_extension;
+
+MAKE_BUDGET_INFO(ttbp, "TT-Budget/Patch DVB-S 1.x PCI", BUDGET_PATCH);
+//MAKE_BUDGET_INFO(satel,"TT-Budget/Patch SATELCO PCI", BUDGET_TT_HW_DISEQC);
+
+static struct pci_device_id pci_tbl[] = {
+	MAKE_EXTENSION_PCI(ttbp,0x13c2, 0x0000),
+//        MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
+	{
+		.vendor    = 0,
+	}
+};
+
+/* those lines are for budget-patch to be tried
+** on a true budget card and observe the
+** behaviour of VSYNC generated by rps1.
+** this code was shamelessly copy/pasted from budget.c
+*/
+static void gpio_Set22K (struct budget *budget, int state)
+{
+	struct saa7146_dev *dev=budget->dev;
+	dprintk(2, "budget: %p\n", budget);
+	saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO));
+}
+
+/* Diseqc functions only for TT Budget card */
+/* taken from the Skyvision DVB driver by
+   Ralph Metzler <rjkm@metzlerbros.de> */
+
+static void DiseqcSendBit (struct budget *budget, int data)
+{
+	struct saa7146_dev *dev=budget->dev;
+	dprintk(2, "budget: %p\n", budget);
+
+	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
+	udelay(data ? 500 : 1000);
+	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+	udelay(data ? 1000 : 500);
+}
+
+static void DiseqcSendByte (struct budget *budget, int data)
+{
+	int i, par=1, d;
+
+	dprintk(2, "budget: %p\n", budget);
+
+	for (i=7; i>=0; i--) {
+		d = (data>>i)&1;
+		par ^= d;
+		DiseqcSendBit(budget, d);
+	}
+
+	DiseqcSendBit(budget, par);
+}
+
+static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst)
+{
+	struct saa7146_dev *dev=budget->dev;
+	int i;
+
+	dprintk(2, "budget: %p\n", budget);
+
+	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+	mdelay(16);
+
+	for (i=0; i<len; i++)
+		DiseqcSendByte(budget, msg[i]);
+
+	mdelay(16);
+
+	if (burst!=-1) {
+		if (burst)
+			DiseqcSendByte(budget, 0xff);
+		else {
+			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
+			mdelay(12);
+			udelay(500);
+			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+		}
+		msleep(20);
+	}
+
+	return 0;
+}
+
+/* shamelessly copy/pasted from budget.c
+*/
+static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		gpio_Set22K (budget, 1);
+		break;
+
+	case SEC_TONE_OFF:
+		gpio_Set22K (budget, 0);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+
+	SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
+
+	return 0;
+}
+
+static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+
+	SendDiSEqCMsg (budget, 0, NULL, minicmd);
+
+	return 0;
+}
+
+static int budget_av7110_send_fw_cmd(struct budget_patch *budget, u16* buf, int length)
+{
+	int i;
+
+	dprintk(2, "budget: %p\n", budget);
+
+	for (i = 2; i < length; i++)
+	{
+		  ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2*i, 2, (u32) buf[i], 0,0);
+		  msleep(5);
+	}
+	if (length)
+		  ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, (u32) buf[1], 0,0);
+	else
+		  ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, 0, 0,0);
+	msleep(5);
+	ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND, 2, (u32) buf[0], 0,0);
+	msleep(5);
+	return 0;
+}
+
+static void av7110_set22k(struct budget_patch *budget, int state)
+{
+	u16 buf[2] = {( COMTYPE_AUDIODAC << 8) | (state ? ON22K : OFF22K), 0};
+
+	dprintk(2, "budget: %p\n", budget);
+	budget_av7110_send_fw_cmd(budget, buf, 2);
+}
+
+static int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg, int burst)
+{
+	int i;
+	u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) | SendDiSEqC),
+		16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+	dprintk(2, "budget: %p\n", budget);
+
+	if (len>10)
+		len=10;
+
+	buf[1] = len+2;
+	buf[2] = len;
+
+	if (burst != -1)
+		buf[3]=burst ? 0x01 : 0x00;
+	else
+		buf[3]=0xffff;
+
+	for (i=0; i<len; i++)
+		buf[i+4]=msg[i];
+
+	budget_av7110_send_fw_cmd(budget, buf, 18);
+	return 0;
+}
+
+static int budget_patch_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		av7110_set22k (budget, 1);
+		break;
+
+	case SEC_TONE_OFF:
+		av7110_set22k (budget, 0);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+
+	av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0);
+
+	return 0;
+}
+
+static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+
+	av7110_send_diseqc_msg (budget, 0, NULL, minicmd);
+
+	return 0;
+}
+
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+	u8 pwr = 0;
+	u8 buf[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	u32 div = (p->frequency + 479500) / 125;
+
+	if (p->frequency > 2000000)
+		pwr = 3;
+	else if (p->frequency > 1800000)
+		pwr = 2;
+	else if (p->frequency > 1600000)
+		pwr = 1;
+	else if (p->frequency > 1200000)
+		pwr = 0;
+	else if (p->frequency >= 1100000)
+		pwr = 1;
+	else pwr = 2;
+
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = ((div & 0x18000) >> 10) | 0x95;
+	buf[3] = (pwr << 6) | 0x30;
+
+	// NOTE: since we're using a prescaler of 2, we set the
+	// divisor frequency to 62.5kHz and divide by 125 above
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static struct ves1x93_config alps_bsrv2_config = {
+	.demod_address = 0x08,
+	.xin = 90100000UL,
+	.invert_pwm = 0,
+};
+
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+	u32 div;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = p->frequency / 125;
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x8e;
+	data[3] = 0x00;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static struct tda8083_config grundig_29504_451_config = {
+	.demod_address = 0x68,
+};
+
+static void frontend_init(struct budget_patch* budget)
+{
+	switch(budget->dev->pci->subsystem_device) {
+	case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X
+	case 0x1013: // SATELCO Multimedia PCI
+
+		// try the ALPS BSRV2 first of all
+		budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+			budget->dvb_frontend->ops.diseqc_send_burst = budget_patch_diseqc_send_burst;
+			budget->dvb_frontend->ops.set_tone = budget_patch_set_tone;
+			break;
+		}
+
+		// try the ALPS BSRU6 now
+		budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+
+			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+			budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+			budget->dvb_frontend->ops.set_tone = budget_set_tone;
+			break;
+		}
+
+		// Try the grundig 29504-451
+		budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+			budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+			budget->dvb_frontend->ops.set_tone = budget_set_tone;
+			break;
+		}
+		break;
+	}
+
+	if (budget->dvb_frontend == NULL) {
+		printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
+		       budget->dev->pci->vendor,
+		       budget->dev->pci->device,
+		       budget->dev->pci->subsystem_vendor,
+		       budget->dev->pci->subsystem_device);
+	} else {
+		if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
+			printk("budget-av: Frontend registration failed!\n");
+			dvb_frontend_detach(budget->dvb_frontend);
+			budget->dvb_frontend = NULL;
+		}
+	}
+}
+
+/* written by Emard */
+static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
+{
+	struct budget_patch *budget;
+	int err;
+	int count = 0;
+	int detected = 0;
+
+#define PATCH_RESET 0
+#define RPS_IRQ 0
+#define HPS_SETUP 0
+#if PATCH_RESET
+	saa7146_write(dev, MC1, MASK_31);
+	msleep(40);
+#endif
+#if HPS_SETUP
+	// initialize registers. Better to have it like this
+	// than leaving something unconfigured
+	saa7146_write(dev, DD1_STREAM_B, 0);
+	// port B VSYNC at rising edge
+	saa7146_write(dev, DD1_INIT, 0x00000200);  // have this in budget-core too!
+	saa7146_write(dev, BRS_CTRL, 0x00000000);  // VBI
+
+	// debi config
+	// saa7146_write(dev, DEBI_CONFIG, MASK_30|MASK_28|MASK_18);
+
+	// zero all HPS registers
+	saa7146_write(dev, HPS_H_PRESCALE, 0);                  // r68
+	saa7146_write(dev, HPS_H_SCALE, 0);                     // r6c
+	saa7146_write(dev, BCS_CTRL, 0);                        // r70
+	saa7146_write(dev, HPS_V_SCALE, 0);                     // r60
+	saa7146_write(dev, HPS_V_GAIN, 0);                      // r64
+	saa7146_write(dev, CHROMA_KEY_RANGE, 0);                // r74
+	saa7146_write(dev, CLIP_FORMAT_CTRL, 0);                // r78
+	// Set HPS prescaler for port B input
+	saa7146_write(dev, HPS_CTRL, (1<<30) | (0<<29) | (1<<28) | (0<<12) );
+	saa7146_write(dev, MC2,
+	  0 * (MASK_08 | MASK_24)  |   // BRS control
+	  0 * (MASK_09 | MASK_25)  |   // a
+	  0 * (MASK_10 | MASK_26)  |   // b
+	  1 * (MASK_06 | MASK_22)  |   // HPS_CTRL1
+	  1 * (MASK_05 | MASK_21)  |   // HPS_CTRL2
+	  0 * (MASK_01 | MASK_15)      // DEBI
+	   );
+#endif
+	// Disable RPS1 and RPS0
+	saa7146_write(dev, MC1, ( MASK_29 | MASK_28));
+	// RPS1 timeout disable
+	saa7146_write(dev, RPS_TOV1, 0);
+
+	// code for autodetection
+	// will wait for VBI_B event (vertical blank at port B)
+	// and will reset GPIO3 after VBI_B is detected.
+	// (GPIO3 should be raised high by CPU to
+	// test if GPIO3 will generate vertical blank signal
+	// in budget patch GPIO3 is connected to VSYNC_B
+	count = 0;
+#if 0
+	WRITE_RPS1(CMD_UPLOAD |
+	  MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 );
+#endif
+	WRITE_RPS1(CMD_PAUSE | EVT_VBI_B);
+	WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+	WRITE_RPS1(GPIO3_MSK);
+	WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
+#if RPS_IRQ
+	// issue RPS1 interrupt to increment counter
+	WRITE_RPS1(CMD_INTERRUPT);
+	// at least a NOP is neede between two interrupts
+	WRITE_RPS1(CMD_NOP);
+	// interrupt again
+	WRITE_RPS1(CMD_INTERRUPT);
+#endif
+	WRITE_RPS1(CMD_STOP);
+
+#if RPS_IRQ
+	// set event counter 1 source as RPS1 interrupt (0x03)          (rE4 p53)
+	// use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
+	// use 0x15 to track VPE  interrupts - increase by 1 every vpeirq() is called
+	saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
+	// set event counter 1 threshold to maximum allowed value        (rEC p55)
+	saa7146_write(dev, ECT1R,  0x3fff );
+#endif
+	// Fix VSYNC level
+	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+	// Set RPS1 Address register to point to RPS code               (r108 p42)
+	saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
+	// Enable RPS1,                                                 (rFC p33)
+	saa7146_write(dev, MC1, (MASK_13 | MASK_29 ));
+
+
+	mdelay(50);
+	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
+	mdelay(150);
+
+
+	if( (saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0)
+		detected = 1;
+
+#if RPS_IRQ
+	printk("Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff );
+#endif
+	// Disable RPS1
+	saa7146_write(dev, MC1, ( MASK_29 ));
+
+	if(detected == 0)
+		printk("budget-patch not detected or saa7146 in non-default state.\n"
+		       "try enabling ressetting of 7146 with MASK_31 in MC1 register\n");
+
+	else
+		printk("BUDGET-PATCH DETECTED.\n");
+
+
+/*      OLD (Original design by Roberto Deza):
+**      This code will setup the SAA7146_RPS1 to generate a square
+**      wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of
+**      TS_WIDTH packets) has been acquired on SAA7146_D1B video port;
+**      then, this GPIO3 output which is connected to the D1B_VSYNC
+**      input, will trigger the acquisition of the alternate field
+**      and so on.
+**      Currently, the TT_budget / WinTV_Nova cards have two ICs
+**      (74HCT4040, LVC74) for the generation of this VSYNC signal,
+**      which seems that can be done perfectly without this :-)).
+*/
+
+/*      New design (By Emard)
+**      this rps1 code will copy internal HS event to GPIO3 pin.
+**      GPIO3 is in budget-patch hardware connected to port B VSYNC
+
+**      HS is an internal event of 7146, accessible with RPS
+**      and temporarily raised high every n lines
+**      (n in defined in the RPS_THRESH1 counter threshold)
+**      I think HS is raised high on the beginning of the n-th line
+**      and remains high until this n-th line that triggered
+**      it is completely received. When the reception of n-th line
+**      ends, HS is lowered.
+
+**      To transmit data over DMA, 7146 needs changing state at
+**      port B VSYNC pin. Any changing of port B VSYNC will
+**      cause some DMA data transfer, with more or less packets loss.
+**      It depends on the phase and frequency of VSYNC and
+**      the way of 7146 is instructed to trigger on port B (defined
+**      in DD1_INIT register, 3rd nibble from the right valid
+**      numbers are 0-7, see datasheet)
+**
+**      The correct triggering can minimize packet loss,
+**      dvbtraffic should give this stable bandwidths:
+**        22k transponder = 33814 kbit/s
+**      27.5k transponder = 38045 kbit/s
+**      by experiment it is found that the best results
+**      (stable bandwidths and almost no packet loss)
+**      are obtained using DD1_INIT triggering number 2
+**      (Va at rising edge of VS Fa = HS x VS-failing forced toggle)
+**      and a VSYNC phase that occurs in the middle of DMA transfer
+**      (about byte 188*512=96256 in the DMA window).
+**
+**      Phase of HS is still not clear to me how to control,
+**      It just happens to be so. It can be seen if one enables
+**      RPS_IRQ and print Event Counter 1 in vpeirq(). Every
+**      time RPS_INTERRUPT is called, the Event Counter 1 will
+**      increment. That's how the 7146 is programmed to do event
+**      counting in this budget-patch.c
+**      I *think* HPS setting has something to do with the phase
+**      of HS but I can't be 100% sure in that.
+
+**      hardware debug note: a working budget card (including budget patch)
+**      with vpeirq() interrupt setup in mode "0x90" (every 64K) will
+**      generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes
+**      and that means 3*25=75 Hz of interrupt frequency, as seen by
+**      watch cat /proc/interrupts
+**
+**      If this frequency is 3x lower (and data received in the DMA
+**      buffer don't start with 0x47, but in the middle of packets,
+**      whose lengths appear to be like 188 292 188 104 etc.
+**      this means VSYNC line is not connected in the hardware.
+**      (check soldering pcb and pins)
+**      The same behaviour of missing VSYNC can be duplicated on budget
+**      cards, by setting DD1_INIT trigger mode 7 in 3rd nibble.
+*/
+
+	// Setup RPS1 "program" (p35)
+	count = 0;
+
+
+	// Wait Source Line Counter Threshold                           (p36)
+	WRITE_RPS1(CMD_PAUSE | EVT_HS);
+	// Set GPIO3=1                                                  (p42)
+	WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+	WRITE_RPS1(GPIO3_MSK);
+	WRITE_RPS1(SAA7146_GPIO_OUTHI<<24);
+#if RPS_IRQ
+	// issue RPS1 interrupt
+	WRITE_RPS1(CMD_INTERRUPT);
+#endif
+	// Wait reset Source Line Counter Threshold                     (p36)
+	WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS);
+	// Set GPIO3=0                                                  (p42)
+	WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+	WRITE_RPS1(GPIO3_MSK);
+	WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
+#if RPS_IRQ
+	// issue RPS1 interrupt
+	WRITE_RPS1(CMD_INTERRUPT);
+#endif
+	// Jump to begin of RPS program                                 (p37)
+	WRITE_RPS1(CMD_JUMP);
+	WRITE_RPS1(dev->d_rps1.dma_handle);
+
+	// Fix VSYNC level
+	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+	// Set RPS1 Address register to point to RPS code               (r108 p42)
+	saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
+
+	if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL)))
+		return -ENOMEM;
+
+	dprintk(2, "budget: %p\n", budget);
+
+	err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr);
+	if (err) {
+		kfree(budget);
+		return err;
+	}
+
+	// Set Source Line Counter Threshold, using BRS                 (rCC p43)
+	// It generates HS event every TS_HEIGHT lines
+	// this is related to TS_WIDTH set in register
+	// NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE
+	// low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188
+	//,then RPS_THRESH1
+	// should be set to trigger every TS_HEIGHT (512) lines.
+	//
+	saa7146_write(dev, RPS_THRESH1, budget->buffer_height | MASK_12 );
+
+	// saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 );
+	// Enable RPS1                                                  (rFC p33)
+	saa7146_write(dev, MC1, (MASK_13 | MASK_29));
+
+
+	dev->ext_priv = budget;
+
+	budget->dvb_adapter.priv = budget;
+	frontend_init(budget);
+
+	ttpci_budget_init_hooks(budget);
+
+	return 0;
+}
+
+static int budget_patch_detach (struct saa7146_dev* dev)
+{
+	struct budget_patch *budget = (struct budget_patch*) dev->ext_priv;
+	int err;
+
+	if (budget->dvb_frontend) {
+		dvb_unregister_frontend(budget->dvb_frontend);
+		dvb_frontend_detach(budget->dvb_frontend);
+	}
+	err = ttpci_budget_deinit (budget);
+
+	kfree (budget);
+
+	return err;
+}
+
+static int __init budget_patch_init(void)
+{
+	return saa7146_register_extension(&budget_extension);
+}
+
+static void __exit budget_patch_exit(void)
+{
+	saa7146_unregister_extension(&budget_extension);
+}
+
+static struct saa7146_extension budget_extension = {
+	.name           = "budget_patch dvb",
+	.flags          = 0,
+
+	.module         = THIS_MODULE,
+	.pci_tbl        = pci_tbl,
+	.attach         = budget_patch_attach,
+	.detach         = budget_patch_detach,
+
+	.irq_mask       = MASK_10,
+	.irq_func       = ttpci_budget_irq10_handler,
+};
+
+module_init(budget_patch_init);
+module_exit(budget_patch_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Emard, Roberto Deza, Holger Waechtler, Michael Hunold, others");
+MODULE_DESCRIPTION("Driver for full TS modified DVB-S SAA7146+AV7110 "
+		   "based so-called Budget Patch cards");
diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c
new file mode 100644
index 0000000..7e6e43a
--- /dev/null
+++ b/drivers/media/pci/ttpci/budget.c
@@ -0,0 +1,871 @@
+/*
+ * budget.c: driver for the SAA7146 based Budget DVB cards
+ *
+ * Compiled from various sources by Michael Hunold <michael@mihu.de>
+ *
+ * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
+ *
+ * Copyright (C) 1999-2002 Ralph  Metzler
+ *                       & Marcus Metzler for convergence integrated media GmbH
+ *
+ * 26feb2004 Support for FS Activy Card (Grundig tuner) by
+ *           Michael Dreher <michael@5dot1.de>,
+ *           Oliver Endriss <o.endriss@gmx.de> and
+ *           Andreas 'randy' Weinberger
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org/ 
+ */
+
+#include "budget.h"
+#include "stv0299.h"
+#include "ves1x93.h"
+#include "ves1820.h"
+#include "l64781.h"
+#include "tda8083.h"
+#include "s5h1420.h"
+#include "tda10086.h"
+#include "tda826x.h"
+#include "lnbp21.h"
+#include "bsru6.h"
+#include "bsbe1.h"
+#include "tdhd1.h"
+#include "stv6110x.h"
+#include "stv090x.h"
+#include "isl6423.h"
+#include "lnbh24.h"
+
+
+static int diseqc_method;
+module_param(diseqc_method, int, 0444);
+MODULE_PARM_DESC(diseqc_method, "Select DiSEqC method for subsystem id 13c2:1003, 0: default, 1: more reliable (for newer revisions only)");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static void Set22K (struct budget *budget, int state)
+{
+	struct saa7146_dev *dev=budget->dev;
+	dprintk(2, "budget: %p\n", budget);
+	saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO));
+}
+
+/* Diseqc functions only for TT Budget card */
+/* taken from the Skyvision DVB driver by
+   Ralph Metzler <rjkm@metzlerbros.de> */
+
+static void DiseqcSendBit (struct budget *budget, int data)
+{
+	struct saa7146_dev *dev=budget->dev;
+	dprintk(2, "budget: %p\n", budget);
+
+	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
+	udelay(data ? 500 : 1000);
+	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+	udelay(data ? 1000 : 500);
+}
+
+static void DiseqcSendByte (struct budget *budget, int data)
+{
+	int i, par=1, d;
+
+	dprintk(2, "budget: %p\n", budget);
+
+	for (i=7; i>=0; i--) {
+		d = (data>>i)&1;
+		par ^= d;
+		DiseqcSendBit(budget, d);
+	}
+
+	DiseqcSendBit(budget, par);
+}
+
+static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst)
+{
+	struct saa7146_dev *dev=budget->dev;
+	int i;
+
+	dprintk(2, "budget: %p\n", budget);
+
+	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+	mdelay(16);
+
+	for (i=0; i<len; i++)
+		DiseqcSendByte(budget, msg[i]);
+
+	mdelay(16);
+
+	if (burst!=-1) {
+		if (burst)
+			DiseqcSendByte(budget, 0xff);
+		else {
+			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
+			mdelay(12);
+			udelay(500);
+			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+		}
+		msleep(20);
+	}
+
+	return 0;
+}
+
+/*
+ *   Routines for the Fujitsu Siemens Activy budget card
+ *   22 kHz tone and DiSEqC are handled by the frontend.
+ *   Voltage must be set here.
+ *   GPIO 1: LNBP EN, GPIO 2: LNBP VSEL
+ */
+static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
+{
+	struct saa7146_dev *dev=budget->dev;
+
+	dprintk(2, "budget: %p\n", budget);
+
+	switch (voltage) {
+		case SEC_VOLTAGE_13:
+			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
+			saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO);
+			break;
+		case SEC_VOLTAGE_18:
+			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
+			saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
+			break;
+		case SEC_VOLTAGE_OFF:
+			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO);
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+
+	return SetVoltage_Activy (budget, voltage);
+}
+
+static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		Set22K (budget, 1);
+		break;
+
+	case SEC_TONE_OFF:
+		Set22K (budget, 0);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+
+	SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
+
+	return 0;
+}
+
+static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+
+	SendDiSEqCMsg (budget, 0, NULL, minicmd);
+
+	return 0;
+}
+
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+	u8 pwr = 0;
+	u8 buf[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	u32 div = (c->frequency + 479500) / 125;
+
+	if (c->frequency > 2000000)
+		pwr = 3;
+	else if (c->frequency > 1800000)
+		pwr = 2;
+	else if (c->frequency > 1600000)
+		pwr = 1;
+	else if (c->frequency > 1200000)
+		pwr = 0;
+	else if (c->frequency >= 1100000)
+		pwr = 1;
+	else pwr = 2;
+
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = ((div & 0x18000) >> 10) | 0x95;
+	buf[3] = (pwr << 6) | 0x30;
+
+	// NOTE: since we're using a prescaler of 2, we set the
+	// divisor frequency to 62.5kHz and divide by 125 above
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+	return 0;
+}
+
+static struct ves1x93_config alps_bsrv2_config =
+{
+	.demod_address = 0x08,
+	.xin = 90100000UL,
+	.invert_pwm = 0,
+};
+
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+	u32 div;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = (c->frequency + 35937500 + 31250) / 62500;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x85 | ((div >> 10) & 0x60);
+	data[3] = (c->frequency < 174000000 ? 0x88 : c->frequency < 470000000 ? 0x84 : 0x81);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+	return 0;
+}
+
+static struct ves1820_config alps_tdbe2_config = {
+	.demod_address = 0x09,
+	.xin = 57840000UL,
+	.invert = 1,
+	.selagc = VES1820_SELAGC_SIGNAMPERR,
+};
+
+static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct budget *budget = fe->dvb->priv;
+	u8 *tuner_addr = fe->tuner_priv;
+	u32 div;
+	u8 cfg, cpump, band_select;
+	u8 data[4];
+	struct i2c_msg msg = { .flags = 0, .buf = data, .len = sizeof(data) };
+
+	if (tuner_addr)
+		msg.addr = *tuner_addr;
+	else
+		msg.addr = 0x61;
+
+	div = (36125000 + c->frequency) / 166666;
+
+	cfg = 0x88;
+
+	if (c->frequency < 175000000)
+		cpump = 2;
+	else if (c->frequency < 390000000)
+		cpump = 1;
+	else if (c->frequency < 470000000)
+		cpump = 2;
+	else if (c->frequency < 750000000)
+		cpump = 1;
+	else
+		cpump = 3;
+
+	if (c->frequency < 175000000)
+		band_select = 0x0e;
+	else if (c->frequency < 470000000)
+		band_select = 0x05;
+	else
+		band_select = 0x03;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = ((div >> 10) & 0x60) | cfg;
+	data[3] = (cpump << 6) | band_select;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+	return 0;
+}
+
+static struct l64781_config grundig_29504_401_config = {
+	.demod_address = 0x55,
+};
+
+static struct l64781_config grundig_29504_401_config_activy = {
+	.demod_address = 0x54,
+};
+
+static u8 tuner_address_grundig_29504_401_activy = 0x60;
+
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+	u32 div;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = c->frequency / 125;
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x8e;
+	data[3] = 0x00;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+	return 0;
+}
+
+static struct tda8083_config grundig_29504_451_config = {
+	.demod_address = 0x68,
+};
+
+static int s5h1420_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+	u32 div;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = c->frequency / 1000;
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0xc2;
+
+	if (div < 1450)
+		data[3] = 0x00;
+	else if (div < 1850)
+		data[3] = 0x40;
+	else if (div < 2000)
+		data[3] = 0x80;
+	else
+		data[3] = 0xc0;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+
+	return 0;
+}
+
+static struct s5h1420_config s5h1420_config = {
+	.demod_address = 0x53,
+	.invert = 1,
+	.cdclk_polarity = 1,
+};
+
+static struct tda10086_config tda10086_config = {
+	.demod_address = 0x0e,
+	.invert = 0,
+	.diseqc_tone = 1,
+	.xtal_freq = TDA10086_XTAL_16M,
+};
+
+static struct stv0299_config alps_bsru6_config_activy = {
+	.demod_address = 0x68,
+	.inittab = alps_bsru6_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.op0_off = 1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = alps_bsru6_set_symbol_rate,
+};
+
+static struct stv0299_config alps_bsbe1_config_activy = {
+	.demod_address = 0x68,
+	.inittab = alps_bsbe1_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.op0_off = 1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = alps_bsbe1_set_symbol_rate,
+};
+
+static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name)
+{
+	struct budget *budget = (struct budget *)fe->dvb->priv;
+
+	return request_firmware(fw, name, &budget->dev->pci->dev);
+}
+
+
+static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg)
+{
+	u8 val;
+	struct i2c_msg msg[] = {
+		{ .addr = adr, .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = adr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
+	};
+
+	return (i2c_transfer(i2c, msg, 2) != 2) ? -EIO : val;
+}
+
+static u8 read_pwm(struct budget* budget)
+{
+	u8 b = 0xff;
+	u8 pwm;
+	struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
+				 { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
+
+	if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
+		pwm = 0x48;
+
+	return pwm;
+}
+
+static struct stv090x_config tt1600_stv090x_config = {
+	.device			= STV0903,
+	.demod_mode		= STV090x_SINGLE,
+	.clk_mode		= STV090x_CLK_EXT,
+
+	.xtal			= 13500000,
+	.address		= 0x68,
+
+	.ts1_mode		= STV090x_TSMODE_DVBCI,
+	.ts2_mode		= STV090x_TSMODE_SERIAL_CONTINUOUS,
+
+	.repeater_level		= STV090x_RPTLEVEL_16,
+
+	.tuner_init		= NULL,
+	.tuner_sleep		= NULL,
+	.tuner_set_mode		= NULL,
+	.tuner_set_frequency	= NULL,
+	.tuner_get_frequency	= NULL,
+	.tuner_set_bandwidth	= NULL,
+	.tuner_get_bandwidth	= NULL,
+	.tuner_set_bbgain	= NULL,
+	.tuner_get_bbgain	= NULL,
+	.tuner_set_refclk	= NULL,
+	.tuner_get_status	= NULL,
+};
+
+static struct stv6110x_config tt1600_stv6110x_config = {
+	.addr			= 0x60,
+	.refclk			= 27000000,
+	.clk_div		= 2,
+};
+
+static struct isl6423_config tt1600_isl6423_config = {
+	.current_max		= SEC_CURRENT_515m,
+	.curlim			= SEC_CURRENT_LIM_ON,
+	.mod_extern		= 1,
+	.addr			= 0x08,
+};
+
+static void frontend_init(struct budget *budget)
+{
+	(void)alps_bsbe1_config; /* avoid warning */
+
+	switch(budget->dev->pci->subsystem_device) {
+	case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
+	case 0x1013:
+		// try the ALPS BSRV2 first of all
+		budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+			budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+			budget->dvb_frontend->ops.set_tone = budget_set_tone;
+			break;
+		}
+
+		// try the ALPS BSRU6 now
+		budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+			if (budget->dev->pci->subsystem_device == 0x1003 && diseqc_method == 0) {
+				budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+				budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+				budget->dvb_frontend->ops.set_tone = budget_set_tone;
+			}
+			break;
+		}
+		break;
+
+	case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
+
+		budget->dvb_frontend = dvb_attach(ves1820_attach, &alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+			break;
+		}
+		break;
+
+	case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
+
+		budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+			budget->dvb_frontend->tuner_priv = NULL;
+			break;
+		}
+		break;
+
+	case 0x4f60: /* Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/tsa5059) */
+	{
+		int subtype = i2c_readreg(&budget->i2c_adap, 0x50, 0x67);
+
+		if (subtype < 0)
+			break;
+		/* fixme: find a better way to identify the card */
+		if (subtype < 0x36) {
+			/* assume ALPS BSRU6 */
+			budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config_activy, &budget->i2c_adap);
+			if (budget->dvb_frontend) {
+				printk(KERN_INFO "budget: tuner ALPS BSRU6 detected\n");
+				budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+				budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+				budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+				budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
+				break;
+			}
+		} else {
+			/* assume ALPS BSBE1 */
+			/* reset tuner */
+			saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTLO);
+			msleep(50);
+			saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTHI);
+			msleep(250);
+			budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config_activy, &budget->i2c_adap);
+			if (budget->dvb_frontend) {
+				printk(KERN_INFO "budget: tuner ALPS BSBE1 detected\n");
+				budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
+				budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+				budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+				budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
+				break;
+			}
+		}
+		break;
+	}
+
+	case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))
+		budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+			budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+			budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
+		}
+		break;
+
+	case 0x5f60: /* Fujitsu Siemens Activy Budget-T PCI rev AL (tda10046/ALPS TDHD1-204A) */
+		budget->dvb_frontend = dvb_attach(tda10046_attach, &alps_tdhd1_204a_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdhd1_204a_tuner_set_params;
+			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+		}
+		break;
+
+	case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */
+		budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->tuner_priv = &tuner_address_grundig_29504_401_activy;
+			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+		}
+		break;
+
+	case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
+		budget->dvb_frontend = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params;
+			if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
+				printk("%s: No LNBP21 found!\n", __func__);
+				goto error_out;
+			}
+			break;
+		}
+
+	case 0x1018: // TT Budget-S-1401 (philips tda10086/philips tda8262)
+		// gpio2 is connected to CLB - reset it + leave it high
+		saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
+		msleep(1);
+		saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
+		msleep(1);
+
+		budget->dvb_frontend = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			if (dvb_attach(tda826x_attach, budget->dvb_frontend, 0x60, &budget->i2c_adap, 0) == NULL)
+				printk("%s: No tda826x found!\n", __func__);
+			if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
+				printk("%s: No LNBP21 found!\n", __func__);
+				goto error_out;
+			}
+			break;
+		}
+
+	case 0x101c: { /* TT S2-1600 */
+			struct stv6110x_devctl *ctl;
+			saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
+			msleep(50);
+			saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
+			msleep(250);
+
+			budget->dvb_frontend = dvb_attach(stv090x_attach,
+							  &tt1600_stv090x_config,
+							  &budget->i2c_adap,
+							  STV090x_DEMODULATOR_0);
+
+			if (budget->dvb_frontend) {
+
+				ctl = dvb_attach(stv6110x_attach,
+						 budget->dvb_frontend,
+						 &tt1600_stv6110x_config,
+						 &budget->i2c_adap);
+
+				if (ctl) {
+					tt1600_stv090x_config.tuner_init	  = ctl->tuner_init;
+					tt1600_stv090x_config.tuner_sleep	  = ctl->tuner_sleep;
+					tt1600_stv090x_config.tuner_set_mode	  = ctl->tuner_set_mode;
+					tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
+					tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
+					tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+					tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+					tt1600_stv090x_config.tuner_set_bbgain	  = ctl->tuner_set_bbgain;
+					tt1600_stv090x_config.tuner_get_bbgain	  = ctl->tuner_get_bbgain;
+					tt1600_stv090x_config.tuner_set_refclk	  = ctl->tuner_set_refclk;
+					tt1600_stv090x_config.tuner_get_status	  = ctl->tuner_get_status;
+
+					/* call the init function once to initialize
+					   tuner's clock output divider and demod's
+					   master clock */
+					if (budget->dvb_frontend->ops.init)
+						budget->dvb_frontend->ops.init(budget->dvb_frontend);
+
+					if (dvb_attach(isl6423_attach,
+						       budget->dvb_frontend,
+						       &budget->i2c_adap,
+						       &tt1600_isl6423_config) == NULL) {
+						printk(KERN_ERR "%s: No Intersil ISL6423 found!\n", __func__);
+						goto error_out;
+					}
+				} else {
+					printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__);
+					goto error_out;
+				}
+			}
+		}
+		break;
+
+	case 0x1020: { /* Omicom S2 */
+			struct stv6110x_devctl *ctl;
+			saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
+			msleep(50);
+			saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
+			msleep(250);
+
+			budget->dvb_frontend = dvb_attach(stv090x_attach,
+							  &tt1600_stv090x_config,
+							  &budget->i2c_adap,
+							  STV090x_DEMODULATOR_0);
+
+			if (budget->dvb_frontend) {
+				printk(KERN_INFO "budget: Omicom S2 detected\n");
+
+				ctl = dvb_attach(stv6110x_attach,
+						 budget->dvb_frontend,
+						 &tt1600_stv6110x_config,
+						 &budget->i2c_adap);
+
+				if (ctl) {
+					tt1600_stv090x_config.tuner_init	  = ctl->tuner_init;
+					tt1600_stv090x_config.tuner_sleep	  = ctl->tuner_sleep;
+					tt1600_stv090x_config.tuner_set_mode	  = ctl->tuner_set_mode;
+					tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
+					tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
+					tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+					tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+					tt1600_stv090x_config.tuner_set_bbgain	  = ctl->tuner_set_bbgain;
+					tt1600_stv090x_config.tuner_get_bbgain	  = ctl->tuner_get_bbgain;
+					tt1600_stv090x_config.tuner_set_refclk	  = ctl->tuner_set_refclk;
+					tt1600_stv090x_config.tuner_get_status	  = ctl->tuner_get_status;
+
+					/* call the init function once to initialize
+					   tuner's clock output divider and demod's
+					   master clock */
+					if (budget->dvb_frontend->ops.init)
+						budget->dvb_frontend->ops.init(budget->dvb_frontend);
+
+					if (dvb_attach(lnbh24_attach,
+							budget->dvb_frontend,
+							&budget->i2c_adap,
+							LNBH24_PCL | LNBH24_TTX,
+							LNBH24_TEN, 0x14>>1) == NULL) {
+						printk(KERN_ERR
+						"No LNBH24 found!\n");
+						goto error_out;
+					}
+				} else {
+					printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__);
+					goto error_out;
+				}
+			}
+		}
+		break;
+	}
+
+	if (budget->dvb_frontend == NULL) {
+		printk("budget: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
+		       budget->dev->pci->vendor,
+		       budget->dev->pci->device,
+		       budget->dev->pci->subsystem_vendor,
+		       budget->dev->pci->subsystem_device);
+	} else {
+		if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend))
+			goto error_out;
+	}
+	return;
+
+error_out:
+	printk("budget: Frontend registration failed!\n");
+	dvb_frontend_detach(budget->dvb_frontend);
+	budget->dvb_frontend = NULL;
+	return;
+}
+
+static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
+{
+	struct budget *budget = NULL;
+	int err;
+
+	budget = kmalloc(sizeof(struct budget), GFP_KERNEL);
+	if( NULL == budget ) {
+		return -ENOMEM;
+	}
+
+	dprintk(2, "dev:%p, info:%p, budget:%p\n", dev, info, budget);
+
+	dev->ext_priv = budget;
+
+	err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr);
+	if (err) {
+		printk("==> failed\n");
+		kfree (budget);
+		return err;
+	}
+
+	budget->dvb_adapter.priv = budget;
+	frontend_init(budget);
+
+	ttpci_budget_init_hooks(budget);
+
+	return 0;
+}
+
+static int budget_detach (struct saa7146_dev* dev)
+{
+	struct budget *budget = (struct budget*) dev->ext_priv;
+	int err;
+
+	if (budget->dvb_frontend) {
+		dvb_unregister_frontend(budget->dvb_frontend);
+		dvb_frontend_detach(budget->dvb_frontend);
+	}
+
+	err = ttpci_budget_deinit (budget);
+
+	kfree (budget);
+	dev->ext_priv = NULL;
+
+	return err;
+}
+
+static struct saa7146_extension budget_extension;
+
+MAKE_BUDGET_INFO(ttbs,	"TT-Budget/WinTV-NOVA-S  PCI",	BUDGET_TT);
+MAKE_BUDGET_INFO(ttbc,	"TT-Budget/WinTV-NOVA-C  PCI",	BUDGET_TT);
+MAKE_BUDGET_INFO(ttbt,	"TT-Budget/WinTV-NOVA-T  PCI",	BUDGET_TT);
+MAKE_BUDGET_INFO(satel,	"SATELCO Multimedia PCI",	BUDGET_TT_HW_DISEQC);
+MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(tt1600, "TT-Budget S2-1600 PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
+MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
+MAKE_BUDGET_INFO(fsact,	 "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY);
+MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY);
+MAKE_BUDGET_INFO(omicom, "Omicom S2 PCI", BUDGET_TT);
+
+static struct pci_device_id pci_tbl[] = {
+	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1003),
+	MAKE_EXTENSION_PCI(ttbc,  0x13c2, 0x1004),
+	MAKE_EXTENSION_PCI(ttbt,  0x13c2, 0x1005),
+	MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
+	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1016),
+	MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018),
+	MAKE_EXTENSION_PCI(tt1600, 0x13c2, 0x101c),
+	MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
+	MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
+	MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60),
+	MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61),
+	MAKE_EXTENSION_PCI(omicom, 0x14c4, 0x1020),
+	{
+		.vendor    = 0,
+	}
+};
+
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+static struct saa7146_extension budget_extension = {
+	.name		= "budget dvb",
+	.flags		= SAA7146_USE_I2C_IRQ,
+
+	.module		= THIS_MODULE,
+	.pci_tbl	= pci_tbl,
+	.attach		= budget_attach,
+	.detach		= budget_detach,
+
+	.irq_mask	= MASK_10,
+	.irq_func	= ttpci_budget_irq10_handler,
+};
+
+static int __init budget_init(void)
+{
+	return saa7146_register_extension(&budget_extension);
+}
+
+static void __exit budget_exit(void)
+{
+	saa7146_unregister_extension(&budget_extension);
+}
+
+module_init(budget_init);
+module_exit(budget_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others");
+MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
+		   "budget PCI DVB cards by Siemens, Technotrend, Hauppauge");
diff --git a/drivers/media/pci/ttpci/budget.h b/drivers/media/pci/ttpci/budget.h
new file mode 100644
index 0000000..3d8a806
--- /dev/null
+++ b/drivers/media/pci/ttpci/budget.h
@@ -0,0 +1,124 @@
+
+#ifndef __BUDGET_DVB__
+#define __BUDGET_DVB__
+
+#include "dvb_frontend.h"
+#include "dvbdev.h"
+#include "demux.h"
+#include "dvb_demux.h"
+#include "dmxdev.h"
+#include "dvb_filter.h"
+#include "dvb_net.h"
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+
+#include <media/saa7146.h>
+
+extern int budget_debug;
+
+#ifdef dprintk
+#undef dprintk
+#endif
+
+#define dprintk(level,args...) \
+	    do { if ((budget_debug & level)) { printk("%s: %s(): ", KBUILD_MODNAME, __func__); printk(args); } } while (0)
+
+struct budget_info {
+	char *name;
+	int type;
+};
+
+/* place to store all the necessary device information */
+struct budget {
+
+	/* devices */
+	struct dvb_device dvb_dev;
+	struct dvb_net dvb_net;
+
+	struct saa7146_dev *dev;
+
+	struct i2c_adapter i2c_adap;
+	struct budget_info *card;
+
+	unsigned char *grabbing;
+	struct saa7146_pgtable pt;
+
+	struct tasklet_struct fidb_tasklet;
+	struct tasklet_struct vpe_tasklet;
+
+	struct dmxdev dmxdev;
+	struct dvb_demux demux;
+
+	struct dmx_frontend hw_frontend;
+	struct dmx_frontend mem_frontend;
+
+	int ci_present;
+	int video_port;
+
+	u32 buffer_width;
+	u32 buffer_height;
+	u32 buffer_size;
+	u32 buffer_warning_threshold;
+	u32 buffer_warnings;
+	unsigned long buffer_warning_time;
+
+	u32 ttbp;
+	int feeding;
+
+	spinlock_t feedlock;
+
+	spinlock_t debilock;
+
+	struct dvb_adapter dvb_adapter;
+	struct dvb_frontend *dvb_frontend;
+	int (*read_fe_status)(struct dvb_frontend *fe, fe_status_t *status);
+	int fe_synced;
+
+	void *priv;
+};
+
+#define MAKE_BUDGET_INFO(x_var,x_name,x_type) \
+static struct budget_info x_var ## _info = { \
+	.name=x_name,	\
+	.type=x_type };	\
+static struct saa7146_pci_extension_data x_var = { \
+	.ext_priv = &x_var ## _info, \
+	.ext = &budget_extension };
+
+#define BUDGET_TT		   0
+#define BUDGET_TT_HW_DISEQC	   1
+#define BUDGET_PATCH		   3
+#define BUDGET_FS_ACTIVY	   4
+#define BUDGET_CIN1200S		   5
+#define BUDGET_CIN1200C		   6
+#define BUDGET_CIN1200T		   7
+#define BUDGET_KNC1S		   8
+#define BUDGET_KNC1C		   9
+#define BUDGET_KNC1T		   10
+#define BUDGET_KNC1SP		   11
+#define BUDGET_KNC1CP		   12
+#define BUDGET_KNC1TP		   13
+#define BUDGET_TVSTAR		   14
+#define BUDGET_CIN1200C_MK3	   15
+#define BUDGET_KNC1C_MK3	   16
+#define BUDGET_KNC1CP_MK3	   17
+#define BUDGET_KNC1S2              18
+#define BUDGET_KNC1C_TDA10024	   19
+
+#define BUDGET_VIDEO_PORTA         0
+#define BUDGET_VIDEO_PORTB         1
+
+extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
+			     struct saa7146_pci_extension_data *info,
+			     struct module *owner, short *adapter_nums);
+extern void ttpci_budget_init_hooks(struct budget *budget);
+extern int ttpci_budget_deinit(struct budget *budget);
+extern void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr);
+extern void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port);
+extern int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count,
+				 int uselocks, int nobusyloop);
+extern int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, int count, u32 value,
+				  int uselocks, int nobusyloop);
+
+#endif
diff --git a/drivers/media/pci/ttpci/ttpci-eeprom.c b/drivers/media/pci/ttpci/ttpci-eeprom.c
new file mode 100644
index 0000000..32d4315
--- /dev/null
+++ b/drivers/media/pci/ttpci/ttpci-eeprom.c
@@ -0,0 +1,176 @@
+/*
+    Retrieve encoded MAC address from 24C16 serial 2-wire EEPROM,
+    decode it and store it in the associated adapter struct for
+    use by dvb_net.c
+
+    This card appear to have the 24C16 write protect held to ground,
+    thus permitting normal read/write operation. Theoretically it
+    would be possible to write routines to burn a different (encoded)
+    MAC address into the EEPROM.
+
+    Robert Schlabbach	GMX
+    Michael Glaum	KVH Industries
+    Holger Waechtler	Convergence
+
+    Copyright (C) 2002-2003 Ralph Metzler <rjkm@metzlerbros.de>
+			    Metzler Brothers Systementwicklung GbR
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <asm/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/i2c.h>
+
+#include "ttpci-eeprom.h"
+
+#if 1
+#define dprintk(x...) do { printk(x); } while (0)
+#else
+#define dprintk(x...) do { } while (0)
+#endif
+
+
+static int check_mac_tt(u8 *buf)
+{
+	int i;
+	u16 tmp = 0xffff;
+
+	for (i = 0; i < 8; i++) {
+		tmp  = (tmp << 8) | ((tmp >> 8) ^ buf[i]);
+		tmp ^= (tmp >> 4) & 0x0f;
+		tmp ^= (tmp << 12) ^ ((tmp & 0xff) << 5);
+	}
+	tmp ^= 0xffff;
+	return (((tmp >> 8) ^ buf[8]) | ((tmp & 0xff) ^ buf[9]));
+}
+
+static int getmac_tt(u8 * decodedMAC, u8 * encodedMAC)
+{
+	u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c,
+		       0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6,
+		       0x1d, 0x36, 0x64, 0x78};
+	u8 data[20];
+	int i;
+
+	/* In case there is a sig check failure have the orig contents available */
+	memcpy(data, encodedMAC, 20);
+
+	for (i = 0; i < 20; i++)
+		data[i] ^= xor[i];
+	for (i = 0; i < 10; i++)
+		data[i] = ((data[2 * i + 1] << 8) | data[2 * i])
+			>> ((data[2 * i + 1] >> 6) & 3);
+
+	if (check_mac_tt(data))
+		return -ENODEV;
+
+	decodedMAC[0] = data[2]; decodedMAC[1] = data[1]; decodedMAC[2] = data[0];
+	decodedMAC[3] = data[6]; decodedMAC[4] = data[5]; decodedMAC[5] = data[4];
+	return 0;
+}
+
+int ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC)
+{
+	u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c,
+		       0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6,
+		       0x1d, 0x36, 0x64, 0x78};
+	u8 data[20];
+	int i;
+
+	memcpy(data, encodedMAC, 20);
+
+	for (i = 0; i < 20; i++)
+		data[i] ^= xor[i];
+	for (i = 0; i < 10; i++)
+		data[i] = ((data[2 * i + 1] << 8) | data[2 * i])
+			>> ((data[2 * i + 1] >> 6) & 3);
+
+	if (check_mac_tt(data))
+		return -ENODEV;
+
+	decodedMAC[0] = data[2];
+	decodedMAC[1] = data[1];
+	decodedMAC[2] = data[0];
+	decodedMAC[3] = data[6];
+	decodedMAC[4] = data[5];
+	decodedMAC[5] = data[4];
+	return 0;
+}
+EXPORT_SYMBOL(ttpci_eeprom_decode_mac);
+
+static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC)
+{
+	int ret;
+	u8 b0[] = { 0xcc };
+
+	struct i2c_msg msg[] = {
+		{ .addr = 0x50, .flags = 0, .buf = b0, .len = 1 },
+		{ .addr = 0x50, .flags = I2C_M_RD, .buf = encodedMAC, .len = 20 }
+	};
+
+	/* dprintk("%s\n", __func__); */
+
+	ret = i2c_transfer(adapter, msg, 2);
+
+	if (ret != 2)		/* Assume EEPROM isn't there */
+		return (-ENODEV);
+
+	return 0;
+}
+
+
+int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac)
+{
+	int ret, i;
+	u8 encodedMAC[20];
+	u8 decodedMAC[6];
+
+	ret = ttpci_eeprom_read_encodedMAC(adapter, encodedMAC);
+
+	if (ret != 0) {		/* Will only be -ENODEV */
+		dprintk("Couldn't read from EEPROM: not there?\n");
+		memset(proposed_mac, 0, 6);
+		return ret;
+	}
+
+	ret = getmac_tt(decodedMAC, encodedMAC);
+	if( ret != 0 ) {
+		dprintk("adapter failed MAC signature check\n");
+		dprintk("encoded MAC from EEPROM was " );
+		for(i=0; i<19; i++) {
+			dprintk( "%.2x:", encodedMAC[i]);
+		}
+		dprintk("%.2x\n", encodedMAC[19]);
+		memset(proposed_mac, 0, 6);
+		return ret;
+	}
+
+	memcpy(proposed_mac, decodedMAC, 6);
+	dprintk("adapter has MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+		decodedMAC[0], decodedMAC[1], decodedMAC[2],
+		decodedMAC[3], decodedMAC[4], decodedMAC[5]);
+	return 0;
+}
+
+EXPORT_SYMBOL(ttpci_eeprom_parse_mac);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others");
+MODULE_DESCRIPTION("Decode dvb_net MAC address from EEPROM of PCI DVB cards "
+		"made by Siemens, Technotrend, Hauppauge");
diff --git a/drivers/media/pci/ttpci/ttpci-eeprom.h b/drivers/media/pci/ttpci/ttpci-eeprom.h
new file mode 100644
index 0000000..dcc33d5
--- /dev/null
+++ b/drivers/media/pci/ttpci/ttpci-eeprom.h
@@ -0,0 +1,34 @@
+/*
+    Retrieve encoded MAC address from ATMEL ttpci_eeprom serial 2-wire EEPROM,
+    decode it and store it in associated adapter net device
+
+    Robert Schlabbach	GMX
+    Michael Glaum	KVH Industries
+    Holger Waechtler	Convergence
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __TTPCI_EEPROM_H__
+#define __TTPCI_EEPROM_H__
+
+#include <linux/types.h>
+#include <linux/i2c.h>
+
+extern int ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC);
+extern int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *propsed_mac);
+
+#endif
diff --git a/drivers/media/pci/zoran/Kconfig b/drivers/media/pci/zoran/Kconfig
new file mode 100644
index 0000000..fd4120e
--- /dev/null
+++ b/drivers/media/pci/zoran/Kconfig
@@ -0,0 +1,74 @@
+config VIDEO_ZORAN
+	tristate "Zoran ZR36057/36067 Video For Linux"
+	depends on PCI && I2C_ALGOBIT && VIDEO_V4L2 && VIRT_TO_BUS
+	help
+	  Say Y for support for MJPEG capture cards based on the Zoran
+	  36057/36067 PCI controller chipset. This includes the Iomega
+	  Buz, Pinnacle DC10+ and the Linux Media Labs LML33. There is
+	  a driver homepage at <http://mjpeg.sf.net/driver-zoran/>. For
+	  more information, check <file:Documentation/video4linux/Zoran>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called zr36067.
+
+config VIDEO_ZORAN_DC30
+	tristate "Pinnacle/Miro DC30(+) support"
+	depends on VIDEO_ZORAN
+	select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO
+	help
+	  Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback
+	  card. This also supports really old DC10 cards based on the
+	  zr36050 MJPEG codec and zr36016 VFE.
+
+config VIDEO_ZORAN_ZR36060
+	tristate "Zoran ZR36060"
+	depends on VIDEO_ZORAN
+	help
+	  Say Y to support Zoran boards based on 36060 chips.
+	  This includes Iomega Buz, Pinnacle DC10, Linux media Labs 33
+	  and 33 R10 and AverMedia 6 boards.
+
+config VIDEO_ZORAN_BUZ
+	tristate "Iomega Buz support"
+	depends on VIDEO_ZORAN_ZR36060
+	select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
+	help
+	  Support for the Iomega Buz MJPEG capture/playback card.
+
+config VIDEO_ZORAN_DC10
+	tristate "Pinnacle/Miro DC10(+) support"
+	depends on VIDEO_ZORAN_ZR36060
+	select VIDEO_SAA7110 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
+	help
+	  Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
+	  card.
+
+config VIDEO_ZORAN_LML33
+	tristate "Linux Media Labs LML33 support"
+	depends on VIDEO_ZORAN_ZR36060
+	select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
+	help
+	  Support for the Linux Media Labs LML33 MJPEG capture/playback
+	  card.
+
+config VIDEO_ZORAN_LML33R10
+	tristate "Linux Media Labs LML33R10 support"
+	depends on VIDEO_ZORAN_ZR36060
+	select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO
+	help
+	  support for the Linux Media Labs LML33R10 MJPEG capture/playback
+	  card.
+
+config VIDEO_ZORAN_AVS6EYES
+	tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
+	depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL
+	select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_BT866 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
+	help
+	  Support for the AverMedia 6 Eyes video surveillance card.
diff --git a/drivers/media/pci/zoran/Makefile b/drivers/media/pci/zoran/Makefile
new file mode 100644
index 0000000..44cc133
--- /dev/null
+++ b/drivers/media/pci/zoran/Makefile
@@ -0,0 +1,6 @@
+zr36067-objs	:=	zoran_procfs.o zoran_device.o \
+			zoran_driver.o zoran_card.o
+
+obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o
+obj-$(CONFIG_VIDEO_ZORAN_DC30) += zr36050.o zr36016.o
+obj-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o
diff --git a/drivers/media/pci/zoran/videocodec.c b/drivers/media/pci/zoran/videocodec.c
new file mode 100644
index 0000000..c010716
--- /dev/null
+++ b/drivers/media/pci/zoran/videocodec.c
@@ -0,0 +1,407 @@
+/*
+ * VIDEO MOTION CODECs internal API for video devices
+ *
+ * Interface for MJPEG (and maybe later MPEG/WAVELETS) codec's
+ * bound to a master device.
+ *
+ * (c) 2002 Wolfgang Scherr <scherr@net4you.at>
+ *
+ * $Id: videocodec.c,v 1.1.2.8 2003/03/29 07:16:04 rbultje Exp $
+ *
+ * ------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * ------------------------------------------------------------------------
+ */
+
+#define VIDEOCODEC_VERSION "v0.2"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+
+// kernel config is here (procfs flag)
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+#endif
+
+#include "videocodec.h"
+
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-4)");
+
+#define dprintk(num, format, args...) \
+	do { \
+		if (debug >= num) \
+			printk(format, ##args); \
+	} while (0)
+
+struct attached_list {
+	struct videocodec *codec;
+	struct attached_list *next;
+};
+
+struct codec_list {
+	const struct videocodec *codec;
+	int attached;
+	struct attached_list *list;
+	struct codec_list *next;
+};
+
+static struct codec_list *codeclist_top = NULL;
+
+/* ================================================= */
+/* function prototypes of the master/slave interface */
+/* ================================================= */
+
+struct videocodec *
+videocodec_attach (struct videocodec_master *master)
+{
+	struct codec_list *h = codeclist_top;
+	struct attached_list *a, *ptr;
+	struct videocodec *codec;
+	int res;
+
+	if (!master) {
+		dprintk(1, KERN_ERR "videocodec_attach: no data\n");
+		return NULL;
+	}
+
+	dprintk(2,
+		"videocodec_attach: '%s', flags %lx, magic %lx\n",
+		master->name, master->flags, master->magic);
+
+	if (!h) {
+		dprintk(1,
+			KERN_ERR
+			"videocodec_attach: no device available\n");
+		return NULL;
+	}
+
+	while (h) {
+		// attach only if the slave has at least the flags
+		// expected by the master
+		if ((master->flags & h->codec->flags) == master->flags) {
+			dprintk(4, "videocodec_attach: try '%s'\n",
+				h->codec->name);
+
+			if (!try_module_get(h->codec->owner))
+				return NULL;
+
+			codec = kmemdup(h->codec, sizeof(struct videocodec),
+					GFP_KERNEL);
+			if (!codec) {
+				dprintk(1,
+					KERN_ERR
+					"videocodec_attach: no mem\n");
+				goto out_module_put;
+			}
+
+			snprintf(codec->name, sizeof(codec->name),
+				 "%s[%d]", codec->name, h->attached);
+			codec->master_data = master;
+			res = codec->setup(codec);
+			if (res == 0) {
+				dprintk(3, "videocodec_attach '%s'\n",
+					codec->name);
+				ptr = kzalloc(sizeof(struct attached_list), GFP_KERNEL);
+				if (!ptr) {
+					dprintk(1,
+						KERN_ERR
+						"videocodec_attach: no memory\n");
+					goto out_kfree;
+				}
+				ptr->codec = codec;
+
+				a = h->list;
+				if (!a) {
+					h->list = ptr;
+					dprintk(4,
+						"videocodec: first element\n");
+				} else {
+					while (a->next)
+						a = a->next;	// find end
+					a->next = ptr;
+					dprintk(4,
+						"videocodec: in after '%s'\n",
+						h->codec->name);
+				}
+
+				h->attached += 1;
+				return codec;
+			} else {
+				kfree(codec);
+			}
+		}
+		h = h->next;
+	}
+
+	dprintk(1, KERN_ERR "videocodec_attach: no codec found!\n");
+	return NULL;
+
+ out_module_put:
+	module_put(h->codec->owner);
+ out_kfree:
+	kfree(codec);
+	return NULL;
+}
+
+int
+videocodec_detach (struct videocodec *codec)
+{
+	struct codec_list *h = codeclist_top;
+	struct attached_list *a, *prev;
+	int res;
+
+	if (!codec) {
+		dprintk(1, KERN_ERR "videocodec_detach: no data\n");
+		return -EINVAL;
+	}
+
+	dprintk(2,
+		"videocodec_detach: '%s', type: %x, flags %lx, magic %lx\n",
+		codec->name, codec->type, codec->flags, codec->magic);
+
+	if (!h) {
+		dprintk(1,
+			KERN_ERR "videocodec_detach: no device left...\n");
+		return -ENXIO;
+	}
+
+	while (h) {
+		a = h->list;
+		prev = NULL;
+		while (a) {
+			if (codec == a->codec) {
+				res = a->codec->unset(a->codec);
+				if (res >= 0) {
+					dprintk(3,
+						"videocodec_detach: '%s'\n",
+						a->codec->name);
+					a->codec->master_data = NULL;
+				} else {
+					dprintk(1,
+						KERN_ERR
+						"videocodec_detach: '%s'\n",
+						a->codec->name);
+					a->codec->master_data = NULL;
+				}
+				if (prev == NULL) {
+					h->list = a->next;
+					dprintk(4,
+						"videocodec: delete first\n");
+				} else {
+					prev->next = a->next;
+					dprintk(4,
+						"videocodec: delete middle\n");
+				}
+				module_put(a->codec->owner);
+				kfree(a->codec);
+				kfree(a);
+				h->attached -= 1;
+				return 0;
+			}
+			prev = a;
+			a = a->next;
+		}
+		h = h->next;
+	}
+
+	dprintk(1, KERN_ERR "videocodec_detach: given codec not found!\n");
+	return -EINVAL;
+}
+
+int
+videocodec_register (const struct videocodec *codec)
+{
+	struct codec_list *ptr, *h = codeclist_top;
+
+	if (!codec) {
+		dprintk(1, KERN_ERR "videocodec_register: no data!\n");
+		return -EINVAL;
+	}
+
+	dprintk(2,
+		"videocodec: register '%s', type: %x, flags %lx, magic %lx\n",
+		codec->name, codec->type, codec->flags, codec->magic);
+
+	ptr = kzalloc(sizeof(struct codec_list), GFP_KERNEL);
+	if (!ptr) {
+		dprintk(1, KERN_ERR "videocodec_register: no memory\n");
+		return -ENOMEM;
+	}
+	ptr->codec = codec;
+
+	if (!h) {
+		codeclist_top = ptr;
+		dprintk(4, "videocodec: hooked in as first element\n");
+	} else {
+		while (h->next)
+			h = h->next;	// find the end
+		h->next = ptr;
+		dprintk(4, "videocodec: hooked in after '%s'\n",
+			h->codec->name);
+	}
+
+	return 0;
+}
+
+int
+videocodec_unregister (const struct videocodec *codec)
+{
+	struct codec_list *prev = NULL, *h = codeclist_top;
+
+	if (!codec) {
+		dprintk(1, KERN_ERR "videocodec_unregister: no data!\n");
+		return -EINVAL;
+	}
+
+	dprintk(2,
+		"videocodec: unregister '%s', type: %x, flags %lx, magic %lx\n",
+		codec->name, codec->type, codec->flags, codec->magic);
+
+	if (!h) {
+		dprintk(1,
+			KERN_ERR
+			"videocodec_unregister: no device left...\n");
+		return -ENXIO;
+	}
+
+	while (h) {
+		if (codec == h->codec) {
+			if (h->attached) {
+				dprintk(1,
+					KERN_ERR
+					"videocodec: '%s' is used\n",
+					h->codec->name);
+				return -EBUSY;
+			}
+			dprintk(3, "videocodec: unregister '%s' is ok.\n",
+				h->codec->name);
+			if (prev == NULL) {
+				codeclist_top = h->next;
+				dprintk(4,
+					"videocodec: delete first element\n");
+			} else {
+				prev->next = h->next;
+				dprintk(4,
+					"videocodec: delete middle element\n");
+			}
+			kfree(h);
+			return 0;
+		}
+		prev = h;
+		h = h->next;
+	}
+
+	dprintk(1,
+		KERN_ERR
+		"videocodec_unregister: given codec not found!\n");
+	return -EINVAL;
+}
+
+#ifdef CONFIG_PROC_FS
+static int proc_videocodecs_show(struct seq_file *m, void *v)
+{
+	struct codec_list *h = codeclist_top;
+	struct attached_list *a;
+
+	seq_printf(m, "<S>lave or attached <M>aster name  type flags    magic    ");
+	seq_printf(m, "(connected as)\n");
+
+	h = codeclist_top;
+	while (h) {
+		seq_printf(m, "S %32s %04x %08lx %08lx (TEMPLATE)\n",
+			      h->codec->name, h->codec->type,
+			      h->codec->flags, h->codec->magic);
+		a = h->list;
+		while (a) {
+			seq_printf(m, "M %32s %04x %08lx %08lx (%s)\n",
+				      a->codec->master_data->name,
+				      a->codec->master_data->type,
+				      a->codec->master_data->flags,
+				      a->codec->master_data->magic,
+				      a->codec->name);
+			a = a->next;
+		}
+		h = h->next;
+	}
+
+	return 0;
+}
+
+static int proc_videocodecs_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, proc_videocodecs_show, NULL);
+}
+
+static const struct file_operations videocodecs_proc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= proc_videocodecs_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+#endif
+
+/* ===================== */
+/* hook in driver module */
+/* ===================== */
+static int __init
+videocodec_init (void)
+{
+#ifdef CONFIG_PROC_FS
+	static struct proc_dir_entry *videocodec_proc_entry;
+#endif
+
+	printk(KERN_INFO "Linux video codec intermediate layer: %s\n",
+	       VIDEOCODEC_VERSION);
+
+#ifdef CONFIG_PROC_FS
+	videocodec_proc_entry = proc_create("videocodecs", 0, NULL, &videocodecs_proc_fops);
+	if (!videocodec_proc_entry) {
+		dprintk(1, KERN_ERR "videocodec: can't init procfs.\n");
+	}
+#endif
+	return 0;
+}
+
+static void __exit
+videocodec_exit (void)
+{
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("videocodecs", NULL);
+#endif
+}
+
+EXPORT_SYMBOL(videocodec_attach);
+EXPORT_SYMBOL(videocodec_detach);
+EXPORT_SYMBOL(videocodec_register);
+EXPORT_SYMBOL(videocodec_unregister);
+
+module_init(videocodec_init);
+module_exit(videocodec_exit);
+
+MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>");
+MODULE_DESCRIPTION("Intermediate API module for video codecs "
+		   VIDEOCODEC_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/zoran/videocodec.h b/drivers/media/pci/zoran/videocodec.h
new file mode 100644
index 0000000..def5558
--- /dev/null
+++ b/drivers/media/pci/zoran/videocodec.h
@@ -0,0 +1,353 @@
+/*
+ * VIDEO MOTION CODECs internal API for video devices
+ *
+ * Interface for MJPEG (and maybe later MPEG/WAVELETS) codec's
+ * bound to a master device.
+ *
+ * (c) 2002 Wolfgang Scherr <scherr@net4you.at>
+ *
+ * $Id: videocodec.h,v 1.1.2.4 2003/01/14 21:15:03 rbultje Exp $
+ *
+ * ------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * ------------------------------------------------------------------------
+ */
+
+/* =================== */
+/* general description */
+/* =================== */
+
+/* Should ease the (re-)usage of drivers supporting cards with (different)
+   video codecs. The codecs register to this module their functionality,
+   and the processors (masters) can attach to them if they fit.
+
+   The codecs are typically have a "strong" binding to their master - so I
+   don't think it makes sense to have a full blown interfacing as with e.g.
+   i2c. If you have an other opinion, let's discuss & implement it :-)))
+
+   Usage:
+
+   The slave has just to setup the videocodec structure and use two functions:
+   videocodec_register(codecdata);
+   videocodec_unregister(codecdata);
+   The best is just calling them at module (de-)initialisation.
+
+   The master sets up the structure videocodec_master and calls:
+   codecdata=videocodec_attach(master_codecdata);
+   videocodec_detach(codecdata);
+
+   The slave is called during attach/detach via functions setup previously
+   during register. At that time, the master_data pointer is set up
+   and the slave can access any io registers of the master device (in the case
+   the slave is bound to it). Otherwise it doesn't need this functions and
+   therfor they may not be initialized.
+
+   The other functions are just for convenience, as they are for sure used by
+   most/all of the codecs. The last ones may be omitted, too.
+
+   See the structure declaration below for more information and which data has
+   to be set up for the master and the slave.
+
+   ----------------------------------------------------------------------------
+   The master should have "knowledge" of the slave and vice versa.  So the data
+   structures sent to/from slave via set_data/get_data set_image/get_image are
+   device dependent and vary between MJPEG/MPEG/WAVELET/... devices. (!!!!)
+   ----------------------------------------------------------------------------
+*/
+
+
+/* ========================================== */
+/* description of the videocodec_io structure */
+/* ========================================== */
+
+/*
+   ==== master setup ====
+   name -> name of the device structure for reference and debugging
+   master_data ->  data ref. for the master (e.g. the zr36055,57,67)
+   readreg -> ref. to read-fn from register (setup by master, used by slave)
+   writereg -> ref. to write-fn to register (setup by master, used by slave)
+	       this two functions do the lowlevel I/O job
+
+   ==== slave functionality setup ====
+   slave_data -> data ref. for the slave (e.g. the zr36050,60)
+   check -> fn-ref. checks availability of an device, returns -EIO on failure or
+	    the type on success
+	    this makes espcecially sense if a driver module supports more than
+	    one codec which may be quite similar to access, nevertheless it
+	    is good for a first functionality check
+
+   -- main functions you always need for compression/decompression --
+
+   set_mode -> this fn-ref. resets the entire codec, and sets up the mode
+	       with the last defined norm/size (or device default if not
+	       available) - it returns 0 if the mode is possible
+   set_size -> this fn-ref. sets the norm and image size for
+	       compression/decompression (returns 0 on success)
+	       the norm param is defined in videodev2.h (V4L2_STD_*)
+
+   additional setup may be available, too - but the codec should work with
+   some default values even without this
+
+   set_data -> sets device-specific data (tables, quality etc.)
+   get_data -> query device-specific data (tables, quality etc.)
+
+   if the device delivers interrupts, they may be setup/handled here
+   setup_interrupt -> codec irq setup (not needed for 36050/60)
+   handle_interrupt -> codec irq handling (not needed for 36050/60)
+
+   if the device delivers pictures, they may be handled here
+   put_image -> puts image data to the codec (not needed for 36050/60)
+   get_image -> gets image data from the codec (not needed for 36050/60)
+		the calls include frame numbers and flags (even/odd/...)
+		if needed and a flag which allows blocking until its ready
+*/
+
+/* ============== */
+/* user interface */
+/* ============== */
+
+/*
+   Currently there is only a information display planned, as the layer
+   is not visible for the user space at all.
+
+   Information is available via procfs. The current entry is "/proc/videocodecs"
+   but it makes sense to "hide" it in the /proc/video tree of v4l(2) --TODO--.
+
+A example for such an output is:
+
+<S>lave or attached <M>aster name  type flags    magic    (connected as)
+S                          zr36050 0002 0000d001 00000000 (TEMPLATE)
+M                       zr36055[0] 0001 0000c001 00000000 (zr36050[0])
+M                       zr36055[1] 0001 0000c001 00000000 (zr36050[1])
+
+*/
+
+
+/* =============================================== */
+/* special defines for the videocodec_io structure */
+/* =============================================== */
+
+#ifndef __LINUX_VIDEOCODEC_H
+#define __LINUX_VIDEOCODEC_H
+
+#include <linux/videodev2.h>
+
+#define CODEC_DO_COMPRESSION 0
+#define CODEC_DO_EXPANSION   1
+
+/* this are the current codec flags I think they are needed */
+/*  -> type value in structure */
+#define CODEC_FLAG_JPEG      0x00000001L	// JPEG codec
+#define CODEC_FLAG_MPEG      0x00000002L	// MPEG1/2/4 codec
+#define CODEC_FLAG_DIVX      0x00000004L	// DIVX codec
+#define CODEC_FLAG_WAVELET   0x00000008L	// WAVELET codec
+					  // room for other types
+
+#define CODEC_FLAG_MAGIC     0x00000800L	// magic key must match
+#define CODEC_FLAG_HARDWARE  0x00001000L	// is a hardware codec
+#define CODEC_FLAG_VFE       0x00002000L	// has direct video frontend
+#define CODEC_FLAG_ENCODER   0x00004000L	// compression capability
+#define CODEC_FLAG_DECODER   0x00008000L	// decompression capability
+#define CODEC_FLAG_NEEDIRQ   0x00010000L	// needs irq handling
+#define CODEC_FLAG_RDWRPIC   0x00020000L	// handles picture I/O
+
+/* a list of modes, some are just examples (is there any HW?) */
+#define CODEC_MODE_BJPG      0x0001	// Baseline JPEG
+#define CODEC_MODE_LJPG      0x0002	// Lossless JPEG
+#define CODEC_MODE_MPEG1     0x0003	// MPEG 1
+#define CODEC_MODE_MPEG2     0x0004	// MPEG 2
+#define CODEC_MODE_MPEG4     0x0005	// MPEG 4
+#define CODEC_MODE_MSDIVX    0x0006	// MS DivX
+#define CODEC_MODE_ODIVX     0x0007	// Open DivX
+#define CODEC_MODE_WAVELET   0x0008	// Wavelet
+
+/* this are the current codec types I want to implement */
+/*  -> type value in structure */
+#define CODEC_TYPE_NONE    0
+#define CODEC_TYPE_L64702  1
+#define CODEC_TYPE_ZR36050 2
+#define CODEC_TYPE_ZR36016 3
+#define CODEC_TYPE_ZR36060 4
+
+/* the type of data may be enhanced by future implementations (data-fn.'s) */
+/*  -> used in command                                                     */
+#define CODEC_G_STATUS         0x0000	/* codec status (query only) */
+#define CODEC_S_CODEC_MODE     0x0001	/* codec mode (baseline JPEG, MPEG1,... */
+#define CODEC_G_CODEC_MODE     0x8001
+#define CODEC_S_VFE            0x0002	/* additional video frontend setup */
+#define CODEC_G_VFE            0x8002
+#define CODEC_S_MMAP           0x0003	/* MMAP setup (if available) */
+
+#define CODEC_S_JPEG_TDS_BYTE  0x0010	/* target data size in bytes */
+#define CODEC_G_JPEG_TDS_BYTE  0x8010
+#define CODEC_S_JPEG_SCALE     0x0011	/* scaling factor for quant. tables */
+#define CODEC_G_JPEG_SCALE     0x8011
+#define CODEC_S_JPEG_HDT_DATA  0x0018	/* huffman-tables */
+#define CODEC_G_JPEG_HDT_DATA  0x8018
+#define CODEC_S_JPEG_QDT_DATA  0x0019	/* quantizing-tables */
+#define CODEC_G_JPEG_QDT_DATA  0x8019
+#define CODEC_S_JPEG_APP_DATA  0x001A	/* APP marker */
+#define CODEC_G_JPEG_APP_DATA  0x801A
+#define CODEC_S_JPEG_COM_DATA  0x001B	/* COM marker */
+#define CODEC_G_JPEG_COM_DATA  0x801B
+
+#define CODEC_S_PRIVATE        0x1000	/* "private" commands start here */
+#define CODEC_G_PRIVATE        0x9000
+
+#define CODEC_G_FLAG           0x8000	/* this is how 'get' is detected */
+
+/* types of transfer, directly user space or a kernel buffer (image-fn.'s) */
+/*  -> used in get_image, put_image                                        */
+#define CODEC_TRANSFER_KERNEL 0	/* use "memcopy" */
+#define CODEC_TRANSFER_USER   1	/* use "to/from_user" */
+
+
+/* ========================= */
+/* the structures itself ... */
+/* ========================= */
+
+struct vfe_polarity {
+	unsigned int vsync_pol:1;
+	unsigned int hsync_pol:1;
+	unsigned int field_pol:1;
+	unsigned int blank_pol:1;
+	unsigned int subimg_pol:1;
+	unsigned int poe_pol:1;
+	unsigned int pvalid_pol:1;
+	unsigned int vclk_pol:1;
+};
+
+struct vfe_settings {
+	__u32 x, y;		/* Offsets into image */
+	__u32 width, height;	/* Area to capture */
+	__u16 decimation;	/* Decimation divider */
+	__u16 flags;		/* Flags for capture */
+	__u16 quality;		/* quality of the video */
+};
+
+struct tvnorm {
+	u16 Wt, Wa, HStart, HSyncStart, Ht, Ha, VStart;
+};
+
+struct jpeg_com_marker {
+	int len; /* number of usable bytes in data */
+	char data[60];
+};
+
+struct jpeg_app_marker {
+	int appn; /* number app segment */
+	int len; /* number of usable bytes in data */
+	char data[60];
+};
+
+struct videocodec {
+	struct module *owner;
+	/* -- filled in by slave device during register -- */
+	char name[32];
+	unsigned long magic;	/* may be used for client<->master attaching */
+	unsigned long flags;	/* functionality flags */
+	unsigned int type;	/* codec type */
+
+	/* -- these is filled in later during master device attach -- */
+
+	struct videocodec_master *master_data;
+
+	/* -- these are filled in by the slave device during register -- */
+
+	void *data;		/* private slave data */
+
+	/* attach/detach client functions (indirect call) */
+	int (*setup) (struct videocodec * codec);
+	int (*unset) (struct videocodec * codec);
+
+	/* main functions, every client needs them for sure! */
+	// set compression or decompression (or freeze, stop, standby, etc)
+	int (*set_mode) (struct videocodec * codec,
+			 int mode);
+	// setup picture size and norm (for the codec's video frontend)
+	int (*set_video) (struct videocodec * codec,
+			  struct tvnorm * norm,
+			  struct vfe_settings * cap,
+			  struct vfe_polarity * pol);
+	// other control commands, also mmap setup etc.
+	int (*control) (struct videocodec * codec,
+			int type,
+			int size,
+			void *data);
+
+	/* additional setup/query/processing (may be NULL pointer) */
+	// interrupt setup / handling (for irq's delivered by master)
+	int (*setup_interrupt) (struct videocodec * codec,
+				long mode);
+	int (*handle_interrupt) (struct videocodec * codec,
+				 int source,
+				 long flag);
+	// picture interface (if any)
+	long (*put_image) (struct videocodec * codec,
+			   int tr_type,
+			   int block,
+			   long *fr_num,
+			   long *flag,
+			   long size,
+			   void *buf);
+	long (*get_image) (struct videocodec * codec,
+			   int tr_type,
+			   int block,
+			   long *fr_num,
+			   long *flag,
+			   long size,
+			   void *buf);
+};
+
+struct videocodec_master {
+	/* -- filled in by master device for registration -- */
+	char name[32];
+	unsigned long magic;	/* may be used for client<->master attaching */
+	unsigned long flags;	/* functionality flags */
+	unsigned int type;	/* master type */
+
+	void *data;		/* private master data */
+
+	 __u32(*readreg) (struct videocodec * codec,
+			  __u16 reg);
+	void (*writereg) (struct videocodec * codec,
+			  __u16 reg,
+			  __u32 value);
+};
+
+
+/* ================================================= */
+/* function prototypes of the master/slave interface */
+/* ================================================= */
+
+/* attach and detach commands for the master */
+// * master structure needs to be kmalloc'ed before calling attach
+//   and free'd after calling detach
+// * returns pointer on success, NULL on failure
+extern struct videocodec *videocodec_attach(struct videocodec_master *);
+// * 0 on success, <0 (errno) on failure
+extern int videocodec_detach(struct videocodec *);
+
+/* register and unregister commands for the slaves */
+// * 0 on success, <0 (errno) on failure
+extern int videocodec_register(const struct videocodec *);
+// * 0 on success, <0 (errno) on failure
+extern int videocodec_unregister(const struct videocodec *);
+
+/* the other calls are directly done via the videocodec structure! */
+
+#endif				/*ifndef __LINUX_VIDEOCODEC_H */
diff --git a/drivers/media/pci/zoran/zoran.h b/drivers/media/pci/zoran/zoran.h
new file mode 100644
index 0000000..ca2754a
--- /dev/null
+++ b/drivers/media/pci/zoran/zoran.h
@@ -0,0 +1,403 @@
+/*
+ * zoran - Iomega Buz driver
+ *
+ * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
+ *
+ * based on
+ *
+ * zoran.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ *
+ * and
+ *
+ * bttv - Bt848 frame grabber driver
+ * Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+ *                        & Marcus Metzler (mocm@thp.uni-koeln.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _BUZ_H_
+#define _BUZ_H_
+
+#include <media/v4l2-device.h>
+
+struct zoran_sync {
+	unsigned long frame;	/* number of buffer that has been free'd */
+	unsigned long length;	/* number of code bytes in buffer (capture only) */
+	unsigned long seq;	/* frame sequence number */
+	struct timeval timestamp;	/* timestamp */
+};
+
+
+#define ZORAN_NAME    "ZORAN"	/* name of the device */
+
+#define ZR_DEVNAME(zr) ((zr)->name)
+
+#define   BUZ_MAX_WIDTH   (zr->timing->Wa)
+#define   BUZ_MAX_HEIGHT  (zr->timing->Ha)
+#define   BUZ_MIN_WIDTH    32	/* never display less than 32 pixels */
+#define   BUZ_MIN_HEIGHT   24	/* never display less than 24 rows */
+
+#define BUZ_NUM_STAT_COM    4
+#define BUZ_MASK_STAT_COM   3
+
+#define BUZ_MAX_FRAME     256	/* Must be a power of 2 */
+#define BUZ_MASK_FRAME    255	/* Must be BUZ_MAX_FRAME-1 */
+
+#define BUZ_MAX_INPUT       16
+
+#if VIDEO_MAX_FRAME <= 32
+#   define   V4L_MAX_FRAME   32
+#elif VIDEO_MAX_FRAME <= 64
+#   define   V4L_MAX_FRAME   64
+#else
+#   error   "Too many video frame buffers to handle"
+#endif
+#define   V4L_MASK_FRAME   (V4L_MAX_FRAME - 1)
+
+#define MAX_FRAME (BUZ_MAX_FRAME > VIDEO_MAX_FRAME ? BUZ_MAX_FRAME : VIDEO_MAX_FRAME)
+
+#include "zr36057.h"
+
+enum card_type {
+	UNKNOWN = -1,
+
+	/* Pinnacle/Miro */
+	DC10_old,		/* DC30 like */
+	DC10_new,		/* DC10plus like */
+	DC10plus,
+	DC30,
+	DC30plus,
+
+	/* Linux Media Labs */
+	LML33,
+	LML33R10,
+
+	/* Iomega */
+	BUZ,
+
+	/* AverMedia */
+	AVS6EYES,
+
+	/* total number of cards */
+	NUM_CARDS
+};
+
+enum zoran_codec_mode {
+	BUZ_MODE_IDLE,		/* nothing going on */
+	BUZ_MODE_MOTION_COMPRESS,	/* grabbing frames */
+	BUZ_MODE_MOTION_DECOMPRESS,	/* playing frames */
+	BUZ_MODE_STILL_COMPRESS,	/* still frame conversion */
+	BUZ_MODE_STILL_DECOMPRESS	/* still frame conversion */
+};
+
+enum zoran_buffer_state {
+	BUZ_STATE_USER,		/* buffer is owned by application */
+	BUZ_STATE_PEND,		/* buffer is queued in pend[] ready to feed to I/O */
+	BUZ_STATE_DMA,		/* buffer is queued in dma[] for I/O */
+	BUZ_STATE_DONE		/* buffer is ready to return to application */
+};
+
+enum zoran_map_mode {
+	ZORAN_MAP_MODE_RAW,
+	ZORAN_MAP_MODE_JPG_REC,
+#define ZORAN_MAP_MODE_JPG ZORAN_MAP_MODE_JPG_REC
+	ZORAN_MAP_MODE_JPG_PLAY,
+};
+
+enum gpio_type {
+	ZR_GPIO_JPEG_SLEEP = 0,
+	ZR_GPIO_JPEG_RESET,
+	ZR_GPIO_JPEG_FRAME,
+	ZR_GPIO_VID_DIR,
+	ZR_GPIO_VID_EN,
+	ZR_GPIO_VID_RESET,
+	ZR_GPIO_CLK_SEL1,
+	ZR_GPIO_CLK_SEL2,
+	ZR_GPIO_MAX,
+};
+
+enum gpcs_type {
+	GPCS_JPEG_RESET = 0,
+	GPCS_JPEG_START,
+	GPCS_MAX,
+};
+
+struct zoran_format {
+	char *name;
+	__u32 fourcc;
+	int colorspace;
+	int depth;
+	__u32 flags;
+	__u32 vfespfr;
+};
+/* flags */
+#define ZORAN_FORMAT_COMPRESSED 1<<0
+#define ZORAN_FORMAT_OVERLAY    1<<1
+#define ZORAN_FORMAT_CAPTURE	1<<2
+#define ZORAN_FORMAT_PLAYBACK	1<<3
+
+/* overlay-settings */
+struct zoran_overlay_settings {
+	int is_set;
+	int x, y, width, height;	/* position */
+	int clipcount;		/* position and number of clips */
+	const struct zoran_format *format;	/* overlay format */
+};
+
+/* v4l-capture settings */
+struct zoran_v4l_settings {
+	int width, height, bytesperline;	/* capture size */
+	const struct zoran_format *format;	/* capture format */
+};
+
+/* jpg-capture/-playback settings */
+struct zoran_jpg_settings {
+	int decimation;		/* this bit is used to set everything to default */
+	int HorDcm, VerDcm, TmpDcm;	/* capture decimation settings (TmpDcm=1 means both fields) */
+	int field_per_buff, odd_even;	/* field-settings (odd_even=1 (+TmpDcm=1) means top-field-first) */
+	int img_x, img_y, img_width, img_height;	/* crop settings (subframe capture) */
+	struct v4l2_jpegcompression jpg_comp;	/* JPEG-specific capture settings */
+};
+
+struct zoran_fh;
+
+struct zoran_mapping {
+	struct zoran_fh *fh;
+	int count;
+};
+
+struct zoran_buffer {
+	struct zoran_mapping *map;
+	enum zoran_buffer_state state;	/* state: unused/pending/dma/done */
+	struct zoran_sync bs;		/* DONE: info to return to application */
+	union {
+		struct {
+			__le32 *frag_tab;	/* addresses of frag table */
+			u32 frag_tab_bus;	/* same value cached to save time in ISR */
+		} jpg;
+		struct {
+			char *fbuffer;		/* virtual address of frame buffer */
+			unsigned long fbuffer_phys;/* physical address of frame buffer */
+			unsigned long fbuffer_bus;/* bus address of frame buffer */
+		} v4l;
+	};
+};
+
+enum zoran_lock_activity {
+	ZORAN_FREE,		/* free for use */
+	ZORAN_ACTIVE,		/* active but unlocked */
+	ZORAN_LOCKED,		/* locked */
+};
+
+/* buffer collections */
+struct zoran_buffer_col {
+	enum zoran_lock_activity active;	/* feature currently in use? */
+	unsigned int num_buffers, buffer_size;
+	struct zoran_buffer buffer[MAX_FRAME];	/* buffers */
+	u8 allocated;		/* Flag if buffers are allocated  */
+	u8 need_contiguous;	/* Flag if contiguous buffers are needed */
+	/* only applies to jpg buffers, raw buffers are always contiguous */
+};
+
+struct zoran;
+
+/* zoran_fh contains per-open() settings */
+struct zoran_fh {
+	struct zoran *zr;
+
+	enum zoran_map_mode map_mode;		/* Flag which bufferset will map by next mmap() */
+
+	struct zoran_overlay_settings overlay_settings;
+	u32 *overlay_mask;			/* overlay mask */
+	enum zoran_lock_activity overlay_active;/* feature currently in use? */
+
+	struct zoran_buffer_col buffers;	/* buffers' info */
+
+	struct zoran_v4l_settings v4l_settings;	/* structure with a lot of things to play with */
+	struct zoran_jpg_settings jpg_settings;	/* structure with a lot of things to play with */
+};
+
+struct card_info {
+	enum card_type type;
+	char name[32];
+	const char *i2c_decoder;	/* i2c decoder device */
+	const unsigned short *addrs_decoder;
+	const char *i2c_encoder;	/* i2c encoder device */
+	const unsigned short *addrs_encoder;
+	u16 video_vfe, video_codec;			/* videocodec types */
+	u16 audio_chip;					/* audio type */
+
+	int inputs;		/* number of video inputs */
+	struct input {
+		int muxsel;
+		char name[32];
+	} input[BUZ_MAX_INPUT];
+
+	v4l2_std_id norms;
+	struct tvnorm *tvn[3];	/* supported TV norms */
+
+	u32 jpeg_int;		/* JPEG interrupt */
+	u32 vsync_int;		/* VSYNC interrupt */
+	s8 gpio[ZR_GPIO_MAX];
+	u8 gpcs[GPCS_MAX];
+
+	struct vfe_polarity vfe_pol;
+	u8 gpio_pol[ZR_GPIO_MAX];
+
+	/* is the /GWS line connected? */
+	u8 gws_not_connected;
+
+	/* avs6eyes mux setting */
+	u8 input_mux;
+
+	void (*init) (struct zoran * zr);
+};
+
+struct zoran {
+	struct v4l2_device v4l2_dev;
+	struct video_device *video_dev;
+
+	struct i2c_adapter i2c_adapter;	/* */
+	struct i2c_algo_bit_data i2c_algo;	/* */
+	u32 i2cbr;
+
+	struct v4l2_subdev *decoder;	/* video decoder sub-device */
+	struct v4l2_subdev *encoder;	/* video encoder sub-device */
+
+	struct videocodec *codec;	/* video codec */
+	struct videocodec *vfe;	/* video front end */
+
+	struct mutex resource_lock;	/* prevent evil stuff */
+	struct mutex other_lock;	/* please merge with above */
+
+	u8 initialized;		/* flag if zoran has been correctly initialized */
+	int user;		/* number of current users */
+	struct card_info card;
+	struct tvnorm *timing;
+
+	unsigned short id;	/* number of this device */
+	char name[32];		/* name of this device */
+	struct pci_dev *pci_dev;	/* PCI device */
+	unsigned char revision;	/* revision of zr36057 */
+	unsigned char __iomem *zr36057_mem;/* pointer to mapped IO memory */
+
+	spinlock_t spinlock;	/* Spinlock */
+
+	/* Video for Linux parameters */
+	int input;	/* card's norm and input */
+	v4l2_std_id norm;
+
+	/* Current buffer params */
+	void    *vbuf_base;
+	int     vbuf_height, vbuf_width;
+	int     vbuf_depth;
+	int     vbuf_bytesperline;
+
+	struct zoran_overlay_settings overlay_settings;
+	u32 *overlay_mask;	/* overlay mask */
+	enum zoran_lock_activity overlay_active;	/* feature currently in use? */
+
+	wait_queue_head_t v4l_capq;
+
+	int v4l_overlay_active;	/* Overlay grab is activated */
+	int v4l_memgrab_active;	/* Memory grab is activated */
+
+	int v4l_grab_frame;	/* Frame number being currently grabbed */
+#define NO_GRAB_ACTIVE (-1)
+	unsigned long v4l_grab_seq;	/* Number of frames grabbed */
+	struct zoran_v4l_settings v4l_settings;	/* structure with a lot of things to play with */
+
+	/* V4L grab queue of frames pending */
+	unsigned long v4l_pend_head;
+	unsigned long v4l_pend_tail;
+	unsigned long v4l_sync_tail;
+	int v4l_pend[V4L_MAX_FRAME];
+	struct zoran_buffer_col v4l_buffers;	/* V4L buffers' info */
+
+	/* Buz MJPEG parameters */
+	enum zoran_codec_mode codec_mode;	/* status of codec */
+	struct zoran_jpg_settings jpg_settings;	/* structure with a lot of things to play with */
+
+	wait_queue_head_t jpg_capq;	/* wait here for grab to finish */
+
+	/* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */
+	/* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */
+	/* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */
+	unsigned long jpg_que_head;	/* Index where to put next buffer which is queued */
+	unsigned long jpg_dma_head;	/* Index of next buffer which goes into stat_com  */
+	unsigned long jpg_dma_tail;	/* Index of last buffer in stat_com               */
+	unsigned long jpg_que_tail;	/* Index of last buffer in queue                  */
+	unsigned long jpg_seq_num;	/* count of frames since grab/play started        */
+	unsigned long jpg_err_seq;	/* last seq_num before error                      */
+	unsigned long jpg_err_shift;
+	unsigned long jpg_queued_num;	/* count of frames queued since grab/play started */
+
+	/* zr36057's code buffer table */
+	__le32 *stat_com;		/* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */
+
+	/* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */
+	int jpg_pend[BUZ_MAX_FRAME];
+
+	/* array indexed by frame number */
+	struct zoran_buffer_col jpg_buffers;	/* MJPEG buffers' info */
+
+	/* Additional stuff for testing */
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *zoran_proc;
+#else
+	void *zoran_proc;
+#endif
+	int testing;
+	int jpeg_error;
+	int intr_counter_GIRQ1;
+	int intr_counter_GIRQ0;
+	int intr_counter_CodRepIRQ;
+	int intr_counter_JPEGRepIRQ;
+	int field_counter;
+	int IRQ1_in;
+	int IRQ1_out;
+	int JPEG_in;
+	int JPEG_out;
+	int JPEG_0;
+	int JPEG_1;
+	int END_event_missed;
+	int JPEG_missed;
+	int JPEG_error;
+	int num_errors;
+	int JPEG_max_missed;
+	int JPEG_min_missed;
+
+	u32 last_isr;
+	unsigned long frame_num;
+
+	wait_queue_head_t test_q;
+};
+
+static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev)
+{
+	return container_of(v4l2_dev, struct zoran, v4l2_dev);
+}
+
+/* There was something called _ALPHA_BUZ that used the PCI address instead of
+ * the kernel iomapped address for btread/btwrite.  */
+#define btwrite(dat,adr)    writel((dat), zr->zr36057_mem+(adr))
+#define btread(adr)         readl(zr->zr36057_mem+(adr))
+
+#define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
+#define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
+#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
+
+#endif
diff --git a/drivers/media/pci/zoran/zoran_card.c b/drivers/media/pci/zoran/zoran_card.c
new file mode 100644
index 0000000..c3602d6
--- /dev/null
+++ b/drivers/media/pci/zoran/zoran_card.c
@@ -0,0 +1,1524 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * This part handles card-specific data and detection
+ *
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Currently maintained by:
+ *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
+ *   Laurent Pinchart <laurent.pinchart@skynet.be>
+ *   Mailinglist      <mjpeg-users@lists.sf.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/delay.h>
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+
+#include <linux/proc_fs.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/videodev2.h>
+#include <linux/spinlock.h>
+#include <linux/sem.h>
+#include <linux/kmod.h>
+#include <linux/wait.h>
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <media/v4l2-common.h>
+#include <media/bt819.h>
+
+#include "videocodec.h"
+#include "zoran.h"
+#include "zoran_card.h"
+#include "zoran_device.h"
+#include "zoran_procfs.h"
+
+extern const struct zoran_format zoran_formats[];
+
+static int card[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 };
+module_param_array(card, int, NULL, 0444);
+MODULE_PARM_DESC(card, "Card type");
+
+/*
+   The video mem address of the video card.
+   The driver has a little database for some videocards
+   to determine it from there. If your video card is not in there
+   you have either to give it to the driver as a parameter
+   or set in in a VIDIOCSFBUF ioctl
+ */
+
+static unsigned long vidmem;	/* default = 0 - Video memory base address */
+module_param(vidmem, ulong, 0444);
+MODULE_PARM_DESC(vidmem, "Default video memory base address");
+
+/*
+   Default input and video norm at startup of the driver.
+*/
+
+static unsigned int default_input;	/* default 0 = Composite, 1 = S-Video */
+module_param(default_input, uint, 0444);
+MODULE_PARM_DESC(default_input,
+		 "Default input (0=Composite, 1=S-Video, 2=Internal)");
+
+static int default_mux = 1;	/* 6 Eyes input selection */
+module_param(default_mux, int, 0644);
+MODULE_PARM_DESC(default_mux,
+		 "Default 6 Eyes mux setting (Input selection)");
+
+static int default_norm;	/* default 0 = PAL, 1 = NTSC 2 = SECAM */
+module_param(default_norm, int, 0444);
+MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)");
+
+/* /dev/videoN, -1 for autodetect */
+static int video_nr[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 };
+module_param_array(video_nr, int, NULL, 0444);
+MODULE_PARM_DESC(video_nr, "Video device number (-1=Auto)");
+
+int v4l_nbufs = 4;
+int v4l_bufsize = 864;		/* Everybody should be able to work with this setting */
+module_param(v4l_nbufs, int, 0644);
+MODULE_PARM_DESC(v4l_nbufs, "Maximum number of V4L buffers to use");
+module_param(v4l_bufsize, int, 0644);
+MODULE_PARM_DESC(v4l_bufsize, "Maximum size per V4L buffer (in kB)");
+
+int jpg_nbufs = 32;
+int jpg_bufsize = 512;		/* max size for 100% quality full-PAL frame */
+module_param(jpg_nbufs, int, 0644);
+MODULE_PARM_DESC(jpg_nbufs, "Maximum number of JPG buffers to use");
+module_param(jpg_bufsize, int, 0644);
+MODULE_PARM_DESC(jpg_bufsize, "Maximum size per JPG buffer (in kB)");
+
+int pass_through = 0;		/* 1=Pass through TV signal when device is not used */
+				/* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */
+module_param(pass_through, int, 0644);
+MODULE_PARM_DESC(pass_through,
+		 "Pass TV signal through to TV-out when idling");
+
+int zr36067_debug = 1;
+module_param_named(debug, zr36067_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-5)");
+
+#define ZORAN_VERSION "0.10.1"
+
+MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver");
+MODULE_AUTHOR("Serguei Miridonov");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(ZORAN_VERSION);
+
+#define ZR_DEVICE(subven, subdev, data)	{ \
+	.vendor = PCI_VENDOR_ID_ZORAN, .device = PCI_DEVICE_ID_ZORAN_36057, \
+	.subvendor = (subven), .subdevice = (subdev), .driver_data = (data) }
+
+static struct pci_device_id zr36067_pci_tbl[] = {
+	ZR_DEVICE(PCI_VENDOR_ID_MIRO, PCI_DEVICE_ID_MIRO_DC10PLUS, DC10plus),
+	ZR_DEVICE(PCI_VENDOR_ID_MIRO, PCI_DEVICE_ID_MIRO_DC30PLUS, DC30plus),
+	ZR_DEVICE(PCI_VENDOR_ID_ELECTRONICDESIGNGMBH, PCI_DEVICE_ID_LML_33R10, LML33R10),
+	ZR_DEVICE(PCI_VENDOR_ID_IOMEGA, PCI_DEVICE_ID_IOMEGA_BUZ, BUZ),
+	ZR_DEVICE(PCI_ANY_ID, PCI_ANY_ID, NUM_CARDS),
+	{0}
+};
+MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl);
+
+static unsigned int zoran_num;		/* number of cards found */
+
+/* videocodec bus functions ZR36060 */
+static u32
+zr36060_read (struct videocodec *codec,
+	      u16                reg)
+{
+	struct zoran *zr = (struct zoran *) codec->master_data->data;
+	__u32 data;
+
+	if (post_office_wait(zr)
+	    || post_office_write(zr, 0, 1, reg >> 8)
+	    || post_office_write(zr, 0, 2, reg & 0xff)) {
+		return -1;
+	}
+
+	data = post_office_read(zr, 0, 3) & 0xff;
+	return data;
+}
+
+static void
+zr36060_write (struct videocodec *codec,
+	       u16                reg,
+	       u32                val)
+{
+	struct zoran *zr = (struct zoran *) codec->master_data->data;
+
+	if (post_office_wait(zr)
+	    || post_office_write(zr, 0, 1, reg >> 8)
+	    || post_office_write(zr, 0, 2, reg & 0xff)) {
+		return;
+	}
+
+	post_office_write(zr, 0, 3, val & 0xff);
+}
+
+/* videocodec bus functions ZR36050 */
+static u32
+zr36050_read (struct videocodec *codec,
+	      u16                reg)
+{
+	struct zoran *zr = (struct zoran *) codec->master_data->data;
+	__u32 data;
+
+	if (post_office_wait(zr)
+	    || post_office_write(zr, 1, 0, reg >> 2)) {	// reg. HIGHBYTES
+		return -1;
+	}
+
+	data = post_office_read(zr, 0, reg & 0x03) & 0xff;	// reg. LOWBYTES + read
+	return data;
+}
+
+static void
+zr36050_write (struct videocodec *codec,
+	       u16                reg,
+	       u32                val)
+{
+	struct zoran *zr = (struct zoran *) codec->master_data->data;
+
+	if (post_office_wait(zr)
+	    || post_office_write(zr, 1, 0, reg >> 2)) {	// reg. HIGHBYTES
+		return;
+	}
+
+	post_office_write(zr, 0, reg & 0x03, val & 0xff);	// reg. LOWBYTES + wr. data
+}
+
+/* videocodec bus functions ZR36016 */
+static u32
+zr36016_read (struct videocodec *codec,
+	      u16                reg)
+{
+	struct zoran *zr = (struct zoran *) codec->master_data->data;
+	__u32 data;
+
+	if (post_office_wait(zr)) {
+		return -1;
+	}
+
+	data = post_office_read(zr, 2, reg & 0x03) & 0xff;	// read
+	return data;
+}
+
+/* hack for in zoran_device.c */
+void
+zr36016_write (struct videocodec *codec,
+	       u16                reg,
+	       u32                val)
+{
+	struct zoran *zr = (struct zoran *) codec->master_data->data;
+
+	if (post_office_wait(zr)) {
+		return;
+	}
+
+	post_office_write(zr, 2, reg & 0x03, val & 0x0ff);	// wr. data
+}
+
+/*
+ * Board specific information
+ */
+
+static void
+dc10_init (struct zoran *zr)
+{
+	dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
+
+	/* Pixel clock selection */
+	GPIO(zr, 4, 0);
+	GPIO(zr, 5, 1);
+	/* Enable the video bus sync signals */
+	GPIO(zr, 7, 0);
+}
+
+static void
+dc10plus_init (struct zoran *zr)
+{
+	dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
+}
+
+static void
+buz_init (struct zoran *zr)
+{
+	dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
+
+	/* some stuff from Iomega */
+	pci_write_config_dword(zr->pci_dev, 0xfc, 0x90680f15);
+	pci_write_config_dword(zr->pci_dev, 0x0c, 0x00012020);
+	pci_write_config_dword(zr->pci_dev, 0xe8, 0xc0200000);
+}
+
+static void
+lml33_init (struct zoran *zr)
+{
+	dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
+
+	GPIO(zr, 2, 1);		// Set Composite input/output
+}
+
+static void
+avs6eyes_init (struct zoran *zr)
+{
+	// AverMedia 6-Eyes original driver by Christer Weinigel
+
+	// Lifted straight from Christer's old driver and
+	// modified slightly by Martin Samuelsson.
+
+	int mux = default_mux; /* 1 = BT866, 7 = VID1 */
+
+	GPIO(zr, 4, 1); /* Bt866 SLEEP on */
+	udelay(2);
+
+	GPIO(zr, 0, 1); /* ZR36060 /RESET on */
+	GPIO(zr, 1, 0); /* ZR36060 /SLEEP on */
+	GPIO(zr, 2, mux & 1);   /* MUX S0 */
+	GPIO(zr, 3, 0); /* /FRAME on */
+	GPIO(zr, 4, 0); /* Bt866 SLEEP off */
+	GPIO(zr, 5, mux & 2);   /* MUX S1 */
+	GPIO(zr, 6, 0); /* ? */
+	GPIO(zr, 7, mux & 4);   /* MUX S2 */
+
+}
+
+static char *
+codecid_to_modulename (u16 codecid)
+{
+	char *name = NULL;
+
+	switch (codecid) {
+	case CODEC_TYPE_ZR36060:
+		name = "zr36060";
+		break;
+	case CODEC_TYPE_ZR36050:
+		name = "zr36050";
+		break;
+	case CODEC_TYPE_ZR36016:
+		name = "zr36016";
+		break;
+	}
+
+	return name;
+}
+
+// struct tvnorm {
+//      u16 Wt, Wa, HStart, HSyncStart, Ht, Ha, VStart;
+// };
+
+static struct tvnorm f50sqpixel = { 944, 768, 83, 880, 625, 576, 16 };
+static struct tvnorm f60sqpixel = { 780, 640, 51, 716, 525, 480, 12 };
+static struct tvnorm f50ccir601 = { 864, 720, 75, 804, 625, 576, 18 };
+static struct tvnorm f60ccir601 = { 858, 720, 57, 788, 525, 480, 16 };
+
+static struct tvnorm f50ccir601_lml33 = { 864, 720, 75+34, 804, 625, 576, 18 };
+static struct tvnorm f60ccir601_lml33 = { 858, 720, 57+34, 788, 525, 480, 16 };
+
+/* The DC10 (57/16/50) uses VActive as HSync, so HStart must be 0 */
+static struct tvnorm f50sqpixel_dc10 = { 944, 768, 0, 880, 625, 576, 0 };
+static struct tvnorm f60sqpixel_dc10 = { 780, 640, 0, 716, 525, 480, 12 };
+
+/* FIXME: I cannot swap U and V in saa7114, so i do one
+ * pixel left shift in zoran (75 -> 74)
+ * (Maxim Yevtyushkin <max@linuxmedialabs.com>) */
+static struct tvnorm f50ccir601_lm33r10 = { 864, 720, 74+54, 804, 625, 576, 18 };
+static struct tvnorm f60ccir601_lm33r10 = { 858, 720, 56+54, 788, 525, 480, 16 };
+
+/* FIXME: The ks0127 seem incapable of swapping U and V, too, which is why I
+ * copy Maxim's left shift hack for the 6 Eyes.
+ *
+ * Christer's driver used the unshifted norms, though...
+ * /Sam  */
+static struct tvnorm f50ccir601_avs6eyes = { 864, 720, 74, 804, 625, 576, 18 };
+static struct tvnorm f60ccir601_avs6eyes = { 858, 720, 56, 788, 525, 480, 16 };
+
+static const unsigned short vpx3220_addrs[] = { 0x43, 0x47, I2C_CLIENT_END };
+static const unsigned short saa7110_addrs[] = { 0x4e, 0x4f, I2C_CLIENT_END };
+static const unsigned short saa7111_addrs[] = { 0x25, 0x24, I2C_CLIENT_END };
+static const unsigned short saa7114_addrs[] = { 0x21, 0x20, I2C_CLIENT_END };
+static const unsigned short adv717x_addrs[] = { 0x6a, 0x6b, 0x2a, 0x2b, I2C_CLIENT_END };
+static const unsigned short ks0127_addrs[] = { 0x6c, 0x6d, I2C_CLIENT_END };
+static const unsigned short saa7185_addrs[] = { 0x44, I2C_CLIENT_END };
+static const unsigned short bt819_addrs[] = { 0x45, I2C_CLIENT_END };
+static const unsigned short bt856_addrs[] = { 0x44, I2C_CLIENT_END };
+static const unsigned short bt866_addrs[] = { 0x44, I2C_CLIENT_END };
+
+static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+	{
+		.type = DC10_old,
+		.name = "DC10(old)",
+		.i2c_decoder = "vpx3220a",
+		.addrs_decoder = vpx3220_addrs,
+		.video_codec = CODEC_TYPE_ZR36050,
+		.video_vfe = CODEC_TYPE_ZR36016,
+
+		.inputs = 3,
+		.input = {
+			{ 1, "Composite" },
+			{ 2, "S-Video" },
+			{ 0, "Internal/comp" }
+		},
+		.norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
+		.tvn = {
+			&f50sqpixel_dc10,
+			&f60sqpixel_dc10,
+			&f50sqpixel_dc10
+		},
+		.jpeg_int = 0,
+		.vsync_int = ZR36057_ISR_GIRQ1,
+		.gpio = { 2, 1, -1, 3, 7, 0, 4, 5 },
+		.gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 },
+		.gpcs = { -1, 0 },
+		.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+		.gws_not_connected = 0,
+		.input_mux = 0,
+		.init = &dc10_init,
+	}, {
+		.type = DC10_new,
+		.name = "DC10(new)",
+		.i2c_decoder = "saa7110",
+		.addrs_decoder = saa7110_addrs,
+		.i2c_encoder = "adv7175",
+		.addrs_encoder = adv717x_addrs,
+		.video_codec = CODEC_TYPE_ZR36060,
+
+		.inputs = 3,
+		.input = {
+				{ 0, "Composite" },
+				{ 7, "S-Video" },
+				{ 5, "Internal/comp" }
+			},
+		.norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
+		.tvn = {
+				&f50sqpixel,
+				&f60sqpixel,
+				&f50sqpixel},
+		.jpeg_int = ZR36057_ISR_GIRQ0,
+		.vsync_int = ZR36057_ISR_GIRQ1,
+		.gpio = { 3, 0, 6, 1, 2, -1, 4, 5 },
+		.gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+		.gpcs = { -1, 1},
+		.vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
+		.gws_not_connected = 0,
+		.input_mux = 0,
+		.init = &dc10plus_init,
+	}, {
+		.type = DC10plus,
+		.name = "DC10plus",
+		.i2c_decoder = "saa7110",
+		.addrs_decoder = saa7110_addrs,
+		.i2c_encoder = "adv7175",
+		.addrs_encoder = adv717x_addrs,
+		.video_codec = CODEC_TYPE_ZR36060,
+
+		.inputs = 3,
+		.input = {
+			{ 0, "Composite" },
+			{ 7, "S-Video" },
+			{ 5, "Internal/comp" }
+		},
+		.norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
+		.tvn = {
+			&f50sqpixel,
+			&f60sqpixel,
+			&f50sqpixel
+		},
+		.jpeg_int = ZR36057_ISR_GIRQ0,
+		.vsync_int = ZR36057_ISR_GIRQ1,
+		.gpio = { 3, 0, 6, 1, 2, -1, 4, 5 },
+		.gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+		.gpcs = { -1, 1 },
+		.vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
+		.gws_not_connected = 0,
+		.input_mux = 0,
+		.init = &dc10plus_init,
+	}, {
+		.type = DC30,
+		.name = "DC30",
+		.i2c_decoder = "vpx3220a",
+		.addrs_decoder = vpx3220_addrs,
+		.i2c_encoder = "adv7175",
+		.addrs_encoder = adv717x_addrs,
+		.video_codec = CODEC_TYPE_ZR36050,
+		.video_vfe = CODEC_TYPE_ZR36016,
+
+		.inputs = 3,
+		.input = {
+			{ 1, "Composite" },
+			{ 2, "S-Video" },
+			{ 0, "Internal/comp" }
+		},
+		.norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
+		.tvn = {
+			&f50sqpixel_dc10,
+			&f60sqpixel_dc10,
+			&f50sqpixel_dc10
+		},
+		.jpeg_int = 0,
+		.vsync_int = ZR36057_ISR_GIRQ1,
+		.gpio = { 2, 1, -1, 3, 7, 0, 4, 5 },
+		.gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 },
+		.gpcs = { -1, 0 },
+		.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+		.gws_not_connected = 0,
+		.input_mux = 0,
+		.init = &dc10_init,
+	}, {
+		.type = DC30plus,
+		.name = "DC30plus",
+		.i2c_decoder = "vpx3220a",
+		.addrs_decoder = vpx3220_addrs,
+		.i2c_encoder = "adv7175",
+		.addrs_encoder = adv717x_addrs,
+		.video_codec = CODEC_TYPE_ZR36050,
+		.video_vfe = CODEC_TYPE_ZR36016,
+
+		.inputs = 3,
+		.input = {
+			{ 1, "Composite" },
+			{ 2, "S-Video" },
+			{ 0, "Internal/comp" }
+		},
+		.norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
+		.tvn = {
+			&f50sqpixel_dc10,
+			&f60sqpixel_dc10,
+			&f50sqpixel_dc10
+		},
+		.jpeg_int = 0,
+		.vsync_int = ZR36057_ISR_GIRQ1,
+		.gpio = { 2, 1, -1, 3, 7, 0, 4, 5 },
+		.gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 },
+		.gpcs = { -1, 0 },
+		.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+		.gws_not_connected = 0,
+		.input_mux = 0,
+		.init = &dc10_init,
+	}, {
+		.type = LML33,
+		.name = "LML33",
+		.i2c_decoder = "bt819a",
+		.addrs_decoder = bt819_addrs,
+		.i2c_encoder = "bt856",
+		.addrs_encoder = bt856_addrs,
+		.video_codec = CODEC_TYPE_ZR36060,
+
+		.inputs = 2,
+		.input = {
+			{ 0, "Composite" },
+			{ 7, "S-Video" }
+		},
+		.norms = V4L2_STD_NTSC|V4L2_STD_PAL,
+		.tvn = {
+			&f50ccir601_lml33,
+			&f60ccir601_lml33,
+			NULL
+		},
+		.jpeg_int = ZR36057_ISR_GIRQ1,
+		.vsync_int = ZR36057_ISR_GIRQ0,
+		.gpio = { 1, -1, 3, 5, 7, -1, -1, -1 },
+		.gpio_pol = { 0, 0, 0, 0, 1, 0, 0, 0 },
+		.gpcs = { 3, 1 },
+		.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
+		.gws_not_connected = 1,
+		.input_mux = 0,
+		.init = &lml33_init,
+	}, {
+		.type = LML33R10,
+		.name = "LML33R10",
+		.i2c_decoder = "saa7114",
+		.addrs_decoder = saa7114_addrs,
+		.i2c_encoder = "adv7170",
+		.addrs_encoder = adv717x_addrs,
+		.video_codec = CODEC_TYPE_ZR36060,
+
+		.inputs = 2,
+		.input = {
+			{ 0, "Composite" },
+			{ 7, "S-Video" }
+		},
+		.norms = V4L2_STD_NTSC|V4L2_STD_PAL,
+		.tvn = {
+			&f50ccir601_lm33r10,
+			&f60ccir601_lm33r10,
+			NULL
+		},
+		.jpeg_int = ZR36057_ISR_GIRQ1,
+		.vsync_int = ZR36057_ISR_GIRQ0,
+		.gpio = { 1, -1, 3, 5, 7, -1, -1, -1 },
+		.gpio_pol = { 0, 0, 0, 0, 1, 0, 0, 0 },
+		.gpcs = { 3, 1 },
+		.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
+		.gws_not_connected = 1,
+		.input_mux = 0,
+		.init = &lml33_init,
+	}, {
+		.type = BUZ,
+		.name = "Buz",
+		.i2c_decoder = "saa7111",
+		.addrs_decoder = saa7111_addrs,
+		.i2c_encoder = "saa7185",
+		.addrs_encoder = saa7185_addrs,
+		.video_codec = CODEC_TYPE_ZR36060,
+
+		.inputs = 2,
+		.input = {
+			{ 3, "Composite" },
+			{ 7, "S-Video" }
+		},
+		.norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
+		.tvn = {
+			&f50ccir601,
+			&f60ccir601,
+			&f50ccir601
+		},
+		.jpeg_int = ZR36057_ISR_GIRQ1,
+		.vsync_int = ZR36057_ISR_GIRQ0,
+		.gpio = { 1, -1, 3, -1, -1, -1, -1, -1 },
+		.gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
+		.gpcs = { 3, 1 },
+		.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
+		.gws_not_connected = 1,
+		.input_mux = 0,
+		.init = &buz_init,
+	}, {
+		.type = AVS6EYES,
+		.name = "6-Eyes",
+		/* AverMedia chose not to brand the 6-Eyes. Thus it
+		   can't be autodetected, and requires card=x. */
+		.i2c_decoder = "ks0127",
+		.addrs_decoder = ks0127_addrs,
+		.i2c_encoder = "bt866",
+		.addrs_encoder = bt866_addrs,
+		.video_codec = CODEC_TYPE_ZR36060,
+
+		.inputs = 10,
+		.input = {
+			{ 0, "Composite 1" },
+			{ 1, "Composite 2" },
+			{ 2, "Composite 3" },
+			{ 4, "Composite 4" },
+			{ 5, "Composite 5" },
+			{ 6, "Composite 6" },
+			{ 8, "S-Video 1" },
+			{ 9, "S-Video 2" },
+			{10, "S-Video 3" },
+			{15, "YCbCr" }
+		},
+		.norms = V4L2_STD_NTSC|V4L2_STD_PAL,
+		.tvn = {
+			&f50ccir601_avs6eyes,
+			&f60ccir601_avs6eyes,
+			NULL
+		},
+		.jpeg_int = ZR36057_ISR_GIRQ1,
+		.vsync_int = ZR36057_ISR_GIRQ0,
+		.gpio = { 1, 0, 3, -1, -1, -1, -1, -1 },// Validity unknown /Sam
+		.gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, // Validity unknown /Sam
+		.gpcs = { 3, 1 },			// Validity unknown /Sam
+		.vfe_pol = { 1, 0, 0, 0, 0, 1, 0, 0 },  // Validity unknown /Sam
+		.gws_not_connected = 1,
+		.input_mux = 1,
+		.init = &avs6eyes_init,
+	}
+
+};
+
+/*
+ * I2C functions
+ */
+/* software I2C functions */
+static int
+zoran_i2c_getsda (void *data)
+{
+	struct zoran *zr = (struct zoran *) data;
+
+	return (btread(ZR36057_I2CBR) >> 1) & 1;
+}
+
+static int
+zoran_i2c_getscl (void *data)
+{
+	struct zoran *zr = (struct zoran *) data;
+
+	return btread(ZR36057_I2CBR) & 1;
+}
+
+static void
+zoran_i2c_setsda (void *data,
+		  int   state)
+{
+	struct zoran *zr = (struct zoran *) data;
+
+	if (state)
+		zr->i2cbr |= 2;
+	else
+		zr->i2cbr &= ~2;
+	btwrite(zr->i2cbr, ZR36057_I2CBR);
+}
+
+static void
+zoran_i2c_setscl (void *data,
+		  int   state)
+{
+	struct zoran *zr = (struct zoran *) data;
+
+	if (state)
+		zr->i2cbr |= 1;
+	else
+		zr->i2cbr &= ~1;
+	btwrite(zr->i2cbr, ZR36057_I2CBR);
+}
+
+static const struct i2c_algo_bit_data zoran_i2c_bit_data_template = {
+	.setsda = zoran_i2c_setsda,
+	.setscl = zoran_i2c_setscl,
+	.getsda = zoran_i2c_getsda,
+	.getscl = zoran_i2c_getscl,
+	.udelay = 10,
+	.timeout = 100,
+};
+
+static int
+zoran_register_i2c (struct zoran *zr)
+{
+	memcpy(&zr->i2c_algo, &zoran_i2c_bit_data_template,
+	       sizeof(struct i2c_algo_bit_data));
+	zr->i2c_algo.data = zr;
+	strlcpy(zr->i2c_adapter.name, ZR_DEVNAME(zr),
+		sizeof(zr->i2c_adapter.name));
+	i2c_set_adapdata(&zr->i2c_adapter, &zr->v4l2_dev);
+	zr->i2c_adapter.algo_data = &zr->i2c_algo;
+	zr->i2c_adapter.dev.parent = &zr->pci_dev->dev;
+	return i2c_bit_add_bus(&zr->i2c_adapter);
+}
+
+static void
+zoran_unregister_i2c (struct zoran *zr)
+{
+	i2c_del_adapter(&zr->i2c_adapter);
+}
+
+/* Check a zoran_params struct for correctness, insert default params */
+
+int
+zoran_check_jpg_settings (struct zoran              *zr,
+			  struct zoran_jpg_settings *settings,
+			  int try)
+{
+	int err = 0, err0 = 0;
+
+	dprintk(4,
+		KERN_DEBUG
+		"%s: %s - dec: %d, Hdcm: %d, Vdcm: %d, Tdcm: %d\n",
+		ZR_DEVNAME(zr), __func__, settings->decimation, settings->HorDcm,
+		settings->VerDcm, settings->TmpDcm);
+	dprintk(4,
+		KERN_DEBUG
+		"%s: %s - x: %d, y: %d, w: %d, y: %d\n",
+		ZR_DEVNAME(zr), __func__, settings->img_x, settings->img_y,
+		settings->img_width, settings->img_height);
+	/* Check decimation, set default values for decimation = 1, 2, 4 */
+	switch (settings->decimation) {
+	case 1:
+
+		settings->HorDcm = 1;
+		settings->VerDcm = 1;
+		settings->TmpDcm = 1;
+		settings->field_per_buff = 2;
+		settings->img_x = 0;
+		settings->img_y = 0;
+		settings->img_width = BUZ_MAX_WIDTH;
+		settings->img_height = BUZ_MAX_HEIGHT / 2;
+		break;
+	case 2:
+
+		settings->HorDcm = 2;
+		settings->VerDcm = 1;
+		settings->TmpDcm = 2;
+		settings->field_per_buff = 1;
+		settings->img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0;
+		settings->img_y = 0;
+		settings->img_width =
+		    (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH;
+		settings->img_height = BUZ_MAX_HEIGHT / 2;
+		break;
+	case 4:
+
+		if (zr->card.type == DC10_new) {
+			dprintk(1,
+				KERN_DEBUG
+				"%s: %s - HDec by 4 is not supported on the DC10\n",
+				ZR_DEVNAME(zr), __func__);
+			err0++;
+			break;
+		}
+
+		settings->HorDcm = 4;
+		settings->VerDcm = 2;
+		settings->TmpDcm = 2;
+		settings->field_per_buff = 1;
+		settings->img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0;
+		settings->img_y = 0;
+		settings->img_width =
+		    (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH;
+		settings->img_height = BUZ_MAX_HEIGHT / 2;
+		break;
+	case 0:
+
+		/* We have to check the data the user has set */
+
+		if (settings->HorDcm != 1 && settings->HorDcm != 2 &&
+		    (zr->card.type == DC10_new || settings->HorDcm != 4)) {
+			settings->HorDcm = clamp(settings->HorDcm, 1, 2);
+			err0++;
+		}
+		if (settings->VerDcm != 1 && settings->VerDcm != 2) {
+			settings->VerDcm = clamp(settings->VerDcm, 1, 2);
+			err0++;
+		}
+		if (settings->TmpDcm != 1 && settings->TmpDcm != 2) {
+			settings->TmpDcm = clamp(settings->TmpDcm, 1, 2);
+			err0++;
+		}
+		if (settings->field_per_buff != 1 &&
+		    settings->field_per_buff != 2) {
+			settings->field_per_buff = clamp(settings->field_per_buff, 1, 2);
+			err0++;
+		}
+		if (settings->img_x < 0) {
+			settings->img_x = 0;
+			err0++;
+		}
+		if (settings->img_y < 0) {
+			settings->img_y = 0;
+			err0++;
+		}
+		if (settings->img_width < 0 || settings->img_width > BUZ_MAX_WIDTH) {
+			settings->img_width = clamp(settings->img_width, 0, (int)BUZ_MAX_WIDTH);
+			err0++;
+		}
+		if (settings->img_height < 0 || settings->img_height > BUZ_MAX_HEIGHT / 2) {
+			settings->img_height = clamp(settings->img_height, 0, BUZ_MAX_HEIGHT / 2);
+			err0++;
+		}
+		if (settings->img_x + settings->img_width > BUZ_MAX_WIDTH) {
+			settings->img_x = BUZ_MAX_WIDTH - settings->img_width;
+			err0++;
+		}
+		if (settings->img_y + settings->img_height > BUZ_MAX_HEIGHT / 2) {
+			settings->img_y = BUZ_MAX_HEIGHT / 2 - settings->img_height;
+			err0++;
+		}
+		if (settings->img_width % (16 * settings->HorDcm) != 0) {
+			settings->img_width -= settings->img_width % (16 * settings->HorDcm);
+			if (settings->img_width == 0)
+				settings->img_width = 16 * settings->HorDcm;
+			err0++;
+		}
+		if (settings->img_height % (8 * settings->VerDcm) != 0) {
+			settings->img_height -= settings->img_height % (8 * settings->VerDcm);
+			if (settings->img_height == 0)
+				settings->img_height = 8 * settings->VerDcm;
+			err0++;
+		}
+
+		if (!try && err0) {
+			dprintk(1,
+				KERN_ERR
+				"%s: %s - error in params for decimation = 0\n",
+				ZR_DEVNAME(zr), __func__);
+			err++;
+		}
+		break;
+	default:
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - decimation = %d, must be 0, 1, 2 or 4\n",
+			ZR_DEVNAME(zr), __func__, settings->decimation);
+		err++;
+		break;
+	}
+
+	if (settings->jpg_comp.quality > 100)
+		settings->jpg_comp.quality = 100;
+	if (settings->jpg_comp.quality < 5)
+		settings->jpg_comp.quality = 5;
+	if (settings->jpg_comp.APPn < 0)
+		settings->jpg_comp.APPn = 0;
+	if (settings->jpg_comp.APPn > 15)
+		settings->jpg_comp.APPn = 15;
+	if (settings->jpg_comp.APP_len < 0)
+		settings->jpg_comp.APP_len = 0;
+	if (settings->jpg_comp.APP_len > 60)
+		settings->jpg_comp.APP_len = 60;
+	if (settings->jpg_comp.COM_len < 0)
+		settings->jpg_comp.COM_len = 0;
+	if (settings->jpg_comp.COM_len > 60)
+		settings->jpg_comp.COM_len = 60;
+	if (err)
+		return -EINVAL;
+	return 0;
+}
+
+void
+zoran_open_init_params (struct zoran *zr)
+{
+	int i;
+
+	/* User must explicitly set a window */
+	zr->overlay_settings.is_set = 0;
+	zr->overlay_mask = NULL;
+	zr->overlay_active = ZORAN_FREE;
+
+	zr->v4l_memgrab_active = 0;
+	zr->v4l_overlay_active = 0;
+	zr->v4l_grab_frame = NO_GRAB_ACTIVE;
+	zr->v4l_grab_seq = 0;
+	zr->v4l_settings.width = 192;
+	zr->v4l_settings.height = 144;
+	zr->v4l_settings.format = &zoran_formats[7];	/* YUY2 - YUV-4:2:2 packed */
+	zr->v4l_settings.bytesperline =
+	    zr->v4l_settings.width *
+	    ((zr->v4l_settings.format->depth + 7) / 8);
+
+	/* DMA ring stuff for V4L */
+	zr->v4l_pend_tail = 0;
+	zr->v4l_pend_head = 0;
+	zr->v4l_sync_tail = 0;
+	zr->v4l_buffers.active = ZORAN_FREE;
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		zr->v4l_buffers.buffer[i].state = BUZ_STATE_USER;	/* nothing going on */
+	}
+	zr->v4l_buffers.allocated = 0;
+
+	for (i = 0; i < BUZ_MAX_FRAME; i++) {
+		zr->jpg_buffers.buffer[i].state = BUZ_STATE_USER;	/* nothing going on */
+	}
+	zr->jpg_buffers.active = ZORAN_FREE;
+	zr->jpg_buffers.allocated = 0;
+	/* Set necessary params and call zoran_check_jpg_settings to set the defaults */
+	zr->jpg_settings.decimation = 1;
+	zr->jpg_settings.jpg_comp.quality = 50;	/* default compression factor 8 */
+	if (zr->card.type != BUZ)
+		zr->jpg_settings.odd_even = 1;
+	else
+		zr->jpg_settings.odd_even = 0;
+	zr->jpg_settings.jpg_comp.APPn = 0;
+	zr->jpg_settings.jpg_comp.APP_len = 0;	/* No APPn marker */
+	memset(zr->jpg_settings.jpg_comp.APP_data, 0,
+	       sizeof(zr->jpg_settings.jpg_comp.APP_data));
+	zr->jpg_settings.jpg_comp.COM_len = 0;	/* No COM marker */
+	memset(zr->jpg_settings.jpg_comp.COM_data, 0,
+	       sizeof(zr->jpg_settings.jpg_comp.COM_data));
+	zr->jpg_settings.jpg_comp.jpeg_markers =
+	    V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT;
+	i = zoran_check_jpg_settings(zr, &zr->jpg_settings, 0);
+	if (i)
+		dprintk(1, KERN_ERR "%s: %s internal error\n",
+			ZR_DEVNAME(zr), __func__);
+
+	clear_interrupt_counters(zr);
+	zr->testing = 0;
+}
+
+static void __devinit
+test_interrupts (struct zoran *zr)
+{
+	DEFINE_WAIT(wait);
+	int timeout, icr;
+
+	clear_interrupt_counters(zr);
+
+	zr->testing = 1;
+	icr = btread(ZR36057_ICR);
+	btwrite(0x78000000 | ZR36057_ICR_IntPinEn, ZR36057_ICR);
+	prepare_to_wait(&zr->test_q, &wait, TASK_INTERRUPTIBLE);
+	timeout = schedule_timeout(HZ);
+	finish_wait(&zr->test_q, &wait);
+	btwrite(0, ZR36057_ICR);
+	btwrite(0x78000000, ZR36057_ISR);
+	zr->testing = 0;
+	dprintk(5, KERN_INFO "%s: Testing interrupts...\n", ZR_DEVNAME(zr));
+	if (timeout) {
+		dprintk(1, ": time spent: %d\n", 1 * HZ - timeout);
+	}
+	if (zr36067_debug > 1)
+		print_interrupts(zr);
+	btwrite(icr, ZR36057_ICR);
+}
+
+static int __devinit
+zr36057_init (struct zoran *zr)
+{
+	int j, err;
+
+	dprintk(1,
+		KERN_INFO
+		"%s: %s - initializing card[%d], zr=%p\n",
+		ZR_DEVNAME(zr), __func__, zr->id, zr);
+
+	/* default setup of all parameters which will persist between opens */
+	zr->user = 0;
+
+	init_waitqueue_head(&zr->v4l_capq);
+	init_waitqueue_head(&zr->jpg_capq);
+	init_waitqueue_head(&zr->test_q);
+	zr->jpg_buffers.allocated = 0;
+	zr->v4l_buffers.allocated = 0;
+
+	zr->vbuf_base = (void *) vidmem;
+	zr->vbuf_width = 0;
+	zr->vbuf_height = 0;
+	zr->vbuf_depth = 0;
+	zr->vbuf_bytesperline = 0;
+
+	/* Avoid nonsense settings from user for default input/norm */
+	if (default_norm < 0 || default_norm > 2)
+		default_norm = 0;
+	if (default_norm == 0) {
+		zr->norm = V4L2_STD_PAL;
+		zr->timing = zr->card.tvn[0];
+	} else if (default_norm == 1) {
+		zr->norm = V4L2_STD_NTSC;
+		zr->timing = zr->card.tvn[1];
+	} else {
+		zr->norm = V4L2_STD_SECAM;
+		zr->timing = zr->card.tvn[2];
+	}
+	if (zr->timing == NULL) {
+		dprintk(1,
+			KERN_WARNING
+			"%s: %s - default TV standard not supported by hardware. PAL will be used.\n",
+			ZR_DEVNAME(zr), __func__);
+		zr->norm = V4L2_STD_PAL;
+		zr->timing = zr->card.tvn[0];
+	}
+
+	if (default_input > zr->card.inputs-1) {
+		dprintk(1,
+			KERN_WARNING
+			"%s: default_input value %d out of range (0-%d)\n",
+			ZR_DEVNAME(zr), default_input, zr->card.inputs-1);
+		default_input = 0;
+	}
+	zr->input = default_input;
+
+	/* default setup (will be repeated at every open) */
+	zoran_open_init_params(zr);
+
+	/* allocate memory *before* doing anything to the hardware
+	 * in case allocation fails */
+	zr->stat_com = kzalloc(BUZ_NUM_STAT_COM * 4, GFP_KERNEL);
+	zr->video_dev = video_device_alloc();
+	if (!zr->stat_com || !zr->video_dev) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - kmalloc (STAT_COM) failed\n",
+			ZR_DEVNAME(zr), __func__);
+		err = -ENOMEM;
+		goto exit_free;
+	}
+	for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
+		zr->stat_com[j] = cpu_to_le32(1); /* mark as unavailable to zr36057 */
+	}
+
+	/*
+	 *   Now add the template and register the device unit.
+	 */
+	memcpy(zr->video_dev, &zoran_template, sizeof(zoran_template));
+	zr->video_dev->parent = &zr->pci_dev->dev;
+	strcpy(zr->video_dev->name, ZR_DEVNAME(zr));
+	err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr[zr->id]);
+	if (err < 0)
+		goto exit_free;
+	video_set_drvdata(zr->video_dev, zr);
+
+	zoran_init_hardware(zr);
+	if (zr36067_debug > 2)
+		detect_guest_activity(zr);
+	test_interrupts(zr);
+	if (!pass_through) {
+		decoder_call(zr, video, s_stream, 0);
+		encoder_call(zr, video, s_routing, 2, 0, 0);
+	}
+
+	zr->zoran_proc = NULL;
+	zr->initialized = 1;
+	return 0;
+
+exit_free:
+	kfree(zr->stat_com);
+	kfree(zr->video_dev);
+	return err;
+}
+
+static void __devexit zoran_remove(struct pci_dev *pdev)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+	struct zoran *zr = to_zoran(v4l2_dev);
+
+	if (!zr->initialized)
+		goto exit_free;
+
+	/* unregister videocodec bus */
+	if (zr->codec) {
+		struct videocodec_master *master = zr->codec->master_data;
+
+		videocodec_detach(zr->codec);
+		kfree(master);
+	}
+	if (zr->vfe) {
+		struct videocodec_master *master = zr->vfe->master_data;
+
+		videocodec_detach(zr->vfe);
+		kfree(master);
+	}
+
+	/* unregister i2c bus */
+	zoran_unregister_i2c(zr);
+	/* disable PCI bus-mastering */
+	zoran_set_pci_master(zr, 0);
+	/* put chip into reset */
+	btwrite(0, ZR36057_SPGPPCR);
+	free_irq(zr->pci_dev->irq, zr);
+	/* unmap and free memory */
+	kfree(zr->stat_com);
+	zoran_proc_cleanup(zr);
+	iounmap(zr->zr36057_mem);
+	pci_disable_device(zr->pci_dev);
+	video_unregister_device(zr->video_dev);
+exit_free:
+	v4l2_device_unregister(&zr->v4l2_dev);
+	kfree(zr);
+}
+
+void
+zoran_vdev_release (struct video_device *vdev)
+{
+	kfree(vdev);
+}
+
+static struct videocodec_master * __devinit
+zoran_setup_videocodec (struct zoran *zr,
+			int           type)
+{
+	struct videocodec_master *m = NULL;
+
+	m = kmalloc(sizeof(struct videocodec_master), GFP_KERNEL);
+	if (!m) {
+		dprintk(1, KERN_ERR "%s: %s - no memory\n",
+			ZR_DEVNAME(zr), __func__);
+		return m;
+	}
+
+	/* magic and type are unused for master struct. Makes sense only at
+	   codec structs.
+	   In the past, .type were initialized to the old V4L1 .hardware
+	   value, as VID_HARDWARE_ZR36067
+	 */
+	m->magic = 0L;
+	m->type = 0;
+
+	m->flags = CODEC_FLAG_ENCODER | CODEC_FLAG_DECODER;
+	strlcpy(m->name, ZR_DEVNAME(zr), sizeof(m->name));
+	m->data = zr;
+
+	switch (type)
+	{
+	case CODEC_TYPE_ZR36060:
+		m->readreg = zr36060_read;
+		m->writereg = zr36060_write;
+		m->flags |= CODEC_FLAG_JPEG | CODEC_FLAG_VFE;
+		break;
+	case CODEC_TYPE_ZR36050:
+		m->readreg = zr36050_read;
+		m->writereg = zr36050_write;
+		m->flags |= CODEC_FLAG_JPEG;
+		break;
+	case CODEC_TYPE_ZR36016:
+		m->readreg = zr36016_read;
+		m->writereg = zr36016_write;
+		m->flags |= CODEC_FLAG_VFE;
+		break;
+	}
+
+	return m;
+}
+
+static void zoran_subdev_notify(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+	struct zoran *zr = to_zoran(sd->v4l2_dev);
+
+	/* Bt819 needs to reset its FIFO buffer using #FRST pin and
+	   LML33 card uses GPIO(7) for that. */
+	if (cmd == BT819_FIFO_RESET_LOW)
+		GPIO(zr, 7, 0);
+	else if (cmd == BT819_FIFO_RESET_HIGH)
+		GPIO(zr, 7, 1);
+}
+
+/*
+ *   Scan for a Buz card (actually for the PCI controller ZR36057),
+ *   request the irq and map the io memory
+ */
+static int __devinit zoran_probe(struct pci_dev *pdev,
+				 const struct pci_device_id *ent)
+{
+	unsigned char latency, need_latency;
+	struct zoran *zr;
+	int result;
+	struct videocodec_master *master_vfe = NULL;
+	struct videocodec_master *master_codec = NULL;
+	int card_num;
+	char *codec_name, *vfe_name;
+	unsigned int nr;
+
+
+	nr = zoran_num++;
+	if (nr >= BUZ_MAX) {
+		dprintk(1, KERN_ERR "%s: driver limited to %d card(s) maximum\n",
+			ZORAN_NAME, BUZ_MAX);
+		return -ENOENT;
+	}
+
+	zr = kzalloc(sizeof(struct zoran), GFP_KERNEL);
+	if (!zr) {
+		dprintk(1, KERN_ERR "%s: %s - kzalloc failed\n",
+			ZORAN_NAME, __func__);
+		return -ENOMEM;
+	}
+	zr->v4l2_dev.notify = zoran_subdev_notify;
+	if (v4l2_device_register(&pdev->dev, &zr->v4l2_dev))
+		goto zr_free_mem;
+	zr->pci_dev = pdev;
+	zr->id = nr;
+	snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%u]", zr->id);
+	spin_lock_init(&zr->spinlock);
+	mutex_init(&zr->resource_lock);
+	mutex_init(&zr->other_lock);
+	if (pci_enable_device(pdev))
+		goto zr_unreg;
+	zr->revision = zr->pci_dev->revision;
+
+	dprintk(1,
+		KERN_INFO
+		"%s: Zoran ZR360%c7 (rev %d), irq: %d, memory: 0x%08llx\n",
+		ZR_DEVNAME(zr), zr->revision < 2 ? '5' : '6', zr->revision,
+		zr->pci_dev->irq, (uint64_t)pci_resource_start(zr->pci_dev, 0));
+	if (zr->revision >= 2) {
+		dprintk(1,
+			KERN_INFO
+			"%s: Subsystem vendor=0x%04x id=0x%04x\n",
+			ZR_DEVNAME(zr), zr->pci_dev->subsystem_vendor,
+			zr->pci_dev->subsystem_device);
+	}
+
+	/* Use auto-detected card type? */
+	if (card[nr] == -1) {
+		if (zr->revision < 2) {
+			dprintk(1,
+				KERN_ERR
+				"%s: No card type specified, please use the card=X module parameter\n",
+				ZR_DEVNAME(zr));
+			dprintk(1,
+				KERN_ERR
+				"%s: It is not possible to auto-detect ZR36057 based cards\n",
+				ZR_DEVNAME(zr));
+			goto zr_unreg;
+		}
+
+		card_num = ent->driver_data;
+		if (card_num >= NUM_CARDS) {
+			dprintk(1,
+				KERN_ERR
+				"%s: Unknown card, try specifying card=X module parameter\n",
+				ZR_DEVNAME(zr));
+			goto zr_unreg;
+		}
+		dprintk(3,
+			KERN_DEBUG
+			"%s: %s() - card %s detected\n",
+			ZR_DEVNAME(zr), __func__, zoran_cards[card_num].name);
+	} else {
+		card_num = card[nr];
+		if (card_num >= NUM_CARDS || card_num < 0) {
+			dprintk(1,
+				KERN_ERR
+				"%s: User specified card type %d out of range (0 .. %d)\n",
+				ZR_DEVNAME(zr), card_num, NUM_CARDS - 1);
+			goto zr_unreg;
+		}
+	}
+
+	/* even though we make this a non pointer and thus
+	 * theoretically allow for making changes to this struct
+	 * on a per-individual card basis at runtime, this is
+	 * strongly discouraged. This structure is intended to
+	 * keep general card information, no settings or anything */
+	zr->card = zoran_cards[card_num];
+	snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)),
+		 "%s[%u]", zr->card.name, zr->id);
+
+	zr->zr36057_mem = pci_ioremap_bar(zr->pci_dev, 0);
+	if (!zr->zr36057_mem) {
+		dprintk(1, KERN_ERR "%s: %s() - ioremap failed\n",
+			ZR_DEVNAME(zr), __func__);
+		goto zr_unreg;
+	}
+
+	result = request_irq(zr->pci_dev->irq, zoran_irq,
+			     IRQF_SHARED | IRQF_DISABLED, ZR_DEVNAME(zr), zr);
+	if (result < 0) {
+		if (result == -EINVAL) {
+			dprintk(1,
+				KERN_ERR
+				"%s: %s - bad irq number or handler\n",
+				ZR_DEVNAME(zr), __func__);
+		} else if (result == -EBUSY) {
+			dprintk(1,
+				KERN_ERR
+				"%s: %s - IRQ %d busy, change your PnP config in BIOS\n",
+				ZR_DEVNAME(zr), __func__, zr->pci_dev->irq);
+		} else {
+			dprintk(1,
+				KERN_ERR
+				"%s: %s - can't assign irq, error code %d\n",
+				ZR_DEVNAME(zr), __func__, result);
+		}
+		goto zr_unmap;
+	}
+
+	/* set PCI latency timer */
+	pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER,
+			     &latency);
+	need_latency = zr->revision > 1 ? 32 : 48;
+	if (latency != need_latency) {
+		dprintk(2, KERN_INFO "%s: Changing PCI latency from %d to %d\n",
+			ZR_DEVNAME(zr), latency, need_latency);
+		pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER,
+				      need_latency);
+	}
+
+	zr36057_restart(zr);
+	/* i2c */
+	dprintk(2, KERN_INFO "%s: Initializing i2c bus...\n",
+		ZR_DEVNAME(zr));
+
+	if (zoran_register_i2c(zr) < 0) {
+		dprintk(1, KERN_ERR "%s: %s - can't initialize i2c bus\n",
+			ZR_DEVNAME(zr), __func__);
+		goto zr_free_irq;
+	}
+
+	zr->decoder = v4l2_i2c_new_subdev(&zr->v4l2_dev,
+		&zr->i2c_adapter, zr->card.i2c_decoder,
+		0, zr->card.addrs_decoder);
+
+	if (zr->card.i2c_encoder)
+		zr->encoder = v4l2_i2c_new_subdev(&zr->v4l2_dev,
+			&zr->i2c_adapter, zr->card.i2c_encoder,
+			0, zr->card.addrs_encoder);
+
+	dprintk(2,
+		KERN_INFO "%s: Initializing videocodec bus...\n",
+		ZR_DEVNAME(zr));
+
+	if (zr->card.video_codec) {
+		codec_name = codecid_to_modulename(zr->card.video_codec);
+		if (codec_name) {
+			result = request_module(codec_name);
+			if (result) {
+				dprintk(1,
+					KERN_ERR
+					"%s: failed to load modules %s: %d\n",
+					ZR_DEVNAME(zr), codec_name, result);
+			}
+		}
+	}
+	if (zr->card.video_vfe) {
+		vfe_name = codecid_to_modulename(zr->card.video_vfe);
+		if (vfe_name) {
+			result = request_module(vfe_name);
+			if (result < 0) {
+				dprintk(1,
+					KERN_ERR
+					"%s: failed to load modules %s: %d\n",
+					ZR_DEVNAME(zr), vfe_name, result);
+			}
+		}
+	}
+
+	/* reset JPEG codec */
+	jpeg_codec_sleep(zr, 1);
+	jpeg_codec_reset(zr);
+	/* video bus enabled */
+	/* display codec revision */
+	if (zr->card.video_codec != 0) {
+		master_codec = zoran_setup_videocodec(zr, zr->card.video_codec);
+		if (!master_codec)
+			goto zr_unreg_i2c;
+		zr->codec = videocodec_attach(master_codec);
+		if (!zr->codec) {
+			dprintk(1, KERN_ERR "%s: %s - no codec found\n",
+				ZR_DEVNAME(zr), __func__);
+			goto zr_free_codec;
+		}
+		if (zr->codec->type != zr->card.video_codec) {
+			dprintk(1, KERN_ERR "%s: %s - wrong codec\n",
+				ZR_DEVNAME(zr), __func__);
+			goto zr_detach_codec;
+		}
+	}
+	if (zr->card.video_vfe != 0) {
+		master_vfe = zoran_setup_videocodec(zr, zr->card.video_vfe);
+		if (!master_vfe)
+			goto zr_detach_codec;
+		zr->vfe = videocodec_attach(master_vfe);
+		if (!zr->vfe) {
+			dprintk(1, KERN_ERR "%s: %s - no VFE found\n",
+				ZR_DEVNAME(zr), __func__);
+			goto zr_free_vfe;
+		}
+		if (zr->vfe->type != zr->card.video_vfe) {
+			dprintk(1, KERN_ERR "%s: %s = wrong VFE\n",
+				ZR_DEVNAME(zr), __func__);
+			goto zr_detach_vfe;
+		}
+	}
+
+	/* take care of Natoma chipset and a revision 1 zr36057 */
+	if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) {
+		zr->jpg_buffers.need_contiguous = 1;
+		dprintk(1, KERN_INFO
+			"%s: ZR36057/Natoma bug, max. buffer size is 128K\n",
+			ZR_DEVNAME(zr));
+	}
+
+	if (zr36057_init(zr) < 0)
+		goto zr_detach_vfe;
+
+	zoran_proc_init(zr);
+
+	return 0;
+
+zr_detach_vfe:
+	videocodec_detach(zr->vfe);
+zr_free_vfe:
+	kfree(master_vfe);
+zr_detach_codec:
+	videocodec_detach(zr->codec);
+zr_free_codec:
+	kfree(master_codec);
+zr_unreg_i2c:
+	zoran_unregister_i2c(zr);
+zr_free_irq:
+	btwrite(0, ZR36057_SPGPPCR);
+	free_irq(zr->pci_dev->irq, zr);
+zr_unmap:
+	iounmap(zr->zr36057_mem);
+zr_unreg:
+	v4l2_device_unregister(&zr->v4l2_dev);
+zr_free_mem:
+	kfree(zr);
+
+	return -ENODEV;
+}
+
+static struct pci_driver zoran_driver = {
+	.name = "zr36067",
+	.id_table = zr36067_pci_tbl,
+	.probe = zoran_probe,
+	.remove = __devexit_p(zoran_remove),
+};
+
+static int __init zoran_init(void)
+{
+	int res;
+
+	printk(KERN_INFO "Zoran MJPEG board driver version %s\n",
+	       ZORAN_VERSION);
+
+	/* check the parameters we have been given, adjust if necessary */
+	if (v4l_nbufs < 2)
+		v4l_nbufs = 2;
+	if (v4l_nbufs > VIDEO_MAX_FRAME)
+		v4l_nbufs = VIDEO_MAX_FRAME;
+	/* The user specfies the in KB, we want them in byte
+	 * (and page aligned) */
+	v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024);
+	if (v4l_bufsize < 32768)
+		v4l_bufsize = 32768;
+	/* 2 MB is arbitrary but sufficient for the maximum possible images */
+	if (v4l_bufsize > 2048 * 1024)
+		v4l_bufsize = 2048 * 1024;
+	if (jpg_nbufs < 4)
+		jpg_nbufs = 4;
+	if (jpg_nbufs > BUZ_MAX_FRAME)
+		jpg_nbufs = BUZ_MAX_FRAME;
+	jpg_bufsize = PAGE_ALIGN(jpg_bufsize * 1024);
+	if (jpg_bufsize < 8192)
+		jpg_bufsize = 8192;
+	if (jpg_bufsize > (512 * 1024))
+		jpg_bufsize = 512 * 1024;
+	/* Use parameter for vidmem or try to find a video card */
+	if (vidmem) {
+		dprintk(1,
+			KERN_INFO
+			"%s: Using supplied video memory base address @ 0x%lx\n",
+			ZORAN_NAME, vidmem);
+	}
+
+	/* some mainboards might not do PCI-PCI data transfer well */
+	if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL|PCIPCI_ALIMAGIK)) {
+		dprintk(1,
+			KERN_WARNING
+			"%s: chipset does not support reliable PCI-PCI DMA\n",
+			ZORAN_NAME);
+	}
+
+	res = pci_register_driver(&zoran_driver);
+	if (res) {
+		dprintk(1,
+			KERN_ERR
+			"%s: Unable to register ZR36057 driver\n",
+			ZORAN_NAME);
+		return res;
+	}
+
+	return 0;
+}
+
+static void __exit zoran_exit(void)
+{
+	pci_unregister_driver(&zoran_driver);
+}
+
+module_init(zoran_init);
+module_exit(zoran_exit);
diff --git a/drivers/media/pci/zoran/zoran_card.h b/drivers/media/pci/zoran/zoran_card.h
new file mode 100644
index 0000000..4936fea
--- /dev/null
+++ b/drivers/media/pci/zoran/zoran_card.h
@@ -0,0 +1,54 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * This part handles card-specific data and detection
+ *
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Currently maintained by:
+ *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
+ *   Laurent Pinchart <laurent.pinchart@skynet.be>
+ *   Mailinglist      <mjpeg-users@lists.sf.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ZORAN_CARD_H__
+#define __ZORAN_CARD_H__
+
+extern int zr36067_debug;
+
+#define dprintk(num, format, args...) \
+	do { \
+		if (zr36067_debug >= num) \
+			printk(format, ##args); \
+	} while (0)
+
+/* Anybody who uses more than four? */
+#define BUZ_MAX 4
+
+extern struct video_device zoran_template;
+
+extern int zoran_check_jpg_settings(struct zoran *zr,
+				    struct zoran_jpg_settings *settings,
+				    int try);
+extern void zoran_open_init_params(struct zoran *zr);
+extern void zoran_vdev_release(struct video_device *vdev);
+
+void zr36016_write(struct videocodec *codec, u16 reg, u32 val);
+
+#endif				/* __ZORAN_CARD_H__ */
diff --git a/drivers/media/pci/zoran/zoran_device.c b/drivers/media/pci/zoran/zoran_device.c
new file mode 100644
index 0000000..a4cd504
--- /dev/null
+++ b/drivers/media/pci/zoran/zoran_device.c
@@ -0,0 +1,1640 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * This part handles device access (PCI/I2C/codec/...)
+ *
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Currently maintained by:
+ *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
+ *   Laurent Pinchart <laurent.pinchart@skynet.be>
+ *   Mailinglist      <mjpeg-users@lists.sf.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/spinlock.h>
+#include <linux/sem.h>
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+
+#include "videocodec.h"
+#include "zoran.h"
+#include "zoran_device.h"
+#include "zoran_card.h"
+
+#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | \
+		   ZR36057_ISR_GIRQ1 | \
+		   ZR36057_ISR_JPEGRepIRQ )
+
+static bool lml33dpath;		/* default = 0
+				 * 1 will use digital path in capture
+				 * mode instead of analog. It can be
+				 * used for picture adjustments using
+				 * tool like xawtv while watching image
+				 * on TV monitor connected to the output.
+				 * However, due to absence of 75 Ohm
+				 * load on Bt819 input, there will be
+				 * some image imperfections */
+
+module_param(lml33dpath, bool, 0644);
+MODULE_PARM_DESC(lml33dpath,
+		 "Use digital path capture mode (on LML33 cards)");
+
+static void
+zr36057_init_vfe (struct zoran *zr);
+
+/*
+ * General Purpose I/O and Guest bus access
+ */
+
+/*
+ * This is a bit tricky. When a board lacks a GPIO function, the corresponding
+ * GPIO bit number in the card_info structure is set to 0.
+ */
+
+void
+GPIO (struct zoran *zr,
+      int           bit,
+      unsigned int  value)
+{
+	u32 reg;
+	u32 mask;
+
+	/* Make sure the bit number is legal
+	 * A bit number of -1 (lacking) gives a mask of 0,
+	 * making it harmless */
+	mask = (1 << (24 + bit)) & 0xff000000;
+	reg = btread(ZR36057_GPPGCR1) & ~mask;
+	if (value) {
+		reg |= mask;
+	}
+	btwrite(reg, ZR36057_GPPGCR1);
+	udelay(1);
+}
+
+/*
+ * Wait til post office is no longer busy
+ */
+
+int
+post_office_wait (struct zoran *zr)
+{
+	u32 por;
+
+//      while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) {
+	while ((por = btread(ZR36057_POR)) & ZR36057_POR_POPen) {
+		/* wait for something to happen */
+	}
+	if ((por & ZR36057_POR_POTime) && !zr->card.gws_not_connected) {
+		/* In LML33/BUZ \GWS line is not connected, so it has always timeout set */
+		dprintk(1, KERN_INFO "%s: pop timeout %08x\n", ZR_DEVNAME(zr),
+			por);
+		return -1;
+	}
+
+	return 0;
+}
+
+int
+post_office_write (struct zoran *zr,
+		   unsigned int  guest,
+		   unsigned int  reg,
+		   unsigned int  value)
+{
+	u32 por;
+
+	por =
+	    ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) |
+	    ((reg & 7) << 16) | (value & 0xFF);
+	btwrite(por, ZR36057_POR);
+
+	return post_office_wait(zr);
+}
+
+int
+post_office_read (struct zoran *zr,
+		  unsigned int  guest,
+		  unsigned int  reg)
+{
+	u32 por;
+
+	por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16);
+	btwrite(por, ZR36057_POR);
+	if (post_office_wait(zr) < 0) {
+		return -1;
+	}
+
+	return btread(ZR36057_POR) & 0xFF;
+}
+
+/*
+ * detect guests
+ */
+
+static void
+dump_guests (struct zoran *zr)
+{
+	if (zr36067_debug > 2) {
+		int i, guest[8];
+
+		for (i = 1; i < 8; i++) {	// Don't read jpeg codec here
+			guest[i] = post_office_read(zr, i, 0);
+		}
+
+		printk(KERN_INFO "%s: Guests:", ZR_DEVNAME(zr));
+
+		for (i = 1; i < 8; i++) {
+			printk(" 0x%02x", guest[i]);
+		}
+		printk("\n");
+	}
+}
+
+static inline unsigned long
+get_time (void)
+{
+	struct timeval tv;
+
+	do_gettimeofday(&tv);
+	return (1000000 * tv.tv_sec + tv.tv_usec);
+}
+
+void
+detect_guest_activity (struct zoran *zr)
+{
+	int timeout, i, j, res, guest[8], guest0[8], change[8][3];
+	unsigned long t0, t1;
+
+	dump_guests(zr);
+	printk(KERN_INFO "%s: Detecting guests activity, please wait...\n",
+	       ZR_DEVNAME(zr));
+	for (i = 1; i < 8; i++) {	// Don't read jpeg codec here
+		guest0[i] = guest[i] = post_office_read(zr, i, 0);
+	}
+
+	timeout = 0;
+	j = 0;
+	t0 = get_time();
+	while (timeout < 10000) {
+		udelay(10);
+		timeout++;
+		for (i = 1; (i < 8) && (j < 8); i++) {
+			res = post_office_read(zr, i, 0);
+			if (res != guest[i]) {
+				t1 = get_time();
+				change[j][0] = (t1 - t0);
+				t0 = t1;
+				change[j][1] = i;
+				change[j][2] = res;
+				j++;
+				guest[i] = res;
+			}
+		}
+		if (j >= 8)
+			break;
+	}
+	printk(KERN_INFO "%s: Guests:", ZR_DEVNAME(zr));
+
+	for (i = 1; i < 8; i++) {
+		printk(" 0x%02x", guest0[i]);
+	}
+	printk("\n");
+	if (j == 0) {
+		printk(KERN_INFO "%s: No activity detected.\n", ZR_DEVNAME(zr));
+		return;
+	}
+	for (i = 0; i < j; i++) {
+		printk(KERN_INFO "%s: %6d: %d => 0x%02x\n", ZR_DEVNAME(zr),
+		       change[i][0], change[i][1], change[i][2]);
+	}
+}
+
+/*
+ * JPEG Codec access
+ */
+
+void
+jpeg_codec_sleep (struct zoran *zr,
+		  int           sleep)
+{
+	GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_SLEEP], !sleep);
+	if (!sleep) {
+		dprintk(3,
+			KERN_DEBUG
+			"%s: jpeg_codec_sleep() - wake GPIO=0x%08x\n",
+			ZR_DEVNAME(zr), btread(ZR36057_GPPGCR1));
+		udelay(500);
+	} else {
+		dprintk(3,
+			KERN_DEBUG
+			"%s: jpeg_codec_sleep() - sleep GPIO=0x%08x\n",
+			ZR_DEVNAME(zr), btread(ZR36057_GPPGCR1));
+		udelay(2);
+	}
+}
+
+int
+jpeg_codec_reset (struct zoran *zr)
+{
+	/* Take the codec out of sleep */
+	jpeg_codec_sleep(zr, 0);
+
+	if (zr->card.gpcs[GPCS_JPEG_RESET] != 0xff) {
+		post_office_write(zr, zr->card.gpcs[GPCS_JPEG_RESET], 0,
+				  0);
+		udelay(2);
+	} else {
+		GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 0);
+		udelay(2);
+		GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 1);
+		udelay(2);
+	}
+
+	return 0;
+}
+
+/*
+ *   Set the registers for the size we have specified. Don't bother
+ *   trying to understand this without the ZR36057 manual in front of
+ *   you [AC].
+ *
+ *   PS: The manual is free for download in .pdf format from
+ *   www.zoran.com - nicely done those folks.
+ */
+
+static void
+zr36057_adjust_vfe (struct zoran          *zr,
+		    enum zoran_codec_mode  mode)
+{
+	u32 reg;
+
+	switch (mode) {
+	case BUZ_MODE_MOTION_DECOMPRESS:
+		btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
+		reg = btread(ZR36057_VFEHCR);
+		if ((reg & (1 << 10)) && zr->card.type != LML33R10) {
+			reg += ((1 << 10) | 1);
+		}
+		btwrite(reg, ZR36057_VFEHCR);
+		break;
+	case BUZ_MODE_MOTION_COMPRESS:
+	case BUZ_MODE_IDLE:
+	default:
+		if ((zr->norm & V4L2_STD_NTSC) ||
+		    (zr->card.type == LML33R10 &&
+		     (zr->norm & V4L2_STD_PAL)))
+			btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
+		else
+			btor(ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
+		reg = btread(ZR36057_VFEHCR);
+		if (!(reg & (1 << 10)) && zr->card.type != LML33R10) {
+			reg -= ((1 << 10) | 1);
+		}
+		btwrite(reg, ZR36057_VFEHCR);
+		break;
+	}
+}
+
+/*
+ * set geometry
+ */
+
+static void
+zr36057_set_vfe (struct zoran              *zr,
+		 int                        video_width,
+		 int                        video_height,
+		 const struct zoran_format *format)
+{
+	struct tvnorm *tvn;
+	unsigned HStart, HEnd, VStart, VEnd;
+	unsigned DispMode;
+	unsigned VidWinWid, VidWinHt;
+	unsigned hcrop1, hcrop2, vcrop1, vcrop2;
+	unsigned Wa, We, Ha, He;
+	unsigned X, Y, HorDcm, VerDcm;
+	u32 reg;
+	unsigned mask_line_size;
+
+	tvn = zr->timing;
+
+	Wa = tvn->Wa;
+	Ha = tvn->Ha;
+
+	dprintk(2, KERN_INFO "%s: set_vfe() - width = %d, height = %d\n",
+		ZR_DEVNAME(zr), video_width, video_height);
+
+	if (video_width < BUZ_MIN_WIDTH ||
+	    video_height < BUZ_MIN_HEIGHT ||
+	    video_width > Wa || video_height > Ha) {
+		dprintk(1, KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n",
+			ZR_DEVNAME(zr), video_width, video_height);
+		return;
+	}
+
+	/**** zr36057 ****/
+
+	/* horizontal */
+	VidWinWid = video_width;
+	X = DIV_ROUND_UP(VidWinWid * 64, tvn->Wa);
+	We = (VidWinWid * 64) / X;
+	HorDcm = 64 - X;
+	hcrop1 = 2 * ((tvn->Wa - We) / 4);
+	hcrop2 = tvn->Wa - We - hcrop1;
+	HStart = tvn->HStart ? tvn->HStart : 1;
+	/* (Ronald) Original comment:
+	 * "| 1 Doesn't have any effect, tested on both a DC10 and a DC10+"
+	 * this is false. It inverses chroma values on the LML33R10 (so Cr
+	 * suddenly is shown as Cb and reverse, really cool effect if you
+	 * want to see blue faces, not useful otherwise). So don't use |1.
+	 * However, the DC10 has '0' as HStart, but does need |1, so we
+	 * use a dirty check...
+	 */
+	HEnd = HStart + tvn->Wa - 1;
+	HStart += hcrop1;
+	HEnd -= hcrop2;
+	reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart)
+	    | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd);
+	if (zr->card.vfe_pol.hsync_pol)
+		reg |= ZR36057_VFEHCR_HSPol;
+	btwrite(reg, ZR36057_VFEHCR);
+
+	/* Vertical */
+	DispMode = !(video_height > BUZ_MAX_HEIGHT / 2);
+	VidWinHt = DispMode ? video_height : video_height / 2;
+	Y = DIV_ROUND_UP(VidWinHt * 64 * 2, tvn->Ha);
+	He = (VidWinHt * 64) / Y;
+	VerDcm = 64 - Y;
+	vcrop1 = (tvn->Ha / 2 - He) / 2;
+	vcrop2 = tvn->Ha / 2 - He - vcrop1;
+	VStart = tvn->VStart;
+	VEnd = VStart + tvn->Ha / 2;	// - 1; FIXME SnapShot times out with -1 in 768*576 on the DC10 - LP
+	VStart += vcrop1;
+	VEnd -= vcrop2;
+	reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart)
+	    | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd);
+	if (zr->card.vfe_pol.vsync_pol)
+		reg |= ZR36057_VFEVCR_VSPol;
+	btwrite(reg, ZR36057_VFEVCR);
+
+	/* scaler and pixel format */
+	reg = 0;
+	reg |= (HorDcm << ZR36057_VFESPFR_HorDcm);
+	reg |= (VerDcm << ZR36057_VFESPFR_VerDcm);
+	reg |= (DispMode << ZR36057_VFESPFR_DispMode);
+	/* RJ: I don't know, why the following has to be the opposite
+	 * of the corresponding ZR36060 setting, but only this way
+	 * we get the correct colors when uncompressing to the screen  */
+	//reg |= ZR36057_VFESPFR_VCLKPol; /**/
+	/* RJ: Don't know if that is needed for NTSC also */
+	if (!(zr->norm & V4L2_STD_NTSC))
+		reg |= ZR36057_VFESPFR_ExtFl;	// NEEDED!!!!!!! Wolfgang
+	reg |= ZR36057_VFESPFR_TopField;
+	if (HorDcm >= 48) {
+		reg |= 3 << ZR36057_VFESPFR_HFilter;	/* 5 tap filter */
+	} else if (HorDcm >= 32) {
+		reg |= 2 << ZR36057_VFESPFR_HFilter;	/* 4 tap filter */
+	} else if (HorDcm >= 16) {
+		reg |= 1 << ZR36057_VFESPFR_HFilter;	/* 3 tap filter */
+	}
+	reg |= format->vfespfr;
+	btwrite(reg, ZR36057_VFESPFR);
+
+	/* display configuration */
+	reg = (16 << ZR36057_VDCR_MinPix)
+	    | (VidWinHt << ZR36057_VDCR_VidWinHt)
+	    | (VidWinWid << ZR36057_VDCR_VidWinWid);
+	if (pci_pci_problems & PCIPCI_TRITON)
+		// || zr->revision < 1) // Revision 1 has also Triton support
+		reg &= ~ZR36057_VDCR_Triton;
+	else
+		reg |= ZR36057_VDCR_Triton;
+	btwrite(reg, ZR36057_VDCR);
+
+	/* (Ronald) don't write this if overlay_mask = NULL */
+	if (zr->overlay_mask) {
+		/* Write overlay clipping mask data, but don't enable overlay clipping */
+		/* RJ: since this makes only sense on the screen, we use
+		 * zr->overlay_settings.width instead of video_width */
+
+		mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
+		reg = virt_to_bus(zr->overlay_mask);
+		btwrite(reg, ZR36057_MMTR);
+		reg = virt_to_bus(zr->overlay_mask + mask_line_size);
+		btwrite(reg, ZR36057_MMBR);
+		reg =
+		    mask_line_size - (zr->overlay_settings.width +
+				      31) / 32;
+		if (DispMode == 0)
+			reg += mask_line_size;
+		reg <<= ZR36057_OCR_MaskStride;
+		btwrite(reg, ZR36057_OCR);
+	}
+
+	zr36057_adjust_vfe(zr, zr->codec_mode);
+}
+
+/*
+ * Switch overlay on or off
+ */
+
+void
+zr36057_overlay (struct zoran *zr,
+		 int           on)
+{
+	u32 reg;
+
+	if (on) {
+		/* do the necessary settings ... */
+		btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);	/* switch it off first */
+
+		zr36057_set_vfe(zr,
+				zr->overlay_settings.width,
+				zr->overlay_settings.height,
+				zr->overlay_settings.format);
+
+		/* Start and length of each line MUST be 4-byte aligned.
+		 * This should be already checked before the call to this routine.
+		 * All error messages are internal driver checking only! */
+
+		/* video display top and bottom registers */
+		reg = (long) zr->vbuf_base +
+		    zr->overlay_settings.x *
+		    ((zr->overlay_settings.format->depth + 7) / 8) +
+		    zr->overlay_settings.y *
+		    zr->vbuf_bytesperline;
+		btwrite(reg, ZR36057_VDTR);
+		if (reg & 3)
+			dprintk(1,
+				KERN_ERR
+				"%s: zr36057_overlay() - video_address not aligned\n",
+				ZR_DEVNAME(zr));
+		if (zr->overlay_settings.height > BUZ_MAX_HEIGHT / 2)
+			reg += zr->vbuf_bytesperline;
+		btwrite(reg, ZR36057_VDBR);
+
+		/* video stride, status, and frame grab register */
+		reg = zr->vbuf_bytesperline -
+		    zr->overlay_settings.width *
+		    ((zr->overlay_settings.format->depth + 7) / 8);
+		if (zr->overlay_settings.height > BUZ_MAX_HEIGHT / 2)
+			reg += zr->vbuf_bytesperline;
+		if (reg & 3)
+			dprintk(1,
+				KERN_ERR
+				"%s: zr36057_overlay() - video_stride not aligned\n",
+				ZR_DEVNAME(zr));
+		reg = (reg << ZR36057_VSSFGR_DispStride);
+		reg |= ZR36057_VSSFGR_VidOvf;	/* clear overflow status */
+		btwrite(reg, ZR36057_VSSFGR);
+
+		/* Set overlay clipping */
+		if (zr->overlay_settings.clipcount > 0)
+			btor(ZR36057_OCR_OvlEnable, ZR36057_OCR);
+
+		/* ... and switch it on */
+		btor(ZR36057_VDCR_VidEn, ZR36057_VDCR);
+	} else {
+		/* Switch it off */
+		btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
+	}
+}
+
+/*
+ * The overlay mask has one bit for each pixel on a scan line,
+ *  and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels.
+ */
+
+void write_overlay_mask(struct zoran_fh *fh, struct v4l2_clip *vp, int count)
+{
+	struct zoran *zr = fh->zr;
+	unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
+	u32 *mask;
+	int x, y, width, height;
+	unsigned i, j, k;
+
+	/* fill mask with one bits */
+	memset(fh->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT);
+
+	for (i = 0; i < count; ++i) {
+		/* pick up local copy of clip */
+		x = vp[i].c.left;
+		y = vp[i].c.top;
+		width = vp[i].c.width;
+		height = vp[i].c.height;
+
+		/* trim clips that extend beyond the window */
+		if (x < 0) {
+			width += x;
+			x = 0;
+		}
+		if (y < 0) {
+			height += y;
+			y = 0;
+		}
+		if (x + width > fh->overlay_settings.width) {
+			width = fh->overlay_settings.width - x;
+		}
+		if (y + height > fh->overlay_settings.height) {
+			height = fh->overlay_settings.height - y;
+		}
+
+		/* ignore degenerate clips */
+		if (height <= 0) {
+			continue;
+		}
+		if (width <= 0) {
+			continue;
+		}
+
+		/* apply clip for each scan line */
+		for (j = 0; j < height; ++j) {
+			/* reset bit for each pixel */
+			/* this can be optimized later if need be */
+			mask = fh->overlay_mask + (y + j) * mask_line_size;
+			for (k = 0; k < width; ++k) {
+				mask[(x + k) / 32] &=
+				    ~((u32) 1 << (x + k) % 32);
+			}
+		}
+	}
+}
+
+/* Enable/Disable uncompressed memory grabbing of the 36057 */
+
+void
+zr36057_set_memgrab (struct zoran *zr,
+		     int           mode)
+{
+	if (mode) {
+		/* We only check SnapShot and not FrameGrab here.  SnapShot==1
+		 * means a capture is already in progress, but FrameGrab==1
+		 * doesn't necessary mean that.  It's more correct to say a 1
+		 * to 0 transition indicates a capture completed.  If a
+		 * capture is pending when capturing is tuned off, FrameGrab
+		 * will be stuck at 1 until capturing is turned back on.
+		 */
+		if (btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot)
+			dprintk(1,
+				KERN_WARNING
+				"%s: zr36057_set_memgrab(1) with SnapShot on!?\n",
+				ZR_DEVNAME(zr));
+
+		/* switch on VSync interrupts */
+		btwrite(IRQ_MASK, ZR36057_ISR);	// Clear Interrupts
+		btor(zr->card.vsync_int, ZR36057_ICR);	// SW
+
+		/* enable SnapShot */
+		btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
+
+		/* Set zr36057 video front end  and enable video */
+		zr36057_set_vfe(zr, zr->v4l_settings.width,
+				zr->v4l_settings.height,
+				zr->v4l_settings.format);
+
+		zr->v4l_memgrab_active = 1;
+	} else {
+		/* switch off VSync interrupts */
+		btand(~zr->card.vsync_int, ZR36057_ICR);	// SW
+
+		zr->v4l_memgrab_active = 0;
+		zr->v4l_grab_frame = NO_GRAB_ACTIVE;
+
+		/* reenable grabbing to screen if it was running */
+		if (zr->v4l_overlay_active) {
+			zr36057_overlay(zr, 1);
+		} else {
+			btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
+			btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
+		}
+	}
+}
+
+int
+wait_grab_pending (struct zoran *zr)
+{
+	unsigned long flags;
+
+	/* wait until all pending grabs are finished */
+
+	if (!zr->v4l_memgrab_active)
+		return 0;
+
+	wait_event_interruptible(zr->v4l_capq,
+			(zr->v4l_pend_tail == zr->v4l_pend_head));
+	if (signal_pending(current))
+		return -ERESTARTSYS;
+
+	spin_lock_irqsave(&zr->spinlock, flags);
+	zr36057_set_memgrab(zr, 0);
+	spin_unlock_irqrestore(&zr->spinlock, flags);
+
+	return 0;
+}
+
+/*****************************************************************************
+ *                                                                           *
+ *  Set up the Buz-specific MJPEG part                                       *
+ *                                                                           *
+ *****************************************************************************/
+
+static inline void
+set_frame (struct zoran *zr,
+	   int           val)
+{
+	GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_FRAME], val);
+}
+
+static void
+set_videobus_dir (struct zoran *zr,
+		  int           val)
+{
+	switch (zr->card.type) {
+	case LML33:
+	case LML33R10:
+		if (lml33dpath == 0)
+			GPIO(zr, 5, val);
+		else
+			GPIO(zr, 5, 1);
+		break;
+	default:
+		GPIO(zr, zr->card.gpio[ZR_GPIO_VID_DIR],
+		     zr->card.gpio_pol[ZR_GPIO_VID_DIR] ? !val : val);
+		break;
+	}
+}
+
+static void
+init_jpeg_queue (struct zoran *zr)
+{
+	int i;
+
+	/* re-initialize DMA ring stuff */
+	zr->jpg_que_head = 0;
+	zr->jpg_dma_head = 0;
+	zr->jpg_dma_tail = 0;
+	zr->jpg_que_tail = 0;
+	zr->jpg_seq_num = 0;
+	zr->JPEG_error = 0;
+	zr->num_errors = 0;
+	zr->jpg_err_seq = 0;
+	zr->jpg_err_shift = 0;
+	zr->jpg_queued_num = 0;
+	for (i = 0; i < zr->jpg_buffers.num_buffers; i++) {
+		zr->jpg_buffers.buffer[i].state = BUZ_STATE_USER;	/* nothing going on */
+	}
+	for (i = 0; i < BUZ_NUM_STAT_COM; i++) {
+		zr->stat_com[i] = cpu_to_le32(1);	/* mark as unavailable to zr36057 */
+	}
+}
+
+static void
+zr36057_set_jpg (struct zoran          *zr,
+		 enum zoran_codec_mode  mode)
+{
+	struct tvnorm *tvn;
+	u32 reg;
+
+	tvn = zr->timing;
+
+	/* assert P_Reset, disable code transfer, deassert Active */
+	btwrite(0, ZR36057_JPC);
+
+	/* MJPEG compression mode */
+	switch (mode) {
+
+	case BUZ_MODE_MOTION_COMPRESS:
+	default:
+		reg = ZR36057_JMC_MJPGCmpMode;
+		break;
+
+	case BUZ_MODE_MOTION_DECOMPRESS:
+		reg = ZR36057_JMC_MJPGExpMode;
+		reg |= ZR36057_JMC_SyncMstr;
+		/* RJ: The following is experimental - improves the output to screen */
+		//if(zr->jpg_settings.VFIFO_FB) reg |= ZR36057_JMC_VFIFO_FB; // No, it doesn't. SM
+		break;
+
+	case BUZ_MODE_STILL_COMPRESS:
+		reg = ZR36057_JMC_JPGCmpMode;
+		break;
+
+	case BUZ_MODE_STILL_DECOMPRESS:
+		reg = ZR36057_JMC_JPGExpMode;
+		break;
+
+	}
+	reg |= ZR36057_JMC_JPG;
+	if (zr->jpg_settings.field_per_buff == 1)
+		reg |= ZR36057_JMC_Fld_per_buff;
+	btwrite(reg, ZR36057_JMC);
+
+	/* vertical */
+	btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR);
+	reg = (6 << ZR36057_VSP_VsyncSize) |
+	      (tvn->Ht << ZR36057_VSP_FrmTot);
+	btwrite(reg, ZR36057_VSP);
+	reg = ((zr->jpg_settings.img_y + tvn->VStart) << ZR36057_FVAP_NAY) |
+	      (zr->jpg_settings.img_height << ZR36057_FVAP_PAY);
+	btwrite(reg, ZR36057_FVAP);
+
+	/* horizontal */
+	if (zr->card.vfe_pol.hsync_pol)
+		btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR);
+	else
+		btand(~ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR);
+	reg = ((tvn->HSyncStart) << ZR36057_HSP_HsyncStart) |
+	      (tvn->Wt << ZR36057_HSP_LineTot);
+	btwrite(reg, ZR36057_HSP);
+	reg = ((zr->jpg_settings.img_x +
+		tvn->HStart + 4) << ZR36057_FHAP_NAX) |
+	      (zr->jpg_settings.img_width << ZR36057_FHAP_PAX);
+	btwrite(reg, ZR36057_FHAP);
+
+	/* field process parameters */
+	if (zr->jpg_settings.odd_even)
+		reg = ZR36057_FPP_Odd_Even;
+	else
+		reg = 0;
+
+	btwrite(reg, ZR36057_FPP);
+
+	/* Set proper VCLK Polarity, else colors will be wrong during playback */
+	//btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR);
+
+	/* code base address */
+	reg = virt_to_bus(zr->stat_com);
+	btwrite(reg, ZR36057_JCBA);
+
+	/* FIFO threshold (FIFO is 160. double words) */
+	/* NOTE: decimal values here */
+	switch (mode) {
+
+	case BUZ_MODE_STILL_COMPRESS:
+	case BUZ_MODE_MOTION_COMPRESS:
+		if (zr->card.type != BUZ)
+			reg = 140;
+		else
+			reg = 60;
+		break;
+
+	case BUZ_MODE_STILL_DECOMPRESS:
+	case BUZ_MODE_MOTION_DECOMPRESS:
+		reg = 20;
+		break;
+
+	default:
+		reg = 80;
+		break;
+
+	}
+	btwrite(reg, ZR36057_JCFT);
+	zr36057_adjust_vfe(zr, mode);
+
+}
+
+void
+print_interrupts (struct zoran *zr)
+{
+	int res, noerr = 0;
+
+	printk(KERN_INFO "%s: interrupts received:", ZR_DEVNAME(zr));
+	if ((res = zr->field_counter) < -1 || res > 1) {
+		printk(" FD:%d", res);
+	}
+	if ((res = zr->intr_counter_GIRQ1) != 0) {
+		printk(" GIRQ1:%d", res);
+		noerr++;
+	}
+	if ((res = zr->intr_counter_GIRQ0) != 0) {
+		printk(" GIRQ0:%d", res);
+		noerr++;
+	}
+	if ((res = zr->intr_counter_CodRepIRQ) != 0) {
+		printk(" CodRepIRQ:%d", res);
+		noerr++;
+	}
+	if ((res = zr->intr_counter_JPEGRepIRQ) != 0) {
+		printk(" JPEGRepIRQ:%d", res);
+		noerr++;
+	}
+	if (zr->JPEG_max_missed) {
+		printk(" JPEG delays: max=%d min=%d", zr->JPEG_max_missed,
+		       zr->JPEG_min_missed);
+	}
+	if (zr->END_event_missed) {
+		printk(" ENDs missed: %d", zr->END_event_missed);
+	}
+	//if (zr->jpg_queued_num) {
+	printk(" queue_state=%ld/%ld/%ld/%ld", zr->jpg_que_tail,
+	       zr->jpg_dma_tail, zr->jpg_dma_head, zr->jpg_que_head);
+	//}
+	if (!noerr) {
+		printk(": no interrupts detected.");
+	}
+	printk("\n");
+}
+
+void
+clear_interrupt_counters (struct zoran *zr)
+{
+	zr->intr_counter_GIRQ1 = 0;
+	zr->intr_counter_GIRQ0 = 0;
+	zr->intr_counter_CodRepIRQ = 0;
+	zr->intr_counter_JPEGRepIRQ = 0;
+	zr->field_counter = 0;
+	zr->IRQ1_in = 0;
+	zr->IRQ1_out = 0;
+	zr->JPEG_in = 0;
+	zr->JPEG_out = 0;
+	zr->JPEG_0 = 0;
+	zr->JPEG_1 = 0;
+	zr->END_event_missed = 0;
+	zr->JPEG_missed = 0;
+	zr->JPEG_max_missed = 0;
+	zr->JPEG_min_missed = 0x7fffffff;
+}
+
+static u32
+count_reset_interrupt (struct zoran *zr)
+{
+	u32 isr;
+
+	if ((isr = btread(ZR36057_ISR) & 0x78000000)) {
+		if (isr & ZR36057_ISR_GIRQ1) {
+			btwrite(ZR36057_ISR_GIRQ1, ZR36057_ISR);
+			zr->intr_counter_GIRQ1++;
+		}
+		if (isr & ZR36057_ISR_GIRQ0) {
+			btwrite(ZR36057_ISR_GIRQ0, ZR36057_ISR);
+			zr->intr_counter_GIRQ0++;
+		}
+		if (isr & ZR36057_ISR_CodRepIRQ) {
+			btwrite(ZR36057_ISR_CodRepIRQ, ZR36057_ISR);
+			zr->intr_counter_CodRepIRQ++;
+		}
+		if (isr & ZR36057_ISR_JPEGRepIRQ) {
+			btwrite(ZR36057_ISR_JPEGRepIRQ, ZR36057_ISR);
+			zr->intr_counter_JPEGRepIRQ++;
+		}
+	}
+	return isr;
+}
+
+void
+jpeg_start (struct zoran *zr)
+{
+	int reg;
+
+	zr->frame_num = 0;
+
+	/* deassert P_reset, disable code transfer, deassert Active */
+	btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC);
+	/* stop flushing the internal code buffer */
+	btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
+	/* enable code transfer */
+	btor(ZR36057_JPC_CodTrnsEn, ZR36057_JPC);
+
+	/* clear IRQs */
+	btwrite(IRQ_MASK, ZR36057_ISR);
+	/* enable the JPEG IRQs */
+	btwrite(zr->card.jpeg_int |
+			ZR36057_ICR_JPEGRepIRQ |
+			ZR36057_ICR_IntPinEn,
+		ZR36057_ICR);
+
+	set_frame(zr, 0);	// \FRAME
+
+	/* set the JPEG codec guest ID */
+	reg = (zr->card.gpcs[1] << ZR36057_JCGI_JPEGuestID) |
+	       (0 << ZR36057_JCGI_JPEGuestReg);
+	btwrite(reg, ZR36057_JCGI);
+
+	if (zr->card.video_vfe == CODEC_TYPE_ZR36016 &&
+	    zr->card.video_codec == CODEC_TYPE_ZR36050) {
+		/* Enable processing on the ZR36016 */
+		if (zr->vfe)
+			zr36016_write(zr->vfe, 0, 1);
+
+		/* load the address of the GO register in the ZR36050 latch */
+		post_office_write(zr, 0, 0, 0);
+	}
+
+	/* assert Active */
+	btor(ZR36057_JPC_Active, ZR36057_JPC);
+
+	/* enable the Go generation */
+	btor(ZR36057_JMC_Go_en, ZR36057_JMC);
+	udelay(30);
+
+	set_frame(zr, 1);	// /FRAME
+
+	dprintk(3, KERN_DEBUG "%s: jpeg_start\n", ZR_DEVNAME(zr));
+}
+
+void
+zr36057_enable_jpg (struct zoran          *zr,
+		    enum zoran_codec_mode  mode)
+{
+	struct vfe_settings cap;
+	int field_size =
+	    zr->jpg_buffers.buffer_size / zr->jpg_settings.field_per_buff;
+
+	zr->codec_mode = mode;
+
+	cap.x = zr->jpg_settings.img_x;
+	cap.y = zr->jpg_settings.img_y;
+	cap.width = zr->jpg_settings.img_width;
+	cap.height = zr->jpg_settings.img_height;
+	cap.decimation =
+	    zr->jpg_settings.HorDcm | (zr->jpg_settings.VerDcm << 8);
+	cap.quality = zr->jpg_settings.jpg_comp.quality;
+
+	switch (mode) {
+
+	case BUZ_MODE_MOTION_COMPRESS: {
+		struct jpeg_app_marker app;
+		struct jpeg_com_marker com;
+
+		/* In motion compress mode, the decoder output must be enabled, and
+		 * the video bus direction set to input.
+		 */
+		set_videobus_dir(zr, 0);
+		decoder_call(zr, video, s_stream, 1);
+		encoder_call(zr, video, s_routing, 0, 0, 0);
+
+		/* Take the JPEG codec and the VFE out of sleep */
+		jpeg_codec_sleep(zr, 0);
+
+		/* set JPEG app/com marker */
+		app.appn = zr->jpg_settings.jpg_comp.APPn;
+		app.len = zr->jpg_settings.jpg_comp.APP_len;
+		memcpy(app.data, zr->jpg_settings.jpg_comp.APP_data, 60);
+		zr->codec->control(zr->codec, CODEC_S_JPEG_APP_DATA,
+				   sizeof(struct jpeg_app_marker), &app);
+
+		com.len = zr->jpg_settings.jpg_comp.COM_len;
+		memcpy(com.data, zr->jpg_settings.jpg_comp.COM_data, 60);
+		zr->codec->control(zr->codec, CODEC_S_JPEG_COM_DATA,
+				   sizeof(struct jpeg_com_marker), &com);
+
+		/* Setup the JPEG codec */
+		zr->codec->control(zr->codec, CODEC_S_JPEG_TDS_BYTE,
+				   sizeof(int), &field_size);
+		zr->codec->set_video(zr->codec, zr->timing, &cap,
+				     &zr->card.vfe_pol);
+		zr->codec->set_mode(zr->codec, CODEC_DO_COMPRESSION);
+
+		/* Setup the VFE */
+		if (zr->vfe) {
+			zr->vfe->control(zr->vfe, CODEC_S_JPEG_TDS_BYTE,
+					 sizeof(int), &field_size);
+			zr->vfe->set_video(zr->vfe, zr->timing, &cap,
+					   &zr->card.vfe_pol);
+			zr->vfe->set_mode(zr->vfe, CODEC_DO_COMPRESSION);
+		}
+
+		init_jpeg_queue(zr);
+		zr36057_set_jpg(zr, mode);	// \P_Reset, ... Video param, FIFO
+
+		clear_interrupt_counters(zr);
+		dprintk(2, KERN_INFO "%s: enable_jpg(MOTION_COMPRESS)\n",
+			ZR_DEVNAME(zr));
+		break;
+	}
+
+	case BUZ_MODE_MOTION_DECOMPRESS:
+		/* In motion decompression mode, the decoder output must be disabled, and
+		 * the video bus direction set to output.
+		 */
+		decoder_call(zr, video, s_stream, 0);
+		set_videobus_dir(zr, 1);
+		encoder_call(zr, video, s_routing, 1, 0, 0);
+
+		/* Take the JPEG codec and the VFE out of sleep */
+		jpeg_codec_sleep(zr, 0);
+		/* Setup the VFE */
+		if (zr->vfe) {
+			zr->vfe->set_video(zr->vfe, zr->timing, &cap,
+					   &zr->card.vfe_pol);
+			zr->vfe->set_mode(zr->vfe, CODEC_DO_EXPANSION);
+		}
+		/* Setup the JPEG codec */
+		zr->codec->set_video(zr->codec, zr->timing, &cap,
+				     &zr->card.vfe_pol);
+		zr->codec->set_mode(zr->codec, CODEC_DO_EXPANSION);
+
+		init_jpeg_queue(zr);
+		zr36057_set_jpg(zr, mode);	// \P_Reset, ... Video param, FIFO
+
+		clear_interrupt_counters(zr);
+		dprintk(2, KERN_INFO "%s: enable_jpg(MOTION_DECOMPRESS)\n",
+			ZR_DEVNAME(zr));
+		break;
+
+	case BUZ_MODE_IDLE:
+	default:
+		/* shut down processing */
+		btand(~(zr->card.jpeg_int | ZR36057_ICR_JPEGRepIRQ),
+		      ZR36057_ICR);
+		btwrite(zr->card.jpeg_int | ZR36057_ICR_JPEGRepIRQ,
+			ZR36057_ISR);
+		btand(~ZR36057_JMC_Go_en, ZR36057_JMC);	// \Go_en
+
+		msleep(50);
+
+		set_videobus_dir(zr, 0);
+		set_frame(zr, 1);	// /FRAME
+		btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);	// /CFlush
+		btwrite(0, ZR36057_JPC);	// \P_Reset,\CodTrnsEn,\Active
+		btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC);
+		btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC);
+		jpeg_codec_reset(zr);
+		jpeg_codec_sleep(zr, 1);
+		zr36057_adjust_vfe(zr, mode);
+
+		decoder_call(zr, video, s_stream, 1);
+		encoder_call(zr, video, s_routing, 0, 0, 0);
+
+		dprintk(2, KERN_INFO "%s: enable_jpg(IDLE)\n", ZR_DEVNAME(zr));
+		break;
+
+	}
+}
+
+/* when this is called the spinlock must be held */
+void
+zoran_feed_stat_com (struct zoran *zr)
+{
+	/* move frames from pending queue to DMA */
+
+	int frame, i, max_stat_com;
+
+	max_stat_com =
+	    (zr->jpg_settings.TmpDcm ==
+	     1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1);
+
+	while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com &&
+	       zr->jpg_dma_head < zr->jpg_que_head) {
+
+		frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME];
+		if (zr->jpg_settings.TmpDcm == 1) {
+			/* fill 1 stat_com entry */
+			i = (zr->jpg_dma_head -
+			     zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
+			if (!(zr->stat_com[i] & cpu_to_le32(1)))
+				break;
+			zr->stat_com[i] =
+			    cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus);
+		} else {
+			/* fill 2 stat_com entries */
+			i = ((zr->jpg_dma_head -
+			      zr->jpg_err_shift) & 1) * 2;
+			if (!(zr->stat_com[i] & cpu_to_le32(1)))
+				break;
+			zr->stat_com[i] =
+			    cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus);
+			zr->stat_com[i + 1] =
+			    cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus);
+		}
+		zr->jpg_buffers.buffer[frame].state = BUZ_STATE_DMA;
+		zr->jpg_dma_head++;
+
+	}
+	if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS)
+		zr->jpg_queued_num++;
+}
+
+/* when this is called the spinlock must be held */
+static void
+zoran_reap_stat_com (struct zoran *zr)
+{
+	/* move frames from DMA queue to done queue */
+
+	int i;
+	u32 stat_com;
+	unsigned int seq;
+	unsigned int dif;
+	struct zoran_buffer *buffer;
+	int frame;
+
+	/* In motion decompress we don't have a hardware frame counter,
+	 * we just count the interrupts here */
+
+	if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) {
+		zr->jpg_seq_num++;
+	}
+	while (zr->jpg_dma_tail < zr->jpg_dma_head) {
+		if (zr->jpg_settings.TmpDcm == 1)
+			i = (zr->jpg_dma_tail -
+			     zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
+		else
+			i = ((zr->jpg_dma_tail -
+			      zr->jpg_err_shift) & 1) * 2 + 1;
+
+		stat_com = le32_to_cpu(zr->stat_com[i]);
+
+		if ((stat_com & 1) == 0) {
+			return;
+		}
+		frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
+		buffer = &zr->jpg_buffers.buffer[frame];
+		do_gettimeofday(&buffer->bs.timestamp);
+
+		if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
+			buffer->bs.length = (stat_com & 0x7fffff) >> 1;
+
+			/* update sequence number with the help of the counter in stat_com */
+
+			seq = ((stat_com >> 24) + zr->jpg_err_seq) & 0xff;
+			dif = (seq - zr->jpg_seq_num) & 0xff;
+			zr->jpg_seq_num += dif;
+		} else {
+			buffer->bs.length = 0;
+		}
+		buffer->bs.seq =
+		    zr->jpg_settings.TmpDcm ==
+		    2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num;
+		buffer->state = BUZ_STATE_DONE;
+
+		zr->jpg_dma_tail++;
+	}
+}
+
+static void zoran_restart(struct zoran *zr)
+{
+	/* Now the stat_comm buffer is ready for restart */
+	unsigned int status = 0;
+	int mode;
+
+	if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
+		decoder_call(zr, video, g_input_status, &status);
+		mode = CODEC_DO_COMPRESSION;
+	} else {
+		status = V4L2_IN_ST_NO_SIGNAL;
+		mode = CODEC_DO_EXPANSION;
+	}
+	if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
+	    !(status & V4L2_IN_ST_NO_SIGNAL)) {
+		/********** RESTART code *************/
+		jpeg_codec_reset(zr);
+		zr->codec->set_mode(zr->codec, mode);
+		zr36057_set_jpg(zr, zr->codec_mode);
+		jpeg_start(zr);
+
+		if (zr->num_errors <= 8)
+			dprintk(2, KERN_INFO "%s: Restart\n",
+				ZR_DEVNAME(zr));
+
+		zr->JPEG_missed = 0;
+		zr->JPEG_error = 2;
+		/********** End RESTART code ***********/
+	}
+}
+
+static void
+error_handler (struct zoran *zr,
+	       u32           astat,
+	       u32           stat)
+{
+	int i;
+
+	/* This is JPEG error handling part */
+	if (zr->codec_mode != BUZ_MODE_MOTION_COMPRESS &&
+	    zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS) {
+		return;
+	}
+
+	if ((stat & 1) == 0 &&
+	    zr->codec_mode == BUZ_MODE_MOTION_COMPRESS &&
+	    zr->jpg_dma_tail - zr->jpg_que_tail >= zr->jpg_buffers.num_buffers) {
+		/* No free buffers... */
+		zoran_reap_stat_com(zr);
+		zoran_feed_stat_com(zr);
+		wake_up_interruptible(&zr->jpg_capq);
+		zr->JPEG_missed = 0;
+		return;
+	}
+
+	if (zr->JPEG_error == 1) {
+		zoran_restart(zr);
+		return;
+	}
+
+	/*
+	 * First entry: error just happened during normal operation
+	 *
+	 * In BUZ_MODE_MOTION_COMPRESS:
+	 *
+	 * Possible glitch in TV signal. In this case we should
+	 * stop the codec and wait for good quality signal before
+	 * restarting it to avoid further problems
+	 *
+	 * In BUZ_MODE_MOTION_DECOMPRESS:
+	 *
+	 * Bad JPEG frame: we have to mark it as processed (codec crashed
+	 * and was not able to do it itself), and to remove it from queue.
+	 */
+	btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
+	udelay(1);
+	stat = stat | (post_office_read(zr, 7, 0) & 3) << 8;
+	btwrite(0, ZR36057_JPC);
+	btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
+	jpeg_codec_reset(zr);
+	jpeg_codec_sleep(zr, 1);
+	zr->JPEG_error = 1;
+	zr->num_errors++;
+
+	/* Report error */
+	if (zr36067_debug > 1 && zr->num_errors <= 8) {
+		long frame;
+		int j;
+
+		frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
+		printk(KERN_ERR
+		       "%s: JPEG error stat=0x%08x(0x%08x) queue_state=%ld/%ld/%ld/%ld seq=%ld frame=%ld. Codec stopped. ",
+		       ZR_DEVNAME(zr), stat, zr->last_isr,
+		       zr->jpg_que_tail, zr->jpg_dma_tail,
+		       zr->jpg_dma_head, zr->jpg_que_head,
+		       zr->jpg_seq_num, frame);
+		printk(KERN_INFO "stat_com frames:");
+		for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
+			for (i = 0; i < zr->jpg_buffers.num_buffers; i++) {
+				if (le32_to_cpu(zr->stat_com[j]) == zr->jpg_buffers.buffer[i].jpg.frag_tab_bus)
+					printk(KERN_CONT "% d->%d", j, i);
+			}
+		}
+		printk(KERN_CONT "\n");
+	}
+	/* Find an entry in stat_com and rotate contents */
+	if (zr->jpg_settings.TmpDcm == 1)
+		i = (zr->jpg_dma_tail - zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
+	else
+		i = ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2;
+	if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) {
+		/* Mimic zr36067 operation */
+		zr->stat_com[i] |= cpu_to_le32(1);
+		if (zr->jpg_settings.TmpDcm != 1)
+			zr->stat_com[i + 1] |= cpu_to_le32(1);
+		/* Refill */
+		zoran_reap_stat_com(zr);
+		zoran_feed_stat_com(zr);
+		wake_up_interruptible(&zr->jpg_capq);
+		/* Find an entry in stat_com again after refill */
+		if (zr->jpg_settings.TmpDcm == 1)
+			i = (zr->jpg_dma_tail - zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
+		else
+			i = ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2;
+	}
+	if (i) {
+		/* Rotate stat_comm entries to make current entry first */
+		int j;
+		__le32 bus_addr[BUZ_NUM_STAT_COM];
+
+		/* Here we are copying the stat_com array, which
+		 * is already in little endian format, so
+		 * no endian conversions here
+		 */
+		memcpy(bus_addr, zr->stat_com, sizeof(bus_addr));
+
+		for (j = 0; j < BUZ_NUM_STAT_COM; j++)
+			zr->stat_com[j] = bus_addr[(i + j) & BUZ_MASK_STAT_COM];
+
+		zr->jpg_err_shift += i;
+		zr->jpg_err_shift &= BUZ_MASK_STAT_COM;
+	}
+	if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)
+		zr->jpg_err_seq = zr->jpg_seq_num;	/* + 1; */
+	zoran_restart(zr);
+}
+
+irqreturn_t
+zoran_irq (int             irq,
+	   void           *dev_id)
+{
+	u32 stat, astat;
+	int count;
+	struct zoran *zr;
+	unsigned long flags;
+
+	zr = dev_id;
+	count = 0;
+
+	if (zr->testing) {
+		/* Testing interrupts */
+		spin_lock_irqsave(&zr->spinlock, flags);
+		while ((stat = count_reset_interrupt(zr))) {
+			if (count++ > 100) {
+				btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
+				dprintk(1,
+					KERN_ERR
+					"%s: IRQ lockup while testing, isr=0x%08x, cleared int mask\n",
+					ZR_DEVNAME(zr), stat);
+				wake_up_interruptible(&zr->test_q);
+			}
+		}
+		zr->last_isr = stat;
+		spin_unlock_irqrestore(&zr->spinlock, flags);
+		return IRQ_HANDLED;
+	}
+
+	spin_lock_irqsave(&zr->spinlock, flags);
+	while (1) {
+		/* get/clear interrupt status bits */
+		stat = count_reset_interrupt(zr);
+		astat = stat & IRQ_MASK;
+		if (!astat) {
+			break;
+		}
+		dprintk(4,
+			KERN_DEBUG
+			"zoran_irq: astat: 0x%08x, mask: 0x%08x\n",
+			astat, btread(ZR36057_ICR));
+		if (astat & zr->card.vsync_int) {	// SW
+
+			if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
+			    zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
+				/* count missed interrupts */
+				zr->JPEG_missed++;
+			}
+			//post_office_read(zr,1,0);
+			/* Interrupts may still happen when
+			 * zr->v4l_memgrab_active is switched off.
+			 * We simply ignore them */
+
+			if (zr->v4l_memgrab_active) {
+				/* A lot more checks should be here ... */
+				if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot) == 0)
+					dprintk(1,
+						KERN_WARNING
+						"%s: BuzIRQ with SnapShot off ???\n",
+						ZR_DEVNAME(zr));
+
+				if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) {
+					/* There is a grab on a frame going on, check if it has finished */
+					if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_FrameGrab) == 0) {
+						/* it is finished, notify the user */
+
+						zr->v4l_buffers.buffer[zr->v4l_grab_frame].state = BUZ_STATE_DONE;
+						zr->v4l_buffers.buffer[zr->v4l_grab_frame].bs.seq = zr->v4l_grab_seq;
+						do_gettimeofday(&zr->v4l_buffers.buffer[zr->v4l_grab_frame].bs.timestamp);
+						zr->v4l_grab_frame = NO_GRAB_ACTIVE;
+						zr->v4l_pend_tail++;
+					}
+				}
+
+				if (zr->v4l_grab_frame == NO_GRAB_ACTIVE)
+					wake_up_interruptible(&zr->v4l_capq);
+
+				/* Check if there is another grab queued */
+
+				if (zr->v4l_grab_frame == NO_GRAB_ACTIVE &&
+				    zr->v4l_pend_tail != zr->v4l_pend_head) {
+					int frame = zr->v4l_pend[zr->v4l_pend_tail & V4L_MASK_FRAME];
+					u32 reg;
+
+					zr->v4l_grab_frame = frame;
+
+					/* Set zr36057 video front end and enable video */
+
+					/* Buffer address */
+
+					reg = zr->v4l_buffers.buffer[frame].v4l.fbuffer_bus;
+					btwrite(reg, ZR36057_VDTR);
+					if (zr->v4l_settings.height > BUZ_MAX_HEIGHT / 2)
+						reg += zr->v4l_settings.bytesperline;
+					btwrite(reg, ZR36057_VDBR);
+
+					/* video stride, status, and frame grab register */
+					reg = 0;
+					if (zr->v4l_settings.height > BUZ_MAX_HEIGHT / 2)
+						reg += zr->v4l_settings.bytesperline;
+					reg = (reg << ZR36057_VSSFGR_DispStride);
+					reg |= ZR36057_VSSFGR_VidOvf;
+					reg |= ZR36057_VSSFGR_SnapShot;
+					reg |= ZR36057_VSSFGR_FrameGrab;
+					btwrite(reg, ZR36057_VSSFGR);
+
+					btor(ZR36057_VDCR_VidEn,
+					     ZR36057_VDCR);
+				}
+			}
+
+			/* even if we don't grab, we do want to increment
+			 * the sequence counter to see lost frames */
+			zr->v4l_grab_seq++;
+		}
+#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ)
+		if (astat & ZR36057_ISR_CodRepIRQ) {
+			zr->intr_counter_CodRepIRQ++;
+			IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n",
+				ZR_DEVNAME(zr)));
+			btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR);
+		}
+#endif				/* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */
+
+#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ)
+		if ((astat & ZR36057_ISR_JPEGRepIRQ) &&
+		    (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
+		     zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)) {
+			if (zr36067_debug > 1 && (!zr->frame_num || zr->JPEG_error)) {
+				char sv[BUZ_NUM_STAT_COM + 1];
+				int i;
+
+				printk(KERN_INFO
+				       "%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n",
+				       ZR_DEVNAME(zr), stat,
+				       zr->jpg_settings.odd_even,
+				       zr->jpg_settings.field_per_buff,
+				       zr->JPEG_missed);
+
+				for (i = 0; i < BUZ_NUM_STAT_COM; i++)
+					sv[i] = le32_to_cpu(zr->stat_com[i]) & 1 ? '1' : '0';
+				sv[BUZ_NUM_STAT_COM] = 0;
+				printk(KERN_INFO
+				       "%s: stat_com=%s queue_state=%ld/%ld/%ld/%ld\n",
+				       ZR_DEVNAME(zr), sv,
+				       zr->jpg_que_tail,
+				       zr->jpg_dma_tail,
+				       zr->jpg_dma_head,
+				       zr->jpg_que_head);
+			} else {
+				/* Get statistics */
+				if (zr->JPEG_missed > zr->JPEG_max_missed)
+					zr->JPEG_max_missed = zr->JPEG_missed;
+				if (zr->JPEG_missed < zr->JPEG_min_missed)
+					zr->JPEG_min_missed = zr->JPEG_missed;
+			}
+
+			if (zr36067_debug > 2 && zr->frame_num < 6) {
+				int i;
+
+				printk(KERN_INFO "%s: seq=%ld stat_com:",
+				       ZR_DEVNAME(zr), zr->jpg_seq_num);
+				for (i = 0; i < 4; i++) {
+					printk(KERN_CONT " %08x",
+					       le32_to_cpu(zr->stat_com[i]));
+				}
+				printk(KERN_CONT "\n");
+			}
+			zr->frame_num++;
+			zr->JPEG_missed = 0;
+			zr->JPEG_error = 0;
+			zoran_reap_stat_com(zr);
+			zoran_feed_stat_com(zr);
+			wake_up_interruptible(&zr->jpg_capq);
+		}
+#endif				/* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */
+
+		/* DATERR, too many fields missed, error processing */
+		if ((astat & zr->card.jpeg_int) ||
+		    zr->JPEG_missed > 25 ||
+		    zr->JPEG_error == 1	||
+		    ((zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) &&
+		     (zr->frame_num && (zr->JPEG_missed > zr->jpg_settings.field_per_buff)))) {
+			error_handler(zr, astat, stat);
+		}
+
+		count++;
+		if (count > 10) {
+			dprintk(2, KERN_WARNING "%s: irq loop %d\n",
+				ZR_DEVNAME(zr), count);
+			if (count > 20) {
+				btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
+				dprintk(2,
+					KERN_ERR
+					"%s: IRQ lockup, cleared int mask\n",
+					ZR_DEVNAME(zr));
+				break;
+			}
+		}
+		zr->last_isr = stat;
+	}
+	spin_unlock_irqrestore(&zr->spinlock, flags);
+
+	return IRQ_HANDLED;
+}
+
+void
+zoran_set_pci_master (struct zoran *zr,
+		      int           set_master)
+{
+	if (set_master) {
+		pci_set_master(zr->pci_dev);
+	} else {
+		u16 command;
+
+		pci_read_config_word(zr->pci_dev, PCI_COMMAND, &command);
+		command &= ~PCI_COMMAND_MASTER;
+		pci_write_config_word(zr->pci_dev, PCI_COMMAND, command);
+	}
+}
+
+void
+zoran_init_hardware (struct zoran *zr)
+{
+	/* Enable bus-mastering */
+	zoran_set_pci_master(zr, 1);
+
+	/* Initialize the board */
+	if (zr->card.init) {
+		zr->card.init(zr);
+	}
+
+	decoder_call(zr, core, init, 0);
+	decoder_call(zr, core, s_std, zr->norm);
+	decoder_call(zr, video, s_routing,
+		zr->card.input[zr->input].muxsel, 0, 0);
+
+	encoder_call(zr, core, init, 0);
+	encoder_call(zr, video, s_std_output, zr->norm);
+	encoder_call(zr, video, s_routing, 0, 0, 0);
+
+	/* toggle JPEG codec sleep to sync PLL */
+	jpeg_codec_sleep(zr, 1);
+	jpeg_codec_sleep(zr, 0);
+
+	/* set individual interrupt enables (without GIRQ1)
+	 * but don't global enable until zoran_open() */
+
+	//btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ1, ZR36057_ICR);  // SW
+	// It looks like using only JPEGRepIRQEn is not always reliable,
+	// may be when JPEG codec crashes it won't generate IRQ? So,
+	 /*CP*/			//        btwrite(IRQ_MASK, ZR36057_ICR); // Enable Vsync interrupts too. SM    WHY ? LP
+	    zr36057_init_vfe(zr);
+
+	zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+
+	btwrite(IRQ_MASK, ZR36057_ISR);	// Clears interrupts
+}
+
+void
+zr36057_restart (struct zoran *zr)
+{
+	btwrite(0, ZR36057_SPGPPCR);
+	mdelay(1);
+	btor(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR);
+	mdelay(1);
+
+	/* assert P_Reset */
+	btwrite(0, ZR36057_JPC);
+	/* set up GPIO direction - all output */
+	btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR);
+
+	/* set up GPIO pins and guest bus timing */
+	btwrite((0x81 << 24) | 0x8888, ZR36057_GPPGCR1);
+}
+
+/*
+ * initialize video front end
+ */
+
+static void
+zr36057_init_vfe (struct zoran *zr)
+{
+	u32 reg;
+
+	reg = btread(ZR36057_VFESPFR);
+	reg |= ZR36057_VFESPFR_LittleEndian;
+	reg &= ~ZR36057_VFESPFR_VCLKPol;
+	reg |= ZR36057_VFESPFR_ExtFl;
+	reg |= ZR36057_VFESPFR_TopField;
+	btwrite(reg, ZR36057_VFESPFR);
+	reg = btread(ZR36057_VDCR);
+	if (pci_pci_problems & PCIPCI_TRITON)
+		// || zr->revision < 1) // Revision 1 has also Triton support
+		reg &= ~ZR36057_VDCR_Triton;
+	else
+		reg |= ZR36057_VDCR_Triton;
+	btwrite(reg, ZR36057_VDCR);
+}
diff --git a/drivers/media/pci/zoran/zoran_device.h b/drivers/media/pci/zoran/zoran_device.h
new file mode 100644
index 0000000..07f2c23
--- /dev/null
+++ b/drivers/media/pci/zoran/zoran_device.h
@@ -0,0 +1,95 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * This part handles card-specific data and detection
+ *
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Currently maintained by:
+ *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
+ *   Laurent Pinchart <laurent.pinchart@skynet.be>
+ *   Mailinglist      <mjpeg-users@lists.sf.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ZORAN_DEVICE_H__
+#define __ZORAN_DEVICE_H__
+
+/* general purpose I/O */
+extern void GPIO(struct zoran *zr,
+		 int bit,
+		 unsigned int value);
+
+/* codec (or actually: guest bus) access */
+extern int post_office_wait(struct zoran *zr);
+extern int post_office_write(struct zoran *zr,
+			     unsigned guest,
+			     unsigned reg,
+			     unsigned value);
+extern int post_office_read(struct zoran *zr,
+			    unsigned guest,
+			    unsigned reg);
+
+extern void detect_guest_activity(struct zoran *zr);
+
+extern void jpeg_codec_sleep(struct zoran *zr,
+			     int sleep);
+extern int jpeg_codec_reset(struct zoran *zr);
+
+/* zr360x7 access to raw capture */
+extern void zr36057_overlay(struct zoran *zr,
+			    int on);
+extern void write_overlay_mask(struct zoran_fh *fh,
+			       struct v4l2_clip *vp,
+			       int count);
+extern void zr36057_set_memgrab(struct zoran *zr,
+				int mode);
+extern int wait_grab_pending(struct zoran *zr);
+
+/* interrupts */
+extern void print_interrupts(struct zoran *zr);
+extern void clear_interrupt_counters(struct zoran *zr);
+extern irqreturn_t zoran_irq(int irq, void *dev_id);
+
+/* JPEG codec access */
+extern void jpeg_start(struct zoran *zr);
+extern void zr36057_enable_jpg(struct zoran *zr,
+			       enum zoran_codec_mode mode);
+extern void zoran_feed_stat_com(struct zoran *zr);
+
+/* general */
+extern void zoran_set_pci_master(struct zoran *zr,
+				 int set_master);
+extern void zoran_init_hardware(struct zoran *zr);
+extern void zr36057_restart(struct zoran *zr);
+
+extern const struct zoran_format zoran_formats[];
+
+extern int v4l_nbufs;
+extern int v4l_bufsize;
+extern int jpg_nbufs;
+extern int jpg_bufsize;
+extern int pass_through;
+
+/* i2c */
+#define decoder_call(zr, o, f, args...) \
+	v4l2_subdev_call(zr->decoder, o, f, ##args)
+#define encoder_call(zr, o, f, args...) \
+	v4l2_subdev_call(zr->encoder, o, f, ##args)
+
+#endif				/* __ZORAN_DEVICE_H__ */
diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c
new file mode 100644
index 0000000..c6ccdeb
--- /dev/null
+++ b/drivers/media/pci/zoran/zoran_driver.c
@@ -0,0 +1,3090 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Changes for BUZ by Wolfgang Scherr <scherr@net4you.net>
+ *
+ * Changes for DC10/DC30 by Laurent Pinchart <laurent.pinchart@skynet.be>
+ *
+ * Changes for LML33R10 by Maxim Yevtyushkin <max@linuxmedialabs.com>
+ *
+ * Changes for videodev2/v4l2 by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * Based on
+ *
+ * Miro DC10 driver
+ * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
+ *
+ * Iomega Buz driver version 1.0
+ * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
+ *
+ * buz.0.0.3
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ *
+ * bttv - Bt848 frame grabber driver
+ * Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+ *                        & Marcus Metzler (mocm@thp.uni-koeln.de)
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include <linux/spinlock.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include "videocodec.h"
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+
+#include <linux/mutex.h>
+#include "zoran.h"
+#include "zoran_device.h"
+#include "zoran_card.h"
+
+
+const struct zoran_format zoran_formats[] = {
+	{
+		.name = "15-bit RGB LE",
+		.fourcc = V4L2_PIX_FMT_RGB555,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.depth = 15,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif|
+			   ZR36057_VFESPFR_LittleEndian,
+	}, {
+		.name = "15-bit RGB BE",
+		.fourcc = V4L2_PIX_FMT_RGB555X,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.depth = 15,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif,
+	}, {
+		.name = "16-bit RGB LE",
+		.fourcc = V4L2_PIX_FMT_RGB565,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.depth = 16,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif|
+			   ZR36057_VFESPFR_LittleEndian,
+	}, {
+		.name = "16-bit RGB BE",
+		.fourcc = V4L2_PIX_FMT_RGB565X,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.depth = 16,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif,
+	}, {
+		.name = "24-bit RGB",
+		.fourcc = V4L2_PIX_FMT_BGR24,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.depth = 24,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_Pack24,
+	}, {
+		.name = "32-bit RGB LE",
+		.fourcc = V4L2_PIX_FMT_BGR32,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.depth = 32,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_LittleEndian,
+	}, {
+		.name = "32-bit RGB BE",
+		.fourcc = V4L2_PIX_FMT_RGB32,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.depth = 32,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB888,
+	}, {
+		.name = "4:2:2, packed, YUYV",
+		.fourcc = V4L2_PIX_FMT_YUYV,
+		.colorspace = V4L2_COLORSPACE_SMPTE170M,
+		.depth = 16,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_YUV422,
+	}, {
+		.name = "4:2:2, packed, UYVY",
+		.fourcc = V4L2_PIX_FMT_UYVY,
+		.colorspace = V4L2_COLORSPACE_SMPTE170M,
+		.depth = 16,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_YUV422|ZR36057_VFESPFR_LittleEndian,
+	}, {
+		.name = "Hardware-encoded Motion-JPEG",
+		.fourcc = V4L2_PIX_FMT_MJPEG,
+		.colorspace = V4L2_COLORSPACE_SMPTE170M,
+		.depth = 0,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_PLAYBACK |
+			 ZORAN_FORMAT_COMPRESSED,
+	}
+};
+#define NUM_FORMATS ARRAY_SIZE(zoran_formats)
+
+	/* small helper function for calculating buffersizes for v4l2
+	 * we calculate the nearest higher power-of-two, which
+	 * will be the recommended buffersize */
+static __u32
+zoran_v4l2_calc_bufsize (struct zoran_jpg_settings *settings)
+{
+	__u8 div = settings->VerDcm * settings->HorDcm * settings->TmpDcm;
+	__u32 num = (1024 * 512) / (div);
+	__u32 result = 2;
+
+	num--;
+	while (num) {
+		num >>= 1;
+		result <<= 1;
+	}
+
+	if (result > jpg_bufsize)
+		return jpg_bufsize;
+	if (result < 8192)
+		return 8192;
+	return result;
+}
+
+/* forward references */
+static void v4l_fbuffer_free(struct zoran_fh *fh);
+static void jpg_fbuffer_free(struct zoran_fh *fh);
+
+/* Set mapping mode */
+static void map_mode_raw(struct zoran_fh *fh)
+{
+	fh->map_mode = ZORAN_MAP_MODE_RAW;
+	fh->buffers.buffer_size = v4l_bufsize;
+	fh->buffers.num_buffers = v4l_nbufs;
+}
+static void map_mode_jpg(struct zoran_fh *fh, int play)
+{
+	fh->map_mode = play ? ZORAN_MAP_MODE_JPG_PLAY : ZORAN_MAP_MODE_JPG_REC;
+	fh->buffers.buffer_size = jpg_bufsize;
+	fh->buffers.num_buffers = jpg_nbufs;
+}
+static inline const char *mode_name(enum zoran_map_mode mode)
+{
+	return mode == ZORAN_MAP_MODE_RAW ? "V4L" : "JPG";
+}
+
+/*
+ *   Allocate the V4L grab buffers
+ *
+ *   These have to be pysically contiguous.
+ */
+
+static int v4l_fbuffer_alloc(struct zoran_fh *fh)
+{
+	struct zoran *zr = fh->zr;
+	int i, off;
+	unsigned char *mem;
+
+	for (i = 0; i < fh->buffers.num_buffers; i++) {
+		if (fh->buffers.buffer[i].v4l.fbuffer)
+			dprintk(2,
+				KERN_WARNING
+				"%s: %s - buffer %d already allocated!?\n",
+				ZR_DEVNAME(zr), __func__, i);
+
+		//udelay(20);
+		mem = kmalloc(fh->buffers.buffer_size,
+			      GFP_KERNEL | __GFP_NOWARN);
+		if (!mem) {
+			dprintk(1,
+				KERN_ERR
+				"%s: %s - kmalloc for V4L buf %d failed\n",
+				ZR_DEVNAME(zr), __func__, i);
+			v4l_fbuffer_free(fh);
+			return -ENOBUFS;
+		}
+		fh->buffers.buffer[i].v4l.fbuffer = mem;
+		fh->buffers.buffer[i].v4l.fbuffer_phys = virt_to_phys(mem);
+		fh->buffers.buffer[i].v4l.fbuffer_bus = virt_to_bus(mem);
+		for (off = 0; off < fh->buffers.buffer_size;
+		     off += PAGE_SIZE)
+			SetPageReserved(virt_to_page(mem + off));
+		dprintk(4,
+			KERN_INFO
+			"%s: %s - V4L frame %d mem 0x%lx (bus: 0x%llx)\n",
+			ZR_DEVNAME(zr), __func__, i, (unsigned long) mem,
+			(unsigned long long)virt_to_bus(mem));
+	}
+
+	fh->buffers.allocated = 1;
+
+	return 0;
+}
+
+/* free the V4L grab buffers */
+static void v4l_fbuffer_free(struct zoran_fh *fh)
+{
+	struct zoran *zr = fh->zr;
+	int i, off;
+	unsigned char *mem;
+
+	dprintk(4, KERN_INFO "%s: %s\n", ZR_DEVNAME(zr), __func__);
+
+	for (i = 0; i < fh->buffers.num_buffers; i++) {
+		if (!fh->buffers.buffer[i].v4l.fbuffer)
+			continue;
+
+		mem = fh->buffers.buffer[i].v4l.fbuffer;
+		for (off = 0; off < fh->buffers.buffer_size;
+		     off += PAGE_SIZE)
+			ClearPageReserved(virt_to_page(mem + off));
+		kfree(fh->buffers.buffer[i].v4l.fbuffer);
+		fh->buffers.buffer[i].v4l.fbuffer = NULL;
+	}
+
+	fh->buffers.allocated = 0;
+}
+
+/*
+ *   Allocate the MJPEG grab buffers.
+ *
+ *   If a Natoma chipset is present and this is a revision 1 zr36057,
+ *   each MJPEG buffer needs to be physically contiguous.
+ *   (RJ: This statement is from Dave Perks' original driver,
+ *   I could never check it because I have a zr36067)
+ *
+ *   RJ: The contents grab buffers needs never be accessed in the driver.
+ *       Therefore there is no need to allocate them with vmalloc in order
+ *       to get a contiguous virtual memory space.
+ *       I don't understand why many other drivers first allocate them with
+ *       vmalloc (which uses internally also get_zeroed_page, but delivers you
+ *       virtual addresses) and then again have to make a lot of efforts
+ *       to get the physical address.
+ *
+ *   Ben Capper:
+ *       On big-endian architectures (such as ppc) some extra steps
+ *       are needed. When reading and writing to the stat_com array
+ *       and fragment buffers, the device expects to see little-
+ *       endian values. The use of cpu_to_le32() and le32_to_cpu()
+ *       in this function (and one or two others in zoran_device.c)
+ *       ensure that these values are always stored in little-endian
+ *       form, regardless of architecture. The zr36057 does Very Bad
+ *       Things on big endian architectures if the stat_com array
+ *       and fragment buffers are not little-endian.
+ */
+
+static int jpg_fbuffer_alloc(struct zoran_fh *fh)
+{
+	struct zoran *zr = fh->zr;
+	int i, j, off;
+	u8 *mem;
+
+	for (i = 0; i < fh->buffers.num_buffers; i++) {
+		if (fh->buffers.buffer[i].jpg.frag_tab)
+			dprintk(2,
+				KERN_WARNING
+				"%s: %s - buffer %d already allocated!?\n",
+				ZR_DEVNAME(zr), __func__, i);
+
+		/* Allocate fragment table for this buffer */
+
+		mem = (void *)get_zeroed_page(GFP_KERNEL);
+		if (!mem) {
+			dprintk(1,
+				KERN_ERR
+				"%s: %s - get_zeroed_page (frag_tab) failed for buffer %d\n",
+				ZR_DEVNAME(zr), __func__, i);
+			jpg_fbuffer_free(fh);
+			return -ENOBUFS;
+		}
+		fh->buffers.buffer[i].jpg.frag_tab = (__le32 *)mem;
+		fh->buffers.buffer[i].jpg.frag_tab_bus = virt_to_bus(mem);
+
+		if (fh->buffers.need_contiguous) {
+			mem = kmalloc(fh->buffers.buffer_size, GFP_KERNEL);
+			if (mem == NULL) {
+				dprintk(1,
+					KERN_ERR
+					"%s: %s - kmalloc failed for buffer %d\n",
+					ZR_DEVNAME(zr), __func__, i);
+				jpg_fbuffer_free(fh);
+				return -ENOBUFS;
+			}
+			fh->buffers.buffer[i].jpg.frag_tab[0] =
+				cpu_to_le32(virt_to_bus(mem));
+			fh->buffers.buffer[i].jpg.frag_tab[1] =
+				cpu_to_le32((fh->buffers.buffer_size >> 1) | 1);
+			for (off = 0; off < fh->buffers.buffer_size; off += PAGE_SIZE)
+				SetPageReserved(virt_to_page(mem + off));
+		} else {
+			/* jpg_bufsize is already page aligned */
+			for (j = 0; j < fh->buffers.buffer_size / PAGE_SIZE; j++) {
+				mem = (void *)get_zeroed_page(GFP_KERNEL);
+				if (mem == NULL) {
+					dprintk(1,
+						KERN_ERR
+						"%s: %s - get_zeroed_page failed for buffer %d\n",
+						ZR_DEVNAME(zr), __func__, i);
+					jpg_fbuffer_free(fh);
+					return -ENOBUFS;
+				}
+
+				fh->buffers.buffer[i].jpg.frag_tab[2 * j] =
+					cpu_to_le32(virt_to_bus(mem));
+				fh->buffers.buffer[i].jpg.frag_tab[2 * j + 1] =
+					cpu_to_le32((PAGE_SIZE >> 2) << 1);
+				SetPageReserved(virt_to_page(mem));
+			}
+
+			fh->buffers.buffer[i].jpg.frag_tab[2 * j - 1] |= cpu_to_le32(1);
+		}
+	}
+
+	dprintk(4,
+		KERN_DEBUG "%s: %s - %d KB allocated\n",
+		ZR_DEVNAME(zr), __func__,
+		(fh->buffers.num_buffers * fh->buffers.buffer_size) >> 10);
+
+	fh->buffers.allocated = 1;
+
+	return 0;
+}
+
+/* free the MJPEG grab buffers */
+static void jpg_fbuffer_free(struct zoran_fh *fh)
+{
+	struct zoran *zr = fh->zr;
+	int i, j, off;
+	unsigned char *mem;
+	__le32 frag_tab;
+	struct zoran_buffer *buffer;
+
+	dprintk(4, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
+
+	for (i = 0, buffer = &fh->buffers.buffer[0];
+	     i < fh->buffers.num_buffers; i++, buffer++) {
+		if (!buffer->jpg.frag_tab)
+			continue;
+
+		if (fh->buffers.need_contiguous) {
+			frag_tab = buffer->jpg.frag_tab[0];
+
+			if (frag_tab) {
+				mem = bus_to_virt(le32_to_cpu(frag_tab));
+				for (off = 0; off < fh->buffers.buffer_size; off += PAGE_SIZE)
+					ClearPageReserved(virt_to_page(mem + off));
+				kfree(mem);
+				buffer->jpg.frag_tab[0] = 0;
+				buffer->jpg.frag_tab[1] = 0;
+			}
+		} else {
+			for (j = 0; j < fh->buffers.buffer_size / PAGE_SIZE; j++) {
+				frag_tab = buffer->jpg.frag_tab[2 * j];
+
+				if (!frag_tab)
+					break;
+				ClearPageReserved(virt_to_page(bus_to_virt(le32_to_cpu(frag_tab))));
+				free_page((unsigned long)bus_to_virt(le32_to_cpu(frag_tab)));
+				buffer->jpg.frag_tab[2 * j] = 0;
+				buffer->jpg.frag_tab[2 * j + 1] = 0;
+			}
+		}
+
+		free_page((unsigned long)buffer->jpg.frag_tab);
+		buffer->jpg.frag_tab = NULL;
+	}
+
+	fh->buffers.allocated = 0;
+}
+
+/*
+ *   V4L Buffer grabbing
+ */
+
+static int
+zoran_v4l_set_format (struct zoran_fh           *fh,
+		      int                        width,
+		      int                        height,
+		      const struct zoran_format *format)
+{
+	struct zoran *zr = fh->zr;
+	int bpp;
+
+	/* Check size and format of the grab wanted */
+
+	if (height < BUZ_MIN_HEIGHT || width < BUZ_MIN_WIDTH ||
+	    height > BUZ_MAX_HEIGHT || width > BUZ_MAX_WIDTH) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - wrong frame size (%dx%d)\n",
+			ZR_DEVNAME(zr), __func__, width, height);
+		return -EINVAL;
+	}
+
+	bpp = (format->depth + 7) / 8;
+
+	/* Check against available buffer size */
+	if (height * width * bpp > fh->buffers.buffer_size) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - video buffer size (%d kB) is too small\n",
+			ZR_DEVNAME(zr), __func__, fh->buffers.buffer_size >> 10);
+		return -EINVAL;
+	}
+
+	/* The video front end needs 4-byte alinged line sizes */
+
+	if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - wrong frame alignment\n",
+			ZR_DEVNAME(zr), __func__);
+		return -EINVAL;
+	}
+
+	fh->v4l_settings.width = width;
+	fh->v4l_settings.height = height;
+	fh->v4l_settings.format = format;
+	fh->v4l_settings.bytesperline = bpp * fh->v4l_settings.width;
+
+	return 0;
+}
+
+static int zoran_v4l_queue_frame(struct zoran_fh *fh, int num)
+{
+	struct zoran *zr = fh->zr;
+	unsigned long flags;
+	int res = 0;
+
+	if (!fh->buffers.allocated) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - buffers not yet allocated\n",
+			ZR_DEVNAME(zr), __func__);
+		res = -ENOMEM;
+	}
+
+	/* No grabbing outside the buffer range! */
+	if (num >= fh->buffers.num_buffers || num < 0) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - buffer %d is out of range\n",
+			ZR_DEVNAME(zr), __func__, num);
+		res = -EINVAL;
+	}
+
+	spin_lock_irqsave(&zr->spinlock, flags);
+
+	if (fh->buffers.active == ZORAN_FREE) {
+		if (zr->v4l_buffers.active == ZORAN_FREE) {
+			zr->v4l_buffers = fh->buffers;
+			fh->buffers.active = ZORAN_ACTIVE;
+		} else {
+			dprintk(1,
+				KERN_ERR
+				"%s: %s - another session is already capturing\n",
+				ZR_DEVNAME(zr), __func__);
+			res = -EBUSY;
+		}
+	}
+
+	/* make sure a grab isn't going on currently with this buffer */
+	if (!res) {
+		switch (zr->v4l_buffers.buffer[num].state) {
+		default:
+		case BUZ_STATE_PEND:
+			if (zr->v4l_buffers.active == ZORAN_FREE) {
+				fh->buffers.active = ZORAN_FREE;
+				zr->v4l_buffers.allocated = 0;
+			}
+			res = -EBUSY;	/* what are you doing? */
+			break;
+		case BUZ_STATE_DONE:
+			dprintk(2,
+				KERN_WARNING
+				"%s: %s - queueing buffer %d in state DONE!?\n",
+				ZR_DEVNAME(zr), __func__, num);
+		case BUZ_STATE_USER:
+			/* since there is at least one unused buffer there's room for at least
+			 * one more pend[] entry */
+			zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = num;
+			zr->v4l_buffers.buffer[num].state = BUZ_STATE_PEND;
+			zr->v4l_buffers.buffer[num].bs.length =
+			    fh->v4l_settings.bytesperline *
+			    zr->v4l_settings.height;
+			fh->buffers.buffer[num] = zr->v4l_buffers.buffer[num];
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&zr->spinlock, flags);
+
+	if (!res && zr->v4l_buffers.active == ZORAN_FREE)
+		zr->v4l_buffers.active = fh->buffers.active;
+
+	return res;
+}
+
+/*
+ * Sync on a V4L buffer
+ */
+
+static int v4l_sync(struct zoran_fh *fh, int frame)
+{
+	struct zoran *zr = fh->zr;
+	unsigned long flags;
+
+	if (fh->buffers.active == ZORAN_FREE) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - no grab active for this session\n",
+			ZR_DEVNAME(zr), __func__);
+		return -EINVAL;
+	}
+
+	/* check passed-in frame number */
+	if (frame >= fh->buffers.num_buffers || frame < 0) {
+		dprintk(1,
+			KERN_ERR "%s: %s - frame %d is invalid\n",
+			ZR_DEVNAME(zr), __func__, frame);
+		return -EINVAL;
+	}
+
+	/* Check if is buffer was queued at all */
+	if (zr->v4l_buffers.buffer[frame].state == BUZ_STATE_USER) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - attempt to sync on a buffer which was not queued?\n",
+			ZR_DEVNAME(zr), __func__);
+		return -EPROTO;
+	}
+
+	/* wait on this buffer to get ready */
+	if (!wait_event_interruptible_timeout(zr->v4l_capq,
+		(zr->v4l_buffers.buffer[frame].state != BUZ_STATE_PEND), 10*HZ))
+		return -ETIME;
+	if (signal_pending(current))
+		return -ERESTARTSYS;
+
+	/* buffer should now be in BUZ_STATE_DONE */
+	if (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_DONE)
+		dprintk(2,
+			KERN_ERR "%s: %s - internal state error\n",
+			ZR_DEVNAME(zr), __func__);
+
+	zr->v4l_buffers.buffer[frame].state = BUZ_STATE_USER;
+	fh->buffers.buffer[frame] = zr->v4l_buffers.buffer[frame];
+
+	spin_lock_irqsave(&zr->spinlock, flags);
+
+	/* Check if streaming capture has finished */
+	if (zr->v4l_pend_tail == zr->v4l_pend_head) {
+		zr36057_set_memgrab(zr, 0);
+		if (zr->v4l_buffers.active == ZORAN_ACTIVE) {
+			fh->buffers.active = zr->v4l_buffers.active = ZORAN_FREE;
+			zr->v4l_buffers.allocated = 0;
+		}
+	}
+
+	spin_unlock_irqrestore(&zr->spinlock, flags);
+
+	return 0;
+}
+
+/*
+ *   Queue a MJPEG buffer for capture/playback
+ */
+
+static int zoran_jpg_queue_frame(struct zoran_fh *fh, int num,
+				 enum zoran_codec_mode mode)
+{
+	struct zoran *zr = fh->zr;
+	unsigned long flags;
+	int res = 0;
+
+	/* Check if buffers are allocated */
+	if (!fh->buffers.allocated) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - buffers not yet allocated\n",
+			ZR_DEVNAME(zr), __func__);
+		return -ENOMEM;
+	}
+
+	/* No grabbing outside the buffer range! */
+	if (num >= fh->buffers.num_buffers || num < 0) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - buffer %d out of range\n",
+			ZR_DEVNAME(zr), __func__, num);
+		return -EINVAL;
+	}
+
+	/* what is the codec mode right now? */
+	if (zr->codec_mode == BUZ_MODE_IDLE) {
+		zr->jpg_settings = fh->jpg_settings;
+	} else if (zr->codec_mode != mode) {
+		/* wrong codec mode active - invalid */
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - codec in wrong mode\n",
+			ZR_DEVNAME(zr), __func__);
+		return -EINVAL;
+	}
+
+	if (fh->buffers.active == ZORAN_FREE) {
+		if (zr->jpg_buffers.active == ZORAN_FREE) {
+			zr->jpg_buffers = fh->buffers;
+			fh->buffers.active = ZORAN_ACTIVE;
+		} else {
+			dprintk(1,
+				KERN_ERR
+				"%s: %s - another session is already capturing\n",
+				ZR_DEVNAME(zr), __func__);
+			res = -EBUSY;
+		}
+	}
+
+	if (!res && zr->codec_mode == BUZ_MODE_IDLE) {
+		/* Ok load up the jpeg codec */
+		zr36057_enable_jpg(zr, mode);
+	}
+
+	spin_lock_irqsave(&zr->spinlock, flags);
+
+	if (!res) {
+		switch (zr->jpg_buffers.buffer[num].state) {
+		case BUZ_STATE_DONE:
+			dprintk(2,
+				KERN_WARNING
+				"%s: %s - queing frame in BUZ_STATE_DONE state!?\n",
+				ZR_DEVNAME(zr), __func__);
+		case BUZ_STATE_USER:
+			/* since there is at least one unused buffer there's room for at
+			 *least one more pend[] entry */
+			zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = num;
+			zr->jpg_buffers.buffer[num].state = BUZ_STATE_PEND;
+			fh->buffers.buffer[num] = zr->jpg_buffers.buffer[num];
+			zoran_feed_stat_com(zr);
+			break;
+		default:
+		case BUZ_STATE_DMA:
+		case BUZ_STATE_PEND:
+			if (zr->jpg_buffers.active == ZORAN_FREE) {
+				fh->buffers.active = ZORAN_FREE;
+				zr->jpg_buffers.allocated = 0;
+			}
+			res = -EBUSY;	/* what are you doing? */
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&zr->spinlock, flags);
+
+	if (!res && zr->jpg_buffers.active == ZORAN_FREE)
+		zr->jpg_buffers.active = fh->buffers.active;
+
+	return res;
+}
+
+static int jpg_qbuf(struct zoran_fh *fh, int frame, enum zoran_codec_mode mode)
+{
+	struct zoran *zr = fh->zr;
+	int res = 0;
+
+	/* Does the user want to stop streaming? */
+	if (frame < 0) {
+		if (zr->codec_mode == mode) {
+			if (fh->buffers.active == ZORAN_FREE) {
+				dprintk(1,
+					KERN_ERR
+					"%s: %s(-1) - session not active\n",
+					ZR_DEVNAME(zr), __func__);
+				return -EINVAL;
+			}
+			fh->buffers.active = zr->jpg_buffers.active = ZORAN_FREE;
+			zr->jpg_buffers.allocated = 0;
+			zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+			return 0;
+		} else {
+			dprintk(1,
+				KERN_ERR
+				"%s: %s - stop streaming but not in streaming mode\n",
+				ZR_DEVNAME(zr), __func__);
+			return -EINVAL;
+		}
+	}
+
+	if ((res = zoran_jpg_queue_frame(fh, frame, mode)))
+		return res;
+
+	/* Start the jpeg codec when the first frame is queued  */
+	if (!res && zr->jpg_que_head == 1)
+		jpeg_start(zr);
+
+	return res;
+}
+
+/*
+ *   Sync on a MJPEG buffer
+ */
+
+static int jpg_sync(struct zoran_fh *fh, struct zoran_sync *bs)
+{
+	struct zoran *zr = fh->zr;
+	unsigned long flags;
+	int frame;
+
+	if (fh->buffers.active == ZORAN_FREE) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - capture is not currently active\n",
+			ZR_DEVNAME(zr), __func__);
+		return -EINVAL;
+	}
+	if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS &&
+	    zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - codec not in streaming mode\n",
+			ZR_DEVNAME(zr), __func__);
+		return -EINVAL;
+	}
+	if (!wait_event_interruptible_timeout(zr->jpg_capq,
+			(zr->jpg_que_tail != zr->jpg_dma_tail ||
+			 zr->jpg_dma_tail == zr->jpg_dma_head),
+			10*HZ)) {
+		int isr;
+
+		btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
+		udelay(1);
+		zr->codec->control(zr->codec, CODEC_G_STATUS,
+					   sizeof(isr), &isr);
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - timeout: codec isr=0x%02x\n",
+			ZR_DEVNAME(zr), __func__, isr);
+
+		return -ETIME;
+
+	}
+	if (signal_pending(current))
+		return -ERESTARTSYS;
+
+	spin_lock_irqsave(&zr->spinlock, flags);
+
+	if (zr->jpg_dma_tail != zr->jpg_dma_head)
+		frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME];
+	else
+		frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
+
+	/* buffer should now be in BUZ_STATE_DONE */
+	if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE)
+		dprintk(2,
+			KERN_ERR "%s: %s - internal state error\n",
+			ZR_DEVNAME(zr), __func__);
+
+	*bs = zr->jpg_buffers.buffer[frame].bs;
+	bs->frame = frame;
+	zr->jpg_buffers.buffer[frame].state = BUZ_STATE_USER;
+	fh->buffers.buffer[frame] = zr->jpg_buffers.buffer[frame];
+
+	spin_unlock_irqrestore(&zr->spinlock, flags);
+
+	return 0;
+}
+
+static void zoran_open_init_session(struct zoran_fh *fh)
+{
+	int i;
+	struct zoran *zr = fh->zr;
+
+	/* Per default, map the V4L Buffers */
+	map_mode_raw(fh);
+
+	/* take over the card's current settings */
+	fh->overlay_settings = zr->overlay_settings;
+	fh->overlay_settings.is_set = 0;
+	fh->overlay_settings.format = zr->overlay_settings.format;
+	fh->overlay_active = ZORAN_FREE;
+
+	/* v4l settings */
+	fh->v4l_settings = zr->v4l_settings;
+	/* jpg settings */
+	fh->jpg_settings = zr->jpg_settings;
+
+	/* buffers */
+	memset(&fh->buffers, 0, sizeof(fh->buffers));
+	for (i = 0; i < MAX_FRAME; i++) {
+		fh->buffers.buffer[i].state = BUZ_STATE_USER;	/* nothing going on */
+		fh->buffers.buffer[i].bs.frame = i;
+	}
+	fh->buffers.allocated = 0;
+	fh->buffers.active = ZORAN_FREE;
+}
+
+static void zoran_close_end_session(struct zoran_fh *fh)
+{
+	struct zoran *zr = fh->zr;
+
+	/* overlay */
+	if (fh->overlay_active != ZORAN_FREE) {
+		fh->overlay_active = zr->overlay_active = ZORAN_FREE;
+		zr->v4l_overlay_active = 0;
+		if (!zr->v4l_memgrab_active)
+			zr36057_overlay(zr, 0);
+		zr->overlay_mask = NULL;
+	}
+
+	if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
+		/* v4l capture */
+		if (fh->buffers.active != ZORAN_FREE) {
+			unsigned long flags;
+
+			spin_lock_irqsave(&zr->spinlock, flags);
+			zr36057_set_memgrab(zr, 0);
+			zr->v4l_buffers.allocated = 0;
+			zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE;
+			spin_unlock_irqrestore(&zr->spinlock, flags);
+		}
+
+		/* v4l buffers */
+		if (fh->buffers.allocated)
+			v4l_fbuffer_free(fh);
+	} else {
+		/* jpg capture */
+		if (fh->buffers.active != ZORAN_FREE) {
+			zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+			zr->jpg_buffers.allocated = 0;
+			zr->jpg_buffers.active = fh->buffers.active = ZORAN_FREE;
+		}
+
+		/* jpg buffers */
+		if (fh->buffers.allocated)
+			jpg_fbuffer_free(fh);
+	}
+}
+
+/*
+ *   Open a zoran card. Right now the flags stuff is just playing
+ */
+
+static int zoran_open(struct file *file)
+{
+	struct zoran *zr = video_drvdata(file);
+	struct zoran_fh *fh;
+	int res, first_open = 0;
+
+	dprintk(2, KERN_INFO "%s: %s(%s, pid=[%d]), users(-)=%d\n",
+		ZR_DEVNAME(zr), __func__, current->comm, task_pid_nr(current), zr->user + 1);
+
+	mutex_lock(&zr->other_lock);
+
+	if (zr->user >= 2048) {
+		dprintk(1, KERN_ERR "%s: too many users (%d) on device\n",
+			ZR_DEVNAME(zr), zr->user);
+		res = -EBUSY;
+		goto fail_unlock;
+	}
+
+	/* now, create the open()-specific file_ops struct */
+	fh = kzalloc(sizeof(struct zoran_fh), GFP_KERNEL);
+	if (!fh) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - allocation of zoran_fh failed\n",
+			ZR_DEVNAME(zr), __func__);
+		res = -ENOMEM;
+		goto fail_unlock;
+	}
+	/* used to be BUZ_MAX_WIDTH/HEIGHT, but that gives overflows
+	 * on norm-change! */
+	fh->overlay_mask =
+	    kmalloc(((768 + 31) / 32) * 576 * 4, GFP_KERNEL);
+	if (!fh->overlay_mask) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - allocation of overlay_mask failed\n",
+			ZR_DEVNAME(zr), __func__);
+		res = -ENOMEM;
+		goto fail_fh;
+	}
+
+	if (zr->user++ == 0)
+		first_open = 1;
+
+	/*mutex_unlock(&zr->resource_lock);*/
+
+	/* default setup - TODO: look at flags */
+	if (first_open) {	/* First device open */
+		zr36057_restart(zr);
+		zoran_open_init_params(zr);
+		zoran_init_hardware(zr);
+
+		btor(ZR36057_ICR_IntPinEn, ZR36057_ICR);
+	}
+
+	/* set file_ops stuff */
+	file->private_data = fh;
+	fh->zr = zr;
+	zoran_open_init_session(fh);
+	mutex_unlock(&zr->other_lock);
+
+	return 0;
+
+fail_fh:
+	kfree(fh);
+fail_unlock:
+	mutex_unlock(&zr->other_lock);
+
+	dprintk(2, KERN_INFO "%s: open failed (%d), users(-)=%d\n",
+		ZR_DEVNAME(zr), res, zr->user);
+
+	return res;
+}
+
+static int
+zoran_close(struct file  *file)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+
+	dprintk(2, KERN_INFO "%s: %s(%s, pid=[%d]), users(+)=%d\n",
+		ZR_DEVNAME(zr), __func__, current->comm, task_pid_nr(current), zr->user - 1);
+
+	/* kernel locks (fs/device.c), so don't do that ourselves
+	 * (prevents deadlocks) */
+	mutex_lock(&zr->other_lock);
+
+	zoran_close_end_session(fh);
+
+	if (zr->user-- == 1) {	/* Last process */
+		/* Clean up JPEG process */
+		wake_up_interruptible(&zr->jpg_capq);
+		zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+		zr->jpg_buffers.allocated = 0;
+		zr->jpg_buffers.active = ZORAN_FREE;
+
+		/* disable interrupts */
+		btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
+
+		if (zr36067_debug > 1)
+			print_interrupts(zr);
+
+		/* Overlay off */
+		zr->v4l_overlay_active = 0;
+		zr36057_overlay(zr, 0);
+		zr->overlay_mask = NULL;
+
+		/* capture off */
+		wake_up_interruptible(&zr->v4l_capq);
+		zr36057_set_memgrab(zr, 0);
+		zr->v4l_buffers.allocated = 0;
+		zr->v4l_buffers.active = ZORAN_FREE;
+		zoran_set_pci_master(zr, 0);
+
+		if (!pass_through) {	/* Switch to color bar */
+			decoder_call(zr, video, s_stream, 0);
+			encoder_call(zr, video, s_routing, 2, 0, 0);
+		}
+	}
+	mutex_unlock(&zr->other_lock);
+
+	file->private_data = NULL;
+	kfree(fh->overlay_mask);
+	kfree(fh);
+
+	dprintk(4, KERN_INFO "%s: %s done\n", ZR_DEVNAME(zr), __func__);
+
+	return 0;
+}
+
+
+static ssize_t
+zoran_read (struct file *file,
+	    char        __user *data,
+	    size_t       count,
+	    loff_t      *ppos)
+{
+	/* we simply don't support read() (yet)... */
+
+	return -EINVAL;
+}
+
+static ssize_t
+zoran_write (struct file *file,
+	     const char  __user *data,
+	     size_t       count,
+	     loff_t      *ppos)
+{
+	/* ...and the same goes for write() */
+
+	return -EINVAL;
+}
+
+static int setup_fbuffer(struct zoran_fh *fh,
+	       void                      *base,
+	       const struct zoran_format *fmt,
+	       int                        width,
+	       int                        height,
+	       int                        bytesperline)
+{
+	struct zoran *zr = fh->zr;
+
+	/* (Ronald) v4l/v4l2 guidelines */
+	if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	/* Don't allow frame buffer overlay if PCI or AGP is buggy, or on
+	   ALi Magik (that needs very low latency while the card needs a
+	   higher value always) */
+
+	if (pci_pci_problems & (PCIPCI_FAIL | PCIAGP_FAIL | PCIPCI_ALIMAGIK))
+		return -ENXIO;
+
+	/* we need a bytesperline value, even if not given */
+	if (!bytesperline)
+		bytesperline = width * ((fmt->depth + 7) & ~7) / 8;
+
+#if 0
+	if (zr->overlay_active) {
+		/* dzjee... stupid users... don't even bother to turn off
+		 * overlay before changing the memory location...
+		 * normally, we would return errors here. However, one of
+		 * the tools that does this is... xawtv! and since xawtv
+		 * is used by +/- 99% of the users, we'd rather be user-
+		 * friendly and silently do as if nothing went wrong */
+		dprintk(3,
+			KERN_ERR
+			"%s: %s - forced overlay turnoff because framebuffer changed\n",
+			ZR_DEVNAME(zr), __func__);
+		zr36057_overlay(zr, 0);
+	}
+#endif
+
+	if (!(fmt->flags & ZORAN_FORMAT_OVERLAY)) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - no valid overlay format given\n",
+			ZR_DEVNAME(zr), __func__);
+		return -EINVAL;
+	}
+	if (height <= 0 || width <= 0 || bytesperline <= 0) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - invalid height/width/bpl value (%d|%d|%d)\n",
+			ZR_DEVNAME(zr), __func__, width, height, bytesperline);
+		return -EINVAL;
+	}
+	if (bytesperline & 3) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - bytesperline (%d) must be 4-byte aligned\n",
+			ZR_DEVNAME(zr), __func__, bytesperline);
+		return -EINVAL;
+	}
+
+	zr->vbuf_base = (void *) ((unsigned long) base & ~3);
+	zr->vbuf_height = height;
+	zr->vbuf_width = width;
+	zr->vbuf_depth = fmt->depth;
+	zr->overlay_settings.format = fmt;
+	zr->vbuf_bytesperline = bytesperline;
+
+	/* The user should set new window parameters */
+	zr->overlay_settings.is_set = 0;
+
+	return 0;
+}
+
+
+static int setup_window(struct zoran_fh *fh,
+			int x,
+			int y,
+			int width,
+			int height,
+			struct v4l2_clip __user *clips,
+			unsigned int clipcount,
+			void __user *bitmap)
+{
+	struct zoran *zr = fh->zr;
+	struct v4l2_clip *vcp = NULL;
+	int on, end;
+
+
+	if (!zr->vbuf_base) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - frame buffer has to be set first\n",
+			ZR_DEVNAME(zr), __func__);
+		return -EINVAL;
+	}
+
+	if (!fh->overlay_settings.format) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - no overlay format set\n",
+			ZR_DEVNAME(zr), __func__);
+		return -EINVAL;
+	}
+
+	if (clipcount > 2048) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - invalid clipcount\n",
+			 ZR_DEVNAME(zr), __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * The video front end needs 4-byte alinged line sizes, we correct that
+	 * silently here if necessary
+	 */
+	if (zr->vbuf_depth == 15 || zr->vbuf_depth == 16) {
+		end = (x + width) & ~1;	/* round down */
+		x = (x + 1) & ~1;	/* round up */
+		width = end - x;
+	}
+
+	if (zr->vbuf_depth == 24) {
+		end = (x + width) & ~3;	/* round down */
+		x = (x + 3) & ~3;	/* round up */
+		width = end - x;
+	}
+
+	if (width > BUZ_MAX_WIDTH)
+		width = BUZ_MAX_WIDTH;
+	if (height > BUZ_MAX_HEIGHT)
+		height = BUZ_MAX_HEIGHT;
+
+	/* Check for invalid parameters */
+	if (width < BUZ_MIN_WIDTH || height < BUZ_MIN_HEIGHT ||
+	    width > BUZ_MAX_WIDTH || height > BUZ_MAX_HEIGHT) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - width = %d or height = %d invalid\n",
+			ZR_DEVNAME(zr), __func__, width, height);
+		return -EINVAL;
+	}
+
+	fh->overlay_settings.x = x;
+	fh->overlay_settings.y = y;
+	fh->overlay_settings.width = width;
+	fh->overlay_settings.height = height;
+	fh->overlay_settings.clipcount = clipcount;
+
+	/*
+	 * If an overlay is running, we have to switch it off
+	 * and switch it on again in order to get the new settings in effect.
+	 *
+	 * We also want to avoid that the overlay mask is written
+	 * when an overlay is running.
+	 */
+
+	on = zr->v4l_overlay_active && !zr->v4l_memgrab_active &&
+	    zr->overlay_active != ZORAN_FREE &&
+	    fh->overlay_active != ZORAN_FREE;
+	if (on)
+		zr36057_overlay(zr, 0);
+
+	/*
+	 *   Write the overlay mask if clips are wanted.
+	 *   We prefer a bitmap.
+	 */
+	if (bitmap) {
+		/* fake value - it just means we want clips */
+		fh->overlay_settings.clipcount = 1;
+
+		if (copy_from_user(fh->overlay_mask, bitmap,
+				   (width * height + 7) / 8)) {
+			return -EFAULT;
+		}
+	} else if (clipcount) {
+		/* write our own bitmap from the clips */
+		vcp = vmalloc(sizeof(struct v4l2_clip) * (clipcount + 4));
+		if (vcp == NULL) {
+			dprintk(1,
+				KERN_ERR
+				"%s: %s - Alloc of clip mask failed\n",
+				ZR_DEVNAME(zr), __func__);
+			return -ENOMEM;
+		}
+		if (copy_from_user
+		    (vcp, clips, sizeof(struct v4l2_clip) * clipcount)) {
+			vfree(vcp);
+			return -EFAULT;
+		}
+		write_overlay_mask(fh, vcp, clipcount);
+		vfree(vcp);
+	}
+
+	fh->overlay_settings.is_set = 1;
+	if (fh->overlay_active != ZORAN_FREE &&
+	    zr->overlay_active != ZORAN_FREE)
+		zr->overlay_settings = fh->overlay_settings;
+
+	if (on)
+		zr36057_overlay(zr, 1);
+
+	/* Make sure the changes come into effect */
+	return wait_grab_pending(zr);
+}
+
+static int setup_overlay(struct zoran_fh *fh, int on)
+{
+	struct zoran *zr = fh->zr;
+
+	/* If there is nothing to do, return immediately */
+	if ((on && fh->overlay_active != ZORAN_FREE) ||
+	    (!on && fh->overlay_active == ZORAN_FREE))
+		return 0;
+
+	/* check whether we're touching someone else's overlay */
+	if (on && zr->overlay_active != ZORAN_FREE &&
+	    fh->overlay_active == ZORAN_FREE) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - overlay is already active for another session\n",
+			ZR_DEVNAME(zr), __func__);
+		return -EBUSY;
+	}
+	if (!on && zr->overlay_active != ZORAN_FREE &&
+	    fh->overlay_active == ZORAN_FREE) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - you cannot cancel someone else's session\n",
+			ZR_DEVNAME(zr), __func__);
+		return -EPERM;
+	}
+
+	if (on == 0) {
+		zr->overlay_active = fh->overlay_active = ZORAN_FREE;
+		zr->v4l_overlay_active = 0;
+		/* When a grab is running, the video simply
+		 * won't be switched on any more */
+		if (!zr->v4l_memgrab_active)
+			zr36057_overlay(zr, 0);
+		zr->overlay_mask = NULL;
+	} else {
+		if (!zr->vbuf_base || !fh->overlay_settings.is_set) {
+			dprintk(1,
+				KERN_ERR
+				"%s: %s - buffer or window not set\n",
+				ZR_DEVNAME(zr), __func__);
+			return -EINVAL;
+		}
+		if (!fh->overlay_settings.format) {
+			dprintk(1,
+				KERN_ERR
+				"%s: %s - no overlay format set\n",
+				ZR_DEVNAME(zr), __func__);
+			return -EINVAL;
+		}
+		zr->overlay_active = fh->overlay_active = ZORAN_LOCKED;
+		zr->v4l_overlay_active = 1;
+		zr->overlay_mask = fh->overlay_mask;
+		zr->overlay_settings = fh->overlay_settings;
+		if (!zr->v4l_memgrab_active)
+			zr36057_overlay(zr, 1);
+		/* When a grab is running, the video will be
+		 * switched on when grab is finished */
+	}
+
+	/* Make sure the changes come into effect */
+	return wait_grab_pending(zr);
+}
+
+/* get the status of a buffer in the clients buffer queue */
+static int zoran_v4l2_buffer_status(struct zoran_fh *fh,
+				    struct v4l2_buffer *buf, int num)
+{
+	struct zoran *zr = fh->zr;
+	unsigned long flags;
+
+	buf->flags = V4L2_BUF_FLAG_MAPPED;
+
+	switch (fh->map_mode) {
+	case ZORAN_MAP_MODE_RAW:
+		/* check range */
+		if (num < 0 || num >= fh->buffers.num_buffers ||
+		    !fh->buffers.allocated) {
+			dprintk(1,
+				KERN_ERR
+				"%s: %s - wrong number or buffers not allocated\n",
+				ZR_DEVNAME(zr), __func__);
+			return -EINVAL;
+		}
+
+		spin_lock_irqsave(&zr->spinlock, flags);
+		dprintk(3,
+			KERN_DEBUG
+			"%s: %s() - raw active=%c, buffer %d: state=%c, map=%c\n",
+			ZR_DEVNAME(zr), __func__,
+			"FAL"[fh->buffers.active], num,
+			"UPMD"[zr->v4l_buffers.buffer[num].state],
+			fh->buffers.buffer[num].map ? 'Y' : 'N');
+		spin_unlock_irqrestore(&zr->spinlock, flags);
+
+		buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		buf->length = fh->buffers.buffer_size;
+
+		/* get buffer */
+		buf->bytesused = fh->buffers.buffer[num].bs.length;
+		if (fh->buffers.buffer[num].state == BUZ_STATE_DONE ||
+		    fh->buffers.buffer[num].state == BUZ_STATE_USER) {
+			buf->sequence = fh->buffers.buffer[num].bs.seq;
+			buf->flags |= V4L2_BUF_FLAG_DONE;
+			buf->timestamp = fh->buffers.buffer[num].bs.timestamp;
+		} else {
+			buf->flags |= V4L2_BUF_FLAG_QUEUED;
+		}
+
+		if (fh->v4l_settings.height <= BUZ_MAX_HEIGHT / 2)
+			buf->field = V4L2_FIELD_TOP;
+		else
+			buf->field = V4L2_FIELD_INTERLACED;
+
+		break;
+
+	case ZORAN_MAP_MODE_JPG_REC:
+	case ZORAN_MAP_MODE_JPG_PLAY:
+
+		/* check range */
+		if (num < 0 || num >= fh->buffers.num_buffers ||
+		    !fh->buffers.allocated) {
+			dprintk(1,
+				KERN_ERR
+				"%s: %s - wrong number or buffers not allocated\n",
+				ZR_DEVNAME(zr), __func__);
+			return -EINVAL;
+		}
+
+		buf->type = (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ?
+			      V4L2_BUF_TYPE_VIDEO_CAPTURE :
+			      V4L2_BUF_TYPE_VIDEO_OUTPUT;
+		buf->length = fh->buffers.buffer_size;
+
+		/* these variables are only written after frame has been captured */
+		if (fh->buffers.buffer[num].state == BUZ_STATE_DONE ||
+		    fh->buffers.buffer[num].state == BUZ_STATE_USER) {
+			buf->sequence = fh->buffers.buffer[num].bs.seq;
+			buf->timestamp = fh->buffers.buffer[num].bs.timestamp;
+			buf->bytesused = fh->buffers.buffer[num].bs.length;
+			buf->flags |= V4L2_BUF_FLAG_DONE;
+		} else {
+			buf->flags |= V4L2_BUF_FLAG_QUEUED;
+		}
+
+		/* which fields are these? */
+		if (fh->jpg_settings.TmpDcm != 1)
+			buf->field = fh->jpg_settings.odd_even ?
+				V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM;
+		else
+			buf->field = fh->jpg_settings.odd_even ?
+				V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT;
+
+		break;
+
+	default:
+
+		dprintk(5,
+			KERN_ERR
+			"%s: %s - invalid buffer type|map_mode (%d|%d)\n",
+			ZR_DEVNAME(zr), __func__, buf->type, fh->map_mode);
+		return -EINVAL;
+	}
+
+	buf->memory = V4L2_MEMORY_MMAP;
+	buf->index = num;
+	buf->m.offset = buf->length * num;
+
+	return 0;
+}
+
+static int
+zoran_set_norm (struct zoran *zr,
+		v4l2_std_id norm)
+{
+	int on;
+
+	if (zr->v4l_buffers.active != ZORAN_FREE ||
+	    zr->jpg_buffers.active != ZORAN_FREE) {
+		dprintk(1,
+			KERN_WARNING
+			"%s: %s called while in playback/capture mode\n",
+			ZR_DEVNAME(zr), __func__);
+		return -EBUSY;
+	}
+
+	if (!(norm & zr->card.norms)) {
+		dprintk(1,
+			KERN_ERR "%s: %s - unsupported norm %llx\n",
+			ZR_DEVNAME(zr), __func__, norm);
+		return -EINVAL;
+	}
+
+	if (norm == V4L2_STD_ALL) {
+		unsigned int status = 0;
+		v4l2_std_id std = 0;
+
+		decoder_call(zr, video, querystd, &std);
+		decoder_call(zr, core, s_std, std);
+
+		/* let changes come into effect */
+		ssleep(2);
+
+		decoder_call(zr, video, g_input_status, &status);
+		if (status & V4L2_IN_ST_NO_SIGNAL) {
+			dprintk(1,
+				KERN_ERR
+				"%s: %s - no norm detected\n",
+				ZR_DEVNAME(zr), __func__);
+			/* reset norm */
+			decoder_call(zr, core, s_std, zr->norm);
+			return -EIO;
+		}
+
+		norm = std;
+	}
+	if (norm & V4L2_STD_SECAM)
+		zr->timing = zr->card.tvn[2];
+	else if (norm & V4L2_STD_NTSC)
+		zr->timing = zr->card.tvn[1];
+	else
+		zr->timing = zr->card.tvn[0];
+
+	/* We switch overlay off and on since a change in the
+	 * norm needs different VFE settings */
+	on = zr->overlay_active && !zr->v4l_memgrab_active;
+	if (on)
+		zr36057_overlay(zr, 0);
+
+	decoder_call(zr, core, s_std, norm);
+	encoder_call(zr, video, s_std_output, norm);
+
+	if (on)
+		zr36057_overlay(zr, 1);
+
+	/* Make sure the changes come into effect */
+	zr->norm = norm;
+
+	return 0;
+}
+
+static int
+zoran_set_input (struct zoran *zr,
+		 int           input)
+{
+	if (input == zr->input) {
+		return 0;
+	}
+
+	if (zr->v4l_buffers.active != ZORAN_FREE ||
+	    zr->jpg_buffers.active != ZORAN_FREE) {
+		dprintk(1,
+			KERN_WARNING
+			"%s: %s called while in playback/capture mode\n",
+			ZR_DEVNAME(zr), __func__);
+		return -EBUSY;
+	}
+
+	if (input < 0 || input >= zr->card.inputs) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - unnsupported input %d\n",
+			ZR_DEVNAME(zr), __func__, input);
+		return -EINVAL;
+	}
+
+	zr->input = input;
+
+	decoder_call(zr, video, s_routing,
+			zr->card.input[input].muxsel, 0, 0);
+
+	return 0;
+}
+
+/*
+ *   ioctl routine
+ */
+
+static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability *cap)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+
+	memset(cap, 0, sizeof(*cap));
+	strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)-1);
+	strncpy(cap->driver, "zoran", sizeof(cap->driver)-1);
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
+		 pci_name(zr->pci_dev));
+	cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE |
+			    V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OVERLAY;
+	return 0;
+}
+
+static int zoran_enum_fmt(struct zoran *zr, struct v4l2_fmtdesc *fmt, int flag)
+{
+	unsigned int num, i;
+
+	for (num = i = 0; i < NUM_FORMATS; i++) {
+		if (zoran_formats[i].flags & flag && num++ == fmt->index) {
+			strncpy(fmt->description, zoran_formats[i].name,
+				sizeof(fmt->description) - 1);
+			/* fmt struct pre-zeroed, so adding '\0' not needed */
+			fmt->pixelformat = zoran_formats[i].fourcc;
+			if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)
+				fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static int zoran_enum_fmt_vid_cap(struct file *file, void *__fh,
+					    struct v4l2_fmtdesc *f)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+
+	return zoran_enum_fmt(zr, f, ZORAN_FORMAT_CAPTURE);
+}
+
+static int zoran_enum_fmt_vid_out(struct file *file, void *__fh,
+					    struct v4l2_fmtdesc *f)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+
+	return zoran_enum_fmt(zr, f, ZORAN_FORMAT_PLAYBACK);
+}
+
+static int zoran_enum_fmt_vid_overlay(struct file *file, void *__fh,
+					    struct v4l2_fmtdesc *f)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+
+	return zoran_enum_fmt(zr, f, ZORAN_FORMAT_OVERLAY);
+}
+
+static int zoran_g_fmt_vid_out(struct file *file, void *__fh,
+					struct v4l2_format *fmt)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+
+	mutex_lock(&zr->resource_lock);
+
+	fmt->fmt.pix.width = fh->jpg_settings.img_width / fh->jpg_settings.HorDcm;
+	fmt->fmt.pix.height = fh->jpg_settings.img_height * 2 /
+		(fh->jpg_settings.VerDcm * fh->jpg_settings.TmpDcm);
+	fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&fh->jpg_settings);
+	fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
+	if (fh->jpg_settings.TmpDcm == 1)
+		fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
+				V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT);
+	else
+		fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
+				V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
+	fmt->fmt.pix.bytesperline = 0;
+	fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+	mutex_unlock(&zr->resource_lock);
+	return 0;
+}
+
+static int zoran_g_fmt_vid_cap(struct file *file, void *__fh,
+					struct v4l2_format *fmt)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+
+	if (fh->map_mode != ZORAN_MAP_MODE_RAW)
+		return zoran_g_fmt_vid_out(file, fh, fmt);
+
+	mutex_lock(&zr->resource_lock);
+	fmt->fmt.pix.width = fh->v4l_settings.width;
+	fmt->fmt.pix.height = fh->v4l_settings.height;
+	fmt->fmt.pix.sizeimage = fh->v4l_settings.bytesperline *
+					fh->v4l_settings.height;
+	fmt->fmt.pix.pixelformat = fh->v4l_settings.format->fourcc;
+	fmt->fmt.pix.colorspace = fh->v4l_settings.format->colorspace;
+	fmt->fmt.pix.bytesperline = fh->v4l_settings.bytesperline;
+	if (BUZ_MAX_HEIGHT < (fh->v4l_settings.height * 2))
+		fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
+	else
+		fmt->fmt.pix.field = V4L2_FIELD_TOP;
+	mutex_unlock(&zr->resource_lock);
+	return 0;
+}
+
+static int zoran_g_fmt_vid_overlay(struct file *file, void *__fh,
+					struct v4l2_format *fmt)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+
+	mutex_lock(&zr->resource_lock);
+
+	fmt->fmt.win.w.left = fh->overlay_settings.x;
+	fmt->fmt.win.w.top = fh->overlay_settings.y;
+	fmt->fmt.win.w.width = fh->overlay_settings.width;
+	fmt->fmt.win.w.height = fh->overlay_settings.height;
+	if (fh->overlay_settings.width * 2 > BUZ_MAX_HEIGHT)
+		fmt->fmt.win.field = V4L2_FIELD_INTERLACED;
+	else
+		fmt->fmt.win.field = V4L2_FIELD_TOP;
+
+	mutex_unlock(&zr->resource_lock);
+	return 0;
+}
+
+static int zoran_try_fmt_vid_overlay(struct file *file, void *__fh,
+					struct v4l2_format *fmt)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+
+	mutex_lock(&zr->resource_lock);
+
+	if (fmt->fmt.win.w.width > BUZ_MAX_WIDTH)
+		fmt->fmt.win.w.width = BUZ_MAX_WIDTH;
+	if (fmt->fmt.win.w.width < BUZ_MIN_WIDTH)
+		fmt->fmt.win.w.width = BUZ_MIN_WIDTH;
+	if (fmt->fmt.win.w.height > BUZ_MAX_HEIGHT)
+		fmt->fmt.win.w.height = BUZ_MAX_HEIGHT;
+	if (fmt->fmt.win.w.height < BUZ_MIN_HEIGHT)
+		fmt->fmt.win.w.height = BUZ_MIN_HEIGHT;
+
+	mutex_unlock(&zr->resource_lock);
+	return 0;
+}
+
+static int zoran_try_fmt_vid_out(struct file *file, void *__fh,
+					struct v4l2_format *fmt)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	struct zoran_jpg_settings settings;
+	int res = 0;
+
+	if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
+		return -EINVAL;
+
+	mutex_lock(&zr->resource_lock);
+	settings = fh->jpg_settings;
+
+	/* we actually need to set 'real' parameters now */
+	if ((fmt->fmt.pix.height * 2) > BUZ_MAX_HEIGHT)
+		settings.TmpDcm = 1;
+	else
+		settings.TmpDcm = 2;
+	settings.decimation = 0;
+	if (fmt->fmt.pix.height <= fh->jpg_settings.img_height / 2)
+		settings.VerDcm = 2;
+	else
+		settings.VerDcm = 1;
+	if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 4)
+		settings.HorDcm = 4;
+	else if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 2)
+		settings.HorDcm = 2;
+	else
+		settings.HorDcm = 1;
+	if (settings.TmpDcm == 1)
+		settings.field_per_buff = 2;
+	else
+		settings.field_per_buff = 1;
+
+	if (settings.HorDcm > 1) {
+		settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0;
+		settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH;
+	} else {
+		settings.img_x = 0;
+		settings.img_width = BUZ_MAX_WIDTH;
+	}
+
+	/* check */
+	res = zoran_check_jpg_settings(zr, &settings, 1);
+	if (res)
+		goto tryfmt_unlock_and_return;
+
+	/* tell the user what we actually did */
+	fmt->fmt.pix.width = settings.img_width / settings.HorDcm;
+	fmt->fmt.pix.height = settings.img_height * 2 /
+		(settings.TmpDcm * settings.VerDcm);
+	if (settings.TmpDcm == 1)
+		fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
+				V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT);
+	else
+		fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
+				V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
+
+	fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&settings);
+	fmt->fmt.pix.bytesperline = 0;
+	fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+tryfmt_unlock_and_return:
+	mutex_unlock(&zr->resource_lock);
+	return res;
+}
+
+static int zoran_try_fmt_vid_cap(struct file *file, void *__fh,
+					struct v4l2_format *fmt)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	int bpp;
+	int i;
+
+	if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
+		return zoran_try_fmt_vid_out(file, fh, fmt);
+
+	mutex_lock(&zr->resource_lock);
+
+	for (i = 0; i < NUM_FORMATS; i++)
+		if (zoran_formats[i].fourcc == fmt->fmt.pix.pixelformat)
+			break;
+
+	if (i == NUM_FORMATS) {
+		mutex_unlock(&zr->resource_lock);
+		return -EINVAL;
+	}
+
+	bpp = DIV_ROUND_UP(zoran_formats[i].depth, 8);
+	v4l_bound_align_image(
+		&fmt->fmt.pix.width, BUZ_MIN_WIDTH, BUZ_MAX_WIDTH, bpp == 2 ? 1 : 2,
+		&fmt->fmt.pix.height, BUZ_MIN_HEIGHT, BUZ_MAX_HEIGHT, 0, 0);
+	mutex_unlock(&zr->resource_lock);
+
+	return 0;
+}
+
+static int zoran_s_fmt_vid_overlay(struct file *file, void *__fh,
+					struct v4l2_format *fmt)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	int res;
+
+	dprintk(3, "x=%d, y=%d, w=%d, h=%d, cnt=%d, map=0x%p\n",
+			fmt->fmt.win.w.left, fmt->fmt.win.w.top,
+			fmt->fmt.win.w.width,
+			fmt->fmt.win.w.height,
+			fmt->fmt.win.clipcount,
+			fmt->fmt.win.bitmap);
+	mutex_lock(&zr->resource_lock);
+	res = setup_window(fh, fmt->fmt.win.w.left, fmt->fmt.win.w.top,
+			   fmt->fmt.win.w.width, fmt->fmt.win.w.height,
+			   (struct v4l2_clip __user *)fmt->fmt.win.clips,
+			   fmt->fmt.win.clipcount, fmt->fmt.win.bitmap);
+	mutex_unlock(&zr->resource_lock);
+	return res;
+}
+
+static int zoran_s_fmt_vid_out(struct file *file, void *__fh,
+					struct v4l2_format *fmt)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	__le32 printformat = __cpu_to_le32(fmt->fmt.pix.pixelformat);
+	struct zoran_jpg_settings settings;
+	int res = 0;
+
+	dprintk(3, "size=%dx%d, fmt=0x%x (%4.4s)\n",
+			fmt->fmt.pix.width, fmt->fmt.pix.height,
+			fmt->fmt.pix.pixelformat,
+			(char *) &printformat);
+	if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
+		return -EINVAL;
+
+	mutex_lock(&zr->resource_lock);
+
+	if (fh->buffers.allocated) {
+		dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - cannot change capture mode\n",
+			ZR_DEVNAME(zr));
+		res = -EBUSY;
+		goto sfmtjpg_unlock_and_return;
+	}
+
+	settings = fh->jpg_settings;
+
+	/* we actually need to set 'real' parameters now */
+	if (fmt->fmt.pix.height * 2 > BUZ_MAX_HEIGHT)
+		settings.TmpDcm = 1;
+	else
+		settings.TmpDcm = 2;
+	settings.decimation = 0;
+	if (fmt->fmt.pix.height <= fh->jpg_settings.img_height / 2)
+		settings.VerDcm = 2;
+	else
+		settings.VerDcm = 1;
+	if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 4)
+		settings.HorDcm = 4;
+	else if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 2)
+		settings.HorDcm = 2;
+	else
+		settings.HorDcm = 1;
+	if (settings.TmpDcm == 1)
+		settings.field_per_buff = 2;
+	else
+		settings.field_per_buff = 1;
+
+	if (settings.HorDcm > 1) {
+		settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0;
+		settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH;
+	} else {
+		settings.img_x = 0;
+		settings.img_width = BUZ_MAX_WIDTH;
+	}
+
+	/* check */
+	res = zoran_check_jpg_settings(zr, &settings, 0);
+	if (res)
+		goto sfmtjpg_unlock_and_return;
+
+	/* it's ok, so set them */
+	fh->jpg_settings = settings;
+
+	map_mode_jpg(fh, fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	fh->buffers.buffer_size = zoran_v4l2_calc_bufsize(&fh->jpg_settings);
+
+	/* tell the user what we actually did */
+	fmt->fmt.pix.width = settings.img_width / settings.HorDcm;
+	fmt->fmt.pix.height = settings.img_height * 2 /
+		(settings.TmpDcm * settings.VerDcm);
+	if (settings.TmpDcm == 1)
+		fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
+				V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT);
+	else
+		fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
+				V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
+	fmt->fmt.pix.bytesperline = 0;
+	fmt->fmt.pix.sizeimage = fh->buffers.buffer_size;
+	fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+sfmtjpg_unlock_and_return:
+	mutex_unlock(&zr->resource_lock);
+	return res;
+}
+
+static int zoran_s_fmt_vid_cap(struct file *file, void *__fh,
+					struct v4l2_format *fmt)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	int i;
+	int res = 0;
+
+	if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
+		return zoran_s_fmt_vid_out(file, fh, fmt);
+
+	for (i = 0; i < NUM_FORMATS; i++)
+		if (fmt->fmt.pix.pixelformat == zoran_formats[i].fourcc)
+			break;
+	if (i == NUM_FORMATS) {
+		dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - unknown/unsupported format 0x%x\n",
+			ZR_DEVNAME(zr), fmt->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	mutex_lock(&zr->resource_lock);
+
+	if ((fh->map_mode != ZORAN_MAP_MODE_RAW && fh->buffers.allocated) ||
+	    fh->buffers.active != ZORAN_FREE) {
+		dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - cannot change capture mode\n",
+				ZR_DEVNAME(zr));
+		res = -EBUSY;
+		goto sfmtv4l_unlock_and_return;
+	}
+	if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
+		fmt->fmt.pix.height = BUZ_MAX_HEIGHT;
+	if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
+		fmt->fmt.pix.width = BUZ_MAX_WIDTH;
+
+	map_mode_raw(fh);
+
+	res = zoran_v4l_set_format(fh, fmt->fmt.pix.width, fmt->fmt.pix.height,
+				   &zoran_formats[i]);
+	if (res)
+		goto sfmtv4l_unlock_and_return;
+
+	/* tell the user the results/missing stuff */
+	fmt->fmt.pix.bytesperline = fh->v4l_settings.bytesperline;
+	fmt->fmt.pix.sizeimage = fh->v4l_settings.height * fh->v4l_settings.bytesperline;
+	fmt->fmt.pix.colorspace = fh->v4l_settings.format->colorspace;
+	if (BUZ_MAX_HEIGHT < (fh->v4l_settings.height * 2))
+		fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
+	else
+		fmt->fmt.pix.field = V4L2_FIELD_TOP;
+
+sfmtv4l_unlock_and_return:
+	mutex_unlock(&zr->resource_lock);
+	return res;
+}
+
+static int zoran_g_fbuf(struct file *file, void *__fh,
+		struct v4l2_framebuffer *fb)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+
+	memset(fb, 0, sizeof(*fb));
+	mutex_lock(&zr->resource_lock);
+	fb->base = zr->vbuf_base;
+	fb->fmt.width = zr->vbuf_width;
+	fb->fmt.height = zr->vbuf_height;
+	if (zr->overlay_settings.format)
+		fb->fmt.pixelformat = fh->overlay_settings.format->fourcc;
+	fb->fmt.bytesperline = zr->vbuf_bytesperline;
+	mutex_unlock(&zr->resource_lock);
+	fb->fmt.colorspace = V4L2_COLORSPACE_SRGB;
+	fb->fmt.field = V4L2_FIELD_INTERLACED;
+	fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+
+	return 0;
+}
+
+static int zoran_s_fbuf(struct file *file, void *__fh,
+		struct v4l2_framebuffer *fb)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	int i, res = 0;
+	__le32 printformat = __cpu_to_le32(fb->fmt.pixelformat);
+
+	for (i = 0; i < NUM_FORMATS; i++)
+		if (zoran_formats[i].fourcc == fb->fmt.pixelformat)
+			break;
+	if (i == NUM_FORMATS) {
+		dprintk(1, KERN_ERR "%s: VIDIOC_S_FBUF - format=0x%x (%4.4s) not allowed\n",
+			ZR_DEVNAME(zr), fb->fmt.pixelformat,
+			(char *)&printformat);
+		return -EINVAL;
+	}
+
+	mutex_lock(&zr->resource_lock);
+	res = setup_fbuffer(fh, fb->base, &zoran_formats[i], fb->fmt.width,
+			    fb->fmt.height, fb->fmt.bytesperline);
+	mutex_unlock(&zr->resource_lock);
+
+	return res;
+}
+
+static int zoran_overlay(struct file *file, void *__fh, unsigned int on)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	int res;
+
+	mutex_lock(&zr->resource_lock);
+	res = setup_overlay(fh, on);
+	mutex_unlock(&zr->resource_lock);
+
+	return res;
+}
+
+static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type);
+
+static int zoran_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *req)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	int res = 0;
+
+	if (req->memory != V4L2_MEMORY_MMAP) {
+		dprintk(2,
+				KERN_ERR
+				"%s: only MEMORY_MMAP capture is supported, not %d\n",
+				ZR_DEVNAME(zr), req->memory);
+		return -EINVAL;
+	}
+
+	if (req->count == 0)
+		return zoran_streamoff(file, fh, req->type);
+
+	mutex_lock(&zr->resource_lock);
+	if (fh->buffers.allocated) {
+		dprintk(2,
+				KERN_ERR
+				"%s: VIDIOC_REQBUFS - buffers already allocated\n",
+				ZR_DEVNAME(zr));
+		res = -EBUSY;
+		goto v4l2reqbuf_unlock_and_return;
+	}
+
+	if (fh->map_mode == ZORAN_MAP_MODE_RAW &&
+	    req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		/* control user input */
+		if (req->count < 2)
+			req->count = 2;
+		if (req->count > v4l_nbufs)
+			req->count = v4l_nbufs;
+
+		/* The next mmap will map the V4L buffers */
+		map_mode_raw(fh);
+		fh->buffers.num_buffers = req->count;
+
+		if (v4l_fbuffer_alloc(fh)) {
+			res = -ENOMEM;
+			goto v4l2reqbuf_unlock_and_return;
+		}
+	} else if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC ||
+		   fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
+		/* we need to calculate size ourselves now */
+		if (req->count < 4)
+			req->count = 4;
+		if (req->count > jpg_nbufs)
+			req->count = jpg_nbufs;
+
+		/* The next mmap will map the MJPEG buffers */
+		map_mode_jpg(fh, req->type == V4L2_BUF_TYPE_VIDEO_OUTPUT);
+		fh->buffers.num_buffers = req->count;
+		fh->buffers.buffer_size = zoran_v4l2_calc_bufsize(&fh->jpg_settings);
+
+		if (jpg_fbuffer_alloc(fh)) {
+			res = -ENOMEM;
+			goto v4l2reqbuf_unlock_and_return;
+		}
+	} else {
+		dprintk(1,
+				KERN_ERR
+				"%s: VIDIOC_REQBUFS - unknown type %d\n",
+				ZR_DEVNAME(zr), req->type);
+		res = -EINVAL;
+		goto v4l2reqbuf_unlock_and_return;
+	}
+v4l2reqbuf_unlock_and_return:
+	mutex_unlock(&zr->resource_lock);
+
+	return res;
+}
+
+static int zoran_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	int res;
+
+	mutex_lock(&zr->resource_lock);
+	res = zoran_v4l2_buffer_status(fh, buf, buf->index);
+	mutex_unlock(&zr->resource_lock);
+
+	return res;
+}
+
+static int zoran_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	int res = 0, codec_mode, buf_type;
+
+	mutex_lock(&zr->resource_lock);
+
+	switch (fh->map_mode) {
+	case ZORAN_MAP_MODE_RAW:
+		if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+			dprintk(1, KERN_ERR
+				"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
+				ZR_DEVNAME(zr), buf->type, fh->map_mode);
+			res = -EINVAL;
+			goto qbuf_unlock_and_return;
+		}
+
+		res = zoran_v4l_queue_frame(fh, buf->index);
+		if (res)
+			goto qbuf_unlock_and_return;
+		if (!zr->v4l_memgrab_active && fh->buffers.active == ZORAN_LOCKED)
+			zr36057_set_memgrab(zr, 1);
+		break;
+
+	case ZORAN_MAP_MODE_JPG_REC:
+	case ZORAN_MAP_MODE_JPG_PLAY:
+		if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
+			buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+			codec_mode = BUZ_MODE_MOTION_DECOMPRESS;
+		} else {
+			buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+			codec_mode = BUZ_MODE_MOTION_COMPRESS;
+		}
+
+		if (buf->type != buf_type) {
+			dprintk(1, KERN_ERR
+				"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
+				ZR_DEVNAME(zr), buf->type, fh->map_mode);
+			res = -EINVAL;
+			goto qbuf_unlock_and_return;
+		}
+
+		res = zoran_jpg_queue_frame(fh, buf->index, codec_mode);
+		if (res != 0)
+			goto qbuf_unlock_and_return;
+		if (zr->codec_mode == BUZ_MODE_IDLE &&
+		    fh->buffers.active == ZORAN_LOCKED)
+			zr36057_enable_jpg(zr, codec_mode);
+
+		break;
+
+	default:
+		dprintk(1, KERN_ERR
+			"%s: VIDIOC_QBUF - unsupported type %d\n",
+			ZR_DEVNAME(zr), buf->type);
+		res = -EINVAL;
+		break;
+	}
+qbuf_unlock_and_return:
+	mutex_unlock(&zr->resource_lock);
+
+	return res;
+}
+
+static int zoran_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	int res = 0, buf_type, num = -1;	/* compiler borks here (?) */
+
+	mutex_lock(&zr->resource_lock);
+
+	switch (fh->map_mode) {
+	case ZORAN_MAP_MODE_RAW:
+		if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+			dprintk(1, KERN_ERR
+				"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
+				ZR_DEVNAME(zr), buf->type, fh->map_mode);
+			res = -EINVAL;
+			goto dqbuf_unlock_and_return;
+		}
+
+		num = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME];
+		if (file->f_flags & O_NONBLOCK &&
+		    zr->v4l_buffers.buffer[num].state != BUZ_STATE_DONE) {
+			res = -EAGAIN;
+			goto dqbuf_unlock_and_return;
+		}
+		res = v4l_sync(fh, num);
+		if (res)
+			goto dqbuf_unlock_and_return;
+		zr->v4l_sync_tail++;
+		res = zoran_v4l2_buffer_status(fh, buf, num);
+		break;
+
+	case ZORAN_MAP_MODE_JPG_REC:
+	case ZORAN_MAP_MODE_JPG_PLAY:
+	{
+		struct zoran_sync bs;
+
+		if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY)
+			buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+		else
+			buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+		if (buf->type != buf_type) {
+			dprintk(1, KERN_ERR
+				"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
+				ZR_DEVNAME(zr), buf->type, fh->map_mode);
+			res = -EINVAL;
+			goto dqbuf_unlock_and_return;
+		}
+
+		num = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
+
+		if (file->f_flags & O_NONBLOCK &&
+		    zr->jpg_buffers.buffer[num].state != BUZ_STATE_DONE) {
+			res = -EAGAIN;
+			goto dqbuf_unlock_and_return;
+		}
+		bs.frame = 0; /* suppress compiler warning */
+		res = jpg_sync(fh, &bs);
+		if (res)
+			goto dqbuf_unlock_and_return;
+		res = zoran_v4l2_buffer_status(fh, buf, bs.frame);
+		break;
+	}
+
+	default:
+		dprintk(1, KERN_ERR
+			"%s: VIDIOC_DQBUF - unsupported type %d\n",
+			ZR_DEVNAME(zr), buf->type);
+		res = -EINVAL;
+		break;
+	}
+dqbuf_unlock_and_return:
+	mutex_unlock(&zr->resource_lock);
+
+	return res;
+}
+
+static int zoran_streamon(struct file *file, void *__fh, enum v4l2_buf_type type)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	int res = 0;
+
+	mutex_lock(&zr->resource_lock);
+
+	switch (fh->map_mode) {
+	case ZORAN_MAP_MODE_RAW:	/* raw capture */
+		if (zr->v4l_buffers.active != ZORAN_ACTIVE ||
+		    fh->buffers.active != ZORAN_ACTIVE) {
+			res = -EBUSY;
+			goto strmon_unlock_and_return;
+		}
+
+		zr->v4l_buffers.active = fh->buffers.active = ZORAN_LOCKED;
+		zr->v4l_settings = fh->v4l_settings;
+
+		zr->v4l_sync_tail = zr->v4l_pend_tail;
+		if (!zr->v4l_memgrab_active &&
+		    zr->v4l_pend_head != zr->v4l_pend_tail) {
+			zr36057_set_memgrab(zr, 1);
+		}
+		break;
+
+	case ZORAN_MAP_MODE_JPG_REC:
+	case ZORAN_MAP_MODE_JPG_PLAY:
+		/* what is the codec mode right now? */
+		if (zr->jpg_buffers.active != ZORAN_ACTIVE ||
+		    fh->buffers.active != ZORAN_ACTIVE) {
+			res = -EBUSY;
+			goto strmon_unlock_and_return;
+		}
+
+		zr->jpg_buffers.active = fh->buffers.active = ZORAN_LOCKED;
+
+		if (zr->jpg_que_head != zr->jpg_que_tail) {
+			/* Start the jpeg codec when the first frame is queued  */
+			jpeg_start(zr);
+		}
+		break;
+
+	default:
+		dprintk(1,
+			KERN_ERR
+			"%s: VIDIOC_STREAMON - invalid map mode %d\n",
+			ZR_DEVNAME(zr), fh->map_mode);
+		res = -EINVAL;
+		break;
+	}
+strmon_unlock_and_return:
+	mutex_unlock(&zr->resource_lock);
+
+	return res;
+}
+
+static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	int i, res = 0;
+	unsigned long flags;
+
+	mutex_lock(&zr->resource_lock);
+
+	switch (fh->map_mode) {
+	case ZORAN_MAP_MODE_RAW:	/* raw capture */
+		if (fh->buffers.active == ZORAN_FREE &&
+		    zr->v4l_buffers.active != ZORAN_FREE) {
+			res = -EPERM;	/* stay off other's settings! */
+			goto strmoff_unlock_and_return;
+		}
+		if (zr->v4l_buffers.active == ZORAN_FREE)
+			goto strmoff_unlock_and_return;
+
+		spin_lock_irqsave(&zr->spinlock, flags);
+		/* unload capture */
+		if (zr->v4l_memgrab_active) {
+
+			zr36057_set_memgrab(zr, 0);
+		}
+
+		for (i = 0; i < fh->buffers.num_buffers; i++)
+			zr->v4l_buffers.buffer[i].state = BUZ_STATE_USER;
+		fh->buffers = zr->v4l_buffers;
+
+		zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE;
+
+		zr->v4l_grab_seq = 0;
+		zr->v4l_pend_head = zr->v4l_pend_tail = 0;
+		zr->v4l_sync_tail = 0;
+
+		spin_unlock_irqrestore(&zr->spinlock, flags);
+
+		break;
+
+	case ZORAN_MAP_MODE_JPG_REC:
+	case ZORAN_MAP_MODE_JPG_PLAY:
+		if (fh->buffers.active == ZORAN_FREE &&
+		    zr->jpg_buffers.active != ZORAN_FREE) {
+			res = -EPERM;	/* stay off other's settings! */
+			goto strmoff_unlock_and_return;
+		}
+		if (zr->jpg_buffers.active == ZORAN_FREE)
+			goto strmoff_unlock_and_return;
+
+		res = jpg_qbuf(fh, -1,
+			     (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ?
+			     BUZ_MODE_MOTION_COMPRESS :
+			     BUZ_MODE_MOTION_DECOMPRESS);
+		if (res)
+			goto strmoff_unlock_and_return;
+		break;
+	default:
+		dprintk(1, KERN_ERR
+			"%s: VIDIOC_STREAMOFF - invalid map mode %d\n",
+			ZR_DEVNAME(zr), fh->map_mode);
+		res = -EINVAL;
+		break;
+	}
+strmoff_unlock_and_return:
+	mutex_unlock(&zr->resource_lock);
+
+	return res;
+}
+
+static int zoran_queryctrl(struct file *file, void *__fh,
+					struct v4l2_queryctrl *ctrl)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+
+	/* we only support hue/saturation/contrast/brightness */
+	if (ctrl->id < V4L2_CID_BRIGHTNESS ||
+	    ctrl->id > V4L2_CID_HUE)
+		return -EINVAL;
+
+	decoder_call(zr, core, queryctrl, ctrl);
+
+	return 0;
+}
+
+static int zoran_g_ctrl(struct file *file, void *__fh, struct v4l2_control *ctrl)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+
+	/* we only support hue/saturation/contrast/brightness */
+	if (ctrl->id < V4L2_CID_BRIGHTNESS ||
+	    ctrl->id > V4L2_CID_HUE)
+		return -EINVAL;
+
+	mutex_lock(&zr->resource_lock);
+	decoder_call(zr, core, g_ctrl, ctrl);
+	mutex_unlock(&zr->resource_lock);
+
+	return 0;
+}
+
+static int zoran_s_ctrl(struct file *file, void *__fh, struct v4l2_control *ctrl)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+
+	/* we only support hue/saturation/contrast/brightness */
+	if (ctrl->id < V4L2_CID_BRIGHTNESS ||
+	    ctrl->id > V4L2_CID_HUE)
+		return -EINVAL;
+
+	mutex_lock(&zr->resource_lock);
+	decoder_call(zr, core, s_ctrl, ctrl);
+	mutex_unlock(&zr->resource_lock);
+
+	return 0;
+}
+
+static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+
+	mutex_lock(&zr->resource_lock);
+	*std = zr->norm;
+	mutex_unlock(&zr->resource_lock);
+	return 0;
+}
+
+static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id *std)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	int res = 0;
+
+	mutex_lock(&zr->resource_lock);
+	res = zoran_set_norm(zr, *std);
+	if (res)
+		goto sstd_unlock_and_return;
+
+	res = wait_grab_pending(zr);
+sstd_unlock_and_return:
+	mutex_unlock(&zr->resource_lock);
+	return res;
+}
+
+static int zoran_enum_input(struct file *file, void *__fh,
+				 struct v4l2_input *inp)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+
+	if (inp->index >= zr->card.inputs)
+		return -EINVAL;
+
+	strncpy(inp->name, zr->card.input[inp->index].name,
+		sizeof(inp->name) - 1);
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+	inp->std = V4L2_STD_ALL;
+
+	/* Get status of video decoder */
+	mutex_lock(&zr->resource_lock);
+	decoder_call(zr, video, g_input_status, &inp->status);
+	mutex_unlock(&zr->resource_lock);
+	return 0;
+}
+
+static int zoran_g_input(struct file *file, void *__fh, unsigned int *input)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+
+	mutex_lock(&zr->resource_lock);
+	*input = zr->input;
+	mutex_unlock(&zr->resource_lock);
+
+	return 0;
+}
+
+static int zoran_s_input(struct file *file, void *__fh, unsigned int input)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	int res;
+
+	mutex_lock(&zr->resource_lock);
+	res = zoran_set_input(zr, input);
+	if (res)
+		goto sinput_unlock_and_return;
+
+	/* Make sure the changes come into effect */
+	res = wait_grab_pending(zr);
+sinput_unlock_and_return:
+	mutex_unlock(&zr->resource_lock);
+	return res;
+}
+
+static int zoran_enum_output(struct file *file, void *__fh,
+				  struct v4l2_output *outp)
+{
+	if (outp->index != 0)
+		return -EINVAL;
+
+	outp->index = 0;
+	outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
+	strncpy(outp->name, "Autodetect", sizeof(outp->name)-1);
+
+	return 0;
+}
+
+static int zoran_g_output(struct file *file, void *__fh, unsigned int *output)
+{
+	*output = 0;
+
+	return 0;
+}
+
+static int zoran_s_output(struct file *file, void *__fh, unsigned int output)
+{
+	if (output != 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+/* cropping (sub-frame capture) */
+static int zoran_cropcap(struct file *file, void *__fh,
+					struct v4l2_cropcap *cropcap)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	int type = cropcap->type, res = 0;
+
+	memset(cropcap, 0, sizeof(*cropcap));
+	cropcap->type = type;
+
+	mutex_lock(&zr->resource_lock);
+
+	if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+	    (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	     fh->map_mode == ZORAN_MAP_MODE_RAW)) {
+		dprintk(1, KERN_ERR
+			"%s: VIDIOC_CROPCAP - subcapture only supported for compressed capture\n",
+			ZR_DEVNAME(zr));
+		res = -EINVAL;
+		goto cropcap_unlock_and_return;
+	}
+
+	cropcap->bounds.top = cropcap->bounds.left = 0;
+	cropcap->bounds.width = BUZ_MAX_WIDTH;
+	cropcap->bounds.height = BUZ_MAX_HEIGHT;
+	cropcap->defrect.top = cropcap->defrect.left = 0;
+	cropcap->defrect.width = BUZ_MIN_WIDTH;
+	cropcap->defrect.height = BUZ_MIN_HEIGHT;
+cropcap_unlock_and_return:
+	mutex_unlock(&zr->resource_lock);
+	return res;
+}
+
+static int zoran_g_crop(struct file *file, void *__fh, struct v4l2_crop *crop)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	int type = crop->type, res = 0;
+
+	memset(crop, 0, sizeof(*crop));
+	crop->type = type;
+
+	mutex_lock(&zr->resource_lock);
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+	    (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	     fh->map_mode == ZORAN_MAP_MODE_RAW)) {
+		dprintk(1,
+			KERN_ERR
+			"%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n",
+			ZR_DEVNAME(zr));
+		res = -EINVAL;
+		goto gcrop_unlock_and_return;
+	}
+
+	crop->c.top = fh->jpg_settings.img_y;
+	crop->c.left = fh->jpg_settings.img_x;
+	crop->c.width = fh->jpg_settings.img_width;
+	crop->c.height = fh->jpg_settings.img_height;
+
+gcrop_unlock_and_return:
+	mutex_unlock(&zr->resource_lock);
+
+	return res;
+}
+
+static int zoran_s_crop(struct file *file, void *__fh, struct v4l2_crop *crop)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	int res = 0;
+	struct zoran_jpg_settings settings;
+
+	settings = fh->jpg_settings;
+
+	mutex_lock(&zr->resource_lock);
+
+	if (fh->buffers.allocated) {
+		dprintk(1, KERN_ERR
+			"%s: VIDIOC_S_CROP - cannot change settings while active\n",
+			ZR_DEVNAME(zr));
+		res = -EBUSY;
+		goto scrop_unlock_and_return;
+	}
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+	    (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	     fh->map_mode == ZORAN_MAP_MODE_RAW)) {
+		dprintk(1, KERN_ERR
+			"%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n",
+			ZR_DEVNAME(zr));
+		res = -EINVAL;
+		goto scrop_unlock_and_return;
+	}
+
+	/* move into a form that we understand */
+	settings.img_x = crop->c.left;
+	settings.img_y = crop->c.top;
+	settings.img_width = crop->c.width;
+	settings.img_height = crop->c.height;
+
+	/* check validity */
+	res = zoran_check_jpg_settings(zr, &settings, 0);
+	if (res)
+		goto scrop_unlock_and_return;
+
+	/* accept */
+	fh->jpg_settings = settings;
+
+scrop_unlock_and_return:
+	mutex_unlock(&zr->resource_lock);
+	return res;
+}
+
+static int zoran_g_jpegcomp(struct file *file, void *__fh,
+					struct v4l2_jpegcompression *params)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	memset(params, 0, sizeof(*params));
+
+	mutex_lock(&zr->resource_lock);
+
+	params->quality = fh->jpg_settings.jpg_comp.quality;
+	params->APPn = fh->jpg_settings.jpg_comp.APPn;
+	memcpy(params->APP_data,
+	       fh->jpg_settings.jpg_comp.APP_data,
+	       fh->jpg_settings.jpg_comp.APP_len);
+	params->APP_len = fh->jpg_settings.jpg_comp.APP_len;
+	memcpy(params->COM_data,
+	       fh->jpg_settings.jpg_comp.COM_data,
+	       fh->jpg_settings.jpg_comp.COM_len);
+	params->COM_len = fh->jpg_settings.jpg_comp.COM_len;
+	params->jpeg_markers =
+	    fh->jpg_settings.jpg_comp.jpeg_markers;
+
+	mutex_unlock(&zr->resource_lock);
+
+	return 0;
+}
+
+static int zoran_s_jpegcomp(struct file *file, void *__fh,
+					struct v4l2_jpegcompression *params)
+{
+	struct zoran_fh *fh = __fh;
+	struct zoran *zr = fh->zr;
+	int res = 0;
+	struct zoran_jpg_settings settings;
+
+	settings = fh->jpg_settings;
+
+	settings.jpg_comp = *params;
+
+	mutex_lock(&zr->resource_lock);
+
+	if (fh->buffers.active != ZORAN_FREE) {
+		dprintk(1, KERN_WARNING
+			"%s: VIDIOC_S_JPEGCOMP called while in playback/capture mode\n",
+			ZR_DEVNAME(zr));
+		res = -EBUSY;
+		goto sjpegc_unlock_and_return;
+	}
+
+	res = zoran_check_jpg_settings(zr, &settings, 0);
+	if (res)
+		goto sjpegc_unlock_and_return;
+	if (!fh->buffers.allocated)
+		fh->buffers.buffer_size =
+			zoran_v4l2_calc_bufsize(&fh->jpg_settings);
+	fh->jpg_settings.jpg_comp = *params = settings.jpg_comp;
+sjpegc_unlock_and_return:
+	mutex_unlock(&zr->resource_lock);
+
+	return res;
+}
+
+static unsigned int
+zoran_poll (struct file *file,
+	    poll_table  *wait)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	int res = 0, frame;
+	unsigned long flags;
+
+	/* we should check whether buffers are ready to be synced on
+	 * (w/o waits - O_NONBLOCK) here
+	 * if ready for read (sync), return POLLIN|POLLRDNORM,
+	 * if ready for write (sync), return POLLOUT|POLLWRNORM,
+	 * if error, return POLLERR,
+	 * if no buffers queued or so, return POLLNVAL
+	 */
+
+	mutex_lock(&zr->resource_lock);
+
+	switch (fh->map_mode) {
+	case ZORAN_MAP_MODE_RAW:
+		poll_wait(file, &zr->v4l_capq, wait);
+		frame = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME];
+
+		spin_lock_irqsave(&zr->spinlock, flags);
+		dprintk(3,
+			KERN_DEBUG
+			"%s: %s() raw - active=%c, sync_tail=%lu/%c, pend_tail=%lu, pend_head=%lu\n",
+			ZR_DEVNAME(zr), __func__,
+			"FAL"[fh->buffers.active], zr->v4l_sync_tail,
+			"UPMD"[zr->v4l_buffers.buffer[frame].state],
+			zr->v4l_pend_tail, zr->v4l_pend_head);
+		/* Process is the one capturing? */
+		if (fh->buffers.active != ZORAN_FREE &&
+		    /* Buffer ready to DQBUF? */
+		    zr->v4l_buffers.buffer[frame].state == BUZ_STATE_DONE)
+			res = POLLIN | POLLRDNORM;
+		spin_unlock_irqrestore(&zr->spinlock, flags);
+
+		break;
+
+	case ZORAN_MAP_MODE_JPG_REC:
+	case ZORAN_MAP_MODE_JPG_PLAY:
+		poll_wait(file, &zr->jpg_capq, wait);
+		frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
+
+		spin_lock_irqsave(&zr->spinlock, flags);
+		dprintk(3,
+			KERN_DEBUG
+			"%s: %s() jpg - active=%c, que_tail=%lu/%c, que_head=%lu, dma=%lu/%lu\n",
+			ZR_DEVNAME(zr), __func__,
+			"FAL"[fh->buffers.active], zr->jpg_que_tail,
+			"UPMD"[zr->jpg_buffers.buffer[frame].state],
+			zr->jpg_que_head, zr->jpg_dma_tail, zr->jpg_dma_head);
+		if (fh->buffers.active != ZORAN_FREE &&
+		    zr->jpg_buffers.buffer[frame].state == BUZ_STATE_DONE) {
+			if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC)
+				res = POLLIN | POLLRDNORM;
+			else
+				res = POLLOUT | POLLWRNORM;
+		}
+		spin_unlock_irqrestore(&zr->spinlock, flags);
+
+		break;
+
+	default:
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - internal error, unknown map_mode=%d\n",
+			ZR_DEVNAME(zr), __func__, fh->map_mode);
+		res = POLLNVAL;
+	}
+
+	mutex_unlock(&zr->resource_lock);
+
+	return res;
+}
+
+
+/*
+ * This maps the buffers to user space.
+ *
+ * Depending on the state of fh->map_mode
+ * the V4L or the MJPEG buffers are mapped
+ * per buffer or all together
+ *
+ * Note that we need to connect to some
+ * unmap signal event to unmap the de-allocate
+ * the buffer accordingly (zoran_vm_close())
+ */
+
+static void
+zoran_vm_open (struct vm_area_struct *vma)
+{
+	struct zoran_mapping *map = vma->vm_private_data;
+
+	map->count++;
+}
+
+static void
+zoran_vm_close (struct vm_area_struct *vma)
+{
+	struct zoran_mapping *map = vma->vm_private_data;
+	struct zoran_fh *fh = map->fh;
+	struct zoran *zr = fh->zr;
+	int i;
+
+	if (--map->count > 0)
+		return;
+
+	dprintk(3, KERN_INFO "%s: %s - munmap(%s)\n", ZR_DEVNAME(zr),
+		__func__, mode_name(fh->map_mode));
+
+	for (i = 0; i < fh->buffers.num_buffers; i++) {
+		if (fh->buffers.buffer[i].map == map)
+			fh->buffers.buffer[i].map = NULL;
+	}
+	kfree(map);
+
+	/* Any buffers still mapped? */
+	for (i = 0; i < fh->buffers.num_buffers; i++)
+		if (fh->buffers.buffer[i].map)
+			return;
+
+	dprintk(3, KERN_INFO "%s: %s - free %s buffers\n", ZR_DEVNAME(zr),
+		__func__, mode_name(fh->map_mode));
+
+	mutex_lock(&zr->resource_lock);
+
+	if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
+		if (fh->buffers.active != ZORAN_FREE) {
+			unsigned long flags;
+
+			spin_lock_irqsave(&zr->spinlock, flags);
+			zr36057_set_memgrab(zr, 0);
+			zr->v4l_buffers.allocated = 0;
+			zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE;
+			spin_unlock_irqrestore(&zr->spinlock, flags);
+		}
+		v4l_fbuffer_free(fh);
+	} else {
+		if (fh->buffers.active != ZORAN_FREE) {
+			jpg_qbuf(fh, -1, zr->codec_mode);
+			zr->jpg_buffers.allocated = 0;
+			zr->jpg_buffers.active = fh->buffers.active = ZORAN_FREE;
+		}
+		jpg_fbuffer_free(fh);
+	}
+
+	mutex_unlock(&zr->resource_lock);
+}
+
+static const struct vm_operations_struct zoran_vm_ops = {
+	.open = zoran_vm_open,
+	.close = zoran_vm_close,
+};
+
+static int
+zoran_mmap (struct file           *file,
+	    struct vm_area_struct *vma)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	unsigned long size = (vma->vm_end - vma->vm_start);
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	int i, j;
+	unsigned long page, start = vma->vm_start, todo, pos, fraglen;
+	int first, last;
+	struct zoran_mapping *map;
+	int res = 0;
+
+	dprintk(3,
+		KERN_INFO "%s: %s(%s) of 0x%08lx-0x%08lx (size=%lu)\n",
+		ZR_DEVNAME(zr), __func__,
+		mode_name(fh->map_mode), vma->vm_start, vma->vm_end, size);
+
+	if (!(vma->vm_flags & VM_SHARED) || !(vma->vm_flags & VM_READ) ||
+	    !(vma->vm_flags & VM_WRITE)) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s - no MAP_SHARED/PROT_{READ,WRITE} given\n",
+			ZR_DEVNAME(zr), __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&zr->resource_lock);
+
+	if (!fh->buffers.allocated) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s(%s) - buffers not yet allocated\n",
+			ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode));
+		res = -ENOMEM;
+		goto mmap_unlock_and_return;
+	}
+
+	first = offset / fh->buffers.buffer_size;
+	last = first - 1 + size / fh->buffers.buffer_size;
+	if (offset % fh->buffers.buffer_size != 0 ||
+	    size % fh->buffers.buffer_size != 0 || first < 0 ||
+	    last < 0 || first >= fh->buffers.num_buffers ||
+	    last >= fh->buffers.buffer_size) {
+		dprintk(1,
+			KERN_ERR
+			"%s: %s(%s) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n",
+			ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode), offset, size,
+			fh->buffers.buffer_size,
+			fh->buffers.num_buffers);
+		res = -EINVAL;
+		goto mmap_unlock_and_return;
+	}
+
+	/* Check if any buffers are already mapped */
+	for (i = first; i <= last; i++) {
+		if (fh->buffers.buffer[i].map) {
+			dprintk(1,
+				KERN_ERR
+				"%s: %s(%s) - buffer %d already mapped\n",
+				ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode), i);
+			res = -EBUSY;
+			goto mmap_unlock_and_return;
+		}
+	}
+
+	/* map these buffers */
+	map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL);
+	if (!map) {
+		res = -ENOMEM;
+		goto mmap_unlock_and_return;
+	}
+	map->fh = fh;
+	map->count = 1;
+
+	vma->vm_ops = &zoran_vm_ops;
+	vma->vm_flags |= VM_DONTEXPAND;
+	vma->vm_private_data = map;
+
+	if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
+		for (i = first; i <= last; i++) {
+			todo = size;
+			if (todo > fh->buffers.buffer_size)
+				todo = fh->buffers.buffer_size;
+			page = fh->buffers.buffer[i].v4l.fbuffer_phys;
+			if (remap_pfn_range(vma, start, page >> PAGE_SHIFT,
+							todo, PAGE_SHARED)) {
+				dprintk(1,
+					KERN_ERR
+					"%s: %s(V4L) - remap_pfn_range failed\n",
+					ZR_DEVNAME(zr), __func__);
+				res = -EAGAIN;
+				goto mmap_unlock_and_return;
+			}
+			size -= todo;
+			start += todo;
+			fh->buffers.buffer[i].map = map;
+			if (size == 0)
+				break;
+		}
+	} else {
+		for (i = first; i <= last; i++) {
+			for (j = 0;
+			     j < fh->buffers.buffer_size / PAGE_SIZE;
+			     j++) {
+				fraglen =
+				    (le32_to_cpu(fh->buffers.buffer[i].jpg.
+				     frag_tab[2 * j + 1]) & ~1) << 1;
+				todo = size;
+				if (todo > fraglen)
+					todo = fraglen;
+				pos =
+				    le32_to_cpu(fh->buffers.
+				    buffer[i].jpg.frag_tab[2 * j]);
+				/* should just be pos on i386 */
+				page = virt_to_phys(bus_to_virt(pos))
+								>> PAGE_SHIFT;
+				if (remap_pfn_range(vma, start, page,
+							todo, PAGE_SHARED)) {
+					dprintk(1,
+						KERN_ERR
+						"%s: %s(V4L) - remap_pfn_range failed\n",
+						ZR_DEVNAME(zr), __func__);
+					res = -EAGAIN;
+					goto mmap_unlock_and_return;
+				}
+				size -= todo;
+				start += todo;
+				if (size == 0)
+					break;
+				if (le32_to_cpu(fh->buffers.buffer[i].jpg.
+				    frag_tab[2 * j + 1]) & 1)
+					break;	/* was last fragment */
+			}
+			fh->buffers.buffer[i].map = map;
+			if (size == 0)
+				break;
+
+		}
+	}
+
+mmap_unlock_and_return:
+	mutex_unlock(&zr->resource_lock);
+
+	return res;
+}
+
+static const struct v4l2_ioctl_ops zoran_ioctl_ops = {
+	.vidioc_querycap    		    = zoran_querycap,
+	.vidioc_cropcap       		    = zoran_cropcap,
+	.vidioc_s_crop       		    = zoran_s_crop,
+	.vidioc_g_crop       		    = zoran_g_crop,
+	.vidioc_enum_input     		    = zoran_enum_input,
+	.vidioc_g_input      		    = zoran_g_input,
+	.vidioc_s_input      		    = zoran_s_input,
+	.vidioc_enum_output    		    = zoran_enum_output,
+	.vidioc_g_output     		    = zoran_g_output,
+	.vidioc_s_output     		    = zoran_s_output,
+	.vidioc_g_fbuf			    = zoran_g_fbuf,
+	.vidioc_s_fbuf			    = zoran_s_fbuf,
+	.vidioc_g_std 			    = zoran_g_std,
+	.vidioc_s_std 			    = zoran_s_std,
+	.vidioc_g_jpegcomp 		    = zoran_g_jpegcomp,
+	.vidioc_s_jpegcomp 		    = zoran_s_jpegcomp,
+	.vidioc_overlay			    = zoran_overlay,
+	.vidioc_reqbufs			    = zoran_reqbufs,
+	.vidioc_querybuf		    = zoran_querybuf,
+	.vidioc_qbuf			    = zoran_qbuf,
+	.vidioc_dqbuf			    = zoran_dqbuf,
+	.vidioc_streamon		    = zoran_streamon,
+	.vidioc_streamoff		    = zoran_streamoff,
+	.vidioc_enum_fmt_vid_cap 	    = zoran_enum_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_out 	    = zoran_enum_fmt_vid_out,
+	.vidioc_enum_fmt_vid_overlay 	    = zoran_enum_fmt_vid_overlay,
+	.vidioc_g_fmt_vid_cap 		    = zoran_g_fmt_vid_cap,
+	.vidioc_g_fmt_vid_out               = zoran_g_fmt_vid_out,
+	.vidioc_g_fmt_vid_overlay           = zoran_g_fmt_vid_overlay,
+	.vidioc_s_fmt_vid_cap  		    = zoran_s_fmt_vid_cap,
+	.vidioc_s_fmt_vid_out               = zoran_s_fmt_vid_out,
+	.vidioc_s_fmt_vid_overlay           = zoran_s_fmt_vid_overlay,
+	.vidioc_try_fmt_vid_cap  	    = zoran_try_fmt_vid_cap,
+	.vidioc_try_fmt_vid_out 	    = zoran_try_fmt_vid_out,
+	.vidioc_try_fmt_vid_overlay 	    = zoran_try_fmt_vid_overlay,
+	.vidioc_queryctrl 		    = zoran_queryctrl,
+	.vidioc_s_ctrl       		    = zoran_s_ctrl,
+	.vidioc_g_ctrl       		    = zoran_g_ctrl,
+};
+
+/* please use zr->resource_lock consistently and kill this wrapper */
+static long zoran_ioctl(struct file *file, unsigned int cmd,
+			unsigned long arg)
+{
+	struct zoran_fh *fh = file->private_data;
+	struct zoran *zr = fh->zr;
+	int ret;
+
+	mutex_lock(&zr->other_lock);
+	ret = video_ioctl2(file, cmd, arg);
+	mutex_unlock(&zr->other_lock);
+
+	return ret;
+}
+
+static const struct v4l2_file_operations zoran_fops = {
+	.owner = THIS_MODULE,
+	.open = zoran_open,
+	.release = zoran_close,
+	.unlocked_ioctl = zoran_ioctl,
+	.read = zoran_read,
+	.write = zoran_write,
+	.mmap = zoran_mmap,
+	.poll = zoran_poll,
+};
+
+struct video_device zoran_template __devinitdata = {
+	.name = ZORAN_NAME,
+	.fops = &zoran_fops,
+	.ioctl_ops = &zoran_ioctl_ops,
+	.release = &zoran_vdev_release,
+	.tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
+};
+
diff --git a/drivers/media/pci/zoran/zoran_procfs.c b/drivers/media/pci/zoran/zoran_procfs.c
new file mode 100644
index 0000000..f1423b7
--- /dev/null
+++ b/drivers/media/pci/zoran/zoran_procfs.c
@@ -0,0 +1,225 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * This part handles the procFS entries (/proc/ZORAN[%d])
+ *
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Currently maintained by:
+ *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
+ *   Laurent Pinchart <laurent.pinchart@skynet.be>
+ *   Mailinglist      <mjpeg-users@lists.sf.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/videodev2.h>
+#include <linux/spinlock.h>
+#include <linux/sem.h>
+#include <linux/seq_file.h>
+
+#include <linux/ctype.h>
+#include <linux/poll.h>
+#include <asm/io.h>
+
+#include "videocodec.h"
+#include "zoran.h"
+#include "zoran_procfs.h"
+#include "zoran_card.h"
+
+#ifdef CONFIG_PROC_FS
+struct procfs_params_zr36067 {
+	char *name;
+	short reg;
+	u32 mask;
+	short bit;
+};
+
+static const struct procfs_params_zr36067 zr67[] = {
+	{"HSPol", 0x000, 1, 30},
+	{"HStart", 0x000, 0x3ff, 10},
+	{"HEnd", 0x000, 0x3ff, 0},
+
+	{"VSPol", 0x004, 1, 30},
+	{"VStart", 0x004, 0x3ff, 10},
+	{"VEnd", 0x004, 0x3ff, 0},
+
+	{"ExtFl", 0x008, 1, 26},
+	{"TopField", 0x008, 1, 25},
+	{"VCLKPol", 0x008, 1, 24},
+	{"DupFld", 0x008, 1, 20},
+	{"LittleEndian", 0x008, 1, 0},
+
+	{"HsyncStart", 0x10c, 0xffff, 16},
+	{"LineTot", 0x10c, 0xffff, 0},
+
+	{"NAX", 0x110, 0xffff, 16},
+	{"PAX", 0x110, 0xffff, 0},
+
+	{"NAY", 0x114, 0xffff, 16},
+	{"PAY", 0x114, 0xffff, 0},
+
+	/* {"",,,}, */
+
+	{NULL, 0, 0, 0},
+};
+
+static void
+setparam (struct zoran *zr,
+	  char         *name,
+	  char         *sval)
+{
+	int i = 0, reg0, reg, val;
+
+	while (zr67[i].name != NULL) {
+		if (!strncmp(name, zr67[i].name, strlen(zr67[i].name))) {
+			reg = reg0 = btread(zr67[i].reg);
+			reg &= ~(zr67[i].mask << zr67[i].bit);
+			if (!isdigit(sval[0]))
+				break;
+			val = simple_strtoul(sval, NULL, 0);
+			if ((val & ~zr67[i].mask))
+				break;
+			reg |= (val & zr67[i].mask) << zr67[i].bit;
+			dprintk(4,
+				KERN_INFO
+				"%s: setparam: setting ZR36067 register 0x%03x: 0x%08x=>0x%08x %s=%d\n",
+				ZR_DEVNAME(zr), zr67[i].reg, reg0, reg,
+				zr67[i].name, val);
+			btwrite(reg, zr67[i].reg);
+			break;
+		}
+		i++;
+	}
+}
+
+static int zoran_show(struct seq_file *p, void *v)
+{
+	struct zoran *zr = p->private;
+	int i;
+
+	seq_printf(p, "ZR36067 registers:\n");
+	for (i = 0; i < 0x130; i += 16)
+		seq_printf(p, "%03X %08X  %08X  %08X  %08X \n", i,
+			   btread(i), btread(i+4), btread(i+8), btread(i+12));
+	return 0;
+}
+
+static int zoran_open(struct inode *inode, struct file *file)
+{
+	struct zoran *data = PDE(inode)->data;
+	return single_open(file, zoran_show, data);
+}
+
+static ssize_t zoran_write(struct file *file, const char __user *buffer,
+			size_t count, loff_t *ppos)
+{
+	struct zoran *zr = PDE(file->f_path.dentry->d_inode)->data;
+	char *string, *sp;
+	char *line, *ldelim, *varname, *svar, *tdelim;
+
+	if (count > 32768)	/* Stupidity filter */
+		return -EINVAL;
+
+	string = sp = vmalloc(count + 1);
+	if (!string) {
+		dprintk(1,
+			KERN_ERR
+			"%s: write_proc: can not allocate memory\n",
+			ZR_DEVNAME(zr));
+		return -ENOMEM;
+	}
+	if (copy_from_user(string, buffer, count)) {
+		vfree (string);
+		return -EFAULT;
+	}
+	string[count] = 0;
+	dprintk(4, KERN_INFO "%s: write_proc: name=%s count=%zu zr=%p\n",
+		ZR_DEVNAME(zr), file->f_path.dentry->d_name.name, count, zr);
+	ldelim = " \t\n";
+	tdelim = "=";
+	line = strpbrk(sp, ldelim);
+	while (line) {
+		*line = 0;
+		svar = strpbrk(sp, tdelim);
+		if (svar) {
+			*svar = 0;
+			varname = sp;
+			svar++;
+			setparam(zr, varname, svar);
+		}
+		sp = line + 1;
+		line = strpbrk(sp, ldelim);
+	}
+	vfree(string);
+
+	return count;
+}
+
+static const struct file_operations zoran_operations = {
+	.owner		= THIS_MODULE,
+	.open		= zoran_open,
+	.read		= seq_read,
+	.write		= zoran_write,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+#endif
+
+int
+zoran_proc_init (struct zoran *zr)
+{
+#ifdef CONFIG_PROC_FS
+	char name[8];
+
+	snprintf(name, 7, "zoran%d", zr->id);
+	zr->zoran_proc = proc_create_data(name, 0, NULL, &zoran_operations, zr);
+	if (zr->zoran_proc != NULL) {
+		dprintk(2,
+			KERN_INFO
+			"%s: procfs entry /proc/%s allocated. data=%p\n",
+			ZR_DEVNAME(zr), name, zr->zoran_proc->data);
+	} else {
+		dprintk(1, KERN_ERR "%s: Unable to initialise /proc/%s\n",
+			ZR_DEVNAME(zr), name);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+void
+zoran_proc_cleanup (struct zoran *zr)
+{
+#ifdef CONFIG_PROC_FS
+	char name[8];
+
+	snprintf(name, 7, "zoran%d", zr->id);
+	if (zr->zoran_proc)
+		remove_proc_entry(name, NULL);
+	zr->zoran_proc = NULL;
+#endif
+}
diff --git a/drivers/media/pci/zoran/zoran_procfs.h b/drivers/media/pci/zoran/zoran_procfs.h
new file mode 100644
index 0000000..f2d5b1b
--- /dev/null
+++ b/drivers/media/pci/zoran/zoran_procfs.h
@@ -0,0 +1,36 @@
+/*
+ * Zoran zr36057/zr36067 PCI controller driver, for the
+ * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
+ * Media Labs LML33/LML33R10.
+ *
+ * This part handles card-specific data and detection
+ *
+ * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+ *
+ * Currently maintained by:
+ *   Ronald Bultje    <rbultje@ronald.bitfreak.net>
+ *   Laurent Pinchart <laurent.pinchart@skynet.be>
+ *   Mailinglist      <mjpeg-users@lists.sf.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ZORAN_PROCFS_H__
+#define __ZORAN_PROCFS_H__
+
+extern int zoran_proc_init(struct zoran *zr);
+extern void zoran_proc_cleanup(struct zoran *zr);
+
+#endif				/* __ZORAN_PROCFS_H__ */
diff --git a/drivers/media/pci/zoran/zr36016.c b/drivers/media/pci/zoran/zr36016.c
new file mode 100644
index 0000000..b87ddba
--- /dev/null
+++ b/drivers/media/pci/zoran/zr36016.c
@@ -0,0 +1,524 @@
+/*
+ * Zoran ZR36016 basic configuration functions
+ *
+ * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at>
+ *
+ * $Id: zr36016.c,v 1.1.2.14 2003/08/20 19:46:55 rbultje Exp $
+ *
+ * ------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * ------------------------------------------------------------------------
+ */
+
+#define ZR016_VERSION "v0.7"
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <linux/types.h>
+#include <linux/wait.h>
+
+/* I/O commands, error codes */
+#include <asm/io.h>
+
+/* v4l  API */
+
+/* headerfile of this module */
+#include "zr36016.h"
+
+/* codec io API */
+#include "videocodec.h"
+
+/* it doesn't make sense to have more than 20 or so,
+  just to prevent some unwanted loops */
+#define MAX_CODECS 20
+
+/* amount of chips attached via this driver */
+static int zr36016_codecs;
+
+/* debugging is available via module parameter */
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-4)");
+
+#define dprintk(num, format, args...) \
+	do { \
+		if (debug >= num) \
+			printk(format, ##args); \
+	} while (0)
+
+/* =========================================================================
+   Local hardware I/O functions:
+
+   read/write via codec layer (registers are located in the master device)
+   ========================================================================= */
+
+/* read and write functions */
+static u8
+zr36016_read (struct zr36016 *ptr,
+	      u16             reg)
+{
+	u8 value = 0;
+
+	// just in case something is wrong...
+	if (ptr->codec->master_data->readreg)
+		value =
+		    (ptr->codec->master_data->
+		     readreg(ptr->codec, reg)) & 0xFF;
+	else
+		dprintk(1,
+			KERN_ERR "%s: invalid I/O setup, nothing read!\n",
+			ptr->name);
+
+	dprintk(4, "%s: reading from 0x%04x: %02x\n", ptr->name, reg,
+		value);
+
+	return value;
+}
+
+static void
+zr36016_write (struct zr36016 *ptr,
+	       u16             reg,
+	       u8              value)
+{
+	dprintk(4, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value,
+		reg);
+
+	// just in case something is wrong...
+	if (ptr->codec->master_data->writereg) {
+		ptr->codec->master_data->writereg(ptr->codec, reg, value);
+	} else
+		dprintk(1,
+			KERN_ERR
+			"%s: invalid I/O setup, nothing written!\n",
+			ptr->name);
+}
+
+/* indirect read and write functions */
+/* the 016 supports auto-addr-increment, but
+ * writing it all time cost not much and is safer... */
+static u8
+zr36016_readi (struct zr36016 *ptr,
+	       u16             reg)
+{
+	u8 value = 0;
+
+	// just in case something is wrong...
+	if ((ptr->codec->master_data->writereg) &&
+	    (ptr->codec->master_data->readreg)) {
+		ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F);	// ADDR
+		value = (ptr->codec->master_data->readreg(ptr->codec, ZR016_IDATA)) & 0xFF;	// DATA
+	} else
+		dprintk(1,
+			KERN_ERR
+			"%s: invalid I/O setup, nothing read (i)!\n",
+			ptr->name);
+
+	dprintk(4, "%s: reading indirect from 0x%04x: %02x\n", ptr->name,
+		reg, value);
+	return value;
+}
+
+static void
+zr36016_writei (struct zr36016 *ptr,
+		u16             reg,
+		u8              value)
+{
+	dprintk(4, "%s: writing indirect 0x%02x to 0x%04x\n", ptr->name,
+		value, reg);
+
+	// just in case something is wrong...
+	if (ptr->codec->master_data->writereg) {
+		ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F);	// ADDR
+		ptr->codec->master_data->writereg(ptr->codec, ZR016_IDATA, value & 0x0FF);	// DATA
+	} else
+		dprintk(1,
+			KERN_ERR
+			"%s: invalid I/O setup, nothing written (i)!\n",
+			ptr->name);
+}
+
+/* =========================================================================
+   Local helper function:
+
+   version read
+   ========================================================================= */
+
+/* version kept in datastructure */
+static u8
+zr36016_read_version (struct zr36016 *ptr)
+{
+	ptr->version = zr36016_read(ptr, 0) >> 4;
+	return ptr->version;
+}
+
+/* =========================================================================
+   Local helper function:
+
+   basic test of "connectivity", writes/reads to/from PAX-Lo register
+   ========================================================================= */
+
+static int
+zr36016_basic_test (struct zr36016 *ptr)
+{
+	if (debug) {
+		int i;
+		zr36016_writei(ptr, ZR016I_PAX_LO, 0x55);
+		dprintk(1, KERN_INFO "%s: registers: ", ptr->name);
+		for (i = 0; i <= 0x0b; i++)
+			dprintk(1, "%02x ", zr36016_readi(ptr, i));
+		dprintk(1, "\n");
+	}
+	// for testing just write 0, then the default value to a register and read
+	// it back in both cases
+	zr36016_writei(ptr, ZR016I_PAX_LO, 0x00);
+	if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0) {
+		dprintk(1,
+			KERN_ERR
+			"%s: attach failed, can't connect to vfe processor!\n",
+			ptr->name);
+		return -ENXIO;
+	}
+	zr36016_writei(ptr, ZR016I_PAX_LO, 0x0d0);
+	if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0d0) {
+		dprintk(1,
+			KERN_ERR
+			"%s: attach failed, can't connect to vfe processor!\n",
+			ptr->name);
+		return -ENXIO;
+	}
+	// we allow version numbers from 0-3, should be enough, though
+	zr36016_read_version(ptr);
+	if (ptr->version & 0x0c) {
+		dprintk(1,
+			KERN_ERR
+			"%s: attach failed, suspicious version %d found...\n",
+			ptr->name, ptr->version);
+		return -ENXIO;
+	}
+
+	return 0;		/* looks good! */
+}
+
+/* =========================================================================
+   Local helper function:
+
+   simple loop for pushing the init datasets - NO USE --
+   ========================================================================= */
+
+#if 0
+static int zr36016_pushit (struct zr36016 *ptr,
+			   u16             startreg,
+			   u16             len,
+			   const char     *data)
+{
+	int i=0;
+
+	dprintk(4, "%s: write data block to 0x%04x (len=%d)\n",
+		ptr->name, startreg,len);
+	while (i<len) {
+		zr36016_writei(ptr, startreg++,  data[i++]);
+	}
+
+	return i;
+}
+#endif
+
+/* =========================================================================
+   Basic datasets & init:
+
+   //TODO//
+   ========================================================================= */
+
+// needed offset values          PAL NTSC SECAM
+static const int zr016_xoff[] = { 20, 20, 20 };
+static const int zr016_yoff[] = { 8, 9, 7 };
+
+static void
+zr36016_init (struct zr36016 *ptr)
+{
+	// stop any processing
+	zr36016_write(ptr, ZR016_GOSTOP, 0);
+
+	// mode setup (yuv422 in and out, compression/expansuon due to mode)
+	zr36016_write(ptr, ZR016_MODE,
+		      ZR016_YUV422 | ZR016_YUV422_YUV422 |
+		      (ptr->mode == CODEC_DO_COMPRESSION ?
+		       ZR016_COMPRESSION : ZR016_EXPANSION));
+
+	// misc setup
+	zr36016_writei(ptr, ZR016I_SETUP1,
+		       (ptr->xdec ? (ZR016_HRFL | ZR016_HORZ) : 0) |
+		       (ptr->ydec ? ZR016_VERT : 0) | ZR016_CNTI);
+	zr36016_writei(ptr, ZR016I_SETUP2, ZR016_CCIR);
+
+	// Window setup
+	// (no extra offset for now, norm defines offset, default width height)
+	zr36016_writei(ptr, ZR016I_PAX_HI, ptr->width >> 8);
+	zr36016_writei(ptr, ZR016I_PAX_LO, ptr->width & 0xFF);
+	zr36016_writei(ptr, ZR016I_PAY_HI, ptr->height >> 8);
+	zr36016_writei(ptr, ZR016I_PAY_LO, ptr->height & 0xFF);
+	zr36016_writei(ptr, ZR016I_NAX_HI, ptr->xoff >> 8);
+	zr36016_writei(ptr, ZR016I_NAX_LO, ptr->xoff & 0xFF);
+	zr36016_writei(ptr, ZR016I_NAY_HI, ptr->yoff >> 8);
+	zr36016_writei(ptr, ZR016I_NAY_LO, ptr->yoff & 0xFF);
+
+	/* shall we continue now, please? */
+	zr36016_write(ptr, ZR016_GOSTOP, 1);
+}
+
+/* =========================================================================
+   CODEC API FUNCTIONS
+
+   this functions are accessed by the master via the API structure
+   ========================================================================= */
+
+/* set compression/expansion mode and launches codec -
+   this should be the last call from the master before starting processing */
+static int
+zr36016_set_mode (struct videocodec *codec,
+		  int                mode)
+{
+	struct zr36016 *ptr = (struct zr36016 *) codec->data;
+
+	dprintk(2, "%s: set_mode %d call\n", ptr->name, mode);
+
+	if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION))
+		return -EINVAL;
+
+	ptr->mode = mode;
+	zr36016_init(ptr);
+
+	return 0;
+}
+
+/* set picture size */
+static int
+zr36016_set_video (struct videocodec   *codec,
+		   struct tvnorm       *norm,
+		   struct vfe_settings *cap,
+		   struct vfe_polarity *pol)
+{
+	struct zr36016 *ptr = (struct zr36016 *) codec->data;
+
+	dprintk(2, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) call\n",
+		ptr->name, norm->HStart, norm->VStart,
+		cap->x, cap->y, cap->width, cap->height,
+		cap->decimation);
+
+	/* if () return -EINVAL;
+	 * trust the master driver that it knows what it does - so
+	 * we allow invalid startx/y for now ... */
+	ptr->width = cap->width;
+	ptr->height = cap->height;
+	/* (Ronald) This is ugly. zoran_device.c, line 387
+	 * already mentions what happens if HStart is even
+	 * (blue faces, etc., cr/cb inversed). There's probably
+	 * some good reason why HStart is 0 instead of 1, so I'm
+	 * leaving it to this for now, but really... This can be
+	 * done a lot simpler */
+	ptr->xoff = (norm->HStart ? norm->HStart : 1) + cap->x;
+	/* Something to note here (I don't understand it), setting
+	 * VStart too high will cause the codec to 'not work'. I
+	 * really don't get it. values of 16 (VStart) already break
+	 * it here. Just '0' seems to work. More testing needed! */
+	ptr->yoff = norm->VStart + cap->y;
+	/* (Ronald) dzjeeh, can't this thing do hor_decimation = 4? */
+	ptr->xdec = ((cap->decimation & 0xff) == 1) ? 0 : 1;
+	ptr->ydec = (((cap->decimation >> 8) & 0xff) == 1) ? 0 : 1;
+
+	return 0;
+}
+
+/* additional control functions */
+static int
+zr36016_control (struct videocodec *codec,
+		 int                type,
+		 int                size,
+		 void              *data)
+{
+	struct zr36016 *ptr = (struct zr36016 *) codec->data;
+	int *ival = (int *) data;
+
+	dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type,
+		size);
+
+	switch (type) {
+	case CODEC_G_STATUS:	/* get last status - we don't know it ... */
+		if (size != sizeof(int))
+			return -EFAULT;
+		*ival = 0;
+		break;
+
+	case CODEC_G_CODEC_MODE:
+		if (size != sizeof(int))
+			return -EFAULT;
+		*ival = 0;
+		break;
+
+	case CODEC_S_CODEC_MODE:
+		if (size != sizeof(int))
+			return -EFAULT;
+		if (*ival != 0)
+			return -EINVAL;
+		/* not needed, do nothing */
+		return 0;
+
+	case CODEC_G_VFE:
+	case CODEC_S_VFE:
+		return 0;
+
+	case CODEC_S_MMAP:
+		/* not available, give an error */
+		return -ENXIO;
+
+	default:
+		return -EINVAL;
+	}
+
+	return size;
+}
+
+/* =========================================================================
+   Exit and unregister function:
+
+   Deinitializes Zoran's JPEG processor
+   ========================================================================= */
+
+static int
+zr36016_unset (struct videocodec *codec)
+{
+	struct zr36016 *ptr = codec->data;
+
+	if (ptr) {
+		/* do wee need some codec deinit here, too ???? */
+
+		dprintk(1, "%s: finished codec #%d\n", ptr->name,
+			ptr->num);
+		kfree(ptr);
+		codec->data = NULL;
+
+		zr36016_codecs--;
+		return 0;
+	}
+
+	return -EFAULT;
+}
+
+/* =========================================================================
+   Setup and registry function:
+
+   Initializes Zoran's JPEG processor
+
+   Also sets pixel size, average code size, mode (compr./decompr.)
+   (the given size is determined by the processor with the video interface)
+   ========================================================================= */
+
+static int
+zr36016_setup (struct videocodec *codec)
+{
+	struct zr36016 *ptr;
+	int res;
+
+	dprintk(2, "zr36016: initializing VFE subsystem #%d.\n",
+		zr36016_codecs);
+
+	if (zr36016_codecs == MAX_CODECS) {
+		dprintk(1,
+			KERN_ERR "zr36016: Can't attach more codecs!\n");
+		return -ENOSPC;
+	}
+	//mem structure init
+	codec->data = ptr = kzalloc(sizeof(struct zr36016), GFP_KERNEL);
+	if (NULL == ptr) {
+		dprintk(1, KERN_ERR "zr36016: Can't get enough memory!\n");
+		return -ENOMEM;
+	}
+
+	snprintf(ptr->name, sizeof(ptr->name), "zr36016[%d]",
+		 zr36016_codecs);
+	ptr->num = zr36016_codecs++;
+	ptr->codec = codec;
+
+	//testing
+	res = zr36016_basic_test(ptr);
+	if (res < 0) {
+		zr36016_unset(codec);
+		return res;
+	}
+	//final setup
+	ptr->mode = CODEC_DO_COMPRESSION;
+	ptr->width = 768;
+	ptr->height = 288;
+	ptr->xdec = 1;
+	ptr->ydec = 0;
+	zr36016_init(ptr);
+
+	dprintk(1, KERN_INFO "%s: codec v%d attached and running\n",
+		ptr->name, ptr->version);
+
+	return 0;
+}
+
+static const struct videocodec zr36016_codec = {
+	.owner = THIS_MODULE,
+	.name = "zr36016",
+	.magic = 0L,		// magic not used
+	.flags =
+	    CODEC_FLAG_HARDWARE | CODEC_FLAG_VFE | CODEC_FLAG_ENCODER |
+	    CODEC_FLAG_DECODER,
+	.type = CODEC_TYPE_ZR36016,
+	.setup = zr36016_setup,	// functionality
+	.unset = zr36016_unset,
+	.set_mode = zr36016_set_mode,
+	.set_video = zr36016_set_video,
+	.control = zr36016_control,
+	// others are not used
+};
+
+/* =========================================================================
+   HOOK IN DRIVER AS KERNEL MODULE
+   ========================================================================= */
+
+static int __init
+zr36016_init_module (void)
+{
+	//dprintk(1, "ZR36016 driver %s\n",ZR016_VERSION);
+	zr36016_codecs = 0;
+	return videocodec_register(&zr36016_codec);
+}
+
+static void __exit
+zr36016_cleanup_module (void)
+{
+	if (zr36016_codecs) {
+		dprintk(1,
+			"zr36016: something's wrong - %d codecs left somehow.\n",
+			zr36016_codecs);
+	}
+	videocodec_unregister(&zr36016_codec);
+}
+
+module_init(zr36016_init_module);
+module_exit(zr36016_cleanup_module);
+
+MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>");
+MODULE_DESCRIPTION("Driver module for ZR36016 video frontends "
+		   ZR016_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/zoran/zr36016.h b/drivers/media/pci/zoran/zr36016.h
new file mode 100644
index 0000000..8c79229
--- /dev/null
+++ b/drivers/media/pci/zoran/zr36016.h
@@ -0,0 +1,111 @@
+/*
+ * Zoran ZR36016 basic configuration functions - header file
+ *
+ * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at>
+ *
+ * $Id: zr36016.h,v 1.1.2.3 2003/01/14 21:18:07 rbultje Exp $
+ *
+ * ------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * ------------------------------------------------------------------------
+ */
+
+#ifndef ZR36016_H
+#define ZR36016_H
+
+/* data stored for each zoran jpeg codec chip */
+struct zr36016 {
+	char name[32];
+	int num;
+	/* io datastructure */
+	struct videocodec *codec;
+	// coder status
+	__u8 version;
+	// actual coder setup
+	int mode;
+
+	__u16 xoff;
+	__u16 yoff;
+	__u16 width;
+	__u16 height;
+	__u16 xdec;
+	__u16 ydec;
+};
+
+/* direct  register addresses */
+#define ZR016_GOSTOP      0x00
+#define ZR016_MODE        0x01
+#define ZR016_IADDR       0x02
+#define ZR016_IDATA       0x03
+
+/* indirect  register addresses */
+#define ZR016I_SETUP1     0x00
+#define ZR016I_SETUP2     0x01
+#define ZR016I_NAX_LO     0x02
+#define ZR016I_NAX_HI     0x03
+#define ZR016I_PAX_LO     0x04
+#define ZR016I_PAX_HI     0x05
+#define ZR016I_NAY_LO     0x06
+#define ZR016I_NAY_HI     0x07
+#define ZR016I_PAY_LO     0x08
+#define ZR016I_PAY_HI     0x09
+#define ZR016I_NOL_LO     0x0a
+#define ZR016I_NOL_HI     0x0b
+
+/* possible values for mode register */
+#define ZR016_RGB444_YUV444  0x00
+#define ZR016_RGB444_YUV422  0x01
+#define ZR016_RGB444_YUV411  0x02
+#define ZR016_RGB444_Y400    0x03
+#define ZR016_RGB444_RGB444  0x04
+#define ZR016_YUV444_YUV444  0x08
+#define ZR016_YUV444_YUV422  0x09
+#define ZR016_YUV444_YUV411  0x0a
+#define ZR016_YUV444_Y400    0x0b
+#define ZR016_YUV444_RGB444  0x0c
+#define ZR016_YUV422_YUV422  0x11
+#define ZR016_YUV422_YUV411  0x12
+#define ZR016_YUV422_Y400    0x13
+#define ZR016_YUV411_YUV411  0x16
+#define ZR016_YUV411_Y400    0x17
+#define ZR016_4444_4444      0x19
+#define ZR016_100_100        0x1b
+
+#define ZR016_RGB444         0x00
+#define ZR016_YUV444         0x20
+#define ZR016_YUV422         0x40
+
+#define ZR016_COMPRESSION    0x80
+#define ZR016_EXPANSION      0x80
+
+/* possible values for setup 1 register */
+#define ZR016_CKRT           0x80
+#define ZR016_VERT           0x40
+#define ZR016_HORZ           0x20
+#define ZR016_HRFL           0x10
+#define ZR016_DSFL           0x08
+#define ZR016_SBFL           0x04
+#define ZR016_RSTR           0x02
+#define ZR016_CNTI           0x01
+
+/* possible values for setup 2 register */
+#define ZR016_SYEN           0x40
+#define ZR016_CCIR           0x04
+#define ZR016_SIGN           0x02
+#define ZR016_YMCS           0x01
+
+#endif				/*fndef ZR36016_H */
diff --git a/drivers/media/pci/zoran/zr36050.c b/drivers/media/pci/zoran/zr36050.c
new file mode 100644
index 0000000..e198560
--- /dev/null
+++ b/drivers/media/pci/zoran/zr36050.c
@@ -0,0 +1,900 @@
+/*
+ * Zoran ZR36050 basic configuration functions
+ *
+ * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at>
+ *
+ * $Id: zr36050.c,v 1.1.2.11 2003/08/03 14:54:53 rbultje Exp $
+ *
+ * ------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * ------------------------------------------------------------------------
+ */
+
+#define ZR050_VERSION "v0.7.1"
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <linux/types.h>
+#include <linux/wait.h>
+
+/* I/O commands, error codes */
+#include <asm/io.h>
+
+/* headerfile of this module */
+#include "zr36050.h"
+
+/* codec io API */
+#include "videocodec.h"
+
+/* it doesn't make sense to have more than 20 or so,
+  just to prevent some unwanted loops */
+#define MAX_CODECS 20
+
+/* amount of chips attached via this driver */
+static int zr36050_codecs;
+
+/* debugging is available via module parameter */
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-4)");
+
+#define dprintk(num, format, args...) \
+	do { \
+		if (debug >= num) \
+			printk(format, ##args); \
+	} while (0)
+
+/* =========================================================================
+   Local hardware I/O functions:
+
+   read/write via codec layer (registers are located in the master device)
+   ========================================================================= */
+
+/* read and write functions */
+static u8
+zr36050_read (struct zr36050 *ptr,
+	      u16             reg)
+{
+	u8 value = 0;
+
+	// just in case something is wrong...
+	if (ptr->codec->master_data->readreg)
+		value = (ptr->codec->master_data->readreg(ptr->codec,
+							  reg)) & 0xFF;
+	else
+		dprintk(1,
+			KERN_ERR "%s: invalid I/O setup, nothing read!\n",
+			ptr->name);
+
+	dprintk(4, "%s: reading from 0x%04x: %02x\n", ptr->name, reg,
+		value);
+
+	return value;
+}
+
+static void
+zr36050_write (struct zr36050 *ptr,
+	       u16             reg,
+	       u8              value)
+{
+	dprintk(4, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value,
+		reg);
+
+	// just in case something is wrong...
+	if (ptr->codec->master_data->writereg)
+		ptr->codec->master_data->writereg(ptr->codec, reg, value);
+	else
+		dprintk(1,
+			KERN_ERR
+			"%s: invalid I/O setup, nothing written!\n",
+			ptr->name);
+}
+
+/* =========================================================================
+   Local helper function:
+
+   status read
+   ========================================================================= */
+
+/* status is kept in datastructure */
+static u8
+zr36050_read_status1 (struct zr36050 *ptr)
+{
+	ptr->status1 = zr36050_read(ptr, ZR050_STATUS_1);
+
+	zr36050_read(ptr, 0);
+	return ptr->status1;
+}
+
+/* =========================================================================
+   Local helper function:
+
+   scale factor read
+   ========================================================================= */
+
+/* scale factor is kept in datastructure */
+static u16
+zr36050_read_scalefactor (struct zr36050 *ptr)
+{
+	ptr->scalefact = (zr36050_read(ptr, ZR050_SF_HI) << 8) |
+			 (zr36050_read(ptr, ZR050_SF_LO) & 0xFF);
+
+	/* leave 0 selected for an eventually GO from master */
+	zr36050_read(ptr, 0);
+	return ptr->scalefact;
+}
+
+/* =========================================================================
+   Local helper function:
+
+   wait if codec is ready to proceed (end of processing) or time is over
+   ========================================================================= */
+
+static void
+zr36050_wait_end (struct zr36050 *ptr)
+{
+	int i = 0;
+
+	while (!(zr36050_read_status1(ptr) & 0x4)) {
+		udelay(1);
+		if (i++ > 200000) {	// 200ms, there is for sure something wrong!!!
+			dprintk(1,
+				"%s: timeout at wait_end (last status: 0x%02x)\n",
+				ptr->name, ptr->status1);
+			break;
+		}
+	}
+}
+
+/* =========================================================================
+   Local helper function:
+
+   basic test of "connectivity", writes/reads to/from memory the SOF marker
+   ========================================================================= */
+
+static int
+zr36050_basic_test (struct zr36050 *ptr)
+{
+	zr36050_write(ptr, ZR050_SOF_IDX, 0x00);
+	zr36050_write(ptr, ZR050_SOF_IDX + 1, 0x00);
+	if ((zr36050_read(ptr, ZR050_SOF_IDX) |
+	     zr36050_read(ptr, ZR050_SOF_IDX + 1)) != 0x0000) {
+		dprintk(1,
+			KERN_ERR
+			"%s: attach failed, can't connect to jpeg processor!\n",
+			ptr->name);
+		return -ENXIO;
+	}
+	zr36050_write(ptr, ZR050_SOF_IDX, 0xff);
+	zr36050_write(ptr, ZR050_SOF_IDX + 1, 0xc0);
+	if (((zr36050_read(ptr, ZR050_SOF_IDX) << 8) |
+	     zr36050_read(ptr, ZR050_SOF_IDX + 1)) != 0xffc0) {
+		dprintk(1,
+			KERN_ERR
+			"%s: attach failed, can't connect to jpeg processor!\n",
+			ptr->name);
+		return -ENXIO;
+	}
+
+	zr36050_wait_end(ptr);
+	if ((ptr->status1 & 0x4) == 0) {
+		dprintk(1,
+			KERN_ERR
+			"%s: attach failed, jpeg processor failed (end flag)!\n",
+			ptr->name);
+		return -EBUSY;
+	}
+
+	return 0;		/* looks good! */
+}
+
+/* =========================================================================
+   Local helper function:
+
+   simple loop for pushing the init datasets
+   ========================================================================= */
+
+static int
+zr36050_pushit (struct zr36050 *ptr,
+		u16             startreg,
+		u16             len,
+		const char     *data)
+{
+	int i = 0;
+
+	dprintk(4, "%s: write data block to 0x%04x (len=%d)\n", ptr->name,
+		startreg, len);
+	while (i < len) {
+		zr36050_write(ptr, startreg++, data[i++]);
+	}
+
+	return i;
+}
+
+/* =========================================================================
+   Basic datasets:
+
+   jpeg baseline setup data (you find it on lots places in internet, or just
+   extract it from any regular .jpg image...)
+
+   Could be variable, but until it's not needed it they are just fixed to save
+   memory. Otherwise expand zr36050 structure with arrays, push the values to
+   it and initialize from there, as e.g. the linux zr36057/60 driver does it.
+   ========================================================================= */
+
+static const char zr36050_dqt[0x86] = {
+	0xff, 0xdb,		//Marker: DQT
+	0x00, 0x84,		//Length: 2*65+2
+	0x00,			//Pq,Tq first table
+	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,
+	0x01,			//Pq,Tq second table
+	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
+};
+
+static const char zr36050_dht[0x1a4] = {
+	0xff, 0xc4,		//Marker: DHT
+	0x01, 0xa2,		//Length: 2*AC, 2*DC
+	0x00,			//DC first table
+	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,
+	0x01,			//DC second table
+	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,
+	0x10,			//AC first table
+	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,
+	0x11,			//AC second table
+	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
+};
+
+/* jpeg baseline setup, this is just fixed in this driver (YUV pictures) */
+#define NO_OF_COMPONENTS          0x3	//Y,U,V
+#define BASELINE_PRECISION        0x8	//MCU size (?)
+static const char zr36050_tq[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };	//table idx's QT
+static const char zr36050_td[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };	//table idx's DC
+static const char zr36050_ta[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };	//table idx's AC
+
+/* horizontal 422 decimation setup (maybe we support 411 or so later, too) */
+static const char zr36050_decimation_h[8] = { 2, 1, 1, 0, 0, 0, 0, 0 };
+static const char zr36050_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 };
+
+/* =========================================================================
+   Local helper functions:
+
+   calculation and setup of parameter-dependent JPEG baseline segments
+   (needed for compression only)
+   ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+
+/* SOF (start of frame) segment depends on width, height and sampling ratio
+			 of each color component */
+
+static int
+zr36050_set_sof (struct zr36050 *ptr)
+{
+	char sof_data[34];	// max. size of register set
+	int i;
+
+	dprintk(3, "%s: write SOF (%dx%d, %d components)\n", ptr->name,
+		ptr->width, ptr->height, NO_OF_COMPONENTS);
+	sof_data[0] = 0xff;
+	sof_data[1] = 0xc0;
+	sof_data[2] = 0x00;
+	sof_data[3] = (3 * NO_OF_COMPONENTS) + 8;
+	sof_data[4] = BASELINE_PRECISION;	// only '8' possible with zr36050
+	sof_data[5] = (ptr->height) >> 8;
+	sof_data[6] = (ptr->height) & 0xff;
+	sof_data[7] = (ptr->width) >> 8;
+	sof_data[8] = (ptr->width) & 0xff;
+	sof_data[9] = NO_OF_COMPONENTS;
+	for (i = 0; i < NO_OF_COMPONENTS; i++) {
+		sof_data[10 + (i * 3)] = i;	// index identifier
+		sof_data[11 + (i * 3)] = (ptr->h_samp_ratio[i] << 4) | (ptr->v_samp_ratio[i]);	// sampling ratios
+		sof_data[12 + (i * 3)] = zr36050_tq[i];	// Q table selection
+	}
+	return zr36050_pushit(ptr, ZR050_SOF_IDX,
+			      (3 * NO_OF_COMPONENTS) + 10, sof_data);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* SOS (start of scan) segment depends on the used scan components
+			of each color component */
+
+static int
+zr36050_set_sos (struct zr36050 *ptr)
+{
+	char sos_data[16];	// max. size of register set
+	int i;
+
+	dprintk(3, "%s: write SOS\n", ptr->name);
+	sos_data[0] = 0xff;
+	sos_data[1] = 0xda;
+	sos_data[2] = 0x00;
+	sos_data[3] = 2 + 1 + (2 * NO_OF_COMPONENTS) + 3;
+	sos_data[4] = NO_OF_COMPONENTS;
+	for (i = 0; i < NO_OF_COMPONENTS; i++) {
+		sos_data[5 + (i * 2)] = i;	// index
+		sos_data[6 + (i * 2)] = (zr36050_td[i] << 4) | zr36050_ta[i];	// AC/DC tbl.sel.
+	}
+	sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 2] = 00;	// scan start
+	sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 3] = 0x3F;
+	sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 4] = 00;
+	return zr36050_pushit(ptr, ZR050_SOS1_IDX,
+			      4 + 1 + (2 * NO_OF_COMPONENTS) + 3,
+			      sos_data);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* DRI (define restart interval) */
+
+static int
+zr36050_set_dri (struct zr36050 *ptr)
+{
+	char dri_data[6];	// max. size of register set
+
+	dprintk(3, "%s: write DRI\n", ptr->name);
+	dri_data[0] = 0xff;
+	dri_data[1] = 0xdd;
+	dri_data[2] = 0x00;
+	dri_data[3] = 0x04;
+	dri_data[4] = ptr->dri >> 8;
+	dri_data[5] = ptr->dri & 0xff;
+	return zr36050_pushit(ptr, ZR050_DRI_IDX, 6, dri_data);
+}
+
+/* =========================================================================
+   Setup function:
+
+   Setup compression/decompression of Zoran's JPEG processor
+   ( see also zoran 36050 manual )
+
+   ... sorry for the spaghetti code ...
+   ========================================================================= */
+static void
+zr36050_init (struct zr36050 *ptr)
+{
+	int sum = 0;
+	long bitcnt, tmp;
+
+	if (ptr->mode == CODEC_DO_COMPRESSION) {
+		dprintk(2, "%s: COMPRESSION SETUP\n", ptr->name);
+
+		/* 050 communicates with 057 in master mode */
+		zr36050_write(ptr, ZR050_HARDWARE, ZR050_HW_MSTR);
+
+		/* encoding table preload for compression */
+		zr36050_write(ptr, ZR050_MODE,
+			      ZR050_MO_COMP | ZR050_MO_TLM);
+		zr36050_write(ptr, ZR050_OPTIONS, 0);
+
+		/* disable all IRQs */
+		zr36050_write(ptr, ZR050_INT_REQ_0, 0);
+		zr36050_write(ptr, ZR050_INT_REQ_1, 3);	// low 2 bits always 1
+
+		/* volume control settings */
+		/*zr36050_write(ptr, ZR050_MBCV, ptr->max_block_vol);*/
+		zr36050_write(ptr, ZR050_SF_HI, ptr->scalefact >> 8);
+		zr36050_write(ptr, ZR050_SF_LO, ptr->scalefact & 0xff);
+
+		zr36050_write(ptr, ZR050_AF_HI, 0xff);
+		zr36050_write(ptr, ZR050_AF_M, 0xff);
+		zr36050_write(ptr, ZR050_AF_LO, 0xff);
+
+		/* setup the variable jpeg tables */
+		sum += zr36050_set_sof(ptr);
+		sum += zr36050_set_sos(ptr);
+		sum += zr36050_set_dri(ptr);
+
+		/* setup the fixed jpeg tables - maybe variable, though -
+		 * (see table init section above) */
+		dprintk(3, "%s: write DQT, DHT, APP\n", ptr->name);
+		sum += zr36050_pushit(ptr, ZR050_DQT_IDX,
+				      sizeof(zr36050_dqt), zr36050_dqt);
+		sum += zr36050_pushit(ptr, ZR050_DHT_IDX,
+				      sizeof(zr36050_dht), zr36050_dht);
+		zr36050_write(ptr, ZR050_APP_IDX, 0xff);
+		zr36050_write(ptr, ZR050_APP_IDX + 1, 0xe0 + ptr->app.appn);
+		zr36050_write(ptr, ZR050_APP_IDX + 2, 0x00);
+		zr36050_write(ptr, ZR050_APP_IDX + 3, ptr->app.len + 2);
+		sum += zr36050_pushit(ptr, ZR050_APP_IDX + 4, 60,
+				      ptr->app.data) + 4;
+		zr36050_write(ptr, ZR050_COM_IDX, 0xff);
+		zr36050_write(ptr, ZR050_COM_IDX + 1, 0xfe);
+		zr36050_write(ptr, ZR050_COM_IDX + 2, 0x00);
+		zr36050_write(ptr, ZR050_COM_IDX + 3, ptr->com.len + 2);
+		sum += zr36050_pushit(ptr, ZR050_COM_IDX + 4, 60,
+				      ptr->com.data) + 4;
+
+		/* do the internal huffman table preload */
+		zr36050_write(ptr, ZR050_MARKERS_EN, ZR050_ME_DHTI);
+
+		zr36050_write(ptr, ZR050_GO, 1);	// launch codec
+		zr36050_wait_end(ptr);
+		dprintk(2, "%s: Status after table preload: 0x%02x\n",
+			ptr->name, ptr->status1);
+
+		if ((ptr->status1 & 0x4) == 0) {
+			dprintk(1, KERN_ERR "%s: init aborted!\n",
+				ptr->name);
+			return;	// something is wrong, its timed out!!!!
+		}
+
+		/* setup misc. data for compression (target code sizes) */
+
+		/* size of compressed code to reach without header data */
+		sum = ptr->real_code_vol - sum;
+		bitcnt = sum << 3;	/* need the size in bits */
+
+		tmp = bitcnt >> 16;
+		dprintk(3,
+			"%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n",
+			ptr->name, sum, ptr->real_code_vol, bitcnt, tmp);
+		zr36050_write(ptr, ZR050_TCV_NET_HI, tmp >> 8);
+		zr36050_write(ptr, ZR050_TCV_NET_MH, tmp & 0xff);
+		tmp = bitcnt & 0xffff;
+		zr36050_write(ptr, ZR050_TCV_NET_ML, tmp >> 8);
+		zr36050_write(ptr, ZR050_TCV_NET_LO, tmp & 0xff);
+
+		bitcnt -= bitcnt >> 7;	// bits without stuffing
+		bitcnt -= ((bitcnt * 5) >> 6);	// bits without eob
+
+		tmp = bitcnt >> 16;
+		dprintk(3, "%s: code: nettobit=%ld, highnettobits=%ld\n",
+			ptr->name, bitcnt, tmp);
+		zr36050_write(ptr, ZR050_TCV_DATA_HI, tmp >> 8);
+		zr36050_write(ptr, ZR050_TCV_DATA_MH, tmp & 0xff);
+		tmp = bitcnt & 0xffff;
+		zr36050_write(ptr, ZR050_TCV_DATA_ML, tmp >> 8);
+		zr36050_write(ptr, ZR050_TCV_DATA_LO, tmp & 0xff);
+
+		/* compression setup with or without bitrate control */
+		zr36050_write(ptr, ZR050_MODE,
+			      ZR050_MO_COMP | ZR050_MO_PASS2 |
+			      (ptr->bitrate_ctrl ? ZR050_MO_BRC : 0));
+
+		/* this headers seem to deliver "valid AVI" jpeg frames */
+		zr36050_write(ptr, ZR050_MARKERS_EN,
+			      ZR050_ME_DQT | ZR050_ME_DHT |
+			      ((ptr->app.len > 0) ? ZR050_ME_APP : 0) |
+			      ((ptr->com.len > 0) ? ZR050_ME_COM : 0));
+	} else {
+		dprintk(2, "%s: EXPANSION SETUP\n", ptr->name);
+
+		/* 050 communicates with 055 in master mode */
+		zr36050_write(ptr, ZR050_HARDWARE,
+			      ZR050_HW_MSTR | ZR050_HW_CFIS_2_CLK);
+
+		/* encoding table preload */
+		zr36050_write(ptr, ZR050_MODE, ZR050_MO_TLM);
+
+		/* disable all IRQs */
+		zr36050_write(ptr, ZR050_INT_REQ_0, 0);
+		zr36050_write(ptr, ZR050_INT_REQ_1, 3);	// low 2 bits always 1
+
+		dprintk(3, "%s: write DHT\n", ptr->name);
+		zr36050_pushit(ptr, ZR050_DHT_IDX, sizeof(zr36050_dht),
+			       zr36050_dht);
+
+		/* do the internal huffman table preload */
+		zr36050_write(ptr, ZR050_MARKERS_EN, ZR050_ME_DHTI);
+
+		zr36050_write(ptr, ZR050_GO, 1);	// launch codec
+		zr36050_wait_end(ptr);
+		dprintk(2, "%s: Status after table preload: 0x%02x\n",
+			ptr->name, ptr->status1);
+
+		if ((ptr->status1 & 0x4) == 0) {
+			dprintk(1, KERN_ERR "%s: init aborted!\n",
+				ptr->name);
+			return;	// something is wrong, its timed out!!!!
+		}
+
+		/* setup misc. data for expansion */
+		zr36050_write(ptr, ZR050_MODE, 0);
+		zr36050_write(ptr, ZR050_MARKERS_EN, 0);
+	}
+
+	/* adr on selected, to allow GO from master */
+	zr36050_read(ptr, 0);
+}
+
+/* =========================================================================
+   CODEC API FUNCTIONS
+
+   this functions are accessed by the master via the API structure
+   ========================================================================= */
+
+/* set compression/expansion mode and launches codec -
+   this should be the last call from the master before starting processing */
+static int
+zr36050_set_mode (struct videocodec *codec,
+		  int                mode)
+{
+	struct zr36050 *ptr = (struct zr36050 *) codec->data;
+
+	dprintk(2, "%s: set_mode %d call\n", ptr->name, mode);
+
+	if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION))
+		return -EINVAL;
+
+	ptr->mode = mode;
+	zr36050_init(ptr);
+
+	return 0;
+}
+
+/* set picture size (norm is ignored as the codec doesn't know about it) */
+static int
+zr36050_set_video (struct videocodec   *codec,
+		   struct tvnorm       *norm,
+		   struct vfe_settings *cap,
+		   struct vfe_polarity *pol)
+{
+	struct zr36050 *ptr = (struct zr36050 *) codec->data;
+	int size;
+
+	dprintk(2, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) q%d call\n",
+		ptr->name, norm->HStart, norm->VStart,
+		cap->x, cap->y, cap->width, cap->height,
+		cap->decimation, cap->quality);
+	/* if () return -EINVAL;
+	 * trust the master driver that it knows what it does - so
+	 * we allow invalid startx/y and norm for now ... */
+	ptr->width = cap->width / (cap->decimation & 0xff);
+	ptr->height = cap->height / ((cap->decimation >> 8) & 0xff);
+
+	/* (KM) JPEG quality */
+	size = ptr->width * ptr->height;
+	size *= 16; /* size in bits */
+	/* apply quality setting */
+	size = size * cap->quality / 200;
+
+	/* Minimum: 1kb */
+	if (size < 8192)
+		size = 8192;
+	/* Maximum: 7/8 of code buffer */
+	if (size > ptr->total_code_vol * 7)
+		size = ptr->total_code_vol * 7;
+
+	ptr->real_code_vol = size >> 3; /* in bytes */
+
+	/* Set max_block_vol here (previously in zr36050_init, moved
+	 * here for consistency with zr36060 code */
+	zr36050_write(ptr, ZR050_MBCV, ptr->max_block_vol);
+
+	return 0;
+}
+
+/* additional control functions */
+static int
+zr36050_control (struct videocodec *codec,
+		 int                type,
+		 int                size,
+		 void              *data)
+{
+	struct zr36050 *ptr = (struct zr36050 *) codec->data;
+	int *ival = (int *) data;
+
+	dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type,
+		size);
+
+	switch (type) {
+	case CODEC_G_STATUS:	/* get last status */
+		if (size != sizeof(int))
+			return -EFAULT;
+		zr36050_read_status1(ptr);
+		*ival = ptr->status1;
+		break;
+
+	case CODEC_G_CODEC_MODE:
+		if (size != sizeof(int))
+			return -EFAULT;
+		*ival = CODEC_MODE_BJPG;
+		break;
+
+	case CODEC_S_CODEC_MODE:
+		if (size != sizeof(int))
+			return -EFAULT;
+		if (*ival != CODEC_MODE_BJPG)
+			return -EINVAL;
+		/* not needed, do nothing */
+		return 0;
+
+	case CODEC_G_VFE:
+	case CODEC_S_VFE:
+		/* not needed, do nothing */
+		return 0;
+
+	case CODEC_S_MMAP:
+		/* not available, give an error */
+		return -ENXIO;
+
+	case CODEC_G_JPEG_TDS_BYTE:	/* get target volume in byte */
+		if (size != sizeof(int))
+			return -EFAULT;
+		*ival = ptr->total_code_vol;
+		break;
+
+	case CODEC_S_JPEG_TDS_BYTE:	/* get target volume in byte */
+		if (size != sizeof(int))
+			return -EFAULT;
+		ptr->total_code_vol = *ival;
+		/* (Kieran Morrissey)
+		 * code copied from zr36060.c to ensure proper bitrate */
+		ptr->real_code_vol = (ptr->total_code_vol * 6) >> 3;
+		break;
+
+	case CODEC_G_JPEG_SCALE:	/* get scaling factor */
+		if (size != sizeof(int))
+			return -EFAULT;
+		*ival = zr36050_read_scalefactor(ptr);
+		break;
+
+	case CODEC_S_JPEG_SCALE:	/* set scaling factor */
+		if (size != sizeof(int))
+			return -EFAULT;
+		ptr->scalefact = *ival;
+		break;
+
+	case CODEC_G_JPEG_APP_DATA: {	/* get appn marker data */
+		struct jpeg_app_marker *app = data;
+
+		if (size != sizeof(struct jpeg_app_marker))
+			return -EFAULT;
+
+		*app = ptr->app;
+		break;
+	}
+
+	case CODEC_S_JPEG_APP_DATA: {	 /* set appn marker data */
+		struct jpeg_app_marker *app = data;
+
+		if (size != sizeof(struct jpeg_app_marker))
+			return -EFAULT;
+
+		ptr->app = *app;
+		break;
+	}
+
+	case CODEC_G_JPEG_COM_DATA: {	/* get comment marker data */
+		struct jpeg_com_marker *com = data;
+
+		if (size != sizeof(struct jpeg_com_marker))
+			return -EFAULT;
+
+		*com = ptr->com;
+		break;
+	}
+
+	case CODEC_S_JPEG_COM_DATA: {	/* set comment marker data */
+		struct jpeg_com_marker *com = data;
+
+		if (size != sizeof(struct jpeg_com_marker))
+			return -EFAULT;
+
+		ptr->com = *com;
+		break;
+	}
+
+	default:
+		return -EINVAL;
+	}
+
+	return size;
+}
+
+/* =========================================================================
+   Exit and unregister function:
+
+   Deinitializes Zoran's JPEG processor
+   ========================================================================= */
+
+static int
+zr36050_unset (struct videocodec *codec)
+{
+	struct zr36050 *ptr = codec->data;
+
+	if (ptr) {
+		/* do wee need some codec deinit here, too ???? */
+
+		dprintk(1, "%s: finished codec #%d\n", ptr->name,
+			ptr->num);
+		kfree(ptr);
+		codec->data = NULL;
+
+		zr36050_codecs--;
+		return 0;
+	}
+
+	return -EFAULT;
+}
+
+/* =========================================================================
+   Setup and registry function:
+
+   Initializes Zoran's JPEG processor
+
+   Also sets pixel size, average code size, mode (compr./decompr.)
+   (the given size is determined by the processor with the video interface)
+   ========================================================================= */
+
+static int
+zr36050_setup (struct videocodec *codec)
+{
+	struct zr36050 *ptr;
+	int res;
+
+	dprintk(2, "zr36050: initializing MJPEG subsystem #%d.\n",
+		zr36050_codecs);
+
+	if (zr36050_codecs == MAX_CODECS) {
+		dprintk(1,
+			KERN_ERR "zr36050: Can't attach more codecs!\n");
+		return -ENOSPC;
+	}
+	//mem structure init
+	codec->data = ptr = kzalloc(sizeof(struct zr36050), GFP_KERNEL);
+	if (NULL == ptr) {
+		dprintk(1, KERN_ERR "zr36050: Can't get enough memory!\n");
+		return -ENOMEM;
+	}
+
+	snprintf(ptr->name, sizeof(ptr->name), "zr36050[%d]",
+		 zr36050_codecs);
+	ptr->num = zr36050_codecs++;
+	ptr->codec = codec;
+
+	//testing
+	res = zr36050_basic_test(ptr);
+	if (res < 0) {
+		zr36050_unset(codec);
+		return res;
+	}
+	//final setup
+	memcpy(ptr->h_samp_ratio, zr36050_decimation_h, 8);
+	memcpy(ptr->v_samp_ratio, zr36050_decimation_v, 8);
+
+	ptr->bitrate_ctrl = 0;	/* 0 or 1 - fixed file size flag
+				 * (what is the difference?) */
+	ptr->mode = CODEC_DO_COMPRESSION;
+	ptr->width = 384;
+	ptr->height = 288;
+	ptr->total_code_vol = 16000;
+	ptr->max_block_vol = 240;
+	ptr->scalefact = 0x100;
+	ptr->dri = 1;
+
+	/* no app/com marker by default */
+	ptr->app.appn = 0;
+	ptr->app.len = 0;
+	ptr->com.len = 0;
+
+	zr36050_init(ptr);
+
+	dprintk(1, KERN_INFO "%s: codec attached and running\n",
+		ptr->name);
+
+	return 0;
+}
+
+static const struct videocodec zr36050_codec = {
+	.owner = THIS_MODULE,
+	.name = "zr36050",
+	.magic = 0L,		// magic not used
+	.flags =
+	    CODEC_FLAG_JPEG | CODEC_FLAG_HARDWARE | CODEC_FLAG_ENCODER |
+	    CODEC_FLAG_DECODER,
+	.type = CODEC_TYPE_ZR36050,
+	.setup = zr36050_setup,	// functionality
+	.unset = zr36050_unset,
+	.set_mode = zr36050_set_mode,
+	.set_video = zr36050_set_video,
+	.control = zr36050_control,
+	// others are not used
+};
+
+/* =========================================================================
+   HOOK IN DRIVER AS KERNEL MODULE
+   ========================================================================= */
+
+static int __init
+zr36050_init_module (void)
+{
+	//dprintk(1, "ZR36050 driver %s\n",ZR050_VERSION);
+	zr36050_codecs = 0;
+	return videocodec_register(&zr36050_codec);
+}
+
+static void __exit
+zr36050_cleanup_module (void)
+{
+	if (zr36050_codecs) {
+		dprintk(1,
+			"zr36050: something's wrong - %d codecs left somehow.\n",
+			zr36050_codecs);
+	}
+	videocodec_unregister(&zr36050_codec);
+}
+
+module_init(zr36050_init_module);
+module_exit(zr36050_cleanup_module);
+
+MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>");
+MODULE_DESCRIPTION("Driver module for ZR36050 jpeg processors "
+		   ZR050_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/zoran/zr36050.h b/drivers/media/pci/zoran/zr36050.h
new file mode 100644
index 0000000..9f52f0c
--- /dev/null
+++ b/drivers/media/pci/zoran/zr36050.h
@@ -0,0 +1,184 @@
+/*
+ * Zoran ZR36050 basic configuration functions - header file
+ *
+ * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at>
+ *
+ * $Id: zr36050.h,v 1.1.2.2 2003/01/14 21:18:22 rbultje Exp $
+ *
+ * ------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * ------------------------------------------------------------------------
+ */
+
+#ifndef ZR36050_H
+#define ZR36050_H
+
+#include "videocodec.h"
+
+/* data stored for each zoran jpeg codec chip */
+struct zr36050 {
+	char name[32];
+	int num;
+	/* io datastructure */
+	struct videocodec *codec;
+	// last coder status
+	__u8 status1;
+	// actual coder setup
+	int mode;
+
+	__u16 width;
+	__u16 height;
+
+	__u16 bitrate_ctrl;
+
+	__u32 total_code_vol;
+	__u32 real_code_vol;
+	__u16 max_block_vol;
+
+	__u8 h_samp_ratio[8];
+	__u8 v_samp_ratio[8];
+	__u16 scalefact;
+	__u16 dri;
+
+	/* com/app marker */
+	struct jpeg_com_marker com;
+	struct jpeg_app_marker app;
+};
+
+/* zr36050 register addresses */
+#define ZR050_GO                  0x000
+#define ZR050_HARDWARE            0x002
+#define ZR050_MODE                0x003
+#define ZR050_OPTIONS             0x004
+#define ZR050_MBCV                0x005
+#define ZR050_MARKERS_EN          0x006
+#define ZR050_INT_REQ_0           0x007
+#define ZR050_INT_REQ_1           0x008
+#define ZR050_TCV_NET_HI          0x009
+#define ZR050_TCV_NET_MH          0x00a
+#define ZR050_TCV_NET_ML          0x00b
+#define ZR050_TCV_NET_LO          0x00c
+#define ZR050_TCV_DATA_HI         0x00d
+#define ZR050_TCV_DATA_MH         0x00e
+#define ZR050_TCV_DATA_ML         0x00f
+#define ZR050_TCV_DATA_LO         0x010
+#define ZR050_SF_HI               0x011
+#define ZR050_SF_LO               0x012
+#define ZR050_AF_HI               0x013
+#define ZR050_AF_M                0x014
+#define ZR050_AF_LO               0x015
+#define ZR050_ACV_HI              0x016
+#define ZR050_ACV_MH              0x017
+#define ZR050_ACV_ML              0x018
+#define ZR050_ACV_LO              0x019
+#define ZR050_ACT_HI              0x01a
+#define ZR050_ACT_MH              0x01b
+#define ZR050_ACT_ML              0x01c
+#define ZR050_ACT_LO              0x01d
+#define ZR050_ACV_TRUN_HI         0x01e
+#define ZR050_ACV_TRUN_MH         0x01f
+#define ZR050_ACV_TRUN_ML         0x020
+#define ZR050_ACV_TRUN_LO         0x021
+#define ZR050_STATUS_0            0x02e
+#define ZR050_STATUS_1            0x02f
+
+#define ZR050_SOF_IDX             0x040
+#define ZR050_SOS1_IDX            0x07a
+#define ZR050_SOS2_IDX            0x08a
+#define ZR050_SOS3_IDX            0x09a
+#define ZR050_SOS4_IDX            0x0aa
+#define ZR050_DRI_IDX             0x0c0
+#define ZR050_DNL_IDX             0x0c6
+#define ZR050_DQT_IDX             0x0cc
+#define ZR050_DHT_IDX             0x1d4
+#define ZR050_APP_IDX             0x380
+#define ZR050_COM_IDX             0x3c0
+
+/* zr36050 hardware register bits */
+
+#define ZR050_HW_BSWD                0x80
+#define ZR050_HW_MSTR                0x40
+#define ZR050_HW_DMA                 0x20
+#define ZR050_HW_CFIS_1_CLK          0x00
+#define ZR050_HW_CFIS_2_CLK          0x04
+#define ZR050_HW_CFIS_3_CLK          0x08
+#define ZR050_HW_CFIS_4_CLK          0x0C
+#define ZR050_HW_CFIS_5_CLK          0x10
+#define ZR050_HW_CFIS_6_CLK          0x14
+#define ZR050_HW_CFIS_7_CLK          0x18
+#define ZR050_HW_CFIS_8_CLK          0x1C
+#define ZR050_HW_BELE                0x01
+
+/* zr36050 mode register bits */
+
+#define ZR050_MO_COMP                0x80
+#define ZR050_MO_COMP                0x80
+#define ZR050_MO_ATP                 0x40
+#define ZR050_MO_PASS2               0x20
+#define ZR050_MO_TLM                 0x10
+#define ZR050_MO_DCONLY              0x08
+#define ZR050_MO_BRC                 0x04
+
+#define ZR050_MO_ATP                 0x40
+#define ZR050_MO_PASS2               0x20
+#define ZR050_MO_TLM                 0x10
+#define ZR050_MO_DCONLY              0x08
+
+/* zr36050 option register bits */
+
+#define ZR050_OP_NSCN_1              0x00
+#define ZR050_OP_NSCN_2              0x20
+#define ZR050_OP_NSCN_3              0x40
+#define ZR050_OP_NSCN_4              0x60
+#define ZR050_OP_NSCN_5              0x80
+#define ZR050_OP_NSCN_6              0xA0
+#define ZR050_OP_NSCN_7              0xC0
+#define ZR050_OP_NSCN_8              0xE0
+#define ZR050_OP_OVF                 0x10
+
+
+/* zr36050 markers-enable register bits */
+
+#define ZR050_ME_APP                 0x80
+#define ZR050_ME_COM                 0x40
+#define ZR050_ME_DRI                 0x20
+#define ZR050_ME_DQT                 0x10
+#define ZR050_ME_DHT                 0x08
+#define ZR050_ME_DNL                 0x04
+#define ZR050_ME_DQTI                0x02
+#define ZR050_ME_DHTI                0x01
+
+/* zr36050 status0/1 register bit masks */
+
+#define ZR050_ST_RST_MASK            0x20
+#define ZR050_ST_SOF_MASK            0x02
+#define ZR050_ST_SOS_MASK            0x02
+#define ZR050_ST_DATRDY_MASK         0x80
+#define ZR050_ST_MRKDET_MASK         0x40
+#define ZR050_ST_RFM_MASK            0x10
+#define ZR050_ST_RFD_MASK            0x08
+#define ZR050_ST_END_MASK            0x04
+#define ZR050_ST_TCVOVF_MASK         0x02
+#define ZR050_ST_DATOVF_MASK         0x01
+
+/* pixel component idx */
+
+#define ZR050_Y_COMPONENT         0
+#define ZR050_U_COMPONENT         1
+#define ZR050_V_COMPONENT         2
+
+#endif				/*fndef ZR36050_H */
diff --git a/drivers/media/pci/zoran/zr36057.h b/drivers/media/pci/zoran/zr36057.h
new file mode 100644
index 0000000..54c9362
--- /dev/null
+++ b/drivers/media/pci/zoran/zr36057.h
@@ -0,0 +1,168 @@
+/*
+ * zr36057.h - zr36057 register offsets
+ *
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _ZR36057_H_
+#define _ZR36057_H_
+
+
+/* Zoran ZR36057 registers */
+
+#define ZR36057_VFEHCR          0x000	/* Video Front End, Horizontal Configuration Register */
+#define ZR36057_VFEHCR_HSPol            (1<<30)
+#define ZR36057_VFEHCR_HStart           10
+#define ZR36057_VFEHCR_HEnd		0
+#define ZR36057_VFEHCR_Hmask		0x3ff
+
+#define ZR36057_VFEVCR          0x004	/* Video Front End, Vertical Configuration Register */
+#define ZR36057_VFEVCR_VSPol            (1<<30)
+#define ZR36057_VFEVCR_VStart           10
+#define ZR36057_VFEVCR_VEnd		0
+#define ZR36057_VFEVCR_Vmask		0x3ff
+
+#define ZR36057_VFESPFR         0x008	/* Video Front End, Scaler and Pixel Format Register */
+#define ZR36057_VFESPFR_ExtFl           (1<<26)
+#define ZR36057_VFESPFR_TopField        (1<<25)
+#define ZR36057_VFESPFR_VCLKPol         (1<<24)
+#define ZR36057_VFESPFR_HFilter         21
+#define ZR36057_VFESPFR_HorDcm          14
+#define ZR36057_VFESPFR_VerDcm          8
+#define ZR36057_VFESPFR_DispMode        6
+#define ZR36057_VFESPFR_YUV422          (0<<3)
+#define ZR36057_VFESPFR_RGB888          (1<<3)
+#define ZR36057_VFESPFR_RGB565          (2<<3)
+#define ZR36057_VFESPFR_RGB555          (3<<3)
+#define ZR36057_VFESPFR_ErrDif          (1<<2)
+#define ZR36057_VFESPFR_Pack24          (1<<1)
+#define ZR36057_VFESPFR_LittleEndian    (1<<0)
+
+#define ZR36057_VDTR            0x00c	/* Video Display "Top" Register */
+
+#define ZR36057_VDBR            0x010	/* Video Display "Bottom" Register */
+
+#define ZR36057_VSSFGR          0x014	/* Video Stride, Status, and Frame Grab Register */
+#define ZR36057_VSSFGR_DispStride       16
+#define ZR36057_VSSFGR_VidOvf           (1<<8)
+#define ZR36057_VSSFGR_SnapShot         (1<<1)
+#define ZR36057_VSSFGR_FrameGrab        (1<<0)
+
+#define ZR36057_VDCR            0x018	/* Video Display Configuration Register */
+#define ZR36057_VDCR_VidEn              (1<<31)
+#define ZR36057_VDCR_MinPix             24
+#define ZR36057_VDCR_Triton             (1<<24)
+#define ZR36057_VDCR_VidWinHt           12
+#define ZR36057_VDCR_VidWinWid          0
+
+#define ZR36057_MMTR            0x01c	/* Masking Map "Top" Register */
+
+#define ZR36057_MMBR            0x020	/* Masking Map "Bottom" Register */
+
+#define ZR36057_OCR             0x024	/* Overlay Control Register */
+#define ZR36057_OCR_OvlEnable           (1 << 15)
+#define ZR36057_OCR_MaskStride          0
+
+#define ZR36057_SPGPPCR         0x028	/* System, PCI, and General Purpose Pins Control Register */
+#define ZR36057_SPGPPCR_SoftReset	(1<<24)
+
+#define ZR36057_GPPGCR1         0x02c	/* General Purpose Pins and GuestBus Control Register (1) */
+
+#define ZR36057_MCSAR           0x030	/* MPEG Code Source Address Register */
+
+#define ZR36057_MCTCR           0x034	/* MPEG Code Transfer Control Register */
+#define ZR36057_MCTCR_CodTime           (1 << 30)
+#define ZR36057_MCTCR_CEmpty            (1 << 29)
+#define ZR36057_MCTCR_CFlush            (1 << 28)
+#define ZR36057_MCTCR_CodGuestID	20
+#define ZR36057_MCTCR_CodGuestReg	16
+
+#define ZR36057_MCMPR           0x038	/* MPEG Code Memory Pointer Register */
+
+#define ZR36057_ISR             0x03c	/* Interrupt Status Register */
+#define ZR36057_ISR_GIRQ1               (1<<30)
+#define ZR36057_ISR_GIRQ0               (1<<29)
+#define ZR36057_ISR_CodRepIRQ           (1<<28)
+#define ZR36057_ISR_JPEGRepIRQ          (1<<27)
+
+#define ZR36057_ICR             0x040	/* Interrupt Control Register */
+#define ZR36057_ICR_GIRQ1               (1<<30)
+#define ZR36057_ICR_GIRQ0               (1<<29)
+#define ZR36057_ICR_CodRepIRQ           (1<<28)
+#define ZR36057_ICR_JPEGRepIRQ          (1<<27)
+#define ZR36057_ICR_IntPinEn            (1<<24)
+
+#define ZR36057_I2CBR           0x044	/* I2C Bus Register */
+#define ZR36057_I2CBR_SDA       	(1<<1)
+#define ZR36057_I2CBR_SCL       	(1<<0)
+
+#define ZR36057_JMC             0x100	/* JPEG Mode and Control */
+#define ZR36057_JMC_JPG                 (1 << 31)
+#define ZR36057_JMC_JPGExpMode          (0 << 29)
+#define ZR36057_JMC_JPGCmpMode          (1 << 29)
+#define ZR36057_JMC_MJPGExpMode         (2 << 29)
+#define ZR36057_JMC_MJPGCmpMode         (3 << 29)
+#define ZR36057_JMC_RTBUSY_FB           (1 << 6)
+#define ZR36057_JMC_Go_en               (1 << 5)
+#define ZR36057_JMC_SyncMstr            (1 << 4)
+#define ZR36057_JMC_Fld_per_buff        (1 << 3)
+#define ZR36057_JMC_VFIFO_FB            (1 << 2)
+#define ZR36057_JMC_CFIFO_FB            (1 << 1)
+#define ZR36057_JMC_Stll_LitEndian      (1 << 0)
+
+#define ZR36057_JPC             0x104	/* JPEG Process Control */
+#define ZR36057_JPC_P_Reset             (1 << 7)
+#define ZR36057_JPC_CodTrnsEn           (1 << 5)
+#define ZR36057_JPC_Active              (1 << 0)
+
+#define ZR36057_VSP             0x108	/* Vertical Sync Parameters */
+#define ZR36057_VSP_VsyncSize           16
+#define ZR36057_VSP_FrmTot              0
+
+#define ZR36057_HSP             0x10c	/* Horizontal Sync Parameters */
+#define ZR36057_HSP_HsyncStart          16
+#define ZR36057_HSP_LineTot             0
+
+#define ZR36057_FHAP            0x110	/* Field Horizontal Active Portion */
+#define ZR36057_FHAP_NAX                16
+#define ZR36057_FHAP_PAX                0
+
+#define ZR36057_FVAP            0x114	/* Field Vertical Active Portion */
+#define ZR36057_FVAP_NAY                16
+#define ZR36057_FVAP_PAY                0
+
+#define ZR36057_FPP             0x118	/* Field Process Parameters */
+#define ZR36057_FPP_Odd_Even            (1 << 0)
+
+#define ZR36057_JCBA            0x11c	/* JPEG Code Base Address */
+
+#define ZR36057_JCFT            0x120	/* JPEG Code FIFO Threshold */
+
+#define ZR36057_JCGI            0x124	/* JPEG Codec Guest ID */
+#define ZR36057_JCGI_JPEGuestID         4
+#define ZR36057_JCGI_JPEGuestReg        0
+
+#define ZR36057_GCR2            0x12c	/* GuestBus Control Register (2) */
+
+#define ZR36057_POR             0x200	/* Post Office Register */
+#define ZR36057_POR_POPen               (1<<25)
+#define ZR36057_POR_POTime              (1<<24)
+#define ZR36057_POR_PODir               (1<<23)
+
+#define ZR36057_STR             0x300	/* "Still" Transfer Register */
+
+#endif
diff --git a/drivers/media/pci/zoran/zr36060.c b/drivers/media/pci/zoran/zr36060.c
new file mode 100644
index 0000000..f08546f
--- /dev/null
+++ b/drivers/media/pci/zoran/zr36060.c
@@ -0,0 +1,1010 @@
+/*
+ * Zoran ZR36060 basic configuration functions
+ *
+ * Copyright (C) 2002 Laurent Pinchart <laurent.pinchart@skynet.be>
+ *
+ * $Id: zr36060.c,v 1.1.2.22 2003/05/06 09:35:36 rbultje Exp $
+ *
+ * ------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * ------------------------------------------------------------------------
+ */
+
+#define ZR060_VERSION "v0.7"
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <linux/types.h>
+#include <linux/wait.h>
+
+/* I/O commands, error codes */
+#include <asm/io.h>
+
+/* headerfile of this module */
+#include "zr36060.h"
+
+/* codec io API */
+#include "videocodec.h"
+
+/* it doesn't make sense to have more than 20 or so,
+  just to prevent some unwanted loops */
+#define MAX_CODECS 20
+
+/* amount of chips attached via this driver */
+static int zr36060_codecs;
+
+static bool low_bitrate;
+module_param(low_bitrate, bool, 0);
+MODULE_PARM_DESC(low_bitrate, "Buz compatibility option, halves bitrate");
+
+/* debugging is available via module parameter */
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-4)");
+
+#define dprintk(num, format, args...) \
+	do { \
+		if (debug >= num) \
+			printk(format, ##args); \
+	} while (0)
+
+/* =========================================================================
+   Local hardware I/O functions:
+
+   read/write via codec layer (registers are located in the master device)
+   ========================================================================= */
+
+/* read and write functions */
+static u8
+zr36060_read (struct zr36060 *ptr,
+	      u16             reg)
+{
+	u8 value = 0;
+
+	// just in case something is wrong...
+	if (ptr->codec->master_data->readreg)
+		value = (ptr->codec->master_data->readreg(ptr->codec,
+							  reg)) & 0xff;
+	else
+		dprintk(1,
+			KERN_ERR "%s: invalid I/O setup, nothing read!\n",
+			ptr->name);
+
+	//dprintk(4, "%s: reading from 0x%04x: %02x\n",ptr->name,reg,value);
+
+	return value;
+}
+
+static void
+zr36060_write(struct zr36060 *ptr,
+	      u16             reg,
+	      u8              value)
+{
+	//dprintk(4, "%s: writing 0x%02x to 0x%04x\n",ptr->name,value,reg);
+	dprintk(4, "0x%02x @0x%04x\n", value, reg);
+
+	// just in case something is wrong...
+	if (ptr->codec->master_data->writereg)
+		ptr->codec->master_data->writereg(ptr->codec, reg, value);
+	else
+		dprintk(1,
+			KERN_ERR
+			"%s: invalid I/O setup, nothing written!\n",
+			ptr->name);
+}
+
+/* =========================================================================
+   Local helper function:
+
+   status read
+   ========================================================================= */
+
+/* status is kept in datastructure */
+static u8
+zr36060_read_status (struct zr36060 *ptr)
+{
+	ptr->status = zr36060_read(ptr, ZR060_CFSR);
+
+	zr36060_read(ptr, 0);
+	return ptr->status;
+}
+
+/* =========================================================================
+   Local helper function:
+
+   scale factor read
+   ========================================================================= */
+
+/* scale factor is kept in datastructure */
+static u16
+zr36060_read_scalefactor (struct zr36060 *ptr)
+{
+	ptr->scalefact = (zr36060_read(ptr, ZR060_SF_HI) << 8) |
+			 (zr36060_read(ptr, ZR060_SF_LO) & 0xFF);
+
+	/* leave 0 selected for an eventually GO from master */
+	zr36060_read(ptr, 0);
+	return ptr->scalefact;
+}
+
+/* =========================================================================
+   Local helper function:
+
+   wait if codec is ready to proceed (end of processing) or time is over
+   ========================================================================= */
+
+static void
+zr36060_wait_end (struct zr36060 *ptr)
+{
+	int i = 0;
+
+	while (zr36060_read_status(ptr) & ZR060_CFSR_Busy) {
+		udelay(1);
+		if (i++ > 200000) {	// 200ms, there is for sure something wrong!!!
+			dprintk(1,
+				"%s: timeout at wait_end (last status: 0x%02x)\n",
+				ptr->name, ptr->status);
+			break;
+		}
+	}
+}
+
+/* =========================================================================
+   Local helper function:
+
+   basic test of "connectivity", writes/reads to/from memory the SOF marker
+   ========================================================================= */
+
+static int
+zr36060_basic_test (struct zr36060 *ptr)
+{
+	if ((zr36060_read(ptr, ZR060_IDR_DEV) != 0x33) &&
+	    (zr36060_read(ptr, ZR060_IDR_REV) != 0x01)) {
+		dprintk(1,
+			KERN_ERR
+			"%s: attach failed, can't connect to jpeg processor!\n",
+			ptr->name);
+		return -ENXIO;
+	}
+
+	zr36060_wait_end(ptr);
+	if (ptr->status & ZR060_CFSR_Busy) {
+		dprintk(1,
+			KERN_ERR
+			"%s: attach failed, jpeg processor failed (end flag)!\n",
+			ptr->name);
+		return -EBUSY;
+	}
+
+	return 0;		/* looks good! */
+}
+
+/* =========================================================================
+   Local helper function:
+
+   simple loop for pushing the init datasets
+   ========================================================================= */
+
+static int
+zr36060_pushit (struct zr36060 *ptr,
+		u16             startreg,
+		u16             len,
+		const char     *data)
+{
+	int i = 0;
+
+	dprintk(4, "%s: write data block to 0x%04x (len=%d)\n", ptr->name,
+		startreg, len);
+	while (i < len) {
+		zr36060_write(ptr, startreg++, data[i++]);
+	}
+
+	return i;
+}
+
+/* =========================================================================
+   Basic datasets:
+
+   jpeg baseline setup data (you find it on lots places in internet, or just
+   extract it from any regular .jpg image...)
+
+   Could be variable, but until it's not needed it they are just fixed to save
+   memory. Otherwise expand zr36060 structure with arrays, push the values to
+   it and initialize from there, as e.g. the linux zr36057/60 driver does it.
+   ========================================================================= */
+
+static const char zr36060_dqt[0x86] = {
+	0xff, 0xdb,		//Marker: DQT
+	0x00, 0x84,		//Length: 2*65+2
+	0x00,			//Pq,Tq first table
+	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,
+	0x01,			//Pq,Tq second table
+	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
+};
+
+static const char zr36060_dht[0x1a4] = {
+	0xff, 0xc4,		//Marker: DHT
+	0x01, 0xa2,		//Length: 2*AC, 2*DC
+	0x00,			//DC first table
+	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,
+	0x01,			//DC second table
+	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,
+	0x10,			//AC first table
+	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,
+	0x11,			//AC second table
+	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
+};
+
+/* jpeg baseline setup, this is just fixed in this driver (YUV pictures) */
+#define NO_OF_COMPONENTS          0x3	//Y,U,V
+#define BASELINE_PRECISION        0x8	//MCU size (?)
+static const char zr36060_tq[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };	//table idx's QT
+static const char zr36060_td[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };	//table idx's DC
+static const char zr36060_ta[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };	//table idx's AC
+
+/* horizontal 422 decimation setup (maybe we support 411 or so later, too) */
+static const char zr36060_decimation_h[8] = { 2, 1, 1, 0, 0, 0, 0, 0 };
+static const char zr36060_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 };
+
+/* =========================================================================
+   Local helper functions:
+
+   calculation and setup of parameter-dependent JPEG baseline segments
+   (needed for compression only)
+   ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+
+/* SOF (start of frame) segment depends on width, height and sampling ratio
+			 of each color component */
+
+static int
+zr36060_set_sof (struct zr36060 *ptr)
+{
+	char sof_data[34];	// max. size of register set
+	int i;
+
+	dprintk(3, "%s: write SOF (%dx%d, %d components)\n", ptr->name,
+		ptr->width, ptr->height, NO_OF_COMPONENTS);
+	sof_data[0] = 0xff;
+	sof_data[1] = 0xc0;
+	sof_data[2] = 0x00;
+	sof_data[3] = (3 * NO_OF_COMPONENTS) + 8;
+	sof_data[4] = BASELINE_PRECISION;	// only '8' possible with zr36060
+	sof_data[5] = (ptr->height) >> 8;
+	sof_data[6] = (ptr->height) & 0xff;
+	sof_data[7] = (ptr->width) >> 8;
+	sof_data[8] = (ptr->width) & 0xff;
+	sof_data[9] = NO_OF_COMPONENTS;
+	for (i = 0; i < NO_OF_COMPONENTS; i++) {
+		sof_data[10 + (i * 3)] = i;	// index identifier
+		sof_data[11 + (i * 3)] = (ptr->h_samp_ratio[i] << 4) |
+					 (ptr->v_samp_ratio[i]); // sampling ratios
+		sof_data[12 + (i * 3)] = zr36060_tq[i];	// Q table selection
+	}
+	return zr36060_pushit(ptr, ZR060_SOF_IDX,
+			      (3 * NO_OF_COMPONENTS) + 10, sof_data);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* SOS (start of scan) segment depends on the used scan components
+			of each color component */
+
+static int
+zr36060_set_sos (struct zr36060 *ptr)
+{
+	char sos_data[16];	// max. size of register set
+	int i;
+
+	dprintk(3, "%s: write SOS\n", ptr->name);
+	sos_data[0] = 0xff;
+	sos_data[1] = 0xda;
+	sos_data[2] = 0x00;
+	sos_data[3] = 2 + 1 + (2 * NO_OF_COMPONENTS) + 3;
+	sos_data[4] = NO_OF_COMPONENTS;
+	for (i = 0; i < NO_OF_COMPONENTS; i++) {
+		sos_data[5 + (i * 2)] = i;	// index
+		sos_data[6 + (i * 2)] = (zr36060_td[i] << 4) |
+					zr36060_ta[i]; // AC/DC tbl.sel.
+	}
+	sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 2] = 00;	// scan start
+	sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 3] = 0x3f;
+	sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 4] = 00;
+	return zr36060_pushit(ptr, ZR060_SOS_IDX,
+			      4 + 1 + (2 * NO_OF_COMPONENTS) + 3,
+			      sos_data);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* DRI (define restart interval) */
+
+static int
+zr36060_set_dri (struct zr36060 *ptr)
+{
+	char dri_data[6];	// max. size of register set
+
+	dprintk(3, "%s: write DRI\n", ptr->name);
+	dri_data[0] = 0xff;
+	dri_data[1] = 0xdd;
+	dri_data[2] = 0x00;
+	dri_data[3] = 0x04;
+	dri_data[4] = (ptr->dri) >> 8;
+	dri_data[5] = (ptr->dri) & 0xff;
+	return zr36060_pushit(ptr, ZR060_DRI_IDX, 6, dri_data);
+}
+
+/* =========================================================================
+   Setup function:
+
+   Setup compression/decompression of Zoran's JPEG processor
+   ( see also zoran 36060 manual )
+
+   ... sorry for the spaghetti code ...
+   ========================================================================= */
+static void
+zr36060_init (struct zr36060 *ptr)
+{
+	int sum = 0;
+	long bitcnt, tmp;
+
+	if (ptr->mode == CODEC_DO_COMPRESSION) {
+		dprintk(2, "%s: COMPRESSION SETUP\n", ptr->name);
+
+		zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SyncRst);
+
+		/* 060 communicates with 067 in master mode */
+		zr36060_write(ptr, ZR060_CIR, ZR060_CIR_CodeMstr);
+
+		/* Compression with or without variable scale factor */
+		/*FIXME: What about ptr->bitrate_ctrl? */
+		zr36060_write(ptr, ZR060_CMR,
+			      ZR060_CMR_Comp | ZR060_CMR_Pass2 |
+			      ZR060_CMR_BRB);
+
+		/* Must be zero */
+		zr36060_write(ptr, ZR060_MBZ, 0x00);
+		zr36060_write(ptr, ZR060_TCR_HI, 0x00);
+		zr36060_write(ptr, ZR060_TCR_LO, 0x00);
+
+		/* Disable all IRQs - no DataErr means autoreset */
+		zr36060_write(ptr, ZR060_IMR, 0);
+
+		/* volume control settings */
+		zr36060_write(ptr, ZR060_SF_HI, ptr->scalefact >> 8);
+		zr36060_write(ptr, ZR060_SF_LO, ptr->scalefact & 0xff);
+
+		zr36060_write(ptr, ZR060_AF_HI, 0xff);
+		zr36060_write(ptr, ZR060_AF_M, 0xff);
+		zr36060_write(ptr, ZR060_AF_LO, 0xff);
+
+		/* setup the variable jpeg tables */
+		sum += zr36060_set_sof(ptr);
+		sum += zr36060_set_sos(ptr);
+		sum += zr36060_set_dri(ptr);
+
+		/* setup the fixed jpeg tables - maybe variable, though -
+		 * (see table init section above) */
+		sum +=
+		    zr36060_pushit(ptr, ZR060_DQT_IDX, sizeof(zr36060_dqt),
+				   zr36060_dqt);
+		sum +=
+		    zr36060_pushit(ptr, ZR060_DHT_IDX, sizeof(zr36060_dht),
+				   zr36060_dht);
+		zr36060_write(ptr, ZR060_APP_IDX, 0xff);
+		zr36060_write(ptr, ZR060_APP_IDX + 1, 0xe0 + ptr->app.appn);
+		zr36060_write(ptr, ZR060_APP_IDX + 2, 0x00);
+		zr36060_write(ptr, ZR060_APP_IDX + 3, ptr->app.len + 2);
+		sum += zr36060_pushit(ptr, ZR060_APP_IDX + 4, 60,
+				      ptr->app.data) + 4;
+		zr36060_write(ptr, ZR060_COM_IDX, 0xff);
+		zr36060_write(ptr, ZR060_COM_IDX + 1, 0xfe);
+		zr36060_write(ptr, ZR060_COM_IDX + 2, 0x00);
+		zr36060_write(ptr, ZR060_COM_IDX + 3, ptr->com.len + 2);
+		sum += zr36060_pushit(ptr, ZR060_COM_IDX + 4, 60,
+				      ptr->com.data) + 4;
+
+		/* setup misc. data for compression (target code sizes) */
+
+		/* size of compressed code to reach without header data */
+		sum = ptr->real_code_vol - sum;
+		bitcnt = sum << 3;	/* need the size in bits */
+
+		tmp = bitcnt >> 16;
+		dprintk(3,
+			"%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n",
+			ptr->name, sum, ptr->real_code_vol, bitcnt, tmp);
+		zr36060_write(ptr, ZR060_TCV_NET_HI, tmp >> 8);
+		zr36060_write(ptr, ZR060_TCV_NET_MH, tmp & 0xff);
+		tmp = bitcnt & 0xffff;
+		zr36060_write(ptr, ZR060_TCV_NET_ML, tmp >> 8);
+		zr36060_write(ptr, ZR060_TCV_NET_LO, tmp & 0xff);
+
+		bitcnt -= bitcnt >> 7;	// bits without stuffing
+		bitcnt -= ((bitcnt * 5) >> 6);	// bits without eob
+
+		tmp = bitcnt >> 16;
+		dprintk(3, "%s: code: nettobit=%ld, highnettobits=%ld\n",
+			ptr->name, bitcnt, tmp);
+		zr36060_write(ptr, ZR060_TCV_DATA_HI, tmp >> 8);
+		zr36060_write(ptr, ZR060_TCV_DATA_MH, tmp & 0xff);
+		tmp = bitcnt & 0xffff;
+		zr36060_write(ptr, ZR060_TCV_DATA_ML, tmp >> 8);
+		zr36060_write(ptr, ZR060_TCV_DATA_LO, tmp & 0xff);
+
+		/* JPEG markers to be included in the compressed stream */
+		zr36060_write(ptr, ZR060_MER,
+			      ZR060_MER_DQT | ZR060_MER_DHT |
+			      ((ptr->com.len > 0) ? ZR060_MER_Com : 0) |
+			      ((ptr->app.len > 0) ? ZR060_MER_App : 0));
+
+		/* Setup the Video Frontend */
+		/* Limit pixel range to 16..235 as per CCIR-601 */
+		zr36060_write(ptr, ZR060_VCR, ZR060_VCR_Range);
+
+	} else {
+		dprintk(2, "%s: EXPANSION SETUP\n", ptr->name);
+
+		zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SyncRst);
+
+		/* 060 communicates with 067 in master mode */
+		zr36060_write(ptr, ZR060_CIR, ZR060_CIR_CodeMstr);
+
+		/* Decompression */
+		zr36060_write(ptr, ZR060_CMR, 0);
+
+		/* Must be zero */
+		zr36060_write(ptr, ZR060_MBZ, 0x00);
+		zr36060_write(ptr, ZR060_TCR_HI, 0x00);
+		zr36060_write(ptr, ZR060_TCR_LO, 0x00);
+
+		/* Disable all IRQs - no DataErr means autoreset */
+		zr36060_write(ptr, ZR060_IMR, 0);
+
+		/* setup misc. data for expansion */
+		zr36060_write(ptr, ZR060_MER, 0);
+
+		/* setup the fixed jpeg tables - maybe variable, though -
+		 * (see table init section above) */
+		zr36060_pushit(ptr, ZR060_DHT_IDX, sizeof(zr36060_dht),
+			       zr36060_dht);
+
+		/* Setup the Video Frontend */
+		//zr36060_write(ptr, ZR060_VCR, ZR060_VCR_FIExt);
+		//this doesn't seem right and doesn't work...
+		zr36060_write(ptr, ZR060_VCR, ZR060_VCR_Range);
+	}
+
+	/* Load the tables */
+	zr36060_write(ptr, ZR060_LOAD,
+		      ZR060_LOAD_SyncRst | ZR060_LOAD_Load);
+	zr36060_wait_end(ptr);
+	dprintk(2, "%s: Status after table preload: 0x%02x\n", ptr->name,
+		ptr->status);
+
+	if (ptr->status & ZR060_CFSR_Busy) {
+		dprintk(1, KERN_ERR "%s: init aborted!\n", ptr->name);
+		return;		// something is wrong, its timed out!!!!
+	}
+}
+
+/* =========================================================================
+   CODEC API FUNCTIONS
+
+   this functions are accessed by the master via the API structure
+   ========================================================================= */
+
+/* set compression/expansion mode and launches codec -
+   this should be the last call from the master before starting processing */
+static int
+zr36060_set_mode (struct videocodec *codec,
+		  int                mode)
+{
+	struct zr36060 *ptr = (struct zr36060 *) codec->data;
+
+	dprintk(2, "%s: set_mode %d call\n", ptr->name, mode);
+
+	if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION))
+		return -EINVAL;
+
+	ptr->mode = mode;
+	zr36060_init(ptr);
+
+	return 0;
+}
+
+/* set picture size (norm is ignored as the codec doesn't know about it) */
+static int
+zr36060_set_video (struct videocodec   *codec,
+		   struct tvnorm       *norm,
+		   struct vfe_settings *cap,
+		   struct vfe_polarity *pol)
+{
+	struct zr36060 *ptr = (struct zr36060 *) codec->data;
+	u32 reg;
+	int size;
+
+	dprintk(2, "%s: set_video %d/%d-%dx%d (%%%d) call\n", ptr->name,
+		cap->x, cap->y, cap->width, cap->height, cap->decimation);
+
+	/* if () return -EINVAL;
+	 * trust the master driver that it knows what it does - so
+	 * we allow invalid startx/y and norm for now ... */
+	ptr->width = cap->width / (cap->decimation & 0xff);
+	ptr->height = cap->height / (cap->decimation >> 8);
+
+	zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SyncRst);
+
+	/* Note that VSPol/HSPol bits in zr36060 have the opposite
+	 * meaning of their zr360x7 counterparts with the same names
+	 * N.b. for VSPol this is only true if FIVEdge = 0 (default,
+	 * left unchanged here - in accordance with datasheet).
+	*/
+	reg = (!pol->vsync_pol ? ZR060_VPR_VSPol : 0)
+	    | (!pol->hsync_pol ? ZR060_VPR_HSPol : 0)
+	    | (pol->field_pol ? ZR060_VPR_FIPol : 0)
+	    | (pol->blank_pol ? ZR060_VPR_BLPol : 0)
+	    | (pol->subimg_pol ? ZR060_VPR_SImgPol : 0)
+	    | (pol->poe_pol ? ZR060_VPR_PoePol : 0)
+	    | (pol->pvalid_pol ? ZR060_VPR_PValPol : 0)
+	    | (pol->vclk_pol ? ZR060_VPR_VCLKPol : 0);
+	zr36060_write(ptr, ZR060_VPR, reg);
+
+	reg = 0;
+	switch (cap->decimation & 0xff) {
+	default:
+	case 1:
+		break;
+
+	case 2:
+		reg |= ZR060_SR_HScale2;
+		break;
+
+	case 4:
+		reg |= ZR060_SR_HScale4;
+		break;
+	}
+
+	switch (cap->decimation >> 8) {
+	default:
+	case 1:
+		break;
+
+	case 2:
+		reg |= ZR060_SR_VScale;
+		break;
+	}
+	zr36060_write(ptr, ZR060_SR, reg);
+
+	zr36060_write(ptr, ZR060_BCR_Y, 0x00);
+	zr36060_write(ptr, ZR060_BCR_U, 0x80);
+	zr36060_write(ptr, ZR060_BCR_V, 0x80);
+
+	/* sync generator */
+
+	reg = norm->Ht - 1;	/* Vtotal */
+	zr36060_write(ptr, ZR060_SGR_VTOTAL_HI, (reg >> 8) & 0xff);
+	zr36060_write(ptr, ZR060_SGR_VTOTAL_LO, (reg >> 0) & 0xff);
+
+	reg = norm->Wt - 1;	/* Htotal */
+	zr36060_write(ptr, ZR060_SGR_HTOTAL_HI, (reg >> 8) & 0xff);
+	zr36060_write(ptr, ZR060_SGR_HTOTAL_LO, (reg >> 0) & 0xff);
+
+	reg = 6 - 1;		/* VsyncSize */
+	zr36060_write(ptr, ZR060_SGR_VSYNC, reg);
+
+	//reg   = 30 - 1;               /* HsyncSize */
+///*CP*/        reg = (zr->params.norm == 1 ? 57 : 68);
+	reg = 68;
+	zr36060_write(ptr, ZR060_SGR_HSYNC, reg);
+
+	reg = norm->VStart - 1;	/* BVstart */
+	zr36060_write(ptr, ZR060_SGR_BVSTART, reg);
+
+	reg += norm->Ha / 2;	/* BVend */
+	zr36060_write(ptr, ZR060_SGR_BVEND_HI, (reg >> 8) & 0xff);
+	zr36060_write(ptr, ZR060_SGR_BVEND_LO, (reg >> 0) & 0xff);
+
+	reg = norm->HStart - 1;	/* BHstart */
+	zr36060_write(ptr, ZR060_SGR_BHSTART, reg);
+
+	reg += norm->Wa;	/* BHend */
+	zr36060_write(ptr, ZR060_SGR_BHEND_HI, (reg >> 8) & 0xff);
+	zr36060_write(ptr, ZR060_SGR_BHEND_LO, (reg >> 0) & 0xff);
+
+	/* active area */
+	reg = cap->y + norm->VStart;	/* Vstart */
+	zr36060_write(ptr, ZR060_AAR_VSTART_HI, (reg >> 8) & 0xff);
+	zr36060_write(ptr, ZR060_AAR_VSTART_LO, (reg >> 0) & 0xff);
+
+	reg += cap->height;	/* Vend */
+	zr36060_write(ptr, ZR060_AAR_VEND_HI, (reg >> 8) & 0xff);
+	zr36060_write(ptr, ZR060_AAR_VEND_LO, (reg >> 0) & 0xff);
+
+	reg = cap->x + norm->HStart;	/* Hstart */
+	zr36060_write(ptr, ZR060_AAR_HSTART_HI, (reg >> 8) & 0xff);
+	zr36060_write(ptr, ZR060_AAR_HSTART_LO, (reg >> 0) & 0xff);
+
+	reg += cap->width;	/* Hend */
+	zr36060_write(ptr, ZR060_AAR_HEND_HI, (reg >> 8) & 0xff);
+	zr36060_write(ptr, ZR060_AAR_HEND_LO, (reg >> 0) & 0xff);
+
+	/* subimage area */
+	reg = norm->VStart - 4;	/* SVstart */
+	zr36060_write(ptr, ZR060_SWR_VSTART_HI, (reg >> 8) & 0xff);
+	zr36060_write(ptr, ZR060_SWR_VSTART_LO, (reg >> 0) & 0xff);
+
+	reg += norm->Ha / 2 + 8;	/* SVend */
+	zr36060_write(ptr, ZR060_SWR_VEND_HI, (reg >> 8) & 0xff);
+	zr36060_write(ptr, ZR060_SWR_VEND_LO, (reg >> 0) & 0xff);
+
+	reg = norm->HStart /*+ 64 */  - 4;	/* SHstart */
+	zr36060_write(ptr, ZR060_SWR_HSTART_HI, (reg >> 8) & 0xff);
+	zr36060_write(ptr, ZR060_SWR_HSTART_LO, (reg >> 0) & 0xff);
+
+	reg += norm->Wa + 8;	/* SHend */
+	zr36060_write(ptr, ZR060_SWR_HEND_HI, (reg >> 8) & 0xff);
+	zr36060_write(ptr, ZR060_SWR_HEND_LO, (reg >> 0) & 0xff);
+
+	size = ptr->width * ptr->height;
+	/* Target compressed field size in bits: */
+	size = size * 16;	/* uncompressed size in bits */
+	/* (Ronald) by default, quality = 100 is a compression
+	 * ratio 1:2. Setting low_bitrate (insmod option) sets
+	 * it to 1:4 (instead of 1:2, zr36060 max) as limit because the
+	 * buz can't handle more at decimation=1... Use low_bitrate if
+	 * you have a Buz, unless you know what you're doing */
+	size = size * cap->quality / (low_bitrate ? 400 : 200);
+	/* Lower limit (arbitrary, 1 KB) */
+	if (size < 8192)
+		size = 8192;
+	/* Upper limit: 7/8 of the code buffers */
+	if (size > ptr->total_code_vol * 7)
+		size = ptr->total_code_vol * 7;
+
+	ptr->real_code_vol = size >> 3;	/* in bytes */
+
+	/* the MBCVR is the *maximum* block volume, according to the
+	 * JPEG ISO specs, this shouldn't be used, since that allows
+	 * for the best encoding quality. So set it to it's max value */
+	reg = ptr->max_block_vol;
+	zr36060_write(ptr, ZR060_MBCVR, reg);
+
+	return 0;
+}
+
+/* additional control functions */
+static int
+zr36060_control (struct videocodec *codec,
+		 int                type,
+		 int                size,
+		 void              *data)
+{
+	struct zr36060 *ptr = (struct zr36060 *) codec->data;
+	int *ival = (int *) data;
+
+	dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type,
+		size);
+
+	switch (type) {
+	case CODEC_G_STATUS:	/* get last status */
+		if (size != sizeof(int))
+			return -EFAULT;
+		zr36060_read_status(ptr);
+		*ival = ptr->status;
+		break;
+
+	case CODEC_G_CODEC_MODE:
+		if (size != sizeof(int))
+			return -EFAULT;
+		*ival = CODEC_MODE_BJPG;
+		break;
+
+	case CODEC_S_CODEC_MODE:
+		if (size != sizeof(int))
+			return -EFAULT;
+		if (*ival != CODEC_MODE_BJPG)
+			return -EINVAL;
+		/* not needed, do nothing */
+		return 0;
+
+	case CODEC_G_VFE:
+	case CODEC_S_VFE:
+		/* not needed, do nothing */
+		return 0;
+
+	case CODEC_S_MMAP:
+		/* not available, give an error */
+		return -ENXIO;
+
+	case CODEC_G_JPEG_TDS_BYTE:	/* get target volume in byte */
+		if (size != sizeof(int))
+			return -EFAULT;
+		*ival = ptr->total_code_vol;
+		break;
+
+	case CODEC_S_JPEG_TDS_BYTE:	/* get target volume in byte */
+		if (size != sizeof(int))
+			return -EFAULT;
+		ptr->total_code_vol = *ival;
+		ptr->real_code_vol = (ptr->total_code_vol * 6) >> 3;
+		break;
+
+	case CODEC_G_JPEG_SCALE:	/* get scaling factor */
+		if (size != sizeof(int))
+			return -EFAULT;
+		*ival = zr36060_read_scalefactor(ptr);
+		break;
+
+	case CODEC_S_JPEG_SCALE:	/* set scaling factor */
+		if (size != sizeof(int))
+			return -EFAULT;
+		ptr->scalefact = *ival;
+		break;
+
+	case CODEC_G_JPEG_APP_DATA: {	/* get appn marker data */
+		struct jpeg_app_marker *app = data;
+
+		if (size != sizeof(struct jpeg_app_marker))
+			return -EFAULT;
+
+		*app = ptr->app;
+		break;
+	}
+
+	case CODEC_S_JPEG_APP_DATA: {	/* set appn marker data */
+		struct jpeg_app_marker *app = data;
+
+		if (size != sizeof(struct jpeg_app_marker))
+			return -EFAULT;
+
+		ptr->app = *app;
+		break;
+	}
+
+	case CODEC_G_JPEG_COM_DATA: {	/* get comment marker data */
+		struct jpeg_com_marker *com = data;
+
+		if (size != sizeof(struct jpeg_com_marker))
+			return -EFAULT;
+
+		*com = ptr->com;
+		break;
+	}
+
+	case CODEC_S_JPEG_COM_DATA: {	/* set comment marker data */
+		struct jpeg_com_marker *com = data;
+
+		if (size != sizeof(struct jpeg_com_marker))
+			return -EFAULT;
+
+		ptr->com = *com;
+		break;
+	}
+
+	default:
+		return -EINVAL;
+	}
+
+	return size;
+}
+
+/* =========================================================================
+   Exit and unregister function:
+
+   Deinitializes Zoran's JPEG processor
+   ========================================================================= */
+
+static int
+zr36060_unset (struct videocodec *codec)
+{
+	struct zr36060 *ptr = codec->data;
+
+	if (ptr) {
+		/* do wee need some codec deinit here, too ???? */
+
+		dprintk(1, "%s: finished codec #%d\n", ptr->name,
+			ptr->num);
+		kfree(ptr);
+		codec->data = NULL;
+
+		zr36060_codecs--;
+		return 0;
+	}
+
+	return -EFAULT;
+}
+
+/* =========================================================================
+   Setup and registry function:
+
+   Initializes Zoran's JPEG processor
+
+   Also sets pixel size, average code size, mode (compr./decompr.)
+   (the given size is determined by the processor with the video interface)
+   ========================================================================= */
+
+static int
+zr36060_setup (struct videocodec *codec)
+{
+	struct zr36060 *ptr;
+	int res;
+
+	dprintk(2, "zr36060: initializing MJPEG subsystem #%d.\n",
+		zr36060_codecs);
+
+	if (zr36060_codecs == MAX_CODECS) {
+		dprintk(1,
+			KERN_ERR "zr36060: Can't attach more codecs!\n");
+		return -ENOSPC;
+	}
+	//mem structure init
+	codec->data = ptr = kzalloc(sizeof(struct zr36060), GFP_KERNEL);
+	if (NULL == ptr) {
+		dprintk(1, KERN_ERR "zr36060: Can't get enough memory!\n");
+		return -ENOMEM;
+	}
+
+	snprintf(ptr->name, sizeof(ptr->name), "zr36060[%d]",
+		 zr36060_codecs);
+	ptr->num = zr36060_codecs++;
+	ptr->codec = codec;
+
+	//testing
+	res = zr36060_basic_test(ptr);
+	if (res < 0) {
+		zr36060_unset(codec);
+		return res;
+	}
+	//final setup
+	memcpy(ptr->h_samp_ratio, zr36060_decimation_h, 8);
+	memcpy(ptr->v_samp_ratio, zr36060_decimation_v, 8);
+
+	ptr->bitrate_ctrl = 0;	/* 0 or 1 - fixed file size flag
+				 * (what is the difference?) */
+	ptr->mode = CODEC_DO_COMPRESSION;
+	ptr->width = 384;
+	ptr->height = 288;
+	ptr->total_code_vol = 16000;	/* CHECKME */
+	ptr->real_code_vol = (ptr->total_code_vol * 6) >> 3;
+	ptr->max_block_vol = 240;	/* CHECKME, was 120 is 240 */
+	ptr->scalefact = 0x100;
+	ptr->dri = 1;		/* CHECKME, was 8 is 1 */
+
+	/* by default, no COM or APP markers - app should set those */
+	ptr->com.len = 0;
+	ptr->app.appn = 0;
+	ptr->app.len = 0;
+
+	zr36060_init(ptr);
+
+	dprintk(1, KERN_INFO "%s: codec attached and running\n",
+		ptr->name);
+
+	return 0;
+}
+
+static const struct videocodec zr36060_codec = {
+	.owner = THIS_MODULE,
+	.name = "zr36060",
+	.magic = 0L,		// magic not used
+	.flags =
+	    CODEC_FLAG_JPEG | CODEC_FLAG_HARDWARE | CODEC_FLAG_ENCODER |
+	    CODEC_FLAG_DECODER | CODEC_FLAG_VFE,
+	.type = CODEC_TYPE_ZR36060,
+	.setup = zr36060_setup,	// functionality
+	.unset = zr36060_unset,
+	.set_mode = zr36060_set_mode,
+	.set_video = zr36060_set_video,
+	.control = zr36060_control,
+	// others are not used
+};
+
+/* =========================================================================
+   HOOK IN DRIVER AS KERNEL MODULE
+   ========================================================================= */
+
+static int __init
+zr36060_init_module (void)
+{
+	//dprintk(1, "zr36060 driver %s\n",ZR060_VERSION);
+	zr36060_codecs = 0;
+	return videocodec_register(&zr36060_codec);
+}
+
+static void __exit
+zr36060_cleanup_module (void)
+{
+	if (zr36060_codecs) {
+		dprintk(1,
+			"zr36060: something's wrong - %d codecs left somehow.\n",
+			zr36060_codecs);
+	}
+
+	/* however, we can't just stay alive */
+	videocodec_unregister(&zr36060_codec);
+}
+
+module_init(zr36060_init_module);
+module_exit(zr36060_cleanup_module);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@skynet.be>");
+MODULE_DESCRIPTION("Driver module for ZR36060 jpeg processors "
+		   ZR060_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/zoran/zr36060.h b/drivers/media/pci/zoran/zr36060.h
new file mode 100644
index 0000000..914ffa4
--- /dev/null
+++ b/drivers/media/pci/zoran/zr36060.h
@@ -0,0 +1,220 @@
+/*
+ * Zoran ZR36060 basic configuration functions - header file
+ *
+ * Copyright (C) 2002 Laurent Pinchart <laurent.pinchart@skynet.be>
+ *
+ * $Id: zr36060.h,v 1.1.1.1.2.3 2003/01/14 21:18:47 rbultje Exp $
+ *
+ * ------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * ------------------------------------------------------------------------
+ */
+
+#ifndef ZR36060_H
+#define ZR36060_H
+
+#include "videocodec.h"
+
+/* data stored for each zoran jpeg codec chip */
+struct zr36060 {
+	char name[32];
+	int num;
+	/* io datastructure */
+	struct videocodec *codec;
+	// last coder status
+	__u8 status;
+	// actual coder setup
+	int mode;
+
+	__u16 width;
+	__u16 height;
+
+	__u16 bitrate_ctrl;
+
+	__u32 total_code_vol;
+	__u32 real_code_vol;
+	__u16 max_block_vol;
+
+	__u8 h_samp_ratio[8];
+	__u8 v_samp_ratio[8];
+	__u16 scalefact;
+	__u16 dri;
+
+	/* app/com marker data */
+	struct jpeg_app_marker app;
+	struct jpeg_com_marker com;
+};
+
+/* ZR36060 register addresses */
+#define ZR060_LOAD			0x000
+#define ZR060_CFSR			0x001
+#define ZR060_CIR			0x002
+#define ZR060_CMR			0x003
+#define ZR060_MBZ			0x004
+#define ZR060_MBCVR			0x005
+#define ZR060_MER			0x006
+#define ZR060_IMR			0x007
+#define ZR060_ISR			0x008
+#define ZR060_TCV_NET_HI		0x009
+#define ZR060_TCV_NET_MH		0x00a
+#define ZR060_TCV_NET_ML		0x00b
+#define ZR060_TCV_NET_LO		0x00c
+#define ZR060_TCV_DATA_HI		0x00d
+#define ZR060_TCV_DATA_MH		0x00e
+#define ZR060_TCV_DATA_ML		0x00f
+#define ZR060_TCV_DATA_LO		0x010
+#define ZR060_SF_HI			0x011
+#define ZR060_SF_LO			0x012
+#define ZR060_AF_HI			0x013
+#define ZR060_AF_M			0x014
+#define ZR060_AF_LO			0x015
+#define ZR060_ACV_HI			0x016
+#define ZR060_ACV_MH			0x017
+#define ZR060_ACV_ML			0x018
+#define ZR060_ACV_LO			0x019
+#define ZR060_ACT_HI			0x01a
+#define ZR060_ACT_MH			0x01b
+#define ZR060_ACT_ML			0x01c
+#define ZR060_ACT_LO			0x01d
+#define ZR060_ACV_TRUN_HI		0x01e
+#define ZR060_ACV_TRUN_MH		0x01f
+#define ZR060_ACV_TRUN_ML		0x020
+#define ZR060_ACV_TRUN_LO		0x021
+#define ZR060_IDR_DEV			0x022
+#define ZR060_IDR_REV			0x023
+#define ZR060_TCR_HI			0x024
+#define ZR060_TCR_LO			0x025
+#define ZR060_VCR			0x030
+#define ZR060_VPR			0x031
+#define ZR060_SR			0x032
+#define ZR060_BCR_Y			0x033
+#define ZR060_BCR_U			0x034
+#define ZR060_BCR_V			0x035
+#define ZR060_SGR_VTOTAL_HI		0x036
+#define ZR060_SGR_VTOTAL_LO		0x037
+#define ZR060_SGR_HTOTAL_HI		0x038
+#define ZR060_SGR_HTOTAL_LO		0x039
+#define ZR060_SGR_VSYNC			0x03a
+#define ZR060_SGR_HSYNC			0x03b
+#define ZR060_SGR_BVSTART		0x03c
+#define ZR060_SGR_BHSTART		0x03d
+#define ZR060_SGR_BVEND_HI		0x03e
+#define ZR060_SGR_BVEND_LO		0x03f
+#define ZR060_SGR_BHEND_HI		0x040
+#define ZR060_SGR_BHEND_LO		0x041
+#define ZR060_AAR_VSTART_HI		0x042
+#define ZR060_AAR_VSTART_LO		0x043
+#define ZR060_AAR_VEND_HI		0x044
+#define ZR060_AAR_VEND_LO		0x045
+#define ZR060_AAR_HSTART_HI		0x046
+#define ZR060_AAR_HSTART_LO		0x047
+#define ZR060_AAR_HEND_HI		0x048
+#define ZR060_AAR_HEND_LO		0x049
+#define ZR060_SWR_VSTART_HI		0x04a
+#define ZR060_SWR_VSTART_LO		0x04b
+#define ZR060_SWR_VEND_HI		0x04c
+#define ZR060_SWR_VEND_LO		0x04d
+#define ZR060_SWR_HSTART_HI		0x04e
+#define ZR060_SWR_HSTART_LO		0x04f
+#define ZR060_SWR_HEND_HI		0x050
+#define ZR060_SWR_HEND_LO		0x051
+
+#define ZR060_SOF_IDX			0x060
+#define ZR060_SOS_IDX			0x07a
+#define ZR060_DRI_IDX			0x0c0
+#define ZR060_DQT_IDX			0x0cc
+#define ZR060_DHT_IDX			0x1d4
+#define ZR060_APP_IDX			0x380
+#define ZR060_COM_IDX			0x3c0
+
+/* ZR36060 LOAD register bits */
+
+#define ZR060_LOAD_Load			(1 << 7)
+#define ZR060_LOAD_SyncRst		(1 << 0)
+
+/* ZR36060 Code FIFO Status register bits */
+
+#define ZR060_CFSR_Busy			(1 << 7)
+#define ZR060_CFSR_CBusy		(1 << 2)
+#define ZR060_CFSR_CFIFO		(3 << 0)
+
+/* ZR36060 Code Interface register */
+
+#define ZR060_CIR_Code16		(1 << 7)
+#define ZR060_CIR_Endian		(1 << 6)
+#define ZR060_CIR_CFIS			(1 << 2)
+#define ZR060_CIR_CodeMstr		(1 << 0)
+
+/* ZR36060 Codec Mode register */
+
+#define ZR060_CMR_Comp			(1 << 7)
+#define ZR060_CMR_ATP			(1 << 6)
+#define ZR060_CMR_Pass2			(1 << 5)
+#define ZR060_CMR_TLM			(1 << 4)
+#define ZR060_CMR_BRB			(1 << 2)
+#define ZR060_CMR_FSF			(1 << 1)
+
+/* ZR36060 Markers Enable register */
+
+#define ZR060_MER_App			(1 << 7)
+#define ZR060_MER_Com			(1 << 6)
+#define ZR060_MER_DRI			(1 << 5)
+#define ZR060_MER_DQT			(1 << 4)
+#define ZR060_MER_DHT			(1 << 3)
+
+/* ZR36060 Interrupt Mask register */
+
+#define ZR060_IMR_EOAV			(1 << 3)
+#define ZR060_IMR_EOI			(1 << 2)
+#define ZR060_IMR_End			(1 << 1)
+#define ZR060_IMR_DataErr		(1 << 0)
+
+/* ZR36060 Interrupt Status register */
+
+#define ZR060_ISR_ProCnt		(3 << 6)
+#define ZR060_ISR_EOAV			(1 << 3)
+#define ZR060_ISR_EOI			(1 << 2)
+#define ZR060_ISR_End			(1 << 1)
+#define ZR060_ISR_DataErr		(1 << 0)
+
+/* ZR36060 Video Control register */
+
+#define ZR060_VCR_Video8		(1 << 7)
+#define ZR060_VCR_Range			(1 << 6)
+#define ZR060_VCR_FIDet			(1 << 3)
+#define ZR060_VCR_FIVedge		(1 << 2)
+#define ZR060_VCR_FIExt			(1 << 1)
+#define ZR060_VCR_SyncMstr		(1 << 0)
+
+/* ZR36060 Video Polarity register */
+
+#define ZR060_VPR_VCLKPol		(1 << 7)
+#define ZR060_VPR_PValPol		(1 << 6)
+#define ZR060_VPR_PoePol		(1 << 5)
+#define ZR060_VPR_SImgPol		(1 << 4)
+#define ZR060_VPR_BLPol			(1 << 3)
+#define ZR060_VPR_FIPol			(1 << 2)
+#define ZR060_VPR_HSPol			(1 << 1)
+#define ZR060_VPR_VSPol			(1 << 0)
+
+/* ZR36060 Scaling register */
+
+#define ZR060_SR_VScale			(1 << 2)
+#define ZR060_SR_HScale2		(1 << 0)
+#define ZR060_SR_HScale4		(2 << 0)
+
+#endif				/*fndef ZR36060_H */
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
new file mode 100644
index 0000000..e1959a8
--- /dev/null
+++ b/drivers/media/platform/Kconfig
@@ -0,0 +1,297 @@
+if MEDIA_CAMERA_SUPPORT
+
+config VIDEO_VIVI
+	tristate "Virtual Video Driver"
+	depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
+	depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
+	select FONT_8x16
+	select VIDEOBUF2_VMALLOC
+	default n
+	---help---
+	  Enables a virtual video driver. This device shows a color bar
+	  and a timestamp, as a real device would generate by using V4L2
+	  api.
+	  Say Y here if you want to test video apps or debug V4L devices.
+	  In doubt, say N.
+
+#
+# Platform drivers
+#	All drivers here are currently for webcam support
+
+menuconfig V4L_PLATFORM_DRIVERS
+	bool "V4L platform devices"
+	depends on MEDIA_CAMERA_SUPPORT
+	default n
+	---help---
+	  Say Y here to enable support for platform-specific V4L drivers.
+
+if V4L_PLATFORM_DRIVERS
+
+source "drivers/media/platform/marvell-ccic/Kconfig"
+
+config VIDEO_VIA_CAMERA
+	tristate "VIAFB camera controller support"
+	depends on FB_VIA
+	select VIDEOBUF_DMA_SG
+	select VIDEO_OV7670
+	help
+	   Driver support for the integrated camera controller in VIA
+	   Chrome9 chipsets.  Currently only tested on OLPC xo-1.5 systems
+	   with ov7670 sensors.
+
+#
+# Platform multimedia device configuration
+#
+
+source "drivers/media/platform/davinci/Kconfig"
+
+source "drivers/media/platform/omap/Kconfig"
+
+source "drivers/media/platform/blackfin/Kconfig"
+
+config VIDEO_SH_VOU
+	tristate "SuperH VOU video output driver"
+	depends on VIDEO_DEV && ARCH_SHMOBILE
+	select VIDEOBUF_DMA_CONTIG
+	help
+	  Support for the Video Output Unit (VOU) on SuperH SoCs.
+
+config VIDEO_VIU
+	tristate "Freescale VIU Video Driver"
+	depends on VIDEO_V4L2 && PPC_MPC512x
+	select VIDEOBUF_DMA_CONTIG
+	default y
+	---help---
+	  Support for Freescale VIU video driver. This device captures
+	  video data, or overlays video on DIU frame buffer.
+
+	  Say Y here if you want to enable VIU device on MPC5121e Rev2+.
+	  In doubt, say N.
+
+config VIDEO_TIMBERDALE
+	tristate "Support for timberdale Video In/LogiWIN"
+	depends on VIDEO_V4L2 && I2C && DMADEVICES
+	select DMA_ENGINE
+	select TIMB_DMA
+	select VIDEO_ADV7180
+	select VIDEOBUF_DMA_CONTIG
+	---help---
+	  Add support for the Video In peripherial of the timberdale FPGA.
+
+config VIDEO_VINO
+	tristate "SGI Vino Video For Linux"
+	depends on I2C && SGI_IP22 && VIDEO_V4L2
+	select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO
+	help
+	  Say Y here to build in support for the Vino video input system found
+	  on SGI Indy machines.
+
+config VIDEO_M32R_AR
+	tristate "AR devices"
+	depends on M32R && VIDEO_V4L2
+	---help---
+	  This is a video4linux driver for the Renesas AR (Artificial Retina)
+	  camera module.
+
+config VIDEO_M32R_AR_M64278
+	tristate "AR device with color module M64278(VGA)"
+	depends on PLAT_M32700UT
+	select VIDEO_M32R_AR
+	---help---
+	  This is a video4linux driver for the Renesas AR (Artificial
+	  Retina) with M64278E-800 camera module.
+	  This module supports VGA(640x480 pixels) resolutions.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called arv.
+
+config VIDEO_OMAP3
+	tristate "OMAP 3 Camera support (EXPERIMENTAL)"
+	depends on OMAP_IOVMM && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 && EXPERIMENTAL
+	---help---
+	  Driver for an OMAP 3 camera controller.
+
+config VIDEO_OMAP3_DEBUG
+	bool "OMAP 3 Camera debug messages"
+	depends on VIDEO_OMAP3
+	---help---
+	  Enable debug messages on OMAP 3 camera controller driver.
+
+config SOC_CAMERA
+	tristate "SoC camera support"
+	depends on VIDEO_V4L2 && HAS_DMA && I2C
+	select VIDEOBUF_GEN
+	select VIDEOBUF2_CORE
+	help
+	  SoC Camera is a common API to several cameras, not connecting
+	  over a bus like PCI or USB. For example some i2c camera connected
+	  directly to the data bus of an SoC.
+
+
+config SOC_CAMERA_PLATFORM
+	tristate "platform camera support"
+	depends on SOC_CAMERA
+	help
+	  This is a generic SoC camera platform driver, useful for testing
+
+config MX1_VIDEO
+	bool
+
+config VIDEO_MX1
+	tristate "i.MX1/i.MXL CMOS Sensor Interface driver"
+	depends on VIDEO_DEV && ARCH_MX1 && SOC_CAMERA
+	select FIQ
+	select VIDEOBUF_DMA_CONTIG
+	select MX1_VIDEO
+	---help---
+	  This is a v4l2 driver for the i.MX1/i.MXL CMOS Sensor Interface
+
+config MX3_VIDEO
+	bool
+
+config VIDEO_MX3
+	tristate "i.MX3x Camera Sensor Interface driver"
+	depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
+	select VIDEOBUF2_DMA_CONTIG
+	select MX3_VIDEO
+	---help---
+	  This is a v4l2 driver for the i.MX3x Camera Sensor Interface
+
+config VIDEO_PXA27x
+	tristate "PXA27x Quick Capture Interface driver"
+	depends on VIDEO_DEV && PXA27x && SOC_CAMERA
+	select VIDEOBUF_DMA_SG
+	---help---
+	  This is a v4l2 driver for the PXA27x Quick Capture Interface
+
+config VIDEO_SH_MOBILE_CSI2
+	tristate "SuperH Mobile MIPI CSI-2 Interface driver"
+	depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK
+	---help---
+	  This is a v4l2 driver for the SuperH MIPI CSI-2 Interface
+
+config VIDEO_SH_MOBILE_CEU
+	tristate "SuperH Mobile CEU Interface driver"
+	depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
+	select VIDEOBUF2_DMA_CONTIG
+	---help---
+	  This is a v4l2 driver for the SuperH Mobile CEU Interface
+
+config VIDEO_OMAP1
+	tristate "OMAP1 Camera Interface driver"
+	depends on VIDEO_DEV && ARCH_OMAP1 && SOC_CAMERA
+	select VIDEOBUF_DMA_CONTIG
+	select VIDEOBUF_DMA_SG
+	---help---
+	  This is a v4l2 driver for the TI OMAP1 camera interface
+
+config VIDEO_OMAP2
+	tristate "OMAP2 Camera Capture Interface driver"
+	depends on VIDEO_DEV && ARCH_OMAP2
+	select VIDEOBUF_DMA_SG
+	---help---
+	  This is a v4l2 driver for the TI OMAP2 camera capture interface
+
+config VIDEO_MX2_HOSTSUPPORT
+	bool
+
+config VIDEO_MX2
+	tristate "i.MX27/i.MX25 Camera Sensor Interface driver"
+	depends on VIDEO_DEV && SOC_CAMERA && (MACH_MX27 || (ARCH_MX25 && BROKEN))
+	select VIDEOBUF2_DMA_CONTIG
+	select VIDEO_MX2_HOSTSUPPORT
+	---help---
+	  This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor
+	  Interface
+
+config VIDEO_ATMEL_ISI
+	tristate "ATMEL Image Sensor Interface (ISI) support"
+	depends on VIDEO_DEV && SOC_CAMERA && ARCH_AT91
+	select VIDEOBUF2_DMA_CONTIG
+	---help---
+	  This module makes the ATMEL Image Sensor Interface available
+	  as a v4l2 device.
+
+source "drivers/media/platform/s5p-fimc/Kconfig"
+source "drivers/media/platform/s5p-tv/Kconfig"
+
+endif # V4L_PLATFORM_DRIVERS
+
+menuconfig V4L_MEM2MEM_DRIVERS
+	bool "Memory-to-memory multimedia devices"
+	depends on VIDEO_V4L2
+	default n
+	---help---
+	  Say Y here to enable selecting drivers for V4L devices that
+	  use system memory for both source and destination buffers, as opposed
+	  to capture and output drivers, which use memory buffers for just
+	  one of those.
+
+if V4L_MEM2MEM_DRIVERS
+
+config VIDEO_MEM2MEM_TESTDEV
+	tristate "Virtual test device for mem2mem framework"
+	depends on VIDEO_DEV && VIDEO_V4L2
+	select VIDEOBUF2_VMALLOC
+	select V4L2_MEM2MEM_DEV
+	default n
+	---help---
+	  This is a virtual test device for the memory-to-memory driver
+	  framework.
+
+config VIDEO_CODA
+	tristate "Chips&Media Coda multi-standard codec IP"
+	depends on VIDEO_DEV && VIDEO_V4L2
+	select VIDEOBUF2_DMA_CONTIG
+	select V4L2_MEM2MEM_DEV
+	---help---
+	   Coda is a range of video codec IPs that supports
+	   H.264, MPEG-4, and other video formats.
+
+config VIDEO_MEM2MEM_DEINTERLACE
+	tristate "Deinterlace support"
+	depends on VIDEO_DEV && VIDEO_V4L2 && DMA_ENGINE
+	select VIDEOBUF2_DMA_CONTIG
+	select V4L2_MEM2MEM_DEV
+	help
+	    Generic deinterlacing V4L2 driver.
+
+config VIDEO_SAMSUNG_S5P_G2D
+	tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver"
+	depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
+	select VIDEOBUF2_DMA_CONTIG
+	select V4L2_MEM2MEM_DEV
+	default n
+	---help---
+	  This is a v4l2 driver for Samsung S5P and EXYNOS4 G2D
+	  2d graphics accelerator.
+
+config VIDEO_SAMSUNG_S5P_JPEG
+	tristate "Samsung S5P/Exynos4 JPEG codec driver (EXPERIMENTAL)"
+	depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P && EXPERIMENTAL
+	select VIDEOBUF2_DMA_CONTIG
+	select V4L2_MEM2MEM_DEV
+	---help---
+	  This is a v4l2 driver for Samsung S5P and EXYNOS4 JPEG codec
+
+config VIDEO_SAMSUNG_S5P_MFC
+	tristate "Samsung S5P MFC 5.1 Video Codec"
+	depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
+	select VIDEOBUF2_DMA_CONTIG
+	default n
+	help
+	    MFC 5.1 driver for V4L2.
+
+config VIDEO_MX2_EMMAPRP
+	tristate "MX2 eMMa-PrP support"
+	depends on VIDEO_DEV && VIDEO_V4L2 && SOC_IMX27
+	select VIDEOBUF2_DMA_CONTIG
+	select V4L2_MEM2MEM_DEV
+	help
+	    MX2X chips have a PrP that can be used to process buffers from
+	    memory to memory. Operations include resizing and format
+	    conversion.
+
+endif # V4L_MEM2MEM_DRIVERS
+
+endif # MEDIA_CAMERA_SUPPORT
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
new file mode 100644
index 0000000..b3effdc
--- /dev/null
+++ b/drivers/media/platform/Makefile
@@ -0,0 +1,66 @@
+#
+# Makefile for the video capture/playback device drivers.
+#
+
+omap2cam-objs	:=	omap24xxcam.o omap24xxcam-dma.o
+
+obj-$(CONFIG_VIDEO_VINO) += indycam.o
+
+obj-$(CONFIG_VIDEO_VINO) += vino.o
+obj-$(CONFIG_VIDEO_TIMBERDALE)	+= timblogiw.o
+
+
+obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
+
+
+obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/
+obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/
+
+obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
+
+obj-$(CONFIG_VIDEO_OMAP3)	+= omap3isp/
+
+obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o
+obj-$(CONFIG_VIDEO_VIVI) += vivi.o
+obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o
+
+
+obj-$(CONFIG_VIDEO_OMAP2)		+= omap2cam.o
+obj-$(CONFIG_SOC_CAMERA)		+= soc_camera.o soc_mediabus.o
+obj-$(CONFIG_SOC_CAMERA_PLATFORM)	+= soc_camera_platform.o
+# soc-camera host drivers have to be linked after camera drivers
+obj-$(CONFIG_VIDEO_MX1)			+= mx1_camera.o
+obj-$(CONFIG_VIDEO_MX2)			+= mx2_camera.o
+obj-$(CONFIG_VIDEO_MX3)			+= mx3_camera.o
+obj-$(CONFIG_VIDEO_PXA27x)		+= pxa_camera.o
+obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2)	+= sh_mobile_csi2.o
+obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)	+= sh_mobile_ceu_camera.o
+obj-$(CONFIG_VIDEO_OMAP1)		+= omap1_camera.o
+obj-$(CONFIG_VIDEO_ATMEL_ISI)		+= atmel-isi.o
+
+obj-$(CONFIG_VIDEO_MX2_EMMAPRP)		+= mx2_emmaprp.o
+obj-$(CONFIG_VIDEO_CODA) 			+= coda.o
+
+obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE)	+= m2m-deinterlace.o
+
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) 	+= s5p-fimc/
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG)	+= s5p-jpeg/
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC)	+= s5p-mfc/
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV)	+= s5p-tv/
+
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D)	+= s5p-g2d/
+
+obj-$(CONFIG_BLACKFIN)                  += blackfin/
+
+obj-$(CONFIG_ARCH_DAVINCI)		+= davinci/
+
+obj-$(CONFIG_VIDEO_SH_VOU)		+= sh_vou.o
+
+obj-y	+= davinci/
+
+obj-$(CONFIG_ARCH_OMAP)	+= omap/
+
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
+ccflags-y += -I$(srctree)/drivers/media/tuners
+ccflags-y += -I$(srctree)/drivers/media/i2c/soc_camera
diff --git a/drivers/media/platform/arv.c b/drivers/media/platform/arv.c
new file mode 100644
index 0000000..e346d32d
--- /dev/null
+++ b/drivers/media/platform/arv.c
@@ -0,0 +1,885 @@
+/*
+ * Colour AR M64278(VGA) driver for Video4Linux
+ *
+ * Copyright (C) 2003	Takeo Takahashi <takahashi.takeo@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Some code is taken from AR driver sample program for M3T-M32700UT.
+ *
+ * AR driver sample (M32R SDK):
+ *     Copyright (c) 2003 RENESAS TECHNOROGY CORPORATION
+ *     AND RENESAS SOLUTIONS CORPORATION
+ *     All Rights Reserved.
+ *
+ * 2003-09-01:	Support w3cam by Takeo Takahashi
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <linux/mutex.h>
+
+#include <asm/uaccess.h>
+#include <asm/m32r.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+
+#if 0
+#define DEBUG(n, args...) printk(KERN_INFO args)
+#define CHECK_LOST	1
+#else
+#define DEBUG(n, args...)
+#define CHECK_LOST	0
+#endif
+
+/*
+ * USE_INT is always 0, interrupt mode is not available
+ * on linux due to lack of speed
+ */
+#define USE_INT		0	/* Don't modify */
+
+#define VERSION	"0.0.5"
+
+#define ar_inl(addr) 		inl((unsigned long)(addr))
+#define ar_outl(val, addr)	outl((unsigned long)(val), (unsigned long)(addr))
+
+extern struct cpuinfo_m32r	boot_cpu_data;
+
+/*
+ * CCD pixel size
+ *	Note that M32700UT does not support CIF mode, but QVGA is
+ *	supported by M32700UT hardware using VGA mode of AR LSI.
+ *
+ * 	Supported: VGA  (Normal mode, Interlace mode)
+ *		   QVGA (Always Interlace mode of VGA)
+ *
+ */
+#define AR_WIDTH_VGA		640
+#define AR_HEIGHT_VGA		480
+#define AR_WIDTH_QVGA		320
+#define AR_HEIGHT_QVGA		240
+#define MIN_AR_WIDTH		AR_WIDTH_QVGA
+#define MIN_AR_HEIGHT		AR_HEIGHT_QVGA
+#define MAX_AR_WIDTH		AR_WIDTH_VGA
+#define MAX_AR_HEIGHT		AR_HEIGHT_VGA
+
+/* bits & bytes per pixel */
+#define AR_BITS_PER_PIXEL	16
+#define AR_BYTES_PER_PIXEL	(AR_BITS_PER_PIXEL / 8)
+
+/* line buffer size */
+#define AR_LINE_BYTES_VGA	(AR_WIDTH_VGA * AR_BYTES_PER_PIXEL)
+#define AR_LINE_BYTES_QVGA	(AR_WIDTH_QVGA * AR_BYTES_PER_PIXEL)
+#define MAX_AR_LINE_BYTES	AR_LINE_BYTES_VGA
+
+/* frame size & type */
+#define AR_FRAME_BYTES_VGA \
+	(AR_WIDTH_VGA * AR_HEIGHT_VGA * AR_BYTES_PER_PIXEL)
+#define AR_FRAME_BYTES_QVGA \
+	(AR_WIDTH_QVGA * AR_HEIGHT_QVGA * AR_BYTES_PER_PIXEL)
+#define MAX_AR_FRAME_BYTES \
+	(MAX_AR_WIDTH * MAX_AR_HEIGHT * AR_BYTES_PER_PIXEL)
+
+#define AR_MAX_FRAME		15
+
+/* capture size */
+#define AR_SIZE_VGA		0
+#define AR_SIZE_QVGA		1
+
+/* capture mode */
+#define AR_MODE_INTERLACE	0
+#define AR_MODE_NORMAL		1
+
+struct ar {
+	struct v4l2_device v4l2_dev;
+	struct video_device vdev;
+	unsigned int start_capture;	/* duaring capture in INT. mode. */
+#if USE_INT
+	unsigned char *line_buff;	/* DMA line buffer */
+#endif
+	unsigned char *frame[MAX_AR_HEIGHT];	/* frame data */
+	short size;			/* capture size */
+	short mode;			/* capture mode */
+	int width, height;
+	int frame_bytes, line_bytes;
+	wait_queue_head_t wait;
+	struct mutex lock;
+};
+
+static struct ar ardev;
+
+static int video_nr = -1;	/* video device number (first free) */
+static unsigned char yuv[MAX_AR_FRAME_BYTES];
+
+/* module parameters */
+/* default frequency */
+#define DEFAULT_FREQ	50	/* 50 or 75 (MHz) is available as BCLK */
+static int freq = DEFAULT_FREQ;	/* BCLK: available 50 or 70 (MHz) */
+static int vga;			/* default mode(0:QVGA mode, other:VGA mode) */
+static int vga_interlace;	/* 0 is normal mode for, else interlace mode */
+module_param(freq, int, 0);
+module_param(vga, int, 0);
+module_param(vga_interlace, int, 0);
+
+static void wait_for_vsync(void)
+{
+	while (ar_inl(ARVCR0) & ARVCR0_VDS)	/* wait for VSYNC */
+		cpu_relax();
+	while (!(ar_inl(ARVCR0) & ARVCR0_VDS))	/* wait for VSYNC */
+		cpu_relax();
+}
+
+static void wait_acknowledge(void)
+{
+	int i;
+
+	for (i = 0; i < 1000; i++)
+		cpu_relax();
+	while (ar_inl(PLDI2CSTS) & PLDI2CSTS_NOACK)
+		cpu_relax();
+}
+
+/*******************************************************************
+ * I2C functions
+ *******************************************************************/
+static void iic(int n, unsigned long addr, unsigned long data1, unsigned long data2,
+	 unsigned long data3)
+{
+	int i;
+
+	/* Slave Address */
+	ar_outl(addr, PLDI2CDATA);
+	wait_for_vsync();
+
+	/* Start */
+	ar_outl(1, PLDI2CCND);
+	wait_acknowledge();
+
+	/* Transfer data 1 */
+	ar_outl(data1, PLDI2CDATA);
+	wait_for_vsync();
+	ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN);
+	wait_acknowledge();
+
+	/* Transfer data 2 */
+	ar_outl(data2, PLDI2CDATA);
+	wait_for_vsync();
+	ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN);
+	wait_acknowledge();
+
+	if (n == 3) {
+		/* Transfer data 3 */
+		ar_outl(data3, PLDI2CDATA);
+		wait_for_vsync();
+		ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN);
+		wait_acknowledge();
+	}
+
+	/* Stop */
+	for (i = 0; i < 100; i++)
+		cpu_relax();
+	ar_outl(2, PLDI2CCND);
+	ar_outl(2, PLDI2CCND);
+
+	while (ar_inl(PLDI2CSTS) & PLDI2CSTS_BB)
+		cpu_relax();
+}
+
+
+static void init_iic(void)
+{
+	DEBUG(1, "init_iic:\n");
+
+	/*
+	 * ICU Setting (iic)
+	 */
+	/* I2C Setting */
+	ar_outl(0x0, PLDI2CCR);      	/* I2CCR Disable                   */
+	ar_outl(0x0300, PLDI2CMOD); 	/* I2CMOD ACK/8b-data/7b-addr/auto */
+	ar_outl(0x1, PLDI2CACK);	/* I2CACK ACK                      */
+
+	/* I2C CLK */
+	/* 50MH-100k */
+	if (freq == 75)
+		ar_outl(369, PLDI2CFREQ);	/* BCLK = 75MHz */
+	else if (freq == 50)
+		ar_outl(244, PLDI2CFREQ);	/* BCLK = 50MHz */
+	else
+		ar_outl(244, PLDI2CFREQ);	/* default: BCLK = 50MHz */
+	ar_outl(0x1, PLDI2CCR); 	/* I2CCR Enable */
+}
+
+/**************************************************************************
+ *
+ * Video4Linux Interface functions
+ *
+ **************************************************************************/
+
+static inline void disable_dma(void)
+{
+	ar_outl(0x8000, M32R_DMAEN_PORTL);	/* disable DMA0 */
+}
+
+static inline void enable_dma(void)
+{
+	ar_outl(0x8080, M32R_DMAEN_PORTL);	/* enable DMA0 */
+}
+
+static inline void clear_dma_status(void)
+{
+	ar_outl(0x8000, M32R_DMAEDET_PORTL);	/* clear status */
+}
+
+static void wait_for_vertical_sync(struct ar *ar, int exp_line)
+{
+#if CHECK_LOST
+	int tmout = 10000;	/* FIXME */
+	int l;
+
+	/*
+	 * check HCOUNT because we cannot check vertical sync.
+	 */
+	for (; tmout >= 0; tmout--) {
+		l = ar_inl(ARVHCOUNT);
+		if (l == exp_line)
+			break;
+	}
+	if (tmout < 0)
+		v4l2_err(&ar->v4l2_dev, "lost %d -> %d\n", exp_line, l);
+#else
+	while (ar_inl(ARVHCOUNT) != exp_line)
+		cpu_relax();
+#endif
+}
+
+static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+	struct ar *ar = video_drvdata(file);
+	long ret = ar->frame_bytes;		/* return read bytes */
+	unsigned long arvcr1 = 0;
+	unsigned long flags;
+	unsigned char *p;
+	int h, w;
+	unsigned char *py, *pu, *pv;
+#if !USE_INT
+	int l;
+#endif
+
+	DEBUG(1, "ar_read()\n");
+
+	if (ar->size == AR_SIZE_QVGA)
+		arvcr1 |= ARVCR1_QVGA;
+	if (ar->mode == AR_MODE_NORMAL)
+		arvcr1 |= ARVCR1_NORMAL;
+
+	mutex_lock(&ar->lock);
+
+#if USE_INT
+	local_irq_save(flags);
+	disable_dma();
+	ar_outl(0xa1871300, M32R_DMA0CR0_PORTL);
+	ar_outl(0x01000000, M32R_DMA0CR1_PORTL);
+
+	/* set AR FIFO address as source(BSEL5) */
+	ar_outl(ARDATA32, M32R_DMA0CSA_PORTL);
+	ar_outl(ARDATA32, M32R_DMA0RSA_PORTL);
+	ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL);	/* destination addr. */
+	ar_outl(ar->line_buff, M32R_DMA0RDA_PORTL); 	/* reload address */
+	ar_outl(ar->line_bytes, M32R_DMA0CBCUT_PORTL); 	/* byte count (bytes) */
+	ar_outl(ar->line_bytes, M32R_DMA0RBCUT_PORTL); 	/* reload count (bytes) */
+
+	/*
+	 * Okay, kick AR LSI to invoke an interrupt
+	 */
+	ar->start_capture = 0;
+	ar_outl(arvcr1 | ARVCR1_HIEN, ARVCR1);
+	local_irq_restore(flags);
+	/* .... AR interrupts .... */
+	interruptible_sleep_on(&ar->wait);
+	if (signal_pending(current)) {
+		printk(KERN_ERR "arv: interrupted while get frame data.\n");
+		ret = -EINTR;
+		goto out_up;
+	}
+#else	/* ! USE_INT */
+	/* polling */
+	ar_outl(arvcr1, ARVCR1);
+	disable_dma();
+	ar_outl(0x8000, M32R_DMAEDET_PORTL);
+	ar_outl(0xa0861300, M32R_DMA0CR0_PORTL);
+	ar_outl(0x01000000, M32R_DMA0CR1_PORTL);
+	ar_outl(ARDATA32, M32R_DMA0CSA_PORTL);
+	ar_outl(ARDATA32, M32R_DMA0RSA_PORTL);
+	ar_outl(ar->line_bytes, M32R_DMA0CBCUT_PORTL);
+	ar_outl(ar->line_bytes, M32R_DMA0RBCUT_PORTL);
+
+	local_irq_save(flags);
+	while (ar_inl(ARVHCOUNT) != 0)		/* wait for 0 */
+		cpu_relax();
+	if (ar->mode == AR_MODE_INTERLACE && ar->size == AR_SIZE_VGA) {
+		for (h = 0; h < ar->height; h++) {
+			wait_for_vertical_sync(ar, h);
+			if (h < (AR_HEIGHT_VGA/2))
+				l = h << 1;
+			else
+				l = (((h - (AR_HEIGHT_VGA/2)) << 1) + 1);
+			ar_outl(virt_to_phys(ar->frame[l]), M32R_DMA0CDA_PORTL);
+			enable_dma();
+			while (!(ar_inl(M32R_DMAEDET_PORTL) & 0x8000))
+				cpu_relax();
+			disable_dma();
+			clear_dma_status();
+			ar_outl(0xa0861300, M32R_DMA0CR0_PORTL);
+		}
+	} else {
+		for (h = 0; h < ar->height; h++) {
+			wait_for_vertical_sync(ar, h);
+			ar_outl(virt_to_phys(ar->frame[h]), M32R_DMA0CDA_PORTL);
+			enable_dma();
+			while (!(ar_inl(M32R_DMAEDET_PORTL) & 0x8000))
+				cpu_relax();
+			disable_dma();
+			clear_dma_status();
+			ar_outl(0xa0861300, M32R_DMA0CR0_PORTL);
+		}
+	}
+	local_irq_restore(flags);
+#endif	/* ! USE_INT */
+
+	/*
+	 * convert YUV422 to YUV422P
+	 * 	+--------------------+
+	 *	|  Y0,Y1,...	     |
+	 *	|  ..............Yn  |
+	 *	+--------------------+
+	 *	|  U0,U1,........Un  |
+	 *	+--------------------+
+	 *	|  V0,V1,........Vn  |
+	 *	+--------------------+
+	 */
+	py = yuv;
+	pu = py + (ar->frame_bytes / 2);
+	pv = pu + (ar->frame_bytes / 4);
+	for (h = 0; h < ar->height; h++) {
+		p = ar->frame[h];
+		for (w = 0; w < ar->line_bytes; w += 4) {
+			*py++ = *p++;
+			*pu++ = *p++;
+			*py++ = *p++;
+			*pv++ = *p++;
+		}
+	}
+	if (copy_to_user(buf, yuv, ar->frame_bytes)) {
+		v4l2_err(&ar->v4l2_dev, "failed while copy_to_user yuv.\n");
+		ret = -EFAULT;
+		goto out_up;
+	}
+	DEBUG(1, "ret = %d\n", ret);
+out_up:
+	mutex_unlock(&ar->lock);
+	return ret;
+}
+
+static int ar_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *vcap)
+{
+	struct ar *ar = video_drvdata(file);
+
+	strlcpy(vcap->driver, ar->vdev.name, sizeof(vcap->driver));
+	strlcpy(vcap->card, "Colour AR VGA", sizeof(vcap->card));
+	strlcpy(vcap->bus_info, "Platform", sizeof(vcap->bus_info));
+	vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
+	return 0;
+}
+
+static int ar_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+	if (vin->index > 0)
+		return -EINVAL;
+	strlcpy(vin->name, "Camera", sizeof(vin->name));
+	vin->type = V4L2_INPUT_TYPE_CAMERA;
+	vin->audioset = 0;
+	vin->tuner = 0;
+	vin->std = V4L2_STD_ALL;
+	vin->status = 0;
+	return 0;
+}
+
+static int ar_g_input(struct file *file, void *fh, unsigned int *inp)
+{
+	*inp = 0;
+	return 0;
+}
+
+static int ar_s_input(struct file *file, void *fh, unsigned int inp)
+{
+	return inp ? -EINVAL : 0;
+}
+
+static int ar_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ar *ar = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	pix->width = ar->width;
+	pix->height = ar->height;
+	pix->pixelformat = V4L2_PIX_FMT_YUV422P;
+	pix->field = (ar->mode == AR_MODE_NORMAL) ? V4L2_FIELD_NONE : V4L2_FIELD_INTERLACED;
+	pix->bytesperline = ar->width;
+	pix->sizeimage = 2 * ar->width * ar->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	return 0;
+}
+
+static int ar_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ar *ar = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	if (pix->height <= AR_HEIGHT_QVGA || pix->width <= AR_WIDTH_QVGA) {
+		pix->height = AR_HEIGHT_QVGA;
+		pix->width = AR_WIDTH_QVGA;
+		pix->field = V4L2_FIELD_INTERLACED;
+	} else {
+		pix->height = AR_HEIGHT_VGA;
+		pix->width = AR_WIDTH_VGA;
+		pix->field = vga_interlace ? V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE;
+	}
+	pix->pixelformat = V4L2_PIX_FMT_YUV422P;
+	pix->bytesperline = ar->width;
+	pix->sizeimage = 2 * ar->width * ar->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	return 0;
+}
+
+static int ar_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ar *ar = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+	int ret = ar_try_fmt_vid_cap(file, fh, fmt);
+
+	if (ret)
+		return ret;
+	mutex_lock(&ar->lock);
+	ar->width = pix->width;
+	ar->height = pix->height;
+	if (ar->width == AR_WIDTH_VGA) {
+		ar->size = AR_SIZE_VGA;
+		ar->frame_bytes = AR_FRAME_BYTES_VGA;
+		ar->line_bytes = AR_LINE_BYTES_VGA;
+		if (vga_interlace)
+			ar->mode = AR_MODE_INTERLACE;
+		else
+			ar->mode = AR_MODE_NORMAL;
+	} else {
+		ar->size = AR_SIZE_QVGA;
+		ar->frame_bytes = AR_FRAME_BYTES_QVGA;
+		ar->line_bytes = AR_LINE_BYTES_QVGA;
+		ar->mode = AR_MODE_INTERLACE;
+	}
+	/* Ok we figured out what to use from our wide choice */
+	mutex_unlock(&ar->lock);
+	return 0;
+}
+
+static int ar_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
+{
+	static struct v4l2_fmtdesc formats[] = {
+		{ 0, 0, 0,
+		  "YUV 4:2:2 Planar", V4L2_PIX_FMT_YUV422P,
+		  { 0, 0, 0, 0 }
+		},
+	};
+	enum v4l2_buf_type type = fmt->type;
+
+	if (fmt->index > 0)
+		return -EINVAL;
+
+	*fmt = formats[fmt->index];
+	fmt->type = type;
+	return 0;
+}
+
+#if USE_INT
+/*
+ * Interrupt handler
+ */
+static void ar_interrupt(int irq, void *dev)
+{
+	struct ar *ar = dev;
+	unsigned int line_count;
+	unsigned int line_number;
+	unsigned int arvcr1;
+
+	line_count = ar_inl(ARVHCOUNT);			/* line number */
+	if (ar->mode == AR_MODE_INTERLACE && ar->size == AR_SIZE_VGA) {
+		/* operations for interlace mode */
+		if (line_count < (AR_HEIGHT_VGA / 2)) 	/* even line */
+			line_number = (line_count << 1);
+		else 					/* odd line */
+			line_number =
+			(((line_count - (AR_HEIGHT_VGA / 2)) << 1) + 1);
+	} else {
+		line_number = line_count;
+	}
+
+	if (line_number == 0) {
+		/*
+		 * It is an interrupt for line 0.
+		 * we have to start capture.
+		 */
+		disable_dma();
+#if 0
+		ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL);	/* needless? */
+#endif
+		memcpy(ar->frame[0], ar->line_buff, ar->line_bytes);
+#if 0
+		ar_outl(0xa1861300, M32R_DMA0CR0_PORTL);
+#endif
+		enable_dma();
+		ar->start_capture = 1;			/* during capture */
+		return;
+	}
+
+	if (ar->start_capture == 1 && line_number <= (ar->height - 1)) {
+		disable_dma();
+		memcpy(ar->frame[line_number], ar->line_buff, ar->line_bytes);
+
+		/*
+		 * if captured all line of a frame, disable AR interrupt
+		 * and wake a process up.
+		 */
+		if (line_number == (ar->height - 1)) { 	/* end  of line */
+
+			ar->start_capture = 0;
+
+			/* disable AR interrupt request */
+			arvcr1 = ar_inl(ARVCR1);
+			arvcr1 &= ~ARVCR1_HIEN;		/* clear int. flag */
+			ar_outl(arvcr1, ARVCR1);	/* disable */
+			wake_up_interruptible(&ar->wait);
+		} else {
+#if 0
+			ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL);
+			ar_outl(0xa1861300, M32R_DMA0CR0_PORTL);
+#endif
+			enable_dma();
+		}
+	}
+}
+#endif
+
+/*
+ * ar_initialize()
+ * 	ar_initialize() is called by video_register_device() and
+ *	initializes AR LSI and peripherals.
+ *
+ *	-1 is returned in all failures.
+ *	0 is returned in success.
+ *
+ */
+static int ar_initialize(struct ar *ar)
+{
+	unsigned long cr = 0;
+	int i, found = 0;
+
+	DEBUG(1, "ar_initialize:\n");
+
+	/*
+	 * initialize AR LSI
+	 */
+	ar_outl(0, ARVCR0);		/* assert reset of AR LSI */
+	for (i = 0; i < 0x18; i++)	/* wait for over 10 cycles @ 27MHz */
+		cpu_relax();
+	ar_outl(ARVCR0_RST, ARVCR0);	/* negate reset of AR LSI (enable) */
+	for (i = 0; i < 0x40d; i++)	/* wait for over 420 cycles @ 27MHz */
+		cpu_relax();
+
+	/* AR uses INT3 of CPU as interrupt pin. */
+	ar_outl(ARINTSEL_INT3, ARINTSEL);
+
+	if (ar->size == AR_SIZE_QVGA)
+		cr |= ARVCR1_QVGA;
+	if (ar->mode == AR_MODE_NORMAL)
+		cr |= ARVCR1_NORMAL;
+	ar_outl(cr, ARVCR1);
+
+	/*
+	 * Initialize IIC so that CPU can communicate with AR LSI,
+	 * and send boot commands to AR LSI.
+	 */
+	init_iic();
+
+	for (i = 0; i < 0x100000; i++) {	/* > 0xa1d10,  56ms */
+		if ((ar_inl(ARVCR0) & ARVCR0_VDS)) {	/* VSYNC */
+			found = 1;
+			break;
+		}
+	}
+
+	if (found == 0)
+		return -ENODEV;
+
+	v4l2_info(&ar->v4l2_dev, "Initializing ");
+
+	iic(2, 0x78, 0x11, 0x01, 0x00);	/* start */
+	iic(3, 0x78, 0x12, 0x00, 0x06);
+	iic(3, 0x78, 0x12, 0x12, 0x30);
+	iic(3, 0x78, 0x12, 0x15, 0x58);
+	iic(3, 0x78, 0x12, 0x17, 0x30);
+	printk(KERN_CONT ".");
+	iic(3, 0x78, 0x12, 0x1a, 0x97);
+	iic(3, 0x78, 0x12, 0x1b, 0xff);
+	iic(3, 0x78, 0x12, 0x1c, 0xff);
+	iic(3, 0x78, 0x12, 0x26, 0x10);
+	iic(3, 0x78, 0x12, 0x27, 0x00);
+	printk(KERN_CONT ".");
+	iic(2, 0x78, 0x34, 0x02, 0x00);
+	iic(2, 0x78, 0x7a, 0x10, 0x00);
+	iic(2, 0x78, 0x80, 0x39, 0x00);
+	iic(2, 0x78, 0x81, 0xe6, 0x00);
+	iic(2, 0x78, 0x8d, 0x00, 0x00);
+	printk(KERN_CONT ".");
+	iic(2, 0x78, 0x8e, 0x0c, 0x00);
+	iic(2, 0x78, 0x8f, 0x00, 0x00);
+#if 0
+	iic(2, 0x78, 0x90, 0x00, 0x00);	/* AWB on=1 off=0 */
+#endif
+	iic(2, 0x78, 0x93, 0x01, 0x00);
+	iic(2, 0x78, 0x94, 0xcd, 0x00);
+	iic(2, 0x78, 0x95, 0x00, 0x00);
+	printk(KERN_CONT ".");
+	iic(2, 0x78, 0x96, 0xa0, 0x00);
+	iic(2, 0x78, 0x97, 0x00, 0x00);
+	iic(2, 0x78, 0x98, 0x60, 0x00);
+	iic(2, 0x78, 0x99, 0x01, 0x00);
+	iic(2, 0x78, 0x9a, 0x19, 0x00);
+	printk(KERN_CONT ".");
+	iic(2, 0x78, 0x9b, 0x02, 0x00);
+	iic(2, 0x78, 0x9c, 0xe8, 0x00);
+	iic(2, 0x78, 0x9d, 0x02, 0x00);
+	iic(2, 0x78, 0x9e, 0x2e, 0x00);
+	iic(2, 0x78, 0xb8, 0x78, 0x00);
+	iic(2, 0x78, 0xba, 0x05, 0x00);
+#if 0
+	iic(2, 0x78, 0x83, 0x8c, 0x00);	/* brightness */
+#endif
+	printk(KERN_CONT ".");
+
+	/* color correction */
+	iic(3, 0x78, 0x49, 0x00, 0x95);	/* a		*/
+	iic(3, 0x78, 0x49, 0x01, 0x96);	/* b		*/
+	iic(3, 0x78, 0x49, 0x03, 0x85);	/* c		*/
+	iic(3, 0x78, 0x49, 0x04, 0x97);	/* d		*/
+	iic(3, 0x78, 0x49, 0x02, 0x7e);	/* e(Lo)	*/
+	iic(3, 0x78, 0x49, 0x05, 0xa4);	/* f(Lo)	*/
+	iic(3, 0x78, 0x49, 0x06, 0x04);	/* e(Hi)	*/
+	iic(3, 0x78, 0x49, 0x07, 0x04);	/* e(Hi)	*/
+	iic(2, 0x78, 0x48, 0x01, 0x00);	/* on=1 off=0	*/
+
+	printk(KERN_CONT ".");
+	iic(2, 0x78, 0x11, 0x00, 0x00);	/* end */
+	printk(KERN_CONT " done\n");
+	return 0;
+}
+
+
+/****************************************************************************
+ *
+ * Video4Linux Module functions
+ *
+ ****************************************************************************/
+
+static const struct v4l2_file_operations ar_fops = {
+	.owner		= THIS_MODULE,
+	.open		= v4l2_fh_open,
+	.release	= v4l2_fh_release,
+	.read		= ar_read,
+	.unlocked_ioctl	= video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops ar_ioctl_ops = {
+	.vidioc_querycap    		    = ar_querycap,
+	.vidioc_g_input      		    = ar_g_input,
+	.vidioc_s_input      		    = ar_s_input,
+	.vidioc_enum_input   		    = ar_enum_input,
+	.vidioc_enum_fmt_vid_cap 	    = ar_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap 		    = ar_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap  		    = ar_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap  	    = ar_try_fmt_vid_cap,
+};
+
+#define ALIGN4(x)	((((int)(x)) & 0x3) == 0)
+
+static int __init ar_init(void)
+{
+	struct ar *ar;
+	struct v4l2_device *v4l2_dev;
+	int ret;
+	int i;
+
+	ar = &ardev;
+	v4l2_dev = &ar->v4l2_dev;
+	strlcpy(v4l2_dev->name, "arv", sizeof(v4l2_dev->name));
+	v4l2_info(v4l2_dev, "Colour AR VGA driver %s\n", VERSION);
+
+	ret = v4l2_device_register(NULL, v4l2_dev);
+	if (ret < 0) {
+		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+		return ret;
+	}
+	ret = -EIO;
+
+#if USE_INT
+	/* allocate a DMA buffer for 1 line.  */
+	ar->line_buff = kmalloc(MAX_AR_LINE_BYTES, GFP_KERNEL | GFP_DMA);
+	if (ar->line_buff == NULL || !ALIGN4(ar->line_buff)) {
+		v4l2_err(v4l2_dev, "buffer allocation failed for DMA.\n");
+		ret = -ENOMEM;
+		goto out_end;
+	}
+#endif
+	/* allocate buffers for a frame */
+	for (i = 0; i < MAX_AR_HEIGHT; i++) {
+		ar->frame[i] = kmalloc(MAX_AR_LINE_BYTES, GFP_KERNEL);
+		if (ar->frame[i] == NULL || !ALIGN4(ar->frame[i])) {
+			v4l2_err(v4l2_dev, "buffer allocation failed for frame.\n");
+			ret = -ENOMEM;
+			goto out_line_buff;
+		}
+	}
+
+	strlcpy(ar->vdev.name, "Colour AR VGA", sizeof(ar->vdev.name));
+	ar->vdev.v4l2_dev = v4l2_dev;
+	ar->vdev.fops = &ar_fops;
+	ar->vdev.ioctl_ops = &ar_ioctl_ops;
+	ar->vdev.release = video_device_release_empty;
+	set_bit(V4L2_FL_USE_FH_PRIO, &ar->vdev.flags);
+	video_set_drvdata(&ar->vdev, ar);
+
+	if (vga) {
+		ar->width 	= AR_WIDTH_VGA;
+		ar->height 	= AR_HEIGHT_VGA;
+		ar->size 	= AR_SIZE_VGA;
+		ar->frame_bytes = AR_FRAME_BYTES_VGA;
+		ar->line_bytes	= AR_LINE_BYTES_VGA;
+		if (vga_interlace)
+			ar->mode = AR_MODE_INTERLACE;
+		else
+			ar->mode = AR_MODE_NORMAL;
+	} else {
+		ar->width 	= AR_WIDTH_QVGA;
+		ar->height 	= AR_HEIGHT_QVGA;
+		ar->size 	= AR_SIZE_QVGA;
+		ar->frame_bytes = AR_FRAME_BYTES_QVGA;
+		ar->line_bytes	= AR_LINE_BYTES_QVGA;
+		ar->mode	= AR_MODE_INTERLACE;
+	}
+	mutex_init(&ar->lock);
+	init_waitqueue_head(&ar->wait);
+
+#if USE_INT
+	if (request_irq(M32R_IRQ_INT3, ar_interrupt, 0, "arv", ar)) {
+		v4l2_err("request_irq(%d) failed.\n", M32R_IRQ_INT3);
+		ret = -EIO;
+		goto out_irq;
+	}
+#endif
+
+	if (ar_initialize(ar) != 0) {
+		v4l2_err(v4l2_dev, "M64278 not found.\n");
+		ret = -ENODEV;
+		goto out_dev;
+	}
+
+	/*
+	 * ok, we can initialize h/w according to parameters,
+	 * so register video device as a frame grabber type.
+	 * device is named "video[0-64]".
+	 * video_register_device() initializes h/w using ar_initialize().
+	 */
+	if (video_register_device(&ar->vdev, VFL_TYPE_GRABBER, video_nr) != 0) {
+		/* return -1, -ENFILE(full) or others */
+		v4l2_err(v4l2_dev, "register video (Colour AR) failed.\n");
+		ret = -ENODEV;
+		goto out_dev;
+	}
+
+	v4l2_info(v4l2_dev, "%s: Found M64278 VGA (IRQ %d, Freq %dMHz).\n",
+		video_device_node_name(&ar->vdev), M32R_IRQ_INT3, freq);
+
+	return 0;
+
+out_dev:
+#if USE_INT
+	free_irq(M32R_IRQ_INT3, ar);
+
+out_irq:
+#endif
+	for (i = 0; i < MAX_AR_HEIGHT; i++)
+		kfree(ar->frame[i]);
+
+out_line_buff:
+#if USE_INT
+	kfree(ar->line_buff);
+
+out_end:
+#endif
+	v4l2_device_unregister(&ar->v4l2_dev);
+	return ret;
+}
+
+
+static int __init ar_init_module(void)
+{
+	freq = (boot_cpu_data.bus_clock / 1000000);
+	printk(KERN_INFO "arv: Bus clock %d\n", freq);
+	if (freq != 50 && freq != 75)
+		freq = DEFAULT_FREQ;
+	return ar_init();
+}
+
+static void __exit ar_cleanup_module(void)
+{
+	struct ar *ar;
+	int i;
+
+	ar = &ardev;
+	video_unregister_device(&ar->vdev);
+#if USE_INT
+	free_irq(M32R_IRQ_INT3, ar);
+#endif
+	for (i = 0; i < MAX_AR_HEIGHT; i++)
+		kfree(ar->frame[i]);
+#if USE_INT
+	kfree(ar->line_buff);
+#endif
+	v4l2_device_unregister(&ar->v4l2_dev);
+}
+
+module_init(ar_init_module);
+module_exit(ar_cleanup_module);
+
+MODULE_AUTHOR("Takeo Takahashi <takahashi.takeo@renesas.com>");
+MODULE_DESCRIPTION("Colour AR M64278(VGA) for Video4Linux");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(VERSION);
diff --git a/drivers/media/platform/atmel-isi.c b/drivers/media/platform/atmel-isi.c
new file mode 100644
index 0000000..6274a91
--- /dev/null
+++ b/drivers/media/platform/atmel-isi.c
@@ -0,0 +1,1099 @@
+/*
+ * Copyright (c) 2011 Atmel Corporation
+ * Josh Wu, <josh.wu@atmel.com>
+ *
+ * Based on previous work by Lars Haring, <lars.haring@atmel.com>
+ * and Sedji Gaouaou
+ * Based on the bttv driver for Bt848 with respective copyright holders
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <media/atmel-isi.h>
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/videobuf2-dma-contig.h>
+
+#define MAX_BUFFER_NUM			32
+#define MAX_SUPPORT_WIDTH		2048
+#define MAX_SUPPORT_HEIGHT		2048
+#define VID_LIMIT_BYTES			(16 * 1024 * 1024)
+#define MIN_FRAME_RATE			15
+#define FRAME_INTERVAL_MILLI_SEC	(1000 / MIN_FRAME_RATE)
+
+/* ISI states */
+enum {
+	ISI_STATE_IDLE = 0,
+	ISI_STATE_READY,
+	ISI_STATE_WAIT_SOF,
+};
+
+/* Frame buffer descriptor */
+struct fbd {
+	/* Physical address of the frame buffer */
+	u32 fb_address;
+	/* DMA Control Register(only in HISI2) */
+	u32 dma_ctrl;
+	/* Physical address of the next fbd */
+	u32 next_fbd_address;
+};
+
+static void set_dma_ctrl(struct fbd *fb_desc, u32 ctrl)
+{
+	fb_desc->dma_ctrl = ctrl;
+}
+
+struct isi_dma_desc {
+	struct list_head list;
+	struct fbd *p_fbd;
+	u32 fbd_phys;
+};
+
+/* Frame buffer data */
+struct frame_buffer {
+	struct vb2_buffer vb;
+	struct isi_dma_desc *p_dma_desc;
+	struct list_head list;
+};
+
+struct atmel_isi {
+	/* Protects the access of variables shared with the ISR */
+	spinlock_t			lock;
+	void __iomem			*regs;
+
+	int				sequence;
+	/* State of the ISI module in capturing mode */
+	int				state;
+
+	/* Wait queue for waiting for SOF */
+	wait_queue_head_t		vsync_wq;
+
+	struct vb2_alloc_ctx		*alloc_ctx;
+
+	/* Allocate descriptors for dma buffer use */
+	struct fbd			*p_fb_descriptors;
+	u32				fb_descriptors_phys;
+	struct				list_head dma_desc_head;
+	struct isi_dma_desc		dma_desc[MAX_BUFFER_NUM];
+
+	struct completion		complete;
+	/* ISI peripherial clock */
+	struct clk			*pclk;
+	/* ISI_MCK, feed to camera sensor to generate pixel clock */
+	struct clk			*mck;
+	unsigned int			irq;
+
+	struct isi_platform_data	*pdata;
+	u16				width_flags;	/* max 12 bits */
+
+	struct list_head		video_buffer_list;
+	struct frame_buffer		*active;
+
+	struct soc_camera_device	*icd;
+	struct soc_camera_host		soc_host;
+};
+
+static void isi_writel(struct atmel_isi *isi, u32 reg, u32 val)
+{
+	writel(val, isi->regs + reg);
+}
+static u32 isi_readl(struct atmel_isi *isi, u32 reg)
+{
+	return readl(isi->regs + reg);
+}
+
+static int configure_geometry(struct atmel_isi *isi, u32 width,
+			u32 height, enum v4l2_mbus_pixelcode code)
+{
+	u32 cfg2, cr;
+
+	switch (code) {
+	/* YUV, including grey */
+	case V4L2_MBUS_FMT_Y8_1X8:
+		cr = ISI_CFG2_GRAYSCALE;
+		break;
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		cr = ISI_CFG2_YCC_SWAP_MODE_3;
+		break;
+	case V4L2_MBUS_FMT_VYUY8_2X8:
+		cr = ISI_CFG2_YCC_SWAP_MODE_2;
+		break;
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+		cr = ISI_CFG2_YCC_SWAP_MODE_1;
+		break;
+	case V4L2_MBUS_FMT_YVYU8_2X8:
+		cr = ISI_CFG2_YCC_SWAP_DEFAULT;
+		break;
+	/* RGB, TODO */
+	default:
+		return -EINVAL;
+	}
+
+	isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
+
+	cfg2 = isi_readl(isi, ISI_CFG2);
+	cfg2 |= cr;
+	/* Set width */
+	cfg2 &= ~(ISI_CFG2_IM_HSIZE_MASK);
+	cfg2 |= ((width - 1) << ISI_CFG2_IM_HSIZE_OFFSET) &
+			ISI_CFG2_IM_HSIZE_MASK;
+	/* Set height */
+	cfg2 &= ~(ISI_CFG2_IM_VSIZE_MASK);
+	cfg2 |= ((height - 1) << ISI_CFG2_IM_VSIZE_OFFSET)
+			& ISI_CFG2_IM_VSIZE_MASK;
+	isi_writel(isi, ISI_CFG2, cfg2);
+
+	return 0;
+}
+
+static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi)
+{
+	if (isi->active) {
+		struct vb2_buffer *vb = &isi->active->vb;
+		struct frame_buffer *buf = isi->active;
+
+		list_del_init(&buf->list);
+		do_gettimeofday(&vb->v4l2_buf.timestamp);
+		vb->v4l2_buf.sequence = isi->sequence++;
+		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+	}
+
+	if (list_empty(&isi->video_buffer_list)) {
+		isi->active = NULL;
+	} else {
+		/* start next dma frame. */
+		isi->active = list_entry(isi->video_buffer_list.next,
+					struct frame_buffer, list);
+		isi_writel(isi, ISI_DMA_C_DSCR,
+			isi->active->p_dma_desc->fbd_phys);
+		isi_writel(isi, ISI_DMA_C_CTRL,
+			ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
+		isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
+	}
+	return IRQ_HANDLED;
+}
+
+/* ISI interrupt service routine */
+static irqreturn_t isi_interrupt(int irq, void *dev_id)
+{
+	struct atmel_isi *isi = dev_id;
+	u32 status, mask, pending;
+	irqreturn_t ret = IRQ_NONE;
+
+	spin_lock(&isi->lock);
+
+	status = isi_readl(isi, ISI_STATUS);
+	mask = isi_readl(isi, ISI_INTMASK);
+	pending = status & mask;
+
+	if (pending & ISI_CTRL_SRST) {
+		complete(&isi->complete);
+		isi_writel(isi, ISI_INTDIS, ISI_CTRL_SRST);
+		ret = IRQ_HANDLED;
+	} else if (pending & ISI_CTRL_DIS) {
+		complete(&isi->complete);
+		isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS);
+		ret = IRQ_HANDLED;
+	} else {
+		if ((pending & ISI_SR_VSYNC) &&
+				(isi->state == ISI_STATE_IDLE)) {
+			isi->state = ISI_STATE_READY;
+			wake_up_interruptible(&isi->vsync_wq);
+			ret = IRQ_HANDLED;
+		}
+		if (likely(pending & ISI_SR_CXFR_DONE))
+			ret = atmel_isi_handle_streaming(isi);
+	}
+
+	spin_unlock(&isi->lock);
+	return ret;
+}
+
+#define	WAIT_ISI_RESET		1
+#define	WAIT_ISI_DISABLE	0
+static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset)
+{
+	unsigned long timeout;
+	/*
+	 * The reset or disable will only succeed if we have a
+	 * pixel clock from the camera.
+	 */
+	init_completion(&isi->complete);
+
+	if (wait_reset) {
+		isi_writel(isi, ISI_INTEN, ISI_CTRL_SRST);
+		isi_writel(isi, ISI_CTRL, ISI_CTRL_SRST);
+	} else {
+		isi_writel(isi, ISI_INTEN, ISI_CTRL_DIS);
+		isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
+	}
+
+	timeout = wait_for_completion_timeout(&isi->complete,
+			msecs_to_jiffies(100));
+	if (timeout == 0)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------
+	Videobuf operations
+   ------------------------------------------------------------------*/
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+				unsigned int *nbuffers, unsigned int *nplanes,
+				unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct atmel_isi *isi = ici->priv;
+	unsigned long size;
+	int ret;
+
+	/* Reset ISI */
+	ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET);
+	if (ret < 0) {
+		dev_err(icd->parent, "Reset ISI timed out\n");
+		return ret;
+	}
+	/* Disable all interrupts */
+	isi_writel(isi, ISI_INTDIS, ~0UL);
+
+	size = icd->sizeimage;
+
+	if (!*nbuffers || *nbuffers > MAX_BUFFER_NUM)
+		*nbuffers = MAX_BUFFER_NUM;
+
+	if (size * *nbuffers > VID_LIMIT_BYTES)
+		*nbuffers = VID_LIMIT_BYTES / size;
+
+	*nplanes = 1;
+	sizes[0] = size;
+	alloc_ctxs[0] = isi->alloc_ctx;
+
+	isi->sequence = 0;
+	isi->active = NULL;
+
+	dev_dbg(icd->parent, "%s, count=%d, size=%ld\n", __func__,
+		*nbuffers, size);
+
+	return 0;
+}
+
+static int buffer_init(struct vb2_buffer *vb)
+{
+	struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb);
+
+	buf->p_dma_desc = NULL;
+	INIT_LIST_HEAD(&buf->list);
+
+	return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+	struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct atmel_isi *isi = ici->priv;
+	unsigned long size;
+	struct isi_dma_desc *desc;
+
+	size = icd->sizeimage;
+
+	if (vb2_plane_size(vb, 0) < size) {
+		dev_err(icd->parent, "%s data will not fit into plane (%lu < %lu)\n",
+				__func__, vb2_plane_size(vb, 0), size);
+		return -EINVAL;
+	}
+
+	vb2_set_plane_payload(&buf->vb, 0, size);
+
+	if (!buf->p_dma_desc) {
+		if (list_empty(&isi->dma_desc_head)) {
+			dev_err(icd->parent, "Not enough dma descriptors.\n");
+			return -EINVAL;
+		} else {
+			/* Get an available descriptor */
+			desc = list_entry(isi->dma_desc_head.next,
+						struct isi_dma_desc, list);
+			/* Delete the descriptor since now it is used */
+			list_del_init(&desc->list);
+
+			/* Initialize the dma descriptor */
+			desc->p_fbd->fb_address =
+					vb2_dma_contig_plane_dma_addr(vb, 0);
+			desc->p_fbd->next_fbd_address = 0;
+			set_dma_ctrl(desc->p_fbd, ISI_DMA_CTRL_WB);
+
+			buf->p_dma_desc = desc;
+		}
+	}
+	return 0;
+}
+
+static void buffer_cleanup(struct vb2_buffer *vb)
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct atmel_isi *isi = ici->priv;
+	struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb);
+
+	/* This descriptor is available now and we add to head list */
+	if (buf->p_dma_desc)
+		list_add(&buf->p_dma_desc->list, &isi->dma_desc_head);
+}
+
+static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer)
+{
+	u32 ctrl, cfg1;
+
+	cfg1 = isi_readl(isi, ISI_CFG1);
+	/* Enable irq: cxfr for the codec path, pxfr for the preview path */
+	isi_writel(isi, ISI_INTEN,
+			ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE);
+
+	/* Check if already in a frame */
+	if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) {
+		dev_err(isi->icd->parent, "Already in frame handling.\n");
+		return;
+	}
+
+	isi_writel(isi, ISI_DMA_C_DSCR, buffer->p_dma_desc->fbd_phys);
+	isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
+	isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
+
+	/* Enable linked list */
+	cfg1 |= isi->pdata->frate | ISI_CFG1_DISCR;
+
+	/* Enable codec path and ISI */
+	ctrl = ISI_CTRL_CDC | ISI_CTRL_EN;
+	isi_writel(isi, ISI_CTRL, ctrl);
+	isi_writel(isi, ISI_CFG1, cfg1);
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct atmel_isi *isi = ici->priv;
+	struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb);
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&isi->lock, flags);
+	list_add_tail(&buf->list, &isi->video_buffer_list);
+
+	if (isi->active == NULL) {
+		isi->active = buf;
+		if (vb2_is_streaming(vb->vb2_queue))
+			start_dma(isi, buf);
+	}
+	spin_unlock_irqrestore(&isi->lock, flags);
+}
+
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct atmel_isi *isi = ici->priv;
+
+	u32 sr = 0;
+	int ret;
+
+	spin_lock_irq(&isi->lock);
+	isi->state = ISI_STATE_IDLE;
+	/* Clear any pending SOF interrupt */
+	sr = isi_readl(isi, ISI_STATUS);
+	/* Enable VSYNC interrupt for SOF */
+	isi_writel(isi, ISI_INTEN, ISI_SR_VSYNC);
+	isi_writel(isi, ISI_CTRL, ISI_CTRL_EN);
+	spin_unlock_irq(&isi->lock);
+
+	dev_dbg(icd->parent, "Waiting for SOF\n");
+	ret = wait_event_interruptible(isi->vsync_wq,
+				       isi->state != ISI_STATE_IDLE);
+	if (ret)
+		goto err;
+
+	if (isi->state != ISI_STATE_READY) {
+		ret = -EIO;
+		goto err;
+	}
+
+	spin_lock_irq(&isi->lock);
+	isi->state = ISI_STATE_WAIT_SOF;
+	isi_writel(isi, ISI_INTDIS, ISI_SR_VSYNC);
+	if (count)
+		start_dma(isi, isi->active);
+	spin_unlock_irq(&isi->lock);
+
+	return 0;
+err:
+	isi->active = NULL;
+	isi->sequence = 0;
+	INIT_LIST_HEAD(&isi->video_buffer_list);
+	return ret;
+}
+
+/* abort streaming and wait for last buffer */
+static int stop_streaming(struct vb2_queue *vq)
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct atmel_isi *isi = ici->priv;
+	struct frame_buffer *buf, *node;
+	int ret = 0;
+	unsigned long timeout;
+
+	spin_lock_irq(&isi->lock);
+	isi->active = NULL;
+	/* Release all active buffers */
+	list_for_each_entry_safe(buf, node, &isi->video_buffer_list, list) {
+		list_del_init(&buf->list);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+	spin_unlock_irq(&isi->lock);
+
+	timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ;
+	/* Wait until the end of the current frame. */
+	while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) &&
+			time_before(jiffies, timeout))
+		msleep(1);
+
+	if (time_after(jiffies, timeout)) {
+		dev_err(icd->parent,
+			"Timeout waiting for finishing codec request\n");
+		return -ETIMEDOUT;
+	}
+
+	/* Disable interrupts */
+	isi_writel(isi, ISI_INTDIS,
+			ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE);
+
+	/* Disable ISI and wait for it is done */
+	ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE);
+	if (ret < 0)
+		dev_err(icd->parent, "Disable ISI timed out\n");
+
+	return ret;
+}
+
+static struct vb2_ops isi_video_qops = {
+	.queue_setup		= queue_setup,
+	.buf_init		= buffer_init,
+	.buf_prepare		= buffer_prepare,
+	.buf_cleanup		= buffer_cleanup,
+	.buf_queue		= buffer_queue,
+	.start_streaming	= start_streaming,
+	.stop_streaming		= stop_streaming,
+	.wait_prepare		= soc_camera_unlock,
+	.wait_finish		= soc_camera_lock,
+};
+
+/* ------------------------------------------------------------------
+	SOC camera operations for the device
+   ------------------------------------------------------------------*/
+static int isi_camera_init_videobuf(struct vb2_queue *q,
+				     struct soc_camera_device *icd)
+{
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	q->io_modes = VB2_MMAP;
+	q->drv_priv = icd;
+	q->buf_struct_size = sizeof(struct frame_buffer);
+	q->ops = &isi_video_qops;
+	q->mem_ops = &vb2_dma_contig_memops;
+
+	return vb2_queue_init(q);
+}
+
+static int isi_camera_set_fmt(struct soc_camera_device *icd,
+			      struct v4l2_format *f)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct atmel_isi *isi = ici->priv;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	const struct soc_camera_format_xlate *xlate;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct v4l2_mbus_framefmt mf;
+	int ret;
+
+	xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+	if (!xlate) {
+		dev_warn(icd->parent, "Format %x not found\n",
+			 pix->pixelformat);
+		return -EINVAL;
+	}
+
+	dev_dbg(icd->parent, "Plan to set format %dx%d\n",
+			pix->width, pix->height);
+
+	mf.width	= pix->width;
+	mf.height	= pix->height;
+	mf.field	= pix->field;
+	mf.colorspace	= pix->colorspace;
+	mf.code		= xlate->code;
+
+	ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+	if (ret < 0)
+		return ret;
+
+	if (mf.code != xlate->code)
+		return -EINVAL;
+
+	ret = configure_geometry(isi, pix->width, pix->height, xlate->code);
+	if (ret < 0)
+		return ret;
+
+	pix->width		= mf.width;
+	pix->height		= mf.height;
+	pix->field		= mf.field;
+	pix->colorspace		= mf.colorspace;
+	icd->current_fmt	= xlate;
+
+	dev_dbg(icd->parent, "Finally set format %dx%d\n",
+		pix->width, pix->height);
+
+	return ret;
+}
+
+static int isi_camera_try_fmt(struct soc_camera_device *icd,
+			      struct v4l2_format *f)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	const struct soc_camera_format_xlate *xlate;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct v4l2_mbus_framefmt mf;
+	u32 pixfmt = pix->pixelformat;
+	int ret;
+
+	xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+	if (pixfmt && !xlate) {
+		dev_warn(icd->parent, "Format %x not found\n", pixfmt);
+		return -EINVAL;
+	}
+
+	/* limit to Atmel ISI hardware capabilities */
+	if (pix->height > MAX_SUPPORT_HEIGHT)
+		pix->height = MAX_SUPPORT_HEIGHT;
+	if (pix->width > MAX_SUPPORT_WIDTH)
+		pix->width = MAX_SUPPORT_WIDTH;
+
+	/* limit to sensor capabilities */
+	mf.width	= pix->width;
+	mf.height	= pix->height;
+	mf.field	= pix->field;
+	mf.colorspace	= pix->colorspace;
+	mf.code		= xlate->code;
+
+	ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+	if (ret < 0)
+		return ret;
+
+	pix->width	= mf.width;
+	pix->height	= mf.height;
+	pix->colorspace	= mf.colorspace;
+
+	switch (mf.field) {
+	case V4L2_FIELD_ANY:
+		pix->field = V4L2_FIELD_NONE;
+		break;
+	case V4L2_FIELD_NONE:
+		break;
+	default:
+		dev_err(icd->parent, "Field type %d unsupported.\n",
+			mf.field);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static const struct soc_mbus_pixelfmt isi_camera_formats[] = {
+	{
+		.fourcc			= V4L2_PIX_FMT_YUYV,
+		.name			= "Packed YUV422 16 bit",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+};
+
+/* This will be corrected as we get more formats */
+static bool isi_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt)
+{
+	return	fmt->packing == SOC_MBUS_PACKING_NONE ||
+		(fmt->bits_per_sample == 8 &&
+		 fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) ||
+		(fmt->bits_per_sample > 8 &&
+		 fmt->packing == SOC_MBUS_PACKING_EXTEND16);
+}
+
+#define ISI_BUS_PARAM (V4L2_MBUS_MASTER |	\
+		V4L2_MBUS_HSYNC_ACTIVE_HIGH |	\
+		V4L2_MBUS_HSYNC_ACTIVE_LOW |	\
+		V4L2_MBUS_VSYNC_ACTIVE_HIGH |	\
+		V4L2_MBUS_VSYNC_ACTIVE_LOW |	\
+		V4L2_MBUS_PCLK_SAMPLE_RISING |	\
+		V4L2_MBUS_PCLK_SAMPLE_FALLING |	\
+		V4L2_MBUS_DATA_ACTIVE_HIGH)
+
+static int isi_camera_try_bus_param(struct soc_camera_device *icd,
+				    unsigned char buswidth)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct atmel_isi *isi = ici->priv;
+	struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+	unsigned long common_flags;
+	int ret;
+
+	ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
+	if (!ret) {
+		common_flags = soc_mbus_config_compatible(&cfg,
+							  ISI_BUS_PARAM);
+		if (!common_flags) {
+			dev_warn(icd->parent,
+				 "Flags incompatible: camera 0x%x, host 0x%x\n",
+				 cfg.flags, ISI_BUS_PARAM);
+			return -EINVAL;
+		}
+	} else if (ret != -ENOIOCTLCMD) {
+		return ret;
+	}
+
+	if ((1 << (buswidth - 1)) & isi->width_flags)
+		return 0;
+	return -EINVAL;
+}
+
+
+static int isi_camera_get_formats(struct soc_camera_device *icd,
+				  unsigned int idx,
+				  struct soc_camera_format_xlate *xlate)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	int formats = 0, ret;
+	/* sensor format */
+	enum v4l2_mbus_pixelcode code;
+	/* soc camera host format */
+	const struct soc_mbus_pixelfmt *fmt;
+
+	ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
+	if (ret < 0)
+		/* No more formats */
+		return 0;
+
+	fmt = soc_mbus_get_fmtdesc(code);
+	if (!fmt) {
+		dev_err(icd->parent,
+			"Invalid format code #%u: %d\n", idx, code);
+		return 0;
+	}
+
+	/* This also checks support for the requested bits-per-sample */
+	ret = isi_camera_try_bus_param(icd, fmt->bits_per_sample);
+	if (ret < 0) {
+		dev_err(icd->parent,
+			"Fail to try the bus parameters.\n");
+		return 0;
+	}
+
+	switch (code) {
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+	case V4L2_MBUS_FMT_VYUY8_2X8:
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+	case V4L2_MBUS_FMT_YVYU8_2X8:
+		formats++;
+		if (xlate) {
+			xlate->host_fmt	= &isi_camera_formats[0];
+			xlate->code	= code;
+			xlate++;
+			dev_dbg(icd->parent, "Providing format %s using code %d\n",
+				isi_camera_formats[0].name, code);
+		}
+		break;
+	default:
+		if (!isi_camera_packing_supported(fmt))
+			return 0;
+		if (xlate)
+			dev_dbg(icd->parent,
+				"Providing format %s in pass-through mode\n",
+				fmt->name);
+	}
+
+	/* Generic pass-through */
+	formats++;
+	if (xlate) {
+		xlate->host_fmt	= fmt;
+		xlate->code	= code;
+		xlate++;
+	}
+
+	return formats;
+}
+
+/* Called with .video_lock held */
+static int isi_camera_add_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct atmel_isi *isi = ici->priv;
+	int ret;
+
+	if (isi->icd)
+		return -EBUSY;
+
+	ret = clk_enable(isi->pclk);
+	if (ret)
+		return ret;
+
+	ret = clk_enable(isi->mck);
+	if (ret) {
+		clk_disable(isi->pclk);
+		return ret;
+	}
+
+	isi->icd = icd;
+	dev_dbg(icd->parent, "Atmel ISI Camera driver attached to camera %d\n",
+		 icd->devnum);
+	return 0;
+}
+/* Called with .video_lock held */
+static void isi_camera_remove_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct atmel_isi *isi = ici->priv;
+
+	BUG_ON(icd != isi->icd);
+
+	clk_disable(isi->mck);
+	clk_disable(isi->pclk);
+	isi->icd = NULL;
+
+	dev_dbg(icd->parent, "Atmel ISI Camera driver detached from camera %d\n",
+		 icd->devnum);
+}
+
+static unsigned int isi_camera_poll(struct file *file, poll_table *pt)
+{
+	struct soc_camera_device *icd = file->private_data;
+
+	return vb2_poll(&icd->vb2_vidq, file, pt);
+}
+
+static int isi_camera_querycap(struct soc_camera_host *ici,
+			       struct v4l2_capability *cap)
+{
+	strcpy(cap->driver, "atmel-isi");
+	strcpy(cap->card, "Atmel Image Sensor Interface");
+	cap->capabilities = (V4L2_CAP_VIDEO_CAPTURE |
+				V4L2_CAP_STREAMING);
+	return 0;
+}
+
+static int isi_camera_set_bus_param(struct soc_camera_device *icd)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct atmel_isi *isi = ici->priv;
+	struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+	unsigned long common_flags;
+	int ret;
+	u32 cfg1 = 0;
+
+	ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
+	if (!ret) {
+		common_flags = soc_mbus_config_compatible(&cfg,
+							  ISI_BUS_PARAM);
+		if (!common_flags) {
+			dev_warn(icd->parent,
+				 "Flags incompatible: camera 0x%x, host 0x%x\n",
+				 cfg.flags, ISI_BUS_PARAM);
+			return -EINVAL;
+		}
+	} else if (ret != -ENOIOCTLCMD) {
+		return ret;
+	} else {
+		common_flags = ISI_BUS_PARAM;
+	}
+	dev_dbg(icd->parent, "Flags cam: 0x%x host: 0x%x common: 0x%lx\n",
+		cfg.flags, ISI_BUS_PARAM, common_flags);
+
+	/* Make choises, based on platform preferences */
+	if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
+	    (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
+		if (isi->pdata->hsync_act_low)
+			common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
+		else
+			common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
+	}
+
+	if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
+	    (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
+		if (isi->pdata->vsync_act_low)
+			common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
+		else
+			common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
+	}
+
+	if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
+	    (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
+		if (isi->pdata->pclk_act_falling)
+			common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
+		else
+			common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
+	}
+
+	cfg.flags = common_flags;
+	ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
+	if (ret < 0 && ret != -ENOIOCTLCMD) {
+		dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n",
+			common_flags, ret);
+		return ret;
+	}
+
+	/* set bus param for ISI */
+	if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+		cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW;
+	if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+		cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW;
+	if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+		cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING;
+
+	if (isi->pdata->has_emb_sync)
+		cfg1 |= ISI_CFG1_EMB_SYNC;
+	if (isi->pdata->full_mode)
+		cfg1 |= ISI_CFG1_FULL_MODE;
+
+	isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
+	isi_writel(isi, ISI_CFG1, cfg1);
+
+	return 0;
+}
+
+static struct soc_camera_host_ops isi_soc_camera_host_ops = {
+	.owner		= THIS_MODULE,
+	.add		= isi_camera_add_device,
+	.remove		= isi_camera_remove_device,
+	.set_fmt	= isi_camera_set_fmt,
+	.try_fmt	= isi_camera_try_fmt,
+	.get_formats	= isi_camera_get_formats,
+	.init_videobuf2	= isi_camera_init_videobuf,
+	.poll		= isi_camera_poll,
+	.querycap	= isi_camera_querycap,
+	.set_bus_param	= isi_camera_set_bus_param,
+};
+
+/* -----------------------------------------------------------------------*/
+static int __devexit atmel_isi_remove(struct platform_device *pdev)
+{
+	struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+	struct atmel_isi *isi = container_of(soc_host,
+					struct atmel_isi, soc_host);
+
+	free_irq(isi->irq, isi);
+	soc_camera_host_unregister(soc_host);
+	vb2_dma_contig_cleanup_ctx(isi->alloc_ctx);
+	dma_free_coherent(&pdev->dev,
+			sizeof(struct fbd) * MAX_BUFFER_NUM,
+			isi->p_fb_descriptors,
+			isi->fb_descriptors_phys);
+
+	iounmap(isi->regs);
+	clk_unprepare(isi->mck);
+	clk_put(isi->mck);
+	clk_unprepare(isi->pclk);
+	clk_put(isi->pclk);
+	kfree(isi);
+
+	return 0;
+}
+
+static int __devinit atmel_isi_probe(struct platform_device *pdev)
+{
+	unsigned int irq;
+	struct atmel_isi *isi;
+	struct clk *pclk;
+	struct resource *regs;
+	int ret, i;
+	struct device *dev = &pdev->dev;
+	struct soc_camera_host *soc_host;
+	struct isi_platform_data *pdata;
+
+	pdata = dev->platform_data;
+	if (!pdata || !pdata->data_width_flags || !pdata->mck_hz) {
+		dev_err(&pdev->dev,
+			"No config available for Atmel ISI\n");
+		return -EINVAL;
+	}
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!regs)
+		return -ENXIO;
+
+	pclk = clk_get(&pdev->dev, "isi_clk");
+	if (IS_ERR(pclk))
+		return PTR_ERR(pclk);
+
+	ret = clk_prepare(pclk);
+	if (ret)
+		goto err_clk_prepare_pclk;
+
+	isi = kzalloc(sizeof(struct atmel_isi), GFP_KERNEL);
+	if (!isi) {
+		ret = -ENOMEM;
+		dev_err(&pdev->dev, "Can't allocate interface!\n");
+		goto err_alloc_isi;
+	}
+
+	isi->pclk = pclk;
+	isi->pdata = pdata;
+	isi->active = NULL;
+	spin_lock_init(&isi->lock);
+	init_waitqueue_head(&isi->vsync_wq);
+	INIT_LIST_HEAD(&isi->video_buffer_list);
+	INIT_LIST_HEAD(&isi->dma_desc_head);
+
+	/* Get ISI_MCK, provided by programmable clock or external clock */
+	isi->mck = clk_get(dev, "isi_mck");
+	if (IS_ERR(isi->mck)) {
+		dev_err(dev, "Failed to get isi_mck\n");
+		ret = PTR_ERR(isi->mck);
+		goto err_clk_get;
+	}
+
+	ret = clk_prepare(isi->mck);
+	if (ret)
+		goto err_clk_prepare_mck;
+
+	/* Set ISI_MCK's frequency, it should be faster than pixel clock */
+	ret = clk_set_rate(isi->mck, pdata->mck_hz);
+	if (ret < 0)
+		goto err_set_mck_rate;
+
+	isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev,
+				sizeof(struct fbd) * MAX_BUFFER_NUM,
+				&isi->fb_descriptors_phys,
+				GFP_KERNEL);
+	if (!isi->p_fb_descriptors) {
+		ret = -ENOMEM;
+		dev_err(&pdev->dev, "Can't allocate descriptors!\n");
+		goto err_alloc_descriptors;
+	}
+
+	for (i = 0; i < MAX_BUFFER_NUM; i++) {
+		isi->dma_desc[i].p_fbd = isi->p_fb_descriptors + i;
+		isi->dma_desc[i].fbd_phys = isi->fb_descriptors_phys +
+					i * sizeof(struct fbd);
+		list_add(&isi->dma_desc[i].list, &isi->dma_desc_head);
+	}
+
+	isi->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+	if (IS_ERR(isi->alloc_ctx)) {
+		ret = PTR_ERR(isi->alloc_ctx);
+		goto err_alloc_ctx;
+	}
+
+	isi->regs = ioremap(regs->start, resource_size(regs));
+	if (!isi->regs) {
+		ret = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	if (pdata->data_width_flags & ISI_DATAWIDTH_8)
+		isi->width_flags = 1 << 7;
+	if (pdata->data_width_flags & ISI_DATAWIDTH_10)
+		isi->width_flags |= 1 << 9;
+
+	isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		ret = irq;
+		goto err_req_irq;
+	}
+
+	ret = request_irq(irq, isi_interrupt, 0, "isi", isi);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to request irq %d\n", irq);
+		goto err_req_irq;
+	}
+	isi->irq = irq;
+
+	soc_host		= &isi->soc_host;
+	soc_host->drv_name	= "isi-camera";
+	soc_host->ops		= &isi_soc_camera_host_ops;
+	soc_host->priv		= isi;
+	soc_host->v4l2_dev.dev	= &pdev->dev;
+	soc_host->nr		= pdev->id;
+
+	ret = soc_camera_host_register(soc_host);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to register soc camera host\n");
+		goto err_register_soc_camera_host;
+	}
+	return 0;
+
+err_register_soc_camera_host:
+	free_irq(isi->irq, isi);
+err_req_irq:
+	iounmap(isi->regs);
+err_ioremap:
+	vb2_dma_contig_cleanup_ctx(isi->alloc_ctx);
+err_alloc_ctx:
+	dma_free_coherent(&pdev->dev,
+			sizeof(struct fbd) * MAX_BUFFER_NUM,
+			isi->p_fb_descriptors,
+			isi->fb_descriptors_phys);
+err_alloc_descriptors:
+err_set_mck_rate:
+	clk_unprepare(isi->mck);
+err_clk_prepare_mck:
+	clk_put(isi->mck);
+err_clk_get:
+	kfree(isi);
+err_alloc_isi:
+	clk_unprepare(pclk);
+err_clk_prepare_pclk:
+	clk_put(pclk);
+
+	return ret;
+}
+
+static struct platform_driver atmel_isi_driver = {
+	.probe		= atmel_isi_probe,
+	.remove		= __devexit_p(atmel_isi_remove),
+	.driver		= {
+		.name = "atmel_isi",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init atmel_isi_init_module(void)
+{
+	return  platform_driver_probe(&atmel_isi_driver, &atmel_isi_probe);
+}
+
+static void __exit atmel_isi_exit(void)
+{
+	platform_driver_unregister(&atmel_isi_driver);
+}
+module_init(atmel_isi_init_module);
+module_exit(atmel_isi_exit);
+
+MODULE_AUTHOR("Josh Wu <josh.wu@atmel.com>");
+MODULE_DESCRIPTION("The V4L2 driver for Atmel Linux");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("video");
diff --git a/drivers/media/platform/blackfin/Kconfig b/drivers/media/platform/blackfin/Kconfig
new file mode 100644
index 0000000..ecd5323
--- /dev/null
+++ b/drivers/media/platform/blackfin/Kconfig
@@ -0,0 +1,10 @@
+config VIDEO_BLACKFIN_CAPTURE
+	tristate "Blackfin Video Capture Driver"
+	depends on VIDEO_V4L2 && BLACKFIN && I2C
+	select VIDEOBUF2_DMA_CONTIG
+	help
+	  V4L2 bridge driver for Blackfin video capture device.
+	  Choose PPI or EPPI as its interface.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bfin_video_capture.
diff --git a/drivers/media/platform/blackfin/Makefile b/drivers/media/platform/blackfin/Makefile
new file mode 100644
index 0000000..aa3a0a2
--- /dev/null
+++ b/drivers/media/platform/blackfin/Makefile
@@ -0,0 +1,2 @@
+bfin_video_capture-objs := bfin_capture.o ppi.o
+obj-$(CONFIG_VIDEO_BLACKFIN_CAPTURE) += bfin_video_capture.o
diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c
new file mode 100644
index 0000000..1677623
--- /dev/null
+++ b/drivers/media/platform/blackfin/bfin_capture.c
@@ -0,0 +1,1068 @@
+/*
+ * Analog Devices video capture driver
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include <asm/dma.h>
+
+#include <media/blackfin/bfin_capture.h>
+#include <media/blackfin/ppi.h>
+
+#define CAPTURE_DRV_NAME        "bfin_capture"
+#define BCAP_MIN_NUM_BUF        2
+
+struct bcap_format {
+	char *desc;
+	u32 pixelformat;
+	enum v4l2_mbus_pixelcode mbus_code;
+	int bpp; /* bits per pixel */
+};
+
+struct bcap_buffer {
+	struct vb2_buffer vb;
+	struct list_head list;
+};
+
+struct bcap_device {
+	/* capture device instance */
+	struct v4l2_device v4l2_dev;
+	/* v4l2 control handler */
+	struct v4l2_ctrl_handler ctrl_handler;
+	/* device node data */
+	struct video_device *video_dev;
+	/* sub device instance */
+	struct v4l2_subdev *sd;
+	/* capture config */
+	struct bfin_capture_config *cfg;
+	/* ppi interface */
+	struct ppi_if *ppi;
+	/* current input */
+	unsigned int cur_input;
+	/* current selected standard */
+	v4l2_std_id std;
+	/* used to store pixel format */
+	struct v4l2_pix_format fmt;
+	/* bits per pixel*/
+	int bpp;
+	/* used to store sensor supported format */
+	struct bcap_format *sensor_formats;
+	/* number of sensor formats array */
+	int num_sensor_formats;
+	/* pointing to current video buffer */
+	struct bcap_buffer *cur_frm;
+	/* pointing to next video buffer */
+	struct bcap_buffer *next_frm;
+	/* buffer queue used in videobuf2 */
+	struct vb2_queue buffer_queue;
+	/* allocator-specific contexts for each plane */
+	struct vb2_alloc_ctx *alloc_ctx;
+	/* queue of filled frames */
+	struct list_head dma_queue;
+	/* used in videobuf2 callback */
+	spinlock_t lock;
+	/* used to access capture device */
+	struct mutex mutex;
+	/* used to wait ppi to complete one transfer */
+	struct completion comp;
+	/* prepare to stop */
+	bool stop;
+};
+
+struct bcap_fh {
+	struct v4l2_fh fh;
+	/* indicates whether this file handle is doing IO */
+	bool io_allowed;
+};
+
+static const struct bcap_format bcap_formats[] = {
+	{
+		.desc        = "YCbCr 4:2:2 Interleaved UYVY",
+		.pixelformat = V4L2_PIX_FMT_UYVY,
+		.mbus_code   = V4L2_MBUS_FMT_UYVY8_2X8,
+		.bpp         = 16,
+	},
+	{
+		.desc        = "YCbCr 4:2:2 Interleaved YUYV",
+		.pixelformat = V4L2_PIX_FMT_YUYV,
+		.mbus_code   = V4L2_MBUS_FMT_YUYV8_2X8,
+		.bpp         = 16,
+	},
+	{
+		.desc        = "RGB 565",
+		.pixelformat = V4L2_PIX_FMT_RGB565,
+		.mbus_code   = V4L2_MBUS_FMT_RGB565_2X8_LE,
+		.bpp         = 16,
+	},
+	{
+		.desc        = "RGB 444",
+		.pixelformat = V4L2_PIX_FMT_RGB444,
+		.mbus_code   = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+		.bpp         = 16,
+	},
+
+};
+#define BCAP_MAX_FMTS ARRAY_SIZE(bcap_formats)
+
+static irqreturn_t bcap_isr(int irq, void *dev_id);
+
+static struct bcap_buffer *to_bcap_vb(struct vb2_buffer *vb)
+{
+	return container_of(vb, struct bcap_buffer, vb);
+}
+
+static int bcap_init_sensor_formats(struct bcap_device *bcap_dev)
+{
+	enum v4l2_mbus_pixelcode code;
+	struct bcap_format *sf;
+	unsigned int num_formats = 0;
+	int i, j;
+
+	while (!v4l2_subdev_call(bcap_dev->sd, video,
+				enum_mbus_fmt, num_formats, &code))
+		num_formats++;
+	if (!num_formats)
+		return -ENXIO;
+
+	sf = kzalloc(num_formats * sizeof(*sf), GFP_KERNEL);
+	if (!sf)
+		return -ENOMEM;
+
+	for (i = 0; i < num_formats; i++) {
+		v4l2_subdev_call(bcap_dev->sd, video,
+				enum_mbus_fmt, i, &code);
+		for (j = 0; j < BCAP_MAX_FMTS; j++)
+			if (code == bcap_formats[j].mbus_code)
+				break;
+		if (j == BCAP_MAX_FMTS) {
+			/* we don't allow this sensor working with our bridge */
+			kfree(sf);
+			return -EINVAL;
+		}
+		sf[i] = bcap_formats[j];
+	}
+	bcap_dev->sensor_formats = sf;
+	bcap_dev->num_sensor_formats = num_formats;
+	return 0;
+}
+
+static void bcap_free_sensor_formats(struct bcap_device *bcap_dev)
+{
+	bcap_dev->num_sensor_formats = 0;
+	kfree(bcap_dev->sensor_formats);
+	bcap_dev->sensor_formats = NULL;
+}
+
+static int bcap_open(struct file *file)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct video_device *vfd = bcap_dev->video_dev;
+	struct bcap_fh *bcap_fh;
+
+	if (!bcap_dev->sd) {
+		v4l2_err(&bcap_dev->v4l2_dev, "No sub device registered\n");
+		return -ENODEV;
+	}
+
+	bcap_fh = kzalloc(sizeof(*bcap_fh), GFP_KERNEL);
+	if (!bcap_fh) {
+		v4l2_err(&bcap_dev->v4l2_dev,
+			 "unable to allocate memory for file handle object\n");
+		return -ENOMEM;
+	}
+
+	v4l2_fh_init(&bcap_fh->fh, vfd);
+
+	/* store pointer to v4l2_fh in private_data member of file */
+	file->private_data = &bcap_fh->fh;
+	v4l2_fh_add(&bcap_fh->fh);
+	bcap_fh->io_allowed = false;
+	return 0;
+}
+
+static int bcap_release(struct file *file)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct v4l2_fh *fh = file->private_data;
+	struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
+
+	/* if this instance is doing IO */
+	if (bcap_fh->io_allowed)
+		vb2_queue_release(&bcap_dev->buffer_queue);
+
+	file->private_data = NULL;
+	v4l2_fh_del(&bcap_fh->fh);
+	v4l2_fh_exit(&bcap_fh->fh);
+	kfree(bcap_fh);
+	return 0;
+}
+
+static int bcap_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	int ret;
+
+	if (mutex_lock_interruptible(&bcap_dev->mutex))
+		return -ERESTARTSYS;
+	ret = vb2_mmap(&bcap_dev->buffer_queue, vma);
+	mutex_unlock(&bcap_dev->mutex);
+	return ret;
+}
+
+#ifndef CONFIG_MMU
+static unsigned long bcap_get_unmapped_area(struct file *file,
+					    unsigned long addr,
+					    unsigned long len,
+					    unsigned long pgoff,
+					    unsigned long flags)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	return vb2_get_unmapped_area(&bcap_dev->buffer_queue,
+				     addr,
+				     len,
+				     pgoff,
+				     flags);
+}
+#endif
+
+static unsigned int bcap_poll(struct file *file, poll_table *wait)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	unsigned int res;
+
+	mutex_lock(&bcap_dev->mutex);
+	res = vb2_poll(&bcap_dev->buffer_queue, file, wait);
+	mutex_unlock(&bcap_dev->mutex);
+	return res;
+}
+
+static int bcap_queue_setup(struct vb2_queue *vq,
+				const struct v4l2_format *fmt,
+				unsigned int *nbuffers, unsigned int *nplanes,
+				unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+
+	if (*nbuffers < BCAP_MIN_NUM_BUF)
+		*nbuffers = BCAP_MIN_NUM_BUF;
+
+	*nplanes = 1;
+	sizes[0] = bcap_dev->fmt.sizeimage;
+	alloc_ctxs[0] = bcap_dev->alloc_ctx;
+
+	return 0;
+}
+
+static int bcap_buffer_init(struct vb2_buffer *vb)
+{
+	struct bcap_buffer *buf = to_bcap_vb(vb);
+
+	INIT_LIST_HEAD(&buf->list);
+	return 0;
+}
+
+static int bcap_buffer_prepare(struct vb2_buffer *vb)
+{
+	struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct bcap_buffer *buf = to_bcap_vb(vb);
+	unsigned long size;
+
+	size = bcap_dev->fmt.sizeimage;
+	if (vb2_plane_size(vb, 0) < size) {
+		v4l2_err(&bcap_dev->v4l2_dev, "buffer too small (%lu < %lu)\n",
+				vb2_plane_size(vb, 0), size);
+		return -EINVAL;
+	}
+	vb2_set_plane_payload(&buf->vb, 0, size);
+
+	return 0;
+}
+
+static void bcap_buffer_queue(struct vb2_buffer *vb)
+{
+	struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct bcap_buffer *buf = to_bcap_vb(vb);
+	unsigned long flags;
+
+	spin_lock_irqsave(&bcap_dev->lock, flags);
+	list_add_tail(&buf->list, &bcap_dev->dma_queue);
+	spin_unlock_irqrestore(&bcap_dev->lock, flags);
+}
+
+static void bcap_buffer_cleanup(struct vb2_buffer *vb)
+{
+	struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct bcap_buffer *buf = to_bcap_vb(vb);
+	unsigned long flags;
+
+	spin_lock_irqsave(&bcap_dev->lock, flags);
+	list_del_init(&buf->list);
+	spin_unlock_irqrestore(&bcap_dev->lock, flags);
+}
+
+static void bcap_lock(struct vb2_queue *vq)
+{
+	struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+	mutex_lock(&bcap_dev->mutex);
+}
+
+static void bcap_unlock(struct vb2_queue *vq)
+{
+	struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+	mutex_unlock(&bcap_dev->mutex);
+}
+
+static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+	struct ppi_if *ppi = bcap_dev->ppi;
+	struct ppi_params params;
+	int ret;
+
+	/* enable streamon on the sub device */
+	ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 1);
+	if (ret && (ret != -ENOIOCTLCMD)) {
+		v4l2_err(&bcap_dev->v4l2_dev, "stream on failed in subdev\n");
+		return ret;
+	}
+
+	/* set ppi params */
+	params.width = bcap_dev->fmt.width;
+	params.height = bcap_dev->fmt.height;
+	params.bpp = bcap_dev->bpp;
+	params.ppi_control = bcap_dev->cfg->ppi_control;
+	params.int_mask = bcap_dev->cfg->int_mask;
+	params.blank_clocks = bcap_dev->cfg->blank_clocks;
+	ret = ppi->ops->set_params(ppi, &params);
+	if (ret < 0) {
+		v4l2_err(&bcap_dev->v4l2_dev,
+				"Error in setting ppi params\n");
+		return ret;
+	}
+
+	/* attach ppi DMA irq handler */
+	ret = ppi->ops->attach_irq(ppi, bcap_isr);
+	if (ret < 0) {
+		v4l2_err(&bcap_dev->v4l2_dev,
+				"Error in attaching interrupt handler\n");
+		return ret;
+	}
+
+	INIT_COMPLETION(bcap_dev->comp);
+	bcap_dev->stop = false;
+	return 0;
+}
+
+static int bcap_stop_streaming(struct vb2_queue *vq)
+{
+	struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+	struct ppi_if *ppi = bcap_dev->ppi;
+	int ret;
+
+	if (!vb2_is_streaming(vq))
+		return 0;
+
+	bcap_dev->stop = true;
+	wait_for_completion(&bcap_dev->comp);
+	ppi->ops->stop(ppi);
+	ppi->ops->detach_irq(ppi);
+	ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 0);
+	if (ret && (ret != -ENOIOCTLCMD))
+		v4l2_err(&bcap_dev->v4l2_dev,
+				"stream off failed in subdev\n");
+
+	/* release all active buffers */
+	while (!list_empty(&bcap_dev->dma_queue)) {
+		bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next,
+						struct bcap_buffer, list);
+		list_del(&bcap_dev->next_frm->list);
+		vb2_buffer_done(&bcap_dev->next_frm->vb, VB2_BUF_STATE_ERROR);
+	}
+	return 0;
+}
+
+static struct vb2_ops bcap_video_qops = {
+	.queue_setup            = bcap_queue_setup,
+	.buf_init               = bcap_buffer_init,
+	.buf_prepare            = bcap_buffer_prepare,
+	.buf_cleanup            = bcap_buffer_cleanup,
+	.buf_queue              = bcap_buffer_queue,
+	.wait_prepare           = bcap_unlock,
+	.wait_finish            = bcap_lock,
+	.start_streaming        = bcap_start_streaming,
+	.stop_streaming         = bcap_stop_streaming,
+};
+
+static int bcap_reqbufs(struct file *file, void *priv,
+			struct v4l2_requestbuffers *req_buf)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct vb2_queue *vq = &bcap_dev->buffer_queue;
+	struct v4l2_fh *fh = file->private_data;
+	struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
+
+	if (vb2_is_busy(vq))
+		return -EBUSY;
+
+	bcap_fh->io_allowed = true;
+
+	return vb2_reqbufs(vq, req_buf);
+}
+
+static int bcap_querybuf(struct file *file, void *priv,
+				struct v4l2_buffer *buf)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	return vb2_querybuf(&bcap_dev->buffer_queue, buf);
+}
+
+static int bcap_qbuf(struct file *file, void *priv,
+			struct v4l2_buffer *buf)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct v4l2_fh *fh = file->private_data;
+	struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
+
+	if (!bcap_fh->io_allowed)
+		return -EBUSY;
+
+	return vb2_qbuf(&bcap_dev->buffer_queue, buf);
+}
+
+static int bcap_dqbuf(struct file *file, void *priv,
+			struct v4l2_buffer *buf)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct v4l2_fh *fh = file->private_data;
+	struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
+
+	if (!bcap_fh->io_allowed)
+		return -EBUSY;
+
+	return vb2_dqbuf(&bcap_dev->buffer_queue,
+				buf, file->f_flags & O_NONBLOCK);
+}
+
+static irqreturn_t bcap_isr(int irq, void *dev_id)
+{
+	struct ppi_if *ppi = dev_id;
+	struct bcap_device *bcap_dev = ppi->priv;
+	struct timeval timevalue;
+	struct vb2_buffer *vb = &bcap_dev->cur_frm->vb;
+	dma_addr_t addr;
+
+	spin_lock(&bcap_dev->lock);
+
+	if (bcap_dev->cur_frm != bcap_dev->next_frm) {
+		do_gettimeofday(&timevalue);
+		vb->v4l2_buf.timestamp = timevalue;
+		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+		bcap_dev->cur_frm = bcap_dev->next_frm;
+	}
+
+	ppi->ops->stop(ppi);
+
+	if (bcap_dev->stop) {
+		complete(&bcap_dev->comp);
+	} else {
+		if (!list_empty(&bcap_dev->dma_queue)) {
+			bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next,
+						struct bcap_buffer, list);
+			list_del(&bcap_dev->next_frm->list);
+			addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->next_frm->vb, 0);
+			ppi->ops->update_addr(ppi, (unsigned long)addr);
+		}
+		ppi->ops->start(ppi);
+	}
+
+	spin_unlock(&bcap_dev->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int bcap_streamon(struct file *file, void *priv,
+				enum v4l2_buf_type buf_type)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct bcap_fh *fh = file->private_data;
+	struct ppi_if *ppi = bcap_dev->ppi;
+	dma_addr_t addr;
+	int ret;
+
+	if (!fh->io_allowed)
+		return -EBUSY;
+
+	/* call streamon to start streaming in videobuf */
+	ret = vb2_streamon(&bcap_dev->buffer_queue, buf_type);
+	if (ret)
+		return ret;
+
+	/* if dma queue is empty, return error */
+	if (list_empty(&bcap_dev->dma_queue)) {
+		v4l2_err(&bcap_dev->v4l2_dev, "dma queue is empty\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* get the next frame from the dma queue */
+	bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next,
+					struct bcap_buffer, list);
+	bcap_dev->cur_frm = bcap_dev->next_frm;
+	/* remove buffer from the dma queue */
+	list_del(&bcap_dev->cur_frm->list);
+	addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb, 0);
+	/* update DMA address */
+	ppi->ops->update_addr(ppi, (unsigned long)addr);
+	/* enable ppi */
+	ppi->ops->start(ppi);
+
+	return 0;
+err:
+	vb2_streamoff(&bcap_dev->buffer_queue, buf_type);
+	return ret;
+}
+
+static int bcap_streamoff(struct file *file, void *priv,
+				enum v4l2_buf_type buf_type)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct bcap_fh *fh = file->private_data;
+
+	if (!fh->io_allowed)
+		return -EBUSY;
+
+	return vb2_streamoff(&bcap_dev->buffer_queue, buf_type);
+}
+
+static int bcap_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	return v4l2_subdev_call(bcap_dev->sd, video, querystd, std);
+}
+
+static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	*std = bcap_dev->std;
+	return 0;
+}
+
+static int bcap_s_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	int ret;
+
+	if (vb2_is_busy(&bcap_dev->buffer_queue))
+		return -EBUSY;
+
+	ret = v4l2_subdev_call(bcap_dev->sd, core, s_std, *std);
+	if (ret < 0)
+		return ret;
+
+	bcap_dev->std = *std;
+	return 0;
+}
+
+static int bcap_enum_input(struct file *file, void *priv,
+				struct v4l2_input *input)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct bfin_capture_config *config = bcap_dev->cfg;
+	int ret;
+	u32 status;
+
+	if (input->index >= config->num_inputs)
+		return -EINVAL;
+
+	*input = config->inputs[input->index];
+	/* get input status */
+	ret = v4l2_subdev_call(bcap_dev->sd, video, g_input_status, &status);
+	if (!ret)
+		input->status = status;
+	return 0;
+}
+
+static int bcap_g_input(struct file *file, void *priv, unsigned int *index)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	*index = bcap_dev->cur_input;
+	return 0;
+}
+
+static int bcap_s_input(struct file *file, void *priv, unsigned int index)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct bfin_capture_config *config = bcap_dev->cfg;
+	struct bcap_route *route;
+	int ret;
+
+	if (vb2_is_busy(&bcap_dev->buffer_queue))
+		return -EBUSY;
+
+	if (index >= config->num_inputs)
+		return -EINVAL;
+
+	route = &config->routes[index];
+	ret = v4l2_subdev_call(bcap_dev->sd, video, s_routing,
+				route->input, route->output, 0);
+	if ((ret < 0) && (ret != -ENOIOCTLCMD)) {
+		v4l2_err(&bcap_dev->v4l2_dev, "Failed to set input\n");
+		return ret;
+	}
+	bcap_dev->cur_input = index;
+	return 0;
+}
+
+static int bcap_try_format(struct bcap_device *bcap,
+				struct v4l2_pix_format *pixfmt,
+				enum v4l2_mbus_pixelcode *mbus_code,
+				int *bpp)
+{
+	struct bcap_format *sf = bcap->sensor_formats;
+	struct bcap_format *fmt = NULL;
+	struct v4l2_mbus_framefmt mbus_fmt;
+	int ret, i;
+
+	for (i = 0; i < bcap->num_sensor_formats; i++) {
+		fmt = &sf[i];
+		if (pixfmt->pixelformat == fmt->pixelformat)
+			break;
+	}
+	if (i == bcap->num_sensor_formats)
+		fmt = &sf[0];
+
+	if (mbus_code)
+		*mbus_code = fmt->mbus_code;
+	if (bpp)
+		*bpp = fmt->bpp;
+	v4l2_fill_mbus_format(&mbus_fmt, pixfmt, fmt->mbus_code);
+	ret = v4l2_subdev_call(bcap->sd, video,
+				try_mbus_fmt, &mbus_fmt);
+	if (ret < 0)
+		return ret;
+	v4l2_fill_pix_format(pixfmt, &mbus_fmt);
+	pixfmt->bytesperline = pixfmt->width * fmt->bpp / 8;
+	pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
+	return 0;
+}
+
+static int bcap_enum_fmt_vid_cap(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *fmt)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct bcap_format *sf = bcap_dev->sensor_formats;
+
+	if (fmt->index >= bcap_dev->num_sensor_formats)
+		return -EINVAL;
+
+	fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	strlcpy(fmt->description,
+		sf[fmt->index].desc,
+		sizeof(fmt->description));
+	fmt->pixelformat = sf[fmt->index].pixelformat;
+	return 0;
+}
+
+static int bcap_try_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *fmt)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+	return bcap_try_format(bcap_dev, pixfmt, NULL, NULL);
+}
+
+static int bcap_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	fmt->fmt.pix = bcap_dev->fmt;
+	return 0;
+}
+
+static int bcap_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct v4l2_mbus_framefmt mbus_fmt;
+	enum v4l2_mbus_pixelcode mbus_code;
+	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+	int ret, bpp;
+
+	if (vb2_is_busy(&bcap_dev->buffer_queue))
+		return -EBUSY;
+
+	/* see if format works */
+	ret = bcap_try_format(bcap_dev, pixfmt, &mbus_code, &bpp);
+	if (ret < 0)
+		return ret;
+
+	v4l2_fill_mbus_format(&mbus_fmt, pixfmt, mbus_code);
+	ret = v4l2_subdev_call(bcap_dev->sd, video, s_mbus_fmt, &mbus_fmt);
+	if (ret < 0)
+		return ret;
+	bcap_dev->fmt = *pixfmt;
+	bcap_dev->bpp = bpp;
+	return 0;
+}
+
+static int bcap_querycap(struct file *file, void  *priv,
+				struct v4l2_capability *cap)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+	strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
+	strlcpy(cap->bus_info, "Blackfin Platform", sizeof(cap->bus_info));
+	strlcpy(cap->card, bcap_dev->cfg->card_name, sizeof(cap->card));
+	return 0;
+}
+
+static int bcap_g_parm(struct file *file, void *fh,
+				struct v4l2_streamparm *a)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	return v4l2_subdev_call(bcap_dev->sd, video, g_parm, a);
+}
+
+static int bcap_s_parm(struct file *file, void *fh,
+				struct v4l2_streamparm *a)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	return v4l2_subdev_call(bcap_dev->sd, video, s_parm, a);
+}
+
+static int bcap_g_chip_ident(struct file *file, void *priv,
+		struct v4l2_dbg_chip_ident *chip)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	chip->ident = V4L2_IDENT_NONE;
+	chip->revision = 0;
+	if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+			chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+
+	return v4l2_subdev_call(bcap_dev->sd, core,
+			g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int bcap_dbg_g_register(struct file *file, void *priv,
+		struct v4l2_dbg_register *reg)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	return v4l2_subdev_call(bcap_dev->sd, core,
+			g_register, reg);
+}
+
+static int bcap_dbg_s_register(struct file *file, void *priv,
+		struct v4l2_dbg_register *reg)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	return v4l2_subdev_call(bcap_dev->sd, core,
+			s_register, reg);
+}
+#endif
+
+static int bcap_log_status(struct file *file, void *priv)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	/* status for sub devices */
+	v4l2_device_call_all(&bcap_dev->v4l2_dev, 0, core, log_status);
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops bcap_ioctl_ops = {
+	.vidioc_querycap         = bcap_querycap,
+	.vidioc_g_fmt_vid_cap    = bcap_g_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_cap = bcap_enum_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap    = bcap_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap  = bcap_try_fmt_vid_cap,
+	.vidioc_enum_input       = bcap_enum_input,
+	.vidioc_g_input          = bcap_g_input,
+	.vidioc_s_input          = bcap_s_input,
+	.vidioc_querystd         = bcap_querystd,
+	.vidioc_s_std            = bcap_s_std,
+	.vidioc_g_std            = bcap_g_std,
+	.vidioc_reqbufs          = bcap_reqbufs,
+	.vidioc_querybuf         = bcap_querybuf,
+	.vidioc_qbuf             = bcap_qbuf,
+	.vidioc_dqbuf            = bcap_dqbuf,
+	.vidioc_streamon         = bcap_streamon,
+	.vidioc_streamoff        = bcap_streamoff,
+	.vidioc_g_parm           = bcap_g_parm,
+	.vidioc_s_parm           = bcap_s_parm,
+	.vidioc_g_chip_ident     = bcap_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register       = bcap_dbg_g_register,
+	.vidioc_s_register       = bcap_dbg_s_register,
+#endif
+	.vidioc_log_status       = bcap_log_status,
+};
+
+static struct v4l2_file_operations bcap_fops = {
+	.owner = THIS_MODULE,
+	.open = bcap_open,
+	.release = bcap_release,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap = bcap_mmap,
+#ifndef CONFIG_MMU
+	.get_unmapped_area = bcap_get_unmapped_area,
+#endif
+	.poll = bcap_poll
+};
+
+static int __devinit bcap_probe(struct platform_device *pdev)
+{
+	struct bcap_device *bcap_dev;
+	struct video_device *vfd;
+	struct i2c_adapter *i2c_adap;
+	struct bfin_capture_config *config;
+	struct vb2_queue *q;
+	int ret;
+
+	config = pdev->dev.platform_data;
+	if (!config) {
+		v4l2_err(pdev->dev.driver, "Unable to get board config\n");
+		return -ENODEV;
+	}
+
+	bcap_dev = kzalloc(sizeof(*bcap_dev), GFP_KERNEL);
+	if (!bcap_dev) {
+		v4l2_err(pdev->dev.driver, "Unable to alloc bcap_dev\n");
+		return -ENOMEM;
+	}
+
+	bcap_dev->cfg = config;
+
+	bcap_dev->ppi = ppi_create_instance(config->ppi_info);
+	if (!bcap_dev->ppi) {
+		v4l2_err(pdev->dev.driver, "Unable to create ppi\n");
+		ret = -ENODEV;
+		goto err_free_dev;
+	}
+	bcap_dev->ppi->priv = bcap_dev;
+
+	bcap_dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+	if (IS_ERR(bcap_dev->alloc_ctx)) {
+		ret = PTR_ERR(bcap_dev->alloc_ctx);
+		goto err_free_ppi;
+	}
+
+	vfd = video_device_alloc();
+	if (!vfd) {
+		ret = -ENOMEM;
+		v4l2_err(pdev->dev.driver, "Unable to alloc video device\n");
+		goto err_cleanup_ctx;
+	}
+
+	/* initialize field of video device */
+	vfd->release            = video_device_release;
+	vfd->fops               = &bcap_fops;
+	vfd->ioctl_ops          = &bcap_ioctl_ops;
+	vfd->tvnorms            = 0;
+	vfd->v4l2_dev           = &bcap_dev->v4l2_dev;
+	set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+	strncpy(vfd->name, CAPTURE_DRV_NAME, sizeof(vfd->name));
+	bcap_dev->video_dev     = vfd;
+
+	ret = v4l2_device_register(&pdev->dev, &bcap_dev->v4l2_dev);
+	if (ret) {
+		v4l2_err(pdev->dev.driver,
+				"Unable to register v4l2 device\n");
+		goto err_release_vdev;
+	}
+	v4l2_info(&bcap_dev->v4l2_dev, "v4l2 device registered\n");
+
+	bcap_dev->v4l2_dev.ctrl_handler = &bcap_dev->ctrl_handler;
+	ret = v4l2_ctrl_handler_init(&bcap_dev->ctrl_handler, 0);
+	if (ret) {
+		v4l2_err(&bcap_dev->v4l2_dev,
+				"Unable to init control handler\n");
+		goto err_unreg_v4l2;
+	}
+
+	spin_lock_init(&bcap_dev->lock);
+	/* initialize queue */
+	q = &bcap_dev->buffer_queue;
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	q->io_modes = VB2_MMAP;
+	q->drv_priv = bcap_dev;
+	q->buf_struct_size = sizeof(struct bcap_buffer);
+	q->ops = &bcap_video_qops;
+	q->mem_ops = &vb2_dma_contig_memops;
+
+	vb2_queue_init(q);
+
+	mutex_init(&bcap_dev->mutex);
+	init_completion(&bcap_dev->comp);
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&bcap_dev->dma_queue);
+
+	vfd->lock = &bcap_dev->mutex;
+
+	/* register video device */
+	ret = video_register_device(bcap_dev->video_dev, VFL_TYPE_GRABBER, -1);
+	if (ret) {
+		v4l2_err(&bcap_dev->v4l2_dev,
+				"Unable to register video device\n");
+		goto err_free_handler;
+	}
+	video_set_drvdata(bcap_dev->video_dev, bcap_dev);
+	v4l2_info(&bcap_dev->v4l2_dev, "video device registered as: %s\n",
+			video_device_node_name(vfd));
+
+	/* load up the subdevice */
+	i2c_adap = i2c_get_adapter(config->i2c_adapter_id);
+	if (!i2c_adap) {
+		v4l2_err(&bcap_dev->v4l2_dev,
+				"Unable to find i2c adapter\n");
+		goto err_unreg_vdev;
+
+	}
+	bcap_dev->sd = v4l2_i2c_new_subdev_board(&bcap_dev->v4l2_dev,
+						 i2c_adap,
+						 &config->board_info,
+						 NULL);
+	if (bcap_dev->sd) {
+		int i;
+		/* update tvnorms from the sub devices */
+		for (i = 0; i < config->num_inputs; i++)
+			vfd->tvnorms |= config->inputs[i].std;
+	} else {
+		v4l2_err(&bcap_dev->v4l2_dev,
+				"Unable to register sub device\n");
+		goto err_unreg_vdev;
+	}
+
+	v4l2_info(&bcap_dev->v4l2_dev, "v4l2 sub device registered\n");
+
+	/* now we can probe the default state */
+	if (vfd->tvnorms) {
+		v4l2_std_id std;
+		ret = v4l2_subdev_call(bcap_dev->sd, core, g_std, &std);
+		if (ret) {
+			v4l2_err(&bcap_dev->v4l2_dev,
+					"Unable to get std\n");
+			goto err_unreg_vdev;
+		}
+		bcap_dev->std = std;
+	}
+	ret = bcap_init_sensor_formats(bcap_dev);
+	if (ret) {
+		v4l2_err(&bcap_dev->v4l2_dev,
+				"Unable to create sensor formats table\n");
+		goto err_unreg_vdev;
+	}
+	return 0;
+err_unreg_vdev:
+	video_unregister_device(bcap_dev->video_dev);
+	bcap_dev->video_dev = NULL;
+err_free_handler:
+	v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler);
+err_unreg_v4l2:
+	v4l2_device_unregister(&bcap_dev->v4l2_dev);
+err_release_vdev:
+	if (bcap_dev->video_dev)
+		video_device_release(bcap_dev->video_dev);
+err_cleanup_ctx:
+	vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx);
+err_free_ppi:
+	ppi_delete_instance(bcap_dev->ppi);
+err_free_dev:
+	kfree(bcap_dev);
+	return ret;
+}
+
+static int __devexit bcap_remove(struct platform_device *pdev)
+{
+	struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+	struct bcap_device *bcap_dev = container_of(v4l2_dev,
+						struct bcap_device, v4l2_dev);
+
+	bcap_free_sensor_formats(bcap_dev);
+	video_unregister_device(bcap_dev->video_dev);
+	v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler);
+	v4l2_device_unregister(v4l2_dev);
+	vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx);
+	ppi_delete_instance(bcap_dev->ppi);
+	kfree(bcap_dev);
+	return 0;
+}
+
+static struct platform_driver bcap_driver = {
+	.driver = {
+		.name  = CAPTURE_DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = bcap_probe,
+	.remove = __devexit_p(bcap_remove),
+};
+
+static __init int bcap_init(void)
+{
+	return platform_driver_register(&bcap_driver);
+}
+
+static __exit void bcap_exit(void)
+{
+	platform_driver_unregister(&bcap_driver);
+}
+
+module_init(bcap_init);
+module_exit(bcap_exit);
+
+MODULE_DESCRIPTION("Analog Devices blackfin video capture driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/blackfin/ppi.c b/drivers/media/platform/blackfin/ppi.c
new file mode 100644
index 0000000..d295921
--- /dev/null
+++ b/drivers/media/platform/blackfin/ppi.c
@@ -0,0 +1,271 @@
+/*
+ * ppi.c Analog Devices Parallel Peripheral Interface driver
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/slab.h>
+
+#include <asm/bfin_ppi.h>
+#include <asm/blackfin.h>
+#include <asm/cacheflush.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#include <media/blackfin/ppi.h>
+
+static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler);
+static void ppi_detach_irq(struct ppi_if *ppi);
+static int ppi_start(struct ppi_if *ppi);
+static int ppi_stop(struct ppi_if *ppi);
+static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params);
+static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr);
+
+static const struct ppi_ops ppi_ops = {
+	.attach_irq = ppi_attach_irq,
+	.detach_irq = ppi_detach_irq,
+	.start = ppi_start,
+	.stop = ppi_stop,
+	.set_params = ppi_set_params,
+	.update_addr = ppi_update_addr,
+};
+
+static irqreturn_t ppi_irq_err(int irq, void *dev_id)
+{
+	struct ppi_if *ppi = dev_id;
+	const struct ppi_info *info = ppi->info;
+
+	switch (info->type) {
+	case PPI_TYPE_PPI:
+	{
+		struct bfin_ppi_regs *reg = info->base;
+		unsigned short status;
+
+		/* register on bf561 is cleared when read 
+		 * others are W1C
+		 */
+		status = bfin_read16(&reg->status);
+		bfin_write16(&reg->status, 0xff00);
+		break;
+	}
+	case PPI_TYPE_EPPI:
+	{
+		struct bfin_eppi_regs *reg = info->base;
+		bfin_write16(&reg->status, 0xffff);
+		break;
+	}
+	default:
+		break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler)
+{
+	const struct ppi_info *info = ppi->info;
+	int ret;
+
+	ret = request_dma(info->dma_ch, "PPI_DMA");
+
+	if (ret) {
+		pr_err("Unable to allocate DMA channel for PPI\n");
+		return ret;
+	}
+	set_dma_callback(info->dma_ch, handler, ppi);
+
+	if (ppi->err_int) {
+		ret = request_irq(info->irq_err, ppi_irq_err, 0, "PPI ERROR", ppi);
+		if (ret) {
+			pr_err("Unable to allocate IRQ for PPI\n");
+			free_dma(info->dma_ch);
+		}
+	}
+	return ret;
+}
+
+static void ppi_detach_irq(struct ppi_if *ppi)
+{
+	const struct ppi_info *info = ppi->info;
+
+	if (ppi->err_int)
+		free_irq(info->irq_err, ppi);
+	free_dma(info->dma_ch);
+}
+
+static int ppi_start(struct ppi_if *ppi)
+{
+	const struct ppi_info *info = ppi->info;
+
+	/* enable DMA */
+	enable_dma(info->dma_ch);
+
+	/* enable PPI */
+	ppi->ppi_control |= PORT_EN;
+	switch (info->type) {
+	case PPI_TYPE_PPI:
+	{
+		struct bfin_ppi_regs *reg = info->base;
+		bfin_write16(&reg->control, ppi->ppi_control);
+		break;
+	}
+	case PPI_TYPE_EPPI:
+	{
+		struct bfin_eppi_regs *reg = info->base;
+		bfin_write32(&reg->control, ppi->ppi_control);
+		break;
+	}
+	default:
+		return -EINVAL;
+	}
+
+	SSYNC();
+	return 0;
+}
+
+static int ppi_stop(struct ppi_if *ppi)
+{
+	const struct ppi_info *info = ppi->info;
+
+	/* disable PPI */
+	ppi->ppi_control &= ~PORT_EN;
+	switch (info->type) {
+	case PPI_TYPE_PPI:
+	{
+		struct bfin_ppi_regs *reg = info->base;
+		bfin_write16(&reg->control, ppi->ppi_control);
+		break;
+	}
+	case PPI_TYPE_EPPI:
+	{
+		struct bfin_eppi_regs *reg = info->base;
+		bfin_write32(&reg->control, ppi->ppi_control);
+		break;
+	}
+	default:
+		return -EINVAL;
+	}
+
+	/* disable DMA */
+	clear_dma_irqstat(info->dma_ch);
+	disable_dma(info->dma_ch);
+
+	SSYNC();
+	return 0;
+}
+
+static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params)
+{
+	const struct ppi_info *info = ppi->info;
+	int dma32 = 0;
+	int dma_config, bytes_per_line, lines_per_frame;
+
+	bytes_per_line = params->width * params->bpp / 8;
+	lines_per_frame = params->height;
+	if (params->int_mask == 0xFFFFFFFF)
+		ppi->err_int = false;
+	else
+		ppi->err_int = true;
+
+	dma_config = (DMA_FLOW_STOP | WNR | RESTART | DMA2D | DI_EN);
+	ppi->ppi_control = params->ppi_control & ~PORT_EN;
+	switch (info->type) {
+	case PPI_TYPE_PPI:
+	{
+		struct bfin_ppi_regs *reg = info->base;
+
+		if (params->ppi_control & DMA32)
+			dma32 = 1;
+
+		bfin_write16(&reg->control, ppi->ppi_control);
+		bfin_write16(&reg->count, bytes_per_line - 1);
+		bfin_write16(&reg->frame, lines_per_frame);
+		break;
+	}
+	case PPI_TYPE_EPPI:
+	{
+		struct bfin_eppi_regs *reg = info->base;
+
+		if ((params->ppi_control & PACK_EN)
+			|| (params->ppi_control & 0x38000) > DLEN_16)
+			dma32 = 1;
+
+		bfin_write32(&reg->control, ppi->ppi_control);
+		bfin_write16(&reg->line, bytes_per_line + params->blank_clocks);
+		bfin_write16(&reg->frame, lines_per_frame);
+		bfin_write16(&reg->hdelay, 0);
+		bfin_write16(&reg->vdelay, 0);
+		bfin_write16(&reg->hcount, bytes_per_line);
+		bfin_write16(&reg->vcount, lines_per_frame);
+		break;
+	}
+	default:
+		return -EINVAL;
+	}
+
+	if (dma32) {
+		dma_config |= WDSIZE_32;
+		set_dma_x_count(info->dma_ch, bytes_per_line >> 2);
+		set_dma_x_modify(info->dma_ch, 4);
+		set_dma_y_modify(info->dma_ch, 4);
+	} else {
+		dma_config |= WDSIZE_16;
+		set_dma_x_count(info->dma_ch, bytes_per_line >> 1);
+		set_dma_x_modify(info->dma_ch, 2);
+		set_dma_y_modify(info->dma_ch, 2);
+	}
+	set_dma_y_count(info->dma_ch, lines_per_frame);
+	set_dma_config(info->dma_ch, dma_config);
+
+	SSYNC();
+	return 0;
+}
+
+static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr)
+{
+	set_dma_start_addr(ppi->info->dma_ch, addr);
+}
+
+struct ppi_if *ppi_create_instance(const struct ppi_info *info)
+{
+	struct ppi_if *ppi;
+
+	if (!info || !info->pin_req)
+		return NULL;
+
+	if (peripheral_request_list(info->pin_req, KBUILD_MODNAME)) {
+		pr_err("request peripheral failed\n");
+		return NULL;
+	}
+
+	ppi = kzalloc(sizeof(*ppi), GFP_KERNEL);
+	if (!ppi) {
+		peripheral_free_list(info->pin_req);
+		pr_err("unable to allocate memory for ppi handle\n");
+		return NULL;
+	}
+	ppi->ops = &ppi_ops;
+	ppi->info = info;
+
+	pr_info("ppi probe success\n");
+	return ppi;
+}
+
+void ppi_delete_instance(struct ppi_if *ppi)
+{
+	peripheral_free_list(ppi->info->pin_req);
+	kfree(ppi);
+}
diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c
new file mode 100644
index 0000000..6908514
--- /dev/null
+++ b/drivers/media/platform/coda.c
@@ -0,0 +1,1849 @@
+/*
+ * Coda multi-standard codec IP
+ *
+ * Copyright (C) 2012 Vista Silicon S.L.
+ *    Javier Martin, <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/of.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "coda.h"
+
+#define CODA_NAME		"coda"
+
+#define CODA_MAX_INSTANCES	4
+
+#define CODA_FMO_BUF_SIZE	32
+#define CODADX6_WORK_BUF_SIZE	(288 * 1024 + CODA_FMO_BUF_SIZE * 8 * 1024)
+#define CODA7_WORK_BUF_SIZE	(512 * 1024 + CODA_FMO_BUF_SIZE * 8 * 1024)
+#define CODA_PARA_BUF_SIZE	(10 * 1024)
+#define CODA_ISRAM_SIZE	(2048 * 2)
+
+#define CODA_OUTPUT_BUFS	4
+#define CODA_CAPTURE_BUFS	2
+
+#define MAX_W		720
+#define MAX_H		576
+#define CODA_MAX_FRAME_SIZE	0x90000
+#define FMO_SLICE_SAVE_BUF_SIZE         (32)
+#define CODA_DEFAULT_GAMMA		4096
+
+#define MIN_W 176
+#define MIN_H 144
+#define MAX_W 720
+#define MAX_H 576
+
+#define S_ALIGN		1 /* multiple of 2 */
+#define W_ALIGN		1 /* multiple of 2 */
+#define H_ALIGN		1 /* multiple of 2 */
+
+#define fh_to_ctx(__fh)	container_of(__fh, struct coda_ctx, fh)
+
+static int coda_debug;
+module_param(coda_debug, int, 0);
+MODULE_PARM_DESC(coda_debug, "Debug level (0-1)");
+
+enum {
+	V4L2_M2M_SRC = 0,
+	V4L2_M2M_DST = 1,
+};
+
+enum coda_fmt_type {
+	CODA_FMT_ENC,
+	CODA_FMT_RAW,
+};
+
+enum coda_inst_type {
+	CODA_INST_ENCODER,
+	CODA_INST_DECODER,
+};
+
+enum coda_product {
+	CODA_DX6 = 0xf001,
+};
+
+struct coda_fmt {
+	char *name;
+	u32 fourcc;
+	enum coda_fmt_type type;
+};
+
+struct coda_devtype {
+	char			*firmware;
+	enum coda_product	product;
+	struct coda_fmt		*formats;
+	unsigned int		num_formats;
+	size_t			workbuf_size;
+};
+
+/* Per-queue, driver-specific private data */
+struct coda_q_data {
+	unsigned int		width;
+	unsigned int		height;
+	unsigned int		sizeimage;
+	struct coda_fmt	*fmt;
+};
+
+struct coda_aux_buf {
+	void			*vaddr;
+	dma_addr_t		paddr;
+	u32			size;
+};
+
+struct coda_dev {
+	struct v4l2_device	v4l2_dev;
+	struct video_device	vfd;
+	struct platform_device	*plat_dev;
+	const struct coda_devtype *devtype;
+
+	void __iomem		*regs_base;
+	struct clk		*clk_per;
+	struct clk		*clk_ahb;
+
+	struct coda_aux_buf	codebuf;
+	struct coda_aux_buf	workbuf;
+
+	spinlock_t		irqlock;
+	struct mutex		dev_mutex;
+	struct v4l2_m2m_dev	*m2m_dev;
+	struct vb2_alloc_ctx	*alloc_ctx;
+	int			instances;
+};
+
+struct coda_params {
+	u8			h264_intra_qp;
+	u8			h264_inter_qp;
+	u8			mpeg4_intra_qp;
+	u8			mpeg4_inter_qp;
+	u8			gop_size;
+	int			codec_mode;
+	enum v4l2_mpeg_video_multi_slice_mode slice_mode;
+	u32			framerate;
+	u16			bitrate;
+	u32			slice_max_mb;
+};
+
+struct coda_ctx {
+	struct coda_dev			*dev;
+	int				aborting;
+	int				rawstreamon;
+	int				compstreamon;
+	u32				isequence;
+	struct coda_q_data		q_data[2];
+	enum coda_inst_type		inst_type;
+	enum v4l2_colorspace		colorspace;
+	struct coda_params		params;
+	struct v4l2_m2m_ctx		*m2m_ctx;
+	struct v4l2_ctrl_handler	ctrls;
+	struct v4l2_fh			fh;
+	struct vb2_buffer		*reference;
+	int				gopcounter;
+	char				vpu_header[3][64];
+	int				vpu_header_size[3];
+	struct coda_aux_buf		parabuf;
+	int				idx;
+};
+
+static inline void coda_write(struct coda_dev *dev, u32 data, u32 reg)
+{
+	v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+		 "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
+	writel(data, dev->regs_base + reg);
+}
+
+static inline unsigned int coda_read(struct coda_dev *dev, u32 reg)
+{
+	u32 data;
+	data = readl(dev->regs_base + reg);
+	v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+		 "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
+	return data;
+}
+
+static inline unsigned long coda_isbusy(struct coda_dev *dev)
+{
+	return coda_read(dev, CODA_REG_BIT_BUSY);
+}
+
+static inline int coda_is_initialized(struct coda_dev *dev)
+{
+	return (coda_read(dev, CODA_REG_BIT_CUR_PC) != 0);
+}
+
+static int coda_wait_timeout(struct coda_dev *dev)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+	while (coda_isbusy(dev)) {
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+static void coda_command_async(struct coda_ctx *ctx, int cmd)
+{
+	struct coda_dev *dev = ctx->dev;
+	coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
+
+	coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX);
+	coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD);
+	coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND);
+}
+
+static int coda_command_sync(struct coda_ctx *ctx, int cmd)
+{
+	struct coda_dev *dev = ctx->dev;
+
+	coda_command_async(ctx, cmd);
+	return coda_wait_timeout(dev);
+}
+
+static struct coda_q_data *get_q_data(struct coda_ctx *ctx,
+					 enum v4l2_buf_type type)
+{
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		return &(ctx->q_data[V4L2_M2M_SRC]);
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return &(ctx->q_data[V4L2_M2M_DST]);
+	default:
+		BUG();
+	}
+	return NULL;
+}
+
+/*
+ * Add one array of supported formats for each version of Coda:
+ *  i.MX27 -> codadx6
+ *  i.MX51 -> coda7
+ *  i.MX6  -> coda960
+ */
+static struct coda_fmt codadx6_formats[] = {
+	{
+		.name = "YUV 4:2:0 Planar",
+		.fourcc = V4L2_PIX_FMT_YUV420,
+		.type = CODA_FMT_RAW,
+	},
+	{
+		.name = "H264 Encoded Stream",
+		.fourcc = V4L2_PIX_FMT_H264,
+		.type = CODA_FMT_ENC,
+	},
+	{
+		.name = "MPEG4 Encoded Stream",
+		.fourcc = V4L2_PIX_FMT_MPEG4,
+		.type = CODA_FMT_ENC,
+	},
+};
+
+static struct coda_fmt *find_format(struct coda_dev *dev, struct v4l2_format *f)
+{
+	struct coda_fmt *formats = dev->devtype->formats;
+	int num_formats = dev->devtype->num_formats;
+	unsigned int k;
+
+	for (k = 0; k < num_formats; k++) {
+		if (formats[k].fourcc == f->fmt.pix.pixelformat)
+			break;
+	}
+
+	if (k == num_formats)
+		return NULL;
+
+	return &formats[k];
+}
+
+/*
+ * V4L2 ioctl() operations.
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	strlcpy(cap->driver, CODA_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, CODA_NAME, sizeof(cap->card));
+	strlcpy(cap->bus_info, CODA_NAME, sizeof(cap->bus_info));
+	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
+				| V4L2_CAP_STREAMING;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+	return 0;
+}
+
+static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
+			enum coda_fmt_type type)
+{
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+	struct coda_dev *dev = ctx->dev;
+	struct coda_fmt *formats = dev->devtype->formats;
+	struct coda_fmt *fmt;
+	int num_formats = dev->devtype->num_formats;
+	int i, num = 0;
+
+	for (i = 0; i < num_formats; i++) {
+		if (formats[i].type == type) {
+			if (num == f->index)
+				break;
+			++num;
+		}
+	}
+
+	if (i < num_formats) {
+		fmt = &formats[i];
+		strlcpy(f->description, fmt->name, sizeof(f->description));
+		f->pixelformat = fmt->fourcc;
+		return 0;
+	}
+
+	/* Format not found */
+	return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	return enum_fmt(priv, f, CODA_FMT_ENC);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	return enum_fmt(priv, f, CODA_FMT_RAW);
+}
+
+static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+	struct vb2_queue *vq;
+	struct coda_q_data *q_data;
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, f->type);
+
+	f->fmt.pix.field	= V4L2_FIELD_NONE;
+	f->fmt.pix.pixelformat	= q_data->fmt->fourcc;
+	f->fmt.pix.width	= q_data->width;
+	f->fmt.pix.height	= q_data->height;
+	if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+		f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 2);
+	else /* encoded formats h.264/mpeg4 */
+		f->fmt.pix.bytesperline = 0;
+
+	f->fmt.pix.sizeimage	= q_data->sizeimage;
+	f->fmt.pix.colorspace	= ctx->colorspace;
+
+	return 0;
+}
+
+static int vidioc_try_fmt(struct coda_dev *dev, struct v4l2_format *f)
+{
+	enum v4l2_field field;
+
+	field = f->fmt.pix.field;
+	if (field == V4L2_FIELD_ANY)
+		field = V4L2_FIELD_NONE;
+	else if (V4L2_FIELD_NONE != field)
+		return -EINVAL;
+
+	/* V4L2 specification suggests the driver corrects the format struct
+	 * if any of the dimensions is unsupported */
+	f->fmt.pix.field = field;
+
+	if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
+		v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W,
+				      W_ALIGN, &f->fmt.pix.height,
+				      MIN_H, MAX_H, H_ALIGN, S_ALIGN);
+		f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 2);
+		f->fmt.pix.sizeimage = f->fmt.pix.height *
+					f->fmt.pix.bytesperline;
+	} else { /*encoded formats h.264/mpeg4 */
+		f->fmt.pix.bytesperline = 0;
+		f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE;
+	}
+
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	int ret;
+	struct coda_fmt *fmt;
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+
+	fmt = find_format(ctx->dev, f);
+	/*
+	 * Since decoding support is not implemented yet do not allow
+	 * CODA_FMT_RAW formats in the capture interface.
+	 */
+	if (!fmt || !(fmt->type == CODA_FMT_ENC))
+		f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
+
+	f->fmt.pix.colorspace = ctx->colorspace;
+
+	ret = vidioc_try_fmt(ctx->dev, f);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+	struct coda_fmt *fmt;
+	int ret;
+
+	fmt = find_format(ctx->dev, f);
+	/*
+	 * Since decoding support is not implemented yet do not allow
+	 * CODA_FMT formats in the capture interface.
+	 */
+	if (!fmt || !(fmt->type == CODA_FMT_RAW))
+		f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+
+	if (!f->fmt.pix.colorspace)
+		f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+
+	ret = vidioc_try_fmt(ctx->dev, f);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int vidioc_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
+{
+	struct coda_q_data *q_data;
+	struct vb2_queue *vq;
+	int ret;
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, f->type);
+	if (!q_data)
+		return -EINVAL;
+
+	if (vb2_is_busy(vq)) {
+		v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
+		return -EBUSY;
+	}
+
+	ret = vidioc_try_fmt(ctx->dev, f);
+	if (ret)
+		return ret;
+
+	q_data->fmt = find_format(ctx->dev, f);
+	q_data->width = f->fmt.pix.width;
+	q_data->height = f->fmt.pix.height;
+	if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420) {
+		q_data->sizeimage = q_data->width * q_data->height * 3 / 2;
+	} else { /* encoded format h.264/mpeg-4 */
+		q_data->sizeimage = CODA_MAX_FRAME_SIZE;
+	}
+
+	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+		"Setting format for type %d, wxh: %dx%d, fmt: %d\n",
+		f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
+
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	int ret;
+
+	ret = vidioc_try_fmt_vid_cap(file, priv, f);
+	if (ret)
+		return ret;
+
+	return vidioc_s_fmt(fh_to_ctx(priv), f);
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+	int ret;
+
+	ret = vidioc_try_fmt_vid_out(file, priv, f);
+	if (ret)
+		return ret;
+
+	ret = vidioc_s_fmt(fh_to_ctx(priv), f);
+	if (ret)
+		ctx->colorspace = f->fmt.pix.colorspace;
+
+	return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *reqbufs)
+{
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+
+	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+			   struct v4l2_buffer *buf)
+{
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+
+	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+
+	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+
+	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type type)
+{
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+
+	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type type)
+{
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+
+	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static const struct v4l2_ioctl_ops coda_ioctl_ops = {
+	.vidioc_querycap	= vidioc_querycap,
+
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt,
+	.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,
+
+	.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out	= vidioc_g_fmt,
+	.vidioc_try_fmt_vid_out	= vidioc_try_fmt_vid_out,
+	.vidioc_s_fmt_vid_out	= vidioc_s_fmt_vid_out,
+
+	.vidioc_reqbufs		= vidioc_reqbufs,
+	.vidioc_querybuf	= vidioc_querybuf,
+
+	.vidioc_qbuf		= vidioc_qbuf,
+	.vidioc_dqbuf		= vidioc_dqbuf,
+
+	.vidioc_streamon	= vidioc_streamon,
+	.vidioc_streamoff	= vidioc_streamoff,
+};
+
+/*
+ * Mem-to-mem operations.
+ */
+static void coda_device_run(void *m2m_priv)
+{
+	struct coda_ctx *ctx = m2m_priv;
+	struct coda_q_data *q_data_src, *q_data_dst;
+	struct vb2_buffer *src_buf, *dst_buf;
+	struct coda_dev *dev = ctx->dev;
+	int force_ipicture;
+	int quant_param = 0;
+	u32 picture_y, picture_cb, picture_cr;
+	u32 pic_stream_buffer_addr, pic_stream_buffer_size;
+	u32 dst_fourcc;
+
+	src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	dst_fourcc = q_data_dst->fmt->fourcc;
+
+	src_buf->v4l2_buf.sequence = ctx->isequence;
+	dst_buf->v4l2_buf.sequence = ctx->isequence;
+	ctx->isequence++;
+
+	/*
+	 * Workaround coda firmware BUG that only marks the first
+	 * frame as IDR. This is a problem for some decoders that can't
+	 * recover when a frame is lost.
+	 */
+	if (src_buf->v4l2_buf.sequence % ctx->params.gop_size) {
+		src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+		src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
+	} else {
+		src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+		src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
+	}
+
+	/*
+	 * Copy headers at the beginning of the first frame for H.264 only.
+	 * In MPEG4 they are already copied by the coda.
+	 */
+	if (src_buf->v4l2_buf.sequence == 0) {
+		pic_stream_buffer_addr =
+			vb2_dma_contig_plane_dma_addr(dst_buf, 0) +
+			ctx->vpu_header_size[0] +
+			ctx->vpu_header_size[1] +
+			ctx->vpu_header_size[2];
+		pic_stream_buffer_size = CODA_MAX_FRAME_SIZE -
+			ctx->vpu_header_size[0] -
+			ctx->vpu_header_size[1] -
+			ctx->vpu_header_size[2];
+		memcpy(vb2_plane_vaddr(dst_buf, 0),
+		       &ctx->vpu_header[0][0], ctx->vpu_header_size[0]);
+		memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0],
+		       &ctx->vpu_header[1][0], ctx->vpu_header_size[1]);
+		memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0] +
+			ctx->vpu_header_size[1], &ctx->vpu_header[2][0],
+			ctx->vpu_header_size[2]);
+	} else {
+		pic_stream_buffer_addr =
+			vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+		pic_stream_buffer_size = CODA_MAX_FRAME_SIZE;
+	}
+
+	if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) {
+		force_ipicture = 1;
+		switch (dst_fourcc) {
+		case V4L2_PIX_FMT_H264:
+			quant_param = ctx->params.h264_intra_qp;
+			break;
+		case V4L2_PIX_FMT_MPEG4:
+			quant_param = ctx->params.mpeg4_intra_qp;
+			break;
+		default:
+			v4l2_warn(&ctx->dev->v4l2_dev,
+				"cannot set intra qp, fmt not supported\n");
+			break;
+		}
+	} else {
+		force_ipicture = 0;
+		switch (dst_fourcc) {
+		case V4L2_PIX_FMT_H264:
+			quant_param = ctx->params.h264_inter_qp;
+			break;
+		case V4L2_PIX_FMT_MPEG4:
+			quant_param = ctx->params.mpeg4_inter_qp;
+			break;
+		default:
+			v4l2_warn(&ctx->dev->v4l2_dev,
+				"cannot set inter qp, fmt not supported\n");
+			break;
+		}
+	}
+
+	/* submit */
+	coda_write(dev, 0, CODA_CMD_ENC_PIC_ROT_MODE);
+	coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS);
+
+
+	picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+	picture_cb = picture_y + q_data_src->width * q_data_src->height;
+	picture_cr = picture_cb + q_data_src->width / 2 *
+			q_data_src->height / 2;
+
+	coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y);
+	coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB);
+	coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR);
+	coda_write(dev, force_ipicture << 1 & 0x2,
+		   CODA_CMD_ENC_PIC_OPTION);
+
+	coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START);
+	coda_write(dev, pic_stream_buffer_size / 1024,
+		   CODA_CMD_ENC_PIC_BB_SIZE);
+	coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
+}
+
+static int coda_job_ready(void *m2m_priv)
+{
+	struct coda_ctx *ctx = m2m_priv;
+
+	/*
+	 * For both 'P' and 'key' frame cases 1 picture
+	 * and 1 frame are needed.
+	 */
+	if (!v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) ||
+		!v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)) {
+		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			 "not ready: not enough video buffers.\n");
+		return 0;
+	}
+
+	/* For P frames a reference picture is needed too */
+	if ((ctx->gopcounter != (ctx->params.gop_size - 1)) &&
+	   !ctx->reference) {
+		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			 "not ready: reference picture not available.\n");
+		return 0;
+	}
+
+	if (coda_isbusy(ctx->dev)) {
+		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			 "not ready: coda is still busy.\n");
+		return 0;
+	}
+
+	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			"job ready\n");
+	return 1;
+}
+
+static void coda_job_abort(void *priv)
+{
+	struct coda_ctx *ctx = priv;
+	struct coda_dev *dev = ctx->dev;
+
+	ctx->aborting = 1;
+
+	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+		 "Aborting task\n");
+
+	v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx);
+}
+
+static void coda_lock(void *m2m_priv)
+{
+	struct coda_ctx *ctx = m2m_priv;
+	struct coda_dev *pcdev = ctx->dev;
+	mutex_lock(&pcdev->dev_mutex);
+}
+
+static void coda_unlock(void *m2m_priv)
+{
+	struct coda_ctx *ctx = m2m_priv;
+	struct coda_dev *pcdev = ctx->dev;
+	mutex_unlock(&pcdev->dev_mutex);
+}
+
+static struct v4l2_m2m_ops coda_m2m_ops = {
+	.device_run	= coda_device_run,
+	.job_ready	= coda_job_ready,
+	.job_abort	= coda_job_abort,
+	.lock		= coda_lock,
+	.unlock		= coda_unlock,
+};
+
+static void set_default_params(struct coda_ctx *ctx)
+{
+	struct coda_dev *dev = ctx->dev;
+
+	ctx->params.codec_mode = CODA_MODE_INVALID;
+	ctx->colorspace = V4L2_COLORSPACE_REC709;
+	ctx->params.framerate = 30;
+	ctx->reference = NULL;
+	ctx->aborting = 0;
+
+	/* Default formats for output and input queues */
+	ctx->q_data[V4L2_M2M_SRC].fmt = &dev->devtype->formats[0];
+	ctx->q_data[V4L2_M2M_DST].fmt = &dev->devtype->formats[1];
+	ctx->q_data[V4L2_M2M_SRC].width = MAX_W;
+	ctx->q_data[V4L2_M2M_SRC].height = MAX_H;
+	ctx->q_data[V4L2_M2M_SRC].sizeimage = (MAX_W * MAX_H * 3) / 2;
+	ctx->q_data[V4L2_M2M_DST].width = MAX_W;
+	ctx->q_data[V4L2_M2M_DST].height = MAX_H;
+	ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
+}
+
+/*
+ * Queue operations
+ */
+static int coda_queue_setup(struct vb2_queue *vq,
+				const struct v4l2_format *fmt,
+				unsigned int *nbuffers, unsigned int *nplanes,
+				unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct coda_ctx *ctx = vb2_get_drv_priv(vq);
+	unsigned int size;
+
+	if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		*nbuffers = CODA_OUTPUT_BUFS;
+		if (fmt)
+			size = fmt->fmt.pix.width *
+				fmt->fmt.pix.height * 3 / 2;
+		else
+			size = MAX_W *
+				MAX_H * 3 / 2;
+	} else {
+		*nbuffers = CODA_CAPTURE_BUFS;
+		size = CODA_MAX_FRAME_SIZE;
+	}
+
+	*nplanes = 1;
+	sizes[0] = size;
+
+	alloc_ctxs[0] = ctx->dev->alloc_ctx;
+
+	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+		 "get %d buffer(s) of size %d each.\n", *nbuffers, size);
+
+	return 0;
+}
+
+static int coda_buf_prepare(struct vb2_buffer *vb)
+{
+	struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct coda_q_data *q_data;
+
+	q_data = get_q_data(ctx, vb->vb2_queue->type);
+
+	if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
+		v4l2_warn(&ctx->dev->v4l2_dev,
+			  "%s data will not fit into plane (%lu < %lu)\n",
+			  __func__, vb2_plane_size(vb, 0),
+			  (long)q_data->sizeimage);
+		return -EINVAL;
+	}
+
+	vb2_set_plane_payload(vb, 0, q_data->sizeimage);
+
+	return 0;
+}
+
+static void coda_buf_queue(struct vb2_buffer *vb)
+{
+	struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static void coda_wait_prepare(struct vb2_queue *q)
+{
+	struct coda_ctx *ctx = vb2_get_drv_priv(q);
+	coda_unlock(ctx);
+}
+
+static void coda_wait_finish(struct vb2_queue *q)
+{
+	struct coda_ctx *ctx = vb2_get_drv_priv(q);
+	coda_lock(ctx);
+}
+
+static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct coda_ctx *ctx = vb2_get_drv_priv(q);
+	struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev;
+	u32 bitstream_buf, bitstream_size;
+	struct coda_dev *dev = ctx->dev;
+	struct coda_q_data *q_data_src, *q_data_dst;
+	u32 dst_fourcc;
+	struct vb2_buffer *buf;
+	struct vb2_queue *src_vq;
+	u32 value;
+	int i = 0;
+
+	if (count < 1)
+		return -EINVAL;
+
+	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		ctx->rawstreamon = 1;
+	else
+		ctx->compstreamon = 1;
+
+	/* Don't start the coda unless both queues are on */
+	if (!(ctx->rawstreamon & ctx->compstreamon))
+		return 0;
+
+	ctx->gopcounter = ctx->params.gop_size - 1;
+
+	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+	bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
+	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	bitstream_size = q_data_dst->sizeimage;
+	dst_fourcc = q_data_dst->fmt->fourcc;
+
+	/* Find out whether coda must encode or decode */
+	if (q_data_src->fmt->type == CODA_FMT_RAW &&
+	    q_data_dst->fmt->type == CODA_FMT_ENC) {
+		ctx->inst_type = CODA_INST_ENCODER;
+	} else if (q_data_src->fmt->type == CODA_FMT_ENC &&
+		   q_data_dst->fmt->type == CODA_FMT_RAW) {
+		ctx->inst_type = CODA_INST_DECODER;
+		v4l2_err(v4l2_dev, "decoding not supported.\n");
+		return -EINVAL;
+	} else {
+		v4l2_err(v4l2_dev, "couldn't tell instance type.\n");
+		return -EINVAL;
+	}
+
+	if (!coda_is_initialized(dev)) {
+		v4l2_err(v4l2_dev, "coda is not initialized.\n");
+		return -EFAULT;
+	}
+	coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
+	coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->idx));
+	coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->idx));
+	switch (dev->devtype->product) {
+	case CODA_DX6:
+		coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN |
+			CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
+		break;
+	default:
+		coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN |
+			CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
+	}
+
+	/* Configure the coda */
+	coda_write(dev, 0xffff4c00, CODA_REG_BIT_SEARCH_RAM_BASE_ADDR);
+
+	/* Could set rotation here if needed */
+	switch (dev->devtype->product) {
+	case CODA_DX6:
+		value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET;
+		break;
+	default:
+		value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
+	}
+	value |= (q_data_src->height & CODA_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
+	coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE);
+	coda_write(dev, ctx->params.framerate,
+		   CODA_CMD_ENC_SEQ_SRC_F_RATE);
+
+	switch (dst_fourcc) {
+	case V4L2_PIX_FMT_MPEG4:
+		if (dev->devtype->product == CODA_DX6)
+			ctx->params.codec_mode = CODADX6_MODE_ENCODE_MP4;
+		else
+			ctx->params.codec_mode = CODA7_MODE_ENCODE_MP4;
+
+		coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD);
+		coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA);
+		break;
+	case V4L2_PIX_FMT_H264:
+		if (dev->devtype->product == CODA_DX6)
+			ctx->params.codec_mode = CODADX6_MODE_ENCODE_H264;
+		else
+			ctx->params.codec_mode = CODA7_MODE_ENCODE_H264;
+
+		coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD);
+		coda_write(dev, 0, CODA_CMD_ENC_SEQ_264_PARA);
+		break;
+	default:
+		v4l2_err(v4l2_dev,
+			 "dst format (0x%08x) invalid.\n", dst_fourcc);
+		return -EINVAL;
+	}
+
+	value  = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET;
+	value |= (1 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET;
+	if (ctx->params.slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB)
+		value |=  1 & CODA_SLICING_MODE_MASK;
+	coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE);
+	value  =  ctx->params.gop_size & CODA_GOP_SIZE_MASK;
+	coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE);
+
+	if (ctx->params.bitrate) {
+		/* Rate control enabled */
+		value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET;
+		value |=  1 & CODA_RATECONTROL_ENABLE_MASK;
+	} else {
+		value = 0;
+	}
+	coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA);
+
+	coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_BUF_SIZE);
+	coda_write(dev, 0, CODA_CMD_ENC_SEQ_INTRA_REFRESH);
+
+	coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START);
+	coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE);
+
+	/* set default gamma */
+	value = (CODA_DEFAULT_GAMMA & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET;
+	coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_GAMMA);
+
+	value  = (CODA_DEFAULT_GAMMA > 0) << CODA_OPTION_GAMMA_OFFSET;
+	value |= (0 & CODA_OPTION_SLICEREPORT_MASK) << CODA_OPTION_SLICEREPORT_OFFSET;
+	coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION);
+
+	if (dst_fourcc == V4L2_PIX_FMT_H264) {
+		value  = (FMO_SLICE_SAVE_BUF_SIZE << 7);
+		value |= (0 & CODA_FMOPARAM_TYPE_MASK) << CODA_FMOPARAM_TYPE_OFFSET;
+		value |=  0 & CODA_FMOPARAM_SLICENUM_MASK;
+		coda_write(dev, value, CODA_CMD_ENC_SEQ_FMO);
+	}
+
+	if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) {
+		v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0)
+		return -EFAULT;
+
+	/*
+	 * Walk the src buffer list and let the codec know the
+	 * addresses of the pictures.
+	 */
+	src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	for (i = 0; i < src_vq->num_buffers; i++) {
+		u32 *p;
+
+		buf = src_vq->bufs[i];
+		p = ctx->parabuf.vaddr;
+
+		p[i * 3] = vb2_dma_contig_plane_dma_addr(buf, 0);
+		p[i * 3 + 1] = p[i * 3] + q_data_src->width *
+				q_data_src->height;
+		p[i * 3 + 2] = p[i * 3 + 1] + q_data_src->width / 2 *
+				q_data_src->height / 2;
+	}
+
+	coda_write(dev, src_vq->num_buffers, CODA_CMD_SET_FRAME_BUF_NUM);
+	coda_write(dev, q_data_src->width, CODA_CMD_SET_FRAME_BUF_STRIDE);
+	if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) {
+		v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	/* Save stream headers */
+	buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+	switch (dst_fourcc) {
+	case V4L2_PIX_FMT_H264:
+		/*
+		 * Get SPS in the first frame and copy it to an
+		 * intermediate buffer.
+		 */
+		coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
+		coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
+		coda_write(dev, CODA_HEADER_H264_SPS, CODA_CMD_ENC_HEADER_CODE);
+		if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
+			v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
+			return -ETIMEDOUT;
+		}
+		ctx->vpu_header_size[0] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+				coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+		memcpy(&ctx->vpu_header[0][0], vb2_plane_vaddr(buf, 0),
+		       ctx->vpu_header_size[0]);
+
+		/*
+		 * Get PPS in the first frame and copy it to an
+		 * intermediate buffer.
+		 */
+		coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
+		coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
+		coda_write(dev, CODA_HEADER_H264_PPS, CODA_CMD_ENC_HEADER_CODE);
+		if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
+			v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
+			return -ETIMEDOUT;
+		}
+		ctx->vpu_header_size[1] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+				coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+		memcpy(&ctx->vpu_header[1][0], vb2_plane_vaddr(buf, 0),
+		       ctx->vpu_header_size[1]);
+		ctx->vpu_header_size[2] = 0;
+		break;
+	case V4L2_PIX_FMT_MPEG4:
+		/*
+		 * Get VOS in the first frame and copy it to an
+		 * intermediate buffer
+		 */
+		coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
+		coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
+		coda_write(dev, CODA_HEADER_MP4V_VOS, CODA_CMD_ENC_HEADER_CODE);
+		if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
+			v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
+			return -ETIMEDOUT;
+		}
+		ctx->vpu_header_size[0] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+				coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+		memcpy(&ctx->vpu_header[0][0], vb2_plane_vaddr(buf, 0),
+		       ctx->vpu_header_size[0]);
+
+		coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
+		coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
+		coda_write(dev, CODA_HEADER_MP4V_VIS, CODA_CMD_ENC_HEADER_CODE);
+		if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
+			v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER failed\n");
+			return -ETIMEDOUT;
+		}
+		ctx->vpu_header_size[1] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+				coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+		memcpy(&ctx->vpu_header[1][0], vb2_plane_vaddr(buf, 0),
+		       ctx->vpu_header_size[1]);
+
+		coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
+		coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
+		coda_write(dev, CODA_HEADER_MP4V_VOL, CODA_CMD_ENC_HEADER_CODE);
+		if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
+			v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER failed\n");
+			return -ETIMEDOUT;
+		}
+		ctx->vpu_header_size[2] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+				coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+		memcpy(&ctx->vpu_header[2][0], vb2_plane_vaddr(buf, 0),
+		       ctx->vpu_header_size[2]);
+		break;
+	default:
+		/* No more formats need to save headers at the moment */
+		break;
+	}
+
+	return 0;
+}
+
+static int coda_stop_streaming(struct vb2_queue *q)
+{
+	struct coda_ctx *ctx = vb2_get_drv_priv(q);
+
+	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			 "%s: output\n", __func__);
+		ctx->rawstreamon = 0;
+	} else {
+		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			 "%s: capture\n", __func__);
+		ctx->compstreamon = 0;
+	}
+
+	if (!ctx->rawstreamon && !ctx->compstreamon) {
+		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			 "%s: sent command 'SEQ_END' to coda\n", __func__);
+		if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
+			v4l2_err(&ctx->dev->v4l2_dev,
+				 "CODA_COMMAND_SEQ_END failed\n");
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+static struct vb2_ops coda_qops = {
+	.queue_setup		= coda_queue_setup,
+	.buf_prepare		= coda_buf_prepare,
+	.buf_queue		= coda_buf_queue,
+	.wait_prepare		= coda_wait_prepare,
+	.wait_finish		= coda_wait_finish,
+	.start_streaming	= coda_start_streaming,
+	.stop_streaming		= coda_stop_streaming,
+};
+
+static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct coda_ctx *ctx =
+			container_of(ctrl->handler, struct coda_ctx, ctrls);
+
+	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+		 "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		ctx->params.bitrate = ctrl->val / 1000;
+		break;
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+		ctx->params.gop_size = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+		ctx->params.h264_intra_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+		ctx->params.h264_inter_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+		ctx->params.mpeg4_intra_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+		ctx->params.mpeg4_inter_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+		ctx->params.slice_mode = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+		ctx->params.slice_max_mb = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+		break;
+	default:
+		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			"Invalid control, id=%d, val=%d\n",
+			ctrl->id, ctrl->val);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct v4l2_ctrl_ops coda_ctrl_ops = {
+	.s_ctrl = coda_s_ctrl,
+};
+
+static int coda_ctrls_setup(struct coda_ctx *ctx)
+{
+	v4l2_ctrl_handler_init(&ctx->ctrls, 9);
+
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 1, 51, 1, 25);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 1, 51, 1, 25);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2);
+	v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+		V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB, 0,
+		V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1);
+	v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+		V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
+		(1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE),
+		V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME);
+
+	if (ctx->ctrls.error) {
+		v4l2_err(&ctx->dev->v4l2_dev, "control initialization error (%d)",
+			ctx->ctrls.error);
+		return -EINVAL;
+	}
+
+	return v4l2_ctrl_handler_setup(&ctx->ctrls);
+}
+
+static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
+		      struct vb2_queue *dst_vq)
+{
+	struct coda_ctx *ctx = priv;
+	int ret;
+
+	memset(src_vq, 0, sizeof(*src_vq));
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->io_modes = VB2_MMAP;
+	src_vq->drv_priv = ctx;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	src_vq->ops = &coda_qops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	memset(dst_vq, 0, sizeof(*dst_vq));
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->io_modes = VB2_MMAP;
+	dst_vq->drv_priv = ctx;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->ops = &coda_qops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+	return vb2_queue_init(dst_vq);
+}
+
+static int coda_open(struct file *file)
+{
+	struct coda_dev *dev = video_drvdata(file);
+	struct coda_ctx *ctx = NULL;
+	int ret = 0;
+
+	if (dev->instances >= CODA_MAX_INSTANCES)
+		return -EBUSY;
+
+	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	v4l2_fh_init(&ctx->fh, video_devdata(file));
+	file->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh);
+	ctx->dev = dev;
+
+	set_default_params(ctx);
+	ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
+					 &coda_queue_init);
+	if (IS_ERR(ctx->m2m_ctx)) {
+		int ret = PTR_ERR(ctx->m2m_ctx);
+
+		v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n",
+			 __func__, ret);
+		goto err;
+	}
+	ret = coda_ctrls_setup(ctx);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "failed to setup coda controls\n");
+		goto err;
+	}
+
+	ctx->fh.ctrl_handler = &ctx->ctrls;
+
+	ctx->parabuf.vaddr = dma_alloc_coherent(&dev->plat_dev->dev,
+			CODA_PARA_BUF_SIZE, &ctx->parabuf.paddr, GFP_KERNEL);
+	if (!ctx->parabuf.vaddr) {
+		v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	coda_lock(ctx);
+	ctx->idx = dev->instances++;
+	coda_unlock(ctx);
+
+	clk_prepare_enable(dev->clk_per);
+	clk_prepare_enable(dev->clk_ahb);
+
+	v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Created instance %d (%p)\n",
+		 ctx->idx, ctx);
+
+	return 0;
+
+err:
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+	return ret;
+}
+
+static int coda_release(struct file *file)
+{
+	struct coda_dev *dev = video_drvdata(file);
+	struct coda_ctx *ctx = fh_to_ctx(file->private_data);
+
+	v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n",
+		 ctx);
+
+	coda_lock(ctx);
+	dev->instances--;
+	coda_unlock(ctx);
+
+	dma_free_coherent(&dev->plat_dev->dev, CODA_PARA_BUF_SIZE,
+		ctx->parabuf.vaddr, ctx->parabuf.paddr);
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+	v4l2_ctrl_handler_free(&ctx->ctrls);
+	clk_disable_unprepare(dev->clk_per);
+	clk_disable_unprepare(dev->clk_ahb);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+
+	return 0;
+}
+
+static unsigned int coda_poll(struct file *file,
+				 struct poll_table_struct *wait)
+{
+	struct coda_ctx *ctx = fh_to_ctx(file->private_data);
+	int ret;
+
+	coda_lock(ctx);
+	ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+	coda_unlock(ctx);
+	return ret;
+}
+
+static int coda_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct coda_ctx *ctx = fh_to_ctx(file->private_data);
+
+	return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations coda_fops = {
+	.owner		= THIS_MODULE,
+	.open		= coda_open,
+	.release	= coda_release,
+	.poll		= coda_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= coda_mmap,
+};
+
+static irqreturn_t coda_irq_handler(int irq, void *data)
+{
+	struct vb2_buffer *src_buf, *dst_buf, *tmp_buf;
+	struct coda_dev *dev = data;
+	u32 wr_ptr, start_ptr;
+	struct coda_ctx *ctx;
+
+	/* read status register to attend the IRQ */
+	coda_read(dev, CODA_REG_BIT_INT_STATUS);
+	coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET,
+		      CODA_REG_BIT_INT_CLEAR);
+
+	ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+	if (ctx == NULL) {
+		v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n");
+		return IRQ_HANDLED;
+	}
+
+	if (ctx->aborting) {
+		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			 "task has been aborted\n");
+		return IRQ_HANDLED;
+	}
+
+	if (coda_isbusy(ctx->dev)) {
+		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			 "coda is still busy!!!!\n");
+		return IRQ_NONE;
+	}
+
+	src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+
+	/* Get results from the coda */
+	coda_read(dev, CODA_RET_ENC_PIC_TYPE);
+	start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START);
+	wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx));
+	/* Calculate bytesused field */
+	if (dst_buf->v4l2_buf.sequence == 0) {
+		dst_buf->v4l2_planes[0].bytesused = (wr_ptr - start_ptr) +
+						ctx->vpu_header_size[0] +
+						ctx->vpu_header_size[1] +
+						ctx->vpu_header_size[2];
+	} else {
+		dst_buf->v4l2_planes[0].bytesused = (wr_ptr - start_ptr);
+	}
+
+	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n",
+		 wr_ptr - start_ptr);
+
+	coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM);
+	coda_read(dev, CODA_RET_ENC_PIC_FLAG);
+
+	if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) {
+		dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+		dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
+	} else {
+		dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+		dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
+	}
+
+	/* Free previous reference picture if available */
+	if (ctx->reference) {
+		v4l2_m2m_buf_done(ctx->reference, VB2_BUF_STATE_DONE);
+		ctx->reference = NULL;
+	}
+
+	/*
+	 * For the last frame of the gop we don't need to save
+	 * a reference picture.
+	 */
+	v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+	tmp_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+	if (ctx->gopcounter == 0)
+		v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+	else
+		ctx->reference = tmp_buf;
+
+	v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+
+	ctx->gopcounter--;
+	if (ctx->gopcounter < 0)
+		ctx->gopcounter = ctx->params.gop_size - 1;
+
+	v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+		"job finished: encoding frame (%d) (%s)\n",
+		dst_buf->v4l2_buf.sequence,
+		(dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
+		"KEYFRAME" : "PFRAME");
+
+	v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx);
+
+	return IRQ_HANDLED;
+}
+
+static u32 coda_supported_firmwares[] = {
+	CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5),
+};
+
+static bool coda_firmware_supported(u32 vernum)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++)
+		if (vernum == coda_supported_firmwares[i])
+			return true;
+	return false;
+}
+
+static char *coda_product_name(int product)
+{
+	static char buf[9];
+
+	switch (product) {
+	case CODA_DX6:
+		return "CodaDx6";
+	default:
+		snprintf(buf, sizeof(buf), "(0x%04x)", product);
+		return buf;
+	}
+}
+
+static int coda_hw_init(struct coda_dev *dev, const struct firmware *fw)
+{
+	u16 product, major, minor, release;
+	u32 data;
+	u16 *p;
+	int i;
+
+	clk_prepare_enable(dev->clk_per);
+	clk_prepare_enable(dev->clk_ahb);
+
+	/* Copy the whole firmware image to the code buffer */
+	memcpy(dev->codebuf.vaddr, fw->data, fw->size);
+	/*
+	 * Copy the first CODA_ISRAM_SIZE in the internal SRAM.
+	 * This memory seems to be big-endian here, which is weird, since
+	 * the internal ARM processor of the coda is little endian.
+	 * Data in this SRAM survives a reboot.
+	 */
+	p = (u16 *)fw->data;
+	for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++)  {
+		data = CODA_DOWN_ADDRESS_SET(i) |
+			CODA_DOWN_DATA_SET(p[i ^ 1]);
+		coda_write(dev, data, CODA_REG_BIT_CODE_DOWN);
+	}
+	release_firmware(fw);
+
+	/* Tell the BIT where to find everything it needs */
+	coda_write(dev, dev->workbuf.paddr,
+		      CODA_REG_BIT_WORK_BUF_ADDR);
+	coda_write(dev, dev->codebuf.paddr,
+		      CODA_REG_BIT_CODE_BUF_ADDR);
+	coda_write(dev, 0, CODA_REG_BIT_CODE_RUN);
+
+	/* Set default values */
+	switch (dev->devtype->product) {
+	case CODA_DX6:
+		coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL);
+		break;
+	default:
+		coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL);
+	}
+	coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL);
+	coda_write(dev, CODA_INT_INTERRUPT_ENABLE,
+		      CODA_REG_BIT_INT_ENABLE);
+
+	/* Reset VPU and start processor */
+	data = coda_read(dev, CODA_REG_BIT_CODE_RESET);
+	data |= CODA_REG_RESET_ENABLE;
+	coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
+	udelay(10);
+	data &= ~CODA_REG_RESET_ENABLE;
+	coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
+	coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
+
+	/* Load firmware */
+	coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM);
+	coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
+	coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX);
+	coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD);
+	coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND);
+	if (coda_wait_timeout(dev)) {
+		clk_disable_unprepare(dev->clk_per);
+		clk_disable_unprepare(dev->clk_ahb);
+		v4l2_err(&dev->v4l2_dev, "firmware get command error\n");
+		return -EIO;
+	}
+
+	/* Check we are compatible with the loaded firmware */
+	data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM);
+	product = CODA_FIRMWARE_PRODUCT(data);
+	major = CODA_FIRMWARE_MAJOR(data);
+	minor = CODA_FIRMWARE_MINOR(data);
+	release = CODA_FIRMWARE_RELEASE(data);
+
+	clk_disable_unprepare(dev->clk_per);
+	clk_disable_unprepare(dev->clk_ahb);
+
+	if (product != dev->devtype->product) {
+		v4l2_err(&dev->v4l2_dev, "Wrong firmware. Hw: %s, Fw: %s,"
+			 " Version: %u.%u.%u\n",
+			 coda_product_name(dev->devtype->product),
+			 coda_product_name(product), major, minor, release);
+		return -EINVAL;
+	}
+
+	v4l2_info(&dev->v4l2_dev, "Initialized %s.\n",
+		  coda_product_name(product));
+
+	if (coda_firmware_supported(data)) {
+		v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n",
+			  major, minor, release);
+	} else {
+		v4l2_warn(&dev->v4l2_dev, "Unsupported firmware version: "
+			  "%u.%u.%u\n", major, minor, release);
+	}
+
+	return 0;
+}
+
+static void coda_fw_callback(const struct firmware *fw, void *context)
+{
+	struct coda_dev *dev = context;
+	struct platform_device *pdev = dev->plat_dev;
+	int ret;
+
+	if (!fw) {
+		v4l2_err(&dev->v4l2_dev, "firmware request failed\n");
+		return;
+	}
+
+	/* allocate auxiliary per-device code buffer for the BIT processor */
+	dev->codebuf.size = fw->size;
+	dev->codebuf.vaddr = dma_alloc_coherent(&pdev->dev, fw->size,
+						    &dev->codebuf.paddr,
+						    GFP_KERNEL);
+	if (!dev->codebuf.vaddr) {
+		dev_err(&pdev->dev, "failed to allocate code buffer\n");
+		return;
+	}
+
+	ret = coda_hw_init(dev, fw);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "HW initialization failed\n");
+		return;
+	}
+
+	dev->vfd.fops	= &coda_fops,
+	dev->vfd.ioctl_ops	= &coda_ioctl_ops;
+	dev->vfd.release	= video_device_release_empty,
+	dev->vfd.lock	= &dev->dev_mutex;
+	dev->vfd.v4l2_dev	= &dev->v4l2_dev;
+	snprintf(dev->vfd.name, sizeof(dev->vfd.name), "%s", CODA_NAME);
+	video_set_drvdata(&dev->vfd, dev);
+
+	dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+	if (IS_ERR(dev->alloc_ctx)) {
+		v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n");
+		return;
+	}
+
+	dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops);
+	if (IS_ERR(dev->m2m_dev)) {
+		v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
+		goto rel_ctx;
+	}
+
+	ret = video_register_device(&dev->vfd, VFL_TYPE_GRABBER, 0);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+		goto rel_m2m;
+	}
+	v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video%d\n",
+		  dev->vfd.num);
+
+	return;
+
+rel_m2m:
+	v4l2_m2m_release(dev->m2m_dev);
+rel_ctx:
+	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+}
+
+static int coda_firmware_request(struct coda_dev *dev)
+{
+	char *fw = dev->devtype->firmware;
+
+	dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw,
+		coda_product_name(dev->devtype->product));
+
+	return request_firmware_nowait(THIS_MODULE, true,
+		fw, &dev->plat_dev->dev, GFP_KERNEL, dev, coda_fw_callback);
+}
+
+enum coda_platform {
+	CODA_IMX27,
+};
+
+static const struct coda_devtype coda_devdata[] = {
+	[CODA_IMX27] = {
+		.firmware    = "v4l-codadx6-imx27.bin",
+		.product     = CODA_DX6,
+		.formats     = codadx6_formats,
+		.num_formats = ARRAY_SIZE(codadx6_formats),
+	},
+};
+
+static struct platform_device_id coda_platform_ids[] = {
+	{ .name = "coda-imx27", .driver_data = CODA_IMX27 },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, coda_platform_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id coda_dt_ids[] = {
+	{ .compatible = "fsl,imx27-vpu", .data = &coda_platform_ids[CODA_IMX27] },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, coda_dt_ids);
+#endif
+
+static int __devinit coda_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id =
+			of_match_device(of_match_ptr(coda_dt_ids), &pdev->dev);
+	const struct platform_device_id *pdev_id;
+	struct coda_dev *dev;
+	struct resource *res;
+	int ret, irq;
+
+	dev = devm_kzalloc(&pdev->dev, sizeof *dev, GFP_KERNEL);
+	if (!dev) {
+		dev_err(&pdev->dev, "Not enough memory for %s\n",
+			CODA_NAME);
+		return -ENOMEM;
+	}
+
+	spin_lock_init(&dev->irqlock);
+
+	dev->plat_dev = pdev;
+	dev->clk_per = devm_clk_get(&pdev->dev, "per");
+	if (IS_ERR(dev->clk_per)) {
+		dev_err(&pdev->dev, "Could not get per clock\n");
+		return PTR_ERR(dev->clk_per);
+	}
+
+	dev->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
+	if (IS_ERR(dev->clk_ahb)) {
+		dev_err(&pdev->dev, "Could not get ahb clock\n");
+		return PTR_ERR(dev->clk_ahb);
+	}
+
+	/* Get  memory for physical registers */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "failed to get memory region resource\n");
+		return -ENOENT;
+	}
+
+	if (devm_request_mem_region(&pdev->dev, res->start,
+			resource_size(res), CODA_NAME) == NULL) {
+		dev_err(&pdev->dev, "failed to request memory region\n");
+		return -ENOENT;
+	}
+	dev->regs_base = devm_ioremap(&pdev->dev, res->start,
+				      resource_size(res));
+	if (!dev->regs_base) {
+		dev_err(&pdev->dev, "failed to ioremap address region\n");
+		return -ENOENT;
+	}
+
+	/* IRQ */
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "failed to get irq resource\n");
+		return -ENOENT;
+	}
+
+	if (devm_request_irq(&pdev->dev, irq, coda_irq_handler,
+		0, CODA_NAME, dev) < 0) {
+		dev_err(&pdev->dev, "failed to request irq\n");
+		return -ENOENT;
+	}
+
+	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+	if (ret)
+		return ret;
+
+	mutex_init(&dev->dev_mutex);
+
+	pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
+
+	if (of_id) {
+		dev->devtype = of_id->data;
+	} else if (pdev_id) {
+		dev->devtype = &coda_devdata[pdev_id->driver_data];
+	} else {
+		v4l2_device_unregister(&dev->v4l2_dev);
+		return -EINVAL;
+	}
+
+	/* allocate auxiliary per-device buffers for the BIT processor */
+	switch (dev->devtype->product) {
+	case CODA_DX6:
+		dev->workbuf.size = CODADX6_WORK_BUF_SIZE;
+		break;
+	default:
+		dev->workbuf.size = CODA7_WORK_BUF_SIZE;
+	}
+	dev->workbuf.vaddr = dma_alloc_coherent(&pdev->dev, dev->workbuf.size,
+						    &dev->workbuf.paddr,
+						    GFP_KERNEL);
+	if (!dev->workbuf.vaddr) {
+		dev_err(&pdev->dev, "failed to allocate work buffer\n");
+		v4l2_device_unregister(&dev->v4l2_dev);
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, dev);
+
+	return coda_firmware_request(dev);
+}
+
+static int coda_remove(struct platform_device *pdev)
+{
+	struct coda_dev *dev = platform_get_drvdata(pdev);
+
+	video_unregister_device(&dev->vfd);
+	if (dev->m2m_dev)
+		v4l2_m2m_release(dev->m2m_dev);
+	if (dev->alloc_ctx)
+		vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+	v4l2_device_unregister(&dev->v4l2_dev);
+	if (dev->codebuf.vaddr)
+		dma_free_coherent(&pdev->dev, dev->codebuf.size,
+				  &dev->codebuf.vaddr, dev->codebuf.paddr);
+	if (dev->workbuf.vaddr)
+		dma_free_coherent(&pdev->dev, dev->workbuf.size, &dev->workbuf.vaddr,
+			  dev->workbuf.paddr);
+	return 0;
+}
+
+static struct platform_driver coda_driver = {
+	.probe	= coda_probe,
+	.remove	= __devexit_p(coda_remove),
+	.driver	= {
+		.name	= CODA_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(coda_dt_ids),
+	},
+	.id_table = coda_platform_ids,
+};
+
+module_platform_driver(coda_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
+MODULE_DESCRIPTION("Coda multi-standard codec V4L2 driver");
diff --git a/drivers/media/platform/coda.h b/drivers/media/platform/coda.h
new file mode 100644
index 0000000..3fbb315
--- /dev/null
+++ b/drivers/media/platform/coda.h
@@ -0,0 +1,216 @@
+/*
+ * linux/drivers/media/platform/coda/coda_regs.h
+ *
+ * Copyright (C) 2012 Vista Silicon SL
+ *    Javier Martin <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ *
+ * 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.
+ */
+
+#ifndef _REGS_CODA_H_
+#define _REGS_CODA_H_
+
+/* HW registers */
+#define CODA_REG_BIT_CODE_RUN			0x000
+#define		CODA_REG_RUN_ENABLE		(1 << 0)
+#define CODA_REG_BIT_CODE_DOWN			0x004
+#define		CODA_DOWN_ADDRESS_SET(x)	(((x) & 0xffff) << 16)
+#define		CODA_DOWN_DATA_SET(x)		((x) & 0xffff)
+#define CODA_REG_BIT_HOST_IN_REQ		0x008
+#define CODA_REG_BIT_INT_CLEAR			0x00c
+#define		CODA_REG_BIT_INT_CLEAR_SET	0x1
+#define CODA_REG_BIT_INT_STATUS		0x010
+#define CODA_REG_BIT_CODE_RESET		0x014
+#define		CODA_REG_RESET_ENABLE		(1 << 0)
+#define CODA_REG_BIT_CUR_PC			0x018
+
+/* Static SW registers */
+#define CODA_REG_BIT_CODE_BUF_ADDR		0x100
+#define CODA_REG_BIT_WORK_BUF_ADDR		0x104
+#define CODA_REG_BIT_PARA_BUF_ADDR		0x108
+#define CODA_REG_BIT_STREAM_CTRL		0x10c
+#define		CODA7_STREAM_BUF_PIC_RESET	(1 << 4)
+#define		CODADX6_STREAM_BUF_PIC_RESET	(1 << 3)
+#define		CODA7_STREAM_BUF_PIC_FLUSH	(1 << 3)
+#define		CODADX6_STREAM_BUF_PIC_FLUSH	(1 << 2)
+#define		CODA7_STREAM_BUF_DYNALLOC_EN	(1 << 5)
+#define		CODADX6_STREAM_BUF_DYNALLOC_EN	(1 << 4)
+#define 	CODA_STREAM_CHKDIS_OFFSET	(1 << 1)
+#define		CODA_STREAM_ENDIAN_SELECT	(1 << 0)
+#define CODA_REG_BIT_FRAME_MEM_CTRL		0x110
+#define		CODA_IMAGE_ENDIAN_SELECT	(1 << 0)
+#define CODA_REG_BIT_RD_PTR(x)			(0x120 + 8 * (x))
+#define CODA_REG_BIT_WR_PTR(x)			(0x124 + 8 * (x))
+#define CODA_REG_BIT_SEARCH_RAM_BASE_ADDR	0x140
+#define CODA_REG_BIT_BUSY			0x160
+#define		CODA_REG_BIT_BUSY_FLAG		1
+#define CODA_REG_BIT_RUN_COMMAND		0x164
+#define		CODA_COMMAND_SEQ_INIT		1
+#define		CODA_COMMAND_SEQ_END		2
+#define		CODA_COMMAND_PIC_RUN		3
+#define		CODA_COMMAND_SET_FRAME_BUF	4
+#define		CODA_COMMAND_ENCODE_HEADER	5
+#define		CODA_COMMAND_ENC_PARA_SET	6
+#define		CODA_COMMAND_DEC_PARA_SET	7
+#define		CODA_COMMAND_DEC_BUF_FLUSH	8
+#define		CODA_COMMAND_RC_CHANGE_PARAMETER 9
+#define		CODA_COMMAND_FIRMWARE_GET	0xf
+#define CODA_REG_BIT_RUN_INDEX			0x168
+#define		CODA_INDEX_SET(x)		((x) & 0x3)
+#define CODA_REG_BIT_RUN_COD_STD		0x16c
+#define		CODADX6_MODE_DECODE_MP4		0
+#define		CODADX6_MODE_ENCODE_MP4		1
+#define		CODADX6_MODE_DECODE_H264	2
+#define		CODADX6_MODE_ENCODE_H264	3
+#define		CODA7_MODE_DECODE_H264		0
+#define		CODA7_MODE_DECODE_VC1		1
+#define		CODA7_MODE_DECODE_MP2		2
+#define		CODA7_MODE_DECODE_MP4		3
+#define		CODA7_MODE_DECODE_DV3		3
+#define		CODA7_MODE_DECODE_RV		4
+#define		CODA7_MODE_DECODE_MJPG		5
+#define		CODA7_MODE_ENCODE_H264		8
+#define		CODA7_MODE_ENCODE_MP4		11
+#define		CODA7_MODE_ENCODE_MJPG		13
+#define 	CODA_MODE_INVALID		0xffff
+#define CODA_REG_BIT_INT_ENABLE		0x170
+#define		CODA_INT_INTERRUPT_ENABLE	(1 << 3)
+
+/*
+ * Commands' mailbox:
+ * registers with offsets in the range 0x180-0x1d0
+ * have different meaning depending on the command being
+ * issued.
+ */
+
+/* Encoder Sequence Initialization */
+#define CODA_CMD_ENC_SEQ_BB_START				0x180
+#define CODA_CMD_ENC_SEQ_BB_SIZE				0x184
+#define CODA_CMD_ENC_SEQ_OPTION				0x188
+#define		CODA_OPTION_GAMMA_OFFSET			7
+#define		CODA_OPTION_GAMMA_MASK				0x01
+#define		CODA_OPTION_LIMITQP_OFFSET			6
+#define		CODA_OPTION_LIMITQP_MASK			0x01
+#define		CODA_OPTION_RCINTRAQP_OFFSET			5
+#define		CODA_OPTION_RCINTRAQP_MASK			0x01
+#define		CODA_OPTION_FMO_OFFSET				4
+#define		CODA_OPTION_FMO_MASK				0x01
+#define		CODA_OPTION_SLICEREPORT_OFFSET			1
+#define		CODA_OPTION_SLICEREPORT_MASK			0x01
+#define CODA_CMD_ENC_SEQ_COD_STD				0x18c
+#define		CODA_STD_MPEG4					0
+#define		CODA_STD_H263					1
+#define		CODA_STD_H264					2
+#define		CODA_STD_MJPG					3
+#define CODA_CMD_ENC_SEQ_SRC_SIZE				0x190
+#define		CODA7_PICWIDTH_OFFSET				16
+#define		CODA7_PICWIDTH_MASK				0xffff
+#define		CODADX6_PICWIDTH_OFFSET				10
+#define		CODADX6_PICWIDTH_MASK				0x3ff
+#define		CODA_PICHEIGHT_OFFSET				0
+#define		CODA_PICHEIGHT_MASK				0x3ff
+#define CODA_CMD_ENC_SEQ_SRC_F_RATE				0x194
+#define CODA_CMD_ENC_SEQ_MP4_PARA				0x198
+#define		CODA_MP4PARAM_VERID_OFFSET			6
+#define		CODA_MP4PARAM_VERID_MASK			0x01
+#define		CODA_MP4PARAM_INTRADCVLCTHR_OFFSET		2
+#define		CODA_MP4PARAM_INTRADCVLCTHR_MASK		0x07
+#define		CODA_MP4PARAM_REVERSIBLEVLCENABLE_OFFSET	1
+#define		CODA_MP4PARAM_REVERSIBLEVLCENABLE_MASK		0x01
+#define		CODA_MP4PARAM_DATAPARTITIONENABLE_OFFSET	0
+#define		CODA_MP4PARAM_DATAPARTITIONENABLE_MASK		0x01
+#define CODA_CMD_ENC_SEQ_263_PARA				0x19c
+#define		CODA_263PARAM_ANNEXJENABLE_OFFSET		2
+#define		CODA_263PARAM_ANNEXJENABLE_MASK		0x01
+#define		CODA_263PARAM_ANNEXKENABLE_OFFSET		1
+#define		CODA_263PARAM_ANNEXKENABLE_MASK		0x01
+#define		CODA_263PARAM_ANNEXTENABLE_OFFSET		0
+#define		CODA_263PARAM_ANNEXTENABLE_MASK		0x01
+#define CODA_CMD_ENC_SEQ_264_PARA				0x1a0
+#define		CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET	12
+#define		CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK	0x0f
+#define		CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET	8
+#define		CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK	0x0f
+#define		CODA_264PARAM_DISABLEDEBLK_OFFSET		6
+#define		CODA_264PARAM_DISABLEDEBLK_MASK		0x01
+#define		CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET	5
+#define		CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_MASK	0x01
+#define		CODA_264PARAM_CHROMAQPOFFSET_OFFSET		0
+#define		CODA_264PARAM_CHROMAQPOFFSET_MASK		0x1f
+#define CODA_CMD_ENC_SEQ_SLICE_MODE				0x1a4
+#define		CODA_SLICING_SIZE_OFFSET			2
+#define		CODA_SLICING_SIZE_MASK				0x3fffffff
+#define		CODA_SLICING_UNIT_OFFSET			1
+#define		CODA_SLICING_UNIT_MASK				0x01
+#define		CODA_SLICING_MODE_OFFSET			0
+#define		CODA_SLICING_MODE_MASK				0x01
+#define CODA_CMD_ENC_SEQ_GOP_SIZE				0x1a8
+#define		CODA_GOP_SIZE_OFFSET				0
+#define		CODA_GOP_SIZE_MASK				0x3f
+#define CODA_CMD_ENC_SEQ_RC_PARA				0x1ac
+#define		CODA_RATECONTROL_AUTOSKIP_OFFSET		31
+#define		CODA_RATECONTROL_AUTOSKIP_MASK			0x01
+#define		CODA_RATECONTROL_INITIALDELAY_OFFSET		16
+#define		CODA_RATECONTROL_INITIALDELAY_MASK		0x7f
+#define		CODA_RATECONTROL_BITRATE_OFFSET		1
+#define		CODA_RATECONTROL_BITRATE_MASK			0x7f
+#define		CODA_RATECONTROL_ENABLE_OFFSET			0
+#define		CODA_RATECONTROL_ENABLE_MASK			0x01
+#define CODA_CMD_ENC_SEQ_RC_BUF_SIZE				0x1b0
+#define CODA_CMD_ENC_SEQ_INTRA_REFRESH				0x1b4
+#define CODA_CMD_ENC_SEQ_FMO					0x1b8
+#define		CODA_FMOPARAM_TYPE_OFFSET			4
+#define		CODA_FMOPARAM_TYPE_MASK				1
+#define		CODA_FMOPARAM_SLICENUM_OFFSET			0
+#define		CODA_FMOPARAM_SLICENUM_MASK			0x0f
+#define CODA_CMD_ENC_SEQ_RC_QP_MAX				0x1c8
+#define		CODA_QPMAX_OFFSET				0
+#define		CODA_QPMAX_MASK					0x3f
+#define CODA_CMD_ENC_SEQ_RC_GAMMA				0x1cc
+#define		CODA_GAMMA_OFFSET				0
+#define		CODA_GAMMA_MASK					0xffff
+#define CODA_RET_ENC_SEQ_SUCCESS				0x1c0
+
+/* Encoder Picture Run */
+#define CODA_CMD_ENC_PIC_SRC_ADDR_Y	0x180
+#define CODA_CMD_ENC_PIC_SRC_ADDR_CB	0x184
+#define CODA_CMD_ENC_PIC_SRC_ADDR_CR	0x188
+#define CODA_CMD_ENC_PIC_QS		0x18c
+#define CODA_CMD_ENC_PIC_ROT_MODE	0x190
+#define CODA_CMD_ENC_PIC_OPTION	0x194
+#define CODA_CMD_ENC_PIC_BB_START	0x198
+#define CODA_CMD_ENC_PIC_BB_SIZE	0x19c
+#define CODA_RET_ENC_PIC_TYPE		0x1c4
+#define CODA_RET_ENC_PIC_SLICE_NUM	0x1cc
+#define CODA_RET_ENC_PIC_FLAG		0x1d0
+
+/* Set Frame Buffer */
+#define CODA_CMD_SET_FRAME_BUF_NUM	0x180
+#define CODA_CMD_SET_FRAME_BUF_STRIDE	0x184
+
+/* Encoder Header */
+#define CODA_CMD_ENC_HEADER_CODE	0x180
+#define		CODA_GAMMA_OFFSET	0
+#define		CODA_HEADER_H264_SPS	0
+#define		CODA_HEADER_H264_PPS	1
+#define		CODA_HEADER_MP4V_VOL	0
+#define		CODA_HEADER_MP4V_VOS	1
+#define		CODA_HEADER_MP4V_VIS	2
+#define CODA_CMD_ENC_HEADER_BB_START	0x184
+#define CODA_CMD_ENC_HEADER_BB_SIZE	0x188
+
+/* Get Version */
+#define CODA_CMD_FIRMWARE_VERNUM		0x1c0
+#define		CODA_FIRMWARE_PRODUCT(x)	(((x) >> 16) & 0xffff)
+#define		CODA_FIRMWARE_MAJOR(x)		(((x) >> 12) & 0x0f)
+#define		CODA_FIRMWARE_MINOR(x)		(((x) >> 8) & 0x0f)
+#define		CODA_FIRMWARE_RELEASE(x)	((x) & 0xff)
+#define		CODA_FIRMWARE_VERNUM(product, major, minor, release)	\
+			((product) << 16 | ((major) << 12) |		\
+			((minor) << 8) | (release))
+
+#endif
diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig
new file mode 100644
index 0000000..52c5ca6
--- /dev/null
+++ b/drivers/media/platform/davinci/Kconfig
@@ -0,0 +1,121 @@
+config VIDEO_DAVINCI_VPIF_DISPLAY
+	tristate "DM646x/DA850/OMAPL138 EVM Video Display"
+	depends on VIDEO_DEV && (MACH_DAVINCI_DM6467_EVM || MACH_DAVINCI_DA850_EVM)
+	select VIDEOBUF2_DMA_CONTIG
+	select VIDEO_DAVINCI_VPIF
+	select VIDEO_ADV7343 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_THS7303 if VIDEO_HELPER_CHIPS_AUTO
+	help
+	  Enables Davinci VPIF module used for display devices.
+	  This module is common for following DM6467/DA850/OMAPL138
+	  based display devices.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vpif_display.
+
+config VIDEO_DAVINCI_VPIF_CAPTURE
+	tristate "DM646x/DA850/OMAPL138 EVM Video Capture"
+	depends on VIDEO_DEV && (MACH_DAVINCI_DM6467_EVM || MACH_DAVINCI_DA850_EVM)
+	select VIDEOBUF2_DMA_CONTIG
+	select VIDEO_DAVINCI_VPIF
+	help
+	  Enables Davinci VPIF module used for captur devices.
+	  This module is common for following DM6467/DA850/OMAPL138
+	  based capture devices.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vpif_capture.
+
+config VIDEO_DAVINCI_VPIF
+	tristate "DaVinci VPIF Driver"
+	depends on VIDEO_DAVINCI_VPIF_DISPLAY || VIDEO_DAVINCI_VPIF_CAPTURE
+	help
+	  Support for DaVinci VPIF Driver.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vpif.
+
+config VIDEO_VPSS_SYSTEM
+	tristate "VPSS System module driver"
+	depends on ARCH_DAVINCI
+	help
+	  Support for vpss system module for video driver
+
+config VIDEO_VPFE_CAPTURE
+	tristate "VPFE Video Capture Driver"
+	depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3)
+	depends on I2C
+	select VIDEOBUF_DMA_CONTIG
+	help
+	  Support for DMx/AMx VPFE based frame grabber. This is the
+	  common V4L2 module for following DMx/AMx SoCs from Texas
+	  Instruments:- DM6446, DM365, DM355 & AM3517/05.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vpfe-capture.
+
+config VIDEO_DM6446_CCDC
+	tristate "DM6446 CCDC HW module"
+	depends on VIDEO_VPFE_CAPTURE
+	select VIDEO_VPSS_SYSTEM
+	default y
+	help
+	   Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
+	   with decoder modules such as TVP5146 over BT656 or
+	   sensor module such as MT9T001 over a raw interface. This
+	   module configures the interface and CCDC/ISIF to do
+	   video frame capture from slave decoders.
+
+	   To compile this driver as a module, choose M here: the
+	   module will be called vpfe.
+
+config VIDEO_DM355_CCDC
+	tristate "DM355 CCDC HW module"
+	depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE
+	select VIDEO_VPSS_SYSTEM
+	default y
+	help
+	   Enables DM355 CCD hw module. DM355 CCDC hw interfaces
+	   with decoder modules such as TVP5146 over BT656 or
+	   sensor module such as MT9T001 over a raw interface. This
+	   module configures the interface and CCDC/ISIF to do
+	   video frame capture from a slave decoders
+
+	   To compile this driver as a module, choose M here: the
+	   module will be called vpfe.
+
+config VIDEO_ISIF
+	tristate "ISIF HW module"
+	depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE
+	select VIDEO_VPSS_SYSTEM
+	default y
+	help
+	   Enables ISIF hw module. This is the hardware module for
+	   configuring ISIF in VPFE to capture Raw Bayer RGB data  from
+	   a image sensor or YUV data from a YUV source.
+
+	   To compile this driver as a module, choose M here: the
+	   module will be called vpfe.
+
+config VIDEO_DM644X_VPBE
+	tristate "DM644X VPBE HW module"
+	depends on ARCH_DAVINCI_DM644x
+	select VIDEO_VPSS_SYSTEM
+	select VIDEOBUF_DMA_CONTIG
+	help
+	    Enables VPBE modules used for display on a DM644x
+	    SoC.
+
+	    To compile this driver as a module, choose M here: the
+	    module will be called vpbe.
+
+
+config VIDEO_VPBE_DISPLAY
+	tristate "VPBE V4L2 Display driver"
+	depends on ARCH_DAVINCI_DM644x
+	select VIDEO_DM644X_VPBE
+	help
+	    Enables VPBE V4L2 Display driver on a DM644x device
+
+	    To compile this driver as a module, choose M here: the
+	    module will be called vpbe_display.
diff --git a/drivers/media/platform/davinci/Makefile b/drivers/media/platform/davinci/Makefile
new file mode 100644
index 0000000..74ed92d
--- /dev/null
+++ b/drivers/media/platform/davinci/Makefile
@@ -0,0 +1,20 @@
+#
+# Makefile for the davinci video device drivers.
+#
+
+# VPIF
+obj-$(CONFIG_VIDEO_DAVINCI_VPIF) += vpif.o
+
+#VPIF Display driver
+obj-$(CONFIG_VIDEO_DAVINCI_VPIF_DISPLAY) += vpif_display.o
+#VPIF Capture driver
+obj-$(CONFIG_VIDEO_DAVINCI_VPIF_CAPTURE) += vpif_capture.o
+
+# Capture: DM6446 and DM355
+obj-$(CONFIG_VIDEO_VPSS_SYSTEM) += vpss.o
+obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o
+obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o
+obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o
+obj-$(CONFIG_VIDEO_ISIF) += isif.o
+obj-$(CONFIG_VIDEO_DM644X_VPBE) += vpbe.o vpbe_osd.o vpbe_venc.o
+obj-$(CONFIG_VIDEO_VPBE_DISPLAY) += vpbe_display.o
diff --git a/drivers/media/platform/davinci/ccdc_hw_device.h b/drivers/media/platform/davinci/ccdc_hw_device.h
new file mode 100644
index 0000000..86b9b35
--- /dev/null
+++ b/drivers/media/platform/davinci/ccdc_hw_device.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2008-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ccdc device API
+ */
+#ifndef _CCDC_HW_DEVICE_H
+#define _CCDC_HW_DEVICE_H
+
+#ifdef __KERNEL__
+#include <linux/videodev2.h>
+#include <linux/device.h>
+#include <media/davinci/vpfe_types.h>
+#include <media/davinci/ccdc_types.h>
+
+/*
+ * ccdc hw operations
+ */
+struct ccdc_hw_ops {
+	/* Pointer to initialize function to initialize ccdc device */
+	int (*open) (struct device *dev);
+	/* Pointer to deinitialize function */
+	int (*close) (struct device *dev);
+	/* set ccdc base address */
+	void (*set_ccdc_base)(void *base, int size);
+	/* Pointer to function to enable or disable ccdc */
+	void (*enable) (int en);
+	/* reset sbl. only for 6446 */
+	void (*reset) (void);
+	/* enable output to sdram */
+	void (*enable_out_to_sdram) (int en);
+	/* Pointer to function to set hw parameters */
+	int (*set_hw_if_params) (struct vpfe_hw_if_param *param);
+	/* get interface parameters */
+	int (*get_hw_if_params) (struct vpfe_hw_if_param *param);
+	/*
+	 * Pointer to function to set parameters. Used
+	 * for implementing VPFE_S_CCDC_PARAMS
+	 */
+	int (*set_params) (void *params);
+	/*
+	 * Pointer to function to get parameter. Used
+	 * for implementing VPFE_G_CCDC_PARAMS
+	 */
+	int (*get_params) (void *params);
+	/* Pointer to function to configure ccdc */
+	int (*configure) (void);
+
+	/* Pointer to function to set buffer type */
+	int (*set_buftype) (enum ccdc_buftype buf_type);
+	/* Pointer to function to get buffer type */
+	enum ccdc_buftype (*get_buftype) (void);
+	/* Pointer to function to set frame format */
+	int (*set_frame_format) (enum ccdc_frmfmt frm_fmt);
+	/* Pointer to function to get frame format */
+	enum ccdc_frmfmt (*get_frame_format) (void);
+	/* enumerate hw pix formats */
+	int (*enum_pix)(u32 *hw_pix, int i);
+	/* Pointer to function to set buffer type */
+	u32 (*get_pixel_format) (void);
+	/* Pointer to function to get pixel format. */
+	int (*set_pixel_format) (u32 pixfmt);
+	/* Pointer to function to set image window */
+	int (*set_image_window) (struct v4l2_rect *win);
+	/* Pointer to function to set image window */
+	void (*get_image_window) (struct v4l2_rect *win);
+	/* Pointer to function to get line length */
+	unsigned int (*get_line_length) (void);
+
+	/* Query CCDC control IDs */
+	int (*queryctrl)(struct v4l2_queryctrl *qctrl);
+	/* Set CCDC control */
+	int (*set_control)(struct v4l2_control *ctrl);
+	/* Get CCDC control */
+	int (*get_control)(struct v4l2_control *ctrl);
+
+	/* Pointer to function to set frame buffer address */
+	void (*setfbaddr) (unsigned long addr);
+	/* Pointer to function to get field id */
+	int (*getfid) (void);
+};
+
+struct ccdc_hw_device {
+	/* ccdc device name */
+	char name[32];
+	/* module owner */
+	struct module *owner;
+	/* hw ops */
+	struct ccdc_hw_ops hw_ops;
+};
+
+/* Used by CCDC module to register & unregister with vpfe capture driver */
+int vpfe_register_ccdc_device(struct ccdc_hw_device *dev);
+void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev);
+
+#endif
+#endif
diff --git a/drivers/media/platform/davinci/dm355_ccdc.c b/drivers/media/platform/davinci/dm355_ccdc.c
new file mode 100644
index 0000000..ce0e413
--- /dev/null
+++ b/drivers/media/platform/davinci/dm355_ccdc.c
@@ -0,0 +1,1072 @@
+/*
+ * Copyright (C) 2005-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * CCDC hardware module for DM355
+ * ------------------------------
+ *
+ * This module is for configuring DM355 CCD controller of VPFE to capture
+ * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
+ * such as Defect Pixel Correction, Color Space Conversion etc to
+ * pre-process the Bayer RGB data, before writing it to SDRAM. This
+ * module also allows application to configure individual
+ * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL.
+ * To do so, application include dm355_ccdc.h and vpfe_capture.h header
+ * files. The setparams() API is called by vpfe_capture driver
+ * to configure module parameters
+ *
+ * TODO: 1) Raw bayer parameter settings and bayer capture
+ * 	 2) Split module parameter structure to module specific ioctl structs
+ *	 3) add support for lense shading correction
+ *	 4) investigate if enum used for user space type definition
+ * 	    to be replaced by #defines or integer
+ */
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/videodev2.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+
+#include <media/davinci/dm355_ccdc.h>
+#include <media/davinci/vpss.h>
+
+#include "dm355_ccdc_regs.h"
+#include "ccdc_hw_device.h"
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CCDC Driver for DM355");
+MODULE_AUTHOR("Texas Instruments");
+
+static struct ccdc_oper_config {
+	struct device *dev;
+	/* CCDC interface type */
+	enum vpfe_hw_if_type if_type;
+	/* Raw Bayer configuration */
+	struct ccdc_params_raw bayer;
+	/* YCbCr configuration */
+	struct ccdc_params_ycbcr ycbcr;
+	/* Master clock */
+	struct clk *mclk;
+	/* slave clock */
+	struct clk *sclk;
+	/* ccdc base address */
+	void __iomem *base_addr;
+} ccdc_cfg = {
+	/* Raw configurations */
+	.bayer = {
+		.pix_fmt = CCDC_PIXFMT_RAW,
+		.frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
+		.win = CCDC_WIN_VGA,
+		.fid_pol = VPFE_PINPOL_POSITIVE,
+		.vd_pol = VPFE_PINPOL_POSITIVE,
+		.hd_pol = VPFE_PINPOL_POSITIVE,
+		.gain = {
+			.r_ye = 256,
+			.gb_g = 256,
+			.gr_cy = 256,
+			.b_mg = 256
+		},
+		.config_params = {
+			.datasft = 2,
+			.mfilt1 = CCDC_NO_MEDIAN_FILTER1,
+			.mfilt2 = CCDC_NO_MEDIAN_FILTER2,
+			.alaw = {
+				.gama_wd = 2,
+			},
+			.blk_clamp = {
+				.sample_pixel = 1,
+				.dc_sub = 25
+			},
+			.col_pat_field0 = {
+				.olop = CCDC_GREEN_BLUE,
+				.olep = CCDC_BLUE,
+				.elop = CCDC_RED,
+				.elep = CCDC_GREEN_RED
+			},
+			.col_pat_field1 = {
+				.olop = CCDC_GREEN_BLUE,
+				.olep = CCDC_BLUE,
+				.elop = CCDC_RED,
+				.elep = CCDC_GREEN_RED
+			},
+		},
+	},
+	/* YCbCr configuration */
+	.ycbcr = {
+		.win = CCDC_WIN_PAL,
+		.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
+		.frm_fmt = CCDC_FRMFMT_INTERLACED,
+		.fid_pol = VPFE_PINPOL_POSITIVE,
+		.vd_pol = VPFE_PINPOL_POSITIVE,
+		.hd_pol = VPFE_PINPOL_POSITIVE,
+		.bt656_enable = 1,
+		.pix_order = CCDC_PIXORDER_CBYCRY,
+		.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
+	},
+};
+
+
+/* Raw Bayer formats */
+static u32 ccdc_raw_bayer_pix_formats[] =
+		{V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
+
+/* Raw YUV formats */
+static u32 ccdc_raw_yuv_pix_formats[] =
+		{V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
+
+/* register access routines */
+static inline u32 regr(u32 offset)
+{
+	return __raw_readl(ccdc_cfg.base_addr + offset);
+}
+
+static inline void regw(u32 val, u32 offset)
+{
+	__raw_writel(val, ccdc_cfg.base_addr + offset);
+}
+
+static void ccdc_enable(int en)
+{
+	unsigned int temp;
+	temp = regr(SYNCEN);
+	temp &= (~CCDC_SYNCEN_VDHDEN_MASK);
+	temp |= (en & CCDC_SYNCEN_VDHDEN_MASK);
+	regw(temp, SYNCEN);
+}
+
+static void ccdc_enable_output_to_sdram(int en)
+{
+	unsigned int temp;
+	temp = regr(SYNCEN);
+	temp &= (~(CCDC_SYNCEN_WEN_MASK));
+	temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK);
+	regw(temp, SYNCEN);
+}
+
+static void ccdc_config_gain_offset(void)
+{
+	/* configure gain */
+	regw(ccdc_cfg.bayer.gain.r_ye, RYEGAIN);
+	regw(ccdc_cfg.bayer.gain.gr_cy, GRCYGAIN);
+	regw(ccdc_cfg.bayer.gain.gb_g, GBGGAIN);
+	regw(ccdc_cfg.bayer.gain.b_mg, BMGGAIN);
+	/* configure offset */
+	regw(ccdc_cfg.bayer.ccdc_offset, OFFSET);
+}
+
+/*
+ * ccdc_restore_defaults()
+ * This function restore power on defaults in the ccdc registers
+ */
+static int ccdc_restore_defaults(void)
+{
+	int i;
+
+	dev_dbg(ccdc_cfg.dev, "\nstarting ccdc_restore_defaults...");
+	/* set all registers to zero */
+	for (i = 0; i <= CCDC_REG_LAST; i += 4)
+		regw(0, i);
+
+	/* now override the values with power on defaults in registers */
+	regw(MODESET_DEFAULT, MODESET);
+	/* no culling support */
+	regw(CULH_DEFAULT, CULH);
+	regw(CULV_DEFAULT, CULV);
+	/* Set default Gain and Offset */
+	ccdc_cfg.bayer.gain.r_ye = GAIN_DEFAULT;
+	ccdc_cfg.bayer.gain.gb_g = GAIN_DEFAULT;
+	ccdc_cfg.bayer.gain.gr_cy = GAIN_DEFAULT;
+	ccdc_cfg.bayer.gain.b_mg = GAIN_DEFAULT;
+	ccdc_config_gain_offset();
+	regw(OUTCLIP_DEFAULT, OUTCLIP);
+	regw(LSCCFG2_DEFAULT, LSCCFG2);
+	/* select ccdc input */
+	if (vpss_select_ccdc_source(VPSS_CCDCIN)) {
+		dev_dbg(ccdc_cfg.dev, "\ncouldn't select ccdc input source");
+		return -EFAULT;
+	}
+	/* select ccdc clock */
+	if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) {
+		dev_dbg(ccdc_cfg.dev, "\ncouldn't enable ccdc clock");
+		return -EFAULT;
+	}
+	dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_restore_defaults...");
+	return 0;
+}
+
+static int ccdc_open(struct device *device)
+{
+	return ccdc_restore_defaults();
+}
+
+static int ccdc_close(struct device *device)
+{
+	/* disable clock */
+	vpss_enable_clock(VPSS_CCDC_CLOCK, 0);
+	/* do nothing for now */
+	return 0;
+}
+/*
+ * ccdc_setwin()
+ * This function will configure the window size to
+ * be capture in CCDC reg.
+ */
+static void ccdc_setwin(struct v4l2_rect *image_win,
+			enum ccdc_frmfmt frm_fmt, int ppc)
+{
+	int horz_start, horz_nr_pixels;
+	int vert_start, vert_nr_lines;
+	int mid_img = 0;
+
+	dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin...");
+
+	/*
+	 * ppc - per pixel count. indicates how many pixels per cell
+	 * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
+	 * raw capture this is 1
+	 */
+	horz_start = image_win->left << (ppc - 1);
+	horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
+
+	/* Writing the horizontal info into the registers */
+	regw(horz_start, SPH);
+	regw(horz_nr_pixels, NPH);
+	vert_start = image_win->top;
+
+	if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+		vert_nr_lines = (image_win->height >> 1) - 1;
+		vert_start >>= 1;
+		/* Since first line doesn't have any data */
+		vert_start += 1;
+		/* configure VDINT0 and VDINT1 */
+		regw(vert_start, VDINT0);
+	} else {
+		/* Since first line doesn't have any data */
+		vert_start += 1;
+		vert_nr_lines = image_win->height - 1;
+		/* configure VDINT0 and VDINT1 */
+		mid_img = vert_start + (image_win->height / 2);
+		regw(vert_start, VDINT0);
+		regw(mid_img, VDINT1);
+	}
+	regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0);
+	regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1);
+	regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV);
+	dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin...");
+}
+
+static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
+{
+	if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT ||
+	    ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) {
+		dev_dbg(ccdc_cfg.dev, "Invalid value of data shift\n");
+		return -EINVAL;
+	}
+
+	if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 ||
+	    ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) {
+		dev_dbg(ccdc_cfg.dev, "Invalid value of median filter1\n");
+		return -EINVAL;
+	}
+
+	if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 ||
+	    ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) {
+		dev_dbg(ccdc_cfg.dev, "Invalid value of median filter2\n");
+		return -EINVAL;
+	}
+
+	if ((ccdcparam->med_filt_thres < 0) ||
+	   (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) {
+		dev_dbg(ccdc_cfg.dev,
+			"Invalid value of median filter threshold\n");
+		return -EINVAL;
+	}
+
+	if (ccdcparam->data_sz < CCDC_DATA_16BITS ||
+	    ccdcparam->data_sz > CCDC_DATA_8BITS) {
+		dev_dbg(ccdc_cfg.dev, "Invalid value of data size\n");
+		return -EINVAL;
+	}
+
+	if (ccdcparam->alaw.enable) {
+		if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 ||
+		    ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) {
+			dev_dbg(ccdc_cfg.dev, "Invalid value of ALAW\n");
+			return -EINVAL;
+		}
+	}
+
+	if (ccdcparam->blk_clamp.b_clamp_enable) {
+		if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS ||
+		    ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) {
+			dev_dbg(ccdc_cfg.dev,
+				"Invalid value of sample pixel\n");
+			return -EINVAL;
+		}
+		if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES ||
+		    ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) {
+			dev_dbg(ccdc_cfg.dev,
+				"Invalid value of sample lines\n");
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+/* Parameter operations */
+static int ccdc_set_params(void __user *params)
+{
+	struct ccdc_config_params_raw ccdc_raw_params;
+	int x;
+
+	/* only raw module parameters can be set through the IOCTL */
+	if (ccdc_cfg.if_type != VPFE_RAW_BAYER)
+		return -EINVAL;
+
+	x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
+	if (x) {
+		dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying ccdc"
+			"params, %d\n", x);
+		return -EFAULT;
+	}
+
+	if (!validate_ccdc_param(&ccdc_raw_params)) {
+		memcpy(&ccdc_cfg.bayer.config_params,
+			&ccdc_raw_params,
+			sizeof(ccdc_raw_params));
+		return 0;
+	}
+	return -EINVAL;
+}
+
+/* This function will configure CCDC for YCbCr video capture */
+static void ccdc_config_ycbcr(void)
+{
+	struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
+	u32 temp;
+
+	/* first set the CCDC power on defaults values in all registers */
+	dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr...");
+	ccdc_restore_defaults();
+
+	/* configure pixel format & video frame format */
+	temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) <<
+		CCDC_INPUT_MODE_SHIFT) |
+		((params->frm_fmt & CCDC_FRM_FMT_MASK) <<
+		CCDC_FRM_FMT_SHIFT));
+
+	/* setup BT.656 sync mode */
+	if (params->bt656_enable) {
+		regw(CCDC_REC656IF_BT656_EN, REC656IF);
+		/*
+		 * configure the FID, VD, HD pin polarity fld,hd pol positive,
+		 * vd negative, 8-bit pack mode
+		 */
+		temp |= CCDC_VD_POL_NEGATIVE;
+	} else {		/* y/c external sync mode */
+		temp |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
+			CCDC_FID_POL_SHIFT) |
+			((params->hd_pol & CCDC_HD_POL_MASK) <<
+			CCDC_HD_POL_SHIFT) |
+			((params->vd_pol & CCDC_VD_POL_MASK) <<
+			CCDC_VD_POL_SHIFT));
+	}
+
+	/* pack the data to 8-bit */
+	temp |= CCDC_DATA_PACK_ENABLE;
+
+	regw(temp, MODESET);
+
+	/* configure video window */
+	ccdc_setwin(&params->win, params->frm_fmt, 2);
+
+	/* configure the order of y cb cr in SD-RAM */
+	temp = (params->pix_order << CCDC_Y8POS_SHIFT);
+	temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC;
+	regw(temp, CCDCFG);
+
+	/*
+	 * configure the horizontal line offset. This is done by rounding up
+	 * width to a multiple of 16 pixels and multiply by two to account for
+	 * y:cb:cr 4:2:2 data
+	 */
+	regw(((params->win.width * 2 + 31) >> 5), HSIZE);
+
+	/* configure the memory line offset */
+	if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) {
+		/* two fields are interleaved in memory */
+		regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST);
+	}
+
+	dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n");
+}
+
+/*
+ * ccdc_config_black_clamp()
+ * configure parameters for Optical Black Clamp
+ */
+static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
+{
+	u32 val;
+
+	if (!bclamp->b_clamp_enable) {
+		/* configure DCSub */
+		regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB);
+		regw(0x0000, CLAMP);
+		return;
+	}
+	/* Enable the Black clamping, set sample lines and pixels */
+	val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) |
+	      ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
+		CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE;
+	regw(val, CLAMP);
+
+	/* If Black clamping is enable then make dcsub 0 */
+	val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK)
+			<< CCDC_NUM_LINE_CALC_SHIFT;
+	regw(val, DCSUB);
+}
+
+/*
+ * ccdc_config_black_compense()
+ * configure parameters for Black Compensation
+ */
+static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
+{
+	u32 val;
+
+	val = (bcomp->b & CCDC_BLK_COMP_MASK) |
+		((bcomp->gb & CCDC_BLK_COMP_MASK) <<
+		CCDC_BLK_COMP_GB_COMP_SHIFT);
+	regw(val, BLKCMP1);
+
+	val = ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
+		CCDC_BLK_COMP_GR_COMP_SHIFT) |
+		((bcomp->r & CCDC_BLK_COMP_MASK) <<
+		CCDC_BLK_COMP_R_COMP_SHIFT);
+	regw(val, BLKCMP0);
+}
+
+/*
+ * ccdc_write_dfc_entry()
+ * write an entry in the dfc table.
+ */
+int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
+{
+/* TODO This is to be re-visited and adjusted */
+#define DFC_WRITE_WAIT_COUNT	1000
+	u32 val, count = DFC_WRITE_WAIT_COUNT;
+
+	regw(dfc->dft_corr_vert[index], DFCMEM0);
+	regw(dfc->dft_corr_horz[index], DFCMEM1);
+	regw(dfc->dft_corr_sub1[index], DFCMEM2);
+	regw(dfc->dft_corr_sub2[index], DFCMEM3);
+	regw(dfc->dft_corr_sub3[index], DFCMEM4);
+	/* set WR bit to write */
+	val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK;
+	regw(val, DFCMEMCTL);
+
+	/*
+	 * Assume, it is very short. If we get an error, we need to
+	 * adjust this value
+	 */
+	while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK)
+		count--;
+	/*
+	 * TODO We expect the count to be non-zero to be successful. Adjust
+	 * the count if write requires more time
+	 */
+
+	if (count) {
+		dev_err(ccdc_cfg.dev, "defect table write timeout !!!\n");
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * ccdc_config_vdfc()
+ * configure parameters for Vertical Defect Correction
+ */
+static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc)
+{
+	u32 val;
+	int i;
+
+	/* Configure General Defect Correction. The table used is from IPIPE */
+	val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK;
+
+	/* Configure Vertical Defect Correction if needed */
+	if (!dfc->ver_dft_en) {
+		/* Enable only General Defect Correction */
+		regw(val, DFCCTL);
+		return 0;
+	}
+
+	if (dfc->table_size > CCDC_DFT_TABLE_SIZE)
+		return -EINVAL;
+
+	val |= CCDC_DFCCTL_VDFC_DISABLE;
+	val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) <<
+		CCDC_DFCCTL_VDFCSL_SHIFT;
+	val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) <<
+		CCDC_DFCCTL_VDFCUDA_SHIFT;
+	val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) <<
+		CCDC_DFCCTL_VDFLSFT_SHIFT;
+	regw(val , DFCCTL);
+
+	/* clear address ptr to offset 0 */
+	val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT;
+
+	/* write defect table entries */
+	for (i = 0; i < dfc->table_size; i++) {
+		/* increment address for non zero index */
+		if (i != 0)
+			val = CCDC_DFCMEMCTL_INC_ADDR;
+		regw(val, DFCMEMCTL);
+		if (ccdc_write_dfc_entry(i, dfc) < 0)
+			return -EFAULT;
+	}
+
+	/* update saturation level and enable dfc */
+	regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT);
+	val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK <<
+			CCDC_DFCCTL_VDFCEN_SHIFT);
+	regw(val, DFCCTL);
+	return 0;
+}
+
+/*
+ * ccdc_config_csc()
+ * configure parameters for color space conversion
+ * Each register CSCM0-7 has two values in S8Q5 format.
+ */
+static void ccdc_config_csc(struct ccdc_csc *csc)
+{
+	u32 val1, val2;
+	int i;
+
+	if (!csc->enable)
+		return;
+
+	/* Enable the CSC sub-module */
+	regw(CCDC_CSC_ENABLE, CSCCTL);
+
+	/* Converting the co-eff as per the format of the register */
+	for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) {
+		if ((i % 2) == 0) {
+			/* CSCM - LSB */
+			val1 = (csc->coeff[i].integer &
+				CCDC_CSC_COEF_INTEG_MASK)
+				<< CCDC_CSC_COEF_INTEG_SHIFT;
+			/*
+			 * convert decimal part to binary. Use 2 decimal
+			 * precision, user values range from .00 - 0.99
+			 */
+			val1 |= (((csc->coeff[i].decimal &
+				CCDC_CSC_COEF_DECIMAL_MASK) *
+				CCDC_CSC_DEC_MAX) / 100);
+		} else {
+
+			/* CSCM - MSB */
+			val2 = (csc->coeff[i].integer &
+				CCDC_CSC_COEF_INTEG_MASK)
+				<< CCDC_CSC_COEF_INTEG_SHIFT;
+			val2 |= (((csc->coeff[i].decimal &
+				 CCDC_CSC_COEF_DECIMAL_MASK) *
+				 CCDC_CSC_DEC_MAX) / 100);
+			val2 <<= CCDC_CSCM_MSB_SHIFT;
+			val2 |= val1;
+			regw(val2, (CSCM0 + ((i - 1) << 1)));
+		}
+	}
+}
+
+/*
+ * ccdc_config_color_patterns()
+ * configure parameters for color patterns
+ */
+static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0,
+				       struct ccdc_col_pat *pat1)
+{
+	u32 val;
+
+	val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) |
+		(pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) |
+		(pat1->elop << 12) | (pat1->elep << 14));
+	regw(val, COLPTN);
+}
+
+/* This function will configure CCDC for Raw mode image capture */
+static int ccdc_config_raw(void)
+{
+	struct ccdc_params_raw *params = &ccdc_cfg.bayer;
+	struct ccdc_config_params_raw *config_params =
+					&ccdc_cfg.bayer.config_params;
+	unsigned int val;
+
+	dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw...");
+
+	/* restore power on defaults to register */
+	ccdc_restore_defaults();
+
+	/* CCDCFG register:
+	 * set CCD Not to swap input since input is RAW data
+	 * set FID detection function to Latch at V-Sync
+	 * set WENLOG - ccdc valid area to AND
+	 * set TRGSEL to WENBIT
+	 * set EXTRG to DISABLE
+	 * disable latching function on VSYNC - shadowed registers
+	 */
+	regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC |
+	     CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN |
+	     CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG);
+
+	/*
+	 * Set VDHD direction to input,  input type to raw input
+	 * normal data polarity, do not use external WEN
+	 */
+	val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL |
+		CCDC_EXWEN_DISABLE);
+
+	/*
+	 * Configure the vertical sync polarity (MODESET.VDPOL), horizontal
+	 * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL),
+	 * frame format(progressive or interlace), & pixel format (Input mode)
+	 */
+	val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
+		((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
+		((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
+		((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
+		((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT));
+
+	/* set pack for alaw compression */
+	if ((config_params->data_sz == CCDC_DATA_8BITS) ||
+	     config_params->alaw.enable)
+		val |= CCDC_DATA_PACK_ENABLE;
+
+	/* Configure for LPF */
+	if (config_params->lpf_enable)
+		val |= (config_params->lpf_enable & CCDC_LPF_MASK) <<
+			CCDC_LPF_SHIFT;
+
+	/* Configure the data shift */
+	val |= (config_params->datasft & CCDC_DATASFT_MASK) <<
+		CCDC_DATASFT_SHIFT;
+	regw(val , MODESET);
+	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to MODESET...\n", val);
+
+	/* Configure the Median Filter threshold */
+	regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT);
+
+	/* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */
+	val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT |
+		CCDC_CFA_MOSAIC;
+
+	/* Enable and configure aLaw register if needed */
+	if (config_params->alaw.enable) {
+		val |= (CCDC_ALAW_ENABLE |
+			((config_params->alaw.gama_wd &
+			CCDC_ALAW_GAMA_WD_MASK) <<
+			CCDC_GAMMAWD_INPUT_SHIFT));
+	}
+
+	/* Configure Median filter1 & filter2 */
+	val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) |
+		(config_params->mfilt2 << CCDC_MFILT2_SHIFT));
+
+	regw(val, GAMMAWD);
+	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to GAMMAWD...\n", val);
+
+	/* configure video window */
+	ccdc_setwin(&params->win, params->frm_fmt, 1);
+
+	/* Optical Clamp Averaging */
+	ccdc_config_black_clamp(&config_params->blk_clamp);
+
+	/* Black level compensation */
+	ccdc_config_black_compense(&config_params->blk_comp);
+
+	/* Vertical Defect Correction if needed */
+	if (ccdc_config_vdfc(&config_params->vertical_dft) < 0)
+		return -EFAULT;
+
+	/* color space conversion */
+	ccdc_config_csc(&config_params->csc);
+
+	/* color pattern */
+	ccdc_config_color_patterns(&config_params->col_pat_field0,
+				   &config_params->col_pat_field1);
+
+	/* Configure the Gain  & offset control */
+	ccdc_config_gain_offset();
+
+	dev_dbg(ccdc_cfg.dev, "\nWriting %x to COLPTN...\n", val);
+
+	/* Configure DATAOFST  register */
+	val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) <<
+		CCDC_DATAOFST_H_SHIFT;
+	val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) <<
+		CCDC_DATAOFST_V_SHIFT;
+	regw(val, DATAOFST);
+
+	/* configuring HSIZE register */
+	val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) <<
+		CCDC_HSIZE_FLIP_SHIFT;
+
+	/* If pack 8 is enable then 1 pixel will take 1 byte */
+	if ((config_params->data_sz == CCDC_DATA_8BITS) ||
+	     config_params->alaw.enable) {
+		val |= (((params->win.width) + 31) >> 5) &
+			CCDC_HSIZE_VAL_MASK;
+
+		/* adjust to multiple of 32 */
+		dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n",
+		       (((params->win.width) + 31) >> 5) &
+			CCDC_HSIZE_VAL_MASK);
+	} else {
+		/* else one pixel will take 2 byte */
+		val |= (((params->win.width * 2) + 31) >> 5) &
+			CCDC_HSIZE_VAL_MASK;
+
+		dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n",
+		       (((params->win.width * 2) + 31) >> 5) &
+			CCDC_HSIZE_VAL_MASK);
+	}
+	regw(val, HSIZE);
+
+	/* Configure SDOFST register */
+	if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
+		if (params->image_invert_enable) {
+			/* For interlace inverse mode */
+			regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST);
+			dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
+				CCDC_SDOFST_INTERLACE_INVERSE);
+		} else {
+			/* For interlace non inverse mode */
+			regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST);
+			dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
+				CCDC_SDOFST_INTERLACE_NORMAL);
+		}
+	} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
+		if (params->image_invert_enable) {
+			/* For progessive inverse mode */
+			regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST);
+			dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
+				CCDC_SDOFST_PROGRESSIVE_INVERSE);
+		} else {
+			/* For progessive non inverse mode */
+			regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST);
+			dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
+				CCDC_SDOFST_PROGRESSIVE_NORMAL);
+		}
+	}
+	dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw...");
+	return 0;
+}
+
+static int ccdc_configure(void)
+{
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+		return ccdc_config_raw();
+	else
+		ccdc_config_ycbcr();
+	return 0;
+}
+
+static int ccdc_set_buftype(enum ccdc_buftype buf_type)
+{
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+		ccdc_cfg.bayer.buf_type = buf_type;
+	else
+		ccdc_cfg.ycbcr.buf_type = buf_type;
+	return 0;
+}
+static enum ccdc_buftype ccdc_get_buftype(void)
+{
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+		return ccdc_cfg.bayer.buf_type;
+	return ccdc_cfg.ycbcr.buf_type;
+}
+
+static int ccdc_enum_pix(u32 *pix, int i)
+{
+	int ret = -EINVAL;
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
+		if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
+			*pix = ccdc_raw_bayer_pix_formats[i];
+			ret = 0;
+		}
+	} else {
+		if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
+			*pix = ccdc_raw_yuv_pix_formats[i];
+			ret = 0;
+		}
+	}
+	return ret;
+}
+
+static int ccdc_set_pixel_format(u32 pixfmt)
+{
+	struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
+
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
+		ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
+		if (pixfmt == V4L2_PIX_FMT_SBGGR8)
+			alaw->enable = 1;
+		else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
+			return -EINVAL;
+	} else {
+		if (pixfmt == V4L2_PIX_FMT_YUYV)
+			ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
+		else if (pixfmt == V4L2_PIX_FMT_UYVY)
+			ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+		else
+			return -EINVAL;
+	}
+	return 0;
+}
+static u32 ccdc_get_pixel_format(void)
+{
+	struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
+	u32 pixfmt;
+
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+		if (alaw->enable)
+			pixfmt = V4L2_PIX_FMT_SBGGR8;
+		else
+			pixfmt = V4L2_PIX_FMT_SBGGR16;
+	else {
+		if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
+			pixfmt = V4L2_PIX_FMT_YUYV;
+		else
+			pixfmt = V4L2_PIX_FMT_UYVY;
+	}
+	return pixfmt;
+}
+static int ccdc_set_image_window(struct v4l2_rect *win)
+{
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+		ccdc_cfg.bayer.win = *win;
+	else
+		ccdc_cfg.ycbcr.win = *win;
+	return 0;
+}
+
+static void ccdc_get_image_window(struct v4l2_rect *win)
+{
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+		*win = ccdc_cfg.bayer.win;
+	else
+		*win = ccdc_cfg.ycbcr.win;
+}
+
+static unsigned int ccdc_get_line_length(void)
+{
+	struct ccdc_config_params_raw *config_params =
+				&ccdc_cfg.bayer.config_params;
+	unsigned int len;
+
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
+		if ((config_params->alaw.enable) ||
+		    (config_params->data_sz == CCDC_DATA_8BITS))
+			len = ccdc_cfg.bayer.win.width;
+		else
+			len = ccdc_cfg.bayer.win.width * 2;
+	} else
+		len = ccdc_cfg.ycbcr.win.width * 2;
+	return ALIGN(len, 32);
+}
+
+static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
+{
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+		ccdc_cfg.bayer.frm_fmt = frm_fmt;
+	else
+		ccdc_cfg.ycbcr.frm_fmt = frm_fmt;
+	return 0;
+}
+
+static enum ccdc_frmfmt ccdc_get_frame_format(void)
+{
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+		return ccdc_cfg.bayer.frm_fmt;
+	else
+		return ccdc_cfg.ycbcr.frm_fmt;
+}
+
+static int ccdc_getfid(void)
+{
+	return  (regr(MODESET) >> 15) & 1;
+}
+
+/* misc operations */
+static inline void ccdc_setfbaddr(unsigned long addr)
+{
+	regw((addr >> 21) & 0x007f, STADRH);
+	regw((addr >> 5) & 0x0ffff, STADRL);
+}
+
+static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
+{
+	ccdc_cfg.if_type = params->if_type;
+
+	switch (params->if_type) {
+	case VPFE_BT656:
+	case VPFE_YCBCR_SYNC_16:
+	case VPFE_YCBCR_SYNC_8:
+		ccdc_cfg.ycbcr.vd_pol = params->vdpol;
+		ccdc_cfg.ycbcr.hd_pol = params->hdpol;
+		break;
+	default:
+		/* TODO add support for raw bayer here */
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static struct ccdc_hw_device ccdc_hw_dev = {
+	.name = "DM355 CCDC",
+	.owner = THIS_MODULE,
+	.hw_ops = {
+		.open = ccdc_open,
+		.close = ccdc_close,
+		.enable = ccdc_enable,
+		.enable_out_to_sdram = ccdc_enable_output_to_sdram,
+		.set_hw_if_params = ccdc_set_hw_if_params,
+		.set_params = ccdc_set_params,
+		.configure = ccdc_configure,
+		.set_buftype = ccdc_set_buftype,
+		.get_buftype = ccdc_get_buftype,
+		.enum_pix = ccdc_enum_pix,
+		.set_pixel_format = ccdc_set_pixel_format,
+		.get_pixel_format = ccdc_get_pixel_format,
+		.set_frame_format = ccdc_set_frame_format,
+		.get_frame_format = ccdc_get_frame_format,
+		.set_image_window = ccdc_set_image_window,
+		.get_image_window = ccdc_get_image_window,
+		.get_line_length = ccdc_get_line_length,
+		.setfbaddr = ccdc_setfbaddr,
+		.getfid = ccdc_getfid,
+	},
+};
+
+static int __devinit dm355_ccdc_probe(struct platform_device *pdev)
+{
+	void (*setup_pinmux)(void);
+	struct resource	*res;
+	int status = 0;
+
+	/*
+	 * first try to register with vpfe. If not correct platform, then we
+	 * don't have to iomap
+	 */
+	status = vpfe_register_ccdc_device(&ccdc_hw_dev);
+	if (status < 0)
+		return status;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		status = -ENODEV;
+		goto fail_nores;
+	}
+
+	res = request_mem_region(res->start, resource_size(res), res->name);
+	if (!res) {
+		status = -EBUSY;
+		goto fail_nores;
+	}
+
+	ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res));
+	if (!ccdc_cfg.base_addr) {
+		status = -ENOMEM;
+		goto fail_nomem;
+	}
+
+	/* Get and enable Master clock */
+	ccdc_cfg.mclk = clk_get(&pdev->dev, "master");
+	if (IS_ERR(ccdc_cfg.mclk)) {
+		status = PTR_ERR(ccdc_cfg.mclk);
+		goto fail_nomap;
+	}
+	if (clk_enable(ccdc_cfg.mclk)) {
+		status = -ENODEV;
+		goto fail_mclk;
+	}
+
+	/* Get and enable Slave clock */
+	ccdc_cfg.sclk = clk_get(&pdev->dev, "slave");
+	if (IS_ERR(ccdc_cfg.sclk)) {
+		status = PTR_ERR(ccdc_cfg.sclk);
+		goto fail_mclk;
+	}
+	if (clk_enable(ccdc_cfg.sclk)) {
+		status = -ENODEV;
+		goto fail_sclk;
+	}
+
+	/* Platform data holds setup_pinmux function ptr */
+	if (NULL == pdev->dev.platform_data) {
+		status = -ENODEV;
+		goto fail_sclk;
+	}
+	setup_pinmux = pdev->dev.platform_data;
+	/*
+	 * setup Mux configuration for ccdc which may be different for
+	 * different SoCs using this CCDC
+	 */
+	setup_pinmux();
+	ccdc_cfg.dev = &pdev->dev;
+	printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);
+	return 0;
+fail_sclk:
+	clk_put(ccdc_cfg.sclk);
+fail_mclk:
+	clk_put(ccdc_cfg.mclk);
+fail_nomap:
+	iounmap(ccdc_cfg.base_addr);
+fail_nomem:
+	release_mem_region(res->start, resource_size(res));
+fail_nores:
+	vpfe_unregister_ccdc_device(&ccdc_hw_dev);
+	return status;
+}
+
+static int dm355_ccdc_remove(struct platform_device *pdev)
+{
+	struct resource	*res;
+
+	clk_put(ccdc_cfg.mclk);
+	clk_put(ccdc_cfg.sclk);
+	iounmap(ccdc_cfg.base_addr);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res)
+		release_mem_region(res->start, resource_size(res));
+	vpfe_unregister_ccdc_device(&ccdc_hw_dev);
+	return 0;
+}
+
+static struct platform_driver dm355_ccdc_driver = {
+	.driver = {
+		.name	= "dm355_ccdc",
+		.owner = THIS_MODULE,
+	},
+	.remove = __devexit_p(dm355_ccdc_remove),
+	.probe = dm355_ccdc_probe,
+};
+
+module_platform_driver(dm355_ccdc_driver);
diff --git a/drivers/media/platform/davinci/dm355_ccdc_regs.h b/drivers/media/platform/davinci/dm355_ccdc_regs.h
new file mode 100644
index 0000000..d6d2ef0
--- /dev/null
+++ b/drivers/media/platform/davinci/dm355_ccdc_regs.h
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2005-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _DM355_CCDC_REGS_H
+#define _DM355_CCDC_REGS_H
+
+/**************************************************************************\
+* Register OFFSET Definitions
+\**************************************************************************/
+#define SYNCEN				0x00
+#define MODESET				0x04
+#define HDWIDTH				0x08
+#define VDWIDTH				0x0c
+#define PPLN				0x10
+#define LPFR				0x14
+#define SPH				0x18
+#define NPH				0x1c
+#define SLV0				0x20
+#define SLV1				0x24
+#define NLV				0x28
+#define CULH				0x2c
+#define CULV				0x30
+#define HSIZE				0x34
+#define SDOFST				0x38
+#define STADRH				0x3c
+#define STADRL				0x40
+#define CLAMP				0x44
+#define DCSUB				0x48
+#define COLPTN				0x4c
+#define BLKCMP0				0x50
+#define BLKCMP1				0x54
+#define MEDFILT				0x58
+#define RYEGAIN				0x5c
+#define GRCYGAIN			0x60
+#define GBGGAIN				0x64
+#define BMGGAIN				0x68
+#define OFFSET				0x6c
+#define OUTCLIP				0x70
+#define VDINT0				0x74
+#define VDINT1				0x78
+#define RSV0				0x7c
+#define GAMMAWD				0x80
+#define REC656IF			0x84
+#define CCDCFG				0x88
+#define FMTCFG				0x8c
+#define FMTPLEN				0x90
+#define FMTSPH				0x94
+#define FMTLNH				0x98
+#define FMTSLV				0x9c
+#define FMTLNV				0xa0
+#define FMTRLEN				0xa4
+#define FMTHCNT				0xa8
+#define FMT_ADDR_PTR_B			0xac
+#define FMT_ADDR_PTR(i)			(FMT_ADDR_PTR_B + (i * 4))
+#define FMTPGM_VF0			0xcc
+#define FMTPGM_VF1			0xd0
+#define FMTPGM_AP0			0xd4
+#define FMTPGM_AP1			0xd8
+#define FMTPGM_AP2			0xdc
+#define FMTPGM_AP3                      0xe0
+#define FMTPGM_AP4                      0xe4
+#define FMTPGM_AP5                      0xe8
+#define FMTPGM_AP6                      0xec
+#define FMTPGM_AP7                      0xf0
+#define LSCCFG1                         0xf4
+#define LSCCFG2                         0xf8
+#define LSCH0                           0xfc
+#define LSCV0                           0x100
+#define LSCKH                           0x104
+#define LSCKV                           0x108
+#define LSCMEMCTL                       0x10c
+#define LSCMEMD                         0x110
+#define LSCMEMQ                         0x114
+#define DFCCTL                          0x118
+#define DFCVSAT                         0x11c
+#define DFCMEMCTL                       0x120
+#define DFCMEM0                         0x124
+#define DFCMEM1                         0x128
+#define DFCMEM2                         0x12c
+#define DFCMEM3                         0x130
+#define DFCMEM4                         0x134
+#define CSCCTL                          0x138
+#define CSCM0                           0x13c
+#define CSCM1                           0x140
+#define CSCM2                           0x144
+#define CSCM3                           0x148
+#define CSCM4                           0x14c
+#define CSCM5                           0x150
+#define CSCM6                           0x154
+#define CSCM7                           0x158
+#define DATAOFST			0x15c
+#define CCDC_REG_LAST			DATAOFST
+/**************************************************************
+*	Define for various register bit mask and shifts for CCDC
+*
+**************************************************************/
+#define CCDC_RAW_IP_MODE			0
+#define CCDC_VDHDOUT_INPUT			0
+#define CCDC_YCINSWP_RAW			(0 << 4)
+#define CCDC_EXWEN_DISABLE 			0
+#define CCDC_DATAPOL_NORMAL			0
+#define CCDC_CCDCFG_FIDMD_LATCH_VSYNC		0
+#define CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC	(1 << 6)
+#define CCDC_CCDCFG_WENLOG_AND			0
+#define CCDC_CCDCFG_TRGSEL_WEN			0
+#define CCDC_CCDCFG_EXTRG_DISABLE		0
+#define CCDC_CFA_MOSAIC				0
+#define CCDC_Y8POS_SHIFT			11
+
+#define CCDC_VDC_DFCVSAT_MASK			0x3fff
+#define CCDC_DATAOFST_MASK			0x0ff
+#define CCDC_DATAOFST_H_SHIFT			0
+#define CCDC_DATAOFST_V_SHIFT			8
+#define CCDC_GAMMAWD_CFA_MASK			1
+#define CCDC_GAMMAWD_CFA_SHIFT			5
+#define CCDC_GAMMAWD_INPUT_SHIFT		2
+#define CCDC_FID_POL_MASK			1
+#define CCDC_FID_POL_SHIFT			4
+#define CCDC_HD_POL_MASK			1
+#define CCDC_HD_POL_SHIFT			3
+#define CCDC_VD_POL_MASK			1
+#define CCDC_VD_POL_SHIFT			2
+#define CCDC_VD_POL_NEGATIVE			(1 << 2)
+#define CCDC_FRM_FMT_MASK			1
+#define CCDC_FRM_FMT_SHIFT			7
+#define CCDC_DATA_SZ_MASK			7
+#define CCDC_DATA_SZ_SHIFT			8
+#define CCDC_VDHDOUT_MASK			1
+#define CCDC_VDHDOUT_SHIFT			0
+#define CCDC_EXWEN_MASK				1
+#define CCDC_EXWEN_SHIFT			5
+#define CCDC_INPUT_MODE_MASK			3
+#define CCDC_INPUT_MODE_SHIFT			12
+#define CCDC_PIX_FMT_MASK			3
+#define CCDC_PIX_FMT_SHIFT			12
+#define CCDC_DATAPOL_MASK			1
+#define CCDC_DATAPOL_SHIFT			6
+#define CCDC_WEN_ENABLE				(1 << 1)
+#define CCDC_VDHDEN_ENABLE			(1 << 16)
+#define CCDC_LPF_ENABLE				(1 << 14)
+#define CCDC_ALAW_ENABLE			1
+#define CCDC_ALAW_GAMA_WD_MASK			7
+#define CCDC_REC656IF_BT656_EN			3
+
+#define CCDC_FMTCFG_FMTMODE_MASK 		3
+#define CCDC_FMTCFG_FMTMODE_SHIFT		1
+#define CCDC_FMTCFG_LNUM_MASK			3
+#define CCDC_FMTCFG_LNUM_SHIFT			4
+#define CCDC_FMTCFG_ADDRINC_MASK		7
+#define CCDC_FMTCFG_ADDRINC_SHIFT		8
+
+#define CCDC_CCDCFG_FIDMD_SHIFT			6
+#define	CCDC_CCDCFG_WENLOG_SHIFT		8
+#define CCDC_CCDCFG_TRGSEL_SHIFT		9
+#define CCDC_CCDCFG_EXTRG_SHIFT			10
+#define CCDC_CCDCFG_MSBINVI_SHIFT		13
+
+#define CCDC_HSIZE_FLIP_SHIFT			12
+#define CCDC_HSIZE_FLIP_MASK			1
+#define CCDC_HSIZE_VAL_MASK			0xFFF
+#define CCDC_SDOFST_FIELD_INTERLEAVED		0x249
+#define CCDC_SDOFST_INTERLACE_INVERSE		0x4B6D
+#define CCDC_SDOFST_INTERLACE_NORMAL		0x0B6D
+#define CCDC_SDOFST_PROGRESSIVE_INVERSE		0x4000
+#define CCDC_SDOFST_PROGRESSIVE_NORMAL		0
+#define CCDC_START_PX_HOR_MASK			0x7FFF
+#define CCDC_NUM_PX_HOR_MASK			0x7FFF
+#define CCDC_START_VER_ONE_MASK			0x7FFF
+#define CCDC_START_VER_TWO_MASK			0x7FFF
+#define CCDC_NUM_LINES_VER			0x7FFF
+
+#define CCDC_BLK_CLAMP_ENABLE			(1 << 15)
+#define CCDC_BLK_SGAIN_MASK			0x1F
+#define CCDC_BLK_ST_PXL_MASK			0x1FFF
+#define CCDC_BLK_SAMPLE_LN_MASK			3
+#define CCDC_BLK_SAMPLE_LN_SHIFT		13
+
+#define CCDC_NUM_LINE_CALC_MASK			3
+#define CCDC_NUM_LINE_CALC_SHIFT		14
+
+#define CCDC_BLK_DC_SUB_MASK			0x3FFF
+#define CCDC_BLK_COMP_MASK			0xFF
+#define CCDC_BLK_COMP_GB_COMP_SHIFT		8
+#define CCDC_BLK_COMP_GR_COMP_SHIFT		0
+#define CCDC_BLK_COMP_R_COMP_SHIFT		8
+#define CCDC_LATCH_ON_VSYNC_DISABLE		(1 << 15)
+#define CCDC_LATCH_ON_VSYNC_ENABLE		(0 << 15)
+#define CCDC_FPC_ENABLE				(1 << 15)
+#define CCDC_FPC_FPC_NUM_MASK 			0x7FFF
+#define CCDC_DATA_PACK_ENABLE			(1 << 11)
+#define CCDC_FMT_HORZ_FMTLNH_MASK		0x1FFF
+#define CCDC_FMT_HORZ_FMTSPH_MASK		0x1FFF
+#define CCDC_FMT_HORZ_FMTSPH_SHIFT		16
+#define CCDC_FMT_VERT_FMTLNV_MASK		0x1FFF
+#define CCDC_FMT_VERT_FMTSLV_MASK		0x1FFF
+#define CCDC_FMT_VERT_FMTSLV_SHIFT		16
+#define CCDC_VP_OUT_VERT_NUM_MASK		0x3FFF
+#define CCDC_VP_OUT_VERT_NUM_SHIFT		17
+#define CCDC_VP_OUT_HORZ_NUM_MASK		0x1FFF
+#define CCDC_VP_OUT_HORZ_NUM_SHIFT		4
+#define CCDC_VP_OUT_HORZ_ST_MASK		0xF
+
+#define CCDC_CSC_COEF_INTEG_MASK		7
+#define CCDC_CSC_COEF_DECIMAL_MASK		0x1f
+#define CCDC_CSC_COEF_INTEG_SHIFT		5
+#define CCDC_CSCM_MSB_SHIFT			8
+#define CCDC_CSC_ENABLE				1
+#define CCDC_CSC_DEC_MAX			32
+
+#define CCDC_MFILT1_SHIFT			10
+#define CCDC_MFILT2_SHIFT			8
+#define CCDC_MED_FILT_THRESH			0x3FFF
+#define CCDC_LPF_MASK				1
+#define CCDC_LPF_SHIFT				14
+#define CCDC_OFFSET_MASK			0x3FF
+#define CCDC_DATASFT_MASK			7
+#define CCDC_DATASFT_SHIFT			8
+
+#define CCDC_DF_ENABLE				1
+
+#define CCDC_FMTPLEN_P0_MASK			0xF
+#define CCDC_FMTPLEN_P1_MASK			0xF
+#define CCDC_FMTPLEN_P2_MASK			7
+#define CCDC_FMTPLEN_P3_MASK			7
+#define CCDC_FMTPLEN_P0_SHIFT			0
+#define CCDC_FMTPLEN_P1_SHIFT			4
+#define CCDC_FMTPLEN_P2_SHIFT			8
+#define CCDC_FMTPLEN_P3_SHIFT			12
+
+#define CCDC_FMTSPH_MASK			0x1FFF
+#define CCDC_FMTLNH_MASK			0x1FFF
+#define CCDC_FMTSLV_MASK			0x1FFF
+#define CCDC_FMTLNV_MASK			0x7FFF
+#define CCDC_FMTRLEN_MASK			0x1FFF
+#define CCDC_FMTHCNT_MASK			0x1FFF
+
+#define CCDC_ADP_INIT_MASK			0x1FFF
+#define CCDC_ADP_LINE_SHIFT			13
+#define CCDC_ADP_LINE_MASK			3
+#define CCDC_FMTPGN_APTR_MASK			7
+
+#define CCDC_DFCCTL_GDFCEN_MASK			1
+#define CCDC_DFCCTL_VDFCEN_MASK			1
+#define CCDC_DFCCTL_VDFC_DISABLE		(0 << 4)
+#define CCDC_DFCCTL_VDFCEN_SHIFT		4
+#define CCDC_DFCCTL_VDFCSL_MASK			3
+#define CCDC_DFCCTL_VDFCSL_SHIFT		5
+#define CCDC_DFCCTL_VDFCUDA_MASK		1
+#define CCDC_DFCCTL_VDFCUDA_SHIFT		7
+#define CCDC_DFCCTL_VDFLSFT_MASK		3
+#define CCDC_DFCCTL_VDFLSFT_SHIFT		8
+#define CCDC_DFCMEMCTL_DFCMARST_MASK		1
+#define CCDC_DFCMEMCTL_DFCMARST_SHIFT		2
+#define CCDC_DFCMEMCTL_DFCMWR_MASK		1
+#define CCDC_DFCMEMCTL_DFCMWR_SHIFT		0
+#define CCDC_DFCMEMCTL_INC_ADDR			(0 << 2)
+
+#define CCDC_LSCCFG_GFTSF_MASK			7
+#define CCDC_LSCCFG_GFTSF_SHIFT			1
+#define CCDC_LSCCFG_GFTINV_MASK			0xf
+#define CCDC_LSCCFG_GFTINV_SHIFT		4
+#define CCDC_LSC_GFTABLE_SEL_MASK		3
+#define CCDC_LSC_GFTABLE_EPEL_SHIFT		8
+#define CCDC_LSC_GFTABLE_OPEL_SHIFT		10
+#define CCDC_LSC_GFTABLE_EPOL_SHIFT		12
+#define CCDC_LSC_GFTABLE_OPOL_SHIFT		14
+#define CCDC_LSC_GFMODE_MASK			3
+#define CCDC_LSC_GFMODE_SHIFT			4
+#define CCDC_LSC_DISABLE			0
+#define CCDC_LSC_ENABLE				1
+#define CCDC_LSC_TABLE1_SLC			0
+#define CCDC_LSC_TABLE2_SLC			1
+#define CCDC_LSC_TABLE3_SLC			2
+#define CCDC_LSC_MEMADDR_RESET			(1 << 2)
+#define CCDC_LSC_MEMADDR_INCR			(0 << 2)
+#define CCDC_LSC_FRAC_MASK_T1			0xFF
+#define CCDC_LSC_INT_MASK			3
+#define CCDC_LSC_FRAC_MASK			0x3FFF
+#define CCDC_LSC_CENTRE_MASK			0x3FFF
+#define CCDC_LSC_COEF_MASK			0xff
+#define CCDC_LSC_COEFL_SHIFT			0
+#define CCDC_LSC_COEFU_SHIFT			8
+#define CCDC_GAIN_MASK				0x7FF
+#define CCDC_SYNCEN_VDHDEN_MASK			(1 << 0)
+#define CCDC_SYNCEN_WEN_MASK			(1 << 1)
+#define CCDC_SYNCEN_WEN_SHIFT			1
+
+/* Power on Defaults in hardware */
+#define MODESET_DEFAULT				0x200
+#define CULH_DEFAULT				0xFFFF
+#define CULV_DEFAULT				0xFF
+#define GAIN_DEFAULT				256
+#define OUTCLIP_DEFAULT				0x3FFF
+#define LSCCFG2_DEFAULT				0xE
+
+#endif
diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c
new file mode 100644
index 0000000..ee7942b
--- /dev/null
+++ b/drivers/media/platform/davinci/dm644x_ccdc.c
@@ -0,0 +1,1081 @@
+/*
+ * Copyright (C) 2006-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * CCDC hardware module for DM6446
+ * ------------------------------
+ *
+ * This module is for configuring CCD controller of DM6446 VPFE to capture
+ * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
+ * such as Defect Pixel Correction, Color Space Conversion etc to
+ * pre-process the Raw Bayer RGB data, before writing it to SDRAM. This
+ * module also allows application to configure individual
+ * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL.
+ * To do so, application includes dm644x_ccdc.h and vpfe_capture.h header
+ * files.  The setparams() API is called by vpfe_capture driver
+ * to configure module parameters. This file is named DM644x so that other
+ * variants such DM6443 may be supported using the same module.
+ *
+ * TODO: Test Raw bayer parameter settings and bayer capture
+ * 	 Split module parameter structure to module specific ioctl structs
+ * 	 investigate if enum used for user space type definition
+ * 	 to be replaced by #defines or integer
+ */
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/videodev2.h>
+#include <linux/gfp.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+
+#include <media/davinci/dm644x_ccdc.h>
+#include <media/davinci/vpss.h>
+
+#include "dm644x_ccdc_regs.h"
+#include "ccdc_hw_device.h"
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CCDC Driver for DM6446");
+MODULE_AUTHOR("Texas Instruments");
+
+static struct ccdc_oper_config {
+	struct device *dev;
+	/* CCDC interface type */
+	enum vpfe_hw_if_type if_type;
+	/* Raw Bayer configuration */
+	struct ccdc_params_raw bayer;
+	/* YCbCr configuration */
+	struct ccdc_params_ycbcr ycbcr;
+	/* Master clock */
+	struct clk *mclk;
+	/* slave clock */
+	struct clk *sclk;
+	/* ccdc base address */
+	void __iomem *base_addr;
+} ccdc_cfg = {
+	/* Raw configurations */
+	.bayer = {
+		.pix_fmt = CCDC_PIXFMT_RAW,
+		.frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
+		.win = CCDC_WIN_VGA,
+		.fid_pol = VPFE_PINPOL_POSITIVE,
+		.vd_pol = VPFE_PINPOL_POSITIVE,
+		.hd_pol = VPFE_PINPOL_POSITIVE,
+		.config_params = {
+			.data_sz = CCDC_DATA_10BITS,
+		},
+	},
+	.ycbcr = {
+		.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
+		.frm_fmt = CCDC_FRMFMT_INTERLACED,
+		.win = CCDC_WIN_PAL,
+		.fid_pol = VPFE_PINPOL_POSITIVE,
+		.vd_pol = VPFE_PINPOL_POSITIVE,
+		.hd_pol = VPFE_PINPOL_POSITIVE,
+		.bt656_enable = 1,
+		.pix_order = CCDC_PIXORDER_CBYCRY,
+		.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
+	},
+};
+
+#define CCDC_MAX_RAW_YUV_FORMATS	2
+
+/* Raw Bayer formats */
+static u32 ccdc_raw_bayer_pix_formats[] =
+	{V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
+
+/* Raw YUV formats */
+static u32 ccdc_raw_yuv_pix_formats[] =
+	{V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
+
+/* CCDC Save/Restore context */
+static u32 ccdc_ctx[CCDC_REG_END / sizeof(u32)];
+
+/* register access routines */
+static inline u32 regr(u32 offset)
+{
+	return __raw_readl(ccdc_cfg.base_addr + offset);
+}
+
+static inline void regw(u32 val, u32 offset)
+{
+	__raw_writel(val, ccdc_cfg.base_addr + offset);
+}
+
+static void ccdc_enable(int flag)
+{
+	regw(flag, CCDC_PCR);
+}
+
+static void ccdc_enable_vport(int flag)
+{
+	if (flag)
+		/* enable video port */
+		regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG);
+	else
+		regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG);
+}
+
+/*
+ * ccdc_setwin()
+ * This function will configure the window size
+ * to be capture in CCDC reg
+ */
+void ccdc_setwin(struct v4l2_rect *image_win,
+		enum ccdc_frmfmt frm_fmt,
+		int ppc)
+{
+	int horz_start, horz_nr_pixels;
+	int vert_start, vert_nr_lines;
+	int val = 0, mid_img = 0;
+
+	dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin...");
+	/*
+	 * ppc - per pixel count. indicates how many pixels per cell
+	 * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
+	 * raw capture this is 1
+	 */
+	horz_start = image_win->left << (ppc - 1);
+	horz_nr_pixels = (image_win->width << (ppc - 1)) - 1;
+	regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels,
+	     CCDC_HORZ_INFO);
+
+	vert_start = image_win->top;
+
+	if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+		vert_nr_lines = (image_win->height >> 1) - 1;
+		vert_start >>= 1;
+		/* Since first line doesn't have any data */
+		vert_start += 1;
+		/* configure VDINT0 */
+		val = (vert_start << CCDC_VDINT_VDINT0_SHIFT);
+		regw(val, CCDC_VDINT);
+
+	} else {
+		/* Since first line doesn't have any data */
+		vert_start += 1;
+		vert_nr_lines = image_win->height - 1;
+		/*
+		 * configure VDINT0 and VDINT1. VDINT1 will be at half
+		 * of image height
+		 */
+		mid_img = vert_start + (image_win->height / 2);
+		val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) |
+		    (mid_img & CCDC_VDINT_VDINT1_MASK);
+		regw(val, CCDC_VDINT);
+
+	}
+	regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start,
+	     CCDC_VERT_START);
+	regw(vert_nr_lines, CCDC_VERT_LINES);
+	dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin...");
+}
+
+static void ccdc_readregs(void)
+{
+	unsigned int val = 0;
+
+	val = regr(CCDC_ALAW);
+	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to ALAW...\n", val);
+	val = regr(CCDC_CLAMP);
+	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to CLAMP...\n", val);
+	val = regr(CCDC_DCSUB);
+	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to DCSUB...\n", val);
+	val = regr(CCDC_BLKCMP);
+	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to BLKCMP...\n", val);
+	val = regr(CCDC_FPC_ADDR);
+	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC_ADDR...\n", val);
+	val = regr(CCDC_FPC);
+	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC...\n", val);
+	val = regr(CCDC_FMTCFG);
+	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMTCFG...\n", val);
+	val = regr(CCDC_COLPTN);
+	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to COLPTN...\n", val);
+	val = regr(CCDC_FMT_HORZ);
+	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_HORZ...\n", val);
+	val = regr(CCDC_FMT_VERT);
+	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_VERT...\n", val);
+	val = regr(CCDC_HSIZE_OFF);
+	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HSIZE_OFF...\n", val);
+	val = regr(CCDC_SDOFST);
+	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SDOFST...\n", val);
+	val = regr(CCDC_VP_OUT);
+	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VP_OUT...\n", val);
+	val = regr(CCDC_SYN_MODE);
+	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SYN_MODE...\n", val);
+	val = regr(CCDC_HORZ_INFO);
+	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HORZ_INFO...\n", val);
+	val = regr(CCDC_VERT_START);
+	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_START...\n", val);
+	val = regr(CCDC_VERT_LINES);
+	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_LINES...\n", val);
+}
+
+static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
+{
+	if (ccdcparam->alaw.enable) {
+		if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) ||
+		    (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) ||
+		    (ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) {
+			dev_dbg(ccdc_cfg.dev, "\nInvalid data line select");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params)
+{
+	struct ccdc_config_params_raw *config_params =
+				&ccdc_cfg.bayer.config_params;
+	unsigned int *fpc_virtaddr = NULL;
+	unsigned int *fpc_physaddr = NULL;
+
+	memcpy(config_params, raw_params, sizeof(*raw_params));
+	/*
+	 * allocate memory for fault pixel table and copy the user
+	 * values to the table
+	 */
+	if (!config_params->fault_pxl.enable)
+		return 0;
+
+	fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;
+	fpc_virtaddr = (unsigned int *)phys_to_virt(
+				(unsigned long)fpc_physaddr);
+	/*
+	 * Allocate memory for FPC table if current
+	 * FPC table buffer is not big enough to
+	 * accommodate FPC Number requested
+	 */
+	if (raw_params->fault_pxl.fp_num != config_params->fault_pxl.fp_num) {
+		if (fpc_physaddr != NULL) {
+			free_pages((unsigned long)fpc_physaddr,
+				   get_order
+				   (config_params->fault_pxl.fp_num *
+				   FP_NUM_BYTES));
+		}
+
+		/* Allocate memory for FPC table */
+		fpc_virtaddr =
+			(unsigned int *)__get_free_pages(GFP_KERNEL | GFP_DMA,
+							 get_order(raw_params->
+							 fault_pxl.fp_num *
+							 FP_NUM_BYTES));
+
+		if (fpc_virtaddr == NULL) {
+			dev_dbg(ccdc_cfg.dev,
+				"\nUnable to allocate memory for FPC");
+			return -EFAULT;
+		}
+		fpc_physaddr =
+		    (unsigned int *)virt_to_phys((void *)fpc_virtaddr);
+	}
+
+	/* Copy number of fault pixels and FPC table */
+	config_params->fault_pxl.fp_num = raw_params->fault_pxl.fp_num;
+	if (copy_from_user(fpc_virtaddr,
+			(void __user *)raw_params->fault_pxl.fpc_table_addr,
+			config_params->fault_pxl.fp_num * FP_NUM_BYTES)) {
+		dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed");
+		return -EFAULT;
+	}
+	config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr;
+	return 0;
+}
+
+static int ccdc_close(struct device *dev)
+{
+	struct ccdc_config_params_raw *config_params =
+				&ccdc_cfg.bayer.config_params;
+	unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL;
+
+	fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;
+
+	if (fpc_physaddr != NULL) {
+		fpc_virtaddr = (unsigned int *)
+		    phys_to_virt((unsigned long)fpc_physaddr);
+		free_pages((unsigned long)fpc_virtaddr,
+			   get_order(config_params->fault_pxl.fp_num *
+			   FP_NUM_BYTES));
+	}
+	return 0;
+}
+
+/*
+ * ccdc_restore_defaults()
+ * This function will write defaults to all CCDC registers
+ */
+static void ccdc_restore_defaults(void)
+{
+	int i;
+
+	/* disable CCDC */
+	ccdc_enable(0);
+	/* set all registers to default value */
+	for (i = 4; i <= 0x94; i += 4)
+		regw(0,  i);
+	regw(CCDC_NO_CULLING, CCDC_CULLING);
+	regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW);
+}
+
+static int ccdc_open(struct device *device)
+{
+	ccdc_restore_defaults();
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+		ccdc_enable_vport(1);
+	return 0;
+}
+
+static void ccdc_sbl_reset(void)
+{
+	vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O);
+}
+
+/* Parameter operations */
+static int ccdc_set_params(void __user *params)
+{
+	struct ccdc_config_params_raw ccdc_raw_params;
+	int x;
+
+	if (ccdc_cfg.if_type != VPFE_RAW_BAYER)
+		return -EINVAL;
+
+	x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
+	if (x) {
+		dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying"
+			   "ccdc params, %d\n", x);
+		return -EFAULT;
+	}
+
+	if (!validate_ccdc_param(&ccdc_raw_params)) {
+		if (!ccdc_update_raw_params(&ccdc_raw_params))
+			return 0;
+	}
+	return -EINVAL;
+}
+
+/*
+ * ccdc_config_ycbcr()
+ * This function will configure CCDC for YCbCr video capture
+ */
+void ccdc_config_ycbcr(void)
+{
+	struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
+	u32 syn_mode;
+
+	dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr...");
+	/*
+	 * first restore the CCDC registers to default values
+	 * This is important since we assume default values to be set in
+	 * a lot of registers that we didn't touch
+	 */
+	ccdc_restore_defaults();
+
+	/*
+	 * configure pixel format, frame format, configure video frame
+	 * format, enable output to SDRAM, enable internal timing generator
+	 * and 8bit pack mode
+	 */
+	syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) <<
+		    CCDC_SYN_MODE_INPMOD_SHIFT) |
+		    ((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) <<
+		    CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE |
+		    CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE);
+
+	/* setup BT.656 sync mode */
+	if (params->bt656_enable) {
+		regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF);
+
+		/*
+		 * configure the FID, VD, HD pin polarity,
+		 * fld,hd pol positive, vd negative, 8-bit data
+		 */
+		syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE;
+		if (ccdc_cfg.if_type == VPFE_BT656_10BIT)
+			syn_mode |= CCDC_SYN_MODE_10BITS;
+		else
+			syn_mode |= CCDC_SYN_MODE_8BITS;
+	} else {
+		/* y/c external sync mode */
+		syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
+			     CCDC_FID_POL_SHIFT) |
+			     ((params->hd_pol & CCDC_HD_POL_MASK) <<
+			     CCDC_HD_POL_SHIFT) |
+			     ((params->vd_pol & CCDC_VD_POL_MASK) <<
+			     CCDC_VD_POL_SHIFT));
+	}
+	regw(syn_mode, CCDC_SYN_MODE);
+
+	/* configure video window */
+	ccdc_setwin(&params->win, params->frm_fmt, 2);
+
+	/*
+	 * configure the order of y cb cr in SDRAM, and disable latch
+	 * internal register on vsync
+	 */
+	if (ccdc_cfg.if_type == VPFE_BT656_10BIT)
+		regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
+			CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_BW656_10BIT,
+			CCDC_CCDCFG);
+	else
+		regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
+			CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
+
+	/*
+	 * configure the horizontal line offset. This should be a
+	 * on 32 byte boundary. So clear LSB 5 bits
+	 */
+	regw(((params->win.width * 2  + 31) & ~0x1f), CCDC_HSIZE_OFF);
+
+	/* configure the memory line offset */
+	if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)
+		/* two fields are interleaved in memory */
+		regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST);
+
+	ccdc_sbl_reset();
+	dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n");
+}
+
+static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
+{
+	u32 val;
+
+	if (!bclamp->enable) {
+		/* configure DCSub */
+		val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK;
+		regw(val, CCDC_DCSUB);
+		dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to DCSUB...\n", val);
+		regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP);
+		dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to CLAMP...\n");
+		return;
+	}
+	/*
+	 * Configure gain,  Start pixel, No of line to be avg,
+	 * No of pixel/line to be avg, & Enable the Black clamping
+	 */
+	val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) |
+	       ((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) <<
+		CCDC_BLK_ST_PXL_SHIFT) |
+	       ((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) <<
+		CCDC_BLK_SAMPLE_LINE_SHIFT) |
+	       ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
+		CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE);
+	regw(val, CCDC_CLAMP);
+	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val);
+	/* If Black clamping is enable then make dcsub 0 */
+	regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB);
+	dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n");
+}
+
+static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
+{
+	u32 val;
+
+	val = ((bcomp->b & CCDC_BLK_COMP_MASK) |
+	      ((bcomp->gb & CCDC_BLK_COMP_MASK) <<
+	       CCDC_BLK_COMP_GB_COMP_SHIFT) |
+	      ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
+	       CCDC_BLK_COMP_GR_COMP_SHIFT) |
+	      ((bcomp->r & CCDC_BLK_COMP_MASK) <<
+	       CCDC_BLK_COMP_R_COMP_SHIFT));
+	regw(val, CCDC_BLKCMP);
+}
+
+static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc)
+{
+	u32 val;
+
+	/* Initially disable FPC */
+	val = CCDC_FPC_DISABLE;
+	regw(val, CCDC_FPC);
+
+	if (!fpc->enable)
+		return;
+
+	/* Configure Fault pixel if needed */
+	regw(fpc->fpc_table_addr, CCDC_FPC_ADDR);
+	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC_ADDR...\n",
+		       (fpc->fpc_table_addr));
+	/* Write the FPC params with FPC disable */
+	val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK;
+	regw(val, CCDC_FPC);
+
+	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val);
+	/* read the FPC register */
+	val = regr(CCDC_FPC) | CCDC_FPC_ENABLE;
+	regw(val, CCDC_FPC);
+	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val);
+}
+
+/*
+ * ccdc_config_raw()
+ * This function will configure CCDC for Raw capture mode
+ */
+void ccdc_config_raw(void)
+{
+	struct ccdc_params_raw *params = &ccdc_cfg.bayer;
+	struct ccdc_config_params_raw *config_params =
+				&ccdc_cfg.bayer.config_params;
+	unsigned int syn_mode = 0;
+	unsigned int val;
+
+	dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw...");
+
+	/*      Reset CCDC */
+	ccdc_restore_defaults();
+
+	/* Disable latching function registers on VSYNC  */
+	regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
+
+	/*
+	 * Configure the vertical sync polarity(SYN_MODE.VDPOL),
+	 * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity
+	 * (SYN_MODE.FLDPOL), frame format(progressive or interlace),
+	 * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output
+	 * SDRAM, enable internal timing generator
+	 */
+	syn_mode =
+		(((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
+		((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
+		((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
+		((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
+		((config_params->data_sz & CCDC_DATA_SZ_MASK) <<
+		CCDC_DATA_SZ_SHIFT) |
+		((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) |
+		CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE);
+
+	/* Enable and configure aLaw register if needed */
+	if (config_params->alaw.enable) {
+		val = ((config_params->alaw.gama_wd &
+		      CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE);
+		regw(val, CCDC_ALAW);
+		dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val);
+	}
+
+	/* Configure video window */
+	ccdc_setwin(&params->win, params->frm_fmt, CCDC_PPC_RAW);
+
+	/* Configure Black Clamp */
+	ccdc_config_black_clamp(&config_params->blk_clamp);
+
+	/* Configure Black level compensation */
+	ccdc_config_black_compense(&config_params->blk_comp);
+
+	/* Configure Fault Pixel Correction */
+	ccdc_config_fpc(&config_params->fault_pxl);
+
+	/* If data size is 8 bit then pack the data */
+	if ((config_params->data_sz == CCDC_DATA_8BITS) ||
+	     config_params->alaw.enable)
+		syn_mode |= CCDC_DATA_PACK_ENABLE;
+
+#ifdef CONFIG_DM644X_VIDEO_PORT_ENABLE
+	/* enable video port */
+	val = CCDC_ENABLE_VIDEO_PORT;
+#else
+	/* disable video port */
+	val = CCDC_DISABLE_VIDEO_PORT;
+#endif
+
+	if (config_params->data_sz == CCDC_DATA_8BITS)
+		val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK)
+		    << CCDC_FMTCFG_VPIN_SHIFT;
+	else
+		val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK)
+		    << CCDC_FMTCFG_VPIN_SHIFT;
+	/* Write value in FMTCFG */
+	regw(val, CCDC_FMTCFG);
+
+	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val);
+	/* Configure the color pattern according to mt9t001 sensor */
+	regw(CCDC_COLPTN_VAL, CCDC_COLPTN);
+
+	dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n");
+	/*
+	 * Configure Data formatter(Video port) pixel selection
+	 * (FMT_HORZ, FMT_VERT)
+	 */
+	val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) <<
+	      CCDC_FMT_HORZ_FMTSPH_SHIFT) |
+	      (params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK);
+	regw(val, CCDC_FMT_HORZ);
+
+	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val);
+	val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK)
+	    << CCDC_FMT_VERT_FMTSLV_SHIFT;
+	if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
+		val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK;
+	else
+		val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK;
+
+	dev_dbg(ccdc_cfg.dev, "\nparams->win.height  0x%x ...\n",
+	       params->win.height);
+	regw(val, CCDC_FMT_VERT);
+
+	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_VERT...\n", val);
+
+	dev_dbg(ccdc_cfg.dev, "\nbelow regw(val, FMT_VERT)...");
+
+	/*
+	 * Configure Horizontal offset register. If pack 8 is enabled then
+	 * 1 pixel will take 1 byte
+	 */
+	if ((config_params->data_sz == CCDC_DATA_8BITS) ||
+	    config_params->alaw.enable)
+		regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) &
+		    CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF);
+	else
+		/* else one pixel will take 2 byte */
+		regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) +
+		    CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK,
+		    CCDC_HSIZE_OFF);
+
+	/* Set value for SDOFST */
+	if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
+		if (params->image_invert_enable) {
+			/* For intelace inverse mode */
+			regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST);
+			dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n");
+		}
+
+		else {
+			/* For intelace non inverse mode */
+			regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST);
+			dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n");
+		}
+	} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
+		regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST);
+		dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to SDOFST...\n");
+	}
+
+	/*
+	 * Configure video port pixel selection (VPOUT)
+	 * Here -1 is to make the height value less than FMT_VERT.FMTLNV
+	 */
+	if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
+		val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK))
+		    << CCDC_VP_OUT_VERT_NUM_SHIFT;
+	else
+		val =
+		    ((((params->win.height >> CCDC_INTERLACED_HEIGHT_SHIFT) -
+		     1) & CCDC_VP_OUT_VERT_NUM_MASK)) <<
+		    CCDC_VP_OUT_VERT_NUM_SHIFT;
+
+	val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK)
+	    << CCDC_VP_OUT_HORZ_NUM_SHIFT;
+	val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK;
+	regw(val, CCDC_VP_OUT);
+
+	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to VP_OUT...\n", val);
+	regw(syn_mode, CCDC_SYN_MODE);
+	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode);
+
+	ccdc_sbl_reset();
+	dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw...");
+	ccdc_readregs();
+}
+
+static int ccdc_configure(void)
+{
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+		ccdc_config_raw();
+	else
+		ccdc_config_ycbcr();
+	return 0;
+}
+
+static int ccdc_set_buftype(enum ccdc_buftype buf_type)
+{
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+		ccdc_cfg.bayer.buf_type = buf_type;
+	else
+		ccdc_cfg.ycbcr.buf_type = buf_type;
+	return 0;
+}
+
+static enum ccdc_buftype ccdc_get_buftype(void)
+{
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+		return ccdc_cfg.bayer.buf_type;
+	return ccdc_cfg.ycbcr.buf_type;
+}
+
+static int ccdc_enum_pix(u32 *pix, int i)
+{
+	int ret = -EINVAL;
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
+		if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
+			*pix = ccdc_raw_bayer_pix_formats[i];
+			ret = 0;
+		}
+	} else {
+		if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
+			*pix = ccdc_raw_yuv_pix_formats[i];
+			ret = 0;
+		}
+	}
+	return ret;
+}
+
+static int ccdc_set_pixel_format(u32 pixfmt)
+{
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
+		ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
+		if (pixfmt == V4L2_PIX_FMT_SBGGR8)
+			ccdc_cfg.bayer.config_params.alaw.enable = 1;
+		else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
+			return -EINVAL;
+	} else {
+		if (pixfmt == V4L2_PIX_FMT_YUYV)
+			ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
+		else if (pixfmt == V4L2_PIX_FMT_UYVY)
+			ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+		else
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static u32 ccdc_get_pixel_format(void)
+{
+	struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
+	u32 pixfmt;
+
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+		if (alaw->enable)
+			pixfmt = V4L2_PIX_FMT_SBGGR8;
+		else
+			pixfmt = V4L2_PIX_FMT_SBGGR16;
+	else {
+		if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
+			pixfmt = V4L2_PIX_FMT_YUYV;
+		else
+			pixfmt = V4L2_PIX_FMT_UYVY;
+	}
+	return pixfmt;
+}
+
+static int ccdc_set_image_window(struct v4l2_rect *win)
+{
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+		ccdc_cfg.bayer.win = *win;
+	else
+		ccdc_cfg.ycbcr.win = *win;
+	return 0;
+}
+
+static void ccdc_get_image_window(struct v4l2_rect *win)
+{
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+		*win = ccdc_cfg.bayer.win;
+	else
+		*win = ccdc_cfg.ycbcr.win;
+}
+
+static unsigned int ccdc_get_line_length(void)
+{
+	struct ccdc_config_params_raw *config_params =
+				&ccdc_cfg.bayer.config_params;
+	unsigned int len;
+
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
+		if ((config_params->alaw.enable) ||
+		    (config_params->data_sz == CCDC_DATA_8BITS))
+			len = ccdc_cfg.bayer.win.width;
+		else
+			len = ccdc_cfg.bayer.win.width * 2;
+	} else
+		len = ccdc_cfg.ycbcr.win.width * 2;
+	return ALIGN(len, 32);
+}
+
+static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
+{
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+		ccdc_cfg.bayer.frm_fmt = frm_fmt;
+	else
+		ccdc_cfg.ycbcr.frm_fmt = frm_fmt;
+	return 0;
+}
+
+static enum ccdc_frmfmt ccdc_get_frame_format(void)
+{
+	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+		return ccdc_cfg.bayer.frm_fmt;
+	else
+		return ccdc_cfg.ycbcr.frm_fmt;
+}
+
+static int ccdc_getfid(void)
+{
+	return (regr(CCDC_SYN_MODE) >> 15) & 1;
+}
+
+/* misc operations */
+static inline void ccdc_setfbaddr(unsigned long addr)
+{
+	regw(addr & 0xffffffe0, CCDC_SDR_ADDR);
+}
+
+static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
+{
+	ccdc_cfg.if_type = params->if_type;
+
+	switch (params->if_type) {
+	case VPFE_BT656:
+	case VPFE_YCBCR_SYNC_16:
+	case VPFE_YCBCR_SYNC_8:
+	case VPFE_BT656_10BIT:
+		ccdc_cfg.ycbcr.vd_pol = params->vdpol;
+		ccdc_cfg.ycbcr.hd_pol = params->hdpol;
+		break;
+	default:
+		/* TODO add support for raw bayer here */
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void ccdc_save_context(void)
+{
+	ccdc_ctx[CCDC_PCR >> 2] = regr(CCDC_PCR);
+	ccdc_ctx[CCDC_SYN_MODE >> 2] = regr(CCDC_SYN_MODE);
+	ccdc_ctx[CCDC_HD_VD_WID >> 2] = regr(CCDC_HD_VD_WID);
+	ccdc_ctx[CCDC_PIX_LINES >> 2] = regr(CCDC_PIX_LINES);
+	ccdc_ctx[CCDC_HORZ_INFO >> 2] = regr(CCDC_HORZ_INFO);
+	ccdc_ctx[CCDC_VERT_START >> 2] = regr(CCDC_VERT_START);
+	ccdc_ctx[CCDC_VERT_LINES >> 2] = regr(CCDC_VERT_LINES);
+	ccdc_ctx[CCDC_CULLING >> 2] = regr(CCDC_CULLING);
+	ccdc_ctx[CCDC_HSIZE_OFF >> 2] = regr(CCDC_HSIZE_OFF);
+	ccdc_ctx[CCDC_SDOFST >> 2] = regr(CCDC_SDOFST);
+	ccdc_ctx[CCDC_SDR_ADDR >> 2] = regr(CCDC_SDR_ADDR);
+	ccdc_ctx[CCDC_CLAMP >> 2] = regr(CCDC_CLAMP);
+	ccdc_ctx[CCDC_DCSUB >> 2] = regr(CCDC_DCSUB);
+	ccdc_ctx[CCDC_COLPTN >> 2] = regr(CCDC_COLPTN);
+	ccdc_ctx[CCDC_BLKCMP >> 2] = regr(CCDC_BLKCMP);
+	ccdc_ctx[CCDC_FPC >> 2] = regr(CCDC_FPC);
+	ccdc_ctx[CCDC_FPC_ADDR >> 2] = regr(CCDC_FPC_ADDR);
+	ccdc_ctx[CCDC_VDINT >> 2] = regr(CCDC_VDINT);
+	ccdc_ctx[CCDC_ALAW >> 2] = regr(CCDC_ALAW);
+	ccdc_ctx[CCDC_REC656IF >> 2] = regr(CCDC_REC656IF);
+	ccdc_ctx[CCDC_CCDCFG >> 2] = regr(CCDC_CCDCFG);
+	ccdc_ctx[CCDC_FMTCFG >> 2] = regr(CCDC_FMTCFG);
+	ccdc_ctx[CCDC_FMT_HORZ >> 2] = regr(CCDC_FMT_HORZ);
+	ccdc_ctx[CCDC_FMT_VERT >> 2] = regr(CCDC_FMT_VERT);
+	ccdc_ctx[CCDC_FMT_ADDR0 >> 2] = regr(CCDC_FMT_ADDR0);
+	ccdc_ctx[CCDC_FMT_ADDR1 >> 2] = regr(CCDC_FMT_ADDR1);
+	ccdc_ctx[CCDC_FMT_ADDR2 >> 2] = regr(CCDC_FMT_ADDR2);
+	ccdc_ctx[CCDC_FMT_ADDR3 >> 2] = regr(CCDC_FMT_ADDR3);
+	ccdc_ctx[CCDC_FMT_ADDR4 >> 2] = regr(CCDC_FMT_ADDR4);
+	ccdc_ctx[CCDC_FMT_ADDR5 >> 2] = regr(CCDC_FMT_ADDR5);
+	ccdc_ctx[CCDC_FMT_ADDR6 >> 2] = regr(CCDC_FMT_ADDR6);
+	ccdc_ctx[CCDC_FMT_ADDR7 >> 2] = regr(CCDC_FMT_ADDR7);
+	ccdc_ctx[CCDC_PRGEVEN_0 >> 2] = regr(CCDC_PRGEVEN_0);
+	ccdc_ctx[CCDC_PRGEVEN_1 >> 2] = regr(CCDC_PRGEVEN_1);
+	ccdc_ctx[CCDC_PRGODD_0 >> 2] = regr(CCDC_PRGODD_0);
+	ccdc_ctx[CCDC_PRGODD_1 >> 2] = regr(CCDC_PRGODD_1);
+	ccdc_ctx[CCDC_VP_OUT >> 2] = regr(CCDC_VP_OUT);
+}
+
+static void ccdc_restore_context(void)
+{
+	regw(ccdc_ctx[CCDC_SYN_MODE >> 2], CCDC_SYN_MODE);
+	regw(ccdc_ctx[CCDC_HD_VD_WID >> 2], CCDC_HD_VD_WID);
+	regw(ccdc_ctx[CCDC_PIX_LINES >> 2], CCDC_PIX_LINES);
+	regw(ccdc_ctx[CCDC_HORZ_INFO >> 2], CCDC_HORZ_INFO);
+	regw(ccdc_ctx[CCDC_VERT_START >> 2], CCDC_VERT_START);
+	regw(ccdc_ctx[CCDC_VERT_LINES >> 2], CCDC_VERT_LINES);
+	regw(ccdc_ctx[CCDC_CULLING >> 2], CCDC_CULLING);
+	regw(ccdc_ctx[CCDC_HSIZE_OFF >> 2], CCDC_HSIZE_OFF);
+	regw(ccdc_ctx[CCDC_SDOFST >> 2], CCDC_SDOFST);
+	regw(ccdc_ctx[CCDC_SDR_ADDR >> 2], CCDC_SDR_ADDR);
+	regw(ccdc_ctx[CCDC_CLAMP >> 2], CCDC_CLAMP);
+	regw(ccdc_ctx[CCDC_DCSUB >> 2], CCDC_DCSUB);
+	regw(ccdc_ctx[CCDC_COLPTN >> 2], CCDC_COLPTN);
+	regw(ccdc_ctx[CCDC_BLKCMP >> 2], CCDC_BLKCMP);
+	regw(ccdc_ctx[CCDC_FPC >> 2], CCDC_FPC);
+	regw(ccdc_ctx[CCDC_FPC_ADDR >> 2], CCDC_FPC_ADDR);
+	regw(ccdc_ctx[CCDC_VDINT >> 2], CCDC_VDINT);
+	regw(ccdc_ctx[CCDC_ALAW >> 2], CCDC_ALAW);
+	regw(ccdc_ctx[CCDC_REC656IF >> 2], CCDC_REC656IF);
+	regw(ccdc_ctx[CCDC_CCDCFG >> 2], CCDC_CCDCFG);
+	regw(ccdc_ctx[CCDC_FMTCFG >> 2], CCDC_FMTCFG);
+	regw(ccdc_ctx[CCDC_FMT_HORZ >> 2], CCDC_FMT_HORZ);
+	regw(ccdc_ctx[CCDC_FMT_VERT >> 2], CCDC_FMT_VERT);
+	regw(ccdc_ctx[CCDC_FMT_ADDR0 >> 2], CCDC_FMT_ADDR0);
+	regw(ccdc_ctx[CCDC_FMT_ADDR1 >> 2], CCDC_FMT_ADDR1);
+	regw(ccdc_ctx[CCDC_FMT_ADDR2 >> 2], CCDC_FMT_ADDR2);
+	regw(ccdc_ctx[CCDC_FMT_ADDR3 >> 2], CCDC_FMT_ADDR3);
+	regw(ccdc_ctx[CCDC_FMT_ADDR4 >> 2], CCDC_FMT_ADDR4);
+	regw(ccdc_ctx[CCDC_FMT_ADDR5 >> 2], CCDC_FMT_ADDR5);
+	regw(ccdc_ctx[CCDC_FMT_ADDR6 >> 2], CCDC_FMT_ADDR6);
+	regw(ccdc_ctx[CCDC_FMT_ADDR7 >> 2], CCDC_FMT_ADDR7);
+	regw(ccdc_ctx[CCDC_PRGEVEN_0 >> 2], CCDC_PRGEVEN_0);
+	regw(ccdc_ctx[CCDC_PRGEVEN_1 >> 2], CCDC_PRGEVEN_1);
+	regw(ccdc_ctx[CCDC_PRGODD_0 >> 2], CCDC_PRGODD_0);
+	regw(ccdc_ctx[CCDC_PRGODD_1 >> 2], CCDC_PRGODD_1);
+	regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT);
+	regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR);
+}
+static struct ccdc_hw_device ccdc_hw_dev = {
+	.name = "DM6446 CCDC",
+	.owner = THIS_MODULE,
+	.hw_ops = {
+		.open = ccdc_open,
+		.close = ccdc_close,
+		.reset = ccdc_sbl_reset,
+		.enable = ccdc_enable,
+		.set_hw_if_params = ccdc_set_hw_if_params,
+		.set_params = ccdc_set_params,
+		.configure = ccdc_configure,
+		.set_buftype = ccdc_set_buftype,
+		.get_buftype = ccdc_get_buftype,
+		.enum_pix = ccdc_enum_pix,
+		.set_pixel_format = ccdc_set_pixel_format,
+		.get_pixel_format = ccdc_get_pixel_format,
+		.set_frame_format = ccdc_set_frame_format,
+		.get_frame_format = ccdc_get_frame_format,
+		.set_image_window = ccdc_set_image_window,
+		.get_image_window = ccdc_get_image_window,
+		.get_line_length = ccdc_get_line_length,
+		.setfbaddr = ccdc_setfbaddr,
+		.getfid = ccdc_getfid,
+	},
+};
+
+static int __devinit dm644x_ccdc_probe(struct platform_device *pdev)
+{
+	struct resource	*res;
+	int status = 0;
+
+	/*
+	 * first try to register with vpfe. If not correct platform, then we
+	 * don't have to iomap
+	 */
+	status = vpfe_register_ccdc_device(&ccdc_hw_dev);
+	if (status < 0)
+		return status;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		status = -ENODEV;
+		goto fail_nores;
+	}
+
+	res = request_mem_region(res->start, resource_size(res), res->name);
+	if (!res) {
+		status = -EBUSY;
+		goto fail_nores;
+	}
+
+	ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res));
+	if (!ccdc_cfg.base_addr) {
+		status = -ENOMEM;
+		goto fail_nomem;
+	}
+
+	/* Get and enable Master clock */
+	ccdc_cfg.mclk = clk_get(&pdev->dev, "master");
+	if (IS_ERR(ccdc_cfg.mclk)) {
+		status = PTR_ERR(ccdc_cfg.mclk);
+		goto fail_nomap;
+	}
+	if (clk_enable(ccdc_cfg.mclk)) {
+		status = -ENODEV;
+		goto fail_mclk;
+	}
+
+	/* Get and enable Slave clock */
+	ccdc_cfg.sclk = clk_get(&pdev->dev, "slave");
+	if (IS_ERR(ccdc_cfg.sclk)) {
+		status = PTR_ERR(ccdc_cfg.sclk);
+		goto fail_mclk;
+	}
+	if (clk_enable(ccdc_cfg.sclk)) {
+		status = -ENODEV;
+		goto fail_sclk;
+	}
+	ccdc_cfg.dev = &pdev->dev;
+	printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);
+	return 0;
+fail_sclk:
+	clk_put(ccdc_cfg.sclk);
+fail_mclk:
+	clk_put(ccdc_cfg.mclk);
+fail_nomap:
+	iounmap(ccdc_cfg.base_addr);
+fail_nomem:
+	release_mem_region(res->start, resource_size(res));
+fail_nores:
+	vpfe_unregister_ccdc_device(&ccdc_hw_dev);
+	return status;
+}
+
+static int dm644x_ccdc_remove(struct platform_device *pdev)
+{
+	struct resource	*res;
+
+	clk_put(ccdc_cfg.mclk);
+	clk_put(ccdc_cfg.sclk);
+	iounmap(ccdc_cfg.base_addr);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res)
+		release_mem_region(res->start, resource_size(res));
+	vpfe_unregister_ccdc_device(&ccdc_hw_dev);
+	return 0;
+}
+
+static int dm644x_ccdc_suspend(struct device *dev)
+{
+	/* Save CCDC context */
+	ccdc_save_context();
+	/* Disable CCDC */
+	ccdc_enable(0);
+	/* Disable both master and slave clock */
+	clk_disable(ccdc_cfg.mclk);
+	clk_disable(ccdc_cfg.sclk);
+
+	return 0;
+}
+
+static int dm644x_ccdc_resume(struct device *dev)
+{
+	/* Enable both master and slave clock */
+	clk_enable(ccdc_cfg.mclk);
+	clk_enable(ccdc_cfg.sclk);
+	/* Restore CCDC context */
+	ccdc_restore_context();
+
+	return 0;
+}
+
+static const struct dev_pm_ops dm644x_ccdc_pm_ops = {
+	.suspend = dm644x_ccdc_suspend,
+	.resume = dm644x_ccdc_resume,
+};
+
+static struct platform_driver dm644x_ccdc_driver = {
+	.driver = {
+		.name	= "dm644x_ccdc",
+		.owner = THIS_MODULE,
+		.pm = &dm644x_ccdc_pm_ops,
+	},
+	.remove = __devexit_p(dm644x_ccdc_remove),
+	.probe = dm644x_ccdc_probe,
+};
+
+module_platform_driver(dm644x_ccdc_driver);
diff --git a/drivers/media/platform/davinci/dm644x_ccdc_regs.h b/drivers/media/platform/davinci/dm644x_ccdc_regs.h
new file mode 100644
index 0000000..90370e4
--- /dev/null
+++ b/drivers/media/platform/davinci/dm644x_ccdc_regs.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2006-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _DM644X_CCDC_REGS_H
+#define _DM644X_CCDC_REGS_H
+
+/**************************************************************************\
+* Register OFFSET Definitions
+\**************************************************************************/
+#define CCDC_PID				0x0
+#define CCDC_PCR				0x4
+#define CCDC_SYN_MODE				0x8
+#define CCDC_HD_VD_WID				0xc
+#define CCDC_PIX_LINES				0x10
+#define CCDC_HORZ_INFO				0x14
+#define CCDC_VERT_START				0x18
+#define CCDC_VERT_LINES				0x1c
+#define CCDC_CULLING				0x20
+#define CCDC_HSIZE_OFF				0x24
+#define CCDC_SDOFST				0x28
+#define CCDC_SDR_ADDR				0x2c
+#define CCDC_CLAMP				0x30
+#define CCDC_DCSUB				0x34
+#define CCDC_COLPTN				0x38
+#define CCDC_BLKCMP				0x3c
+#define CCDC_FPC				0x40
+#define CCDC_FPC_ADDR				0x44
+#define CCDC_VDINT				0x48
+#define CCDC_ALAW				0x4c
+#define CCDC_REC656IF				0x50
+#define CCDC_CCDCFG				0x54
+#define CCDC_FMTCFG				0x58
+#define CCDC_FMT_HORZ				0x5c
+#define CCDC_FMT_VERT				0x60
+#define CCDC_FMT_ADDR0				0x64
+#define CCDC_FMT_ADDR1				0x68
+#define CCDC_FMT_ADDR2				0x6c
+#define CCDC_FMT_ADDR3				0x70
+#define CCDC_FMT_ADDR4				0x74
+#define CCDC_FMT_ADDR5				0x78
+#define CCDC_FMT_ADDR6				0x7c
+#define CCDC_FMT_ADDR7				0x80
+#define CCDC_PRGEVEN_0				0x84
+#define CCDC_PRGEVEN_1				0x88
+#define CCDC_PRGODD_0				0x8c
+#define CCDC_PRGODD_1				0x90
+#define CCDC_VP_OUT				0x94
+#define CCDC_REG_END				0x98
+
+/***************************************************************
+*	Define for various register bit mask and shifts for CCDC
+****************************************************************/
+#define CCDC_FID_POL_MASK			1
+#define CCDC_FID_POL_SHIFT			4
+#define CCDC_HD_POL_MASK			1
+#define CCDC_HD_POL_SHIFT			3
+#define CCDC_VD_POL_MASK			1
+#define CCDC_VD_POL_SHIFT			2
+#define CCDC_HSIZE_OFF_MASK			0xffffffe0
+#define CCDC_32BYTE_ALIGN_VAL			31
+#define CCDC_FRM_FMT_MASK			0x1
+#define CCDC_FRM_FMT_SHIFT			7
+#define CCDC_DATA_SZ_MASK			7
+#define CCDC_DATA_SZ_SHIFT			8
+#define CCDC_PIX_FMT_MASK			3
+#define CCDC_PIX_FMT_SHIFT			12
+#define CCDC_VP2SDR_DISABLE			0xFFFBFFFF
+#define CCDC_WEN_ENABLE				(1 << 17)
+#define CCDC_SDR2RSZ_DISABLE			0xFFF7FFFF
+#define CCDC_VDHDEN_ENABLE			(1 << 16)
+#define CCDC_LPF_ENABLE				(1 << 14)
+#define CCDC_ALAW_ENABLE			(1 << 3)
+#define CCDC_ALAW_GAMA_WD_MASK			7
+#define CCDC_BLK_CLAMP_ENABLE			(1 << 31)
+#define CCDC_BLK_SGAIN_MASK			0x1F
+#define CCDC_BLK_ST_PXL_MASK			0x7FFF
+#define CCDC_BLK_ST_PXL_SHIFT			10
+#define CCDC_BLK_SAMPLE_LN_MASK			7
+#define CCDC_BLK_SAMPLE_LN_SHIFT		28
+#define CCDC_BLK_SAMPLE_LINE_MASK		7
+#define CCDC_BLK_SAMPLE_LINE_SHIFT		25
+#define CCDC_BLK_DC_SUB_MASK			0x03FFF
+#define CCDC_BLK_COMP_MASK			0xFF
+#define CCDC_BLK_COMP_GB_COMP_SHIFT		8
+#define CCDC_BLK_COMP_GR_COMP_SHIFT		16
+#define CCDC_BLK_COMP_R_COMP_SHIFT		24
+#define CCDC_LATCH_ON_VSYNC_DISABLE		(1 << 15)
+#define CCDC_FPC_ENABLE				(1 << 15)
+#define CCDC_FPC_DISABLE			0
+#define CCDC_FPC_FPC_NUM_MASK 			0x7FFF
+#define CCDC_DATA_PACK_ENABLE			(1 << 11)
+#define CCDC_FMTCFG_VPIN_MASK			7
+#define CCDC_FMTCFG_VPIN_SHIFT			12
+#define CCDC_FMT_HORZ_FMTLNH_MASK		0x1FFF
+#define CCDC_FMT_HORZ_FMTSPH_MASK		0x1FFF
+#define CCDC_FMT_HORZ_FMTSPH_SHIFT		16
+#define CCDC_FMT_VERT_FMTLNV_MASK		0x1FFF
+#define CCDC_FMT_VERT_FMTSLV_MASK		0x1FFF
+#define CCDC_FMT_VERT_FMTSLV_SHIFT		16
+#define CCDC_VP_OUT_VERT_NUM_MASK		0x3FFF
+#define CCDC_VP_OUT_VERT_NUM_SHIFT		17
+#define CCDC_VP_OUT_HORZ_NUM_MASK		0x1FFF
+#define CCDC_VP_OUT_HORZ_NUM_SHIFT		4
+#define CCDC_VP_OUT_HORZ_ST_MASK		0xF
+#define CCDC_HORZ_INFO_SPH_SHIFT		16
+#define CCDC_VERT_START_SLV0_SHIFT		16
+#define CCDC_VDINT_VDINT0_SHIFT			16
+#define CCDC_VDINT_VDINT1_MASK			0xFFFF
+#define CCDC_PPC_RAW				1
+#define CCDC_DCSUB_DEFAULT_VAL			0
+#define CCDC_CLAMP_DEFAULT_VAL			0
+#define CCDC_ENABLE_VIDEO_PORT			0x8000
+#define CCDC_DISABLE_VIDEO_PORT			0
+#define CCDC_COLPTN_VAL				0xBB11BB11
+#define CCDC_TWO_BYTES_PER_PIXEL		2
+#define CCDC_INTERLACED_IMAGE_INVERT		0x4B6D
+#define CCDC_INTERLACED_NO_IMAGE_INVERT		0x0249
+#define CCDC_PROGRESSIVE_IMAGE_INVERT		0x4000
+#define CCDC_PROGRESSIVE_NO_IMAGE_INVERT	0
+#define CCDC_INTERLACED_HEIGHT_SHIFT		1
+#define CCDC_SYN_MODE_INPMOD_SHIFT		12
+#define CCDC_SYN_MODE_INPMOD_MASK		3
+#define CCDC_SYN_MODE_8BITS			(7 << 8)
+#define CCDC_SYN_MODE_10BITS			(6 << 8)
+#define CCDC_SYN_MODE_11BITS			(5 << 8)
+#define CCDC_SYN_MODE_12BITS			(4 << 8)
+#define CCDC_SYN_MODE_13BITS			(3 << 8)
+#define CCDC_SYN_MODE_14BITS			(2 << 8)
+#define CCDC_SYN_MODE_15BITS			(1 << 8)
+#define CCDC_SYN_MODE_16BITS			(0 << 8)
+#define CCDC_SYN_FLDMODE_MASK			1
+#define CCDC_SYN_FLDMODE_SHIFT			7
+#define CCDC_REC656IF_BT656_EN			3
+#define CCDC_SYN_MODE_VD_POL_NEGATIVE		(1 << 2)
+#define CCDC_CCDCFG_Y8POS_SHIFT			11
+#define CCDC_CCDCFG_BW656_10BIT 		(1 << 5)
+#define CCDC_SDOFST_FIELD_INTERLEAVED		0x249
+#define CCDC_NO_CULLING				0xffff00ff
+#endif
diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c
new file mode 100644
index 0000000..b99d542
--- /dev/null
+++ b/drivers/media/platform/davinci/isif.c
@@ -0,0 +1,1162 @@
+/*
+ * Copyright (C) 2008-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Image Sensor Interface (ISIF) driver
+ *
+ * This driver is for configuring the ISIF IP available on DM365 or any other
+ * TI SoCs. This is used for capturing yuv or bayer video or image data
+ * from a decoder or sensor. This IP is similar to the CCDC IP on DM355
+ * and DM6446, but with enhanced or additional ip blocks. The driver
+ * configures the ISIF upon commands from the vpfe bridge driver through
+ * ccdc_hw_device interface.
+ *
+ * TODO: 1) Raw bayer parameter settings and bayer capture
+ *	 2) Add support for control ioctl
+ */
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/videodev2.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+
+#include <mach/mux.h>
+
+#include <media/davinci/isif.h>
+#include <media/davinci/vpss.h>
+
+#include "isif_regs.h"
+#include "ccdc_hw_device.h"
+
+/* Defaults for module configuration parameters */
+static struct isif_config_params_raw isif_config_defaults = {
+	.linearize = {
+		.en = 0,
+		.corr_shft = ISIF_NO_SHIFT,
+		.scale_fact = {1, 0},
+	},
+	.df_csc = {
+		.df_or_csc = 0,
+		.csc = {
+			.en = 0,
+		},
+	},
+	.dfc = {
+		.en = 0,
+	},
+	.bclamp = {
+		.en = 0,
+	},
+	.gain_offset = {
+		.gain = {
+			.r_ye = {1, 0},
+			.gr_cy = {1, 0},
+			.gb_g = {1, 0},
+			.b_mg = {1, 0},
+		},
+	},
+	.culling = {
+		.hcpat_odd = 0xff,
+		.hcpat_even = 0xff,
+		.vcpat = 0xff,
+	},
+	.compress = {
+		.alg = ISIF_ALAW,
+	},
+};
+
+/* ISIF operation configuration */
+static struct isif_oper_config {
+	struct device *dev;
+	enum vpfe_hw_if_type if_type;
+	struct isif_ycbcr_config ycbcr;
+	struct isif_params_raw bayer;
+	enum isif_data_pack data_pack;
+	/* Master clock */
+	struct clk *mclk;
+	/* ISIF base address */
+	void __iomem *base_addr;
+	/* ISIF Linear Table 0 */
+	void __iomem *linear_tbl0_addr;
+	/* ISIF Linear Table 1 */
+	void __iomem *linear_tbl1_addr;
+} isif_cfg = {
+	.ycbcr = {
+		.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
+		.frm_fmt = CCDC_FRMFMT_INTERLACED,
+		.win = ISIF_WIN_NTSC,
+		.fid_pol = VPFE_PINPOL_POSITIVE,
+		.vd_pol = VPFE_PINPOL_POSITIVE,
+		.hd_pol = VPFE_PINPOL_POSITIVE,
+		.pix_order = CCDC_PIXORDER_CBYCRY,
+		.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED,
+	},
+	.bayer = {
+		.pix_fmt = CCDC_PIXFMT_RAW,
+		.frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
+		.win = ISIF_WIN_VGA,
+		.fid_pol = VPFE_PINPOL_POSITIVE,
+		.vd_pol = VPFE_PINPOL_POSITIVE,
+		.hd_pol = VPFE_PINPOL_POSITIVE,
+		.gain = {
+			.r_ye = {1, 0},
+			.gr_cy = {1, 0},
+			.gb_g = {1, 0},
+			.b_mg = {1, 0},
+		},
+		.cfa_pat = ISIF_CFA_PAT_MOSAIC,
+		.data_msb = ISIF_BIT_MSB_11,
+		.config_params = {
+			.data_shift = ISIF_NO_SHIFT,
+			.col_pat_field0 = {
+				.olop = ISIF_GREEN_BLUE,
+				.olep = ISIF_BLUE,
+				.elop = ISIF_RED,
+				.elep = ISIF_GREEN_RED,
+			},
+			.col_pat_field1 = {
+				.olop = ISIF_GREEN_BLUE,
+				.olep = ISIF_BLUE,
+				.elop = ISIF_RED,
+				.elep = ISIF_GREEN_RED,
+			},
+			.test_pat_gen = 0,
+		},
+	},
+	.data_pack = ISIF_DATA_PACK8,
+};
+
+/* Raw Bayer formats */
+static const u32 isif_raw_bayer_pix_formats[] = {
+	V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
+
+/* Raw YUV formats */
+static const u32 isif_raw_yuv_pix_formats[] = {
+	V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
+
+/* register access routines */
+static inline u32 regr(u32 offset)
+{
+	return __raw_readl(isif_cfg.base_addr + offset);
+}
+
+static inline void regw(u32 val, u32 offset)
+{
+	__raw_writel(val, isif_cfg.base_addr + offset);
+}
+
+/* reg_modify() - read, modify and write register */
+static inline u32 reg_modify(u32 mask, u32 val, u32 offset)
+{
+	u32 new_val = (regr(offset) & ~mask) | (val & mask);
+
+	regw(new_val, offset);
+	return new_val;
+}
+
+static inline void regw_lin_tbl(u32 val, u32 offset, int i)
+{
+	if (!i)
+		__raw_writel(val, isif_cfg.linear_tbl0_addr + offset);
+	else
+		__raw_writel(val, isif_cfg.linear_tbl1_addr + offset);
+}
+
+static void isif_disable_all_modules(void)
+{
+	/* disable BC */
+	regw(0, CLAMPCFG);
+	/* disable vdfc */
+	regw(0, DFCCTL);
+	/* disable CSC */
+	regw(0, CSCCTL);
+	/* disable linearization */
+	regw(0, LINCFG0);
+	/* disable other modules here as they are supported */
+}
+
+static void isif_enable(int en)
+{
+	if (!en) {
+		/* Before disable isif, disable all ISIF modules */
+		isif_disable_all_modules();
+		/*
+		 * wait for next VD. Assume lowest scan rate is 12 Hz. So
+		 * 100 msec delay is good enough
+		 */
+		msleep(100);
+	}
+	reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN);
+}
+
+static void isif_enable_output_to_sdram(int en)
+{
+	reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN);
+}
+
+static void isif_config_culling(struct isif_cul *cul)
+{
+	u32 val;
+
+	/* Horizontal pattern */
+	val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd;
+	regw(val, CULH);
+
+	/* vertical pattern */
+	regw(cul->vcpat, CULV);
+
+	/* LPF */
+	reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT,
+		  cul->en_lpf << ISIF_LPF_SHIFT, MODESET);
+}
+
+static void isif_config_gain_offset(void)
+{
+	struct isif_gain_offsets_adj *gain_off_p =
+		&isif_cfg.bayer.config_params.gain_offset;
+	u32 val;
+
+	val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) |
+	      (!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) |
+	      (!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) |
+	      (!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) |
+	      (!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) |
+	      (!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT);
+
+	reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD);
+
+	val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) |
+	       gain_off_p->gain.r_ye.decimal;
+	regw(val, CRGAIN);
+
+	val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) |
+	       gain_off_p->gain.gr_cy.decimal;
+	regw(val, CGRGAIN);
+
+	val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) |
+	       gain_off_p->gain.gb_g.decimal;
+	regw(val, CGBGAIN);
+
+	val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) |
+	       gain_off_p->gain.b_mg.decimal;
+	regw(val, CBGAIN);
+
+	regw(gain_off_p->offset, COFSTA);
+}
+
+static void isif_restore_defaults(void)
+{
+	enum vpss_ccdc_source_sel source = VPSS_CCDCIN;
+
+	dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults...");
+	isif_cfg.bayer.config_params = isif_config_defaults;
+	/* Enable clock to ISIF, IPIPEIF and BL */
+	vpss_enable_clock(VPSS_CCDC_CLOCK, 1);
+	vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
+	vpss_enable_clock(VPSS_BL_CLOCK, 1);
+	/* Set default offset and gain */
+	isif_config_gain_offset();
+	vpss_select_ccdc_source(source);
+	dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults...");
+}
+
+static int isif_open(struct device *device)
+{
+	isif_restore_defaults();
+	return 0;
+}
+
+/* This function will configure the window size to be capture in ISIF reg */
+static void isif_setwin(struct v4l2_rect *image_win,
+			enum ccdc_frmfmt frm_fmt, int ppc)
+{
+	int horz_start, horz_nr_pixels;
+	int vert_start, vert_nr_lines;
+	int mid_img = 0;
+
+	dev_dbg(isif_cfg.dev, "\nStarting isif_setwin...");
+	/*
+	 * ppc - per pixel count. indicates how many pixels per cell
+	 * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
+	 * raw capture this is 1
+	 */
+	horz_start = image_win->left << (ppc - 1);
+	horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
+
+	/* Writing the horizontal info into the registers */
+	regw(horz_start & START_PX_HOR_MASK, SPH);
+	regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH);
+	vert_start = image_win->top;
+
+	if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+		vert_nr_lines = (image_win->height >> 1) - 1;
+		vert_start >>= 1;
+		/* To account for VD since line 0 doesn't have any data */
+		vert_start += 1;
+	} else {
+		/* To account for VD since line 0 doesn't have any data */
+		vert_start += 1;
+		vert_nr_lines = image_win->height - 1;
+		/* configure VDINT0 and VDINT1 */
+		mid_img = vert_start + (image_win->height / 2);
+		regw(mid_img, VDINT1);
+	}
+
+	regw(0, VDINT0);
+	regw(vert_start & START_VER_ONE_MASK, SLV0);
+	regw(vert_start & START_VER_TWO_MASK, SLV1);
+	regw(vert_nr_lines & NUM_LINES_VER, LNV);
+}
+
+static void isif_config_bclamp(struct isif_black_clamp *bc)
+{
+	u32 val;
+
+	/*
+	 * DC Offset is always added to image data irrespective of bc enable
+	 * status
+	 */
+	regw(bc->dc_offset, CLDCOFST);
+
+	if (bc->en) {
+		val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT;
+
+		/* Enable BC and horizontal clamp caculation paramaters */
+		val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT);
+
+		regw(val, CLAMPCFG);
+
+		if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) {
+			/*
+			 * Window count for calculation
+			 * Base window selection
+			 * pixel limit
+			 * Horizontal size of window
+			 * vertical size of the window
+			 * Horizontal start position of the window
+			 * Vertical start position of the window
+			 */
+			val = bc->horz.win_count_calc |
+			      ((!!bc->horz.base_win_sel_calc) <<
+				ISIF_HORZ_BC_WIN_SEL_SHIFT) |
+			      ((!!bc->horz.clamp_pix_limit) <<
+				ISIF_HORZ_BC_PIX_LIMIT_SHIFT) |
+			      (bc->horz.win_h_sz_calc <<
+				ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) |
+			      (bc->horz.win_v_sz_calc <<
+				ISIF_HORZ_BC_WIN_V_SIZE_SHIFT);
+			regw(val, CLHWIN0);
+
+			regw(bc->horz.win_start_h_calc, CLHWIN1);
+			regw(bc->horz.win_start_v_calc, CLHWIN2);
+		}
+
+		/* vertical clamp caculation paramaters */
+
+		/* Reset clamp value sel for previous line */
+		val |=
+		(bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) |
+		(bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT);
+		regw(val, CLVWIN0);
+
+		/* Optical Black horizontal start position */
+		regw(bc->vert.ob_start_h, CLVWIN1);
+		/* Optical Black vertical start position */
+		regw(bc->vert.ob_start_v, CLVWIN2);
+		/* Optical Black vertical size for calculation */
+		regw(bc->vert.ob_v_sz_calc, CLVWIN3);
+		/* Vertical start position for BC subtraction */
+		regw(bc->vert_start_sub, CLSV);
+	}
+}
+
+static void isif_config_linearization(struct isif_linearize *linearize)
+{
+	u32 val, i;
+
+	if (!linearize->en) {
+		regw(0, LINCFG0);
+		return;
+	}
+
+	/* shift value for correction & enable linearization (set lsb) */
+	val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1;
+	regw(val, LINCFG0);
+
+	/* Scale factor */
+	val = ((!!linearize->scale_fact.integer) <<
+	       ISIF_LIN_SCALE_FACT_INTEG_SHIFT) |
+	       linearize->scale_fact.decimal;
+	regw(val, LINCFG1);
+
+	for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) {
+		if (i % 2)
+			regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1);
+		else
+			regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0);
+	}
+}
+
+static int isif_config_dfc(struct isif_dfc *vdfc)
+{
+	/* initialize retries to loop for max ~ 250 usec */
+	u32 val, count, retries = loops_per_jiffy / (4000/HZ);
+	int i;
+
+	if (!vdfc->en)
+		return 0;
+
+	/* Correction mode */
+	val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT);
+
+	/* Correct whole line or partial */
+	if (vdfc->corr_whole_line)
+		val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT;
+
+	/* level shift value */
+	val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT;
+
+	regw(val, DFCCTL);
+
+	/* Defect saturation level */
+	regw(vdfc->def_sat_level, VDFSATLV);
+
+	regw(vdfc->table[0].pos_vert, DFCMEM0);
+	regw(vdfc->table[0].pos_horz, DFCMEM1);
+	if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
+	    vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
+		regw(vdfc->table[0].level_at_pos, DFCMEM2);
+		regw(vdfc->table[0].level_up_pixels, DFCMEM3);
+		regw(vdfc->table[0].level_low_pixels, DFCMEM4);
+	}
+
+	/* set DFCMARST and set DFCMWR */
+	val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1;
+	regw(val, DFCMEMCTL);
+
+	count = retries;
+	while (count && (regr(DFCMEMCTL) & 0x1))
+		count--;
+
+	if (!count) {
+		dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n");
+		return -1;
+	}
+
+	for (i = 1; i < vdfc->num_vdefects; i++) {
+		regw(vdfc->table[i].pos_vert, DFCMEM0);
+		regw(vdfc->table[i].pos_horz, DFCMEM1);
+		if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
+		    vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
+			regw(vdfc->table[i].level_at_pos, DFCMEM2);
+			regw(vdfc->table[i].level_up_pixels, DFCMEM3);
+			regw(vdfc->table[i].level_low_pixels, DFCMEM4);
+		}
+		val = regr(DFCMEMCTL);
+		/* clear DFCMARST and set DFCMWR */
+		val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT);
+		val |= 1;
+		regw(val, DFCMEMCTL);
+
+		count = retries;
+		while (count && (regr(DFCMEMCTL) & 0x1))
+			count--;
+
+		if (!count) {
+			dev_err(isif_cfg.dev,
+				"defect table write timeout !!!\n");
+			return -1;
+		}
+	}
+	if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) {
+		/* Extra cycle needed */
+		regw(0, DFCMEM0);
+		regw(0x1FFF, DFCMEM1);
+		regw(1, DFCMEMCTL);
+	}
+
+	/* enable VDFC */
+	reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT),
+		   DFCCTL);
+	return 0;
+}
+
+static void isif_config_csc(struct isif_df_csc *df_csc)
+{
+	u32 val1 = 0, val2 = 0, i;
+
+	if (!df_csc->csc.en) {
+		regw(0, CSCCTL);
+		return;
+	}
+	for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) {
+		if ((i % 2) == 0) {
+			/* CSCM - LSB */
+			val1 = (df_csc->csc.coeff[i].integer <<
+				ISIF_CSC_COEF_INTEG_SHIFT) |
+				df_csc->csc.coeff[i].decimal;
+		} else {
+
+			/* CSCM - MSB */
+			val2 = (df_csc->csc.coeff[i].integer <<
+				ISIF_CSC_COEF_INTEG_SHIFT) |
+				df_csc->csc.coeff[i].decimal;
+			val2 <<= ISIF_CSCM_MSB_SHIFT;
+			val2 |= val1;
+			regw(val2, (CSCM0 + ((i - 1) << 1)));
+		}
+	}
+
+	/* program the active area */
+	regw(df_csc->start_pix, FMTSPH);
+	/*
+	 * one extra pixel as required for CSC. Actually number of
+	 * pixel - 1 should be configured in this register. So we
+	 * need to subtract 1 before writing to FMTSPH, but we will
+	 * not do this since csc requires one extra pixel
+	 */
+	regw(df_csc->num_pixels, FMTLNH);
+	regw(df_csc->start_line, FMTSLV);
+	/*
+	 * one extra line as required for CSC. See reason documented for
+	 * num_pixels
+	 */
+	regw(df_csc->num_lines, FMTLNV);
+
+	/* Enable CSC */
+	regw(1, CSCCTL);
+}
+
+static int isif_config_raw(void)
+{
+	struct isif_params_raw *params = &isif_cfg.bayer;
+	struct isif_config_params_raw *module_params =
+		&isif_cfg.bayer.config_params;
+	struct vpss_pg_frame_size frame_size;
+	struct vpss_sync_pol sync;
+	u32 val;
+
+	dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n");
+
+	/*
+	 * Configure CCDCFG register:-
+	 * Set CCD Not to swap input since input is RAW data
+	 * Set FID detection function to Latch at V-Sync
+	 * Set WENLOG - isif valid area
+	 * Set TRGSEL
+	 * Set EXTRG
+	 * Packed to 8 or 16 bits
+	 */
+
+	val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC |
+		ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN |
+		ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack;
+
+	dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val);
+	regw(val, CCDCFG);
+
+	/*
+	 * Configure the vertical sync polarity(MODESET.VDPOL)
+	 * Configure the horizontal sync polarity (MODESET.HDPOL)
+	 * Configure frame id polarity (MODESET.FLDPOL)
+	 * Configure data polarity
+	 * Configure External WEN Selection
+	 * Configure frame format(progressive or interlace)
+	 * Configure pixel format (Input mode)
+	 * Configure the data shift
+	 */
+
+	val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) |
+		(params->hd_pol << ISIF_HD_POL_SHIFT) |
+		(params->fid_pol << ISIF_FID_POL_SHIFT) |
+		(ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) |
+		(ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) |
+		(params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
+		(params->pix_fmt << ISIF_INPUT_SHIFT) |
+		(params->config_params.data_shift << ISIF_DATASFT_SHIFT);
+
+	regw(val, MODESET);
+	dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val);
+
+	/*
+	 * Configure GAMMAWD register
+	 * CFA pattern setting
+	 */
+	val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT;
+
+	/* Gamma msb */
+	if (module_params->compress.alg == ISIF_ALAW)
+		val |= ISIF_ALAW_ENABLE;
+
+	val |= (params->data_msb << ISIF_ALAW_GAMA_WD_SHIFT);
+	regw(val, CGAMMAWD);
+
+	/* Configure DPCM compression settings */
+	if (module_params->compress.alg == ISIF_DPCM) {
+		val =  BIT(ISIF_DPCM_EN_SHIFT) |
+		       (module_params->compress.pred <<
+		       ISIF_DPCM_PREDICTOR_SHIFT);
+	}
+
+	regw(val, MISC);
+
+	/* Configure Gain & Offset */
+	isif_config_gain_offset();
+
+	/* Configure Color pattern */
+	val = (params->config_params.col_pat_field0.olop) |
+	      (params->config_params.col_pat_field0.olep << 2) |
+	      (params->config_params.col_pat_field0.elop << 4) |
+	      (params->config_params.col_pat_field0.elep << 6) |
+	      (params->config_params.col_pat_field1.olop << 8) |
+	      (params->config_params.col_pat_field1.olep << 10) |
+	      (params->config_params.col_pat_field1.elop << 12) |
+	      (params->config_params.col_pat_field1.elep << 14);
+	regw(val, CCOLP);
+	dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val);
+
+	/* Configure HSIZE register  */
+	val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT;
+
+	/* calculate line offset in 32 bytes based on pack value */
+	if (isif_cfg.data_pack == ISIF_PACK_8BIT)
+		val |= ((params->win.width + 31) >> 5);
+	else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
+		val |= (((params->win.width +
+		       (params->win.width >> 2)) + 31) >> 5);
+	else
+		val |= (((params->win.width * 2) + 31) >> 5);
+	regw(val, HSIZE);
+
+	/* Configure SDOFST register  */
+	if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
+		if (params->image_invert_en) {
+			/* For interlace inverse mode */
+			regw(0x4B6D, SDOFST);
+			dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n");
+		} else {
+			/* For interlace non inverse mode */
+			regw(0x0B6D, SDOFST);
+			dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n");
+		}
+	} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
+		if (params->image_invert_en) {
+			/* For progressive inverse mode */
+			regw(0x4000, SDOFST);
+			dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n");
+		} else {
+			/* For progressive non inverse mode */
+			regw(0x0000, SDOFST);
+			dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n");
+		}
+	}
+
+	/* Configure video window */
+	isif_setwin(&params->win, params->frm_fmt, 1);
+
+	/* Configure Black Clamp */
+	isif_config_bclamp(&module_params->bclamp);
+
+	/* Configure Vertical Defection Pixel Correction */
+	if (isif_config_dfc(&module_params->dfc) < 0)
+		return -EFAULT;
+
+	if (!module_params->df_csc.df_or_csc)
+		/* Configure Color Space Conversion */
+		isif_config_csc(&module_params->df_csc);
+
+	isif_config_linearization(&module_params->linearize);
+
+	/* Configure Culling */
+	isif_config_culling(&module_params->culling);
+
+	/* Configure horizontal and vertical offsets(DFC,LSC,Gain) */
+	regw(module_params->horz_offset, DATAHOFST);
+	regw(module_params->vert_offset, DATAVOFST);
+
+	/* Setup test pattern if enabled */
+	if (params->config_params.test_pat_gen) {
+		/* Use the HD/VD pol settings from user */
+		sync.ccdpg_hdpol = params->hd_pol;
+		sync.ccdpg_vdpol = params->vd_pol;
+		dm365_vpss_set_sync_pol(sync);
+		frame_size.hlpfr = isif_cfg.bayer.win.width;
+		frame_size.pplen = isif_cfg.bayer.win.height;
+		dm365_vpss_set_pg_frame_size(frame_size);
+		vpss_select_ccdc_source(VPSS_PGLPBK);
+	}
+
+	dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n");
+	return 0;
+}
+
+static int isif_set_buftype(enum ccdc_buftype buf_type)
+{
+	if (isif_cfg.if_type == VPFE_RAW_BAYER)
+		isif_cfg.bayer.buf_type = buf_type;
+	else
+		isif_cfg.ycbcr.buf_type = buf_type;
+
+	return 0;
+
+}
+static enum ccdc_buftype isif_get_buftype(void)
+{
+	if (isif_cfg.if_type == VPFE_RAW_BAYER)
+		return isif_cfg.bayer.buf_type;
+
+	return isif_cfg.ycbcr.buf_type;
+}
+
+static int isif_enum_pix(u32 *pix, int i)
+{
+	int ret = -EINVAL;
+
+	if (isif_cfg.if_type == VPFE_RAW_BAYER) {
+		if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) {
+			*pix = isif_raw_bayer_pix_formats[i];
+			ret = 0;
+		}
+	} else {
+		if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) {
+			*pix = isif_raw_yuv_pix_formats[i];
+			ret = 0;
+		}
+	}
+
+	return ret;
+}
+
+static int isif_set_pixel_format(unsigned int pixfmt)
+{
+	if (isif_cfg.if_type == VPFE_RAW_BAYER) {
+		if (pixfmt == V4L2_PIX_FMT_SBGGR8) {
+			if ((isif_cfg.bayer.config_params.compress.alg !=
+			     ISIF_ALAW) &&
+			    (isif_cfg.bayer.config_params.compress.alg !=
+			     ISIF_DPCM)) {
+				dev_dbg(isif_cfg.dev,
+					"Either configure A-Law or DPCM\n");
+				return -EINVAL;
+			}
+			isif_cfg.data_pack = ISIF_PACK_8BIT;
+		} else if (pixfmt == V4L2_PIX_FMT_SBGGR16) {
+			isif_cfg.bayer.config_params.compress.alg =
+					ISIF_NO_COMPRESSION;
+			isif_cfg.data_pack = ISIF_PACK_16BIT;
+		} else
+			return -EINVAL;
+		isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
+	} else {
+		if (pixfmt == V4L2_PIX_FMT_YUYV)
+			isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
+		else if (pixfmt == V4L2_PIX_FMT_UYVY)
+			isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+		else
+			return -EINVAL;
+		isif_cfg.data_pack = ISIF_PACK_8BIT;
+	}
+	return 0;
+}
+
+static u32 isif_get_pixel_format(void)
+{
+	u32 pixfmt;
+
+	if (isif_cfg.if_type == VPFE_RAW_BAYER)
+		if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW ||
+		    isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM)
+			pixfmt = V4L2_PIX_FMT_SBGGR8;
+		else
+			pixfmt = V4L2_PIX_FMT_SBGGR16;
+	else {
+		if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
+			pixfmt = V4L2_PIX_FMT_YUYV;
+		else
+			pixfmt = V4L2_PIX_FMT_UYVY;
+	}
+	return pixfmt;
+}
+
+static int isif_set_image_window(struct v4l2_rect *win)
+{
+	if (isif_cfg.if_type == VPFE_RAW_BAYER) {
+		isif_cfg.bayer.win.top = win->top;
+		isif_cfg.bayer.win.left = win->left;
+		isif_cfg.bayer.win.width = win->width;
+		isif_cfg.bayer.win.height = win->height;
+	} else {
+		isif_cfg.ycbcr.win.top = win->top;
+		isif_cfg.ycbcr.win.left = win->left;
+		isif_cfg.ycbcr.win.width = win->width;
+		isif_cfg.ycbcr.win.height = win->height;
+	}
+	return 0;
+}
+
+static void isif_get_image_window(struct v4l2_rect *win)
+{
+	if (isif_cfg.if_type == VPFE_RAW_BAYER)
+		*win = isif_cfg.bayer.win;
+	else
+		*win = isif_cfg.ycbcr.win;
+}
+
+static unsigned int isif_get_line_length(void)
+{
+	unsigned int len;
+
+	if (isif_cfg.if_type == VPFE_RAW_BAYER) {
+		if (isif_cfg.data_pack == ISIF_PACK_8BIT)
+			len = ((isif_cfg.bayer.win.width));
+		else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
+			len = (((isif_cfg.bayer.win.width * 2) +
+				 (isif_cfg.bayer.win.width >> 2)));
+		else
+			len = (((isif_cfg.bayer.win.width * 2)));
+	} else
+		len = (((isif_cfg.ycbcr.win.width * 2)));
+	return ALIGN(len, 32);
+}
+
+static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt)
+{
+	if (isif_cfg.if_type == VPFE_RAW_BAYER)
+		isif_cfg.bayer.frm_fmt = frm_fmt;
+	else
+		isif_cfg.ycbcr.frm_fmt = frm_fmt;
+	return 0;
+}
+static enum ccdc_frmfmt isif_get_frame_format(void)
+{
+	if (isif_cfg.if_type == VPFE_RAW_BAYER)
+		return isif_cfg.bayer.frm_fmt;
+	return isif_cfg.ycbcr.frm_fmt;
+}
+
+static int isif_getfid(void)
+{
+	return (regr(MODESET) >> 15) & 0x1;
+}
+
+/* misc operations */
+static void isif_setfbaddr(unsigned long addr)
+{
+	regw((addr >> 21) & 0x07ff, CADU);
+	regw((addr >> 5) & 0x0ffff, CADL);
+}
+
+static int isif_set_hw_if_params(struct vpfe_hw_if_param *params)
+{
+	isif_cfg.if_type = params->if_type;
+
+	switch (params->if_type) {
+	case VPFE_BT656:
+	case VPFE_BT656_10BIT:
+	case VPFE_YCBCR_SYNC_8:
+		isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;
+		isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+		break;
+	case VPFE_BT1120:
+	case VPFE_YCBCR_SYNC_16:
+		isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT;
+		isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+		break;
+	case VPFE_RAW_BAYER:
+		isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
+		break;
+	default:
+		dev_dbg(isif_cfg.dev, "Invalid interface type\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* This function will configure ISIF for YCbCr parameters. */
+static int isif_config_ycbcr(void)
+{
+	struct isif_ycbcr_config *params = &isif_cfg.ycbcr;
+	struct vpss_pg_frame_size frame_size;
+	u32 modeset = 0, ccdcfg = 0;
+	struct vpss_sync_pol sync;
+
+	dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr...");
+
+	/* configure pixel format or input mode */
+	modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) |
+		  (params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
+		  (params->fid_pol << ISIF_FID_POL_SHIFT) |
+		  (params->hd_pol << ISIF_HD_POL_SHIFT) |
+		  (params->vd_pol << ISIF_VD_POL_SHIFT);
+
+	/* pack the data to 8-bit ISIFCFG */
+	switch (isif_cfg.if_type) {
+	case VPFE_BT656:
+		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
+			dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
+			return -EINVAL;
+		}
+		modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT);
+		regw(3, REC656IF);
+		ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR;
+		break;
+	case VPFE_BT656_10BIT:
+		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
+			dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
+			return -EINVAL;
+		}
+		/* setup BT.656, embedded sync  */
+		regw(3, REC656IF);
+		/* enable 10 bit mode in ccdcfg */
+		ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR |
+			ISIF_BW656_ENABLE;
+		break;
+	case VPFE_BT1120:
+		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
+			dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
+			return -EINVAL;
+		}
+		regw(3, REC656IF);
+		break;
+
+	case VPFE_YCBCR_SYNC_8:
+		ccdcfg |= ISIF_DATA_PACK8;
+		ccdcfg |= ISIF_YCINSWP_YCBCR;
+		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
+			dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
+			return -EINVAL;
+		}
+		break;
+	case VPFE_YCBCR_SYNC_16:
+		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
+			dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
+			return -EINVAL;
+		}
+		break;
+	default:
+		/* should never come here */
+		dev_dbg(isif_cfg.dev, "Invalid interface type\n");
+		return -EINVAL;
+	}
+
+	regw(modeset, MODESET);
+
+	/* Set up pix order */
+	ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT;
+
+	regw(ccdcfg, CCDCFG);
+
+	/* configure video window */
+	if ((isif_cfg.if_type == VPFE_BT1120) ||
+	    (isif_cfg.if_type == VPFE_YCBCR_SYNC_16))
+		isif_setwin(&params->win, params->frm_fmt, 1);
+	else
+		isif_setwin(&params->win, params->frm_fmt, 2);
+
+	/*
+	 * configure the horizontal line offset
+	 * this is done by rounding up width to a multiple of 16 pixels
+	 * and multiply by two to account for y:cb:cr 4:2:2 data
+	 */
+	regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE);
+
+	/* configure the memory line offset */
+	if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) &&
+	    (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED))
+		/* two fields are interleaved in memory */
+		regw(0x00000249, SDOFST);
+
+	/* Setup test pattern if enabled */
+	if (isif_cfg.bayer.config_params.test_pat_gen) {
+		sync.ccdpg_hdpol = params->hd_pol;
+		sync.ccdpg_vdpol = params->vd_pol;
+		dm365_vpss_set_sync_pol(sync);
+		dm365_vpss_set_pg_frame_size(frame_size);
+	}
+	return 0;
+}
+
+static int isif_configure(void)
+{
+	if (isif_cfg.if_type == VPFE_RAW_BAYER)
+		return isif_config_raw();
+	return isif_config_ycbcr();
+}
+
+static int isif_close(struct device *device)
+{
+	/* copy defaults to module params */
+	isif_cfg.bayer.config_params = isif_config_defaults;
+	return 0;
+}
+
+static struct ccdc_hw_device isif_hw_dev = {
+	.name = "ISIF",
+	.owner = THIS_MODULE,
+	.hw_ops = {
+		.open = isif_open,
+		.close = isif_close,
+		.enable = isif_enable,
+		.enable_out_to_sdram = isif_enable_output_to_sdram,
+		.set_hw_if_params = isif_set_hw_if_params,
+		.configure = isif_configure,
+		.set_buftype = isif_set_buftype,
+		.get_buftype = isif_get_buftype,
+		.enum_pix = isif_enum_pix,
+		.set_pixel_format = isif_set_pixel_format,
+		.get_pixel_format = isif_get_pixel_format,
+		.set_frame_format = isif_set_frame_format,
+		.get_frame_format = isif_get_frame_format,
+		.set_image_window = isif_set_image_window,
+		.get_image_window = isif_get_image_window,
+		.get_line_length = isif_get_line_length,
+		.setfbaddr = isif_setfbaddr,
+		.getfid = isif_getfid,
+	},
+};
+
+static int __devinit isif_probe(struct platform_device *pdev)
+{
+	void (*setup_pinmux)(void);
+	struct resource	*res;
+	void *__iomem addr;
+	int status = 0, i;
+
+	/*
+	 * first try to register with vpfe. If not correct platform, then we
+	 * don't have to iomap
+	 */
+	status = vpfe_register_ccdc_device(&isif_hw_dev);
+	if (status < 0)
+		return status;
+
+	/* Get and enable Master clock */
+	isif_cfg.mclk = clk_get(&pdev->dev, "master");
+	if (IS_ERR(isif_cfg.mclk)) {
+		status = PTR_ERR(isif_cfg.mclk);
+		goto fail_mclk;
+	}
+	if (clk_enable(isif_cfg.mclk)) {
+		status = -ENODEV;
+		goto fail_mclk;
+	}
+
+	/* Platform data holds setup_pinmux function ptr */
+	if (NULL == pdev->dev.platform_data) {
+		status = -ENODEV;
+		goto fail_mclk;
+	}
+	setup_pinmux = pdev->dev.platform_data;
+	/*
+	 * setup Mux configuration for ccdc which may be different for
+	 * different SoCs using this CCDC
+	 */
+	setup_pinmux();
+
+	i = 0;
+	/* Get the ISIF base address, linearization table0 and table1 addr. */
+	while (i < 3) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (!res) {
+			status = -ENODEV;
+			goto fail_nobase_res;
+		}
+		res = request_mem_region(res->start, resource_size(res),
+					 res->name);
+		if (!res) {
+			status = -EBUSY;
+			goto fail_nobase_res;
+		}
+		addr = ioremap_nocache(res->start, resource_size(res));
+		if (!addr) {
+			status = -ENOMEM;
+			goto fail_base_iomap;
+		}
+		switch (i) {
+		case 0:
+			/* ISIF base address */
+			isif_cfg.base_addr = addr;
+			break;
+		case 1:
+			/* ISIF linear tbl0 address */
+			isif_cfg.linear_tbl0_addr = addr;
+			break;
+		default:
+			/* ISIF linear tbl0 address */
+			isif_cfg.linear_tbl1_addr = addr;
+			break;
+		}
+		i++;
+	}
+	isif_cfg.dev = &pdev->dev;
+
+	printk(KERN_NOTICE "%s is registered with vpfe.\n",
+		isif_hw_dev.name);
+	return 0;
+fail_base_iomap:
+	release_mem_region(res->start, resource_size(res));
+	i--;
+fail_nobase_res:
+	if (isif_cfg.base_addr)
+		iounmap(isif_cfg.base_addr);
+	if (isif_cfg.linear_tbl0_addr)
+		iounmap(isif_cfg.linear_tbl0_addr);
+
+	while (i >= 0) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		release_mem_region(res->start, resource_size(res));
+		i--;
+	}
+fail_mclk:
+	clk_put(isif_cfg.mclk);
+	vpfe_unregister_ccdc_device(&isif_hw_dev);
+	return status;
+}
+
+static int isif_remove(struct platform_device *pdev)
+{
+	struct resource	*res;
+	int i = 0;
+
+	iounmap(isif_cfg.base_addr);
+	iounmap(isif_cfg.linear_tbl0_addr);
+	iounmap(isif_cfg.linear_tbl1_addr);
+	while (i < 3) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (res)
+			release_mem_region(res->start, resource_size(res));
+		i++;
+	}
+	vpfe_unregister_ccdc_device(&isif_hw_dev);
+	return 0;
+}
+
+static struct platform_driver isif_driver = {
+	.driver = {
+		.name	= "isif",
+		.owner = THIS_MODULE,
+	},
+	.remove = __devexit_p(isif_remove),
+	.probe = isif_probe,
+};
+
+module_platform_driver(isif_driver);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/davinci/isif_regs.h b/drivers/media/platform/davinci/isif_regs.h
new file mode 100644
index 0000000..aa69a46
--- /dev/null
+++ b/drivers/media/platform/davinci/isif_regs.h
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2008-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _ISIF_REGS_H
+#define _ISIF_REGS_H
+
+/* ISIF registers relative offsets */
+#define SYNCEN					0x00
+#define MODESET					0x04
+#define HDW					0x08
+#define VDW					0x0c
+#define PPLN					0x10
+#define LPFR					0x14
+#define SPH					0x18
+#define LNH					0x1c
+#define SLV0					0x20
+#define SLV1					0x24
+#define LNV					0x28
+#define CULH					0x2c
+#define CULV					0x30
+#define HSIZE					0x34
+#define SDOFST					0x38
+#define CADU					0x3c
+#define CADL					0x40
+#define LINCFG0					0x44
+#define LINCFG1					0x48
+#define CCOLP					0x4c
+#define CRGAIN 					0x50
+#define CGRGAIN					0x54
+#define CGBGAIN					0x58
+#define CBGAIN					0x5c
+#define COFSTA					0x60
+#define FLSHCFG0				0x64
+#define FLSHCFG1				0x68
+#define FLSHCFG2				0x6c
+#define VDINT0					0x70
+#define VDINT1					0x74
+#define VDINT2					0x78
+#define MISC 					0x7c
+#define CGAMMAWD				0x80
+#define REC656IF				0x84
+#define CCDCFG					0x88
+/*****************************************************
+* Defect Correction registers
+*****************************************************/
+#define DFCCTL					0x8c
+#define VDFSATLV				0x90
+#define DFCMEMCTL				0x94
+#define DFCMEM0					0x98
+#define DFCMEM1					0x9c
+#define DFCMEM2					0xa0
+#define DFCMEM3					0xa4
+#define DFCMEM4					0xa8
+/****************************************************
+* Black Clamp registers
+****************************************************/
+#define CLAMPCFG				0xac
+#define CLDCOFST				0xb0
+#define CLSV					0xb4
+#define CLHWIN0					0xb8
+#define CLHWIN1					0xbc
+#define CLHWIN2					0xc0
+#define CLVRV					0xc4
+#define CLVWIN0					0xc8
+#define CLVWIN1					0xcc
+#define CLVWIN2					0xd0
+#define CLVWIN3					0xd4
+/****************************************************
+* Lense Shading Correction
+****************************************************/
+#define DATAHOFST				0xd8
+#define DATAVOFST				0xdc
+#define LSCHVAL					0xe0
+#define LSCVVAL					0xe4
+#define TWODLSCCFG				0xe8
+#define TWODLSCOFST				0xec
+#define TWODLSCINI				0xf0
+#define TWODLSCGRBU				0xf4
+#define TWODLSCGRBL				0xf8
+#define TWODLSCGROF				0xfc
+#define TWODLSCORBU				0x100
+#define TWODLSCORBL				0x104
+#define TWODLSCOROF				0x108
+#define TWODLSCIRQEN				0x10c
+#define TWODLSCIRQST				0x110
+/****************************************************
+* Data formatter
+****************************************************/
+#define FMTCFG					0x114
+#define FMTPLEN					0x118
+#define FMTSPH					0x11c
+#define FMTLNH					0x120
+#define FMTSLV					0x124
+#define FMTLNV					0x128
+#define FMTRLEN					0x12c
+#define FMTHCNT					0x130
+#define FMTAPTR_BASE				0x134
+/* Below macro for addresses FMTAPTR0 - FMTAPTR15 */
+#define FMTAPTR(i)			(FMTAPTR_BASE + (i * 4))
+#define FMTPGMVF0				0x174
+#define FMTPGMVF1				0x178
+#define FMTPGMAPU0				0x17c
+#define FMTPGMAPU1				0x180
+#define FMTPGMAPS0				0x184
+#define FMTPGMAPS1				0x188
+#define FMTPGMAPS2				0x18c
+#define FMTPGMAPS3				0x190
+#define FMTPGMAPS4				0x194
+#define FMTPGMAPS5				0x198
+#define FMTPGMAPS6				0x19c
+#define FMTPGMAPS7				0x1a0
+/************************************************
+* Color Space Converter
+************************************************/
+#define CSCCTL					0x1a4
+#define CSCM0					0x1a8
+#define CSCM1					0x1ac
+#define CSCM2					0x1b0
+#define CSCM3					0x1b4
+#define CSCM4					0x1b8
+#define CSCM5					0x1bc
+#define CSCM6					0x1c0
+#define CSCM7					0x1c4
+#define OBWIN0					0x1c8
+#define OBWIN1					0x1cc
+#define OBWIN2					0x1d0
+#define OBWIN3					0x1d4
+#define OBVAL0					0x1d8
+#define OBVAL1					0x1dc
+#define OBVAL2					0x1e0
+#define OBVAL3					0x1e4
+#define OBVAL4					0x1e8
+#define OBVAL5					0x1ec
+#define OBVAL6					0x1f0
+#define OBVAL7					0x1f4
+#define CLKCTL					0x1f8
+
+/* Masks & Shifts below */
+#define START_PX_HOR_MASK			0x7FFF
+#define NUM_PX_HOR_MASK				0x7FFF
+#define START_VER_ONE_MASK			0x7FFF
+#define START_VER_TWO_MASK			0x7FFF
+#define NUM_LINES_VER				0x7FFF
+
+/* gain - offset masks */
+#define GAIN_INTEGER_SHIFT			9
+#define OFFSET_MASK				0xFFF
+#define GAIN_SDRAM_EN_SHIFT			12
+#define GAIN_IPIPE_EN_SHIFT			13
+#define GAIN_H3A_EN_SHIFT			14
+#define OFST_SDRAM_EN_SHIFT			8
+#define OFST_IPIPE_EN_SHIFT			9
+#define OFST_H3A_EN_SHIFT			10
+#define GAIN_OFFSET_EN_MASK			0x7700
+
+/* Culling */
+#define CULL_PAT_EVEN_LINE_SHIFT		8
+
+/* CCDCFG register */
+#define ISIF_YCINSWP_RAW			(0x00 << 4)
+#define ISIF_YCINSWP_YCBCR			(0x01 << 4)
+#define ISIF_CCDCFG_FIDMD_LATCH_VSYNC		(0x00 << 6)
+#define ISIF_CCDCFG_WENLOG_AND			(0x00 << 8)
+#define ISIF_CCDCFG_TRGSEL_WEN			(0x00 << 9)
+#define ISIF_CCDCFG_EXTRG_DISABLE		(0x00 << 10)
+#define ISIF_LATCH_ON_VSYNC_DISABLE		(0x01 << 15)
+#define ISIF_LATCH_ON_VSYNC_ENABLE		(0x00 << 15)
+#define ISIF_DATA_PACK_MASK			3
+#define ISIF_DATA_PACK16			0
+#define ISIF_DATA_PACK12			1
+#define ISIF_DATA_PACK8				2
+#define ISIF_PIX_ORDER_SHIFT			11
+#define ISIF_BW656_ENABLE			(0x01 << 5)
+
+/* MODESET registers */
+#define ISIF_VDHDOUT_INPUT			(0x00 << 0)
+#define ISIF_INPUT_SHIFT			12
+#define ISIF_RAW_INPUT_MODE			0
+#define ISIF_FID_POL_SHIFT			4
+#define ISIF_HD_POL_SHIFT			3
+#define ISIF_VD_POL_SHIFT			2
+#define ISIF_DATAPOL_NORMAL			0
+#define ISIF_DATAPOL_SHIFT			6
+#define ISIF_EXWEN_DISABLE 			0
+#define ISIF_EXWEN_SHIFT			5
+#define ISIF_FRM_FMT_SHIFT			7
+#define ISIF_DATASFT_SHIFT			8
+#define ISIF_LPF_SHIFT				14
+#define ISIF_LPF_MASK				1
+
+/* GAMMAWD registers */
+#define ISIF_ALAW_GAMA_WD_MASK			0xF
+#define ISIF_ALAW_GAMA_WD_SHIFT			1
+#define ISIF_ALAW_ENABLE			1
+#define ISIF_GAMMAWD_CFA_SHIFT			5
+
+/* HSIZE registers */
+#define ISIF_HSIZE_FLIP_MASK			1
+#define ISIF_HSIZE_FLIP_SHIFT			12
+
+/* MISC registers */
+#define ISIF_DPCM_EN_SHIFT			12
+#define ISIF_DPCM_PREDICTOR_SHIFT		13
+
+/* Black clamp related */
+#define ISIF_BC_MODE_COLOR_SHIFT		4
+#define ISIF_HORZ_BC_MODE_SHIFT			1
+#define ISIF_HORZ_BC_WIN_SEL_SHIFT		5
+#define ISIF_HORZ_BC_PIX_LIMIT_SHIFT		6
+#define ISIF_HORZ_BC_WIN_H_SIZE_SHIFT		8
+#define ISIF_HORZ_BC_WIN_V_SIZE_SHIFT		12
+#define	ISIF_VERT_BC_RST_VAL_SEL_SHIFT		4
+#define ISIF_VERT_BC_LINE_AVE_COEF_SHIFT	8
+
+/* VDFC registers */
+#define ISIF_VDFC_EN_SHIFT			4
+#define ISIF_VDFC_CORR_MOD_SHIFT		5
+#define ISIF_VDFC_CORR_WHOLE_LN_SHIFT		7
+#define ISIF_VDFC_LEVEL_SHFT_SHIFT		8
+#define ISIF_VDFC_POS_MASK			0x1FFF
+#define ISIF_DFCMEMCTL_DFCMARST_SHIFT		2
+
+/* CSC registers */
+#define ISIF_CSC_COEF_INTEG_MASK		7
+#define ISIF_CSC_COEF_DECIMAL_MASK		0x1f
+#define ISIF_CSC_COEF_INTEG_SHIFT		5
+#define ISIF_CSCM_MSB_SHIFT			8
+#define ISIF_DF_CSC_SPH_MASK			0x1FFF
+#define ISIF_DF_CSC_LNH_MASK			0x1FFF
+#define ISIF_DF_CSC_SLV_MASK			0x1FFF
+#define ISIF_DF_CSC_LNV_MASK			0x1FFF
+#define ISIF_DF_NUMLINES			0x7FFF
+#define ISIF_DF_NUMPIX				0x1FFF
+
+/* Offsets for LSC/DFC/Gain */
+#define ISIF_DATA_H_OFFSET_MASK			0x1FFF
+#define ISIF_DATA_V_OFFSET_MASK			0x1FFF
+
+/* Linearization */
+#define ISIF_LIN_CORRSFT_SHIFT			4
+#define ISIF_LIN_SCALE_FACT_INTEG_SHIFT		10
+
+
+/* Pattern registers */
+#define ISIF_PG_EN				(1 << 3)
+#define ISIF_SEL_PG_SRC				(3 << 4)
+#define ISIF_PG_VD_POL_SHIFT			0
+#define ISIF_PG_HD_POL_SHIFT			1
+
+/*random other junk*/
+#define ISIF_SYNCEN_VDHDEN_MASK			(1 << 0)
+#define ISIF_SYNCEN_WEN_MASK			(1 << 1)
+#define ISIF_SYNCEN_WEN_SHIFT			1
+
+#endif
diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c
new file mode 100644
index 0000000..c4a82a1
--- /dev/null
+++ b/drivers/media/platform/davinci/vpbe.c
@@ -0,0 +1,886 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Inc
+ *
+ * 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 version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <media/v4l2-device.h>
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe.h>
+#include <media/davinci/vpss.h>
+#include <media/davinci/vpbe_venc.h>
+
+#define VPBE_DEFAULT_OUTPUT	"Composite"
+#define VPBE_DEFAULT_MODE	"ntsc"
+
+static char *def_output = VPBE_DEFAULT_OUTPUT;
+static char *def_mode = VPBE_DEFAULT_MODE;
+static int debug;
+
+module_param(def_output, charp, S_IRUGO);
+module_param(def_mode, charp, S_IRUGO);
+module_param(debug, int, 0644);
+
+MODULE_PARM_DESC(def_output, "vpbe output name (default:Composite)");
+MODULE_PARM_DESC(def_mode, "vpbe output mode name (default:ntsc");
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+
+MODULE_DESCRIPTION("TI DMXXX VPBE Display controller");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments");
+
+/**
+ * vpbe_current_encoder_info - Get config info for current encoder
+ * @vpbe_dev - vpbe device ptr
+ *
+ * Return ptr to current encoder config info
+ */
+static struct encoder_config_info*
+vpbe_current_encoder_info(struct vpbe_device *vpbe_dev)
+{
+	struct vpbe_config *cfg = vpbe_dev->cfg;
+	int index = vpbe_dev->current_sd_index;
+
+	return ((index == 0) ? &cfg->venc :
+				&cfg->ext_encoders[index-1]);
+}
+
+/**
+ * vpbe_find_encoder_sd_index - Given a name find encoder sd index
+ *
+ * @vpbe_config - ptr to vpbe cfg
+ * @output_index - index used by application
+ *
+ * Return sd index of the encoder
+ */
+static int vpbe_find_encoder_sd_index(struct vpbe_config *cfg,
+			     int index)
+{
+	char *encoder_name = cfg->outputs[index].subdev_name;
+	int i;
+
+	/* Venc is always first	*/
+	if (!strcmp(encoder_name, cfg->venc.module_name))
+		return 0;
+
+	for (i = 0; i < cfg->num_ext_encoders; i++) {
+		if (!strcmp(encoder_name,
+		     cfg->ext_encoders[i].module_name))
+			return i+1;
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * vpbe_g_cropcap - Get crop capabilities of the display
+ * @vpbe_dev - vpbe device ptr
+ * @cropcap - cropcap is a ptr to struct v4l2_cropcap
+ *
+ * Update the crop capabilities in crop cap for current
+ * mode
+ */
+static int vpbe_g_cropcap(struct vpbe_device *vpbe_dev,
+			  struct v4l2_cropcap *cropcap)
+{
+	if (NULL == cropcap)
+		return -EINVAL;
+	cropcap->bounds.left = 0;
+	cropcap->bounds.top = 0;
+	cropcap->bounds.width = vpbe_dev->current_timings.xres;
+	cropcap->bounds.height = vpbe_dev->current_timings.yres;
+	cropcap->defrect = cropcap->bounds;
+
+	return 0;
+}
+
+/**
+ * vpbe_enum_outputs - enumerate outputs
+ * @vpbe_dev - vpbe device ptr
+ * @output - ptr to v4l2_output structure
+ *
+ * Enumerates the outputs available at the vpbe display
+ * returns the status, -EINVAL if end of output list
+ */
+static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev,
+			     struct v4l2_output *output)
+{
+	struct vpbe_config *cfg = vpbe_dev->cfg;
+	int temp_index = output->index;
+
+	if (temp_index >= cfg->num_outputs)
+		return -EINVAL;
+
+	*output = cfg->outputs[temp_index].output;
+	output->index = temp_index;
+
+	return 0;
+}
+
+static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode,
+			      int output_index)
+{
+	struct vpbe_config *cfg = vpbe_dev->cfg;
+	struct vpbe_enc_mode_info var;
+	int curr_output = output_index;
+	int i;
+
+	if (NULL == mode)
+		return -EINVAL;
+
+	for (i = 0; i < cfg->outputs[curr_output].num_modes; i++) {
+		var = cfg->outputs[curr_output].modes[i];
+		if (!strcmp(mode, var.name)) {
+			vpbe_dev->current_timings = var;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int vpbe_get_current_mode_info(struct vpbe_device *vpbe_dev,
+				      struct vpbe_enc_mode_info *mode_info)
+{
+	if (NULL == mode_info)
+		return -EINVAL;
+
+	*mode_info = vpbe_dev->current_timings;
+
+	return 0;
+}
+
+static int vpbe_get_dv_preset_info(struct vpbe_device *vpbe_dev,
+				   unsigned int dv_preset)
+{
+	struct vpbe_config *cfg = vpbe_dev->cfg;
+	struct vpbe_enc_mode_info var;
+	int curr_output = vpbe_dev->current_out_index;
+	int i;
+
+	for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) {
+		var = cfg->outputs[curr_output].modes[i];
+		if ((var.timings_type & VPBE_ENC_DV_PRESET) &&
+		  (var.timings.dv_preset == dv_preset)) {
+			vpbe_dev->current_timings = var;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+/* Get std by std id */
+static int vpbe_get_std_info(struct vpbe_device *vpbe_dev,
+			     v4l2_std_id std_id)
+{
+	struct vpbe_config *cfg = vpbe_dev->cfg;
+	struct vpbe_enc_mode_info var;
+	int curr_output = vpbe_dev->current_out_index;
+	int i;
+
+	for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) {
+		var = cfg->outputs[curr_output].modes[i];
+		if ((var.timings_type & VPBE_ENC_STD) &&
+		  (var.timings.std_id & std_id)) {
+			vpbe_dev->current_timings = var;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int vpbe_get_std_info_by_name(struct vpbe_device *vpbe_dev,
+				char *std_name)
+{
+	struct vpbe_config *cfg = vpbe_dev->cfg;
+	struct vpbe_enc_mode_info var;
+	int curr_output = vpbe_dev->current_out_index;
+	int i;
+
+	for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) {
+		var = cfg->outputs[curr_output].modes[i];
+		if (!strcmp(var.name, std_name)) {
+			vpbe_dev->current_timings = var;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * vpbe_set_output - Set output
+ * @vpbe_dev - vpbe device ptr
+ * @index - index of output
+ *
+ * Set vpbe output to the output specified by the index
+ */
+static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index)
+{
+	struct encoder_config_info *curr_enc_info =
+			vpbe_current_encoder_info(vpbe_dev);
+	struct vpbe_config *cfg = vpbe_dev->cfg;
+	struct venc_platform_data *venc_device = vpbe_dev->venc_device;
+	enum v4l2_mbus_pixelcode if_params;
+	int enc_out_index;
+	int sd_index;
+	int ret = 0;
+
+	if (index >= cfg->num_outputs)
+		return -EINVAL;
+
+	mutex_lock(&vpbe_dev->lock);
+
+	sd_index = vpbe_dev->current_sd_index;
+	enc_out_index = cfg->outputs[index].output.index;
+	/*
+	 * Currently we switch the encoder based on output selected
+	 * by the application. If media controller is implemented later
+	 * there is will be an API added to setup_link between venc
+	 * and external encoder. So in that case below comparison always
+	 * match and encoder will not be switched. But if application
+	 * chose not to use media controller, then this provides current
+	 * way of switching encoder at the venc output.
+	 */
+	if (strcmp(curr_enc_info->module_name,
+		   cfg->outputs[index].subdev_name)) {
+		/* Need to switch the encoder at the output */
+		sd_index = vpbe_find_encoder_sd_index(cfg, index);
+		if (sd_index < 0) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		if_params = cfg->outputs[index].if_params;
+		venc_device->setup_if_config(if_params);
+		if (ret)
+			goto out;
+	}
+
+	/* Set output at the encoder */
+	ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video,
+				       s_routing, 0, enc_out_index, 0);
+	if (ret)
+		goto out;
+
+	/*
+	 * It is assumed that venc or extenal encoder will set a default
+	 * mode in the sub device. For external encoder or LCD pannel output,
+	 * we also need to set up the lcd port for the required mode. So setup
+	 * the lcd port for the default mode that is configured in the board
+	 * arch/arm/mach-davinci/board-dm355-evm.setup file for the external
+	 * encoder.
+	 */
+	ret = vpbe_get_mode_info(vpbe_dev,
+				 cfg->outputs[index].default_mode, index);
+	if (!ret) {
+		struct osd_state *osd_device = vpbe_dev->osd_device;
+
+		osd_device->ops.set_left_margin(osd_device,
+			vpbe_dev->current_timings.left_margin);
+		osd_device->ops.set_top_margin(osd_device,
+		vpbe_dev->current_timings.upper_margin);
+		vpbe_dev->current_sd_index = sd_index;
+		vpbe_dev->current_out_index = index;
+	}
+out:
+	mutex_unlock(&vpbe_dev->lock);
+	return ret;
+}
+
+static int vpbe_set_default_output(struct vpbe_device *vpbe_dev)
+{
+	struct vpbe_config *cfg = vpbe_dev->cfg;
+	int ret = 0;
+	int i;
+
+	for (i = 0; i < cfg->num_outputs; i++) {
+		if (!strcmp(def_output,
+			    cfg->outputs[i].output.name)) {
+			ret = vpbe_set_output(vpbe_dev, i);
+			if (!ret)
+				vpbe_dev->current_out_index = i;
+			return ret;
+		}
+	}
+	return ret;
+}
+
+/**
+ * vpbe_get_output - Get output
+ * @vpbe_dev - vpbe device ptr
+ *
+ * return current vpbe output to the the index
+ */
+static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev)
+{
+	return vpbe_dev->current_out_index;
+}
+
+/**
+ * vpbe_s_dv_preset - Set the given preset timings in the encoder
+ *
+ * Sets the preset if supported by the current encoder. Return the status.
+ * 0 - success & -EINVAL on error
+ */
+static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev,
+		     struct v4l2_dv_preset *dv_preset)
+{
+	struct vpbe_config *cfg = vpbe_dev->cfg;
+	int out_index = vpbe_dev->current_out_index;
+	int sd_index = vpbe_dev->current_sd_index;
+	int ret;
+
+
+	if (!(cfg->outputs[out_index].output.capabilities &
+	    V4L2_OUT_CAP_PRESETS))
+		return -EINVAL;
+
+	ret = vpbe_get_dv_preset_info(vpbe_dev, dv_preset->preset);
+
+	if (ret)
+		return ret;
+
+	mutex_lock(&vpbe_dev->lock);
+
+
+	ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video,
+					s_dv_preset, dv_preset);
+	if (!ret && (vpbe_dev->amp != NULL)) {
+		/* Call amplifier subdevice */
+		ret = v4l2_subdev_call(vpbe_dev->amp, video,
+				s_dv_preset, dv_preset);
+	}
+	/* set the lcd controller output for the given mode */
+	if (!ret) {
+		struct osd_state *osd_device = vpbe_dev->osd_device;
+
+		osd_device->ops.set_left_margin(osd_device,
+		vpbe_dev->current_timings.left_margin);
+		osd_device->ops.set_top_margin(osd_device,
+		vpbe_dev->current_timings.upper_margin);
+	}
+	mutex_unlock(&vpbe_dev->lock);
+
+	return ret;
+}
+
+/**
+ * vpbe_g_dv_preset - Get the preset in the current encoder
+ *
+ * Get the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int vpbe_g_dv_preset(struct vpbe_device *vpbe_dev,
+		     struct v4l2_dv_preset *dv_preset)
+{
+	if (vpbe_dev->current_timings.timings_type &
+	  VPBE_ENC_DV_PRESET) {
+		dv_preset->preset = vpbe_dev->current_timings.timings.dv_preset;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * vpbe_enum_dv_presets - Enumerate the dv presets in the current encoder
+ *
+ * Get the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev,
+			 struct v4l2_dv_enum_preset *preset_info)
+{
+	struct vpbe_config *cfg = vpbe_dev->cfg;
+	int out_index = vpbe_dev->current_out_index;
+	struct vpbe_output *output = &cfg->outputs[out_index];
+	int j = 0;
+	int i;
+
+	if (!(output->output.capabilities & V4L2_OUT_CAP_PRESETS))
+		return -EINVAL;
+
+	for (i = 0; i < output->num_modes; i++) {
+		if (output->modes[i].timings_type == VPBE_ENC_DV_PRESET) {
+			if (j == preset_info->index)
+				break;
+			j++;
+		}
+	}
+
+	if (i == output->num_modes)
+		return -EINVAL;
+
+	return v4l_fill_dv_preset_info(output->modes[i].timings.dv_preset,
+					preset_info);
+}
+
+/**
+ * vpbe_s_std - Set the given standard in the encoder
+ *
+ * Sets the standard if supported by the current encoder. Return the status.
+ * 0 - success & -EINVAL on error
+ */
+static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id)
+{
+	struct vpbe_config *cfg = vpbe_dev->cfg;
+	int out_index = vpbe_dev->current_out_index;
+	int sd_index = vpbe_dev->current_sd_index;
+	int ret;
+
+	if (!(cfg->outputs[out_index].output.capabilities &
+		V4L2_OUT_CAP_STD))
+		return -EINVAL;
+
+	ret = vpbe_get_std_info(vpbe_dev, *std_id);
+	if (ret)
+		return ret;
+
+	mutex_lock(&vpbe_dev->lock);
+
+	ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video,
+			       s_std_output, *std_id);
+	/* set the lcd controller output for the given mode */
+	if (!ret) {
+		struct osd_state *osd_device = vpbe_dev->osd_device;
+
+		osd_device->ops.set_left_margin(osd_device,
+		vpbe_dev->current_timings.left_margin);
+		osd_device->ops.set_top_margin(osd_device,
+		vpbe_dev->current_timings.upper_margin);
+	}
+	mutex_unlock(&vpbe_dev->lock);
+
+	return ret;
+}
+
+/**
+ * vpbe_g_std - Get the standard in the current encoder
+ *
+ * Get the standard in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id)
+{
+	struct vpbe_enc_mode_info cur_timings = vpbe_dev->current_timings;
+
+	if (cur_timings.timings_type & VPBE_ENC_STD) {
+		*std_id = cur_timings.timings.std_id;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * vpbe_set_mode - Set mode in the current encoder using mode info
+ *
+ * Use the mode string to decide what timings to set in the encoder
+ * This is typically useful when fbset command is used to change the current
+ * timings by specifying a string to indicate the timings.
+ */
+static int vpbe_set_mode(struct vpbe_device *vpbe_dev,
+			 struct vpbe_enc_mode_info *mode_info)
+{
+	struct vpbe_enc_mode_info *preset_mode = NULL;
+	struct vpbe_config *cfg = vpbe_dev->cfg;
+	struct v4l2_dv_preset dv_preset;
+	struct osd_state *osd_device;
+	int out_index = vpbe_dev->current_out_index;
+	int ret = 0;
+	int i;
+
+	if ((NULL == mode_info) || (NULL == mode_info->name))
+		return -EINVAL;
+
+	for (i = 0; i < cfg->outputs[out_index].num_modes; i++) {
+		if (!strcmp(mode_info->name,
+		     cfg->outputs[out_index].modes[i].name)) {
+			preset_mode = &cfg->outputs[out_index].modes[i];
+			/*
+			 * it may be one of the 3 timings type. Check and
+			 * invoke right API
+			 */
+			if (preset_mode->timings_type & VPBE_ENC_STD)
+				return vpbe_s_std(vpbe_dev,
+						 &preset_mode->timings.std_id);
+			if (preset_mode->timings_type & VPBE_ENC_DV_PRESET) {
+				dv_preset.preset =
+					preset_mode->timings.dv_preset;
+				return vpbe_s_dv_preset(vpbe_dev, &dv_preset);
+			}
+		}
+	}
+
+	/* Only custom timing should reach here */
+	if (preset_mode == NULL)
+		return -EINVAL;
+
+	mutex_lock(&vpbe_dev->lock);
+
+	osd_device = vpbe_dev->osd_device;
+	vpbe_dev->current_timings = *preset_mode;
+	osd_device->ops.set_left_margin(osd_device,
+		vpbe_dev->current_timings.left_margin);
+	osd_device->ops.set_top_margin(osd_device,
+		vpbe_dev->current_timings.upper_margin);
+
+	mutex_unlock(&vpbe_dev->lock);
+
+	return ret;
+}
+
+static int vpbe_set_default_mode(struct vpbe_device *vpbe_dev)
+{
+	int ret;
+
+	ret = vpbe_get_std_info_by_name(vpbe_dev, def_mode);
+	if (ret)
+		return ret;
+
+	/* set the default mode in the encoder */
+	return vpbe_set_mode(vpbe_dev, &vpbe_dev->current_timings);
+}
+
+static int platform_device_get(struct device *dev, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct vpbe_device *vpbe_dev = data;
+
+	if (strcmp("vpbe-osd", pdev->name) == 0)
+		vpbe_dev->osd_device = platform_get_drvdata(pdev);
+	if (strcmp("vpbe-venc", pdev->name) == 0)
+		vpbe_dev->venc_device = dev_get_platdata(&pdev->dev);
+
+	return 0;
+}
+
+/**
+ * vpbe_initialize() - Initialize the vpbe display controller
+ * @vpbe_dev - vpbe device ptr
+ *
+ * Master frame buffer device drivers calls this to initialize vpbe
+ * display controller. This will then registers v4l2 device and the sub
+ * devices and sets a current encoder sub device for display. v4l2 display
+ * device driver is the master and frame buffer display device driver is
+ * the slave. Frame buffer display driver checks the initialized during
+ * probe and exit if not initialized. Returns status.
+ */
+static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
+{
+	struct encoder_config_info *enc_info;
+	struct amp_config_info *amp_info;
+	struct v4l2_subdev **enc_subdev;
+	struct osd_state *osd_device;
+	struct i2c_adapter *i2c_adap;
+	int output_index;
+	int num_encoders;
+	int ret = 0;
+	int err;
+	int i;
+
+	/*
+	 * v4l2 abd FBDev frame buffer devices will get the vpbe_dev pointer
+	 * from the platform device by iteration of platform drivers and
+	 * matching with device name
+	 */
+	if (NULL == vpbe_dev || NULL == dev) {
+		printk(KERN_ERR "Null device pointers.\n");
+		return -ENODEV;
+	}
+
+	if (vpbe_dev->initialized)
+		return 0;
+
+	mutex_lock(&vpbe_dev->lock);
+
+	if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) {
+		/* We have dac clock available for platform */
+		vpbe_dev->dac_clk = clk_get(vpbe_dev->pdev, "vpss_dac");
+		if (IS_ERR(vpbe_dev->dac_clk)) {
+			ret =  PTR_ERR(vpbe_dev->dac_clk);
+			goto vpbe_unlock;
+		}
+		if (clk_enable(vpbe_dev->dac_clk)) {
+			ret =  -ENODEV;
+			goto vpbe_unlock;
+		}
+	}
+
+	/* first enable vpss clocks */
+	vpss_enable_clock(VPSS_VPBE_CLOCK, 1);
+
+	/* First register a v4l2 device */
+	ret = v4l2_device_register(dev, &vpbe_dev->v4l2_dev);
+	if (ret) {
+		v4l2_err(dev->driver,
+			"Unable to register v4l2 device.\n");
+		goto vpbe_fail_clock;
+	}
+	v4l2_info(&vpbe_dev->v4l2_dev, "vpbe v4l2 device registered\n");
+
+	err = bus_for_each_dev(&platform_bus_type, NULL, vpbe_dev,
+			       platform_device_get);
+	if (err < 0)
+		return err;
+
+	vpbe_dev->venc = venc_sub_dev_init(&vpbe_dev->v4l2_dev,
+					   vpbe_dev->cfg->venc.module_name);
+	/* register venc sub device */
+	if (vpbe_dev->venc == NULL) {
+		v4l2_err(&vpbe_dev->v4l2_dev,
+			"vpbe unable to init venc sub device\n");
+		ret = -ENODEV;
+		goto vpbe_fail_v4l2_device;
+	}
+	/* initialize osd device */
+	osd_device = vpbe_dev->osd_device;
+
+	if (NULL != osd_device->ops.initialize) {
+		err = osd_device->ops.initialize(osd_device);
+		if (err) {
+			v4l2_err(&vpbe_dev->v4l2_dev,
+				 "unable to initialize the OSD device");
+			err = -ENOMEM;
+			goto vpbe_fail_v4l2_device;
+		}
+	}
+
+	/*
+	 * Register any external encoders that are configured. At index 0 we
+	 * store venc sd index.
+	 */
+	num_encoders = vpbe_dev->cfg->num_ext_encoders + 1;
+	vpbe_dev->encoders = kmalloc(
+				sizeof(struct v4l2_subdev *)*num_encoders,
+				GFP_KERNEL);
+	if (NULL == vpbe_dev->encoders) {
+		v4l2_err(&vpbe_dev->v4l2_dev,
+			"unable to allocate memory for encoders sub devices");
+		ret = -ENOMEM;
+		goto vpbe_fail_v4l2_device;
+	}
+
+	i2c_adap = i2c_get_adapter(vpbe_dev->cfg->i2c_adapter_id);
+	for (i = 0; i < (vpbe_dev->cfg->num_ext_encoders + 1); i++) {
+		if (i == 0) {
+			/* venc is at index 0 */
+			enc_subdev = &vpbe_dev->encoders[i];
+			*enc_subdev = vpbe_dev->venc;
+			continue;
+		}
+		enc_info = &vpbe_dev->cfg->ext_encoders[i];
+		if (enc_info->is_i2c) {
+			enc_subdev = &vpbe_dev->encoders[i];
+			*enc_subdev = v4l2_i2c_new_subdev_board(
+						&vpbe_dev->v4l2_dev, i2c_adap,
+						&enc_info->board_info, NULL);
+			if (*enc_subdev)
+				v4l2_info(&vpbe_dev->v4l2_dev,
+					  "v4l2 sub device %s registered\n",
+					  enc_info->module_name);
+			else {
+				v4l2_err(&vpbe_dev->v4l2_dev, "encoder %s"
+					 " failed to register",
+					 enc_info->module_name);
+				ret = -ENODEV;
+				goto vpbe_fail_sd_register;
+			}
+		} else
+			v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders"
+				 " currently not supported");
+	}
+	/* Add amplifier subdevice for dm365 */
+	if ((strcmp(vpbe_dev->cfg->module_name, "dm365-vpbe-display") == 0) &&
+			vpbe_dev->cfg->amp != NULL) {
+		amp_info = vpbe_dev->cfg->amp;
+		if (amp_info->is_i2c) {
+			vpbe_dev->amp = v4l2_i2c_new_subdev_board(
+			&vpbe_dev->v4l2_dev, i2c_adap,
+			&amp_info->board_info, NULL);
+			if (!vpbe_dev->amp) {
+				v4l2_err(&vpbe_dev->v4l2_dev,
+					 "amplifier %s failed to register",
+					 amp_info->module_name);
+				ret = -ENODEV;
+				goto vpbe_fail_amp_register;
+			}
+			v4l2_info(&vpbe_dev->v4l2_dev,
+					  "v4l2 sub device %s registered\n",
+					  amp_info->module_name);
+		} else {
+			    vpbe_dev->amp = NULL;
+			    v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c amplifiers"
+			    " currently not supported");
+		}
+	} else {
+	    vpbe_dev->amp = NULL;
+	}
+
+	/* set the current encoder and output to that of venc by default */
+	vpbe_dev->current_sd_index = 0;
+	vpbe_dev->current_out_index = 0;
+	output_index = 0;
+
+	mutex_unlock(&vpbe_dev->lock);
+
+	printk(KERN_NOTICE "Setting default output to %s\n", def_output);
+	ret = vpbe_set_default_output(vpbe_dev);
+	if (ret) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default output %s",
+			 def_output);
+		return ret;
+	}
+
+	printk(KERN_NOTICE "Setting default mode to %s\n", def_mode);
+	ret = vpbe_set_default_mode(vpbe_dev);
+	if (ret) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default mode %s",
+			 def_mode);
+		return ret;
+	}
+	vpbe_dev->initialized = 1;
+	/* TBD handling of bootargs for default output and mode */
+	return 0;
+
+vpbe_fail_amp_register:
+	kfree(vpbe_dev->amp);
+vpbe_fail_sd_register:
+	kfree(vpbe_dev->encoders);
+vpbe_fail_v4l2_device:
+	v4l2_device_unregister(&vpbe_dev->v4l2_dev);
+vpbe_fail_clock:
+	if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0)
+		clk_put(vpbe_dev->dac_clk);
+vpbe_unlock:
+	mutex_unlock(&vpbe_dev->lock);
+	return ret;
+}
+
+/**
+ * vpbe_deinitialize() - de-initialize the vpbe display controller
+ * @dev - Master and slave device ptr
+ *
+ * vpbe_master and slave frame buffer devices calls this to de-initialize
+ * the display controller. It is called when master and slave device
+ * driver modules are removed and no longer requires the display controller.
+ */
+static void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev)
+{
+	v4l2_device_unregister(&vpbe_dev->v4l2_dev);
+	if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0)
+		clk_put(vpbe_dev->dac_clk);
+
+	kfree(vpbe_dev->amp);
+	kfree(vpbe_dev->encoders);
+	vpbe_dev->initialized = 0;
+	/* disable vpss clocks */
+	vpss_enable_clock(VPSS_VPBE_CLOCK, 0);
+}
+
+static struct vpbe_device_ops vpbe_dev_ops = {
+	.g_cropcap = vpbe_g_cropcap,
+	.enum_outputs = vpbe_enum_outputs,
+	.set_output = vpbe_set_output,
+	.get_output = vpbe_get_output,
+	.s_dv_preset = vpbe_s_dv_preset,
+	.g_dv_preset = vpbe_g_dv_preset,
+	.enum_dv_presets = vpbe_enum_dv_presets,
+	.s_std = vpbe_s_std,
+	.g_std = vpbe_g_std,
+	.initialize = vpbe_initialize,
+	.deinitialize = vpbe_deinitialize,
+	.get_mode_info = vpbe_get_current_mode_info,
+	.set_mode = vpbe_set_mode,
+};
+
+static __devinit int vpbe_probe(struct platform_device *pdev)
+{
+	struct vpbe_device *vpbe_dev;
+	struct vpbe_config *cfg;
+	int ret = -EINVAL;
+
+	if (pdev->dev.platform_data == NULL) {
+		v4l2_err(pdev->dev.driver, "No platform data\n");
+		return -ENODEV;
+	}
+	cfg = pdev->dev.platform_data;
+
+	if (!cfg->module_name[0] ||
+	    !cfg->osd.module_name[0] ||
+	    !cfg->venc.module_name[0]) {
+		v4l2_err(pdev->dev.driver, "vpbe display module names not"
+			 " defined\n");
+		return ret;
+	}
+
+	vpbe_dev = kzalloc(sizeof(*vpbe_dev), GFP_KERNEL);
+	if (vpbe_dev == NULL) {
+		v4l2_err(pdev->dev.driver, "Unable to allocate memory"
+			 " for vpbe_device\n");
+		return -ENOMEM;
+	}
+	vpbe_dev->cfg = cfg;
+	vpbe_dev->ops = vpbe_dev_ops;
+	vpbe_dev->pdev = &pdev->dev;
+
+	if (cfg->outputs->num_modes > 0)
+		vpbe_dev->current_timings = vpbe_dev->cfg->outputs[0].modes[0];
+	else {
+		kfree(vpbe_dev);
+		return -ENODEV;
+	}
+
+	/* set the driver data in platform device */
+	platform_set_drvdata(pdev, vpbe_dev);
+	mutex_init(&vpbe_dev->lock);
+
+	return 0;
+}
+
+static int vpbe_remove(struct platform_device *device)
+{
+	struct vpbe_device *vpbe_dev = platform_get_drvdata(device);
+
+	kfree(vpbe_dev);
+
+	return 0;
+}
+
+static struct platform_driver vpbe_driver = {
+	.driver	= {
+		.name	= "vpbe_controller",
+		.owner	= THIS_MODULE,
+	},
+	.probe = vpbe_probe,
+	.remove = vpbe_remove,
+};
+
+module_platform_driver(vpbe_driver);
diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c
new file mode 100644
index 0000000..9a05c81
--- /dev/null
+++ b/drivers/media/platform/davinci/vpbe_display.c
@@ -0,0 +1,1838 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; 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/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+
+#include <asm/pgtable.h>
+#include <mach/cputype.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/davinci/vpbe_display.h>
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe.h>
+#include <media/davinci/vpbe_venc.h>
+#include <media/davinci/vpbe_osd.h>
+#include "vpbe_venc_regs.h"
+
+#define VPBE_DISPLAY_DRIVER "vpbe-v4l2"
+
+static int debug;
+
+#define VPBE_DEFAULT_NUM_BUFS 3
+
+module_param(debug, int, 0644);
+
+static int venc_is_second_field(struct vpbe_display *disp_dev)
+{
+	struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+	int ret;
+	int val;
+
+	ret = v4l2_subdev_call(vpbe_dev->venc,
+			       core,
+			       ioctl,
+			       VENC_GET_FLD,
+			       &val);
+	if (ret < 0) {
+		v4l2_err(&vpbe_dev->v4l2_dev,
+			 "Error in getting Field ID 0\n");
+	}
+	return val;
+}
+
+static void vpbe_isr_even_field(struct vpbe_display *disp_obj,
+				struct vpbe_layer *layer)
+{
+	struct timespec timevalue;
+
+	if (layer->cur_frm == layer->next_frm)
+		return;
+	ktime_get_ts(&timevalue);
+	layer->cur_frm->ts.tv_sec = timevalue.tv_sec;
+	layer->cur_frm->ts.tv_usec = timevalue.tv_nsec / NSEC_PER_USEC;
+	layer->cur_frm->state = VIDEOBUF_DONE;
+	wake_up_interruptible(&layer->cur_frm->done);
+	/* Make cur_frm pointing to next_frm */
+	layer->cur_frm = layer->next_frm;
+}
+
+static void vpbe_isr_odd_field(struct vpbe_display *disp_obj,
+				struct vpbe_layer *layer)
+{
+	struct osd_state *osd_device = disp_obj->osd_device;
+	unsigned long addr;
+
+	spin_lock(&disp_obj->dma_queue_lock);
+	if (list_empty(&layer->dma_queue) ||
+		(layer->cur_frm != layer->next_frm)) {
+		spin_unlock(&disp_obj->dma_queue_lock);
+		return;
+	}
+	/*
+	 * one field is displayed configure
+	 * the next frame if it is available
+	 * otherwise hold on current frame
+	 * Get next from the buffer queue
+	 */
+	layer->next_frm = list_entry(
+				layer->dma_queue.next,
+				struct  videobuf_buffer,
+				queue);
+	/* Remove that from the buffer queue */
+	list_del(&layer->next_frm->queue);
+	spin_unlock(&disp_obj->dma_queue_lock);
+	/* Mark state of the frame to active */
+	layer->next_frm->state = VIDEOBUF_ACTIVE;
+	addr = videobuf_to_dma_contig(layer->next_frm);
+	osd_device->ops.start_layer(osd_device,
+			layer->layer_info.id,
+			addr,
+			disp_obj->cbcr_ofst);
+}
+
+/* interrupt service routine */
+static irqreturn_t venc_isr(int irq, void *arg)
+{
+	struct vpbe_display *disp_dev = (struct vpbe_display *)arg;
+	struct vpbe_layer *layer;
+	static unsigned last_event;
+	unsigned event = 0;
+	int fid;
+	int i;
+
+	if ((NULL == arg) || (NULL == disp_dev->dev[0]))
+		return IRQ_HANDLED;
+
+	if (venc_is_second_field(disp_dev))
+		event |= VENC_SECOND_FIELD;
+	else
+		event |= VENC_FIRST_FIELD;
+
+	if (event == (last_event & ~VENC_END_OF_FRAME)) {
+		/*
+		* If the display is non-interlaced, then we need to flag the
+		* end-of-frame event at every interrupt regardless of the
+		* value of the FIDST bit.  We can conclude that the display is
+		* non-interlaced if the value of the FIDST bit is unchanged
+		* from the previous interrupt.
+		*/
+		event |= VENC_END_OF_FRAME;
+	} else if (event == VENC_SECOND_FIELD) {
+		/* end-of-frame for interlaced display */
+		event |= VENC_END_OF_FRAME;
+	}
+	last_event = event;
+
+	for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+		layer = disp_dev->dev[i];
+		/* If streaming is started in this layer */
+		if (!layer->started)
+			continue;
+
+		if (layer->layer_first_int) {
+			layer->layer_first_int = 0;
+			continue;
+		}
+		/* Check the field format */
+		if ((V4L2_FIELD_NONE == layer->pix_fmt.field) &&
+			(event & VENC_END_OF_FRAME)) {
+			/* Progressive mode */
+
+			vpbe_isr_even_field(disp_dev, layer);
+			vpbe_isr_odd_field(disp_dev, layer);
+		} else {
+		/* Interlaced mode */
+
+			layer->field_id ^= 1;
+			if (event & VENC_FIRST_FIELD)
+				fid = 0;
+			else
+				fid = 1;
+
+			/*
+			* If field id does not match with store
+			* field id
+			*/
+			if (fid != layer->field_id) {
+				/* Make them in sync */
+				layer->field_id = fid;
+				continue;
+			}
+			/*
+			* device field id and local field id are
+			* in sync. If this is even field
+			*/
+			if (0 == fid)
+				vpbe_isr_even_field(disp_dev, layer);
+			else  /* odd field */
+				vpbe_isr_odd_field(disp_dev, layer);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * vpbe_buffer_prepare()
+ * This is the callback function called from videobuf_qbuf() function
+ * the buffer is prepared and user space virtual address is converted into
+ * physical address
+ */
+static int vpbe_buffer_prepare(struct videobuf_queue *q,
+				  struct videobuf_buffer *vb,
+				  enum v4l2_field field)
+{
+	struct vpbe_fh *fh = q->priv_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+	unsigned long addr;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+				"vpbe_buffer_prepare\n");
+
+	/* If buffer is not initialized, initialize it */
+	if (VIDEOBUF_NEEDS_INIT == vb->state) {
+		vb->width = layer->pix_fmt.width;
+		vb->height = layer->pix_fmt.height;
+		vb->size = layer->pix_fmt.sizeimage;
+		vb->field = field;
+
+		ret = videobuf_iolock(q, vb, NULL);
+		if (ret < 0) {
+			v4l2_err(&vpbe_dev->v4l2_dev, "Failed to map \
+				user address\n");
+			return -EINVAL;
+		}
+
+		addr = videobuf_to_dma_contig(vb);
+
+		if (q->streaming) {
+			if (!IS_ALIGNED(addr, 8)) {
+				v4l2_err(&vpbe_dev->v4l2_dev,
+					"buffer_prepare:offset is \
+					not aligned to 32 bytes\n");
+				return -EINVAL;
+			}
+		}
+		vb->state = VIDEOBUF_PREPARED;
+	}
+	return 0;
+}
+
+/*
+ * vpbe_buffer_setup()
+ * This function allocates memory for the buffers
+ */
+static int vpbe_buffer_setup(struct videobuf_queue *q,
+				unsigned int *count,
+				unsigned int *size)
+{
+	/* Get the file handle object and layer object */
+	struct vpbe_fh *fh = q->priv_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n");
+
+	*size = layer->pix_fmt.sizeimage;
+
+	/* Store number of buffers allocated in numbuffer member */
+	if (*count < VPBE_DEFAULT_NUM_BUFS)
+		*count = layer->numbuffers = VPBE_DEFAULT_NUM_BUFS;
+
+	return 0;
+}
+
+/*
+ * vpbe_buffer_queue()
+ * This function adds the buffer to DMA queue
+ */
+static void vpbe_buffer_queue(struct videobuf_queue *q,
+				 struct videobuf_buffer *vb)
+{
+	/* Get the file handle object and layer object */
+	struct vpbe_fh *fh = q->priv_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_display *disp = fh->disp_dev;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+	unsigned long flags;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+			"vpbe_buffer_queue\n");
+
+	/* add the buffer to the DMA queue */
+	spin_lock_irqsave(&disp->dma_queue_lock, flags);
+	list_add_tail(&vb->queue, &layer->dma_queue);
+	spin_unlock_irqrestore(&disp->dma_queue_lock, flags);
+	/* Change state of the buffer */
+	vb->state = VIDEOBUF_QUEUED;
+}
+
+/*
+ * vpbe_buffer_release()
+ * This function is called from the videobuf layer to free memory allocated to
+ * the buffers
+ */
+static void vpbe_buffer_release(struct videobuf_queue *q,
+				   struct videobuf_buffer *vb)
+{
+	/* Get the file handle object and layer object */
+	struct vpbe_fh *fh = q->priv_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+			"vpbe_buffer_release\n");
+
+	if (V4L2_MEMORY_USERPTR != layer->memory)
+		videobuf_dma_contig_free(q, vb);
+
+	vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops video_qops = {
+	.buf_setup = vpbe_buffer_setup,
+	.buf_prepare = vpbe_buffer_prepare,
+	.buf_queue = vpbe_buffer_queue,
+	.buf_release = vpbe_buffer_release,
+};
+
+static
+struct vpbe_layer*
+_vpbe_display_get_other_win_layer(struct vpbe_display *disp_dev,
+			struct vpbe_layer *layer)
+{
+	enum vpbe_display_device_id thiswin, otherwin;
+	thiswin = layer->device_id;
+
+	otherwin = (thiswin == VPBE_DISPLAY_DEVICE_0) ?
+	VPBE_DISPLAY_DEVICE_1 : VPBE_DISPLAY_DEVICE_0;
+	return disp_dev->dev[otherwin];
+}
+
+static int vpbe_set_osd_display_params(struct vpbe_display *disp_dev,
+			struct vpbe_layer *layer)
+{
+	struct osd_layer_config *cfg  = &layer->layer_info.config;
+	struct osd_state *osd_device = disp_dev->osd_device;
+	struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+	unsigned long addr;
+	int ret;
+
+	addr = videobuf_to_dma_contig(layer->cur_frm);
+	/* Set address in the display registers */
+	osd_device->ops.start_layer(osd_device,
+				    layer->layer_info.id,
+				    addr,
+				    disp_dev->cbcr_ofst);
+
+	ret = osd_device->ops.enable_layer(osd_device,
+				layer->layer_info.id, 0);
+	if (ret < 0) {
+		v4l2_err(&vpbe_dev->v4l2_dev,
+			"Error in enabling osd window layer 0\n");
+		return -1;
+	}
+
+	/* Enable the window */
+	layer->layer_info.enable = 1;
+	if (cfg->pixfmt == PIXFMT_NV12) {
+		struct vpbe_layer *otherlayer =
+			_vpbe_display_get_other_win_layer(disp_dev, layer);
+
+		ret = osd_device->ops.enable_layer(osd_device,
+				otherlayer->layer_info.id, 1);
+		if (ret < 0) {
+			v4l2_err(&vpbe_dev->v4l2_dev,
+				"Error in enabling osd window layer 1\n");
+			return -1;
+		}
+		otherlayer->layer_info.enable = 1;
+	}
+	return 0;
+}
+
+static void
+vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev,
+			struct vpbe_layer *layer,
+			int expected_xsize, int expected_ysize)
+{
+	struct display_layer_info *layer_info = &layer->layer_info;
+	struct v4l2_pix_format *pixfmt = &layer->pix_fmt;
+	struct osd_layer_config *cfg  = &layer->layer_info.config;
+	struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+	int calculated_xsize;
+	int h_exp = 0;
+	int v_exp = 0;
+	int h_scale;
+	int v_scale;
+
+	v4l2_std_id standard_id = vpbe_dev->current_timings.timings.std_id;
+
+	/*
+	 * Application initially set the image format. Current display
+	 * size is obtained from the vpbe display controller. expected_xsize
+	 * and expected_ysize are set through S_CROP ioctl. Based on this,
+	 * driver will calculate the scale factors for vertical and
+	 * horizontal direction so that the image is displayed scaled
+	 * and expanded. Application uses expansion to display the image
+	 * in a square pixel. Otherwise it is displayed using displays
+	 * pixel aspect ratio.It is expected that application chooses
+	 * the crop coordinates for cropped or scaled display. if crop
+	 * size is less than the image size, it is displayed cropped or
+	 * it is displayed scaled and/or expanded.
+	 *
+	 * to begin with, set the crop window same as expected. Later we
+	 * will override with scaled window size
+	 */
+
+	cfg->xsize = pixfmt->width;
+	cfg->ysize = pixfmt->height;
+	layer_info->h_zoom = ZOOM_X1;	/* no horizontal zoom */
+	layer_info->v_zoom = ZOOM_X1;	/* no horizontal zoom */
+	layer_info->h_exp = H_EXP_OFF;	/* no horizontal zoom */
+	layer_info->v_exp = V_EXP_OFF;	/* no horizontal zoom */
+
+	if (pixfmt->width < expected_xsize) {
+		h_scale = vpbe_dev->current_timings.xres / pixfmt->width;
+		if (h_scale < 2)
+			h_scale = 1;
+		else if (h_scale >= 4)
+			h_scale = 4;
+		else
+			h_scale = 2;
+		cfg->xsize *= h_scale;
+		if (cfg->xsize < expected_xsize) {
+			if ((standard_id & V4L2_STD_525_60) ||
+			(standard_id & V4L2_STD_625_50)) {
+				calculated_xsize = (cfg->xsize *
+					VPBE_DISPLAY_H_EXP_RATIO_N) /
+					VPBE_DISPLAY_H_EXP_RATIO_D;
+				if (calculated_xsize <= expected_xsize) {
+					h_exp = 1;
+					cfg->xsize = calculated_xsize;
+				}
+			}
+		}
+		if (h_scale == 2)
+			layer_info->h_zoom = ZOOM_X2;
+		else if (h_scale == 4)
+			layer_info->h_zoom = ZOOM_X4;
+		if (h_exp)
+			layer_info->h_exp = H_EXP_9_OVER_8;
+	} else {
+		/* no scaling, only cropping. Set display area to crop area */
+		cfg->xsize = expected_xsize;
+	}
+
+	if (pixfmt->height < expected_ysize) {
+		v_scale = expected_ysize / pixfmt->height;
+		if (v_scale < 2)
+			v_scale = 1;
+		else if (v_scale >= 4)
+			v_scale = 4;
+		else
+			v_scale = 2;
+		cfg->ysize *= v_scale;
+		if (cfg->ysize < expected_ysize) {
+			if ((standard_id & V4L2_STD_625_50)) {
+				calculated_xsize = (cfg->ysize *
+					VPBE_DISPLAY_V_EXP_RATIO_N) /
+					VPBE_DISPLAY_V_EXP_RATIO_D;
+				if (calculated_xsize <= expected_ysize) {
+					v_exp = 1;
+					cfg->ysize = calculated_xsize;
+				}
+			}
+		}
+		if (v_scale == 2)
+			layer_info->v_zoom = ZOOM_X2;
+		else if (v_scale == 4)
+			layer_info->v_zoom = ZOOM_X4;
+		if (v_exp)
+			layer_info->h_exp = V_EXP_6_OVER_5;
+	} else {
+		/* no scaling, only cropping. Set display area to crop area */
+		cfg->ysize = expected_ysize;
+	}
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+		"crop display xsize = %d, ysize = %d\n",
+		cfg->xsize, cfg->ysize);
+}
+
+static void vpbe_disp_adj_position(struct vpbe_display *disp_dev,
+			struct vpbe_layer *layer,
+			int top, int left)
+{
+	struct osd_layer_config *cfg = &layer->layer_info.config;
+	struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+
+	cfg->xpos = min((unsigned int)left,
+			vpbe_dev->current_timings.xres - cfg->xsize);
+	cfg->ypos = min((unsigned int)top,
+			vpbe_dev->current_timings.yres - cfg->ysize);
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+		"new xpos = %d, ypos = %d\n",
+		cfg->xpos, cfg->ypos);
+}
+
+static void vpbe_disp_check_window_params(struct vpbe_display *disp_dev,
+			struct v4l2_rect *c)
+{
+	struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+
+	if ((c->width == 0) ||
+	  ((c->width + c->left) > vpbe_dev->current_timings.xres))
+		c->width = vpbe_dev->current_timings.xres - c->left;
+
+	if ((c->height == 0) || ((c->height + c->top) >
+	  vpbe_dev->current_timings.yres))
+		c->height = vpbe_dev->current_timings.yres - c->top;
+
+	/* window height must be even for interlaced display */
+	if (vpbe_dev->current_timings.interlaced)
+		c->height &= (~0x01);
+
+}
+
+/**
+ * vpbe_try_format()
+ * If user application provides width and height, and have bytesperline set
+ * to zero, driver calculates bytesperline and sizeimage based on hardware
+ * limits.
+ */
+static int vpbe_try_format(struct vpbe_display *disp_dev,
+			struct v4l2_pix_format *pixfmt, int check)
+{
+	struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+	int min_height = 1;
+	int min_width = 32;
+	int max_height;
+	int max_width;
+	int bpp;
+
+	if ((pixfmt->pixelformat != V4L2_PIX_FMT_UYVY) &&
+	    (pixfmt->pixelformat != V4L2_PIX_FMT_NV12))
+		/* choose default as V4L2_PIX_FMT_UYVY */
+		pixfmt->pixelformat = V4L2_PIX_FMT_UYVY;
+
+	/* Check the field format */
+	if ((pixfmt->field != V4L2_FIELD_INTERLACED) &&
+		(pixfmt->field != V4L2_FIELD_NONE)) {
+		if (vpbe_dev->current_timings.interlaced)
+			pixfmt->field = V4L2_FIELD_INTERLACED;
+		else
+			pixfmt->field = V4L2_FIELD_NONE;
+	}
+
+	if (pixfmt->field == V4L2_FIELD_INTERLACED)
+		min_height = 2;
+
+	if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12)
+		bpp = 1;
+	else
+		bpp = 2;
+
+	max_width = vpbe_dev->current_timings.xres;
+	max_height = vpbe_dev->current_timings.yres;
+
+	min_width /= bpp;
+
+	if (!pixfmt->width || (pixfmt->width < min_width) ||
+		(pixfmt->width > max_width)) {
+		pixfmt->width = vpbe_dev->current_timings.xres;
+	}
+
+	if (!pixfmt->height || (pixfmt->height  < min_height) ||
+		(pixfmt->height  > max_height)) {
+		pixfmt->height = vpbe_dev->current_timings.yres;
+	}
+
+	if (pixfmt->bytesperline < (pixfmt->width * bpp))
+		pixfmt->bytesperline = pixfmt->width * bpp;
+
+	/* Make the bytesperline 32 byte aligned */
+	pixfmt->bytesperline = ((pixfmt->width * bpp + 31) & ~31);
+
+	if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12)
+		pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height +
+				(pixfmt->bytesperline * pixfmt->height >> 1);
+	else
+		pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
+
+	return 0;
+}
+
+static int vpbe_display_g_priority(struct file *file, void *priv,
+				enum v4l2_priority *p)
+{
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_layer *layer = fh->layer;
+
+	*p = v4l2_prio_max(&layer->prio);
+
+	return 0;
+}
+
+static int vpbe_display_s_priority(struct file *file, void *priv,
+				enum v4l2_priority p)
+{
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_layer *layer = fh->layer;
+	int ret;
+
+	ret = v4l2_prio_change(&layer->prio, &fh->prio, p);
+
+	return ret;
+}
+
+static int vpbe_display_querycap(struct file *file, void  *priv,
+			       struct v4l2_capability *cap)
+{
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+	cap->version = VPBE_DISPLAY_VERSION_CODE;
+	cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+	strlcpy(cap->driver, VPBE_DISPLAY_DRIVER, sizeof(cap->driver));
+	strlcpy(cap->bus_info, "platform", sizeof(cap->bus_info));
+	strlcpy(cap->card, vpbe_dev->cfg->module_name, sizeof(cap->card));
+
+	return 0;
+}
+
+static int vpbe_display_s_crop(struct file *file, void *priv,
+			     struct v4l2_crop *crop)
+{
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_display *disp_dev = fh->disp_dev;
+	struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+	struct osd_layer_config *cfg = &layer->layer_info.config;
+	struct osd_state *osd_device = disp_dev->osd_device;
+	struct v4l2_rect *rect = &crop->c;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+		"VIDIOC_S_CROP, layer id = %d\n", layer->device_id);
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n");
+		return -EINVAL;
+	}
+
+	if (rect->top < 0)
+		rect->top = 0;
+	if (rect->left < 0)
+		rect->left = 0;
+
+	vpbe_disp_check_window_params(disp_dev, rect);
+
+	osd_device->ops.get_layer_config(osd_device,
+			layer->layer_info.id, cfg);
+
+	vpbe_disp_calculate_scale_factor(disp_dev, layer,
+					rect->width,
+					rect->height);
+	vpbe_disp_adj_position(disp_dev, layer, rect->top,
+					rect->left);
+	ret = osd_device->ops.set_layer_config(osd_device,
+				layer->layer_info.id, cfg);
+	if (ret < 0) {
+		v4l2_err(&vpbe_dev->v4l2_dev,
+			"Error in set layer config:\n");
+		return -EINVAL;
+	}
+
+	/* apply zooming and h or v expansion */
+	osd_device->ops.set_zoom(osd_device,
+			layer->layer_info.id,
+			layer->layer_info.h_zoom,
+			layer->layer_info.v_zoom);
+	ret = osd_device->ops.set_vid_expansion(osd_device,
+			layer->layer_info.h_exp,
+			layer->layer_info.v_exp);
+	if (ret < 0) {
+		v4l2_err(&vpbe_dev->v4l2_dev,
+		"Error in set vid expansion:\n");
+		return -EINVAL;
+	}
+
+	if ((layer->layer_info.h_zoom != ZOOM_X1) ||
+		(layer->layer_info.v_zoom != ZOOM_X1) ||
+		(layer->layer_info.h_exp != H_EXP_OFF) ||
+		(layer->layer_info.v_exp != V_EXP_OFF))
+		/* Enable expansion filter */
+		osd_device->ops.set_interpolation_filter(osd_device, 1);
+	else
+		osd_device->ops.set_interpolation_filter(osd_device, 0);
+
+	return 0;
+}
+
+static int vpbe_display_g_crop(struct file *file, void *priv,
+			     struct v4l2_crop *crop)
+{
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct osd_layer_config *cfg = &layer->layer_info.config;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+	struct osd_state *osd_device = fh->disp_dev->osd_device;
+	struct v4l2_rect *rect = &crop->c;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+			"VIDIOC_G_CROP, layer id = %d\n",
+			layer->device_id);
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n");
+		ret = -EINVAL;
+	}
+	osd_device->ops.get_layer_config(osd_device,
+				layer->layer_info.id, cfg);
+	rect->top = cfg->ypos;
+	rect->left = cfg->xpos;
+	rect->width = cfg->xsize;
+	rect->height = cfg->ysize;
+
+	return 0;
+}
+
+static int vpbe_display_cropcap(struct file *file, void *priv,
+			      struct v4l2_cropcap *cropcap)
+{
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n");
+
+	cropcap->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	cropcap->bounds.left = 0;
+	cropcap->bounds.top = 0;
+	cropcap->bounds.width = vpbe_dev->current_timings.xres;
+	cropcap->bounds.height = vpbe_dev->current_timings.yres;
+	cropcap->pixelaspect = vpbe_dev->current_timings.aspect;
+	cropcap->defrect = cropcap->bounds;
+	return 0;
+}
+
+static int vpbe_display_g_fmt(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+			"VIDIOC_G_FMT, layer id = %d\n",
+			layer->device_id);
+
+	/* If buffer type is video output */
+	if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n");
+		return -EINVAL;
+	}
+	/* Fill in the information about format */
+	fmt->fmt.pix = layer->pix_fmt;
+
+	return 0;
+}
+
+static int vpbe_display_enum_fmt(struct file *file, void  *priv,
+				   struct v4l2_fmtdesc *fmt)
+{
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+	unsigned int index = 0;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+				"VIDIOC_ENUM_FMT, layer id = %d\n",
+				layer->device_id);
+	if (fmt->index > 1) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "Invalid format index\n");
+		return -EINVAL;
+	}
+
+	/* Fill in the information about format */
+	index = fmt->index;
+	memset(fmt, 0, sizeof(*fmt));
+	fmt->index = index;
+	fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	if (index == 0) {
+		strcpy(fmt->description, "YUV 4:2:2 - UYVY");
+		fmt->pixelformat = V4L2_PIX_FMT_UYVY;
+	} else {
+		strcpy(fmt->description, "Y/CbCr 4:2:0");
+		fmt->pixelformat = V4L2_PIX_FMT_NV12;
+	}
+
+	return 0;
+}
+
+static int vpbe_display_s_fmt(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_display *disp_dev = fh->disp_dev;
+	struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+	struct osd_layer_config *cfg  = &layer->layer_info.config;
+	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+	struct osd_state *osd_device = disp_dev->osd_device;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+			"VIDIOC_S_FMT, layer id = %d\n",
+			layer->device_id);
+
+	/* If streaming is started, return error */
+	if (layer->started) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+		return -EBUSY;
+	}
+	if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) {
+		v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "invalid type\n");
+		return -EINVAL;
+	}
+	/* Check for valid pixel format */
+	ret = vpbe_try_format(disp_dev, pixfmt, 1);
+	if (ret)
+		return ret;
+
+	/* YUV420 is requested, check availability of the
+	other video window */
+
+	layer->pix_fmt = *pixfmt;
+
+	/* Get osd layer config */
+	osd_device->ops.get_layer_config(osd_device,
+			layer->layer_info.id, cfg);
+	/* Store the pixel format in the layer object */
+	cfg->xsize = pixfmt->width;
+	cfg->ysize = pixfmt->height;
+	cfg->line_length = pixfmt->bytesperline;
+	cfg->ypos = 0;
+	cfg->xpos = 0;
+	cfg->interlaced = vpbe_dev->current_timings.interlaced;
+
+	if (V4L2_PIX_FMT_UYVY == pixfmt->pixelformat)
+		cfg->pixfmt = PIXFMT_YCbCrI;
+
+	/* Change of the default pixel format for both video windows */
+	if (V4L2_PIX_FMT_NV12 == pixfmt->pixelformat) {
+		struct vpbe_layer *otherlayer;
+		cfg->pixfmt = PIXFMT_NV12;
+		otherlayer = _vpbe_display_get_other_win_layer(disp_dev,
+								layer);
+		otherlayer->layer_info.config.pixfmt = PIXFMT_NV12;
+	}
+
+	/* Set the layer config in the osd window */
+	ret = osd_device->ops.set_layer_config(osd_device,
+				layer->layer_info.id, cfg);
+	if (ret < 0) {
+		v4l2_err(&vpbe_dev->v4l2_dev,
+				"Error in S_FMT params:\n");
+		return -EINVAL;
+	}
+
+	/* Readback and fill the local copy of current pix format */
+	osd_device->ops.get_layer_config(osd_device,
+			layer->layer_info.id, cfg);
+
+	return 0;
+}
+
+static int vpbe_display_try_fmt(struct file *file, void *priv,
+				  struct v4l2_format *fmt)
+{
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_display *disp_dev = fh->disp_dev;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_TRY_FMT\n");
+
+	if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n");
+		return -EINVAL;
+	}
+
+	/* Check for valid field format */
+	return  vpbe_try_format(disp_dev, pixfmt, 0);
+
+}
+
+/**
+ * vpbe_display_s_std - Set the given standard in the encoder
+ *
+ * Sets the standard if supported by the current encoder. Return the status.
+ * 0 - success & -EINVAL on error
+ */
+static int vpbe_display_s_std(struct file *file, void *priv,
+				v4l2_std_id *std_id)
+{
+	struct vpbe_fh *fh = priv;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_STD\n");
+
+	/* If streaming is started, return error */
+	if (layer->started) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+		return -EBUSY;
+	}
+	if (NULL != vpbe_dev->ops.s_std) {
+		ret = vpbe_dev->ops.s_std(vpbe_dev, std_id);
+		if (ret) {
+			v4l2_err(&vpbe_dev->v4l2_dev,
+			"Failed to set standard for sub devices\n");
+			return -EINVAL;
+		}
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * vpbe_display_g_std - Get the standard in the current encoder
+ *
+ * Get the standard in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int vpbe_display_g_std(struct file *file, void *priv,
+				v4l2_std_id *std_id)
+{
+	struct vpbe_fh *fh = priv;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,	"VIDIOC_G_STD\n");
+
+	/* Get the standard from the current encoder */
+	if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) {
+		*std_id = vpbe_dev->current_timings.timings.std_id;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * vpbe_display_enum_output - enumerate outputs
+ *
+ * Enumerates the outputs available at the vpbe display
+ * returns the status, -EINVAL if end of output list
+ */
+static int vpbe_display_enum_output(struct file *file, void *priv,
+				    struct v4l2_output *output)
+{
+	struct vpbe_fh *fh = priv;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,	"VIDIOC_ENUM_OUTPUT\n");
+
+	/* Enumerate outputs */
+
+	if (NULL == vpbe_dev->ops.enum_outputs)
+		return -EINVAL;
+
+	ret = vpbe_dev->ops.enum_outputs(vpbe_dev, output);
+	if (ret) {
+		v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+			"Failed to enumerate outputs\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * vpbe_display_s_output - Set output to
+ * the output specified by the index
+ */
+static int vpbe_display_s_output(struct file *file, void *priv,
+				unsigned int i)
+{
+	struct vpbe_fh *fh = priv;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,	"VIDIOC_S_OUTPUT\n");
+	/* If streaming is started, return error */
+	if (layer->started) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+		return -EBUSY;
+	}
+	if (NULL == vpbe_dev->ops.set_output)
+		return -EINVAL;
+
+	ret = vpbe_dev->ops.set_output(vpbe_dev, i);
+	if (ret) {
+		v4l2_err(&vpbe_dev->v4l2_dev,
+			"Failed to set output for sub devices\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * vpbe_display_g_output - Get output from subdevice
+ * for a given by the index
+ */
+static int vpbe_display_g_output(struct file *file, void *priv,
+				unsigned int *i)
+{
+	struct vpbe_fh *fh = priv;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_OUTPUT\n");
+	/* Get the standard from the current encoder */
+	*i = vpbe_dev->current_out_index;
+
+	return 0;
+}
+
+/**
+ * vpbe_display_enum_dv_presets - Enumerate the dv presets
+ *
+ * enum the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int
+vpbe_display_enum_dv_presets(struct file *file, void *priv,
+			struct v4l2_dv_enum_preset *preset)
+{
+	struct vpbe_fh *fh = priv;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_PRESETS\n");
+
+	/* Enumerate outputs */
+	if (NULL == vpbe_dev->ops.enum_dv_presets)
+		return -EINVAL;
+
+	ret = vpbe_dev->ops.enum_dv_presets(vpbe_dev, preset);
+	if (ret) {
+		v4l2_err(&vpbe_dev->v4l2_dev,
+			"Failed to enumerate dv presets info\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * vpbe_display_s_dv_preset - Set the dv presets
+ *
+ * Set the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int
+vpbe_display_s_dv_preset(struct file *file, void *priv,
+				struct v4l2_dv_preset *preset)
+{
+	struct vpbe_fh *fh = priv;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_PRESETS\n");
+
+
+	/* If streaming is started, return error */
+	if (layer->started) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+		return -EBUSY;
+	}
+
+	/* Set the given standard in the encoder */
+	if (!vpbe_dev->ops.s_dv_preset)
+		return -EINVAL;
+
+	ret = vpbe_dev->ops.s_dv_preset(vpbe_dev, preset);
+	if (ret) {
+		v4l2_err(&vpbe_dev->v4l2_dev,
+			"Failed to set the dv presets info\n");
+		return -EINVAL;
+	}
+	/* set the current norm to zero to be consistent. If STD is used
+	 * v4l2 layer will set the norm properly on successful s_std call
+	 */
+	layer->video_dev.current_norm = 0;
+
+	return 0;
+}
+
+/**
+ * vpbe_display_g_dv_preset - Set the dv presets
+ *
+ * Get the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int
+vpbe_display_g_dv_preset(struct file *file, void *priv,
+				struct v4l2_dv_preset *dv_preset)
+{
+	struct vpbe_fh *fh = priv;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_PRESETS\n");
+
+	/* Get the given standard in the encoder */
+
+	if (vpbe_dev->current_timings.timings_type &
+				VPBE_ENC_DV_PRESET) {
+		dv_preset->preset =
+			vpbe_dev->current_timings.timings.dv_preset;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vpbe_display_streamoff(struct file *file, void *priv,
+				enum v4l2_buf_type buf_type)
+{
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+	struct osd_state *osd_device = fh->disp_dev->osd_device;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+			"VIDIOC_STREAMOFF,layer id = %d\n",
+			layer->device_id);
+
+	if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+		return -EINVAL;
+	}
+
+	/* If io is allowed for this file handle, return error */
+	if (!fh->io_allowed) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
+		return -EACCES;
+	}
+
+	/* If streaming is not started, return error */
+	if (!layer->started) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "streaming not started in layer"
+			" id = %d\n", layer->device_id);
+		return -EINVAL;
+	}
+
+	osd_device->ops.disable_layer(osd_device,
+			layer->layer_info.id);
+	layer->started = 0;
+	ret = videobuf_streamoff(&layer->buffer_queue);
+
+	return ret;
+}
+
+static int vpbe_display_streamon(struct file *file, void *priv,
+			 enum v4l2_buf_type buf_type)
+{
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_display *disp_dev = fh->disp_dev;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+	struct osd_state *osd_device = disp_dev->osd_device;
+	int ret;
+
+	osd_device->ops.disable_layer(osd_device,
+			layer->layer_info.id);
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_STREAMON, layerid=%d\n",
+						layer->device_id);
+
+	if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+		return -EINVAL;
+	}
+
+	/* If file handle is not allowed IO, return error */
+	if (!fh->io_allowed) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
+		return -EACCES;
+	}
+	/* If Streaming is already started, return error */
+	if (layer->started) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "layer is already streaming\n");
+		return -EBUSY;
+	}
+
+	/*
+	 * Call videobuf_streamon to start streaming
+	 * in videobuf
+	 */
+	ret = videobuf_streamon(&layer->buffer_queue);
+	if (ret) {
+		v4l2_err(&vpbe_dev->v4l2_dev,
+		"error in videobuf_streamon\n");
+		return ret;
+	}
+	/* If buffer queue is empty, return error */
+	if (list_empty(&layer->dma_queue)) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n");
+		goto streamoff;
+	}
+	/* Get the next frame from the buffer queue */
+	layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next,
+				struct videobuf_buffer, queue);
+	/* Remove buffer from the buffer queue */
+	list_del(&layer->cur_frm->queue);
+	/* Mark state of the current frame to active */
+	layer->cur_frm->state = VIDEOBUF_ACTIVE;
+	/* Initialize field_id and started member */
+	layer->field_id = 0;
+
+	/* Set parameters in OSD and VENC */
+	ret = vpbe_set_osd_display_params(disp_dev, layer);
+	if (ret < 0)
+		goto streamoff;
+
+	/*
+	 * if request format is yuv420 semiplanar, need to
+	 * enable both video windows
+	 */
+	layer->started = 1;
+
+	layer->layer_first_int = 1;
+
+	return ret;
+streamoff:
+	ret = videobuf_streamoff(&layer->buffer_queue);
+	return ret;
+}
+
+static int vpbe_display_dqbuf(struct file *file, void *priv,
+		      struct v4l2_buffer *buf)
+{
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+		"VIDIOC_DQBUF, layer id = %d\n",
+		layer->device_id);
+
+	if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+		return -EINVAL;
+	}
+	/* If this file handle is not allowed to do IO, return error */
+	if (!fh->io_allowed) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
+		return -EACCES;
+	}
+	if (file->f_flags & O_NONBLOCK)
+		/* Call videobuf_dqbuf for non blocking mode */
+		ret = videobuf_dqbuf(&layer->buffer_queue, buf, 1);
+	else
+		/* Call videobuf_dqbuf for blocking mode */
+		ret = videobuf_dqbuf(&layer->buffer_queue, buf, 0);
+
+	return ret;
+}
+
+static int vpbe_display_qbuf(struct file *file, void *priv,
+		     struct v4l2_buffer *p)
+{
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+		"VIDIOC_QBUF, layer id = %d\n",
+		layer->device_id);
+
+	if (V4L2_BUF_TYPE_VIDEO_OUTPUT != p->type) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+		return -EINVAL;
+	}
+
+	/* If this file handle is not allowed to do IO, return error */
+	if (!fh->io_allowed) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
+		return -EACCES;
+	}
+
+	return videobuf_qbuf(&layer->buffer_queue, p);
+}
+
+static int vpbe_display_querybuf(struct file *file, void *priv,
+			 struct v4l2_buffer *buf)
+{
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+		"VIDIOC_QUERYBUF, layer id = %d\n",
+		layer->device_id);
+
+	if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+		return -EINVAL;
+	}
+
+	/* Call videobuf_querybuf to get information */
+	ret = videobuf_querybuf(&layer->buffer_queue, buf);
+
+	return ret;
+}
+
+static int vpbe_display_reqbufs(struct file *file, void *priv,
+			struct v4l2_requestbuffers *req_buf)
+{
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_reqbufs\n");
+
+	if (V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+		return -EINVAL;
+	}
+
+	/* If io users of the layer is not zero, return error */
+	if (0 != layer->io_usrs) {
+		v4l2_err(&vpbe_dev->v4l2_dev, "not IO user\n");
+		return -EBUSY;
+	}
+	/* Initialize videobuf queue as per the buffer type */
+	videobuf_queue_dma_contig_init(&layer->buffer_queue,
+				&video_qops,
+				vpbe_dev->pdev,
+				&layer->irqlock,
+				V4L2_BUF_TYPE_VIDEO_OUTPUT,
+				layer->pix_fmt.field,
+				sizeof(struct videobuf_buffer),
+				fh, NULL);
+
+	/* Set io allowed member of file handle to TRUE */
+	fh->io_allowed = 1;
+	/* Increment io usrs member of layer object to 1 */
+	layer->io_usrs = 1;
+	/* Store type of memory requested in layer object */
+	layer->memory = req_buf->memory;
+	/* Initialize buffer queue */
+	INIT_LIST_HEAD(&layer->dma_queue);
+	/* Allocate buffers */
+	ret = videobuf_reqbufs(&layer->buffer_queue, req_buf);
+
+	return ret;
+}
+
+/*
+ * vpbe_display_mmap()
+ * It is used to map kernel space buffers into user spaces
+ */
+static int vpbe_display_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+	/* Get the layer object and file handle object */
+	struct vpbe_fh *fh = filep->private_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_mmap\n");
+
+	if (mutex_lock_interruptible(&layer->opslock))
+		return -ERESTARTSYS;
+	ret = videobuf_mmap_mapper(&layer->buffer_queue, vma);
+	mutex_unlock(&layer->opslock);
+	return ret;
+}
+
+/* vpbe_display_poll(): It is used for select/poll system call
+ */
+static unsigned int vpbe_display_poll(struct file *filep, poll_table *wait)
+{
+	struct vpbe_fh *fh = filep->private_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+	unsigned int err = 0;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_poll\n");
+	if (layer->started) {
+		mutex_lock(&layer->opslock);
+		err = videobuf_poll_stream(filep, &layer->buffer_queue, wait);
+		mutex_unlock(&layer->opslock);
+	}
+	return err;
+}
+
+/*
+ * vpbe_display_open()
+ * It creates object of file handle structure and stores it in private_data
+ * member of filepointer
+ */
+static int vpbe_display_open(struct file *file)
+{
+	struct vpbe_fh *fh = NULL;
+	struct vpbe_layer *layer = video_drvdata(file);
+	struct vpbe_display *disp_dev = layer->disp_dev;
+	struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+	struct osd_state *osd_device = disp_dev->osd_device;
+	int err;
+
+	/* Allocate memory for the file handle object */
+	fh = kmalloc(sizeof(struct vpbe_fh), GFP_KERNEL);
+	if (fh == NULL) {
+		v4l2_err(&vpbe_dev->v4l2_dev,
+			"unable to allocate memory for file handle object\n");
+		return -ENOMEM;
+	}
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+			"vpbe display open plane = %d\n",
+			layer->device_id);
+
+	/* store pointer to fh in private_data member of filep */
+	file->private_data = fh;
+	fh->layer = layer;
+	fh->disp_dev = disp_dev;
+
+	if (!layer->usrs) {
+		if (mutex_lock_interruptible(&layer->opslock))
+			return -ERESTARTSYS;
+		/* First claim the layer for this device */
+		err = osd_device->ops.request_layer(osd_device,
+						layer->layer_info.id);
+		mutex_unlock(&layer->opslock);
+		if (err < 0) {
+			/* Couldn't get layer */
+			v4l2_err(&vpbe_dev->v4l2_dev,
+				"Display Manager failed to allocate layer\n");
+			kfree(fh);
+			return -EINVAL;
+		}
+	}
+	/* Increment layer usrs counter */
+	layer->usrs++;
+	/* Set io_allowed member to false */
+	fh->io_allowed = 0;
+	/* Initialize priority of this instance to default priority */
+	fh->prio = V4L2_PRIORITY_UNSET;
+	v4l2_prio_open(&layer->prio, &fh->prio);
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+			"vpbe display device opened successfully\n");
+	return 0;
+}
+
+/*
+ * vpbe_display_release()
+ * This function deletes buffer queue, frees the buffers and the davinci
+ * display file * handle
+ */
+static int vpbe_display_release(struct file *file)
+{
+	/* Get the layer object and file handle object */
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_layer *layer = fh->layer;
+	struct osd_layer_config *cfg  = &layer->layer_info.config;
+	struct vpbe_display *disp_dev = fh->disp_dev;
+	struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+	struct osd_state *osd_device = disp_dev->osd_device;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_release\n");
+
+	mutex_lock(&layer->opslock);
+	/* if this instance is doing IO */
+	if (fh->io_allowed) {
+		/* Reset io_usrs member of layer object */
+		layer->io_usrs = 0;
+
+		osd_device->ops.disable_layer(osd_device,
+				layer->layer_info.id);
+		layer->started = 0;
+		/* Free buffers allocated */
+		videobuf_queue_cancel(&layer->buffer_queue);
+		videobuf_mmap_free(&layer->buffer_queue);
+	}
+
+	/* Decrement layer usrs counter */
+	layer->usrs--;
+	/* If this file handle has initialize encoder device, reset it */
+	if (!layer->usrs) {
+		if (cfg->pixfmt == PIXFMT_NV12) {
+			struct vpbe_layer *otherlayer;
+			otherlayer =
+			_vpbe_display_get_other_win_layer(disp_dev, layer);
+			osd_device->ops.disable_layer(osd_device,
+					otherlayer->layer_info.id);
+			osd_device->ops.release_layer(osd_device,
+					otherlayer->layer_info.id);
+		}
+		osd_device->ops.disable_layer(osd_device,
+				layer->layer_info.id);
+		osd_device->ops.release_layer(osd_device,
+				layer->layer_info.id);
+	}
+	/* Close the priority */
+	v4l2_prio_close(&layer->prio, fh->prio);
+	file->private_data = NULL;
+	mutex_unlock(&layer->opslock);
+
+	/* Free memory allocated to file handle object */
+	kfree(fh);
+
+	disp_dev->cbcr_ofst = 0;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vpbe_display_g_register(struct file *file, void *priv,
+			struct v4l2_dbg_register *reg)
+{
+	struct v4l2_dbg_match *match = &reg->match;
+	struct vpbe_fh *fh = file->private_data;
+	struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+	if (match->type >= 2) {
+		v4l2_subdev_call(vpbe_dev->venc,
+				 core,
+				 g_register,
+				 reg);
+	}
+
+	return 0;
+}
+
+static int vpbe_display_s_register(struct file *file, void *priv,
+			struct v4l2_dbg_register *reg)
+{
+	return 0;
+}
+#endif
+
+/* vpbe capture ioctl operations */
+static const struct v4l2_ioctl_ops vpbe_ioctl_ops = {
+	.vidioc_querycap	 = vpbe_display_querycap,
+	.vidioc_g_fmt_vid_out    = vpbe_display_g_fmt,
+	.vidioc_enum_fmt_vid_out = vpbe_display_enum_fmt,
+	.vidioc_s_fmt_vid_out    = vpbe_display_s_fmt,
+	.vidioc_try_fmt_vid_out  = vpbe_display_try_fmt,
+	.vidioc_reqbufs		 = vpbe_display_reqbufs,
+	.vidioc_querybuf	 = vpbe_display_querybuf,
+	.vidioc_qbuf		 = vpbe_display_qbuf,
+	.vidioc_dqbuf		 = vpbe_display_dqbuf,
+	.vidioc_streamon	 = vpbe_display_streamon,
+	.vidioc_streamoff	 = vpbe_display_streamoff,
+	.vidioc_cropcap		 = vpbe_display_cropcap,
+	.vidioc_g_crop		 = vpbe_display_g_crop,
+	.vidioc_s_crop		 = vpbe_display_s_crop,
+	.vidioc_g_priority	 = vpbe_display_g_priority,
+	.vidioc_s_priority	 = vpbe_display_s_priority,
+	.vidioc_s_std		 = vpbe_display_s_std,
+	.vidioc_g_std		 = vpbe_display_g_std,
+	.vidioc_enum_output	 = vpbe_display_enum_output,
+	.vidioc_s_output	 = vpbe_display_s_output,
+	.vidioc_g_output	 = vpbe_display_g_output,
+	.vidioc_s_dv_preset	 = vpbe_display_s_dv_preset,
+	.vidioc_g_dv_preset	 = vpbe_display_g_dv_preset,
+	.vidioc_enum_dv_presets	 = vpbe_display_enum_dv_presets,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register	 = vpbe_display_g_register,
+	.vidioc_s_register	 = vpbe_display_s_register,
+#endif
+};
+
+static struct v4l2_file_operations vpbe_fops = {
+	.owner = THIS_MODULE,
+	.open = vpbe_display_open,
+	.release = vpbe_display_release,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap = vpbe_display_mmap,
+	.poll = vpbe_display_poll
+};
+
+static int vpbe_device_get(struct device *dev, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct vpbe_display *vpbe_disp  = data;
+
+	if (strcmp("vpbe_controller", pdev->name) == 0)
+		vpbe_disp->vpbe_dev = platform_get_drvdata(pdev);
+
+	if (strcmp("vpbe-osd", pdev->name) == 0)
+		vpbe_disp->osd_device = platform_get_drvdata(pdev);
+
+	return 0;
+}
+
+static __devinit int init_vpbe_layer(int i, struct vpbe_display *disp_dev,
+				     struct platform_device *pdev)
+{
+	struct vpbe_layer *vpbe_display_layer = NULL;
+	struct video_device *vbd = NULL;
+
+	/* Allocate memory for four plane display objects */
+
+	disp_dev->dev[i] =
+		kzalloc(sizeof(struct vpbe_layer), GFP_KERNEL);
+
+	/* If memory allocation fails, return error */
+	if (!disp_dev->dev[i]) {
+		printk(KERN_ERR "ran out of memory\n");
+		return  -ENOMEM;
+	}
+	spin_lock_init(&disp_dev->dev[i]->irqlock);
+	mutex_init(&disp_dev->dev[i]->opslock);
+
+	/* Get the pointer to the layer object */
+	vpbe_display_layer = disp_dev->dev[i];
+	vbd = &vpbe_display_layer->video_dev;
+	/* Initialize field of video device */
+	vbd->release	= video_device_release_empty;
+	vbd->fops	= &vpbe_fops;
+	vbd->ioctl_ops	= &vpbe_ioctl_ops;
+	vbd->minor	= -1;
+	vbd->v4l2_dev   = &disp_dev->vpbe_dev->v4l2_dev;
+	vbd->lock	= &vpbe_display_layer->opslock;
+
+	if (disp_dev->vpbe_dev->current_timings.timings_type &
+			VPBE_ENC_STD) {
+		vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50);
+		vbd->current_norm =
+			disp_dev->vpbe_dev->
+			current_timings.timings.std_id;
+	} else
+		vbd->current_norm = 0;
+
+	snprintf(vbd->name, sizeof(vbd->name),
+			"DaVinci_VPBE Display_DRIVER_V%d.%d.%d",
+			(VPBE_DISPLAY_VERSION_CODE >> 16) & 0xff,
+			(VPBE_DISPLAY_VERSION_CODE >> 8) & 0xff,
+			(VPBE_DISPLAY_VERSION_CODE) & 0xff);
+
+	vpbe_display_layer->device_id = i;
+
+	vpbe_display_layer->layer_info.id =
+		((i == VPBE_DISPLAY_DEVICE_0) ? WIN_VID0 : WIN_VID1);
+
+	/* Initialize prio member of layer object */
+	v4l2_prio_init(&vpbe_display_layer->prio);
+
+	return 0;
+}
+
+static __devinit int register_device(struct vpbe_layer *vpbe_display_layer,
+					struct vpbe_display *disp_dev,
+					struct platform_device *pdev) {
+	int err;
+
+	v4l2_info(&disp_dev->vpbe_dev->v4l2_dev,
+		  "Trying to register VPBE display device.\n");
+	v4l2_info(&disp_dev->vpbe_dev->v4l2_dev,
+		  "layer=%x,layer->video_dev=%x\n",
+		  (int)vpbe_display_layer,
+		  (int)&vpbe_display_layer->video_dev);
+
+	err = video_register_device(&vpbe_display_layer->video_dev,
+				    VFL_TYPE_GRABBER,
+				    -1);
+	if (err)
+		return -ENODEV;
+
+	vpbe_display_layer->disp_dev = disp_dev;
+	/* set the driver data in platform device */
+	platform_set_drvdata(pdev, disp_dev);
+	video_set_drvdata(&vpbe_display_layer->video_dev,
+			  vpbe_display_layer);
+
+	return 0;
+}
+
+
+
+/*
+ * vpbe_display_probe()
+ * This function creates device entries by register itself to the V4L2 driver
+ * and initializes fields of each layer objects
+ */
+static __devinit int vpbe_display_probe(struct platform_device *pdev)
+{
+	struct vpbe_layer *vpbe_display_layer;
+	struct vpbe_display *disp_dev;
+	struct resource *res = NULL;
+	int k;
+	int i;
+	int err;
+	int irq;
+
+	printk(KERN_DEBUG "vpbe_display_probe\n");
+	/* Allocate memory for vpbe_display */
+	disp_dev = kzalloc(sizeof(struct vpbe_display), GFP_KERNEL);
+	if (!disp_dev) {
+		printk(KERN_ERR "ran out of memory\n");
+		return -ENOMEM;
+	}
+
+	spin_lock_init(&disp_dev->dma_queue_lock);
+	/*
+	 * Scan all the platform devices to find the vpbe
+	 * controller device and get the vpbe_dev object
+	 */
+	err = bus_for_each_dev(&platform_bus_type, NULL, disp_dev,
+			vpbe_device_get);
+	if (err < 0)
+		return err;
+	/* Initialize the vpbe display controller */
+	if (NULL != disp_dev->vpbe_dev->ops.initialize) {
+		err = disp_dev->vpbe_dev->ops.initialize(&pdev->dev,
+							 disp_dev->vpbe_dev);
+		if (err) {
+			v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
+					"Error initing vpbe\n");
+			err = -ENOMEM;
+			goto probe_out;
+		}
+	}
+
+	for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+		if (init_vpbe_layer(i, disp_dev, pdev)) {
+			err = -ENODEV;
+			goto probe_out;
+		}
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
+			 "Unable to get VENC interrupt resource\n");
+		err = -ENODEV;
+		goto probe_out;
+	}
+
+	irq = res->start;
+	if (request_irq(irq, venc_isr,  IRQF_DISABLED, VPBE_DISPLAY_DRIVER,
+		disp_dev)) {
+		v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
+				"Unable to request interrupt\n");
+		err = -ENODEV;
+		goto probe_out;
+	}
+
+	for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+		if (register_device(disp_dev->dev[i], disp_dev, pdev)) {
+			err = -ENODEV;
+			goto probe_out_irq;
+		}
+	}
+
+	printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n");
+	return 0;
+
+probe_out_irq:
+	free_irq(res->start, disp_dev);
+probe_out:
+	for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) {
+		/* Get the pointer to the layer object */
+		vpbe_display_layer = disp_dev->dev[k];
+		/* Unregister video device */
+		if (vpbe_display_layer) {
+			video_unregister_device(
+				&vpbe_display_layer->video_dev);
+				kfree(disp_dev->dev[k]);
+		}
+	}
+	kfree(disp_dev);
+	return err;
+}
+
+/*
+ * vpbe_display_remove()
+ * It un-register hardware layer from V4L2 driver
+ */
+static int vpbe_display_remove(struct platform_device *pdev)
+{
+	struct vpbe_layer *vpbe_display_layer;
+	struct vpbe_display *disp_dev = platform_get_drvdata(pdev);
+	struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+	struct resource *res;
+	int i;
+
+	v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_remove\n");
+
+	/* unregister irq */
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	free_irq(res->start, disp_dev);
+
+	/* deinitialize the vpbe display controller */
+	if (NULL != vpbe_dev->ops.deinitialize)
+		vpbe_dev->ops.deinitialize(&pdev->dev, vpbe_dev);
+	/* un-register device */
+	for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+		/* Get the pointer to the layer object */
+		vpbe_display_layer = disp_dev->dev[i];
+		/* Unregister video device */
+		video_unregister_device(&vpbe_display_layer->video_dev);
+
+	}
+	for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+		kfree(disp_dev->dev[i]);
+		disp_dev->dev[i] = NULL;
+	}
+
+	return 0;
+}
+
+static struct platform_driver vpbe_display_driver = {
+	.driver = {
+		.name = VPBE_DISPLAY_DRIVER,
+		.owner = THIS_MODULE,
+		.bus = &platform_bus_type,
+	},
+	.probe = vpbe_display_probe,
+	.remove = __devexit_p(vpbe_display_remove),
+};
+
+module_platform_driver(vpbe_display_driver);
+
+MODULE_DESCRIPTION("TI DM644x/DM355/DM365 VPBE Display controller");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments");
diff --git a/drivers/media/platform/davinci/vpbe_osd.c b/drivers/media/platform/davinci/vpbe_osd.c
new file mode 100644
index 0000000..bba299d
--- /dev/null
+++ b/drivers/media/platform/davinci/vpbe_osd.c
@@ -0,0 +1,1605 @@
+/*
+ * Copyright (C) 2007-2010 Texas Instruments Inc
+ * Copyright (C) 2007 MontaVista Software, Inc.
+ *
+ * Andy Lowe (alowe@mvista.com), MontaVista Software
+ * - Initial version
+ * Murali Karicheri (mkaricheri@gmail.com), Texas Instruments Ltd.
+ * - ported to sub device interface
+ *
+ * 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 version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include <mach/cputype.h>
+#include <mach/hardware.h>
+
+#include <media/davinci/vpss.h>
+#include <media/v4l2-device.h>
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe_osd.h>
+
+#include <linux/io.h>
+#include "vpbe_osd_regs.h"
+
+#define MODULE_NAME	VPBE_OSD_SUBDEV_NAME
+
+/* register access routines */
+static inline u32 osd_read(struct osd_state *sd, u32 offset)
+{
+	struct osd_state *osd = sd;
+
+	return readl(osd->osd_base + offset);
+}
+
+static inline u32 osd_write(struct osd_state *sd, u32 val, u32 offset)
+{
+	struct osd_state *osd = sd;
+
+	writel(val, osd->osd_base + offset);
+
+	return val;
+}
+
+static inline u32 osd_set(struct osd_state *sd, u32 mask, u32 offset)
+{
+	struct osd_state *osd = sd;
+
+	u32 addr = osd->osd_base + offset;
+	u32 val = readl(addr) | mask;
+
+	writel(val, addr);
+
+	return val;
+}
+
+static inline u32 osd_clear(struct osd_state *sd, u32 mask, u32 offset)
+{
+	struct osd_state *osd = sd;
+
+	u32 addr = osd->osd_base + offset;
+	u32 val = readl(addr) & ~mask;
+
+	writel(val, addr);
+
+	return val;
+}
+
+static inline u32 osd_modify(struct osd_state *sd, u32 mask, u32 val,
+				 u32 offset)
+{
+	struct osd_state *osd = sd;
+
+	u32 addr = osd->osd_base + offset;
+	u32 new_val = (readl(addr) & ~mask) | (val & mask);
+
+	writel(new_val, addr);
+
+	return new_val;
+}
+
+/* define some macros for layer and pixfmt classification */
+#define is_osd_win(layer) (((layer) == WIN_OSD0) || ((layer) == WIN_OSD1))
+#define is_vid_win(layer) (((layer) == WIN_VID0) || ((layer) == WIN_VID1))
+#define is_rgb_pixfmt(pixfmt) \
+	(((pixfmt) == PIXFMT_RGB565) || ((pixfmt) == PIXFMT_RGB888))
+#define is_yc_pixfmt(pixfmt) \
+	(((pixfmt) == PIXFMT_YCbCrI) || ((pixfmt) == PIXFMT_YCrCbI) || \
+	((pixfmt) == PIXFMT_NV12))
+#define MAX_WIN_SIZE OSD_VIDWIN0XP_V0X
+#define MAX_LINE_LENGTH (OSD_VIDWIN0OFST_V0LO << 5)
+
+/**
+ * _osd_dm6446_vid0_pingpong() - field inversion fix for DM6446
+ * @sd - ptr to struct osd_state
+ * @field_inversion - inversion flag
+ * @fb_base_phys - frame buffer address
+ * @lconfig - ptr to layer config
+ *
+ * This routine implements a workaround for the field signal inversion silicon
+ * erratum described in Advisory 1.3.8 for the DM6446.  The fb_base_phys and
+ * lconfig parameters apply to the vid0 window.  This routine should be called
+ * whenever the vid0 layer configuration or start address is modified, or when
+ * the OSD field inversion setting is modified.
+ * Returns: 1 if the ping-pong buffers need to be toggled in the vsync isr, or
+ *          0 otherwise
+ */
+static int _osd_dm6446_vid0_pingpong(struct osd_state *sd,
+				     int field_inversion,
+				     unsigned long fb_base_phys,
+				     const struct osd_layer_config *lconfig)
+{
+	struct osd_platform_data *pdata;
+
+	pdata = (struct osd_platform_data *)sd->dev->platform_data;
+	if (pdata->field_inv_wa_enable) {
+
+		if (!field_inversion || !lconfig->interlaced) {
+			osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR);
+			osd_write(sd, fb_base_phys & ~0x1F, OSD_PPVWIN0ADR);
+			osd_modify(sd, OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, 0,
+				   OSD_MISCCTL);
+			return 0;
+		} else {
+			unsigned miscctl = OSD_MISCCTL_PPRV;
+
+			osd_write(sd,
+				(fb_base_phys & ~0x1F) - lconfig->line_length,
+				OSD_VIDWIN0ADR);
+			osd_write(sd,
+				(fb_base_phys & ~0x1F) + lconfig->line_length,
+				OSD_PPVWIN0ADR);
+			osd_modify(sd,
+				OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, miscctl,
+				OSD_MISCCTL);
+
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static void _osd_set_field_inversion(struct osd_state *sd, int enable)
+{
+	unsigned fsinv = 0;
+
+	if (enable)
+		fsinv = OSD_MODE_FSINV;
+
+	osd_modify(sd, OSD_MODE_FSINV, fsinv, OSD_MODE);
+}
+
+static void _osd_set_blink_attribute(struct osd_state *sd, int enable,
+				     enum osd_blink_interval blink)
+{
+	u32 osdatrmd = 0;
+
+	if (enable) {
+		osdatrmd |= OSD_OSDATRMD_BLNK;
+		osdatrmd |= blink << OSD_OSDATRMD_BLNKINT_SHIFT;
+	}
+	/* caller must ensure that OSD1 is configured in attribute mode */
+	osd_modify(sd, OSD_OSDATRMD_BLNKINT | OSD_OSDATRMD_BLNK, osdatrmd,
+		  OSD_OSDATRMD);
+}
+
+static void _osd_set_rom_clut(struct osd_state *sd,
+			      enum osd_rom_clut rom_clut)
+{
+	if (rom_clut == ROM_CLUT0)
+		osd_clear(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL);
+	else
+		osd_set(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL);
+}
+
+static void _osd_set_palette_map(struct osd_state *sd,
+				 enum osd_win_layer osdwin,
+				 unsigned char pixel_value,
+				 unsigned char clut_index,
+				 enum osd_pix_format pixfmt)
+{
+	static const int map_2bpp[] = { 0, 5, 10, 15 };
+	static const int map_1bpp[] = { 0, 15 };
+	int bmp_offset;
+	int bmp_shift;
+	int bmp_mask;
+	int bmp_reg;
+
+	switch (pixfmt) {
+	case PIXFMT_1BPP:
+		bmp_reg = map_1bpp[pixel_value & 0x1];
+		break;
+	case PIXFMT_2BPP:
+		bmp_reg = map_2bpp[pixel_value & 0x3];
+		break;
+	case PIXFMT_4BPP:
+		bmp_reg = pixel_value & 0xf;
+		break;
+	default:
+		return;
+	}
+
+	switch (osdwin) {
+	case OSDWIN_OSD0:
+		bmp_offset = OSD_W0BMP01 + (bmp_reg >> 1) * sizeof(u32);
+		break;
+	case OSDWIN_OSD1:
+		bmp_offset = OSD_W1BMP01 + (bmp_reg >> 1) * sizeof(u32);
+		break;
+	default:
+		return;
+	}
+
+	if (bmp_reg & 1) {
+		bmp_shift = 8;
+		bmp_mask = 0xff << 8;
+	} else {
+		bmp_shift = 0;
+		bmp_mask = 0xff;
+	}
+
+	osd_modify(sd, bmp_mask, clut_index << bmp_shift, bmp_offset);
+}
+
+static void _osd_set_rec601_attenuation(struct osd_state *sd,
+					enum osd_win_layer osdwin, int enable)
+{
+	switch (osdwin) {
+	case OSDWIN_OSD0:
+		osd_modify(sd, OSD_OSDWIN0MD_ATN0E,
+			  enable ? OSD_OSDWIN0MD_ATN0E : 0,
+			  OSD_OSDWIN0MD);
+		if (sd->vpbe_type == VPBE_VERSION_1)
+			osd_modify(sd, OSD_OSDWIN0MD_ATN0E,
+				  enable ? OSD_OSDWIN0MD_ATN0E : 0,
+				  OSD_OSDWIN0MD);
+		else if ((sd->vpbe_type == VPBE_VERSION_3) ||
+			   (sd->vpbe_type == VPBE_VERSION_2))
+			osd_modify(sd, OSD_EXTMODE_ATNOSD0EN,
+				  enable ? OSD_EXTMODE_ATNOSD0EN : 0,
+				  OSD_EXTMODE);
+		break;
+	case OSDWIN_OSD1:
+		osd_modify(sd, OSD_OSDWIN1MD_ATN1E,
+			  enable ? OSD_OSDWIN1MD_ATN1E : 0,
+			  OSD_OSDWIN1MD);
+		if (sd->vpbe_type == VPBE_VERSION_1)
+			osd_modify(sd, OSD_OSDWIN1MD_ATN1E,
+				  enable ? OSD_OSDWIN1MD_ATN1E : 0,
+				  OSD_OSDWIN1MD);
+		else if ((sd->vpbe_type == VPBE_VERSION_3) ||
+			   (sd->vpbe_type == VPBE_VERSION_2))
+			osd_modify(sd, OSD_EXTMODE_ATNOSD1EN,
+				  enable ? OSD_EXTMODE_ATNOSD1EN : 0,
+				  OSD_EXTMODE);
+		break;
+	}
+}
+
+static void _osd_set_blending_factor(struct osd_state *sd,
+				     enum osd_win_layer osdwin,
+				     enum osd_blending_factor blend)
+{
+	switch (osdwin) {
+	case OSDWIN_OSD0:
+		osd_modify(sd, OSD_OSDWIN0MD_BLND0,
+			  blend << OSD_OSDWIN0MD_BLND0_SHIFT, OSD_OSDWIN0MD);
+		break;
+	case OSDWIN_OSD1:
+		osd_modify(sd, OSD_OSDWIN1MD_BLND1,
+			  blend << OSD_OSDWIN1MD_BLND1_SHIFT, OSD_OSDWIN1MD);
+		break;
+	}
+}
+
+static void _osd_enable_rgb888_pixblend(struct osd_state *sd,
+					enum osd_win_layer osdwin)
+{
+
+	osd_modify(sd, OSD_MISCCTL_BLDSEL, 0, OSD_MISCCTL);
+	switch (osdwin) {
+	case OSDWIN_OSD0:
+		osd_modify(sd, OSD_EXTMODE_OSD0BLDCHR,
+			  OSD_EXTMODE_OSD0BLDCHR, OSD_EXTMODE);
+		break;
+	case OSDWIN_OSD1:
+		osd_modify(sd, OSD_EXTMODE_OSD1BLDCHR,
+			  OSD_EXTMODE_OSD1BLDCHR, OSD_EXTMODE);
+		break;
+	}
+}
+
+static void _osd_enable_color_key(struct osd_state *sd,
+				  enum osd_win_layer osdwin,
+				  unsigned colorkey,
+				  enum osd_pix_format pixfmt)
+{
+	switch (pixfmt) {
+	case PIXFMT_1BPP:
+	case PIXFMT_2BPP:
+	case PIXFMT_4BPP:
+	case PIXFMT_8BPP:
+		if (sd->vpbe_type == VPBE_VERSION_3) {
+			switch (osdwin) {
+			case OSDWIN_OSD0:
+				osd_modify(sd, OSD_TRANSPBMPIDX_BMP0,
+					  colorkey <<
+					  OSD_TRANSPBMPIDX_BMP0_SHIFT,
+					  OSD_TRANSPBMPIDX);
+				break;
+			case OSDWIN_OSD1:
+				osd_modify(sd, OSD_TRANSPBMPIDX_BMP1,
+					  colorkey <<
+					  OSD_TRANSPBMPIDX_BMP1_SHIFT,
+					  OSD_TRANSPBMPIDX);
+				break;
+			}
+		}
+		break;
+	case PIXFMT_RGB565:
+		if (sd->vpbe_type == VPBE_VERSION_1)
+			osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS,
+				  OSD_TRANSPVAL);
+		else if (sd->vpbe_type == VPBE_VERSION_3)
+			osd_write(sd, colorkey & OSD_TRANSPVALL_RGBL,
+				  OSD_TRANSPVALL);
+		break;
+	case PIXFMT_YCbCrI:
+	case PIXFMT_YCrCbI:
+		if (sd->vpbe_type == VPBE_VERSION_3)
+			osd_modify(sd, OSD_TRANSPVALU_Y, colorkey,
+				   OSD_TRANSPVALU);
+		break;
+	case PIXFMT_RGB888:
+		if (sd->vpbe_type == VPBE_VERSION_3) {
+			osd_write(sd, colorkey & OSD_TRANSPVALL_RGBL,
+				  OSD_TRANSPVALL);
+			osd_modify(sd, OSD_TRANSPVALU_RGBU, colorkey >> 16,
+				  OSD_TRANSPVALU);
+		}
+		break;
+	default:
+		break;
+	}
+
+	switch (osdwin) {
+	case OSDWIN_OSD0:
+		osd_set(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD);
+		break;
+	case OSDWIN_OSD1:
+		osd_set(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD);
+		break;
+	}
+}
+
+static void _osd_disable_color_key(struct osd_state *sd,
+				   enum osd_win_layer osdwin)
+{
+	switch (osdwin) {
+	case OSDWIN_OSD0:
+		osd_clear(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD);
+		break;
+	case OSDWIN_OSD1:
+		osd_clear(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD);
+		break;
+	}
+}
+
+static void _osd_set_osd_clut(struct osd_state *sd,
+			      enum osd_win_layer osdwin,
+			      enum osd_clut clut)
+{
+	u32 winmd = 0;
+
+	switch (osdwin) {
+	case OSDWIN_OSD0:
+		if (clut == RAM_CLUT)
+			winmd |= OSD_OSDWIN0MD_CLUTS0;
+		osd_modify(sd, OSD_OSDWIN0MD_CLUTS0, winmd, OSD_OSDWIN0MD);
+		break;
+	case OSDWIN_OSD1:
+		if (clut == RAM_CLUT)
+			winmd |= OSD_OSDWIN1MD_CLUTS1;
+		osd_modify(sd, OSD_OSDWIN1MD_CLUTS1, winmd, OSD_OSDWIN1MD);
+		break;
+	}
+}
+
+static void _osd_set_zoom(struct osd_state *sd, enum osd_layer layer,
+			  enum osd_zoom_factor h_zoom,
+			  enum osd_zoom_factor v_zoom)
+{
+	u32 winmd = 0;
+
+	switch (layer) {
+	case WIN_OSD0:
+		winmd |= (h_zoom << OSD_OSDWIN0MD_OHZ0_SHIFT);
+		winmd |= (v_zoom << OSD_OSDWIN0MD_OVZ0_SHIFT);
+		osd_modify(sd, OSD_OSDWIN0MD_OHZ0 | OSD_OSDWIN0MD_OVZ0, winmd,
+			  OSD_OSDWIN0MD);
+		break;
+	case WIN_VID0:
+		winmd |= (h_zoom << OSD_VIDWINMD_VHZ0_SHIFT);
+		winmd |= (v_zoom << OSD_VIDWINMD_VVZ0_SHIFT);
+		osd_modify(sd, OSD_VIDWINMD_VHZ0 | OSD_VIDWINMD_VVZ0, winmd,
+			  OSD_VIDWINMD);
+		break;
+	case WIN_OSD1:
+		winmd |= (h_zoom << OSD_OSDWIN1MD_OHZ1_SHIFT);
+		winmd |= (v_zoom << OSD_OSDWIN1MD_OVZ1_SHIFT);
+		osd_modify(sd, OSD_OSDWIN1MD_OHZ1 | OSD_OSDWIN1MD_OVZ1, winmd,
+			  OSD_OSDWIN1MD);
+		break;
+	case WIN_VID1:
+		winmd |= (h_zoom << OSD_VIDWINMD_VHZ1_SHIFT);
+		winmd |= (v_zoom << OSD_VIDWINMD_VVZ1_SHIFT);
+		osd_modify(sd, OSD_VIDWINMD_VHZ1 | OSD_VIDWINMD_VVZ1, winmd,
+			  OSD_VIDWINMD);
+		break;
+	}
+}
+
+static void _osd_disable_layer(struct osd_state *sd, enum osd_layer layer)
+{
+	switch (layer) {
+	case WIN_OSD0:
+		osd_clear(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD);
+		break;
+	case WIN_VID0:
+		osd_clear(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD);
+		break;
+	case WIN_OSD1:
+		/* disable attribute mode as well as disabling the window */
+		osd_clear(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1,
+			  OSD_OSDWIN1MD);
+		break;
+	case WIN_VID1:
+		osd_clear(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD);
+		break;
+	}
+}
+
+static void osd_disable_layer(struct osd_state *sd, enum osd_layer layer)
+{
+	struct osd_state *osd = sd;
+	struct osd_window_state *win = &osd->win[layer];
+	unsigned long flags;
+
+	spin_lock_irqsave(&osd->lock, flags);
+
+	if (!win->is_enabled) {
+		spin_unlock_irqrestore(&osd->lock, flags);
+		return;
+	}
+	win->is_enabled = 0;
+
+	_osd_disable_layer(sd, layer);
+
+	spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void _osd_enable_attribute_mode(struct osd_state *sd)
+{
+	/* enable attribute mode for OSD1 */
+	osd_set(sd, OSD_OSDWIN1MD_OASW, OSD_OSDWIN1MD);
+}
+
+static void _osd_enable_layer(struct osd_state *sd, enum osd_layer layer)
+{
+	switch (layer) {
+	case WIN_OSD0:
+		osd_set(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD);
+		break;
+	case WIN_VID0:
+		osd_set(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD);
+		break;
+	case WIN_OSD1:
+		/* enable OSD1 and disable attribute mode */
+		osd_modify(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1,
+			  OSD_OSDWIN1MD_OACT1, OSD_OSDWIN1MD);
+		break;
+	case WIN_VID1:
+		osd_set(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD);
+		break;
+	}
+}
+
+static int osd_enable_layer(struct osd_state *sd, enum osd_layer layer,
+			    int otherwin)
+{
+	struct osd_state *osd = sd;
+	struct osd_window_state *win = &osd->win[layer];
+	struct osd_layer_config *cfg = &win->lconfig;
+	unsigned long flags;
+
+	spin_lock_irqsave(&osd->lock, flags);
+
+	/*
+	 * use otherwin flag to know this is the other vid window
+	 * in YUV420 mode, if is, skip this check
+	 */
+	if (!otherwin && (!win->is_allocated ||
+			!win->fb_base_phys ||
+			!cfg->line_length ||
+			!cfg->xsize ||
+			!cfg->ysize)) {
+		spin_unlock_irqrestore(&osd->lock, flags);
+		return -1;
+	}
+
+	if (win->is_enabled) {
+		spin_unlock_irqrestore(&osd->lock, flags);
+		return 0;
+	}
+	win->is_enabled = 1;
+
+	if (cfg->pixfmt != PIXFMT_OSD_ATTR)
+		_osd_enable_layer(sd, layer);
+	else {
+		_osd_enable_attribute_mode(sd);
+		_osd_set_blink_attribute(sd, osd->is_blinking, osd->blink);
+	}
+
+	spin_unlock_irqrestore(&osd->lock, flags);
+
+	return 0;
+}
+
+#define OSD_SRC_ADDR_HIGH4	0x7800000
+#define OSD_SRC_ADDR_HIGH7	0x7F0000
+#define OSD_SRCADD_OFSET_SFT	23
+#define OSD_SRCADD_ADD_SFT	16
+#define OSD_WINADL_MASK		0xFFFF
+#define OSD_WINOFST_MASK	0x1000
+#define VPBE_REG_BASE		0x80000000
+
+static void _osd_start_layer(struct osd_state *sd, enum osd_layer layer,
+			     unsigned long fb_base_phys,
+			     unsigned long cbcr_ofst)
+{
+
+	if (sd->vpbe_type == VPBE_VERSION_1) {
+		switch (layer) {
+		case WIN_OSD0:
+			osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR);
+			break;
+		case WIN_VID0:
+			osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR);
+			break;
+		case WIN_OSD1:
+			osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR);
+			break;
+		case WIN_VID1:
+			osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR);
+			break;
+	      }
+	} else if (sd->vpbe_type == VPBE_VERSION_3) {
+		unsigned long fb_offset_32 =
+		    (fb_base_phys - VPBE_REG_BASE) >> 5;
+
+		switch (layer) {
+		case WIN_OSD0:
+			osd_modify(sd, OSD_OSDWINADH_O0AH,
+				  fb_offset_32 >> (OSD_SRCADD_ADD_SFT -
+						   OSD_OSDWINADH_O0AH_SHIFT),
+				  OSD_OSDWINADH);
+			osd_write(sd, fb_offset_32 & OSD_OSDWIN0ADL_O0AL,
+				  OSD_OSDWIN0ADL);
+			break;
+		case WIN_VID0:
+			osd_modify(sd, OSD_VIDWINADH_V0AH,
+				  fb_offset_32 >> (OSD_SRCADD_ADD_SFT -
+						   OSD_VIDWINADH_V0AH_SHIFT),
+				  OSD_VIDWINADH);
+			osd_write(sd, fb_offset_32 & OSD_VIDWIN0ADL_V0AL,
+				  OSD_VIDWIN0ADL);
+			break;
+		case WIN_OSD1:
+			osd_modify(sd, OSD_OSDWINADH_O1AH,
+				  fb_offset_32 >> (OSD_SRCADD_ADD_SFT -
+						   OSD_OSDWINADH_O1AH_SHIFT),
+				  OSD_OSDWINADH);
+			osd_write(sd, fb_offset_32 & OSD_OSDWIN1ADL_O1AL,
+				  OSD_OSDWIN1ADL);
+			break;
+		case WIN_VID1:
+			osd_modify(sd, OSD_VIDWINADH_V1AH,
+				  fb_offset_32 >> (OSD_SRCADD_ADD_SFT -
+						   OSD_VIDWINADH_V1AH_SHIFT),
+				  OSD_VIDWINADH);
+			osd_write(sd, fb_offset_32 & OSD_VIDWIN1ADL_V1AL,
+				  OSD_VIDWIN1ADL);
+			break;
+		}
+	} else if (sd->vpbe_type == VPBE_VERSION_2) {
+		struct osd_window_state *win = &sd->win[layer];
+		unsigned long fb_offset_32, cbcr_offset_32;
+
+		fb_offset_32 = fb_base_phys - VPBE_REG_BASE;
+		if (cbcr_ofst)
+			cbcr_offset_32 = cbcr_ofst;
+		else
+			cbcr_offset_32 = win->lconfig.line_length *
+					 win->lconfig.ysize;
+		cbcr_offset_32 += fb_offset_32;
+		fb_offset_32 = fb_offset_32 >> 5;
+		cbcr_offset_32 = cbcr_offset_32 >> 5;
+		/*
+		 * DM365: start address is 27-bit long address b26 - b23 are
+		 * in offset register b12 - b9, and * bit 26 has to be '1'
+		 */
+		if (win->lconfig.pixfmt == PIXFMT_NV12) {
+			switch (layer) {
+			case WIN_VID0:
+			case WIN_VID1:
+				/* Y is in VID0 */
+				osd_modify(sd, OSD_VIDWIN0OFST_V0AH,
+					 ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >>
+					 (OSD_SRCADD_OFSET_SFT -
+					 OSD_WINOFST_AH_SHIFT)) |
+					 OSD_WINOFST_MASK, OSD_VIDWIN0OFST);
+				osd_modify(sd, OSD_VIDWINADH_V0AH,
+					  (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >>
+					  (OSD_SRCADD_ADD_SFT -
+					  OSD_VIDWINADH_V0AH_SHIFT),
+					   OSD_VIDWINADH);
+				osd_write(sd, fb_offset_32 & OSD_WINADL_MASK,
+					  OSD_VIDWIN0ADL);
+				/* CbCr is in VID1 */
+				osd_modify(sd, OSD_VIDWIN1OFST_V1AH,
+					 ((cbcr_offset_32 &
+					 OSD_SRC_ADDR_HIGH4) >>
+					 (OSD_SRCADD_OFSET_SFT -
+					 OSD_WINOFST_AH_SHIFT)) |
+					 OSD_WINOFST_MASK, OSD_VIDWIN1OFST);
+				osd_modify(sd, OSD_VIDWINADH_V1AH,
+					  (cbcr_offset_32 &
+					  OSD_SRC_ADDR_HIGH7) >>
+					  (OSD_SRCADD_ADD_SFT -
+					  OSD_VIDWINADH_V1AH_SHIFT),
+					  OSD_VIDWINADH);
+				osd_write(sd, cbcr_offset_32 & OSD_WINADL_MASK,
+					  OSD_VIDWIN1ADL);
+				break;
+			default:
+				break;
+			}
+		}
+
+		switch (layer) {
+		case WIN_OSD0:
+			osd_modify(sd, OSD_OSDWIN0OFST_O0AH,
+				 ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >>
+				 (OSD_SRCADD_OFSET_SFT -
+				 OSD_WINOFST_AH_SHIFT)) | OSD_WINOFST_MASK,
+				  OSD_OSDWIN0OFST);
+			osd_modify(sd, OSD_OSDWINADH_O0AH,
+				 (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >>
+				 (OSD_SRCADD_ADD_SFT -
+				 OSD_OSDWINADH_O0AH_SHIFT), OSD_OSDWINADH);
+			osd_write(sd, fb_offset_32 & OSD_WINADL_MASK,
+					OSD_OSDWIN0ADL);
+			break;
+		case WIN_VID0:
+			if (win->lconfig.pixfmt != PIXFMT_NV12) {
+				osd_modify(sd, OSD_VIDWIN0OFST_V0AH,
+					 ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >>
+					 (OSD_SRCADD_OFSET_SFT -
+					 OSD_WINOFST_AH_SHIFT)) |
+					 OSD_WINOFST_MASK, OSD_VIDWIN0OFST);
+				osd_modify(sd, OSD_VIDWINADH_V0AH,
+					  (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >>
+					  (OSD_SRCADD_ADD_SFT -
+					  OSD_VIDWINADH_V0AH_SHIFT),
+					  OSD_VIDWINADH);
+				osd_write(sd, fb_offset_32 & OSD_WINADL_MASK,
+					  OSD_VIDWIN0ADL);
+			}
+			break;
+		case WIN_OSD1:
+			osd_modify(sd, OSD_OSDWIN1OFST_O1AH,
+				 ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >>
+				 (OSD_SRCADD_OFSET_SFT -
+				 OSD_WINOFST_AH_SHIFT)) | OSD_WINOFST_MASK,
+				  OSD_OSDWIN1OFST);
+			osd_modify(sd, OSD_OSDWINADH_O1AH,
+				  (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >>
+				  (OSD_SRCADD_ADD_SFT -
+				  OSD_OSDWINADH_O1AH_SHIFT),
+				  OSD_OSDWINADH);
+			osd_write(sd, fb_offset_32 & OSD_WINADL_MASK,
+					OSD_OSDWIN1ADL);
+			break;
+		case WIN_VID1:
+			if (win->lconfig.pixfmt != PIXFMT_NV12) {
+				osd_modify(sd, OSD_VIDWIN1OFST_V1AH,
+					 ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >>
+					 (OSD_SRCADD_OFSET_SFT -
+					 OSD_WINOFST_AH_SHIFT)) |
+					 OSD_WINOFST_MASK, OSD_VIDWIN1OFST);
+				osd_modify(sd, OSD_VIDWINADH_V1AH,
+					  (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >>
+					  (OSD_SRCADD_ADD_SFT -
+					  OSD_VIDWINADH_V1AH_SHIFT),
+					  OSD_VIDWINADH);
+				osd_write(sd, fb_offset_32 & OSD_WINADL_MASK,
+					  OSD_VIDWIN1ADL);
+			}
+			break;
+		}
+	}
+}
+
+static void osd_start_layer(struct osd_state *sd, enum osd_layer layer,
+			    unsigned long fb_base_phys,
+			    unsigned long cbcr_ofst)
+{
+	struct osd_state *osd = sd;
+	struct osd_window_state *win = &osd->win[layer];
+	struct osd_layer_config *cfg = &win->lconfig;
+	unsigned long flags;
+
+	spin_lock_irqsave(&osd->lock, flags);
+
+	win->fb_base_phys = fb_base_phys & ~0x1F;
+	_osd_start_layer(sd, layer, fb_base_phys, cbcr_ofst);
+
+	if (layer == WIN_VID0) {
+		osd->pingpong =
+		    _osd_dm6446_vid0_pingpong(sd, osd->field_inversion,
+						       win->fb_base_phys,
+						       cfg);
+	}
+
+	spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void osd_get_layer_config(struct osd_state *sd, enum osd_layer layer,
+				 struct osd_layer_config *lconfig)
+{
+	struct osd_state *osd = sd;
+	struct osd_window_state *win = &osd->win[layer];
+	unsigned long flags;
+
+	spin_lock_irqsave(&osd->lock, flags);
+
+	*lconfig = win->lconfig;
+
+	spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+/**
+ * try_layer_config() - Try a specific configuration for the layer
+ * @sd  - ptr to struct osd_state
+ * @layer - layer to configure
+ * @lconfig - layer configuration to try
+ *
+ * If the requested lconfig is completely rejected and the value of lconfig on
+ * exit is the current lconfig, then try_layer_config() returns 1.  Otherwise,
+ * try_layer_config() returns 0.  A return value of 0 does not necessarily mean
+ * that the value of lconfig on exit is identical to the value of lconfig on
+ * entry, but merely that it represents a change from the current lconfig.
+ */
+static int try_layer_config(struct osd_state *sd, enum osd_layer layer,
+			    struct osd_layer_config *lconfig)
+{
+	struct osd_state *osd = sd;
+	struct osd_window_state *win = &osd->win[layer];
+	int bad_config = 0;
+
+	/* verify that the pixel format is compatible with the layer */
+	switch (lconfig->pixfmt) {
+	case PIXFMT_1BPP:
+	case PIXFMT_2BPP:
+	case PIXFMT_4BPP:
+	case PIXFMT_8BPP:
+	case PIXFMT_RGB565:
+		if (osd->vpbe_type == VPBE_VERSION_1)
+			bad_config = !is_vid_win(layer);
+		break;
+	case PIXFMT_YCbCrI:
+	case PIXFMT_YCrCbI:
+		bad_config = !is_vid_win(layer);
+		break;
+	case PIXFMT_RGB888:
+		if (osd->vpbe_type == VPBE_VERSION_1)
+			bad_config = !is_vid_win(layer);
+		else if ((osd->vpbe_type == VPBE_VERSION_3) ||
+			 (osd->vpbe_type == VPBE_VERSION_2))
+			bad_config = !is_osd_win(layer);
+		break;
+	case PIXFMT_NV12:
+		if (osd->vpbe_type != VPBE_VERSION_2)
+			bad_config = 1;
+		else
+			bad_config = is_osd_win(layer);
+		break;
+	case PIXFMT_OSD_ATTR:
+		bad_config = (layer != WIN_OSD1);
+		break;
+	default:
+		bad_config = 1;
+		break;
+	}
+	if (bad_config) {
+		/*
+		 * The requested pixel format is incompatible with the layer,
+		 * so keep the current layer configuration.
+		 */
+		*lconfig = win->lconfig;
+		return bad_config;
+	}
+
+	/* DM6446: */
+	/* only one OSD window at a time can use RGB pixel formats */
+	  if ((osd->vpbe_type == VPBE_VERSION_1) &&
+		  is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) {
+		enum osd_pix_format pixfmt;
+		if (layer == WIN_OSD0)
+			pixfmt = osd->win[WIN_OSD1].lconfig.pixfmt;
+		else
+			pixfmt = osd->win[WIN_OSD0].lconfig.pixfmt;
+
+		if (is_rgb_pixfmt(pixfmt)) {
+			/*
+			 * The other OSD window is already configured for an
+			 * RGB, so keep the current layer configuration.
+			 */
+			*lconfig = win->lconfig;
+			return 1;
+		}
+	}
+
+	/* DM6446: only one video window at a time can use RGB888 */
+	if ((osd->vpbe_type == VPBE_VERSION_1) && is_vid_win(layer) &&
+		lconfig->pixfmt == PIXFMT_RGB888) {
+		enum osd_pix_format pixfmt;
+
+		if (layer == WIN_VID0)
+			pixfmt = osd->win[WIN_VID1].lconfig.pixfmt;
+		else
+			pixfmt = osd->win[WIN_VID0].lconfig.pixfmt;
+
+		if (pixfmt == PIXFMT_RGB888) {
+			/*
+			 * The other video window is already configured for
+			 * RGB888, so keep the current layer configuration.
+			 */
+			*lconfig = win->lconfig;
+			return 1;
+		}
+	}
+
+	/* window dimensions must be non-zero */
+	if (!lconfig->line_length || !lconfig->xsize || !lconfig->ysize) {
+		*lconfig = win->lconfig;
+		return 1;
+	}
+
+	/* round line_length up to a multiple of 32 */
+	lconfig->line_length = ((lconfig->line_length + 31) / 32) * 32;
+	lconfig->line_length =
+	    min(lconfig->line_length, (unsigned)MAX_LINE_LENGTH);
+	lconfig->xsize = min(lconfig->xsize, (unsigned)MAX_WIN_SIZE);
+	lconfig->ysize = min(lconfig->ysize, (unsigned)MAX_WIN_SIZE);
+	lconfig->xpos = min(lconfig->xpos, (unsigned)MAX_WIN_SIZE);
+	lconfig->ypos = min(lconfig->ypos, (unsigned)MAX_WIN_SIZE);
+	lconfig->interlaced = (lconfig->interlaced != 0);
+	if (lconfig->interlaced) {
+		/* ysize and ypos must be even for interlaced displays */
+		lconfig->ysize &= ~1;
+		lconfig->ypos &= ~1;
+	}
+
+	return 0;
+}
+
+static void _osd_disable_vid_rgb888(struct osd_state *sd)
+{
+	/*
+	 * The DM6446 supports RGB888 pixel format in a single video window.
+	 * This routine disables RGB888 pixel format for both video windows.
+	 * The caller must ensure that neither video window is currently
+	 * configured for RGB888 pixel format.
+	 */
+	if (sd->vpbe_type == VPBE_VERSION_1)
+		osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL);
+}
+
+static void _osd_enable_vid_rgb888(struct osd_state *sd,
+				   enum osd_layer layer)
+{
+	/*
+	 * The DM6446 supports RGB888 pixel format in a single video window.
+	 * This routine enables RGB888 pixel format for the specified video
+	 * window.  The caller must ensure that the other video window is not
+	 * currently configured for RGB888 pixel format, as this routine will
+	 * disable RGB888 pixel format for the other window.
+	 */
+	if (sd->vpbe_type == VPBE_VERSION_1) {
+		if (layer == WIN_VID0)
+			osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
+				  OSD_MISCCTL_RGBEN, OSD_MISCCTL);
+		else if (layer == WIN_VID1)
+			osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
+				  OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
+				  OSD_MISCCTL);
+	}
+}
+
+static void _osd_set_cbcr_order(struct osd_state *sd,
+				enum osd_pix_format pixfmt)
+{
+	/*
+	 * The caller must ensure that all windows using YC pixfmt use the same
+	 * Cb/Cr order.
+	 */
+	if (pixfmt == PIXFMT_YCbCrI)
+		osd_clear(sd, OSD_MODE_CS, OSD_MODE);
+	else if (pixfmt == PIXFMT_YCrCbI)
+		osd_set(sd, OSD_MODE_CS, OSD_MODE);
+}
+
+static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
+				  const struct osd_layer_config *lconfig)
+{
+	u32 winmd = 0, winmd_mask = 0, bmw = 0;
+
+	_osd_set_cbcr_order(sd, lconfig->pixfmt);
+
+	switch (layer) {
+	case WIN_OSD0:
+		if (sd->vpbe_type == VPBE_VERSION_1) {
+			winmd_mask |= OSD_OSDWIN0MD_RGB0E;
+			if (lconfig->pixfmt == PIXFMT_RGB565)
+				winmd |= OSD_OSDWIN0MD_RGB0E;
+		} else if ((sd->vpbe_type == VPBE_VERSION_3) ||
+		  (sd->vpbe_type == VPBE_VERSION_2)) {
+			winmd_mask |= OSD_OSDWIN0MD_BMP0MD;
+			switch (lconfig->pixfmt) {
+			case PIXFMT_RGB565:
+					winmd |= (1 <<
+					OSD_OSDWIN0MD_BMP0MD_SHIFT);
+					break;
+			case PIXFMT_RGB888:
+				winmd |= (2 << OSD_OSDWIN0MD_BMP0MD_SHIFT);
+				_osd_enable_rgb888_pixblend(sd, OSDWIN_OSD0);
+				break;
+			case PIXFMT_YCbCrI:
+			case PIXFMT_YCrCbI:
+				winmd |= (3 << OSD_OSDWIN0MD_BMP0MD_SHIFT);
+				break;
+			default:
+				break;
+			}
+		}
+
+		winmd_mask |= OSD_OSDWIN0MD_BMW0 | OSD_OSDWIN0MD_OFF0;
+
+		switch (lconfig->pixfmt) {
+		case PIXFMT_1BPP:
+			bmw = 0;
+			break;
+		case PIXFMT_2BPP:
+			bmw = 1;
+			break;
+		case PIXFMT_4BPP:
+			bmw = 2;
+			break;
+		case PIXFMT_8BPP:
+			bmw = 3;
+			break;
+		default:
+			break;
+		}
+		winmd |= (bmw << OSD_OSDWIN0MD_BMW0_SHIFT);
+
+		if (lconfig->interlaced)
+			winmd |= OSD_OSDWIN0MD_OFF0;
+
+		osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN0MD);
+		osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN0OFST);
+		osd_write(sd, lconfig->xpos, OSD_OSDWIN0XP);
+		osd_write(sd, lconfig->xsize, OSD_OSDWIN0XL);
+		if (lconfig->interlaced) {
+			osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN0YP);
+			osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN0YL);
+		} else {
+			osd_write(sd, lconfig->ypos, OSD_OSDWIN0YP);
+			osd_write(sd, lconfig->ysize, OSD_OSDWIN0YL);
+		}
+		break;
+	case WIN_VID0:
+		winmd_mask |= OSD_VIDWINMD_VFF0;
+		if (lconfig->interlaced)
+			winmd |= OSD_VIDWINMD_VFF0;
+
+		osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD);
+		osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN0OFST);
+		osd_write(sd, lconfig->xpos, OSD_VIDWIN0XP);
+		osd_write(sd, lconfig->xsize, OSD_VIDWIN0XL);
+		/*
+		 * For YUV420P format the register contents are
+		 * duplicated in both VID registers
+		 */
+		if ((sd->vpbe_type == VPBE_VERSION_2) &&
+				(lconfig->pixfmt == PIXFMT_NV12)) {
+			/* other window also */
+			if (lconfig->interlaced) {
+				winmd_mask |= OSD_VIDWINMD_VFF1;
+				winmd |= OSD_VIDWINMD_VFF1;
+				osd_modify(sd, winmd_mask, winmd,
+					  OSD_VIDWINMD);
+			}
+
+			osd_modify(sd, OSD_MISCCTL_S420D,
+				    OSD_MISCCTL_S420D, OSD_MISCCTL);
+			osd_write(sd, lconfig->line_length >> 5,
+				  OSD_VIDWIN1OFST);
+			osd_write(sd, lconfig->xpos, OSD_VIDWIN1XP);
+			osd_write(sd, lconfig->xsize, OSD_VIDWIN1XL);
+			/*
+			  * if NV21 pixfmt and line length not 32B
+			  * aligned (e.g. NTSC), Need to set window
+			  * X pixel size to be 32B aligned as well
+			  */
+			if (lconfig->xsize % 32) {
+				osd_write(sd,
+					  ((lconfig->xsize + 31) & ~31),
+					  OSD_VIDWIN1XL);
+				osd_write(sd,
+					  ((lconfig->xsize + 31) & ~31),
+					  OSD_VIDWIN0XL);
+			}
+		} else if ((sd->vpbe_type == VPBE_VERSION_2) &&
+				(lconfig->pixfmt != PIXFMT_NV12)) {
+			osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D,
+						OSD_MISCCTL);
+		}
+
+		if (lconfig->interlaced) {
+			osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN0YP);
+			osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN0YL);
+			if ((sd->vpbe_type == VPBE_VERSION_2) &&
+				lconfig->pixfmt == PIXFMT_NV12) {
+				osd_write(sd, lconfig->ypos >> 1,
+					  OSD_VIDWIN1YP);
+				osd_write(sd, lconfig->ysize >> 1,
+					  OSD_VIDWIN1YL);
+			}
+		} else {
+			osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP);
+			osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL);
+			if ((sd->vpbe_type == VPBE_VERSION_2) &&
+				lconfig->pixfmt == PIXFMT_NV12) {
+				osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP);
+				osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL);
+			}
+		}
+		break;
+	case WIN_OSD1:
+		/*
+		 * The caller must ensure that OSD1 is disabled prior to
+		 * switching from a normal mode to attribute mode or from
+		 * attribute mode to a normal mode.
+		 */
+		if (lconfig->pixfmt == PIXFMT_OSD_ATTR) {
+			if (sd->vpbe_type == VPBE_VERSION_1) {
+				winmd_mask |= OSD_OSDWIN1MD_ATN1E |
+				OSD_OSDWIN1MD_RGB1E | OSD_OSDWIN1MD_CLUTS1 |
+				OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1;
+			} else {
+				winmd_mask |= OSD_OSDWIN1MD_BMP1MD |
+				OSD_OSDWIN1MD_CLUTS1 | OSD_OSDWIN1MD_BLND1 |
+				OSD_OSDWIN1MD_TE1;
+			}
+		} else {
+			if (sd->vpbe_type == VPBE_VERSION_1) {
+				winmd_mask |= OSD_OSDWIN1MD_RGB1E;
+				if (lconfig->pixfmt == PIXFMT_RGB565)
+					winmd |= OSD_OSDWIN1MD_RGB1E;
+			} else if ((sd->vpbe_type == VPBE_VERSION_3)
+				   || (sd->vpbe_type == VPBE_VERSION_2)) {
+				winmd_mask |= OSD_OSDWIN1MD_BMP1MD;
+				switch (lconfig->pixfmt) {
+				case PIXFMT_RGB565:
+					winmd |=
+					    (1 << OSD_OSDWIN1MD_BMP1MD_SHIFT);
+					break;
+				case PIXFMT_RGB888:
+					winmd |=
+					    (2 << OSD_OSDWIN1MD_BMP1MD_SHIFT);
+					_osd_enable_rgb888_pixblend(sd,
+							OSDWIN_OSD1);
+					break;
+				case PIXFMT_YCbCrI:
+				case PIXFMT_YCrCbI:
+					winmd |=
+					    (3 << OSD_OSDWIN1MD_BMP1MD_SHIFT);
+					break;
+				default:
+					break;
+				}
+			}
+
+			winmd_mask |= OSD_OSDWIN1MD_BMW1;
+			switch (lconfig->pixfmt) {
+			case PIXFMT_1BPP:
+				bmw = 0;
+				break;
+			case PIXFMT_2BPP:
+				bmw = 1;
+				break;
+			case PIXFMT_4BPP:
+				bmw = 2;
+				break;
+			case PIXFMT_8BPP:
+				bmw = 3;
+				break;
+			default:
+				break;
+			}
+			winmd |= (bmw << OSD_OSDWIN1MD_BMW1_SHIFT);
+		}
+
+		winmd_mask |= OSD_OSDWIN1MD_OFF1;
+		if (lconfig->interlaced)
+			winmd |= OSD_OSDWIN1MD_OFF1;
+
+		osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN1MD);
+		osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN1OFST);
+		osd_write(sd, lconfig->xpos, OSD_OSDWIN1XP);
+		osd_write(sd, lconfig->xsize, OSD_OSDWIN1XL);
+		if (lconfig->interlaced) {
+			osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN1YP);
+			osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN1YL);
+		} else {
+			osd_write(sd, lconfig->ypos, OSD_OSDWIN1YP);
+			osd_write(sd, lconfig->ysize, OSD_OSDWIN1YL);
+		}
+		break;
+	case WIN_VID1:
+		winmd_mask |= OSD_VIDWINMD_VFF1;
+		if (lconfig->interlaced)
+			winmd |= OSD_VIDWINMD_VFF1;
+
+		osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD);
+		osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN1OFST);
+		osd_write(sd, lconfig->xpos, OSD_VIDWIN1XP);
+		osd_write(sd, lconfig->xsize, OSD_VIDWIN1XL);
+		/*
+		 * For YUV420P format the register contents are
+		 * duplicated in both VID registers
+		 */
+		if (sd->vpbe_type == VPBE_VERSION_2) {
+			if (lconfig->pixfmt == PIXFMT_NV12) {
+				/* other window also */
+				if (lconfig->interlaced) {
+					winmd_mask |= OSD_VIDWINMD_VFF0;
+					winmd |= OSD_VIDWINMD_VFF0;
+					osd_modify(sd, winmd_mask, winmd,
+						  OSD_VIDWINMD);
+				}
+				osd_modify(sd, OSD_MISCCTL_S420D,
+					   OSD_MISCCTL_S420D, OSD_MISCCTL);
+				osd_write(sd, lconfig->line_length >> 5,
+					  OSD_VIDWIN0OFST);
+				osd_write(sd, lconfig->xpos, OSD_VIDWIN0XP);
+				osd_write(sd, lconfig->xsize, OSD_VIDWIN0XL);
+			} else {
+				osd_modify(sd, OSD_MISCCTL_S420D,
+					   ~OSD_MISCCTL_S420D, OSD_MISCCTL);
+			}
+		}
+
+		if (lconfig->interlaced) {
+			osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN1YP);
+			osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN1YL);
+			if ((sd->vpbe_type == VPBE_VERSION_2) &&
+				lconfig->pixfmt == PIXFMT_NV12) {
+				osd_write(sd, lconfig->ypos >> 1,
+					  OSD_VIDWIN0YP);
+				osd_write(sd, lconfig->ysize >> 1,
+					  OSD_VIDWIN0YL);
+			}
+		} else {
+			osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP);
+			osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL);
+			if ((sd->vpbe_type == VPBE_VERSION_2) &&
+				lconfig->pixfmt == PIXFMT_NV12) {
+				osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP);
+				osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL);
+			}
+		}
+		break;
+	}
+}
+
+static int osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
+				struct osd_layer_config *lconfig)
+{
+	struct osd_state *osd = sd;
+	struct osd_window_state *win = &osd->win[layer];
+	struct osd_layer_config *cfg = &win->lconfig;
+	unsigned long flags;
+	int reject_config;
+
+	spin_lock_irqsave(&osd->lock, flags);
+
+	reject_config = try_layer_config(sd, layer, lconfig);
+	if (reject_config) {
+		spin_unlock_irqrestore(&osd->lock, flags);
+		return reject_config;
+	}
+
+	/* update the current Cb/Cr order */
+	if (is_yc_pixfmt(lconfig->pixfmt))
+		osd->yc_pixfmt = lconfig->pixfmt;
+
+	/*
+	 * If we are switching OSD1 from normal mode to attribute mode or from
+	 * attribute mode to normal mode, then we must disable the window.
+	 */
+	if (layer == WIN_OSD1) {
+		if (((lconfig->pixfmt == PIXFMT_OSD_ATTR) &&
+		  (cfg->pixfmt != PIXFMT_OSD_ATTR)) ||
+		  ((lconfig->pixfmt != PIXFMT_OSD_ATTR) &&
+		  (cfg->pixfmt == PIXFMT_OSD_ATTR))) {
+			win->is_enabled = 0;
+			_osd_disable_layer(sd, layer);
+		}
+	}
+
+	_osd_set_layer_config(sd, layer, lconfig);
+
+	if (layer == WIN_OSD1) {
+		struct osd_osdwin_state *osdwin_state =
+		    &osd->osdwin[OSDWIN_OSD1];
+
+		if ((lconfig->pixfmt != PIXFMT_OSD_ATTR) &&
+		  (cfg->pixfmt == PIXFMT_OSD_ATTR)) {
+			/*
+			 * We just switched OSD1 from attribute mode to normal
+			 * mode, so we must initialize the CLUT select, the
+			 * blend factor, transparency colorkey enable, and
+			 * attenuation enable (DM6446 only) bits in the
+			 * OSDWIN1MD register.
+			 */
+			_osd_set_osd_clut(sd, OSDWIN_OSD1,
+						   osdwin_state->clut);
+			_osd_set_blending_factor(sd, OSDWIN_OSD1,
+							  osdwin_state->blend);
+			if (osdwin_state->colorkey_blending) {
+				_osd_enable_color_key(sd, OSDWIN_OSD1,
+							       osdwin_state->
+							       colorkey,
+							       lconfig->pixfmt);
+			} else
+				_osd_disable_color_key(sd, OSDWIN_OSD1);
+			_osd_set_rec601_attenuation(sd, OSDWIN_OSD1,
+						    osdwin_state->
+						    rec601_attenuation);
+		} else if ((lconfig->pixfmt == PIXFMT_OSD_ATTR) &&
+		  (cfg->pixfmt != PIXFMT_OSD_ATTR)) {
+			/*
+			 * We just switched OSD1 from normal mode to attribute
+			 * mode, so we must initialize the blink enable and
+			 * blink interval bits in the OSDATRMD register.
+			 */
+			_osd_set_blink_attribute(sd, osd->is_blinking,
+							  osd->blink);
+		}
+	}
+
+	/*
+	 * If we just switched to a 1-, 2-, or 4-bits-per-pixel bitmap format
+	 * then configure a default palette map.
+	 */
+	if ((lconfig->pixfmt != cfg->pixfmt) &&
+	  ((lconfig->pixfmt == PIXFMT_1BPP) ||
+	  (lconfig->pixfmt == PIXFMT_2BPP) ||
+	  (lconfig->pixfmt == PIXFMT_4BPP))) {
+		enum osd_win_layer osdwin =
+		    ((layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1);
+		struct osd_osdwin_state *osdwin_state =
+		    &osd->osdwin[osdwin];
+		unsigned char clut_index;
+		unsigned char clut_entries = 0;
+
+		switch (lconfig->pixfmt) {
+		case PIXFMT_1BPP:
+			clut_entries = 2;
+			break;
+		case PIXFMT_2BPP:
+			clut_entries = 4;
+			break;
+		case PIXFMT_4BPP:
+			clut_entries = 16;
+			break;
+		default:
+			break;
+		}
+		/*
+		 * The default palette map maps the pixel value to the clut
+		 * index, i.e. pixel value 0 maps to clut entry 0, pixel value
+		 * 1 maps to clut entry 1, etc.
+		 */
+		for (clut_index = 0; clut_index < 16; clut_index++) {
+			osdwin_state->palette_map[clut_index] = clut_index;
+			if (clut_index < clut_entries) {
+				_osd_set_palette_map(sd, osdwin, clut_index,
+						     clut_index,
+						     lconfig->pixfmt);
+			}
+		}
+	}
+
+	*cfg = *lconfig;
+	/* DM6446: configure the RGB888 enable and window selection */
+	if (osd->win[WIN_VID0].lconfig.pixfmt == PIXFMT_RGB888)
+		_osd_enable_vid_rgb888(sd, WIN_VID0);
+	else if (osd->win[WIN_VID1].lconfig.pixfmt == PIXFMT_RGB888)
+		_osd_enable_vid_rgb888(sd, WIN_VID1);
+	else
+		_osd_disable_vid_rgb888(sd);
+
+	if (layer == WIN_VID0) {
+		osd->pingpong =
+		    _osd_dm6446_vid0_pingpong(sd, osd->field_inversion,
+						       win->fb_base_phys,
+						       cfg);
+	}
+
+	spin_unlock_irqrestore(&osd->lock, flags);
+
+	return 0;
+}
+
+static void osd_init_layer(struct osd_state *sd, enum osd_layer layer)
+{
+	struct osd_state *osd = sd;
+	struct osd_window_state *win = &osd->win[layer];
+	enum osd_win_layer osdwin;
+	struct osd_osdwin_state *osdwin_state;
+	struct osd_layer_config *cfg = &win->lconfig;
+	unsigned long flags;
+
+	spin_lock_irqsave(&osd->lock, flags);
+
+	win->is_enabled = 0;
+	_osd_disable_layer(sd, layer);
+
+	win->h_zoom = ZOOM_X1;
+	win->v_zoom = ZOOM_X1;
+	_osd_set_zoom(sd, layer, win->h_zoom, win->v_zoom);
+
+	win->fb_base_phys = 0;
+	_osd_start_layer(sd, layer, win->fb_base_phys, 0);
+
+	cfg->line_length = 0;
+	cfg->xsize = 0;
+	cfg->ysize = 0;
+	cfg->xpos = 0;
+	cfg->ypos = 0;
+	cfg->interlaced = 0;
+	switch (layer) {
+	case WIN_OSD0:
+	case WIN_OSD1:
+		osdwin = (layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1;
+		osdwin_state = &osd->osdwin[osdwin];
+		/*
+		 * Other code relies on the fact that OSD windows default to a
+		 * bitmap pixel format when they are deallocated, so don't
+		 * change this default pixel format.
+		 */
+		cfg->pixfmt = PIXFMT_8BPP;
+		_osd_set_layer_config(sd, layer, cfg);
+		osdwin_state->clut = RAM_CLUT;
+		_osd_set_osd_clut(sd, osdwin, osdwin_state->clut);
+		osdwin_state->colorkey_blending = 0;
+		_osd_disable_color_key(sd, osdwin);
+		osdwin_state->blend = OSD_8_VID_0;
+		_osd_set_blending_factor(sd, osdwin, osdwin_state->blend);
+		osdwin_state->rec601_attenuation = 0;
+		_osd_set_rec601_attenuation(sd, osdwin,
+						     osdwin_state->
+						     rec601_attenuation);
+		if (osdwin == OSDWIN_OSD1) {
+			osd->is_blinking = 0;
+			osd->blink = BLINK_X1;
+		}
+		break;
+	case WIN_VID0:
+	case WIN_VID1:
+		cfg->pixfmt = osd->yc_pixfmt;
+		_osd_set_layer_config(sd, layer, cfg);
+		break;
+	}
+
+	spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void osd_release_layer(struct osd_state *sd, enum osd_layer layer)
+{
+	struct osd_state *osd = sd;
+	struct osd_window_state *win = &osd->win[layer];
+	unsigned long flags;
+
+	spin_lock_irqsave(&osd->lock, flags);
+
+	if (!win->is_allocated) {
+		spin_unlock_irqrestore(&osd->lock, flags);
+		return;
+	}
+
+	spin_unlock_irqrestore(&osd->lock, flags);
+	osd_init_layer(sd, layer);
+	spin_lock_irqsave(&osd->lock, flags);
+
+	win->is_allocated = 0;
+
+	spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static int osd_request_layer(struct osd_state *sd, enum osd_layer layer)
+{
+	struct osd_state *osd = sd;
+	struct osd_window_state *win = &osd->win[layer];
+	unsigned long flags;
+
+	spin_lock_irqsave(&osd->lock, flags);
+
+	if (win->is_allocated) {
+		spin_unlock_irqrestore(&osd->lock, flags);
+		return -1;
+	}
+	win->is_allocated = 1;
+
+	spin_unlock_irqrestore(&osd->lock, flags);
+
+	return 0;
+}
+
+static void _osd_init(struct osd_state *sd)
+{
+	osd_write(sd, 0, OSD_MODE);
+	osd_write(sd, 0, OSD_VIDWINMD);
+	osd_write(sd, 0, OSD_OSDWIN0MD);
+	osd_write(sd, 0, OSD_OSDWIN1MD);
+	osd_write(sd, 0, OSD_RECTCUR);
+	osd_write(sd, 0, OSD_MISCCTL);
+	if (sd->vpbe_type == VPBE_VERSION_3) {
+		osd_write(sd, 0, OSD_VBNDRY);
+		osd_write(sd, 0, OSD_EXTMODE);
+		osd_write(sd, OSD_MISCCTL_DMANG, OSD_MISCCTL);
+	}
+}
+
+static void osd_set_left_margin(struct osd_state *sd, u32 val)
+{
+	osd_write(sd, val, OSD_BASEPX);
+}
+
+static void osd_set_top_margin(struct osd_state *sd, u32 val)
+{
+	osd_write(sd, val, OSD_BASEPY);
+}
+
+static int osd_initialize(struct osd_state *osd)
+{
+	if (osd == NULL)
+		return -ENODEV;
+	_osd_init(osd);
+
+	/* set default Cb/Cr order */
+	osd->yc_pixfmt = PIXFMT_YCbCrI;
+
+	if (osd->vpbe_type == VPBE_VERSION_3) {
+		/*
+		 * ROM CLUT1 on the DM355 is similar (identical?) to ROM CLUT0
+		 * on the DM6446, so make ROM_CLUT1 the default on the DM355.
+		 */
+		osd->rom_clut = ROM_CLUT1;
+	}
+
+	_osd_set_field_inversion(osd, osd->field_inversion);
+	_osd_set_rom_clut(osd, osd->rom_clut);
+
+	osd_init_layer(osd, WIN_OSD0);
+	osd_init_layer(osd, WIN_VID0);
+	osd_init_layer(osd, WIN_OSD1);
+	osd_init_layer(osd, WIN_VID1);
+
+	return 0;
+}
+
+static const struct vpbe_osd_ops osd_ops = {
+	.initialize = osd_initialize,
+	.request_layer = osd_request_layer,
+	.release_layer = osd_release_layer,
+	.enable_layer = osd_enable_layer,
+	.disable_layer = osd_disable_layer,
+	.set_layer_config = osd_set_layer_config,
+	.get_layer_config = osd_get_layer_config,
+	.start_layer = osd_start_layer,
+	.set_left_margin = osd_set_left_margin,
+	.set_top_margin = osd_set_top_margin,
+};
+
+static int osd_probe(struct platform_device *pdev)
+{
+	struct osd_platform_data *pdata;
+	struct osd_state *osd;
+	struct resource *res;
+	int ret = 0;
+
+	osd = kzalloc(sizeof(struct osd_state), GFP_KERNEL);
+	if (osd == NULL)
+		return -ENOMEM;
+
+	osd->dev = &pdev->dev;
+	pdata = (struct osd_platform_data *)pdev->dev.platform_data;
+	osd->vpbe_type = (enum vpbe_version)pdata->vpbe_type;
+	if (NULL == pdev->dev.platform_data) {
+		dev_err(osd->dev, "No platform data defined for OSD"
+			" sub device\n");
+		ret = -ENOENT;
+		goto free_mem;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(osd->dev, "Unable to get OSD register address map\n");
+		ret = -ENODEV;
+		goto free_mem;
+	}
+	osd->osd_base_phys = res->start;
+	osd->osd_size = resource_size(res);
+	if (!request_mem_region(osd->osd_base_phys, osd->osd_size,
+				MODULE_NAME)) {
+		dev_err(osd->dev, "Unable to reserve OSD MMIO region\n");
+		ret = -ENODEV;
+		goto free_mem;
+	}
+	osd->osd_base = (unsigned long)ioremap_nocache(res->start,
+							osd->osd_size);
+	if (!osd->osd_base) {
+		dev_err(osd->dev, "Unable to map the OSD region\n");
+		ret = -ENODEV;
+		goto release_mem_region;
+	}
+	spin_lock_init(&osd->lock);
+	osd->ops = osd_ops;
+	platform_set_drvdata(pdev, osd);
+	dev_notice(osd->dev, "OSD sub device probe success\n");
+	return ret;
+
+release_mem_region:
+	release_mem_region(osd->osd_base_phys, osd->osd_size);
+free_mem:
+	kfree(osd);
+	return ret;
+}
+
+static int osd_remove(struct platform_device *pdev)
+{
+	struct osd_state *osd = platform_get_drvdata(pdev);
+
+	iounmap((void *)osd->osd_base);
+	release_mem_region(osd->osd_base_phys, osd->osd_size);
+	kfree(osd);
+	return 0;
+}
+
+static struct platform_driver osd_driver = {
+	.probe		= osd_probe,
+	.remove		= osd_remove,
+	.driver		= {
+		.name	= MODULE_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(osd_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DaVinci OSD Manager Driver");
+MODULE_AUTHOR("Texas Instruments");
diff --git a/drivers/media/platform/davinci/vpbe_osd_regs.h b/drivers/media/platform/davinci/vpbe_osd_regs.h
new file mode 100644
index 0000000..584520f
--- /dev/null
+++ b/drivers/media/platform/davinci/vpbe_osd_regs.h
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2006-2010 Texas Instruments Inc
+ *
+ * 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 version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _VPBE_OSD_REGS_H
+#define _VPBE_OSD_REGS_H
+
+/* VPBE Global Registers */
+#define VPBE_PID				0x0
+#define VPBE_PCR				0x4
+
+/* VPSS CLock Registers */
+#define VPSSCLK_PID				0x00
+#define VPSSCLK_CLKCTRL				0x04
+
+/* VPSS Buffer Logic Registers */
+#define VPSSBL_PID				0x00
+#define VPSSBL_PCR				0x04
+#define VPSSBL_BCR				0x08
+#define VPSSBL_INTSTAT				0x0C
+#define VPSSBL_INTSEL				0x10
+#define VPSSBL_EVTSEL				0x14
+#define VPSSBL_MEMCTRL				0x18
+#define VPSSBL_CCDCMUX				0x1C
+
+/* DM365 ISP5 system configuration */
+#define ISP5_PID				0x0
+#define ISP5_PCCR				0x4
+#define ISP5_BCR				0x8
+#define ISP5_INTSTAT				0xC
+#define ISP5_INTSEL1				0x10
+#define ISP5_INTSEL2				0x14
+#define ISP5_INTSEL3				0x18
+#define ISP5_EVTSEL				0x1c
+#define ISP5_CCDCMUX				0x20
+
+/* VPBE On-Screen Display Subsystem Registers (OSD) */
+#define OSD_MODE				0x00
+#define OSD_VIDWINMD				0x04
+#define OSD_OSDWIN0MD				0x08
+#define OSD_OSDWIN1MD				0x0C
+#define OSD_OSDATRMD				0x0C
+#define OSD_RECTCUR				0x10
+#define OSD_VIDWIN0OFST				0x18
+#define OSD_VIDWIN1OFST				0x1C
+#define OSD_OSDWIN0OFST				0x20
+#define OSD_OSDWIN1OFST				0x24
+#define OSD_VIDWINADH				0x28
+#define OSD_VIDWIN0ADL				0x2C
+#define OSD_VIDWIN0ADR				0x2C
+#define OSD_VIDWIN1ADL				0x30
+#define OSD_VIDWIN1ADR				0x30
+#define OSD_OSDWINADH				0x34
+#define OSD_OSDWIN0ADL				0x38
+#define OSD_OSDWIN0ADR				0x38
+#define OSD_OSDWIN1ADL				0x3C
+#define OSD_OSDWIN1ADR				0x3C
+#define OSD_BASEPX				0x40
+#define OSD_BASEPY				0x44
+#define OSD_VIDWIN0XP				0x48
+#define OSD_VIDWIN0YP				0x4C
+#define OSD_VIDWIN0XL				0x50
+#define OSD_VIDWIN0YL				0x54
+#define OSD_VIDWIN1XP				0x58
+#define OSD_VIDWIN1YP				0x5C
+#define OSD_VIDWIN1XL				0x60
+#define OSD_VIDWIN1YL				0x64
+#define OSD_OSDWIN0XP				0x68
+#define OSD_OSDWIN0YP				0x6C
+#define OSD_OSDWIN0XL				0x70
+#define OSD_OSDWIN0YL				0x74
+#define OSD_OSDWIN1XP				0x78
+#define OSD_OSDWIN1YP				0x7C
+#define OSD_OSDWIN1XL				0x80
+#define OSD_OSDWIN1YL				0x84
+#define OSD_CURXP				0x88
+#define OSD_CURYP				0x8C
+#define OSD_CURXL				0x90
+#define OSD_CURYL				0x94
+#define OSD_W0BMP01				0xA0
+#define OSD_W0BMP23				0xA4
+#define OSD_W0BMP45				0xA8
+#define OSD_W0BMP67				0xAC
+#define OSD_W0BMP89				0xB0
+#define OSD_W0BMPAB				0xB4
+#define OSD_W0BMPCD				0xB8
+#define OSD_W0BMPEF				0xBC
+#define OSD_W1BMP01				0xC0
+#define OSD_W1BMP23				0xC4
+#define OSD_W1BMP45				0xC8
+#define OSD_W1BMP67				0xCC
+#define OSD_W1BMP89				0xD0
+#define OSD_W1BMPAB				0xD4
+#define OSD_W1BMPCD				0xD8
+#define OSD_W1BMPEF				0xDC
+#define OSD_VBNDRY				0xE0
+#define OSD_EXTMODE				0xE4
+#define OSD_MISCCTL				0xE8
+#define OSD_CLUTRAMYCB				0xEC
+#define OSD_CLUTRAMCR				0xF0
+#define OSD_TRANSPVAL				0xF4
+#define OSD_TRANSPVALL				0xF4
+#define OSD_TRANSPVALU				0xF8
+#define OSD_TRANSPBMPIDX			0xFC
+#define OSD_PPVWIN0ADR				0xFC
+
+/* bit definitions */
+#define VPBE_PCR_VENC_DIV			(1 << 1)
+#define VPBE_PCR_CLK_OFF			(1 << 0)
+
+#define VPSSBL_INTSTAT_HSSIINT			(1 << 14)
+#define VPSSBL_INTSTAT_CFALDINT			(1 << 13)
+#define VPSSBL_INTSTAT_IPIPE_INT5		(1 << 12)
+#define VPSSBL_INTSTAT_IPIPE_INT4		(1 << 11)
+#define VPSSBL_INTSTAT_IPIPE_INT3		(1 << 10)
+#define VPSSBL_INTSTAT_IPIPE_INT2		(1 << 9)
+#define VPSSBL_INTSTAT_IPIPE_INT1		(1 << 8)
+#define VPSSBL_INTSTAT_IPIPE_INT0		(1 << 7)
+#define VPSSBL_INTSTAT_IPIPEIFINT		(1 << 6)
+#define VPSSBL_INTSTAT_OSDINT			(1 << 5)
+#define VPSSBL_INTSTAT_VENCINT			(1 << 4)
+#define VPSSBL_INTSTAT_H3AINT			(1 << 3)
+#define VPSSBL_INTSTAT_CCDC_VDINT2		(1 << 2)
+#define VPSSBL_INTSTAT_CCDC_VDINT1		(1 << 1)
+#define VPSSBL_INTSTAT_CCDC_VDINT0		(1 << 0)
+
+/* DM365 ISP5 bit definitions */
+#define ISP5_INTSTAT_VENCINT			(1 << 21)
+#define ISP5_INTSTAT_OSDINT			(1 << 20)
+
+/* VMOD TVTYP options for HDMD=0 */
+#define SDTV_NTSC				0
+#define SDTV_PAL				1
+/* VMOD TVTYP options for HDMD=1 */
+#define HDTV_525P				0
+#define HDTV_625P				1
+#define HDTV_1080I				2
+#define HDTV_720P				3
+
+#define OSD_MODE_CS				(1 << 15)
+#define OSD_MODE_OVRSZ				(1 << 14)
+#define OSD_MODE_OHRSZ				(1 << 13)
+#define OSD_MODE_EF				(1 << 12)
+#define OSD_MODE_VVRSZ				(1 << 11)
+#define OSD_MODE_VHRSZ				(1 << 10)
+#define OSD_MODE_FSINV				(1 << 9)
+#define OSD_MODE_BCLUT				(1 << 8)
+#define OSD_MODE_CABG_SHIFT			0
+#define OSD_MODE_CABG				(0xff << 0)
+
+#define OSD_VIDWINMD_VFINV			(1 << 15)
+#define OSD_VIDWINMD_V1EFC			(1 << 14)
+#define OSD_VIDWINMD_VHZ1_SHIFT			12
+#define OSD_VIDWINMD_VHZ1			(3 << 12)
+#define OSD_VIDWINMD_VVZ1_SHIFT			10
+#define OSD_VIDWINMD_VVZ1			(3 << 10)
+#define OSD_VIDWINMD_VFF1			(1 << 9)
+#define OSD_VIDWINMD_ACT1			(1 << 8)
+#define OSD_VIDWINMD_V0EFC			(1 << 6)
+#define OSD_VIDWINMD_VHZ0_SHIFT			4
+#define OSD_VIDWINMD_VHZ0			(3 << 4)
+#define OSD_VIDWINMD_VVZ0_SHIFT			2
+#define OSD_VIDWINMD_VVZ0			(3 << 2)
+#define OSD_VIDWINMD_VFF0			(1 << 1)
+#define OSD_VIDWINMD_ACT0			(1 << 0)
+
+#define OSD_OSDWIN0MD_ATN0E			(1 << 14)
+#define OSD_OSDWIN0MD_RGB0E			(1 << 13)
+#define OSD_OSDWIN0MD_BMP0MD_SHIFT		13
+#define OSD_OSDWIN0MD_BMP0MD			(3 << 13)
+#define OSD_OSDWIN0MD_CLUTS0			(1 << 12)
+#define OSD_OSDWIN0MD_OHZ0_SHIFT		10
+#define OSD_OSDWIN0MD_OHZ0			(3 << 10)
+#define OSD_OSDWIN0MD_OVZ0_SHIFT		8
+#define OSD_OSDWIN0MD_OVZ0			(3 << 8)
+#define OSD_OSDWIN0MD_BMW0_SHIFT		6
+#define OSD_OSDWIN0MD_BMW0			(3 << 6)
+#define OSD_OSDWIN0MD_BLND0_SHIFT		3
+#define OSD_OSDWIN0MD_BLND0			(7 << 3)
+#define OSD_OSDWIN0MD_TE0			(1 << 2)
+#define OSD_OSDWIN0MD_OFF0			(1 << 1)
+#define OSD_OSDWIN0MD_OACT0			(1 << 0)
+
+#define OSD_OSDWIN1MD_OASW			(1 << 15)
+#define OSD_OSDWIN1MD_ATN1E			(1 << 14)
+#define OSD_OSDWIN1MD_RGB1E			(1 << 13)
+#define OSD_OSDWIN1MD_BMP1MD_SHIFT		13
+#define OSD_OSDWIN1MD_BMP1MD			(3 << 13)
+#define OSD_OSDWIN1MD_CLUTS1			(1 << 12)
+#define OSD_OSDWIN1MD_OHZ1_SHIFT		10
+#define OSD_OSDWIN1MD_OHZ1			(3 << 10)
+#define OSD_OSDWIN1MD_OVZ1_SHIFT		8
+#define OSD_OSDWIN1MD_OVZ1			(3 << 8)
+#define OSD_OSDWIN1MD_BMW1_SHIFT		6
+#define OSD_OSDWIN1MD_BMW1			(3 << 6)
+#define OSD_OSDWIN1MD_BLND1_SHIFT		3
+#define OSD_OSDWIN1MD_BLND1			(7 << 3)
+#define OSD_OSDWIN1MD_TE1			(1 << 2)
+#define OSD_OSDWIN1MD_OFF1			(1 << 1)
+#define OSD_OSDWIN1MD_OACT1			(1 << 0)
+
+#define OSD_OSDATRMD_OASW			(1 << 15)
+#define OSD_OSDATRMD_OHZA_SHIFT			10
+#define OSD_OSDATRMD_OHZA			(3 << 10)
+#define OSD_OSDATRMD_OVZA_SHIFT			8
+#define OSD_OSDATRMD_OVZA			(3 << 8)
+#define OSD_OSDATRMD_BLNKINT_SHIFT		6
+#define OSD_OSDATRMD_BLNKINT			(3 << 6)
+#define OSD_OSDATRMD_OFFA			(1 << 1)
+#define OSD_OSDATRMD_BLNK			(1 << 0)
+
+#define OSD_RECTCUR_RCAD_SHIFT			8
+#define OSD_RECTCUR_RCAD			(0xff << 8)
+#define OSD_RECTCUR_CLUTSR			(1 << 7)
+#define OSD_RECTCUR_RCHW_SHIFT			4
+#define OSD_RECTCUR_RCHW			(7 << 4)
+#define OSD_RECTCUR_RCVW_SHIFT			1
+#define OSD_RECTCUR_RCVW			(7 << 1)
+#define OSD_RECTCUR_RCACT			(1 << 0)
+
+#define OSD_VIDWIN0OFST_V0LO			(0x1ff << 0)
+
+#define OSD_VIDWIN1OFST_V1LO			(0x1ff << 0)
+
+#define OSD_OSDWIN0OFST_O0LO			(0x1ff << 0)
+
+#define OSD_OSDWIN1OFST_O1LO			(0x1ff << 0)
+
+#define OSD_WINOFST_AH_SHIFT			9
+
+#define OSD_VIDWIN0OFST_V0AH			(0xf << 9)
+#define OSD_VIDWIN1OFST_V1AH			(0xf << 9)
+#define OSD_OSDWIN0OFST_O0AH			(0xf << 9)
+#define OSD_OSDWIN1OFST_O1AH			(0xf << 9)
+
+#define OSD_VIDWINADH_V1AH_SHIFT		8
+#define OSD_VIDWINADH_V1AH			(0x7f << 8)
+#define OSD_VIDWINADH_V0AH_SHIFT		0
+#define OSD_VIDWINADH_V0AH			(0x7f << 0)
+
+#define OSD_VIDWIN0ADL_V0AL			(0xffff << 0)
+
+#define OSD_VIDWIN1ADL_V1AL			(0xffff << 0)
+
+#define OSD_OSDWINADH_O1AH_SHIFT		8
+#define OSD_OSDWINADH_O1AH			(0x7f << 8)
+#define OSD_OSDWINADH_O0AH_SHIFT		0
+#define OSD_OSDWINADH_O0AH			(0x7f << 0)
+
+#define OSD_OSDWIN0ADL_O0AL			(0xffff << 0)
+
+#define OSD_OSDWIN1ADL_O1AL			(0xffff << 0)
+
+#define OSD_BASEPX_BPX				(0x3ff << 0)
+
+#define OSD_BASEPY_BPY				(0x1ff << 0)
+
+#define OSD_VIDWIN0XP_V0X			(0x7ff << 0)
+
+#define OSD_VIDWIN0YP_V0Y			(0x7ff << 0)
+
+#define OSD_VIDWIN0XL_V0W			(0x7ff << 0)
+
+#define OSD_VIDWIN0YL_V0H			(0x7ff << 0)
+
+#define OSD_VIDWIN1XP_V1X			(0x7ff << 0)
+
+#define OSD_VIDWIN1YP_V1Y			(0x7ff << 0)
+
+#define OSD_VIDWIN1XL_V1W			(0x7ff << 0)
+
+#define OSD_VIDWIN1YL_V1H			(0x7ff << 0)
+
+#define OSD_OSDWIN0XP_W0X			(0x7ff << 0)
+
+#define OSD_OSDWIN0YP_W0Y			(0x7ff << 0)
+
+#define OSD_OSDWIN0XL_W0W			(0x7ff << 0)
+
+#define OSD_OSDWIN0YL_W0H			(0x7ff << 0)
+
+#define OSD_OSDWIN1XP_W1X			(0x7ff << 0)
+
+#define OSD_OSDWIN1YP_W1Y			(0x7ff << 0)
+
+#define OSD_OSDWIN1XL_W1W			(0x7ff << 0)
+
+#define OSD_OSDWIN1YL_W1H			(0x7ff << 0)
+
+#define OSD_CURXP_RCSX				(0x7ff << 0)
+
+#define OSD_CURYP_RCSY				(0x7ff << 0)
+
+#define OSD_CURXL_RCSW				(0x7ff << 0)
+
+#define OSD_CURYL_RCSH				(0x7ff << 0)
+
+#define OSD_EXTMODE_EXPMDSEL			(1 << 15)
+#define OSD_EXTMODE_SCRNHEXP_SHIFT		13
+#define OSD_EXTMODE_SCRNHEXP			(3 << 13)
+#define OSD_EXTMODE_SCRNVEXP			(1 << 12)
+#define OSD_EXTMODE_OSD1BLDCHR			(1 << 11)
+#define OSD_EXTMODE_OSD0BLDCHR			(1 << 10)
+#define OSD_EXTMODE_ATNOSD1EN			(1 << 9)
+#define OSD_EXTMODE_ATNOSD0EN			(1 << 8)
+#define OSD_EXTMODE_OSDHRSZ15			(1 << 7)
+#define OSD_EXTMODE_VIDHRSZ15			(1 << 6)
+#define OSD_EXTMODE_ZMFILV1HEN			(1 << 5)
+#define OSD_EXTMODE_ZMFILV1VEN			(1 << 4)
+#define OSD_EXTMODE_ZMFILV0HEN			(1 << 3)
+#define OSD_EXTMODE_ZMFILV0VEN			(1 << 2)
+#define OSD_EXTMODE_EXPFILHEN			(1 << 1)
+#define OSD_EXTMODE_EXPFILVEN			(1 << 0)
+
+#define OSD_MISCCTL_BLDSEL			(1 << 15)
+#define OSD_MISCCTL_S420D			(1 << 14)
+#define OSD_MISCCTL_BMAPT			(1 << 13)
+#define OSD_MISCCTL_DM365M			(1 << 12)
+#define OSD_MISCCTL_RGBEN			(1 << 7)
+#define OSD_MISCCTL_RGBWIN			(1 << 6)
+#define OSD_MISCCTL_DMANG			(1 << 6)
+#define OSD_MISCCTL_TMON			(1 << 5)
+#define OSD_MISCCTL_RSEL			(1 << 4)
+#define OSD_MISCCTL_CPBSY			(1 << 3)
+#define OSD_MISCCTL_PPSW			(1 << 2)
+#define OSD_MISCCTL_PPRV			(1 << 1)
+
+#define OSD_CLUTRAMYCB_Y_SHIFT			8
+#define OSD_CLUTRAMYCB_Y			(0xff << 8)
+#define OSD_CLUTRAMYCB_CB_SHIFT			0
+#define OSD_CLUTRAMYCB_CB			(0xff << 0)
+
+#define OSD_CLUTRAMCR_CR_SHIFT			8
+#define OSD_CLUTRAMCR_CR			(0xff << 8)
+#define OSD_CLUTRAMCR_CADDR_SHIFT		0
+#define OSD_CLUTRAMCR_CADDR			(0xff << 0)
+
+#define OSD_TRANSPVAL_RGBTRANS			(0xffff << 0)
+
+#define OSD_TRANSPVALL_RGBL			(0xffff << 0)
+
+#define OSD_TRANSPVALU_Y_SHIFT			8
+#define OSD_TRANSPVALU_Y			(0xff << 8)
+#define OSD_TRANSPVALU_RGBU_SHIFT		0
+#define OSD_TRANSPVALU_RGBU			(0xff << 0)
+
+#define OSD_TRANSPBMPIDX_BMP1_SHIFT		8
+#define OSD_TRANSPBMPIDX_BMP1			(0xff << 8)
+#define OSD_TRANSPBMPIDX_BMP0_SHIFT		0
+#define OSD_TRANSPBMPIDX_BMP0			0xff
+
+#endif				/* _DAVINCI_VPBE_H_ */
diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c
new file mode 100644
index 0000000..b21ecc8
--- /dev/null
+++ b/drivers/media/platform/davinci/vpbe_venc.c
@@ -0,0 +1,706 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Inc
+ *
+ * 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 version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+
+#include <mach/hardware.h>
+#include <mach/mux.h>
+#include <mach/i2c.h>
+
+#include <linux/io.h>
+
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe_venc.h>
+#include <media/davinci/vpss.h>
+#include <media/v4l2-device.h>
+
+#include "vpbe_venc_regs.h"
+
+#define MODULE_NAME	VPBE_VENC_SUBDEV_NAME
+
+static int debug = 2;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level 0-2");
+
+struct venc_state {
+	struct v4l2_subdev sd;
+	struct venc_callback *callback;
+	struct venc_platform_data *pdata;
+	struct device *pdev;
+	u32 output;
+	v4l2_std_id std;
+	spinlock_t lock;
+	void __iomem *venc_base;
+	void __iomem *vdaccfg_reg;
+};
+
+static inline struct venc_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct venc_state, sd);
+}
+
+static inline u32 venc_read(struct v4l2_subdev *sd, u32 offset)
+{
+	struct venc_state *venc = to_state(sd);
+
+	return readl(venc->venc_base + offset);
+}
+
+static inline u32 venc_write(struct v4l2_subdev *sd, u32 offset, u32 val)
+{
+	struct venc_state *venc = to_state(sd);
+
+	writel(val, (venc->venc_base + offset));
+
+	return val;
+}
+
+static inline u32 venc_modify(struct v4l2_subdev *sd, u32 offset,
+				 u32 val, u32 mask)
+{
+	u32 new_val = (venc_read(sd, offset) & ~mask) | (val & mask);
+
+	venc_write(sd, offset, new_val);
+
+	return new_val;
+}
+
+static inline u32 vdaccfg_write(struct v4l2_subdev *sd, u32 val)
+{
+	struct venc_state *venc = to_state(sd);
+
+	writel(val, venc->vdaccfg_reg);
+
+	val = readl(venc->vdaccfg_reg);
+
+	return val;
+}
+
+#define VDAC_COMPONENT	0x543
+#define VDAC_S_VIDEO	0x210
+/* This function sets the dac of the VPBE for various outputs
+ */
+static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index)
+{
+	switch (out_index) {
+	case 0:
+		v4l2_dbg(debug, 1, sd, "Setting output to Composite\n");
+		venc_write(sd, VENC_DACSEL, 0);
+		break;
+	case 1:
+		v4l2_dbg(debug, 1, sd, "Setting output to Component\n");
+		venc_write(sd, VENC_DACSEL, VDAC_COMPONENT);
+		break;
+	case 2:
+		v4l2_dbg(debug, 1, sd, "Setting output to S-video\n");
+		venc_write(sd, VENC_DACSEL, VDAC_S_VIDEO);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable)
+{
+	struct venc_state *venc = to_state(sd);
+	struct venc_platform_data *pdata = venc->pdata;
+	v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n");
+
+	if (benable) {
+		venc_write(sd, VENC_VMOD, 0);
+		venc_write(sd, VENC_CVBS, 0);
+		venc_write(sd, VENC_LCDOUT, 0);
+		venc_write(sd, VENC_HSPLS, 0);
+		venc_write(sd, VENC_HSTART, 0);
+		venc_write(sd, VENC_HVALID, 0);
+		venc_write(sd, VENC_HINT, 0);
+		venc_write(sd, VENC_VSPLS, 0);
+		venc_write(sd, VENC_VSTART, 0);
+		venc_write(sd, VENC_VVALID, 0);
+		venc_write(sd, VENC_VINT, 0);
+		venc_write(sd, VENC_YCCCTL, 0);
+		venc_write(sd, VENC_DACSEL, 0);
+
+	} else {
+		venc_write(sd, VENC_VMOD, 0);
+		/* disable VCLK output pin enable */
+		venc_write(sd, VENC_VIDCTL, 0x141);
+
+		/* Disable output sync pins */
+		venc_write(sd, VENC_SYNCCTL, 0);
+
+		/* Disable DCLOCK */
+		venc_write(sd, VENC_DCLKCTL, 0);
+		venc_write(sd, VENC_DRGBX1, 0x0000057C);
+
+		/* Disable LCD output control (accepting default polarity) */
+		venc_write(sd, VENC_LCDOUT, 0);
+		if (pdata->venc_type != VPBE_VERSION_3)
+			venc_write(sd, VENC_CMPNT, 0x100);
+		venc_write(sd, VENC_HSPLS, 0);
+		venc_write(sd, VENC_HINT, 0);
+		venc_write(sd, VENC_HSTART, 0);
+		venc_write(sd, VENC_HVALID, 0);
+
+		venc_write(sd, VENC_VSPLS, 0);
+		venc_write(sd, VENC_VINT, 0);
+		venc_write(sd, VENC_VSTART, 0);
+		venc_write(sd, VENC_VVALID, 0);
+
+		venc_write(sd, VENC_HSDLY, 0);
+		venc_write(sd, VENC_VSDLY, 0);
+
+		venc_write(sd, VENC_YCCCTL, 0);
+		venc_write(sd, VENC_VSTARTA, 0);
+
+		/* Set OSD clock and OSD Sync Adavance registers */
+		venc_write(sd, VENC_OSDCLK0, 1);
+		venc_write(sd, VENC_OSDCLK1, 2);
+	}
+}
+
+#define VDAC_CONFIG_SD_V3	0x0E21A6B6
+#define VDAC_CONFIG_SD_V2	0x081141CF
+/*
+ * setting NTSC mode
+ */
+static int venc_set_ntsc(struct v4l2_subdev *sd)
+{
+	u32 val;
+	struct venc_state *venc = to_state(sd);
+	struct venc_platform_data *pdata = venc->pdata;
+
+	v4l2_dbg(debug, 2, sd, "venc_set_ntsc\n");
+
+	/* Setup clock at VPSS & VENC for SD */
+	vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1);
+	if (pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_525_60) < 0)
+		return -EINVAL;
+
+	venc_enabledigitaloutput(sd, 0);
+
+	if (pdata->venc_type == VPBE_VERSION_3) {
+		venc_write(sd, VENC_CLKCTL, 0x01);
+		venc_write(sd, VENC_VIDCTL, 0);
+		val = vdaccfg_write(sd, VDAC_CONFIG_SD_V3);
+	} else if (pdata->venc_type == VPBE_VERSION_2) {
+		venc_write(sd, VENC_CLKCTL, 0x01);
+		venc_write(sd, VENC_VIDCTL, 0);
+		vdaccfg_write(sd, VDAC_CONFIG_SD_V2);
+	} else {
+		/* to set VENC CLK DIV to 1 - final clock is 54 MHz */
+		venc_modify(sd, VENC_VIDCTL, 0, 1 << 1);
+		/* Set REC656 Mode */
+		venc_write(sd, VENC_YCCCTL, 0x1);
+		venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ);
+		venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS);
+	}
+
+	venc_write(sd, VENC_VMOD, 0);
+	venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
+			VENC_VMOD_VIE);
+	venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_VMD), VENC_VMOD_VMD);
+	venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_TVTYP_SHIFT),
+			VENC_VMOD_TVTYP);
+	venc_write(sd, VENC_DACTST, 0x0);
+	venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+
+	return 0;
+}
+
+/*
+ * setting PAL mode
+ */
+static int venc_set_pal(struct v4l2_subdev *sd)
+{
+	struct venc_state *venc = to_state(sd);
+	struct venc_platform_data *pdata = venc->pdata;
+
+	v4l2_dbg(debug, 2, sd, "venc_set_pal\n");
+
+	/* Setup clock at VPSS & VENC for SD */
+	vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1);
+	if (venc->pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_625_50) < 0)
+		return -EINVAL;
+
+	venc_enabledigitaloutput(sd, 0);
+
+	if (pdata->venc_type == VPBE_VERSION_3) {
+		venc_write(sd, VENC_CLKCTL, 0x1);
+		venc_write(sd, VENC_VIDCTL, 0);
+		vdaccfg_write(sd, VDAC_CONFIG_SD_V3);
+	} else if (pdata->venc_type == VPBE_VERSION_2) {
+		venc_write(sd, VENC_CLKCTL, 0x1);
+		venc_write(sd, VENC_VIDCTL, 0);
+		vdaccfg_write(sd, VDAC_CONFIG_SD_V2);
+	} else {
+		/* to set VENC CLK DIV to 1 - final clock is 54 MHz */
+		venc_modify(sd, VENC_VIDCTL, 0, 1 << 1);
+		/* Set REC656 Mode */
+		venc_write(sd, VENC_YCCCTL, 0x1);
+	}
+
+	venc_modify(sd, VENC_SYNCCTL, 1 << VENC_SYNCCTL_OVD_SHIFT,
+			VENC_SYNCCTL_OVD);
+	venc_write(sd, VENC_VMOD, 0);
+	venc_modify(sd, VENC_VMOD,
+			(1 << VENC_VMOD_VIE_SHIFT),
+			VENC_VMOD_VIE);
+	venc_modify(sd, VENC_VMOD,
+			(0 << VENC_VMOD_VMD), VENC_VMOD_VMD);
+	venc_modify(sd, VENC_VMOD,
+			(1 << VENC_VMOD_TVTYP_SHIFT),
+			VENC_VMOD_TVTYP);
+	venc_write(sd, VENC_DACTST, 0x0);
+	venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+
+	return 0;
+}
+
+#define VDAC_CONFIG_HD_V2	0x081141EF
+/*
+ * venc_set_480p59_94
+ *
+ * This function configures the video encoder to EDTV(525p) component setting.
+ */
+static int venc_set_480p59_94(struct v4l2_subdev *sd)
+{
+	struct venc_state *venc = to_state(sd);
+	struct venc_platform_data *pdata = venc->pdata;
+
+	v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n");
+	if ((pdata->venc_type != VPBE_VERSION_1) &&
+	    (pdata->venc_type != VPBE_VERSION_2))
+		return -EINVAL;
+
+	/* Setup clock at VPSS & VENC for SD */
+	if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_480P59_94) < 0)
+		return -EINVAL;
+
+	venc_enabledigitaloutput(sd, 0);
+
+	if (pdata->venc_type == VPBE_VERSION_2)
+		vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
+	venc_write(sd, VENC_OSDCLK0, 0);
+	venc_write(sd, VENC_OSDCLK1, 1);
+
+	if (pdata->venc_type == VPBE_VERSION_1) {
+		venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
+			    VENC_VDPRO_DAFRQ);
+		venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
+			    VENC_VDPRO_DAUPS);
+	}
+
+	venc_write(sd, VENC_VMOD, 0);
+	venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
+		    VENC_VMOD_VIE);
+	venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD);
+	venc_modify(sd, VENC_VMOD, (HDTV_525P << VENC_VMOD_TVTYP_SHIFT),
+		    VENC_VMOD_TVTYP);
+	venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 <<
+		    VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD);
+
+	venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+
+	return 0;
+}
+
+/*
+ * venc_set_625p
+ *
+ * This function configures the video encoder to HDTV(625p) component setting
+ */
+static int venc_set_576p50(struct v4l2_subdev *sd)
+{
+	struct venc_state *venc = to_state(sd);
+	struct venc_platform_data *pdata = venc->pdata;
+
+	v4l2_dbg(debug, 2, sd, "venc_set_576p50\n");
+
+	if ((pdata->venc_type != VPBE_VERSION_1) &&
+	  (pdata->venc_type != VPBE_VERSION_2))
+		return -EINVAL;
+	/* Setup clock at VPSS & VENC for SD */
+	if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_576P50) < 0)
+		return -EINVAL;
+
+	venc_enabledigitaloutput(sd, 0);
+
+	if (pdata->venc_type == VPBE_VERSION_2)
+		vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
+
+	venc_write(sd, VENC_OSDCLK0, 0);
+	venc_write(sd, VENC_OSDCLK1, 1);
+
+	if (pdata->venc_type == VPBE_VERSION_1) {
+		venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
+			    VENC_VDPRO_DAFRQ);
+		venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
+			    VENC_VDPRO_DAUPS);
+	}
+
+	venc_write(sd, VENC_VMOD, 0);
+	venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
+		    VENC_VMOD_VIE);
+	venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD);
+	venc_modify(sd, VENC_VMOD, (HDTV_625P << VENC_VMOD_TVTYP_SHIFT),
+		    VENC_VMOD_TVTYP);
+
+	venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 <<
+		    VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD);
+	venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+
+	return 0;
+}
+
+/*
+ * venc_set_720p60_internal - Setup 720p60 in venc for dm365 only
+ */
+static int venc_set_720p60_internal(struct v4l2_subdev *sd)
+{
+	struct venc_state *venc = to_state(sd);
+	struct venc_platform_data *pdata = venc->pdata;
+
+	if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_720P60) < 0)
+		return -EINVAL;
+
+	venc_enabledigitaloutput(sd, 0);
+
+	venc_write(sd, VENC_OSDCLK0, 0);
+	venc_write(sd, VENC_OSDCLK1, 1);
+
+	venc_write(sd, VENC_VMOD, 0);
+	/* DM365 component HD mode */
+	venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
+	    VENC_VMOD_VIE);
+	venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD);
+	venc_modify(sd, VENC_VMOD, (HDTV_720P << VENC_VMOD_TVTYP_SHIFT),
+		    VENC_VMOD_TVTYP);
+	venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+	venc_write(sd, VENC_XHINTVL, 0);
+	return 0;
+}
+
+/*
+ * venc_set_1080i30_internal - Setup 1080i30 in venc for dm365 only
+ */
+static int venc_set_1080i30_internal(struct v4l2_subdev *sd)
+{
+	struct venc_state *venc = to_state(sd);
+	struct venc_platform_data *pdata = venc->pdata;
+
+	if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_1080P30) < 0)
+		return -EINVAL;
+
+	venc_enabledigitaloutput(sd, 0);
+
+	venc_write(sd, VENC_OSDCLK0, 0);
+	venc_write(sd, VENC_OSDCLK1, 1);
+
+
+	venc_write(sd, VENC_VMOD, 0);
+	/* DM365 component HD mode */
+	venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
+		    VENC_VMOD_VIE);
+	venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD);
+	venc_modify(sd, VENC_VMOD, (HDTV_1080I << VENC_VMOD_TVTYP_SHIFT),
+		    VENC_VMOD_TVTYP);
+	venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+	venc_write(sd, VENC_XHINTVL, 0);
+	return 0;
+}
+
+static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+	v4l2_dbg(debug, 1, sd, "venc_s_std_output\n");
+
+	if (norm & V4L2_STD_525_60)
+		return venc_set_ntsc(sd);
+	else if (norm & V4L2_STD_625_50)
+		return venc_set_pal(sd);
+
+	return -EINVAL;
+}
+
+static int venc_s_dv_preset(struct v4l2_subdev *sd,
+			    struct v4l2_dv_preset *dv_preset)
+{
+	struct venc_state *venc = to_state(sd);
+	int ret;
+
+	v4l2_dbg(debug, 1, sd, "venc_s_dv_preset\n");
+
+	if (dv_preset->preset == V4L2_DV_576P50)
+		return venc_set_576p50(sd);
+	else if (dv_preset->preset == V4L2_DV_480P59_94)
+		return venc_set_480p59_94(sd);
+	else if ((dv_preset->preset == V4L2_DV_720P60) &&
+			(venc->pdata->venc_type == VPBE_VERSION_2)) {
+		/* TBD setup internal 720p mode here */
+		ret = venc_set_720p60_internal(sd);
+		/* for DM365 VPBE, there is DAC inside */
+		vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
+		return ret;
+	} else if ((dv_preset->preset == V4L2_DV_1080I30) &&
+		(venc->pdata->venc_type == VPBE_VERSION_2)) {
+		/* TBD setup internal 1080i mode here */
+		ret = venc_set_1080i30_internal(sd);
+		/* for DM365 VPBE, there is DAC inside */
+		vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
+		return ret;
+	}
+	return -EINVAL;
+}
+
+static int venc_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
+			  u32 config)
+{
+	struct venc_state *venc = to_state(sd);
+	int ret;
+
+	v4l2_dbg(debug, 1, sd, "venc_s_routing\n");
+
+	ret = venc_set_dac(sd, output);
+	if (!ret)
+		venc->output = output;
+
+	return ret;
+}
+
+static long venc_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd,
+			void *arg)
+{
+	u32 val;
+
+	switch (cmd) {
+	case VENC_GET_FLD:
+		val = venc_read(sd, VENC_VSTAT);
+		*((int *)arg) = ((val & VENC_VSTAT_FIDST) ==
+		VENC_VSTAT_FIDST);
+		break;
+	default:
+		v4l2_err(sd, "Wrong IOCTL cmd\n");
+		break;
+	}
+
+	return 0;
+}
+
+static const struct v4l2_subdev_core_ops venc_core_ops = {
+	.ioctl      = venc_ioctl,
+};
+
+static const struct v4l2_subdev_video_ops venc_video_ops = {
+	.s_routing = venc_s_routing,
+	.s_std_output = venc_s_std_output,
+	.s_dv_preset = venc_s_dv_preset,
+};
+
+static const struct v4l2_subdev_ops venc_ops = {
+	.core = &venc_core_ops,
+	.video = &venc_video_ops,
+};
+
+static int venc_initialize(struct v4l2_subdev *sd)
+{
+	struct venc_state *venc = to_state(sd);
+	int ret;
+
+	/* Set default to output to composite and std to NTSC */
+	venc->output = 0;
+	venc->std = V4L2_STD_525_60;
+
+	ret = venc_s_routing(sd, 0, venc->output, 0);
+	if (ret < 0) {
+		v4l2_err(sd, "Error setting output during init\n");
+		return -EINVAL;
+	}
+
+	ret = venc_s_std_output(sd, venc->std);
+	if (ret < 0) {
+		v4l2_err(sd, "Error setting std during init\n");
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int venc_device_get(struct device *dev, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct venc_state **venc = data;
+
+	if (strcmp(MODULE_NAME, pdev->name) == 0)
+		*venc = platform_get_drvdata(pdev);
+
+	return 0;
+}
+
+struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev,
+		const char *venc_name)
+{
+	struct venc_state *venc;
+	int err;
+
+	err = bus_for_each_dev(&platform_bus_type, NULL, &venc,
+			venc_device_get);
+	if (venc == NULL)
+		return NULL;
+
+	v4l2_subdev_init(&venc->sd, &venc_ops);
+
+	strcpy(venc->sd.name, venc_name);
+	if (v4l2_device_register_subdev(v4l2_dev, &venc->sd) < 0) {
+		v4l2_err(v4l2_dev,
+			"vpbe unable to register venc sub device\n");
+		return NULL;
+	}
+	if (venc_initialize(&venc->sd)) {
+		v4l2_err(v4l2_dev,
+			"vpbe venc initialization failed\n");
+		return NULL;
+	}
+
+	return &venc->sd;
+}
+EXPORT_SYMBOL(venc_sub_dev_init);
+
+static int venc_probe(struct platform_device *pdev)
+{
+	struct venc_state *venc;
+	struct resource *res;
+	int ret;
+
+	venc = kzalloc(sizeof(struct venc_state), GFP_KERNEL);
+	if (venc == NULL)
+		return -ENOMEM;
+
+	venc->pdev = &pdev->dev;
+	venc->pdata = pdev->dev.platform_data;
+	if (NULL == venc->pdata) {
+		dev_err(venc->pdev, "Unable to get platform data for"
+			" VENC sub device");
+		ret = -ENOENT;
+		goto free_mem;
+	}
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(venc->pdev,
+			"Unable to get VENC register address map\n");
+		ret = -ENODEV;
+		goto free_mem;
+	}
+
+	if (!request_mem_region(res->start, resource_size(res), "venc")) {
+		dev_err(venc->pdev, "Unable to reserve VENC MMIO region\n");
+		ret = -ENODEV;
+		goto free_mem;
+	}
+
+	venc->venc_base = ioremap_nocache(res->start, resource_size(res));
+	if (!venc->venc_base) {
+		dev_err(venc->pdev, "Unable to map VENC IO space\n");
+		ret = -ENODEV;
+		goto release_venc_mem_region;
+	}
+
+	if (venc->pdata->venc_type != VPBE_VERSION_1) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+		if (!res) {
+			dev_err(venc->pdev,
+				"Unable to get VDAC_CONFIG address map\n");
+			ret = -ENODEV;
+			goto unmap_venc_io;
+		}
+
+		if (!request_mem_region(res->start,
+					resource_size(res), "venc")) {
+			dev_err(venc->pdev,
+				"Unable to reserve VDAC_CONFIG  MMIO region\n");
+			ret = -ENODEV;
+			goto unmap_venc_io;
+		}
+
+		venc->vdaccfg_reg = ioremap_nocache(res->start,
+						    resource_size(res));
+		if (!venc->vdaccfg_reg) {
+			dev_err(venc->pdev,
+				"Unable to map VDAC_CONFIG IO space\n");
+			ret = -ENODEV;
+			goto release_vdaccfg_mem_region;
+		}
+	}
+	spin_lock_init(&venc->lock);
+	platform_set_drvdata(pdev, venc);
+	dev_notice(venc->pdev, "VENC sub device probe success\n");
+	return 0;
+
+release_vdaccfg_mem_region:
+	release_mem_region(res->start, resource_size(res));
+unmap_venc_io:
+	iounmap(venc->venc_base);
+release_venc_mem_region:
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, resource_size(res));
+free_mem:
+	kfree(venc);
+	return ret;
+}
+
+static int venc_remove(struct platform_device *pdev)
+{
+	struct venc_state *venc = platform_get_drvdata(pdev);
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	iounmap((void *)venc->venc_base);
+	release_mem_region(res->start, resource_size(res));
+	if (venc->pdata->venc_type != VPBE_VERSION_1) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+		iounmap((void *)venc->vdaccfg_reg);
+		release_mem_region(res->start, resource_size(res));
+	}
+	kfree(venc);
+
+	return 0;
+}
+
+static struct platform_driver venc_driver = {
+	.probe		= venc_probe,
+	.remove		= venc_remove,
+	.driver		= {
+		.name	= MODULE_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(venc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("VPBE VENC Driver");
+MODULE_AUTHOR("Texas Instruments");
diff --git a/drivers/media/platform/davinci/vpbe_venc_regs.h b/drivers/media/platform/davinci/vpbe_venc_regs.h
new file mode 100644
index 0000000..947cb15
--- /dev/null
+++ b/drivers/media/platform/davinci/vpbe_venc_regs.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2006-2010 Texas Instruments Inc
+ *
+ * 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 version 2..
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _VPBE_VENC_REGS_H
+#define _VPBE_VENC_REGS_H
+
+/* VPBE Video Encoder / Digital LCD Subsystem Registers (VENC) */
+#define VENC_VMOD				0x00
+#define VENC_VIDCTL				0x04
+#define VENC_VDPRO				0x08
+#define VENC_SYNCCTL				0x0C
+#define VENC_HSPLS				0x10
+#define VENC_VSPLS				0x14
+#define VENC_HINT				0x18
+#define VENC_HSTART				0x1C
+#define VENC_HVALID				0x20
+#define VENC_VINT				0x24
+#define VENC_VSTART				0x28
+#define VENC_VVALID				0x2C
+#define VENC_HSDLY				0x30
+#define VENC_VSDLY				0x34
+#define VENC_YCCCTL				0x38
+#define VENC_RGBCTL				0x3C
+#define VENC_RGBCLP				0x40
+#define VENC_LINECTL				0x44
+#define VENC_CULLLINE				0x48
+#define VENC_LCDOUT				0x4C
+#define VENC_BRTS				0x50
+#define VENC_BRTW				0x54
+#define VENC_ACCTL				0x58
+#define VENC_PWMP				0x5C
+#define VENC_PWMW				0x60
+#define VENC_DCLKCTL				0x64
+#define VENC_DCLKPTN0				0x68
+#define VENC_DCLKPTN1				0x6C
+#define VENC_DCLKPTN2				0x70
+#define VENC_DCLKPTN3				0x74
+#define VENC_DCLKPTN0A				0x78
+#define VENC_DCLKPTN1A				0x7C
+#define VENC_DCLKPTN2A				0x80
+#define VENC_DCLKPTN3A				0x84
+#define VENC_DCLKHS				0x88
+#define VENC_DCLKHSA				0x8C
+#define VENC_DCLKHR				0x90
+#define VENC_DCLKVS				0x94
+#define VENC_DCLKVR				0x98
+#define VENC_CAPCTL				0x9C
+#define VENC_CAPDO				0xA0
+#define VENC_CAPDE				0xA4
+#define VENC_ATR0				0xA8
+#define VENC_ATR1				0xAC
+#define VENC_ATR2				0xB0
+#define VENC_VSTAT				0xB8
+#define VENC_RAMADR				0xBC
+#define VENC_RAMPORT				0xC0
+#define VENC_DACTST				0xC4
+#define VENC_YCOLVL				0xC8
+#define VENC_SCPROG				0xCC
+#define VENC_CVBS				0xDC
+#define VENC_CMPNT				0xE0
+#define VENC_ETMG0				0xE4
+#define VENC_ETMG1				0xE8
+#define VENC_ETMG2				0xEC
+#define VENC_ETMG3				0xF0
+#define VENC_DACSEL				0xF4
+#define VENC_ARGBX0				0x100
+#define VENC_ARGBX1				0x104
+#define VENC_ARGBX2				0x108
+#define VENC_ARGBX3				0x10C
+#define VENC_ARGBX4				0x110
+#define VENC_DRGBX0				0x114
+#define VENC_DRGBX1				0x118
+#define VENC_DRGBX2				0x11C
+#define VENC_DRGBX3				0x120
+#define VENC_DRGBX4				0x124
+#define VENC_VSTARTA				0x128
+#define VENC_OSDCLK0				0x12C
+#define VENC_OSDCLK1				0x130
+#define VENC_HVLDCL0				0x134
+#define VENC_HVLDCL1				0x138
+#define VENC_OSDHADV				0x13C
+#define VENC_CLKCTL				0x140
+#define VENC_GAMCTL				0x144
+#define VENC_XHINTVL				0x174
+
+/* bit definitions */
+#define VPBE_PCR_VENC_DIV			(1 << 1)
+#define VPBE_PCR_CLK_OFF			(1 << 0)
+
+#define VENC_VMOD_VDMD_SHIFT			12
+#define VENC_VMOD_VDMD_YCBCR16			0
+#define VENC_VMOD_VDMD_YCBCR8			1
+#define VENC_VMOD_VDMD_RGB666			2
+#define VENC_VMOD_VDMD_RGB8			3
+#define VENC_VMOD_VDMD_EPSON			4
+#define VENC_VMOD_VDMD_CASIO			5
+#define VENC_VMOD_VDMD_UDISPQVGA		6
+#define VENC_VMOD_VDMD_STNLCD			7
+#define VENC_VMOD_VIE_SHIFT			1
+#define VENC_VMOD_VDMD				(7 << 12)
+#define VENC_VMOD_ITLCL				(1 << 11)
+#define VENC_VMOD_ITLC				(1 << 10)
+#define VENC_VMOD_NSIT				(1 << 9)
+#define VENC_VMOD_HDMD				(1 << 8)
+#define VENC_VMOD_TVTYP_SHIFT			6
+#define VENC_VMOD_TVTYP				(3 << 6)
+#define VENC_VMOD_SLAVE				(1 << 5)
+#define VENC_VMOD_VMD				(1 << 4)
+#define VENC_VMOD_BLNK				(1 << 3)
+#define VENC_VMOD_VIE				(1 << 1)
+#define VENC_VMOD_VENC				(1 << 0)
+
+/* VMOD TVTYP options for HDMD=0 */
+#define SDTV_NTSC				0
+#define SDTV_PAL				1
+/* VMOD TVTYP options for HDMD=1 */
+#define HDTV_525P				0
+#define HDTV_625P				1
+#define HDTV_1080I				2
+#define HDTV_720P				3
+
+#define VENC_VIDCTL_VCLKP			(1 << 14)
+#define VENC_VIDCTL_VCLKE_SHIFT			13
+#define VENC_VIDCTL_VCLKE			(1 << 13)
+#define VENC_VIDCTL_VCLKZ_SHIFT			12
+#define VENC_VIDCTL_VCLKZ			(1 << 12)
+#define VENC_VIDCTL_SYDIR_SHIFT			8
+#define VENC_VIDCTL_SYDIR			(1 << 8)
+#define VENC_VIDCTL_DOMD_SHIFT			4
+#define VENC_VIDCTL_DOMD			(3 << 4)
+#define VENC_VIDCTL_YCDIR_SHIFT			0
+#define VENC_VIDCTL_YCDIR			(1 << 0)
+
+#define VENC_VDPRO_ATYCC_SHIFT			5
+#define VENC_VDPRO_ATYCC			(1 << 5)
+#define VENC_VDPRO_ATCOM_SHIFT			4
+#define VENC_VDPRO_ATCOM			(1 << 4)
+#define VENC_VDPRO_DAFRQ			(1 << 3)
+#define VENC_VDPRO_DAUPS			(1 << 2)
+#define VENC_VDPRO_CUPS				(1 << 1)
+#define VENC_VDPRO_YUPS				(1 << 0)
+
+#define VENC_SYNCCTL_VPL_SHIFT			3
+#define VENC_SYNCCTL_VPL			(1 << 3)
+#define VENC_SYNCCTL_HPL_SHIFT			2
+#define VENC_SYNCCTL_HPL			(1 << 2)
+#define VENC_SYNCCTL_SYEV_SHIFT			1
+#define VENC_SYNCCTL_SYEV			(1 << 1)
+#define VENC_SYNCCTL_SYEH_SHIFT			0
+#define VENC_SYNCCTL_SYEH			(1 << 0)
+#define VENC_SYNCCTL_OVD_SHIFT			14
+#define VENC_SYNCCTL_OVD			(1 << 14)
+
+#define VENC_DCLKCTL_DCKEC_SHIFT		11
+#define VENC_DCLKCTL_DCKEC			(1 << 11)
+#define VENC_DCLKCTL_DCKPW_SHIFT		0
+#define VENC_DCLKCTL_DCKPW			(0x3f << 0)
+
+#define VENC_VSTAT_FIDST			(1 << 4)
+
+#define VENC_CMPNT_MRGB_SHIFT			14
+#define VENC_CMPNT_MRGB				(1 << 14)
+
+#endif				/* _VPBE_VENC_REGS_H */
diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c
new file mode 100644
index 0000000..843b138
--- /dev/null
+++ b/drivers/media/platform/davinci/vpfe_capture.c
@@ -0,0 +1,2079 @@
+/*
+ * Copyright (C) 2008-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ * Driver name : VPFE Capture driver
+ *    VPFE Capture driver allows applications to capture and stream video
+ *    frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as
+ *    TVP5146 or  Raw Bayer RGB image data from an image sensor
+ *    such as Microns' MT9T001, MT9T031 etc.
+ *
+ *    These SoCs have, in common, a Video Processing Subsystem (VPSS) that
+ *    consists of a Video Processing Front End (VPFE) for capturing
+ *    video/raw image data and Video Processing Back End (VPBE) for displaying
+ *    YUV data through an in-built analog encoder or Digital LCD port. This
+ *    driver is for capture through VPFE. A typical EVM using these SoCs have
+ *    following high level configuration.
+ *
+ *
+ *    decoder(TVP5146/		YUV/
+ * 	     MT9T001)   -->  Raw Bayer RGB ---> MUX -> VPFE (CCDC/ISIF)
+ *    				data input              |      |
+ *							V      |
+ *						      SDRAM    |
+ *							       V
+ *							   Image Processor
+ *							       |
+ *							       V
+ *							     SDRAM
+ *    The data flow happens from a decoder connected to the VPFE over a
+ *    YUV embedded (BT.656/BT.1120) or separate sync or raw bayer rgb interface
+ *    and to the input of VPFE through an optional MUX (if more inputs are
+ *    to be interfaced on the EVM). The input data is first passed through
+ *    CCDC (CCD Controller, a.k.a Image Sensor Interface, ISIF). The CCDC
+ *    does very little or no processing on YUV data and does pre-process Raw
+ *    Bayer RGB data through modules such as Defect Pixel Correction (DFC)
+ *    Color Space Conversion (CSC), data gain/offset etc. After this, data
+ *    can be written to SDRAM or can be connected to the image processing
+ *    block such as IPIPE (on DM355 only).
+ *
+ *    Features supported
+ *  		- MMAP IO
+ *		- Capture using TVP5146 over BT.656
+ *		- support for interfacing decoders using sub device model
+ *		- Work with DM355 or DM6446 CCDC to do Raw Bayer RGB/YUV
+ *		  data capture to SDRAM.
+ *    TODO list
+ *		- Support multiple REQBUF after open
+ *		- Support for de-allocating buffers through REQBUF
+ *		- Support for Raw Bayer RGB capture
+ *		- Support for chaining Image Processor
+ *		- Support for static allocation of buffers
+ *		- Support for USERPTR IO
+ *		- Support for STREAMON before QBUF
+ *		- Support for control ioctls
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <media/v4l2-common.h>
+#include <linux/io.h>
+#include <media/davinci/vpfe_capture.h>
+#include "ccdc_hw_device.h"
+
+static int debug;
+static u32 numbuffers = 3;
+static u32 bufsize = (720 * 576 * 2);
+
+module_param(numbuffers, uint, S_IRUGO);
+module_param(bufsize, uint, S_IRUGO);
+module_param(debug, int, 0644);
+
+MODULE_PARM_DESC(numbuffers, "buffer count (default:3)");
+MODULE_PARM_DESC(bufsize, "buffer size in bytes (default:720 x 576 x 2)");
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+
+MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments");
+
+/* standard information */
+struct vpfe_standard {
+	v4l2_std_id std_id;
+	unsigned int width;
+	unsigned int height;
+	struct v4l2_fract pixelaspect;
+	/* 0 - progressive, 1 - interlaced */
+	int frame_format;
+};
+
+/* ccdc configuration */
+struct ccdc_config {
+	/* This make sure vpfe is probed and ready to go */
+	int vpfe_probed;
+	/* name of ccdc device */
+	char name[32];
+};
+
+/* data structures */
+static struct vpfe_config_params config_params = {
+	.min_numbuffers = 3,
+	.numbuffers = 3,
+	.min_bufsize = 720 * 480 * 2,
+	.device_bufsize = 720 * 576 * 2,
+};
+
+/* ccdc device registered */
+static struct ccdc_hw_device *ccdc_dev;
+/* lock for accessing ccdc information */
+static DEFINE_MUTEX(ccdc_lock);
+/* ccdc configuration */
+static struct ccdc_config *ccdc_cfg;
+
+const struct vpfe_standard vpfe_standards[] = {
+	{V4L2_STD_525_60, 720, 480, {11, 10}, 1},
+	{V4L2_STD_625_50, 720, 576, {54, 59}, 1},
+};
+
+/* Used when raw Bayer image from ccdc is directly captured to SDRAM */
+static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
+	{
+		.fmtdesc = {
+			.index = 0,
+			.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			.description = "Bayer GrRBGb 8bit A-Law compr.",
+			.pixelformat = V4L2_PIX_FMT_SBGGR8,
+		},
+		.bpp = 1,
+	},
+	{
+		.fmtdesc = {
+			.index = 1,
+			.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			.description = "Bayer GrRBGb - 16bit",
+			.pixelformat = V4L2_PIX_FMT_SBGGR16,
+		},
+		.bpp = 2,
+	},
+	{
+		.fmtdesc = {
+			.index = 2,
+			.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			.description = "Bayer GrRBGb 8bit DPCM compr.",
+			.pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
+		},
+		.bpp = 1,
+	},
+	{
+		.fmtdesc = {
+			.index = 3,
+			.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			.description = "YCbCr 4:2:2 Interleaved UYVY",
+			.pixelformat = V4L2_PIX_FMT_UYVY,
+		},
+		.bpp = 2,
+	},
+	{
+		.fmtdesc = {
+			.index = 4,
+			.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			.description = "YCbCr 4:2:2 Interleaved YUYV",
+			.pixelformat = V4L2_PIX_FMT_YUYV,
+		},
+		.bpp = 2,
+	},
+	{
+		.fmtdesc = {
+			.index = 5,
+			.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			.description = "Y/CbCr 4:2:0 - Semi planar",
+			.pixelformat = V4L2_PIX_FMT_NV12,
+		},
+		.bpp = 1,
+	},
+};
+
+/*
+ * vpfe_lookup_pix_format()
+ * lookup an entry in the vpfe pix format table based on pix_format
+ */
+static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vpfe_pix_fmts); i++) {
+		if (pix_format == vpfe_pix_fmts[i].fmtdesc.pixelformat)
+			return &vpfe_pix_fmts[i];
+	}
+	return NULL;
+}
+
+/*
+ * vpfe_register_ccdc_device. CCDC module calls this to
+ * register with vpfe capture
+ */
+int vpfe_register_ccdc_device(struct ccdc_hw_device *dev)
+{
+	int ret = 0;
+	printk(KERN_NOTICE "vpfe_register_ccdc_device: %s\n", dev->name);
+
+	BUG_ON(!dev->hw_ops.open);
+	BUG_ON(!dev->hw_ops.enable);
+	BUG_ON(!dev->hw_ops.set_hw_if_params);
+	BUG_ON(!dev->hw_ops.configure);
+	BUG_ON(!dev->hw_ops.set_buftype);
+	BUG_ON(!dev->hw_ops.get_buftype);
+	BUG_ON(!dev->hw_ops.enum_pix);
+	BUG_ON(!dev->hw_ops.set_frame_format);
+	BUG_ON(!dev->hw_ops.get_frame_format);
+	BUG_ON(!dev->hw_ops.get_pixel_format);
+	BUG_ON(!dev->hw_ops.set_pixel_format);
+	BUG_ON(!dev->hw_ops.set_image_window);
+	BUG_ON(!dev->hw_ops.get_image_window);
+	BUG_ON(!dev->hw_ops.get_line_length);
+	BUG_ON(!dev->hw_ops.getfid);
+
+	mutex_lock(&ccdc_lock);
+	if (NULL == ccdc_cfg) {
+		/*
+		 * TODO. Will this ever happen? if so, we need to fix it.
+		 * Proabably we need to add the request to a linked list and
+		 * walk through it during vpfe probe
+		 */
+		printk(KERN_ERR "vpfe capture not initialized\n");
+		ret = -EFAULT;
+		goto unlock;
+	}
+
+	if (strcmp(dev->name, ccdc_cfg->name)) {
+		/* ignore this ccdc */
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+	if (ccdc_dev) {
+		printk(KERN_ERR "ccdc already registered\n");
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+	ccdc_dev = dev;
+unlock:
+	mutex_unlock(&ccdc_lock);
+	return ret;
+}
+EXPORT_SYMBOL(vpfe_register_ccdc_device);
+
+/*
+ * vpfe_unregister_ccdc_device. CCDC module calls this to
+ * unregister with vpfe capture
+ */
+void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev)
+{
+	if (NULL == dev) {
+		printk(KERN_ERR "invalid ccdc device ptr\n");
+		return;
+	}
+
+	printk(KERN_NOTICE "vpfe_unregister_ccdc_device, dev->name = %s\n",
+		dev->name);
+
+	if (strcmp(dev->name, ccdc_cfg->name)) {
+		/* ignore this ccdc */
+		return;
+	}
+
+	mutex_lock(&ccdc_lock);
+	ccdc_dev = NULL;
+	mutex_unlock(&ccdc_lock);
+	return;
+}
+EXPORT_SYMBOL(vpfe_unregister_ccdc_device);
+
+/*
+ * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings
+ */
+static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe_dev,
+				 struct v4l2_format *f)
+{
+	struct v4l2_rect image_win;
+	enum ccdc_buftype buf_type;
+	enum ccdc_frmfmt frm_fmt;
+
+	memset(f, 0, sizeof(*f));
+	f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	ccdc_dev->hw_ops.get_image_window(&image_win);
+	f->fmt.pix.width = image_win.width;
+	f->fmt.pix.height = image_win.height;
+	f->fmt.pix.bytesperline = ccdc_dev->hw_ops.get_line_length();
+	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+				f->fmt.pix.height;
+	buf_type = ccdc_dev->hw_ops.get_buftype();
+	f->fmt.pix.pixelformat = ccdc_dev->hw_ops.get_pixel_format();
+	frm_fmt = ccdc_dev->hw_ops.get_frame_format();
+	if (frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
+		f->fmt.pix.field = V4L2_FIELD_NONE;
+	else if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+		if (buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)
+			f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+		else if (buf_type == CCDC_BUFTYPE_FLD_SEPARATED)
+			f->fmt.pix.field = V4L2_FIELD_SEQ_TB;
+		else {
+			v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf_type\n");
+			return -EINVAL;
+		}
+	} else {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid frm_fmt\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * vpfe_config_ccdc_image_format()
+ * For a pix format, configure ccdc to setup the capture
+ */
+static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev)
+{
+	enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED;
+	int ret = 0;
+
+	if (ccdc_dev->hw_ops.set_pixel_format(
+			vpfe_dev->fmt.fmt.pix.pixelformat) < 0) {
+		v4l2_err(&vpfe_dev->v4l2_dev,
+			"couldn't set pix format in ccdc\n");
+		return -EINVAL;
+	}
+	/* configure the image window */
+	ccdc_dev->hw_ops.set_image_window(&vpfe_dev->crop);
+
+	switch (vpfe_dev->fmt.fmt.pix.field) {
+	case V4L2_FIELD_INTERLACED:
+		/* do nothing, since it is default */
+		ret = ccdc_dev->hw_ops.set_buftype(
+				CCDC_BUFTYPE_FLD_INTERLEAVED);
+		break;
+	case V4L2_FIELD_NONE:
+		frm_fmt = CCDC_FRMFMT_PROGRESSIVE;
+		/* buffer type only applicable for interlaced scan */
+		break;
+	case V4L2_FIELD_SEQ_TB:
+		ret = ccdc_dev->hw_ops.set_buftype(
+				CCDC_BUFTYPE_FLD_SEPARATED);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set the frame format */
+	if (!ret)
+		ret = ccdc_dev->hw_ops.set_frame_format(frm_fmt);
+	return ret;
+}
+/*
+ * vpfe_config_image_format()
+ * For a given standard, this functions sets up the default
+ * pix format & crop values in the vpfe device and ccdc.  It first
+ * starts with defaults based values from the standard table.
+ * It then checks if sub device support g_mbus_fmt and then override the
+ * values based on that.Sets crop values to match with scan resolution
+ * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the
+ * values in ccdc
+ */
+static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
+				    const v4l2_std_id *std_id)
+{
+	struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev;
+	struct v4l2_mbus_framefmt mbus_fmt;
+	struct v4l2_pix_format *pix = &vpfe_dev->fmt.fmt.pix;
+	int i, ret = 0;
+
+	for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) {
+		if (vpfe_standards[i].std_id & *std_id) {
+			vpfe_dev->std_info.active_pixels =
+					vpfe_standards[i].width;
+			vpfe_dev->std_info.active_lines =
+					vpfe_standards[i].height;
+			vpfe_dev->std_info.frame_format =
+					vpfe_standards[i].frame_format;
+			vpfe_dev->std_index = i;
+			break;
+		}
+	}
+
+	if (i ==  ARRAY_SIZE(vpfe_standards)) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "standard not supported\n");
+		return -EINVAL;
+	}
+
+	vpfe_dev->crop.top = 0;
+	vpfe_dev->crop.left = 0;
+	vpfe_dev->crop.width = vpfe_dev->std_info.active_pixels;
+	vpfe_dev->crop.height = vpfe_dev->std_info.active_lines;
+	pix->width = vpfe_dev->crop.width;
+	pix->height = vpfe_dev->crop.height;
+
+	/* first field and frame format based on standard frame format */
+	if (vpfe_dev->std_info.frame_format) {
+		pix->field = V4L2_FIELD_INTERLACED;
+		/* assume V4L2_PIX_FMT_UYVY as default */
+		pix->pixelformat = V4L2_PIX_FMT_UYVY;
+		v4l2_fill_mbus_format(&mbus_fmt, pix,
+				V4L2_MBUS_FMT_YUYV10_2X10);
+	} else {
+		pix->field = V4L2_FIELD_NONE;
+		/* assume V4L2_PIX_FMT_SBGGR8 */
+		pix->pixelformat = V4L2_PIX_FMT_SBGGR8;
+		v4l2_fill_mbus_format(&mbus_fmt, pix,
+				V4L2_MBUS_FMT_SBGGR8_1X8);
+	}
+
+	/* if sub device supports g_mbus_fmt, override the defaults */
+	ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
+			sdinfo->grp_id, video, g_mbus_fmt, &mbus_fmt);
+
+	if (ret && ret != -ENOIOCTLCMD) {
+		v4l2_err(&vpfe_dev->v4l2_dev,
+			"error in getting g_mbus_fmt from sub device\n");
+		return ret;
+	}
+	v4l2_fill_pix_format(pix, &mbus_fmt);
+	pix->bytesperline = pix->width * 2;
+	pix->sizeimage = pix->bytesperline * pix->height;
+
+	/* Sets the values in CCDC */
+	ret = vpfe_config_ccdc_image_format(vpfe_dev);
+	if (ret)
+		return ret;
+
+	/* Update the values of sizeimage and bytesperline */
+	if (!ret) {
+		pix->bytesperline = ccdc_dev->hw_ops.get_line_length();
+		pix->sizeimage = pix->bytesperline * pix->height;
+	}
+	return ret;
+}
+
+static int vpfe_initialize_device(struct vpfe_device *vpfe_dev)
+{
+	int ret = 0;
+
+	/* set first input of current subdevice as the current input */
+	vpfe_dev->current_input = 0;
+
+	/* set default standard */
+	vpfe_dev->std_index = 0;
+
+	/* Configure the default format information */
+	ret = vpfe_config_image_format(vpfe_dev,
+				&vpfe_standards[vpfe_dev->std_index].std_id);
+	if (ret)
+		return ret;
+
+	/* now open the ccdc device to initialize it */
+	mutex_lock(&ccdc_lock);
+	if (NULL == ccdc_dev) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "ccdc device not registered\n");
+		ret = -ENODEV;
+		goto unlock;
+	}
+
+	if (!try_module_get(ccdc_dev->owner)) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Couldn't lock ccdc module\n");
+		ret = -ENODEV;
+		goto unlock;
+	}
+	ret = ccdc_dev->hw_ops.open(vpfe_dev->pdev);
+	if (!ret)
+		vpfe_dev->initialized = 1;
+
+	/* Clear all VPFE/CCDC interrupts */
+	if (vpfe_dev->cfg->clr_intr)
+		vpfe_dev->cfg->clr_intr(-1);
+
+unlock:
+	mutex_unlock(&ccdc_lock);
+	return ret;
+}
+
+/*
+ * vpfe_open : It creates object of file handle structure and
+ * stores it in private_data  member of filepointer
+ */
+static int vpfe_open(struct file *file)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	struct vpfe_fh *fh;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_open\n");
+
+	if (!vpfe_dev->cfg->num_subdevs) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "No decoder registered\n");
+		return -ENODEV;
+	}
+
+	/* Allocate memory for the file handle object */
+	fh = kmalloc(sizeof(struct vpfe_fh), GFP_KERNEL);
+	if (NULL == fh) {
+		v4l2_err(&vpfe_dev->v4l2_dev,
+			"unable to allocate memory for file handle object\n");
+		return -ENOMEM;
+	}
+	/* store pointer to fh in private_data member of file */
+	file->private_data = fh;
+	fh->vpfe_dev = vpfe_dev;
+	mutex_lock(&vpfe_dev->lock);
+	/* If decoder is not initialized. initialize it */
+	if (!vpfe_dev->initialized) {
+		if (vpfe_initialize_device(vpfe_dev)) {
+			mutex_unlock(&vpfe_dev->lock);
+			return -ENODEV;
+		}
+	}
+	/* Increment device usrs counter */
+	vpfe_dev->usrs++;
+	/* Set io_allowed member to false */
+	fh->io_allowed = 0;
+	/* Initialize priority of this instance to default priority */
+	fh->prio = V4L2_PRIORITY_UNSET;
+	v4l2_prio_open(&vpfe_dev->prio, &fh->prio);
+	mutex_unlock(&vpfe_dev->lock);
+	return 0;
+}
+
+static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe_dev)
+{
+	unsigned long addr;
+
+	vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next,
+					struct videobuf_buffer, queue);
+	list_del(&vpfe_dev->next_frm->queue);
+	vpfe_dev->next_frm->state = VIDEOBUF_ACTIVE;
+	addr = videobuf_to_dma_contig(vpfe_dev->next_frm);
+
+	ccdc_dev->hw_ops.setfbaddr(addr);
+}
+
+static void vpfe_schedule_bottom_field(struct vpfe_device *vpfe_dev)
+{
+	unsigned long addr;
+
+	addr = videobuf_to_dma_contig(vpfe_dev->cur_frm);
+	addr += vpfe_dev->field_off;
+	ccdc_dev->hw_ops.setfbaddr(addr);
+}
+
+static void vpfe_process_buffer_complete(struct vpfe_device *vpfe_dev)
+{
+	struct timeval timevalue;
+
+	do_gettimeofday(&timevalue);
+	vpfe_dev->cur_frm->ts = timevalue;
+	vpfe_dev->cur_frm->state = VIDEOBUF_DONE;
+	vpfe_dev->cur_frm->size = vpfe_dev->fmt.fmt.pix.sizeimage;
+	wake_up_interruptible(&vpfe_dev->cur_frm->done);
+	vpfe_dev->cur_frm = vpfe_dev->next_frm;
+}
+
+/* ISR for VINT0*/
+static irqreturn_t vpfe_isr(int irq, void *dev_id)
+{
+	struct vpfe_device *vpfe_dev = dev_id;
+	enum v4l2_field field;
+	int fid;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nStarting vpfe_isr...\n");
+	field = vpfe_dev->fmt.fmt.pix.field;
+
+	/* if streaming not started, don't do anything */
+	if (!vpfe_dev->started)
+		goto clear_intr;
+
+	/* only for 6446 this will be applicable */
+	if (NULL != ccdc_dev->hw_ops.reset)
+		ccdc_dev->hw_ops.reset();
+
+	if (field == V4L2_FIELD_NONE) {
+		/* handle progressive frame capture */
+		v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+			"frame format is progressive...\n");
+		if (vpfe_dev->cur_frm != vpfe_dev->next_frm)
+			vpfe_process_buffer_complete(vpfe_dev);
+		goto clear_intr;
+	}
+
+	/* interlaced or TB capture check which field we are in hardware */
+	fid = ccdc_dev->hw_ops.getfid();
+
+	/* switch the software maintained field id */
+	vpfe_dev->field_id ^= 1;
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "field id = %x:%x.\n",
+		fid, vpfe_dev->field_id);
+	if (fid == vpfe_dev->field_id) {
+		/* we are in-sync here,continue */
+		if (fid == 0) {
+			/*
+			 * One frame is just being captured. If the next frame
+			 * is available, release the current frame and move on
+			 */
+			if (vpfe_dev->cur_frm != vpfe_dev->next_frm)
+				vpfe_process_buffer_complete(vpfe_dev);
+			/*
+			 * based on whether the two fields are stored
+			 * interleavely or separately in memory, reconfigure
+			 * the CCDC memory address
+			 */
+			if (field == V4L2_FIELD_SEQ_TB) {
+				vpfe_schedule_bottom_field(vpfe_dev);
+			}
+			goto clear_intr;
+		}
+		/*
+		 * if one field is just being captured configure
+		 * the next frame get the next frame from the empty
+		 * queue if no frame is available hold on to the
+		 * current buffer
+		 */
+		spin_lock(&vpfe_dev->dma_queue_lock);
+		if (!list_empty(&vpfe_dev->dma_queue) &&
+		    vpfe_dev->cur_frm == vpfe_dev->next_frm)
+			vpfe_schedule_next_buffer(vpfe_dev);
+		spin_unlock(&vpfe_dev->dma_queue_lock);
+	} else if (fid == 0) {
+		/*
+		 * out of sync. Recover from any hardware out-of-sync.
+		 * May loose one frame
+		 */
+		vpfe_dev->field_id = fid;
+	}
+clear_intr:
+	if (vpfe_dev->cfg->clr_intr)
+		vpfe_dev->cfg->clr_intr(irq);
+
+	return IRQ_HANDLED;
+}
+
+/* vdint1_isr - isr handler for VINT1 interrupt */
+static irqreturn_t vdint1_isr(int irq, void *dev_id)
+{
+	struct vpfe_device *vpfe_dev = dev_id;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nInside vdint1_isr...\n");
+
+	/* if streaming not started, don't do anything */
+	if (!vpfe_dev->started) {
+		if (vpfe_dev->cfg->clr_intr)
+			vpfe_dev->cfg->clr_intr(irq);
+		return IRQ_HANDLED;
+	}
+
+	spin_lock(&vpfe_dev->dma_queue_lock);
+	if ((vpfe_dev->fmt.fmt.pix.field == V4L2_FIELD_NONE) &&
+	    !list_empty(&vpfe_dev->dma_queue) &&
+	    vpfe_dev->cur_frm == vpfe_dev->next_frm)
+		vpfe_schedule_next_buffer(vpfe_dev);
+	spin_unlock(&vpfe_dev->dma_queue_lock);
+
+	if (vpfe_dev->cfg->clr_intr)
+		vpfe_dev->cfg->clr_intr(irq);
+
+	return IRQ_HANDLED;
+}
+
+static void vpfe_detach_irq(struct vpfe_device *vpfe_dev)
+{
+	enum ccdc_frmfmt frame_format;
+
+	frame_format = ccdc_dev->hw_ops.get_frame_format();
+	if (frame_format == CCDC_FRMFMT_PROGRESSIVE)
+		free_irq(vpfe_dev->ccdc_irq1, vpfe_dev);
+}
+
+static int vpfe_attach_irq(struct vpfe_device *vpfe_dev)
+{
+	enum ccdc_frmfmt frame_format;
+
+	frame_format = ccdc_dev->hw_ops.get_frame_format();
+	if (frame_format == CCDC_FRMFMT_PROGRESSIVE) {
+		return request_irq(vpfe_dev->ccdc_irq1, vdint1_isr,
+				    IRQF_DISABLED, "vpfe_capture1",
+				    vpfe_dev);
+	}
+	return 0;
+}
+
+/* vpfe_stop_ccdc_capture: stop streaming in ccdc/isif */
+static void vpfe_stop_ccdc_capture(struct vpfe_device *vpfe_dev)
+{
+	vpfe_dev->started = 0;
+	ccdc_dev->hw_ops.enable(0);
+	if (ccdc_dev->hw_ops.enable_out_to_sdram)
+		ccdc_dev->hw_ops.enable_out_to_sdram(0);
+}
+
+/*
+ * vpfe_release : This function deletes buffer queue, frees the
+ * buffers and the vpfe file  handle
+ */
+static int vpfe_release(struct file *file)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	struct vpfe_fh *fh = file->private_data;
+	struct vpfe_subdev_info *sdinfo;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n");
+
+	/* Get the device lock */
+	mutex_lock(&vpfe_dev->lock);
+	/* if this instance is doing IO */
+	if (fh->io_allowed) {
+		if (vpfe_dev->started) {
+			sdinfo = vpfe_dev->current_subdev;
+			ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
+							 sdinfo->grp_id,
+							 video, s_stream, 0);
+			if (ret && (ret != -ENOIOCTLCMD))
+				v4l2_err(&vpfe_dev->v4l2_dev,
+				"stream off failed in subdev\n");
+			vpfe_stop_ccdc_capture(vpfe_dev);
+			vpfe_detach_irq(vpfe_dev);
+			videobuf_streamoff(&vpfe_dev->buffer_queue);
+		}
+		vpfe_dev->io_usrs = 0;
+		vpfe_dev->numbuffers = config_params.numbuffers;
+	}
+
+	/* Decrement device usrs counter */
+	vpfe_dev->usrs--;
+	/* Close the priority */
+	v4l2_prio_close(&vpfe_dev->prio, fh->prio);
+	/* If this is the last file handle */
+	if (!vpfe_dev->usrs) {
+		vpfe_dev->initialized = 0;
+		if (ccdc_dev->hw_ops.close)
+			ccdc_dev->hw_ops.close(vpfe_dev->pdev);
+		module_put(ccdc_dev->owner);
+	}
+	mutex_unlock(&vpfe_dev->lock);
+	file->private_data = NULL;
+	/* Free memory allocated to file handle object */
+	kfree(fh);
+	return 0;
+}
+
+/*
+ * vpfe_mmap : It is used to map kernel space buffers
+ * into user spaces
+ */
+static int vpfe_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	/* Get the device object and file handle object */
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n");
+
+	return videobuf_mmap_mapper(&vpfe_dev->buffer_queue, vma);
+}
+
+/*
+ * vpfe_poll: It is used for select/poll system call
+ */
+static unsigned int vpfe_poll(struct file *file, poll_table *wait)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n");
+
+	if (vpfe_dev->started)
+		return videobuf_poll_stream(file,
+					    &vpfe_dev->buffer_queue, wait);
+	return 0;
+}
+
+/* vpfe capture driver file operations */
+static const struct v4l2_file_operations vpfe_fops = {
+	.owner = THIS_MODULE,
+	.open = vpfe_open,
+	.release = vpfe_release,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap = vpfe_mmap,
+	.poll = vpfe_poll
+};
+
+/*
+ * vpfe_check_format()
+ * This function adjust the input pixel format as per hardware
+ * capabilities and update the same in pixfmt.
+ * Following algorithm used :-
+ *
+ *	If given pixformat is not in the vpfe list of pix formats or not
+ *	supported by the hardware, current value of pixformat in the device
+ *	is used
+ *	If given field is not supported, then current field is used. If field
+ *	is different from current, then it is matched with that from sub device.
+ *	Minimum height is 2 lines for interlaced or tb field and 1 line for
+ *	progressive. Maximum height is clamped to active active lines of scan
+ *	Minimum width is 32 bytes in memory and width is clamped to active
+ *	pixels of scan.
+ *	bytesperline is a multiple of 32.
+ */
+static const struct vpfe_pixel_format *
+	vpfe_check_format(struct vpfe_device *vpfe_dev,
+			  struct v4l2_pix_format *pixfmt)
+{
+	u32 min_height = 1, min_width = 32, max_width, max_height;
+	const struct vpfe_pixel_format *vpfe_pix_fmt;
+	u32 pix;
+	int temp, found;
+
+	vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat);
+	if (NULL == vpfe_pix_fmt) {
+		/*
+		 * use current pixel format in the vpfe device. We
+		 * will find this pix format in the table
+		 */
+		pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat;
+		vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat);
+	}
+
+	/* check if hw supports it */
+	temp = 0;
+	found = 0;
+	while (ccdc_dev->hw_ops.enum_pix(&pix, temp) >= 0) {
+		if (vpfe_pix_fmt->fmtdesc.pixelformat == pix) {
+			found = 1;
+			break;
+		}
+		temp++;
+	}
+
+	if (!found) {
+		/* use current pixel format */
+		pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat;
+		/*
+		 * Since this is currently used in the vpfe device, we
+		 * will find this pix format in the table
+		 */
+		vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat);
+	}
+
+	/* check what field format is supported */
+	if (pixfmt->field == V4L2_FIELD_ANY) {
+		/* if field is any, use current value as default */
+		pixfmt->field = vpfe_dev->fmt.fmt.pix.field;
+	}
+
+	/*
+	 * if field is not same as current field in the vpfe device
+	 * try matching the field with the sub device field
+	 */
+	if (vpfe_dev->fmt.fmt.pix.field != pixfmt->field) {
+		/*
+		 * If field value is not in the supported fields, use current
+		 * field used in the device as default
+		 */
+		switch (pixfmt->field) {
+		case V4L2_FIELD_INTERLACED:
+		case V4L2_FIELD_SEQ_TB:
+			/* if sub device is supporting progressive, use that */
+			if (!vpfe_dev->std_info.frame_format)
+				pixfmt->field = V4L2_FIELD_NONE;
+			break;
+		case V4L2_FIELD_NONE:
+			if (vpfe_dev->std_info.frame_format)
+				pixfmt->field = V4L2_FIELD_INTERLACED;
+			break;
+
+		default:
+			/* use current field as default */
+			pixfmt->field = vpfe_dev->fmt.fmt.pix.field;
+			break;
+		}
+	}
+
+	/* Now adjust image resolutions supported */
+	if (pixfmt->field == V4L2_FIELD_INTERLACED ||
+	    pixfmt->field == V4L2_FIELD_SEQ_TB)
+		min_height = 2;
+
+	max_width = vpfe_dev->std_info.active_pixels;
+	max_height = vpfe_dev->std_info.active_lines;
+	min_width /= vpfe_pix_fmt->bpp;
+
+	v4l2_info(&vpfe_dev->v4l2_dev, "width = %d, height = %d, bpp = %d\n",
+		  pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp);
+
+	pixfmt->width = clamp((pixfmt->width), min_width, max_width);
+	pixfmt->height = clamp((pixfmt->height), min_height, max_height);
+
+	/* If interlaced, adjust height to be a multiple of 2 */
+	if (pixfmt->field == V4L2_FIELD_INTERLACED)
+		pixfmt->height &= (~1);
+	/*
+	 * recalculate bytesperline and sizeimage since width
+	 * and height might have changed
+	 */
+	pixfmt->bytesperline = (((pixfmt->width * vpfe_pix_fmt->bpp) + 31)
+				& ~31);
+	if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12)
+		pixfmt->sizeimage =
+			pixfmt->bytesperline * pixfmt->height +
+			((pixfmt->bytesperline * pixfmt->height) >> 1);
+	else
+		pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
+
+	v4l2_info(&vpfe_dev->v4l2_dev, "adjusted width = %d, height ="
+		 " %d, bpp = %d, bytesperline = %d, sizeimage = %d\n",
+		 pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp,
+		 pixfmt->bytesperline, pixfmt->sizeimage);
+	return vpfe_pix_fmt;
+}
+
+static int vpfe_querycap(struct file *file, void  *priv,
+			       struct v4l2_capability *cap)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n");
+
+	cap->version = VPFE_CAPTURE_VERSION_CODE;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+	strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
+	strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info));
+	strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card));
+	return 0;
+}
+
+static int vpfe_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	int ret = 0;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt_vid_cap\n");
+	/* Fill in the information about format */
+	*fmt = vpfe_dev->fmt;
+	return ret;
+}
+
+static int vpfe_enum_fmt_vid_cap(struct file *file, void  *priv,
+				   struct v4l2_fmtdesc *fmt)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	const struct vpfe_pixel_format *pix_fmt;
+	int temp_index;
+	u32 pix;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt_vid_cap\n");
+
+	if (ccdc_dev->hw_ops.enum_pix(&pix, fmt->index) < 0)
+		return -EINVAL;
+
+	/* Fill in the information about format */
+	pix_fmt = vpfe_lookup_pix_format(pix);
+	if (NULL != pix_fmt) {
+		temp_index = fmt->index;
+		*fmt = pix_fmt->fmtdesc;
+		fmt->index = temp_index;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int vpfe_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	const struct vpfe_pixel_format *pix_fmts;
+	int ret = 0;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt_vid_cap\n");
+
+	/* If streaming is started, return error */
+	if (vpfe_dev->started) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n");
+		return -EBUSY;
+	}
+
+	/* Check for valid frame format */
+	pix_fmts = vpfe_check_format(vpfe_dev, &fmt->fmt.pix);
+
+	if (NULL == pix_fmts)
+		return -EINVAL;
+
+	/* store the pixel format in the device  object */
+	ret = mutex_lock_interruptible(&vpfe_dev->lock);
+	if (ret)
+		return ret;
+
+	/* First detach any IRQ if currently attached */
+	vpfe_detach_irq(vpfe_dev);
+	vpfe_dev->fmt = *fmt;
+	/* set image capture parameters in the ccdc */
+	ret = vpfe_config_ccdc_image_format(vpfe_dev);
+	mutex_unlock(&vpfe_dev->lock);
+	return ret;
+}
+
+static int vpfe_try_fmt_vid_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	const struct vpfe_pixel_format *pix_fmts;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt_vid_cap\n");
+
+	pix_fmts = vpfe_check_format(vpfe_dev, &f->fmt.pix);
+	if (NULL == pix_fmts)
+		return -EINVAL;
+	return 0;
+}
+
+/*
+ * vpfe_get_subdev_input_index - Get subdev index and subdev input index for a
+ * given app input index
+ */
+static int vpfe_get_subdev_input_index(struct vpfe_device *vpfe_dev,
+					int *subdev_index,
+					int *subdev_input_index,
+					int app_input_index)
+{
+	struct vpfe_config *cfg = vpfe_dev->cfg;
+	struct vpfe_subdev_info *sdinfo;
+	int i, j = 0;
+
+	for (i = 0; i < cfg->num_subdevs; i++) {
+		sdinfo = &cfg->sub_devs[i];
+		if (app_input_index < (j + sdinfo->num_inputs)) {
+			*subdev_index = i;
+			*subdev_input_index = app_input_index - j;
+			return 0;
+		}
+		j += sdinfo->num_inputs;
+	}
+	return -EINVAL;
+}
+
+/*
+ * vpfe_get_app_input - Get app input index for a given subdev input index
+ * driver stores the input index of the current sub device and translate it
+ * when application request the current input
+ */
+static int vpfe_get_app_input_index(struct vpfe_device *vpfe_dev,
+				    int *app_input_index)
+{
+	struct vpfe_config *cfg = vpfe_dev->cfg;
+	struct vpfe_subdev_info *sdinfo;
+	int i, j = 0;
+
+	for (i = 0; i < cfg->num_subdevs; i++) {
+		sdinfo = &cfg->sub_devs[i];
+		if (!strcmp(sdinfo->name, vpfe_dev->current_subdev->name)) {
+			if (vpfe_dev->current_input >= sdinfo->num_inputs)
+				return -1;
+			*app_input_index = j + vpfe_dev->current_input;
+			return 0;
+		}
+		j += sdinfo->num_inputs;
+	}
+	return -EINVAL;
+}
+
+static int vpfe_enum_input(struct file *file, void *priv,
+				 struct v4l2_input *inp)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	struct vpfe_subdev_info *sdinfo;
+	int subdev, index ;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n");
+
+	if (vpfe_get_subdev_input_index(vpfe_dev,
+					&subdev,
+					&index,
+					inp->index) < 0) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "input information not found"
+			 " for the subdev\n");
+		return -EINVAL;
+	}
+	sdinfo = &vpfe_dev->cfg->sub_devs[subdev];
+	memcpy(inp, &sdinfo->inputs[index], sizeof(struct v4l2_input));
+	return 0;
+}
+
+static int vpfe_g_input(struct file *file, void *priv, unsigned int *index)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n");
+
+	return vpfe_get_app_input_index(vpfe_dev, index);
+}
+
+
+static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	struct vpfe_subdev_info *sdinfo;
+	int subdev_index, inp_index;
+	struct vpfe_route *route;
+	u32 input = 0, output = 0;
+	int ret = -EINVAL;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n");
+
+	ret = mutex_lock_interruptible(&vpfe_dev->lock);
+	if (ret)
+		return ret;
+
+	/*
+	 * If streaming is started return device busy
+	 * error
+	 */
+	if (vpfe_dev->started) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n");
+		ret = -EBUSY;
+		goto unlock_out;
+	}
+
+	if (vpfe_get_subdev_input_index(vpfe_dev,
+					&subdev_index,
+					&inp_index,
+					index) < 0) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "invalid input index\n");
+		goto unlock_out;
+	}
+
+	sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index];
+	route = &sdinfo->routes[inp_index];
+	if (route && sdinfo->can_route) {
+		input = route->input;
+		output = route->output;
+	}
+
+	ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+					 video, s_routing, input, output, 0);
+
+	if (ret) {
+		v4l2_err(&vpfe_dev->v4l2_dev,
+			"vpfe_doioctl:error in setting input in decoder\n");
+		ret = -EINVAL;
+		goto unlock_out;
+	}
+	vpfe_dev->current_subdev = sdinfo;
+	vpfe_dev->current_input = index;
+	vpfe_dev->std_index = 0;
+
+	/* set the bus/interface parameter for the sub device in ccdc */
+	ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params);
+	if (ret)
+		goto unlock_out;
+
+	/* set the default image parameters in the device */
+	ret = vpfe_config_image_format(vpfe_dev,
+				&vpfe_standards[vpfe_dev->std_index].std_id);
+unlock_out:
+	mutex_unlock(&vpfe_dev->lock);
+	return ret;
+}
+
+static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	struct vpfe_subdev_info *sdinfo;
+	int ret = 0;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n");
+
+	ret = mutex_lock_interruptible(&vpfe_dev->lock);
+	sdinfo = vpfe_dev->current_subdev;
+	if (ret)
+		return ret;
+	/* Call querystd function of decoder device */
+	ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+					 video, querystd, std_id);
+	mutex_unlock(&vpfe_dev->lock);
+	return ret;
+}
+
+static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	struct vpfe_subdev_info *sdinfo;
+	int ret = 0;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n");
+
+	/* Call decoder driver function to set the standard */
+	ret = mutex_lock_interruptible(&vpfe_dev->lock);
+	if (ret)
+		return ret;
+
+	sdinfo = vpfe_dev->current_subdev;
+	/* If streaming is started, return device busy error */
+	if (vpfe_dev->started) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n");
+		ret = -EBUSY;
+		goto unlock_out;
+	}
+
+	ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+					 core, s_std, *std_id);
+	if (ret < 0) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n");
+		goto unlock_out;
+	}
+	ret = vpfe_config_image_format(vpfe_dev, std_id);
+
+unlock_out:
+	mutex_unlock(&vpfe_dev->lock);
+	return ret;
+}
+
+static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n");
+
+	*std_id = vpfe_standards[vpfe_dev->std_index].std_id;
+	return 0;
+}
+/*
+ *  Videobuf operations
+ */
+static int vpfe_videobuf_setup(struct videobuf_queue *vq,
+				unsigned int *count,
+				unsigned int *size)
+{
+	struct vpfe_fh *fh = vq->priv_data;
+	struct vpfe_device *vpfe_dev = fh->vpfe_dev;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n");
+	*size = vpfe_dev->fmt.fmt.pix.sizeimage;
+	if (vpfe_dev->memory == V4L2_MEMORY_MMAP &&
+		vpfe_dev->fmt.fmt.pix.sizeimage > config_params.device_bufsize)
+		*size = config_params.device_bufsize;
+
+	if (*count < config_params.min_numbuffers)
+		*count = config_params.min_numbuffers;
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+		"count=%d, size=%d\n", *count, *size);
+	return 0;
+}
+
+static int vpfe_videobuf_prepare(struct videobuf_queue *vq,
+				struct videobuf_buffer *vb,
+				enum v4l2_field field)
+{
+	struct vpfe_fh *fh = vq->priv_data;
+	struct vpfe_device *vpfe_dev = fh->vpfe_dev;
+	unsigned long addr;
+	int ret;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n");
+
+	/* If buffer is not initialized, initialize it */
+	if (VIDEOBUF_NEEDS_INIT == vb->state) {
+		vb->width = vpfe_dev->fmt.fmt.pix.width;
+		vb->height = vpfe_dev->fmt.fmt.pix.height;
+		vb->size = vpfe_dev->fmt.fmt.pix.sizeimage;
+		vb->field = field;
+
+		ret = videobuf_iolock(vq, vb, NULL);
+		if (ret < 0)
+			return ret;
+
+		addr = videobuf_to_dma_contig(vb);
+		/* Make sure user addresses are aligned to 32 bytes */
+		if (!ALIGN(addr, 32))
+			return -EINVAL;
+
+		vb->state = VIDEOBUF_PREPARED;
+	}
+	return 0;
+}
+
+static void vpfe_videobuf_queue(struct videobuf_queue *vq,
+				struct videobuf_buffer *vb)
+{
+	/* Get the file handle object and device object */
+	struct vpfe_fh *fh = vq->priv_data;
+	struct vpfe_device *vpfe_dev = fh->vpfe_dev;
+	unsigned long flags;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_queue\n");
+
+	/* add the buffer to the DMA queue */
+	spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags);
+	list_add_tail(&vb->queue, &vpfe_dev->dma_queue);
+	spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags);
+
+	/* Change state of the buffer */
+	vb->state = VIDEOBUF_QUEUED;
+}
+
+static void vpfe_videobuf_release(struct videobuf_queue *vq,
+				  struct videobuf_buffer *vb)
+{
+	struct vpfe_fh *fh = vq->priv_data;
+	struct vpfe_device *vpfe_dev = fh->vpfe_dev;
+	unsigned long flags;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_release\n");
+
+	/*
+	 * We need to flush the buffer from the dma queue since
+	 * they are de-allocated
+	 */
+	spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags);
+	INIT_LIST_HEAD(&vpfe_dev->dma_queue);
+	spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags);
+	videobuf_dma_contig_free(vq, vb);
+	vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops vpfe_videobuf_qops = {
+	.buf_setup      = vpfe_videobuf_setup,
+	.buf_prepare    = vpfe_videobuf_prepare,
+	.buf_queue      = vpfe_videobuf_queue,
+	.buf_release    = vpfe_videobuf_release,
+};
+
+/*
+ * vpfe_reqbufs. currently support REQBUF only once opening
+ * the device.
+ */
+static int vpfe_reqbufs(struct file *file, void *priv,
+			struct v4l2_requestbuffers *req_buf)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	struct vpfe_fh *fh = file->private_data;
+	int ret = 0;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n");
+
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != req_buf->type) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n");
+		return -EINVAL;
+	}
+
+	ret = mutex_lock_interruptible(&vpfe_dev->lock);
+	if (ret)
+		return ret;
+
+	if (vpfe_dev->io_usrs != 0) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n");
+		ret = -EBUSY;
+		goto unlock_out;
+	}
+
+	vpfe_dev->memory = req_buf->memory;
+	videobuf_queue_dma_contig_init(&vpfe_dev->buffer_queue,
+				&vpfe_videobuf_qops,
+				vpfe_dev->pdev,
+				&vpfe_dev->irqlock,
+				req_buf->type,
+				vpfe_dev->fmt.fmt.pix.field,
+				sizeof(struct videobuf_buffer),
+				fh, NULL);
+
+	fh->io_allowed = 1;
+	vpfe_dev->io_usrs = 1;
+	INIT_LIST_HEAD(&vpfe_dev->dma_queue);
+	ret = videobuf_reqbufs(&vpfe_dev->buffer_queue, req_buf);
+unlock_out:
+	mutex_unlock(&vpfe_dev->lock);
+	return ret;
+}
+
+static int vpfe_querybuf(struct file *file, void *priv,
+			 struct v4l2_buffer *buf)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n");
+
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+		return  -EINVAL;
+	}
+
+	if (vpfe_dev->memory != V4L2_MEMORY_MMAP) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n");
+		return -EINVAL;
+	}
+	/* Call videobuf_querybuf to get information */
+	return videobuf_querybuf(&vpfe_dev->buffer_queue, buf);
+}
+
+static int vpfe_qbuf(struct file *file, void *priv,
+		     struct v4l2_buffer *p)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	struct vpfe_fh *fh = file->private_data;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n");
+
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * If this file handle is not allowed to do IO,
+	 * return error
+	 */
+	if (!fh->io_allowed) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
+		return -EACCES;
+	}
+	return videobuf_qbuf(&vpfe_dev->buffer_queue, p);
+}
+
+static int vpfe_dqbuf(struct file *file, void *priv,
+		      struct v4l2_buffer *buf)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n");
+
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+		return -EINVAL;
+	}
+	return videobuf_dqbuf(&vpfe_dev->buffer_queue,
+				      buf, file->f_flags & O_NONBLOCK);
+}
+
+static int vpfe_queryctrl(struct file *file, void *priv,
+		struct v4l2_queryctrl *qctrl)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	struct vpfe_subdev_info *sdinfo;
+
+	sdinfo = vpfe_dev->current_subdev;
+
+	return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+					 core, queryctrl, qctrl);
+
+}
+
+static int vpfe_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	struct vpfe_subdev_info *sdinfo;
+
+	sdinfo = vpfe_dev->current_subdev;
+
+	return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+					 core, g_ctrl, ctrl);
+}
+
+static int vpfe_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	struct vpfe_subdev_info *sdinfo;
+
+	sdinfo = vpfe_dev->current_subdev;
+
+	return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+					 core, s_ctrl, ctrl);
+}
+
+/*
+ * vpfe_calculate_offsets : This function calculates buffers offset
+ * for top and bottom field
+ */
+static void vpfe_calculate_offsets(struct vpfe_device *vpfe_dev)
+{
+	struct v4l2_rect image_win;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_calculate_offsets\n");
+
+	ccdc_dev->hw_ops.get_image_window(&image_win);
+	vpfe_dev->field_off = image_win.height * image_win.width;
+}
+
+/* vpfe_start_ccdc_capture: start streaming in ccdc/isif */
+static void vpfe_start_ccdc_capture(struct vpfe_device *vpfe_dev)
+{
+	ccdc_dev->hw_ops.enable(1);
+	if (ccdc_dev->hw_ops.enable_out_to_sdram)
+		ccdc_dev->hw_ops.enable_out_to_sdram(1);
+	vpfe_dev->started = 1;
+}
+
+/*
+ * vpfe_streamon. Assume the DMA queue is not empty.
+ * application is expected to call QBUF before calling
+ * this ioctl. If not, driver returns error
+ */
+static int vpfe_streamon(struct file *file, void *priv,
+			 enum v4l2_buf_type buf_type)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	struct vpfe_fh *fh = file->private_data;
+	struct vpfe_subdev_info *sdinfo;
+	unsigned long addr;
+	int ret = 0;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n");
+
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+		return -EINVAL;
+	}
+
+	/* If file handle is not allowed IO, return error */
+	if (!fh->io_allowed) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
+		return -EACCES;
+	}
+
+	sdinfo = vpfe_dev->current_subdev;
+	ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+					video, s_stream, 1);
+
+	if (ret && (ret != -ENOIOCTLCMD)) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "stream on failed in subdev\n");
+		return -EINVAL;
+	}
+
+	/* If buffer queue is empty, return error */
+	if (list_empty(&vpfe_dev->buffer_queue.stream)) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n");
+		return -EIO;
+	}
+
+	/* Call videobuf_streamon to start streaming * in videobuf */
+	ret = videobuf_streamon(&vpfe_dev->buffer_queue);
+	if (ret)
+		return ret;
+
+
+	ret = mutex_lock_interruptible(&vpfe_dev->lock);
+	if (ret)
+		goto streamoff;
+	/* Get the next frame from the buffer queue */
+	vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next,
+					struct videobuf_buffer, queue);
+	vpfe_dev->cur_frm = vpfe_dev->next_frm;
+	/* Remove buffer from the buffer queue */
+	list_del(&vpfe_dev->cur_frm->queue);
+	/* Mark state of the current frame to active */
+	vpfe_dev->cur_frm->state = VIDEOBUF_ACTIVE;
+	/* Initialize field_id and started member */
+	vpfe_dev->field_id = 0;
+	addr = videobuf_to_dma_contig(vpfe_dev->cur_frm);
+
+	/* Calculate field offset */
+	vpfe_calculate_offsets(vpfe_dev);
+
+	if (vpfe_attach_irq(vpfe_dev) < 0) {
+		v4l2_err(&vpfe_dev->v4l2_dev,
+			 "Error in attaching interrupt handle\n");
+		ret = -EFAULT;
+		goto unlock_out;
+	}
+	if (ccdc_dev->hw_ops.configure() < 0) {
+		v4l2_err(&vpfe_dev->v4l2_dev,
+			 "Error in configuring ccdc\n");
+		ret = -EINVAL;
+		goto unlock_out;
+	}
+	ccdc_dev->hw_ops.setfbaddr((unsigned long)(addr));
+	vpfe_start_ccdc_capture(vpfe_dev);
+	mutex_unlock(&vpfe_dev->lock);
+	return ret;
+unlock_out:
+	mutex_unlock(&vpfe_dev->lock);
+streamoff:
+	ret = videobuf_streamoff(&vpfe_dev->buffer_queue);
+	return ret;
+}
+
+static int vpfe_streamoff(struct file *file, void *priv,
+			  enum v4l2_buf_type buf_type)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	struct vpfe_fh *fh = file->private_data;
+	struct vpfe_subdev_info *sdinfo;
+	int ret = 0;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n");
+
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+		return -EINVAL;
+	}
+
+	/* If io is allowed for this file handle, return error */
+	if (!fh->io_allowed) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
+		return -EACCES;
+	}
+
+	/* If streaming is not started, return error */
+	if (!vpfe_dev->started) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "device started\n");
+		return -EINVAL;
+	}
+
+	ret = mutex_lock_interruptible(&vpfe_dev->lock);
+	if (ret)
+		return ret;
+
+	vpfe_stop_ccdc_capture(vpfe_dev);
+	vpfe_detach_irq(vpfe_dev);
+
+	sdinfo = vpfe_dev->current_subdev;
+	ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+					video, s_stream, 0);
+
+	if (ret && (ret != -ENOIOCTLCMD))
+		v4l2_err(&vpfe_dev->v4l2_dev, "stream off failed in subdev\n");
+	ret = videobuf_streamoff(&vpfe_dev->buffer_queue);
+	mutex_unlock(&vpfe_dev->lock);
+	return ret;
+}
+
+static int vpfe_cropcap(struct file *file, void *priv,
+			      struct v4l2_cropcap *crop)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n");
+
+	if (vpfe_dev->std_index >= ARRAY_SIZE(vpfe_standards))
+		return -EINVAL;
+
+	memset(crop, 0, sizeof(struct v4l2_cropcap));
+	crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	crop->bounds.width = crop->defrect.width =
+		vpfe_standards[vpfe_dev->std_index].width;
+	crop->bounds.height = crop->defrect.height =
+		vpfe_standards[vpfe_dev->std_index].height;
+	crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect;
+	return 0;
+}
+
+static int vpfe_g_crop(struct file *file, void *priv,
+			     struct v4l2_crop *crop)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_crop\n");
+
+	crop->c = vpfe_dev->crop;
+	return 0;
+}
+
+static int vpfe_s_crop(struct file *file, void *priv,
+			     struct v4l2_crop *crop)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	int ret = 0;
+
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_crop\n");
+
+	if (vpfe_dev->started) {
+		/* make sure streaming is not started */
+		v4l2_err(&vpfe_dev->v4l2_dev,
+			"Cannot change crop when streaming is ON\n");
+		return -EBUSY;
+	}
+
+	ret = mutex_lock_interruptible(&vpfe_dev->lock);
+	if (ret)
+		return ret;
+
+	if (crop->c.top < 0 || crop->c.left < 0) {
+		v4l2_err(&vpfe_dev->v4l2_dev,
+			"doesn't support negative values for top & left\n");
+		ret = -EINVAL;
+		goto unlock_out;
+	}
+
+	/* adjust the width to 16 pixel boundary */
+	crop->c.width = ((crop->c.width + 15) & ~0xf);
+
+	/* make sure parameters are valid */
+	if ((crop->c.left + crop->c.width >
+		vpfe_dev->std_info.active_pixels) ||
+	    (crop->c.top + crop->c.height >
+		vpfe_dev->std_info.active_lines)) {
+		v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_CROP params\n");
+		ret = -EINVAL;
+		goto unlock_out;
+	}
+	ccdc_dev->hw_ops.set_image_window(&crop->c);
+	vpfe_dev->fmt.fmt.pix.width = crop->c.width;
+	vpfe_dev->fmt.fmt.pix.height = crop->c.height;
+	vpfe_dev->fmt.fmt.pix.bytesperline =
+		ccdc_dev->hw_ops.get_line_length();
+	vpfe_dev->fmt.fmt.pix.sizeimage =
+		vpfe_dev->fmt.fmt.pix.bytesperline *
+		vpfe_dev->fmt.fmt.pix.height;
+	vpfe_dev->crop = crop->c;
+unlock_out:
+	mutex_unlock(&vpfe_dev->lock);
+	return ret;
+}
+
+
+static long vpfe_param_handler(struct file *file, void *priv,
+		bool valid_prio, int cmd, void *param)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	int ret = 0;
+
+	v4l2_dbg(2, debug, &vpfe_dev->v4l2_dev, "vpfe_param_handler\n");
+
+	if (vpfe_dev->started) {
+		/* only allowed if streaming is not started */
+		v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+			"device already started\n");
+		return -EBUSY;
+	}
+
+	ret = mutex_lock_interruptible(&vpfe_dev->lock);
+	if (ret)
+		return ret;
+
+	switch (cmd) {
+	case VPFE_CMD_S_CCDC_RAW_PARAMS:
+		v4l2_warn(&vpfe_dev->v4l2_dev,
+			  "VPFE_CMD_S_CCDC_RAW_PARAMS: experimental ioctl\n");
+		if (ccdc_dev->hw_ops.set_params) {
+			ret = ccdc_dev->hw_ops.set_params(param);
+			if (ret) {
+				v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+					"Error setting parameters in CCDC\n");
+				goto unlock_out;
+			}
+			if (vpfe_get_ccdc_image_format(vpfe_dev,
+						       &vpfe_dev->fmt) < 0) {
+				v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+					"Invalid image format at CCDC\n");
+				goto unlock_out;
+			}
+		} else {
+			ret = -EINVAL;
+			v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+				"VPFE_CMD_S_CCDC_RAW_PARAMS not supported\n");
+		}
+		break;
+	default:
+		ret = -ENOTTY;
+	}
+unlock_out:
+	mutex_unlock(&vpfe_dev->lock);
+	return ret;
+}
+
+
+/* vpfe capture ioctl operations */
+static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
+	.vidioc_querycap	 = vpfe_querycap,
+	.vidioc_g_fmt_vid_cap    = vpfe_g_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_cap = vpfe_enum_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap    = vpfe_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap  = vpfe_try_fmt_vid_cap,
+	.vidioc_enum_input	 = vpfe_enum_input,
+	.vidioc_g_input		 = vpfe_g_input,
+	.vidioc_s_input		 = vpfe_s_input,
+	.vidioc_querystd	 = vpfe_querystd,
+	.vidioc_s_std		 = vpfe_s_std,
+	.vidioc_g_std		 = vpfe_g_std,
+	.vidioc_queryctrl	 = vpfe_queryctrl,
+	.vidioc_g_ctrl		 = vpfe_g_ctrl,
+	.vidioc_s_ctrl		 = vpfe_s_ctrl,
+	.vidioc_reqbufs		 = vpfe_reqbufs,
+	.vidioc_querybuf	 = vpfe_querybuf,
+	.vidioc_qbuf		 = vpfe_qbuf,
+	.vidioc_dqbuf		 = vpfe_dqbuf,
+	.vidioc_streamon	 = vpfe_streamon,
+	.vidioc_streamoff	 = vpfe_streamoff,
+	.vidioc_cropcap		 = vpfe_cropcap,
+	.vidioc_g_crop		 = vpfe_g_crop,
+	.vidioc_s_crop		 = vpfe_s_crop,
+	.vidioc_default		 = vpfe_param_handler,
+};
+
+static struct vpfe_device *vpfe_initialize(void)
+{
+	struct vpfe_device *vpfe_dev;
+
+	/* Default number of buffers should be 3 */
+	if ((numbuffers > 0) &&
+	    (numbuffers < config_params.min_numbuffers))
+		numbuffers = config_params.min_numbuffers;
+
+	/*
+	 * Set buffer size to min buffers size if invalid buffer size is
+	 * given
+	 */
+	if (bufsize < config_params.min_bufsize)
+		bufsize = config_params.min_bufsize;
+
+	config_params.numbuffers = numbuffers;
+
+	if (numbuffers)
+		config_params.device_bufsize = bufsize;
+
+	/* Allocate memory for device objects */
+	vpfe_dev = kzalloc(sizeof(*vpfe_dev), GFP_KERNEL);
+
+	return vpfe_dev;
+}
+
+/*
+ * vpfe_probe : This function creates device entries by register
+ * itself to the V4L2 driver and initializes fields of each
+ * device objects
+ */
+static __devinit int vpfe_probe(struct platform_device *pdev)
+{
+	struct vpfe_subdev_info *sdinfo;
+	struct vpfe_config *vpfe_cfg;
+	struct resource *res1;
+	struct vpfe_device *vpfe_dev;
+	struct i2c_adapter *i2c_adap;
+	struct video_device *vfd;
+	int ret = -ENOMEM, i, j;
+	int num_subdevs = 0;
+
+	/* Get the pointer to the device object */
+	vpfe_dev = vpfe_initialize();
+
+	if (!vpfe_dev) {
+		v4l2_err(pdev->dev.driver,
+			"Failed to allocate memory for vpfe_dev\n");
+		return ret;
+	}
+
+	vpfe_dev->pdev = &pdev->dev;
+
+	if (NULL == pdev->dev.platform_data) {
+		v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n");
+		ret = -ENODEV;
+		goto probe_free_dev_mem;
+	}
+
+	vpfe_cfg = pdev->dev.platform_data;
+	vpfe_dev->cfg = vpfe_cfg;
+	if (NULL == vpfe_cfg->ccdc ||
+	    NULL == vpfe_cfg->card_name ||
+	    NULL == vpfe_cfg->sub_devs) {
+		v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n");
+		ret = -ENOENT;
+		goto probe_free_dev_mem;
+	}
+
+	/* Allocate memory for ccdc configuration */
+	ccdc_cfg = kmalloc(sizeof(struct ccdc_config), GFP_KERNEL);
+	if (NULL == ccdc_cfg) {
+		v4l2_err(pdev->dev.driver,
+			 "Memory allocation failed for ccdc_cfg\n");
+		goto probe_free_lock;
+	}
+
+	mutex_lock(&ccdc_lock);
+
+	strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32);
+	/* Get VINT0 irq resource */
+	res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res1) {
+		v4l2_err(pdev->dev.driver,
+			 "Unable to get interrupt for VINT0\n");
+		ret = -ENODEV;
+		goto probe_free_ccdc_cfg_mem;
+	}
+	vpfe_dev->ccdc_irq0 = res1->start;
+
+	/* Get VINT1 irq resource */
+	res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+	if (!res1) {
+		v4l2_err(pdev->dev.driver,
+			 "Unable to get interrupt for VINT1\n");
+		ret = -ENODEV;
+		goto probe_free_ccdc_cfg_mem;
+	}
+	vpfe_dev->ccdc_irq1 = res1->start;
+
+	ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, IRQF_DISABLED,
+			  "vpfe_capture0", vpfe_dev);
+
+	if (0 != ret) {
+		v4l2_err(pdev->dev.driver, "Unable to request interrupt\n");
+		goto probe_free_ccdc_cfg_mem;
+	}
+
+	/* Allocate memory for video device */
+	vfd = video_device_alloc();
+	if (NULL == vfd) {
+		ret = -ENOMEM;
+		v4l2_err(pdev->dev.driver, "Unable to alloc video device\n");
+		goto probe_out_release_irq;
+	}
+
+	/* Initialize field of video device */
+	vfd->release		= video_device_release;
+	vfd->fops		= &vpfe_fops;
+	vfd->ioctl_ops		= &vpfe_ioctl_ops;
+	vfd->tvnorms		= 0;
+	vfd->current_norm	= V4L2_STD_PAL;
+	vfd->v4l2_dev 		= &vpfe_dev->v4l2_dev;
+	snprintf(vfd->name, sizeof(vfd->name),
+		 "%s_V%d.%d.%d",
+		 CAPTURE_DRV_NAME,
+		 (VPFE_CAPTURE_VERSION_CODE >> 16) & 0xff,
+		 (VPFE_CAPTURE_VERSION_CODE >> 8) & 0xff,
+		 (VPFE_CAPTURE_VERSION_CODE) & 0xff);
+	/* Set video_dev to the video device */
+	vpfe_dev->video_dev	= vfd;
+
+	ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev);
+	if (ret) {
+		v4l2_err(pdev->dev.driver,
+			"Unable to register v4l2 device.\n");
+		goto probe_out_video_release;
+	}
+	v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n");
+	spin_lock_init(&vpfe_dev->irqlock);
+	spin_lock_init(&vpfe_dev->dma_queue_lock);
+	mutex_init(&vpfe_dev->lock);
+
+	/* Initialize field of the device objects */
+	vpfe_dev->numbuffers = config_params.numbuffers;
+
+	/* Initialize prio member of device object */
+	v4l2_prio_init(&vpfe_dev->prio);
+	/* register video device */
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+		"trying to register vpfe device.\n");
+	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+		"video_dev=%x\n", (int)&vpfe_dev->video_dev);
+	vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	ret = video_register_device(vpfe_dev->video_dev,
+				    VFL_TYPE_GRABBER, -1);
+
+	if (ret) {
+		v4l2_err(pdev->dev.driver,
+			"Unable to register video device.\n");
+		goto probe_out_v4l2_unregister;
+	}
+
+	v4l2_info(&vpfe_dev->v4l2_dev, "video device registered\n");
+	/* set the driver data in platform device */
+	platform_set_drvdata(pdev, vpfe_dev);
+	/* set driver private data */
+	video_set_drvdata(vpfe_dev->video_dev, vpfe_dev);
+	i2c_adap = i2c_get_adapter(vpfe_cfg->i2c_adapter_id);
+	num_subdevs = vpfe_cfg->num_subdevs;
+	vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs,
+				GFP_KERNEL);
+	if (NULL == vpfe_dev->sd) {
+		v4l2_err(&vpfe_dev->v4l2_dev,
+			"unable to allocate memory for subdevice pointers\n");
+		ret = -ENOMEM;
+		goto probe_out_video_unregister;
+	}
+
+	for (i = 0; i < num_subdevs; i++) {
+		struct v4l2_input *inps;
+
+		sdinfo = &vpfe_cfg->sub_devs[i];
+
+		/* Load up the subdevice */
+		vpfe_dev->sd[i] =
+			v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev,
+						  i2c_adap,
+						  &sdinfo->board_info,
+						  NULL);
+		if (vpfe_dev->sd[i]) {
+			v4l2_info(&vpfe_dev->v4l2_dev,
+				  "v4l2 sub device %s registered\n",
+				  sdinfo->name);
+			vpfe_dev->sd[i]->grp_id = sdinfo->grp_id;
+			/* update tvnorms from the sub devices */
+			for (j = 0; j < sdinfo->num_inputs; j++) {
+				inps = &sdinfo->inputs[j];
+				vfd->tvnorms |= inps->std;
+			}
+		} else {
+			v4l2_info(&vpfe_dev->v4l2_dev,
+				  "v4l2 sub device %s register fails\n",
+				  sdinfo->name);
+			goto probe_sd_out;
+		}
+	}
+
+	/* set first sub device as current one */
+	vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0];
+
+	/* We have at least one sub device to work with */
+	mutex_unlock(&ccdc_lock);
+	return 0;
+
+probe_sd_out:
+	kfree(vpfe_dev->sd);
+probe_out_video_unregister:
+	video_unregister_device(vpfe_dev->video_dev);
+probe_out_v4l2_unregister:
+	v4l2_device_unregister(&vpfe_dev->v4l2_dev);
+probe_out_video_release:
+	if (!video_is_registered(vpfe_dev->video_dev))
+		video_device_release(vpfe_dev->video_dev);
+probe_out_release_irq:
+	free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
+probe_free_ccdc_cfg_mem:
+	kfree(ccdc_cfg);
+probe_free_lock:
+	mutex_unlock(&ccdc_lock);
+probe_free_dev_mem:
+	kfree(vpfe_dev);
+	return ret;
+}
+
+/*
+ * vpfe_remove : It un-register device from V4L2 driver
+ */
+static int __devexit vpfe_remove(struct platform_device *pdev)
+{
+	struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev);
+
+	v4l2_info(pdev->dev.driver, "vpfe_remove\n");
+
+	free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
+	kfree(vpfe_dev->sd);
+	v4l2_device_unregister(&vpfe_dev->v4l2_dev);
+	video_unregister_device(vpfe_dev->video_dev);
+	kfree(vpfe_dev);
+	kfree(ccdc_cfg);
+	return 0;
+}
+
+static int vpfe_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int vpfe_resume(struct device *dev)
+{
+	return 0;
+}
+
+static const struct dev_pm_ops vpfe_dev_pm_ops = {
+	.suspend = vpfe_suspend,
+	.resume = vpfe_resume,
+};
+
+static struct platform_driver vpfe_driver = {
+	.driver = {
+		.name = CAPTURE_DRV_NAME,
+		.owner = THIS_MODULE,
+		.pm = &vpfe_dev_pm_ops,
+	},
+	.probe = vpfe_probe,
+	.remove = __devexit_p(vpfe_remove),
+};
+
+module_platform_driver(vpfe_driver);
diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c
new file mode 100644
index 0000000..9bd3caa
--- /dev/null
+++ b/drivers/media/platform/davinci/vpif.c
@@ -0,0 +1,514 @@
+/*
+ * vpif - Video Port Interface driver
+ * VPIF is a receiver and transmitter for video data. It has two channels(0, 1)
+ * that receiveing video byte stream and two channels(2, 3) for video output.
+ * The hardware supports SDTV, HDTV formats, raw data capture.
+ * Currently, the driver supports NTSC and PAL standards.
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <mach/hardware.h>
+
+#include "vpif.h"
+
+MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver");
+MODULE_LICENSE("GPL");
+
+#define VPIF_CH0_MAX_MODES	(22)
+#define VPIF_CH1_MAX_MODES	(02)
+#define VPIF_CH2_MAX_MODES	(15)
+#define VPIF_CH3_MAX_MODES	(02)
+
+static resource_size_t	res_len;
+static struct resource	*res;
+spinlock_t vpif_lock;
+
+void __iomem *vpif_base;
+struct clk *vpif_clk;
+
+/**
+ * ch_params: video standard configuration parameters for vpif
+ * The table must include all presets from supported subdevices.
+ */
+const struct vpif_channel_config_params ch_params[] = {
+	/* HDTV formats */
+	{
+		.name = "480p59_94",
+		.width = 720,
+		.height = 480,
+		.frm_fmt = 1,
+		.ycmux_mode = 0,
+		.eav2sav = 138-8,
+		.sav2eav = 720,
+		.l1 = 1,
+		.l3 = 43,
+		.l5 = 523,
+		.vsize = 525,
+		.capture_format = 0,
+		.vbi_supported = 0,
+		.hd_sd = 1,
+		.dv_preset = V4L2_DV_480P59_94,
+	},
+	{
+		.name = "576p50",
+		.width = 720,
+		.height = 576,
+		.frm_fmt = 1,
+		.ycmux_mode = 0,
+		.eav2sav = 144-8,
+		.sav2eav = 720,
+		.l1 = 1,
+		.l3 = 45,
+		.l5 = 621,
+		.vsize = 625,
+		.capture_format = 0,
+		.vbi_supported = 0,
+		.hd_sd = 1,
+		.dv_preset = V4L2_DV_576P50,
+	},
+	{
+		.name = "720p50",
+		.width = 1280,
+		.height = 720,
+		.frm_fmt = 1,
+		.ycmux_mode = 0,
+		.eav2sav = 700-8,
+		.sav2eav = 1280,
+		.l1 = 1,
+		.l3 = 26,
+		.l5 = 746,
+		.vsize = 750,
+		.capture_format = 0,
+		.vbi_supported = 0,
+		.hd_sd = 1,
+		.dv_preset = V4L2_DV_720P50,
+	},
+	{
+		.name = "720p60",
+		.width = 1280,
+		.height = 720,
+		.frm_fmt = 1,
+		.ycmux_mode = 0,
+		.eav2sav = 370 - 8,
+		.sav2eav = 1280,
+		.l1 = 1,
+		.l3 = 26,
+		.l5 = 746,
+		.vsize = 750,
+		.capture_format = 0,
+		.vbi_supported = 0,
+		.hd_sd = 1,
+		.dv_preset = V4L2_DV_720P60,
+	},
+	{
+		.name = "1080I50",
+		.width = 1920,
+		.height = 1080,
+		.frm_fmt = 0,
+		.ycmux_mode = 0,
+		.eav2sav = 720 - 8,
+		.sav2eav = 1920,
+		.l1 = 1,
+		.l3 = 21,
+		.l5 = 561,
+		.l7 = 563,
+		.l9 = 584,
+		.l11 = 1124,
+		.vsize = 1125,
+		.capture_format = 0,
+		.vbi_supported = 0,
+		.hd_sd = 1,
+		.dv_preset = V4L2_DV_1080I50,
+	},
+	{
+		.name = "1080I60",
+		.width = 1920,
+		.height = 1080,
+		.frm_fmt = 0,
+		.ycmux_mode = 0,
+		.eav2sav = 280 - 8,
+		.sav2eav = 1920,
+		.l1 = 1,
+		.l3 = 21,
+		.l5 = 561,
+		.l7 = 563,
+		.l9 = 584,
+		.l11 = 1124,
+		.vsize = 1125,
+		.capture_format = 0,
+		.vbi_supported = 0,
+		.hd_sd = 1,
+		.dv_preset = V4L2_DV_1080I60,
+	},
+	{
+		.name = "1080p60",
+		.width = 1920,
+		.height = 1080,
+		.frm_fmt = 1,
+		.ycmux_mode = 0,
+		.eav2sav = 280 - 8,
+		.sav2eav = 1920,
+		.l1 = 1,
+		.l3 = 42,
+		.l5 = 1122,
+		.vsize = 1125,
+		.capture_format = 0,
+		.vbi_supported = 0,
+		.hd_sd = 1,
+		.dv_preset = V4L2_DV_1080P60,
+	},
+
+	/* SDTV formats */
+	{
+		.name = "NTSC_M",
+		.width = 720,
+		.height = 480,
+		.frm_fmt = 0,
+		.ycmux_mode = 1,
+		.eav2sav = 268,
+		.sav2eav = 1440,
+		.l1 = 1,
+		.l3 = 23,
+		.l5 = 263,
+		.l7 = 266,
+		.l9 = 286,
+		.l11 = 525,
+		.vsize = 525,
+		.capture_format = 0,
+		.vbi_supported = 1,
+		.hd_sd = 0,
+		.stdid = V4L2_STD_525_60,
+	},
+	{
+		.name = "PAL_BDGHIK",
+		.width = 720,
+		.height = 576,
+		.frm_fmt = 0,
+		.ycmux_mode = 1,
+		.eav2sav = 280,
+		.sav2eav = 1440,
+		.l1 = 1,
+		.l3 = 23,
+		.l5 = 311,
+		.l7 = 313,
+		.l9 = 336,
+		.l11 = 624,
+		.vsize = 625,
+		.capture_format = 0,
+		.vbi_supported = 1,
+		.hd_sd = 0,
+		.stdid = V4L2_STD_625_50,
+	},
+};
+
+const unsigned int vpif_ch_params_count = ARRAY_SIZE(ch_params);
+
+static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val)
+{
+	if (val)
+		vpif_set_bit(reg, bit);
+	else
+		vpif_clr_bit(reg, bit);
+}
+
+/* This structure is used to keep track of VPIF size register's offsets */
+struct vpif_registers {
+	u32 h_cfg, v_cfg_00, v_cfg_01, v_cfg_02, v_cfg, ch_ctrl;
+	u32 line_offset, vanc0_strt, vanc0_size, vanc1_strt;
+	u32 vanc1_size, width_mask, len_mask;
+	u8 max_modes;
+};
+
+static const struct vpif_registers vpifregs[VPIF_NUM_CHANNELS] = {
+	/* Channel0 */
+	{
+		VPIF_CH0_H_CFG, VPIF_CH0_V_CFG_00, VPIF_CH0_V_CFG_01,
+		VPIF_CH0_V_CFG_02, VPIF_CH0_V_CFG_03, VPIF_CH0_CTRL,
+		VPIF_CH0_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF,
+		VPIF_CH0_MAX_MODES,
+	},
+	/* Channel1 */
+	{
+		VPIF_CH1_H_CFG, VPIF_CH1_V_CFG_00, VPIF_CH1_V_CFG_01,
+		VPIF_CH1_V_CFG_02, VPIF_CH1_V_CFG_03, VPIF_CH1_CTRL,
+		VPIF_CH1_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF,
+		VPIF_CH1_MAX_MODES,
+	},
+	/* Channel2 */
+	{
+		VPIF_CH2_H_CFG, VPIF_CH2_V_CFG_00, VPIF_CH2_V_CFG_01,
+		VPIF_CH2_V_CFG_02, VPIF_CH2_V_CFG_03, VPIF_CH2_CTRL,
+		VPIF_CH2_IMG_ADD_OFST, VPIF_CH2_VANC0_STRT, VPIF_CH2_VANC0_SIZE,
+		VPIF_CH2_VANC1_STRT, VPIF_CH2_VANC1_SIZE, 0x7FF, 0x7FF,
+		VPIF_CH2_MAX_MODES
+	},
+	/* Channel3 */
+	{
+		VPIF_CH3_H_CFG, VPIF_CH3_V_CFG_00, VPIF_CH3_V_CFG_01,
+		VPIF_CH3_V_CFG_02, VPIF_CH3_V_CFG_03, VPIF_CH3_CTRL,
+		VPIF_CH3_IMG_ADD_OFST, VPIF_CH3_VANC0_STRT, VPIF_CH3_VANC0_SIZE,
+		VPIF_CH3_VANC1_STRT, VPIF_CH3_VANC1_SIZE, 0x7FF, 0x7FF,
+		VPIF_CH3_MAX_MODES
+	},
+};
+
+/* vpif_set_mode_info:
+ * This function is used to set horizontal and vertical config parameters
+ * As per the standard in the channel, configure the values of L1, L3,
+ * L5, L7  L9, L11 in VPIF Register , also write width and height
+ */
+static void vpif_set_mode_info(const struct vpif_channel_config_params *config,
+				u8 channel_id, u8 config_channel_id)
+{
+	u32 value;
+
+	value = (config->eav2sav & vpifregs[config_channel_id].width_mask);
+	value <<= VPIF_CH_LEN_SHIFT;
+	value |= (config->sav2eav & vpifregs[config_channel_id].width_mask);
+	regw(value, vpifregs[channel_id].h_cfg);
+
+	value = (config->l1 & vpifregs[config_channel_id].len_mask);
+	value <<= VPIF_CH_LEN_SHIFT;
+	value |= (config->l3 & vpifregs[config_channel_id].len_mask);
+	regw(value, vpifregs[channel_id].v_cfg_00);
+
+	value = (config->l5 & vpifregs[config_channel_id].len_mask);
+	value <<= VPIF_CH_LEN_SHIFT;
+	value |= (config->l7 & vpifregs[config_channel_id].len_mask);
+	regw(value, vpifregs[channel_id].v_cfg_01);
+
+	value = (config->l9 & vpifregs[config_channel_id].len_mask);
+	value <<= VPIF_CH_LEN_SHIFT;
+	value |= (config->l11 & vpifregs[config_channel_id].len_mask);
+	regw(value, vpifregs[channel_id].v_cfg_02);
+
+	value = (config->vsize & vpifregs[config_channel_id].len_mask);
+	regw(value, vpifregs[channel_id].v_cfg);
+}
+
+/* config_vpif_params
+ * Function to set the parameters of a channel
+ * Mainly modifies the channel ciontrol register
+ * It sets frame format, yc mux mode
+ */
+static void config_vpif_params(struct vpif_params *vpifparams,
+				u8 channel_id, u8 found)
+{
+	const struct vpif_channel_config_params *config = &vpifparams->std_info;
+	u32 value, ch_nip, reg;
+	u8 start, end;
+	int i;
+
+	start = channel_id;
+	end = channel_id + found;
+
+	for (i = start; i < end; i++) {
+		reg = vpifregs[i].ch_ctrl;
+		if (channel_id < 2)
+			ch_nip = VPIF_CAPTURE_CH_NIP;
+		else
+			ch_nip = VPIF_DISPLAY_CH_NIP;
+
+		vpif_wr_bit(reg, ch_nip, config->frm_fmt);
+		vpif_wr_bit(reg, VPIF_CH_YC_MUX_BIT, config->ycmux_mode);
+		vpif_wr_bit(reg, VPIF_CH_INPUT_FIELD_FRAME_BIT,
+					vpifparams->video_params.storage_mode);
+
+		/* Set raster scanning SDR Format */
+		vpif_clr_bit(reg, VPIF_CH_SDR_FMT_BIT);
+		vpif_wr_bit(reg, VPIF_CH_DATA_MODE_BIT, config->capture_format);
+
+		if (channel_id > 1)	/* Set the Pixel enable bit */
+			vpif_set_bit(reg, VPIF_DISPLAY_PIX_EN_BIT);
+		else if (config->capture_format) {
+			/* Set the polarity of various pins */
+			vpif_wr_bit(reg, VPIF_CH_FID_POLARITY_BIT,
+					vpifparams->iface.fid_pol);
+			vpif_wr_bit(reg, VPIF_CH_V_VALID_POLARITY_BIT,
+					vpifparams->iface.vd_pol);
+			vpif_wr_bit(reg, VPIF_CH_H_VALID_POLARITY_BIT,
+					vpifparams->iface.hd_pol);
+
+			value = regr(reg);
+			/* Set data width */
+			value &= ~(0x3u <<
+					VPIF_CH_DATA_WIDTH_BIT);
+			value |= ((vpifparams->params.data_sz) <<
+						     VPIF_CH_DATA_WIDTH_BIT);
+			regw(value, reg);
+		}
+
+		/* Write the pitch in the driver */
+		regw((vpifparams->video_params.hpitch),
+						vpifregs[i].line_offset);
+	}
+}
+
+/* vpif_set_video_params
+ * This function is used to set video parameters in VPIF register
+ */
+int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id)
+{
+	const struct vpif_channel_config_params *config = &vpifparams->std_info;
+	int found = 1;
+
+	vpif_set_mode_info(config, channel_id, channel_id);
+	if (!config->ycmux_mode) {
+		/* YC are on separate channels (HDTV formats) */
+		vpif_set_mode_info(config, channel_id + 1, channel_id);
+		found = 2;
+	}
+
+	config_vpif_params(vpifparams, channel_id, found);
+
+	regw(0x80, VPIF_REQ_SIZE);
+	regw(0x01, VPIF_EMULATION_CTRL);
+
+	return found;
+}
+EXPORT_SYMBOL(vpif_set_video_params);
+
+void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams,
+				u8 channel_id)
+{
+	u32 value;
+
+	value = 0x3F8 & (vbiparams->hstart0);
+	value |= 0x3FFFFFF & ((vbiparams->vstart0) << 16);
+	regw(value, vpifregs[channel_id].vanc0_strt);
+
+	value = 0x3F8 & (vbiparams->hstart1);
+	value |= 0x3FFFFFF & ((vbiparams->vstart1) << 16);
+	regw(value, vpifregs[channel_id].vanc1_strt);
+
+	value = 0x3F8 & (vbiparams->hsize0);
+	value |= 0x3FFFFFF & ((vbiparams->vsize0) << 16);
+	regw(value, vpifregs[channel_id].vanc0_size);
+
+	value = 0x3F8 & (vbiparams->hsize1);
+	value |= 0x3FFFFFF & ((vbiparams->vsize1) << 16);
+	regw(value, vpifregs[channel_id].vanc1_size);
+
+}
+EXPORT_SYMBOL(vpif_set_vbi_display_params);
+
+int vpif_channel_getfid(u8 channel_id)
+{
+	return (regr(vpifregs[channel_id].ch_ctrl) & VPIF_CH_FID_MASK)
+					>> VPIF_CH_FID_SHIFT;
+}
+EXPORT_SYMBOL(vpif_channel_getfid);
+
+static int __devinit vpif_probe(struct platform_device *pdev)
+{
+	int status = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENOENT;
+
+	res_len = resource_size(res);
+
+	res = request_mem_region(res->start, res_len, res->name);
+	if (!res)
+		return -EBUSY;
+
+	vpif_base = ioremap(res->start, res_len);
+	if (!vpif_base) {
+		status = -EBUSY;
+		goto fail;
+	}
+
+	vpif_clk = clk_get(&pdev->dev, "vpif");
+	if (IS_ERR(vpif_clk)) {
+		status = PTR_ERR(vpif_clk);
+		goto clk_fail;
+	}
+	clk_enable(vpif_clk);
+
+	spin_lock_init(&vpif_lock);
+	dev_info(&pdev->dev, "vpif probe success\n");
+	return 0;
+
+clk_fail:
+	iounmap(vpif_base);
+fail:
+	release_mem_region(res->start, res_len);
+	return status;
+}
+
+static int __devexit vpif_remove(struct platform_device *pdev)
+{
+	if (vpif_clk) {
+		clk_disable(vpif_clk);
+		clk_put(vpif_clk);
+	}
+
+	iounmap(vpif_base);
+	release_mem_region(res->start, res_len);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int vpif_suspend(struct device *dev)
+{
+	clk_disable(vpif_clk);
+	return 0;
+}
+
+static int vpif_resume(struct device *dev)
+{
+	clk_enable(vpif_clk);
+	return 0;
+}
+
+static const struct dev_pm_ops vpif_pm = {
+	.suspend        = vpif_suspend,
+	.resume         = vpif_resume,
+};
+
+#define vpif_pm_ops (&vpif_pm)
+#else
+#define vpif_pm_ops NULL
+#endif
+
+static struct platform_driver vpif_driver = {
+	.driver = {
+		.name	= "vpif",
+		.owner = THIS_MODULE,
+		.pm	= vpif_pm_ops,
+	},
+	.remove = __devexit_p(vpif_remove),
+	.probe = vpif_probe,
+};
+
+static void vpif_exit(void)
+{
+	platform_driver_unregister(&vpif_driver);
+}
+
+static int __init vpif_init(void)
+{
+	return platform_driver_register(&vpif_driver);
+}
+subsys_initcall(vpif_init);
+module_exit(vpif_exit);
+
diff --git a/drivers/media/platform/davinci/vpif.h b/drivers/media/platform/davinci/vpif.h
new file mode 100644
index 0000000..c2ce4d9
--- /dev/null
+++ b/drivers/media/platform/davinci/vpif.h
@@ -0,0 +1,688 @@
+/*
+ * VPIF header file
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef VPIF_H
+#define VPIF_H
+
+#include <linux/io.h>
+#include <linux/videodev2.h>
+#include <media/davinci/vpif_types.h>
+
+/* Maximum channel allowed */
+#define VPIF_NUM_CHANNELS		(4)
+#define VPIF_CAPTURE_NUM_CHANNELS	(2)
+#define VPIF_DISPLAY_NUM_CHANNELS	(2)
+
+/* Macros to read/write registers */
+extern void __iomem *vpif_base;
+extern spinlock_t vpif_lock;
+
+#define regr(reg)               readl((reg) + vpif_base)
+#define regw(value, reg)        writel(value, (reg + vpif_base))
+
+/* Register Address Offsets */
+#define VPIF_PID			(0x0000)
+#define VPIF_CH0_CTRL			(0x0004)
+#define VPIF_CH1_CTRL			(0x0008)
+#define VPIF_CH2_CTRL			(0x000C)
+#define VPIF_CH3_CTRL			(0x0010)
+
+#define VPIF_INTEN			(0x0020)
+#define VPIF_INTEN_SET			(0x0024)
+#define VPIF_INTEN_CLR			(0x0028)
+#define VPIF_STATUS			(0x002C)
+#define VPIF_STATUS_CLR			(0x0030)
+#define VPIF_EMULATION_CTRL		(0x0034)
+#define VPIF_REQ_SIZE			(0x0038)
+
+#define VPIF_CH0_TOP_STRT_ADD_LUMA	(0x0040)
+#define VPIF_CH0_BTM_STRT_ADD_LUMA	(0x0044)
+#define VPIF_CH0_TOP_STRT_ADD_CHROMA	(0x0048)
+#define VPIF_CH0_BTM_STRT_ADD_CHROMA	(0x004c)
+#define VPIF_CH0_TOP_STRT_ADD_HANC	(0x0050)
+#define VPIF_CH0_BTM_STRT_ADD_HANC	(0x0054)
+#define VPIF_CH0_TOP_STRT_ADD_VANC	(0x0058)
+#define VPIF_CH0_BTM_STRT_ADD_VANC	(0x005c)
+#define VPIF_CH0_SP_CFG			(0x0060)
+#define VPIF_CH0_IMG_ADD_OFST		(0x0064)
+#define VPIF_CH0_HANC_ADD_OFST		(0x0068)
+#define VPIF_CH0_H_CFG			(0x006c)
+#define VPIF_CH0_V_CFG_00		(0x0070)
+#define VPIF_CH0_V_CFG_01		(0x0074)
+#define VPIF_CH0_V_CFG_02		(0x0078)
+#define VPIF_CH0_V_CFG_03		(0x007c)
+
+#define VPIF_CH1_TOP_STRT_ADD_LUMA	(0x0080)
+#define VPIF_CH1_BTM_STRT_ADD_LUMA	(0x0084)
+#define VPIF_CH1_TOP_STRT_ADD_CHROMA	(0x0088)
+#define VPIF_CH1_BTM_STRT_ADD_CHROMA	(0x008c)
+#define VPIF_CH1_TOP_STRT_ADD_HANC	(0x0090)
+#define VPIF_CH1_BTM_STRT_ADD_HANC	(0x0094)
+#define VPIF_CH1_TOP_STRT_ADD_VANC	(0x0098)
+#define VPIF_CH1_BTM_STRT_ADD_VANC	(0x009c)
+#define VPIF_CH1_SP_CFG			(0x00a0)
+#define VPIF_CH1_IMG_ADD_OFST		(0x00a4)
+#define VPIF_CH1_HANC_ADD_OFST		(0x00a8)
+#define VPIF_CH1_H_CFG			(0x00ac)
+#define VPIF_CH1_V_CFG_00		(0x00b0)
+#define VPIF_CH1_V_CFG_01		(0x00b4)
+#define VPIF_CH1_V_CFG_02		(0x00b8)
+#define VPIF_CH1_V_CFG_03		(0x00bc)
+
+#define VPIF_CH2_TOP_STRT_ADD_LUMA	(0x00c0)
+#define VPIF_CH2_BTM_STRT_ADD_LUMA	(0x00c4)
+#define VPIF_CH2_TOP_STRT_ADD_CHROMA	(0x00c8)
+#define VPIF_CH2_BTM_STRT_ADD_CHROMA	(0x00cc)
+#define VPIF_CH2_TOP_STRT_ADD_HANC	(0x00d0)
+#define VPIF_CH2_BTM_STRT_ADD_HANC	(0x00d4)
+#define VPIF_CH2_TOP_STRT_ADD_VANC	(0x00d8)
+#define VPIF_CH2_BTM_STRT_ADD_VANC	(0x00dc)
+#define VPIF_CH2_SP_CFG			(0x00e0)
+#define VPIF_CH2_IMG_ADD_OFST		(0x00e4)
+#define VPIF_CH2_HANC_ADD_OFST		(0x00e8)
+#define VPIF_CH2_H_CFG			(0x00ec)
+#define VPIF_CH2_V_CFG_00		(0x00f0)
+#define VPIF_CH2_V_CFG_01		(0x00f4)
+#define VPIF_CH2_V_CFG_02		(0x00f8)
+#define VPIF_CH2_V_CFG_03		(0x00fc)
+#define VPIF_CH2_HANC0_STRT		(0x0100)
+#define VPIF_CH2_HANC0_SIZE		(0x0104)
+#define VPIF_CH2_HANC1_STRT		(0x0108)
+#define VPIF_CH2_HANC1_SIZE		(0x010c)
+#define VPIF_CH2_VANC0_STRT		(0x0110)
+#define VPIF_CH2_VANC0_SIZE		(0x0114)
+#define VPIF_CH2_VANC1_STRT		(0x0118)
+#define VPIF_CH2_VANC1_SIZE		(0x011c)
+
+#define VPIF_CH3_TOP_STRT_ADD_LUMA	(0x0140)
+#define VPIF_CH3_BTM_STRT_ADD_LUMA	(0x0144)
+#define VPIF_CH3_TOP_STRT_ADD_CHROMA	(0x0148)
+#define VPIF_CH3_BTM_STRT_ADD_CHROMA	(0x014c)
+#define VPIF_CH3_TOP_STRT_ADD_HANC	(0x0150)
+#define VPIF_CH3_BTM_STRT_ADD_HANC	(0x0154)
+#define VPIF_CH3_TOP_STRT_ADD_VANC	(0x0158)
+#define VPIF_CH3_BTM_STRT_ADD_VANC	(0x015c)
+#define VPIF_CH3_SP_CFG			(0x0160)
+#define VPIF_CH3_IMG_ADD_OFST		(0x0164)
+#define VPIF_CH3_HANC_ADD_OFST		(0x0168)
+#define VPIF_CH3_H_CFG			(0x016c)
+#define VPIF_CH3_V_CFG_00		(0x0170)
+#define VPIF_CH3_V_CFG_01		(0x0174)
+#define VPIF_CH3_V_CFG_02		(0x0178)
+#define VPIF_CH3_V_CFG_03		(0x017c)
+#define VPIF_CH3_HANC0_STRT		(0x0180)
+#define VPIF_CH3_HANC0_SIZE		(0x0184)
+#define VPIF_CH3_HANC1_STRT		(0x0188)
+#define VPIF_CH3_HANC1_SIZE		(0x018c)
+#define VPIF_CH3_VANC0_STRT		(0x0190)
+#define VPIF_CH3_VANC0_SIZE		(0x0194)
+#define VPIF_CH3_VANC1_STRT		(0x0198)
+#define VPIF_CH3_VANC1_SIZE		(0x019c)
+
+#define VPIF_IODFT_CTRL			(0x01c0)
+
+/* Functions for bit Manipulation */
+static inline void vpif_set_bit(u32 reg, u32 bit)
+{
+	regw((regr(reg)) | (0x01 << bit), reg);
+}
+
+static inline void vpif_clr_bit(u32 reg, u32 bit)
+{
+	regw(((regr(reg)) & ~(0x01 << bit)), reg);
+}
+
+/* Macro for Generating mask */
+#ifdef GENERATE_MASK
+#undef GENERATE_MASK
+#endif
+
+#define GENERATE_MASK(bits, pos) \
+		((((0xFFFFFFFF) << (32 - bits)) >> (32 - bits)) << pos)
+
+/* Bit positions in the channel control registers */
+#define VPIF_CH_DATA_MODE_BIT	(2)
+#define VPIF_CH_YC_MUX_BIT	(3)
+#define VPIF_CH_SDR_FMT_BIT	(4)
+#define VPIF_CH_HANC_EN_BIT	(8)
+#define VPIF_CH_VANC_EN_BIT	(9)
+
+#define VPIF_CAPTURE_CH_NIP	(10)
+#define VPIF_DISPLAY_CH_NIP	(11)
+
+#define VPIF_DISPLAY_PIX_EN_BIT	(10)
+
+#define VPIF_CH_INPUT_FIELD_FRAME_BIT	(12)
+
+#define VPIF_CH_FID_POLARITY_BIT	(15)
+#define VPIF_CH_V_VALID_POLARITY_BIT	(14)
+#define VPIF_CH_H_VALID_POLARITY_BIT	(13)
+#define VPIF_CH_DATA_WIDTH_BIT		(28)
+
+#define VPIF_CH_CLK_EDGE_CTRL_BIT	(31)
+
+/* Mask various length */
+#define VPIF_CH_EAVSAV_MASK	GENERATE_MASK(13, 0)
+#define VPIF_CH_LEN_MASK	GENERATE_MASK(12, 0)
+#define VPIF_CH_WIDTH_MASK	GENERATE_MASK(13, 0)
+#define VPIF_CH_LEN_SHIFT	(16)
+
+/* VPIF masks for registers */
+#define VPIF_REQ_SIZE_MASK	(0x1ff)
+
+/* bit posotion of interrupt vpif_ch_intr register */
+#define VPIF_INTEN_FRAME_CH0	(0x00000001)
+#define VPIF_INTEN_FRAME_CH1	(0x00000002)
+#define VPIF_INTEN_FRAME_CH2	(0x00000004)
+#define VPIF_INTEN_FRAME_CH3	(0x00000008)
+
+/* bit position of clock and channel enable in vpif_chn_ctrl register */
+
+#define VPIF_CH0_CLK_EN		(0x00000002)
+#define VPIF_CH0_EN		(0x00000001)
+#define VPIF_CH1_CLK_EN		(0x00000002)
+#define VPIF_CH1_EN		(0x00000001)
+#define VPIF_CH2_CLK_EN		(0x00000002)
+#define VPIF_CH2_EN		(0x00000001)
+#define VPIF_CH3_CLK_EN		(0x00000002)
+#define VPIF_CH3_EN		(0x00000001)
+#define VPIF_CH_CLK_EN		(0x00000002)
+#define VPIF_CH_EN		(0x00000001)
+
+#define VPIF_INT_TOP	(0x00)
+#define VPIF_INT_BOTTOM	(0x01)
+#define VPIF_INT_BOTH	(0x02)
+
+#define VPIF_CH0_INT_CTRL_SHIFT	(6)
+#define VPIF_CH1_INT_CTRL_SHIFT	(6)
+#define VPIF_CH2_INT_CTRL_SHIFT	(6)
+#define VPIF_CH3_INT_CTRL_SHIFT	(6)
+#define VPIF_CH_INT_CTRL_SHIFT	(6)
+
+#define VPIF_CH2_CLIP_ANC_EN	14
+#define VPIF_CH2_CLIP_ACTIVE_EN	13
+
+#define VPIF_CH3_CLIP_ANC_EN	14
+#define VPIF_CH3_CLIP_ACTIVE_EN	13
+
+/* enabled interrupt on both the fields on vpid_ch0_ctrl register */
+#define channel0_intr_assert()	(regw((regr(VPIF_CH0_CTRL)|\
+	(VPIF_INT_BOTH << VPIF_CH0_INT_CTRL_SHIFT)), VPIF_CH0_CTRL))
+
+/* enabled interrupt on both the fields on vpid_ch1_ctrl register */
+#define channel1_intr_assert()	(regw((regr(VPIF_CH1_CTRL)|\
+	(VPIF_INT_BOTH << VPIF_CH1_INT_CTRL_SHIFT)), VPIF_CH1_CTRL))
+
+/* enabled interrupt on both the fields on vpid_ch0_ctrl register */
+#define channel2_intr_assert() 	(regw((regr(VPIF_CH2_CTRL)|\
+	(VPIF_INT_BOTH << VPIF_CH2_INT_CTRL_SHIFT)), VPIF_CH2_CTRL))
+
+/* enabled interrupt on both the fields on vpid_ch1_ctrl register */
+#define channel3_intr_assert() 	(regw((regr(VPIF_CH3_CTRL)|\
+	(VPIF_INT_BOTH << VPIF_CH3_INT_CTRL_SHIFT)), VPIF_CH3_CTRL))
+
+#define VPIF_CH_FID_MASK	(0x20)
+#define VPIF_CH_FID_SHIFT	(5)
+
+#define VPIF_NTSC_VBI_START_FIELD0	(1)
+#define VPIF_NTSC_VBI_START_FIELD1	(263)
+#define VPIF_PAL_VBI_START_FIELD0	(624)
+#define VPIF_PAL_VBI_START_FIELD1	(311)
+
+#define VPIF_NTSC_HBI_START_FIELD0	(1)
+#define VPIF_NTSC_HBI_START_FIELD1	(263)
+#define VPIF_PAL_HBI_START_FIELD0	(624)
+#define VPIF_PAL_HBI_START_FIELD1	(311)
+
+#define VPIF_NTSC_VBI_COUNT_FIELD0	(20)
+#define VPIF_NTSC_VBI_COUNT_FIELD1	(19)
+#define VPIF_PAL_VBI_COUNT_FIELD0	(24)
+#define VPIF_PAL_VBI_COUNT_FIELD1	(25)
+
+#define VPIF_NTSC_HBI_COUNT_FIELD0	(263)
+#define VPIF_NTSC_HBI_COUNT_FIELD1	(262)
+#define VPIF_PAL_HBI_COUNT_FIELD0	(312)
+#define VPIF_PAL_HBI_COUNT_FIELD1	(313)
+
+#define VPIF_NTSC_VBI_SAMPLES_PER_LINE	(720)
+#define VPIF_PAL_VBI_SAMPLES_PER_LINE	(720)
+#define VPIF_NTSC_HBI_SAMPLES_PER_LINE	(268)
+#define VPIF_PAL_HBI_SAMPLES_PER_LINE	(280)
+
+#define VPIF_CH_VANC_EN			(0x20)
+#define VPIF_DMA_REQ_SIZE		(0x080)
+#define VPIF_EMULATION_DISABLE		(0x01)
+
+extern u8 irq_vpif_capture_channel[VPIF_NUM_CHANNELS];
+
+/* inline function to enable/disable channel0 */
+static inline void enable_channel0(int enable)
+{
+	if (enable)
+		regw((regr(VPIF_CH0_CTRL) | (VPIF_CH0_EN)), VPIF_CH0_CTRL);
+	else
+		regw((regr(VPIF_CH0_CTRL) & (~VPIF_CH0_EN)), VPIF_CH0_CTRL);
+}
+
+/* inline function to enable/disable channel1 */
+static inline void enable_channel1(int enable)
+{
+	if (enable)
+		regw((regr(VPIF_CH1_CTRL) | (VPIF_CH1_EN)), VPIF_CH1_CTRL);
+	else
+		regw((regr(VPIF_CH1_CTRL) & (~VPIF_CH1_EN)), VPIF_CH1_CTRL);
+}
+
+/* inline function to enable interrupt for channel0 */
+static inline void channel0_intr_enable(int enable)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&vpif_lock, flags);
+
+	if (enable) {
+		regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN);
+		regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET);
+
+		regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH0), VPIF_INTEN);
+		regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0),
+							VPIF_INTEN_SET);
+	} else {
+		regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH0)), VPIF_INTEN);
+		regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0),
+							VPIF_INTEN_SET);
+	}
+	spin_unlock_irqrestore(&vpif_lock, flags);
+}
+
+/* inline function to enable interrupt for channel1 */
+static inline void channel1_intr_enable(int enable)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&vpif_lock, flags);
+
+	if (enable) {
+		regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN);
+		regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET);
+
+		regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH1), VPIF_INTEN);
+		regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1),
+							VPIF_INTEN_SET);
+	} else {
+		regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH1)), VPIF_INTEN);
+		regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1),
+							VPIF_INTEN_SET);
+	}
+	spin_unlock_irqrestore(&vpif_lock, flags);
+}
+
+/* inline function to set buffer addresses in case of Y/C non mux mode */
+static inline void ch0_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma,
+						 unsigned long btm_strt_luma,
+						 unsigned long top_strt_chroma,
+						 unsigned long btm_strt_chroma)
+{
+	regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA);
+	regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA);
+	regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA);
+	regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA);
+}
+
+/* inline function to set buffer addresses in VPIF registers for video data */
+static inline void ch0_set_videobuf_addr(unsigned long top_strt_luma,
+					 unsigned long btm_strt_luma,
+					 unsigned long top_strt_chroma,
+					 unsigned long btm_strt_chroma)
+{
+	regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA);
+	regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA);
+	regw(top_strt_chroma, VPIF_CH0_TOP_STRT_ADD_CHROMA);
+	regw(btm_strt_chroma, VPIF_CH0_BTM_STRT_ADD_CHROMA);
+}
+
+static inline void ch1_set_videobuf_addr(unsigned long top_strt_luma,
+					 unsigned long btm_strt_luma,
+					 unsigned long top_strt_chroma,
+					 unsigned long btm_strt_chroma)
+{
+
+	regw(top_strt_luma, VPIF_CH1_TOP_STRT_ADD_LUMA);
+	regw(btm_strt_luma, VPIF_CH1_BTM_STRT_ADD_LUMA);
+	regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA);
+	regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA);
+}
+
+static inline void ch0_set_vbi_addr(unsigned long top_vbi,
+	unsigned long btm_vbi, unsigned long a, unsigned long b)
+{
+	regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_VANC);
+	regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_VANC);
+}
+
+static inline void ch0_set_hbi_addr(unsigned long top_vbi,
+	unsigned long btm_vbi, unsigned long a, unsigned long b)
+{
+	regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_HANC);
+	regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_HANC);
+}
+
+static inline void ch1_set_vbi_addr(unsigned long top_vbi,
+	unsigned long btm_vbi, unsigned long a, unsigned long b)
+{
+	regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_VANC);
+	regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_VANC);
+}
+
+static inline void ch1_set_hbi_addr(unsigned long top_vbi,
+	unsigned long btm_vbi, unsigned long a, unsigned long b)
+{
+	regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_HANC);
+	regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_HANC);
+}
+
+/* Inline function to enable raw vbi in the given channel */
+static inline void disable_raw_feature(u8 channel_id, u8 index)
+{
+	u32 ctrl_reg;
+	if (0 == channel_id)
+		ctrl_reg = VPIF_CH0_CTRL;
+	else
+		ctrl_reg = VPIF_CH1_CTRL;
+
+	if (1 == index)
+		vpif_clr_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT);
+	else
+		vpif_clr_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT);
+}
+
+static inline void enable_raw_feature(u8 channel_id, u8 index)
+{
+	u32 ctrl_reg;
+	if (0 == channel_id)
+		ctrl_reg = VPIF_CH0_CTRL;
+	else
+		ctrl_reg = VPIF_CH1_CTRL;
+
+	if (1 == index)
+		vpif_set_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT);
+	else
+		vpif_set_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT);
+}
+
+/* inline function to enable/disable channel2 */
+static inline void enable_channel2(int enable)
+{
+	if (enable) {
+		regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL);
+		regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_EN)), VPIF_CH2_CTRL);
+	} else {
+		regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL);
+		regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_EN)), VPIF_CH2_CTRL);
+	}
+}
+
+/* inline function to enable/disable channel3 */
+static inline void enable_channel3(int enable)
+{
+	if (enable) {
+		regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL);
+		regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_EN)), VPIF_CH3_CTRL);
+	} else {
+		regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL);
+		regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_EN)), VPIF_CH3_CTRL);
+	}
+}
+
+/* inline function to enable interrupt for channel2 */
+static inline void channel2_intr_enable(int enable)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&vpif_lock, flags);
+
+	if (enable) {
+		regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN);
+		regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET);
+		regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH2), VPIF_INTEN);
+		regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2),
+							VPIF_INTEN_SET);
+	} else {
+		regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH2)), VPIF_INTEN);
+		regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2),
+							VPIF_INTEN_SET);
+	}
+	spin_unlock_irqrestore(&vpif_lock, flags);
+}
+
+/* inline function to enable interrupt for channel3 */
+static inline void channel3_intr_enable(int enable)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&vpif_lock, flags);
+
+	if (enable) {
+		regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN);
+		regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET);
+
+		regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH3), VPIF_INTEN);
+		regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3),
+							VPIF_INTEN_SET);
+	} else {
+		regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH3)), VPIF_INTEN);
+		regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3),
+							VPIF_INTEN_SET);
+	}
+	spin_unlock_irqrestore(&vpif_lock, flags);
+}
+
+/* inline function to enable raw vbi data for channel2 */
+static inline void channel2_raw_enable(int enable, u8 index)
+{
+	u32 mask;
+
+	if (1 == index)
+		mask = VPIF_CH_VANC_EN_BIT;
+	else
+		mask = VPIF_CH_HANC_EN_BIT;
+
+	if (enable)
+		vpif_set_bit(VPIF_CH2_CTRL, mask);
+	else
+		vpif_clr_bit(VPIF_CH2_CTRL, mask);
+}
+
+/* inline function to enable raw vbi data for channel3*/
+static inline void channel3_raw_enable(int enable, u8 index)
+{
+	u32 mask;
+
+	if (1 == index)
+		mask = VPIF_CH_VANC_EN_BIT;
+	else
+		mask = VPIF_CH_HANC_EN_BIT;
+
+	if (enable)
+		vpif_set_bit(VPIF_CH3_CTRL, mask);
+	else
+		vpif_clr_bit(VPIF_CH3_CTRL, mask);
+}
+
+/* function to enable clipping (for both active and blanking regions) on ch 2 */
+static inline void channel2_clipping_enable(int enable)
+{
+	if (enable) {
+		vpif_set_bit(VPIF_CH2_CTRL, VPIF_CH2_CLIP_ANC_EN);
+		vpif_set_bit(VPIF_CH2_CTRL, VPIF_CH2_CLIP_ACTIVE_EN);
+	} else {
+		vpif_clr_bit(VPIF_CH2_CTRL, VPIF_CH2_CLIP_ANC_EN);
+		vpif_clr_bit(VPIF_CH2_CTRL, VPIF_CH2_CLIP_ACTIVE_EN);
+	}
+}
+
+/* function to enable clipping (for both active and blanking regions) on ch 2 */
+static inline void channel3_clipping_enable(int enable)
+{
+	if (enable) {
+		vpif_set_bit(VPIF_CH3_CTRL, VPIF_CH3_CLIP_ANC_EN);
+		vpif_set_bit(VPIF_CH3_CTRL, VPIF_CH3_CLIP_ACTIVE_EN);
+	} else {
+		vpif_clr_bit(VPIF_CH3_CTRL, VPIF_CH3_CLIP_ANC_EN);
+		vpif_clr_bit(VPIF_CH3_CTRL, VPIF_CH3_CLIP_ACTIVE_EN);
+	}
+}
+
+/* inline function to set buffer addresses in case of Y/C non mux mode */
+static inline void ch2_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma,
+						 unsigned long btm_strt_luma,
+						 unsigned long top_strt_chroma,
+						 unsigned long btm_strt_chroma)
+{
+	regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA);
+	regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA);
+	regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA);
+	regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA);
+}
+
+/* inline function to set buffer addresses in VPIF registers for video data */
+static inline void ch2_set_videobuf_addr(unsigned long top_strt_luma,
+					 unsigned long btm_strt_luma,
+					 unsigned long top_strt_chroma,
+					 unsigned long btm_strt_chroma)
+{
+	regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA);
+	regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA);
+	regw(top_strt_chroma, VPIF_CH2_TOP_STRT_ADD_CHROMA);
+	regw(btm_strt_chroma, VPIF_CH2_BTM_STRT_ADD_CHROMA);
+}
+
+static inline void ch3_set_videobuf_addr(unsigned long top_strt_luma,
+					 unsigned long btm_strt_luma,
+					 unsigned long top_strt_chroma,
+					 unsigned long btm_strt_chroma)
+{
+	regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_LUMA);
+	regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_LUMA);
+	regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA);
+	regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA);
+}
+
+/* inline function to set buffer addresses in VPIF registers for vbi data */
+static inline void ch2_set_vbi_addr(unsigned long top_strt_luma,
+					 unsigned long btm_strt_luma,
+					 unsigned long top_strt_chroma,
+					 unsigned long btm_strt_chroma)
+{
+	regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_VANC);
+	regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_VANC);
+}
+
+static inline void ch3_set_vbi_addr(unsigned long top_strt_luma,
+					 unsigned long btm_strt_luma,
+					 unsigned long top_strt_chroma,
+					 unsigned long btm_strt_chroma)
+{
+	regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_VANC);
+	regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_VANC);
+}
+
+static inline int vpif_intr_status(int channel)
+{
+	int status = 0;
+	int mask;
+
+	if (channel < 0 || channel > 3)
+		return 0;
+
+	mask = 1 << channel;
+	status = regr(VPIF_STATUS) & mask;
+	regw(status, VPIF_STATUS_CLR);
+
+	return status;
+}
+
+#define VPIF_MAX_NAME	(30)
+
+/* This structure will store size parameters as per the mode selected by user */
+struct vpif_channel_config_params {
+	char name[VPIF_MAX_NAME];	/* Name of the mode */
+	u16 width;			/* Indicates width of the image */
+	u16 height;			/* Indicates height of the image */
+	u8 frm_fmt;			/* Interlaced (0) or progressive (1) */
+	u8 ycmux_mode;			/* This mode requires one (0) or two (1)
+					   channels */
+	u16 eav2sav;			/* length of eav 2 sav */
+	u16 sav2eav;			/* length of sav 2 eav */
+	u16 l1, l3, l5, l7, l9, l11;	/* Other parameter configurations */
+	u16 vsize;			/* Vertical size of the image */
+	u8 capture_format;		/* Indicates whether capture format
+					 * is in BT or in CCD/CMOS */
+	u8  vbi_supported;		/* Indicates whether this mode
+					 * supports capturing vbi or not */
+	u8 hd_sd;			/* HDTV (1) or SDTV (0) format */
+	v4l2_std_id stdid;		/* SDTV format */
+	u32 dv_preset;			/* HDTV format */
+};
+
+extern const unsigned int vpif_ch_params_count;
+extern const struct vpif_channel_config_params ch_params[];
+
+struct vpif_video_params;
+struct vpif_params;
+struct vpif_vbi_params;
+
+int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id);
+void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams,
+							u8 channel_id);
+int vpif_channel_getfid(u8 channel_id);
+
+enum data_size {
+	_8BITS = 0,
+	_10BITS,
+	_12BITS,
+};
+
+/* Structure for vpif parameters for raw vbi data */
+struct vpif_vbi_params {
+	__u32 hstart0;  /* Horizontal start of raw vbi data for first field */
+	__u32 vstart0;  /* Vertical start of raw vbi data for first field */
+	__u32 hsize0;   /* Horizontal size of raw vbi data for first field */
+	__u32 vsize0;   /* Vertical size of raw vbi data for first field */
+	__u32 hstart1;  /* Horizontal start of raw vbi data for second field */
+	__u32 vstart1;  /* Vertical start of raw vbi data for second field */
+	__u32 hsize1;   /* Horizontal size of raw vbi data for second field */
+	__u32 vsize1;   /* Vertical size of raw vbi data for second field */
+};
+
+/* structure for vpif parameters */
+struct vpif_video_params {
+	__u8 storage_mode;	/* Indicates field or frame mode */
+	unsigned long hpitch;
+	v4l2_std_id stdid;
+};
+
+struct vpif_params {
+	struct vpif_interface iface;
+	struct vpif_video_params video_params;
+	struct vpif_channel_config_params std_info;
+	union param {
+		struct vpif_vbi_params	vbi_params;
+		enum data_size data_sz;
+	} params;
+};
+
+#endif				/* End of #ifndef VPIF_H */
+
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
new file mode 100644
index 0000000..1b625b0
--- /dev/null
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -0,0 +1,2456 @@
+/*
+ * Copyright (C) 2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ * TODO : add support for VBI & HBI data service
+ *	  add static buffer allocation
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "vpif_capture.h"
+#include "vpif.h"
+
+MODULE_DESCRIPTION("TI DaVinci VPIF Capture driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(VPIF_CAPTURE_VERSION);
+
+#define vpif_err(fmt, arg...)	v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg)
+#define vpif_dbg(level, debug, fmt, arg...)	\
+		v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg)
+
+static int debug = 1;
+static u32 ch0_numbuffers = 3;
+static u32 ch1_numbuffers = 3;
+static u32 ch0_bufsize = 1920 * 1080 * 2;
+static u32 ch1_bufsize = 720 * 576 * 2;
+
+module_param(debug, int, 0644);
+module_param(ch0_numbuffers, uint, S_IRUGO);
+module_param(ch1_numbuffers, uint, S_IRUGO);
+module_param(ch0_bufsize, uint, S_IRUGO);
+module_param(ch1_bufsize, uint, S_IRUGO);
+
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+MODULE_PARM_DESC(ch2_numbuffers, "Channel0 buffer count (default:3)");
+MODULE_PARM_DESC(ch3_numbuffers, "Channel1 buffer count (default:3)");
+MODULE_PARM_DESC(ch2_bufsize, "Channel0 buffer size (default:1920 x 1080 x 2)");
+MODULE_PARM_DESC(ch3_bufsize, "Channel1 buffer size (default:720 x 576 x 2)");
+
+static struct vpif_config_params config_params = {
+	.min_numbuffers = 3,
+	.numbuffers[0] = 3,
+	.numbuffers[1] = 3,
+	.min_bufsize[0] = 720 * 480 * 2,
+	.min_bufsize[1] = 720 * 480 * 2,
+	.channel_bufsize[0] = 1920 * 1080 * 2,
+	.channel_bufsize[1] = 720 * 576 * 2,
+};
+
+/* global variables */
+static struct vpif_device vpif_obj = { {NULL} };
+static struct device *vpif_dev;
+static void vpif_calculate_offsets(struct channel_obj *ch);
+static void vpif_config_addr(struct channel_obj *ch, int muxmode);
+
+/**
+ * buffer_prepare :  callback function for buffer prepare
+ * @vb: ptr to vb2_buffer
+ *
+ * This is the callback function for buffer prepare when vb2_qbuf()
+ * function is called. The buffer is prepared and user space virtual address
+ * or user address is converted into  physical address
+ */
+static int vpif_buffer_prepare(struct vb2_buffer *vb)
+{
+	/* Get the file handle object and channel object */
+	struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
+	struct vb2_queue *q = vb->vb2_queue;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common;
+	unsigned long addr;
+
+	vpif_dbg(2, debug, "vpif_buffer_prepare\n");
+
+	common = &ch->common[VPIF_VIDEO_INDEX];
+
+	if (vb->state != VB2_BUF_STATE_ACTIVE &&
+		vb->state != VB2_BUF_STATE_PREPARED) {
+		vb2_set_plane_payload(vb, 0, common->fmt.fmt.pix.sizeimage);
+		if (vb2_plane_vaddr(vb, 0) &&
+		vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0))
+			goto exit;
+		addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+
+		if (q->streaming) {
+			if (!IS_ALIGNED((addr + common->ytop_off), 8) ||
+				!IS_ALIGNED((addr + common->ybtm_off), 8) ||
+				!IS_ALIGNED((addr + common->ctop_off), 8) ||
+				!IS_ALIGNED((addr + common->cbtm_off), 8))
+				goto exit;
+		}
+	}
+	return 0;
+exit:
+	vpif_dbg(1, debug, "buffer_prepare:offset is not aligned to 8 bytes\n");
+	return -EINVAL;
+}
+
+/**
+ * vpif_buffer_queue_setup : Callback function for buffer setup.
+ * @vq: vb2_queue ptr
+ * @fmt: v4l2 format
+ * @nbuffers: ptr to number of buffers requested by application
+ * @nplanes:: contains number of distinct video planes needed to hold a frame
+ * @sizes[]: contains the size (in bytes) of each plane.
+ * @alloc_ctxs: ptr to allocation context
+ *
+ * This callback function is called when reqbuf() is called to adjust
+ * the buffer count and buffer size
+ */
+static int vpif_buffer_queue_setup(struct vb2_queue *vq,
+				const struct v4l2_format *fmt,
+				unsigned int *nbuffers, unsigned int *nplanes,
+				unsigned int sizes[], void *alloc_ctxs[])
+{
+	/* Get the file handle object and channel object */
+	struct vpif_fh *fh = vb2_get_drv_priv(vq);
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common;
+	unsigned long size;
+
+	common = &ch->common[VPIF_VIDEO_INDEX];
+
+	vpif_dbg(2, debug, "vpif_buffer_setup\n");
+
+	/* If memory type is not mmap, return */
+	if (V4L2_MEMORY_MMAP == common->memory) {
+		/* Calculate the size of the buffer */
+		size = config_params.channel_bufsize[ch->channel_id];
+		/*
+		 * Checking if the buffer size exceeds the available buffer
+		 * ycmux_mode = 0 means 1 channel mode HD and
+		 * ycmux_mode = 1 means 2 channels mode SD
+		 */
+		if (ch->vpifparams.std_info.ycmux_mode == 0) {
+			if (config_params.video_limit[ch->channel_id])
+				while (size * *nbuffers >
+					(config_params.video_limit[0]
+						+ config_params.video_limit[1]))
+					(*nbuffers)--;
+		} else {
+			if (config_params.video_limit[ch->channel_id])
+				while (size * *nbuffers >
+				config_params.video_limit[ch->channel_id])
+					(*nbuffers)--;
+		}
+
+	} else {
+		size = common->fmt.fmt.pix.sizeimage;
+	}
+
+	if (*nbuffers < config_params.min_numbuffers)
+		*nbuffers = config_params.min_numbuffers;
+
+	*nplanes = 1;
+	sizes[0] = size;
+	alloc_ctxs[0] = common->alloc_ctx;
+
+	return 0;
+}
+
+/**
+ * vpif_buffer_queue : Callback function to add buffer to DMA queue
+ * @vb: ptr to vb2_buffer
+ */
+static void vpif_buffer_queue(struct vb2_buffer *vb)
+{
+	/* Get the file handle object and channel object */
+	struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
+	struct channel_obj *ch = fh->channel;
+	struct vpif_cap_buffer *buf = container_of(vb,
+				struct vpif_cap_buffer, vb);
+	struct common_obj *common;
+
+	common = &ch->common[VPIF_VIDEO_INDEX];
+
+	vpif_dbg(2, debug, "vpif_buffer_queue\n");
+
+	/* add the buffer to the DMA queue */
+	list_add_tail(&buf->list, &common->dma_queue);
+}
+
+/**
+ * vpif_buf_cleanup : Callback function to free buffer
+ * @vb: ptr to vb2_buffer
+ *
+ * This function is called from the videobuf2 layer to free memory
+ * allocated to  the buffers
+ */
+static void vpif_buf_cleanup(struct vb2_buffer *vb)
+{
+	/* Get the file handle object and channel object */
+	struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
+	struct vpif_cap_buffer *buf = container_of(vb,
+					struct vpif_cap_buffer, vb);
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common;
+	unsigned long flags;
+
+	common = &ch->common[VPIF_VIDEO_INDEX];
+
+	spin_lock_irqsave(&common->irqlock, flags);
+	if (vb->state == VB2_BUF_STATE_ACTIVE)
+		list_del_init(&buf->list);
+	spin_unlock_irqrestore(&common->irqlock, flags);
+
+}
+
+static void vpif_wait_prepare(struct vb2_queue *vq)
+{
+	struct vpif_fh *fh = vb2_get_drv_priv(vq);
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common;
+
+	common = &ch->common[VPIF_VIDEO_INDEX];
+	mutex_unlock(&common->lock);
+}
+
+static void vpif_wait_finish(struct vb2_queue *vq)
+{
+	struct vpif_fh *fh = vb2_get_drv_priv(vq);
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common;
+
+	common = &ch->common[VPIF_VIDEO_INDEX];
+	mutex_lock(&common->lock);
+}
+
+static int vpif_buffer_init(struct vb2_buffer *vb)
+{
+	struct vpif_cap_buffer *buf = container_of(vb,
+					struct vpif_cap_buffer, vb);
+
+	INIT_LIST_HEAD(&buf->list);
+
+	return 0;
+}
+
+static u8 channel_first_int[VPIF_NUMBER_OF_OBJECTS][2] =
+	{ {1, 1} };
+
+static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct vpif_capture_config *vpif_config_data =
+					vpif_dev->platform_data;
+	struct vpif_fh *fh = vb2_get_drv_priv(vq);
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	struct vpif_params *vpif = &ch->vpifparams;
+	unsigned long addr = 0;
+	int ret;
+
+		/* If buffer queue is empty, return error */
+	if (list_empty(&common->dma_queue)) {
+		vpif_dbg(1, debug, "buffer queue is empty\n");
+		return -EIO;
+	}
+
+	/* Get the next frame from the buffer queue */
+	common->cur_frm = common->next_frm = list_entry(common->dma_queue.next,
+				    struct vpif_cap_buffer, list);
+	/* Remove buffer from the buffer queue */
+	list_del(&common->cur_frm->list);
+	/* Mark state of the current frame to active */
+	common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
+	/* Initialize field_id and started member */
+	ch->field_id = 0;
+	common->started = 1;
+	addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0);
+
+	/* Calculate the offset for Y and C data in the buffer */
+	vpif_calculate_offsets(ch);
+
+	if ((vpif->std_info.frm_fmt &&
+	    ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) &&
+	     (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) ||
+	    (!vpif->std_info.frm_fmt &&
+	     (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) {
+		vpif_dbg(1, debug, "conflict in field format and std format\n");
+		return -EINVAL;
+	}
+
+	/* configure 1 or 2 channel mode */
+	ret = vpif_config_data->setup_input_channel_mode
+					(vpif->std_info.ycmux_mode);
+
+	if (ret < 0) {
+		vpif_dbg(1, debug, "can't set vpif channel mode\n");
+		return ret;
+	}
+
+	/* Call vpif_set_params function to set the parameters and addresses */
+	ret = vpif_set_video_params(vpif, ch->channel_id);
+
+	if (ret < 0) {
+		vpif_dbg(1, debug, "can't set video params\n");
+		return ret;
+	}
+
+	common->started = ret;
+	vpif_config_addr(ch, ret);
+
+	common->set_addr(addr + common->ytop_off,
+			 addr + common->ybtm_off,
+			 addr + common->ctop_off,
+			 addr + common->cbtm_off);
+
+	/**
+	 * Set interrupt for both the fields in VPIF Register enable channel in
+	 * VPIF register
+	 */
+	if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)) {
+		channel0_intr_assert();
+		channel0_intr_enable(1);
+		enable_channel0(1);
+	}
+	if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) ||
+	    (common->started == 2)) {
+		channel1_intr_assert();
+		channel1_intr_enable(1);
+		enable_channel1(1);
+	}
+	channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
+
+	return 0;
+}
+
+/* abort streaming and wait for last buffer */
+static int vpif_stop_streaming(struct vb2_queue *vq)
+{
+	struct vpif_fh *fh = vb2_get_drv_priv(vq);
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common;
+
+	if (!vb2_is_streaming(vq))
+		return 0;
+
+	common = &ch->common[VPIF_VIDEO_INDEX];
+
+	/* release all active buffers */
+	while (!list_empty(&common->dma_queue)) {
+		common->next_frm = list_entry(common->dma_queue.next,
+						struct vpif_cap_buffer, list);
+		list_del(&common->next_frm->list);
+		vb2_buffer_done(&common->next_frm->vb, VB2_BUF_STATE_ERROR);
+	}
+
+	return 0;
+}
+
+static struct vb2_ops video_qops = {
+	.queue_setup		= vpif_buffer_queue_setup,
+	.wait_prepare		= vpif_wait_prepare,
+	.wait_finish		= vpif_wait_finish,
+	.buf_init		= vpif_buffer_init,
+	.buf_prepare		= vpif_buffer_prepare,
+	.start_streaming	= vpif_start_streaming,
+	.stop_streaming		= vpif_stop_streaming,
+	.buf_cleanup		= vpif_buf_cleanup,
+	.buf_queue		= vpif_buffer_queue,
+};
+
+/**
+ * vpif_process_buffer_complete: process a completed buffer
+ * @common: ptr to common channel object
+ *
+ * This function time stamp the buffer and mark it as DONE. It also
+ * wake up any process waiting on the QUEUE and set the next buffer
+ * as current
+ */
+static void vpif_process_buffer_complete(struct common_obj *common)
+{
+	do_gettimeofday(&common->cur_frm->vb.v4l2_buf.timestamp);
+	vb2_buffer_done(&common->cur_frm->vb,
+					    VB2_BUF_STATE_DONE);
+	/* Make curFrm pointing to nextFrm */
+	common->cur_frm = common->next_frm;
+}
+
+/**
+ * vpif_schedule_next_buffer: set next buffer address for capture
+ * @common : ptr to common channel object
+ *
+ * This function will get next buffer from the dma queue and
+ * set the buffer address in the vpif register for capture.
+ * the buffer is marked active
+ */
+static void vpif_schedule_next_buffer(struct common_obj *common)
+{
+	unsigned long addr = 0;
+
+	common->next_frm = list_entry(common->dma_queue.next,
+				     struct vpif_cap_buffer, list);
+	/* Remove that buffer from the buffer queue */
+	list_del(&common->next_frm->list);
+	common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE;
+	addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0);
+
+	/* Set top and bottom field addresses in VPIF registers */
+	common->set_addr(addr + common->ytop_off,
+			 addr + common->ybtm_off,
+			 addr + common->ctop_off,
+			 addr + common->cbtm_off);
+}
+
+/**
+ * vpif_channel_isr : ISR handler for vpif capture
+ * @irq: irq number
+ * @dev_id: dev_id ptr
+ *
+ * It changes status of the captured buffer, takes next buffer from the queue
+ * and sets its address in VPIF registers
+ */
+static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
+{
+	struct vpif_device *dev = &vpif_obj;
+	struct common_obj *common;
+	struct channel_obj *ch;
+	enum v4l2_field field;
+	int channel_id = 0;
+	int fid = -1, i;
+
+	channel_id = *(int *)(dev_id);
+	if (!vpif_intr_status(channel_id))
+		return IRQ_NONE;
+
+	ch = dev->dev[channel_id];
+
+	field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field;
+
+	for (i = 0; i < VPIF_NUMBER_OF_OBJECTS; i++) {
+		common = &ch->common[i];
+		/* skip If streaming is not started in this channel */
+		if (0 == common->started)
+			continue;
+
+		/* Check the field format */
+		if (1 == ch->vpifparams.std_info.frm_fmt) {
+			/* Progressive mode */
+			if (list_empty(&common->dma_queue))
+				continue;
+
+			if (!channel_first_int[i][channel_id])
+				vpif_process_buffer_complete(common);
+
+			channel_first_int[i][channel_id] = 0;
+
+			vpif_schedule_next_buffer(common);
+
+
+			channel_first_int[i][channel_id] = 0;
+		} else {
+			/**
+			 * Interlaced mode. If it is first interrupt, ignore
+			 * it
+			 */
+			if (channel_first_int[i][channel_id]) {
+				channel_first_int[i][channel_id] = 0;
+				continue;
+			}
+			if (0 == i) {
+				ch->field_id ^= 1;
+				/* Get field id from VPIF registers */
+				fid = vpif_channel_getfid(ch->channel_id);
+				if (fid != ch->field_id) {
+					/**
+					 * If field id does not match stored
+					 * field id, make them in sync
+					 */
+					if (0 == fid)
+						ch->field_id = fid;
+					return IRQ_HANDLED;
+				}
+			}
+			/* device field id and local field id are in sync */
+			if (0 == fid) {
+				/* this is even field */
+				if (common->cur_frm == common->next_frm)
+					continue;
+
+				/* mark the current buffer as done */
+				vpif_process_buffer_complete(common);
+			} else if (1 == fid) {
+				/* odd field */
+				if (list_empty(&common->dma_queue) ||
+				    (common->cur_frm != common->next_frm))
+					continue;
+
+				vpif_schedule_next_buffer(common);
+			}
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+/**
+ * vpif_update_std_info() - update standard related info
+ * @ch: ptr to channel object
+ *
+ * For a given standard selected by application, update values
+ * in the device data structures
+ */
+static int vpif_update_std_info(struct channel_obj *ch)
+{
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	struct vpif_params *vpifparams = &ch->vpifparams;
+	const struct vpif_channel_config_params *config;
+	struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+	struct video_obj *vid_ch = &ch->video;
+	int index;
+
+	vpif_dbg(2, debug, "vpif_update_std_info\n");
+
+	for (index = 0; index < vpif_ch_params_count; index++) {
+		config = &ch_params[index];
+		if (config->hd_sd == 0) {
+			vpif_dbg(2, debug, "SD format\n");
+			if (config->stdid & vid_ch->stdid) {
+				memcpy(std_info, config, sizeof(*config));
+				break;
+			}
+		} else {
+			vpif_dbg(2, debug, "HD format\n");
+			if (config->dv_preset == vid_ch->dv_preset) {
+				memcpy(std_info, config, sizeof(*config));
+				break;
+			}
+		}
+	}
+
+	/* standard not found */
+	if (index == vpif_ch_params_count)
+		return -EINVAL;
+
+	common->fmt.fmt.pix.width = std_info->width;
+	common->width = std_info->width;
+	common->fmt.fmt.pix.height = std_info->height;
+	common->height = std_info->height;
+	common->fmt.fmt.pix.bytesperline = std_info->width;
+	vpifparams->video_params.hpitch = std_info->width;
+	vpifparams->video_params.storage_mode = std_info->frm_fmt;
+
+	return 0;
+}
+
+/**
+ * vpif_calculate_offsets : This function calculates buffers offsets
+ * @ch : ptr to channel object
+ *
+ * This function calculates buffer offsets for Y and C in the top and
+ * bottom field
+ */
+static void vpif_calculate_offsets(struct channel_obj *ch)
+{
+	unsigned int hpitch, vpitch, sizeimage;
+	struct video_obj *vid_ch = &(ch->video);
+	struct vpif_params *vpifparams = &ch->vpifparams;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	enum v4l2_field field = common->fmt.fmt.pix.field;
+
+	vpif_dbg(2, debug, "vpif_calculate_offsets\n");
+
+	if (V4L2_FIELD_ANY == field) {
+		if (vpifparams->std_info.frm_fmt)
+			vid_ch->buf_field = V4L2_FIELD_NONE;
+		else
+			vid_ch->buf_field = V4L2_FIELD_INTERLACED;
+	} else
+		vid_ch->buf_field = common->fmt.fmt.pix.field;
+
+	sizeimage = common->fmt.fmt.pix.sizeimage;
+
+	hpitch = common->fmt.fmt.pix.bytesperline;
+	vpitch = sizeimage / (hpitch * 2);
+
+	if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
+	    (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
+		/* Calculate offsets for Y top, Y Bottom, C top and C Bottom */
+		common->ytop_off = 0;
+		common->ybtm_off = hpitch;
+		common->ctop_off = sizeimage / 2;
+		common->cbtm_off = sizeimage / 2 + hpitch;
+	} else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) {
+		/* Calculate offsets for Y top, Y Bottom, C top and C Bottom */
+		common->ytop_off = 0;
+		common->ybtm_off = sizeimage / 4;
+		common->ctop_off = sizeimage / 2;
+		common->cbtm_off = common->ctop_off + sizeimage / 4;
+	} else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) {
+		/* Calculate offsets for Y top, Y Bottom, C top and C Bottom */
+		common->ybtm_off = 0;
+		common->ytop_off = sizeimage / 4;
+		common->cbtm_off = sizeimage / 2;
+		common->ctop_off = common->cbtm_off + sizeimage / 4;
+	}
+	if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
+	    (V4L2_FIELD_INTERLACED == vid_ch->buf_field))
+		vpifparams->video_params.storage_mode = 1;
+	else
+		vpifparams->video_params.storage_mode = 0;
+
+	if (1 == vpifparams->std_info.frm_fmt)
+		vpifparams->video_params.hpitch =
+		    common->fmt.fmt.pix.bytesperline;
+	else {
+		if ((field == V4L2_FIELD_ANY)
+		    || (field == V4L2_FIELD_INTERLACED))
+			vpifparams->video_params.hpitch =
+			    common->fmt.fmt.pix.bytesperline * 2;
+		else
+			vpifparams->video_params.hpitch =
+			    common->fmt.fmt.pix.bytesperline;
+	}
+
+	ch->vpifparams.video_params.stdid = vpifparams->std_info.stdid;
+}
+
+/**
+ * vpif_config_format: configure default frame format in the device
+ * ch : ptr to channel object
+ */
+static void vpif_config_format(struct channel_obj *ch)
+{
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+	vpif_dbg(2, debug, "vpif_config_format\n");
+
+	common->fmt.fmt.pix.field = V4L2_FIELD_ANY;
+	if (config_params.numbuffers[ch->channel_id] == 0)
+		common->memory = V4L2_MEMORY_USERPTR;
+	else
+		common->memory = V4L2_MEMORY_MMAP;
+
+	common->fmt.fmt.pix.sizeimage
+	    = config_params.channel_bufsize[ch->channel_id];
+
+	if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER)
+		common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
+	else
+		common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
+	common->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+}
+
+/**
+ * vpif_get_default_field() - Get default field type based on interface
+ * @vpif_params - ptr to vpif params
+ */
+static inline enum v4l2_field vpif_get_default_field(
+				struct vpif_interface *iface)
+{
+	return (iface->if_type == VPIF_IF_RAW_BAYER) ? V4L2_FIELD_NONE :
+						V4L2_FIELD_INTERLACED;
+}
+
+/**
+ * vpif_check_format()  - check given pixel format for compatibility
+ * @ch - channel  ptr
+ * @pixfmt - Given pixel format
+ * @update - update the values as per hardware requirement
+ *
+ * Check the application pixel format for S_FMT and update the input
+ * values as per hardware limits for TRY_FMT. The default pixel and
+ * field format is selected based on interface type.
+ */
+static int vpif_check_format(struct channel_obj *ch,
+			     struct v4l2_pix_format *pixfmt,
+			     int update)
+{
+	struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
+	struct vpif_params *vpif_params = &ch->vpifparams;
+	enum v4l2_field field = pixfmt->field;
+	u32 sizeimage, hpitch, vpitch;
+	int ret = -EINVAL;
+
+	vpif_dbg(2, debug, "vpif_check_format\n");
+	/**
+	 * first check for the pixel format. If if_type is Raw bayer,
+	 * only V4L2_PIX_FMT_SBGGR8 format is supported. Otherwise only
+	 * V4L2_PIX_FMT_YUV422P is supported
+	 */
+	if (vpif_params->iface.if_type == VPIF_IF_RAW_BAYER) {
+		if (pixfmt->pixelformat != V4L2_PIX_FMT_SBGGR8) {
+			if (!update) {
+				vpif_dbg(2, debug, "invalid pix format\n");
+				goto exit;
+			}
+			pixfmt->pixelformat = V4L2_PIX_FMT_SBGGR8;
+		}
+	} else {
+		if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) {
+			if (!update) {
+				vpif_dbg(2, debug, "invalid pixel format\n");
+				goto exit;
+			}
+			pixfmt->pixelformat = V4L2_PIX_FMT_YUV422P;
+		}
+	}
+
+	if (!(VPIF_VALID_FIELD(field))) {
+		if (!update) {
+			vpif_dbg(2, debug, "invalid field format\n");
+			goto exit;
+		}
+		/**
+		 * By default use FIELD_NONE for RAW Bayer capture
+		 * and FIELD_INTERLACED for other interfaces
+		 */
+		field = vpif_get_default_field(&vpif_params->iface);
+	} else if (field == V4L2_FIELD_ANY)
+		/* unsupported field. Use default */
+		field = vpif_get_default_field(&vpif_params->iface);
+
+	/* validate the hpitch */
+	hpitch = pixfmt->bytesperline;
+	if (hpitch < vpif_params->std_info.width) {
+		if (!update) {
+			vpif_dbg(2, debug, "invalid hpitch\n");
+			goto exit;
+		}
+		hpitch = vpif_params->std_info.width;
+	}
+
+	sizeimage = pixfmt->sizeimage;
+
+	vpitch = sizeimage / (hpitch * 2);
+
+	/* validate the vpitch */
+	if (vpitch < vpif_params->std_info.height) {
+		if (!update) {
+			vpif_dbg(2, debug, "Invalid vpitch\n");
+			goto exit;
+		}
+		vpitch = vpif_params->std_info.height;
+	}
+
+	/* Check for 8 byte alignment */
+	if (!ALIGN(hpitch, 8)) {
+		if (!update) {
+			vpif_dbg(2, debug, "invalid pitch alignment\n");
+			goto exit;
+		}
+		/* adjust to next 8 byte boundary */
+		hpitch = (((hpitch + 7) / 8) * 8);
+	}
+	/* if update is set, modify the bytesperline and sizeimage */
+	if (update) {
+		pixfmt->bytesperline = hpitch;
+		pixfmt->sizeimage = hpitch * vpitch * 2;
+	}
+	/**
+	 * Image width and height is always based on current standard width and
+	 * height
+	 */
+	pixfmt->width = common->fmt.fmt.pix.width;
+	pixfmt->height = common->fmt.fmt.pix.height;
+	return 0;
+exit:
+	return ret;
+}
+
+/**
+ * vpif_config_addr() - function to configure buffer address in vpif
+ * @ch - channel ptr
+ * @muxmode - channel mux mode
+ */
+static void vpif_config_addr(struct channel_obj *ch, int muxmode)
+{
+	struct common_obj *common;
+
+	vpif_dbg(2, debug, "vpif_config_addr\n");
+
+	common = &(ch->common[VPIF_VIDEO_INDEX]);
+
+	if (VPIF_CHANNEL1_VIDEO == ch->channel_id)
+		common->set_addr = ch1_set_videobuf_addr;
+	else if (2 == muxmode)
+		common->set_addr = ch0_set_videobuf_addr_yc_nmux;
+	else
+		common->set_addr = ch0_set_videobuf_addr;
+}
+
+/**
+ * vpif_mmap : It is used to map kernel space buffers into user spaces
+ * @filep: file pointer
+ * @vma: ptr to vm_area_struct
+ */
+static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+	/* Get the channel object and file handle object */
+	struct vpif_fh *fh = filep->private_data;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
+	int ret;
+
+	vpif_dbg(2, debug, "vpif_mmap\n");
+
+	if (mutex_lock_interruptible(&common->lock))
+		return -ERESTARTSYS;
+	ret = vb2_mmap(&common->buffer_queue, vma);
+	mutex_unlock(&common->lock);
+	return ret;
+}
+
+/**
+ * vpif_poll: It is used for select/poll system call
+ * @filep: file pointer
+ * @wait: poll table to wait
+ */
+static unsigned int vpif_poll(struct file *filep, poll_table * wait)
+{
+	struct vpif_fh *fh = filep->private_data;
+	struct channel_obj *channel = fh->channel;
+	struct common_obj *common = &(channel->common[VPIF_VIDEO_INDEX]);
+	unsigned int res = 0;
+
+	vpif_dbg(2, debug, "vpif_poll\n");
+
+	if (common->started) {
+		mutex_lock(&common->lock);
+		res = vb2_poll(&common->buffer_queue, filep, wait);
+		mutex_unlock(&common->lock);
+	}
+	return res;
+}
+
+/**
+ * vpif_open : vpif open handler
+ * @filep: file ptr
+ *
+ * It creates object of file handle structure and stores it in private_data
+ * member of filepointer
+ */
+static int vpif_open(struct file *filep)
+{
+	struct vpif_capture_config *config = vpif_dev->platform_data;
+	struct video_device *vdev = video_devdata(filep);
+	struct common_obj *common;
+	struct video_obj *vid_ch;
+	struct channel_obj *ch;
+	struct vpif_fh *fh;
+	int i;
+
+	vpif_dbg(2, debug, "vpif_open\n");
+
+	ch = video_get_drvdata(vdev);
+
+	vid_ch = &ch->video;
+	common = &ch->common[VPIF_VIDEO_INDEX];
+
+	if (NULL == ch->curr_subdev_info) {
+		/**
+		 * search through the sub device to see a registered
+		 * sub device and make it as current sub device
+		 */
+		for (i = 0; i < config->subdev_count; i++) {
+			if (vpif_obj.sd[i]) {
+				/* the sub device is registered */
+				ch->curr_subdev_info = &config->subdev_info[i];
+				/* make first input as the current input */
+				vid_ch->input_idx = 0;
+				break;
+			}
+		}
+		if (i == config->subdev_count) {
+			vpif_err("No sub device registered\n");
+			return -ENOENT;
+		}
+	}
+
+	/* Allocate memory for the file handle object */
+	fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);
+	if (NULL == fh) {
+		vpif_err("unable to allocate memory for file handle object\n");
+		return -ENOMEM;
+	}
+
+	if (mutex_lock_interruptible(&common->lock)) {
+		kfree(fh);
+		return -ERESTARTSYS;
+	}
+	/* store pointer to fh in private_data member of filep */
+	filep->private_data = fh;
+	fh->channel = ch;
+	fh->initialized = 0;
+	/* If decoder is not initialized. initialize it */
+	if (!ch->initialized) {
+		fh->initialized = 1;
+		ch->initialized = 1;
+		memset(&(ch->vpifparams), 0, sizeof(struct vpif_params));
+	}
+	/* Increment channel usrs counter */
+	ch->usrs++;
+	/* Set io_allowed member to false */
+	fh->io_allowed[VPIF_VIDEO_INDEX] = 0;
+	/* Initialize priority of this instance to default priority */
+	fh->prio = V4L2_PRIORITY_UNSET;
+	v4l2_prio_open(&ch->prio, &fh->prio);
+	mutex_unlock(&common->lock);
+	return 0;
+}
+
+/**
+ * vpif_release : function to clean up file close
+ * @filep: file pointer
+ *
+ * This function deletes buffer queue, frees the buffers and the vpif file
+ * handle
+ */
+static int vpif_release(struct file *filep)
+{
+	struct vpif_fh *fh = filep->private_data;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common;
+
+	vpif_dbg(2, debug, "vpif_release\n");
+
+	common = &ch->common[VPIF_VIDEO_INDEX];
+
+	mutex_lock(&common->lock);
+	/* if this instance is doing IO */
+	if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
+		/* Reset io_usrs member of channel object */
+		common->io_usrs = 0;
+		/* Disable channel as per its device type and channel id */
+		if (VPIF_CHANNEL0_VIDEO == ch->channel_id) {
+			enable_channel0(0);
+			channel0_intr_enable(0);
+		}
+		if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) ||
+		    (2 == common->started)) {
+			enable_channel1(0);
+			channel1_intr_enable(0);
+		}
+		common->started = 0;
+		/* Free buffers allocated */
+		vb2_queue_release(&common->buffer_queue);
+		vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
+	}
+
+	/* Decrement channel usrs counter */
+	ch->usrs--;
+
+	/* Close the priority */
+	v4l2_prio_close(&ch->prio, fh->prio);
+
+	if (fh->initialized)
+		ch->initialized = 0;
+
+	mutex_unlock(&common->lock);
+	filep->private_data = NULL;
+	kfree(fh);
+	return 0;
+}
+
+/**
+ * vpif_reqbufs() - request buffer handler
+ * @file: file ptr
+ * @priv: file handle
+ * @reqbuf: request buffer structure ptr
+ */
+static int vpif_reqbufs(struct file *file, void *priv,
+			struct v4l2_requestbuffers *reqbuf)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common;
+	u8 index = 0;
+	struct vb2_queue *q;
+
+	vpif_dbg(2, debug, "vpif_reqbufs\n");
+
+	/**
+	 * This file handle has not initialized the channel,
+	 * It is not allowed to do settings
+	 */
+	if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)
+	    || (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
+		if (!fh->initialized) {
+			vpif_dbg(1, debug, "Channel Busy\n");
+			return -EBUSY;
+		}
+	}
+
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != reqbuf->type || !vpif_dev)
+		return -EINVAL;
+
+	index = VPIF_VIDEO_INDEX;
+
+	common = &ch->common[index];
+
+	if (0 != common->io_usrs)
+		return -EBUSY;
+
+	/* Initialize videobuf2 queue as per the buffer type */
+	common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev);
+	if (!common->alloc_ctx) {
+		vpif_err("Failed to get the context\n");
+		return -EINVAL;
+	}
+	q = &common->buffer_queue;
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	q->io_modes = VB2_MMAP | VB2_USERPTR;
+	q->drv_priv = fh;
+	q->ops = &video_qops;
+	q->mem_ops = &vb2_dma_contig_memops;
+	q->buf_struct_size = sizeof(struct vpif_cap_buffer);
+
+	vb2_queue_init(q);
+
+	/* Set io allowed member of file handle to TRUE */
+	fh->io_allowed[index] = 1;
+	/* Increment io usrs member of channel object to 1 */
+	common->io_usrs = 1;
+	/* Store type of memory requested in channel object */
+	common->memory = reqbuf->memory;
+	INIT_LIST_HEAD(&common->dma_queue);
+
+	/* Allocate buffers */
+	return vb2_reqbufs(&common->buffer_queue, reqbuf);
+}
+
+/**
+ * vpif_querybuf() - query buffer handler
+ * @file: file ptr
+ * @priv: file handle
+ * @buf: v4l2 buffer structure ptr
+ */
+static int vpif_querybuf(struct file *file, void *priv,
+				struct v4l2_buffer *buf)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+	vpif_dbg(2, debug, "vpif_querybuf\n");
+
+	if (common->fmt.type != buf->type)
+		return -EINVAL;
+
+	if (common->memory != V4L2_MEMORY_MMAP) {
+		vpif_dbg(1, debug, "Invalid memory\n");
+		return -EINVAL;
+	}
+
+	return vb2_querybuf(&common->buffer_queue, buf);
+}
+
+/**
+ * vpif_qbuf() - query buffer handler
+ * @file: file ptr
+ * @priv: file handle
+ * @buf: v4l2 buffer structure ptr
+ */
+static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	struct v4l2_buffer tbuf = *buf;
+
+	vpif_dbg(2, debug, "vpif_qbuf\n");
+
+	if (common->fmt.type != tbuf.type) {
+		vpif_err("invalid buffer type\n");
+		return -EINVAL;
+	}
+
+	if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+		vpif_err("fh io not allowed\n");
+		return -EACCES;
+	}
+
+	return vb2_qbuf(&common->buffer_queue, buf);
+}
+
+/**
+ * vpif_dqbuf() - query buffer handler
+ * @file: file ptr
+ * @priv: file handle
+ * @buf: v4l2 buffer structure ptr
+ */
+static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+	vpif_dbg(2, debug, "vpif_dqbuf\n");
+
+	return vb2_dqbuf(&common->buffer_queue, buf,
+			 (file->f_flags & O_NONBLOCK));
+}
+
+/**
+ * vpif_streamon() - streamon handler
+ * @file: file ptr
+ * @priv: file handle
+ * @buftype: v4l2 buffer type
+ */
+static int vpif_streamon(struct file *file, void *priv,
+				enum v4l2_buf_type buftype)
+{
+
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id];
+	struct vpif_params *vpif;
+	int ret = 0;
+
+	vpif_dbg(2, debug, "vpif_streamon\n");
+
+	vpif = &ch->vpifparams;
+
+	if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		vpif_dbg(1, debug, "buffer type not supported\n");
+		return -EINVAL;
+	}
+
+	/* If file handle is not allowed IO, return error */
+	if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+		vpif_dbg(1, debug, "io not allowed\n");
+		return -EACCES;
+	}
+
+	/* If Streaming is already started, return error */
+	if (common->started) {
+		vpif_dbg(1, debug, "channel->started\n");
+		return -EBUSY;
+	}
+
+	if ((ch->channel_id == VPIF_CHANNEL0_VIDEO &&
+	    oth_ch->common[VPIF_VIDEO_INDEX].started &&
+	    vpif->std_info.ycmux_mode == 0) ||
+	   ((ch->channel_id == VPIF_CHANNEL1_VIDEO) &&
+	    (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) {
+		vpif_dbg(1, debug, "other channel is being used\n");
+		return -EBUSY;
+	}
+
+	ret = vpif_check_format(ch, &common->fmt.fmt.pix, 0);
+	if (ret)
+		return ret;
+
+	/* Enable streamon on the sub device */
+	ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video,
+				s_stream, 1);
+
+	if (ret && (ret != -ENOIOCTLCMD)) {
+		vpif_dbg(1, debug, "stream on failed in subdev\n");
+		return ret;
+	}
+
+	/* Call vb2_streamon to start streaming in videobuf2 */
+	ret = vb2_streamon(&common->buffer_queue, buftype);
+	if (ret) {
+		vpif_dbg(1, debug, "vb2_streamon\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+/**
+ * vpif_streamoff() - streamoff handler
+ * @file: file ptr
+ * @priv: file handle
+ * @buftype: v4l2 buffer type
+ */
+static int vpif_streamoff(struct file *file, void *priv,
+				enum v4l2_buf_type buftype)
+{
+
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	int ret;
+
+	vpif_dbg(2, debug, "vpif_streamoff\n");
+
+	if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		vpif_dbg(1, debug, "buffer type not supported\n");
+		return -EINVAL;
+	}
+
+	/* If io is allowed for this file handle, return error */
+	if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+		vpif_dbg(1, debug, "io not allowed\n");
+		return -EACCES;
+	}
+
+	/* If streaming is not started, return error */
+	if (!common->started) {
+		vpif_dbg(1, debug, "channel->started\n");
+		return -EINVAL;
+	}
+
+	/* disable channel */
+	if (VPIF_CHANNEL0_VIDEO == ch->channel_id) {
+		enable_channel0(0);
+		channel0_intr_enable(0);
+	} else {
+		enable_channel1(0);
+		channel1_intr_enable(0);
+	}
+
+	common->started = 0;
+
+	ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video,
+				s_stream, 0);
+
+	if (ret && (ret != -ENOIOCTLCMD))
+		vpif_dbg(1, debug, "stream off failed in subdev\n");
+
+	return vb2_streamoff(&common->buffer_queue, buftype);
+}
+
+/**
+ * vpif_map_sub_device_to_input() - Maps sub device to input
+ * @ch - ptr to channel
+ * @config - ptr to capture configuration
+ * @input_index - Given input index from application
+ * @sub_device_index - index into sd table
+ *
+ * lookup the sub device information for a given input index.
+ * we report all the inputs to application. inputs table also
+ * has sub device name for the each input
+ */
+static struct vpif_subdev_info *vpif_map_sub_device_to_input(
+				struct channel_obj *ch,
+				struct vpif_capture_config *vpif_cfg,
+				int input_index,
+				int *sub_device_index)
+{
+	struct vpif_capture_chan_config *chan_cfg;
+	struct vpif_subdev_info *subdev_info = NULL;
+	const char *subdev_name = NULL;
+	int i;
+
+	vpif_dbg(2, debug, "vpif_map_sub_device_to_input\n");
+
+	chan_cfg = &vpif_cfg->chan_config[ch->channel_id];
+
+	/**
+	 * search through the inputs to find the sub device supporting
+	 * the input
+	 */
+	for (i = 0; i < chan_cfg->input_count; i++) {
+		/* For each sub device, loop through input */
+		if (i == input_index) {
+			subdev_name = chan_cfg->inputs[i].subdev_name;
+			break;
+		}
+	}
+
+	/* if reached maximum. return null */
+	if (i == chan_cfg->input_count || (NULL == subdev_name))
+		return subdev_info;
+
+	/* loop through the sub device list to get the sub device info */
+	for (i = 0; i < vpif_cfg->subdev_count; i++) {
+		subdev_info = &vpif_cfg->subdev_info[i];
+		if (!strcmp(subdev_info->name, subdev_name))
+			break;
+	}
+
+	if (i == vpif_cfg->subdev_count)
+		return subdev_info;
+
+	/* check if the sub device is registered */
+	if (NULL == vpif_obj.sd[i])
+		return NULL;
+
+	*sub_device_index = i;
+	return subdev_info;
+}
+
+/**
+ * vpif_querystd() - querystd handler
+ * @file: file ptr
+ * @priv: file handle
+ * @std_id: ptr to std id
+ *
+ * This function is called to detect standard at the selected input
+ */
+static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	int ret = 0;
+
+	vpif_dbg(2, debug, "vpif_querystd\n");
+
+	/* Call querystd function of decoder device */
+	ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video,
+				querystd, std_id);
+	if (ret < 0)
+		vpif_dbg(1, debug, "Failed to set standard for sub devices\n");
+
+	return ret;
+}
+
+/**
+ * vpif_g_std() - get STD handler
+ * @file: file ptr
+ * @priv: file handle
+ * @std_id: ptr to std id
+ */
+static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+
+	vpif_dbg(2, debug, "vpif_g_std\n");
+
+	*std = ch->video.stdid;
+	return 0;
+}
+
+/**
+ * vpif_s_std() - set STD handler
+ * @file: file ptr
+ * @priv: file handle
+ * @std_id: ptr to std id
+ */
+static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	int ret = 0;
+
+	vpif_dbg(2, debug, "vpif_s_std\n");
+
+	if (common->started) {
+		vpif_err("streaming in progress\n");
+		return -EBUSY;
+	}
+
+	if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
+	    (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
+		if (!fh->initialized) {
+			vpif_dbg(1, debug, "Channel Busy\n");
+			return -EBUSY;
+		}
+	}
+
+	ret = v4l2_prio_check(&ch->prio, fh->prio);
+	if (0 != ret)
+		return ret;
+
+	fh->initialized = 1;
+
+	/* Call encoder subdevice function to set the standard */
+	ch->video.stdid = *std_id;
+	ch->video.dv_preset = V4L2_DV_INVALID;
+	memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
+
+	/* Get the information about the standard */
+	if (vpif_update_std_info(ch)) {
+		vpif_err("Error getting the standard info\n");
+		return -EINVAL;
+	}
+
+	/* Configure the default format information */
+	vpif_config_format(ch);
+
+	/* set standard in the sub device */
+	ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,
+				s_std, *std_id);
+	if (ret < 0)
+		vpif_dbg(1, debug, "Failed to set standard for sub devices\n");
+	return ret;
+}
+
+/**
+ * vpif_enum_input() - ENUMINPUT handler
+ * @file: file ptr
+ * @priv: file handle
+ * @input: ptr to input structure
+ */
+static int vpif_enum_input(struct file *file, void *priv,
+				struct v4l2_input *input)
+{
+
+	struct vpif_capture_config *config = vpif_dev->platform_data;
+	struct vpif_capture_chan_config *chan_cfg;
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+
+	chan_cfg = &config->chan_config[ch->channel_id];
+
+	if (input->index >= chan_cfg->input_count) {
+		vpif_dbg(1, debug, "Invalid input index\n");
+		return -EINVAL;
+	}
+
+	memcpy(input, &chan_cfg->inputs[input->index].input,
+		sizeof(*input));
+	return 0;
+}
+
+/**
+ * vpif_g_input() - Get INPUT handler
+ * @file: file ptr
+ * @priv: file handle
+ * @index: ptr to input index
+ */
+static int vpif_g_input(struct file *file, void *priv, unsigned int *index)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct video_obj *vid_ch = &ch->video;
+
+	*index = vid_ch->input_idx;
+
+	return 0;
+}
+
+/**
+ * vpif_s_input() - Set INPUT handler
+ * @file: file ptr
+ * @priv: file handle
+ * @index: input index
+ */
+static int vpif_s_input(struct file *file, void *priv, unsigned int index)
+{
+	struct vpif_capture_config *config = vpif_dev->platform_data;
+	struct vpif_capture_chan_config *chan_cfg;
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	struct video_obj *vid_ch = &ch->video;
+	struct vpif_subdev_info *subdev_info;
+	int ret = 0, sd_index = 0;
+	u32 input = 0, output = 0;
+
+	chan_cfg = &config->chan_config[ch->channel_id];
+
+	if (common->started) {
+		vpif_err("Streaming in progress\n");
+		return -EBUSY;
+	}
+
+	if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
+	    (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
+		if (!fh->initialized) {
+			vpif_dbg(1, debug, "Channel Busy\n");
+			return -EBUSY;
+		}
+	}
+
+	ret = v4l2_prio_check(&ch->prio, fh->prio);
+	if (0 != ret)
+		return ret;
+
+	fh->initialized = 1;
+	subdev_info = vpif_map_sub_device_to_input(ch, config, index,
+						   &sd_index);
+	if (NULL == subdev_info) {
+		vpif_dbg(1, debug,
+			"couldn't lookup sub device for the input index\n");
+		return -EINVAL;
+	}
+
+	/* first setup input path from sub device to vpif */
+	if (config->setup_input_path) {
+		ret = config->setup_input_path(ch->channel_id,
+					       subdev_info->name);
+		if (ret < 0) {
+			vpif_dbg(1, debug, "couldn't setup input path for the"
+				" sub device %s, for input index %d\n",
+				subdev_info->name, index);
+			return ret;
+		}
+	}
+
+	if (subdev_info->can_route) {
+		input = subdev_info->input;
+		output = subdev_info->output;
+		ret = v4l2_subdev_call(vpif_obj.sd[sd_index], video, s_routing,
+					input, output, 0);
+		if (ret < 0) {
+			vpif_dbg(1, debug, "Failed to set input\n");
+			return ret;
+		}
+	}
+	vid_ch->input_idx = index;
+	ch->curr_subdev_info = subdev_info;
+	ch->curr_sd_index = sd_index;
+	/* copy interface parameters to vpif */
+	ch->vpifparams.iface = subdev_info->vpif_if;
+
+	/* update tvnorms from the sub device input info */
+	ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std;
+	return ret;
+}
+
+/**
+ * vpif_enum_fmt_vid_cap() - ENUM_FMT handler
+ * @file: file ptr
+ * @priv: file handle
+ * @index: input index
+ */
+static int vpif_enum_fmt_vid_cap(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *fmt)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+
+	if (fmt->index != 0) {
+		vpif_dbg(1, debug, "Invalid format index\n");
+		return -EINVAL;
+	}
+
+	/* Fill in the information about format */
+	if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) {
+		fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		strcpy(fmt->description, "Raw Mode -Bayer Pattern GrRBGb");
+		fmt->pixelformat = V4L2_PIX_FMT_SBGGR8;
+	} else {
+		fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		strcpy(fmt->description, "YCbCr4:2:2 YC Planar");
+		fmt->pixelformat = V4L2_PIX_FMT_YUV422P;
+	}
+	return 0;
+}
+
+/**
+ * vpif_try_fmt_vid_cap() - TRY_FMT handler
+ * @file: file ptr
+ * @priv: file handle
+ * @fmt: ptr to v4l2 format structure
+ */
+static int vpif_try_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+	return vpif_check_format(ch, pixfmt, 1);
+}
+
+
+/**
+ * vpif_g_fmt_vid_cap() - Set INPUT handler
+ * @file: file ptr
+ * @priv: file handle
+ * @fmt: ptr to v4l2 format structure
+ */
+static int vpif_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+	/* Check the validity of the buffer type */
+	if (common->fmt.type != fmt->type)
+		return -EINVAL;
+
+	/* Fill in the information about format */
+	*fmt = common->fmt;
+	return 0;
+}
+
+/**
+ * vpif_s_fmt_vid_cap() - Set FMT handler
+ * @file: file ptr
+ * @priv: file handle
+ * @fmt: ptr to v4l2 format structure
+ */
+static int vpif_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	struct v4l2_pix_format *pixfmt;
+	int ret = 0;
+
+	vpif_dbg(2, debug, "%s\n", __func__);
+
+	/* If streaming is started, return error */
+	if (common->started) {
+		vpif_dbg(1, debug, "Streaming is started\n");
+		return -EBUSY;
+	}
+
+	if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
+	    (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
+		if (!fh->initialized) {
+			vpif_dbg(1, debug, "Channel Busy\n");
+			return -EBUSY;
+		}
+	}
+
+	ret = v4l2_prio_check(&ch->prio, fh->prio);
+	if (0 != ret)
+		return ret;
+
+	fh->initialized = 1;
+
+	pixfmt = &fmt->fmt.pix;
+	/* Check for valid field format */
+	ret = vpif_check_format(ch, pixfmt, 0);
+
+	if (ret)
+		return ret;
+	/* store the format in the channel object */
+	common->fmt = *fmt;
+	return 0;
+}
+
+/**
+ * vpif_querycap() - QUERYCAP handler
+ * @file: file ptr
+ * @priv: file handle
+ * @cap: ptr to v4l2_capability structure
+ */
+static int vpif_querycap(struct file *file, void  *priv,
+				struct v4l2_capability *cap)
+{
+	struct vpif_capture_config *config = vpif_dev->platform_data;
+
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+	strlcpy(cap->driver, "vpif capture", sizeof(cap->driver));
+	strlcpy(cap->bus_info, "VPIF Platform", sizeof(cap->bus_info));
+	strlcpy(cap->card, config->card_name, sizeof(cap->card));
+
+	return 0;
+}
+
+/**
+ * vpif_g_priority() - get priority handler
+ * @file: file ptr
+ * @priv: file handle
+ * @prio: ptr to v4l2_priority structure
+ */
+static int vpif_g_priority(struct file *file, void *priv,
+			   enum v4l2_priority *prio)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+
+	*prio = v4l2_prio_max(&ch->prio);
+
+	return 0;
+}
+
+/**
+ * vpif_s_priority() - set priority handler
+ * @file: file ptr
+ * @priv: file handle
+ * @prio: ptr to v4l2_priority structure
+ */
+static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+
+	return v4l2_prio_change(&ch->prio, &fh->prio, p);
+}
+
+/**
+ * vpif_cropcap() - cropcap handler
+ * @file: file ptr
+ * @priv: file handle
+ * @crop: ptr to v4l2_cropcap structure
+ */
+static int vpif_cropcap(struct file *file, void *priv,
+			struct v4l2_cropcap *crop)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != crop->type)
+		return -EINVAL;
+
+	crop->bounds.left = 0;
+	crop->bounds.top = 0;
+	crop->bounds.height = common->height;
+	crop->bounds.width = common->width;
+	crop->defrect = crop->bounds;
+	return 0;
+}
+
+/**
+ * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_enum_dv_presets(struct file *file, void *priv,
+		struct v4l2_dv_enum_preset *preset)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+
+	return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+			video, enum_dv_presets, preset);
+}
+
+/**
+ * vpif_query_dv_presets() - QUERY_DV_PRESET handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_query_dv_preset(struct file *file, void *priv,
+		struct v4l2_dv_preset *preset)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+
+	return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+		       video, query_dv_preset, preset);
+}
+/**
+ * vpif_s_dv_presets() - S_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_s_dv_preset(struct file *file, void *priv,
+		struct v4l2_dv_preset *preset)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	int ret = 0;
+
+	if (common->started) {
+		vpif_dbg(1, debug, "streaming in progress\n");
+		return -EBUSY;
+	}
+
+	if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
+	    (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
+		if (!fh->initialized) {
+			vpif_dbg(1, debug, "Channel Busy\n");
+			return -EBUSY;
+		}
+	}
+
+	ret = v4l2_prio_check(&ch->prio, fh->prio);
+	if (ret)
+		return ret;
+
+	fh->initialized = 1;
+
+	/* Call encoder subdevice function to set the standard */
+	if (mutex_lock_interruptible(&common->lock))
+		return -ERESTARTSYS;
+
+	ch->video.dv_preset = preset->preset;
+	ch->video.stdid = V4L2_STD_UNKNOWN;
+	memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
+
+	/* Get the information about the standard */
+	if (vpif_update_std_info(ch)) {
+		vpif_dbg(1, debug, "Error getting the standard info\n");
+		ret = -EINVAL;
+	} else {
+		/* Configure the default format information */
+		vpif_config_format(ch);
+
+		ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+				video, s_dv_preset, preset);
+	}
+
+	mutex_unlock(&common->lock);
+
+	return ret;
+}
+/**
+ * vpif_g_dv_presets() - G_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_g_dv_preset(struct file *file, void *priv,
+		struct v4l2_dv_preset *preset)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+
+	preset->preset = ch->video.dv_preset;
+
+	return 0;
+}
+
+/**
+ * vpif_s_dv_timings() - S_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_s_dv_timings(struct file *file, void *priv,
+		struct v4l2_dv_timings *timings)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct vpif_params *vpifparams = &ch->vpifparams;
+	struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+	struct video_obj *vid_ch = &ch->video;
+	struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+	int ret;
+
+	if (timings->type != V4L2_DV_BT_656_1120) {
+		vpif_dbg(2, debug, "Timing type not defined\n");
+		return -EINVAL;
+	}
+
+	/* Configure subdevice timings, if any */
+	ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+			video, s_dv_timings, timings);
+	if (ret == -ENOIOCTLCMD) {
+		vpif_dbg(2, debug, "Custom DV timings not supported by "
+				"subdevice\n");
+		return -EINVAL;
+	}
+	if (ret < 0) {
+		vpif_dbg(2, debug, "Error setting custom DV timings\n");
+		return ret;
+	}
+
+	if (!(timings->bt.width && timings->bt.height &&
+				(timings->bt.hbackporch ||
+				 timings->bt.hfrontporch ||
+				 timings->bt.hsync) &&
+				timings->bt.vfrontporch &&
+				(timings->bt.vbackporch ||
+				 timings->bt.vsync))) {
+		vpif_dbg(2, debug, "Timings for width, height, "
+				"horizontal back porch, horizontal sync, "
+				"horizontal front porch, vertical back porch, "
+				"vertical sync and vertical back porch "
+				"must be defined\n");
+		return -EINVAL;
+	}
+
+	*bt = timings->bt;
+
+	/* Configure video port timings */
+
+	std_info->eav2sav = bt->hbackporch + bt->hfrontporch +
+		bt->hsync - 8;
+	std_info->sav2eav = bt->width;
+
+	std_info->l1 = 1;
+	std_info->l3 = bt->vsync + bt->vbackporch + 1;
+
+	if (bt->interlaced) {
+		if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) {
+			std_info->vsize = bt->height * 2 +
+				bt->vfrontporch + bt->vsync + bt->vbackporch +
+				bt->il_vfrontporch + bt->il_vsync +
+				bt->il_vbackporch;
+			std_info->l5 = std_info->vsize/2 -
+				(bt->vfrontporch - 1);
+			std_info->l7 = std_info->vsize/2 + 1;
+			std_info->l9 = std_info->l7 + bt->il_vsync +
+				bt->il_vbackporch + 1;
+			std_info->l11 = std_info->vsize -
+				(bt->il_vfrontporch - 1);
+		} else {
+			vpif_dbg(2, debug, "Required timing values for "
+					"interlaced BT format missing\n");
+			return -EINVAL;
+		}
+	} else {
+		std_info->vsize = bt->height + bt->vfrontporch +
+			bt->vsync + bt->vbackporch;
+		std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);
+	}
+	strncpy(std_info->name, "Custom timings BT656/1120", VPIF_MAX_NAME);
+	std_info->width = bt->width;
+	std_info->height = bt->height;
+	std_info->frm_fmt = bt->interlaced ? 0 : 1;
+	std_info->ycmux_mode = 0;
+	std_info->capture_format = 0;
+	std_info->vbi_supported = 0;
+	std_info->hd_sd = 1;
+	std_info->stdid = 0;
+	std_info->dv_preset = V4L2_DV_INVALID;
+
+	vid_ch->stdid = 0;
+	vid_ch->dv_preset = V4L2_DV_INVALID;
+	return 0;
+}
+
+/**
+ * vpif_g_dv_timings() - G_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_g_dv_timings(struct file *file, void *priv,
+		struct v4l2_dv_timings *timings)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct video_obj *vid_ch = &ch->video;
+	struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+
+	timings->bt = *bt;
+
+	return 0;
+}
+
+/*
+ * vpif_g_chip_ident() - Identify the chip
+ * @file: file ptr
+ * @priv: file handle
+ * @chip: chip identity
+ *
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_g_chip_ident(struct file *file, void *priv,
+		struct v4l2_dbg_chip_ident *chip)
+{
+	chip->ident = V4L2_IDENT_NONE;
+	chip->revision = 0;
+	if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+			chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) {
+		vpif_dbg(2, debug, "match_type is invalid.\n");
+		return -EINVAL;
+	}
+
+	return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core,
+			g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/*
+ * vpif_dbg_g_register() - Read register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be read
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_dbg_g_register(struct file *file, void *priv,
+		struct v4l2_dbg_register *reg){
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+
+	return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,
+			g_register, reg);
+}
+
+/*
+ * vpif_dbg_s_register() - Write to register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be modified
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if write operations fails.
+ */
+static int vpif_dbg_s_register(struct file *file, void *priv,
+		struct v4l2_dbg_register *reg){
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+
+	return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,
+			s_register, reg);
+}
+#endif
+
+/*
+ * vpif_log_status() - Status information
+ * @file: file ptr
+ * @priv: file handle
+ *
+ * Returns zero.
+ */
+static int vpif_log_status(struct file *filep, void *priv)
+{
+	/* status for sub devices */
+	v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status);
+
+	return 0;
+}
+
+/* vpif capture ioctl operations */
+static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
+	.vidioc_querycap        	= vpif_querycap,
+	.vidioc_g_priority		= vpif_g_priority,
+	.vidioc_s_priority		= vpif_s_priority,
+	.vidioc_enum_fmt_vid_cap	= vpif_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap  		= vpif_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap		= vpif_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap		= vpif_try_fmt_vid_cap,
+	.vidioc_enum_input		= vpif_enum_input,
+	.vidioc_s_input			= vpif_s_input,
+	.vidioc_g_input			= vpif_g_input,
+	.vidioc_reqbufs         	= vpif_reqbufs,
+	.vidioc_querybuf        	= vpif_querybuf,
+	.vidioc_querystd		= vpif_querystd,
+	.vidioc_s_std           	= vpif_s_std,
+	.vidioc_g_std			= vpif_g_std,
+	.vidioc_qbuf            	= vpif_qbuf,
+	.vidioc_dqbuf           	= vpif_dqbuf,
+	.vidioc_streamon        	= vpif_streamon,
+	.vidioc_streamoff       	= vpif_streamoff,
+	.vidioc_cropcap         	= vpif_cropcap,
+	.vidioc_enum_dv_presets         = vpif_enum_dv_presets,
+	.vidioc_s_dv_preset             = vpif_s_dv_preset,
+	.vidioc_g_dv_preset             = vpif_g_dv_preset,
+	.vidioc_query_dv_preset         = vpif_query_dv_preset,
+	.vidioc_s_dv_timings            = vpif_s_dv_timings,
+	.vidioc_g_dv_timings            = vpif_g_dv_timings,
+	.vidioc_g_chip_ident		= vpif_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register		= vpif_dbg_g_register,
+	.vidioc_s_register		= vpif_dbg_s_register,
+#endif
+	.vidioc_log_status		= vpif_log_status,
+};
+
+/* vpif file operations */
+static struct v4l2_file_operations vpif_fops = {
+	.owner = THIS_MODULE,
+	.open = vpif_open,
+	.release = vpif_release,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap = vpif_mmap,
+	.poll = vpif_poll
+};
+
+/* vpif video template */
+static struct video_device vpif_video_template = {
+	.name		= "vpif",
+	.fops		= &vpif_fops,
+	.minor		= -1,
+	.ioctl_ops	= &vpif_ioctl_ops,
+};
+
+/**
+ * initialize_vpif() - Initialize vpif data structures
+ *
+ * Allocate memory for data structures and initialize them
+ */
+static int initialize_vpif(void)
+{
+	int err = 0, i, j;
+	int free_channel_objects_index;
+
+	/* Default number of buffers should be 3 */
+	if ((ch0_numbuffers > 0) &&
+	    (ch0_numbuffers < config_params.min_numbuffers))
+		ch0_numbuffers = config_params.min_numbuffers;
+	if ((ch1_numbuffers > 0) &&
+	    (ch1_numbuffers < config_params.min_numbuffers))
+		ch1_numbuffers = config_params.min_numbuffers;
+
+	/* Set buffer size to min buffers size if it is invalid */
+	if (ch0_bufsize < config_params.min_bufsize[VPIF_CHANNEL0_VIDEO])
+		ch0_bufsize =
+		    config_params.min_bufsize[VPIF_CHANNEL0_VIDEO];
+	if (ch1_bufsize < config_params.min_bufsize[VPIF_CHANNEL1_VIDEO])
+		ch1_bufsize =
+		    config_params.min_bufsize[VPIF_CHANNEL1_VIDEO];
+
+	config_params.numbuffers[VPIF_CHANNEL0_VIDEO] = ch0_numbuffers;
+	config_params.numbuffers[VPIF_CHANNEL1_VIDEO] = ch1_numbuffers;
+	if (ch0_numbuffers) {
+		config_params.channel_bufsize[VPIF_CHANNEL0_VIDEO]
+		    = ch0_bufsize;
+	}
+	if (ch1_numbuffers) {
+		config_params.channel_bufsize[VPIF_CHANNEL1_VIDEO]
+		    = ch1_bufsize;
+	}
+
+	/* Allocate memory for six channel objects */
+	for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
+		vpif_obj.dev[i] =
+		    kzalloc(sizeof(*vpif_obj.dev[i]), GFP_KERNEL);
+		/* If memory allocation fails, return error */
+		if (!vpif_obj.dev[i]) {
+			free_channel_objects_index = i;
+			err = -ENOMEM;
+			goto vpif_init_free_channel_objects;
+		}
+	}
+	return 0;
+
+vpif_init_free_channel_objects:
+	for (j = 0; j < free_channel_objects_index; j++)
+		kfree(vpif_obj.dev[j]);
+	return err;
+}
+
+/**
+ * vpif_probe : This function probes the vpif capture driver
+ * @pdev: platform device pointer
+ *
+ * This creates device entries by register itself to the V4L2 driver and
+ * initializes fields of each channel objects
+ */
+static __init int vpif_probe(struct platform_device *pdev)
+{
+	struct vpif_subdev_info *subdevdata;
+	struct vpif_capture_config *config;
+	int i, j, k, m, q, err;
+	struct i2c_adapter *i2c_adap;
+	struct channel_obj *ch;
+	struct common_obj *common;
+	struct video_device *vfd;
+	struct resource *res;
+	int subdev_count;
+	size_t size;
+
+	vpif_dev = &pdev->dev;
+
+	err = initialize_vpif();
+	if (err) {
+		v4l2_err(vpif_dev->driver, "Error initializing vpif\n");
+		return err;
+	}
+
+	err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev);
+	if (err) {
+		v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n");
+		return err;
+	}
+
+	k = 0;
+	while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) {
+		for (i = res->start; i <= res->end; i++) {
+			if (request_irq(i, vpif_channel_isr, IRQF_SHARED,
+					"VPIF_Capture",
+				(void *)(&vpif_obj.dev[k]->channel_id))) {
+				err = -EBUSY;
+				i--;
+				goto vpif_int_err;
+			}
+		}
+		k++;
+	}
+
+	for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
+		/* Get the pointer to the channel object */
+		ch = vpif_obj.dev[i];
+		/* Allocate memory for video device */
+		vfd = video_device_alloc();
+		if (NULL == vfd) {
+			for (j = 0; j < i; j++) {
+				ch = vpif_obj.dev[j];
+				video_device_release(ch->video_dev);
+			}
+			err = -ENOMEM;
+			goto vpif_dev_alloc_err;
+		}
+
+		/* Initialize field of video device */
+		*vfd = vpif_video_template;
+		vfd->v4l2_dev = &vpif_obj.v4l2_dev;
+		vfd->release = video_device_release;
+		snprintf(vfd->name, sizeof(vfd->name),
+			 "VPIF_Capture_DRIVER_V%s",
+			 VPIF_CAPTURE_VERSION);
+		/* Set video_dev to the video device */
+		ch->video_dev = vfd;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res) {
+		size = resource_size(res);
+		/* The resources are divided into two equal memory and when we
+		 * have HD output we can add them together
+		 */
+		for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) {
+			ch = vpif_obj.dev[j];
+			ch->channel_id = j;
+			/* only enabled if second resource exists */
+			config_params.video_limit[ch->channel_id] = 0;
+			if (size)
+				config_params.video_limit[ch->channel_id] =
+									size/2;
+		}
+	}
+
+	for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) {
+		ch = vpif_obj.dev[j];
+		ch->channel_id = j;
+		common = &(ch->common[VPIF_VIDEO_INDEX]);
+		spin_lock_init(&common->irqlock);
+		mutex_init(&common->lock);
+		ch->video_dev->lock = &common->lock;
+		/* Initialize prio member of channel object */
+		v4l2_prio_init(&ch->prio);
+		err = video_register_device(ch->video_dev,
+					    VFL_TYPE_GRABBER, (j ? 1 : 0));
+		if (err)
+			goto probe_out;
+
+		video_set_drvdata(ch->video_dev, ch);
+
+	}
+
+	i2c_adap = i2c_get_adapter(1);
+	config = pdev->dev.platform_data;
+
+	subdev_count = config->subdev_count;
+	vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count,
+				GFP_KERNEL);
+	if (vpif_obj.sd == NULL) {
+		vpif_err("unable to allocate memory for subdevice pointers\n");
+		err = -ENOMEM;
+		goto probe_out;
+	}
+
+	for (i = 0; i < subdev_count; i++) {
+		subdevdata = &config->subdev_info[i];
+		vpif_obj.sd[i] =
+			v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
+						  i2c_adap,
+						  &subdevdata->board_info,
+						  NULL);
+
+		if (!vpif_obj.sd[i]) {
+			vpif_err("Error registering v4l2 subdevice\n");
+			goto probe_subdev_out;
+		}
+		v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n",
+			  subdevdata->name);
+
+		if (vpif_obj.sd[i])
+			vpif_obj.sd[i]->grp_id = 1 << i;
+	}
+
+	v4l2_info(&vpif_obj.v4l2_dev, "VPIF capture driver initialized\n");
+	return 0;
+
+probe_subdev_out:
+	/* free sub devices memory */
+	kfree(vpif_obj.sd);
+
+	j = VPIF_CAPTURE_MAX_DEVICES;
+probe_out:
+	for (k = 0; k < j; k++) {
+		/* Get the pointer to the channel object */
+		ch = vpif_obj.dev[k];
+		/* Unregister video device */
+		video_unregister_device(ch->video_dev);
+	}
+
+vpif_dev_alloc_err:
+	k = VPIF_CAPTURE_MAX_DEVICES-1;
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, k);
+	i = res->end;
+
+vpif_int_err:
+	for (q = k; q >= 0; q--) {
+		for (m = i; m >= (int)res->start; m--)
+			free_irq(m, (void *)(&vpif_obj.dev[q]->channel_id));
+
+		res = platform_get_resource(pdev, IORESOURCE_IRQ, q-1);
+		if (res)
+			i = res->end;
+	}
+	v4l2_device_unregister(&vpif_obj.v4l2_dev);
+	return err;
+}
+
+/**
+ * vpif_remove() - driver remove handler
+ * @device: ptr to platform device structure
+ *
+ * The vidoe device is unregistered
+ */
+static int vpif_remove(struct platform_device *device)
+{
+	int i;
+	struct channel_obj *ch;
+
+	v4l2_device_unregister(&vpif_obj.v4l2_dev);
+
+	/* un-register device */
+	for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
+		/* Get the pointer to the channel object */
+		ch = vpif_obj.dev[i];
+		/* Unregister video device */
+		video_unregister_device(ch->video_dev);
+	}
+	return 0;
+}
+
+#ifdef CONFIG_PM
+/**
+ * vpif_suspend: vpif device suspend
+ */
+static int vpif_suspend(struct device *dev)
+{
+
+	struct common_obj *common;
+	struct channel_obj *ch;
+	int i;
+
+	for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
+		/* Get the pointer to the channel object */
+		ch = vpif_obj.dev[i];
+		common = &ch->common[VPIF_VIDEO_INDEX];
+		mutex_lock(&common->lock);
+		if (ch->usrs && common->io_usrs) {
+			/* Disable channel */
+			if (ch->channel_id == VPIF_CHANNEL0_VIDEO) {
+				enable_channel0(0);
+				channel0_intr_enable(0);
+			}
+			if (ch->channel_id == VPIF_CHANNEL1_VIDEO ||
+			    common->started == 2) {
+				enable_channel1(0);
+				channel1_intr_enable(0);
+			}
+		}
+		mutex_unlock(&common->lock);
+	}
+
+	return 0;
+}
+
+/*
+ * vpif_resume: vpif device suspend
+ */
+static int vpif_resume(struct device *dev)
+{
+	struct common_obj *common;
+	struct channel_obj *ch;
+	int i;
+
+	for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
+		/* Get the pointer to the channel object */
+		ch = vpif_obj.dev[i];
+		common = &ch->common[VPIF_VIDEO_INDEX];
+		mutex_lock(&common->lock);
+		if (ch->usrs && common->io_usrs) {
+			/* Disable channel */
+			if (ch->channel_id == VPIF_CHANNEL0_VIDEO) {
+				enable_channel0(1);
+				channel0_intr_enable(1);
+			}
+			if (ch->channel_id == VPIF_CHANNEL1_VIDEO ||
+			    common->started == 2) {
+				enable_channel1(1);
+				channel1_intr_enable(1);
+			}
+		}
+		mutex_unlock(&common->lock);
+	}
+
+	return 0;
+}
+
+static const struct dev_pm_ops vpif_dev_pm_ops = {
+	.suspend = vpif_suspend,
+	.resume = vpif_resume,
+};
+
+#define vpif_pm_ops (&vpif_dev_pm_ops)
+#else
+#define vpif_pm_ops NULL
+#endif
+
+static __refdata struct platform_driver vpif_driver = {
+	.driver	= {
+		.name	= "vpif_capture",
+		.owner	= THIS_MODULE,
+		.pm	= vpif_pm_ops,
+	},
+	.probe = vpif_probe,
+	.remove = vpif_remove,
+};
+
+/**
+ * vpif_init: initialize the vpif driver
+ *
+ * This function registers device and driver to the kernel, requests irq
+ * handler and allocates memory
+ * for channel objects
+ */
+static __init int vpif_init(void)
+{
+	return platform_driver_register(&vpif_driver);
+}
+
+/**
+ * vpif_cleanup : This function clean up the vpif capture resources
+ *
+ * This will un-registers device and driver to the kernel, frees
+ * requested irq handler and de-allocates memory allocated for channel
+ * objects.
+ */
+static void vpif_cleanup(void)
+{
+	struct platform_device *pdev;
+	struct resource *res;
+	int irq_num;
+	int i = 0;
+
+	pdev = container_of(vpif_dev, struct platform_device, dev);
+	while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) {
+		for (irq_num = res->start; irq_num <= res->end; irq_num++)
+			free_irq(irq_num,
+				 (void *)(&vpif_obj.dev[i]->channel_id));
+		i++;
+	}
+
+	platform_driver_unregister(&vpif_driver);
+
+	kfree(vpif_obj.sd);
+	for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++)
+		kfree(vpif_obj.dev[i]);
+}
+
+/* Function for module initialization and cleanup */
+module_init(vpif_init);
+module_exit(vpif_cleanup);
diff --git a/drivers/media/platform/davinci/vpif_capture.h b/drivers/media/platform/davinci/vpif_capture.h
new file mode 100644
index 0000000..3511510
--- /dev/null
+++ b/drivers/media/platform/davinci/vpif_capture.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef VPIF_CAPTURE_H
+#define VPIF_CAPTURE_H
+
+#ifdef __KERNEL__
+
+/* Header files */
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf-core.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/davinci/vpif_types.h>
+
+#include "vpif.h"
+
+/* Macros */
+#define VPIF_CAPTURE_VERSION		"0.0.2"
+
+#define VPIF_VALID_FIELD(field)		(((V4L2_FIELD_ANY == field) || \
+	(V4L2_FIELD_NONE == field)) || \
+	(((V4L2_FIELD_INTERLACED == field) || \
+	(V4L2_FIELD_SEQ_TB == field)) || \
+	(V4L2_FIELD_SEQ_BT == field)))
+
+#define VPIF_CAPTURE_MAX_DEVICES	2
+#define VPIF_VIDEO_INDEX		0
+#define VPIF_NUMBER_OF_OBJECTS		1
+
+/* Enumerated data type to give id to each device per channel */
+enum vpif_channel_id {
+	VPIF_CHANNEL0_VIDEO = 0,
+	VPIF_CHANNEL1_VIDEO,
+};
+
+struct video_obj {
+	enum v4l2_field buf_field;
+	/* Currently selected or default standard */
+	v4l2_std_id stdid;
+	u32 dv_preset;
+	struct v4l2_bt_timings bt_timings;
+	/* This is to track the last input that is passed to application */
+	u32 input_idx;
+};
+
+struct vpif_cap_buffer {
+	struct vb2_buffer vb;
+	struct list_head list;
+};
+
+struct common_obj {
+	/* Pointer pointing to current v4l2_buffer */
+	struct vpif_cap_buffer *cur_frm;
+	/* Pointer pointing to current v4l2_buffer */
+	struct vpif_cap_buffer *next_frm;
+	/*
+	 * This field keeps track of type of buffer exchange mechanism
+	 * user has selected
+	 */
+	enum v4l2_memory memory;
+	/* Used to store pixel format */
+	struct v4l2_format fmt;
+	/* Buffer queue used in video-buf */
+	struct vb2_queue buffer_queue;
+	/* allocator-specific contexts for each plane */
+	struct vb2_alloc_ctx *alloc_ctx;
+	/* Queue of filled frames */
+	struct list_head dma_queue;
+	/* Used in video-buf */
+	spinlock_t irqlock;
+	/* lock used to access this structure */
+	struct mutex lock;
+	/* number of users performing IO */
+	u32 io_usrs;
+	/* Indicates whether streaming started */
+	u8 started;
+	/* Function pointer to set the addresses */
+	void (*set_addr) (unsigned long, unsigned long, unsigned long,
+			  unsigned long);
+	/* offset where Y top starts from the starting of the buffer */
+	u32 ytop_off;
+	/* offset where Y bottom starts from the starting of the buffer */
+	u32 ybtm_off;
+	/* offset where C top starts from the starting of the buffer */
+	u32 ctop_off;
+	/* offset where C bottom starts from the starting of the buffer */
+	u32 cbtm_off;
+	/* Indicates width of the image data */
+	u32 width;
+	/* Indicates height of the image data */
+	u32 height;
+};
+
+struct channel_obj {
+	/* Identifies video device for this channel */
+	struct video_device *video_dev;
+	/* Used to keep track of state of the priority */
+	struct v4l2_prio_state prio;
+	/* number of open instances of the channel */
+	int usrs;
+	/* Indicates id of the field which is being displayed */
+	u32 field_id;
+	/* flag to indicate whether decoder is initialized */
+	u8 initialized;
+	/* Identifies channel */
+	enum vpif_channel_id channel_id;
+	/* index into sd table */
+	int curr_sd_index;
+	/* ptr to current sub device information */
+	struct vpif_subdev_info *curr_subdev_info;
+	/* vpif configuration params */
+	struct vpif_params vpifparams;
+	/* common object array */
+	struct common_obj common[VPIF_NUMBER_OF_OBJECTS];
+	/* video object */
+	struct video_obj video;
+};
+
+/* File handle structure */
+struct vpif_fh {
+	/* pointer to channel object for opened device */
+	struct channel_obj *channel;
+	/* Indicates whether this file handle is doing IO */
+	u8 io_allowed[VPIF_NUMBER_OF_OBJECTS];
+	/* Used to keep track priority of this instance */
+	enum v4l2_priority prio;
+	/* Used to indicate channel is initialize or not */
+	u8 initialized;
+};
+
+struct vpif_device {
+	struct v4l2_device v4l2_dev;
+	struct channel_obj *dev[VPIF_CAPTURE_NUM_CHANNELS];
+	struct v4l2_subdev **sd;
+};
+
+struct vpif_config_params {
+	u8 min_numbuffers;
+	u8 numbuffers[VPIF_CAPTURE_NUM_CHANNELS];
+	s8 device_type;
+	u32 min_bufsize[VPIF_CAPTURE_NUM_CHANNELS];
+	u32 channel_bufsize[VPIF_CAPTURE_NUM_CHANNELS];
+	u8 default_device[VPIF_CAPTURE_NUM_CHANNELS];
+	u32 video_limit[VPIF_CAPTURE_NUM_CHANNELS];
+	u8 max_device_type;
+};
+/* Struct which keeps track of the line numbers for the sliced vbi service */
+struct vpif_service_line {
+	u16 service_id;
+	u16 service_line[2];
+};
+#endif				/* End of __KERNEL__ */
+#endif				/* VPIF_CAPTURE_H */
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
new file mode 100644
index 0000000..4a24848
--- /dev/null
+++ b/drivers/media/platform/davinci/vpif_display.c
@@ -0,0 +1,2010 @@
+/*
+ * vpif-display - VPIF display driver
+ * Display driver for TI DaVinci VPIF
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; 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/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <asm/irq.h>
+#include <asm/page.h>
+
+#include <media/adv7343.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "vpif_display.h"
+#include "vpif.h"
+
+MODULE_DESCRIPTION("TI DaVinci VPIF Display driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(VPIF_DISPLAY_VERSION);
+
+#define VPIF_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50)
+
+#define vpif_err(fmt, arg...)	v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg)
+#define vpif_dbg(level, debug, fmt, arg...)	\
+		v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg)
+
+static int debug = 1;
+static u32 ch2_numbuffers = 3;
+static u32 ch3_numbuffers = 3;
+static u32 ch2_bufsize = 1920 * 1080 * 2;
+static u32 ch3_bufsize = 720 * 576 * 2;
+
+module_param(debug, int, 0644);
+module_param(ch2_numbuffers, uint, S_IRUGO);
+module_param(ch3_numbuffers, uint, S_IRUGO);
+module_param(ch2_bufsize, uint, S_IRUGO);
+module_param(ch3_bufsize, uint, S_IRUGO);
+
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+MODULE_PARM_DESC(ch2_numbuffers, "Channel2 buffer count (default:3)");
+MODULE_PARM_DESC(ch3_numbuffers, "Channel3 buffer count (default:3)");
+MODULE_PARM_DESC(ch2_bufsize, "Channel2 buffer size (default:1920 x 1080 x 2)");
+MODULE_PARM_DESC(ch3_bufsize, "Channel3 buffer size (default:720 x 576 x 2)");
+
+static struct vpif_config_params config_params = {
+	.min_numbuffers		= 3,
+	.numbuffers[0]		= 3,
+	.numbuffers[1]		= 3,
+	.min_bufsize[0]		= 720 * 480 * 2,
+	.min_bufsize[1]		= 720 * 480 * 2,
+	.channel_bufsize[0]	= 1920 * 1080 * 2,
+	.channel_bufsize[1]	= 720 * 576 * 2,
+};
+
+static struct vpif_device vpif_obj = { {NULL} };
+static struct device *vpif_dev;
+static void vpif_calculate_offsets(struct channel_obj *ch);
+static void vpif_config_addr(struct channel_obj *ch, int muxmode);
+
+/*
+ * buffer_prepare: This is the callback function called from vb2_qbuf()
+ * function the buffer is prepared and user space virtual address is converted
+ * into physical address
+ */
+static int vpif_buffer_prepare(struct vb2_buffer *vb)
+{
+	struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
+	struct vb2_queue *q = vb->vb2_queue;
+	struct common_obj *common;
+	unsigned long addr;
+
+	common = &fh->channel->common[VPIF_VIDEO_INDEX];
+	if (vb->state != VB2_BUF_STATE_ACTIVE &&
+		vb->state != VB2_BUF_STATE_PREPARED) {
+		vb2_set_plane_payload(vb, 0, common->fmt.fmt.pix.sizeimage);
+		if (vb2_plane_vaddr(vb, 0) &&
+		vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0))
+			goto buf_align_exit;
+
+		addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+		if (q->streaming &&
+			(V4L2_BUF_TYPE_SLICED_VBI_OUTPUT != q->type)) {
+			if (!ISALIGNED(addr + common->ytop_off) ||
+			!ISALIGNED(addr + common->ybtm_off) ||
+			!ISALIGNED(addr + common->ctop_off) ||
+			!ISALIGNED(addr + common->cbtm_off))
+				goto buf_align_exit;
+		}
+	}
+	return 0;
+
+buf_align_exit:
+	vpif_err("buffer offset not aligned to 8 bytes\n");
+	return -EINVAL;
+}
+
+/*
+ * vpif_buffer_queue_setup: This function allocates memory for the buffers
+ */
+static int vpif_buffer_queue_setup(struct vb2_queue *vq,
+				const struct v4l2_format *fmt,
+				unsigned int *nbuffers, unsigned int *nplanes,
+				unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct vpif_fh *fh = vb2_get_drv_priv(vq);
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	unsigned long size;
+
+	if (V4L2_MEMORY_MMAP == common->memory) {
+		size = config_params.channel_bufsize[ch->channel_id];
+		/*
+		* Checking if the buffer size exceeds the available buffer
+		* ycmux_mode = 0 means 1 channel mode HD and
+		* ycmux_mode = 1 means 2 channels mode SD
+		*/
+		if (ch->vpifparams.std_info.ycmux_mode == 0) {
+			if (config_params.video_limit[ch->channel_id])
+				while (size * *nbuffers >
+					(config_params.video_limit[0]
+						+ config_params.video_limit[1]))
+					(*nbuffers)--;
+		} else {
+			if (config_params.video_limit[ch->channel_id])
+				while (size * *nbuffers >
+				config_params.video_limit[ch->channel_id])
+					(*nbuffers)--;
+		}
+	} else {
+		size = common->fmt.fmt.pix.sizeimage;
+	}
+
+	if (*nbuffers < config_params.min_numbuffers)
+			*nbuffers = config_params.min_numbuffers;
+
+	*nplanes = 1;
+	sizes[0] = size;
+	alloc_ctxs[0] = common->alloc_ctx;
+	return 0;
+}
+
+/*
+ * vpif_buffer_queue: This function adds the buffer to DMA queue
+ */
+static void vpif_buffer_queue(struct vb2_buffer *vb)
+{
+	struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
+	struct vpif_disp_buffer *buf = container_of(vb,
+				struct vpif_disp_buffer, vb);
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common;
+
+	common = &ch->common[VPIF_VIDEO_INDEX];
+
+	/* add the buffer to the DMA queue */
+	list_add_tail(&buf->list, &common->dma_queue);
+}
+
+/*
+ * vpif_buf_cleanup: This function is called from the videobuf2 layer to
+ * free memory allocated to the buffers
+ */
+static void vpif_buf_cleanup(struct vb2_buffer *vb)
+{
+	struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
+	struct vpif_disp_buffer *buf = container_of(vb,
+					struct vpif_disp_buffer, vb);
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common;
+	unsigned long flags;
+
+	common = &ch->common[VPIF_VIDEO_INDEX];
+
+	spin_lock_irqsave(&common->irqlock, flags);
+	if (vb->state == VB2_BUF_STATE_ACTIVE)
+		list_del_init(&buf->list);
+	spin_unlock_irqrestore(&common->irqlock, flags);
+}
+
+static void vpif_wait_prepare(struct vb2_queue *vq)
+{
+	struct vpif_fh *fh = vb2_get_drv_priv(vq);
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common;
+
+	common = &ch->common[VPIF_VIDEO_INDEX];
+	mutex_unlock(&common->lock);
+}
+
+static void vpif_wait_finish(struct vb2_queue *vq)
+{
+	struct vpif_fh *fh = vb2_get_drv_priv(vq);
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common;
+
+	common = &ch->common[VPIF_VIDEO_INDEX];
+	mutex_lock(&common->lock);
+}
+
+static int vpif_buffer_init(struct vb2_buffer *vb)
+{
+	struct vpif_disp_buffer *buf = container_of(vb,
+					struct vpif_disp_buffer, vb);
+
+	INIT_LIST_HEAD(&buf->list);
+
+	return 0;
+}
+
+static u8 channel_first_int[VPIF_NUMOBJECTS][2] = { {1, 1} };
+
+static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct vpif_display_config *vpif_config_data =
+					vpif_dev->platform_data;
+	struct vpif_fh *fh = vb2_get_drv_priv(vq);
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	struct vpif_params *vpif = &ch->vpifparams;
+	unsigned long addr = 0;
+	int ret;
+
+	/* If buffer queue is empty, return error */
+	if (list_empty(&common->dma_queue)) {
+		vpif_err("buffer queue is empty\n");
+		return -EIO;
+	}
+
+	/* Get the next frame from the buffer queue */
+	common->next_frm = common->cur_frm =
+			    list_entry(common->dma_queue.next,
+				       struct vpif_disp_buffer, list);
+
+	list_del(&common->cur_frm->list);
+	/* Mark state of the current frame to active */
+	common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
+
+	/* Initialize field_id and started member */
+	ch->field_id = 0;
+	common->started = 1;
+	addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0);
+	/* Calculate the offset for Y and C data  in the buffer */
+	vpif_calculate_offsets(ch);
+
+	if ((ch->vpifparams.std_info.frm_fmt &&
+		((common->fmt.fmt.pix.field != V4L2_FIELD_NONE)
+		&& (common->fmt.fmt.pix.field != V4L2_FIELD_ANY)))
+		|| (!ch->vpifparams.std_info.frm_fmt
+		&& (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) {
+		vpif_err("conflict in field format and std format\n");
+		return -EINVAL;
+	}
+
+	/* clock settings */
+	ret =
+	    vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode,
+					ch->vpifparams.std_info.hd_sd);
+	if (ret < 0) {
+		vpif_err("can't set clock\n");
+		return ret;
+	}
+
+	/* set the parameters and addresses */
+	ret = vpif_set_video_params(vpif, ch->channel_id + 2);
+	if (ret < 0)
+		return ret;
+
+	common->started = ret;
+	vpif_config_addr(ch, ret);
+	common->set_addr((addr + common->ytop_off),
+			    (addr + common->ybtm_off),
+			    (addr + common->ctop_off),
+			    (addr + common->cbtm_off));
+
+	/* Set interrupt for both the fields in VPIF
+	    Register enable channel in VPIF register */
+	if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
+		channel2_intr_assert();
+		channel2_intr_enable(1);
+		enable_channel2(1);
+		if (vpif_config_data->ch2_clip_en)
+			channel2_clipping_enable(1);
+	}
+
+	if ((VPIF_CHANNEL3_VIDEO == ch->channel_id)
+		|| (common->started == 2)) {
+		channel3_intr_assert();
+		channel3_intr_enable(1);
+		enable_channel3(1);
+		if (vpif_config_data->ch3_clip_en)
+			channel3_clipping_enable(1);
+	}
+	channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
+
+	return 0;
+}
+
+/* abort streaming and wait for last buffer */
+static int vpif_stop_streaming(struct vb2_queue *vq)
+{
+	struct vpif_fh *fh = vb2_get_drv_priv(vq);
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common;
+
+	if (!vb2_is_streaming(vq))
+		return 0;
+
+	common = &ch->common[VPIF_VIDEO_INDEX];
+
+	/* release all active buffers */
+	while (!list_empty(&common->dma_queue)) {
+		common->next_frm = list_entry(common->dma_queue.next,
+						struct vpif_disp_buffer, list);
+		list_del(&common->next_frm->list);
+		vb2_buffer_done(&common->next_frm->vb, VB2_BUF_STATE_ERROR);
+	}
+
+	return 0;
+}
+
+static struct vb2_ops video_qops = {
+	.queue_setup		= vpif_buffer_queue_setup,
+	.wait_prepare		= vpif_wait_prepare,
+	.wait_finish		= vpif_wait_finish,
+	.buf_init		= vpif_buffer_init,
+	.buf_prepare		= vpif_buffer_prepare,
+	.start_streaming	= vpif_start_streaming,
+	.stop_streaming		= vpif_stop_streaming,
+	.buf_cleanup		= vpif_buf_cleanup,
+	.buf_queue		= vpif_buffer_queue,
+};
+
+static void process_progressive_mode(struct common_obj *common)
+{
+	unsigned long addr = 0;
+
+	/* Get the next buffer from buffer queue */
+	common->next_frm = list_entry(common->dma_queue.next,
+				struct vpif_disp_buffer, list);
+	/* Remove that buffer from the buffer queue */
+	list_del(&common->next_frm->list);
+	/* Mark status of the buffer as active */
+	common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE;
+
+	/* Set top and bottom field addrs in VPIF registers */
+	addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0);
+	common->set_addr(addr + common->ytop_off,
+				 addr + common->ybtm_off,
+				 addr + common->ctop_off,
+				 addr + common->cbtm_off);
+}
+
+static void process_interlaced_mode(int fid, struct common_obj *common)
+{
+	/* device field id and local field id are in sync */
+	/* If this is even field */
+	if (0 == fid) {
+		if (common->cur_frm == common->next_frm)
+			return;
+
+		/* one frame is displayed If next frame is
+		 *  available, release cur_frm and move on */
+		/* Copy frame display time */
+		do_gettimeofday(&common->cur_frm->vb.v4l2_buf.timestamp);
+		/* Change status of the cur_frm */
+		vb2_buffer_done(&common->cur_frm->vb,
+					    VB2_BUF_STATE_DONE);
+		/* Make cur_frm pointing to next_frm */
+		common->cur_frm = common->next_frm;
+
+	} else if (1 == fid) {	/* odd field */
+		if (list_empty(&common->dma_queue)
+		    || (common->cur_frm != common->next_frm)) {
+			return;
+		}
+		/* one field is displayed configure the next
+		 * frame if it is available else hold on current
+		 * frame */
+		/* Get next from the buffer queue */
+		process_progressive_mode(common);
+
+	}
+}
+
+/*
+ * vpif_channel_isr: It changes status of the displayed buffer, takes next
+ * buffer from the queue and sets its address in VPIF registers
+ */
+static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
+{
+	struct vpif_device *dev = &vpif_obj;
+	struct channel_obj *ch;
+	struct common_obj *common;
+	enum v4l2_field field;
+	int fid = -1, i;
+	int channel_id = 0;
+
+	channel_id = *(int *)(dev_id);
+	if (!vpif_intr_status(channel_id + 2))
+		return IRQ_NONE;
+
+	ch = dev->dev[channel_id];
+	field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field;
+	for (i = 0; i < VPIF_NUMOBJECTS; i++) {
+		common = &ch->common[i];
+		/* If streaming is started in this channel */
+		if (0 == common->started)
+			continue;
+
+		if (1 == ch->vpifparams.std_info.frm_fmt) {
+			if (list_empty(&common->dma_queue))
+				continue;
+
+			/* Progressive mode */
+			if (!channel_first_int[i][channel_id]) {
+				/* Mark status of the cur_frm to
+				 * done and unlock semaphore on it */
+				do_gettimeofday(&common->cur_frm->vb.
+						v4l2_buf.timestamp);
+				vb2_buffer_done(&common->cur_frm->vb,
+					    VB2_BUF_STATE_DONE);
+				/* Make cur_frm pointing to next_frm */
+				common->cur_frm = common->next_frm;
+			}
+
+			channel_first_int[i][channel_id] = 0;
+			process_progressive_mode(common);
+		} else {
+			/* Interlaced mode */
+			/* If it is first interrupt, ignore it */
+
+			if (channel_first_int[i][channel_id]) {
+				channel_first_int[i][channel_id] = 0;
+				continue;
+			}
+
+			if (0 == i) {
+				ch->field_id ^= 1;
+				/* Get field id from VPIF registers */
+				fid = vpif_channel_getfid(ch->channel_id + 2);
+				/* If fid does not match with stored field id */
+				if (fid != ch->field_id) {
+					/* Make them in sync */
+					if (0 == fid)
+						ch->field_id = fid;
+
+					return IRQ_HANDLED;
+				}
+			}
+			process_interlaced_mode(fid, common);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int vpif_update_std_info(struct channel_obj *ch)
+{
+	struct video_obj *vid_ch = &ch->video;
+	struct vpif_params *vpifparams = &ch->vpifparams;
+	struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+	const struct vpif_channel_config_params *config;
+
+	int i;
+
+	for (i = 0; i < vpif_ch_params_count; i++) {
+		config = &ch_params[i];
+		if (config->hd_sd == 0) {
+			vpif_dbg(2, debug, "SD format\n");
+			if (config->stdid & vid_ch->stdid) {
+				memcpy(std_info, config, sizeof(*config));
+				break;
+			}
+		} else {
+			vpif_dbg(2, debug, "HD format\n");
+			if (config->dv_preset == vid_ch->dv_preset) {
+				memcpy(std_info, config, sizeof(*config));
+				break;
+			}
+		}
+	}
+
+	if (i == vpif_ch_params_count) {
+		vpif_dbg(1, debug, "Format not found\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vpif_update_resolution(struct channel_obj *ch)
+{
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	struct video_obj *vid_ch = &ch->video;
+	struct vpif_params *vpifparams = &ch->vpifparams;
+	struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+
+	if (!vid_ch->stdid && !vid_ch->dv_preset && !vid_ch->bt_timings.height)
+		return -EINVAL;
+
+	if (vid_ch->stdid || vid_ch->dv_preset) {
+		if (vpif_update_std_info(ch))
+			return -EINVAL;
+	}
+
+	common->fmt.fmt.pix.width = std_info->width;
+	common->fmt.fmt.pix.height = std_info->height;
+	vpif_dbg(1, debug, "Pixel details: Width = %d,Height = %d\n",
+			common->fmt.fmt.pix.width, common->fmt.fmt.pix.height);
+
+	/* Set height and width paramateres */
+	common->height = std_info->height;
+	common->width = std_info->width;
+
+	return 0;
+}
+
+/*
+ * vpif_calculate_offsets: This function calculates buffers offset for Y and C
+ * in the top and bottom field
+ */
+static void vpif_calculate_offsets(struct channel_obj *ch)
+{
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	struct vpif_params *vpifparams = &ch->vpifparams;
+	enum v4l2_field field = common->fmt.fmt.pix.field;
+	struct video_obj *vid_ch = &ch->video;
+	unsigned int hpitch, vpitch, sizeimage;
+
+	if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) {
+		if (ch->vpifparams.std_info.frm_fmt)
+			vid_ch->buf_field = V4L2_FIELD_NONE;
+		else
+			vid_ch->buf_field = V4L2_FIELD_INTERLACED;
+	} else {
+		vid_ch->buf_field = common->fmt.fmt.pix.field;
+	}
+
+	sizeimage = common->fmt.fmt.pix.sizeimage;
+
+	hpitch = common->fmt.fmt.pix.bytesperline;
+	vpitch = sizeimage / (hpitch * 2);
+	if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
+	    (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
+		common->ytop_off = 0;
+		common->ybtm_off = hpitch;
+		common->ctop_off = sizeimage / 2;
+		common->cbtm_off = sizeimage / 2 + hpitch;
+	} else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) {
+		common->ytop_off = 0;
+		common->ybtm_off = sizeimage / 4;
+		common->ctop_off = sizeimage / 2;
+		common->cbtm_off = common->ctop_off + sizeimage / 4;
+	} else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) {
+		common->ybtm_off = 0;
+		common->ytop_off = sizeimage / 4;
+		common->cbtm_off = sizeimage / 2;
+		common->ctop_off = common->cbtm_off + sizeimage / 4;
+	}
+
+	if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
+	    (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
+		vpifparams->video_params.storage_mode = 1;
+	} else {
+		vpifparams->video_params.storage_mode = 0;
+	}
+
+	if (ch->vpifparams.std_info.frm_fmt == 1) {
+		vpifparams->video_params.hpitch =
+		    common->fmt.fmt.pix.bytesperline;
+	} else {
+		if ((field == V4L2_FIELD_ANY) ||
+			(field == V4L2_FIELD_INTERLACED))
+			vpifparams->video_params.hpitch =
+			    common->fmt.fmt.pix.bytesperline * 2;
+		else
+			vpifparams->video_params.hpitch =
+			    common->fmt.fmt.pix.bytesperline;
+	}
+
+	ch->vpifparams.video_params.stdid = ch->vpifparams.std_info.stdid;
+}
+
+static void vpif_config_format(struct channel_obj *ch)
+{
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+	common->fmt.fmt.pix.field = V4L2_FIELD_ANY;
+	if (config_params.numbuffers[ch->channel_id] == 0)
+		common->memory = V4L2_MEMORY_USERPTR;
+	else
+		common->memory = V4L2_MEMORY_MMAP;
+
+	common->fmt.fmt.pix.sizeimage =
+			config_params.channel_bufsize[ch->channel_id];
+	common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
+	common->fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+}
+
+static int vpif_check_format(struct channel_obj *ch,
+			     struct v4l2_pix_format *pixfmt)
+{
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	enum v4l2_field field = pixfmt->field;
+	u32 sizeimage, hpitch, vpitch;
+
+	if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P)
+		goto invalid_fmt_exit;
+
+	if (!(VPIF_VALID_FIELD(field)))
+		goto invalid_fmt_exit;
+
+	if (pixfmt->bytesperline <= 0)
+		goto invalid_pitch_exit;
+
+	sizeimage = pixfmt->sizeimage;
+
+	if (vpif_update_resolution(ch))
+		return -EINVAL;
+
+	hpitch = pixfmt->bytesperline;
+	vpitch = sizeimage / (hpitch * 2);
+
+	/* Check for valid value of pitch */
+	if ((hpitch < ch->vpifparams.std_info.width) ||
+	    (vpitch < ch->vpifparams.std_info.height))
+		goto invalid_pitch_exit;
+
+	/* Check for 8 byte alignment */
+	if (!ISALIGNED(hpitch)) {
+		vpif_err("invalid pitch alignment\n");
+		return -EINVAL;
+	}
+	pixfmt->width = common->fmt.fmt.pix.width;
+	pixfmt->height = common->fmt.fmt.pix.height;
+
+	return 0;
+
+invalid_fmt_exit:
+	vpif_err("invalid field format\n");
+	return -EINVAL;
+
+invalid_pitch_exit:
+	vpif_err("invalid pitch\n");
+	return -EINVAL;
+}
+
+static void vpif_config_addr(struct channel_obj *ch, int muxmode)
+{
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+	if (VPIF_CHANNEL3_VIDEO == ch->channel_id) {
+		common->set_addr = ch3_set_videobuf_addr;
+	} else {
+		if (2 == muxmode)
+			common->set_addr = ch2_set_videobuf_addr_yc_nmux;
+		else
+			common->set_addr = ch2_set_videobuf_addr;
+	}
+}
+
+/*
+ * vpif_mmap: It is used to map kernel space buffers into user spaces
+ */
+static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+	struct vpif_fh *fh = filep->private_data;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
+	int ret;
+
+	vpif_dbg(2, debug, "vpif_mmap\n");
+
+	if (mutex_lock_interruptible(&common->lock))
+		return -ERESTARTSYS;
+	ret = vb2_mmap(&common->buffer_queue, vma);
+	mutex_unlock(&common->lock);
+	return ret;
+}
+
+/*
+ * vpif_poll: It is used for select/poll system call
+ */
+static unsigned int vpif_poll(struct file *filep, poll_table *wait)
+{
+	struct vpif_fh *fh = filep->private_data;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	unsigned int res = 0;
+
+	if (common->started) {
+		mutex_lock(&common->lock);
+		res = vb2_poll(&common->buffer_queue, filep, wait);
+		mutex_unlock(&common->lock);
+	}
+
+	return res;
+}
+
+/*
+ * vpif_open: It creates object of file handle structure and stores it in
+ * private_data member of filepointer
+ */
+static int vpif_open(struct file *filep)
+{
+	struct video_device *vdev = video_devdata(filep);
+	struct channel_obj *ch = video_get_drvdata(vdev);
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	struct vpif_fh *fh;
+
+	/* Allocate memory for the file handle object */
+	fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);
+	if (fh == NULL) {
+		vpif_err("unable to allocate memory for file handle object\n");
+		return -ENOMEM;
+	}
+
+	if (mutex_lock_interruptible(&common->lock)) {
+		kfree(fh);
+		return -ERESTARTSYS;
+	}
+	/* store pointer to fh in private_data member of filep */
+	filep->private_data = fh;
+	fh->channel = ch;
+	fh->initialized = 0;
+	if (!ch->initialized) {
+		fh->initialized = 1;
+		ch->initialized = 1;
+		memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));
+	}
+
+	/* Increment channel usrs counter */
+	atomic_inc(&ch->usrs);
+	/* Set io_allowed[VPIF_VIDEO_INDEX] member to false */
+	fh->io_allowed[VPIF_VIDEO_INDEX] = 0;
+	/* Initialize priority of this instance to default priority */
+	fh->prio = V4L2_PRIORITY_UNSET;
+	v4l2_prio_open(&ch->prio, &fh->prio);
+	mutex_unlock(&common->lock);
+
+	return 0;
+}
+
+/*
+ * vpif_release: This function deletes buffer queue, frees the buffers and
+ * the vpif file handle
+ */
+static int vpif_release(struct file *filep)
+{
+	struct vpif_fh *fh = filep->private_data;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+	mutex_lock(&common->lock);
+	/* if this instance is doing IO */
+	if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
+		/* Reset io_usrs member of channel object */
+		common->io_usrs = 0;
+		/* Disable channel */
+		if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
+			enable_channel2(0);
+			channel2_intr_enable(0);
+		}
+		if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) ||
+		    (2 == common->started)) {
+			enable_channel3(0);
+			channel3_intr_enable(0);
+		}
+		common->started = 0;
+
+		/* Free buffers allocated */
+		vb2_queue_release(&common->buffer_queue);
+		vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
+
+		common->numbuffers =
+		    config_params.numbuffers[ch->channel_id];
+	}
+
+	/* Decrement channel usrs counter */
+	atomic_dec(&ch->usrs);
+	/* If this file handle has initialize encoder device, reset it */
+	if (fh->initialized)
+		ch->initialized = 0;
+
+	/* Close the priority */
+	v4l2_prio_close(&ch->prio, fh->prio);
+	filep->private_data = NULL;
+	fh->initialized = 0;
+	mutex_unlock(&common->lock);
+	kfree(fh);
+
+	return 0;
+}
+
+/* functions implementing ioctls */
+/**
+ * vpif_querycap() - QUERYCAP handler
+ * @file: file ptr
+ * @priv: file handle
+ * @cap: ptr to v4l2_capability structure
+ */
+static int vpif_querycap(struct file *file, void  *priv,
+				struct v4l2_capability *cap)
+{
+	struct vpif_display_config *config = vpif_dev->platform_data;
+
+	cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+	strlcpy(cap->driver, "vpif display", sizeof(cap->driver));
+	strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info));
+	strlcpy(cap->card, config->card_name, sizeof(cap->card));
+
+	return 0;
+}
+
+static int vpif_enum_fmt_vid_out(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *fmt)
+{
+	if (fmt->index != 0) {
+		vpif_err("Invalid format index\n");
+		return -EINVAL;
+	}
+
+	/* Fill in the information about format */
+	fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	strcpy(fmt->description, "YCbCr4:2:2 YC Planar");
+	fmt->pixelformat = V4L2_PIX_FMT_YUV422P;
+
+	return 0;
+}
+
+static int vpif_g_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+	/* Check the validity of the buffer type */
+	if (common->fmt.type != fmt->type)
+		return -EINVAL;
+
+	if (vpif_update_resolution(ch))
+		return -EINVAL;
+	*fmt = common->fmt;
+	return 0;
+}
+
+static int vpif_s_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct vpif_fh *fh = priv;
+	struct v4l2_pix_format *pixfmt;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	int ret = 0;
+
+	if ((VPIF_CHANNEL2_VIDEO == ch->channel_id)
+	    || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) {
+		if (!fh->initialized) {
+			vpif_dbg(1, debug, "Channel Busy\n");
+			return -EBUSY;
+		}
+
+		/* Check for the priority */
+		ret = v4l2_prio_check(&ch->prio, fh->prio);
+		if (0 != ret)
+			return ret;
+		fh->initialized = 1;
+	}
+
+	if (common->started) {
+		vpif_dbg(1, debug, "Streaming in progress\n");
+		return -EBUSY;
+	}
+
+	pixfmt = &fmt->fmt.pix;
+	/* Check for valid field format */
+	ret = vpif_check_format(ch, pixfmt);
+	if (ret)
+		return ret;
+
+	/* store the pix format in the channel object */
+	common->fmt.fmt.pix = *pixfmt;
+	/* store the format in the channel object */
+	common->fmt = *fmt;
+	return 0;
+}
+
+static int vpif_try_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+	int ret = 0;
+
+	ret = vpif_check_format(ch, pixfmt);
+	if (ret) {
+		*pixfmt = common->fmt.fmt.pix;
+		pixfmt->sizeimage = pixfmt->width * pixfmt->height * 2;
+	}
+
+	return ret;
+}
+
+static int vpif_reqbufs(struct file *file, void *priv,
+			struct v4l2_requestbuffers *reqbuf)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common;
+	enum v4l2_field field;
+	struct vb2_queue *q;
+	u8 index = 0;
+
+	/* This file handle has not initialized the channel,
+	   It is not allowed to do settings */
+	if ((VPIF_CHANNEL2_VIDEO == ch->channel_id)
+	    || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) {
+		if (!fh->initialized) {
+			vpif_err("Channel Busy\n");
+			return -EBUSY;
+		}
+	}
+
+	if (V4L2_BUF_TYPE_VIDEO_OUTPUT != reqbuf->type)
+		return -EINVAL;
+
+	index = VPIF_VIDEO_INDEX;
+
+	common = &ch->common[index];
+
+	if (common->fmt.type != reqbuf->type || !vpif_dev)
+		return -EINVAL;
+	if (0 != common->io_usrs)
+		return -EBUSY;
+
+	if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		if (common->fmt.fmt.pix.field == V4L2_FIELD_ANY)
+			field = V4L2_FIELD_INTERLACED;
+		else
+			field = common->fmt.fmt.pix.field;
+	} else {
+		field = V4L2_VBI_INTERLACED;
+	}
+	/* Initialize videobuf2 queue as per the buffer type */
+	common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev);
+	if (!common->alloc_ctx) {
+		vpif_err("Failed to get the context\n");
+		return -EINVAL;
+	}
+	q = &common->buffer_queue;
+	q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	q->io_modes = VB2_MMAP | VB2_USERPTR;
+	q->drv_priv = fh;
+	q->ops = &video_qops;
+	q->mem_ops = &vb2_dma_contig_memops;
+	q->buf_struct_size = sizeof(struct vpif_disp_buffer);
+
+	vb2_queue_init(q);
+
+	/* Set io allowed member of file handle to TRUE */
+	fh->io_allowed[index] = 1;
+	/* Increment io usrs member of channel object to 1 */
+	common->io_usrs = 1;
+	/* Store type of memory requested in channel object */
+	common->memory = reqbuf->memory;
+	INIT_LIST_HEAD(&common->dma_queue);
+	/* Allocate buffers */
+	return vb2_reqbufs(&common->buffer_queue, reqbuf);
+}
+
+static int vpif_querybuf(struct file *file, void *priv,
+				struct v4l2_buffer *tbuf)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+	if (common->fmt.type != tbuf->type)
+		return -EINVAL;
+
+	return vb2_querybuf(&common->buffer_queue, tbuf);
+}
+
+static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct vpif_fh *fh = NULL;
+	struct channel_obj *ch = NULL;
+	struct common_obj *common = NULL;
+
+	if (!buf || !priv)
+		return -EINVAL;
+
+	fh = priv;
+	ch = fh->channel;
+	if (!ch)
+		return -EINVAL;
+
+	common = &(ch->common[VPIF_VIDEO_INDEX]);
+	if (common->fmt.type != buf->type)
+		return -EINVAL;
+
+	if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+		vpif_err("fh->io_allowed\n");
+		return -EACCES;
+	}
+
+	return vb2_qbuf(&common->buffer_queue, buf);
+}
+
+static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	int ret = 0;
+
+	if (!(*std_id & VPIF_V4L2_STD))
+		return -EINVAL;
+
+	if (common->started) {
+		vpif_err("streaming in progress\n");
+		return -EBUSY;
+	}
+
+	/* Call encoder subdevice function to set the standard */
+	ch->video.stdid = *std_id;
+	ch->video.dv_preset = V4L2_DV_INVALID;
+	memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
+
+	/* Get the information about the standard */
+	if (vpif_update_resolution(ch))
+		return -EINVAL;
+
+	if ((ch->vpifparams.std_info.width *
+		ch->vpifparams.std_info.height * 2) >
+		config_params.channel_bufsize[ch->channel_id]) {
+		vpif_err("invalid std for this size\n");
+		return -EINVAL;
+	}
+
+	common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width;
+	/* Configure the default format information */
+	vpif_config_format(ch);
+
+	ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,
+						s_std_output, *std_id);
+	if (ret < 0) {
+		vpif_err("Failed to set output standard\n");
+		return ret;
+	}
+
+	ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core,
+							s_std, *std_id);
+	if (ret < 0)
+		vpif_err("Failed to set standard for sub devices\n");
+	return ret;
+}
+
+static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+
+	*std = ch->video.stdid;
+	return 0;
+}
+
+static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+	return vb2_dqbuf(&common->buffer_queue, p,
+					(file->f_flags & O_NONBLOCK));
+}
+
+static int vpif_streamon(struct file *file, void *priv,
+				enum v4l2_buf_type buftype)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id];
+	int ret = 0;
+
+	if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		vpif_err("buffer type not supported\n");
+		return -EINVAL;
+	}
+
+	if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+		vpif_err("fh->io_allowed\n");
+		return -EACCES;
+	}
+
+	/* If Streaming is already started, return error */
+	if (common->started) {
+		vpif_err("channel->started\n");
+		return -EBUSY;
+	}
+
+	if ((ch->channel_id == VPIF_CHANNEL2_VIDEO
+		&& oth_ch->common[VPIF_VIDEO_INDEX].started &&
+		ch->vpifparams.std_info.ycmux_mode == 0)
+		|| ((ch->channel_id == VPIF_CHANNEL3_VIDEO)
+		&& (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) {
+		vpif_err("other channel is using\n");
+		return -EBUSY;
+	}
+
+	ret = vpif_check_format(ch, &common->fmt.fmt.pix);
+	if (ret < 0)
+		return ret;
+
+	/* Call vb2_streamon to start streaming in videobuf2 */
+	ret = vb2_streamon(&common->buffer_queue, buftype);
+	if (ret < 0) {
+		vpif_err("vb2_streamon\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static int vpif_streamoff(struct file *file, void *priv,
+				enum v4l2_buf_type buftype)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	struct vpif_display_config *vpif_config_data =
+					vpif_dev->platform_data;
+
+	if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		vpif_err("buffer type not supported\n");
+		return -EINVAL;
+	}
+
+	if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+		vpif_err("fh->io_allowed\n");
+		return -EACCES;
+	}
+
+	if (!common->started) {
+		vpif_err("channel->started\n");
+		return -EINVAL;
+	}
+
+	if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		/* disable channel */
+		if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
+			if (vpif_config_data->ch2_clip_en)
+				channel2_clipping_enable(0);
+			enable_channel2(0);
+			channel2_intr_enable(0);
+		}
+		if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) ||
+					(2 == common->started)) {
+			if (vpif_config_data->ch3_clip_en)
+				channel3_clipping_enable(0);
+			enable_channel3(0);
+			channel3_intr_enable(0);
+		}
+	}
+
+	common->started = 0;
+	return vb2_streamoff(&common->buffer_queue, buftype);
+}
+
+static int vpif_cropcap(struct file *file, void *priv,
+			struct v4l2_cropcap *crop)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	if (V4L2_BUF_TYPE_VIDEO_OUTPUT != crop->type)
+		return -EINVAL;
+
+	crop->bounds.left = crop->bounds.top = 0;
+	crop->defrect.left = crop->defrect.top = 0;
+	crop->defrect.height = crop->bounds.height = common->height;
+	crop->defrect.width = crop->bounds.width = common->width;
+
+	return 0;
+}
+
+static int vpif_enum_output(struct file *file, void *fh,
+				struct v4l2_output *output)
+{
+
+	struct vpif_display_config *config = vpif_dev->platform_data;
+
+	if (output->index >= config->output_count) {
+		vpif_dbg(1, debug, "Invalid output index\n");
+		return -EINVAL;
+	}
+
+	strcpy(output->name, config->output[output->index]);
+	output->type = V4L2_OUTPUT_TYPE_ANALOG;
+	output->std = VPIF_V4L2_STD;
+
+	return 0;
+}
+
+static int vpif_s_output(struct file *file, void *priv, unsigned int i)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct video_obj *vid_ch = &ch->video;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	int ret = 0;
+
+	if (common->started) {
+		vpif_err("Streaming in progress\n");
+		return -EBUSY;
+	}
+
+	ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,
+							s_routing, 0, i, 0);
+
+	if (ret < 0)
+		vpif_err("Failed to set output standard\n");
+
+	vid_ch->output_id = i;
+	return ret;
+}
+
+static int vpif_g_output(struct file *file, void *priv, unsigned int *i)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct video_obj *vid_ch = &ch->video;
+
+	*i = vid_ch->output_id;
+
+	return 0;
+}
+
+static int vpif_g_priority(struct file *file, void *priv, enum v4l2_priority *p)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+
+	*p = v4l2_prio_max(&ch->prio);
+
+	return 0;
+}
+
+static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+
+	return v4l2_prio_change(&ch->prio, &fh->prio, p);
+}
+
+/**
+ * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_enum_dv_presets(struct file *file, void *priv,
+		struct v4l2_dv_enum_preset *preset)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct video_obj *vid_ch = &ch->video;
+
+	return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
+			video, enum_dv_presets, preset);
+}
+
+/**
+ * vpif_s_dv_presets() - S_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_s_dv_preset(struct file *file, void *priv,
+		struct v4l2_dv_preset *preset)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+	struct video_obj *vid_ch = &ch->video;
+	int ret = 0;
+
+	if (common->started) {
+		vpif_dbg(1, debug, "streaming in progress\n");
+		return -EBUSY;
+	}
+
+	ret = v4l2_prio_check(&ch->prio, fh->prio);
+	if (ret != 0)
+		return ret;
+
+	fh->initialized = 1;
+
+	/* Call encoder subdevice function to set the standard */
+	if (mutex_lock_interruptible(&common->lock))
+		return -ERESTARTSYS;
+
+	ch->video.dv_preset = preset->preset;
+	ch->video.stdid = V4L2_STD_UNKNOWN;
+	memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
+
+	/* Get the information about the standard */
+	if (vpif_update_resolution(ch)) {
+		ret = -EINVAL;
+	} else {
+		/* Configure the default format information */
+		vpif_config_format(ch);
+
+		ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
+				video, s_dv_preset, preset);
+	}
+
+	mutex_unlock(&common->lock);
+
+	return ret;
+}
+/**
+ * vpif_g_dv_presets() - G_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_g_dv_preset(struct file *file, void *priv,
+		struct v4l2_dv_preset *preset)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+
+	preset->preset = ch->video.dv_preset;
+
+	return 0;
+}
+/**
+ * vpif_s_dv_timings() - S_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_s_dv_timings(struct file *file, void *priv,
+		struct v4l2_dv_timings *timings)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct vpif_params *vpifparams = &ch->vpifparams;
+	struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+	struct video_obj *vid_ch = &ch->video;
+	struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+	int ret;
+
+	if (timings->type != V4L2_DV_BT_656_1120) {
+		vpif_dbg(2, debug, "Timing type not defined\n");
+		return -EINVAL;
+	}
+
+	/* Configure subdevice timings, if any */
+	ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
+			video, s_dv_timings, timings);
+	if (ret == -ENOIOCTLCMD) {
+		vpif_dbg(2, debug, "Custom DV timings not supported by "
+				"subdevice\n");
+		return -EINVAL;
+	}
+	if (ret < 0) {
+		vpif_dbg(2, debug, "Error setting custom DV timings\n");
+		return ret;
+	}
+
+	if (!(timings->bt.width && timings->bt.height &&
+				(timings->bt.hbackporch ||
+				 timings->bt.hfrontporch ||
+				 timings->bt.hsync) &&
+				timings->bt.vfrontporch &&
+				(timings->bt.vbackporch ||
+				 timings->bt.vsync))) {
+		vpif_dbg(2, debug, "Timings for width, height, "
+				"horizontal back porch, horizontal sync, "
+				"horizontal front porch, vertical back porch, "
+				"vertical sync and vertical back porch "
+				"must be defined\n");
+		return -EINVAL;
+	}
+
+	*bt = timings->bt;
+
+	/* Configure video port timings */
+
+	std_info->eav2sav = bt->hbackporch + bt->hfrontporch +
+		bt->hsync - 8;
+	std_info->sav2eav = bt->width;
+
+	std_info->l1 = 1;
+	std_info->l3 = bt->vsync + bt->vbackporch + 1;
+
+	if (bt->interlaced) {
+		if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) {
+			std_info->vsize = bt->height * 2 +
+				bt->vfrontporch + bt->vsync + bt->vbackporch +
+				bt->il_vfrontporch + bt->il_vsync +
+				bt->il_vbackporch;
+			std_info->l5 = std_info->vsize/2 -
+				(bt->vfrontporch - 1);
+			std_info->l7 = std_info->vsize/2 + 1;
+			std_info->l9 = std_info->l7 + bt->il_vsync +
+				bt->il_vbackporch + 1;
+			std_info->l11 = std_info->vsize -
+				(bt->il_vfrontporch - 1);
+		} else {
+			vpif_dbg(2, debug, "Required timing values for "
+					"interlaced BT format missing\n");
+			return -EINVAL;
+		}
+	} else {
+		std_info->vsize = bt->height + bt->vfrontporch +
+			bt->vsync + bt->vbackporch;
+		std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);
+	}
+	strncpy(std_info->name, "Custom timings BT656/1120",
+			VPIF_MAX_NAME);
+	std_info->width = bt->width;
+	std_info->height = bt->height;
+	std_info->frm_fmt = bt->interlaced ? 0 : 1;
+	std_info->ycmux_mode = 0;
+	std_info->capture_format = 0;
+	std_info->vbi_supported = 0;
+	std_info->hd_sd = 1;
+	std_info->stdid = 0;
+	std_info->dv_preset = V4L2_DV_INVALID;
+
+	vid_ch->stdid = 0;
+	vid_ch->dv_preset = V4L2_DV_INVALID;
+
+	return 0;
+}
+
+/**
+ * vpif_g_dv_timings() - G_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_g_dv_timings(struct file *file, void *priv,
+		struct v4l2_dv_timings *timings)
+{
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct video_obj *vid_ch = &ch->video;
+	struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+
+	timings->bt = *bt;
+
+	return 0;
+}
+
+/*
+ * vpif_g_chip_ident() - Identify the chip
+ * @file: file ptr
+ * @priv: file handle
+ * @chip: chip identity
+ *
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_g_chip_ident(struct file *file, void *priv,
+		struct v4l2_dbg_chip_ident *chip)
+{
+	chip->ident = V4L2_IDENT_NONE;
+	chip->revision = 0;
+	if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+			chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) {
+		vpif_dbg(2, debug, "match_type is invalid.\n");
+		return -EINVAL;
+	}
+
+	return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core,
+			g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/*
+ * vpif_dbg_g_register() - Read register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be read
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_dbg_g_register(struct file *file, void *priv,
+		struct v4l2_dbg_register *reg){
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct video_obj *vid_ch = &ch->video;
+
+	return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core,
+			g_register, reg);
+}
+
+/*
+ * vpif_dbg_s_register() - Write to register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be modified
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if write operations fails.
+ */
+static int vpif_dbg_s_register(struct file *file, void *priv,
+		struct v4l2_dbg_register *reg){
+	struct vpif_fh *fh = priv;
+	struct channel_obj *ch = fh->channel;
+	struct video_obj *vid_ch = &ch->video;
+
+	return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core,
+			s_register, reg);
+}
+#endif
+
+/*
+ * vpif_log_status() - Status information
+ * @file: file ptr
+ * @priv: file handle
+ *
+ * Returns zero.
+ */
+static int vpif_log_status(struct file *filep, void *priv)
+{
+	/* status for sub devices */
+	v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status);
+
+	return 0;
+}
+
+/* vpif display ioctl operations */
+static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
+	.vidioc_querycap        	= vpif_querycap,
+	.vidioc_g_priority		= vpif_g_priority,
+	.vidioc_s_priority		= vpif_s_priority,
+	.vidioc_enum_fmt_vid_out	= vpif_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out  		= vpif_g_fmt_vid_out,
+	.vidioc_s_fmt_vid_out   	= vpif_s_fmt_vid_out,
+	.vidioc_try_fmt_vid_out 	= vpif_try_fmt_vid_out,
+	.vidioc_reqbufs         	= vpif_reqbufs,
+	.vidioc_querybuf        	= vpif_querybuf,
+	.vidioc_qbuf            	= vpif_qbuf,
+	.vidioc_dqbuf           	= vpif_dqbuf,
+	.vidioc_streamon        	= vpif_streamon,
+	.vidioc_streamoff       	= vpif_streamoff,
+	.vidioc_s_std           	= vpif_s_std,
+	.vidioc_g_std			= vpif_g_std,
+	.vidioc_enum_output		= vpif_enum_output,
+	.vidioc_s_output		= vpif_s_output,
+	.vidioc_g_output		= vpif_g_output,
+	.vidioc_cropcap         	= vpif_cropcap,
+	.vidioc_enum_dv_presets         = vpif_enum_dv_presets,
+	.vidioc_s_dv_preset             = vpif_s_dv_preset,
+	.vidioc_g_dv_preset             = vpif_g_dv_preset,
+	.vidioc_s_dv_timings            = vpif_s_dv_timings,
+	.vidioc_g_dv_timings            = vpif_g_dv_timings,
+	.vidioc_g_chip_ident		= vpif_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register		= vpif_dbg_g_register,
+	.vidioc_s_register		= vpif_dbg_s_register,
+#endif
+	.vidioc_log_status		= vpif_log_status,
+};
+
+static const struct v4l2_file_operations vpif_fops = {
+	.owner		= THIS_MODULE,
+	.open		= vpif_open,
+	.release	= vpif_release,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= vpif_mmap,
+	.poll		= vpif_poll
+};
+
+static struct video_device vpif_video_template = {
+	.name		= "vpif",
+	.fops		= &vpif_fops,
+	.ioctl_ops	= &vpif_ioctl_ops,
+	.tvnorms	= VPIF_V4L2_STD,
+	.current_norm	= V4L2_STD_625_50,
+
+};
+
+/*Configure the channels, buffer sizei, request irq */
+static int initialize_vpif(void)
+{
+	int free_channel_objects_index;
+	int free_buffer_channel_index;
+	int free_buffer_index;
+	int err = 0, i, j;
+
+	/* Default number of buffers should be 3 */
+	if ((ch2_numbuffers > 0) &&
+	    (ch2_numbuffers < config_params.min_numbuffers))
+		ch2_numbuffers = config_params.min_numbuffers;
+	if ((ch3_numbuffers > 0) &&
+	    (ch3_numbuffers < config_params.min_numbuffers))
+		ch3_numbuffers = config_params.min_numbuffers;
+
+	/* Set buffer size to min buffers size if invalid buffer size is
+	 * given */
+	if (ch2_bufsize < config_params.min_bufsize[VPIF_CHANNEL2_VIDEO])
+		ch2_bufsize =
+		    config_params.min_bufsize[VPIF_CHANNEL2_VIDEO];
+	if (ch3_bufsize < config_params.min_bufsize[VPIF_CHANNEL3_VIDEO])
+		ch3_bufsize =
+		    config_params.min_bufsize[VPIF_CHANNEL3_VIDEO];
+
+	config_params.numbuffers[VPIF_CHANNEL2_VIDEO] = ch2_numbuffers;
+
+	if (ch2_numbuffers) {
+		config_params.channel_bufsize[VPIF_CHANNEL2_VIDEO] =
+							ch2_bufsize;
+	}
+	config_params.numbuffers[VPIF_CHANNEL3_VIDEO] = ch3_numbuffers;
+
+	if (ch3_numbuffers) {
+		config_params.channel_bufsize[VPIF_CHANNEL3_VIDEO] =
+							ch3_bufsize;
+	}
+
+	/* Allocate memory for six channel objects */
+	for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+		vpif_obj.dev[i] =
+		    kzalloc(sizeof(struct channel_obj), GFP_KERNEL);
+		/* If memory allocation fails, return error */
+		if (!vpif_obj.dev[i]) {
+			free_channel_objects_index = i;
+			err = -ENOMEM;
+			goto vpif_init_free_channel_objects;
+		}
+	}
+
+	free_channel_objects_index = VPIF_DISPLAY_MAX_DEVICES;
+	free_buffer_channel_index = VPIF_DISPLAY_NUM_CHANNELS;
+	free_buffer_index = config_params.numbuffers[i - 1];
+
+	return 0;
+
+vpif_init_free_channel_objects:
+	for (j = 0; j < free_channel_objects_index; j++)
+		kfree(vpif_obj.dev[j]);
+	return err;
+}
+
+/*
+ * vpif_probe: This function creates device entries by register itself to the
+ * V4L2 driver and initializes fields of each channel objects
+ */
+static __init int vpif_probe(struct platform_device *pdev)
+{
+	struct vpif_subdev_info *subdevdata;
+	struct vpif_display_config *config;
+	int i, j = 0, k, q, m, err = 0;
+	struct i2c_adapter *i2c_adap;
+	struct common_obj *common;
+	struct channel_obj *ch;
+	struct video_device *vfd;
+	struct resource *res;
+	int subdev_count;
+	size_t size;
+
+	vpif_dev = &pdev->dev;
+	err = initialize_vpif();
+
+	if (err) {
+		v4l2_err(vpif_dev->driver, "Error initializing vpif\n");
+		return err;
+	}
+
+	err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev);
+	if (err) {
+		v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n");
+		return err;
+	}
+
+	k = 0;
+	while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) {
+		for (i = res->start; i <= res->end; i++) {
+			if (request_irq(i, vpif_channel_isr, IRQF_SHARED,
+					"VPIF_Display",
+				(void *)(&vpif_obj.dev[k]->channel_id))) {
+				err = -EBUSY;
+				goto vpif_int_err;
+			}
+		}
+		k++;
+	}
+
+	for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+
+		/* Get the pointer to the channel object */
+		ch = vpif_obj.dev[i];
+
+		/* Allocate memory for video device */
+		vfd = video_device_alloc();
+		if (vfd == NULL) {
+			for (j = 0; j < i; j++) {
+				ch = vpif_obj.dev[j];
+				video_device_release(ch->video_dev);
+			}
+			err = -ENOMEM;
+			goto vpif_int_err;
+		}
+
+		/* Initialize field of video device */
+		*vfd = vpif_video_template;
+		vfd->v4l2_dev = &vpif_obj.v4l2_dev;
+		vfd->release = video_device_release;
+		snprintf(vfd->name, sizeof(vfd->name),
+			 "VPIF_Display_DRIVER_V%s",
+			 VPIF_DISPLAY_VERSION);
+
+		/* Set video_dev to the video device */
+		ch->video_dev = vfd;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res) {
+		size = resource_size(res);
+		/* The resources are divided into two equal memory and when
+		 * we have HD output we can add them together
+		 */
+		for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {
+			ch = vpif_obj.dev[j];
+			ch->channel_id = j;
+
+			/* only enabled if second resource exists */
+			config_params.video_limit[ch->channel_id] = 0;
+			if (size)
+				config_params.video_limit[ch->channel_id] =
+									size/2;
+		}
+	}
+
+	for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {
+		ch = vpif_obj.dev[j];
+		/* Initialize field of the channel objects */
+		atomic_set(&ch->usrs, 0);
+		for (k = 0; k < VPIF_NUMOBJECTS; k++) {
+			ch->common[k].numbuffers = 0;
+			common = &ch->common[k];
+			common->io_usrs = 0;
+			common->started = 0;
+			spin_lock_init(&common->irqlock);
+			mutex_init(&common->lock);
+			common->numbuffers = 0;
+			common->set_addr = NULL;
+			common->ytop_off = common->ybtm_off = 0;
+			common->ctop_off = common->cbtm_off = 0;
+			common->cur_frm = common->next_frm = NULL;
+			memset(&common->fmt, 0, sizeof(common->fmt));
+			common->numbuffers = config_params.numbuffers[k];
+
+		}
+		ch->initialized = 0;
+		ch->channel_id = j;
+		if (j < 2)
+			ch->common[VPIF_VIDEO_INDEX].numbuffers =
+			    config_params.numbuffers[ch->channel_id];
+		else
+			ch->common[VPIF_VIDEO_INDEX].numbuffers = 0;
+
+		memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));
+
+		/* Initialize prio member of channel object */
+		v4l2_prio_init(&ch->prio);
+		ch->common[VPIF_VIDEO_INDEX].fmt.type =
+						V4L2_BUF_TYPE_VIDEO_OUTPUT;
+		ch->video_dev->lock = &common->lock;
+
+		/* register video device */
+		vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n",
+				(int)ch, (int)&ch->video_dev);
+
+		err = video_register_device(ch->video_dev,
+					  VFL_TYPE_GRABBER, (j ? 3 : 2));
+		if (err < 0)
+			goto probe_out;
+
+		video_set_drvdata(ch->video_dev, ch);
+	}
+
+	i2c_adap = i2c_get_adapter(1);
+	config = pdev->dev.platform_data;
+	subdev_count = config->subdev_count;
+	subdevdata = config->subdevinfo;
+	vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count,
+								GFP_KERNEL);
+	if (vpif_obj.sd == NULL) {
+		vpif_err("unable to allocate memory for subdevice pointers\n");
+		err = -ENOMEM;
+		goto probe_out;
+	}
+
+	for (i = 0; i < subdev_count; i++) {
+		vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
+						i2c_adap,
+						&subdevdata[i].board_info,
+						NULL);
+		if (!vpif_obj.sd[i]) {
+			vpif_err("Error registering v4l2 subdevice\n");
+			goto probe_subdev_out;
+		}
+
+		if (vpif_obj.sd[i])
+			vpif_obj.sd[i]->grp_id = 1 << i;
+	}
+
+	v4l2_info(&vpif_obj.v4l2_dev,
+			" VPIF display driver initialized\n");
+	return 0;
+
+probe_subdev_out:
+	kfree(vpif_obj.sd);
+probe_out:
+	for (k = 0; k < j; k++) {
+		ch = vpif_obj.dev[k];
+		video_unregister_device(ch->video_dev);
+		video_device_release(ch->video_dev);
+		ch->video_dev = NULL;
+	}
+vpif_int_err:
+	v4l2_device_unregister(&vpif_obj.v4l2_dev);
+	vpif_err("VPIF IRQ request failed\n");
+	for (q = k; k >= 0; k--) {
+		for (m = i; m >= res->start; m--)
+			free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id));
+		res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1);
+		m = res->end;
+	}
+
+	return err;
+}
+
+/*
+ * vpif_remove: It un-register channels from V4L2 driver
+ */
+static int vpif_remove(struct platform_device *device)
+{
+	struct channel_obj *ch;
+	int i;
+
+	v4l2_device_unregister(&vpif_obj.v4l2_dev);
+
+	/* un-register device */
+	for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+		/* Get the pointer to the channel object */
+		ch = vpif_obj.dev[i];
+		/* Unregister video device */
+		video_unregister_device(ch->video_dev);
+
+		ch->video_dev = NULL;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int vpif_suspend(struct device *dev)
+{
+	struct common_obj *common;
+	struct channel_obj *ch;
+	int i;
+
+	for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+		/* Get the pointer to the channel object */
+		ch = vpif_obj.dev[i];
+		common = &ch->common[VPIF_VIDEO_INDEX];
+		mutex_lock(&common->lock);
+		if (atomic_read(&ch->usrs) && common->io_usrs) {
+			/* Disable channel */
+			if (ch->channel_id == VPIF_CHANNEL2_VIDEO) {
+				enable_channel2(0);
+				channel2_intr_enable(0);
+			}
+			if (ch->channel_id == VPIF_CHANNEL3_VIDEO ||
+					common->started == 2) {
+				enable_channel3(0);
+				channel3_intr_enable(0);
+			}
+		}
+		mutex_unlock(&common->lock);
+	}
+
+	return 0;
+}
+
+static int vpif_resume(struct device *dev)
+{
+
+	struct common_obj *common;
+	struct channel_obj *ch;
+	int i;
+
+	for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+		/* Get the pointer to the channel object */
+		ch = vpif_obj.dev[i];
+		common = &ch->common[VPIF_VIDEO_INDEX];
+		mutex_lock(&common->lock);
+		if (atomic_read(&ch->usrs) && common->io_usrs) {
+			/* Enable channel */
+			if (ch->channel_id == VPIF_CHANNEL2_VIDEO) {
+				enable_channel2(1);
+				channel2_intr_enable(1);
+			}
+			if (ch->channel_id == VPIF_CHANNEL3_VIDEO ||
+					common->started == 2) {
+				enable_channel3(1);
+				channel3_intr_enable(1);
+			}
+		}
+		mutex_unlock(&common->lock);
+	}
+
+	return 0;
+}
+
+static const struct dev_pm_ops vpif_pm = {
+	.suspend        = vpif_suspend,
+	.resume         = vpif_resume,
+};
+
+#define vpif_pm_ops (&vpif_pm)
+#else
+#define vpif_pm_ops NULL
+#endif
+
+static __refdata struct platform_driver vpif_driver = {
+	.driver	= {
+			.name	= "vpif_display",
+			.owner	= THIS_MODULE,
+			.pm	= vpif_pm_ops,
+	},
+	.probe	= vpif_probe,
+	.remove	= vpif_remove,
+};
+
+static __init int vpif_init(void)
+{
+	return platform_driver_register(&vpif_driver);
+}
+
+/*
+ * vpif_cleanup: This function un-registers device and driver to the kernel,
+ * frees requested irq handler and de-allocates memory allocated for channel
+ * objects.
+ */
+static void vpif_cleanup(void)
+{
+	struct platform_device *pdev;
+	struct resource *res;
+	int irq_num;
+	int i = 0;
+
+	pdev = container_of(vpif_dev, struct platform_device, dev);
+
+	while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) {
+		for (irq_num = res->start; irq_num <= res->end; irq_num++)
+			free_irq(irq_num,
+				 (void *)(&vpif_obj.dev[i]->channel_id));
+		i++;
+	}
+
+	platform_driver_unregister(&vpif_driver);
+	kfree(vpif_obj.sd);
+	for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++)
+		kfree(vpif_obj.dev[i]);
+}
+
+module_init(vpif_init);
+module_exit(vpif_cleanup);
diff --git a/drivers/media/platform/davinci/vpif_display.h b/drivers/media/platform/davinci/vpif_display.h
new file mode 100644
index 0000000..8967ffb
--- /dev/null
+++ b/drivers/media/platform/davinci/vpif_display.h
@@ -0,0 +1,181 @@
+/*
+ * VPIF display header file
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef DAVINCIHD_DISPLAY_H
+#define DAVINCIHD_DISPLAY_H
+
+/* Header files */
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf-core.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/davinci/vpif_types.h>
+
+#include "vpif.h"
+
+/* Macros */
+#define VPIF_DISPLAY_VERSION	"0.0.2"
+
+#define VPIF_VALID_FIELD(field) \
+	(((V4L2_FIELD_ANY == field) || (V4L2_FIELD_NONE == field)) || \
+	(((V4L2_FIELD_INTERLACED == field) || (V4L2_FIELD_SEQ_TB == field)) || \
+	(V4L2_FIELD_SEQ_BT == field)))
+
+#define VPIF_DISPLAY_MAX_DEVICES	(2)
+#define VPIF_SLICED_BUF_SIZE		(256)
+#define VPIF_SLICED_MAX_SERVICES	(3)
+#define VPIF_VIDEO_INDEX		(0)
+#define VPIF_VBI_INDEX			(1)
+#define VPIF_HBI_INDEX			(2)
+
+/* Setting it to 1 as HBI/VBI support yet to be added , else 3*/
+#define VPIF_NUMOBJECTS	(1)
+
+/* Macros */
+#define ISALIGNED(a)    (0 == ((a) & 7))
+
+/* enumerated data types */
+/* Enumerated data type to give id to each device per channel */
+enum vpif_channel_id {
+	VPIF_CHANNEL2_VIDEO = 0,	/* Channel2 Video */
+	VPIF_CHANNEL3_VIDEO,		/* Channel3 Video */
+};
+
+/* structures */
+
+struct video_obj {
+	enum v4l2_field buf_field;
+	u32 latest_only;		/* indicate whether to return
+					 * most recent displayed frame only */
+	v4l2_std_id stdid;		/* Currently selected or default
+					 * standard */
+	u32 dv_preset;
+	struct v4l2_bt_timings bt_timings;
+	u32 output_id;			/* Current output id */
+};
+
+struct vbi_obj {
+	int num_services;
+	struct vpif_vbi_params vbiparams;	/* vpif parameters for the raw
+						 * vbi data */
+};
+
+struct vpif_disp_buffer {
+	struct vb2_buffer vb;
+	struct list_head list;
+};
+
+struct common_obj {
+	/* Buffer specific parameters */
+	u8 *fbuffers[VIDEO_MAX_FRAME];		/* List of buffer pointers for
+						 * storing frames */
+	u32 numbuffers;				/* number of buffers */
+	struct vpif_disp_buffer *cur_frm;	/* Pointer pointing to current
+						 * vb2_buffer */
+	struct vpif_disp_buffer *next_frm;	/* Pointer pointing to next
+						 * vb2_buffer */
+	enum v4l2_memory memory;		/* This field keeps track of
+						 * type of buffer exchange
+						 * method user has selected */
+	struct v4l2_format fmt;			/* Used to store the format */
+	struct vb2_queue buffer_queue;		/* Buffer queue used in
+						 * video-buf */
+	/* allocator-specific contexts for each plane */
+	struct vb2_alloc_ctx *alloc_ctx;
+
+	struct list_head dma_queue;		/* Queue of filled frames */
+	spinlock_t irqlock;			/* Used in video-buf */
+
+	/* channel specific parameters */
+	struct mutex lock;			/* lock used to access this
+						 * structure */
+	u32 io_usrs;				/* number of users performing
+						 * IO */
+	u8 started;				/* Indicates whether streaming
+						 * started */
+	u32 ytop_off;				/* offset of Y top from the
+						 * starting of the buffer */
+	u32 ybtm_off;				/* offset of Y bottom from the
+						 * starting of the buffer */
+	u32 ctop_off;				/* offset of C top from the
+						 * starting of the buffer */
+	u32 cbtm_off;				/* offset of C bottom from the
+						 * starting of the buffer */
+	/* Function pointer to set the addresses */
+	void (*set_addr) (unsigned long, unsigned long,
+				unsigned long, unsigned long);
+	u32 height;
+	u32 width;
+};
+
+struct channel_obj {
+	/* V4l2 specific parameters */
+	struct video_device *video_dev;	/* Identifies video device for
+					 * this channel */
+	struct v4l2_prio_state prio;	/* Used to keep track of state of
+					 * the priority */
+	atomic_t usrs;			/* number of open instances of
+					 * the channel */
+	u32 field_id;			/* Indicates id of the field
+					 * which is being displayed */
+	u8 initialized;			/* flag to indicate whether
+					 * encoder is initialized */
+
+	enum vpif_channel_id channel_id;/* Identifies channel */
+	struct vpif_params vpifparams;
+	struct common_obj common[VPIF_NUMOBJECTS];
+	struct video_obj video;
+	struct vbi_obj vbi;
+};
+
+/* File handle structure */
+struct vpif_fh {
+	struct channel_obj *channel;	/* pointer to channel object for
+					 * opened device */
+	u8 io_allowed[VPIF_NUMOBJECTS];	/* Indicates whether this file handle
+					 * is doing IO */
+	enum v4l2_priority prio;	/* Used to keep track priority of
+					 * this instance */
+	u8 initialized;			/* Used to keep track of whether this
+					 * file handle has initialized
+					 * channel or not */
+};
+
+/* vpif device structure */
+struct vpif_device {
+	struct v4l2_device v4l2_dev;
+	struct channel_obj *dev[VPIF_DISPLAY_NUM_CHANNELS];
+	struct v4l2_subdev **sd;
+
+};
+
+struct vpif_config_params {
+	u32 min_bufsize[VPIF_DISPLAY_NUM_CHANNELS];
+	u32 channel_bufsize[VPIF_DISPLAY_NUM_CHANNELS];
+	u8 numbuffers[VPIF_DISPLAY_NUM_CHANNELS];
+	u32 video_limit[VPIF_DISPLAY_NUM_CHANNELS];
+	u8 min_numbuffers;
+};
+
+/* Struct which keeps track of the line numbers for the sliced vbi service */
+struct vpif_service_line {
+	u16 service_id;
+	u16 service_line[2];
+	u16 enc_service_id;
+	u8 bytestowrite;
+};
+
+#endif				/* DAVINCIHD_DISPLAY_H */
diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c
new file mode 100644
index 0000000..146e4b0
--- /dev/null
+++ b/drivers/media/platform/davinci/vpss.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * common vpss system module platform driver for all video drivers.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/compiler.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include <media/davinci/vpss.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("VPSS Driver");
+MODULE_AUTHOR("Texas Instruments");
+
+/* DM644x defines */
+#define DM644X_SBL_PCR_VPSS		(4)
+
+#define DM355_VPSSBL_INTSEL		0x10
+#define DM355_VPSSBL_EVTSEL		0x14
+/* vpss BL register offsets */
+#define DM355_VPSSBL_CCDCMUX		0x1c
+/* vpss CLK register offsets */
+#define DM355_VPSSCLK_CLKCTRL		0x04
+/* masks and shifts */
+#define VPSS_HSSISEL_SHIFT		4
+/*
+ * VDINT0 - vpss_int0, VDINT1 - vpss_int1, H3A - vpss_int4,
+ * IPIPE_INT1_SDR - vpss_int5
+ */
+#define DM355_VPSSBL_INTSEL_DEFAULT	0xff83ff10
+/* VENCINT - vpss_int8 */
+#define DM355_VPSSBL_EVTSEL_DEFAULT	0x4
+
+#define DM365_ISP5_PCCR 		0x04
+#define DM365_ISP5_INTSEL1		0x10
+#define DM365_ISP5_INTSEL2		0x14
+#define DM365_ISP5_INTSEL3		0x18
+#define DM365_ISP5_CCDCMUX 		0x20
+#define DM365_ISP5_PG_FRAME_SIZE 	0x28
+#define DM365_VPBE_CLK_CTRL 		0x00
+/*
+ * vpss interrupts. VDINT0 - vpss_int0, VDINT1 - vpss_int1,
+ * AF - vpss_int3
+ */
+#define DM365_ISP5_INTSEL1_DEFAULT	0x0b1f0100
+/* AEW - vpss_int6, RSZ_INT_DMA - vpss_int5 */
+#define DM365_ISP5_INTSEL2_DEFAULT	0x1f0a0f1f
+/* VENC - vpss_int8 */
+#define DM365_ISP5_INTSEL3_DEFAULT	0x00000015
+
+/* masks and shifts for DM365*/
+#define DM365_CCDC_PG_VD_POL_SHIFT 	0
+#define DM365_CCDC_PG_HD_POL_SHIFT 	1
+
+#define CCD_SRC_SEL_MASK		(BIT_MASK(5) | BIT_MASK(4))
+#define CCD_SRC_SEL_SHIFT		4
+
+/* Different SoC platforms supported by this driver */
+enum vpss_platform_type {
+	DM644X,
+	DM355,
+	DM365,
+};
+
+/*
+ * vpss operations. Depends on platform. Not all functions are available
+ * on all platforms. The api, first check if a functio is available before
+ * invoking it. In the probe, the function ptrs are initialized based on
+ * vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc.
+ */
+struct vpss_hw_ops {
+	/* enable clock */
+	int (*enable_clock)(enum vpss_clock_sel clock_sel, int en);
+	/* select input to ccdc */
+	void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel);
+	/* clear wbl overflow bit */
+	int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel);
+};
+
+/* vpss configuration */
+struct vpss_oper_config {
+	__iomem void *vpss_regs_base0;
+	__iomem void *vpss_regs_base1;
+	enum vpss_platform_type platform;
+	spinlock_t vpss_lock;
+	struct vpss_hw_ops hw_ops;
+};
+
+static struct vpss_oper_config oper_cfg;
+
+/* register access routines */
+static inline u32 bl_regr(u32 offset)
+{
+	return __raw_readl(oper_cfg.vpss_regs_base0 + offset);
+}
+
+static inline void bl_regw(u32 val, u32 offset)
+{
+	__raw_writel(val, oper_cfg.vpss_regs_base0 + offset);
+}
+
+static inline u32 vpss_regr(u32 offset)
+{
+	return __raw_readl(oper_cfg.vpss_regs_base1 + offset);
+}
+
+static inline void vpss_regw(u32 val, u32 offset)
+{
+	__raw_writel(val, oper_cfg.vpss_regs_base1 + offset);
+}
+
+/* For DM365 only */
+static inline u32 isp5_read(u32 offset)
+{
+	return __raw_readl(oper_cfg.vpss_regs_base0 + offset);
+}
+
+/* For DM365 only */
+static inline void isp5_write(u32 val, u32 offset)
+{
+	__raw_writel(val, oper_cfg.vpss_regs_base0 + offset);
+}
+
+static void dm365_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
+{
+	u32 temp = isp5_read(DM365_ISP5_CCDCMUX) & ~CCD_SRC_SEL_MASK;
+
+	/* if we are using pattern generator, enable it */
+	if (src_sel == VPSS_PGLPBK || src_sel == VPSS_CCDCPG)
+		temp |= 0x08;
+
+	temp |= (src_sel << CCD_SRC_SEL_SHIFT);
+	isp5_write(temp, DM365_ISP5_CCDCMUX);
+}
+
+static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
+{
+	bl_regw(src_sel << VPSS_HSSISEL_SHIFT, DM355_VPSSBL_CCDCMUX);
+}
+
+int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
+{
+	if (!oper_cfg.hw_ops.select_ccdc_source)
+		return -EINVAL;
+
+	oper_cfg.hw_ops.select_ccdc_source(src_sel);
+	return 0;
+}
+EXPORT_SYMBOL(vpss_select_ccdc_source);
+
+static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
+{
+	u32 mask = 1, val;
+
+	if (wbl_sel < VPSS_PCR_AEW_WBL_0 ||
+	    wbl_sel > VPSS_PCR_CCDC_WBL_O)
+		return -EINVAL;
+
+	/* writing a 0 clear the overflow */
+	mask = ~(mask << wbl_sel);
+	val = bl_regr(DM644X_SBL_PCR_VPSS) & mask;
+	bl_regw(val, DM644X_SBL_PCR_VPSS);
+	return 0;
+}
+
+int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
+{
+	if (!oper_cfg.hw_ops.clear_wbl_overflow)
+		return -EINVAL;
+
+	return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel);
+}
+EXPORT_SYMBOL(vpss_clear_wbl_overflow);
+
+/*
+ *  dm355_enable_clock - Enable VPSS Clock
+ *  @clock_sel: CLock to be enabled/disabled
+ *  @en: enable/disable flag
+ *
+ *  This is called to enable or disable a vpss clock
+ */
+static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en)
+{
+	unsigned long flags;
+	u32 utemp, mask = 0x1, shift = 0;
+
+	switch (clock_sel) {
+	case VPSS_VPBE_CLOCK:
+		/* nothing since lsb */
+		break;
+	case VPSS_VENC_CLOCK_SEL:
+		shift = 2;
+		break;
+	case VPSS_CFALD_CLOCK:
+		shift = 3;
+		break;
+	case VPSS_H3A_CLOCK:
+		shift = 4;
+		break;
+	case VPSS_IPIPE_CLOCK:
+		shift = 5;
+		break;
+	case VPSS_CCDC_CLOCK:
+		shift = 6;
+		break;
+	default:
+		printk(KERN_ERR "dm355_enable_clock:"
+				" Invalid selector: %d\n", clock_sel);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&oper_cfg.vpss_lock, flags);
+	utemp = vpss_regr(DM355_VPSSCLK_CLKCTRL);
+	if (!en)
+		utemp &= ~(mask << shift);
+	else
+		utemp |= (mask << shift);
+
+	vpss_regw(utemp, DM355_VPSSCLK_CLKCTRL);
+	spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags);
+	return 0;
+}
+
+static int dm365_enable_clock(enum vpss_clock_sel clock_sel, int en)
+{
+	unsigned long flags;
+	u32 utemp, mask = 0x1, shift = 0, offset = DM365_ISP5_PCCR;
+	u32 (*read)(u32 offset) = isp5_read;
+	void(*write)(u32 val, u32 offset) = isp5_write;
+
+	switch (clock_sel) {
+	case VPSS_BL_CLOCK:
+		break;
+	case VPSS_CCDC_CLOCK:
+		shift = 1;
+		break;
+	case VPSS_H3A_CLOCK:
+		shift = 2;
+		break;
+	case VPSS_RSZ_CLOCK:
+		shift = 3;
+		break;
+	case VPSS_IPIPE_CLOCK:
+		shift = 4;
+		break;
+	case VPSS_IPIPEIF_CLOCK:
+		shift = 5;
+		break;
+	case VPSS_PCLK_INTERNAL:
+		shift = 6;
+		break;
+	case VPSS_PSYNC_CLOCK_SEL:
+		shift = 7;
+		break;
+	case VPSS_VPBE_CLOCK:
+		read = vpss_regr;
+		write = vpss_regw;
+		offset = DM365_VPBE_CLK_CTRL;
+		break;
+	case VPSS_VENC_CLOCK_SEL:
+		shift = 2;
+		read = vpss_regr;
+		write = vpss_regw;
+		offset = DM365_VPBE_CLK_CTRL;
+		break;
+	case VPSS_LDC_CLOCK:
+		shift = 3;
+		read = vpss_regr;
+		write = vpss_regw;
+		offset = DM365_VPBE_CLK_CTRL;
+		break;
+	case VPSS_FDIF_CLOCK:
+		shift = 4;
+		read = vpss_regr;
+		write = vpss_regw;
+		offset = DM365_VPBE_CLK_CTRL;
+		break;
+	case VPSS_OSD_CLOCK_SEL:
+		shift = 6;
+		read = vpss_regr;
+		write = vpss_regw;
+		offset = DM365_VPBE_CLK_CTRL;
+		break;
+	case VPSS_LDC_CLOCK_SEL:
+		shift = 7;
+		read = vpss_regr;
+		write = vpss_regw;
+		offset = DM365_VPBE_CLK_CTRL;
+		break;
+	default:
+		printk(KERN_ERR "dm365_enable_clock: Invalid selector: %d\n",
+		       clock_sel);
+		return -1;
+	}
+
+	spin_lock_irqsave(&oper_cfg.vpss_lock, flags);
+	utemp = read(offset);
+	if (!en) {
+		mask = ~mask;
+		utemp &= (mask << shift);
+	} else
+		utemp |= (mask << shift);
+
+	write(utemp, offset);
+	spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags);
+
+	return 0;
+}
+
+int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en)
+{
+	if (!oper_cfg.hw_ops.enable_clock)
+		return -EINVAL;
+
+	return oper_cfg.hw_ops.enable_clock(clock_sel, en);
+}
+EXPORT_SYMBOL(vpss_enable_clock);
+
+void dm365_vpss_set_sync_pol(struct vpss_sync_pol sync)
+{
+	int val = 0;
+	val = isp5_read(DM365_ISP5_CCDCMUX);
+
+	val |= (sync.ccdpg_hdpol << DM365_CCDC_PG_HD_POL_SHIFT);
+	val |= (sync.ccdpg_vdpol << DM365_CCDC_PG_VD_POL_SHIFT);
+
+	isp5_write(val, DM365_ISP5_CCDCMUX);
+}
+EXPORT_SYMBOL(dm365_vpss_set_sync_pol);
+
+void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size)
+{
+	int current_reg = ((frame_size.hlpfr >> 1) - 1) << 16;
+
+	current_reg |= (frame_size.pplen - 1);
+	isp5_write(current_reg, DM365_ISP5_PG_FRAME_SIZE);
+}
+EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size);
+
+static int __devinit vpss_probe(struct platform_device *pdev)
+{
+	struct resource		*r1, *r2;
+	char *platform_name;
+	int status;
+
+	if (!pdev->dev.platform_data) {
+		dev_err(&pdev->dev, "no platform data\n");
+		return -ENOENT;
+	}
+
+	platform_name = pdev->dev.platform_data;
+	if (!strcmp(platform_name, "dm355_vpss"))
+		oper_cfg.platform = DM355;
+	else if (!strcmp(platform_name, "dm365_vpss"))
+		oper_cfg.platform = DM365;
+	else if (!strcmp(platform_name, "dm644x_vpss"))
+		oper_cfg.platform = DM644X;
+	else {
+		dev_err(&pdev->dev, "vpss driver not supported on"
+			" this platform\n");
+		return -ENODEV;
+	}
+
+	dev_info(&pdev->dev, "%s vpss probed\n", platform_name);
+	r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r1)
+		return -ENOENT;
+
+	r1 = request_mem_region(r1->start, resource_size(r1), r1->name);
+	if (!r1)
+		return -EBUSY;
+
+	oper_cfg.vpss_regs_base0 = ioremap(r1->start, resource_size(r1));
+	if (!oper_cfg.vpss_regs_base0) {
+		status = -EBUSY;
+		goto fail1;
+	}
+
+	if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) {
+		r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+		if (!r2) {
+			status = -ENOENT;
+			goto fail2;
+		}
+		r2 = request_mem_region(r2->start, resource_size(r2), r2->name);
+		if (!r2) {
+			status = -EBUSY;
+			goto fail2;
+		}
+
+		oper_cfg.vpss_regs_base1 = ioremap(r2->start,
+						   resource_size(r2));
+		if (!oper_cfg.vpss_regs_base1) {
+			status = -EBUSY;
+			goto fail3;
+		}
+	}
+
+	if (oper_cfg.platform == DM355) {
+		oper_cfg.hw_ops.enable_clock = dm355_enable_clock;
+		oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source;
+		/* Setup vpss interrupts */
+		bl_regw(DM355_VPSSBL_INTSEL_DEFAULT, DM355_VPSSBL_INTSEL);
+		bl_regw(DM355_VPSSBL_EVTSEL_DEFAULT, DM355_VPSSBL_EVTSEL);
+	} else if (oper_cfg.platform == DM365) {
+		oper_cfg.hw_ops.enable_clock = dm365_enable_clock;
+		oper_cfg.hw_ops.select_ccdc_source = dm365_select_ccdc_source;
+		/* Setup vpss interrupts */
+		isp5_write(DM365_ISP5_INTSEL1_DEFAULT, DM365_ISP5_INTSEL1);
+		isp5_write(DM365_ISP5_INTSEL2_DEFAULT, DM365_ISP5_INTSEL2);
+		isp5_write(DM365_ISP5_INTSEL3_DEFAULT, DM365_ISP5_INTSEL3);
+	} else
+		oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow;
+
+	spin_lock_init(&oper_cfg.vpss_lock);
+	dev_info(&pdev->dev, "%s vpss probe success\n", platform_name);
+	return 0;
+
+fail3:
+	release_mem_region(r2->start, resource_size(r2));
+fail2:
+	iounmap(oper_cfg.vpss_regs_base0);
+fail1:
+	release_mem_region(r1->start, resource_size(r1));
+	return status;
+}
+
+static int __devexit vpss_remove(struct platform_device *pdev)
+{
+	struct resource		*res;
+
+	iounmap(oper_cfg.vpss_regs_base0);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, resource_size(res));
+	if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) {
+		iounmap(oper_cfg.vpss_regs_base1);
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+		release_mem_region(res->start, resource_size(res));
+	}
+	return 0;
+}
+
+static struct platform_driver vpss_driver = {
+	.driver = {
+		.name	= "vpss",
+		.owner = THIS_MODULE,
+	},
+	.remove = __devexit_p(vpss_remove),
+	.probe = vpss_probe,
+};
+
+static void vpss_exit(void)
+{
+	platform_driver_unregister(&vpss_driver);
+}
+
+static int __init vpss_init(void)
+{
+	return platform_driver_register(&vpss_driver);
+}
+subsys_initcall(vpss_init);
+module_exit(vpss_exit);
diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c
new file mode 100644
index 0000000..20f9810
--- /dev/null
+++ b/drivers/media/platform/fsl-viu.c
@@ -0,0 +1,1690 @@
+/*
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ *  Freescale VIU video driver
+ *
+ *  Authors: Hongjun Chen <hong-jun.chen@freescale.com>
+ *	     Porting to 2.6.35 by DENX Software Engineering,
+ *	     Anatolij Gustschin <agust@denx.de>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf-dma-contig.h>
+
+#define DRV_NAME		"fsl_viu"
+#define VIU_VERSION		"0.5.1"
+
+#define BUFFER_TIMEOUT		msecs_to_jiffies(500)  /* 0.5 seconds */
+
+#define	VIU_VID_MEM_LIMIT	4	/* Video memory limit, in Mb */
+
+/* I2C address of video decoder chip is 0x4A */
+#define VIU_VIDEO_DECODER_ADDR	0x25
+
+/* supported controls */
+static struct v4l2_queryctrl viu_qctrl[] = {
+	{
+		.id            = V4L2_CID_BRIGHTNESS,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Brightness",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = 127,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_CONTRAST,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Contrast",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 0x1,
+		.default_value = 0x10,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_SATURATION,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Saturation",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 0x1,
+		.default_value = 127,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_HUE,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Hue",
+		.minimum       = -128,
+		.maximum       = 127,
+		.step          = 0x1,
+		.default_value = 0,
+		.flags         = 0,
+	}
+};
+
+static int qctl_regs[ARRAY_SIZE(viu_qctrl)];
+
+static int info_level;
+
+#define dprintk(level, fmt, arg...)					\
+	do {								\
+		if (level <= info_level)				\
+			printk(KERN_DEBUG "viu: " fmt , ## arg);	\
+	} while (0)
+
+/*
+ * Basic structures
+ */
+struct viu_fmt {
+	char  name[32];
+	u32   fourcc;		/* v4l2 format id */
+	u32   pixelformat;
+	int   depth;
+};
+
+static struct viu_fmt formats[] = {
+	{
+		.name		= "RGB-16 (5/B-6/G-5/R)",
+		.fourcc		= V4L2_PIX_FMT_RGB565,
+		.pixelformat	= V4L2_PIX_FMT_RGB565,
+		.depth		= 16,
+	}, {
+		.name		= "RGB-32 (A-R-G-B)",
+		.fourcc		= V4L2_PIX_FMT_RGB32,
+		.pixelformat	= V4L2_PIX_FMT_RGB32,
+		.depth		= 32,
+	}
+};
+
+struct viu_dev;
+struct viu_buf;
+
+/* buffer for one video frame */
+struct viu_buf {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+	struct viu_fmt *fmt;
+};
+
+struct viu_dmaqueue {
+	struct viu_dev		*dev;
+	struct list_head	active;
+	struct list_head	queued;
+	struct timer_list	timeout;
+};
+
+struct viu_status {
+	u32 field_irq;
+	u32 vsync_irq;
+	u32 hsync_irq;
+	u32 vstart_irq;
+	u32 dma_end_irq;
+	u32 error_irq;
+};
+
+struct viu_reg {
+	u32 status_cfg;
+	u32 luminance;
+	u32 chroma_r;
+	u32 chroma_g;
+	u32 chroma_b;
+	u32 field_base_addr;
+	u32 dma_inc;
+	u32 picture_count;
+	u32 req_alarm;
+	u32 alpha;
+} __attribute__ ((packed));
+
+struct viu_dev {
+	struct v4l2_device	v4l2_dev;
+	struct mutex		lock;
+	spinlock_t		slock;
+	int			users;
+
+	struct device		*dev;
+	/* various device info */
+	struct video_device	*vdev;
+	struct viu_dmaqueue	vidq;
+	enum v4l2_field		capfield;
+	int			field;
+	int			first;
+	int			dma_done;
+
+	/* Hardware register area */
+	struct viu_reg		*vr;
+
+	/* Interrupt vector */
+	int			irq;
+	struct viu_status	irqs;
+
+	/* video overlay */
+	struct v4l2_framebuffer	ovbuf;
+	struct viu_fmt		*ovfmt;
+	unsigned int		ovenable;
+	enum v4l2_field		ovfield;
+
+	/* crop */
+	struct v4l2_rect	crop_current;
+
+	/* clock pointer */
+	struct clk		*clk;
+
+	/* decoder */
+	struct v4l2_subdev	*decoder;
+
+	v4l2_std_id		std;
+};
+
+struct viu_fh {
+	struct viu_dev		*dev;
+
+	/* video capture */
+	struct videobuf_queue	vb_vidq;
+	spinlock_t		vbq_lock; /* spinlock for the videobuf queue */
+
+	/* video overlay */
+	struct v4l2_window	win;
+	struct v4l2_clip	clips[1];
+
+	/* video capture */
+	struct viu_fmt		*fmt;
+	int			width, height, sizeimage;
+	enum v4l2_buf_type	type;
+};
+
+static struct viu_reg reg_val;
+
+/*
+ * Macro definitions of VIU registers
+ */
+
+/* STATUS_CONFIG register */
+enum status_config {
+	SOFT_RST		= 1 << 0,
+
+	ERR_MASK		= 0x0f << 4,	/* Error code mask */
+	ERR_NO			= 0x00,		/* No error */
+	ERR_DMA_V		= 0x01 << 4,	/* DMA in vertical active */
+	ERR_DMA_VB		= 0x02 << 4,	/* DMA in vertical blanking */
+	ERR_LINE_TOO_LONG	= 0x04 << 4,	/* Line too long */
+	ERR_TOO_MANG_LINES	= 0x05 << 4,	/* Too many lines in field */
+	ERR_LINE_TOO_SHORT	= 0x06 << 4,	/* Line too short */
+	ERR_NOT_ENOUGH_LINE	= 0x07 << 4,	/* Not enough lines in field */
+	ERR_FIFO_OVERFLOW	= 0x08 << 4,	/* FIFO overflow */
+	ERR_FIFO_UNDERFLOW	= 0x09 << 4,	/* FIFO underflow */
+	ERR_1bit_ECC		= 0x0a << 4,	/* One bit ECC error */
+	ERR_MORE_ECC		= 0x0b << 4,	/* Two/more bits ECC error */
+
+	INT_FIELD_EN		= 0x01 << 8,	/* Enable field interrupt */
+	INT_VSYNC_EN		= 0x01 << 9,	/* Enable vsync interrupt */
+	INT_HSYNC_EN		= 0x01 << 10,	/* Enable hsync interrupt */
+	INT_VSTART_EN		= 0x01 << 11,	/* Enable vstart interrupt */
+	INT_DMA_END_EN		= 0x01 << 12,	/* Enable DMA end interrupt */
+	INT_ERROR_EN		= 0x01 << 13,	/* Enable error interrupt */
+	INT_ECC_EN		= 0x01 << 14,	/* Enable ECC interrupt */
+
+	INT_FIELD_STATUS	= 0x01 << 16,	/* field interrupt status */
+	INT_VSYNC_STATUS	= 0x01 << 17,	/* vsync interrupt status */
+	INT_HSYNC_STATUS	= 0x01 << 18,	/* hsync interrupt status */
+	INT_VSTART_STATUS	= 0x01 << 19,	/* vstart interrupt status */
+	INT_DMA_END_STATUS	= 0x01 << 20,	/* DMA end interrupt status */
+	INT_ERROR_STATUS	= 0x01 << 21,	/* error interrupt status */
+
+	DMA_ACT			= 0x01 << 27,	/* Enable DMA transfer */
+	FIELD_NO		= 0x01 << 28,	/* Field number */
+	DITHER_ON		= 0x01 << 29,	/* Dithering is on */
+	ROUND_ON		= 0x01 << 30,	/* Round is on */
+	MODE_32BIT		= 0x01 << 31,	/* Data in RGBa888,
+						 * 0 in RGB565
+						 */
+};
+
+#define norm_maxw()	720
+#define norm_maxh()	576
+
+#define INT_ALL_STATUS	(INT_FIELD_STATUS | INT_VSYNC_STATUS | \
+			 INT_HSYNC_STATUS | INT_VSTART_STATUS | \
+			 INT_DMA_END_STATUS | INT_ERROR_STATUS)
+
+#define NUM_FORMATS	ARRAY_SIZE(formats)
+
+static irqreturn_t viu_intr(int irq, void *dev_id);
+
+struct viu_fmt *format_by_fourcc(int fourcc)
+{
+	int i;
+
+	for (i = 0; i < NUM_FORMATS; i++) {
+		if (formats[i].pixelformat == fourcc)
+			return formats + i;
+	}
+
+	dprintk(0, "unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
+	return NULL;
+}
+
+void viu_start_dma(struct viu_dev *dev)
+{
+	struct viu_reg *vr = dev->vr;
+
+	dev->field = 0;
+
+	/* Enable DMA operation */
+	out_be32(&vr->status_cfg, SOFT_RST);
+	out_be32(&vr->status_cfg, INT_FIELD_EN);
+}
+
+void viu_stop_dma(struct viu_dev *dev)
+{
+	struct viu_reg *vr = dev->vr;
+	int cnt = 100;
+	u32 status_cfg;
+
+	out_be32(&vr->status_cfg, 0);
+
+	/* Clear pending interrupts */
+	status_cfg = in_be32(&vr->status_cfg);
+	if (status_cfg & 0x3f0000)
+		out_be32(&vr->status_cfg, status_cfg & 0x3f0000);
+
+	if (status_cfg & DMA_ACT) {
+		do {
+			status_cfg = in_be32(&vr->status_cfg);
+			if (status_cfg & INT_DMA_END_STATUS)
+				break;
+		} while (cnt--);
+
+		if (cnt < 0) {
+			/* timed out, issue soft reset */
+			out_be32(&vr->status_cfg, SOFT_RST);
+			out_be32(&vr->status_cfg, 0);
+		} else {
+			/* clear DMA_END and other pending irqs */
+			out_be32(&vr->status_cfg, status_cfg & 0x3f0000);
+		}
+	}
+
+	dev->field = 0;
+}
+
+static int restart_video_queue(struct viu_dmaqueue *vidq)
+{
+	struct viu_buf *buf, *prev;
+
+	dprintk(1, "%s vidq=0x%08lx\n", __func__, (unsigned long)vidq);
+	if (!list_empty(&vidq->active)) {
+		buf = list_entry(vidq->active.next, struct viu_buf, vb.queue);
+		dprintk(2, "restart_queue [%p/%d]: restart dma\n",
+			buf, buf->vb.i);
+
+		viu_stop_dma(vidq->dev);
+
+		/* cancel all outstanding capture requests */
+		list_for_each_entry_safe(buf, prev, &vidq->active, vb.queue) {
+			list_del(&buf->vb.queue);
+			buf->vb.state = VIDEOBUF_ERROR;
+			wake_up(&buf->vb.done);
+		}
+		mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+		return 0;
+	}
+
+	prev = NULL;
+	for (;;) {
+		if (list_empty(&vidq->queued))
+			return 0;
+		buf = list_entry(vidq->queued.next, struct viu_buf, vb.queue);
+		if (prev == NULL) {
+			list_del(&buf->vb.queue);
+			list_add_tail(&buf->vb.queue, &vidq->active);
+
+			dprintk(1, "Restarting video dma\n");
+			viu_stop_dma(vidq->dev);
+			viu_start_dma(vidq->dev);
+
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+			dprintk(2, "[%p/%d] restart_queue - first active\n",
+				buf, buf->vb.i);
+
+		} else if (prev->vb.width  == buf->vb.width  &&
+			   prev->vb.height == buf->vb.height &&
+			   prev->fmt       == buf->fmt) {
+			list_del(&buf->vb.queue);
+			list_add_tail(&buf->vb.queue, &vidq->active);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			dprintk(2, "[%p/%d] restart_queue - move to active\n",
+				buf, buf->vb.i);
+		} else {
+			return 0;
+		}
+		prev = buf;
+	}
+}
+
+static void viu_vid_timeout(unsigned long data)
+{
+	struct viu_dev *dev = (struct viu_dev *)data;
+	struct viu_buf *buf;
+	struct viu_dmaqueue *vidq = &dev->vidq;
+
+	while (!list_empty(&vidq->active)) {
+		buf = list_entry(vidq->active.next, struct viu_buf, vb.queue);
+		list_del(&buf->vb.queue);
+		buf->vb.state = VIDEOBUF_ERROR;
+		wake_up(&buf->vb.done);
+		dprintk(1, "viu/0: [%p/%d] timeout\n", buf, buf->vb.i);
+	}
+
+	restart_video_queue(vidq);
+}
+
+/*
+ * Videobuf operations
+ */
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+			unsigned int *size)
+{
+	struct viu_fh *fh = vq->priv_data;
+
+	*size = fh->width * fh->height * fh->fmt->depth >> 3;
+	if (*count == 0)
+		*count = 32;
+
+	while (*size * *count > VIU_VID_MEM_LIMIT * 1024 * 1024)
+		(*count)--;
+
+	dprintk(1, "%s, count=%d, size=%d\n", __func__, *count, *size);
+	return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct viu_buf *buf)
+{
+	struct videobuf_buffer *vb = &buf->vb;
+	void *vaddr = NULL;
+
+	BUG_ON(in_interrupt());
+
+	videobuf_waiton(vq, &buf->vb, 0, 0);
+
+	if (vq->int_ops && vq->int_ops->vaddr)
+		vaddr = vq->int_ops->vaddr(vb);
+
+	if (vaddr)
+		videobuf_dma_contig_free(vq, &buf->vb);
+
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+inline int buffer_activate(struct viu_dev *dev, struct viu_buf *buf)
+{
+	struct viu_reg *vr = dev->vr;
+	int bpp;
+
+	/* setup the DMA base address */
+	reg_val.field_base_addr = videobuf_to_dma_contig(&buf->vb);
+
+	dprintk(1, "buffer_activate [%p/%d]: dma addr 0x%lx\n",
+		buf, buf->vb.i, (unsigned long)reg_val.field_base_addr);
+
+	/* interlace is on by default, set horizontal DMA increment */
+	reg_val.status_cfg = 0;
+	bpp = buf->fmt->depth >> 3;
+	switch (bpp) {
+	case 2:
+		reg_val.status_cfg &= ~MODE_32BIT;
+		reg_val.dma_inc = buf->vb.width * 2;
+		break;
+	case 4:
+		reg_val.status_cfg |= MODE_32BIT;
+		reg_val.dma_inc = buf->vb.width * 4;
+		break;
+	default:
+		dprintk(0, "doesn't support color depth(%d)\n",
+			bpp * 8);
+		return -EINVAL;
+	}
+
+	/* setup picture_count register */
+	reg_val.picture_count = (buf->vb.height / 2) << 16 |
+				buf->vb.width;
+
+	reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN;
+
+	buf->vb.state = VIDEOBUF_ACTIVE;
+	dev->capfield = buf->vb.field;
+
+	/* reset dma increment if needed */
+	if (!V4L2_FIELD_HAS_BOTH(buf->vb.field))
+		reg_val.dma_inc = 0;
+
+	out_be32(&vr->dma_inc, reg_val.dma_inc);
+	out_be32(&vr->picture_count, reg_val.picture_count);
+	out_be32(&vr->field_base_addr, reg_val.field_base_addr);
+	mod_timer(&dev->vidq.timeout, jiffies + BUFFER_TIMEOUT);
+	return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq,
+			  struct videobuf_buffer *vb,
+			  enum v4l2_field field)
+{
+	struct viu_fh  *fh  = vq->priv_data;
+	struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
+	int rc;
+
+	BUG_ON(fh->fmt == NULL);
+
+	if (fh->width  < 48 || fh->width  > norm_maxw() ||
+	    fh->height < 32 || fh->height > norm_maxh())
+		return -EINVAL;
+	buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+	if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size)
+		return -EINVAL;
+
+	if (buf->fmt       != fh->fmt	 ||
+	    buf->vb.width  != fh->width  ||
+	    buf->vb.height != fh->height ||
+	    buf->vb.field  != field) {
+		buf->fmt       = fh->fmt;
+		buf->vb.width  = fh->width;
+		buf->vb.height = fh->height;
+		buf->vb.field  = field;
+	}
+
+	if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
+		rc = videobuf_iolock(vq, &buf->vb, NULL);
+		if (rc != 0)
+			goto fail;
+
+		buf->vb.width  = fh->width;
+		buf->vb.height = fh->height;
+		buf->vb.field  = field;
+		buf->fmt       = fh->fmt;
+	}
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+fail:
+	free_buffer(vq, buf);
+	return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct viu_buf       *buf     = container_of(vb, struct viu_buf, vb);
+	struct viu_fh        *fh      = vq->priv_data;
+	struct viu_dev       *dev     = fh->dev;
+	struct viu_dmaqueue  *vidq    = &dev->vidq;
+	struct viu_buf       *prev;
+
+	if (!list_empty(&vidq->queued)) {
+		dprintk(1, "adding vb queue=0x%08lx\n",
+				(unsigned long)&buf->vb.queue);
+		dprintk(1, "vidq pointer 0x%p, queued 0x%p\n",
+				vidq, &vidq->queued);
+		dprintk(1, "dev %p, queued: self %p, next %p, head %p\n",
+			dev, &vidq->queued, vidq->queued.next,
+			vidq->queued.prev);
+		list_add_tail(&buf->vb.queue, &vidq->queued);
+		buf->vb.state = VIDEOBUF_QUEUED;
+		dprintk(2, "[%p/%d] buffer_queue - append to queued\n",
+			buf, buf->vb.i);
+	} else if (list_empty(&vidq->active)) {
+		dprintk(1, "adding vb active=0x%08lx\n",
+				(unsigned long)&buf->vb.queue);
+		list_add_tail(&buf->vb.queue, &vidq->active);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+		dprintk(2, "[%p/%d] buffer_queue - first active\n",
+			buf, buf->vb.i);
+
+		buffer_activate(dev, buf);
+	} else {
+		dprintk(1, "adding vb queue2=0x%08lx\n",
+				(unsigned long)&buf->vb.queue);
+		prev = list_entry(vidq->active.prev, struct viu_buf, vb.queue);
+		if (prev->vb.width  == buf->vb.width  &&
+		    prev->vb.height == buf->vb.height &&
+		    prev->fmt       == buf->fmt) {
+			list_add_tail(&buf->vb.queue, &vidq->active);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			dprintk(2, "[%p/%d] buffer_queue - append to active\n",
+				buf, buf->vb.i);
+		} else {
+			list_add_tail(&buf->vb.queue, &vidq->queued);
+			buf->vb.state = VIDEOBUF_QUEUED;
+			dprintk(2, "[%p/%d] buffer_queue - first queued\n",
+				buf, buf->vb.i);
+		}
+	}
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+				struct videobuf_buffer *vb)
+{
+	struct viu_buf *buf  = container_of(vb, struct viu_buf, vb);
+	struct viu_fh  *fh   = vq->priv_data;
+	struct viu_dev *dev  = (struct viu_dev *)fh->dev;
+
+	viu_stop_dma(dev);
+	free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops viu_video_qops = {
+	.buf_setup      = buffer_setup,
+	.buf_prepare    = buffer_prepare,
+	.buf_queue      = buffer_queue,
+	.buf_release    = buffer_release,
+};
+
+/*
+ * IOCTL vidioc handling
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	strcpy(cap->driver, "viu");
+	strcpy(cap->card, "viu");
+	cap->capabilities =	V4L2_CAP_VIDEO_CAPTURE |
+				V4L2_CAP_STREAMING     |
+				V4L2_CAP_VIDEO_OVERLAY |
+				V4L2_CAP_READWRITE;
+	return 0;
+}
+
+static int vidioc_enum_fmt(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	int index = f->index;
+
+	if (f->index > NUM_FORMATS)
+		return -EINVAL;
+
+	strlcpy(f->description, formats[index].name, sizeof(f->description));
+	f->pixelformat = formats[index].fourcc;
+	return 0;
+}
+
+static int vidioc_g_fmt_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct viu_fh *fh = priv;
+
+	f->fmt.pix.width        = fh->width;
+	f->fmt.pix.height       = fh->height;
+	f->fmt.pix.field        = fh->vb_vidq.field;
+	f->fmt.pix.pixelformat  = fh->fmt->pixelformat;
+	f->fmt.pix.bytesperline =
+			(f->fmt.pix.width * fh->fmt->depth) >> 3;
+	f->fmt.pix.sizeimage	= fh->sizeimage;
+	return 0;
+}
+
+static int vidioc_try_fmt_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct viu_fmt *fmt;
+	enum v4l2_field field;
+	unsigned int maxw, maxh;
+
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	if (!fmt) {
+		dprintk(1, "Fourcc format (0x%08x) invalid.",
+			f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	field = f->fmt.pix.field;
+
+	if (field == V4L2_FIELD_ANY) {
+		field = V4L2_FIELD_INTERLACED;
+	} else if (field != V4L2_FIELD_INTERLACED) {
+		dprintk(1, "Field type invalid.\n");
+		return -EINVAL;
+	}
+
+	maxw  = norm_maxw();
+	maxh  = norm_maxh();
+
+	f->fmt.pix.field = field;
+	if (f->fmt.pix.height < 32)
+		f->fmt.pix.height = 32;
+	if (f->fmt.pix.height > maxh)
+		f->fmt.pix.height = maxh;
+	if (f->fmt.pix.width < 48)
+		f->fmt.pix.width = 48;
+	if (f->fmt.pix.width > maxw)
+		f->fmt.pix.width = maxw;
+	f->fmt.pix.width &= ~0x03;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * fmt->depth) >> 3;
+
+	return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct viu_fh *fh = priv;
+	int ret;
+
+	ret = vidioc_try_fmt_cap(file, fh, f);
+	if (ret < 0)
+		return ret;
+
+	fh->fmt           = format_by_fourcc(f->fmt.pix.pixelformat);
+	fh->width         = f->fmt.pix.width;
+	fh->height        = f->fmt.pix.height;
+	fh->sizeimage     = f->fmt.pix.sizeimage;
+	fh->vb_vidq.field = f->fmt.pix.field;
+	fh->type          = f->type;
+	dprintk(1, "set to pixelformat '%4.6s'\n", (char *)&fh->fmt->name);
+	return 0;
+}
+
+static int vidioc_g_fmt_overlay(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct viu_fh *fh = priv;
+
+	f->fmt.win = fh->win;
+	return 0;
+}
+
+static int verify_preview(struct viu_dev *dev, struct v4l2_window *win)
+{
+	enum v4l2_field field;
+	int maxw, maxh;
+
+	if (dev->ovbuf.base == NULL)
+		return -EINVAL;
+	if (dev->ovfmt == NULL)
+		return -EINVAL;
+	if (win->w.width < 48 || win->w.height < 32)
+		return -EINVAL;
+
+	field = win->field;
+	maxw  = dev->crop_current.width;
+	maxh  = dev->crop_current.height;
+
+	if (field == V4L2_FIELD_ANY) {
+		field = (win->w.height > maxh/2)
+			? V4L2_FIELD_INTERLACED
+			: V4L2_FIELD_TOP;
+	}
+	switch (field) {
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+		maxh = maxh / 2;
+		break;
+	case V4L2_FIELD_INTERLACED:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	win->field = field;
+	if (win->w.width > maxw)
+		win->w.width = maxw;
+	if (win->w.height > maxh)
+		win->w.height = maxh;
+	return 0;
+}
+
+inline void viu_activate_overlay(struct viu_reg *viu_reg)
+{
+	struct viu_reg *vr = viu_reg;
+
+	out_be32(&vr->field_base_addr, reg_val.field_base_addr);
+	out_be32(&vr->dma_inc, reg_val.dma_inc);
+	out_be32(&vr->picture_count, reg_val.picture_count);
+}
+
+static int viu_setup_preview(struct viu_dev *dev, struct viu_fh *fh)
+{
+	int bpp;
+
+	dprintk(1, "%s %dx%d %s\n", __func__,
+		fh->win.w.width, fh->win.w.height, dev->ovfmt->name);
+
+	reg_val.status_cfg = 0;
+
+	/* setup window */
+	reg_val.picture_count = (fh->win.w.height / 2) << 16 |
+				fh->win.w.width;
+
+	/* setup color depth and dma increment */
+	bpp = dev->ovfmt->depth / 8;
+	switch (bpp) {
+	case 2:
+		reg_val.status_cfg &= ~MODE_32BIT;
+		reg_val.dma_inc = fh->win.w.width * 2;
+		break;
+	case 4:
+		reg_val.status_cfg |= MODE_32BIT;
+		reg_val.dma_inc = fh->win.w.width * 4;
+		break;
+	default:
+		dprintk(0, "device doesn't support color depth(%d)\n",
+			bpp * 8);
+		return -EINVAL;
+	}
+
+	dev->ovfield = fh->win.field;
+	if (!V4L2_FIELD_HAS_BOTH(dev->ovfield))
+		reg_val.dma_inc = 0;
+
+	reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN;
+
+	/* setup the base address of the overlay buffer */
+	reg_val.field_base_addr = (u32)dev->ovbuf.base;
+
+	return 0;
+}
+
+static int vidioc_s_fmt_overlay(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct viu_fh  *fh  = priv;
+	struct viu_dev *dev = (struct viu_dev *)fh->dev;
+	unsigned long  flags;
+	int err;
+
+	err = verify_preview(dev, &f->fmt.win);
+	if (err)
+		return err;
+
+	fh->win = f->fmt.win;
+
+	spin_lock_irqsave(&dev->slock, flags);
+	viu_setup_preview(dev, fh);
+	spin_unlock_irqrestore(&dev->slock, flags);
+	return 0;
+}
+
+static int vidioc_try_fmt_overlay(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	return 0;
+}
+
+static int vidioc_overlay(struct file *file, void *priv, unsigned int on)
+{
+	struct viu_fh  *fh  = priv;
+	struct viu_dev *dev = (struct viu_dev *)fh->dev;
+	unsigned long  flags;
+
+	if (on) {
+		spin_lock_irqsave(&dev->slock, flags);
+		viu_activate_overlay(dev->vr);
+		dev->ovenable = 1;
+
+		/* start dma */
+		viu_start_dma(dev);
+		spin_unlock_irqrestore(&dev->slock, flags);
+	} else {
+		viu_stop_dma(dev);
+		dev->ovenable = 0;
+	}
+
+	return 0;
+}
+
+int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
+{
+	struct viu_fh  *fh = priv;
+	struct viu_dev *dev = fh->dev;
+	struct v4l2_framebuffer *fb = arg;
+
+	*fb = dev->ovbuf;
+	fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+	return 0;
+}
+
+int vidioc_s_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
+{
+	struct viu_fh  *fh = priv;
+	struct viu_dev *dev = fh->dev;
+	struct v4l2_framebuffer *fb = arg;
+	struct viu_fmt *fmt;
+
+	if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	/* check args */
+	fmt = format_by_fourcc(fb->fmt.pixelformat);
+	if (fmt == NULL)
+		return -EINVAL;
+
+	/* ok, accept it */
+	dev->ovbuf = *fb;
+	dev->ovfmt = fmt;
+	if (dev->ovbuf.fmt.bytesperline == 0) {
+		dev->ovbuf.fmt.bytesperline =
+			dev->ovbuf.fmt.width * fmt->depth / 8;
+	}
+	return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+				struct v4l2_requestbuffers *p)
+{
+	struct viu_fh *fh = priv;
+
+	return videobuf_reqbufs(&fh->vb_vidq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+					struct v4l2_buffer *p)
+{
+	struct viu_fh *fh = priv;
+
+	return videobuf_querybuf(&fh->vb_vidq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct viu_fh *fh = priv;
+
+	return videobuf_qbuf(&fh->vb_vidq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct viu_fh *fh = priv;
+
+	return videobuf_dqbuf(&fh->vb_vidq, p,
+				file->f_flags & O_NONBLOCK);
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct viu_fh *fh = priv;
+	struct viu_dev *dev = fh->dev;
+
+	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (fh->type != i)
+		return -EINVAL;
+
+	if (dev->ovenable)
+		dev->ovenable = 0;
+
+	viu_start_dma(fh->dev);
+
+	return videobuf_streamon(&fh->vb_vidq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct viu_fh  *fh = priv;
+
+	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (fh->type != i)
+		return -EINVAL;
+
+	viu_stop_dma(fh->dev);
+
+	return videobuf_streamoff(&fh->vb_vidq);
+}
+
+#define decoder_call(viu, o, f, args...) \
+	v4l2_subdev_call(viu->decoder, o, f, ##args)
+
+static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+	struct viu_fh *fh = priv;
+
+	decoder_call(fh->dev, video, querystd, std_id);
+	return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct viu_fh *fh = priv;
+
+	fh->dev->std = *id;
+	decoder_call(fh->dev, core, s_std, *id);
+	return 0;
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+	struct viu_fh *fh = priv;
+
+	*std_id = fh->dev->std;
+	return 0;
+}
+
+/* only one input in this driver */
+static int vidioc_enum_input(struct file *file, void *priv,
+					struct v4l2_input *inp)
+{
+	struct viu_fh *fh = priv;
+
+	if (inp->index != 0)
+		return -EINVAL;
+
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+	inp->std = fh->dev->vdev->tvnorms;
+	strcpy(inp->name, "Camera");
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct viu_fh *fh = priv;
+
+	if (i > 1)
+		return -EINVAL;
+
+	decoder_call(fh->dev, video, s_routing, i, 0, 0);
+	return 0;
+}
+
+/* Controls */
+static int vidioc_queryctrl(struct file *file, void *priv,
+				struct v4l2_queryctrl *qc)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+		if (qc->id && qc->id == viu_qctrl[i].id) {
+			memcpy(qc, &(viu_qctrl[i]), sizeof(*qc));
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+		if (ctrl->id == viu_qctrl[i].id) {
+			ctrl->value = qctl_regs[i];
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+static int vidioc_s_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+		if (ctrl->id == viu_qctrl[i].id) {
+			if (ctrl->value < viu_qctrl[i].minimum
+				|| ctrl->value > viu_qctrl[i].maximum)
+					return -ERANGE;
+			qctl_regs[i] = ctrl->value;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+inline void viu_activate_next_buf(struct viu_dev *dev,
+				struct viu_dmaqueue *viuq)
+{
+	struct viu_dmaqueue *vidq = viuq;
+	struct viu_buf *buf;
+
+	/* launch another DMA operation for an active/queued buffer */
+	if (!list_empty(&vidq->active)) {
+		buf = list_entry(vidq->active.next, struct viu_buf,
+					vb.queue);
+		dprintk(1, "start another queued buffer: 0x%p\n", buf);
+		buffer_activate(dev, buf);
+	} else if (!list_empty(&vidq->queued)) {
+		buf = list_entry(vidq->queued.next, struct viu_buf,
+					vb.queue);
+		list_del(&buf->vb.queue);
+
+		dprintk(1, "start another queued buffer: 0x%p\n", buf);
+		list_add_tail(&buf->vb.queue, &vidq->active);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		buffer_activate(dev, buf);
+	}
+}
+
+inline void viu_default_settings(struct viu_reg *viu_reg)
+{
+	struct viu_reg *vr = viu_reg;
+
+	out_be32(&vr->luminance, 0x9512A254);
+	out_be32(&vr->chroma_r, 0x03310000);
+	out_be32(&vr->chroma_g, 0x06600F38);
+	out_be32(&vr->chroma_b, 0x00000409);
+	out_be32(&vr->alpha, 0x000000ff);
+	out_be32(&vr->req_alarm, 0x00000090);
+	dprintk(1, "status reg: 0x%08x, field base: 0x%08x\n",
+		in_be32(&vr->status_cfg), in_be32(&vr->field_base_addr));
+}
+
+static void viu_overlay_intr(struct viu_dev *dev, u32 status)
+{
+	struct viu_reg *vr = dev->vr;
+
+	if (status & INT_DMA_END_STATUS)
+		dev->dma_done = 1;
+
+	if (status & INT_FIELD_STATUS) {
+		if (dev->dma_done) {
+			u32 addr = reg_val.field_base_addr;
+
+			dev->dma_done = 0;
+			if (status & FIELD_NO)
+				addr += reg_val.dma_inc;
+
+			out_be32(&vr->field_base_addr, addr);
+			out_be32(&vr->dma_inc, reg_val.dma_inc);
+			out_be32(&vr->status_cfg,
+				 (status & 0xffc0ffff) |
+				 (status & INT_ALL_STATUS) |
+				 reg_val.status_cfg);
+		} else if (status & INT_VSYNC_STATUS) {
+			out_be32(&vr->status_cfg,
+				 (status & 0xffc0ffff) |
+				 (status & INT_ALL_STATUS) |
+				 reg_val.status_cfg);
+		}
+	}
+}
+
+static void viu_capture_intr(struct viu_dev *dev, u32 status)
+{
+	struct viu_dmaqueue *vidq = &dev->vidq;
+	struct viu_reg *vr = dev->vr;
+	struct viu_buf *buf;
+	int field_num;
+	int need_two;
+	int dma_done = 0;
+
+	field_num = status & FIELD_NO;
+	need_two = V4L2_FIELD_HAS_BOTH(dev->capfield);
+
+	if (status & INT_DMA_END_STATUS) {
+		dma_done = 1;
+		if (((field_num == 0) && (dev->field == 0)) ||
+		    (field_num && (dev->field == 1)))
+			dev->field++;
+	}
+
+	if (status & INT_FIELD_STATUS) {
+		dprintk(1, "irq: field %d, done %d\n",
+			!!field_num, dma_done);
+		if (unlikely(dev->first)) {
+			if (field_num == 0) {
+				dev->first = 0;
+				dprintk(1, "activate first buf\n");
+				viu_activate_next_buf(dev, vidq);
+			} else
+				dprintk(1, "wait field 0\n");
+			return;
+		}
+
+		/* setup buffer address for next dma operation */
+		if (!list_empty(&vidq->active)) {
+			u32 addr = reg_val.field_base_addr;
+
+			if (field_num && need_two) {
+				addr += reg_val.dma_inc;
+				dprintk(1, "field 1, 0x%lx, dev field %d\n",
+					(unsigned long)addr, dev->field);
+			}
+			out_be32(&vr->field_base_addr, addr);
+			out_be32(&vr->dma_inc, reg_val.dma_inc);
+			out_be32(&vr->status_cfg,
+				 (status & 0xffc0ffff) |
+				 (status & INT_ALL_STATUS) |
+				 reg_val.status_cfg);
+			return;
+		}
+	}
+
+	if (dma_done && field_num && (dev->field == 2)) {
+		dev->field = 0;
+		buf = list_entry(vidq->active.next,
+				 struct viu_buf, vb.queue);
+		dprintk(1, "viu/0: [%p/%d] 0x%lx/0x%lx: dma complete\n",
+			buf, buf->vb.i,
+			(unsigned long)videobuf_to_dma_contig(&buf->vb),
+			(unsigned long)in_be32(&vr->field_base_addr));
+
+		if (waitqueue_active(&buf->vb.done)) {
+			list_del(&buf->vb.queue);
+			do_gettimeofday(&buf->vb.ts);
+			buf->vb.state = VIDEOBUF_DONE;
+			buf->vb.field_count++;
+			wake_up(&buf->vb.done);
+		}
+		/* activate next dma buffer */
+		viu_activate_next_buf(dev, vidq);
+	}
+}
+
+static irqreturn_t viu_intr(int irq, void *dev_id)
+{
+	struct viu_dev *dev  = (struct viu_dev *)dev_id;
+	struct viu_reg *vr = dev->vr;
+	u32 status;
+	u32 error;
+
+	status = in_be32(&vr->status_cfg);
+
+	if (status & INT_ERROR_STATUS) {
+		dev->irqs.error_irq++;
+		error = status & ERR_MASK;
+		if (error)
+			dprintk(1, "Err: error(%d), times:%d!\n",
+				error >> 4, dev->irqs.error_irq);
+		/* Clear interrupt error bit and error flags */
+		out_be32(&vr->status_cfg,
+			 (status & 0xffc0ffff) | INT_ERROR_STATUS);
+	}
+
+	if (status & INT_DMA_END_STATUS) {
+		dev->irqs.dma_end_irq++;
+		dev->dma_done = 1;
+		dprintk(2, "VIU DMA end interrupt times: %d\n",
+					dev->irqs.dma_end_irq);
+	}
+
+	if (status & INT_HSYNC_STATUS)
+		dev->irqs.hsync_irq++;
+
+	if (status & INT_FIELD_STATUS) {
+		dev->irqs.field_irq++;
+		dprintk(2, "VIU field interrupt times: %d\n",
+					dev->irqs.field_irq);
+	}
+
+	if (status & INT_VSTART_STATUS)
+		dev->irqs.vstart_irq++;
+
+	if (status & INT_VSYNC_STATUS) {
+		dev->irqs.vsync_irq++;
+		dprintk(2, "VIU vsync interrupt times: %d\n",
+			dev->irqs.vsync_irq);
+	}
+
+	/* clear all pending irqs */
+	status = in_be32(&vr->status_cfg);
+	out_be32(&vr->status_cfg,
+		 (status & 0xffc0ffff) | (status & INT_ALL_STATUS));
+
+	if (dev->ovenable) {
+		viu_overlay_intr(dev, status);
+		return IRQ_HANDLED;
+	}
+
+	/* Capture mode */
+	viu_capture_intr(dev, status);
+	return IRQ_HANDLED;
+}
+
+/*
+ * File operations for the device
+ */
+static int viu_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct viu_dev *dev = video_get_drvdata(vdev);
+	struct viu_fh *fh;
+	struct viu_reg *vr;
+	int minor = vdev->minor;
+	u32 status_cfg;
+	int i;
+
+	dprintk(1, "viu: open (minor=%d)\n", minor);
+
+	dev->users++;
+	if (dev->users > 1) {
+		dev->users--;
+		return -EBUSY;
+	}
+
+	vr = dev->vr;
+
+	dprintk(1, "open minor=%d type=%s users=%d\n", minor,
+		v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
+
+	if (mutex_lock_interruptible(&dev->lock)) {
+		dev->users--;
+		return -ERESTARTSYS;
+	}
+
+	/* allocate and initialize per filehandle data */
+	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+	if (!fh) {
+		dev->users--;
+		mutex_unlock(&dev->lock);
+		return -ENOMEM;
+	}
+
+	file->private_data = fh;
+	fh->dev = dev;
+
+	fh->type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_RGB32);
+	fh->width    = norm_maxw();
+	fh->height   = norm_maxh();
+	dev->crop_current.width  = fh->width;
+	dev->crop_current.height = fh->height;
+
+	/* Put all controls at a sane state */
+	for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++)
+		qctl_regs[i] = viu_qctrl[i].default_value;
+
+	dprintk(1, "Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n",
+		(unsigned long)fh, (unsigned long)dev,
+		(unsigned long)&dev->vidq);
+	dprintk(1, "Open: list_empty queued=%d\n",
+		list_empty(&dev->vidq.queued));
+	dprintk(1, "Open: list_empty active=%d\n",
+		list_empty(&dev->vidq.active));
+
+	viu_default_settings(vr);
+
+	status_cfg = in_be32(&vr->status_cfg);
+	out_be32(&vr->status_cfg,
+		 status_cfg & ~(INT_VSYNC_EN | INT_HSYNC_EN |
+				INT_FIELD_EN | INT_VSTART_EN |
+				INT_DMA_END_EN | INT_ERROR_EN | INT_ECC_EN));
+
+	status_cfg = in_be32(&vr->status_cfg);
+	out_be32(&vr->status_cfg, status_cfg | INT_ALL_STATUS);
+
+	spin_lock_init(&fh->vbq_lock);
+	videobuf_queue_dma_contig_init(&fh->vb_vidq, &viu_video_qops,
+				       dev->dev, &fh->vbq_lock,
+				       fh->type, V4L2_FIELD_INTERLACED,
+				       sizeof(struct viu_buf), fh,
+				       &fh->dev->lock);
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static ssize_t viu_read(struct file *file, char __user *data, size_t count,
+			loff_t *ppos)
+{
+	struct viu_fh *fh = file->private_data;
+	struct viu_dev *dev = fh->dev;
+	int ret = 0;
+
+	dprintk(2, "%s\n", __func__);
+	if (dev->ovenable)
+		dev->ovenable = 0;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		if (mutex_lock_interruptible(&dev->lock))
+			return -ERESTARTSYS;
+		viu_start_dma(dev);
+		ret = videobuf_read_stream(&fh->vb_vidq, data, count,
+				ppos, 0, file->f_flags & O_NONBLOCK);
+		mutex_unlock(&dev->lock);
+		return ret;
+	}
+	return 0;
+}
+
+static unsigned int viu_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct viu_fh *fh = file->private_data;
+	struct videobuf_queue *q = &fh->vb_vidq;
+	struct viu_dev *dev = fh->dev;
+	unsigned int res;
+
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+		return POLLERR;
+
+	mutex_lock(&dev->lock);
+	res = videobuf_poll_stream(file, q, wait);
+	mutex_unlock(&dev->lock);
+	return res;
+}
+
+static int viu_release(struct file *file)
+{
+	struct viu_fh *fh = file->private_data;
+	struct viu_dev *dev = fh->dev;
+	int minor = video_devdata(file)->minor;
+
+	mutex_lock(&dev->lock);
+	viu_stop_dma(dev);
+	videobuf_stop(&fh->vb_vidq);
+	videobuf_mmap_free(&fh->vb_vidq);
+	mutex_unlock(&dev->lock);
+
+	kfree(fh);
+
+	dev->users--;
+	dprintk(1, "close (minor=%d, users=%d)\n",
+		minor, dev->users);
+	return 0;
+}
+
+void viu_reset(struct viu_reg *reg)
+{
+	out_be32(&reg->status_cfg, 0);
+	out_be32(&reg->luminance, 0x9512a254);
+	out_be32(&reg->chroma_r, 0x03310000);
+	out_be32(&reg->chroma_g, 0x06600f38);
+	out_be32(&reg->chroma_b, 0x00000409);
+	out_be32(&reg->field_base_addr, 0);
+	out_be32(&reg->dma_inc, 0);
+	out_be32(&reg->picture_count, 0x01e002d0);
+	out_be32(&reg->req_alarm, 0x00000090);
+	out_be32(&reg->alpha, 0x000000ff);
+}
+
+static int viu_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct viu_fh *fh = file->private_data;
+	struct viu_dev *dev = fh->dev;
+	int ret;
+
+	dprintk(1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+
+	if (mutex_lock_interruptible(&dev->lock))
+		return -ERESTARTSYS;
+	ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+	mutex_unlock(&dev->lock);
+
+	dprintk(1, "vma start=0x%08lx, size=%ld, ret=%d\n",
+		(unsigned long)vma->vm_start,
+		(unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+		ret);
+
+	return ret;
+}
+
+static struct v4l2_file_operations viu_fops = {
+	.owner		= THIS_MODULE,
+	.open		= viu_open,
+	.release	= viu_release,
+	.read		= viu_read,
+	.poll		= viu_poll,
+	.unlocked_ioctl	= video_ioctl2, /* V4L2 ioctl handler */
+	.mmap		= viu_mmap,
+};
+
+static const struct v4l2_ioctl_ops viu_ioctl_ops = {
+	.vidioc_querycap	= vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt,
+	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_cap,
+	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_cap,
+	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_cap,
+	.vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt,
+	.vidioc_g_fmt_vid_overlay = vidioc_g_fmt_overlay,
+	.vidioc_try_fmt_vid_overlay = vidioc_try_fmt_overlay,
+	.vidioc_s_fmt_vid_overlay = vidioc_s_fmt_overlay,
+	.vidioc_overlay	      = vidioc_overlay,
+	.vidioc_g_fbuf	      = vidioc_g_fbuf,
+	.vidioc_s_fbuf	      = vidioc_s_fbuf,
+	.vidioc_reqbufs       = vidioc_reqbufs,
+	.vidioc_querybuf      = vidioc_querybuf,
+	.vidioc_qbuf          = vidioc_qbuf,
+	.vidioc_dqbuf         = vidioc_dqbuf,
+	.vidioc_g_std         = vidioc_g_std,
+	.vidioc_s_std         = vidioc_s_std,
+	.vidioc_querystd      = vidioc_querystd,
+	.vidioc_enum_input    = vidioc_enum_input,
+	.vidioc_g_input       = vidioc_g_input,
+	.vidioc_s_input       = vidioc_s_input,
+	.vidioc_queryctrl     = vidioc_queryctrl,
+	.vidioc_g_ctrl        = vidioc_g_ctrl,
+	.vidioc_s_ctrl        = vidioc_s_ctrl,
+	.vidioc_streamon      = vidioc_streamon,
+	.vidioc_streamoff     = vidioc_streamoff,
+};
+
+static struct video_device viu_template = {
+	.name		= "FSL viu",
+	.fops		= &viu_fops,
+	.minor		= -1,
+	.ioctl_ops	= &viu_ioctl_ops,
+	.release	= video_device_release,
+
+	.tvnorms        = V4L2_STD_NTSC_M | V4L2_STD_PAL,
+	.current_norm   = V4L2_STD_NTSC_M,
+};
+
+static int __devinit viu_of_probe(struct platform_device *op)
+{
+	struct viu_dev *viu_dev;
+	struct video_device *vdev;
+	struct resource r;
+	struct viu_reg __iomem *viu_regs;
+	struct i2c_adapter *ad;
+	int ret, viu_irq;
+
+	ret = of_address_to_resource(op->dev.of_node, 0, &r);
+	if (ret) {
+		dev_err(&op->dev, "Can't parse device node resource\n");
+		return -ENODEV;
+	}
+
+	viu_irq = irq_of_parse_and_map(op->dev.of_node, 0);
+	if (viu_irq == NO_IRQ) {
+		dev_err(&op->dev, "Error while mapping the irq\n");
+		return -EINVAL;
+	}
+
+	/* request mem region */
+	if (!devm_request_mem_region(&op->dev, r.start,
+				     sizeof(struct viu_reg), DRV_NAME)) {
+		dev_err(&op->dev, "Error while requesting mem region\n");
+		ret = -EBUSY;
+		goto err;
+	}
+
+	/* remap registers */
+	viu_regs = devm_ioremap(&op->dev, r.start, sizeof(struct viu_reg));
+	if (!viu_regs) {
+		dev_err(&op->dev, "Can't map register set\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	/* Prepare our private structure */
+	viu_dev = devm_kzalloc(&op->dev, sizeof(struct viu_dev), GFP_ATOMIC);
+	if (!viu_dev) {
+		dev_err(&op->dev, "Can't allocate private structure\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	viu_dev->vr = viu_regs;
+	viu_dev->irq = viu_irq;
+	viu_dev->dev = &op->dev;
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&viu_dev->vidq.active);
+	INIT_LIST_HEAD(&viu_dev->vidq.queued);
+
+	snprintf(viu_dev->v4l2_dev.name,
+		 sizeof(viu_dev->v4l2_dev.name), "%s", "VIU");
+	ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev);
+	if (ret < 0) {
+		dev_err(&op->dev, "v4l2_device_register() failed: %d\n", ret);
+		goto err;
+	}
+
+	ad = i2c_get_adapter(0);
+	viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad,
+			"saa7113", VIU_VIDEO_DECODER_ADDR, NULL);
+
+	viu_dev->vidq.timeout.function = viu_vid_timeout;
+	viu_dev->vidq.timeout.data     = (unsigned long)viu_dev;
+	init_timer(&viu_dev->vidq.timeout);
+	viu_dev->first = 1;
+
+	/* Allocate memory for video device */
+	vdev = video_device_alloc();
+	if (vdev == NULL) {
+		ret = -ENOMEM;
+		goto err_vdev;
+	}
+
+	memcpy(vdev, &viu_template, sizeof(viu_template));
+
+	vdev->v4l2_dev = &viu_dev->v4l2_dev;
+
+	viu_dev->vdev = vdev;
+
+	/* initialize locks */
+	mutex_init(&viu_dev->lock);
+	viu_dev->vdev->lock = &viu_dev->lock;
+	spin_lock_init(&viu_dev->slock);
+
+	video_set_drvdata(viu_dev->vdev, viu_dev);
+
+	mutex_lock(&viu_dev->lock);
+
+	ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1);
+	if (ret < 0) {
+		video_device_release(viu_dev->vdev);
+		goto err_vdev;
+	}
+
+	/* enable VIU clock */
+	viu_dev->clk = clk_get(&op->dev, "viu_clk");
+	if (IS_ERR(viu_dev->clk)) {
+		dev_err(&op->dev, "failed to find the clock module!\n");
+		ret = -ENODEV;
+		goto err_clk;
+	} else {
+		clk_enable(viu_dev->clk);
+	}
+
+	/* reset VIU module */
+	viu_reset(viu_dev->vr);
+
+	/* install interrupt handler */
+	if (request_irq(viu_dev->irq, viu_intr, 0, "viu", (void *)viu_dev)) {
+		dev_err(&op->dev, "Request VIU IRQ failed.\n");
+		ret = -ENODEV;
+		goto err_irq;
+	}
+
+	mutex_unlock(&viu_dev->lock);
+
+	dev_info(&op->dev, "Freescale VIU Video Capture Board\n");
+	return ret;
+
+err_irq:
+	clk_disable(viu_dev->clk);
+	clk_put(viu_dev->clk);
+err_clk:
+	video_unregister_device(viu_dev->vdev);
+err_vdev:
+	mutex_unlock(&viu_dev->lock);
+	i2c_put_adapter(ad);
+	v4l2_device_unregister(&viu_dev->v4l2_dev);
+err:
+	irq_dispose_mapping(viu_irq);
+	return ret;
+}
+
+static int __devexit viu_of_remove(struct platform_device *op)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+	struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+	struct v4l2_subdev *sdev = list_entry(v4l2_dev->subdevs.next,
+					      struct v4l2_subdev, list);
+	struct i2c_client *client = v4l2_get_subdevdata(sdev);
+
+	free_irq(dev->irq, (void *)dev);
+	irq_dispose_mapping(dev->irq);
+
+	clk_disable(dev->clk);
+	clk_put(dev->clk);
+
+	video_unregister_device(dev->vdev);
+	i2c_put_adapter(client->adapter);
+	v4l2_device_unregister(&dev->v4l2_dev);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int viu_suspend(struct platform_device *op, pm_message_t state)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+	struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+
+	clk_disable(dev->clk);
+	return 0;
+}
+
+static int viu_resume(struct platform_device *op)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+	struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+
+	clk_enable(dev->clk);
+	return 0;
+}
+#endif
+
+/*
+ * Initialization and module stuff
+ */
+static struct of_device_id mpc512x_viu_of_match[] = {
+	{
+		.compatible = "fsl,mpc5121-viu",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, mpc512x_viu_of_match);
+
+static struct platform_driver viu_of_platform_driver = {
+	.probe = viu_of_probe,
+	.remove = __devexit_p(viu_of_remove),
+#ifdef CONFIG_PM
+	.suspend = viu_suspend,
+	.resume = viu_resume,
+#endif
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = mpc512x_viu_of_match,
+	},
+};
+
+module_platform_driver(viu_of_platform_driver);
+
+MODULE_DESCRIPTION("Freescale Video-In(VIU)");
+MODULE_AUTHOR("Hongjun Chen");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(VIU_VERSION);
diff --git a/drivers/media/platform/indycam.c b/drivers/media/platform/indycam.c
new file mode 100644
index 0000000..5482363
--- /dev/null
+++ b/drivers/media/platform/indycam.c
@@ -0,0 +1,390 @@
+/*
+ *  indycam.c - Silicon Graphics IndyCam digital camera driver
+ *
+ *  Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ *  Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+/* IndyCam decodes stream of photons into digital image representation ;-) */
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "indycam.h"
+
+#define INDYCAM_MODULE_VERSION "0.0.5"
+
+MODULE_DESCRIPTION("SGI IndyCam driver");
+MODULE_VERSION(INDYCAM_MODULE_VERSION);
+MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
+MODULE_LICENSE("GPL");
+
+
+// #define INDYCAM_DEBUG
+
+#ifdef INDYCAM_DEBUG
+#define dprintk(x...) printk("IndyCam: " x);
+#define indycam_regdump(client) indycam_regdump_debug(client)
+#else
+#define dprintk(x...)
+#define indycam_regdump(client)
+#endif
+
+struct indycam {
+	struct v4l2_subdev sd;
+	u8 version;
+};
+
+static inline struct indycam *to_indycam(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct indycam, sd);
+}
+
+static const u8 initseq[] = {
+	INDYCAM_CONTROL_AGCENA,		/* INDYCAM_CONTROL */
+	INDYCAM_SHUTTER_60,		/* INDYCAM_SHUTTER */
+	INDYCAM_GAIN_DEFAULT,		/* INDYCAM_GAIN */
+	0x00,				/* INDYCAM_BRIGHTNESS (read-only) */
+	INDYCAM_RED_BALANCE_DEFAULT,	/* INDYCAM_RED_BALANCE */
+	INDYCAM_BLUE_BALANCE_DEFAULT,	/* INDYCAM_BLUE_BALANCE */
+	INDYCAM_RED_SATURATION_DEFAULT,	/* INDYCAM_RED_SATURATION */
+	INDYCAM_BLUE_SATURATION_DEFAULT,/* INDYCAM_BLUE_SATURATION */
+};
+
+/* IndyCam register handling */
+
+static int indycam_read_reg(struct v4l2_subdev *sd, u8 reg, u8 *value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+
+	if (reg == INDYCAM_REG_RESET) {
+		dprintk("indycam_read_reg(): "
+			"skipping write-only register %d\n", reg);
+		*value = 0;
+		return 0;
+	}
+
+	ret = i2c_smbus_read_byte_data(client, reg);
+
+	if (ret < 0) {
+		printk(KERN_ERR "IndyCam: indycam_read_reg(): read failed, "
+		       "register = 0x%02x\n", reg);
+		return ret;
+	}
+
+	*value = (u8)ret;
+
+	return 0;
+}
+
+static int indycam_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int err;
+
+	if (reg == INDYCAM_REG_BRIGHTNESS || reg == INDYCAM_REG_VERSION) {
+		dprintk("indycam_write_reg(): "
+			"skipping read-only register %d\n", reg);
+		return 0;
+	}
+
+	dprintk("Writing Reg %d = 0x%02x\n", reg, value);
+	err = i2c_smbus_write_byte_data(client, reg, value);
+
+	if (err) {
+		printk(KERN_ERR "IndyCam: indycam_write_reg(): write failed, "
+		       "register = 0x%02x, value = 0x%02x\n", reg, value);
+	}
+	return err;
+}
+
+static int indycam_write_block(struct v4l2_subdev *sd, u8 reg,
+			       u8 length, u8 *data)
+{
+	int i, err;
+
+	for (i = 0; i < length; i++) {
+		err = indycam_write_reg(sd, reg + i, data[i]);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/* Helper functions */
+
+#ifdef INDYCAM_DEBUG
+static void indycam_regdump_debug(struct v4l2_subdev *sd)
+{
+	int i;
+	u8 val;
+
+	for (i = 0; i < 9; i++) {
+		indycam_read_reg(sd, i, &val);
+		dprintk("Reg %d = 0x%02x\n", i, val);
+	}
+}
+#endif
+
+static int indycam_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	struct indycam *camera = to_indycam(sd);
+	u8 reg;
+	int ret = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTOGAIN:
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, &reg);
+		if (ret)
+			return -EIO;
+		if (ctrl->id == V4L2_CID_AUTOGAIN)
+			ctrl->value = (reg & INDYCAM_CONTROL_AGCENA)
+				? 1 : 0;
+		else
+			ctrl->value = (reg & INDYCAM_CONTROL_AWBCTL)
+				? 1 : 0;
+		break;
+	case V4L2_CID_EXPOSURE:
+		ret = indycam_read_reg(sd, INDYCAM_REG_SHUTTER, &reg);
+		if (ret)
+			return -EIO;
+		ctrl->value = ((s32)reg == 0x00) ? 0xff : ((s32)reg - 1);
+		break;
+	case V4L2_CID_GAIN:
+		ret = indycam_read_reg(sd, INDYCAM_REG_GAIN, &reg);
+		if (ret)
+			return -EIO;
+		ctrl->value = (s32)reg;
+		break;
+	case V4L2_CID_RED_BALANCE:
+		ret = indycam_read_reg(sd, INDYCAM_REG_RED_BALANCE, &reg);
+		if (ret)
+			return -EIO;
+		ctrl->value = (s32)reg;
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		ret = indycam_read_reg(sd, INDYCAM_REG_BLUE_BALANCE, &reg);
+		if (ret)
+			return -EIO;
+		ctrl->value = (s32)reg;
+		break;
+	case INDYCAM_CONTROL_RED_SATURATION:
+		ret = indycam_read_reg(sd,
+				       INDYCAM_REG_RED_SATURATION, &reg);
+		if (ret)
+			return -EIO;
+		ctrl->value = (s32)reg;
+		break;
+	case INDYCAM_CONTROL_BLUE_SATURATION:
+		ret = indycam_read_reg(sd,
+				       INDYCAM_REG_BLUE_SATURATION, &reg);
+		if (ret)
+			return -EIO;
+		ctrl->value = (s32)reg;
+		break;
+	case V4L2_CID_GAMMA:
+		if (camera->version == CAMERA_VERSION_MOOSE) {
+			ret = indycam_read_reg(sd,
+					       INDYCAM_REG_GAMMA, &reg);
+			if (ret)
+				return -EIO;
+			ctrl->value = (s32)reg;
+		} else {
+			ctrl->value = INDYCAM_GAMMA_DEFAULT;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int indycam_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	struct indycam *camera = to_indycam(sd);
+	u8 reg;
+	int ret = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTOGAIN:
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, &reg);
+		if (ret)
+			break;
+
+		if (ctrl->id == V4L2_CID_AUTOGAIN) {
+			if (ctrl->value)
+				reg |= INDYCAM_CONTROL_AGCENA;
+			else
+				reg &= ~INDYCAM_CONTROL_AGCENA;
+		} else {
+			if (ctrl->value)
+				reg |= INDYCAM_CONTROL_AWBCTL;
+			else
+				reg &= ~INDYCAM_CONTROL_AWBCTL;
+		}
+
+		ret = indycam_write_reg(sd, INDYCAM_REG_CONTROL, reg);
+		break;
+	case V4L2_CID_EXPOSURE:
+		reg = (ctrl->value == 0xff) ? 0x00 : (ctrl->value + 1);
+		ret = indycam_write_reg(sd, INDYCAM_REG_SHUTTER, reg);
+		break;
+	case V4L2_CID_GAIN:
+		ret = indycam_write_reg(sd, INDYCAM_REG_GAIN, ctrl->value);
+		break;
+	case V4L2_CID_RED_BALANCE:
+		ret = indycam_write_reg(sd, INDYCAM_REG_RED_BALANCE,
+					ctrl->value);
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_BALANCE,
+					ctrl->value);
+		break;
+	case INDYCAM_CONTROL_RED_SATURATION:
+		ret = indycam_write_reg(sd, INDYCAM_REG_RED_SATURATION,
+					ctrl->value);
+		break;
+	case INDYCAM_CONTROL_BLUE_SATURATION:
+		ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_SATURATION,
+					ctrl->value);
+		break;
+	case V4L2_CID_GAMMA:
+		if (camera->version == CAMERA_VERSION_MOOSE) {
+			ret = indycam_write_reg(sd, INDYCAM_REG_GAMMA,
+						ctrl->value);
+		}
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/* I2C-interface */
+
+static int indycam_g_chip_ident(struct v4l2_subdev *sd,
+		struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct indycam *camera = to_indycam(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_INDYCAM,
+		       camera->version);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops indycam_core_ops = {
+	.g_chip_ident = indycam_g_chip_ident,
+	.g_ctrl = indycam_g_ctrl,
+	.s_ctrl = indycam_s_ctrl,
+};
+
+static const struct v4l2_subdev_ops indycam_ops = {
+	.core = &indycam_core_ops,
+};
+
+static int indycam_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	int err = 0;
+	struct indycam *camera;
+	struct v4l2_subdev *sd;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	camera = kzalloc(sizeof(struct indycam), GFP_KERNEL);
+	if (!camera)
+		return -ENOMEM;
+
+	sd = &camera->sd;
+	v4l2_i2c_subdev_init(sd, client, &indycam_ops);
+
+	camera->version = i2c_smbus_read_byte_data(client,
+						   INDYCAM_REG_VERSION);
+	if (camera->version != CAMERA_VERSION_INDY &&
+	    camera->version != CAMERA_VERSION_MOOSE) {
+		kfree(camera);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "IndyCam v%d.%d detected\n",
+	       INDYCAM_VERSION_MAJOR(camera->version),
+	       INDYCAM_VERSION_MINOR(camera->version));
+
+	indycam_regdump(sd);
+
+	// initialize
+	err = indycam_write_block(sd, 0, sizeof(initseq), (u8 *)&initseq);
+	if (err) {
+		printk(KERN_ERR "IndyCam initialization failed\n");
+		kfree(camera);
+		return -EIO;
+	}
+
+	indycam_regdump(sd);
+
+	// white balance
+	err = indycam_write_reg(sd, INDYCAM_REG_CONTROL,
+			  INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL);
+	if (err) {
+		printk(KERN_ERR "IndyCam: White balancing camera failed\n");
+		kfree(camera);
+		return -EIO;
+	}
+
+	indycam_regdump(sd);
+
+	printk(KERN_INFO "IndyCam initialized\n");
+
+	return 0;
+}
+
+static int indycam_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_indycam(sd));
+	return 0;
+}
+
+static const struct i2c_device_id indycam_id[] = {
+	{ "indycam", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, indycam_id);
+
+static struct i2c_driver indycam_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "indycam",
+	},
+	.probe		= indycam_probe,
+	.remove		= indycam_remove,
+	.id_table	= indycam_id,
+};
+
+module_i2c_driver(indycam_driver);
diff --git a/drivers/media/platform/indycam.h b/drivers/media/platform/indycam.h
new file mode 100644
index 0000000..881f21c
--- /dev/null
+++ b/drivers/media/platform/indycam.h
@@ -0,0 +1,93 @@
+/*
+ *  indycam.h - Silicon Graphics IndyCam digital camera driver
+ *
+ *  Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ *  Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#ifndef _INDYCAM_H_
+#define _INDYCAM_H_
+
+/* I2C address for the Guinness Camera */
+#define INDYCAM_ADDR			0x56
+
+/* Camera version */
+#define CAMERA_VERSION_INDY		0x10	/* v1.0 */
+#define CAMERA_VERSION_MOOSE		0x12	/* v1.2 */
+#define INDYCAM_VERSION_MAJOR(x)	(((x) & 0xf0) >> 4)
+#define INDYCAM_VERSION_MINOR(x)	((x) & 0x0f)
+
+/* Register bus addresses */
+#define INDYCAM_REG_CONTROL		0x00
+#define INDYCAM_REG_SHUTTER		0x01
+#define INDYCAM_REG_GAIN		0x02
+#define INDYCAM_REG_BRIGHTNESS		0x03 /* read-only */
+#define INDYCAM_REG_RED_BALANCE		0x04
+#define INDYCAM_REG_BLUE_BALANCE	0x05
+#define INDYCAM_REG_RED_SATURATION	0x06
+#define INDYCAM_REG_BLUE_SATURATION	0x07
+#define INDYCAM_REG_GAMMA		0x08
+#define INDYCAM_REG_VERSION		0x0e /* read-only */
+#define INDYCAM_REG_RESET		0x0f /* write-only */
+
+#define INDYCAM_REG_LED			0x46
+#define INDYCAM_REG_ORIENTATION		0x47
+#define INDYCAM_REG_BUTTON		0x48
+
+/* Field definitions of registers */
+#define INDYCAM_CONTROL_AGCENA		(1<<0) /* automatic gain control */
+#define INDYCAM_CONTROL_AWBCTL		(1<<1) /* automatic white balance */
+						/* 2-3 are reserved */
+#define INDYCAM_CONTROL_EVNFLD		(1<<4)	/* read-only */
+
+#define INDYCAM_SHUTTER_10000		0x02	/* 1/10000 second */
+#define INDYCAM_SHUTTER_4000		0x04	/* 1/4000 second */
+#define INDYCAM_SHUTTER_2000		0x08	/* 1/2000 second */
+#define INDYCAM_SHUTTER_1000		0x10	/* 1/1000 second */
+#define INDYCAM_SHUTTER_500		0x20	/* 1/500 second */
+#define INDYCAM_SHUTTER_250		0x3f	/* 1/250 second */
+#define INDYCAM_SHUTTER_125		0x7e	/* 1/125 second */
+#define INDYCAM_SHUTTER_100		0x9e	/* 1/100 second */
+#define INDYCAM_SHUTTER_60		0x00	/* 1/60 second */
+
+#define INDYCAM_LED_ACTIVE			0x10
+#define INDYCAM_LED_INACTIVE			0x30
+#define INDYCAM_ORIENTATION_BOTTOM_TO_TOP	0x40
+#define INDYCAM_BUTTON_RELEASED			0x10
+
+/* Values for controls */
+#define INDYCAM_SHUTTER_MIN		0x00
+#define INDYCAM_SHUTTER_MAX		0xff
+#define INDYCAM_GAIN_MIN                0x00
+#define INDYCAM_GAIN_MAX                0xff
+#define INDYCAM_RED_BALANCE_MIN		0x00
+#define INDYCAM_RED_BALANCE_MAX		0xff
+#define INDYCAM_BLUE_BALANCE_MIN        0x00
+#define INDYCAM_BLUE_BALANCE_MAX        0xff
+#define INDYCAM_RED_SATURATION_MIN      0x00
+#define INDYCAM_RED_SATURATION_MAX      0xff
+#define INDYCAM_BLUE_SATURATION_MIN	0x00
+#define INDYCAM_BLUE_SATURATION_MAX	0xff
+#define INDYCAM_GAMMA_MIN		0x00
+#define INDYCAM_GAMMA_MAX		0xff
+
+#define INDYCAM_AGC_DEFAULT		1
+#define INDYCAM_AWB_DEFAULT		0
+#define INDYCAM_SHUTTER_DEFAULT		0xff
+#define INDYCAM_GAIN_DEFAULT		0x80
+#define INDYCAM_RED_BALANCE_DEFAULT	0x18
+#define INDYCAM_BLUE_BALANCE_DEFAULT	0xa4
+#define INDYCAM_RED_SATURATION_DEFAULT	0x80
+#define INDYCAM_BLUE_SATURATION_DEFAULT	0xc0
+#define INDYCAM_GAMMA_DEFAULT		0x80
+
+/* Driver interface definitions */
+
+#define INDYCAM_CONTROL_RED_SATURATION		(V4L2_CID_PRIVATE_BASE + 0)
+#define INDYCAM_CONTROL_BLUE_SATURATION		(V4L2_CID_PRIVATE_BASE + 1)
+
+#endif
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c
new file mode 100644
index 0000000..a38c152
--- /dev/null
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -0,0 +1,1120 @@
+/*
+ * V4L2 deinterlacing support.
+ *
+ * Copyright (c) 2012 Vista Silicon S.L.
+ * Javier Martin <javier.martin@vista-silicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/platform_device.h>
+
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+
+#define MEM2MEM_TEST_MODULE_NAME "mem2mem-deinterlace"
+
+MODULE_DESCRIPTION("mem2mem device which supports deinterlacing using dmaengine");
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.1");
+
+static bool debug = true;
+module_param(debug, bool, 0644);
+
+/* Flags that indicate a format can be used for capture/output */
+#define MEM2MEM_CAPTURE	(1 << 0)
+#define MEM2MEM_OUTPUT	(1 << 1)
+
+#define MEM2MEM_NAME		"m2m-deinterlace"
+
+#define dprintk(dev, fmt, arg...) \
+	v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
+
+struct deinterlace_fmt {
+	char	*name;
+	u32	fourcc;
+	/* Types the format can be used for */
+	u32	types;
+};
+
+static struct deinterlace_fmt formats[] = {
+	{
+		.name	= "YUV 4:2:0 Planar",
+		.fourcc	= V4L2_PIX_FMT_YUV420,
+		.types	= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+	},
+	{
+		.name	= "YUYV 4:2:2",
+		.fourcc	= V4L2_PIX_FMT_YUYV,
+		.types	= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+	},
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+/* Per-queue, driver-specific private data */
+struct deinterlace_q_data {
+	unsigned int		width;
+	unsigned int		height;
+	unsigned int		sizeimage;
+	struct deinterlace_fmt	*fmt;
+	enum v4l2_field		field;
+};
+
+enum {
+	V4L2_M2M_SRC = 0,
+	V4L2_M2M_DST = 1,
+};
+
+enum {
+	YUV420_DMA_Y_ODD,
+	YUV420_DMA_Y_EVEN,
+	YUV420_DMA_U_ODD,
+	YUV420_DMA_U_EVEN,
+	YUV420_DMA_V_ODD,
+	YUV420_DMA_V_EVEN,
+	YUV420_DMA_Y_ODD_DOUBLING,
+	YUV420_DMA_U_ODD_DOUBLING,
+	YUV420_DMA_V_ODD_DOUBLING,
+	YUYV_DMA_ODD,
+	YUYV_DMA_EVEN,
+	YUYV_DMA_EVEN_DOUBLING,
+};
+
+/* Source and destination queue data */
+static struct deinterlace_q_data q_data[2];
+
+static struct deinterlace_q_data *get_q_data(enum v4l2_buf_type type)
+{
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		return &q_data[V4L2_M2M_SRC];
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return &q_data[V4L2_M2M_DST];
+	default:
+		BUG();
+	}
+	return NULL;
+}
+
+static struct deinterlace_fmt *find_format(struct v4l2_format *f)
+{
+	struct deinterlace_fmt *fmt;
+	unsigned int k;
+
+	for (k = 0; k < NUM_FORMATS; k++) {
+		fmt = &formats[k];
+		if ((fmt->types & f->type) &&
+			(fmt->fourcc == f->fmt.pix.pixelformat))
+			break;
+	}
+
+	if (k == NUM_FORMATS)
+		return NULL;
+
+	return &formats[k];
+}
+
+struct deinterlace_dev {
+	struct v4l2_device	v4l2_dev;
+	struct video_device	*vfd;
+
+	atomic_t		busy;
+	struct mutex		dev_mutex;
+	spinlock_t		irqlock;
+
+	struct dma_chan		*dma_chan;
+
+	struct v4l2_m2m_dev	*m2m_dev;
+	struct vb2_alloc_ctx	*alloc_ctx;
+};
+
+struct deinterlace_ctx {
+	struct deinterlace_dev	*dev;
+
+	/* Abort requested by m2m */
+	int			aborting;
+	enum v4l2_colorspace	colorspace;
+	dma_cookie_t		cookie;
+	struct v4l2_m2m_ctx	*m2m_ctx;
+	struct dma_interleaved_template *xt;
+};
+
+/*
+ * mem2mem callbacks
+ */
+static int deinterlace_job_ready(void *priv)
+{
+	struct deinterlace_ctx *ctx = priv;
+	struct deinterlace_dev *pcdev = ctx->dev;
+
+	if ((v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) > 0)
+	    && (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) > 0)
+	    && (atomic_read(&ctx->dev->busy) == 0)) {
+		dprintk(pcdev, "Task ready\n");
+		return 1;
+	}
+
+	dprintk(pcdev, "Task not ready to run\n");
+
+	return 0;
+}
+
+static void deinterlace_job_abort(void *priv)
+{
+	struct deinterlace_ctx *ctx = priv;
+	struct deinterlace_dev *pcdev = ctx->dev;
+
+	ctx->aborting = 1;
+
+	dprintk(pcdev, "Aborting task\n");
+
+	v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx);
+}
+
+static void deinterlace_lock(void *priv)
+{
+	struct deinterlace_ctx *ctx = priv;
+	struct deinterlace_dev *pcdev = ctx->dev;
+	mutex_lock(&pcdev->dev_mutex);
+}
+
+static void deinterlace_unlock(void *priv)
+{
+	struct deinterlace_ctx *ctx = priv;
+	struct deinterlace_dev *pcdev = ctx->dev;
+	mutex_unlock(&pcdev->dev_mutex);
+}
+
+static void dma_callback(void *data)
+{
+	struct deinterlace_ctx *curr_ctx = data;
+	struct deinterlace_dev *pcdev = curr_ctx->dev;
+	struct vb2_buffer *src_vb, *dst_vb;
+
+	atomic_set(&pcdev->busy, 0);
+
+	src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
+	dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+
+	v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+	v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+
+	v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx);
+
+	dprintk(pcdev, "dma transfers completed.\n");
+}
+
+static void deinterlace_issue_dma(struct deinterlace_ctx *ctx, int op,
+				  int do_callback)
+{
+	struct deinterlace_q_data *s_q_data, *d_q_data;
+	struct vb2_buffer *src_buf, *dst_buf;
+	struct deinterlace_dev *pcdev = ctx->dev;
+	struct dma_chan *chan = pcdev->dma_chan;
+	struct dma_device *dmadev = chan->device;
+	struct dma_async_tx_descriptor *tx;
+	unsigned int s_width, s_height;
+	unsigned int d_width, d_height;
+	unsigned int d_size, s_size;
+	dma_addr_t p_in, p_out;
+	enum dma_ctrl_flags flags;
+
+	src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+
+	s_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	s_width	= s_q_data->width;
+	s_height = s_q_data->height;
+	s_size = s_width * s_height;
+
+	d_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	d_width = d_q_data->width;
+	d_height = d_q_data->height;
+	d_size = d_width * d_height;
+
+	p_in = (dma_addr_t)vb2_dma_contig_plane_dma_addr(src_buf, 0);
+	p_out = (dma_addr_t)vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+	if (!p_in || !p_out) {
+		v4l2_err(&pcdev->v4l2_dev,
+			 "Acquiring kernel pointers to buffers failed\n");
+		return;
+	}
+
+	switch (op) {
+	case YUV420_DMA_Y_ODD:
+		ctx->xt->numf = s_height / 2;
+		ctx->xt->sgl[0].size = s_width;
+		ctx->xt->sgl[0].icg = s_width;
+		ctx->xt->src_start = p_in;
+		ctx->xt->dst_start = p_out;
+		break;
+	case YUV420_DMA_Y_EVEN:
+		ctx->xt->numf = s_height / 2;
+		ctx->xt->sgl[0].size = s_width;
+		ctx->xt->sgl[0].icg = s_width;
+		ctx->xt->src_start = p_in + s_size / 2;
+		ctx->xt->dst_start = p_out + s_width;
+		break;
+	case YUV420_DMA_U_ODD:
+		ctx->xt->numf = s_height / 4;
+		ctx->xt->sgl[0].size = s_width / 2;
+		ctx->xt->sgl[0].icg = s_width / 2;
+		ctx->xt->src_start = p_in + s_size;
+		ctx->xt->dst_start = p_out + s_size;
+		break;
+	case YUV420_DMA_U_EVEN:
+		ctx->xt->numf = s_height / 4;
+		ctx->xt->sgl[0].size = s_width / 2;
+		ctx->xt->sgl[0].icg = s_width / 2;
+		ctx->xt->src_start = p_in + (9 * s_size) / 8;
+		ctx->xt->dst_start = p_out + s_size + s_width / 2;
+		break;
+	case YUV420_DMA_V_ODD:
+		ctx->xt->numf = s_height / 4;
+		ctx->xt->sgl[0].size = s_width / 2;
+		ctx->xt->sgl[0].icg = s_width / 2;
+		ctx->xt->src_start = p_in + (5 * s_size) / 4;
+		ctx->xt->dst_start = p_out + (5 * s_size) / 4;
+		break;
+	case YUV420_DMA_V_EVEN:
+		ctx->xt->numf = s_height / 4;
+		ctx->xt->sgl[0].size = s_width / 2;
+		ctx->xt->sgl[0].icg = s_width / 2;
+		ctx->xt->src_start = p_in + (11 * s_size) / 8;
+		ctx->xt->dst_start = p_out + (5 * s_size) / 4 + s_width / 2;
+		break;
+	case YUV420_DMA_Y_ODD_DOUBLING:
+		ctx->xt->numf = s_height / 2;
+		ctx->xt->sgl[0].size = s_width;
+		ctx->xt->sgl[0].icg = s_width;
+		ctx->xt->src_start = p_in;
+		ctx->xt->dst_start = p_out + s_width;
+		break;
+	case YUV420_DMA_U_ODD_DOUBLING:
+		ctx->xt->numf = s_height / 4;
+		ctx->xt->sgl[0].size = s_width / 2;
+		ctx->xt->sgl[0].icg = s_width / 2;
+		ctx->xt->src_start = p_in + s_size;
+		ctx->xt->dst_start = p_out + s_size + s_width / 2;
+		break;
+	case YUV420_DMA_V_ODD_DOUBLING:
+		ctx->xt->numf = s_height / 4;
+		ctx->xt->sgl[0].size = s_width / 2;
+		ctx->xt->sgl[0].icg = s_width / 2;
+		ctx->xt->src_start = p_in + (5 * s_size) / 4;
+		ctx->xt->dst_start = p_out + (5 * s_size) / 4 + s_width / 2;
+		break;
+	case YUYV_DMA_ODD:
+		ctx->xt->numf = s_height / 2;
+		ctx->xt->sgl[0].size = s_width * 2;
+		ctx->xt->sgl[0].icg = s_width * 2;
+		ctx->xt->src_start = p_in;
+		ctx->xt->dst_start = p_out;
+		break;
+	case YUYV_DMA_EVEN:
+		ctx->xt->numf = s_height / 2;
+		ctx->xt->sgl[0].size = s_width * 2;
+		ctx->xt->sgl[0].icg = s_width * 2;
+		ctx->xt->src_start = p_in + s_size;
+		ctx->xt->dst_start = p_out + s_width * 2;
+		break;
+	case YUYV_DMA_EVEN_DOUBLING:
+	default:
+		ctx->xt->numf = s_height / 2;
+		ctx->xt->sgl[0].size = s_width * 2;
+		ctx->xt->sgl[0].icg = s_width * 2;
+		ctx->xt->src_start = p_in;
+		ctx->xt->dst_start = p_out + s_width * 2;
+		break;
+	}
+
+	/* Common parameters for al transfers */
+	ctx->xt->frame_size = 1;
+	ctx->xt->dir = DMA_MEM_TO_MEM;
+	ctx->xt->src_sgl = false;
+	ctx->xt->dst_sgl = true;
+	flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT |
+		DMA_COMPL_SKIP_DEST_UNMAP | DMA_COMPL_SKIP_SRC_UNMAP;
+
+	tx = dmadev->device_prep_interleaved_dma(chan, ctx->xt, flags);
+	if (tx == NULL) {
+		v4l2_warn(&pcdev->v4l2_dev, "DMA interleaved prep error\n");
+		return;
+	}
+
+	if (do_callback) {
+		tx->callback = dma_callback;
+		tx->callback_param = ctx;
+	}
+
+	ctx->cookie = dmaengine_submit(tx);
+	if (dma_submit_error(ctx->cookie)) {
+		v4l2_warn(&pcdev->v4l2_dev,
+			  "DMA submit error %d with src=0x%x dst=0x%x len=0x%x\n",
+			  ctx->cookie, (unsigned)p_in, (unsigned)p_out,
+			  s_size * 3/2);
+		return;
+	}
+
+	dma_async_issue_pending(chan);
+}
+
+static void deinterlace_device_run(void *priv)
+{
+	struct deinterlace_ctx *ctx = priv;
+	struct deinterlace_q_data *dst_q_data;
+
+	atomic_set(&ctx->dev->busy, 1);
+
+	dprintk(ctx->dev, "%s: DMA try issue.\n", __func__);
+
+	dst_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+	/*
+	 * 4 possible field conversions are possible at the moment:
+	 *  V4L2_FIELD_SEQ_TB --> V4L2_FIELD_INTERLACED_TB:
+	 *	two separate fields in the same input buffer are interlaced
+	 * 	in the output buffer using weaving. Top field comes first.
+	 *  V4L2_FIELD_SEQ_TB --> V4L2_FIELD_NONE:
+	 * 	top field from the input buffer is copied to the output buffer
+	 * 	using line doubling. Bottom field from the input buffer is discarded.
+	 * V4L2_FIELD_SEQ_BT --> V4L2_FIELD_INTERLACED_BT:
+	 *	two separate fields in the same input buffer are interlaced
+	 * 	in the output buffer using weaving. Bottom field comes first.
+	 * V4L2_FIELD_SEQ_BT --> V4L2_FIELD_NONE:
+	 * 	bottom field from the input buffer is copied to the output buffer
+	 * 	using line doubling. Top field from the input buffer is discarded.
+	 */
+	switch (dst_q_data->fmt->fourcc) {
+	case V4L2_PIX_FMT_YUV420:
+		switch (dst_q_data->field) {
+		case V4L2_FIELD_INTERLACED_TB:
+		case V4L2_FIELD_INTERLACED_BT:
+			dprintk(ctx->dev, "%s: yuv420 interlaced tb.\n",
+				__func__);
+			deinterlace_issue_dma(ctx, YUV420_DMA_Y_ODD, 0);
+			deinterlace_issue_dma(ctx, YUV420_DMA_Y_EVEN, 0);
+			deinterlace_issue_dma(ctx, YUV420_DMA_U_ODD, 0);
+			deinterlace_issue_dma(ctx, YUV420_DMA_U_EVEN, 0);
+			deinterlace_issue_dma(ctx, YUV420_DMA_V_ODD, 0);
+			deinterlace_issue_dma(ctx, YUV420_DMA_V_EVEN, 1);
+			break;
+		case V4L2_FIELD_NONE:
+		default:
+			dprintk(ctx->dev, "%s: yuv420 interlaced line doubling.\n",
+				__func__);
+			deinterlace_issue_dma(ctx, YUV420_DMA_Y_ODD, 0);
+			deinterlace_issue_dma(ctx, YUV420_DMA_Y_ODD_DOUBLING, 0);
+			deinterlace_issue_dma(ctx, YUV420_DMA_U_ODD, 0);
+			deinterlace_issue_dma(ctx, YUV420_DMA_U_ODD_DOUBLING, 0);
+			deinterlace_issue_dma(ctx, YUV420_DMA_V_ODD, 0);
+			deinterlace_issue_dma(ctx, YUV420_DMA_V_ODD_DOUBLING, 1);
+			break;
+		}
+		break;
+	case V4L2_PIX_FMT_YUYV:
+	default:
+		switch (dst_q_data->field) {
+		case V4L2_FIELD_INTERLACED_TB:
+		case V4L2_FIELD_INTERLACED_BT:
+			dprintk(ctx->dev, "%s: yuyv interlaced_tb.\n",
+				__func__);
+			deinterlace_issue_dma(ctx, YUYV_DMA_ODD, 0);
+			deinterlace_issue_dma(ctx, YUYV_DMA_EVEN, 1);
+			break;
+		case V4L2_FIELD_NONE:
+		default:
+			dprintk(ctx->dev, "%s: yuyv interlaced line doubling.\n",
+				__func__);
+			deinterlace_issue_dma(ctx, YUYV_DMA_ODD, 0);
+			deinterlace_issue_dma(ctx, YUYV_DMA_EVEN_DOUBLING, 1);
+			break;
+		}
+		break;
+	}
+
+	dprintk(ctx->dev, "%s: DMA issue done.\n", __func__);
+}
+
+/*
+ * video ioctls
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	strlcpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
+	strlcpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->card));
+	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
+			  | V4L2_CAP_STREAMING;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+	return 0;
+}
+
+static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
+{
+	int i, num;
+	struct deinterlace_fmt *fmt;
+
+	num = 0;
+
+	for (i = 0; i < NUM_FORMATS; ++i) {
+		if (formats[i].types & type) {
+			/* index-th format of type type found ? */
+			if (num == f->index)
+				break;
+			/* Correct type but haven't reached our index yet,
+			 * just increment per-type index */
+			++num;
+		}
+	}
+
+	if (i < NUM_FORMATS) {
+		/* Format found */
+		fmt = &formats[i];
+		strlcpy(f->description, fmt->name, sizeof(f->description));
+		f->pixelformat = fmt->fourcc;
+		return 0;
+	}
+
+	/* Format not found */
+	return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	return enum_fmt(f, MEM2MEM_CAPTURE);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	return enum_fmt(f, MEM2MEM_OUTPUT);
+}
+
+static int vidioc_g_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f)
+{
+	struct vb2_queue *vq;
+	struct deinterlace_q_data *q_data;
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+
+	q_data = get_q_data(f->type);
+
+	f->fmt.pix.width	= q_data->width;
+	f->fmt.pix.height	= q_data->height;
+	f->fmt.pix.field	= q_data->field;
+	f->fmt.pix.pixelformat	= q_data->fmt->fourcc;
+
+	switch (q_data->fmt->fourcc) {
+	case V4L2_PIX_FMT_YUV420:
+		f->fmt.pix.bytesperline = q_data->width * 3 / 2;
+		break;
+	case V4L2_PIX_FMT_YUYV:
+	default:
+		f->fmt.pix.bytesperline = q_data->width * 2;
+	}
+
+	f->fmt.pix.sizeimage	= q_data->sizeimage;
+	f->fmt.pix.colorspace	= ctx->colorspace;
+
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	return vidioc_g_fmt(priv, f);
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	return vidioc_g_fmt(priv, f);
+}
+
+static int vidioc_try_fmt(struct v4l2_format *f, struct deinterlace_fmt *fmt)
+{
+	switch (f->fmt.pix.pixelformat) {
+	case V4L2_PIX_FMT_YUV420:
+		f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2;
+		break;
+	case V4L2_PIX_FMT_YUYV:
+	default:
+		f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+	}
+	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct deinterlace_fmt *fmt;
+	struct deinterlace_ctx *ctx = priv;
+
+	fmt = find_format(f);
+	if (!fmt || !(fmt->types & MEM2MEM_CAPTURE))
+		f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+
+	f->fmt.pix.colorspace = ctx->colorspace;
+
+	if (f->fmt.pix.field != V4L2_FIELD_INTERLACED_TB &&
+	    f->fmt.pix.field != V4L2_FIELD_INTERLACED_BT &&
+	    f->fmt.pix.field != V4L2_FIELD_NONE)
+		f->fmt.pix.field = V4L2_FIELD_INTERLACED_TB;
+
+	return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct deinterlace_fmt *fmt;
+
+	fmt = find_format(f);
+	if (!fmt || !(fmt->types & MEM2MEM_OUTPUT))
+		f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+
+	if (!f->fmt.pix.colorspace)
+		f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+
+	if (f->fmt.pix.field != V4L2_FIELD_SEQ_TB &&
+	    f->fmt.pix.field != V4L2_FIELD_SEQ_BT)
+		f->fmt.pix.field = V4L2_FIELD_SEQ_TB;
+
+	return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_s_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f)
+{
+	struct deinterlace_q_data *q_data;
+	struct vb2_queue *vq;
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+
+	q_data = get_q_data(f->type);
+	if (!q_data)
+		return -EINVAL;
+
+	if (vb2_is_busy(vq)) {
+		v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
+		return -EBUSY;
+	}
+
+	q_data->fmt = find_format(f);
+	if (!q_data->fmt) {
+		v4l2_err(&ctx->dev->v4l2_dev,
+			 "Couldn't set format type %d, wxh: %dx%d. fmt: %d, field: %d\n",
+			f->type, f->fmt.pix.width, f->fmt.pix.height,
+			f->fmt.pix.pixelformat, f->fmt.pix.field);
+		return -EINVAL;
+	}
+
+	q_data->width		= f->fmt.pix.width;
+	q_data->height		= f->fmt.pix.height;
+	q_data->field		= f->fmt.pix.field;
+
+	switch (f->fmt.pix.pixelformat) {
+	case V4L2_PIX_FMT_YUV420:
+		f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2;
+		q_data->sizeimage = (q_data->width * q_data->height * 3) / 2;
+		break;
+	case V4L2_PIX_FMT_YUYV:
+	default:
+		f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+		q_data->sizeimage = q_data->width * q_data->height * 2;
+	}
+
+	dprintk(ctx->dev,
+		"Setting format for type %d, wxh: %dx%d, fmt: %d, field: %d\n",
+		f->type, q_data->width, q_data->height, q_data->fmt->fourcc,
+		q_data->field);
+
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	int ret;
+
+	ret = vidioc_try_fmt_vid_cap(file, priv, f);
+	if (ret)
+		return ret;
+	return vidioc_s_fmt(priv, f);
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct deinterlace_ctx *ctx = priv;
+	int ret;
+
+	ret = vidioc_try_fmt_vid_out(file, priv, f);
+	if (ret)
+		return ret;
+
+	ret = vidioc_s_fmt(priv, f);
+	if (!ret)
+		ctx->colorspace = f->fmt.pix.colorspace;
+
+	return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *reqbufs)
+{
+	struct deinterlace_ctx *ctx = priv;
+
+	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+			   struct v4l2_buffer *buf)
+{
+	struct deinterlace_ctx *ctx = priv;
+
+	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct deinterlace_ctx *ctx = priv;
+
+	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct deinterlace_ctx *ctx = priv;
+
+	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type type)
+{
+	struct deinterlace_q_data *s_q_data, *d_q_data;
+	struct deinterlace_ctx *ctx = priv;
+
+	s_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	d_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+	/* Check that src and dst queues have the same pix format */
+	if (s_q_data->fmt->fourcc != d_q_data->fmt->fourcc) {
+		v4l2_err(&ctx->dev->v4l2_dev,
+			 "src and dst formats don't match.\n");
+		return -EINVAL;
+	}
+
+	/* Check that input and output deinterlacing types are compatible */
+	switch (s_q_data->field) {
+	case V4L2_FIELD_SEQ_BT:
+		if (d_q_data->field != V4L2_FIELD_NONE &&
+			d_q_data->field != V4L2_FIELD_INTERLACED_BT) {
+			v4l2_err(&ctx->dev->v4l2_dev,
+			 "src and dst field conversion [(%d)->(%d)] not supported.\n",
+				s_q_data->field, d_q_data->field);
+			return -EINVAL;
+		}
+		break;
+	case V4L2_FIELD_SEQ_TB:
+		if (d_q_data->field != V4L2_FIELD_NONE &&
+			d_q_data->field != V4L2_FIELD_INTERLACED_TB) {
+			v4l2_err(&ctx->dev->v4l2_dev,
+			 "src and dst field conversion [(%d)->(%d)] not supported.\n",
+				s_q_data->field, d_q_data->field);
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type type)
+{
+	struct deinterlace_ctx *ctx = priv;
+
+	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static const struct v4l2_ioctl_ops deinterlace_ioctl_ops = {
+	.vidioc_querycap	= vidioc_querycap,
+
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,
+
+	.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out	= vidioc_g_fmt_vid_out,
+	.vidioc_try_fmt_vid_out	= vidioc_try_fmt_vid_out,
+	.vidioc_s_fmt_vid_out	= vidioc_s_fmt_vid_out,
+
+	.vidioc_reqbufs		= vidioc_reqbufs,
+	.vidioc_querybuf	= vidioc_querybuf,
+
+	.vidioc_qbuf		= vidioc_qbuf,
+	.vidioc_dqbuf		= vidioc_dqbuf,
+
+	.vidioc_streamon	= vidioc_streamon,
+	.vidioc_streamoff	= vidioc_streamoff,
+};
+
+
+/*
+ * Queue operations
+ */
+struct vb2_dc_conf {
+	struct device           *dev;
+};
+
+static int deinterlace_queue_setup(struct vb2_queue *vq,
+				const struct v4l2_format *fmt,
+				unsigned int *nbuffers, unsigned int *nplanes,
+				unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq);
+	struct deinterlace_q_data *q_data;
+	unsigned int size, count = *nbuffers;
+
+	q_data = get_q_data(vq->type);
+
+	switch (q_data->fmt->fourcc) {
+	case V4L2_PIX_FMT_YUV420:
+		size = q_data->width * q_data->height * 3 / 2;
+		break;
+	case V4L2_PIX_FMT_YUYV:
+	default:
+		size = q_data->width * q_data->height * 2;
+	}
+
+	*nplanes = 1;
+	*nbuffers = count;
+	sizes[0] = size;
+
+	alloc_ctxs[0] = ctx->dev->alloc_ctx;
+
+	dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
+
+	return 0;
+}
+
+static int deinterlace_buf_prepare(struct vb2_buffer *vb)
+{
+	struct deinterlace_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct deinterlace_q_data *q_data;
+
+	dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
+
+	q_data = get_q_data(vb->vb2_queue->type);
+
+	if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
+		dprintk(ctx->dev, "%s data will not fit into plane (%lu < %lu)\n",
+			__func__, vb2_plane_size(vb, 0), (long)q_data->sizeimage);
+		return -EINVAL;
+	}
+
+	vb2_set_plane_payload(vb, 0, q_data->sizeimage);
+
+	return 0;
+}
+
+static void deinterlace_buf_queue(struct vb2_buffer *vb)
+{
+	struct deinterlace_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static struct vb2_ops deinterlace_qops = {
+	.queue_setup	 = deinterlace_queue_setup,
+	.buf_prepare	 = deinterlace_buf_prepare,
+	.buf_queue	 = deinterlace_buf_queue,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+		      struct vb2_queue *dst_vq)
+{
+	struct deinterlace_ctx *ctx = priv;
+	int ret;
+
+	memset(src_vq, 0, sizeof(*src_vq));
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+	src_vq->drv_priv = ctx;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	src_vq->ops = &deinterlace_qops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+	q_data[V4L2_M2M_SRC].fmt = &formats[0];
+	q_data[V4L2_M2M_SRC].width = 640;
+	q_data[V4L2_M2M_SRC].height = 480;
+	q_data[V4L2_M2M_SRC].sizeimage = (640 * 480 * 3) / 2;
+	q_data[V4L2_M2M_SRC].field = V4L2_FIELD_SEQ_TB;
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	memset(dst_vq, 0, sizeof(*dst_vq));
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+	dst_vq->drv_priv = ctx;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->ops = &deinterlace_qops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+	q_data[V4L2_M2M_DST].fmt = &formats[0];
+	q_data[V4L2_M2M_DST].width = 640;
+	q_data[V4L2_M2M_DST].height = 480;
+	q_data[V4L2_M2M_DST].sizeimage = (640 * 480 * 3) / 2;
+	q_data[V4L2_M2M_SRC].field = V4L2_FIELD_INTERLACED_TB;
+
+	return vb2_queue_init(dst_vq);
+}
+
+/*
+ * File operations
+ */
+static int deinterlace_open(struct file *file)
+{
+	struct deinterlace_dev *pcdev = video_drvdata(file);
+	struct deinterlace_ctx *ctx = NULL;
+
+	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	file->private_data = ctx;
+	ctx->dev = pcdev;
+
+	ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init);
+	if (IS_ERR(ctx->m2m_ctx)) {
+		int ret = PTR_ERR(ctx->m2m_ctx);
+
+		kfree(ctx);
+		return ret;
+	}
+
+	ctx->xt = kzalloc(sizeof(struct dma_async_tx_descriptor) +
+				sizeof(struct data_chunk), GFP_KERNEL);
+	if (!ctx->xt) {
+		int ret = PTR_ERR(ctx->xt);
+
+		kfree(ctx);
+		return ret;
+	}
+
+	ctx->colorspace = V4L2_COLORSPACE_REC709;
+
+	dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
+
+	return 0;
+}
+
+static int deinterlace_release(struct file *file)
+{
+	struct deinterlace_dev *pcdev = video_drvdata(file);
+	struct deinterlace_ctx *ctx = file->private_data;
+
+	dprintk(pcdev, "Releasing instance %p\n", ctx);
+
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+	kfree(ctx->xt);
+	kfree(ctx);
+
+	return 0;
+}
+
+static unsigned int deinterlace_poll(struct file *file,
+				 struct poll_table_struct *wait)
+{
+	struct deinterlace_ctx *ctx = file->private_data;
+	int ret;
+
+	deinterlace_lock(ctx);
+	ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+	deinterlace_unlock(ctx);
+
+	return ret;
+}
+
+static int deinterlace_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct deinterlace_ctx *ctx = file->private_data;
+
+	return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations deinterlace_fops = {
+	.owner		= THIS_MODULE,
+	.open		= deinterlace_open,
+	.release	= deinterlace_release,
+	.poll		= deinterlace_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= deinterlace_mmap,
+};
+
+static struct video_device deinterlace_videodev = {
+	.name		= MEM2MEM_NAME,
+	.fops		= &deinterlace_fops,
+	.ioctl_ops	= &deinterlace_ioctl_ops,
+	.minor		= -1,
+	.release	= video_device_release,
+};
+
+static struct v4l2_m2m_ops m2m_ops = {
+	.device_run	= deinterlace_device_run,
+	.job_ready	= deinterlace_job_ready,
+	.job_abort	= deinterlace_job_abort,
+	.lock		= deinterlace_lock,
+	.unlock		= deinterlace_unlock,
+};
+
+static int deinterlace_probe(struct platform_device *pdev)
+{
+	struct deinterlace_dev *pcdev;
+	struct video_device *vfd;
+	dma_cap_mask_t mask;
+	int ret = 0;
+
+	pcdev = kzalloc(sizeof *pcdev, GFP_KERNEL);
+	if (!pcdev)
+		return -ENOMEM;
+
+	spin_lock_init(&pcdev->irqlock);
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_INTERLEAVE, mask);
+	pcdev->dma_chan = dma_request_channel(mask, NULL, pcdev);
+	if (!pcdev->dma_chan)
+		goto free_dev;
+
+	if (!dma_has_cap(DMA_INTERLEAVE, pcdev->dma_chan->device->cap_mask)) {
+		v4l2_err(&pcdev->v4l2_dev, "DMA does not support INTERLEAVE\n");
+		goto rel_dma;
+	}
+
+	ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev);
+	if (ret)
+		goto rel_dma;
+
+	atomic_set(&pcdev->busy, 0);
+	mutex_init(&pcdev->dev_mutex);
+
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(&pcdev->v4l2_dev, "Failed to allocate video device\n");
+		ret = -ENOMEM;
+		goto unreg_dev;
+	}
+
+	*vfd = deinterlace_videodev;
+	vfd->lock = &pcdev->dev_mutex;
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+	if (ret) {
+		v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n");
+		goto rel_vdev;
+	}
+
+	video_set_drvdata(vfd, pcdev);
+	snprintf(vfd->name, sizeof(vfd->name), "%s", deinterlace_videodev.name);
+	pcdev->vfd = vfd;
+	v4l2_info(&pcdev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME
+			" Device registered as /dev/video%d\n", vfd->num);
+
+	platform_set_drvdata(pdev, pcdev);
+
+	pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+	if (IS_ERR(pcdev->alloc_ctx)) {
+		v4l2_err(&pcdev->v4l2_dev, "Failed to alloc vb2 context\n");
+		ret = PTR_ERR(pcdev->alloc_ctx);
+		goto err_ctx;
+	}
+
+	pcdev->m2m_dev = v4l2_m2m_init(&m2m_ops);
+	if (IS_ERR(pcdev->m2m_dev)) {
+		v4l2_err(&pcdev->v4l2_dev, "Failed to init mem2mem device\n");
+		ret = PTR_ERR(pcdev->m2m_dev);
+		goto err_m2m;
+	}
+
+	return 0;
+
+	v4l2_m2m_release(pcdev->m2m_dev);
+err_m2m:
+	video_unregister_device(pcdev->vfd);
+err_ctx:
+	vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+rel_vdev:
+	video_device_release(vfd);
+unreg_dev:
+	v4l2_device_unregister(&pcdev->v4l2_dev);
+rel_dma:
+	dma_release_channel(pcdev->dma_chan);
+free_dev:
+	kfree(pcdev);
+
+	return ret;
+}
+
+static int deinterlace_remove(struct platform_device *pdev)
+{
+	struct deinterlace_dev *pcdev =
+		(struct deinterlace_dev *)platform_get_drvdata(pdev);
+
+	v4l2_info(&pcdev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME);
+	v4l2_m2m_release(pcdev->m2m_dev);
+	video_unregister_device(pcdev->vfd);
+	v4l2_device_unregister(&pcdev->v4l2_dev);
+	vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+	dma_release_channel(pcdev->dma_chan);
+	kfree(pcdev);
+
+	return 0;
+}
+
+static struct platform_driver deinterlace_pdrv = {
+	.probe		= deinterlace_probe,
+	.remove		= deinterlace_remove,
+	.driver		= {
+		.name	= MEM2MEM_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static void __exit deinterlace_exit(void)
+{
+	platform_driver_unregister(&deinterlace_pdrv);
+}
+
+static int __init deinterlace_init(void)
+{
+	return platform_driver_register(&deinterlace_pdrv);
+}
+
+module_init(deinterlace_init);
+module_exit(deinterlace_exit);
+
diff --git a/drivers/media/platform/marvell-ccic/Kconfig b/drivers/media/platform/marvell-ccic/Kconfig
new file mode 100644
index 0000000..bf739e3
--- /dev/null
+++ b/drivers/media/platform/marvell-ccic/Kconfig
@@ -0,0 +1,23 @@
+config VIDEO_CAFE_CCIC
+	tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support"
+	depends on PCI && I2C && VIDEO_V4L2
+	select VIDEO_OV7670
+	select VIDEOBUF2_VMALLOC
+	select VIDEOBUF2_DMA_CONTIG
+	---help---
+	  This is a video4linux2 driver for the Marvell 88ALP01 integrated
+	  CMOS camera controller.  This is the controller found on first-
+	  generation OLPC systems.
+
+config VIDEO_MMP_CAMERA
+	tristate "Marvell Armada 610 integrated camera controller support"
+	depends on ARCH_MMP && I2C && VIDEO_V4L2
+	select VIDEO_OV7670
+	select I2C_GPIO
+	select VIDEOBUF2_DMA_SG
+	---help---
+	  This is a Video4Linux2 driver for the integrated camera
+	  controller found on Marvell Armada 610 application
+	  processors (and likely beyond).  This is the controller found
+	  in OLPC XO 1.75 systems.
+
diff --git a/drivers/media/platform/marvell-ccic/Makefile b/drivers/media/platform/marvell-ccic/Makefile
new file mode 100644
index 0000000..05a792c
--- /dev/null
+++ b/drivers/media/platform/marvell-ccic/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
+cafe_ccic-y := cafe-driver.o mcam-core.o
+
+obj-$(CONFIG_VIDEO_MMP_CAMERA) += mmp_camera.o
+mmp_camera-y := mmp-driver.o mcam-core.o
+
diff --git a/drivers/media/platform/marvell-ccic/cafe-driver.c b/drivers/media/platform/marvell-ccic/cafe-driver.c
new file mode 100644
index 0000000..d030f9b
--- /dev/null
+++ b/drivers/media/platform/marvell-ccic/cafe-driver.c
@@ -0,0 +1,654 @@
+/*
+ * A driver for the CMOS camera controller in the Marvell 88ALP01 "cafe"
+ * multifunction chip.  Currently works with the Omnivision OV7670
+ * sensor.
+ *
+ * The data sheet for this device can be found at:
+ *    http://www.marvell.com/products/pc_connectivity/88alp01/
+ *
+ * Copyright 2006-11 One Laptop Per Child Association, Inc.
+ * Copyright 2006-11 Jonathan Corbet <corbet@lwn.net>
+ *
+ * Written by Jonathan Corbet, corbet@lwn.net.
+ *
+ * v4l2_device/v4l2_subdev conversion by:
+ * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "mcam-core.h"
+
+#define CAFE_VERSION 0x000002
+
+
+/*
+ * Parameters.
+ */
+MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
+MODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("Video");
+
+
+
+
+struct cafe_camera {
+	int registered;			/* Fully initialized? */
+	struct mcam_camera mcam;
+	struct pci_dev *pdev;
+	wait_queue_head_t smbus_wait;	/* Waiting on i2c events */
+};
+
+/*
+ * Most of the camera controller registers are defined in mcam-core.h,
+ * but the Cafe platform has some additional registers of its own;
+ * they are described here.
+ */
+
+/*
+ * "General purpose register" has a couple of GPIOs used for sensor
+ * power and reset on OLPC XO 1.0 systems.
+ */
+#define REG_GPR		0xb4
+#define	  GPR_C1EN	  0x00000020	/* Pad 1 (power down) enable */
+#define	  GPR_C0EN	  0x00000010	/* Pad 0 (reset) enable */
+#define	  GPR_C1	  0x00000002	/* Control 1 value */
+/*
+ * Control 0 is wired to reset on OLPC machines.  For ov7x sensors,
+ * it is active low.
+ */
+#define	  GPR_C0	  0x00000001	/* Control 0 value */
+
+/*
+ * These registers control the SMBUS module for communicating
+ * with the sensor.
+ */
+#define REG_TWSIC0	0xb8	/* TWSI (smbus) control 0 */
+#define	  TWSIC0_EN	  0x00000001	/* TWSI enable */
+#define	  TWSIC0_MODE	  0x00000002	/* 1 = 16-bit, 0 = 8-bit */
+#define	  TWSIC0_SID	  0x000003fc	/* Slave ID */
+/*
+ * Subtle trickery: the slave ID field starts with bit 2.  But the
+ * Linux i2c stack wants to treat the bottommost bit as a separate
+ * read/write bit, which is why slave ID's are usually presented
+ * >>1.  For consistency with that behavior, we shift over three
+ * bits instead of two.
+ */
+#define	  TWSIC0_SID_SHIFT 3
+#define	  TWSIC0_CLKDIV	  0x0007fc00	/* Clock divider */
+#define	  TWSIC0_MASKACK  0x00400000	/* Mask ack from sensor */
+#define	  TWSIC0_OVMAGIC  0x00800000	/* Make it work on OV sensors */
+
+#define REG_TWSIC1	0xbc	/* TWSI control 1 */
+#define	  TWSIC1_DATA	  0x0000ffff	/* Data to/from camchip */
+#define	  TWSIC1_ADDR	  0x00ff0000	/* Address (register) */
+#define	  TWSIC1_ADDR_SHIFT 16
+#define	  TWSIC1_READ	  0x01000000	/* Set for read op */
+#define	  TWSIC1_WSTAT	  0x02000000	/* Write status */
+#define	  TWSIC1_RVALID	  0x04000000	/* Read data valid */
+#define	  TWSIC1_ERROR	  0x08000000	/* Something screwed up */
+
+/*
+ * Here's the weird global control registers
+ */
+#define REG_GL_CSR     0x3004  /* Control/status register */
+#define	  GCSR_SRS	 0x00000001	/* SW Reset set */
+#define	  GCSR_SRC	 0x00000002	/* SW Reset clear */
+#define	  GCSR_MRS	 0x00000004	/* Master reset set */
+#define	  GCSR_MRC	 0x00000008	/* HW Reset clear */
+#define	  GCSR_CCIC_EN	 0x00004000    /* CCIC Clock enable */
+#define REG_GL_IMASK   0x300c  /* Interrupt mask register */
+#define	  GIMSK_CCIC_EN		 0x00000004    /* CCIC Interrupt enable */
+
+#define REG_GL_FCR	0x3038	/* GPIO functional control register */
+#define	  GFCR_GPIO_ON	  0x08		/* Camera GPIO enabled */
+#define REG_GL_GPIOR	0x315c	/* GPIO register */
+#define	  GGPIO_OUT		0x80000	/* GPIO output */
+#define	  GGPIO_VAL		0x00008	/* Output pin value */
+
+#define REG_LEN		       (REG_GL_IMASK + 4)
+
+
+/*
+ * Debugging and related.
+ */
+#define cam_err(cam, fmt, arg...) \
+	dev_err(&(cam)->pdev->dev, fmt, ##arg);
+#define cam_warn(cam, fmt, arg...) \
+	dev_warn(&(cam)->pdev->dev, fmt, ##arg);
+
+/* -------------------------------------------------------------------- */
+/*
+ * The I2C/SMBUS interface to the camera itself starts here.  The
+ * controller handles SMBUS itself, presenting a relatively simple register
+ * interface; all we have to do is to tell it where to route the data.
+ */
+#define CAFE_SMBUS_TIMEOUT (HZ)  /* generous */
+
+static inline struct cafe_camera *to_cam(struct v4l2_device *dev)
+{
+	struct mcam_camera *m = container_of(dev, struct mcam_camera, v4l2_dev);
+	return container_of(m, struct cafe_camera, mcam);
+}
+
+
+static int cafe_smbus_write_done(struct mcam_camera *mcam)
+{
+	unsigned long flags;
+	int c1;
+
+	/*
+	 * We must delay after the interrupt, or the controller gets confused
+	 * and never does give us good status.  Fortunately, we don't do this
+	 * often.
+	 */
+	udelay(20);
+	spin_lock_irqsave(&mcam->dev_lock, flags);
+	c1 = mcam_reg_read(mcam, REG_TWSIC1);
+	spin_unlock_irqrestore(&mcam->dev_lock, flags);
+	return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT;
+}
+
+static int cafe_smbus_write_data(struct cafe_camera *cam,
+		u16 addr, u8 command, u8 value)
+{
+	unsigned int rval;
+	unsigned long flags;
+	struct mcam_camera *mcam = &cam->mcam;
+
+	spin_lock_irqsave(&mcam->dev_lock, flags);
+	rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
+	rval |= TWSIC0_OVMAGIC;  /* Make OV sensors work */
+	/*
+	 * Marvell sez set clkdiv to all 1's for now.
+	 */
+	rval |= TWSIC0_CLKDIV;
+	mcam_reg_write(mcam, REG_TWSIC0, rval);
+	(void) mcam_reg_read(mcam, REG_TWSIC1); /* force write */
+	rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
+	mcam_reg_write(mcam, REG_TWSIC1, rval);
+	spin_unlock_irqrestore(&mcam->dev_lock, flags);
+
+	/* Unfortunately, reading TWSIC1 too soon after sending a command
+	 * causes the device to die.
+	 * Use a busy-wait because we often send a large quantity of small
+	 * commands at-once; using msleep() would cause a lot of context
+	 * switches which take longer than 2ms, resulting in a noticeable
+	 * boot-time and capture-start delays.
+	 */
+	mdelay(2);
+
+	/*
+	 * Another sad fact is that sometimes, commands silently complete but
+	 * cafe_smbus_write_done() never becomes aware of this.
+	 * This happens at random and appears to possible occur with any
+	 * command.
+	 * We don't understand why this is. We work around this issue
+	 * with the timeout in the wait below, assuming that all commands
+	 * complete within the timeout.
+	 */
+	wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(mcam),
+			CAFE_SMBUS_TIMEOUT);
+
+	spin_lock_irqsave(&mcam->dev_lock, flags);
+	rval = mcam_reg_read(mcam, REG_TWSIC1);
+	spin_unlock_irqrestore(&mcam->dev_lock, flags);
+
+	if (rval & TWSIC1_WSTAT) {
+		cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr,
+				command, value);
+		return -EIO;
+	}
+	if (rval & TWSIC1_ERROR) {
+		cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr,
+				command, value);
+		return -EIO;
+	}
+	return 0;
+}
+
+
+
+static int cafe_smbus_read_done(struct mcam_camera *mcam)
+{
+	unsigned long flags;
+	int c1;
+
+	/*
+	 * We must delay after the interrupt, or the controller gets confused
+	 * and never does give us good status.  Fortunately, we don't do this
+	 * often.
+	 */
+	udelay(20);
+	spin_lock_irqsave(&mcam->dev_lock, flags);
+	c1 = mcam_reg_read(mcam, REG_TWSIC1);
+	spin_unlock_irqrestore(&mcam->dev_lock, flags);
+	return c1 & (TWSIC1_RVALID|TWSIC1_ERROR);
+}
+
+
+
+static int cafe_smbus_read_data(struct cafe_camera *cam,
+		u16 addr, u8 command, u8 *value)
+{
+	unsigned int rval;
+	unsigned long flags;
+	struct mcam_camera *mcam = &cam->mcam;
+
+	spin_lock_irqsave(&mcam->dev_lock, flags);
+	rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
+	rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */
+	/*
+	 * Marvel sez set clkdiv to all 1's for now.
+	 */
+	rval |= TWSIC0_CLKDIV;
+	mcam_reg_write(mcam, REG_TWSIC0, rval);
+	(void) mcam_reg_read(mcam, REG_TWSIC1); /* force write */
+	rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
+	mcam_reg_write(mcam, REG_TWSIC1, rval);
+	spin_unlock_irqrestore(&mcam->dev_lock, flags);
+
+	wait_event_timeout(cam->smbus_wait,
+			cafe_smbus_read_done(mcam), CAFE_SMBUS_TIMEOUT);
+	spin_lock_irqsave(&mcam->dev_lock, flags);
+	rval = mcam_reg_read(mcam, REG_TWSIC1);
+	spin_unlock_irqrestore(&mcam->dev_lock, flags);
+
+	if (rval & TWSIC1_ERROR) {
+		cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command);
+		return -EIO;
+	}
+	if (!(rval & TWSIC1_RVALID)) {
+		cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr,
+				command);
+		return -EIO;
+	}
+	*value = rval & 0xff;
+	return 0;
+}
+
+/*
+ * Perform a transfer over SMBUS.  This thing is called under
+ * the i2c bus lock, so we shouldn't race with ourselves...
+ */
+static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+		unsigned short flags, char rw, u8 command,
+		int size, union i2c_smbus_data *data)
+{
+	struct cafe_camera *cam = i2c_get_adapdata(adapter);
+	int ret = -EINVAL;
+
+	/*
+	 * This interface would appear to only do byte data ops.  OK
+	 * it can do word too, but the cam chip has no use for that.
+	 */
+	if (size != I2C_SMBUS_BYTE_DATA) {
+		cam_err(cam, "funky xfer size %d\n", size);
+		return -EINVAL;
+	}
+
+	if (rw == I2C_SMBUS_WRITE)
+		ret = cafe_smbus_write_data(cam, addr, command, data->byte);
+	else if (rw == I2C_SMBUS_READ)
+		ret = cafe_smbus_read_data(cam, addr, command, &data->byte);
+	return ret;
+}
+
+
+static void cafe_smbus_enable_irq(struct cafe_camera *cam)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cam->mcam.dev_lock, flags);
+	mcam_reg_set_bit(&cam->mcam, REG_IRQMASK, TWSIIRQS);
+	spin_unlock_irqrestore(&cam->mcam.dev_lock, flags);
+}
+
+static u32 cafe_smbus_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_READ_BYTE_DATA  |
+	       I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
+}
+
+static struct i2c_algorithm cafe_smbus_algo = {
+	.smbus_xfer = cafe_smbus_xfer,
+	.functionality = cafe_smbus_func
+};
+
+static int cafe_smbus_setup(struct cafe_camera *cam)
+{
+	struct i2c_adapter *adap;
+	int ret;
+
+	adap = kzalloc(sizeof(*adap), GFP_KERNEL);
+	if (adap == NULL)
+		return -ENOMEM;
+	cam->mcam.i2c_adapter = adap;
+	cafe_smbus_enable_irq(cam);
+	adap->owner = THIS_MODULE;
+	adap->algo = &cafe_smbus_algo;
+	strcpy(adap->name, "cafe_ccic");
+	adap->dev.parent = &cam->pdev->dev;
+	i2c_set_adapdata(adap, cam);
+	ret = i2c_add_adapter(adap);
+	if (ret)
+		printk(KERN_ERR "Unable to register cafe i2c adapter\n");
+	return ret;
+}
+
+static void cafe_smbus_shutdown(struct cafe_camera *cam)
+{
+	i2c_del_adapter(cam->mcam.i2c_adapter);
+	kfree(cam->mcam.i2c_adapter);
+}
+
+
+/*
+ * Controller-level stuff
+ */
+
+static void cafe_ctlr_init(struct mcam_camera *mcam)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mcam->dev_lock, flags);
+	/*
+	 * Added magic to bring up the hardware on the B-Test board
+	 */
+	mcam_reg_write(mcam, 0x3038, 0x8);
+	mcam_reg_write(mcam, 0x315c, 0x80008);
+	/*
+	 * Go through the dance needed to wake the device up.
+	 * Note that these registers are global and shared
+	 * with the NAND and SD devices.  Interaction between the
+	 * three still needs to be examined.
+	 */
+	mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */
+	mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRC|GCSR_MRC);
+	mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRC|GCSR_MRS);
+	/*
+	 * Here we must wait a bit for the controller to come around.
+	 */
+	spin_unlock_irqrestore(&mcam->dev_lock, flags);
+	msleep(5);
+	spin_lock_irqsave(&mcam->dev_lock, flags);
+
+	mcam_reg_write(mcam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC);
+	mcam_reg_set_bit(mcam, REG_GL_IMASK, GIMSK_CCIC_EN);
+	/*
+	 * Mask all interrupts.
+	 */
+	mcam_reg_write(mcam, REG_IRQMASK, 0);
+	spin_unlock_irqrestore(&mcam->dev_lock, flags);
+}
+
+
+static void cafe_ctlr_power_up(struct mcam_camera *mcam)
+{
+	/*
+	 * Part one of the sensor dance: turn the global
+	 * GPIO signal on.
+	 */
+	mcam_reg_write(mcam, REG_GL_FCR, GFCR_GPIO_ON);
+	mcam_reg_write(mcam, REG_GL_GPIOR, GGPIO_OUT|GGPIO_VAL);
+	/*
+	 * Put the sensor into operational mode (assumes OLPC-style
+	 * wiring).  Control 0 is reset - set to 1 to operate.
+	 * Control 1 is power down, set to 0 to operate.
+	 */
+	mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */
+	mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
+}
+
+static void cafe_ctlr_power_down(struct mcam_camera *mcam)
+{
+	mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1);
+	mcam_reg_write(mcam, REG_GL_FCR, GFCR_GPIO_ON);
+	mcam_reg_write(mcam, REG_GL_GPIOR, GGPIO_OUT);
+}
+
+
+
+/*
+ * The platform interrupt handler.
+ */
+static irqreturn_t cafe_irq(int irq, void *data)
+{
+	struct cafe_camera *cam = data;
+	struct mcam_camera *mcam = &cam->mcam;
+	unsigned int irqs, handled;
+
+	spin_lock(&mcam->dev_lock);
+	irqs = mcam_reg_read(mcam, REG_IRQSTAT);
+	handled = cam->registered && mccic_irq(mcam, irqs);
+	if (irqs & TWSIIRQS) {
+		mcam_reg_write(mcam, REG_IRQSTAT, TWSIIRQS);
+		wake_up(&cam->smbus_wait);
+		handled = 1;
+	}
+	spin_unlock(&mcam->dev_lock);
+	return IRQ_RETVAL(handled);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/*
+ * PCI interface stuff.
+ */
+
+static int cafe_pci_probe(struct pci_dev *pdev,
+		const struct pci_device_id *id)
+{
+	int ret;
+	struct cafe_camera *cam;
+	struct mcam_camera *mcam;
+
+	/*
+	 * Start putting together one of our big camera structures.
+	 */
+	ret = -ENOMEM;
+	cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL);
+	if (cam == NULL)
+		goto out;
+	cam->pdev = pdev;
+	mcam = &cam->mcam;
+	mcam->chip_id = V4L2_IDENT_CAFE;
+	spin_lock_init(&mcam->dev_lock);
+	init_waitqueue_head(&cam->smbus_wait);
+	mcam->plat_power_up = cafe_ctlr_power_up;
+	mcam->plat_power_down = cafe_ctlr_power_down;
+	mcam->dev = &pdev->dev;
+	/*
+	 * Set the clock speed for the XO 1; I don't believe this
+	 * driver has ever run anywhere else.
+	 */
+	mcam->clock_speed = 45;
+	mcam->use_smbus = 1;
+	/*
+	 * Vmalloc mode for buffers is traditional with this driver.
+	 * We *might* be able to run DMA_contig, especially on a system
+	 * with CMA in it.
+	 */
+	mcam->buffer_mode = B_vmalloc;
+	/*
+	 * Get set up on the PCI bus.
+	 */
+	ret = pci_enable_device(pdev);
+	if (ret)
+		goto out_free;
+	pci_set_master(pdev);
+
+	ret = -EIO;
+	mcam->regs = pci_iomap(pdev, 0, 0);
+	if (!mcam->regs) {
+		printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n");
+		goto out_disable;
+	}
+	ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam);
+	if (ret)
+		goto out_iounmap;
+
+	/*
+	 * Initialize the controller and leave it powered up.  It will
+	 * stay that way until the sensor driver shows up.
+	 */
+	cafe_ctlr_init(mcam);
+	cafe_ctlr_power_up(mcam);
+	/*
+	 * Set up I2C/SMBUS communications.  We have to drop the mutex here
+	 * because the sensor could attach in this call chain, leading to
+	 * unsightly deadlocks.
+	 */
+	ret = cafe_smbus_setup(cam);
+	if (ret)
+		goto out_pdown;
+
+	ret = mccic_register(mcam);
+	if (ret == 0) {
+		cam->registered = 1;
+		return 0;
+	}
+
+	cafe_smbus_shutdown(cam);
+out_pdown:
+	cafe_ctlr_power_down(mcam);
+	free_irq(pdev->irq, cam);
+out_iounmap:
+	pci_iounmap(pdev, mcam->regs);
+out_disable:
+	pci_disable_device(pdev);
+out_free:
+	kfree(cam);
+out:
+	return ret;
+}
+
+
+/*
+ * Shut down an initialized device
+ */
+static void cafe_shutdown(struct cafe_camera *cam)
+{
+	mccic_shutdown(&cam->mcam);
+	cafe_smbus_shutdown(cam);
+	free_irq(cam->pdev->irq, cam);
+	pci_iounmap(cam->pdev, cam->mcam.regs);
+}
+
+
+static void cafe_pci_remove(struct pci_dev *pdev)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+	struct cafe_camera *cam = to_cam(v4l2_dev);
+
+	if (cam == NULL) {
+		printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev);
+		return;
+	}
+	cafe_shutdown(cam);
+	kfree(cam);
+}
+
+
+#ifdef CONFIG_PM
+/*
+ * Basic power management.
+ */
+static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+	struct cafe_camera *cam = to_cam(v4l2_dev);
+	int ret;
+
+	ret = pci_save_state(pdev);
+	if (ret)
+		return ret;
+	mccic_suspend(&cam->mcam);
+	pci_disable_device(pdev);
+	return 0;
+}
+
+
+static int cafe_pci_resume(struct pci_dev *pdev)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+	struct cafe_camera *cam = to_cam(v4l2_dev);
+	int ret = 0;
+
+	pci_restore_state(pdev);
+	ret = pci_enable_device(pdev);
+
+	if (ret) {
+		cam_warn(cam, "Unable to re-enable device on resume!\n");
+		return ret;
+	}
+	cafe_ctlr_init(&cam->mcam);
+	return mccic_resume(&cam->mcam);
+}
+
+#endif  /* CONFIG_PM */
+
+static struct pci_device_id cafe_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL,
+		     PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, cafe_ids);
+
+static struct pci_driver cafe_pci_driver = {
+	.name = "cafe1000-ccic",
+	.id_table = cafe_ids,
+	.probe = cafe_pci_probe,
+	.remove = cafe_pci_remove,
+#ifdef CONFIG_PM
+	.suspend = cafe_pci_suspend,
+	.resume = cafe_pci_resume,
+#endif
+};
+
+
+
+
+static int __init cafe_init(void)
+{
+	int ret;
+
+	printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n",
+			CAFE_VERSION);
+	ret = pci_register_driver(&cafe_pci_driver);
+	if (ret) {
+		printk(KERN_ERR "Unable to register cafe_ccic driver\n");
+		goto out;
+	}
+	ret = 0;
+
+out:
+	return ret;
+}
+
+
+static void __exit cafe_exit(void)
+{
+	pci_unregister_driver(&cafe_pci_driver);
+}
+
+module_init(cafe_init);
+module_exit(cafe_exit);
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
new file mode 100644
index 0000000..ce2b7b4
--- /dev/null
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -0,0 +1,1878 @@
+/*
+ * The Marvell camera core.  This device appears in a number of settings,
+ * so it needs platform-specific support outside of the core.
+ *
+ * Copyright 2011 Jonathan Corbet corbet@lwn.net
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include <linux/io.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/ov7670.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "mcam-core.h"
+
+/*
+ * Basic frame stats - to be deleted shortly
+ */
+static int frames;
+static int singles;
+static int delivered;
+
+#ifdef MCAM_MODE_VMALLOC
+/*
+ * Internal DMA buffer management.  Since the controller cannot do S/G I/O,
+ * we must have physically contiguous buffers to bring frames into.
+ * These parameters control how many buffers we use, whether we
+ * allocate them at load time (better chance of success, but nails down
+ * memory) or when somebody tries to use the camera (riskier), and,
+ * for load-time allocation, how big they should be.
+ *
+ * The controller can cycle through three buffers.  We could use
+ * more by flipping pointers around, but it probably makes little
+ * sense.
+ */
+
+static bool alloc_bufs_at_read;
+module_param(alloc_bufs_at_read, bool, 0444);
+MODULE_PARM_DESC(alloc_bufs_at_read,
+		"Non-zero value causes DMA buffers to be allocated when the "
+		"video capture device is read, rather than at module load "
+		"time.  This saves memory, but decreases the chances of "
+		"successfully getting those buffers.  This parameter is "
+		"only used in the vmalloc buffer mode");
+
+static int n_dma_bufs = 3;
+module_param(n_dma_bufs, uint, 0644);
+MODULE_PARM_DESC(n_dma_bufs,
+		"The number of DMA buffers to allocate.  Can be either two "
+		"(saves memory, makes timing tighter) or three.");
+
+static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2;  /* Worst case */
+module_param(dma_buf_size, uint, 0444);
+MODULE_PARM_DESC(dma_buf_size,
+		"The size of the allocated DMA buffers.  If actual operating "
+		"parameters require larger buffers, an attempt to reallocate "
+		"will be made.");
+#else /* MCAM_MODE_VMALLOC */
+static const bool alloc_bufs_at_read = 0;
+static const int n_dma_bufs = 3;  /* Used by S/G_PARM */
+#endif /* MCAM_MODE_VMALLOC */
+
+static bool flip;
+module_param(flip, bool, 0444);
+MODULE_PARM_DESC(flip,
+		"If set, the sensor will be instructed to flip the image "
+		"vertically.");
+
+static int buffer_mode = -1;
+module_param(buffer_mode, int, 0444);
+MODULE_PARM_DESC(buffer_mode,
+		"Set the buffer mode to be used; default is to go with what "
+		"the platform driver asks for.  Set to 0 for vmalloc, 1 for "
+		"DMA contiguous.");
+
+/*
+ * Status flags.  Always manipulated with bit operations.
+ */
+#define CF_BUF0_VALID	 0	/* Buffers valid - first three */
+#define CF_BUF1_VALID	 1
+#define CF_BUF2_VALID	 2
+#define CF_DMA_ACTIVE	 3	/* A frame is incoming */
+#define CF_CONFIG_NEEDED 4	/* Must configure hardware */
+#define CF_SINGLE_BUFFER 5	/* Running with a single buffer */
+#define CF_SG_RESTART	 6	/* SG restart needed */
+
+#define sensor_call(cam, o, f, args...) \
+	v4l2_subdev_call(cam->sensor, o, f, ##args)
+
+static struct mcam_format_struct {
+	__u8 *desc;
+	__u32 pixelformat;
+	int bpp;   /* Bytes per pixel */
+	enum v4l2_mbus_pixelcode mbus_code;
+} mcam_formats[] = {
+	{
+		.desc		= "YUYV 4:2:2",
+		.pixelformat	= V4L2_PIX_FMT_YUYV,
+		.mbus_code	= V4L2_MBUS_FMT_YUYV8_2X8,
+		.bpp		= 2,
+	},
+	{
+		.desc		= "RGB 444",
+		.pixelformat	= V4L2_PIX_FMT_RGB444,
+		.mbus_code	= V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+		.bpp		= 2,
+	},
+	{
+		.desc		= "RGB 565",
+		.pixelformat	= V4L2_PIX_FMT_RGB565,
+		.mbus_code	= V4L2_MBUS_FMT_RGB565_2X8_LE,
+		.bpp		= 2,
+	},
+	{
+		.desc		= "Raw RGB Bayer",
+		.pixelformat	= V4L2_PIX_FMT_SBGGR8,
+		.mbus_code	= V4L2_MBUS_FMT_SBGGR8_1X8,
+		.bpp		= 1
+	},
+};
+#define N_MCAM_FMTS ARRAY_SIZE(mcam_formats)
+
+static struct mcam_format_struct *mcam_find_format(u32 pixelformat)
+{
+	unsigned i;
+
+	for (i = 0; i < N_MCAM_FMTS; i++)
+		if (mcam_formats[i].pixelformat == pixelformat)
+			return mcam_formats + i;
+	/* Not found? Then return the first format. */
+	return mcam_formats;
+}
+
+/*
+ * The default format we use until somebody says otherwise.
+ */
+static const struct v4l2_pix_format mcam_def_pix_format = {
+	.width		= VGA_WIDTH,
+	.height		= VGA_HEIGHT,
+	.pixelformat	= V4L2_PIX_FMT_YUYV,
+	.field		= V4L2_FIELD_NONE,
+	.bytesperline	= VGA_WIDTH*2,
+	.sizeimage	= VGA_WIDTH*VGA_HEIGHT*2,
+};
+
+static const enum v4l2_mbus_pixelcode mcam_def_mbus_code =
+					V4L2_MBUS_FMT_YUYV8_2X8;
+
+
+/*
+ * The two-word DMA descriptor format used by the Armada 610 and like.  There
+ * Is a three-word format as well (set C1_DESC_3WORD) where the third
+ * word is a pointer to the next descriptor, but we don't use it.  Two-word
+ * descriptors have to be contiguous in memory.
+ */
+struct mcam_dma_desc {
+	u32 dma_addr;
+	u32 segment_len;
+};
+
+/*
+ * Our buffer type for working with videobuf2.  Note that the vb2
+ * developers have decreed that struct vb2_buffer must be at the
+ * beginning of this structure.
+ */
+struct mcam_vb_buffer {
+	struct vb2_buffer vb_buf;
+	struct list_head queue;
+	struct mcam_dma_desc *dma_desc;	/* Descriptor virtual address */
+	dma_addr_t dma_desc_pa;		/* Descriptor physical address */
+	int dma_desc_nent;		/* Number of mapped descriptors */
+};
+
+static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_buffer *vb)
+{
+	return container_of(vb, struct mcam_vb_buffer, vb_buf);
+}
+
+/*
+ * Hand a completed buffer back to user space.
+ */
+static void mcam_buffer_done(struct mcam_camera *cam, int frame,
+		struct vb2_buffer *vbuf)
+{
+	vbuf->v4l2_buf.bytesused = cam->pix_format.sizeimage;
+	vbuf->v4l2_buf.sequence = cam->buf_seq[frame];
+	vb2_set_plane_payload(vbuf, 0, cam->pix_format.sizeimage);
+	vb2_buffer_done(vbuf, VB2_BUF_STATE_DONE);
+}
+
+
+
+/*
+ * Debugging and related.
+ */
+#define cam_err(cam, fmt, arg...) \
+	dev_err((cam)->dev, fmt, ##arg);
+#define cam_warn(cam, fmt, arg...) \
+	dev_warn((cam)->dev, fmt, ##arg);
+#define cam_dbg(cam, fmt, arg...) \
+	dev_dbg((cam)->dev, fmt, ##arg);
+
+
+/*
+ * Flag manipulation helpers
+ */
+static void mcam_reset_buffers(struct mcam_camera *cam)
+{
+	int i;
+
+	cam->next_buf = -1;
+	for (i = 0; i < cam->nbufs; i++)
+		clear_bit(i, &cam->flags);
+}
+
+static inline int mcam_needs_config(struct mcam_camera *cam)
+{
+	return test_bit(CF_CONFIG_NEEDED, &cam->flags);
+}
+
+static void mcam_set_config_needed(struct mcam_camera *cam, int needed)
+{
+	if (needed)
+		set_bit(CF_CONFIG_NEEDED, &cam->flags);
+	else
+		clear_bit(CF_CONFIG_NEEDED, &cam->flags);
+}
+
+/* ------------------------------------------------------------------- */
+/*
+ * Make the controller start grabbing images.  Everything must
+ * be set up before doing this.
+ */
+static void mcam_ctlr_start(struct mcam_camera *cam)
+{
+	/* set_bit performs a read, so no other barrier should be
+	   needed here */
+	mcam_reg_set_bit(cam, REG_CTRL0, C0_ENABLE);
+}
+
+static void mcam_ctlr_stop(struct mcam_camera *cam)
+{
+	mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
+}
+
+/* ------------------------------------------------------------------- */
+
+#ifdef MCAM_MODE_VMALLOC
+/*
+ * Code specific to the vmalloc buffer mode.
+ */
+
+/*
+ * Allocate in-kernel DMA buffers for vmalloc mode.
+ */
+static int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime)
+{
+	int i;
+
+	mcam_set_config_needed(cam, 1);
+	if (loadtime)
+		cam->dma_buf_size = dma_buf_size;
+	else
+		cam->dma_buf_size = cam->pix_format.sizeimage;
+	if (n_dma_bufs > 3)
+		n_dma_bufs = 3;
+
+	cam->nbufs = 0;
+	for (i = 0; i < n_dma_bufs; i++) {
+		cam->dma_bufs[i] = dma_alloc_coherent(cam->dev,
+				cam->dma_buf_size, cam->dma_handles + i,
+				GFP_KERNEL);
+		if (cam->dma_bufs[i] == NULL) {
+			cam_warn(cam, "Failed to allocate DMA buffer\n");
+			break;
+		}
+		(cam->nbufs)++;
+	}
+
+	switch (cam->nbufs) {
+	case 1:
+		dma_free_coherent(cam->dev, cam->dma_buf_size,
+				cam->dma_bufs[0], cam->dma_handles[0]);
+		cam->nbufs = 0;
+	case 0:
+		cam_err(cam, "Insufficient DMA buffers, cannot operate\n");
+		return -ENOMEM;
+
+	case 2:
+		if (n_dma_bufs > 2)
+			cam_warn(cam, "Will limp along with only 2 buffers\n");
+		break;
+	}
+	return 0;
+}
+
+static void mcam_free_dma_bufs(struct mcam_camera *cam)
+{
+	int i;
+
+	for (i = 0; i < cam->nbufs; i++) {
+		dma_free_coherent(cam->dev, cam->dma_buf_size,
+				cam->dma_bufs[i], cam->dma_handles[i]);
+		cam->dma_bufs[i] = NULL;
+	}
+	cam->nbufs = 0;
+}
+
+
+/*
+ * Set up DMA buffers when operating in vmalloc mode
+ */
+static void mcam_ctlr_dma_vmalloc(struct mcam_camera *cam)
+{
+	/*
+	 * Store the first two Y buffers (we aren't supporting
+	 * planar formats for now, so no UV bufs).  Then either
+	 * set the third if it exists, or tell the controller
+	 * to just use two.
+	 */
+	mcam_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]);
+	mcam_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]);
+	if (cam->nbufs > 2) {
+		mcam_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]);
+		mcam_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS);
+	} else
+		mcam_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS);
+	if (cam->chip_id == V4L2_IDENT_CAFE)
+		mcam_reg_write(cam, REG_UBAR, 0); /* 32 bits only */
+}
+
+/*
+ * Copy data out to user space in the vmalloc case
+ */
+static void mcam_frame_tasklet(unsigned long data)
+{
+	struct mcam_camera *cam = (struct mcam_camera *) data;
+	int i;
+	unsigned long flags;
+	struct mcam_vb_buffer *buf;
+
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	for (i = 0; i < cam->nbufs; i++) {
+		int bufno = cam->next_buf;
+
+		if (cam->state != S_STREAMING || bufno < 0)
+			break;  /* I/O got stopped */
+		if (++(cam->next_buf) >= cam->nbufs)
+			cam->next_buf = 0;
+		if (!test_bit(bufno, &cam->flags))
+			continue;
+		if (list_empty(&cam->buffers)) {
+			singles++;
+			break;  /* Leave it valid, hope for better later */
+		}
+		delivered++;
+		clear_bit(bufno, &cam->flags);
+		buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer,
+				queue);
+		list_del_init(&buf->queue);
+		/*
+		 * Drop the lock during the big copy.  This *should* be safe...
+		 */
+		spin_unlock_irqrestore(&cam->dev_lock, flags);
+		memcpy(vb2_plane_vaddr(&buf->vb_buf, 0), cam->dma_bufs[bufno],
+				cam->pix_format.sizeimage);
+		mcam_buffer_done(cam, bufno, &buf->vb_buf);
+		spin_lock_irqsave(&cam->dev_lock, flags);
+	}
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+
+/*
+ * Make sure our allocated buffers are up to the task.
+ */
+static int mcam_check_dma_buffers(struct mcam_camera *cam)
+{
+	if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage)
+			mcam_free_dma_bufs(cam);
+	if (cam->nbufs == 0)
+		return mcam_alloc_dma_bufs(cam, 0);
+	return 0;
+}
+
+static void mcam_vmalloc_done(struct mcam_camera *cam, int frame)
+{
+	tasklet_schedule(&cam->s_tasklet);
+}
+
+#else /* MCAM_MODE_VMALLOC */
+
+static inline int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime)
+{
+	return 0;
+}
+
+static inline void mcam_free_dma_bufs(struct mcam_camera *cam)
+{
+	return;
+}
+
+static inline int mcam_check_dma_buffers(struct mcam_camera *cam)
+{
+	return 0;
+}
+
+
+
+#endif /* MCAM_MODE_VMALLOC */
+
+
+#ifdef MCAM_MODE_DMA_CONTIG
+/* ---------------------------------------------------------------------- */
+/*
+ * DMA-contiguous code.
+ */
+/*
+ * Set up a contiguous buffer for the given frame.  Here also is where
+ * the underrun strategy is set: if there is no buffer available, reuse
+ * the buffer from the other BAR and set the CF_SINGLE_BUFFER flag to
+ * keep the interrupt handler from giving that buffer back to user
+ * space.  In this way, we always have a buffer to DMA to and don't
+ * have to try to play games stopping and restarting the controller.
+ */
+static void mcam_set_contig_buffer(struct mcam_camera *cam, int frame)
+{
+	struct mcam_vb_buffer *buf;
+	/*
+	 * If there are no available buffers, go into single mode
+	 */
+	if (list_empty(&cam->buffers)) {
+		buf = cam->vb_bufs[frame ^ 0x1];
+		cam->vb_bufs[frame] = buf;
+		mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR,
+				vb2_dma_contig_plane_dma_addr(&buf->vb_buf, 0));
+		set_bit(CF_SINGLE_BUFFER, &cam->flags);
+		singles++;
+		return;
+	}
+	/*
+	 * OK, we have a buffer we can use.
+	 */
+	buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue);
+	list_del_init(&buf->queue);
+	mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR,
+			vb2_dma_contig_plane_dma_addr(&buf->vb_buf, 0));
+	cam->vb_bufs[frame] = buf;
+	clear_bit(CF_SINGLE_BUFFER, &cam->flags);
+}
+
+/*
+ * Initial B_DMA_contig setup.
+ */
+static void mcam_ctlr_dma_contig(struct mcam_camera *cam)
+{
+	mcam_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS);
+	cam->nbufs = 2;
+	mcam_set_contig_buffer(cam, 0);
+	mcam_set_contig_buffer(cam, 1);
+}
+
+/*
+ * Frame completion handling.
+ */
+static void mcam_dma_contig_done(struct mcam_camera *cam, int frame)
+{
+	struct mcam_vb_buffer *buf = cam->vb_bufs[frame];
+
+	if (!test_bit(CF_SINGLE_BUFFER, &cam->flags)) {
+		delivered++;
+		mcam_buffer_done(cam, frame, &buf->vb_buf);
+	}
+	mcam_set_contig_buffer(cam, frame);
+}
+
+#endif /* MCAM_MODE_DMA_CONTIG */
+
+#ifdef MCAM_MODE_DMA_SG
+/* ---------------------------------------------------------------------- */
+/*
+ * Scatter/gather-specific code.
+ */
+
+/*
+ * Set up the next buffer for S/G I/O; caller should be sure that
+ * the controller is stopped and a buffer is available.
+ */
+static void mcam_sg_next_buffer(struct mcam_camera *cam)
+{
+	struct mcam_vb_buffer *buf;
+
+	buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue);
+	list_del_init(&buf->queue);
+	/*
+	 * Very Bad Not Good Things happen if you don't clear
+	 * C1_DESC_ENA before making any descriptor changes.
+	 */
+	mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA);
+	mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa);
+	mcam_reg_write(cam, REG_DESC_LEN_Y,
+			buf->dma_desc_nent*sizeof(struct mcam_dma_desc));
+	mcam_reg_write(cam, REG_DESC_LEN_U, 0);
+	mcam_reg_write(cam, REG_DESC_LEN_V, 0);
+	mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
+	cam->vb_bufs[0] = buf;
+}
+
+/*
+ * Initial B_DMA_sg setup
+ */
+static void mcam_ctlr_dma_sg(struct mcam_camera *cam)
+{
+	/*
+	 * The list-empty condition can hit us at resume time
+	 * if the buffer list was empty when the system was suspended.
+	 */
+	if (list_empty(&cam->buffers)) {
+		set_bit(CF_SG_RESTART, &cam->flags);
+		return;
+	}
+
+	mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD);
+	mcam_sg_next_buffer(cam);
+	cam->nbufs = 3;
+}
+
+
+/*
+ * Frame completion with S/G is trickier.  We can't muck with
+ * a descriptor chain on the fly, since the controller buffers it
+ * internally.  So we have to actually stop and restart; Marvell
+ * says this is the way to do it.
+ *
+ * Of course, stopping is easier said than done; experience shows
+ * that the controller can start a frame *after* C0_ENABLE has been
+ * cleared.  So when running in S/G mode, the controller is "stopped"
+ * on receipt of the start-of-frame interrupt.  That means we can
+ * safely change the DMA descriptor array here and restart things
+ * (assuming there's another buffer waiting to go).
+ */
+static void mcam_dma_sg_done(struct mcam_camera *cam, int frame)
+{
+	struct mcam_vb_buffer *buf = cam->vb_bufs[0];
+
+	/*
+	 * If we're no longer supposed to be streaming, don't do anything.
+	 */
+	if (cam->state != S_STREAMING)
+		return;
+	/*
+	 * If we have another buffer available, put it in and
+	 * restart the engine.
+	 */
+	if (!list_empty(&cam->buffers)) {
+		mcam_sg_next_buffer(cam);
+		mcam_ctlr_start(cam);
+	/*
+	 * Otherwise set CF_SG_RESTART and the controller will
+	 * be restarted once another buffer shows up.
+	 */
+	} else {
+		set_bit(CF_SG_RESTART, &cam->flags);
+		singles++;
+		cam->vb_bufs[0] = NULL;
+	}
+	/*
+	 * Now we can give the completed frame back to user space.
+	 */
+	delivered++;
+	mcam_buffer_done(cam, frame, &buf->vb_buf);
+}
+
+
+/*
+ * Scatter/gather mode requires stopping the controller between
+ * frames so we can put in a new DMA descriptor array.  If no new
+ * buffer exists at frame completion, the controller is left stopped;
+ * this function is charged with gettig things going again.
+ */
+static void mcam_sg_restart(struct mcam_camera *cam)
+{
+	mcam_ctlr_dma_sg(cam);
+	mcam_ctlr_start(cam);
+	clear_bit(CF_SG_RESTART, &cam->flags);
+}
+
+#else /* MCAM_MODE_DMA_SG */
+
+static inline void mcam_sg_restart(struct mcam_camera *cam)
+{
+	return;
+}
+
+#endif /* MCAM_MODE_DMA_SG */
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Buffer-mode-independent controller code.
+ */
+
+/*
+ * Image format setup
+ */
+static void mcam_ctlr_image(struct mcam_camera *cam)
+{
+	int imgsz;
+	struct v4l2_pix_format *fmt = &cam->pix_format;
+
+	imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) |
+		(fmt->bytesperline & IMGSZ_H_MASK);
+	mcam_reg_write(cam, REG_IMGSIZE, imgsz);
+	mcam_reg_write(cam, REG_IMGOFFSET, 0);
+	/* YPITCH just drops the last two bits */
+	mcam_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline,
+			IMGP_YP_MASK);
+	/*
+	 * Tell the controller about the image format we are using.
+	 */
+	switch (cam->pix_format.pixelformat) {
+	case V4L2_PIX_FMT_YUYV:
+	    mcam_reg_write_mask(cam, REG_CTRL0,
+			    C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV,
+			    C0_DF_MASK);
+	    break;
+
+	case V4L2_PIX_FMT_RGB444:
+	    mcam_reg_write_mask(cam, REG_CTRL0,
+			    C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB,
+			    C0_DF_MASK);
+		/* Alpha value? */
+	    break;
+
+	case V4L2_PIX_FMT_RGB565:
+	    mcam_reg_write_mask(cam, REG_CTRL0,
+			    C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR,
+			    C0_DF_MASK);
+	    break;
+
+	default:
+	    cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat);
+	    break;
+	}
+	/*
+	 * Make sure it knows we want to use hsync/vsync.
+	 */
+	mcam_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC,
+			C0_SIFM_MASK);
+}
+
+
+/*
+ * Configure the controller for operation; caller holds the
+ * device mutex.
+ */
+static int mcam_ctlr_configure(struct mcam_camera *cam)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	clear_bit(CF_SG_RESTART, &cam->flags);
+	cam->dma_setup(cam);
+	mcam_ctlr_image(cam);
+	mcam_set_config_needed(cam, 0);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+	return 0;
+}
+
+static void mcam_ctlr_irq_enable(struct mcam_camera *cam)
+{
+	/*
+	 * Clear any pending interrupts, since we do not
+	 * expect to have I/O active prior to enabling.
+	 */
+	mcam_reg_write(cam, REG_IRQSTAT, FRAMEIRQS);
+	mcam_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS);
+}
+
+static void mcam_ctlr_irq_disable(struct mcam_camera *cam)
+{
+	mcam_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS);
+}
+
+
+
+static void mcam_ctlr_init(struct mcam_camera *cam)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	/*
+	 * Make sure it's not powered down.
+	 */
+	mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
+	/*
+	 * Turn off the enable bit.  It sure should be off anyway,
+	 * but it's good to be sure.
+	 */
+	mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
+	/*
+	 * Clock the sensor appropriately.  Controller clock should
+	 * be 48MHz, sensor "typical" value is half that.
+	 */
+	mcam_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+
+/*
+ * Stop the controller, and don't return until we're really sure that no
+ * further DMA is going on.
+ */
+static void mcam_ctlr_stop_dma(struct mcam_camera *cam)
+{
+	unsigned long flags;
+
+	/*
+	 * Theory: stop the camera controller (whether it is operating
+	 * or not).  Delay briefly just in case we race with the SOF
+	 * interrupt, then wait until no DMA is active.
+	 */
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	clear_bit(CF_SG_RESTART, &cam->flags);
+	mcam_ctlr_stop(cam);
+	cam->state = S_IDLE;
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+	/*
+	 * This is a brutally long sleep, but experience shows that
+	 * it can take the controller a while to get the message that
+	 * it needs to stop grabbing frames.  In particular, we can
+	 * sometimes (on mmp) get a frame at the end WITHOUT the
+	 * start-of-frame indication.
+	 */
+	msleep(150);
+	if (test_bit(CF_DMA_ACTIVE, &cam->flags))
+		cam_err(cam, "Timeout waiting for DMA to end\n");
+		/* This would be bad news - what now? */
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	mcam_ctlr_irq_disable(cam);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+/*
+ * Power up and down.
+ */
+static void mcam_ctlr_power_up(struct mcam_camera *cam)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	cam->plat_power_up(cam);
+	mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+	msleep(5); /* Just to be sure */
+}
+
+static void mcam_ctlr_power_down(struct mcam_camera *cam)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	/*
+	 * School of hard knocks department: be sure we do any register
+	 * twiddling on the controller *before* calling the platform
+	 * power down routine.
+	 */
+	mcam_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN);
+	cam->plat_power_down(cam);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+/* -------------------------------------------------------------------- */
+/*
+ * Communications with the sensor.
+ */
+
+static int __mcam_cam_reset(struct mcam_camera *cam)
+{
+	return sensor_call(cam, core, reset, 0);
+}
+
+/*
+ * We have found the sensor on the i2c.  Let's try to have a
+ * conversation.
+ */
+static int mcam_cam_init(struct mcam_camera *cam)
+{
+	struct v4l2_dbg_chip_ident chip;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	if (cam->state != S_NOTREADY)
+		cam_warn(cam, "Cam init with device in funky state %d",
+				cam->state);
+	ret = __mcam_cam_reset(cam);
+	if (ret)
+		goto out;
+	chip.ident = V4L2_IDENT_NONE;
+	chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR;
+	chip.match.addr = cam->sensor_addr;
+	ret = sensor_call(cam, core, g_chip_ident, &chip);
+	if (ret)
+		goto out;
+	cam->sensor_type = chip.ident;
+	if (cam->sensor_type != V4L2_IDENT_OV7670) {
+		cam_err(cam, "Unsupported sensor type 0x%x", cam->sensor_type);
+		ret = -EINVAL;
+		goto out;
+	}
+/* Get/set parameters? */
+	ret = 0;
+	cam->state = S_IDLE;
+out:
+	mcam_ctlr_power_down(cam);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+/*
+ * Configure the sensor to match the parameters we have.  Caller should
+ * hold s_mutex
+ */
+static int mcam_cam_set_flip(struct mcam_camera *cam)
+{
+	struct v4l2_control ctrl;
+
+	memset(&ctrl, 0, sizeof(ctrl));
+	ctrl.id = V4L2_CID_VFLIP;
+	ctrl.value = flip;
+	return sensor_call(cam, core, s_ctrl, &ctrl);
+}
+
+
+static int mcam_cam_configure(struct mcam_camera *cam)
+{
+	struct v4l2_mbus_framefmt mbus_fmt;
+	int ret;
+
+	v4l2_fill_mbus_format(&mbus_fmt, &cam->pix_format, cam->mbus_code);
+	ret = sensor_call(cam, core, init, 0);
+	if (ret == 0)
+		ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt);
+	/*
+	 * OV7670 does weird things if flip is set *before* format...
+	 */
+	ret += mcam_cam_set_flip(cam);
+	return ret;
+}
+
+/*
+ * Get everything ready, and start grabbing frames.
+ */
+static int mcam_read_setup(struct mcam_camera *cam)
+{
+	int ret;
+	unsigned long flags;
+
+	/*
+	 * Configuration.  If we still don't have DMA buffers,
+	 * make one last, desperate attempt.
+	 */
+	if (cam->buffer_mode == B_vmalloc && cam->nbufs == 0 &&
+			mcam_alloc_dma_bufs(cam, 0))
+		return -ENOMEM;
+
+	if (mcam_needs_config(cam)) {
+		mcam_cam_configure(cam);
+		ret = mcam_ctlr_configure(cam);
+		if (ret)
+			return ret;
+	}
+
+	/*
+	 * Turn it loose.
+	 */
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	clear_bit(CF_DMA_ACTIVE, &cam->flags);
+	mcam_reset_buffers(cam);
+	mcam_ctlr_irq_enable(cam);
+	cam->state = S_STREAMING;
+	if (!test_bit(CF_SG_RESTART, &cam->flags))
+		mcam_ctlr_start(cam);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+/*
+ * Videobuf2 interface code.
+ */
+
+static int mcam_vb_queue_setup(struct vb2_queue *vq,
+		const struct v4l2_format *fmt, unsigned int *nbufs,
+		unsigned int *num_planes, unsigned int sizes[],
+		void *alloc_ctxs[])
+{
+	struct mcam_camera *cam = vb2_get_drv_priv(vq);
+	int minbufs = (cam->buffer_mode == B_DMA_contig) ? 3 : 2;
+
+	sizes[0] = cam->pix_format.sizeimage;
+	*num_planes = 1; /* Someday we have to support planar formats... */
+	if (*nbufs < minbufs)
+		*nbufs = minbufs;
+	if (cam->buffer_mode == B_DMA_contig)
+		alloc_ctxs[0] = cam->vb_alloc_ctx;
+	return 0;
+}
+
+
+static void mcam_vb_buf_queue(struct vb2_buffer *vb)
+{
+	struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
+	struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
+	unsigned long flags;
+	int start;
+
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	start = (cam->state == S_BUFWAIT) && !list_empty(&cam->buffers);
+	list_add(&mvb->queue, &cam->buffers);
+	if (cam->state == S_STREAMING && test_bit(CF_SG_RESTART, &cam->flags))
+		mcam_sg_restart(cam);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+	if (start)
+		mcam_read_setup(cam);
+}
+
+
+/*
+ * vb2 uses these to release the mutex when waiting in dqbuf.  I'm
+ * not actually sure we need to do this (I'm not sure that vb2_dqbuf() needs
+ * to be called with the mutex held), but better safe than sorry.
+ */
+static void mcam_vb_wait_prepare(struct vb2_queue *vq)
+{
+	struct mcam_camera *cam = vb2_get_drv_priv(vq);
+
+	mutex_unlock(&cam->s_mutex);
+}
+
+static void mcam_vb_wait_finish(struct vb2_queue *vq)
+{
+	struct mcam_camera *cam = vb2_get_drv_priv(vq);
+
+	mutex_lock(&cam->s_mutex);
+}
+
+/*
+ * These need to be called with the mutex held from vb2
+ */
+static int mcam_vb_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct mcam_camera *cam = vb2_get_drv_priv(vq);
+
+	if (cam->state != S_IDLE) {
+		INIT_LIST_HEAD(&cam->buffers);
+		return -EINVAL;
+	}
+	cam->sequence = 0;
+	/*
+	 * Videobuf2 sneakily hoards all the buffers and won't
+	 * give them to us until *after* streaming starts.  But
+	 * we can't actually start streaming until we have a
+	 * destination.  So go into a wait state and hope they
+	 * give us buffers soon.
+	 */
+	if (cam->buffer_mode != B_vmalloc && list_empty(&cam->buffers)) {
+		cam->state = S_BUFWAIT;
+		return 0;
+	}
+	return mcam_read_setup(cam);
+}
+
+static int mcam_vb_stop_streaming(struct vb2_queue *vq)
+{
+	struct mcam_camera *cam = vb2_get_drv_priv(vq);
+	unsigned long flags;
+
+	if (cam->state == S_BUFWAIT) {
+		/* They never gave us buffers */
+		cam->state = S_IDLE;
+		return 0;
+	}
+	if (cam->state != S_STREAMING)
+		return -EINVAL;
+	mcam_ctlr_stop_dma(cam);
+	/*
+	 * VB2 reclaims the buffers, so we need to forget
+	 * about them.
+	 */
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	INIT_LIST_HEAD(&cam->buffers);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+	return 0;
+}
+
+
+static const struct vb2_ops mcam_vb2_ops = {
+	.queue_setup		= mcam_vb_queue_setup,
+	.buf_queue		= mcam_vb_buf_queue,
+	.start_streaming	= mcam_vb_start_streaming,
+	.stop_streaming		= mcam_vb_stop_streaming,
+	.wait_prepare		= mcam_vb_wait_prepare,
+	.wait_finish		= mcam_vb_wait_finish,
+};
+
+
+#ifdef MCAM_MODE_DMA_SG
+/*
+ * Scatter/gather mode uses all of the above functions plus a
+ * few extras to deal with DMA mapping.
+ */
+static int mcam_vb_sg_buf_init(struct vb2_buffer *vb)
+{
+	struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
+	struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
+	int ndesc = cam->pix_format.sizeimage/PAGE_SIZE + 1;
+
+	mvb->dma_desc = dma_alloc_coherent(cam->dev,
+			ndesc * sizeof(struct mcam_dma_desc),
+			&mvb->dma_desc_pa, GFP_KERNEL);
+	if (mvb->dma_desc == NULL) {
+		cam_err(cam, "Unable to get DMA descriptor array\n");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static int mcam_vb_sg_buf_prepare(struct vb2_buffer *vb)
+{
+	struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
+	struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
+	struct vb2_dma_sg_desc *sgd = vb2_dma_sg_plane_desc(vb, 0);
+	struct mcam_dma_desc *desc = mvb->dma_desc;
+	struct scatterlist *sg;
+	int i;
+
+	mvb->dma_desc_nent = dma_map_sg(cam->dev, sgd->sglist, sgd->num_pages,
+			DMA_FROM_DEVICE);
+	if (mvb->dma_desc_nent <= 0)
+		return -EIO;  /* Not sure what's right here */
+	for_each_sg(sgd->sglist, sg, mvb->dma_desc_nent, i) {
+		desc->dma_addr = sg_dma_address(sg);
+		desc->segment_len = sg_dma_len(sg);
+		desc++;
+	}
+	return 0;
+}
+
+static int mcam_vb_sg_buf_finish(struct vb2_buffer *vb)
+{
+	struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
+	struct vb2_dma_sg_desc *sgd = vb2_dma_sg_plane_desc(vb, 0);
+
+	dma_unmap_sg(cam->dev, sgd->sglist, sgd->num_pages, DMA_FROM_DEVICE);
+	return 0;
+}
+
+static void mcam_vb_sg_buf_cleanup(struct vb2_buffer *vb)
+{
+	struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
+	struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
+	int ndesc = cam->pix_format.sizeimage/PAGE_SIZE + 1;
+
+	dma_free_coherent(cam->dev, ndesc * sizeof(struct mcam_dma_desc),
+			mvb->dma_desc, mvb->dma_desc_pa);
+}
+
+
+static const struct vb2_ops mcam_vb2_sg_ops = {
+	.queue_setup		= mcam_vb_queue_setup,
+	.buf_init		= mcam_vb_sg_buf_init,
+	.buf_prepare		= mcam_vb_sg_buf_prepare,
+	.buf_queue		= mcam_vb_buf_queue,
+	.buf_finish		= mcam_vb_sg_buf_finish,
+	.buf_cleanup		= mcam_vb_sg_buf_cleanup,
+	.start_streaming	= mcam_vb_start_streaming,
+	.stop_streaming		= mcam_vb_stop_streaming,
+	.wait_prepare		= mcam_vb_wait_prepare,
+	.wait_finish		= mcam_vb_wait_finish,
+};
+
+#endif /* MCAM_MODE_DMA_SG */
+
+static int mcam_setup_vb2(struct mcam_camera *cam)
+{
+	struct vb2_queue *vq = &cam->vb_queue;
+
+	memset(vq, 0, sizeof(*vq));
+	vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	vq->drv_priv = cam;
+	INIT_LIST_HEAD(&cam->buffers);
+	switch (cam->buffer_mode) {
+	case B_DMA_contig:
+#ifdef MCAM_MODE_DMA_CONTIG
+		vq->ops = &mcam_vb2_ops;
+		vq->mem_ops = &vb2_dma_contig_memops;
+		cam->vb_alloc_ctx = vb2_dma_contig_init_ctx(cam->dev);
+		vq->io_modes = VB2_MMAP | VB2_USERPTR;
+		cam->dma_setup = mcam_ctlr_dma_contig;
+		cam->frame_complete = mcam_dma_contig_done;
+#endif
+		break;
+	case B_DMA_sg:
+#ifdef MCAM_MODE_DMA_SG
+		vq->ops = &mcam_vb2_sg_ops;
+		vq->mem_ops = &vb2_dma_sg_memops;
+		vq->io_modes = VB2_MMAP | VB2_USERPTR;
+		cam->dma_setup = mcam_ctlr_dma_sg;
+		cam->frame_complete = mcam_dma_sg_done;
+#endif
+		break;
+	case B_vmalloc:
+#ifdef MCAM_MODE_VMALLOC
+		tasklet_init(&cam->s_tasklet, mcam_frame_tasklet,
+				(unsigned long) cam);
+		vq->ops = &mcam_vb2_ops;
+		vq->mem_ops = &vb2_vmalloc_memops;
+		vq->buf_struct_size = sizeof(struct mcam_vb_buffer);
+		vq->io_modes = VB2_MMAP;
+		cam->dma_setup = mcam_ctlr_dma_vmalloc;
+		cam->frame_complete = mcam_vmalloc_done;
+#endif
+		break;
+	}
+	return vb2_queue_init(vq);
+}
+
+static void mcam_cleanup_vb2(struct mcam_camera *cam)
+{
+	vb2_queue_release(&cam->vb_queue);
+#ifdef MCAM_MODE_DMA_CONTIG
+	if (cam->buffer_mode == B_DMA_contig)
+		vb2_dma_contig_cleanup_ctx(cam->vb_alloc_ctx);
+#endif
+}
+
+
+/* ---------------------------------------------------------------------- */
+/*
+ * The long list of V4L2 ioctl() operations.
+ */
+
+static int mcam_vidioc_streamon(struct file *filp, void *priv,
+		enum v4l2_buf_type type)
+{
+	struct mcam_camera *cam = filp->private_data;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	ret = vb2_streamon(&cam->vb_queue, type);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+
+static int mcam_vidioc_streamoff(struct file *filp, void *priv,
+		enum v4l2_buf_type type)
+{
+	struct mcam_camera *cam = filp->private_data;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	ret = vb2_streamoff(&cam->vb_queue, type);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+
+static int mcam_vidioc_reqbufs(struct file *filp, void *priv,
+		struct v4l2_requestbuffers *req)
+{
+	struct mcam_camera *cam = filp->private_data;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	ret = vb2_reqbufs(&cam->vb_queue, req);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+
+static int mcam_vidioc_querybuf(struct file *filp, void *priv,
+		struct v4l2_buffer *buf)
+{
+	struct mcam_camera *cam = filp->private_data;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	ret = vb2_querybuf(&cam->vb_queue, buf);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+static int mcam_vidioc_qbuf(struct file *filp, void *priv,
+		struct v4l2_buffer *buf)
+{
+	struct mcam_camera *cam = filp->private_data;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	ret = vb2_qbuf(&cam->vb_queue, buf);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+static int mcam_vidioc_dqbuf(struct file *filp, void *priv,
+		struct v4l2_buffer *buf)
+{
+	struct mcam_camera *cam = filp->private_data;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	ret = vb2_dqbuf(&cam->vb_queue, buf, filp->f_flags & O_NONBLOCK);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+
+
+static int mcam_vidioc_queryctrl(struct file *filp, void *priv,
+		struct v4l2_queryctrl *qc)
+{
+	struct mcam_camera *cam = priv;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	ret = sensor_call(cam, core, queryctrl, qc);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+
+static int mcam_vidioc_g_ctrl(struct file *filp, void *priv,
+		struct v4l2_control *ctrl)
+{
+	struct mcam_camera *cam = priv;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	ret = sensor_call(cam, core, g_ctrl, ctrl);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+
+static int mcam_vidioc_s_ctrl(struct file *filp, void *priv,
+		struct v4l2_control *ctrl)
+{
+	struct mcam_camera *cam = priv;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	ret = sensor_call(cam, core, s_ctrl, ctrl);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+
+static int mcam_vidioc_querycap(struct file *file, void *priv,
+		struct v4l2_capability *cap)
+{
+	strcpy(cap->driver, "marvell_ccic");
+	strcpy(cap->card, "marvell_ccic");
+	cap->version = 1;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+	return 0;
+}
+
+
+static int mcam_vidioc_enum_fmt_vid_cap(struct file *filp,
+		void *priv, struct v4l2_fmtdesc *fmt)
+{
+	if (fmt->index >= N_MCAM_FMTS)
+		return -EINVAL;
+	strlcpy(fmt->description, mcam_formats[fmt->index].desc,
+			sizeof(fmt->description));
+	fmt->pixelformat = mcam_formats[fmt->index].pixelformat;
+	return 0;
+}
+
+static int mcam_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
+		struct v4l2_format *fmt)
+{
+	struct mcam_camera *cam = priv;
+	struct mcam_format_struct *f;
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+	struct v4l2_mbus_framefmt mbus_fmt;
+	int ret;
+
+	f = mcam_find_format(pix->pixelformat);
+	pix->pixelformat = f->pixelformat;
+	v4l2_fill_mbus_format(&mbus_fmt, pix, f->mbus_code);
+	mutex_lock(&cam->s_mutex);
+	ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt);
+	mutex_unlock(&cam->s_mutex);
+	v4l2_fill_pix_format(pix, &mbus_fmt);
+	pix->bytesperline = pix->width * f->bpp;
+	pix->sizeimage = pix->height * pix->bytesperline;
+	return ret;
+}
+
+static int mcam_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
+		struct v4l2_format *fmt)
+{
+	struct mcam_camera *cam = priv;
+	struct mcam_format_struct *f;
+	int ret;
+
+	/*
+	 * Can't do anything if the device is not idle
+	 * Also can't if there are streaming buffers in place.
+	 */
+	if (cam->state != S_IDLE || cam->vb_queue.num_buffers > 0)
+		return -EBUSY;
+
+	f = mcam_find_format(fmt->fmt.pix.pixelformat);
+
+	/*
+	 * See if the formatting works in principle.
+	 */
+	ret = mcam_vidioc_try_fmt_vid_cap(filp, priv, fmt);
+	if (ret)
+		return ret;
+	/*
+	 * Now we start to change things for real, so let's do it
+	 * under lock.
+	 */
+	mutex_lock(&cam->s_mutex);
+	cam->pix_format = fmt->fmt.pix;
+	cam->mbus_code = f->mbus_code;
+
+	/*
+	 * Make sure we have appropriate DMA buffers.
+	 */
+	if (cam->buffer_mode == B_vmalloc) {
+		ret = mcam_check_dma_buffers(cam);
+		if (ret)
+			goto out;
+	}
+	mcam_set_config_needed(cam, 1);
+out:
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+/*
+ * Return our stored notion of how the camera is/should be configured.
+ * The V4l2 spec wants us to be smarter, and actually get this from
+ * the camera (and not mess with it at open time).  Someday.
+ */
+static int mcam_vidioc_g_fmt_vid_cap(struct file *filp, void *priv,
+		struct v4l2_format *f)
+{
+	struct mcam_camera *cam = priv;
+
+	f->fmt.pix = cam->pix_format;
+	return 0;
+}
+
+/*
+ * We only have one input - the sensor - so minimize the nonsense here.
+ */
+static int mcam_vidioc_enum_input(struct file *filp, void *priv,
+		struct v4l2_input *input)
+{
+	if (input->index != 0)
+		return -EINVAL;
+
+	input->type = V4L2_INPUT_TYPE_CAMERA;
+	input->std = V4L2_STD_ALL; /* Not sure what should go here */
+	strcpy(input->name, "Camera");
+	return 0;
+}
+
+static int mcam_vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int mcam_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+	return 0;
+}
+
+/* from vivi.c */
+static int mcam_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a)
+{
+	return 0;
+}
+
+/*
+ * G/S_PARM.  Most of this is done by the sensor, but we are
+ * the level which controls the number of read buffers.
+ */
+static int mcam_vidioc_g_parm(struct file *filp, void *priv,
+		struct v4l2_streamparm *parms)
+{
+	struct mcam_camera *cam = priv;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	ret = sensor_call(cam, video, g_parm, parms);
+	mutex_unlock(&cam->s_mutex);
+	parms->parm.capture.readbuffers = n_dma_bufs;
+	return ret;
+}
+
+static int mcam_vidioc_s_parm(struct file *filp, void *priv,
+		struct v4l2_streamparm *parms)
+{
+	struct mcam_camera *cam = priv;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	ret = sensor_call(cam, video, s_parm, parms);
+	mutex_unlock(&cam->s_mutex);
+	parms->parm.capture.readbuffers = n_dma_bufs;
+	return ret;
+}
+
+static int mcam_vidioc_g_chip_ident(struct file *file, void *priv,
+		struct v4l2_dbg_chip_ident *chip)
+{
+	struct mcam_camera *cam = priv;
+
+	chip->ident = V4L2_IDENT_NONE;
+	chip->revision = 0;
+	if (v4l2_chip_match_host(&chip->match)) {
+		chip->ident = cam->chip_id;
+		return 0;
+	}
+	return sensor_call(cam, core, g_chip_ident, chip);
+}
+
+static int mcam_vidioc_enum_framesizes(struct file *filp, void *priv,
+		struct v4l2_frmsizeenum *sizes)
+{
+	struct mcam_camera *cam = priv;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	ret = sensor_call(cam, video, enum_framesizes, sizes);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+static int mcam_vidioc_enum_frameintervals(struct file *filp, void *priv,
+		struct v4l2_frmivalenum *interval)
+{
+	struct mcam_camera *cam = priv;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	ret = sensor_call(cam, video, enum_frameintervals, interval);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mcam_vidioc_g_register(struct file *file, void *priv,
+		struct v4l2_dbg_register *reg)
+{
+	struct mcam_camera *cam = priv;
+
+	if (v4l2_chip_match_host(&reg->match)) {
+		reg->val = mcam_reg_read(cam, reg->reg);
+		reg->size = 4;
+		return 0;
+	}
+	return sensor_call(cam, core, g_register, reg);
+}
+
+static int mcam_vidioc_s_register(struct file *file, void *priv,
+		struct v4l2_dbg_register *reg)
+{
+	struct mcam_camera *cam = priv;
+
+	if (v4l2_chip_match_host(&reg->match)) {
+		mcam_reg_write(cam, reg->reg, reg->val);
+		return 0;
+	}
+	return sensor_call(cam, core, s_register, reg);
+}
+#endif
+
+static const struct v4l2_ioctl_ops mcam_v4l_ioctl_ops = {
+	.vidioc_querycap	= mcam_vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = mcam_vidioc_enum_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	= mcam_vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= mcam_vidioc_s_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	= mcam_vidioc_g_fmt_vid_cap,
+	.vidioc_enum_input	= mcam_vidioc_enum_input,
+	.vidioc_g_input		= mcam_vidioc_g_input,
+	.vidioc_s_input		= mcam_vidioc_s_input,
+	.vidioc_s_std		= mcam_vidioc_s_std,
+	.vidioc_reqbufs		= mcam_vidioc_reqbufs,
+	.vidioc_querybuf	= mcam_vidioc_querybuf,
+	.vidioc_qbuf		= mcam_vidioc_qbuf,
+	.vidioc_dqbuf		= mcam_vidioc_dqbuf,
+	.vidioc_streamon	= mcam_vidioc_streamon,
+	.vidioc_streamoff	= mcam_vidioc_streamoff,
+	.vidioc_queryctrl	= mcam_vidioc_queryctrl,
+	.vidioc_g_ctrl		= mcam_vidioc_g_ctrl,
+	.vidioc_s_ctrl		= mcam_vidioc_s_ctrl,
+	.vidioc_g_parm		= mcam_vidioc_g_parm,
+	.vidioc_s_parm		= mcam_vidioc_s_parm,
+	.vidioc_enum_framesizes = mcam_vidioc_enum_framesizes,
+	.vidioc_enum_frameintervals = mcam_vidioc_enum_frameintervals,
+	.vidioc_g_chip_ident	= mcam_vidioc_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register	= mcam_vidioc_g_register,
+	.vidioc_s_register	= mcam_vidioc_s_register,
+#endif
+};
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Our various file operations.
+ */
+static int mcam_v4l_open(struct file *filp)
+{
+	struct mcam_camera *cam = video_drvdata(filp);
+	int ret = 0;
+
+	filp->private_data = cam;
+
+	frames = singles = delivered = 0;
+	mutex_lock(&cam->s_mutex);
+	if (cam->users == 0) {
+		ret = mcam_setup_vb2(cam);
+		if (ret)
+			goto out;
+		mcam_ctlr_power_up(cam);
+		__mcam_cam_reset(cam);
+		mcam_set_config_needed(cam, 1);
+	}
+	(cam->users)++;
+out:
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+
+static int mcam_v4l_release(struct file *filp)
+{
+	struct mcam_camera *cam = filp->private_data;
+
+	cam_dbg(cam, "Release, %d frames, %d singles, %d delivered\n", frames,
+			singles, delivered);
+	mutex_lock(&cam->s_mutex);
+	(cam->users)--;
+	if (cam->users == 0) {
+		mcam_ctlr_stop_dma(cam);
+		mcam_cleanup_vb2(cam);
+		mcam_ctlr_power_down(cam);
+		if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read)
+			mcam_free_dma_bufs(cam);
+	}
+	mutex_unlock(&cam->s_mutex);
+	return 0;
+}
+
+static ssize_t mcam_v4l_read(struct file *filp,
+		char __user *buffer, size_t len, loff_t *pos)
+{
+	struct mcam_camera *cam = filp->private_data;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	ret = vb2_read(&cam->vb_queue, buffer, len, pos,
+			filp->f_flags & O_NONBLOCK);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+
+
+static unsigned int mcam_v4l_poll(struct file *filp,
+		struct poll_table_struct *pt)
+{
+	struct mcam_camera *cam = filp->private_data;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	ret = vb2_poll(&cam->vb_queue, filp, pt);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+
+static int mcam_v4l_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct mcam_camera *cam = filp->private_data;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	ret = vb2_mmap(&cam->vb_queue, vma);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+
+
+static const struct v4l2_file_operations mcam_v4l_fops = {
+	.owner = THIS_MODULE,
+	.open = mcam_v4l_open,
+	.release = mcam_v4l_release,
+	.read = mcam_v4l_read,
+	.poll = mcam_v4l_poll,
+	.mmap = mcam_v4l_mmap,
+	.unlocked_ioctl = video_ioctl2,
+};
+
+
+/*
+ * This template device holds all of those v4l2 methods; we
+ * clone it for specific real devices.
+ */
+static struct video_device mcam_v4l_template = {
+	.name = "mcam",
+	.tvnorms = V4L2_STD_NTSC_M,
+	.current_norm = V4L2_STD_NTSC_M,  /* make mplayer happy */
+
+	.fops = &mcam_v4l_fops,
+	.ioctl_ops = &mcam_v4l_ioctl_ops,
+	.release = video_device_release_empty,
+};
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Interrupt handler stuff
+ */
+static void mcam_frame_complete(struct mcam_camera *cam, int frame)
+{
+	/*
+	 * Basic frame housekeeping.
+	 */
+	set_bit(frame, &cam->flags);
+	clear_bit(CF_DMA_ACTIVE, &cam->flags);
+	cam->next_buf = frame;
+	cam->buf_seq[frame] = ++(cam->sequence);
+	frames++;
+	/*
+	 * "This should never happen"
+	 */
+	if (cam->state != S_STREAMING)
+		return;
+	/*
+	 * Process the frame and set up the next one.
+	 */
+	cam->frame_complete(cam, frame);
+}
+
+
+/*
+ * The interrupt handler; this needs to be called from the
+ * platform irq handler with the lock held.
+ */
+int mccic_irq(struct mcam_camera *cam, unsigned int irqs)
+{
+	unsigned int frame, handled = 0;
+
+	mcam_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); /* Clear'em all */
+	/*
+	 * Handle any frame completions.  There really should
+	 * not be more than one of these, or we have fallen
+	 * far behind.
+	 *
+	 * When running in S/G mode, the frame number lacks any
+	 * real meaning - there's only one descriptor array - but
+	 * the controller still picks a different one to signal
+	 * each time.
+	 */
+	for (frame = 0; frame < cam->nbufs; frame++)
+		if (irqs & (IRQ_EOF0 << frame)) {
+			mcam_frame_complete(cam, frame);
+			handled = 1;
+			if (cam->buffer_mode == B_DMA_sg)
+				break;
+		}
+	/*
+	 * If a frame starts, note that we have DMA active.  This
+	 * code assumes that we won't get multiple frame interrupts
+	 * at once; may want to rethink that.
+	 */
+	if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2)) {
+		set_bit(CF_DMA_ACTIVE, &cam->flags);
+		handled = 1;
+		if (cam->buffer_mode == B_DMA_sg)
+			mcam_ctlr_stop(cam);
+	}
+	return handled;
+}
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Registration and such.
+ */
+static struct ov7670_config sensor_cfg = {
+	/*
+	 * Exclude QCIF mode, because it only captures a tiny portion
+	 * of the sensor FOV
+	 */
+	.min_width = 320,
+	.min_height = 240,
+};
+
+
+int mccic_register(struct mcam_camera *cam)
+{
+	struct i2c_board_info ov7670_info = {
+		.type = "ov7670",
+		.addr = 0x42 >> 1,
+		.platform_data = &sensor_cfg,
+	};
+	int ret;
+
+	/*
+	 * Validate the requested buffer mode.
+	 */
+	if (buffer_mode >= 0)
+		cam->buffer_mode = buffer_mode;
+	if (cam->buffer_mode == B_DMA_sg &&
+			cam->chip_id == V4L2_IDENT_CAFE) {
+		printk(KERN_ERR "marvell-cam: Cafe can't do S/G I/O, "
+			"attempting vmalloc mode instead\n");
+		cam->buffer_mode = B_vmalloc;
+	}
+	if (!mcam_buffer_mode_supported(cam->buffer_mode)) {
+		printk(KERN_ERR "marvell-cam: buffer mode %d unsupported\n",
+				cam->buffer_mode);
+		return -EINVAL;
+	}
+	/*
+	 * Register with V4L
+	 */
+	ret = v4l2_device_register(cam->dev, &cam->v4l2_dev);
+	if (ret)
+		return ret;
+
+	mutex_init(&cam->s_mutex);
+	cam->state = S_NOTREADY;
+	mcam_set_config_needed(cam, 1);
+	cam->pix_format = mcam_def_pix_format;
+	cam->mbus_code = mcam_def_mbus_code;
+	INIT_LIST_HEAD(&cam->buffers);
+	mcam_ctlr_init(cam);
+
+	/*
+	 * Try to find the sensor.
+	 */
+	sensor_cfg.clock_speed = cam->clock_speed;
+	sensor_cfg.use_smbus = cam->use_smbus;
+	cam->sensor_addr = ov7670_info.addr;
+	cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev,
+			cam->i2c_adapter, &ov7670_info, NULL);
+	if (cam->sensor == NULL) {
+		ret = -ENODEV;
+		goto out_unregister;
+	}
+
+	ret = mcam_cam_init(cam);
+	if (ret)
+		goto out_unregister;
+	/*
+	 * Get the v4l2 setup done.
+	 */
+	mutex_lock(&cam->s_mutex);
+	cam->vdev = mcam_v4l_template;
+	cam->vdev.debug = 0;
+	cam->vdev.v4l2_dev = &cam->v4l2_dev;
+	ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
+	if (ret)
+		goto out;
+	video_set_drvdata(&cam->vdev, cam);
+
+	/*
+	 * If so requested, try to get our DMA buffers now.
+	 */
+	if (cam->buffer_mode == B_vmalloc && !alloc_bufs_at_read) {
+		if (mcam_alloc_dma_bufs(cam, 1))
+			cam_warn(cam, "Unable to alloc DMA buffers at load"
+					" will try again later.");
+	}
+
+out:
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+out_unregister:
+	v4l2_device_unregister(&cam->v4l2_dev);
+	return ret;
+}
+
+
+void mccic_shutdown(struct mcam_camera *cam)
+{
+	/*
+	 * If we have no users (and we really, really should have no
+	 * users) the device will already be powered down.  Trying to
+	 * take it down again will wedge the machine, which is frowned
+	 * upon.
+	 */
+	if (cam->users > 0) {
+		cam_warn(cam, "Removing a device with users!\n");
+		mcam_ctlr_power_down(cam);
+	}
+	vb2_queue_release(&cam->vb_queue);
+	if (cam->buffer_mode == B_vmalloc)
+		mcam_free_dma_bufs(cam);
+	video_unregister_device(&cam->vdev);
+	v4l2_device_unregister(&cam->v4l2_dev);
+}
+
+/*
+ * Power management
+ */
+#ifdef CONFIG_PM
+
+void mccic_suspend(struct mcam_camera *cam)
+{
+	mutex_lock(&cam->s_mutex);
+	if (cam->users > 0) {
+		enum mcam_state cstate = cam->state;
+
+		mcam_ctlr_stop_dma(cam);
+		mcam_ctlr_power_down(cam);
+		cam->state = cstate;
+	}
+	mutex_unlock(&cam->s_mutex);
+}
+
+int mccic_resume(struct mcam_camera *cam)
+{
+	int ret = 0;
+
+	mutex_lock(&cam->s_mutex);
+	if (cam->users > 0) {
+		mcam_ctlr_power_up(cam);
+		__mcam_cam_reset(cam);
+	} else {
+		mcam_ctlr_power_down(cam);
+	}
+	mutex_unlock(&cam->s_mutex);
+
+	set_bit(CF_CONFIG_NEEDED, &cam->flags);
+	if (cam->state == S_STREAMING) {
+		/*
+		 * If there was a buffer in the DMA engine at suspend
+		 * time, put it back on the queue or we'll forget about it.
+		 */
+		if (cam->buffer_mode == B_DMA_sg && cam->vb_bufs[0])
+			list_add(&cam->vb_bufs[0]->queue, &cam->buffers);
+		ret = mcam_read_setup(cam);
+	}
+	return ret;
+}
+#endif /* CONFIG_PM */
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.h b/drivers/media/platform/marvell-ccic/mcam-core.h
new file mode 100644
index 0000000..bd6acba
--- /dev/null
+++ b/drivers/media/platform/marvell-ccic/mcam-core.h
@@ -0,0 +1,322 @@
+/*
+ * Marvell camera core structures.
+ *
+ * Copyright 2011 Jonathan Corbet corbet@lwn.net
+ */
+#ifndef _MCAM_CORE_H
+#define _MCAM_CORE_H
+
+#include <linux/list.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf2-core.h>
+
+/*
+ * Create our own symbols for the supported buffer modes, but, for now,
+ * base them entirely on which videobuf2 options have been selected.
+ */
+#if defined(CONFIG_VIDEOBUF2_VMALLOC) || defined(CONFIG_VIDEOBUF2_VMALLOC_MODULE)
+#define MCAM_MODE_VMALLOC 1
+#endif
+
+#if defined(CONFIG_VIDEOBUF2_DMA_CONTIG) || defined(CONFIG_VIDEOBUF2_DMA_CONTIG_MODULE)
+#define MCAM_MODE_DMA_CONTIG 1
+#endif
+
+#if defined(CONFIG_VIDEOBUF2_DMA_SG) || defined(CONFIG_VIDEOBUF2_DMA_SG_MODULE)
+#define MCAM_MODE_DMA_SG 1
+#endif
+
+#if !defined(MCAM_MODE_VMALLOC) && !defined(MCAM_MODE_DMA_CONTIG) && \
+	!defined(MCAM_MODE_DMA_SG)
+#error One of the videobuf buffer modes must be selected in the config
+#endif
+
+
+enum mcam_state {
+	S_NOTREADY,	/* Not yet initialized */
+	S_IDLE,		/* Just hanging around */
+	S_FLAKED,	/* Some sort of problem */
+	S_STREAMING,	/* Streaming data */
+	S_BUFWAIT	/* streaming requested but no buffers yet */
+};
+#define MAX_DMA_BUFS 3
+
+/*
+ * Different platforms work best with different buffer modes, so we
+ * let the platform pick.
+ */
+enum mcam_buffer_mode {
+	B_vmalloc = 0,
+	B_DMA_contig = 1,
+	B_DMA_sg = 2
+};
+
+/*
+ * Is a given buffer mode supported by the current kernel configuration?
+ */
+static inline int mcam_buffer_mode_supported(enum mcam_buffer_mode mode)
+{
+	switch (mode) {
+#ifdef MCAM_MODE_VMALLOC
+	case B_vmalloc:
+#endif
+#ifdef MCAM_MODE_DMA_CONTIG
+	case B_DMA_contig:
+#endif
+#ifdef MCAM_MODE_DMA_SG
+	case B_DMA_sg:
+#endif
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+
+/*
+ * A description of one of our devices.
+ * Locking: controlled by s_mutex.  Certain fields, however, require
+ *          the dev_lock spinlock; they are marked as such by comments.
+ *          dev_lock is also required for access to device registers.
+ */
+struct mcam_camera {
+	/*
+	 * These fields should be set by the platform code prior to
+	 * calling mcam_register().
+	 */
+	struct i2c_adapter *i2c_adapter;
+	unsigned char __iomem *regs;
+	spinlock_t dev_lock;
+	struct device *dev; /* For messages, dma alloc */
+	unsigned int chip_id;
+	short int clock_speed;	/* Sensor clock speed, default 30 */
+	short int use_smbus;	/* SMBUS or straight I2c? */
+	enum mcam_buffer_mode buffer_mode;
+	/*
+	 * Callbacks from the core to the platform code.
+	 */
+	void (*plat_power_up) (struct mcam_camera *cam);
+	void (*plat_power_down) (struct mcam_camera *cam);
+
+	/*
+	 * Everything below here is private to the mcam core and
+	 * should not be touched by the platform code.
+	 */
+	struct v4l2_device v4l2_dev;
+	enum mcam_state state;
+	unsigned long flags;		/* Buffer status, mainly (dev_lock) */
+	int users;			/* How many open FDs */
+
+	/*
+	 * Subsystem structures.
+	 */
+	struct video_device vdev;
+	struct v4l2_subdev *sensor;
+	unsigned short sensor_addr;
+
+	/* Videobuf2 stuff */
+	struct vb2_queue vb_queue;
+	struct list_head buffers;	/* Available frames */
+
+	unsigned int nbufs;		/* How many are alloc'd */
+	int next_buf;			/* Next to consume (dev_lock) */
+
+	/* DMA buffers - vmalloc mode */
+#ifdef MCAM_MODE_VMALLOC
+	unsigned int dma_buf_size;	/* allocated size */
+	void *dma_bufs[MAX_DMA_BUFS];	/* Internal buffer addresses */
+	dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */
+	struct tasklet_struct s_tasklet;
+#endif
+	unsigned int sequence;		/* Frame sequence number */
+	unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual bufs */
+
+	/* DMA buffers - DMA modes */
+	struct mcam_vb_buffer *vb_bufs[MAX_DMA_BUFS];
+	struct vb2_alloc_ctx *vb_alloc_ctx;
+
+	/* Mode-specific ops, set at open time */
+	void (*dma_setup)(struct mcam_camera *cam);
+	void (*frame_complete)(struct mcam_camera *cam, int frame);
+
+	/* Current operating parameters */
+	u32 sensor_type;		/* Currently ov7670 only */
+	struct v4l2_pix_format pix_format;
+	enum v4l2_mbus_pixelcode mbus_code;
+
+	/* Locks */
+	struct mutex s_mutex; /* Access to this structure */
+};
+
+
+/*
+ * Register I/O functions.  These are here because the platform code
+ * may legitimately need to mess with the register space.
+ */
+/*
+ * Device register I/O
+ */
+static inline void mcam_reg_write(struct mcam_camera *cam, unsigned int reg,
+		unsigned int val)
+{
+	iowrite32(val, cam->regs + reg);
+}
+
+static inline unsigned int mcam_reg_read(struct mcam_camera *cam,
+		unsigned int reg)
+{
+	return ioread32(cam->regs + reg);
+}
+
+
+static inline void mcam_reg_write_mask(struct mcam_camera *cam, unsigned int reg,
+		unsigned int val, unsigned int mask)
+{
+	unsigned int v = mcam_reg_read(cam, reg);
+
+	v = (v & ~mask) | (val & mask);
+	mcam_reg_write(cam, reg, v);
+}
+
+static inline void mcam_reg_clear_bit(struct mcam_camera *cam,
+		unsigned int reg, unsigned int val)
+{
+	mcam_reg_write_mask(cam, reg, 0, val);
+}
+
+static inline void mcam_reg_set_bit(struct mcam_camera *cam,
+		unsigned int reg, unsigned int val)
+{
+	mcam_reg_write_mask(cam, reg, val, val);
+}
+
+/*
+ * Functions for use by platform code.
+ */
+int mccic_register(struct mcam_camera *cam);
+int mccic_irq(struct mcam_camera *cam, unsigned int irqs);
+void mccic_shutdown(struct mcam_camera *cam);
+#ifdef CONFIG_PM
+void mccic_suspend(struct mcam_camera *cam);
+int mccic_resume(struct mcam_camera *cam);
+#endif
+
+/*
+ * Register definitions for the m88alp01 camera interface.  Offsets in bytes
+ * as given in the spec.
+ */
+#define REG_Y0BAR	0x00
+#define REG_Y1BAR	0x04
+#define REG_Y2BAR	0x08
+/* ... */
+
+#define REG_IMGPITCH	0x24	/* Image pitch register */
+#define   IMGP_YP_SHFT	  2		/* Y pitch params */
+#define   IMGP_YP_MASK	  0x00003ffc	/* Y pitch field */
+#define	  IMGP_UVP_SHFT	  18		/* UV pitch (planar) */
+#define   IMGP_UVP_MASK   0x3ffc0000
+#define REG_IRQSTATRAW	0x28	/* RAW IRQ Status */
+#define   IRQ_EOF0	  0x00000001	/* End of frame 0 */
+#define   IRQ_EOF1	  0x00000002	/* End of frame 1 */
+#define   IRQ_EOF2	  0x00000004	/* End of frame 2 */
+#define   IRQ_SOF0	  0x00000008	/* Start of frame 0 */
+#define   IRQ_SOF1	  0x00000010	/* Start of frame 1 */
+#define   IRQ_SOF2	  0x00000020	/* Start of frame 2 */
+#define   IRQ_OVERFLOW	  0x00000040	/* FIFO overflow */
+#define   IRQ_TWSIW	  0x00010000	/* TWSI (smbus) write */
+#define   IRQ_TWSIR	  0x00020000	/* TWSI read */
+#define   IRQ_TWSIE	  0x00040000	/* TWSI error */
+#define   TWSIIRQS (IRQ_TWSIW|IRQ_TWSIR|IRQ_TWSIE)
+#define   FRAMEIRQS (IRQ_EOF0|IRQ_EOF1|IRQ_EOF2|IRQ_SOF0|IRQ_SOF1|IRQ_SOF2)
+#define   ALLIRQS (TWSIIRQS|FRAMEIRQS|IRQ_OVERFLOW)
+#define REG_IRQMASK	0x2c	/* IRQ mask - same bits as IRQSTAT */
+#define REG_IRQSTAT	0x30	/* IRQ status / clear */
+
+#define REG_IMGSIZE	0x34	/* Image size */
+#define  IMGSZ_V_MASK	  0x1fff0000
+#define  IMGSZ_V_SHIFT	  16
+#define	 IMGSZ_H_MASK	  0x00003fff
+#define REG_IMGOFFSET	0x38	/* IMage offset */
+
+#define REG_CTRL0	0x3c	/* Control 0 */
+#define   C0_ENABLE	  0x00000001	/* Makes the whole thing go */
+
+/* Mask for all the format bits */
+#define   C0_DF_MASK	  0x00fffffc    /* Bits 2-23 */
+
+/* RGB ordering */
+#define	  C0_RGB4_RGBX	  0x00000000
+#define	  C0_RGB4_XRGB	  0x00000004
+#define	  C0_RGB4_BGRX	  0x00000008
+#define	  C0_RGB4_XBGR	  0x0000000c
+#define	  C0_RGB5_RGGB	  0x00000000
+#define	  C0_RGB5_GRBG	  0x00000004
+#define	  C0_RGB5_GBRG	  0x00000008
+#define	  C0_RGB5_BGGR	  0x0000000c
+
+/* Spec has two fields for DIN and DOUT, but they must match, so
+   combine them here. */
+#define	  C0_DF_YUV	  0x00000000	/* Data is YUV	    */
+#define	  C0_DF_RGB	  0x000000a0	/* ... RGB		    */
+#define	  C0_DF_BAYER	  0x00000140	/* ... Bayer		    */
+/* 8-8-8 must be missing from the below - ask */
+#define	  C0_RGBF_565	  0x00000000
+#define	  C0_RGBF_444	  0x00000800
+#define	  C0_RGB_BGR	  0x00001000	/* Blue comes first */
+#define	  C0_YUV_PLANAR	  0x00000000	/* YUV 422 planar format */
+#define	  C0_YUV_PACKED	  0x00008000	/* YUV 422 packed	*/
+#define	  C0_YUV_420PL	  0x0000a000	/* YUV 420 planar	*/
+/* Think that 420 packed must be 111 - ask */
+#define	  C0_YUVE_YUYV	  0x00000000	/* Y1CbY0Cr		*/
+#define	  C0_YUVE_YVYU	  0x00010000	/* Y1CrY0Cb		*/
+#define	  C0_YUVE_VYUY	  0x00020000	/* CrY1CbY0		*/
+#define	  C0_YUVE_UYVY	  0x00030000	/* CbY1CrY0		*/
+#define	  C0_YUVE_XYUV	  0x00000000	/* 420: .YUV		*/
+#define	  C0_YUVE_XYVU	  0x00010000	/* 420: .YVU		*/
+#define	  C0_YUVE_XUVY	  0x00020000	/* 420: .UVY		*/
+#define	  C0_YUVE_XVUY	  0x00030000	/* 420: .VUY		*/
+/* Bayer bits 18,19 if needed */
+#define	  C0_HPOL_LOW	  0x01000000	/* HSYNC polarity active low */
+#define	  C0_VPOL_LOW	  0x02000000	/* VSYNC polarity active low */
+#define	  C0_VCLK_LOW	  0x04000000	/* VCLK on falling edge */
+#define	  C0_DOWNSCALE	  0x08000000	/* Enable downscaler */
+#define	  C0_SIFM_MASK	  0xc0000000	/* SIF mode bits */
+#define	  C0_SIF_HVSYNC	  0x00000000	/* Use H/VSYNC */
+#define	  CO_SOF_NOSYNC	  0x40000000	/* Use inband active signaling */
+
+/* Bits below C1_444ALPHA are not present in Cafe */
+#define REG_CTRL1	0x40	/* Control 1 */
+#define	  C1_CLKGATE	  0x00000001	/* Sensor clock gate */
+#define   C1_DESC_ENA	  0x00000100	/* DMA descriptor enable */
+#define   C1_DESC_3WORD   0x00000200	/* Three-word descriptors used */
+#define	  C1_444ALPHA	  0x00f00000	/* Alpha field in RGB444 */
+#define	  C1_ALPHA_SHFT	  20
+#define	  C1_DMAB32	  0x00000000	/* 32-byte DMA burst */
+#define	  C1_DMAB16	  0x02000000	/* 16-byte DMA burst */
+#define	  C1_DMAB64	  0x04000000	/* 64-byte DMA burst */
+#define	  C1_DMAB_MASK	  0x06000000
+#define	  C1_TWOBUFS	  0x08000000	/* Use only two DMA buffers */
+#define	  C1_PWRDWN	  0x10000000	/* Power down */
+
+#define REG_CLKCTRL	0x88	/* Clock control */
+#define	  CLK_DIV_MASK	  0x0000ffff	/* Upper bits RW "reserved" */
+
+/* This appears to be a Cafe-only register */
+#define REG_UBAR	0xc4	/* Upper base address register */
+
+/* Armada 610 DMA descriptor registers */
+#define	REG_DMA_DESC_Y	0x200
+#define	REG_DMA_DESC_U	0x204
+#define	REG_DMA_DESC_V	0x208
+#define REG_DESC_LEN_Y	0x20c	/* Lengths are in bytes */
+#define	REG_DESC_LEN_U	0x210
+#define REG_DESC_LEN_V	0x214
+
+/*
+ * Useful stuff that probably belongs somewhere global.
+ */
+#define VGA_WIDTH	640
+#define VGA_HEIGHT	480
+
+#endif /* _MCAM_CORE_H */
diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c
new file mode 100644
index 0000000..c4c17fe
--- /dev/null
+++ b/drivers/media/platform/marvell-ccic/mmp-driver.c
@@ -0,0 +1,380 @@
+/*
+ * Support for the camera device found on Marvell MMP processors; known
+ * to work with the Armada 610 as used in the OLPC 1.75 system.
+ *
+ * Copyright 2011 Jonathan Corbet <corbet@lwn.net>
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/mmp-camera.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/pm.h>
+
+#include "mcam-core.h"
+
+MODULE_ALIAS("platform:mmp-camera");
+MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
+MODULE_LICENSE("GPL");
+
+struct mmp_camera {
+	void *power_regs;
+	struct platform_device *pdev;
+	struct mcam_camera mcam;
+	struct list_head devlist;
+	int irq;
+};
+
+static inline struct mmp_camera *mcam_to_cam(struct mcam_camera *mcam)
+{
+	return container_of(mcam, struct mmp_camera, mcam);
+}
+
+/*
+ * A silly little infrastructure so we can keep track of our devices.
+ * Chances are that we will never have more than one of them, but
+ * the Armada 610 *does* have two controllers...
+ */
+
+static LIST_HEAD(mmpcam_devices);
+static struct mutex mmpcam_devices_lock;
+
+static void mmpcam_add_device(struct mmp_camera *cam)
+{
+	mutex_lock(&mmpcam_devices_lock);
+	list_add(&cam->devlist, &mmpcam_devices);
+	mutex_unlock(&mmpcam_devices_lock);
+}
+
+static void mmpcam_remove_device(struct mmp_camera *cam)
+{
+	mutex_lock(&mmpcam_devices_lock);
+	list_del(&cam->devlist);
+	mutex_unlock(&mmpcam_devices_lock);
+}
+
+/*
+ * Platform dev remove passes us a platform_device, and there's
+ * no handy unused drvdata to stash a backpointer in.  So just
+ * dig it out of our list.
+ */
+static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev)
+{
+	struct mmp_camera *cam;
+
+	mutex_lock(&mmpcam_devices_lock);
+	list_for_each_entry(cam, &mmpcam_devices, devlist) {
+		if (cam->pdev == pdev) {
+			mutex_unlock(&mmpcam_devices_lock);
+			return cam;
+		}
+	}
+	mutex_unlock(&mmpcam_devices_lock);
+	return NULL;
+}
+
+
+
+
+/*
+ * Power-related registers; this almost certainly belongs
+ * somewhere else.
+ *
+ * ARMADA 610 register manual, sec 7.2.1, p1842.
+ */
+#define CPU_SUBSYS_PMU_BASE	0xd4282800
+#define REG_CCIC_DCGCR		0x28	/* CCIC dyn clock gate ctrl reg */
+#define REG_CCIC_CRCR		0x50	/* CCIC clk reset ctrl reg	*/
+
+/*
+ * Power control.
+ */
+static void mmpcam_power_up_ctlr(struct mmp_camera *cam)
+{
+	iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR);
+	iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR);
+	mdelay(1);
+}
+
+static void mmpcam_power_up(struct mcam_camera *mcam)
+{
+	struct mmp_camera *cam = mcam_to_cam(mcam);
+	struct mmp_camera_platform_data *pdata;
+/*
+ * Turn on power and clocks to the controller.
+ */
+	mmpcam_power_up_ctlr(cam);
+/*
+ * Provide power to the sensor.
+ */
+	mcam_reg_write(mcam, REG_CLKCTRL, 0x60000002);
+	pdata = cam->pdev->dev.platform_data;
+	gpio_set_value(pdata->sensor_power_gpio, 1);
+	mdelay(5);
+	mcam_reg_clear_bit(mcam, REG_CTRL1, 0x10000000);
+	gpio_set_value(pdata->sensor_reset_gpio, 0); /* reset is active low */
+	mdelay(5);
+	gpio_set_value(pdata->sensor_reset_gpio, 1); /* reset is active low */
+	mdelay(5);
+}
+
+static void mmpcam_power_down(struct mcam_camera *mcam)
+{
+	struct mmp_camera *cam = mcam_to_cam(mcam);
+	struct mmp_camera_platform_data *pdata;
+/*
+ * Turn off clocks and set reset lines
+ */
+	iowrite32(0, cam->power_regs + REG_CCIC_DCGCR);
+	iowrite32(0, cam->power_regs + REG_CCIC_CRCR);
+/*
+ * Shut down the sensor.
+ */
+	pdata = cam->pdev->dev.platform_data;
+	gpio_set_value(pdata->sensor_power_gpio, 0);
+	gpio_set_value(pdata->sensor_reset_gpio, 0);
+}
+
+
+static irqreturn_t mmpcam_irq(int irq, void *data)
+{
+	struct mcam_camera *mcam = data;
+	unsigned int irqs, handled;
+
+	spin_lock(&mcam->dev_lock);
+	irqs = mcam_reg_read(mcam, REG_IRQSTAT);
+	handled = mccic_irq(mcam, irqs);
+	spin_unlock(&mcam->dev_lock);
+	return IRQ_RETVAL(handled);
+}
+
+
+static int mmpcam_probe(struct platform_device *pdev)
+{
+	struct mmp_camera *cam;
+	struct mcam_camera *mcam;
+	struct resource *res;
+	struct mmp_camera_platform_data *pdata;
+	int ret;
+
+	cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+	if (cam == NULL)
+		return -ENOMEM;
+	cam->pdev = pdev;
+	INIT_LIST_HEAD(&cam->devlist);
+
+	mcam = &cam->mcam;
+	mcam->plat_power_up = mmpcam_power_up;
+	mcam->plat_power_down = mmpcam_power_down;
+	mcam->dev = &pdev->dev;
+	mcam->use_smbus = 0;
+	mcam->chip_id = V4L2_IDENT_ARMADA610;
+	mcam->buffer_mode = B_DMA_sg;
+	spin_lock_init(&mcam->dev_lock);
+	/*
+	 * Get our I/O memory.
+	 */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "no iomem resource!\n");
+		ret = -ENODEV;
+		goto out_free;
+	}
+	mcam->regs = ioremap(res->start, resource_size(res));
+	if (mcam->regs == NULL) {
+		dev_err(&pdev->dev, "MMIO ioremap fail\n");
+		ret = -ENODEV;
+		goto out_free;
+	}
+	/*
+	 * Power/clock memory is elsewhere; get it too.  Perhaps this
+	 * should really be managed outside of this driver?
+	 */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "no power resource!\n");
+		ret = -ENODEV;
+		goto out_unmap1;
+	}
+	cam->power_regs = ioremap(res->start, resource_size(res));
+	if (cam->power_regs == NULL) {
+		dev_err(&pdev->dev, "power MMIO ioremap fail\n");
+		ret = -ENODEV;
+		goto out_unmap1;
+	}
+	/*
+	 * Find the i2c adapter.  This assumes, of course, that the
+	 * i2c bus is already up and functioning.
+	 */
+	pdata = pdev->dev.platform_data;
+	mcam->i2c_adapter = platform_get_drvdata(pdata->i2c_device);
+	if (mcam->i2c_adapter == NULL) {
+		ret = -ENODEV;
+		dev_err(&pdev->dev, "No i2c adapter\n");
+		goto out_unmap2;
+	}
+	/*
+	 * Sensor GPIO pins.
+	 */
+	ret = gpio_request(pdata->sensor_power_gpio, "cam-power");
+	if (ret) {
+		dev_err(&pdev->dev, "Can't get sensor power gpio %d",
+				pdata->sensor_power_gpio);
+		goto out_unmap2;
+	}
+	gpio_direction_output(pdata->sensor_power_gpio, 0);
+	ret = gpio_request(pdata->sensor_reset_gpio, "cam-reset");
+	if (ret) {
+		dev_err(&pdev->dev, "Can't get sensor reset gpio %d",
+				pdata->sensor_reset_gpio);
+		goto out_gpio;
+	}
+	gpio_direction_output(pdata->sensor_reset_gpio, 0);
+	/*
+	 * Power the device up and hand it off to the core.
+	 */
+	mmpcam_power_up(mcam);
+	ret = mccic_register(mcam);
+	if (ret)
+		goto out_gpio2;
+	/*
+	 * Finally, set up our IRQ now that the core is ready to
+	 * deal with it.
+	 */
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res == NULL) {
+		ret = -ENODEV;
+		goto out_unregister;
+	}
+	cam->irq = res->start;
+	ret = request_irq(cam->irq, mmpcam_irq, IRQF_SHARED,
+			"mmp-camera", mcam);
+	if (ret == 0) {
+		mmpcam_add_device(cam);
+		return 0;
+	}
+
+out_unregister:
+	mccic_shutdown(mcam);
+out_gpio2:
+	mmpcam_power_down(mcam);
+	gpio_free(pdata->sensor_reset_gpio);
+out_gpio:
+	gpio_free(pdata->sensor_power_gpio);
+out_unmap2:
+	iounmap(cam->power_regs);
+out_unmap1:
+	iounmap(mcam->regs);
+out_free:
+	kfree(cam);
+	return ret;
+}
+
+
+static int mmpcam_remove(struct mmp_camera *cam)
+{
+	struct mcam_camera *mcam = &cam->mcam;
+	struct mmp_camera_platform_data *pdata;
+
+	mmpcam_remove_device(cam);
+	free_irq(cam->irq, mcam);
+	mccic_shutdown(mcam);
+	mmpcam_power_down(mcam);
+	pdata = cam->pdev->dev.platform_data;
+	gpio_free(pdata->sensor_reset_gpio);
+	gpio_free(pdata->sensor_power_gpio);
+	iounmap(cam->power_regs);
+	iounmap(mcam->regs);
+	kfree(cam);
+	return 0;
+}
+
+static int mmpcam_platform_remove(struct platform_device *pdev)
+{
+	struct mmp_camera *cam = mmpcam_find_device(pdev);
+
+	if (cam == NULL)
+		return -ENODEV;
+	return mmpcam_remove(cam);
+}
+
+/*
+ * Suspend/resume support.
+ */
+#ifdef CONFIG_PM
+
+static int mmpcam_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct mmp_camera *cam = mmpcam_find_device(pdev);
+
+	if (state.event != PM_EVENT_SUSPEND)
+		return 0;
+	mccic_suspend(&cam->mcam);
+	return 0;
+}
+
+static int mmpcam_resume(struct platform_device *pdev)
+{
+	struct mmp_camera *cam = mmpcam_find_device(pdev);
+
+	/*
+	 * Power up unconditionally just in case the core tries to
+	 * touch a register even if nothing was active before; trust
+	 * me, it's better this way.
+	 */
+	mmpcam_power_up_ctlr(cam);
+	return mccic_resume(&cam->mcam);
+}
+
+#endif
+
+
+static struct platform_driver mmpcam_driver = {
+	.probe		= mmpcam_probe,
+	.remove		= mmpcam_platform_remove,
+#ifdef CONFIG_PM
+	.suspend	= mmpcam_suspend,
+	.resume		= mmpcam_resume,
+#endif
+	.driver = {
+		.name	= "mmp-camera",
+		.owner	= THIS_MODULE
+	}
+};
+
+
+static int __init mmpcam_init_module(void)
+{
+	mutex_init(&mmpcam_devices_lock);
+	return platform_driver_register(&mmpcam_driver);
+}
+
+static void __exit mmpcam_exit_module(void)
+{
+	platform_driver_unregister(&mmpcam_driver);
+	/*
+	 * platform_driver_unregister() should have emptied the list
+	 */
+	if (!list_empty(&mmpcam_devices))
+		printk(KERN_ERR "mmp_camera leaving devices behind\n");
+}
+
+module_init(mmpcam_init_module);
+module_exit(mmpcam_exit_module);
diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c
new file mode 100644
index 0000000..0b496f3
--- /dev/null
+++ b/drivers/media/platform/mem2mem_testdev.c
@@ -0,0 +1,1130 @@
+/*
+ * A virtual v4l2-mem2mem example device.
+ *
+ * This is a virtual device driver for testing mem-to-mem videobuf framework.
+ * It simulates a device that uses memory buffers for both source and
+ * destination, processes the data and issues an "irq" (simulated by a timer).
+ * The device is capable of multi-instance, multi-buffer-per-transaction
+ * operation (via the mem2mem framework).
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <linux/platform_device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-vmalloc.h>
+
+#define MEM2MEM_TEST_MODULE_NAME "mem2mem-testdev"
+
+MODULE_DESCRIPTION("Virtual device for mem2mem framework testing");
+MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1.1");
+
+#define MIN_W 32
+#define MIN_H 32
+#define MAX_W 640
+#define MAX_H 480
+#define DIM_ALIGN_MASK 7 /* 8-byte alignment for line length */
+
+/* Flags that indicate a format can be used for capture/output */
+#define MEM2MEM_CAPTURE	(1 << 0)
+#define MEM2MEM_OUTPUT	(1 << 1)
+
+#define MEM2MEM_NAME		"m2m-testdev"
+
+/* Per queue */
+#define MEM2MEM_DEF_NUM_BUFS	VIDEO_MAX_FRAME
+/* In bytes, per queue */
+#define MEM2MEM_VID_MEM_LIMIT	(16 * 1024 * 1024)
+
+/* Default transaction time in msec */
+#define MEM2MEM_DEF_TRANSTIME	1000
+/* Default number of buffers per transaction */
+#define MEM2MEM_DEF_TRANSLEN	1
+#define MEM2MEM_COLOR_STEP	(0xff >> 4)
+#define MEM2MEM_NUM_TILES	8
+
+/* Flags that indicate processing mode */
+#define MEM2MEM_HFLIP	(1 << 0)
+#define MEM2MEM_VFLIP	(1 << 1)
+
+#define dprintk(dev, fmt, arg...) \
+	v4l2_dbg(1, 1, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
+
+
+void m2mtest_dev_release(struct device *dev)
+{}
+
+static struct platform_device m2mtest_pdev = {
+	.name		= MEM2MEM_NAME,
+	.dev.release	= m2mtest_dev_release,
+};
+
+struct m2mtest_fmt {
+	char	*name;
+	u32	fourcc;
+	int	depth;
+	/* Types the format can be used for */
+	u32	types;
+};
+
+static struct m2mtest_fmt formats[] = {
+	{
+		.name	= "RGB565 (BE)",
+		.fourcc	= V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
+		.depth	= 16,
+		/* Both capture and output format */
+		.types	= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+	},
+	{
+		.name	= "4:2:2, packed, YUYV",
+		.fourcc	= V4L2_PIX_FMT_YUYV,
+		.depth	= 16,
+		/* Output-only format */
+		.types	= MEM2MEM_OUTPUT,
+	},
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+/* Per-queue, driver-specific private data */
+struct m2mtest_q_data {
+	unsigned int		width;
+	unsigned int		height;
+	unsigned int		sizeimage;
+	struct m2mtest_fmt	*fmt;
+};
+
+enum {
+	V4L2_M2M_SRC = 0,
+	V4L2_M2M_DST = 1,
+};
+
+#define V4L2_CID_TRANS_TIME_MSEC	(V4L2_CID_USER_BASE + 0x1000)
+#define V4L2_CID_TRANS_NUM_BUFS		(V4L2_CID_USER_BASE + 0x1001)
+
+static struct m2mtest_fmt *find_format(struct v4l2_format *f)
+{
+	struct m2mtest_fmt *fmt;
+	unsigned int k;
+
+	for (k = 0; k < NUM_FORMATS; k++) {
+		fmt = &formats[k];
+		if (fmt->fourcc == f->fmt.pix.pixelformat)
+			break;
+	}
+
+	if (k == NUM_FORMATS)
+		return NULL;
+
+	return &formats[k];
+}
+
+struct m2mtest_dev {
+	struct v4l2_device	v4l2_dev;
+	struct video_device	*vfd;
+
+	atomic_t		num_inst;
+	struct mutex		dev_mutex;
+	spinlock_t		irqlock;
+
+	struct timer_list	timer;
+
+	struct v4l2_m2m_dev	*m2m_dev;
+};
+
+struct m2mtest_ctx {
+	struct v4l2_fh		fh;
+	struct m2mtest_dev	*dev;
+
+	struct v4l2_ctrl_handler hdl;
+
+	/* Processed buffers in this transaction */
+	u8			num_processed;
+
+	/* Transaction length (i.e. how many buffers per transaction) */
+	u32			translen;
+	/* Transaction time (i.e. simulated processing time) in milliseconds */
+	u32			transtime;
+
+	/* Abort requested by m2m */
+	int			aborting;
+
+	/* Processing mode */
+	int			mode;
+
+	enum v4l2_colorspace	colorspace;
+
+	struct v4l2_m2m_ctx	*m2m_ctx;
+
+	/* Source and destination queue data */
+	struct m2mtest_q_data   q_data[2];
+};
+
+static inline struct m2mtest_ctx *file2ctx(struct file *file)
+{
+	return container_of(file->private_data, struct m2mtest_ctx, fh);
+}
+
+static struct m2mtest_q_data *get_q_data(struct m2mtest_ctx *ctx,
+					 enum v4l2_buf_type type)
+{
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		return &ctx->q_data[V4L2_M2M_SRC];
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return &ctx->q_data[V4L2_M2M_DST];
+	default:
+		BUG();
+	}
+	return NULL;
+}
+
+
+static int device_process(struct m2mtest_ctx *ctx,
+			  struct vb2_buffer *in_vb,
+			  struct vb2_buffer *out_vb)
+{
+	struct m2mtest_dev *dev = ctx->dev;
+	struct m2mtest_q_data *q_data;
+	u8 *p_in, *p_out;
+	int x, y, t, w;
+	int tile_w, bytes_left;
+	int width, height, bytesperline;
+
+	q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
+	width	= q_data->width;
+	height	= q_data->height;
+	bytesperline	= (q_data->width * q_data->fmt->depth) >> 3;
+
+	p_in = vb2_plane_vaddr(in_vb, 0);
+	p_out = vb2_plane_vaddr(out_vb, 0);
+	if (!p_in || !p_out) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Acquiring kernel pointers to buffers failed\n");
+		return -EFAULT;
+	}
+
+	if (vb2_plane_size(in_vb, 0) > vb2_plane_size(out_vb, 0)) {
+		v4l2_err(&dev->v4l2_dev, "Output buffer is too small\n");
+		return -EINVAL;
+	}
+
+	tile_w = (width * (q_data[V4L2_M2M_DST].fmt->depth >> 3))
+		/ MEM2MEM_NUM_TILES;
+	bytes_left = bytesperline - tile_w * MEM2MEM_NUM_TILES;
+	w = 0;
+
+	switch (ctx->mode) {
+	case MEM2MEM_HFLIP | MEM2MEM_VFLIP:
+		p_out += bytesperline * height - bytes_left;
+		for (y = 0; y < height; ++y) {
+			for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
+				if (w & 0x1) {
+					for (x = 0; x < tile_w; ++x)
+						*--p_out = *p_in++ +
+							MEM2MEM_COLOR_STEP;
+				} else {
+					for (x = 0; x < tile_w; ++x)
+						*--p_out = *p_in++ -
+							MEM2MEM_COLOR_STEP;
+				}
+				++w;
+			}
+			p_in += bytes_left;
+			p_out -= bytes_left;
+		}
+		break;
+
+	case MEM2MEM_HFLIP:
+		for (y = 0; y < height; ++y) {
+			p_out += MEM2MEM_NUM_TILES * tile_w;
+			for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
+				if (w & 0x01) {
+					for (x = 0; x < tile_w; ++x)
+						*--p_out = *p_in++ +
+							MEM2MEM_COLOR_STEP;
+				} else {
+					for (x = 0; x < tile_w; ++x)
+						*--p_out = *p_in++ -
+							MEM2MEM_COLOR_STEP;
+				}
+				++w;
+			}
+			p_in += bytes_left;
+			p_out += bytesperline;
+		}
+		break;
+
+	case MEM2MEM_VFLIP:
+		p_out += bytesperline * (height - 1);
+		for (y = 0; y < height; ++y) {
+			for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
+				if (w & 0x1) {
+					for (x = 0; x < tile_w; ++x)
+						*p_out++ = *p_in++ +
+							MEM2MEM_COLOR_STEP;
+				} else {
+					for (x = 0; x < tile_w; ++x)
+						*p_out++ = *p_in++ -
+							MEM2MEM_COLOR_STEP;
+				}
+				++w;
+			}
+			p_in += bytes_left;
+			p_out += bytes_left - 2 * bytesperline;
+		}
+		break;
+
+	default:
+		for (y = 0; y < height; ++y) {
+			for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
+				if (w & 0x1) {
+					for (x = 0; x < tile_w; ++x)
+						*p_out++ = *p_in++ +
+							MEM2MEM_COLOR_STEP;
+				} else {
+					for (x = 0; x < tile_w; ++x)
+						*p_out++ = *p_in++ -
+							MEM2MEM_COLOR_STEP;
+				}
+				++w;
+			}
+			p_in += bytes_left;
+			p_out += bytes_left;
+		}
+	}
+
+	return 0;
+}
+
+static void schedule_irq(struct m2mtest_dev *dev, int msec_timeout)
+{
+	dprintk(dev, "Scheduling a simulated irq\n");
+	mod_timer(&dev->timer, jiffies + msecs_to_jiffies(msec_timeout));
+}
+
+/*
+ * mem2mem callbacks
+ */
+
+/**
+ * job_ready() - check whether an instance is ready to be scheduled to run
+ */
+static int job_ready(void *priv)
+{
+	struct m2mtest_ctx *ctx = priv;
+
+	if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < ctx->translen
+	    || v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < ctx->translen) {
+		dprintk(ctx->dev, "Not enough buffers available\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static void job_abort(void *priv)
+{
+	struct m2mtest_ctx *ctx = priv;
+
+	/* Will cancel the transaction in the next interrupt handler */
+	ctx->aborting = 1;
+}
+
+static void m2mtest_lock(void *priv)
+{
+	struct m2mtest_ctx *ctx = priv;
+	struct m2mtest_dev *dev = ctx->dev;
+	mutex_lock(&dev->dev_mutex);
+}
+
+static void m2mtest_unlock(void *priv)
+{
+	struct m2mtest_ctx *ctx = priv;
+	struct m2mtest_dev *dev = ctx->dev;
+	mutex_unlock(&dev->dev_mutex);
+}
+
+
+/* device_run() - prepares and starts the device
+ *
+ * This simulates all the immediate preparations required before starting
+ * a device. This will be called by the framework when it decides to schedule
+ * a particular instance.
+ */
+static void device_run(void *priv)
+{
+	struct m2mtest_ctx *ctx = priv;
+	struct m2mtest_dev *dev = ctx->dev;
+	struct vb2_buffer *src_buf, *dst_buf;
+
+	src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+
+	device_process(ctx, src_buf, dst_buf);
+
+	/* Run a timer, which simulates a hardware irq  */
+	schedule_irq(dev, ctx->transtime);
+}
+
+static void device_isr(unsigned long priv)
+{
+	struct m2mtest_dev *m2mtest_dev = (struct m2mtest_dev *)priv;
+	struct m2mtest_ctx *curr_ctx;
+	struct vb2_buffer *src_vb, *dst_vb;
+	unsigned long flags;
+
+	curr_ctx = v4l2_m2m_get_curr_priv(m2mtest_dev->m2m_dev);
+
+	if (NULL == curr_ctx) {
+		printk(KERN_ERR
+			"Instance released before the end of transaction\n");
+		return;
+	}
+
+	src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
+	dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+
+	curr_ctx->num_processed++;
+
+	spin_lock_irqsave(&m2mtest_dev->irqlock, flags);
+	v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+	v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+	spin_unlock_irqrestore(&m2mtest_dev->irqlock, flags);
+
+	if (curr_ctx->num_processed == curr_ctx->translen
+	    || curr_ctx->aborting) {
+		dprintk(curr_ctx->dev, "Finishing transaction\n");
+		curr_ctx->num_processed = 0;
+		v4l2_m2m_job_finish(m2mtest_dev->m2m_dev, curr_ctx->m2m_ctx);
+	} else {
+		device_run(curr_ctx);
+	}
+}
+
+/*
+ * video ioctls
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
+	strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
+	strlcpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->bus_info));
+	cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+	return 0;
+}
+
+static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
+{
+	int i, num;
+	struct m2mtest_fmt *fmt;
+
+	num = 0;
+
+	for (i = 0; i < NUM_FORMATS; ++i) {
+		if (formats[i].types & type) {
+			/* index-th format of type type found ? */
+			if (num == f->index)
+				break;
+			/* Correct type but haven't reached our index yet,
+			 * just increment per-type index */
+			++num;
+		}
+	}
+
+	if (i < NUM_FORMATS) {
+		/* Format found */
+		fmt = &formats[i];
+		strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+		f->pixelformat = fmt->fourcc;
+		return 0;
+	}
+
+	/* Format not found */
+	return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	return enum_fmt(f, MEM2MEM_CAPTURE);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	return enum_fmt(f, MEM2MEM_OUTPUT);
+}
+
+static int vidioc_g_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
+{
+	struct vb2_queue *vq;
+	struct m2mtest_q_data *q_data;
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, f->type);
+
+	f->fmt.pix.width	= q_data->width;
+	f->fmt.pix.height	= q_data->height;
+	f->fmt.pix.field	= V4L2_FIELD_NONE;
+	f->fmt.pix.pixelformat	= q_data->fmt->fourcc;
+	f->fmt.pix.bytesperline	= (q_data->width * q_data->fmt->depth) >> 3;
+	f->fmt.pix.sizeimage	= q_data->sizeimage;
+	f->fmt.pix.colorspace	= ctx->colorspace;
+
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	return vidioc_g_fmt(file2ctx(file), f);
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	return vidioc_g_fmt(file2ctx(file), f);
+}
+
+static int vidioc_try_fmt(struct v4l2_format *f, struct m2mtest_fmt *fmt)
+{
+	enum v4l2_field field;
+
+	field = f->fmt.pix.field;
+
+	if (field == V4L2_FIELD_ANY)
+		field = V4L2_FIELD_NONE;
+	else if (V4L2_FIELD_NONE != field)
+		return -EINVAL;
+
+	/* V4L2 specification suggests the driver corrects the format struct
+	 * if any of the dimensions is unsupported */
+	f->fmt.pix.field = field;
+
+	if (f->fmt.pix.height < MIN_H)
+		f->fmt.pix.height = MIN_H;
+	else if (f->fmt.pix.height > MAX_H)
+		f->fmt.pix.height = MAX_H;
+
+	if (f->fmt.pix.width < MIN_W)
+		f->fmt.pix.width = MIN_W;
+	else if (f->fmt.pix.width > MAX_W)
+		f->fmt.pix.width = MAX_W;
+
+	f->fmt.pix.width &= ~DIM_ALIGN_MASK;
+	f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
+	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct m2mtest_fmt *fmt;
+	struct m2mtest_ctx *ctx = file2ctx(file);
+
+	fmt = find_format(f);
+	if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
+		v4l2_err(&ctx->dev->v4l2_dev,
+			 "Fourcc format (0x%08x) invalid.\n",
+			 f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+	f->fmt.pix.colorspace = ctx->colorspace;
+
+	return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct m2mtest_fmt *fmt;
+	struct m2mtest_ctx *ctx = file2ctx(file);
+
+	fmt = find_format(f);
+	if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
+		v4l2_err(&ctx->dev->v4l2_dev,
+			 "Fourcc format (0x%08x) invalid.\n",
+			 f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+	if (!f->fmt.pix.colorspace)
+		f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+
+	return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
+{
+	struct m2mtest_q_data *q_data;
+	struct vb2_queue *vq;
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, f->type);
+	if (!q_data)
+		return -EINVAL;
+
+	if (vb2_is_busy(vq)) {
+		v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
+		return -EBUSY;
+	}
+
+	q_data->fmt		= find_format(f);
+	q_data->width		= f->fmt.pix.width;
+	q_data->height		= f->fmt.pix.height;
+	q_data->sizeimage	= q_data->width * q_data->height
+				* q_data->fmt->depth >> 3;
+
+	dprintk(ctx->dev,
+		"Setting format for type %d, wxh: %dx%d, fmt: %d\n",
+		f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
+
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	int ret;
+
+	ret = vidioc_try_fmt_vid_cap(file, priv, f);
+	if (ret)
+		return ret;
+
+	return vidioc_s_fmt(file2ctx(file), f);
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct m2mtest_ctx *ctx = file2ctx(file);
+	int ret;
+
+	ret = vidioc_try_fmt_vid_out(file, priv, f);
+	if (ret)
+		return ret;
+
+	ret = vidioc_s_fmt(file2ctx(file), f);
+	if (!ret)
+		ctx->colorspace = f->fmt.pix.colorspace;
+	return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *reqbufs)
+{
+	struct m2mtest_ctx *ctx = file2ctx(file);
+
+	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+			   struct v4l2_buffer *buf)
+{
+	struct m2mtest_ctx *ctx = file2ctx(file);
+
+	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct m2mtest_ctx *ctx = file2ctx(file);
+
+	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct m2mtest_ctx *ctx = file2ctx(file);
+
+	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type type)
+{
+	struct m2mtest_ctx *ctx = file2ctx(file);
+
+	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type type)
+{
+	struct m2mtest_ctx *ctx = file2ctx(file);
+
+	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static int m2mtest_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct m2mtest_ctx *ctx =
+		container_of(ctrl->handler, struct m2mtest_ctx, hdl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_HFLIP:
+		if (ctrl->val)
+			ctx->mode |= MEM2MEM_HFLIP;
+		else
+			ctx->mode &= ~MEM2MEM_HFLIP;
+		break;
+
+	case V4L2_CID_VFLIP:
+		if (ctrl->val)
+			ctx->mode |= MEM2MEM_VFLIP;
+		else
+			ctx->mode &= ~MEM2MEM_VFLIP;
+		break;
+
+	case V4L2_CID_TRANS_TIME_MSEC:
+		ctx->transtime = ctrl->val;
+		break;
+
+	case V4L2_CID_TRANS_NUM_BUFS:
+		ctx->translen = ctrl->val;
+		break;
+
+	default:
+		v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops m2mtest_ctrl_ops = {
+	.s_ctrl = m2mtest_s_ctrl,
+};
+
+
+static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = {
+	.vidioc_querycap	= vidioc_querycap,
+
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,
+
+	.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out	= vidioc_g_fmt_vid_out,
+	.vidioc_try_fmt_vid_out	= vidioc_try_fmt_vid_out,
+	.vidioc_s_fmt_vid_out	= vidioc_s_fmt_vid_out,
+
+	.vidioc_reqbufs		= vidioc_reqbufs,
+	.vidioc_querybuf	= vidioc_querybuf,
+
+	.vidioc_qbuf		= vidioc_qbuf,
+	.vidioc_dqbuf		= vidioc_dqbuf,
+
+	.vidioc_streamon	= vidioc_streamon,
+	.vidioc_streamoff	= vidioc_streamoff,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+
+/*
+ * Queue operations
+ */
+
+static int m2mtest_queue_setup(struct vb2_queue *vq,
+				const struct v4l2_format *fmt,
+				unsigned int *nbuffers, unsigned int *nplanes,
+				unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq);
+	struct m2mtest_q_data *q_data;
+	unsigned int size, count = *nbuffers;
+
+	q_data = get_q_data(ctx, vq->type);
+
+	size = q_data->width * q_data->height * q_data->fmt->depth >> 3;
+
+	while (size * count > MEM2MEM_VID_MEM_LIMIT)
+		(count)--;
+
+	*nplanes = 1;
+	*nbuffers = count;
+	sizes[0] = size;
+
+	/*
+	 * videobuf2-vmalloc allocator is context-less so no need to set
+	 * alloc_ctxs array.
+	 */
+
+	dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
+
+	return 0;
+}
+
+static int m2mtest_buf_prepare(struct vb2_buffer *vb)
+{
+	struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct m2mtest_q_data *q_data;
+
+	dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
+
+	q_data = get_q_data(ctx, vb->vb2_queue->type);
+
+	if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
+		dprintk(ctx->dev, "%s data will not fit into plane (%lu < %lu)\n",
+				__func__, vb2_plane_size(vb, 0), (long)q_data->sizeimage);
+		return -EINVAL;
+	}
+
+	vb2_set_plane_payload(vb, 0, q_data->sizeimage);
+
+	return 0;
+}
+
+static void m2mtest_buf_queue(struct vb2_buffer *vb)
+{
+	struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static void m2mtest_wait_prepare(struct vb2_queue *q)
+{
+	struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
+	m2mtest_unlock(ctx);
+}
+
+static void m2mtest_wait_finish(struct vb2_queue *q)
+{
+	struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
+	m2mtest_lock(ctx);
+}
+
+static struct vb2_ops m2mtest_qops = {
+	.queue_setup	 = m2mtest_queue_setup,
+	.buf_prepare	 = m2mtest_buf_prepare,
+	.buf_queue	 = m2mtest_buf_queue,
+	.wait_prepare	 = m2mtest_wait_prepare,
+	.wait_finish	 = m2mtest_wait_finish,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
+{
+	struct m2mtest_ctx *ctx = priv;
+	int ret;
+
+	memset(src_vq, 0, sizeof(*src_vq));
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->io_modes = VB2_MMAP;
+	src_vq->drv_priv = ctx;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	src_vq->ops = &m2mtest_qops;
+	src_vq->mem_ops = &vb2_vmalloc_memops;
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	memset(dst_vq, 0, sizeof(*dst_vq));
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->io_modes = VB2_MMAP;
+	dst_vq->drv_priv = ctx;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->ops = &m2mtest_qops;
+	dst_vq->mem_ops = &vb2_vmalloc_memops;
+
+	return vb2_queue_init(dst_vq);
+}
+
+static const struct v4l2_ctrl_config m2mtest_ctrl_trans_time_msec = {
+	.ops = &m2mtest_ctrl_ops,
+	.id = V4L2_CID_TRANS_TIME_MSEC,
+	.name = "Transaction Time (msec)",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.def = 1001,
+	.min = 1,
+	.max = 10001,
+	.step = 100,
+};
+
+static const struct v4l2_ctrl_config m2mtest_ctrl_trans_num_bufs = {
+	.ops = &m2mtest_ctrl_ops,
+	.id = V4L2_CID_TRANS_NUM_BUFS,
+	.name = "Buffers Per Transaction",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.def = 1,
+	.min = 1,
+	.max = MEM2MEM_DEF_NUM_BUFS,
+	.step = 1,
+};
+
+/*
+ * File operations
+ */
+static int m2mtest_open(struct file *file)
+{
+	struct m2mtest_dev *dev = video_drvdata(file);
+	struct m2mtest_ctx *ctx = NULL;
+	struct v4l2_ctrl_handler *hdl;
+	int rc = 0;
+
+	if (mutex_lock_interruptible(&dev->dev_mutex))
+		return -ERESTARTSYS;
+	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+	if (!ctx) {
+		rc = -ENOMEM;
+		goto open_unlock;
+	}
+
+	v4l2_fh_init(&ctx->fh, video_devdata(file));
+	file->private_data = &ctx->fh;
+	ctx->dev = dev;
+	hdl = &ctx->hdl;
+	v4l2_ctrl_handler_init(hdl, 4);
+	v4l2_ctrl_new_std(hdl, &m2mtest_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(hdl, &m2mtest_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_custom(hdl, &m2mtest_ctrl_trans_time_msec, NULL);
+	v4l2_ctrl_new_custom(hdl, &m2mtest_ctrl_trans_num_bufs, NULL);
+	if (hdl->error) {
+		rc = hdl->error;
+		v4l2_ctrl_handler_free(hdl);
+		goto open_unlock;
+	}
+	ctx->fh.ctrl_handler = hdl;
+	v4l2_ctrl_handler_setup(hdl);
+
+	ctx->q_data[V4L2_M2M_SRC].fmt = &formats[0];
+	ctx->q_data[V4L2_M2M_SRC].width = 640;
+	ctx->q_data[V4L2_M2M_SRC].height = 480;
+	ctx->q_data[V4L2_M2M_SRC].sizeimage =
+		ctx->q_data[V4L2_M2M_SRC].width *
+		ctx->q_data[V4L2_M2M_SRC].height *
+		(ctx->q_data[V4L2_M2M_SRC].fmt->depth >> 3);
+	ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
+	ctx->colorspace = V4L2_COLORSPACE_REC709;
+
+	ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
+
+	if (IS_ERR(ctx->m2m_ctx)) {
+		rc = PTR_ERR(ctx->m2m_ctx);
+
+		v4l2_ctrl_handler_free(hdl);
+		kfree(ctx);
+		goto open_unlock;
+	}
+
+	v4l2_fh_add(&ctx->fh);
+	atomic_inc(&dev->num_inst);
+
+	dprintk(dev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
+
+open_unlock:
+	mutex_unlock(&dev->dev_mutex);
+	return rc;
+}
+
+static int m2mtest_release(struct file *file)
+{
+	struct m2mtest_dev *dev = video_drvdata(file);
+	struct m2mtest_ctx *ctx = file2ctx(file);
+
+	dprintk(dev, "Releasing instance %p\n", ctx);
+
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	v4l2_ctrl_handler_free(&ctx->hdl);
+	mutex_lock(&dev->dev_mutex);
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+	mutex_unlock(&dev->dev_mutex);
+	kfree(ctx);
+
+	atomic_dec(&dev->num_inst);
+
+	return 0;
+}
+
+static unsigned int m2mtest_poll(struct file *file,
+				 struct poll_table_struct *wait)
+{
+	struct m2mtest_ctx *ctx = file2ctx(file);
+
+	return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+}
+
+static int m2mtest_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct m2mtest_dev *dev = video_drvdata(file);
+	struct m2mtest_ctx *ctx = file2ctx(file);
+	int res;
+
+	if (mutex_lock_interruptible(&dev->dev_mutex))
+		return -ERESTARTSYS;
+	res = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+	mutex_unlock(&dev->dev_mutex);
+	return res;
+}
+
+static const struct v4l2_file_operations m2mtest_fops = {
+	.owner		= THIS_MODULE,
+	.open		= m2mtest_open,
+	.release	= m2mtest_release,
+	.poll		= m2mtest_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= m2mtest_mmap,
+};
+
+static struct video_device m2mtest_videodev = {
+	.name		= MEM2MEM_NAME,
+	.fops		= &m2mtest_fops,
+	.ioctl_ops	= &m2mtest_ioctl_ops,
+	.minor		= -1,
+	.release	= video_device_release,
+};
+
+static struct v4l2_m2m_ops m2m_ops = {
+	.device_run	= device_run,
+	.job_ready	= job_ready,
+	.job_abort	= job_abort,
+	.lock		= m2mtest_lock,
+	.unlock		= m2mtest_unlock,
+};
+
+static int m2mtest_probe(struct platform_device *pdev)
+{
+	struct m2mtest_dev *dev;
+	struct video_device *vfd;
+	int ret;
+
+	dev = kzalloc(sizeof *dev, GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	spin_lock_init(&dev->irqlock);
+
+	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+	if (ret)
+		goto free_dev;
+
+	atomic_set(&dev->num_inst, 0);
+	mutex_init(&dev->dev_mutex);
+
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+		ret = -ENOMEM;
+		goto unreg_dev;
+	}
+
+	*vfd = m2mtest_videodev;
+	vfd->lock = &dev->dev_mutex;
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+		goto rel_vdev;
+	}
+
+	video_set_drvdata(vfd, dev);
+	snprintf(vfd->name, sizeof(vfd->name), "%s", m2mtest_videodev.name);
+	dev->vfd = vfd;
+	v4l2_info(&dev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME
+			"Device registered as /dev/video%d\n", vfd->num);
+
+	setup_timer(&dev->timer, device_isr, (long)dev);
+	platform_set_drvdata(pdev, dev);
+
+	dev->m2m_dev = v4l2_m2m_init(&m2m_ops);
+	if (IS_ERR(dev->m2m_dev)) {
+		v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
+		ret = PTR_ERR(dev->m2m_dev);
+		goto err_m2m;
+	}
+
+	return 0;
+
+	v4l2_m2m_release(dev->m2m_dev);
+err_m2m:
+	video_unregister_device(dev->vfd);
+rel_vdev:
+	video_device_release(vfd);
+unreg_dev:
+	v4l2_device_unregister(&dev->v4l2_dev);
+free_dev:
+	kfree(dev);
+
+	return ret;
+}
+
+static int m2mtest_remove(struct platform_device *pdev)
+{
+	struct m2mtest_dev *dev =
+		(struct m2mtest_dev *)platform_get_drvdata(pdev);
+
+	v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME);
+	v4l2_m2m_release(dev->m2m_dev);
+	del_timer_sync(&dev->timer);
+	video_unregister_device(dev->vfd);
+	v4l2_device_unregister(&dev->v4l2_dev);
+	kfree(dev);
+
+	return 0;
+}
+
+static struct platform_driver m2mtest_pdrv = {
+	.probe		= m2mtest_probe,
+	.remove		= m2mtest_remove,
+	.driver		= {
+		.name	= MEM2MEM_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static void __exit m2mtest_exit(void)
+{
+	platform_driver_unregister(&m2mtest_pdrv);
+	platform_device_unregister(&m2mtest_pdev);
+}
+
+static int __init m2mtest_init(void)
+{
+	int ret;
+
+	ret = platform_device_register(&m2mtest_pdev);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&m2mtest_pdrv);
+	if (ret)
+		platform_device_unregister(&m2mtest_pdev);
+
+	return 0;
+}
+
+module_init(m2mtest_init);
+module_exit(m2mtest_exit);
+
diff --git a/drivers/media/platform/mx1_camera.c b/drivers/media/platform/mx1_camera.c
new file mode 100644
index 0000000..560a65a
--- /dev/null
+++ b/drivers/media/platform/mx1_camera.c
@@ -0,0 +1,889 @@
+/*
+ * V4L2 Driver for i.MXL/i.MXL camera (CSI) host
+ *
+ * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ * Copyright (C) 2009, Darius Augulis <augulis.darius@gmail.com>
+ *
+ * Based on PXA SoC camera driver
+ * Copyright (C) 2006, Sascha Hauer, Pengutronix
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/videodev2.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf-dma-contig.h>
+#include <media/soc_mediabus.h>
+
+#include <asm/dma.h>
+#include <asm/fiq.h>
+#include <mach/dma-mx1-mx2.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/mx1_camera.h>
+
+/*
+ * CSI registers
+ */
+#define CSICR1		0x00			/* CSI Control Register 1 */
+#define CSISR		0x08			/* CSI Status Register */
+#define CSIRXR		0x10			/* CSI RxFIFO Register */
+
+#define CSICR1_RXFF_LEVEL(x)	(((x) & 0x3) << 19)
+#define CSICR1_SOF_POL		(1 << 17)
+#define CSICR1_SOF_INTEN	(1 << 16)
+#define CSICR1_MCLKDIV(x)	(((x) & 0xf) << 12)
+#define CSICR1_MCLKEN		(1 << 9)
+#define CSICR1_FCC		(1 << 8)
+#define CSICR1_BIG_ENDIAN	(1 << 7)
+#define CSICR1_CLR_RXFIFO	(1 << 5)
+#define CSICR1_GCLK_MODE	(1 << 4)
+#define CSICR1_DATA_POL		(1 << 2)
+#define CSICR1_REDGE		(1 << 1)
+#define CSICR1_EN		(1 << 0)
+
+#define CSISR_SFF_OR_INT	(1 << 25)
+#define CSISR_RFF_OR_INT	(1 << 24)
+#define CSISR_STATFF_INT	(1 << 21)
+#define CSISR_RXFF_INT		(1 << 18)
+#define CSISR_SOF_INT		(1 << 16)
+#define CSISR_DRDY		(1 << 0)
+
+#define DRIVER_VERSION "0.0.2"
+#define DRIVER_NAME "mx1-camera"
+
+#define CSI_IRQ_MASK	(CSISR_SFF_OR_INT | CSISR_RFF_OR_INT | \
+			CSISR_STATFF_INT | CSISR_RXFF_INT | CSISR_SOF_INT)
+
+#define CSI_BUS_FLAGS	(V4L2_MBUS_MASTER | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
+			V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | \
+			V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \
+			V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_LOW)
+
+#define MAX_VIDEO_MEM 16	/* Video memory limit in megabytes */
+
+/*
+ * Structures
+ */
+
+/* buffer for one video frame */
+struct mx1_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer		vb;
+	enum v4l2_mbus_pixelcode	code;
+	int				inwork;
+};
+
+/*
+ * i.MX1/i.MXL is only supposed to handle one camera on its Camera Sensor
+ * Interface. If anyone ever builds hardware to enable more than
+ * one camera, they will have to modify this driver too
+ */
+struct mx1_camera_dev {
+	struct soc_camera_host		soc_host;
+	struct soc_camera_device	*icd;
+	struct mx1_camera_pdata		*pdata;
+	struct mx1_buffer		*active;
+	struct resource			*res;
+	struct clk			*clk;
+	struct list_head		capture;
+
+	void __iomem			*base;
+	int				dma_chan;
+	unsigned int			irq;
+	unsigned long			mclk;
+
+	spinlock_t			lock;
+};
+
+/*
+ *  Videobuf operations
+ */
+static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
+			      unsigned int *size)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+
+	*size = icd->sizeimage;
+
+	if (!*count)
+		*count = 32;
+
+	if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
+		*count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
+
+	dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size);
+
+	return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct mx1_buffer *buf)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct videobuf_buffer *vb = &buf->vb;
+
+	BUG_ON(in_interrupt());
+
+	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+		vb, vb->baddr, vb->bsize);
+
+	/*
+	 * This waits until this buffer is out of danger, i.e., until it is no
+	 * longer in STATE_QUEUED or STATE_ACTIVE
+	 */
+	videobuf_waiton(vq, vb, 0, 0);
+	videobuf_dma_contig_free(vq, vb);
+
+	vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int mx1_videobuf_prepare(struct videobuf_queue *vq,
+		struct videobuf_buffer *vb, enum v4l2_field field)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
+	int ret;
+
+	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+		vb, vb->baddr, vb->bsize);
+
+	/* Added list head initialization on alloc */
+	WARN_ON(!list_empty(&vb->queue));
+
+	BUG_ON(NULL == icd->current_fmt);
+
+	/*
+	 * I think, in buf_prepare you only have to protect global data,
+	 * the actual buffer is yours
+	 */
+	buf->inwork = 1;
+
+	if (buf->code	!= icd->current_fmt->code ||
+	    vb->width	!= icd->user_width ||
+	    vb->height	!= icd->user_height ||
+	    vb->field	!= field) {
+		buf->code	= icd->current_fmt->code;
+		vb->width	= icd->user_width;
+		vb->height	= icd->user_height;
+		vb->field	= field;
+		vb->state	= VIDEOBUF_NEEDS_INIT;
+	}
+
+	vb->size = icd->sizeimage;
+	if (0 != vb->baddr && vb->bsize < vb->size) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (vb->state == VIDEOBUF_NEEDS_INIT) {
+		ret = videobuf_iolock(vq, vb, NULL);
+		if (ret)
+			goto fail;
+
+		vb->state = VIDEOBUF_PREPARED;
+	}
+
+	buf->inwork = 0;
+
+	return 0;
+
+fail:
+	free_buffer(vq, buf);
+out:
+	buf->inwork = 0;
+	return ret;
+}
+
+static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev)
+{
+	struct videobuf_buffer *vbuf = &pcdev->active->vb;
+	struct device *dev = pcdev->icd->parent;
+	int ret;
+
+	if (unlikely(!pcdev->active)) {
+		dev_err(dev, "DMA End IRQ with no active buffer\n");
+		return -EFAULT;
+	}
+
+	/* setup sg list for future DMA */
+	ret = imx_dma_setup_single(pcdev->dma_chan,
+		videobuf_to_dma_contig(vbuf),
+		vbuf->size, pcdev->res->start +
+		CSIRXR, DMA_MODE_READ);
+	if (unlikely(ret))
+		dev_err(dev, "Failed to setup DMA sg list\n");
+
+	return ret;
+}
+
+/* Called under spinlock_irqsave(&pcdev->lock, ...) */
+static void mx1_videobuf_queue(struct videobuf_queue *vq,
+						struct videobuf_buffer *vb)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx1_camera_dev *pcdev = ici->priv;
+	struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
+
+	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+		vb, vb->baddr, vb->bsize);
+
+	list_add_tail(&vb->queue, &pcdev->capture);
+
+	vb->state = VIDEOBUF_ACTIVE;
+
+	if (!pcdev->active) {
+		pcdev->active = buf;
+
+		/* setup sg list for future DMA */
+		if (!mx1_camera_setup_dma(pcdev)) {
+			unsigned int temp;
+			/* enable SOF irq */
+			temp = __raw_readl(pcdev->base + CSICR1) |
+							CSICR1_SOF_INTEN;
+			__raw_writel(temp, pcdev->base + CSICR1);
+		}
+	}
+}
+
+static void mx1_videobuf_release(struct videobuf_queue *vq,
+				 struct videobuf_buffer *vb)
+{
+	struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
+#ifdef DEBUG
+	struct soc_camera_device *icd = vq->priv_data;
+	struct device *dev = icd->parent;
+
+	dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+		vb, vb->baddr, vb->bsize);
+
+	switch (vb->state) {
+	case VIDEOBUF_ACTIVE:
+		dev_dbg(dev, "%s (active)\n", __func__);
+		break;
+	case VIDEOBUF_QUEUED:
+		dev_dbg(dev, "%s (queued)\n", __func__);
+		break;
+	case VIDEOBUF_PREPARED:
+		dev_dbg(dev, "%s (prepared)\n", __func__);
+		break;
+	default:
+		dev_dbg(dev, "%s (unknown)\n", __func__);
+		break;
+	}
+#endif
+
+	free_buffer(vq, buf);
+}
+
+static void mx1_camera_wakeup(struct mx1_camera_dev *pcdev,
+			      struct videobuf_buffer *vb,
+			      struct mx1_buffer *buf)
+{
+	/* _init is used to debug races, see comment in mx1_camera_reqbufs() */
+	list_del_init(&vb->queue);
+	vb->state = VIDEOBUF_DONE;
+	do_gettimeofday(&vb->ts);
+	vb->field_count++;
+	wake_up(&vb->done);
+
+	if (list_empty(&pcdev->capture)) {
+		pcdev->active = NULL;
+		return;
+	}
+
+	pcdev->active = list_entry(pcdev->capture.next,
+				   struct mx1_buffer, vb.queue);
+
+	/* setup sg list for future DMA */
+	if (likely(!mx1_camera_setup_dma(pcdev))) {
+		unsigned int temp;
+
+		/* enable SOF irq */
+		temp = __raw_readl(pcdev->base + CSICR1) | CSICR1_SOF_INTEN;
+		__raw_writel(temp, pcdev->base + CSICR1);
+	}
+}
+
+static void mx1_camera_dma_irq(int channel, void *data)
+{
+	struct mx1_camera_dev *pcdev = data;
+	struct device *dev = pcdev->icd->parent;
+	struct mx1_buffer *buf;
+	struct videobuf_buffer *vb;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pcdev->lock, flags);
+
+	imx_dma_disable(channel);
+
+	if (unlikely(!pcdev->active)) {
+		dev_err(dev, "DMA End IRQ with no active buffer\n");
+		goto out;
+	}
+
+	vb = &pcdev->active->vb;
+	buf = container_of(vb, struct mx1_buffer, vb);
+	WARN_ON(buf->inwork || list_empty(&vb->queue));
+	dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+		vb, vb->baddr, vb->bsize);
+
+	mx1_camera_wakeup(pcdev, vb, buf);
+out:
+	spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static struct videobuf_queue_ops mx1_videobuf_ops = {
+	.buf_setup	= mx1_videobuf_setup,
+	.buf_prepare	= mx1_videobuf_prepare,
+	.buf_queue	= mx1_videobuf_queue,
+	.buf_release	= mx1_videobuf_release,
+};
+
+static void mx1_camera_init_videobuf(struct videobuf_queue *q,
+				     struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx1_camera_dev *pcdev = ici->priv;
+
+	videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, icd->parent,
+				&pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+				V4L2_FIELD_NONE,
+				sizeof(struct mx1_buffer), icd, &icd->video_lock);
+}
+
+static int mclk_get_divisor(struct mx1_camera_dev *pcdev)
+{
+	unsigned int mclk = pcdev->mclk;
+	unsigned long div;
+	unsigned long lcdclk;
+
+	lcdclk = clk_get_rate(pcdev->clk);
+
+	/*
+	 * We verify platform_mclk_10khz != 0, so if anyone breaks it, here
+	 * they get a nice Oops
+	 */
+	div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1;
+
+	dev_dbg(pcdev->icd->parent,
+		"System clock %lukHz, target freq %dkHz, divisor %lu\n",
+		lcdclk / 1000, mclk / 1000, div);
+
+	return div;
+}
+
+static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
+{
+	unsigned int csicr1 = CSICR1_EN;
+
+	dev_dbg(pcdev->icd->parent, "Activate device\n");
+
+	clk_prepare_enable(pcdev->clk);
+
+	/* enable CSI before doing anything else */
+	__raw_writel(csicr1, pcdev->base + CSICR1);
+
+	csicr1 |= CSICR1_MCLKEN | CSICR1_FCC | CSICR1_GCLK_MODE;
+	csicr1 |= CSICR1_MCLKDIV(mclk_get_divisor(pcdev));
+	csicr1 |= CSICR1_RXFF_LEVEL(2); /* 16 words */
+
+	__raw_writel(csicr1, pcdev->base + CSICR1);
+}
+
+static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev)
+{
+	dev_dbg(pcdev->icd->parent, "Deactivate device\n");
+
+	/* Disable all CSI interface */
+	__raw_writel(0x00, pcdev->base + CSICR1);
+
+	clk_disable_unprepare(pcdev->clk);
+}
+
+/*
+ * The following two functions absolutely depend on the fact, that
+ * there can be only one camera on i.MX1/i.MXL camera sensor interface
+ */
+static int mx1_camera_add_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx1_camera_dev *pcdev = ici->priv;
+
+	if (pcdev->icd)
+		return -EBUSY;
+
+	dev_info(icd->parent, "MX1 Camera driver attached to camera %d\n",
+		 icd->devnum);
+
+	mx1_camera_activate(pcdev);
+
+	pcdev->icd = icd;
+
+	return 0;
+}
+
+static void mx1_camera_remove_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx1_camera_dev *pcdev = ici->priv;
+	unsigned int csicr1;
+
+	BUG_ON(icd != pcdev->icd);
+
+	/* disable interrupts */
+	csicr1 = __raw_readl(pcdev->base + CSICR1) & ~CSI_IRQ_MASK;
+	__raw_writel(csicr1, pcdev->base + CSICR1);
+
+	/* Stop DMA engine */
+	imx_dma_disable(pcdev->dma_chan);
+
+	dev_info(icd->parent, "MX1 Camera driver detached from camera %d\n",
+		 icd->devnum);
+
+	mx1_camera_deactivate(pcdev);
+
+	pcdev->icd = NULL;
+}
+
+static int mx1_camera_set_crop(struct soc_camera_device *icd,
+			       struct v4l2_crop *a)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+
+	return v4l2_subdev_call(sd, video, s_crop, a);
+}
+
+static int mx1_camera_set_bus_param(struct soc_camera_device *icd)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx1_camera_dev *pcdev = ici->priv;
+	struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+	unsigned long common_flags;
+	unsigned int csicr1;
+	int ret;
+
+	/* MX1 supports only 8bit buswidth */
+	ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
+	if (!ret) {
+		common_flags = soc_mbus_config_compatible(&cfg, CSI_BUS_FLAGS);
+		if (!common_flags) {
+			dev_warn(icd->parent,
+				 "Flags incompatible: camera 0x%x, host 0x%x\n",
+				 cfg.flags, CSI_BUS_FLAGS);
+			return -EINVAL;
+		}
+	} else if (ret != -ENOIOCTLCMD) {
+		return ret;
+	} else {
+		common_flags = CSI_BUS_FLAGS;
+	}
+
+	/* Make choises, based on platform choice */
+	if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
+		(common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
+			if (!pcdev->pdata ||
+			     pcdev->pdata->flags & MX1_CAMERA_VSYNC_HIGH)
+				common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
+			else
+				common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
+	}
+
+	if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
+		(common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
+			if (!pcdev->pdata ||
+			     pcdev->pdata->flags & MX1_CAMERA_PCLK_RISING)
+				common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
+			else
+				common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
+	}
+
+	if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) &&
+		(common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) {
+			if (!pcdev->pdata ||
+			     pcdev->pdata->flags & MX1_CAMERA_DATA_HIGH)
+				common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW;
+			else
+				common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH;
+	}
+
+	cfg.flags = common_flags;
+	ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
+	if (ret < 0 && ret != -ENOIOCTLCMD) {
+		dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n",
+			common_flags, ret);
+		return ret;
+	}
+
+	csicr1 = __raw_readl(pcdev->base + CSICR1);
+
+	if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+		csicr1 |= CSICR1_REDGE;
+	if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
+		csicr1 |= CSICR1_SOF_POL;
+	if (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)
+		csicr1 |= CSICR1_DATA_POL;
+
+	__raw_writel(csicr1, pcdev->base + CSICR1);
+
+	return 0;
+}
+
+static int mx1_camera_set_fmt(struct soc_camera_device *icd,
+			      struct v4l2_format *f)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	const struct soc_camera_format_xlate *xlate;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct v4l2_mbus_framefmt mf;
+	int ret, buswidth;
+
+	xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+	if (!xlate) {
+		dev_warn(icd->parent, "Format %x not found\n",
+			 pix->pixelformat);
+		return -EINVAL;
+	}
+
+	buswidth = xlate->host_fmt->bits_per_sample;
+	if (buswidth > 8) {
+		dev_warn(icd->parent,
+			 "bits-per-sample %d for format %x unsupported\n",
+			 buswidth, pix->pixelformat);
+		return -EINVAL;
+	}
+
+	mf.width	= pix->width;
+	mf.height	= pix->height;
+	mf.field	= pix->field;
+	mf.colorspace	= pix->colorspace;
+	mf.code		= xlate->code;
+
+	ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+	if (ret < 0)
+		return ret;
+
+	if (mf.code != xlate->code)
+		return -EINVAL;
+
+	pix->width		= mf.width;
+	pix->height		= mf.height;
+	pix->field		= mf.field;
+	pix->colorspace		= mf.colorspace;
+	icd->current_fmt	= xlate;
+
+	return ret;
+}
+
+static int mx1_camera_try_fmt(struct soc_camera_device *icd,
+			      struct v4l2_format *f)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	const struct soc_camera_format_xlate *xlate;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct v4l2_mbus_framefmt mf;
+	int ret;
+	/* TODO: limit to mx1 hardware capabilities */
+
+	xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+	if (!xlate) {
+		dev_warn(icd->parent, "Format %x not found\n",
+			 pix->pixelformat);
+		return -EINVAL;
+	}
+
+	mf.width	= pix->width;
+	mf.height	= pix->height;
+	mf.field	= pix->field;
+	mf.colorspace	= pix->colorspace;
+	mf.code		= xlate->code;
+
+	/* limit to sensor capabilities */
+	ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+	if (ret < 0)
+		return ret;
+
+	pix->width	= mf.width;
+	pix->height	= mf.height;
+	pix->field	= mf.field;
+	pix->colorspace	= mf.colorspace;
+
+	return 0;
+}
+
+static int mx1_camera_reqbufs(struct soc_camera_device *icd,
+			      struct v4l2_requestbuffers *p)
+{
+	int i;
+
+	/*
+	 * This is for locking debugging only. I removed spinlocks and now I
+	 * check whether .prepare is ever called on a linked buffer, or whether
+	 * a dma IRQ can occur for an in-work or unlinked buffer. Until now
+	 * it hadn't triggered
+	 */
+	for (i = 0; i < p->count; i++) {
+		struct mx1_buffer *buf = container_of(icd->vb_vidq.bufs[i],
+						      struct mx1_buffer, vb);
+		buf->inwork = 0;
+		INIT_LIST_HEAD(&buf->vb.queue);
+	}
+
+	return 0;
+}
+
+static unsigned int mx1_camera_poll(struct file *file, poll_table *pt)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct mx1_buffer *buf;
+
+	buf = list_entry(icd->vb_vidq.stream.next, struct mx1_buffer,
+			 vb.stream);
+
+	poll_wait(file, &buf->vb.done, pt);
+
+	if (buf->vb.state == VIDEOBUF_DONE ||
+	    buf->vb.state == VIDEOBUF_ERROR)
+		return POLLIN | POLLRDNORM;
+
+	return 0;
+}
+
+static int mx1_camera_querycap(struct soc_camera_host *ici,
+			       struct v4l2_capability *cap)
+{
+	/* cap->name is set by the friendly caller:-> */
+	strlcpy(cap->card, "i.MX1/i.MXL Camera", sizeof(cap->card));
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+static struct soc_camera_host_ops mx1_soc_camera_host_ops = {
+	.owner		= THIS_MODULE,
+	.add		= mx1_camera_add_device,
+	.remove		= mx1_camera_remove_device,
+	.set_bus_param	= mx1_camera_set_bus_param,
+	.set_crop	= mx1_camera_set_crop,
+	.set_fmt	= mx1_camera_set_fmt,
+	.try_fmt	= mx1_camera_try_fmt,
+	.init_videobuf	= mx1_camera_init_videobuf,
+	.reqbufs	= mx1_camera_reqbufs,
+	.poll		= mx1_camera_poll,
+	.querycap	= mx1_camera_querycap,
+};
+
+static struct fiq_handler fh = {
+	.name		= "csi_sof"
+};
+
+static int __init mx1_camera_probe(struct platform_device *pdev)
+{
+	struct mx1_camera_dev *pcdev;
+	struct resource *res;
+	struct pt_regs regs;
+	struct clk *clk;
+	void __iomem *base;
+	unsigned int irq;
+	int err = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(pdev, 0);
+	if (!res || (int)irq <= 0) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	clk = clk_get(&pdev->dev, "csi_clk");
+	if (IS_ERR(clk)) {
+		err = PTR_ERR(clk);
+		goto exit;
+	}
+
+	pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);
+	if (!pcdev) {
+		dev_err(&pdev->dev, "Could not allocate pcdev\n");
+		err = -ENOMEM;
+		goto exit_put_clk;
+	}
+
+	pcdev->res = res;
+	pcdev->clk = clk;
+
+	pcdev->pdata = pdev->dev.platform_data;
+
+	if (pcdev->pdata)
+		pcdev->mclk = pcdev->pdata->mclk_10khz * 10000;
+
+	if (!pcdev->mclk) {
+		dev_warn(&pdev->dev,
+			 "mclk_10khz == 0! Please, fix your platform data. "
+			 "Using default 20MHz\n");
+		pcdev->mclk = 20000000;
+	}
+
+	INIT_LIST_HEAD(&pcdev->capture);
+	spin_lock_init(&pcdev->lock);
+
+	/*
+	 * Request the regions.
+	 */
+	if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) {
+		err = -EBUSY;
+		goto exit_kfree;
+	}
+
+	base = ioremap(res->start, resource_size(res));
+	if (!base) {
+		err = -ENOMEM;
+		goto exit_release;
+	}
+	pcdev->irq = irq;
+	pcdev->base = base;
+
+	/* request dma */
+	pcdev->dma_chan = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_HIGH);
+	if (pcdev->dma_chan < 0) {
+		dev_err(&pdev->dev, "Can't request DMA for MX1 CSI\n");
+		err = -EBUSY;
+		goto exit_iounmap;
+	}
+	dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chan);
+
+	imx_dma_setup_handlers(pcdev->dma_chan, mx1_camera_dma_irq, NULL,
+			       pcdev);
+
+	imx_dma_config_channel(pcdev->dma_chan, IMX_DMA_TYPE_FIFO,
+			       IMX_DMA_MEMSIZE_32, MX1_DMA_REQ_CSI_R, 0);
+	/* burst length : 16 words = 64 bytes */
+	imx_dma_config_burstlen(pcdev->dma_chan, 0);
+
+	/* request irq */
+	err = claim_fiq(&fh);
+	if (err) {
+		dev_err(&pdev->dev, "Camera interrupt register failed \n");
+		goto exit_free_dma;
+	}
+
+	set_fiq_handler(&mx1_camera_sof_fiq_start, &mx1_camera_sof_fiq_end -
+						   &mx1_camera_sof_fiq_start);
+
+	regs.ARM_r8 = (long)MX1_DMA_DIMR;
+	regs.ARM_r9 = (long)MX1_DMA_CCR(pcdev->dma_chan);
+	regs.ARM_r10 = (long)pcdev->base + CSICR1;
+	regs.ARM_fp = (long)pcdev->base + CSISR;
+	regs.ARM_sp = 1 << pcdev->dma_chan;
+	set_fiq_regs(&regs);
+
+	mxc_set_irq_fiq(irq, 1);
+	enable_fiq(irq);
+
+	pcdev->soc_host.drv_name	= DRIVER_NAME;
+	pcdev->soc_host.ops		= &mx1_soc_camera_host_ops;
+	pcdev->soc_host.priv		= pcdev;
+	pcdev->soc_host.v4l2_dev.dev	= &pdev->dev;
+	pcdev->soc_host.nr		= pdev->id;
+	err = soc_camera_host_register(&pcdev->soc_host);
+	if (err)
+		goto exit_free_irq;
+
+	dev_info(&pdev->dev, "MX1 Camera driver loaded\n");
+
+	return 0;
+
+exit_free_irq:
+	disable_fiq(irq);
+	mxc_set_irq_fiq(irq, 0);
+	release_fiq(&fh);
+exit_free_dma:
+	imx_dma_free(pcdev->dma_chan);
+exit_iounmap:
+	iounmap(base);
+exit_release:
+	release_mem_region(res->start, resource_size(res));
+exit_kfree:
+	kfree(pcdev);
+exit_put_clk:
+	clk_put(clk);
+exit:
+	return err;
+}
+
+static int __exit mx1_camera_remove(struct platform_device *pdev)
+{
+	struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+	struct mx1_camera_dev *pcdev = container_of(soc_host,
+					struct mx1_camera_dev, soc_host);
+	struct resource *res;
+
+	imx_dma_free(pcdev->dma_chan);
+	disable_fiq(pcdev->irq);
+	mxc_set_irq_fiq(pcdev->irq, 0);
+	release_fiq(&fh);
+
+	clk_put(pcdev->clk);
+
+	soc_camera_host_unregister(soc_host);
+
+	iounmap(pcdev->base);
+
+	res = pcdev->res;
+	release_mem_region(res->start, resource_size(res));
+
+	kfree(pcdev);
+
+	dev_info(&pdev->dev, "MX1 Camera driver unloaded\n");
+
+	return 0;
+}
+
+static struct platform_driver mx1_camera_driver = {
+	.driver 	= {
+		.name	= DRIVER_NAME,
+	},
+	.remove		= __exit_p(mx1_camera_remove),
+};
+
+static int __init mx1_camera_init(void)
+{
+	return platform_driver_probe(&mx1_camera_driver, mx1_camera_probe);
+}
+
+static void __exit mx1_camera_exit(void)
+{
+	return platform_driver_unregister(&mx1_camera_driver);
+}
+
+module_init(mx1_camera_init);
+module_exit(mx1_camera_exit);
+
+MODULE_DESCRIPTION("i.MX1/i.MXL SoC Camera Host driver");
+MODULE_AUTHOR("Paulius Zaleckas <paulius.zaleckas@teltonika.lt>");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/media/platform/mx2_camera.c b/drivers/media/platform/mx2_camera.c
new file mode 100644
index 0000000..256187f
--- /dev/null
+++ b/drivers/media/platform/mx2_camera.c
@@ -0,0 +1,1924 @@
+/*
+ * V4L2 Driver for i.MX27/i.MX25 camera host
+ *
+ * Copyright (C) 2008, Sascha Hauer, Pengutronix
+ * Copyright (C) 2010, Baruch Siach, Orex Computed Radiography
+ * Copyright (C) 2012, Javier Martin, Vista Silicon S.L.
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/gcd.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+
+#include <linux/videodev2.h>
+
+#include <mach/mx2_cam.h>
+#include <mach/hardware.h>
+
+#include <asm/dma.h>
+
+#define MX2_CAM_DRV_NAME "mx2-camera"
+#define MX2_CAM_VERSION "0.0.6"
+#define MX2_CAM_DRIVER_DESCRIPTION "i.MX2x_Camera"
+
+/* reset values */
+#define CSICR1_RESET_VAL	0x40000800
+#define CSICR2_RESET_VAL	0x0
+#define CSICR3_RESET_VAL	0x0
+
+/* csi control reg 1 */
+#define CSICR1_SWAP16_EN	(1 << 31)
+#define CSICR1_EXT_VSYNC	(1 << 30)
+#define CSICR1_EOF_INTEN	(1 << 29)
+#define CSICR1_PRP_IF_EN	(1 << 28)
+#define CSICR1_CCIR_MODE	(1 << 27)
+#define CSICR1_COF_INTEN	(1 << 26)
+#define CSICR1_SF_OR_INTEN	(1 << 25)
+#define CSICR1_RF_OR_INTEN	(1 << 24)
+#define CSICR1_STATFF_LEVEL	(3 << 22)
+#define CSICR1_STATFF_INTEN	(1 << 21)
+#define CSICR1_RXFF_LEVEL(l)	(((l) & 3) << 19)	/* MX27 */
+#define CSICR1_FB2_DMA_INTEN	(1 << 20)		/* MX25 */
+#define CSICR1_FB1_DMA_INTEN	(1 << 19)		/* MX25 */
+#define CSICR1_RXFF_INTEN	(1 << 18)
+#define CSICR1_SOF_POL		(1 << 17)
+#define CSICR1_SOF_INTEN	(1 << 16)
+#define CSICR1_MCLKDIV(d)	(((d) & 0xF) << 12)
+#define CSICR1_HSYNC_POL	(1 << 11)
+#define CSICR1_CCIR_EN		(1 << 10)
+#define CSICR1_MCLKEN		(1 << 9)
+#define CSICR1_FCC		(1 << 8)
+#define CSICR1_PACK_DIR		(1 << 7)
+#define CSICR1_CLR_STATFIFO	(1 << 6)
+#define CSICR1_CLR_RXFIFO	(1 << 5)
+#define CSICR1_GCLK_MODE	(1 << 4)
+#define CSICR1_INV_DATA		(1 << 3)
+#define CSICR1_INV_PCLK		(1 << 2)
+#define CSICR1_REDGE		(1 << 1)
+#define CSICR1_FMT_MASK		(CSICR1_PACK_DIR | CSICR1_SWAP16_EN)
+
+#define SHIFT_STATFF_LEVEL	22
+#define SHIFT_RXFF_LEVEL	19
+#define SHIFT_MCLKDIV		12
+
+/* control reg 3 */
+#define CSICR3_FRMCNT		(0xFFFF << 16)
+#define CSICR3_FRMCNT_RST	(1 << 15)
+#define CSICR3_DMA_REFLASH_RFF	(1 << 14)
+#define CSICR3_DMA_REFLASH_SFF	(1 << 13)
+#define CSICR3_DMA_REQ_EN_RFF	(1 << 12)
+#define CSICR3_DMA_REQ_EN_SFF	(1 << 11)
+#define CSICR3_RXFF_LEVEL(l)	(((l) & 7) << 4)	/* MX25 */
+#define CSICR3_CSI_SUP		(1 << 3)
+#define CSICR3_ZERO_PACK_EN	(1 << 2)
+#define CSICR3_ECC_INT_EN	(1 << 1)
+#define CSICR3_ECC_AUTO_EN	(1 << 0)
+
+#define SHIFT_FRMCNT		16
+
+/* csi status reg */
+#define CSISR_SFF_OR_INT	(1 << 25)
+#define CSISR_RFF_OR_INT	(1 << 24)
+#define CSISR_STATFF_INT	(1 << 21)
+#define CSISR_DMA_TSF_FB2_INT	(1 << 20)	/* MX25 */
+#define CSISR_DMA_TSF_FB1_INT	(1 << 19)	/* MX25 */
+#define CSISR_RXFF_INT		(1 << 18)
+#define CSISR_EOF_INT		(1 << 17)
+#define CSISR_SOF_INT		(1 << 16)
+#define CSISR_F2_INT		(1 << 15)
+#define CSISR_F1_INT		(1 << 14)
+#define CSISR_COF_INT		(1 << 13)
+#define CSISR_ECC_INT		(1 << 1)
+#define CSISR_DRDY		(1 << 0)
+
+#define CSICR1			0x00
+#define CSICR2			0x04
+#define CSISR			(cpu_is_mx27() ? 0x08 : 0x18)
+#define CSISTATFIFO		0x0c
+#define CSIRFIFO		0x10
+#define CSIRXCNT		0x14
+#define CSICR3			(cpu_is_mx27() ? 0x1C : 0x08)
+#define CSIDMASA_STATFIFO	0x20
+#define CSIDMATA_STATFIFO	0x24
+#define CSIDMASA_FB1		0x28
+#define CSIDMASA_FB2		0x2c
+#define CSIFBUF_PARA		0x30
+#define CSIIMAG_PARA		0x34
+
+/* EMMA PrP */
+#define PRP_CNTL			0x00
+#define PRP_INTR_CNTL			0x04
+#define PRP_INTRSTATUS			0x08
+#define PRP_SOURCE_Y_PTR		0x0c
+#define PRP_SOURCE_CB_PTR		0x10
+#define PRP_SOURCE_CR_PTR		0x14
+#define PRP_DEST_RGB1_PTR		0x18
+#define PRP_DEST_RGB2_PTR		0x1c
+#define PRP_DEST_Y_PTR			0x20
+#define PRP_DEST_CB_PTR			0x24
+#define PRP_DEST_CR_PTR			0x28
+#define PRP_SRC_FRAME_SIZE		0x2c
+#define PRP_DEST_CH1_LINE_STRIDE	0x30
+#define PRP_SRC_PIXEL_FORMAT_CNTL	0x34
+#define PRP_CH1_PIXEL_FORMAT_CNTL	0x38
+#define PRP_CH1_OUT_IMAGE_SIZE		0x3c
+#define PRP_CH2_OUT_IMAGE_SIZE		0x40
+#define PRP_SRC_LINE_STRIDE		0x44
+#define PRP_CSC_COEF_012		0x48
+#define PRP_CSC_COEF_345		0x4c
+#define PRP_CSC_COEF_678		0x50
+#define PRP_CH1_RZ_HORI_COEF1		0x54
+#define PRP_CH1_RZ_HORI_COEF2		0x58
+#define PRP_CH1_RZ_HORI_VALID		0x5c
+#define PRP_CH1_RZ_VERT_COEF1		0x60
+#define PRP_CH1_RZ_VERT_COEF2		0x64
+#define PRP_CH1_RZ_VERT_VALID		0x68
+#define PRP_CH2_RZ_HORI_COEF1		0x6c
+#define PRP_CH2_RZ_HORI_COEF2		0x70
+#define PRP_CH2_RZ_HORI_VALID		0x74
+#define PRP_CH2_RZ_VERT_COEF1		0x78
+#define PRP_CH2_RZ_VERT_COEF2		0x7c
+#define PRP_CH2_RZ_VERT_VALID		0x80
+
+#define PRP_CNTL_CH1EN		(1 << 0)
+#define PRP_CNTL_CH2EN		(1 << 1)
+#define PRP_CNTL_CSIEN		(1 << 2)
+#define PRP_CNTL_DATA_IN_YUV420	(0 << 3)
+#define PRP_CNTL_DATA_IN_YUV422	(1 << 3)
+#define PRP_CNTL_DATA_IN_RGB16	(2 << 3)
+#define PRP_CNTL_DATA_IN_RGB32	(3 << 3)
+#define PRP_CNTL_CH1_OUT_RGB8	(0 << 5)
+#define PRP_CNTL_CH1_OUT_RGB16	(1 << 5)
+#define PRP_CNTL_CH1_OUT_RGB32	(2 << 5)
+#define PRP_CNTL_CH1_OUT_YUV422	(3 << 5)
+#define PRP_CNTL_CH2_OUT_YUV420	(0 << 7)
+#define PRP_CNTL_CH2_OUT_YUV422 (1 << 7)
+#define PRP_CNTL_CH2_OUT_YUV444	(2 << 7)
+#define PRP_CNTL_CH1_LEN	(1 << 9)
+#define PRP_CNTL_CH2_LEN	(1 << 10)
+#define PRP_CNTL_SKIP_FRAME	(1 << 11)
+#define PRP_CNTL_SWRST		(1 << 12)
+#define PRP_CNTL_CLKEN		(1 << 13)
+#define PRP_CNTL_WEN		(1 << 14)
+#define PRP_CNTL_CH1BYP		(1 << 15)
+#define PRP_CNTL_IN_TSKIP(x)	((x) << 16)
+#define PRP_CNTL_CH1_TSKIP(x)	((x) << 19)
+#define PRP_CNTL_CH2_TSKIP(x)	((x) << 22)
+#define PRP_CNTL_INPUT_FIFO_LEVEL(x)	((x) << 25)
+#define PRP_CNTL_RZ_FIFO_LEVEL(x)	((x) << 27)
+#define PRP_CNTL_CH2B1EN	(1 << 29)
+#define PRP_CNTL_CH2B2EN	(1 << 30)
+#define PRP_CNTL_CH2FEN		(1 << 31)
+
+/* IRQ Enable and status register */
+#define PRP_INTR_RDERR		(1 << 0)
+#define PRP_INTR_CH1WERR	(1 << 1)
+#define PRP_INTR_CH2WERR	(1 << 2)
+#define PRP_INTR_CH1FC		(1 << 3)
+#define PRP_INTR_CH2FC		(1 << 5)
+#define PRP_INTR_LBOVF		(1 << 7)
+#define PRP_INTR_CH2OVF		(1 << 8)
+
+/* Resizing registers */
+#define PRP_RZ_VALID_TBL_LEN(x)	((x) << 24)
+#define PRP_RZ_VALID_BILINEAR	(1 << 31)
+
+#define MAX_VIDEO_MEM	16
+
+#define RESIZE_NUM_MIN	1
+#define RESIZE_NUM_MAX	20
+#define BC_COEF		3
+#define SZ_COEF		(1 << BC_COEF)
+
+#define RESIZE_DIR_H	0
+#define RESIZE_DIR_V	1
+
+#define RESIZE_ALGO_BILINEAR 0
+#define RESIZE_ALGO_AVERAGING 1
+
+struct mx2_prp_cfg {
+	int channel;
+	u32 in_fmt;
+	u32 out_fmt;
+	u32 src_pixel;
+	u32 ch1_pixel;
+	u32 irq_flags;
+	u32 csicr1;
+};
+
+/* prp resizing parameters */
+struct emma_prp_resize {
+	int		algo; /* type of algorithm used */
+	int		len; /* number of coefficients */
+	unsigned char	s[RESIZE_NUM_MAX]; /* table of coefficients */
+};
+
+/* prp configuration for a client-host fmt pair */
+struct mx2_fmt_cfg {
+	enum v4l2_mbus_pixelcode	in_fmt;
+	u32				out_fmt;
+	struct mx2_prp_cfg		cfg;
+};
+
+enum mx2_buffer_state {
+	MX2_STATE_QUEUED,
+	MX2_STATE_ACTIVE,
+	MX2_STATE_DONE,
+};
+
+struct mx2_buf_internal {
+	struct list_head	queue;
+	int			bufnum;
+	bool			discard;
+};
+
+/* buffer for one video frame */
+struct mx2_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct vb2_buffer		vb;
+	enum mx2_buffer_state		state;
+	struct mx2_buf_internal		internal;
+};
+
+struct mx2_camera_dev {
+	struct device		*dev;
+	struct soc_camera_host	soc_host;
+	struct soc_camera_device *icd;
+	struct clk		*clk_csi, *clk_emma_ahb, *clk_emma_ipg;
+
+	unsigned int		irq_csi, irq_emma;
+	void __iomem		*base_csi, *base_emma;
+	unsigned long		base_dma;
+
+	struct mx2_camera_platform_data *pdata;
+	struct resource		*res_csi, *res_emma;
+	unsigned long		platform_flags;
+
+	struct list_head	capture;
+	struct list_head	active_bufs;
+	struct list_head	discard;
+
+	spinlock_t		lock;
+
+	int			dma;
+	struct mx2_buffer	*active;
+	struct mx2_buffer	*fb1_active;
+	struct mx2_buffer	*fb2_active;
+
+	u32			csicr1;
+
+	struct mx2_buf_internal buf_discard[2];
+	void			*discard_buffer;
+	dma_addr_t		discard_buffer_dma;
+	size_t			discard_size;
+	struct mx2_fmt_cfg	*emma_prp;
+	struct emma_prp_resize	resizing[2];
+	unsigned int		s_width, s_height;
+	u32			frame_count;
+	struct vb2_alloc_ctx	*alloc_ctx;
+};
+
+static struct mx2_buffer *mx2_ibuf_to_buf(struct mx2_buf_internal *int_buf)
+{
+	return container_of(int_buf, struct mx2_buffer, internal);
+}
+
+static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
+	/*
+	 * This is a generic configuration which is valid for most
+	 * prp input-output format combinations.
+	 * We set the incomming and outgoing pixelformat to a
+	 * 16 Bit wide format and adjust the bytesperline
+	 * accordingly. With this configuration the inputdata
+	 * will not be changed by the emma and could be any type
+	 * of 16 Bit Pixelformat.
+	 */
+	{
+		.in_fmt		= 0,
+		.out_fmt	= 0,
+		.cfg		= {
+			.channel	= 1,
+			.in_fmt		= PRP_CNTL_DATA_IN_RGB16,
+			.out_fmt	= PRP_CNTL_CH1_OUT_RGB16,
+			.src_pixel	= 0x2ca00565, /* RGB565 */
+			.ch1_pixel	= 0x2ca00565, /* RGB565 */
+			.irq_flags	= PRP_INTR_RDERR | PRP_INTR_CH1WERR |
+						PRP_INTR_CH1FC | PRP_INTR_LBOVF,
+			.csicr1		= 0,
+		}
+	},
+	{
+		.in_fmt		= V4L2_MBUS_FMT_UYVY8_2X8,
+		.out_fmt	= V4L2_PIX_FMT_YUYV,
+		.cfg		= {
+			.channel	= 1,
+			.in_fmt		= PRP_CNTL_DATA_IN_YUV422,
+			.out_fmt	= PRP_CNTL_CH1_OUT_YUV422,
+			.src_pixel	= 0x22000888, /* YUV422 (YUYV) */
+			.ch1_pixel	= 0x62000888, /* YUV422 (YUYV) */
+			.irq_flags	= PRP_INTR_RDERR | PRP_INTR_CH1WERR |
+						PRP_INTR_CH1FC | PRP_INTR_LBOVF,
+			.csicr1		= CSICR1_SWAP16_EN,
+		}
+	},
+	{
+		.in_fmt		= V4L2_MBUS_FMT_YUYV8_2X8,
+		.out_fmt	= V4L2_PIX_FMT_YUYV,
+		.cfg		= {
+			.channel	= 1,
+			.in_fmt		= PRP_CNTL_DATA_IN_YUV422,
+			.out_fmt	= PRP_CNTL_CH1_OUT_YUV422,
+			.src_pixel	= 0x22000888, /* YUV422 (YUYV) */
+			.ch1_pixel	= 0x62000888, /* YUV422 (YUYV) */
+			.irq_flags	= PRP_INTR_RDERR | PRP_INTR_CH1WERR |
+						PRP_INTR_CH1FC | PRP_INTR_LBOVF,
+			.csicr1		= CSICR1_PACK_DIR,
+		}
+	},
+	{
+		.in_fmt		= V4L2_MBUS_FMT_YUYV8_2X8,
+		.out_fmt	= V4L2_PIX_FMT_YUV420,
+		.cfg		= {
+			.channel	= 2,
+			.in_fmt		= PRP_CNTL_DATA_IN_YUV422,
+			.out_fmt	= PRP_CNTL_CH2_OUT_YUV420,
+			.src_pixel	= 0x22000888, /* YUV422 (YUYV) */
+			.irq_flags	= PRP_INTR_RDERR | PRP_INTR_CH2WERR |
+					PRP_INTR_CH2FC | PRP_INTR_LBOVF |
+					PRP_INTR_CH2OVF,
+			.csicr1		= CSICR1_PACK_DIR,
+		}
+	},
+	{
+		.in_fmt		= V4L2_MBUS_FMT_UYVY8_2X8,
+		.out_fmt	= V4L2_PIX_FMT_YUV420,
+		.cfg		= {
+			.channel	= 2,
+			.in_fmt		= PRP_CNTL_DATA_IN_YUV422,
+			.out_fmt	= PRP_CNTL_CH2_OUT_YUV420,
+			.src_pixel	= 0x22000888, /* YUV422 (YUYV) */
+			.irq_flags	= PRP_INTR_RDERR | PRP_INTR_CH2WERR |
+					PRP_INTR_CH2FC | PRP_INTR_LBOVF |
+					PRP_INTR_CH2OVF,
+			.csicr1		= CSICR1_SWAP16_EN,
+		}
+	},
+};
+
+static struct mx2_fmt_cfg *mx27_emma_prp_get_format(
+					enum v4l2_mbus_pixelcode in_fmt,
+					u32 out_fmt)
+{
+	int i;
+
+	for (i = 1; i < ARRAY_SIZE(mx27_emma_prp_table); i++)
+		if ((mx27_emma_prp_table[i].in_fmt == in_fmt) &&
+				(mx27_emma_prp_table[i].out_fmt == out_fmt)) {
+			return &mx27_emma_prp_table[i];
+		}
+	/* If no match return the most generic configuration */
+	return &mx27_emma_prp_table[0];
+};
+
+static void mx27_update_emma_buf(struct mx2_camera_dev *pcdev,
+				 unsigned long phys, int bufnum)
+{
+	struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+
+	if (prp->cfg.channel == 1) {
+		writel(phys, pcdev->base_emma +
+				PRP_DEST_RGB1_PTR + 4 * bufnum);
+	} else {
+		writel(phys, pcdev->base_emma +
+			PRP_DEST_Y_PTR - 0x14 * bufnum);
+		if (prp->out_fmt == V4L2_PIX_FMT_YUV420) {
+			u32 imgsize = pcdev->icd->user_height *
+					pcdev->icd->user_width;
+
+			writel(phys + imgsize, pcdev->base_emma +
+				PRP_DEST_CB_PTR - 0x14 * bufnum);
+			writel(phys + ((5 * imgsize) / 4), pcdev->base_emma +
+				PRP_DEST_CR_PTR - 0x14 * bufnum);
+		}
+	}
+}
+
+static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev)
+{
+	unsigned long flags;
+
+	clk_disable_unprepare(pcdev->clk_csi);
+	writel(0, pcdev->base_csi + CSICR1);
+	if (cpu_is_mx27()) {
+		writel(0, pcdev->base_emma + PRP_CNTL);
+	} else if (cpu_is_mx25()) {
+		spin_lock_irqsave(&pcdev->lock, flags);
+		pcdev->fb1_active = NULL;
+		pcdev->fb2_active = NULL;
+		writel(0, pcdev->base_csi + CSIDMASA_FB1);
+		writel(0, pcdev->base_csi + CSIDMASA_FB2);
+		spin_unlock_irqrestore(&pcdev->lock, flags);
+	}
+}
+
+/*
+ * The following two functions absolutely depend on the fact, that
+ * there can be only one camera on mx2 camera sensor interface
+ */
+static int mx2_camera_add_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx2_camera_dev *pcdev = ici->priv;
+	int ret;
+	u32 csicr1;
+
+	if (pcdev->icd)
+		return -EBUSY;
+
+	ret = clk_prepare_enable(pcdev->clk_csi);
+	if (ret < 0)
+		return ret;
+
+	csicr1 = CSICR1_MCLKEN;
+
+	if (cpu_is_mx27()) {
+		csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC |
+			CSICR1_RXFF_LEVEL(0);
+	} else if (cpu_is_mx27())
+		csicr1 |= CSICR1_SOF_INTEN | CSICR1_RXFF_LEVEL(2);
+
+	pcdev->csicr1 = csicr1;
+	writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
+
+	pcdev->icd = icd;
+	pcdev->frame_count = 0;
+
+	dev_info(icd->parent, "Camera driver attached to camera %d\n",
+		 icd->devnum);
+
+	return 0;
+}
+
+static void mx2_camera_remove_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx2_camera_dev *pcdev = ici->priv;
+
+	BUG_ON(icd != pcdev->icd);
+
+	dev_info(icd->parent, "Camera driver detached from camera %d\n",
+		 icd->devnum);
+
+	mx2_camera_deactivate(pcdev);
+
+	pcdev->icd = NULL;
+}
+
+static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb,
+		int state)
+{
+	struct vb2_buffer *vb;
+	struct mx2_buffer *buf;
+	struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active :
+		&pcdev->fb2_active;
+	u32 fb_reg = fb == 1 ? CSIDMASA_FB1 : CSIDMASA_FB2;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pcdev->lock, flags);
+
+	if (*fb_active == NULL)
+		goto out;
+
+	vb = &(*fb_active)->vb;
+	dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+		vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
+
+	do_gettimeofday(&vb->v4l2_buf.timestamp);
+	vb->v4l2_buf.sequence++;
+	vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+
+	if (list_empty(&pcdev->capture)) {
+		buf = NULL;
+		writel(0, pcdev->base_csi + fb_reg);
+	} else {
+		buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+				internal.queue);
+		vb = &buf->vb;
+		list_del(&buf->internal.queue);
+		buf->state = MX2_STATE_ACTIVE;
+		writel(vb2_dma_contig_plane_dma_addr(vb, 0),
+		       pcdev->base_csi + fb_reg);
+	}
+
+	*fb_active = buf;
+
+out:
+	spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static irqreturn_t mx25_camera_irq(int irq_csi, void *data)
+{
+	struct mx2_camera_dev *pcdev = data;
+	u32 status = readl(pcdev->base_csi + CSISR);
+
+	if (status & CSISR_DMA_TSF_FB1_INT)
+		mx25_camera_frame_done(pcdev, 1, MX2_STATE_DONE);
+	else if (status & CSISR_DMA_TSF_FB2_INT)
+		mx25_camera_frame_done(pcdev, 2, MX2_STATE_DONE);
+
+	/* FIXME: handle CSISR_RFF_OR_INT */
+
+	writel(status, pcdev->base_csi + CSISR);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ *  Videobuf operations
+ */
+static int mx2_videobuf_setup(struct vb2_queue *vq,
+			const struct v4l2_format *fmt,
+			unsigned int *count, unsigned int *num_planes,
+			unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx2_camera_dev *pcdev = ici->priv;
+
+	dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]);
+
+	/* TODO: support for VIDIOC_CREATE_BUFS not ready */
+	if (fmt != NULL)
+		return -ENOTTY;
+
+	alloc_ctxs[0] = pcdev->alloc_ctx;
+
+	sizes[0] = icd->sizeimage;
+
+	if (0 == *count)
+		*count = 32;
+	if (!*num_planes &&
+	    sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024)
+		*count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0];
+
+	*num_planes = 1;
+
+	return 0;
+}
+
+static int mx2_videobuf_prepare(struct vb2_buffer *vb)
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+	int ret = 0;
+
+	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+		vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
+
+#ifdef DEBUG
+	/*
+	 * This can be useful if you want to see if we actually fill
+	 * the buffer with something
+	 */
+	memset((void *)vb2_plane_vaddr(vb, 0),
+	       0xaa, vb2_get_plane_payload(vb, 0));
+#endif
+
+	vb2_set_plane_payload(vb, 0, icd->sizeimage);
+	if (vb2_plane_vaddr(vb, 0) &&
+	    vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	return 0;
+
+out:
+	return ret;
+}
+
+static void mx2_videobuf_queue(struct vb2_buffer *vb)
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->parent);
+	struct mx2_camera_dev *pcdev = ici->priv;
+	struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
+	unsigned long flags;
+
+	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+		vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
+
+	spin_lock_irqsave(&pcdev->lock, flags);
+
+	buf->state = MX2_STATE_QUEUED;
+	list_add_tail(&buf->internal.queue, &pcdev->capture);
+
+	if (cpu_is_mx25()) {
+		u32 csicr3, dma_inten = 0;
+
+		if (pcdev->fb1_active == NULL) {
+			writel(vb2_dma_contig_plane_dma_addr(vb, 0),
+					pcdev->base_csi + CSIDMASA_FB1);
+			pcdev->fb1_active = buf;
+			dma_inten = CSICR1_FB1_DMA_INTEN;
+		} else if (pcdev->fb2_active == NULL) {
+			writel(vb2_dma_contig_plane_dma_addr(vb, 0),
+					pcdev->base_csi + CSIDMASA_FB2);
+			pcdev->fb2_active = buf;
+			dma_inten = CSICR1_FB2_DMA_INTEN;
+		}
+
+		if (dma_inten) {
+			list_del(&buf->internal.queue);
+			buf->state = MX2_STATE_ACTIVE;
+
+			csicr3 = readl(pcdev->base_csi + CSICR3);
+
+			/* Reflash DMA */
+			writel(csicr3 | CSICR3_DMA_REFLASH_RFF,
+					pcdev->base_csi + CSICR3);
+
+			/* clear & enable interrupts */
+			writel(dma_inten, pcdev->base_csi + CSISR);
+			pcdev->csicr1 |= dma_inten;
+			writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
+
+			/* enable DMA */
+			csicr3 |= CSICR3_DMA_REQ_EN_RFF | CSICR3_RXFF_LEVEL(1);
+			writel(csicr3, pcdev->base_csi + CSICR3);
+		}
+	}
+
+	spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static void mx2_videobuf_release(struct vb2_buffer *vb)
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx2_camera_dev *pcdev = ici->priv;
+	struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
+	unsigned long flags;
+
+#ifdef DEBUG
+	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+		vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
+
+	switch (buf->state) {
+	case MX2_STATE_ACTIVE:
+		dev_info(icd->parent, "%s (active)\n", __func__);
+		break;
+	case MX2_STATE_QUEUED:
+		dev_info(icd->parent, "%s (queued)\n", __func__);
+		break;
+	default:
+		dev_info(icd->parent, "%s (unknown) %d\n", __func__,
+				buf->state);
+		break;
+	}
+#endif
+
+	/*
+	 * Terminate only queued but inactive buffers. Active buffers are
+	 * released when they become inactive after videobuf_waiton().
+	 *
+	 * FIXME: implement forced termination of active buffers for mx27 and
+	 * mx27 eMMA, so that the user won't get stuck in an uninterruptible
+	 * state. This requires a specific handling for each of the these DMA
+	 * types.
+	 */
+
+	spin_lock_irqsave(&pcdev->lock, flags);
+	if (cpu_is_mx25() && buf->state == MX2_STATE_ACTIVE) {
+		if (pcdev->fb1_active == buf) {
+			pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN;
+			writel(0, pcdev->base_csi + CSIDMASA_FB1);
+			pcdev->fb1_active = NULL;
+		} else if (pcdev->fb2_active == buf) {
+			pcdev->csicr1 &= ~CSICR1_FB2_DMA_INTEN;
+			writel(0, pcdev->base_csi + CSIDMASA_FB2);
+			pcdev->fb2_active = NULL;
+		}
+		writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
+	}
+	spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
+		int bytesperline)
+{
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->parent);
+	struct mx2_camera_dev *pcdev = ici->priv;
+	struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+
+	writel((pcdev->s_width << 16) | pcdev->s_height,
+	       pcdev->base_emma + PRP_SRC_FRAME_SIZE);
+	writel(prp->cfg.src_pixel,
+	       pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
+	if (prp->cfg.channel == 1) {
+		writel((icd->user_width << 16) | icd->user_height,
+			pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE);
+		writel(bytesperline,
+			pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE);
+		writel(prp->cfg.ch1_pixel,
+			pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL);
+	} else { /* channel 2 */
+		writel((icd->user_width << 16) | icd->user_height,
+			pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE);
+	}
+
+	/* Enable interrupts */
+	writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL);
+}
+
+static void mx2_prp_resize_commit(struct mx2_camera_dev *pcdev)
+{
+	int dir;
+
+	for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) {
+		unsigned char *s = pcdev->resizing[dir].s;
+		int len = pcdev->resizing[dir].len;
+		unsigned int coeff[2] = {0, 0};
+		unsigned int valid  = 0;
+		int i;
+
+		if (len == 0)
+			continue;
+
+		for (i = RESIZE_NUM_MAX - 1; i >= 0; i--) {
+			int j;
+
+			j = i > 9 ? 1 : 0;
+			coeff[j] = (coeff[j] << BC_COEF) |
+					(s[i] & (SZ_COEF - 1));
+
+			if (i == 5 || i == 15)
+				coeff[j] <<= 1;
+
+			valid = (valid << 1) | (s[i] >> BC_COEF);
+		}
+
+		valid |= PRP_RZ_VALID_TBL_LEN(len);
+
+		if (pcdev->resizing[dir].algo == RESIZE_ALGO_BILINEAR)
+			valid |= PRP_RZ_VALID_BILINEAR;
+
+		if (pcdev->emma_prp->cfg.channel == 1) {
+			if (dir == RESIZE_DIR_H) {
+				writel(coeff[0], pcdev->base_emma +
+							PRP_CH1_RZ_HORI_COEF1);
+				writel(coeff[1], pcdev->base_emma +
+							PRP_CH1_RZ_HORI_COEF2);
+				writel(valid, pcdev->base_emma +
+							PRP_CH1_RZ_HORI_VALID);
+			} else {
+				writel(coeff[0], pcdev->base_emma +
+							PRP_CH1_RZ_VERT_COEF1);
+				writel(coeff[1], pcdev->base_emma +
+							PRP_CH1_RZ_VERT_COEF2);
+				writel(valid, pcdev->base_emma +
+							PRP_CH1_RZ_VERT_VALID);
+			}
+		} else {
+			if (dir == RESIZE_DIR_H) {
+				writel(coeff[0], pcdev->base_emma +
+							PRP_CH2_RZ_HORI_COEF1);
+				writel(coeff[1], pcdev->base_emma +
+							PRP_CH2_RZ_HORI_COEF2);
+				writel(valid, pcdev->base_emma +
+							PRP_CH2_RZ_HORI_VALID);
+			} else {
+				writel(coeff[0], pcdev->base_emma +
+							PRP_CH2_RZ_VERT_COEF1);
+				writel(coeff[1], pcdev->base_emma +
+							PRP_CH2_RZ_VERT_COEF2);
+				writel(valid, pcdev->base_emma +
+							PRP_CH2_RZ_VERT_VALID);
+			}
+		}
+	}
+}
+
+static int mx2_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(q);
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->parent);
+	struct mx2_camera_dev *pcdev = ici->priv;
+	struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+	struct vb2_buffer *vb;
+	struct mx2_buffer *buf;
+	unsigned long phys;
+	int bytesperline;
+
+	if (cpu_is_mx27()) {
+		unsigned long flags;
+		if (count < 2)
+			return -EINVAL;
+
+		spin_lock_irqsave(&pcdev->lock, flags);
+
+		buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+				       internal.queue);
+		buf->internal.bufnum = 0;
+		vb = &buf->vb;
+		buf->state = MX2_STATE_ACTIVE;
+
+		phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+		mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum);
+		list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
+
+		buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+				       internal.queue);
+		buf->internal.bufnum = 1;
+		vb = &buf->vb;
+		buf->state = MX2_STATE_ACTIVE;
+
+		phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+		mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum);
+		list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
+
+		bytesperline = soc_mbus_bytes_per_line(icd->user_width,
+				icd->current_fmt->host_fmt);
+		if (bytesperline < 0)
+			return bytesperline;
+
+		/*
+		 * I didn't manage to properly enable/disable the prp
+		 * on a per frame basis during running transfers,
+		 * thus we allocate a buffer here and use it to
+		 * discard frames when no buffer is available.
+		 * Feel free to work on this ;)
+		 */
+		pcdev->discard_size = icd->user_height * bytesperline;
+		pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev,
+				pcdev->discard_size, &pcdev->discard_buffer_dma,
+				GFP_KERNEL);
+		if (!pcdev->discard_buffer)
+			return -ENOMEM;
+
+		pcdev->buf_discard[0].discard = true;
+		list_add_tail(&pcdev->buf_discard[0].queue,
+				      &pcdev->discard);
+
+		pcdev->buf_discard[1].discard = true;
+		list_add_tail(&pcdev->buf_discard[1].queue,
+				      &pcdev->discard);
+
+		mx2_prp_resize_commit(pcdev);
+
+		mx27_camera_emma_buf_init(icd, bytesperline);
+
+		if (prp->cfg.channel == 1) {
+			writel(PRP_CNTL_CH1EN |
+				PRP_CNTL_CSIEN |
+				prp->cfg.in_fmt |
+				prp->cfg.out_fmt |
+				PRP_CNTL_CH1_LEN |
+				PRP_CNTL_CH1BYP |
+				PRP_CNTL_CH1_TSKIP(0) |
+				PRP_CNTL_IN_TSKIP(0),
+				pcdev->base_emma + PRP_CNTL);
+		} else {
+			writel(PRP_CNTL_CH2EN |
+				PRP_CNTL_CSIEN |
+				prp->cfg.in_fmt |
+				prp->cfg.out_fmt |
+				PRP_CNTL_CH2_LEN |
+				PRP_CNTL_CH2_TSKIP(0) |
+				PRP_CNTL_IN_TSKIP(0),
+				pcdev->base_emma + PRP_CNTL);
+		}
+		spin_unlock_irqrestore(&pcdev->lock, flags);
+	}
+
+	return 0;
+}
+
+static int mx2_stop_streaming(struct vb2_queue *q)
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(q);
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->parent);
+	struct mx2_camera_dev *pcdev = ici->priv;
+	struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+	unsigned long flags;
+	void *b;
+	u32 cntl;
+
+	if (cpu_is_mx27()) {
+		spin_lock_irqsave(&pcdev->lock, flags);
+
+		cntl = readl(pcdev->base_emma + PRP_CNTL);
+		if (prp->cfg.channel == 1) {
+			writel(cntl & ~PRP_CNTL_CH1EN,
+			       pcdev->base_emma + PRP_CNTL);
+		} else {
+			writel(cntl & ~PRP_CNTL_CH2EN,
+			       pcdev->base_emma + PRP_CNTL);
+		}
+		INIT_LIST_HEAD(&pcdev->capture);
+		INIT_LIST_HEAD(&pcdev->active_bufs);
+		INIT_LIST_HEAD(&pcdev->discard);
+
+		b = pcdev->discard_buffer;
+		pcdev->discard_buffer = NULL;
+
+		spin_unlock_irqrestore(&pcdev->lock, flags);
+
+		dma_free_coherent(ici->v4l2_dev.dev,
+			pcdev->discard_size, b, pcdev->discard_buffer_dma);
+	}
+
+	return 0;
+}
+
+static struct vb2_ops mx2_videobuf_ops = {
+	.queue_setup	 = mx2_videobuf_setup,
+	.buf_prepare	 = mx2_videobuf_prepare,
+	.buf_queue	 = mx2_videobuf_queue,
+	.buf_cleanup	 = mx2_videobuf_release,
+	.start_streaming = mx2_start_streaming,
+	.stop_streaming	 = mx2_stop_streaming,
+};
+
+static int mx2_camera_init_videobuf(struct vb2_queue *q,
+			      struct soc_camera_device *icd)
+{
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	q->io_modes = VB2_MMAP | VB2_USERPTR;
+	q->drv_priv = icd;
+	q->ops = &mx2_videobuf_ops;
+	q->mem_ops = &vb2_dma_contig_memops;
+	q->buf_struct_size = sizeof(struct mx2_buffer);
+
+	return vb2_queue_init(q);
+}
+
+#define MX2_BUS_FLAGS	(V4L2_MBUS_MASTER | \
+			V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
+			V4L2_MBUS_VSYNC_ACTIVE_LOW | \
+			V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
+			V4L2_MBUS_HSYNC_ACTIVE_LOW | \
+			V4L2_MBUS_PCLK_SAMPLE_RISING | \
+			V4L2_MBUS_PCLK_SAMPLE_FALLING | \
+			V4L2_MBUS_DATA_ACTIVE_HIGH | \
+			V4L2_MBUS_DATA_ACTIVE_LOW)
+
+static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev)
+{
+	u32 cntl;
+	int count = 0;
+
+	cntl = readl(pcdev->base_emma + PRP_CNTL);
+	writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
+	while (count++ < 100) {
+		if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST))
+			return 0;
+		barrier();
+		udelay(1);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx2_camera_dev *pcdev = ici->priv;
+	struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+	unsigned long common_flags;
+	int ret;
+	int bytesperline;
+	u32 csicr1 = pcdev->csicr1;
+
+	ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
+	if (!ret) {
+		common_flags = soc_mbus_config_compatible(&cfg, MX2_BUS_FLAGS);
+		if (!common_flags) {
+			dev_warn(icd->parent,
+				 "Flags incompatible: camera 0x%x, host 0x%x\n",
+				 cfg.flags, MX2_BUS_FLAGS);
+			return -EINVAL;
+		}
+	} else if (ret != -ENOIOCTLCMD) {
+		return ret;
+	} else {
+		common_flags = MX2_BUS_FLAGS;
+	}
+
+	if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
+	    (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
+		if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH)
+			common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
+		else
+			common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
+	}
+
+	if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
+	    (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
+		if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING)
+			common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
+		else
+			common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
+	}
+
+	cfg.flags = common_flags;
+	ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
+	if (ret < 0 && ret != -ENOIOCTLCMD) {
+		dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n",
+			common_flags, ret);
+		return ret;
+	}
+
+	csicr1 = (csicr1 & ~CSICR1_FMT_MASK) | pcdev->emma_prp->cfg.csicr1;
+
+	if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+		csicr1 |= CSICR1_REDGE;
+	if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
+		csicr1 |= CSICR1_SOF_POL;
+	if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
+		csicr1 |= CSICR1_HSYNC_POL;
+	if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC)
+		csicr1 |= CSICR1_EXT_VSYNC;
+	if (pcdev->platform_flags & MX2_CAMERA_CCIR)
+		csicr1 |= CSICR1_CCIR_EN;
+	if (pcdev->platform_flags & MX2_CAMERA_CCIR_INTERLACE)
+		csicr1 |= CSICR1_CCIR_MODE;
+	if (pcdev->platform_flags & MX2_CAMERA_GATED_CLOCK)
+		csicr1 |= CSICR1_GCLK_MODE;
+	if (pcdev->platform_flags & MX2_CAMERA_INV_DATA)
+		csicr1 |= CSICR1_INV_DATA;
+
+	pcdev->csicr1 = csicr1;
+
+	bytesperline = soc_mbus_bytes_per_line(icd->user_width,
+			icd->current_fmt->host_fmt);
+	if (bytesperline < 0)
+		return bytesperline;
+
+	if (cpu_is_mx27()) {
+		ret = mx27_camera_emma_prp_reset(pcdev);
+		if (ret)
+			return ret;
+	} else if (cpu_is_mx25()) {
+		writel((bytesperline * icd->user_height) >> 2,
+				pcdev->base_csi + CSIRXCNT);
+		writel((bytesperline << 16) | icd->user_height,
+				pcdev->base_csi + CSIIMAG_PARA);
+	}
+
+	writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
+
+	return 0;
+}
+
+static int mx2_camera_set_crop(struct soc_camera_device *icd,
+				struct v4l2_crop *a)
+{
+	struct v4l2_rect *rect = &a->c;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct v4l2_mbus_framefmt mf;
+	int ret;
+
+	soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096);
+	soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096);
+
+	ret = v4l2_subdev_call(sd, video, s_crop, a);
+	if (ret < 0)
+		return ret;
+
+	/* The capture device might have changed its output  */
+	ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(icd->parent, "Sensor cropped %dx%d\n",
+		mf.width, mf.height);
+
+	icd->user_width		= mf.width;
+	icd->user_height	= mf.height;
+
+	return ret;
+}
+
+static int mx2_camera_get_formats(struct soc_camera_device *icd,
+				  unsigned int idx,
+				  struct soc_camera_format_xlate *xlate)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	const struct soc_mbus_pixelfmt *fmt;
+	struct device *dev = icd->parent;
+	enum v4l2_mbus_pixelcode code;
+	int ret, formats = 0;
+
+	ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
+	if (ret < 0)
+		/* no more formats */
+		return 0;
+
+	fmt = soc_mbus_get_fmtdesc(code);
+	if (!fmt) {
+		dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
+		return 0;
+	}
+
+	if (code == V4L2_MBUS_FMT_YUYV8_2X8 ||
+	    code == V4L2_MBUS_FMT_UYVY8_2X8) {
+		formats++;
+		if (xlate) {
+			/*
+			 * CH2 can output YUV420 which is a standard format in
+			 * soc_mediabus.c
+			 */
+			xlate->host_fmt =
+				soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_1_5X8);
+			xlate->code	= code;
+			dev_dbg(dev, "Providing host format %s for sensor code %d\n",
+			       xlate->host_fmt->name, code);
+			xlate++;
+		}
+	}
+
+	if (code == V4L2_MBUS_FMT_UYVY8_2X8) {
+		formats++;
+		if (xlate) {
+			xlate->host_fmt =
+				soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_2X8);
+			xlate->code	= code;
+			dev_dbg(dev, "Providing host format %s for sensor code %d\n",
+				xlate->host_fmt->name, code);
+			xlate++;
+		}
+	}
+
+	/* Generic pass-trough */
+	formats++;
+	if (xlate) {
+		xlate->host_fmt = fmt;
+		xlate->code	= code;
+		xlate++;
+	}
+	return formats;
+}
+
+static int mx2_emmaprp_resize(struct mx2_camera_dev *pcdev,
+			      struct v4l2_mbus_framefmt *mf_in,
+			      struct v4l2_pix_format *pix_out, bool apply)
+{
+	int num, den;
+	unsigned long m;
+	int i, dir;
+
+	for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) {
+		struct emma_prp_resize tmprsz;
+		unsigned char *s = tmprsz.s;
+		int len = 0;
+		int in, out;
+
+		if (dir == RESIZE_DIR_H) {
+			in = mf_in->width;
+			out = pix_out->width;
+		} else {
+			in = mf_in->height;
+			out = pix_out->height;
+		}
+
+		if (in < out)
+			return -EINVAL;
+		else if (in == out)
+			continue;
+
+		/* Calculate ratio */
+		m = gcd(in, out);
+		num = in / m;
+		den = out / m;
+		if (num > RESIZE_NUM_MAX)
+			return -EINVAL;
+
+		if ((num >= 2 * den) && (den == 1) &&
+		    (num < 9) && (!(num & 0x01))) {
+			int sum = 0;
+			int j;
+
+			/* Average scaling for >= 2:1 ratios */
+			/* Support can be added for num >=9 and odd values */
+
+			tmprsz.algo = RESIZE_ALGO_AVERAGING;
+			len = num;
+
+			for (i = 0; i < (len / 2); i++)
+				s[i] = 8;
+
+			do {
+				for (i = 0; i < (len / 2); i++) {
+					s[i] = s[i] >> 1;
+					sum = 0;
+					for (j = 0; j < (len / 2); j++)
+						sum += s[j];
+					if (sum == 4)
+						break;
+				}
+			} while (sum != 4);
+
+			for (i = (len / 2); i < len; i++)
+				s[i] = s[len - i - 1];
+
+			s[len - 1] |= SZ_COEF;
+		} else {
+			/* bilinear scaling for < 2:1 ratios */
+			int v; /* overflow counter */
+			int coeff, nxt; /* table output */
+			int in_pos_inc = 2 * den;
+			int out_pos = num;
+			int out_pos_inc = 2 * num;
+			int init_carry = num - den;
+			int carry = init_carry;
+
+			tmprsz.algo = RESIZE_ALGO_BILINEAR;
+			v = den + in_pos_inc;
+			do {
+				coeff = v - out_pos;
+				out_pos += out_pos_inc;
+				carry += out_pos_inc;
+				for (nxt = 0; v < out_pos; nxt++) {
+					v += in_pos_inc;
+					carry -= in_pos_inc;
+				}
+
+				if (len > RESIZE_NUM_MAX)
+					return -EINVAL;
+
+				coeff = ((coeff << BC_COEF) +
+					(in_pos_inc >> 1)) / in_pos_inc;
+
+				if (coeff >= (SZ_COEF - 1))
+					coeff--;
+
+				coeff |= SZ_COEF;
+				s[len] = (unsigned char)coeff;
+				len++;
+
+				for (i = 1; i < nxt; i++) {
+					if (len >= RESIZE_NUM_MAX)
+						return -EINVAL;
+					s[len] = 0;
+					len++;
+				}
+			} while (carry != init_carry);
+		}
+		tmprsz.len = len;
+		if (dir == RESIZE_DIR_H)
+			mf_in->width = pix_out->width;
+		else
+			mf_in->height = pix_out->height;
+
+		if (apply)
+			memcpy(&pcdev->resizing[dir], &tmprsz, sizeof(tmprsz));
+	}
+	return 0;
+}
+
+static int mx2_camera_set_fmt(struct soc_camera_device *icd,
+			       struct v4l2_format *f)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx2_camera_dev *pcdev = ici->priv;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	const struct soc_camera_format_xlate *xlate;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct v4l2_mbus_framefmt mf;
+	int ret;
+
+	dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n",
+		__func__, pix->width, pix->height);
+
+	xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+	if (!xlate) {
+		dev_warn(icd->parent, "Format %x not found\n",
+				pix->pixelformat);
+		return -EINVAL;
+	}
+
+	mf.width	= pix->width;
+	mf.height	= pix->height;
+	mf.field	= pix->field;
+	mf.colorspace	= pix->colorspace;
+	mf.code		= xlate->code;
+
+	ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+	if (ret < 0 && ret != -ENOIOCTLCMD)
+		return ret;
+
+	/* Store width and height returned by the sensor for resizing */
+	pcdev->s_width = mf.width;
+	pcdev->s_height = mf.height;
+	dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n",
+		__func__, pcdev->s_width, pcdev->s_height);
+
+	pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code,
+						   xlate->host_fmt->fourcc);
+
+	memset(pcdev->resizing, 0, sizeof(pcdev->resizing));
+	if ((mf.width != pix->width || mf.height != pix->height) &&
+		pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) {
+		if (mx2_emmaprp_resize(pcdev, &mf, pix, true) < 0)
+			dev_dbg(icd->parent, "%s: can't resize\n", __func__);
+	}
+
+	if (mf.code != xlate->code)
+		return -EINVAL;
+
+	pix->width		= mf.width;
+	pix->height		= mf.height;
+	pix->field		= mf.field;
+	pix->colorspace		= mf.colorspace;
+	icd->current_fmt	= xlate;
+
+	dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n",
+		__func__, pix->width, pix->height);
+
+	return 0;
+}
+
+static int mx2_camera_try_fmt(struct soc_camera_device *icd,
+				  struct v4l2_format *f)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	const struct soc_camera_format_xlate *xlate;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct v4l2_mbus_framefmt mf;
+	__u32 pixfmt = pix->pixelformat;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx2_camera_dev *pcdev = ici->priv;
+	unsigned int width_limit;
+	int ret;
+
+	dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n",
+		__func__, pix->width, pix->height);
+
+	xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+	if (pixfmt && !xlate) {
+		dev_warn(icd->parent, "Format %x not found\n", pixfmt);
+		return -EINVAL;
+	}
+
+	/* FIXME: implement MX27 limits */
+
+	/* limit to MX25 hardware capabilities */
+	if (cpu_is_mx25()) {
+		if (xlate->host_fmt->bits_per_sample <= 8)
+			width_limit = 0xffff * 4;
+		else
+			width_limit = 0xffff * 2;
+		/* CSIIMAG_PARA limit */
+		if (pix->width > width_limit)
+			pix->width = width_limit;
+		if (pix->height > 0xffff)
+			pix->height = 0xffff;
+
+		pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
+				xlate->host_fmt);
+		if (pix->bytesperline < 0)
+			return pix->bytesperline;
+		pix->sizeimage = soc_mbus_image_size(xlate->host_fmt,
+						pix->bytesperline, pix->height);
+		/* Check against the CSIRXCNT limit */
+		if (pix->sizeimage > 4 * 0x3ffff) {
+			/* Adjust geometry, preserve aspect ratio */
+			unsigned int new_height = int_sqrt(div_u64(0x3ffffULL *
+					4 * pix->height, pix->bytesperline));
+			pix->width = new_height * pix->width / pix->height;
+			pix->height = new_height;
+			pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
+							xlate->host_fmt);
+			BUG_ON(pix->bytesperline < 0);
+			pix->sizeimage = soc_mbus_image_size(xlate->host_fmt,
+						pix->bytesperline, pix->height);
+		}
+	}
+
+	/* limit to sensor capabilities */
+	mf.width	= pix->width;
+	mf.height	= pix->height;
+	mf.field	= pix->field;
+	mf.colorspace	= pix->colorspace;
+	mf.code		= xlate->code;
+
+	ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n",
+		__func__, pcdev->s_width, pcdev->s_height);
+
+	/* If the sensor does not support image size try PrP resizing */
+	pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code,
+						   xlate->host_fmt->fourcc);
+
+	memset(pcdev->resizing, 0, sizeof(pcdev->resizing));
+	if ((mf.width != pix->width || mf.height != pix->height) &&
+		pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) {
+		if (mx2_emmaprp_resize(pcdev, &mf, pix, false) < 0)
+			dev_dbg(icd->parent, "%s: can't resize\n", __func__);
+	}
+
+	if (mf.field == V4L2_FIELD_ANY)
+		mf.field = V4L2_FIELD_NONE;
+	/*
+	 * Driver supports interlaced images provided they have
+	 * both fields so that they can be processed as if they
+	 * were progressive.
+	 */
+	if (mf.field != V4L2_FIELD_NONE && !V4L2_FIELD_HAS_BOTH(mf.field)) {
+		dev_err(icd->parent, "Field type %d unsupported.\n",
+				mf.field);
+		return -EINVAL;
+	}
+
+	pix->width	= mf.width;
+	pix->height	= mf.height;
+	pix->field	= mf.field;
+	pix->colorspace	= mf.colorspace;
+
+	dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n",
+		__func__, pix->width, pix->height);
+
+	return 0;
+}
+
+static int mx2_camera_querycap(struct soc_camera_host *ici,
+			       struct v4l2_capability *cap)
+{
+	/* cap->name is set by the friendly caller:-> */
+	strlcpy(cap->card, MX2_CAM_DRIVER_DESCRIPTION, sizeof(cap->card));
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+static unsigned int mx2_camera_poll(struct file *file, poll_table *pt)
+{
+	struct soc_camera_device *icd = file->private_data;
+
+	return vb2_poll(&icd->vb2_vidq, file, pt);
+}
+
+static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
+	.owner		= THIS_MODULE,
+	.add		= mx2_camera_add_device,
+	.remove		= mx2_camera_remove_device,
+	.set_fmt	= mx2_camera_set_fmt,
+	.set_crop	= mx2_camera_set_crop,
+	.get_formats	= mx2_camera_get_formats,
+	.try_fmt	= mx2_camera_try_fmt,
+	.init_videobuf2	= mx2_camera_init_videobuf,
+	.poll		= mx2_camera_poll,
+	.querycap	= mx2_camera_querycap,
+	.set_bus_param	= mx2_camera_set_bus_param,
+};
+
+static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
+		int bufnum, bool err)
+{
+#ifdef DEBUG
+	struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+#endif
+	struct mx2_buf_internal *ibuf;
+	struct mx2_buffer *buf;
+	struct vb2_buffer *vb;
+	unsigned long phys;
+
+	ibuf = list_first_entry(&pcdev->active_bufs, struct mx2_buf_internal,
+			       queue);
+
+	BUG_ON(ibuf->bufnum != bufnum);
+
+	if (ibuf->discard) {
+		/*
+		 * Discard buffer must not be returned to user space.
+		 * Just return it to the discard queue.
+		 */
+		list_move_tail(pcdev->active_bufs.next, &pcdev->discard);
+	} else {
+		buf = mx2_ibuf_to_buf(ibuf);
+
+		vb = &buf->vb;
+#ifdef DEBUG
+		phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+		if (prp->cfg.channel == 1) {
+			if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR +
+				4 * bufnum) != phys) {
+				dev_err(pcdev->dev, "%lx != %x\n", phys,
+					readl(pcdev->base_emma +
+					PRP_DEST_RGB1_PTR + 4 * bufnum));
+			}
+		} else {
+			if (readl(pcdev->base_emma + PRP_DEST_Y_PTR -
+				0x14 * bufnum) != phys) {
+				dev_err(pcdev->dev, "%lx != %x\n", phys,
+					readl(pcdev->base_emma +
+					PRP_DEST_Y_PTR - 0x14 * bufnum));
+			}
+		}
+#endif
+		dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb,
+				vb2_plane_vaddr(vb, 0),
+				vb2_get_plane_payload(vb, 0));
+
+		list_del_init(&buf->internal.queue);
+		do_gettimeofday(&vb->v4l2_buf.timestamp);
+		vb->v4l2_buf.sequence = pcdev->frame_count;
+		if (err)
+			vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+		else
+			vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+	}
+
+	pcdev->frame_count++;
+
+	if (list_empty(&pcdev->capture)) {
+		if (list_empty(&pcdev->discard)) {
+			dev_warn(pcdev->dev, "%s: trying to access empty discard list\n",
+				 __func__);
+			return;
+		}
+
+		ibuf = list_first_entry(&pcdev->discard,
+					struct mx2_buf_internal, queue);
+		ibuf->bufnum = bufnum;
+
+		list_move_tail(pcdev->discard.next, &pcdev->active_bufs);
+		mx27_update_emma_buf(pcdev, pcdev->discard_buffer_dma, bufnum);
+		return;
+	}
+
+	buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+			       internal.queue);
+
+	buf->internal.bufnum = bufnum;
+
+	list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
+
+	vb = &buf->vb;
+	buf->state = MX2_STATE_ACTIVE;
+
+	phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+	mx27_update_emma_buf(pcdev, phys, bufnum);
+}
+
+static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data)
+{
+	struct mx2_camera_dev *pcdev = data;
+	unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS);
+	struct mx2_buf_internal *ibuf;
+
+	spin_lock(&pcdev->lock);
+
+	if (list_empty(&pcdev->active_bufs)) {
+		dev_warn(pcdev->dev, "%s: called while active list is empty\n",
+			__func__);
+
+		if (!status) {
+			spin_unlock(&pcdev->lock);
+			return IRQ_NONE;
+		}
+	}
+
+	if (status & (1 << 7)) { /* overflow */
+		u32 cntl = readl(pcdev->base_emma + PRP_CNTL);
+		writel(cntl & ~(PRP_CNTL_CH1EN | PRP_CNTL_CH2EN),
+		       pcdev->base_emma + PRP_CNTL);
+		writel(cntl, pcdev->base_emma + PRP_CNTL);
+
+		ibuf = list_first_entry(&pcdev->active_bufs,
+					struct mx2_buf_internal, queue);
+		mx27_camera_frame_done_emma(pcdev,
+					ibuf->bufnum, true);
+
+		status &= ~(1 << 7);
+	} else if (((status & (3 << 5)) == (3 << 5)) ||
+		((status & (3 << 3)) == (3 << 3))) {
+		/*
+		 * Both buffers have triggered, process the one we're expecting
+		 * to first
+		 */
+		ibuf = list_first_entry(&pcdev->active_bufs,
+					struct mx2_buf_internal, queue);
+		mx27_camera_frame_done_emma(pcdev, ibuf->bufnum, false);
+		status &= ~(1 << (6 - ibuf->bufnum)); /* mark processed */
+	} else if ((status & (1 << 6)) || (status & (1 << 4))) {
+		mx27_camera_frame_done_emma(pcdev, 0, false);
+	} else if ((status & (1 << 5)) || (status & (1 << 3))) {
+		mx27_camera_frame_done_emma(pcdev, 1, false);
+	}
+
+	spin_unlock(&pcdev->lock);
+	writel(status, pcdev->base_emma + PRP_INTRSTATUS);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit mx27_camera_emma_init(struct mx2_camera_dev *pcdev)
+{
+	struct resource *res_emma = pcdev->res_emma;
+	int err = 0;
+
+	if (!request_mem_region(res_emma->start, resource_size(res_emma),
+				MX2_CAM_DRV_NAME)) {
+		err = -EBUSY;
+		goto out;
+	}
+
+	pcdev->base_emma = ioremap(res_emma->start, resource_size(res_emma));
+	if (!pcdev->base_emma) {
+		err = -ENOMEM;
+		goto exit_release;
+	}
+
+	err = request_irq(pcdev->irq_emma, mx27_camera_emma_irq, 0,
+			MX2_CAM_DRV_NAME, pcdev);
+	if (err) {
+		dev_err(pcdev->dev, "Camera EMMA interrupt register failed \n");
+		goto exit_iounmap;
+	}
+
+	pcdev->clk_emma_ipg = clk_get(pcdev->dev, "emma-ipg");
+	if (IS_ERR(pcdev->clk_emma_ipg)) {
+		err = PTR_ERR(pcdev->clk_emma_ipg);
+		goto exit_free_irq;
+	}
+
+	clk_prepare_enable(pcdev->clk_emma_ipg);
+
+	pcdev->clk_emma_ahb = clk_get(pcdev->dev, "emma-ahb");
+	if (IS_ERR(pcdev->clk_emma_ahb)) {
+		err = PTR_ERR(pcdev->clk_emma_ahb);
+		goto exit_clk_emma_ipg_put;
+	}
+
+	clk_prepare_enable(pcdev->clk_emma_ahb);
+
+	err = mx27_camera_emma_prp_reset(pcdev);
+	if (err)
+		goto exit_clk_emma_ahb_put;
+
+	return err;
+
+exit_clk_emma_ahb_put:
+	clk_disable_unprepare(pcdev->clk_emma_ahb);
+	clk_put(pcdev->clk_emma_ahb);
+exit_clk_emma_ipg_put:
+	clk_disable_unprepare(pcdev->clk_emma_ipg);
+	clk_put(pcdev->clk_emma_ipg);
+exit_free_irq:
+	free_irq(pcdev->irq_emma, pcdev);
+exit_iounmap:
+	iounmap(pcdev->base_emma);
+exit_release:
+	release_mem_region(res_emma->start, resource_size(res_emma));
+out:
+	return err;
+}
+
+static int __devinit mx2_camera_probe(struct platform_device *pdev)
+{
+	struct mx2_camera_dev *pcdev;
+	struct resource *res_csi, *res_emma;
+	void __iomem *base_csi;
+	int irq_csi, irq_emma;
+	int err = 0;
+
+	dev_dbg(&pdev->dev, "initialising\n");
+
+	res_csi = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	irq_csi = platform_get_irq(pdev, 0);
+	if (res_csi == NULL || irq_csi < 0) {
+		dev_err(&pdev->dev, "Missing platform resources data\n");
+		err = -ENODEV;
+		goto exit;
+	}
+
+	pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);
+	if (!pcdev) {
+		dev_err(&pdev->dev, "Could not allocate pcdev\n");
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	pcdev->clk_csi = clk_get(&pdev->dev, "ahb");
+	if (IS_ERR(pcdev->clk_csi)) {
+		dev_err(&pdev->dev, "Could not get csi clock\n");
+		err = PTR_ERR(pcdev->clk_csi);
+		goto exit_kfree;
+	}
+
+	pcdev->res_csi = res_csi;
+	pcdev->pdata = pdev->dev.platform_data;
+	if (pcdev->pdata) {
+		long rate;
+
+		pcdev->platform_flags = pcdev->pdata->flags;
+
+		rate = clk_round_rate(pcdev->clk_csi, pcdev->pdata->clk * 2);
+		if (rate <= 0) {
+			err = -ENODEV;
+			goto exit_dma_free;
+		}
+		err = clk_set_rate(pcdev->clk_csi, rate);
+		if (err < 0)
+			goto exit_dma_free;
+	}
+
+	INIT_LIST_HEAD(&pcdev->capture);
+	INIT_LIST_HEAD(&pcdev->active_bufs);
+	INIT_LIST_HEAD(&pcdev->discard);
+	spin_lock_init(&pcdev->lock);
+
+	/*
+	 * Request the regions.
+	 */
+	if (!request_mem_region(res_csi->start, resource_size(res_csi),
+				MX2_CAM_DRV_NAME)) {
+		err = -EBUSY;
+		goto exit_dma_free;
+	}
+
+	base_csi = ioremap(res_csi->start, resource_size(res_csi));
+	if (!base_csi) {
+		err = -ENOMEM;
+		goto exit_release;
+	}
+	pcdev->irq_csi = irq_csi;
+	pcdev->base_csi = base_csi;
+	pcdev->base_dma = res_csi->start;
+	pcdev->dev = &pdev->dev;
+
+	if (cpu_is_mx25()) {
+		err = request_irq(pcdev->irq_csi, mx25_camera_irq, 0,
+				MX2_CAM_DRV_NAME, pcdev);
+		if (err) {
+			dev_err(pcdev->dev, "Camera interrupt register failed \n");
+			goto exit_iounmap;
+		}
+	}
+
+	if (cpu_is_mx27()) {
+		/* EMMA support */
+		res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+		irq_emma = platform_get_irq(pdev, 1);
+
+		if (!res_emma || !irq_emma) {
+			dev_err(&pdev->dev, "no EMMA resources\n");
+			goto exit_free_irq;
+		}
+
+		pcdev->res_emma = res_emma;
+		pcdev->irq_emma = irq_emma;
+		if (mx27_camera_emma_init(pcdev))
+			goto exit_free_irq;
+	}
+
+	pcdev->soc_host.drv_name	= MX2_CAM_DRV_NAME,
+	pcdev->soc_host.ops		= &mx2_soc_camera_host_ops,
+	pcdev->soc_host.priv		= pcdev;
+	pcdev->soc_host.v4l2_dev.dev	= &pdev->dev;
+	pcdev->soc_host.nr		= pdev->id;
+	if (cpu_is_mx25())
+		pcdev->soc_host.capabilities = SOCAM_HOST_CAP_STRIDE;
+
+	pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+	if (IS_ERR(pcdev->alloc_ctx)) {
+		err = PTR_ERR(pcdev->alloc_ctx);
+		goto eallocctx;
+	}
+	err = soc_camera_host_register(&pcdev->soc_host);
+	if (err)
+		goto exit_free_emma;
+
+	dev_info(&pdev->dev, "MX2 Camera (CSI) driver probed, clock frequency: %ld\n",
+			clk_get_rate(pcdev->clk_csi));
+
+	return 0;
+
+exit_free_emma:
+	vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+eallocctx:
+	if (cpu_is_mx27()) {
+		free_irq(pcdev->irq_emma, pcdev);
+		clk_disable_unprepare(pcdev->clk_emma_ipg);
+		clk_put(pcdev->clk_emma_ipg);
+		clk_disable_unprepare(pcdev->clk_emma_ahb);
+		clk_put(pcdev->clk_emma_ahb);
+		iounmap(pcdev->base_emma);
+		release_mem_region(pcdev->res_emma->start, resource_size(pcdev->res_emma));
+	}
+exit_free_irq:
+	if (cpu_is_mx25())
+		free_irq(pcdev->irq_csi, pcdev);
+exit_iounmap:
+	iounmap(base_csi);
+exit_release:
+	release_mem_region(res_csi->start, resource_size(res_csi));
+exit_dma_free:
+	clk_put(pcdev->clk_csi);
+exit_kfree:
+	kfree(pcdev);
+exit:
+	return err;
+}
+
+static int __devexit mx2_camera_remove(struct platform_device *pdev)
+{
+	struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+	struct mx2_camera_dev *pcdev = container_of(soc_host,
+			struct mx2_camera_dev, soc_host);
+	struct resource *res;
+
+	clk_put(pcdev->clk_csi);
+	if (cpu_is_mx25())
+		free_irq(pcdev->irq_csi, pcdev);
+	if (cpu_is_mx27())
+		free_irq(pcdev->irq_emma, pcdev);
+
+	soc_camera_host_unregister(&pcdev->soc_host);
+
+	vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+
+	iounmap(pcdev->base_csi);
+
+	if (cpu_is_mx27()) {
+		clk_disable_unprepare(pcdev->clk_emma_ipg);
+		clk_put(pcdev->clk_emma_ipg);
+		clk_disable_unprepare(pcdev->clk_emma_ahb);
+		clk_put(pcdev->clk_emma_ahb);
+		iounmap(pcdev->base_emma);
+		res = pcdev->res_emma;
+		release_mem_region(res->start, resource_size(res));
+	}
+
+	res = pcdev->res_csi;
+	release_mem_region(res->start, resource_size(res));
+
+	kfree(pcdev);
+
+	dev_info(&pdev->dev, "MX2 Camera driver unloaded\n");
+
+	return 0;
+}
+
+static struct platform_driver mx2_camera_driver = {
+	.driver 	= {
+		.name	= MX2_CAM_DRV_NAME,
+	},
+	.remove		= __devexit_p(mx2_camera_remove),
+};
+
+
+static int __init mx2_camera_init(void)
+{
+	return platform_driver_probe(&mx2_camera_driver, &mx2_camera_probe);
+}
+
+static void __exit mx2_camera_exit(void)
+{
+	return platform_driver_unregister(&mx2_camera_driver);
+}
+
+module_init(mx2_camera_init);
+module_exit(mx2_camera_exit);
+
+MODULE_DESCRIPTION("i.MX27/i.MX25 SoC Camera Host driver");
+MODULE_AUTHOR("Sascha Hauer <sha@pengutronix.de>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(MX2_CAM_VERSION);
diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c
new file mode 100644
index 0000000..dab380a
--- /dev/null
+++ b/drivers/media/platform/mx2_emmaprp.c
@@ -0,0 +1,1030 @@
+/*
+ * Support eMMa-PrP through mem2mem framework.
+ *
+ * eMMa-PrP is a piece of HW that allows fetching buffers
+ * from one memory location and do several operations on
+ * them such as scaling or format conversion giving, as a result
+ * a new processed buffer in another memory location.
+ *
+ * Based on mem2mem_testdev.c by Pawel Osciak.
+ *
+ * Copyright (c) 2011 Vista Silicon S.L.
+ * Javier Martin <javier.martin@vista-silicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version
+ */
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <linux/platform_device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+#include <asm/sizes.h>
+
+#define EMMAPRP_MODULE_NAME "mem2mem-emmaprp"
+
+MODULE_DESCRIPTION("Mem-to-mem device which supports eMMa-PrP present in mx2 SoCs");
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.1");
+
+static bool debug;
+module_param(debug, bool, 0644);
+
+#define MIN_W 32
+#define MIN_H 32
+#define MAX_W 2040
+#define MAX_H 2046
+
+#define S_ALIGN		1 /* multiple of 2 */
+#define W_ALIGN_YUV420	3 /* multiple of 8 */
+#define W_ALIGN_OTHERS	2 /* multiple of 4 */
+#define H_ALIGN		1 /* multiple of 2 */
+
+/* Flags that indicate a format can be used for capture/output */
+#define MEM2MEM_CAPTURE	(1 << 0)
+#define MEM2MEM_OUTPUT	(1 << 1)
+
+#define MEM2MEM_NAME		"m2m-emmaprp"
+
+/* In bytes, per queue */
+#define MEM2MEM_VID_MEM_LIMIT	SZ_16M
+
+#define dprintk(dev, fmt, arg...) \
+	v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
+
+/* EMMA PrP */
+#define PRP_CNTL                        0x00
+#define PRP_INTR_CNTL                   0x04
+#define PRP_INTRSTATUS                  0x08
+#define PRP_SOURCE_Y_PTR                0x0c
+#define PRP_SOURCE_CB_PTR               0x10
+#define PRP_SOURCE_CR_PTR               0x14
+#define PRP_DEST_RGB1_PTR               0x18
+#define PRP_DEST_RGB2_PTR               0x1c
+#define PRP_DEST_Y_PTR                  0x20
+#define PRP_DEST_CB_PTR                 0x24
+#define PRP_DEST_CR_PTR                 0x28
+#define PRP_SRC_FRAME_SIZE              0x2c
+#define PRP_DEST_CH1_LINE_STRIDE        0x30
+#define PRP_SRC_PIXEL_FORMAT_CNTL       0x34
+#define PRP_CH1_PIXEL_FORMAT_CNTL       0x38
+#define PRP_CH1_OUT_IMAGE_SIZE          0x3c
+#define PRP_CH2_OUT_IMAGE_SIZE          0x40
+#define PRP_SRC_LINE_STRIDE             0x44
+#define PRP_CSC_COEF_012                0x48
+#define PRP_CSC_COEF_345                0x4c
+#define PRP_CSC_COEF_678                0x50
+#define PRP_CH1_RZ_HORI_COEF1           0x54
+#define PRP_CH1_RZ_HORI_COEF2           0x58
+#define PRP_CH1_RZ_HORI_VALID           0x5c
+#define PRP_CH1_RZ_VERT_COEF1           0x60
+#define PRP_CH1_RZ_VERT_COEF2           0x64
+#define PRP_CH1_RZ_VERT_VALID           0x68
+#define PRP_CH2_RZ_HORI_COEF1           0x6c
+#define PRP_CH2_RZ_HORI_COEF2           0x70
+#define PRP_CH2_RZ_HORI_VALID           0x74
+#define PRP_CH2_RZ_VERT_COEF1           0x78
+#define PRP_CH2_RZ_VERT_COEF2           0x7c
+#define PRP_CH2_RZ_VERT_VALID           0x80
+
+#define PRP_CNTL_CH1EN          (1 << 0)
+#define PRP_CNTL_CH2EN          (1 << 1)
+#define PRP_CNTL_CSIEN          (1 << 2)
+#define PRP_CNTL_DATA_IN_YUV420 (0 << 3)
+#define PRP_CNTL_DATA_IN_YUV422 (1 << 3)
+#define PRP_CNTL_DATA_IN_RGB16  (2 << 3)
+#define PRP_CNTL_DATA_IN_RGB32  (3 << 3)
+#define PRP_CNTL_CH1_OUT_RGB8   (0 << 5)
+#define PRP_CNTL_CH1_OUT_RGB16  (1 << 5)
+#define PRP_CNTL_CH1_OUT_RGB32  (2 << 5)
+#define PRP_CNTL_CH1_OUT_YUV422 (3 << 5)
+#define PRP_CNTL_CH2_OUT_YUV420 (0 << 7)
+#define PRP_CNTL_CH2_OUT_YUV422 (1 << 7)
+#define PRP_CNTL_CH2_OUT_YUV444 (2 << 7)
+#define PRP_CNTL_CH1_LEN        (1 << 9)
+#define PRP_CNTL_CH2_LEN        (1 << 10)
+#define PRP_CNTL_SKIP_FRAME     (1 << 11)
+#define PRP_CNTL_SWRST          (1 << 12)
+#define PRP_CNTL_CLKEN          (1 << 13)
+#define PRP_CNTL_WEN            (1 << 14)
+#define PRP_CNTL_CH1BYP         (1 << 15)
+#define PRP_CNTL_IN_TSKIP(x)    ((x) << 16)
+#define PRP_CNTL_CH1_TSKIP(x)   ((x) << 19)
+#define PRP_CNTL_CH2_TSKIP(x)   ((x) << 22)
+#define PRP_CNTL_INPUT_FIFO_LEVEL(x)    ((x) << 25)
+#define PRP_CNTL_RZ_FIFO_LEVEL(x)       ((x) << 27)
+#define PRP_CNTL_CH2B1EN        (1 << 29)
+#define PRP_CNTL_CH2B2EN        (1 << 30)
+#define PRP_CNTL_CH2FEN         (1 << 31)
+
+#define PRP_SIZE_HEIGHT(x)	(x)
+#define PRP_SIZE_WIDTH(x)	((x) << 16)
+
+/* IRQ Enable and status register */
+#define PRP_INTR_RDERR          (1 << 0)
+#define PRP_INTR_CH1WERR        (1 << 1)
+#define PRP_INTR_CH2WERR        (1 << 2)
+#define PRP_INTR_CH1FC          (1 << 3)
+#define PRP_INTR_CH2FC          (1 << 5)
+#define PRP_INTR_LBOVF          (1 << 7)
+#define PRP_INTR_CH2OVF         (1 << 8)
+
+#define PRP_INTR_ST_RDERR	(1 << 0)
+#define PRP_INTR_ST_CH1WERR	(1 << 1)
+#define PRP_INTR_ST_CH2WERR	(1 << 2)
+#define PRP_INTR_ST_CH2B2CI	(1 << 3)
+#define PRP_INTR_ST_CH2B1CI	(1 << 4)
+#define PRP_INTR_ST_CH1B2CI	(1 << 5)
+#define PRP_INTR_ST_CH1B1CI	(1 << 6)
+#define PRP_INTR_ST_LBOVF	(1 << 7)
+#define PRP_INTR_ST_CH2OVF	(1 << 8)
+
+struct emmaprp_fmt {
+	char	*name;
+	u32	fourcc;
+	/* Types the format can be used for */
+	u32	types;
+};
+
+static struct emmaprp_fmt formats[] = {
+	{
+		.name	= "YUV 4:2:0 Planar",
+		.fourcc	= V4L2_PIX_FMT_YUV420,
+		.types	= MEM2MEM_CAPTURE,
+	},
+	{
+		.name	= "4:2:2, packed, YUYV",
+		.fourcc	= V4L2_PIX_FMT_YUYV,
+		.types	= MEM2MEM_OUTPUT,
+	},
+};
+
+/* Per-queue, driver-specific private data */
+struct emmaprp_q_data {
+	unsigned int		width;
+	unsigned int		height;
+	unsigned int		sizeimage;
+	struct emmaprp_fmt	*fmt;
+};
+
+enum {
+	V4L2_M2M_SRC = 0,
+	V4L2_M2M_DST = 1,
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+static struct emmaprp_fmt *find_format(struct v4l2_format *f)
+{
+	struct emmaprp_fmt *fmt;
+	unsigned int k;
+
+	for (k = 0; k < NUM_FORMATS; k++) {
+		fmt = &formats[k];
+		if (fmt->fourcc == f->fmt.pix.pixelformat)
+			break;
+	}
+
+	if (k == NUM_FORMATS)
+		return NULL;
+
+	return &formats[k];
+}
+
+struct emmaprp_dev {
+	struct v4l2_device	v4l2_dev;
+	struct video_device	*vfd;
+
+	struct mutex		dev_mutex;
+	spinlock_t		irqlock;
+
+	int			irq_emma;
+	void __iomem		*base_emma;
+	struct clk		*clk_emma_ahb, *clk_emma_ipg;
+	struct resource		*res_emma;
+
+	struct v4l2_m2m_dev	*m2m_dev;
+	struct vb2_alloc_ctx	*alloc_ctx;
+};
+
+struct emmaprp_ctx {
+	struct emmaprp_dev	*dev;
+	/* Abort requested by m2m */
+	int			aborting;
+	struct emmaprp_q_data	q_data[2];
+	struct v4l2_m2m_ctx	*m2m_ctx;
+};
+
+static struct emmaprp_q_data *get_q_data(struct emmaprp_ctx *ctx,
+					 enum v4l2_buf_type type)
+{
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		return &(ctx->q_data[V4L2_M2M_SRC]);
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return &(ctx->q_data[V4L2_M2M_DST]);
+	default:
+		BUG();
+	}
+	return NULL;
+}
+
+/*
+ * mem2mem callbacks
+ */
+static void emmaprp_job_abort(void *priv)
+{
+	struct emmaprp_ctx *ctx = priv;
+	struct emmaprp_dev *pcdev = ctx->dev;
+
+	ctx->aborting = 1;
+
+	dprintk(pcdev, "Aborting task\n");
+
+	v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx);
+}
+
+static void emmaprp_lock(void *priv)
+{
+	struct emmaprp_ctx *ctx = priv;
+	struct emmaprp_dev *pcdev = ctx->dev;
+	mutex_lock(&pcdev->dev_mutex);
+}
+
+static void emmaprp_unlock(void *priv)
+{
+	struct emmaprp_ctx *ctx = priv;
+	struct emmaprp_dev *pcdev = ctx->dev;
+	mutex_unlock(&pcdev->dev_mutex);
+}
+
+static inline void emmaprp_dump_regs(struct emmaprp_dev *pcdev)
+{
+	dprintk(pcdev,
+		"eMMa-PrP Registers:\n"
+		"  SOURCE_Y_PTR = 0x%08X\n"
+		"  SRC_FRAME_SIZE = 0x%08X\n"
+		"  DEST_Y_PTR = 0x%08X\n"
+		"  DEST_CR_PTR = 0x%08X\n"
+		"  DEST_CB_PTR = 0x%08X\n"
+		"  CH2_OUT_IMAGE_SIZE = 0x%08X\n"
+		"  CNTL = 0x%08X\n",
+		readl(pcdev->base_emma + PRP_SOURCE_Y_PTR),
+		readl(pcdev->base_emma + PRP_SRC_FRAME_SIZE),
+		readl(pcdev->base_emma + PRP_DEST_Y_PTR),
+		readl(pcdev->base_emma + PRP_DEST_CR_PTR),
+		readl(pcdev->base_emma + PRP_DEST_CB_PTR),
+		readl(pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE),
+		readl(pcdev->base_emma + PRP_CNTL));
+}
+
+static void emmaprp_device_run(void *priv)
+{
+	struct emmaprp_ctx *ctx = priv;
+	struct emmaprp_q_data *s_q_data, *d_q_data;
+	struct vb2_buffer *src_buf, *dst_buf;
+	struct emmaprp_dev *pcdev = ctx->dev;
+	unsigned int s_width, s_height;
+	unsigned int d_width, d_height;
+	unsigned int d_size;
+	dma_addr_t p_in, p_out;
+	u32 tmp;
+
+	src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+
+	s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	s_width	= s_q_data->width;
+	s_height = s_q_data->height;
+
+	d_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	d_width = d_q_data->width;
+	d_height = d_q_data->height;
+	d_size = d_width * d_height;
+
+	p_in = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+	p_out = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+	if (!p_in || !p_out) {
+		v4l2_err(&pcdev->v4l2_dev,
+			 "Acquiring kernel pointers to buffers failed\n");
+		return;
+	}
+
+	/* Input frame parameters */
+	writel(p_in, pcdev->base_emma + PRP_SOURCE_Y_PTR);
+	writel(PRP_SIZE_WIDTH(s_width) | PRP_SIZE_HEIGHT(s_height),
+	       pcdev->base_emma + PRP_SRC_FRAME_SIZE);
+
+	/* Output frame parameters */
+	writel(p_out, pcdev->base_emma + PRP_DEST_Y_PTR);
+	writel(p_out + d_size, pcdev->base_emma + PRP_DEST_CB_PTR);
+	writel(p_out + d_size + (d_size >> 2),
+	       pcdev->base_emma + PRP_DEST_CR_PTR);
+	writel(PRP_SIZE_WIDTH(d_width) | PRP_SIZE_HEIGHT(d_height),
+	       pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE);
+
+	/* IRQ configuration */
+	tmp = readl(pcdev->base_emma + PRP_INTR_CNTL);
+	writel(tmp | PRP_INTR_RDERR |
+		PRP_INTR_CH2WERR |
+		PRP_INTR_CH2FC,
+		pcdev->base_emma + PRP_INTR_CNTL);
+
+	emmaprp_dump_regs(pcdev);
+
+	/* Enable transfer */
+	tmp = readl(pcdev->base_emma + PRP_CNTL);
+	writel(tmp | PRP_CNTL_CH2_OUT_YUV420 |
+		PRP_CNTL_DATA_IN_YUV422 |
+		PRP_CNTL_CH2EN,
+		pcdev->base_emma + PRP_CNTL);
+}
+
+static irqreturn_t emmaprp_irq(int irq_emma, void *data)
+{
+	struct emmaprp_dev *pcdev = data;
+	struct emmaprp_ctx *curr_ctx;
+	struct vb2_buffer *src_vb, *dst_vb;
+	unsigned long flags;
+	u32 irqst;
+
+	/* Check irq flags and clear irq */
+	irqst = readl(pcdev->base_emma + PRP_INTRSTATUS);
+	writel(irqst, pcdev->base_emma + PRP_INTRSTATUS);
+	dprintk(pcdev, "irqst = 0x%08x\n", irqst);
+
+	curr_ctx = v4l2_m2m_get_curr_priv(pcdev->m2m_dev);
+	if (curr_ctx == NULL) {
+		pr_err("Instance released before the end of transaction\n");
+		return IRQ_HANDLED;
+	}
+
+	if (!curr_ctx->aborting) {
+		if ((irqst & PRP_INTR_ST_RDERR) ||
+		(irqst & PRP_INTR_ST_CH2WERR)) {
+			pr_err("PrP bus error ocurred, this transfer is probably corrupted\n");
+			writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
+		} else if (irqst & PRP_INTR_ST_CH2B1CI) { /* buffer ready */
+			src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
+			dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+
+			spin_lock_irqsave(&pcdev->irqlock, flags);
+			v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+			v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+			spin_unlock_irqrestore(&pcdev->irqlock, flags);
+		}
+	}
+
+	v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx);
+	return IRQ_HANDLED;
+}
+
+/*
+ * video ioctls
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
+	strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
+	/*
+	 * This is only a mem-to-mem video device. The capture and output
+	 * device capability flags are left only for backward compatibility
+	 * and are scheduled for removal.
+	 */
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
+			    V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+	return 0;
+}
+
+static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
+{
+	int i, num;
+	struct emmaprp_fmt *fmt;
+
+	num = 0;
+
+	for (i = 0; i < NUM_FORMATS; ++i) {
+		if (formats[i].types & type) {
+			/* index-th format of type type found ? */
+			if (num == f->index)
+				break;
+			/* Correct type but haven't reached our index yet,
+			 * just increment per-type index */
+			++num;
+		}
+	}
+
+	if (i < NUM_FORMATS) {
+		/* Format found */
+		fmt = &formats[i];
+		strlcpy(f->description, fmt->name, sizeof(f->description) - 1);
+		f->pixelformat = fmt->fourcc;
+		return 0;
+	}
+
+	/* Format not found */
+	return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	return enum_fmt(f, MEM2MEM_CAPTURE);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	return enum_fmt(f, MEM2MEM_OUTPUT);
+}
+
+static int vidioc_g_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f)
+{
+	struct vb2_queue *vq;
+	struct emmaprp_q_data *q_data;
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, f->type);
+
+	f->fmt.pix.width	= q_data->width;
+	f->fmt.pix.height	= q_data->height;
+	f->fmt.pix.field	= V4L2_FIELD_NONE;
+	f->fmt.pix.pixelformat	= q_data->fmt->fourcc;
+	if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+		f->fmt.pix.bytesperline = q_data->width * 3 / 2;
+	else /* YUYV */
+		f->fmt.pix.bytesperline = q_data->width * 2;
+	f->fmt.pix.sizeimage	= q_data->sizeimage;
+
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	return vidioc_g_fmt(priv, f);
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	return vidioc_g_fmt(priv, f);
+}
+
+static int vidioc_try_fmt(struct v4l2_format *f)
+{
+	enum v4l2_field field;
+
+
+	if (!find_format(f))
+		return -EINVAL;
+
+	field = f->fmt.pix.field;
+	if (field == V4L2_FIELD_ANY)
+		field = V4L2_FIELD_NONE;
+	else if (V4L2_FIELD_NONE != field)
+		return -EINVAL;
+
+	/* V4L2 specification suggests the driver corrects the format struct
+	 * if any of the dimensions is unsupported */
+	f->fmt.pix.field = field;
+
+	if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
+		v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W,
+				      W_ALIGN_YUV420, &f->fmt.pix.height,
+				      MIN_H, MAX_H, H_ALIGN, S_ALIGN);
+		f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2;
+	} else {
+		v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W,
+				      W_ALIGN_OTHERS, &f->fmt.pix.height,
+				      MIN_H, MAX_H, H_ALIGN, S_ALIGN);
+		f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+	}
+	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct emmaprp_fmt *fmt;
+	struct emmaprp_ctx *ctx = priv;
+
+	fmt = find_format(f);
+	if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
+		v4l2_err(&ctx->dev->v4l2_dev,
+			 "Fourcc format (0x%08x) invalid.\n",
+			 f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	return vidioc_try_fmt(f);
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct emmaprp_fmt *fmt;
+	struct emmaprp_ctx *ctx = priv;
+
+	fmt = find_format(f);
+	if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
+		v4l2_err(&ctx->dev->v4l2_dev,
+			 "Fourcc format (0x%08x) invalid.\n",
+			 f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	return vidioc_try_fmt(f);
+}
+
+static int vidioc_s_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f)
+{
+	struct emmaprp_q_data *q_data;
+	struct vb2_queue *vq;
+	int ret;
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, f->type);
+	if (!q_data)
+		return -EINVAL;
+
+	if (vb2_is_busy(vq)) {
+		v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
+		return -EBUSY;
+	}
+
+	ret = vidioc_try_fmt(f);
+	if (ret)
+		return ret;
+
+	q_data->fmt		= find_format(f);
+	q_data->width		= f->fmt.pix.width;
+	q_data->height		= f->fmt.pix.height;
+	if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420)
+		q_data->sizeimage = q_data->width * q_data->height * 3 / 2;
+	else /* YUYV */
+		q_data->sizeimage = q_data->width * q_data->height * 2;
+
+	dprintk(ctx->dev,
+		"Setting format for type %d, wxh: %dx%d, fmt: %d\n",
+		f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
+
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	int ret;
+
+	ret = vidioc_try_fmt_vid_cap(file, priv, f);
+	if (ret)
+		return ret;
+
+	return vidioc_s_fmt(priv, f);
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	int ret;
+
+	ret = vidioc_try_fmt_vid_out(file, priv, f);
+	if (ret)
+		return ret;
+
+	return vidioc_s_fmt(priv, f);
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *reqbufs)
+{
+	struct emmaprp_ctx *ctx = priv;
+
+	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+			   struct v4l2_buffer *buf)
+{
+	struct emmaprp_ctx *ctx = priv;
+
+	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct emmaprp_ctx *ctx = priv;
+
+	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct emmaprp_ctx *ctx = priv;
+
+	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type type)
+{
+	struct emmaprp_ctx *ctx = priv;
+
+	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type type)
+{
+	struct emmaprp_ctx *ctx = priv;
+
+	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = {
+	.vidioc_querycap	= vidioc_querycap,
+
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,
+
+	.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out	= vidioc_g_fmt_vid_out,
+	.vidioc_try_fmt_vid_out	= vidioc_try_fmt_vid_out,
+	.vidioc_s_fmt_vid_out	= vidioc_s_fmt_vid_out,
+
+	.vidioc_reqbufs		= vidioc_reqbufs,
+	.vidioc_querybuf	= vidioc_querybuf,
+
+	.vidioc_qbuf		= vidioc_qbuf,
+	.vidioc_dqbuf		= vidioc_dqbuf,
+
+	.vidioc_streamon	= vidioc_streamon,
+	.vidioc_streamoff	= vidioc_streamoff,
+};
+
+
+/*
+ * Queue operations
+ */
+static int emmaprp_queue_setup(struct vb2_queue *vq,
+				const struct v4l2_format *fmt,
+				unsigned int *nbuffers, unsigned int *nplanes,
+				unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct emmaprp_ctx *ctx = vb2_get_drv_priv(vq);
+	struct emmaprp_q_data *q_data;
+	unsigned int size, count = *nbuffers;
+
+	q_data = get_q_data(ctx, vq->type);
+
+	if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420)
+		size = q_data->width * q_data->height * 3 / 2;
+	else
+		size = q_data->width * q_data->height * 2;
+
+	while (size * count > MEM2MEM_VID_MEM_LIMIT)
+		(count)--;
+
+	*nplanes = 1;
+	*nbuffers = count;
+	sizes[0] = size;
+
+	alloc_ctxs[0] = ctx->dev->alloc_ctx;
+
+	dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
+
+	return 0;
+}
+
+static int emmaprp_buf_prepare(struct vb2_buffer *vb)
+{
+	struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct emmaprp_q_data *q_data;
+
+	dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
+
+	q_data = get_q_data(ctx, vb->vb2_queue->type);
+
+	if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
+		dprintk(ctx->dev, "%s data will not fit into plane"
+				  "(%lu < %lu)\n", __func__,
+				  vb2_plane_size(vb, 0),
+				  (long)q_data->sizeimage);
+		return -EINVAL;
+	}
+
+	vb2_set_plane_payload(vb, 0, q_data->sizeimage);
+
+	return 0;
+}
+
+static void emmaprp_buf_queue(struct vb2_buffer *vb)
+{
+	struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static struct vb2_ops emmaprp_qops = {
+	.queue_setup	 = emmaprp_queue_setup,
+	.buf_prepare	 = emmaprp_buf_prepare,
+	.buf_queue	 = emmaprp_buf_queue,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+		      struct vb2_queue *dst_vq)
+{
+	struct emmaprp_ctx *ctx = priv;
+	int ret;
+
+	memset(src_vq, 0, sizeof(*src_vq));
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+	src_vq->drv_priv = ctx;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	src_vq->ops = &emmaprp_qops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	memset(dst_vq, 0, sizeof(*dst_vq));
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+	dst_vq->drv_priv = ctx;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->ops = &emmaprp_qops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+	return vb2_queue_init(dst_vq);
+}
+
+/*
+ * File operations
+ */
+static int emmaprp_open(struct file *file)
+{
+	struct emmaprp_dev *pcdev = video_drvdata(file);
+	struct emmaprp_ctx *ctx;
+
+	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	file->private_data = ctx;
+	ctx->dev = pcdev;
+
+	if (mutex_lock_interruptible(&pcdev->dev_mutex)) {
+		kfree(ctx);
+		return -ERESTARTSYS;
+	}
+
+	ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init);
+
+	if (IS_ERR(ctx->m2m_ctx)) {
+		int ret = PTR_ERR(ctx->m2m_ctx);
+
+		mutex_unlock(&pcdev->dev_mutex);
+		kfree(ctx);
+		return ret;
+	}
+
+	clk_prepare_enable(pcdev->clk_emma_ipg);
+	clk_prepare_enable(pcdev->clk_emma_ahb);
+	ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1];
+	ctx->q_data[V4L2_M2M_DST].fmt = &formats[0];
+	mutex_unlock(&pcdev->dev_mutex);
+
+	dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
+
+	return 0;
+}
+
+static int emmaprp_release(struct file *file)
+{
+	struct emmaprp_dev *pcdev = video_drvdata(file);
+	struct emmaprp_ctx *ctx = file->private_data;
+
+	dprintk(pcdev, "Releasing instance %p\n", ctx);
+
+	mutex_lock(&pcdev->dev_mutex);
+	clk_disable_unprepare(pcdev->clk_emma_ahb);
+	clk_disable_unprepare(pcdev->clk_emma_ipg);
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+	mutex_unlock(&pcdev->dev_mutex);
+	kfree(ctx);
+
+	return 0;
+}
+
+static unsigned int emmaprp_poll(struct file *file,
+				 struct poll_table_struct *wait)
+{
+	struct emmaprp_dev *pcdev = video_drvdata(file);
+	struct emmaprp_ctx *ctx = file->private_data;
+	unsigned int res;
+
+	mutex_lock(&pcdev->dev_mutex);
+	res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+	mutex_unlock(&pcdev->dev_mutex);
+	return res;
+}
+
+static int emmaprp_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct emmaprp_dev *pcdev = video_drvdata(file);
+	struct emmaprp_ctx *ctx = file->private_data;
+	int ret;
+
+	if (mutex_lock_interruptible(&pcdev->dev_mutex))
+		return -ERESTARTSYS;
+	ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+	mutex_unlock(&pcdev->dev_mutex);
+	return ret;
+}
+
+static const struct v4l2_file_operations emmaprp_fops = {
+	.owner		= THIS_MODULE,
+	.open		= emmaprp_open,
+	.release	= emmaprp_release,
+	.poll		= emmaprp_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= emmaprp_mmap,
+};
+
+static struct video_device emmaprp_videodev = {
+	.name		= MEM2MEM_NAME,
+	.fops		= &emmaprp_fops,
+	.ioctl_ops	= &emmaprp_ioctl_ops,
+	.minor		= -1,
+	.release	= video_device_release,
+};
+
+static struct v4l2_m2m_ops m2m_ops = {
+	.device_run	= emmaprp_device_run,
+	.job_abort	= emmaprp_job_abort,
+	.lock		= emmaprp_lock,
+	.unlock		= emmaprp_unlock,
+};
+
+static int emmaprp_probe(struct platform_device *pdev)
+{
+	struct emmaprp_dev *pcdev;
+	struct video_device *vfd;
+	struct resource *res_emma;
+	int irq_emma;
+	int ret;
+
+	pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL);
+	if (!pcdev)
+		return -ENOMEM;
+
+	spin_lock_init(&pcdev->irqlock);
+
+	pcdev->clk_emma_ipg = devm_clk_get(&pdev->dev, "ipg");
+	if (IS_ERR(pcdev->clk_emma_ipg)) {
+		return PTR_ERR(pcdev->clk_emma_ipg);
+	}
+
+	pcdev->clk_emma_ahb = devm_clk_get(&pdev->dev, "ahb");
+	if (IS_ERR(pcdev->clk_emma_ipg)) {
+		return PTR_ERR(pcdev->clk_emma_ahb);
+	}
+
+	irq_emma = platform_get_irq(pdev, 0);
+	res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (irq_emma < 0 || res_emma == NULL) {
+		dev_err(&pdev->dev, "Missing platform resources data\n");
+		return -ENODEV;
+	}
+
+	ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev);
+	if (ret)
+		return ret;
+
+	mutex_init(&pcdev->dev_mutex);
+
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(&pcdev->v4l2_dev, "Failed to allocate video device\n");
+		ret = -ENOMEM;
+		goto unreg_dev;
+	}
+
+	*vfd = emmaprp_videodev;
+	vfd->lock = &pcdev->dev_mutex;
+
+	video_set_drvdata(vfd, pcdev);
+	snprintf(vfd->name, sizeof(vfd->name), "%s", emmaprp_videodev.name);
+	pcdev->vfd = vfd;
+	v4l2_info(&pcdev->v4l2_dev, EMMAPRP_MODULE_NAME
+			" Device registered as /dev/video%d\n", vfd->num);
+
+	platform_set_drvdata(pdev, pcdev);
+
+	pcdev->base_emma = devm_request_and_ioremap(&pdev->dev, res_emma);
+	if (!pcdev->base_emma) {
+		ret = -ENXIO;
+		goto rel_vdev;
+	}
+
+	pcdev->irq_emma = irq_emma;
+	pcdev->res_emma = res_emma;
+
+	if (devm_request_irq(&pdev->dev, pcdev->irq_emma, emmaprp_irq,
+			     0, MEM2MEM_NAME, pcdev) < 0) {
+		ret = -ENODEV;
+		goto rel_vdev;
+	}
+
+	pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+	if (IS_ERR(pcdev->alloc_ctx)) {
+		v4l2_err(&pcdev->v4l2_dev, "Failed to alloc vb2 context\n");
+		ret = PTR_ERR(pcdev->alloc_ctx);
+		goto rel_vdev;
+	}
+
+	pcdev->m2m_dev = v4l2_m2m_init(&m2m_ops);
+	if (IS_ERR(pcdev->m2m_dev)) {
+		v4l2_err(&pcdev->v4l2_dev, "Failed to init mem2mem device\n");
+		ret = PTR_ERR(pcdev->m2m_dev);
+		goto rel_ctx;
+	}
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+	if (ret) {
+		v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n");
+		goto rel_m2m;
+	}
+
+	return 0;
+
+
+rel_m2m:
+	v4l2_m2m_release(pcdev->m2m_dev);
+rel_ctx:
+	vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+rel_vdev:
+	video_device_release(vfd);
+unreg_dev:
+	v4l2_device_unregister(&pcdev->v4l2_dev);
+
+	return ret;
+}
+
+static int emmaprp_remove(struct platform_device *pdev)
+{
+	struct emmaprp_dev *pcdev = platform_get_drvdata(pdev);
+
+	v4l2_info(&pcdev->v4l2_dev, "Removing " EMMAPRP_MODULE_NAME);
+
+	video_unregister_device(pcdev->vfd);
+	v4l2_m2m_release(pcdev->m2m_dev);
+	vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+	v4l2_device_unregister(&pcdev->v4l2_dev);
+
+	return 0;
+}
+
+static struct platform_driver emmaprp_pdrv = {
+	.probe		= emmaprp_probe,
+	.remove		= emmaprp_remove,
+	.driver		= {
+		.name	= MEM2MEM_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static void __exit emmaprp_exit(void)
+{
+	platform_driver_unregister(&emmaprp_pdrv);
+}
+
+static int __init emmaprp_init(void)
+{
+	return platform_driver_register(&emmaprp_pdrv);
+}
+
+module_init(emmaprp_init);
+module_exit(emmaprp_exit);
diff --git a/drivers/media/platform/mx3_camera.c b/drivers/media/platform/mx3_camera.c
new file mode 100644
index 0000000..16975c6
--- /dev/null
+++ b/drivers/media/platform/mx3_camera.c
@@ -0,0 +1,1290 @@
+/*
+ * V4L2 Driver for i.MX3x camera host
+ *
+ * Copyright (C) 2008
+ * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+
+#include <mach/ipu.h>
+#include <mach/mx3_camera.h>
+#include <mach/dma.h>
+
+#define MX3_CAM_DRV_NAME "mx3-camera"
+
+/* CMOS Sensor Interface Registers */
+#define CSI_REG_START		0x60
+
+#define CSI_SENS_CONF		(0x60 - CSI_REG_START)
+#define CSI_SENS_FRM_SIZE	(0x64 - CSI_REG_START)
+#define CSI_ACT_FRM_SIZE	(0x68 - CSI_REG_START)
+#define CSI_OUT_FRM_CTRL	(0x6C - CSI_REG_START)
+#define CSI_TST_CTRL		(0x70 - CSI_REG_START)
+#define CSI_CCIR_CODE_1		(0x74 - CSI_REG_START)
+#define CSI_CCIR_CODE_2		(0x78 - CSI_REG_START)
+#define CSI_CCIR_CODE_3		(0x7C - CSI_REG_START)
+#define CSI_FLASH_STROBE_1	(0x80 - CSI_REG_START)
+#define CSI_FLASH_STROBE_2	(0x84 - CSI_REG_START)
+
+#define CSI_SENS_CONF_VSYNC_POL_SHIFT		0
+#define CSI_SENS_CONF_HSYNC_POL_SHIFT		1
+#define CSI_SENS_CONF_DATA_POL_SHIFT		2
+#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT		3
+#define CSI_SENS_CONF_SENS_PRTCL_SHIFT		4
+#define CSI_SENS_CONF_SENS_CLKSRC_SHIFT		7
+#define CSI_SENS_CONF_DATA_FMT_SHIFT		8
+#define CSI_SENS_CONF_DATA_WIDTH_SHIFT		10
+#define CSI_SENS_CONF_EXT_VSYNC_SHIFT		15
+#define CSI_SENS_CONF_DIVRATIO_SHIFT		16
+
+#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444	(0UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
+#define CSI_SENS_CONF_DATA_FMT_YUV422		(2UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
+#define CSI_SENS_CONF_DATA_FMT_BAYER		(3UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
+
+#define MAX_VIDEO_MEM 16
+
+struct mx3_camera_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct vb2_buffer			vb;
+	struct list_head			queue;
+
+	/* One descriptot per scatterlist (per frame) */
+	struct dma_async_tx_descriptor		*txd;
+
+	/* We have to "build" a scatterlist ourselves - one element per frame */
+	struct scatterlist			sg;
+};
+
+/**
+ * struct mx3_camera_dev - i.MX3x camera (CSI) object
+ * @dev:		camera device, to which the coherent buffer is attached
+ * @icd:		currently attached camera sensor
+ * @clk:		pointer to clock
+ * @base:		remapped register base address
+ * @pdata:		platform data
+ * @platform_flags:	platform flags
+ * @mclk:		master clock frequency in Hz
+ * @capture:		list of capture videobuffers
+ * @lock:		protects video buffer lists
+ * @active:		active video buffer
+ * @idmac_channel:	array of pointers to IPU DMAC DMA channels
+ * @soc_host:		embedded soc_host object
+ */
+struct mx3_camera_dev {
+	/*
+	 * i.MX3x is only supposed to handle one camera on its Camera Sensor
+	 * Interface. If anyone ever builds hardware to enable more than one
+	 * camera _simultaneously_, they will have to modify this driver too
+	 */
+	struct soc_camera_device *icd;
+	struct clk		*clk;
+
+	void __iomem		*base;
+
+	struct mx3_camera_pdata	*pdata;
+
+	unsigned long		platform_flags;
+	unsigned long		mclk;
+	u16			width_flags;	/* max 15 bits */
+
+	struct list_head	capture;
+	spinlock_t		lock;		/* Protects video buffer lists */
+	struct mx3_camera_buffer *active;
+	size_t			buf_total;
+	struct vb2_alloc_ctx	*alloc_ctx;
+	enum v4l2_field		field;
+	int			sequence;
+
+	/* IDMAC / dmaengine interface */
+	struct idmac_channel	*idmac_channel[1];	/* We need one channel */
+
+	struct soc_camera_host	soc_host;
+};
+
+struct dma_chan_request {
+	struct mx3_camera_dev	*mx3_cam;
+	enum ipu_channel	id;
+};
+
+static u32 csi_reg_read(struct mx3_camera_dev *mx3, off_t reg)
+{
+	return __raw_readl(mx3->base + reg);
+}
+
+static void csi_reg_write(struct mx3_camera_dev *mx3, u32 value, off_t reg)
+{
+	__raw_writel(value, mx3->base + reg);
+}
+
+static struct mx3_camera_buffer *to_mx3_vb(struct vb2_buffer *vb)
+{
+	return container_of(vb, struct mx3_camera_buffer, vb);
+}
+
+/* Called from the IPU IDMAC ISR */
+static void mx3_cam_dma_done(void *arg)
+{
+	struct idmac_tx_desc *desc = to_tx_desc(arg);
+	struct dma_chan *chan = desc->txd.chan;
+	struct idmac_channel *ichannel = to_idmac_chan(chan);
+	struct mx3_camera_dev *mx3_cam = ichannel->client;
+
+	dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n",
+		desc->txd.cookie, mx3_cam->active ? sg_dma_address(&mx3_cam->active->sg) : 0);
+
+	spin_lock(&mx3_cam->lock);
+	if (mx3_cam->active) {
+		struct vb2_buffer *vb = &mx3_cam->active->vb;
+		struct mx3_camera_buffer *buf = to_mx3_vb(vb);
+
+		list_del_init(&buf->queue);
+		do_gettimeofday(&vb->v4l2_buf.timestamp);
+		vb->v4l2_buf.field = mx3_cam->field;
+		vb->v4l2_buf.sequence = mx3_cam->sequence++;
+		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+	}
+
+	if (list_empty(&mx3_cam->capture)) {
+		mx3_cam->active = NULL;
+		spin_unlock(&mx3_cam->lock);
+
+		/*
+		 * stop capture - without further buffers IPU_CHA_BUF0_RDY will
+		 * not get updated
+		 */
+		return;
+	}
+
+	mx3_cam->active = list_entry(mx3_cam->capture.next,
+				     struct mx3_camera_buffer, queue);
+	spin_unlock(&mx3_cam->lock);
+}
+
+/*
+ * Videobuf operations
+ */
+
+/*
+ * Calculate the __buffer__ (not data) size and number of buffers.
+ */
+static int mx3_videobuf_setup(struct vb2_queue *vq,
+			const struct v4l2_format *fmt,
+			unsigned int *count, unsigned int *num_planes,
+			unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx3_camera_dev *mx3_cam = ici->priv;
+
+	if (!mx3_cam->idmac_channel[0])
+		return -EINVAL;
+
+	if (fmt) {
+		const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd,
+								fmt->fmt.pix.pixelformat);
+		unsigned int bytes_per_line;
+		int ret;
+
+		if (!xlate)
+			return -EINVAL;
+
+		ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
+					      xlate->host_fmt);
+		if (ret < 0)
+			return ret;
+
+		bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret);
+
+		ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line,
+					  fmt->fmt.pix.height);
+		if (ret < 0)
+			return ret;
+
+		sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret);
+	} else {
+		/* Called from VIDIOC_REQBUFS or in compatibility mode */
+		sizes[0] = icd->sizeimage;
+	}
+
+	alloc_ctxs[0] = mx3_cam->alloc_ctx;
+
+	if (!vq->num_buffers)
+		mx3_cam->sequence = 0;
+
+	if (!*count)
+		*count = 2;
+
+	/* If *num_planes != 0, we have already verified *count. */
+	if (!*num_planes &&
+	    sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024)
+		*count = (MAX_VIDEO_MEM * 1024 * 1024 - mx3_cam->buf_total) /
+			sizes[0];
+
+	*num_planes = 1;
+
+	return 0;
+}
+
+static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc)
+{
+	/* Add more formats as need arises and test possibilities appear... */
+	switch (fourcc) {
+	case V4L2_PIX_FMT_RGB24:
+		return IPU_PIX_FMT_RGB24;
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_RGB565:
+	default:
+		return IPU_PIX_FMT_GENERIC;
+	}
+}
+
+static void mx3_videobuf_queue(struct vb2_buffer *vb)
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx3_camera_dev *mx3_cam = ici->priv;
+	struct mx3_camera_buffer *buf = to_mx3_vb(vb);
+	struct scatterlist *sg = &buf->sg;
+	struct dma_async_tx_descriptor *txd;
+	struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
+	struct idmac_video_param *video = &ichan->params.video;
+	const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt;
+	unsigned long flags;
+	dma_cookie_t cookie;
+	size_t new_size;
+
+	new_size = icd->sizeimage;
+
+	if (vb2_plane_size(vb, 0) < new_size) {
+		dev_err(icd->parent, "Buffer #%d too small (%lu < %zu)\n",
+			vb->v4l2_buf.index, vb2_plane_size(vb, 0), new_size);
+		goto error;
+	}
+
+	if (!buf->txd) {
+		sg_dma_address(sg)	= vb2_dma_contig_plane_dma_addr(vb, 0);
+		sg_dma_len(sg)		= new_size;
+
+		txd = dmaengine_prep_slave_sg(
+			&ichan->dma_chan, sg, 1, DMA_DEV_TO_MEM,
+			DMA_PREP_INTERRUPT);
+		if (!txd)
+			goto error;
+
+		txd->callback_param	= txd;
+		txd->callback		= mx3_cam_dma_done;
+
+		buf->txd		= txd;
+	} else {
+		txd = buf->txd;
+	}
+
+	vb2_set_plane_payload(vb, 0, new_size);
+
+	/* This is the configuration of one sg-element */
+	video->out_pixel_fmt = fourcc_to_ipu_pix(host_fmt->fourcc);
+
+	if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) {
+		/*
+		 * If the IPU DMA channel is configured to transfer generic
+		 * 8-bit data, we have to set up the geometry parameters
+		 * correctly, according to the current pixel format. The DMA
+		 * horizontal parameters in this case are expressed in bytes,
+		 * not in pixels.
+		 */
+		video->out_width	= icd->bytesperline;
+		video->out_height	= icd->user_height;
+		video->out_stride	= icd->bytesperline;
+	} else {
+		/*
+		 * For IPU known formats the pixel unit will be managed
+		 * successfully by the IPU code
+		 */
+		video->out_width	= icd->user_width;
+		video->out_height	= icd->user_height;
+		video->out_stride	= icd->user_width;
+	}
+
+#ifdef DEBUG
+	/* helps to see what DMA actually has written */
+	if (vb2_plane_vaddr(vb, 0))
+		memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0));
+#endif
+
+	spin_lock_irqsave(&mx3_cam->lock, flags);
+	list_add_tail(&buf->queue, &mx3_cam->capture);
+
+	if (!mx3_cam->active)
+		mx3_cam->active = buf;
+
+	spin_unlock_irq(&mx3_cam->lock);
+
+	cookie = txd->tx_submit(txd);
+	dev_dbg(icd->parent, "Submitted cookie %d DMA 0x%08x\n",
+		cookie, sg_dma_address(&buf->sg));
+
+	if (cookie >= 0)
+		return;
+
+	spin_lock_irq(&mx3_cam->lock);
+
+	/* Submit error */
+	list_del_init(&buf->queue);
+
+	if (mx3_cam->active == buf)
+		mx3_cam->active = NULL;
+
+	spin_unlock_irqrestore(&mx3_cam->lock, flags);
+error:
+	vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+}
+
+static void mx3_videobuf_release(struct vb2_buffer *vb)
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx3_camera_dev *mx3_cam = ici->priv;
+	struct mx3_camera_buffer *buf = to_mx3_vb(vb);
+	struct dma_async_tx_descriptor *txd = buf->txd;
+	unsigned long flags;
+
+	dev_dbg(icd->parent,
+		"Release%s DMA 0x%08x, queue %sempty\n",
+		mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg),
+		list_empty(&buf->queue) ? "" : "not ");
+
+	spin_lock_irqsave(&mx3_cam->lock, flags);
+
+	if (mx3_cam->active == buf)
+		mx3_cam->active = NULL;
+
+	/* Doesn't hurt also if the list is empty */
+	list_del_init(&buf->queue);
+
+	if (txd) {
+		buf->txd = NULL;
+		if (mx3_cam->idmac_channel[0])
+			async_tx_ack(txd);
+	}
+
+	spin_unlock_irqrestore(&mx3_cam->lock, flags);
+
+	mx3_cam->buf_total -= vb2_plane_size(vb, 0);
+}
+
+static int mx3_videobuf_init(struct vb2_buffer *vb)
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx3_camera_dev *mx3_cam = ici->priv;
+	struct mx3_camera_buffer *buf = to_mx3_vb(vb);
+
+	if (!buf->txd) {
+		/* This is for locking debugging only */
+		INIT_LIST_HEAD(&buf->queue);
+		sg_init_table(&buf->sg, 1);
+
+		mx3_cam->buf_total += vb2_plane_size(vb, 0);
+	}
+
+	return 0;
+}
+
+static int mx3_stop_streaming(struct vb2_queue *q)
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(q);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx3_camera_dev *mx3_cam = ici->priv;
+	struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
+	struct mx3_camera_buffer *buf, *tmp;
+	unsigned long flags;
+
+	if (ichan) {
+		struct dma_chan *chan = &ichan->dma_chan;
+		chan->device->device_control(chan, DMA_PAUSE, 0);
+	}
+
+	spin_lock_irqsave(&mx3_cam->lock, flags);
+
+	mx3_cam->active = NULL;
+
+	list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) {
+		list_del_init(&buf->queue);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+
+	spin_unlock_irqrestore(&mx3_cam->lock, flags);
+
+	return 0;
+}
+
+static struct vb2_ops mx3_videobuf_ops = {
+	.queue_setup	= mx3_videobuf_setup,
+	.buf_queue	= mx3_videobuf_queue,
+	.buf_cleanup	= mx3_videobuf_release,
+	.buf_init	= mx3_videobuf_init,
+	.wait_prepare	= soc_camera_unlock,
+	.wait_finish	= soc_camera_lock,
+	.stop_streaming	= mx3_stop_streaming,
+};
+
+static int mx3_camera_init_videobuf(struct vb2_queue *q,
+				     struct soc_camera_device *icd)
+{
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	q->io_modes = VB2_MMAP | VB2_USERPTR;
+	q->drv_priv = icd;
+	q->ops = &mx3_videobuf_ops;
+	q->mem_ops = &vb2_dma_contig_memops;
+	q->buf_struct_size = sizeof(struct mx3_camera_buffer);
+
+	return vb2_queue_init(q);
+}
+
+/* First part of ipu_csi_init_interface() */
+static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam,
+				struct soc_camera_device *icd)
+{
+	u32 conf;
+	long rate;
+
+	/* Set default size: ipu_csi_set_window_size() */
+	csi_reg_write(mx3_cam, (640 - 1) | ((480 - 1) << 16), CSI_ACT_FRM_SIZE);
+	/* ...and position to 0:0: ipu_csi_set_window_pos() */
+	conf = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000;
+	csi_reg_write(mx3_cam, conf, CSI_OUT_FRM_CTRL);
+
+	/* We use only gated clock synchronisation mode so far */
+	conf = 0 << CSI_SENS_CONF_SENS_PRTCL_SHIFT;
+
+	/* Set generic data, platform-biggest bus-width */
+	conf |= CSI_SENS_CONF_DATA_FMT_BAYER;
+
+	if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15)
+		conf |= 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+	else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10)
+		conf |= 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+	else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8)
+		conf |= 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+	else/* if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)*/
+		conf |= 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+
+	if (mx3_cam->platform_flags & MX3_CAMERA_CLK_SRC)
+		conf |= 1 << CSI_SENS_CONF_SENS_CLKSRC_SHIFT;
+	if (mx3_cam->platform_flags & MX3_CAMERA_EXT_VSYNC)
+		conf |= 1 << CSI_SENS_CONF_EXT_VSYNC_SHIFT;
+	if (mx3_cam->platform_flags & MX3_CAMERA_DP)
+		conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT;
+	if (mx3_cam->platform_flags & MX3_CAMERA_PCP)
+		conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT;
+	if (mx3_cam->platform_flags & MX3_CAMERA_HSP)
+		conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT;
+	if (mx3_cam->platform_flags & MX3_CAMERA_VSP)
+		conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT;
+
+	/* ipu_csi_init_interface() */
+	csi_reg_write(mx3_cam, conf, CSI_SENS_CONF);
+
+	clk_prepare_enable(mx3_cam->clk);
+	rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk);
+	dev_dbg(icd->parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
+	if (rate)
+		clk_set_rate(mx3_cam->clk, rate);
+}
+
+/* Called with .video_lock held */
+static int mx3_camera_add_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx3_camera_dev *mx3_cam = ici->priv;
+
+	if (mx3_cam->icd)
+		return -EBUSY;
+
+	mx3_camera_activate(mx3_cam, icd);
+
+	mx3_cam->buf_total = 0;
+	mx3_cam->icd = icd;
+
+	dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n",
+		 icd->devnum);
+
+	return 0;
+}
+
+/* Called with .video_lock held */
+static void mx3_camera_remove_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx3_camera_dev *mx3_cam = ici->priv;
+	struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
+
+	BUG_ON(icd != mx3_cam->icd);
+
+	if (*ichan) {
+		dma_release_channel(&(*ichan)->dma_chan);
+		*ichan = NULL;
+	}
+
+	clk_disable_unprepare(mx3_cam->clk);
+
+	mx3_cam->icd = NULL;
+
+	dev_info(icd->parent, "MX3 Camera driver detached from camera %d\n",
+		 icd->devnum);
+}
+
+static int test_platform_param(struct mx3_camera_dev *mx3_cam,
+			       unsigned char buswidth, unsigned long *flags)
+{
+	/*
+	 * If requested data width is supported by the platform, use it or any
+	 * possible lower value - i.MX31 is smart enough to shift bits
+	 */
+	if (buswidth > fls(mx3_cam->width_flags))
+		return -EINVAL;
+
+	/*
+	 * Platform specified synchronization and pixel clock polarities are
+	 * only a recommendation and are only used during probing. MX3x
+	 * camera interface only works in master mode, i.e., uses HSYNC and
+	 * VSYNC signals from the sensor
+	 */
+	*flags = V4L2_MBUS_MASTER |
+		V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+		V4L2_MBUS_HSYNC_ACTIVE_LOW |
+		V4L2_MBUS_VSYNC_ACTIVE_HIGH |
+		V4L2_MBUS_VSYNC_ACTIVE_LOW |
+		V4L2_MBUS_PCLK_SAMPLE_RISING |
+		V4L2_MBUS_PCLK_SAMPLE_FALLING |
+		V4L2_MBUS_DATA_ACTIVE_HIGH |
+		V4L2_MBUS_DATA_ACTIVE_LOW;
+
+	return 0;
+}
+
+static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
+				    const unsigned int depth)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx3_camera_dev *mx3_cam = ici->priv;
+	struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+	unsigned long bus_flags, common_flags;
+	int ret = test_platform_param(mx3_cam, depth, &bus_flags);
+
+	dev_dbg(icd->parent, "request bus width %d bit: %d\n", depth, ret);
+
+	if (ret < 0)
+		return ret;
+
+	ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
+	if (!ret) {
+		common_flags = soc_mbus_config_compatible(&cfg,
+							  bus_flags);
+		if (!common_flags) {
+			dev_warn(icd->parent,
+				 "Flags incompatible: camera 0x%x, host 0x%lx\n",
+				 cfg.flags, bus_flags);
+			return -EINVAL;
+		}
+	} else if (ret != -ENOIOCTLCMD) {
+		return ret;
+	}
+
+	return 0;
+}
+
+static bool chan_filter(struct dma_chan *chan, void *arg)
+{
+	struct dma_chan_request *rq = arg;
+	struct mx3_camera_pdata *pdata;
+
+	if (!imx_dma_is_ipu(chan))
+		return false;
+
+	if (!rq)
+		return false;
+
+	pdata = rq->mx3_cam->soc_host.v4l2_dev.dev->platform_data;
+
+	return rq->id == chan->chan_id &&
+		pdata->dma_dev == chan->device->dev;
+}
+
+static const struct soc_mbus_pixelfmt mx3_camera_formats[] = {
+	{
+		.fourcc			= V4L2_PIX_FMT_SBGGR8,
+		.name			= "Bayer BGGR (sRGB) 8 bit",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_NONE,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	}, {
+		.fourcc			= V4L2_PIX_FMT_GREY,
+		.name			= "Monochrome 8 bit",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_NONE,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+};
+
+/* This will be corrected as we get more formats */
+static bool mx3_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt)
+{
+	return	fmt->packing == SOC_MBUS_PACKING_NONE ||
+		(fmt->bits_per_sample == 8 &&
+		 fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) ||
+		(fmt->bits_per_sample > 8 &&
+		 fmt->packing == SOC_MBUS_PACKING_EXTEND16);
+}
+
+static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int idx,
+				  struct soc_camera_format_xlate *xlate)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct device *dev = icd->parent;
+	int formats = 0, ret;
+	enum v4l2_mbus_pixelcode code;
+	const struct soc_mbus_pixelfmt *fmt;
+
+	ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
+	if (ret < 0)
+		/* No more formats */
+		return 0;
+
+	fmt = soc_mbus_get_fmtdesc(code);
+	if (!fmt) {
+		dev_warn(icd->parent,
+			 "Unsupported format code #%u: %d\n", idx, code);
+		return 0;
+	}
+
+	/* This also checks support for the requested bits-per-sample */
+	ret = mx3_camera_try_bus_param(icd, fmt->bits_per_sample);
+	if (ret < 0)
+		return 0;
+
+	switch (code) {
+	case V4L2_MBUS_FMT_SBGGR10_1X10:
+		formats++;
+		if (xlate) {
+			xlate->host_fmt	= &mx3_camera_formats[0];
+			xlate->code	= code;
+			xlate++;
+			dev_dbg(dev, "Providing format %s using code %d\n",
+				mx3_camera_formats[0].name, code);
+		}
+		break;
+	case V4L2_MBUS_FMT_Y10_1X10:
+		formats++;
+		if (xlate) {
+			xlate->host_fmt	= &mx3_camera_formats[1];
+			xlate->code	= code;
+			xlate++;
+			dev_dbg(dev, "Providing format %s using code %d\n",
+				mx3_camera_formats[1].name, code);
+		}
+		break;
+	default:
+		if (!mx3_camera_packing_supported(fmt))
+			return 0;
+	}
+
+	/* Generic pass-through */
+	formats++;
+	if (xlate) {
+		xlate->host_fmt	= fmt;
+		xlate->code	= code;
+		dev_dbg(dev, "Providing format %c%c%c%c in pass-through mode\n",
+			(fmt->fourcc >> (0*8)) & 0xFF,
+			(fmt->fourcc >> (1*8)) & 0xFF,
+			(fmt->fourcc >> (2*8)) & 0xFF,
+			(fmt->fourcc >> (3*8)) & 0xFF);
+		xlate++;
+	}
+
+	return formats;
+}
+
+static void configure_geometry(struct mx3_camera_dev *mx3_cam,
+			       unsigned int width, unsigned int height,
+			       const struct soc_mbus_pixelfmt *fmt)
+{
+	u32 ctrl, width_field, height_field;
+
+	if (fourcc_to_ipu_pix(fmt->fourcc) == IPU_PIX_FMT_GENERIC) {
+		/*
+		 * As the CSI will be configured to output BAYER, here
+		 * the width parameter count the number of samples to
+		 * capture to complete the whole image width.
+		 */
+		unsigned int num, den;
+		int ret = soc_mbus_samples_per_pixel(fmt, &num, &den);
+		BUG_ON(ret < 0);
+		width = width * num / den;
+	}
+
+	/* Setup frame size - this cannot be changed on-the-fly... */
+	width_field = width - 1;
+	height_field = height - 1;
+	csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE);
+
+	csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1);
+	csi_reg_write(mx3_cam, (height_field << 16) | 0x22, CSI_FLASH_STROBE_2);
+
+	csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_ACT_FRM_SIZE);
+
+	/* ...and position */
+	ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000;
+	/* Sensor does the cropping */
+	csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL);
+}
+
+static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam)
+{
+	dma_cap_mask_t mask;
+	struct dma_chan *chan;
+	struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
+	/* We have to use IDMAC_IC_7 for Bayer / generic data */
+	struct dma_chan_request rq = {.mx3_cam = mx3_cam,
+				      .id = IDMAC_IC_7};
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	dma_cap_set(DMA_PRIVATE, mask);
+	chan = dma_request_channel(mask, chan_filter, &rq);
+	if (!chan)
+		return -EBUSY;
+
+	*ichan = to_idmac_chan(chan);
+	(*ichan)->client = mx3_cam;
+
+	return 0;
+}
+
+/*
+ * FIXME: learn to use stride != width, then we can keep stride properly aligned
+ * and support arbitrary (even) widths.
+ */
+static inline void stride_align(__u32 *width)
+{
+	if (ALIGN(*width, 8) < 4096)
+		*width = ALIGN(*width, 8);
+	else
+		*width = *width &  ~7;
+}
+
+/*
+ * As long as we don't implement host-side cropping and scaling, we can use
+ * default g_crop and cropcap from soc_camera.c
+ */
+static int mx3_camera_set_crop(struct soc_camera_device *icd,
+			       struct v4l2_crop *a)
+{
+	struct v4l2_rect *rect = &a->c;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx3_camera_dev *mx3_cam = ici->priv;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct v4l2_mbus_framefmt mf;
+	int ret;
+
+	soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096);
+	soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096);
+
+	ret = v4l2_subdev_call(sd, video, s_crop, a);
+	if (ret < 0)
+		return ret;
+
+	/* The capture device might have changed its output sizes */
+	ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
+	if (ret < 0)
+		return ret;
+
+	if (mf.code != icd->current_fmt->code)
+		return -EINVAL;
+
+	if (mf.width & 7) {
+		/* Ouch! We can only handle 8-byte aligned width... */
+		stride_align(&mf.width);
+		ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (mf.width != icd->user_width || mf.height != icd->user_height)
+		configure_geometry(mx3_cam, mf.width, mf.height,
+				   icd->current_fmt->host_fmt);
+
+	dev_dbg(icd->parent, "Sensor cropped %dx%d\n",
+		mf.width, mf.height);
+
+	icd->user_width		= mf.width;
+	icd->user_height	= mf.height;
+
+	return ret;
+}
+
+static int mx3_camera_set_fmt(struct soc_camera_device *icd,
+			      struct v4l2_format *f)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx3_camera_dev *mx3_cam = ici->priv;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	const struct soc_camera_format_xlate *xlate;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct v4l2_mbus_framefmt mf;
+	int ret;
+
+	xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+	if (!xlate) {
+		dev_warn(icd->parent, "Format %x not found\n",
+			 pix->pixelformat);
+		return -EINVAL;
+	}
+
+	stride_align(&pix->width);
+	dev_dbg(icd->parent, "Set format %dx%d\n", pix->width, pix->height);
+
+	/*
+	 * Might have to perform a complete interface initialisation like in
+	 * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider
+	 * mxc_v4l2_s_fmt()
+	 */
+
+	configure_geometry(mx3_cam, pix->width, pix->height, xlate->host_fmt);
+
+	mf.width	= pix->width;
+	mf.height	= pix->height;
+	mf.field	= pix->field;
+	mf.colorspace	= pix->colorspace;
+	mf.code		= xlate->code;
+
+	ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+	if (ret < 0)
+		return ret;
+
+	if (mf.code != xlate->code)
+		return -EINVAL;
+
+	if (!mx3_cam->idmac_channel[0]) {
+		ret = acquire_dma_channel(mx3_cam);
+		if (ret < 0)
+			return ret;
+	}
+
+	pix->width		= mf.width;
+	pix->height		= mf.height;
+	pix->field		= mf.field;
+	mx3_cam->field		= mf.field;
+	pix->colorspace		= mf.colorspace;
+	icd->current_fmt	= xlate;
+
+	dev_dbg(icd->parent, "Sensor set %dx%d\n", pix->width, pix->height);
+
+	return ret;
+}
+
+static int mx3_camera_try_fmt(struct soc_camera_device *icd,
+			      struct v4l2_format *f)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	const struct soc_camera_format_xlate *xlate;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct v4l2_mbus_framefmt mf;
+	__u32 pixfmt = pix->pixelformat;
+	int ret;
+
+	xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+	if (pixfmt && !xlate) {
+		dev_warn(icd->parent, "Format %x not found\n", pixfmt);
+		return -EINVAL;
+	}
+
+	/* limit to MX3 hardware capabilities */
+	if (pix->height > 4096)
+		pix->height = 4096;
+	if (pix->width > 4096)
+		pix->width = 4096;
+
+	/* limit to sensor capabilities */
+	mf.width	= pix->width;
+	mf.height	= pix->height;
+	mf.field	= pix->field;
+	mf.colorspace	= pix->colorspace;
+	mf.code		= xlate->code;
+
+	ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+	if (ret < 0)
+		return ret;
+
+	pix->width	= mf.width;
+	pix->height	= mf.height;
+	pix->colorspace	= mf.colorspace;
+
+	switch (mf.field) {
+	case V4L2_FIELD_ANY:
+		pix->field = V4L2_FIELD_NONE;
+		break;
+	case V4L2_FIELD_NONE:
+		break;
+	default:
+		dev_err(icd->parent, "Field type %d unsupported.\n",
+			mf.field);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int mx3_camera_reqbufs(struct soc_camera_device *icd,
+			      struct v4l2_requestbuffers *p)
+{
+	return 0;
+}
+
+static unsigned int mx3_camera_poll(struct file *file, poll_table *pt)
+{
+	struct soc_camera_device *icd = file->private_data;
+
+	return vb2_poll(&icd->vb2_vidq, file, pt);
+}
+
+static int mx3_camera_querycap(struct soc_camera_host *ici,
+			       struct v4l2_capability *cap)
+{
+	/* cap->name is set by the firendly caller:-> */
+	strlcpy(cap->card, "i.MX3x Camera", sizeof(cap->card));
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+static int mx3_camera_set_bus_param(struct soc_camera_device *icd)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx3_camera_dev *mx3_cam = ici->priv;
+	struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+	u32 pixfmt = icd->current_fmt->host_fmt->fourcc;
+	unsigned long bus_flags, common_flags;
+	u32 dw, sens_conf;
+	const struct soc_mbus_pixelfmt *fmt;
+	int buswidth;
+	int ret;
+	const struct soc_camera_format_xlate *xlate;
+	struct device *dev = icd->parent;
+
+	fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code);
+	if (!fmt)
+		return -EINVAL;
+
+	xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+	if (!xlate) {
+		dev_warn(dev, "Format %x not found\n", pixfmt);
+		return -EINVAL;
+	}
+
+	buswidth = fmt->bits_per_sample;
+	ret = test_platform_param(mx3_cam, buswidth, &bus_flags);
+
+	dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret);
+
+	if (ret < 0)
+		return ret;
+
+	ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
+	if (!ret) {
+		common_flags = soc_mbus_config_compatible(&cfg,
+							  bus_flags);
+		if (!common_flags) {
+			dev_warn(icd->parent,
+				 "Flags incompatible: camera 0x%x, host 0x%lx\n",
+				 cfg.flags, bus_flags);
+			return -EINVAL;
+		}
+	} else if (ret != -ENOIOCTLCMD) {
+		return ret;
+	} else {
+		common_flags = bus_flags;
+	}
+
+	dev_dbg(dev, "Flags cam: 0x%x host: 0x%lx common: 0x%lx\n",
+		cfg.flags, bus_flags, common_flags);
+
+	/* Make choices, based on platform preferences */
+	if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
+	    (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
+		if (mx3_cam->platform_flags & MX3_CAMERA_HSP)
+			common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
+		else
+			common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
+	}
+
+	if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
+	    (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
+		if (mx3_cam->platform_flags & MX3_CAMERA_VSP)
+			common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
+		else
+			common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
+	}
+
+	if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) &&
+	    (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) {
+		if (mx3_cam->platform_flags & MX3_CAMERA_DP)
+			common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH;
+		else
+			common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW;
+	}
+
+	if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
+	    (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
+		if (mx3_cam->platform_flags & MX3_CAMERA_PCP)
+			common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
+		else
+			common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
+	}
+
+	cfg.flags = common_flags;
+	ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
+	if (ret < 0 && ret != -ENOIOCTLCMD) {
+		dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n",
+			common_flags, ret);
+		return ret;
+	}
+
+	/*
+	 * So far only gated clock mode is supported. Add a line
+	 *	(3 << CSI_SENS_CONF_SENS_PRTCL_SHIFT) |
+	 * below and select the required mode when supporting other
+	 * synchronisation protocols.
+	 */
+	sens_conf = csi_reg_read(mx3_cam, CSI_SENS_CONF) &
+		~((1 << CSI_SENS_CONF_VSYNC_POL_SHIFT) |
+		  (1 << CSI_SENS_CONF_HSYNC_POL_SHIFT) |
+		  (1 << CSI_SENS_CONF_DATA_POL_SHIFT) |
+		  (1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT) |
+		  (3 << CSI_SENS_CONF_DATA_FMT_SHIFT) |
+		  (3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT));
+
+	/* TODO: Support RGB and YUV formats */
+
+	/* This has been set in mx3_camera_activate(), but we clear it above */
+	sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER;
+
+	if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+		sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT;
+	if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+		sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT;
+	if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+		sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT;
+	if (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)
+		sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT;
+
+	/* Just do what we're asked to do */
+	switch (xlate->host_fmt->bits_per_sample) {
+	case 4:
+		dw = 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+		break;
+	case 8:
+		dw = 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+		break;
+	case 10:
+		dw = 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+		break;
+	default:
+		/*
+		 * Actually it can only be 15 now, default is just to silence
+		 * compiler warnings
+		 */
+	case 15:
+		dw = 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+	}
+
+	csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF);
+
+	dev_dbg(dev, "Set SENS_CONF to %x\n", sens_conf | dw);
+
+	return 0;
+}
+
+static struct soc_camera_host_ops mx3_soc_camera_host_ops = {
+	.owner		= THIS_MODULE,
+	.add		= mx3_camera_add_device,
+	.remove		= mx3_camera_remove_device,
+	.set_crop	= mx3_camera_set_crop,
+	.set_fmt	= mx3_camera_set_fmt,
+	.try_fmt	= mx3_camera_try_fmt,
+	.get_formats	= mx3_camera_get_formats,
+	.init_videobuf2	= mx3_camera_init_videobuf,
+	.reqbufs	= mx3_camera_reqbufs,
+	.poll		= mx3_camera_poll,
+	.querycap	= mx3_camera_querycap,
+	.set_bus_param	= mx3_camera_set_bus_param,
+};
+
+static int __devinit mx3_camera_probe(struct platform_device *pdev)
+{
+	struct mx3_camera_dev *mx3_cam;
+	struct resource *res;
+	void __iomem *base;
+	int err = 0;
+	struct soc_camera_host *soc_host;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		err = -ENODEV;
+		goto egetres;
+	}
+
+	mx3_cam = vzalloc(sizeof(*mx3_cam));
+	if (!mx3_cam) {
+		dev_err(&pdev->dev, "Could not allocate mx3 camera object\n");
+		err = -ENOMEM;
+		goto ealloc;
+	}
+
+	mx3_cam->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(mx3_cam->clk)) {
+		err = PTR_ERR(mx3_cam->clk);
+		goto eclkget;
+	}
+
+	mx3_cam->pdata = pdev->dev.platform_data;
+	mx3_cam->platform_flags = mx3_cam->pdata->flags;
+	if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_MASK)) {
+		/*
+		 * Platform hasn't set available data widths. This is bad.
+		 * Warn and use a default.
+		 */
+		dev_warn(&pdev->dev, "WARNING! Platform hasn't set available "
+			 "data widths, using default 8 bit\n");
+		mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8;
+	}
+	if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)
+		mx3_cam->width_flags = 1 << 3;
+	if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8)
+		mx3_cam->width_flags |= 1 << 7;
+	if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10)
+		mx3_cam->width_flags |= 1 << 9;
+	if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15)
+		mx3_cam->width_flags |= 1 << 14;
+
+	mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000;
+	if (!mx3_cam->mclk) {
+		dev_warn(&pdev->dev,
+			 "mclk_10khz == 0! Please, fix your platform data. "
+			 "Using default 20MHz\n");
+		mx3_cam->mclk = 20000000;
+	}
+
+	/* list of video-buffers */
+	INIT_LIST_HEAD(&mx3_cam->capture);
+	spin_lock_init(&mx3_cam->lock);
+
+	base = ioremap(res->start, resource_size(res));
+	if (!base) {
+		pr_err("Couldn't map %x@%x\n", resource_size(res), res->start);
+		err = -ENOMEM;
+		goto eioremap;
+	}
+
+	mx3_cam->base	= base;
+
+	soc_host		= &mx3_cam->soc_host;
+	soc_host->drv_name	= MX3_CAM_DRV_NAME;
+	soc_host->ops		= &mx3_soc_camera_host_ops;
+	soc_host->priv		= mx3_cam;
+	soc_host->v4l2_dev.dev	= &pdev->dev;
+	soc_host->nr		= pdev->id;
+
+	mx3_cam->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+	if (IS_ERR(mx3_cam->alloc_ctx)) {
+		err = PTR_ERR(mx3_cam->alloc_ctx);
+		goto eallocctx;
+	}
+
+	err = soc_camera_host_register(soc_host);
+	if (err)
+		goto ecamhostreg;
+
+	/* IDMAC interface */
+	dmaengine_get();
+
+	return 0;
+
+ecamhostreg:
+	vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx);
+eallocctx:
+	iounmap(base);
+eioremap:
+	clk_put(mx3_cam->clk);
+eclkget:
+	vfree(mx3_cam);
+ealloc:
+egetres:
+	return err;
+}
+
+static int __devexit mx3_camera_remove(struct platform_device *pdev)
+{
+	struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+	struct mx3_camera_dev *mx3_cam = container_of(soc_host,
+					struct mx3_camera_dev, soc_host);
+
+	clk_put(mx3_cam->clk);
+
+	soc_camera_host_unregister(soc_host);
+
+	iounmap(mx3_cam->base);
+
+	/*
+	 * The channel has either not been allocated,
+	 * or should have been released
+	 */
+	if (WARN_ON(mx3_cam->idmac_channel[0]))
+		dma_release_channel(&mx3_cam->idmac_channel[0]->dma_chan);
+
+	vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx);
+
+	vfree(mx3_cam);
+
+	dmaengine_put();
+
+	return 0;
+}
+
+static struct platform_driver mx3_camera_driver = {
+	.driver 	= {
+		.name	= MX3_CAM_DRV_NAME,
+	},
+	.probe		= mx3_camera_probe,
+	.remove		= __devexit_p(mx3_camera_remove),
+};
+
+module_platform_driver(mx3_camera_driver);
+
+MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.2.3");
+MODULE_ALIAS("platform:" MX3_CAM_DRV_NAME);
diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig
new file mode 100644
index 0000000..390ab09
--- /dev/null
+++ b/drivers/media/platform/omap/Kconfig
@@ -0,0 +1,14 @@
+config VIDEO_OMAP2_VOUT_VRFB
+	bool
+
+config VIDEO_OMAP2_VOUT
+	tristate "OMAP2/OMAP3 V4L2-Display driver"
+	depends on ARCH_OMAP2 || ARCH_OMAP3
+	select VIDEOBUF_GEN
+	select VIDEOBUF_DMA_CONTIG
+	select OMAP2_DSS
+	select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
+	select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB
+	default n
+	---help---
+	  V4L2 Display driver support for OMAP2/3 based boards.
diff --git a/drivers/media/platform/omap/Makefile b/drivers/media/platform/omap/Makefile
new file mode 100644
index 0000000..d80df41
--- /dev/null
+++ b/drivers/media/platform/omap/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the omap video device drivers.
+#
+
+# OMAP2/3 Display driver
+omap-vout-y += omap_vout.o omap_voutlib.o
+omap-vout-$(CONFIG_VIDEO_OMAP2_VOUT_VRFB) += omap_vout_vrfb.o
+obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout.o
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
new file mode 100644
index 0000000..45797aa
--- /dev/null
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -0,0 +1,2289 @@
+/*
+ * omap_vout.c
+ *
+ * Copyright (C) 2005-2010 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * Leveraged code from the OMAP2 camera driver
+ * Video-for-Linux (Version 2) camera capture driver for
+ * the OMAP24xx camera controller.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * History:
+ * 20-APR-2006 Khasim		Modified VRFB based Rotation,
+ *				The image data is always read from 0 degree
+ *				view and written
+ *				to the virtual space of desired rotation angle
+ * 4-DEC-2006  Jian		Changed to support better memory management
+ *
+ * 17-Nov-2008 Hardik		Changed driver to use video_ioctl2
+ *
+ * 23-Feb-2010 Vaibhav H	Modified to use new DSS2 interface
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/videodev2.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+
+#include <media/videobuf-dma-contig.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+
+#include <plat/dma.h>
+#include <plat/vrfb.h>
+#include <video/omapdss.h>
+
+#include "omap_voutlib.h"
+#include "omap_voutdef.h"
+#include "omap_vout_vrfb.h"
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("OMAP Video for Linux Video out driver");
+MODULE_LICENSE("GPL");
+
+/* Driver Configuration macros */
+#define VOUT_NAME		"omap_vout"
+
+enum omap_vout_channels {
+	OMAP_VIDEO1,
+	OMAP_VIDEO2,
+};
+
+static struct videobuf_queue_ops video_vbq_ops;
+/* Variables configurable through module params*/
+static u32 video1_numbuffers = 3;
+static u32 video2_numbuffers = 3;
+static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
+static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
+static bool vid1_static_vrfb_alloc;
+static bool vid2_static_vrfb_alloc;
+static bool debug;
+
+/* Module parameters */
+module_param(video1_numbuffers, uint, S_IRUGO);
+MODULE_PARM_DESC(video1_numbuffers,
+	"Number of buffers to be allocated at init time for Video1 device.");
+
+module_param(video2_numbuffers, uint, S_IRUGO);
+MODULE_PARM_DESC(video2_numbuffers,
+	"Number of buffers to be allocated at init time for Video2 device.");
+
+module_param(video1_bufsize, uint, S_IRUGO);
+MODULE_PARM_DESC(video1_bufsize,
+	"Size of the buffer to be allocated for video1 device");
+
+module_param(video2_bufsize, uint, S_IRUGO);
+MODULE_PARM_DESC(video2_bufsize,
+	"Size of the buffer to be allocated for video2 device");
+
+module_param(vid1_static_vrfb_alloc, bool, S_IRUGO);
+MODULE_PARM_DESC(vid1_static_vrfb_alloc,
+	"Static allocation of the VRFB buffer for video1 device");
+
+module_param(vid2_static_vrfb_alloc, bool, S_IRUGO);
+MODULE_PARM_DESC(vid2_static_vrfb_alloc,
+	"Static allocation of the VRFB buffer for video2 device");
+
+module_param(debug, bool, S_IRUGO);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/* list of image formats supported by OMAP2 video pipelines */
+static const struct v4l2_fmtdesc omap_formats[] = {
+	{
+		/* Note:  V4L2 defines RGB565 as:
+		 *
+		 *      Byte 0                    Byte 1
+		 *      g2 g1 g0 r4 r3 r2 r1 r0   b4 b3 b2 b1 b0 g5 g4 g3
+		 *
+		 * We interpret RGB565 as:
+		 *
+		 *      Byte 0                    Byte 1
+		 *      g2 g1 g0 b4 b3 b2 b1 b0   r4 r3 r2 r1 r0 g5 g4 g3
+		 */
+		.description = "RGB565, le",
+		.pixelformat = V4L2_PIX_FMT_RGB565,
+	},
+	{
+		/* Note:  V4L2 defines RGB32 as: RGB-8-8-8-8  we use
+		 *  this for RGB24 unpack mode, the last 8 bits are ignored
+		 * */
+		.description = "RGB32, le",
+		.pixelformat = V4L2_PIX_FMT_RGB32,
+	},
+	{
+		/* Note:  V4L2 defines RGB24 as: RGB-8-8-8  we use
+		 *        this for RGB24 packed mode
+		 *
+		 */
+		.description = "RGB24, le",
+		.pixelformat = V4L2_PIX_FMT_RGB24,
+	},
+	{
+		.description = "YUYV (YUV 4:2:2), packed",
+		.pixelformat = V4L2_PIX_FMT_YUYV,
+	},
+	{
+		.description = "UYVY, packed",
+		.pixelformat = V4L2_PIX_FMT_UYVY,
+	},
+};
+
+#define NUM_OUTPUT_FORMATS (ARRAY_SIZE(omap_formats))
+
+/*
+ * Try format
+ */
+static int omap_vout_try_format(struct v4l2_pix_format *pix)
+{
+	int ifmt, bpp = 0;
+
+	pix->height = clamp(pix->height, (u32)VID_MIN_HEIGHT,
+						(u32)VID_MAX_HEIGHT);
+	pix->width = clamp(pix->width, (u32)VID_MIN_WIDTH, (u32)VID_MAX_WIDTH);
+
+	for (ifmt = 0; ifmt < NUM_OUTPUT_FORMATS; ifmt++) {
+		if (pix->pixelformat == omap_formats[ifmt].pixelformat)
+			break;
+	}
+
+	if (ifmt == NUM_OUTPUT_FORMATS)
+		ifmt = 0;
+
+	pix->pixelformat = omap_formats[ifmt].pixelformat;
+	pix->field = V4L2_FIELD_ANY;
+	pix->priv = 0;
+
+	switch (pix->pixelformat) {
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_UYVY:
+	default:
+		pix->colorspace = V4L2_COLORSPACE_JPEG;
+		bpp = YUYV_BPP;
+		break;
+	case V4L2_PIX_FMT_RGB565:
+	case V4L2_PIX_FMT_RGB565X:
+		pix->colorspace = V4L2_COLORSPACE_SRGB;
+		bpp = RGB565_BPP;
+		break;
+	case V4L2_PIX_FMT_RGB24:
+		pix->colorspace = V4L2_COLORSPACE_SRGB;
+		bpp = RGB24_BPP;
+		break;
+	case V4L2_PIX_FMT_RGB32:
+	case V4L2_PIX_FMT_BGR32:
+		pix->colorspace = V4L2_COLORSPACE_SRGB;
+		bpp = RGB32_BPP;
+		break;
+	}
+	pix->bytesperline = pix->width * bpp;
+	pix->sizeimage = pix->bytesperline * pix->height;
+
+	return bpp;
+}
+
+/*
+ * omap_vout_uservirt_to_phys: This inline function is used to convert user
+ * space virtual address to physical address.
+ */
+static u32 omap_vout_uservirt_to_phys(u32 virtp)
+{
+	unsigned long physp = 0;
+	struct vm_area_struct *vma;
+	struct mm_struct *mm = current->mm;
+
+	vma = find_vma(mm, virtp);
+	/* For kernel direct-mapped memory, take the easy way */
+	if (virtp >= PAGE_OFFSET) {
+		physp = virt_to_phys((void *) virtp);
+	} else if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) {
+		/* this will catch, kernel-allocated, mmaped-to-usermode
+		   addresses */
+		physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
+	} else {
+		/* otherwise, use get_user_pages() for general userland pages */
+		int res, nr_pages = 1;
+		struct page *pages;
+		down_read(&current->mm->mmap_sem);
+
+		res = get_user_pages(current, current->mm, virtp, nr_pages, 1,
+				0, &pages, NULL);
+		up_read(&current->mm->mmap_sem);
+
+		if (res == nr_pages) {
+			physp =  __pa(page_address(&pages[0]) +
+					(virtp & ~PAGE_MASK));
+		} else {
+			printk(KERN_WARNING VOUT_NAME
+					"get_user_pages failed\n");
+			return 0;
+		}
+	}
+
+	return physp;
+}
+
+/*
+ * Free the V4L2 buffers
+ */
+void omap_vout_free_buffers(struct omap_vout_device *vout)
+{
+	int i, numbuffers;
+
+	/* Allocate memory for the buffers */
+	numbuffers = (vout->vid) ?  video2_numbuffers : video1_numbuffers;
+	vout->buffer_size = (vout->vid) ? video2_bufsize : video1_bufsize;
+
+	for (i = 0; i < numbuffers; i++) {
+		omap_vout_free_buffer(vout->buf_virt_addr[i],
+				vout->buffer_size);
+		vout->buf_phy_addr[i] = 0;
+		vout->buf_virt_addr[i] = 0;
+	}
+}
+
+/*
+ * Convert V4L2 rotation to DSS rotation
+ *	V4L2 understand 0, 90, 180, 270.
+ *	Convert to 0, 1, 2 and 3 respectively for DSS
+ */
+static int v4l2_rot_to_dss_rot(int v4l2_rotation,
+			enum dss_rotation *rotation, bool mirror)
+{
+	int ret = 0;
+
+	switch (v4l2_rotation) {
+	case 90:
+		*rotation = dss_rotation_90_degree;
+		break;
+	case 180:
+		*rotation = dss_rotation_180_degree;
+		break;
+	case 270:
+		*rotation = dss_rotation_270_degree;
+		break;
+	case 0:
+		*rotation = dss_rotation_0_degree;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int omap_vout_calculate_offset(struct omap_vout_device *vout)
+{
+	struct omapvideo_info *ovid;
+	struct v4l2_rect *crop = &vout->crop;
+	struct v4l2_pix_format *pix = &vout->pix;
+	int *cropped_offset = &vout->cropped_offset;
+	int ps = 2, line_length = 0;
+
+	ovid = &vout->vid_info;
+
+	if (ovid->rotation_type == VOUT_ROT_VRFB) {
+		omap_vout_calculate_vrfb_offset(vout);
+	} else {
+		vout->line_length = line_length = pix->width;
+
+		if (V4L2_PIX_FMT_YUYV == pix->pixelformat ||
+			V4L2_PIX_FMT_UYVY == pix->pixelformat)
+			ps = 2;
+		else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat)
+			ps = 4;
+		else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat)
+			ps = 3;
+
+		vout->ps = ps;
+
+		*cropped_offset = (line_length * ps) *
+			crop->top + crop->left * ps;
+	}
+
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "%s Offset:%x\n",
+			__func__, vout->cropped_offset);
+
+	return 0;
+}
+
+/*
+ * Convert V4L2 pixel format to DSS pixel format
+ */
+static int video_mode_to_dss_mode(struct omap_vout_device *vout)
+{
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid;
+	struct v4l2_pix_format *pix = &vout->pix;
+	enum omap_color_mode mode;
+
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+
+	switch (pix->pixelformat) {
+	case 0:
+		break;
+	case V4L2_PIX_FMT_YUYV:
+		mode = OMAP_DSS_COLOR_YUV2;
+		break;
+	case V4L2_PIX_FMT_UYVY:
+		mode = OMAP_DSS_COLOR_UYVY;
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		mode = OMAP_DSS_COLOR_RGB16;
+		break;
+	case V4L2_PIX_FMT_RGB24:
+		mode = OMAP_DSS_COLOR_RGB24P;
+		break;
+	case V4L2_PIX_FMT_RGB32:
+		mode = (ovl->id == OMAP_DSS_VIDEO1) ?
+			OMAP_DSS_COLOR_RGB24U : OMAP_DSS_COLOR_ARGB32;
+		break;
+	case V4L2_PIX_FMT_BGR32:
+		mode = OMAP_DSS_COLOR_RGBX32;
+		break;
+	default:
+		mode = -EINVAL;
+	}
+	return mode;
+}
+
+/*
+ * Setup the overlay
+ */
+static int omapvid_setup_overlay(struct omap_vout_device *vout,
+		struct omap_overlay *ovl, int posx, int posy, int outw,
+		int outh, u32 addr)
+{
+	int ret = 0;
+	struct omap_overlay_info info;
+	int cropheight, cropwidth, pixheight, pixwidth;
+
+	if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 &&
+			(outw != vout->pix.width || outh != vout->pix.height)) {
+		ret = -EINVAL;
+		goto setup_ovl_err;
+	}
+
+	vout->dss_mode = video_mode_to_dss_mode(vout);
+	if (vout->dss_mode == -EINVAL) {
+		ret = -EINVAL;
+		goto setup_ovl_err;
+	}
+
+	/* Setup the input plane parameters according to
+	 * rotation value selected.
+	 */
+	if (is_rotation_90_or_270(vout)) {
+		cropheight = vout->crop.width;
+		cropwidth = vout->crop.height;
+		pixheight = vout->pix.width;
+		pixwidth = vout->pix.height;
+	} else {
+		cropheight = vout->crop.height;
+		cropwidth = vout->crop.width;
+		pixheight = vout->pix.height;
+		pixwidth = vout->pix.width;
+	}
+
+	ovl->get_overlay_info(ovl, &info);
+	info.paddr = addr;
+	info.width = cropwidth;
+	info.height = cropheight;
+	info.color_mode = vout->dss_mode;
+	info.mirror = vout->mirror;
+	info.pos_x = posx;
+	info.pos_y = posy;
+	info.out_width = outw;
+	info.out_height = outh;
+	info.global_alpha = vout->win.global_alpha;
+	if (!is_rotation_enabled(vout)) {
+		info.rotation = 0;
+		info.rotation_type = OMAP_DSS_ROT_DMA;
+		info.screen_width = pixwidth;
+	} else {
+		info.rotation = vout->rotation;
+		info.rotation_type = OMAP_DSS_ROT_VRFB;
+		info.screen_width = 2048;
+	}
+
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
+		"%s enable=%d addr=%x width=%d\n height=%d color_mode=%d\n"
+		"rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n"
+		"out_height=%d rotation_type=%d screen_width=%d\n",
+		__func__, ovl->is_enabled(ovl), info.paddr, info.width, info.height,
+		info.color_mode, info.rotation, info.mirror, info.pos_x,
+		info.pos_y, info.out_width, info.out_height, info.rotation_type,
+		info.screen_width);
+
+	ret = ovl->set_overlay_info(ovl, &info);
+	if (ret)
+		goto setup_ovl_err;
+
+	return 0;
+
+setup_ovl_err:
+	v4l2_warn(&vout->vid_dev->v4l2_dev, "setup_overlay failed\n");
+	return ret;
+}
+
+/*
+ * Initialize the overlay structure
+ */
+static int omapvid_init(struct omap_vout_device *vout, u32 addr)
+{
+	int ret = 0, i;
+	struct v4l2_window *win;
+	struct omap_overlay *ovl;
+	int posx, posy, outw, outh, temp;
+	struct omap_video_timings *timing;
+	struct omapvideo_info *ovid = &vout->vid_info;
+
+	win = &vout->win;
+	for (i = 0; i < ovid->num_overlays; i++) {
+		ovl = ovid->overlays[i];
+		if (!ovl->manager || !ovl->manager->device)
+			return -EINVAL;
+
+		timing = &ovl->manager->device->panel.timings;
+
+		outw = win->w.width;
+		outh = win->w.height;
+		switch (vout->rotation) {
+		case dss_rotation_90_degree:
+			/* Invert the height and width for 90
+			 * and 270 degree rotation
+			 */
+			temp = outw;
+			outw = outh;
+			outh = temp;
+			posy = (timing->y_res - win->w.width) - win->w.left;
+			posx = win->w.top;
+			break;
+
+		case dss_rotation_180_degree:
+			posx = (timing->x_res - win->w.width) - win->w.left;
+			posy = (timing->y_res - win->w.height) - win->w.top;
+			break;
+
+		case dss_rotation_270_degree:
+			temp = outw;
+			outw = outh;
+			outh = temp;
+			posy = win->w.left;
+			posx = (timing->x_res - win->w.height) - win->w.top;
+			break;
+
+		default:
+			posx = win->w.left;
+			posy = win->w.top;
+			break;
+		}
+
+		ret = omapvid_setup_overlay(vout, ovl, posx, posy,
+				outw, outh, addr);
+		if (ret)
+			goto omapvid_init_err;
+	}
+	return 0;
+
+omapvid_init_err:
+	v4l2_warn(&vout->vid_dev->v4l2_dev, "apply_changes failed\n");
+	return ret;
+}
+
+/*
+ * Apply the changes set the go bit of DSS
+ */
+static int omapvid_apply_changes(struct omap_vout_device *vout)
+{
+	int i;
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid = &vout->vid_info;
+
+	for (i = 0; i < ovid->num_overlays; i++) {
+		ovl = ovid->overlays[i];
+		if (!ovl->manager || !ovl->manager->device)
+			return -EINVAL;
+		ovl->manager->apply(ovl->manager);
+	}
+
+	return 0;
+}
+
+static int omapvid_handle_interlace_display(struct omap_vout_device *vout,
+		unsigned int irqstatus, struct timeval timevalue)
+{
+	u32 fid;
+
+	if (vout->first_int) {
+		vout->first_int = 0;
+		goto err;
+	}
+
+	if (irqstatus & DISPC_IRQ_EVSYNC_ODD)
+		fid = 1;
+	else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN)
+		fid = 0;
+	else
+		goto err;
+
+	vout->field_id ^= 1;
+	if (fid != vout->field_id) {
+		if (fid == 0)
+			vout->field_id = fid;
+	} else if (0 == fid) {
+		if (vout->cur_frm == vout->next_frm)
+			goto err;
+
+		vout->cur_frm->ts = timevalue;
+		vout->cur_frm->state = VIDEOBUF_DONE;
+		wake_up_interruptible(&vout->cur_frm->done);
+		vout->cur_frm = vout->next_frm;
+	} else {
+		if (list_empty(&vout->dma_queue) ||
+				(vout->cur_frm != vout->next_frm))
+			goto err;
+	}
+
+	return vout->field_id;
+err:
+	return 0;
+}
+
+static void omap_vout_isr(void *arg, unsigned int irqstatus)
+{
+	int ret, fid, mgr_id;
+	u32 addr, irq;
+	struct omap_overlay *ovl;
+	struct timeval timevalue;
+	struct omapvideo_info *ovid;
+	struct omap_dss_device *cur_display;
+	struct omap_vout_device *vout = (struct omap_vout_device *)arg;
+
+	if (!vout->streaming)
+		return;
+
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+	/* get the display device attached to the overlay */
+	if (!ovl->manager || !ovl->manager->device)
+		return;
+
+	mgr_id = ovl->manager->id;
+	cur_display = ovl->manager->device;
+
+	spin_lock(&vout->vbq_lock);
+	do_gettimeofday(&timevalue);
+
+	switch (cur_display->type) {
+	case OMAP_DISPLAY_TYPE_DSI:
+	case OMAP_DISPLAY_TYPE_DPI:
+		if (mgr_id == OMAP_DSS_CHANNEL_LCD)
+			irq = DISPC_IRQ_VSYNC;
+		else if (mgr_id == OMAP_DSS_CHANNEL_LCD2)
+			irq = DISPC_IRQ_VSYNC2;
+		else
+			goto vout_isr_err;
+
+		if (!(irqstatus & irq))
+			goto vout_isr_err;
+		break;
+	case OMAP_DISPLAY_TYPE_VENC:
+		fid = omapvid_handle_interlace_display(vout, irqstatus,
+				timevalue);
+		if (!fid)
+			goto vout_isr_err;
+		break;
+	case OMAP_DISPLAY_TYPE_HDMI:
+		if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN))
+			goto vout_isr_err;
+		break;
+	default:
+		goto vout_isr_err;
+	}
+
+	if (!vout->first_int && (vout->cur_frm != vout->next_frm)) {
+		vout->cur_frm->ts = timevalue;
+		vout->cur_frm->state = VIDEOBUF_DONE;
+		wake_up_interruptible(&vout->cur_frm->done);
+		vout->cur_frm = vout->next_frm;
+	}
+
+	vout->first_int = 0;
+	if (list_empty(&vout->dma_queue))
+		goto vout_isr_err;
+
+	vout->next_frm = list_entry(vout->dma_queue.next,
+			struct videobuf_buffer, queue);
+	list_del(&vout->next_frm->queue);
+
+	vout->next_frm->state = VIDEOBUF_ACTIVE;
+
+	addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i]
+		+ vout->cropped_offset;
+
+	/* First save the configuration in ovelray structure */
+	ret = omapvid_init(vout, addr);
+	if (ret)
+		printk(KERN_ERR VOUT_NAME
+			"failed to set overlay info\n");
+	/* Enable the pipeline and set the Go bit */
+	ret = omapvid_apply_changes(vout);
+	if (ret)
+		printk(KERN_ERR VOUT_NAME "failed to change mode\n");
+
+vout_isr_err:
+	spin_unlock(&vout->vbq_lock);
+}
+
+/* Video buffer call backs */
+
+/*
+ * Buffer setup function is called by videobuf layer when REQBUF ioctl is
+ * called. This is used to setup buffers and return size and count of
+ * buffers allocated. After the call to this buffer, videobuf layer will
+ * setup buffer queue depending on the size and count of buffers
+ */
+static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
+			  unsigned int *size)
+{
+	int startindex = 0, i, j;
+	u32 phy_addr = 0, virt_addr = 0;
+	struct omap_vout_device *vout = q->priv_data;
+	struct omapvideo_info *ovid = &vout->vid_info;
+	int vid_max_buf_size;
+
+	if (!vout)
+		return -EINVAL;
+
+	vid_max_buf_size = vout->vid == OMAP_VIDEO1 ? video1_bufsize :
+		video2_bufsize;
+
+	if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type)
+		return -EINVAL;
+
+	startindex = (vout->vid == OMAP_VIDEO1) ?
+		video1_numbuffers : video2_numbuffers;
+	if (V4L2_MEMORY_MMAP == vout->memory && *count < startindex)
+		*count = startindex;
+
+	if (ovid->rotation_type == VOUT_ROT_VRFB) {
+		if (omap_vout_vrfb_buffer_setup(vout, count, startindex))
+			return -ENOMEM;
+	}
+
+	if (V4L2_MEMORY_MMAP != vout->memory)
+		return 0;
+
+	/* Now allocated the V4L2 buffers */
+	*size = PAGE_ALIGN(vout->pix.width * vout->pix.height * vout->bpp);
+	startindex = (vout->vid == OMAP_VIDEO1) ?
+		video1_numbuffers : video2_numbuffers;
+
+	/* Check the size of the buffer */
+	if (*size > vid_max_buf_size) {
+		v4l2_err(&vout->vid_dev->v4l2_dev,
+				"buffer allocation mismatch [%u] [%u]\n",
+				*size, vout->buffer_size);
+		return -ENOMEM;
+	}
+
+	for (i = startindex; i < *count; i++) {
+		vout->buffer_size = *size;
+
+		virt_addr = omap_vout_alloc_buffer(vout->buffer_size,
+				&phy_addr);
+		if (!virt_addr) {
+			if (ovid->rotation_type == VOUT_ROT_NONE) {
+				break;
+			} else {
+				if (!is_rotation_enabled(vout))
+					break;
+			/* Free the VRFB buffers if no space for V4L2 buffers */
+			for (j = i; j < *count; j++) {
+				omap_vout_free_buffer(
+						vout->smsshado_virt_addr[j],
+						vout->smsshado_size);
+				vout->smsshado_virt_addr[j] = 0;
+				vout->smsshado_phy_addr[j] = 0;
+				}
+			}
+		}
+		vout->buf_virt_addr[i] = virt_addr;
+		vout->buf_phy_addr[i] = phy_addr;
+	}
+	*count = vout->buffer_allocated = i;
+
+	return 0;
+}
+
+/*
+ * Free the V4L2 buffers additionally allocated than default
+ * number of buffers
+ */
+static void omap_vout_free_extra_buffers(struct omap_vout_device *vout)
+{
+	int num_buffers = 0, i;
+
+	num_buffers = (vout->vid == OMAP_VIDEO1) ?
+		video1_numbuffers : video2_numbuffers;
+
+	for (i = num_buffers; i < vout->buffer_allocated; i++) {
+		if (vout->buf_virt_addr[i])
+			omap_vout_free_buffer(vout->buf_virt_addr[i],
+					vout->buffer_size);
+
+		vout->buf_virt_addr[i] = 0;
+		vout->buf_phy_addr[i] = 0;
+	}
+	vout->buffer_allocated = num_buffers;
+}
+
+/*
+ * This function will be called when VIDIOC_QBUF ioctl is called.
+ * It prepare buffers before give out for the display. This function
+ * converts user space virtual address into physical address if userptr memory
+ * exchange mechanism is used. If rotation is enabled, it copies entire
+ * buffer into VRFB memory space before giving it to the DSS.
+ */
+static int omap_vout_buffer_prepare(struct videobuf_queue *q,
+			struct videobuf_buffer *vb,
+			enum v4l2_field field)
+{
+	struct omap_vout_device *vout = q->priv_data;
+	struct omapvideo_info *ovid = &vout->vid_info;
+
+	if (VIDEOBUF_NEEDS_INIT == vb->state) {
+		vb->width = vout->pix.width;
+		vb->height = vout->pix.height;
+		vb->size = vb->width * vb->height * vout->bpp;
+		vb->field = field;
+	}
+	vb->state = VIDEOBUF_PREPARED;
+	/* if user pointer memory mechanism is used, get the physical
+	 * address of the buffer
+	 */
+	if (V4L2_MEMORY_USERPTR == vb->memory) {
+		if (0 == vb->baddr)
+			return -EINVAL;
+		/* Physical address */
+		vout->queued_buf_addr[vb->i] = (u8 *)
+			omap_vout_uservirt_to_phys(vb->baddr);
+	} else {
+		u32 addr, dma_addr;
+		unsigned long size;
+
+		addr = (unsigned long) vout->buf_virt_addr[vb->i];
+		size = (unsigned long) vb->size;
+
+		dma_addr = dma_map_single(vout->vid_dev->v4l2_dev.dev, (void *) addr,
+				size, DMA_TO_DEVICE);
+		if (dma_mapping_error(vout->vid_dev->v4l2_dev.dev, dma_addr))
+			v4l2_err(&vout->vid_dev->v4l2_dev, "dma_map_single failed\n");
+
+		vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i];
+	}
+
+	if (ovid->rotation_type == VOUT_ROT_VRFB)
+		return omap_vout_prepare_vrfb(vout, vb);
+	else
+		return 0;
+}
+
+/*
+ * Buffer queue function will be called from the videobuf layer when _QBUF
+ * ioctl is called. It is used to enqueue buffer, which is ready to be
+ * displayed.
+ */
+static void omap_vout_buffer_queue(struct videobuf_queue *q,
+			  struct videobuf_buffer *vb)
+{
+	struct omap_vout_device *vout = q->priv_data;
+
+	/* Driver is also maintainig a queue. So enqueue buffer in the driver
+	 * queue */
+	list_add_tail(&vb->queue, &vout->dma_queue);
+
+	vb->state = VIDEOBUF_QUEUED;
+}
+
+/*
+ * Buffer release function is called from videobuf layer to release buffer
+ * which are already allocated
+ */
+static void omap_vout_buffer_release(struct videobuf_queue *q,
+			    struct videobuf_buffer *vb)
+{
+	struct omap_vout_device *vout = q->priv_data;
+
+	vb->state = VIDEOBUF_NEEDS_INIT;
+
+	if (V4L2_MEMORY_MMAP != vout->memory)
+		return;
+}
+
+/*
+ *  File operations
+ */
+static unsigned int omap_vout_poll(struct file *file,
+				   struct poll_table_struct *wait)
+{
+	struct omap_vout_device *vout = file->private_data;
+	struct videobuf_queue *q = &vout->vbq;
+
+	return videobuf_poll_stream(file, q, wait);
+}
+
+static void omap_vout_vm_open(struct vm_area_struct *vma)
+{
+	struct omap_vout_device *vout = vma->vm_private_data;
+
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
+		"vm_open [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
+	vout->mmap_count++;
+}
+
+static void omap_vout_vm_close(struct vm_area_struct *vma)
+{
+	struct omap_vout_device *vout = vma->vm_private_data;
+
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
+		"vm_close [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
+	vout->mmap_count--;
+}
+
+static struct vm_operations_struct omap_vout_vm_ops = {
+	.open	= omap_vout_vm_open,
+	.close	= omap_vout_vm_close,
+};
+
+static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	int i;
+	void *pos;
+	unsigned long start = vma->vm_start;
+	unsigned long size = (vma->vm_end - vma->vm_start);
+	struct omap_vout_device *vout = file->private_data;
+	struct videobuf_queue *q = &vout->vbq;
+
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
+			" %s pgoff=0x%lx, start=0x%lx, end=0x%lx\n", __func__,
+			vma->vm_pgoff, vma->vm_start, vma->vm_end);
+
+	/* look for the buffer to map */
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (NULL == q->bufs[i])
+			continue;
+		if (V4L2_MEMORY_MMAP != q->bufs[i]->memory)
+			continue;
+		if (q->bufs[i]->boff == (vma->vm_pgoff << PAGE_SHIFT))
+			break;
+	}
+
+	if (VIDEO_MAX_FRAME == i) {
+		v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
+				"offset invalid [offset=0x%lx]\n",
+				(vma->vm_pgoff << PAGE_SHIFT));
+		return -EINVAL;
+	}
+	/* Check the size of the buffer */
+	if (size > vout->buffer_size) {
+		v4l2_err(&vout->vid_dev->v4l2_dev,
+				"insufficient memory [%lu] [%u]\n",
+				size, vout->buffer_size);
+		return -ENOMEM;
+	}
+
+	q->bufs[i]->baddr = vma->vm_start;
+
+	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+	vma->vm_ops = &omap_vout_vm_ops;
+	vma->vm_private_data = (void *) vout;
+	pos = (void *)vout->buf_virt_addr[i];
+	vma->vm_pgoff = virt_to_phys((void *)pos) >> PAGE_SHIFT;
+	while (size > 0) {
+		unsigned long pfn;
+		pfn = virt_to_phys((void *) pos) >> PAGE_SHIFT;
+		if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED))
+			return -EAGAIN;
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+	vout->mmap_count++;
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
+
+	return 0;
+}
+
+static int omap_vout_release(struct file *file)
+{
+	unsigned int ret, i;
+	struct videobuf_queue *q;
+	struct omapvideo_info *ovid;
+	struct omap_vout_device *vout = file->private_data;
+
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__);
+	ovid = &vout->vid_info;
+
+	if (!vout)
+		return 0;
+
+	q = &vout->vbq;
+	/* Disable all the overlay managers connected with this interface */
+	for (i = 0; i < ovid->num_overlays; i++) {
+		struct omap_overlay *ovl = ovid->overlays[i];
+		if (ovl->manager && ovl->manager->device)
+			ovl->disable(ovl);
+	}
+	/* Turn off the pipeline */
+	ret = omapvid_apply_changes(vout);
+	if (ret)
+		v4l2_warn(&vout->vid_dev->v4l2_dev,
+				"Unable to apply changes\n");
+
+	/* Free all buffers */
+	omap_vout_free_extra_buffers(vout);
+
+	/* Free the VRFB buffers only if they are allocated
+	 * during reqbufs.  Don't free if init time allocated
+	 */
+	if (ovid->rotation_type == VOUT_ROT_VRFB) {
+		if (!vout->vrfb_static_allocation)
+			omap_vout_free_vrfb_buffers(vout);
+	}
+	videobuf_mmap_free(q);
+
+	/* Even if apply changes fails we should continue
+	   freeing allocated memory */
+	if (vout->streaming) {
+		u32 mask = 0;
+
+		mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN |
+			DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2;
+		omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
+		vout->streaming = 0;
+
+		videobuf_streamoff(q);
+		videobuf_queue_cancel(q);
+	}
+
+	if (vout->mmap_count != 0)
+		vout->mmap_count = 0;
+
+	vout->opened -= 1;
+	file->private_data = NULL;
+
+	if (vout->buffer_allocated)
+		videobuf_mmap_free(q);
+
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
+	return ret;
+}
+
+static int omap_vout_open(struct file *file)
+{
+	struct videobuf_queue *q;
+	struct omap_vout_device *vout = NULL;
+
+	vout = video_drvdata(file);
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__);
+
+	if (vout == NULL)
+		return -ENODEV;
+
+	/* for now, we only support single open */
+	if (vout->opened)
+		return -EBUSY;
+
+	vout->opened += 1;
+
+	file->private_data = vout;
+	vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+	q = &vout->vbq;
+	video_vbq_ops.buf_setup = omap_vout_buffer_setup;
+	video_vbq_ops.buf_prepare = omap_vout_buffer_prepare;
+	video_vbq_ops.buf_release = omap_vout_buffer_release;
+	video_vbq_ops.buf_queue = omap_vout_buffer_queue;
+	spin_lock_init(&vout->vbq_lock);
+
+	videobuf_queue_dma_contig_init(q, &video_vbq_ops, q->dev,
+			&vout->vbq_lock, vout->type, V4L2_FIELD_NONE,
+			sizeof(struct videobuf_buffer), vout, NULL);
+
+	v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
+	return 0;
+}
+
+/*
+ * V4L2 ioctls
+ */
+static int vidioc_querycap(struct file *file, void *fh,
+		struct v4l2_capability *cap)
+{
+	struct omap_vout_device *vout = fh;
+
+	strlcpy(cap->driver, VOUT_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, vout->vfd->name, sizeof(cap->card));
+	cap->bus_info[0] = '\0';
+	cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT |
+		V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
+
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *fh,
+			struct v4l2_fmtdesc *fmt)
+{
+	int index = fmt->index;
+
+	if (index >= NUM_OUTPUT_FORMATS)
+		return -EINVAL;
+
+	fmt->flags = omap_formats[index].flags;
+	strlcpy(fmt->description, omap_formats[index].description,
+			sizeof(fmt->description));
+	fmt->pixelformat = omap_formats[index].pixelformat;
+
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_out(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	struct omap_vout_device *vout = fh;
+
+	f->fmt.pix = vout->pix;
+	return 0;
+
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid;
+	struct omap_video_timings *timing;
+	struct omap_vout_device *vout = fh;
+
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+
+	if (!ovl->manager || !ovl->manager->device)
+		return -EINVAL;
+	/* get the display device attached to the overlay */
+	timing = &ovl->manager->device->panel.timings;
+
+	vout->fbuf.fmt.height = timing->y_res;
+	vout->fbuf.fmt.width = timing->x_res;
+
+	omap_vout_try_format(&f->fmt.pix);
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	int ret, bpp;
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid;
+	struct omap_video_timings *timing;
+	struct omap_vout_device *vout = fh;
+
+	if (vout->streaming)
+		return -EBUSY;
+
+	mutex_lock(&vout->lock);
+
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+
+	/* get the display device attached to the overlay */
+	if (!ovl->manager || !ovl->manager->device) {
+		ret = -EINVAL;
+		goto s_fmt_vid_out_exit;
+	}
+	timing = &ovl->manager->device->panel.timings;
+
+	/* We dont support RGB24-packed mode if vrfb rotation
+	 * is enabled*/
+	if ((is_rotation_enabled(vout)) &&
+			f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) {
+		ret = -EINVAL;
+		goto s_fmt_vid_out_exit;
+	}
+
+	/* get the framebuffer parameters */
+
+	if (is_rotation_90_or_270(vout)) {
+		vout->fbuf.fmt.height = timing->x_res;
+		vout->fbuf.fmt.width = timing->y_res;
+	} else {
+		vout->fbuf.fmt.height = timing->y_res;
+		vout->fbuf.fmt.width = timing->x_res;
+	}
+
+	/* change to samller size is OK */
+
+	bpp = omap_vout_try_format(&f->fmt.pix);
+	f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height * bpp;
+
+	/* try & set the new output format */
+	vout->bpp = bpp;
+	vout->pix = f->fmt.pix;
+	vout->vrfb_bpp = 1;
+
+	/* If YUYV then vrfb bpp is 2, for  others its 1 */
+	if (V4L2_PIX_FMT_YUYV == vout->pix.pixelformat ||
+			V4L2_PIX_FMT_UYVY == vout->pix.pixelformat)
+		vout->vrfb_bpp = 2;
+
+	/* set default crop and win */
+	omap_vout_new_format(&vout->pix, &vout->fbuf, &vout->crop, &vout->win);
+
+	/* Save the changes in the overlay strcuture */
+	ret = omapvid_init(vout, 0);
+	if (ret) {
+		v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n");
+		goto s_fmt_vid_out_exit;
+	}
+
+	ret = 0;
+
+s_fmt_vid_out_exit:
+	mutex_unlock(&vout->lock);
+	return ret;
+}
+
+static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	int ret = 0;
+	struct omap_vout_device *vout = fh;
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid;
+	struct v4l2_window *win = &f->fmt.win;
+
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+
+	ret = omap_vout_try_window(&vout->fbuf, win);
+
+	if (!ret) {
+		if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
+			win->global_alpha = 255;
+		else
+			win->global_alpha = f->fmt.win.global_alpha;
+	}
+
+	return ret;
+}
+
+static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	int ret = 0;
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid;
+	struct omap_vout_device *vout = fh;
+	struct v4l2_window *win = &f->fmt.win;
+
+	mutex_lock(&vout->lock);
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+
+	ret = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win);
+	if (!ret) {
+		/* Video1 plane does not support global alpha on OMAP3 */
+		if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
+			vout->win.global_alpha = 255;
+		else
+			vout->win.global_alpha = f->fmt.win.global_alpha;
+
+		vout->win.chromakey = f->fmt.win.chromakey;
+	}
+	mutex_unlock(&vout->lock);
+	return ret;
+}
+
+static int vidioc_enum_fmt_vid_overlay(struct file *file, void *fh,
+			struct v4l2_fmtdesc *fmt)
+{
+	int index = fmt->index;
+
+	if (index >= NUM_OUTPUT_FORMATS)
+		return -EINVAL;
+
+	fmt->flags = omap_formats[index].flags;
+	strlcpy(fmt->description, omap_formats[index].description,
+			sizeof(fmt->description));
+	fmt->pixelformat = omap_formats[index].pixelformat;
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	u32 key_value =  0;
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid;
+	struct omap_vout_device *vout = fh;
+	struct omap_overlay_manager_info info;
+	struct v4l2_window *win = &f->fmt.win;
+
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+
+	win->w = vout->win.w;
+	win->field = vout->win.field;
+	win->global_alpha = vout->win.global_alpha;
+
+	if (ovl->manager && ovl->manager->get_manager_info) {
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		key_value = info.trans_key;
+	}
+	win->chromakey = key_value;
+	return 0;
+}
+
+static int vidioc_cropcap(struct file *file, void *fh,
+		struct v4l2_cropcap *cropcap)
+{
+	struct omap_vout_device *vout = fh;
+	struct v4l2_pix_format *pix = &vout->pix;
+
+	if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	/* Width and height are always even */
+	cropcap->bounds.width = pix->width & ~1;
+	cropcap->bounds.height = pix->height & ~1;
+
+	omap_vout_default_crop(&vout->pix, &vout->fbuf, &cropcap->defrect);
+	cropcap->pixelaspect.numerator = 1;
+	cropcap->pixelaspect.denominator = 1;
+	return 0;
+}
+
+static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+	struct omap_vout_device *vout = fh;
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+	crop->c = vout->crop;
+	return 0;
+}
+
+static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+	int ret = -EINVAL;
+	struct omap_vout_device *vout = fh;
+	struct omapvideo_info *ovid;
+	struct omap_overlay *ovl;
+	struct omap_video_timings *timing;
+
+	if (vout->streaming)
+		return -EBUSY;
+
+	mutex_lock(&vout->lock);
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+
+	if (!ovl->manager || !ovl->manager->device) {
+		ret = -EINVAL;
+		goto s_crop_err;
+	}
+	/* get the display device attached to the overlay */
+	timing = &ovl->manager->device->panel.timings;
+
+	if (is_rotation_90_or_270(vout)) {
+		vout->fbuf.fmt.height = timing->x_res;
+		vout->fbuf.fmt.width = timing->y_res;
+	} else {
+		vout->fbuf.fmt.height = timing->y_res;
+		vout->fbuf.fmt.width = timing->x_res;
+	}
+
+	if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		ret = omap_vout_new_crop(&vout->pix, &vout->crop, &vout->win,
+				&vout->fbuf, &crop->c);
+
+s_crop_err:
+	mutex_unlock(&vout->lock);
+	return ret;
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh,
+		struct v4l2_queryctrl *ctrl)
+{
+	int ret = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_ROTATE:
+		ret = v4l2_ctrl_query_fill(ctrl, 0, 270, 90, 0);
+		break;
+	case V4L2_CID_BG_COLOR:
+		ret = v4l2_ctrl_query_fill(ctrl, 0, 0xFFFFFF, 1, 0);
+		break;
+	case V4L2_CID_VFLIP:
+		ret = v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0);
+		break;
+	default:
+		ctrl->name[0] = '\0';
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl)
+{
+	int ret = 0;
+	struct omap_vout_device *vout = fh;
+
+	switch (ctrl->id) {
+	case V4L2_CID_ROTATE:
+		ctrl->value = vout->control[0].value;
+		break;
+	case V4L2_CID_BG_COLOR:
+	{
+		struct omap_overlay_manager_info info;
+		struct omap_overlay *ovl;
+
+		ovl = vout->vid_info.overlays[0];
+		if (!ovl->manager || !ovl->manager->get_manager_info) {
+			ret = -EINVAL;
+			break;
+		}
+
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		ctrl->value = info.default_color;
+		break;
+	}
+	case V4L2_CID_VFLIP:
+		ctrl->value = vout->control[2].value;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
+{
+	int ret = 0;
+	struct omap_vout_device *vout = fh;
+
+	switch (a->id) {
+	case V4L2_CID_ROTATE:
+	{
+		struct omapvideo_info *ovid;
+		int rotation = a->value;
+
+		ovid = &vout->vid_info;
+
+		mutex_lock(&vout->lock);
+		if (rotation && ovid->rotation_type == VOUT_ROT_NONE) {
+			mutex_unlock(&vout->lock);
+			ret = -ERANGE;
+			break;
+		}
+
+		if (rotation && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
+			mutex_unlock(&vout->lock);
+			ret = -EINVAL;
+			break;
+		}
+
+		if (v4l2_rot_to_dss_rot(rotation, &vout->rotation,
+							vout->mirror)) {
+			mutex_unlock(&vout->lock);
+			ret = -EINVAL;
+			break;
+		}
+
+		vout->control[0].value = rotation;
+		mutex_unlock(&vout->lock);
+		break;
+	}
+	case V4L2_CID_BG_COLOR:
+	{
+		struct omap_overlay *ovl;
+		unsigned int  color = a->value;
+		struct omap_overlay_manager_info info;
+
+		ovl = vout->vid_info.overlays[0];
+
+		mutex_lock(&vout->lock);
+		if (!ovl->manager || !ovl->manager->get_manager_info) {
+			mutex_unlock(&vout->lock);
+			ret = -EINVAL;
+			break;
+		}
+
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		info.default_color = color;
+		if (ovl->manager->set_manager_info(ovl->manager, &info)) {
+			mutex_unlock(&vout->lock);
+			ret = -EINVAL;
+			break;
+		}
+
+		vout->control[1].value = color;
+		mutex_unlock(&vout->lock);
+		break;
+	}
+	case V4L2_CID_VFLIP:
+	{
+		struct omap_overlay *ovl;
+		struct omapvideo_info *ovid;
+		unsigned int  mirror = a->value;
+
+		ovid = &vout->vid_info;
+		ovl = ovid->overlays[0];
+
+		mutex_lock(&vout->lock);
+		if (mirror && ovid->rotation_type == VOUT_ROT_NONE) {
+			mutex_unlock(&vout->lock);
+			ret = -ERANGE;
+			break;
+		}
+
+		if (mirror  && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
+			mutex_unlock(&vout->lock);
+			ret = -EINVAL;
+			break;
+		}
+		vout->mirror = mirror;
+		vout->control[2].value = mirror;
+		mutex_unlock(&vout->lock);
+		break;
+	}
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *fh,
+			struct v4l2_requestbuffers *req)
+{
+	int ret = 0;
+	unsigned int i, num_buffers = 0;
+	struct omap_vout_device *vout = fh;
+	struct videobuf_queue *q = &vout->vbq;
+
+	if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0))
+		return -EINVAL;
+	/* if memory is not mmp or userptr
+	   return error */
+	if ((V4L2_MEMORY_MMAP != req->memory) &&
+			(V4L2_MEMORY_USERPTR != req->memory))
+		return -EINVAL;
+
+	mutex_lock(&vout->lock);
+	/* Cannot be requested when streaming is on */
+	if (vout->streaming) {
+		ret = -EBUSY;
+		goto reqbuf_err;
+	}
+
+	/* If buffers are already allocated free them */
+	if (q->bufs[0] && (V4L2_MEMORY_MMAP == q->bufs[0]->memory)) {
+		if (vout->mmap_count) {
+			ret = -EBUSY;
+			goto reqbuf_err;
+		}
+		num_buffers = (vout->vid == OMAP_VIDEO1) ?
+			video1_numbuffers : video2_numbuffers;
+		for (i = num_buffers; i < vout->buffer_allocated; i++) {
+			omap_vout_free_buffer(vout->buf_virt_addr[i],
+					vout->buffer_size);
+			vout->buf_virt_addr[i] = 0;
+			vout->buf_phy_addr[i] = 0;
+		}
+		vout->buffer_allocated = num_buffers;
+		videobuf_mmap_free(q);
+	} else if (q->bufs[0] && (V4L2_MEMORY_USERPTR == q->bufs[0]->memory)) {
+		if (vout->buffer_allocated) {
+			videobuf_mmap_free(q);
+			for (i = 0; i < vout->buffer_allocated; i++) {
+				kfree(q->bufs[i]);
+				q->bufs[i] = NULL;
+			}
+			vout->buffer_allocated = 0;
+		}
+	}
+
+	/*store the memory type in data structure */
+	vout->memory = req->memory;
+
+	INIT_LIST_HEAD(&vout->dma_queue);
+
+	/* call videobuf_reqbufs api */
+	ret = videobuf_reqbufs(q, req);
+	if (ret < 0)
+		goto reqbuf_err;
+
+	vout->buffer_allocated = req->count;
+
+reqbuf_err:
+	mutex_unlock(&vout->lock);
+	return ret;
+}
+
+static int vidioc_querybuf(struct file *file, void *fh,
+			struct v4l2_buffer *b)
+{
+	struct omap_vout_device *vout = fh;
+
+	return videobuf_querybuf(&vout->vbq, b);
+}
+
+static int vidioc_qbuf(struct file *file, void *fh,
+			struct v4l2_buffer *buffer)
+{
+	struct omap_vout_device *vout = fh;
+	struct videobuf_queue *q = &vout->vbq;
+
+	if ((V4L2_BUF_TYPE_VIDEO_OUTPUT != buffer->type) ||
+			(buffer->index >= vout->buffer_allocated) ||
+			(q->bufs[buffer->index]->memory != buffer->memory)) {
+		return -EINVAL;
+	}
+	if (V4L2_MEMORY_USERPTR == buffer->memory) {
+		if ((buffer->length < vout->pix.sizeimage) ||
+				(0 == buffer->m.userptr)) {
+			return -EINVAL;
+		}
+	}
+
+	if ((is_rotation_enabled(vout)) &&
+			vout->vrfb_dma_tx.req_status == DMA_CHAN_NOT_ALLOTED) {
+		v4l2_warn(&vout->vid_dev->v4l2_dev,
+				"DMA Channel not allocated for Rotation\n");
+		return -EINVAL;
+	}
+
+	return videobuf_qbuf(q, buffer);
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+	struct omap_vout_device *vout = fh;
+	struct videobuf_queue *q = &vout->vbq;
+
+	int ret;
+	u32 addr;
+	unsigned long size;
+	struct videobuf_buffer *vb;
+
+	vb = q->bufs[b->index];
+
+	if (!vout->streaming)
+		return -EINVAL;
+
+	if (file->f_flags & O_NONBLOCK)
+		/* Call videobuf_dqbuf for non blocking mode */
+		ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1);
+	else
+		/* Call videobuf_dqbuf for  blocking mode */
+		ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);
+
+	addr = (unsigned long) vout->buf_phy_addr[vb->i];
+	size = (unsigned long) vb->size;
+	dma_unmap_single(vout->vid_dev->v4l2_dev.dev,  addr,
+				size, DMA_TO_DEVICE);
+	return ret;
+}
+
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+	int ret = 0, j;
+	u32 addr = 0, mask = 0;
+	struct omap_vout_device *vout = fh;
+	struct videobuf_queue *q = &vout->vbq;
+	struct omapvideo_info *ovid = &vout->vid_info;
+
+	mutex_lock(&vout->lock);
+
+	if (vout->streaming) {
+		ret = -EBUSY;
+		goto streamon_err;
+	}
+
+	ret = videobuf_streamon(q);
+	if (ret)
+		goto streamon_err;
+
+	if (list_empty(&vout->dma_queue)) {
+		ret = -EIO;
+		goto streamon_err1;
+	}
+
+	/* Get the next frame from the buffer queue */
+	vout->next_frm = vout->cur_frm = list_entry(vout->dma_queue.next,
+			struct videobuf_buffer, queue);
+	/* Remove buffer from the buffer queue */
+	list_del(&vout->cur_frm->queue);
+	/* Mark state of the current frame to active */
+	vout->cur_frm->state = VIDEOBUF_ACTIVE;
+	/* Initialize field_id and started member */
+	vout->field_id = 0;
+
+	/* set flag here. Next QBUF will start DMA */
+	vout->streaming = 1;
+
+	vout->first_int = 1;
+
+	if (omap_vout_calculate_offset(vout)) {
+		ret = -EINVAL;
+		goto streamon_err1;
+	}
+	addr = (unsigned long) vout->queued_buf_addr[vout->cur_frm->i]
+		+ vout->cropped_offset;
+
+	mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
+		| DISPC_IRQ_VSYNC2;
+
+	omap_dispc_register_isr(omap_vout_isr, vout, mask);
+
+	for (j = 0; j < ovid->num_overlays; j++) {
+		struct omap_overlay *ovl = ovid->overlays[j];
+
+		if (ovl->manager && ovl->manager->device) {
+			struct omap_overlay_info info;
+			ovl->get_overlay_info(ovl, &info);
+			info.paddr = addr;
+			if (ovl->set_overlay_info(ovl, &info)) {
+				ret = -EINVAL;
+				goto streamon_err1;
+			}
+		}
+	}
+
+	/* First save the configuration in ovelray structure */
+	ret = omapvid_init(vout, addr);
+	if (ret)
+		v4l2_err(&vout->vid_dev->v4l2_dev,
+				"failed to set overlay info\n");
+	/* Enable the pipeline and set the Go bit */
+	ret = omapvid_apply_changes(vout);
+	if (ret)
+		v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n");
+
+	for (j = 0; j < ovid->num_overlays; j++) {
+		struct omap_overlay *ovl = ovid->overlays[j];
+
+		if (ovl->manager && ovl->manager->device) {
+			ret = ovl->enable(ovl);
+			if (ret)
+				goto streamon_err1;
+		}
+	}
+
+	ret = 0;
+
+streamon_err1:
+	if (ret)
+		ret = videobuf_streamoff(q);
+streamon_err:
+	mutex_unlock(&vout->lock);
+	return ret;
+}
+
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+	u32 mask = 0;
+	int ret = 0, j;
+	struct omap_vout_device *vout = fh;
+	struct omapvideo_info *ovid = &vout->vid_info;
+
+	if (!vout->streaming)
+		return -EINVAL;
+
+	vout->streaming = 0;
+	mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
+		| DISPC_IRQ_VSYNC2;
+
+	omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
+
+	for (j = 0; j < ovid->num_overlays; j++) {
+		struct omap_overlay *ovl = ovid->overlays[j];
+
+		if (ovl->manager && ovl->manager->device)
+			ovl->disable(ovl);
+	}
+
+	/* Turn of the pipeline */
+	ret = omapvid_apply_changes(vout);
+	if (ret)
+		v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode in"
+				" streamoff\n");
+
+	INIT_LIST_HEAD(&vout->dma_queue);
+	ret = videobuf_streamoff(&vout->vbq);
+
+	return ret;
+}
+
+static int vidioc_s_fbuf(struct file *file, void *fh,
+				struct v4l2_framebuffer *a)
+{
+	int enable = 0;
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid;
+	struct omap_vout_device *vout = fh;
+	struct omap_overlay_manager_info info;
+	enum omap_dss_trans_key_type key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
+
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+
+	/* OMAP DSS doesn't support Source and Destination color
+	   key together */
+	if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) &&
+			(a->flags & V4L2_FBUF_FLAG_CHROMAKEY))
+		return -EINVAL;
+	/* OMAP DSS Doesn't support the Destination color key
+	   and alpha blending together */
+	if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY) &&
+			(a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA))
+		return -EINVAL;
+
+	if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY)) {
+		vout->fbuf.flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
+		key_type =  OMAP_DSS_COLOR_KEY_VID_SRC;
+	} else
+		vout->fbuf.flags &= ~V4L2_FBUF_FLAG_SRC_CHROMAKEY;
+
+	if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY)) {
+		vout->fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+		key_type =  OMAP_DSS_COLOR_KEY_GFX_DST;
+	} else
+		vout->fbuf.flags &=  ~V4L2_FBUF_FLAG_CHROMAKEY;
+
+	if (a->flags & (V4L2_FBUF_FLAG_CHROMAKEY |
+				V4L2_FBUF_FLAG_SRC_CHROMAKEY))
+		enable = 1;
+	else
+		enable = 0;
+	if (ovl->manager && ovl->manager->get_manager_info &&
+			ovl->manager->set_manager_info) {
+
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		info.trans_enabled = enable;
+		info.trans_key_type = key_type;
+		info.trans_key = vout->win.chromakey;
+
+		if (ovl->manager->set_manager_info(ovl->manager, &info))
+			return -EINVAL;
+	}
+	if (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) {
+		vout->fbuf.flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
+		enable = 1;
+	} else {
+		vout->fbuf.flags &= ~V4L2_FBUF_FLAG_LOCAL_ALPHA;
+		enable = 0;
+	}
+	if (ovl->manager && ovl->manager->get_manager_info &&
+			ovl->manager->set_manager_info) {
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		/* enable this only if there is no zorder cap */
+		if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
+			info.partial_alpha_enabled = enable;
+		if (ovl->manager->set_manager_info(ovl->manager, &info))
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vidioc_g_fbuf(struct file *file, void *fh,
+		struct v4l2_framebuffer *a)
+{
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid;
+	struct omap_vout_device *vout = fh;
+	struct omap_overlay_manager_info info;
+
+	ovid = &vout->vid_info;
+	ovl = ovid->overlays[0];
+
+	/* The video overlay must stay within the framebuffer and can't be
+	   positioned independently. */
+	a->flags = V4L2_FBUF_FLAG_OVERLAY;
+	a->capability = V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_CHROMAKEY
+		| V4L2_FBUF_CAP_SRC_CHROMAKEY;
+
+	if (ovl->manager && ovl->manager->get_manager_info) {
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		if (info.trans_key_type == OMAP_DSS_COLOR_KEY_VID_SRC)
+			a->flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
+		if (info.trans_key_type == OMAP_DSS_COLOR_KEY_GFX_DST)
+			a->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+	}
+	if (ovl->manager && ovl->manager->get_manager_info) {
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		if (info.partial_alpha_enabled)
+			a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
+	}
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops vout_ioctl_ops = {
+	.vidioc_querycap      			= vidioc_querycap,
+	.vidioc_enum_fmt_vid_out 		= vidioc_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out			= vidioc_g_fmt_vid_out,
+	.vidioc_try_fmt_vid_out			= vidioc_try_fmt_vid_out,
+	.vidioc_s_fmt_vid_out			= vidioc_s_fmt_vid_out,
+	.vidioc_queryctrl    			= vidioc_queryctrl,
+	.vidioc_g_ctrl       			= vidioc_g_ctrl,
+	.vidioc_s_fbuf				= vidioc_s_fbuf,
+	.vidioc_g_fbuf				= vidioc_g_fbuf,
+	.vidioc_s_ctrl       			= vidioc_s_ctrl,
+	.vidioc_try_fmt_vid_overlay 		= vidioc_try_fmt_vid_overlay,
+	.vidioc_s_fmt_vid_overlay		= vidioc_s_fmt_vid_overlay,
+	.vidioc_enum_fmt_vid_overlay		= vidioc_enum_fmt_vid_overlay,
+	.vidioc_g_fmt_vid_overlay		= vidioc_g_fmt_vid_overlay,
+	.vidioc_cropcap				= vidioc_cropcap,
+	.vidioc_g_crop				= vidioc_g_crop,
+	.vidioc_s_crop				= vidioc_s_crop,
+	.vidioc_reqbufs				= vidioc_reqbufs,
+	.vidioc_querybuf			= vidioc_querybuf,
+	.vidioc_qbuf				= vidioc_qbuf,
+	.vidioc_dqbuf				= vidioc_dqbuf,
+	.vidioc_streamon			= vidioc_streamon,
+	.vidioc_streamoff			= vidioc_streamoff,
+};
+
+static const struct v4l2_file_operations omap_vout_fops = {
+	.owner 		= THIS_MODULE,
+	.poll		= omap_vout_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap 		= omap_vout_mmap,
+	.open 		= omap_vout_open,
+	.release 	= omap_vout_release,
+};
+
+/* Init functions used during driver initialization */
+/* Initial setup of video_data */
+static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
+{
+	struct video_device *vfd;
+	struct v4l2_pix_format *pix;
+	struct v4l2_control *control;
+	struct omap_dss_device *display =
+		vout->vid_info.overlays[0]->manager->device;
+
+	/* set the default pix */
+	pix = &vout->pix;
+
+	/* Set the default picture of QVGA  */
+	pix->width = QQVGA_WIDTH;
+	pix->height = QQVGA_HEIGHT;
+
+	/* Default pixel format is RGB 5-6-5 */
+	pix->pixelformat = V4L2_PIX_FMT_RGB565;
+	pix->field = V4L2_FIELD_ANY;
+	pix->bytesperline = pix->width * 2;
+	pix->sizeimage = pix->bytesperline * pix->height;
+	pix->priv = 0;
+	pix->colorspace = V4L2_COLORSPACE_JPEG;
+
+	vout->bpp = RGB565_BPP;
+	vout->fbuf.fmt.width  =  display->panel.timings.x_res;
+	vout->fbuf.fmt.height =  display->panel.timings.y_res;
+
+	/* Set the data structures for the overlay parameters*/
+	vout->win.global_alpha = 255;
+	vout->fbuf.flags = 0;
+	vout->fbuf.capability = V4L2_FBUF_CAP_LOCAL_ALPHA |
+		V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY;
+	vout->win.chromakey = 0;
+
+	omap_vout_new_format(pix, &vout->fbuf, &vout->crop, &vout->win);
+
+	/*Initialize the control variables for
+	  rotation, flipping and background color. */
+	control = vout->control;
+	control[0].id = V4L2_CID_ROTATE;
+	control[0].value = 0;
+	vout->rotation = 0;
+	vout->mirror = 0;
+	vout->control[2].id = V4L2_CID_HFLIP;
+	vout->control[2].value = 0;
+	if (vout->vid_info.rotation_type == VOUT_ROT_VRFB)
+		vout->vrfb_bpp = 2;
+
+	control[1].id = V4L2_CID_BG_COLOR;
+	control[1].value = 0;
+
+	/* initialize the video_device struct */
+	vfd = vout->vfd = video_device_alloc();
+
+	if (!vfd) {
+		printk(KERN_ERR VOUT_NAME ": could not allocate"
+				" video device struct\n");
+		return -ENOMEM;
+	}
+	vfd->release = video_device_release;
+	vfd->ioctl_ops = &vout_ioctl_ops;
+
+	strlcpy(vfd->name, VOUT_NAME, sizeof(vfd->name));
+
+	vfd->fops = &omap_vout_fops;
+	vfd->v4l2_dev = &vout->vid_dev->v4l2_dev;
+	mutex_init(&vout->lock);
+
+	vfd->minor = -1;
+	return 0;
+
+}
+
+/* Setup video buffers */
+static int __init omap_vout_setup_video_bufs(struct platform_device *pdev,
+		int vid_num)
+{
+	u32 numbuffers;
+	int ret = 0, i;
+	struct omapvideo_info *ovid;
+	struct omap_vout_device *vout;
+	struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+	struct omap2video_device *vid_dev =
+		container_of(v4l2_dev, struct omap2video_device, v4l2_dev);
+
+	vout = vid_dev->vouts[vid_num];
+	ovid = &vout->vid_info;
+
+	numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers;
+	vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize;
+	dev_info(&pdev->dev, "Buffer Size = %d\n", vout->buffer_size);
+
+	for (i = 0; i < numbuffers; i++) {
+		vout->buf_virt_addr[i] =
+			omap_vout_alloc_buffer(vout->buffer_size,
+					(u32 *) &vout->buf_phy_addr[i]);
+		if (!vout->buf_virt_addr[i]) {
+			numbuffers = i;
+			ret = -ENOMEM;
+			goto free_buffers;
+		}
+	}
+
+	vout->cropped_offset = 0;
+
+	if (ovid->rotation_type == VOUT_ROT_VRFB) {
+		int static_vrfb_allocation = (vid_num == 0) ?
+			vid1_static_vrfb_alloc : vid2_static_vrfb_alloc;
+		ret = omap_vout_setup_vrfb_bufs(pdev, vid_num,
+				static_vrfb_allocation);
+	}
+
+	return ret;
+
+free_buffers:
+	for (i = 0; i < numbuffers; i++) {
+		omap_vout_free_buffer(vout->buf_virt_addr[i],
+						vout->buffer_size);
+		vout->buf_virt_addr[i] = 0;
+		vout->buf_phy_addr[i] = 0;
+	}
+	return ret;
+
+}
+
+/* Create video out devices */
+static int __init omap_vout_create_video_devices(struct platform_device *pdev)
+{
+	int ret = 0, k;
+	struct omap_vout_device *vout;
+	struct video_device *vfd = NULL;
+	struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+	struct omap2video_device *vid_dev = container_of(v4l2_dev,
+			struct omap2video_device, v4l2_dev);
+
+	for (k = 0; k < pdev->num_resources; k++) {
+
+		vout = kzalloc(sizeof(struct omap_vout_device), GFP_KERNEL);
+		if (!vout) {
+			dev_err(&pdev->dev, ": could not allocate memory\n");
+			return -ENOMEM;
+		}
+
+		vout->vid = k;
+		vid_dev->vouts[k] = vout;
+		vout->vid_dev = vid_dev;
+		/* Select video2 if only 1 overlay is controlled by V4L2 */
+		if (pdev->num_resources == 1)
+			vout->vid_info.overlays[0] = vid_dev->overlays[k + 2];
+		else
+			/* Else select video1 and video2 one by one. */
+			vout->vid_info.overlays[0] = vid_dev->overlays[k + 1];
+		vout->vid_info.num_overlays = 1;
+		vout->vid_info.id = k + 1;
+
+		/* Set VRFB as rotation_type for omap2 and omap3 */
+		if (cpu_is_omap24xx() || cpu_is_omap34xx())
+			vout->vid_info.rotation_type = VOUT_ROT_VRFB;
+
+		/* Setup the default configuration for the video devices
+		 */
+		if (omap_vout_setup_video_data(vout) != 0) {
+			ret = -ENOMEM;
+			goto error;
+		}
+
+		/* Allocate default number of buffers for the video streaming
+		 * and reserve the VRFB space for rotation
+		 */
+		if (omap_vout_setup_video_bufs(pdev, k) != 0) {
+			ret = -ENOMEM;
+			goto error1;
+		}
+
+		/* Register the Video device with V4L2
+		 */
+		vfd = vout->vfd;
+		if (video_register_device(vfd, VFL_TYPE_GRABBER, -1) < 0) {
+			dev_err(&pdev->dev, ": Could not register "
+					"Video for Linux device\n");
+			vfd->minor = -1;
+			ret = -ENODEV;
+			goto error2;
+		}
+		video_set_drvdata(vfd, vout);
+
+		/* Configure the overlay structure */
+		ret = omapvid_init(vid_dev->vouts[k], 0);
+		if (!ret)
+			goto success;
+
+error2:
+		if (vout->vid_info.rotation_type == VOUT_ROT_VRFB)
+			omap_vout_release_vrfb(vout);
+		omap_vout_free_buffers(vout);
+error1:
+		video_device_release(vfd);
+error:
+		kfree(vout);
+		return ret;
+
+success:
+		dev_info(&pdev->dev, ": registered and initialized"
+				" video device %d\n", vfd->minor);
+		if (k == (pdev->num_resources - 1))
+			return 0;
+	}
+
+	return -ENODEV;
+}
+/* Driver functions */
+static void omap_vout_cleanup_device(struct omap_vout_device *vout)
+{
+	struct video_device *vfd;
+	struct omapvideo_info *ovid;
+
+	if (!vout)
+		return;
+
+	vfd = vout->vfd;
+	ovid = &vout->vid_info;
+	if (vfd) {
+		if (!video_is_registered(vfd)) {
+			/*
+			 * The device was never registered, so release the
+			 * video_device struct directly.
+			 */
+			video_device_release(vfd);
+		} else {
+			/*
+			 * The unregister function will release the video_device
+			 * struct as well as unregistering it.
+			 */
+			video_unregister_device(vfd);
+		}
+	}
+	if (ovid->rotation_type == VOUT_ROT_VRFB) {
+		omap_vout_release_vrfb(vout);
+		/* Free the VRFB buffer if allocated
+		 * init time
+		 */
+		if (vout->vrfb_static_allocation)
+			omap_vout_free_vrfb_buffers(vout);
+	}
+	omap_vout_free_buffers(vout);
+
+	kfree(vout);
+}
+
+static int omap_vout_remove(struct platform_device *pdev)
+{
+	int k;
+	struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+	struct omap2video_device *vid_dev = container_of(v4l2_dev, struct
+			omap2video_device, v4l2_dev);
+
+	v4l2_device_unregister(v4l2_dev);
+	for (k = 0; k < pdev->num_resources; k++)
+		omap_vout_cleanup_device(vid_dev->vouts[k]);
+
+	for (k = 0; k < vid_dev->num_displays; k++) {
+		if (vid_dev->displays[k]->state != OMAP_DSS_DISPLAY_DISABLED)
+			vid_dev->displays[k]->driver->disable(vid_dev->displays[k]);
+
+		omap_dss_put_device(vid_dev->displays[k]);
+	}
+	kfree(vid_dev);
+	return 0;
+}
+
+static int __init omap_vout_probe(struct platform_device *pdev)
+{
+	int ret = 0, i;
+	struct omap_overlay *ovl;
+	struct omap_dss_device *dssdev = NULL;
+	struct omap_dss_device *def_display;
+	struct omap2video_device *vid_dev = NULL;
+
+	if (pdev->num_resources == 0) {
+		dev_err(&pdev->dev, "probed for an unknown device\n");
+		return -ENODEV;
+	}
+
+	vid_dev = kzalloc(sizeof(struct omap2video_device), GFP_KERNEL);
+	if (vid_dev == NULL)
+		return -ENOMEM;
+
+	vid_dev->num_displays = 0;
+	for_each_dss_dev(dssdev) {
+		omap_dss_get_device(dssdev);
+
+		if (!dssdev->driver) {
+			dev_warn(&pdev->dev, "no driver for display: %s\n",
+					dssdev->name);
+			omap_dss_put_device(dssdev);
+			continue;
+		}
+
+		vid_dev->displays[vid_dev->num_displays++] = dssdev;
+	}
+
+	if (vid_dev->num_displays == 0) {
+		dev_err(&pdev->dev, "no displays\n");
+		ret = -EINVAL;
+		goto probe_err0;
+	}
+
+	vid_dev->num_overlays = omap_dss_get_num_overlays();
+	for (i = 0; i < vid_dev->num_overlays; i++)
+		vid_dev->overlays[i] = omap_dss_get_overlay(i);
+
+	vid_dev->num_managers = omap_dss_get_num_overlay_managers();
+	for (i = 0; i < vid_dev->num_managers; i++)
+		vid_dev->managers[i] = omap_dss_get_overlay_manager(i);
+
+	/* Get the Video1 overlay and video2 overlay.
+	 * Setup the Display attached to that overlays
+	 */
+	for (i = 1; i < vid_dev->num_overlays; i++) {
+		ovl = omap_dss_get_overlay(i);
+		if (ovl->manager && ovl->manager->device) {
+			def_display = ovl->manager->device;
+		} else {
+			dev_warn(&pdev->dev, "cannot find display\n");
+			def_display = NULL;
+		}
+		if (def_display) {
+			struct omap_dss_driver *dssdrv = def_display->driver;
+
+			ret = dssdrv->enable(def_display);
+			if (ret) {
+				/* Here we are not considering a error
+				 *  as display may be enabled by frame
+				 *  buffer driver
+				 */
+				dev_warn(&pdev->dev,
+					"'%s' Display already enabled\n",
+					def_display->name);
+			}
+		}
+	}
+
+	if (v4l2_device_register(&pdev->dev, &vid_dev->v4l2_dev) < 0) {
+		dev_err(&pdev->dev, "v4l2_device_register failed\n");
+		ret = -ENODEV;
+		goto probe_err1;
+	}
+
+	ret = omap_vout_create_video_devices(pdev);
+	if (ret)
+		goto probe_err2;
+
+	for (i = 0; i < vid_dev->num_displays; i++) {
+		struct omap_dss_device *display = vid_dev->displays[i];
+
+		if (display->driver->update)
+			display->driver->update(display, 0, 0,
+					display->panel.timings.x_res,
+					display->panel.timings.y_res);
+	}
+	return 0;
+
+probe_err2:
+	v4l2_device_unregister(&vid_dev->v4l2_dev);
+probe_err1:
+	for (i = 1; i < vid_dev->num_overlays; i++) {
+		def_display = NULL;
+		ovl = omap_dss_get_overlay(i);
+		if (ovl->manager && ovl->manager->device)
+			def_display = ovl->manager->device;
+
+		if (def_display && def_display->driver)
+			def_display->driver->disable(def_display);
+	}
+probe_err0:
+	kfree(vid_dev);
+	return ret;
+}
+
+static struct platform_driver omap_vout_driver = {
+	.driver = {
+		.name = VOUT_NAME,
+	},
+	.remove = omap_vout_remove,
+};
+
+static int __init omap_vout_init(void)
+{
+	if (platform_driver_probe(&omap_vout_driver, omap_vout_probe) != 0) {
+		printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void omap_vout_cleanup(void)
+{
+	platform_driver_unregister(&omap_vout_driver);
+}
+
+late_initcall(omap_vout_init);
+module_exit(omap_vout_cleanup);
diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c
new file mode 100644
index 0000000..4be26ab
--- /dev/null
+++ b/drivers/media/platform/omap/omap_vout_vrfb.c
@@ -0,0 +1,390 @@
+/*
+ * omap_vout_vrfb.c
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+
+#include <media/videobuf-dma-contig.h>
+#include <media/v4l2-device.h>
+
+#include <plat/dma.h>
+#include <plat/vrfb.h>
+
+#include "omap_voutdef.h"
+#include "omap_voutlib.h"
+
+/*
+ * Function for allocating video buffers
+ */
+static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout,
+		unsigned int *count, int startindex)
+{
+	int i, j;
+
+	for (i = 0; i < *count; i++) {
+		if (!vout->smsshado_virt_addr[i]) {
+			vout->smsshado_virt_addr[i] =
+				omap_vout_alloc_buffer(vout->smsshado_size,
+						&vout->smsshado_phy_addr[i]);
+		}
+		if (!vout->smsshado_virt_addr[i] && startindex != -1) {
+			if (V4L2_MEMORY_MMAP == vout->memory && i >= startindex)
+				break;
+		}
+		if (!vout->smsshado_virt_addr[i]) {
+			for (j = 0; j < i; j++) {
+				omap_vout_free_buffer(
+						vout->smsshado_virt_addr[j],
+						vout->smsshado_size);
+				vout->smsshado_virt_addr[j] = 0;
+				vout->smsshado_phy_addr[j] = 0;
+			}
+			*count = 0;
+			return -ENOMEM;
+		}
+		memset((void *) vout->smsshado_virt_addr[i], 0,
+				vout->smsshado_size);
+	}
+	return 0;
+}
+
+/*
+ * Wakes up the application once the DMA transfer to VRFB space is completed.
+ */
+static void omap_vout_vrfb_dma_tx_callback(int lch, u16 ch_status, void *data)
+{
+	struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data;
+
+	t->tx_status = 1;
+	wake_up_interruptible(&t->wait);
+}
+
+/*
+ * Free VRFB buffers
+ */
+void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout)
+{
+	int j;
+
+	for (j = 0; j < VRFB_NUM_BUFS; j++) {
+		omap_vout_free_buffer(vout->smsshado_virt_addr[j],
+				vout->smsshado_size);
+		vout->smsshado_virt_addr[j] = 0;
+		vout->smsshado_phy_addr[j] = 0;
+	}
+}
+
+int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
+			      bool static_vrfb_allocation)
+{
+	int ret = 0, i, j;
+	struct omap_vout_device *vout;
+	struct video_device *vfd;
+	int image_width, image_height;
+	int vrfb_num_bufs = VRFB_NUM_BUFS;
+	struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+	struct omap2video_device *vid_dev =
+		container_of(v4l2_dev, struct omap2video_device, v4l2_dev);
+
+	vout = vid_dev->vouts[vid_num];
+	vfd = vout->vfd;
+
+	for (i = 0; i < VRFB_NUM_BUFS; i++) {
+		if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) {
+			dev_info(&pdev->dev, ": VRFB allocation failed\n");
+			for (j = 0; j < i; j++)
+				omap_vrfb_release_ctx(&vout->vrfb_context[j]);
+			ret = -ENOMEM;
+			goto free_buffers;
+		}
+	}
+
+	/* Calculate VRFB memory size */
+	/* allocate for worst case size */
+	image_width = VID_MAX_WIDTH / TILE_SIZE;
+	if (VID_MAX_WIDTH % TILE_SIZE)
+		image_width++;
+
+	image_width = image_width * TILE_SIZE;
+	image_height = VID_MAX_HEIGHT / TILE_SIZE;
+
+	if (VID_MAX_HEIGHT % TILE_SIZE)
+		image_height++;
+
+	image_height = image_height * TILE_SIZE;
+	vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2);
+
+	/*
+	 * Request and Initialize DMA, for DMA based VRFB transfer
+	 */
+	vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE;
+	vout->vrfb_dma_tx.dma_ch = -1;
+	vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED;
+	ret = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX",
+			omap_vout_vrfb_dma_tx_callback,
+			(void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch);
+	if (ret < 0) {
+		vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
+		dev_info(&pdev->dev, ": failed to allocate DMA Channel for"
+				" video%d\n", vfd->minor);
+	}
+	init_waitqueue_head(&vout->vrfb_dma_tx.wait);
+
+	/* statically allocated the VRFB buffer is done through
+	   commands line aruments */
+	if (static_vrfb_allocation) {
+		if (omap_vout_allocate_vrfb_buffers(vout, &vrfb_num_bufs, -1)) {
+			ret =  -ENOMEM;
+			goto release_vrfb_ctx;
+		}
+		vout->vrfb_static_allocation = 1;
+	}
+	return 0;
+
+release_vrfb_ctx:
+	for (j = 0; j < VRFB_NUM_BUFS; j++)
+		omap_vrfb_release_ctx(&vout->vrfb_context[j]);
+free_buffers:
+	omap_vout_free_buffers(vout);
+
+	return ret;
+}
+
+/*
+ * Release the VRFB context once the module exits
+ */
+void omap_vout_release_vrfb(struct omap_vout_device *vout)
+{
+	int i;
+
+	for (i = 0; i < VRFB_NUM_BUFS; i++)
+		omap_vrfb_release_ctx(&vout->vrfb_context[i]);
+
+	if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) {
+		vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
+		omap_free_dma(vout->vrfb_dma_tx.dma_ch);
+	}
+}
+
+/*
+ * Allocate the buffers for the VRFB space.  Data is copied from V4L2
+ * buffers to the VRFB buffers using the DMA engine.
+ */
+int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
+			  unsigned int *count, unsigned int startindex)
+{
+	int i;
+	bool yuv_mode;
+
+	if (!is_rotation_enabled(vout))
+		return 0;
+
+	/* If rotation is enabled, allocate memory for VRFB space also */
+	*count = *count > VRFB_NUM_BUFS ? VRFB_NUM_BUFS : *count;
+
+	/* Allocate the VRFB buffers only if the buffers are not
+	 * allocated during init time.
+	 */
+	if (!vout->vrfb_static_allocation)
+		if (omap_vout_allocate_vrfb_buffers(vout, count, startindex))
+			return -ENOMEM;
+
+	if (vout->dss_mode == OMAP_DSS_COLOR_YUV2 ||
+			vout->dss_mode == OMAP_DSS_COLOR_UYVY)
+		yuv_mode = true;
+	else
+		yuv_mode = false;
+
+	for (i = 0; i < *count; i++)
+		omap_vrfb_setup(&vout->vrfb_context[i],
+				vout->smsshado_phy_addr[i], vout->pix.width,
+				vout->pix.height, vout->bpp, yuv_mode);
+
+	return 0;
+}
+
+int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
+				struct videobuf_buffer *vb)
+{
+	dma_addr_t dmabuf;
+	struct vid_vrfb_dma *tx;
+	enum dss_rotation rotation;
+	u32 dest_frame_index = 0, src_element_index = 0;
+	u32 dest_element_index = 0, src_frame_index = 0;
+	u32 elem_count = 0, frame_count = 0, pixsize = 2;
+
+	if (!is_rotation_enabled(vout))
+		return 0;
+
+	dmabuf = vout->buf_phy_addr[vb->i];
+	/* If rotation is enabled, copy input buffer into VRFB
+	 * memory space using DMA. We are copying input buffer
+	 * into VRFB memory space of desired angle and DSS will
+	 * read image VRFB memory for 0 degree angle
+	 */
+	pixsize = vout->bpp * vout->vrfb_bpp;
+	/*
+	 * DMA transfer in double index mode
+	 */
+
+	/* Frame index */
+	dest_frame_index = ((MAX_PIXELS_PER_LINE * pixsize) -
+			(vout->pix.width * vout->bpp)) + 1;
+
+	/* Source and destination parameters */
+	src_element_index = 0;
+	src_frame_index = 0;
+	dest_element_index = 1;
+	/* Number of elements per frame */
+	elem_count = vout->pix.width * vout->bpp;
+	frame_count = vout->pix.height;
+	tx = &vout->vrfb_dma_tx;
+	tx->tx_status = 0;
+	omap_set_dma_transfer_params(tx->dma_ch, OMAP_DMA_DATA_TYPE_S32,
+			(elem_count / 4), frame_count, OMAP_DMA_SYNC_ELEMENT,
+			tx->dev_id, 0x0);
+	/* src_port required only for OMAP1 */
+	omap_set_dma_src_params(tx->dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
+			dmabuf, src_element_index, src_frame_index);
+	/*set dma source burst mode for VRFB */
+	omap_set_dma_src_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
+	rotation = calc_rotation(vout);
+
+	/* dest_port required only for OMAP1 */
+	omap_set_dma_dest_params(tx->dma_ch, 0, OMAP_DMA_AMODE_DOUBLE_IDX,
+			vout->vrfb_context[vb->i].paddr[0], dest_element_index,
+			dest_frame_index);
+	/*set dma dest burst mode for VRFB */
+	omap_set_dma_dest_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
+	omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0);
+
+	omap_start_dma(tx->dma_ch);
+	interruptible_sleep_on_timeout(&tx->wait, VRFB_TX_TIMEOUT);
+
+	if (tx->tx_status == 0) {
+		omap_stop_dma(tx->dma_ch);
+		return -EINVAL;
+	}
+	/* Store buffers physical address into an array. Addresses
+	 * from this array will be used to configure DSS */
+	vout->queued_buf_addr[vb->i] = (u8 *)
+		vout->vrfb_context[vb->i].paddr[rotation];
+	return 0;
+}
+
+/*
+ * Calculate the buffer offsets from which the streaming should
+ * start. This offset calculation is mainly required because of
+ * the VRFB 32 pixels alignment with rotation.
+ */
+void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout)
+{
+	enum dss_rotation rotation;
+	bool mirroring = vout->mirror;
+	struct v4l2_rect *crop = &vout->crop;
+	struct v4l2_pix_format *pix = &vout->pix;
+	int *cropped_offset = &vout->cropped_offset;
+	int vr_ps = 1, ps = 2, temp_ps = 2;
+	int offset = 0, ctop = 0, cleft = 0, line_length = 0;
+
+	rotation = calc_rotation(vout);
+
+	if (V4L2_PIX_FMT_YUYV == pix->pixelformat ||
+			V4L2_PIX_FMT_UYVY == pix->pixelformat) {
+		if (is_rotation_enabled(vout)) {
+			/*
+			 * ps    - Actual pixel size for YUYV/UYVY for
+			 *         VRFB/Mirroring is 4 bytes
+			 * vr_ps - Virtually pixel size for YUYV/UYVY is
+			 *         2 bytes
+			 */
+			ps = 4;
+			vr_ps = 2;
+		} else {
+			ps = 2;	/* otherwise the pixel size is 2 byte */
+		}
+	} else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) {
+		ps = 4;
+	} else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) {
+		ps = 3;
+	}
+	vout->ps = ps;
+	vout->vr_ps = vr_ps;
+
+	if (is_rotation_enabled(vout)) {
+		line_length = MAX_PIXELS_PER_LINE;
+		ctop = (pix->height - crop->height) - crop->top;
+		cleft = (pix->width - crop->width) - crop->left;
+	} else {
+		line_length = pix->width;
+	}
+	vout->line_length = line_length;
+	switch (rotation) {
+	case dss_rotation_90_degree:
+		offset = vout->vrfb_context[0].yoffset *
+			vout->vrfb_context[0].bytespp;
+		temp_ps = ps / vr_ps;
+		if (mirroring == 0) {
+			*cropped_offset = offset + line_length *
+				temp_ps * cleft + crop->top * temp_ps;
+		} else {
+			*cropped_offset = offset + line_length * temp_ps *
+				cleft + crop->top * temp_ps + (line_length *
+				((crop->width / (vr_ps)) - 1) * ps);
+		}
+		break;
+	case dss_rotation_180_degree:
+		offset = ((MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset *
+			vout->vrfb_context[0].bytespp) +
+			(vout->vrfb_context[0].xoffset *
+			vout->vrfb_context[0].bytespp));
+		if (mirroring == 0) {
+			*cropped_offset = offset + (line_length * ps * ctop) +
+				(cleft / vr_ps) * ps;
+
+		} else {
+			*cropped_offset = offset + (line_length * ps * ctop) +
+				(cleft / vr_ps) * ps + (line_length *
+				(crop->height - 1) * ps);
+		}
+		break;
+	case dss_rotation_270_degree:
+		offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset *
+			vout->vrfb_context[0].bytespp;
+		temp_ps = ps / vr_ps;
+		if (mirroring == 0) {
+			*cropped_offset = offset + line_length *
+			    temp_ps * crop->left + ctop * ps;
+		} else {
+			*cropped_offset = offset + line_length *
+				temp_ps * crop->left + ctop * ps +
+				(line_length * ((crop->width / vr_ps) - 1) *
+				 ps);
+		}
+		break;
+	case dss_rotation_0_degree:
+		if (mirroring == 0) {
+			*cropped_offset = (line_length * ps) *
+				crop->top + (crop->left / vr_ps) * ps;
+		} else {
+			*cropped_offset = (line_length * ps) *
+				crop->top + (crop->left / vr_ps) * ps +
+				(line_length * (crop->height - 1) * ps);
+		}
+		break;
+	default:
+		*cropped_offset = (line_length * ps * crop->top) /
+			vr_ps + (crop->left * ps) / vr_ps +
+			((crop->width / vr_ps) - 1) * ps;
+		break;
+	}
+}
diff --git a/drivers/media/platform/omap/omap_vout_vrfb.h b/drivers/media/platform/omap/omap_vout_vrfb.h
new file mode 100644
index 0000000..ffde741
--- /dev/null
+++ b/drivers/media/platform/omap/omap_vout_vrfb.h
@@ -0,0 +1,40 @@
+/*
+ * omap_vout_vrfb.h
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#ifndef OMAP_VOUT_VRFB_H
+#define OMAP_VOUT_VRFB_H
+
+#ifdef CONFIG_VIDEO_OMAP2_VOUT_VRFB
+void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout);
+int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
+			u32 static_vrfb_allocation);
+void omap_vout_release_vrfb(struct omap_vout_device *vout);
+int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
+			unsigned int *count, unsigned int startindex);
+int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
+			struct videobuf_buffer *vb);
+void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout);
+#else
+void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { }
+int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
+			u32 static_vrfb_allocation)
+		{ return 0; }
+void omap_vout_release_vrfb(struct omap_vout_device *vout) { }
+int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
+			unsigned int *count, unsigned int startindex)
+		{ return 0; }
+int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
+			struct videobuf_buffer *vb)
+		{ return 0; }
+void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { }
+#endif
+
+#endif
diff --git a/drivers/media/platform/omap/omap_voutdef.h b/drivers/media/platform/omap/omap_voutdef.h
new file mode 100644
index 0000000..27a95d2
--- /dev/null
+++ b/drivers/media/platform/omap/omap_voutdef.h
@@ -0,0 +1,225 @@
+/*
+ * omap_voutdef.h
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef OMAP_VOUTDEF_H
+#define OMAP_VOUTDEF_H
+
+#include <video/omapdss.h>
+#include <plat/vrfb.h>
+
+#define YUYV_BPP        2
+#define RGB565_BPP      2
+#define RGB24_BPP       3
+#define RGB32_BPP       4
+#define TILE_SIZE       32
+#define YUYV_VRFB_BPP   2
+#define RGB_VRFB_BPP    1
+#define MAX_CID		3
+#define MAC_VRFB_CTXS	4
+#define MAX_VOUT_DEV	2
+#define MAX_OVLS	3
+#define MAX_DISPLAYS	10
+#define MAX_MANAGERS	3
+
+#define QQVGA_WIDTH		160
+#define QQVGA_HEIGHT		120
+
+/* Max Resolution supported by the driver */
+#define VID_MAX_WIDTH		1280	/* Largest width */
+#define VID_MAX_HEIGHT		720	/* Largest height */
+
+/* Mimimum requirement is 2x2 for DSS */
+#define VID_MIN_WIDTH		2
+#define VID_MIN_HEIGHT		2
+
+/* 2048 x 2048 is max res supported by OMAP display controller */
+#define MAX_PIXELS_PER_LINE     2048
+
+#define VRFB_TX_TIMEOUT         1000
+#define VRFB_NUM_BUFS		4
+
+/* Max buffer size tobe allocated during init */
+#define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_MAX_HEIGHT*4)
+
+enum dma_channel_state {
+	DMA_CHAN_NOT_ALLOTED,
+	DMA_CHAN_ALLOTED,
+};
+
+/* Enum for Rotation
+ * DSS understands rotation in 0, 1, 2, 3 context
+ * while V4L2 driver understands it as 0, 90, 180, 270
+ */
+enum dss_rotation {
+	dss_rotation_0_degree	= 0,
+	dss_rotation_90_degree	= 1,
+	dss_rotation_180_degree	= 2,
+	dss_rotation_270_degree = 3,
+};
+
+/* Enum for choosing rotation type for vout
+ * DSS2 doesn't understand no rotation as an
+ * option while V4L2 driver doesn't support
+ * rotation in the case where VRFB is not built in
+ * the kernel
+ */
+enum vout_rotaion_type {
+	VOUT_ROT_NONE	= 0,
+	VOUT_ROT_VRFB	= 1,
+};
+
+/*
+ * This structure is used to store the DMA transfer parameters
+ * for VRFB hidden buffer
+ */
+struct vid_vrfb_dma {
+	int dev_id;
+	int dma_ch;
+	int req_status;
+	int tx_status;
+	wait_queue_head_t wait;
+};
+
+struct omapvideo_info {
+	int id;
+	int num_overlays;
+	struct omap_overlay *overlays[MAX_OVLS];
+	enum vout_rotaion_type rotation_type;
+};
+
+struct omap2video_device {
+	struct mutex  mtx;
+
+	int state;
+
+	struct v4l2_device v4l2_dev;
+	struct omap_vout_device *vouts[MAX_VOUT_DEV];
+
+	int num_displays;
+	struct omap_dss_device *displays[MAX_DISPLAYS];
+	int num_overlays;
+	struct omap_overlay *overlays[MAX_OVLS];
+	int num_managers;
+	struct omap_overlay_manager *managers[MAX_MANAGERS];
+};
+
+/* per-device data structure */
+struct omap_vout_device {
+
+	struct omapvideo_info vid_info;
+	struct video_device *vfd;
+	struct omap2video_device *vid_dev;
+	int vid;
+	int opened;
+
+	/* we don't allow to change image fmt/size once buffer has
+	 * been allocated
+	 */
+	int buffer_allocated;
+	/* allow to reuse previously allocated buffer which is big enough */
+	int buffer_size;
+	/* keep buffer info across opens */
+	unsigned long buf_virt_addr[VIDEO_MAX_FRAME];
+	unsigned long buf_phy_addr[VIDEO_MAX_FRAME];
+	enum omap_color_mode dss_mode;
+
+	/* we don't allow to request new buffer when old buffers are
+	 * still mmaped
+	 */
+	int mmap_count;
+
+	spinlock_t vbq_lock;		/* spinlock for videobuf queues */
+	unsigned long field_count;	/* field counter for videobuf_buffer */
+
+	/* non-NULL means streaming is in progress. */
+	bool streaming;
+
+	struct v4l2_pix_format pix;
+	struct v4l2_rect crop;
+	struct v4l2_window win;
+	struct v4l2_framebuffer fbuf;
+
+	/* Lock to protect the shared data structures in ioctl */
+	struct mutex lock;
+
+	/* V4L2 control structure for different control id */
+	struct v4l2_control control[MAX_CID];
+	enum dss_rotation rotation;
+	bool mirror;
+	int flicker_filter;
+	/* V4L2 control structure for different control id */
+
+	int bpp; /* bytes per pixel */
+	int vrfb_bpp; /* bytes per pixel with respect to VRFB */
+
+	struct vid_vrfb_dma vrfb_dma_tx;
+	unsigned int smsshado_phy_addr[MAC_VRFB_CTXS];
+	unsigned int smsshado_virt_addr[MAC_VRFB_CTXS];
+	struct vrfb vrfb_context[MAC_VRFB_CTXS];
+	bool vrfb_static_allocation;
+	unsigned int smsshado_size;
+	unsigned char pos;
+
+	int ps, vr_ps, line_length, first_int, field_id;
+	enum v4l2_memory memory;
+	struct videobuf_buffer *cur_frm, *next_frm;
+	struct list_head dma_queue;
+	u8 *queued_buf_addr[VIDEO_MAX_FRAME];
+	u32 cropped_offset;
+	s32 tv_field1_offset;
+	void *isr_handle;
+
+	/* Buffer queue variables */
+	struct omap_vout_device *vout;
+	enum v4l2_buf_type type;
+	struct videobuf_queue vbq;
+	int io_allowed;
+
+};
+
+/*
+ * Return true if rotation is 90 or 270
+ */
+static inline int is_rotation_90_or_270(const struct omap_vout_device *vout)
+{
+	return (vout->rotation == dss_rotation_90_degree ||
+			vout->rotation == dss_rotation_270_degree);
+}
+
+/*
+ * Return true if rotation is enabled
+ */
+static inline int is_rotation_enabled(const struct omap_vout_device *vout)
+{
+	return vout->rotation || vout->mirror;
+}
+
+/*
+ * Reverse the rotation degree if mirroring is enabled
+ */
+static inline int calc_rotation(const struct omap_vout_device *vout)
+{
+	if (!vout->mirror)
+		return vout->rotation;
+
+	switch (vout->rotation) {
+	case dss_rotation_90_degree:
+		return dss_rotation_270_degree;
+	case dss_rotation_270_degree:
+		return dss_rotation_90_degree;
+	case dss_rotation_180_degree:
+		return dss_rotation_0_degree;
+	default:
+		return dss_rotation_180_degree;
+	}
+}
+
+void omap_vout_free_buffers(struct omap_vout_device *vout);
+#endif	/* ifndef OMAP_VOUTDEF_H */
diff --git a/drivers/media/platform/omap/omap_voutlib.c b/drivers/media/platform/omap/omap_voutlib.c
new file mode 100644
index 0000000..115408b
--- /dev/null
+++ b/drivers/media/platform/omap/omap_voutlib.c
@@ -0,0 +1,339 @@
+/*
+ * omap_voutlib.c
+ *
+ * Copyright (C) 2005-2010 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * Based on the OMAP2 camera driver
+ * Video-for-Linux (Version 2) camera capture driver for
+ * the OMAP24xx camera controller.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <linux/dma-mapping.h>
+
+#include <plat/cpu.h>
+
+#include "omap_voutlib.h"
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("OMAP Video library");
+MODULE_LICENSE("GPL");
+
+/* Return the default overlay cropping rectangle in crop given the image
+ * size in pix and the video display size in fbuf.  The default
+ * cropping rectangle is the largest rectangle no larger than the capture size
+ * that will fit on the display.  The default cropping rectangle is centered in
+ * the image.  All dimensions and offsets are rounded down to even numbers.
+ */
+void omap_vout_default_crop(struct v4l2_pix_format *pix,
+		  struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop)
+{
+	crop->width = (pix->width < fbuf->fmt.width) ?
+		pix->width : fbuf->fmt.width;
+	crop->height = (pix->height < fbuf->fmt.height) ?
+		pix->height : fbuf->fmt.height;
+	crop->width &= ~1;
+	crop->height &= ~1;
+	crop->left = ((pix->width - crop->width) >> 1) & ~1;
+	crop->top = ((pix->height - crop->height) >> 1) & ~1;
+}
+EXPORT_SYMBOL_GPL(omap_vout_default_crop);
+
+/* Given a new render window in new_win, adjust the window to the
+ * nearest supported configuration.  The adjusted window parameters are
+ * returned in new_win.
+ * Returns zero if successful, or -EINVAL if the requested window is
+ * impossible and cannot reasonably be adjusted.
+ */
+int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
+			struct v4l2_window *new_win)
+{
+	struct v4l2_rect try_win;
+
+	/* make a working copy of the new_win rectangle */
+	try_win = new_win->w;
+
+	/* adjust the preview window so it fits on the display by clipping any
+	 * offscreen areas
+	 */
+	if (try_win.left < 0) {
+		try_win.width += try_win.left;
+		try_win.left = 0;
+	}
+	if (try_win.top < 0) {
+		try_win.height += try_win.top;
+		try_win.top = 0;
+	}
+	try_win.width = (try_win.width < fbuf->fmt.width) ?
+		try_win.width : fbuf->fmt.width;
+	try_win.height = (try_win.height < fbuf->fmt.height) ?
+		try_win.height : fbuf->fmt.height;
+	if (try_win.left + try_win.width > fbuf->fmt.width)
+		try_win.width = fbuf->fmt.width - try_win.left;
+	if (try_win.top + try_win.height > fbuf->fmt.height)
+		try_win.height = fbuf->fmt.height - try_win.top;
+	try_win.width &= ~1;
+	try_win.height &= ~1;
+
+	if (try_win.width <= 0 || try_win.height <= 0)
+		return -EINVAL;
+
+	/* We now have a valid preview window, so go with it */
+	new_win->w = try_win;
+	new_win->field = V4L2_FIELD_ANY;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(omap_vout_try_window);
+
+/* Given a new render window in new_win, adjust the window to the
+ * nearest supported configuration.  The image cropping window in crop
+ * will also be adjusted if necessary.  Preference is given to keeping the
+ * the window as close to the requested configuration as possible.  If
+ * successful, new_win, vout->win, and crop are updated.
+ * Returns zero if successful, or -EINVAL if the requested preview window is
+ * impossible and cannot reasonably be adjusted.
+ */
+int omap_vout_new_window(struct v4l2_rect *crop,
+		struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
+		struct v4l2_window *new_win)
+{
+	int err;
+
+	err = omap_vout_try_window(fbuf, new_win);
+	if (err)
+		return err;
+
+	/* update our preview window */
+	win->w = new_win->w;
+	win->field = new_win->field;
+	win->chromakey = new_win->chromakey;
+
+	/* Adjust the cropping window to allow for resizing limitation */
+	if (cpu_is_omap24xx()) {
+		/* For 24xx limit is 8x to 1/2x scaling. */
+		if ((crop->height/win->w.height) >= 2)
+			crop->height = win->w.height * 2;
+
+		if ((crop->width/win->w.width) >= 2)
+			crop->width = win->w.width * 2;
+
+		if (crop->width > 768) {
+			/* The OMAP2420 vertical resizing line buffer is 768
+			 * pixels wide. If the cropped image is wider than
+			 * 768 pixels then it cannot be vertically resized.
+			 */
+			if (crop->height != win->w.height)
+				crop->width = 768;
+		}
+	} else if (cpu_is_omap34xx()) {
+		/* For 34xx limit is 8x to 1/4x scaling. */
+		if ((crop->height/win->w.height) >= 4)
+			crop->height = win->w.height * 4;
+
+		if ((crop->width/win->w.width) >= 4)
+			crop->width = win->w.width * 4;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(omap_vout_new_window);
+
+/* Given a new cropping rectangle in new_crop, adjust the cropping rectangle to
+ * the nearest supported configuration.  The image render window in win will
+ * also be adjusted if necessary.  The preview window is adjusted such that the
+ * horizontal and vertical rescaling ratios stay constant.  If the render
+ * window would fall outside the display boundaries, the cropping rectangle
+ * will also be adjusted to maintain the rescaling ratios.  If successful, crop
+ * and win are updated.
+ * Returns zero if successful, or -EINVAL if the requested cropping rectangle is
+ * impossible and cannot reasonably be adjusted.
+ */
+int omap_vout_new_crop(struct v4l2_pix_format *pix,
+	      struct v4l2_rect *crop, struct v4l2_window *win,
+	      struct v4l2_framebuffer *fbuf, const struct v4l2_rect *new_crop)
+{
+	struct v4l2_rect try_crop;
+	unsigned long vresize, hresize;
+
+	/* make a working copy of the new_crop rectangle */
+	try_crop = *new_crop;
+
+	/* adjust the cropping rectangle so it fits in the image */
+	if (try_crop.left < 0) {
+		try_crop.width += try_crop.left;
+		try_crop.left = 0;
+	}
+	if (try_crop.top < 0) {
+		try_crop.height += try_crop.top;
+		try_crop.top = 0;
+	}
+	try_crop.width = (try_crop.width < pix->width) ?
+		try_crop.width : pix->width;
+	try_crop.height = (try_crop.height < pix->height) ?
+		try_crop.height : pix->height;
+	if (try_crop.left + try_crop.width > pix->width)
+		try_crop.width = pix->width - try_crop.left;
+	if (try_crop.top + try_crop.height > pix->height)
+		try_crop.height = pix->height - try_crop.top;
+
+	try_crop.width &= ~1;
+	try_crop.height &= ~1;
+
+	if (try_crop.width <= 0 || try_crop.height <= 0)
+		return -EINVAL;
+
+	if (cpu_is_omap24xx()) {
+		if (try_crop.height != win->w.height) {
+			/* If we're resizing vertically, we can't support a
+			 * crop width wider than 768 pixels.
+			 */
+			if (try_crop.width > 768)
+				try_crop.width = 768;
+		}
+	}
+	/* vertical resizing */
+	vresize = (1024 * try_crop.height) / win->w.height;
+	if (cpu_is_omap24xx() && (vresize > 2048))
+		vresize = 2048;
+	else if (cpu_is_omap34xx() && (vresize > 4096))
+		vresize = 4096;
+
+	win->w.height = ((1024 * try_crop.height) / vresize) & ~1;
+	if (win->w.height == 0)
+		win->w.height = 2;
+	if (win->w.height + win->w.top > fbuf->fmt.height) {
+		/* We made the preview window extend below the bottom of the
+		 * display, so clip it to the display boundary and resize the
+		 * cropping height to maintain the vertical resizing ratio.
+		 */
+		win->w.height = (fbuf->fmt.height - win->w.top) & ~1;
+		if (try_crop.height == 0)
+			try_crop.height = 2;
+	}
+	/* horizontal resizing */
+	hresize = (1024 * try_crop.width) / win->w.width;
+	if (cpu_is_omap24xx() && (hresize > 2048))
+		hresize = 2048;
+	else if (cpu_is_omap34xx() && (hresize > 4096))
+		hresize = 4096;
+
+	win->w.width = ((1024 * try_crop.width) / hresize) & ~1;
+	if (win->w.width == 0)
+		win->w.width = 2;
+	if (win->w.width + win->w.left > fbuf->fmt.width) {
+		/* We made the preview window extend past the right side of the
+		 * display, so clip it to the display boundary and resize the
+		 * cropping width to maintain the horizontal resizing ratio.
+		 */
+		win->w.width = (fbuf->fmt.width - win->w.left) & ~1;
+		if (try_crop.width == 0)
+			try_crop.width = 2;
+	}
+	if (cpu_is_omap24xx()) {
+		if ((try_crop.height/win->w.height) >= 2)
+			try_crop.height = win->w.height * 2;
+
+		if ((try_crop.width/win->w.width) >= 2)
+			try_crop.width = win->w.width * 2;
+
+		if (try_crop.width > 768) {
+			/* The OMAP2420 vertical resizing line buffer is
+			 * 768 pixels wide.  If the cropped image is wider
+			 * than 768 pixels then it cannot be vertically resized.
+			 */
+			if (try_crop.height != win->w.height)
+				try_crop.width = 768;
+		}
+	} else if (cpu_is_omap34xx()) {
+		if ((try_crop.height/win->w.height) >= 4)
+			try_crop.height = win->w.height * 4;
+
+		if ((try_crop.width/win->w.width) >= 4)
+			try_crop.width = win->w.width * 4;
+	}
+	/* update our cropping rectangle and we're done */
+	*crop = try_crop;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(omap_vout_new_crop);
+
+/* Given a new format in pix and fbuf,  crop and win
+ * structures are initialized to default values. crop
+ * is initialized to the largest window size that will fit on the display.  The
+ * crop window is centered in the image. win is initialized to
+ * the same size as crop and is centered on the display.
+ * All sizes and offsets are constrained to be even numbers.
+ */
+void omap_vout_new_format(struct v4l2_pix_format *pix,
+		struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
+		struct v4l2_window *win)
+{
+	/* crop defines the preview source window in the image capture
+	 * buffer
+	 */
+	omap_vout_default_crop(pix, fbuf, crop);
+
+	/* win defines the preview target window on the display */
+	win->w.width = crop->width;
+	win->w.height = crop->height;
+	win->w.left = ((fbuf->fmt.width - win->w.width) >> 1) & ~1;
+	win->w.top = ((fbuf->fmt.height - win->w.height) >> 1) & ~1;
+}
+EXPORT_SYMBOL_GPL(omap_vout_new_format);
+
+/*
+ * Allocate buffers
+ */
+unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr)
+{
+	u32 order, size;
+	unsigned long virt_addr, addr;
+
+	size = PAGE_ALIGN(buf_size);
+	order = get_order(size);
+	virt_addr = __get_free_pages(GFP_KERNEL, order);
+	addr = virt_addr;
+
+	if (virt_addr) {
+		while (size > 0) {
+			SetPageReserved(virt_to_page(addr));
+			addr += PAGE_SIZE;
+			size -= PAGE_SIZE;
+		}
+	}
+	*phys_addr = (u32) virt_to_phys((void *) virt_addr);
+	return virt_addr;
+}
+
+/*
+ * Free buffers
+ */
+void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size)
+{
+	u32 order, size;
+	unsigned long addr = virtaddr;
+
+	size = PAGE_ALIGN(buf_size);
+	order = get_order(size);
+
+	while (size > 0) {
+		ClearPageReserved(virt_to_page(addr));
+		addr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+	free_pages((unsigned long) virtaddr, order);
+}
diff --git a/drivers/media/platform/omap/omap_voutlib.h b/drivers/media/platform/omap/omap_voutlib.h
new file mode 100644
index 0000000..e51750a
--- /dev/null
+++ b/drivers/media/platform/omap/omap_voutlib.h
@@ -0,0 +1,36 @@
+/*
+ * omap_voutlib.h
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#ifndef OMAP_VOUTLIB_H
+#define OMAP_VOUTLIB_H
+
+void omap_vout_default_crop(struct v4l2_pix_format *pix,
+		struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop);
+
+int omap_vout_new_crop(struct v4l2_pix_format *pix,
+		struct v4l2_rect *crop, struct v4l2_window *win,
+		struct v4l2_framebuffer *fbuf,
+		const struct v4l2_rect *new_crop);
+
+int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
+		struct v4l2_window *new_win);
+
+int omap_vout_new_window(struct v4l2_rect *crop,
+		struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
+		struct v4l2_window *new_win);
+
+void omap_vout_new_format(struct v4l2_pix_format *pix,
+		struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
+		struct v4l2_window *win);
+unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr);
+void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size);
+#endif	/* #ifndef OMAP_VOUTLIB_H */
+
diff --git a/drivers/media/platform/omap1_camera.c b/drivers/media/platform/omap1_camera.c
new file mode 100644
index 0000000..fa08c76
--- /dev/null
+++ b/drivers/media/platform/omap1_camera.c
@@ -0,0 +1,1723 @@
+/*
+ * V4L2 SoC Camera driver for OMAP1 Camera Interface
+ *
+ * Copyright (C) 2010, Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
+ *
+ * Based on V4L2 Driver for i.MXL/i.MXL camera (CSI) host
+ * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ * Copyright (C) 2009, Darius Augulis <augulis.darius@gmail.com>
+ *
+ * Based on PXA SoC camera driver
+ * Copyright (C) 2006, Sascha Hauer, Pengutronix
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * Hardware specific bits initialy based on former work by Matt Callow
+ * drivers/media/platform/omap/omap1510cam.c
+ * Copyright (C) 2006 Matt Callow
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <media/omap1_camera.h>
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/videobuf-dma-contig.h>
+#include <media/videobuf-dma-sg.h>
+
+#include <plat/dma.h>
+
+
+#define DRIVER_NAME		"omap1-camera"
+#define DRIVER_VERSION		"0.0.2"
+
+
+/*
+ * ---------------------------------------------------------------------------
+ *  OMAP1 Camera Interface registers
+ * ---------------------------------------------------------------------------
+ */
+
+#define REG_CTRLCLOCK		0x00
+#define REG_IT_STATUS		0x04
+#define REG_MODE		0x08
+#define REG_STATUS		0x0C
+#define REG_CAMDATA		0x10
+#define REG_GPIO		0x14
+#define REG_PEAK_COUNTER	0x18
+
+/* CTRLCLOCK bit shifts */
+#define LCLK_EN			BIT(7)
+#define DPLL_EN			BIT(6)
+#define MCLK_EN			BIT(5)
+#define CAMEXCLK_EN		BIT(4)
+#define POLCLK			BIT(3)
+#define FOSCMOD_SHIFT		0
+#define FOSCMOD_MASK		(0x7 << FOSCMOD_SHIFT)
+#define FOSCMOD_12MHz		0x0
+#define FOSCMOD_6MHz		0x2
+#define FOSCMOD_9_6MHz		0x4
+#define FOSCMOD_24MHz		0x5
+#define FOSCMOD_8MHz		0x6
+
+/* IT_STATUS bit shifts */
+#define DATA_TRANSFER		BIT(5)
+#define FIFO_FULL		BIT(4)
+#define H_DOWN			BIT(3)
+#define H_UP			BIT(2)
+#define V_DOWN			BIT(1)
+#define V_UP			BIT(0)
+
+/* MODE bit shifts */
+#define RAZ_FIFO		BIT(18)
+#define EN_FIFO_FULL		BIT(17)
+#define EN_NIRQ			BIT(16)
+#define THRESHOLD_SHIFT		9
+#define THRESHOLD_MASK		(0x7f << THRESHOLD_SHIFT)
+#define DMA			BIT(8)
+#define EN_H_DOWN		BIT(7)
+#define EN_H_UP			BIT(6)
+#define EN_V_DOWN		BIT(5)
+#define EN_V_UP			BIT(4)
+#define ORDERCAMD		BIT(3)
+
+#define IRQ_MASK		(EN_V_UP | EN_V_DOWN | EN_H_UP | EN_H_DOWN | \
+				 EN_NIRQ | EN_FIFO_FULL)
+
+/* STATUS bit shifts */
+#define HSTATUS			BIT(1)
+#define VSTATUS			BIT(0)
+
+/* GPIO bit shifts */
+#define CAM_RST			BIT(0)
+
+/* end of OMAP1 Camera Interface registers */
+
+
+#define SOCAM_BUS_FLAGS	(V4L2_MBUS_MASTER | \
+			V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
+			V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \
+			V4L2_MBUS_DATA_ACTIVE_HIGH)
+
+
+#define FIFO_SIZE		((THRESHOLD_MASK >> THRESHOLD_SHIFT) + 1)
+#define FIFO_SHIFT		__fls(FIFO_SIZE)
+
+#define DMA_BURST_SHIFT		(1 + OMAP_DMA_DATA_BURST_4)
+#define DMA_BURST_SIZE		(1 << DMA_BURST_SHIFT)
+
+#define DMA_ELEMENT_SHIFT	OMAP_DMA_DATA_TYPE_S32
+#define DMA_ELEMENT_SIZE	(1 << DMA_ELEMENT_SHIFT)
+
+#define DMA_FRAME_SHIFT_CONTIG	(FIFO_SHIFT - 1)
+#define DMA_FRAME_SHIFT_SG	DMA_BURST_SHIFT
+
+#define DMA_FRAME_SHIFT(x)	((x) == OMAP1_CAM_DMA_CONTIG ? \
+						DMA_FRAME_SHIFT_CONTIG : \
+						DMA_FRAME_SHIFT_SG)
+#define DMA_FRAME_SIZE(x)	(1 << DMA_FRAME_SHIFT(x))
+#define DMA_SYNC		OMAP_DMA_SYNC_FRAME
+#define THRESHOLD_LEVEL		DMA_FRAME_SIZE
+
+
+#define MAX_VIDEO_MEM		4	/* arbitrary video memory limit in MB */
+
+
+/*
+ * Structures
+ */
+
+/* buffer for one video frame */
+struct omap1_cam_buf {
+	struct videobuf_buffer		vb;
+	enum v4l2_mbus_pixelcode	code;
+	int				inwork;
+	struct scatterlist		*sgbuf;
+	int				sgcount;
+	int				bytes_left;
+	enum videobuf_state		result;
+};
+
+struct omap1_cam_dev {
+	struct soc_camera_host		soc_host;
+	struct soc_camera_device	*icd;
+	struct clk			*clk;
+
+	unsigned int			irq;
+	void __iomem			*base;
+
+	int				dma_ch;
+
+	struct omap1_cam_platform_data	*pdata;
+	struct resource			*res;
+	unsigned long			pflags;
+	unsigned long			camexclk;
+
+	struct list_head		capture;
+
+	/* lock used to protect videobuf */
+	spinlock_t			lock;
+
+	/* Pointers to DMA buffers */
+	struct omap1_cam_buf		*active;
+	struct omap1_cam_buf		*ready;
+
+	enum omap1_cam_vb_mode		vb_mode;
+	int				(*mmap_mapper)(struct videobuf_queue *q,
+						struct videobuf_buffer *buf,
+						struct vm_area_struct *vma);
+
+	u32				reg_cache[0];
+};
+
+
+static void cam_write(struct omap1_cam_dev *pcdev, u16 reg, u32 val)
+{
+	pcdev->reg_cache[reg / sizeof(u32)] = val;
+	__raw_writel(val, pcdev->base + reg);
+}
+
+static u32 cam_read(struct omap1_cam_dev *pcdev, u16 reg, bool from_cache)
+{
+	return !from_cache ? __raw_readl(pcdev->base + reg) :
+			pcdev->reg_cache[reg / sizeof(u32)];
+}
+
+#define CAM_READ(pcdev, reg) \
+		cam_read(pcdev, REG_##reg, false)
+#define CAM_WRITE(pcdev, reg, val) \
+		cam_write(pcdev, REG_##reg, val)
+#define CAM_READ_CACHE(pcdev, reg) \
+		cam_read(pcdev, REG_##reg, true)
+
+/*
+ *  Videobuf operations
+ */
+static int omap1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
+		unsigned int *size)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct omap1_cam_dev *pcdev = ici->priv;
+
+	*size = icd->sizeimage;
+
+	if (!*count || *count < OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode))
+		*count = OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode);
+
+	if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
+		*count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
+
+	dev_dbg(icd->parent,
+			"%s: count=%d, size=%d\n", __func__, *count, *size);
+
+	return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct omap1_cam_buf *buf,
+		enum omap1_cam_vb_mode vb_mode)
+{
+	struct videobuf_buffer *vb = &buf->vb;
+
+	BUG_ON(in_interrupt());
+
+	videobuf_waiton(vq, vb, 0, 0);
+
+	if (vb_mode == OMAP1_CAM_DMA_CONTIG) {
+		videobuf_dma_contig_free(vq, vb);
+	} else {
+		struct soc_camera_device *icd = vq->priv_data;
+		struct device *dev = icd->parent;
+		struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+		videobuf_dma_unmap(dev, dma);
+		videobuf_dma_free(dma);
+	}
+
+	vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int omap1_videobuf_prepare(struct videobuf_queue *vq,
+		struct videobuf_buffer *vb, enum v4l2_field field)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct omap1_cam_buf *buf = container_of(vb, struct omap1_cam_buf, vb);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct omap1_cam_dev *pcdev = ici->priv;
+	int ret;
+
+	WARN_ON(!list_empty(&vb->queue));
+
+	BUG_ON(NULL == icd->current_fmt);
+
+	buf->inwork = 1;
+
+	if (buf->code != icd->current_fmt->code || vb->field != field ||
+			vb->width  != icd->user_width ||
+			vb->height != icd->user_height) {
+		buf->code  = icd->current_fmt->code;
+		vb->width  = icd->user_width;
+		vb->height = icd->user_height;
+		vb->field  = field;
+		vb->state  = VIDEOBUF_NEEDS_INIT;
+	}
+
+	vb->size = icd->sizeimage;
+
+	if (vb->baddr && vb->bsize < vb->size) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (vb->state == VIDEOBUF_NEEDS_INIT) {
+		ret = videobuf_iolock(vq, vb, NULL);
+		if (ret)
+			goto fail;
+
+		vb->state = VIDEOBUF_PREPARED;
+	}
+	buf->inwork = 0;
+
+	return 0;
+fail:
+	free_buffer(vq, buf, pcdev->vb_mode);
+out:
+	buf->inwork = 0;
+	return ret;
+}
+
+static void set_dma_dest_params(int dma_ch, struct omap1_cam_buf *buf,
+		enum omap1_cam_vb_mode vb_mode)
+{
+	dma_addr_t dma_addr;
+	unsigned int block_size;
+
+	if (vb_mode == OMAP1_CAM_DMA_CONTIG) {
+		dma_addr = videobuf_to_dma_contig(&buf->vb);
+		block_size = buf->vb.size;
+	} else {
+		if (WARN_ON(!buf->sgbuf)) {
+			buf->result = VIDEOBUF_ERROR;
+			return;
+		}
+		dma_addr = sg_dma_address(buf->sgbuf);
+		if (WARN_ON(!dma_addr)) {
+			buf->sgbuf = NULL;
+			buf->result = VIDEOBUF_ERROR;
+			return;
+		}
+		block_size = sg_dma_len(buf->sgbuf);
+		if (WARN_ON(!block_size)) {
+			buf->sgbuf = NULL;
+			buf->result = VIDEOBUF_ERROR;
+			return;
+		}
+		if (unlikely(buf->bytes_left < block_size))
+			block_size = buf->bytes_left;
+		if (WARN_ON(dma_addr & (DMA_FRAME_SIZE(vb_mode) *
+				DMA_ELEMENT_SIZE - 1))) {
+			dma_addr = ALIGN(dma_addr, DMA_FRAME_SIZE(vb_mode) *
+					DMA_ELEMENT_SIZE);
+			block_size &= ~(DMA_FRAME_SIZE(vb_mode) *
+					DMA_ELEMENT_SIZE - 1);
+		}
+		buf->bytes_left -= block_size;
+		buf->sgcount++;
+	}
+
+	omap_set_dma_dest_params(dma_ch,
+		OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, dma_addr, 0, 0);
+	omap_set_dma_transfer_params(dma_ch,
+		OMAP_DMA_DATA_TYPE_S32, DMA_FRAME_SIZE(vb_mode),
+		block_size >> (DMA_FRAME_SHIFT(vb_mode) + DMA_ELEMENT_SHIFT),
+		DMA_SYNC, 0, 0);
+}
+
+static struct omap1_cam_buf *prepare_next_vb(struct omap1_cam_dev *pcdev)
+{
+	struct omap1_cam_buf *buf;
+
+	/*
+	 * If there is already a buffer pointed out by the pcdev->ready,
+	 * (re)use it, otherwise try to fetch and configure a new one.
+	 */
+	buf = pcdev->ready;
+	if (!buf) {
+		if (list_empty(&pcdev->capture))
+			return buf;
+		buf = list_entry(pcdev->capture.next,
+				struct omap1_cam_buf, vb.queue);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		pcdev->ready = buf;
+		list_del_init(&buf->vb.queue);
+	}
+
+	if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+		/*
+		 * In CONTIG mode, we can safely enter next buffer parameters
+		 * into the DMA programming register set after the DMA
+		 * has already been activated on the previous buffer
+		 */
+		set_dma_dest_params(pcdev->dma_ch, buf, pcdev->vb_mode);
+	} else {
+		/*
+		 * In SG mode, the above is not safe since there are probably
+		 * a bunch of sgbufs from previous sglist still pending.
+		 * Instead, mark the sglist fresh for the upcoming
+		 * try_next_sgbuf().
+		 */
+		buf->sgbuf = NULL;
+	}
+
+	return buf;
+}
+
+static struct scatterlist *try_next_sgbuf(int dma_ch, struct omap1_cam_buf *buf)
+{
+	struct scatterlist *sgbuf;
+
+	if (likely(buf->sgbuf)) {
+		/* current sglist is active */
+		if (unlikely(!buf->bytes_left)) {
+			/* indicate sglist complete */
+			sgbuf = NULL;
+		} else {
+			/* process next sgbuf */
+			sgbuf = sg_next(buf->sgbuf);
+			if (WARN_ON(!sgbuf)) {
+				buf->result = VIDEOBUF_ERROR;
+			} else if (WARN_ON(!sg_dma_len(sgbuf))) {
+				sgbuf = NULL;
+				buf->result = VIDEOBUF_ERROR;
+			}
+		}
+		buf->sgbuf = sgbuf;
+	} else {
+		/* sglist is fresh, initialize it before using */
+		struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+
+		sgbuf = dma->sglist;
+		if (!(WARN_ON(!sgbuf))) {
+			buf->sgbuf = sgbuf;
+			buf->sgcount = 0;
+			buf->bytes_left = buf->vb.size;
+			buf->result = VIDEOBUF_DONE;
+		}
+	}
+	if (sgbuf)
+		/*
+		 * Put our next sgbuf parameters (address, size)
+		 * into the DMA programming register set.
+		 */
+		set_dma_dest_params(dma_ch, buf, OMAP1_CAM_DMA_SG);
+
+	return sgbuf;
+}
+
+static void start_capture(struct omap1_cam_dev *pcdev)
+{
+	struct omap1_cam_buf *buf = pcdev->active;
+	u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
+	u32 mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN;
+
+	if (WARN_ON(!buf))
+		return;
+
+	/*
+	 * Enable start of frame interrupt, which we will use for activating
+	 * our end of frame watchdog when capture actually starts.
+	 */
+	mode |= EN_V_UP;
+
+	if (unlikely(ctrlclock & LCLK_EN))
+		/* stop pixel clock before FIFO reset */
+		CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
+	/* reset FIFO */
+	CAM_WRITE(pcdev, MODE, mode | RAZ_FIFO);
+
+	omap_start_dma(pcdev->dma_ch);
+
+	if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
+		/*
+		 * In SG mode, it's a good moment for fetching next sgbuf
+		 * from the current sglist and, if available, already putting
+		 * its parameters into the DMA programming register set.
+		 */
+		try_next_sgbuf(pcdev->dma_ch, buf);
+	}
+
+	/* (re)enable pixel clock */
+	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | LCLK_EN);
+	/* release FIFO reset */
+	CAM_WRITE(pcdev, MODE, mode);
+}
+
+static void suspend_capture(struct omap1_cam_dev *pcdev)
+{
+	u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
+
+	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
+	omap_stop_dma(pcdev->dma_ch);
+}
+
+static void disable_capture(struct omap1_cam_dev *pcdev)
+{
+	u32 mode = CAM_READ_CACHE(pcdev, MODE);
+
+	CAM_WRITE(pcdev, MODE, mode & ~(IRQ_MASK | DMA));
+}
+
+static void omap1_videobuf_queue(struct videobuf_queue *vq,
+						struct videobuf_buffer *vb)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct omap1_cam_dev *pcdev = ici->priv;
+	struct omap1_cam_buf *buf;
+	u32 mode;
+
+	list_add_tail(&vb->queue, &pcdev->capture);
+	vb->state = VIDEOBUF_QUEUED;
+
+	if (pcdev->active) {
+		/*
+		 * Capture in progress, so don't touch pcdev->ready even if
+		 * empty. Since the transfer of the DMA programming register set
+		 * content to the DMA working register set is done automatically
+		 * by the DMA hardware, this can pretty well happen while we
+		 * are keeping the lock here. Leave fetching it from the queue
+		 * to be done when a next DMA interrupt occures instead.
+		 */
+		return;
+	}
+
+	WARN_ON(pcdev->ready);
+
+	buf = prepare_next_vb(pcdev);
+	if (WARN_ON(!buf))
+		return;
+
+	pcdev->active = buf;
+	pcdev->ready = NULL;
+
+	dev_dbg(icd->parent,
+		"%s: capture not active, setup FIFO, start DMA\n", __func__);
+	mode = CAM_READ_CACHE(pcdev, MODE) & ~THRESHOLD_MASK;
+	mode |= THRESHOLD_LEVEL(pcdev->vb_mode) << THRESHOLD_SHIFT;
+	CAM_WRITE(pcdev, MODE, mode | EN_FIFO_FULL | DMA);
+
+	if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
+		/*
+		 * In SG mode, the above prepare_next_vb() didn't actually
+		 * put anything into the DMA programming register set,
+		 * so we have to do it now, before activating DMA.
+		 */
+		try_next_sgbuf(pcdev->dma_ch, buf);
+	}
+
+	start_capture(pcdev);
+}
+
+static void omap1_videobuf_release(struct videobuf_queue *vq,
+				 struct videobuf_buffer *vb)
+{
+	struct omap1_cam_buf *buf =
+			container_of(vb, struct omap1_cam_buf, vb);
+	struct soc_camera_device *icd = vq->priv_data;
+	struct device *dev = icd->parent;
+	struct soc_camera_host *ici = to_soc_camera_host(dev);
+	struct omap1_cam_dev *pcdev = ici->priv;
+
+	switch (vb->state) {
+	case VIDEOBUF_DONE:
+		dev_dbg(dev, "%s (done)\n", __func__);
+		break;
+	case VIDEOBUF_ACTIVE:
+		dev_dbg(dev, "%s (active)\n", __func__);
+		break;
+	case VIDEOBUF_QUEUED:
+		dev_dbg(dev, "%s (queued)\n", __func__);
+		break;
+	case VIDEOBUF_PREPARED:
+		dev_dbg(dev, "%s (prepared)\n", __func__);
+		break;
+	default:
+		dev_dbg(dev, "%s (unknown %d)\n", __func__, vb->state);
+		break;
+	}
+
+	free_buffer(vq, buf, pcdev->vb_mode);
+}
+
+static void videobuf_done(struct omap1_cam_dev *pcdev,
+		enum videobuf_state result)
+{
+	struct omap1_cam_buf *buf = pcdev->active;
+	struct videobuf_buffer *vb;
+	struct device *dev = pcdev->icd->parent;
+
+	if (WARN_ON(!buf)) {
+		suspend_capture(pcdev);
+		disable_capture(pcdev);
+		return;
+	}
+
+	if (result == VIDEOBUF_ERROR)
+		suspend_capture(pcdev);
+
+	vb = &buf->vb;
+	if (waitqueue_active(&vb->done)) {
+		if (!pcdev->ready && result != VIDEOBUF_ERROR) {
+			/*
+			 * No next buffer has been entered into the DMA
+			 * programming register set on time (could be done only
+			 * while the previous DMA interurpt was processed, not
+			 * later), so the last DMA block, be it a whole buffer
+			 * if in CONTIG or its last sgbuf if in SG mode, is
+			 * about to be reused by the just autoreinitialized DMA
+			 * engine, and overwritten with next frame data. Best we
+			 * can do is stopping the capture as soon as possible,
+			 * hopefully before the next frame start.
+			 */
+			suspend_capture(pcdev);
+		}
+		vb->state = result;
+		do_gettimeofday(&vb->ts);
+		if (result != VIDEOBUF_ERROR)
+			vb->field_count++;
+		wake_up(&vb->done);
+
+		/* shift in next buffer */
+		buf = pcdev->ready;
+		pcdev->active = buf;
+		pcdev->ready = NULL;
+
+		if (!buf) {
+			/*
+			 * No next buffer was ready on time (see above), so
+			 * indicate error condition to force capture restart or
+			 * stop, depending on next buffer already queued or not.
+			 */
+			result = VIDEOBUF_ERROR;
+			prepare_next_vb(pcdev);
+
+			buf = pcdev->ready;
+			pcdev->active = buf;
+			pcdev->ready = NULL;
+		}
+	} else if (pcdev->ready) {
+		/*
+		 * In both CONTIG and SG mode, the DMA engine has possibly
+		 * been already autoreinitialized with the preprogrammed
+		 * pcdev->ready buffer.  We can either accept this fact
+		 * and just swap the buffers, or provoke an error condition
+		 * and restart capture.  The former seems less intrusive.
+		 */
+		dev_dbg(dev, "%s: nobody waiting on videobuf, swap with next\n",
+				__func__);
+		pcdev->active = pcdev->ready;
+
+		if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
+			/*
+			 * In SG mode, we have to make sure that the buffer we
+			 * are putting back into the pcdev->ready is marked
+			 * fresh.
+			 */
+			buf->sgbuf = NULL;
+		}
+		pcdev->ready = buf;
+
+		buf = pcdev->active;
+	} else {
+		/*
+		 * No next buffer has been entered into
+		 * the DMA programming register set on time.
+		 */
+		if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+			/*
+			 * In CONTIG mode, the DMA engine has already been
+			 * reinitialized with the current buffer. Best we can do
+			 * is not touching it.
+			 */
+			dev_dbg(dev,
+				"%s: nobody waiting on videobuf, reuse it\n",
+				__func__);
+		} else {
+			/*
+			 * In SG mode, the DMA engine has just been
+			 * autoreinitialized with the last sgbuf from the
+			 * current list. Restart capture in order to transfer
+			 * next frame start into the first sgbuf, not the last
+			 * one.
+			 */
+			if (result != VIDEOBUF_ERROR) {
+				suspend_capture(pcdev);
+				result = VIDEOBUF_ERROR;
+			}
+		}
+	}
+
+	if (!buf) {
+		dev_dbg(dev, "%s: no more videobufs, stop capture\n", __func__);
+		disable_capture(pcdev);
+		return;
+	}
+
+	if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+		/*
+		 * In CONTIG mode, the current buffer parameters had already
+		 * been entered into the DMA programming register set while the
+		 * buffer was fetched with prepare_next_vb(), they may have also
+		 * been transferred into the runtime set and already active if
+		 * the DMA still running.
+		 */
+	} else {
+		/* In SG mode, extra steps are required */
+		if (result == VIDEOBUF_ERROR)
+			/* make sure we (re)use sglist from start on error */
+			buf->sgbuf = NULL;
+
+		/*
+		 * In any case, enter the next sgbuf parameters into the DMA
+		 * programming register set.  They will be used either during
+		 * nearest DMA autoreinitialization or, in case of an error,
+		 * on DMA startup below.
+		 */
+		try_next_sgbuf(pcdev->dma_ch, buf);
+	}
+
+	if (result == VIDEOBUF_ERROR) {
+		dev_dbg(dev, "%s: videobuf error; reset FIFO, restart DMA\n",
+				__func__);
+		start_capture(pcdev);
+		/*
+		 * In SG mode, the above also resulted in the next sgbuf
+		 * parameters being entered into the DMA programming register
+		 * set, making them ready for next DMA autoreinitialization.
+		 */
+	}
+
+	/*
+	 * Finally, try fetching next buffer.
+	 * In CONTIG mode, it will also enter it into the DMA programming
+	 * register set, making it ready for next DMA autoreinitialization.
+	 */
+	prepare_next_vb(pcdev);
+}
+
+static void dma_isr(int channel, unsigned short status, void *data)
+{
+	struct omap1_cam_dev *pcdev = data;
+	struct omap1_cam_buf *buf = pcdev->active;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pcdev->lock, flags);
+
+	if (WARN_ON(!buf)) {
+		suspend_capture(pcdev);
+		disable_capture(pcdev);
+		goto out;
+	}
+
+	if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+		/*
+		 * In CONTIG mode, assume we have just managed to collect the
+		 * whole frame, hopefully before our end of frame watchdog is
+		 * triggered. Then, all we have to do is disabling the watchdog
+		 * for this frame, and calling videobuf_done() with success
+		 * indicated.
+		 */
+		CAM_WRITE(pcdev, MODE,
+				CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN);
+		videobuf_done(pcdev, VIDEOBUF_DONE);
+	} else {
+		/*
+		 * In SG mode, we have to process every sgbuf from the current
+		 * sglist, one after another.
+		 */
+		if (buf->sgbuf) {
+			/*
+			 * Current sglist not completed yet, try fetching next
+			 * sgbuf, hopefully putting it into the DMA programming
+			 * register set, making it ready for next DMA
+			 * autoreinitialization.
+			 */
+			try_next_sgbuf(pcdev->dma_ch, buf);
+			if (buf->sgbuf)
+				goto out;
+
+			/*
+			 * No more sgbufs left in the current sglist. This
+			 * doesn't mean that the whole videobuffer is already
+			 * complete, but only that the last sgbuf from the
+			 * current sglist is about to be filled. It will be
+			 * ready on next DMA interrupt, signalled with the
+			 * buf->sgbuf set back to NULL.
+			 */
+			if (buf->result != VIDEOBUF_ERROR) {
+				/*
+				 * Video frame collected without errors so far,
+				 * we can prepare for collecting a next one
+				 * as soon as DMA gets autoreinitialized
+				 * after the current (last) sgbuf is completed.
+				 */
+				buf = prepare_next_vb(pcdev);
+				if (!buf)
+					goto out;
+
+				try_next_sgbuf(pcdev->dma_ch, buf);
+				goto out;
+			}
+		}
+		/* end of videobuf */
+		videobuf_done(pcdev, buf->result);
+	}
+
+out:
+	spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static irqreturn_t cam_isr(int irq, void *data)
+{
+	struct omap1_cam_dev *pcdev = data;
+	struct device *dev = pcdev->icd->parent;
+	struct omap1_cam_buf *buf = pcdev->active;
+	u32 it_status;
+	unsigned long flags;
+
+	it_status = CAM_READ(pcdev, IT_STATUS);
+	if (!it_status)
+		return IRQ_NONE;
+
+	spin_lock_irqsave(&pcdev->lock, flags);
+
+	if (WARN_ON(!buf)) {
+		dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n",
+			 __func__, it_status);
+		suspend_capture(pcdev);
+		disable_capture(pcdev);
+		goto out;
+	}
+
+	if (unlikely(it_status & FIFO_FULL)) {
+		dev_warn(dev, "%s: FIFO overflow\n", __func__);
+
+	} else if (it_status & V_DOWN) {
+		/* end of video frame watchdog */
+		if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+			/*
+			 * In CONTIG mode, the watchdog is disabled with
+			 * successful DMA end of block interrupt, and reenabled
+			 * on next frame start. If we get here, there is nothing
+			 * to check, we must be out of sync.
+			 */
+		} else {
+			if (buf->sgcount == 2) {
+				/*
+				 * If exactly 2 sgbufs from the next sglist have
+				 * been programmed into the DMA engine (the
+				 * first one already transferred into the DMA
+				 * runtime register set, the second one still
+				 * in the programming set), then we are in sync.
+				 */
+				goto out;
+			}
+		}
+		dev_notice(dev, "%s: unexpected end of video frame\n",
+				__func__);
+
+	} else if (it_status & V_UP) {
+		u32 mode;
+
+		if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+			/*
+			 * In CONTIG mode, we need this interrupt every frame
+			 * in oredr to reenable our end of frame watchdog.
+			 */
+			mode = CAM_READ_CACHE(pcdev, MODE);
+		} else {
+			/*
+			 * In SG mode, the below enabled end of frame watchdog
+			 * is kept on permanently, so we can turn this one shot
+			 * setup off.
+			 */
+			mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_UP;
+		}
+
+		if (!(mode & EN_V_DOWN)) {
+			/* (re)enable end of frame watchdog interrupt */
+			mode |= EN_V_DOWN;
+		}
+		CAM_WRITE(pcdev, MODE, mode);
+		goto out;
+
+	} else {
+		dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n",
+				__func__, it_status);
+		goto out;
+	}
+
+	videobuf_done(pcdev, VIDEOBUF_ERROR);
+out:
+	spin_unlock_irqrestore(&pcdev->lock, flags);
+	return IRQ_HANDLED;
+}
+
+static struct videobuf_queue_ops omap1_videobuf_ops = {
+	.buf_setup	= omap1_videobuf_setup,
+	.buf_prepare	= omap1_videobuf_prepare,
+	.buf_queue	= omap1_videobuf_queue,
+	.buf_release	= omap1_videobuf_release,
+};
+
+
+/*
+ * SOC Camera host operations
+ */
+
+static void sensor_reset(struct omap1_cam_dev *pcdev, bool reset)
+{
+	/* apply/release camera sensor reset if requested by platform data */
+	if (pcdev->pflags & OMAP1_CAMERA_RST_HIGH)
+		CAM_WRITE(pcdev, GPIO, reset);
+	else if (pcdev->pflags & OMAP1_CAMERA_RST_LOW)
+		CAM_WRITE(pcdev, GPIO, !reset);
+}
+
+/*
+ * The following two functions absolutely depend on the fact, that
+ * there can be only one camera on OMAP1 camera sensor interface
+ */
+static int omap1_cam_add_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct omap1_cam_dev *pcdev = ici->priv;
+	u32 ctrlclock;
+
+	if (pcdev->icd)
+		return -EBUSY;
+
+	clk_enable(pcdev->clk);
+
+	/* setup sensor clock */
+	ctrlclock = CAM_READ(pcdev, CTRLCLOCK);
+	ctrlclock &= ~(CAMEXCLK_EN | MCLK_EN | DPLL_EN);
+	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+
+	ctrlclock &= ~FOSCMOD_MASK;
+	switch (pcdev->camexclk) {
+	case 6000000:
+		ctrlclock |= CAMEXCLK_EN | FOSCMOD_6MHz;
+		break;
+	case 8000000:
+		ctrlclock |= CAMEXCLK_EN | FOSCMOD_8MHz | DPLL_EN;
+		break;
+	case 9600000:
+		ctrlclock |= CAMEXCLK_EN | FOSCMOD_9_6MHz | DPLL_EN;
+		break;
+	case 12000000:
+		ctrlclock |= CAMEXCLK_EN | FOSCMOD_12MHz;
+		break;
+	case 24000000:
+		ctrlclock |= CAMEXCLK_EN | FOSCMOD_24MHz | DPLL_EN;
+	default:
+		break;
+	}
+	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~DPLL_EN);
+
+	/* enable internal clock */
+	ctrlclock |= MCLK_EN;
+	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+
+	sensor_reset(pcdev, false);
+
+	pcdev->icd = icd;
+
+	dev_dbg(icd->parent, "OMAP1 Camera driver attached to camera %d\n",
+			icd->devnum);
+	return 0;
+}
+
+static void omap1_cam_remove_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct omap1_cam_dev *pcdev = ici->priv;
+	u32 ctrlclock;
+
+	BUG_ON(icd != pcdev->icd);
+
+	suspend_capture(pcdev);
+	disable_capture(pcdev);
+
+	sensor_reset(pcdev, true);
+
+	/* disable and release system clocks */
+	ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
+	ctrlclock &= ~(MCLK_EN | DPLL_EN | CAMEXCLK_EN);
+	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+
+	ctrlclock = (ctrlclock & ~FOSCMOD_MASK) | FOSCMOD_12MHz;
+	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | MCLK_EN);
+
+	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~MCLK_EN);
+
+	clk_disable(pcdev->clk);
+
+	pcdev->icd = NULL;
+
+	dev_dbg(icd->parent,
+		"OMAP1 Camera driver detached from camera %d\n", icd->devnum);
+}
+
+/* Duplicate standard formats based on host capability of byte swapping */
+static const struct soc_mbus_lookup omap1_cam_formats[] = {
+{
+	.code = V4L2_MBUS_FMT_UYVY8_2X8,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_YUYV,
+		.name			= "YUYV",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_VYUY8_2X8,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_YVYU,
+		.name			= "YVYU",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_YUYV8_2X8,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_UYVY,
+		.name			= "UYVY",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_YVYU8_2X8,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_VYUY,
+		.name			= "VYUY",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_RGB555,
+		.name			= "RGB555",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_RGB555X,
+		.name			= "RGB555X",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_RGB565,
+		.name			= "RGB565",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_RGB565X,
+		.name			= "RGB565X",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+},
+};
+
+static int omap1_cam_get_formats(struct soc_camera_device *icd,
+		unsigned int idx, struct soc_camera_format_xlate *xlate)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct device *dev = icd->parent;
+	int formats = 0, ret;
+	enum v4l2_mbus_pixelcode code;
+	const struct soc_mbus_pixelfmt *fmt;
+
+	ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
+	if (ret < 0)
+		/* No more formats */
+		return 0;
+
+	fmt = soc_mbus_get_fmtdesc(code);
+	if (!fmt) {
+		dev_warn(dev, "%s: unsupported format code #%d: %d\n", __func__,
+				idx, code);
+		return 0;
+	}
+
+	/* Check support for the requested bits-per-sample */
+	if (fmt->bits_per_sample != 8)
+		return 0;
+
+	switch (code) {
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+	case V4L2_MBUS_FMT_YVYU8_2X8:
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+	case V4L2_MBUS_FMT_VYUY8_2X8:
+	case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+	case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+	case V4L2_MBUS_FMT_RGB565_2X8_BE:
+	case V4L2_MBUS_FMT_RGB565_2X8_LE:
+		formats++;
+		if (xlate) {
+			xlate->host_fmt	= soc_mbus_find_fmtdesc(code,
+						omap1_cam_formats,
+						ARRAY_SIZE(omap1_cam_formats));
+			xlate->code	= code;
+			xlate++;
+			dev_dbg(dev,
+				"%s: providing format %s as byte swapped code #%d\n",
+				__func__, xlate->host_fmt->name, code);
+		}
+	default:
+		if (xlate)
+			dev_dbg(dev,
+				"%s: providing format %s in pass-through mode\n",
+				__func__, fmt->name);
+	}
+	formats++;
+	if (xlate) {
+		xlate->host_fmt	= fmt;
+		xlate->code	= code;
+		xlate++;
+	}
+
+	return formats;
+}
+
+static bool is_dma_aligned(s32 bytes_per_line, unsigned int height,
+		enum omap1_cam_vb_mode vb_mode)
+{
+	int size = bytes_per_line * height;
+
+	return IS_ALIGNED(bytes_per_line, DMA_ELEMENT_SIZE) &&
+		IS_ALIGNED(size, DMA_FRAME_SIZE(vb_mode) * DMA_ELEMENT_SIZE);
+}
+
+static int dma_align(int *width, int *height,
+		const struct soc_mbus_pixelfmt *fmt,
+		enum omap1_cam_vb_mode vb_mode, bool enlarge)
+{
+	s32 bytes_per_line = soc_mbus_bytes_per_line(*width, fmt);
+
+	if (bytes_per_line < 0)
+		return bytes_per_line;
+
+	if (!is_dma_aligned(bytes_per_line, *height, vb_mode)) {
+		unsigned int pxalign = __fls(bytes_per_line / *width);
+		unsigned int salign  = DMA_FRAME_SHIFT(vb_mode) +
+				DMA_ELEMENT_SHIFT - pxalign;
+		unsigned int incr    = enlarge << salign;
+
+		v4l_bound_align_image(width, 1, *width + incr, 0,
+				height, 1, *height + incr, 0, salign);
+		return 0;
+	}
+	return 1;
+}
+
+#define subdev_call_with_sense(pcdev, dev, icd, sd, function, args...)		     \
+({										     \
+	struct soc_camera_sense sense = {					     \
+		.master_clock		= pcdev->camexclk,			     \
+		.pixel_clock_max	= 0,					     \
+	};									     \
+	int __ret;								     \
+										     \
+	if (pcdev->pdata)							     \
+		sense.pixel_clock_max = pcdev->pdata->lclk_khz_max * 1000;	     \
+	icd->sense = &sense;							     \
+	__ret = v4l2_subdev_call(sd, video, function, ##args);			     \
+	icd->sense = NULL;							     \
+										     \
+	if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {				     \
+		if (sense.pixel_clock > sense.pixel_clock_max) {		     \
+			dev_err(dev,						     \
+				"%s: pixel clock %lu set by the camera too high!\n", \
+				__func__, sense.pixel_clock);			     \
+			__ret = -EINVAL;					     \
+		}								     \
+	}									     \
+	__ret;									     \
+})
+
+static int set_mbus_format(struct omap1_cam_dev *pcdev, struct device *dev,
+		struct soc_camera_device *icd, struct v4l2_subdev *sd,
+		struct v4l2_mbus_framefmt *mf,
+		const struct soc_camera_format_xlate *xlate)
+{
+	s32 bytes_per_line;
+	int ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_mbus_fmt, mf);
+
+	if (ret < 0) {
+		dev_err(dev, "%s: s_mbus_fmt failed\n", __func__);
+		return ret;
+	}
+
+	if (mf->code != xlate->code) {
+		dev_err(dev, "%s: unexpected pixel code change\n", __func__);
+		return -EINVAL;
+	}
+
+	bytes_per_line = soc_mbus_bytes_per_line(mf->width, xlate->host_fmt);
+	if (bytes_per_line < 0) {
+		dev_err(dev, "%s: soc_mbus_bytes_per_line() failed\n",
+				__func__);
+		return bytes_per_line;
+	}
+
+	if (!is_dma_aligned(bytes_per_line, mf->height, pcdev->vb_mode)) {
+		dev_err(dev, "%s: resulting geometry %ux%u not DMA aligned\n",
+				__func__, mf->width, mf->height);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int omap1_cam_set_crop(struct soc_camera_device *icd,
+			       struct v4l2_crop *crop)
+{
+	struct v4l2_rect *rect = &crop->c;
+	const struct soc_camera_format_xlate *xlate = icd->current_fmt;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct device *dev = icd->parent;
+	struct soc_camera_host *ici = to_soc_camera_host(dev);
+	struct omap1_cam_dev *pcdev = ici->priv;
+	struct v4l2_mbus_framefmt mf;
+	int ret;
+
+	ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_crop, crop);
+	if (ret < 0) {
+		dev_warn(dev, "%s: failed to crop to %ux%u@%u:%u\n", __func__,
+			 rect->width, rect->height, rect->left, rect->top);
+		return ret;
+	}
+
+	ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
+	if (ret < 0) {
+		dev_warn(dev, "%s: failed to fetch current format\n", __func__);
+		return ret;
+	}
+
+	ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode,
+			false);
+	if (ret < 0) {
+		dev_err(dev, "%s: failed to align %ux%u %s with DMA\n",
+				__func__, mf.width, mf.height,
+				xlate->host_fmt->name);
+		return ret;
+	}
+
+	if (!ret) {
+		/* sensor returned geometry not DMA aligned, trying to fix */
+		ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate);
+		if (ret < 0) {
+			dev_err(dev, "%s: failed to set format\n", __func__);
+			return ret;
+		}
+	}
+
+	icd->user_width	 = mf.width;
+	icd->user_height = mf.height;
+
+	return 0;
+}
+
+static int omap1_cam_set_fmt(struct soc_camera_device *icd,
+			      struct v4l2_format *f)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	const struct soc_camera_format_xlate *xlate;
+	struct device *dev = icd->parent;
+	struct soc_camera_host *ici = to_soc_camera_host(dev);
+	struct omap1_cam_dev *pcdev = ici->priv;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct v4l2_mbus_framefmt mf;
+	int ret;
+
+	xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+	if (!xlate) {
+		dev_warn(dev, "%s: format %#x not found\n", __func__,
+				pix->pixelformat);
+		return -EINVAL;
+	}
+
+	mf.width	= pix->width;
+	mf.height	= pix->height;
+	mf.field	= pix->field;
+	mf.colorspace	= pix->colorspace;
+	mf.code		= xlate->code;
+
+	ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode,
+			true);
+	if (ret < 0) {
+		dev_err(dev, "%s: failed to align %ux%u %s with DMA\n",
+				__func__, pix->width, pix->height,
+				xlate->host_fmt->name);
+		return ret;
+	}
+
+	ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate);
+	if (ret < 0) {
+		dev_err(dev, "%s: failed to set format\n", __func__);
+		return ret;
+	}
+
+	pix->width	 = mf.width;
+	pix->height	 = mf.height;
+	pix->field	 = mf.field;
+	pix->colorspace  = mf.colorspace;
+	icd->current_fmt = xlate;
+
+	return 0;
+}
+
+static int omap1_cam_try_fmt(struct soc_camera_device *icd,
+			      struct v4l2_format *f)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	const struct soc_camera_format_xlate *xlate;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct v4l2_mbus_framefmt mf;
+	int ret;
+	/* TODO: limit to mx1 hardware capabilities */
+
+	xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+	if (!xlate) {
+		dev_warn(icd->parent, "Format %#x not found\n",
+			 pix->pixelformat);
+		return -EINVAL;
+	}
+
+	mf.width	= pix->width;
+	mf.height	= pix->height;
+	mf.field	= pix->field;
+	mf.colorspace	= pix->colorspace;
+	mf.code		= xlate->code;
+
+	/* limit to sensor capabilities */
+	ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+	if (ret < 0)
+		return ret;
+
+	pix->width	= mf.width;
+	pix->height	= mf.height;
+	pix->field	= mf.field;
+	pix->colorspace	= mf.colorspace;
+
+	return 0;
+}
+
+static bool sg_mode;
+
+/*
+ * Local mmap_mapper wrapper,
+ * used for detecting videobuf-dma-contig buffer allocation failures
+ * and switching to videobuf-dma-sg automatically for future attempts.
+ */
+static int omap1_cam_mmap_mapper(struct videobuf_queue *q,
+				  struct videobuf_buffer *buf,
+				  struct vm_area_struct *vma)
+{
+	struct soc_camera_device *icd = q->priv_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct omap1_cam_dev *pcdev = ici->priv;
+	int ret;
+
+	ret = pcdev->mmap_mapper(q, buf, vma);
+
+	if (ret == -ENOMEM)
+		sg_mode = true;
+
+	return ret;
+}
+
+static void omap1_cam_init_videobuf(struct videobuf_queue *q,
+				     struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct omap1_cam_dev *pcdev = ici->priv;
+
+	if (!sg_mode)
+		videobuf_queue_dma_contig_init(q, &omap1_videobuf_ops,
+				icd->parent, &pcdev->lock,
+				V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+				sizeof(struct omap1_cam_buf), icd, &icd->video_lock);
+	else
+		videobuf_queue_sg_init(q, &omap1_videobuf_ops,
+				icd->parent, &pcdev->lock,
+				V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+				sizeof(struct omap1_cam_buf), icd, &icd->video_lock);
+
+	/* use videobuf mode (auto)selected with the module parameter */
+	pcdev->vb_mode = sg_mode ? OMAP1_CAM_DMA_SG : OMAP1_CAM_DMA_CONTIG;
+
+	/*
+	 * Ensure we substitute the videobuf-dma-contig version of the
+	 * mmap_mapper() callback with our own wrapper, used for switching
+	 * automatically to videobuf-dma-sg on buffer allocation failure.
+	 */
+	if (!sg_mode && q->int_ops->mmap_mapper != omap1_cam_mmap_mapper) {
+		pcdev->mmap_mapper = q->int_ops->mmap_mapper;
+		q->int_ops->mmap_mapper = omap1_cam_mmap_mapper;
+	}
+}
+
+static int omap1_cam_reqbufs(struct soc_camera_device *icd,
+			      struct v4l2_requestbuffers *p)
+{
+	int i;
+
+	/*
+	 * This is for locking debugging only. I removed spinlocks and now I
+	 * check whether .prepare is ever called on a linked buffer, or whether
+	 * a dma IRQ can occur for an in-work or unlinked buffer. Until now
+	 * it hadn't triggered
+	 */
+	for (i = 0; i < p->count; i++) {
+		struct omap1_cam_buf *buf = container_of(icd->vb_vidq.bufs[i],
+						      struct omap1_cam_buf, vb);
+		buf->inwork = 0;
+		INIT_LIST_HEAD(&buf->vb.queue);
+	}
+
+	return 0;
+}
+
+static int omap1_cam_querycap(struct soc_camera_host *ici,
+			       struct v4l2_capability *cap)
+{
+	/* cap->name is set by the friendly caller:-> */
+	strlcpy(cap->card, "OMAP1 Camera", sizeof(cap->card));
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+static int omap1_cam_set_bus_param(struct soc_camera_device *icd)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct device *dev = icd->parent;
+	struct soc_camera_host *ici = to_soc_camera_host(dev);
+	struct omap1_cam_dev *pcdev = ici->priv;
+	u32 pixfmt = icd->current_fmt->host_fmt->fourcc;
+	const struct soc_camera_format_xlate *xlate;
+	const struct soc_mbus_pixelfmt *fmt;
+	struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+	unsigned long common_flags;
+	u32 ctrlclock, mode;
+	int ret;
+
+	ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
+	if (!ret) {
+		common_flags = soc_mbus_config_compatible(&cfg, SOCAM_BUS_FLAGS);
+		if (!common_flags) {
+			dev_warn(dev,
+				 "Flags incompatible: camera 0x%x, host 0x%x\n",
+				 cfg.flags, SOCAM_BUS_FLAGS);
+			return -EINVAL;
+		}
+	} else if (ret != -ENOIOCTLCMD) {
+		return ret;
+	} else {
+		common_flags = SOCAM_BUS_FLAGS;
+	}
+
+	/* Make choices, possibly based on platform configuration */
+	if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
+			(common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
+		if (!pcdev->pdata ||
+				pcdev->pdata->flags & OMAP1_CAMERA_LCLK_RISING)
+			common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
+		else
+			common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
+	}
+
+	cfg.flags = common_flags;
+	ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
+	if (ret < 0 && ret != -ENOIOCTLCMD) {
+		dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n",
+			common_flags, ret);
+		return ret;
+	}
+
+	ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
+	if (ctrlclock & LCLK_EN)
+		CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
+
+	if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) {
+		dev_dbg(dev, "CTRLCLOCK_REG |= POLCLK\n");
+		ctrlclock |= POLCLK;
+	} else {
+		dev_dbg(dev, "CTRLCLOCK_REG &= ~POLCLK\n");
+		ctrlclock &= ~POLCLK;
+	}
+	CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
+
+	if (ctrlclock & LCLK_EN)
+		CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+
+	/* select bus endianess */
+	xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+	fmt = xlate->host_fmt;
+
+	mode = CAM_READ(pcdev, MODE) & ~(RAZ_FIFO | IRQ_MASK | DMA);
+	if (fmt->order == SOC_MBUS_ORDER_LE) {
+		dev_dbg(dev, "MODE_REG &= ~ORDERCAMD\n");
+		CAM_WRITE(pcdev, MODE, mode & ~ORDERCAMD);
+	} else {
+		dev_dbg(dev, "MODE_REG |= ORDERCAMD\n");
+		CAM_WRITE(pcdev, MODE, mode | ORDERCAMD);
+	}
+
+	return 0;
+}
+
+static unsigned int omap1_cam_poll(struct file *file, poll_table *pt)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct omap1_cam_buf *buf;
+
+	buf = list_entry(icd->vb_vidq.stream.next, struct omap1_cam_buf,
+			 vb.stream);
+
+	poll_wait(file, &buf->vb.done, pt);
+
+	if (buf->vb.state == VIDEOBUF_DONE ||
+	    buf->vb.state == VIDEOBUF_ERROR)
+		return POLLIN | POLLRDNORM;
+
+	return 0;
+}
+
+static struct soc_camera_host_ops omap1_host_ops = {
+	.owner		= THIS_MODULE,
+	.add		= omap1_cam_add_device,
+	.remove		= omap1_cam_remove_device,
+	.get_formats	= omap1_cam_get_formats,
+	.set_crop	= omap1_cam_set_crop,
+	.set_fmt	= omap1_cam_set_fmt,
+	.try_fmt	= omap1_cam_try_fmt,
+	.init_videobuf	= omap1_cam_init_videobuf,
+	.reqbufs	= omap1_cam_reqbufs,
+	.querycap	= omap1_cam_querycap,
+	.set_bus_param	= omap1_cam_set_bus_param,
+	.poll		= omap1_cam_poll,
+};
+
+static int __init omap1_cam_probe(struct platform_device *pdev)
+{
+	struct omap1_cam_dev *pcdev;
+	struct resource *res;
+	struct clk *clk;
+	void __iomem *base;
+	unsigned int irq;
+	int err = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(pdev, 0);
+	if (!res || (int)irq <= 0) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	clk = clk_get(&pdev->dev, "armper_ck");
+	if (IS_ERR(clk)) {
+		err = PTR_ERR(clk);
+		goto exit;
+	}
+
+	pcdev = kzalloc(sizeof(*pcdev) + resource_size(res), GFP_KERNEL);
+	if (!pcdev) {
+		dev_err(&pdev->dev, "Could not allocate pcdev\n");
+		err = -ENOMEM;
+		goto exit_put_clk;
+	}
+
+	pcdev->res = res;
+	pcdev->clk = clk;
+
+	pcdev->pdata = pdev->dev.platform_data;
+	if (pcdev->pdata) {
+		pcdev->pflags = pcdev->pdata->flags;
+		pcdev->camexclk = pcdev->pdata->camexclk_khz * 1000;
+	}
+
+	switch (pcdev->camexclk) {
+	case 6000000:
+	case 8000000:
+	case 9600000:
+	case 12000000:
+	case 24000000:
+		break;
+	default:
+		/* pcdev->camexclk != 0 => pcdev->pdata != NULL */
+		dev_warn(&pdev->dev,
+				"Incorrect sensor clock frequency %ld kHz, "
+				"should be one of 0, 6, 8, 9.6, 12 or 24 MHz, "
+				"please correct your platform data\n",
+				pcdev->pdata->camexclk_khz);
+		pcdev->camexclk = 0;
+	case 0:
+		dev_info(&pdev->dev, "Not providing sensor clock\n");
+	}
+
+	INIT_LIST_HEAD(&pcdev->capture);
+	spin_lock_init(&pcdev->lock);
+
+	/*
+	 * Request the region.
+	 */
+	if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) {
+		err = -EBUSY;
+		goto exit_kfree;
+	}
+
+	base = ioremap(res->start, resource_size(res));
+	if (!base) {
+		err = -ENOMEM;
+		goto exit_release;
+	}
+	pcdev->irq = irq;
+	pcdev->base = base;
+
+	sensor_reset(pcdev, true);
+
+	err = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, DRIVER_NAME,
+			dma_isr, (void *)pcdev, &pcdev->dma_ch);
+	if (err < 0) {
+		dev_err(&pdev->dev, "Can't request DMA for OMAP1 Camera\n");
+		err = -EBUSY;
+		goto exit_iounmap;
+	}
+	dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_ch);
+
+	/* preconfigure DMA */
+	omap_set_dma_src_params(pcdev->dma_ch, OMAP_DMA_PORT_TIPB,
+			OMAP_DMA_AMODE_CONSTANT, res->start + REG_CAMDATA,
+			0, 0);
+	omap_set_dma_dest_burst_mode(pcdev->dma_ch, OMAP_DMA_DATA_BURST_4);
+	/* setup DMA autoinitialization */
+	omap_dma_link_lch(pcdev->dma_ch, pcdev->dma_ch);
+
+	err = request_irq(pcdev->irq, cam_isr, 0, DRIVER_NAME, pcdev);
+	if (err) {
+		dev_err(&pdev->dev, "Camera interrupt register failed\n");
+		goto exit_free_dma;
+	}
+
+	pcdev->soc_host.drv_name	= DRIVER_NAME;
+	pcdev->soc_host.ops		= &omap1_host_ops;
+	pcdev->soc_host.priv		= pcdev;
+	pcdev->soc_host.v4l2_dev.dev	= &pdev->dev;
+	pcdev->soc_host.nr		= pdev->id;
+
+	err = soc_camera_host_register(&pcdev->soc_host);
+	if (err)
+		goto exit_free_irq;
+
+	dev_info(&pdev->dev, "OMAP1 Camera Interface driver loaded\n");
+
+	return 0;
+
+exit_free_irq:
+	free_irq(pcdev->irq, pcdev);
+exit_free_dma:
+	omap_free_dma(pcdev->dma_ch);
+exit_iounmap:
+	iounmap(base);
+exit_release:
+	release_mem_region(res->start, resource_size(res));
+exit_kfree:
+	kfree(pcdev);
+exit_put_clk:
+	clk_put(clk);
+exit:
+	return err;
+}
+
+static int __exit omap1_cam_remove(struct platform_device *pdev)
+{
+	struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+	struct omap1_cam_dev *pcdev = container_of(soc_host,
+					struct omap1_cam_dev, soc_host);
+	struct resource *res;
+
+	free_irq(pcdev->irq, pcdev);
+
+	omap_free_dma(pcdev->dma_ch);
+
+	soc_camera_host_unregister(soc_host);
+
+	iounmap(pcdev->base);
+
+	res = pcdev->res;
+	release_mem_region(res->start, resource_size(res));
+
+	clk_put(pcdev->clk);
+
+	kfree(pcdev);
+
+	dev_info(&pdev->dev, "OMAP1 Camera Interface driver unloaded\n");
+
+	return 0;
+}
+
+static struct platform_driver omap1_cam_driver = {
+	.driver		= {
+		.name	= DRIVER_NAME,
+	},
+	.probe		= omap1_cam_probe,
+	.remove		= __exit_p(omap1_cam_remove),
+};
+
+module_platform_driver(omap1_cam_driver);
+
+module_param(sg_mode, bool, 0644);
+MODULE_PARM_DESC(sg_mode, "videobuf mode, 0: dma-contig (default), 1: dma-sg");
+
+MODULE_DESCRIPTION("OMAP1 Camera Interface driver");
+MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/media/platform/omap24xxcam-dma.c b/drivers/media/platform/omap24xxcam-dma.c
new file mode 100644
index 0000000..9c00776
--- /dev/null
+++ b/drivers/media/platform/omap24xxcam-dma.c
@@ -0,0 +1,601 @@
+/*
+ * drivers/media/platform/omap24xxcam-dma.c
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from Andy Lowe <source@mvista.com> and
+ *                    David Cohen <david.cohen@indt.org.br>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/scatterlist.h>
+
+#include "omap24xxcam.h"
+
+/*
+ *
+ * DMA hardware.
+ *
+ */
+
+/* Ack all interrupt on CSR and IRQSTATUS_L0 */
+static void omap24xxcam_dmahw_ack_all(void __iomem *base)
+{
+	u32 csr;
+	int i;
+
+	for (i = 0; i < NUM_CAMDMA_CHANNELS; ++i) {
+		csr = omap24xxcam_reg_in(base, CAMDMA_CSR(i));
+		/* ack interrupt in CSR */
+		omap24xxcam_reg_out(base, CAMDMA_CSR(i), csr);
+	}
+	omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, 0xf);
+}
+
+/* Ack dmach on CSR and IRQSTATUS_L0 */
+static u32 omap24xxcam_dmahw_ack_ch(void __iomem *base, int dmach)
+{
+	u32 csr;
+
+	csr = omap24xxcam_reg_in(base, CAMDMA_CSR(dmach));
+	/* ack interrupt in CSR */
+	omap24xxcam_reg_out(base, CAMDMA_CSR(dmach), csr);
+	/* ack interrupt in IRQSTATUS */
+	omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, (1 << dmach));
+
+	return csr;
+}
+
+static int omap24xxcam_dmahw_running(void __iomem *base, int dmach)
+{
+	return omap24xxcam_reg_in(base, CAMDMA_CCR(dmach)) & CAMDMA_CCR_ENABLE;
+}
+
+static void omap24xxcam_dmahw_transfer_setup(void __iomem *base, int dmach,
+					     dma_addr_t start, u32 len)
+{
+	omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
+			    CAMDMA_CCR_SEL_SRC_DST_SYNC
+			    | CAMDMA_CCR_BS
+			    | CAMDMA_CCR_DST_AMODE_POST_INC
+			    | CAMDMA_CCR_SRC_AMODE_POST_INC
+			    | CAMDMA_CCR_FS
+			    | CAMDMA_CCR_WR_ACTIVE
+			    | CAMDMA_CCR_RD_ACTIVE
+			    | CAMDMA_CCR_SYNCHRO_CAMERA);
+	omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(dmach), 0);
+	omap24xxcam_reg_out(base, CAMDMA_CEN(dmach), len);
+	omap24xxcam_reg_out(base, CAMDMA_CFN(dmach), 1);
+	omap24xxcam_reg_out(base, CAMDMA_CSDP(dmach),
+			    CAMDMA_CSDP_WRITE_MODE_POSTED
+			    | CAMDMA_CSDP_DST_BURST_EN_32
+			    | CAMDMA_CSDP_DST_PACKED
+			    | CAMDMA_CSDP_SRC_BURST_EN_32
+			    | CAMDMA_CSDP_SRC_PACKED
+			    | CAMDMA_CSDP_DATA_TYPE_8BITS);
+	omap24xxcam_reg_out(base, CAMDMA_CSSA(dmach), 0);
+	omap24xxcam_reg_out(base, CAMDMA_CDSA(dmach), start);
+	omap24xxcam_reg_out(base, CAMDMA_CSEI(dmach), 0);
+	omap24xxcam_reg_out(base, CAMDMA_CSFI(dmach), DMA_THRESHOLD);
+	omap24xxcam_reg_out(base, CAMDMA_CDEI(dmach), 0);
+	omap24xxcam_reg_out(base, CAMDMA_CDFI(dmach), 0);
+	omap24xxcam_reg_out(base, CAMDMA_CSR(dmach),
+			    CAMDMA_CSR_MISALIGNED_ERR
+			    | CAMDMA_CSR_SECURE_ERR
+			    | CAMDMA_CSR_TRANS_ERR
+			    | CAMDMA_CSR_BLOCK
+			    | CAMDMA_CSR_DROP);
+	omap24xxcam_reg_out(base, CAMDMA_CICR(dmach),
+			    CAMDMA_CICR_MISALIGNED_ERR_IE
+			    | CAMDMA_CICR_SECURE_ERR_IE
+			    | CAMDMA_CICR_TRANS_ERR_IE
+			    | CAMDMA_CICR_BLOCK_IE
+			    | CAMDMA_CICR_DROP_IE);
+}
+
+static void omap24xxcam_dmahw_transfer_start(void __iomem *base, int dmach)
+{
+	omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
+			    CAMDMA_CCR_SEL_SRC_DST_SYNC
+			    | CAMDMA_CCR_BS
+			    | CAMDMA_CCR_DST_AMODE_POST_INC
+			    | CAMDMA_CCR_SRC_AMODE_POST_INC
+			    | CAMDMA_CCR_ENABLE
+			    | CAMDMA_CCR_FS
+			    | CAMDMA_CCR_SYNCHRO_CAMERA);
+}
+
+static void omap24xxcam_dmahw_transfer_chain(void __iomem *base, int dmach,
+					     int free_dmach)
+{
+	int prev_dmach, ch;
+
+	if (dmach == 0)
+		prev_dmach = NUM_CAMDMA_CHANNELS - 1;
+	else
+		prev_dmach = dmach - 1;
+	omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(prev_dmach),
+			    CAMDMA_CLNK_CTRL_ENABLE_LNK | dmach);
+	/* Did we chain the DMA transfer before the previous one
+	 * finished?
+	 */
+	ch = (dmach + free_dmach) % NUM_CAMDMA_CHANNELS;
+	while (!(omap24xxcam_reg_in(base, CAMDMA_CCR(ch))
+		 & CAMDMA_CCR_ENABLE)) {
+		if (ch == dmach) {
+			/* The previous transfer has ended and this one
+			 * hasn't started, so we must not have chained
+			 * to the previous one in time.  We'll have to
+			 * start it now.
+			 */
+			omap24xxcam_dmahw_transfer_start(base, dmach);
+			break;
+		} else
+			ch = (ch + 1) % NUM_CAMDMA_CHANNELS;
+	}
+}
+
+/* Abort all chained DMA transfers. After all transfers have been
+ * aborted and the DMA controller is idle, the completion routines for
+ * any aborted transfers will be called in sequence. The DMA
+ * controller may not be idle after this routine completes, because
+ * the completion routines might start new transfers.
+ */
+static void omap24xxcam_dmahw_abort_ch(void __iomem *base, int dmach)
+{
+	/* mask all interrupts from this channel */
+	omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), 0);
+	/* unlink this channel */
+	omap24xxcam_reg_merge(base, CAMDMA_CLNK_CTRL(dmach), 0,
+			      CAMDMA_CLNK_CTRL_ENABLE_LNK);
+	/* disable this channel */
+	omap24xxcam_reg_merge(base, CAMDMA_CCR(dmach), 0, CAMDMA_CCR_ENABLE);
+}
+
+static void omap24xxcam_dmahw_init(void __iomem *base)
+{
+	omap24xxcam_reg_out(base, CAMDMA_OCP_SYSCONFIG,
+			    CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY
+			    | CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE
+			    | CAMDMA_OCP_SYSCONFIG_AUTOIDLE);
+
+	omap24xxcam_reg_merge(base, CAMDMA_GCR, 0x10,
+			      CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH);
+
+	omap24xxcam_reg_out(base, CAMDMA_IRQENABLE_L0, 0xf);
+}
+
+/*
+ *
+ * Individual DMA channel handling.
+ *
+ */
+
+/* Start a DMA transfer from the camera to memory.
+ * Returns zero if the transfer was successfully started, or non-zero if all
+ * DMA channels are already in use or starting is currently inhibited.
+ */
+static int omap24xxcam_dma_start(struct omap24xxcam_dma *dma, dma_addr_t start,
+				 u32 len, dma_callback_t callback, void *arg)
+{
+	unsigned long flags;
+	int dmach;
+
+	spin_lock_irqsave(&dma->lock, flags);
+
+	if (!dma->free_dmach || atomic_read(&dma->dma_stop)) {
+		spin_unlock_irqrestore(&dma->lock, flags);
+		return -EBUSY;
+	}
+
+	dmach = dma->next_dmach;
+
+	dma->ch_state[dmach].callback = callback;
+	dma->ch_state[dmach].arg = arg;
+
+	omap24xxcam_dmahw_transfer_setup(dma->base, dmach, start, len);
+
+	/* We're ready to start the DMA transfer. */
+
+	if (dma->free_dmach < NUM_CAMDMA_CHANNELS) {
+		/* A transfer is already in progress, so try to chain to it. */
+		omap24xxcam_dmahw_transfer_chain(dma->base, dmach,
+						 dma->free_dmach);
+	} else {
+		/* No transfer is in progress, so we'll just start this one
+		 * now.
+		 */
+		omap24xxcam_dmahw_transfer_start(dma->base, dmach);
+	}
+
+	dma->next_dmach = (dma->next_dmach + 1) % NUM_CAMDMA_CHANNELS;
+	dma->free_dmach--;
+
+	spin_unlock_irqrestore(&dma->lock, flags);
+
+	return 0;
+}
+
+/* Abort all chained DMA transfers. After all transfers have been
+ * aborted and the DMA controller is idle, the completion routines for
+ * any aborted transfers will be called in sequence. The DMA
+ * controller may not be idle after this routine completes, because
+ * the completion routines might start new transfers.
+ */
+static void omap24xxcam_dma_abort(struct omap24xxcam_dma *dma, u32 csr)
+{
+	unsigned long flags;
+	int dmach, i, free_dmach;
+	dma_callback_t callback;
+	void *arg;
+
+	spin_lock_irqsave(&dma->lock, flags);
+
+	/* stop any DMA transfers in progress */
+	dmach = (dma->next_dmach + dma->free_dmach) % NUM_CAMDMA_CHANNELS;
+	for (i = 0; i < NUM_CAMDMA_CHANNELS; i++) {
+		omap24xxcam_dmahw_abort_ch(dma->base, dmach);
+		dmach = (dmach + 1) % NUM_CAMDMA_CHANNELS;
+	}
+
+	/* We have to be careful here because the callback routine
+	 * might start a new DMA transfer, and we only want to abort
+	 * transfers that were started before this routine was called.
+	 */
+	free_dmach = dma->free_dmach;
+	while ((dma->free_dmach < NUM_CAMDMA_CHANNELS) &&
+	       (free_dmach < NUM_CAMDMA_CHANNELS)) {
+		dmach = (dma->next_dmach + dma->free_dmach)
+			% NUM_CAMDMA_CHANNELS;
+		callback = dma->ch_state[dmach].callback;
+		arg = dma->ch_state[dmach].arg;
+		dma->free_dmach++;
+		free_dmach++;
+		if (callback) {
+			/* leave interrupts disabled during callback */
+			spin_unlock(&dma->lock);
+			(*callback) (dma, csr, arg);
+			spin_lock(&dma->lock);
+		}
+	}
+
+	spin_unlock_irqrestore(&dma->lock, flags);
+}
+
+/* Abort all chained DMA transfers. After all transfers have been
+ * aborted and the DMA controller is idle, the completion routines for
+ * any aborted transfers will be called in sequence. If the completion
+ * routines attempt to start a new DMA transfer it will fail, so the
+ * DMA controller will be idle after this routine completes.
+ */
+static void omap24xxcam_dma_stop(struct omap24xxcam_dma *dma, u32 csr)
+{
+	atomic_inc(&dma->dma_stop);
+	omap24xxcam_dma_abort(dma, csr);
+	atomic_dec(&dma->dma_stop);
+}
+
+/* Camera DMA interrupt service routine. */
+void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma)
+{
+	int dmach;
+	dma_callback_t callback;
+	void *arg;
+	u32 csr;
+	const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+		| CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+		| CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+	spin_lock(&dma->lock);
+
+	if (dma->free_dmach == NUM_CAMDMA_CHANNELS) {
+		/* A camera DMA interrupt occurred while all channels
+		 * are idle, so we'll acknowledge the interrupt in the
+		 * IRQSTATUS register and exit.
+		 */
+		omap24xxcam_dmahw_ack_all(dma->base);
+		spin_unlock(&dma->lock);
+		return;
+	}
+
+	while (dma->free_dmach < NUM_CAMDMA_CHANNELS) {
+		dmach = (dma->next_dmach + dma->free_dmach)
+			% NUM_CAMDMA_CHANNELS;
+		if (omap24xxcam_dmahw_running(dma->base, dmach)) {
+			/* This buffer hasn't finished yet, so we're done. */
+			break;
+		}
+		csr = omap24xxcam_dmahw_ack_ch(dma->base, dmach);
+		if (csr & csr_error) {
+			/* A DMA error occurred, so stop all DMA
+			 * transfers in progress.
+			 */
+			spin_unlock(&dma->lock);
+			omap24xxcam_dma_stop(dma, csr);
+			return;
+		} else {
+			callback = dma->ch_state[dmach].callback;
+			arg = dma->ch_state[dmach].arg;
+			dma->free_dmach++;
+			if (callback) {
+				spin_unlock(&dma->lock);
+				(*callback) (dma, csr, arg);
+				spin_lock(&dma->lock);
+			}
+		}
+	}
+
+	spin_unlock(&dma->lock);
+
+	omap24xxcam_sgdma_process(
+		container_of(dma, struct omap24xxcam_sgdma, dma));
+}
+
+void omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dma->lock, flags);
+
+	omap24xxcam_dmahw_init(dma->base);
+
+	spin_unlock_irqrestore(&dma->lock, flags);
+}
+
+static void omap24xxcam_dma_init(struct omap24xxcam_dma *dma,
+				 void __iomem *base)
+{
+	int ch;
+
+	/* group all channels on DMA IRQ0 and unmask irq */
+	spin_lock_init(&dma->lock);
+	dma->base = base;
+	dma->free_dmach = NUM_CAMDMA_CHANNELS;
+	dma->next_dmach = 0;
+	for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++) {
+		dma->ch_state[ch].callback = NULL;
+		dma->ch_state[ch].arg = NULL;
+	}
+}
+
+/*
+ *
+ * Scatter-gather DMA.
+ *
+ * High-level DMA construct for transferring whole picture frames to
+ * memory that is discontinuous.
+ *
+ */
+
+/* DMA completion routine for the scatter-gather DMA fragments. */
+static void omap24xxcam_sgdma_callback(struct omap24xxcam_dma *dma, u32 csr,
+				       void *arg)
+{
+	struct omap24xxcam_sgdma *sgdma =
+		container_of(dma, struct omap24xxcam_sgdma, dma);
+	int sgslot = (int)arg;
+	struct sgdma_state *sg_state;
+	const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+		| CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+		| CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+	spin_lock(&sgdma->lock);
+
+	/* We got an interrupt, we can remove the timer */
+	del_timer(&sgdma->reset_timer);
+
+	sg_state = sgdma->sg_state + sgslot;
+	if (!sg_state->queued_sglist) {
+		spin_unlock(&sgdma->lock);
+		printk(KERN_ERR "%s: sgdma completed when none queued!\n",
+		       __func__);
+		return;
+	}
+
+	sg_state->csr |= csr;
+	if (!--sg_state->queued_sglist) {
+		/* Queue for this sglist is empty, so check to see if we're
+		 * done.
+		 */
+		if ((sg_state->next_sglist == sg_state->sglen)
+		    || (sg_state->csr & csr_error)) {
+			sgdma_callback_t callback = sg_state->callback;
+			void *arg = sg_state->arg;
+			u32 sg_csr = sg_state->csr;
+			/* All done with this sglist */
+			sgdma->free_sgdma++;
+			if (callback) {
+				spin_unlock(&sgdma->lock);
+				(*callback) (sgdma, sg_csr, arg);
+				return;
+			}
+		}
+	}
+
+	spin_unlock(&sgdma->lock);
+}
+
+/* Start queued scatter-gather DMA transfers. */
+void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma)
+{
+	unsigned long flags;
+	int queued_sgdma, sgslot;
+	struct sgdma_state *sg_state;
+	const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+		| CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+		| CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+	spin_lock_irqsave(&sgdma->lock, flags);
+
+	queued_sgdma = NUM_SG_DMA - sgdma->free_sgdma;
+	sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA;
+	while (queued_sgdma > 0) {
+		sg_state = sgdma->sg_state + sgslot;
+		while ((sg_state->next_sglist < sg_state->sglen) &&
+		       !(sg_state->csr & csr_error)) {
+			const struct scatterlist *sglist;
+			unsigned int len;
+
+			sglist = sg_state->sglist + sg_state->next_sglist;
+			/* try to start the next DMA transfer */
+			if (sg_state->next_sglist + 1 == sg_state->sglen) {
+				/*
+				 *  On the last sg, we handle the case where
+				 *  cam->img.pix.sizeimage % PAGE_ALIGN != 0
+				 */
+				len = sg_state->len - sg_state->bytes_read;
+			} else {
+				len = sg_dma_len(sglist);
+			}
+
+			if (omap24xxcam_dma_start(&sgdma->dma,
+						  sg_dma_address(sglist),
+						  len,
+						  omap24xxcam_sgdma_callback,
+						  (void *)sgslot)) {
+				/* DMA start failed */
+				spin_unlock_irqrestore(&sgdma->lock, flags);
+				return;
+			} else {
+				unsigned long expires;
+				/* DMA start was successful */
+				sg_state->next_sglist++;
+				sg_state->bytes_read += len;
+				sg_state->queued_sglist++;
+
+				/* We start the reset timer */
+				expires = jiffies + HZ;
+				mod_timer(&sgdma->reset_timer, expires);
+			}
+		}
+		queued_sgdma--;
+		sgslot = (sgslot + 1) % NUM_SG_DMA;
+	}
+
+	spin_unlock_irqrestore(&sgdma->lock, flags);
+}
+
+/*
+ * Queue a scatter-gather DMA transfer from the camera to memory.
+ * Returns zero if the transfer was successfully queued, or non-zero
+ * if all of the scatter-gather slots are already in use.
+ */
+int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma,
+			    const struct scatterlist *sglist, int sglen,
+			    int len, sgdma_callback_t callback, void *arg)
+{
+	unsigned long flags;
+	struct sgdma_state *sg_state;
+
+	if ((sglen < 0) || ((sglen > 0) && !sglist))
+		return -EINVAL;
+
+	spin_lock_irqsave(&sgdma->lock, flags);
+
+	if (!sgdma->free_sgdma) {
+		spin_unlock_irqrestore(&sgdma->lock, flags);
+		return -EBUSY;
+	}
+
+	sg_state = sgdma->sg_state + sgdma->next_sgdma;
+
+	sg_state->sglist = sglist;
+	sg_state->sglen = sglen;
+	sg_state->next_sglist = 0;
+	sg_state->bytes_read = 0;
+	sg_state->len = len;
+	sg_state->queued_sglist = 0;
+	sg_state->csr = 0;
+	sg_state->callback = callback;
+	sg_state->arg = arg;
+
+	sgdma->next_sgdma = (sgdma->next_sgdma + 1) % NUM_SG_DMA;
+	sgdma->free_sgdma--;
+
+	spin_unlock_irqrestore(&sgdma->lock, flags);
+
+	omap24xxcam_sgdma_process(sgdma);
+
+	return 0;
+}
+
+/* Sync scatter-gather DMA by aborting any DMA transfers currently in progress.
+ * Any queued scatter-gather DMA transactions that have not yet been started
+ * will remain queued.  The DMA controller will be idle after this routine
+ * completes.  When the scatter-gather queue is restarted, the next
+ * scatter-gather DMA transfer will begin at the start of a new transaction.
+ */
+void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma)
+{
+	unsigned long flags;
+	int sgslot;
+	struct sgdma_state *sg_state;
+	u32 csr = CAMDMA_CSR_TRANS_ERR;
+
+	/* stop any DMA transfers in progress */
+	omap24xxcam_dma_stop(&sgdma->dma, csr);
+
+	spin_lock_irqsave(&sgdma->lock, flags);
+
+	if (sgdma->free_sgdma < NUM_SG_DMA) {
+		sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA;
+		sg_state = sgdma->sg_state + sgslot;
+		if (sg_state->next_sglist != 0) {
+			/* This DMA transfer was in progress, so abort it. */
+			sgdma_callback_t callback = sg_state->callback;
+			void *arg = sg_state->arg;
+			sgdma->free_sgdma++;
+			if (callback) {
+				/* leave interrupts masked */
+				spin_unlock(&sgdma->lock);
+				(*callback) (sgdma, csr, arg);
+				spin_lock(&sgdma->lock);
+			}
+		}
+	}
+
+	spin_unlock_irqrestore(&sgdma->lock, flags);
+}
+
+void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
+			    void __iomem *base,
+			    void (*reset_callback)(unsigned long data),
+			    unsigned long reset_callback_data)
+{
+	int sg;
+
+	spin_lock_init(&sgdma->lock);
+	sgdma->free_sgdma = NUM_SG_DMA;
+	sgdma->next_sgdma = 0;
+	for (sg = 0; sg < NUM_SG_DMA; sg++) {
+		sgdma->sg_state[sg].sglen = 0;
+		sgdma->sg_state[sg].next_sglist = 0;
+		sgdma->sg_state[sg].bytes_read = 0;
+		sgdma->sg_state[sg].queued_sglist = 0;
+		sgdma->sg_state[sg].csr = 0;
+		sgdma->sg_state[sg].callback = NULL;
+		sgdma->sg_state[sg].arg = NULL;
+	}
+
+	omap24xxcam_dma_init(&sgdma->dma, base);
+	setup_timer(&sgdma->reset_timer, reset_callback, reset_callback_data);
+}
diff --git a/drivers/media/platform/omap24xxcam.c b/drivers/media/platform/omap24xxcam.c
new file mode 100644
index 0000000..fde2e66
--- /dev/null
+++ b/drivers/media/platform/omap24xxcam.c
@@ -0,0 +1,1881 @@
+/*
+ * drivers/media/platform/omap24xxcam.c
+ *
+ * OMAP 2 camera block driver.
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ * Copyright (C) 2007-2008 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from Andy Lowe <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+#include <linux/pci.h>		/* needed for videobufs */
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+
+#include "omap24xxcam.h"
+
+#define OMAP24XXCAM_VERSION "0.0.1"
+
+#define RESET_TIMEOUT_NS 10000
+
+static void omap24xxcam_reset(struct omap24xxcam_device *cam);
+static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam);
+static void omap24xxcam_device_unregister(struct v4l2_int_device *s);
+static int omap24xxcam_remove(struct platform_device *pdev);
+
+/* module parameters */
+static int video_nr = -1;	/* video device minor (-1 ==> auto assign) */
+/*
+ * Maximum amount of memory to use for capture buffers.
+ * Default is 4800KB, enough to double-buffer SXGA.
+ */
+static int capture_mem = 1280 * 960 * 2 * 2;
+
+static struct v4l2_int_device omap24xxcam;
+
+/*
+ *
+ * Clocks.
+ *
+ */
+
+static void omap24xxcam_clock_put(struct omap24xxcam_device *cam)
+{
+	if (cam->ick != NULL && !IS_ERR(cam->ick))
+		clk_put(cam->ick);
+	if (cam->fck != NULL && !IS_ERR(cam->fck))
+		clk_put(cam->fck);
+
+	cam->ick = cam->fck = NULL;
+}
+
+static int omap24xxcam_clock_get(struct omap24xxcam_device *cam)
+{
+	int rval = 0;
+
+	cam->fck = clk_get(cam->dev, "fck");
+	if (IS_ERR(cam->fck)) {
+		dev_err(cam->dev, "can't get camera fck");
+		rval = PTR_ERR(cam->fck);
+		omap24xxcam_clock_put(cam);
+		return rval;
+	}
+
+	cam->ick = clk_get(cam->dev, "ick");
+	if (IS_ERR(cam->ick)) {
+		dev_err(cam->dev, "can't get camera ick");
+		rval = PTR_ERR(cam->ick);
+		omap24xxcam_clock_put(cam);
+	}
+
+	return rval;
+}
+
+static void omap24xxcam_clock_on(struct omap24xxcam_device *cam)
+{
+	clk_enable(cam->fck);
+	clk_enable(cam->ick);
+}
+
+static void omap24xxcam_clock_off(struct omap24xxcam_device *cam)
+{
+	clk_disable(cam->fck);
+	clk_disable(cam->ick);
+}
+
+/*
+ *
+ * Camera core
+ *
+ */
+
+/*
+ * Set xclk.
+ *
+ * To disable xclk, use value zero.
+ */
+static void omap24xxcam_core_xclk_set(const struct omap24xxcam_device *cam,
+				      u32 xclk)
+{
+	if (xclk) {
+		u32 divisor = CAM_MCLK / xclk;
+
+		if (divisor == 1)
+			omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+					    CC_CTRL_XCLK,
+					    CC_CTRL_XCLK_DIV_BYPASS);
+		else
+			omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+					    CC_CTRL_XCLK, divisor);
+	} else
+		omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+				    CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_STABLE_LOW);
+}
+
+static void omap24xxcam_core_hwinit(const struct omap24xxcam_device *cam)
+{
+	/*
+	 * Setting the camera core AUTOIDLE bit causes problems with frame
+	 * synchronization, so we will clear the AUTOIDLE bit instead.
+	 */
+	omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_SYSCONFIG,
+			    CC_SYSCONFIG_AUTOIDLE);
+
+	/* program the camera interface DMA packet size */
+	omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL_DMA,
+			    CC_CTRL_DMA_EN | (DMA_THRESHOLD / 4 - 1));
+
+	/* enable camera core error interrupts */
+	omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQENABLE,
+			    CC_IRQENABLE_FW_ERR_IRQ
+			    | CC_IRQENABLE_FSC_ERR_IRQ
+			    | CC_IRQENABLE_SSC_ERR_IRQ
+			    | CC_IRQENABLE_FIFO_OF_IRQ);
+}
+
+/*
+ * Enable the camera core.
+ *
+ * Data transfer to the camera DMA starts from next starting frame.
+ */
+static void omap24xxcam_core_enable(const struct omap24xxcam_device *cam)
+{
+
+	omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL,
+			    cam->cc_ctrl);
+}
+
+/*
+ * Disable camera core.
+ *
+ * The data transfer will be stopped immediately (CC_CTRL_CC_RST). The
+ * core internal state machines will be reset. Use
+ * CC_CTRL_CC_FRAME_TRIG instead if you want to transfer the current
+ * frame completely.
+ */
+static void omap24xxcam_core_disable(const struct omap24xxcam_device *cam)
+{
+	omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL,
+			    CC_CTRL_CC_RST);
+}
+
+/* Interrupt service routine for camera core interrupts. */
+static void omap24xxcam_core_isr(struct omap24xxcam_device *cam)
+{
+	u32 cc_irqstatus;
+	const u32 cc_irqstatus_err =
+		CC_IRQSTATUS_FW_ERR_IRQ
+		| CC_IRQSTATUS_FSC_ERR_IRQ
+		| CC_IRQSTATUS_SSC_ERR_IRQ
+		| CC_IRQSTATUS_FIFO_UF_IRQ
+		| CC_IRQSTATUS_FIFO_OF_IRQ;
+
+	cc_irqstatus = omap24xxcam_reg_in(cam->mmio_base + CC_REG_OFFSET,
+					  CC_IRQSTATUS);
+	omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQSTATUS,
+			    cc_irqstatus);
+
+	if (cc_irqstatus & cc_irqstatus_err
+	    && !atomic_read(&cam->in_reset)) {
+		dev_dbg(cam->dev, "resetting camera, cc_irqstatus 0x%x\n",
+			cc_irqstatus);
+		omap24xxcam_reset(cam);
+	}
+}
+
+/*
+ *
+ * videobuf_buffer handling.
+ *
+ * Memory for mmapped videobuf_buffers is not allocated
+ * conventionally, but by several kmalloc allocations and then
+ * creating the scatterlist on our own. User-space buffers are handled
+ * normally.
+ *
+ */
+
+/*
+ * Free the memory-mapped buffer memory allocated for a
+ * videobuf_buffer and the associated scatterlist.
+ */
+static void omap24xxcam_vbq_free_mmap_buffer(struct videobuf_buffer *vb)
+{
+	struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+	size_t alloc_size;
+	struct page *page;
+	int i;
+
+	if (dma->sglist == NULL)
+		return;
+
+	i = dma->sglen;
+	while (i) {
+		i--;
+		alloc_size = sg_dma_len(&dma->sglist[i]);
+		page = sg_page(&dma->sglist[i]);
+		do {
+			ClearPageReserved(page++);
+		} while (alloc_size -= PAGE_SIZE);
+		__free_pages(sg_page(&dma->sglist[i]),
+			     get_order(sg_dma_len(&dma->sglist[i])));
+	}
+
+	kfree(dma->sglist);
+	dma->sglist = NULL;
+}
+
+/* Release all memory related to the videobuf_queue. */
+static void omap24xxcam_vbq_free_mmap_buffers(struct videobuf_queue *vbq)
+{
+	int i;
+
+	mutex_lock(&vbq->vb_lock);
+
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (NULL == vbq->bufs[i])
+			continue;
+		if (V4L2_MEMORY_MMAP != vbq->bufs[i]->memory)
+			continue;
+		vbq->ops->buf_release(vbq, vbq->bufs[i]);
+		omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]);
+		kfree(vbq->bufs[i]);
+		vbq->bufs[i] = NULL;
+	}
+
+	mutex_unlock(&vbq->vb_lock);
+
+	videobuf_mmap_free(vbq);
+}
+
+/*
+ * Allocate physically as contiguous as possible buffer for video
+ * frame and allocate and build DMA scatter-gather list for it.
+ */
+static int omap24xxcam_vbq_alloc_mmap_buffer(struct videobuf_buffer *vb)
+{
+	unsigned int order;
+	size_t alloc_size, size = vb->bsize; /* vb->bsize is page aligned */
+	struct page *page;
+	int max_pages, err = 0, i = 0;
+	struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+	/*
+	 * allocate maximum size scatter-gather list. Note this is
+	 * overhead. We may not use as many entries as we allocate
+	 */
+	max_pages = vb->bsize >> PAGE_SHIFT;
+	dma->sglist = kcalloc(max_pages, sizeof(*dma->sglist), GFP_KERNEL);
+	if (dma->sglist == NULL) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	while (size) {
+		order = get_order(size);
+		/*
+		 * do not over-allocate even if we would get larger
+		 * contiguous chunk that way
+		 */
+		if ((PAGE_SIZE << order) > size)
+			order--;
+
+		/* try to allocate as many contiguous pages as possible */
+		page = alloc_pages(GFP_KERNEL, order);
+		/* if allocation fails, try to allocate smaller amount */
+		while (page == NULL) {
+			order--;
+			page = alloc_pages(GFP_KERNEL, order);
+			if (page == NULL && !order) {
+				err = -ENOMEM;
+				goto out;
+			}
+		}
+		size -= (PAGE_SIZE << order);
+
+		/* append allocated chunk of pages into scatter-gather list */
+		sg_set_page(&dma->sglist[i], page, PAGE_SIZE << order, 0);
+		dma->sglen++;
+		i++;
+
+		alloc_size = (PAGE_SIZE << order);
+
+		/* clear pages before giving them to user space */
+		memset(page_address(page), 0, alloc_size);
+
+		/* mark allocated pages reserved */
+		do {
+			SetPageReserved(page++);
+		} while (alloc_size -= PAGE_SIZE);
+	}
+	/*
+	 * REVISIT: not fully correct to assign nr_pages == sglen but
+	 * video-buf is passing nr_pages for e.g. unmap_sg calls
+	 */
+	dma->nr_pages = dma->sglen;
+	dma->direction = PCI_DMA_FROMDEVICE;
+
+	return 0;
+
+out:
+	omap24xxcam_vbq_free_mmap_buffer(vb);
+	return err;
+}
+
+static int omap24xxcam_vbq_alloc_mmap_buffers(struct videobuf_queue *vbq,
+					      unsigned int count)
+{
+	int i, err = 0;
+	struct omap24xxcam_fh *fh =
+		container_of(vbq, struct omap24xxcam_fh, vbq);
+
+	mutex_lock(&vbq->vb_lock);
+
+	for (i = 0; i < count; i++) {
+		err = omap24xxcam_vbq_alloc_mmap_buffer(vbq->bufs[i]);
+		if (err)
+			goto out;
+		dev_dbg(fh->cam->dev, "sglen is %d for buffer %d\n",
+			videobuf_to_dma(vbq->bufs[i])->sglen, i);
+	}
+
+	mutex_unlock(&vbq->vb_lock);
+
+	return 0;
+out:
+	while (i) {
+		i--;
+		omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]);
+	}
+
+	mutex_unlock(&vbq->vb_lock);
+
+	return err;
+}
+
+/*
+ * This routine is called from interrupt context when a scatter-gather DMA
+ * transfer of a videobuf_buffer completes.
+ */
+static void omap24xxcam_vbq_complete(struct omap24xxcam_sgdma *sgdma,
+				     u32 csr, void *arg)
+{
+	struct omap24xxcam_device *cam =
+		container_of(sgdma, struct omap24xxcam_device, sgdma);
+	struct omap24xxcam_fh *fh = cam->streaming->private_data;
+	struct videobuf_buffer *vb = (struct videobuf_buffer *)arg;
+	const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+		| CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+		| CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+	if (--cam->sgdma_in_queue == 0)
+		omap24xxcam_core_disable(cam);
+	spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+
+	do_gettimeofday(&vb->ts);
+	vb->field_count = atomic_add_return(2, &fh->field_count);
+	if (csr & csr_error) {
+		vb->state = VIDEOBUF_ERROR;
+		if (!atomic_read(&fh->cam->in_reset)) {
+			dev_dbg(cam->dev, "resetting camera, csr 0x%x\n", csr);
+			omap24xxcam_reset(cam);
+		}
+	} else
+		vb->state = VIDEOBUF_DONE;
+	wake_up(&vb->done);
+}
+
+static void omap24xxcam_vbq_release(struct videobuf_queue *vbq,
+				    struct videobuf_buffer *vb)
+{
+	struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+	/* wait for buffer, especially to get out of the sgdma queue */
+	videobuf_waiton(vbq, vb, 0, 0);
+	if (vb->memory == V4L2_MEMORY_MMAP) {
+		dma_unmap_sg(vbq->dev, dma->sglist, dma->sglen,
+			     dma->direction);
+		dma->direction = DMA_NONE;
+	} else {
+		videobuf_dma_unmap(vbq->dev, videobuf_to_dma(vb));
+		videobuf_dma_free(videobuf_to_dma(vb));
+	}
+
+	vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+/*
+ * Limit the number of available kernel image capture buffers based on the
+ * number requested, the currently selected image size, and the maximum
+ * amount of memory permitted for kernel capture buffers.
+ */
+static int omap24xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
+				 unsigned int *size)
+{
+	struct omap24xxcam_fh *fh = vbq->priv_data;
+
+	if (*cnt <= 0)
+		*cnt = VIDEO_MAX_FRAME;	/* supply a default number of buffers */
+
+	if (*cnt > VIDEO_MAX_FRAME)
+		*cnt = VIDEO_MAX_FRAME;
+
+	*size = fh->pix.sizeimage;
+
+	/* accessing fh->cam->capture_mem is ok, it's constant */
+	if (*size * *cnt > fh->cam->capture_mem)
+		*cnt = fh->cam->capture_mem / *size;
+
+	return 0;
+}
+
+static int omap24xxcam_dma_iolock(struct videobuf_queue *vbq,
+				  struct videobuf_dmabuf *dma)
+{
+	int err = 0;
+
+	dma->direction = PCI_DMA_FROMDEVICE;
+	if (!dma_map_sg(vbq->dev, dma->sglist, dma->sglen, dma->direction)) {
+		kfree(dma->sglist);
+		dma->sglist = NULL;
+		dma->sglen = 0;
+		err = -EIO;
+	}
+
+	return err;
+}
+
+static int omap24xxcam_vbq_prepare(struct videobuf_queue *vbq,
+				   struct videobuf_buffer *vb,
+				   enum v4l2_field field)
+{
+	struct omap24xxcam_fh *fh = vbq->priv_data;
+	int err = 0;
+
+	/*
+	 * Accessing pix here is okay since it's constant while
+	 * streaming is on (and we only get called then).
+	 */
+	if (vb->baddr) {
+		/* This is a userspace buffer. */
+		if (fh->pix.sizeimage > vb->bsize) {
+			/* The buffer isn't big enough. */
+			err = -EINVAL;
+		} else
+			vb->size = fh->pix.sizeimage;
+	} else {
+		if (vb->state != VIDEOBUF_NEEDS_INIT) {
+			/*
+			 * We have a kernel bounce buffer that has
+			 * already been allocated.
+			 */
+			if (fh->pix.sizeimage > vb->size) {
+				/*
+				 * The image size has been changed to
+				 * a larger size since this buffer was
+				 * allocated, so we need to free and
+				 * reallocate it.
+				 */
+				omap24xxcam_vbq_release(vbq, vb);
+				vb->size = fh->pix.sizeimage;
+			}
+		} else {
+			/* We need to allocate a new kernel bounce buffer. */
+			vb->size = fh->pix.sizeimage;
+		}
+	}
+
+	if (err)
+		return err;
+
+	vb->width = fh->pix.width;
+	vb->height = fh->pix.height;
+	vb->field = field;
+
+	if (vb->state == VIDEOBUF_NEEDS_INIT) {
+		if (vb->memory == V4L2_MEMORY_MMAP)
+			/*
+			 * we have built the scatter-gather list by ourself so
+			 * do the scatter-gather mapping as well
+			 */
+			err = omap24xxcam_dma_iolock(vbq, videobuf_to_dma(vb));
+		else
+			err = videobuf_iolock(vbq, vb, NULL);
+	}
+
+	if (!err)
+		vb->state = VIDEOBUF_PREPARED;
+	else
+		omap24xxcam_vbq_release(vbq, vb);
+
+	return err;
+}
+
+static void omap24xxcam_vbq_queue(struct videobuf_queue *vbq,
+				  struct videobuf_buffer *vb)
+{
+	struct omap24xxcam_fh *fh = vbq->priv_data;
+	struct omap24xxcam_device *cam = fh->cam;
+	enum videobuf_state state = vb->state;
+	unsigned long flags;
+	int err;
+
+	/*
+	 * FIXME: We're marking the buffer active since we have no
+	 * pretty way of marking it active exactly when the
+	 * scatter-gather transfer starts.
+	 */
+	vb->state = VIDEOBUF_ACTIVE;
+
+	err = omap24xxcam_sgdma_queue(&fh->cam->sgdma,
+				      videobuf_to_dma(vb)->sglist,
+				      videobuf_to_dma(vb)->sglen, vb->size,
+				      omap24xxcam_vbq_complete, vb);
+
+	if (!err) {
+		spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+		if (++cam->sgdma_in_queue == 1
+		    && !atomic_read(&cam->in_reset))
+			omap24xxcam_core_enable(cam);
+		spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+	} else {
+		/*
+		 * Oops. We're not supposed to get any errors here.
+		 * The only way we could get an error is if we ran out
+		 * of scatter-gather DMA slots, but we are supposed to
+		 * have at least as many scatter-gather DMA slots as
+		 * video buffers so that can't happen.
+		 */
+		dev_err(cam->dev, "failed to queue a video buffer for dma!\n");
+		dev_err(cam->dev, "likely a bug in the driver!\n");
+		vb->state = state;
+	}
+}
+
+static struct videobuf_queue_ops omap24xxcam_vbq_ops = {
+	.buf_setup   = omap24xxcam_vbq_setup,
+	.buf_prepare = omap24xxcam_vbq_prepare,
+	.buf_queue   = omap24xxcam_vbq_queue,
+	.buf_release = omap24xxcam_vbq_release,
+};
+
+/*
+ *
+ * OMAP main camera system
+ *
+ */
+
+/*
+ * Reset camera block to power-on state.
+ */
+static void omap24xxcam_poweron_reset(struct omap24xxcam_device *cam)
+{
+	int max_loop = RESET_TIMEOUT_NS;
+
+	/* Reset whole camera subsystem */
+	omap24xxcam_reg_out(cam->mmio_base,
+			    CAM_SYSCONFIG,
+			    CAM_SYSCONFIG_SOFTRESET);
+
+	/* Wait till it's finished */
+	while (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS)
+		 & CAM_SYSSTATUS_RESETDONE)
+	       && --max_loop) {
+		ndelay(1);
+	}
+
+	if (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS)
+	      & CAM_SYSSTATUS_RESETDONE))
+		dev_err(cam->dev, "camera soft reset timeout\n");
+}
+
+/*
+ * (Re)initialise the camera block.
+ */
+static void omap24xxcam_hwinit(struct omap24xxcam_device *cam)
+{
+	omap24xxcam_poweron_reset(cam);
+
+	/* set the camera subsystem autoidle bit */
+	omap24xxcam_reg_out(cam->mmio_base, CAM_SYSCONFIG,
+			    CAM_SYSCONFIG_AUTOIDLE);
+
+	/* set the camera MMU autoidle bit */
+	omap24xxcam_reg_out(cam->mmio_base,
+			    CAMMMU_REG_OFFSET + CAMMMU_SYSCONFIG,
+			    CAMMMU_SYSCONFIG_AUTOIDLE);
+
+	omap24xxcam_core_hwinit(cam);
+
+	omap24xxcam_dma_hwinit(&cam->sgdma.dma);
+}
+
+/*
+ * Callback for dma transfer stalling.
+ */
+static void omap24xxcam_stalled_dma_reset(unsigned long data)
+{
+	struct omap24xxcam_device *cam = (struct omap24xxcam_device *)data;
+
+	if (!atomic_read(&cam->in_reset)) {
+		dev_dbg(cam->dev, "dma stalled, resetting camera\n");
+		omap24xxcam_reset(cam);
+	}
+}
+
+/*
+ * Stop capture. Mark we're doing a reset, stop DMA transfers and
+ * core. (No new scatter-gather transfers will be queued whilst
+ * in_reset is non-zero.)
+ *
+ * If omap24xxcam_capture_stop is called from several places at
+ * once, only the first call will have an effect. Similarly, the last
+ * call omap24xxcam_streaming_cont will have effect.
+ *
+ * Serialisation is ensured by using cam->core_enable_disable_lock.
+ */
+static void omap24xxcam_capture_stop(struct omap24xxcam_device *cam)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+
+	if (atomic_inc_return(&cam->in_reset) != 1) {
+		spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+		return;
+	}
+
+	omap24xxcam_core_disable(cam);
+
+	spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+
+	omap24xxcam_sgdma_sync(&cam->sgdma);
+}
+
+/*
+ * Reset and continue streaming.
+ *
+ * Note: Resetting the camera FIFO via the CC_RST bit in the CC_CTRL
+ * register is supposed to be sufficient to recover from a camera
+ * interface error, but it doesn't seem to be enough. If we only do
+ * that then subsequent image captures are out of sync by either one
+ * or two times DMA_THRESHOLD bytes. Resetting and re-initializing the
+ * entire camera subsystem prevents the problem with frame
+ * synchronization.
+ */
+static void omap24xxcam_capture_cont(struct omap24xxcam_device *cam)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+
+	if (atomic_read(&cam->in_reset) != 1)
+		goto out;
+
+	omap24xxcam_hwinit(cam);
+
+	omap24xxcam_sensor_if_enable(cam);
+
+	omap24xxcam_sgdma_process(&cam->sgdma);
+
+	if (cam->sgdma_in_queue)
+		omap24xxcam_core_enable(cam);
+
+out:
+	atomic_dec(&cam->in_reset);
+	spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+}
+
+static ssize_t
+omap24xxcam_streaming_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct omap24xxcam_device *cam = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", cam->streaming ?  "active" : "inactive");
+}
+static DEVICE_ATTR(streaming, S_IRUGO, omap24xxcam_streaming_show, NULL);
+
+/*
+ * Stop capture and restart it. I.e. reset the camera during use.
+ */
+static void omap24xxcam_reset(struct omap24xxcam_device *cam)
+{
+	omap24xxcam_capture_stop(cam);
+	omap24xxcam_capture_cont(cam);
+}
+
+/*
+ * The main interrupt handler.
+ */
+static irqreturn_t omap24xxcam_isr(int irq, void *arg)
+{
+	struct omap24xxcam_device *cam = (struct omap24xxcam_device *)arg;
+	u32 irqstatus;
+	unsigned int irqhandled = 0;
+
+	irqstatus = omap24xxcam_reg_in(cam->mmio_base, CAM_IRQSTATUS);
+
+	if (irqstatus &
+	    (CAM_IRQSTATUS_DMA_IRQ2 | CAM_IRQSTATUS_DMA_IRQ1
+	     | CAM_IRQSTATUS_DMA_IRQ0)) {
+		omap24xxcam_dma_isr(&cam->sgdma.dma);
+		irqhandled = 1;
+	}
+	if (irqstatus & CAM_IRQSTATUS_CC_IRQ) {
+		omap24xxcam_core_isr(cam);
+		irqhandled = 1;
+	}
+	if (irqstatus & CAM_IRQSTATUS_MMU_IRQ)
+		dev_err(cam->dev, "unhandled camera MMU interrupt!\n");
+
+	return IRQ_RETVAL(irqhandled);
+}
+
+/*
+ *
+ * Sensor handling.
+ *
+ */
+
+/*
+ * Enable the external sensor interface. Try to negotiate interface
+ * parameters with the sensor and start using the new ones. The calls
+ * to sensor_if_enable and sensor_if_disable need not to be balanced.
+ */
+static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam)
+{
+	int rval;
+	struct v4l2_ifparm p;
+
+	rval = vidioc_int_g_ifparm(cam->sdev, &p);
+	if (rval) {
+		dev_err(cam->dev, "vidioc_int_g_ifparm failed with %d\n", rval);
+		return rval;
+	}
+
+	cam->if_type = p.if_type;
+
+	cam->cc_ctrl = CC_CTRL_CC_EN;
+
+	switch (p.if_type) {
+	case V4L2_IF_TYPE_BT656:
+		if (p.u.bt656.frame_start_on_rising_vs)
+			cam->cc_ctrl |= CC_CTRL_NOBT_SYNCHRO;
+		if (p.u.bt656.bt_sync_correct)
+			cam->cc_ctrl |= CC_CTRL_BT_CORRECT;
+		if (p.u.bt656.swap)
+			cam->cc_ctrl |= CC_CTRL_PAR_ORDERCAM;
+		if (p.u.bt656.latch_clk_inv)
+			cam->cc_ctrl |= CC_CTRL_PAR_CLK_POL;
+		if (p.u.bt656.nobt_hs_inv)
+			cam->cc_ctrl |= CC_CTRL_NOBT_HS_POL;
+		if (p.u.bt656.nobt_vs_inv)
+			cam->cc_ctrl |= CC_CTRL_NOBT_VS_POL;
+
+		switch (p.u.bt656.mode) {
+		case V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT:
+			cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT8;
+			break;
+		case V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT:
+			cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT10;
+			break;
+		case V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT:
+			cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT12;
+			break;
+		case V4L2_IF_TYPE_BT656_MODE_BT_8BIT:
+			cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT8;
+			break;
+		case V4L2_IF_TYPE_BT656_MODE_BT_10BIT:
+			cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT10;
+			break;
+		default:
+			dev_err(cam->dev,
+				"bt656 interface mode %d not supported\n",
+				p.u.bt656.mode);
+			return -EINVAL;
+		}
+		/*
+		 * The clock rate that the sensor wants has changed.
+		 * We have to adjust the xclk from OMAP 2 side to
+		 * match the sensor's wish as closely as possible.
+		 */
+		if (p.u.bt656.clock_curr != cam->if_u.bt656.xclk) {
+			u32 xclk = p.u.bt656.clock_curr;
+			u32 divisor;
+
+			if (xclk == 0)
+				return -EINVAL;
+
+			if (xclk > CAM_MCLK)
+				xclk = CAM_MCLK;
+
+			divisor = CAM_MCLK / xclk;
+			if (divisor * xclk < CAM_MCLK)
+				divisor++;
+			if (CAM_MCLK / divisor < p.u.bt656.clock_min
+			    && divisor > 1)
+				divisor--;
+			if (divisor > 30)
+				divisor = 30;
+
+			xclk = CAM_MCLK / divisor;
+
+			if (xclk < p.u.bt656.clock_min
+			    || xclk > p.u.bt656.clock_max)
+				return -EINVAL;
+
+			cam->if_u.bt656.xclk = xclk;
+		}
+		omap24xxcam_core_xclk_set(cam, cam->if_u.bt656.xclk);
+		break;
+	default:
+		/* FIXME: how about other interfaces? */
+		dev_err(cam->dev, "interface type %d not supported\n",
+			p.if_type);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void omap24xxcam_sensor_if_disable(const struct omap24xxcam_device *cam)
+{
+	switch (cam->if_type) {
+	case V4L2_IF_TYPE_BT656:
+		omap24xxcam_core_xclk_set(cam, 0);
+		break;
+	}
+}
+
+/*
+ * Initialise the sensor hardware.
+ */
+static int omap24xxcam_sensor_init(struct omap24xxcam_device *cam)
+{
+	int err = 0;
+	struct v4l2_int_device *sdev = cam->sdev;
+
+	omap24xxcam_clock_on(cam);
+	err = omap24xxcam_sensor_if_enable(cam);
+	if (err) {
+		dev_err(cam->dev, "sensor interface could not be enabled at "
+			"initialisation, %d\n", err);
+		cam->sdev = NULL;
+		goto out;
+	}
+
+	/* power up sensor during sensor initialization */
+	vidioc_int_s_power(sdev, 1);
+
+	err = vidioc_int_dev_init(sdev);
+	if (err) {
+		dev_err(cam->dev, "cannot initialize sensor, error %d\n", err);
+		/* Sensor init failed --- it's nonexistent to us! */
+		cam->sdev = NULL;
+		goto out;
+	}
+
+	dev_info(cam->dev, "sensor is %s\n", sdev->name);
+
+out:
+	omap24xxcam_sensor_if_disable(cam);
+	omap24xxcam_clock_off(cam);
+
+	vidioc_int_s_power(sdev, 0);
+
+	return err;
+}
+
+static void omap24xxcam_sensor_exit(struct omap24xxcam_device *cam)
+{
+	if (cam->sdev)
+		vidioc_int_dev_exit(cam->sdev);
+}
+
+static void omap24xxcam_sensor_disable(struct omap24xxcam_device *cam)
+{
+	omap24xxcam_sensor_if_disable(cam);
+	omap24xxcam_clock_off(cam);
+	vidioc_int_s_power(cam->sdev, 0);
+}
+
+/*
+ * Power-up and configure camera sensor. It's ready for capturing now.
+ */
+static int omap24xxcam_sensor_enable(struct omap24xxcam_device *cam)
+{
+	int rval;
+
+	omap24xxcam_clock_on(cam);
+
+	omap24xxcam_sensor_if_enable(cam);
+
+	rval = vidioc_int_s_power(cam->sdev, 1);
+	if (rval)
+		goto out;
+
+	rval = vidioc_int_init(cam->sdev);
+	if (rval)
+		goto out;
+
+	return 0;
+
+out:
+	omap24xxcam_sensor_disable(cam);
+
+	return rval;
+}
+
+static void omap24xxcam_sensor_reset_work(struct work_struct *work)
+{
+	struct omap24xxcam_device *cam =
+		container_of(work, struct omap24xxcam_device,
+			     sensor_reset_work);
+
+	if (atomic_read(&cam->reset_disable))
+		return;
+
+	omap24xxcam_capture_stop(cam);
+
+	if (vidioc_int_reset(cam->sdev) == 0) {
+		vidioc_int_init(cam->sdev);
+	} else {
+		/* Can't reset it by vidioc_int_reset. */
+		omap24xxcam_sensor_disable(cam);
+		omap24xxcam_sensor_enable(cam);
+	}
+
+	omap24xxcam_capture_cont(cam);
+}
+
+/*
+ *
+ * IOCTL interface.
+ *
+ */
+
+static int vidioc_querycap(struct file *file, void *fh,
+			   struct v4l2_capability *cap)
+{
+	struct omap24xxcam_fh *ofh = fh;
+	struct omap24xxcam_device *cam = ofh->cam;
+
+	strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, cam->vfd->name, sizeof(cap->card));
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
+				   struct v4l2_fmtdesc *f)
+{
+	struct omap24xxcam_fh *ofh = fh;
+	struct omap24xxcam_device *cam = ofh->cam;
+	int rval;
+
+	rval = vidioc_int_enum_fmt_cap(cam->sdev, f);
+
+	return rval;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
+				struct v4l2_format *f)
+{
+	struct omap24xxcam_fh *ofh = fh;
+	struct omap24xxcam_device *cam = ofh->cam;
+	int rval;
+
+	mutex_lock(&cam->mutex);
+	rval = vidioc_int_g_fmt_cap(cam->sdev, f);
+	mutex_unlock(&cam->mutex);
+
+	return rval;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
+				struct v4l2_format *f)
+{
+	struct omap24xxcam_fh *ofh = fh;
+	struct omap24xxcam_device *cam = ofh->cam;
+	int rval;
+
+	mutex_lock(&cam->mutex);
+	if (cam->streaming) {
+		rval = -EBUSY;
+		goto out;
+	}
+
+	rval = vidioc_int_s_fmt_cap(cam->sdev, f);
+
+out:
+	mutex_unlock(&cam->mutex);
+
+	if (!rval) {
+		mutex_lock(&ofh->vbq.vb_lock);
+		ofh->pix = f->fmt.pix;
+		mutex_unlock(&ofh->vbq.vb_lock);
+	}
+
+	memset(f, 0, sizeof(*f));
+	vidioc_g_fmt_vid_cap(file, fh, f);
+
+	return rval;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
+				  struct v4l2_format *f)
+{
+	struct omap24xxcam_fh *ofh = fh;
+	struct omap24xxcam_device *cam = ofh->cam;
+	int rval;
+
+	mutex_lock(&cam->mutex);
+	rval = vidioc_int_try_fmt_cap(cam->sdev, f);
+	mutex_unlock(&cam->mutex);
+
+	return rval;
+}
+
+static int vidioc_reqbufs(struct file *file, void *fh,
+			  struct v4l2_requestbuffers *b)
+{
+	struct omap24xxcam_fh *ofh = fh;
+	struct omap24xxcam_device *cam = ofh->cam;
+	int rval;
+
+	mutex_lock(&cam->mutex);
+	if (cam->streaming) {
+		mutex_unlock(&cam->mutex);
+		return -EBUSY;
+	}
+
+	omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq);
+	mutex_unlock(&cam->mutex);
+
+	rval = videobuf_reqbufs(&ofh->vbq, b);
+
+	/*
+	 * Either videobuf_reqbufs failed or the buffers are not
+	 * memory-mapped (which would need special attention).
+	 */
+	if (rval < 0 || b->memory != V4L2_MEMORY_MMAP)
+		goto out;
+
+	rval = omap24xxcam_vbq_alloc_mmap_buffers(&ofh->vbq, rval);
+	if (rval)
+		omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq);
+
+out:
+	return rval;
+}
+
+static int vidioc_querybuf(struct file *file, void *fh,
+			   struct v4l2_buffer *b)
+{
+	struct omap24xxcam_fh *ofh = fh;
+
+	return videobuf_querybuf(&ofh->vbq, b);
+}
+
+static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+	struct omap24xxcam_fh *ofh = fh;
+
+	return videobuf_qbuf(&ofh->vbq, b);
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+	struct omap24xxcam_fh *ofh = fh;
+	struct omap24xxcam_device *cam = ofh->cam;
+	struct videobuf_buffer *vb;
+	int rval;
+
+videobuf_dqbuf_again:
+	rval = videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
+	if (rval)
+		goto out;
+
+	vb = ofh->vbq.bufs[b->index];
+
+	mutex_lock(&cam->mutex);
+	/* _needs_reset returns -EIO if reset is required. */
+	rval = vidioc_int_g_needs_reset(cam->sdev, (void *)vb->baddr);
+	mutex_unlock(&cam->mutex);
+	if (rval == -EIO)
+		schedule_work(&cam->sensor_reset_work);
+	else
+		rval = 0;
+
+out:
+	/*
+	 * This is a hack. We don't want to show -EIO to the user
+	 * space. Requeue the buffer and try again if we're not doing
+	 * this in non-blocking mode.
+	 */
+	if (rval == -EIO) {
+		videobuf_qbuf(&ofh->vbq, b);
+		if (!(file->f_flags & O_NONBLOCK))
+			goto videobuf_dqbuf_again;
+		/*
+		 * We don't have a videobuf_buffer now --- maybe next
+		 * time...
+		 */
+		rval = -EAGAIN;
+	}
+
+	return rval;
+}
+
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+	struct omap24xxcam_fh *ofh = fh;
+	struct omap24xxcam_device *cam = ofh->cam;
+	int rval;
+
+	mutex_lock(&cam->mutex);
+	if (cam->streaming) {
+		rval = -EBUSY;
+		goto out;
+	}
+
+	rval = omap24xxcam_sensor_if_enable(cam);
+	if (rval) {
+		dev_dbg(cam->dev, "vidioc_int_g_ifparm failed\n");
+		goto out;
+	}
+
+	rval = videobuf_streamon(&ofh->vbq);
+	if (!rval) {
+		cam->streaming = file;
+		sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+	}
+
+out:
+	mutex_unlock(&cam->mutex);
+
+	return rval;
+}
+
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+	struct omap24xxcam_fh *ofh = fh;
+	struct omap24xxcam_device *cam = ofh->cam;
+	struct videobuf_queue *q = &ofh->vbq;
+	int rval;
+
+	atomic_inc(&cam->reset_disable);
+
+	flush_work_sync(&cam->sensor_reset_work);
+
+	rval = videobuf_streamoff(q);
+	if (!rval) {
+		mutex_lock(&cam->mutex);
+		cam->streaming = NULL;
+		mutex_unlock(&cam->mutex);
+		sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+	}
+
+	atomic_dec(&cam->reset_disable);
+
+	return rval;
+}
+
+static int vidioc_enum_input(struct file *file, void *fh,
+			     struct v4l2_input *inp)
+{
+	if (inp->index > 0)
+		return -EINVAL;
+
+	strlcpy(inp->name, "camera", sizeof(inp->name));
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+	*i = 0;
+
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+	if (i > 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh,
+			    struct v4l2_queryctrl *a)
+{
+	struct omap24xxcam_fh *ofh = fh;
+	struct omap24xxcam_device *cam = ofh->cam;
+	int rval;
+
+	rval = vidioc_int_queryctrl(cam->sdev, a);
+
+	return rval;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *fh,
+			 struct v4l2_control *a)
+{
+	struct omap24xxcam_fh *ofh = fh;
+	struct omap24xxcam_device *cam = ofh->cam;
+	int rval;
+
+	mutex_lock(&cam->mutex);
+	rval = vidioc_int_g_ctrl(cam->sdev, a);
+	mutex_unlock(&cam->mutex);
+
+	return rval;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *fh,
+			 struct v4l2_control *a)
+{
+	struct omap24xxcam_fh *ofh = fh;
+	struct omap24xxcam_device *cam = ofh->cam;
+	int rval;
+
+	mutex_lock(&cam->mutex);
+	rval = vidioc_int_s_ctrl(cam->sdev, a);
+	mutex_unlock(&cam->mutex);
+
+	return rval;
+}
+
+static int vidioc_g_parm(struct file *file, void *fh,
+			 struct v4l2_streamparm *a) {
+	struct omap24xxcam_fh *ofh = fh;
+	struct omap24xxcam_device *cam = ofh->cam;
+	int rval;
+
+	mutex_lock(&cam->mutex);
+	rval = vidioc_int_g_parm(cam->sdev, a);
+	mutex_unlock(&cam->mutex);
+
+	return rval;
+}
+
+static int vidioc_s_parm(struct file *file, void *fh,
+			 struct v4l2_streamparm *a)
+{
+	struct omap24xxcam_fh *ofh = fh;
+	struct omap24xxcam_device *cam = ofh->cam;
+	struct v4l2_streamparm old_streamparm;
+	int rval;
+
+	mutex_lock(&cam->mutex);
+	if (cam->streaming) {
+		rval = -EBUSY;
+		goto out;
+	}
+
+	old_streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	rval = vidioc_int_g_parm(cam->sdev, &old_streamparm);
+	if (rval)
+		goto out;
+
+	rval = vidioc_int_s_parm(cam->sdev, a);
+	if (rval)
+		goto out;
+
+	rval = omap24xxcam_sensor_if_enable(cam);
+	/*
+	 * Revert to old streaming parameters if enabling sensor
+	 * interface with the new ones failed.
+	 */
+	if (rval)
+		vidioc_int_s_parm(cam->sdev, &old_streamparm);
+
+out:
+	mutex_unlock(&cam->mutex);
+
+	return rval;
+}
+
+/*
+ *
+ * File operations.
+ *
+ */
+
+static unsigned int omap24xxcam_poll(struct file *file,
+				     struct poll_table_struct *wait)
+{
+	struct omap24xxcam_fh *fh = file->private_data;
+	struct omap24xxcam_device *cam = fh->cam;
+	struct videobuf_buffer *vb;
+
+	mutex_lock(&cam->mutex);
+	if (cam->streaming != file) {
+		mutex_unlock(&cam->mutex);
+		return POLLERR;
+	}
+	mutex_unlock(&cam->mutex);
+
+	mutex_lock(&fh->vbq.vb_lock);
+	if (list_empty(&fh->vbq.stream)) {
+		mutex_unlock(&fh->vbq.vb_lock);
+		return POLLERR;
+	}
+	vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream);
+	mutex_unlock(&fh->vbq.vb_lock);
+
+	poll_wait(file, &vb->done, wait);
+
+	if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR)
+		return POLLIN | POLLRDNORM;
+
+	return 0;
+}
+
+static int omap24xxcam_mmap_buffers(struct file *file,
+				    struct vm_area_struct *vma)
+{
+	struct omap24xxcam_fh *fh = file->private_data;
+	struct omap24xxcam_device *cam = fh->cam;
+	struct videobuf_queue *vbq = &fh->vbq;
+	unsigned int first, last, size, i, j;
+	int err = 0;
+
+	mutex_lock(&cam->mutex);
+	if (cam->streaming) {
+		mutex_unlock(&cam->mutex);
+		return -EBUSY;
+	}
+	mutex_unlock(&cam->mutex);
+	mutex_lock(&vbq->vb_lock);
+
+	/* look for first buffer to map */
+	for (first = 0; first < VIDEO_MAX_FRAME; first++) {
+		if (NULL == vbq->bufs[first])
+			continue;
+		if (V4L2_MEMORY_MMAP != vbq->bufs[first]->memory)
+			continue;
+		if (vbq->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))
+			break;
+	}
+
+	/* look for last buffer to map */
+	for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {
+		if (NULL == vbq->bufs[last])
+			continue;
+		if (V4L2_MEMORY_MMAP != vbq->bufs[last]->memory)
+			continue;
+		size += vbq->bufs[last]->bsize;
+		if (size == (vma->vm_end - vma->vm_start))
+			break;
+	}
+
+	size = 0;
+	for (i = first; i <= last && i < VIDEO_MAX_FRAME; i++) {
+		struct videobuf_dmabuf *dma = videobuf_to_dma(vbq->bufs[i]);
+
+		for (j = 0; j < dma->sglen; j++) {
+			err = remap_pfn_range(
+				vma, vma->vm_start + size,
+				page_to_pfn(sg_page(&dma->sglist[j])),
+				sg_dma_len(&dma->sglist[j]), vma->vm_page_prot);
+			if (err)
+				goto out;
+			size += sg_dma_len(&dma->sglist[j]);
+		}
+	}
+
+out:
+	mutex_unlock(&vbq->vb_lock);
+
+	return err;
+}
+
+static int omap24xxcam_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct omap24xxcam_fh *fh = file->private_data;
+	int rval;
+
+	/* let the video-buf mapper check arguments and set-up structures */
+	rval = videobuf_mmap_mapper(&fh->vbq, vma);
+	if (rval)
+		return rval;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	/* do mapping to our allocated buffers */
+	rval = omap24xxcam_mmap_buffers(file, vma);
+	/*
+	 * In case of error, free vma->vm_private_data allocated by
+	 * videobuf_mmap_mapper.
+	 */
+	if (rval)
+		kfree(vma->vm_private_data);
+
+	return rval;
+}
+
+static int omap24xxcam_open(struct file *file)
+{
+	struct omap24xxcam_device *cam = omap24xxcam.priv;
+	struct omap24xxcam_fh *fh;
+	struct v4l2_format format;
+
+	if (!cam || !cam->vfd)
+		return -ENODEV;
+
+	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+	if (fh == NULL)
+		return -ENOMEM;
+
+	mutex_lock(&cam->mutex);
+	if (cam->sdev == NULL || !try_module_get(cam->sdev->module)) {
+		mutex_unlock(&cam->mutex);
+		goto out_try_module_get;
+	}
+
+	if (atomic_inc_return(&cam->users) == 1) {
+		omap24xxcam_hwinit(cam);
+		if (omap24xxcam_sensor_enable(cam)) {
+			mutex_unlock(&cam->mutex);
+			goto out_omap24xxcam_sensor_enable;
+		}
+	}
+	mutex_unlock(&cam->mutex);
+
+	fh->cam = cam;
+	mutex_lock(&cam->mutex);
+	vidioc_int_g_fmt_cap(cam->sdev, &format);
+	mutex_unlock(&cam->mutex);
+	/* FIXME: how about fh->pix when there are more users? */
+	fh->pix = format.fmt.pix;
+
+	file->private_data = fh;
+
+	spin_lock_init(&fh->vbq_lock);
+
+	videobuf_queue_sg_init(&fh->vbq, &omap24xxcam_vbq_ops, NULL,
+				&fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+				V4L2_FIELD_NONE,
+				sizeof(struct videobuf_buffer), fh, NULL);
+
+	return 0;
+
+out_omap24xxcam_sensor_enable:
+	omap24xxcam_poweron_reset(cam);
+	module_put(cam->sdev->module);
+
+out_try_module_get:
+	kfree(fh);
+
+	return -ENODEV;
+}
+
+static int omap24xxcam_release(struct file *file)
+{
+	struct omap24xxcam_fh *fh = file->private_data;
+	struct omap24xxcam_device *cam = fh->cam;
+
+	atomic_inc(&cam->reset_disable);
+
+	flush_work_sync(&cam->sensor_reset_work);
+
+	/* stop streaming capture */
+	videobuf_streamoff(&fh->vbq);
+
+	mutex_lock(&cam->mutex);
+	if (cam->streaming == file) {
+		cam->streaming = NULL;
+		mutex_unlock(&cam->mutex);
+		sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+	} else {
+		mutex_unlock(&cam->mutex);
+	}
+
+	atomic_dec(&cam->reset_disable);
+
+	omap24xxcam_vbq_free_mmap_buffers(&fh->vbq);
+
+	/*
+	 * Make sure the reset work we might have scheduled is not
+	 * pending! It may be run *only* if we have users. (And it may
+	 * not be scheduled anymore since streaming is already
+	 * disabled.)
+	 */
+	flush_work_sync(&cam->sensor_reset_work);
+
+	mutex_lock(&cam->mutex);
+	if (atomic_dec_return(&cam->users) == 0) {
+		omap24xxcam_sensor_disable(cam);
+		omap24xxcam_poweron_reset(cam);
+	}
+	mutex_unlock(&cam->mutex);
+
+	file->private_data = NULL;
+
+	module_put(cam->sdev->module);
+	kfree(fh);
+
+	return 0;
+}
+
+static struct v4l2_file_operations omap24xxcam_fops = {
+	.ioctl	 = video_ioctl2,
+	.poll	 = omap24xxcam_poll,
+	.mmap	 = omap24xxcam_mmap,
+	.open	 = omap24xxcam_open,
+	.release = omap24xxcam_release,
+};
+
+/*
+ *
+ * Power management.
+ *
+ */
+
+#ifdef CONFIG_PM
+static int omap24xxcam_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+	if (atomic_read(&cam->users) == 0)
+		return 0;
+
+	if (!atomic_read(&cam->reset_disable))
+		omap24xxcam_capture_stop(cam);
+
+	omap24xxcam_sensor_disable(cam);
+	omap24xxcam_poweron_reset(cam);
+
+	return 0;
+}
+
+static int omap24xxcam_resume(struct platform_device *pdev)
+{
+	struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+	if (atomic_read(&cam->users) == 0)
+		return 0;
+
+	omap24xxcam_hwinit(cam);
+	omap24xxcam_sensor_enable(cam);
+
+	if (!atomic_read(&cam->reset_disable))
+		omap24xxcam_capture_cont(cam);
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct v4l2_ioctl_ops omap24xxcam_ioctl_fops = {
+	.vidioc_querycap	= vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap	= vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,
+	.vidioc_reqbufs		= vidioc_reqbufs,
+	.vidioc_querybuf	= vidioc_querybuf,
+	.vidioc_qbuf		= vidioc_qbuf,
+	.vidioc_dqbuf		= vidioc_dqbuf,
+	.vidioc_streamon	= vidioc_streamon,
+	.vidioc_streamoff	= vidioc_streamoff,
+	.vidioc_enum_input	= vidioc_enum_input,
+	.vidioc_g_input		= vidioc_g_input,
+	.vidioc_s_input		= vidioc_s_input,
+	.vidioc_queryctrl	= vidioc_queryctrl,
+	.vidioc_g_ctrl		= vidioc_g_ctrl,
+	.vidioc_s_ctrl		= vidioc_s_ctrl,
+	.vidioc_g_parm		= vidioc_g_parm,
+	.vidioc_s_parm		= vidioc_s_parm,
+};
+
+/*
+ *
+ * Camera device (i.e. /dev/video).
+ *
+ */
+
+static int omap24xxcam_device_register(struct v4l2_int_device *s)
+{
+	struct omap24xxcam_device *cam = s->u.slave->master->priv;
+	struct video_device *vfd;
+	int rval;
+
+	/* We already have a slave. */
+	if (cam->sdev)
+		return -EBUSY;
+
+	cam->sdev = s;
+
+	if (device_create_file(cam->dev, &dev_attr_streaming) != 0) {
+		dev_err(cam->dev, "could not register sysfs entry\n");
+		rval = -EBUSY;
+		goto err;
+	}
+
+	/* initialize the video_device struct */
+	vfd = cam->vfd = video_device_alloc();
+	if (!vfd) {
+		dev_err(cam->dev, "could not allocate video device struct\n");
+		rval = -ENOMEM;
+		goto err;
+	}
+	vfd->release = video_device_release;
+
+	vfd->parent = cam->dev;
+
+	strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
+	vfd->fops		 = &omap24xxcam_fops;
+	vfd->ioctl_ops		 = &omap24xxcam_ioctl_fops;
+
+	omap24xxcam_hwinit(cam);
+
+	rval = omap24xxcam_sensor_init(cam);
+	if (rval)
+		goto err;
+
+	if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
+		dev_err(cam->dev, "could not register V4L device\n");
+		rval = -EBUSY;
+		goto err;
+	}
+
+	omap24xxcam_poweron_reset(cam);
+
+	dev_info(cam->dev, "registered device %s\n",
+		 video_device_node_name(vfd));
+
+	return 0;
+
+err:
+	omap24xxcam_device_unregister(s);
+
+	return rval;
+}
+
+static void omap24xxcam_device_unregister(struct v4l2_int_device *s)
+{
+	struct omap24xxcam_device *cam = s->u.slave->master->priv;
+
+	omap24xxcam_sensor_exit(cam);
+
+	if (cam->vfd) {
+		if (!video_is_registered(cam->vfd)) {
+			/*
+			 * The device was never registered, so release the
+			 * video_device struct directly.
+			 */
+			video_device_release(cam->vfd);
+		} else {
+			/*
+			 * The unregister function will release the
+			 * video_device struct as well as
+			 * unregistering it.
+			 */
+			video_unregister_device(cam->vfd);
+		}
+		cam->vfd = NULL;
+	}
+
+	device_remove_file(cam->dev, &dev_attr_streaming);
+
+	cam->sdev = NULL;
+}
+
+static struct v4l2_int_master omap24xxcam_master = {
+	.attach = omap24xxcam_device_register,
+	.detach = omap24xxcam_device_unregister,
+};
+
+static struct v4l2_int_device omap24xxcam = {
+	.module	= THIS_MODULE,
+	.name	= CAM_NAME,
+	.type	= v4l2_int_type_master,
+	.u	= {
+		.master = &omap24xxcam_master
+	},
+};
+
+/*
+ *
+ * Driver initialisation and deinitialisation.
+ *
+ */
+
+static int __devinit omap24xxcam_probe(struct platform_device *pdev)
+{
+	struct omap24xxcam_device *cam;
+	struct resource *mem;
+	int irq;
+
+	cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+	if (!cam) {
+		dev_err(&pdev->dev, "could not allocate memory\n");
+		goto err;
+	}
+
+	platform_set_drvdata(pdev, cam);
+
+	cam->dev = &pdev->dev;
+
+	/*
+	 * Impose a lower limit on the amount of memory allocated for
+	 * capture. We require at least enough memory to double-buffer
+	 * QVGA (300KB).
+	 */
+	if (capture_mem < 320 * 240 * 2 * 2)
+		capture_mem = 320 * 240 * 2 * 2;
+	cam->capture_mem = capture_mem;
+
+	/* request the mem region for the camera registers */
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(cam->dev, "no mem resource?\n");
+		goto err;
+	}
+	if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
+		dev_err(cam->dev,
+			"cannot reserve camera register I/O region\n");
+		goto err;
+	}
+	cam->mmio_base_phys = mem->start;
+	cam->mmio_size = resource_size(mem);
+
+	/* map the region */
+	cam->mmio_base = ioremap_nocache(cam->mmio_base_phys, cam->mmio_size);
+	if (!cam->mmio_base) {
+		dev_err(cam->dev, "cannot map camera register I/O region\n");
+		goto err;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq <= 0) {
+		dev_err(cam->dev, "no irq for camera?\n");
+		goto err;
+	}
+
+	/* install the interrupt service routine */
+	if (request_irq(irq, omap24xxcam_isr, 0, CAM_NAME, cam)) {
+		dev_err(cam->dev,
+			"could not install interrupt service routine\n");
+		goto err;
+	}
+	cam->irq = irq;
+
+	if (omap24xxcam_clock_get(cam))
+		goto err;
+
+	INIT_WORK(&cam->sensor_reset_work, omap24xxcam_sensor_reset_work);
+
+	mutex_init(&cam->mutex);
+	spin_lock_init(&cam->core_enable_disable_lock);
+
+	omap24xxcam_sgdma_init(&cam->sgdma,
+			       cam->mmio_base + CAMDMA_REG_OFFSET,
+			       omap24xxcam_stalled_dma_reset,
+			       (unsigned long)cam);
+
+	omap24xxcam.priv = cam;
+
+	if (v4l2_int_device_register(&omap24xxcam))
+		goto err;
+
+	return 0;
+
+err:
+	omap24xxcam_remove(pdev);
+	return -ENODEV;
+}
+
+static int omap24xxcam_remove(struct platform_device *pdev)
+{
+	struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+	if (!cam)
+		return 0;
+
+	if (omap24xxcam.priv != NULL)
+		v4l2_int_device_unregister(&omap24xxcam);
+	omap24xxcam.priv = NULL;
+
+	omap24xxcam_clock_put(cam);
+
+	if (cam->irq) {
+		free_irq(cam->irq, cam);
+		cam->irq = 0;
+	}
+
+	if (cam->mmio_base) {
+		iounmap((void *)cam->mmio_base);
+		cam->mmio_base = 0;
+	}
+
+	if (cam->mmio_base_phys) {
+		release_mem_region(cam->mmio_base_phys, cam->mmio_size);
+		cam->mmio_base_phys = 0;
+	}
+
+	kfree(cam);
+
+	return 0;
+}
+
+static struct platform_driver omap24xxcam_driver = {
+	.probe	 = omap24xxcam_probe,
+	.remove	 = omap24xxcam_remove,
+#ifdef CONFIG_PM
+	.suspend = omap24xxcam_suspend,
+	.resume	 = omap24xxcam_resume,
+#endif
+	.driver	 = {
+		.name = CAM_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+module_platform_driver(omap24xxcam_driver);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
+MODULE_DESCRIPTION("OMAP24xx Video for Linux camera driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(OMAP24XXCAM_VERSION);
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr,
+		 "Minor number for video device (-1 ==> auto assign)");
+module_param(capture_mem, int, 0);
+MODULE_PARM_DESC(capture_mem, "Maximum amount of memory for capture "
+		 "buffers (default 4800kiB)");
diff --git a/drivers/media/platform/omap24xxcam.h b/drivers/media/platform/omap24xxcam.h
new file mode 100644
index 0000000..c439595
--- /dev/null
+++ b/drivers/media/platform/omap24xxcam.h
@@ -0,0 +1,593 @@
+/*
+ * drivers/media/platform/omap24xxcam.h
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from Andy Lowe <source@mvista.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP24XXCAM_H
+#define OMAP24XXCAM_H
+
+#include <media/videobuf-dma-sg.h>
+#include <media/v4l2-int-device.h>
+
+/*
+ *
+ * General driver related definitions.
+ *
+ */
+
+#define CAM_NAME				"omap24xxcam"
+
+#define CAM_MCLK				96000000
+
+/* number of bytes transferred per DMA request */
+#define DMA_THRESHOLD				32
+
+/*
+ * NUM_CAMDMA_CHANNELS is the number of logical channels provided by
+ * the camera DMA controller.
+ */
+#define NUM_CAMDMA_CHANNELS			4
+
+/*
+ * NUM_SG_DMA is the number of scatter-gather DMA transfers that can
+ * be queued. (We don't have any overlay sglists now.)
+ */
+#define NUM_SG_DMA				(VIDEO_MAX_FRAME)
+
+/*
+ *
+ * Register definitions.
+ *
+ */
+
+/* subsystem register block offsets */
+#define CC_REG_OFFSET				0x00000400
+#define CAMDMA_REG_OFFSET			0x00000800
+#define CAMMMU_REG_OFFSET			0x00000C00
+
+/* define camera subsystem register offsets */
+#define CAM_REVISION				0x000
+#define CAM_SYSCONFIG				0x010
+#define CAM_SYSSTATUS				0x014
+#define CAM_IRQSTATUS				0x018
+#define CAM_GPO					0x040
+#define CAM_GPI					0x050
+
+/* define camera core register offsets */
+#define CC_REVISION				0x000
+#define CC_SYSCONFIG				0x010
+#define CC_SYSSTATUS				0x014
+#define CC_IRQSTATUS				0x018
+#define CC_IRQENABLE				0x01C
+#define CC_CTRL					0x040
+#define CC_CTRL_DMA				0x044
+#define CC_CTRL_XCLK				0x048
+#define CC_FIFODATA				0x04C
+#define CC_TEST					0x050
+#define CC_GENPAR				0x054
+#define CC_CCPFSCR				0x058
+#define CC_CCPFECR				0x05C
+#define CC_CCPLSCR				0x060
+#define CC_CCPLECR				0x064
+#define CC_CCPDFR				0x068
+
+/* define camera dma register offsets */
+#define CAMDMA_REVISION				0x000
+#define CAMDMA_IRQSTATUS_L0			0x008
+#define CAMDMA_IRQSTATUS_L1			0x00C
+#define CAMDMA_IRQSTATUS_L2			0x010
+#define CAMDMA_IRQSTATUS_L3			0x014
+#define CAMDMA_IRQENABLE_L0			0x018
+#define CAMDMA_IRQENABLE_L1			0x01C
+#define CAMDMA_IRQENABLE_L2			0x020
+#define CAMDMA_IRQENABLE_L3			0x024
+#define CAMDMA_SYSSTATUS			0x028
+#define CAMDMA_OCP_SYSCONFIG			0x02C
+#define CAMDMA_CAPS_0				0x064
+#define CAMDMA_CAPS_2				0x06C
+#define CAMDMA_CAPS_3				0x070
+#define CAMDMA_CAPS_4				0x074
+#define CAMDMA_GCR				0x078
+#define CAMDMA_CCR(n)				(0x080 + (n)*0x60)
+#define CAMDMA_CLNK_CTRL(n)			(0x084 + (n)*0x60)
+#define CAMDMA_CICR(n)				(0x088 + (n)*0x60)
+#define CAMDMA_CSR(n)				(0x08C + (n)*0x60)
+#define CAMDMA_CSDP(n)				(0x090 + (n)*0x60)
+#define CAMDMA_CEN(n)				(0x094 + (n)*0x60)
+#define CAMDMA_CFN(n)				(0x098 + (n)*0x60)
+#define CAMDMA_CSSA(n)				(0x09C + (n)*0x60)
+#define CAMDMA_CDSA(n)				(0x0A0 + (n)*0x60)
+#define CAMDMA_CSEI(n)				(0x0A4 + (n)*0x60)
+#define CAMDMA_CSFI(n)				(0x0A8 + (n)*0x60)
+#define CAMDMA_CDEI(n)				(0x0AC + (n)*0x60)
+#define CAMDMA_CDFI(n)				(0x0B0 + (n)*0x60)
+#define CAMDMA_CSAC(n)				(0x0B4 + (n)*0x60)
+#define CAMDMA_CDAC(n)				(0x0B8 + (n)*0x60)
+#define CAMDMA_CCEN(n)				(0x0BC + (n)*0x60)
+#define CAMDMA_CCFN(n)				(0x0C0 + (n)*0x60)
+#define CAMDMA_COLOR(n)				(0x0C4 + (n)*0x60)
+
+/* define camera mmu register offsets */
+#define CAMMMU_REVISION				0x000
+#define CAMMMU_SYSCONFIG			0x010
+#define CAMMMU_SYSSTATUS			0x014
+#define CAMMMU_IRQSTATUS			0x018
+#define CAMMMU_IRQENABLE			0x01C
+#define CAMMMU_WALKING_ST			0x040
+#define CAMMMU_CNTL				0x044
+#define CAMMMU_FAULT_AD				0x048
+#define CAMMMU_TTB				0x04C
+#define CAMMMU_LOCK				0x050
+#define CAMMMU_LD_TLB				0x054
+#define CAMMMU_CAM				0x058
+#define CAMMMU_RAM				0x05C
+#define CAMMMU_GFLUSH				0x060
+#define CAMMMU_FLUSH_ENTRY			0x064
+#define CAMMMU_READ_CAM				0x068
+#define CAMMMU_READ_RAM				0x06C
+#define CAMMMU_EMU_FAULT_AD			0x070
+
+/* Define bit fields within selected registers */
+#define CAM_REVISION_MAJOR			(15 << 4)
+#define CAM_REVISION_MAJOR_SHIFT		4
+#define CAM_REVISION_MINOR			(15 << 0)
+#define CAM_REVISION_MINOR_SHIFT		0
+
+#define CAM_SYSCONFIG_SOFTRESET			(1 <<  1)
+#define CAM_SYSCONFIG_AUTOIDLE			(1 <<  0)
+
+#define CAM_SYSSTATUS_RESETDONE			(1 <<  0)
+
+#define CAM_IRQSTATUS_CC_IRQ			(1 <<  4)
+#define CAM_IRQSTATUS_MMU_IRQ			(1 <<  3)
+#define CAM_IRQSTATUS_DMA_IRQ2			(1 <<  2)
+#define CAM_IRQSTATUS_DMA_IRQ1			(1 <<  1)
+#define CAM_IRQSTATUS_DMA_IRQ0			(1 <<  0)
+
+#define CAM_GPO_CAM_S_P_EN			(1 <<  1)
+#define CAM_GPO_CAM_CCP_MODE			(1 <<  0)
+
+#define CAM_GPI_CC_DMA_REQ1			(1 << 24)
+#define CAP_GPI_CC_DMA_REQ0			(1 << 23)
+#define CAP_GPI_CAM_MSTANDBY			(1 << 21)
+#define CAP_GPI_CAM_WAIT			(1 << 20)
+#define CAP_GPI_CAM_S_DATA			(1 << 17)
+#define CAP_GPI_CAM_S_CLK			(1 << 16)
+#define CAP_GPI_CAM_P_DATA			(0xFFF << 3)
+#define CAP_GPI_CAM_P_DATA_SHIFT		3
+#define CAP_GPI_CAM_P_VS			(1 <<  2)
+#define CAP_GPI_CAM_P_HS			(1 <<  1)
+#define CAP_GPI_CAM_P_CLK			(1 <<  0)
+
+#define CC_REVISION_MAJOR			(15 << 4)
+#define CC_REVISION_MAJOR_SHIFT			4
+#define CC_REVISION_MINOR			(15 << 0)
+#define CC_REVISION_MINOR_SHIFT			0
+
+#define CC_SYSCONFIG_SIDLEMODE			(3 <<  3)
+#define CC_SYSCONFIG_SIDLEMODE_FIDLE		(0 <<  3)
+#define CC_SYSCONFIG_SIDLEMODE_NIDLE		(1 <<  3)
+#define CC_SYSCONFIG_SOFTRESET			(1 <<  1)
+#define CC_SYSCONFIG_AUTOIDLE			(1 <<  0)
+
+#define CC_SYSSTATUS_RESETDONE			(1 <<  0)
+
+#define CC_IRQSTATUS_FS_IRQ			(1 << 19)
+#define CC_IRQSTATUS_LE_IRQ			(1 << 18)
+#define CC_IRQSTATUS_LS_IRQ			(1 << 17)
+#define CC_IRQSTATUS_FE_IRQ			(1 << 16)
+#define CC_IRQSTATUS_FW_ERR_IRQ			(1 << 10)
+#define CC_IRQSTATUS_FSC_ERR_IRQ		(1 <<  9)
+#define CC_IRQSTATUS_SSC_ERR_IRQ		(1 <<  8)
+#define CC_IRQSTATUS_FIFO_NOEMPTY_IRQ		(1 <<  4)
+#define CC_IRQSTATUS_FIFO_FULL_IRQ		(1 <<  3)
+#define CC_IRQSTATUS_FIFO_THR_IRQ		(1 <<  2)
+#define CC_IRQSTATUS_FIFO_OF_IRQ		(1 <<  1)
+#define CC_IRQSTATUS_FIFO_UF_IRQ		(1 <<  0)
+
+#define CC_IRQENABLE_FS_IRQ			(1 << 19)
+#define CC_IRQENABLE_LE_IRQ			(1 << 18)
+#define CC_IRQENABLE_LS_IRQ			(1 << 17)
+#define CC_IRQENABLE_FE_IRQ			(1 << 16)
+#define CC_IRQENABLE_FW_ERR_IRQ			(1 << 10)
+#define CC_IRQENABLE_FSC_ERR_IRQ		(1 <<  9)
+#define CC_IRQENABLE_SSC_ERR_IRQ		(1 <<  8)
+#define CC_IRQENABLE_FIFO_NOEMPTY_IRQ		(1 <<  4)
+#define CC_IRQENABLE_FIFO_FULL_IRQ		(1 <<  3)
+#define CC_IRQENABLE_FIFO_THR_IRQ		(1 <<  2)
+#define CC_IRQENABLE_FIFO_OF_IRQ		(1 <<  1)
+#define CC_IRQENABLE_FIFO_UF_IRQ		(1 <<  0)
+
+#define CC_CTRL_CC_ONE_SHOT			(1 << 20)
+#define CC_CTRL_CC_IF_SYNCHRO			(1 << 19)
+#define CC_CTRL_CC_RST				(1 << 18)
+#define CC_CTRL_CC_FRAME_TRIG			(1 << 17)
+#define CC_CTRL_CC_EN				(1 << 16)
+#define CC_CTRL_NOBT_SYNCHRO			(1 << 13)
+#define CC_CTRL_BT_CORRECT			(1 << 12)
+#define CC_CTRL_PAR_ORDERCAM			(1 << 11)
+#define CC_CTRL_PAR_CLK_POL			(1 << 10)
+#define CC_CTRL_NOBT_HS_POL			(1 <<  9)
+#define CC_CTRL_NOBT_VS_POL			(1 <<  8)
+#define CC_CTRL_PAR_MODE			(7 <<  1)
+#define CC_CTRL_PAR_MODE_SHIFT			1
+#define CC_CTRL_PAR_MODE_NOBT8			(0 <<  1)
+#define CC_CTRL_PAR_MODE_NOBT10			(1 <<  1)
+#define CC_CTRL_PAR_MODE_NOBT12			(2 <<  1)
+#define CC_CTRL_PAR_MODE_BT8			(4 <<  1)
+#define CC_CTRL_PAR_MODE_BT10			(5 <<  1)
+#define CC_CTRL_PAR_MODE_FIFOTEST		(7 <<  1)
+#define CC_CTRL_CCP_MODE			(1 <<  0)
+
+#define CC_CTRL_DMA_EN				(1 <<  8)
+#define CC_CTRL_DMA_FIFO_THRESHOLD		(0x7F << 0)
+#define CC_CTRL_DMA_FIFO_THRESHOLD_SHIFT	0
+
+#define CC_CTRL_XCLK_DIV			(0x1F << 0)
+#define CC_CTRL_XCLK_DIV_SHIFT			0
+#define CC_CTRL_XCLK_DIV_STABLE_LOW		(0 <<  0)
+#define CC_CTRL_XCLK_DIV_STABLE_HIGH		(1 <<  0)
+#define CC_CTRL_XCLK_DIV_BYPASS			(31 << 0)
+
+#define CC_TEST_FIFO_RD_POINTER			(0xFF << 24)
+#define CC_TEST_FIFO_RD_POINTER_SHIFT		24
+#define CC_TEST_FIFO_WR_POINTER			(0xFF << 16)
+#define CC_TEST_FIFO_WR_POINTER_SHIFT		16
+#define CC_TEST_FIFO_LEVEL			(0xFF <<  8)
+#define CC_TEST_FIFO_LEVEL_SHIFT		8
+#define CC_TEST_FIFO_LEVEL_PEAK			(0xFF <<  0)
+#define CC_TEST_FIFO_LEVEL_PEAK_SHIFT		0
+
+#define CC_GENPAR_FIFO_DEPTH			(7 <<  0)
+#define CC_GENPAR_FIFO_DEPTH_SHIFT		0
+
+#define CC_CCPDFR_ALPHA				(0xFF <<  8)
+#define CC_CCPDFR_ALPHA_SHIFT			8
+#define CC_CCPDFR_DATAFORMAT			(15 <<  0)
+#define CC_CCPDFR_DATAFORMAT_SHIFT		0
+#define CC_CCPDFR_DATAFORMAT_YUV422BE		(0 <<  0)
+#define CC_CCPDFR_DATAFORMAT_YUV422		(1 <<  0)
+#define CC_CCPDFR_DATAFORMAT_YUV420		(2 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RGB444		(4 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RGB565		(5 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RGB888NDE		(6 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RGB888		(7 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RAW8NDE		(8 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RAW8		(9 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RAW10NDE		(10 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RAW10		(11 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RAW12NDE		(12 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RAW12		(13 <<  0)
+#define CC_CCPDFR_DATAFORMAT_JPEG8		(15 <<  0)
+
+#define CAMDMA_REVISION_MAJOR			(15 << 4)
+#define CAMDMA_REVISION_MAJOR_SHIFT		4
+#define CAMDMA_REVISION_MINOR			(15 << 0)
+#define CAMDMA_REVISION_MINOR_SHIFT		0
+
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE		(3 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY	(0 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_NSTANDBY	(1 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_SSTANDBY	(2 << 12)
+#define CAMDMA_OCP_SYSCONFIG_FUNC_CLOCK		(1 <<  9)
+#define CAMDMA_OCP_SYSCONFIG_OCP_CLOCK		(1 <<  8)
+#define CAMDMA_OCP_SYSCONFIG_EMUFREE		(1 <<  5)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE		(3 <<  3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE	(0 <<  3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_NIDLE	(1 <<  3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_SIDLE	(2 <<  3)
+#define CAMDMA_OCP_SYSCONFIG_SOFTRESET		(1 <<  1)
+#define CAMDMA_OCP_SYSCONFIG_AUTOIDLE		(1 <<  0)
+
+#define CAMDMA_SYSSTATUS_RESETDONE		(1 <<  0)
+
+#define CAMDMA_GCR_ARBITRATION_RATE		(0xFF << 16)
+#define CAMDMA_GCR_ARBITRATION_RATE_SHIFT	16
+#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH	(0xFF << 0)
+#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH_SHIFT	0
+
+#define CAMDMA_CCR_SEL_SRC_DST_SYNC		(1 << 24)
+#define CAMDMA_CCR_PREFETCH			(1 << 23)
+#define CAMDMA_CCR_SUPERVISOR			(1 << 22)
+#define CAMDMA_CCR_SECURE			(1 << 21)
+#define CAMDMA_CCR_BS				(1 << 18)
+#define CAMDMA_CCR_TRANSPARENT_COPY_ENABLE	(1 << 17)
+#define CAMDMA_CCR_CONSTANT_FILL_ENABLE		(1 << 16)
+#define CAMDMA_CCR_DST_AMODE			(3 << 14)
+#define CAMDMA_CCR_DST_AMODE_CONST_ADDR		(0 << 14)
+#define CAMDMA_CCR_DST_AMODE_POST_INC		(1 << 14)
+#define CAMDMA_CCR_DST_AMODE_SGL_IDX		(2 << 14)
+#define CAMDMA_CCR_DST_AMODE_DBL_IDX		(3 << 14)
+#define CAMDMA_CCR_SRC_AMODE			(3 << 12)
+#define CAMDMA_CCR_SRC_AMODE_CONST_ADDR		(0 << 12)
+#define CAMDMA_CCR_SRC_AMODE_POST_INC		(1 << 12)
+#define CAMDMA_CCR_SRC_AMODE_SGL_IDX		(2 << 12)
+#define CAMDMA_CCR_SRC_AMODE_DBL_IDX		(3 << 12)
+#define CAMDMA_CCR_WR_ACTIVE			(1 << 10)
+#define CAMDMA_CCR_RD_ACTIVE			(1 <<  9)
+#define CAMDMA_CCR_SUSPEND_SENSITIVE		(1 <<  8)
+#define CAMDMA_CCR_ENABLE			(1 <<  7)
+#define CAMDMA_CCR_PRIO				(1 <<  6)
+#define CAMDMA_CCR_FS				(1 <<  5)
+#define CAMDMA_CCR_SYNCHRO			((3 << 19) | (31 << 0))
+#define CAMDMA_CCR_SYNCHRO_CAMERA		0x01
+
+#define CAMDMA_CLNK_CTRL_ENABLE_LNK		(1 << 15)
+#define CAMDMA_CLNK_CTRL_NEXTLCH_ID		(0x1F << 0)
+#define CAMDMA_CLNK_CTRL_NEXTLCH_ID_SHIFT	0
+
+#define CAMDMA_CICR_MISALIGNED_ERR_IE		(1 << 11)
+#define CAMDMA_CICR_SUPERVISOR_ERR_IE		(1 << 10)
+#define CAMDMA_CICR_SECURE_ERR_IE		(1 <<  9)
+#define CAMDMA_CICR_TRANS_ERR_IE		(1 <<  8)
+#define CAMDMA_CICR_PACKET_IE			(1 <<  7)
+#define CAMDMA_CICR_BLOCK_IE			(1 <<  5)
+#define CAMDMA_CICR_LAST_IE			(1 <<  4)
+#define CAMDMA_CICR_FRAME_IE			(1 <<  3)
+#define CAMDMA_CICR_HALF_IE			(1 <<  2)
+#define CAMDMA_CICR_DROP_IE			(1 <<  1)
+
+#define CAMDMA_CSR_MISALIGNED_ERR		(1 << 11)
+#define CAMDMA_CSR_SUPERVISOR_ERR		(1 << 10)
+#define CAMDMA_CSR_SECURE_ERR			(1 <<  9)
+#define CAMDMA_CSR_TRANS_ERR			(1 <<  8)
+#define CAMDMA_CSR_PACKET			(1 <<  7)
+#define CAMDMA_CSR_SYNC				(1 <<  6)
+#define CAMDMA_CSR_BLOCK			(1 <<  5)
+#define CAMDMA_CSR_LAST				(1 <<  4)
+#define CAMDMA_CSR_FRAME			(1 <<  3)
+#define CAMDMA_CSR_HALF				(1 <<  2)
+#define CAMDMA_CSR_DROP				(1 <<  1)
+
+#define CAMDMA_CSDP_SRC_ENDIANNESS		(1 << 21)
+#define CAMDMA_CSDP_SRC_ENDIANNESS_LOCK		(1 << 20)
+#define CAMDMA_CSDP_DST_ENDIANNESS		(1 << 19)
+#define CAMDMA_CSDP_DST_ENDIANNESS_LOCK		(1 << 18)
+#define CAMDMA_CSDP_WRITE_MODE			(3 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_WRNP		(0 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_POSTED		(1 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_POSTED_LAST_WRNP	(2 << 16)
+#define CAMDMA_CSDP_DST_BURST_EN		(3 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_1		(0 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_16		(1 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_32		(2 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_64		(3 << 14)
+#define CAMDMA_CSDP_DST_PACKED			(1 << 13)
+#define CAMDMA_CSDP_WR_ADD_TRSLT		(15 << 9)
+#define CAMDMA_CSDP_WR_ADD_TRSLT_ENABLE_MREQADD	(3 <<  9)
+#define CAMDMA_CSDP_SRC_BURST_EN		(3 <<  7)
+#define CAMDMA_CSDP_SRC_BURST_EN_1		(0 <<  7)
+#define CAMDMA_CSDP_SRC_BURST_EN_16		(1 <<  7)
+#define CAMDMA_CSDP_SRC_BURST_EN_32		(2 <<  7)
+#define CAMDMA_CSDP_SRC_BURST_EN_64		(3 <<  7)
+#define CAMDMA_CSDP_SRC_PACKED			(1 <<  6)
+#define CAMDMA_CSDP_RD_ADD_TRSLT		(15 << 2)
+#define CAMDMA_CSDP_RD_ADD_TRSLT_ENABLE_MREQADD	(3 <<  2)
+#define CAMDMA_CSDP_DATA_TYPE			(3 <<  0)
+#define CAMDMA_CSDP_DATA_TYPE_8BITS		(0 <<  0)
+#define CAMDMA_CSDP_DATA_TYPE_16BITS		(1 <<  0)
+#define CAMDMA_CSDP_DATA_TYPE_32BITS		(2 <<  0)
+
+#define CAMMMU_SYSCONFIG_AUTOIDLE		(1 <<  0)
+
+/*
+ *
+ * Declarations.
+ *
+ */
+
+/* forward declarations */
+struct omap24xxcam_sgdma;
+struct omap24xxcam_dma;
+
+typedef void (*sgdma_callback_t)(struct omap24xxcam_sgdma *cam,
+				 u32 status, void *arg);
+typedef void (*dma_callback_t)(struct omap24xxcam_dma *cam,
+			       u32 status, void *arg);
+
+struct channel_state {
+	dma_callback_t callback;
+	void *arg;
+};
+
+/* sgdma state for each of the possible videobuf_buffers + 2 overlays */
+struct sgdma_state {
+	const struct scatterlist *sglist;
+	int sglen;		 /* number of sglist entries */
+	int next_sglist;	 /* index of next sglist entry to process */
+	unsigned int bytes_read; /* number of bytes read */
+	unsigned int len;        /* total length of sglist (excluding
+				  * bytes due to page alignment) */
+	int queued_sglist;	 /* number of sglist entries queued for DMA */
+	u32 csr;		 /* DMA return code */
+	sgdma_callback_t callback;
+	void *arg;
+};
+
+/* physical DMA channel management */
+struct omap24xxcam_dma {
+	spinlock_t lock;	/* Lock for the whole structure. */
+
+	void __iomem *base;	/* base address for dma controller */
+
+	/* While dma_stop!=0, an attempt to start a new DMA transfer will
+	 * fail.
+	 */
+	atomic_t dma_stop;
+	int free_dmach;		/* number of dma channels free */
+	int next_dmach;		/* index of next dma channel to use */
+	struct channel_state ch_state[NUM_CAMDMA_CHANNELS];
+};
+
+/* scatter-gather DMA (scatterlist stuff) management */
+struct omap24xxcam_sgdma {
+	struct omap24xxcam_dma dma;
+
+	spinlock_t lock;	/* Lock for the fields below. */
+	int free_sgdma;		/* number of free sg dma slots */
+	int next_sgdma;		/* index of next sg dma slot to use */
+	struct sgdma_state sg_state[NUM_SG_DMA];
+
+	/* Reset timer data */
+	struct timer_list reset_timer;
+};
+
+/* per-device data structure */
+struct omap24xxcam_device {
+	/*** mutex  ***/
+	/*
+	 * mutex serialises access to this structure. Also camera
+	 * opening and releasing is synchronised by this.
+	 */
+	struct mutex mutex;
+
+	/*** general driver state information ***/
+	atomic_t users;
+	/*
+	 * Lock to serialise core enabling and disabling and access to
+	 * sgdma_in_queue.
+	 */
+	spinlock_t core_enable_disable_lock;
+	/*
+	 * Number or sgdma requests in scatter-gather queue, protected
+	 * by the lock above.
+	 */
+	int sgdma_in_queue;
+	/*
+	 * Sensor interface parameters: interface type, CC_CTRL
+	 * register value and interface specific data.
+	 */
+	int if_type;
+	union {
+		struct parallel {
+			u32 xclk;
+		} bt656;
+	} if_u;
+	u32 cc_ctrl;
+
+	/*** subsystem structures ***/
+	struct omap24xxcam_sgdma sgdma;
+
+	/*** hardware resources ***/
+	unsigned int irq;
+	void __iomem *mmio_base;
+	unsigned long mmio_base_phys;
+	unsigned long mmio_size;
+
+	/*** interfaces and device ***/
+	struct v4l2_int_device *sdev;
+	struct device *dev;
+	struct video_device *vfd;
+
+	/*** camera and sensor reset related stuff ***/
+	struct work_struct sensor_reset_work;
+	/*
+	 * We're in the middle of a reset. Don't enable core if this
+	 * is non-zero! This exists to help decisionmaking in a case
+	 * where videobuf_qbuf is called while we are in the middle of
+	 * a reset.
+	 */
+	atomic_t in_reset;
+	/*
+	 * Non-zero if we don't want any resets for now. Used to
+	 * prevent reset work to run when we're about to stop
+	 * streaming.
+	 */
+	atomic_t reset_disable;
+
+	/*** video device parameters ***/
+	int capture_mem;
+
+	/*** camera module clocks ***/
+	struct clk *fck;
+	struct clk *ick;
+
+	/*** capture data ***/
+	/* file handle, if streaming is on */
+	struct file *streaming;
+};
+
+/* Per-file handle data. */
+struct omap24xxcam_fh {
+	spinlock_t vbq_lock; /* spinlock for the videobuf queue */
+	struct videobuf_queue vbq;
+	struct v4l2_pix_format pix; /* serialise pix by vbq->lock */
+	atomic_t field_count; /* field counter for videobuf_buffer */
+	/* accessing cam here doesn't need serialisation: it's constant */
+	struct omap24xxcam_device *cam;
+};
+
+/*
+ *
+ * Register I/O functions.
+ *
+ */
+
+static inline u32 omap24xxcam_reg_in(u32 __iomem *base, u32 offset)
+{
+	return readl(base + offset);
+}
+
+static inline u32 omap24xxcam_reg_out(u32 __iomem *base, u32 offset,
+					  u32 val)
+{
+	writel(val, base + offset);
+	return val;
+}
+
+static inline u32 omap24xxcam_reg_merge(u32 __iomem *base, u32 offset,
+					    u32 val, u32 mask)
+{
+	u32 __iomem *addr = base + offset;
+	u32 new_val = (readl(addr) & ~mask) | (val & mask);
+
+	writel(new_val, addr);
+	return new_val;
+}
+
+/*
+ *
+ * Function prototypes.
+ *
+ */
+
+/* dma prototypes */
+
+void omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma);
+void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma);
+
+/* sgdma prototypes */
+
+void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma);
+int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma,
+			    const struct scatterlist *sglist, int sglen,
+			    int len, sgdma_callback_t callback, void *arg);
+void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma);
+void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
+			    void __iomem *base,
+			    void (*reset_callback)(unsigned long data),
+			    unsigned long reset_callback_data);
+void omap24xxcam_sgdma_exit(struct omap24xxcam_sgdma *sgdma);
+
+#endif
diff --git a/drivers/media/platform/omap3isp/Makefile b/drivers/media/platform/omap3isp/Makefile
new file mode 100644
index 0000000..e8847e7
--- /dev/null
+++ b/drivers/media/platform/omap3isp/Makefile
@@ -0,0 +1,11 @@
+# Makefile for OMAP3 ISP driver
+
+ccflags-$(CONFIG_VIDEO_OMAP3_DEBUG) += -DDEBUG
+
+omap3-isp-objs += \
+	isp.o ispqueue.o ispvideo.o \
+	ispcsiphy.o ispccp2.o ispcsi2.o \
+	ispccdc.o isppreview.o ispresizer.o \
+	ispstat.o isph3a_aewb.o isph3a_af.o isphist.o
+
+obj-$(CONFIG_VIDEO_OMAP3) += omap3-isp.o
diff --git a/drivers/media/platform/omap3isp/cfa_coef_table.h b/drivers/media/platform/omap3isp/cfa_coef_table.h
new file mode 100644
index 0000000..c84df07
--- /dev/null
+++ b/drivers/media/platform/omap3isp/cfa_coef_table.h
@@ -0,0 +1,61 @@
+/*
+ * cfa_coef_table.h
+ *
+ * TI OMAP3 ISP - CFA coefficients table
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+{ 244, 0, 247,   0,  12,  27,  36, 247, 250,   0,  27,   0,   4, 250,  12, 244,
+248,   0,   0,   0,   0,  40,   0,   0, 244,  12, 250,   4,   0,  27,   0, 250,
+247,  36,  27,  12,   0, 247,   0, 244,   0,   0,  40,   0,   0,   0,   0, 248,
+244,   0, 247,   0,  12,  27,  36, 247, 250,   0,  27,   0,   4, 250,  12, 244,
+248,   0,   0,   0,   0,  40,   0,   0, 244,  12, 250,   4,   0,  27,   0, 250,
+247,  36,  27,  12,   0, 247,   0, 244,   0,   0,  40,   0,   0,   0,   0, 248,
+244,   0, 247,   0,  12,  27,  36, 247, 250,   0,  27,   0,   4, 250,  12, 244,
+248,   0,   0,   0,   0,  40,   0,   0, 244,  12, 250,   4,   0,  27,   0, 250,
+247,  36,  27,  12,   0, 247,   0, 244,   0,   0,  40,   0,   0,   0,   0, 248 },
+{ 0, 247,   0, 244, 247,  36,  27,  12,   0,  27,   0, 250, 244,  12, 250,   4,
+  0,   0,   0, 248,   0,   0,  40,   0,   4, 250,  12, 244, 250,   0,  27,   0,
+ 12,  27,  36, 247, 244,   0, 247,   0,   0,  40,   0,   0, 248,   0,   0,   0,
+  0, 247,   0, 244, 247,  36,  27,  12,   0,  27,   0, 250, 244,  12, 250,   4,
+  0,   0,   0, 248,   0,   0,  40,   0,   4, 250,  12, 244, 250,   0,  27,   0,
+ 12,  27,  36, 247, 244,   0, 247,   0,   0,  40,   0,   0, 248,   0,   0,   0,
+  0, 247,   0, 244, 247,  36,  27,  12,   0,  27,   0, 250, 244,  12, 250,   4,
+  0,   0,   0, 248,   0,   0,  40,   0,   4, 250,  12, 244, 250,   0,  27,   0,
+ 12,  27,  36, 247, 244,   0, 247,   0,   0,  40,   0,   0, 248,   0,   0,   0 },
+{ 4, 250,  12, 244, 250,   0,  27,   0,  12,  27,  36, 247, 244,   0, 247,   0,
+  0,   0,   0, 248,   0,   0,  40,   0,   0, 247,   0, 244, 247,  36,  27,  12,
+  0,  27,   0, 250, 244,  12, 250,   4,   0,  40,   0,   0, 248,   0,   0,   0,
+  4, 250,  12, 244, 250,   0,  27,   0,  12,  27,  36, 247, 244,   0, 247,   0,
+  0,   0,   0, 248,   0,   0,  40,   0,   0, 247,   0, 244, 247,  36,  27,  12,
+  0,  27,   0, 250, 244,  12, 250,   4,   0,  40,   0,   0, 248,   0,   0,   0,
+  4, 250,  12, 244, 250,   0,  27,   0,  12,  27,  36, 247, 244,   0, 247,   0,
+  0,   0,   0, 248,   0,   0,  40,   0,   0, 247,   0, 244, 247,  36,  27,  12,
+  0,  27,   0, 250, 244,  12, 250,   4,   0,  40,   0,   0, 248,   0,   0,   0 },
+{ 244,12, 250,   4,   0,  27,   0, 250, 247,  36,  27,  12,   0, 247,   0, 244,
+248,   0,   0,   0,   0,  40,   0,   0, 244,   0, 247,   0,  12,  27,  36, 247,
+250,   0,  27,   0,   4, 250,  12, 244,   0,   0,  40,   0,   0,   0,   0, 248,
+244,  12, 250,   4,   0,  27,   0, 250, 247,  36,  27,  12,   0, 247,   0, 244,
+248,   0,   0,   0,   0,  40,   0,   0, 244,   0, 247,   0,  12,  27,  36, 247,
+250,   0,  27,   0,   4, 250,  12, 244,   0,   0,  40,   0,   0,   0,   0, 248,
+244,  12, 250,   4,   0,  27,   0, 250, 247,  36,  27,  12,   0, 247,   0, 244,
+248,   0,   0,   0,   0,  40,   0,   0, 244,   0, 247,   0,  12,  27,  36, 247,
+250,   0,  27,   0,   4, 250,  12, 244,   0,   0,  40,   0,   0,   0,   0, 248 },
diff --git a/drivers/media/platform/omap3isp/gamma_table.h b/drivers/media/platform/omap3isp/gamma_table.h
new file mode 100644
index 0000000..78deebf
--- /dev/null
+++ b/drivers/media/platform/omap3isp/gamma_table.h
@@ -0,0 +1,90 @@
+/*
+ * gamma_table.h
+ *
+ * TI OMAP3 ISP - Default gamma table for all components
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+  0,   0,   1,   2,   3,   3,   4,   5,   6,   8,  10,  12,  14,  16,  18,  20,
+ 22,  23,  25,  26,  28,  29,  31,  32,  34,  35,  36,  37,  39,  40,  41,  42,
+ 43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  52,  53,  54,  55,  56,  57,
+ 58,  59,  60,  61,  62,  63,  63,  64,  65,  66,  66,  67,  68,  69,  69,  70,
+ 71,  72,  72,  73,  74,  75,  75,  76,  77,  78,  78,  79,  80,  81,  81,  82,
+ 83,  84,  84,  85,  86,  87,  88,  88,  89,  90,  91,  91,  92,  93,  94,  94,
+ 95,  96,  97,  97,  98,  98,  99,  99, 100, 100, 101, 101, 102, 103, 104, 104,
+105, 106, 107, 108, 108, 109, 110, 111, 111, 112, 113, 114, 114, 115, 116, 117,
+117, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125,
+126, 126, 127, 127, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, 133, 133,
+134, 134, 135, 135, 136, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141,
+142, 142, 143, 143, 144, 144, 145, 145, 146, 146, 147, 147, 148, 148, 149, 149,
+150, 150, 151, 151, 152, 152, 153, 153, 153, 153, 154, 154, 154, 154, 155, 155,
+156, 156, 157, 157, 158, 158, 158, 159, 159, 159, 160, 160, 160, 161, 161, 162,
+162, 163, 163, 164, 164, 164, 164, 165, 165, 165, 165, 166, 166, 167, 167, 168,
+168, 169, 169, 170, 170, 170, 170, 171, 171, 171, 171, 172, 172, 173, 173, 174,
+174, 175, 175, 176, 176, 176, 176, 177, 177, 177, 177, 178, 178, 178, 178, 179,
+179, 179, 179, 180, 180, 180, 180, 181, 181, 181, 181, 182, 182, 182, 182, 183,
+183, 183, 183, 184, 184, 184, 184, 185, 185, 185, 185, 186, 186, 186, 186, 187,
+187, 187, 187, 188, 188, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191,
+191, 191, 191, 192, 192, 192, 192, 193, 193, 193, 193, 194, 194, 194, 194, 195,
+195, 195, 195, 196, 196, 196, 196, 197, 197, 197, 197, 198, 198, 198, 198, 199,
+199, 199, 199, 200, 200, 200, 200, 201, 201, 201, 201, 202, 202, 202, 203, 203,
+203, 203, 204, 204, 204, 204, 205, 205, 205, 205, 206, 206, 206, 206, 207, 207,
+207, 207, 208, 208, 208, 208, 209, 209, 209, 209, 210, 210, 210, 210, 210, 210,
+210, 210, 210, 210, 210, 210, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211,
+211, 212, 212, 212, 212, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213,
+213, 214, 214, 214, 214, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+216, 216, 216, 216, 217, 217, 217, 217, 218, 218, 218, 218, 219, 219, 219, 219,
+219, 219, 219, 219, 219, 219, 219, 219, 220, 220, 220, 220, 221, 221, 221, 221,
+221, 221, 221, 221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 223,
+223, 223, 223, 223, 223, 223, 223, 224, 224, 224, 224, 225, 225, 225, 225, 225,
+225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 226, 226,
+226, 226, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 228, 228,
+228, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 230, 230, 230,
+230, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 232, 232, 232,
+232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232,
+233, 233, 233, 233, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 235,
+235, 235, 235, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236,
+236, 236, 236, 236, 236, 236, 237, 237, 237, 237, 238, 238, 238, 238, 238, 238,
+238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238,
+238, 238, 238, 238, 238, 239, 239, 239, 239, 240, 240, 240, 240, 240, 240, 240,
+240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
+240, 240, 240, 240, 241, 241, 241, 241, 242, 242, 242, 242, 242, 242, 242, 242,
+242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242,
+242, 242, 243, 243, 243, 243, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244,
+244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244,
+244, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246,
+246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246,
+246, 246, 246, 246, 246, 246, 246, 247, 247, 247, 247, 248, 248, 248, 248, 248,
+248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
+248, 248, 248, 248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 250, 250,
+250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
+250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
+250, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 252, 252,
+252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252,
+252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252,
+252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252,
+252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253,
+253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253,
+253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253,
+253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253,
+253, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
new file mode 100644
index 0000000..e0096e0
--- /dev/null
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -0,0 +1,2241 @@
+/*
+ * isp.c
+ *
+ * TI OMAP3 ISP - Core
+ *
+ * Copyright (C) 2006-2010 Nokia Corporation
+ * Copyright (C) 2007-2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * Contributors:
+ *	Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	Sakari Ailus <sakari.ailus@iki.fi>
+ *	David Cohen <dacohen@gmail.com>
+ *	Stanimir Varbanov <svarbanov@mm-sol.com>
+ *	Vimarsh Zutshi <vimarsh.zutshi@gmail.com>
+ *	Tuukka Toivonen <tuukkat76@gmail.com>
+ *	Sergio Aguirre <saaguirre@ti.com>
+ *	Antti Koskipaa <akoskipa@gmail.com>
+ *	Ivan T. Ivanov <iivanov@mm-sol.com>
+ *	RaniSuneela <r-m@ti.com>
+ *	Atanas Filipov <afilipov@mm-sol.com>
+ *	Gjorgji Rosikopulos <grosikopulos@mm-sol.com>
+ *	Hiroshi DOYU <hiroshi.doyu@nokia.com>
+ *	Nayden Kanchev <nkanchev@mm-sol.com>
+ *	Phil Carmody <ext-phil.2.carmody@nokia.com>
+ *	Artem Bityutskiy <artem.bityutskiy@nokia.com>
+ *	Dominic Curran <dcurran@ti.com>
+ *	Ilkka Myllyperkio <ilkka.myllyperkio@sofica.fi>
+ *	Pallavi Kulkarni <p-kulkarni@ti.com>
+ *	Vaibhav Hiremath <hvaibhav@ti.com>
+ *	Mohit Jalori <mjalori@ti.com>
+ *	Sameer Venkatraman <sameerv@ti.com>
+ *	Senthilvadivu Guruswamy <svadivu@ti.com>
+ *	Thara Gopinath <thara@ti.com>
+ *	Toni Leinonen <toni.leinonen@nokia.com>
+ *	Troy Laramy <t-laramy@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <asm/cacheflush.h>
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispccdc.h"
+#include "isppreview.h"
+#include "ispresizer.h"
+#include "ispcsi2.h"
+#include "ispccp2.h"
+#include "isph3a.h"
+#include "isphist.h"
+
+static unsigned int autoidle;
+module_param(autoidle, int, 0444);
+MODULE_PARM_DESC(autoidle, "Enable OMAP3ISP AUTOIDLE support");
+
+static void isp_save_ctx(struct isp_device *isp);
+
+static void isp_restore_ctx(struct isp_device *isp);
+
+static const struct isp_res_mapping isp_res_maps[] = {
+	{
+		.isp_rev = ISP_REVISION_2_0,
+		.map = 1 << OMAP3_ISP_IOMEM_MAIN |
+		       1 << OMAP3_ISP_IOMEM_CCP2 |
+		       1 << OMAP3_ISP_IOMEM_CCDC |
+		       1 << OMAP3_ISP_IOMEM_HIST |
+		       1 << OMAP3_ISP_IOMEM_H3A |
+		       1 << OMAP3_ISP_IOMEM_PREV |
+		       1 << OMAP3_ISP_IOMEM_RESZ |
+		       1 << OMAP3_ISP_IOMEM_SBL |
+		       1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 |
+		       1 << OMAP3_ISP_IOMEM_CSIPHY2,
+	},
+	{
+		.isp_rev = ISP_REVISION_15_0,
+		.map = 1 << OMAP3_ISP_IOMEM_MAIN |
+		       1 << OMAP3_ISP_IOMEM_CCP2 |
+		       1 << OMAP3_ISP_IOMEM_CCDC |
+		       1 << OMAP3_ISP_IOMEM_HIST |
+		       1 << OMAP3_ISP_IOMEM_H3A |
+		       1 << OMAP3_ISP_IOMEM_PREV |
+		       1 << OMAP3_ISP_IOMEM_RESZ |
+		       1 << OMAP3_ISP_IOMEM_SBL |
+		       1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 |
+		       1 << OMAP3_ISP_IOMEM_CSIPHY2 |
+		       1 << OMAP3_ISP_IOMEM_CSI2A_REGS2 |
+		       1 << OMAP3_ISP_IOMEM_CSI2C_REGS1 |
+		       1 << OMAP3_ISP_IOMEM_CSIPHY1 |
+		       1 << OMAP3_ISP_IOMEM_CSI2C_REGS2,
+	},
+};
+
+/* Structure for saving/restoring ISP module registers */
+static struct isp_reg isp_reg_list[] = {
+	{OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG, 0},
+	{OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, 0},
+	{OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, 0},
+	{0, ISP_TOK_TERM, 0}
+};
+
+/*
+ * omap3isp_flush - Post pending L3 bus writes by doing a register readback
+ * @isp: OMAP3 ISP device
+ *
+ * In order to force posting of pending writes, we need to write and
+ * readback the same register, in this case the revision register.
+ *
+ * See this link for reference:
+ *   http://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html
+ */
+void omap3isp_flush(struct isp_device *isp)
+{
+	isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
+	isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
+}
+
+/*
+ * isp_enable_interrupts - Enable ISP interrupts.
+ * @isp: OMAP3 ISP device
+ */
+static void isp_enable_interrupts(struct isp_device *isp)
+{
+	static const u32 irq = IRQ0ENABLE_CSIA_IRQ
+			     | IRQ0ENABLE_CSIB_IRQ
+			     | IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ
+			     | IRQ0ENABLE_CCDC_LSC_DONE_IRQ
+			     | IRQ0ENABLE_CCDC_VD0_IRQ
+			     | IRQ0ENABLE_CCDC_VD1_IRQ
+			     | IRQ0ENABLE_HS_VS_IRQ
+			     | IRQ0ENABLE_HIST_DONE_IRQ
+			     | IRQ0ENABLE_H3A_AWB_DONE_IRQ
+			     | IRQ0ENABLE_H3A_AF_DONE_IRQ
+			     | IRQ0ENABLE_PRV_DONE_IRQ
+			     | IRQ0ENABLE_RSZ_DONE_IRQ;
+
+	isp_reg_writel(isp, irq, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+	isp_reg_writel(isp, irq, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
+}
+
+/*
+ * isp_disable_interrupts - Disable ISP interrupts.
+ * @isp: OMAP3 ISP device
+ */
+static void isp_disable_interrupts(struct isp_device *isp)
+{
+	isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
+}
+
+/**
+ * isp_set_xclk - Configures the specified cam_xclk to the desired frequency.
+ * @isp: OMAP3 ISP device
+ * @xclk: Desired frequency of the clock in Hz. 0 = stable low, 1 is stable high
+ * @xclksel: XCLK to configure (0 = A, 1 = B).
+ *
+ * Configures the specified MCLK divisor in the ISP timing control register
+ * (TCTRL_CTRL) to generate the desired xclk clock value.
+ *
+ * Divisor = cam_mclk_hz / xclk
+ *
+ * Returns the final frequency that is actually being generated
+ **/
+static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel)
+{
+	u32 divisor;
+	u32 currentxclk;
+	unsigned long mclk_hz;
+
+	if (!omap3isp_get(isp))
+		return 0;
+
+	mclk_hz = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]);
+
+	if (xclk >= mclk_hz) {
+		divisor = ISPTCTRL_CTRL_DIV_BYPASS;
+		currentxclk = mclk_hz;
+	} else if (xclk >= 2) {
+		divisor = mclk_hz / xclk;
+		if (divisor >= ISPTCTRL_CTRL_DIV_BYPASS)
+			divisor = ISPTCTRL_CTRL_DIV_BYPASS - 1;
+		currentxclk = mclk_hz / divisor;
+	} else {
+		divisor = xclk;
+		currentxclk = 0;
+	}
+
+	switch (xclksel) {
+	case ISP_XCLK_A:
+		isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
+				ISPTCTRL_CTRL_DIVA_MASK,
+				divisor << ISPTCTRL_CTRL_DIVA_SHIFT);
+		dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n",
+			currentxclk);
+		break;
+	case ISP_XCLK_B:
+		isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
+				ISPTCTRL_CTRL_DIVB_MASK,
+				divisor << ISPTCTRL_CTRL_DIVB_SHIFT);
+		dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n",
+			currentxclk);
+		break;
+	case ISP_XCLK_NONE:
+	default:
+		omap3isp_put(isp);
+		dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested "
+			"xclk. Must be 0 (A) or 1 (B).\n");
+		return -EINVAL;
+	}
+
+	/* Do we go from stable whatever to clock? */
+	if (divisor >= 2 && isp->xclk_divisor[xclksel - 1] < 2)
+		omap3isp_get(isp);
+	/* Stopping the clock. */
+	else if (divisor < 2 && isp->xclk_divisor[xclksel - 1] >= 2)
+		omap3isp_put(isp);
+
+	isp->xclk_divisor[xclksel - 1] = divisor;
+
+	omap3isp_put(isp);
+
+	return currentxclk;
+}
+
+/*
+ * isp_core_init - ISP core settings
+ * @isp: OMAP3 ISP device
+ * @idle: Consider idle state.
+ *
+ * Set the power settings for the ISP and SBL bus and cConfigure the HS/VS
+ * interrupt source.
+ *
+ * We need to configure the HS/VS interrupt source before interrupts get
+ * enabled, as the sensor might be free-running and the ISP default setting
+ * (HS edge) would put an unnecessary burden on the CPU.
+ */
+static void isp_core_init(struct isp_device *isp, int idle)
+{
+	isp_reg_writel(isp,
+		       ((idle ? ISP_SYSCONFIG_MIDLEMODE_SMARTSTANDBY :
+				ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY) <<
+			ISP_SYSCONFIG_MIDLEMODE_SHIFT) |
+			((isp->revision == ISP_REVISION_15_0) ?
+			  ISP_SYSCONFIG_AUTOIDLE : 0),
+		       OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG);
+
+	isp_reg_writel(isp,
+		       (isp->autoidle ? ISPCTRL_SBL_AUTOIDLE : 0) |
+		       ISPCTRL_SYNC_DETECT_VSRISE,
+		       OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+}
+
+/*
+ * Configure the bridge and lane shifter. Valid inputs are
+ *
+ * CCDC_INPUT_PARALLEL: Parallel interface
+ * CCDC_INPUT_CSI2A: CSI2a receiver
+ * CCDC_INPUT_CCP2B: CCP2b receiver
+ * CCDC_INPUT_CSI2C: CSI2c receiver
+ *
+ * The bridge and lane shifter are configured according to the selected input
+ * and the ISP platform data.
+ */
+void omap3isp_configure_bridge(struct isp_device *isp,
+			       enum ccdc_input_entity input,
+			       const struct isp_parallel_platform_data *pdata,
+			       unsigned int shift, unsigned int bridge)
+{
+	u32 ispctrl_val;
+
+	ispctrl_val  = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+	ispctrl_val &= ~ISPCTRL_SHIFT_MASK;
+	ispctrl_val &= ~ISPCTRL_PAR_CLK_POL_INV;
+	ispctrl_val &= ~ISPCTRL_PAR_SER_CLK_SEL_MASK;
+	ispctrl_val &= ~ISPCTRL_PAR_BRIDGE_MASK;
+	ispctrl_val |= bridge;
+
+	switch (input) {
+	case CCDC_INPUT_PARALLEL:
+		ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL;
+		ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT;
+		shift += pdata->data_lane_shift * 2;
+		break;
+
+	case CCDC_INPUT_CSI2A:
+		ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIA;
+		break;
+
+	case CCDC_INPUT_CCP2B:
+		ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIB;
+		break;
+
+	case CCDC_INPUT_CSI2C:
+		ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIC;
+		break;
+
+	default:
+		return;
+	}
+
+	ispctrl_val |= ((shift/2) << ISPCTRL_SHIFT_SHIFT) & ISPCTRL_SHIFT_MASK;
+
+	isp_reg_writel(isp, ispctrl_val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+}
+
+void omap3isp_hist_dma_done(struct isp_device *isp)
+{
+	if (omap3isp_ccdc_busy(&isp->isp_ccdc) ||
+	    omap3isp_stat_pcr_busy(&isp->isp_hist)) {
+		/* Histogram cannot be enabled in this frame anymore */
+		atomic_set(&isp->isp_hist.buf_err, 1);
+		dev_dbg(isp->dev, "hist: Out of synchronization with "
+				  "CCDC. Ignoring next buffer.\n");
+	}
+}
+
+static inline void isp_isr_dbg(struct isp_device *isp, u32 irqstatus)
+{
+	static const char *name[] = {
+		"CSIA_IRQ",
+		"res1",
+		"res2",
+		"CSIB_LCM_IRQ",
+		"CSIB_IRQ",
+		"res5",
+		"res6",
+		"res7",
+		"CCDC_VD0_IRQ",
+		"CCDC_VD1_IRQ",
+		"CCDC_VD2_IRQ",
+		"CCDC_ERR_IRQ",
+		"H3A_AF_DONE_IRQ",
+		"H3A_AWB_DONE_IRQ",
+		"res14",
+		"res15",
+		"HIST_DONE_IRQ",
+		"CCDC_LSC_DONE",
+		"CCDC_LSC_PREFETCH_COMPLETED",
+		"CCDC_LSC_PREFETCH_ERROR",
+		"PRV_DONE_IRQ",
+		"CBUFF_IRQ",
+		"res22",
+		"res23",
+		"RSZ_DONE_IRQ",
+		"OVF_IRQ",
+		"res26",
+		"res27",
+		"MMU_ERR_IRQ",
+		"OCP_ERR_IRQ",
+		"SEC_ERR_IRQ",
+		"HS_VS_IRQ",
+	};
+	int i;
+
+	dev_dbg(isp->dev, "ISP IRQ: ");
+
+	for (i = 0; i < ARRAY_SIZE(name); i++) {
+		if ((1 << i) & irqstatus)
+			printk(KERN_CONT "%s ", name[i]);
+	}
+	printk(KERN_CONT "\n");
+}
+
+static void isp_isr_sbl(struct isp_device *isp)
+{
+	struct device *dev = isp->dev;
+	struct isp_pipeline *pipe;
+	u32 sbl_pcr;
+
+	/*
+	 * Handle shared buffer logic overflows for video buffers.
+	 * ISPSBL_PCR_CCDCPRV_2_RSZ_OVF can be safely ignored.
+	 */
+	sbl_pcr = isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR);
+	isp_reg_writel(isp, sbl_pcr, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR);
+	sbl_pcr &= ~ISPSBL_PCR_CCDCPRV_2_RSZ_OVF;
+
+	if (sbl_pcr)
+		dev_dbg(dev, "SBL overflow (PCR = 0x%08x)\n", sbl_pcr);
+
+	if (sbl_pcr & ISPSBL_PCR_CSIB_WBL_OVF) {
+		pipe = to_isp_pipeline(&isp->isp_ccp2.subdev.entity);
+		if (pipe != NULL)
+			pipe->error = true;
+	}
+
+	if (sbl_pcr & ISPSBL_PCR_CSIA_WBL_OVF) {
+		pipe = to_isp_pipeline(&isp->isp_csi2a.subdev.entity);
+		if (pipe != NULL)
+			pipe->error = true;
+	}
+
+	if (sbl_pcr & ISPSBL_PCR_CCDC_WBL_OVF) {
+		pipe = to_isp_pipeline(&isp->isp_ccdc.subdev.entity);
+		if (pipe != NULL)
+			pipe->error = true;
+	}
+
+	if (sbl_pcr & ISPSBL_PCR_PRV_WBL_OVF) {
+		pipe = to_isp_pipeline(&isp->isp_prev.subdev.entity);
+		if (pipe != NULL)
+			pipe->error = true;
+	}
+
+	if (sbl_pcr & (ISPSBL_PCR_RSZ1_WBL_OVF
+		       | ISPSBL_PCR_RSZ2_WBL_OVF
+		       | ISPSBL_PCR_RSZ3_WBL_OVF
+		       | ISPSBL_PCR_RSZ4_WBL_OVF)) {
+		pipe = to_isp_pipeline(&isp->isp_res.subdev.entity);
+		if (pipe != NULL)
+			pipe->error = true;
+	}
+
+	if (sbl_pcr & ISPSBL_PCR_H3A_AF_WBL_OVF)
+		omap3isp_stat_sbl_overflow(&isp->isp_af);
+
+	if (sbl_pcr & ISPSBL_PCR_H3A_AEAWB_WBL_OVF)
+		omap3isp_stat_sbl_overflow(&isp->isp_aewb);
+}
+
+/*
+ * isp_isr - Interrupt Service Routine for Camera ISP module.
+ * @irq: Not used currently.
+ * @_isp: Pointer to the OMAP3 ISP device
+ *
+ * Handles the corresponding callback if plugged in.
+ *
+ * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the
+ * IRQ wasn't handled.
+ */
+static irqreturn_t isp_isr(int irq, void *_isp)
+{
+	static const u32 ccdc_events = IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ |
+				       IRQ0STATUS_CCDC_LSC_DONE_IRQ |
+				       IRQ0STATUS_CCDC_VD0_IRQ |
+				       IRQ0STATUS_CCDC_VD1_IRQ |
+				       IRQ0STATUS_HS_VS_IRQ;
+	struct isp_device *isp = _isp;
+	u32 irqstatus;
+
+	irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+	isp_reg_writel(isp, irqstatus, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+
+	isp_isr_sbl(isp);
+
+	if (irqstatus & IRQ0STATUS_CSIA_IRQ)
+		omap3isp_csi2_isr(&isp->isp_csi2a);
+
+	if (irqstatus & IRQ0STATUS_CSIB_IRQ)
+		omap3isp_ccp2_isr(&isp->isp_ccp2);
+
+	if (irqstatus & IRQ0STATUS_CCDC_VD0_IRQ) {
+		if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW)
+			omap3isp_preview_isr_frame_sync(&isp->isp_prev);
+		if (isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER)
+			omap3isp_resizer_isr_frame_sync(&isp->isp_res);
+		omap3isp_stat_isr_frame_sync(&isp->isp_aewb);
+		omap3isp_stat_isr_frame_sync(&isp->isp_af);
+		omap3isp_stat_isr_frame_sync(&isp->isp_hist);
+	}
+
+	if (irqstatus & ccdc_events)
+		omap3isp_ccdc_isr(&isp->isp_ccdc, irqstatus & ccdc_events);
+
+	if (irqstatus & IRQ0STATUS_PRV_DONE_IRQ) {
+		if (isp->isp_prev.output & PREVIEW_OUTPUT_RESIZER)
+			omap3isp_resizer_isr_frame_sync(&isp->isp_res);
+		omap3isp_preview_isr(&isp->isp_prev);
+	}
+
+	if (irqstatus & IRQ0STATUS_RSZ_DONE_IRQ)
+		omap3isp_resizer_isr(&isp->isp_res);
+
+	if (irqstatus & IRQ0STATUS_H3A_AWB_DONE_IRQ)
+		omap3isp_stat_isr(&isp->isp_aewb);
+
+	if (irqstatus & IRQ0STATUS_H3A_AF_DONE_IRQ)
+		omap3isp_stat_isr(&isp->isp_af);
+
+	if (irqstatus & IRQ0STATUS_HIST_DONE_IRQ)
+		omap3isp_stat_isr(&isp->isp_hist);
+
+	omap3isp_flush(isp);
+
+#if defined(DEBUG) && defined(ISP_ISR_DEBUG)
+	isp_isr_dbg(isp, irqstatus);
+#endif
+
+	return IRQ_HANDLED;
+}
+
+/* -----------------------------------------------------------------------------
+ * Pipeline power management
+ *
+ * Entities must be powered up when part of a pipeline that contains at least
+ * one open video device node.
+ *
+ * To achieve this use the entity use_count field to track the number of users.
+ * For entities corresponding to video device nodes the use_count field stores
+ * the users count of the node. For entities corresponding to subdevs the
+ * use_count field stores the total number of users of all video device nodes
+ * in the pipeline.
+ *
+ * The omap3isp_pipeline_pm_use() function must be called in the open() and
+ * close() handlers of video device nodes. It increments or decrements the use
+ * count of all subdev entities in the pipeline.
+ *
+ * To react to link management on powered pipelines, the link setup notification
+ * callback updates the use count of all entities in the source and sink sides
+ * of the link.
+ */
+
+/*
+ * isp_pipeline_pm_use_count - Count the number of users of a pipeline
+ * @entity: The entity
+ *
+ * Return the total number of users of all video device nodes in the pipeline.
+ */
+static int isp_pipeline_pm_use_count(struct media_entity *entity)
+{
+	struct media_entity_graph graph;
+	int use = 0;
+
+	media_entity_graph_walk_start(&graph, entity);
+
+	while ((entity = media_entity_graph_walk_next(&graph))) {
+		if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
+			use += entity->use_count;
+	}
+
+	return use;
+}
+
+/*
+ * isp_pipeline_pm_power_one - Apply power change to an entity
+ * @entity: The entity
+ * @change: Use count change
+ *
+ * Change the entity use count by @change. If the entity is a subdev update its
+ * power state by calling the core::s_power operation when the use count goes
+ * from 0 to != 0 or from != 0 to 0.
+ *
+ * Return 0 on success or a negative error code on failure.
+ */
+static int isp_pipeline_pm_power_one(struct media_entity *entity, int change)
+{
+	struct v4l2_subdev *subdev;
+	int ret;
+
+	subdev = media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV
+	       ? media_entity_to_v4l2_subdev(entity) : NULL;
+
+	if (entity->use_count == 0 && change > 0 && subdev != NULL) {
+		ret = v4l2_subdev_call(subdev, core, s_power, 1);
+		if (ret < 0 && ret != -ENOIOCTLCMD)
+			return ret;
+	}
+
+	entity->use_count += change;
+	WARN_ON(entity->use_count < 0);
+
+	if (entity->use_count == 0 && change < 0 && subdev != NULL)
+		v4l2_subdev_call(subdev, core, s_power, 0);
+
+	return 0;
+}
+
+/*
+ * isp_pipeline_pm_power - Apply power change to all entities in a pipeline
+ * @entity: The entity
+ * @change: Use count change
+ *
+ * Walk the pipeline to update the use count and the power state of all non-node
+ * entities.
+ *
+ * Return 0 on success or a negative error code on failure.
+ */
+static int isp_pipeline_pm_power(struct media_entity *entity, int change)
+{
+	struct media_entity_graph graph;
+	struct media_entity *first = entity;
+	int ret = 0;
+
+	if (!change)
+		return 0;
+
+	media_entity_graph_walk_start(&graph, entity);
+
+	while (!ret && (entity = media_entity_graph_walk_next(&graph)))
+		if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+			ret = isp_pipeline_pm_power_one(entity, change);
+
+	if (!ret)
+		return 0;
+
+	media_entity_graph_walk_start(&graph, first);
+
+	while ((first = media_entity_graph_walk_next(&graph))
+	       && first != entity)
+		if (media_entity_type(first) != MEDIA_ENT_T_DEVNODE)
+			isp_pipeline_pm_power_one(first, -change);
+
+	return ret;
+}
+
+/*
+ * omap3isp_pipeline_pm_use - Update the use count of an entity
+ * @entity: The entity
+ * @use: Use (1) or stop using (0) the entity
+ *
+ * Update the use count of all entities in the pipeline and power entities on or
+ * off accordingly.
+ *
+ * Return 0 on success or a negative error code on failure. Powering entities
+ * off is assumed to never fail. No failure can occur when the use parameter is
+ * set to 0.
+ */
+int omap3isp_pipeline_pm_use(struct media_entity *entity, int use)
+{
+	int change = use ? 1 : -1;
+	int ret;
+
+	mutex_lock(&entity->parent->graph_mutex);
+
+	/* Apply use count to node. */
+	entity->use_count += change;
+	WARN_ON(entity->use_count < 0);
+
+	/* Apply power change to connected non-nodes. */
+	ret = isp_pipeline_pm_power(entity, change);
+	if (ret < 0)
+		entity->use_count -= change;
+
+	mutex_unlock(&entity->parent->graph_mutex);
+
+	return ret;
+}
+
+/*
+ * isp_pipeline_link_notify - Link management notification callback
+ * @source: Pad at the start of the link
+ * @sink: Pad at the end of the link
+ * @flags: New link flags that will be applied
+ *
+ * React to link management on powered pipelines by updating the use count of
+ * all entities in the source and sink sides of the link. Entities are powered
+ * on or off accordingly.
+ *
+ * Return 0 on success or a negative error code on failure. Powering entities
+ * off is assumed to never fail. This function will not fail for disconnection
+ * events.
+ */
+static int isp_pipeline_link_notify(struct media_pad *source,
+				    struct media_pad *sink, u32 flags)
+{
+	int source_use = isp_pipeline_pm_use_count(source->entity);
+	int sink_use = isp_pipeline_pm_use_count(sink->entity);
+	int ret;
+
+	if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+		/* Powering off entities is assumed to never fail. */
+		isp_pipeline_pm_power(source->entity, -sink_use);
+		isp_pipeline_pm_power(sink->entity, -source_use);
+		return 0;
+	}
+
+	ret = isp_pipeline_pm_power(source->entity, sink_use);
+	if (ret < 0)
+		return ret;
+
+	ret = isp_pipeline_pm_power(sink->entity, source_use);
+	if (ret < 0)
+		isp_pipeline_pm_power(source->entity, -sink_use);
+
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Pipeline stream management
+ */
+
+/*
+ * isp_pipeline_enable - Enable streaming on a pipeline
+ * @pipe: ISP pipeline
+ * @mode: Stream mode (single shot or continuous)
+ *
+ * Walk the entities chain starting at the pipeline output video node and start
+ * all modules in the chain in the given mode.
+ *
+ * Return 0 if successful, or the return value of the failed video::s_stream
+ * operation otherwise.
+ */
+static int isp_pipeline_enable(struct isp_pipeline *pipe,
+			       enum isp_pipeline_stream_state mode)
+{
+	struct isp_device *isp = pipe->output->isp;
+	struct media_entity *entity;
+	struct media_pad *pad;
+	struct v4l2_subdev *subdev;
+	unsigned long flags;
+	int ret;
+
+	/* If the preview engine crashed it might not respond to read/write
+	 * operations on the L4 bus. This would result in a bus fault and a
+	 * kernel oops. Refuse to start streaming in that case. This check must
+	 * be performed before the loop below to avoid starting entities if the
+	 * pipeline won't start anyway (those entities would then likely fail to
+	 * stop, making the problem worse).
+	 */
+	if ((pipe->entities & isp->crashed) &
+	    (1U << isp->isp_prev.subdev.entity.id))
+		return -EIO;
+
+	spin_lock_irqsave(&pipe->lock, flags);
+	pipe->state &= ~(ISP_PIPELINE_IDLE_INPUT | ISP_PIPELINE_IDLE_OUTPUT);
+	spin_unlock_irqrestore(&pipe->lock, flags);
+
+	pipe->do_propagation = false;
+
+	entity = &pipe->output->video.entity;
+	while (1) {
+		pad = &entity->pads[0];
+		if (!(pad->flags & MEDIA_PAD_FL_SINK))
+			break;
+
+		pad = media_entity_remote_source(pad);
+		if (pad == NULL ||
+		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+			break;
+
+		entity = pad->entity;
+		subdev = media_entity_to_v4l2_subdev(entity);
+
+		ret = v4l2_subdev_call(subdev, video, s_stream, mode);
+		if (ret < 0 && ret != -ENOIOCTLCMD)
+			return ret;
+
+		if (subdev == &isp->isp_ccdc.subdev) {
+			v4l2_subdev_call(&isp->isp_aewb.subdev, video,
+					s_stream, mode);
+			v4l2_subdev_call(&isp->isp_af.subdev, video,
+					s_stream, mode);
+			v4l2_subdev_call(&isp->isp_hist.subdev, video,
+					s_stream, mode);
+			pipe->do_propagation = true;
+		}
+	}
+
+	return 0;
+}
+
+static int isp_pipeline_wait_resizer(struct isp_device *isp)
+{
+	return omap3isp_resizer_busy(&isp->isp_res);
+}
+
+static int isp_pipeline_wait_preview(struct isp_device *isp)
+{
+	return omap3isp_preview_busy(&isp->isp_prev);
+}
+
+static int isp_pipeline_wait_ccdc(struct isp_device *isp)
+{
+	return omap3isp_stat_busy(&isp->isp_af)
+	    || omap3isp_stat_busy(&isp->isp_aewb)
+	    || omap3isp_stat_busy(&isp->isp_hist)
+	    || omap3isp_ccdc_busy(&isp->isp_ccdc);
+}
+
+#define ISP_STOP_TIMEOUT	msecs_to_jiffies(1000)
+
+static int isp_pipeline_wait(struct isp_device *isp,
+			     int(*busy)(struct isp_device *isp))
+{
+	unsigned long timeout = jiffies + ISP_STOP_TIMEOUT;
+
+	while (!time_after(jiffies, timeout)) {
+		if (!busy(isp))
+			return 0;
+	}
+
+	return 1;
+}
+
+/*
+ * isp_pipeline_disable - Disable streaming on a pipeline
+ * @pipe: ISP pipeline
+ *
+ * Walk the entities chain starting at the pipeline output video node and stop
+ * all modules in the chain. Wait synchronously for the modules to be stopped if
+ * necessary.
+ *
+ * Return 0 if all modules have been properly stopped, or -ETIMEDOUT if a module
+ * can't be stopped (in which case a software reset of the ISP is probably
+ * necessary).
+ */
+static int isp_pipeline_disable(struct isp_pipeline *pipe)
+{
+	struct isp_device *isp = pipe->output->isp;
+	struct media_entity *entity;
+	struct media_pad *pad;
+	struct v4l2_subdev *subdev;
+	int failure = 0;
+	int ret;
+
+	/*
+	 * We need to stop all the modules after CCDC first or they'll
+	 * never stop since they may not get a full frame from CCDC.
+	 */
+	entity = &pipe->output->video.entity;
+	while (1) {
+		pad = &entity->pads[0];
+		if (!(pad->flags & MEDIA_PAD_FL_SINK))
+			break;
+
+		pad = media_entity_remote_source(pad);
+		if (pad == NULL ||
+		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+			break;
+
+		entity = pad->entity;
+		subdev = media_entity_to_v4l2_subdev(entity);
+
+		if (subdev == &isp->isp_ccdc.subdev) {
+			v4l2_subdev_call(&isp->isp_aewb.subdev,
+					 video, s_stream, 0);
+			v4l2_subdev_call(&isp->isp_af.subdev,
+					 video, s_stream, 0);
+			v4l2_subdev_call(&isp->isp_hist.subdev,
+					 video, s_stream, 0);
+		}
+
+		v4l2_subdev_call(subdev, video, s_stream, 0);
+
+		if (subdev == &isp->isp_res.subdev)
+			ret = isp_pipeline_wait(isp, isp_pipeline_wait_resizer);
+		else if (subdev == &isp->isp_prev.subdev)
+			ret = isp_pipeline_wait(isp, isp_pipeline_wait_preview);
+		else if (subdev == &isp->isp_ccdc.subdev)
+			ret = isp_pipeline_wait(isp, isp_pipeline_wait_ccdc);
+		else
+			ret = 0;
+
+		if (ret) {
+			dev_info(isp->dev, "Unable to stop %s\n", subdev->name);
+			/* If the entity failed to stopped, assume it has
+			 * crashed. Mark it as such, the ISP will be reset when
+			 * applications will release it.
+			 */
+			isp->crashed |= 1U << subdev->entity.id;
+			failure = -ETIMEDOUT;
+		}
+	}
+
+	return failure;
+}
+
+/*
+ * omap3isp_pipeline_set_stream - Enable/disable streaming on a pipeline
+ * @pipe: ISP pipeline
+ * @state: Stream state (stopped, single shot or continuous)
+ *
+ * Set the pipeline to the given stream state. Pipelines can be started in
+ * single-shot or continuous mode.
+ *
+ * Return 0 if successful, or the return value of the failed video::s_stream
+ * operation otherwise. The pipeline state is not updated when the operation
+ * fails, except when stopping the pipeline.
+ */
+int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
+				 enum isp_pipeline_stream_state state)
+{
+	int ret;
+
+	if (state == ISP_PIPELINE_STREAM_STOPPED)
+		ret = isp_pipeline_disable(pipe);
+	else
+		ret = isp_pipeline_enable(pipe, state);
+
+	if (ret == 0 || state == ISP_PIPELINE_STREAM_STOPPED)
+		pipe->stream_state = state;
+
+	return ret;
+}
+
+/*
+ * isp_pipeline_resume - Resume streaming on a pipeline
+ * @pipe: ISP pipeline
+ *
+ * Resume video output and input and re-enable pipeline.
+ */
+static void isp_pipeline_resume(struct isp_pipeline *pipe)
+{
+	int singleshot = pipe->stream_state == ISP_PIPELINE_STREAM_SINGLESHOT;
+
+	omap3isp_video_resume(pipe->output, !singleshot);
+	if (singleshot)
+		omap3isp_video_resume(pipe->input, 0);
+	isp_pipeline_enable(pipe, pipe->stream_state);
+}
+
+/*
+ * isp_pipeline_suspend - Suspend streaming on a pipeline
+ * @pipe: ISP pipeline
+ *
+ * Suspend pipeline.
+ */
+static void isp_pipeline_suspend(struct isp_pipeline *pipe)
+{
+	isp_pipeline_disable(pipe);
+}
+
+/*
+ * isp_pipeline_is_last - Verify if entity has an enabled link to the output
+ * 			  video node
+ * @me: ISP module's media entity
+ *
+ * Returns 1 if the entity has an enabled link to the output video node or 0
+ * otherwise. It's true only while pipeline can have no more than one output
+ * node.
+ */
+static int isp_pipeline_is_last(struct media_entity *me)
+{
+	struct isp_pipeline *pipe;
+	struct media_pad *pad;
+
+	if (!me->pipe)
+		return 0;
+	pipe = to_isp_pipeline(me);
+	if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED)
+		return 0;
+	pad = media_entity_remote_source(&pipe->output->pad);
+	return pad->entity == me;
+}
+
+/*
+ * isp_suspend_module_pipeline - Suspend pipeline to which belongs the module
+ * @me: ISP module's media entity
+ *
+ * Suspend the whole pipeline if module's entity has an enabled link to the
+ * output video node. It works only while pipeline can have no more than one
+ * output node.
+ */
+static void isp_suspend_module_pipeline(struct media_entity *me)
+{
+	if (isp_pipeline_is_last(me))
+		isp_pipeline_suspend(to_isp_pipeline(me));
+}
+
+/*
+ * isp_resume_module_pipeline - Resume pipeline to which belongs the module
+ * @me: ISP module's media entity
+ *
+ * Resume the whole pipeline if module's entity has an enabled link to the
+ * output video node. It works only while pipeline can have no more than one
+ * output node.
+ */
+static void isp_resume_module_pipeline(struct media_entity *me)
+{
+	if (isp_pipeline_is_last(me))
+		isp_pipeline_resume(to_isp_pipeline(me));
+}
+
+/*
+ * isp_suspend_modules - Suspend ISP submodules.
+ * @isp: OMAP3 ISP device
+ *
+ * Returns 0 if suspend left in idle state all the submodules properly,
+ * or returns 1 if a general Reset is required to suspend the submodules.
+ */
+static int isp_suspend_modules(struct isp_device *isp)
+{
+	unsigned long timeout;
+
+	omap3isp_stat_suspend(&isp->isp_aewb);
+	omap3isp_stat_suspend(&isp->isp_af);
+	omap3isp_stat_suspend(&isp->isp_hist);
+	isp_suspend_module_pipeline(&isp->isp_res.subdev.entity);
+	isp_suspend_module_pipeline(&isp->isp_prev.subdev.entity);
+	isp_suspend_module_pipeline(&isp->isp_ccdc.subdev.entity);
+	isp_suspend_module_pipeline(&isp->isp_csi2a.subdev.entity);
+	isp_suspend_module_pipeline(&isp->isp_ccp2.subdev.entity);
+
+	timeout = jiffies + ISP_STOP_TIMEOUT;
+	while (omap3isp_stat_busy(&isp->isp_af)
+	    || omap3isp_stat_busy(&isp->isp_aewb)
+	    || omap3isp_stat_busy(&isp->isp_hist)
+	    || omap3isp_preview_busy(&isp->isp_prev)
+	    || omap3isp_resizer_busy(&isp->isp_res)
+	    || omap3isp_ccdc_busy(&isp->isp_ccdc)) {
+		if (time_after(jiffies, timeout)) {
+			dev_info(isp->dev, "can't stop modules.\n");
+			return 1;
+		}
+		msleep(1);
+	}
+
+	return 0;
+}
+
+/*
+ * isp_resume_modules - Resume ISP submodules.
+ * @isp: OMAP3 ISP device
+ */
+static void isp_resume_modules(struct isp_device *isp)
+{
+	omap3isp_stat_resume(&isp->isp_aewb);
+	omap3isp_stat_resume(&isp->isp_af);
+	omap3isp_stat_resume(&isp->isp_hist);
+	isp_resume_module_pipeline(&isp->isp_res.subdev.entity);
+	isp_resume_module_pipeline(&isp->isp_prev.subdev.entity);
+	isp_resume_module_pipeline(&isp->isp_ccdc.subdev.entity);
+	isp_resume_module_pipeline(&isp->isp_csi2a.subdev.entity);
+	isp_resume_module_pipeline(&isp->isp_ccp2.subdev.entity);
+}
+
+/*
+ * isp_reset - Reset ISP with a timeout wait for idle.
+ * @isp: OMAP3 ISP device
+ */
+static int isp_reset(struct isp_device *isp)
+{
+	unsigned long timeout = 0;
+
+	isp_reg_writel(isp,
+		       isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG)
+		       | ISP_SYSCONFIG_SOFTRESET,
+		       OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG);
+	while (!(isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN,
+			       ISP_SYSSTATUS) & 0x1)) {
+		if (timeout++ > 10000) {
+			dev_alert(isp->dev, "cannot reset ISP\n");
+			return -ETIMEDOUT;
+		}
+		udelay(1);
+	}
+
+	isp->crashed = 0;
+	return 0;
+}
+
+/*
+ * isp_save_context - Saves the values of the ISP module registers.
+ * @isp: OMAP3 ISP device
+ * @reg_list: Structure containing pairs of register address and value to
+ *            modify on OMAP.
+ */
+static void
+isp_save_context(struct isp_device *isp, struct isp_reg *reg_list)
+{
+	struct isp_reg *next = reg_list;
+
+	for (; next->reg != ISP_TOK_TERM; next++)
+		next->val = isp_reg_readl(isp, next->mmio_range, next->reg);
+}
+
+/*
+ * isp_restore_context - Restores the values of the ISP module registers.
+ * @isp: OMAP3 ISP device
+ * @reg_list: Structure containing pairs of register address and value to
+ *            modify on OMAP.
+ */
+static void
+isp_restore_context(struct isp_device *isp, struct isp_reg *reg_list)
+{
+	struct isp_reg *next = reg_list;
+
+	for (; next->reg != ISP_TOK_TERM; next++)
+		isp_reg_writel(isp, next->val, next->mmio_range, next->reg);
+}
+
+/*
+ * isp_save_ctx - Saves ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context.
+ * @isp: OMAP3 ISP device
+ *
+ * Routine for saving the context of each module in the ISP.
+ * CCDC, HIST, H3A, PREV, RESZ and MMU.
+ */
+static void isp_save_ctx(struct isp_device *isp)
+{
+	isp_save_context(isp, isp_reg_list);
+	omap_iommu_save_ctx(isp->dev);
+}
+
+/*
+ * isp_restore_ctx - Restores ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context.
+ * @isp: OMAP3 ISP device
+ *
+ * Routine for restoring the context of each module in the ISP.
+ * CCDC, HIST, H3A, PREV, RESZ and MMU.
+ */
+static void isp_restore_ctx(struct isp_device *isp)
+{
+	isp_restore_context(isp, isp_reg_list);
+	omap_iommu_restore_ctx(isp->dev);
+	omap3isp_ccdc_restore_context(isp);
+	omap3isp_preview_restore_context(isp);
+}
+
+/* -----------------------------------------------------------------------------
+ * SBL resources management
+ */
+#define OMAP3_ISP_SBL_READ	(OMAP3_ISP_SBL_CSI1_READ | \
+				 OMAP3_ISP_SBL_CCDC_LSC_READ | \
+				 OMAP3_ISP_SBL_PREVIEW_READ | \
+				 OMAP3_ISP_SBL_RESIZER_READ)
+#define OMAP3_ISP_SBL_WRITE	(OMAP3_ISP_SBL_CSI1_WRITE | \
+				 OMAP3_ISP_SBL_CSI2A_WRITE | \
+				 OMAP3_ISP_SBL_CSI2C_WRITE | \
+				 OMAP3_ISP_SBL_CCDC_WRITE | \
+				 OMAP3_ISP_SBL_PREVIEW_WRITE)
+
+void omap3isp_sbl_enable(struct isp_device *isp, enum isp_sbl_resource res)
+{
+	u32 sbl = 0;
+
+	isp->sbl_resources |= res;
+
+	if (isp->sbl_resources & OMAP3_ISP_SBL_CSI1_READ)
+		sbl |= ISPCTRL_SBL_SHARED_RPORTA;
+
+	if (isp->sbl_resources & OMAP3_ISP_SBL_CCDC_LSC_READ)
+		sbl |= ISPCTRL_SBL_SHARED_RPORTB;
+
+	if (isp->sbl_resources & OMAP3_ISP_SBL_CSI2C_WRITE)
+		sbl |= ISPCTRL_SBL_SHARED_WPORTC;
+
+	if (isp->sbl_resources & OMAP3_ISP_SBL_RESIZER_WRITE)
+		sbl |= ISPCTRL_SBL_WR0_RAM_EN;
+
+	if (isp->sbl_resources & OMAP3_ISP_SBL_WRITE)
+		sbl |= ISPCTRL_SBL_WR1_RAM_EN;
+
+	if (isp->sbl_resources & OMAP3_ISP_SBL_READ)
+		sbl |= ISPCTRL_SBL_RD_RAM_EN;
+
+	isp_reg_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, sbl);
+}
+
+void omap3isp_sbl_disable(struct isp_device *isp, enum isp_sbl_resource res)
+{
+	u32 sbl = 0;
+
+	isp->sbl_resources &= ~res;
+
+	if (!(isp->sbl_resources & OMAP3_ISP_SBL_CSI1_READ))
+		sbl |= ISPCTRL_SBL_SHARED_RPORTA;
+
+	if (!(isp->sbl_resources & OMAP3_ISP_SBL_CCDC_LSC_READ))
+		sbl |= ISPCTRL_SBL_SHARED_RPORTB;
+
+	if (!(isp->sbl_resources & OMAP3_ISP_SBL_CSI2C_WRITE))
+		sbl |= ISPCTRL_SBL_SHARED_WPORTC;
+
+	if (!(isp->sbl_resources & OMAP3_ISP_SBL_RESIZER_WRITE))
+		sbl |= ISPCTRL_SBL_WR0_RAM_EN;
+
+	if (!(isp->sbl_resources & OMAP3_ISP_SBL_WRITE))
+		sbl |= ISPCTRL_SBL_WR1_RAM_EN;
+
+	if (!(isp->sbl_resources & OMAP3_ISP_SBL_READ))
+		sbl |= ISPCTRL_SBL_RD_RAM_EN;
+
+	isp_reg_clr(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, sbl);
+}
+
+/*
+ * isp_module_sync_idle - Helper to sync module with its idle state
+ * @me: ISP submodule's media entity
+ * @wait: ISP submodule's wait queue for streamoff/interrupt synchronization
+ * @stopping: flag which tells module wants to stop
+ *
+ * This function checks if ISP submodule needs to wait for next interrupt. If
+ * yes, makes the caller to sleep while waiting for such event.
+ */
+int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
+			      atomic_t *stopping)
+{
+	struct isp_pipeline *pipe = to_isp_pipeline(me);
+
+	if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED ||
+	    (pipe->stream_state == ISP_PIPELINE_STREAM_SINGLESHOT &&
+	     !isp_pipeline_ready(pipe)))
+		return 0;
+
+	/*
+	 * atomic_set() doesn't include memory barrier on ARM platform for SMP
+	 * scenario. We'll call it here to avoid race conditions.
+	 */
+	atomic_set(stopping, 1);
+	smp_mb();
+
+	/*
+	 * If module is the last one, it's writing to memory. In this case,
+	 * it's necessary to check if the module is already paused due to
+	 * DMA queue underrun or if it has to wait for next interrupt to be
+	 * idle.
+	 * If it isn't the last one, the function won't sleep but *stopping
+	 * will still be set to warn next submodule caller's interrupt the
+	 * module wants to be idle.
+	 */
+	if (isp_pipeline_is_last(me)) {
+		struct isp_video *video = pipe->output;
+		unsigned long flags;
+		spin_lock_irqsave(&video->queue->irqlock, flags);
+		if (video->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) {
+			spin_unlock_irqrestore(&video->queue->irqlock, flags);
+			atomic_set(stopping, 0);
+			smp_mb();
+			return 0;
+		}
+		spin_unlock_irqrestore(&video->queue->irqlock, flags);
+		if (!wait_event_timeout(*wait, !atomic_read(stopping),
+					msecs_to_jiffies(1000))) {
+			atomic_set(stopping, 0);
+			smp_mb();
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * omap3isp_module_sync_is_stopped - Helper to verify if module was stopping
+ * @wait: ISP submodule's wait queue for streamoff/interrupt synchronization
+ * @stopping: flag which tells module wants to stop
+ *
+ * This function checks if ISP submodule was stopping. In case of yes, it
+ * notices the caller by setting stopping to 0 and waking up the wait queue.
+ * Returns 1 if it was stopping or 0 otherwise.
+ */
+int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait,
+				     atomic_t *stopping)
+{
+	if (atomic_cmpxchg(stopping, 1, 0)) {
+		wake_up(wait);
+		return 1;
+	}
+
+	return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * Clock management
+ */
+
+#define ISPCTRL_CLKS_MASK	(ISPCTRL_H3A_CLK_EN | \
+				 ISPCTRL_HIST_CLK_EN | \
+				 ISPCTRL_RSZ_CLK_EN | \
+				 (ISPCTRL_CCDC_CLK_EN | ISPCTRL_CCDC_RAM_EN) | \
+				 (ISPCTRL_PREV_CLK_EN | ISPCTRL_PREV_RAM_EN))
+
+static void __isp_subclk_update(struct isp_device *isp)
+{
+	u32 clk = 0;
+
+	/* AEWB and AF share the same clock. */
+	if (isp->subclk_resources &
+	    (OMAP3_ISP_SUBCLK_AEWB | OMAP3_ISP_SUBCLK_AF))
+		clk |= ISPCTRL_H3A_CLK_EN;
+
+	if (isp->subclk_resources & OMAP3_ISP_SUBCLK_HIST)
+		clk |= ISPCTRL_HIST_CLK_EN;
+
+	if (isp->subclk_resources & OMAP3_ISP_SUBCLK_RESIZER)
+		clk |= ISPCTRL_RSZ_CLK_EN;
+
+	/* NOTE: For CCDC & Preview submodules, we need to affect internal
+	 *       RAM as well.
+	 */
+	if (isp->subclk_resources & OMAP3_ISP_SUBCLK_CCDC)
+		clk |= ISPCTRL_CCDC_CLK_EN | ISPCTRL_CCDC_RAM_EN;
+
+	if (isp->subclk_resources & OMAP3_ISP_SUBCLK_PREVIEW)
+		clk |= ISPCTRL_PREV_CLK_EN | ISPCTRL_PREV_RAM_EN;
+
+	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
+			ISPCTRL_CLKS_MASK, clk);
+}
+
+void omap3isp_subclk_enable(struct isp_device *isp,
+			    enum isp_subclk_resource res)
+{
+	isp->subclk_resources |= res;
+
+	__isp_subclk_update(isp);
+}
+
+void omap3isp_subclk_disable(struct isp_device *isp,
+			     enum isp_subclk_resource res)
+{
+	isp->subclk_resources &= ~res;
+
+	__isp_subclk_update(isp);
+}
+
+/*
+ * isp_enable_clocks - Enable ISP clocks
+ * @isp: OMAP3 ISP device
+ *
+ * Return 0 if successful, or clk_enable return value if any of tthem fails.
+ */
+static int isp_enable_clocks(struct isp_device *isp)
+{
+	int r;
+	unsigned long rate;
+	int divisor;
+
+	/*
+	 * cam_mclk clock chain:
+	 *   dpll4 -> dpll4_m5 -> dpll4_m5x2 -> cam_mclk
+	 *
+	 * In OMAP3630 dpll4_m5x2 != 2 x dpll4_m5 but both are
+	 * set to the same value. Hence the rate set for dpll4_m5
+	 * has to be twice of what is set on OMAP3430 to get
+	 * the required value for cam_mclk
+	 */
+	if (cpu_is_omap3630())
+		divisor = 1;
+	else
+		divisor = 2;
+
+	r = clk_enable(isp->clock[ISP_CLK_CAM_ICK]);
+	if (r) {
+		dev_err(isp->dev, "clk_enable cam_ick failed\n");
+		goto out_clk_enable_ick;
+	}
+	r = clk_set_rate(isp->clock[ISP_CLK_DPLL4_M5_CK],
+			 CM_CAM_MCLK_HZ/divisor);
+	if (r) {
+		dev_err(isp->dev, "clk_set_rate for dpll4_m5_ck failed\n");
+		goto out_clk_enable_mclk;
+	}
+	r = clk_enable(isp->clock[ISP_CLK_CAM_MCLK]);
+	if (r) {
+		dev_err(isp->dev, "clk_enable cam_mclk failed\n");
+		goto out_clk_enable_mclk;
+	}
+	rate = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]);
+	if (rate != CM_CAM_MCLK_HZ)
+		dev_warn(isp->dev, "unexpected cam_mclk rate:\n"
+				   " expected : %d\n"
+				   " actual   : %ld\n", CM_CAM_MCLK_HZ, rate);
+	r = clk_enable(isp->clock[ISP_CLK_CSI2_FCK]);
+	if (r) {
+		dev_err(isp->dev, "clk_enable csi2_fck failed\n");
+		goto out_clk_enable_csi2_fclk;
+	}
+	return 0;
+
+out_clk_enable_csi2_fclk:
+	clk_disable(isp->clock[ISP_CLK_CAM_MCLK]);
+out_clk_enable_mclk:
+	clk_disable(isp->clock[ISP_CLK_CAM_ICK]);
+out_clk_enable_ick:
+	return r;
+}
+
+/*
+ * isp_disable_clocks - Disable ISP clocks
+ * @isp: OMAP3 ISP device
+ */
+static void isp_disable_clocks(struct isp_device *isp)
+{
+	clk_disable(isp->clock[ISP_CLK_CAM_ICK]);
+	clk_disable(isp->clock[ISP_CLK_CAM_MCLK]);
+	clk_disable(isp->clock[ISP_CLK_CSI2_FCK]);
+}
+
+static const char *isp_clocks[] = {
+	"cam_ick",
+	"cam_mclk",
+	"dpll4_m5_ck",
+	"csi2_96m_fck",
+	"l3_ick",
+};
+
+static void isp_put_clocks(struct isp_device *isp)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(isp_clocks); ++i) {
+		if (isp->clock[i]) {
+			clk_put(isp->clock[i]);
+			isp->clock[i] = NULL;
+		}
+	}
+}
+
+static int isp_get_clocks(struct isp_device *isp)
+{
+	struct clk *clk;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(isp_clocks); ++i) {
+		clk = clk_get(isp->dev, isp_clocks[i]);
+		if (IS_ERR(clk)) {
+			dev_err(isp->dev, "clk_get %s failed\n", isp_clocks[i]);
+			isp_put_clocks(isp);
+			return PTR_ERR(clk);
+		}
+
+		isp->clock[i] = clk;
+	}
+
+	return 0;
+}
+
+/*
+ * omap3isp_get - Acquire the ISP resource.
+ *
+ * Initializes the clocks for the first acquire.
+ *
+ * Increment the reference count on the ISP. If the first reference is taken,
+ * enable clocks and power-up all submodules.
+ *
+ * Return a pointer to the ISP device structure, or NULL if an error occurred.
+ */
+static struct isp_device *__omap3isp_get(struct isp_device *isp, bool irq)
+{
+	struct isp_device *__isp = isp;
+
+	if (isp == NULL)
+		return NULL;
+
+	mutex_lock(&isp->isp_mutex);
+	if (isp->ref_count > 0)
+		goto out;
+
+	if (isp_enable_clocks(isp) < 0) {
+		__isp = NULL;
+		goto out;
+	}
+
+	/* We don't want to restore context before saving it! */
+	if (isp->has_context)
+		isp_restore_ctx(isp);
+
+	if (irq)
+		isp_enable_interrupts(isp);
+
+out:
+	if (__isp != NULL)
+		isp->ref_count++;
+	mutex_unlock(&isp->isp_mutex);
+
+	return __isp;
+}
+
+struct isp_device *omap3isp_get(struct isp_device *isp)
+{
+	return __omap3isp_get(isp, true);
+}
+
+/*
+ * omap3isp_put - Release the ISP
+ *
+ * Decrement the reference count on the ISP. If the last reference is released,
+ * power-down all submodules, disable clocks and free temporary buffers.
+ */
+void omap3isp_put(struct isp_device *isp)
+{
+	if (isp == NULL)
+		return;
+
+	mutex_lock(&isp->isp_mutex);
+	BUG_ON(isp->ref_count == 0);
+	if (--isp->ref_count == 0) {
+		isp_disable_interrupts(isp);
+		if (isp->domain) {
+			isp_save_ctx(isp);
+			isp->has_context = 1;
+		}
+		/* Reset the ISP if an entity has failed to stop. This is the
+		 * only way to recover from such conditions.
+		 */
+		if (isp->crashed)
+			isp_reset(isp);
+		isp_disable_clocks(isp);
+	}
+	mutex_unlock(&isp->isp_mutex);
+}
+
+/* --------------------------------------------------------------------------
+ * Platform device driver
+ */
+
+/*
+ * omap3isp_print_status - Prints the values of the ISP Control Module registers
+ * @isp: OMAP3 ISP device
+ */
+#define ISP_PRINT_REGISTER(isp, name)\
+	dev_dbg(isp->dev, "###ISP " #name "=0x%08x\n", \
+		isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_##name))
+#define SBL_PRINT_REGISTER(isp, name)\
+	dev_dbg(isp->dev, "###SBL " #name "=0x%08x\n", \
+		isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_##name))
+
+void omap3isp_print_status(struct isp_device *isp)
+{
+	dev_dbg(isp->dev, "-------------ISP Register dump--------------\n");
+
+	ISP_PRINT_REGISTER(isp, SYSCONFIG);
+	ISP_PRINT_REGISTER(isp, SYSSTATUS);
+	ISP_PRINT_REGISTER(isp, IRQ0ENABLE);
+	ISP_PRINT_REGISTER(isp, IRQ0STATUS);
+	ISP_PRINT_REGISTER(isp, TCTRL_GRESET_LENGTH);
+	ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_REPLAY);
+	ISP_PRINT_REGISTER(isp, CTRL);
+	ISP_PRINT_REGISTER(isp, TCTRL_CTRL);
+	ISP_PRINT_REGISTER(isp, TCTRL_FRAME);
+	ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_DELAY);
+	ISP_PRINT_REGISTER(isp, TCTRL_STRB_DELAY);
+	ISP_PRINT_REGISTER(isp, TCTRL_SHUT_DELAY);
+	ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_LENGTH);
+	ISP_PRINT_REGISTER(isp, TCTRL_STRB_LENGTH);
+	ISP_PRINT_REGISTER(isp, TCTRL_SHUT_LENGTH);
+
+	SBL_PRINT_REGISTER(isp, PCR);
+	SBL_PRINT_REGISTER(isp, SDR_REQ_EXP);
+
+	dev_dbg(isp->dev, "--------------------------------------------\n");
+}
+
+#ifdef CONFIG_PM
+
+/*
+ * Power management support.
+ *
+ * As the ISP can't properly handle an input video stream interruption on a non
+ * frame boundary, the ISP pipelines need to be stopped before sensors get
+ * suspended. However, as suspending the sensors can require a running clock,
+ * which can be provided by the ISP, the ISP can't be completely suspended
+ * before the sensor.
+ *
+ * To solve this problem power management support is split into prepare/complete
+ * and suspend/resume operations. The pipelines are stopped in prepare() and the
+ * ISP clocks get disabled in suspend(). Similarly, the clocks are reenabled in
+ * resume(), and the the pipelines are restarted in complete().
+ *
+ * TODO: PM dependencies between the ISP and sensors are not modeled explicitly
+ * yet.
+ */
+static int isp_pm_prepare(struct device *dev)
+{
+	struct isp_device *isp = dev_get_drvdata(dev);
+	int reset;
+
+	WARN_ON(mutex_is_locked(&isp->isp_mutex));
+
+	if (isp->ref_count == 0)
+		return 0;
+
+	reset = isp_suspend_modules(isp);
+	isp_disable_interrupts(isp);
+	isp_save_ctx(isp);
+	if (reset)
+		isp_reset(isp);
+
+	return 0;
+}
+
+static int isp_pm_suspend(struct device *dev)
+{
+	struct isp_device *isp = dev_get_drvdata(dev);
+
+	WARN_ON(mutex_is_locked(&isp->isp_mutex));
+
+	if (isp->ref_count)
+		isp_disable_clocks(isp);
+
+	return 0;
+}
+
+static int isp_pm_resume(struct device *dev)
+{
+	struct isp_device *isp = dev_get_drvdata(dev);
+
+	if (isp->ref_count == 0)
+		return 0;
+
+	return isp_enable_clocks(isp);
+}
+
+static void isp_pm_complete(struct device *dev)
+{
+	struct isp_device *isp = dev_get_drvdata(dev);
+
+	if (isp->ref_count == 0)
+		return;
+
+	isp_restore_ctx(isp);
+	isp_enable_interrupts(isp);
+	isp_resume_modules(isp);
+}
+
+#else
+
+#define isp_pm_prepare	NULL
+#define isp_pm_suspend	NULL
+#define isp_pm_resume	NULL
+#define isp_pm_complete	NULL
+
+#endif /* CONFIG_PM */
+
+static void isp_unregister_entities(struct isp_device *isp)
+{
+	omap3isp_csi2_unregister_entities(&isp->isp_csi2a);
+	omap3isp_ccp2_unregister_entities(&isp->isp_ccp2);
+	omap3isp_ccdc_unregister_entities(&isp->isp_ccdc);
+	omap3isp_preview_unregister_entities(&isp->isp_prev);
+	omap3isp_resizer_unregister_entities(&isp->isp_res);
+	omap3isp_stat_unregister_entities(&isp->isp_aewb);
+	omap3isp_stat_unregister_entities(&isp->isp_af);
+	omap3isp_stat_unregister_entities(&isp->isp_hist);
+
+	v4l2_device_unregister(&isp->v4l2_dev);
+	media_device_unregister(&isp->media_dev);
+}
+
+/*
+ * isp_register_subdev_group - Register a group of subdevices
+ * @isp: OMAP3 ISP device
+ * @board_info: I2C subdevs board information array
+ *
+ * Register all I2C subdevices in the board_info array. The array must be
+ * terminated by a NULL entry, and the first entry must be the sensor.
+ *
+ * Return a pointer to the sensor media entity if it has been successfully
+ * registered, or NULL otherwise.
+ */
+static struct v4l2_subdev *
+isp_register_subdev_group(struct isp_device *isp,
+		     struct isp_subdev_i2c_board_info *board_info)
+{
+	struct v4l2_subdev *sensor = NULL;
+	unsigned int first;
+
+	if (board_info->board_info == NULL)
+		return NULL;
+
+	for (first = 1; board_info->board_info; ++board_info, first = 0) {
+		struct v4l2_subdev *subdev;
+		struct i2c_adapter *adapter;
+
+		adapter = i2c_get_adapter(board_info->i2c_adapter_id);
+		if (adapter == NULL) {
+			printk(KERN_ERR "%s: Unable to get I2C adapter %d for "
+				"device %s\n", __func__,
+				board_info->i2c_adapter_id,
+				board_info->board_info->type);
+			continue;
+		}
+
+		subdev = v4l2_i2c_new_subdev_board(&isp->v4l2_dev, adapter,
+				board_info->board_info, NULL);
+		if (subdev == NULL) {
+			printk(KERN_ERR "%s: Unable to register subdev %s\n",
+				__func__, board_info->board_info->type);
+			continue;
+		}
+
+		if (first)
+			sensor = subdev;
+	}
+
+	return sensor;
+}
+
+static int isp_register_entities(struct isp_device *isp)
+{
+	struct isp_platform_data *pdata = isp->pdata;
+	struct isp_v4l2_subdevs_group *subdevs;
+	int ret;
+
+	isp->media_dev.dev = isp->dev;
+	strlcpy(isp->media_dev.model, "TI OMAP3 ISP",
+		sizeof(isp->media_dev.model));
+	isp->media_dev.hw_revision = isp->revision;
+	isp->media_dev.link_notify = isp_pipeline_link_notify;
+	ret = media_device_register(&isp->media_dev);
+	if (ret < 0) {
+		printk(KERN_ERR "%s: Media device registration failed (%d)\n",
+			__func__, ret);
+		return ret;
+	}
+
+	isp->v4l2_dev.mdev = &isp->media_dev;
+	ret = v4l2_device_register(isp->dev, &isp->v4l2_dev);
+	if (ret < 0) {
+		printk(KERN_ERR "%s: V4L2 device registration failed (%d)\n",
+			__func__, ret);
+		goto done;
+	}
+
+	/* Register internal entities */
+	ret = omap3isp_ccp2_register_entities(&isp->isp_ccp2, &isp->v4l2_dev);
+	if (ret < 0)
+		goto done;
+
+	ret = omap3isp_csi2_register_entities(&isp->isp_csi2a, &isp->v4l2_dev);
+	if (ret < 0)
+		goto done;
+
+	ret = omap3isp_ccdc_register_entities(&isp->isp_ccdc, &isp->v4l2_dev);
+	if (ret < 0)
+		goto done;
+
+	ret = omap3isp_preview_register_entities(&isp->isp_prev,
+						 &isp->v4l2_dev);
+	if (ret < 0)
+		goto done;
+
+	ret = omap3isp_resizer_register_entities(&isp->isp_res, &isp->v4l2_dev);
+	if (ret < 0)
+		goto done;
+
+	ret = omap3isp_stat_register_entities(&isp->isp_aewb, &isp->v4l2_dev);
+	if (ret < 0)
+		goto done;
+
+	ret = omap3isp_stat_register_entities(&isp->isp_af, &isp->v4l2_dev);
+	if (ret < 0)
+		goto done;
+
+	ret = omap3isp_stat_register_entities(&isp->isp_hist, &isp->v4l2_dev);
+	if (ret < 0)
+		goto done;
+
+	/* Register external entities */
+	for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) {
+		struct v4l2_subdev *sensor;
+		struct media_entity *input;
+		unsigned int flags;
+		unsigned int pad;
+
+		sensor = isp_register_subdev_group(isp, subdevs->subdevs);
+		if (sensor == NULL)
+			continue;
+
+		sensor->host_priv = subdevs;
+
+		/* Connect the sensor to the correct interface module. Parallel
+		 * sensors are connected directly to the CCDC, while serial
+		 * sensors are connected to the CSI2a, CCP2b or CSI2c receiver
+		 * through CSIPHY1 or CSIPHY2.
+		 */
+		switch (subdevs->interface) {
+		case ISP_INTERFACE_PARALLEL:
+			input = &isp->isp_ccdc.subdev.entity;
+			pad = CCDC_PAD_SINK;
+			flags = 0;
+			break;
+
+		case ISP_INTERFACE_CSI2A_PHY2:
+			input = &isp->isp_csi2a.subdev.entity;
+			pad = CSI2_PAD_SINK;
+			flags = MEDIA_LNK_FL_IMMUTABLE
+			      | MEDIA_LNK_FL_ENABLED;
+			break;
+
+		case ISP_INTERFACE_CCP2B_PHY1:
+		case ISP_INTERFACE_CCP2B_PHY2:
+			input = &isp->isp_ccp2.subdev.entity;
+			pad = CCP2_PAD_SINK;
+			flags = 0;
+			break;
+
+		case ISP_INTERFACE_CSI2C_PHY1:
+			input = &isp->isp_csi2c.subdev.entity;
+			pad = CSI2_PAD_SINK;
+			flags = MEDIA_LNK_FL_IMMUTABLE
+			      | MEDIA_LNK_FL_ENABLED;
+			break;
+
+		default:
+			printk(KERN_ERR "%s: invalid interface type %u\n",
+			       __func__, subdevs->interface);
+			ret = -EINVAL;
+			goto done;
+		}
+
+		ret = media_entity_create_link(&sensor->entity, 0, input, pad,
+					       flags);
+		if (ret < 0)
+			goto done;
+	}
+
+	ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev);
+
+done:
+	if (ret < 0)
+		isp_unregister_entities(isp);
+
+	return ret;
+}
+
+static void isp_cleanup_modules(struct isp_device *isp)
+{
+	omap3isp_h3a_aewb_cleanup(isp);
+	omap3isp_h3a_af_cleanup(isp);
+	omap3isp_hist_cleanup(isp);
+	omap3isp_resizer_cleanup(isp);
+	omap3isp_preview_cleanup(isp);
+	omap3isp_ccdc_cleanup(isp);
+	omap3isp_ccp2_cleanup(isp);
+	omap3isp_csi2_cleanup(isp);
+}
+
+static int isp_initialize_modules(struct isp_device *isp)
+{
+	int ret;
+
+	ret = omap3isp_csiphy_init(isp);
+	if (ret < 0) {
+		dev_err(isp->dev, "CSI PHY initialization failed\n");
+		goto error_csiphy;
+	}
+
+	ret = omap3isp_csi2_init(isp);
+	if (ret < 0) {
+		dev_err(isp->dev, "CSI2 initialization failed\n");
+		goto error_csi2;
+	}
+
+	ret = omap3isp_ccp2_init(isp);
+	if (ret < 0) {
+		dev_err(isp->dev, "CCP2 initialization failed\n");
+		goto error_ccp2;
+	}
+
+	ret = omap3isp_ccdc_init(isp);
+	if (ret < 0) {
+		dev_err(isp->dev, "CCDC initialization failed\n");
+		goto error_ccdc;
+	}
+
+	ret = omap3isp_preview_init(isp);
+	if (ret < 0) {
+		dev_err(isp->dev, "Preview initialization failed\n");
+		goto error_preview;
+	}
+
+	ret = omap3isp_resizer_init(isp);
+	if (ret < 0) {
+		dev_err(isp->dev, "Resizer initialization failed\n");
+		goto error_resizer;
+	}
+
+	ret = omap3isp_hist_init(isp);
+	if (ret < 0) {
+		dev_err(isp->dev, "Histogram initialization failed\n");
+		goto error_hist;
+	}
+
+	ret = omap3isp_h3a_aewb_init(isp);
+	if (ret < 0) {
+		dev_err(isp->dev, "H3A AEWB initialization failed\n");
+		goto error_h3a_aewb;
+	}
+
+	ret = omap3isp_h3a_af_init(isp);
+	if (ret < 0) {
+		dev_err(isp->dev, "H3A AF initialization failed\n");
+		goto error_h3a_af;
+	}
+
+	/* Connect the submodules. */
+	ret = media_entity_create_link(
+			&isp->isp_csi2a.subdev.entity, CSI2_PAD_SOURCE,
+			&isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
+	if (ret < 0)
+		goto error_link;
+
+	ret = media_entity_create_link(
+			&isp->isp_ccp2.subdev.entity, CCP2_PAD_SOURCE,
+			&isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
+	if (ret < 0)
+		goto error_link;
+
+	ret = media_entity_create_link(
+			&isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+			&isp->isp_prev.subdev.entity, PREV_PAD_SINK, 0);
+	if (ret < 0)
+		goto error_link;
+
+	ret = media_entity_create_link(
+			&isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_OF,
+			&isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
+	if (ret < 0)
+		goto error_link;
+
+	ret = media_entity_create_link(
+			&isp->isp_prev.subdev.entity, PREV_PAD_SOURCE,
+			&isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
+	if (ret < 0)
+		goto error_link;
+
+	ret = media_entity_create_link(
+			&isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+			&isp->isp_aewb.subdev.entity, 0,
+			MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+	if (ret < 0)
+		goto error_link;
+
+	ret = media_entity_create_link(
+			&isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+			&isp->isp_af.subdev.entity, 0,
+			MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+	if (ret < 0)
+		goto error_link;
+
+	ret = media_entity_create_link(
+			&isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+			&isp->isp_hist.subdev.entity, 0,
+			MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+	if (ret < 0)
+		goto error_link;
+
+	return 0;
+
+error_link:
+	omap3isp_h3a_af_cleanup(isp);
+error_h3a_af:
+	omap3isp_h3a_aewb_cleanup(isp);
+error_h3a_aewb:
+	omap3isp_hist_cleanup(isp);
+error_hist:
+	omap3isp_resizer_cleanup(isp);
+error_resizer:
+	omap3isp_preview_cleanup(isp);
+error_preview:
+	omap3isp_ccdc_cleanup(isp);
+error_ccdc:
+	omap3isp_ccp2_cleanup(isp);
+error_ccp2:
+	omap3isp_csi2_cleanup(isp);
+error_csi2:
+error_csiphy:
+	return ret;
+}
+
+/*
+ * isp_remove - Remove ISP platform device
+ * @pdev: Pointer to ISP platform device
+ *
+ * Always returns 0.
+ */
+static int __devexit isp_remove(struct platform_device *pdev)
+{
+	struct isp_device *isp = platform_get_drvdata(pdev);
+	int i;
+
+	isp_unregister_entities(isp);
+	isp_cleanup_modules(isp);
+
+	__omap3isp_get(isp, false);
+	iommu_detach_device(isp->domain, &pdev->dev);
+	iommu_domain_free(isp->domain);
+	isp->domain = NULL;
+	omap3isp_put(isp);
+
+	free_irq(isp->irq_num, isp);
+	isp_put_clocks(isp);
+
+	for (i = 0; i < OMAP3_ISP_IOMEM_LAST; i++) {
+		if (isp->mmio_base[i]) {
+			iounmap(isp->mmio_base[i]);
+			isp->mmio_base[i] = NULL;
+		}
+
+		if (isp->mmio_base_phys[i]) {
+			release_mem_region(isp->mmio_base_phys[i],
+					   isp->mmio_size[i]);
+			isp->mmio_base_phys[i] = 0;
+		}
+	}
+
+	regulator_put(isp->isp_csiphy1.vdd);
+	regulator_put(isp->isp_csiphy2.vdd);
+	kfree(isp);
+
+	return 0;
+}
+
+static int isp_map_mem_resource(struct platform_device *pdev,
+				struct isp_device *isp,
+				enum isp_mem_resources res)
+{
+	struct resource *mem;
+
+	/* request the mem region for the camera registers */
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, res);
+	if (!mem) {
+		dev_err(isp->dev, "no mem resource?\n");
+		return -ENODEV;
+	}
+
+	if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
+		dev_err(isp->dev,
+			"cannot reserve camera register I/O region\n");
+		return -ENODEV;
+	}
+	isp->mmio_base_phys[res] = mem->start;
+	isp->mmio_size[res] = resource_size(mem);
+
+	/* map the region */
+	isp->mmio_base[res] = ioremap_nocache(isp->mmio_base_phys[res],
+					      isp->mmio_size[res]);
+	if (!isp->mmio_base[res]) {
+		dev_err(isp->dev, "cannot map camera register I/O region\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/*
+ * isp_probe - Probe ISP platform device
+ * @pdev: Pointer to ISP platform device
+ *
+ * Returns 0 if successful,
+ *   -ENOMEM if no memory available,
+ *   -ENODEV if no platform device resources found
+ *     or no space for remapping registers,
+ *   -EINVAL if couldn't install ISR,
+ *   or clk_get return error value.
+ */
+static int __devinit isp_probe(struct platform_device *pdev)
+{
+	struct isp_platform_data *pdata = pdev->dev.platform_data;
+	struct isp_device *isp;
+	int ret;
+	int i, m;
+
+	if (pdata == NULL)
+		return -EINVAL;
+
+	isp = kzalloc(sizeof(*isp), GFP_KERNEL);
+	if (!isp) {
+		dev_err(&pdev->dev, "could not allocate memory\n");
+		return -ENOMEM;
+	}
+
+	isp->autoidle = autoidle;
+	isp->platform_cb.set_xclk = isp_set_xclk;
+
+	mutex_init(&isp->isp_mutex);
+	spin_lock_init(&isp->stat_lock);
+
+	isp->dev = &pdev->dev;
+	isp->pdata = pdata;
+	isp->ref_count = 0;
+
+	isp->raw_dmamask = DMA_BIT_MASK(32);
+	isp->dev->dma_mask = &isp->raw_dmamask;
+	isp->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	platform_set_drvdata(pdev, isp);
+
+	/* Regulators */
+	isp->isp_csiphy1.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY1");
+	isp->isp_csiphy2.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY2");
+
+	/* Clocks */
+	ret = isp_map_mem_resource(pdev, isp, OMAP3_ISP_IOMEM_MAIN);
+	if (ret < 0)
+		goto error;
+
+	ret = isp_get_clocks(isp);
+	if (ret < 0)
+		goto error;
+
+	if (__omap3isp_get(isp, false) == NULL)
+		goto error;
+
+	ret = isp_reset(isp);
+	if (ret < 0)
+		goto error_isp;
+
+	/* Memory resources */
+	isp->revision = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
+	dev_info(isp->dev, "Revision %d.%d found\n",
+		 (isp->revision & 0xf0) >> 4, isp->revision & 0x0f);
+
+	for (m = 0; m < ARRAY_SIZE(isp_res_maps); m++)
+		if (isp->revision == isp_res_maps[m].isp_rev)
+			break;
+
+	if (m == ARRAY_SIZE(isp_res_maps)) {
+		dev_err(isp->dev, "No resource map found for ISP rev %d.%d\n",
+			(isp->revision & 0xf0) >> 4, isp->revision & 0xf);
+		ret = -ENODEV;
+		goto error_isp;
+	}
+
+	for (i = 1; i < OMAP3_ISP_IOMEM_LAST; i++) {
+		if (isp_res_maps[m].map & 1 << i) {
+			ret = isp_map_mem_resource(pdev, isp, i);
+			if (ret)
+				goto error_isp;
+		}
+	}
+
+	isp->domain = iommu_domain_alloc(pdev->dev.bus);
+	if (!isp->domain) {
+		dev_err(isp->dev, "can't alloc iommu domain\n");
+		ret = -ENOMEM;
+		goto error_isp;
+	}
+
+	ret = iommu_attach_device(isp->domain, &pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "can't attach iommu device: %d\n", ret);
+		goto free_domain;
+	}
+
+	/* Interrupt */
+	isp->irq_num = platform_get_irq(pdev, 0);
+	if (isp->irq_num <= 0) {
+		dev_err(isp->dev, "No IRQ resource\n");
+		ret = -ENODEV;
+		goto detach_dev;
+	}
+
+	if (request_irq(isp->irq_num, isp_isr, IRQF_SHARED, "OMAP3 ISP", isp)) {
+		dev_err(isp->dev, "Unable to request IRQ\n");
+		ret = -EINVAL;
+		goto detach_dev;
+	}
+
+	/* Entities */
+	ret = isp_initialize_modules(isp);
+	if (ret < 0)
+		goto error_irq;
+
+	ret = isp_register_entities(isp);
+	if (ret < 0)
+		goto error_modules;
+
+	isp_core_init(isp, 1);
+	omap3isp_put(isp);
+
+	return 0;
+
+error_modules:
+	isp_cleanup_modules(isp);
+error_irq:
+	free_irq(isp->irq_num, isp);
+detach_dev:
+	iommu_detach_device(isp->domain, &pdev->dev);
+free_domain:
+	iommu_domain_free(isp->domain);
+error_isp:
+	omap3isp_put(isp);
+error:
+	isp_put_clocks(isp);
+
+	for (i = 0; i < OMAP3_ISP_IOMEM_LAST; i++) {
+		if (isp->mmio_base[i]) {
+			iounmap(isp->mmio_base[i]);
+			isp->mmio_base[i] = NULL;
+		}
+
+		if (isp->mmio_base_phys[i]) {
+			release_mem_region(isp->mmio_base_phys[i],
+					   isp->mmio_size[i]);
+			isp->mmio_base_phys[i] = 0;
+		}
+	}
+	regulator_put(isp->isp_csiphy2.vdd);
+	regulator_put(isp->isp_csiphy1.vdd);
+	platform_set_drvdata(pdev, NULL);
+
+	mutex_destroy(&isp->isp_mutex);
+	kfree(isp);
+
+	return ret;
+}
+
+static const struct dev_pm_ops omap3isp_pm_ops = {
+	.prepare = isp_pm_prepare,
+	.suspend = isp_pm_suspend,
+	.resume = isp_pm_resume,
+	.complete = isp_pm_complete,
+};
+
+static struct platform_device_id omap3isp_id_table[] = {
+	{ "omap3isp", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, omap3isp_id_table);
+
+static struct platform_driver omap3isp_driver = {
+	.probe = isp_probe,
+	.remove = __devexit_p(isp_remove),
+	.id_table = omap3isp_id_table,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "omap3isp",
+		.pm	= &omap3isp_pm_ops,
+	},
+};
+
+module_platform_driver(omap3isp_driver);
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("TI OMAP3 ISP driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(ISP_VIDEO_DRIVER_VERSION);
diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h
new file mode 100644
index 0000000..8be7487
--- /dev/null
+++ b/drivers/media/platform/omap3isp/isp.h
@@ -0,0 +1,352 @@
+/*
+ * isp.h
+ *
+ * TI OMAP3 ISP - Core
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_CORE_H
+#define OMAP3_ISP_CORE_H
+
+#include <media/omap3isp.h>
+#include <media/v4l2-device.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/wait.h>
+#include <linux/iommu.h>
+#include <plat/iommu.h>
+#include <plat/iovmm.h>
+
+#include "ispstat.h"
+#include "ispccdc.h"
+#include "ispreg.h"
+#include "ispresizer.h"
+#include "isppreview.h"
+#include "ispcsiphy.h"
+#include "ispcsi2.h"
+#include "ispccp2.h"
+
+#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8)
+
+#define ISP_TOK_TERM		0xFFFFFFFF	/*
+						 * terminating token for ISP
+						 * modules reg list
+						 */
+#define to_isp_device(ptr_module)				\
+	container_of(ptr_module, struct isp_device, isp_##ptr_module)
+#define to_device(ptr_module)						\
+	(to_isp_device(ptr_module)->dev)
+
+enum isp_mem_resources {
+	OMAP3_ISP_IOMEM_MAIN,
+	OMAP3_ISP_IOMEM_CCP2,
+	OMAP3_ISP_IOMEM_CCDC,
+	OMAP3_ISP_IOMEM_HIST,
+	OMAP3_ISP_IOMEM_H3A,
+	OMAP3_ISP_IOMEM_PREV,
+	OMAP3_ISP_IOMEM_RESZ,
+	OMAP3_ISP_IOMEM_SBL,
+	OMAP3_ISP_IOMEM_CSI2A_REGS1,
+	OMAP3_ISP_IOMEM_CSIPHY2,
+	OMAP3_ISP_IOMEM_CSI2A_REGS2,
+	OMAP3_ISP_IOMEM_CSI2C_REGS1,
+	OMAP3_ISP_IOMEM_CSIPHY1,
+	OMAP3_ISP_IOMEM_CSI2C_REGS2,
+	OMAP3_ISP_IOMEM_LAST
+};
+
+enum isp_sbl_resource {
+	OMAP3_ISP_SBL_CSI1_READ		= 0x1,
+	OMAP3_ISP_SBL_CSI1_WRITE	= 0x2,
+	OMAP3_ISP_SBL_CSI2A_WRITE	= 0x4,
+	OMAP3_ISP_SBL_CSI2C_WRITE	= 0x8,
+	OMAP3_ISP_SBL_CCDC_LSC_READ	= 0x10,
+	OMAP3_ISP_SBL_CCDC_WRITE	= 0x20,
+	OMAP3_ISP_SBL_PREVIEW_READ	= 0x40,
+	OMAP3_ISP_SBL_PREVIEW_WRITE	= 0x80,
+	OMAP3_ISP_SBL_RESIZER_READ	= 0x100,
+	OMAP3_ISP_SBL_RESIZER_WRITE	= 0x200,
+};
+
+enum isp_subclk_resource {
+	OMAP3_ISP_SUBCLK_CCDC		= (1 << 0),
+	OMAP3_ISP_SUBCLK_AEWB		= (1 << 1),
+	OMAP3_ISP_SUBCLK_AF		= (1 << 2),
+	OMAP3_ISP_SUBCLK_HIST		= (1 << 3),
+	OMAP3_ISP_SUBCLK_PREVIEW	= (1 << 4),
+	OMAP3_ISP_SUBCLK_RESIZER	= (1 << 5),
+};
+
+/* ISP: OMAP 34xx ES 1.0 */
+#define ISP_REVISION_1_0		0x10
+/* ISP2: OMAP 34xx ES 2.0, 2.1 and 3.0 */
+#define ISP_REVISION_2_0		0x20
+/* ISP2P: OMAP 36xx */
+#define ISP_REVISION_15_0		0xF0
+
+/*
+ * struct isp_res_mapping - Map ISP io resources to ISP revision.
+ * @isp_rev: ISP_REVISION_x_x
+ * @map: bitmap for enum isp_mem_resources
+ */
+struct isp_res_mapping {
+	u32 isp_rev;
+	u32 map;
+};
+
+/*
+ * struct isp_reg - Structure for ISP register values.
+ * @reg: 32-bit Register address.
+ * @val: 32-bit Register value.
+ */
+struct isp_reg {
+	enum isp_mem_resources mmio_range;
+	u32 reg;
+	u32 val;
+};
+
+struct isp_platform_callback {
+	u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel);
+	int (*csiphy_config)(struct isp_csiphy *phy,
+			     struct isp_csiphy_dphy_cfg *dphy,
+			     struct isp_csiphy_lanes_cfg *lanes);
+};
+
+/*
+ * struct isp_device - ISP device structure.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @revision: Stores current ISP module revision.
+ * @irq_num: Currently used IRQ number.
+ * @mmio_base: Array with kernel base addresses for ioremapped ISP register
+ *             regions.
+ * @mmio_base_phys: Array with physical L4 bus addresses for ISP register
+ *                  regions.
+ * @mmio_size: Array with ISP register regions size in bytes.
+ * @raw_dmamask: Raw DMA mask
+ * @stat_lock: Spinlock for handling statistics
+ * @isp_mutex: Mutex for serializing requests to ISP.
+ * @crashed: Bitmask of crashed entities (indexed by entity ID)
+ * @has_context: Context has been saved at least once and can be restored.
+ * @ref_count: Reference count for handling multiple ISP requests.
+ * @cam_ick: Pointer to camera interface clock structure.
+ * @cam_mclk: Pointer to camera functional clock structure.
+ * @dpll4_m5_ck: Pointer to DPLL4 M5 clock structure.
+ * @csi2_fck: Pointer to camera CSI2 complexIO clock structure.
+ * @l3_ick: Pointer to OMAP3 L3 bus interface clock.
+ * @irq: Currently attached ISP ISR callbacks information structure.
+ * @isp_af: Pointer to current settings for ISP AutoFocus SCM.
+ * @isp_hist: Pointer to current settings for ISP Histogram SCM.
+ * @isp_h3a: Pointer to current settings for ISP Auto Exposure and
+ *           White Balance SCM.
+ * @isp_res: Pointer to current settings for ISP Resizer.
+ * @isp_prev: Pointer to current settings for ISP Preview.
+ * @isp_ccdc: Pointer to current settings for ISP CCDC.
+ * @iommu: Pointer to requested IOMMU instance for ISP.
+ * @platform_cb: ISP driver callback function pointers for platform code
+ *
+ * This structure is used to store the OMAP ISP Information.
+ */
+struct isp_device {
+	struct v4l2_device v4l2_dev;
+	struct media_device media_dev;
+	struct device *dev;
+	u32 revision;
+
+	/* platform HW resources */
+	struct isp_platform_data *pdata;
+	unsigned int irq_num;
+
+	void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST];
+	unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST];
+	resource_size_t mmio_size[OMAP3_ISP_IOMEM_LAST];
+
+	u64 raw_dmamask;
+
+	/* ISP Obj */
+	spinlock_t stat_lock;	/* common lock for statistic drivers */
+	struct mutex isp_mutex;	/* For handling ref_count field */
+	u32 crashed;
+	int has_context;
+	int ref_count;
+	unsigned int autoidle;
+	u32 xclk_divisor[2];	/* Two clocks, a and b. */
+#define ISP_CLK_CAM_ICK		0
+#define ISP_CLK_CAM_MCLK	1
+#define ISP_CLK_DPLL4_M5_CK	2
+#define ISP_CLK_CSI2_FCK	3
+#define ISP_CLK_L3_ICK		4
+	struct clk *clock[5];
+
+	/* ISP modules */
+	struct ispstat isp_af;
+	struct ispstat isp_aewb;
+	struct ispstat isp_hist;
+	struct isp_res_device isp_res;
+	struct isp_prev_device isp_prev;
+	struct isp_ccdc_device isp_ccdc;
+	struct isp_csi2_device isp_csi2a;
+	struct isp_csi2_device isp_csi2c;
+	struct isp_ccp2_device isp_ccp2;
+	struct isp_csiphy isp_csiphy1;
+	struct isp_csiphy isp_csiphy2;
+
+	unsigned int sbl_resources;
+	unsigned int subclk_resources;
+
+	struct iommu_domain *domain;
+
+	struct isp_platform_callback platform_cb;
+};
+
+#define v4l2_dev_to_isp_device(dev) \
+	container_of(dev, struct isp_device, v4l2_dev)
+
+void omap3isp_hist_dma_done(struct isp_device *isp);
+
+void omap3isp_flush(struct isp_device *isp);
+
+int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
+			      atomic_t *stopping);
+
+int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait,
+				     atomic_t *stopping);
+
+int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
+				 enum isp_pipeline_stream_state state);
+void omap3isp_configure_bridge(struct isp_device *isp,
+			       enum ccdc_input_entity input,
+			       const struct isp_parallel_platform_data *pdata,
+			       unsigned int shift, unsigned int bridge);
+
+struct isp_device *omap3isp_get(struct isp_device *isp);
+void omap3isp_put(struct isp_device *isp);
+
+void omap3isp_print_status(struct isp_device *isp);
+
+void omap3isp_sbl_enable(struct isp_device *isp, enum isp_sbl_resource res);
+void omap3isp_sbl_disable(struct isp_device *isp, enum isp_sbl_resource res);
+
+void omap3isp_subclk_enable(struct isp_device *isp,
+			    enum isp_subclk_resource res);
+void omap3isp_subclk_disable(struct isp_device *isp,
+			     enum isp_subclk_resource res);
+
+int omap3isp_pipeline_pm_use(struct media_entity *entity, int use);
+
+int omap3isp_register_entities(struct platform_device *pdev,
+			       struct v4l2_device *v4l2_dev);
+void omap3isp_unregister_entities(struct platform_device *pdev);
+
+/*
+ * isp_reg_readl - Read value of an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @isp_mmio_range: Range to which the register offset refers to.
+ * @reg_offset: Register offset to read from.
+ *
+ * Returns an unsigned 32 bit value with the required register contents.
+ */
+static inline
+u32 isp_reg_readl(struct isp_device *isp, enum isp_mem_resources isp_mmio_range,
+		  u32 reg_offset)
+{
+	return __raw_readl(isp->mmio_base[isp_mmio_range] + reg_offset);
+}
+
+/*
+ * isp_reg_writel - Write value to an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @reg_value: 32 bit value to write to the register.
+ * @isp_mmio_range: Range to which the register offset refers to.
+ * @reg_offset: Register offset to write into.
+ */
+static inline
+void isp_reg_writel(struct isp_device *isp, u32 reg_value,
+		    enum isp_mem_resources isp_mmio_range, u32 reg_offset)
+{
+	__raw_writel(reg_value, isp->mmio_base[isp_mmio_range] + reg_offset);
+}
+
+/*
+ * isp_reg_and - Clear individual bits in an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @mmio_range: Range to which the register offset refers to.
+ * @reg: Register offset to work on.
+ * @clr_bits: 32 bit value which would be cleared in the register.
+ */
+static inline
+void isp_reg_clr(struct isp_device *isp, enum isp_mem_resources mmio_range,
+		 u32 reg, u32 clr_bits)
+{
+	u32 v = isp_reg_readl(isp, mmio_range, reg);
+
+	isp_reg_writel(isp, v & ~clr_bits, mmio_range, reg);
+}
+
+/*
+ * isp_reg_set - Set individual bits in an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @mmio_range: Range to which the register offset refers to.
+ * @reg: Register offset to work on.
+ * @set_bits: 32 bit value which would be set in the register.
+ */
+static inline
+void isp_reg_set(struct isp_device *isp, enum isp_mem_resources mmio_range,
+		 u32 reg, u32 set_bits)
+{
+	u32 v = isp_reg_readl(isp, mmio_range, reg);
+
+	isp_reg_writel(isp, v | set_bits, mmio_range, reg);
+}
+
+/*
+ * isp_reg_clr_set - Clear and set invidial bits in an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @mmio_range: Range to which the register offset refers to.
+ * @reg: Register offset to work on.
+ * @clr_bits: 32 bit value which would be cleared in the register.
+ * @set_bits: 32 bit value which would be set in the register.
+ *
+ * The clear operation is done first, and then the set operation.
+ */
+static inline
+void isp_reg_clr_set(struct isp_device *isp, enum isp_mem_resources mmio_range,
+		     u32 reg, u32 clr_bits, u32 set_bits)
+{
+	u32 v = isp_reg_readl(isp, mmio_range, reg);
+
+	isp_reg_writel(isp, (v & ~clr_bits) | set_bits, mmio_range, reg);
+}
+
+static inline enum v4l2_buf_type
+isp_pad_buffer_type(const struct v4l2_subdev *subdev, int pad)
+{
+	if (pad >= subdev->entity.num_pads)
+		return 0;
+
+	if (subdev->entity.pads[pad].flags & MEDIA_PAD_FL_SINK)
+		return V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	else
+		return V4L2_BUF_TYPE_VIDEO_CAPTURE;
+}
+
+#endif	/* OMAP3_ISP_CORE_H */
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
new file mode 100644
index 0000000..aa9df9d
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -0,0 +1,2583 @@
+/*
+ * ispccdc.c
+ *
+ * TI OMAP3 ISP - CCDC module
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <media/v4l2-event.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispccdc.h"
+
+#define CCDC_MIN_WIDTH		32
+#define CCDC_MIN_HEIGHT		32
+
+static struct v4l2_mbus_framefmt *
+__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+		  unsigned int pad, enum v4l2_subdev_format_whence which);
+
+static const unsigned int ccdc_fmts[] = {
+	V4L2_MBUS_FMT_Y8_1X8,
+	V4L2_MBUS_FMT_Y10_1X10,
+	V4L2_MBUS_FMT_Y12_1X12,
+	V4L2_MBUS_FMT_SGRBG8_1X8,
+	V4L2_MBUS_FMT_SRGGB8_1X8,
+	V4L2_MBUS_FMT_SBGGR8_1X8,
+	V4L2_MBUS_FMT_SGBRG8_1X8,
+	V4L2_MBUS_FMT_SGRBG10_1X10,
+	V4L2_MBUS_FMT_SRGGB10_1X10,
+	V4L2_MBUS_FMT_SBGGR10_1X10,
+	V4L2_MBUS_FMT_SGBRG10_1X10,
+	V4L2_MBUS_FMT_SGRBG12_1X12,
+	V4L2_MBUS_FMT_SRGGB12_1X12,
+	V4L2_MBUS_FMT_SBGGR12_1X12,
+	V4L2_MBUS_FMT_SGBRG12_1X12,
+	V4L2_MBUS_FMT_YUYV8_2X8,
+	V4L2_MBUS_FMT_UYVY8_2X8,
+};
+
+/*
+ * ccdc_print_status - Print current CCDC Module register values.
+ * @ccdc: Pointer to ISP CCDC device.
+ *
+ * Also prints other debug information stored in the CCDC module.
+ */
+#define CCDC_PRINT_REGISTER(isp, name)\
+	dev_dbg(isp->dev, "###CCDC " #name "=0x%08x\n", \
+		isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_##name))
+
+static void ccdc_print_status(struct isp_ccdc_device *ccdc)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+
+	dev_dbg(isp->dev, "-------------CCDC Register dump-------------\n");
+
+	CCDC_PRINT_REGISTER(isp, PCR);
+	CCDC_PRINT_REGISTER(isp, SYN_MODE);
+	CCDC_PRINT_REGISTER(isp, HD_VD_WID);
+	CCDC_PRINT_REGISTER(isp, PIX_LINES);
+	CCDC_PRINT_REGISTER(isp, HORZ_INFO);
+	CCDC_PRINT_REGISTER(isp, VERT_START);
+	CCDC_PRINT_REGISTER(isp, VERT_LINES);
+	CCDC_PRINT_REGISTER(isp, CULLING);
+	CCDC_PRINT_REGISTER(isp, HSIZE_OFF);
+	CCDC_PRINT_REGISTER(isp, SDOFST);
+	CCDC_PRINT_REGISTER(isp, SDR_ADDR);
+	CCDC_PRINT_REGISTER(isp, CLAMP);
+	CCDC_PRINT_REGISTER(isp, DCSUB);
+	CCDC_PRINT_REGISTER(isp, COLPTN);
+	CCDC_PRINT_REGISTER(isp, BLKCMP);
+	CCDC_PRINT_REGISTER(isp, FPC);
+	CCDC_PRINT_REGISTER(isp, FPC_ADDR);
+	CCDC_PRINT_REGISTER(isp, VDINT);
+	CCDC_PRINT_REGISTER(isp, ALAW);
+	CCDC_PRINT_REGISTER(isp, REC656IF);
+	CCDC_PRINT_REGISTER(isp, CFG);
+	CCDC_PRINT_REGISTER(isp, FMTCFG);
+	CCDC_PRINT_REGISTER(isp, FMT_HORZ);
+	CCDC_PRINT_REGISTER(isp, FMT_VERT);
+	CCDC_PRINT_REGISTER(isp, PRGEVEN0);
+	CCDC_PRINT_REGISTER(isp, PRGEVEN1);
+	CCDC_PRINT_REGISTER(isp, PRGODD0);
+	CCDC_PRINT_REGISTER(isp, PRGODD1);
+	CCDC_PRINT_REGISTER(isp, VP_OUT);
+	CCDC_PRINT_REGISTER(isp, LSC_CONFIG);
+	CCDC_PRINT_REGISTER(isp, LSC_INITIAL);
+	CCDC_PRINT_REGISTER(isp, LSC_TABLE_BASE);
+	CCDC_PRINT_REGISTER(isp, LSC_TABLE_OFFSET);
+
+	dev_dbg(isp->dev, "--------------------------------------------\n");
+}
+
+/*
+ * omap3isp_ccdc_busy - Get busy state of the CCDC.
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+int omap3isp_ccdc_busy(struct isp_ccdc_device *ccdc)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+
+	return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR) &
+		ISPCCDC_PCR_BUSY;
+}
+
+/* -----------------------------------------------------------------------------
+ * Lens Shading Compensation
+ */
+
+/*
+ * ccdc_lsc_validate_config - Check that LSC configuration is valid.
+ * @ccdc: Pointer to ISP CCDC device.
+ * @lsc_cfg: the LSC configuration to check.
+ *
+ * Returns 0 if the LSC configuration is valid, or -EINVAL if invalid.
+ */
+static int ccdc_lsc_validate_config(struct isp_ccdc_device *ccdc,
+				    struct omap3isp_ccdc_lsc_config *lsc_cfg)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+	struct v4l2_mbus_framefmt *format;
+	unsigned int paxel_width, paxel_height;
+	unsigned int paxel_shift_x, paxel_shift_y;
+	unsigned int min_width, min_height, min_size;
+	unsigned int input_width, input_height;
+
+	paxel_shift_x = lsc_cfg->gain_mode_m;
+	paxel_shift_y = lsc_cfg->gain_mode_n;
+
+	if ((paxel_shift_x < 2) || (paxel_shift_x > 6) ||
+	    (paxel_shift_y < 2) || (paxel_shift_y > 6)) {
+		dev_dbg(isp->dev, "CCDC: LSC: Invalid paxel size\n");
+		return -EINVAL;
+	}
+
+	if (lsc_cfg->offset & 3) {
+		dev_dbg(isp->dev, "CCDC: LSC: Offset must be a multiple of "
+			"4\n");
+		return -EINVAL;
+	}
+
+	if ((lsc_cfg->initial_x & 1) || (lsc_cfg->initial_y & 1)) {
+		dev_dbg(isp->dev, "CCDC: LSC: initial_x and y must be even\n");
+		return -EINVAL;
+	}
+
+	format = __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK,
+				   V4L2_SUBDEV_FORMAT_ACTIVE);
+	input_width = format->width;
+	input_height = format->height;
+
+	/* Calculate minimum bytesize for validation */
+	paxel_width = 1 << paxel_shift_x;
+	min_width = ((input_width + lsc_cfg->initial_x + paxel_width - 1)
+		     >> paxel_shift_x) + 1;
+
+	paxel_height = 1 << paxel_shift_y;
+	min_height = ((input_height + lsc_cfg->initial_y + paxel_height - 1)
+		     >> paxel_shift_y) + 1;
+
+	min_size = 4 * min_width * min_height;
+	if (min_size > lsc_cfg->size) {
+		dev_dbg(isp->dev, "CCDC: LSC: too small table\n");
+		return -EINVAL;
+	}
+	if (lsc_cfg->offset < (min_width * 4)) {
+		dev_dbg(isp->dev, "CCDC: LSC: Offset is too small\n");
+		return -EINVAL;
+	}
+	if ((lsc_cfg->size / lsc_cfg->offset) < min_height) {
+		dev_dbg(isp->dev, "CCDC: LSC: Wrong size/offset combination\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * ccdc_lsc_program_table - Program Lens Shading Compensation table address.
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_lsc_program_table(struct isp_ccdc_device *ccdc, u32 addr)
+{
+	isp_reg_writel(to_isp_device(ccdc), addr,
+		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_BASE);
+}
+
+/*
+ * ccdc_lsc_setup_regs - Configures the lens shading compensation module
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_lsc_setup_regs(struct isp_ccdc_device *ccdc,
+				struct omap3isp_ccdc_lsc_config *cfg)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+	int reg;
+
+	isp_reg_writel(isp, cfg->offset, OMAP3_ISP_IOMEM_CCDC,
+		       ISPCCDC_LSC_TABLE_OFFSET);
+
+	reg = 0;
+	reg |= cfg->gain_mode_n << ISPCCDC_LSC_GAIN_MODE_N_SHIFT;
+	reg |= cfg->gain_mode_m << ISPCCDC_LSC_GAIN_MODE_M_SHIFT;
+	reg |= cfg->gain_format << ISPCCDC_LSC_GAIN_FORMAT_SHIFT;
+	isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG);
+
+	reg = 0;
+	reg &= ~ISPCCDC_LSC_INITIAL_X_MASK;
+	reg |= cfg->initial_x << ISPCCDC_LSC_INITIAL_X_SHIFT;
+	reg &= ~ISPCCDC_LSC_INITIAL_Y_MASK;
+	reg |= cfg->initial_y << ISPCCDC_LSC_INITIAL_Y_SHIFT;
+	isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC,
+		       ISPCCDC_LSC_INITIAL);
+}
+
+static int ccdc_lsc_wait_prefetch(struct isp_ccdc_device *ccdc)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+	unsigned int wait;
+
+	isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ,
+		       OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+
+	/* timeout 1 ms */
+	for (wait = 0; wait < 1000; wait++) {
+		if (isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS) &
+				  IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ) {
+			isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ,
+				       OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+			return 0;
+		}
+
+		rmb();
+		udelay(1);
+	}
+
+	return -ETIMEDOUT;
+}
+
+/*
+ * __ccdc_lsc_enable - Enables/Disables the Lens Shading Compensation module.
+ * @ccdc: Pointer to ISP CCDC device.
+ * @enable: 0 Disables LSC, 1 Enables LSC.
+ */
+static int __ccdc_lsc_enable(struct isp_ccdc_device *ccdc, int enable)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+	const struct v4l2_mbus_framefmt *format =
+		__ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK,
+				  V4L2_SUBDEV_FORMAT_ACTIVE);
+
+	if ((format->code != V4L2_MBUS_FMT_SGRBG10_1X10) &&
+	    (format->code != V4L2_MBUS_FMT_SRGGB10_1X10) &&
+	    (format->code != V4L2_MBUS_FMT_SBGGR10_1X10) &&
+	    (format->code != V4L2_MBUS_FMT_SGBRG10_1X10))
+		return -EINVAL;
+
+	if (enable)
+		omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_LSC_READ);
+
+	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG,
+			ISPCCDC_LSC_ENABLE, enable ? ISPCCDC_LSC_ENABLE : 0);
+
+	if (enable) {
+		if (ccdc_lsc_wait_prefetch(ccdc) < 0) {
+			isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC,
+				    ISPCCDC_LSC_CONFIG, ISPCCDC_LSC_ENABLE);
+			ccdc->lsc.state = LSC_STATE_STOPPED;
+			dev_warn(to_device(ccdc), "LSC prefecth timeout\n");
+			return -ETIMEDOUT;
+		}
+		ccdc->lsc.state = LSC_STATE_RUNNING;
+	} else {
+		ccdc->lsc.state = LSC_STATE_STOPPING;
+	}
+
+	return 0;
+}
+
+static int ccdc_lsc_busy(struct isp_ccdc_device *ccdc)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+
+	return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG) &
+			     ISPCCDC_LSC_BUSY;
+}
+
+/* __ccdc_lsc_configure - Apply a new configuration to the LSC engine
+ * @ccdc: Pointer to ISP CCDC device
+ * @req: New configuration request
+ *
+ * context: in_interrupt()
+ */
+static int __ccdc_lsc_configure(struct isp_ccdc_device *ccdc,
+				struct ispccdc_lsc_config_req *req)
+{
+	if (!req->enable)
+		return -EINVAL;
+
+	if (ccdc_lsc_validate_config(ccdc, &req->config) < 0) {
+		dev_dbg(to_device(ccdc), "Discard LSC configuration\n");
+		return -EINVAL;
+	}
+
+	if (ccdc_lsc_busy(ccdc))
+		return -EBUSY;
+
+	ccdc_lsc_setup_regs(ccdc, &req->config);
+	ccdc_lsc_program_table(ccdc, req->table);
+	return 0;
+}
+
+/*
+ * ccdc_lsc_error_handler - Handle LSC prefetch error scenario.
+ * @ccdc: Pointer to ISP CCDC device.
+ *
+ * Disables LSC, and defers enablement to shadow registers update time.
+ */
+static void ccdc_lsc_error_handler(struct isp_ccdc_device *ccdc)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+	/*
+	 * From OMAP3 TRM: When this event is pending, the module
+	 * goes into transparent mode (output =input). Normal
+	 * operation can be resumed at the start of the next frame
+	 * after:
+	 *  1) Clearing this event
+	 *  2) Disabling the LSC module
+	 *  3) Enabling it
+	 */
+	isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG,
+		    ISPCCDC_LSC_ENABLE);
+	ccdc->lsc.state = LSC_STATE_STOPPED;
+}
+
+static void ccdc_lsc_free_request(struct isp_ccdc_device *ccdc,
+				  struct ispccdc_lsc_config_req *req)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+
+	if (req == NULL)
+		return;
+
+	if (req->iovm)
+		dma_unmap_sg(isp->dev, req->iovm->sgt->sgl,
+			     req->iovm->sgt->nents, DMA_TO_DEVICE);
+	if (req->table)
+		omap_iommu_vfree(isp->domain, isp->dev, req->table);
+	kfree(req);
+}
+
+static void ccdc_lsc_free_queue(struct isp_ccdc_device *ccdc,
+				struct list_head *queue)
+{
+	struct ispccdc_lsc_config_req *req, *n;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+	list_for_each_entry_safe(req, n, queue, list) {
+		list_del(&req->list);
+		spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+		ccdc_lsc_free_request(ccdc, req);
+		spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+	}
+	spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+}
+
+static void ccdc_lsc_free_table_work(struct work_struct *work)
+{
+	struct isp_ccdc_device *ccdc;
+	struct ispccdc_lsc *lsc;
+
+	lsc = container_of(work, struct ispccdc_lsc, table_work);
+	ccdc = container_of(lsc, struct isp_ccdc_device, lsc);
+
+	ccdc_lsc_free_queue(ccdc, &lsc->free_queue);
+}
+
+/*
+ * ccdc_lsc_config - Configure the LSC module from a userspace request
+ *
+ * Store the request LSC configuration in the LSC engine request pointer. The
+ * configuration will be applied to the hardware when the CCDC will be enabled,
+ * or at the next LSC interrupt if the CCDC is already running.
+ */
+static int ccdc_lsc_config(struct isp_ccdc_device *ccdc,
+			   struct omap3isp_ccdc_update_config *config)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+	struct ispccdc_lsc_config_req *req;
+	unsigned long flags;
+	void *table;
+	u16 update;
+	int ret;
+
+	update = config->update &
+		 (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC);
+	if (!update)
+		return 0;
+
+	if (update != (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC)) {
+		dev_dbg(to_device(ccdc), "%s: Both LSC configuration and table "
+			"need to be supplied\n", __func__);
+		return -EINVAL;
+	}
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (req == NULL)
+		return -ENOMEM;
+
+	if (config->flag & OMAP3ISP_CCDC_CONFIG_LSC) {
+		if (copy_from_user(&req->config, config->lsc_cfg,
+				   sizeof(req->config))) {
+			ret = -EFAULT;
+			goto done;
+		}
+
+		req->enable = 1;
+
+		req->table = omap_iommu_vmalloc(isp->domain, isp->dev, 0,
+					req->config.size, IOMMU_FLAG);
+		if (IS_ERR_VALUE(req->table)) {
+			req->table = 0;
+			ret = -ENOMEM;
+			goto done;
+		}
+
+		req->iovm = omap_find_iovm_area(isp->dev, req->table);
+		if (req->iovm == NULL) {
+			ret = -ENOMEM;
+			goto done;
+		}
+
+		if (!dma_map_sg(isp->dev, req->iovm->sgt->sgl,
+				req->iovm->sgt->nents, DMA_TO_DEVICE)) {
+			ret = -ENOMEM;
+			req->iovm = NULL;
+			goto done;
+		}
+
+		dma_sync_sg_for_cpu(isp->dev, req->iovm->sgt->sgl,
+				    req->iovm->sgt->nents, DMA_TO_DEVICE);
+
+		table = omap_da_to_va(isp->dev, req->table);
+		if (copy_from_user(table, config->lsc, req->config.size)) {
+			ret = -EFAULT;
+			goto done;
+		}
+
+		dma_sync_sg_for_device(isp->dev, req->iovm->sgt->sgl,
+				       req->iovm->sgt->nents, DMA_TO_DEVICE);
+	}
+
+	spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+	if (ccdc->lsc.request) {
+		list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue);
+		schedule_work(&ccdc->lsc.table_work);
+	}
+	ccdc->lsc.request = req;
+	spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+
+	ret = 0;
+
+done:
+	if (ret < 0)
+		ccdc_lsc_free_request(ccdc, req);
+
+	return ret;
+}
+
+static inline int ccdc_lsc_is_configured(struct isp_ccdc_device *ccdc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+	if (ccdc->lsc.active) {
+		spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+		return 1;
+	}
+	spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+	return 0;
+}
+
+static int ccdc_lsc_enable(struct isp_ccdc_device *ccdc)
+{
+	struct ispccdc_lsc *lsc = &ccdc->lsc;
+
+	if (lsc->state != LSC_STATE_STOPPED)
+		return -EINVAL;
+
+	if (lsc->active) {
+		list_add_tail(&lsc->active->list, &lsc->free_queue);
+		lsc->active = NULL;
+	}
+
+	if (__ccdc_lsc_configure(ccdc, lsc->request) < 0) {
+		omap3isp_sbl_disable(to_isp_device(ccdc),
+				OMAP3_ISP_SBL_CCDC_LSC_READ);
+		list_add_tail(&lsc->request->list, &lsc->free_queue);
+		lsc->request = NULL;
+		goto done;
+	}
+
+	lsc->active = lsc->request;
+	lsc->request = NULL;
+	__ccdc_lsc_enable(ccdc, 1);
+
+done:
+	if (!list_empty(&lsc->free_queue))
+		schedule_work(&lsc->table_work);
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Parameters configuration
+ */
+
+/*
+ * ccdc_configure_clamp - Configure optical-black or digital clamping
+ * @ccdc: Pointer to ISP CCDC device.
+ *
+ * The CCDC performs either optical-black or digital clamp. Configure and enable
+ * the selected clamp method.
+ */
+static void ccdc_configure_clamp(struct isp_ccdc_device *ccdc)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+	u32 clamp;
+
+	if (ccdc->obclamp) {
+		clamp  = ccdc->clamp.obgain << ISPCCDC_CLAMP_OBGAIN_SHIFT;
+		clamp |= ccdc->clamp.oblen << ISPCCDC_CLAMP_OBSLEN_SHIFT;
+		clamp |= ccdc->clamp.oblines << ISPCCDC_CLAMP_OBSLN_SHIFT;
+		clamp |= ccdc->clamp.obstpixel << ISPCCDC_CLAMP_OBST_SHIFT;
+		isp_reg_writel(isp, clamp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP);
+	} else {
+		isp_reg_writel(isp, ccdc->clamp.dcsubval,
+			       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_DCSUB);
+	}
+
+	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP,
+			ISPCCDC_CLAMP_CLAMPEN,
+			ccdc->obclamp ? ISPCCDC_CLAMP_CLAMPEN : 0);
+}
+
+/*
+ * ccdc_configure_fpc - Configure Faulty Pixel Correction
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_configure_fpc(struct isp_ccdc_device *ccdc)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+
+	isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC, ISPCCDC_FPC_FPCEN);
+
+	if (!ccdc->fpc_en)
+		return;
+
+	isp_reg_writel(isp, ccdc->fpc.fpcaddr, OMAP3_ISP_IOMEM_CCDC,
+		       ISPCCDC_FPC_ADDR);
+	/* The FPNUM field must be set before enabling FPC. */
+	isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT),
+		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
+	isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT) |
+		       ISPCCDC_FPC_FPCEN, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
+}
+
+/*
+ * ccdc_configure_black_comp - Configure Black Level Compensation.
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_configure_black_comp(struct isp_ccdc_device *ccdc)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+	u32 blcomp;
+
+	blcomp  = ccdc->blcomp.b_mg << ISPCCDC_BLKCMP_B_MG_SHIFT;
+	blcomp |= ccdc->blcomp.gb_g << ISPCCDC_BLKCMP_GB_G_SHIFT;
+	blcomp |= ccdc->blcomp.gr_cy << ISPCCDC_BLKCMP_GR_CY_SHIFT;
+	blcomp |= ccdc->blcomp.r_ye << ISPCCDC_BLKCMP_R_YE_SHIFT;
+
+	isp_reg_writel(isp, blcomp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_BLKCMP);
+}
+
+/*
+ * ccdc_configure_lpf - Configure Low-Pass Filter (LPF).
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_configure_lpf(struct isp_ccdc_device *ccdc)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+
+	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE,
+			ISPCCDC_SYN_MODE_LPF,
+			ccdc->lpf ? ISPCCDC_SYN_MODE_LPF : 0);
+}
+
+/*
+ * ccdc_configure_alaw - Configure A-law compression.
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_configure_alaw(struct isp_ccdc_device *ccdc)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+	const struct isp_format_info *info;
+	u32 alaw = 0;
+
+	info = omap3isp_video_format_info(ccdc->formats[CCDC_PAD_SINK].code);
+
+	switch (info->width) {
+	case 8:
+		return;
+
+	case 10:
+		alaw = ISPCCDC_ALAW_GWDI_9_0;
+		break;
+	case 11:
+		alaw = ISPCCDC_ALAW_GWDI_10_1;
+		break;
+	case 12:
+		alaw = ISPCCDC_ALAW_GWDI_11_2;
+		break;
+	case 13:
+		alaw = ISPCCDC_ALAW_GWDI_12_3;
+		break;
+	}
+
+	if (ccdc->alaw)
+		alaw |= ISPCCDC_ALAW_CCDTBL;
+
+	isp_reg_writel(isp, alaw, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW);
+}
+
+/*
+ * ccdc_config_imgattr - Configure sensor image specific attributes.
+ * @ccdc: Pointer to ISP CCDC device.
+ * @colptn: Color pattern of the sensor.
+ */
+static void ccdc_config_imgattr(struct isp_ccdc_device *ccdc, u32 colptn)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+
+	isp_reg_writel(isp, colptn, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_COLPTN);
+}
+
+/*
+ * ccdc_config - Set CCDC configuration from userspace
+ * @ccdc: Pointer to ISP CCDC device.
+ * @userspace_add: Structure containing CCDC configuration sent from userspace.
+ *
+ * Returns 0 if successful, -EINVAL if the pointer to the configuration
+ * structure is null, or the copy_from_user function fails to copy user space
+ * memory to kernel space memory.
+ */
+static int ccdc_config(struct isp_ccdc_device *ccdc,
+		       struct omap3isp_ccdc_update_config *ccdc_struct)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ccdc->lock, flags);
+	ccdc->shadow_update = 1;
+	spin_unlock_irqrestore(&ccdc->lock, flags);
+
+	if (OMAP3ISP_CCDC_ALAW & ccdc_struct->update) {
+		ccdc->alaw = !!(OMAP3ISP_CCDC_ALAW & ccdc_struct->flag);
+		ccdc->update |= OMAP3ISP_CCDC_ALAW;
+	}
+
+	if (OMAP3ISP_CCDC_LPF & ccdc_struct->update) {
+		ccdc->lpf = !!(OMAP3ISP_CCDC_LPF & ccdc_struct->flag);
+		ccdc->update |= OMAP3ISP_CCDC_LPF;
+	}
+
+	if (OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->update) {
+		if (copy_from_user(&ccdc->clamp, ccdc_struct->bclamp,
+				   sizeof(ccdc->clamp))) {
+			ccdc->shadow_update = 0;
+			return -EFAULT;
+		}
+
+		ccdc->obclamp = !!(OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->flag);
+		ccdc->update |= OMAP3ISP_CCDC_BLCLAMP;
+	}
+
+	if (OMAP3ISP_CCDC_BCOMP & ccdc_struct->update) {
+		if (copy_from_user(&ccdc->blcomp, ccdc_struct->blcomp,
+				   sizeof(ccdc->blcomp))) {
+			ccdc->shadow_update = 0;
+			return -EFAULT;
+		}
+
+		ccdc->update |= OMAP3ISP_CCDC_BCOMP;
+	}
+
+	ccdc->shadow_update = 0;
+
+	if (OMAP3ISP_CCDC_FPC & ccdc_struct->update) {
+		u32 table_old = 0;
+		u32 table_new;
+		u32 size;
+
+		if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED)
+			return -EBUSY;
+
+		ccdc->fpc_en = !!(OMAP3ISP_CCDC_FPC & ccdc_struct->flag);
+
+		if (ccdc->fpc_en) {
+			if (copy_from_user(&ccdc->fpc, ccdc_struct->fpc,
+					   sizeof(ccdc->fpc)))
+				return -EFAULT;
+
+			/*
+			 * table_new must be 64-bytes aligned, but it's
+			 * already done by omap_iommu_vmalloc().
+			 */
+			size = ccdc->fpc.fpnum * 4;
+			table_new = omap_iommu_vmalloc(isp->domain, isp->dev,
+							0, size, IOMMU_FLAG);
+			if (IS_ERR_VALUE(table_new))
+				return -ENOMEM;
+
+			if (copy_from_user(omap_da_to_va(isp->dev, table_new),
+					   (__force void __user *)
+					   ccdc->fpc.fpcaddr, size)) {
+				omap_iommu_vfree(isp->domain, isp->dev,
+								table_new);
+				return -EFAULT;
+			}
+
+			table_old = ccdc->fpc.fpcaddr;
+			ccdc->fpc.fpcaddr = table_new;
+		}
+
+		ccdc_configure_fpc(ccdc);
+		if (table_old != 0)
+			omap_iommu_vfree(isp->domain, isp->dev, table_old);
+	}
+
+	return ccdc_lsc_config(ccdc, ccdc_struct);
+}
+
+static void ccdc_apply_controls(struct isp_ccdc_device *ccdc)
+{
+	if (ccdc->update & OMAP3ISP_CCDC_ALAW) {
+		ccdc_configure_alaw(ccdc);
+		ccdc->update &= ~OMAP3ISP_CCDC_ALAW;
+	}
+
+	if (ccdc->update & OMAP3ISP_CCDC_LPF) {
+		ccdc_configure_lpf(ccdc);
+		ccdc->update &= ~OMAP3ISP_CCDC_LPF;
+	}
+
+	if (ccdc->update & OMAP3ISP_CCDC_BLCLAMP) {
+		ccdc_configure_clamp(ccdc);
+		ccdc->update &= ~OMAP3ISP_CCDC_BLCLAMP;
+	}
+
+	if (ccdc->update & OMAP3ISP_CCDC_BCOMP) {
+		ccdc_configure_black_comp(ccdc);
+		ccdc->update &= ~OMAP3ISP_CCDC_BCOMP;
+	}
+}
+
+/*
+ * omap3isp_ccdc_restore_context - Restore values of the CCDC module registers
+ * @dev: Pointer to ISP device
+ */
+void omap3isp_ccdc_restore_context(struct isp_device *isp)
+{
+	struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
+
+	isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ISPCCDC_CFG_VDLC);
+
+	ccdc->update = OMAP3ISP_CCDC_ALAW | OMAP3ISP_CCDC_LPF
+		     | OMAP3ISP_CCDC_BLCLAMP | OMAP3ISP_CCDC_BCOMP;
+	ccdc_apply_controls(ccdc);
+	ccdc_configure_fpc(ccdc);
+}
+
+/* -----------------------------------------------------------------------------
+ * Format- and pipeline-related configuration helpers
+ */
+
+/*
+ * ccdc_config_vp - Configure the Video Port.
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_config_vp(struct isp_ccdc_device *ccdc)
+{
+	struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
+	struct isp_device *isp = to_isp_device(ccdc);
+	const struct isp_format_info *info;
+	unsigned long l3_ick = pipe->l3_ick;
+	unsigned int max_div = isp->revision == ISP_REVISION_15_0 ? 64 : 8;
+	unsigned int div = 0;
+	u32 fmtcfg_vp;
+
+	fmtcfg_vp = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG)
+		  & ~(ISPCCDC_FMTCFG_VPIN_MASK | ISPCCDC_FMTCFG_VPIF_FRQ_MASK);
+
+	info = omap3isp_video_format_info(ccdc->formats[CCDC_PAD_SINK].code);
+
+	switch (info->width) {
+	case 8:
+	case 10:
+		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0;
+		break;
+	case 11:
+		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1;
+		break;
+	case 12:
+		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2;
+		break;
+	case 13:
+		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3;
+		break;
+	}
+
+	if (pipe->input)
+		div = DIV_ROUND_UP(l3_ick, pipe->max_rate);
+	else if (pipe->external_rate)
+		div = l3_ick / pipe->external_rate;
+
+	div = clamp(div, 2U, max_div);
+	fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;
+
+	isp_reg_writel(isp, fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
+}
+
+/*
+ * ccdc_enable_vp - Enable Video Port.
+ * @ccdc: Pointer to ISP CCDC device.
+ * @enable: 0 Disables VP, 1 Enables VP
+ *
+ * This is needed for outputting image to Preview, H3A and HIST ISP submodules.
+ */
+static void ccdc_enable_vp(struct isp_ccdc_device *ccdc, u8 enable)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+
+	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG,
+			ISPCCDC_FMTCFG_VPEN, enable ? ISPCCDC_FMTCFG_VPEN : 0);
+}
+
+/*
+ * ccdc_config_outlineoffset - Configure memory saving output line offset
+ * @ccdc: Pointer to ISP CCDC device.
+ * @offset: Address offset to start a new line. Must be twice the
+ *          Output width and aligned on 32 byte boundary
+ * @oddeven: Specifies the odd/even line pattern to be chosen to store the
+ *           output.
+ * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines.
+ *
+ * - Configures the output line offset when stored in memory
+ * - Sets the odd/even line pattern to store the output
+ *    (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4))
+ * - Configures the number of even and odd line fields in case of rearranging
+ * the lines.
+ */
+static void ccdc_config_outlineoffset(struct isp_ccdc_device *ccdc,
+					u32 offset, u8 oddeven, u8 numlines)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+
+	isp_reg_writel(isp, offset & 0xffff,
+		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF);
+
+	isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+		    ISPCCDC_SDOFST_FINV);
+
+	isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+		    ISPCCDC_SDOFST_FOFST_4L);
+
+	switch (oddeven) {
+	case EVENEVEN:
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+			    (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT);
+		break;
+	case ODDEVEN:
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+			    (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT);
+		break;
+	case EVENODD:
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+			    (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT);
+		break;
+	case ODDODD:
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+			    (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT);
+		break;
+	default:
+		break;
+	}
+}
+
+/*
+ * ccdc_set_outaddr - Set memory address to save output image
+ * @ccdc: Pointer to ISP CCDC device.
+ * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary.
+ *
+ * Sets the memory address where the output will be saved.
+ */
+static void ccdc_set_outaddr(struct isp_ccdc_device *ccdc, u32 addr)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+
+	isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR);
+}
+
+/*
+ * omap3isp_ccdc_max_rate - Calculate maximum input data rate based on the input
+ * @ccdc: Pointer to ISP CCDC device.
+ * @max_rate: Maximum calculated data rate.
+ *
+ * Returns in *max_rate less value between calculated and passed
+ */
+void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc,
+			    unsigned int *max_rate)
+{
+	struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
+	unsigned int rate;
+
+	if (pipe == NULL)
+		return;
+
+	/*
+	 * TRM says that for parallel sensors the maximum data rate
+	 * should be 90% form L3/2 clock, otherwise just L3/2.
+	 */
+	if (ccdc->input == CCDC_INPUT_PARALLEL)
+		rate = pipe->l3_ick / 2 * 9 / 10;
+	else
+		rate = pipe->l3_ick / 2;
+
+	*max_rate = min(*max_rate, rate);
+}
+
+/*
+ * ccdc_config_sync_if - Set CCDC sync interface configuration
+ * @ccdc: Pointer to ISP CCDC device.
+ * @pdata: Parallel interface platform data (may be NULL)
+ * @data_size: Data size
+ */
+static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
+				struct isp_parallel_platform_data *pdata,
+				unsigned int data_size)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+	const struct v4l2_mbus_framefmt *format;
+	u32 syn_mode = ISPCCDC_SYN_MODE_VDHDEN;
+
+	format = &ccdc->formats[CCDC_PAD_SINK];
+
+	if (format->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
+	    format->code == V4L2_MBUS_FMT_UYVY8_2X8) {
+		/* The bridge is enabled for YUV8 formats. Configure the input
+		 * mode accordingly.
+		 */
+		syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16;
+	}
+
+	switch (data_size) {
+	case 8:
+		syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_8;
+		break;
+	case 10:
+		syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_10;
+		break;
+	case 11:
+		syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_11;
+		break;
+	case 12:
+		syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_12;
+		break;
+	}
+
+	if (pdata && pdata->data_pol)
+		syn_mode |= ISPCCDC_SYN_MODE_DATAPOL;
+
+	if (pdata && pdata->hs_pol)
+		syn_mode |= ISPCCDC_SYN_MODE_HDPOL;
+
+	if (pdata && pdata->vs_pol)
+		syn_mode |= ISPCCDC_SYN_MODE_VDPOL;
+
+	isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
+
+	/* The CCDC_CFG.Y8POS bit is used in YCbCr8 input mode only. The
+	 * hardware seems to ignore it in all other input modes.
+	 */
+	if (format->code == V4L2_MBUS_FMT_UYVY8_2X8)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+			    ISPCCDC_CFG_Y8POS);
+	else
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+			    ISPCCDC_CFG_Y8POS);
+
+	isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
+		    ISPCCDC_REC656IF_R656ON);
+}
+
+/* CCDC formats descriptions */
+static const u32 ccdc_sgrbg_pattern =
+	ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
+	ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
+	ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
+	ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
+	ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
+	ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
+	ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
+	ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
+	ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
+	ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
+	ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
+	ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
+	ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
+	ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
+	ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
+	ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
+
+static const u32 ccdc_srggb_pattern =
+	ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
+	ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
+	ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
+	ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
+	ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
+	ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
+	ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
+	ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
+	ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
+	ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
+	ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
+	ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
+	ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
+	ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
+	ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
+	ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
+
+static const u32 ccdc_sbggr_pattern =
+	ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
+	ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
+	ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
+	ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
+	ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
+	ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
+	ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
+	ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
+	ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
+	ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
+	ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
+	ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
+	ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
+	ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
+	ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
+	ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
+
+static const u32 ccdc_sgbrg_pattern =
+	ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
+	ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
+	ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
+	ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
+	ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
+	ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
+	ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
+	ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
+	ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
+	ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
+	ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
+	ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
+	ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
+	ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
+	ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
+	ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
+
+static void ccdc_configure(struct isp_ccdc_device *ccdc)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+	struct isp_parallel_platform_data *pdata = NULL;
+	struct v4l2_subdev *sensor;
+	struct v4l2_mbus_framefmt *format;
+	const struct v4l2_rect *crop;
+	const struct isp_format_info *fmt_info;
+	struct v4l2_subdev_format fmt_src;
+	unsigned int depth_out;
+	unsigned int depth_in = 0;
+	struct media_pad *pad;
+	unsigned long flags;
+	unsigned int bridge;
+	unsigned int shift;
+	u32 syn_mode;
+	u32 ccdc_pattern;
+
+	pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]);
+	sensor = media_entity_to_v4l2_subdev(pad->entity);
+	if (ccdc->input == CCDC_INPUT_PARALLEL)
+		pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv)
+			->bus.parallel;
+
+	/* Compute the lane shifter shift value and enable the bridge when the
+	 * input format is YUV.
+	 */
+	fmt_src.pad = pad->index;
+	fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+	if (!v4l2_subdev_call(sensor, pad, get_fmt, NULL, &fmt_src)) {
+		fmt_info = omap3isp_video_format_info(fmt_src.format.code);
+		depth_in = fmt_info->width;
+	}
+
+	fmt_info = omap3isp_video_format_info
+		(isp->isp_ccdc.formats[CCDC_PAD_SINK].code);
+	depth_out = fmt_info->width;
+	shift = depth_in - depth_out;
+
+	if (fmt_info->code == V4L2_MBUS_FMT_YUYV8_2X8)
+		bridge = ISPCTRL_PAR_BRIDGE_LENDIAN;
+	else if (fmt_info->code == V4L2_MBUS_FMT_UYVY8_2X8)
+		bridge = ISPCTRL_PAR_BRIDGE_BENDIAN;
+	else
+		bridge = ISPCTRL_PAR_BRIDGE_DISABLE;
+
+	omap3isp_configure_bridge(isp, ccdc->input, pdata, shift, bridge);
+
+	ccdc_config_sync_if(ccdc, pdata, depth_out);
+
+	syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
+
+	/* Use the raw, unprocessed data when writing to memory. The H3A and
+	 * histogram modules are still fed with lens shading corrected data.
+	 */
+	syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
+
+	if (ccdc->output & CCDC_OUTPUT_MEMORY)
+		syn_mode |= ISPCCDC_SYN_MODE_WEN;
+	else
+		syn_mode &= ~ISPCCDC_SYN_MODE_WEN;
+
+	if (ccdc->output & CCDC_OUTPUT_RESIZER)
+		syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ;
+	else
+		syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
+
+	/* CCDC_PAD_SINK */
+	format = &ccdc->formats[CCDC_PAD_SINK];
+
+	/* Mosaic filter */
+	switch (format->code) {
+	case V4L2_MBUS_FMT_SRGGB10_1X10:
+	case V4L2_MBUS_FMT_SRGGB12_1X12:
+		ccdc_pattern = ccdc_srggb_pattern;
+		break;
+	case V4L2_MBUS_FMT_SBGGR10_1X10:
+	case V4L2_MBUS_FMT_SBGGR12_1X12:
+		ccdc_pattern = ccdc_sbggr_pattern;
+		break;
+	case V4L2_MBUS_FMT_SGBRG10_1X10:
+	case V4L2_MBUS_FMT_SGBRG12_1X12:
+		ccdc_pattern = ccdc_sgbrg_pattern;
+		break;
+	default:
+		/* Use GRBG */
+		ccdc_pattern = ccdc_sgrbg_pattern;
+		break;
+	}
+	ccdc_config_imgattr(ccdc, ccdc_pattern);
+
+	/* Generate VD0 on the last line of the image and VD1 on the
+	 * 2/3 height line.
+	 */
+	isp_reg_writel(isp, ((format->height - 2) << ISPCCDC_VDINT_0_SHIFT) |
+		       ((format->height * 2 / 3) << ISPCCDC_VDINT_1_SHIFT),
+		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT);
+
+	/* CCDC_PAD_SOURCE_OF */
+	format = &ccdc->formats[CCDC_PAD_SOURCE_OF];
+	crop = &ccdc->crop;
+
+	isp_reg_writel(isp, (crop->left << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
+		       ((crop->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT),
+		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO);
+	isp_reg_writel(isp, crop->top << ISPCCDC_VERT_START_SLV0_SHIFT,
+		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START);
+	isp_reg_writel(isp, (crop->height - 1)
+			<< ISPCCDC_VERT_LINES_NLV_SHIFT,
+		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES);
+
+	ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value, 0, 0);
+
+	/* The CCDC outputs data in UYVY order by default. Swap bytes to get
+	 * YUYV.
+	 */
+	if (format->code == V4L2_MBUS_FMT_YUYV8_1X16)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+			    ISPCCDC_CFG_BSWD);
+	else
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+			    ISPCCDC_CFG_BSWD);
+
+	/* Use PACK8 mode for 1byte per pixel formats. */
+	if (omap3isp_video_format_info(format->code)->width <= 8)
+		syn_mode |= ISPCCDC_SYN_MODE_PACK8;
+	else
+		syn_mode &= ~ISPCCDC_SYN_MODE_PACK8;
+
+	isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
+
+	/* CCDC_PAD_SOURCE_VP */
+	format = &ccdc->formats[CCDC_PAD_SOURCE_VP];
+
+	isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
+		       (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
+		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ);
+	isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
+		       ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
+		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT);
+
+	isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
+		       (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
+		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT);
+
+	/* Lens shading correction. */
+	spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+	if (ccdc->lsc.request == NULL)
+		goto unlock;
+
+	WARN_ON(ccdc->lsc.active);
+
+	/* Get last good LSC configuration. If it is not supported for
+	 * the current active resolution discard it.
+	 */
+	if (ccdc->lsc.active == NULL &&
+	    __ccdc_lsc_configure(ccdc, ccdc->lsc.request) == 0) {
+		ccdc->lsc.active = ccdc->lsc.request;
+	} else {
+		list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue);
+		schedule_work(&ccdc->lsc.table_work);
+	}
+
+	ccdc->lsc.request = NULL;
+
+unlock:
+	spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+
+	ccdc_apply_controls(ccdc);
+}
+
+static void __ccdc_enable(struct isp_ccdc_device *ccdc, int enable)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+
+	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR,
+			ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0);
+}
+
+static int ccdc_disable(struct isp_ccdc_device *ccdc)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&ccdc->lock, flags);
+	if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS)
+		ccdc->stopping = CCDC_STOP_REQUEST;
+	spin_unlock_irqrestore(&ccdc->lock, flags);
+
+	ret = wait_event_timeout(ccdc->wait,
+				 ccdc->stopping == CCDC_STOP_FINISHED,
+				 msecs_to_jiffies(2000));
+	if (ret == 0) {
+		ret = -ETIMEDOUT;
+		dev_warn(to_device(ccdc), "CCDC stop timeout!\n");
+	}
+
+	omap3isp_sbl_disable(to_isp_device(ccdc), OMAP3_ISP_SBL_CCDC_LSC_READ);
+
+	mutex_lock(&ccdc->ioctl_lock);
+	ccdc_lsc_free_request(ccdc, ccdc->lsc.request);
+	ccdc->lsc.request = ccdc->lsc.active;
+	ccdc->lsc.active = NULL;
+	cancel_work_sync(&ccdc->lsc.table_work);
+	ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue);
+	mutex_unlock(&ccdc->ioctl_lock);
+
+	ccdc->stopping = CCDC_STOP_NOT_REQUESTED;
+
+	return ret > 0 ? 0 : ret;
+}
+
+static void ccdc_enable(struct isp_ccdc_device *ccdc)
+{
+	if (ccdc_lsc_is_configured(ccdc))
+		__ccdc_lsc_enable(ccdc, 1);
+	__ccdc_enable(ccdc, 1);
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+/*
+ * ccdc_sbl_busy - Poll idle state of CCDC and related SBL memory write bits
+ * @ccdc: Pointer to ISP CCDC device.
+ *
+ * Returns zero if the CCDC is idle and the image has been written to
+ * memory, too.
+ */
+static int ccdc_sbl_busy(struct isp_ccdc_device *ccdc)
+{
+	struct isp_device *isp = to_isp_device(ccdc);
+
+	return omap3isp_ccdc_busy(ccdc)
+		| (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_0) &
+		   ISPSBL_CCDC_WR_0_DATA_READY)
+		| (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_1) &
+		   ISPSBL_CCDC_WR_0_DATA_READY)
+		| (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_2) &
+		   ISPSBL_CCDC_WR_0_DATA_READY)
+		| (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_3) &
+		   ISPSBL_CCDC_WR_0_DATA_READY);
+}
+
+/*
+ * ccdc_sbl_wait_idle - Wait until the CCDC and related SBL are idle
+ * @ccdc: Pointer to ISP CCDC device.
+ * @max_wait: Max retry count in us for wait for idle/busy transition.
+ */
+static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc,
+			      unsigned int max_wait)
+{
+	unsigned int wait = 0;
+
+	if (max_wait == 0)
+		max_wait = 10000; /* 10 ms */
+
+	for (wait = 0; wait <= max_wait; wait++) {
+		if (!ccdc_sbl_busy(ccdc))
+			return 0;
+
+		rmb();
+		udelay(1);
+	}
+
+	return -EBUSY;
+}
+
+/* __ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence
+ * @ccdc: Pointer to ISP CCDC device.
+ * @event: Pointing which event trigger handler
+ *
+ * Return 1 when the event and stopping request combination is satisfied,
+ * zero otherwise.
+ */
+static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)
+{
+	int rval = 0;
+
+	switch ((ccdc->stopping & 3) | event) {
+	case CCDC_STOP_REQUEST | CCDC_EVENT_VD1:
+		if (ccdc->lsc.state != LSC_STATE_STOPPED)
+			__ccdc_lsc_enable(ccdc, 0);
+		__ccdc_enable(ccdc, 0);
+		ccdc->stopping = CCDC_STOP_EXECUTED;
+		return 1;
+
+	case CCDC_STOP_EXECUTED | CCDC_EVENT_VD0:
+		ccdc->stopping |= CCDC_STOP_CCDC_FINISHED;
+		if (ccdc->lsc.state == LSC_STATE_STOPPED)
+			ccdc->stopping |= CCDC_STOP_LSC_FINISHED;
+		rval = 1;
+		break;
+
+	case CCDC_STOP_EXECUTED | CCDC_EVENT_LSC_DONE:
+		ccdc->stopping |= CCDC_STOP_LSC_FINISHED;
+		rval = 1;
+		break;
+
+	case CCDC_STOP_EXECUTED | CCDC_EVENT_VD1:
+		return 1;
+	}
+
+	if (ccdc->stopping == CCDC_STOP_FINISHED) {
+		wake_up(&ccdc->wait);
+		rval = 1;
+	}
+
+	return rval;
+}
+
+static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc)
+{
+	struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
+	struct video_device *vdev = ccdc->subdev.devnode;
+	struct v4l2_event event;
+
+	/* Frame number propagation */
+	atomic_inc(&pipe->frame_number);
+
+	memset(&event, 0, sizeof(event));
+	event.type = V4L2_EVENT_FRAME_SYNC;
+	event.u.frame_sync.frame_sequence = atomic_read(&pipe->frame_number);
+
+	v4l2_event_queue(vdev, &event);
+}
+
+/*
+ * ccdc_lsc_isr - Handle LSC events
+ * @ccdc: Pointer to ISP CCDC device.
+ * @events: LSC events
+ */
+static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events)
+{
+	unsigned long flags;
+
+	if (events & IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ) {
+		struct isp_pipeline *pipe =
+			to_isp_pipeline(&ccdc->subdev.entity);
+
+		ccdc_lsc_error_handler(ccdc);
+		pipe->error = true;
+		dev_dbg(to_device(ccdc), "lsc prefetch error\n");
+	}
+
+	if (!(events & IRQ0STATUS_CCDC_LSC_DONE_IRQ))
+		return;
+
+	/* LSC_DONE interrupt occur, there are two cases
+	 * 1. stopping for reconfiguration
+	 * 2. stopping because of STREAM OFF command
+	 */
+	spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+
+	if (ccdc->lsc.state == LSC_STATE_STOPPING)
+		ccdc->lsc.state = LSC_STATE_STOPPED;
+
+	if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE))
+		goto done;
+
+	if (ccdc->lsc.state != LSC_STATE_RECONFIG)
+		goto done;
+
+	/* LSC is in STOPPING state, change to the new state */
+	ccdc->lsc.state = LSC_STATE_STOPPED;
+
+	/* This is an exception. Start of frame and LSC_DONE interrupt
+	 * have been received on the same time. Skip this event and wait
+	 * for better times.
+	 */
+	if (events & IRQ0STATUS_HS_VS_IRQ)
+		goto done;
+
+	/* The LSC engine is stopped at this point. Enable it if there's a
+	 * pending request.
+	 */
+	if (ccdc->lsc.request == NULL)
+		goto done;
+
+	ccdc_lsc_enable(ccdc);
+
+done:
+	spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+}
+
+static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
+{
+	struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
+	struct isp_device *isp = to_isp_device(ccdc);
+	struct isp_buffer *buffer;
+	int restart = 0;
+
+	/* The CCDC generates VD0 interrupts even when disabled (the datasheet
+	 * doesn't explicitly state if that's supposed to happen or not, so it
+	 * can be considered as a hardware bug or as a feature, but we have to
+	 * deal with it anyway). Disabling the CCDC when no buffer is available
+	 * would thus not be enough, we need to handle the situation explicitly.
+	 */
+	if (list_empty(&ccdc->video_out.dmaqueue))
+		goto done;
+
+	/* We're in continuous mode, and memory writes were disabled due to a
+	 * buffer underrun. Reenable them now that we have a buffer. The buffer
+	 * address has been set in ccdc_video_queue.
+	 */
+	if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && ccdc->underrun) {
+		restart = 1;
+		ccdc->underrun = 0;
+		goto done;
+	}
+
+	if (ccdc_sbl_wait_idle(ccdc, 1000)) {
+		dev_info(isp->dev, "CCDC won't become idle!\n");
+		goto done;
+	}
+
+	buffer = omap3isp_video_buffer_next(&ccdc->video_out);
+	if (buffer != NULL) {
+		ccdc_set_outaddr(ccdc, buffer->isp_addr);
+		restart = 1;
+	}
+
+	pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
+
+	if (ccdc->state == ISP_PIPELINE_STREAM_SINGLESHOT &&
+	    isp_pipeline_ready(pipe))
+		omap3isp_pipeline_set_stream(pipe,
+					ISP_PIPELINE_STREAM_SINGLESHOT);
+
+done:
+	return restart;
+}
+
+/*
+ * ccdc_vd0_isr - Handle VD0 event
+ * @ccdc: Pointer to ISP CCDC device.
+ *
+ * Executes LSC deferred enablement before next frame starts.
+ */
+static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc)
+{
+	unsigned long flags;
+	int restart = 0;
+
+	if (ccdc->output & CCDC_OUTPUT_MEMORY)
+		restart = ccdc_isr_buffer(ccdc);
+
+	spin_lock_irqsave(&ccdc->lock, flags);
+	if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) {
+		spin_unlock_irqrestore(&ccdc->lock, flags);
+		return;
+	}
+
+	if (!ccdc->shadow_update)
+		ccdc_apply_controls(ccdc);
+	spin_unlock_irqrestore(&ccdc->lock, flags);
+
+	if (restart)
+		ccdc_enable(ccdc);
+}
+
+/*
+ * ccdc_vd1_isr - Handle VD1 event
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+
+	/*
+	 * Depending on the CCDC pipeline state, CCDC stopping should be
+	 * handled differently. In SINGLESHOT we emulate an internal CCDC
+	 * stopping because the CCDC hw works only in continuous mode.
+	 * When CONTINUOUS pipeline state is used and the CCDC writes it's
+	 * data to memory the CCDC and LSC are stopped immediately but
+	 * without change the CCDC stopping state machine. The CCDC
+	 * stopping state machine should be used only when user request
+	 * for stopping is received (SINGLESHOT is an exeption).
+	 */
+	switch (ccdc->state) {
+	case ISP_PIPELINE_STREAM_SINGLESHOT:
+		ccdc->stopping = CCDC_STOP_REQUEST;
+		break;
+
+	case ISP_PIPELINE_STREAM_CONTINUOUS:
+		if (ccdc->output & CCDC_OUTPUT_MEMORY) {
+			if (ccdc->lsc.state != LSC_STATE_STOPPED)
+				__ccdc_lsc_enable(ccdc, 0);
+			__ccdc_enable(ccdc, 0);
+		}
+		break;
+
+	case ISP_PIPELINE_STREAM_STOPPED:
+		break;
+	}
+
+	if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1))
+		goto done;
+
+	if (ccdc->lsc.request == NULL)
+		goto done;
+
+	/*
+	 * LSC need to be reconfigured. Stop it here and on next LSC_DONE IRQ
+	 * do the appropriate changes in registers
+	 */
+	if (ccdc->lsc.state == LSC_STATE_RUNNING) {
+		__ccdc_lsc_enable(ccdc, 0);
+		ccdc->lsc.state = LSC_STATE_RECONFIG;
+		goto done;
+	}
+
+	/* LSC has been in STOPPED state, enable it */
+	if (ccdc->lsc.state == LSC_STATE_STOPPED)
+		ccdc_lsc_enable(ccdc);
+
+done:
+	spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+}
+
+/*
+ * omap3isp_ccdc_isr - Configure CCDC during interframe time.
+ * @ccdc: Pointer to ISP CCDC device.
+ * @events: CCDC events
+ */
+int omap3isp_ccdc_isr(struct isp_ccdc_device *ccdc, u32 events)
+{
+	if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED)
+		return 0;
+
+	if (events & IRQ0STATUS_CCDC_VD1_IRQ)
+		ccdc_vd1_isr(ccdc);
+
+	ccdc_lsc_isr(ccdc, events);
+
+	if (events & IRQ0STATUS_CCDC_VD0_IRQ)
+		ccdc_vd0_isr(ccdc);
+
+	if (events & IRQ0STATUS_HS_VS_IRQ)
+		ccdc_hs_vs_isr(ccdc);
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP video operations
+ */
+
+static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer)
+{
+	struct isp_ccdc_device *ccdc = &video->isp->isp_ccdc;
+
+	if (!(ccdc->output & CCDC_OUTPUT_MEMORY))
+		return -ENODEV;
+
+	ccdc_set_outaddr(ccdc, buffer->isp_addr);
+
+	/* We now have a buffer queued on the output, restart the pipeline
+	 * on the next CCDC interrupt if running in continuous mode (or when
+	 * starting the stream).
+	 */
+	ccdc->underrun = 1;
+
+	return 0;
+}
+
+static const struct isp_video_operations ccdc_video_ops = {
+	.queue = ccdc_video_queue,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+/*
+ * ccdc_ioctl - CCDC module private ioctl's
+ * @sd: ISP CCDC V4L2 subdevice
+ * @cmd: ioctl command
+ * @arg: ioctl argument
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static long ccdc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+	struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+	int ret;
+
+	switch (cmd) {
+	case VIDIOC_OMAP3ISP_CCDC_CFG:
+		mutex_lock(&ccdc->ioctl_lock);
+		ret = ccdc_config(ccdc, arg);
+		mutex_unlock(&ccdc->ioctl_lock);
+		break;
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	return ret;
+}
+
+static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+				struct v4l2_event_subscription *sub)
+{
+	if (sub->type != V4L2_EVENT_FRAME_SYNC)
+		return -EINVAL;
+
+	/* line number is zero at frame start */
+	if (sub->id != 0)
+		return -EINVAL;
+
+	return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS, NULL);
+}
+
+static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+				  struct v4l2_event_subscription *sub)
+{
+	return v4l2_event_unsubscribe(fh, sub);
+}
+
+/*
+ * ccdc_set_stream - Enable/Disable streaming on the CCDC module
+ * @sd: ISP CCDC V4L2 subdevice
+ * @enable: Enable/disable stream
+ *
+ * When writing to memory, the CCDC hardware can't be enabled without a memory
+ * buffer to write to. As the s_stream operation is called in response to a
+ * STREAMON call without any buffer queued yet, just update the enabled field
+ * and return immediately. The CCDC will be enabled in ccdc_isr_buffer().
+ *
+ * When not writing to memory enable the CCDC immediately.
+ */
+static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+	struct isp_device *isp = to_isp_device(ccdc);
+	int ret = 0;
+
+	if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED) {
+		if (enable == ISP_PIPELINE_STREAM_STOPPED)
+			return 0;
+
+		omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_CCDC);
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+			    ISPCCDC_CFG_VDLC);
+
+		ccdc_configure(ccdc);
+
+		/* TODO: Don't configure the video port if all of its output
+		 * links are inactive.
+		 */
+		ccdc_config_vp(ccdc);
+		ccdc_enable_vp(ccdc, 1);
+		ccdc_print_status(ccdc);
+	}
+
+	switch (enable) {
+	case ISP_PIPELINE_STREAM_CONTINUOUS:
+		if (ccdc->output & CCDC_OUTPUT_MEMORY)
+			omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
+
+		if (ccdc->underrun || !(ccdc->output & CCDC_OUTPUT_MEMORY))
+			ccdc_enable(ccdc);
+
+		ccdc->underrun = 0;
+		break;
+
+	case ISP_PIPELINE_STREAM_SINGLESHOT:
+		if (ccdc->output & CCDC_OUTPUT_MEMORY &&
+		    ccdc->state != ISP_PIPELINE_STREAM_SINGLESHOT)
+			omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
+
+		ccdc_enable(ccdc);
+		break;
+
+	case ISP_PIPELINE_STREAM_STOPPED:
+		ret = ccdc_disable(ccdc);
+		if (ccdc->output & CCDC_OUTPUT_MEMORY)
+			omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
+		omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_CCDC);
+		ccdc->underrun = 0;
+		break;
+	}
+
+	ccdc->state = enable;
+	return ret;
+}
+
+static struct v4l2_mbus_framefmt *
+__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+		  unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_format(fh, pad);
+	else
+		return &ccdc->formats[pad];
+}
+
+static struct v4l2_rect *
+__ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+		enum v4l2_subdev_format_whence which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_crop(fh, CCDC_PAD_SOURCE_OF);
+	else
+		return &ccdc->crop;
+}
+
+/*
+ * ccdc_try_format - Try video format on a pad
+ * @ccdc: ISP CCDC device
+ * @fh : V4L2 subdev file handle
+ * @pad: Pad number
+ * @fmt: Format
+ */
+static void
+ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+		unsigned int pad, struct v4l2_mbus_framefmt *fmt,
+		enum v4l2_subdev_format_whence which)
+{
+	const struct isp_format_info *info;
+	enum v4l2_mbus_pixelcode pixelcode;
+	unsigned int width = fmt->width;
+	unsigned int height = fmt->height;
+	struct v4l2_rect *crop;
+	unsigned int i;
+
+	switch (pad) {
+	case CCDC_PAD_SINK:
+		for (i = 0; i < ARRAY_SIZE(ccdc_fmts); i++) {
+			if (fmt->code == ccdc_fmts[i])
+				break;
+		}
+
+		/* If not found, use SGRBG10 as default */
+		if (i >= ARRAY_SIZE(ccdc_fmts))
+			fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+		/* Clamp the input size. */
+		fmt->width = clamp_t(u32, width, 32, 4096);
+		fmt->height = clamp_t(u32, height, 32, 4096);
+		break;
+
+	case CCDC_PAD_SOURCE_OF:
+		pixelcode = fmt->code;
+		*fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
+
+		/* YUV formats are converted from 2X8 to 1X16 by the bridge and
+		 * can be byte-swapped.
+		 */
+		if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
+		    fmt->code == V4L2_MBUS_FMT_UYVY8_2X8) {
+			/* Use the user requested format if YUV. */
+			if (pixelcode == V4L2_MBUS_FMT_YUYV8_2X8 ||
+			    pixelcode == V4L2_MBUS_FMT_UYVY8_2X8 ||
+			    pixelcode == V4L2_MBUS_FMT_YUYV8_1X16 ||
+			    pixelcode == V4L2_MBUS_FMT_UYVY8_1X16)
+				fmt->code = pixelcode;
+
+			if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8)
+				fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
+			else if (fmt->code == V4L2_MBUS_FMT_UYVY8_2X8)
+				fmt->code = V4L2_MBUS_FMT_UYVY8_1X16;
+		}
+
+		/* Hardcode the output size to the crop rectangle size. */
+		crop = __ccdc_get_crop(ccdc, fh, which);
+		fmt->width = crop->width;
+		fmt->height = crop->height;
+		break;
+
+	case CCDC_PAD_SOURCE_VP:
+		*fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
+
+		/* The video port interface truncates the data to 10 bits. */
+		info = omap3isp_video_format_info(fmt->code);
+		fmt->code = info->truncated;
+
+		/* YUV formats are not supported by the video port. */
+		if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
+		    fmt->code == V4L2_MBUS_FMT_UYVY8_2X8)
+			fmt->code = 0;
+
+		/* The number of lines that can be clocked out from the video
+		 * port output must be at least one line less than the number
+		 * of input lines.
+		 */
+		fmt->width = clamp_t(u32, width, 32, fmt->width);
+		fmt->height = clamp_t(u32, height, 32, fmt->height - 1);
+		break;
+	}
+
+	/* Data is written to memory unpacked, each 10-bit or 12-bit pixel is
+	 * stored on 2 bytes.
+	 */
+	fmt->colorspace = V4L2_COLORSPACE_SRGB;
+	fmt->field = V4L2_FIELD_NONE;
+}
+
+/*
+ * ccdc_try_crop - Validate a crop rectangle
+ * @ccdc: ISP CCDC device
+ * @sink: format on the sink pad
+ * @crop: crop rectangle to be validated
+ */
+static void ccdc_try_crop(struct isp_ccdc_device *ccdc,
+			  const struct v4l2_mbus_framefmt *sink,
+			  struct v4l2_rect *crop)
+{
+	const struct isp_format_info *info;
+	unsigned int max_width;
+
+	/* For Bayer formats, restrict left/top and width/height to even values
+	 * to keep the Bayer pattern.
+	 */
+	info = omap3isp_video_format_info(sink->code);
+	if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) {
+		crop->left &= ~1;
+		crop->top &= ~1;
+	}
+
+	crop->left = clamp_t(u32, crop->left, 0, sink->width - CCDC_MIN_WIDTH);
+	crop->top = clamp_t(u32, crop->top, 0, sink->height - CCDC_MIN_HEIGHT);
+
+	/* The data formatter truncates the number of horizontal output pixels
+	 * to a multiple of 16. To avoid clipping data, allow callers to request
+	 * an output size bigger than the input size up to the nearest multiple
+	 * of 16.
+	 */
+	max_width = (sink->width - crop->left + 15) & ~15;
+	crop->width = clamp_t(u32, crop->width, CCDC_MIN_WIDTH, max_width)
+		    & ~15;
+	crop->height = clamp_t(u32, crop->height, CCDC_MIN_HEIGHT,
+			       sink->height - crop->top);
+
+	/* Odd width/height values don't make sense for Bayer formats. */
+	if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) {
+		crop->width &= ~1;
+		crop->height &= ~1;
+	}
+}
+
+/*
+ * ccdc_enum_mbus_code - Handle pixel format enumeration
+ * @sd     : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @code   : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
+			       struct v4l2_subdev_fh *fh,
+			       struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	switch (code->pad) {
+	case CCDC_PAD_SINK:
+		if (code->index >= ARRAY_SIZE(ccdc_fmts))
+			return -EINVAL;
+
+		code->code = ccdc_fmts[code->index];
+		break;
+
+	case CCDC_PAD_SOURCE_OF:
+		format = __ccdc_get_format(ccdc, fh, code->pad,
+					   V4L2_SUBDEV_FORMAT_TRY);
+
+		if (format->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
+		    format->code == V4L2_MBUS_FMT_UYVY8_2X8) {
+			/* In YUV mode the CCDC can swap bytes. */
+			if (code->index == 0)
+				code->code = V4L2_MBUS_FMT_YUYV8_1X16;
+			else if (code->index == 1)
+				code->code = V4L2_MBUS_FMT_UYVY8_1X16;
+			else
+				return -EINVAL;
+		} else {
+			/* In raw mode, no configurable format confversion is
+			 * available.
+			 */
+			if (code->index == 0)
+				code->code = format->code;
+			else
+				return -EINVAL;
+		}
+		break;
+
+	case CCDC_PAD_SOURCE_VP:
+		/* The CCDC supports no configurable format conversion
+		 * compatible with the video port. Enumerate a single output
+		 * format code.
+		 */
+		if (code->index != 0)
+			return -EINVAL;
+
+		format = __ccdc_get_format(ccdc, fh, code->pad,
+					   V4L2_SUBDEV_FORMAT_TRY);
+
+		/* A pixel code equal to 0 means that the video port doesn't
+		 * support the input format. Don't enumerate any pixel code.
+		 */
+		if (format->code == 0)
+			return -EINVAL;
+
+		code->code = format->code;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt format;
+
+	if (fse->index != 0)
+		return -EINVAL;
+
+	format.code = fse->code;
+	format.width = 1;
+	format.height = 1;
+	ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+	fse->min_width = format.width;
+	fse->min_height = format.height;
+
+	if (format.code != fse->code)
+		return -EINVAL;
+
+	format.code = fse->code;
+	format.width = -1;
+	format.height = -1;
+	ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+	fse->max_width = format.width;
+	fse->max_height = format.height;
+
+	return 0;
+}
+
+/*
+ * ccdc_get_selection - Retrieve a selection rectangle on a pad
+ * @sd: ISP CCDC V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangles are the crop rectangles on the output formatter
+ * source pad.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_selection *sel)
+{
+	struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	if (sel->pad != CCDC_PAD_SOURCE_OF)
+		return -EINVAL;
+
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		sel->r.left = 0;
+		sel->r.top = 0;
+		sel->r.width = INT_MAX;
+		sel->r.height = INT_MAX;
+
+		format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which);
+		ccdc_try_crop(ccdc, format, &sel->r);
+		break;
+
+	case V4L2_SEL_TGT_CROP:
+		sel->r = *__ccdc_get_crop(ccdc, fh, sel->which);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * ccdc_set_selection - Set a selection rectangle on a pad
+ * @sd: ISP CCDC V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangle is the actual crop rectangle on the output
+ * formatter source pad.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_selection *sel)
+{
+	struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	if (sel->target != V4L2_SEL_TGT_CROP ||
+	    sel->pad != CCDC_PAD_SOURCE_OF)
+		return -EINVAL;
+
+	/* The crop rectangle can't be changed while streaming. */
+	if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED)
+		return -EBUSY;
+
+	/* Modifying the crop rectangle always changes the format on the source
+	 * pad. If the KEEP_CONFIG flag is set, just return the current crop
+	 * rectangle.
+	 */
+	if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
+		sel->r = *__ccdc_get_crop(ccdc, fh, sel->which);
+		return 0;
+	}
+
+	format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which);
+	ccdc_try_crop(ccdc, format, &sel->r);
+	*__ccdc_get_crop(ccdc, fh, sel->which) = sel->r;
+
+	/* Update the source format. */
+	format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, sel->which);
+	ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format, sel->which);
+
+	return 0;
+}
+
+/*
+ * ccdc_get_format - Retrieve the video format on a pad
+ * @sd : ISP CCDC V4L2 subdevice
+ * @fh : V4L2 subdev file handle
+ * @fmt: Format
+ *
+ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
+ * to the format type.
+ */
+static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			   struct v4l2_subdev_format *fmt)
+{
+	struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
+	if (format == NULL)
+		return -EINVAL;
+
+	fmt->format = *format;
+	return 0;
+}
+
+/*
+ * ccdc_set_format - Set the video format on a pad
+ * @sd : ISP CCDC V4L2 subdevice
+ * @fh : V4L2 subdev file handle
+ * @fmt: Format
+ *
+ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
+ * to the format type.
+ */
+static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			   struct v4l2_subdev_format *fmt)
+{
+	struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+	struct v4l2_rect *crop;
+
+	format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
+	if (format == NULL)
+		return -EINVAL;
+
+	ccdc_try_format(ccdc, fh, fmt->pad, &fmt->format, fmt->which);
+	*format = fmt->format;
+
+	/* Propagate the format from sink to source */
+	if (fmt->pad == CCDC_PAD_SINK) {
+		/* Reset the crop rectangle. */
+		crop = __ccdc_get_crop(ccdc, fh, fmt->which);
+		crop->left = 0;
+		crop->top = 0;
+		crop->width = fmt->format.width;
+		crop->height = fmt->format.height;
+
+		ccdc_try_crop(ccdc, &fmt->format, crop);
+
+		/* Update the source formats. */
+		format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF,
+					   fmt->which);
+		*format = fmt->format;
+		ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format,
+				fmt->which);
+
+		format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_VP,
+					   fmt->which);
+		*format = fmt->format;
+		ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_VP, format,
+				fmt->which);
+	}
+
+	return 0;
+}
+
+/*
+ * Decide whether desired output pixel code can be obtained with
+ * the lane shifter by shifting the input pixel code.
+ * @in: input pixelcode to shifter
+ * @out: output pixelcode from shifter
+ * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0]
+ *
+ * return true if the combination is possible
+ * return false otherwise
+ */
+static bool ccdc_is_shiftable(enum v4l2_mbus_pixelcode in,
+			      enum v4l2_mbus_pixelcode out,
+			      unsigned int additional_shift)
+{
+	const struct isp_format_info *in_info, *out_info;
+
+	if (in == out)
+		return true;
+
+	in_info = omap3isp_video_format_info(in);
+	out_info = omap3isp_video_format_info(out);
+
+	if ((in_info->flavor == 0) || (out_info->flavor == 0))
+		return false;
+
+	if (in_info->flavor != out_info->flavor)
+		return false;
+
+	return in_info->width - out_info->width + additional_shift <= 6;
+}
+
+static int ccdc_link_validate(struct v4l2_subdev *sd,
+			      struct media_link *link,
+			      struct v4l2_subdev_format *source_fmt,
+			      struct v4l2_subdev_format *sink_fmt)
+{
+	struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+	unsigned long parallel_shift;
+
+	/* Check if the two ends match */
+	if (source_fmt->format.width != sink_fmt->format.width ||
+	    source_fmt->format.height != sink_fmt->format.height)
+		return -EPIPE;
+
+	/* We've got a parallel sensor here. */
+	if (ccdc->input == CCDC_INPUT_PARALLEL) {
+		struct isp_parallel_platform_data *pdata =
+			&((struct isp_v4l2_subdevs_group *)
+			  media_entity_to_v4l2_subdev(link->source->entity)
+			  ->host_priv)->bus.parallel;
+		parallel_shift = pdata->data_lane_shift * 2;
+	} else {
+		parallel_shift = 0;
+	}
+
+	/* Lane shifter may be used to drop bits on CCDC sink pad */
+	if (!ccdc_is_shiftable(source_fmt->format.code,
+			       sink_fmt->format.code, parallel_shift))
+		return -EPIPE;
+
+	return 0;
+}
+
+/*
+ * ccdc_init_formats - Initialize formats on all pads
+ * @sd: ISP CCDC V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct v4l2_subdev_format format;
+
+	memset(&format, 0, sizeof(format));
+	format.pad = CCDC_PAD_SINK;
+	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+	format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+	format.format.width = 4096;
+	format.format.height = 4096;
+	ccdc_set_format(sd, fh, &format);
+
+	return 0;
+}
+
+/* V4L2 subdev core operations */
+static const struct v4l2_subdev_core_ops ccdc_v4l2_core_ops = {
+	.ioctl = ccdc_ioctl,
+	.subscribe_event = ccdc_subscribe_event,
+	.unsubscribe_event = ccdc_unsubscribe_event,
+};
+
+/* V4L2 subdev video operations */
+static const struct v4l2_subdev_video_ops ccdc_v4l2_video_ops = {
+	.s_stream = ccdc_set_stream,
+};
+
+/* V4L2 subdev pad operations */
+static const struct v4l2_subdev_pad_ops ccdc_v4l2_pad_ops = {
+	.enum_mbus_code = ccdc_enum_mbus_code,
+	.enum_frame_size = ccdc_enum_frame_size,
+	.get_fmt = ccdc_get_format,
+	.set_fmt = ccdc_set_format,
+	.get_selection = ccdc_get_selection,
+	.set_selection = ccdc_set_selection,
+	.link_validate = ccdc_link_validate,
+};
+
+/* V4L2 subdev operations */
+static const struct v4l2_subdev_ops ccdc_v4l2_ops = {
+	.core = &ccdc_v4l2_core_ops,
+	.video = &ccdc_v4l2_video_ops,
+	.pad = &ccdc_v4l2_pad_ops,
+};
+
+/* V4L2 subdev internal operations */
+static const struct v4l2_subdev_internal_ops ccdc_v4l2_internal_ops = {
+	.open = ccdc_init_formats,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * ccdc_link_setup - Setup CCDC connections
+ * @entity: CCDC media entity
+ * @local: Pad at the local end of the link
+ * @remote: Pad at the remote end of the link
+ * @flags: Link flags
+ *
+ * return -EINVAL or zero on success
+ */
+static int ccdc_link_setup(struct media_entity *entity,
+			   const struct media_pad *local,
+			   const struct media_pad *remote, u32 flags)
+{
+	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+	struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+	struct isp_device *isp = to_isp_device(ccdc);
+
+	switch (local->index | media_entity_type(remote->entity)) {
+	case CCDC_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+		/* Read from the sensor (parallel interface), CCP2, CSI2a or
+		 * CSI2c.
+		 */
+		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+			ccdc->input = CCDC_INPUT_NONE;
+			break;
+		}
+
+		if (ccdc->input != CCDC_INPUT_NONE)
+			return -EBUSY;
+
+		if (remote->entity == &isp->isp_ccp2.subdev.entity)
+			ccdc->input = CCDC_INPUT_CCP2B;
+		else if (remote->entity == &isp->isp_csi2a.subdev.entity)
+			ccdc->input = CCDC_INPUT_CSI2A;
+		else if (remote->entity == &isp->isp_csi2c.subdev.entity)
+			ccdc->input = CCDC_INPUT_CSI2C;
+		else
+			ccdc->input = CCDC_INPUT_PARALLEL;
+
+		break;
+
+	/*
+	 * The ISP core doesn't support pipelines with multiple video outputs.
+	 * Revisit this when it will be implemented, and return -EBUSY for now.
+	 */
+
+	case CCDC_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV:
+		/* Write to preview engine, histogram and H3A. When none of
+		 * those links are active, the video port can be disabled.
+		 */
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			if (ccdc->output & ~CCDC_OUTPUT_PREVIEW)
+				return -EBUSY;
+			ccdc->output |= CCDC_OUTPUT_PREVIEW;
+		} else {
+			ccdc->output &= ~CCDC_OUTPUT_PREVIEW;
+		}
+		break;
+
+	case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_DEVNODE:
+		/* Write to memory */
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			if (ccdc->output & ~CCDC_OUTPUT_MEMORY)
+				return -EBUSY;
+			ccdc->output |= CCDC_OUTPUT_MEMORY;
+		} else {
+			ccdc->output &= ~CCDC_OUTPUT_MEMORY;
+		}
+		break;
+
+	case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_V4L2_SUBDEV:
+		/* Write to resizer */
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			if (ccdc->output & ~CCDC_OUTPUT_RESIZER)
+				return -EBUSY;
+			ccdc->output |= CCDC_OUTPUT_RESIZER;
+		} else {
+			ccdc->output &= ~CCDC_OUTPUT_RESIZER;
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations ccdc_media_ops = {
+	.link_setup = ccdc_link_setup,
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc)
+{
+	v4l2_device_unregister_subdev(&ccdc->subdev);
+	omap3isp_video_unregister(&ccdc->video_out);
+}
+
+int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc,
+	struct v4l2_device *vdev)
+{
+	int ret;
+
+	/* Register the subdev and video node. */
+	ret = v4l2_device_register_subdev(vdev, &ccdc->subdev);
+	if (ret < 0)
+		goto error;
+
+	ret = omap3isp_video_register(&ccdc->video_out, vdev);
+	if (ret < 0)
+		goto error;
+
+	return 0;
+
+error:
+	omap3isp_ccdc_unregister_entities(ccdc);
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP CCDC initialisation and cleanup
+ */
+
+/*
+ * ccdc_init_entities - Initialize V4L2 subdev and media entity
+ * @ccdc: ISP CCDC module
+ *
+ * Return 0 on success and a negative error code on failure.
+ */
+static int ccdc_init_entities(struct isp_ccdc_device *ccdc)
+{
+	struct v4l2_subdev *sd = &ccdc->subdev;
+	struct media_pad *pads = ccdc->pads;
+	struct media_entity *me = &sd->entity;
+	int ret;
+
+	ccdc->input = CCDC_INPUT_NONE;
+
+	v4l2_subdev_init(sd, &ccdc_v4l2_ops);
+	sd->internal_ops = &ccdc_v4l2_internal_ops;
+	strlcpy(sd->name, "OMAP3 ISP CCDC", sizeof(sd->name));
+	sd->grp_id = 1 << 16;	/* group ID for isp subdevs */
+	v4l2_set_subdevdata(sd, ccdc);
+	sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	pads[CCDC_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;
+	pads[CCDC_PAD_SOURCE_OF].flags = MEDIA_PAD_FL_SOURCE;
+
+	me->ops = &ccdc_media_ops;
+	ret = media_entity_init(me, CCDC_PADS_NUM, pads, 0);
+	if (ret < 0)
+		return ret;
+
+	ccdc_init_formats(sd, NULL);
+
+	ccdc->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	ccdc->video_out.ops = &ccdc_video_ops;
+	ccdc->video_out.isp = to_isp_device(ccdc);
+	ccdc->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
+	ccdc->video_out.bpl_alignment = 32;
+
+	ret = omap3isp_video_init(&ccdc->video_out, "CCDC");
+	if (ret < 0)
+		goto error_video;
+
+	/* Connect the CCDC subdev to the video node. */
+	ret = media_entity_create_link(&ccdc->subdev.entity, CCDC_PAD_SOURCE_OF,
+			&ccdc->video_out.video.entity, 0, 0);
+	if (ret < 0)
+		goto error_link;
+
+	return 0;
+
+error_link:
+	omap3isp_video_cleanup(&ccdc->video_out);
+error_video:
+	media_entity_cleanup(me);
+	return ret;
+}
+
+/*
+ * omap3isp_ccdc_init - CCDC module initialization.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ *
+ * TODO: Get the initialisation values from platform data.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+int omap3isp_ccdc_init(struct isp_device *isp)
+{
+	struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
+	int ret;
+
+	spin_lock_init(&ccdc->lock);
+	init_waitqueue_head(&ccdc->wait);
+	mutex_init(&ccdc->ioctl_lock);
+
+	ccdc->stopping = CCDC_STOP_NOT_REQUESTED;
+
+	INIT_WORK(&ccdc->lsc.table_work, ccdc_lsc_free_table_work);
+	ccdc->lsc.state = LSC_STATE_STOPPED;
+	INIT_LIST_HEAD(&ccdc->lsc.free_queue);
+	spin_lock_init(&ccdc->lsc.req_lock);
+
+	ccdc->clamp.oblen = 0;
+	ccdc->clamp.dcsubval = 0;
+
+	ccdc->update = OMAP3ISP_CCDC_BLCLAMP;
+	ccdc_apply_controls(ccdc);
+
+	ret = ccdc_init_entities(ccdc);
+	if (ret < 0) {
+		mutex_destroy(&ccdc->ioctl_lock);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * omap3isp_ccdc_cleanup - CCDC module cleanup.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ */
+void omap3isp_ccdc_cleanup(struct isp_device *isp)
+{
+	struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
+
+	omap3isp_video_cleanup(&ccdc->video_out);
+	media_entity_cleanup(&ccdc->subdev.entity);
+
+	/* Free LSC requests. As the CCDC is stopped there's no active request,
+	 * so only the pending request and the free queue need to be handled.
+	 */
+	ccdc_lsc_free_request(ccdc, ccdc->lsc.request);
+	cancel_work_sync(&ccdc->lsc.table_work);
+	ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue);
+
+	if (ccdc->fpc.fpcaddr != 0)
+		omap_iommu_vfree(isp->domain, isp->dev, ccdc->fpc.fpcaddr);
+
+	mutex_destroy(&ccdc->ioctl_lock);
+}
diff --git a/drivers/media/platform/omap3isp/ispccdc.h b/drivers/media/platform/omap3isp/ispccdc.h
new file mode 100644
index 0000000..a5da9e1
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispccdc.h
@@ -0,0 +1,172 @@
+/*
+ * ispccdc.h
+ *
+ * TI OMAP3 ISP - CCDC module
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_CCDC_H
+#define OMAP3_ISP_CCDC_H
+
+#include <linux/omap3isp.h>
+#include <linux/workqueue.h>
+
+#include "ispvideo.h"
+
+enum ccdc_input_entity {
+	CCDC_INPUT_NONE,
+	CCDC_INPUT_PARALLEL,
+	CCDC_INPUT_CSI2A,
+	CCDC_INPUT_CCP2B,
+	CCDC_INPUT_CSI2C
+};
+
+#define CCDC_OUTPUT_MEMORY	(1 << 0)
+#define CCDC_OUTPUT_PREVIEW	(1 << 1)
+#define CCDC_OUTPUT_RESIZER	(1 << 2)
+
+#define	OMAP3ISP_CCDC_NEVENTS	16
+
+enum ispccdc_lsc_state {
+	LSC_STATE_STOPPED = 0,
+	LSC_STATE_STOPPING = 1,
+	LSC_STATE_RUNNING = 2,
+	LSC_STATE_RECONFIG = 3,
+};
+
+struct ispccdc_lsc_config_req {
+	struct list_head list;
+	struct omap3isp_ccdc_lsc_config config;
+	unsigned char enable;
+	u32 table;
+	struct iovm_struct *iovm;
+};
+
+/*
+ * ispccdc_lsc - CCDC LSC parameters
+ * @update_config: Set when user changes config
+ * @request_enable: Whether LSC is requested to be enabled
+ * @config: LSC config set by user
+ * @update_table: Set when user provides a new LSC table to table_new
+ * @table_new: LSC table set by user, ISP address
+ * @table_inuse: LSC table currently in use, ISP address
+ */
+struct ispccdc_lsc {
+	enum ispccdc_lsc_state state;
+	struct work_struct table_work;
+
+	/* LSC queue of configurations */
+	spinlock_t req_lock;
+	struct ispccdc_lsc_config_req *request;	/* requested configuration */
+	struct ispccdc_lsc_config_req *active;	/* active configuration */
+	struct list_head free_queue;	/* configurations for freeing */
+};
+
+#define CCDC_STOP_NOT_REQUESTED		0x00
+#define CCDC_STOP_REQUEST		0x01
+#define CCDC_STOP_EXECUTED		(0x02 | CCDC_STOP_REQUEST)
+#define CCDC_STOP_CCDC_FINISHED		0x04
+#define CCDC_STOP_LSC_FINISHED		0x08
+#define CCDC_STOP_FINISHED		\
+	(CCDC_STOP_EXECUTED | CCDC_STOP_CCDC_FINISHED | CCDC_STOP_LSC_FINISHED)
+
+#define CCDC_EVENT_VD1			0x10
+#define CCDC_EVENT_VD0			0x20
+#define CCDC_EVENT_LSC_DONE		0x40
+
+/* Sink and source CCDC pads */
+#define CCDC_PAD_SINK			0
+#define CCDC_PAD_SOURCE_OF		1
+#define CCDC_PAD_SOURCE_VP		2
+#define CCDC_PADS_NUM			3
+
+/*
+ * struct isp_ccdc_device - Structure for the CCDC module to store its own
+ *			    information
+ * @subdev: V4L2 subdevice
+ * @pads: Sink and source media entity pads
+ * @formats: Active video formats
+ * @crop: Active crop rectangle on the OF source pad
+ * @input: Active input
+ * @output: Active outputs
+ * @video_out: Output video node
+ * @alaw: A-law compression enabled (1) or disabled (0)
+ * @lpf: Low pass filter enabled (1) or disabled (0)
+ * @obclamp: Optical-black clamp enabled (1) or disabled (0)
+ * @fpc_en: Faulty pixels correction enabled (1) or disabled (0)
+ * @blcomp: Black level compensation configuration
+ * @clamp: Optical-black or digital clamp configuration
+ * @fpc: Faulty pixels correction configuration
+ * @lsc: Lens shading compensation configuration
+ * @update: Bitmask of controls to update during the next interrupt
+ * @shadow_update: Controls update in progress by userspace
+ * @underrun: A buffer underrun occurred and a new buffer has been queued
+ * @state: Streaming state
+ * @lock: Serializes shadow_update with interrupt handler
+ * @wait: Wait queue used to stop the module
+ * @stopping: Stopping state
+ * @ioctl_lock: Serializes ioctl calls and LSC requests freeing
+ */
+struct isp_ccdc_device {
+	struct v4l2_subdev subdev;
+	struct media_pad pads[CCDC_PADS_NUM];
+	struct v4l2_mbus_framefmt formats[CCDC_PADS_NUM];
+	struct v4l2_rect crop;
+
+	enum ccdc_input_entity input;
+	unsigned int output;
+	struct isp_video video_out;
+
+	unsigned int alaw:1,
+		     lpf:1,
+		     obclamp:1,
+		     fpc_en:1;
+	struct omap3isp_ccdc_blcomp blcomp;
+	struct omap3isp_ccdc_bclamp clamp;
+	struct omap3isp_ccdc_fpc fpc;
+	struct ispccdc_lsc lsc;
+	unsigned int update;
+	unsigned int shadow_update;
+
+	unsigned int underrun:1;
+	enum isp_pipeline_stream_state state;
+	spinlock_t lock;
+	wait_queue_head_t wait;
+	unsigned int stopping;
+	struct mutex ioctl_lock;
+};
+
+struct isp_device;
+
+int omap3isp_ccdc_init(struct isp_device *isp);
+void omap3isp_ccdc_cleanup(struct isp_device *isp);
+int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc,
+	struct v4l2_device *vdev);
+void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc);
+
+int omap3isp_ccdc_busy(struct isp_ccdc_device *isp_ccdc);
+int omap3isp_ccdc_isr(struct isp_ccdc_device *isp_ccdc, u32 events);
+void omap3isp_ccdc_restore_context(struct isp_device *isp);
+void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc,
+	unsigned int *max_rate);
+
+#endif	/* OMAP3_ISP_CCDC_H */
diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c
new file mode 100644
index 0000000..85f0de8
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispccp2.c
@@ -0,0 +1,1171 @@
+/*
+ * ispccp2.c
+ *
+ * TI OMAP3 ISP - CCP2 module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/regulator/consumer.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispccp2.h"
+
+/* Number of LCX channels */
+#define CCP2_LCx_CHANS_NUM			3
+/* Max/Min size for CCP2 video port */
+#define ISPCCP2_DAT_START_MIN			0
+#define ISPCCP2_DAT_START_MAX			4095
+#define ISPCCP2_DAT_SIZE_MIN			0
+#define ISPCCP2_DAT_SIZE_MAX			4095
+#define ISPCCP2_VPCLK_FRACDIV			65536
+#define ISPCCP2_LCx_CTRL_FORMAT_RAW8_DPCM10_VP	0x12
+#define ISPCCP2_LCx_CTRL_FORMAT_RAW10_VP	0x16
+/* Max/Min size for CCP2 memory channel */
+#define ISPCCP2_LCM_HSIZE_COUNT_MIN		16
+#define ISPCCP2_LCM_HSIZE_COUNT_MAX		8191
+#define ISPCCP2_LCM_HSIZE_SKIP_MIN		0
+#define ISPCCP2_LCM_HSIZE_SKIP_MAX		8191
+#define ISPCCP2_LCM_VSIZE_MIN			1
+#define ISPCCP2_LCM_VSIZE_MAX			8191
+#define ISPCCP2_LCM_HWORDS_MIN			1
+#define ISPCCP2_LCM_HWORDS_MAX			4095
+#define ISPCCP2_LCM_CTRL_BURST_SIZE_32X		5
+#define ISPCCP2_LCM_CTRL_READ_THROTTLE_FULL	0
+#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_DPCM10	2
+#define ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW8	2
+#define ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW10	3
+#define ISPCCP2_LCM_CTRL_DST_FORMAT_RAW10	3
+#define ISPCCP2_LCM_CTRL_DST_PORT_VP		0
+#define ISPCCP2_LCM_CTRL_DST_PORT_MEM		1
+
+/* Set only the required bits */
+#define BIT_SET(var, shift, mask, val)			\
+	do {						\
+		var = ((var) & ~((mask) << (shift)))	\
+			| ((val) << (shift));		\
+	} while (0)
+
+/*
+ * ccp2_print_status - Print current CCP2 module register values.
+ */
+#define CCP2_PRINT_REGISTER(isp, name)\
+	dev_dbg(isp->dev, "###CCP2 " #name "=0x%08x\n", \
+		isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_##name))
+
+static void ccp2_print_status(struct isp_ccp2_device *ccp2)
+{
+	struct isp_device *isp = to_isp_device(ccp2);
+
+	dev_dbg(isp->dev, "-------------CCP2 Register dump-------------\n");
+
+	CCP2_PRINT_REGISTER(isp, SYSCONFIG);
+	CCP2_PRINT_REGISTER(isp, SYSSTATUS);
+	CCP2_PRINT_REGISTER(isp, LC01_IRQENABLE);
+	CCP2_PRINT_REGISTER(isp, LC01_IRQSTATUS);
+	CCP2_PRINT_REGISTER(isp, LC23_IRQENABLE);
+	CCP2_PRINT_REGISTER(isp, LC23_IRQSTATUS);
+	CCP2_PRINT_REGISTER(isp, LCM_IRQENABLE);
+	CCP2_PRINT_REGISTER(isp, LCM_IRQSTATUS);
+	CCP2_PRINT_REGISTER(isp, CTRL);
+	CCP2_PRINT_REGISTER(isp, LCx_CTRL(0));
+	CCP2_PRINT_REGISTER(isp, LCx_CODE(0));
+	CCP2_PRINT_REGISTER(isp, LCx_STAT_START(0));
+	CCP2_PRINT_REGISTER(isp, LCx_STAT_SIZE(0));
+	CCP2_PRINT_REGISTER(isp, LCx_SOF_ADDR(0));
+	CCP2_PRINT_REGISTER(isp, LCx_EOF_ADDR(0));
+	CCP2_PRINT_REGISTER(isp, LCx_DAT_START(0));
+	CCP2_PRINT_REGISTER(isp, LCx_DAT_SIZE(0));
+	CCP2_PRINT_REGISTER(isp, LCx_DAT_PING_ADDR(0));
+	CCP2_PRINT_REGISTER(isp, LCx_DAT_PONG_ADDR(0));
+	CCP2_PRINT_REGISTER(isp, LCx_DAT_OFST(0));
+	CCP2_PRINT_REGISTER(isp, LCM_CTRL);
+	CCP2_PRINT_REGISTER(isp, LCM_VSIZE);
+	CCP2_PRINT_REGISTER(isp, LCM_HSIZE);
+	CCP2_PRINT_REGISTER(isp, LCM_PREFETCH);
+	CCP2_PRINT_REGISTER(isp, LCM_SRC_ADDR);
+	CCP2_PRINT_REGISTER(isp, LCM_SRC_OFST);
+	CCP2_PRINT_REGISTER(isp, LCM_DST_ADDR);
+	CCP2_PRINT_REGISTER(isp, LCM_DST_OFST);
+
+	dev_dbg(isp->dev, "--------------------------------------------\n");
+}
+
+/*
+ * ccp2_reset - Reset the CCP2
+ * @ccp2: pointer to ISP CCP2 device
+ */
+static void ccp2_reset(struct isp_ccp2_device *ccp2)
+{
+	struct isp_device *isp = to_isp_device(ccp2);
+	int i = 0;
+
+	/* Reset the CSI1/CCP2B and wait for reset to complete */
+	isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG,
+		    ISPCCP2_SYSCONFIG_SOFT_RESET);
+	while (!(isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSSTATUS) &
+		 ISPCCP2_SYSSTATUS_RESET_DONE)) {
+		udelay(10);
+		if (i++ > 10) {  /* try read 10 times */
+			dev_warn(isp->dev,
+				"omap3_isp: timeout waiting for ccp2 reset\n");
+			break;
+		}
+	}
+}
+
+/*
+ * ccp2_pwr_cfg - Configure the power mode settings
+ * @ccp2: pointer to ISP CCP2 device
+ */
+static void ccp2_pwr_cfg(struct isp_ccp2_device *ccp2)
+{
+	struct isp_device *isp = to_isp_device(ccp2);
+
+	isp_reg_writel(isp, ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SMART |
+			((isp->revision == ISP_REVISION_15_0 && isp->autoidle) ?
+			  ISPCCP2_SYSCONFIG_AUTO_IDLE : 0),
+		       OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG);
+}
+
+/*
+ * ccp2_if_enable - Enable CCP2 interface.
+ * @ccp2: pointer to ISP CCP2 device
+ * @enable: enable/disable flag
+ */
+static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable)
+{
+	struct isp_device *isp = to_isp_device(ccp2);
+	int i;
+
+	if (enable && ccp2->vdds_csib)
+		regulator_enable(ccp2->vdds_csib);
+
+	/* Enable/Disable all the LCx channels */
+	for (i = 0; i < CCP2_LCx_CHANS_NUM; i++)
+		isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(i),
+				ISPCCP2_LCx_CTRL_CHAN_EN,
+				enable ? ISPCCP2_LCx_CTRL_CHAN_EN : 0);
+
+	/* Enable/Disable ccp2 interface in ccp2 mode */
+	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL,
+			ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN,
+			enable ? (ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN) : 0);
+
+	if (!enable && ccp2->vdds_csib)
+		regulator_disable(ccp2->vdds_csib);
+}
+
+/*
+ * ccp2_mem_enable - Enable CCP2 memory interface.
+ * @ccp2: pointer to ISP CCP2 device
+ * @enable: enable/disable flag
+ */
+static void ccp2_mem_enable(struct isp_ccp2_device *ccp2, u8 enable)
+{
+	struct isp_device *isp = to_isp_device(ccp2);
+
+	if (enable)
+		ccp2_if_enable(ccp2, 0);
+
+	/* Enable/Disable ccp2 interface in ccp2 mode */
+	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL,
+			ISPCCP2_CTRL_MODE, enable ? ISPCCP2_CTRL_MODE : 0);
+
+	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_CTRL,
+			ISPCCP2_LCM_CTRL_CHAN_EN,
+			enable ? ISPCCP2_LCM_CTRL_CHAN_EN : 0);
+}
+
+/*
+ * ccp2_phyif_config - Initialize CCP2 phy interface config
+ * @ccp2: Pointer to ISP CCP2 device
+ * @config: CCP2 platform data
+ *
+ * Configure the CCP2 physical interface module from platform data.
+ *
+ * Returns -EIO if strobe is chosen in CSI1 mode, or 0 on success.
+ */
+static int ccp2_phyif_config(struct isp_ccp2_device *ccp2,
+			     const struct isp_ccp2_platform_data *pdata)
+{
+	struct isp_device *isp = to_isp_device(ccp2);
+	u32 val;
+
+	/* CCP2B mode */
+	val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL) |
+			    ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE;
+	/* Data/strobe physical layer */
+	BIT_SET(val, ISPCCP2_CTRL_PHY_SEL_SHIFT, ISPCCP2_CTRL_PHY_SEL_MASK,
+		pdata->phy_layer);
+	BIT_SET(val, ISPCCP2_CTRL_INV_SHIFT, ISPCCP2_CTRL_INV_MASK,
+		pdata->strobe_clk_pol);
+	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL);
+
+	val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL);
+	if (!(val & ISPCCP2_CTRL_MODE)) {
+		if (pdata->ccp2_mode == ISP_CCP2_MODE_CCP2)
+			dev_warn(isp->dev, "OMAP3 CCP2 bus not available\n");
+		if (pdata->phy_layer == ISP_CCP2_PHY_DATA_STROBE)
+			/* Strobe mode requires CCP2 */
+			return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ * ccp2_vp_config - Initialize CCP2 video port interface.
+ * @ccp2: Pointer to ISP CCP2 device
+ * @vpclk_div: Video port divisor
+ *
+ * Configure the CCP2 video port with the given clock divisor. The valid divisor
+ * values depend on the ISP revision:
+ *
+ * - revision 1.0 and 2.0	1 to 4
+ * - revision 15.0		1 to 65536
+ *
+ * The exact divisor value used might differ from the requested value, as ISP
+ * revision 15.0 represent the divisor by 65536 divided by an integer.
+ */
+static void ccp2_vp_config(struct isp_ccp2_device *ccp2,
+			   unsigned int vpclk_div)
+{
+	struct isp_device *isp = to_isp_device(ccp2);
+	u32 val;
+
+	/* ISPCCP2_CTRL Video port */
+	val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL);
+	val |= ISPCCP2_CTRL_VP_ONLY_EN;	/* Disable the memory write port */
+
+	if (isp->revision == ISP_REVISION_15_0) {
+		vpclk_div = clamp_t(unsigned int, vpclk_div, 1, 65536);
+		vpclk_div = min(ISPCCP2_VPCLK_FRACDIV / vpclk_div, 65535U);
+		BIT_SET(val, ISPCCP2_CTRL_VPCLK_DIV_SHIFT,
+			ISPCCP2_CTRL_VPCLK_DIV_MASK, vpclk_div);
+	} else {
+		vpclk_div = clamp_t(unsigned int, vpclk_div, 1, 4);
+		BIT_SET(val, ISPCCP2_CTRL_VP_OUT_CTRL_SHIFT,
+			ISPCCP2_CTRL_VP_OUT_CTRL_MASK, vpclk_div - 1);
+	}
+
+	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL);
+}
+
+/*
+ * ccp2_lcx_config - Initialize CCP2 logical channel interface.
+ * @ccp2: Pointer to ISP CCP2 device
+ * @config: Pointer to ISP LCx config structure.
+ *
+ * This will analyze the parameters passed by the interface config
+ * and configure CSI1/CCP2 logical channel
+ *
+ */
+static void ccp2_lcx_config(struct isp_ccp2_device *ccp2,
+			    struct isp_interface_lcx_config *config)
+{
+	struct isp_device *isp = to_isp_device(ccp2);
+	u32 val, format;
+
+	switch (config->format) {
+	case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+		format = ISPCCP2_LCx_CTRL_FORMAT_RAW8_DPCM10_VP;
+		break;
+	case V4L2_MBUS_FMT_SGRBG10_1X10:
+	default:
+		format = ISPCCP2_LCx_CTRL_FORMAT_RAW10_VP;	/* RAW10+VP */
+		break;
+	}
+	/* ISPCCP2_LCx_CTRL logical channel #0 */
+	val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(0))
+			    | (ISPCCP2_LCx_CTRL_REGION_EN); /* Region */
+
+	if (isp->revision == ISP_REVISION_15_0) {
+		/* CRC */
+		BIT_SET(val, ISPCCP2_LCx_CTRL_CRC_SHIFT_15_0,
+			ISPCCP2_LCx_CTRL_CRC_MASK,
+			config->crc);
+		/* Format = RAW10+VP or RAW8+DPCM10+VP*/
+		BIT_SET(val, ISPCCP2_LCx_CTRL_FORMAT_SHIFT_15_0,
+			ISPCCP2_LCx_CTRL_FORMAT_MASK_15_0, format);
+	} else {
+		BIT_SET(val, ISPCCP2_LCx_CTRL_CRC_SHIFT,
+			ISPCCP2_LCx_CTRL_CRC_MASK,
+			config->crc);
+
+		BIT_SET(val, ISPCCP2_LCx_CTRL_FORMAT_SHIFT,
+			ISPCCP2_LCx_CTRL_FORMAT_MASK, format);
+	}
+	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(0));
+
+	/* ISPCCP2_DAT_START for logical channel #0 */
+	isp_reg_writel(isp, config->data_start << ISPCCP2_LCx_DAT_SHIFT,
+		       OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_DAT_START(0));
+
+	/* ISPCCP2_DAT_SIZE for logical channel #0 */
+	isp_reg_writel(isp, config->data_size << ISPCCP2_LCx_DAT_SHIFT,
+		       OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_DAT_SIZE(0));
+
+	/* Enable error IRQs for logical channel #0 */
+	val = ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ |
+	      ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ |
+	      ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ |
+	      ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ |
+	      ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ |
+	      ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ;
+
+	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQSTATUS);
+	isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, val);
+}
+
+/*
+ * ccp2_if_configure - Configure ccp2 with data from sensor
+ * @ccp2: Pointer to ISP CCP2 device
+ *
+ * Return 0 on success or a negative error code
+ */
+static int ccp2_if_configure(struct isp_ccp2_device *ccp2)
+{
+	const struct isp_v4l2_subdevs_group *pdata;
+	struct v4l2_mbus_framefmt *format;
+	struct media_pad *pad;
+	struct v4l2_subdev *sensor;
+	u32 lines = 0;
+	int ret;
+
+	ccp2_pwr_cfg(ccp2);
+
+	pad = media_entity_remote_source(&ccp2->pads[CCP2_PAD_SINK]);
+	sensor = media_entity_to_v4l2_subdev(pad->entity);
+	pdata = sensor->host_priv;
+
+	ret = ccp2_phyif_config(ccp2, &pdata->bus.ccp2);
+	if (ret < 0)
+		return ret;
+
+	ccp2_vp_config(ccp2, pdata->bus.ccp2.vpclk_div + 1);
+
+	v4l2_subdev_call(sensor, sensor, g_skip_top_lines, &lines);
+
+	format = &ccp2->formats[CCP2_PAD_SINK];
+
+	ccp2->if_cfg.data_start = lines;
+	ccp2->if_cfg.crc = pdata->bus.ccp2.crc;
+	ccp2->if_cfg.format = format->code;
+	ccp2->if_cfg.data_size = format->height;
+
+	ccp2_lcx_config(ccp2, &ccp2->if_cfg);
+
+	return 0;
+}
+
+static int ccp2_adjust_bandwidth(struct isp_ccp2_device *ccp2)
+{
+	struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
+	struct isp_device *isp = to_isp_device(ccp2);
+	const struct v4l2_mbus_framefmt *ofmt = &ccp2->formats[CCP2_PAD_SOURCE];
+	unsigned long l3_ick = pipe->l3_ick;
+	struct v4l2_fract *timeperframe;
+	unsigned int vpclk_div = 2;
+	unsigned int value;
+	u64 bound;
+	u64 area;
+
+	/* Compute the minimum clock divisor, based on the pipeline maximum
+	 * data rate. This is an absolute lower bound if we don't want SBL
+	 * overflows, so round the value up.
+	 */
+	vpclk_div = max_t(unsigned int, DIV_ROUND_UP(l3_ick, pipe->max_rate),
+			  vpclk_div);
+
+	/* Compute the maximum clock divisor, based on the requested frame rate.
+	 * This is a soft lower bound to achieve a frame rate equal or higher
+	 * than the requested value, so round the value down.
+	 */
+	timeperframe = &pipe->max_timeperframe;
+
+	if (timeperframe->numerator) {
+		area = ofmt->width * ofmt->height;
+		bound = div_u64(area * timeperframe->denominator,
+				timeperframe->numerator);
+		value = min_t(u64, bound, l3_ick);
+		vpclk_div = max_t(unsigned int, l3_ick / value, vpclk_div);
+	}
+
+	dev_dbg(isp->dev, "%s: minimum clock divisor = %u\n", __func__,
+		vpclk_div);
+
+	return vpclk_div;
+}
+
+/*
+ * ccp2_mem_configure - Initialize CCP2 memory input/output interface
+ * @ccp2: Pointer to ISP CCP2 device
+ * @config: Pointer to ISP mem interface config structure
+ *
+ * This will analyze the parameters passed by the interface config
+ * structure, and configure the respective registers for proper
+ * CSI1/CCP2 memory input.
+ */
+static void ccp2_mem_configure(struct isp_ccp2_device *ccp2,
+			       struct isp_interface_mem_config *config)
+{
+	struct isp_device *isp = to_isp_device(ccp2);
+	u32 sink_pixcode = ccp2->formats[CCP2_PAD_SINK].code;
+	u32 source_pixcode = ccp2->formats[CCP2_PAD_SOURCE].code;
+	unsigned int dpcm_decompress = 0;
+	u32 val, hwords;
+
+	if (sink_pixcode != source_pixcode &&
+	    sink_pixcode == V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8)
+		dpcm_decompress = 1;
+
+	ccp2_pwr_cfg(ccp2);
+
+	/* Hsize, Skip */
+	isp_reg_writel(isp, ISPCCP2_LCM_HSIZE_SKIP_MIN |
+		       (config->hsize_count << ISPCCP2_LCM_HSIZE_SHIFT),
+		       OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_HSIZE);
+
+	/* Vsize, no. of lines */
+	isp_reg_writel(isp, config->vsize_count << ISPCCP2_LCM_VSIZE_SHIFT,
+		       OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_VSIZE);
+
+	if (ccp2->video_in.bpl_padding == 0)
+		config->src_ofst = 0;
+	else
+		config->src_ofst = ccp2->video_in.bpl_value;
+
+	isp_reg_writel(isp, config->src_ofst, OMAP3_ISP_IOMEM_CCP2,
+		       ISPCCP2_LCM_SRC_OFST);
+
+	/* Source and Destination formats */
+	val = ISPCCP2_LCM_CTRL_DST_FORMAT_RAW10 <<
+	      ISPCCP2_LCM_CTRL_DST_FORMAT_SHIFT;
+
+	if (dpcm_decompress) {
+		/* source format is RAW8 */
+		val |= ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW8 <<
+		       ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT;
+
+		/* RAW8 + DPCM10 - simple predictor */
+		val |= ISPCCP2_LCM_CTRL_SRC_DPCM_PRED;
+
+		/* enable source DPCM decompression */
+		val |= ISPCCP2_LCM_CTRL_SRC_DECOMPR_DPCM10 <<
+		       ISPCCP2_LCM_CTRL_SRC_DECOMPR_SHIFT;
+	} else {
+		/* source format is RAW10 */
+		val |= ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW10 <<
+		       ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT;
+	}
+
+	/* Burst size to 32x64 */
+	val |= ISPCCP2_LCM_CTRL_BURST_SIZE_32X <<
+	       ISPCCP2_LCM_CTRL_BURST_SIZE_SHIFT;
+
+	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_CTRL);
+
+	/* Prefetch setup */
+	if (dpcm_decompress)
+		hwords = (ISPCCP2_LCM_HSIZE_SKIP_MIN +
+			  config->hsize_count) >> 3;
+	else
+		hwords = (ISPCCP2_LCM_HSIZE_SKIP_MIN +
+			  config->hsize_count) >> 2;
+
+	isp_reg_writel(isp, hwords << ISPCCP2_LCM_PREFETCH_SHIFT,
+		       OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_PREFETCH);
+
+	/* Video port */
+	isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL,
+		    ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE);
+	ccp2_vp_config(ccp2, ccp2_adjust_bandwidth(ccp2));
+
+	/* Clear LCM interrupts */
+	isp_reg_writel(isp, ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ |
+		       ISPCCP2_LCM_IRQSTATUS_EOF_IRQ,
+		       OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQSTATUS);
+
+	/* Enable LCM interupts */
+	isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQENABLE,
+		    ISPCCP2_LCM_IRQSTATUS_EOF_IRQ |
+		    ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ);
+}
+
+/*
+ * ccp2_set_inaddr - Sets memory address of input frame.
+ * @ccp2: Pointer to ISP CCP2 device
+ * @addr: 32bit memory address aligned on 32byte boundary.
+ *
+ * Configures the memory address from which the input frame is to be read.
+ */
+static void ccp2_set_inaddr(struct isp_ccp2_device *ccp2, u32 addr)
+{
+	struct isp_device *isp = to_isp_device(ccp2);
+
+	isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_SRC_ADDR);
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2)
+{
+	struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
+	struct isp_buffer *buffer;
+
+	buffer = omap3isp_video_buffer_next(&ccp2->video_in);
+	if (buffer != NULL)
+		ccp2_set_inaddr(ccp2, buffer->isp_addr);
+
+	pipe->state |= ISP_PIPELINE_IDLE_INPUT;
+
+	if (ccp2->state == ISP_PIPELINE_STREAM_SINGLESHOT) {
+		if (isp_pipeline_ready(pipe))
+			omap3isp_pipeline_set_stream(pipe,
+						ISP_PIPELINE_STREAM_SINGLESHOT);
+	}
+}
+
+/*
+ * omap3isp_ccp2_isr - Handle ISP CCP2 interrupts
+ * @ccp2: Pointer to ISP CCP2 device
+ *
+ * This will handle the CCP2 interrupts
+ */
+void omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
+{
+	struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
+	struct isp_device *isp = to_isp_device(ccp2);
+	static const u32 ISPCCP2_LC01_ERROR =
+		ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ |
+		ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ |
+		ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ |
+		ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ |
+		ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ |
+		ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ;
+	u32 lcx_irqstatus, lcm_irqstatus;
+
+	/* First clear the interrupts */
+	lcx_irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2,
+				      ISPCCP2_LC01_IRQSTATUS);
+	isp_reg_writel(isp, lcx_irqstatus, OMAP3_ISP_IOMEM_CCP2,
+		       ISPCCP2_LC01_IRQSTATUS);
+
+	lcm_irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2,
+				      ISPCCP2_LCM_IRQSTATUS);
+	isp_reg_writel(isp, lcm_irqstatus, OMAP3_ISP_IOMEM_CCP2,
+		       ISPCCP2_LCM_IRQSTATUS);
+	/* Errors */
+	if (lcx_irqstatus & ISPCCP2_LC01_ERROR) {
+		pipe->error = true;
+		dev_dbg(isp->dev, "CCP2 err:%x\n", lcx_irqstatus);
+		return;
+	}
+
+	if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ) {
+		pipe->error = true;
+		dev_dbg(isp->dev, "CCP2 OCP err:%x\n", lcm_irqstatus);
+	}
+
+	if (omap3isp_module_sync_is_stopping(&ccp2->wait, &ccp2->stopping))
+		return;
+
+	/* Handle queued buffers on frame end interrupts */
+	if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_EOF_IRQ)
+		ccp2_isr_buffer(ccp2);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+static const unsigned int ccp2_fmts[] = {
+	V4L2_MBUS_FMT_SGRBG10_1X10,
+	V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+};
+
+/*
+ * __ccp2_get_format - helper function for getting ccp2 format
+ * @ccp2  : Pointer to ISP CCP2 device
+ * @fh    : V4L2 subdev file handle
+ * @pad   : pad number
+ * @which : wanted subdev format
+ * return format structure or NULL on error
+ */
+static struct v4l2_mbus_framefmt *
+__ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_fh *fh,
+		     unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_format(fh, pad);
+	else
+		return &ccp2->formats[pad];
+}
+
+/*
+ * ccp2_try_format - Handle try format by pad subdev method
+ * @ccp2  : Pointer to ISP CCP2 device
+ * @fh    : V4L2 subdev file handle
+ * @pad   : pad num
+ * @fmt   : pointer to v4l2 mbus format structure
+ * @which : wanted subdev format
+ */
+static void ccp2_try_format(struct isp_ccp2_device *ccp2,
+			       struct v4l2_subdev_fh *fh, unsigned int pad,
+			       struct v4l2_mbus_framefmt *fmt,
+			       enum v4l2_subdev_format_whence which)
+{
+	struct v4l2_mbus_framefmt *format;
+
+	switch (pad) {
+	case CCP2_PAD_SINK:
+		if (fmt->code != V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8)
+			fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+		if (ccp2->input == CCP2_INPUT_SENSOR) {
+			fmt->width = clamp_t(u32, fmt->width,
+					     ISPCCP2_DAT_START_MIN,
+					     ISPCCP2_DAT_START_MAX);
+			fmt->height = clamp_t(u32, fmt->height,
+					      ISPCCP2_DAT_SIZE_MIN,
+					      ISPCCP2_DAT_SIZE_MAX);
+		} else if (ccp2->input == CCP2_INPUT_MEMORY) {
+			fmt->width = clamp_t(u32, fmt->width,
+					     ISPCCP2_LCM_HSIZE_COUNT_MIN,
+					     ISPCCP2_LCM_HSIZE_COUNT_MAX);
+			fmt->height = clamp_t(u32, fmt->height,
+					      ISPCCP2_LCM_VSIZE_MIN,
+					      ISPCCP2_LCM_VSIZE_MAX);
+		}
+		break;
+
+	case CCP2_PAD_SOURCE:
+		/* Source format - copy sink format and change pixel code
+		 * to SGRBG10_1X10 as we don't support CCP2 write to memory.
+		 * When CCP2 write to memory feature will be added this
+		 * should be changed properly.
+		 */
+		format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, which);
+		memcpy(fmt, format, sizeof(*fmt));
+		fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+		break;
+	}
+
+	fmt->field = V4L2_FIELD_NONE;
+	fmt->colorspace = V4L2_COLORSPACE_SRGB;
+}
+
+/*
+ * ccp2_enum_mbus_code - Handle pixel format enumeration
+ * @sd     : pointer to v4l2 subdev structure
+ * @fh     : V4L2 subdev file handle
+ * @code   : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int ccp2_enum_mbus_code(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	if (code->pad == CCP2_PAD_SINK) {
+		if (code->index >= ARRAY_SIZE(ccp2_fmts))
+			return -EINVAL;
+
+		code->code = ccp2_fmts[code->index];
+	} else {
+		if (code->index != 0)
+			return -EINVAL;
+
+		format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK,
+					      V4L2_SUBDEV_FORMAT_TRY);
+		code->code = format->code;
+	}
+
+	return 0;
+}
+
+static int ccp2_enum_frame_size(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_fh *fh,
+				   struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt format;
+
+	if (fse->index != 0)
+		return -EINVAL;
+
+	format.code = fse->code;
+	format.width = 1;
+	format.height = 1;
+	ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+	fse->min_width = format.width;
+	fse->min_height = format.height;
+
+	if (format.code != fse->code)
+		return -EINVAL;
+
+	format.code = fse->code;
+	format.width = -1;
+	format.height = -1;
+	ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+	fse->max_width = format.width;
+	fse->max_height = format.height;
+
+	return 0;
+}
+
+/*
+ * ccp2_get_format - Handle get format by pads subdev method
+ * @sd    : pointer to v4l2 subdev structure
+ * @fh    : V4L2 subdev file handle
+ * @fmt   : pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_format *fmt)
+{
+	struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which);
+	if (format == NULL)
+		return -EINVAL;
+
+	fmt->format = *format;
+	return 0;
+}
+
+/*
+ * ccp2_set_format - Handle set format by pads subdev method
+ * @sd    : pointer to v4l2 subdev structure
+ * @fh    : V4L2 subdev file handle
+ * @fmt   : pointer to v4l2 subdev format structure
+ * returns zero
+ */
+static int ccp2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_format *fmt)
+{
+	struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which);
+	if (format == NULL)
+		return -EINVAL;
+
+	ccp2_try_format(ccp2, fh, fmt->pad, &fmt->format, fmt->which);
+	*format = fmt->format;
+
+	/* Propagate the format from sink to source */
+	if (fmt->pad == CCP2_PAD_SINK) {
+		format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SOURCE,
+					   fmt->which);
+		*format = fmt->format;
+		ccp2_try_format(ccp2, fh, CCP2_PAD_SOURCE, format, fmt->which);
+	}
+
+	return 0;
+}
+
+/*
+ * ccp2_init_formats - Initialize formats on all pads
+ * @sd: ISP CCP2 V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int ccp2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct v4l2_subdev_format format;
+
+	memset(&format, 0, sizeof(format));
+	format.pad = CCP2_PAD_SINK;
+	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+	format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+	format.format.width = 4096;
+	format.format.height = 4096;
+	ccp2_set_format(sd, fh, &format);
+
+	return 0;
+}
+
+/*
+ * ccp2_s_stream - Enable/Disable streaming on ccp2 subdev
+ * @sd    : pointer to v4l2 subdev structure
+ * @enable: 1 == Enable, 0 == Disable
+ * return zero
+ */
+static int ccp2_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
+	struct isp_device *isp = to_isp_device(ccp2);
+	struct device *dev = to_device(ccp2);
+	int ret;
+
+	if (ccp2->state == ISP_PIPELINE_STREAM_STOPPED) {
+		if (enable == ISP_PIPELINE_STREAM_STOPPED)
+			return 0;
+		atomic_set(&ccp2->stopping, 0);
+	}
+
+	switch (enable) {
+	case ISP_PIPELINE_STREAM_CONTINUOUS:
+		if (ccp2->phy) {
+			ret = omap3isp_csiphy_acquire(ccp2->phy);
+			if (ret < 0)
+				return ret;
+		}
+
+		ccp2_if_configure(ccp2);
+		ccp2_print_status(ccp2);
+
+		/* Enable CSI1/CCP2 interface */
+		ccp2_if_enable(ccp2, 1);
+		break;
+
+	case ISP_PIPELINE_STREAM_SINGLESHOT:
+		if (ccp2->state != ISP_PIPELINE_STREAM_SINGLESHOT) {
+			struct v4l2_mbus_framefmt *format;
+
+			format = &ccp2->formats[CCP2_PAD_SINK];
+
+			ccp2->mem_cfg.hsize_count = format->width;
+			ccp2->mem_cfg.vsize_count = format->height;
+			ccp2->mem_cfg.src_ofst = 0;
+
+			ccp2_mem_configure(ccp2, &ccp2->mem_cfg);
+			omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI1_READ);
+			ccp2_print_status(ccp2);
+		}
+		ccp2_mem_enable(ccp2, 1);
+		break;
+
+	case ISP_PIPELINE_STREAM_STOPPED:
+		if (omap3isp_module_sync_idle(&sd->entity, &ccp2->wait,
+					      &ccp2->stopping))
+			dev_dbg(dev, "%s: module stop timeout.\n", sd->name);
+		if (ccp2->input == CCP2_INPUT_MEMORY) {
+			ccp2_mem_enable(ccp2, 0);
+			omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI1_READ);
+		} else if (ccp2->input == CCP2_INPUT_SENSOR) {
+			/* Disable CSI1/CCP2 interface */
+			ccp2_if_enable(ccp2, 0);
+			if (ccp2->phy)
+				omap3isp_csiphy_release(ccp2->phy);
+		}
+		break;
+	}
+
+	ccp2->state = enable;
+	return 0;
+}
+
+/* subdev video operations */
+static const struct v4l2_subdev_video_ops ccp2_sd_video_ops = {
+	.s_stream = ccp2_s_stream,
+};
+
+/* subdev pad operations */
+static const struct v4l2_subdev_pad_ops ccp2_sd_pad_ops = {
+	.enum_mbus_code = ccp2_enum_mbus_code,
+	.enum_frame_size = ccp2_enum_frame_size,
+	.get_fmt = ccp2_get_format,
+	.set_fmt = ccp2_set_format,
+};
+
+/* subdev operations */
+static const struct v4l2_subdev_ops ccp2_sd_ops = {
+	.video = &ccp2_sd_video_ops,
+	.pad = &ccp2_sd_pad_ops,
+};
+
+/* subdev internal operations */
+static const struct v4l2_subdev_internal_ops ccp2_sd_internal_ops = {
+	.open = ccp2_init_formats,
+};
+
+/* --------------------------------------------------------------------------
+ * ISP ccp2 video device node
+ */
+
+/*
+ * ccp2_video_queue - Queue video buffer.
+ * @video : Pointer to isp video structure
+ * @buffer: Pointer to isp_buffer structure
+ * return -EIO or zero on success
+ */
+static int ccp2_video_queue(struct isp_video *video, struct isp_buffer *buffer)
+{
+	struct isp_ccp2_device *ccp2 = &video->isp->isp_ccp2;
+
+	ccp2_set_inaddr(ccp2, buffer->isp_addr);
+	return 0;
+}
+
+static const struct isp_video_operations ccp2_video_ops = {
+	.queue = ccp2_video_queue,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * ccp2_link_setup - Setup ccp2 connections.
+ * @entity : Pointer to media entity structure
+ * @local  : Pointer to local pad array
+ * @remote : Pointer to remote pad array
+ * @flags  : Link flags
+ * return -EINVAL on error or zero on success
+ */
+static int ccp2_link_setup(struct media_entity *entity,
+			   const struct media_pad *local,
+			   const struct media_pad *remote, u32 flags)
+{
+	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+	struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
+
+	switch (local->index | media_entity_type(remote->entity)) {
+	case CCP2_PAD_SINK | MEDIA_ENT_T_DEVNODE:
+		/* read from memory */
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			if (ccp2->input == CCP2_INPUT_SENSOR)
+				return -EBUSY;
+			ccp2->input = CCP2_INPUT_MEMORY;
+		} else {
+			if (ccp2->input == CCP2_INPUT_MEMORY)
+				ccp2->input = CCP2_INPUT_NONE;
+		}
+		break;
+
+	case CCP2_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+		/* read from sensor/phy */
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			if (ccp2->input == CCP2_INPUT_MEMORY)
+				return -EBUSY;
+			ccp2->input = CCP2_INPUT_SENSOR;
+		} else {
+			if (ccp2->input == CCP2_INPUT_SENSOR)
+				ccp2->input = CCP2_INPUT_NONE;
+		} break;
+
+	case CCP2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+		/* write to video port/ccdc */
+		if (flags & MEDIA_LNK_FL_ENABLED)
+			ccp2->output = CCP2_OUTPUT_CCDC;
+		else
+			ccp2->output = CCP2_OUTPUT_NONE;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations ccp2_media_ops = {
+	.link_setup = ccp2_link_setup,
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+/*
+ * omap3isp_ccp2_unregister_entities - Unregister media entities: subdev
+ * @ccp2: Pointer to ISP CCP2 device
+ */
+void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2)
+{
+	v4l2_device_unregister_subdev(&ccp2->subdev);
+	omap3isp_video_unregister(&ccp2->video_in);
+}
+
+/*
+ * omap3isp_ccp2_register_entities - Register the subdev media entity
+ * @ccp2: Pointer to ISP CCP2 device
+ * @vdev: Pointer to v4l device
+ * return negative error code or zero on success
+ */
+
+int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2,
+				    struct v4l2_device *vdev)
+{
+	int ret;
+
+	/* Register the subdev and video nodes. */
+	ret = v4l2_device_register_subdev(vdev, &ccp2->subdev);
+	if (ret < 0)
+		goto error;
+
+	ret = omap3isp_video_register(&ccp2->video_in, vdev);
+	if (ret < 0)
+		goto error;
+
+	return 0;
+
+error:
+	omap3isp_ccp2_unregister_entities(ccp2);
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP ccp2 initialisation and cleanup
+ */
+
+/*
+ * ccp2_init_entities - Initialize ccp2 subdev and media entity.
+ * @ccp2: Pointer to ISP CCP2 device
+ * return negative error code or zero on success
+ */
+static int ccp2_init_entities(struct isp_ccp2_device *ccp2)
+{
+	struct v4l2_subdev *sd = &ccp2->subdev;
+	struct media_pad *pads = ccp2->pads;
+	struct media_entity *me = &sd->entity;
+	int ret;
+
+	ccp2->input = CCP2_INPUT_NONE;
+	ccp2->output = CCP2_OUTPUT_NONE;
+
+	v4l2_subdev_init(sd, &ccp2_sd_ops);
+	sd->internal_ops = &ccp2_sd_internal_ops;
+	strlcpy(sd->name, "OMAP3 ISP CCP2", sizeof(sd->name));
+	sd->grp_id = 1 << 16;   /* group ID for isp subdevs */
+	v4l2_set_subdevdata(sd, ccp2);
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	pads[CCP2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	pads[CCP2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+	me->ops = &ccp2_media_ops;
+	ret = media_entity_init(me, CCP2_PADS_NUM, pads, 0);
+	if (ret < 0)
+		return ret;
+
+	ccp2_init_formats(sd, NULL);
+
+	/*
+	 * The CCP2 has weird line alignment requirements, possibly caused by
+	 * DPCM8 decompression. Line length for data read from memory must be a
+	 * multiple of 128 bits (16 bytes) in continuous mode (when no padding
+	 * is present at end of lines). Additionally, if padding is used, the
+	 * padded line length must be a multiple of 32 bytes. To simplify the
+	 * implementation we use a fixed 32 bytes alignment regardless of the
+	 * input format and width. If strict 128 bits alignment support is
+	 * required ispvideo will need to be made aware of this special dual
+	 * alignement requirements.
+	 */
+	ccp2->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	ccp2->video_in.bpl_alignment = 32;
+	ccp2->video_in.bpl_max = 0xffffffe0;
+	ccp2->video_in.isp = to_isp_device(ccp2);
+	ccp2->video_in.ops = &ccp2_video_ops;
+	ccp2->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
+
+	ret = omap3isp_video_init(&ccp2->video_in, "CCP2");
+	if (ret < 0)
+		goto error_video;
+
+	/* Connect the video node to the ccp2 subdev. */
+	ret = media_entity_create_link(&ccp2->video_in.video.entity, 0,
+				       &ccp2->subdev.entity, CCP2_PAD_SINK, 0);
+	if (ret < 0)
+		goto error_link;
+
+	return 0;
+
+error_link:
+	omap3isp_video_cleanup(&ccp2->video_in);
+error_video:
+	media_entity_cleanup(&ccp2->subdev.entity);
+	return ret;
+}
+
+/*
+ * omap3isp_ccp2_init - CCP2 initialization.
+ * @isp : Pointer to ISP device
+ * return negative error code or zero on success
+ */
+int omap3isp_ccp2_init(struct isp_device *isp)
+{
+	struct isp_ccp2_device *ccp2 = &isp->isp_ccp2;
+	int ret;
+
+	init_waitqueue_head(&ccp2->wait);
+
+	/*
+	 * On the OMAP34xx the CSI1 receiver is operated in the CSIb IO
+	 * complex, which is powered by vdds_csib power rail. Hence the
+	 * request for the regulator.
+	 *
+	 * On the OMAP36xx, the CCP2 uses the CSI PHY1 or PHY2, shared with
+	 * the CSI2c or CSI2a receivers. The PHY then needs to be explicitly
+	 * configured.
+	 *
+	 * TODO: Don't hardcode the usage of PHY1 (shared with CSI2c).
+	 */
+	if (isp->revision == ISP_REVISION_2_0) {
+		ccp2->vdds_csib = regulator_get(isp->dev, "vdds_csib");
+		if (IS_ERR(ccp2->vdds_csib)) {
+			dev_dbg(isp->dev,
+				"Could not get regulator vdds_csib\n");
+			ccp2->vdds_csib = NULL;
+		}
+	} else if (isp->revision == ISP_REVISION_15_0) {
+		ccp2->phy = &isp->isp_csiphy1;
+	}
+
+	ret = ccp2_init_entities(ccp2);
+	if (ret < 0) {
+		regulator_put(ccp2->vdds_csib);
+		return ret;
+	}
+
+	ccp2_reset(ccp2);
+	return 0;
+}
+
+/*
+ * omap3isp_ccp2_cleanup - CCP2 un-initialization
+ * @isp : Pointer to ISP device
+ */
+void omap3isp_ccp2_cleanup(struct isp_device *isp)
+{
+	struct isp_ccp2_device *ccp2 = &isp->isp_ccp2;
+
+	omap3isp_video_cleanup(&ccp2->video_in);
+	media_entity_cleanup(&ccp2->subdev.entity);
+
+	regulator_put(ccp2->vdds_csib);
+}
diff --git a/drivers/media/platform/omap3isp/ispccp2.h b/drivers/media/platform/omap3isp/ispccp2.h
new file mode 100644
index 0000000..76d65f4
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispccp2.h
@@ -0,0 +1,98 @@
+/*
+ * ispccp2.h
+ *
+ * TI OMAP3 ISP - CCP2 module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_CCP2_H
+#define OMAP3_ISP_CCP2_H
+
+#include <linux/videodev2.h>
+
+struct isp_device;
+struct isp_csiphy;
+
+/* Sink and source ccp2 pads */
+#define CCP2_PAD_SINK			0
+#define CCP2_PAD_SOURCE			1
+#define CCP2_PADS_NUM			2
+
+/* CCP2 input media entity */
+enum ccp2_input_entity {
+	CCP2_INPUT_NONE,
+	CCP2_INPUT_SENSOR,
+	CCP2_INPUT_MEMORY,
+};
+
+/* CCP2 output media entity */
+enum ccp2_output_entity {
+	CCP2_OUTPUT_NONE,
+	CCP2_OUTPUT_CCDC,
+	CCP2_OUTPUT_MEMORY,
+};
+
+
+/* Logical channel configuration */
+struct isp_interface_lcx_config {
+	int crc;
+	u32 data_start;
+	u32 data_size;
+	u32 format;
+};
+
+/* Memory channel configuration */
+struct isp_interface_mem_config {
+	u32 dst_port;
+	u32 vsize_count;
+	u32 hsize_count;
+	u32 src_ofst;
+	u32 dst_ofst;
+};
+
+/* CCP2 device */
+struct isp_ccp2_device {
+	struct v4l2_subdev subdev;
+	struct v4l2_mbus_framefmt formats[CCP2_PADS_NUM];
+	struct media_pad pads[CCP2_PADS_NUM];
+
+	enum ccp2_input_entity input;
+	enum ccp2_output_entity output;
+	struct isp_interface_lcx_config if_cfg;
+	struct isp_interface_mem_config mem_cfg;
+	struct isp_video video_in;
+	struct isp_csiphy *phy;
+	struct regulator *vdds_csib;
+	enum isp_pipeline_stream_state state;
+	wait_queue_head_t wait;
+	atomic_t stopping;
+};
+
+/* Function declarations */
+int omap3isp_ccp2_init(struct isp_device *isp);
+void omap3isp_ccp2_cleanup(struct isp_device *isp);
+int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2,
+			struct v4l2_device *vdev);
+void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2);
+void omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2);
+
+#endif	/* OMAP3_ISP_CCP2_H */
diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c
new file mode 100644
index 0000000..6a3ff79
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispcsi2.c
@@ -0,0 +1,1328 @@
+/*
+ * ispcsi2.c
+ *
+ * TI OMAP3 ISP - CSI2 module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <linux/delay.h>
+#include <media/v4l2-common.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/mm.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispcsi2.h"
+
+/*
+ * csi2_if_enable - Enable CSI2 Receiver interface.
+ * @enable: enable flag
+ *
+ */
+static void csi2_if_enable(struct isp_device *isp,
+			   struct isp_csi2_device *csi2, u8 enable)
+{
+	struct isp_csi2_ctrl_cfg *currctrl = &csi2->ctrl;
+
+	isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_CTRL, ISPCSI2_CTRL_IF_EN,
+			enable ? ISPCSI2_CTRL_IF_EN : 0);
+
+	currctrl->if_enable = enable;
+}
+
+/*
+ * csi2_recv_config - CSI2 receiver module configuration.
+ * @currctrl: isp_csi2_ctrl_cfg structure
+ *
+ */
+static void csi2_recv_config(struct isp_device *isp,
+			     struct isp_csi2_device *csi2,
+			     struct isp_csi2_ctrl_cfg *currctrl)
+{
+	u32 reg;
+
+	reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTRL);
+
+	if (currctrl->frame_mode)
+		reg |= ISPCSI2_CTRL_FRAME;
+	else
+		reg &= ~ISPCSI2_CTRL_FRAME;
+
+	if (currctrl->vp_clk_enable)
+		reg |= ISPCSI2_CTRL_VP_CLK_EN;
+	else
+		reg &= ~ISPCSI2_CTRL_VP_CLK_EN;
+
+	if (currctrl->vp_only_enable)
+		reg |= ISPCSI2_CTRL_VP_ONLY_EN;
+	else
+		reg &= ~ISPCSI2_CTRL_VP_ONLY_EN;
+
+	reg &= ~ISPCSI2_CTRL_VP_OUT_CTRL_MASK;
+	reg |= currctrl->vp_out_ctrl << ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT;
+
+	if (currctrl->ecc_enable)
+		reg |= ISPCSI2_CTRL_ECC_EN;
+	else
+		reg &= ~ISPCSI2_CTRL_ECC_EN;
+
+	isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTRL);
+}
+
+static const unsigned int csi2_input_fmts[] = {
+	V4L2_MBUS_FMT_SGRBG10_1X10,
+	V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+	V4L2_MBUS_FMT_SRGGB10_1X10,
+	V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8,
+	V4L2_MBUS_FMT_SBGGR10_1X10,
+	V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8,
+	V4L2_MBUS_FMT_SGBRG10_1X10,
+	V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8,
+	V4L2_MBUS_FMT_YUYV8_2X8,
+};
+
+/* To set the format on the CSI2 requires a mapping function that takes
+ * the following inputs:
+ * - 3 different formats (at this time)
+ * - 2 destinations (mem, vp+mem) (vp only handled separately)
+ * - 2 decompression options (on, off)
+ * - 2 isp revisions (certain format must be handled differently on OMAP3630)
+ * Output should be CSI2 frame format code
+ * Array indices as follows: [format][dest][decompr][is_3630]
+ * Not all combinations are valid. 0 means invalid.
+ */
+static const u16 __csi2_fmt_map[3][2][2][2] = {
+	/* RAW10 formats */
+	{
+		/* Output to memory */
+		{
+			/* No DPCM decompression */
+			{ CSI2_PIX_FMT_RAW10_EXP16, CSI2_PIX_FMT_RAW10_EXP16 },
+			/* DPCM decompression */
+			{ 0, 0 },
+		},
+		/* Output to both */
+		{
+			/* No DPCM decompression */
+			{ CSI2_PIX_FMT_RAW10_EXP16_VP,
+			  CSI2_PIX_FMT_RAW10_EXP16_VP },
+			/* DPCM decompression */
+			{ 0, 0 },
+		},
+	},
+	/* RAW10 DPCM8 formats */
+	{
+		/* Output to memory */
+		{
+			/* No DPCM decompression */
+			{ CSI2_PIX_FMT_RAW8, CSI2_USERDEF_8BIT_DATA1 },
+			/* DPCM decompression */
+			{ CSI2_PIX_FMT_RAW8_DPCM10_EXP16,
+			  CSI2_USERDEF_8BIT_DATA1_DPCM10 },
+		},
+		/* Output to both */
+		{
+			/* No DPCM decompression */
+			{ CSI2_PIX_FMT_RAW8_VP,
+			  CSI2_PIX_FMT_RAW8_VP },
+			/* DPCM decompression */
+			{ CSI2_PIX_FMT_RAW8_DPCM10_VP,
+			  CSI2_USERDEF_8BIT_DATA1_DPCM10_VP },
+		},
+	},
+	/* YUYV8 2X8 formats */
+	{
+		/* Output to memory */
+		{
+			/* No DPCM decompression */
+			{ CSI2_PIX_FMT_YUV422_8BIT,
+			  CSI2_PIX_FMT_YUV422_8BIT },
+			/* DPCM decompression */
+			{ 0, 0 },
+		},
+		/* Output to both */
+		{
+			/* No DPCM decompression */
+			{ CSI2_PIX_FMT_YUV422_8BIT_VP,
+			  CSI2_PIX_FMT_YUV422_8BIT_VP },
+			/* DPCM decompression */
+			{ 0, 0 },
+		},
+	},
+};
+
+/*
+ * csi2_ctx_map_format - Map CSI2 sink media bus format to CSI2 format ID
+ * @csi2: ISP CSI2 device
+ *
+ * Returns CSI2 physical format id
+ */
+static u16 csi2_ctx_map_format(struct isp_csi2_device *csi2)
+{
+	const struct v4l2_mbus_framefmt *fmt = &csi2->formats[CSI2_PAD_SINK];
+	int fmtidx, destidx, is_3630;
+
+	switch (fmt->code) {
+	case V4L2_MBUS_FMT_SGRBG10_1X10:
+	case V4L2_MBUS_FMT_SRGGB10_1X10:
+	case V4L2_MBUS_FMT_SBGGR10_1X10:
+	case V4L2_MBUS_FMT_SGBRG10_1X10:
+		fmtidx = 0;
+		break;
+	case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+	case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8:
+	case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8:
+	case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8:
+		fmtidx = 1;
+		break;
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+		fmtidx = 2;
+		break;
+	default:
+		WARN(1, KERN_ERR "CSI2: pixel format %08x unsupported!\n",
+		     fmt->code);
+		return 0;
+	}
+
+	if (!(csi2->output & CSI2_OUTPUT_CCDC) &&
+	    !(csi2->output & CSI2_OUTPUT_MEMORY)) {
+		/* Neither output enabled is a valid combination */
+		return CSI2_PIX_FMT_OTHERS;
+	}
+
+	/* If we need to skip frames at the beginning of the stream disable the
+	 * video port to avoid sending the skipped frames to the CCDC.
+	 */
+	destidx = csi2->frame_skip ? 0 : !!(csi2->output & CSI2_OUTPUT_CCDC);
+	is_3630 = csi2->isp->revision == ISP_REVISION_15_0;
+
+	return __csi2_fmt_map[fmtidx][destidx][csi2->dpcm_decompress][is_3630];
+}
+
+/*
+ * csi2_set_outaddr - Set memory address to save output image
+ * @csi2: Pointer to ISP CSI2a device.
+ * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary.
+ *
+ * Sets the memory address where the output will be saved.
+ *
+ * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte
+ * boundary.
+ */
+static void csi2_set_outaddr(struct isp_csi2_device *csi2, u32 addr)
+{
+	struct isp_device *isp = csi2->isp;
+	struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[0];
+
+	ctx->ping_addr = addr;
+	ctx->pong_addr = addr;
+	isp_reg_writel(isp, ctx->ping_addr,
+		       csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum));
+	isp_reg_writel(isp, ctx->pong_addr,
+		       csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum));
+}
+
+/*
+ * is_usr_def_mapping - Checks whether USER_DEF_MAPPING should
+ *			be enabled by CSI2.
+ * @format_id: mapped format id
+ *
+ */
+static inline int is_usr_def_mapping(u32 format_id)
+{
+	return (format_id & 0x40) ? 1 : 0;
+}
+
+/*
+ * csi2_ctx_enable - Enable specified CSI2 context
+ * @ctxnum: Context number, valid between 0 and 7 values.
+ * @enable: enable
+ *
+ */
+static void csi2_ctx_enable(struct isp_device *isp,
+			    struct isp_csi2_device *csi2, u8 ctxnum, u8 enable)
+{
+	struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[ctxnum];
+	unsigned int skip = 0;
+	u32 reg;
+
+	reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum));
+
+	if (enable) {
+		if (csi2->frame_skip)
+			skip = csi2->frame_skip;
+		else if (csi2->output & CSI2_OUTPUT_MEMORY)
+			skip = 1;
+
+		reg &= ~ISPCSI2_CTX_CTRL1_COUNT_MASK;
+		reg |= ISPCSI2_CTX_CTRL1_COUNT_UNLOCK
+		    |  (skip << ISPCSI2_CTX_CTRL1_COUNT_SHIFT)
+		    |  ISPCSI2_CTX_CTRL1_CTX_EN;
+	} else {
+		reg &= ~ISPCSI2_CTX_CTRL1_CTX_EN;
+	}
+
+	isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum));
+	ctx->enabled = enable;
+}
+
+/*
+ * csi2_ctx_config - CSI2 context configuration.
+ * @ctx: context configuration
+ *
+ */
+static void csi2_ctx_config(struct isp_device *isp,
+			    struct isp_csi2_device *csi2,
+			    struct isp_csi2_ctx_cfg *ctx)
+{
+	u32 reg;
+
+	/* Set up CSI2_CTx_CTRL1 */
+	reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum));
+
+	if (ctx->eof_enabled)
+		reg |= ISPCSI2_CTX_CTRL1_EOF_EN;
+	else
+		reg &= ~ISPCSI2_CTX_CTRL1_EOF_EN;
+
+	if (ctx->eol_enabled)
+		reg |= ISPCSI2_CTX_CTRL1_EOL_EN;
+	else
+		reg &= ~ISPCSI2_CTX_CTRL1_EOL_EN;
+
+	if (ctx->checksum_enabled)
+		reg |= ISPCSI2_CTX_CTRL1_CS_EN;
+	else
+		reg &= ~ISPCSI2_CTX_CTRL1_CS_EN;
+
+	isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum));
+
+	/* Set up CSI2_CTx_CTRL2 */
+	reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum));
+
+	reg &= ~(ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK);
+	reg |= ctx->virtual_id << ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT;
+
+	reg &= ~(ISPCSI2_CTX_CTRL2_FORMAT_MASK);
+	reg |= ctx->format_id << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT;
+
+	if (ctx->dpcm_decompress) {
+		if (ctx->dpcm_predictor)
+			reg |= ISPCSI2_CTX_CTRL2_DPCM_PRED;
+		else
+			reg &= ~ISPCSI2_CTX_CTRL2_DPCM_PRED;
+	}
+
+	if (is_usr_def_mapping(ctx->format_id)) {
+		reg &= ~ISPCSI2_CTX_CTRL2_USER_DEF_MAP_MASK;
+		reg |= 2 << ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT;
+	}
+
+	isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum));
+
+	/* Set up CSI2_CTx_CTRL3 */
+	reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum));
+	reg &= ~(ISPCSI2_CTX_CTRL3_ALPHA_MASK);
+	reg |= (ctx->alpha << ISPCSI2_CTX_CTRL3_ALPHA_SHIFT);
+
+	isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum));
+
+	/* Set up CSI2_CTx_DAT_OFST */
+	reg = isp_reg_readl(isp, csi2->regs1,
+			    ISPCSI2_CTX_DAT_OFST(ctx->ctxnum));
+	reg &= ~ISPCSI2_CTX_DAT_OFST_OFST_MASK;
+	reg |= ctx->data_offset << ISPCSI2_CTX_DAT_OFST_OFST_SHIFT;
+	isp_reg_writel(isp, reg, csi2->regs1,
+		       ISPCSI2_CTX_DAT_OFST(ctx->ctxnum));
+
+	isp_reg_writel(isp, ctx->ping_addr,
+		       csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum));
+
+	isp_reg_writel(isp, ctx->pong_addr,
+		       csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum));
+}
+
+/*
+ * csi2_timing_config - CSI2 timing configuration.
+ * @timing: csi2_timing_cfg structure
+ */
+static void csi2_timing_config(struct isp_device *isp,
+			       struct isp_csi2_device *csi2,
+			       struct isp_csi2_timing_cfg *timing)
+{
+	u32 reg;
+
+	reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_TIMING);
+
+	if (timing->force_rx_mode)
+		reg |= ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum);
+	else
+		reg &= ~ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum);
+
+	if (timing->stop_state_16x)
+		reg |= ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum);
+	else
+		reg &= ~ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum);
+
+	if (timing->stop_state_4x)
+		reg |= ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum);
+	else
+		reg &= ~ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum);
+
+	reg &= ~ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(timing->ionum);
+	reg |= timing->stop_state_counter <<
+	       ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(timing->ionum);
+
+	isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_TIMING);
+}
+
+/*
+ * csi2_irq_ctx_set - Enables CSI2 Context IRQs.
+ * @enable: Enable/disable CSI2 Context interrupts
+ */
+static void csi2_irq_ctx_set(struct isp_device *isp,
+			     struct isp_csi2_device *csi2, int enable)
+{
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		isp_reg_writel(isp, ISPCSI2_CTX_IRQSTATUS_FE_IRQ, csi2->regs1,
+			       ISPCSI2_CTX_IRQSTATUS(i));
+		if (enable)
+			isp_reg_set(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i),
+				    ISPCSI2_CTX_IRQSTATUS_FE_IRQ);
+		else
+			isp_reg_clr(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i),
+				    ISPCSI2_CTX_IRQSTATUS_FE_IRQ);
+	}
+}
+
+/*
+ * csi2_irq_complexio1_set - Enables CSI2 ComplexIO IRQs.
+ * @enable: Enable/disable CSI2 ComplexIO #1 interrupts
+ */
+static void csi2_irq_complexio1_set(struct isp_device *isp,
+				    struct isp_csi2_device *csi2, int enable)
+{
+	u32 reg;
+	reg = ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT |
+		ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER |
+		ISPCSI2_PHY_IRQENABLE_STATEULPM5 |
+		ISPCSI2_PHY_IRQENABLE_ERRCONTROL5 |
+		ISPCSI2_PHY_IRQENABLE_ERRESC5 |
+		ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5 |
+		ISPCSI2_PHY_IRQENABLE_ERRSOTHS5 |
+		ISPCSI2_PHY_IRQENABLE_STATEULPM4 |
+		ISPCSI2_PHY_IRQENABLE_ERRCONTROL4 |
+		ISPCSI2_PHY_IRQENABLE_ERRESC4 |
+		ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4 |
+		ISPCSI2_PHY_IRQENABLE_ERRSOTHS4 |
+		ISPCSI2_PHY_IRQENABLE_STATEULPM3 |
+		ISPCSI2_PHY_IRQENABLE_ERRCONTROL3 |
+		ISPCSI2_PHY_IRQENABLE_ERRESC3 |
+		ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3 |
+		ISPCSI2_PHY_IRQENABLE_ERRSOTHS3 |
+		ISPCSI2_PHY_IRQENABLE_STATEULPM2 |
+		ISPCSI2_PHY_IRQENABLE_ERRCONTROL2 |
+		ISPCSI2_PHY_IRQENABLE_ERRESC2 |
+		ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2 |
+		ISPCSI2_PHY_IRQENABLE_ERRSOTHS2 |
+		ISPCSI2_PHY_IRQENABLE_STATEULPM1 |
+		ISPCSI2_PHY_IRQENABLE_ERRCONTROL1 |
+		ISPCSI2_PHY_IRQENABLE_ERRESC1 |
+		ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1 |
+		ISPCSI2_PHY_IRQENABLE_ERRSOTHS1;
+	isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQSTATUS);
+	if (enable)
+		reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_PHY_IRQENABLE);
+	else
+		reg = 0;
+	isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQENABLE);
+}
+
+/*
+ * csi2_irq_status_set - Enables CSI2 Status IRQs.
+ * @enable: Enable/disable CSI2 Status interrupts
+ */
+static void csi2_irq_status_set(struct isp_device *isp,
+				struct isp_csi2_device *csi2, int enable)
+{
+	u32 reg;
+	reg = ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
+		ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ |
+		ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ |
+		ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ |
+		ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ |
+		ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ |
+		ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ |
+		ISPCSI2_IRQSTATUS_CONTEXT(0);
+	isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQSTATUS);
+	if (enable)
+		reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQENABLE);
+	else
+		reg = 0;
+
+	isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQENABLE);
+}
+
+/*
+ * omap3isp_csi2_reset - Resets the CSI2 module.
+ *
+ * Must be called with the phy lock held.
+ *
+ * Returns 0 if successful, or -EBUSY if power command didn't respond.
+ */
+int omap3isp_csi2_reset(struct isp_csi2_device *csi2)
+{
+	struct isp_device *isp = csi2->isp;
+	u8 soft_reset_retries = 0;
+	u32 reg;
+	int i;
+
+	if (!csi2->available)
+		return -ENODEV;
+
+	if (csi2->phy->phy_in_use)
+		return -EBUSY;
+
+	isp_reg_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG,
+		    ISPCSI2_SYSCONFIG_SOFT_RESET);
+
+	do {
+		reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_SYSSTATUS) &
+				    ISPCSI2_SYSSTATUS_RESET_DONE;
+		if (reg == ISPCSI2_SYSSTATUS_RESET_DONE)
+			break;
+		soft_reset_retries++;
+		if (soft_reset_retries < 5)
+			udelay(100);
+	} while (soft_reset_retries < 5);
+
+	if (soft_reset_retries == 5) {
+		printk(KERN_ERR "CSI2: Soft reset try count exceeded!\n");
+		return -EBUSY;
+	}
+
+	if (isp->revision == ISP_REVISION_15_0)
+		isp_reg_set(isp, csi2->regs1, ISPCSI2_PHY_CFG,
+			    ISPCSI2_PHY_CFG_RESET_CTRL);
+
+	i = 100;
+	do {
+		reg = isp_reg_readl(isp, csi2->phy->phy_regs, ISPCSIPHY_REG1)
+		    & ISPCSIPHY_REG1_RESET_DONE_CTRLCLK;
+		if (reg == ISPCSIPHY_REG1_RESET_DONE_CTRLCLK)
+			break;
+		udelay(100);
+	} while (--i > 0);
+
+	if (i == 0) {
+		printk(KERN_ERR
+		       "CSI2: Reset for CSI2_96M_FCLK domain Failed!\n");
+		return -EBUSY;
+	}
+
+	if (isp->autoidle)
+		isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG,
+				ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK |
+				ISPCSI2_SYSCONFIG_AUTO_IDLE,
+				ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART |
+				((isp->revision == ISP_REVISION_15_0) ?
+				 ISPCSI2_SYSCONFIG_AUTO_IDLE : 0));
+	else
+		isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG,
+				ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK |
+				ISPCSI2_SYSCONFIG_AUTO_IDLE,
+				ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO);
+
+	return 0;
+}
+
+static int csi2_configure(struct isp_csi2_device *csi2)
+{
+	const struct isp_v4l2_subdevs_group *pdata;
+	struct isp_device *isp = csi2->isp;
+	struct isp_csi2_timing_cfg *timing = &csi2->timing[0];
+	struct v4l2_subdev *sensor;
+	struct media_pad *pad;
+
+	/*
+	 * CSI2 fields that can be updated while the context has
+	 * been enabled or the interface has been enabled are not
+	 * updated dynamically currently. So we do not allow to
+	 * reconfigure if either has been enabled
+	 */
+	if (csi2->contexts[0].enabled || csi2->ctrl.if_enable)
+		return -EBUSY;
+
+	pad = media_entity_remote_source(&csi2->pads[CSI2_PAD_SINK]);
+	sensor = media_entity_to_v4l2_subdev(pad->entity);
+	pdata = sensor->host_priv;
+
+	csi2->frame_skip = 0;
+	v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip);
+
+	csi2->ctrl.vp_out_ctrl = pdata->bus.csi2.vpclk_div;
+	csi2->ctrl.frame_mode = ISP_CSI2_FRAME_IMMEDIATE;
+	csi2->ctrl.ecc_enable = pdata->bus.csi2.crc;
+
+	timing->ionum = 1;
+	timing->force_rx_mode = 1;
+	timing->stop_state_16x = 1;
+	timing->stop_state_4x = 1;
+	timing->stop_state_counter = 0x1FF;
+
+	/*
+	 * The CSI2 receiver can't do any format conversion except DPCM
+	 * decompression, so every set_format call configures both pads
+	 * and enables DPCM decompression as a special case:
+	 */
+	if (csi2->formats[CSI2_PAD_SINK].code !=
+	    csi2->formats[CSI2_PAD_SOURCE].code)
+		csi2->dpcm_decompress = true;
+	else
+		csi2->dpcm_decompress = false;
+
+	csi2->contexts[0].format_id = csi2_ctx_map_format(csi2);
+
+	if (csi2->video_out.bpl_padding == 0)
+		csi2->contexts[0].data_offset = 0;
+	else
+		csi2->contexts[0].data_offset = csi2->video_out.bpl_value;
+
+	/*
+	 * Enable end of frame and end of line signals generation for
+	 * context 0. These signals are generated from CSI2 receiver to
+	 * qualify the last pixel of a frame and the last pixel of a line.
+	 * Without enabling the signals CSI2 receiver writes data to memory
+	 * beyond buffer size and/or data line offset is not handled correctly.
+	 */
+	csi2->contexts[0].eof_enabled = 1;
+	csi2->contexts[0].eol_enabled = 1;
+
+	csi2_irq_complexio1_set(isp, csi2, 1);
+	csi2_irq_ctx_set(isp, csi2, 1);
+	csi2_irq_status_set(isp, csi2, 1);
+
+	/* Set configuration (timings, format and links) */
+	csi2_timing_config(isp, csi2, timing);
+	csi2_recv_config(isp, csi2, &csi2->ctrl);
+	csi2_ctx_config(isp, csi2, &csi2->contexts[0]);
+
+	return 0;
+}
+
+/*
+ * csi2_print_status - Prints CSI2 debug information.
+ */
+#define CSI2_PRINT_REGISTER(isp, regs, name)\
+	dev_dbg(isp->dev, "###CSI2 " #name "=0x%08x\n", \
+		isp_reg_readl(isp, regs, ISPCSI2_##name))
+
+static void csi2_print_status(struct isp_csi2_device *csi2)
+{
+	struct isp_device *isp = csi2->isp;
+
+	if (!csi2->available)
+		return;
+
+	dev_dbg(isp->dev, "-------------CSI2 Register dump-------------\n");
+
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSCONFIG);
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSSTATUS);
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQENABLE);
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQSTATUS);
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, CTRL);
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_H);
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, GNQ);
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_CFG);
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQSTATUS);
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, SHORT_PACKET);
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQENABLE);
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_P);
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, TIMING);
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL1(0));
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL2(0));
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_OFST(0));
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PING_ADDR(0));
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PONG_ADDR(0));
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQENABLE(0));
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQSTATUS(0));
+	CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL3(0));
+
+	dev_dbg(isp->dev, "--------------------------------------------\n");
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+/*
+ * csi2_isr_buffer - Does buffer handling at end-of-frame
+ * when writing to memory.
+ */
+static void csi2_isr_buffer(struct isp_csi2_device *csi2)
+{
+	struct isp_device *isp = csi2->isp;
+	struct isp_buffer *buffer;
+
+	csi2_ctx_enable(isp, csi2, 0, 0);
+
+	buffer = omap3isp_video_buffer_next(&csi2->video_out);
+
+	/*
+	 * Let video queue operation restart engine if there is an underrun
+	 * condition.
+	 */
+	if (buffer == NULL)
+		return;
+
+	csi2_set_outaddr(csi2, buffer->isp_addr);
+	csi2_ctx_enable(isp, csi2, 0, 1);
+}
+
+static void csi2_isr_ctx(struct isp_csi2_device *csi2,
+			 struct isp_csi2_ctx_cfg *ctx)
+{
+	struct isp_device *isp = csi2->isp;
+	unsigned int n = ctx->ctxnum;
+	u32 status;
+
+	status = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));
+	isp_reg_writel(isp, status, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));
+
+	if (!(status & ISPCSI2_CTX_IRQSTATUS_FE_IRQ))
+		return;
+
+	/* Skip interrupts until we reach the frame skip count. The CSI2 will be
+	 * automatically disabled, as the frame skip count has been programmed
+	 * in the CSI2_CTx_CTRL1::COUNT field, so reenable it.
+	 *
+	 * It would have been nice to rely on the FRAME_NUMBER interrupt instead
+	 * but it turned out that the interrupt is only generated when the CSI2
+	 * writes to memory (the CSI2_CTx_CTRL1::COUNT field is decreased
+	 * correctly and reaches 0 when data is forwarded to the video port only
+	 * but no interrupt arrives). Maybe a CSI2 hardware bug.
+	 */
+	if (csi2->frame_skip) {
+		csi2->frame_skip--;
+		if (csi2->frame_skip == 0) {
+			ctx->format_id = csi2_ctx_map_format(csi2);
+			csi2_ctx_config(isp, csi2, ctx);
+			csi2_ctx_enable(isp, csi2, n, 1);
+		}
+		return;
+	}
+
+	if (csi2->output & CSI2_OUTPUT_MEMORY)
+		csi2_isr_buffer(csi2);
+}
+
+/*
+ * omap3isp_csi2_isr - CSI2 interrupt handling.
+ */
+void omap3isp_csi2_isr(struct isp_csi2_device *csi2)
+{
+	struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity);
+	u32 csi2_irqstatus, cpxio1_irqstatus;
+	struct isp_device *isp = csi2->isp;
+
+	if (!csi2->available)
+		return;
+
+	csi2_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQSTATUS);
+	isp_reg_writel(isp, csi2_irqstatus, csi2->regs1, ISPCSI2_IRQSTATUS);
+
+	/* Failure Cases */
+	if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ) {
+		cpxio1_irqstatus = isp_reg_readl(isp, csi2->regs1,
+						 ISPCSI2_PHY_IRQSTATUS);
+		isp_reg_writel(isp, cpxio1_irqstatus,
+			       csi2->regs1, ISPCSI2_PHY_IRQSTATUS);
+		dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ "
+			"%x\n", cpxio1_irqstatus);
+		pipe->error = true;
+	}
+
+	if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
+			      ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ |
+			      ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ |
+			      ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ |
+			      ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)) {
+		dev_dbg(isp->dev, "CSI2 Err:"
+			" OCP:%d,"
+			" Short_pack:%d,"
+			" ECC:%d,"
+			" CPXIO2:%d,"
+			" FIFO_OVF:%d,"
+			"\n",
+			(csi2_irqstatus &
+			 ISPCSI2_IRQSTATUS_OCP_ERR_IRQ) ? 1 : 0,
+			(csi2_irqstatus &
+			 ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ) ? 1 : 0,
+			(csi2_irqstatus &
+			 ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ) ? 1 : 0,
+			(csi2_irqstatus &
+			 ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0,
+			(csi2_irqstatus &
+			 ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0);
+		pipe->error = true;
+	}
+
+	if (omap3isp_module_sync_is_stopping(&csi2->wait, &csi2->stopping))
+		return;
+
+	/* Successful cases */
+	if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0))
+		csi2_isr_ctx(csi2, &csi2->contexts[0]);
+
+	if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ)
+		dev_dbg(isp->dev, "CSI2: ECC correction done\n");
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP video operations
+ */
+
+/*
+ * csi2_queue - Queues the first buffer when using memory output
+ * @video: The video node
+ * @buffer: buffer to queue
+ */
+static int csi2_queue(struct isp_video *video, struct isp_buffer *buffer)
+{
+	struct isp_device *isp = video->isp;
+	struct isp_csi2_device *csi2 = &isp->isp_csi2a;
+
+	csi2_set_outaddr(csi2, buffer->isp_addr);
+
+	/*
+	 * If streaming was enabled before there was a buffer queued
+	 * or underrun happened in the ISR, the hardware was not enabled
+	 * and DMA queue flag ISP_VIDEO_DMAQUEUE_UNDERRUN is still set.
+	 * Enable it now.
+	 */
+	if (csi2->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) {
+		/* Enable / disable context 0 and IRQs */
+		csi2_if_enable(isp, csi2, 1);
+		csi2_ctx_enable(isp, csi2, 0, 1);
+		isp_video_dmaqueue_flags_clr(&csi2->video_out);
+	}
+
+	return 0;
+}
+
+static const struct isp_video_operations csi2_ispvideo_ops = {
+	.queue = csi2_queue,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+static struct v4l2_mbus_framefmt *
+__csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh,
+		  unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_format(fh, pad);
+	else
+		return &csi2->formats[pad];
+}
+
+static void
+csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh,
+		unsigned int pad, struct v4l2_mbus_framefmt *fmt,
+		enum v4l2_subdev_format_whence which)
+{
+	enum v4l2_mbus_pixelcode pixelcode;
+	struct v4l2_mbus_framefmt *format;
+	const struct isp_format_info *info;
+	unsigned int i;
+
+	switch (pad) {
+	case CSI2_PAD_SINK:
+		/* Clamp the width and height to valid range (1-8191). */
+		for (i = 0; i < ARRAY_SIZE(csi2_input_fmts); i++) {
+			if (fmt->code == csi2_input_fmts[i])
+				break;
+		}
+
+		/* If not found, use SGRBG10 as default */
+		if (i >= ARRAY_SIZE(csi2_input_fmts))
+			fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+		fmt->width = clamp_t(u32, fmt->width, 1, 8191);
+		fmt->height = clamp_t(u32, fmt->height, 1, 8191);
+		break;
+
+	case CSI2_PAD_SOURCE:
+		/* Source format same as sink format, except for DPCM
+		 * compression.
+		 */
+		pixelcode = fmt->code;
+		format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, which);
+		memcpy(fmt, format, sizeof(*fmt));
+
+		/*
+		 * Only Allow DPCM decompression, and check that the
+		 * pattern is preserved
+		 */
+		info = omap3isp_video_format_info(fmt->code);
+		if (info->uncompressed == pixelcode)
+			fmt->code = pixelcode;
+		break;
+	}
+
+	/* RGB, non-interlaced */
+	fmt->colorspace = V4L2_COLORSPACE_SRGB;
+	fmt->field = V4L2_FIELD_NONE;
+}
+
+/*
+ * csi2_enum_mbus_code - Handle pixel format enumeration
+ * @sd     : pointer to v4l2 subdev structure
+ * @fh     : V4L2 subdev file handle
+ * @code   : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
+			       struct v4l2_subdev_fh *fh,
+			       struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+	const struct isp_format_info *info;
+
+	if (code->pad == CSI2_PAD_SINK) {
+		if (code->index >= ARRAY_SIZE(csi2_input_fmts))
+			return -EINVAL;
+
+		code->code = csi2_input_fmts[code->index];
+	} else {
+		format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK,
+					   V4L2_SUBDEV_FORMAT_TRY);
+		switch (code->index) {
+		case 0:
+			/* Passthrough sink pad code */
+			code->code = format->code;
+			break;
+		case 1:
+			/* Uncompressed code */
+			info = omap3isp_video_format_info(format->code);
+			if (info->uncompressed == format->code)
+				return -EINVAL;
+
+			code->code = info->uncompressed;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int csi2_enum_frame_size(struct v4l2_subdev *sd,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt format;
+
+	if (fse->index != 0)
+		return -EINVAL;
+
+	format.code = fse->code;
+	format.width = 1;
+	format.height = 1;
+	csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+	fse->min_width = format.width;
+	fse->min_height = format.height;
+
+	if (format.code != fse->code)
+		return -EINVAL;
+
+	format.code = fse->code;
+	format.width = -1;
+	format.height = -1;
+	csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+	fse->max_width = format.width;
+	fse->max_height = format.height;
+
+	return 0;
+}
+
+/*
+ * csi2_get_format - Handle get format by pads subdev method
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @fmt: pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			   struct v4l2_subdev_format *fmt)
+{
+	struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which);
+	if (format == NULL)
+		return -EINVAL;
+
+	fmt->format = *format;
+	return 0;
+}
+
+/*
+ * csi2_set_format - Handle set format by pads subdev method
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @fmt: pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			   struct v4l2_subdev_format *fmt)
+{
+	struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which);
+	if (format == NULL)
+		return -EINVAL;
+
+	csi2_try_format(csi2, fh, fmt->pad, &fmt->format, fmt->which);
+	*format = fmt->format;
+
+	/* Propagate the format from sink to source */
+	if (fmt->pad == CSI2_PAD_SINK) {
+		format = __csi2_get_format(csi2, fh, CSI2_PAD_SOURCE,
+					   fmt->which);
+		*format = fmt->format;
+		csi2_try_format(csi2, fh, CSI2_PAD_SOURCE, format, fmt->which);
+	}
+
+	return 0;
+}
+
+/*
+ * csi2_init_formats - Initialize formats on all pads
+ * @sd: ISP CSI2 V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct v4l2_subdev_format format;
+
+	memset(&format, 0, sizeof(format));
+	format.pad = CSI2_PAD_SINK;
+	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+	format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+	format.format.width = 4096;
+	format.format.height = 4096;
+	csi2_set_format(sd, fh, &format);
+
+	return 0;
+}
+
+/*
+ * csi2_set_stream - Enable/Disable streaming on the CSI2 module
+ * @sd: ISP CSI2 V4L2 subdevice
+ * @enable: ISP pipeline stream state
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int csi2_set_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+	struct isp_device *isp = csi2->isp;
+	struct isp_video *video_out = &csi2->video_out;
+
+	switch (enable) {
+	case ISP_PIPELINE_STREAM_CONTINUOUS:
+		if (omap3isp_csiphy_acquire(csi2->phy) < 0)
+			return -ENODEV;
+		if (csi2->output & CSI2_OUTPUT_MEMORY)
+			omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI2A_WRITE);
+		csi2_configure(csi2);
+		csi2_print_status(csi2);
+
+		/*
+		 * When outputting to memory with no buffer available, let the
+		 * buffer queue handler start the hardware. A DMA queue flag
+		 * ISP_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is
+		 * a buffer available.
+		 */
+		if (csi2->output & CSI2_OUTPUT_MEMORY &&
+		    !(video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED))
+			break;
+		/* Enable context 0 and IRQs */
+		atomic_set(&csi2->stopping, 0);
+		csi2_ctx_enable(isp, csi2, 0, 1);
+		csi2_if_enable(isp, csi2, 1);
+		isp_video_dmaqueue_flags_clr(video_out);
+		break;
+
+	case ISP_PIPELINE_STREAM_STOPPED:
+		if (csi2->state == ISP_PIPELINE_STREAM_STOPPED)
+			return 0;
+		if (omap3isp_module_sync_idle(&sd->entity, &csi2->wait,
+					      &csi2->stopping))
+			dev_dbg(isp->dev, "%s: module stop timeout.\n",
+				sd->name);
+		csi2_ctx_enable(isp, csi2, 0, 0);
+		csi2_if_enable(isp, csi2, 0);
+		csi2_irq_ctx_set(isp, csi2, 0);
+		omap3isp_csiphy_release(csi2->phy);
+		isp_video_dmaqueue_flags_clr(video_out);
+		omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI2A_WRITE);
+		break;
+	}
+
+	csi2->state = enable;
+	return 0;
+}
+
+/* subdev video operations */
+static const struct v4l2_subdev_video_ops csi2_video_ops = {
+	.s_stream = csi2_set_stream,
+};
+
+/* subdev pad operations */
+static const struct v4l2_subdev_pad_ops csi2_pad_ops = {
+	.enum_mbus_code = csi2_enum_mbus_code,
+	.enum_frame_size = csi2_enum_frame_size,
+	.get_fmt = csi2_get_format,
+	.set_fmt = csi2_set_format,
+};
+
+/* subdev operations */
+static const struct v4l2_subdev_ops csi2_ops = {
+	.video = &csi2_video_ops,
+	.pad = &csi2_pad_ops,
+};
+
+/* subdev internal operations */
+static const struct v4l2_subdev_internal_ops csi2_internal_ops = {
+	.open = csi2_init_formats,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * csi2_link_setup - Setup CSI2 connections.
+ * @entity : Pointer to media entity structure
+ * @local  : Pointer to local pad array
+ * @remote : Pointer to remote pad array
+ * @flags  : Link flags
+ * return -EINVAL or zero on success
+ */
+static int csi2_link_setup(struct media_entity *entity,
+			   const struct media_pad *local,
+			   const struct media_pad *remote, u32 flags)
+{
+	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+	struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+	struct isp_csi2_ctrl_cfg *ctrl = &csi2->ctrl;
+
+	/*
+	 * The ISP core doesn't support pipelines with multiple video outputs.
+	 * Revisit this when it will be implemented, and return -EBUSY for now.
+	 */
+
+	switch (local->index | media_entity_type(remote->entity)) {
+	case CSI2_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			if (csi2->output & ~CSI2_OUTPUT_MEMORY)
+				return -EBUSY;
+			csi2->output |= CSI2_OUTPUT_MEMORY;
+		} else {
+			csi2->output &= ~CSI2_OUTPUT_MEMORY;
+		}
+		break;
+
+	case CSI2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			if (csi2->output & ~CSI2_OUTPUT_CCDC)
+				return -EBUSY;
+			csi2->output |= CSI2_OUTPUT_CCDC;
+		} else {
+			csi2->output &= ~CSI2_OUTPUT_CCDC;
+		}
+		break;
+
+	default:
+		/* Link from camera to CSI2 is fixed... */
+		return -EINVAL;
+	}
+
+	ctrl->vp_only_enable =
+		(csi2->output & CSI2_OUTPUT_MEMORY) ? false : true;
+	ctrl->vp_clk_enable = !!(csi2->output & CSI2_OUTPUT_CCDC);
+
+	return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations csi2_media_ops = {
+	.link_setup = csi2_link_setup,
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2)
+{
+	v4l2_device_unregister_subdev(&csi2->subdev);
+	omap3isp_video_unregister(&csi2->video_out);
+}
+
+int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2,
+				    struct v4l2_device *vdev)
+{
+	int ret;
+
+	/* Register the subdev and video nodes. */
+	ret = v4l2_device_register_subdev(vdev, &csi2->subdev);
+	if (ret < 0)
+		goto error;
+
+	ret = omap3isp_video_register(&csi2->video_out, vdev);
+	if (ret < 0)
+		goto error;
+
+	return 0;
+
+error:
+	omap3isp_csi2_unregister_entities(csi2);
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP CSI2 initialisation and cleanup
+ */
+
+/*
+ * csi2_init_entities - Initialize subdev and media entity.
+ * @csi2: Pointer to csi2 structure.
+ * return -ENOMEM or zero on success
+ */
+static int csi2_init_entities(struct isp_csi2_device *csi2)
+{
+	struct v4l2_subdev *sd = &csi2->subdev;
+	struct media_pad *pads = csi2->pads;
+	struct media_entity *me = &sd->entity;
+	int ret;
+
+	v4l2_subdev_init(sd, &csi2_ops);
+	sd->internal_ops = &csi2_internal_ops;
+	strlcpy(sd->name, "OMAP3 ISP CSI2a", sizeof(sd->name));
+
+	sd->grp_id = 1 << 16;	/* group ID for isp subdevs */
+	v4l2_set_subdevdata(sd, csi2);
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+	pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+
+	me->ops = &csi2_media_ops;
+	ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0);
+	if (ret < 0)
+		return ret;
+
+	csi2_init_formats(sd, NULL);
+
+	/* Video device node */
+	csi2->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	csi2->video_out.ops = &csi2_ispvideo_ops;
+	csi2->video_out.bpl_alignment = 32;
+	csi2->video_out.bpl_zero_padding = 1;
+	csi2->video_out.bpl_max = 0x1ffe0;
+	csi2->video_out.isp = csi2->isp;
+	csi2->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
+
+	ret = omap3isp_video_init(&csi2->video_out, "CSI2a");
+	if (ret < 0)
+		goto error_video;
+
+	/* Connect the CSI2 subdev to the video node. */
+	ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE,
+				       &csi2->video_out.video.entity, 0, 0);
+	if (ret < 0)
+		goto error_link;
+
+	return 0;
+
+error_link:
+	omap3isp_video_cleanup(&csi2->video_out);
+error_video:
+	media_entity_cleanup(&csi2->subdev.entity);
+	return ret;
+}
+
+/*
+ * omap3isp_csi2_init - Routine for module driver init
+ */
+int omap3isp_csi2_init(struct isp_device *isp)
+{
+	struct isp_csi2_device *csi2a = &isp->isp_csi2a;
+	struct isp_csi2_device *csi2c = &isp->isp_csi2c;
+	int ret;
+
+	csi2a->isp = isp;
+	csi2a->available = 1;
+	csi2a->regs1 = OMAP3_ISP_IOMEM_CSI2A_REGS1;
+	csi2a->regs2 = OMAP3_ISP_IOMEM_CSI2A_REGS2;
+	csi2a->phy = &isp->isp_csiphy2;
+	csi2a->state = ISP_PIPELINE_STREAM_STOPPED;
+	init_waitqueue_head(&csi2a->wait);
+
+	ret = csi2_init_entities(csi2a);
+	if (ret < 0)
+		return ret;
+
+	if (isp->revision == ISP_REVISION_15_0) {
+		csi2c->isp = isp;
+		csi2c->available = 1;
+		csi2c->regs1 = OMAP3_ISP_IOMEM_CSI2C_REGS1;
+		csi2c->regs2 = OMAP3_ISP_IOMEM_CSI2C_REGS2;
+		csi2c->phy = &isp->isp_csiphy1;
+		csi2c->state = ISP_PIPELINE_STREAM_STOPPED;
+		init_waitqueue_head(&csi2c->wait);
+	}
+
+	return 0;
+}
+
+/*
+ * omap3isp_csi2_cleanup - Routine for module driver cleanup
+ */
+void omap3isp_csi2_cleanup(struct isp_device *isp)
+{
+	struct isp_csi2_device *csi2a = &isp->isp_csi2a;
+
+	omap3isp_video_cleanup(&csi2a->video_out);
+	media_entity_cleanup(&csi2a->subdev.entity);
+}
diff --git a/drivers/media/platform/omap3isp/ispcsi2.h b/drivers/media/platform/omap3isp/ispcsi2.h
new file mode 100644
index 0000000..c57729b
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispcsi2.h
@@ -0,0 +1,165 @@
+/*
+ * ispcsi2.h
+ *
+ * TI OMAP3 ISP - CSI2 module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_CSI2_H
+#define OMAP3_ISP_CSI2_H
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+struct isp_csiphy;
+
+/* This is not an exhaustive list */
+enum isp_csi2_pix_formats {
+	CSI2_PIX_FMT_OTHERS = 0,
+	CSI2_PIX_FMT_YUV422_8BIT = 0x1e,
+	CSI2_PIX_FMT_YUV422_8BIT_VP = 0x9e,
+	CSI2_PIX_FMT_RAW10_EXP16 = 0xab,
+	CSI2_PIX_FMT_RAW10_EXP16_VP = 0x12f,
+	CSI2_PIX_FMT_RAW8 = 0x2a,
+	CSI2_PIX_FMT_RAW8_DPCM10_EXP16 = 0x2aa,
+	CSI2_PIX_FMT_RAW8_DPCM10_VP = 0x32a,
+	CSI2_PIX_FMT_RAW8_VP = 0x12a,
+	CSI2_USERDEF_8BIT_DATA1_DPCM10_VP = 0x340,
+	CSI2_USERDEF_8BIT_DATA1_DPCM10 = 0x2c0,
+	CSI2_USERDEF_8BIT_DATA1 = 0x40,
+};
+
+enum isp_csi2_irqevents {
+	OCP_ERR_IRQ = 0x4000,
+	SHORT_PACKET_IRQ = 0x2000,
+	ECC_CORRECTION_IRQ = 0x1000,
+	ECC_NO_CORRECTION_IRQ = 0x800,
+	COMPLEXIO2_ERR_IRQ = 0x400,
+	COMPLEXIO1_ERR_IRQ = 0x200,
+	FIFO_OVF_IRQ = 0x100,
+	CONTEXT7 = 0x80,
+	CONTEXT6 = 0x40,
+	CONTEXT5 = 0x20,
+	CONTEXT4 = 0x10,
+	CONTEXT3 = 0x8,
+	CONTEXT2 = 0x4,
+	CONTEXT1 = 0x2,
+	CONTEXT0 = 0x1,
+};
+
+enum isp_csi2_ctx_irqevents {
+	CTX_ECC_CORRECTION = 0x100,
+	CTX_LINE_NUMBER = 0x80,
+	CTX_FRAME_NUMBER = 0x40,
+	CTX_CS = 0x20,
+	CTX_LE = 0x8,
+	CTX_LS = 0x4,
+	CTX_FE = 0x2,
+	CTX_FS = 0x1,
+};
+
+enum isp_csi2_frame_mode {
+	ISP_CSI2_FRAME_IMMEDIATE,
+	ISP_CSI2_FRAME_AFTERFEC,
+};
+
+#define ISP_CSI2_MAX_CTX_NUM	7
+
+struct isp_csi2_ctx_cfg {
+	u8 ctxnum;		/* context number 0 - 7 */
+	u8 dpcm_decompress;
+
+	/* Fields in CSI2_CTx_CTRL2 - locked by CSI2_CTx_CTRL1.CTX_EN */
+	u8 virtual_id;
+	u16 format_id;		/* as in CSI2_CTx_CTRL2[9:0] */
+	u8 dpcm_predictor;	/* 1: simple, 0: advanced */
+
+	/* Fields in CSI2_CTx_CTRL1/3 - Shadowed */
+	u16 alpha;
+	u16 data_offset;
+	u32 ping_addr;
+	u32 pong_addr;
+	u8 eof_enabled;
+	u8 eol_enabled;
+	u8 checksum_enabled;
+	u8 enabled;
+};
+
+struct isp_csi2_timing_cfg {
+	u8 ionum;			/* IO1 or IO2 as in CSI2_TIMING */
+	unsigned force_rx_mode:1;
+	unsigned stop_state_16x:1;
+	unsigned stop_state_4x:1;
+	u16 stop_state_counter;
+};
+
+struct isp_csi2_ctrl_cfg {
+	bool vp_clk_enable;
+	bool vp_only_enable;
+	u8 vp_out_ctrl;
+	enum isp_csi2_frame_mode frame_mode;
+	bool ecc_enable;
+	bool if_enable;
+};
+
+#define CSI2_PAD_SINK		0
+#define CSI2_PAD_SOURCE		1
+#define CSI2_PADS_NUM		2
+
+#define CSI2_OUTPUT_CCDC	(1 << 0)
+#define CSI2_OUTPUT_MEMORY	(1 << 1)
+
+struct isp_csi2_device {
+	struct v4l2_subdev subdev;
+	struct media_pad pads[CSI2_PADS_NUM];
+	struct v4l2_mbus_framefmt formats[CSI2_PADS_NUM];
+
+	struct isp_video video_out;
+	struct isp_device *isp;
+
+	u8 available;		/* Is the IP present on the silicon? */
+
+	/* mem resources - enums as defined in enum isp_mem_resources */
+	u8 regs1;
+	u8 regs2;
+
+	u32 output; /* output to CCDC, memory or both? */
+	bool dpcm_decompress;
+	unsigned int frame_skip;
+
+	struct isp_csiphy *phy;
+	struct isp_csi2_ctx_cfg contexts[ISP_CSI2_MAX_CTX_NUM + 1];
+	struct isp_csi2_timing_cfg timing[2];
+	struct isp_csi2_ctrl_cfg ctrl;
+	enum isp_pipeline_stream_state state;
+	wait_queue_head_t wait;
+	atomic_t stopping;
+};
+
+void omap3isp_csi2_isr(struct isp_csi2_device *csi2);
+int omap3isp_csi2_reset(struct isp_csi2_device *csi2);
+int omap3isp_csi2_init(struct isp_device *isp);
+void omap3isp_csi2_cleanup(struct isp_device *isp);
+void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2);
+int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2,
+				    struct v4l2_device *vdev);
+#endif	/* OMAP3_ISP_CSI2_H */
diff --git a/drivers/media/platform/omap3isp/ispcsiphy.c b/drivers/media/platform/omap3isp/ispcsiphy.c
new file mode 100644
index 0000000..348f67e
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispcsiphy.c
@@ -0,0 +1,249 @@
+/*
+ * ispcsiphy.c
+ *
+ * TI OMAP3 ISP - CSI PHY module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/regulator/consumer.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispcsiphy.h"
+
+/*
+ * csiphy_lanes_config - Configuration of CSIPHY lanes.
+ *
+ * Updates HW configuration.
+ * Called with phy->mutex taken.
+ */
+static void csiphy_lanes_config(struct isp_csiphy *phy)
+{
+	unsigned int i;
+	u32 reg;
+
+	reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG);
+
+	for (i = 0; i < phy->num_data_lanes; i++) {
+		reg &= ~(ISPCSI2_PHY_CFG_DATA_POL_MASK(i + 1) |
+			 ISPCSI2_PHY_CFG_DATA_POSITION_MASK(i + 1));
+		reg |= (phy->lanes.data[i].pol <<
+			ISPCSI2_PHY_CFG_DATA_POL_SHIFT(i + 1));
+		reg |= (phy->lanes.data[i].pos <<
+			ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(i + 1));
+	}
+
+	reg &= ~(ISPCSI2_PHY_CFG_CLOCK_POL_MASK |
+		 ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK);
+	reg |= phy->lanes.clk.pol << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT;
+	reg |= phy->lanes.clk.pos << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT;
+
+	isp_reg_writel(phy->isp, reg, phy->cfg_regs, ISPCSI2_PHY_CFG);
+}
+
+/*
+ * csiphy_power_autoswitch_enable
+ * @enable: Sets or clears the autoswitch function enable flag.
+ */
+static void csiphy_power_autoswitch_enable(struct isp_csiphy *phy, bool enable)
+{
+	isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG,
+			ISPCSI2_PHY_CFG_PWR_AUTO,
+			enable ? ISPCSI2_PHY_CFG_PWR_AUTO : 0);
+}
+
+/*
+ * csiphy_set_power
+ * @power: Power state to be set.
+ *
+ * Returns 0 if successful, or -EBUSY if the retry count is exceeded.
+ */
+static int csiphy_set_power(struct isp_csiphy *phy, u32 power)
+{
+	u32 reg;
+	u8 retry_count;
+
+	isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG,
+			ISPCSI2_PHY_CFG_PWR_CMD_MASK, power);
+
+	retry_count = 0;
+	do {
+		udelay(50);
+		reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG) &
+				    ISPCSI2_PHY_CFG_PWR_STATUS_MASK;
+
+		if (reg != power >> 2)
+			retry_count++;
+
+	} while ((reg != power >> 2) && (retry_count < 100));
+
+	if (retry_count == 100) {
+		printk(KERN_ERR "CSI2 CIO set power failed!\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+/*
+ * csiphy_dphy_config - Configure CSI2 D-PHY parameters.
+ *
+ * Called with phy->mutex taken.
+ */
+static void csiphy_dphy_config(struct isp_csiphy *phy)
+{
+	u32 reg;
+
+	/* Set up ISPCSIPHY_REG0 */
+	reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG0);
+
+	reg &= ~(ISPCSIPHY_REG0_THS_TERM_MASK |
+		 ISPCSIPHY_REG0_THS_SETTLE_MASK);
+	reg |= phy->dphy.ths_term << ISPCSIPHY_REG0_THS_TERM_SHIFT;
+	reg |= phy->dphy.ths_settle << ISPCSIPHY_REG0_THS_SETTLE_SHIFT;
+
+	isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG0);
+
+	/* Set up ISPCSIPHY_REG1 */
+	reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG1);
+
+	reg &= ~(ISPCSIPHY_REG1_TCLK_TERM_MASK |
+		 ISPCSIPHY_REG1_TCLK_MISS_MASK |
+		 ISPCSIPHY_REG1_TCLK_SETTLE_MASK);
+	reg |= phy->dphy.tclk_term << ISPCSIPHY_REG1_TCLK_TERM_SHIFT;
+	reg |= phy->dphy.tclk_miss << ISPCSIPHY_REG1_TCLK_MISS_SHIFT;
+	reg |= phy->dphy.tclk_settle << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT;
+
+	isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1);
+}
+
+static int csiphy_config(struct isp_csiphy *phy,
+			 struct isp_csiphy_dphy_cfg *dphy,
+			 struct isp_csiphy_lanes_cfg *lanes)
+{
+	unsigned int used_lanes = 0;
+	unsigned int i;
+
+	/* Clock and data lanes verification */
+	for (i = 0; i < phy->num_data_lanes; i++) {
+		if (lanes->data[i].pol > 1 || lanes->data[i].pos > 3)
+			return -EINVAL;
+
+		if (used_lanes & (1 << lanes->data[i].pos))
+			return -EINVAL;
+
+		used_lanes |= 1 << lanes->data[i].pos;
+	}
+
+	if (lanes->clk.pol > 1 || lanes->clk.pos > 3)
+		return -EINVAL;
+
+	if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos))
+		return -EINVAL;
+
+	mutex_lock(&phy->mutex);
+	phy->dphy = *dphy;
+	phy->lanes = *lanes;
+	mutex_unlock(&phy->mutex);
+
+	return 0;
+}
+
+int omap3isp_csiphy_acquire(struct isp_csiphy *phy)
+{
+	int rval;
+
+	if (phy->vdd == NULL) {
+		dev_err(phy->isp->dev, "Power regulator for CSI PHY not "
+			"available\n");
+		return -ENODEV;
+	}
+
+	mutex_lock(&phy->mutex);
+
+	rval = regulator_enable(phy->vdd);
+	if (rval < 0)
+		goto done;
+
+	rval = omap3isp_csi2_reset(phy->csi2);
+	if (rval < 0)
+		goto done;
+
+	csiphy_dphy_config(phy);
+	csiphy_lanes_config(phy);
+
+	rval = csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_ON);
+	if (rval) {
+		regulator_disable(phy->vdd);
+		goto done;
+	}
+
+	csiphy_power_autoswitch_enable(phy, true);
+	phy->phy_in_use = 1;
+
+done:
+	mutex_unlock(&phy->mutex);
+	return rval;
+}
+
+void omap3isp_csiphy_release(struct isp_csiphy *phy)
+{
+	mutex_lock(&phy->mutex);
+	if (phy->phy_in_use) {
+		csiphy_power_autoswitch_enable(phy, false);
+		csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF);
+		regulator_disable(phy->vdd);
+		phy->phy_in_use = 0;
+	}
+	mutex_unlock(&phy->mutex);
+}
+
+/*
+ * omap3isp_csiphy_init - Initialize the CSI PHY frontends
+ */
+int omap3isp_csiphy_init(struct isp_device *isp)
+{
+	struct isp_csiphy *phy1 = &isp->isp_csiphy1;
+	struct isp_csiphy *phy2 = &isp->isp_csiphy2;
+
+	isp->platform_cb.csiphy_config = csiphy_config;
+
+	phy2->isp = isp;
+	phy2->csi2 = &isp->isp_csi2a;
+	phy2->num_data_lanes = ISP_CSIPHY2_NUM_DATA_LANES;
+	phy2->cfg_regs = OMAP3_ISP_IOMEM_CSI2A_REGS1;
+	phy2->phy_regs = OMAP3_ISP_IOMEM_CSIPHY2;
+	mutex_init(&phy2->mutex);
+
+	if (isp->revision == ISP_REVISION_15_0) {
+		phy1->isp = isp;
+		phy1->csi2 = &isp->isp_csi2c;
+		phy1->num_data_lanes = ISP_CSIPHY1_NUM_DATA_LANES;
+		phy1->cfg_regs = OMAP3_ISP_IOMEM_CSI2C_REGS1;
+		phy1->phy_regs = OMAP3_ISP_IOMEM_CSIPHY1;
+		mutex_init(&phy1->mutex);
+	}
+
+	return 0;
+}
diff --git a/drivers/media/platform/omap3isp/ispcsiphy.h b/drivers/media/platform/omap3isp/ispcsiphy.h
new file mode 100644
index 0000000..e93a661
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispcsiphy.h
@@ -0,0 +1,63 @@
+/*
+ * ispcsiphy.h
+ *
+ * TI OMAP3 ISP - CSI PHY module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_CSI_PHY_H
+#define OMAP3_ISP_CSI_PHY_H
+
+#include <media/omap3isp.h>
+
+struct isp_csi2_device;
+struct regulator;
+
+struct isp_csiphy_dphy_cfg {
+	u8 ths_term;
+	u8 ths_settle;
+	u8 tclk_term;
+	unsigned tclk_miss:1;
+	u8 tclk_settle;
+};
+
+struct isp_csiphy {
+	struct isp_device *isp;
+	struct mutex mutex;	/* serialize csiphy configuration */
+	u8 phy_in_use;
+	struct isp_csi2_device *csi2;
+	struct regulator *vdd;
+
+	/* mem resources - enums as defined in enum isp_mem_resources */
+	unsigned int cfg_regs;
+	unsigned int phy_regs;
+
+	u8 num_data_lanes;	/* number of CSI2 Data Lanes supported */
+	struct isp_csiphy_lanes_cfg lanes;
+	struct isp_csiphy_dphy_cfg dphy;
+};
+
+int omap3isp_csiphy_acquire(struct isp_csiphy *phy);
+void omap3isp_csiphy_release(struct isp_csiphy *phy);
+int omap3isp_csiphy_init(struct isp_device *isp);
+
+#endif	/* OMAP3_ISP_CSI_PHY_H */
diff --git a/drivers/media/platform/omap3isp/isph3a.h b/drivers/media/platform/omap3isp/isph3a.h
new file mode 100644
index 0000000..fb09fd4
--- /dev/null
+++ b/drivers/media/platform/omap3isp/isph3a.h
@@ -0,0 +1,117 @@
+/*
+ * isph3a.h
+ *
+ * TI OMAP3 ISP - H3A AF module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: David Cohen <dacohen@gmail.com>
+ *	     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_H3A_H
+#define OMAP3_ISP_H3A_H
+
+#include <linux/omap3isp.h>
+
+/*
+ * ----------
+ * -H3A AEWB-
+ * ----------
+ */
+
+#define AEWB_PACKET_SIZE	16
+#define AEWB_SATURATION_LIMIT	0x3ff
+
+/* Flags for changed registers */
+#define PCR_CHNG		(1 << 0)
+#define AEWWIN1_CHNG		(1 << 1)
+#define AEWINSTART_CHNG		(1 << 2)
+#define AEWINBLK_CHNG		(1 << 3)
+#define AEWSUBWIN_CHNG		(1 << 4)
+#define PRV_WBDGAIN_CHNG	(1 << 5)
+#define PRV_WBGAIN_CHNG		(1 << 6)
+
+/* ISPH3A REGISTERS bits */
+#define ISPH3A_PCR_AF_EN	(1 << 0)
+#define ISPH3A_PCR_AF_ALAW_EN	(1 << 1)
+#define ISPH3A_PCR_AF_MED_EN	(1 << 2)
+#define ISPH3A_PCR_AF_BUSY	(1 << 15)
+#define ISPH3A_PCR_AEW_EN	(1 << 16)
+#define ISPH3A_PCR_AEW_ALAW_EN	(1 << 17)
+#define ISPH3A_PCR_AEW_BUSY	(1 << 18)
+#define ISPH3A_PCR_AEW_MASK	(ISPH3A_PCR_AEW_ALAW_EN | \
+				 ISPH3A_PCR_AEW_AVE2LMT_MASK)
+
+/*
+ * --------
+ * -H3A AF-
+ * --------
+ */
+
+/* Peripheral Revision */
+#define AFPID				0x0
+
+#define AFCOEF_OFFSET			0x00000004	/* COEF base address */
+
+/* PCR fields */
+#define AF_BUSYAF			(1 << 15)
+#define AF_FVMODE			(1 << 14)
+#define AF_RGBPOS			(0x7 << 11)
+#define AF_MED_TH			(0xFF << 3)
+#define AF_MED_EN			(1 << 2)
+#define AF_ALAW_EN			(1 << 1)
+#define AF_EN				(1 << 0)
+#define AF_PCR_MASK			(AF_FVMODE | AF_RGBPOS | AF_MED_TH | \
+					 AF_MED_EN | AF_ALAW_EN)
+
+/* AFPAX1 fields */
+#define AF_PAXW				(0x7F << 16)
+#define AF_PAXH				0x7F
+
+/* AFPAX2 fields */
+#define AF_AFINCV			(0xF << 13)
+#define AF_PAXVC			(0x7F << 6)
+#define AF_PAXHC			0x3F
+
+/* AFPAXSTART fields */
+#define AF_PAXSH			(0xFFF<<16)
+#define AF_PAXSV			0xFFF
+
+/* COEFFICIENT MASK */
+#define AF_COEF_MASK0			0xFFF
+#define AF_COEF_MASK1			(0xFFF<<16)
+
+/* BIT SHIFTS */
+#define AF_RGBPOS_SHIFT			11
+#define AF_MED_TH_SHIFT			3
+#define AF_PAXW_SHIFT			16
+#define AF_LINE_INCR_SHIFT		13
+#define AF_VT_COUNT_SHIFT		6
+#define AF_HZ_START_SHIFT		16
+#define AF_COEF_SHIFT			16
+
+/* Init and cleanup functions */
+int omap3isp_h3a_aewb_init(struct isp_device *isp);
+int omap3isp_h3a_af_init(struct isp_device *isp);
+
+void omap3isp_h3a_aewb_cleanup(struct isp_device *isp);
+void omap3isp_h3a_af_cleanup(struct isp_device *isp);
+
+#endif /* OMAP3_ISP_H3A_H */
diff --git a/drivers/media/platform/omap3isp/isph3a_aewb.c b/drivers/media/platform/omap3isp/isph3a_aewb.c
new file mode 100644
index 0000000..036e996
--- /dev/null
+++ b/drivers/media/platform/omap3isp/isph3a_aewb.c
@@ -0,0 +1,368 @@
+/*
+ * isph3a.c
+ *
+ * TI OMAP3 ISP - H3A module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: David Cohen <dacohen@gmail.com>
+ *	     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "isp.h"
+#include "isph3a.h"
+#include "ispstat.h"
+
+/*
+ * h3a_aewb_update_regs - Helper function to update h3a registers.
+ */
+static void h3a_aewb_setup_regs(struct ispstat *aewb, void *priv)
+{
+	struct omap3isp_h3a_aewb_config *conf = priv;
+	u32 pcr;
+	u32 win1;
+	u32 start;
+	u32 blk;
+	u32 subwin;
+
+	if (aewb->state == ISPSTAT_DISABLED)
+		return;
+
+	isp_reg_writel(aewb->isp, aewb->active_buf->iommu_addr,
+		       OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST);
+
+	if (!aewb->update)
+		return;
+
+	/* Converting config metadata into reg values */
+	pcr = conf->saturation_limit << ISPH3A_PCR_AEW_AVE2LMT_SHIFT;
+	pcr |= !!conf->alaw_enable << ISPH3A_PCR_AEW_ALAW_EN_SHIFT;
+
+	win1 = ((conf->win_height >> 1) - 1) << ISPH3A_AEWWIN1_WINH_SHIFT;
+	win1 |= ((conf->win_width >> 1) - 1) << ISPH3A_AEWWIN1_WINW_SHIFT;
+	win1 |= (conf->ver_win_count - 1) << ISPH3A_AEWWIN1_WINVC_SHIFT;
+	win1 |= (conf->hor_win_count - 1) << ISPH3A_AEWWIN1_WINHC_SHIFT;
+
+	start = conf->hor_win_start << ISPH3A_AEWINSTART_WINSH_SHIFT;
+	start |= conf->ver_win_start << ISPH3A_AEWINSTART_WINSV_SHIFT;
+
+	blk = conf->blk_ver_win_start << ISPH3A_AEWINBLK_WINSV_SHIFT;
+	blk |= ((conf->blk_win_height >> 1) - 1) << ISPH3A_AEWINBLK_WINH_SHIFT;
+
+	subwin = ((conf->subsample_ver_inc >> 1) - 1) <<
+		 ISPH3A_AEWSUBWIN_AEWINCV_SHIFT;
+	subwin |= ((conf->subsample_hor_inc >> 1) - 1) <<
+		  ISPH3A_AEWSUBWIN_AEWINCH_SHIFT;
+
+	isp_reg_writel(aewb->isp, win1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1);
+	isp_reg_writel(aewb->isp, start, OMAP3_ISP_IOMEM_H3A,
+		       ISPH3A_AEWINSTART);
+	isp_reg_writel(aewb->isp, blk, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK);
+	isp_reg_writel(aewb->isp, subwin, OMAP3_ISP_IOMEM_H3A,
+		       ISPH3A_AEWSUBWIN);
+	isp_reg_clr_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+			ISPH3A_PCR_AEW_MASK, pcr);
+
+	aewb->update = 0;
+	aewb->config_counter += aewb->inc_config;
+	aewb->inc_config = 0;
+	aewb->buf_size = conf->buf_size;
+}
+
+static void h3a_aewb_enable(struct ispstat *aewb, int enable)
+{
+	if (enable) {
+		isp_reg_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+			    ISPH3A_PCR_AEW_EN);
+		omap3isp_subclk_enable(aewb->isp, OMAP3_ISP_SUBCLK_AEWB);
+	} else {
+		isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+			    ISPH3A_PCR_AEW_EN);
+		omap3isp_subclk_disable(aewb->isp, OMAP3_ISP_SUBCLK_AEWB);
+	}
+}
+
+static int h3a_aewb_busy(struct ispstat *aewb)
+{
+	return isp_reg_readl(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
+						& ISPH3A_PCR_BUSYAEAWB;
+}
+
+static u32 h3a_aewb_get_buf_size(struct omap3isp_h3a_aewb_config *conf)
+{
+	/* Number of configured windows + extra row for black data */
+	u32 win_count = (conf->ver_win_count + 1) * conf->hor_win_count;
+
+	/*
+	 * Unsaturated block counts for each 8 windows.
+	 * 1 extra for the last (win_count % 8) windows if win_count is not
+	 * divisible by 8.
+	 */
+	win_count += (win_count + 7) / 8;
+
+	return win_count * AEWB_PACKET_SIZE;
+}
+
+static int h3a_aewb_validate_params(struct ispstat *aewb, void *new_conf)
+{
+	struct omap3isp_h3a_aewb_config *user_cfg = new_conf;
+	u32 buf_size;
+
+	if (unlikely(user_cfg->saturation_limit >
+		     OMAP3ISP_AEWB_MAX_SATURATION_LIM))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->win_height < OMAP3ISP_AEWB_MIN_WIN_H ||
+		     user_cfg->win_height > OMAP3ISP_AEWB_MAX_WIN_H ||
+		     user_cfg->win_height & 0x01))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->win_width < OMAP3ISP_AEWB_MIN_WIN_W ||
+		     user_cfg->win_width > OMAP3ISP_AEWB_MAX_WIN_W ||
+		     user_cfg->win_width & 0x01))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->ver_win_count < OMAP3ISP_AEWB_MIN_WINVC ||
+		     user_cfg->ver_win_count > OMAP3ISP_AEWB_MAX_WINVC))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->hor_win_count < OMAP3ISP_AEWB_MIN_WINHC ||
+		     user_cfg->hor_win_count > OMAP3ISP_AEWB_MAX_WINHC))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->hor_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->blk_ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->blk_win_height < OMAP3ISP_AEWB_MIN_WIN_H ||
+		     user_cfg->blk_win_height > OMAP3ISP_AEWB_MAX_WIN_H ||
+		     user_cfg->blk_win_height & 0x01))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->subsample_ver_inc < OMAP3ISP_AEWB_MIN_SUB_INC ||
+		     user_cfg->subsample_ver_inc > OMAP3ISP_AEWB_MAX_SUB_INC ||
+		     user_cfg->subsample_ver_inc & 0x01))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->subsample_hor_inc < OMAP3ISP_AEWB_MIN_SUB_INC ||
+		     user_cfg->subsample_hor_inc > OMAP3ISP_AEWB_MAX_SUB_INC ||
+		     user_cfg->subsample_hor_inc & 0x01))
+		return -EINVAL;
+
+	buf_size = h3a_aewb_get_buf_size(user_cfg);
+	if (buf_size > user_cfg->buf_size)
+		user_cfg->buf_size = buf_size;
+	else if (user_cfg->buf_size > OMAP3ISP_AEWB_MAX_BUF_SIZE)
+		user_cfg->buf_size = OMAP3ISP_AEWB_MAX_BUF_SIZE;
+
+	return 0;
+}
+
+/*
+ * h3a_aewb_set_params - Helper function to check & store user given params.
+ * @new_conf: Pointer to AE and AWB parameters struct.
+ *
+ * As most of them are busy-lock registers, need to wait until AEW_BUSY = 0 to
+ * program them during ISR.
+ */
+static void h3a_aewb_set_params(struct ispstat *aewb, void *new_conf)
+{
+	struct omap3isp_h3a_aewb_config *user_cfg = new_conf;
+	struct omap3isp_h3a_aewb_config *cur_cfg = aewb->priv;
+	int update = 0;
+
+	if (cur_cfg->saturation_limit != user_cfg->saturation_limit) {
+		cur_cfg->saturation_limit = user_cfg->saturation_limit;
+		update = 1;
+	}
+	if (cur_cfg->alaw_enable != user_cfg->alaw_enable) {
+		cur_cfg->alaw_enable = user_cfg->alaw_enable;
+		update = 1;
+	}
+	if (cur_cfg->win_height != user_cfg->win_height) {
+		cur_cfg->win_height = user_cfg->win_height;
+		update = 1;
+	}
+	if (cur_cfg->win_width != user_cfg->win_width) {
+		cur_cfg->win_width = user_cfg->win_width;
+		update = 1;
+	}
+	if (cur_cfg->ver_win_count != user_cfg->ver_win_count) {
+		cur_cfg->ver_win_count = user_cfg->ver_win_count;
+		update = 1;
+	}
+	if (cur_cfg->hor_win_count != user_cfg->hor_win_count) {
+		cur_cfg->hor_win_count = user_cfg->hor_win_count;
+		update = 1;
+	}
+	if (cur_cfg->ver_win_start != user_cfg->ver_win_start) {
+		cur_cfg->ver_win_start = user_cfg->ver_win_start;
+		update = 1;
+	}
+	if (cur_cfg->hor_win_start != user_cfg->hor_win_start) {
+		cur_cfg->hor_win_start = user_cfg->hor_win_start;
+		update = 1;
+	}
+	if (cur_cfg->blk_ver_win_start != user_cfg->blk_ver_win_start) {
+		cur_cfg->blk_ver_win_start = user_cfg->blk_ver_win_start;
+		update = 1;
+	}
+	if (cur_cfg->blk_win_height != user_cfg->blk_win_height) {
+		cur_cfg->blk_win_height = user_cfg->blk_win_height;
+		update = 1;
+	}
+	if (cur_cfg->subsample_ver_inc != user_cfg->subsample_ver_inc) {
+		cur_cfg->subsample_ver_inc = user_cfg->subsample_ver_inc;
+		update = 1;
+	}
+	if (cur_cfg->subsample_hor_inc != user_cfg->subsample_hor_inc) {
+		cur_cfg->subsample_hor_inc = user_cfg->subsample_hor_inc;
+		update = 1;
+	}
+
+	if (update || !aewb->configured) {
+		aewb->inc_config++;
+		aewb->update = 1;
+		cur_cfg->buf_size = h3a_aewb_get_buf_size(cur_cfg);
+	}
+}
+
+static long h3a_aewb_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+	struct ispstat *stat = v4l2_get_subdevdata(sd);
+
+	switch (cmd) {
+	case VIDIOC_OMAP3ISP_AEWB_CFG:
+		return omap3isp_stat_config(stat, arg);
+	case VIDIOC_OMAP3ISP_STAT_REQ:
+		return omap3isp_stat_request_statistics(stat, arg);
+	case VIDIOC_OMAP3ISP_STAT_EN: {
+		unsigned long *en = arg;
+		return omap3isp_stat_enable(stat, !!*en);
+	}
+	}
+
+	return -ENOIOCTLCMD;
+}
+
+static const struct ispstat_ops h3a_aewb_ops = {
+	.validate_params	= h3a_aewb_validate_params,
+	.set_params		= h3a_aewb_set_params,
+	.setup_regs		= h3a_aewb_setup_regs,
+	.enable			= h3a_aewb_enable,
+	.busy			= h3a_aewb_busy,
+};
+
+static const struct v4l2_subdev_core_ops h3a_aewb_subdev_core_ops = {
+	.ioctl = h3a_aewb_ioctl,
+	.subscribe_event = omap3isp_stat_subscribe_event,
+	.unsubscribe_event = omap3isp_stat_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_video_ops h3a_aewb_subdev_video_ops = {
+	.s_stream = omap3isp_stat_s_stream,
+};
+
+static const struct v4l2_subdev_ops h3a_aewb_subdev_ops = {
+	.core = &h3a_aewb_subdev_core_ops,
+	.video = &h3a_aewb_subdev_video_ops,
+};
+
+/*
+ * omap3isp_h3a_aewb_init - Module Initialisation.
+ */
+int omap3isp_h3a_aewb_init(struct isp_device *isp)
+{
+	struct ispstat *aewb = &isp->isp_aewb;
+	struct omap3isp_h3a_aewb_config *aewb_cfg;
+	struct omap3isp_h3a_aewb_config *aewb_recover_cfg;
+	int ret;
+
+	aewb_cfg = kzalloc(sizeof(*aewb_cfg), GFP_KERNEL);
+	if (!aewb_cfg)
+		return -ENOMEM;
+
+	memset(aewb, 0, sizeof(*aewb));
+	aewb->ops = &h3a_aewb_ops;
+	aewb->priv = aewb_cfg;
+	aewb->dma_ch = -1;
+	aewb->event_type = V4L2_EVENT_OMAP3ISP_AEWB;
+	aewb->isp = isp;
+
+	/* Set recover state configuration */
+	aewb_recover_cfg = kzalloc(sizeof(*aewb_recover_cfg), GFP_KERNEL);
+	if (!aewb_recover_cfg) {
+		dev_err(aewb->isp->dev, "AEWB: cannot allocate memory for "
+					"recover configuration.\n");
+		ret = -ENOMEM;
+		goto err_recover_alloc;
+	}
+
+	aewb_recover_cfg->saturation_limit = OMAP3ISP_AEWB_MAX_SATURATION_LIM;
+	aewb_recover_cfg->win_height = OMAP3ISP_AEWB_MIN_WIN_H;
+	aewb_recover_cfg->win_width = OMAP3ISP_AEWB_MIN_WIN_W;
+	aewb_recover_cfg->ver_win_count = OMAP3ISP_AEWB_MIN_WINVC;
+	aewb_recover_cfg->hor_win_count = OMAP3ISP_AEWB_MIN_WINHC;
+	aewb_recover_cfg->blk_ver_win_start = aewb_recover_cfg->ver_win_start +
+		aewb_recover_cfg->win_height * aewb_recover_cfg->ver_win_count;
+	aewb_recover_cfg->blk_win_height = OMAP3ISP_AEWB_MIN_WIN_H;
+	aewb_recover_cfg->subsample_ver_inc = OMAP3ISP_AEWB_MIN_SUB_INC;
+	aewb_recover_cfg->subsample_hor_inc = OMAP3ISP_AEWB_MIN_SUB_INC;
+
+	if (h3a_aewb_validate_params(aewb, aewb_recover_cfg)) {
+		dev_err(aewb->isp->dev, "AEWB: recover configuration is "
+					"invalid.\n");
+		ret = -EINVAL;
+		goto err_conf;
+	}
+
+	aewb_recover_cfg->buf_size = h3a_aewb_get_buf_size(aewb_recover_cfg);
+	aewb->recover_priv = aewb_recover_cfg;
+
+	ret = omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops);
+	if (ret)
+		goto err_conf;
+
+	return 0;
+
+err_conf:
+	kfree(aewb_recover_cfg);
+err_recover_alloc:
+	kfree(aewb_cfg);
+
+	return ret;
+}
+
+/*
+ * omap3isp_h3a_aewb_cleanup - Module exit.
+ */
+void omap3isp_h3a_aewb_cleanup(struct isp_device *isp)
+{
+	kfree(isp->isp_aewb.priv);
+	kfree(isp->isp_aewb.recover_priv);
+	omap3isp_stat_cleanup(&isp->isp_aewb);
+}
diff --git a/drivers/media/platform/omap3isp/isph3a_af.c b/drivers/media/platform/omap3isp/isph3a_af.c
new file mode 100644
index 0000000..42ccce3
--- /dev/null
+++ b/drivers/media/platform/omap3isp/isph3a_af.c
@@ -0,0 +1,423 @@
+/*
+ * isph3a_af.c
+ *
+ * TI OMAP3 ISP - H3A AF module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: David Cohen <dacohen@gmail.com>
+ *	     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+/* Linux specific include files */
+#include <linux/device.h>
+#include <linux/slab.h>
+
+#include "isp.h"
+#include "isph3a.h"
+#include "ispstat.h"
+
+#define IS_OUT_OF_BOUNDS(value, min, max)		\
+	(((value) < (min)) || ((value) > (max)))
+
+static void h3a_af_setup_regs(struct ispstat *af, void *priv)
+{
+	struct omap3isp_h3a_af_config *conf = priv;
+	u32 pcr;
+	u32 pax1;
+	u32 pax2;
+	u32 paxstart;
+	u32 coef;
+	u32 base_coef_set0;
+	u32 base_coef_set1;
+	int index;
+
+	if (af->state == ISPSTAT_DISABLED)
+		return;
+
+	isp_reg_writel(af->isp, af->active_buf->iommu_addr, OMAP3_ISP_IOMEM_H3A,
+		       ISPH3A_AFBUFST);
+
+	if (!af->update)
+		return;
+
+	/* Configure Hardware Registers */
+	pax1 = ((conf->paxel.width >> 1) - 1) << AF_PAXW_SHIFT;
+	/* Set height in AFPAX1 */
+	pax1 |= (conf->paxel.height >> 1) - 1;
+	isp_reg_writel(af->isp, pax1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1);
+
+	/* Configure AFPAX2 Register */
+	/* Set Line Increment in AFPAX2 Register */
+	pax2 = ((conf->paxel.line_inc >> 1) - 1) << AF_LINE_INCR_SHIFT;
+	/* Set Vertical Count */
+	pax2 |= (conf->paxel.v_cnt - 1) << AF_VT_COUNT_SHIFT;
+	/* Set Horizontal Count */
+	pax2 |= (conf->paxel.h_cnt - 1);
+	isp_reg_writel(af->isp, pax2, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2);
+
+	/* Configure PAXSTART Register */
+	/*Configure Horizontal Start */
+	paxstart = conf->paxel.h_start << AF_HZ_START_SHIFT;
+	/* Configure Vertical Start */
+	paxstart |= conf->paxel.v_start;
+	isp_reg_writel(af->isp, paxstart, OMAP3_ISP_IOMEM_H3A,
+		       ISPH3A_AFPAXSTART);
+
+	/*SetIIRSH Register */
+	isp_reg_writel(af->isp, conf->iir.h_start,
+		       OMAP3_ISP_IOMEM_H3A, ISPH3A_AFIIRSH);
+
+	base_coef_set0 = ISPH3A_AFCOEF010;
+	base_coef_set1 = ISPH3A_AFCOEF110;
+	for (index = 0; index <= 8; index += 2) {
+		/*Set IIR Filter0 Coefficients */
+		coef = 0;
+		coef |= conf->iir.coeff_set0[index];
+		coef |= conf->iir.coeff_set0[index + 1] <<
+			AF_COEF_SHIFT;
+		isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A,
+			       base_coef_set0);
+		base_coef_set0 += AFCOEF_OFFSET;
+
+		/*Set IIR Filter1 Coefficients */
+		coef = 0;
+		coef |= conf->iir.coeff_set1[index];
+		coef |= conf->iir.coeff_set1[index + 1] <<
+			AF_COEF_SHIFT;
+		isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A,
+			       base_coef_set1);
+		base_coef_set1 += AFCOEF_OFFSET;
+	}
+	/* set AFCOEF0010 Register */
+	isp_reg_writel(af->isp, conf->iir.coeff_set0[10],
+		       OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF0010);
+	/* set AFCOEF1010 Register */
+	isp_reg_writel(af->isp, conf->iir.coeff_set1[10],
+		       OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF1010);
+
+	/* PCR Register */
+	/* Set RGB Position */
+	pcr = conf->rgb_pos << AF_RGBPOS_SHIFT;
+	/* Set Accumulator Mode */
+	if (conf->fvmode == OMAP3ISP_AF_MODE_PEAK)
+		pcr |= AF_FVMODE;
+	/* Set A-law */
+	if (conf->alaw_enable)
+		pcr |= AF_ALAW_EN;
+	/* HMF Configurations */
+	if (conf->hmf.enable) {
+		/* Enable HMF */
+		pcr |= AF_MED_EN;
+		/* Set Median Threshold */
+		pcr |= conf->hmf.threshold << AF_MED_TH_SHIFT;
+	}
+	/* Set PCR Register */
+	isp_reg_clr_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+			AF_PCR_MASK, pcr);
+
+	af->update = 0;
+	af->config_counter += af->inc_config;
+	af->inc_config = 0;
+	af->buf_size = conf->buf_size;
+}
+
+static void h3a_af_enable(struct ispstat *af, int enable)
+{
+	if (enable) {
+		isp_reg_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+			    ISPH3A_PCR_AF_EN);
+		omap3isp_subclk_enable(af->isp, OMAP3_ISP_SUBCLK_AF);
+	} else {
+		isp_reg_clr(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+			    ISPH3A_PCR_AF_EN);
+		omap3isp_subclk_disable(af->isp, OMAP3_ISP_SUBCLK_AF);
+	}
+}
+
+static int h3a_af_busy(struct ispstat *af)
+{
+	return isp_reg_readl(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
+						& ISPH3A_PCR_BUSYAF;
+}
+
+static u32 h3a_af_get_buf_size(struct omap3isp_h3a_af_config *conf)
+{
+	return conf->paxel.h_cnt * conf->paxel.v_cnt * OMAP3ISP_AF_PAXEL_SIZE;
+}
+
+/* Function to check paxel parameters */
+static int h3a_af_validate_params(struct ispstat *af, void *new_conf)
+{
+	struct omap3isp_h3a_af_config *user_cfg = new_conf;
+	struct omap3isp_h3a_af_paxel *paxel_cfg = &user_cfg->paxel;
+	struct omap3isp_h3a_af_iir *iir_cfg = &user_cfg->iir;
+	int index;
+	u32 buf_size;
+
+	/* Check horizontal Count */
+	if (IS_OUT_OF_BOUNDS(paxel_cfg->h_cnt,
+			     OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN,
+			     OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MAX))
+		return -EINVAL;
+
+	/* Check Vertical Count */
+	if (IS_OUT_OF_BOUNDS(paxel_cfg->v_cnt,
+			     OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN,
+			     OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MAX))
+		return -EINVAL;
+
+	if (IS_OUT_OF_BOUNDS(paxel_cfg->height, OMAP3ISP_AF_PAXEL_HEIGHT_MIN,
+			     OMAP3ISP_AF_PAXEL_HEIGHT_MAX) ||
+	    paxel_cfg->height % 2)
+		return -EINVAL;
+
+	/* Check width */
+	if (IS_OUT_OF_BOUNDS(paxel_cfg->width, OMAP3ISP_AF_PAXEL_WIDTH_MIN,
+			     OMAP3ISP_AF_PAXEL_WIDTH_MAX) ||
+	    paxel_cfg->width % 2)
+		return -EINVAL;
+
+	/* Check Line Increment */
+	if (IS_OUT_OF_BOUNDS(paxel_cfg->line_inc,
+			     OMAP3ISP_AF_PAXEL_INCREMENT_MIN,
+			     OMAP3ISP_AF_PAXEL_INCREMENT_MAX) ||
+	    paxel_cfg->line_inc % 2)
+		return -EINVAL;
+
+	/* Check Horizontal Start */
+	if ((paxel_cfg->h_start < iir_cfg->h_start) ||
+	    IS_OUT_OF_BOUNDS(paxel_cfg->h_start,
+			     OMAP3ISP_AF_PAXEL_HZSTART_MIN,
+			     OMAP3ISP_AF_PAXEL_HZSTART_MAX))
+		return -EINVAL;
+
+	/* Check IIR */
+	for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) {
+		if ((iir_cfg->coeff_set0[index]) > OMAP3ISP_AF_COEF_MAX)
+			return -EINVAL;
+
+		if ((iir_cfg->coeff_set1[index]) > OMAP3ISP_AF_COEF_MAX)
+			return -EINVAL;
+	}
+
+	if (IS_OUT_OF_BOUNDS(iir_cfg->h_start, OMAP3ISP_AF_IIRSH_MIN,
+			     OMAP3ISP_AF_IIRSH_MAX))
+		return -EINVAL;
+
+	/* Hack: If paxel size is 12, the 10th AF window may be corrupted */
+	if ((paxel_cfg->h_cnt * paxel_cfg->v_cnt > 9) &&
+	    (paxel_cfg->width * paxel_cfg->height == 12))
+		return -EINVAL;
+
+	buf_size = h3a_af_get_buf_size(user_cfg);
+	if (buf_size > user_cfg->buf_size)
+		/* User buf_size request wasn't enough */
+		user_cfg->buf_size = buf_size;
+	else if (user_cfg->buf_size > OMAP3ISP_AF_MAX_BUF_SIZE)
+		user_cfg->buf_size = OMAP3ISP_AF_MAX_BUF_SIZE;
+
+	return 0;
+}
+
+/* Update local parameters */
+static void h3a_af_set_params(struct ispstat *af, void *new_conf)
+{
+	struct omap3isp_h3a_af_config *user_cfg = new_conf;
+	struct omap3isp_h3a_af_config *cur_cfg = af->priv;
+	int update = 0;
+	int index;
+
+	/* alaw */
+	if (cur_cfg->alaw_enable != user_cfg->alaw_enable) {
+		update = 1;
+		goto out;
+	}
+
+	/* hmf */
+	if (cur_cfg->hmf.enable != user_cfg->hmf.enable) {
+		update = 1;
+		goto out;
+	}
+	if (cur_cfg->hmf.threshold != user_cfg->hmf.threshold) {
+		update = 1;
+		goto out;
+	}
+
+	/* rgbpos */
+	if (cur_cfg->rgb_pos != user_cfg->rgb_pos) {
+		update = 1;
+		goto out;
+	}
+
+	/* iir */
+	if (cur_cfg->iir.h_start != user_cfg->iir.h_start) {
+		update = 1;
+		goto out;
+	}
+	for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) {
+		if (cur_cfg->iir.coeff_set0[index] !=
+				user_cfg->iir.coeff_set0[index]) {
+			update = 1;
+			goto out;
+		}
+		if (cur_cfg->iir.coeff_set1[index] !=
+				user_cfg->iir.coeff_set1[index]) {
+			update = 1;
+			goto out;
+		}
+	}
+
+	/* paxel */
+	if ((cur_cfg->paxel.width != user_cfg->paxel.width) ||
+	    (cur_cfg->paxel.height != user_cfg->paxel.height) ||
+	    (cur_cfg->paxel.h_start != user_cfg->paxel.h_start) ||
+	    (cur_cfg->paxel.v_start != user_cfg->paxel.v_start) ||
+	    (cur_cfg->paxel.h_cnt != user_cfg->paxel.h_cnt) ||
+	    (cur_cfg->paxel.v_cnt != user_cfg->paxel.v_cnt) ||
+	    (cur_cfg->paxel.line_inc != user_cfg->paxel.line_inc)) {
+		update = 1;
+		goto out;
+	}
+
+	/* af_mode */
+	if (cur_cfg->fvmode != user_cfg->fvmode)
+		update = 1;
+
+out:
+	if (update || !af->configured) {
+		memcpy(cur_cfg, user_cfg, sizeof(*cur_cfg));
+		af->inc_config++;
+		af->update = 1;
+		/*
+		 * User might be asked for a bigger buffer than necessary for
+		 * this configuration. In order to return the right amount of
+		 * data during buffer request, let's calculate the size here
+		 * instead of stick with user_cfg->buf_size.
+		 */
+		cur_cfg->buf_size = h3a_af_get_buf_size(cur_cfg);
+	}
+}
+
+static long h3a_af_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+	struct ispstat *stat = v4l2_get_subdevdata(sd);
+
+	switch (cmd) {
+	case VIDIOC_OMAP3ISP_AF_CFG:
+		return omap3isp_stat_config(stat, arg);
+	case VIDIOC_OMAP3ISP_STAT_REQ:
+		return omap3isp_stat_request_statistics(stat, arg);
+	case VIDIOC_OMAP3ISP_STAT_EN: {
+		int *en = arg;
+		return omap3isp_stat_enable(stat, !!*en);
+	}
+	}
+
+	return -ENOIOCTLCMD;
+
+}
+
+static const struct ispstat_ops h3a_af_ops = {
+	.validate_params	= h3a_af_validate_params,
+	.set_params		= h3a_af_set_params,
+	.setup_regs		= h3a_af_setup_regs,
+	.enable			= h3a_af_enable,
+	.busy			= h3a_af_busy,
+};
+
+static const struct v4l2_subdev_core_ops h3a_af_subdev_core_ops = {
+	.ioctl = h3a_af_ioctl,
+	.subscribe_event = omap3isp_stat_subscribe_event,
+	.unsubscribe_event = omap3isp_stat_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_video_ops h3a_af_subdev_video_ops = {
+	.s_stream = omap3isp_stat_s_stream,
+};
+
+static const struct v4l2_subdev_ops h3a_af_subdev_ops = {
+	.core = &h3a_af_subdev_core_ops,
+	.video = &h3a_af_subdev_video_ops,
+};
+
+/* Function to register the AF character device driver. */
+int omap3isp_h3a_af_init(struct isp_device *isp)
+{
+	struct ispstat *af = &isp->isp_af;
+	struct omap3isp_h3a_af_config *af_cfg;
+	struct omap3isp_h3a_af_config *af_recover_cfg;
+	int ret;
+
+	af_cfg = kzalloc(sizeof(*af_cfg), GFP_KERNEL);
+	if (af_cfg == NULL)
+		return -ENOMEM;
+
+	memset(af, 0, sizeof(*af));
+	af->ops = &h3a_af_ops;
+	af->priv = af_cfg;
+	af->dma_ch = -1;
+	af->event_type = V4L2_EVENT_OMAP3ISP_AF;
+	af->isp = isp;
+
+	/* Set recover state configuration */
+	af_recover_cfg = kzalloc(sizeof(*af_recover_cfg), GFP_KERNEL);
+	if (!af_recover_cfg) {
+		dev_err(af->isp->dev, "AF: cannot allocate memory for recover "
+				      "configuration.\n");
+		ret = -ENOMEM;
+		goto err_recover_alloc;
+	}
+
+	af_recover_cfg->paxel.h_start = OMAP3ISP_AF_PAXEL_HZSTART_MIN;
+	af_recover_cfg->paxel.width = OMAP3ISP_AF_PAXEL_WIDTH_MIN;
+	af_recover_cfg->paxel.height = OMAP3ISP_AF_PAXEL_HEIGHT_MIN;
+	af_recover_cfg->paxel.h_cnt = OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN;
+	af_recover_cfg->paxel.v_cnt = OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN;
+	af_recover_cfg->paxel.line_inc = OMAP3ISP_AF_PAXEL_INCREMENT_MIN;
+	if (h3a_af_validate_params(af, af_recover_cfg)) {
+		dev_err(af->isp->dev, "AF: recover configuration is "
+				      "invalid.\n");
+		ret = -EINVAL;
+		goto err_conf;
+	}
+
+	af_recover_cfg->buf_size = h3a_af_get_buf_size(af_recover_cfg);
+	af->recover_priv = af_recover_cfg;
+
+	ret = omap3isp_stat_init(af, "AF", &h3a_af_subdev_ops);
+	if (ret)
+		goto err_conf;
+
+	return 0;
+
+err_conf:
+	kfree(af_recover_cfg);
+err_recover_alloc:
+	kfree(af_cfg);
+
+	return ret;
+}
+
+void omap3isp_h3a_af_cleanup(struct isp_device *isp)
+{
+	kfree(isp->isp_af.priv);
+	kfree(isp->isp_af.recover_priv);
+	omap3isp_stat_cleanup(&isp->isp_af);
+}
diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c
new file mode 100644
index 0000000..d1a8dee
--- /dev/null
+++ b/drivers/media/platform/omap3isp/isphist.c
@@ -0,0 +1,518 @@
+/*
+ * isphist.c
+ *
+ * TI OMAP3 ISP - Histogram module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: David Cohen <dacohen@gmail.com>
+ *	     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/device.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "isphist.h"
+
+#define HIST_CONFIG_DMA	1
+
+#define HIST_USING_DMA(hist) ((hist)->dma_ch >= 0)
+
+/*
+ * hist_reset_mem - clear Histogram memory before start stats engine.
+ */
+static void hist_reset_mem(struct ispstat *hist)
+{
+	struct isp_device *isp = hist->isp;
+	struct omap3isp_hist_config *conf = hist->priv;
+	unsigned int i;
+
+	isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
+
+	/*
+	 * By setting it, the histogram internal buffer is being cleared at the
+	 * same time it's being read. This bit must be cleared afterwards.
+	 */
+	isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR);
+
+	/*
+	 * We'll clear 4 words at each iteration for optimization. It avoids
+	 * 3/4 of the jumps. We also know HIST_MEM_SIZE is divisible by 4.
+	 */
+	for (i = OMAP3ISP_HIST_MEM_SIZE / 4; i > 0; i--) {
+		isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+		isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+		isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+		isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+	}
+	isp_reg_clr(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR);
+
+	hist->wait_acc_frames = conf->num_acc_frames;
+}
+
+static void hist_dma_config(struct ispstat *hist)
+{
+	hist->dma_config.data_type = OMAP_DMA_DATA_TYPE_S32;
+	hist->dma_config.sync_mode = OMAP_DMA_SYNC_ELEMENT;
+	hist->dma_config.frame_count = 1;
+	hist->dma_config.src_amode = OMAP_DMA_AMODE_CONSTANT;
+	hist->dma_config.src_start = OMAP3ISP_HIST_REG_BASE + ISPHIST_DATA;
+	hist->dma_config.dst_amode = OMAP_DMA_AMODE_POST_INC;
+	hist->dma_config.src_or_dst_synch = OMAP_DMA_SRC_SYNC;
+}
+
+/*
+ * hist_setup_regs - Helper function to update Histogram registers.
+ */
+static void hist_setup_regs(struct ispstat *hist, void *priv)
+{
+	struct isp_device *isp = hist->isp;
+	struct omap3isp_hist_config *conf = priv;
+	int c;
+	u32 cnt;
+	u32 wb_gain;
+	u32 reg_hor[OMAP3ISP_HIST_MAX_REGIONS];
+	u32 reg_ver[OMAP3ISP_HIST_MAX_REGIONS];
+
+	if (!hist->update || hist->state == ISPSTAT_DISABLED ||
+	    hist->state == ISPSTAT_DISABLING)
+		return;
+
+	cnt = conf->cfa << ISPHIST_CNT_CFA_SHIFT;
+
+	wb_gain = conf->wg[0] << ISPHIST_WB_GAIN_WG00_SHIFT;
+	wb_gain |= conf->wg[1] << ISPHIST_WB_GAIN_WG01_SHIFT;
+	wb_gain |= conf->wg[2] << ISPHIST_WB_GAIN_WG02_SHIFT;
+	if (conf->cfa == OMAP3ISP_HIST_CFA_BAYER)
+		wb_gain |= conf->wg[3] << ISPHIST_WB_GAIN_WG03_SHIFT;
+
+	/* Regions size and position */
+	for (c = 0; c < OMAP3ISP_HIST_MAX_REGIONS; c++) {
+		if (c < conf->num_regions) {
+			reg_hor[c] = conf->region[c].h_start <<
+				     ISPHIST_REG_START_SHIFT;
+			reg_hor[c] = conf->region[c].h_end <<
+				     ISPHIST_REG_END_SHIFT;
+			reg_ver[c] = conf->region[c].v_start <<
+				     ISPHIST_REG_START_SHIFT;
+			reg_ver[c] = conf->region[c].v_end <<
+				     ISPHIST_REG_END_SHIFT;
+		} else {
+			reg_hor[c] = 0;
+			reg_ver[c] = 0;
+		}
+	}
+
+	cnt |= conf->hist_bins << ISPHIST_CNT_BINS_SHIFT;
+	switch (conf->hist_bins) {
+	case OMAP3ISP_HIST_BINS_256:
+		cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 8) <<
+			ISPHIST_CNT_SHIFT_SHIFT;
+		break;
+	case OMAP3ISP_HIST_BINS_128:
+		cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 7) <<
+			ISPHIST_CNT_SHIFT_SHIFT;
+		break;
+	case OMAP3ISP_HIST_BINS_64:
+		cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 6) <<
+			ISPHIST_CNT_SHIFT_SHIFT;
+		break;
+	default: /* OMAP3ISP_HIST_BINS_32 */
+		cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 5) <<
+			ISPHIST_CNT_SHIFT_SHIFT;
+		break;
+	}
+
+	hist_reset_mem(hist);
+
+	isp_reg_writel(isp, cnt, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT);
+	isp_reg_writel(isp, wb_gain,  OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN);
+	isp_reg_writel(isp, reg_hor[0], OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_HORZ);
+	isp_reg_writel(isp, reg_ver[0], OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_VERT);
+	isp_reg_writel(isp, reg_hor[1], OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_HORZ);
+	isp_reg_writel(isp, reg_ver[1], OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_VERT);
+	isp_reg_writel(isp, reg_hor[2], OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_HORZ);
+	isp_reg_writel(isp, reg_ver[2], OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_VERT);
+	isp_reg_writel(isp, reg_hor[3], OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_HORZ);
+	isp_reg_writel(isp, reg_ver[3], OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_VERT);
+
+	hist->update = 0;
+	hist->config_counter += hist->inc_config;
+	hist->inc_config = 0;
+	hist->buf_size = conf->buf_size;
+}
+
+static void hist_enable(struct ispstat *hist, int enable)
+{
+	if (enable) {
+		isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR,
+			    ISPHIST_PCR_ENABLE);
+		omap3isp_subclk_enable(hist->isp, OMAP3_ISP_SUBCLK_HIST);
+	} else {
+		isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR,
+			    ISPHIST_PCR_ENABLE);
+		omap3isp_subclk_disable(hist->isp, OMAP3_ISP_SUBCLK_HIST);
+	}
+}
+
+static int hist_busy(struct ispstat *hist)
+{
+	return isp_reg_readl(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR)
+						& ISPHIST_PCR_BUSY;
+}
+
+static void hist_dma_cb(int lch, u16 ch_status, void *data)
+{
+	struct ispstat *hist = data;
+
+	if (ch_status & ~OMAP_DMA_BLOCK_IRQ) {
+		dev_dbg(hist->isp->dev, "hist: DMA error. status = 0x%04x\n",
+			ch_status);
+		omap_stop_dma(lch);
+		hist_reset_mem(hist);
+		atomic_set(&hist->buf_err, 1);
+	}
+	isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+		    ISPHIST_CNT_CLEAR);
+
+	omap3isp_stat_dma_isr(hist);
+	if (hist->state != ISPSTAT_DISABLED)
+		omap3isp_hist_dma_done(hist->isp);
+}
+
+static int hist_buf_dma(struct ispstat *hist)
+{
+	dma_addr_t dma_addr = hist->active_buf->dma_addr;
+
+	if (unlikely(!dma_addr)) {
+		dev_dbg(hist->isp->dev, "hist: invalid DMA buffer address\n");
+		hist_reset_mem(hist);
+		return STAT_NO_BUF;
+	}
+
+	isp_reg_writel(hist->isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
+	isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+		    ISPHIST_CNT_CLEAR);
+	omap3isp_flush(hist->isp);
+	hist->dma_config.dst_start = dma_addr;
+	hist->dma_config.elem_count = hist->buf_size / sizeof(u32);
+	omap_set_dma_params(hist->dma_ch, &hist->dma_config);
+
+	omap_start_dma(hist->dma_ch);
+
+	return STAT_BUF_WAITING_DMA;
+}
+
+static int hist_buf_pio(struct ispstat *hist)
+{
+	struct isp_device *isp = hist->isp;
+	u32 *buf = hist->active_buf->virt_addr;
+	unsigned int i;
+
+	if (!buf) {
+		dev_dbg(isp->dev, "hist: invalid PIO buffer address\n");
+		hist_reset_mem(hist);
+		return STAT_NO_BUF;
+	}
+
+	isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
+
+	/*
+	 * By setting it, the histogram internal buffer is being cleared at the
+	 * same time it's being read. This bit must be cleared just after all
+	 * data is acquired.
+	 */
+	isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR);
+
+	/*
+	 * We'll read 4 times a 4-bytes-word at each iteration for
+	 * optimization. It avoids 3/4 of the jumps. We also know buf_size is
+	 * divisible by 16.
+	 */
+	for (i = hist->buf_size / 16; i > 0; i--) {
+		*buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+		*buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+		*buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+		*buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+	}
+	isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+		    ISPHIST_CNT_CLEAR);
+
+	return STAT_BUF_DONE;
+}
+
+/*
+ * hist_buf_process - Callback from ISP driver for HIST interrupt.
+ */
+static int hist_buf_process(struct ispstat *hist)
+{
+	struct omap3isp_hist_config *user_cfg = hist->priv;
+	int ret;
+
+	if (atomic_read(&hist->buf_err) || hist->state != ISPSTAT_ENABLED) {
+		hist_reset_mem(hist);
+		return STAT_NO_BUF;
+	}
+
+	if (--(hist->wait_acc_frames))
+		return STAT_NO_BUF;
+
+	if (HIST_USING_DMA(hist))
+		ret = hist_buf_dma(hist);
+	else
+		ret = hist_buf_pio(hist);
+
+	hist->wait_acc_frames = user_cfg->num_acc_frames;
+
+	return ret;
+}
+
+static u32 hist_get_buf_size(struct omap3isp_hist_config *conf)
+{
+	return OMAP3ISP_HIST_MEM_SIZE_BINS(conf->hist_bins) * conf->num_regions;
+}
+
+/*
+ * hist_validate_params - Helper function to check user given params.
+ * @user_cfg: Pointer to user configuration structure.
+ *
+ * Returns 0 on success configuration.
+ */
+static int hist_validate_params(struct ispstat *hist, void *new_conf)
+{
+	struct omap3isp_hist_config *user_cfg = new_conf;
+	int c;
+	u32 buf_size;
+
+	if (user_cfg->cfa > OMAP3ISP_HIST_CFA_FOVEONX3)
+		return -EINVAL;
+
+	/* Regions size and position */
+
+	if ((user_cfg->num_regions < OMAP3ISP_HIST_MIN_REGIONS) ||
+	    (user_cfg->num_regions > OMAP3ISP_HIST_MAX_REGIONS))
+		return -EINVAL;
+
+	/* Regions */
+	for (c = 0; c < user_cfg->num_regions; c++) {
+		if (user_cfg->region[c].h_start & ~ISPHIST_REG_START_END_MASK)
+			return -EINVAL;
+		if (user_cfg->region[c].h_end & ~ISPHIST_REG_START_END_MASK)
+			return -EINVAL;
+		if (user_cfg->region[c].v_start & ~ISPHIST_REG_START_END_MASK)
+			return -EINVAL;
+		if (user_cfg->region[c].v_end & ~ISPHIST_REG_START_END_MASK)
+			return -EINVAL;
+		if (user_cfg->region[c].h_start > user_cfg->region[c].h_end)
+			return -EINVAL;
+		if (user_cfg->region[c].v_start > user_cfg->region[c].v_end)
+			return -EINVAL;
+	}
+
+	switch (user_cfg->num_regions) {
+	case 1:
+		if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_256)
+			return -EINVAL;
+		break;
+	case 2:
+		if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_128)
+			return -EINVAL;
+		break;
+	default: /* 3 or 4 */
+		if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_64)
+			return -EINVAL;
+		break;
+	}
+
+	buf_size = hist_get_buf_size(user_cfg);
+	if (buf_size > user_cfg->buf_size)
+		/* User's buf_size request wasn't enoght */
+		user_cfg->buf_size = buf_size;
+	else if (user_cfg->buf_size > OMAP3ISP_HIST_MAX_BUF_SIZE)
+		user_cfg->buf_size = OMAP3ISP_HIST_MAX_BUF_SIZE;
+
+	return 0;
+}
+
+static int hist_comp_params(struct ispstat *hist,
+			    struct omap3isp_hist_config *user_cfg)
+{
+	struct omap3isp_hist_config *cur_cfg = hist->priv;
+	int c;
+
+	if (cur_cfg->cfa != user_cfg->cfa)
+		return 1;
+
+	if (cur_cfg->num_acc_frames != user_cfg->num_acc_frames)
+		return 1;
+
+	if (cur_cfg->hist_bins != user_cfg->hist_bins)
+		return 1;
+
+	for (c = 0; c < OMAP3ISP_HIST_MAX_WG; c++) {
+		if (c == 3 && user_cfg->cfa == OMAP3ISP_HIST_CFA_FOVEONX3)
+			break;
+		else if (cur_cfg->wg[c] != user_cfg->wg[c])
+			return 1;
+	}
+
+	if (cur_cfg->num_regions != user_cfg->num_regions)
+		return 1;
+
+	/* Regions */
+	for (c = 0; c < user_cfg->num_regions; c++) {
+		if (cur_cfg->region[c].h_start != user_cfg->region[c].h_start)
+			return 1;
+		if (cur_cfg->region[c].h_end != user_cfg->region[c].h_end)
+			return 1;
+		if (cur_cfg->region[c].v_start != user_cfg->region[c].v_start)
+			return 1;
+		if (cur_cfg->region[c].v_end != user_cfg->region[c].v_end)
+			return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * hist_update_params - Helper function to check and store user given params.
+ * @new_conf: Pointer to user configuration structure.
+ */
+static void hist_set_params(struct ispstat *hist, void *new_conf)
+{
+	struct omap3isp_hist_config *user_cfg = new_conf;
+	struct omap3isp_hist_config *cur_cfg = hist->priv;
+
+	if (!hist->configured || hist_comp_params(hist, user_cfg)) {
+		memcpy(cur_cfg, user_cfg, sizeof(*user_cfg));
+		if (user_cfg->num_acc_frames == 0)
+			user_cfg->num_acc_frames = 1;
+		hist->inc_config++;
+		hist->update = 1;
+		/*
+		 * User might be asked for a bigger buffer than necessary for
+		 * this configuration. In order to return the right amount of
+		 * data during buffer request, let's calculate the size here
+		 * instead of stick with user_cfg->buf_size.
+		 */
+		cur_cfg->buf_size = hist_get_buf_size(cur_cfg);
+
+	}
+}
+
+static long hist_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+	struct ispstat *stat = v4l2_get_subdevdata(sd);
+
+	switch (cmd) {
+	case VIDIOC_OMAP3ISP_HIST_CFG:
+		return omap3isp_stat_config(stat, arg);
+	case VIDIOC_OMAP3ISP_STAT_REQ:
+		return omap3isp_stat_request_statistics(stat, arg);
+	case VIDIOC_OMAP3ISP_STAT_EN: {
+		int *en = arg;
+		return omap3isp_stat_enable(stat, !!*en);
+	}
+	}
+
+	return -ENOIOCTLCMD;
+
+}
+
+static const struct ispstat_ops hist_ops = {
+	.validate_params	= hist_validate_params,
+	.set_params		= hist_set_params,
+	.setup_regs		= hist_setup_regs,
+	.enable			= hist_enable,
+	.busy			= hist_busy,
+	.buf_process		= hist_buf_process,
+};
+
+static const struct v4l2_subdev_core_ops hist_subdev_core_ops = {
+	.ioctl = hist_ioctl,
+	.subscribe_event = omap3isp_stat_subscribe_event,
+	.unsubscribe_event = omap3isp_stat_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_video_ops hist_subdev_video_ops = {
+	.s_stream = omap3isp_stat_s_stream,
+};
+
+static const struct v4l2_subdev_ops hist_subdev_ops = {
+	.core = &hist_subdev_core_ops,
+	.video = &hist_subdev_video_ops,
+};
+
+/*
+ * omap3isp_hist_init - Module Initialization.
+ */
+int omap3isp_hist_init(struct isp_device *isp)
+{
+	struct ispstat *hist = &isp->isp_hist;
+	struct omap3isp_hist_config *hist_cfg;
+	int ret = -1;
+
+	hist_cfg = kzalloc(sizeof(*hist_cfg), GFP_KERNEL);
+	if (hist_cfg == NULL)
+		return -ENOMEM;
+
+	memset(hist, 0, sizeof(*hist));
+	if (HIST_CONFIG_DMA)
+		ret = omap_request_dma(OMAP24XX_DMA_NO_DEVICE, "DMA_ISP_HIST",
+				       hist_dma_cb, hist, &hist->dma_ch);
+	if (ret) {
+		if (HIST_CONFIG_DMA)
+			dev_warn(isp->dev, "hist: DMA request channel failed. "
+					   "Using PIO only.\n");
+		hist->dma_ch = -1;
+	} else {
+		dev_dbg(isp->dev, "hist: DMA channel = %d\n", hist->dma_ch);
+		hist_dma_config(hist);
+		omap_enable_dma_irq(hist->dma_ch, OMAP_DMA_BLOCK_IRQ);
+	}
+
+	hist->ops = &hist_ops;
+	hist->priv = hist_cfg;
+	hist->event_type = V4L2_EVENT_OMAP3ISP_HIST;
+	hist->isp = isp;
+
+	ret = omap3isp_stat_init(hist, "histogram", &hist_subdev_ops);
+	if (ret) {
+		kfree(hist_cfg);
+		if (HIST_USING_DMA(hist))
+			omap_free_dma(hist->dma_ch);
+	}
+
+	return ret;
+}
+
+/*
+ * omap3isp_hist_cleanup - Module cleanup.
+ */
+void omap3isp_hist_cleanup(struct isp_device *isp)
+{
+	if (HIST_USING_DMA(&isp->isp_hist))
+		omap_free_dma(isp->isp_hist.dma_ch);
+	kfree(isp->isp_hist.priv);
+	omap3isp_stat_cleanup(&isp->isp_hist);
+}
diff --git a/drivers/media/platform/omap3isp/isphist.h b/drivers/media/platform/omap3isp/isphist.h
new file mode 100644
index 0000000..0b2a38e
--- /dev/null
+++ b/drivers/media/platform/omap3isp/isphist.h
@@ -0,0 +1,40 @@
+/*
+ * isphist.h
+ *
+ * TI OMAP3 ISP - Histogram module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: David Cohen <dacohen@gmail.com>
+ *	     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_HIST_H
+#define OMAP3_ISP_HIST_H
+
+#include <linux/omap3isp.h>
+
+#define ISPHIST_IN_BIT_WIDTH_CCDC	10
+
+struct isp_device;
+
+int omap3isp_hist_init(struct isp_device *isp);
+void omap3isp_hist_cleanup(struct isp_device *isp);
+
+#endif /* OMAP3_ISP_HIST */
diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c
new file mode 100644
index 0000000..1ae1c09
--- /dev/null
+++ b/drivers/media/platform/omap3isp/isppreview.c
@@ -0,0 +1,2348 @@
+/*
+ * isppreview.c
+ *
+ * TI OMAP3 ISP driver - Preview module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "isppreview.h"
+
+/* Default values in Office Fluorescent Light for RGBtoRGB Blending */
+static struct omap3isp_prev_rgbtorgb flr_rgb2rgb = {
+	{	/* RGB-RGB Matrix */
+		{0x01E2, 0x0F30, 0x0FEE},
+		{0x0F9B, 0x01AC, 0x0FB9},
+		{0x0FE0, 0x0EC0, 0x0260}
+	},	/* RGB Offset */
+	{0x0000, 0x0000, 0x0000}
+};
+
+/* Default values in Office Fluorescent Light for RGB to YUV Conversion*/
+static struct omap3isp_prev_csc flr_prev_csc = {
+	{	/* CSC Coef Matrix */
+		{66, 129, 25},
+		{-38, -75, 112},
+		{112, -94 , -18}
+	},	/* CSC Offset */
+	{0x0, 0x0, 0x0}
+};
+
+/* Default values in Office Fluorescent Light for CFA Gradient*/
+#define FLR_CFA_GRADTHRS_HORZ	0x28
+#define FLR_CFA_GRADTHRS_VERT	0x28
+
+/* Default values in Office Fluorescent Light for Chroma Suppression*/
+#define FLR_CSUP_GAIN		0x0D
+#define FLR_CSUP_THRES		0xEB
+
+/* Default values in Office Fluorescent Light for Noise Filter*/
+#define FLR_NF_STRGTH		0x03
+
+/* Default values for White Balance */
+#define FLR_WBAL_DGAIN		0x100
+#define FLR_WBAL_COEF		0x20
+
+/* Default values in Office Fluorescent Light for Black Adjustment*/
+#define FLR_BLKADJ_BLUE		0x0
+#define FLR_BLKADJ_GREEN	0x0
+#define FLR_BLKADJ_RED		0x0
+
+#define DEF_DETECT_CORRECT_VAL	0xe
+
+/*
+ * Margins and image size limits.
+ *
+ * The preview engine crops several rows and columns internally depending on
+ * which filters are enabled. To avoid format changes when the filters are
+ * enabled or disabled (which would prevent them from being turned on or off
+ * during streaming), the driver assumes all the filters are enabled when
+ * computing sink crop and source format limits.
+ *
+ * If a filter is disabled, additional cropping is automatically added at the
+ * preview engine input by the driver to avoid overflow at line and frame end.
+ * This is completely transparent for applications.
+ *
+ * Median filter		4 pixels
+ * Noise filter,
+ * Faulty pixels correction	4 pixels, 4 lines
+ * CFA filter			4 pixels, 4 lines in Bayer mode
+ *					  2 lines in other modes
+ * Color suppression		2 pixels
+ * or luma enhancement
+ * -------------------------------------------------------------
+ * Maximum total		14 pixels, 8 lines
+ *
+ * The color suppression and luma enhancement filters are applied after bayer to
+ * YUV conversion. They thus can crop one pixel on the left and one pixel on the
+ * right side of the image without changing the color pattern. When both those
+ * filters are disabled, the driver must crop the two pixels on the same side of
+ * the image to avoid changing the bayer pattern. The left margin is thus set to
+ * 8 pixels and the right margin to 6 pixels.
+ */
+
+#define PREV_MARGIN_LEFT	8
+#define PREV_MARGIN_RIGHT	6
+#define PREV_MARGIN_TOP		4
+#define PREV_MARGIN_BOTTOM	4
+
+#define PREV_MIN_IN_WIDTH	64
+#define PREV_MIN_IN_HEIGHT	8
+#define PREV_MAX_IN_HEIGHT	16384
+
+#define PREV_MIN_OUT_WIDTH		0
+#define PREV_MIN_OUT_HEIGHT		0
+#define PREV_MAX_OUT_WIDTH_REV_1	1280
+#define PREV_MAX_OUT_WIDTH_REV_2	3300
+#define PREV_MAX_OUT_WIDTH_REV_15	4096
+
+/*
+ * Coeficient Tables for the submodules in Preview.
+ * Array is initialised with the values from.the tables text file.
+ */
+
+/*
+ * CFA Filter Coefficient Table
+ *
+ */
+static u32 cfa_coef_table[4][OMAP3ISP_PREV_CFA_BLK_SIZE] = {
+#include "cfa_coef_table.h"
+};
+
+/*
+ * Default Gamma Correction Table - All components
+ */
+static u32 gamma_table[] = {
+#include "gamma_table.h"
+};
+
+/*
+ * Noise Filter Threshold table
+ */
+static u32 noise_filter_table[] = {
+#include "noise_filter_table.h"
+};
+
+/*
+ * Luminance Enhancement Table
+ */
+static u32 luma_enhance_table[] = {
+#include "luma_enhance_table.h"
+};
+
+/*
+ * preview_config_luma_enhancement - Configure the Luminance Enhancement table
+ */
+static void
+preview_config_luma_enhancement(struct isp_prev_device *prev,
+				const struct prev_params *params)
+{
+	struct isp_device *isp = to_isp_device(prev);
+	const struct omap3isp_prev_luma *yt = &params->luma;
+	unsigned int i;
+
+	isp_reg_writel(isp, ISPPRV_YENH_TABLE_ADDR,
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+	for (i = 0; i < OMAP3ISP_PREV_YENH_TBL_SIZE; i++) {
+		isp_reg_writel(isp, yt->table[i],
+			       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
+	}
+}
+
+/*
+ * preview_enable_luma_enhancement - Enable/disable Luminance Enhancement
+ */
+static void
+preview_enable_luma_enhancement(struct isp_prev_device *prev, bool enable)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	if (enable)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_YNENHEN);
+	else
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_YNENHEN);
+}
+
+/*
+ * preview_enable_invalaw - Enable/disable Inverse A-Law decompression
+ */
+static void preview_enable_invalaw(struct isp_prev_device *prev, bool enable)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	if (enable)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW);
+	else
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW);
+}
+
+/*
+ * preview_config_hmed - Configure the Horizontal Median Filter
+ */
+static void preview_config_hmed(struct isp_prev_device *prev,
+				const struct prev_params *params)
+{
+	struct isp_device *isp = to_isp_device(prev);
+	const struct omap3isp_prev_hmed *hmed = &params->hmed;
+
+	isp_reg_writel(isp, (hmed->odddist == 1 ? 0 : ISPPRV_HMED_ODDDIST) |
+		       (hmed->evendist == 1 ? 0 : ISPPRV_HMED_EVENDIST) |
+		       (hmed->thres << ISPPRV_HMED_THRESHOLD_SHIFT),
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED);
+}
+
+/*
+ * preview_enable_hmed - Enable/disable the Horizontal Median Filter
+ */
+static void preview_enable_hmed(struct isp_prev_device *prev, bool enable)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	if (enable)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_HMEDEN);
+	else
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_HMEDEN);
+}
+
+/*
+ * preview_config_cfa - Configure CFA Interpolation for Bayer formats
+ *
+ * The CFA table is organised in four blocks, one per Bayer component. The
+ * hardware expects blocks to follow the Bayer order of the input data, while
+ * the driver stores the table in GRBG order in memory. The blocks need to be
+ * reordered to support non-GRBG Bayer patterns.
+ */
+static void preview_config_cfa(struct isp_prev_device *prev,
+			       const struct prev_params *params)
+{
+	static const unsigned int cfa_coef_order[4][4] = {
+		{ 0, 1, 2, 3 }, /* GRBG */
+		{ 1, 0, 3, 2 }, /* RGGB */
+		{ 2, 3, 0, 1 }, /* BGGR */
+		{ 3, 2, 1, 0 }, /* GBRG */
+	};
+	const unsigned int *order = cfa_coef_order[prev->params.cfa_order];
+	const struct omap3isp_prev_cfa *cfa = &params->cfa;
+	struct isp_device *isp = to_isp_device(prev);
+	unsigned int i;
+	unsigned int j;
+
+	isp_reg_writel(isp,
+		(cfa->gradthrs_vert << ISPPRV_CFA_GRADTH_VER_SHIFT) |
+		(cfa->gradthrs_horz << ISPPRV_CFA_GRADTH_HOR_SHIFT),
+		OMAP3_ISP_IOMEM_PREV, ISPPRV_CFA);
+
+	isp_reg_writel(isp, ISPPRV_CFA_TABLE_ADDR,
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+
+	for (i = 0; i < 4; ++i) {
+		const __u32 *block = cfa->table[order[i]];
+
+		for (j = 0; j < OMAP3ISP_PREV_CFA_BLK_SIZE; ++j)
+			isp_reg_writel(isp, block[j], OMAP3_ISP_IOMEM_PREV,
+				       ISPPRV_SET_TBL_DATA);
+	}
+}
+
+/*
+ * preview_config_chroma_suppression - Configure Chroma Suppression
+ */
+static void
+preview_config_chroma_suppression(struct isp_prev_device *prev,
+				  const struct prev_params *params)
+{
+	struct isp_device *isp = to_isp_device(prev);
+	const struct omap3isp_prev_csup *cs = &params->csup;
+
+	isp_reg_writel(isp,
+		       cs->gain | (cs->thres << ISPPRV_CSUP_THRES_SHIFT) |
+		       (cs->hypf_en << ISPPRV_CSUP_HPYF_SHIFT),
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CSUP);
+}
+
+/*
+ * preview_enable_chroma_suppression - Enable/disable Chrominance Suppression
+ */
+static void
+preview_enable_chroma_suppression(struct isp_prev_device *prev, bool enable)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	if (enable)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_SUPEN);
+	else
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_SUPEN);
+}
+
+/*
+ * preview_config_whitebalance - Configure White Balance parameters
+ *
+ * Coefficient matrix always with default values.
+ */
+static void
+preview_config_whitebalance(struct isp_prev_device *prev,
+			    const struct prev_params *params)
+{
+	struct isp_device *isp = to_isp_device(prev);
+	const struct omap3isp_prev_wbal *wbal = &params->wbal;
+	u32 val;
+
+	isp_reg_writel(isp, wbal->dgain, OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN);
+
+	val = wbal->coef0 << ISPPRV_WBGAIN_COEF0_SHIFT;
+	val |= wbal->coef1 << ISPPRV_WBGAIN_COEF1_SHIFT;
+	val |= wbal->coef2 << ISPPRV_WBGAIN_COEF2_SHIFT;
+	val |= wbal->coef3 << ISPPRV_WBGAIN_COEF3_SHIFT;
+	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN);
+
+	isp_reg_writel(isp,
+		       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_0_SHIFT |
+		       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_1_SHIFT |
+		       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_2_SHIFT |
+		       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_3_SHIFT |
+		       ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_0_SHIFT |
+		       ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_1_SHIFT |
+		       ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_2_SHIFT |
+		       ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_3_SHIFT |
+		       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_0_SHIFT |
+		       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_1_SHIFT |
+		       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_2_SHIFT |
+		       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_3_SHIFT |
+		       ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_0_SHIFT |
+		       ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_1_SHIFT |
+		       ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_2_SHIFT |
+		       ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_3_SHIFT,
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_WBSEL);
+}
+
+/*
+ * preview_config_blkadj - Configure Black Adjustment
+ */
+static void
+preview_config_blkadj(struct isp_prev_device *prev,
+		      const struct prev_params *params)
+{
+	struct isp_device *isp = to_isp_device(prev);
+	const struct omap3isp_prev_blkadj *blkadj = &params->blkadj;
+
+	isp_reg_writel(isp, (blkadj->blue << ISPPRV_BLKADJOFF_B_SHIFT) |
+		       (blkadj->green << ISPPRV_BLKADJOFF_G_SHIFT) |
+		       (blkadj->red << ISPPRV_BLKADJOFF_R_SHIFT),
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_BLKADJOFF);
+}
+
+/*
+ * preview_config_rgb_blending - Configure RGB-RGB Blending
+ */
+static void
+preview_config_rgb_blending(struct isp_prev_device *prev,
+			    const struct prev_params *params)
+{
+	struct isp_device *isp = to_isp_device(prev);
+	const struct omap3isp_prev_rgbtorgb *rgbrgb = &params->rgb2rgb;
+	u32 val;
+
+	val = (rgbrgb->matrix[0][0] & 0xfff) << ISPPRV_RGB_MAT1_MTX_RR_SHIFT;
+	val |= (rgbrgb->matrix[0][1] & 0xfff) << ISPPRV_RGB_MAT1_MTX_GR_SHIFT;
+	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT1);
+
+	val = (rgbrgb->matrix[0][2] & 0xfff) << ISPPRV_RGB_MAT2_MTX_BR_SHIFT;
+	val |= (rgbrgb->matrix[1][0] & 0xfff) << ISPPRV_RGB_MAT2_MTX_RG_SHIFT;
+	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT2);
+
+	val = (rgbrgb->matrix[1][1] & 0xfff) << ISPPRV_RGB_MAT3_MTX_GG_SHIFT;
+	val |= (rgbrgb->matrix[1][2] & 0xfff) << ISPPRV_RGB_MAT3_MTX_BG_SHIFT;
+	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT3);
+
+	val = (rgbrgb->matrix[2][0] & 0xfff) << ISPPRV_RGB_MAT4_MTX_RB_SHIFT;
+	val |= (rgbrgb->matrix[2][1] & 0xfff) << ISPPRV_RGB_MAT4_MTX_GB_SHIFT;
+	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT4);
+
+	val = (rgbrgb->matrix[2][2] & 0xfff) << ISPPRV_RGB_MAT5_MTX_BB_SHIFT;
+	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT5);
+
+	val = (rgbrgb->offset[0] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT;
+	val |= (rgbrgb->offset[1] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT;
+	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF1);
+
+	val = (rgbrgb->offset[2] & 0x3ff) << ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT;
+	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF2);
+}
+
+/*
+ * preview_config_csc - Configure Color Space Conversion (RGB to YCbYCr)
+ */
+static void
+preview_config_csc(struct isp_prev_device *prev,
+		   const struct prev_params *params)
+{
+	struct isp_device *isp = to_isp_device(prev);
+	const struct omap3isp_prev_csc *csc = &params->csc;
+	u32 val;
+
+	val = (csc->matrix[0][0] & 0x3ff) << ISPPRV_CSC0_RY_SHIFT;
+	val |= (csc->matrix[0][1] & 0x3ff) << ISPPRV_CSC0_GY_SHIFT;
+	val |= (csc->matrix[0][2] & 0x3ff) << ISPPRV_CSC0_BY_SHIFT;
+	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0);
+
+	val = (csc->matrix[1][0] & 0x3ff) << ISPPRV_CSC1_RCB_SHIFT;
+	val |= (csc->matrix[1][1] & 0x3ff) << ISPPRV_CSC1_GCB_SHIFT;
+	val |= (csc->matrix[1][2] & 0x3ff) << ISPPRV_CSC1_BCB_SHIFT;
+	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1);
+
+	val = (csc->matrix[2][0] & 0x3ff) << ISPPRV_CSC2_RCR_SHIFT;
+	val |= (csc->matrix[2][1] & 0x3ff) << ISPPRV_CSC2_GCR_SHIFT;
+	val |= (csc->matrix[2][2] & 0x3ff) << ISPPRV_CSC2_BCR_SHIFT;
+	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2);
+
+	val = (csc->offset[0] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT;
+	val |= (csc->offset[1] & 0xff) << ISPPRV_CSC_OFFSET_CB_SHIFT;
+	val |= (csc->offset[2] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT;
+	isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET);
+}
+
+/*
+ * preview_config_yc_range - Configure the max and min Y and C values
+ */
+static void
+preview_config_yc_range(struct isp_prev_device *prev,
+			const struct prev_params *params)
+{
+	struct isp_device *isp = to_isp_device(prev);
+	const struct omap3isp_prev_yclimit *yc = &params->yclimit;
+
+	isp_reg_writel(isp,
+		       yc->maxC << ISPPRV_SETUP_YC_MAXC_SHIFT |
+		       yc->maxY << ISPPRV_SETUP_YC_MAXY_SHIFT |
+		       yc->minC << ISPPRV_SETUP_YC_MINC_SHIFT |
+		       yc->minY << ISPPRV_SETUP_YC_MINY_SHIFT,
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC);
+}
+
+/*
+ * preview_config_dcor - Configure Couplet Defect Correction
+ */
+static void
+preview_config_dcor(struct isp_prev_device *prev,
+		    const struct prev_params *params)
+{
+	struct isp_device *isp = to_isp_device(prev);
+	const struct omap3isp_prev_dcor *dcor = &params->dcor;
+
+	isp_reg_writel(isp, dcor->detect_correct[0],
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR0);
+	isp_reg_writel(isp, dcor->detect_correct[1],
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1);
+	isp_reg_writel(isp, dcor->detect_correct[2],
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2);
+	isp_reg_writel(isp, dcor->detect_correct[3],
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3);
+	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			ISPPRV_PCR_DCCOUP,
+			dcor->couplet_mode_en ? ISPPRV_PCR_DCCOUP : 0);
+}
+
+/*
+ * preview_enable_dcor - Enable/disable Couplet Defect Correction
+ */
+static void preview_enable_dcor(struct isp_prev_device *prev, bool enable)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	if (enable)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_DCOREN);
+	else
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_DCOREN);
+}
+
+/*
+ * preview_enable_drkframe_capture - Enable/disable Dark Frame Capture
+ */
+static void
+preview_enable_drkframe_capture(struct isp_prev_device *prev, bool enable)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	if (enable)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_DRKFCAP);
+	else
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_DRKFCAP);
+}
+
+/*
+ * preview_enable_drkframe - Enable/disable Dark Frame Subtraction
+ */
+static void preview_enable_drkframe(struct isp_prev_device *prev, bool enable)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	if (enable)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_DRKFEN);
+	else
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_DRKFEN);
+}
+
+/*
+ * preview_config_noisefilter - Configure the Noise Filter
+ */
+static void
+preview_config_noisefilter(struct isp_prev_device *prev,
+			   const struct prev_params *params)
+{
+	struct isp_device *isp = to_isp_device(prev);
+	const struct omap3isp_prev_nf *nf = &params->nf;
+	unsigned int i;
+
+	isp_reg_writel(isp, nf->spread, OMAP3_ISP_IOMEM_PREV, ISPPRV_NF);
+	isp_reg_writel(isp, ISPPRV_NF_TABLE_ADDR,
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+	for (i = 0; i < OMAP3ISP_PREV_NF_TBL_SIZE; i++) {
+		isp_reg_writel(isp, nf->table[i],
+			       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
+	}
+}
+
+/*
+ * preview_enable_noisefilter - Enable/disable the Noise Filter
+ */
+static void
+preview_enable_noisefilter(struct isp_prev_device *prev, bool enable)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	if (enable)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_NFEN);
+	else
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_NFEN);
+}
+
+/*
+ * preview_config_gammacorrn - Configure the Gamma Correction tables
+ */
+static void
+preview_config_gammacorrn(struct isp_prev_device *prev,
+			  const struct prev_params *params)
+{
+	struct isp_device *isp = to_isp_device(prev);
+	const struct omap3isp_prev_gtables *gt = &params->gamma;
+	unsigned int i;
+
+	isp_reg_writel(isp, ISPPRV_REDGAMMA_TABLE_ADDR,
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+	for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
+		isp_reg_writel(isp, gt->red[i], OMAP3_ISP_IOMEM_PREV,
+			       ISPPRV_SET_TBL_DATA);
+
+	isp_reg_writel(isp, ISPPRV_GREENGAMMA_TABLE_ADDR,
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+	for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
+		isp_reg_writel(isp, gt->green[i], OMAP3_ISP_IOMEM_PREV,
+			       ISPPRV_SET_TBL_DATA);
+
+	isp_reg_writel(isp, ISPPRV_BLUEGAMMA_TABLE_ADDR,
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+	for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
+		isp_reg_writel(isp, gt->blue[i], OMAP3_ISP_IOMEM_PREV,
+			       ISPPRV_SET_TBL_DATA);
+}
+
+/*
+ * preview_enable_gammacorrn - Enable/disable Gamma Correction
+ *
+ * When gamma correction is disabled, the module is bypassed and its output is
+ * the 8 MSB of the 10-bit input .
+ */
+static void
+preview_enable_gammacorrn(struct isp_prev_device *prev, bool enable)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	if (enable)
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_GAMMA_BYPASS);
+	else
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_GAMMA_BYPASS);
+}
+
+/*
+ * preview_config_contrast - Configure the Contrast
+ *
+ * Value should be programmed before enabling the module.
+ */
+static void
+preview_config_contrast(struct isp_prev_device *prev,
+			const struct prev_params *params)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
+			0xff << ISPPRV_CNT_BRT_CNT_SHIFT,
+			params->contrast << ISPPRV_CNT_BRT_CNT_SHIFT);
+}
+
+/*
+ * preview_config_brightness - Configure the Brightness
+ */
+static void
+preview_config_brightness(struct isp_prev_device *prev,
+			  const struct prev_params *params)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
+			0xff << ISPPRV_CNT_BRT_BRT_SHIFT,
+			params->brightness << ISPPRV_CNT_BRT_BRT_SHIFT);
+}
+
+/*
+ * preview_update_contrast - Updates the contrast.
+ * @contrast: Pointer to hold the current programmed contrast value.
+ *
+ * Value should be programmed before enabling the module.
+ */
+static void
+preview_update_contrast(struct isp_prev_device *prev, u8 contrast)
+{
+	struct prev_params *params;
+	unsigned long flags;
+
+	spin_lock_irqsave(&prev->params.lock, flags);
+	params = (prev->params.active & OMAP3ISP_PREV_CONTRAST)
+	       ? &prev->params.params[0] : &prev->params.params[1];
+
+	if (params->contrast != (contrast * ISPPRV_CONTRAST_UNITS)) {
+		params->contrast = contrast * ISPPRV_CONTRAST_UNITS;
+		params->update |= OMAP3ISP_PREV_CONTRAST;
+	}
+	spin_unlock_irqrestore(&prev->params.lock, flags);
+}
+
+/*
+ * preview_update_brightness - Updates the brightness in preview module.
+ * @brightness: Pointer to hold the current programmed brightness value.
+ *
+ */
+static void
+preview_update_brightness(struct isp_prev_device *prev, u8 brightness)
+{
+	struct prev_params *params;
+	unsigned long flags;
+
+	spin_lock_irqsave(&prev->params.lock, flags);
+	params = (prev->params.active & OMAP3ISP_PREV_BRIGHTNESS)
+	       ? &prev->params.params[0] : &prev->params.params[1];
+
+	if (params->brightness != (brightness * ISPPRV_BRIGHT_UNITS)) {
+		params->brightness = brightness * ISPPRV_BRIGHT_UNITS;
+		params->update |= OMAP3ISP_PREV_BRIGHTNESS;
+	}
+	spin_unlock_irqrestore(&prev->params.lock, flags);
+}
+
+static u32
+preview_params_lock(struct isp_prev_device *prev, u32 update, bool shadow)
+{
+	u32 active = prev->params.active;
+
+	if (shadow) {
+		/* Mark all shadow parameters we are going to touch as busy. */
+		prev->params.params[0].busy |= ~active & update;
+		prev->params.params[1].busy |= active & update;
+	} else {
+		/* Mark all active parameters we are going to touch as busy. */
+		update = (prev->params.params[0].update & active)
+		       | (prev->params.params[1].update & ~active);
+
+		prev->params.params[0].busy |= active & update;
+		prev->params.params[1].busy |= ~active & update;
+	}
+
+	return update;
+}
+
+static void
+preview_params_unlock(struct isp_prev_device *prev, u32 update, bool shadow)
+{
+	u32 active = prev->params.active;
+
+	if (shadow) {
+		/* Set the update flag for shadow parameters that have been
+		 * updated and clear the busy flag for all shadow parameters.
+		 */
+		prev->params.params[0].update |= (~active & update);
+		prev->params.params[1].update |= (active & update);
+		prev->params.params[0].busy &= active;
+		prev->params.params[1].busy &= ~active;
+	} else {
+		/* Clear the update flag for active parameters that have been
+		 * applied and the busy flag for all active parameters.
+		 */
+		prev->params.params[0].update &= ~(active & update);
+		prev->params.params[1].update &= ~(~active & update);
+		prev->params.params[0].busy &= ~active;
+		prev->params.params[1].busy &= active;
+	}
+}
+
+static void preview_params_switch(struct isp_prev_device *prev)
+{
+	u32 to_switch;
+
+	/* Switch active parameters with updated shadow parameters when the
+	 * shadow parameter has been updated and neither the active not the
+	 * shadow parameter is busy.
+	 */
+	to_switch = (prev->params.params[0].update & ~prev->params.active)
+		  | (prev->params.params[1].update & prev->params.active);
+	to_switch &= ~(prev->params.params[0].busy |
+		       prev->params.params[1].busy);
+	if (to_switch == 0)
+		return;
+
+	prev->params.active ^= to_switch;
+
+	/* Remove the update flag for the shadow copy of parameters we have
+	 * switched.
+	 */
+	prev->params.params[0].update &= ~(~prev->params.active & to_switch);
+	prev->params.params[1].update &= ~(prev->params.active & to_switch);
+}
+
+/* preview parameters update structure */
+struct preview_update {
+	void (*config)(struct isp_prev_device *, const struct prev_params *);
+	void (*enable)(struct isp_prev_device *, bool);
+	unsigned int param_offset;
+	unsigned int param_size;
+	unsigned int config_offset;
+	bool skip;
+};
+
+/* Keep the array indexed by the OMAP3ISP_PREV_* bit number. */
+static const struct preview_update update_attrs[] = {
+	/* OMAP3ISP_PREV_LUMAENH */ {
+		preview_config_luma_enhancement,
+		preview_enable_luma_enhancement,
+		offsetof(struct prev_params, luma),
+		FIELD_SIZEOF(struct prev_params, luma),
+		offsetof(struct omap3isp_prev_update_config, luma),
+	}, /* OMAP3ISP_PREV_INVALAW */ {
+		NULL,
+		preview_enable_invalaw,
+	}, /* OMAP3ISP_PREV_HRZ_MED */ {
+		preview_config_hmed,
+		preview_enable_hmed,
+		offsetof(struct prev_params, hmed),
+		FIELD_SIZEOF(struct prev_params, hmed),
+		offsetof(struct omap3isp_prev_update_config, hmed),
+	}, /* OMAP3ISP_PREV_CFA */ {
+		preview_config_cfa,
+		NULL,
+		offsetof(struct prev_params, cfa),
+		FIELD_SIZEOF(struct prev_params, cfa),
+		offsetof(struct omap3isp_prev_update_config, cfa),
+	}, /* OMAP3ISP_PREV_CHROMA_SUPP */ {
+		preview_config_chroma_suppression,
+		preview_enable_chroma_suppression,
+		offsetof(struct prev_params, csup),
+		FIELD_SIZEOF(struct prev_params, csup),
+		offsetof(struct omap3isp_prev_update_config, csup),
+	}, /* OMAP3ISP_PREV_WB */ {
+		preview_config_whitebalance,
+		NULL,
+		offsetof(struct prev_params, wbal),
+		FIELD_SIZEOF(struct prev_params, wbal),
+		offsetof(struct omap3isp_prev_update_config, wbal),
+	}, /* OMAP3ISP_PREV_BLKADJ */ {
+		preview_config_blkadj,
+		NULL,
+		offsetof(struct prev_params, blkadj),
+		FIELD_SIZEOF(struct prev_params, blkadj),
+		offsetof(struct omap3isp_prev_update_config, blkadj),
+	}, /* OMAP3ISP_PREV_RGB2RGB */ {
+		preview_config_rgb_blending,
+		NULL,
+		offsetof(struct prev_params, rgb2rgb),
+		FIELD_SIZEOF(struct prev_params, rgb2rgb),
+		offsetof(struct omap3isp_prev_update_config, rgb2rgb),
+	}, /* OMAP3ISP_PREV_COLOR_CONV */ {
+		preview_config_csc,
+		NULL,
+		offsetof(struct prev_params, csc),
+		FIELD_SIZEOF(struct prev_params, csc),
+		offsetof(struct omap3isp_prev_update_config, csc),
+	}, /* OMAP3ISP_PREV_YC_LIMIT */ {
+		preview_config_yc_range,
+		NULL,
+		offsetof(struct prev_params, yclimit),
+		FIELD_SIZEOF(struct prev_params, yclimit),
+		offsetof(struct omap3isp_prev_update_config, yclimit),
+	}, /* OMAP3ISP_PREV_DEFECT_COR */ {
+		preview_config_dcor,
+		preview_enable_dcor,
+		offsetof(struct prev_params, dcor),
+		FIELD_SIZEOF(struct prev_params, dcor),
+		offsetof(struct omap3isp_prev_update_config, dcor),
+	}, /* Previously OMAP3ISP_PREV_GAMMABYPASS, not used anymore */ {
+		NULL,
+		NULL,
+	}, /* OMAP3ISP_PREV_DRK_FRM_CAPTURE */ {
+		NULL,
+		preview_enable_drkframe_capture,
+	}, /* OMAP3ISP_PREV_DRK_FRM_SUBTRACT */ {
+		NULL,
+		preview_enable_drkframe,
+	}, /* OMAP3ISP_PREV_LENS_SHADING */ {
+		NULL,
+		preview_enable_drkframe,
+	}, /* OMAP3ISP_PREV_NF */ {
+		preview_config_noisefilter,
+		preview_enable_noisefilter,
+		offsetof(struct prev_params, nf),
+		FIELD_SIZEOF(struct prev_params, nf),
+		offsetof(struct omap3isp_prev_update_config, nf),
+	}, /* OMAP3ISP_PREV_GAMMA */ {
+		preview_config_gammacorrn,
+		preview_enable_gammacorrn,
+		offsetof(struct prev_params, gamma),
+		FIELD_SIZEOF(struct prev_params, gamma),
+		offsetof(struct omap3isp_prev_update_config, gamma),
+	}, /* OMAP3ISP_PREV_CONTRAST */ {
+		preview_config_contrast,
+		NULL,
+		0, 0, 0, true,
+	}, /* OMAP3ISP_PREV_BRIGHTNESS */ {
+		preview_config_brightness,
+		NULL,
+		0, 0, 0, true,
+	},
+};
+
+/*
+ * preview_config - Copy and update local structure with userspace preview
+ *                  configuration.
+ * @prev: ISP preview engine
+ * @cfg: Configuration
+ *
+ * Return zero if success or -EFAULT if the configuration can't be copied from
+ * userspace.
+ */
+static int preview_config(struct isp_prev_device *prev,
+			  struct omap3isp_prev_update_config *cfg)
+{
+	unsigned long flags;
+	unsigned int i;
+	int rval = 0;
+	u32 update;
+	u32 active;
+
+	if (cfg->update == 0)
+		return 0;
+
+	/* Mark the shadow parameters we're going to update as busy. */
+	spin_lock_irqsave(&prev->params.lock, flags);
+	preview_params_lock(prev, cfg->update, true);
+	active = prev->params.active;
+	spin_unlock_irqrestore(&prev->params.lock, flags);
+
+	update = 0;
+
+	for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
+		const struct preview_update *attr = &update_attrs[i];
+		struct prev_params *params;
+		unsigned int bit = 1 << i;
+
+		if (attr->skip || !(cfg->update & bit))
+			continue;
+
+		params = &prev->params.params[!!(active & bit)];
+
+		if (cfg->flag & bit) {
+			void __user *from = *(void * __user *)
+				((void *)cfg + attr->config_offset);
+			void *to = (void *)params + attr->param_offset;
+			size_t size = attr->param_size;
+
+			if (to && from && size) {
+				if (copy_from_user(to, from, size)) {
+					rval = -EFAULT;
+					break;
+				}
+			}
+			params->features |= bit;
+		} else {
+			params->features &= ~bit;
+		}
+
+		update |= bit;
+	}
+
+	spin_lock_irqsave(&prev->params.lock, flags);
+	preview_params_unlock(prev, update, true);
+	preview_params_switch(prev);
+	spin_unlock_irqrestore(&prev->params.lock, flags);
+
+	return rval;
+}
+
+/*
+ * preview_setup_hw - Setup preview registers and/or internal memory
+ * @prev: pointer to preview private structure
+ * @update: Bitmask of parameters to setup
+ * @active: Bitmask of parameters active in set 0
+ * Note: can be called from interrupt context
+ * Return none
+ */
+static void preview_setup_hw(struct isp_prev_device *prev, u32 update,
+			     u32 active)
+{
+	unsigned int i;
+	u32 features;
+
+	if (update == 0)
+		return;
+
+	features = (prev->params.params[0].features & active)
+		 | (prev->params.params[1].features & ~active);
+
+	for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
+		const struct preview_update *attr = &update_attrs[i];
+		struct prev_params *params;
+		unsigned int bit = 1 << i;
+
+		if (!(update & bit))
+			continue;
+
+		params = &prev->params.params[!(active & bit)];
+
+		if (params->features & bit) {
+			if (attr->config)
+				attr->config(prev, params);
+			if (attr->enable)
+				attr->enable(prev, true);
+		} else {
+			if (attr->enable)
+				attr->enable(prev, false);
+		}
+	}
+}
+
+/*
+ * preview_config_ycpos - Configure byte layout of YUV image.
+ * @mode: Indicates the required byte layout.
+ */
+static void
+preview_config_ycpos(struct isp_prev_device *prev,
+		     enum v4l2_mbus_pixelcode pixelcode)
+{
+	struct isp_device *isp = to_isp_device(prev);
+	enum preview_ycpos_mode mode;
+
+	switch (pixelcode) {
+	case V4L2_MBUS_FMT_YUYV8_1X16:
+		mode = YCPOS_CrYCbY;
+		break;
+	case V4L2_MBUS_FMT_UYVY8_1X16:
+		mode = YCPOS_YCrYCb;
+		break;
+	default:
+		return;
+	}
+
+	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			ISPPRV_PCR_YCPOS_CrYCbY,
+			mode << ISPPRV_PCR_YCPOS_SHIFT);
+}
+
+/*
+ * preview_config_averager - Enable / disable / configure averager
+ * @average: Average value to be configured.
+ */
+static void preview_config_averager(struct isp_prev_device *prev, u8 average)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	isp_reg_writel(isp, ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT |
+		       ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT |
+		       average, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
+}
+
+
+/*
+ * preview_config_input_format - Configure the input format
+ * @prev: The preview engine
+ * @format: Format on the preview engine sink pad
+ *
+ * Enable and configure CFA interpolation for Bayer formats and disable it for
+ * greyscale formats.
+ *
+ * The CFA table is organised in four blocks, one per Bayer component. The
+ * hardware expects blocks to follow the Bayer order of the input data, while
+ * the driver stores the table in GRBG order in memory. The blocks need to be
+ * reordered to support non-GRBG Bayer patterns.
+ */
+static void preview_config_input_format(struct isp_prev_device *prev,
+					const struct v4l2_mbus_framefmt *format)
+{
+	struct isp_device *isp = to_isp_device(prev);
+	struct prev_params *params;
+
+	switch (format->code) {
+	case V4L2_MBUS_FMT_SGRBG10_1X10:
+		prev->params.cfa_order = 0;
+		break;
+	case V4L2_MBUS_FMT_SRGGB10_1X10:
+		prev->params.cfa_order = 1;
+		break;
+	case V4L2_MBUS_FMT_SBGGR10_1X10:
+		prev->params.cfa_order = 2;
+		break;
+	case V4L2_MBUS_FMT_SGBRG10_1X10:
+		prev->params.cfa_order = 3;
+		break;
+	default:
+		/* Disable CFA for non-Bayer formats. */
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_CFAEN);
+		return;
+	}
+
+	isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_CFAEN);
+	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			ISPPRV_PCR_CFAFMT_MASK, ISPPRV_PCR_CFAFMT_BAYER);
+
+	params = (prev->params.active & OMAP3ISP_PREV_CFA)
+	       ? &prev->params.params[0] : &prev->params.params[1];
+
+	preview_config_cfa(prev, params);
+}
+
+/*
+ * preview_config_input_size - Configure the input frame size
+ *
+ * The preview engine crops several rows and columns internally depending on
+ * which processing blocks are enabled. The driver assumes all those blocks are
+ * enabled when reporting source pad formats to userspace. If this assumption is
+ * not true, rows and columns must be manually cropped at the preview engine
+ * input to avoid overflows at the end of lines and frames.
+ *
+ * See the explanation at the PREV_MARGIN_* definitions for more details.
+ */
+static void preview_config_input_size(struct isp_prev_device *prev, u32 active)
+{
+	const struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK];
+	struct isp_device *isp = to_isp_device(prev);
+	unsigned int sph = prev->crop.left;
+	unsigned int eph = prev->crop.left + prev->crop.width - 1;
+	unsigned int slv = prev->crop.top;
+	unsigned int elv = prev->crop.top + prev->crop.height - 1;
+	u32 features;
+
+	if (format->code != V4L2_MBUS_FMT_Y10_1X10) {
+		sph -= 2;
+		eph += 2;
+		slv -= 2;
+		elv += 2;
+	}
+
+	features = (prev->params.params[0].features & active)
+		 | (prev->params.params[1].features & ~active);
+
+	if (features & (OMAP3ISP_PREV_DEFECT_COR | OMAP3ISP_PREV_NF)) {
+		sph -= 2;
+		eph += 2;
+		slv -= 2;
+		elv += 2;
+	}
+	if (features & OMAP3ISP_PREV_HRZ_MED) {
+		sph -= 2;
+		eph += 2;
+	}
+	if (features & (OMAP3ISP_PREV_CHROMA_SUPP | OMAP3ISP_PREV_LUMAENH))
+		sph -= 2;
+
+	isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph,
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO);
+	isp_reg_writel(isp, (slv << ISPPRV_VERT_INFO_SLV_SHIFT) | elv,
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO);
+}
+
+/*
+ * preview_config_inlineoffset - Configures the Read address line offset.
+ * @prev: Preview module
+ * @offset: Line offset
+ *
+ * According to the TRM, the line offset must be aligned on a 32 bytes boundary.
+ * However, a hardware bug requires the memory start address to be aligned on a
+ * 64 bytes boundary, so the offset probably should be aligned on 64 bytes as
+ * well.
+ */
+static void
+preview_config_inlineoffset(struct isp_prev_device *prev, u32 offset)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
+		       ISPPRV_RADR_OFFSET);
+}
+
+/*
+ * preview_set_inaddr - Sets memory address of input frame.
+ * @addr: 32bit memory address aligned on 32byte boundary.
+ *
+ * Configures the memory address from which the input frame is to be read.
+ */
+static void preview_set_inaddr(struct isp_prev_device *prev, u32 addr)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR);
+}
+
+/*
+ * preview_config_outlineoffset - Configures the Write address line offset.
+ * @offset: Line Offset for the preview output.
+ *
+ * The offset must be a multiple of 32 bytes.
+ */
+static void preview_config_outlineoffset(struct isp_prev_device *prev,
+				    u32 offset)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
+		       ISPPRV_WADD_OFFSET);
+}
+
+/*
+ * preview_set_outaddr - Sets the memory address to store output frame
+ * @addr: 32bit memory address aligned on 32byte boundary.
+ *
+ * Configures the memory address to which the output frame is written.
+ */
+static void preview_set_outaddr(struct isp_prev_device *prev, u32 addr)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR);
+}
+
+static void preview_adjust_bandwidth(struct isp_prev_device *prev)
+{
+	struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
+	struct isp_device *isp = to_isp_device(prev);
+	const struct v4l2_mbus_framefmt *ifmt = &prev->formats[PREV_PAD_SINK];
+	unsigned long l3_ick = pipe->l3_ick;
+	struct v4l2_fract *timeperframe;
+	unsigned int cycles_per_frame;
+	unsigned int requests_per_frame;
+	unsigned int cycles_per_request;
+	unsigned int minimum;
+	unsigned int maximum;
+	unsigned int value;
+
+	if (prev->input != PREVIEW_INPUT_MEMORY) {
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
+			    ISPSBL_SDR_REQ_PRV_EXP_MASK);
+		return;
+	}
+
+	/* Compute the minimum number of cycles per request, based on the
+	 * pipeline maximum data rate. This is an absolute lower bound if we
+	 * don't want SBL overflows, so round the value up.
+	 */
+	cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
+				     pipe->max_rate);
+	minimum = DIV_ROUND_UP(cycles_per_request, 32);
+
+	/* Compute the maximum number of cycles per request, based on the
+	 * requested frame rate. This is a soft upper bound to achieve a frame
+	 * rate equal or higher than the requested value, so round the value
+	 * down.
+	 */
+	timeperframe = &pipe->max_timeperframe;
+
+	requests_per_frame = DIV_ROUND_UP(ifmt->width * 2, 256) * ifmt->height;
+	cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
+				   timeperframe->denominator);
+	cycles_per_request = cycles_per_frame / requests_per_frame;
+
+	maximum = cycles_per_request / 32;
+
+	value = max(minimum, maximum);
+
+	dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
+	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
+			ISPSBL_SDR_REQ_PRV_EXP_MASK,
+			value << ISPSBL_SDR_REQ_PRV_EXP_SHIFT);
+}
+
+/*
+ * omap3isp_preview_busy - Gets busy state of preview module.
+ */
+int omap3isp_preview_busy(struct isp_prev_device *prev)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	return isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR)
+		& ISPPRV_PCR_BUSY;
+}
+
+/*
+ * omap3isp_preview_restore_context - Restores the values of preview registers
+ */
+void omap3isp_preview_restore_context(struct isp_device *isp)
+{
+	struct isp_prev_device *prev = &isp->isp_prev;
+	const u32 update = OMAP3ISP_PREV_FEATURES_END - 1;
+
+	prev->params.params[0].update = prev->params.active & update;
+	prev->params.params[1].update = ~prev->params.active & update;
+
+	preview_setup_hw(prev, update, prev->params.active);
+
+	prev->params.params[0].update = 0;
+	prev->params.params[1].update = 0;
+}
+
+/*
+ * preview_print_status - Dump preview module registers to the kernel log
+ */
+#define PREV_PRINT_REGISTER(isp, name)\
+	dev_dbg(isp->dev, "###PRV " #name "=0x%08x\n", \
+		isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_##name))
+
+static void preview_print_status(struct isp_prev_device *prev)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	dev_dbg(isp->dev, "-------------Preview Register dump----------\n");
+
+	PREV_PRINT_REGISTER(isp, PCR);
+	PREV_PRINT_REGISTER(isp, HORZ_INFO);
+	PREV_PRINT_REGISTER(isp, VERT_INFO);
+	PREV_PRINT_REGISTER(isp, RSDR_ADDR);
+	PREV_PRINT_REGISTER(isp, RADR_OFFSET);
+	PREV_PRINT_REGISTER(isp, DSDR_ADDR);
+	PREV_PRINT_REGISTER(isp, DRKF_OFFSET);
+	PREV_PRINT_REGISTER(isp, WSDR_ADDR);
+	PREV_PRINT_REGISTER(isp, WADD_OFFSET);
+	PREV_PRINT_REGISTER(isp, AVE);
+	PREV_PRINT_REGISTER(isp, HMED);
+	PREV_PRINT_REGISTER(isp, NF);
+	PREV_PRINT_REGISTER(isp, WB_DGAIN);
+	PREV_PRINT_REGISTER(isp, WBGAIN);
+	PREV_PRINT_REGISTER(isp, WBSEL);
+	PREV_PRINT_REGISTER(isp, CFA);
+	PREV_PRINT_REGISTER(isp, BLKADJOFF);
+	PREV_PRINT_REGISTER(isp, RGB_MAT1);
+	PREV_PRINT_REGISTER(isp, RGB_MAT2);
+	PREV_PRINT_REGISTER(isp, RGB_MAT3);
+	PREV_PRINT_REGISTER(isp, RGB_MAT4);
+	PREV_PRINT_REGISTER(isp, RGB_MAT5);
+	PREV_PRINT_REGISTER(isp, RGB_OFF1);
+	PREV_PRINT_REGISTER(isp, RGB_OFF2);
+	PREV_PRINT_REGISTER(isp, CSC0);
+	PREV_PRINT_REGISTER(isp, CSC1);
+	PREV_PRINT_REGISTER(isp, CSC2);
+	PREV_PRINT_REGISTER(isp, CSC_OFFSET);
+	PREV_PRINT_REGISTER(isp, CNT_BRT);
+	PREV_PRINT_REGISTER(isp, CSUP);
+	PREV_PRINT_REGISTER(isp, SETUP_YC);
+	PREV_PRINT_REGISTER(isp, SET_TBL_ADDR);
+	PREV_PRINT_REGISTER(isp, CDC_THR0);
+	PREV_PRINT_REGISTER(isp, CDC_THR1);
+	PREV_PRINT_REGISTER(isp, CDC_THR2);
+	PREV_PRINT_REGISTER(isp, CDC_THR3);
+
+	dev_dbg(isp->dev, "--------------------------------------------\n");
+}
+
+/*
+ * preview_init_params - init image processing parameters.
+ * @prev: pointer to previewer private structure
+ */
+static void preview_init_params(struct isp_prev_device *prev)
+{
+	struct prev_params *params;
+	unsigned int i;
+
+	spin_lock_init(&prev->params.lock);
+
+	prev->params.active = ~0;
+	prev->params.params[0].busy = 0;
+	prev->params.params[0].update = OMAP3ISP_PREV_FEATURES_END - 1;
+	prev->params.params[1].busy = 0;
+	prev->params.params[1].update = 0;
+
+	params = &prev->params.params[0];
+
+	/* Init values */
+	params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS;
+	params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS;
+	params->cfa.format = OMAP3ISP_CFAFMT_BAYER;
+	memcpy(params->cfa.table, cfa_coef_table,
+	       sizeof(params->cfa.table));
+	params->cfa.gradthrs_horz = FLR_CFA_GRADTHRS_HORZ;
+	params->cfa.gradthrs_vert = FLR_CFA_GRADTHRS_VERT;
+	params->csup.gain = FLR_CSUP_GAIN;
+	params->csup.thres = FLR_CSUP_THRES;
+	params->csup.hypf_en = 0;
+	memcpy(params->luma.table, luma_enhance_table,
+	       sizeof(params->luma.table));
+	params->nf.spread = FLR_NF_STRGTH;
+	memcpy(params->nf.table, noise_filter_table, sizeof(params->nf.table));
+	params->dcor.couplet_mode_en = 1;
+	for (i = 0; i < OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS; i++)
+		params->dcor.detect_correct[i] = DEF_DETECT_CORRECT_VAL;
+	memcpy(params->gamma.blue, gamma_table, sizeof(params->gamma.blue));
+	memcpy(params->gamma.green, gamma_table, sizeof(params->gamma.green));
+	memcpy(params->gamma.red, gamma_table, sizeof(params->gamma.red));
+	params->wbal.dgain = FLR_WBAL_DGAIN;
+	params->wbal.coef0 = FLR_WBAL_COEF;
+	params->wbal.coef1 = FLR_WBAL_COEF;
+	params->wbal.coef2 = FLR_WBAL_COEF;
+	params->wbal.coef3 = FLR_WBAL_COEF;
+	params->blkadj.red = FLR_BLKADJ_RED;
+	params->blkadj.green = FLR_BLKADJ_GREEN;
+	params->blkadj.blue = FLR_BLKADJ_BLUE;
+	params->rgb2rgb = flr_rgb2rgb;
+	params->csc = flr_prev_csc;
+	params->yclimit.minC = ISPPRV_YC_MIN;
+	params->yclimit.maxC = ISPPRV_YC_MAX;
+	params->yclimit.minY = ISPPRV_YC_MIN;
+	params->yclimit.maxY = ISPPRV_YC_MAX;
+
+	params->features = OMAP3ISP_PREV_CFA | OMAP3ISP_PREV_DEFECT_COR
+			 | OMAP3ISP_PREV_NF | OMAP3ISP_PREV_GAMMA
+			 | OMAP3ISP_PREV_BLKADJ | OMAP3ISP_PREV_YC_LIMIT
+			 | OMAP3ISP_PREV_RGB2RGB | OMAP3ISP_PREV_COLOR_CONV
+			 | OMAP3ISP_PREV_WB | OMAP3ISP_PREV_BRIGHTNESS
+			 | OMAP3ISP_PREV_CONTRAST;
+}
+
+/*
+ * preview_max_out_width - Handle previewer hardware ouput limitations
+ * @isp_revision : ISP revision
+ * returns maximum width output for current isp revision
+ */
+static unsigned int preview_max_out_width(struct isp_prev_device *prev)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	switch (isp->revision) {
+	case ISP_REVISION_1_0:
+		return PREV_MAX_OUT_WIDTH_REV_1;
+
+	case ISP_REVISION_2_0:
+	default:
+		return PREV_MAX_OUT_WIDTH_REV_2;
+
+	case ISP_REVISION_15_0:
+		return PREV_MAX_OUT_WIDTH_REV_15;
+	}
+}
+
+static void preview_configure(struct isp_prev_device *prev)
+{
+	struct isp_device *isp = to_isp_device(prev);
+	struct v4l2_mbus_framefmt *format;
+	unsigned long flags;
+	u32 update;
+	u32 active;
+
+	spin_lock_irqsave(&prev->params.lock, flags);
+	/* Mark all active parameters we are going to touch as busy. */
+	update = preview_params_lock(prev, 0, false);
+	active = prev->params.active;
+	spin_unlock_irqrestore(&prev->params.lock, flags);
+
+	/* PREV_PAD_SINK */
+	format = &prev->formats[PREV_PAD_SINK];
+
+	preview_adjust_bandwidth(prev);
+
+	preview_config_input_format(prev, format);
+	preview_config_input_size(prev, active);
+
+	if (prev->input == PREVIEW_INPUT_CCDC)
+		preview_config_inlineoffset(prev, 0);
+	else
+		preview_config_inlineoffset(prev,
+				ALIGN(format->width, 0x20) * 2);
+
+	preview_setup_hw(prev, update, active);
+
+	/* PREV_PAD_SOURCE */
+	format = &prev->formats[PREV_PAD_SOURCE];
+
+	if (prev->output & PREVIEW_OUTPUT_MEMORY)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_SDRPORT);
+	else
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_SDRPORT);
+
+	if (prev->output & PREVIEW_OUTPUT_RESIZER)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_RSZPORT);
+	else
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_RSZPORT);
+
+	if (prev->output & PREVIEW_OUTPUT_MEMORY)
+		preview_config_outlineoffset(prev,
+				ALIGN(format->width, 0x10) * 2);
+
+	preview_config_averager(prev, 0);
+	preview_config_ycpos(prev, format->code);
+
+	spin_lock_irqsave(&prev->params.lock, flags);
+	preview_params_unlock(prev, update, false);
+	spin_unlock_irqrestore(&prev->params.lock, flags);
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+static void preview_enable_oneshot(struct isp_prev_device *prev)
+{
+	struct isp_device *isp = to_isp_device(prev);
+
+	/* The PCR.SOURCE bit is automatically reset to 0 when the PCR.ENABLE
+	 * bit is set. As the preview engine is used in single-shot mode, we
+	 * need to set PCR.SOURCE before enabling the preview engine.
+	 */
+	if (prev->input == PREVIEW_INPUT_MEMORY)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ISPPRV_PCR_SOURCE);
+
+	isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+		    ISPPRV_PCR_EN | ISPPRV_PCR_ONESHOT);
+}
+
+void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev)
+{
+	/*
+	 * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
+	 * condition, the module was paused and now we have a buffer queued
+	 * on the output again. Restart the pipeline if running in continuous
+	 * mode.
+	 */
+	if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
+	    prev->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
+		preview_enable_oneshot(prev);
+		isp_video_dmaqueue_flags_clr(&prev->video_out);
+	}
+}
+
+static void preview_isr_buffer(struct isp_prev_device *prev)
+{
+	struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
+	struct isp_buffer *buffer;
+	int restart = 0;
+
+	if (prev->input == PREVIEW_INPUT_MEMORY) {
+		buffer = omap3isp_video_buffer_next(&prev->video_in);
+		if (buffer != NULL)
+			preview_set_inaddr(prev, buffer->isp_addr);
+		pipe->state |= ISP_PIPELINE_IDLE_INPUT;
+	}
+
+	if (prev->output & PREVIEW_OUTPUT_MEMORY) {
+		buffer = omap3isp_video_buffer_next(&prev->video_out);
+		if (buffer != NULL) {
+			preview_set_outaddr(prev, buffer->isp_addr);
+			restart = 1;
+		}
+		pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
+	}
+
+	switch (prev->state) {
+	case ISP_PIPELINE_STREAM_SINGLESHOT:
+		if (isp_pipeline_ready(pipe))
+			omap3isp_pipeline_set_stream(pipe,
+						ISP_PIPELINE_STREAM_SINGLESHOT);
+		break;
+
+	case ISP_PIPELINE_STREAM_CONTINUOUS:
+		/* If an underrun occurs, the video queue operation handler will
+		 * restart the preview engine. Otherwise restart it immediately.
+		 */
+		if (restart)
+			preview_enable_oneshot(prev);
+		break;
+
+	case ISP_PIPELINE_STREAM_STOPPED:
+	default:
+		return;
+	}
+}
+
+/*
+ * omap3isp_preview_isr - ISP preview engine interrupt handler
+ *
+ * Manage the preview engine video buffers and configure shadowed registers.
+ */
+void omap3isp_preview_isr(struct isp_prev_device *prev)
+{
+	unsigned long flags;
+	u32 update;
+	u32 active;
+
+	if (omap3isp_module_sync_is_stopping(&prev->wait, &prev->stopping))
+		return;
+
+	spin_lock_irqsave(&prev->params.lock, flags);
+	preview_params_switch(prev);
+	update = preview_params_lock(prev, 0, false);
+	active = prev->params.active;
+	spin_unlock_irqrestore(&prev->params.lock, flags);
+
+	preview_setup_hw(prev, update, active);
+	preview_config_input_size(prev, active);
+
+	if (prev->input == PREVIEW_INPUT_MEMORY ||
+	    prev->output & PREVIEW_OUTPUT_MEMORY)
+		preview_isr_buffer(prev);
+	else if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS)
+		preview_enable_oneshot(prev);
+
+	spin_lock_irqsave(&prev->params.lock, flags);
+	preview_params_unlock(prev, update, false);
+	spin_unlock_irqrestore(&prev->params.lock, flags);
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP video operations
+ */
+
+static int preview_video_queue(struct isp_video *video,
+			       struct isp_buffer *buffer)
+{
+	struct isp_prev_device *prev = &video->isp->isp_prev;
+
+	if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		preview_set_inaddr(prev, buffer->isp_addr);
+
+	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		preview_set_outaddr(prev, buffer->isp_addr);
+
+	return 0;
+}
+
+static const struct isp_video_operations preview_video_ops = {
+	.queue = preview_video_queue,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+/*
+ * preview_s_ctrl - Handle set control subdev method
+ * @ctrl: pointer to v4l2 control structure
+ */
+static int preview_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct isp_prev_device *prev =
+		container_of(ctrl->handler, struct isp_prev_device, ctrls);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		preview_update_brightness(prev, ctrl->val);
+		break;
+	case V4L2_CID_CONTRAST:
+		preview_update_contrast(prev, ctrl->val);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops preview_ctrl_ops = {
+	.s_ctrl = preview_s_ctrl,
+};
+
+/*
+ * preview_ioctl - Handle preview module private ioctl's
+ * @prev: pointer to preview context structure
+ * @cmd: configuration command
+ * @arg: configuration argument
+ * return -EINVAL or zero on success
+ */
+static long preview_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+
+	switch (cmd) {
+	case VIDIOC_OMAP3ISP_PRV_CFG:
+		return preview_config(prev, arg);
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+/*
+ * preview_set_stream - Enable/Disable streaming on preview subdev
+ * @sd    : pointer to v4l2 subdev structure
+ * @enable: 1 == Enable, 0 == Disable
+ * return -EINVAL or zero on success
+ */
+static int preview_set_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+	struct isp_video *video_out = &prev->video_out;
+	struct isp_device *isp = to_isp_device(prev);
+	struct device *dev = to_device(prev);
+
+	if (prev->state == ISP_PIPELINE_STREAM_STOPPED) {
+		if (enable == ISP_PIPELINE_STREAM_STOPPED)
+			return 0;
+
+		omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
+		preview_configure(prev);
+		atomic_set(&prev->stopping, 0);
+		preview_print_status(prev);
+	}
+
+	switch (enable) {
+	case ISP_PIPELINE_STREAM_CONTINUOUS:
+		if (prev->output & PREVIEW_OUTPUT_MEMORY)
+			omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
+
+		if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED ||
+		    !(prev->output & PREVIEW_OUTPUT_MEMORY))
+			preview_enable_oneshot(prev);
+
+		isp_video_dmaqueue_flags_clr(video_out);
+		break;
+
+	case ISP_PIPELINE_STREAM_SINGLESHOT:
+		if (prev->input == PREVIEW_INPUT_MEMORY)
+			omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
+		if (prev->output & PREVIEW_OUTPUT_MEMORY)
+			omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
+
+		preview_enable_oneshot(prev);
+		break;
+
+	case ISP_PIPELINE_STREAM_STOPPED:
+		if (omap3isp_module_sync_idle(&sd->entity, &prev->wait,
+					      &prev->stopping))
+			dev_dbg(dev, "%s: stop timeout.\n", sd->name);
+		omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
+		omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
+		omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
+		isp_video_dmaqueue_flags_clr(video_out);
+		break;
+	}
+
+	prev->state = enable;
+	return 0;
+}
+
+static struct v4l2_mbus_framefmt *
+__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh,
+		     unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_format(fh, pad);
+	else
+		return &prev->formats[pad];
+}
+
+static struct v4l2_rect *
+__preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh,
+		   enum v4l2_subdev_format_whence which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_crop(fh, PREV_PAD_SINK);
+	else
+		return &prev->crop;
+}
+
+/* previewer format descriptions */
+static const unsigned int preview_input_fmts[] = {
+	V4L2_MBUS_FMT_Y10_1X10,
+	V4L2_MBUS_FMT_SGRBG10_1X10,
+	V4L2_MBUS_FMT_SRGGB10_1X10,
+	V4L2_MBUS_FMT_SBGGR10_1X10,
+	V4L2_MBUS_FMT_SGBRG10_1X10,
+};
+
+static const unsigned int preview_output_fmts[] = {
+	V4L2_MBUS_FMT_UYVY8_1X16,
+	V4L2_MBUS_FMT_YUYV8_1X16,
+};
+
+/*
+ * preview_try_format - Validate a format
+ * @prev: ISP preview engine
+ * @fh: V4L2 subdev file handle
+ * @pad: pad number
+ * @fmt: format to be validated
+ * @which: try/active format selector
+ *
+ * Validate and adjust the given format for the given pad based on the preview
+ * engine limits and the format and crop rectangles on other pads.
+ */
+static void preview_try_format(struct isp_prev_device *prev,
+			       struct v4l2_subdev_fh *fh, unsigned int pad,
+			       struct v4l2_mbus_framefmt *fmt,
+			       enum v4l2_subdev_format_whence which)
+{
+	enum v4l2_mbus_pixelcode pixelcode;
+	struct v4l2_rect *crop;
+	unsigned int i;
+
+	switch (pad) {
+	case PREV_PAD_SINK:
+		/* When reading data from the CCDC, the input size has already
+		 * been mangled by the CCDC output pad so it can be accepted
+		 * as-is.
+		 *
+		 * When reading data from memory, clamp the requested width and
+		 * height. The TRM doesn't specify a minimum input height, make
+		 * sure we got enough lines to enable the noise filter and color
+		 * filter array interpolation.
+		 */
+		if (prev->input == PREVIEW_INPUT_MEMORY) {
+			fmt->width = clamp_t(u32, fmt->width, PREV_MIN_IN_WIDTH,
+					     preview_max_out_width(prev));
+			fmt->height = clamp_t(u32, fmt->height,
+					      PREV_MIN_IN_HEIGHT,
+					      PREV_MAX_IN_HEIGHT);
+		}
+
+		fmt->colorspace = V4L2_COLORSPACE_SRGB;
+
+		for (i = 0; i < ARRAY_SIZE(preview_input_fmts); i++) {
+			if (fmt->code == preview_input_fmts[i])
+				break;
+		}
+
+		/* If not found, use SGRBG10 as default */
+		if (i >= ARRAY_SIZE(preview_input_fmts))
+			fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+		break;
+
+	case PREV_PAD_SOURCE:
+		pixelcode = fmt->code;
+		*fmt = *__preview_get_format(prev, fh, PREV_PAD_SINK, which);
+
+		switch (pixelcode) {
+		case V4L2_MBUS_FMT_YUYV8_1X16:
+		case V4L2_MBUS_FMT_UYVY8_1X16:
+			fmt->code = pixelcode;
+			break;
+
+		default:
+			fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
+			break;
+		}
+
+		/* The preview module output size is configurable through the
+		 * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). This
+		 * is not supported yet, hardcode the output size to the crop
+		 * rectangle size.
+		 */
+		crop = __preview_get_crop(prev, fh, which);
+		fmt->width = crop->width;
+		fmt->height = crop->height;
+
+		fmt->colorspace = V4L2_COLORSPACE_JPEG;
+		break;
+	}
+
+	fmt->field = V4L2_FIELD_NONE;
+}
+
+/*
+ * preview_try_crop - Validate a crop rectangle
+ * @prev: ISP preview engine
+ * @sink: format on the sink pad
+ * @crop: crop rectangle to be validated
+ *
+ * The preview engine crops lines and columns for its internal operation,
+ * depending on which filters are enabled. Enforce minimum crop margins to
+ * handle that transparently for userspace.
+ *
+ * See the explanation at the PREV_MARGIN_* definitions for more details.
+ */
+static void preview_try_crop(struct isp_prev_device *prev,
+			     const struct v4l2_mbus_framefmt *sink,
+			     struct v4l2_rect *crop)
+{
+	unsigned int left = PREV_MARGIN_LEFT;
+	unsigned int right = sink->width - PREV_MARGIN_RIGHT;
+	unsigned int top = PREV_MARGIN_TOP;
+	unsigned int bottom = sink->height - PREV_MARGIN_BOTTOM;
+
+	/* When processing data on-the-fly from the CCDC, at least 2 pixels must
+	 * be cropped from the left and right sides of the image. As we don't
+	 * know which filters will be enabled, increase the left and right
+	 * margins by two.
+	 */
+	if (prev->input == PREVIEW_INPUT_CCDC) {
+		left += 2;
+		right -= 2;
+	}
+
+	/* Restrict left/top to even values to keep the Bayer pattern. */
+	crop->left &= ~1;
+	crop->top &= ~1;
+
+	crop->left = clamp_t(u32, crop->left, left, right - PREV_MIN_OUT_WIDTH);
+	crop->top = clamp_t(u32, crop->top, top, bottom - PREV_MIN_OUT_HEIGHT);
+	crop->width = clamp_t(u32, crop->width, PREV_MIN_OUT_WIDTH,
+			      right - crop->left);
+	crop->height = clamp_t(u32, crop->height, PREV_MIN_OUT_HEIGHT,
+			       bottom - crop->top);
+}
+
+/*
+ * preview_enum_mbus_code - Handle pixel format enumeration
+ * @sd     : pointer to v4l2 subdev structure
+ * @fh     : V4L2 subdev file handle
+ * @code   : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int preview_enum_mbus_code(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	switch (code->pad) {
+	case PREV_PAD_SINK:
+		if (code->index >= ARRAY_SIZE(preview_input_fmts))
+			return -EINVAL;
+
+		code->code = preview_input_fmts[code->index];
+		break;
+	case PREV_PAD_SOURCE:
+		if (code->index >= ARRAY_SIZE(preview_output_fmts))
+			return -EINVAL;
+
+		code->code = preview_output_fmts[code->index];
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int preview_enum_frame_size(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_fh *fh,
+				   struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt format;
+
+	if (fse->index != 0)
+		return -EINVAL;
+
+	format.code = fse->code;
+	format.width = 1;
+	format.height = 1;
+	preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+	fse->min_width = format.width;
+	fse->min_height = format.height;
+
+	if (format.code != fse->code)
+		return -EINVAL;
+
+	format.code = fse->code;
+	format.width = -1;
+	format.height = -1;
+	preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+	fse->max_width = format.width;
+	fse->max_height = format.height;
+
+	return 0;
+}
+
+/*
+ * preview_get_selection - Retrieve a selection rectangle on a pad
+ * @sd: ISP preview V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangles are the crop rectangles on the sink pad.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int preview_get_selection(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_selection *sel)
+{
+	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	if (sel->pad != PREV_PAD_SINK)
+		return -EINVAL;
+
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		sel->r.left = 0;
+		sel->r.top = 0;
+		sel->r.width = INT_MAX;
+		sel->r.height = INT_MAX;
+
+		format = __preview_get_format(prev, fh, PREV_PAD_SINK,
+					      sel->which);
+		preview_try_crop(prev, format, &sel->r);
+		break;
+
+	case V4L2_SEL_TGT_CROP:
+		sel->r = *__preview_get_crop(prev, fh, sel->which);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * preview_set_selection - Set a selection rectangle on a pad
+ * @sd: ISP preview V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangle is the actual crop rectangle on the sink pad.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int preview_set_selection(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_selection *sel)
+{
+	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	if (sel->target != V4L2_SEL_TGT_CROP ||
+	    sel->pad != PREV_PAD_SINK)
+		return -EINVAL;
+
+	/* The crop rectangle can't be changed while streaming. */
+	if (prev->state != ISP_PIPELINE_STREAM_STOPPED)
+		return -EBUSY;
+
+	/* Modifying the crop rectangle always changes the format on the source
+	 * pad. If the KEEP_CONFIG flag is set, just return the current crop
+	 * rectangle.
+	 */
+	if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
+		sel->r = *__preview_get_crop(prev, fh, sel->which);
+		return 0;
+	}
+
+	format = __preview_get_format(prev, fh, PREV_PAD_SINK, sel->which);
+	preview_try_crop(prev, format, &sel->r);
+	*__preview_get_crop(prev, fh, sel->which) = sel->r;
+
+	/* Update the source format. */
+	format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, sel->which);
+	preview_try_format(prev, fh, PREV_PAD_SOURCE, format, sel->which);
+
+	return 0;
+}
+
+/*
+ * preview_get_format - Handle get format by pads subdev method
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @fmt: pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_format *fmt)
+{
+	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	format = __preview_get_format(prev, fh, fmt->pad, fmt->which);
+	if (format == NULL)
+		return -EINVAL;
+
+	fmt->format = *format;
+	return 0;
+}
+
+/*
+ * preview_set_format - Handle set format by pads subdev method
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @fmt: pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_format *fmt)
+{
+	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+	struct v4l2_rect *crop;
+
+	format = __preview_get_format(prev, fh, fmt->pad, fmt->which);
+	if (format == NULL)
+		return -EINVAL;
+
+	preview_try_format(prev, fh, fmt->pad, &fmt->format, fmt->which);
+	*format = fmt->format;
+
+	/* Propagate the format from sink to source */
+	if (fmt->pad == PREV_PAD_SINK) {
+		/* Reset the crop rectangle. */
+		crop = __preview_get_crop(prev, fh, fmt->which);
+		crop->left = 0;
+		crop->top = 0;
+		crop->width = fmt->format.width;
+		crop->height = fmt->format.height;
+
+		preview_try_crop(prev, &fmt->format, crop);
+
+		/* Update the source format. */
+		format = __preview_get_format(prev, fh, PREV_PAD_SOURCE,
+					      fmt->which);
+		preview_try_format(prev, fh, PREV_PAD_SOURCE, format,
+				   fmt->which);
+	}
+
+	return 0;
+}
+
+/*
+ * preview_init_formats - Initialize formats on all pads
+ * @sd: ISP preview V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int preview_init_formats(struct v4l2_subdev *sd,
+				struct v4l2_subdev_fh *fh)
+{
+	struct v4l2_subdev_format format;
+
+	memset(&format, 0, sizeof(format));
+	format.pad = PREV_PAD_SINK;
+	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+	format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+	format.format.width = 4096;
+	format.format.height = 4096;
+	preview_set_format(sd, fh, &format);
+
+	return 0;
+}
+
+/* subdev core operations */
+static const struct v4l2_subdev_core_ops preview_v4l2_core_ops = {
+	.ioctl = preview_ioctl,
+};
+
+/* subdev video operations */
+static const struct v4l2_subdev_video_ops preview_v4l2_video_ops = {
+	.s_stream = preview_set_stream,
+};
+
+/* subdev pad operations */
+static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = {
+	.enum_mbus_code = preview_enum_mbus_code,
+	.enum_frame_size = preview_enum_frame_size,
+	.get_fmt = preview_get_format,
+	.set_fmt = preview_set_format,
+	.get_selection = preview_get_selection,
+	.set_selection = preview_set_selection,
+};
+
+/* subdev operations */
+static const struct v4l2_subdev_ops preview_v4l2_ops = {
+	.core = &preview_v4l2_core_ops,
+	.video = &preview_v4l2_video_ops,
+	.pad = &preview_v4l2_pad_ops,
+};
+
+/* subdev internal operations */
+static const struct v4l2_subdev_internal_ops preview_v4l2_internal_ops = {
+	.open = preview_init_formats,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * preview_link_setup - Setup previewer connections.
+ * @entity : Pointer to media entity structure
+ * @local  : Pointer to local pad array
+ * @remote : Pointer to remote pad array
+ * @flags  : Link flags
+ * return -EINVAL or zero on success
+ */
+static int preview_link_setup(struct media_entity *entity,
+			      const struct media_pad *local,
+			      const struct media_pad *remote, u32 flags)
+{
+	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+	struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+
+	switch (local->index | media_entity_type(remote->entity)) {
+	case PREV_PAD_SINK | MEDIA_ENT_T_DEVNODE:
+		/* read from memory */
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			if (prev->input == PREVIEW_INPUT_CCDC)
+				return -EBUSY;
+			prev->input = PREVIEW_INPUT_MEMORY;
+		} else {
+			if (prev->input == PREVIEW_INPUT_MEMORY)
+				prev->input = PREVIEW_INPUT_NONE;
+		}
+		break;
+
+	case PREV_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+		/* read from ccdc */
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			if (prev->input == PREVIEW_INPUT_MEMORY)
+				return -EBUSY;
+			prev->input = PREVIEW_INPUT_CCDC;
+		} else {
+			if (prev->input == PREVIEW_INPUT_CCDC)
+				prev->input = PREVIEW_INPUT_NONE;
+		}
+		break;
+
+	/*
+	 * The ISP core doesn't support pipelines with multiple video outputs.
+	 * Revisit this when it will be implemented, and return -EBUSY for now.
+	 */
+
+	case PREV_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+		/* write to memory */
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			if (prev->output & ~PREVIEW_OUTPUT_MEMORY)
+				return -EBUSY;
+			prev->output |= PREVIEW_OUTPUT_MEMORY;
+		} else {
+			prev->output &= ~PREVIEW_OUTPUT_MEMORY;
+		}
+		break;
+
+	case PREV_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+		/* write to resizer */
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			if (prev->output & ~PREVIEW_OUTPUT_RESIZER)
+				return -EBUSY;
+			prev->output |= PREVIEW_OUTPUT_RESIZER;
+		} else {
+			prev->output &= ~PREVIEW_OUTPUT_RESIZER;
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations preview_media_ops = {
+	.link_setup = preview_link_setup,
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+void omap3isp_preview_unregister_entities(struct isp_prev_device *prev)
+{
+	v4l2_device_unregister_subdev(&prev->subdev);
+	omap3isp_video_unregister(&prev->video_in);
+	omap3isp_video_unregister(&prev->video_out);
+}
+
+int omap3isp_preview_register_entities(struct isp_prev_device *prev,
+	struct v4l2_device *vdev)
+{
+	int ret;
+
+	/* Register the subdev and video nodes. */
+	ret = v4l2_device_register_subdev(vdev, &prev->subdev);
+	if (ret < 0)
+		goto error;
+
+	ret = omap3isp_video_register(&prev->video_in, vdev);
+	if (ret < 0)
+		goto error;
+
+	ret = omap3isp_video_register(&prev->video_out, vdev);
+	if (ret < 0)
+		goto error;
+
+	return 0;
+
+error:
+	omap3isp_preview_unregister_entities(prev);
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP previewer initialisation and cleanup
+ */
+
+/*
+ * preview_init_entities - Initialize subdev and media entity.
+ * @prev : Pointer to preview structure
+ * return -ENOMEM or zero on success
+ */
+static int preview_init_entities(struct isp_prev_device *prev)
+{
+	struct v4l2_subdev *sd = &prev->subdev;
+	struct media_pad *pads = prev->pads;
+	struct media_entity *me = &sd->entity;
+	int ret;
+
+	prev->input = PREVIEW_INPUT_NONE;
+
+	v4l2_subdev_init(sd, &preview_v4l2_ops);
+	sd->internal_ops = &preview_v4l2_internal_ops;
+	strlcpy(sd->name, "OMAP3 ISP preview", sizeof(sd->name));
+	sd->grp_id = 1 << 16;	/* group ID for isp subdevs */
+	v4l2_set_subdevdata(sd, prev);
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	v4l2_ctrl_handler_init(&prev->ctrls, 2);
+	v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_BRIGHTNESS,
+			  ISPPRV_BRIGHT_LOW, ISPPRV_BRIGHT_HIGH,
+			  ISPPRV_BRIGHT_STEP, ISPPRV_BRIGHT_DEF);
+	v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_CONTRAST,
+			  ISPPRV_CONTRAST_LOW, ISPPRV_CONTRAST_HIGH,
+			  ISPPRV_CONTRAST_STEP, ISPPRV_CONTRAST_DEF);
+	v4l2_ctrl_handler_setup(&prev->ctrls);
+	sd->ctrl_handler = &prev->ctrls;
+
+	pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+	me->ops = &preview_media_ops;
+	ret = media_entity_init(me, PREV_PADS_NUM, pads, 0);
+	if (ret < 0)
+		return ret;
+
+	preview_init_formats(sd, NULL);
+
+	/* According to the OMAP34xx TRM, video buffers need to be aligned on a
+	 * 32 bytes boundary. However, an undocumented hardware bug requires a
+	 * 64 bytes boundary at the preview engine input.
+	 */
+	prev->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	prev->video_in.ops = &preview_video_ops;
+	prev->video_in.isp = to_isp_device(prev);
+	prev->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
+	prev->video_in.bpl_alignment = 64;
+	prev->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	prev->video_out.ops = &preview_video_ops;
+	prev->video_out.isp = to_isp_device(prev);
+	prev->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
+	prev->video_out.bpl_alignment = 32;
+
+	ret = omap3isp_video_init(&prev->video_in, "preview");
+	if (ret < 0)
+		goto error_video_in;
+
+	ret = omap3isp_video_init(&prev->video_out, "preview");
+	if (ret < 0)
+		goto error_video_out;
+
+	/* Connect the video nodes to the previewer subdev. */
+	ret = media_entity_create_link(&prev->video_in.video.entity, 0,
+			&prev->subdev.entity, PREV_PAD_SINK, 0);
+	if (ret < 0)
+		goto error_link;
+
+	ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE,
+			&prev->video_out.video.entity, 0, 0);
+	if (ret < 0)
+		goto error_link;
+
+	return 0;
+
+error_link:
+	omap3isp_video_cleanup(&prev->video_out);
+error_video_out:
+	omap3isp_video_cleanup(&prev->video_in);
+error_video_in:
+	media_entity_cleanup(&prev->subdev.entity);
+	return ret;
+}
+
+/*
+ * omap3isp_preview_init - Previewer initialization.
+ * @dev : Pointer to ISP device
+ * return -ENOMEM or zero on success
+ */
+int omap3isp_preview_init(struct isp_device *isp)
+{
+	struct isp_prev_device *prev = &isp->isp_prev;
+
+	init_waitqueue_head(&prev->wait);
+
+	preview_init_params(prev);
+
+	return preview_init_entities(prev);
+}
+
+void omap3isp_preview_cleanup(struct isp_device *isp)
+{
+	struct isp_prev_device *prev = &isp->isp_prev;
+
+	v4l2_ctrl_handler_free(&prev->ctrls);
+	omap3isp_video_cleanup(&prev->video_in);
+	omap3isp_video_cleanup(&prev->video_out);
+	media_entity_cleanup(&prev->subdev.entity);
+}
diff --git a/drivers/media/platform/omap3isp/isppreview.h b/drivers/media/platform/omap3isp/isppreview.h
new file mode 100644
index 0000000..f669234
--- /dev/null
+++ b/drivers/media/platform/omap3isp/isppreview.h
@@ -0,0 +1,174 @@
+/*
+ * isppreview.h
+ *
+ * TI OMAP3 ISP - Preview module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_PREVIEW_H
+#define OMAP3_ISP_PREVIEW_H
+
+#include <linux/omap3isp.h>
+#include <linux/types.h>
+#include <media/v4l2-ctrls.h>
+
+#include "ispvideo.h"
+
+#define ISPPRV_BRIGHT_STEP		0x1
+#define ISPPRV_BRIGHT_DEF		0x0
+#define ISPPRV_BRIGHT_LOW		0x0
+#define ISPPRV_BRIGHT_HIGH		0xFF
+#define ISPPRV_BRIGHT_UNITS		0x1
+
+#define ISPPRV_CONTRAST_STEP		0x1
+#define ISPPRV_CONTRAST_DEF		0x10
+#define ISPPRV_CONTRAST_LOW		0x0
+#define ISPPRV_CONTRAST_HIGH		0xFF
+#define ISPPRV_CONTRAST_UNITS		0x1
+
+/* Additional features not listed in linux/omap3isp.h */
+#define OMAP3ISP_PREV_CONTRAST		(1 << 17)
+#define OMAP3ISP_PREV_BRIGHTNESS	(1 << 18)
+#define OMAP3ISP_PREV_FEATURES_END	(1 << 19)
+
+enum preview_input_entity {
+	PREVIEW_INPUT_NONE,
+	PREVIEW_INPUT_CCDC,
+	PREVIEW_INPUT_MEMORY,
+};
+
+#define PREVIEW_OUTPUT_RESIZER		(1 << 1)
+#define PREVIEW_OUTPUT_MEMORY		(1 << 2)
+
+/* Configure byte layout of YUV image */
+enum preview_ycpos_mode {
+	YCPOS_YCrYCb = 0,
+	YCPOS_YCbYCr = 1,
+	YCPOS_CbYCrY = 2,
+	YCPOS_CrYCbY = 3
+};
+
+/*
+ * struct prev_params - Structure for all configuration
+ * @busy: Bitmask of busy parameters (being updated or used)
+ * @update: Bitmask of the parameters to be updated
+ * @features: Set of features enabled.
+ * @cfa: CFA coefficients.
+ * @csup: Chroma suppression coefficients.
+ * @luma: Luma enhancement coefficients.
+ * @nf: Noise filter coefficients.
+ * @dcor: Noise filter coefficients.
+ * @gamma: Gamma coefficients.
+ * @wbal: White Balance parameters.
+ * @blkadj: Black adjustment parameters.
+ * @rgb2rgb: RGB blending parameters.
+ * @csc: Color space conversion (RGB to YCbCr) parameters.
+ * @hmed: Horizontal median filter.
+ * @yclimit: YC limits parameters.
+ * @contrast: Contrast.
+ * @brightness: Brightness.
+ */
+struct prev_params {
+	u32 busy;
+	u32 update;
+	u32 features;
+	struct omap3isp_prev_cfa cfa;
+	struct omap3isp_prev_csup csup;
+	struct omap3isp_prev_luma luma;
+	struct omap3isp_prev_nf nf;
+	struct omap3isp_prev_dcor dcor;
+	struct omap3isp_prev_gtables gamma;
+	struct omap3isp_prev_wbal wbal;
+	struct omap3isp_prev_blkadj blkadj;
+	struct omap3isp_prev_rgbtorgb rgb2rgb;
+	struct omap3isp_prev_csc csc;
+	struct omap3isp_prev_hmed hmed;
+	struct omap3isp_prev_yclimit yclimit;
+	u8 contrast;
+	u8 brightness;
+};
+
+/* Sink and source previewer pads */
+#define PREV_PAD_SINK			0
+#define PREV_PAD_SOURCE			1
+#define PREV_PADS_NUM			2
+
+/*
+ * struct isp_prev_device - Structure for storing ISP Preview module information
+ * @subdev: V4L2 subdevice
+ * @pads: Media entity pads
+ * @formats: Active formats at the subdev pad
+ * @crop: Active crop rectangle
+ * @input: Module currently connected to the input pad
+ * @output: Bitmask of the active output
+ * @video_in: Input video entity
+ * @video_out: Output video entity
+ * @params.params : Active and shadow parameters sets
+ * @params.active: Bitmask of parameters active in set 0
+ * @params.lock: Parameters lock, protects params.active and params.shadow
+ * @underrun: Whether the preview entity has queued buffers on the output
+ * @state: Current preview pipeline state
+ *
+ * This structure is used to store the OMAP ISP Preview module Information.
+ */
+struct isp_prev_device {
+	struct v4l2_subdev subdev;
+	struct media_pad pads[PREV_PADS_NUM];
+	struct v4l2_mbus_framefmt formats[PREV_PADS_NUM];
+	struct v4l2_rect crop;
+
+	struct v4l2_ctrl_handler ctrls;
+
+	enum preview_input_entity input;
+	unsigned int output;
+	struct isp_video video_in;
+	struct isp_video video_out;
+
+	struct {
+		unsigned int cfa_order;
+		struct prev_params params[2];
+		u32 active;
+		spinlock_t lock;
+	} params;
+
+	enum isp_pipeline_stream_state state;
+	wait_queue_head_t wait;
+	atomic_t stopping;
+};
+
+struct isp_device;
+
+int omap3isp_preview_init(struct isp_device *isp);
+void omap3isp_preview_cleanup(struct isp_device *isp);
+
+int omap3isp_preview_register_entities(struct isp_prev_device *prv,
+				       struct v4l2_device *vdev);
+void omap3isp_preview_unregister_entities(struct isp_prev_device *prv);
+
+void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev);
+void omap3isp_preview_isr(struct isp_prev_device *prev);
+
+int omap3isp_preview_busy(struct isp_prev_device *isp_prev);
+
+void omap3isp_preview_restore_context(struct isp_device *isp);
+
+#endif	/* OMAP3_ISP_PREVIEW_H */
diff --git a/drivers/media/platform/omap3isp/ispqueue.c b/drivers/media/platform/omap3isp/ispqueue.c
new file mode 100644
index 0000000..15bf3ea
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispqueue.c
@@ -0,0 +1,1158 @@
+/*
+ * ispqueue.c
+ *
+ * TI OMAP3 ISP - Video buffers queue handling
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <asm/cacheflush.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/poll.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include "ispqueue.h"
+
+/* -----------------------------------------------------------------------------
+ * Video buffers management
+ */
+
+/*
+ * isp_video_buffer_cache_sync - Keep the buffers coherent between CPU and ISP
+ *
+ * The typical operation required here is Cache Invalidation across
+ * the (user space) buffer address range. And this _must_ be done
+ * at QBUF stage (and *only* at QBUF).
+ *
+ * We try to use optimal cache invalidation function:
+ * - dmac_map_area:
+ *    - used when the number of pages are _low_.
+ *    - it becomes quite slow as the number of pages increase.
+ *       - for 648x492 viewfinder (150 pages) it takes 1.3 ms.
+ *       - for 5 Mpix buffer (2491 pages) it takes between 25-50 ms.
+ *
+ * - flush_cache_all:
+ *    - used when the number of pages are _high_.
+ *    - time taken in the range of 500-900 us.
+ *    - has a higher penalty but, as whole dcache + icache is invalidated
+ */
+/*
+ * FIXME: dmac_inv_range crashes randomly on the user space buffer
+ *        address. Fall back to flush_cache_all for now.
+ */
+#define ISP_CACHE_FLUSH_PAGES_MAX       0
+
+static void isp_video_buffer_cache_sync(struct isp_video_buffer *buf)
+{
+	if (buf->skip_cache)
+		return;
+
+	if (buf->vbuf.m.userptr == 0 || buf->npages == 0 ||
+	    buf->npages > ISP_CACHE_FLUSH_PAGES_MAX)
+		flush_cache_all();
+	else {
+		dmac_map_area((void *)buf->vbuf.m.userptr, buf->vbuf.length,
+			      DMA_FROM_DEVICE);
+		outer_inv_range(buf->vbuf.m.userptr,
+				buf->vbuf.m.userptr + buf->vbuf.length);
+	}
+}
+
+/*
+ * isp_video_buffer_lock_vma - Prevent VMAs from being unmapped
+ *
+ * Lock the VMAs underlying the given buffer into memory. This avoids the
+ * userspace buffer mapping from being swapped out, making VIPT cache handling
+ * easier.
+ *
+ * Note that the pages will not be freed as the buffers have been locked to
+ * memory using by a call to get_user_pages(), but the userspace mapping could
+ * still disappear if the VMAs are not locked. This is caused by the memory
+ * management code trying to be as lock-less as possible, which results in the
+ * userspace mapping manager not finding out that the pages are locked under
+ * some conditions.
+ */
+static int isp_video_buffer_lock_vma(struct isp_video_buffer *buf, int lock)
+{
+	struct vm_area_struct *vma;
+	unsigned long start;
+	unsigned long end;
+	int ret = 0;
+
+	if (buf->vbuf.memory == V4L2_MEMORY_MMAP)
+		return 0;
+
+	/* We can be called from workqueue context if the current task dies to
+	 * unlock the VMAs. In that case there's no current memory management
+	 * context so unlocking can't be performed, but the VMAs have been or
+	 * are getting destroyed anyway so it doesn't really matter.
+	 */
+	if (!current || !current->mm)
+		return lock ? -EINVAL : 0;
+
+	start = buf->vbuf.m.userptr;
+	end = buf->vbuf.m.userptr + buf->vbuf.length - 1;
+
+	down_write(&current->mm->mmap_sem);
+	spin_lock(&current->mm->page_table_lock);
+
+	do {
+		vma = find_vma(current->mm, start);
+		if (vma == NULL) {
+			ret = -EFAULT;
+			goto out;
+		}
+
+		if (lock)
+			vma->vm_flags |= VM_LOCKED;
+		else
+			vma->vm_flags &= ~VM_LOCKED;
+
+		start = vma->vm_end + 1;
+	} while (vma->vm_end < end);
+
+	if (lock)
+		buf->vm_flags |= VM_LOCKED;
+	else
+		buf->vm_flags &= ~VM_LOCKED;
+
+out:
+	spin_unlock(&current->mm->page_table_lock);
+	up_write(&current->mm->mmap_sem);
+	return ret;
+}
+
+/*
+ * isp_video_buffer_sglist_kernel - Build a scatter list for a vmalloc'ed buffer
+ *
+ * Iterate over the vmalloc'ed area and create a scatter list entry for every
+ * page.
+ */
+static int isp_video_buffer_sglist_kernel(struct isp_video_buffer *buf)
+{
+	struct scatterlist *sglist;
+	unsigned int npages;
+	unsigned int i;
+	void *addr;
+
+	addr = buf->vaddr;
+	npages = PAGE_ALIGN(buf->vbuf.length) >> PAGE_SHIFT;
+
+	sglist = vmalloc(npages * sizeof(*sglist));
+	if (sglist == NULL)
+		return -ENOMEM;
+
+	sg_init_table(sglist, npages);
+
+	for (i = 0; i < npages; ++i, addr += PAGE_SIZE) {
+		struct page *page = vmalloc_to_page(addr);
+
+		if (page == NULL || PageHighMem(page)) {
+			vfree(sglist);
+			return -EINVAL;
+		}
+
+		sg_set_page(&sglist[i], page, PAGE_SIZE, 0);
+	}
+
+	buf->sglen = npages;
+	buf->sglist = sglist;
+
+	return 0;
+}
+
+/*
+ * isp_video_buffer_sglist_user - Build a scatter list for a userspace buffer
+ *
+ * Walk the buffer pages list and create a 1:1 mapping to a scatter list.
+ */
+static int isp_video_buffer_sglist_user(struct isp_video_buffer *buf)
+{
+	struct scatterlist *sglist;
+	unsigned int offset = buf->offset;
+	unsigned int i;
+
+	sglist = vmalloc(buf->npages * sizeof(*sglist));
+	if (sglist == NULL)
+		return -ENOMEM;
+
+	sg_init_table(sglist, buf->npages);
+
+	for (i = 0; i < buf->npages; ++i) {
+		if (PageHighMem(buf->pages[i])) {
+			vfree(sglist);
+			return -EINVAL;
+		}
+
+		sg_set_page(&sglist[i], buf->pages[i], PAGE_SIZE - offset,
+			    offset);
+		offset = 0;
+	}
+
+	buf->sglen = buf->npages;
+	buf->sglist = sglist;
+
+	return 0;
+}
+
+/*
+ * isp_video_buffer_sglist_pfnmap - Build a scatter list for a VM_PFNMAP buffer
+ *
+ * Create a scatter list of physically contiguous pages starting at the buffer
+ * memory physical address.
+ */
+static int isp_video_buffer_sglist_pfnmap(struct isp_video_buffer *buf)
+{
+	struct scatterlist *sglist;
+	unsigned int offset = buf->offset;
+	unsigned long pfn = buf->paddr >> PAGE_SHIFT;
+	unsigned int i;
+
+	sglist = vmalloc(buf->npages * sizeof(*sglist));
+	if (sglist == NULL)
+		return -ENOMEM;
+
+	sg_init_table(sglist, buf->npages);
+
+	for (i = 0; i < buf->npages; ++i, ++pfn) {
+		sg_set_page(&sglist[i], pfn_to_page(pfn), PAGE_SIZE - offset,
+			    offset);
+		/* PFNMAP buffers will not get DMA-mapped, set the DMA address
+		 * manually.
+		 */
+		sg_dma_address(&sglist[i]) = (pfn << PAGE_SHIFT) + offset;
+		offset = 0;
+	}
+
+	buf->sglen = buf->npages;
+	buf->sglist = sglist;
+
+	return 0;
+}
+
+/*
+ * isp_video_buffer_cleanup - Release pages for a userspace VMA.
+ *
+ * Release pages locked by a call isp_video_buffer_prepare_user and free the
+ * pages table.
+ */
+static void isp_video_buffer_cleanup(struct isp_video_buffer *buf)
+{
+	enum dma_data_direction direction;
+	unsigned int i;
+
+	if (buf->queue->ops->buffer_cleanup)
+		buf->queue->ops->buffer_cleanup(buf);
+
+	if (!(buf->vm_flags & VM_PFNMAP)) {
+		direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE
+			  ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+		dma_unmap_sg(buf->queue->dev, buf->sglist, buf->sglen,
+			     direction);
+	}
+
+	vfree(buf->sglist);
+	buf->sglist = NULL;
+	buf->sglen = 0;
+
+	if (buf->pages != NULL) {
+		isp_video_buffer_lock_vma(buf, 0);
+
+		for (i = 0; i < buf->npages; ++i)
+			page_cache_release(buf->pages[i]);
+
+		vfree(buf->pages);
+		buf->pages = NULL;
+	}
+
+	buf->npages = 0;
+	buf->skip_cache = false;
+}
+
+/*
+ * isp_video_buffer_prepare_user - Pin userspace VMA pages to memory.
+ *
+ * This function creates a list of pages for a userspace VMA. The number of
+ * pages is first computed based on the buffer size, and pages are then
+ * retrieved by a call to get_user_pages.
+ *
+ * Pages are pinned to memory by get_user_pages, making them available for DMA
+ * transfers. However, due to memory management optimization, it seems the
+ * get_user_pages doesn't guarantee that the pinned pages will not be written
+ * to swap and removed from the userspace mapping(s). When this happens, a page
+ * fault can be generated when accessing those unmapped pages.
+ *
+ * If the fault is triggered by a page table walk caused by VIPT cache
+ * management operations, the page fault handler might oops if the MM semaphore
+ * is held, as it can't handle kernel page faults in that case. To fix that, a
+ * fixup entry needs to be added to the cache management code, or the userspace
+ * VMA must be locked to avoid removing pages from the userspace mapping in the
+ * first place.
+ *
+ * If the number of pages retrieved is smaller than the number required by the
+ * buffer size, the function returns -EFAULT.
+ */
+static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf)
+{
+	unsigned long data;
+	unsigned int first;
+	unsigned int last;
+	int ret;
+
+	data = buf->vbuf.m.userptr;
+	first = (data & PAGE_MASK) >> PAGE_SHIFT;
+	last = ((data + buf->vbuf.length - 1) & PAGE_MASK) >> PAGE_SHIFT;
+
+	buf->offset = data & ~PAGE_MASK;
+	buf->npages = last - first + 1;
+	buf->pages = vmalloc(buf->npages * sizeof(buf->pages[0]));
+	if (buf->pages == NULL)
+		return -ENOMEM;
+
+	down_read(&current->mm->mmap_sem);
+	ret = get_user_pages(current, current->mm, data & PAGE_MASK,
+			     buf->npages,
+			     buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
+			     buf->pages, NULL);
+	up_read(&current->mm->mmap_sem);
+
+	if (ret != buf->npages) {
+		buf->npages = ret < 0 ? 0 : ret;
+		isp_video_buffer_cleanup(buf);
+		return -EFAULT;
+	}
+
+	ret = isp_video_buffer_lock_vma(buf, 1);
+	if (ret < 0)
+		isp_video_buffer_cleanup(buf);
+
+	return ret;
+}
+
+/*
+ * isp_video_buffer_prepare_pfnmap - Validate a VM_PFNMAP userspace buffer
+ *
+ * Userspace VM_PFNMAP buffers are supported only if they are contiguous in
+ * memory and if they span a single VMA.
+ *
+ * Return 0 if the buffer is valid, or -EFAULT otherwise.
+ */
+static int isp_video_buffer_prepare_pfnmap(struct isp_video_buffer *buf)
+{
+	struct vm_area_struct *vma;
+	unsigned long prev_pfn;
+	unsigned long this_pfn;
+	unsigned long start;
+	unsigned long end;
+	dma_addr_t pa;
+	int ret = -EFAULT;
+
+	start = buf->vbuf.m.userptr;
+	end = buf->vbuf.m.userptr + buf->vbuf.length - 1;
+
+	buf->offset = start & ~PAGE_MASK;
+	buf->npages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1;
+	buf->pages = NULL;
+
+	down_read(&current->mm->mmap_sem);
+	vma = find_vma(current->mm, start);
+	if (vma == NULL || vma->vm_end < end)
+		goto done;
+
+	for (prev_pfn = 0; start <= end; start += PAGE_SIZE) {
+		ret = follow_pfn(vma, start, &this_pfn);
+		if (ret)
+			goto done;
+
+		if (prev_pfn == 0)
+			pa = this_pfn << PAGE_SHIFT;
+		else if (this_pfn != prev_pfn + 1) {
+			ret = -EFAULT;
+			goto done;
+		}
+
+		prev_pfn = this_pfn;
+	}
+
+	buf->paddr = pa + buf->offset;
+	ret = 0;
+
+done:
+	up_read(&current->mm->mmap_sem);
+	return ret;
+}
+
+/*
+ * isp_video_buffer_prepare_vm_flags - Get VMA flags for a userspace address
+ *
+ * This function locates the VMAs for the buffer's userspace address and checks
+ * that their flags match. The only flag that we need to care for at the moment
+ * is VM_PFNMAP.
+ *
+ * The buffer vm_flags field is set to the first VMA flags.
+ *
+ * Return -EFAULT if no VMA can be found for part of the buffer, or if the VMAs
+ * have incompatible flags.
+ */
+static int isp_video_buffer_prepare_vm_flags(struct isp_video_buffer *buf)
+{
+	struct vm_area_struct *vma;
+	pgprot_t vm_page_prot;
+	unsigned long start;
+	unsigned long end;
+	int ret = -EFAULT;
+
+	start = buf->vbuf.m.userptr;
+	end = buf->vbuf.m.userptr + buf->vbuf.length - 1;
+
+	down_read(&current->mm->mmap_sem);
+
+	do {
+		vma = find_vma(current->mm, start);
+		if (vma == NULL)
+			goto done;
+
+		if (start == buf->vbuf.m.userptr) {
+			buf->vm_flags = vma->vm_flags;
+			vm_page_prot = vma->vm_page_prot;
+		}
+
+		if ((buf->vm_flags ^ vma->vm_flags) & VM_PFNMAP)
+			goto done;
+
+		if (vm_page_prot != vma->vm_page_prot)
+			goto done;
+
+		start = vma->vm_end + 1;
+	} while (vma->vm_end < end);
+
+	/* Skip cache management to enhance performances for non-cached or
+	 * write-combining buffers.
+	 */
+	if (vm_page_prot == pgprot_noncached(vm_page_prot) ||
+	    vm_page_prot == pgprot_writecombine(vm_page_prot))
+		buf->skip_cache = true;
+
+	ret = 0;
+
+done:
+	up_read(&current->mm->mmap_sem);
+	return ret;
+}
+
+/*
+ * isp_video_buffer_prepare - Make a buffer ready for operation
+ *
+ * Preparing a buffer involves:
+ *
+ * - validating VMAs (userspace buffers only)
+ * - locking pages and VMAs into memory (userspace buffers only)
+ * - building page and scatter-gather lists
+ * - mapping buffers for DMA operation
+ * - performing driver-specific preparation
+ *
+ * The function must be called in userspace context with a valid mm context
+ * (this excludes cleanup paths such as sys_close when the userspace process
+ * segfaults).
+ */
+static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
+{
+	enum dma_data_direction direction;
+	int ret;
+
+	switch (buf->vbuf.memory) {
+	case V4L2_MEMORY_MMAP:
+		ret = isp_video_buffer_sglist_kernel(buf);
+		break;
+
+	case V4L2_MEMORY_USERPTR:
+		ret = isp_video_buffer_prepare_vm_flags(buf);
+		if (ret < 0)
+			return ret;
+
+		if (buf->vm_flags & VM_PFNMAP) {
+			ret = isp_video_buffer_prepare_pfnmap(buf);
+			if (ret < 0)
+				return ret;
+
+			ret = isp_video_buffer_sglist_pfnmap(buf);
+		} else {
+			ret = isp_video_buffer_prepare_user(buf);
+			if (ret < 0)
+				return ret;
+
+			ret = isp_video_buffer_sglist_user(buf);
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (ret < 0)
+		goto done;
+
+	if (!(buf->vm_flags & VM_PFNMAP)) {
+		direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE
+			  ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+		ret = dma_map_sg(buf->queue->dev, buf->sglist, buf->sglen,
+				 direction);
+		if (ret != buf->sglen) {
+			ret = -EFAULT;
+			goto done;
+		}
+	}
+
+	if (buf->queue->ops->buffer_prepare)
+		ret = buf->queue->ops->buffer_prepare(buf);
+
+done:
+	if (ret < 0) {
+		isp_video_buffer_cleanup(buf);
+		return ret;
+	}
+
+	return ret;
+}
+
+/*
+ * isp_video_queue_query - Query the status of a given buffer
+ *
+ * Locking: must be called with the queue lock held.
+ */
+static void isp_video_buffer_query(struct isp_video_buffer *buf,
+				   struct v4l2_buffer *vbuf)
+{
+	memcpy(vbuf, &buf->vbuf, sizeof(*vbuf));
+
+	if (buf->vma_use_count)
+		vbuf->flags |= V4L2_BUF_FLAG_MAPPED;
+
+	switch (buf->state) {
+	case ISP_BUF_STATE_ERROR:
+		vbuf->flags |= V4L2_BUF_FLAG_ERROR;
+	case ISP_BUF_STATE_DONE:
+		vbuf->flags |= V4L2_BUF_FLAG_DONE;
+	case ISP_BUF_STATE_QUEUED:
+	case ISP_BUF_STATE_ACTIVE:
+		vbuf->flags |= V4L2_BUF_FLAG_QUEUED;
+		break;
+	case ISP_BUF_STATE_IDLE:
+	default:
+		break;
+	}
+}
+
+/*
+ * isp_video_buffer_wait - Wait for a buffer to be ready
+ *
+ * In non-blocking mode, return immediately with 0 if the buffer is ready or
+ * -EAGAIN if the buffer is in the QUEUED or ACTIVE state.
+ *
+ * In blocking mode, wait (interruptibly but with no timeout) on the buffer wait
+ * queue using the same condition.
+ */
+static int isp_video_buffer_wait(struct isp_video_buffer *buf, int nonblocking)
+{
+	if (nonblocking) {
+		return (buf->state != ISP_BUF_STATE_QUEUED &&
+			buf->state != ISP_BUF_STATE_ACTIVE)
+			? 0 : -EAGAIN;
+	}
+
+	return wait_event_interruptible(buf->wait,
+		buf->state != ISP_BUF_STATE_QUEUED &&
+		buf->state != ISP_BUF_STATE_ACTIVE);
+}
+
+/* -----------------------------------------------------------------------------
+ * Queue management
+ */
+
+/*
+ * isp_video_queue_free - Free video buffers memory
+ *
+ * Buffers can only be freed if the queue isn't streaming and if no buffer is
+ * mapped to userspace. Return -EBUSY if those conditions aren't statisfied.
+ *
+ * This function must be called with the queue lock held.
+ */
+static int isp_video_queue_free(struct isp_video_queue *queue)
+{
+	unsigned int i;
+
+	if (queue->streaming)
+		return -EBUSY;
+
+	for (i = 0; i < queue->count; ++i) {
+		if (queue->buffers[i]->vma_use_count != 0)
+			return -EBUSY;
+	}
+
+	for (i = 0; i < queue->count; ++i) {
+		struct isp_video_buffer *buf = queue->buffers[i];
+
+		isp_video_buffer_cleanup(buf);
+
+		vfree(buf->vaddr);
+		buf->vaddr = NULL;
+
+		kfree(buf);
+		queue->buffers[i] = NULL;
+	}
+
+	INIT_LIST_HEAD(&queue->queue);
+	queue->count = 0;
+	return 0;
+}
+
+/*
+ * isp_video_queue_alloc - Allocate video buffers memory
+ *
+ * This function must be called with the queue lock held.
+ */
+static int isp_video_queue_alloc(struct isp_video_queue *queue,
+				 unsigned int nbuffers,
+				 unsigned int size, enum v4l2_memory memory)
+{
+	struct isp_video_buffer *buf;
+	unsigned int i;
+	void *mem;
+	int ret;
+
+	/* Start by freeing the buffers. */
+	ret = isp_video_queue_free(queue);
+	if (ret < 0)
+		return ret;
+
+	/* Bail out if no buffers should be allocated. */
+	if (nbuffers == 0)
+		return 0;
+
+	/* Initialize the allocated buffers. */
+	for (i = 0; i < nbuffers; ++i) {
+		buf = kzalloc(queue->bufsize, GFP_KERNEL);
+		if (buf == NULL)
+			break;
+
+		if (memory == V4L2_MEMORY_MMAP) {
+			/* Allocate video buffers memory for mmap mode. Align
+			 * the size to the page size.
+			 */
+			mem = vmalloc_32_user(PAGE_ALIGN(size));
+			if (mem == NULL) {
+				kfree(buf);
+				break;
+			}
+
+			buf->vbuf.m.offset = i * PAGE_ALIGN(size);
+			buf->vaddr = mem;
+		}
+
+		buf->vbuf.index = i;
+		buf->vbuf.length = size;
+		buf->vbuf.type = queue->type;
+		buf->vbuf.field = V4L2_FIELD_NONE;
+		buf->vbuf.memory = memory;
+
+		buf->queue = queue;
+		init_waitqueue_head(&buf->wait);
+
+		queue->buffers[i] = buf;
+	}
+
+	if (i == 0)
+		return -ENOMEM;
+
+	queue->count = i;
+	return nbuffers;
+}
+
+/**
+ * omap3isp_video_queue_cleanup - Clean up the video buffers queue
+ * @queue: Video buffers queue
+ *
+ * Free all allocated resources and clean up the video buffers queue. The queue
+ * must not be busy (no ongoing video stream) and buffers must have been
+ * unmapped.
+ *
+ * Return 0 on success or -EBUSY if the queue is busy or buffers haven't been
+ * unmapped.
+ */
+int omap3isp_video_queue_cleanup(struct isp_video_queue *queue)
+{
+	return isp_video_queue_free(queue);
+}
+
+/**
+ * omap3isp_video_queue_init - Initialize the video buffers queue
+ * @queue: Video buffers queue
+ * @type: V4L2 buffer type (capture or output)
+ * @ops: Driver-specific queue operations
+ * @dev: Device used for DMA operations
+ * @bufsize: Size of the driver-specific buffer structure
+ *
+ * Initialize the video buffers queue with the supplied parameters.
+ *
+ * The queue type must be one of V4L2_BUF_TYPE_VIDEO_CAPTURE or
+ * V4L2_BUF_TYPE_VIDEO_OUTPUT. Other buffer types are not supported yet.
+ *
+ * Buffer objects will be allocated using the given buffer size to allow room
+ * for driver-specific fields. Driver-specific buffer structures must start
+ * with a struct isp_video_buffer field. Drivers with no driver-specific buffer
+ * structure must pass the size of the isp_video_buffer structure in the bufsize
+ * parameter.
+ *
+ * Return 0 on success.
+ */
+int omap3isp_video_queue_init(struct isp_video_queue *queue,
+			      enum v4l2_buf_type type,
+			      const struct isp_video_queue_operations *ops,
+			      struct device *dev, unsigned int bufsize)
+{
+	INIT_LIST_HEAD(&queue->queue);
+	mutex_init(&queue->lock);
+	spin_lock_init(&queue->irqlock);
+
+	queue->type = type;
+	queue->ops = ops;
+	queue->dev = dev;
+	queue->bufsize = bufsize;
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 operations
+ */
+
+/**
+ * omap3isp_video_queue_reqbufs - Allocate video buffers memory
+ *
+ * This function is intended to be used as a VIDIOC_REQBUFS ioctl handler. It
+ * allocated video buffer objects and, for MMAP buffers, buffer memory.
+ *
+ * If the number of buffers is 0, all buffers are freed and the function returns
+ * without performing any allocation.
+ *
+ * If the number of buffers is not 0, currently allocated buffers (if any) are
+ * freed and the requested number of buffers are allocated. Depending on
+ * driver-specific requirements and on memory availability, a number of buffer
+ * smaller or bigger than requested can be allocated. This isn't considered as
+ * an error.
+ *
+ * Return 0 on success or one of the following error codes:
+ *
+ * -EINVAL if the buffer type or index are invalid
+ * -EBUSY if the queue is busy (streaming or buffers mapped)
+ * -ENOMEM if the buffers can't be allocated due to an out-of-memory condition
+ */
+int omap3isp_video_queue_reqbufs(struct isp_video_queue *queue,
+				 struct v4l2_requestbuffers *rb)
+{
+	unsigned int nbuffers = rb->count;
+	unsigned int size;
+	int ret;
+
+	if (rb->type != queue->type)
+		return -EINVAL;
+
+	queue->ops->queue_prepare(queue, &nbuffers, &size);
+	if (size == 0)
+		return -EINVAL;
+
+	nbuffers = min_t(unsigned int, nbuffers, ISP_VIDEO_MAX_BUFFERS);
+
+	mutex_lock(&queue->lock);
+
+	ret = isp_video_queue_alloc(queue, nbuffers, size, rb->memory);
+	if (ret < 0)
+		goto done;
+
+	rb->count = ret;
+	ret = 0;
+
+done:
+	mutex_unlock(&queue->lock);
+	return ret;
+}
+
+/**
+ * omap3isp_video_queue_querybuf - Query the status of a buffer in a queue
+ *
+ * This function is intended to be used as a VIDIOC_QUERYBUF ioctl handler. It
+ * returns the status of a given video buffer.
+ *
+ * Return 0 on success or -EINVAL if the buffer type or index are invalid.
+ */
+int omap3isp_video_queue_querybuf(struct isp_video_queue *queue,
+				  struct v4l2_buffer *vbuf)
+{
+	struct isp_video_buffer *buf;
+	int ret = 0;
+
+	if (vbuf->type != queue->type)
+		return -EINVAL;
+
+	mutex_lock(&queue->lock);
+
+	if (vbuf->index >= queue->count) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	buf = queue->buffers[vbuf->index];
+	isp_video_buffer_query(buf, vbuf);
+
+done:
+	mutex_unlock(&queue->lock);
+	return ret;
+}
+
+/**
+ * omap3isp_video_queue_qbuf - Queue a buffer
+ *
+ * This function is intended to be used as a VIDIOC_QBUF ioctl handler.
+ *
+ * The v4l2_buffer structure passed from userspace is first sanity tested. If
+ * sane, the buffer is then processed and added to the main queue and, if the
+ * queue is streaming, to the IRQ queue.
+ *
+ * Before being enqueued, USERPTR buffers are checked for address changes. If
+ * the buffer has a different userspace address, the old memory area is unlocked
+ * and the new memory area is locked.
+ */
+int omap3isp_video_queue_qbuf(struct isp_video_queue *queue,
+			      struct v4l2_buffer *vbuf)
+{
+	struct isp_video_buffer *buf;
+	unsigned long flags;
+	int ret = -EINVAL;
+
+	if (vbuf->type != queue->type)
+		goto done;
+
+	mutex_lock(&queue->lock);
+
+	if (vbuf->index >= queue->count)
+		goto done;
+
+	buf = queue->buffers[vbuf->index];
+
+	if (vbuf->memory != buf->vbuf.memory)
+		goto done;
+
+	if (buf->state != ISP_BUF_STATE_IDLE)
+		goto done;
+
+	if (vbuf->memory == V4L2_MEMORY_USERPTR &&
+	    vbuf->length < buf->vbuf.length)
+		goto done;
+
+	if (vbuf->memory == V4L2_MEMORY_USERPTR &&
+	    vbuf->m.userptr != buf->vbuf.m.userptr) {
+		isp_video_buffer_cleanup(buf);
+		buf->vbuf.m.userptr = vbuf->m.userptr;
+		buf->prepared = 0;
+	}
+
+	if (!buf->prepared) {
+		ret = isp_video_buffer_prepare(buf);
+		if (ret < 0)
+			goto done;
+		buf->prepared = 1;
+	}
+
+	isp_video_buffer_cache_sync(buf);
+
+	buf->state = ISP_BUF_STATE_QUEUED;
+	list_add_tail(&buf->stream, &queue->queue);
+
+	if (queue->streaming) {
+		spin_lock_irqsave(&queue->irqlock, flags);
+		queue->ops->buffer_queue(buf);
+		spin_unlock_irqrestore(&queue->irqlock, flags);
+	}
+
+	ret = 0;
+
+done:
+	mutex_unlock(&queue->lock);
+	return ret;
+}
+
+/**
+ * omap3isp_video_queue_dqbuf - Dequeue a buffer
+ *
+ * This function is intended to be used as a VIDIOC_DQBUF ioctl handler.
+ *
+ * Wait until a buffer is ready to be dequeued, remove it from the queue and
+ * copy its information to the v4l2_buffer structure.
+ *
+ * If the nonblocking argument is not zero and no buffer is ready, return
+ * -EAGAIN immediately instead of waiting.
+ *
+ * If no buffer has been enqueued, or if the requested buffer type doesn't match
+ * the queue type, return -EINVAL.
+ */
+int omap3isp_video_queue_dqbuf(struct isp_video_queue *queue,
+			       struct v4l2_buffer *vbuf, int nonblocking)
+{
+	struct isp_video_buffer *buf;
+	int ret;
+
+	if (vbuf->type != queue->type)
+		return -EINVAL;
+
+	mutex_lock(&queue->lock);
+
+	if (list_empty(&queue->queue)) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream);
+	ret = isp_video_buffer_wait(buf, nonblocking);
+	if (ret < 0)
+		goto done;
+
+	list_del(&buf->stream);
+
+	isp_video_buffer_query(buf, vbuf);
+	buf->state = ISP_BUF_STATE_IDLE;
+	vbuf->flags &= ~V4L2_BUF_FLAG_QUEUED;
+
+done:
+	mutex_unlock(&queue->lock);
+	return ret;
+}
+
+/**
+ * omap3isp_video_queue_streamon - Start streaming
+ *
+ * This function is intended to be used as a VIDIOC_STREAMON ioctl handler. It
+ * starts streaming on the queue and calls the buffer_queue operation for all
+ * queued buffers.
+ *
+ * Return 0 on success.
+ */
+int omap3isp_video_queue_streamon(struct isp_video_queue *queue)
+{
+	struct isp_video_buffer *buf;
+	unsigned long flags;
+
+	mutex_lock(&queue->lock);
+
+	if (queue->streaming)
+		goto done;
+
+	queue->streaming = 1;
+
+	spin_lock_irqsave(&queue->irqlock, flags);
+	list_for_each_entry(buf, &queue->queue, stream)
+		queue->ops->buffer_queue(buf);
+	spin_unlock_irqrestore(&queue->irqlock, flags);
+
+done:
+	mutex_unlock(&queue->lock);
+	return 0;
+}
+
+/**
+ * omap3isp_video_queue_streamoff - Stop streaming
+ *
+ * This function is intended to be used as a VIDIOC_STREAMOFF ioctl handler. It
+ * stops streaming on the queue and wakes up all the buffers.
+ *
+ * Drivers must stop the hardware and synchronize with interrupt handlers and/or
+ * delayed works before calling this function to make sure no buffer will be
+ * touched by the driver and/or hardware.
+ */
+void omap3isp_video_queue_streamoff(struct isp_video_queue *queue)
+{
+	struct isp_video_buffer *buf;
+	unsigned long flags;
+	unsigned int i;
+
+	mutex_lock(&queue->lock);
+
+	if (!queue->streaming)
+		goto done;
+
+	queue->streaming = 0;
+
+	spin_lock_irqsave(&queue->irqlock, flags);
+	for (i = 0; i < queue->count; ++i) {
+		buf = queue->buffers[i];
+
+		if (buf->state == ISP_BUF_STATE_ACTIVE)
+			wake_up(&buf->wait);
+
+		buf->state = ISP_BUF_STATE_IDLE;
+	}
+	spin_unlock_irqrestore(&queue->irqlock, flags);
+
+	INIT_LIST_HEAD(&queue->queue);
+
+done:
+	mutex_unlock(&queue->lock);
+}
+
+/**
+ * omap3isp_video_queue_discard_done - Discard all buffers marked as DONE
+ *
+ * This function is intended to be used with suspend/resume operations. It
+ * discards all 'done' buffers as they would be too old to be requested after
+ * resume.
+ *
+ * Drivers must stop the hardware and synchronize with interrupt handlers and/or
+ * delayed works before calling this function to make sure no buffer will be
+ * touched by the driver and/or hardware.
+ */
+void omap3isp_video_queue_discard_done(struct isp_video_queue *queue)
+{
+	struct isp_video_buffer *buf;
+	unsigned int i;
+
+	mutex_lock(&queue->lock);
+
+	if (!queue->streaming)
+		goto done;
+
+	for (i = 0; i < queue->count; ++i) {
+		buf = queue->buffers[i];
+
+		if (buf->state == ISP_BUF_STATE_DONE)
+			buf->state = ISP_BUF_STATE_ERROR;
+	}
+
+done:
+	mutex_unlock(&queue->lock);
+}
+
+static void isp_video_queue_vm_open(struct vm_area_struct *vma)
+{
+	struct isp_video_buffer *buf = vma->vm_private_data;
+
+	buf->vma_use_count++;
+}
+
+static void isp_video_queue_vm_close(struct vm_area_struct *vma)
+{
+	struct isp_video_buffer *buf = vma->vm_private_data;
+
+	buf->vma_use_count--;
+}
+
+static const struct vm_operations_struct isp_video_queue_vm_ops = {
+	.open = isp_video_queue_vm_open,
+	.close = isp_video_queue_vm_close,
+};
+
+/**
+ * omap3isp_video_queue_mmap - Map buffers to userspace
+ *
+ * This function is intended to be used as an mmap() file operation handler. It
+ * maps a buffer to userspace based on the VMA offset.
+ *
+ * Only buffers of memory type MMAP are supported.
+ */
+int omap3isp_video_queue_mmap(struct isp_video_queue *queue,
+			 struct vm_area_struct *vma)
+{
+	struct isp_video_buffer *uninitialized_var(buf);
+	unsigned long size;
+	unsigned int i;
+	int ret = 0;
+
+	mutex_lock(&queue->lock);
+
+	for (i = 0; i < queue->count; ++i) {
+		buf = queue->buffers[i];
+		if ((buf->vbuf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
+			break;
+	}
+
+	if (i == queue->count) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	size = vma->vm_end - vma->vm_start;
+
+	if (buf->vbuf.memory != V4L2_MEMORY_MMAP ||
+	    size != PAGE_ALIGN(buf->vbuf.length)) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = remap_vmalloc_range(vma, buf->vaddr, 0);
+	if (ret < 0)
+		goto done;
+
+	vma->vm_ops = &isp_video_queue_vm_ops;
+	vma->vm_private_data = buf;
+	isp_video_queue_vm_open(vma);
+
+done:
+	mutex_unlock(&queue->lock);
+	return ret;
+}
+
+/**
+ * omap3isp_video_queue_poll - Poll video queue state
+ *
+ * This function is intended to be used as a poll() file operation handler. It
+ * polls the state of the video buffer at the front of the queue and returns an
+ * events mask.
+ *
+ * If no buffer is present at the front of the queue, POLLERR is returned.
+ */
+unsigned int omap3isp_video_queue_poll(struct isp_video_queue *queue,
+				       struct file *file, poll_table *wait)
+{
+	struct isp_video_buffer *buf;
+	unsigned int mask = 0;
+
+	mutex_lock(&queue->lock);
+	if (list_empty(&queue->queue)) {
+		mask |= POLLERR;
+		goto done;
+	}
+	buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream);
+
+	poll_wait(file, &buf->wait, wait);
+	if (buf->state == ISP_BUF_STATE_DONE ||
+	    buf->state == ISP_BUF_STATE_ERROR) {
+		if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			mask |= POLLIN | POLLRDNORM;
+		else
+			mask |= POLLOUT | POLLWRNORM;
+	}
+
+done:
+	mutex_unlock(&queue->lock);
+	return mask;
+}
diff --git a/drivers/media/platform/omap3isp/ispqueue.h b/drivers/media/platform/omap3isp/ispqueue.h
new file mode 100644
index 0000000..908dfd7
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispqueue.h
@@ -0,0 +1,187 @@
+/*
+ * ispqueue.h
+ *
+ * TI OMAP3 ISP - Video buffers queue handling
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_QUEUE_H
+#define OMAP3_ISP_QUEUE_H
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/wait.h>
+
+struct isp_video_queue;
+struct page;
+struct scatterlist;
+
+#define ISP_VIDEO_MAX_BUFFERS		16
+
+/**
+ * enum isp_video_buffer_state - ISP video buffer state
+ * @ISP_BUF_STATE_IDLE:	The buffer is under userspace control (dequeued
+ *	or not queued yet).
+ * @ISP_BUF_STATE_QUEUED: The buffer has been queued but isn't used by the
+ *	device yet.
+ * @ISP_BUF_STATE_ACTIVE: The buffer is in use for an active video transfer.
+ * @ISP_BUF_STATE_ERROR: The device is done with the buffer and an error
+ *	occurred. For capture device the buffer likely contains corrupted data or
+ *	no data at all.
+ * @ISP_BUF_STATE_DONE: The device is done with the buffer and no error occurred.
+ *	For capture devices the buffer contains valid data.
+ */
+enum isp_video_buffer_state {
+	ISP_BUF_STATE_IDLE,
+	ISP_BUF_STATE_QUEUED,
+	ISP_BUF_STATE_ACTIVE,
+	ISP_BUF_STATE_ERROR,
+	ISP_BUF_STATE_DONE,
+};
+
+/**
+ * struct isp_video_buffer - ISP video buffer
+ * @vma_use_count: Number of times the buffer is mmap'ed to userspace
+ * @stream: List head for insertion into main queue
+ * @queue: ISP buffers queue this buffer belongs to
+ * @prepared: Whether the buffer has been prepared
+ * @skip_cache: Whether to skip cache management operations for this buffer
+ * @vaddr: Memory virtual address (for kernel buffers)
+ * @vm_flags: Buffer VMA flags (for userspace buffers)
+ * @offset: Offset inside the first page (for userspace buffers)
+ * @npages: Number of pages (for userspace buffers)
+ * @pages: Pages table (for userspace non-VM_PFNMAP buffers)
+ * @paddr: Memory physical address (for userspace VM_PFNMAP buffers)
+ * @sglen: Number of elements in the scatter list (for non-VM_PFNMAP buffers)
+ * @sglist: Scatter list (for non-VM_PFNMAP buffers)
+ * @vbuf: V4L2 buffer
+ * @irqlist: List head for insertion into IRQ queue
+ * @state: Current buffer state
+ * @wait: Wait queue to signal buffer completion
+ */
+struct isp_video_buffer {
+	unsigned long vma_use_count;
+	struct list_head stream;
+	struct isp_video_queue *queue;
+	unsigned int prepared:1;
+	bool skip_cache;
+
+	/* For kernel buffers. */
+	void *vaddr;
+
+	/* For userspace buffers. */
+	vm_flags_t vm_flags;
+	unsigned long offset;
+	unsigned int npages;
+	struct page **pages;
+	dma_addr_t paddr;
+
+	/* For all buffers except VM_PFNMAP. */
+	unsigned int sglen;
+	struct scatterlist *sglist;
+
+	/* Touched by the interrupt handler. */
+	struct v4l2_buffer vbuf;
+	struct list_head irqlist;
+	enum isp_video_buffer_state state;
+	wait_queue_head_t wait;
+};
+
+#define to_isp_video_buffer(vb)	container_of(vb, struct isp_video_buffer, vb)
+
+/**
+ * struct isp_video_queue_operations - Driver-specific operations
+ * @queue_prepare: Called before allocating buffers. Drivers should clamp the
+ *	number of buffers according to their requirements, and must return the
+ *	buffer size in bytes.
+ * @buffer_prepare: Called the first time a buffer is queued, or after changing
+ *	the userspace memory address for a USERPTR buffer, with the queue lock
+ *	held. Drivers should perform device-specific buffer preparation (such as
+ *	mapping the buffer memory in an IOMMU). This operation is optional.
+ * @buffer_queue: Called when a buffer is being added to the queue with the
+ *	queue irqlock spinlock held.
+ * @buffer_cleanup: Called before freeing buffers, or before changing the
+ *	userspace memory address for a USERPTR buffer, with the queue lock held.
+ *	Drivers must perform cleanup operations required to undo the
+ *	buffer_prepare call. This operation is optional.
+ */
+struct isp_video_queue_operations {
+	void (*queue_prepare)(struct isp_video_queue *queue,
+			      unsigned int *nbuffers, unsigned int *size);
+	int  (*buffer_prepare)(struct isp_video_buffer *buf);
+	void (*buffer_queue)(struct isp_video_buffer *buf);
+	void (*buffer_cleanup)(struct isp_video_buffer *buf);
+};
+
+/**
+ * struct isp_video_queue - ISP video buffers queue
+ * @type: Type of video buffers handled by this queue
+ * @ops: Queue operations
+ * @dev: Device used for DMA operations
+ * @bufsize: Size of a driver-specific buffer object
+ * @count: Number of currently allocated buffers
+ * @buffers: ISP video buffers
+ * @lock: Mutex to protect access to the buffers, main queue and state
+ * @irqlock: Spinlock to protect access to the IRQ queue
+ * @streaming: Queue state, indicates whether the queue is streaming
+ * @queue: List of all queued buffers
+ */
+struct isp_video_queue {
+	enum v4l2_buf_type type;
+	const struct isp_video_queue_operations *ops;
+	struct device *dev;
+	unsigned int bufsize;
+
+	unsigned int count;
+	struct isp_video_buffer *buffers[ISP_VIDEO_MAX_BUFFERS];
+	struct mutex lock;
+	spinlock_t irqlock;
+
+	unsigned int streaming:1;
+
+	struct list_head queue;
+};
+
+int omap3isp_video_queue_cleanup(struct isp_video_queue *queue);
+int omap3isp_video_queue_init(struct isp_video_queue *queue,
+			      enum v4l2_buf_type type,
+			      const struct isp_video_queue_operations *ops,
+			      struct device *dev, unsigned int bufsize);
+
+int omap3isp_video_queue_reqbufs(struct isp_video_queue *queue,
+				 struct v4l2_requestbuffers *rb);
+int omap3isp_video_queue_querybuf(struct isp_video_queue *queue,
+				  struct v4l2_buffer *vbuf);
+int omap3isp_video_queue_qbuf(struct isp_video_queue *queue,
+			      struct v4l2_buffer *vbuf);
+int omap3isp_video_queue_dqbuf(struct isp_video_queue *queue,
+			       struct v4l2_buffer *vbuf, int nonblocking);
+int omap3isp_video_queue_streamon(struct isp_video_queue *queue);
+void omap3isp_video_queue_streamoff(struct isp_video_queue *queue);
+void omap3isp_video_queue_discard_done(struct isp_video_queue *queue);
+int omap3isp_video_queue_mmap(struct isp_video_queue *queue,
+			      struct vm_area_struct *vma);
+unsigned int omap3isp_video_queue_poll(struct isp_video_queue *queue,
+				       struct file *file, poll_table *wait);
+
+#endif /* OMAP3_ISP_QUEUE_H */
diff --git a/drivers/media/platform/omap3isp/ispreg.h b/drivers/media/platform/omap3isp/ispreg.h
new file mode 100644
index 0000000..084ea77
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispreg.h
@@ -0,0 +1,1586 @@
+/*
+ * ispreg.h
+ *
+ * TI OMAP3 ISP - Registers definitions
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_REG_H
+#define OMAP3_ISP_REG_H
+
+#include <plat/omap34xx.h>
+
+
+#define CM_CAM_MCLK_HZ			172800000	/* Hz */
+
+/* ISP Submodules offset */
+
+#define OMAP3ISP_REG_BASE		OMAP3430_ISP_BASE
+#define OMAP3ISP_REG(offset)		(OMAP3ISP_REG_BASE + (offset))
+
+#define OMAP3ISP_CCP2_REG_OFFSET	0x0400
+#define OMAP3ISP_CCP2_REG_BASE		(OMAP3ISP_REG_BASE +		\
+					 OMAP3ISP_CCP2_REG_OFFSET)
+#define OMAP3ISP_CCP2_REG(offset)	(OMAP3ISP_CCP2_REG_BASE + (offset))
+
+#define OMAP3ISP_CCDC_REG_OFFSET	0x0600
+#define OMAP3ISP_CCDC_REG_BASE		(OMAP3ISP_REG_BASE +		\
+					 OMAP3ISP_CCDC_REG_OFFSET)
+#define OMAP3ISP_CCDC_REG(offset)	(OMAP3ISP_CCDC_REG_BASE + (offset))
+
+#define OMAP3ISP_HIST_REG_OFFSET	0x0A00
+#define OMAP3ISP_HIST_REG_BASE		(OMAP3ISP_REG_BASE +		\
+					 OMAP3ISP_HIST_REG_OFFSET)
+#define OMAP3ISP_HIST_REG(offset)	(OMAP3ISP_HIST_REG_BASE + (offset))
+
+#define OMAP3ISP_H3A_REG_OFFSET		0x0C00
+#define OMAP3ISP_H3A_REG_BASE		(OMAP3ISP_REG_BASE +		\
+					 OMAP3ISP_H3A_REG_OFFSET)
+#define OMAP3ISP_H3A_REG(offset)	(OMAP3ISP_H3A_REG_BASE + (offset))
+
+#define OMAP3ISP_PREV_REG_OFFSET	0x0E00
+#define OMAP3ISP_PREV_REG_BASE		(OMAP3ISP_REG_BASE +		\
+					 OMAP3ISP_PREV_REG_OFFSET)
+#define OMAP3ISP_PREV_REG(offset)	(OMAP3ISP_PREV_REG_BASE + (offset))
+
+#define OMAP3ISP_RESZ_REG_OFFSET	0x1000
+#define OMAP3ISP_RESZ_REG_BASE		(OMAP3ISP_REG_BASE +		\
+					 OMAP3ISP_RESZ_REG_OFFSET)
+#define OMAP3ISP_RESZ_REG(offset)	(OMAP3ISP_RESZ_REG_BASE + (offset))
+
+#define OMAP3ISP_SBL_REG_OFFSET		0x1200
+#define OMAP3ISP_SBL_REG_BASE		(OMAP3ISP_REG_BASE +		\
+					 OMAP3ISP_SBL_REG_OFFSET)
+#define OMAP3ISP_SBL_REG(offset)	(OMAP3ISP_SBL_REG_BASE + (offset))
+
+#define OMAP3ISP_CSI2A_REGS1_REG_OFFSET	0x1800
+#define OMAP3ISP_CSI2A_REGS1_REG_BASE	(OMAP3ISP_REG_BASE +		\
+					 OMAP3ISP_CSI2A_REGS1_REG_OFFSET)
+#define OMAP3ISP_CSI2A_REGS1_REG(offset)				\
+				(OMAP3ISP_CSI2A_REGS1_REG_BASE + (offset))
+
+#define OMAP3ISP_CSIPHY2_REG_OFFSET	0x1970
+#define OMAP3ISP_CSIPHY2_REG_BASE	(OMAP3ISP_REG_BASE +	\
+					 OMAP3ISP_CSIPHY2_REG_OFFSET)
+#define OMAP3ISP_CSIPHY2_REG(offset)	(OMAP3ISP_CSIPHY2_REG_BASE + (offset))
+
+#define OMAP3ISP_CSI2A_REGS2_REG_OFFSET	0x19C0
+#define OMAP3ISP_CSI2A_REGS2_REG_BASE	(OMAP3ISP_REG_BASE +		\
+					 OMAP3ISP_CSI2A_REGS2_REG_OFFSET)
+#define OMAP3ISP_CSI2A_REGS2_REG(offset)				\
+				(OMAP3ISP_CSI2A_REGS2_REG_BASE + (offset))
+
+#define OMAP3ISP_CSI2C_REGS1_REG_OFFSET	0x1C00
+#define OMAP3ISP_CSI2C_REGS1_REG_BASE	(OMAP3ISP_REG_BASE +		\
+					 OMAP3ISP_CSI2C_REGS1_REG_OFFSET)
+#define OMAP3ISP_CSI2C_REGS1_REG(offset)				\
+				(OMAP3ISP_CSI2C_REGS1_REG_BASE + (offset))
+
+#define OMAP3ISP_CSIPHY1_REG_OFFSET	0x1D70
+#define OMAP3ISP_CSIPHY1_REG_BASE	(OMAP3ISP_REG_BASE +	\
+					 OMAP3ISP_CSIPHY1_REG_OFFSET)
+#define OMAP3ISP_CSIPHY1_REG(offset)	(OMAP3ISP_CSIPHY1_REG_BASE + (offset))
+
+#define OMAP3ISP_CSI2C_REGS2_REG_OFFSET	0x1DC0
+#define OMAP3ISP_CSI2C_REGS2_REG_BASE	(OMAP3ISP_REG_BASE +		\
+					 OMAP3ISP_CSI2C_REGS2_REG_OFFSET)
+#define OMAP3ISP_CSI2C_REGS2_REG(offset)				\
+				(OMAP3ISP_CSI2C_REGS2_REG_BASE + (offset))
+
+/* ISP module register offset */
+
+#define ISP_REVISION			(0x000)
+#define ISP_SYSCONFIG			(0x004)
+#define ISP_SYSSTATUS			(0x008)
+#define ISP_IRQ0ENABLE			(0x00C)
+#define ISP_IRQ0STATUS			(0x010)
+#define ISP_IRQ1ENABLE			(0x014)
+#define ISP_IRQ1STATUS			(0x018)
+#define ISP_TCTRL_GRESET_LENGTH		(0x030)
+#define ISP_TCTRL_PSTRB_REPLAY		(0x034)
+#define ISP_CTRL			(0x040)
+#define ISP_SECURE			(0x044)
+#define ISP_TCTRL_CTRL			(0x050)
+#define ISP_TCTRL_FRAME			(0x054)
+#define ISP_TCTRL_PSTRB_DELAY		(0x058)
+#define ISP_TCTRL_STRB_DELAY		(0x05C)
+#define ISP_TCTRL_SHUT_DELAY		(0x060)
+#define ISP_TCTRL_PSTRB_LENGTH		(0x064)
+#define ISP_TCTRL_STRB_LENGTH		(0x068)
+#define ISP_TCTRL_SHUT_LENGTH		(0x06C)
+#define ISP_PING_PONG_ADDR		(0x070)
+#define ISP_PING_PONG_MEM_RANGE		(0x074)
+#define ISP_PING_PONG_BUF_SIZE		(0x078)
+
+/* CCP2 receiver registers */
+
+#define ISPCCP2_REVISION		(0x000)
+#define ISPCCP2_SYSCONFIG		(0x004)
+#define ISPCCP2_SYSCONFIG_SOFT_RESET	(1 << 1)
+#define ISPCCP2_SYSCONFIG_AUTO_IDLE		0x1
+#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT	12
+#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_FORCE	\
+	(0x0 << ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
+#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_NO	\
+	(0x1 << ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
+#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SMART	\
+	(0x2 << ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
+#define ISPCCP2_SYSSTATUS		(0x008)
+#define ISPCCP2_SYSSTATUS_RESET_DONE	(1 << 0)
+#define ISPCCP2_LC01_IRQENABLE		(0x00C)
+#define ISPCCP2_LC01_IRQSTATUS		(0x010)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ	(1 << 11)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_LE_IRQ	(1 << 10)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_LS_IRQ	(1 << 9)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FE_IRQ	(1 << 8)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_COUNT_IRQ	(1 << 7)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ	(1 << 5)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ	(1 << 4)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ	(1 << 3)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ	(1 << 2)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ	(1 << 1)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ	(1 << 0)
+
+#define ISPCCP2_LC23_IRQENABLE		(0x014)
+#define ISPCCP2_LC23_IRQSTATUS		(0x018)
+#define ISPCCP2_LCM_IRQENABLE		(0x02C)
+#define ISPCCP2_LCM_IRQSTATUS_EOF_IRQ		(1 << 0)
+#define ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ	(1 << 1)
+#define ISPCCP2_LCM_IRQSTATUS		(0x030)
+#define ISPCCP2_CTRL			(0x040)
+#define ISPCCP2_CTRL_IF_EN		(1 << 0)
+#define ISPCCP2_CTRL_PHY_SEL		(1 << 1)
+#define ISPCCP2_CTRL_PHY_SEL_CLOCK	(0 << 1)
+#define ISPCCP2_CTRL_PHY_SEL_STROBE	(1 << 1)
+#define ISPCCP2_CTRL_PHY_SEL_MASK	0x1
+#define ISPCCP2_CTRL_PHY_SEL_SHIFT	1
+#define ISPCCP2_CTRL_IO_OUT_SEL		(1 << 2)
+#define ISPCCP2_CTRL_MODE		(1 << 4)
+#define ISPCCP2_CTRL_VP_CLK_FORCE_ON	(1 << 9)
+#define ISPCCP2_CTRL_INV		(1 << 10)
+#define ISPCCP2_CTRL_INV_MASK		0x1
+#define ISPCCP2_CTRL_INV_SHIFT		10
+#define ISPCCP2_CTRL_VP_ONLY_EN		(1 << 11)
+#define ISPCCP2_CTRL_VP_CLK_POL		(1 << 12)
+#define ISPCCP2_CTRL_VPCLK_DIV_SHIFT	15
+#define ISPCCP2_CTRL_VPCLK_DIV_MASK	0x1ffff /* [31:15] */
+#define ISPCCP2_CTRL_VP_OUT_CTRL_SHIFT	8 /* 3430 bits */
+#define ISPCCP2_CTRL_VP_OUT_CTRL_MASK	0x3 /* 3430 bits */
+#define ISPCCP2_DBG			(0x044)
+#define ISPCCP2_GNQ			(0x048)
+#define ISPCCP2_LCx_CTRL(x)			((0x050)+0x30*(x))
+#define ISPCCP2_LCx_CTRL_CHAN_EN		(1 << 0)
+#define ISPCCP2_LCx_CTRL_CRC_EN			(1 << 19)
+#define ISPCCP2_LCx_CTRL_CRC_MASK		0x1
+#define ISPCCP2_LCx_CTRL_CRC_SHIFT		2
+#define ISPCCP2_LCx_CTRL_CRC_SHIFT_15_0		19
+#define ISPCCP2_LCx_CTRL_REGION_EN		(1 << 1)
+#define ISPCCP2_LCx_CTRL_REGION_MASK		0x1
+#define ISPCCP2_LCx_CTRL_REGION_SHIFT		1
+#define ISPCCP2_LCx_CTRL_FORMAT_MASK_15_0	0x3f
+#define ISPCCP2_LCx_CTRL_FORMAT_SHIFT_15_0	0x2
+#define ISPCCP2_LCx_CTRL_FORMAT_MASK		0x1f
+#define ISPCCP2_LCx_CTRL_FORMAT_SHIFT		0x3
+#define ISPCCP2_LCx_CODE(x)		((0x054)+0x30*(x))
+#define ISPCCP2_LCx_STAT_START(x)	((0x058)+0x30*(x))
+#define ISPCCP2_LCx_STAT_SIZE(x)	((0x05C)+0x30*(x))
+#define ISPCCP2_LCx_SOF_ADDR(x)		((0x060)+0x30*(x))
+#define ISPCCP2_LCx_EOF_ADDR(x)		((0x064)+0x30*(x))
+#define ISPCCP2_LCx_DAT_START(x)	((0x068)+0x30*(x))
+#define ISPCCP2_LCx_DAT_SIZE(x)		((0x06C)+0x30*(x))
+#define ISPCCP2_LCx_DAT_MASK		0xFFF
+#define ISPCCP2_LCx_DAT_SHIFT		16
+#define ISPCCP2_LCx_DAT_PING_ADDR(x)	((0x070)+0x30*(x))
+#define ISPCCP2_LCx_DAT_PONG_ADDR(x)	((0x074)+0x30*(x))
+#define ISPCCP2_LCx_DAT_OFST(x)		((0x078)+0x30*(x))
+#define ISPCCP2_LCM_CTRL		(0x1D0)
+#define ISPCCP2_LCM_CTRL_CHAN_EN               (1 << 0)
+#define ISPCCP2_LCM_CTRL_DST_PORT              (1 << 2)
+#define ISPCCP2_LCM_CTRL_DST_PORT_SHIFT		2
+#define ISPCCP2_LCM_CTRL_READ_THROTTLE_SHIFT	3
+#define ISPCCP2_LCM_CTRL_READ_THROTTLE_MASK	0x11
+#define ISPCCP2_LCM_CTRL_BURST_SIZE_SHIFT	5
+#define ISPCCP2_LCM_CTRL_BURST_SIZE_MASK	0x7
+#define ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT	16
+#define ISPCCP2_LCM_CTRL_SRC_FORMAT_MASK	0x7
+#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_SHIFT	20
+#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_MASK	0x3
+#define ISPCCP2_LCM_CTRL_SRC_DPCM_PRED		(1 << 22)
+#define ISPCCP2_LCM_CTRL_SRC_PACK		(1 << 23)
+#define ISPCCP2_LCM_CTRL_DST_FORMAT_SHIFT	24
+#define ISPCCP2_LCM_CTRL_DST_FORMAT_MASK	0x7
+#define ISPCCP2_LCM_VSIZE		(0x1D4)
+#define ISPCCP2_LCM_VSIZE_SHIFT		16
+#define ISPCCP2_LCM_HSIZE		(0x1D8)
+#define ISPCCP2_LCM_HSIZE_SHIFT		16
+#define ISPCCP2_LCM_PREFETCH		(0x1DC)
+#define ISPCCP2_LCM_PREFETCH_SHIFT	3
+#define ISPCCP2_LCM_SRC_ADDR		(0x1E0)
+#define ISPCCP2_LCM_SRC_OFST		(0x1E4)
+#define ISPCCP2_LCM_DST_ADDR		(0x1E8)
+#define ISPCCP2_LCM_DST_OFST		(0x1EC)
+
+/* CCDC module register offset */
+
+#define ISPCCDC_PID			(0x000)
+#define ISPCCDC_PCR			(0x004)
+#define ISPCCDC_SYN_MODE		(0x008)
+#define ISPCCDC_HD_VD_WID		(0x00C)
+#define ISPCCDC_PIX_LINES		(0x010)
+#define ISPCCDC_HORZ_INFO		(0x014)
+#define ISPCCDC_VERT_START		(0x018)
+#define ISPCCDC_VERT_LINES		(0x01C)
+#define ISPCCDC_CULLING			(0x020)
+#define ISPCCDC_HSIZE_OFF		(0x024)
+#define ISPCCDC_SDOFST			(0x028)
+#define ISPCCDC_SDR_ADDR		(0x02C)
+#define ISPCCDC_CLAMP			(0x030)
+#define ISPCCDC_DCSUB			(0x034)
+#define ISPCCDC_COLPTN			(0x038)
+#define ISPCCDC_BLKCMP			(0x03C)
+#define ISPCCDC_FPC			(0x040)
+#define ISPCCDC_FPC_ADDR		(0x044)
+#define ISPCCDC_VDINT			(0x048)
+#define ISPCCDC_ALAW			(0x04C)
+#define ISPCCDC_REC656IF		(0x050)
+#define ISPCCDC_CFG			(0x054)
+#define ISPCCDC_FMTCFG			(0x058)
+#define ISPCCDC_FMT_HORZ		(0x05C)
+#define ISPCCDC_FMT_VERT		(0x060)
+#define ISPCCDC_FMT_ADDR0		(0x064)
+#define ISPCCDC_FMT_ADDR1		(0x068)
+#define ISPCCDC_FMT_ADDR2		(0x06C)
+#define ISPCCDC_FMT_ADDR3		(0x070)
+#define ISPCCDC_FMT_ADDR4		(0x074)
+#define ISPCCDC_FMT_ADDR5		(0x078)
+#define ISPCCDC_FMT_ADDR6		(0x07C)
+#define ISPCCDC_FMT_ADDR7		(0x080)
+#define ISPCCDC_PRGEVEN0		(0x084)
+#define ISPCCDC_PRGEVEN1		(0x088)
+#define ISPCCDC_PRGODD0			(0x08C)
+#define ISPCCDC_PRGODD1			(0x090)
+#define ISPCCDC_VP_OUT			(0x094)
+
+#define ISPCCDC_LSC_CONFIG		(0x098)
+#define ISPCCDC_LSC_INITIAL		(0x09C)
+#define ISPCCDC_LSC_TABLE_BASE		(0x0A0)
+#define ISPCCDC_LSC_TABLE_OFFSET	(0x0A4)
+
+/* SBL */
+#define ISPSBL_PCR			0x4
+#define ISPSBL_PCR_H3A_AEAWB_WBL_OVF	(1 << 16)
+#define ISPSBL_PCR_H3A_AF_WBL_OVF	(1 << 17)
+#define ISPSBL_PCR_RSZ4_WBL_OVF		(1 << 18)
+#define ISPSBL_PCR_RSZ3_WBL_OVF		(1 << 19)
+#define ISPSBL_PCR_RSZ2_WBL_OVF		(1 << 20)
+#define ISPSBL_PCR_RSZ1_WBL_OVF		(1 << 21)
+#define ISPSBL_PCR_PRV_WBL_OVF		(1 << 22)
+#define ISPSBL_PCR_CCDC_WBL_OVF		(1 << 23)
+#define ISPSBL_PCR_CCDCPRV_2_RSZ_OVF	(1 << 24)
+#define ISPSBL_PCR_CSIA_WBL_OVF		(1 << 25)
+#define ISPSBL_PCR_CSIB_WBL_OVF		(1 << 26)
+#define ISPSBL_CCDC_WR_0		(0x028)
+#define ISPSBL_CCDC_WR_0_DATA_READY	(1 << 21)
+#define ISPSBL_CCDC_WR_1		(0x02C)
+#define ISPSBL_CCDC_WR_2		(0x030)
+#define ISPSBL_CCDC_WR_3		(0x034)
+
+#define ISPSBL_SDR_REQ_EXP		0xF8
+#define ISPSBL_SDR_REQ_HIST_EXP_SHIFT	0
+#define ISPSBL_SDR_REQ_HIST_EXP_MASK	(0x3FF)
+#define ISPSBL_SDR_REQ_RSZ_EXP_SHIFT	10
+#define ISPSBL_SDR_REQ_RSZ_EXP_MASK	(0x3FF << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT)
+#define ISPSBL_SDR_REQ_PRV_EXP_SHIFT	20
+#define ISPSBL_SDR_REQ_PRV_EXP_MASK	(0x3FF << ISPSBL_SDR_REQ_PRV_EXP_SHIFT)
+
+/* Histogram registers */
+#define ISPHIST_PID			(0x000)
+#define ISPHIST_PCR			(0x004)
+#define ISPHIST_CNT			(0x008)
+#define ISPHIST_WB_GAIN			(0x00C)
+#define ISPHIST_R0_HORZ			(0x010)
+#define ISPHIST_R0_VERT			(0x014)
+#define ISPHIST_R1_HORZ			(0x018)
+#define ISPHIST_R1_VERT			(0x01C)
+#define ISPHIST_R2_HORZ			(0x020)
+#define ISPHIST_R2_VERT			(0x024)
+#define ISPHIST_R3_HORZ			(0x028)
+#define ISPHIST_R3_VERT			(0x02C)
+#define ISPHIST_ADDR			(0x030)
+#define ISPHIST_DATA			(0x034)
+#define ISPHIST_RADD			(0x038)
+#define ISPHIST_RADD_OFF		(0x03C)
+#define ISPHIST_H_V_INFO		(0x040)
+
+/* H3A module registers */
+#define ISPH3A_PID			(0x000)
+#define ISPH3A_PCR			(0x004)
+#define ISPH3A_AEWWIN1			(0x04C)
+#define ISPH3A_AEWINSTART		(0x050)
+#define ISPH3A_AEWINBLK			(0x054)
+#define ISPH3A_AEWSUBWIN		(0x058)
+#define ISPH3A_AEWBUFST			(0x05C)
+#define ISPH3A_AFPAX1			(0x008)
+#define ISPH3A_AFPAX2			(0x00C)
+#define ISPH3A_AFPAXSTART		(0x010)
+#define ISPH3A_AFIIRSH			(0x014)
+#define ISPH3A_AFBUFST			(0x018)
+#define ISPH3A_AFCOEF010		(0x01C)
+#define ISPH3A_AFCOEF032		(0x020)
+#define ISPH3A_AFCOEF054		(0x024)
+#define ISPH3A_AFCOEF076		(0x028)
+#define ISPH3A_AFCOEF098		(0x02C)
+#define ISPH3A_AFCOEF0010		(0x030)
+#define ISPH3A_AFCOEF110		(0x034)
+#define ISPH3A_AFCOEF132		(0x038)
+#define ISPH3A_AFCOEF154		(0x03C)
+#define ISPH3A_AFCOEF176		(0x040)
+#define ISPH3A_AFCOEF198		(0x044)
+#define ISPH3A_AFCOEF1010		(0x048)
+
+#define ISPPRV_PCR			(0x004)
+#define ISPPRV_HORZ_INFO		(0x008)
+#define ISPPRV_VERT_INFO		(0x00C)
+#define ISPPRV_RSDR_ADDR		(0x010)
+#define ISPPRV_RADR_OFFSET		(0x014)
+#define ISPPRV_DSDR_ADDR		(0x018)
+#define ISPPRV_DRKF_OFFSET		(0x01C)
+#define ISPPRV_WSDR_ADDR		(0x020)
+#define ISPPRV_WADD_OFFSET		(0x024)
+#define ISPPRV_AVE			(0x028)
+#define ISPPRV_HMED			(0x02C)
+#define ISPPRV_NF			(0x030)
+#define ISPPRV_WB_DGAIN			(0x034)
+#define ISPPRV_WBGAIN			(0x038)
+#define ISPPRV_WBSEL			(0x03C)
+#define ISPPRV_CFA			(0x040)
+#define ISPPRV_BLKADJOFF		(0x044)
+#define ISPPRV_RGB_MAT1			(0x048)
+#define ISPPRV_RGB_MAT2			(0x04C)
+#define ISPPRV_RGB_MAT3			(0x050)
+#define ISPPRV_RGB_MAT4			(0x054)
+#define ISPPRV_RGB_MAT5			(0x058)
+#define ISPPRV_RGB_OFF1			(0x05C)
+#define ISPPRV_RGB_OFF2			(0x060)
+#define ISPPRV_CSC0			(0x064)
+#define ISPPRV_CSC1			(0x068)
+#define ISPPRV_CSC2			(0x06C)
+#define ISPPRV_CSC_OFFSET		(0x070)
+#define ISPPRV_CNT_BRT			(0x074)
+#define ISPPRV_CSUP			(0x078)
+#define ISPPRV_SETUP_YC			(0x07C)
+#define ISPPRV_SET_TBL_ADDR		(0x080)
+#define ISPPRV_SET_TBL_DATA		(0x084)
+#define ISPPRV_CDC_THR0			(0x090)
+#define ISPPRV_CDC_THR1			(ISPPRV_CDC_THR0 + (0x4))
+#define ISPPRV_CDC_THR2			(ISPPRV_CDC_THR0 + (0x4) * 2)
+#define ISPPRV_CDC_THR3			(ISPPRV_CDC_THR0 + (0x4) * 3)
+
+#define ISPPRV_REDGAMMA_TABLE_ADDR	0x0000
+#define ISPPRV_GREENGAMMA_TABLE_ADDR	0x0400
+#define ISPPRV_BLUEGAMMA_TABLE_ADDR	0x0800
+#define ISPPRV_NF_TABLE_ADDR		0x0C00
+#define ISPPRV_YENH_TABLE_ADDR		0x1000
+#define ISPPRV_CFA_TABLE_ADDR		0x1400
+
+#define ISPRSZ_MIN_OUTPUT		64
+#define ISPRSZ_MAX_OUTPUT		3312
+
+/* Resizer module register offset */
+#define ISPRSZ_PID			(0x000)
+#define ISPRSZ_PCR			(0x004)
+#define ISPRSZ_CNT			(0x008)
+#define ISPRSZ_OUT_SIZE			(0x00C)
+#define ISPRSZ_IN_START			(0x010)
+#define ISPRSZ_IN_SIZE			(0x014)
+#define ISPRSZ_SDR_INADD		(0x018)
+#define ISPRSZ_SDR_INOFF		(0x01C)
+#define ISPRSZ_SDR_OUTADD		(0x020)
+#define ISPRSZ_SDR_OUTOFF		(0x024)
+#define ISPRSZ_HFILT10			(0x028)
+#define ISPRSZ_HFILT32			(0x02C)
+#define ISPRSZ_HFILT54			(0x030)
+#define ISPRSZ_HFILT76			(0x034)
+#define ISPRSZ_HFILT98			(0x038)
+#define ISPRSZ_HFILT1110		(0x03C)
+#define ISPRSZ_HFILT1312		(0x040)
+#define ISPRSZ_HFILT1514		(0x044)
+#define ISPRSZ_HFILT1716		(0x048)
+#define ISPRSZ_HFILT1918		(0x04C)
+#define ISPRSZ_HFILT2120		(0x050)
+#define ISPRSZ_HFILT2322		(0x054)
+#define ISPRSZ_HFILT2524		(0x058)
+#define ISPRSZ_HFILT2726		(0x05C)
+#define ISPRSZ_HFILT2928		(0x060)
+#define ISPRSZ_HFILT3130		(0x064)
+#define ISPRSZ_VFILT10			(0x068)
+#define ISPRSZ_VFILT32			(0x06C)
+#define ISPRSZ_VFILT54			(0x070)
+#define ISPRSZ_VFILT76			(0x074)
+#define ISPRSZ_VFILT98			(0x078)
+#define ISPRSZ_VFILT1110		(0x07C)
+#define ISPRSZ_VFILT1312		(0x080)
+#define ISPRSZ_VFILT1514		(0x084)
+#define ISPRSZ_VFILT1716		(0x088)
+#define ISPRSZ_VFILT1918		(0x08C)
+#define ISPRSZ_VFILT2120		(0x090)
+#define ISPRSZ_VFILT2322		(0x094)
+#define ISPRSZ_VFILT2524		(0x098)
+#define ISPRSZ_VFILT2726		(0x09C)
+#define ISPRSZ_VFILT2928		(0x0A0)
+#define ISPRSZ_VFILT3130		(0x0A4)
+#define ISPRSZ_YENH			(0x0A8)
+
+#define ISP_INT_CLR			0xFF113F11
+#define ISPPRV_PCR_EN			1
+#define ISPPRV_PCR_BUSY			(1 << 1)
+#define ISPPRV_PCR_SOURCE		(1 << 2)
+#define ISPPRV_PCR_ONESHOT		(1 << 3)
+#define ISPPRV_PCR_WIDTH		(1 << 4)
+#define ISPPRV_PCR_INVALAW		(1 << 5)
+#define ISPPRV_PCR_DRKFEN		(1 << 6)
+#define ISPPRV_PCR_DRKFCAP		(1 << 7)
+#define ISPPRV_PCR_HMEDEN		(1 << 8)
+#define ISPPRV_PCR_NFEN			(1 << 9)
+#define ISPPRV_PCR_CFAEN		(1 << 10)
+#define ISPPRV_PCR_CFAFMT_SHIFT		11
+#define ISPPRV_PCR_CFAFMT_MASK		0x7800
+#define ISPPRV_PCR_CFAFMT_BAYER		(0 << 11)
+#define ISPPRV_PCR_CFAFMT_SONYVGA	(1 << 11)
+#define ISPPRV_PCR_CFAFMT_RGBFOVEON	(2 << 11)
+#define ISPPRV_PCR_CFAFMT_DNSPL		(3 << 11)
+#define ISPPRV_PCR_CFAFMT_HONEYCOMB	(4 << 11)
+#define ISPPRV_PCR_CFAFMT_RRGGBBFOVEON	(5 << 11)
+#define ISPPRV_PCR_YNENHEN		(1 << 15)
+#define ISPPRV_PCR_SUPEN		(1 << 16)
+#define ISPPRV_PCR_YCPOS_SHIFT		17
+#define ISPPRV_PCR_YCPOS_YCrYCb		(0 << 17)
+#define ISPPRV_PCR_YCPOS_YCbYCr		(1 << 17)
+#define ISPPRV_PCR_YCPOS_CbYCrY		(2 << 17)
+#define ISPPRV_PCR_YCPOS_CrYCbY		(3 << 17)
+#define ISPPRV_PCR_RSZPORT		(1 << 19)
+#define ISPPRV_PCR_SDRPORT		(1 << 20)
+#define ISPPRV_PCR_SCOMP_EN		(1 << 21)
+#define ISPPRV_PCR_SCOMP_SFT_SHIFT	(22)
+#define ISPPRV_PCR_SCOMP_SFT_MASK	(7 << 22)
+#define ISPPRV_PCR_GAMMA_BYPASS		(1 << 26)
+#define ISPPRV_PCR_DCOREN		(1 << 27)
+#define ISPPRV_PCR_DCCOUP		(1 << 28)
+#define ISPPRV_PCR_DRK_FAIL		(1 << 31)
+
+#define ISPPRV_HORZ_INFO_EPH_SHIFT	0
+#define ISPPRV_HORZ_INFO_EPH_MASK	0x3fff
+#define ISPPRV_HORZ_INFO_SPH_SHIFT	16
+#define ISPPRV_HORZ_INFO_SPH_MASK	0x3fff0
+
+#define ISPPRV_VERT_INFO_ELV_SHIFT	0
+#define ISPPRV_VERT_INFO_ELV_MASK	0x3fff
+#define ISPPRV_VERT_INFO_SLV_SHIFT	16
+#define ISPPRV_VERT_INFO_SLV_MASK	0x3fff0
+
+#define ISPPRV_AVE_EVENDIST_SHIFT	2
+#define ISPPRV_AVE_EVENDIST_1		0x0
+#define ISPPRV_AVE_EVENDIST_2		0x1
+#define ISPPRV_AVE_EVENDIST_3		0x2
+#define ISPPRV_AVE_EVENDIST_4		0x3
+#define ISPPRV_AVE_ODDDIST_SHIFT	4
+#define ISPPRV_AVE_ODDDIST_1		0x0
+#define ISPPRV_AVE_ODDDIST_2		0x1
+#define ISPPRV_AVE_ODDDIST_3		0x2
+#define ISPPRV_AVE_ODDDIST_4		0x3
+
+#define ISPPRV_HMED_THRESHOLD_SHIFT	0
+#define ISPPRV_HMED_EVENDIST		(1 << 8)
+#define ISPPRV_HMED_ODDDIST		(1 << 9)
+
+#define ISPPRV_WBGAIN_COEF0_SHIFT	0
+#define ISPPRV_WBGAIN_COEF1_SHIFT	8
+#define ISPPRV_WBGAIN_COEF2_SHIFT	16
+#define ISPPRV_WBGAIN_COEF3_SHIFT	24
+
+#define ISPPRV_WBSEL_COEF0		0x0
+#define ISPPRV_WBSEL_COEF1		0x1
+#define ISPPRV_WBSEL_COEF2		0x2
+#define ISPPRV_WBSEL_COEF3		0x3
+
+#define ISPPRV_WBSEL_N0_0_SHIFT		0
+#define ISPPRV_WBSEL_N0_1_SHIFT		2
+#define ISPPRV_WBSEL_N0_2_SHIFT		4
+#define ISPPRV_WBSEL_N0_3_SHIFT		6
+#define ISPPRV_WBSEL_N1_0_SHIFT		8
+#define ISPPRV_WBSEL_N1_1_SHIFT		10
+#define ISPPRV_WBSEL_N1_2_SHIFT		12
+#define ISPPRV_WBSEL_N1_3_SHIFT		14
+#define ISPPRV_WBSEL_N2_0_SHIFT		16
+#define ISPPRV_WBSEL_N2_1_SHIFT		18
+#define ISPPRV_WBSEL_N2_2_SHIFT		20
+#define ISPPRV_WBSEL_N2_3_SHIFT		22
+#define ISPPRV_WBSEL_N3_0_SHIFT		24
+#define ISPPRV_WBSEL_N3_1_SHIFT		26
+#define ISPPRV_WBSEL_N3_2_SHIFT		28
+#define ISPPRV_WBSEL_N3_3_SHIFT		30
+
+#define ISPPRV_CFA_GRADTH_HOR_SHIFT	0
+#define ISPPRV_CFA_GRADTH_VER_SHIFT	8
+
+#define ISPPRV_BLKADJOFF_B_SHIFT	0
+#define ISPPRV_BLKADJOFF_G_SHIFT	8
+#define ISPPRV_BLKADJOFF_R_SHIFT	16
+
+#define ISPPRV_RGB_MAT1_MTX_RR_SHIFT	0
+#define ISPPRV_RGB_MAT1_MTX_GR_SHIFT	16
+
+#define ISPPRV_RGB_MAT2_MTX_BR_SHIFT	0
+#define ISPPRV_RGB_MAT2_MTX_RG_SHIFT	16
+
+#define ISPPRV_RGB_MAT3_MTX_GG_SHIFT	0
+#define ISPPRV_RGB_MAT3_MTX_BG_SHIFT	16
+
+#define ISPPRV_RGB_MAT4_MTX_RB_SHIFT	0
+#define ISPPRV_RGB_MAT4_MTX_GB_SHIFT	16
+
+#define ISPPRV_RGB_MAT5_MTX_BB_SHIFT	0
+
+#define ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT	0
+#define ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT	16
+
+#define ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT	0
+
+#define ISPPRV_CSC0_RY_SHIFT		0
+#define ISPPRV_CSC0_GY_SHIFT		10
+#define ISPPRV_CSC0_BY_SHIFT		20
+
+#define ISPPRV_CSC1_RCB_SHIFT		0
+#define ISPPRV_CSC1_GCB_SHIFT		10
+#define ISPPRV_CSC1_BCB_SHIFT		20
+
+#define ISPPRV_CSC2_RCR_SHIFT		0
+#define ISPPRV_CSC2_GCR_SHIFT		10
+#define ISPPRV_CSC2_BCR_SHIFT		20
+
+#define ISPPRV_CSC_OFFSET_CR_SHIFT	0
+#define ISPPRV_CSC_OFFSET_CB_SHIFT	8
+#define ISPPRV_CSC_OFFSET_Y_SHIFT	16
+
+#define ISPPRV_CNT_BRT_BRT_SHIFT	0
+#define ISPPRV_CNT_BRT_CNT_SHIFT	8
+
+#define ISPPRV_CONTRAST_MAX		0x10
+#define ISPPRV_CONTRAST_MIN		0xFF
+#define ISPPRV_BRIGHT_MIN		0x00
+#define ISPPRV_BRIGHT_MAX		0xFF
+
+#define ISPPRV_CSUP_CSUPG_SHIFT		0
+#define ISPPRV_CSUP_THRES_SHIFT		8
+#define ISPPRV_CSUP_HPYF_SHIFT		16
+
+#define ISPPRV_SETUP_YC_MINC_SHIFT	0
+#define ISPPRV_SETUP_YC_MAXC_SHIFT	8
+#define ISPPRV_SETUP_YC_MINY_SHIFT	16
+#define ISPPRV_SETUP_YC_MAXY_SHIFT	24
+#define ISPPRV_YC_MAX			0xFF
+#define ISPPRV_YC_MIN			0x0
+
+/* Define bit fields within selected registers */
+#define ISP_REVISION_SHIFT			0
+
+#define ISP_SYSCONFIG_AUTOIDLE			(1 << 0)
+#define ISP_SYSCONFIG_SOFTRESET			(1 << 1)
+#define ISP_SYSCONFIG_MIDLEMODE_SHIFT		12
+#define ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY	0x0
+#define ISP_SYSCONFIG_MIDLEMODE_NOSTANBY	0x1
+#define ISP_SYSCONFIG_MIDLEMODE_SMARTSTANDBY	0x2
+
+#define ISP_SYSSTATUS_RESETDONE			0
+
+#define IRQ0ENABLE_CSIA_IRQ			(1 << 0)
+#define IRQ0ENABLE_CSIC_IRQ			(1 << 1)
+#define IRQ0ENABLE_CCP2_LCM_IRQ			(1 << 3)
+#define IRQ0ENABLE_CCP2_LC0_IRQ			(1 << 4)
+#define IRQ0ENABLE_CCP2_LC1_IRQ			(1 << 5)
+#define IRQ0ENABLE_CCP2_LC2_IRQ			(1 << 6)
+#define IRQ0ENABLE_CCP2_LC3_IRQ			(1 << 7)
+#define IRQ0ENABLE_CSIB_IRQ			(IRQ0ENABLE_CCP2_LCM_IRQ | \
+						IRQ0ENABLE_CCP2_LC0_IRQ | \
+						IRQ0ENABLE_CCP2_LC1_IRQ | \
+						IRQ0ENABLE_CCP2_LC2_IRQ | \
+						IRQ0ENABLE_CCP2_LC3_IRQ)
+
+#define IRQ0ENABLE_CCDC_VD0_IRQ			(1 << 8)
+#define IRQ0ENABLE_CCDC_VD1_IRQ			(1 << 9)
+#define IRQ0ENABLE_CCDC_VD2_IRQ			(1 << 10)
+#define IRQ0ENABLE_CCDC_ERR_IRQ			(1 << 11)
+#define IRQ0ENABLE_H3A_AF_DONE_IRQ		(1 << 12)
+#define IRQ0ENABLE_H3A_AWB_DONE_IRQ		(1 << 13)
+#define IRQ0ENABLE_HIST_DONE_IRQ		(1 << 16)
+#define IRQ0ENABLE_CCDC_LSC_DONE_IRQ		(1 << 17)
+#define IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ	(1 << 18)
+#define IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ	(1 << 19)
+#define IRQ0ENABLE_PRV_DONE_IRQ			(1 << 20)
+#define IRQ0ENABLE_RSZ_DONE_IRQ			(1 << 24)
+#define IRQ0ENABLE_OVF_IRQ			(1 << 25)
+#define IRQ0ENABLE_PING_IRQ			(1 << 26)
+#define IRQ0ENABLE_PONG_IRQ			(1 << 27)
+#define IRQ0ENABLE_MMU_ERR_IRQ			(1 << 28)
+#define IRQ0ENABLE_OCP_ERR_IRQ			(1 << 29)
+#define IRQ0ENABLE_SEC_ERR_IRQ			(1 << 30)
+#define IRQ0ENABLE_HS_VS_IRQ			(1 << 31)
+
+#define IRQ0STATUS_CSIA_IRQ			(1 << 0)
+#define IRQ0STATUS_CSI2C_IRQ			(1 << 1)
+#define IRQ0STATUS_CCP2_LCM_IRQ			(1 << 3)
+#define IRQ0STATUS_CCP2_LC0_IRQ			(1 << 4)
+#define IRQ0STATUS_CSIB_IRQ			(IRQ0STATUS_CCP2_LCM_IRQ | \
+						IRQ0STATUS_CCP2_LC0_IRQ)
+
+#define IRQ0STATUS_CSIB_LC1_IRQ			(1 << 5)
+#define IRQ0STATUS_CSIB_LC2_IRQ			(1 << 6)
+#define IRQ0STATUS_CSIB_LC3_IRQ			(1 << 7)
+#define IRQ0STATUS_CCDC_VD0_IRQ			(1 << 8)
+#define IRQ0STATUS_CCDC_VD1_IRQ			(1 << 9)
+#define IRQ0STATUS_CCDC_VD2_IRQ			(1 << 10)
+#define IRQ0STATUS_CCDC_ERR_IRQ			(1 << 11)
+#define IRQ0STATUS_H3A_AF_DONE_IRQ		(1 << 12)
+#define IRQ0STATUS_H3A_AWB_DONE_IRQ		(1 << 13)
+#define IRQ0STATUS_HIST_DONE_IRQ		(1 << 16)
+#define IRQ0STATUS_CCDC_LSC_DONE_IRQ		(1 << 17)
+#define IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ	(1 << 18)
+#define IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ	(1 << 19)
+#define IRQ0STATUS_PRV_DONE_IRQ			(1 << 20)
+#define IRQ0STATUS_RSZ_DONE_IRQ			(1 << 24)
+#define IRQ0STATUS_OVF_IRQ			(1 << 25)
+#define IRQ0STATUS_PING_IRQ			(1 << 26)
+#define IRQ0STATUS_PONG_IRQ			(1 << 27)
+#define IRQ0STATUS_MMU_ERR_IRQ			(1 << 28)
+#define IRQ0STATUS_OCP_ERR_IRQ			(1 << 29)
+#define IRQ0STATUS_SEC_ERR_IRQ			(1 << 30)
+#define IRQ0STATUS_HS_VS_IRQ			(1 << 31)
+
+#define TCTRL_GRESET_LEN			0
+
+#define TCTRL_PSTRB_REPLAY_DELAY		0
+#define TCTRL_PSTRB_REPLAY_COUNTER_SHIFT	25
+
+#define ISPCTRL_PAR_SER_CLK_SEL_PARALLEL	0x0
+#define ISPCTRL_PAR_SER_CLK_SEL_CSIA		0x1
+#define ISPCTRL_PAR_SER_CLK_SEL_CSIB		0x2
+#define ISPCTRL_PAR_SER_CLK_SEL_CSIC		0x3
+#define ISPCTRL_PAR_SER_CLK_SEL_MASK		0x3
+
+#define ISPCTRL_PAR_BRIDGE_SHIFT		2
+#define ISPCTRL_PAR_BRIDGE_DISABLE		(0x0 << 2)
+#define ISPCTRL_PAR_BRIDGE_LENDIAN		(0x2 << 2)
+#define ISPCTRL_PAR_BRIDGE_BENDIAN		(0x3 << 2)
+#define ISPCTRL_PAR_BRIDGE_MASK			(0x3 << 2)
+
+#define ISPCTRL_PAR_CLK_POL_SHIFT		4
+#define ISPCTRL_PAR_CLK_POL_INV			(1 << 4)
+#define ISPCTRL_PING_PONG_EN			(1 << 5)
+#define ISPCTRL_SHIFT_SHIFT			6
+#define ISPCTRL_SHIFT_0				(0x0 << 6)
+#define ISPCTRL_SHIFT_2				(0x1 << 6)
+#define ISPCTRL_SHIFT_4				(0x2 << 6)
+#define ISPCTRL_SHIFT_MASK			(0x3 << 6)
+
+#define ISPCTRL_CCDC_CLK_EN			(1 << 8)
+#define ISPCTRL_SCMP_CLK_EN			(1 << 9)
+#define ISPCTRL_H3A_CLK_EN			(1 << 10)
+#define ISPCTRL_HIST_CLK_EN			(1 << 11)
+#define ISPCTRL_PREV_CLK_EN			(1 << 12)
+#define ISPCTRL_RSZ_CLK_EN			(1 << 13)
+#define ISPCTRL_SYNC_DETECT_SHIFT		14
+#define ISPCTRL_SYNC_DETECT_HSFALL	(0x0 << ISPCTRL_SYNC_DETECT_SHIFT)
+#define ISPCTRL_SYNC_DETECT_HSRISE	(0x1 << ISPCTRL_SYNC_DETECT_SHIFT)
+#define ISPCTRL_SYNC_DETECT_VSFALL	(0x2 << ISPCTRL_SYNC_DETECT_SHIFT)
+#define ISPCTRL_SYNC_DETECT_VSRISE	(0x3 << ISPCTRL_SYNC_DETECT_SHIFT)
+#define ISPCTRL_SYNC_DETECT_MASK	(0x3 << ISPCTRL_SYNC_DETECT_SHIFT)
+
+#define ISPCTRL_CCDC_RAM_EN		(1 << 16)
+#define ISPCTRL_PREV_RAM_EN		(1 << 17)
+#define ISPCTRL_SBL_RD_RAM_EN		(1 << 18)
+#define ISPCTRL_SBL_WR1_RAM_EN		(1 << 19)
+#define ISPCTRL_SBL_WR0_RAM_EN		(1 << 20)
+#define ISPCTRL_SBL_AUTOIDLE		(1 << 21)
+#define ISPCTRL_SBL_SHARED_WPORTC	(1 << 26)
+#define ISPCTRL_SBL_SHARED_RPORTA	(1 << 27)
+#define ISPCTRL_SBL_SHARED_RPORTB	(1 << 28)
+#define ISPCTRL_JPEG_FLUSH		(1 << 30)
+#define ISPCTRL_CCDC_FLUSH		(1 << 31)
+
+#define ISPSECURE_SECUREMODE		0
+
+#define ISPTCTRL_CTRL_DIV_LOW		0x0
+#define ISPTCTRL_CTRL_DIV_HIGH		0x1
+#define ISPTCTRL_CTRL_DIV_BYPASS	0x1F
+
+#define ISPTCTRL_CTRL_DIVA_SHIFT	0
+#define ISPTCTRL_CTRL_DIVA_MASK		(0x1F << ISPTCTRL_CTRL_DIVA_SHIFT)
+
+#define ISPTCTRL_CTRL_DIVB_SHIFT	5
+#define ISPTCTRL_CTRL_DIVB_MASK		(0x1F << ISPTCTRL_CTRL_DIVB_SHIFT)
+
+#define ISPTCTRL_CTRL_DIVC_SHIFT	10
+#define ISPTCTRL_CTRL_DIVC_NOCLOCK	(0x0 << 10)
+
+#define ISPTCTRL_CTRL_SHUTEN		(1 << 21)
+#define ISPTCTRL_CTRL_PSTRBEN		(1 << 22)
+#define ISPTCTRL_CTRL_STRBEN		(1 << 23)
+#define ISPTCTRL_CTRL_SHUTPOL		(1 << 24)
+#define ISPTCTRL_CTRL_STRBPSTRBPOL	(1 << 26)
+
+#define ISPTCTRL_CTRL_INSEL_SHIFT	27
+#define ISPTCTRL_CTRL_INSEL_PARALLEL	(0x0 << 27)
+#define ISPTCTRL_CTRL_INSEL_CSIA	(0x1 << 27)
+#define ISPTCTRL_CTRL_INSEL_CSIB	(0x2 << 27)
+
+#define ISPTCTRL_CTRL_GRESETEn		(1 << 29)
+#define ISPTCTRL_CTRL_GRESETPOL		(1 << 30)
+#define ISPTCTRL_CTRL_GRESETDIR		(1 << 31)
+
+#define ISPTCTRL_FRAME_SHUT_SHIFT		0
+#define ISPTCTRL_FRAME_PSTRB_SHIFT		6
+#define ISPTCTRL_FRAME_STRB_SHIFT		12
+
+#define ISPCCDC_PID_PREV_SHIFT			0
+#define ISPCCDC_PID_CID_SHIFT			8
+#define ISPCCDC_PID_TID_SHIFT			16
+
+#define ISPCCDC_PCR_EN				1
+#define ISPCCDC_PCR_BUSY			(1 << 1)
+
+#define ISPCCDC_SYN_MODE_VDHDOUT		0x1
+#define ISPCCDC_SYN_MODE_FLDOUT			(1 << 1)
+#define ISPCCDC_SYN_MODE_VDPOL			(1 << 2)
+#define ISPCCDC_SYN_MODE_HDPOL			(1 << 3)
+#define ISPCCDC_SYN_MODE_FLDPOL			(1 << 4)
+#define ISPCCDC_SYN_MODE_EXWEN			(1 << 5)
+#define ISPCCDC_SYN_MODE_DATAPOL		(1 << 6)
+#define ISPCCDC_SYN_MODE_FLDMODE		(1 << 7)
+#define ISPCCDC_SYN_MODE_DATSIZ_MASK		(0x7 << 8)
+#define ISPCCDC_SYN_MODE_DATSIZ_8_16		(0x0 << 8)
+#define ISPCCDC_SYN_MODE_DATSIZ_12		(0x4 << 8)
+#define ISPCCDC_SYN_MODE_DATSIZ_11		(0x5 << 8)
+#define ISPCCDC_SYN_MODE_DATSIZ_10		(0x6 << 8)
+#define ISPCCDC_SYN_MODE_DATSIZ_8		(0x7 << 8)
+#define ISPCCDC_SYN_MODE_PACK8			(1 << 11)
+#define ISPCCDC_SYN_MODE_INPMOD_MASK		(3 << 12)
+#define ISPCCDC_SYN_MODE_INPMOD_RAW		(0 << 12)
+#define ISPCCDC_SYN_MODE_INPMOD_YCBCR16		(1 << 12)
+#define ISPCCDC_SYN_MODE_INPMOD_YCBCR8		(2 << 12)
+#define ISPCCDC_SYN_MODE_LPF			(1 << 14)
+#define ISPCCDC_SYN_MODE_FLDSTAT		(1 << 15)
+#define ISPCCDC_SYN_MODE_VDHDEN			(1 << 16)
+#define ISPCCDC_SYN_MODE_WEN			(1 << 17)
+#define ISPCCDC_SYN_MODE_VP2SDR			(1 << 18)
+#define ISPCCDC_SYN_MODE_SDR2RSZ		(1 << 19)
+
+#define ISPCCDC_HD_VD_WID_VDW_SHIFT		0
+#define ISPCCDC_HD_VD_WID_HDW_SHIFT		16
+
+#define ISPCCDC_PIX_LINES_HLPRF_SHIFT		0
+#define ISPCCDC_PIX_LINES_PPLN_SHIFT		16
+
+#define ISPCCDC_HORZ_INFO_NPH_SHIFT		0
+#define ISPCCDC_HORZ_INFO_NPH_MASK		0x00007fff
+#define ISPCCDC_HORZ_INFO_SPH_SHIFT		16
+#define ISPCCDC_HORZ_INFO_SPH_MASK		0x7fff0000
+
+#define ISPCCDC_VERT_START_SLV1_SHIFT		0
+#define ISPCCDC_VERT_START_SLV0_SHIFT		16
+#define ISPCCDC_VERT_START_SLV0_MASK		0x7fff0000
+
+#define ISPCCDC_VERT_LINES_NLV_SHIFT		0
+#define ISPCCDC_VERT_LINES_NLV_MASK		0x00007fff
+
+#define ISPCCDC_CULLING_CULV_SHIFT		0
+#define ISPCCDC_CULLING_CULHODD_SHIFT		16
+#define ISPCCDC_CULLING_CULHEVN_SHIFT		24
+
+#define ISPCCDC_HSIZE_OFF_SHIFT			0
+
+#define ISPCCDC_SDOFST_FINV			(1 << 14)
+#define ISPCCDC_SDOFST_FOFST_1L			0
+#define ISPCCDC_SDOFST_FOFST_4L			(3 << 12)
+#define ISPCCDC_SDOFST_LOFST3_SHIFT		0
+#define ISPCCDC_SDOFST_LOFST2_SHIFT		3
+#define ISPCCDC_SDOFST_LOFST1_SHIFT		6
+#define ISPCCDC_SDOFST_LOFST0_SHIFT		9
+#define EVENEVEN				1
+#define ODDEVEN					2
+#define EVENODD					3
+#define ODDODD					4
+
+#define ISPCCDC_CLAMP_OBGAIN_SHIFT		0
+#define ISPCCDC_CLAMP_OBST_SHIFT		10
+#define ISPCCDC_CLAMP_OBSLN_SHIFT		25
+#define ISPCCDC_CLAMP_OBSLEN_SHIFT		28
+#define ISPCCDC_CLAMP_CLAMPEN			(1 << 31)
+
+#define ISPCCDC_COLPTN_R_Ye			0x0
+#define ISPCCDC_COLPTN_Gr_Cy			0x1
+#define ISPCCDC_COLPTN_Gb_G			0x2
+#define ISPCCDC_COLPTN_B_Mg			0x3
+#define ISPCCDC_COLPTN_CP0PLC0_SHIFT		0
+#define ISPCCDC_COLPTN_CP0PLC1_SHIFT		2
+#define ISPCCDC_COLPTN_CP0PLC2_SHIFT		4
+#define ISPCCDC_COLPTN_CP0PLC3_SHIFT		6
+#define ISPCCDC_COLPTN_CP1PLC0_SHIFT		8
+#define ISPCCDC_COLPTN_CP1PLC1_SHIFT		10
+#define ISPCCDC_COLPTN_CP1PLC2_SHIFT		12
+#define ISPCCDC_COLPTN_CP1PLC3_SHIFT		14
+#define ISPCCDC_COLPTN_CP2PLC0_SHIFT		16
+#define ISPCCDC_COLPTN_CP2PLC1_SHIFT		18
+#define ISPCCDC_COLPTN_CP2PLC2_SHIFT		20
+#define ISPCCDC_COLPTN_CP2PLC3_SHIFT		22
+#define ISPCCDC_COLPTN_CP3PLC0_SHIFT		24
+#define ISPCCDC_COLPTN_CP3PLC1_SHIFT		26
+#define ISPCCDC_COLPTN_CP3PLC2_SHIFT		28
+#define ISPCCDC_COLPTN_CP3PLC3_SHIFT		30
+
+#define ISPCCDC_BLKCMP_B_MG_SHIFT		0
+#define ISPCCDC_BLKCMP_GB_G_SHIFT		8
+#define ISPCCDC_BLKCMP_GR_CY_SHIFT		16
+#define ISPCCDC_BLKCMP_R_YE_SHIFT		24
+
+#define ISPCCDC_FPC_FPNUM_SHIFT			0
+#define ISPCCDC_FPC_FPCEN			(1 << 15)
+#define ISPCCDC_FPC_FPERR			(1 << 16)
+
+#define ISPCCDC_VDINT_1_SHIFT			0
+#define ISPCCDC_VDINT_1_MASK			0x00007fff
+#define ISPCCDC_VDINT_0_SHIFT			16
+#define ISPCCDC_VDINT_0_MASK			0x7fff0000
+
+#define ISPCCDC_ALAW_GWDI_12_3			(0x3 << 0)
+#define ISPCCDC_ALAW_GWDI_11_2			(0x4 << 0)
+#define ISPCCDC_ALAW_GWDI_10_1			(0x5 << 0)
+#define ISPCCDC_ALAW_GWDI_9_0			(0x6 << 0)
+#define ISPCCDC_ALAW_CCDTBL			(1 << 3)
+
+#define ISPCCDC_REC656IF_R656ON			1
+#define ISPCCDC_REC656IF_ECCFVH			(1 << 1)
+
+#define ISPCCDC_CFG_BW656			(1 << 5)
+#define ISPCCDC_CFG_FIDMD_SHIFT			6
+#define ISPCCDC_CFG_WENLOG			(1 << 8)
+#define ISPCCDC_CFG_WENLOG_AND			(0 << 8)
+#define ISPCCDC_CFG_WENLOG_OR			(1 << 8)
+#define ISPCCDC_CFG_Y8POS			(1 << 11)
+#define ISPCCDC_CFG_BSWD			(1 << 12)
+#define ISPCCDC_CFG_MSBINVI			(1 << 13)
+#define ISPCCDC_CFG_VDLC			(1 << 15)
+
+#define ISPCCDC_FMTCFG_FMTEN			0x1
+#define ISPCCDC_FMTCFG_LNALT			(1 << 1)
+#define ISPCCDC_FMTCFG_LNUM_SHIFT		2
+#define ISPCCDC_FMTCFG_PLEN_ODD_SHIFT		4
+#define ISPCCDC_FMTCFG_PLEN_EVEN_SHIFT		8
+#define ISPCCDC_FMTCFG_VPIN_MASK		0x00007000
+#define ISPCCDC_FMTCFG_VPIN_12_3		(0x3 << 12)
+#define ISPCCDC_FMTCFG_VPIN_11_2		(0x4 << 12)
+#define ISPCCDC_FMTCFG_VPIN_10_1		(0x5 << 12)
+#define ISPCCDC_FMTCFG_VPIN_9_0			(0x6 << 12)
+#define ISPCCDC_FMTCFG_VPEN			(1 << 15)
+
+#define ISPCCDC_FMTCFG_VPIF_FRQ_MASK		0x003f0000
+#define ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT		16
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY2		(0x0 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY3		(0x1 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY4		(0x2 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY5		(0x3 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY6		(0x4 << 16)
+
+#define ISPCCDC_FMT_HORZ_FMTLNH_SHIFT		0
+#define ISPCCDC_FMT_HORZ_FMTSPH_SHIFT		16
+
+#define ISPCCDC_FMT_VERT_FMTLNV_SHIFT		0
+#define ISPCCDC_FMT_VERT_FMTSLV_SHIFT		16
+
+#define ISPCCDC_FMT_HORZ_FMTSPH_MASK		0x1fff0000
+#define ISPCCDC_FMT_HORZ_FMTLNH_MASK		0x00001fff
+
+#define ISPCCDC_FMT_VERT_FMTSLV_MASK		0x1fff0000
+#define ISPCCDC_FMT_VERT_FMTLNV_MASK		0x00001fff
+
+#define ISPCCDC_VP_OUT_HORZ_ST_SHIFT		0
+#define ISPCCDC_VP_OUT_HORZ_NUM_SHIFT		4
+#define ISPCCDC_VP_OUT_VERT_NUM_SHIFT		17
+
+#define ISPRSZ_PID_PREV_SHIFT			0
+#define ISPRSZ_PID_CID_SHIFT			8
+#define ISPRSZ_PID_TID_SHIFT			16
+
+#define ISPRSZ_PCR_ENABLE			(1 << 0)
+#define ISPRSZ_PCR_BUSY				(1 << 1)
+#define ISPRSZ_PCR_ONESHOT			(1 << 2)
+
+#define ISPRSZ_CNT_HRSZ_SHIFT			0
+#define ISPRSZ_CNT_HRSZ_MASK			\
+	(0x3FF << ISPRSZ_CNT_HRSZ_SHIFT)
+#define ISPRSZ_CNT_VRSZ_SHIFT			10
+#define ISPRSZ_CNT_VRSZ_MASK			\
+	(0x3FF << ISPRSZ_CNT_VRSZ_SHIFT)
+#define ISPRSZ_CNT_HSTPH_SHIFT			20
+#define ISPRSZ_CNT_HSTPH_MASK			(0x7 << ISPRSZ_CNT_HSTPH_SHIFT)
+#define ISPRSZ_CNT_VSTPH_SHIFT			23
+#define ISPRSZ_CNT_VSTPH_MASK			(0x7 << ISPRSZ_CNT_VSTPH_SHIFT)
+#define ISPRSZ_CNT_YCPOS			(1 << 26)
+#define ISPRSZ_CNT_INPTYP			(1 << 27)
+#define ISPRSZ_CNT_INPSRC			(1 << 28)
+#define ISPRSZ_CNT_CBILIN			(1 << 29)
+
+#define ISPRSZ_OUT_SIZE_HORZ_SHIFT		0
+#define ISPRSZ_OUT_SIZE_HORZ_MASK		\
+	(0xFFF << ISPRSZ_OUT_SIZE_HORZ_SHIFT)
+#define ISPRSZ_OUT_SIZE_VERT_SHIFT		16
+#define ISPRSZ_OUT_SIZE_VERT_MASK		\
+	(0xFFF << ISPRSZ_OUT_SIZE_VERT_SHIFT)
+
+#define ISPRSZ_IN_START_HORZ_ST_SHIFT		0
+#define ISPRSZ_IN_START_HORZ_ST_MASK		\
+	(0x1FFF << ISPRSZ_IN_START_HORZ_ST_SHIFT)
+#define ISPRSZ_IN_START_VERT_ST_SHIFT		16
+#define ISPRSZ_IN_START_VERT_ST_MASK		\
+	(0x1FFF << ISPRSZ_IN_START_VERT_ST_SHIFT)
+
+#define ISPRSZ_IN_SIZE_HORZ_SHIFT		0
+#define ISPRSZ_IN_SIZE_HORZ_MASK		\
+	(0x1FFF << ISPRSZ_IN_SIZE_HORZ_SHIFT)
+#define ISPRSZ_IN_SIZE_VERT_SHIFT		16
+#define ISPRSZ_IN_SIZE_VERT_MASK		\
+	(0x1FFF << ISPRSZ_IN_SIZE_VERT_SHIFT)
+
+#define ISPRSZ_SDR_INADD_ADDR_SHIFT		0
+#define ISPRSZ_SDR_INADD_ADDR_MASK		0xFFFFFFFF
+
+#define ISPRSZ_SDR_INOFF_OFFSET_SHIFT		0
+#define ISPRSZ_SDR_INOFF_OFFSET_MASK		\
+	(0xFFFF << ISPRSZ_SDR_INOFF_OFFSET_SHIFT)
+
+#define ISPRSZ_SDR_OUTADD_ADDR_SHIFT		0
+#define ISPRSZ_SDR_OUTADD_ADDR_MASK		0xFFFFFFFF
+
+
+#define ISPRSZ_SDR_OUTOFF_OFFSET_SHIFT		0
+#define ISPRSZ_SDR_OUTOFF_OFFSET_MASK		\
+	(0xFFFF << ISPRSZ_SDR_OUTOFF_OFFSET_SHIFT)
+
+#define ISPRSZ_HFILT_COEF0_SHIFT		0
+#define ISPRSZ_HFILT_COEF0_MASK			\
+	(0x3FF << ISPRSZ_HFILT_COEF0_SHIFT)
+#define ISPRSZ_HFILT_COEF1_SHIFT		16
+#define ISPRSZ_HFILT_COEF1_MASK			\
+	(0x3FF << ISPRSZ_HFILT_COEF1_SHIFT)
+
+#define ISPRSZ_HFILT32_COEF2_SHIFT		0
+#define ISPRSZ_HFILT32_COEF2_MASK		0x3FF
+#define ISPRSZ_HFILT32_COEF3_SHIFT		16
+#define ISPRSZ_HFILT32_COEF3_MASK		0x3FF0000
+
+#define ISPRSZ_HFILT54_COEF4_SHIFT		0
+#define ISPRSZ_HFILT54_COEF4_MASK		0x3FF
+#define ISPRSZ_HFILT54_COEF5_SHIFT		16
+#define ISPRSZ_HFILT54_COEF5_MASK		0x3FF0000
+
+#define ISPRSZ_HFILT76_COEFF6_SHIFT		0
+#define ISPRSZ_HFILT76_COEFF6_MASK		0x3FF
+#define ISPRSZ_HFILT76_COEFF7_SHIFT		16
+#define ISPRSZ_HFILT76_COEFF7_MASK		0x3FF0000
+
+#define ISPRSZ_HFILT98_COEFF8_SHIFT		0
+#define ISPRSZ_HFILT98_COEFF8_MASK		0x3FF
+#define ISPRSZ_HFILT98_COEFF9_SHIFT		16
+#define ISPRSZ_HFILT98_COEFF9_MASK		0x3FF0000
+
+#define ISPRSZ_HFILT1110_COEF10_SHIFT		0
+#define ISPRSZ_HFILT1110_COEF10_MASK		0x3FF
+#define ISPRSZ_HFILT1110_COEF11_SHIFT		16
+#define ISPRSZ_HFILT1110_COEF11_MASK		0x3FF0000
+
+#define ISPRSZ_HFILT1312_COEFF12_SHIFT		0
+#define ISPRSZ_HFILT1312_COEFF12_MASK		0x3FF
+#define ISPRSZ_HFILT1312_COEFF13_SHIFT		16
+#define ISPRSZ_HFILT1312_COEFF13_MASK		0x3FF0000
+
+#define ISPRSZ_HFILT1514_COEFF14_SHIFT		0
+#define ISPRSZ_HFILT1514_COEFF14_MASK		0x3FF
+#define ISPRSZ_HFILT1514_COEFF15_SHIFT		16
+#define ISPRSZ_HFILT1514_COEFF15_MASK		0x3FF0000
+
+#define ISPRSZ_HFILT1716_COEF16_SHIFT		0
+#define ISPRSZ_HFILT1716_COEF16_MASK		0x3FF
+#define ISPRSZ_HFILT1716_COEF17_SHIFT		16
+#define ISPRSZ_HFILT1716_COEF17_MASK		0x3FF0000
+
+#define ISPRSZ_HFILT1918_COEF18_SHIFT		0
+#define ISPRSZ_HFILT1918_COEF18_MASK		0x3FF
+#define ISPRSZ_HFILT1918_COEF19_SHIFT		16
+#define ISPRSZ_HFILT1918_COEF19_MASK		0x3FF0000
+
+#define ISPRSZ_HFILT2120_COEF20_SHIFT		0
+#define ISPRSZ_HFILT2120_COEF20_MASK		0x3FF
+#define ISPRSZ_HFILT2120_COEF21_SHIFT		16
+#define ISPRSZ_HFILT2120_COEF21_MASK		0x3FF0000
+
+#define ISPRSZ_HFILT2322_COEF22_SHIFT		0
+#define ISPRSZ_HFILT2322_COEF22_MASK		0x3FF
+#define ISPRSZ_HFILT2322_COEF23_SHIFT		16
+#define ISPRSZ_HFILT2322_COEF23_MASK		0x3FF0000
+
+#define ISPRSZ_HFILT2524_COEF24_SHIFT		0
+#define ISPRSZ_HFILT2524_COEF24_MASK		0x3FF
+#define ISPRSZ_HFILT2524_COEF25_SHIFT		16
+#define ISPRSZ_HFILT2524_COEF25_MASK		0x3FF0000
+
+#define ISPRSZ_HFILT2726_COEF26_SHIFT		0
+#define ISPRSZ_HFILT2726_COEF26_MASK		0x3FF
+#define ISPRSZ_HFILT2726_COEF27_SHIFT		16
+#define ISPRSZ_HFILT2726_COEF27_MASK		0x3FF0000
+
+#define ISPRSZ_HFILT2928_COEF28_SHIFT		0
+#define ISPRSZ_HFILT2928_COEF28_MASK		0x3FF
+#define ISPRSZ_HFILT2928_COEF29_SHIFT		16
+#define ISPRSZ_HFILT2928_COEF29_MASK		0x3FF0000
+
+#define ISPRSZ_HFILT3130_COEF30_SHIFT		0
+#define ISPRSZ_HFILT3130_COEF30_MASK		0x3FF
+#define ISPRSZ_HFILT3130_COEF31_SHIFT		16
+#define ISPRSZ_HFILT3130_COEF31_MASK		0x3FF0000
+
+#define ISPRSZ_VFILT_COEF0_SHIFT		0
+#define ISPRSZ_VFILT_COEF0_MASK			\
+	(0x3FF << ISPRSZ_VFILT_COEF0_SHIFT)
+#define ISPRSZ_VFILT_COEF1_SHIFT		16
+#define ISPRSZ_VFILT_COEF1_MASK			\
+	(0x3FF << ISPRSZ_VFILT_COEF1_SHIFT)
+
+#define ISPRSZ_VFILT10_COEF0_SHIFT		0
+#define ISPRSZ_VFILT10_COEF0_MASK		0x3FF
+#define ISPRSZ_VFILT10_COEF1_SHIFT		16
+#define ISPRSZ_VFILT10_COEF1_MASK		0x3FF0000
+
+#define ISPRSZ_VFILT32_COEF2_SHIFT		0
+#define ISPRSZ_VFILT32_COEF2_MASK		0x3FF
+#define ISPRSZ_VFILT32_COEF3_SHIFT		16
+#define ISPRSZ_VFILT32_COEF3_MASK		0x3FF0000
+
+#define ISPRSZ_VFILT54_COEF4_SHIFT		0
+#define ISPRSZ_VFILT54_COEF4_MASK		0x3FF
+#define ISPRSZ_VFILT54_COEF5_SHIFT		16
+#define ISPRSZ_VFILT54_COEF5_MASK		0x3FF0000
+
+#define ISPRSZ_VFILT76_COEFF6_SHIFT		0
+#define ISPRSZ_VFILT76_COEFF6_MASK		0x3FF
+#define ISPRSZ_VFILT76_COEFF7_SHIFT		16
+#define ISPRSZ_VFILT76_COEFF7_MASK		0x3FF0000
+
+#define ISPRSZ_VFILT98_COEFF8_SHIFT		0
+#define ISPRSZ_VFILT98_COEFF8_MASK		0x3FF
+#define ISPRSZ_VFILT98_COEFF9_SHIFT		16
+#define ISPRSZ_VFILT98_COEFF9_MASK		0x3FF0000
+
+#define ISPRSZ_VFILT1110_COEF10_SHIFT		0
+#define ISPRSZ_VFILT1110_COEF10_MASK		0x3FF
+#define ISPRSZ_VFILT1110_COEF11_SHIFT		16
+#define ISPRSZ_VFILT1110_COEF11_MASK		0x3FF0000
+
+#define ISPRSZ_VFILT1312_COEFF12_SHIFT		0
+#define ISPRSZ_VFILT1312_COEFF12_MASK		0x3FF
+#define ISPRSZ_VFILT1312_COEFF13_SHIFT		16
+#define ISPRSZ_VFILT1312_COEFF13_MASK		0x3FF0000
+
+#define ISPRSZ_VFILT1514_COEFF14_SHIFT		0
+#define ISPRSZ_VFILT1514_COEFF14_MASK		0x3FF
+#define ISPRSZ_VFILT1514_COEFF15_SHIFT		16
+#define ISPRSZ_VFILT1514_COEFF15_MASK		0x3FF0000
+
+#define ISPRSZ_VFILT1716_COEF16_SHIFT		0
+#define ISPRSZ_VFILT1716_COEF16_MASK		0x3FF
+#define ISPRSZ_VFILT1716_COEF17_SHIFT		16
+#define ISPRSZ_VFILT1716_COEF17_MASK		0x3FF0000
+
+#define ISPRSZ_VFILT1918_COEF18_SHIFT		0
+#define ISPRSZ_VFILT1918_COEF18_MASK		0x3FF
+#define ISPRSZ_VFILT1918_COEF19_SHIFT		16
+#define ISPRSZ_VFILT1918_COEF19_MASK		0x3FF0000
+
+#define ISPRSZ_VFILT2120_COEF20_SHIFT		0
+#define ISPRSZ_VFILT2120_COEF20_MASK		0x3FF
+#define ISPRSZ_VFILT2120_COEF21_SHIFT		16
+#define ISPRSZ_VFILT2120_COEF21_MASK		0x3FF0000
+
+#define ISPRSZ_VFILT2322_COEF22_SHIFT		0
+#define ISPRSZ_VFILT2322_COEF22_MASK		0x3FF
+#define ISPRSZ_VFILT2322_COEF23_SHIFT		16
+#define ISPRSZ_VFILT2322_COEF23_MASK		0x3FF0000
+
+#define ISPRSZ_VFILT2524_COEF24_SHIFT		0
+#define ISPRSZ_VFILT2524_COEF24_MASK		0x3FF
+#define ISPRSZ_VFILT2524_COEF25_SHIFT		16
+#define ISPRSZ_VFILT2524_COEF25_MASK		0x3FF0000
+
+#define ISPRSZ_VFILT2726_COEF26_SHIFT		0
+#define ISPRSZ_VFILT2726_COEF26_MASK		0x3FF
+#define ISPRSZ_VFILT2726_COEF27_SHIFT		16
+#define ISPRSZ_VFILT2726_COEF27_MASK		0x3FF0000
+
+#define ISPRSZ_VFILT2928_COEF28_SHIFT		0
+#define ISPRSZ_VFILT2928_COEF28_MASK		0x3FF
+#define ISPRSZ_VFILT2928_COEF29_SHIFT		16
+#define ISPRSZ_VFILT2928_COEF29_MASK		0x3FF0000
+
+#define ISPRSZ_VFILT3130_COEF30_SHIFT		0
+#define ISPRSZ_VFILT3130_COEF30_MASK		0x3FF
+#define ISPRSZ_VFILT3130_COEF31_SHIFT		16
+#define ISPRSZ_VFILT3130_COEF31_MASK		0x3FF0000
+
+#define ISPRSZ_YENH_CORE_SHIFT			0
+#define ISPRSZ_YENH_CORE_MASK			\
+	(0xFF << ISPRSZ_YENH_CORE_SHIFT)
+#define ISPRSZ_YENH_SLOP_SHIFT			8
+#define ISPRSZ_YENH_SLOP_MASK			\
+	(0xF << ISPRSZ_YENH_SLOP_SHIFT)
+#define ISPRSZ_YENH_GAIN_SHIFT			12
+#define ISPRSZ_YENH_GAIN_MASK			\
+	(0xF << ISPRSZ_YENH_GAIN_SHIFT)
+#define ISPRSZ_YENH_ALGO_SHIFT			16
+#define ISPRSZ_YENH_ALGO_MASK			\
+	(0x3 << ISPRSZ_YENH_ALGO_SHIFT)
+
+#define ISPH3A_PCR_AEW_ALAW_EN_SHIFT		1
+#define ISPH3A_PCR_AF_MED_TH_SHIFT		3
+#define ISPH3A_PCR_AF_RGBPOS_SHIFT		11
+#define ISPH3A_PCR_AEW_AVE2LMT_SHIFT		22
+#define ISPH3A_PCR_AEW_AVE2LMT_MASK		0xFFC00000
+#define ISPH3A_PCR_BUSYAF			(1 << 15)
+#define ISPH3A_PCR_BUSYAEAWB			(1 << 18)
+
+#define ISPH3A_AEWWIN1_WINHC_SHIFT		0
+#define ISPH3A_AEWWIN1_WINHC_MASK		0x3F
+#define ISPH3A_AEWWIN1_WINVC_SHIFT		6
+#define ISPH3A_AEWWIN1_WINVC_MASK		0x1FC0
+#define ISPH3A_AEWWIN1_WINW_SHIFT		13
+#define ISPH3A_AEWWIN1_WINW_MASK		0xFE000
+#define ISPH3A_AEWWIN1_WINH_SHIFT		24
+#define ISPH3A_AEWWIN1_WINH_MASK		0x7F000000
+
+#define ISPH3A_AEWINSTART_WINSH_SHIFT		0
+#define ISPH3A_AEWINSTART_WINSH_MASK		0x0FFF
+#define ISPH3A_AEWINSTART_WINSV_SHIFT		16
+#define ISPH3A_AEWINSTART_WINSV_MASK		0x0FFF0000
+
+#define ISPH3A_AEWINBLK_WINH_SHIFT		0
+#define ISPH3A_AEWINBLK_WINH_MASK		0x7F
+#define ISPH3A_AEWINBLK_WINSV_SHIFT		16
+#define ISPH3A_AEWINBLK_WINSV_MASK		0x0FFF0000
+
+#define ISPH3A_AEWSUBWIN_AEWINCH_SHIFT		0
+#define ISPH3A_AEWSUBWIN_AEWINCH_MASK		0x0F
+#define ISPH3A_AEWSUBWIN_AEWINCV_SHIFT		8
+#define ISPH3A_AEWSUBWIN_AEWINCV_MASK		0x0F00
+
+#define ISPHIST_PCR_ENABLE_SHIFT	0
+#define ISPHIST_PCR_ENABLE_MASK		0x01
+#define ISPHIST_PCR_ENABLE		(1 << ISPHIST_PCR_ENABLE_SHIFT)
+#define ISPHIST_PCR_BUSY		0x02
+
+#define ISPHIST_CNT_DATASIZE_SHIFT	8
+#define ISPHIST_CNT_DATASIZE_MASK	0x0100
+#define ISPHIST_CNT_CLEAR_SHIFT		7
+#define ISPHIST_CNT_CLEAR_MASK		0x080
+#define ISPHIST_CNT_CLEAR		(1 << ISPHIST_CNT_CLEAR_SHIFT)
+#define ISPHIST_CNT_CFA_SHIFT		6
+#define ISPHIST_CNT_CFA_MASK		0x040
+#define ISPHIST_CNT_BINS_SHIFT		4
+#define ISPHIST_CNT_BINS_MASK		0x030
+#define ISPHIST_CNT_SOURCE_SHIFT	3
+#define ISPHIST_CNT_SOURCE_MASK		0x08
+#define ISPHIST_CNT_SHIFT_SHIFT		0
+#define ISPHIST_CNT_SHIFT_MASK		0x07
+
+#define ISPHIST_WB_GAIN_WG00_SHIFT	24
+#define ISPHIST_WB_GAIN_WG00_MASK	0xFF000000
+#define ISPHIST_WB_GAIN_WG01_SHIFT	16
+#define ISPHIST_WB_GAIN_WG01_MASK	0xFF0000
+#define ISPHIST_WB_GAIN_WG02_SHIFT	8
+#define ISPHIST_WB_GAIN_WG02_MASK	0xFF00
+#define ISPHIST_WB_GAIN_WG03_SHIFT	0
+#define ISPHIST_WB_GAIN_WG03_MASK	0xFF
+
+#define ISPHIST_REG_START_END_MASK		0x3FFF
+#define ISPHIST_REG_START_SHIFT			16
+#define ISPHIST_REG_END_SHIFT			0
+#define ISPHIST_REG_START_MASK			(ISPHIST_REG_START_END_MASK << \
+						 ISPHIST_REG_START_SHIFT)
+#define ISPHIST_REG_END_MASK			(ISPHIST_REG_START_END_MASK << \
+						 ISPHIST_REG_END_SHIFT)
+
+#define ISPHIST_REG_MASK			(ISPHIST_REG_START_MASK | \
+						 ISPHIST_REG_END_MASK)
+
+#define ISPHIST_ADDR_SHIFT			0
+#define ISPHIST_ADDR_MASK			0x3FF
+
+#define ISPHIST_DATA_SHIFT			0
+#define ISPHIST_DATA_MASK			0xFFFFF
+
+#define ISPHIST_RADD_SHIFT			0
+#define ISPHIST_RADD_MASK			0xFFFFFFFF
+
+#define ISPHIST_RADD_OFF_SHIFT			0
+#define ISPHIST_RADD_OFF_MASK			0xFFFF
+
+#define ISPHIST_HV_INFO_HSIZE_SHIFT		16
+#define ISPHIST_HV_INFO_HSIZE_MASK		0x3FFF0000
+#define ISPHIST_HV_INFO_VSIZE_SHIFT		0
+#define ISPHIST_HV_INFO_VSIZE_MASK		0x3FFF
+
+#define ISPHIST_HV_INFO_MASK			0x3FFF3FFF
+
+#define ISPCCDC_LSC_ENABLE			1
+#define ISPCCDC_LSC_BUSY			(1 << 7)
+#define ISPCCDC_LSC_GAIN_MODE_N_MASK		0x700
+#define ISPCCDC_LSC_GAIN_MODE_N_SHIFT		8
+#define ISPCCDC_LSC_GAIN_MODE_M_MASK		0x3800
+#define ISPCCDC_LSC_GAIN_MODE_M_SHIFT		12
+#define ISPCCDC_LSC_GAIN_FORMAT_MASK		0xE
+#define ISPCCDC_LSC_GAIN_FORMAT_SHIFT		1
+#define ISPCCDC_LSC_AFTER_REFORMATTER_MASK	(1<<6)
+
+#define ISPCCDC_LSC_INITIAL_X_MASK		0x3F
+#define ISPCCDC_LSC_INITIAL_X_SHIFT		0
+#define ISPCCDC_LSC_INITIAL_Y_MASK		0x3F0000
+#define ISPCCDC_LSC_INITIAL_Y_SHIFT		16
+
+/* -----------------------------------------------------------------------------
+ * CSI2 receiver registers (ES2.0)
+ */
+
+#define ISPCSI2_REVISION			(0x000)
+#define ISPCSI2_SYSCONFIG			(0x010)
+#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT	12
+#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK	\
+	(0x3 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
+#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_FORCE	\
+	(0x0 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
+#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO	\
+	(0x1 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
+#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART	\
+	(0x2 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
+#define ISPCSI2_SYSCONFIG_SOFT_RESET		(1 << 1)
+#define ISPCSI2_SYSCONFIG_AUTO_IDLE		(1 << 0)
+
+#define ISPCSI2_SYSSTATUS			(0x014)
+#define ISPCSI2_SYSSTATUS_RESET_DONE		(1 << 0)
+
+#define ISPCSI2_IRQSTATUS			(0x018)
+#define ISPCSI2_IRQSTATUS_OCP_ERR_IRQ		(1 << 14)
+#define ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ	(1 << 13)
+#define ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ	(1 << 12)
+#define ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ	(1 << 11)
+#define ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ	(1 << 10)
+#define ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ	(1 << 9)
+#define ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ		(1 << 8)
+#define ISPCSI2_IRQSTATUS_CONTEXT(n)		(1 << (n))
+
+#define ISPCSI2_IRQENABLE			(0x01c)
+#define ISPCSI2_CTRL				(0x040)
+#define ISPCSI2_CTRL_VP_CLK_EN			(1 << 15)
+#define ISPCSI2_CTRL_VP_ONLY_EN			(1 << 11)
+#define ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT		8
+#define ISPCSI2_CTRL_VP_OUT_CTRL_MASK		\
+	(3 << ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT)
+#define ISPCSI2_CTRL_DBG_EN			(1 << 7)
+#define ISPCSI2_CTRL_BURST_SIZE_SHIFT		5
+#define ISPCSI2_CTRL_BURST_SIZE_MASK		\
+	(3 << ISPCSI2_CTRL_BURST_SIZE_SHIFT)
+#define ISPCSI2_CTRL_FRAME			(1 << 3)
+#define ISPCSI2_CTRL_ECC_EN			(1 << 2)
+#define ISPCSI2_CTRL_SECURE			(1 << 1)
+#define ISPCSI2_CTRL_IF_EN			(1 << 0)
+
+#define ISPCSI2_DBG_H				(0x044)
+#define ISPCSI2_GNQ				(0x048)
+#define ISPCSI2_PHY_CFG				(0x050)
+#define ISPCSI2_PHY_CFG_RESET_CTRL		(1 << 30)
+#define ISPCSI2_PHY_CFG_RESET_DONE		(1 << 29)
+#define ISPCSI2_PHY_CFG_PWR_CMD_SHIFT		27
+#define ISPCSI2_PHY_CFG_PWR_CMD_MASK		\
+	(0x3 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT)
+#define ISPCSI2_PHY_CFG_PWR_CMD_OFF		\
+	(0x0 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT)
+#define ISPCSI2_PHY_CFG_PWR_CMD_ON		\
+	(0x1 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT)
+#define ISPCSI2_PHY_CFG_PWR_CMD_ULPW		\
+	(0x2 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT)
+#define ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT	25
+#define ISPCSI2_PHY_CFG_PWR_STATUS_MASK		\
+	(0x3 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT)
+#define ISPCSI2_PHY_CFG_PWR_STATUS_OFF		\
+	(0x0 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT)
+#define ISPCSI2_PHY_CFG_PWR_STATUS_ON		\
+	(0x1 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT)
+#define ISPCSI2_PHY_CFG_PWR_STATUS_ULPW		\
+	(0x2 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT)
+#define ISPCSI2_PHY_CFG_PWR_AUTO		(1 << 24)
+
+#define ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n)	(3 + ((n) * 4))
+#define ISPCSI2_PHY_CFG_DATA_POL_MASK(n)	\
+	(0x1 << ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n))
+#define ISPCSI2_PHY_CFG_DATA_POL_PN(n)		\
+	(0x0 << ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n))
+#define ISPCSI2_PHY_CFG_DATA_POL_NP(n)		\
+	(0x1 << ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n))
+
+#define ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n)	((n) * 4)
+#define ISPCSI2_PHY_CFG_DATA_POSITION_MASK(n)	\
+	(0x7 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
+#define ISPCSI2_PHY_CFG_DATA_POSITION_NC(n)	\
+	(0x0 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
+#define ISPCSI2_PHY_CFG_DATA_POSITION_1(n)	\
+	(0x1 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
+#define ISPCSI2_PHY_CFG_DATA_POSITION_2(n)	\
+	(0x2 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
+#define ISPCSI2_PHY_CFG_DATA_POSITION_3(n)	\
+	(0x3 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
+#define ISPCSI2_PHY_CFG_DATA_POSITION_4(n)	\
+	(0x4 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
+#define ISPCSI2_PHY_CFG_DATA_POSITION_5(n)	\
+	(0x5 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
+
+#define ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT		3
+#define ISPCSI2_PHY_CFG_CLOCK_POL_MASK		\
+	(0x1 << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT)
+#define ISPCSI2_PHY_CFG_CLOCK_POL_PN		\
+	(0x0 << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT)
+#define ISPCSI2_PHY_CFG_CLOCK_POL_NP		\
+	(0x1 << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT)
+
+#define ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT	0
+#define ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK	\
+	(0x7 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
+#define ISPCSI2_PHY_CFG_CLOCK_POSITION_1	\
+	(0x1 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
+#define ISPCSI2_PHY_CFG_CLOCK_POSITION_2	\
+	(0x2 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
+#define ISPCSI2_PHY_CFG_CLOCK_POSITION_3	\
+	(0x3 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
+#define ISPCSI2_PHY_CFG_CLOCK_POSITION_4	\
+	(0x4 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
+#define ISPCSI2_PHY_CFG_CLOCK_POSITION_5	\
+	(0x5 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
+
+#define ISPCSI2_PHY_IRQSTATUS			(0x054)
+#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMEXIT	(1 << 26)
+#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMENTER	(1 << 25)
+#define ISPCSI2_PHY_IRQSTATUS_STATEULPM5	(1 << 24)
+#define ISPCSI2_PHY_IRQSTATUS_STATEULPM4	(1 << 23)
+#define ISPCSI2_PHY_IRQSTATUS_STATEULPM3	(1 << 22)
+#define ISPCSI2_PHY_IRQSTATUS_STATEULPM2	(1 << 21)
+#define ISPCSI2_PHY_IRQSTATUS_STATEULPM1	(1 << 20)
+#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL5	(1 << 19)
+#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL4	(1 << 18)
+#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL3	(1 << 17)
+#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL2	(1 << 16)
+#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL1	(1 << 15)
+#define ISPCSI2_PHY_IRQSTATUS_ERRESC5		(1 << 14)
+#define ISPCSI2_PHY_IRQSTATUS_ERRESC4		(1 << 13)
+#define ISPCSI2_PHY_IRQSTATUS_ERRESC3		(1 << 12)
+#define ISPCSI2_PHY_IRQSTATUS_ERRESC2		(1 << 11)
+#define ISPCSI2_PHY_IRQSTATUS_ERRESC1		(1 << 10)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS5	(1 << 9)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS4	(1 << 8)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS3	(1 << 7)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS2	(1 << 6)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS1	(1 << 5)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS5		(1 << 4)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS4		(1 << 3)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS3		(1 << 2)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS2		(1 << 1)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS1		1
+
+#define ISPCSI2_SHORT_PACKET			(0x05c)
+#define ISPCSI2_PHY_IRQENABLE			(0x060)
+#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT	(1 << 26)
+#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER	(1 << 25)
+#define ISPCSI2_PHY_IRQENABLE_STATEULPM5	(1 << 24)
+#define ISPCSI2_PHY_IRQENABLE_STATEULPM4	(1 << 23)
+#define ISPCSI2_PHY_IRQENABLE_STATEULPM3	(1 << 22)
+#define ISPCSI2_PHY_IRQENABLE_STATEULPM2	(1 << 21)
+#define ISPCSI2_PHY_IRQENABLE_STATEULPM1	(1 << 20)
+#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL5	(1 << 19)
+#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL4	(1 << 18)
+#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL3	(1 << 17)
+#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL2	(1 << 16)
+#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL1	(1 << 15)
+#define ISPCSI2_PHY_IRQENABLE_ERRESC5		(1 << 14)
+#define ISPCSI2_PHY_IRQENABLE_ERRESC4		(1 << 13)
+#define ISPCSI2_PHY_IRQENABLE_ERRESC3		(1 << 12)
+#define ISPCSI2_PHY_IRQENABLE_ERRESC2		(1 << 11)
+#define ISPCSI2_PHY_IRQENABLE_ERRESC1		(1 << 10)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5	(1 << 9)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4	(1 << 8)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3	(1 << 7)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2	(1 << 6)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1	(1 << 5)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS5		(1 << 4)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS4		(1 << 3)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS3		(1 << 2)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS2		(1 << 1)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS1		(1 << 0)
+
+#define ISPCSI2_DBG_P				(0x068)
+#define ISPCSI2_TIMING				(0x06c)
+#define ISPCSI2_TIMING_FORCE_RX_MODE_IO(n)	(1 << ((16 * ((n) - 1)) + 15))
+#define ISPCSI2_TIMING_STOP_STATE_X16_IO(n)	(1 << ((16 * ((n) - 1)) + 14))
+#define ISPCSI2_TIMING_STOP_STATE_X4_IO(n)	(1 << ((16 * ((n) - 1)) + 13))
+#define ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(n)	(16 * ((n) - 1))
+#define ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(n)	\
+	(0x1fff << ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(n))
+
+#define ISPCSI2_CTX_CTRL1(n)			((0x070) + 0x20 * (n))
+#define ISPCSI2_CTX_CTRL1_COUNT_SHIFT		8
+#define ISPCSI2_CTX_CTRL1_COUNT_MASK		\
+	(0xff << ISPCSI2_CTX_CTRL1_COUNT_SHIFT)
+#define ISPCSI2_CTX_CTRL1_EOF_EN		(1 << 7)
+#define ISPCSI2_CTX_CTRL1_EOL_EN		(1 << 6)
+#define ISPCSI2_CTX_CTRL1_CS_EN			(1 << 5)
+#define ISPCSI2_CTX_CTRL1_COUNT_UNLOCK		(1 << 4)
+#define ISPCSI2_CTX_CTRL1_PING_PONG		(1 << 3)
+#define ISPCSI2_CTX_CTRL1_CTX_EN		(1 << 0)
+
+#define ISPCSI2_CTX_CTRL2(n)			((0x074) + 0x20 * (n))
+#define ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT	13
+#define ISPCSI2_CTX_CTRL2_USER_DEF_MAP_MASK	\
+	(0x3 << ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT)
+#define ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT	11
+#define ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK	\
+	(0x3 <<	ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT)
+#define ISPCSI2_CTX_CTRL2_DPCM_PRED		(1 << 10)
+#define ISPCSI2_CTX_CTRL2_FORMAT_SHIFT		0
+#define ISPCSI2_CTX_CTRL2_FORMAT_MASK		\
+	(0x3ff << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT)
+#define ISPCSI2_CTX_CTRL2_FRAME_SHIFT		16
+#define ISPCSI2_CTX_CTRL2_FRAME_MASK		\
+	(0xffff << ISPCSI2_CTX_CTRL2_FRAME_SHIFT)
+
+#define ISPCSI2_CTX_DAT_OFST(n)			((0x078) + 0x20 * (n))
+#define ISPCSI2_CTX_DAT_OFST_OFST_SHIFT		0
+#define ISPCSI2_CTX_DAT_OFST_OFST_MASK		\
+	(0x1ffe0 << ISPCSI2_CTX_DAT_OFST_OFST_SHIFT)
+
+#define ISPCSI2_CTX_DAT_PING_ADDR(n)		((0x07c) + 0x20 * (n))
+#define ISPCSI2_CTX_DAT_PONG_ADDR(n)		((0x080) + 0x20 * (n))
+#define ISPCSI2_CTX_IRQENABLE(n)		((0x084) + 0x20 * (n))
+#define ISPCSI2_CTX_IRQENABLE_ECC_CORRECTION_IRQ	(1 << 8)
+#define ISPCSI2_CTX_IRQENABLE_LINE_NUMBER_IRQ	(1 << 7)
+#define ISPCSI2_CTX_IRQENABLE_FRAME_NUMBER_IRQ	(1 << 6)
+#define ISPCSI2_CTX_IRQENABLE_CS_IRQ		(1 << 5)
+#define ISPCSI2_CTX_IRQENABLE_LE_IRQ		(1 << 3)
+#define ISPCSI2_CTX_IRQENABLE_LS_IRQ		(1 << 2)
+#define ISPCSI2_CTX_IRQENABLE_FE_IRQ		(1 << 1)
+#define ISPCSI2_CTX_IRQENABLE_FS_IRQ		(1 << 0)
+
+#define ISPCSI2_CTX_IRQSTATUS(n)		((0x088) + 0x20 * (n))
+#define ISPCSI2_CTX_IRQSTATUS_ECC_CORRECTION_IRQ	(1 << 8)
+#define ISPCSI2_CTX_IRQSTATUS_LINE_NUMBER_IRQ	(1 << 7)
+#define ISPCSI2_CTX_IRQSTATUS_FRAME_NUMBER_IRQ	(1 << 6)
+#define ISPCSI2_CTX_IRQSTATUS_CS_IRQ		(1 << 5)
+#define ISPCSI2_CTX_IRQSTATUS_LE_IRQ		(1 << 3)
+#define ISPCSI2_CTX_IRQSTATUS_LS_IRQ		(1 << 2)
+#define ISPCSI2_CTX_IRQSTATUS_FE_IRQ		(1 << 1)
+#define ISPCSI2_CTX_IRQSTATUS_FS_IRQ		(1 << 0)
+
+#define ISPCSI2_CTX_CTRL3(n)			((0x08c) + 0x20 * (n))
+#define ISPCSI2_CTX_CTRL3_ALPHA_SHIFT		5
+#define ISPCSI2_CTX_CTRL3_ALPHA_MASK		\
+	(0x3fff << ISPCSI2_CTX_CTRL3_ALPHA_SHIFT)
+
+/* This instance is for OMAP3630 only */
+#define ISPCSI2_CTX_TRANSCODEH(n)		(0x000 + 0x8 * (n))
+#define ISPCSI2_CTX_TRANSCODEH_HCOUNT_SHIFT	16
+#define ISPCSI2_CTX_TRANSCODEH_HCOUNT_MASK	\
+	(0x1fff << ISPCSI2_CTX_TRANSCODEH_HCOUNT_SHIFT)
+#define ISPCSI2_CTX_TRANSCODEH_HSKIP_SHIFT	0
+#define ISPCSI2_CTX_TRANSCODEH_HSKIP_MASK	\
+	(0x1fff << ISPCSI2_CTX_TRANSCODEH_HCOUNT_SHIFT)
+#define ISPCSI2_CTX_TRANSCODEV(n)		(0x004 + 0x8 * (n))
+#define ISPCSI2_CTX_TRANSCODEV_VCOUNT_SHIFT	16
+#define ISPCSI2_CTX_TRANSCODEV_VCOUNT_MASK	\
+	(0x1fff << ISPCSI2_CTX_TRANSCODEV_VCOUNT_SHIFT)
+#define ISPCSI2_CTX_TRANSCODEV_VSKIP_SHIFT	0
+#define ISPCSI2_CTX_TRANSCODEV_VSKIP_MASK	\
+	(0x1fff << ISPCSI2_CTX_TRANSCODEV_VCOUNT_SHIFT)
+
+/* -----------------------------------------------------------------------------
+ * CSI PHY registers
+ */
+
+#define ISPCSIPHY_REG0				(0x000)
+#define ISPCSIPHY_REG0_THS_TERM_SHIFT		8
+#define ISPCSIPHY_REG0_THS_TERM_MASK		\
+	(0xff << ISPCSIPHY_REG0_THS_TERM_SHIFT)
+#define ISPCSIPHY_REG0_THS_SETTLE_SHIFT		0
+#define ISPCSIPHY_REG0_THS_SETTLE_MASK		\
+	(0xff << ISPCSIPHY_REG0_THS_SETTLE_SHIFT)
+
+#define ISPCSIPHY_REG1					(0x004)
+#define ISPCSIPHY_REG1_RESET_DONE_CTRLCLK		(1 << 29)
+/* This field is for OMAP3630 only */
+#define ISPCSIPHY_REG1_CLOCK_MISS_DETECTOR_STATUS	(1 << 25)
+#define ISPCSIPHY_REG1_TCLK_TERM_SHIFT			18
+#define ISPCSIPHY_REG1_TCLK_TERM_MASK			\
+	(0x7f << ISPCSIPHY_REG1_TCLK_TERM_SHIFT)
+#define ISPCSIPHY_REG1_DPHY_HS_SYNC_PATTERN_SHIFT	10
+#define ISPCSIPHY_REG1_DPHY_HS_SYNC_PATTERN_MASK	\
+	(0xff << ISPCSIPHY_REG1_DPHY_HS_SYNC_PATTERN)
+/* This field is for OMAP3430 only */
+#define ISPCSIPHY_REG1_TCLK_MISS_SHIFT			8
+#define ISPCSIPHY_REG1_TCLK_MISS_MASK			\
+	(0x3 << ISPCSIPHY_REG1_TCLK_MISS_SHIFT)
+/* This field is for OMAP3630 only */
+#define ISPCSIPHY_REG1_CTRLCLK_DIV_FACTOR_SHIFT		8
+#define ISPCSIPHY_REG1_CTRLCLK_DIV_FACTOR_MASK		\
+	(0x3 << ISPCSIPHY_REG1_CTRLCLK_DIV_FACTOR_SHIFT)
+#define ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT		0
+#define ISPCSIPHY_REG1_TCLK_SETTLE_MASK			\
+	(0xff << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT)
+
+/* This register is for OMAP3630 only */
+#define ISPCSIPHY_REG2					(0x008)
+#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC0_SHIFT	30
+#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC0_MASK	\
+	(0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC0_SHIFT)
+#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC1_SHIFT	28
+#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC1_MASK	\
+	(0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC1_SHIFT)
+#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC2_SHIFT	26
+#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC2_MASK	\
+	(0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC2_SHIFT)
+#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC3_SHIFT	24
+#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC3_MASK	\
+	(0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC3_SHIFT)
+#define ISPCSIPHY_REG2_CCP2_SYNC_PATTERN_SHIFT		0
+#define ISPCSIPHY_REG2_CCP2_SYNC_PATTERN_MASK		\
+	(0x7fffff << ISPCSIPHY_REG2_CCP2_SYNC_PATTERN_SHIFT)
+
+#endif	/* OMAP3_ISP_REG_H */
diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c
new file mode 100644
index 0000000..d11fb26
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispresizer.c
@@ -0,0 +1,1778 @@
+/*
+ * ispresizer.c
+ *
+ * TI OMAP3 ISP - Resizer module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispresizer.h"
+
+/*
+ * Resizer Constants
+ */
+#define MIN_RESIZE_VALUE		64
+#define MID_RESIZE_VALUE		512
+#define MAX_RESIZE_VALUE		1024
+
+#define MIN_IN_WIDTH			32
+#define MIN_IN_HEIGHT			32
+#define MAX_IN_WIDTH_MEMORY_MODE	4095
+#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES1	1280
+#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES2	4095
+#define MAX_IN_HEIGHT			4095
+
+#define MIN_OUT_WIDTH			16
+#define MIN_OUT_HEIGHT			2
+#define MAX_OUT_HEIGHT			4095
+
+/*
+ * Resizer Use Constraints
+ * "TRM ES3.1, table 12-46"
+ */
+#define MAX_4TAP_OUT_WIDTH_ES1		1280
+#define MAX_7TAP_OUT_WIDTH_ES1		640
+#define MAX_4TAP_OUT_WIDTH_ES2		3312
+#define MAX_7TAP_OUT_WIDTH_ES2		1650
+#define MAX_4TAP_OUT_WIDTH_3630		4096
+#define MAX_7TAP_OUT_WIDTH_3630		2048
+
+/*
+ * Constants for ratio calculation
+ */
+#define RESIZE_DIVISOR			256
+#define DEFAULT_PHASE			1
+
+/*
+ * Default (and only) configuration of filter coefficients.
+ * 7-tap mode is for scale factors 0.25x to 0.5x.
+ * 4-tap mode is for scale factors 0.5x to 4.0x.
+ * There shouldn't be any reason to recalculate these, EVER.
+ */
+static const struct isprsz_coef filter_coefs = {
+	/* For 8-phase 4-tap horizontal filter: */
+	{
+		0x0000, 0x0100, 0x0000, 0x0000,
+		0x03FA, 0x00F6, 0x0010, 0x0000,
+		0x03F9, 0x00DB, 0x002C, 0x0000,
+		0x03FB, 0x00B3, 0x0053, 0x03FF,
+		0x03FD, 0x0082, 0x0084, 0x03FD,
+		0x03FF, 0x0053, 0x00B3, 0x03FB,
+		0x0000, 0x002C, 0x00DB, 0x03F9,
+		0x0000, 0x0010, 0x00F6, 0x03FA
+	},
+	/* For 8-phase 4-tap vertical filter: */
+	{
+		0x0000, 0x0100, 0x0000, 0x0000,
+		0x03FA, 0x00F6, 0x0010, 0x0000,
+		0x03F9, 0x00DB, 0x002C, 0x0000,
+		0x03FB, 0x00B3, 0x0053, 0x03FF,
+		0x03FD, 0x0082, 0x0084, 0x03FD,
+		0x03FF, 0x0053, 0x00B3, 0x03FB,
+		0x0000, 0x002C, 0x00DB, 0x03F9,
+		0x0000, 0x0010, 0x00F6, 0x03FA
+	},
+	/* For 4-phase 7-tap horizontal filter: */
+	#define DUMMY 0
+	{
+		0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
+		0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
+		0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
+		0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
+	},
+	/* For 4-phase 7-tap vertical filter: */
+	{
+		0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
+		0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
+		0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
+		0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
+	}
+	/*
+	 * The dummy padding is required in 7-tap mode because of how the
+	 * registers are arranged physically.
+	 */
+	#undef DUMMY
+};
+
+/*
+ * __resizer_get_format - helper function for getting resizer format
+ * @res   : pointer to resizer private structure
+ * @pad   : pad number
+ * @fh    : V4L2 subdev file handle
+ * @which : wanted subdev format
+ * return zero
+ */
+static struct v4l2_mbus_framefmt *
+__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
+		     unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_format(fh, pad);
+	else
+		return &res->formats[pad];
+}
+
+/*
+ * __resizer_get_crop - helper function for getting resizer crop rectangle
+ * @res   : pointer to resizer private structure
+ * @fh    : V4L2 subdev file handle
+ * @which : wanted subdev crop rectangle
+ */
+static struct v4l2_rect *
+__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
+		   enum v4l2_subdev_format_whence which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_crop(fh, RESZ_PAD_SINK);
+	else
+		return &res->crop.request;
+}
+
+/*
+ * resizer_set_filters - Set resizer filters
+ * @res: Device context.
+ * @h_coeff: horizontal coefficient
+ * @v_coeff: vertical coefficient
+ * Return none
+ */
+static void resizer_set_filters(struct isp_res_device *res, const u16 *h_coeff,
+				const u16 *v_coeff)
+{
+	struct isp_device *isp = to_isp_device(res);
+	u32 startaddr_h, startaddr_v, tmp_h, tmp_v;
+	int i;
+
+	startaddr_h = ISPRSZ_HFILT10;
+	startaddr_v = ISPRSZ_VFILT10;
+
+	for (i = 0; i < COEFF_CNT; i += 2) {
+		tmp_h = h_coeff[i] |
+			(h_coeff[i + 1] << ISPRSZ_HFILT_COEF1_SHIFT);
+		tmp_v = v_coeff[i] |
+			(v_coeff[i + 1] << ISPRSZ_VFILT_COEF1_SHIFT);
+		isp_reg_writel(isp, tmp_h, OMAP3_ISP_IOMEM_RESZ, startaddr_h);
+		isp_reg_writel(isp, tmp_v, OMAP3_ISP_IOMEM_RESZ, startaddr_v);
+		startaddr_h += 4;
+		startaddr_v += 4;
+	}
+}
+
+/*
+ * resizer_set_bilinear - Chrominance horizontal algorithm select
+ * @res: Device context.
+ * @type: Filtering interpolation type.
+ *
+ * Filtering that is same as luminance processing is
+ * intended only for downsampling, and bilinear interpolation
+ * is intended only for upsampling.
+ */
+static void resizer_set_bilinear(struct isp_res_device *res,
+				 enum resizer_chroma_algo type)
+{
+	struct isp_device *isp = to_isp_device(res);
+
+	if (type == RSZ_BILINEAR)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+			    ISPRSZ_CNT_CBILIN);
+	else
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+			    ISPRSZ_CNT_CBILIN);
+}
+
+/*
+ * resizer_set_ycpos - Luminance and chrominance order
+ * @res: Device context.
+ * @order: order type.
+ */
+static void resizer_set_ycpos(struct isp_res_device *res,
+			      enum v4l2_mbus_pixelcode pixelcode)
+{
+	struct isp_device *isp = to_isp_device(res);
+
+	switch (pixelcode) {
+	case V4L2_MBUS_FMT_YUYV8_1X16:
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+			    ISPRSZ_CNT_YCPOS);
+		break;
+	case V4L2_MBUS_FMT_UYVY8_1X16:
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+			    ISPRSZ_CNT_YCPOS);
+		break;
+	default:
+		return;
+	}
+}
+
+/*
+ * resizer_set_phase - Setup horizontal and vertical starting phase
+ * @res: Device context.
+ * @h_phase: horizontal phase parameters.
+ * @v_phase: vertical phase parameters.
+ *
+ * Horizontal and vertical phase range is 0 to 7
+ */
+static void resizer_set_phase(struct isp_res_device *res, u32 h_phase,
+			      u32 v_phase)
+{
+	struct isp_device *isp = to_isp_device(res);
+	u32 rgval = 0;
+
+	rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
+	      ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK);
+	rgval |= (h_phase << ISPRSZ_CNT_HSTPH_SHIFT) & ISPRSZ_CNT_HSTPH_MASK;
+	rgval |= (v_phase << ISPRSZ_CNT_VSTPH_SHIFT) & ISPRSZ_CNT_VSTPH_MASK;
+
+	isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
+}
+
+/*
+ * resizer_set_luma - Setup luminance enhancer parameters
+ * @res: Device context.
+ * @luma: Structure for luminance enhancer parameters.
+ *
+ * Algorithm select:
+ *  0x0: Disable
+ *  0x1: [-1  2 -1]/2 high-pass filter
+ *  0x2: [-1 -2  6 -2 -1]/4 high-pass filter
+ *
+ * Maximum gain:
+ *  The data is coded in U4Q4 representation.
+ *
+ * Slope:
+ *  The data is coded in U4Q4 representation.
+ *
+ * Coring offset:
+ *  The data is coded in U8Q0 representation.
+ *
+ * The new luminance value is computed as:
+ *  Y += HPF(Y) x max(GAIN, (HPF(Y) - CORE) x SLOP + 8) >> 4.
+ */
+static void resizer_set_luma(struct isp_res_device *res,
+			     struct resizer_luma_yenh *luma)
+{
+	struct isp_device *isp = to_isp_device(res);
+	u32 rgval = 0;
+
+	rgval  = (luma->algo << ISPRSZ_YENH_ALGO_SHIFT)
+		  & ISPRSZ_YENH_ALGO_MASK;
+	rgval |= (luma->gain << ISPRSZ_YENH_GAIN_SHIFT)
+		  & ISPRSZ_YENH_GAIN_MASK;
+	rgval |= (luma->slope << ISPRSZ_YENH_SLOP_SHIFT)
+		  & ISPRSZ_YENH_SLOP_MASK;
+	rgval |= (luma->core << ISPRSZ_YENH_CORE_SHIFT)
+		  & ISPRSZ_YENH_CORE_MASK;
+
+	isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH);
+}
+
+/*
+ * resizer_set_source - Input source select
+ * @res: Device context.
+ * @source: Input source type
+ *
+ * If this field is set to RESIZER_INPUT_VP, the resizer input is fed from
+ * Preview/CCDC engine, otherwise from memory.
+ */
+static void resizer_set_source(struct isp_res_device *res,
+			       enum resizer_input_entity source)
+{
+	struct isp_device *isp = to_isp_device(res);
+
+	if (source == RESIZER_INPUT_MEMORY)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+			    ISPRSZ_CNT_INPSRC);
+	else
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+			    ISPRSZ_CNT_INPSRC);
+}
+
+/*
+ * resizer_set_ratio - Setup horizontal and vertical resizing value
+ * @res: Device context.
+ * @ratio: Structure for ratio parameters.
+ *
+ * Resizing range from 64 to 1024
+ */
+static void resizer_set_ratio(struct isp_res_device *res,
+			      const struct resizer_ratio *ratio)
+{
+	struct isp_device *isp = to_isp_device(res);
+	const u16 *h_filter, *v_filter;
+	u32 rgval = 0;
+
+	rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
+			      ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK);
+	rgval |= ((ratio->horz - 1) << ISPRSZ_CNT_HRSZ_SHIFT)
+		  & ISPRSZ_CNT_HRSZ_MASK;
+	rgval |= ((ratio->vert - 1) << ISPRSZ_CNT_VRSZ_SHIFT)
+		  & ISPRSZ_CNT_VRSZ_MASK;
+	isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
+
+	/* prepare horizontal filter coefficients */
+	if (ratio->horz > MID_RESIZE_VALUE)
+		h_filter = &filter_coefs.h_filter_coef_7tap[0];
+	else
+		h_filter = &filter_coefs.h_filter_coef_4tap[0];
+
+	/* prepare vertical filter coefficients */
+	if (ratio->vert > MID_RESIZE_VALUE)
+		v_filter = &filter_coefs.v_filter_coef_7tap[0];
+	else
+		v_filter = &filter_coefs.v_filter_coef_4tap[0];
+
+	resizer_set_filters(res, h_filter, v_filter);
+}
+
+/*
+ * resizer_set_dst_size - Setup the output height and width
+ * @res: Device context.
+ * @width: Output width.
+ * @height: Output height.
+ *
+ * Width :
+ *  The value must be EVEN.
+ *
+ * Height:
+ *  The number of bytes written to SDRAM must be
+ *  a multiple of 16-bytes if the vertical resizing factor
+ *  is greater than 1x (upsizing)
+ */
+static void resizer_set_output_size(struct isp_res_device *res,
+				    u32 width, u32 height)
+{
+	struct isp_device *isp = to_isp_device(res);
+	u32 rgval = 0;
+
+	dev_dbg(isp->dev, "Output size[w/h]: %dx%d\n", width, height);
+	rgval  = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT)
+		 & ISPRSZ_OUT_SIZE_HORZ_MASK;
+	rgval |= (height << ISPRSZ_OUT_SIZE_VERT_SHIFT)
+		 & ISPRSZ_OUT_SIZE_VERT_MASK;
+	isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE);
+}
+
+/*
+ * resizer_set_output_offset - Setup memory offset for the output lines.
+ * @res: Device context.
+ * @offset: Memory offset.
+ *
+ * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte
+ * boundary; the 5 LSBs are read-only. For optimal use of SDRAM bandwidth,
+ * the SDRAM line offset must be set on a 256-byte boundary
+ */
+static void resizer_set_output_offset(struct isp_res_device *res, u32 offset)
+{
+	struct isp_device *isp = to_isp_device(res);
+
+	isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
+}
+
+/*
+ * resizer_set_start - Setup vertical and horizontal start position
+ * @res: Device context.
+ * @left: Horizontal start position.
+ * @top: Vertical start position.
+ *
+ * Vertical start line:
+ *  This field makes sense only when the resizer obtains its input
+ *  from the preview engine/CCDC
+ *
+ * Horizontal start pixel:
+ *  Pixels are coded on 16 bits for YUV and 8 bits for color separate data.
+ *  When the resizer gets its input from SDRAM, this field must be set
+ *  to <= 15 for YUV 16-bit data and <= 31 for 8-bit color separate data
+ */
+static void resizer_set_start(struct isp_res_device *res, u32 left, u32 top)
+{
+	struct isp_device *isp = to_isp_device(res);
+	u32 rgval = 0;
+
+	rgval = (left << ISPRSZ_IN_START_HORZ_ST_SHIFT)
+		& ISPRSZ_IN_START_HORZ_ST_MASK;
+	rgval |= (top << ISPRSZ_IN_START_VERT_ST_SHIFT)
+		 & ISPRSZ_IN_START_VERT_ST_MASK;
+
+	isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
+}
+
+/*
+ * resizer_set_input_size - Setup the input size
+ * @res: Device context.
+ * @width: The range is 0 to 4095 pixels
+ * @height: The range is 0 to 4095 lines
+ */
+static void resizer_set_input_size(struct isp_res_device *res,
+				   u32 width, u32 height)
+{
+	struct isp_device *isp = to_isp_device(res);
+	u32 rgval = 0;
+
+	dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height);
+
+	rgval = (width << ISPRSZ_IN_SIZE_HORZ_SHIFT)
+		& ISPRSZ_IN_SIZE_HORZ_MASK;
+	rgval |= (height << ISPRSZ_IN_SIZE_VERT_SHIFT)
+		 & ISPRSZ_IN_SIZE_VERT_MASK;
+
+	isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE);
+}
+
+/*
+ * resizer_set_src_offs - Setup the memory offset for the input lines
+ * @res: Device context.
+ * @offset: Memory offset.
+ *
+ * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte
+ * boundary; the 5 LSBs are read-only. This field must be programmed to be
+ * 0x0 if the resizer input is from preview engine/CCDC.
+ */
+static void resizer_set_input_offset(struct isp_res_device *res, u32 offset)
+{
+	struct isp_device *isp = to_isp_device(res);
+
+	isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF);
+}
+
+/*
+ * resizer_set_intype - Input type select
+ * @res: Device context.
+ * @type: Pixel format type.
+ */
+static void resizer_set_intype(struct isp_res_device *res,
+			       enum resizer_colors_type type)
+{
+	struct isp_device *isp = to_isp_device(res);
+
+	if (type == RSZ_COLOR8)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+			    ISPRSZ_CNT_INPTYP);
+	else
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+			    ISPRSZ_CNT_INPTYP);
+}
+
+/*
+ * __resizer_set_inaddr - Helper function for set input address
+ * @res : pointer to resizer private data structure
+ * @addr: input address
+ * return none
+ */
+static void __resizer_set_inaddr(struct isp_res_device *res, u32 addr)
+{
+	struct isp_device *isp = to_isp_device(res);
+
+	isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
+}
+
+/*
+ * The data rate at the horizontal resizer output must not exceed half the
+ * functional clock or 100 MP/s, whichever is lower. According to the TRM
+ * there's no similar requirement for the vertical resizer output. However
+ * experience showed that vertical upscaling by 4 leads to SBL overflows (with
+ * data rates at the resizer output exceeding 300 MP/s). Limiting the resizer
+ * output data rate to the functional clock or 200 MP/s, whichever is lower,
+ * seems to get rid of SBL overflows.
+ *
+ * The maximum data rate at the output of the horizontal resizer can thus be
+ * computed with
+ *
+ * max intermediate rate <= L3 clock * input height / output height
+ * max intermediate rate <= L3 clock / 2
+ *
+ * The maximum data rate at the resizer input is then
+ *
+ * max input rate <= max intermediate rate * input width / output width
+ *
+ * where the input width and height are the resizer input crop rectangle size.
+ * The TRM doesn't clearly explain if that's a maximum instant data rate or a
+ * maximum average data rate.
+ */
+void omap3isp_resizer_max_rate(struct isp_res_device *res,
+			       unsigned int *max_rate)
+{
+	struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
+	const struct v4l2_mbus_framefmt *ofmt = &res->formats[RESZ_PAD_SOURCE];
+	unsigned long limit = min(pipe->l3_ick, 200000000UL);
+	unsigned long clock;
+
+	clock = div_u64((u64)limit * res->crop.active.height, ofmt->height);
+	clock = min(clock, limit / 2);
+	*max_rate = div_u64((u64)clock * res->crop.active.width, ofmt->width);
+}
+
+/*
+ * When the resizer processes images from memory, the driver must slow down read
+ * requests on the input to at least comply with the internal data rate
+ * requirements. If the application real-time requirements can cope with slower
+ * processing, the resizer can be slowed down even more to put less pressure on
+ * the overall system.
+ *
+ * When the resizer processes images on the fly (either from the CCDC or the
+ * preview module), the same data rate requirements apply but they can't be
+ * enforced at the resizer level. The image input module (sensor, CCP2 or
+ * preview module) must not provide image data faster than the resizer can
+ * process.
+ *
+ * For live image pipelines, the data rate is set by the frame format, size and
+ * rate. The sensor output frame rate must not exceed the maximum resizer data
+ * rate.
+ *
+ * The resizer slows down read requests by inserting wait cycles in the SBL
+ * requests. The maximum number of 256-byte requests per second can be computed
+ * as (the data rate is multiplied by 2 to convert from pixels per second to
+ * bytes per second)
+ *
+ * request per second = data rate * 2 / 256
+ * cycles per request = cycles per second / requests per second
+ *
+ * The number of cycles per second is controlled by the L3 clock, leading to
+ *
+ * cycles per request = L3 frequency / 2 * 256 / data rate
+ */
+static void resizer_adjust_bandwidth(struct isp_res_device *res)
+{
+	struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
+	struct isp_device *isp = to_isp_device(res);
+	unsigned long l3_ick = pipe->l3_ick;
+	struct v4l2_fract *timeperframe;
+	unsigned int cycles_per_frame;
+	unsigned int requests_per_frame;
+	unsigned int cycles_per_request;
+	unsigned int granularity;
+	unsigned int minimum;
+	unsigned int maximum;
+	unsigned int value;
+
+	if (res->input != RESIZER_INPUT_MEMORY) {
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
+			    ISPSBL_SDR_REQ_RSZ_EXP_MASK);
+		return;
+	}
+
+	switch (isp->revision) {
+	case ISP_REVISION_1_0:
+	case ISP_REVISION_2_0:
+	default:
+		granularity = 1024;
+		break;
+
+	case ISP_REVISION_15_0:
+		granularity = 32;
+		break;
+	}
+
+	/* Compute the minimum number of cycles per request, based on the
+	 * pipeline maximum data rate. This is an absolute lower bound if we
+	 * don't want SBL overflows, so round the value up.
+	 */
+	cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
+				     pipe->max_rate);
+	minimum = DIV_ROUND_UP(cycles_per_request, granularity);
+
+	/* Compute the maximum number of cycles per request, based on the
+	 * requested frame rate. This is a soft upper bound to achieve a frame
+	 * rate equal or higher than the requested value, so round the value
+	 * down.
+	 */
+	timeperframe = &pipe->max_timeperframe;
+
+	requests_per_frame = DIV_ROUND_UP(res->crop.active.width * 2, 256)
+			   * res->crop.active.height;
+	cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
+				   timeperframe->denominator);
+	cycles_per_request = cycles_per_frame / requests_per_frame;
+
+	maximum = cycles_per_request / granularity;
+
+	value = max(minimum, maximum);
+
+	dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
+	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
+			ISPSBL_SDR_REQ_RSZ_EXP_MASK,
+			value << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT);
+}
+
+/*
+ * omap3isp_resizer_busy - Checks if ISP resizer is busy.
+ *
+ * Returns busy field from ISPRSZ_PCR register.
+ */
+int omap3isp_resizer_busy(struct isp_res_device *res)
+{
+	struct isp_device *isp = to_isp_device(res);
+
+	return isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
+			     ISPRSZ_PCR_BUSY;
+}
+
+/*
+ * resizer_set_inaddr - Sets the memory address of the input frame.
+ * @addr: 32bit memory address aligned on 32byte boundary.
+ */
+static void resizer_set_inaddr(struct isp_res_device *res, u32 addr)
+{
+	res->addr_base = addr;
+
+	/* This will handle crop settings in stream off state */
+	if (res->crop_offset)
+		addr += res->crop_offset & ~0x1f;
+
+	__resizer_set_inaddr(res, addr);
+}
+
+/*
+ * Configures the memory address to which the output frame is written.
+ * @addr: 32bit memory address aligned on 32byte boundary.
+ * Note: For SBL efficiency reasons the address should be on a 256-byte
+ * boundary.
+ */
+static void resizer_set_outaddr(struct isp_res_device *res, u32 addr)
+{
+	struct isp_device *isp = to_isp_device(res);
+
+	/*
+	 * Set output address. This needs to be in its own function
+	 * because it changes often.
+	 */
+	isp_reg_writel(isp, addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT,
+		       OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
+}
+
+/*
+ * resizer_print_status - Prints the values of the resizer module registers.
+ */
+#define RSZ_PRINT_REGISTER(isp, name)\
+	dev_dbg(isp->dev, "###RSZ " #name "=0x%08x\n", \
+		isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_##name))
+
+static void resizer_print_status(struct isp_res_device *res)
+{
+	struct isp_device *isp = to_isp_device(res);
+
+	dev_dbg(isp->dev, "-------------Resizer Register dump----------\n");
+
+	RSZ_PRINT_REGISTER(isp, PCR);
+	RSZ_PRINT_REGISTER(isp, CNT);
+	RSZ_PRINT_REGISTER(isp, OUT_SIZE);
+	RSZ_PRINT_REGISTER(isp, IN_START);
+	RSZ_PRINT_REGISTER(isp, IN_SIZE);
+	RSZ_PRINT_REGISTER(isp, SDR_INADD);
+	RSZ_PRINT_REGISTER(isp, SDR_INOFF);
+	RSZ_PRINT_REGISTER(isp, SDR_OUTADD);
+	RSZ_PRINT_REGISTER(isp, SDR_OUTOFF);
+	RSZ_PRINT_REGISTER(isp, YENH);
+
+	dev_dbg(isp->dev, "--------------------------------------------\n");
+}
+
+/*
+ * resizer_calc_ratios - Helper function for calculating resizer ratios
+ * @res: pointer to resizer private data structure
+ * @input: input frame size
+ * @output: output frame size
+ * @ratio : return calculated ratios
+ * return none
+ *
+ * The resizer uses a polyphase sample rate converter. The upsampling filter
+ * has a fixed number of phases that depend on the resizing ratio. As the ratio
+ * computation depends on the number of phases, we need to compute a first
+ * approximation and then refine it.
+ *
+ * The input/output/ratio relationship is given by the OMAP34xx TRM:
+ *
+ * - 8-phase, 4-tap mode (RSZ = 64 ~ 512)
+ *	iw = (32 * sph + (ow - 1) * hrsz + 16) >> 8 + 7
+ *	ih = (32 * spv + (oh - 1) * vrsz + 16) >> 8 + 4
+ * - 4-phase, 7-tap mode (RSZ = 513 ~ 1024)
+ *	iw = (64 * sph + (ow - 1) * hrsz + 32) >> 8 + 7
+ *	ih = (64 * spv + (oh - 1) * vrsz + 32) >> 8 + 7
+ *
+ * iw and ih are the input width and height after cropping. Those equations need
+ * to be satisfied exactly for the resizer to work correctly.
+ *
+ * The equations can't be easily reverted, as the >> 8 operation is not linear.
+ * In addition, not all input sizes can be achieved for a given output size. To
+ * get the highest input size lower than or equal to the requested input size,
+ * we need to compute the highest resizing ratio that satisfies the following
+ * inequality (taking the 4-tap mode width equation as an example)
+ *
+ *	iw >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 - 7
+ *
+ * (where iw is the requested input width) which can be rewritten as
+ *
+ *	  iw - 7            >= (32 * sph + (ow - 1) * hrsz + 16) >> 8
+ *	 (iw - 7) << 8      >=  32 * sph + (ow - 1) * hrsz + 16 - b
+ *	((iw - 7) << 8) + b >=  32 * sph + (ow - 1) * hrsz + 16
+ *
+ * where b is the value of the 8 least significant bits of the right hand side
+ * expression of the last inequality. The highest resizing ratio value will be
+ * achieved when b is equal to its maximum value of 255. That resizing ratio
+ * value will still satisfy the original inequality, as b will disappear when
+ * the expression will be shifted right by 8.
+ *
+ * The reverted equations thus become
+ *
+ * - 8-phase, 4-tap mode
+ *	hrsz = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / (ow - 1)
+ *	vrsz = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / (oh - 1)
+ * - 4-phase, 7-tap mode
+ *	hrsz = ((iw - 7) * 256 + 255 - 32 - 64 * sph) / (ow - 1)
+ *	vrsz = ((ih - 7) * 256 + 255 - 32 - 64 * spv) / (oh - 1)
+ *
+ * The ratios are integer values, and are rounded down to ensure that the
+ * cropped input size is not bigger than the uncropped input size.
+ *
+ * As the number of phases/taps, used to select the correct equations to compute
+ * the ratio, depends on the ratio, we start with the 4-tap mode equations to
+ * compute an approximation of the ratio, and switch to the 7-tap mode equations
+ * if the approximation is higher than the ratio threshold.
+ *
+ * As the 7-tap mode equations will return a ratio smaller than or equal to the
+ * 4-tap mode equations, the resulting ratio could become lower than or equal to
+ * the ratio threshold. This 'equations loop' isn't an issue as long as the
+ * correct equations are used to compute the final input size. Starting with the
+ * 4-tap mode equations ensure that, in case of values resulting in a 'ratio
+ * loop', the smallest of the ratio values will be used, never exceeding the
+ * requested input size.
+ *
+ * We first clamp the output size according to the hardware capability to avoid
+ * auto-cropping the input more than required to satisfy the TRM equations. The
+ * minimum output size is achieved with a scaling factor of 1024. It is thus
+ * computed using the 7-tap equations.
+ *
+ *	min ow = ((iw - 7) * 256 - 32 - 64 * sph) / 1024 + 1
+ *	min oh = ((ih - 7) * 256 - 32 - 64 * spv) / 1024 + 1
+ *
+ * Similarly, the maximum output size is achieved with a scaling factor of 64
+ * and computed using the 4-tap equations.
+ *
+ *	max ow = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / 64 + 1
+ *	max oh = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1
+ *
+ * The additional +255 term compensates for the round down operation performed
+ * by the TRM equations when shifting the value right by 8 bits.
+ *
+ * We then compute and clamp the ratios (x1/4 ~ x4). Clamping the output size to
+ * the maximum value guarantees that the ratio value will never be smaller than
+ * the minimum, but it could still slightly exceed the maximum. Clamping the
+ * ratio will thus result in a resizing factor slightly larger than the
+ * requested value.
+ *
+ * To accommodate that, and make sure the TRM equations are satisfied exactly, we
+ * compute the input crop rectangle as the last step.
+ *
+ * As if the situation wasn't complex enough, the maximum output width depends
+ * on the vertical resizing ratio.  Fortunately, the output height doesn't
+ * depend on the horizontal resizing ratio. We can then start by computing the
+ * output height and the vertical ratio, and then move to computing the output
+ * width and the horizontal ratio.
+ */
+static void resizer_calc_ratios(struct isp_res_device *res,
+				struct v4l2_rect *input,
+				struct v4l2_mbus_framefmt *output,
+				struct resizer_ratio *ratio)
+{
+	struct isp_device *isp = to_isp_device(res);
+	const unsigned int spv = DEFAULT_PHASE;
+	const unsigned int sph = DEFAULT_PHASE;
+	unsigned int upscaled_width;
+	unsigned int upscaled_height;
+	unsigned int min_width;
+	unsigned int min_height;
+	unsigned int max_width;
+	unsigned int max_height;
+	unsigned int width_alignment;
+	unsigned int width;
+	unsigned int height;
+
+	/*
+	 * Clamp the output height based on the hardware capabilities and
+	 * compute the vertical resizing ratio.
+	 */
+	min_height = ((input->height - 7) * 256 - 32 - 64 * spv) / 1024 + 1;
+	min_height = max_t(unsigned int, min_height, MIN_OUT_HEIGHT);
+	max_height = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1;
+	max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT);
+	output->height = clamp(output->height, min_height, max_height);
+
+	ratio->vert = ((input->height - 4) * 256 + 255 - 16 - 32 * spv)
+		    / (output->height - 1);
+	if (ratio->vert > MID_RESIZE_VALUE)
+		ratio->vert = ((input->height - 7) * 256 + 255 - 32 - 64 * spv)
+			    / (output->height - 1);
+	ratio->vert = clamp_t(unsigned int, ratio->vert,
+			      MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
+
+	if (ratio->vert <= MID_RESIZE_VALUE) {
+		upscaled_height = (output->height - 1) * ratio->vert
+				+ 32 * spv + 16;
+		height = (upscaled_height >> 8) + 4;
+	} else {
+		upscaled_height = (output->height - 1) * ratio->vert
+				+ 64 * spv + 32;
+		height = (upscaled_height >> 8) + 7;
+	}
+
+	/*
+	 * Compute the minimum and maximum output widths based on the hardware
+	 * capabilities. The maximum depends on the vertical resizing ratio.
+	 */
+	min_width = ((input->width - 7) * 256 - 32 - 64 * sph) / 1024 + 1;
+	min_width = max_t(unsigned int, min_width, MIN_OUT_WIDTH);
+
+	if (ratio->vert <= MID_RESIZE_VALUE) {
+		switch (isp->revision) {
+		case ISP_REVISION_1_0:
+			max_width = MAX_4TAP_OUT_WIDTH_ES1;
+			break;
+
+		case ISP_REVISION_2_0:
+		default:
+			max_width = MAX_4TAP_OUT_WIDTH_ES2;
+			break;
+
+		case ISP_REVISION_15_0:
+			max_width = MAX_4TAP_OUT_WIDTH_3630;
+			break;
+		}
+	} else {
+		switch (isp->revision) {
+		case ISP_REVISION_1_0:
+			max_width = MAX_7TAP_OUT_WIDTH_ES1;
+			break;
+
+		case ISP_REVISION_2_0:
+		default:
+			max_width = MAX_7TAP_OUT_WIDTH_ES2;
+			break;
+
+		case ISP_REVISION_15_0:
+			max_width = MAX_7TAP_OUT_WIDTH_3630;
+			break;
+		}
+	}
+	max_width = min(((input->width - 7) * 256 + 255 - 16 - 32 * sph) / 64
+			+ 1, max_width);
+
+	/*
+	 * The output width must be even, and must be a multiple of 16 bytes
+	 * when upscaling vertically. Clamp the output width to the valid range.
+	 * Take the alignment into account (the maximum width in 7-tap mode on
+	 * ES2 isn't a multiple of 8) and align the result up to make sure it
+	 * won't be smaller than the minimum.
+	 */
+	width_alignment = ratio->vert < 256 ? 8 : 2;
+	output->width = clamp(output->width, min_width,
+			      max_width & ~(width_alignment - 1));
+	output->width = ALIGN(output->width, width_alignment);
+
+	ratio->horz = ((input->width - 7) * 256 + 255 - 16 - 32 * sph)
+		    / (output->width - 1);
+	if (ratio->horz > MID_RESIZE_VALUE)
+		ratio->horz = ((input->width - 7) * 256 + 255 - 32 - 64 * sph)
+			    / (output->width - 1);
+	ratio->horz = clamp_t(unsigned int, ratio->horz,
+			      MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
+
+	if (ratio->horz <= MID_RESIZE_VALUE) {
+		upscaled_width = (output->width - 1) * ratio->horz
+			       + 32 * sph + 16;
+		width = (upscaled_width >> 8) + 7;
+	} else {
+		upscaled_width = (output->width - 1) * ratio->horz
+			       + 64 * sph + 32;
+		width = (upscaled_width >> 8) + 7;
+	}
+
+	/* Center the new crop rectangle. */
+	input->left += (input->width - width) / 2;
+	input->top += (input->height - height) / 2;
+	input->width = width;
+	input->height = height;
+}
+
+/*
+ * resizer_set_crop_params - Setup hardware with cropping parameters
+ * @res : resizer private structure
+ * @crop_rect : current crop rectangle
+ * @ratio : resizer ratios
+ * return none
+ */
+static void resizer_set_crop_params(struct isp_res_device *res,
+				    const struct v4l2_mbus_framefmt *input,
+				    const struct v4l2_mbus_framefmt *output)
+{
+	resizer_set_ratio(res, &res->ratio);
+
+	/* Set chrominance horizontal algorithm */
+	if (res->ratio.horz >= RESIZE_DIVISOR)
+		resizer_set_bilinear(res, RSZ_THE_SAME);
+	else
+		resizer_set_bilinear(res, RSZ_BILINEAR);
+
+	resizer_adjust_bandwidth(res);
+
+	if (res->input == RESIZER_INPUT_MEMORY) {
+		/* Calculate additional offset for crop */
+		res->crop_offset = (res->crop.active.top * input->width +
+				    res->crop.active.left) * 2;
+		/*
+		 * Write lowest 4 bits of horizontal pixel offset (in pixels),
+		 * vertical start must be 0.
+		 */
+		resizer_set_start(res, (res->crop_offset / 2) & 0xf, 0);
+
+		/*
+		 * Set start (read) address for cropping, in bytes.
+		 * Lowest 5 bits must be zero.
+		 */
+		__resizer_set_inaddr(res,
+				res->addr_base + (res->crop_offset & ~0x1f));
+	} else {
+		/*
+		 * Set vertical start line and horizontal starting pixel.
+		 * If the input is from CCDC/PREV, horizontal start field is
+		 * in bytes (twice number of pixels).
+		 */
+		resizer_set_start(res, res->crop.active.left * 2,
+				  res->crop.active.top);
+		/* Input address and offset must be 0 for preview/ccdc input */
+		__resizer_set_inaddr(res, 0);
+		resizer_set_input_offset(res, 0);
+	}
+
+	/* Set the input size */
+	resizer_set_input_size(res, res->crop.active.width,
+			       res->crop.active.height);
+}
+
+static void resizer_configure(struct isp_res_device *res)
+{
+	struct v4l2_mbus_framefmt *informat, *outformat;
+	struct resizer_luma_yenh luma = {0, 0, 0, 0};
+
+	resizer_set_source(res, res->input);
+
+	informat = &res->formats[RESZ_PAD_SINK];
+	outformat = &res->formats[RESZ_PAD_SOURCE];
+
+	/* RESZ_PAD_SINK */
+	if (res->input == RESIZER_INPUT_VP)
+		resizer_set_input_offset(res, 0);
+	else
+		resizer_set_input_offset(res, ALIGN(informat->width, 0x10) * 2);
+
+	/* YUV422 interleaved, default phase, no luma enhancement */
+	resizer_set_intype(res, RSZ_YUV422);
+	resizer_set_ycpos(res, informat->code);
+	resizer_set_phase(res, DEFAULT_PHASE, DEFAULT_PHASE);
+	resizer_set_luma(res, &luma);
+
+	/* RESZ_PAD_SOURCE */
+	resizer_set_output_offset(res, ALIGN(outformat->width * 2, 32));
+	resizer_set_output_size(res, outformat->width, outformat->height);
+
+	resizer_set_crop_params(res, informat, outformat);
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+static void resizer_enable_oneshot(struct isp_res_device *res)
+{
+	struct isp_device *isp = to_isp_device(res);
+
+	isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR,
+		    ISPRSZ_PCR_ENABLE | ISPRSZ_PCR_ONESHOT);
+}
+
+void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res)
+{
+	/*
+	 * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
+	 * condition, the module was paused and now we have a buffer queued
+	 * on the output again. Restart the pipeline if running in continuous
+	 * mode.
+	 */
+	if (res->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
+	    res->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
+		resizer_enable_oneshot(res);
+		isp_video_dmaqueue_flags_clr(&res->video_out);
+	}
+}
+
+static void resizer_isr_buffer(struct isp_res_device *res)
+{
+	struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
+	struct isp_buffer *buffer;
+	int restart = 0;
+
+	if (res->state == ISP_PIPELINE_STREAM_STOPPED)
+		return;
+
+	/* Complete the output buffer and, if reading from memory, the input
+	 * buffer.
+	 */
+	buffer = omap3isp_video_buffer_next(&res->video_out);
+	if (buffer != NULL) {
+		resizer_set_outaddr(res, buffer->isp_addr);
+		restart = 1;
+	}
+
+	pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
+
+	if (res->input == RESIZER_INPUT_MEMORY) {
+		buffer = omap3isp_video_buffer_next(&res->video_in);
+		if (buffer != NULL)
+			resizer_set_inaddr(res, buffer->isp_addr);
+		pipe->state |= ISP_PIPELINE_IDLE_INPUT;
+	}
+
+	if (res->state == ISP_PIPELINE_STREAM_SINGLESHOT) {
+		if (isp_pipeline_ready(pipe))
+			omap3isp_pipeline_set_stream(pipe,
+						ISP_PIPELINE_STREAM_SINGLESHOT);
+	} else {
+		/* If an underrun occurs, the video queue operation handler will
+		 * restart the resizer. Otherwise restart it immediately.
+		 */
+		if (restart)
+			resizer_enable_oneshot(res);
+	}
+}
+
+/*
+ * omap3isp_resizer_isr - ISP resizer interrupt handler
+ *
+ * Manage the resizer video buffers and configure shadowed and busy-locked
+ * registers.
+ */
+void omap3isp_resizer_isr(struct isp_res_device *res)
+{
+	struct v4l2_mbus_framefmt *informat, *outformat;
+
+	if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping))
+		return;
+
+	if (res->applycrop) {
+		outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE,
+					      V4L2_SUBDEV_FORMAT_ACTIVE);
+		informat = __resizer_get_format(res, NULL, RESZ_PAD_SINK,
+					      V4L2_SUBDEV_FORMAT_ACTIVE);
+		resizer_set_crop_params(res, informat, outformat);
+		res->applycrop = 0;
+	}
+
+	resizer_isr_buffer(res);
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP video operations
+ */
+
+static int resizer_video_queue(struct isp_video *video,
+			       struct isp_buffer *buffer)
+{
+	struct isp_res_device *res = &video->isp->isp_res;
+
+	if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		resizer_set_inaddr(res, buffer->isp_addr);
+
+	/*
+	 * We now have a buffer queued on the output. Despite what the
+	 * TRM says, the resizer can't be restarted immediately.
+	 * Enabling it in one shot mode in the middle of a frame (or at
+	 * least asynchronously to the frame) results in the output
+	 * being shifted randomly left/right and up/down, as if the
+	 * hardware didn't synchronize itself to the beginning of the
+	 * frame correctly.
+	 *
+	 * Restart the resizer on the next sync interrupt if running in
+	 * continuous mode or when starting the stream.
+	 */
+	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		resizer_set_outaddr(res, buffer->isp_addr);
+
+	return 0;
+}
+
+static const struct isp_video_operations resizer_video_ops = {
+	.queue = resizer_video_queue,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+/*
+ * resizer_set_stream - Enable/Disable streaming on resizer subdev
+ * @sd: ISP resizer V4L2 subdev
+ * @enable: 1 == Enable, 0 == Disable
+ *
+ * The resizer hardware can't be enabled without a memory buffer to write to.
+ * As the s_stream operation is called in response to a STREAMON call without
+ * any buffer queued yet, just update the state field and return immediately.
+ * The resizer will be enabled in resizer_video_queue().
+ */
+static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct isp_res_device *res = v4l2_get_subdevdata(sd);
+	struct isp_video *video_out = &res->video_out;
+	struct isp_device *isp = to_isp_device(res);
+	struct device *dev = to_device(res);
+
+	if (res->state == ISP_PIPELINE_STREAM_STOPPED) {
+		if (enable == ISP_PIPELINE_STREAM_STOPPED)
+			return 0;
+
+		omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER);
+		resizer_configure(res);
+		resizer_print_status(res);
+	}
+
+	switch (enable) {
+	case ISP_PIPELINE_STREAM_CONTINUOUS:
+		omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
+		if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
+			resizer_enable_oneshot(res);
+			isp_video_dmaqueue_flags_clr(video_out);
+		}
+		break;
+
+	case ISP_PIPELINE_STREAM_SINGLESHOT:
+		if (res->input == RESIZER_INPUT_MEMORY)
+			omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_READ);
+		omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
+
+		resizer_enable_oneshot(res);
+		break;
+
+	case ISP_PIPELINE_STREAM_STOPPED:
+		if (omap3isp_module_sync_idle(&sd->entity, &res->wait,
+					      &res->stopping))
+			dev_dbg(dev, "%s: module stop timeout.\n", sd->name);
+		omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_RESIZER_READ |
+				OMAP3_ISP_SBL_RESIZER_WRITE);
+		omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_RESIZER);
+		isp_video_dmaqueue_flags_clr(video_out);
+		break;
+	}
+
+	res->state = enable;
+	return 0;
+}
+
+/*
+ * resizer_try_crop - mangles crop parameters.
+ */
+static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
+			     const struct v4l2_mbus_framefmt *source,
+			     struct v4l2_rect *crop)
+{
+	const unsigned int spv = DEFAULT_PHASE;
+	const unsigned int sph = DEFAULT_PHASE;
+
+	/* Crop rectangle is constrained by the output size so that zoom ratio
+	 * cannot exceed +/-4.0.
+	 */
+	unsigned int min_width =
+		((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7;
+	unsigned int min_height =
+		((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4;
+	unsigned int max_width =
+		((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7;
+	unsigned int max_height =
+		((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7;
+
+	crop->width = clamp_t(u32, crop->width, min_width, max_width);
+	crop->height = clamp_t(u32, crop->height, min_height, max_height);
+
+	/* Crop can not go beyond of the input rectangle */
+	crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH);
+	crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH,
+			      sink->width - crop->left);
+	crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT);
+	crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT,
+			       sink->height - crop->top);
+}
+
+/*
+ * resizer_get_selection - Retrieve a selection rectangle on a pad
+ * @sd: ISP resizer V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangles are the crop rectangles on the sink pad.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int resizer_get_selection(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_selection *sel)
+{
+	struct isp_res_device *res = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format_source;
+	struct v4l2_mbus_framefmt *format_sink;
+	struct resizer_ratio ratio;
+
+	if (sel->pad != RESZ_PAD_SINK)
+		return -EINVAL;
+
+	format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
+					   sel->which);
+	format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
+					     sel->which);
+
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		sel->r.left = 0;
+		sel->r.top = 0;
+		sel->r.width = INT_MAX;
+		sel->r.height = INT_MAX;
+
+		resizer_try_crop(format_sink, format_source, &sel->r);
+		resizer_calc_ratios(res, &sel->r, format_source, &ratio);
+		break;
+
+	case V4L2_SEL_TGT_CROP:
+		sel->r = *__resizer_get_crop(res, fh, sel->which);
+		resizer_calc_ratios(res, &sel->r, format_source, &ratio);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * resizer_set_selection - Set a selection rectangle on a pad
+ * @sd: ISP resizer V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangle is the actual crop rectangle on the sink pad.
+ *
+ * FIXME: This function currently behaves as if the KEEP_CONFIG selection flag
+ * was always set.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int resizer_set_selection(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_selection *sel)
+{
+	struct isp_res_device *res = v4l2_get_subdevdata(sd);
+	struct isp_device *isp = to_isp_device(res);
+	struct v4l2_mbus_framefmt *format_sink, *format_source;
+	struct resizer_ratio ratio;
+
+	if (sel->target != V4L2_SEL_TGT_CROP ||
+	    sel->pad != RESZ_PAD_SINK)
+		return -EINVAL;
+
+	format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
+					   sel->which);
+	format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
+					     sel->which);
+
+	dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
+		sel->r.left, sel->r.top, sel->r.width, sel->r.height,
+		sel->which);
+
+	dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
+		format_sink->width, format_sink->height,
+		format_source->width, format_source->height);
+
+	/* Clamp the crop rectangle to the bounds, and then mangle it further to
+	 * fulfill the TRM equations. Store the clamped but otherwise unmangled
+	 * rectangle to avoid cropping the input multiple times: when an
+	 * application sets the output format, the current crop rectangle is
+	 * mangled during crop rectangle computation, which would lead to a new,
+	 * smaller input crop rectangle every time the output size is set if we
+	 * stored the mangled rectangle.
+	 */
+	resizer_try_crop(format_sink, format_source, &sel->r);
+	*__resizer_get_crop(res, fh, sel->which) = sel->r;
+	resizer_calc_ratios(res, &sel->r, format_source, &ratio);
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
+		return 0;
+
+	res->ratio = ratio;
+	res->crop.active = sel->r;
+
+	/*
+	 * set_selection can be called while streaming is on. In this case the
+	 * crop values will be set in the next IRQ.
+	 */
+	if (res->state != ISP_PIPELINE_STREAM_STOPPED)
+		res->applycrop = 1;
+
+	return 0;
+}
+
+/* resizer pixel formats */
+static const unsigned int resizer_formats[] = {
+	V4L2_MBUS_FMT_UYVY8_1X16,
+	V4L2_MBUS_FMT_YUYV8_1X16,
+};
+
+static unsigned int resizer_max_in_width(struct isp_res_device *res)
+{
+	struct isp_device *isp = to_isp_device(res);
+
+	if (res->input == RESIZER_INPUT_MEMORY) {
+		return MAX_IN_WIDTH_MEMORY_MODE;
+	} else {
+		if (isp->revision == ISP_REVISION_1_0)
+			return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1;
+		else
+			return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
+	}
+}
+
+/*
+ * resizer_try_format - Handle try format by pad subdev method
+ * @res   : ISP resizer device
+ * @fh    : V4L2 subdev file handle
+ * @pad   : pad num
+ * @fmt   : pointer to v4l2 format structure
+ * @which : wanted subdev format
+ */
+static void resizer_try_format(struct isp_res_device *res,
+			       struct v4l2_subdev_fh *fh, unsigned int pad,
+			       struct v4l2_mbus_framefmt *fmt,
+			       enum v4l2_subdev_format_whence which)
+{
+	struct v4l2_mbus_framefmt *format;
+	struct resizer_ratio ratio;
+	struct v4l2_rect crop;
+
+	switch (pad) {
+	case RESZ_PAD_SINK:
+		if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 &&
+		    fmt->code != V4L2_MBUS_FMT_UYVY8_1X16)
+			fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
+
+		fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
+				     resizer_max_in_width(res));
+		fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
+				      MAX_IN_HEIGHT);
+		break;
+
+	case RESZ_PAD_SOURCE:
+		format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which);
+		fmt->code = format->code;
+
+		crop = *__resizer_get_crop(res, fh, which);
+		resizer_calc_ratios(res, &crop, fmt, &ratio);
+		break;
+	}
+
+	fmt->colorspace = V4L2_COLORSPACE_JPEG;
+	fmt->field = V4L2_FIELD_NONE;
+}
+
+/*
+ * resizer_enum_mbus_code - Handle pixel format enumeration
+ * @sd     : pointer to v4l2 subdev structure
+ * @fh     : V4L2 subdev file handle
+ * @code   : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct isp_res_device *res = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	if (code->pad == RESZ_PAD_SINK) {
+		if (code->index >= ARRAY_SIZE(resizer_formats))
+			return -EINVAL;
+
+		code->code = resizer_formats[code->index];
+	} else {
+		if (code->index != 0)
+			return -EINVAL;
+
+		format = __resizer_get_format(res, fh, RESZ_PAD_SINK,
+					      V4L2_SUBDEV_FORMAT_TRY);
+		code->code = format->code;
+	}
+
+	return 0;
+}
+
+static int resizer_enum_frame_size(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_fh *fh,
+				   struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct isp_res_device *res = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt format;
+
+	if (fse->index != 0)
+		return -EINVAL;
+
+	format.code = fse->code;
+	format.width = 1;
+	format.height = 1;
+	resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+	fse->min_width = format.width;
+	fse->min_height = format.height;
+
+	if (format.code != fse->code)
+		return -EINVAL;
+
+	format.code = fse->code;
+	format.width = -1;
+	format.height = -1;
+	resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+	fse->max_width = format.width;
+	fse->max_height = format.height;
+
+	return 0;
+}
+
+/*
+ * resizer_get_format - Handle get format by pads subdev method
+ * @sd    : pointer to v4l2 subdev structure
+ * @fh    : V4L2 subdev file handle
+ * @fmt   : pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_format *fmt)
+{
+	struct isp_res_device *res = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
+	if (format == NULL)
+		return -EINVAL;
+
+	fmt->format = *format;
+	return 0;
+}
+
+/*
+ * resizer_set_format - Handle set format by pads subdev method
+ * @sd    : pointer to v4l2 subdev structure
+ * @fh    : V4L2 subdev file handle
+ * @fmt   : pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_format *fmt)
+{
+	struct isp_res_device *res = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *format;
+	struct v4l2_rect *crop;
+
+	format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
+	if (format == NULL)
+		return -EINVAL;
+
+	resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which);
+	*format = fmt->format;
+
+	if (fmt->pad == RESZ_PAD_SINK) {
+		/* reset crop rectangle */
+		crop = __resizer_get_crop(res, fh, fmt->which);
+		crop->left = 0;
+		crop->top = 0;
+		crop->width = fmt->format.width;
+		crop->height = fmt->format.height;
+
+		/* Propagate the format from sink to source */
+		format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
+					      fmt->which);
+		*format = fmt->format;
+		resizer_try_format(res, fh, RESZ_PAD_SOURCE, format,
+				   fmt->which);
+	}
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		/* Compute and store the active crop rectangle and resizer
+		 * ratios. format already points to the source pad active
+		 * format.
+		 */
+		res->crop.active = res->crop.request;
+		resizer_calc_ratios(res, &res->crop.active, format,
+				       &res->ratio);
+	}
+
+	return 0;
+}
+
+/*
+ * resizer_init_formats - Initialize formats on all pads
+ * @sd: ISP resizer V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int resizer_init_formats(struct v4l2_subdev *sd,
+				struct v4l2_subdev_fh *fh)
+{
+	struct v4l2_subdev_format format;
+
+	memset(&format, 0, sizeof(format));
+	format.pad = RESZ_PAD_SINK;
+	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+	format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
+	format.format.width = 4096;
+	format.format.height = 4096;
+	resizer_set_format(sd, fh, &format);
+
+	return 0;
+}
+
+/* subdev video operations */
+static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
+	.s_stream = resizer_set_stream,
+};
+
+/* subdev pad operations */
+static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
+	.enum_mbus_code = resizer_enum_mbus_code,
+	.enum_frame_size = resizer_enum_frame_size,
+	.get_fmt = resizer_get_format,
+	.set_fmt = resizer_set_format,
+	.get_selection = resizer_get_selection,
+	.set_selection = resizer_set_selection,
+};
+
+/* subdev operations */
+static const struct v4l2_subdev_ops resizer_v4l2_ops = {
+	.video = &resizer_v4l2_video_ops,
+	.pad = &resizer_v4l2_pad_ops,
+};
+
+/* subdev internal operations */
+static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
+	.open = resizer_init_formats,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * resizer_link_setup - Setup resizer connections.
+ * @entity : Pointer to media entity structure
+ * @local  : Pointer to local pad array
+ * @remote : Pointer to remote pad array
+ * @flags  : Link flags
+ * return -EINVAL or zero on success
+ */
+static int resizer_link_setup(struct media_entity *entity,
+			      const struct media_pad *local,
+			      const struct media_pad *remote, u32 flags)
+{
+	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+	struct isp_res_device *res = v4l2_get_subdevdata(sd);
+
+	switch (local->index | media_entity_type(remote->entity)) {
+	case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
+		/* read from memory */
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			if (res->input == RESIZER_INPUT_VP)
+				return -EBUSY;
+			res->input = RESIZER_INPUT_MEMORY;
+		} else {
+			if (res->input == RESIZER_INPUT_MEMORY)
+				res->input = RESIZER_INPUT_NONE;
+		}
+		break;
+
+	case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+		/* read from ccdc or previewer */
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			if (res->input == RESIZER_INPUT_MEMORY)
+				return -EBUSY;
+			res->input = RESIZER_INPUT_VP;
+		} else {
+			if (res->input == RESIZER_INPUT_VP)
+				res->input = RESIZER_INPUT_NONE;
+		}
+		break;
+
+	case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+		/* resizer always write to memory */
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations resizer_media_ops = {
+	.link_setup = resizer_link_setup,
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
+{
+	v4l2_device_unregister_subdev(&res->subdev);
+	omap3isp_video_unregister(&res->video_in);
+	omap3isp_video_unregister(&res->video_out);
+}
+
+int omap3isp_resizer_register_entities(struct isp_res_device *res,
+				       struct v4l2_device *vdev)
+{
+	int ret;
+
+	/* Register the subdev and video nodes. */
+	ret = v4l2_device_register_subdev(vdev, &res->subdev);
+	if (ret < 0)
+		goto error;
+
+	ret = omap3isp_video_register(&res->video_in, vdev);
+	if (ret < 0)
+		goto error;
+
+	ret = omap3isp_video_register(&res->video_out, vdev);
+	if (ret < 0)
+		goto error;
+
+	return 0;
+
+error:
+	omap3isp_resizer_unregister_entities(res);
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP resizer initialization and cleanup
+ */
+
+/*
+ * resizer_init_entities - Initialize resizer subdev and media entity.
+ * @res : Pointer to resizer device structure
+ * return -ENOMEM or zero on success
+ */
+static int resizer_init_entities(struct isp_res_device *res)
+{
+	struct v4l2_subdev *sd = &res->subdev;
+	struct media_pad *pads = res->pads;
+	struct media_entity *me = &sd->entity;
+	int ret;
+
+	res->input = RESIZER_INPUT_NONE;
+
+	v4l2_subdev_init(sd, &resizer_v4l2_ops);
+	sd->internal_ops = &resizer_v4l2_internal_ops;
+	strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
+	sd->grp_id = 1 << 16;	/* group ID for isp subdevs */
+	v4l2_set_subdevdata(sd, res);
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+	me->ops = &resizer_media_ops;
+	ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
+	if (ret < 0)
+		return ret;
+
+	resizer_init_formats(sd, NULL);
+
+	res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	res->video_in.ops = &resizer_video_ops;
+	res->video_in.isp = to_isp_device(res);
+	res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
+	res->video_in.bpl_alignment = 32;
+	res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	res->video_out.ops = &resizer_video_ops;
+	res->video_out.isp = to_isp_device(res);
+	res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
+	res->video_out.bpl_alignment = 32;
+
+	ret = omap3isp_video_init(&res->video_in, "resizer");
+	if (ret < 0)
+		goto error_video_in;
+
+	ret = omap3isp_video_init(&res->video_out, "resizer");
+	if (ret < 0)
+		goto error_video_out;
+
+	res->video_out.video.entity.flags |= MEDIA_ENT_FL_DEFAULT;
+
+	/* Connect the video nodes to the resizer subdev. */
+	ret = media_entity_create_link(&res->video_in.video.entity, 0,
+			&res->subdev.entity, RESZ_PAD_SINK, 0);
+	if (ret < 0)
+		goto error_link;
+
+	ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
+			&res->video_out.video.entity, 0, 0);
+	if (ret < 0)
+		goto error_link;
+
+	return 0;
+
+error_link:
+	omap3isp_video_cleanup(&res->video_out);
+error_video_out:
+	omap3isp_video_cleanup(&res->video_in);
+error_video_in:
+	media_entity_cleanup(&res->subdev.entity);
+	return ret;
+}
+
+/*
+ * isp_resizer_init - Resizer initialization.
+ * @isp : Pointer to ISP device
+ * return -ENOMEM or zero on success
+ */
+int omap3isp_resizer_init(struct isp_device *isp)
+{
+	struct isp_res_device *res = &isp->isp_res;
+
+	init_waitqueue_head(&res->wait);
+	atomic_set(&res->stopping, 0);
+	return resizer_init_entities(res);
+}
+
+void omap3isp_resizer_cleanup(struct isp_device *isp)
+{
+	struct isp_res_device *res = &isp->isp_res;
+
+	omap3isp_video_cleanup(&res->video_in);
+	omap3isp_video_cleanup(&res->video_out);
+	media_entity_cleanup(&res->subdev.entity);
+}
diff --git a/drivers/media/platform/omap3isp/ispresizer.h b/drivers/media/platform/omap3isp/ispresizer.h
new file mode 100644
index 0000000..70c1c0e
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispresizer.h
@@ -0,0 +1,146 @@
+/*
+ * ispresizer.h
+ *
+ * TI OMAP3 ISP - Resizer module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_RESIZER_H
+#define OMAP3_ISP_RESIZER_H
+
+#include <linux/types.h>
+
+/*
+ * Constants for filter coefficents count
+ */
+#define COEFF_CNT		32
+
+/*
+ * struct isprsz_coef - Structure for resizer filter coeffcients.
+ * @h_filter_coef_4tap: Horizontal filter coefficients for 8-phase/4-tap
+ *			mode (.5x-4x)
+ * @v_filter_coef_4tap: Vertical filter coefficients for 8-phase/4-tap
+ *			mode (.5x-4x)
+ * @h_filter_coef_7tap: Horizontal filter coefficients for 4-phase/7-tap
+ *			mode (.25x-.5x)
+ * @v_filter_coef_7tap: Vertical filter coefficients for 4-phase/7-tap
+ *			mode (.25x-.5x)
+ */
+struct isprsz_coef {
+	u16 h_filter_coef_4tap[32];
+	u16 v_filter_coef_4tap[32];
+	/* Every 8th value is a dummy value in the following arrays: */
+	u16 h_filter_coef_7tap[32];
+	u16 v_filter_coef_7tap[32];
+};
+
+/* Chrominance horizontal algorithm */
+enum resizer_chroma_algo {
+	RSZ_THE_SAME = 0,	/* Chrominance the same as Luminance */
+	RSZ_BILINEAR = 1,	/* Chrominance uses bilinear interpolation */
+};
+
+/* Resizer input type select */
+enum resizer_colors_type {
+	RSZ_YUV422 = 0,		/* YUV422 color is interleaved */
+	RSZ_COLOR8 = 1,		/* Color separate data on 8 bits */
+};
+
+/*
+ * Structure for horizontal and vertical resizing value
+ */
+struct resizer_ratio {
+	u32 horz;
+	u32 vert;
+};
+
+/*
+ * Structure for luminance enhancer parameters.
+ */
+struct resizer_luma_yenh {
+	u8 algo;		/* algorithm select. */
+	u8 gain;		/* maximum gain. */
+	u8 slope;		/* slope. */
+	u8 core;		/* core offset. */
+};
+
+enum resizer_input_entity {
+	RESIZER_INPUT_NONE,
+	RESIZER_INPUT_VP,	/* input video port - prev or ccdc */
+	RESIZER_INPUT_MEMORY,
+};
+
+/* Sink and source resizer pads */
+#define RESZ_PAD_SINK			0
+#define RESZ_PAD_SOURCE			1
+#define RESZ_PADS_NUM			2
+
+/*
+ * struct isp_res_device - OMAP3 ISP resizer module
+ * @crop.request: Crop rectangle requested by the user
+ * @crop.active: Active crop rectangle (based on hardware requirements)
+ */
+struct isp_res_device {
+	struct v4l2_subdev subdev;
+	struct media_pad pads[RESZ_PADS_NUM];
+	struct v4l2_mbus_framefmt formats[RESZ_PADS_NUM];
+
+	enum resizer_input_entity input;
+	struct isp_video video_in;
+	struct isp_video video_out;
+
+	u32 addr_base;   /* stored source buffer address in memory mode */
+	u32 crop_offset; /* additional offset for crop in memory mode */
+	struct resizer_ratio ratio;
+	int pm_state;
+	unsigned int applycrop:1;
+	enum isp_pipeline_stream_state state;
+	wait_queue_head_t wait;
+	atomic_t stopping;
+
+	struct {
+		struct v4l2_rect request;
+		struct v4l2_rect active;
+	} crop;
+};
+
+struct isp_device;
+
+int omap3isp_resizer_init(struct isp_device *isp);
+void omap3isp_resizer_cleanup(struct isp_device *isp);
+
+int omap3isp_resizer_register_entities(struct isp_res_device *res,
+				       struct v4l2_device *vdev);
+void omap3isp_resizer_unregister_entities(struct isp_res_device *res);
+void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res);
+void omap3isp_resizer_isr(struct isp_res_device *isp_res);
+
+void omap3isp_resizer_max_rate(struct isp_res_device *res,
+			       unsigned int *max_rate);
+
+void omap3isp_resizer_suspend(struct isp_res_device *isp_res);
+
+void omap3isp_resizer_resume(struct isp_res_device *isp_res);
+
+int omap3isp_resizer_busy(struct isp_res_device *isp_res);
+
+#endif	/* OMAP3_ISP_RESIZER_H */
diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c
new file mode 100644
index 0000000..b8640be
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispstat.c
@@ -0,0 +1,1102 @@
+/*
+ * ispstat.c
+ *
+ * TI OMAP3 ISP - Statistics core
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc
+ *
+ * Contacts: David Cohen <dacohen@gmail.com>
+ *	     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "isp.h"
+
+#define IS_COHERENT_BUF(stat)	((stat)->dma_ch >= 0)
+
+/*
+ * MAGIC_SIZE must always be the greatest common divisor of
+ * AEWB_PACKET_SIZE and AF_PAXEL_SIZE.
+ */
+#define MAGIC_SIZE		16
+#define MAGIC_NUM		0x55
+
+/* HACK: AF module seems to be writing one more paxel data than it should. */
+#define AF_EXTRA_DATA		OMAP3ISP_AF_PAXEL_SIZE
+
+/*
+ * HACK: H3A modules go to an invalid state after have a SBL overflow. It makes
+ * the next buffer to start to be written in the same point where the overflow
+ * occurred instead of the configured address. The only known way to make it to
+ * go back to a valid state is having a valid buffer processing. Of course it
+ * requires at least a doubled buffer size to avoid an access to invalid memory
+ * region. But it does not fix everything. It may happen more than one
+ * consecutive SBL overflows. In that case, it might be unpredictable how many
+ * buffers the allocated memory should fit. For that case, a recover
+ * configuration was created. It produces the minimum buffer size for each H3A
+ * module and decrease the change for more SBL overflows. This recover state
+ * will be enabled every time a SBL overflow occur. As the output buffer size
+ * isn't big, it's possible to have an extra size able to fit many recover
+ * buffers making it extreamily unlikely to have an access to invalid memory
+ * region.
+ */
+#define NUM_H3A_RECOVER_BUFS	10
+
+/*
+ * HACK: Because of HW issues the generic layer sometimes need to have
+ * different behaviour for different statistic modules.
+ */
+#define IS_H3A_AF(stat)		((stat) == &(stat)->isp->isp_af)
+#define IS_H3A_AEWB(stat)	((stat) == &(stat)->isp->isp_aewb)
+#define IS_H3A(stat)		(IS_H3A_AF(stat) || IS_H3A_AEWB(stat))
+
+static void __isp_stat_buf_sync_magic(struct ispstat *stat,
+				      struct ispstat_buffer *buf,
+				      u32 buf_size, enum dma_data_direction dir,
+				      void (*dma_sync)(struct device *,
+					dma_addr_t, unsigned long, size_t,
+					enum dma_data_direction))
+{
+	struct device *dev = stat->isp->dev;
+	struct page *pg;
+	dma_addr_t dma_addr;
+	u32 offset;
+
+	/* Initial magic words */
+	pg = vmalloc_to_page(buf->virt_addr);
+	dma_addr = pfn_to_dma(dev, page_to_pfn(pg));
+	dma_sync(dev, dma_addr, 0, MAGIC_SIZE, dir);
+
+	/* Final magic words */
+	pg = vmalloc_to_page(buf->virt_addr + buf_size);
+	dma_addr = pfn_to_dma(dev, page_to_pfn(pg));
+	offset = ((u32)buf->virt_addr + buf_size) & ~PAGE_MASK;
+	dma_sync(dev, dma_addr, offset, MAGIC_SIZE, dir);
+}
+
+static void isp_stat_buf_sync_magic_for_device(struct ispstat *stat,
+					       struct ispstat_buffer *buf,
+					       u32 buf_size,
+					       enum dma_data_direction dir)
+{
+	if (IS_COHERENT_BUF(stat))
+		return;
+
+	__isp_stat_buf_sync_magic(stat, buf, buf_size, dir,
+				  dma_sync_single_range_for_device);
+}
+
+static void isp_stat_buf_sync_magic_for_cpu(struct ispstat *stat,
+					    struct ispstat_buffer *buf,
+					    u32 buf_size,
+					    enum dma_data_direction dir)
+{
+	if (IS_COHERENT_BUF(stat))
+		return;
+
+	__isp_stat_buf_sync_magic(stat, buf, buf_size, dir,
+				  dma_sync_single_range_for_cpu);
+}
+
+static int isp_stat_buf_check_magic(struct ispstat *stat,
+				    struct ispstat_buffer *buf)
+{
+	const u32 buf_size = IS_H3A_AF(stat) ?
+			     buf->buf_size + AF_EXTRA_DATA : buf->buf_size;
+	u8 *w;
+	u8 *end;
+	int ret = -EINVAL;
+
+	isp_stat_buf_sync_magic_for_cpu(stat, buf, buf_size, DMA_FROM_DEVICE);
+
+	/* Checking initial magic numbers. They shouldn't be here anymore. */
+	for (w = buf->virt_addr, end = w + MAGIC_SIZE; w < end; w++)
+		if (likely(*w != MAGIC_NUM))
+			ret = 0;
+
+	if (ret) {
+		dev_dbg(stat->isp->dev, "%s: beginning magic check does not "
+					"match.\n", stat->subdev.name);
+		return ret;
+	}
+
+	/* Checking magic numbers at the end. They must be still here. */
+	for (w = buf->virt_addr + buf_size, end = w + MAGIC_SIZE;
+	     w < end; w++) {
+		if (unlikely(*w != MAGIC_NUM)) {
+			dev_dbg(stat->isp->dev, "%s: endding magic check does "
+				"not match.\n", stat->subdev.name);
+			return -EINVAL;
+		}
+	}
+
+	isp_stat_buf_sync_magic_for_device(stat, buf, buf_size,
+					   DMA_FROM_DEVICE);
+
+	return 0;
+}
+
+static void isp_stat_buf_insert_magic(struct ispstat *stat,
+				      struct ispstat_buffer *buf)
+{
+	const u32 buf_size = IS_H3A_AF(stat) ?
+			     stat->buf_size + AF_EXTRA_DATA : stat->buf_size;
+
+	isp_stat_buf_sync_magic_for_cpu(stat, buf, buf_size, DMA_FROM_DEVICE);
+
+	/*
+	 * Inserting MAGIC_NUM at the beginning and end of the buffer.
+	 * buf->buf_size is set only after the buffer is queued. For now the
+	 * right buf_size for the current configuration is pointed by
+	 * stat->buf_size.
+	 */
+	memset(buf->virt_addr, MAGIC_NUM, MAGIC_SIZE);
+	memset(buf->virt_addr + buf_size, MAGIC_NUM, MAGIC_SIZE);
+
+	isp_stat_buf_sync_magic_for_device(stat, buf, buf_size,
+					   DMA_BIDIRECTIONAL);
+}
+
+static void isp_stat_buf_sync_for_device(struct ispstat *stat,
+					 struct ispstat_buffer *buf)
+{
+	if (IS_COHERENT_BUF(stat))
+		return;
+
+	dma_sync_sg_for_device(stat->isp->dev, buf->iovm->sgt->sgl,
+			       buf->iovm->sgt->nents, DMA_FROM_DEVICE);
+}
+
+static void isp_stat_buf_sync_for_cpu(struct ispstat *stat,
+				      struct ispstat_buffer *buf)
+{
+	if (IS_COHERENT_BUF(stat))
+		return;
+
+	dma_sync_sg_for_cpu(stat->isp->dev, buf->iovm->sgt->sgl,
+			    buf->iovm->sgt->nents, DMA_FROM_DEVICE);
+}
+
+static void isp_stat_buf_clear(struct ispstat *stat)
+{
+	int i;
+
+	for (i = 0; i < STAT_MAX_BUFS; i++)
+		stat->buf[i].empty = 1;
+}
+
+static struct ispstat_buffer *
+__isp_stat_buf_find(struct ispstat *stat, int look_empty)
+{
+	struct ispstat_buffer *found = NULL;
+	int i;
+
+	for (i = 0; i < STAT_MAX_BUFS; i++) {
+		struct ispstat_buffer *curr = &stat->buf[i];
+
+		/*
+		 * Don't select the buffer which is being copied to
+		 * userspace or used by the module.
+		 */
+		if (curr == stat->locked_buf || curr == stat->active_buf)
+			continue;
+
+		/* Don't select uninitialised buffers if it's not required */
+		if (!look_empty && curr->empty)
+			continue;
+
+		/* Pick uninitialised buffer over anything else if look_empty */
+		if (curr->empty) {
+			found = curr;
+			break;
+		}
+
+		/* Choose the oldest buffer */
+		if (!found ||
+		    (s32)curr->frame_number - (s32)found->frame_number < 0)
+			found = curr;
+	}
+
+	return found;
+}
+
+static inline struct ispstat_buffer *
+isp_stat_buf_find_oldest(struct ispstat *stat)
+{
+	return __isp_stat_buf_find(stat, 0);
+}
+
+static inline struct ispstat_buffer *
+isp_stat_buf_find_oldest_or_empty(struct ispstat *stat)
+{
+	return __isp_stat_buf_find(stat, 1);
+}
+
+static int isp_stat_buf_queue(struct ispstat *stat)
+{
+	if (!stat->active_buf)
+		return STAT_NO_BUF;
+
+	do_gettimeofday(&stat->active_buf->ts);
+
+	stat->active_buf->buf_size = stat->buf_size;
+	if (isp_stat_buf_check_magic(stat, stat->active_buf)) {
+		dev_dbg(stat->isp->dev, "%s: data wasn't properly written.\n",
+			stat->subdev.name);
+		return STAT_NO_BUF;
+	}
+	stat->active_buf->config_counter = stat->config_counter;
+	stat->active_buf->frame_number = stat->frame_number;
+	stat->active_buf->empty = 0;
+	stat->active_buf = NULL;
+
+	return STAT_BUF_DONE;
+}
+
+/* Get next free buffer to write the statistics to and mark it active. */
+static void isp_stat_buf_next(struct ispstat *stat)
+{
+	if (unlikely(stat->active_buf))
+		/* Overwriting unused active buffer */
+		dev_dbg(stat->isp->dev, "%s: new buffer requested without "
+					"queuing active one.\n",
+					stat->subdev.name);
+	else
+		stat->active_buf = isp_stat_buf_find_oldest_or_empty(stat);
+}
+
+static void isp_stat_buf_release(struct ispstat *stat)
+{
+	unsigned long flags;
+
+	isp_stat_buf_sync_for_device(stat, stat->locked_buf);
+	spin_lock_irqsave(&stat->isp->stat_lock, flags);
+	stat->locked_buf = NULL;
+	spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
+}
+
+/* Get buffer to userspace. */
+static struct ispstat_buffer *isp_stat_buf_get(struct ispstat *stat,
+					       struct omap3isp_stat_data *data)
+{
+	int rval = 0;
+	unsigned long flags;
+	struct ispstat_buffer *buf;
+
+	spin_lock_irqsave(&stat->isp->stat_lock, flags);
+
+	while (1) {
+		buf = isp_stat_buf_find_oldest(stat);
+		if (!buf) {
+			spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
+			dev_dbg(stat->isp->dev, "%s: cannot find a buffer.\n",
+				stat->subdev.name);
+			return ERR_PTR(-EBUSY);
+		}
+		if (isp_stat_buf_check_magic(stat, buf)) {
+			dev_dbg(stat->isp->dev, "%s: current buffer has "
+				"corrupted data\n.", stat->subdev.name);
+			/* Mark empty because it doesn't have valid data. */
+			buf->empty = 1;
+		} else {
+			/* Buffer isn't corrupted. */
+			break;
+		}
+	}
+
+	stat->locked_buf = buf;
+
+	spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
+
+	if (buf->buf_size > data->buf_size) {
+		dev_warn(stat->isp->dev, "%s: userspace's buffer size is "
+					 "not enough.\n", stat->subdev.name);
+		isp_stat_buf_release(stat);
+		return ERR_PTR(-EINVAL);
+	}
+
+	isp_stat_buf_sync_for_cpu(stat, buf);
+
+	rval = copy_to_user(data->buf,
+			    buf->virt_addr,
+			    buf->buf_size);
+
+	if (rval) {
+		dev_info(stat->isp->dev,
+			 "%s: failed copying %d bytes of stat data\n",
+			 stat->subdev.name, rval);
+		buf = ERR_PTR(-EFAULT);
+		isp_stat_buf_release(stat);
+	}
+
+	return buf;
+}
+
+static void isp_stat_bufs_free(struct ispstat *stat)
+{
+	struct isp_device *isp = stat->isp;
+	int i;
+
+	for (i = 0; i < STAT_MAX_BUFS; i++) {
+		struct ispstat_buffer *buf = &stat->buf[i];
+
+		if (!IS_COHERENT_BUF(stat)) {
+			if (IS_ERR_OR_NULL((void *)buf->iommu_addr))
+				continue;
+			if (buf->iovm)
+				dma_unmap_sg(isp->dev, buf->iovm->sgt->sgl,
+					     buf->iovm->sgt->nents,
+					     DMA_FROM_DEVICE);
+			omap_iommu_vfree(isp->domain, isp->dev,
+							buf->iommu_addr);
+		} else {
+			if (!buf->virt_addr)
+				continue;
+			dma_free_coherent(stat->isp->dev, stat->buf_alloc_size,
+					  buf->virt_addr, buf->dma_addr);
+		}
+		buf->iommu_addr = 0;
+		buf->iovm = NULL;
+		buf->dma_addr = 0;
+		buf->virt_addr = NULL;
+		buf->empty = 1;
+	}
+
+	dev_dbg(stat->isp->dev, "%s: all buffers were freed.\n",
+		stat->subdev.name);
+
+	stat->buf_alloc_size = 0;
+	stat->active_buf = NULL;
+}
+
+static int isp_stat_bufs_alloc_iommu(struct ispstat *stat, unsigned int size)
+{
+	struct isp_device *isp = stat->isp;
+	int i;
+
+	stat->buf_alloc_size = size;
+
+	for (i = 0; i < STAT_MAX_BUFS; i++) {
+		struct ispstat_buffer *buf = &stat->buf[i];
+		struct iovm_struct *iovm;
+
+		WARN_ON(buf->dma_addr);
+		buf->iommu_addr = omap_iommu_vmalloc(isp->domain, isp->dev, 0,
+							size, IOMMU_FLAG);
+		if (IS_ERR((void *)buf->iommu_addr)) {
+			dev_err(stat->isp->dev,
+				 "%s: Can't acquire memory for "
+				 "buffer %d\n", stat->subdev.name, i);
+			isp_stat_bufs_free(stat);
+			return -ENOMEM;
+		}
+
+		iovm = omap_find_iovm_area(isp->dev, buf->iommu_addr);
+		if (!iovm ||
+		    !dma_map_sg(isp->dev, iovm->sgt->sgl, iovm->sgt->nents,
+				DMA_FROM_DEVICE)) {
+			isp_stat_bufs_free(stat);
+			return -ENOMEM;
+		}
+		buf->iovm = iovm;
+
+		buf->virt_addr = omap_da_to_va(stat->isp->dev,
+					  (u32)buf->iommu_addr);
+		buf->empty = 1;
+		dev_dbg(stat->isp->dev, "%s: buffer[%d] allocated."
+			"iommu_addr=0x%08lx virt_addr=0x%08lx",
+			stat->subdev.name, i, buf->iommu_addr,
+			(unsigned long)buf->virt_addr);
+	}
+
+	return 0;
+}
+
+static int isp_stat_bufs_alloc_dma(struct ispstat *stat, unsigned int size)
+{
+	int i;
+
+	stat->buf_alloc_size = size;
+
+	for (i = 0; i < STAT_MAX_BUFS; i++) {
+		struct ispstat_buffer *buf = &stat->buf[i];
+
+		WARN_ON(buf->iommu_addr);
+		buf->virt_addr = dma_alloc_coherent(stat->isp->dev, size,
+					&buf->dma_addr, GFP_KERNEL | GFP_DMA);
+
+		if (!buf->virt_addr || !buf->dma_addr) {
+			dev_info(stat->isp->dev,
+				 "%s: Can't acquire memory for "
+				 "DMA buffer %d\n", stat->subdev.name, i);
+			isp_stat_bufs_free(stat);
+			return -ENOMEM;
+		}
+		buf->empty = 1;
+
+		dev_dbg(stat->isp->dev, "%s: buffer[%d] allocated."
+			"dma_addr=0x%08lx virt_addr=0x%08lx\n",
+			stat->subdev.name, i, (unsigned long)buf->dma_addr,
+			(unsigned long)buf->virt_addr);
+	}
+
+	return 0;
+}
+
+static int isp_stat_bufs_alloc(struct ispstat *stat, u32 size)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&stat->isp->stat_lock, flags);
+
+	BUG_ON(stat->locked_buf != NULL);
+
+	/* Are the old buffers big enough? */
+	if (stat->buf_alloc_size >= size) {
+		spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
+		return 0;
+	}
+
+	if (stat->state != ISPSTAT_DISABLED || stat->buf_processing) {
+		dev_info(stat->isp->dev,
+			 "%s: trying to allocate memory when busy\n",
+			 stat->subdev.name);
+		spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
+		return -EBUSY;
+	}
+
+	spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
+
+	isp_stat_bufs_free(stat);
+
+	if (IS_COHERENT_BUF(stat))
+		return isp_stat_bufs_alloc_dma(stat, size);
+	else
+		return isp_stat_bufs_alloc_iommu(stat, size);
+}
+
+static void isp_stat_queue_event(struct ispstat *stat, int err)
+{
+	struct video_device *vdev = stat->subdev.devnode;
+	struct v4l2_event event;
+	struct omap3isp_stat_event_status *status = (void *)event.u.data;
+
+	memset(&event, 0, sizeof(event));
+	if (!err) {
+		status->frame_number = stat->frame_number;
+		status->config_counter = stat->config_counter;
+	} else {
+		status->buf_err = 1;
+	}
+	event.type = stat->event_type;
+	v4l2_event_queue(vdev, &event);
+}
+
+
+/*
+ * omap3isp_stat_request_statistics - Request statistics.
+ * @data: Pointer to return statistics data.
+ *
+ * Returns 0 if successful.
+ */
+int omap3isp_stat_request_statistics(struct ispstat *stat,
+				     struct omap3isp_stat_data *data)
+{
+	struct ispstat_buffer *buf;
+
+	if (stat->state != ISPSTAT_ENABLED) {
+		dev_dbg(stat->isp->dev, "%s: engine not enabled.\n",
+			stat->subdev.name);
+		return -EINVAL;
+	}
+
+	mutex_lock(&stat->ioctl_lock);
+	buf = isp_stat_buf_get(stat, data);
+	if (IS_ERR(buf)) {
+		mutex_unlock(&stat->ioctl_lock);
+		return PTR_ERR(buf);
+	}
+
+	data->ts = buf->ts;
+	data->config_counter = buf->config_counter;
+	data->frame_number = buf->frame_number;
+	data->buf_size = buf->buf_size;
+
+	buf->empty = 1;
+	isp_stat_buf_release(stat);
+	mutex_unlock(&stat->ioctl_lock);
+
+	return 0;
+}
+
+/*
+ * omap3isp_stat_config - Receives new statistic engine configuration.
+ * @new_conf: Pointer to config structure.
+ *
+ * Returns 0 if successful, -EINVAL if new_conf pointer is NULL, -ENOMEM if
+ * was unable to allocate memory for the buffer, or other errors if parameters
+ * are invalid.
+ */
+int omap3isp_stat_config(struct ispstat *stat, void *new_conf)
+{
+	int ret;
+	unsigned long irqflags;
+	struct ispstat_generic_config *user_cfg = new_conf;
+	u32 buf_size = user_cfg->buf_size;
+
+	if (!new_conf) {
+		dev_dbg(stat->isp->dev, "%s: configuration is NULL\n",
+			stat->subdev.name);
+		return -EINVAL;
+	}
+
+	mutex_lock(&stat->ioctl_lock);
+
+	dev_dbg(stat->isp->dev, "%s: configuring module with buffer "
+		"size=0x%08lx\n", stat->subdev.name, (unsigned long)buf_size);
+
+	ret = stat->ops->validate_params(stat, new_conf);
+	if (ret) {
+		mutex_unlock(&stat->ioctl_lock);
+		dev_dbg(stat->isp->dev, "%s: configuration values are "
+					"invalid.\n", stat->subdev.name);
+		return ret;
+	}
+
+	if (buf_size != user_cfg->buf_size)
+		dev_dbg(stat->isp->dev, "%s: driver has corrected buffer size "
+			"request to 0x%08lx\n", stat->subdev.name,
+			(unsigned long)user_cfg->buf_size);
+
+	/*
+	 * Hack: H3A modules may need a doubled buffer size to avoid access
+	 * to a invalid memory address after a SBL overflow.
+	 * The buffer size is always PAGE_ALIGNED.
+	 * Hack 2: MAGIC_SIZE is added to buf_size so a magic word can be
+	 * inserted at the end to data integrity check purpose.
+	 * Hack 3: AF module writes one paxel data more than it should, so
+	 * the buffer allocation must consider it to avoid invalid memory
+	 * access.
+	 * Hack 4: H3A need to allocate extra space for the recover state.
+	 */
+	if (IS_H3A(stat)) {
+		buf_size = user_cfg->buf_size * 2 + MAGIC_SIZE;
+		if (IS_H3A_AF(stat))
+			/*
+			 * Adding one extra paxel data size for each recover
+			 * buffer + 2 regular ones.
+			 */
+			buf_size += AF_EXTRA_DATA * (NUM_H3A_RECOVER_BUFS + 2);
+		if (stat->recover_priv) {
+			struct ispstat_generic_config *recover_cfg =
+				stat->recover_priv;
+			buf_size += recover_cfg->buf_size *
+				    NUM_H3A_RECOVER_BUFS;
+		}
+		buf_size = PAGE_ALIGN(buf_size);
+	} else { /* Histogram */
+		buf_size = PAGE_ALIGN(user_cfg->buf_size + MAGIC_SIZE);
+	}
+
+	ret = isp_stat_bufs_alloc(stat, buf_size);
+	if (ret) {
+		mutex_unlock(&stat->ioctl_lock);
+		return ret;
+	}
+
+	spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
+	stat->ops->set_params(stat, new_conf);
+	spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+
+	/*
+	 * Returning the right future config_counter for this setup, so
+	 * userspace can *know* when it has been applied.
+	 */
+	user_cfg->config_counter = stat->config_counter + stat->inc_config;
+
+	/* Module has a valid configuration. */
+	stat->configured = 1;
+	dev_dbg(stat->isp->dev, "%s: module has been successfully "
+		"configured.\n", stat->subdev.name);
+
+	mutex_unlock(&stat->ioctl_lock);
+
+	return 0;
+}
+
+/*
+ * isp_stat_buf_process - Process statistic buffers.
+ * @buf_state: points out if buffer is ready to be processed. It's necessary
+ *	       because histogram needs to copy the data from internal memory
+ *	       before be able to process the buffer.
+ */
+static int isp_stat_buf_process(struct ispstat *stat, int buf_state)
+{
+	int ret = STAT_NO_BUF;
+
+	if (!atomic_add_unless(&stat->buf_err, -1, 0) &&
+	    buf_state == STAT_BUF_DONE && stat->state == ISPSTAT_ENABLED) {
+		ret = isp_stat_buf_queue(stat);
+		isp_stat_buf_next(stat);
+	}
+
+	return ret;
+}
+
+int omap3isp_stat_pcr_busy(struct ispstat *stat)
+{
+	return stat->ops->busy(stat);
+}
+
+int omap3isp_stat_busy(struct ispstat *stat)
+{
+	return omap3isp_stat_pcr_busy(stat) | stat->buf_processing |
+		(stat->state != ISPSTAT_DISABLED);
+}
+
+/*
+ * isp_stat_pcr_enable - Disables/Enables statistic engines.
+ * @pcr_enable: 0/1 - Disables/Enables the engine.
+ *
+ * Must be called from ISP driver when the module is idle and synchronized
+ * with CCDC.
+ */
+static void isp_stat_pcr_enable(struct ispstat *stat, u8 pcr_enable)
+{
+	if ((stat->state != ISPSTAT_ENABLING &&
+	     stat->state != ISPSTAT_ENABLED) && pcr_enable)
+		/* Userspace has disabled the module. Aborting. */
+		return;
+
+	stat->ops->enable(stat, pcr_enable);
+	if (stat->state == ISPSTAT_DISABLING && !pcr_enable)
+		stat->state = ISPSTAT_DISABLED;
+	else if (stat->state == ISPSTAT_ENABLING && pcr_enable)
+		stat->state = ISPSTAT_ENABLED;
+}
+
+void omap3isp_stat_suspend(struct ispstat *stat)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&stat->isp->stat_lock, flags);
+
+	if (stat->state != ISPSTAT_DISABLED)
+		stat->ops->enable(stat, 0);
+	if (stat->state == ISPSTAT_ENABLED)
+		stat->state = ISPSTAT_SUSPENDED;
+
+	spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
+}
+
+void omap3isp_stat_resume(struct ispstat *stat)
+{
+	/* Module will be re-enabled with its pipeline */
+	if (stat->state == ISPSTAT_SUSPENDED)
+		stat->state = ISPSTAT_ENABLING;
+}
+
+static void isp_stat_try_enable(struct ispstat *stat)
+{
+	unsigned long irqflags;
+
+	if (stat->priv == NULL)
+		/* driver wasn't initialised */
+		return;
+
+	spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
+	if (stat->state == ISPSTAT_ENABLING && !stat->buf_processing &&
+	    stat->buf_alloc_size) {
+		/*
+		 * Userspace's requested to enable the engine but it wasn't yet.
+		 * Let's do that now.
+		 */
+		stat->update = 1;
+		isp_stat_buf_next(stat);
+		stat->ops->setup_regs(stat, stat->priv);
+		isp_stat_buf_insert_magic(stat, stat->active_buf);
+
+		/*
+		 * H3A module has some hw issues which forces the driver to
+		 * ignore next buffers even if it was disabled in the meantime.
+		 * On the other hand, Histogram shouldn't ignore buffers anymore
+		 * if it's being enabled.
+		 */
+		if (!IS_H3A(stat))
+			atomic_set(&stat->buf_err, 0);
+
+		isp_stat_pcr_enable(stat, 1);
+		spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+		dev_dbg(stat->isp->dev, "%s: module is enabled.\n",
+			stat->subdev.name);
+	} else {
+		spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+	}
+}
+
+void omap3isp_stat_isr_frame_sync(struct ispstat *stat)
+{
+	isp_stat_try_enable(stat);
+}
+
+void omap3isp_stat_sbl_overflow(struct ispstat *stat)
+{
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
+	/*
+	 * Due to a H3A hw issue which prevents the next buffer to start from
+	 * the correct memory address, 2 buffers must be ignored.
+	 */
+	atomic_set(&stat->buf_err, 2);
+
+	/*
+	 * If more than one SBL overflow happen in a row, H3A module may access
+	 * invalid memory region.
+	 * stat->sbl_ovl_recover is set to tell to the driver to temporarily use
+	 * a soft configuration which helps to avoid consecutive overflows.
+	 */
+	if (stat->recover_priv)
+		stat->sbl_ovl_recover = 1;
+	spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+}
+
+/*
+ * omap3isp_stat_enable - Disable/Enable statistic engine as soon as possible
+ * @enable: 0/1 - Disables/Enables the engine.
+ *
+ * Client should configure all the module registers before this.
+ * This function can be called from a userspace request.
+ */
+int omap3isp_stat_enable(struct ispstat *stat, u8 enable)
+{
+	unsigned long irqflags;
+
+	dev_dbg(stat->isp->dev, "%s: user wants to %s module.\n",
+		stat->subdev.name, enable ? "enable" : "disable");
+
+	/* Prevent enabling while configuring */
+	mutex_lock(&stat->ioctl_lock);
+
+	spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
+
+	if (!stat->configured && enable) {
+		spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+		mutex_unlock(&stat->ioctl_lock);
+		dev_dbg(stat->isp->dev, "%s: cannot enable module as it's "
+			"never been successfully configured so far.\n",
+			stat->subdev.name);
+		return -EINVAL;
+	}
+
+	if (enable) {
+		if (stat->state == ISPSTAT_DISABLING)
+			/* Previous disabling request wasn't done yet */
+			stat->state = ISPSTAT_ENABLED;
+		else if (stat->state == ISPSTAT_DISABLED)
+			/* Module is now being enabled */
+			stat->state = ISPSTAT_ENABLING;
+	} else {
+		if (stat->state == ISPSTAT_ENABLING) {
+			/* Previous enabling request wasn't done yet */
+			stat->state = ISPSTAT_DISABLED;
+		} else if (stat->state == ISPSTAT_ENABLED) {
+			/* Module is now being disabled */
+			stat->state = ISPSTAT_DISABLING;
+			isp_stat_buf_clear(stat);
+		}
+	}
+
+	spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+	mutex_unlock(&stat->ioctl_lock);
+
+	return 0;
+}
+
+int omap3isp_stat_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+	struct ispstat *stat = v4l2_get_subdevdata(subdev);
+
+	if (enable) {
+		/*
+		 * Only set enable PCR bit if the module was previously
+		 * enabled through ioct.
+		 */
+		isp_stat_try_enable(stat);
+	} else {
+		unsigned long flags;
+		/* Disable PCR bit and config enable field */
+		omap3isp_stat_enable(stat, 0);
+		spin_lock_irqsave(&stat->isp->stat_lock, flags);
+		stat->ops->enable(stat, 0);
+		spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
+
+		/*
+		 * If module isn't busy, a new interrupt may come or not to
+		 * set the state to DISABLED. As Histogram needs to read its
+		 * internal memory to clear it, let interrupt handler
+		 * responsible of changing state to DISABLED. If the last
+		 * interrupt is coming, it's still safe as the handler will
+		 * ignore the second time when state is already set to DISABLED.
+		 * It's necessary to synchronize Histogram with streamoff, once
+		 * the module may be considered idle before last SDMA transfer
+		 * starts if we return here.
+		 */
+		if (!omap3isp_stat_pcr_busy(stat))
+			omap3isp_stat_isr(stat);
+
+		dev_dbg(stat->isp->dev, "%s: module is being disabled\n",
+			stat->subdev.name);
+	}
+
+	return 0;
+}
+
+/*
+ * __stat_isr - Interrupt handler for statistic drivers
+ */
+static void __stat_isr(struct ispstat *stat, int from_dma)
+{
+	int ret = STAT_BUF_DONE;
+	int buf_processing;
+	unsigned long irqflags;
+	struct isp_pipeline *pipe;
+
+	/*
+	 * stat->buf_processing must be set before disable module. It's
+	 * necessary to not inform too early the buffers aren't busy in case
+	 * of SDMA is going to be used.
+	 */
+	spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
+	if (stat->state == ISPSTAT_DISABLED) {
+		spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+		return;
+	}
+	buf_processing = stat->buf_processing;
+	stat->buf_processing = 1;
+	stat->ops->enable(stat, 0);
+
+	if (buf_processing && !from_dma) {
+		if (stat->state == ISPSTAT_ENABLED) {
+			spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+			dev_err(stat->isp->dev,
+				"%s: interrupt occurred when module was still "
+				"processing a buffer.\n", stat->subdev.name);
+			ret = STAT_NO_BUF;
+			goto out;
+		} else {
+			/*
+			 * Interrupt handler was called from streamoff when
+			 * the module wasn't busy anymore to ensure it is being
+			 * disabled after process last buffer. If such buffer
+			 * processing has already started, no need to do
+			 * anything else.
+			 */
+			spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+			return;
+		}
+	}
+	spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+
+	/* If it's busy we can't process this buffer anymore */
+	if (!omap3isp_stat_pcr_busy(stat)) {
+		if (!from_dma && stat->ops->buf_process)
+			/* Module still need to copy data to buffer. */
+			ret = stat->ops->buf_process(stat);
+		if (ret == STAT_BUF_WAITING_DMA)
+			/* Buffer is not ready yet */
+			return;
+
+		spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
+
+		/*
+		 * Histogram needs to read its internal memory to clear it
+		 * before be disabled. For that reason, common statistic layer
+		 * can return only after call stat's buf_process() operator.
+		 */
+		if (stat->state == ISPSTAT_DISABLING) {
+			stat->state = ISPSTAT_DISABLED;
+			spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+			stat->buf_processing = 0;
+			return;
+		}
+		pipe = to_isp_pipeline(&stat->subdev.entity);
+		stat->frame_number = atomic_read(&pipe->frame_number);
+
+		/*
+		 * Before this point, 'ret' stores the buffer's status if it's
+		 * ready to be processed. Afterwards, it holds the status if
+		 * it was processed successfully.
+		 */
+		ret = isp_stat_buf_process(stat, ret);
+
+		if (likely(!stat->sbl_ovl_recover)) {
+			stat->ops->setup_regs(stat, stat->priv);
+		} else {
+			/*
+			 * Using recover config to increase the chance to have
+			 * a good buffer processing and make the H3A module to
+			 * go back to a valid state.
+			 */
+			stat->update = 1;
+			stat->ops->setup_regs(stat, stat->recover_priv);
+			stat->sbl_ovl_recover = 0;
+
+			/*
+			 * Set 'update' in case of the module needs to use
+			 * regular configuration after next buffer.
+			 */
+			stat->update = 1;
+		}
+
+		isp_stat_buf_insert_magic(stat, stat->active_buf);
+
+		/*
+		 * Hack: H3A modules may access invalid memory address or send
+		 * corrupted data to userspace if more than 1 SBL overflow
+		 * happens in a row without re-writing its buffer's start memory
+		 * address in the meantime. Such situation is avoided if the
+		 * module is not immediately re-enabled when the ISR misses the
+		 * timing to process the buffer and to setup the registers.
+		 * Because of that, pcr_enable(1) was moved to inside this 'if'
+		 * block. But the next interruption will still happen as during
+		 * pcr_enable(0) the module was busy.
+		 */
+		isp_stat_pcr_enable(stat, 1);
+		spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+	} else {
+		/*
+		 * If a SBL overflow occurs and the H3A driver misses the timing
+		 * to process the buffer, stat->buf_err is set and won't be
+		 * cleared now. So the next buffer will be correctly ignored.
+		 * It's necessary due to a hw issue which makes the next H3A
+		 * buffer to start from the memory address where the previous
+		 * one stopped, instead of start where it was configured to.
+		 * Do not "stat->buf_err = 0" here.
+		 */
+
+		if (stat->ops->buf_process)
+			/*
+			 * Driver may need to erase current data prior to
+			 * process a new buffer. If it misses the timing, the
+			 * next buffer might be wrong. So should be ignored.
+			 * It happens only for Histogram.
+			 */
+			atomic_set(&stat->buf_err, 1);
+
+		ret = STAT_NO_BUF;
+		dev_dbg(stat->isp->dev, "%s: cannot process buffer, "
+					"device is busy.\n", stat->subdev.name);
+	}
+
+out:
+	stat->buf_processing = 0;
+	isp_stat_queue_event(stat, ret != STAT_BUF_DONE);
+}
+
+void omap3isp_stat_isr(struct ispstat *stat)
+{
+	__stat_isr(stat, 0);
+}
+
+void omap3isp_stat_dma_isr(struct ispstat *stat)
+{
+	__stat_isr(stat, 1);
+}
+
+int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev,
+				  struct v4l2_fh *fh,
+				  struct v4l2_event_subscription *sub)
+{
+	struct ispstat *stat = v4l2_get_subdevdata(subdev);
+
+	if (sub->type != stat->event_type)
+		return -EINVAL;
+
+	return v4l2_event_subscribe(fh, sub, STAT_NEVENTS, NULL);
+}
+
+int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev,
+				    struct v4l2_fh *fh,
+				    struct v4l2_event_subscription *sub)
+{
+	return v4l2_event_unsubscribe(fh, sub);
+}
+
+void omap3isp_stat_unregister_entities(struct ispstat *stat)
+{
+	v4l2_device_unregister_subdev(&stat->subdev);
+}
+
+int omap3isp_stat_register_entities(struct ispstat *stat,
+				    struct v4l2_device *vdev)
+{
+	return v4l2_device_register_subdev(vdev, &stat->subdev);
+}
+
+static int isp_stat_init_entities(struct ispstat *stat, const char *name,
+				  const struct v4l2_subdev_ops *sd_ops)
+{
+	struct v4l2_subdev *subdev = &stat->subdev;
+	struct media_entity *me = &subdev->entity;
+
+	v4l2_subdev_init(subdev, sd_ops);
+	snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name);
+	subdev->grp_id = 1 << 16;	/* group ID for isp subdevs */
+	subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
+	v4l2_set_subdevdata(subdev, stat);
+
+	stat->pad.flags = MEDIA_PAD_FL_SINK;
+	me->ops = NULL;
+
+	return media_entity_init(me, 1, &stat->pad, 0);
+}
+
+int omap3isp_stat_init(struct ispstat *stat, const char *name,
+		       const struct v4l2_subdev_ops *sd_ops)
+{
+	int ret;
+
+	stat->buf = kcalloc(STAT_MAX_BUFS, sizeof(*stat->buf), GFP_KERNEL);
+	if (!stat->buf)
+		return -ENOMEM;
+
+	isp_stat_buf_clear(stat);
+	mutex_init(&stat->ioctl_lock);
+	atomic_set(&stat->buf_err, 0);
+
+	ret = isp_stat_init_entities(stat, name, sd_ops);
+	if (ret < 0) {
+		mutex_destroy(&stat->ioctl_lock);
+		kfree(stat->buf);
+	}
+
+	return ret;
+}
+
+void omap3isp_stat_cleanup(struct ispstat *stat)
+{
+	media_entity_cleanup(&stat->subdev.entity);
+	mutex_destroy(&stat->ioctl_lock);
+	isp_stat_bufs_free(stat);
+	kfree(stat->buf);
+}
diff --git a/drivers/media/platform/omap3isp/ispstat.h b/drivers/media/platform/omap3isp/ispstat.h
new file mode 100644
index 0000000..9b7c865
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispstat.h
@@ -0,0 +1,169 @@
+/*
+ * ispstat.h
+ *
+ * TI OMAP3 ISP - Statistics core
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc
+ *
+ * Contacts: David Cohen <dacohen@gmail.com>
+ *	     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_STAT_H
+#define OMAP3_ISP_STAT_H
+
+#include <linux/types.h>
+#include <linux/omap3isp.h>
+#include <plat/dma.h>
+#include <media/v4l2-event.h>
+
+#include "isp.h"
+#include "ispvideo.h"
+
+#define STAT_MAX_BUFS		5
+#define STAT_NEVENTS		8
+
+#define STAT_BUF_DONE		0	/* Buffer is ready */
+#define STAT_NO_BUF		1	/* An error has occurred */
+#define STAT_BUF_WAITING_DMA	2	/* Histogram only: DMA is running */
+
+struct ispstat;
+
+struct ispstat_buffer {
+	unsigned long iommu_addr;
+	struct iovm_struct *iovm;
+	void *virt_addr;
+	dma_addr_t dma_addr;
+	struct timeval ts;
+	u32 buf_size;
+	u32 frame_number;
+	u16 config_counter;
+	u8 empty;
+};
+
+struct ispstat_ops {
+	/*
+	 * Validate new params configuration.
+	 * new_conf->buf_size value must be changed to the exact buffer size
+	 * necessary for the new configuration if it's smaller.
+	 */
+	int (*validate_params)(struct ispstat *stat, void *new_conf);
+
+	/*
+	 * Save new params configuration.
+	 * stat->priv->buf_size value must be set to the exact buffer size for
+	 * the new configuration.
+	 * stat->update is set to 1 if new configuration is different than
+	 * current one.
+	 */
+	void (*set_params)(struct ispstat *stat, void *new_conf);
+
+	/* Apply stored configuration. */
+	void (*setup_regs)(struct ispstat *stat, void *priv);
+
+	/* Enable/Disable module. */
+	void (*enable)(struct ispstat *stat, int enable);
+
+	/* Verify is module is busy. */
+	int (*busy)(struct ispstat *stat);
+
+	/* Used for specific operations during generic buf process task. */
+	int (*buf_process)(struct ispstat *stat);
+};
+
+enum ispstat_state_t {
+	ISPSTAT_DISABLED = 0,
+	ISPSTAT_DISABLING,
+	ISPSTAT_ENABLED,
+	ISPSTAT_ENABLING,
+	ISPSTAT_SUSPENDED,
+};
+
+struct ispstat {
+	struct v4l2_subdev subdev;
+	struct media_pad pad;	/* sink pad */
+
+	/* Control */
+	unsigned configured:1;
+	unsigned update:1;
+	unsigned buf_processing:1;
+	unsigned sbl_ovl_recover:1;
+	u8 inc_config;
+	atomic_t buf_err;
+	enum ispstat_state_t state;	/* enabling/disabling state */
+	struct omap_dma_channel_params dma_config;
+	struct isp_device *isp;
+	void *priv;		/* pointer to priv config struct */
+	void *recover_priv;	/* pointer to recover priv configuration */
+	struct mutex ioctl_lock; /* serialize private ioctl */
+
+	const struct ispstat_ops *ops;
+
+	/* Buffer */
+	u8 wait_acc_frames;
+	u16 config_counter;
+	u32 frame_number;
+	u32 buf_size;
+	u32 buf_alloc_size;
+	int dma_ch;
+	unsigned long event_type;
+	struct ispstat_buffer *buf;
+	struct ispstat_buffer *active_buf;
+	struct ispstat_buffer *locked_buf;
+};
+
+struct ispstat_generic_config {
+	/*
+	 * Fields must be in the same order as in:
+	 *  - omap3isp_h3a_aewb_config
+	 *  - omap3isp_h3a_af_config
+	 *  - omap3isp_hist_config
+	 */
+	u32 buf_size;
+	u16 config_counter;
+};
+
+int omap3isp_stat_config(struct ispstat *stat, void *new_conf);
+int omap3isp_stat_request_statistics(struct ispstat *stat,
+				     struct omap3isp_stat_data *data);
+int omap3isp_stat_init(struct ispstat *stat, const char *name,
+		       const struct v4l2_subdev_ops *sd_ops);
+void omap3isp_stat_cleanup(struct ispstat *stat);
+int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev,
+				  struct v4l2_fh *fh,
+				  struct v4l2_event_subscription *sub);
+int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev,
+				    struct v4l2_fh *fh,
+				    struct v4l2_event_subscription *sub);
+int omap3isp_stat_s_stream(struct v4l2_subdev *subdev, int enable);
+
+int omap3isp_stat_busy(struct ispstat *stat);
+int omap3isp_stat_pcr_busy(struct ispstat *stat);
+void omap3isp_stat_suspend(struct ispstat *stat);
+void omap3isp_stat_resume(struct ispstat *stat);
+int omap3isp_stat_enable(struct ispstat *stat, u8 enable);
+void omap3isp_stat_sbl_overflow(struct ispstat *stat);
+void omap3isp_stat_isr(struct ispstat *stat);
+void omap3isp_stat_isr_frame_sync(struct ispstat *stat);
+void omap3isp_stat_dma_isr(struct ispstat *stat);
+int omap3isp_stat_register_entities(struct ispstat *stat,
+				    struct v4l2_device *vdev);
+void omap3isp_stat_unregister_entities(struct ispstat *stat);
+
+#endif /* OMAP3_ISP_STAT_H */
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
new file mode 100644
index 0000000..3a5085e
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -0,0 +1,1403 @@
+/*
+ * ispvideo.c
+ *
+ * TI OMAP3 ISP - Generic video node
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <asm/cacheflush.h>
+#include <linux/clk.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <plat/iommu.h>
+#include <plat/iovmm.h>
+#include <plat/omap-pm.h>
+
+#include "ispvideo.h"
+#include "isp.h"
+
+
+/* -----------------------------------------------------------------------------
+ * Helper functions
+ */
+
+/*
+ * NOTE: When adding new media bus codes, always remember to add
+ * corresponding in-memory formats to the table below!!!
+ */
+static struct isp_format_info formats[] = {
+	{ V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
+	  V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
+	  V4L2_PIX_FMT_GREY, 8, 1, },
+	{ V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10,
+	  V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y8_1X8,
+	  V4L2_PIX_FMT_Y10, 10, 2, },
+	{ V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10,
+	  V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y8_1X8,
+	  V4L2_PIX_FMT_Y12, 12, 2, },
+	{ V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
+	  V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
+	  V4L2_PIX_FMT_SBGGR8, 8, 1, },
+	{ V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
+	  V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
+	  V4L2_PIX_FMT_SGBRG8, 8, 1, },
+	{ V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
+	  V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
+	  V4L2_PIX_FMT_SGRBG8, 8, 1, },
+	{ V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
+	  V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
+	  V4L2_PIX_FMT_SRGGB8, 8, 1, },
+	{ V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8,
+	  V4L2_MBUS_FMT_SBGGR10_1X10, 0,
+	  V4L2_PIX_FMT_SBGGR10DPCM8, 8, 1, },
+	{ V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8,
+	  V4L2_MBUS_FMT_SGBRG10_1X10, 0,
+	  V4L2_PIX_FMT_SGBRG10DPCM8, 8, 1, },
+	{ V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+	  V4L2_MBUS_FMT_SGRBG10_1X10, 0,
+	  V4L2_PIX_FMT_SGRBG10DPCM8, 8, 1, },
+	{ V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8,
+	  V4L2_MBUS_FMT_SRGGB10_1X10, 0,
+	  V4L2_PIX_FMT_SRGGB10DPCM8, 8, 1, },
+	{ V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10,
+	  V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8,
+	  V4L2_PIX_FMT_SBGGR10, 10, 2, },
+	{ V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10,
+	  V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG8_1X8,
+	  V4L2_PIX_FMT_SGBRG10, 10, 2, },
+	{ V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10,
+	  V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG8_1X8,
+	  V4L2_PIX_FMT_SGRBG10, 10, 2, },
+	{ V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10,
+	  V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB8_1X8,
+	  V4L2_PIX_FMT_SRGGB10, 10, 2, },
+	{ V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10,
+	  V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR8_1X8,
+	  V4L2_PIX_FMT_SBGGR12, 12, 2, },
+	{ V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10,
+	  V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG8_1X8,
+	  V4L2_PIX_FMT_SGBRG12, 12, 2, },
+	{ V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10,
+	  V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG8_1X8,
+	  V4L2_PIX_FMT_SGRBG12, 12, 2, },
+	{ V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10,
+	  V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB8_1X8,
+	  V4L2_PIX_FMT_SRGGB12, 12, 2, },
+	{ V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16,
+	  V4L2_MBUS_FMT_UYVY8_1X16, 0,
+	  V4L2_PIX_FMT_UYVY, 16, 2, },
+	{ V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16,
+	  V4L2_MBUS_FMT_YUYV8_1X16, 0,
+	  V4L2_PIX_FMT_YUYV, 16, 2, },
+	{ V4L2_MBUS_FMT_UYVY8_2X8, V4L2_MBUS_FMT_UYVY8_2X8,
+	  V4L2_MBUS_FMT_UYVY8_2X8, 0,
+	  V4L2_PIX_FMT_UYVY, 8, 2, },
+	{ V4L2_MBUS_FMT_YUYV8_2X8, V4L2_MBUS_FMT_YUYV8_2X8,
+	  V4L2_MBUS_FMT_YUYV8_2X8, 0,
+	  V4L2_PIX_FMT_YUYV, 8, 2, },
+	/* Empty entry to catch the unsupported pixel code (0) used by the CCDC
+	 * module and avoid NULL pointer dereferences.
+	 */
+	{ 0, }
+};
+
+const struct isp_format_info *
+omap3isp_video_format_info(enum v4l2_mbus_pixelcode code)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+		if (formats[i].code == code)
+			return &formats[i];
+	}
+
+	return NULL;
+}
+
+/*
+ * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format
+ * @video: ISP video instance
+ * @mbus: v4l2_mbus_framefmt format (input)
+ * @pix: v4l2_pix_format format (output)
+ *
+ * Fill the output pix structure with information from the input mbus format.
+ * The bytesperline and sizeimage fields are computed from the requested bytes
+ * per line value in the pix format and information from the video instance.
+ *
+ * Return the number of padding bytes at end of line.
+ */
+static unsigned int isp_video_mbus_to_pix(const struct isp_video *video,
+					  const struct v4l2_mbus_framefmt *mbus,
+					  struct v4l2_pix_format *pix)
+{
+	unsigned int bpl = pix->bytesperline;
+	unsigned int min_bpl;
+	unsigned int i;
+
+	memset(pix, 0, sizeof(*pix));
+	pix->width = mbus->width;
+	pix->height = mbus->height;
+
+	for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+		if (formats[i].code == mbus->code)
+			break;
+	}
+
+	if (WARN_ON(i == ARRAY_SIZE(formats)))
+		return 0;
+
+	min_bpl = pix->width * formats[i].bpp;
+
+	/* Clamp the requested bytes per line value. If the maximum bytes per
+	 * line value is zero, the module doesn't support user configurable line
+	 * sizes. Override the requested value with the minimum in that case.
+	 */
+	if (video->bpl_max)
+		bpl = clamp(bpl, min_bpl, video->bpl_max);
+	else
+		bpl = min_bpl;
+
+	if (!video->bpl_zero_padding || bpl != min_bpl)
+		bpl = ALIGN(bpl, video->bpl_alignment);
+
+	pix->pixelformat = formats[i].pixelformat;
+	pix->bytesperline = bpl;
+	pix->sizeimage = pix->bytesperline * pix->height;
+	pix->colorspace = mbus->colorspace;
+	pix->field = mbus->field;
+
+	return bpl - min_bpl;
+}
+
+static void isp_video_pix_to_mbus(const struct v4l2_pix_format *pix,
+				  struct v4l2_mbus_framefmt *mbus)
+{
+	unsigned int i;
+
+	memset(mbus, 0, sizeof(*mbus));
+	mbus->width = pix->width;
+	mbus->height = pix->height;
+
+	/* Skip the last format in the loop so that it will be selected if no
+	 * match is found.
+	 */
+	for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) {
+		if (formats[i].pixelformat == pix->pixelformat)
+			break;
+	}
+
+	mbus->code = formats[i].code;
+	mbus->colorspace = pix->colorspace;
+	mbus->field = pix->field;
+}
+
+static struct v4l2_subdev *
+isp_video_remote_subdev(struct isp_video *video, u32 *pad)
+{
+	struct media_pad *remote;
+
+	remote = media_entity_remote_source(&video->pad);
+
+	if (remote == NULL ||
+	    media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+		return NULL;
+
+	if (pad)
+		*pad = remote->index;
+
+	return media_entity_to_v4l2_subdev(remote->entity);
+}
+
+/* Return a pointer to the ISP video instance at the far end of the pipeline. */
+static int isp_video_get_graph_data(struct isp_video *video,
+				    struct isp_pipeline *pipe)
+{
+	struct media_entity_graph graph;
+	struct media_entity *entity = &video->video.entity;
+	struct media_device *mdev = entity->parent;
+	struct isp_video *far_end = NULL;
+
+	mutex_lock(&mdev->graph_mutex);
+	media_entity_graph_walk_start(&graph, entity);
+
+	while ((entity = media_entity_graph_walk_next(&graph))) {
+		struct isp_video *__video;
+
+		pipe->entities |= 1 << entity->id;
+
+		if (far_end != NULL)
+			continue;
+
+		if (entity == &video->video.entity)
+			continue;
+
+		if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+			continue;
+
+		__video = to_isp_video(media_entity_to_video_device(entity));
+		if (__video->type != video->type)
+			far_end = __video;
+	}
+
+	mutex_unlock(&mdev->graph_mutex);
+
+	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		pipe->input = far_end;
+		pipe->output = video;
+	} else {
+		if (far_end == NULL)
+			return -EPIPE;
+
+		pipe->input = video;
+		pipe->output = far_end;
+	}
+
+	return 0;
+}
+
+/*
+ * Validate a pipeline by checking both ends of all links for format
+ * discrepancies.
+ *
+ * Compute the minimum time per frame value as the maximum of time per frame
+ * limits reported by every block in the pipeline.
+ *
+ * Return 0 if all formats match, or -EPIPE if at least one link is found with
+ * different formats on its two ends or if the pipeline doesn't start with a
+ * video source (either a subdev with no input pad, or a non-subdev entity).
+ */
+static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
+{
+	struct isp_device *isp = pipe->output->isp;
+	struct media_pad *pad;
+	struct v4l2_subdev *subdev;
+
+	subdev = isp_video_remote_subdev(pipe->output, NULL);
+	if (subdev == NULL)
+		return -EPIPE;
+
+	while (1) {
+		/* Retrieve the sink format */
+		pad = &subdev->entity.pads[0];
+		if (!(pad->flags & MEDIA_PAD_FL_SINK))
+			break;
+
+		/* Update the maximum frame rate */
+		if (subdev == &isp->isp_res.subdev)
+			omap3isp_resizer_max_rate(&isp->isp_res,
+						  &pipe->max_rate);
+
+		/* Retrieve the source format. Return an error if no source
+		 * entity can be found, and stop checking the pipeline if the
+		 * source entity isn't a subdev.
+		 */
+		pad = media_entity_remote_source(pad);
+		if (pad == NULL)
+			return -EPIPE;
+
+		if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+			break;
+
+		subdev = media_entity_to_v4l2_subdev(pad->entity);
+	}
+
+	return 0;
+}
+
+static int
+__isp_video_get_format(struct isp_video *video, struct v4l2_format *format)
+{
+	struct v4l2_subdev_format fmt;
+	struct v4l2_subdev *subdev;
+	u32 pad;
+	int ret;
+
+	subdev = isp_video_remote_subdev(video, &pad);
+	if (subdev == NULL)
+		return -EINVAL;
+
+	mutex_lock(&video->mutex);
+
+	fmt.pad = pad;
+	fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+	ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
+	if (ret == -ENOIOCTLCMD)
+		ret = -EINVAL;
+
+	mutex_unlock(&video->mutex);
+
+	if (ret)
+		return ret;
+
+	format->type = video->type;
+	return isp_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix);
+}
+
+static int
+isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh)
+{
+	struct v4l2_format format;
+	int ret;
+
+	memcpy(&format, &vfh->format, sizeof(format));
+	ret = __isp_video_get_format(video, &format);
+	if (ret < 0)
+		return ret;
+
+	if (vfh->format.fmt.pix.pixelformat != format.fmt.pix.pixelformat ||
+	    vfh->format.fmt.pix.height != format.fmt.pix.height ||
+	    vfh->format.fmt.pix.width != format.fmt.pix.width ||
+	    vfh->format.fmt.pix.bytesperline != format.fmt.pix.bytesperline ||
+	    vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage)
+		return -EINVAL;
+
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * IOMMU management
+ */
+
+#define IOMMU_FLAG	(IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8)
+
+/*
+ * ispmmu_vmap - Wrapper for Virtual memory mapping of a scatter gather list
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @sglist: Pointer to source Scatter gather list to allocate.
+ * @sglen: Number of elements of the scatter-gatter list.
+ *
+ * Returns a resulting mapped device address by the ISP MMU, or -ENOMEM if
+ * we ran out of memory.
+ */
+static dma_addr_t
+ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen)
+{
+	struct sg_table *sgt;
+	u32 da;
+
+	sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
+	if (sgt == NULL)
+		return -ENOMEM;
+
+	sgt->sgl = (struct scatterlist *)sglist;
+	sgt->nents = sglen;
+	sgt->orig_nents = sglen;
+
+	da = omap_iommu_vmap(isp->domain, isp->dev, 0, sgt, IOMMU_FLAG);
+	if (IS_ERR_VALUE(da))
+		kfree(sgt);
+
+	return da;
+}
+
+/*
+ * ispmmu_vunmap - Unmap a device address from the ISP MMU
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @da: Device address generated from a ispmmu_vmap call.
+ */
+static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da)
+{
+	struct sg_table *sgt;
+
+	sgt = omap_iommu_vunmap(isp->domain, isp->dev, (u32)da);
+	kfree(sgt);
+}
+
+/* -----------------------------------------------------------------------------
+ * Video queue operations
+ */
+
+static void isp_video_queue_prepare(struct isp_video_queue *queue,
+				    unsigned int *nbuffers, unsigned int *size)
+{
+	struct isp_video_fh *vfh =
+		container_of(queue, struct isp_video_fh, queue);
+	struct isp_video *video = vfh->video;
+
+	*size = vfh->format.fmt.pix.sizeimage;
+	if (*size == 0)
+		return;
+
+	*nbuffers = min(*nbuffers, video->capture_mem / PAGE_ALIGN(*size));
+}
+
+static void isp_video_buffer_cleanup(struct isp_video_buffer *buf)
+{
+	struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
+	struct isp_buffer *buffer = to_isp_buffer(buf);
+	struct isp_video *video = vfh->video;
+
+	if (buffer->isp_addr) {
+		ispmmu_vunmap(video->isp, buffer->isp_addr);
+		buffer->isp_addr = 0;
+	}
+}
+
+static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
+{
+	struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
+	struct isp_buffer *buffer = to_isp_buffer(buf);
+	struct isp_video *video = vfh->video;
+	unsigned long addr;
+
+	addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen);
+	if (IS_ERR_VALUE(addr))
+		return -EIO;
+
+	if (!IS_ALIGNED(addr, 32)) {
+		dev_dbg(video->isp->dev, "Buffer address must be "
+			"aligned to 32 bytes boundary.\n");
+		ispmmu_vunmap(video->isp, buffer->isp_addr);
+		return -EINVAL;
+	}
+
+	buf->vbuf.bytesused = vfh->format.fmt.pix.sizeimage;
+	buffer->isp_addr = addr;
+	return 0;
+}
+
+/*
+ * isp_video_buffer_queue - Add buffer to streaming queue
+ * @buf: Video buffer
+ *
+ * In memory-to-memory mode, start streaming on the pipeline if buffers are
+ * queued on both the input and the output, if the pipeline isn't already busy.
+ * If the pipeline is busy, it will be restarted in the output module interrupt
+ * handler.
+ */
+static void isp_video_buffer_queue(struct isp_video_buffer *buf)
+{
+	struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
+	struct isp_buffer *buffer = to_isp_buffer(buf);
+	struct isp_video *video = vfh->video;
+	struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
+	enum isp_pipeline_state state;
+	unsigned long flags;
+	unsigned int empty;
+	unsigned int start;
+
+	empty = list_empty(&video->dmaqueue);
+	list_add_tail(&buffer->buffer.irqlist, &video->dmaqueue);
+
+	if (empty) {
+		if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			state = ISP_PIPELINE_QUEUE_OUTPUT;
+		else
+			state = ISP_PIPELINE_QUEUE_INPUT;
+
+		spin_lock_irqsave(&pipe->lock, flags);
+		pipe->state |= state;
+		video->ops->queue(video, buffer);
+		video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED;
+
+		start = isp_pipeline_ready(pipe);
+		if (start)
+			pipe->state |= ISP_PIPELINE_STREAM;
+		spin_unlock_irqrestore(&pipe->lock, flags);
+
+		if (start)
+			omap3isp_pipeline_set_stream(pipe,
+						ISP_PIPELINE_STREAM_SINGLESHOT);
+	}
+}
+
+static const struct isp_video_queue_operations isp_video_queue_ops = {
+	.queue_prepare = &isp_video_queue_prepare,
+	.buffer_prepare = &isp_video_buffer_prepare,
+	.buffer_queue = &isp_video_buffer_queue,
+	.buffer_cleanup = &isp_video_buffer_cleanup,
+};
+
+/*
+ * omap3isp_video_buffer_next - Complete the current buffer and return the next
+ * @video: ISP video object
+ *
+ * Remove the current video buffer from the DMA queue and fill its timestamp,
+ * field count and state fields before waking up its completion handler.
+ *
+ * For capture video nodes the buffer state is set to ISP_BUF_STATE_DONE if no
+ * error has been flagged in the pipeline, or to ISP_BUF_STATE_ERROR otherwise.
+ * For video output nodes the buffer state is always set to ISP_BUF_STATE_DONE.
+ *
+ * The DMA queue is expected to contain at least one buffer.
+ *
+ * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is
+ * empty.
+ */
+struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
+{
+	struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
+	struct isp_video_queue *queue = video->queue;
+	enum isp_pipeline_state state;
+	struct isp_video_buffer *buf;
+	unsigned long flags;
+	struct timespec ts;
+
+	spin_lock_irqsave(&queue->irqlock, flags);
+	if (WARN_ON(list_empty(&video->dmaqueue))) {
+		spin_unlock_irqrestore(&queue->irqlock, flags);
+		return NULL;
+	}
+
+	buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer,
+			       irqlist);
+	list_del(&buf->irqlist);
+	spin_unlock_irqrestore(&queue->irqlock, flags);
+
+	ktime_get_ts(&ts);
+	buf->vbuf.timestamp.tv_sec = ts.tv_sec;
+	buf->vbuf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+
+	/* Do frame number propagation only if this is the output video node.
+	 * Frame number either comes from the CSI receivers or it gets
+	 * incremented here if H3A is not active.
+	 * Note: There is no guarantee that the output buffer will finish
+	 * first, so the input number might lag behind by 1 in some cases.
+	 */
+	if (video == pipe->output && !pipe->do_propagation)
+		buf->vbuf.sequence = atomic_inc_return(&pipe->frame_number);
+	else
+		buf->vbuf.sequence = atomic_read(&pipe->frame_number);
+
+	/* Report pipeline errors to userspace on the capture device side. */
+	if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) {
+		buf->state = ISP_BUF_STATE_ERROR;
+		pipe->error = false;
+	} else {
+		buf->state = ISP_BUF_STATE_DONE;
+	}
+
+	wake_up(&buf->wait);
+
+	if (list_empty(&video->dmaqueue)) {
+		if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			state = ISP_PIPELINE_QUEUE_OUTPUT
+			      | ISP_PIPELINE_STREAM;
+		else
+			state = ISP_PIPELINE_QUEUE_INPUT
+			      | ISP_PIPELINE_STREAM;
+
+		spin_lock_irqsave(&pipe->lock, flags);
+		pipe->state &= ~state;
+		if (video->pipe.stream_state == ISP_PIPELINE_STREAM_CONTINUOUS)
+			video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
+		spin_unlock_irqrestore(&pipe->lock, flags);
+		return NULL;
+	}
+
+	if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) {
+		spin_lock_irqsave(&pipe->lock, flags);
+		pipe->state &= ~ISP_PIPELINE_STREAM;
+		spin_unlock_irqrestore(&pipe->lock, flags);
+	}
+
+	buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer,
+			       irqlist);
+	buf->state = ISP_BUF_STATE_ACTIVE;
+	return to_isp_buffer(buf);
+}
+
+/*
+ * omap3isp_video_resume - Perform resume operation on the buffers
+ * @video: ISP video object
+ * @continuous: Pipeline is in single shot mode if 0 or continuous mode otherwise
+ *
+ * This function is intended to be used on suspend/resume scenario. It
+ * requests video queue layer to discard buffers marked as DONE if it's in
+ * continuous mode and requests ISP modules to queue again the ACTIVE buffer
+ * if there's any.
+ */
+void omap3isp_video_resume(struct isp_video *video, int continuous)
+{
+	struct isp_buffer *buf = NULL;
+
+	if (continuous && video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		omap3isp_video_queue_discard_done(video->queue);
+
+	if (!list_empty(&video->dmaqueue)) {
+		buf = list_first_entry(&video->dmaqueue,
+				       struct isp_buffer, buffer.irqlist);
+		video->ops->queue(video, buf);
+		video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED;
+	} else {
+		if (continuous)
+			video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
+	}
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 ioctls
+ */
+
+static int
+isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
+{
+	struct isp_video *video = video_drvdata(file);
+
+	strlcpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, video->video.name, sizeof(cap->card));
+	strlcpy(cap->bus_info, "media", sizeof(cap->bus_info));
+
+	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+	else
+		cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+static int
+isp_video_get_format(struct file *file, void *fh, struct v4l2_format *format)
+{
+	struct isp_video_fh *vfh = to_isp_video_fh(fh);
+	struct isp_video *video = video_drvdata(file);
+
+	if (format->type != video->type)
+		return -EINVAL;
+
+	mutex_lock(&video->mutex);
+	*format = vfh->format;
+	mutex_unlock(&video->mutex);
+
+	return 0;
+}
+
+static int
+isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
+{
+	struct isp_video_fh *vfh = to_isp_video_fh(fh);
+	struct isp_video *video = video_drvdata(file);
+	struct v4l2_mbus_framefmt fmt;
+
+	if (format->type != video->type)
+		return -EINVAL;
+
+	mutex_lock(&video->mutex);
+
+	/* Fill the bytesperline and sizeimage fields by converting to media bus
+	 * format and back to pixel format.
+	 */
+	isp_video_pix_to_mbus(&format->fmt.pix, &fmt);
+	isp_video_mbus_to_pix(video, &fmt, &format->fmt.pix);
+
+	vfh->format = *format;
+
+	mutex_unlock(&video->mutex);
+	return 0;
+}
+
+static int
+isp_video_try_format(struct file *file, void *fh, struct v4l2_format *format)
+{
+	struct isp_video *video = video_drvdata(file);
+	struct v4l2_subdev_format fmt;
+	struct v4l2_subdev *subdev;
+	u32 pad;
+	int ret;
+
+	if (format->type != video->type)
+		return -EINVAL;
+
+	subdev = isp_video_remote_subdev(video, &pad);
+	if (subdev == NULL)
+		return -EINVAL;
+
+	isp_video_pix_to_mbus(&format->fmt.pix, &fmt.format);
+
+	fmt.pad = pad;
+	fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+	ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
+	if (ret)
+		return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+
+	isp_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix);
+	return 0;
+}
+
+static int
+isp_video_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap)
+{
+	struct isp_video *video = video_drvdata(file);
+	struct v4l2_subdev *subdev;
+	int ret;
+
+	subdev = isp_video_remote_subdev(video, NULL);
+	if (subdev == NULL)
+		return -EINVAL;
+
+	mutex_lock(&video->mutex);
+	ret = v4l2_subdev_call(subdev, video, cropcap, cropcap);
+	mutex_unlock(&video->mutex);
+
+	return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+}
+
+static int
+isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+	struct isp_video *video = video_drvdata(file);
+	struct v4l2_subdev_format format;
+	struct v4l2_subdev *subdev;
+	u32 pad;
+	int ret;
+
+	subdev = isp_video_remote_subdev(video, &pad);
+	if (subdev == NULL)
+		return -EINVAL;
+
+	/* Try the get crop operation first and fallback to get format if not
+	 * implemented.
+	 */
+	ret = v4l2_subdev_call(subdev, video, g_crop, crop);
+	if (ret != -ENOIOCTLCMD)
+		return ret;
+
+	format.pad = pad;
+	format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+	ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &format);
+	if (ret < 0)
+		return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+
+	crop->c.left = 0;
+	crop->c.top = 0;
+	crop->c.width = format.format.width;
+	crop->c.height = format.format.height;
+
+	return 0;
+}
+
+static int
+isp_video_set_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+	struct isp_video *video = video_drvdata(file);
+	struct v4l2_subdev *subdev;
+	int ret;
+
+	subdev = isp_video_remote_subdev(video, NULL);
+	if (subdev == NULL)
+		return -EINVAL;
+
+	mutex_lock(&video->mutex);
+	ret = v4l2_subdev_call(subdev, video, s_crop, crop);
+	mutex_unlock(&video->mutex);
+
+	return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+}
+
+static int
+isp_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+	struct isp_video_fh *vfh = to_isp_video_fh(fh);
+	struct isp_video *video = video_drvdata(file);
+
+	if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+	    video->type != a->type)
+		return -EINVAL;
+
+	memset(a, 0, sizeof(*a));
+	a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+	a->parm.output.timeperframe = vfh->timeperframe;
+
+	return 0;
+}
+
+static int
+isp_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+	struct isp_video_fh *vfh = to_isp_video_fh(fh);
+	struct isp_video *video = video_drvdata(file);
+
+	if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+	    video->type != a->type)
+		return -EINVAL;
+
+	if (a->parm.output.timeperframe.denominator == 0)
+		a->parm.output.timeperframe.denominator = 1;
+
+	vfh->timeperframe = a->parm.output.timeperframe;
+
+	return 0;
+}
+
+static int
+isp_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb)
+{
+	struct isp_video_fh *vfh = to_isp_video_fh(fh);
+
+	return omap3isp_video_queue_reqbufs(&vfh->queue, rb);
+}
+
+static int
+isp_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+	struct isp_video_fh *vfh = to_isp_video_fh(fh);
+
+	return omap3isp_video_queue_querybuf(&vfh->queue, b);
+}
+
+static int
+isp_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+	struct isp_video_fh *vfh = to_isp_video_fh(fh);
+
+	return omap3isp_video_queue_qbuf(&vfh->queue, b);
+}
+
+static int
+isp_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+	struct isp_video_fh *vfh = to_isp_video_fh(fh);
+
+	return omap3isp_video_queue_dqbuf(&vfh->queue, b,
+					  file->f_flags & O_NONBLOCK);
+}
+
+static int isp_video_check_external_subdevs(struct isp_video *video,
+					    struct isp_pipeline *pipe)
+{
+	struct isp_device *isp = video->isp;
+	struct media_entity *ents[] = {
+		&isp->isp_csi2a.subdev.entity,
+		&isp->isp_csi2c.subdev.entity,
+		&isp->isp_ccp2.subdev.entity,
+		&isp->isp_ccdc.subdev.entity
+	};
+	struct media_pad *source_pad;
+	struct media_entity *source = NULL;
+	struct media_entity *sink;
+	struct v4l2_subdev_format fmt;
+	struct v4l2_ext_controls ctrls;
+	struct v4l2_ext_control ctrl;
+	unsigned int i;
+	int ret = 0;
+
+	for (i = 0; i < ARRAY_SIZE(ents); i++) {
+		/* Is the entity part of the pipeline? */
+		if (!(pipe->entities & (1 << ents[i]->id)))
+			continue;
+
+		/* ISP entities have always sink pad == 0. Find source. */
+		source_pad = media_entity_remote_source(&ents[i]->pads[0]);
+		if (source_pad == NULL)
+			continue;
+
+		source = source_pad->entity;
+		sink = ents[i];
+		break;
+	}
+
+	if (!source) {
+		dev_warn(isp->dev, "can't find source, failing now\n");
+		return ret;
+	}
+
+	if (media_entity_type(source) != MEDIA_ENT_T_V4L2_SUBDEV)
+		return 0;
+
+	pipe->external = media_entity_to_v4l2_subdev(source);
+
+	fmt.pad = source_pad->index;
+	fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+	ret = v4l2_subdev_call(media_entity_to_v4l2_subdev(sink),
+			       pad, get_fmt, NULL, &fmt);
+	if (unlikely(ret < 0)) {
+		dev_warn(isp->dev, "get_fmt returned null!\n");
+		return ret;
+	}
+
+	pipe->external_width =
+		omap3isp_video_format_info(fmt.format.code)->width;
+
+	memset(&ctrls, 0, sizeof(ctrls));
+	memset(&ctrl, 0, sizeof(ctrl));
+
+	ctrl.id = V4L2_CID_PIXEL_RATE;
+
+	ctrls.count = 1;
+	ctrls.controls = &ctrl;
+
+	ret = v4l2_g_ext_ctrls(pipe->external->ctrl_handler, &ctrls);
+	if (ret < 0) {
+		dev_warn(isp->dev, "no pixel rate control in subdev %s\n",
+			 pipe->external->name);
+		return ret;
+	}
+
+	pipe->external_rate = ctrl.value64;
+
+	if (pipe->entities & (1 << isp->isp_ccdc.subdev.entity.id)) {
+		unsigned int rate = UINT_MAX;
+		/*
+		 * Check that maximum allowed CCDC pixel rate isn't
+		 * exceeded by the pixel rate.
+		 */
+		omap3isp_ccdc_max_rate(&isp->isp_ccdc, &rate);
+		if (pipe->external_rate > rate)
+			return -ENOSPC;
+	}
+
+	return 0;
+}
+
+/*
+ * Stream management
+ *
+ * Every ISP pipeline has a single input and a single output. The input can be
+ * either a sensor or a video node. The output is always a video node.
+ *
+ * As every pipeline has an output video node, the ISP video objects at the
+ * pipeline output stores the pipeline state. It tracks the streaming state of
+ * both the input and output, as well as the availability of buffers.
+ *
+ * In sensor-to-memory mode, frames are always available at the pipeline input.
+ * Starting the sensor usually requires I2C transfers and must be done in
+ * interruptible context. The pipeline is started and stopped synchronously
+ * to the stream on/off commands. All modules in the pipeline will get their
+ * subdev set stream handler called. The module at the end of the pipeline must
+ * delay starting the hardware until buffers are available at its output.
+ *
+ * In memory-to-memory mode, starting/stopping the stream requires
+ * synchronization between the input and output. ISP modules can't be stopped
+ * in the middle of a frame, and at least some of the modules seem to become
+ * busy as soon as they're started, even if they don't receive a frame start
+ * event. For that reason frames need to be processed in single-shot mode. The
+ * driver needs to wait until a frame is completely processed and written to
+ * memory before restarting the pipeline for the next frame. Pipelined
+ * processing might be possible but requires more testing.
+ *
+ * Stream start must be delayed until buffers are available at both the input
+ * and output. The pipeline must be started in the videobuf queue callback with
+ * the buffers queue spinlock held. The modules subdev set stream operation must
+ * not sleep.
+ */
+static int
+isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
+{
+	struct isp_video_fh *vfh = to_isp_video_fh(fh);
+	struct isp_video *video = video_drvdata(file);
+	enum isp_pipeline_state state;
+	struct isp_pipeline *pipe;
+	unsigned long flags;
+	int ret;
+
+	if (type != video->type)
+		return -EINVAL;
+
+	mutex_lock(&video->stream_lock);
+
+	if (video->streaming) {
+		mutex_unlock(&video->stream_lock);
+		return -EBUSY;
+	}
+
+	/* Start streaming on the pipeline. No link touching an entity in the
+	 * pipeline can be activated or deactivated once streaming is started.
+	 */
+	pipe = video->video.entity.pipe
+	     ? to_isp_pipeline(&video->video.entity) : &video->pipe;
+
+	pipe->entities = 0;
+
+	if (video->isp->pdata->set_constraints)
+		video->isp->pdata->set_constraints(video->isp, true);
+	pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]);
+	pipe->max_rate = pipe->l3_ick;
+
+	ret = media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
+	if (ret < 0)
+		goto err_pipeline_start;
+
+	/* Verify that the currently configured format matches the output of
+	 * the connected subdev.
+	 */
+	ret = isp_video_check_format(video, vfh);
+	if (ret < 0)
+		goto err_check_format;
+
+	video->bpl_padding = ret;
+	video->bpl_value = vfh->format.fmt.pix.bytesperline;
+
+	ret = isp_video_get_graph_data(video, pipe);
+	if (ret < 0)
+		goto err_check_format;
+
+	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		state = ISP_PIPELINE_STREAM_OUTPUT | ISP_PIPELINE_IDLE_OUTPUT;
+	else
+		state = ISP_PIPELINE_STREAM_INPUT | ISP_PIPELINE_IDLE_INPUT;
+
+	ret = isp_video_check_external_subdevs(video, pipe);
+	if (ret < 0)
+		goto err_check_format;
+
+	/* Validate the pipeline and update its state. */
+	ret = isp_video_validate_pipeline(pipe);
+	if (ret < 0)
+		goto err_check_format;
+
+	pipe->error = false;
+
+	spin_lock_irqsave(&pipe->lock, flags);
+	pipe->state &= ~ISP_PIPELINE_STREAM;
+	pipe->state |= state;
+	spin_unlock_irqrestore(&pipe->lock, flags);
+
+	/* Set the maximum time per frame as the value requested by userspace.
+	 * This is a soft limit that can be overridden if the hardware doesn't
+	 * support the request limit.
+	 */
+	if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		pipe->max_timeperframe = vfh->timeperframe;
+
+	video->queue = &vfh->queue;
+	INIT_LIST_HEAD(&video->dmaqueue);
+	atomic_set(&pipe->frame_number, -1);
+
+	ret = omap3isp_video_queue_streamon(&vfh->queue);
+	if (ret < 0)
+		goto err_check_format;
+
+	/* In sensor-to-memory mode, the stream can be started synchronously
+	 * to the stream on command. In memory-to-memory mode, it will be
+	 * started when buffers are queued on both the input and output.
+	 */
+	if (pipe->input == NULL) {
+		ret = omap3isp_pipeline_set_stream(pipe,
+					      ISP_PIPELINE_STREAM_CONTINUOUS);
+		if (ret < 0)
+			goto err_set_stream;
+		spin_lock_irqsave(&video->queue->irqlock, flags);
+		if (list_empty(&video->dmaqueue))
+			video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
+		spin_unlock_irqrestore(&video->queue->irqlock, flags);
+	}
+
+	video->streaming = 1;
+
+	mutex_unlock(&video->stream_lock);
+	return 0;
+
+err_set_stream:
+	omap3isp_video_queue_streamoff(&vfh->queue);
+err_check_format:
+	media_entity_pipeline_stop(&video->video.entity);
+err_pipeline_start:
+	if (video->isp->pdata->set_constraints)
+		video->isp->pdata->set_constraints(video->isp, false);
+	/* The DMA queue must be emptied here, otherwise CCDC interrupts that
+	 * will get triggered the next time the CCDC is powered up will try to
+	 * access buffers that might have been freed but still present in the
+	 * DMA queue. This can easily get triggered if the above
+	 * omap3isp_pipeline_set_stream() call fails on a system with a
+	 * free-running sensor.
+	 */
+	INIT_LIST_HEAD(&video->dmaqueue);
+	video->queue = NULL;
+
+	mutex_unlock(&video->stream_lock);
+	return ret;
+}
+
+static int
+isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
+{
+	struct isp_video_fh *vfh = to_isp_video_fh(fh);
+	struct isp_video *video = video_drvdata(file);
+	struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
+	enum isp_pipeline_state state;
+	unsigned int streaming;
+	unsigned long flags;
+
+	if (type != video->type)
+		return -EINVAL;
+
+	mutex_lock(&video->stream_lock);
+
+	/* Make sure we're not streaming yet. */
+	mutex_lock(&vfh->queue.lock);
+	streaming = vfh->queue.streaming;
+	mutex_unlock(&vfh->queue.lock);
+
+	if (!streaming)
+		goto done;
+
+	/* Update the pipeline state. */
+	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		state = ISP_PIPELINE_STREAM_OUTPUT
+		      | ISP_PIPELINE_QUEUE_OUTPUT;
+	else
+		state = ISP_PIPELINE_STREAM_INPUT
+		      | ISP_PIPELINE_QUEUE_INPUT;
+
+	spin_lock_irqsave(&pipe->lock, flags);
+	pipe->state &= ~state;
+	spin_unlock_irqrestore(&pipe->lock, flags);
+
+	/* Stop the stream. */
+	omap3isp_pipeline_set_stream(pipe, ISP_PIPELINE_STREAM_STOPPED);
+	omap3isp_video_queue_streamoff(&vfh->queue);
+	video->queue = NULL;
+	video->streaming = 0;
+
+	if (video->isp->pdata->set_constraints)
+		video->isp->pdata->set_constraints(video->isp, false);
+	media_entity_pipeline_stop(&video->video.entity);
+
+done:
+	mutex_unlock(&video->stream_lock);
+	return 0;
+}
+
+static int
+isp_video_enum_input(struct file *file, void *fh, struct v4l2_input *input)
+{
+	if (input->index > 0)
+		return -EINVAL;
+
+	strlcpy(input->name, "camera", sizeof(input->name));
+	input->type = V4L2_INPUT_TYPE_CAMERA;
+
+	return 0;
+}
+
+static int
+isp_video_g_input(struct file *file, void *fh, unsigned int *input)
+{
+	*input = 0;
+
+	return 0;
+}
+
+static int
+isp_video_s_input(struct file *file, void *fh, unsigned int input)
+{
+	return input == 0 ? 0 : -EINVAL;
+}
+
+static const struct v4l2_ioctl_ops isp_video_ioctl_ops = {
+	.vidioc_querycap		= isp_video_querycap,
+	.vidioc_g_fmt_vid_cap		= isp_video_get_format,
+	.vidioc_s_fmt_vid_cap		= isp_video_set_format,
+	.vidioc_try_fmt_vid_cap		= isp_video_try_format,
+	.vidioc_g_fmt_vid_out		= isp_video_get_format,
+	.vidioc_s_fmt_vid_out		= isp_video_set_format,
+	.vidioc_try_fmt_vid_out		= isp_video_try_format,
+	.vidioc_cropcap			= isp_video_cropcap,
+	.vidioc_g_crop			= isp_video_get_crop,
+	.vidioc_s_crop			= isp_video_set_crop,
+	.vidioc_g_parm			= isp_video_get_param,
+	.vidioc_s_parm			= isp_video_set_param,
+	.vidioc_reqbufs			= isp_video_reqbufs,
+	.vidioc_querybuf		= isp_video_querybuf,
+	.vidioc_qbuf			= isp_video_qbuf,
+	.vidioc_dqbuf			= isp_video_dqbuf,
+	.vidioc_streamon		= isp_video_streamon,
+	.vidioc_streamoff		= isp_video_streamoff,
+	.vidioc_enum_input		= isp_video_enum_input,
+	.vidioc_g_input			= isp_video_g_input,
+	.vidioc_s_input			= isp_video_s_input,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 file operations
+ */
+
+static int isp_video_open(struct file *file)
+{
+	struct isp_video *video = video_drvdata(file);
+	struct isp_video_fh *handle;
+	int ret = 0;
+
+	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+	if (handle == NULL)
+		return -ENOMEM;
+
+	v4l2_fh_init(&handle->vfh, &video->video);
+	v4l2_fh_add(&handle->vfh);
+
+	/* If this is the first user, initialise the pipeline. */
+	if (omap3isp_get(video->isp) == NULL) {
+		ret = -EBUSY;
+		goto done;
+	}
+
+	ret = omap3isp_pipeline_pm_use(&video->video.entity, 1);
+	if (ret < 0) {
+		omap3isp_put(video->isp);
+		goto done;
+	}
+
+	omap3isp_video_queue_init(&handle->queue, video->type,
+				  &isp_video_queue_ops, video->isp->dev,
+				  sizeof(struct isp_buffer));
+
+	memset(&handle->format, 0, sizeof(handle->format));
+	handle->format.type = video->type;
+	handle->timeperframe.denominator = 1;
+
+	handle->video = video;
+	file->private_data = &handle->vfh;
+
+done:
+	if (ret < 0) {
+		v4l2_fh_del(&handle->vfh);
+		kfree(handle);
+	}
+
+	return ret;
+}
+
+static int isp_video_release(struct file *file)
+{
+	struct isp_video *video = video_drvdata(file);
+	struct v4l2_fh *vfh = file->private_data;
+	struct isp_video_fh *handle = to_isp_video_fh(vfh);
+
+	/* Disable streaming and free the buffers queue resources. */
+	isp_video_streamoff(file, vfh, video->type);
+
+	mutex_lock(&handle->queue.lock);
+	omap3isp_video_queue_cleanup(&handle->queue);
+	mutex_unlock(&handle->queue.lock);
+
+	omap3isp_pipeline_pm_use(&video->video.entity, 0);
+
+	/* Release the file handle. */
+	v4l2_fh_del(vfh);
+	kfree(handle);
+	file->private_data = NULL;
+
+	omap3isp_put(video->isp);
+
+	return 0;
+}
+
+static unsigned int isp_video_poll(struct file *file, poll_table *wait)
+{
+	struct isp_video_fh *vfh = to_isp_video_fh(file->private_data);
+	struct isp_video_queue *queue = &vfh->queue;
+
+	return omap3isp_video_queue_poll(queue, file, wait);
+}
+
+static int isp_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct isp_video_fh *vfh = to_isp_video_fh(file->private_data);
+
+	return omap3isp_video_queue_mmap(&vfh->queue, vma);
+}
+
+static struct v4l2_file_operations isp_video_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = video_ioctl2,
+	.open = isp_video_open,
+	.release = isp_video_release,
+	.poll = isp_video_poll,
+	.mmap = isp_video_mmap,
+};
+
+/* -----------------------------------------------------------------------------
+ * ISP video core
+ */
+
+static const struct isp_video_operations isp_video_dummy_ops = {
+};
+
+int omap3isp_video_init(struct isp_video *video, const char *name)
+{
+	const char *direction;
+	int ret;
+
+	switch (video->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		direction = "output";
+		video->pad.flags = MEDIA_PAD_FL_SINK;
+		break;
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		direction = "input";
+		video->pad.flags = MEDIA_PAD_FL_SOURCE;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	ret = media_entity_init(&video->video.entity, 1, &video->pad, 0);
+	if (ret < 0)
+		return ret;
+
+	mutex_init(&video->mutex);
+	atomic_set(&video->active, 0);
+
+	spin_lock_init(&video->pipe.lock);
+	mutex_init(&video->stream_lock);
+
+	/* Initialize the video device. */
+	if (video->ops == NULL)
+		video->ops = &isp_video_dummy_ops;
+
+	video->video.fops = &isp_video_fops;
+	snprintf(video->video.name, sizeof(video->video.name),
+		 "OMAP3 ISP %s %s", name, direction);
+	video->video.vfl_type = VFL_TYPE_GRABBER;
+	video->video.release = video_device_release_empty;
+	video->video.ioctl_ops = &isp_video_ioctl_ops;
+	video->pipe.stream_state = ISP_PIPELINE_STREAM_STOPPED;
+
+	video_set_drvdata(&video->video, video);
+
+	return 0;
+}
+
+void omap3isp_video_cleanup(struct isp_video *video)
+{
+	media_entity_cleanup(&video->video.entity);
+	mutex_destroy(&video->stream_lock);
+	mutex_destroy(&video->mutex);
+}
+
+int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev)
+{
+	int ret;
+
+	video->video.v4l2_dev = vdev;
+
+	ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1);
+	if (ret < 0)
+		printk(KERN_ERR "%s: could not register video device (%d)\n",
+			__func__, ret);
+
+	return ret;
+}
+
+void omap3isp_video_unregister(struct isp_video *video)
+{
+	if (video_is_registered(&video->video))
+		video_unregister_device(&video->video);
+}
diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h
new file mode 100644
index 0000000..1ad470e
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispvideo.h
@@ -0,0 +1,216 @@
+/*
+ * ispvideo.h
+ *
+ * TI OMAP3 ISP - Generic video node
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_VIDEO_H
+#define OMAP3_ISP_VIDEO_H
+
+#include <linux/v4l2-mediabus.h>
+#include <media/media-entity.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+
+#include "ispqueue.h"
+
+#define ISP_VIDEO_DRIVER_NAME		"ispvideo"
+#define ISP_VIDEO_DRIVER_VERSION	"0.0.2"
+
+struct isp_device;
+struct isp_video;
+struct v4l2_mbus_framefmt;
+struct v4l2_pix_format;
+
+/*
+ * struct isp_format_info - ISP media bus format information
+ * @code: V4L2 media bus format code
+ * @truncated: V4L2 media bus format code for the same format truncated to 10
+ *	bits. Identical to @code if the format is 10 bits wide or less.
+ * @uncompressed: V4L2 media bus format code for the corresponding uncompressed
+ *	format. Identical to @code if the format is not DPCM compressed.
+ * @flavor: V4L2 media bus format code for the same pixel layout but
+ *	shifted to be 8 bits per pixel. =0 if format is not shiftable.
+ * @pixelformat: V4L2 pixel format FCC identifier
+ * @width: Bits per pixel (when transferred over a bus)
+ * @bpp: Bytes per pixel (when stored in memory)
+ */
+struct isp_format_info {
+	enum v4l2_mbus_pixelcode code;
+	enum v4l2_mbus_pixelcode truncated;
+	enum v4l2_mbus_pixelcode uncompressed;
+	enum v4l2_mbus_pixelcode flavor;
+	u32 pixelformat;
+	unsigned int width;
+	unsigned int bpp;
+};
+
+enum isp_pipeline_stream_state {
+	ISP_PIPELINE_STREAM_STOPPED = 0,
+	ISP_PIPELINE_STREAM_CONTINUOUS = 1,
+	ISP_PIPELINE_STREAM_SINGLESHOT = 2,
+};
+
+enum isp_pipeline_state {
+	/* The stream has been started on the input video node. */
+	ISP_PIPELINE_STREAM_INPUT = 1,
+	/* The stream has been started on the output video node. */
+	ISP_PIPELINE_STREAM_OUTPUT = 2,
+	/* At least one buffer is queued on the input video node. */
+	ISP_PIPELINE_QUEUE_INPUT = 4,
+	/* At least one buffer is queued on the output video node. */
+	ISP_PIPELINE_QUEUE_OUTPUT = 8,
+	/* The input entity is idle, ready to be started. */
+	ISP_PIPELINE_IDLE_INPUT = 16,
+	/* The output entity is idle, ready to be started. */
+	ISP_PIPELINE_IDLE_OUTPUT = 32,
+	/* The pipeline is currently streaming. */
+	ISP_PIPELINE_STREAM = 64,
+};
+
+/*
+ * struct isp_pipeline - An ISP hardware pipeline
+ * @error: A hardware error occurred during capture
+ * @entities: Bitmask of entities in the pipeline (indexed by entity ID)
+ */
+struct isp_pipeline {
+	struct media_pipeline pipe;
+	spinlock_t lock;		/* Pipeline state and queue flags */
+	unsigned int state;
+	enum isp_pipeline_stream_state stream_state;
+	struct isp_video *input;
+	struct isp_video *output;
+	u32 entities;
+	unsigned long l3_ick;
+	unsigned int max_rate;
+	atomic_t frame_number;
+	bool do_propagation; /* of frame number */
+	bool error;
+	struct v4l2_fract max_timeperframe;
+	struct v4l2_subdev *external;
+	unsigned int external_rate;
+	unsigned int external_width;
+};
+
+#define to_isp_pipeline(__e) \
+	container_of((__e)->pipe, struct isp_pipeline, pipe)
+
+static inline int isp_pipeline_ready(struct isp_pipeline *pipe)
+{
+	return pipe->state == (ISP_PIPELINE_STREAM_INPUT |
+			       ISP_PIPELINE_STREAM_OUTPUT |
+			       ISP_PIPELINE_QUEUE_INPUT |
+			       ISP_PIPELINE_QUEUE_OUTPUT |
+			       ISP_PIPELINE_IDLE_INPUT |
+			       ISP_PIPELINE_IDLE_OUTPUT);
+}
+
+/*
+ * struct isp_buffer - ISP buffer
+ * @buffer: ISP video buffer
+ * @isp_addr: MMU mapped address (a.k.a. device address) of the buffer.
+ */
+struct isp_buffer {
+	struct isp_video_buffer buffer;
+	dma_addr_t isp_addr;
+};
+
+#define to_isp_buffer(buf)	container_of(buf, struct isp_buffer, buffer)
+
+enum isp_video_dmaqueue_flags {
+	/* Set if DMA queue becomes empty when ISP_PIPELINE_STREAM_CONTINUOUS */
+	ISP_VIDEO_DMAQUEUE_UNDERRUN = (1 << 0),
+	/* Set when queuing buffer to an empty DMA queue */
+	ISP_VIDEO_DMAQUEUE_QUEUED = (1 << 1),
+};
+
+#define isp_video_dmaqueue_flags_clr(video)	\
+			({ (video)->dmaqueue_flags = 0; })
+
+/*
+ * struct isp_video_operations - ISP video operations
+ * @queue:	Resume streaming when a buffer is queued. Called on VIDIOC_QBUF
+ *		if there was no buffer previously queued.
+ */
+struct isp_video_operations {
+	int(*queue)(struct isp_video *video, struct isp_buffer *buffer);
+};
+
+struct isp_video {
+	struct video_device video;
+	enum v4l2_buf_type type;
+	struct media_pad pad;
+
+	struct mutex mutex;		/* format and crop settings */
+	atomic_t active;
+
+	struct isp_device *isp;
+
+	unsigned int capture_mem;
+	unsigned int bpl_alignment;	/* alignment value */
+	unsigned int bpl_zero_padding;	/* whether the alignment is optional */
+	unsigned int bpl_max;		/* maximum bytes per line value */
+	unsigned int bpl_value;		/* bytes per line value */
+	unsigned int bpl_padding;	/* padding at end of line */
+
+	/* Entity video node streaming */
+	unsigned int streaming:1;
+
+	/* Pipeline state */
+	struct isp_pipeline pipe;
+	struct mutex stream_lock;	/* pipeline and stream states */
+
+	/* Video buffers queue */
+	struct isp_video_queue *queue;
+	struct list_head dmaqueue;
+	enum isp_video_dmaqueue_flags dmaqueue_flags;
+
+	const struct isp_video_operations *ops;
+};
+
+#define to_isp_video(vdev)	container_of(vdev, struct isp_video, video)
+
+struct isp_video_fh {
+	struct v4l2_fh vfh;
+	struct isp_video *video;
+	struct isp_video_queue queue;
+	struct v4l2_format format;
+	struct v4l2_fract timeperframe;
+};
+
+#define to_isp_video_fh(fh)	container_of(fh, struct isp_video_fh, vfh)
+#define isp_video_queue_to_isp_video_fh(q) \
+				container_of(q, struct isp_video_fh, queue)
+
+int omap3isp_video_init(struct isp_video *video, const char *name);
+void omap3isp_video_cleanup(struct isp_video *video);
+int omap3isp_video_register(struct isp_video *video,
+			    struct v4l2_device *vdev);
+void omap3isp_video_unregister(struct isp_video *video);
+struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video);
+void omap3isp_video_resume(struct isp_video *video, int continuous);
+struct media_pad *omap3isp_video_remote_pad(struct isp_video *video);
+
+const struct isp_format_info *
+omap3isp_video_format_info(enum v4l2_mbus_pixelcode code);
+
+#endif /* OMAP3_ISP_VIDEO_H */
diff --git a/drivers/media/platform/omap3isp/luma_enhance_table.h b/drivers/media/platform/omap3isp/luma_enhance_table.h
new file mode 100644
index 0000000..098b45e
--- /dev/null
+++ b/drivers/media/platform/omap3isp/luma_enhance_table.h
@@ -0,0 +1,42 @@
+/*
+ * luma_enhance_table.h
+ *
+ * TI OMAP3 ISP - Luminance enhancement table
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552,
+1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552,
+1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552,
+1047552, 1047552, 1047552, 1047552, 1048575, 1047551, 1046527, 1045503,
+1044479, 1043455, 1042431, 1041407, 1040383, 1039359, 1038335, 1037311,
+1036287, 1035263, 1034239, 1033215, 1032191, 1031167, 1030143, 1028096,
+1028096, 1028096, 1028096, 1028096, 1028096, 1028096, 1028096, 1028096,
+1028096, 1028100, 1032196, 1036292, 1040388, 1044484,       0,       0,
+      0,       5,    5125,   10245,   15365,   20485,   25605,   30720,
+  30720,   30720,   30720,   30720,   30720,   30720,   30720,   30720,
+  30720,   30720,   31743,   30719,   29695,   28671,   27647,   26623,
+  25599,   24575,   23551,   22527,   21503,   20479,   19455,   18431,
+  17407,   16383,   15359,   14335,   13311,   12287,   11263,   10239,
+   9215,    8191,    7167,    6143,    5119,    4095,    3071,    1024,
+   1024,    1024,    1024,    1024,    1024,    1024,    1024,    1024,
+   1024,    1024,    1024,    1024,    1024,    1024,    1024,    1024
diff --git a/drivers/media/platform/omap3isp/noise_filter_table.h b/drivers/media/platform/omap3isp/noise_filter_table.h
new file mode 100644
index 0000000..d50451a
--- /dev/null
+++ b/drivers/media/platform/omap3isp/noise_filter_table.h
@@ -0,0 +1,30 @@
+/*
+ * noise_filter_table.h
+ *
+ * TI OMAP3 ISP - Noise filter table
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *	     Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31
diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c
new file mode 100644
index 0000000..9c21e01
--- /dev/null
+++ b/drivers/media/platform/pxa_camera.c
@@ -0,0 +1,1852 @@
+/*
+ * V4L2 Driver for PXA camera host
+ *
+ * Copyright (C) 2006, Sascha Hauer, Pengutronix
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+
+#include <linux/videodev2.h>
+
+#include <mach/dma.h>
+#include <mach/camera.h>
+
+#define PXA_CAM_VERSION "0.0.6"
+#define PXA_CAM_DRV_NAME "pxa27x-camera"
+
+/* Camera Interface */
+#define CICR0		0x0000
+#define CICR1		0x0004
+#define CICR2		0x0008
+#define CICR3		0x000C
+#define CICR4		0x0010
+#define CISR		0x0014
+#define CIFR		0x0018
+#define CITOR		0x001C
+#define CIBR0		0x0028
+#define CIBR1		0x0030
+#define CIBR2		0x0038
+
+#define CICR0_DMAEN	(1 << 31)	/* DMA request enable */
+#define CICR0_PAR_EN	(1 << 30)	/* Parity enable */
+#define CICR0_SL_CAP_EN	(1 << 29)	/* Capture enable for slave mode */
+#define CICR0_ENB	(1 << 28)	/* Camera interface enable */
+#define CICR0_DIS	(1 << 27)	/* Camera interface disable */
+#define CICR0_SIM	(0x7 << 24)	/* Sensor interface mode mask */
+#define CICR0_TOM	(1 << 9)	/* Time-out mask */
+#define CICR0_RDAVM	(1 << 8)	/* Receive-data-available mask */
+#define CICR0_FEM	(1 << 7)	/* FIFO-empty mask */
+#define CICR0_EOLM	(1 << 6)	/* End-of-line mask */
+#define CICR0_PERRM	(1 << 5)	/* Parity-error mask */
+#define CICR0_QDM	(1 << 4)	/* Quick-disable mask */
+#define CICR0_CDM	(1 << 3)	/* Disable-done mask */
+#define CICR0_SOFM	(1 << 2)	/* Start-of-frame mask */
+#define CICR0_EOFM	(1 << 1)	/* End-of-frame mask */
+#define CICR0_FOM	(1 << 0)	/* FIFO-overrun mask */
+
+#define CICR1_TBIT	(1 << 31)	/* Transparency bit */
+#define CICR1_RGBT_CONV	(0x3 << 29)	/* RGBT conversion mask */
+#define CICR1_PPL	(0x7ff << 15)	/* Pixels per line mask */
+#define CICR1_RGB_CONV	(0x7 << 12)	/* RGB conversion mask */
+#define CICR1_RGB_F	(1 << 11)	/* RGB format */
+#define CICR1_YCBCR_F	(1 << 10)	/* YCbCr format */
+#define CICR1_RGB_BPP	(0x7 << 7)	/* RGB bis per pixel mask */
+#define CICR1_RAW_BPP	(0x3 << 5)	/* Raw bis per pixel mask */
+#define CICR1_COLOR_SP	(0x3 << 3)	/* Color space mask */
+#define CICR1_DW	(0x7 << 0)	/* Data width mask */
+
+#define CICR2_BLW	(0xff << 24)	/* Beginning-of-line pixel clock
+					   wait count mask */
+#define CICR2_ELW	(0xff << 16)	/* End-of-line pixel clock
+					   wait count mask */
+#define CICR2_HSW	(0x3f << 10)	/* Horizontal sync pulse width mask */
+#define CICR2_BFPW	(0x3f << 3)	/* Beginning-of-frame pixel clock
+					   wait count mask */
+#define CICR2_FSW	(0x7 << 0)	/* Frame stabilization
+					   wait count mask */
+
+#define CICR3_BFW	(0xff << 24)	/* Beginning-of-frame line clock
+					   wait count mask */
+#define CICR3_EFW	(0xff << 16)	/* End-of-frame line clock
+					   wait count mask */
+#define CICR3_VSW	(0x3f << 10)	/* Vertical sync pulse width mask */
+#define CICR3_BFPW	(0x3f << 3)	/* Beginning-of-frame pixel clock
+					   wait count mask */
+#define CICR3_LPF	(0x7ff << 0)	/* Lines per frame mask */
+
+#define CICR4_MCLK_DLY	(0x3 << 24)	/* MCLK Data Capture Delay mask */
+#define CICR4_PCLK_EN	(1 << 23)	/* Pixel clock enable */
+#define CICR4_PCP	(1 << 22)	/* Pixel clock polarity */
+#define CICR4_HSP	(1 << 21)	/* Horizontal sync polarity */
+#define CICR4_VSP	(1 << 20)	/* Vertical sync polarity */
+#define CICR4_MCLK_EN	(1 << 19)	/* MCLK enable */
+#define CICR4_FR_RATE	(0x7 << 8)	/* Frame rate mask */
+#define CICR4_DIV	(0xff << 0)	/* Clock divisor mask */
+
+#define CISR_FTO	(1 << 15)	/* FIFO time-out */
+#define CISR_RDAV_2	(1 << 14)	/* Channel 2 receive data available */
+#define CISR_RDAV_1	(1 << 13)	/* Channel 1 receive data available */
+#define CISR_RDAV_0	(1 << 12)	/* Channel 0 receive data available */
+#define CISR_FEMPTY_2	(1 << 11)	/* Channel 2 FIFO empty */
+#define CISR_FEMPTY_1	(1 << 10)	/* Channel 1 FIFO empty */
+#define CISR_FEMPTY_0	(1 << 9)	/* Channel 0 FIFO empty */
+#define CISR_EOL	(1 << 8)	/* End of line */
+#define CISR_PAR_ERR	(1 << 7)	/* Parity error */
+#define CISR_CQD	(1 << 6)	/* Camera interface quick disable */
+#define CISR_CDD	(1 << 5)	/* Camera interface disable done */
+#define CISR_SOF	(1 << 4)	/* Start of frame */
+#define CISR_EOF	(1 << 3)	/* End of frame */
+#define CISR_IFO_2	(1 << 2)	/* FIFO overrun for Channel 2 */
+#define CISR_IFO_1	(1 << 1)	/* FIFO overrun for Channel 1 */
+#define CISR_IFO_0	(1 << 0)	/* FIFO overrun for Channel 0 */
+
+#define CIFR_FLVL2	(0x7f << 23)	/* FIFO 2 level mask */
+#define CIFR_FLVL1	(0x7f << 16)	/* FIFO 1 level mask */
+#define CIFR_FLVL0	(0xff << 8)	/* FIFO 0 level mask */
+#define CIFR_THL_0	(0x3 << 4)	/* Threshold Level for Channel 0 FIFO */
+#define CIFR_RESET_F	(1 << 3)	/* Reset input FIFOs */
+#define CIFR_FEN2	(1 << 2)	/* FIFO enable for channel 2 */
+#define CIFR_FEN1	(1 << 1)	/* FIFO enable for channel 1 */
+#define CIFR_FEN0	(1 << 0)	/* FIFO enable for channel 0 */
+
+#define CICR0_SIM_MP	(0 << 24)
+#define CICR0_SIM_SP	(1 << 24)
+#define CICR0_SIM_MS	(2 << 24)
+#define CICR0_SIM_EP	(3 << 24)
+#define CICR0_SIM_ES	(4 << 24)
+
+#define CICR1_DW_VAL(x)   ((x) & CICR1_DW)	    /* Data bus width */
+#define CICR1_PPL_VAL(x)  (((x) << 15) & CICR1_PPL) /* Pixels per line */
+#define CICR1_COLOR_SP_VAL(x)	(((x) << 3) & CICR1_COLOR_SP)	/* color space */
+#define CICR1_RGB_BPP_VAL(x)	(((x) << 7) & CICR1_RGB_BPP)	/* bpp for rgb */
+#define CICR1_RGBT_CONV_VAL(x)	(((x) << 29) & CICR1_RGBT_CONV)	/* rgbt conv */
+
+#define CICR2_BLW_VAL(x)  (((x) << 24) & CICR2_BLW) /* Beginning-of-line pixel clock wait count */
+#define CICR2_ELW_VAL(x)  (((x) << 16) & CICR2_ELW) /* End-of-line pixel clock wait count */
+#define CICR2_HSW_VAL(x)  (((x) << 10) & CICR2_HSW) /* Horizontal sync pulse width */
+#define CICR2_BFPW_VAL(x) (((x) << 3) & CICR2_BFPW) /* Beginning-of-frame pixel clock wait count */
+#define CICR2_FSW_VAL(x)  (((x) << 0) & CICR2_FSW)  /* Frame stabilization wait count */
+
+#define CICR3_BFW_VAL(x)  (((x) << 24) & CICR3_BFW) /* Beginning-of-frame line clock wait count  */
+#define CICR3_EFW_VAL(x)  (((x) << 16) & CICR3_EFW) /* End-of-frame line clock wait count */
+#define CICR3_VSW_VAL(x)  (((x) << 11) & CICR3_VSW) /* Vertical sync pulse width */
+#define CICR3_LPF_VAL(x)  (((x) << 0) & CICR3_LPF)  /* Lines per frame */
+
+#define CICR0_IRQ_MASK (CICR0_TOM | CICR0_RDAVM | CICR0_FEM | CICR0_EOLM | \
+			CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \
+			CICR0_EOFM | CICR0_FOM)
+
+/*
+ * Structures
+ */
+enum pxa_camera_active_dma {
+	DMA_Y = 0x1,
+	DMA_U = 0x2,
+	DMA_V = 0x4,
+};
+
+/* descriptor needed for the PXA DMA engine */
+struct pxa_cam_dma {
+	dma_addr_t		sg_dma;
+	struct pxa_dma_desc	*sg_cpu;
+	size_t			sg_size;
+	int			sglen;
+};
+
+/* buffer for one video frame */
+struct pxa_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer		vb;
+	enum v4l2_mbus_pixelcode	code;
+	/* our descriptor lists for Y, U and V channels */
+	struct pxa_cam_dma		dmas[3];
+	int				inwork;
+	enum pxa_camera_active_dma	active_dma;
+};
+
+struct pxa_camera_dev {
+	struct soc_camera_host	soc_host;
+	/*
+	 * PXA27x is only supposed to handle one camera on its Quick Capture
+	 * interface. If anyone ever builds hardware to enable more than
+	 * one camera, they will have to modify this driver too
+	 */
+	struct soc_camera_device *icd;
+	struct clk		*clk;
+
+	unsigned int		irq;
+	void __iomem		*base;
+
+	int			channels;
+	unsigned int		dma_chans[3];
+
+	struct pxacamera_platform_data *pdata;
+	struct resource		*res;
+	unsigned long		platform_flags;
+	unsigned long		ciclk;
+	unsigned long		mclk;
+	u32			mclk_divisor;
+	u16			width_flags;	/* max 10 bits */
+
+	struct list_head	capture;
+
+	spinlock_t		lock;
+
+	struct pxa_buffer	*active;
+	struct pxa_dma_desc	*sg_tail[3];
+
+	u32			save_cicr[5];
+};
+
+struct pxa_cam {
+	unsigned long flags;
+};
+
+static const char *pxa_cam_driver_description = "PXA_Camera";
+
+static unsigned int vid_limit = 16;	/* Video memory limit, in Mb */
+
+/*
+ *  Videobuf operations
+ */
+static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
+			      unsigned int *size)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+
+	dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size);
+
+	*size = icd->sizeimage;
+
+	if (0 == *count)
+		*count = 32;
+	if (*size * *count > vid_limit * 1024 * 1024)
+		*count = (vid_limit * 1024 * 1024) / *size;
+
+	return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+	int i;
+
+	BUG_ON(in_interrupt());
+
+	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+		&buf->vb, buf->vb.baddr, buf->vb.bsize);
+
+	/*
+	 * This waits until this buffer is out of danger, i.e., until it is no
+	 * longer in STATE_QUEUED or STATE_ACTIVE
+	 */
+	videobuf_waiton(vq, &buf->vb, 0, 0);
+	videobuf_dma_unmap(vq->dev, dma);
+	videobuf_dma_free(dma);
+
+	for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) {
+		if (buf->dmas[i].sg_cpu)
+			dma_free_coherent(ici->v4l2_dev.dev,
+					  buf->dmas[i].sg_size,
+					  buf->dmas[i].sg_cpu,
+					  buf->dmas[i].sg_dma);
+		buf->dmas[i].sg_cpu = NULL;
+	}
+
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int calculate_dma_sglen(struct scatterlist *sglist, int sglen,
+			       int sg_first_ofs, int size)
+{
+	int i, offset, dma_len, xfer_len;
+	struct scatterlist *sg;
+
+	offset = sg_first_ofs;
+	for_each_sg(sglist, sg, sglen, i) {
+		dma_len = sg_dma_len(sg);
+
+		/* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */
+		xfer_len = roundup(min(dma_len - offset, size), 8);
+
+		size = max(0, size - xfer_len);
+		offset = 0;
+		if (size == 0)
+			break;
+	}
+
+	BUG_ON(size != 0);
+	return i + 1;
+}
+
+/**
+ * pxa_init_dma_channel - init dma descriptors
+ * @pcdev: pxa camera device
+ * @buf: pxa buffer to find pxa dma channel
+ * @dma: dma video buffer
+ * @channel: dma channel (0 => 'Y', 1 => 'U', 2 => 'V')
+ * @cibr: camera Receive Buffer Register
+ * @size: bytes to transfer
+ * @sg_first: first element of sg_list
+ * @sg_first_ofs: offset in first element of sg_list
+ *
+ * Prepares the pxa dma descriptors to transfer one camera channel.
+ * Beware sg_first and sg_first_ofs are both input and output parameters.
+ *
+ * Returns 0 or -ENOMEM if no coherent memory is available
+ */
+static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
+				struct pxa_buffer *buf,
+				struct videobuf_dmabuf *dma, int channel,
+				int cibr, int size,
+				struct scatterlist **sg_first, int *sg_first_ofs)
+{
+	struct pxa_cam_dma *pxa_dma = &buf->dmas[channel];
+	struct device *dev = pcdev->soc_host.v4l2_dev.dev;
+	struct scatterlist *sg;
+	int i, offset, sglen;
+	int dma_len = 0, xfer_len = 0;
+
+	if (pxa_dma->sg_cpu)
+		dma_free_coherent(dev, pxa_dma->sg_size,
+				  pxa_dma->sg_cpu, pxa_dma->sg_dma);
+
+	sglen = calculate_dma_sglen(*sg_first, dma->sglen,
+				    *sg_first_ofs, size);
+
+	pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc);
+	pxa_dma->sg_cpu = dma_alloc_coherent(dev, pxa_dma->sg_size,
+					     &pxa_dma->sg_dma, GFP_KERNEL);
+	if (!pxa_dma->sg_cpu)
+		return -ENOMEM;
+
+	pxa_dma->sglen = sglen;
+	offset = *sg_first_ofs;
+
+	dev_dbg(dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n",
+		*sg_first, sglen, *sg_first_ofs, pxa_dma->sg_dma);
+
+
+	for_each_sg(*sg_first, sg, sglen, i) {
+		dma_len = sg_dma_len(sg);
+
+		/* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */
+		xfer_len = roundup(min(dma_len - offset, size), 8);
+
+		size = max(0, size - xfer_len);
+
+		pxa_dma->sg_cpu[i].dsadr = pcdev->res->start + cibr;
+		pxa_dma->sg_cpu[i].dtadr = sg_dma_address(sg) + offset;
+		pxa_dma->sg_cpu[i].dcmd =
+			DCMD_FLOWSRC | DCMD_BURST8 | DCMD_INCTRGADDR | xfer_len;
+#ifdef DEBUG
+		if (!i)
+			pxa_dma->sg_cpu[i].dcmd |= DCMD_STARTIRQEN;
+#endif
+		pxa_dma->sg_cpu[i].ddadr =
+			pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc);
+
+		dev_vdbg(dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n",
+			 pxa_dma->sg_dma + i * sizeof(struct pxa_dma_desc),
+			 sg_dma_address(sg) + offset, xfer_len);
+		offset = 0;
+
+		if (size == 0)
+			break;
+	}
+
+	pxa_dma->sg_cpu[sglen].ddadr = DDADR_STOP;
+	pxa_dma->sg_cpu[sglen].dcmd  = DCMD_FLOWSRC | DCMD_BURST8 | DCMD_ENDIRQEN;
+
+	/*
+	 * Handle 1 special case :
+	 *  - in 3 planes (YUV422P format), we might finish with xfer_len equal
+	 *    to dma_len (end on PAGE boundary). In this case, the sg element
+	 *    for next plane should be the next after the last used to store the
+	 *    last scatter gather RAM page
+	 */
+	if (xfer_len >= dma_len) {
+		*sg_first_ofs = xfer_len - dma_len;
+		*sg_first = sg_next(sg);
+	} else {
+		*sg_first_ofs = xfer_len;
+		*sg_first = sg;
+	}
+
+	return 0;
+}
+
+static void pxa_videobuf_set_actdma(struct pxa_camera_dev *pcdev,
+				    struct pxa_buffer *buf)
+{
+	buf->active_dma = DMA_Y;
+	if (pcdev->channels == 3)
+		buf->active_dma |= DMA_U | DMA_V;
+}
+
+/*
+ * Please check the DMA prepared buffer structure in :
+ *   Documentation/video4linux/pxa_camera.txt
+ * Please check also in pxa_camera_check_link_miss() to understand why DMA chain
+ * modification while DMA chain is running will work anyway.
+ */
+static int pxa_videobuf_prepare(struct videobuf_queue *vq,
+		struct videobuf_buffer *vb, enum v4l2_field field)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	struct device *dev = pcdev->soc_host.v4l2_dev.dev;
+	struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
+	int ret;
+	int size_y, size_u = 0, size_v = 0;
+
+	dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+		vb, vb->baddr, vb->bsize);
+
+	/* Added list head initialization on alloc */
+	WARN_ON(!list_empty(&vb->queue));
+
+#ifdef DEBUG
+	/*
+	 * This can be useful if you want to see if we actually fill
+	 * the buffer with something
+	 */
+	memset((void *)vb->baddr, 0xaa, vb->bsize);
+#endif
+
+	BUG_ON(NULL == icd->current_fmt);
+
+	/*
+	 * I think, in buf_prepare you only have to protect global data,
+	 * the actual buffer is yours
+	 */
+	buf->inwork = 1;
+
+	if (buf->code	!= icd->current_fmt->code ||
+	    vb->width	!= icd->user_width ||
+	    vb->height	!= icd->user_height ||
+	    vb->field	!= field) {
+		buf->code	= icd->current_fmt->code;
+		vb->width	= icd->user_width;
+		vb->height	= icd->user_height;
+		vb->field	= field;
+		vb->state	= VIDEOBUF_NEEDS_INIT;
+	}
+
+	vb->size = icd->sizeimage;
+	if (0 != vb->baddr && vb->bsize < vb->size) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (vb->state == VIDEOBUF_NEEDS_INIT) {
+		int size = vb->size;
+		int next_ofs = 0;
+		struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+		struct scatterlist *sg;
+
+		ret = videobuf_iolock(vq, vb, NULL);
+		if (ret)
+			goto fail;
+
+		if (pcdev->channels == 3) {
+			size_y = size / 2;
+			size_u = size_v = size / 4;
+		} else {
+			size_y = size;
+		}
+
+		sg = dma->sglist;
+
+		/* init DMA for Y channel */
+		ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, size_y,
+					   &sg, &next_ofs);
+		if (ret) {
+			dev_err(dev, "DMA initialization for Y/RGB failed\n");
+			goto fail;
+		}
+
+		/* init DMA for U channel */
+		if (size_u)
+			ret = pxa_init_dma_channel(pcdev, buf, dma, 1, CIBR1,
+						   size_u, &sg, &next_ofs);
+		if (ret) {
+			dev_err(dev, "DMA initialization for U failed\n");
+			goto fail_u;
+		}
+
+		/* init DMA for V channel */
+		if (size_v)
+			ret = pxa_init_dma_channel(pcdev, buf, dma, 2, CIBR2,
+						   size_v, &sg, &next_ofs);
+		if (ret) {
+			dev_err(dev, "DMA initialization for V failed\n");
+			goto fail_v;
+		}
+
+		vb->state = VIDEOBUF_PREPARED;
+	}
+
+	buf->inwork = 0;
+	pxa_videobuf_set_actdma(pcdev, buf);
+
+	return 0;
+
+fail_v:
+	dma_free_coherent(dev, buf->dmas[1].sg_size,
+			  buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma);
+fail_u:
+	dma_free_coherent(dev, buf->dmas[0].sg_size,
+			  buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma);
+fail:
+	free_buffer(vq, buf);
+out:
+	buf->inwork = 0;
+	return ret;
+}
+
+/**
+ * pxa_dma_start_channels - start DMA channel for active buffer
+ * @pcdev: pxa camera device
+ *
+ * Initialize DMA channels to the beginning of the active video buffer, and
+ * start these channels.
+ */
+static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev)
+{
+	int i;
+	struct pxa_buffer *active;
+
+	active = pcdev->active;
+
+	for (i = 0; i < pcdev->channels; i++) {
+		dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+			"%s (channel=%d) ddadr=%08x\n", __func__,
+			i, active->dmas[i].sg_dma);
+		DDADR(pcdev->dma_chans[i]) = active->dmas[i].sg_dma;
+		DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
+	}
+}
+
+static void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev)
+{
+	int i;
+
+	for (i = 0; i < pcdev->channels; i++) {
+		dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+			"%s (channel=%d)\n", __func__, i);
+		DCSR(pcdev->dma_chans[i]) = 0;
+	}
+}
+
+static void pxa_dma_add_tail_buf(struct pxa_camera_dev *pcdev,
+				 struct pxa_buffer *buf)
+{
+	int i;
+	struct pxa_dma_desc *buf_last_desc;
+
+	for (i = 0; i < pcdev->channels; i++) {
+		buf_last_desc = buf->dmas[i].sg_cpu + buf->dmas[i].sglen;
+		buf_last_desc->ddadr = DDADR_STOP;
+
+		if (pcdev->sg_tail[i])
+			/* Link the new buffer to the old tail */
+			pcdev->sg_tail[i]->ddadr = buf->dmas[i].sg_dma;
+
+		/* Update the channel tail */
+		pcdev->sg_tail[i] = buf_last_desc;
+	}
+}
+
+/**
+ * pxa_camera_start_capture - start video capturing
+ * @pcdev: camera device
+ *
+ * Launch capturing. DMA channels should not be active yet. They should get
+ * activated at the end of frame interrupt, to capture only whole frames, and
+ * never begin the capture of a partial frame.
+ */
+static void pxa_camera_start_capture(struct pxa_camera_dev *pcdev)
+{
+	unsigned long cicr0;
+
+	dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__);
+	/* Enable End-Of-Frame Interrupt */
+	cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_ENB;
+	cicr0 &= ~CICR0_EOFM;
+	__raw_writel(cicr0, pcdev->base + CICR0);
+}
+
+static void pxa_camera_stop_capture(struct pxa_camera_dev *pcdev)
+{
+	unsigned long cicr0;
+
+	pxa_dma_stop_channels(pcdev);
+
+	cicr0 = __raw_readl(pcdev->base + CICR0) & ~CICR0_ENB;
+	__raw_writel(cicr0, pcdev->base + CICR0);
+
+	pcdev->active = NULL;
+	dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__);
+}
+
+/* Called under spinlock_irqsave(&pcdev->lock, ...) */
+static void pxa_videobuf_queue(struct videobuf_queue *vq,
+			       struct videobuf_buffer *vb)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
+
+	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d active=%p\n",
+		__func__, vb, vb->baddr, vb->bsize, pcdev->active);
+
+	list_add_tail(&vb->queue, &pcdev->capture);
+
+	vb->state = VIDEOBUF_ACTIVE;
+	pxa_dma_add_tail_buf(pcdev, buf);
+
+	if (!pcdev->active)
+		pxa_camera_start_capture(pcdev);
+}
+
+static void pxa_videobuf_release(struct videobuf_queue *vq,
+				 struct videobuf_buffer *vb)
+{
+	struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
+#ifdef DEBUG
+	struct soc_camera_device *icd = vq->priv_data;
+	struct device *dev = icd->parent;
+
+	dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+		vb, vb->baddr, vb->bsize);
+
+	switch (vb->state) {
+	case VIDEOBUF_ACTIVE:
+		dev_dbg(dev, "%s (active)\n", __func__);
+		break;
+	case VIDEOBUF_QUEUED:
+		dev_dbg(dev, "%s (queued)\n", __func__);
+		break;
+	case VIDEOBUF_PREPARED:
+		dev_dbg(dev, "%s (prepared)\n", __func__);
+		break;
+	default:
+		dev_dbg(dev, "%s (unknown)\n", __func__);
+		break;
+	}
+#endif
+
+	free_buffer(vq, buf);
+}
+
+static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
+			      struct videobuf_buffer *vb,
+			      struct pxa_buffer *buf)
+{
+	int i;
+
+	/* _init is used to debug races, see comment in pxa_camera_reqbufs() */
+	list_del_init(&vb->queue);
+	vb->state = VIDEOBUF_DONE;
+	do_gettimeofday(&vb->ts);
+	vb->field_count++;
+	wake_up(&vb->done);
+	dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s dequeud buffer (vb=0x%p)\n",
+		__func__, vb);
+
+	if (list_empty(&pcdev->capture)) {
+		pxa_camera_stop_capture(pcdev);
+		for (i = 0; i < pcdev->channels; i++)
+			pcdev->sg_tail[i] = NULL;
+		return;
+	}
+
+	pcdev->active = list_entry(pcdev->capture.next,
+				   struct pxa_buffer, vb.queue);
+}
+
+/**
+ * pxa_camera_check_link_miss - check missed DMA linking
+ * @pcdev: camera device
+ *
+ * The DMA chaining is done with DMA running. This means a tiny temporal window
+ * remains, where a buffer is queued on the chain, while the chain is already
+ * stopped. This means the tailed buffer would never be transferred by DMA.
+ * This function restarts the capture for this corner case, where :
+ *  - DADR() == DADDR_STOP
+ *  - a videobuffer is queued on the pcdev->capture list
+ *
+ * Please check the "DMA hot chaining timeslice issue" in
+ *   Documentation/video4linux/pxa_camera.txt
+ *
+ * Context: should only be called within the dma irq handler
+ */
+static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev)
+{
+	int i, is_dma_stopped = 1;
+
+	for (i = 0; i < pcdev->channels; i++)
+		if (DDADR(pcdev->dma_chans[i]) != DDADR_STOP)
+			is_dma_stopped = 0;
+	dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+		"%s : top queued buffer=%p, dma_stopped=%d\n",
+		__func__, pcdev->active, is_dma_stopped);
+	if (pcdev->active && is_dma_stopped)
+		pxa_camera_start_capture(pcdev);
+}
+
+static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
+			       enum pxa_camera_active_dma act_dma)
+{
+	struct device *dev = pcdev->soc_host.v4l2_dev.dev;
+	struct pxa_buffer *buf;
+	unsigned long flags;
+	u32 status, camera_status, overrun;
+	struct videobuf_buffer *vb;
+
+	spin_lock_irqsave(&pcdev->lock, flags);
+
+	status = DCSR(channel);
+	DCSR(channel) = status;
+
+	camera_status = __raw_readl(pcdev->base + CISR);
+	overrun = CISR_IFO_0;
+	if (pcdev->channels == 3)
+		overrun |= CISR_IFO_1 | CISR_IFO_2;
+
+	if (status & DCSR_BUSERR) {
+		dev_err(dev, "DMA Bus Error IRQ!\n");
+		goto out;
+	}
+
+	if (!(status & (DCSR_ENDINTR | DCSR_STARTINTR))) {
+		dev_err(dev, "Unknown DMA IRQ source, status: 0x%08x\n",
+			status);
+		goto out;
+	}
+
+	/*
+	 * pcdev->active should not be NULL in DMA irq handler.
+	 *
+	 * But there is one corner case : if capture was stopped due to an
+	 * overrun of channel 1, and at that same channel 2 was completed.
+	 *
+	 * When handling the overrun in DMA irq for channel 1, we'll stop the
+	 * capture and restart it (and thus set pcdev->active to NULL). But the
+	 * DMA irq handler will already be pending for channel 2. So on entering
+	 * the DMA irq handler for channel 2 there will be no active buffer, yet
+	 * that is normal.
+	 */
+	if (!pcdev->active)
+		goto out;
+
+	vb = &pcdev->active->vb;
+	buf = container_of(vb, struct pxa_buffer, vb);
+	WARN_ON(buf->inwork || list_empty(&vb->queue));
+
+	dev_dbg(dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n",
+		__func__, channel, status & DCSR_STARTINTR ? "SOF " : "",
+		status & DCSR_ENDINTR ? "EOF " : "", vb, DDADR(channel));
+
+	if (status & DCSR_ENDINTR) {
+		/*
+		 * It's normal if the last frame creates an overrun, as there
+		 * are no more DMA descriptors to fetch from QCI fifos
+		 */
+		if (camera_status & overrun &&
+		    !list_is_last(pcdev->capture.next, &pcdev->capture)) {
+			dev_dbg(dev, "FIFO overrun! CISR: %x\n",
+				camera_status);
+			pxa_camera_stop_capture(pcdev);
+			pxa_camera_start_capture(pcdev);
+			goto out;
+		}
+		buf->active_dma &= ~act_dma;
+		if (!buf->active_dma) {
+			pxa_camera_wakeup(pcdev, vb, buf);
+			pxa_camera_check_link_miss(pcdev);
+		}
+	}
+
+out:
+	spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static void pxa_camera_dma_irq_y(int channel, void *data)
+{
+	struct pxa_camera_dev *pcdev = data;
+	pxa_camera_dma_irq(channel, pcdev, DMA_Y);
+}
+
+static void pxa_camera_dma_irq_u(int channel, void *data)
+{
+	struct pxa_camera_dev *pcdev = data;
+	pxa_camera_dma_irq(channel, pcdev, DMA_U);
+}
+
+static void pxa_camera_dma_irq_v(int channel, void *data)
+{
+	struct pxa_camera_dev *pcdev = data;
+	pxa_camera_dma_irq(channel, pcdev, DMA_V);
+}
+
+static struct videobuf_queue_ops pxa_videobuf_ops = {
+	.buf_setup      = pxa_videobuf_setup,
+	.buf_prepare    = pxa_videobuf_prepare,
+	.buf_queue      = pxa_videobuf_queue,
+	.buf_release    = pxa_videobuf_release,
+};
+
+static void pxa_camera_init_videobuf(struct videobuf_queue *q,
+			      struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+
+	/*
+	 * We must pass NULL as dev pointer, then all pci_* dma operations
+	 * transform to normal dma_* ones.
+	 */
+	videobuf_queue_sg_init(q, &pxa_videobuf_ops, NULL, &pcdev->lock,
+				V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+				sizeof(struct pxa_buffer), icd, &icd->video_lock);
+}
+
+static u32 mclk_get_divisor(struct platform_device *pdev,
+			    struct pxa_camera_dev *pcdev)
+{
+	unsigned long mclk = pcdev->mclk;
+	struct device *dev = &pdev->dev;
+	u32 div;
+	unsigned long lcdclk;
+
+	lcdclk = clk_get_rate(pcdev->clk);
+	pcdev->ciclk = lcdclk;
+
+	/* mclk <= ciclk / 4 (27.4.2) */
+	if (mclk > lcdclk / 4) {
+		mclk = lcdclk / 4;
+		dev_warn(dev, "Limiting master clock to %lu\n", mclk);
+	}
+
+	/* We verify mclk != 0, so if anyone breaks it, here comes their Oops */
+	div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1;
+
+	/* If we're not supplying MCLK, leave it at 0 */
+	if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
+		pcdev->mclk = lcdclk / (2 * (div + 1));
+
+	dev_dbg(dev, "LCD clock %luHz, target freq %luHz, divisor %u\n",
+		lcdclk, mclk, div);
+
+	return div;
+}
+
+static void recalculate_fifo_timeout(struct pxa_camera_dev *pcdev,
+				     unsigned long pclk)
+{
+	/* We want a timeout > 1 pixel time, not ">=" */
+	u32 ciclk_per_pixel = pcdev->ciclk / pclk + 1;
+
+	__raw_writel(ciclk_per_pixel, pcdev->base + CITOR);
+}
+
+static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
+{
+	u32 cicr4 = 0;
+
+	/* disable all interrupts */
+	__raw_writel(0x3ff, pcdev->base + CICR0);
+
+	if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
+		cicr4 |= CICR4_PCLK_EN;
+	if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
+		cicr4 |= CICR4_MCLK_EN;
+	if (pcdev->platform_flags & PXA_CAMERA_PCP)
+		cicr4 |= CICR4_PCP;
+	if (pcdev->platform_flags & PXA_CAMERA_HSP)
+		cicr4 |= CICR4_HSP;
+	if (pcdev->platform_flags & PXA_CAMERA_VSP)
+		cicr4 |= CICR4_VSP;
+
+	__raw_writel(pcdev->mclk_divisor | cicr4, pcdev->base + CICR4);
+
+	if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
+		/* Initialise the timeout under the assumption pclk = mclk */
+		recalculate_fifo_timeout(pcdev, pcdev->mclk);
+	else
+		/* "Safe default" - 13MHz */
+		recalculate_fifo_timeout(pcdev, 13000000);
+
+	clk_prepare_enable(pcdev->clk);
+}
+
+static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev)
+{
+	clk_disable_unprepare(pcdev->clk);
+}
+
+static irqreturn_t pxa_camera_irq(int irq, void *data)
+{
+	struct pxa_camera_dev *pcdev = data;
+	unsigned long status, cifr, cicr0;
+	struct pxa_buffer *buf;
+	struct videobuf_buffer *vb;
+
+	status = __raw_readl(pcdev->base + CISR);
+	dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+		"Camera interrupt status 0x%lx\n", status);
+
+	if (!status)
+		return IRQ_NONE;
+
+	__raw_writel(status, pcdev->base + CISR);
+
+	if (status & CISR_EOF) {
+		/* Reset the FIFOs */
+		cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
+		__raw_writel(cifr, pcdev->base + CIFR);
+
+		pcdev->active = list_first_entry(&pcdev->capture,
+					   struct pxa_buffer, vb.queue);
+		vb = &pcdev->active->vb;
+		buf = container_of(vb, struct pxa_buffer, vb);
+		pxa_videobuf_set_actdma(pcdev, buf);
+
+		pxa_dma_start_channels(pcdev);
+
+		cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_EOFM;
+		__raw_writel(cicr0, pcdev->base + CICR0);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * The following two functions absolutely depend on the fact, that
+ * there can be only one camera on PXA quick capture interface
+ * Called with .video_lock held
+ */
+static int pxa_camera_add_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+
+	if (pcdev->icd)
+		return -EBUSY;
+
+	pxa_camera_activate(pcdev);
+
+	pcdev->icd = icd;
+
+	dev_info(icd->parent, "PXA Camera driver attached to camera %d\n",
+		 icd->devnum);
+
+	return 0;
+}
+
+/* Called with .video_lock held */
+static void pxa_camera_remove_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+
+	BUG_ON(icd != pcdev->icd);
+
+	dev_info(icd->parent, "PXA Camera driver detached from camera %d\n",
+		 icd->devnum);
+
+	/* disable capture, disable interrupts */
+	__raw_writel(0x3ff, pcdev->base + CICR0);
+
+	/* Stop DMA engine */
+	DCSR(pcdev->dma_chans[0]) = 0;
+	DCSR(pcdev->dma_chans[1]) = 0;
+	DCSR(pcdev->dma_chans[2]) = 0;
+
+	pxa_camera_deactivate(pcdev);
+
+	pcdev->icd = NULL;
+}
+
+static int test_platform_param(struct pxa_camera_dev *pcdev,
+			       unsigned char buswidth, unsigned long *flags)
+{
+	/*
+	 * Platform specified synchronization and pixel clock polarities are
+	 * only a recommendation and are only used during probing. The PXA270
+	 * quick capture interface supports both.
+	 */
+	*flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ?
+		  V4L2_MBUS_MASTER : V4L2_MBUS_SLAVE) |
+		V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+		V4L2_MBUS_HSYNC_ACTIVE_LOW |
+		V4L2_MBUS_VSYNC_ACTIVE_HIGH |
+		V4L2_MBUS_VSYNC_ACTIVE_LOW |
+		V4L2_MBUS_DATA_ACTIVE_HIGH |
+		V4L2_MBUS_PCLK_SAMPLE_RISING |
+		V4L2_MBUS_PCLK_SAMPLE_FALLING;
+
+	/* If requested data width is supported by the platform, use it */
+	if ((1 << (buswidth - 1)) & pcdev->width_flags)
+		return 0;
+
+	return -EINVAL;
+}
+
+static void pxa_camera_setup_cicr(struct soc_camera_device *icd,
+				  unsigned long flags, __u32 pixfmt)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	unsigned long dw, bpp;
+	u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0, y_skip_top;
+	int ret = v4l2_subdev_call(sd, sensor, g_skip_top_lines, &y_skip_top);
+
+	if (ret < 0)
+		y_skip_top = 0;
+
+	/*
+	 * Datawidth is now guaranteed to be equal to one of the three values.
+	 * We fix bit-per-pixel equal to data-width...
+	 */
+	switch (icd->current_fmt->host_fmt->bits_per_sample) {
+	case 10:
+		dw = 4;
+		bpp = 0x40;
+		break;
+	case 9:
+		dw = 3;
+		bpp = 0x20;
+		break;
+	default:
+		/*
+		 * Actually it can only be 8 now,
+		 * default is just to silence compiler warnings
+		 */
+	case 8:
+		dw = 2;
+		bpp = 0;
+	}
+
+	if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
+		cicr4 |= CICR4_PCLK_EN;
+	if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
+		cicr4 |= CICR4_MCLK_EN;
+	if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+		cicr4 |= CICR4_PCP;
+	if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+		cicr4 |= CICR4_HSP;
+	if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+		cicr4 |= CICR4_VSP;
+
+	cicr0 = __raw_readl(pcdev->base + CICR0);
+	if (cicr0 & CICR0_ENB)
+		__raw_writel(cicr0 & ~CICR0_ENB, pcdev->base + CICR0);
+
+	cicr1 = CICR1_PPL_VAL(icd->user_width - 1) | bpp | dw;
+
+	switch (pixfmt) {
+	case V4L2_PIX_FMT_YUV422P:
+		pcdev->channels = 3;
+		cicr1 |= CICR1_YCBCR_F;
+		/*
+		 * Normally, pxa bus wants as input UYVY format. We allow all
+		 * reorderings of the YUV422 format, as no processing is done,
+		 * and the YUV stream is just passed through without any
+		 * transformation. Note that UYVY is the only format that
+		 * should be used if pxa framebuffer Overlay2 is used.
+		 */
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_VYUY:
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_YVYU:
+		cicr1 |= CICR1_COLOR_SP_VAL(2);
+		break;
+	case V4L2_PIX_FMT_RGB555:
+		cicr1 |= CICR1_RGB_BPP_VAL(1) | CICR1_RGBT_CONV_VAL(2) |
+			CICR1_TBIT | CICR1_COLOR_SP_VAL(1);
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		cicr1 |= CICR1_COLOR_SP_VAL(1) | CICR1_RGB_BPP_VAL(2);
+		break;
+	}
+
+	cicr2 = 0;
+	cicr3 = CICR3_LPF_VAL(icd->user_height - 1) |
+		CICR3_BFW_VAL(min((u32)255, y_skip_top));
+	cicr4 |= pcdev->mclk_divisor;
+
+	__raw_writel(cicr1, pcdev->base + CICR1);
+	__raw_writel(cicr2, pcdev->base + CICR2);
+	__raw_writel(cicr3, pcdev->base + CICR3);
+	__raw_writel(cicr4, pcdev->base + CICR4);
+
+	/* CIF interrupts are not used, only DMA */
+	cicr0 = (cicr0 & CICR0_ENB) | (pcdev->platform_flags & PXA_CAMERA_MASTER ?
+		CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP));
+	cicr0 |= CICR0_DMAEN | CICR0_IRQ_MASK;
+	__raw_writel(cicr0, pcdev->base + CICR0);
+}
+
+static int pxa_camera_set_bus_param(struct soc_camera_device *icd)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+	u32 pixfmt = icd->current_fmt->host_fmt->fourcc;
+	unsigned long bus_flags, common_flags;
+	int ret;
+	struct pxa_cam *cam = icd->host_priv;
+
+	ret = test_platform_param(pcdev, icd->current_fmt->host_fmt->bits_per_sample,
+				  &bus_flags);
+	if (ret < 0)
+		return ret;
+
+	ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
+	if (!ret) {
+		common_flags = soc_mbus_config_compatible(&cfg,
+							  bus_flags);
+		if (!common_flags) {
+			dev_warn(icd->parent,
+				 "Flags incompatible: camera 0x%x, host 0x%lx\n",
+				 cfg.flags, bus_flags);
+			return -EINVAL;
+		}
+	} else if (ret != -ENOIOCTLCMD) {
+		return ret;
+	} else {
+		common_flags = bus_flags;
+	}
+
+	pcdev->channels = 1;
+
+	/* Make choises, based on platform preferences */
+	if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
+	    (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
+		if (pcdev->platform_flags & PXA_CAMERA_HSP)
+			common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
+		else
+			common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
+	}
+
+	if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
+	    (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
+		if (pcdev->platform_flags & PXA_CAMERA_VSP)
+			common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
+		else
+			common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
+	}
+
+	if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
+	    (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
+		if (pcdev->platform_flags & PXA_CAMERA_PCP)
+			common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
+		else
+			common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
+	}
+
+	cfg.flags = common_flags;
+	ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
+	if (ret < 0 && ret != -ENOIOCTLCMD) {
+		dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n",
+			common_flags, ret);
+		return ret;
+	}
+
+	cam->flags = common_flags;
+
+	pxa_camera_setup_cicr(icd, common_flags, pixfmt);
+
+	return 0;
+}
+
+static int pxa_camera_try_bus_param(struct soc_camera_device *icd,
+				    unsigned char buswidth)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+	unsigned long bus_flags, common_flags;
+	int ret = test_platform_param(pcdev, buswidth, &bus_flags);
+
+	if (ret < 0)
+		return ret;
+
+	ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
+	if (!ret) {
+		common_flags = soc_mbus_config_compatible(&cfg,
+							  bus_flags);
+		if (!common_flags) {
+			dev_warn(icd->parent,
+				 "Flags incompatible: camera 0x%x, host 0x%lx\n",
+				 cfg.flags, bus_flags);
+			return -EINVAL;
+		}
+	} else if (ret == -ENOIOCTLCMD) {
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static const struct soc_mbus_pixelfmt pxa_camera_formats[] = {
+	{
+		.fourcc			= V4L2_PIX_FMT_YUV422P,
+		.name			= "Planar YUV422 16 bit",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PLANAR_2Y_U_V,
+	},
+};
+
+/* This will be corrected as we get more formats */
+static bool pxa_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt)
+{
+	return	fmt->packing == SOC_MBUS_PACKING_NONE ||
+		(fmt->bits_per_sample == 8 &&
+		 fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) ||
+		(fmt->bits_per_sample > 8 &&
+		 fmt->packing == SOC_MBUS_PACKING_EXTEND16);
+}
+
+static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int idx,
+				  struct soc_camera_format_xlate *xlate)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct device *dev = icd->parent;
+	int formats = 0, ret;
+	struct pxa_cam *cam;
+	enum v4l2_mbus_pixelcode code;
+	const struct soc_mbus_pixelfmt *fmt;
+
+	ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
+	if (ret < 0)
+		/* No more formats */
+		return 0;
+
+	fmt = soc_mbus_get_fmtdesc(code);
+	if (!fmt) {
+		dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
+		return 0;
+	}
+
+	/* This also checks support for the requested bits-per-sample */
+	ret = pxa_camera_try_bus_param(icd, fmt->bits_per_sample);
+	if (ret < 0)
+		return 0;
+
+	if (!icd->host_priv) {
+		cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+		if (!cam)
+			return -ENOMEM;
+
+		icd->host_priv = cam;
+	} else {
+		cam = icd->host_priv;
+	}
+
+	switch (code) {
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		formats++;
+		if (xlate) {
+			xlate->host_fmt	= &pxa_camera_formats[0];
+			xlate->code	= code;
+			xlate++;
+			dev_dbg(dev, "Providing format %s using code %d\n",
+				pxa_camera_formats[0].name, code);
+		}
+	case V4L2_MBUS_FMT_VYUY8_2X8:
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+	case V4L2_MBUS_FMT_YVYU8_2X8:
+	case V4L2_MBUS_FMT_RGB565_2X8_LE:
+	case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+		if (xlate)
+			dev_dbg(dev, "Providing format %s packed\n",
+				fmt->name);
+		break;
+	default:
+		if (!pxa_camera_packing_supported(fmt))
+			return 0;
+		if (xlate)
+			dev_dbg(dev,
+				"Providing format %s in pass-through mode\n",
+				fmt->name);
+	}
+
+	/* Generic pass-through */
+	formats++;
+	if (xlate) {
+		xlate->host_fmt	= fmt;
+		xlate->code	= code;
+		xlate++;
+	}
+
+	return formats;
+}
+
+static void pxa_camera_put_formats(struct soc_camera_device *icd)
+{
+	kfree(icd->host_priv);
+	icd->host_priv = NULL;
+}
+
+static int pxa_camera_check_frame(u32 width, u32 height)
+{
+	/* limit to pxa hardware capabilities */
+	return height < 32 || height > 2048 || width < 48 || width > 2048 ||
+		(width & 0x01);
+}
+
+static int pxa_camera_set_crop(struct soc_camera_device *icd,
+			       struct v4l2_crop *a)
+{
+	struct v4l2_rect *rect = &a->c;
+	struct device *dev = icd->parent;
+	struct soc_camera_host *ici = to_soc_camera_host(dev);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct soc_camera_sense sense = {
+		.master_clock = pcdev->mclk,
+		.pixel_clock_max = pcdev->ciclk / 4,
+	};
+	struct v4l2_mbus_framefmt mf;
+	struct pxa_cam *cam = icd->host_priv;
+	u32 fourcc = icd->current_fmt->host_fmt->fourcc;
+	int ret;
+
+	/* If PCLK is used to latch data from the sensor, check sense */
+	if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
+		icd->sense = &sense;
+
+	ret = v4l2_subdev_call(sd, video, s_crop, a);
+
+	icd->sense = NULL;
+
+	if (ret < 0) {
+		dev_warn(dev, "Failed to crop to %ux%u@%u:%u\n",
+			 rect->width, rect->height, rect->left, rect->top);
+		return ret;
+	}
+
+	ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
+	if (ret < 0)
+		return ret;
+
+	if (pxa_camera_check_frame(mf.width, mf.height)) {
+		/*
+		 * Camera cropping produced a frame beyond our capabilities.
+		 * FIXME: just extract a subframe, that we can process.
+		 */
+		v4l_bound_align_image(&mf.width, 48, 2048, 1,
+			&mf.height, 32, 2048, 0,
+			fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0);
+		ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+		if (ret < 0)
+			return ret;
+
+		if (pxa_camera_check_frame(mf.width, mf.height)) {
+			dev_warn(icd->parent,
+				 "Inconsistent state. Use S_FMT to repair\n");
+			return -EINVAL;
+		}
+	}
+
+	if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
+		if (sense.pixel_clock > sense.pixel_clock_max) {
+			dev_err(dev,
+				"pixel clock %lu set by the camera too high!",
+				sense.pixel_clock);
+			return -EIO;
+		}
+		recalculate_fifo_timeout(pcdev, sense.pixel_clock);
+	}
+
+	icd->user_width		= mf.width;
+	icd->user_height	= mf.height;
+
+	pxa_camera_setup_cicr(icd, cam->flags, fourcc);
+
+	return ret;
+}
+
+static int pxa_camera_set_fmt(struct soc_camera_device *icd,
+			      struct v4l2_format *f)
+{
+	struct device *dev = icd->parent;
+	struct soc_camera_host *ici = to_soc_camera_host(dev);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	const struct soc_camera_format_xlate *xlate = NULL;
+	struct soc_camera_sense sense = {
+		.master_clock = pcdev->mclk,
+		.pixel_clock_max = pcdev->ciclk / 4,
+	};
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct v4l2_mbus_framefmt mf;
+	int ret;
+
+	xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+	if (!xlate) {
+		dev_warn(dev, "Format %x not found\n", pix->pixelformat);
+		return -EINVAL;
+	}
+
+	/* If PCLK is used to latch data from the sensor, check sense */
+	if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
+		/* The caller holds a mutex. */
+		icd->sense = &sense;
+
+	mf.width	= pix->width;
+	mf.height	= pix->height;
+	mf.field	= pix->field;
+	mf.colorspace	= pix->colorspace;
+	mf.code		= xlate->code;
+
+	ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+
+	if (mf.code != xlate->code)
+		return -EINVAL;
+
+	icd->sense = NULL;
+
+	if (ret < 0) {
+		dev_warn(dev, "Failed to configure for format %x\n",
+			 pix->pixelformat);
+	} else if (pxa_camera_check_frame(mf.width, mf.height)) {
+		dev_warn(dev,
+			 "Camera driver produced an unsupported frame %dx%d\n",
+			 mf.width, mf.height);
+		ret = -EINVAL;
+	} else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
+		if (sense.pixel_clock > sense.pixel_clock_max) {
+			dev_err(dev,
+				"pixel clock %lu set by the camera too high!",
+				sense.pixel_clock);
+			return -EIO;
+		}
+		recalculate_fifo_timeout(pcdev, sense.pixel_clock);
+	}
+
+	if (ret < 0)
+		return ret;
+
+	pix->width		= mf.width;
+	pix->height		= mf.height;
+	pix->field		= mf.field;
+	pix->colorspace		= mf.colorspace;
+	icd->current_fmt	= xlate;
+
+	return ret;
+}
+
+static int pxa_camera_try_fmt(struct soc_camera_device *icd,
+			      struct v4l2_format *f)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	const struct soc_camera_format_xlate *xlate;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct v4l2_mbus_framefmt mf;
+	__u32 pixfmt = pix->pixelformat;
+	int ret;
+
+	xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+	if (!xlate) {
+		dev_warn(icd->parent, "Format %x not found\n", pixfmt);
+		return -EINVAL;
+	}
+
+	/*
+	 * Limit to pxa hardware capabilities.  YUV422P planar format requires
+	 * images size to be a multiple of 16 bytes.  If not, zeros will be
+	 * inserted between Y and U planes, and U and V planes, which violates
+	 * the YUV422P standard.
+	 */
+	v4l_bound_align_image(&pix->width, 48, 2048, 1,
+			      &pix->height, 32, 2048, 0,
+			      pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0);
+
+	/* limit to sensor capabilities */
+	mf.width	= pix->width;
+	mf.height	= pix->height;
+	/* Only progressive video supported so far */
+	mf.field	= V4L2_FIELD_NONE;
+	mf.colorspace	= pix->colorspace;
+	mf.code		= xlate->code;
+
+	ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+	if (ret < 0)
+		return ret;
+
+	pix->width	= mf.width;
+	pix->height	= mf.height;
+	pix->colorspace	= mf.colorspace;
+
+	switch (mf.field) {
+	case V4L2_FIELD_ANY:
+	case V4L2_FIELD_NONE:
+		pix->field	= V4L2_FIELD_NONE;
+		break;
+	default:
+		/* TODO: support interlaced at least in pass-through mode */
+		dev_err(icd->parent, "Field type %d unsupported.\n",
+			mf.field);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int pxa_camera_reqbufs(struct soc_camera_device *icd,
+			      struct v4l2_requestbuffers *p)
+{
+	int i;
+
+	/*
+	 * This is for locking debugging only. I removed spinlocks and now I
+	 * check whether .prepare is ever called on a linked buffer, or whether
+	 * a dma IRQ can occur for an in-work or unlinked buffer. Until now
+	 * it hadn't triggered
+	 */
+	for (i = 0; i < p->count; i++) {
+		struct pxa_buffer *buf = container_of(icd->vb_vidq.bufs[i],
+						      struct pxa_buffer, vb);
+		buf->inwork = 0;
+		INIT_LIST_HEAD(&buf->vb.queue);
+	}
+
+	return 0;
+}
+
+static unsigned int pxa_camera_poll(struct file *file, poll_table *pt)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct pxa_buffer *buf;
+
+	buf = list_entry(icd->vb_vidq.stream.next, struct pxa_buffer,
+			 vb.stream);
+
+	poll_wait(file, &buf->vb.done, pt);
+
+	if (buf->vb.state == VIDEOBUF_DONE ||
+	    buf->vb.state == VIDEOBUF_ERROR)
+		return POLLIN|POLLRDNORM;
+
+	return 0;
+}
+
+static int pxa_camera_querycap(struct soc_camera_host *ici,
+			       struct v4l2_capability *cap)
+{
+	/* cap->name is set by the firendly caller:-> */
+	strlcpy(cap->card, pxa_cam_driver_description, sizeof(cap->card));
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+static int pxa_camera_suspend(struct device *dev)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(dev);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	int i = 0, ret = 0;
+
+	pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR0);
+	pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR1);
+	pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR2);
+	pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR3);
+	pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR4);
+
+	if (pcdev->icd) {
+		struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->icd);
+		ret = v4l2_subdev_call(sd, core, s_power, 0);
+		if (ret == -ENOIOCTLCMD)
+			ret = 0;
+	}
+
+	return ret;
+}
+
+static int pxa_camera_resume(struct device *dev)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(dev);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	int i = 0, ret = 0;
+
+	DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD;
+	DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD;
+	DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD;
+
+	__raw_writel(pcdev->save_cicr[i++] & ~CICR0_ENB, pcdev->base + CICR0);
+	__raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR1);
+	__raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR2);
+	__raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR3);
+	__raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR4);
+
+	if (pcdev->icd) {
+		struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->icd);
+		ret = v4l2_subdev_call(sd, core, s_power, 1);
+		if (ret == -ENOIOCTLCMD)
+			ret = 0;
+	}
+
+	/* Restart frame capture if active buffer exists */
+	if (!ret && pcdev->active)
+		pxa_camera_start_capture(pcdev);
+
+	return ret;
+}
+
+static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
+	.owner		= THIS_MODULE,
+	.add		= pxa_camera_add_device,
+	.remove		= pxa_camera_remove_device,
+	.set_crop	= pxa_camera_set_crop,
+	.get_formats	= pxa_camera_get_formats,
+	.put_formats	= pxa_camera_put_formats,
+	.set_fmt	= pxa_camera_set_fmt,
+	.try_fmt	= pxa_camera_try_fmt,
+	.init_videobuf	= pxa_camera_init_videobuf,
+	.reqbufs	= pxa_camera_reqbufs,
+	.poll		= pxa_camera_poll,
+	.querycap	= pxa_camera_querycap,
+	.set_bus_param	= pxa_camera_set_bus_param,
+};
+
+static int __devinit pxa_camera_probe(struct platform_device *pdev)
+{
+	struct pxa_camera_dev *pcdev;
+	struct resource *res;
+	void __iomem *base;
+	int irq;
+	int err = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(pdev, 0);
+	if (!res || irq < 0) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);
+	if (!pcdev) {
+		dev_err(&pdev->dev, "Could not allocate pcdev\n");
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	pcdev->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(pcdev->clk)) {
+		err = PTR_ERR(pcdev->clk);
+		goto exit_kfree;
+	}
+
+	pcdev->res = res;
+
+	pcdev->pdata = pdev->dev.platform_data;
+	pcdev->platform_flags = pcdev->pdata->flags;
+	if (!(pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 |
+			PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10))) {
+		/*
+		 * Platform hasn't set available data widths. This is bad.
+		 * Warn and use a default.
+		 */
+		dev_warn(&pdev->dev, "WARNING! Platform hasn't set available "
+			 "data widths, using default 10 bit\n");
+		pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10;
+	}
+	if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8)
+		pcdev->width_flags = 1 << 7;
+	if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9)
+		pcdev->width_flags |= 1 << 8;
+	if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10)
+		pcdev->width_flags |= 1 << 9;
+	pcdev->mclk = pcdev->pdata->mclk_10khz * 10000;
+	if (!pcdev->mclk) {
+		dev_warn(&pdev->dev,
+			 "mclk == 0! Please, fix your platform data. "
+			 "Using default 20MHz\n");
+		pcdev->mclk = 20000000;
+	}
+
+	pcdev->mclk_divisor = mclk_get_divisor(pdev, pcdev);
+
+	INIT_LIST_HEAD(&pcdev->capture);
+	spin_lock_init(&pcdev->lock);
+
+	/*
+	 * Request the regions.
+	 */
+	if (!request_mem_region(res->start, resource_size(res),
+				PXA_CAM_DRV_NAME)) {
+		err = -EBUSY;
+		goto exit_clk;
+	}
+
+	base = ioremap(res->start, resource_size(res));
+	if (!base) {
+		err = -ENOMEM;
+		goto exit_release;
+	}
+	pcdev->irq = irq;
+	pcdev->base = base;
+
+	/* request dma */
+	err = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
+			      pxa_camera_dma_irq_y, pcdev);
+	if (err < 0) {
+		dev_err(&pdev->dev, "Can't request DMA for Y\n");
+		goto exit_iounmap;
+	}
+	pcdev->dma_chans[0] = err;
+	dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]);
+
+	err = pxa_request_dma("CI_U", DMA_PRIO_HIGH,
+			      pxa_camera_dma_irq_u, pcdev);
+	if (err < 0) {
+		dev_err(&pdev->dev, "Can't request DMA for U\n");
+		goto exit_free_dma_y;
+	}
+	pcdev->dma_chans[1] = err;
+	dev_dbg(&pdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]);
+
+	err = pxa_request_dma("CI_V", DMA_PRIO_HIGH,
+			      pxa_camera_dma_irq_v, pcdev);
+	if (err < 0) {
+		dev_err(&pdev->dev, "Can't request DMA for V\n");
+		goto exit_free_dma_u;
+	}
+	pcdev->dma_chans[2] = err;
+	dev_dbg(&pdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]);
+
+	DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD;
+	DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD;
+	DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD;
+
+	/* request irq */
+	err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME,
+			  pcdev);
+	if (err) {
+		dev_err(&pdev->dev, "Camera interrupt register failed \n");
+		goto exit_free_dma;
+	}
+
+	pcdev->soc_host.drv_name	= PXA_CAM_DRV_NAME;
+	pcdev->soc_host.ops		= &pxa_soc_camera_host_ops;
+	pcdev->soc_host.priv		= pcdev;
+	pcdev->soc_host.v4l2_dev.dev	= &pdev->dev;
+	pcdev->soc_host.nr		= pdev->id;
+
+	err = soc_camera_host_register(&pcdev->soc_host);
+	if (err)
+		goto exit_free_irq;
+
+	return 0;
+
+exit_free_irq:
+	free_irq(pcdev->irq, pcdev);
+exit_free_dma:
+	pxa_free_dma(pcdev->dma_chans[2]);
+exit_free_dma_u:
+	pxa_free_dma(pcdev->dma_chans[1]);
+exit_free_dma_y:
+	pxa_free_dma(pcdev->dma_chans[0]);
+exit_iounmap:
+	iounmap(base);
+exit_release:
+	release_mem_region(res->start, resource_size(res));
+exit_clk:
+	clk_put(pcdev->clk);
+exit_kfree:
+	kfree(pcdev);
+exit:
+	return err;
+}
+
+static int __devexit pxa_camera_remove(struct platform_device *pdev)
+{
+	struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+	struct pxa_camera_dev *pcdev = container_of(soc_host,
+					struct pxa_camera_dev, soc_host);
+	struct resource *res;
+
+	clk_put(pcdev->clk);
+
+	pxa_free_dma(pcdev->dma_chans[0]);
+	pxa_free_dma(pcdev->dma_chans[1]);
+	pxa_free_dma(pcdev->dma_chans[2]);
+	free_irq(pcdev->irq, pcdev);
+
+	soc_camera_host_unregister(soc_host);
+
+	iounmap(pcdev->base);
+
+	res = pcdev->res;
+	release_mem_region(res->start, resource_size(res));
+
+	kfree(pcdev);
+
+	dev_info(&pdev->dev, "PXA Camera driver unloaded\n");
+
+	return 0;
+}
+
+static struct dev_pm_ops pxa_camera_pm = {
+	.suspend	= pxa_camera_suspend,
+	.resume		= pxa_camera_resume,
+};
+
+static struct platform_driver pxa_camera_driver = {
+	.driver 	= {
+		.name	= PXA_CAM_DRV_NAME,
+		.pm	= &pxa_camera_pm,
+	},
+	.probe		= pxa_camera_probe,
+	.remove		= __devexit_p(pxa_camera_remove),
+};
+
+module_platform_driver(pxa_camera_driver);
+
+MODULE_DESCRIPTION("PXA27x SoC Camera Host driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(PXA_CAM_VERSION);
+MODULE_ALIAS("platform:" PXA_CAM_DRV_NAME);
diff --git a/drivers/media/platform/s5p-fimc/Kconfig b/drivers/media/platform/s5p-fimc/Kconfig
new file mode 100644
index 0000000..a564f7e
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/Kconfig
@@ -0,0 +1,48 @@
+
+config VIDEO_SAMSUNG_S5P_FIMC
+	bool "Samsung S5P/EXYNOS SoC camera interface driver (experimental)"
+	depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && PLAT_S5P && PM_RUNTIME
+	depends on EXPERIMENTAL
+	help
+	  Say Y here to enable camera host interface devices for
+	  Samsung S5P and EXYNOS SoC series.
+
+if VIDEO_SAMSUNG_S5P_FIMC
+
+config VIDEO_S5P_FIMC
+	tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver"
+	depends on I2C
+	select VIDEOBUF2_DMA_CONTIG
+	select V4L2_MEM2MEM_DEV
+	help
+	  This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC camera host
+	  interface and video postprocessor (FIMC and FIMC-LITE) devices.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called s5p-fimc.
+
+config VIDEO_S5P_MIPI_CSIS
+	tristate "S5P/EXYNOS MIPI-CSI2 receiver (MIPI-CSIS) driver"
+	depends on REGULATOR
+	help
+	  This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC MIPI-CSI2
+	  receiver (MIPI-CSIS) devices.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called s5p-csis.
+
+if ARCH_EXYNOS
+
+config VIDEO_EXYNOS_FIMC_LITE
+	tristate "EXYNOS FIMC-LITE camera interface driver"
+	depends on I2C
+	select VIDEOBUF2_DMA_CONTIG
+	help
+	  This is a V4L2 driver for Samsung EXYNOS4/5 SoC FIMC-LITE camera
+	  host interface.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called exynos-fimc-lite.
+endif
+
+endif # VIDEO_SAMSUNG_S5P_FIMC
diff --git a/drivers/media/platform/s5p-fimc/Makefile b/drivers/media/platform/s5p-fimc/Makefile
new file mode 100644
index 0000000..4648514
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/Makefile
@@ -0,0 +1,7 @@
+s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-m2m.o fimc-capture.o fimc-mdevice.o
+exynos-fimc-lite-objs += fimc-lite-reg.o fimc-lite.o
+s5p-csis-objs := mipi-csis.o
+
+obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS)	+= s5p-csis.o
+obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE)	+= exynos-fimc-lite.o
+obj-$(CONFIG_VIDEO_S5P_FIMC)		+= s5p-fimc.o
diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c
new file mode 100644
index 0000000..8e413dd
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-capture.c
@@ -0,0 +1,1738 @@
+/*
+ * Samsung S5P/EXYNOS4 SoC series camera interface (camera capture) driver
+ *
+ * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/pm_runtime.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "fimc-mdevice.h"
+#include "fimc-core.h"
+#include "fimc-reg.h"
+
+static int fimc_capture_hw_init(struct fimc_dev *fimc)
+{
+	struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+	struct fimc_pipeline *p = &fimc->pipeline;
+	struct fimc_sensor_info *sensor;
+	unsigned long flags;
+	int ret = 0;
+
+	if (p->subdevs[IDX_SENSOR] == NULL || ctx == NULL)
+		return -ENXIO;
+	if (ctx->s_frame.fmt == NULL)
+		return -EINVAL;
+
+	sensor = v4l2_get_subdev_hostdata(p->subdevs[IDX_SENSOR]);
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	fimc_prepare_dma_offset(ctx, &ctx->d_frame);
+	fimc_set_yuv_order(ctx);
+
+	fimc_hw_set_camera_polarity(fimc, sensor->pdata);
+	fimc_hw_set_camera_type(fimc, sensor->pdata);
+	fimc_hw_set_camera_source(fimc, sensor->pdata);
+	fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
+
+	ret = fimc_set_scaler_info(ctx);
+	if (!ret) {
+		fimc_hw_set_input_path(ctx);
+		fimc_hw_set_prescaler(ctx);
+		fimc_hw_set_mainscaler(ctx);
+		fimc_hw_set_target_format(ctx);
+		fimc_hw_set_rotation(ctx);
+		fimc_hw_set_effect(ctx);
+		fimc_hw_set_output_path(ctx);
+		fimc_hw_set_out_dma(ctx);
+		if (fimc->variant->has_alpha)
+			fimc_hw_set_rgb_alpha(ctx);
+		clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);
+	}
+	spin_unlock_irqrestore(&fimc->slock, flags);
+	return ret;
+}
+
+/*
+ * Reinitialize the driver so it is ready to start the streaming again.
+ * Set fimc->state to indicate stream off and the hardware shut down state.
+ * If not suspending (@suspend is false), return any buffers to videobuf2.
+ * Otherwise put any owned buffers onto the pending buffers queue, so they
+ * can be re-spun when the device is being resumed. Also perform FIMC
+ * software reset and disable streaming on the whole pipeline if required.
+ */
+static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend)
+{
+	struct fimc_vid_cap *cap = &fimc->vid_cap;
+	struct fimc_vid_buffer *buf;
+	unsigned long flags;
+	bool streaming;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	streaming = fimc->state & (1 << ST_CAPT_ISP_STREAM);
+
+	fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_SHUT |
+			 1 << ST_CAPT_STREAM | 1 << ST_CAPT_ISP_STREAM);
+	if (suspend)
+		fimc->state |= (1 << ST_CAPT_SUSPENDED);
+	else
+		fimc->state &= ~(1 << ST_CAPT_PEND | 1 << ST_CAPT_SUSPENDED);
+
+	/* Release unused buffers */
+	while (!suspend && !list_empty(&cap->pending_buf_q)) {
+		buf = fimc_pending_queue_pop(cap);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+	/* If suspending put unused buffers onto pending queue */
+	while (!list_empty(&cap->active_buf_q)) {
+		buf = fimc_active_queue_pop(cap);
+		if (suspend)
+			fimc_pending_queue_add(cap, buf);
+		else
+			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+
+	fimc_hw_reset(fimc);
+	cap->buf_index = 0;
+
+	spin_unlock_irqrestore(&fimc->slock, flags);
+
+	if (streaming)
+		return fimc_pipeline_s_stream(&fimc->pipeline, 0);
+	else
+		return 0;
+}
+
+static int fimc_stop_capture(struct fimc_dev *fimc, bool suspend)
+{
+	unsigned long flags;
+
+	if (!fimc_capture_active(fimc))
+		return 0;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	set_bit(ST_CAPT_SHUT, &fimc->state);
+	fimc_deactivate_capture(fimc);
+	spin_unlock_irqrestore(&fimc->slock, flags);
+
+	wait_event_timeout(fimc->irq_queue,
+			   !test_bit(ST_CAPT_SHUT, &fimc->state),
+			   (2*HZ/10)); /* 200 ms */
+
+	return fimc_capture_state_cleanup(fimc, suspend);
+}
+
+/**
+ * fimc_capture_config_update - apply the camera interface configuration
+ *
+ * To be called from within the interrupt handler with fimc.slock
+ * spinlock held. It updates the camera pixel crop, rotation and
+ * image flip in H/W.
+ */
+static int fimc_capture_config_update(struct fimc_ctx *ctx)
+{
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	int ret;
+
+	fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
+
+	ret = fimc_set_scaler_info(ctx);
+	if (ret)
+		return ret;
+
+	fimc_hw_set_prescaler(ctx);
+	fimc_hw_set_mainscaler(ctx);
+	fimc_hw_set_target_format(ctx);
+	fimc_hw_set_rotation(ctx);
+	fimc_hw_set_effect(ctx);
+	fimc_prepare_dma_offset(ctx, &ctx->d_frame);
+	fimc_hw_set_out_dma(ctx);
+	if (fimc->variant->has_alpha)
+		fimc_hw_set_rgb_alpha(ctx);
+
+	clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);
+	return ret;
+}
+
+void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf)
+{
+	struct fimc_vid_cap *cap = &fimc->vid_cap;
+	struct fimc_vid_buffer *v_buf;
+	struct timeval *tv;
+	struct timespec ts;
+
+	if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) {
+		wake_up(&fimc->irq_queue);
+		goto done;
+	}
+
+	if (!list_empty(&cap->active_buf_q) &&
+	    test_bit(ST_CAPT_RUN, &fimc->state) && deq_buf) {
+		ktime_get_real_ts(&ts);
+
+		v_buf = fimc_active_queue_pop(cap);
+
+		tv = &v_buf->vb.v4l2_buf.timestamp;
+		tv->tv_sec = ts.tv_sec;
+		tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+		v_buf->vb.v4l2_buf.sequence = cap->frame_count++;
+
+		vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE);
+	}
+
+	if (!list_empty(&cap->pending_buf_q)) {
+
+		v_buf = fimc_pending_queue_pop(cap);
+		fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index);
+		v_buf->index = cap->buf_index;
+
+		/* Move the buffer to the capture active queue */
+		fimc_active_queue_add(cap, v_buf);
+
+		dbg("next frame: %d, done frame: %d",
+		    fimc_hw_get_frame_index(fimc), v_buf->index);
+
+		if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
+			cap->buf_index = 0;
+	}
+
+	if (cap->active_buf_cnt == 0) {
+		if (deq_buf)
+			clear_bit(ST_CAPT_RUN, &fimc->state);
+
+		if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
+			cap->buf_index = 0;
+	} else {
+		set_bit(ST_CAPT_RUN, &fimc->state);
+	}
+
+	if (test_bit(ST_CAPT_APPLY_CFG, &fimc->state))
+		fimc_capture_config_update(cap->ctx);
+done:
+	if (cap->active_buf_cnt == 1) {
+		fimc_deactivate_capture(fimc);
+		clear_bit(ST_CAPT_STREAM, &fimc->state);
+	}
+
+	dbg("frame: %d, active_buf_cnt: %d",
+	    fimc_hw_get_frame_index(fimc), cap->active_buf_cnt);
+}
+
+
+static int start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct fimc_ctx *ctx = q->drv_priv;
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+	int min_bufs;
+	int ret;
+
+	vid_cap->frame_count = 0;
+
+	ret = fimc_capture_hw_init(fimc);
+	if (ret) {
+		fimc_capture_state_cleanup(fimc, false);
+		return ret;
+	}
+
+	set_bit(ST_CAPT_PEND, &fimc->state);
+
+	min_bufs = fimc->vid_cap.reqbufs_count > 1 ? 2 : 1;
+
+	if (vid_cap->active_buf_cnt >= min_bufs &&
+	    !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) {
+		fimc_activate_capture(ctx);
+
+		if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
+			fimc_pipeline_s_stream(&fimc->pipeline, 1);
+	}
+
+	return 0;
+}
+
+static int stop_streaming(struct vb2_queue *q)
+{
+	struct fimc_ctx *ctx = q->drv_priv;
+	struct fimc_dev *fimc = ctx->fimc_dev;
+
+	if (!fimc_capture_active(fimc))
+		return -EINVAL;
+
+	return fimc_stop_capture(fimc, false);
+}
+
+int fimc_capture_suspend(struct fimc_dev *fimc)
+{
+	bool suspend = fimc_capture_busy(fimc);
+
+	int ret = fimc_stop_capture(fimc, suspend);
+	if (ret)
+		return ret;
+	return fimc_pipeline_shutdown(&fimc->pipeline);
+}
+
+static void buffer_queue(struct vb2_buffer *vb);
+
+int fimc_capture_resume(struct fimc_dev *fimc)
+{
+	struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+	struct fimc_vid_buffer *buf;
+	int i;
+
+	if (!test_and_clear_bit(ST_CAPT_SUSPENDED, &fimc->state))
+		return 0;
+
+	INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
+	vid_cap->buf_index = 0;
+	fimc_pipeline_initialize(&fimc->pipeline, &vid_cap->vfd->entity,
+				 false);
+	fimc_capture_hw_init(fimc);
+
+	clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
+
+	for (i = 0; i < vid_cap->reqbufs_count; i++) {
+		if (list_empty(&vid_cap->pending_buf_q))
+			break;
+		buf = fimc_pending_queue_pop(vid_cap);
+		buffer_queue(&buf->vb);
+	}
+	return 0;
+
+}
+
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt,
+		       unsigned int *num_buffers, unsigned int *num_planes,
+		       unsigned int sizes[], void *allocators[])
+{
+	const struct v4l2_pix_format_mplane *pixm = NULL;
+	struct fimc_ctx *ctx = vq->drv_priv;
+	struct fimc_frame *frame = &ctx->d_frame;
+	struct fimc_fmt *fmt = frame->fmt;
+	unsigned long wh;
+	int i;
+
+	if (pfmt) {
+		pixm = &pfmt->fmt.pix_mp;
+		fmt = fimc_find_format(&pixm->pixelformat, NULL,
+				       FMT_FLAGS_CAM | FMT_FLAGS_M2M, -1);
+		wh = pixm->width * pixm->height;
+	} else {
+		wh = frame->f_width * frame->f_height;
+	}
+
+	if (fmt == NULL)
+		return -EINVAL;
+
+	*num_planes = fmt->memplanes;
+
+	for (i = 0; i < fmt->memplanes; i++) {
+		unsigned int size = (wh * fmt->depth[i]) / 8;
+		if (pixm)
+			sizes[i] = max(size, pixm->plane_fmt[i].sizeimage);
+		else
+			sizes[i] = max_t(u32, size, frame->payload[i]);
+
+		allocators[i] = ctx->fimc_dev->alloc_ctx;
+	}
+
+	return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct fimc_ctx *ctx = vq->drv_priv;
+	int i;
+
+	if (ctx->d_frame.fmt == NULL)
+		return -EINVAL;
+
+	for (i = 0; i < ctx->d_frame.fmt->memplanes; i++) {
+		unsigned long size = ctx->d_frame.payload[i];
+
+		if (vb2_plane_size(vb, i) < size) {
+			v4l2_err(ctx->fimc_dev->vid_cap.vfd,
+				 "User buffer too small (%ld < %ld)\n",
+				 vb2_plane_size(vb, i), size);
+			return -EINVAL;
+		}
+		vb2_set_plane_payload(vb, i, size);
+	}
+
+	return 0;
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+	struct fimc_vid_buffer *buf
+		= container_of(vb, struct fimc_vid_buffer, vb);
+	struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+	unsigned long flags;
+	int min_bufs;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	fimc_prepare_addr(ctx, &buf->vb, &ctx->d_frame, &buf->paddr);
+
+	if (!test_bit(ST_CAPT_SUSPENDED, &fimc->state) &&
+	    !test_bit(ST_CAPT_STREAM, &fimc->state) &&
+	    vid_cap->active_buf_cnt < FIMC_MAX_OUT_BUFS) {
+		/* Setup the buffer directly for processing. */
+		int buf_id = (vid_cap->reqbufs_count == 1) ? -1 :
+				vid_cap->buf_index;
+
+		fimc_hw_set_output_addr(fimc, &buf->paddr, buf_id);
+		buf->index = vid_cap->buf_index;
+		fimc_active_queue_add(vid_cap, buf);
+
+		if (++vid_cap->buf_index >= FIMC_MAX_OUT_BUFS)
+			vid_cap->buf_index = 0;
+	} else {
+		fimc_pending_queue_add(vid_cap, buf);
+	}
+
+	min_bufs = vid_cap->reqbufs_count > 1 ? 2 : 1;
+
+
+	if (vb2_is_streaming(&vid_cap->vbq) &&
+	    vid_cap->active_buf_cnt >= min_bufs &&
+	    !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) {
+		fimc_activate_capture(ctx);
+		spin_unlock_irqrestore(&fimc->slock, flags);
+
+		if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
+			fimc_pipeline_s_stream(&fimc->pipeline, 1);
+		return;
+	}
+	spin_unlock_irqrestore(&fimc->slock, flags);
+}
+
+static void fimc_lock(struct vb2_queue *vq)
+{
+	struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
+	mutex_lock(&ctx->fimc_dev->lock);
+}
+
+static void fimc_unlock(struct vb2_queue *vq)
+{
+	struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
+	mutex_unlock(&ctx->fimc_dev->lock);
+}
+
+static struct vb2_ops fimc_capture_qops = {
+	.queue_setup		= queue_setup,
+	.buf_prepare		= buffer_prepare,
+	.buf_queue		= buffer_queue,
+	.wait_prepare		= fimc_unlock,
+	.wait_finish		= fimc_lock,
+	.start_streaming	= start_streaming,
+	.stop_streaming		= stop_streaming,
+};
+
+/**
+ * fimc_capture_ctrls_create - initialize the control handler
+ * Initialize the capture video node control handler and fill it
+ * with the FIMC controls. Inherit any sensor's controls if the
+ * 'user_subdev_api' flag is false (default behaviour).
+ * This function need to be called with the graph mutex held.
+ */
+int fimc_capture_ctrls_create(struct fimc_dev *fimc)
+{
+	struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+	int ret;
+
+	if (WARN_ON(vid_cap->ctx == NULL))
+		return -ENXIO;
+	if (vid_cap->ctx->ctrls.ready)
+		return 0;
+
+	ret = fimc_ctrls_create(vid_cap->ctx);
+	if (ret || vid_cap->user_subdev_api || !vid_cap->ctx->ctrls.ready)
+		return ret;
+
+	return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrls.handler,
+		    fimc->pipeline.subdevs[IDX_SENSOR]->ctrl_handler);
+}
+
+static int fimc_capture_set_default_format(struct fimc_dev *fimc);
+
+static int fimc_capture_open(struct file *file)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+	int ret = -EBUSY;
+
+	dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
+
+	if (mutex_lock_interruptible(&fimc->lock))
+		return -ERESTARTSYS;
+
+	if (fimc_m2m_active(fimc))
+		goto unlock;
+
+	set_bit(ST_CAPT_BUSY, &fimc->state);
+	ret = pm_runtime_get_sync(&fimc->pdev->dev);
+	if (ret < 0)
+		goto unlock;
+
+	ret = v4l2_fh_open(file);
+	if (ret) {
+		pm_runtime_put(&fimc->pdev->dev);
+		goto unlock;
+	}
+
+	if (++fimc->vid_cap.refcnt == 1) {
+		ret = fimc_pipeline_initialize(&fimc->pipeline,
+				       &fimc->vid_cap.vfd->entity, true);
+
+		if (!ret && !fimc->vid_cap.user_subdev_api)
+			ret = fimc_capture_set_default_format(fimc);
+
+		if (!ret)
+			ret = fimc_capture_ctrls_create(fimc);
+
+		if (ret < 0) {
+			clear_bit(ST_CAPT_BUSY, &fimc->state);
+			pm_runtime_put_sync(&fimc->pdev->dev);
+			fimc->vid_cap.refcnt--;
+			v4l2_fh_release(file);
+		}
+	}
+unlock:
+	mutex_unlock(&fimc->lock);
+	return ret;
+}
+
+static int fimc_capture_close(struct file *file)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+	int ret;
+
+	dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
+
+	if (mutex_lock_interruptible(&fimc->lock))
+		return -ERESTARTSYS;
+
+	if (--fimc->vid_cap.refcnt == 0) {
+		clear_bit(ST_CAPT_BUSY, &fimc->state);
+		fimc_stop_capture(fimc, false);
+		fimc_pipeline_shutdown(&fimc->pipeline);
+		clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
+	}
+
+	pm_runtime_put(&fimc->pdev->dev);
+
+	if (fimc->vid_cap.refcnt == 0) {
+		vb2_queue_release(&fimc->vid_cap.vbq);
+		fimc_ctrls_delete(fimc->vid_cap.ctx);
+	}
+
+	ret = v4l2_fh_release(file);
+
+	mutex_unlock(&fimc->lock);
+	return ret;
+}
+
+static unsigned int fimc_capture_poll(struct file *file,
+				      struct poll_table_struct *wait)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+	int ret;
+
+	if (mutex_lock_interruptible(&fimc->lock))
+		return POLL_ERR;
+
+	ret = vb2_poll(&fimc->vid_cap.vbq, file, wait);
+	mutex_unlock(&fimc->lock);
+
+	return ret;
+}
+
+static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+	int ret;
+
+	if (mutex_lock_interruptible(&fimc->lock))
+		return -ERESTARTSYS;
+
+	ret = vb2_mmap(&fimc->vid_cap.vbq, vma);
+	mutex_unlock(&fimc->lock);
+
+	return ret;
+}
+
+static const struct v4l2_file_operations fimc_capture_fops = {
+	.owner		= THIS_MODULE,
+	.open		= fimc_capture_open,
+	.release	= fimc_capture_close,
+	.poll		= fimc_capture_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= fimc_capture_mmap,
+};
+
+/*
+ * Format and crop negotiation helpers
+ */
+
+static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx,
+						u32 *width, u32 *height,
+						u32 *code, u32 *fourcc, int pad)
+{
+	bool rotation = ctx->rotation == 90 || ctx->rotation == 270;
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	struct fimc_variant *var = fimc->variant;
+	struct fimc_pix_limit *pl = var->pix_limit;
+	struct fimc_frame *dst = &ctx->d_frame;
+	u32 depth, min_w, max_w, min_h, align_h = 3;
+	u32 mask = FMT_FLAGS_CAM;
+	struct fimc_fmt *ffmt;
+
+	/* Color conversion from/to JPEG is not supported */
+	if (code && ctx->s_frame.fmt && pad == FIMC_SD_PAD_SOURCE &&
+	    fimc_fmt_is_jpeg(ctx->s_frame.fmt->color))
+		*code = V4L2_MBUS_FMT_JPEG_1X8;
+
+	if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad != FIMC_SD_PAD_SINK)
+		mask |= FMT_FLAGS_M2M;
+
+	ffmt = fimc_find_format(fourcc, code, mask, 0);
+	if (WARN_ON(!ffmt))
+		return NULL;
+	if (code)
+		*code = ffmt->mbus_code;
+	if (fourcc)
+		*fourcc = ffmt->fourcc;
+
+	if (pad == FIMC_SD_PAD_SINK) {
+		max_w = fimc_fmt_is_jpeg(ffmt->color) ?
+			pl->scaler_dis_w : pl->scaler_en_w;
+		/* Apply the camera input interface pixel constraints */
+		v4l_bound_align_image(width, max_t(u32, *width, 32), max_w, 4,
+				      height, max_t(u32, *height, 32),
+				      FIMC_CAMIF_MAX_HEIGHT,
+				      fimc_fmt_is_jpeg(ffmt->color) ? 3 : 1,
+				      0);
+		return ffmt;
+	}
+	/* Can't scale or crop in transparent (JPEG) transfer mode */
+	if (fimc_fmt_is_jpeg(ffmt->color)) {
+		*width  = ctx->s_frame.f_width;
+		*height = ctx->s_frame.f_height;
+		return ffmt;
+	}
+	/* Apply the scaler and the output DMA constraints */
+	max_w = rotation ? pl->out_rot_en_w : pl->out_rot_dis_w;
+	if (ctx->state & FIMC_COMPOSE) {
+		min_w = dst->offs_h + dst->width;
+		min_h = dst->offs_v + dst->height;
+	} else {
+		min_w = var->min_out_pixsize;
+		min_h = var->min_out_pixsize;
+	}
+	if (var->min_vsize_align == 1 && !rotation)
+		align_h = fimc_fmt_is_rgb(ffmt->color) ? 0 : 1;
+
+	depth = fimc_get_format_depth(ffmt);
+	v4l_bound_align_image(width, min_w, max_w,
+			      ffs(var->min_out_pixsize) - 1,
+			      height, min_h, FIMC_CAMIF_MAX_HEIGHT,
+			      align_h,
+			      64/(ALIGN(depth, 8)));
+
+	dbg("pad%d: code: 0x%x, %dx%d. dst fmt: %dx%d",
+	    pad, code ? *code : 0, *width, *height,
+	    dst->f_width, dst->f_height);
+
+	return ffmt;
+}
+
+static void fimc_capture_try_selection(struct fimc_ctx *ctx,
+				       struct v4l2_rect *r,
+				       int target)
+{
+	bool rotate = ctx->rotation == 90 || ctx->rotation == 270;
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	struct fimc_variant *var = fimc->variant;
+	struct fimc_pix_limit *pl = var->pix_limit;
+	struct fimc_frame *sink = &ctx->s_frame;
+	u32 max_w, max_h, min_w = 0, min_h = 0, min_sz;
+	u32 align_sz = 0, align_h = 4;
+	u32 max_sc_h, max_sc_v;
+
+	/* In JPEG transparent transfer mode cropping is not supported */
+	if (fimc_fmt_is_jpeg(ctx->d_frame.fmt->color)) {
+		r->width  = sink->f_width;
+		r->height = sink->f_height;
+		r->left   = r->top = 0;
+		return;
+	}
+	if (target == V4L2_SEL_TGT_COMPOSE) {
+		if (ctx->rotation != 90 && ctx->rotation != 270)
+			align_h = 1;
+		max_sc_h = min(SCALER_MAX_HRATIO, 1 << (ffs(sink->width) - 3));
+		max_sc_v = min(SCALER_MAX_VRATIO, 1 << (ffs(sink->height) - 1));
+		min_sz = var->min_out_pixsize;
+	} else {
+		u32 depth = fimc_get_format_depth(sink->fmt);
+		align_sz = 64/ALIGN(depth, 8);
+		min_sz = var->min_inp_pixsize;
+		min_w = min_h = min_sz;
+		max_sc_h = max_sc_v = 1;
+	}
+	/*
+	 * For the compose rectangle the following constraints must be met:
+	 * - it must fit in the sink pad format rectangle (f_width/f_height);
+	 * - maximum downscaling ratio is 64;
+	 * - maximum crop size depends if the rotator is used or not;
+	 * - the sink pad format width/height must be 4 multiple of the
+	 *   prescaler ratios determined by sink pad size and source pad crop,
+	 *   the prescaler ratio is returned by fimc_get_scaler_factor().
+	 */
+	max_w = min_t(u32,
+		      rotate ? pl->out_rot_en_w : pl->out_rot_dis_w,
+		      rotate ? sink->f_height : sink->f_width);
+	max_h = min_t(u32, FIMC_CAMIF_MAX_HEIGHT, sink->f_height);
+
+	if (target == V4L2_SEL_TGT_COMPOSE) {
+		min_w = min_t(u32, max_w, sink->f_width / max_sc_h);
+		min_h = min_t(u32, max_h, sink->f_height / max_sc_v);
+		if (rotate) {
+			swap(max_sc_h, max_sc_v);
+			swap(min_w, min_h);
+		}
+	}
+	v4l_bound_align_image(&r->width, min_w, max_w, ffs(min_sz) - 1,
+			      &r->height, min_h, max_h, align_h,
+			      align_sz);
+	/* Adjust left/top if crop/compose rectangle is out of bounds */
+	r->left = clamp_t(u32, r->left, 0, sink->f_width - r->width);
+	r->top  = clamp_t(u32, r->top, 0, sink->f_height - r->height);
+	r->left = round_down(r->left, var->hor_offs_align);
+
+	dbg("target %#x: (%d,%d)/%dx%d, sink fmt: %dx%d",
+	    target, r->left, r->top, r->width, r->height,
+	    sink->f_width, sink->f_height);
+}
+
+/*
+ * The video node ioctl operations
+ */
+static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
+					struct v4l2_capability *cap)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+
+	strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
+	strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
+	cap->bus_info[0] = 0;
+	cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+
+	return 0;
+}
+
+static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv,
+				    struct v4l2_fmtdesc *f)
+{
+	struct fimc_fmt *fmt;
+
+	fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM | FMT_FLAGS_M2M,
+			       f->index);
+	if (!fmt)
+		return -EINVAL;
+	strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+	f->pixelformat = fmt->fourcc;
+	if (fmt->fourcc == V4L2_MBUS_FMT_JPEG_1X8)
+		f->flags |= V4L2_FMT_FLAG_COMPRESSED;
+	return 0;
+}
+
+/**
+ * fimc_pipeline_try_format - negotiate and/or set formats at pipeline
+ *                            elements
+ * @ctx: FIMC capture context
+ * @tfmt: media bus format to try/set on subdevs
+ * @fmt_id: fimc pixel format id corresponding to returned @tfmt (output)
+ * @set: true to set format on subdevs, false to try only
+ */
+static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
+				    struct v4l2_mbus_framefmt *tfmt,
+				    struct fimc_fmt **fmt_id,
+				    bool set)
+{
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
+	struct v4l2_subdev *csis = fimc->pipeline.subdevs[IDX_CSIS];
+	struct v4l2_subdev_format sfmt;
+	struct v4l2_mbus_framefmt *mf = &sfmt.format;
+	struct fimc_fmt *ffmt = NULL;
+	int ret, i = 0;
+
+	if (WARN_ON(!sd || !tfmt))
+		return -EINVAL;
+
+	memset(&sfmt, 0, sizeof(sfmt));
+	sfmt.format = *tfmt;
+
+	sfmt.which = set ? V4L2_SUBDEV_FORMAT_ACTIVE : V4L2_SUBDEV_FORMAT_TRY;
+	while (1) {
+		ffmt = fimc_find_format(NULL, mf->code != 0 ? &mf->code : NULL,
+					FMT_FLAGS_CAM, i++);
+		if (ffmt == NULL) {
+			/*
+			 * Notify user-space if common pixel code for
+			 * host and sensor does not exist.
+			 */
+			return -EINVAL;
+		}
+		mf->code = tfmt->code = ffmt->mbus_code;
+
+		ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &sfmt);
+		if (ret)
+			return ret;
+		if (mf->code != tfmt->code) {
+			mf->code = 0;
+			continue;
+		}
+		if (mf->width != tfmt->width || mf->height != tfmt->height) {
+			u32 fcc = ffmt->fourcc;
+			tfmt->width  = mf->width;
+			tfmt->height = mf->height;
+			ffmt = fimc_capture_try_format(ctx,
+					       &tfmt->width, &tfmt->height,
+					       NULL, &fcc, FIMC_SD_PAD_SOURCE);
+			if (ffmt && ffmt->mbus_code)
+				mf->code = ffmt->mbus_code;
+			if (mf->width != tfmt->width ||
+			    mf->height != tfmt->height)
+				continue;
+			tfmt->code = mf->code;
+		}
+		if (csis)
+			ret = v4l2_subdev_call(csis, pad, set_fmt, NULL, &sfmt);
+
+		if (mf->code == tfmt->code &&
+		    mf->width == tfmt->width && mf->height == tfmt->height)
+			break;
+	}
+
+	if (fmt_id && ffmt)
+		*fmt_id = ffmt;
+	*tfmt = *mf;
+
+	dbg("code: 0x%x, %dx%d, %p", mf->code, mf->width, mf->height, ffmt);
+	return 0;
+}
+
+static int fimc_cap_g_fmt_mplane(struct file *file, void *fh,
+				 struct v4l2_format *f)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+	struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+
+	return fimc_fill_format(&ctx->d_frame, f);
+}
+
+static int fimc_cap_try_fmt_mplane(struct file *file, void *fh,
+				   struct v4l2_format *f)
+{
+	struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+	struct fimc_dev *fimc = video_drvdata(file);
+	struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+	struct v4l2_mbus_framefmt mf;
+	struct fimc_fmt *ffmt = NULL;
+
+	if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
+		fimc_capture_try_format(ctx, &pix->width, &pix->height,
+					NULL, &pix->pixelformat,
+					FIMC_SD_PAD_SINK);
+		ctx->s_frame.f_width  = pix->width;
+		ctx->s_frame.f_height = pix->height;
+	}
+	ffmt = fimc_capture_try_format(ctx, &pix->width, &pix->height,
+				       NULL, &pix->pixelformat,
+				       FIMC_SD_PAD_SOURCE);
+	if (!ffmt)
+		return -EINVAL;
+
+	if (!fimc->vid_cap.user_subdev_api) {
+		mf.width  = pix->width;
+		mf.height = pix->height;
+		mf.code   = ffmt->mbus_code;
+		fimc_md_graph_lock(fimc);
+		fimc_pipeline_try_format(ctx, &mf, &ffmt, false);
+		fimc_md_graph_unlock(fimc);
+
+		pix->width	 = mf.width;
+		pix->height	 = mf.height;
+		if (ffmt)
+			pix->pixelformat = ffmt->fourcc;
+	}
+
+	fimc_adjust_mplane_format(ffmt, pix->width, pix->height, pix);
+	return 0;
+}
+
+static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx, bool jpeg)
+{
+	ctx->scaler.enabled = !jpeg;
+	fimc_ctrls_activate(ctx, !jpeg);
+
+	if (jpeg)
+		set_bit(ST_CAPT_JPEG, &ctx->fimc_dev->state);
+	else
+		clear_bit(ST_CAPT_JPEG, &ctx->fimc_dev->state);
+}
+
+static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f)
+{
+	struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+	struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+	struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.mf;
+	struct fimc_frame *ff = &ctx->d_frame;
+	struct fimc_fmt *s_fmt = NULL;
+	int ret, i;
+
+	if (vb2_is_busy(&fimc->vid_cap.vbq))
+		return -EBUSY;
+
+	/* Pre-configure format at camera interface input, for JPEG only */
+	if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
+		fimc_capture_try_format(ctx, &pix->width, &pix->height,
+					NULL, &pix->pixelformat,
+					FIMC_SD_PAD_SINK);
+		ctx->s_frame.f_width  = pix->width;
+		ctx->s_frame.f_height = pix->height;
+	}
+	/* Try the format at the scaler and the DMA output */
+	ff->fmt = fimc_capture_try_format(ctx, &pix->width, &pix->height,
+					  NULL, &pix->pixelformat,
+					  FIMC_SD_PAD_SOURCE);
+	if (!ff->fmt)
+		return -EINVAL;
+
+	/* Update RGB Alpha control state and value range */
+	fimc_alpha_ctrl_update(ctx);
+
+	/* Try to match format at the host and the sensor */
+	if (!fimc->vid_cap.user_subdev_api) {
+		mf->code   = ff->fmt->mbus_code;
+		mf->width  = pix->width;
+		mf->height = pix->height;
+
+		fimc_md_graph_lock(fimc);
+		ret = fimc_pipeline_try_format(ctx, mf, &s_fmt, true);
+		fimc_md_graph_unlock(fimc);
+		if (ret)
+			return ret;
+		pix->width  = mf->width;
+		pix->height = mf->height;
+	}
+
+	fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix);
+	for (i = 0; i < ff->fmt->colplanes; i++)
+		ff->payload[i] = pix->plane_fmt[i].sizeimage;
+
+	set_frame_bounds(ff, pix->width, pix->height);
+	/* Reset the composition rectangle if not yet configured */
+	if (!(ctx->state & FIMC_COMPOSE))
+		set_frame_crop(ff, 0, 0, pix->width, pix->height);
+
+	fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ff->fmt->color));
+
+	/* Reset cropping and set format at the camera interface input */
+	if (!fimc->vid_cap.user_subdev_api) {
+		ctx->s_frame.fmt = s_fmt;
+		set_frame_bounds(&ctx->s_frame, pix->width, pix->height);
+		set_frame_crop(&ctx->s_frame, 0, 0, pix->width, pix->height);
+	}
+
+	return ret;
+}
+
+static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
+				 struct v4l2_format *f)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+
+	return fimc_capture_set_format(fimc, f);
+}
+
+static int fimc_cap_enum_input(struct file *file, void *priv,
+			       struct v4l2_input *i)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+	struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
+
+	if (i->index != 0)
+		return -EINVAL;
+
+	i->type = V4L2_INPUT_TYPE_CAMERA;
+	if (sd)
+		strlcpy(i->name, sd->name, sizeof(i->name));
+	return 0;
+}
+
+static int fimc_cap_s_input(struct file *file, void *priv, unsigned int i)
+{
+	return i == 0 ? i : -EINVAL;
+}
+
+static int fimc_cap_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+/**
+ * fimc_pipeline_validate - check for formats inconsistencies
+ *                          between source and sink pad of each link
+ *
+ * Return 0 if all formats match or -EPIPE otherwise.
+ */
+static int fimc_pipeline_validate(struct fimc_dev *fimc)
+{
+	struct v4l2_subdev_format sink_fmt, src_fmt;
+	struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+	struct v4l2_subdev *sd;
+	struct media_pad *pad;
+	int ret;
+
+	/* Start with the video capture node pad */
+	pad = media_entity_remote_source(&vid_cap->vd_pad);
+	if (pad == NULL)
+		return -EPIPE;
+	/* FIMC.{N} subdevice */
+	sd = media_entity_to_v4l2_subdev(pad->entity);
+
+	while (1) {
+		/* Retrieve format at the sink pad */
+		pad = &sd->entity.pads[0];
+		if (!(pad->flags & MEDIA_PAD_FL_SINK))
+			break;
+		/* Don't call FIMC subdev operation to avoid nested locking */
+		if (sd == &fimc->vid_cap.subdev) {
+			struct fimc_frame *ff = &vid_cap->ctx->s_frame;
+			sink_fmt.format.width = ff->f_width;
+			sink_fmt.format.height = ff->f_height;
+			sink_fmt.format.code = ff->fmt ? ff->fmt->mbus_code : 0;
+		} else {
+			sink_fmt.pad = pad->index;
+			sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+			ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sink_fmt);
+			if (ret < 0 && ret != -ENOIOCTLCMD)
+				return -EPIPE;
+		}
+		/* Retrieve format at the source pad */
+		pad = media_entity_remote_source(pad);
+		if (pad == NULL ||
+		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+			break;
+
+		sd = media_entity_to_v4l2_subdev(pad->entity);
+		src_fmt.pad = pad->index;
+		src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+		ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt);
+		if (ret < 0 && ret != -ENOIOCTLCMD)
+			return -EPIPE;
+
+		if (src_fmt.format.width != sink_fmt.format.width ||
+		    src_fmt.format.height != sink_fmt.format.height ||
+		    src_fmt.format.code != sink_fmt.format.code)
+			return -EPIPE;
+	}
+	return 0;
+}
+
+static int fimc_cap_streamon(struct file *file, void *priv,
+			     enum v4l2_buf_type type)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+	struct fimc_pipeline *p = &fimc->pipeline;
+	struct v4l2_subdev *sd = p->subdevs[IDX_SENSOR];
+	int ret;
+
+	if (fimc_capture_active(fimc))
+		return -EBUSY;
+
+	ret = media_entity_pipeline_start(&sd->entity, p->m_pipeline);
+	if (ret < 0)
+		return ret;
+
+	if (fimc->vid_cap.user_subdev_api) {
+		ret = fimc_pipeline_validate(fimc);
+		if (ret < 0) {
+			media_entity_pipeline_stop(&sd->entity);
+			return ret;
+		}
+	}
+	return vb2_streamon(&fimc->vid_cap.vbq, type);
+}
+
+static int fimc_cap_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type type)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+	struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
+	int ret;
+
+	ret = vb2_streamoff(&fimc->vid_cap.vbq, type);
+	if (ret == 0)
+		media_entity_pipeline_stop(&sd->entity);
+	return ret;
+}
+
+static int fimc_cap_reqbufs(struct file *file, void *priv,
+			    struct v4l2_requestbuffers *reqbufs)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+	int ret = vb2_reqbufs(&fimc->vid_cap.vbq, reqbufs);
+
+	if (!ret)
+		fimc->vid_cap.reqbufs_count = reqbufs->count;
+	return ret;
+}
+
+static int fimc_cap_querybuf(struct file *file, void *priv,
+			   struct v4l2_buffer *buf)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+
+	return vb2_querybuf(&fimc->vid_cap.vbq, buf);
+}
+
+static int fimc_cap_qbuf(struct file *file, void *priv,
+			  struct v4l2_buffer *buf)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+
+	return vb2_qbuf(&fimc->vid_cap.vbq, buf);
+}
+
+static int fimc_cap_dqbuf(struct file *file, void *priv,
+			   struct v4l2_buffer *buf)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+
+	return vb2_dqbuf(&fimc->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK);
+}
+
+static int fimc_cap_create_bufs(struct file *file, void *priv,
+				struct v4l2_create_buffers *create)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+
+	return vb2_create_bufs(&fimc->vid_cap.vbq, create);
+}
+
+static int fimc_cap_prepare_buf(struct file *file, void *priv,
+				struct v4l2_buffer *b)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+
+	return vb2_prepare_buf(&fimc->vid_cap.vbq, b);
+}
+
+static int fimc_cap_g_selection(struct file *file, void *fh,
+				struct v4l2_selection *s)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+	struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+	struct fimc_frame *f = &ctx->s_frame;
+
+	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return -EINVAL;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		f = &ctx->d_frame;
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = f->o_width;
+		s->r.height = f->o_height;
+		return 0;
+
+	case V4L2_SEL_TGT_COMPOSE:
+		f = &ctx->d_frame;
+	case V4L2_SEL_TGT_CROP:
+		s->r.left = f->offs_h;
+		s->r.top = f->offs_v;
+		s->r.width = f->width;
+		s->r.height = f->height;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
+static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
+{
+	if (a->left < b->left || a->top < b->top)
+		return 0;
+	if (a->left + a->width > b->left + b->width)
+		return 0;
+	if (a->top + a->height > b->top + b->height)
+		return 0;
+
+	return 1;
+}
+
+static int fimc_cap_s_selection(struct file *file, void *fh,
+				struct v4l2_selection *s)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+	struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+	struct v4l2_rect rect = s->r;
+	struct fimc_frame *f;
+	unsigned long flags;
+
+	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return -EINVAL;
+
+	if (s->target == V4L2_SEL_TGT_COMPOSE)
+		f = &ctx->d_frame;
+	else if (s->target == V4L2_SEL_TGT_CROP)
+		f = &ctx->s_frame;
+	else
+		return -EINVAL;
+
+	fimc_capture_try_selection(ctx, &rect, s->target);
+
+	if (s->flags & V4L2_SEL_FLAG_LE &&
+	    !enclosed_rectangle(&rect, &s->r))
+		return -ERANGE;
+
+	if (s->flags & V4L2_SEL_FLAG_GE &&
+	    !enclosed_rectangle(&s->r, &rect))
+		return -ERANGE;
+
+	s->r = rect;
+	spin_lock_irqsave(&fimc->slock, flags);
+	set_frame_crop(f, s->r.left, s->r.top, s->r.width,
+		       s->r.height);
+	spin_unlock_irqrestore(&fimc->slock, flags);
+
+	set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
+	.vidioc_querycap		= fimc_vidioc_querycap_capture,
+
+	.vidioc_enum_fmt_vid_cap_mplane	= fimc_cap_enum_fmt_mplane,
+	.vidioc_try_fmt_vid_cap_mplane	= fimc_cap_try_fmt_mplane,
+	.vidioc_s_fmt_vid_cap_mplane	= fimc_cap_s_fmt_mplane,
+	.vidioc_g_fmt_vid_cap_mplane	= fimc_cap_g_fmt_mplane,
+
+	.vidioc_reqbufs			= fimc_cap_reqbufs,
+	.vidioc_querybuf		= fimc_cap_querybuf,
+
+	.vidioc_qbuf			= fimc_cap_qbuf,
+	.vidioc_dqbuf			= fimc_cap_dqbuf,
+
+	.vidioc_prepare_buf		= fimc_cap_prepare_buf,
+	.vidioc_create_bufs		= fimc_cap_create_bufs,
+
+	.vidioc_streamon		= fimc_cap_streamon,
+	.vidioc_streamoff		= fimc_cap_streamoff,
+
+	.vidioc_g_selection		= fimc_cap_g_selection,
+	.vidioc_s_selection		= fimc_cap_s_selection,
+
+	.vidioc_enum_input		= fimc_cap_enum_input,
+	.vidioc_s_input			= fimc_cap_s_input,
+	.vidioc_g_input			= fimc_cap_g_input,
+};
+
+/* Capture subdev media entity operations */
+static int fimc_link_setup(struct media_entity *entity,
+			   const struct media_pad *local,
+			   const struct media_pad *remote, u32 flags)
+{
+	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+	struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+
+	if (media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+		return -EINVAL;
+
+	if (WARN_ON(fimc == NULL))
+		return 0;
+
+	dbg("%s --> %s, flags: 0x%x. input: 0x%x",
+	    local->entity->name, remote->entity->name, flags,
+	    fimc->vid_cap.input);
+
+	if (flags & MEDIA_LNK_FL_ENABLED) {
+		if (fimc->vid_cap.input != 0)
+			return -EBUSY;
+		fimc->vid_cap.input = sd->grp_id;
+		return 0;
+	}
+
+	fimc->vid_cap.input = 0;
+	return 0;
+}
+
+static const struct media_entity_operations fimc_sd_media_ops = {
+	.link_setup = fimc_link_setup,
+};
+
+/**
+ * fimc_sensor_notify - v4l2_device notification from a sensor subdev
+ * @sd: pointer to a subdev generating the notification
+ * @notification: the notification type, must be S5P_FIMC_TX_END_NOTIFY
+ * @arg: pointer to an u32 type integer that stores the frame payload value
+ *
+ * The End Of Frame notification sent by sensor subdev in its still capture
+ * mode. If there is only a single VSYNC generated by the sensor at the
+ * beginning of a frame transmission, FIMC does not issue the LastIrq
+ * (end of frame) interrupt. And this notification is used to complete the
+ * frame capture and returning a buffer to user-space. Subdev drivers should
+ * call this notification from their last 'End of frame capture' interrupt.
+ */
+void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification,
+			void *arg)
+{
+	struct fimc_sensor_info	*sensor;
+	struct fimc_vid_buffer *buf;
+	struct fimc_md *fmd;
+	struct fimc_dev *fimc;
+	unsigned long flags;
+
+	if (sd == NULL)
+		return;
+
+	sensor = v4l2_get_subdev_hostdata(sd);
+	fmd = entity_to_fimc_mdev(&sd->entity);
+
+	spin_lock_irqsave(&fmd->slock, flags);
+	fimc = sensor ? sensor->host : NULL;
+
+	if (fimc && arg && notification == S5P_FIMC_TX_END_NOTIFY &&
+	    test_bit(ST_CAPT_PEND, &fimc->state)) {
+		unsigned long irq_flags;
+		spin_lock_irqsave(&fimc->slock, irq_flags);
+		if (!list_empty(&fimc->vid_cap.active_buf_q)) {
+			buf = list_entry(fimc->vid_cap.active_buf_q.next,
+					 struct fimc_vid_buffer, list);
+			vb2_set_plane_payload(&buf->vb, 0, *((u32 *)arg));
+		}
+		fimc_capture_irq_handler(fimc, 1);
+		fimc_deactivate_capture(fimc);
+		spin_unlock_irqrestore(&fimc->slock, irq_flags);
+	}
+	spin_unlock_irqrestore(&fmd->slock, flags);
+}
+
+static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_fh *fh,
+				      struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct fimc_fmt *fmt;
+
+	fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, code->index);
+	if (!fmt)
+		return -EINVAL;
+	code->code = fmt->mbus_code;
+	return 0;
+}
+
+static int fimc_subdev_get_fmt(struct v4l2_subdev *sd,
+			       struct v4l2_subdev_fh *fh,
+			       struct v4l2_subdev_format *fmt)
+{
+	struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+	struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+	struct v4l2_mbus_framefmt *mf;
+	struct fimc_frame *ff;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+		fmt->format = *mf;
+		return 0;
+	}
+	mf = &fmt->format;
+	mf->colorspace = V4L2_COLORSPACE_JPEG;
+	ff = fmt->pad == FIMC_SD_PAD_SINK ? &ctx->s_frame : &ctx->d_frame;
+
+	mutex_lock(&fimc->lock);
+	/* The pixel code is same on both input and output pad */
+	if (!WARN_ON(ctx->s_frame.fmt == NULL))
+		mf->code = ctx->s_frame.fmt->mbus_code;
+	mf->width  = ff->f_width;
+	mf->height = ff->f_height;
+	mutex_unlock(&fimc->lock);
+
+	return 0;
+}
+
+static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
+			       struct v4l2_subdev_fh *fh,
+			       struct v4l2_subdev_format *fmt)
+{
+	struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *mf = &fmt->format;
+	struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+	struct fimc_frame *ff;
+	struct fimc_fmt *ffmt;
+
+	dbg("pad%d: code: 0x%x, %dx%d",
+	    fmt->pad, mf->code, mf->width, mf->height);
+
+	if (fmt->pad == FIMC_SD_PAD_SOURCE &&
+	    vb2_is_busy(&fimc->vid_cap.vbq))
+		return -EBUSY;
+
+	mutex_lock(&fimc->lock);
+	ffmt = fimc_capture_try_format(ctx, &mf->width, &mf->height,
+				       &mf->code, NULL, fmt->pad);
+	mutex_unlock(&fimc->lock);
+	mf->colorspace = V4L2_COLORSPACE_JPEG;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+		*mf = fmt->format;
+		return 0;
+	}
+	/* Update RGB Alpha control state and value range */
+	fimc_alpha_ctrl_update(ctx);
+
+	fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ffmt->color));
+
+	ff = fmt->pad == FIMC_SD_PAD_SINK ?
+		&ctx->s_frame : &ctx->d_frame;
+
+	mutex_lock(&fimc->lock);
+	set_frame_bounds(ff, mf->width, mf->height);
+	fimc->vid_cap.mf = *mf;
+	ff->fmt = ffmt;
+
+	/* Reset the crop rectangle if required. */
+	if (!(fmt->pad == FIMC_SD_PAD_SOURCE && (ctx->state & FIMC_COMPOSE)))
+		set_frame_crop(ff, 0, 0, mf->width, mf->height);
+
+	if (fmt->pad == FIMC_SD_PAD_SINK)
+		ctx->state &= ~FIMC_COMPOSE;
+	mutex_unlock(&fimc->lock);
+	return 0;
+}
+
+static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_fh *fh,
+				     struct v4l2_subdev_selection *sel)
+{
+	struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+	struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+	struct fimc_frame *f = &ctx->s_frame;
+	struct v4l2_rect *r = &sel->r;
+	struct v4l2_rect *try_sel;
+
+	if (sel->pad != FIMC_SD_PAD_SINK)
+		return -EINVAL;
+
+	mutex_lock(&fimc->lock);
+
+	switch (sel->target) {
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		f = &ctx->d_frame;
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		r->width = f->o_width;
+		r->height = f->o_height;
+		r->left = 0;
+		r->top = 0;
+		mutex_unlock(&fimc->lock);
+		return 0;
+
+	case V4L2_SEL_TGT_CROP:
+		try_sel = v4l2_subdev_get_try_crop(fh, sel->pad);
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+		try_sel = v4l2_subdev_get_try_compose(fh, sel->pad);
+		f = &ctx->d_frame;
+		break;
+	default:
+		mutex_unlock(&fimc->lock);
+		return -EINVAL;
+	}
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+		sel->r = *try_sel;
+	} else {
+		r->left = f->offs_h;
+		r->top = f->offs_v;
+		r->width = f->width;
+		r->height = f->height;
+	}
+
+	dbg("target %#x: l:%d, t:%d, %dx%d, f_w: %d, f_h: %d",
+	    sel->pad, r->left, r->top, r->width, r->height,
+	    f->f_width, f->f_height);
+
+	mutex_unlock(&fimc->lock);
+	return 0;
+}
+
+static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_fh *fh,
+				     struct v4l2_subdev_selection *sel)
+{
+	struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+	struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+	struct fimc_frame *f = &ctx->s_frame;
+	struct v4l2_rect *r = &sel->r;
+	struct v4l2_rect *try_sel;
+	unsigned long flags;
+
+	if (sel->pad != FIMC_SD_PAD_SINK)
+		return -EINVAL;
+
+	mutex_lock(&fimc->lock);
+	fimc_capture_try_selection(ctx, r, V4L2_SEL_TGT_CROP);
+
+	switch (sel->target) {
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		f = &ctx->d_frame;
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		r->width = f->o_width;
+		r->height = f->o_height;
+		r->left = 0;
+		r->top = 0;
+		mutex_unlock(&fimc->lock);
+		return 0;
+
+	case V4L2_SEL_TGT_CROP:
+		try_sel = v4l2_subdev_get_try_crop(fh, sel->pad);
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+		try_sel = v4l2_subdev_get_try_compose(fh, sel->pad);
+		f = &ctx->d_frame;
+		break;
+	default:
+		mutex_unlock(&fimc->lock);
+		return -EINVAL;
+	}
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+		*try_sel = sel->r;
+	} else {
+		spin_lock_irqsave(&fimc->slock, flags);
+		set_frame_crop(f, r->left, r->top, r->width, r->height);
+		set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
+		spin_unlock_irqrestore(&fimc->slock, flags);
+		if (sel->target == V4L2_SEL_TGT_COMPOSE)
+			ctx->state |= FIMC_COMPOSE;
+	}
+
+	dbg("target %#x: (%d,%d)/%dx%d", sel->target, r->left, r->top,
+	    r->width, r->height);
+
+	mutex_unlock(&fimc->lock);
+	return 0;
+}
+
+static struct v4l2_subdev_pad_ops fimc_subdev_pad_ops = {
+	.enum_mbus_code = fimc_subdev_enum_mbus_code,
+	.get_selection = fimc_subdev_get_selection,
+	.set_selection = fimc_subdev_set_selection,
+	.get_fmt = fimc_subdev_get_fmt,
+	.set_fmt = fimc_subdev_set_fmt,
+};
+
+static struct v4l2_subdev_ops fimc_subdev_ops = {
+	.pad = &fimc_subdev_pad_ops,
+};
+
+/* Set default format at the sensor and host interface */
+static int fimc_capture_set_default_format(struct fimc_dev *fimc)
+{
+	struct v4l2_format fmt = {
+		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+		.fmt.pix_mp = {
+			.width		= 640,
+			.height		= 480,
+			.pixelformat	= V4L2_PIX_FMT_YUYV,
+			.field		= V4L2_FIELD_NONE,
+			.colorspace	= V4L2_COLORSPACE_JPEG,
+		},
+	};
+
+	return fimc_capture_set_format(fimc, &fmt);
+}
+
+/* fimc->lock must be already initialized */
+static int fimc_register_capture_device(struct fimc_dev *fimc,
+				 struct v4l2_device *v4l2_dev)
+{
+	struct video_device *vfd;
+	struct fimc_vid_cap *vid_cap;
+	struct fimc_ctx *ctx;
+	struct vb2_queue *q;
+	int ret = -ENOMEM;
+
+	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->fimc_dev	 = fimc;
+	ctx->in_path	 = FIMC_IO_CAMERA;
+	ctx->out_path	 = FIMC_IO_DMA;
+	ctx->state	 = FIMC_CTX_CAP;
+	ctx->s_frame.fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0);
+	ctx->d_frame.fmt = ctx->s_frame.fmt;
+
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(v4l2_dev, "Failed to allocate video device\n");
+		goto err_vd_alloc;
+	}
+
+	snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.capture", fimc->id);
+
+	vfd->fops	= &fimc_capture_fops;
+	vfd->ioctl_ops	= &fimc_capture_ioctl_ops;
+	vfd->v4l2_dev	= v4l2_dev;
+	vfd->minor	= -1;
+	vfd->release	= video_device_release;
+	vfd->lock	= &fimc->lock;
+
+	video_set_drvdata(vfd, fimc);
+
+	vid_cap = &fimc->vid_cap;
+	vid_cap->vfd = vfd;
+	vid_cap->active_buf_cnt = 0;
+	vid_cap->reqbufs_count  = 0;
+	vid_cap->refcnt = 0;
+
+	INIT_LIST_HEAD(&vid_cap->pending_buf_q);
+	INIT_LIST_HEAD(&vid_cap->active_buf_q);
+	vid_cap->ctx = ctx;
+
+	q = &fimc->vid_cap.vbq;
+	memset(q, 0, sizeof(*q));
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	q->io_modes = VB2_MMAP | VB2_USERPTR;
+	q->drv_priv = fimc->vid_cap.ctx;
+	q->ops = &fimc_capture_qops;
+	q->mem_ops = &vb2_dma_contig_memops;
+	q->buf_struct_size = sizeof(struct fimc_vid_buffer);
+
+	vb2_queue_init(q);
+
+	vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK;
+	ret = media_entity_init(&vfd->entity, 1, &vid_cap->vd_pad, 0);
+	if (ret)
+		goto err_ent;
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+	if (ret)
+		goto err_vd;
+
+	v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",
+		  vfd->name, video_device_node_name(vfd));
+
+	vfd->ctrl_handler = &ctx->ctrls.handler;
+	return 0;
+
+err_vd:
+	media_entity_cleanup(&vfd->entity);
+err_ent:
+	video_device_release(vfd);
+err_vd_alloc:
+	kfree(ctx);
+	return ret;
+}
+
+static int fimc_capture_subdev_registered(struct v4l2_subdev *sd)
+{
+	struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+	int ret;
+
+	ret = fimc_register_m2m_device(fimc, sd->v4l2_dev);
+	if (ret)
+		return ret;
+
+	ret = fimc_register_capture_device(fimc, sd->v4l2_dev);
+	if (ret)
+		fimc_unregister_m2m_device(fimc);
+
+	return ret;
+}
+
+static void fimc_capture_subdev_unregistered(struct v4l2_subdev *sd)
+{
+	struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+
+	if (fimc == NULL)
+		return;
+
+	fimc_unregister_m2m_device(fimc);
+
+	if (fimc->vid_cap.vfd) {
+		media_entity_cleanup(&fimc->vid_cap.vfd->entity);
+		video_unregister_device(fimc->vid_cap.vfd);
+		fimc->vid_cap.vfd = NULL;
+	}
+
+	kfree(fimc->vid_cap.ctx);
+	fimc->vid_cap.ctx = NULL;
+}
+
+static const struct v4l2_subdev_internal_ops fimc_capture_sd_internal_ops = {
+	.registered = fimc_capture_subdev_registered,
+	.unregistered = fimc_capture_subdev_unregistered,
+};
+
+int fimc_initialize_capture_subdev(struct fimc_dev *fimc)
+{
+	struct v4l2_subdev *sd = &fimc->vid_cap.subdev;
+	int ret;
+
+	v4l2_subdev_init(sd, &fimc_subdev_ops);
+	sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->pdev->id);
+
+	fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM,
+				fimc->vid_cap.sd_pads, 0);
+	if (ret)
+		return ret;
+
+	sd->entity.ops = &fimc_sd_media_ops;
+	sd->internal_ops = &fimc_capture_sd_internal_ops;
+	v4l2_set_subdevdata(sd, fimc);
+	return 0;
+}
+
+void fimc_unregister_capture_subdev(struct fimc_dev *fimc)
+{
+	struct v4l2_subdev *sd = &fimc->vid_cap.subdev;
+
+	v4l2_device_unregister_subdev(sd);
+	media_entity_cleanup(&sd->entity);
+	v4l2_set_subdevdata(sd, NULL);
+}
diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c
new file mode 100644
index 0000000..1a44540
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-core.c
@@ -0,0 +1,1239 @@
+/*
+ * Samsung S5P/EXYNOS4 SoC series FIMC (CAMIF) driver
+ *
+ * Copyright (C) 2010-2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 2 of the License,
+ * or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "fimc-core.h"
+#include "fimc-reg.h"
+#include "fimc-mdevice.h"
+
+static char *fimc_clocks[MAX_FIMC_CLOCKS] = {
+	"sclk_fimc", "fimc"
+};
+
+static struct fimc_fmt fimc_formats[] = {
+	{
+		.name		= "RGB565",
+		.fourcc		= V4L2_PIX_FMT_RGB565,
+		.depth		= { 16 },
+		.color		= FIMC_FMT_RGB565,
+		.memplanes	= 1,
+		.colplanes	= 1,
+		.flags		= FMT_FLAGS_M2M,
+	}, {
+		.name		= "BGR666",
+		.fourcc		= V4L2_PIX_FMT_BGR666,
+		.depth		= { 32 },
+		.color		= FIMC_FMT_RGB666,
+		.memplanes	= 1,
+		.colplanes	= 1,
+		.flags		= FMT_FLAGS_M2M,
+	}, {
+		.name		= "ARGB8888, 32 bpp",
+		.fourcc		= V4L2_PIX_FMT_RGB32,
+		.depth		= { 32 },
+		.color		= FIMC_FMT_RGB888,
+		.memplanes	= 1,
+		.colplanes	= 1,
+		.flags		= FMT_FLAGS_M2M | FMT_HAS_ALPHA,
+	}, {
+		.name		= "ARGB1555",
+		.fourcc		= V4L2_PIX_FMT_RGB555,
+		.depth		= { 16 },
+		.color		= FIMC_FMT_RGB555,
+		.memplanes	= 1,
+		.colplanes	= 1,
+		.flags		= FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
+	}, {
+		.name		= "ARGB4444",
+		.fourcc		= V4L2_PIX_FMT_RGB444,
+		.depth		= { 16 },
+		.color		= FIMC_FMT_RGB444,
+		.memplanes	= 1,
+		.colplanes	= 1,
+		.flags		= FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
+	}, {
+		.name		= "YUV 4:2:2 packed, YCbYCr",
+		.fourcc		= V4L2_PIX_FMT_YUYV,
+		.depth		= { 16 },
+		.color		= FIMC_FMT_YCBYCR422,
+		.memplanes	= 1,
+		.colplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_YUYV8_2X8,
+		.flags		= FMT_FLAGS_M2M | FMT_FLAGS_CAM,
+	}, {
+		.name		= "YUV 4:2:2 packed, CbYCrY",
+		.fourcc		= V4L2_PIX_FMT_UYVY,
+		.depth		= { 16 },
+		.color		= FIMC_FMT_CBYCRY422,
+		.memplanes	= 1,
+		.colplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_UYVY8_2X8,
+		.flags		= FMT_FLAGS_M2M | FMT_FLAGS_CAM,
+	}, {
+		.name		= "YUV 4:2:2 packed, CrYCbY",
+		.fourcc		= V4L2_PIX_FMT_VYUY,
+		.depth		= { 16 },
+		.color		= FIMC_FMT_CRYCBY422,
+		.memplanes	= 1,
+		.colplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_VYUY8_2X8,
+		.flags		= FMT_FLAGS_M2M | FMT_FLAGS_CAM,
+	}, {
+		.name		= "YUV 4:2:2 packed, YCrYCb",
+		.fourcc		= V4L2_PIX_FMT_YVYU,
+		.depth		= { 16 },
+		.color		= FIMC_FMT_YCRYCB422,
+		.memplanes	= 1,
+		.colplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_YVYU8_2X8,
+		.flags		= FMT_FLAGS_M2M | FMT_FLAGS_CAM,
+	}, {
+		.name		= "YUV 4:2:2 planar, Y/Cb/Cr",
+		.fourcc		= V4L2_PIX_FMT_YUV422P,
+		.depth		= { 12 },
+		.color		= FIMC_FMT_YCBYCR422,
+		.memplanes	= 1,
+		.colplanes	= 3,
+		.flags		= FMT_FLAGS_M2M,
+	}, {
+		.name		= "YUV 4:2:2 planar, Y/CbCr",
+		.fourcc		= V4L2_PIX_FMT_NV16,
+		.depth		= { 16 },
+		.color		= FIMC_FMT_YCBYCR422,
+		.memplanes	= 1,
+		.colplanes	= 2,
+		.flags		= FMT_FLAGS_M2M,
+	}, {
+		.name		= "YUV 4:2:2 planar, Y/CrCb",
+		.fourcc		= V4L2_PIX_FMT_NV61,
+		.depth		= { 16 },
+		.color		= FIMC_FMT_YCRYCB422,
+		.memplanes	= 1,
+		.colplanes	= 2,
+		.flags		= FMT_FLAGS_M2M,
+	}, {
+		.name		= "YUV 4:2:0 planar, YCbCr",
+		.fourcc		= V4L2_PIX_FMT_YUV420,
+		.depth		= { 12 },
+		.color		= FIMC_FMT_YCBCR420,
+		.memplanes	= 1,
+		.colplanes	= 3,
+		.flags		= FMT_FLAGS_M2M,
+	}, {
+		.name		= "YUV 4:2:0 planar, Y/CbCr",
+		.fourcc		= V4L2_PIX_FMT_NV12,
+		.depth		= { 12 },
+		.color		= FIMC_FMT_YCBCR420,
+		.memplanes	= 1,
+		.colplanes	= 2,
+		.flags		= FMT_FLAGS_M2M,
+	}, {
+		.name		= "YUV 4:2:0 non-contig. 2p, Y/CbCr",
+		.fourcc		= V4L2_PIX_FMT_NV12M,
+		.color		= FIMC_FMT_YCBCR420,
+		.depth		= { 8, 4 },
+		.memplanes	= 2,
+		.colplanes	= 2,
+		.flags		= FMT_FLAGS_M2M,
+	}, {
+		.name		= "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr",
+		.fourcc		= V4L2_PIX_FMT_YUV420M,
+		.color		= FIMC_FMT_YCBCR420,
+		.depth		= { 8, 2, 2 },
+		.memplanes	= 3,
+		.colplanes	= 3,
+		.flags		= FMT_FLAGS_M2M,
+	}, {
+		.name		= "YUV 4:2:0 non-contig. 2p, tiled",
+		.fourcc		= V4L2_PIX_FMT_NV12MT,
+		.color		= FIMC_FMT_YCBCR420,
+		.depth		= { 8, 4 },
+		.memplanes	= 2,
+		.colplanes	= 2,
+		.flags		= FMT_FLAGS_M2M,
+	}, {
+		.name		= "JPEG encoded data",
+		.fourcc		= V4L2_PIX_FMT_JPEG,
+		.color		= FIMC_FMT_JPEG,
+		.depth		= { 8 },
+		.memplanes	= 1,
+		.colplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_JPEG_1X8,
+		.flags		= FMT_FLAGS_CAM,
+	},
+};
+
+struct fimc_fmt *fimc_get_format(unsigned int index)
+{
+	if (index >= ARRAY_SIZE(fimc_formats))
+		return NULL;
+
+	return &fimc_formats[index];
+}
+
+int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
+			    int dw, int dh, int rotation)
+{
+	if (rotation == 90 || rotation == 270)
+		swap(dw, dh);
+
+	if (!ctx->scaler.enabled)
+		return (sw == dw && sh == dh) ? 0 : -EINVAL;
+
+	if ((sw >= SCALER_MAX_HRATIO * dw) || (sh >= SCALER_MAX_VRATIO * dh))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
+{
+	u32 sh = 6;
+
+	if (src >= 64 * tar)
+		return -EINVAL;
+
+	while (sh--) {
+		u32 tmp = 1 << sh;
+		if (src >= tar * tmp) {
+			*shift = sh, *ratio = tmp;
+			return 0;
+		}
+	}
+	*shift = 0, *ratio = 1;
+	return 0;
+}
+
+int fimc_set_scaler_info(struct fimc_ctx *ctx)
+{
+	struct fimc_variant *variant = ctx->fimc_dev->variant;
+	struct device *dev = &ctx->fimc_dev->pdev->dev;
+	struct fimc_scaler *sc = &ctx->scaler;
+	struct fimc_frame *s_frame = &ctx->s_frame;
+	struct fimc_frame *d_frame = &ctx->d_frame;
+	int tx, ty, sx, sy;
+	int ret;
+
+	if (ctx->rotation == 90 || ctx->rotation == 270) {
+		ty = d_frame->width;
+		tx = d_frame->height;
+	} else {
+		tx = d_frame->width;
+		ty = d_frame->height;
+	}
+	if (tx <= 0 || ty <= 0) {
+		dev_err(dev, "Invalid target size: %dx%d", tx, ty);
+		return -EINVAL;
+	}
+
+	sx = s_frame->width;
+	sy = s_frame->height;
+	if (sx <= 0 || sy <= 0) {
+		dev_err(dev, "Invalid source size: %dx%d", sx, sy);
+		return -EINVAL;
+	}
+	sc->real_width = sx;
+	sc->real_height = sy;
+
+	ret = fimc_get_scaler_factor(sx, tx, &sc->pre_hratio, &sc->hfactor);
+	if (ret)
+		return ret;
+
+	ret = fimc_get_scaler_factor(sy, ty,  &sc->pre_vratio, &sc->vfactor);
+	if (ret)
+		return ret;
+
+	sc->pre_dst_width = sx / sc->pre_hratio;
+	sc->pre_dst_height = sy / sc->pre_vratio;
+
+	if (variant->has_mainscaler_ext) {
+		sc->main_hratio = (sx << 14) / (tx << sc->hfactor);
+		sc->main_vratio = (sy << 14) / (ty << sc->vfactor);
+	} else {
+		sc->main_hratio = (sx << 8) / (tx << sc->hfactor);
+		sc->main_vratio = (sy << 8) / (ty << sc->vfactor);
+
+	}
+
+	sc->scaleup_h = (tx >= sx) ? 1 : 0;
+	sc->scaleup_v = (ty >= sy) ? 1 : 0;
+
+	/* check to see if input and output size/format differ */
+	if (s_frame->fmt->color == d_frame->fmt->color
+		&& s_frame->width == d_frame->width
+		&& s_frame->height == d_frame->height)
+		sc->copy_mode = 1;
+	else
+		sc->copy_mode = 0;
+
+	return 0;
+}
+
+static irqreturn_t fimc_irq_handler(int irq, void *priv)
+{
+	struct fimc_dev *fimc = priv;
+	struct fimc_ctx *ctx;
+
+	fimc_hw_clear_irq(fimc);
+
+	spin_lock(&fimc->slock);
+
+	if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) {
+		if (test_and_clear_bit(ST_M2M_SUSPENDING, &fimc->state)) {
+			set_bit(ST_M2M_SUSPENDED, &fimc->state);
+			wake_up(&fimc->irq_queue);
+			goto out;
+		}
+		ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev);
+		if (ctx != NULL) {
+			spin_unlock(&fimc->slock);
+			fimc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE);
+
+			if (ctx->state & FIMC_CTX_SHUT) {
+				ctx->state &= ~FIMC_CTX_SHUT;
+				wake_up(&fimc->irq_queue);
+			}
+			return IRQ_HANDLED;
+		}
+	} else if (test_bit(ST_CAPT_PEND, &fimc->state)) {
+		int last_buf = test_bit(ST_CAPT_JPEG, &fimc->state) &&
+				fimc->vid_cap.reqbufs_count == 1;
+		fimc_capture_irq_handler(fimc, !last_buf);
+	}
+out:
+	spin_unlock(&fimc->slock);
+	return IRQ_HANDLED;
+}
+
+/* The color format (colplanes, memplanes) must be already configured. */
+int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
+		      struct fimc_frame *frame, struct fimc_addr *paddr)
+{
+	int ret = 0;
+	u32 pix_size;
+
+	if (vb == NULL || frame == NULL)
+		return -EINVAL;
+
+	pix_size = frame->width * frame->height;
+
+	dbg("memplanes= %d, colplanes= %d, pix_size= %d",
+		frame->fmt->memplanes, frame->fmt->colplanes, pix_size);
+
+	paddr->y = vb2_dma_contig_plane_dma_addr(vb, 0);
+
+	if (frame->fmt->memplanes == 1) {
+		switch (frame->fmt->colplanes) {
+		case 1:
+			paddr->cb = 0;
+			paddr->cr = 0;
+			break;
+		case 2:
+			/* decompose Y into Y/Cb */
+			paddr->cb = (u32)(paddr->y + pix_size);
+			paddr->cr = 0;
+			break;
+		case 3:
+			paddr->cb = (u32)(paddr->y + pix_size);
+			/* decompose Y into Y/Cb/Cr */
+			if (FIMC_FMT_YCBCR420 == frame->fmt->color)
+				paddr->cr = (u32)(paddr->cb
+						+ (pix_size >> 2));
+			else /* 422 */
+				paddr->cr = (u32)(paddr->cb
+						+ (pix_size >> 1));
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		if (frame->fmt->memplanes >= 2)
+			paddr->cb = vb2_dma_contig_plane_dma_addr(vb, 1);
+
+		if (frame->fmt->memplanes == 3)
+			paddr->cr = vb2_dma_contig_plane_dma_addr(vb, 2);
+	}
+
+	dbg("PHYS_ADDR: y= 0x%X  cb= 0x%X cr= 0x%X ret= %d",
+	    paddr->y, paddr->cb, paddr->cr, ret);
+
+	return ret;
+}
+
+/* Set order for 1 and 2 plane YCBCR 4:2:2 formats. */
+void fimc_set_yuv_order(struct fimc_ctx *ctx)
+{
+	/* The one only mode supported in SoC. */
+	ctx->in_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB;
+	ctx->out_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB;
+
+	/* Set order for 1 plane input formats. */
+	switch (ctx->s_frame.fmt->color) {
+	case FIMC_FMT_YCRYCB422:
+		ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CBYCRY;
+		break;
+	case FIMC_FMT_CBYCRY422:
+		ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCRYCB;
+		break;
+	case FIMC_FMT_CRYCBY422:
+		ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCBYCR;
+		break;
+	case FIMC_FMT_YCBYCR422:
+	default:
+		ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CRYCBY;
+		break;
+	}
+	dbg("ctx->in_order_1p= %d", ctx->in_order_1p);
+
+	switch (ctx->d_frame.fmt->color) {
+	case FIMC_FMT_YCRYCB422:
+		ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CBYCRY;
+		break;
+	case FIMC_FMT_CBYCRY422:
+		ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCRYCB;
+		break;
+	case FIMC_FMT_CRYCBY422:
+		ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCBYCR;
+		break;
+	case FIMC_FMT_YCBYCR422:
+	default:
+		ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CRYCBY;
+		break;
+	}
+	dbg("ctx->out_order_1p= %d", ctx->out_order_1p);
+}
+
+void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
+{
+	struct fimc_variant *variant = ctx->fimc_dev->variant;
+	u32 i, depth = 0;
+
+	for (i = 0; i < f->fmt->colplanes; i++)
+		depth += f->fmt->depth[i];
+
+	f->dma_offset.y_h = f->offs_h;
+	if (!variant->pix_hoff)
+		f->dma_offset.y_h *= (depth >> 3);
+
+	f->dma_offset.y_v = f->offs_v;
+
+	f->dma_offset.cb_h = f->offs_h;
+	f->dma_offset.cb_v = f->offs_v;
+
+	f->dma_offset.cr_h = f->offs_h;
+	f->dma_offset.cr_v = f->offs_v;
+
+	if (!variant->pix_hoff) {
+		if (f->fmt->colplanes == 3) {
+			f->dma_offset.cb_h >>= 1;
+			f->dma_offset.cr_h >>= 1;
+		}
+		if (f->fmt->color == FIMC_FMT_YCBCR420) {
+			f->dma_offset.cb_v >>= 1;
+			f->dma_offset.cr_v >>= 1;
+		}
+	}
+
+	dbg("in_offset: color= %d, y_h= %d, y_v= %d",
+	    f->fmt->color, f->dma_offset.y_h, f->dma_offset.y_v);
+}
+
+static int fimc_set_color_effect(struct fimc_ctx *ctx, enum v4l2_colorfx colorfx)
+{
+	struct fimc_effect *effect = &ctx->effect;
+
+	switch (colorfx) {
+	case V4L2_COLORFX_NONE:
+		effect->type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
+		break;
+	case V4L2_COLORFX_BW:
+		effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
+		effect->pat_cb = 128;
+		effect->pat_cr = 128;
+		break;
+	case V4L2_COLORFX_SEPIA:
+		effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
+		effect->pat_cb = 115;
+		effect->pat_cr = 145;
+		break;
+	case V4L2_COLORFX_NEGATIVE:
+		effect->type = FIMC_REG_CIIMGEFF_FIN_NEGATIVE;
+		break;
+	case V4L2_COLORFX_EMBOSS:
+		effect->type = FIMC_REG_CIIMGEFF_FIN_EMBOSSING;
+		break;
+	case V4L2_COLORFX_ART_FREEZE:
+		effect->type = FIMC_REG_CIIMGEFF_FIN_ARTFREEZE;
+		break;
+	case V4L2_COLORFX_SILHOUETTE:
+		effect->type = FIMC_REG_CIIMGEFF_FIN_SILHOUETTE;
+		break;
+	case V4L2_COLORFX_SET_CBCR:
+		effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
+		effect->pat_cb = ctx->ctrls.colorfx_cbcr->val >> 8;
+		effect->pat_cr = ctx->ctrls.colorfx_cbcr->val & 0xff;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * V4L2 controls handling
+ */
+#define ctrl_to_ctx(__ctrl) \
+	container_of((__ctrl)->handler, struct fimc_ctx, ctrls.handler)
+
+static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	struct fimc_variant *variant = fimc->variant;
+	unsigned int flags = FIMC_DST_FMT | FIMC_SRC_FMT;
+	int ret = 0;
+
+	if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_HFLIP:
+		ctx->hflip = ctrl->val;
+		break;
+
+	case V4L2_CID_VFLIP:
+		ctx->vflip = ctrl->val;
+		break;
+
+	case V4L2_CID_ROTATE:
+		if (fimc_capture_pending(fimc) ||
+		    (ctx->state & flags) == flags) {
+			ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
+					ctx->s_frame.height, ctx->d_frame.width,
+					ctx->d_frame.height, ctrl->val);
+			if (ret)
+				return -EINVAL;
+		}
+		if ((ctrl->val == 90 || ctrl->val == 270) &&
+		    !variant->has_out_rot)
+			return -EINVAL;
+
+		ctx->rotation = ctrl->val;
+		break;
+
+	case V4L2_CID_ALPHA_COMPONENT:
+		ctx->d_frame.alpha = ctrl->val;
+		break;
+
+	case V4L2_CID_COLORFX:
+		ret = fimc_set_color_effect(ctx, ctrl->val);
+		if (ret)
+			return ret;
+		break;
+	}
+
+	ctx->state |= FIMC_PARAMS;
+	set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
+	return 0;
+}
+
+static int fimc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct fimc_ctx *ctx = ctrl_to_ctx(ctrl);
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&ctx->fimc_dev->slock, flags);
+	ret = __fimc_s_ctrl(ctx, ctrl);
+	spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags);
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops fimc_ctrl_ops = {
+	.s_ctrl = fimc_s_ctrl,
+};
+
+int fimc_ctrls_create(struct fimc_ctx *ctx)
+{
+	struct fimc_variant *variant = ctx->fimc_dev->variant;
+	unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt);
+	struct fimc_ctrls *ctrls = &ctx->ctrls;
+	struct v4l2_ctrl_handler *handler = &ctrls->handler;
+
+	if (ctx->ctrls.ready)
+		return 0;
+
+	v4l2_ctrl_handler_init(handler, 6);
+
+	ctrls->rotate = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
+					V4L2_CID_ROTATE, 0, 270, 90, 0);
+	ctrls->hflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
+					V4L2_CID_HFLIP, 0, 1, 1, 0);
+	ctrls->vflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
+					V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+	if (variant->has_alpha)
+		ctrls->alpha = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
+					V4L2_CID_ALPHA_COMPONENT,
+					0, max_alpha, 1, 0);
+	else
+		ctrls->alpha = NULL;
+
+	ctrls->colorfx = v4l2_ctrl_new_std_menu(handler, &fimc_ctrl_ops,
+				V4L2_CID_COLORFX, V4L2_COLORFX_SET_CBCR,
+				~0x983f, V4L2_COLORFX_NONE);
+
+	ctrls->colorfx_cbcr = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
+				V4L2_CID_COLORFX_CBCR, 0, 0xffff, 1, 0);
+
+	ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
+
+	if (!handler->error) {
+		v4l2_ctrl_cluster(2, &ctrls->colorfx);
+		ctrls->ready = true;
+	}
+
+	return handler->error;
+}
+
+void fimc_ctrls_delete(struct fimc_ctx *ctx)
+{
+	struct fimc_ctrls *ctrls = &ctx->ctrls;
+
+	if (ctrls->ready) {
+		v4l2_ctrl_handler_free(&ctrls->handler);
+		ctrls->ready = false;
+		ctrls->alpha = NULL;
+	}
+}
+
+void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
+{
+	unsigned int has_alpha = ctx->d_frame.fmt->flags & FMT_HAS_ALPHA;
+	struct fimc_ctrls *ctrls = &ctx->ctrls;
+
+	if (!ctrls->ready)
+		return;
+
+	mutex_lock(ctrls->handler.lock);
+	v4l2_ctrl_activate(ctrls->rotate, active);
+	v4l2_ctrl_activate(ctrls->hflip, active);
+	v4l2_ctrl_activate(ctrls->vflip, active);
+	v4l2_ctrl_activate(ctrls->colorfx, active);
+	if (ctrls->alpha)
+		v4l2_ctrl_activate(ctrls->alpha, active && has_alpha);
+
+	if (active) {
+		fimc_set_color_effect(ctx, ctrls->colorfx->cur.val);
+		ctx->rotation = ctrls->rotate->val;
+		ctx->hflip    = ctrls->hflip->val;
+		ctx->vflip    = ctrls->vflip->val;
+	} else {
+		ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
+		ctx->rotation = 0;
+		ctx->hflip    = 0;
+		ctx->vflip    = 0;
+	}
+	mutex_unlock(ctrls->handler.lock);
+}
+
+/* Update maximum value of the alpha color control */
+void fimc_alpha_ctrl_update(struct fimc_ctx *ctx)
+{
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	struct v4l2_ctrl *ctrl = ctx->ctrls.alpha;
+
+	if (ctrl == NULL || !fimc->variant->has_alpha)
+		return;
+
+	v4l2_ctrl_lock(ctrl);
+	ctrl->maximum = fimc_get_alpha_mask(ctx->d_frame.fmt);
+
+	if (ctrl->cur.val > ctrl->maximum)
+		ctrl->cur.val = ctrl->maximum;
+
+	v4l2_ctrl_unlock(ctrl);
+}
+
+int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f)
+{
+	struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
+	int i;
+
+	pixm->width = frame->o_width;
+	pixm->height = frame->o_height;
+	pixm->field = V4L2_FIELD_NONE;
+	pixm->pixelformat = frame->fmt->fourcc;
+	pixm->colorspace = V4L2_COLORSPACE_JPEG;
+	pixm->num_planes = frame->fmt->memplanes;
+
+	for (i = 0; i < pixm->num_planes; ++i) {
+		int bpl = frame->f_width;
+		if (frame->fmt->colplanes == 1) /* packed formats */
+			bpl = (bpl * frame->fmt->depth[0]) / 8;
+		pixm->plane_fmt[i].bytesperline = bpl;
+		pixm->plane_fmt[i].sizeimage = (frame->o_width *
+			frame->o_height * frame->fmt->depth[i]) / 8;
+	}
+	return 0;
+}
+
+void fimc_fill_frame(struct fimc_frame *frame, struct v4l2_format *f)
+{
+	struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
+
+	frame->f_width  = pixm->plane_fmt[0].bytesperline;
+	if (frame->fmt->colplanes == 1)
+		frame->f_width = (frame->f_width * 8) / frame->fmt->depth[0];
+	frame->f_height	= pixm->height;
+	frame->width    = pixm->width;
+	frame->height   = pixm->height;
+	frame->o_width  = pixm->width;
+	frame->o_height = pixm->height;
+	frame->offs_h   = 0;
+	frame->offs_v   = 0;
+}
+
+/**
+ * fimc_adjust_mplane_format - adjust bytesperline/sizeimage for each plane
+ * @fmt: fimc pixel format description (input)
+ * @width: requested pixel width
+ * @height: requested pixel height
+ * @pix: multi-plane format to adjust
+ */
+void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
+			       struct v4l2_pix_format_mplane *pix)
+{
+	u32 bytesperline = 0;
+	int i;
+
+	pix->colorspace	= V4L2_COLORSPACE_JPEG;
+	pix->field = V4L2_FIELD_NONE;
+	pix->num_planes = fmt->memplanes;
+	pix->pixelformat = fmt->fourcc;
+	pix->height = height;
+	pix->width = width;
+
+	for (i = 0; i < pix->num_planes; ++i) {
+		struct v4l2_plane_pix_format *plane_fmt = &pix->plane_fmt[i];
+		u32 bpl = plane_fmt->bytesperline;
+
+		if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width))
+			bpl = pix->width; /* Planar */
+
+		if (fmt->colplanes == 1 && /* Packed */
+		    (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width))
+			bpl = (pix->width * fmt->depth[0]) / 8;
+
+		if (i == 0) /* Same bytesperline for each plane. */
+			bytesperline = bpl;
+
+		plane_fmt->bytesperline = bytesperline;
+		plane_fmt->sizeimage = max((pix->width * pix->height *
+				   fmt->depth[i]) / 8, plane_fmt->sizeimage);
+	}
+}
+
+/**
+ * fimc_find_format - lookup fimc color format by fourcc or media bus format
+ * @pixelformat: fourcc to match, ignored if null
+ * @mbus_code: media bus code to match, ignored if null
+ * @mask: the color flags to match
+ * @index: offset in the fimc_formats array, ignored if negative
+ */
+struct fimc_fmt *fimc_find_format(const u32 *pixelformat, const u32 *mbus_code,
+				  unsigned int mask, int index)
+{
+	struct fimc_fmt *fmt, *def_fmt = NULL;
+	unsigned int i;
+	int id = 0;
+
+	if (index >= (int)ARRAY_SIZE(fimc_formats))
+		return NULL;
+
+	for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
+		fmt = &fimc_formats[i];
+		if (!(fmt->flags & mask))
+			continue;
+		if (pixelformat && fmt->fourcc == *pixelformat)
+			return fmt;
+		if (mbus_code && fmt->mbus_code == *mbus_code)
+			return fmt;
+		if (index == id)
+			def_fmt = fmt;
+		id++;
+	}
+	return def_fmt;
+}
+
+static void fimc_clk_put(struct fimc_dev *fimc)
+{
+	int i;
+	for (i = 0; i < MAX_FIMC_CLOCKS; i++) {
+		if (IS_ERR_OR_NULL(fimc->clock[i]))
+			continue;
+		clk_unprepare(fimc->clock[i]);
+		clk_put(fimc->clock[i]);
+		fimc->clock[i] = NULL;
+	}
+}
+
+static int fimc_clk_get(struct fimc_dev *fimc)
+{
+	int i, ret;
+
+	for (i = 0; i < MAX_FIMC_CLOCKS; i++) {
+		fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]);
+		if (IS_ERR(fimc->clock[i]))
+			goto err;
+		ret = clk_prepare(fimc->clock[i]);
+		if (ret < 0) {
+			clk_put(fimc->clock[i]);
+			fimc->clock[i] = NULL;
+			goto err;
+		}
+	}
+	return 0;
+err:
+	fimc_clk_put(fimc);
+	dev_err(&fimc->pdev->dev, "failed to get clock: %s\n",
+		fimc_clocks[i]);
+	return -ENXIO;
+}
+
+static int fimc_m2m_suspend(struct fimc_dev *fimc)
+{
+	unsigned long flags;
+	int timeout;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	if (!fimc_m2m_pending(fimc)) {
+		spin_unlock_irqrestore(&fimc->slock, flags);
+		return 0;
+	}
+	clear_bit(ST_M2M_SUSPENDED, &fimc->state);
+	set_bit(ST_M2M_SUSPENDING, &fimc->state);
+	spin_unlock_irqrestore(&fimc->slock, flags);
+
+	timeout = wait_event_timeout(fimc->irq_queue,
+			     test_bit(ST_M2M_SUSPENDED, &fimc->state),
+			     FIMC_SHUTDOWN_TIMEOUT);
+
+	clear_bit(ST_M2M_SUSPENDING, &fimc->state);
+	return timeout == 0 ? -EAGAIN : 0;
+}
+
+static int fimc_m2m_resume(struct fimc_dev *fimc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	/* Clear for full H/W setup in first run after resume */
+	fimc->m2m.ctx = NULL;
+	spin_unlock_irqrestore(&fimc->slock, flags);
+
+	if (test_and_clear_bit(ST_M2M_SUSPENDED, &fimc->state))
+		fimc_m2m_job_finish(fimc->m2m.ctx,
+				    VB2_BUF_STATE_ERROR);
+	return 0;
+}
+
+static int fimc_probe(struct platform_device *pdev)
+{
+	struct fimc_drvdata *drv_data = fimc_get_drvdata(pdev);
+	struct s5p_platform_fimc *pdata;
+	struct fimc_dev *fimc;
+	struct resource *res;
+	int ret = 0;
+
+	if (pdev->id >= drv_data->num_entities) {
+		dev_err(&pdev->dev, "Invalid platform device id: %d\n",
+			pdev->id);
+		return -EINVAL;
+	}
+
+	fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL);
+	if (!fimc)
+		return -ENOMEM;
+
+	fimc->id = pdev->id;
+
+	fimc->variant = drv_data->variant[fimc->id];
+	fimc->pdev = pdev;
+	pdata = pdev->dev.platform_data;
+	fimc->pdata = pdata;
+
+	init_waitqueue_head(&fimc->irq_queue);
+	spin_lock_init(&fimc->slock);
+	mutex_init(&fimc->lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	fimc->regs = devm_request_and_ioremap(&pdev->dev, res);
+	if (fimc->regs == NULL) {
+		dev_err(&pdev->dev, "Failed to obtain io memory\n");
+		return -ENOENT;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "Failed to get IRQ resource\n");
+		return -ENXIO;
+	}
+
+	ret = fimc_clk_get(fimc);
+	if (ret)
+		return ret;
+	clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency);
+	clk_enable(fimc->clock[CLK_BUS]);
+
+	ret = devm_request_irq(&pdev->dev, res->start, fimc_irq_handler,
+			       0, dev_name(&pdev->dev), fimc);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to install irq (%d)\n", ret);
+		goto err_clk;
+	}
+
+	ret = fimc_initialize_capture_subdev(fimc);
+	if (ret)
+		goto err_clk;
+
+	platform_set_drvdata(pdev, fimc);
+	pm_runtime_enable(&pdev->dev);
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (ret < 0)
+		goto err_sd;
+	/* Initialize contiguous memory allocator */
+	fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+	if (IS_ERR(fimc->alloc_ctx)) {
+		ret = PTR_ERR(fimc->alloc_ctx);
+		goto err_pm;
+	}
+
+	dev_dbg(&pdev->dev, "FIMC.%d registered successfully\n", fimc->id);
+
+	pm_runtime_put(&pdev->dev);
+	return 0;
+err_pm:
+	pm_runtime_put(&pdev->dev);
+err_sd:
+	fimc_unregister_capture_subdev(fimc);
+err_clk:
+	fimc_clk_put(fimc);
+	return ret;
+}
+
+static int fimc_runtime_resume(struct device *dev)
+{
+	struct fimc_dev *fimc =	dev_get_drvdata(dev);
+
+	dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
+
+	/* Enable clocks and perform basic initalization */
+	clk_enable(fimc->clock[CLK_GATE]);
+	fimc_hw_reset(fimc);
+
+	/* Resume the capture or mem-to-mem device */
+	if (fimc_capture_busy(fimc))
+		return fimc_capture_resume(fimc);
+
+	return fimc_m2m_resume(fimc);
+}
+
+static int fimc_runtime_suspend(struct device *dev)
+{
+	struct fimc_dev *fimc =	dev_get_drvdata(dev);
+	int ret = 0;
+
+	if (fimc_capture_busy(fimc))
+		ret = fimc_capture_suspend(fimc);
+	else
+		ret = fimc_m2m_suspend(fimc);
+	if (!ret)
+		clk_disable(fimc->clock[CLK_GATE]);
+
+	dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
+	return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int fimc_resume(struct device *dev)
+{
+	struct fimc_dev *fimc =	dev_get_drvdata(dev);
+	unsigned long flags;
+
+	dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
+
+	/* Do not resume if the device was idle before system suspend */
+	spin_lock_irqsave(&fimc->slock, flags);
+	if (!test_and_clear_bit(ST_LPM, &fimc->state) ||
+	    (!fimc_m2m_active(fimc) && !fimc_capture_busy(fimc))) {
+		spin_unlock_irqrestore(&fimc->slock, flags);
+		return 0;
+	}
+	fimc_hw_reset(fimc);
+	spin_unlock_irqrestore(&fimc->slock, flags);
+
+	if (fimc_capture_busy(fimc))
+		return fimc_capture_resume(fimc);
+
+	return fimc_m2m_resume(fimc);
+}
+
+static int fimc_suspend(struct device *dev)
+{
+	struct fimc_dev *fimc =	dev_get_drvdata(dev);
+
+	dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
+
+	if (test_and_set_bit(ST_LPM, &fimc->state))
+		return 0;
+	if (fimc_capture_busy(fimc))
+		return fimc_capture_suspend(fimc);
+
+	return fimc_m2m_suspend(fimc);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static int __devexit fimc_remove(struct platform_device *pdev)
+{
+	struct fimc_dev *fimc = platform_get_drvdata(pdev);
+
+	pm_runtime_disable(&pdev->dev);
+	pm_runtime_set_suspended(&pdev->dev);
+
+	fimc_unregister_capture_subdev(fimc);
+	vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx);
+
+	clk_disable(fimc->clock[CLK_BUS]);
+	fimc_clk_put(fimc);
+
+	dev_info(&pdev->dev, "driver unloaded\n");
+	return 0;
+}
+
+/* Image pixel limits, similar across several FIMC HW revisions. */
+static struct fimc_pix_limit s5p_pix_limit[4] = {
+	[0] = {
+		.scaler_en_w	= 3264,
+		.scaler_dis_w	= 8192,
+		.in_rot_en_h	= 1920,
+		.in_rot_dis_w	= 8192,
+		.out_rot_en_w	= 1920,
+		.out_rot_dis_w	= 4224,
+	},
+	[1] = {
+		.scaler_en_w	= 4224,
+		.scaler_dis_w	= 8192,
+		.in_rot_en_h	= 1920,
+		.in_rot_dis_w	= 8192,
+		.out_rot_en_w	= 1920,
+		.out_rot_dis_w	= 4224,
+	},
+	[2] = {
+		.scaler_en_w	= 1920,
+		.scaler_dis_w	= 8192,
+		.in_rot_en_h	= 1280,
+		.in_rot_dis_w	= 8192,
+		.out_rot_en_w	= 1280,
+		.out_rot_dis_w	= 1920,
+	},
+	[3] = {
+		.scaler_en_w	= 1920,
+		.scaler_dis_w	= 8192,
+		.in_rot_en_h	= 1366,
+		.in_rot_dis_w	= 8192,
+		.out_rot_en_w	= 1366,
+		.out_rot_dis_w	= 1920,
+	},
+};
+
+static struct fimc_variant fimc0_variant_s5p = {
+	.has_inp_rot	 = 1,
+	.has_out_rot	 = 1,
+	.has_cam_if	 = 1,
+	.min_inp_pixsize = 16,
+	.min_out_pixsize = 16,
+	.hor_offs_align	 = 8,
+	.min_vsize_align = 16,
+	.out_buf_count	 = 4,
+	.pix_limit	 = &s5p_pix_limit[0],
+};
+
+static struct fimc_variant fimc2_variant_s5p = {
+	.has_cam_if	 = 1,
+	.min_inp_pixsize = 16,
+	.min_out_pixsize = 16,
+	.hor_offs_align	 = 8,
+	.min_vsize_align = 16,
+	.out_buf_count	 = 4,
+	.pix_limit	 = &s5p_pix_limit[1],
+};
+
+static struct fimc_variant fimc0_variant_s5pv210 = {
+	.pix_hoff	 = 1,
+	.has_inp_rot	 = 1,
+	.has_out_rot	 = 1,
+	.has_cam_if	 = 1,
+	.min_inp_pixsize = 16,
+	.min_out_pixsize = 16,
+	.hor_offs_align	 = 8,
+	.min_vsize_align = 16,
+	.out_buf_count	 = 4,
+	.pix_limit	 = &s5p_pix_limit[1],
+};
+
+static struct fimc_variant fimc1_variant_s5pv210 = {
+	.pix_hoff	 = 1,
+	.has_inp_rot	 = 1,
+	.has_out_rot	 = 1,
+	.has_cam_if	 = 1,
+	.has_mainscaler_ext = 1,
+	.min_inp_pixsize = 16,
+	.min_out_pixsize = 16,
+	.hor_offs_align	 = 1,
+	.min_vsize_align = 1,
+	.out_buf_count	 = 4,
+	.pix_limit	 = &s5p_pix_limit[2],
+};
+
+static struct fimc_variant fimc2_variant_s5pv210 = {
+	.has_cam_if	 = 1,
+	.pix_hoff	 = 1,
+	.min_inp_pixsize = 16,
+	.min_out_pixsize = 16,
+	.hor_offs_align	 = 8,
+	.min_vsize_align = 16,
+	.out_buf_count	 = 4,
+	.pix_limit	 = &s5p_pix_limit[2],
+};
+
+static struct fimc_variant fimc0_variant_exynos4 = {
+	.pix_hoff	 = 1,
+	.has_inp_rot	 = 1,
+	.has_out_rot	 = 1,
+	.has_cam_if	 = 1,
+	.has_cistatus2	 = 1,
+	.has_mainscaler_ext = 1,
+	.has_alpha	 = 1,
+	.min_inp_pixsize = 16,
+	.min_out_pixsize = 16,
+	.hor_offs_align	 = 2,
+	.min_vsize_align = 1,
+	.out_buf_count	 = 32,
+	.pix_limit	 = &s5p_pix_limit[1],
+};
+
+static struct fimc_variant fimc3_variant_exynos4 = {
+	.pix_hoff	 = 1,
+	.has_cam_if	 = 1,
+	.has_cistatus2	 = 1,
+	.has_mainscaler_ext = 1,
+	.has_alpha	 = 1,
+	.min_inp_pixsize = 16,
+	.min_out_pixsize = 16,
+	.hor_offs_align	 = 2,
+	.min_vsize_align = 1,
+	.out_buf_count	 = 32,
+	.pix_limit	 = &s5p_pix_limit[3],
+};
+
+/* S5PC100 */
+static struct fimc_drvdata fimc_drvdata_s5p = {
+	.variant = {
+		[0] = &fimc0_variant_s5p,
+		[1] = &fimc0_variant_s5p,
+		[2] = &fimc2_variant_s5p,
+	},
+	.num_entities = 3,
+	.lclk_frequency = 133000000UL,
+};
+
+/* S5PV210, S5PC110 */
+static struct fimc_drvdata fimc_drvdata_s5pv210 = {
+	.variant = {
+		[0] = &fimc0_variant_s5pv210,
+		[1] = &fimc1_variant_s5pv210,
+		[2] = &fimc2_variant_s5pv210,
+	},
+	.num_entities = 3,
+	.lclk_frequency = 166000000UL,
+};
+
+/* EXYNOS4210, S5PV310, S5PC210 */
+static struct fimc_drvdata fimc_drvdata_exynos4 = {
+	.variant = {
+		[0] = &fimc0_variant_exynos4,
+		[1] = &fimc0_variant_exynos4,
+		[2] = &fimc0_variant_exynos4,
+		[3] = &fimc3_variant_exynos4,
+	},
+	.num_entities = 4,
+	.lclk_frequency = 166000000UL,
+};
+
+static struct platform_device_id fimc_driver_ids[] = {
+	{
+		.name		= "s5p-fimc",
+		.driver_data	= (unsigned long)&fimc_drvdata_s5p,
+	}, {
+		.name		= "s5pv210-fimc",
+		.driver_data	= (unsigned long)&fimc_drvdata_s5pv210,
+	}, {
+		.name		= "exynos4-fimc",
+		.driver_data	= (unsigned long)&fimc_drvdata_exynos4,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(platform, fimc_driver_ids);
+
+static const struct dev_pm_ops fimc_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume)
+	SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL)
+};
+
+static struct platform_driver fimc_driver = {
+	.probe		= fimc_probe,
+	.remove		= __devexit_p(fimc_remove),
+	.id_table	= fimc_driver_ids,
+	.driver = {
+		.name	= FIMC_MODULE_NAME,
+		.owner	= THIS_MODULE,
+		.pm     = &fimc_pm_ops,
+	}
+};
+
+int __init fimc_register_driver(void)
+{
+	return platform_driver_register(&fimc_driver);
+}
+
+void __exit fimc_unregister_driver(void)
+{
+	platform_driver_unregister(&fimc_driver);
+}
diff --git a/drivers/media/platform/s5p-fimc/fimc-core.h b/drivers/media/platform/s5p-fimc/fimc-core.h
new file mode 100644
index 0000000..808ccc6
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-core.h
@@ -0,0 +1,713 @@
+/*
+ * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef FIMC_CORE_H_
+#define FIMC_CORE_H_
+
+/*#define DEBUG*/
+
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/io.h>
+#include <asm/sizes.h>
+
+#include <media/media-entity.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-mediabus.h>
+#include <media/s5p_fimc.h>
+
+#define dbg(fmt, args...) \
+	pr_debug("%s:%d: " fmt "\n", __func__, __LINE__, ##args)
+
+/* Time to wait for next frame VSYNC interrupt while stopping operation. */
+#define FIMC_SHUTDOWN_TIMEOUT	((100*HZ)/1000)
+#define MAX_FIMC_CLOCKS		2
+#define FIMC_MODULE_NAME	"s5p-fimc"
+#define FIMC_MAX_DEVS		4
+#define FIMC_MAX_OUT_BUFS	4
+#define SCALER_MAX_HRATIO	64
+#define SCALER_MAX_VRATIO	64
+#define DMA_MIN_SIZE		8
+#define FIMC_CAMIF_MAX_HEIGHT	0x2000
+
+/* indices to the clocks array */
+enum {
+	CLK_BUS,
+	CLK_GATE,
+};
+
+enum fimc_dev_flags {
+	ST_LPM,
+	/* m2m node */
+	ST_M2M_RUN,
+	ST_M2M_PEND,
+	ST_M2M_SUSPENDING,
+	ST_M2M_SUSPENDED,
+	/* capture node */
+	ST_CAPT_PEND,
+	ST_CAPT_RUN,
+	ST_CAPT_STREAM,
+	ST_CAPT_ISP_STREAM,
+	ST_CAPT_SUSPENDED,
+	ST_CAPT_SHUT,
+	ST_CAPT_BUSY,
+	ST_CAPT_APPLY_CFG,
+	ST_CAPT_JPEG,
+};
+
+#define fimc_m2m_active(dev) test_bit(ST_M2M_RUN, &(dev)->state)
+#define fimc_m2m_pending(dev) test_bit(ST_M2M_PEND, &(dev)->state)
+
+#define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state)
+#define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state)
+#define fimc_capture_busy(dev) test_bit(ST_CAPT_BUSY, &(dev)->state)
+
+enum fimc_datapath {
+	FIMC_IO_NONE,
+	FIMC_IO_CAMERA,
+	FIMC_IO_DMA,
+	FIMC_IO_LCDFIFO,
+	FIMC_IO_WRITEBACK,
+	FIMC_IO_ISP,
+};
+
+enum fimc_color_fmt {
+	FIMC_FMT_RGB444 = 0x10,
+	FIMC_FMT_RGB555,
+	FIMC_FMT_RGB565,
+	FIMC_FMT_RGB666,
+	FIMC_FMT_RGB888,
+	FIMC_FMT_RGB30_LOCAL,
+	FIMC_FMT_YCBCR420 = 0x20,
+	FIMC_FMT_YCBYCR422,
+	FIMC_FMT_YCRYCB422,
+	FIMC_FMT_CBYCRY422,
+	FIMC_FMT_CRYCBY422,
+	FIMC_FMT_YCBCR444_LOCAL,
+	FIMC_FMT_JPEG = 0x40,
+	FIMC_FMT_RAW8 = 0x80,
+	FIMC_FMT_RAW10,
+	FIMC_FMT_RAW12,
+};
+
+#define fimc_fmt_is_rgb(x) (!!((x) & 0x10))
+#define fimc_fmt_is_jpeg(x) (!!((x) & 0x40))
+
+#define IS_M2M(__strt) ((__strt) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE || \
+			__strt == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+
+/* The hardware context state. */
+#define	FIMC_PARAMS		(1 << 0)
+#define	FIMC_SRC_FMT		(1 << 3)
+#define	FIMC_DST_FMT		(1 << 4)
+#define	FIMC_COMPOSE		(1 << 5)
+#define	FIMC_CTX_M2M		(1 << 16)
+#define	FIMC_CTX_CAP		(1 << 17)
+#define	FIMC_CTX_SHUT		(1 << 18)
+
+/* Image conversion flags */
+#define	FIMC_IN_DMA_ACCESS_TILED	(1 << 0)
+#define	FIMC_IN_DMA_ACCESS_LINEAR	(0 << 0)
+#define	FIMC_OUT_DMA_ACCESS_TILED	(1 << 1)
+#define	FIMC_OUT_DMA_ACCESS_LINEAR	(0 << 1)
+#define	FIMC_SCAN_MODE_PROGRESSIVE	(0 << 2)
+#define	FIMC_SCAN_MODE_INTERLACED	(1 << 2)
+/*
+ * YCbCr data dynamic range for RGB-YUV color conversion.
+ * Y/Cb/Cr: (0 ~ 255) */
+#define	FIMC_COLOR_RANGE_WIDE		(0 << 3)
+/* Y (16 ~ 235), Cb/Cr (16 ~ 240) */
+#define	FIMC_COLOR_RANGE_NARROW		(1 << 3)
+
+/**
+ * struct fimc_fmt - the driver's internal color format data
+ * @mbus_code: Media Bus pixel code, -1 if not applicable
+ * @name: format description
+ * @fourcc: the fourcc code for this format, 0 if not applicable
+ * @color: the corresponding fimc_color_fmt
+ * @memplanes: number of physically non-contiguous data planes
+ * @colplanes: number of physically contiguous data planes
+ * @depth: per plane driver's private 'number of bits per pixel'
+ * @flags: flags indicating which operation mode format applies to
+ */
+struct fimc_fmt {
+	enum v4l2_mbus_pixelcode mbus_code;
+	char	*name;
+	u32	fourcc;
+	u32	color;
+	u16	memplanes;
+	u16	colplanes;
+	u8	depth[VIDEO_MAX_PLANES];
+	u16	flags;
+#define FMT_FLAGS_CAM		(1 << 0)
+#define FMT_FLAGS_M2M_IN	(1 << 1)
+#define FMT_FLAGS_M2M_OUT	(1 << 2)
+#define FMT_FLAGS_M2M		(1 << 1 | 1 << 2)
+#define FMT_HAS_ALPHA		(1 << 3)
+};
+
+/**
+ * struct fimc_dma_offset - pixel offset information for DMA
+ * @y_h:	y value horizontal offset
+ * @y_v:	y value vertical offset
+ * @cb_h:	cb value horizontal offset
+ * @cb_v:	cb value vertical offset
+ * @cr_h:	cr value horizontal offset
+ * @cr_v:	cr value vertical offset
+ */
+struct fimc_dma_offset {
+	int	y_h;
+	int	y_v;
+	int	cb_h;
+	int	cb_v;
+	int	cr_h;
+	int	cr_v;
+};
+
+/**
+ * struct fimc_effect - color effect information
+ * @type:	effect type
+ * @pat_cb:	cr value when type is "arbitrary"
+ * @pat_cr:	cr value when type is "arbitrary"
+ */
+struct fimc_effect {
+	u32	type;
+	u8	pat_cb;
+	u8	pat_cr;
+};
+
+/**
+ * struct fimc_scaler - the configuration data for FIMC inetrnal scaler
+ * @scaleup_h:		flag indicating scaling up horizontally
+ * @scaleup_v:		flag indicating scaling up vertically
+ * @copy_mode:		flag indicating transparent DMA transfer (no scaling
+ *			and color format conversion)
+ * @enabled:		flag indicating if the scaler is used
+ * @hfactor:		horizontal shift factor
+ * @vfactor:		vertical shift factor
+ * @pre_hratio:		horizontal ratio of the prescaler
+ * @pre_vratio:		vertical ratio of the prescaler
+ * @pre_dst_width:	the prescaler's destination width
+ * @pre_dst_height:	the prescaler's destination height
+ * @main_hratio:	the main scaler's horizontal ratio
+ * @main_vratio:	the main scaler's vertical ratio
+ * @real_width:		source pixel (width - offset)
+ * @real_height:	source pixel (height - offset)
+ */
+struct fimc_scaler {
+	unsigned int scaleup_h:1;
+	unsigned int scaleup_v:1;
+	unsigned int copy_mode:1;
+	unsigned int enabled:1;
+	u32	hfactor;
+	u32	vfactor;
+	u32	pre_hratio;
+	u32	pre_vratio;
+	u32	pre_dst_width;
+	u32	pre_dst_height;
+	u32	main_hratio;
+	u32	main_vratio;
+	u32	real_width;
+	u32	real_height;
+};
+
+/**
+ * struct fimc_addr - the FIMC physical address set for DMA
+ * @y:	 luminance plane physical address
+ * @cb:	 Cb plane physical address
+ * @cr:	 Cr plane physical address
+ */
+struct fimc_addr {
+	u32	y;
+	u32	cb;
+	u32	cr;
+};
+
+/**
+ * struct fimc_vid_buffer - the driver's video buffer
+ * @vb:    v4l videobuf buffer
+ * @list:  linked list structure for buffer queue
+ * @paddr: precalculated physical address set
+ * @index: buffer index for the output DMA engine
+ */
+struct fimc_vid_buffer {
+	struct vb2_buffer	vb;
+	struct list_head	list;
+	struct fimc_addr	paddr;
+	int			index;
+};
+
+/**
+ * struct fimc_frame - source/target frame properties
+ * @f_width:	image full width (virtual screen size)
+ * @f_height:	image full height (virtual screen size)
+ * @o_width:	original image width as set by S_FMT
+ * @o_height:	original image height as set by S_FMT
+ * @offs_h:	image horizontal pixel offset
+ * @offs_v:	image vertical pixel offset
+ * @width:	image pixel width
+ * @height:	image pixel weight
+ * @payload:	image size in bytes (w x h x bpp)
+ * @paddr:	image frame buffer physical addresses
+ * @dma_offset:	DMA offset in bytes
+ * @fmt:	fimc color format pointer
+ */
+struct fimc_frame {
+	u32	f_width;
+	u32	f_height;
+	u32	o_width;
+	u32	o_height;
+	u32	offs_h;
+	u32	offs_v;
+	u32	width;
+	u32	height;
+	unsigned long		payload[VIDEO_MAX_PLANES];
+	struct fimc_addr	paddr;
+	struct fimc_dma_offset	dma_offset;
+	struct fimc_fmt		*fmt;
+	u8			alpha;
+};
+
+/**
+ * struct fimc_m2m_device - v4l2 memory-to-memory device data
+ * @vfd: the video device node for v4l2 m2m mode
+ * @m2m_dev: v4l2 memory-to-memory device data
+ * @ctx: hardware context data
+ * @refcnt: the reference counter
+ */
+struct fimc_m2m_device {
+	struct video_device	*vfd;
+	struct v4l2_m2m_dev	*m2m_dev;
+	struct fimc_ctx		*ctx;
+	int			refcnt;
+};
+
+#define FIMC_SD_PAD_SINK	0
+#define FIMC_SD_PAD_SOURCE	1
+#define FIMC_SD_PADS_NUM	2
+
+/**
+ * struct fimc_vid_cap - camera capture device information
+ * @ctx: hardware context data
+ * @vfd: video device node for camera capture mode
+ * @subdev: subdev exposing the FIMC processing block
+ * @vd_pad: fimc video capture node pad
+ * @sd_pads: fimc video processing block pads
+ * @mf: media bus format at the FIMC camera input (and the scaler output) pad
+ * @pending_buf_q: the pending buffer queue head
+ * @active_buf_q: the queue head of buffers scheduled in hardware
+ * @vbq: the capture am video buffer queue
+ * @active_buf_cnt: number of video buffers scheduled in hardware
+ * @buf_index: index for managing the output DMA buffers
+ * @frame_count: the frame counter for statistics
+ * @reqbufs_count: the number of buffers requested in REQBUFS ioctl
+ * @input_index: input (camera sensor) index
+ * @refcnt: driver's private reference counter
+ * @input: capture input type, grp_id of the attached subdev
+ * @user_subdev_api: true if subdevs are not configured by the host driver
+ */
+struct fimc_vid_cap {
+	struct fimc_ctx			*ctx;
+	struct vb2_alloc_ctx		*alloc_ctx;
+	struct video_device		*vfd;
+	struct v4l2_subdev		subdev;
+	struct media_pad		vd_pad;
+	struct v4l2_mbus_framefmt	mf;
+	struct media_pad		sd_pads[FIMC_SD_PADS_NUM];
+	struct list_head		pending_buf_q;
+	struct list_head		active_buf_q;
+	struct vb2_queue		vbq;
+	int				active_buf_cnt;
+	int				buf_index;
+	unsigned int			frame_count;
+	unsigned int			reqbufs_count;
+	int				input_index;
+	int				refcnt;
+	u32				input;
+	bool				user_subdev_api;
+};
+
+/**
+ *  struct fimc_pix_limit - image pixel size limits in various IP configurations
+ *
+ *  @scaler_en_w: max input pixel width when the scaler is enabled
+ *  @scaler_dis_w: max input pixel width when the scaler is disabled
+ *  @in_rot_en_h: max input width with the input rotator is on
+ *  @in_rot_dis_w: max input width with the input rotator is off
+ *  @out_rot_en_w: max output width with the output rotator on
+ *  @out_rot_dis_w: max output width with the output rotator off
+ */
+struct fimc_pix_limit {
+	u16 scaler_en_w;
+	u16 scaler_dis_w;
+	u16 in_rot_en_h;
+	u16 in_rot_dis_w;
+	u16 out_rot_en_w;
+	u16 out_rot_dis_w;
+};
+
+/**
+ * struct fimc_variant - FIMC device variant information
+ * @pix_hoff: indicate whether horizontal offset is in pixels or in bytes
+ * @has_inp_rot: set if has input rotator
+ * @has_out_rot: set if has output rotator
+ * @has_cistatus2: 1 if CISTATUS2 register is present in this IP revision
+ * @has_mainscaler_ext: 1 if extended mainscaler ratios in CIEXTEN register
+ *			 are present in this IP revision
+ * @has_cam_if: set if this instance has a camera input interface
+ * @pix_limit: pixel size constraints for the scaler
+ * @min_inp_pixsize: minimum input pixel size
+ * @min_out_pixsize: minimum output pixel size
+ * @hor_offs_align: horizontal pixel offset aligment
+ * @min_vsize_align: minimum vertical pixel size alignment
+ * @out_buf_count: the number of buffers in output DMA sequence
+ */
+struct fimc_variant {
+	unsigned int	pix_hoff:1;
+	unsigned int	has_inp_rot:1;
+	unsigned int	has_out_rot:1;
+	unsigned int	has_cistatus2:1;
+	unsigned int	has_mainscaler_ext:1;
+	unsigned int	has_cam_if:1;
+	unsigned int	has_alpha:1;
+	struct fimc_pix_limit *pix_limit;
+	u16		min_inp_pixsize;
+	u16		min_out_pixsize;
+	u16		hor_offs_align;
+	u16		min_vsize_align;
+	u16		out_buf_count;
+};
+
+/**
+ * struct fimc_drvdata - per device type driver data
+ * @variant: variant information for this device
+ * @num_entities: number of fimc instances available in a SoC
+ * @lclk_frequency: local bus clock frequency
+ */
+struct fimc_drvdata {
+	struct fimc_variant *variant[FIMC_MAX_DEVS];
+	int num_entities;
+	unsigned long lclk_frequency;
+};
+
+#define fimc_get_drvdata(_pdev) \
+	((struct fimc_drvdata *) platform_get_device_id(_pdev)->driver_data)
+
+struct fimc_ctx;
+
+/**
+ * struct fimc_dev - abstraction for FIMC entity
+ * @slock:	the spinlock protecting this data structure
+ * @lock:	the mutex protecting this data structure
+ * @pdev:	pointer to the FIMC platform device
+ * @pdata:	pointer to the device platform data
+ * @variant:	the IP variant information
+ * @id:		FIMC device index (0..FIMC_MAX_DEVS)
+ * @clock:	clocks required for FIMC operation
+ * @regs:	the mapped hardware registers
+ * @irq_queue:	interrupt handler waitqueue
+ * @v4l2_dev:	root v4l2_device
+ * @m2m:	memory-to-memory V4L2 device information
+ * @vid_cap:	camera capture device information
+ * @state:	flags used to synchronize m2m and capture mode operation
+ * @alloc_ctx:	videobuf2 memory allocator context
+ * @pipeline:	fimc video capture pipeline data structure
+ */
+struct fimc_dev {
+	spinlock_t			slock;
+	struct mutex			lock;
+	struct platform_device		*pdev;
+	struct s5p_platform_fimc	*pdata;
+	struct fimc_variant		*variant;
+	u16				id;
+	struct clk			*clock[MAX_FIMC_CLOCKS];
+	void __iomem			*regs;
+	wait_queue_head_t		irq_queue;
+	struct v4l2_device		*v4l2_dev;
+	struct fimc_m2m_device		m2m;
+	struct fimc_vid_cap		vid_cap;
+	unsigned long			state;
+	struct vb2_alloc_ctx		*alloc_ctx;
+	struct fimc_pipeline		pipeline;
+};
+
+/**
+ * struct fimc_ctrls - v4l2 controls structure
+ * @handler: the control handler
+ * @colorfx: image effect control
+ * @colorfx_cbcr: Cb/Cr coefficients control
+ * @rotate: image rotation control
+ * @hflip: horizontal flip control
+ * @vflip: vertical flip control
+ * @alpha: RGB alpha control
+ * @ready: true if @handler is initialized
+ */
+struct fimc_ctrls {
+	struct v4l2_ctrl_handler handler;
+	struct {
+		struct v4l2_ctrl *colorfx;
+		struct v4l2_ctrl *colorfx_cbcr;
+	};
+	struct v4l2_ctrl *rotate;
+	struct v4l2_ctrl *hflip;
+	struct v4l2_ctrl *vflip;
+	struct v4l2_ctrl *alpha;
+	bool ready;
+};
+
+/**
+ * fimc_ctx - the device context data
+ * @s_frame:		source frame properties
+ * @d_frame:		destination frame properties
+ * @out_order_1p:	output 1-plane YCBCR order
+ * @out_order_2p:	output 2-plane YCBCR order
+ * @in_order_1p		input 1-plane YCBCR order
+ * @in_order_2p:	input 2-plane YCBCR order
+ * @in_path:		input mode (DMA or camera)
+ * @out_path:		output mode (DMA or FIFO)
+ * @scaler:		image scaler properties
+ * @effect:		image effect
+ * @rotation:		image clockwise rotation in degrees
+ * @hflip:		indicates image horizontal flip if set
+ * @vflip:		indicates image vertical flip if set
+ * @flags:		additional flags for image conversion
+ * @state:		flags to keep track of user configuration
+ * @fimc_dev:		the FIMC device this context applies to
+ * @m2m_ctx:		memory-to-memory device context
+ * @fh:			v4l2 file handle
+ * @ctrls:		v4l2 controls structure
+ */
+struct fimc_ctx {
+	struct fimc_frame	s_frame;
+	struct fimc_frame	d_frame;
+	u32			out_order_1p;
+	u32			out_order_2p;
+	u32			in_order_1p;
+	u32			in_order_2p;
+	enum fimc_datapath	in_path;
+	enum fimc_datapath	out_path;
+	struct fimc_scaler	scaler;
+	struct fimc_effect	effect;
+	int			rotation;
+	unsigned int		hflip:1;
+	unsigned int		vflip:1;
+	u32			flags;
+	u32			state;
+	struct fimc_dev		*fimc_dev;
+	struct v4l2_m2m_ctx	*m2m_ctx;
+	struct v4l2_fh		fh;
+	struct fimc_ctrls	ctrls;
+};
+
+#define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh)
+
+static inline void set_frame_bounds(struct fimc_frame *f, u32 width, u32 height)
+{
+	f->o_width  = width;
+	f->o_height = height;
+	f->f_width  = width;
+	f->f_height = height;
+}
+
+static inline void set_frame_crop(struct fimc_frame *f,
+				  u32 left, u32 top, u32 width, u32 height)
+{
+	f->offs_h = left;
+	f->offs_v = top;
+	f->width  = width;
+	f->height = height;
+}
+
+static inline u32 fimc_get_format_depth(struct fimc_fmt *ff)
+{
+	u32 i, depth = 0;
+
+	if (ff != NULL)
+		for (i = 0; i < ff->colplanes; i++)
+			depth += ff->depth[i];
+	return depth;
+}
+
+static inline bool fimc_capture_active(struct fimc_dev *fimc)
+{
+	unsigned long flags;
+	bool ret;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	ret = !!(fimc->state & (1 << ST_CAPT_RUN) ||
+		 fimc->state & (1 << ST_CAPT_PEND));
+	spin_unlock_irqrestore(&fimc->slock, flags);
+	return ret;
+}
+
+static inline void fimc_ctx_state_set(u32 state, struct fimc_ctx *ctx)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctx->fimc_dev->slock, flags);
+	ctx->state |= state;
+	spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags);
+}
+
+static inline bool fimc_ctx_state_is_set(u32 mask, struct fimc_ctx *ctx)
+{
+	unsigned long flags;
+	bool ret;
+
+	spin_lock_irqsave(&ctx->fimc_dev->slock, flags);
+	ret = (ctx->state & mask) == mask;
+	spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags);
+	return ret;
+}
+
+static inline int tiled_fmt(struct fimc_fmt *fmt)
+{
+	return fmt->fourcc == V4L2_PIX_FMT_NV12MT;
+}
+
+/* Return the alpha component bit mask */
+static inline int fimc_get_alpha_mask(struct fimc_fmt *fmt)
+{
+	switch (fmt->color) {
+	case FIMC_FMT_RGB444:	return 0x0f;
+	case FIMC_FMT_RGB555:	return 0x01;
+	case FIMC_FMT_RGB888:	return 0xff;
+	default:		return 0;
+	};
+}
+
+static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
+					       enum v4l2_buf_type type)
+{
+	struct fimc_frame *frame;
+
+	if (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == type) {
+		if (fimc_ctx_state_is_set(FIMC_CTX_M2M, ctx))
+			frame = &ctx->s_frame;
+		else
+			return ERR_PTR(-EINVAL);
+	} else if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {
+		frame = &ctx->d_frame;
+	} else {
+		v4l2_err(ctx->fimc_dev->v4l2_dev,
+			"Wrong buffer/video queue type (%d)\n", type);
+		return ERR_PTR(-EINVAL);
+	}
+
+	return frame;
+}
+
+/* -----------------------------------------------------*/
+/* fimc-core.c */
+int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv,
+				struct v4l2_fmtdesc *f);
+int fimc_ctrls_create(struct fimc_ctx *ctx);
+void fimc_ctrls_delete(struct fimc_ctx *ctx);
+void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active);
+void fimc_alpha_ctrl_update(struct fimc_ctx *ctx);
+int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f);
+void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
+			       struct v4l2_pix_format_mplane *pix);
+struct fimc_fmt *fimc_find_format(const u32 *pixelformat, const u32 *mbus_code,
+				  unsigned int mask, int index);
+struct fimc_fmt *fimc_get_format(unsigned int index);
+
+int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
+			    int dw, int dh, int rotation);
+int fimc_set_scaler_info(struct fimc_ctx *ctx);
+int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags);
+int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
+		      struct fimc_frame *frame, struct fimc_addr *paddr);
+void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f);
+void fimc_set_yuv_order(struct fimc_ctx *ctx);
+void fimc_fill_frame(struct fimc_frame *frame, struct v4l2_format *f);
+void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf);
+
+int fimc_register_m2m_device(struct fimc_dev *fimc,
+			     struct v4l2_device *v4l2_dev);
+void fimc_unregister_m2m_device(struct fimc_dev *fimc);
+int fimc_register_driver(void);
+void fimc_unregister_driver(void);
+
+/* -----------------------------------------------------*/
+/* fimc-m2m.c */
+void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state);
+
+/* -----------------------------------------------------*/
+/* fimc-capture.c					*/
+int fimc_initialize_capture_subdev(struct fimc_dev *fimc);
+void fimc_unregister_capture_subdev(struct fimc_dev *fimc);
+int fimc_capture_ctrls_create(struct fimc_dev *fimc);
+void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification,
+			void *arg);
+int fimc_capture_suspend(struct fimc_dev *fimc);
+int fimc_capture_resume(struct fimc_dev *fimc);
+
+/*
+ * Buffer list manipulation functions. Must be called with fimc.slock held.
+ */
+
+/**
+ * fimc_active_queue_add - add buffer to the capture active buffers queue
+ * @buf: buffer to add to the active buffers list
+ */
+static inline void fimc_active_queue_add(struct fimc_vid_cap *vid_cap,
+					 struct fimc_vid_buffer *buf)
+{
+	list_add_tail(&buf->list, &vid_cap->active_buf_q);
+	vid_cap->active_buf_cnt++;
+}
+
+/**
+ * fimc_active_queue_pop - pop buffer from the capture active buffers queue
+ *
+ * The caller must assure the active_buf_q list is not empty.
+ */
+static inline struct fimc_vid_buffer *fimc_active_queue_pop(
+				    struct fimc_vid_cap *vid_cap)
+{
+	struct fimc_vid_buffer *buf;
+	buf = list_entry(vid_cap->active_buf_q.next,
+			 struct fimc_vid_buffer, list);
+	list_del(&buf->list);
+	vid_cap->active_buf_cnt--;
+	return buf;
+}
+
+/**
+ * fimc_pending_queue_add - add buffer to the capture pending buffers queue
+ * @buf: buffer to add to the pending buffers list
+ */
+static inline void fimc_pending_queue_add(struct fimc_vid_cap *vid_cap,
+					  struct fimc_vid_buffer *buf)
+{
+	list_add_tail(&buf->list, &vid_cap->pending_buf_q);
+}
+
+/**
+ * fimc_pending_queue_pop - pop buffer from the capture pending buffers queue
+ *
+ * The caller must assure the pending_buf_q list is not empty.
+ */
+static inline struct fimc_vid_buffer *fimc_pending_queue_pop(
+				     struct fimc_vid_cap *vid_cap)
+{
+	struct fimc_vid_buffer *buf;
+	buf = list_entry(vid_cap->pending_buf_q.next,
+			struct fimc_vid_buffer, list);
+	list_del(&buf->list);
+	return buf;
+}
+
+#endif /* FIMC_CORE_H_ */
diff --git a/drivers/media/platform/s5p-fimc/fimc-lite-reg.c b/drivers/media/platform/s5p-fimc/fimc-lite-reg.c
new file mode 100644
index 0000000..f996e94
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-lite-reg.c
@@ -0,0 +1,300 @@
+/*
+ * Register interface file for EXYNOS FIMC-LITE (camera interface) driver
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <media/s5p_fimc.h>
+
+#include "fimc-lite-reg.h"
+#include "fimc-lite.h"
+#include "fimc-core.h"
+
+#define FLITE_RESET_TIMEOUT 50 /* in ms */
+
+void flite_hw_reset(struct fimc_lite *dev)
+{
+	unsigned long end = jiffies + msecs_to_jiffies(FLITE_RESET_TIMEOUT);
+	u32 cfg;
+
+	cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+	cfg |= FLITE_REG_CIGCTRL_SWRST_REQ;
+	writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+
+	while (time_is_after_jiffies(end)) {
+		cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+		if (cfg & FLITE_REG_CIGCTRL_SWRST_RDY)
+			break;
+		usleep_range(1000, 5000);
+	}
+
+	cfg |= FLITE_REG_CIGCTRL_SWRST;
+	writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+}
+
+void flite_hw_clear_pending_irq(struct fimc_lite *dev)
+{
+	u32 cfg = readl(dev->regs + FLITE_REG_CISTATUS);
+	cfg &= ~FLITE_REG_CISTATUS_IRQ_CAM;
+	writel(cfg, dev->regs + FLITE_REG_CISTATUS);
+}
+
+u32 flite_hw_get_interrupt_source(struct fimc_lite *dev)
+{
+	u32 intsrc = readl(dev->regs + FLITE_REG_CISTATUS);
+	return intsrc & FLITE_REG_CISTATUS_IRQ_MASK;
+}
+
+void flite_hw_clear_last_capture_end(struct fimc_lite *dev)
+{
+
+	u32 cfg = readl(dev->regs + FLITE_REG_CISTATUS2);
+	cfg &= ~FLITE_REG_CISTATUS2_LASTCAPEND;
+	writel(cfg, dev->regs + FLITE_REG_CISTATUS2);
+}
+
+void flite_hw_set_interrupt_mask(struct fimc_lite *dev)
+{
+	u32 cfg, intsrc;
+
+	/* Select interrupts to be enabled for each output mode */
+	if (dev->out_path == FIMC_IO_DMA) {
+		intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
+			 FLITE_REG_CIGCTRL_IRQ_LASTEN |
+			 FLITE_REG_CIGCTRL_IRQ_STARTEN;
+	} else {
+		/* An output to the FIMC-IS */
+		intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
+			 FLITE_REG_CIGCTRL_IRQ_LASTEN;
+	}
+
+	cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+	cfg |= FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK;
+	cfg &= ~intsrc;
+	writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+}
+
+void flite_hw_capture_start(struct fimc_lite *dev)
+{
+	u32 cfg = readl(dev->regs + FLITE_REG_CIIMGCPT);
+	cfg |= FLITE_REG_CIIMGCPT_IMGCPTEN;
+	writel(cfg, dev->regs + FLITE_REG_CIIMGCPT);
+}
+
+void flite_hw_capture_stop(struct fimc_lite *dev)
+{
+	u32 cfg = readl(dev->regs + FLITE_REG_CIIMGCPT);
+	cfg &= ~FLITE_REG_CIIMGCPT_IMGCPTEN;
+	writel(cfg, dev->regs + FLITE_REG_CIIMGCPT);
+}
+
+/*
+ * Test pattern (color bars) enable/disable. External sensor
+ * pixel clock must be active for the test pattern to work.
+ */
+void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on)
+{
+	u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+	if (on)
+		cfg |= FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR;
+	else
+		cfg &= ~FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR;
+	writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+}
+
+static const u32 src_pixfmt_map[8][3] = {
+	{ V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR,
+	  FLITE_REG_CIGCTRL_YUV422_1P },
+	{ V4L2_MBUS_FMT_YVYU8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB,
+	  FLITE_REG_CIGCTRL_YUV422_1P },
+	{ V4L2_MBUS_FMT_UYVY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY,
+	  FLITE_REG_CIGCTRL_YUV422_1P },
+	{ V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY,
+	  FLITE_REG_CIGCTRL_YUV422_1P },
+	{ V4L2_PIX_FMT_SGRBG8, 0, FLITE_REG_CIGCTRL_RAW8 },
+	{ V4L2_PIX_FMT_SGRBG10, 0, FLITE_REG_CIGCTRL_RAW10 },
+	{ V4L2_PIX_FMT_SGRBG12, 0, FLITE_REG_CIGCTRL_RAW12 },
+	{ V4L2_MBUS_FMT_JPEG_1X8, 0, FLITE_REG_CIGCTRL_USER(1) },
+};
+
+/* Set camera input pixel format and resolution */
+void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f)
+{
+	enum v4l2_mbus_pixelcode pixelcode = dev->fmt->mbus_code;
+	unsigned int i = ARRAY_SIZE(src_pixfmt_map);
+	u32 cfg;
+
+	while (i-- >= 0) {
+		if (src_pixfmt_map[i][0] == pixelcode)
+			break;
+	}
+
+	if (i == 0 && src_pixfmt_map[i][0] != pixelcode) {
+		v4l2_err(dev->vfd,
+			 "Unsupported pixel code, falling back to %#08x\n",
+			 src_pixfmt_map[i][0]);
+	}
+
+	cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+	cfg &= ~FLITE_REG_CIGCTRL_FMT_MASK;
+	cfg |= src_pixfmt_map[i][2];
+	writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+
+	cfg = readl(dev->regs + FLITE_REG_CISRCSIZE);
+	cfg &= ~(FLITE_REG_CISRCSIZE_ORDER422_MASK |
+		 FLITE_REG_CISRCSIZE_SIZE_CAM_MASK);
+	cfg |= (f->f_width << 16) | f->f_height;
+	cfg |= src_pixfmt_map[i][1];
+	writel(cfg, dev->regs + FLITE_REG_CISRCSIZE);
+}
+
+/* Set the camera host input window offsets (cropping) */
+void flite_hw_set_window_offset(struct fimc_lite *dev, struct flite_frame *f)
+{
+	u32 hoff2, voff2;
+	u32 cfg;
+
+	cfg = readl(dev->regs + FLITE_REG_CIWDOFST);
+	cfg &= ~FLITE_REG_CIWDOFST_OFST_MASK;
+	cfg |= (f->rect.left << 16) | f->rect.top;
+	cfg |= FLITE_REG_CIWDOFST_WINOFSEN;
+	writel(cfg, dev->regs + FLITE_REG_CIWDOFST);
+
+	hoff2 = f->f_width - f->rect.width - f->rect.left;
+	voff2 = f->f_height - f->rect.height - f->rect.top;
+
+	cfg = (hoff2 << 16) | voff2;
+	writel(cfg, dev->regs + FLITE_REG_CIWDOFST2);
+}
+
+/* Select camera port (A, B) */
+static void flite_hw_set_camera_port(struct fimc_lite *dev, int id)
+{
+	u32 cfg = readl(dev->regs + FLITE_REG_CIGENERAL);
+	if (id == 0)
+		cfg &= ~FLITE_REG_CIGENERAL_CAM_B;
+	else
+		cfg |= FLITE_REG_CIGENERAL_CAM_B;
+	writel(cfg, dev->regs + FLITE_REG_CIGENERAL);
+}
+
+/* Select serial or parallel bus, camera port (A,B) and set signals polarity */
+void flite_hw_set_camera_bus(struct fimc_lite *dev,
+			     struct s5p_fimc_isp_info *s_info)
+{
+	u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+	unsigned int flags = s_info->flags;
+
+	if (s_info->bus_type != FIMC_MIPI_CSI2) {
+		cfg &= ~(FLITE_REG_CIGCTRL_SELCAM_MIPI |
+			 FLITE_REG_CIGCTRL_INVPOLPCLK |
+			 FLITE_REG_CIGCTRL_INVPOLVSYNC |
+			 FLITE_REG_CIGCTRL_INVPOLHREF);
+
+		if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+			cfg |= FLITE_REG_CIGCTRL_INVPOLPCLK;
+
+		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+			cfg |= FLITE_REG_CIGCTRL_INVPOLVSYNC;
+
+		if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+			cfg |= FLITE_REG_CIGCTRL_INVPOLHREF;
+	} else {
+		cfg |= FLITE_REG_CIGCTRL_SELCAM_MIPI;
+	}
+
+	writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+
+	flite_hw_set_camera_port(dev, s_info->mux_id);
+}
+
+static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
+{
+	static const u32 pixcode[4][2] = {
+		{ V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CIODMAFMT_YCBYCR },
+		{ V4L2_MBUS_FMT_YVYU8_2X8, FLITE_REG_CIODMAFMT_YCRYCB },
+		{ V4L2_MBUS_FMT_UYVY8_2X8, FLITE_REG_CIODMAFMT_CBYCRY },
+		{ V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CIODMAFMT_CRYCBY },
+	};
+	u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT);
+	unsigned int i = ARRAY_SIZE(pixcode);
+
+	while (i-- >= 0)
+		if (pixcode[i][0] == dev->fmt->mbus_code)
+			break;
+	cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK;
+	writel(cfg | pixcode[i][1], dev->regs + FLITE_REG_CIODMAFMT);
+}
+
+void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f)
+{
+	u32 cfg;
+
+	/* Maximum output pixel size */
+	cfg = readl(dev->regs + FLITE_REG_CIOCAN);
+	cfg &= ~FLITE_REG_CIOCAN_MASK;
+	cfg = (f->f_height << 16) | f->f_width;
+	writel(cfg, dev->regs + FLITE_REG_CIOCAN);
+
+	/* DMA offsets */
+	cfg = readl(dev->regs + FLITE_REG_CIOOFF);
+	cfg &= ~FLITE_REG_CIOOFF_MASK;
+	cfg |= (f->rect.top << 16) | f->rect.left;
+	writel(cfg, dev->regs + FLITE_REG_CIOOFF);
+}
+
+/* Enable/disable output DMA, set output pixel size and offsets (composition) */
+void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f,
+			     bool enable)
+{
+	u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+
+	if (!enable) {
+		cfg |= FLITE_REG_CIGCTRL_ODMA_DISABLE;
+		writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+		return;
+	}
+
+	cfg &= ~FLITE_REG_CIGCTRL_ODMA_DISABLE;
+	writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+
+	flite_hw_set_out_order(dev, f);
+	flite_hw_set_dma_window(dev, f);
+}
+
+void flite_hw_dump_regs(struct fimc_lite *dev, const char *label)
+{
+	struct {
+		u32 offset;
+		const char * const name;
+	} registers[] = {
+		{ 0x00, "CISRCSIZE" },
+		{ 0x04, "CIGCTRL" },
+		{ 0x08, "CIIMGCPT" },
+		{ 0x0c, "CICPTSEQ" },
+		{ 0x10, "CIWDOFST" },
+		{ 0x14, "CIWDOFST2" },
+		{ 0x18, "CIODMAFMT" },
+		{ 0x20, "CIOCAN" },
+		{ 0x24, "CIOOFF" },
+		{ 0x30, "CIOSA" },
+		{ 0x40, "CISTATUS" },
+		{ 0x44, "CISTATUS2" },
+		{ 0xf0, "CITHOLD" },
+		{ 0xfc, "CIGENERAL" },
+	};
+	u32 i;
+
+	pr_info("--- %s ---\n", label);
+	for (i = 0; i < ARRAY_SIZE(registers); i++) {
+		u32 cfg = readl(dev->regs + registers[i].offset);
+		pr_info("%s: %s:\t0x%08x\n", __func__, registers[i].name, cfg);
+	}
+}
diff --git a/drivers/media/platform/s5p-fimc/fimc-lite-reg.h b/drivers/media/platform/s5p-fimc/fimc-lite-reg.h
new file mode 100644
index 0000000..adb9e9e
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-lite-reg.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef FIMC_LITE_REG_H_
+#define FIMC_LITE_REG_H_
+
+#include "fimc-lite.h"
+
+/* Camera Source size */
+#define FLITE_REG_CISRCSIZE			0x00
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR	(0 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB	(1 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY	(2 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY	(3 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_MASK	(0x3 << 14)
+#define FLITE_REG_CISRCSIZE_SIZE_CAM_MASK	(0x3fff << 16 | 0x3fff)
+
+/* Global control */
+#define FLITE_REG_CIGCTRL			0x04
+#define FLITE_REG_CIGCTRL_YUV422_1P		(0x1e << 24)
+#define FLITE_REG_CIGCTRL_RAW8			(0x2a << 24)
+#define FLITE_REG_CIGCTRL_RAW10			(0x2b << 24)
+#define FLITE_REG_CIGCTRL_RAW12			(0x2c << 24)
+#define FLITE_REG_CIGCTRL_RAW14			(0x2d << 24)
+/* User defined formats. x = 0...15 */
+#define FLITE_REG_CIGCTRL_USER(x)		((0x30 + x - 1) << 24)
+#define FLITE_REG_CIGCTRL_FMT_MASK		(0x3f << 24)
+#define FLITE_REG_CIGCTRL_SHADOWMASK_DISABLE	(1 << 21)
+#define FLITE_REG_CIGCTRL_ODMA_DISABLE		(1 << 20)
+#define FLITE_REG_CIGCTRL_SWRST_REQ		(1 << 19)
+#define FLITE_REG_CIGCTRL_SWRST_RDY		(1 << 18)
+#define FLITE_REG_CIGCTRL_SWRST			(1 << 17)
+#define FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR	(1 << 15)
+#define FLITE_REG_CIGCTRL_INVPOLPCLK		(1 << 14)
+#define FLITE_REG_CIGCTRL_INVPOLVSYNC		(1 << 13)
+#define FLITE_REG_CIGCTRL_INVPOLHREF		(1 << 12)
+/* Interrupts mask bits (1 disables an interrupt) */
+#define FLITE_REG_CIGCTRL_IRQ_LASTEN		(1 << 8)
+#define FLITE_REG_CIGCTRL_IRQ_ENDEN		(1 << 7)
+#define FLITE_REG_CIGCTRL_IRQ_STARTEN		(1 << 6)
+#define FLITE_REG_CIGCTRL_IRQ_OVFEN		(1 << 5)
+#define FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK	(0xf << 5)
+#define FLITE_REG_CIGCTRL_SELCAM_MIPI		(1 << 3)
+
+/* Image Capture Enable */
+#define FLITE_REG_CIIMGCPT			0x08
+#define FLITE_REG_CIIMGCPT_IMGCPTEN		(1 << 31)
+#define FLITE_REG_CIIMGCPT_CPT_FREN		(1 << 25)
+#define FLITE_REG_CIIMGCPT_CPT_MOD_FRCNT	(1 << 18)
+#define FLITE_REG_CIIMGCPT_CPT_MOD_FREN		(0 << 18)
+
+/* Capture Sequence */
+#define FLITE_REG_CICPTSEQ			0x0c
+
+/* Camera Window Offset */
+#define FLITE_REG_CIWDOFST			0x10
+#define FLITE_REG_CIWDOFST_WINOFSEN		(1 << 31)
+#define FLITE_REG_CIWDOFST_CLROVIY		(1 << 31)
+#define FLITE_REG_CIWDOFST_CLROVFICB		(1 << 15)
+#define FLITE_REG_CIWDOFST_CLROVFICR		(1 << 14)
+#define FLITE_REG_CIWDOFST_OFST_MASK		((0x1fff << 16) | 0x1fff)
+
+/* Camera Window Offset2 */
+#define FLITE_REG_CIWDOFST2			0x14
+
+/* Camera Output DMA Format */
+#define FLITE_REG_CIODMAFMT			0x18
+#define FLITE_REG_CIODMAFMT_RAW_CON		(1 << 15)
+#define FLITE_REG_CIODMAFMT_PACK12		(1 << 14)
+#define FLITE_REG_CIODMAFMT_CRYCBY		(0 << 4)
+#define FLITE_REG_CIODMAFMT_CBYCRY		(1 << 4)
+#define FLITE_REG_CIODMAFMT_YCRYCB		(2 << 4)
+#define FLITE_REG_CIODMAFMT_YCBYCR		(3 << 4)
+#define FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK	(0x3 << 4)
+
+/* Camera Output Canvas */
+#define FLITE_REG_CIOCAN			0x20
+#define FLITE_REG_CIOCAN_MASK			((0x3fff << 16) | 0x3fff)
+
+/* Camera Output DMA Offset */
+#define FLITE_REG_CIOOFF			0x24
+#define FLITE_REG_CIOOFF_MASK			((0x3fff << 16) | 0x3fff)
+
+/* Camera Output DMA Start Address */
+#define FLITE_REG_CIOSA				0x30
+
+/* Camera Status */
+#define FLITE_REG_CISTATUS			0x40
+#define FLITE_REG_CISTATUS_MIPI_VVALID		(1 << 22)
+#define FLITE_REG_CISTATUS_MIPI_HVALID		(1 << 21)
+#define FLITE_REG_CISTATUS_MIPI_DVALID		(1 << 20)
+#define FLITE_REG_CISTATUS_ITU_VSYNC		(1 << 14)
+#define FLITE_REG_CISTATUS_ITU_HREFF		(1 << 13)
+#define FLITE_REG_CISTATUS_OVFIY		(1 << 10)
+#define FLITE_REG_CISTATUS_OVFICB		(1 << 9)
+#define FLITE_REG_CISTATUS_OVFICR		(1 << 8)
+#define FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW	(1 << 7)
+#define FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND	(1 << 6)
+#define FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART	(1 << 5)
+#define FLITE_REG_CISTATUS_IRQ_SRC_FRMEND	(1 << 4)
+#define FLITE_REG_CISTATUS_IRQ_CAM		(1 << 0)
+#define FLITE_REG_CISTATUS_IRQ_MASK		(0xf << 4)
+
+/* Camera Status2 */
+#define FLITE_REG_CISTATUS2			0x44
+#define FLITE_REG_CISTATUS2_LASTCAPEND		(1 << 1)
+#define FLITE_REG_CISTATUS2_FRMEND		(1 << 0)
+
+/* Qos Threshold */
+#define FLITE_REG_CITHOLD			0xf0
+#define FLITE_REG_CITHOLD_W_QOS_EN		(1 << 30)
+
+/* Camera General Purpose */
+#define FLITE_REG_CIGENERAL			0xfc
+/* b0: 1 - camera B, 0 - camera A */
+#define FLITE_REG_CIGENERAL_CAM_B		(1 << 0)
+
+/* ----------------------------------------------------------------------------
+ * Function declarations
+ */
+void flite_hw_reset(struct fimc_lite *dev);
+void flite_hw_clear_pending_irq(struct fimc_lite *dev);
+u32 flite_hw_get_interrupt_source(struct fimc_lite *dev);
+void flite_hw_clear_last_capture_end(struct fimc_lite *dev);
+void flite_hw_set_interrupt_mask(struct fimc_lite *dev);
+void flite_hw_capture_start(struct fimc_lite *dev);
+void flite_hw_capture_stop(struct fimc_lite *dev);
+void flite_hw_set_camera_bus(struct fimc_lite *dev,
+			     struct s5p_fimc_isp_info *s_info);
+void flite_hw_set_camera_polarity(struct fimc_lite *dev,
+				  struct s5p_fimc_isp_info *cam);
+void flite_hw_set_window_offset(struct fimc_lite *dev, struct flite_frame *f);
+void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f);
+
+void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f,
+			     bool enable);
+void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f);
+void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on);
+void flite_hw_dump_regs(struct fimc_lite *dev, const char *label);
+
+static inline void flite_hw_set_output_addr(struct fimc_lite *dev, u32 paddr)
+{
+	writel(paddr, dev->regs + FLITE_REG_CIOSA);
+}
+#endif /* FIMC_LITE_REG_H */
diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c
new file mode 100644
index 0000000..c5b57e8
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-lite.c
@@ -0,0 +1,1606 @@
+/*
+ * Samsung EXYNOS FIMC-LITE (camera host interface) driver
+*
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "fimc-mdevice.h"
+#include "fimc-core.h"
+#include "fimc-lite-reg.h"
+
+static int debug;
+module_param(debug, int, 0644);
+
+static const struct fimc_fmt fimc_lite_formats[] = {
+	{
+		.name		= "YUV 4:2:2 packed, YCbYCr",
+		.fourcc		= V4L2_PIX_FMT_YUYV,
+		.depth		= { 16 },
+		.color		= FIMC_FMT_YCBYCR422,
+		.memplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_YUYV8_2X8,
+	}, {
+		.name		= "YUV 4:2:2 packed, CbYCrY",
+		.fourcc		= V4L2_PIX_FMT_UYVY,
+		.depth		= { 16 },
+		.color		= FIMC_FMT_CBYCRY422,
+		.memplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_UYVY8_2X8,
+	}, {
+		.name		= "YUV 4:2:2 packed, CrYCbY",
+		.fourcc		= V4L2_PIX_FMT_VYUY,
+		.depth		= { 16 },
+		.color		= FIMC_FMT_CRYCBY422,
+		.memplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_VYUY8_2X8,
+	}, {
+		.name		= "YUV 4:2:2 packed, YCrYCb",
+		.fourcc		= V4L2_PIX_FMT_YVYU,
+		.depth		= { 16 },
+		.color		= FIMC_FMT_YCRYCB422,
+		.memplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_YVYU8_2X8,
+	}, {
+		.name		= "RAW8 (GRBG)",
+		.fourcc		= V4L2_PIX_FMT_SGRBG8,
+		.depth		= { 8 },
+		.color		= FIMC_FMT_RAW8,
+		.memplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_SGRBG8_1X8,
+	}, {
+		.name		= "RAW10 (GRBG)",
+		.fourcc		= V4L2_PIX_FMT_SGRBG10,
+		.depth		= { 10 },
+		.color		= FIMC_FMT_RAW10,
+		.memplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_SGRBG10_1X10,
+	}, {
+		.name		= "RAW12 (GRBG)",
+		.fourcc		= V4L2_PIX_FMT_SGRBG12,
+		.depth		= { 12 },
+		.color		= FIMC_FMT_RAW12,
+		.memplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_SGRBG12_1X12,
+	},
+};
+
+/**
+ * fimc_lite_find_format - lookup fimc color format by fourcc or media bus code
+ * @pixelformat: fourcc to match, ignored if null
+ * @mbus_code: media bus code to match, ignored if null
+ * @index: index to the fimc_lite_formats array, ignored if negative
+ */
+static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat,
+					const u32 *mbus_code, int index)
+{
+	const struct fimc_fmt *fmt, *def_fmt = NULL;
+	unsigned int i;
+	int id = 0;
+
+	if (index >= (int)ARRAY_SIZE(fimc_lite_formats))
+		return NULL;
+
+	for (i = 0; i < ARRAY_SIZE(fimc_lite_formats); ++i) {
+		fmt = &fimc_lite_formats[i];
+		if (pixelformat && fmt->fourcc == *pixelformat)
+			return fmt;
+		if (mbus_code && fmt->mbus_code == *mbus_code)
+			return fmt;
+		if (index == id)
+			def_fmt = fmt;
+		id++;
+	}
+	return def_fmt;
+}
+
+static int fimc_lite_hw_init(struct fimc_lite *fimc)
+{
+	struct fimc_pipeline *pipeline = &fimc->pipeline;
+	struct fimc_sensor_info *sensor;
+	unsigned long flags;
+
+	if (pipeline->subdevs[IDX_SENSOR] == NULL)
+		return -ENXIO;
+
+	if (fimc->fmt == NULL)
+		return -EINVAL;
+
+	sensor = v4l2_get_subdev_hostdata(pipeline->subdevs[IDX_SENSOR]);
+	spin_lock_irqsave(&fimc->slock, flags);
+
+	flite_hw_set_camera_bus(fimc, sensor->pdata);
+	flite_hw_set_source_format(fimc, &fimc->inp_frame);
+	flite_hw_set_window_offset(fimc, &fimc->inp_frame);
+	flite_hw_set_output_dma(fimc, &fimc->out_frame, true);
+	flite_hw_set_interrupt_mask(fimc);
+	flite_hw_set_test_pattern(fimc, fimc->test_pattern->val);
+
+	if (debug > 0)
+		flite_hw_dump_regs(fimc, __func__);
+
+	spin_unlock_irqrestore(&fimc->slock, flags);
+	return 0;
+}
+
+/*
+ * Reinitialize the driver so it is ready to start the streaming again.
+ * Set fimc->state to indicate stream off and the hardware shut down state.
+ * If not suspending (@suspend is false), return any buffers to videobuf2.
+ * Otherwise put any owned buffers onto the pending buffers queue, so they
+ * can be re-spun when the device is being resumed. Also perform FIMC
+ * software reset and disable streaming on the whole pipeline if required.
+ */
+static int fimc_lite_reinit(struct fimc_lite *fimc, bool suspend)
+{
+	struct flite_buffer *buf;
+	unsigned long flags;
+	bool streaming;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	streaming = fimc->state & (1 << ST_SENSOR_STREAM);
+
+	fimc->state &= ~(1 << ST_FLITE_RUN | 1 << ST_FLITE_OFF |
+			 1 << ST_FLITE_STREAM | 1 << ST_SENSOR_STREAM);
+	if (suspend)
+		fimc->state |= (1 << ST_FLITE_SUSPENDED);
+	else
+		fimc->state &= ~(1 << ST_FLITE_PENDING |
+				 1 << ST_FLITE_SUSPENDED);
+
+	/* Release unused buffers */
+	while (!suspend && !list_empty(&fimc->pending_buf_q)) {
+		buf = fimc_lite_pending_queue_pop(fimc);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+	/* If suspending put unused buffers onto pending queue */
+	while (!list_empty(&fimc->active_buf_q)) {
+		buf = fimc_lite_active_queue_pop(fimc);
+		if (suspend)
+			fimc_lite_pending_queue_add(fimc, buf);
+		else
+			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+
+	spin_unlock_irqrestore(&fimc->slock, flags);
+
+	flite_hw_reset(fimc);
+
+	if (!streaming)
+		return 0;
+
+	return fimc_pipeline_s_stream(&fimc->pipeline, 0);
+}
+
+static int fimc_lite_stop_capture(struct fimc_lite *fimc, bool suspend)
+{
+	unsigned long flags;
+
+	if (!fimc_lite_active(fimc))
+		return 0;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	set_bit(ST_FLITE_OFF, &fimc->state);
+	flite_hw_capture_stop(fimc);
+	spin_unlock_irqrestore(&fimc->slock, flags);
+
+	wait_event_timeout(fimc->irq_queue,
+			   !test_bit(ST_FLITE_OFF, &fimc->state),
+			   (2*HZ/10)); /* 200 ms */
+
+	return fimc_lite_reinit(fimc, suspend);
+}
+
+/* Must be called  with fimc.slock spinlock held. */
+static void fimc_lite_config_update(struct fimc_lite *fimc)
+{
+	flite_hw_set_window_offset(fimc, &fimc->inp_frame);
+	flite_hw_set_dma_window(fimc, &fimc->out_frame);
+	flite_hw_set_test_pattern(fimc, fimc->test_pattern->val);
+	clear_bit(ST_FLITE_CONFIG, &fimc->state);
+}
+
+static irqreturn_t flite_irq_handler(int irq, void *priv)
+{
+	struct fimc_lite *fimc = priv;
+	struct flite_buffer *vbuf;
+	unsigned long flags;
+	struct timeval *tv;
+	struct timespec ts;
+	u32 intsrc;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+
+	intsrc = flite_hw_get_interrupt_source(fimc);
+	flite_hw_clear_pending_irq(fimc);
+
+	if (test_and_clear_bit(ST_FLITE_OFF, &fimc->state)) {
+		wake_up(&fimc->irq_queue);
+		goto done;
+	}
+
+	if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW) {
+		clear_bit(ST_FLITE_RUN, &fimc->state);
+		fimc->events.data_overflow++;
+	}
+
+	if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND) {
+		flite_hw_clear_last_capture_end(fimc);
+		clear_bit(ST_FLITE_STREAM, &fimc->state);
+		wake_up(&fimc->irq_queue);
+	}
+
+	if (fimc->out_path != FIMC_IO_DMA)
+		goto done;
+
+	if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) &&
+	    test_bit(ST_FLITE_RUN, &fimc->state) &&
+	    !list_empty(&fimc->active_buf_q) &&
+	    !list_empty(&fimc->pending_buf_q)) {
+		vbuf = fimc_lite_active_queue_pop(fimc);
+		ktime_get_ts(&ts);
+		tv = &vbuf->vb.v4l2_buf.timestamp;
+		tv->tv_sec = ts.tv_sec;
+		tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+		vbuf->vb.v4l2_buf.sequence = fimc->frame_count++;
+		vb2_buffer_done(&vbuf->vb, VB2_BUF_STATE_DONE);
+
+		vbuf = fimc_lite_pending_queue_pop(fimc);
+		flite_hw_set_output_addr(fimc, vbuf->paddr);
+		fimc_lite_active_queue_add(fimc, vbuf);
+	}
+
+	if (test_bit(ST_FLITE_CONFIG, &fimc->state))
+		fimc_lite_config_update(fimc);
+
+	if (list_empty(&fimc->pending_buf_q)) {
+		flite_hw_capture_stop(fimc);
+		clear_bit(ST_FLITE_STREAM, &fimc->state);
+	}
+done:
+	set_bit(ST_FLITE_RUN, &fimc->state);
+	spin_unlock_irqrestore(&fimc->slock, flags);
+	return IRQ_HANDLED;
+}
+
+static int start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct fimc_lite *fimc = q->drv_priv;
+	int ret;
+
+	fimc->frame_count = 0;
+
+	ret = fimc_lite_hw_init(fimc);
+	if (ret) {
+		fimc_lite_reinit(fimc, false);
+		return ret;
+	}
+
+	set_bit(ST_FLITE_PENDING, &fimc->state);
+
+	if (!list_empty(&fimc->active_buf_q) &&
+	    !test_and_set_bit(ST_FLITE_STREAM, &fimc->state)) {
+		flite_hw_capture_start(fimc);
+
+		if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state))
+			fimc_pipeline_s_stream(&fimc->pipeline, 1);
+	}
+	if (debug > 0)
+		flite_hw_dump_regs(fimc, __func__);
+
+	return 0;
+}
+
+static int stop_streaming(struct vb2_queue *q)
+{
+	struct fimc_lite *fimc = q->drv_priv;
+
+	if (!fimc_lite_active(fimc))
+		return -EINVAL;
+
+	return fimc_lite_stop_capture(fimc, false);
+}
+
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt,
+		       unsigned int *num_buffers, unsigned int *num_planes,
+		       unsigned int sizes[], void *allocators[])
+{
+	const struct v4l2_pix_format_mplane *pixm = NULL;
+	struct fimc_lite *fimc = vq->drv_priv;
+	struct flite_frame *frame = &fimc->out_frame;
+	const struct fimc_fmt *fmt = fimc->fmt;
+	unsigned long wh;
+	int i;
+
+	if (pfmt) {
+		pixm = &pfmt->fmt.pix_mp;
+		fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, -1);
+		wh = pixm->width * pixm->height;
+	} else {
+		wh = frame->f_width * frame->f_height;
+	}
+
+	if (fmt == NULL)
+		return -EINVAL;
+
+	*num_planes = fmt->memplanes;
+
+	for (i = 0; i < fmt->memplanes; i++) {
+		unsigned int size = (wh * fmt->depth[i]) / 8;
+		if (pixm)
+			sizes[i] = max(size, pixm->plane_fmt[i].sizeimage);
+		else
+			sizes[i] = size;
+		allocators[i] = fimc->alloc_ctx;
+	}
+
+	return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct fimc_lite *fimc = vq->drv_priv;
+	int i;
+
+	if (fimc->fmt == NULL)
+		return -EINVAL;
+
+	for (i = 0; i < fimc->fmt->memplanes; i++) {
+		unsigned long size = fimc->payload[i];
+
+		if (vb2_plane_size(vb, i) < size) {
+			v4l2_err(fimc->vfd,
+				 "User buffer too small (%ld < %ld)\n",
+				 vb2_plane_size(vb, i), size);
+			return -EINVAL;
+		}
+		vb2_set_plane_payload(vb, i, size);
+	}
+
+	return 0;
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+	struct flite_buffer *buf
+		= container_of(vb, struct flite_buffer, vb);
+	struct fimc_lite *fimc = vb2_get_drv_priv(vb->vb2_queue);
+	unsigned long flags;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	buf->paddr = vb2_dma_contig_plane_dma_addr(vb, 0);
+
+	if (!test_bit(ST_FLITE_SUSPENDED, &fimc->state) &&
+	    !test_bit(ST_FLITE_STREAM, &fimc->state) &&
+	    list_empty(&fimc->active_buf_q)) {
+		flite_hw_set_output_addr(fimc, buf->paddr);
+		fimc_lite_active_queue_add(fimc, buf);
+	} else {
+		fimc_lite_pending_queue_add(fimc, buf);
+	}
+
+	if (vb2_is_streaming(&fimc->vb_queue) &&
+	    !list_empty(&fimc->pending_buf_q) &&
+	    !test_and_set_bit(ST_FLITE_STREAM, &fimc->state)) {
+		flite_hw_capture_start(fimc);
+		spin_unlock_irqrestore(&fimc->slock, flags);
+
+		if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state))
+			fimc_pipeline_s_stream(&fimc->pipeline, 1);
+		return;
+	}
+	spin_unlock_irqrestore(&fimc->slock, flags);
+}
+
+static void fimc_lock(struct vb2_queue *vq)
+{
+	struct fimc_lite *fimc = vb2_get_drv_priv(vq);
+	mutex_lock(&fimc->lock);
+}
+
+static void fimc_unlock(struct vb2_queue *vq)
+{
+	struct fimc_lite *fimc = vb2_get_drv_priv(vq);
+	mutex_unlock(&fimc->lock);
+}
+
+static const struct vb2_ops fimc_lite_qops = {
+	.queue_setup	 = queue_setup,
+	.buf_prepare	 = buffer_prepare,
+	.buf_queue	 = buffer_queue,
+	.wait_prepare	 = fimc_unlock,
+	.wait_finish	 = fimc_lock,
+	.start_streaming = start_streaming,
+	.stop_streaming	 = stop_streaming,
+};
+
+static void fimc_lite_clear_event_counters(struct fimc_lite *fimc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	memset(&fimc->events, 0, sizeof(fimc->events));
+	spin_unlock_irqrestore(&fimc->slock, flags);
+}
+
+static int fimc_lite_open(struct file *file)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	int ret;
+
+	if (mutex_lock_interruptible(&fimc->lock))
+		return -ERESTARTSYS;
+
+	set_bit(ST_FLITE_IN_USE, &fimc->state);
+	ret = pm_runtime_get_sync(&fimc->pdev->dev);
+	if (ret < 0)
+		goto done;
+
+	ret = v4l2_fh_open(file);
+	if (ret < 0)
+		goto done;
+
+	if (++fimc->ref_count == 1 && fimc->out_path == FIMC_IO_DMA) {
+		ret = fimc_pipeline_initialize(&fimc->pipeline,
+					       &fimc->vfd->entity, true);
+		if (ret < 0) {
+			pm_runtime_put_sync(&fimc->pdev->dev);
+			fimc->ref_count--;
+			v4l2_fh_release(file);
+			clear_bit(ST_FLITE_IN_USE, &fimc->state);
+		}
+
+		fimc_lite_clear_event_counters(fimc);
+	}
+done:
+	mutex_unlock(&fimc->lock);
+	return ret;
+}
+
+static int fimc_lite_close(struct file *file)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	int ret;
+
+	if (mutex_lock_interruptible(&fimc->lock))
+		return -ERESTARTSYS;
+
+	if (--fimc->ref_count == 0 && fimc->out_path == FIMC_IO_DMA) {
+		clear_bit(ST_FLITE_IN_USE, &fimc->state);
+		fimc_lite_stop_capture(fimc, false);
+		fimc_pipeline_shutdown(&fimc->pipeline);
+		clear_bit(ST_FLITE_SUSPENDED, &fimc->state);
+	}
+
+	pm_runtime_put(&fimc->pdev->dev);
+
+	if (fimc->ref_count == 0)
+		vb2_queue_release(&fimc->vb_queue);
+
+	ret = v4l2_fh_release(file);
+
+	mutex_unlock(&fimc->lock);
+	return ret;
+}
+
+static unsigned int fimc_lite_poll(struct file *file,
+				   struct poll_table_struct *wait)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	int ret;
+
+	if (mutex_lock_interruptible(&fimc->lock))
+		return POLL_ERR;
+
+	ret = vb2_poll(&fimc->vb_queue, file, wait);
+	mutex_unlock(&fimc->lock);
+
+	return ret;
+}
+
+static int fimc_lite_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	int ret;
+
+	if (mutex_lock_interruptible(&fimc->lock))
+		return -ERESTARTSYS;
+
+	ret = vb2_mmap(&fimc->vb_queue, vma);
+	mutex_unlock(&fimc->lock);
+
+	return ret;
+}
+
+static const struct v4l2_file_operations fimc_lite_fops = {
+	.owner		= THIS_MODULE,
+	.open		= fimc_lite_open,
+	.release	= fimc_lite_close,
+	.poll		= fimc_lite_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= fimc_lite_mmap,
+};
+
+/*
+ * Format and crop negotiation helpers
+ */
+
+static const struct fimc_fmt *fimc_lite_try_format(struct fimc_lite *fimc,
+					u32 *width, u32 *height,
+					u32 *code, u32 *fourcc, int pad)
+{
+	struct flite_variant *variant = fimc->variant;
+	const struct fimc_fmt *fmt;
+
+	fmt = fimc_lite_find_format(fourcc, code, 0);
+	if (WARN_ON(!fmt))
+		return NULL;
+
+	if (code)
+		*code = fmt->mbus_code;
+	if (fourcc)
+		*fourcc = fmt->fourcc;
+
+	if (pad == FLITE_SD_PAD_SINK) {
+		v4l_bound_align_image(width, 8, variant->max_width,
+				      ffs(variant->out_width_align) - 1,
+				      height, 0, variant->max_height, 0, 0);
+	} else {
+		v4l_bound_align_image(width, 8, fimc->inp_frame.rect.width,
+				      ffs(variant->out_width_align) - 1,
+				      height, 0, fimc->inp_frame.rect.height,
+				      0, 0);
+	}
+
+	v4l2_dbg(1, debug, &fimc->subdev, "code: 0x%x, %dx%d\n",
+		 code ? *code : 0, *width, *height);
+
+	return fmt;
+}
+
+static void fimc_lite_try_crop(struct fimc_lite *fimc, struct v4l2_rect *r)
+{
+	struct flite_frame *frame = &fimc->inp_frame;
+
+	v4l_bound_align_image(&r->width, 0, frame->f_width, 0,
+			      &r->height, 0, frame->f_height, 0, 0);
+
+	/* Adjust left/top if cropping rectangle got out of bounds */
+	r->left = clamp_t(u32, r->left, 0, frame->f_width - r->width);
+	r->left = round_down(r->left, fimc->variant->win_hor_offs_align);
+	r->top  = clamp_t(u32, r->top, 0, frame->f_height - r->height);
+
+	v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, sink fmt: %dx%d",
+		 r->left, r->top, r->width, r->height,
+		 frame->f_width, frame->f_height);
+}
+
+static void fimc_lite_try_compose(struct fimc_lite *fimc, struct v4l2_rect *r)
+{
+	struct flite_frame *frame = &fimc->out_frame;
+	struct v4l2_rect *crop_rect = &fimc->inp_frame.rect;
+
+	/* Scaling is not supported so we enforce compose rectangle size
+	   same as size of the sink crop rectangle. */
+	r->width = crop_rect->width;
+	r->height = crop_rect->height;
+
+	/* Adjust left/top if the composing rectangle got out of bounds */
+	r->left = clamp_t(u32, r->left, 0, frame->f_width - r->width);
+	r->left = round_down(r->left, fimc->variant->out_hor_offs_align);
+	r->top  = clamp_t(u32, r->top, 0, fimc->out_frame.f_height - r->height);
+
+	v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, source fmt: %dx%d",
+		 r->left, r->top, r->width, r->height,
+		 frame->f_width, frame->f_height);
+}
+
+/*
+ * Video node ioctl operations
+ */
+static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
+					struct v4l2_capability *cap)
+{
+	strlcpy(cap->driver, FIMC_LITE_DRV_NAME, sizeof(cap->driver));
+	cap->bus_info[0] = 0;
+	cap->card[0] = 0;
+	cap->capabilities = V4L2_CAP_STREAMING;
+	return 0;
+}
+
+static int fimc_lite_enum_fmt_mplane(struct file *file, void *priv,
+				     struct v4l2_fmtdesc *f)
+{
+	const struct fimc_fmt *fmt;
+
+	if (f->index >= ARRAY_SIZE(fimc_lite_formats))
+		return -EINVAL;
+
+	fmt = &fimc_lite_formats[f->index];
+	strlcpy(f->description, fmt->name, sizeof(f->description));
+	f->pixelformat = fmt->fourcc;
+
+	return 0;
+}
+
+static int fimc_lite_g_fmt_mplane(struct file *file, void *fh,
+				  struct v4l2_format *f)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
+	struct v4l2_plane_pix_format *plane_fmt = &pixm->plane_fmt[0];
+	struct flite_frame *frame = &fimc->out_frame;
+	const struct fimc_fmt *fmt = fimc->fmt;
+
+	plane_fmt->bytesperline = (frame->f_width * fmt->depth[0]) / 8;
+	plane_fmt->sizeimage = plane_fmt->bytesperline * frame->f_height;
+
+	pixm->num_planes = fmt->memplanes;
+	pixm->pixelformat = fmt->fourcc;
+	pixm->width = frame->f_width;
+	pixm->height = frame->f_height;
+	pixm->field = V4L2_FIELD_NONE;
+	pixm->colorspace = V4L2_COLORSPACE_JPEG;
+	return 0;
+}
+
+static int fimc_lite_try_fmt(struct fimc_lite *fimc,
+			     struct v4l2_pix_format_mplane *pixm,
+			     const struct fimc_fmt **ffmt)
+{
+	struct flite_variant *variant = fimc->variant;
+	u32 bpl = pixm->plane_fmt[0].bytesperline;
+	const struct fimc_fmt *fmt;
+
+	fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, 0);
+	if (WARN_ON(fmt == NULL))
+		return -EINVAL;
+	if (ffmt)
+		*ffmt = fmt;
+	v4l_bound_align_image(&pixm->width, 8, variant->max_width,
+			      ffs(variant->out_width_align) - 1,
+			      &pixm->height, 0, variant->max_height, 0, 0);
+
+	if ((bpl == 0 || ((bpl * 8) / fmt->depth[0]) < pixm->width))
+		pixm->plane_fmt[0].bytesperline = (pixm->width *
+						   fmt->depth[0]) / 8;
+
+	if (pixm->plane_fmt[0].sizeimage == 0)
+		pixm->plane_fmt[0].sizeimage = (pixm->width * pixm->height *
+						fmt->depth[0]) / 8;
+	pixm->num_planes = fmt->memplanes;
+	pixm->pixelformat = fmt->fourcc;
+	pixm->colorspace = V4L2_COLORSPACE_JPEG;
+	pixm->field = V4L2_FIELD_NONE;
+	return 0;
+}
+
+static int fimc_lite_try_fmt_mplane(struct file *file, void *fh,
+				    struct v4l2_format *f)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+
+	return fimc_lite_try_fmt(fimc, &f->fmt.pix_mp, NULL);
+}
+
+static int fimc_lite_s_fmt_mplane(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
+	struct fimc_lite *fimc = video_drvdata(file);
+	struct flite_frame *frame = &fimc->out_frame;
+	const struct fimc_fmt *fmt = NULL;
+	int ret;
+
+	if (vb2_is_busy(&fimc->vb_queue))
+		return -EBUSY;
+
+	ret = fimc_lite_try_fmt(fimc, &f->fmt.pix_mp, &fmt);
+	if (ret < 0)
+		return ret;
+
+	fimc->fmt = fmt;
+	fimc->payload[0] = max((pixm->width * pixm->height * fmt->depth[0]) / 8,
+			       pixm->plane_fmt[0].sizeimage);
+	frame->f_width = pixm->width;
+	frame->f_height = pixm->height;
+
+	return 0;
+}
+
+static int fimc_pipeline_validate(struct fimc_lite *fimc)
+{
+	struct v4l2_subdev *sd = &fimc->subdev;
+	struct v4l2_subdev_format sink_fmt, src_fmt;
+	struct media_pad *pad;
+	int ret;
+
+	while (1) {
+		/* Retrieve format at the sink pad */
+		pad = &sd->entity.pads[0];
+		if (!(pad->flags & MEDIA_PAD_FL_SINK))
+			break;
+		/* Don't call FIMC subdev operation to avoid nested locking */
+		if (sd == &fimc->subdev) {
+			struct flite_frame *ff = &fimc->out_frame;
+			sink_fmt.format.width = ff->f_width;
+			sink_fmt.format.height = ff->f_height;
+			sink_fmt.format.code = fimc->fmt->mbus_code;
+		} else {
+			sink_fmt.pad = pad->index;
+			sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+			ret = v4l2_subdev_call(sd, pad, get_fmt, NULL,
+					       &sink_fmt);
+			if (ret < 0 && ret != -ENOIOCTLCMD)
+				return -EPIPE;
+		}
+		/* Retrieve format at the source pad */
+		pad = media_entity_remote_source(pad);
+		if (pad == NULL ||
+		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+			break;
+
+		sd = media_entity_to_v4l2_subdev(pad->entity);
+		src_fmt.pad = pad->index;
+		src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+		ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt);
+		if (ret < 0 && ret != -ENOIOCTLCMD)
+			return -EPIPE;
+
+		if (src_fmt.format.width != sink_fmt.format.width ||
+		    src_fmt.format.height != sink_fmt.format.height ||
+		    src_fmt.format.code != sink_fmt.format.code)
+			return -EPIPE;
+	}
+	return 0;
+}
+
+static int fimc_lite_streamon(struct file *file, void *priv,
+			      enum v4l2_buf_type type)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	struct v4l2_subdev *sensor = fimc->pipeline.subdevs[IDX_SENSOR];
+	struct fimc_pipeline *p = &fimc->pipeline;
+	int ret;
+
+	if (fimc_lite_active(fimc))
+		return -EBUSY;
+
+	ret = media_entity_pipeline_start(&sensor->entity, p->m_pipeline);
+	if (ret < 0)
+		return ret;
+
+	ret = fimc_pipeline_validate(fimc);
+	if (ret) {
+		media_entity_pipeline_stop(&sensor->entity);
+		return ret;
+	}
+
+	return vb2_streamon(&fimc->vb_queue, type);
+}
+
+static int fimc_lite_streamoff(struct file *file, void *priv,
+			       enum v4l2_buf_type type)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
+	int ret;
+
+	ret = vb2_streamoff(&fimc->vb_queue, type);
+	if (ret == 0)
+		media_entity_pipeline_stop(&sd->entity);
+	return ret;
+}
+
+static int fimc_lite_reqbufs(struct file *file, void *priv,
+			     struct v4l2_requestbuffers *reqbufs)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	int ret;
+
+	reqbufs->count = max_t(u32, FLITE_REQ_BUFS_MIN, reqbufs->count);
+	ret = vb2_reqbufs(&fimc->vb_queue, reqbufs);
+	if (!ret < 0)
+		fimc->reqbufs_count = reqbufs->count;
+
+	return ret;
+}
+
+static int fimc_lite_querybuf(struct file *file, void *priv,
+			      struct v4l2_buffer *buf)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+
+	return vb2_querybuf(&fimc->vb_queue, buf);
+}
+
+static int fimc_lite_qbuf(struct file *file, void *priv,
+			  struct v4l2_buffer *buf)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+
+	return vb2_qbuf(&fimc->vb_queue, buf);
+}
+
+static int fimc_lite_dqbuf(struct file *file, void *priv,
+			   struct v4l2_buffer *buf)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+
+	return vb2_dqbuf(&fimc->vb_queue, buf, file->f_flags & O_NONBLOCK);
+}
+
+static int fimc_lite_create_bufs(struct file *file, void *priv,
+				 struct v4l2_create_buffers *create)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+
+	return vb2_create_bufs(&fimc->vb_queue, create);
+}
+
+static int fimc_lite_prepare_buf(struct file *file, void *priv,
+				 struct v4l2_buffer *b)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+
+	return vb2_prepare_buf(&fimc->vb_queue, b);
+}
+
+/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
+static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
+{
+	if (a->left < b->left || a->top < b->top)
+		return 0;
+	if (a->left + a->width > b->left + b->width)
+		return 0;
+	if (a->top + a->height > b->top + b->height)
+		return 0;
+
+	return 1;
+}
+
+static int fimc_lite_g_selection(struct file *file, void *fh,
+				 struct v4l2_selection *sel)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	struct flite_frame *f = &fimc->out_frame;
+
+	if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return -EINVAL;
+
+	switch (sel->target) {
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+		sel->r.left = 0;
+		sel->r.top = 0;
+		sel->r.width = f->f_width;
+		sel->r.height = f->f_height;
+		return 0;
+
+	case V4L2_SEL_TGT_COMPOSE:
+		sel->r = f->rect;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int fimc_lite_s_selection(struct file *file, void *fh,
+				 struct v4l2_selection *sel)
+{
+	struct fimc_lite *fimc = video_drvdata(file);
+	struct flite_frame *f = &fimc->out_frame;
+	struct v4l2_rect rect = sel->r;
+	unsigned long flags;
+
+	if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
+	    sel->target != V4L2_SEL_TGT_COMPOSE)
+		return -EINVAL;
+
+	fimc_lite_try_compose(fimc, &rect);
+
+	if ((sel->flags & V4L2_SEL_FLAG_LE) &&
+	    !enclosed_rectangle(&rect, &sel->r))
+		return -ERANGE;
+
+	if ((sel->flags & V4L2_SEL_FLAG_GE) &&
+	    !enclosed_rectangle(&sel->r, &rect))
+		return -ERANGE;
+
+	sel->r = rect;
+	spin_lock_irqsave(&fimc->slock, flags);
+	f->rect = rect;
+	set_bit(ST_FLITE_CONFIG, &fimc->state);
+	spin_unlock_irqrestore(&fimc->slock, flags);
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops fimc_lite_ioctl_ops = {
+	.vidioc_querycap		= fimc_vidioc_querycap_capture,
+	.vidioc_enum_fmt_vid_cap_mplane	= fimc_lite_enum_fmt_mplane,
+	.vidioc_try_fmt_vid_cap_mplane	= fimc_lite_try_fmt_mplane,
+	.vidioc_s_fmt_vid_cap_mplane	= fimc_lite_s_fmt_mplane,
+	.vidioc_g_fmt_vid_cap_mplane	= fimc_lite_g_fmt_mplane,
+	.vidioc_g_selection		= fimc_lite_g_selection,
+	.vidioc_s_selection		= fimc_lite_s_selection,
+	.vidioc_reqbufs			= fimc_lite_reqbufs,
+	.vidioc_querybuf		= fimc_lite_querybuf,
+	.vidioc_prepare_buf		= fimc_lite_prepare_buf,
+	.vidioc_create_bufs		= fimc_lite_create_bufs,
+	.vidioc_qbuf			= fimc_lite_qbuf,
+	.vidioc_dqbuf			= fimc_lite_dqbuf,
+	.vidioc_streamon		= fimc_lite_streamon,
+	.vidioc_streamoff		= fimc_lite_streamoff,
+};
+
+/* Capture subdev media entity operations */
+static int fimc_lite_link_setup(struct media_entity *entity,
+				const struct media_pad *local,
+				const struct media_pad *remote, u32 flags)
+{
+	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+	unsigned int remote_ent_type = media_entity_type(remote->entity);
+
+	if (WARN_ON(fimc == NULL))
+		return 0;
+
+	v4l2_dbg(1, debug, sd, "%s: %s --> %s, flags: 0x%x. source_id: 0x%x",
+		 __func__, local->entity->name, remote->entity->name,
+		 flags, fimc->source_subdev_grp_id);
+
+	switch (local->index) {
+	case FIMC_SD_PAD_SINK:
+		if (remote_ent_type != MEDIA_ENT_T_V4L2_SUBDEV)
+			return -EINVAL;
+
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			if (fimc->source_subdev_grp_id != 0)
+				return -EBUSY;
+			fimc->source_subdev_grp_id = sd->grp_id;
+			return 0;
+		}
+
+		fimc->source_subdev_grp_id = 0;
+		break;
+
+	case FIMC_SD_PAD_SOURCE:
+		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+			fimc->out_path = FIMC_IO_NONE;
+			return 0;
+		}
+		if (remote_ent_type == MEDIA_ENT_T_V4L2_SUBDEV)
+			fimc->out_path = FIMC_IO_ISP;
+		else
+			fimc->out_path = FIMC_IO_DMA;
+		break;
+
+	default:
+		v4l2_err(sd, "Invalid pad index\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct media_entity_operations fimc_lite_subdev_media_ops = {
+	.link_setup = fimc_lite_link_setup,
+};
+
+static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd,
+					   struct v4l2_subdev_fh *fh,
+					   struct v4l2_subdev_mbus_code_enum *code)
+{
+	const struct fimc_fmt *fmt;
+
+	fmt = fimc_lite_find_format(NULL, NULL, code->index);
+	if (!fmt)
+		return -EINVAL;
+	code->code = fmt->mbus_code;
+	return 0;
+}
+
+static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_fh *fh,
+				    struct v4l2_subdev_format *fmt)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *mf = &fmt->format;
+	struct flite_frame *f = &fimc->out_frame;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+		fmt->format = *mf;
+		return 0;
+	}
+	mf->colorspace = V4L2_COLORSPACE_JPEG;
+
+	mutex_lock(&fimc->lock);
+	mf->code = fimc->fmt->mbus_code;
+
+	if (fmt->pad == FLITE_SD_PAD_SINK) {
+		/* full camera input frame size */
+		mf->width = f->f_width;
+		mf->height = f->f_height;
+	} else {
+		/* crop size */
+		mf->width = f->rect.width;
+		mf->height = f->rect.height;
+	}
+	mutex_unlock(&fimc->lock);
+	return 0;
+}
+
+static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_fh *fh,
+				    struct v4l2_subdev_format *fmt)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *mf = &fmt->format;
+	struct flite_frame *sink = &fimc->inp_frame;
+	const struct fimc_fmt *ffmt;
+
+	v4l2_dbg(1, debug, sd, "pad%d: code: 0x%x, %dx%d",
+		 fmt->pad, mf->code, mf->width, mf->height);
+
+	mf->colorspace = V4L2_COLORSPACE_JPEG;
+	mutex_lock(&fimc->lock);
+
+	if ((fimc->out_path == FIMC_IO_ISP && sd->entity.stream_count > 0) ||
+	    (fimc->out_path == FIMC_IO_DMA && vb2_is_busy(&fimc->vb_queue))) {
+		mutex_unlock(&fimc->lock);
+		return -EBUSY;
+	}
+
+	ffmt = fimc_lite_try_format(fimc, &mf->width, &mf->height,
+				    &mf->code, NULL, fmt->pad);
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+		*mf = fmt->format;
+		mutex_unlock(&fimc->lock);
+		return 0;
+	}
+
+	if (fmt->pad == FLITE_SD_PAD_SINK) {
+		sink->f_width = mf->width;
+		sink->f_height = mf->height;
+		fimc->fmt = ffmt;
+		/* Set sink crop rectangle */
+		sink->rect.width = mf->width;
+		sink->rect.height = mf->height;
+		sink->rect.left = 0;
+		sink->rect.top = 0;
+		/* Reset source crop rectangle */
+		fimc->out_frame.rect = sink->rect;
+	} else {
+		/* Allow changing format only on sink pad */
+		mf->code = fimc->fmt->mbus_code;
+		mf->width = sink->rect.width;
+		mf->height = sink->rect.height;
+	}
+
+	mutex_unlock(&fimc->lock);
+	return 0;
+}
+
+static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd,
+					  struct v4l2_subdev_fh *fh,
+					  struct v4l2_subdev_selection *sel)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+	struct flite_frame *f = &fimc->inp_frame;
+
+	if ((sel->target != V4L2_SEL_TGT_CROP &&
+	     sel->target != V4L2_SEL_TGT_CROP_BOUNDS) ||
+	     sel->pad != FLITE_SD_PAD_SINK)
+		return -EINVAL;
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+		sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad);
+		return 0;
+	}
+
+	mutex_lock(&fimc->lock);
+	if (sel->target == V4L2_SEL_TGT_CROP) {
+		sel->r = f->rect;
+	} else {
+		sel->r.left = 0;
+		sel->r.top = 0;
+		sel->r.width = f->f_width;
+		sel->r.height = f->f_height;
+	}
+	mutex_unlock(&fimc->lock);
+
+	v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %d, f_h: %d",
+		 __func__, f->rect.left, f->rect.top, f->rect.width,
+		 f->rect.height, f->f_width, f->f_height);
+
+	return 0;
+}
+
+static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd,
+					  struct v4l2_subdev_fh *fh,
+					  struct v4l2_subdev_selection *sel)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+	struct flite_frame *f = &fimc->inp_frame;
+	int ret = 0;
+
+	if (sel->target != V4L2_SEL_TGT_CROP || sel->pad != FLITE_SD_PAD_SINK)
+		return -EINVAL;
+
+	mutex_lock(&fimc->lock);
+	fimc_lite_try_crop(fimc, &sel->r);
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+		*v4l2_subdev_get_try_crop(fh, sel->pad) = sel->r;
+	} else {
+		unsigned long flags;
+		spin_lock_irqsave(&fimc->slock, flags);
+		f->rect = sel->r;
+		/* Same crop rectangle on the source pad */
+		fimc->out_frame.rect = sel->r;
+		set_bit(ST_FLITE_CONFIG, &fimc->state);
+		spin_unlock_irqrestore(&fimc->slock, flags);
+	}
+	mutex_unlock(&fimc->lock);
+
+	v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %d, f_h: %d",
+		 __func__, f->rect.left, f->rect.top, f->rect.width,
+		 f->rect.height, f->f_width, f->f_height);
+
+	return ret;
+}
+
+static int fimc_lite_subdev_s_stream(struct v4l2_subdev *sd, int on)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+
+	if (fimc->out_path == FIMC_IO_DMA)
+		return -ENOIOCTLCMD;
+
+	/* TODO: */
+
+	return 0;
+}
+
+static int fimc_lite_subdev_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+
+	if (fimc->out_path == FIMC_IO_DMA)
+		return -ENOIOCTLCMD;
+
+	/* TODO: */
+
+	return 0;
+}
+
+static int fimc_lite_log_status(struct v4l2_subdev *sd)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+
+	flite_hw_dump_regs(fimc, __func__);
+	return 0;
+}
+
+static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+	struct vb2_queue *q = &fimc->vb_queue;
+	struct video_device *vfd;
+	int ret;
+
+	fimc->fmt = &fimc_lite_formats[0];
+	fimc->out_path = FIMC_IO_DMA;
+
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(sd->v4l2_dev, "Failed to allocate video device\n");
+		return -ENOMEM;
+	}
+
+	snprintf(vfd->name, sizeof(vfd->name), "fimc-lite.%d.capture",
+		 fimc->index);
+
+	vfd->fops = &fimc_lite_fops;
+	vfd->ioctl_ops = &fimc_lite_ioctl_ops;
+	vfd->v4l2_dev = sd->v4l2_dev;
+	vfd->minor = -1;
+	vfd->release = video_device_release;
+	vfd->lock = &fimc->lock;
+	fimc->vfd = vfd;
+	fimc->ref_count = 0;
+	fimc->reqbufs_count = 0;
+
+	INIT_LIST_HEAD(&fimc->pending_buf_q);
+	INIT_LIST_HEAD(&fimc->active_buf_q);
+
+	memset(q, 0, sizeof(*q));
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	q->io_modes = VB2_MMAP | VB2_USERPTR;
+	q->ops = &fimc_lite_qops;
+	q->mem_ops = &vb2_dma_contig_memops;
+	q->buf_struct_size = sizeof(struct flite_buffer);
+	q->drv_priv = fimc;
+
+	vb2_queue_init(q);
+
+	fimc->vd_pad.flags = MEDIA_PAD_FL_SINK;
+	ret = media_entity_init(&vfd->entity, 1, &fimc->vd_pad, 0);
+	if (ret)
+		goto err;
+
+	video_set_drvdata(vfd, fimc);
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+	if (ret)
+		goto err_vd;
+
+	v4l2_info(sd->v4l2_dev, "Registered %s as /dev/%s\n",
+		  vfd->name, video_device_node_name(vfd));
+	return 0;
+
+ err_vd:
+	media_entity_cleanup(&vfd->entity);
+ err:
+	video_device_release(vfd);
+	return ret;
+}
+
+static void fimc_lite_subdev_unregistered(struct v4l2_subdev *sd)
+{
+	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+
+	if (fimc == NULL)
+		return;
+
+	if (fimc->vfd) {
+		video_unregister_device(fimc->vfd);
+		media_entity_cleanup(&fimc->vfd->entity);
+		fimc->vfd = NULL;
+	}
+}
+
+static const struct v4l2_subdev_internal_ops fimc_lite_subdev_internal_ops = {
+	.registered = fimc_lite_subdev_registered,
+	.unregistered = fimc_lite_subdev_unregistered,
+};
+
+static const struct v4l2_subdev_pad_ops fimc_lite_subdev_pad_ops = {
+	.enum_mbus_code = fimc_lite_subdev_enum_mbus_code,
+	.get_selection = fimc_lite_subdev_get_selection,
+	.set_selection = fimc_lite_subdev_set_selection,
+	.get_fmt = fimc_lite_subdev_get_fmt,
+	.set_fmt = fimc_lite_subdev_set_fmt,
+};
+
+static const struct v4l2_subdev_video_ops fimc_lite_subdev_video_ops = {
+	.s_stream = fimc_lite_subdev_s_stream,
+};
+
+static const struct v4l2_subdev_core_ops fimc_lite_core_ops = {
+	.s_power = fimc_lite_subdev_s_power,
+	.log_status = fimc_lite_log_status,
+};
+
+static struct v4l2_subdev_ops fimc_lite_subdev_ops = {
+	.core = &fimc_lite_core_ops,
+	.video = &fimc_lite_subdev_video_ops,
+	.pad = &fimc_lite_subdev_pad_ops,
+};
+
+static int fimc_lite_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct fimc_lite *fimc = container_of(ctrl->handler, struct fimc_lite,
+					      ctrl_handler);
+	set_bit(ST_FLITE_CONFIG, &fimc->state);
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops fimc_lite_ctrl_ops = {
+	.s_ctrl	= fimc_lite_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config fimc_lite_ctrl = {
+	.ops	= &fimc_lite_ctrl_ops,
+	.id	= V4L2_CTRL_CLASS_USER | 0x1001,
+	.type	= V4L2_CTRL_TYPE_BOOLEAN,
+	.name	= "Test Pattern 640x480",
+};
+
+static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc)
+{
+	struct v4l2_ctrl_handler *handler = &fimc->ctrl_handler;
+	struct v4l2_subdev *sd = &fimc->subdev;
+	int ret;
+
+	v4l2_subdev_init(sd, &fimc_lite_subdev_ops);
+	sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(sd->name, sizeof(sd->name), "FIMC-LITE.%d", fimc->index);
+
+	fimc->subdev_pads[FIMC_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	fimc->subdev_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM,
+				fimc->subdev_pads, 0);
+	if (ret)
+		return ret;
+
+	v4l2_ctrl_handler_init(handler, 1);
+	fimc->test_pattern = v4l2_ctrl_new_custom(handler, &fimc_lite_ctrl,
+						  NULL);
+	if (handler->error) {
+		media_entity_cleanup(&sd->entity);
+		return handler->error;
+	}
+
+	sd->ctrl_handler = handler;
+	sd->internal_ops = &fimc_lite_subdev_internal_ops;
+	sd->entity.ops = &fimc_lite_subdev_media_ops;
+	v4l2_set_subdevdata(sd, fimc);
+
+	return 0;
+}
+
+static void fimc_lite_unregister_capture_subdev(struct fimc_lite *fimc)
+{
+	struct v4l2_subdev *sd = &fimc->subdev;
+
+	v4l2_device_unregister_subdev(sd);
+	media_entity_cleanup(&sd->entity);
+	v4l2_ctrl_handler_free(&fimc->ctrl_handler);
+	v4l2_set_subdevdata(sd, NULL);
+}
+
+static void fimc_lite_clk_put(struct fimc_lite *fimc)
+{
+	if (IS_ERR_OR_NULL(fimc->clock))
+		return;
+
+	clk_unprepare(fimc->clock);
+	clk_put(fimc->clock);
+	fimc->clock = NULL;
+}
+
+static int fimc_lite_clk_get(struct fimc_lite *fimc)
+{
+	int ret;
+
+	fimc->clock = clk_get(&fimc->pdev->dev, FLITE_CLK_NAME);
+	if (IS_ERR(fimc->clock))
+		return PTR_ERR(fimc->clock);
+
+	ret = clk_prepare(fimc->clock);
+	if (ret < 0) {
+		clk_put(fimc->clock);
+		fimc->clock = NULL;
+	}
+	return ret;
+}
+
+static int __devinit fimc_lite_probe(struct platform_device *pdev)
+{
+	struct flite_drvdata *drv_data = fimc_lite_get_drvdata(pdev);
+	struct fimc_lite *fimc;
+	struct resource *res;
+	int ret;
+
+	fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL);
+	if (!fimc)
+		return -ENOMEM;
+
+	fimc->index = pdev->id;
+	fimc->variant = drv_data->variant[fimc->index];
+	fimc->pdev = pdev;
+
+	init_waitqueue_head(&fimc->irq_queue);
+	spin_lock_init(&fimc->slock);
+	mutex_init(&fimc->lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	fimc->regs = devm_request_and_ioremap(&pdev->dev, res);
+	if (fimc->regs == NULL) {
+		dev_err(&pdev->dev, "Failed to obtain io memory\n");
+		return -ENOENT;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "Failed to get IRQ resource\n");
+		return -ENXIO;
+	}
+
+	ret = fimc_lite_clk_get(fimc);
+	if (ret)
+		return ret;
+
+	ret = devm_request_irq(&pdev->dev, res->start, flite_irq_handler,
+			       0, dev_name(&pdev->dev), fimc);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret);
+		goto err_clk;
+	}
+
+	/* The video node will be created within the subdev's registered() op */
+	ret = fimc_lite_create_capture_subdev(fimc);
+	if (ret)
+		goto err_clk;
+
+	platform_set_drvdata(pdev, fimc);
+	pm_runtime_enable(&pdev->dev);
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (ret < 0)
+		goto err_sd;
+
+	fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+	if (IS_ERR(fimc->alloc_ctx)) {
+		ret = PTR_ERR(fimc->alloc_ctx);
+		goto err_pm;
+	}
+	pm_runtime_put(&pdev->dev);
+
+	dev_dbg(&pdev->dev, "FIMC-LITE.%d registered successfully\n",
+		fimc->index);
+	return 0;
+err_pm:
+	pm_runtime_put(&pdev->dev);
+err_sd:
+	fimc_lite_unregister_capture_subdev(fimc);
+err_clk:
+	fimc_lite_clk_put(fimc);
+	return ret;
+}
+
+static int fimc_lite_runtime_resume(struct device *dev)
+{
+	struct fimc_lite *fimc = dev_get_drvdata(dev);
+
+	clk_enable(fimc->clock);
+	return 0;
+}
+
+static int fimc_lite_runtime_suspend(struct device *dev)
+{
+	struct fimc_lite *fimc = dev_get_drvdata(dev);
+
+	clk_disable(fimc->clock);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int fimc_lite_resume(struct device *dev)
+{
+	struct fimc_lite *fimc = dev_get_drvdata(dev);
+	struct flite_buffer *buf;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	if (!test_and_clear_bit(ST_LPM, &fimc->state) ||
+	    !test_bit(ST_FLITE_IN_USE, &fimc->state)) {
+		spin_unlock_irqrestore(&fimc->slock, flags);
+		return 0;
+	}
+	flite_hw_reset(fimc);
+	spin_unlock_irqrestore(&fimc->slock, flags);
+
+	if (!test_and_clear_bit(ST_FLITE_SUSPENDED, &fimc->state))
+		return 0;
+
+	INIT_LIST_HEAD(&fimc->active_buf_q);
+	fimc_pipeline_initialize(&fimc->pipeline, &fimc->vfd->entity, false);
+	fimc_lite_hw_init(fimc);
+	clear_bit(ST_FLITE_SUSPENDED, &fimc->state);
+
+	for (i = 0; i < fimc->reqbufs_count; i++) {
+		if (list_empty(&fimc->pending_buf_q))
+			break;
+		buf = fimc_lite_pending_queue_pop(fimc);
+		buffer_queue(&buf->vb);
+	}
+	return 0;
+}
+
+static int fimc_lite_suspend(struct device *dev)
+{
+	struct fimc_lite *fimc = dev_get_drvdata(dev);
+	bool suspend = test_bit(ST_FLITE_IN_USE, &fimc->state);
+	int ret;
+
+	if (test_and_set_bit(ST_LPM, &fimc->state))
+		return 0;
+
+	ret = fimc_lite_stop_capture(fimc, suspend);
+	if (ret < 0 || !fimc_lite_active(fimc))
+		return ret;
+
+	return fimc_pipeline_shutdown(&fimc->pipeline);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static int __devexit fimc_lite_remove(struct platform_device *pdev)
+{
+	struct fimc_lite *fimc = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+
+	pm_runtime_disable(dev);
+	pm_runtime_set_suspended(dev);
+	fimc_lite_unregister_capture_subdev(fimc);
+	vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx);
+	fimc_lite_clk_put(fimc);
+
+	dev_info(dev, "Driver unloaded\n");
+	return 0;
+}
+
+static struct flite_variant fimc_lite0_variant_exynos4 = {
+	.max_width		= 8192,
+	.max_height		= 8192,
+	.out_width_align	= 8,
+	.win_hor_offs_align	= 2,
+	.out_hor_offs_align	= 8,
+};
+
+/* EXYNOS4212, EXYNOS4412 */
+static struct flite_drvdata fimc_lite_drvdata_exynos4 = {
+	.variant = {
+		[0] = &fimc_lite0_variant_exynos4,
+		[1] = &fimc_lite0_variant_exynos4,
+	},
+};
+
+static struct platform_device_id fimc_lite_driver_ids[] = {
+	{
+		.name		= "exynos-fimc-lite",
+		.driver_data	= (unsigned long)&fimc_lite_drvdata_exynos4,
+	},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, fimc_lite_driver_ids);
+
+static const struct dev_pm_ops fimc_lite_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(fimc_lite_suspend, fimc_lite_resume)
+	SET_RUNTIME_PM_OPS(fimc_lite_runtime_suspend, fimc_lite_runtime_resume,
+			   NULL)
+};
+
+static struct platform_driver fimc_lite_driver = {
+	.probe		= fimc_lite_probe,
+	.remove		= __devexit_p(fimc_lite_remove),
+	.id_table	= fimc_lite_driver_ids,
+	.driver = {
+		.name		= FIMC_LITE_DRV_NAME,
+		.owner		= THIS_MODULE,
+		.pm		= &fimc_lite_pm_ops,
+	}
+};
+module_platform_driver(fimc_lite_driver);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" FIMC_LITE_DRV_NAME);
diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.h b/drivers/media/platform/s5p-fimc/fimc-lite.h
new file mode 100644
index 0000000..44424ee
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-lite.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef FIMC_LITE_H_
+#define FIMC_LITE_H_
+
+#include <asm/sizes.h>
+#include <linux/io.h>
+#include <linux/irqreturn.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/media-entity.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/s5p_fimc.h>
+
+#include "fimc-core.h"
+
+#define FIMC_LITE_DRV_NAME	"exynos-fimc-lite"
+#define FLITE_CLK_NAME		"flite"
+#define FIMC_LITE_MAX_DEVS	2
+#define FLITE_REQ_BUFS_MIN	2
+
+/* Bit index definitions for struct fimc_lite::state */
+enum {
+	ST_FLITE_LPM,
+	ST_FLITE_PENDING,
+	ST_FLITE_RUN,
+	ST_FLITE_STREAM,
+	ST_FLITE_SUSPENDED,
+	ST_FLITE_OFF,
+	ST_FLITE_IN_USE,
+	ST_FLITE_CONFIG,
+	ST_SENSOR_STREAM,
+};
+
+#define FLITE_SD_PAD_SINK	0
+#define FLITE_SD_PAD_SOURCE	1
+#define FLITE_SD_PADS_NUM	2
+
+struct flite_variant {
+	unsigned short max_width;
+	unsigned short max_height;
+	unsigned short out_width_align;
+	unsigned short win_hor_offs_align;
+	unsigned short out_hor_offs_align;
+};
+
+struct flite_drvdata {
+	struct flite_variant *variant[FIMC_LITE_MAX_DEVS];
+};
+
+#define fimc_lite_get_drvdata(_pdev) \
+	((struct flite_drvdata *) platform_get_device_id(_pdev)->driver_data)
+
+struct fimc_lite_events {
+	unsigned int data_overflow;
+};
+
+#define FLITE_MAX_PLANES	1
+
+/**
+ * struct flite_frame - source/target frame properties
+ * @f_width: full pixel width
+ * @f_height: full pixel height
+ * @rect: crop/composition rectangle
+ */
+struct flite_frame {
+	u16 f_width;
+	u16 f_height;
+	struct v4l2_rect rect;
+};
+
+/**
+ * struct flite_buffer - video buffer structure
+ * @vb:    vb2 buffer
+ * @list:  list head for the buffers queue
+ * @paddr: precalculated physical address
+ */
+struct flite_buffer {
+	struct vb2_buffer vb;
+	struct list_head list;
+	dma_addr_t paddr;
+};
+
+/**
+ * struct fimc_lite - fimc lite structure
+ * @pdev: pointer to FIMC-LITE platform device
+ * @variant: variant information for this IP
+ * @v4l2_dev: pointer to top the level v4l2_device
+ * @vfd: video device node
+ * @fh: v4l2 file handle
+ * @alloc_ctx: videobuf2 memory allocator context
+ * @subdev: FIMC-LITE subdev
+ * @vd_pad: media (sink) pad for the capture video node
+ * @subdev_pads: the subdev media pads
+ * @ctrl_handler: v4l2 control handler
+ * @test_pattern: test pattern controls
+ * @index: FIMC-LITE platform device index
+ * @pipeline: video capture pipeline data structure
+ * @slock: spinlock protecting this data structure and the hw registers
+ * @lock: mutex serializing video device and the subdev operations
+ * @clock: FIMC-LITE gate clock
+ * @regs: memory mapped io registers
+ * @irq_queue: interrupt handler waitqueue
+ * @fmt: pointer to color format description structure
+ * @payload: image size in bytes (w x h x bpp)
+ * @inp_frame: camera input frame structure
+ * @out_frame: DMA output frame structure
+ * @out_path: output data path (DMA or FIFO)
+ * @source_subdev_grp_id: source subdev group id
+ * @state: driver state flags
+ * @pending_buf_q: pending buffers queue head
+ * @active_buf_q: the queue head of buffers scheduled in hardware
+ * @vb_queue: vb2 buffers queue
+ * @active_buf_count: number of video buffers scheduled in hardware
+ * @frame_count: the captured frames counter
+ * @reqbufs_count: the number of buffers requested with REQBUFS ioctl
+ * @ref_count: driver's private reference counter
+ */
+struct fimc_lite {
+	struct platform_device	*pdev;
+	struct flite_variant	*variant;
+	struct v4l2_device	*v4l2_dev;
+	struct video_device	*vfd;
+	struct v4l2_fh		fh;
+	struct vb2_alloc_ctx	*alloc_ctx;
+	struct v4l2_subdev	subdev;
+	struct media_pad	vd_pad;
+	struct media_pad	subdev_pads[FLITE_SD_PADS_NUM];
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct v4l2_ctrl	*test_pattern;
+	u32			index;
+	struct fimc_pipeline	pipeline;
+
+	struct mutex		lock;
+	spinlock_t		slock;
+
+	struct clk		*clock;
+	void __iomem		*regs;
+	wait_queue_head_t	irq_queue;
+
+	const struct fimc_fmt	*fmt;
+	unsigned long		payload[FLITE_MAX_PLANES];
+	struct flite_frame	inp_frame;
+	struct flite_frame	out_frame;
+	enum fimc_datapath	out_path;
+	unsigned int		source_subdev_grp_id;
+
+	unsigned long		state;
+	struct list_head	pending_buf_q;
+	struct list_head	active_buf_q;
+	struct vb2_queue	vb_queue;
+	unsigned int		frame_count;
+	unsigned int		reqbufs_count;
+	int			ref_count;
+
+	struct fimc_lite_events	events;
+};
+
+static inline bool fimc_lite_active(struct fimc_lite *fimc)
+{
+	unsigned long flags;
+	bool ret;
+
+	spin_lock_irqsave(&fimc->slock, flags);
+	ret = fimc->state & (1 << ST_FLITE_RUN) ||
+		fimc->state & (1 << ST_FLITE_PENDING);
+	spin_unlock_irqrestore(&fimc->slock, flags);
+	return ret;
+}
+
+static inline void fimc_lite_active_queue_add(struct fimc_lite *dev,
+					 struct flite_buffer *buf)
+{
+	list_add_tail(&buf->list, &dev->active_buf_q);
+}
+
+static inline struct flite_buffer *fimc_lite_active_queue_pop(
+					struct fimc_lite *dev)
+{
+	struct flite_buffer *buf = list_entry(dev->active_buf_q.next,
+					      struct flite_buffer, list);
+	list_del(&buf->list);
+	return buf;
+}
+
+static inline void fimc_lite_pending_queue_add(struct fimc_lite *dev,
+					struct flite_buffer *buf)
+{
+	list_add_tail(&buf->list, &dev->pending_buf_q);
+}
+
+static inline struct flite_buffer *fimc_lite_pending_queue_pop(
+					struct fimc_lite *dev)
+{
+	struct flite_buffer *buf = list_entry(dev->pending_buf_q.next,
+					      struct flite_buffer, list);
+	list_del(&buf->list);
+	return buf;
+}
+
+#endif /* FIMC_LITE_H_ */
diff --git a/drivers/media/platform/s5p-fimc/fimc-m2m.c b/drivers/media/platform/s5p-fimc/fimc-m2m.c
new file mode 100644
index 0000000..c587011
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-m2m.c
@@ -0,0 +1,854 @@
+/*
+ * Samsung S5P/EXYNOS4 SoC series FIMC (video postprocessor) driver
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 2 of the License,
+ * or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "fimc-core.h"
+#include "fimc-reg.h"
+#include "fimc-mdevice.h"
+
+
+static unsigned int get_m2m_fmt_flags(unsigned int stream_type)
+{
+	if (stream_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return FMT_FLAGS_M2M_IN;
+	else
+		return FMT_FLAGS_M2M_OUT;
+}
+
+void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state)
+{
+	struct vb2_buffer *src_vb, *dst_vb;
+
+	if (!ctx || !ctx->m2m_ctx)
+		return;
+
+	src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+	dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+
+	if (src_vb && dst_vb) {
+		v4l2_m2m_buf_done(src_vb, vb_state);
+		v4l2_m2m_buf_done(dst_vb, vb_state);
+		v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev,
+				    ctx->m2m_ctx);
+	}
+}
+
+/* Complete the transaction which has been scheduled for execution. */
+static int fimc_m2m_shutdown(struct fimc_ctx *ctx)
+{
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	int ret;
+
+	if (!fimc_m2m_pending(fimc))
+		return 0;
+
+	fimc_ctx_state_set(FIMC_CTX_SHUT, ctx);
+
+	ret = wait_event_timeout(fimc->irq_queue,
+			   !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx),
+			   FIMC_SHUTDOWN_TIMEOUT);
+
+	return ret == 0 ? -ETIMEDOUT : ret;
+}
+
+static int start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct fimc_ctx *ctx = q->drv_priv;
+	int ret;
+
+	ret = pm_runtime_get_sync(&ctx->fimc_dev->pdev->dev);
+	return ret > 0 ? 0 : ret;
+}
+
+static int stop_streaming(struct vb2_queue *q)
+{
+	struct fimc_ctx *ctx = q->drv_priv;
+	int ret;
+
+	ret = fimc_m2m_shutdown(ctx);
+	if (ret == -ETIMEDOUT)
+		fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+
+	pm_runtime_put(&ctx->fimc_dev->pdev->dev);
+	return 0;
+}
+
+static void fimc_device_run(void *priv)
+{
+	struct vb2_buffer *vb = NULL;
+	struct fimc_ctx *ctx = priv;
+	struct fimc_frame *sf, *df;
+	struct fimc_dev *fimc;
+	unsigned long flags;
+	u32 ret;
+
+	if (WARN(!ctx, "Null context\n"))
+		return;
+
+	fimc = ctx->fimc_dev;
+	spin_lock_irqsave(&fimc->slock, flags);
+
+	set_bit(ST_M2M_PEND, &fimc->state);
+	sf = &ctx->s_frame;
+	df = &ctx->d_frame;
+
+	if (ctx->state & FIMC_PARAMS) {
+		/* Prepare the DMA offsets for scaler */
+		fimc_prepare_dma_offset(ctx, sf);
+		fimc_prepare_dma_offset(ctx, df);
+	}
+
+	vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	ret = fimc_prepare_addr(ctx, vb, sf, &sf->paddr);
+	if (ret)
+		goto dma_unlock;
+
+	vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+	ret = fimc_prepare_addr(ctx, vb, df, &df->paddr);
+	if (ret)
+		goto dma_unlock;
+
+	/* Reconfigure hardware if the context has changed. */
+	if (fimc->m2m.ctx != ctx) {
+		ctx->state |= FIMC_PARAMS;
+		fimc->m2m.ctx = ctx;
+	}
+
+	if (ctx->state & FIMC_PARAMS) {
+		fimc_set_yuv_order(ctx);
+		fimc_hw_set_input_path(ctx);
+		fimc_hw_set_in_dma(ctx);
+		ret = fimc_set_scaler_info(ctx);
+		if (ret)
+			goto dma_unlock;
+		fimc_hw_set_prescaler(ctx);
+		fimc_hw_set_mainscaler(ctx);
+		fimc_hw_set_target_format(ctx);
+		fimc_hw_set_rotation(ctx);
+		fimc_hw_set_effect(ctx);
+		fimc_hw_set_out_dma(ctx);
+		if (fimc->variant->has_alpha)
+			fimc_hw_set_rgb_alpha(ctx);
+		fimc_hw_set_output_path(ctx);
+	}
+	fimc_hw_set_input_addr(fimc, &sf->paddr);
+	fimc_hw_set_output_addr(fimc, &df->paddr, -1);
+
+	fimc_activate_capture(ctx);
+	ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP |
+		       FIMC_SRC_FMT | FIMC_DST_FMT);
+	fimc_hw_activate_input_dma(fimc, true);
+
+dma_unlock:
+	spin_unlock_irqrestore(&fimc->slock, flags);
+}
+
+static void fimc_job_abort(void *priv)
+{
+	fimc_m2m_shutdown(priv);
+}
+
+static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+			    unsigned int *num_buffers, unsigned int *num_planes,
+			    unsigned int sizes[], void *allocators[])
+{
+	struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
+	struct fimc_frame *f;
+	int i;
+
+	f = ctx_get_frame(ctx, vq->type);
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+	/*
+	 * Return number of non-contigous planes (plane buffers)
+	 * depending on the configured color format.
+	 */
+	if (!f->fmt)
+		return -EINVAL;
+
+	*num_planes = f->fmt->memplanes;
+	for (i = 0; i < f->fmt->memplanes; i++) {
+		sizes[i] = (f->f_width * f->f_height * f->fmt->depth[i]) / 8;
+		allocators[i] = ctx->fimc_dev->alloc_ctx;
+	}
+	return 0;
+}
+
+static int fimc_buf_prepare(struct vb2_buffer *vb)
+{
+	struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct fimc_frame *frame;
+	int i;
+
+	frame = ctx_get_frame(ctx, vb->vb2_queue->type);
+	if (IS_ERR(frame))
+		return PTR_ERR(frame);
+
+	for (i = 0; i < frame->fmt->memplanes; i++)
+		vb2_set_plane_payload(vb, i, frame->payload[i]);
+
+	return 0;
+}
+
+static void fimc_buf_queue(struct vb2_buffer *vb)
+{
+	struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+	dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
+
+	if (ctx->m2m_ctx)
+		v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static void fimc_lock(struct vb2_queue *vq)
+{
+	struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
+	mutex_lock(&ctx->fimc_dev->lock);
+}
+
+static void fimc_unlock(struct vb2_queue *vq)
+{
+	struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
+	mutex_unlock(&ctx->fimc_dev->lock);
+}
+
+static struct vb2_ops fimc_qops = {
+	.queue_setup	 = fimc_queue_setup,
+	.buf_prepare	 = fimc_buf_prepare,
+	.buf_queue	 = fimc_buf_queue,
+	.wait_prepare	 = fimc_unlock,
+	.wait_finish	 = fimc_lock,
+	.stop_streaming	 = stop_streaming,
+	.start_streaming = start_streaming,
+};
+
+/*
+ * V4L2 ioctl handlers
+ */
+static int fimc_m2m_querycap(struct file *file, void *fh,
+			     struct v4l2_capability *cap)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+	struct fimc_dev *fimc = ctx->fimc_dev;
+
+	strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
+	strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
+	cap->bus_info[0] = 0;
+	/*
+	 * This is only a mem-to-mem video device. The capture and output
+	 * device capability flags are left only for backward compatibility
+	 * and are scheduled for removal.
+	 */
+	cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE |
+		V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+
+	return 0;
+}
+
+static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv,
+				    struct v4l2_fmtdesc *f)
+{
+	struct fimc_fmt *fmt;
+
+	fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type),
+			       f->index);
+	if (!fmt)
+		return -EINVAL;
+
+	strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+	f->pixelformat = fmt->fourcc;
+	return 0;
+}
+
+static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh,
+				 struct v4l2_format *f)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+	struct fimc_frame *frame = ctx_get_frame(ctx, f->type);
+
+	if (IS_ERR(frame))
+		return PTR_ERR(frame);
+
+	return fimc_fill_format(frame, f);
+}
+
+static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f)
+{
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	struct fimc_variant *variant = fimc->variant;
+	struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+	struct fimc_fmt *fmt;
+	u32 max_w, mod_x, mod_y;
+
+	if (!IS_M2M(f->type))
+		return -EINVAL;
+
+	dbg("w: %d, h: %d", pix->width, pix->height);
+
+	fmt = fimc_find_format(&pix->pixelformat, NULL,
+			       get_m2m_fmt_flags(f->type), 0);
+	if (WARN(fmt == NULL, "Pixel format lookup failed"))
+		return -EINVAL;
+
+	if (pix->field == V4L2_FIELD_ANY)
+		pix->field = V4L2_FIELD_NONE;
+	else if (pix->field != V4L2_FIELD_NONE)
+		return -EINVAL;
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		max_w = variant->pix_limit->scaler_dis_w;
+		mod_x = ffs(variant->min_inp_pixsize) - 1;
+	} else {
+		max_w = variant->pix_limit->out_rot_dis_w;
+		mod_x = ffs(variant->min_out_pixsize) - 1;
+	}
+
+	if (tiled_fmt(fmt)) {
+		mod_x = 6; /* 64 x 32 pixels tile */
+		mod_y = 5;
+	} else {
+		if (variant->min_vsize_align == 1)
+			mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1;
+		else
+			mod_y = ffs(variant->min_vsize_align) - 1;
+	}
+
+	v4l_bound_align_image(&pix->width, 16, max_w, mod_x,
+		&pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0);
+
+	fimc_adjust_mplane_format(fmt, pix->width, pix->height, &f->fmt.pix_mp);
+	return 0;
+}
+
+static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh,
+				   struct v4l2_format *f)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+	return fimc_try_fmt_mplane(ctx, f);
+}
+
+static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
+				 struct v4l2_format *f)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	struct vb2_queue *vq;
+	struct fimc_frame *frame;
+	struct v4l2_pix_format_mplane *pix;
+	int i, ret = 0;
+
+	ret = fimc_try_fmt_mplane(ctx, f);
+	if (ret)
+		return ret;
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+
+	if (vb2_is_busy(vq)) {
+		v4l2_err(fimc->m2m.vfd, "queue (%d) busy\n", f->type);
+		return -EBUSY;
+	}
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		frame = &ctx->s_frame;
+	else
+		frame = &ctx->d_frame;
+
+	pix = &f->fmt.pix_mp;
+	frame->fmt = fimc_find_format(&pix->pixelformat, NULL,
+				      get_m2m_fmt_flags(f->type), 0);
+	if (!frame->fmt)
+		return -EINVAL;
+
+	/* Update RGB Alpha control state and value range */
+	fimc_alpha_ctrl_update(ctx);
+
+	for (i = 0; i < frame->fmt->colplanes; i++) {
+		frame->payload[i] =
+			(pix->width * pix->height * frame->fmt->depth[i]) / 8;
+	}
+
+	fimc_fill_frame(frame, f);
+
+	ctx->scaler.enabled = 1;
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		fimc_ctx_state_set(FIMC_PARAMS | FIMC_DST_FMT, ctx);
+	else
+		fimc_ctx_state_set(FIMC_PARAMS | FIMC_SRC_FMT, ctx);
+
+	dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height);
+
+	return 0;
+}
+
+static int fimc_m2m_reqbufs(struct file *file, void *fh,
+			    struct v4l2_requestbuffers *reqbufs)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int fimc_m2m_querybuf(struct file *file, void *fh,
+			     struct v4l2_buffer *buf)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int fimc_m2m_qbuf(struct file *file, void *fh,
+			 struct v4l2_buffer *buf)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int fimc_m2m_dqbuf(struct file *file, void *fh,
+			  struct v4l2_buffer *buf)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int fimc_m2m_streamon(struct file *file, void *fh,
+			     enum v4l2_buf_type type)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+	/* The source and target color format need to be set */
+	if (V4L2_TYPE_IS_OUTPUT(type)) {
+		if (!fimc_ctx_state_is_set(FIMC_SRC_FMT, ctx))
+			return -EINVAL;
+	} else if (!fimc_ctx_state_is_set(FIMC_DST_FMT, ctx)) {
+		return -EINVAL;
+	}
+
+	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int fimc_m2m_streamoff(struct file *file, void *fh,
+			    enum v4l2_buf_type type)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static int fimc_m2m_cropcap(struct file *file, void *fh,
+			    struct v4l2_cropcap *cr)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+	struct fimc_frame *frame;
+
+	frame = ctx_get_frame(ctx, cr->type);
+	if (IS_ERR(frame))
+		return PTR_ERR(frame);
+
+	cr->bounds.left = 0;
+	cr->bounds.top = 0;
+	cr->bounds.width = frame->o_width;
+	cr->bounds.height = frame->o_height;
+	cr->defrect = cr->bounds;
+
+	return 0;
+}
+
+static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+	struct fimc_frame *frame;
+
+	frame = ctx_get_frame(ctx, cr->type);
+	if (IS_ERR(frame))
+		return PTR_ERR(frame);
+
+	cr->c.left = frame->offs_h;
+	cr->c.top = frame->offs_v;
+	cr->c.width = frame->width;
+	cr->c.height = frame->height;
+
+	return 0;
+}
+
+static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
+{
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	struct fimc_frame *f;
+	u32 min_size, halign, depth = 0;
+	int i;
+
+	if (cr->c.top < 0 || cr->c.left < 0) {
+		v4l2_err(fimc->m2m.vfd,
+			"doesn't support negative values for top & left\n");
+		return -EINVAL;
+	}
+	if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		f = &ctx->d_frame;
+	else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		f = &ctx->s_frame;
+	else
+		return -EINVAL;
+
+	min_size = (f == &ctx->s_frame) ?
+		fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
+
+	/* Get pixel alignment constraints. */
+	if (fimc->variant->min_vsize_align == 1)
+		halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
+	else
+		halign = ffs(fimc->variant->min_vsize_align) - 1;
+
+	for (i = 0; i < f->fmt->colplanes; i++)
+		depth += f->fmt->depth[i];
+
+	v4l_bound_align_image(&cr->c.width, min_size, f->o_width,
+			      ffs(min_size) - 1,
+			      &cr->c.height, min_size, f->o_height,
+			      halign, 64/(ALIGN(depth, 8)));
+
+	/* adjust left/top if cropping rectangle is out of bounds */
+	if (cr->c.left + cr->c.width > f->o_width)
+		cr->c.left = f->o_width - cr->c.width;
+	if (cr->c.top + cr->c.height > f->o_height)
+		cr->c.top = f->o_height - cr->c.height;
+
+	cr->c.left = round_down(cr->c.left, min_size);
+	cr->c.top  = round_down(cr->c.top, fimc->variant->hor_offs_align);
+
+	dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
+	    cr->c.left, cr->c.top, cr->c.width, cr->c.height,
+	    f->f_width, f->f_height);
+
+	return 0;
+}
+
+static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(fh);
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	struct fimc_frame *f;
+	int ret;
+
+	ret = fimc_m2m_try_crop(ctx, cr);
+	if (ret)
+		return ret;
+
+	f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
+		&ctx->s_frame : &ctx->d_frame;
+
+	/* Check to see if scaling ratio is within supported range */
+	if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) {
+		if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+			ret = fimc_check_scaler_ratio(ctx, cr->c.width,
+					cr->c.height, ctx->d_frame.width,
+					ctx->d_frame.height, ctx->rotation);
+		} else {
+			ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
+					ctx->s_frame.height, cr->c.width,
+					cr->c.height, ctx->rotation);
+		}
+		if (ret) {
+			v4l2_err(fimc->m2m.vfd, "Out of scaler range\n");
+			return -EINVAL;
+		}
+	}
+
+	f->offs_h = cr->c.left;
+	f->offs_v = cr->c.top;
+	f->width  = cr->c.width;
+	f->height = cr->c.height;
+
+	fimc_ctx_state_set(FIMC_PARAMS, ctx);
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
+	.vidioc_querycap		= fimc_m2m_querycap,
+	.vidioc_enum_fmt_vid_cap_mplane	= fimc_m2m_enum_fmt_mplane,
+	.vidioc_enum_fmt_vid_out_mplane	= fimc_m2m_enum_fmt_mplane,
+	.vidioc_g_fmt_vid_cap_mplane	= fimc_m2m_g_fmt_mplane,
+	.vidioc_g_fmt_vid_out_mplane	= fimc_m2m_g_fmt_mplane,
+	.vidioc_try_fmt_vid_cap_mplane	= fimc_m2m_try_fmt_mplane,
+	.vidioc_try_fmt_vid_out_mplane	= fimc_m2m_try_fmt_mplane,
+	.vidioc_s_fmt_vid_cap_mplane	= fimc_m2m_s_fmt_mplane,
+	.vidioc_s_fmt_vid_out_mplane	= fimc_m2m_s_fmt_mplane,
+	.vidioc_reqbufs			= fimc_m2m_reqbufs,
+	.vidioc_querybuf		= fimc_m2m_querybuf,
+	.vidioc_qbuf			= fimc_m2m_qbuf,
+	.vidioc_dqbuf			= fimc_m2m_dqbuf,
+	.vidioc_streamon		= fimc_m2m_streamon,
+	.vidioc_streamoff		= fimc_m2m_streamoff,
+	.vidioc_g_crop			= fimc_m2m_g_crop,
+	.vidioc_s_crop			= fimc_m2m_s_crop,
+	.vidioc_cropcap			= fimc_m2m_cropcap
+
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+		      struct vb2_queue *dst_vq)
+{
+	struct fimc_ctx *ctx = priv;
+	int ret;
+
+	memset(src_vq, 0, sizeof(*src_vq));
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+	src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+	src_vq->drv_priv = ctx;
+	src_vq->ops = &fimc_qops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	memset(dst_vq, 0, sizeof(*dst_vq));
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+	dst_vq->drv_priv = ctx;
+	dst_vq->ops = &fimc_qops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+	return vb2_queue_init(dst_vq);
+}
+
+static int fimc_m2m_open(struct file *file)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+	struct fimc_ctx *ctx;
+	int ret = -EBUSY;
+
+	dbg("pid: %d, state: 0x%lx, refcnt: %d",
+	    task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt);
+
+	if (mutex_lock_interruptible(&fimc->lock))
+		return -ERESTARTSYS;
+	/*
+	 * Return if the corresponding video capture node
+	 * is already opened.
+	 */
+	if (fimc->vid_cap.refcnt > 0)
+		goto unlock;
+
+	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+	if (!ctx) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+	v4l2_fh_init(&ctx->fh, fimc->m2m.vfd);
+	ctx->fimc_dev = fimc;
+
+	/* Default color format */
+	ctx->s_frame.fmt = fimc_get_format(0);
+	ctx->d_frame.fmt = fimc_get_format(0);
+
+	ret = fimc_ctrls_create(ctx);
+	if (ret)
+		goto error_fh;
+
+	/* Use separate control handler per file handle */
+	ctx->fh.ctrl_handler = &ctx->ctrls.handler;
+	file->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh);
+
+	/* Setup the device context for memory-to-memory mode */
+	ctx->state = FIMC_CTX_M2M;
+	ctx->flags = 0;
+	ctx->in_path = FIMC_IO_DMA;
+	ctx->out_path = FIMC_IO_DMA;
+
+	ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init);
+	if (IS_ERR(ctx->m2m_ctx)) {
+		ret = PTR_ERR(ctx->m2m_ctx);
+		goto error_c;
+	}
+
+	if (fimc->m2m.refcnt++ == 0)
+		set_bit(ST_M2M_RUN, &fimc->state);
+
+	mutex_unlock(&fimc->lock);
+	return 0;
+
+error_c:
+	fimc_ctrls_delete(ctx);
+error_fh:
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+unlock:
+	mutex_unlock(&fimc->lock);
+	return ret;
+}
+
+static int fimc_m2m_release(struct file *file)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
+	struct fimc_dev *fimc = ctx->fimc_dev;
+
+	dbg("pid: %d, state: 0x%lx, refcnt= %d",
+		task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
+
+	if (mutex_lock_interruptible(&fimc->lock))
+		return -ERESTARTSYS;
+
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+	fimc_ctrls_delete(ctx);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+
+	if (--fimc->m2m.refcnt <= 0)
+		clear_bit(ST_M2M_RUN, &fimc->state);
+	kfree(ctx);
+
+	mutex_unlock(&fimc->lock);
+	return 0;
+}
+
+static unsigned int fimc_m2m_poll(struct file *file,
+				  struct poll_table_struct *wait)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	int ret;
+
+	if (mutex_lock_interruptible(&fimc->lock))
+		return -ERESTARTSYS;
+
+	ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+	mutex_unlock(&fimc->lock);
+
+	return ret;
+}
+
+
+static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
+	struct fimc_dev *fimc = ctx->fimc_dev;
+	int ret;
+
+	if (mutex_lock_interruptible(&fimc->lock))
+		return -ERESTARTSYS;
+
+	ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+	mutex_unlock(&fimc->lock);
+
+	return ret;
+}
+
+static const struct v4l2_file_operations fimc_m2m_fops = {
+	.owner		= THIS_MODULE,
+	.open		= fimc_m2m_open,
+	.release	= fimc_m2m_release,
+	.poll		= fimc_m2m_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= fimc_m2m_mmap,
+};
+
+static struct v4l2_m2m_ops m2m_ops = {
+	.device_run	= fimc_device_run,
+	.job_abort	= fimc_job_abort,
+};
+
+int fimc_register_m2m_device(struct fimc_dev *fimc,
+			     struct v4l2_device *v4l2_dev)
+{
+	struct video_device *vfd;
+	struct platform_device *pdev;
+	int ret = 0;
+
+	if (!fimc)
+		return -ENODEV;
+
+	pdev = fimc->pdev;
+	fimc->v4l2_dev = v4l2_dev;
+
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(v4l2_dev, "Failed to allocate video device\n");
+		return -ENOMEM;
+	}
+
+	vfd->fops = &fimc_m2m_fops;
+	vfd->ioctl_ops = &fimc_m2m_ioctl_ops;
+	vfd->v4l2_dev = v4l2_dev;
+	vfd->minor = -1;
+	vfd->release = video_device_release;
+	vfd->lock = &fimc->lock;
+
+	snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id);
+	video_set_drvdata(vfd, fimc);
+
+	fimc->m2m.vfd = vfd;
+	fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops);
+	if (IS_ERR(fimc->m2m.m2m_dev)) {
+		v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n");
+		ret = PTR_ERR(fimc->m2m.m2m_dev);
+		goto err_init;
+	}
+
+	ret = media_entity_init(&vfd->entity, 0, NULL, 0);
+	if (ret)
+		goto err_me;
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+	if (ret)
+		goto err_vd;
+
+	v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",
+		  vfd->name, video_device_node_name(vfd));
+	return 0;
+
+err_vd:
+	media_entity_cleanup(&vfd->entity);
+err_me:
+	v4l2_m2m_release(fimc->m2m.m2m_dev);
+err_init:
+	video_device_release(fimc->m2m.vfd);
+	return ret;
+}
+
+void fimc_unregister_m2m_device(struct fimc_dev *fimc)
+{
+	if (!fimc)
+		return;
+
+	if (fimc->m2m.m2m_dev)
+		v4l2_m2m_release(fimc->m2m.m2m_dev);
+	if (fimc->m2m.vfd) {
+		media_entity_cleanup(&fimc->m2m.vfd->entity);
+		/* Can also be called if video device wasn't registered */
+		video_unregister_device(fimc->m2m.vfd);
+	}
+}
diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c
new file mode 100644
index 0000000..e65bb28
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c
@@ -0,0 +1,1037 @@
+/*
+ * S5P/EXYNOS4 SoC series camera host interface media device driver
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 2 of the License,
+ * or (at your option) any later version.
+ */
+
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <media/v4l2-ctrls.h>
+#include <media/media-device.h>
+
+#include "fimc-core.h"
+#include "fimc-lite.h"
+#include "fimc-mdevice.h"
+#include "mipi-csis.h"
+
+static int __fimc_md_set_camclk(struct fimc_md *fmd,
+				struct fimc_sensor_info *s_info,
+				bool on);
+/**
+ * fimc_pipeline_prepare - update pipeline information with subdevice pointers
+ * @fimc: fimc device terminating the pipeline
+ *
+ * Caller holds the graph mutex.
+ */
+void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_entity *me)
+{
+	struct media_pad *pad = &me->pads[0];
+	struct v4l2_subdev *sd;
+	int i;
+
+	for (i = 0; i < IDX_MAX; i++)
+		p->subdevs[i] = NULL;
+
+	while (1) {
+		if (!(pad->flags & MEDIA_PAD_FL_SINK))
+			break;
+
+		/* source pad */
+		pad = media_entity_remote_source(pad);
+		if (pad == NULL ||
+		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+			break;
+
+		sd = media_entity_to_v4l2_subdev(pad->entity);
+
+		switch (sd->grp_id) {
+		case SENSOR_GROUP_ID:
+			p->subdevs[IDX_SENSOR] = sd;
+			break;
+		case CSIS_GROUP_ID:
+			p->subdevs[IDX_CSIS] = sd;
+			break;
+		case FLITE_GROUP_ID:
+			p->subdevs[IDX_FLITE] = sd;
+			break;
+		case FIMC_GROUP_ID:
+			/* No need to control FIMC subdev through subdev ops */
+			break;
+		default:
+			pr_warn("%s: Unknown subdev grp_id: %#x\n",
+				__func__, sd->grp_id);
+		}
+		/* sink pad */
+		pad = &sd->entity.pads[0];
+	}
+}
+
+/**
+ * __subdev_set_power - change power state of a single subdev
+ * @sd: subdevice to change power state for
+ * @on: 1 to enable power or 0 to disable
+ *
+ * Return result of s_power subdev operation or -ENXIO if sd argument
+ * is NULL. Return 0 if the subdevice does not implement s_power.
+ */
+static int __subdev_set_power(struct v4l2_subdev *sd, int on)
+{
+	int *use_count;
+	int ret;
+
+	if (sd == NULL)
+		return -ENXIO;
+
+	use_count = &sd->entity.use_count;
+	if (on && (*use_count)++ > 0)
+		return 0;
+	else if (!on && (*use_count == 0 || --(*use_count) > 0))
+		return 0;
+	ret = v4l2_subdev_call(sd, core, s_power, on);
+
+	return ret != -ENOIOCTLCMD ? ret : 0;
+}
+
+/**
+ * fimc_pipeline_s_power - change power state of all pipeline subdevs
+ * @fimc: fimc device terminating the pipeline
+ * @state: true to power on, false to power off
+ *
+ * Needs to be called with the graph mutex held.
+ */
+int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state)
+{
+	unsigned int i;
+	int ret;
+
+	if (p->subdevs[IDX_SENSOR] == NULL)
+		return -ENXIO;
+
+	for (i = 0; i < IDX_MAX; i++) {
+		unsigned int idx = state ? (IDX_MAX - 1) - i : i;
+
+		ret = __subdev_set_power(p->subdevs[idx], state);
+		if (ret < 0 && ret != -ENXIO)
+			return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * __fimc_pipeline_initialize - update the pipeline information, enable power
+ *                              of all pipeline subdevs and the sensor clock
+ * @me: media entity to start graph walk with
+ * @prep: true to acquire sensor (and csis) subdevs
+ *
+ * This function must be called with the graph mutex held.
+ */
+static int __fimc_pipeline_initialize(struct fimc_pipeline *p,
+				      struct media_entity *me, bool prep)
+{
+	int ret;
+
+	if (prep)
+		fimc_pipeline_prepare(p, me);
+
+	if (p->subdevs[IDX_SENSOR] == NULL)
+		return -EINVAL;
+
+	ret = fimc_md_set_camclk(p->subdevs[IDX_SENSOR], true);
+	if (ret)
+		return ret;
+
+	return fimc_pipeline_s_power(p, 1);
+}
+
+int fimc_pipeline_initialize(struct fimc_pipeline *p, struct media_entity *me,
+			     bool prep)
+{
+	int ret;
+
+	mutex_lock(&me->parent->graph_mutex);
+	ret =  __fimc_pipeline_initialize(p, me, prep);
+	mutex_unlock(&me->parent->graph_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(fimc_pipeline_initialize);
+
+/**
+ * __fimc_pipeline_shutdown - disable the sensor clock and pipeline power
+ * @fimc: fimc device terminating the pipeline
+ *
+ * Disable power of all subdevs in the pipeline and turn off the external
+ * sensor clock.
+ * Called with the graph mutex held.
+ */
+static int __fimc_pipeline_shutdown(struct fimc_pipeline *p)
+{
+	int ret = 0;
+
+	if (p->subdevs[IDX_SENSOR]) {
+		ret = fimc_pipeline_s_power(p, 0);
+		fimc_md_set_camclk(p->subdevs[IDX_SENSOR], false);
+	}
+	return ret == -ENXIO ? 0 : ret;
+}
+
+int fimc_pipeline_shutdown(struct fimc_pipeline *p)
+{
+	struct media_entity *me;
+	int ret;
+
+	if (!p || !p->subdevs[IDX_SENSOR])
+		return -EINVAL;
+
+	me = &p->subdevs[IDX_SENSOR]->entity;
+	mutex_lock(&me->parent->graph_mutex);
+	ret = __fimc_pipeline_shutdown(p);
+	mutex_unlock(&me->parent->graph_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(fimc_pipeline_shutdown);
+
+/**
+ * fimc_pipeline_s_stream - invoke s_stream on pipeline subdevs
+ * @pipeline: video pipeline structure
+ * @on: passed as the s_stream call argument
+ */
+int fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on)
+{
+	int i, ret;
+
+	if (p->subdevs[IDX_SENSOR] == NULL)
+		return -ENODEV;
+
+	for (i = 0; i < IDX_MAX; i++) {
+		unsigned int idx = on ? (IDX_MAX - 1) - i : i;
+
+		ret = v4l2_subdev_call(p->subdevs[idx], video, s_stream, on);
+
+		if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
+			return ret;
+	}
+
+	return 0;
+
+}
+EXPORT_SYMBOL_GPL(fimc_pipeline_s_stream);
+
+/*
+ * Sensor subdevice helper functions
+ */
+static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd,
+				   struct fimc_sensor_info *s_info)
+{
+	struct i2c_adapter *adapter;
+	struct v4l2_subdev *sd = NULL;
+
+	if (!s_info || !fmd)
+		return NULL;
+
+	adapter = i2c_get_adapter(s_info->pdata->i2c_bus_num);
+	if (!adapter) {
+		v4l2_warn(&fmd->v4l2_dev,
+			  "Failed to get I2C adapter %d, deferring probe\n",
+			  s_info->pdata->i2c_bus_num);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+	sd = v4l2_i2c_new_subdev_board(&fmd->v4l2_dev, adapter,
+				       s_info->pdata->board_info, NULL);
+	if (IS_ERR_OR_NULL(sd)) {
+		i2c_put_adapter(adapter);
+		v4l2_warn(&fmd->v4l2_dev,
+			  "Failed to acquire subdev %s, deferring probe\n",
+			  s_info->pdata->board_info->type);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+	v4l2_set_subdev_hostdata(sd, s_info);
+	sd->grp_id = SENSOR_GROUP_ID;
+
+	v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice %s\n",
+		  s_info->pdata->board_info->type);
+	return sd;
+}
+
+static void fimc_md_unregister_sensor(struct v4l2_subdev *sd)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct i2c_adapter *adapter;
+
+	if (!client)
+		return;
+	v4l2_device_unregister_subdev(sd);
+	adapter = client->adapter;
+	i2c_unregister_device(client);
+	if (adapter)
+		i2c_put_adapter(adapter);
+}
+
+static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
+{
+	struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data;
+	struct fimc_dev *fd = NULL;
+	int num_clients, ret, i;
+
+	/*
+	 * Runtime resume one of the FIMC entities to make sure
+	 * the sclk_cam clocks are not globally disabled.
+	 */
+	for (i = 0; !fd && i < ARRAY_SIZE(fmd->fimc); i++)
+		if (fmd->fimc[i])
+			fd = fmd->fimc[i];
+	if (!fd)
+		return -ENXIO;
+	ret = pm_runtime_get_sync(&fd->pdev->dev);
+	if (ret < 0)
+		return ret;
+
+	WARN_ON(pdata->num_clients > ARRAY_SIZE(fmd->sensor));
+	num_clients = min_t(u32, pdata->num_clients, ARRAY_SIZE(fmd->sensor));
+
+	fmd->num_sensors = num_clients;
+	for (i = 0; i < num_clients; i++) {
+		struct v4l2_subdev *sd;
+
+		fmd->sensor[i].pdata = &pdata->isp_info[i];
+		ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], true);
+		if (ret)
+			break;
+		sd = fimc_md_register_sensor(fmd, &fmd->sensor[i]);
+		ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], false);
+
+		if (!IS_ERR(sd)) {
+			fmd->sensor[i].subdev = sd;
+		} else {
+			fmd->sensor[i].subdev = NULL;
+			ret = PTR_ERR(sd);
+			break;
+		}
+		if (ret)
+			break;
+	}
+	pm_runtime_put(&fd->pdev->dev);
+	return ret;
+}
+
+/*
+ * MIPI CSIS and FIMC platform devices registration.
+ */
+static int fimc_register_callback(struct device *dev, void *p)
+{
+	struct fimc_dev *fimc = dev_get_drvdata(dev);
+	struct v4l2_subdev *sd = &fimc->vid_cap.subdev;
+	struct fimc_md *fmd = p;
+	int ret = 0;
+
+	if (!fimc || !fimc->pdev)
+		return 0;
+
+	if (fimc->pdev->id < 0 || fimc->pdev->id >= FIMC_MAX_DEVS)
+		return 0;
+
+	fmd->fimc[fimc->pdev->id] = fimc;
+	sd->grp_id = FIMC_GROUP_ID;
+
+	ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
+	if (ret) {
+		v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.%d (%d)\n",
+			 fimc->id, ret);
+	}
+
+	return ret;
+}
+
+static int fimc_lite_register_callback(struct device *dev, void *p)
+{
+	struct fimc_lite *fimc = dev_get_drvdata(dev);
+	struct v4l2_subdev *sd = &fimc->subdev;
+	struct fimc_md *fmd = p;
+	int ret;
+
+	if (fimc == NULL)
+		return 0;
+
+	if (fimc->index >= FIMC_LITE_MAX_DEVS)
+		return 0;
+
+	fmd->fimc_lite[fimc->index] = fimc;
+	sd->grp_id = FLITE_GROUP_ID;
+
+	ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
+	if (ret) {
+		v4l2_err(&fmd->v4l2_dev,
+			 "Failed to register FIMC-LITE.%d (%d)\n",
+			 fimc->index, ret);
+	}
+	return ret;
+}
+
+static int csis_register_callback(struct device *dev, void *p)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct platform_device *pdev;
+	struct fimc_md *fmd = p;
+	int id, ret;
+
+	if (!sd)
+		return 0;
+	pdev = v4l2_get_subdevdata(sd);
+	if (!pdev || pdev->id < 0 || pdev->id >= CSIS_MAX_ENTITIES)
+		return 0;
+	v4l2_info(sd, "csis%d sd: %s\n", pdev->id, sd->name);
+
+	id = pdev->id < 0 ? 0 : pdev->id;
+	fmd->csis[id].sd = sd;
+	sd->grp_id = CSIS_GROUP_ID;
+	ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
+	if (ret)
+		v4l2_err(&fmd->v4l2_dev,
+			 "Failed to register CSIS subdevice: %d\n", ret);
+	return ret;
+}
+
+/**
+ * fimc_md_register_platform_entities - register FIMC and CSIS media entities
+ */
+static int fimc_md_register_platform_entities(struct fimc_md *fmd)
+{
+	struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data;
+	struct device_driver *driver;
+	int ret, i;
+
+	driver = driver_find(FIMC_MODULE_NAME, &platform_bus_type);
+	if (!driver) {
+		v4l2_warn(&fmd->v4l2_dev,
+			 "%s driver not found, deffering probe\n",
+			 FIMC_MODULE_NAME);
+		return -EPROBE_DEFER;
+	}
+
+	ret = driver_for_each_device(driver, NULL, fmd,
+				     fimc_register_callback);
+	if (ret)
+		return ret;
+
+	driver = driver_find(FIMC_LITE_DRV_NAME, &platform_bus_type);
+	if (driver && try_module_get(driver->owner)) {
+		ret = driver_for_each_device(driver, NULL, fmd,
+					     fimc_lite_register_callback);
+		if (ret)
+			return ret;
+		module_put(driver->owner);
+	}
+	/*
+	 * Check if there is any sensor on the MIPI-CSI2 bus and
+	 * if not skip the s5p-csis module loading.
+	 */
+	if (pdata == NULL)
+		return 0;
+	for (i = 0; i < pdata->num_clients; i++) {
+		if (pdata->isp_info[i].bus_type == FIMC_MIPI_CSI2) {
+			ret = 1;
+			break;
+		}
+	}
+	if (!ret)
+		return 0;
+
+	driver = driver_find(CSIS_DRIVER_NAME, &platform_bus_type);
+	if (!driver || !try_module_get(driver->owner)) {
+		v4l2_warn(&fmd->v4l2_dev,
+			 "%s driver not found, deffering probe\n",
+			 CSIS_DRIVER_NAME);
+		return -EPROBE_DEFER;
+	}
+
+	return driver_for_each_device(driver, NULL, fmd,
+				      csis_register_callback);
+}
+
+static void fimc_md_unregister_entities(struct fimc_md *fmd)
+{
+	int i;
+
+	for (i = 0; i < FIMC_MAX_DEVS; i++) {
+		if (fmd->fimc[i] == NULL)
+			continue;
+		v4l2_device_unregister_subdev(&fmd->fimc[i]->vid_cap.subdev);
+		fmd->fimc[i] = NULL;
+	}
+	for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
+		if (fmd->fimc_lite[i] == NULL)
+			continue;
+		v4l2_device_unregister_subdev(&fmd->fimc_lite[i]->subdev);
+		fmd->fimc_lite[i] = NULL;
+	}
+	for (i = 0; i < CSIS_MAX_ENTITIES; i++) {
+		if (fmd->csis[i].sd == NULL)
+			continue;
+		v4l2_device_unregister_subdev(fmd->csis[i].sd);
+		module_put(fmd->csis[i].sd->owner);
+		fmd->csis[i].sd = NULL;
+	}
+	for (i = 0; i < fmd->num_sensors; i++) {
+		if (fmd->sensor[i].subdev == NULL)
+			continue;
+		fimc_md_unregister_sensor(fmd->sensor[i].subdev);
+		fmd->sensor[i].subdev = NULL;
+	}
+}
+
+/**
+ * __fimc_md_create_fimc_links - create links to all FIMC entities
+ * @fmd: fimc media device
+ * @source: the source entity to create links to all fimc entities from
+ * @sensor: sensor subdev linked to FIMC[fimc_id] entity, may be null
+ * @pad: the source entity pad index
+ * @link_mask: bitmask of the fimc devices for which link should be enabled
+ */
+static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
+					    struct media_entity *source,
+					    struct v4l2_subdev *sensor,
+					    int pad, int link_mask)
+{
+	struct fimc_sensor_info *s_info;
+	struct media_entity *sink;
+	unsigned int flags = 0;
+	int ret, i;
+
+	for (i = 0; i < FIMC_MAX_DEVS; i++) {
+		if (!fmd->fimc[i])
+			continue;
+		/*
+		 * Some FIMC variants are not fitted with camera capture
+		 * interface. Skip creating a link from sensor for those.
+		 */
+		if (!fmd->fimc[i]->variant->has_cam_if)
+			continue;
+
+		flags = ((1 << i) & link_mask) ? MEDIA_LNK_FL_ENABLED : 0;
+
+		sink = &fmd->fimc[i]->vid_cap.subdev.entity;
+		ret = media_entity_create_link(source, pad, sink,
+					      FIMC_SD_PAD_SINK, flags);
+		if (ret)
+			return ret;
+
+		/* Notify FIMC capture subdev entity */
+		ret = media_entity_call(sink, link_setup, &sink->pads[0],
+					&source->pads[pad], flags);
+		if (ret)
+			break;
+
+		v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
+			  source->name, flags ? '=' : '-', sink->name);
+
+		if (flags == 0 || sensor == NULL)
+			continue;
+		s_info = v4l2_get_subdev_hostdata(sensor);
+		if (!WARN_ON(s_info == NULL)) {
+			unsigned long irq_flags;
+			spin_lock_irqsave(&fmd->slock, irq_flags);
+			s_info->host = fmd->fimc[i];
+			spin_unlock_irqrestore(&fmd->slock, irq_flags);
+		}
+	}
+
+	for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
+		if (!fmd->fimc_lite[i])
+			continue;
+
+		if (link_mask & (1 << (i + FIMC_MAX_DEVS)))
+			flags = MEDIA_LNK_FL_ENABLED;
+		else
+			flags = 0;
+
+		sink = &fmd->fimc_lite[i]->subdev.entity;
+		ret = media_entity_create_link(source, pad, sink,
+					       FLITE_SD_PAD_SINK, flags);
+		if (ret)
+			return ret;
+
+		/* Notify FIMC-LITE subdev entity */
+		ret = media_entity_call(sink, link_setup, &sink->pads[0],
+					&source->pads[pad], flags);
+		if (ret)
+			break;
+
+		v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
+			  source->name, flags ? '=' : '-', sink->name);
+	}
+	return 0;
+}
+
+/* Create links from FIMC-LITE source pads to other entities */
+static int __fimc_md_create_flite_source_links(struct fimc_md *fmd)
+{
+	struct media_entity *source, *sink;
+	unsigned int flags = MEDIA_LNK_FL_ENABLED;
+	int i, ret;
+
+	for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
+		struct fimc_lite *fimc = fmd->fimc_lite[i];
+		if (fimc == NULL)
+			continue;
+		source = &fimc->subdev.entity;
+		sink = &fimc->vfd->entity;
+		/* FIMC-LITE's subdev and video node */
+		ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
+					       sink, 0, flags);
+		if (ret)
+			break;
+		/* TODO: create links to other entities */
+	}
+
+	return ret;
+}
+
+/**
+ * fimc_md_create_links - create default links between registered entities
+ *
+ * Parallel interface sensor entities are connected directly to FIMC capture
+ * entities. The sensors using MIPI CSIS bus are connected through immutable
+ * link with CSI receiver entity specified by mux_id. Any registered CSIS
+ * entity has a link to each registered FIMC capture entity. Enabled links
+ * are created by default between each subsequent registered sensor and
+ * subsequent FIMC capture entity. The number of default active links is
+ * determined by the number of available sensors or FIMC entities,
+ * whichever is less.
+ */
+static int fimc_md_create_links(struct fimc_md *fmd)
+{
+	struct v4l2_subdev *sensor, *csis;
+	struct s5p_fimc_isp_info *pdata;
+	struct fimc_sensor_info *s_info;
+	struct media_entity *source, *sink;
+	int i, pad, fimc_id = 0, ret = 0;
+	u32 flags, link_mask = 0;
+
+	for (i = 0; i < fmd->num_sensors; i++) {
+		if (fmd->sensor[i].subdev == NULL)
+			continue;
+
+		sensor = fmd->sensor[i].subdev;
+		s_info = v4l2_get_subdev_hostdata(sensor);
+		if (!s_info || !s_info->pdata)
+			continue;
+
+		source = NULL;
+		pdata = s_info->pdata;
+
+		switch (pdata->bus_type) {
+		case FIMC_MIPI_CSI2:
+			if (WARN(pdata->mux_id >= CSIS_MAX_ENTITIES,
+				"Wrong CSI channel id: %d\n", pdata->mux_id))
+				return -EINVAL;
+
+			csis = fmd->csis[pdata->mux_id].sd;
+			if (WARN(csis == NULL,
+				 "MIPI-CSI interface specified "
+				 "but s5p-csis module is not loaded!\n"))
+				return -EINVAL;
+
+			ret = media_entity_create_link(&sensor->entity, 0,
+					      &csis->entity, CSIS_PAD_SINK,
+					      MEDIA_LNK_FL_IMMUTABLE |
+					      MEDIA_LNK_FL_ENABLED);
+			if (ret)
+				return ret;
+
+			v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]",
+				  sensor->entity.name, csis->entity.name);
+
+			source = NULL;
+			break;
+
+		case FIMC_ITU_601...FIMC_ITU_656:
+			source = &sensor->entity;
+			pad = 0;
+			break;
+
+		default:
+			v4l2_err(&fmd->v4l2_dev, "Wrong bus_type: %x\n",
+				 pdata->bus_type);
+			return -EINVAL;
+		}
+		if (source == NULL)
+			continue;
+
+		link_mask = 1 << fimc_id++;
+		ret = __fimc_md_create_fimc_sink_links(fmd, source, sensor,
+						       pad, link_mask);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(fmd->csis); i++) {
+		if (fmd->csis[i].sd == NULL)
+			continue;
+		source = &fmd->csis[i].sd->entity;
+		pad = CSIS_PAD_SOURCE;
+
+		link_mask = 1 << fimc_id++;
+		ret = __fimc_md_create_fimc_sink_links(fmd, source, NULL,
+						       pad, link_mask);
+	}
+
+	/* Create immutable links between each FIMC's subdev and video node */
+	flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED;
+	for (i = 0; i < FIMC_MAX_DEVS; i++) {
+		if (!fmd->fimc[i])
+			continue;
+		source = &fmd->fimc[i]->vid_cap.subdev.entity;
+		sink = &fmd->fimc[i]->vid_cap.vfd->entity;
+		ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
+					      sink, 0, flags);
+		if (ret)
+			break;
+	}
+
+	return __fimc_md_create_flite_source_links(fmd);
+}
+
+/*
+ * The peripheral sensor clock management.
+ */
+static int fimc_md_get_clocks(struct fimc_md *fmd)
+{
+	char clk_name[32];
+	struct clk *clock;
+	int i;
+
+	for (i = 0; i < FIMC_MAX_CAMCLKS; i++) {
+		snprintf(clk_name, sizeof(clk_name), "sclk_cam%u", i);
+		clock = clk_get(NULL, clk_name);
+		if (IS_ERR_OR_NULL(clock)) {
+			v4l2_err(&fmd->v4l2_dev, "Failed to get clock: %s",
+				  clk_name);
+			return -ENXIO;
+		}
+		fmd->camclk[i].clock = clock;
+	}
+	return 0;
+}
+
+static void fimc_md_put_clocks(struct fimc_md *fmd)
+{
+	int i = FIMC_MAX_CAMCLKS;
+
+	while (--i >= 0) {
+		if (IS_ERR_OR_NULL(fmd->camclk[i].clock))
+			continue;
+		clk_put(fmd->camclk[i].clock);
+		fmd->camclk[i].clock = NULL;
+	}
+}
+
+static int __fimc_md_set_camclk(struct fimc_md *fmd,
+				struct fimc_sensor_info *s_info,
+				bool on)
+{
+	struct s5p_fimc_isp_info *pdata = s_info->pdata;
+	struct fimc_camclk_info *camclk;
+	int ret = 0;
+
+	if (WARN_ON(pdata->clk_id >= FIMC_MAX_CAMCLKS) || fmd == NULL)
+		return -EINVAL;
+
+	camclk = &fmd->camclk[pdata->clk_id];
+
+	dbg("camclk %d, f: %lu, use_count: %d, on: %d",
+	    pdata->clk_id, pdata->clk_frequency, camclk->use_count, on);
+
+	if (on) {
+		if (camclk->use_count > 0 &&
+		    camclk->frequency != pdata->clk_frequency)
+			return -EINVAL;
+
+		if (camclk->use_count++ == 0) {
+			clk_set_rate(camclk->clock, pdata->clk_frequency);
+			camclk->frequency = pdata->clk_frequency;
+			ret = clk_enable(camclk->clock);
+			dbg("Enabled camclk %d: f: %lu", pdata->clk_id,
+			    clk_get_rate(camclk->clock));
+		}
+		return ret;
+	}
+
+	if (WARN_ON(camclk->use_count == 0))
+		return 0;
+
+	if (--camclk->use_count == 0) {
+		clk_disable(camclk->clock);
+		dbg("Disabled camclk %d", pdata->clk_id);
+	}
+	return ret;
+}
+
+/**
+ * fimc_md_set_camclk - peripheral sensor clock setup
+ * @sd: sensor subdev to configure sclk_cam clock for
+ * @on: 1 to enable or 0 to disable the clock
+ *
+ * There are 2 separate clock outputs available in the SoC for external
+ * image processors. These clocks are shared between all registered FIMC
+ * devices to which sensors can be attached, either directly or through
+ * the MIPI CSI receiver. The clock is allowed here to be used by
+ * multiple sensors concurrently if they use same frequency.
+ * This function should only be called when the graph mutex is held.
+ */
+int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on)
+{
+	struct fimc_sensor_info *s_info = v4l2_get_subdev_hostdata(sd);
+	struct fimc_md *fmd = entity_to_fimc_mdev(&sd->entity);
+
+	return __fimc_md_set_camclk(fmd, s_info, on);
+}
+
+static int fimc_md_link_notify(struct media_pad *source,
+			       struct media_pad *sink, u32 flags)
+{
+	struct fimc_lite *fimc_lite = NULL;
+	struct fimc_dev *fimc = NULL;
+	struct fimc_pipeline *pipeline;
+	struct v4l2_subdev *sd;
+	int ret = 0;
+
+	if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+		return 0;
+
+	sd = media_entity_to_v4l2_subdev(sink->entity);
+
+	switch (sd->grp_id) {
+	case FLITE_GROUP_ID:
+		fimc_lite = v4l2_get_subdevdata(sd);
+		pipeline = &fimc_lite->pipeline;
+		break;
+	case FIMC_GROUP_ID:
+		fimc = v4l2_get_subdevdata(sd);
+		pipeline = &fimc->pipeline;
+		break;
+	default:
+		return 0;
+	}
+
+	if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+		ret = __fimc_pipeline_shutdown(pipeline);
+		pipeline->subdevs[IDX_SENSOR] = NULL;
+		pipeline->subdevs[IDX_CSIS] = NULL;
+
+		if (fimc) {
+			mutex_lock(&fimc->lock);
+			fimc_ctrls_delete(fimc->vid_cap.ctx);
+			mutex_unlock(&fimc->lock);
+		}
+		return ret;
+	}
+	/*
+	 * Link activation. Enable power of pipeline elements only if the
+	 * pipeline is already in use, i.e. its video node is opened.
+	 * Recreate the controls destroyed during the link deactivation.
+	 */
+	if (fimc) {
+		mutex_lock(&fimc->lock);
+		if (fimc->vid_cap.refcnt > 0) {
+			ret = __fimc_pipeline_initialize(pipeline,
+							 source->entity, true);
+		if (!ret)
+			ret = fimc_capture_ctrls_create(fimc);
+		}
+		mutex_unlock(&fimc->lock);
+	} else {
+		mutex_lock(&fimc_lite->lock);
+		if (fimc_lite->ref_count > 0) {
+			ret = __fimc_pipeline_initialize(pipeline,
+							 source->entity, true);
+		}
+		mutex_unlock(&fimc_lite->lock);
+	}
+	return ret ? -EPIPE : ret;
+}
+
+static ssize_t fimc_md_sysfs_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct fimc_md *fmd = platform_get_drvdata(pdev);
+
+	if (fmd->user_subdev_api)
+		return strlcpy(buf, "Sub-device API (sub-dev)\n", PAGE_SIZE);
+
+	return strlcpy(buf, "V4L2 video node only API (vid-dev)\n", PAGE_SIZE);
+}
+
+static ssize_t fimc_md_sysfs_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct fimc_md *fmd = platform_get_drvdata(pdev);
+	bool subdev_api;
+	int i;
+
+	if (!strcmp(buf, "vid-dev\n"))
+		subdev_api = false;
+	else if (!strcmp(buf, "sub-dev\n"))
+		subdev_api = true;
+	else
+		return count;
+
+	fmd->user_subdev_api = subdev_api;
+	for (i = 0; i < FIMC_MAX_DEVS; i++)
+		if (fmd->fimc[i])
+			fmd->fimc[i]->vid_cap.user_subdev_api = subdev_api;
+	return count;
+}
+/*
+ * This device attribute is to select video pipeline configuration method.
+ * There are following valid values:
+ *  vid-dev - for V4L2 video node API only, subdevice will be configured
+ *  by the host driver.
+ *  sub-dev - for media controller API, subdevs must be configured in user
+ *  space before starting streaming.
+ */
+static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO,
+		   fimc_md_sysfs_show, fimc_md_sysfs_store);
+
+static int fimc_md_probe(struct platform_device *pdev)
+{
+	struct v4l2_device *v4l2_dev;
+	struct fimc_md *fmd;
+	int ret;
+
+	fmd = devm_kzalloc(&pdev->dev, sizeof(*fmd), GFP_KERNEL);
+	if (!fmd)
+		return -ENOMEM;
+
+	spin_lock_init(&fmd->slock);
+	fmd->pdev = pdev;
+
+	strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC",
+		sizeof(fmd->media_dev.model));
+	fmd->media_dev.link_notify = fimc_md_link_notify;
+	fmd->media_dev.dev = &pdev->dev;
+
+	v4l2_dev = &fmd->v4l2_dev;
+	v4l2_dev->mdev = &fmd->media_dev;
+	v4l2_dev->notify = fimc_sensor_notify;
+	snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s",
+		 dev_name(&pdev->dev));
+
+	ret = v4l2_device_register(&pdev->dev, &fmd->v4l2_dev);
+	if (ret < 0) {
+		v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret);
+		return ret;
+	}
+	ret = media_device_register(&fmd->media_dev);
+	if (ret < 0) {
+		v4l2_err(v4l2_dev, "Failed to register media device: %d\n", ret);
+		goto err_md;
+	}
+	ret = fimc_md_get_clocks(fmd);
+	if (ret)
+		goto err_clk;
+
+	fmd->user_subdev_api = false;
+
+	/* Protect the media graph while we're registering entities */
+	mutex_lock(&fmd->media_dev.graph_mutex);
+
+	ret = fimc_md_register_platform_entities(fmd);
+	if (ret)
+		goto err_unlock;
+
+	if (pdev->dev.platform_data) {
+		ret = fimc_md_register_sensor_entities(fmd);
+		if (ret)
+			goto err_unlock;
+	}
+	ret = fimc_md_create_links(fmd);
+	if (ret)
+		goto err_unlock;
+	ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev);
+	if (ret)
+		goto err_unlock;
+
+	ret = device_create_file(&pdev->dev, &dev_attr_subdev_conf_mode);
+	if (ret)
+		goto err_unlock;
+
+	platform_set_drvdata(pdev, fmd);
+	mutex_unlock(&fmd->media_dev.graph_mutex);
+	return 0;
+
+err_unlock:
+	mutex_unlock(&fmd->media_dev.graph_mutex);
+err_clk:
+	media_device_unregister(&fmd->media_dev);
+	fimc_md_put_clocks(fmd);
+	fimc_md_unregister_entities(fmd);
+err_md:
+	v4l2_device_unregister(&fmd->v4l2_dev);
+	return ret;
+}
+
+static int __devexit fimc_md_remove(struct platform_device *pdev)
+{
+	struct fimc_md *fmd = platform_get_drvdata(pdev);
+
+	if (!fmd)
+		return 0;
+	device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode);
+	fimc_md_unregister_entities(fmd);
+	media_device_unregister(&fmd->media_dev);
+	fimc_md_put_clocks(fmd);
+	return 0;
+}
+
+static struct platform_driver fimc_md_driver = {
+	.probe		= fimc_md_probe,
+	.remove		= __devexit_p(fimc_md_remove),
+	.driver = {
+		.name	= "s5p-fimc-md",
+		.owner	= THIS_MODULE,
+	}
+};
+
+static int __init fimc_md_init(void)
+{
+	int ret;
+
+	request_module("s5p-csis");
+	ret = fimc_register_driver();
+	if (ret)
+		return ret;
+
+	return platform_driver_register(&fimc_md_driver);
+}
+
+static void __exit fimc_md_exit(void)
+{
+	platform_driver_unregister(&fimc_md_driver);
+	fimc_unregister_driver();
+}
+
+module_init(fimc_md_init);
+module_exit(fimc_md_exit);
+
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("2.0.1");
diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.h b/drivers/media/platform/s5p-fimc/fimc-mdevice.h
new file mode 100644
index 0000000..1f5dbaf
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef FIMC_MDEVICE_H_
+#define FIMC_MDEVICE_H_
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <media/media-device.h>
+#include <media/media-entity.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "fimc-core.h"
+#include "fimc-lite.h"
+#include "mipi-csis.h"
+
+/* Group IDs of sensor, MIPI-CSIS, FIMC-LITE and the writeback subdevs. */
+#define SENSOR_GROUP_ID		(1 << 8)
+#define CSIS_GROUP_ID		(1 << 9)
+#define WRITEBACK_GROUP_ID	(1 << 10)
+#define FIMC_GROUP_ID		(1 << 11)
+#define FLITE_GROUP_ID		(1 << 12)
+
+#define FIMC_MAX_SENSORS	8
+#define FIMC_MAX_CAMCLKS	2
+
+struct fimc_csis_info {
+	struct v4l2_subdev *sd;
+	int id;
+};
+
+struct fimc_camclk_info {
+	struct clk *clock;
+	int use_count;
+	unsigned long frequency;
+};
+
+/**
+ * struct fimc_sensor_info - image data source subdev information
+ * @pdata: sensor's atrributes passed as media device's platform data
+ * @subdev: image sensor v4l2 subdev
+ * @host: fimc device the sensor is currently linked to
+ *
+ * This data structure applies to image sensor and the writeback subdevs.
+ */
+struct fimc_sensor_info {
+	struct s5p_fimc_isp_info *pdata;
+	struct v4l2_subdev *subdev;
+	struct fimc_dev *host;
+};
+
+/**
+ * struct fimc_md - fimc media device information
+ * @csis: MIPI CSIS subdevs data
+ * @sensor: array of registered sensor subdevs
+ * @num_sensors: actual number of registered sensors
+ * @camclk: external sensor clock information
+ * @fimc: array of registered fimc devices
+ * @media_dev: top level media device
+ * @v4l2_dev: top level v4l2_device holding up the subdevs
+ * @pdev: platform device this media device is hooked up into
+ * @user_subdev_api: true if subdevs are not configured by the host driver
+ * @slock: spinlock protecting @sensor array
+ */
+struct fimc_md {
+	struct fimc_csis_info csis[CSIS_MAX_ENTITIES];
+	struct fimc_sensor_info sensor[FIMC_MAX_SENSORS];
+	int num_sensors;
+	struct fimc_camclk_info camclk[FIMC_MAX_CAMCLKS];
+	struct fimc_lite *fimc_lite[FIMC_LITE_MAX_DEVS];
+	struct fimc_dev *fimc[FIMC_MAX_DEVS];
+	struct media_device media_dev;
+	struct v4l2_device v4l2_dev;
+	struct platform_device *pdev;
+	bool user_subdev_api;
+	spinlock_t slock;
+};
+
+#define is_subdev_pad(pad) (pad == NULL || \
+	media_entity_type(pad->entity) == MEDIA_ENT_T_V4L2_SUBDEV)
+
+#define me_subtype(me) \
+	((me->type) & (MEDIA_ENT_TYPE_MASK | MEDIA_ENT_SUBTYPE_MASK))
+
+#define subdev_has_devnode(__sd) (__sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)
+
+static inline struct fimc_md *entity_to_fimc_mdev(struct media_entity *me)
+{
+	return me->parent == NULL ? NULL :
+		container_of(me->parent, struct fimc_md, media_dev);
+}
+
+static inline void fimc_md_graph_lock(struct fimc_dev *fimc)
+{
+	BUG_ON(fimc->vid_cap.vfd == NULL);
+	mutex_lock(&fimc->vid_cap.vfd->entity.parent->graph_mutex);
+}
+
+static inline void fimc_md_graph_unlock(struct fimc_dev *fimc)
+{
+	BUG_ON(fimc->vid_cap.vfd == NULL);
+	mutex_unlock(&fimc->vid_cap.vfd->entity.parent->graph_mutex);
+}
+
+int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on);
+void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_entity *me);
+int fimc_pipeline_initialize(struct fimc_pipeline *p, struct media_entity *me,
+			     bool resume);
+int fimc_pipeline_shutdown(struct fimc_pipeline *p);
+int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state);
+int fimc_pipeline_s_stream(struct fimc_pipeline *p, bool state);
+
+#endif
diff --git a/drivers/media/platform/s5p-fimc/fimc-reg.c b/drivers/media/platform/s5p-fimc/fimc-reg.c
new file mode 100644
index 0000000..0e3eb9c
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-reg.c
@@ -0,0 +1,775 @@
+/*
+ * Register interface file for Samsung Camera Interface (FIMC) driver
+ *
+ * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <media/s5p_fimc.h>
+
+#include "fimc-reg.h"
+#include "fimc-core.h"
+
+
+void fimc_hw_reset(struct fimc_dev *dev)
+{
+	u32 cfg;
+
+	cfg = readl(dev->regs + FIMC_REG_CISRCFMT);
+	cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
+	writel(cfg, dev->regs + FIMC_REG_CISRCFMT);
+
+	/* Software reset. */
+	cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
+	cfg |= (FIMC_REG_CIGCTRL_SWRST | FIMC_REG_CIGCTRL_IRQ_LEVEL);
+	writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
+	udelay(10);
+
+	cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
+	cfg &= ~FIMC_REG_CIGCTRL_SWRST;
+	writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
+
+	if (dev->variant->out_buf_count > 4)
+		fimc_hw_set_dma_seq(dev, 0xF);
+}
+
+static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx)
+{
+	u32 flip = FIMC_REG_MSCTRL_FLIP_NORMAL;
+
+	if (ctx->hflip)
+		flip = FIMC_REG_MSCTRL_FLIP_X_MIRROR;
+	if (ctx->vflip)
+		flip = FIMC_REG_MSCTRL_FLIP_Y_MIRROR;
+
+	if (ctx->rotation <= 90)
+		return flip;
+
+	return (flip ^ FIMC_REG_MSCTRL_FLIP_180) & FIMC_REG_MSCTRL_FLIP_180;
+}
+
+static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx)
+{
+	u32 flip = FIMC_REG_CITRGFMT_FLIP_NORMAL;
+
+	if (ctx->hflip)
+		flip |= FIMC_REG_CITRGFMT_FLIP_X_MIRROR;
+	if (ctx->vflip)
+		flip |= FIMC_REG_CITRGFMT_FLIP_Y_MIRROR;
+
+	if (ctx->rotation <= 90)
+		return flip;
+
+	return (flip ^ FIMC_REG_CITRGFMT_FLIP_180) & FIMC_REG_CITRGFMT_FLIP_180;
+}
+
+void fimc_hw_set_rotation(struct fimc_ctx *ctx)
+{
+	u32 cfg, flip;
+	struct fimc_dev *dev = ctx->fimc_dev;
+
+	cfg = readl(dev->regs + FIMC_REG_CITRGFMT);
+	cfg &= ~(FIMC_REG_CITRGFMT_INROT90 | FIMC_REG_CITRGFMT_OUTROT90 |
+		 FIMC_REG_CITRGFMT_FLIP_180);
+
+	/*
+	 * The input and output rotator cannot work simultaneously.
+	 * Use the output rotator in output DMA mode or the input rotator
+	 * in direct fifo output mode.
+	 */
+	if (ctx->rotation == 90 || ctx->rotation == 270) {
+		if (ctx->out_path == FIMC_IO_LCDFIFO)
+			cfg |= FIMC_REG_CITRGFMT_INROT90;
+		else
+			cfg |= FIMC_REG_CITRGFMT_OUTROT90;
+	}
+
+	if (ctx->out_path == FIMC_IO_DMA) {
+		cfg |= fimc_hw_get_target_flip(ctx);
+		writel(cfg, dev->regs + FIMC_REG_CITRGFMT);
+	} else {
+		/* LCD FIFO path */
+		flip = readl(dev->regs + FIMC_REG_MSCTRL);
+		flip &= ~FIMC_REG_MSCTRL_FLIP_MASK;
+		flip |= fimc_hw_get_in_flip(ctx);
+		writel(flip, dev->regs + FIMC_REG_MSCTRL);
+	}
+}
+
+void fimc_hw_set_target_format(struct fimc_ctx *ctx)
+{
+	u32 cfg;
+	struct fimc_dev *dev = ctx->fimc_dev;
+	struct fimc_frame *frame = &ctx->d_frame;
+
+	dbg("w= %d, h= %d color: %d", frame->width,
+	    frame->height, frame->fmt->color);
+
+	cfg = readl(dev->regs + FIMC_REG_CITRGFMT);
+	cfg &= ~(FIMC_REG_CITRGFMT_FMT_MASK | FIMC_REG_CITRGFMT_HSIZE_MASK |
+		 FIMC_REG_CITRGFMT_VSIZE_MASK);
+
+	switch (frame->fmt->color) {
+	case FIMC_FMT_RGB444...FIMC_FMT_RGB888:
+		cfg |= FIMC_REG_CITRGFMT_RGB;
+		break;
+	case FIMC_FMT_YCBCR420:
+		cfg |= FIMC_REG_CITRGFMT_YCBCR420;
+		break;
+	case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422:
+		if (frame->fmt->colplanes == 1)
+			cfg |= FIMC_REG_CITRGFMT_YCBCR422_1P;
+		else
+			cfg |= FIMC_REG_CITRGFMT_YCBCR422;
+		break;
+	default:
+		break;
+	}
+
+	if (ctx->rotation == 90 || ctx->rotation == 270)
+		cfg |= (frame->height << 16) | frame->width;
+	else
+		cfg |= (frame->width << 16) | frame->height;
+
+	writel(cfg, dev->regs + FIMC_REG_CITRGFMT);
+
+	cfg = readl(dev->regs + FIMC_REG_CITAREA);
+	cfg &= ~FIMC_REG_CITAREA_MASK;
+	cfg |= (frame->width * frame->height);
+	writel(cfg, dev->regs + FIMC_REG_CITAREA);
+}
+
+static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx)
+{
+	struct fimc_dev *dev = ctx->fimc_dev;
+	struct fimc_frame *frame = &ctx->d_frame;
+	u32 cfg;
+
+	cfg = (frame->f_height << 16) | frame->f_width;
+	writel(cfg, dev->regs + FIMC_REG_ORGOSIZE);
+
+	/* Select color space conversion equation (HD/SD size).*/
+	cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
+	if (frame->f_width >= 1280) /* HD */
+		cfg |= FIMC_REG_CIGCTRL_CSC_ITU601_709;
+	else	/* SD */
+		cfg &= ~FIMC_REG_CIGCTRL_CSC_ITU601_709;
+	writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
+
+}
+
+void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
+{
+	struct fimc_dev *dev = ctx->fimc_dev;
+	struct fimc_frame *frame = &ctx->d_frame;
+	struct fimc_dma_offset *offset = &frame->dma_offset;
+	struct fimc_fmt *fmt = frame->fmt;
+	u32 cfg;
+
+	/* Set the input dma offsets. */
+	cfg = (offset->y_v << 16) | offset->y_h;
+	writel(cfg, dev->regs + FIMC_REG_CIOYOFF);
+
+	cfg = (offset->cb_v << 16) | offset->cb_h;
+	writel(cfg, dev->regs + FIMC_REG_CIOCBOFF);
+
+	cfg = (offset->cr_v << 16) | offset->cr_h;
+	writel(cfg, dev->regs + FIMC_REG_CIOCROFF);
+
+	fimc_hw_set_out_dma_size(ctx);
+
+	/* Configure chroma components order. */
+	cfg = readl(dev->regs + FIMC_REG_CIOCTRL);
+
+	cfg &= ~(FIMC_REG_CIOCTRL_ORDER2P_MASK |
+		 FIMC_REG_CIOCTRL_ORDER422_MASK |
+		 FIMC_REG_CIOCTRL_YCBCR_PLANE_MASK |
+		 FIMC_REG_CIOCTRL_RGB16FMT_MASK);
+
+	if (fmt->colplanes == 1)
+		cfg |= ctx->out_order_1p;
+	else if (fmt->colplanes == 2)
+		cfg |= ctx->out_order_2p | FIMC_REG_CIOCTRL_YCBCR_2PLANE;
+	else if (fmt->colplanes == 3)
+		cfg |= FIMC_REG_CIOCTRL_YCBCR_3PLANE;
+
+	if (fmt->color == FIMC_FMT_RGB565)
+		cfg |= FIMC_REG_CIOCTRL_RGB565;
+	else if (fmt->color == FIMC_FMT_RGB555)
+		cfg |= FIMC_REG_CIOCTRL_ARGB1555;
+	else if (fmt->color == FIMC_FMT_RGB444)
+		cfg |= FIMC_REG_CIOCTRL_ARGB4444;
+
+	writel(cfg, dev->regs + FIMC_REG_CIOCTRL);
+}
+
+static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable)
+{
+	u32 cfg = readl(dev->regs + FIMC_REG_ORGISIZE);
+	if (enable)
+		cfg |= FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN;
+	else
+		cfg &= ~FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN;
+	writel(cfg, dev->regs + FIMC_REG_ORGISIZE);
+}
+
+void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable)
+{
+	u32 cfg = readl(dev->regs + FIMC_REG_CIOCTRL);
+	if (enable)
+		cfg |= FIMC_REG_CIOCTRL_LASTIRQ_ENABLE;
+	else
+		cfg &= ~FIMC_REG_CIOCTRL_LASTIRQ_ENABLE;
+	writel(cfg, dev->regs + FIMC_REG_CIOCTRL);
+}
+
+void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
+{
+	struct fimc_dev *dev =  ctx->fimc_dev;
+	struct fimc_scaler *sc = &ctx->scaler;
+	u32 cfg, shfactor;
+
+	shfactor = 10 - (sc->hfactor + sc->vfactor);
+	cfg = shfactor << 28;
+
+	cfg |= (sc->pre_hratio << 16) | sc->pre_vratio;
+	writel(cfg, dev->regs + FIMC_REG_CISCPRERATIO);
+
+	cfg = (sc->pre_dst_width << 16) | sc->pre_dst_height;
+	writel(cfg, dev->regs + FIMC_REG_CISCPREDST);
+}
+
+static void fimc_hw_set_scaler(struct fimc_ctx *ctx)
+{
+	struct fimc_dev *dev = ctx->fimc_dev;
+	struct fimc_scaler *sc = &ctx->scaler;
+	struct fimc_frame *src_frame = &ctx->s_frame;
+	struct fimc_frame *dst_frame = &ctx->d_frame;
+
+	u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
+
+	cfg &= ~(FIMC_REG_CISCCTRL_CSCR2Y_WIDE | FIMC_REG_CISCCTRL_CSCY2R_WIDE |
+		 FIMC_REG_CISCCTRL_SCALEUP_H | FIMC_REG_CISCCTRL_SCALEUP_V |
+		 FIMC_REG_CISCCTRL_SCALERBYPASS | FIMC_REG_CISCCTRL_ONE2ONE |
+		 FIMC_REG_CISCCTRL_INRGB_FMT_MASK | FIMC_REG_CISCCTRL_OUTRGB_FMT_MASK |
+		 FIMC_REG_CISCCTRL_INTERLACE | FIMC_REG_CISCCTRL_RGB_EXT);
+
+	if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW))
+		cfg |= (FIMC_REG_CISCCTRL_CSCR2Y_WIDE |
+			FIMC_REG_CISCCTRL_CSCY2R_WIDE);
+
+	if (!sc->enabled)
+		cfg |= FIMC_REG_CISCCTRL_SCALERBYPASS;
+
+	if (sc->scaleup_h)
+		cfg |= FIMC_REG_CISCCTRL_SCALEUP_H;
+
+	if (sc->scaleup_v)
+		cfg |= FIMC_REG_CISCCTRL_SCALEUP_V;
+
+	if (sc->copy_mode)
+		cfg |= FIMC_REG_CISCCTRL_ONE2ONE;
+
+	if (ctx->in_path == FIMC_IO_DMA) {
+		switch (src_frame->fmt->color) {
+		case FIMC_FMT_RGB565:
+			cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB565;
+			break;
+		case FIMC_FMT_RGB666:
+			cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB666;
+			break;
+		case FIMC_FMT_RGB888:
+			cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB888;
+			break;
+		}
+	}
+
+	if (ctx->out_path == FIMC_IO_DMA) {
+		u32 color = dst_frame->fmt->color;
+
+		if (color >= FIMC_FMT_RGB444 && color <= FIMC_FMT_RGB565)
+			cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB565;
+		else if (color == FIMC_FMT_RGB666)
+			cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB666;
+		else if (color == FIMC_FMT_RGB888)
+			cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888;
+	} else {
+		cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888;
+
+		if (ctx->flags & FIMC_SCAN_MODE_INTERLACED)
+			cfg |= FIMC_REG_CISCCTRL_INTERLACE;
+	}
+
+	writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
+}
+
+void fimc_hw_set_mainscaler(struct fimc_ctx *ctx)
+{
+	struct fimc_dev *dev = ctx->fimc_dev;
+	struct fimc_variant *variant = dev->variant;
+	struct fimc_scaler *sc = &ctx->scaler;
+	u32 cfg;
+
+	dbg("main_hratio= 0x%X  main_vratio= 0x%X",
+	    sc->main_hratio, sc->main_vratio);
+
+	fimc_hw_set_scaler(ctx);
+
+	cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
+	cfg &= ~(FIMC_REG_CISCCTRL_MHRATIO_MASK |
+		 FIMC_REG_CISCCTRL_MVRATIO_MASK);
+
+	if (variant->has_mainscaler_ext) {
+		cfg |= FIMC_REG_CISCCTRL_MHRATIO_EXT(sc->main_hratio);
+		cfg |= FIMC_REG_CISCCTRL_MVRATIO_EXT(sc->main_vratio);
+		writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
+
+		cfg = readl(dev->regs + FIMC_REG_CIEXTEN);
+
+		cfg &= ~(FIMC_REG_CIEXTEN_MVRATIO_EXT_MASK |
+			 FIMC_REG_CIEXTEN_MHRATIO_EXT_MASK);
+		cfg |= FIMC_REG_CIEXTEN_MHRATIO_EXT(sc->main_hratio);
+		cfg |= FIMC_REG_CIEXTEN_MVRATIO_EXT(sc->main_vratio);
+		writel(cfg, dev->regs + FIMC_REG_CIEXTEN);
+	} else {
+		cfg |= FIMC_REG_CISCCTRL_MHRATIO(sc->main_hratio);
+		cfg |= FIMC_REG_CISCCTRL_MVRATIO(sc->main_vratio);
+		writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
+	}
+}
+
+void fimc_hw_en_capture(struct fimc_ctx *ctx)
+{
+	struct fimc_dev *dev = ctx->fimc_dev;
+
+	u32 cfg = readl(dev->regs + FIMC_REG_CIIMGCPT);
+
+	if (ctx->out_path == FIMC_IO_DMA) {
+		/* one shot mode */
+		cfg |= FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE |
+			FIMC_REG_CIIMGCPT_IMGCPTEN;
+	} else {
+		/* Continuous frame capture mode (freerun). */
+		cfg &= ~(FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE |
+			 FIMC_REG_CIIMGCPT_CPT_FRMOD_CNT);
+		cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN;
+	}
+
+	if (ctx->scaler.enabled)
+		cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN_SC;
+
+	cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN;
+	writel(cfg, dev->regs + FIMC_REG_CIIMGCPT);
+}
+
+void fimc_hw_set_effect(struct fimc_ctx *ctx)
+{
+	struct fimc_dev *dev = ctx->fimc_dev;
+	struct fimc_effect *effect = &ctx->effect;
+	u32 cfg = 0;
+
+	if (effect->type != FIMC_REG_CIIMGEFF_FIN_BYPASS) {
+		cfg |= FIMC_REG_CIIMGEFF_IE_SC_AFTER |
+			FIMC_REG_CIIMGEFF_IE_ENABLE;
+		cfg |= effect->type;
+		if (effect->type == FIMC_REG_CIIMGEFF_FIN_ARBITRARY)
+			cfg |= (effect->pat_cb << 13) | effect->pat_cr;
+	}
+
+	writel(cfg, dev->regs + FIMC_REG_CIIMGEFF);
+}
+
+void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx)
+{
+	struct fimc_dev *dev = ctx->fimc_dev;
+	struct fimc_frame *frame = &ctx->d_frame;
+	u32 cfg;
+
+	if (!(frame->fmt->flags & FMT_HAS_ALPHA))
+		return;
+
+	cfg = readl(dev->regs + FIMC_REG_CIOCTRL);
+	cfg &= ~FIMC_REG_CIOCTRL_ALPHA_OUT_MASK;
+	cfg |= (frame->alpha << 4);
+	writel(cfg, dev->regs + FIMC_REG_CIOCTRL);
+}
+
+static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx)
+{
+	struct fimc_dev *dev = ctx->fimc_dev;
+	struct fimc_frame *frame = &ctx->s_frame;
+	u32 cfg_o = 0;
+	u32 cfg_r = 0;
+
+	if (FIMC_IO_LCDFIFO == ctx->out_path)
+		cfg_r |= FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN;
+
+	cfg_o |= (frame->f_height << 16) | frame->f_width;
+	cfg_r |= (frame->height << 16) | frame->width;
+
+	writel(cfg_o, dev->regs + FIMC_REG_ORGISIZE);
+	writel(cfg_r, dev->regs + FIMC_REG_CIREAL_ISIZE);
+}
+
+void fimc_hw_set_in_dma(struct fimc_ctx *ctx)
+{
+	struct fimc_dev *dev = ctx->fimc_dev;
+	struct fimc_frame *frame = &ctx->s_frame;
+	struct fimc_dma_offset *offset = &frame->dma_offset;
+	u32 cfg;
+
+	/* Set the pixel offsets. */
+	cfg = (offset->y_v << 16) | offset->y_h;
+	writel(cfg, dev->regs + FIMC_REG_CIIYOFF);
+
+	cfg = (offset->cb_v << 16) | offset->cb_h;
+	writel(cfg, dev->regs + FIMC_REG_CIICBOFF);
+
+	cfg = (offset->cr_v << 16) | offset->cr_h;
+	writel(cfg, dev->regs + FIMC_REG_CIICROFF);
+
+	/* Input original and real size. */
+	fimc_hw_set_in_dma_size(ctx);
+
+	/* Use DMA autoload only in FIFO mode. */
+	fimc_hw_en_autoload(dev, ctx->out_path == FIMC_IO_LCDFIFO);
+
+	/* Set the input DMA to process single frame only. */
+	cfg = readl(dev->regs + FIMC_REG_MSCTRL);
+	cfg &= ~(FIMC_REG_MSCTRL_INFORMAT_MASK
+		 | FIMC_REG_MSCTRL_IN_BURST_COUNT_MASK
+		 | FIMC_REG_MSCTRL_INPUT_MASK
+		 | FIMC_REG_MSCTRL_C_INT_IN_MASK
+		 | FIMC_REG_MSCTRL_2P_IN_ORDER_MASK);
+
+	cfg |= (FIMC_REG_MSCTRL_IN_BURST_COUNT(4)
+		| FIMC_REG_MSCTRL_INPUT_MEMORY
+		| FIMC_REG_MSCTRL_FIFO_CTRL_FULL);
+
+	switch (frame->fmt->color) {
+	case FIMC_FMT_RGB565...FIMC_FMT_RGB888:
+		cfg |= FIMC_REG_MSCTRL_INFORMAT_RGB;
+		break;
+	case FIMC_FMT_YCBCR420:
+		cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR420;
+
+		if (frame->fmt->colplanes == 2)
+			cfg |= ctx->in_order_2p | FIMC_REG_MSCTRL_C_INT_IN_2PLANE;
+		else
+			cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE;
+
+		break;
+	case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422:
+		if (frame->fmt->colplanes == 1) {
+			cfg |= ctx->in_order_1p
+				| FIMC_REG_MSCTRL_INFORMAT_YCBCR422_1P;
+		} else {
+			cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR422;
+
+			if (frame->fmt->colplanes == 2)
+				cfg |= ctx->in_order_2p
+					| FIMC_REG_MSCTRL_C_INT_IN_2PLANE;
+			else
+				cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE;
+		}
+		break;
+	default:
+		break;
+	}
+
+	writel(cfg, dev->regs + FIMC_REG_MSCTRL);
+
+	/* Input/output DMA linear/tiled mode. */
+	cfg = readl(dev->regs + FIMC_REG_CIDMAPARAM);
+	cfg &= ~FIMC_REG_CIDMAPARAM_TILE_MASK;
+
+	if (tiled_fmt(ctx->s_frame.fmt))
+		cfg |= FIMC_REG_CIDMAPARAM_R_64X32;
+
+	if (tiled_fmt(ctx->d_frame.fmt))
+		cfg |= FIMC_REG_CIDMAPARAM_W_64X32;
+
+	writel(cfg, dev->regs + FIMC_REG_CIDMAPARAM);
+}
+
+
+void fimc_hw_set_input_path(struct fimc_ctx *ctx)
+{
+	struct fimc_dev *dev = ctx->fimc_dev;
+
+	u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL);
+	cfg &= ~FIMC_REG_MSCTRL_INPUT_MASK;
+
+	if (ctx->in_path == FIMC_IO_DMA)
+		cfg |= FIMC_REG_MSCTRL_INPUT_MEMORY;
+	else
+		cfg |= FIMC_REG_MSCTRL_INPUT_EXTCAM;
+
+	writel(cfg, dev->regs + FIMC_REG_MSCTRL);
+}
+
+void fimc_hw_set_output_path(struct fimc_ctx *ctx)
+{
+	struct fimc_dev *dev = ctx->fimc_dev;
+
+	u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
+	cfg &= ~FIMC_REG_CISCCTRL_LCDPATHEN_FIFO;
+	if (ctx->out_path == FIMC_IO_LCDFIFO)
+		cfg |= FIMC_REG_CISCCTRL_LCDPATHEN_FIFO;
+	writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
+}
+
+void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr)
+{
+	u32 cfg = readl(dev->regs + FIMC_REG_CIREAL_ISIZE);
+	cfg |= FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS;
+	writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE);
+
+	writel(paddr->y, dev->regs + FIMC_REG_CIIYSA(0));
+	writel(paddr->cb, dev->regs + FIMC_REG_CIICBSA(0));
+	writel(paddr->cr, dev->regs + FIMC_REG_CIICRSA(0));
+
+	cfg &= ~FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS;
+	writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE);
+}
+
+void fimc_hw_set_output_addr(struct fimc_dev *dev,
+			     struct fimc_addr *paddr, int index)
+{
+	int i = (index == -1) ? 0 : index;
+	do {
+		writel(paddr->y, dev->regs + FIMC_REG_CIOYSA(i));
+		writel(paddr->cb, dev->regs + FIMC_REG_CIOCBSA(i));
+		writel(paddr->cr, dev->regs + FIMC_REG_CIOCRSA(i));
+		dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
+		    i, paddr->y, paddr->cb, paddr->cr);
+	} while (index == -1 && ++i < FIMC_MAX_OUT_BUFS);
+}
+
+int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
+				struct s5p_fimc_isp_info *cam)
+{
+	u32 cfg = readl(fimc->regs + FIMC_REG_CIGCTRL);
+
+	cfg &= ~(FIMC_REG_CIGCTRL_INVPOLPCLK | FIMC_REG_CIGCTRL_INVPOLVSYNC |
+		 FIMC_REG_CIGCTRL_INVPOLHREF | FIMC_REG_CIGCTRL_INVPOLHSYNC |
+		 FIMC_REG_CIGCTRL_INVPOLFIELD);
+
+	if (cam->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+		cfg |= FIMC_REG_CIGCTRL_INVPOLPCLK;
+
+	if (cam->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+		cfg |= FIMC_REG_CIGCTRL_INVPOLVSYNC;
+
+	if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+		cfg |= FIMC_REG_CIGCTRL_INVPOLHREF;
+
+	if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+		cfg |= FIMC_REG_CIGCTRL_INVPOLHSYNC;
+
+	if (cam->flags & V4L2_MBUS_FIELD_EVEN_LOW)
+		cfg |= FIMC_REG_CIGCTRL_INVPOLFIELD;
+
+	writel(cfg, fimc->regs + FIMC_REG_CIGCTRL);
+
+	return 0;
+}
+
+struct mbus_pixfmt_desc {
+	u32 pixelcode;
+	u32 cisrcfmt;
+	u16 bus_width;
+};
+
+static const struct mbus_pixfmt_desc pix_desc[] = {
+	{ V4L2_MBUS_FMT_YUYV8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCBYCR, 8 },
+	{ V4L2_MBUS_FMT_YVYU8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCRYCB, 8 },
+	{ V4L2_MBUS_FMT_VYUY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CRYCBY, 8 },
+	{ V4L2_MBUS_FMT_UYVY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CBYCRY, 8 },
+};
+
+int fimc_hw_set_camera_source(struct fimc_dev *fimc,
+			      struct s5p_fimc_isp_info *cam)
+{
+	struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
+	u32 cfg = 0;
+	u32 bus_width;
+	int i;
+
+	if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
+		for (i = 0; i < ARRAY_SIZE(pix_desc); i++) {
+			if (fimc->vid_cap.mf.code == pix_desc[i].pixelcode) {
+				cfg = pix_desc[i].cisrcfmt;
+				bus_width = pix_desc[i].bus_width;
+				break;
+			}
+		}
+
+		if (i == ARRAY_SIZE(pix_desc)) {
+			v4l2_err(fimc->vid_cap.vfd,
+				 "Camera color format not supported: %d\n",
+				 fimc->vid_cap.mf.code);
+			return -EINVAL;
+		}
+
+		if (cam->bus_type == FIMC_ITU_601) {
+			if (bus_width == 8)
+				cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
+			else if (bus_width == 16)
+				cfg |= FIMC_REG_CISRCFMT_ITU601_16BIT;
+		} /* else defaults to ITU-R BT.656 8-bit */
+	} else if (cam->bus_type == FIMC_MIPI_CSI2) {
+		if (fimc_fmt_is_jpeg(f->fmt->color))
+			cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
+	}
+
+	cfg |= (f->o_width << 16) | f->o_height;
+	writel(cfg, fimc->regs + FIMC_REG_CISRCFMT);
+	return 0;
+}
+
+void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
+{
+	u32 hoff2, voff2;
+
+	u32 cfg = readl(fimc->regs + FIMC_REG_CIWDOFST);
+
+	cfg &= ~(FIMC_REG_CIWDOFST_HOROFF_MASK | FIMC_REG_CIWDOFST_VEROFF_MASK);
+	cfg |=  FIMC_REG_CIWDOFST_OFF_EN |
+		(f->offs_h << 16) | f->offs_v;
+
+	writel(cfg, fimc->regs + FIMC_REG_CIWDOFST);
+
+	/* See CIWDOFSTn register description in the datasheet for details. */
+	hoff2 = f->o_width - f->width - f->offs_h;
+	voff2 = f->o_height - f->height - f->offs_v;
+	cfg = (hoff2 << 16) | voff2;
+	writel(cfg, fimc->regs + FIMC_REG_CIWDOFST2);
+}
+
+int fimc_hw_set_camera_type(struct fimc_dev *fimc,
+			    struct s5p_fimc_isp_info *cam)
+{
+	u32 cfg, tmp;
+	struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+	u32 csis_data_alignment = 32;
+
+	cfg = readl(fimc->regs + FIMC_REG_CIGCTRL);
+
+	/* Select ITU B interface, disable Writeback path and test pattern. */
+	cfg &= ~(FIMC_REG_CIGCTRL_TESTPAT_MASK | FIMC_REG_CIGCTRL_SELCAM_ITU_A |
+		FIMC_REG_CIGCTRL_SELCAM_MIPI | FIMC_REG_CIGCTRL_CAMIF_SELWB |
+		FIMC_REG_CIGCTRL_SELCAM_MIPI_A | FIMC_REG_CIGCTRL_CAM_JPEG);
+
+	switch (cam->bus_type) {
+	case FIMC_MIPI_CSI2:
+		cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI;
+
+		if (cam->mux_id == 0)
+			cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI_A;
+
+		/* TODO: add remaining supported formats. */
+		switch (vid_cap->mf.code) {
+		case V4L2_MBUS_FMT_VYUY8_2X8:
+			tmp = FIMC_REG_CSIIMGFMT_YCBCR422_8BIT;
+			break;
+		case V4L2_MBUS_FMT_JPEG_1X8:
+			tmp = FIMC_REG_CSIIMGFMT_USER(1);
+			cfg |= FIMC_REG_CIGCTRL_CAM_JPEG;
+			break;
+		default:
+			v4l2_err(vid_cap->vfd,
+				 "Not supported camera pixel format: %#x\n",
+				 vid_cap->mf.code);
+			return -EINVAL;
+		}
+		tmp |= (csis_data_alignment == 32) << 8;
+
+		writel(tmp, fimc->regs + FIMC_REG_CSIIMGFMT);
+		break;
+	case FIMC_ITU_601...FIMC_ITU_656:
+		if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */
+			cfg |= FIMC_REG_CIGCTRL_SELCAM_ITU_A;
+		break;
+	case FIMC_LCD_WB:
+		cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB;
+		break;
+	default:
+		v4l2_err(vid_cap->vfd, "Invalid camera bus type selected\n");
+		return -EINVAL;
+	}
+	writel(cfg, fimc->regs + FIMC_REG_CIGCTRL);
+
+	return 0;
+}
+
+void fimc_hw_clear_irq(struct fimc_dev *dev)
+{
+	u32 cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
+	cfg |= FIMC_REG_CIGCTRL_IRQ_CLR;
+	writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
+}
+
+void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on)
+{
+	u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
+	if (on)
+		cfg |= FIMC_REG_CISCCTRL_SCALERSTART;
+	else
+		cfg &= ~FIMC_REG_CISCCTRL_SCALERSTART;
+	writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
+}
+
+void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on)
+{
+	u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL);
+	if (on)
+		cfg |= FIMC_REG_MSCTRL_ENVID;
+	else
+		cfg &= ~FIMC_REG_MSCTRL_ENVID;
+	writel(cfg, dev->regs + FIMC_REG_MSCTRL);
+}
+
+void fimc_hw_dis_capture(struct fimc_dev *dev)
+{
+	u32 cfg = readl(dev->regs + FIMC_REG_CIIMGCPT);
+	cfg &= ~(FIMC_REG_CIIMGCPT_IMGCPTEN | FIMC_REG_CIIMGCPT_IMGCPTEN_SC);
+	writel(cfg, dev->regs + FIMC_REG_CIIMGCPT);
+}
+
+/* Return an index to the buffer actually being written. */
+u32 fimc_hw_get_frame_index(struct fimc_dev *dev)
+{
+	u32 reg;
+
+	if (dev->variant->has_cistatus2) {
+		reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3F;
+		return reg > 0 ? --reg : reg;
+	}
+
+	reg = readl(dev->regs + FIMC_REG_CISTATUS);
+
+	return (reg & FIMC_REG_CISTATUS_FRAMECNT_MASK) >>
+		FIMC_REG_CISTATUS_FRAMECNT_SHIFT;
+}
+
+/* Locking: the caller holds fimc->slock */
+void fimc_activate_capture(struct fimc_ctx *ctx)
+{
+	fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled);
+	fimc_hw_en_capture(ctx);
+}
+
+void fimc_deactivate_capture(struct fimc_dev *fimc)
+{
+	fimc_hw_en_lastirq(fimc, true);
+	fimc_hw_dis_capture(fimc);
+	fimc_hw_enable_scaler(fimc, false);
+	fimc_hw_en_lastirq(fimc, false);
+}
diff --git a/drivers/media/platform/s5p-fimc/fimc-reg.h b/drivers/media/platform/s5p-fimc/fimc-reg.h
new file mode 100644
index 0000000..579ac8a
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-reg.h
@@ -0,0 +1,326 @@
+/*
+ * Samsung camera host interface (FIMC) registers definition
+ *
+ * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef FIMC_REG_H_
+#define FIMC_REG_H_
+
+#include "fimc-core.h"
+
+/* Input source format */
+#define FIMC_REG_CISRCFMT			0x00
+#define FIMC_REG_CISRCFMT_ITU601_8BIT		(1 << 31)
+#define FIMC_REG_CISRCFMT_ITU601_16BIT		(1 << 29)
+#define FIMC_REG_CISRCFMT_ORDER422_YCBYCR	(0 << 14)
+#define FIMC_REG_CISRCFMT_ORDER422_YCRYCB	(1 << 14)
+#define FIMC_REG_CISRCFMT_ORDER422_CBYCRY	(2 << 14)
+#define FIMC_REG_CISRCFMT_ORDER422_CRYCBY	(3 << 14)
+
+/* Window offset */
+#define FIMC_REG_CIWDOFST			0x04
+#define FIMC_REG_CIWDOFST_OFF_EN		(1 << 31)
+#define FIMC_REG_CIWDOFST_CLROVFIY		(1 << 30)
+#define FIMC_REG_CIWDOFST_CLROVRLB		(1 << 29)
+#define FIMC_REG_CIWDOFST_HOROFF_MASK		(0x7ff << 16)
+#define FIMC_REG_CIWDOFST_CLROVFICB		(1 << 15)
+#define FIMC_REG_CIWDOFST_CLROVFICR		(1 << 14)
+#define FIMC_REG_CIWDOFST_VEROFF_MASK		(0xfff << 0)
+
+/* Global control */
+#define FIMC_REG_CIGCTRL			0x08
+#define FIMC_REG_CIGCTRL_SWRST			(1 << 31)
+#define FIMC_REG_CIGCTRL_CAMRST_A		(1 << 30)
+#define FIMC_REG_CIGCTRL_SELCAM_ITU_A		(1 << 29)
+#define FIMC_REG_CIGCTRL_TESTPAT_NORMAL		(0 << 27)
+#define FIMC_REG_CIGCTRL_TESTPAT_COLOR_BAR	(1 << 27)
+#define FIMC_REG_CIGCTRL_TESTPAT_HOR_INC	(2 << 27)
+#define FIMC_REG_CIGCTRL_TESTPAT_VER_INC	(3 << 27)
+#define FIMC_REG_CIGCTRL_TESTPAT_MASK		(3 << 27)
+#define FIMC_REG_CIGCTRL_TESTPAT_SHIFT		27
+#define FIMC_REG_CIGCTRL_INVPOLPCLK		(1 << 26)
+#define FIMC_REG_CIGCTRL_INVPOLVSYNC		(1 << 25)
+#define FIMC_REG_CIGCTRL_INVPOLHREF		(1 << 24)
+#define FIMC_REG_CIGCTRL_IRQ_OVFEN		(1 << 22)
+#define FIMC_REG_CIGCTRL_HREF_MASK		(1 << 21)
+#define FIMC_REG_CIGCTRL_IRQ_LEVEL		(1 << 20)
+#define FIMC_REG_CIGCTRL_IRQ_CLR		(1 << 19)
+#define FIMC_REG_CIGCTRL_IRQ_ENABLE		(1 << 16)
+#define FIMC_REG_CIGCTRL_SHDW_DISABLE		(1 << 12)
+#define FIMC_REG_CIGCTRL_CAM_JPEG		(1 << 8)
+#define FIMC_REG_CIGCTRL_SELCAM_MIPI_A		(1 << 7)
+#define FIMC_REG_CIGCTRL_CAMIF_SELWB		(1 << 6)
+/* 0 - ITU601; 1 - ITU709 */
+#define FIMC_REG_CIGCTRL_CSC_ITU601_709		(1 << 5)
+#define FIMC_REG_CIGCTRL_INVPOLHSYNC		(1 << 4)
+#define FIMC_REG_CIGCTRL_SELCAM_MIPI		(1 << 3)
+#define FIMC_REG_CIGCTRL_INVPOLFIELD		(1 << 1)
+#define FIMC_REG_CIGCTRL_INTERLACE		(1 << 0)
+
+/* Window offset 2 */
+#define FIMC_REG_CIWDOFST2			0x14
+#define FIMC_REG_CIWDOFST2_HOROFF_MASK		(0xfff << 16)
+#define FIMC_REG_CIWDOFST2_VEROFF_MASK		(0xfff << 0)
+
+/* Output DMA Y/Cb/Cr plane start addresses */
+#define FIMC_REG_CIOYSA(n)			(0x18 + (n) * 4)
+#define FIMC_REG_CIOCBSA(n)			(0x28 + (n) * 4)
+#define FIMC_REG_CIOCRSA(n)			(0x38 + (n) * 4)
+
+/* Target image format */
+#define FIMC_REG_CITRGFMT			0x48
+#define FIMC_REG_CITRGFMT_INROT90		(1 << 31)
+#define FIMC_REG_CITRGFMT_YCBCR420		(0 << 29)
+#define FIMC_REG_CITRGFMT_YCBCR422		(1 << 29)
+#define FIMC_REG_CITRGFMT_YCBCR422_1P		(2 << 29)
+#define FIMC_REG_CITRGFMT_RGB			(3 << 29)
+#define FIMC_REG_CITRGFMT_FMT_MASK		(3 << 29)
+#define FIMC_REG_CITRGFMT_HSIZE_MASK		(0xfff << 16)
+#define FIMC_REG_CITRGFMT_FLIP_SHIFT		14
+#define FIMC_REG_CITRGFMT_FLIP_NORMAL		(0 << 14)
+#define FIMC_REG_CITRGFMT_FLIP_X_MIRROR		(1 << 14)
+#define FIMC_REG_CITRGFMT_FLIP_Y_MIRROR		(2 << 14)
+#define FIMC_REG_CITRGFMT_FLIP_180		(3 << 14)
+#define FIMC_REG_CITRGFMT_FLIP_MASK		(3 << 14)
+#define FIMC_REG_CITRGFMT_OUTROT90		(1 << 13)
+#define FIMC_REG_CITRGFMT_VSIZE_MASK		(0xfff << 0)
+
+/* Output DMA control */
+#define FIMC_REG_CIOCTRL			0x4c
+#define FIMC_REG_CIOCTRL_ORDER422_MASK		(3 << 0)
+#define FIMC_REG_CIOCTRL_ORDER422_CRYCBY	(0 << 0)
+#define FIMC_REG_CIOCTRL_ORDER422_CBYCRY	(1 << 0)
+#define FIMC_REG_CIOCTRL_ORDER422_YCRYCB	(2 << 0)
+#define FIMC_REG_CIOCTRL_ORDER422_YCBYCR	(3 << 0)
+#define FIMC_REG_CIOCTRL_LASTIRQ_ENABLE		(1 << 2)
+#define FIMC_REG_CIOCTRL_YCBCR_3PLANE		(0 << 3)
+#define FIMC_REG_CIOCTRL_YCBCR_2PLANE		(1 << 3)
+#define FIMC_REG_CIOCTRL_YCBCR_PLANE_MASK	(1 << 3)
+#define FIMC_REG_CIOCTRL_ALPHA_OUT_MASK		(0xff << 4)
+#define FIMC_REG_CIOCTRL_RGB16FMT_MASK		(3 << 16)
+#define FIMC_REG_CIOCTRL_RGB565			(0 << 16)
+#define FIMC_REG_CIOCTRL_ARGB1555		(1 << 16)
+#define FIMC_REG_CIOCTRL_ARGB4444		(2 << 16)
+#define FIMC_REG_CIOCTRL_ORDER2P_SHIFT		24
+#define FIMC_REG_CIOCTRL_ORDER2P_MASK		(3 << 24)
+#define FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB	(0 << 24)
+
+/* Pre-scaler control 1 */
+#define FIMC_REG_CISCPRERATIO			0x50
+
+#define FIMC_REG_CISCPREDST			0x54
+
+/* Main scaler control */
+#define FIMC_REG_CISCCTRL			0x58
+#define FIMC_REG_CISCCTRL_SCALERBYPASS		(1 << 31)
+#define FIMC_REG_CISCCTRL_SCALEUP_H		(1 << 30)
+#define FIMC_REG_CISCCTRL_SCALEUP_V		(1 << 29)
+#define FIMC_REG_CISCCTRL_CSCR2Y_WIDE		(1 << 28)
+#define FIMC_REG_CISCCTRL_CSCY2R_WIDE		(1 << 27)
+#define FIMC_REG_CISCCTRL_LCDPATHEN_FIFO	(1 << 26)
+#define FIMC_REG_CISCCTRL_INTERLACE		(1 << 25)
+#define FIMC_REG_CISCCTRL_SCALERSTART		(1 << 15)
+#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB565	(0 << 13)
+#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB666	(1 << 13)
+#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB888	(2 << 13)
+#define FIMC_REG_CISCCTRL_INRGB_FMT_MASK	(3 << 13)
+#define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB565	(0 << 11)
+#define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB666	(1 << 11)
+#define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888	(2 << 11)
+#define FIMC_REG_CISCCTRL_OUTRGB_FMT_MASK	(3 << 11)
+#define FIMC_REG_CISCCTRL_RGB_EXT		(1 << 10)
+#define FIMC_REG_CISCCTRL_ONE2ONE		(1 << 9)
+#define FIMC_REG_CISCCTRL_MHRATIO(x)		((x) << 16)
+#define FIMC_REG_CISCCTRL_MVRATIO(x)		((x) << 0)
+#define FIMC_REG_CISCCTRL_MHRATIO_MASK		(0x1ff << 16)
+#define FIMC_REG_CISCCTRL_MVRATIO_MASK		(0x1ff << 0)
+#define FIMC_REG_CISCCTRL_MHRATIO_EXT(x)	(((x) >> 6) << 16)
+#define FIMC_REG_CISCCTRL_MVRATIO_EXT(x)	(((x) >> 6) << 0)
+
+/* Target area */
+#define FIMC_REG_CITAREA			0x5c
+#define FIMC_REG_CITAREA_MASK			0x0fffffff
+
+/* General status */
+#define FIMC_REG_CISTATUS			0x64
+#define FIMC_REG_CISTATUS_OVFIY			(1 << 31)
+#define FIMC_REG_CISTATUS_OVFICB		(1 << 30)
+#define FIMC_REG_CISTATUS_OVFICR		(1 << 29)
+#define FIMC_REG_CISTATUS_VSYNC			(1 << 28)
+#define FIMC_REG_CISTATUS_FRAMECNT_MASK		(3 << 26)
+#define FIMC_REG_CISTATUS_FRAMECNT_SHIFT	26
+#define FIMC_REG_CISTATUS_WINOFF_EN		(1 << 25)
+#define FIMC_REG_CISTATUS_IMGCPT_EN		(1 << 22)
+#define FIMC_REG_CISTATUS_IMGCPT_SCEN		(1 << 21)
+#define FIMC_REG_CISTATUS_VSYNC_A		(1 << 20)
+#define FIMC_REG_CISTATUS_VSYNC_B		(1 << 19)
+#define FIMC_REG_CISTATUS_OVRLB			(1 << 18)
+#define FIMC_REG_CISTATUS_FRAME_END		(1 << 17)
+#define FIMC_REG_CISTATUS_LASTCAPT_END		(1 << 16)
+#define FIMC_REG_CISTATUS_VVALID_A		(1 << 15)
+#define FIMC_REG_CISTATUS_VVALID_B		(1 << 14)
+
+/* Indexes to the last and the currently processed buffer. */
+#define FIMC_REG_CISTATUS2			0x68
+
+/* Image capture control */
+#define FIMC_REG_CIIMGCPT			0xc0
+#define FIMC_REG_CIIMGCPT_IMGCPTEN		(1 << 31)
+#define FIMC_REG_CIIMGCPT_IMGCPTEN_SC		(1 << 30)
+#define FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE	(1 << 25)
+#define FIMC_REG_CIIMGCPT_CPT_FRMOD_CNT		(1 << 18)
+
+/* Frame capture sequence */
+#define FIMC_REG_CICPTSEQ			0xc4
+
+/* Image effect */
+#define FIMC_REG_CIIMGEFF			0xd0
+#define FIMC_REG_CIIMGEFF_IE_ENABLE		(1 << 30)
+#define FIMC_REG_CIIMGEFF_IE_SC_BEFORE		(0 << 29)
+#define FIMC_REG_CIIMGEFF_IE_SC_AFTER		(1 << 29)
+#define FIMC_REG_CIIMGEFF_FIN_BYPASS		(0 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_ARBITRARY		(1 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_NEGATIVE		(2 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_ARTFREEZE		(3 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_EMBOSSING		(4 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_SILHOUETTE	(5 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_MASK		(7 << 26)
+#define FIMC_REG_CIIMGEFF_PAT_CBCR_MASK		((0xff << 13) | 0xff)
+
+/* Input DMA Y/Cb/Cr plane start address 0/1 */
+#define FIMC_REG_CIIYSA(n)			(0xd4 + (n) * 0x70)
+#define FIMC_REG_CIICBSA(n)			(0xd8 + (n) * 0x70)
+#define FIMC_REG_CIICRSA(n)			(0xdc + (n) * 0x70)
+
+/* Real input DMA image size */
+#define FIMC_REG_CIREAL_ISIZE			0xf8
+#define FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN	(1 << 31)
+#define FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS	(1 << 30)
+
+/* Input DMA control */
+#define FIMC_REG_MSCTRL				0xfc
+#define FIMC_REG_MSCTRL_IN_BURST_COUNT_MASK	(0xf << 24)
+#define FIMC_REG_MSCTRL_2P_IN_ORDER_MASK	(3 << 16)
+#define FIMC_REG_MSCTRL_2P_IN_ORDER_SHIFT	16
+#define FIMC_REG_MSCTRL_C_INT_IN_3PLANE		(0 << 15)
+#define FIMC_REG_MSCTRL_C_INT_IN_2PLANE		(1 << 15)
+#define FIMC_REG_MSCTRL_C_INT_IN_MASK		(1 << 15)
+#define FIMC_REG_MSCTRL_FLIP_SHIFT		13
+#define FIMC_REG_MSCTRL_FLIP_MASK		(3 << 13)
+#define FIMC_REG_MSCTRL_FLIP_NORMAL		(0 << 13)
+#define FIMC_REG_MSCTRL_FLIP_X_MIRROR		(1 << 13)
+#define FIMC_REG_MSCTRL_FLIP_Y_MIRROR		(2 << 13)
+#define FIMC_REG_MSCTRL_FLIP_180		(3 << 13)
+#define FIMC_REG_MSCTRL_FIFO_CTRL_FULL		(1 << 12)
+#define FIMC_REG_MSCTRL_ORDER422_SHIFT		4
+#define FIMC_REG_MSCTRL_ORDER422_YCBYCR		(0 << 4)
+#define FIMC_REG_MSCTRL_ORDER422_CBYCRY		(1 << 4)
+#define FIMC_REG_MSCTRL_ORDER422_YCRYCB		(2 << 4)
+#define FIMC_REG_MSCTRL_ORDER422_CRYCBY		(3 << 4)
+#define FIMC_REG_MSCTRL_ORDER422_MASK		(3 << 4)
+#define FIMC_REG_MSCTRL_INPUT_EXTCAM		(0 << 3)
+#define FIMC_REG_MSCTRL_INPUT_MEMORY		(1 << 3)
+#define FIMC_REG_MSCTRL_INPUT_MASK		(1 << 3)
+#define FIMC_REG_MSCTRL_INFORMAT_YCBCR420	(0 << 1)
+#define FIMC_REG_MSCTRL_INFORMAT_YCBCR422	(1 << 1)
+#define FIMC_REG_MSCTRL_INFORMAT_YCBCR422_1P	(2 << 1)
+#define FIMC_REG_MSCTRL_INFORMAT_RGB		(3 << 1)
+#define FIMC_REG_MSCTRL_INFORMAT_MASK		(3 << 1)
+#define FIMC_REG_MSCTRL_ENVID			(1 << 0)
+#define FIMC_REG_MSCTRL_IN_BURST_COUNT(x)	((x) << 24)
+
+/* Output DMA Y/Cb/Cr offset */
+#define FIMC_REG_CIOYOFF			0x168
+#define FIMC_REG_CIOCBOFF			0x16c
+#define FIMC_REG_CIOCROFF			0x170
+
+/* Input DMA Y/Cb/Cr offset */
+#define FIMC_REG_CIIYOFF			0x174
+#define FIMC_REG_CIICBOFF			0x178
+#define FIMC_REG_CIICROFF			0x17c
+
+/* Input DMA original image size */
+#define FIMC_REG_ORGISIZE			0x180
+
+/* Output DMA original image size */
+#define FIMC_REG_ORGOSIZE			0x184
+
+/* Real output DMA image size (extension register) */
+#define FIMC_REG_CIEXTEN			0x188
+#define FIMC_REG_CIEXTEN_MHRATIO_EXT(x)		(((x) & 0x3f) << 10)
+#define FIMC_REG_CIEXTEN_MVRATIO_EXT(x)		((x) & 0x3f)
+#define FIMC_REG_CIEXTEN_MHRATIO_EXT_MASK	(0x3f << 10)
+#define FIMC_REG_CIEXTEN_MVRATIO_EXT_MASK	0x3f
+
+#define FIMC_REG_CIDMAPARAM			0x18c
+#define FIMC_REG_CIDMAPARAM_R_LINEAR		(0 << 29)
+#define FIMC_REG_CIDMAPARAM_R_64X32		(3 << 29)
+#define FIMC_REG_CIDMAPARAM_W_LINEAR		(0 << 13)
+#define FIMC_REG_CIDMAPARAM_W_64X32		(3 << 13)
+#define FIMC_REG_CIDMAPARAM_TILE_MASK		((3 << 29) | (3 << 13))
+
+/* MIPI CSI image format */
+#define FIMC_REG_CSIIMGFMT			0x194
+#define FIMC_REG_CSIIMGFMT_YCBCR422_8BIT	0x1e
+#define FIMC_REG_CSIIMGFMT_RAW8			0x2a
+#define FIMC_REG_CSIIMGFMT_RAW10		0x2b
+#define FIMC_REG_CSIIMGFMT_RAW12		0x2c
+/* User defined formats. x = 0...16. */
+#define FIMC_REG_CSIIMGFMT_USER(x)		(0x30 + x - 1)
+
+/* Output frame buffer sequence mask */
+#define FIMC_REG_CIFCNTSEQ			0x1fc
+
+/*
+ * Function declarations
+ */
+void fimc_hw_reset(struct fimc_dev *fimc);
+void fimc_hw_set_rotation(struct fimc_ctx *ctx);
+void fimc_hw_set_target_format(struct fimc_ctx *ctx);
+void fimc_hw_set_out_dma(struct fimc_ctx *ctx);
+void fimc_hw_en_lastirq(struct fimc_dev *fimc, int enable);
+void fimc_hw_en_irq(struct fimc_dev *fimc, int enable);
+void fimc_hw_set_prescaler(struct fimc_ctx *ctx);
+void fimc_hw_set_mainscaler(struct fimc_ctx *ctx);
+void fimc_hw_en_capture(struct fimc_ctx *ctx);
+void fimc_hw_set_effect(struct fimc_ctx *ctx);
+void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx);
+void fimc_hw_set_in_dma(struct fimc_ctx *ctx);
+void fimc_hw_set_input_path(struct fimc_ctx *ctx);
+void fimc_hw_set_output_path(struct fimc_ctx *ctx);
+void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr);
+void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr,
+			     int index);
+int fimc_hw_set_camera_source(struct fimc_dev *fimc,
+			      struct s5p_fimc_isp_info *cam);
+void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f);
+int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
+				struct s5p_fimc_isp_info *cam);
+int fimc_hw_set_camera_type(struct fimc_dev *fimc,
+			    struct s5p_fimc_isp_info *cam);
+void fimc_hw_clear_irq(struct fimc_dev *dev);
+void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on);
+void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on);
+void fimc_hw_dis_capture(struct fimc_dev *dev);
+u32 fimc_hw_get_frame_index(struct fimc_dev *dev);
+void fimc_activate_capture(struct fimc_ctx *ctx);
+void fimc_deactivate_capture(struct fimc_dev *fimc);
+
+/**
+ * fimc_hw_set_dma_seq - configure output DMA buffer sequence
+ * @mask: bitmask for the DMA output buffer registers, set to 0 to skip buffer
+ * This function masks output DMA ring buffers, it allows to select which of
+ * the 32 available output buffer address registers will be used by the DMA
+ * engine.
+ */
+static inline void fimc_hw_set_dma_seq(struct fimc_dev *dev, u32 mask)
+{
+	writel(mask, dev->regs + FIMC_REG_CIFCNTSEQ);
+}
+
+#endif /* FIMC_REG_H_ */
diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c
new file mode 100644
index 0000000..2f73d9e
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/mipi-csis.c
@@ -0,0 +1,722 @@
+/*
+ * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/memory.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+#include <plat/mipi_csis.h>
+#include "mipi-csis.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/* Register map definition */
+
+/* CSIS global control */
+#define S5PCSIS_CTRL			0x00
+#define S5PCSIS_CTRL_DPDN_DEFAULT	(0 << 31)
+#define S5PCSIS_CTRL_DPDN_SWAP		(1 << 31)
+#define S5PCSIS_CTRL_ALIGN_32BIT	(1 << 20)
+#define S5PCSIS_CTRL_UPDATE_SHADOW	(1 << 16)
+#define S5PCSIS_CTRL_WCLK_EXTCLK	(1 << 8)
+#define S5PCSIS_CTRL_RESET		(1 << 4)
+#define S5PCSIS_CTRL_ENABLE		(1 << 0)
+
+/* D-PHY control */
+#define S5PCSIS_DPHYCTRL		0x04
+#define S5PCSIS_DPHYCTRL_HSS_MASK	(0x1f << 27)
+#define S5PCSIS_DPHYCTRL_ENABLE		(0x1f << 0)
+
+#define S5PCSIS_CONFIG			0x08
+#define S5PCSIS_CFG_FMT_YCBCR422_8BIT	(0x1e << 2)
+#define S5PCSIS_CFG_FMT_RAW8		(0x2a << 2)
+#define S5PCSIS_CFG_FMT_RAW10		(0x2b << 2)
+#define S5PCSIS_CFG_FMT_RAW12		(0x2c << 2)
+/* User defined formats, x = 1...4 */
+#define S5PCSIS_CFG_FMT_USER(x)		((0x30 + x - 1) << 2)
+#define S5PCSIS_CFG_FMT_MASK		(0x3f << 2)
+#define S5PCSIS_CFG_NR_LANE_MASK	3
+
+/* Interrupt mask. */
+#define S5PCSIS_INTMSK			0x10
+#define S5PCSIS_INTMSK_EN_ALL		0xf000003f
+#define S5PCSIS_INTSRC			0x14
+
+/* Pixel resolution */
+#define S5PCSIS_RESOL			0x2c
+#define CSIS_MAX_PIX_WIDTH		0xffff
+#define CSIS_MAX_PIX_HEIGHT		0xffff
+
+enum {
+	CSIS_CLK_MUX,
+	CSIS_CLK_GATE,
+};
+
+static char *csi_clock_name[] = {
+	[CSIS_CLK_MUX]  = "sclk_csis",
+	[CSIS_CLK_GATE] = "csis",
+};
+#define NUM_CSIS_CLOCKS	ARRAY_SIZE(csi_clock_name)
+
+static const char * const csis_supply_name[] = {
+	"vdd11", /* 1.1V or 1.2V (s5pc100) MIPI CSI suppply */
+	"vdd18", /* VDD 1.8V and MIPI CSI PLL supply */
+};
+#define CSIS_NUM_SUPPLIES ARRAY_SIZE(csis_supply_name)
+
+enum {
+	ST_POWERED	= 1,
+	ST_STREAMING	= 2,
+	ST_SUSPENDED	= 4,
+};
+
+/**
+ * struct csis_state - the driver's internal state data structure
+ * @lock: mutex serializing the subdev and power management operations,
+ *        protecting @format and @flags members
+ * @pads: CSIS pads array
+ * @sd: v4l2_subdev associated with CSIS device instance
+ * @pdev: CSIS platform device
+ * @regs: mmaped I/O registers memory
+ * @clock: CSIS clocks
+ * @irq: requested s5p-mipi-csis irq number
+ * @flags: the state variable for power and streaming control
+ * @csis_fmt: current CSIS pixel format
+ * @format: common media bus format for the source and sink pad
+ */
+struct csis_state {
+	struct mutex lock;
+	struct media_pad pads[CSIS_PADS_NUM];
+	struct v4l2_subdev sd;
+	struct platform_device *pdev;
+	void __iomem *regs;
+	struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES];
+	struct clk *clock[NUM_CSIS_CLOCKS];
+	int irq;
+	u32 flags;
+	const struct csis_pix_format *csis_fmt;
+	struct v4l2_mbus_framefmt format;
+};
+
+/**
+ * struct csis_pix_format - CSIS pixel format description
+ * @pix_width_alignment: horizontal pixel alignment, width will be
+ *                       multiple of 2^pix_width_alignment
+ * @code: corresponding media bus code
+ * @fmt_reg: S5PCSIS_CONFIG register value
+ * @data_alignment: MIPI-CSI data alignment in bits
+ */
+struct csis_pix_format {
+	unsigned int pix_width_alignment;
+	enum v4l2_mbus_pixelcode code;
+	u32 fmt_reg;
+	u8 data_alignment;
+};
+
+static const struct csis_pix_format s5pcsis_formats[] = {
+	{
+		.code = V4L2_MBUS_FMT_VYUY8_2X8,
+		.fmt_reg = S5PCSIS_CFG_FMT_YCBCR422_8BIT,
+		.data_alignment = 32,
+	}, {
+		.code = V4L2_MBUS_FMT_JPEG_1X8,
+		.fmt_reg = S5PCSIS_CFG_FMT_USER(1),
+		.data_alignment = 32,
+	},
+};
+
+#define s5pcsis_write(__csis, __r, __v) writel(__v, __csis->regs + __r)
+#define s5pcsis_read(__csis, __r) readl(__csis->regs + __r)
+
+static struct csis_state *sd_to_csis_state(struct v4l2_subdev *sdev)
+{
+	return container_of(sdev, struct csis_state, sd);
+}
+
+static const struct csis_pix_format *find_csis_format(
+	struct v4l2_mbus_framefmt *mf)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(s5pcsis_formats); i++)
+		if (mf->code == s5pcsis_formats[i].code)
+			return &s5pcsis_formats[i];
+	return NULL;
+}
+
+static void s5pcsis_enable_interrupts(struct csis_state *state, bool on)
+{
+	u32 val = s5pcsis_read(state, S5PCSIS_INTMSK);
+
+	val = on ? val | S5PCSIS_INTMSK_EN_ALL :
+		   val & ~S5PCSIS_INTMSK_EN_ALL;
+	s5pcsis_write(state, S5PCSIS_INTMSK, val);
+}
+
+static void s5pcsis_reset(struct csis_state *state)
+{
+	u32 val = s5pcsis_read(state, S5PCSIS_CTRL);
+
+	s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_RESET);
+	udelay(10);
+}
+
+static void s5pcsis_system_enable(struct csis_state *state, int on)
+{
+	u32 val;
+
+	val = s5pcsis_read(state, S5PCSIS_CTRL);
+	if (on)
+		val |= S5PCSIS_CTRL_ENABLE;
+	else
+		val &= ~S5PCSIS_CTRL_ENABLE;
+	s5pcsis_write(state, S5PCSIS_CTRL, val);
+
+	val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
+	if (on)
+		val |= S5PCSIS_DPHYCTRL_ENABLE;
+	else
+		val &= ~S5PCSIS_DPHYCTRL_ENABLE;
+	s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
+}
+
+/* Called with the state.lock mutex held */
+static void __s5pcsis_set_format(struct csis_state *state)
+{
+	struct v4l2_mbus_framefmt *mf = &state->format;
+	u32 val;
+
+	v4l2_dbg(1, debug, &state->sd, "fmt: %d, %d x %d\n",
+		 mf->code, mf->width, mf->height);
+
+	/* Color format */
+	val = s5pcsis_read(state, S5PCSIS_CONFIG);
+	val = (val & ~S5PCSIS_CFG_FMT_MASK) | state->csis_fmt->fmt_reg;
+	s5pcsis_write(state, S5PCSIS_CONFIG, val);
+
+	/* Pixel resolution */
+	val = (mf->width << 16) | mf->height;
+	s5pcsis_write(state, S5PCSIS_RESOL, val);
+}
+
+static void s5pcsis_set_hsync_settle(struct csis_state *state, int settle)
+{
+	u32 val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
+
+	val = (val & ~S5PCSIS_DPHYCTRL_HSS_MASK) | (settle << 27);
+	s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
+}
+
+static void s5pcsis_set_params(struct csis_state *state)
+{
+	struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data;
+	u32 val;
+
+	val = s5pcsis_read(state, S5PCSIS_CONFIG);
+	val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (pdata->lanes - 1);
+	s5pcsis_write(state, S5PCSIS_CONFIG, val);
+
+	__s5pcsis_set_format(state);
+	s5pcsis_set_hsync_settle(state, pdata->hs_settle);
+
+	val = s5pcsis_read(state, S5PCSIS_CTRL);
+	if (state->csis_fmt->data_alignment == 32)
+		val |= S5PCSIS_CTRL_ALIGN_32BIT;
+	else /* 24-bits */
+		val &= ~S5PCSIS_CTRL_ALIGN_32BIT;
+	/* Not using external clock. */
+	val &= ~S5PCSIS_CTRL_WCLK_EXTCLK;
+	s5pcsis_write(state, S5PCSIS_CTRL, val);
+
+	/* Update the shadow register. */
+	val = s5pcsis_read(state, S5PCSIS_CTRL);
+	s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_UPDATE_SHADOW);
+}
+
+static void s5pcsis_clk_put(struct csis_state *state)
+{
+	int i;
+
+	for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
+		if (IS_ERR_OR_NULL(state->clock[i]))
+			continue;
+		clk_unprepare(state->clock[i]);
+		clk_put(state->clock[i]);
+		state->clock[i] = NULL;
+	}
+}
+
+static int s5pcsis_clk_get(struct csis_state *state)
+{
+	struct device *dev = &state->pdev->dev;
+	int i, ret;
+
+	for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
+		state->clock[i] = clk_get(dev, csi_clock_name[i]);
+		if (IS_ERR(state->clock[i]))
+			goto err;
+		ret = clk_prepare(state->clock[i]);
+		if (ret < 0) {
+			clk_put(state->clock[i]);
+			state->clock[i] = NULL;
+			goto err;
+		}
+	}
+	return 0;
+err:
+	s5pcsis_clk_put(state);
+	dev_err(dev, "failed to get clock: %s\n", csi_clock_name[i]);
+	return -ENXIO;
+}
+
+static int s5pcsis_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct csis_state *state = sd_to_csis_state(sd);
+	struct device *dev = &state->pdev->dev;
+
+	if (on)
+		return pm_runtime_get_sync(dev);
+
+	return pm_runtime_put_sync(dev);
+}
+
+static void s5pcsis_start_stream(struct csis_state *state)
+{
+	s5pcsis_reset(state);
+	s5pcsis_set_params(state);
+	s5pcsis_system_enable(state, true);
+	s5pcsis_enable_interrupts(state, true);
+}
+
+static void s5pcsis_stop_stream(struct csis_state *state)
+{
+	s5pcsis_enable_interrupts(state, false);
+	s5pcsis_system_enable(state, false);
+}
+
+/* v4l2_subdev operations */
+static int s5pcsis_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct csis_state *state = sd_to_csis_state(sd);
+	int ret = 0;
+
+	v4l2_dbg(1, debug, sd, "%s: %d, state: 0x%x\n",
+		 __func__, enable, state->flags);
+
+	if (enable) {
+		ret = pm_runtime_get_sync(&state->pdev->dev);
+		if (ret && ret != 1)
+			return ret;
+	}
+	mutex_lock(&state->lock);
+	if (enable) {
+		if (state->flags & ST_SUSPENDED) {
+			ret = -EBUSY;
+			goto unlock;
+		}
+		s5pcsis_start_stream(state);
+		state->flags |= ST_STREAMING;
+	} else {
+		s5pcsis_stop_stream(state);
+		state->flags &= ~ST_STREAMING;
+	}
+unlock:
+	mutex_unlock(&state->lock);
+	if (!enable)
+		pm_runtime_put(&state->pdev->dev);
+
+	return ret == 1 ? 0 : ret;
+}
+
+static int s5pcsis_enum_mbus_code(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->index >= ARRAY_SIZE(s5pcsis_formats))
+		return -EINVAL;
+
+	code->code = s5pcsis_formats[code->index].code;
+	return 0;
+}
+
+static struct csis_pix_format const *s5pcsis_try_format(
+	struct v4l2_mbus_framefmt *mf)
+{
+	struct csis_pix_format const *csis_fmt;
+
+	csis_fmt = find_csis_format(mf);
+	if (csis_fmt == NULL)
+		csis_fmt = &s5pcsis_formats[0];
+
+	mf->code = csis_fmt->code;
+	v4l_bound_align_image(&mf->width, 1, CSIS_MAX_PIX_WIDTH,
+			      csis_fmt->pix_width_alignment,
+			      &mf->height, 1, CSIS_MAX_PIX_HEIGHT, 1,
+			      0);
+	return csis_fmt;
+}
+
+static struct v4l2_mbus_framefmt *__s5pcsis_get_format(
+		struct csis_state *state, struct v4l2_subdev_fh *fh,
+		u32 pad, enum v4l2_subdev_format_whence which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL;
+
+	return &state->format;
+}
+
+static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			   struct v4l2_subdev_format *fmt)
+{
+	struct csis_state *state = sd_to_csis_state(sd);
+	struct csis_pix_format const *csis_fmt;
+	struct v4l2_mbus_framefmt *mf;
+
+	if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK)
+		return -EINVAL;
+
+	mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
+
+	if (fmt->pad == CSIS_PAD_SOURCE) {
+		if (mf) {
+			mutex_lock(&state->lock);
+			fmt->format = *mf;
+			mutex_unlock(&state->lock);
+		}
+		return 0;
+	}
+	csis_fmt = s5pcsis_try_format(&fmt->format);
+	if (mf) {
+		mutex_lock(&state->lock);
+		*mf = fmt->format;
+		if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+			state->csis_fmt = csis_fmt;
+		mutex_unlock(&state->lock);
+	}
+	return 0;
+}
+
+static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			   struct v4l2_subdev_format *fmt)
+{
+	struct csis_state *state = sd_to_csis_state(sd);
+	struct v4l2_mbus_framefmt *mf;
+
+	if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK)
+		return -EINVAL;
+
+	mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
+	if (!mf)
+		return -EINVAL;
+
+	mutex_lock(&state->lock);
+	fmt->format = *mf;
+	mutex_unlock(&state->lock);
+	return 0;
+}
+
+static int s5pcsis_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
+
+	format->colorspace = V4L2_COLORSPACE_JPEG;
+	format->code = s5pcsis_formats[0].code;
+	format->width = S5PCSIS_DEF_PIX_WIDTH;
+	format->height = S5PCSIS_DEF_PIX_HEIGHT;
+	format->field = V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops s5pcsis_sd_internal_ops = {
+	.open = s5pcsis_open,
+};
+
+static struct v4l2_subdev_core_ops s5pcsis_core_ops = {
+	.s_power = s5pcsis_s_power,
+};
+
+static struct v4l2_subdev_pad_ops s5pcsis_pad_ops = {
+	.enum_mbus_code = s5pcsis_enum_mbus_code,
+	.get_fmt = s5pcsis_get_fmt,
+	.set_fmt = s5pcsis_set_fmt,
+};
+
+static struct v4l2_subdev_video_ops s5pcsis_video_ops = {
+	.s_stream = s5pcsis_s_stream,
+};
+
+static struct v4l2_subdev_ops s5pcsis_subdev_ops = {
+	.core = &s5pcsis_core_ops,
+	.pad = &s5pcsis_pad_ops,
+	.video = &s5pcsis_video_ops,
+};
+
+static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id)
+{
+	struct csis_state *state = dev_id;
+	u32 val;
+
+	/* Just clear the interrupt pending bits. */
+	val = s5pcsis_read(state, S5PCSIS_INTSRC);
+	s5pcsis_write(state, S5PCSIS_INTSRC, val);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit s5pcsis_probe(struct platform_device *pdev)
+{
+	struct s5p_platform_mipi_csis *pdata;
+	struct resource *mem_res;
+	struct csis_state *state;
+	int ret = -ENOMEM;
+	int i;
+
+	state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	mutex_init(&state->lock);
+	state->pdev = pdev;
+
+	pdata = pdev->dev.platform_data;
+	if (pdata == NULL || pdata->phy_enable == NULL) {
+		dev_err(&pdev->dev, "Platform data not fully specified\n");
+		return -EINVAL;
+	}
+
+	if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) ||
+	    pdata->lanes > CSIS0_MAX_LANES) {
+		dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n",
+			pdata->lanes);
+		return -EINVAL;
+	}
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	state->regs = devm_request_and_ioremap(&pdev->dev, mem_res);
+	if (state->regs == NULL) {
+		dev_err(&pdev->dev, "Failed to request and remap io memory\n");
+		return -ENXIO;
+	}
+
+	state->irq = platform_get_irq(pdev, 0);
+	if (state->irq < 0) {
+		dev_err(&pdev->dev, "Failed to get irq\n");
+		return state->irq;
+	}
+
+	for (i = 0; i < CSIS_NUM_SUPPLIES; i++)
+		state->supplies[i].supply = csis_supply_name[i];
+
+	ret = regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES,
+				 state->supplies);
+	if (ret)
+		return ret;
+
+	ret = s5pcsis_clk_get(state);
+	if (ret)
+		goto e_clkput;
+
+	clk_enable(state->clock[CSIS_CLK_MUX]);
+	if (pdata->clk_rate)
+		clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate);
+	else
+		dev_WARN(&pdev->dev, "No clock frequency specified!\n");
+
+	ret = devm_request_irq(&pdev->dev, state->irq, s5pcsis_irq_handler,
+			       0, dev_name(&pdev->dev), state);
+	if (ret) {
+		dev_err(&pdev->dev, "Interrupt request failed\n");
+		goto e_regput;
+	}
+
+	v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops);
+	state->sd.owner = THIS_MODULE;
+	strlcpy(state->sd.name, dev_name(&pdev->dev), sizeof(state->sd.name));
+	state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	state->csis_fmt = &s5pcsis_formats[0];
+
+	state->format.code = s5pcsis_formats[0].code;
+	state->format.width = S5PCSIS_DEF_PIX_WIDTH;
+	state->format.height = S5PCSIS_DEF_PIX_HEIGHT;
+
+	state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_init(&state->sd.entity,
+				CSIS_PADS_NUM, state->pads, 0);
+	if (ret < 0)
+		goto e_clkput;
+
+	/* This allows to retrieve the platform device id by the host driver */
+	v4l2_set_subdevdata(&state->sd, pdev);
+
+	/* .. and a pointer to the subdev. */
+	platform_set_drvdata(pdev, &state->sd);
+
+	pm_runtime_enable(&pdev->dev);
+	return 0;
+
+e_regput:
+	regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies);
+e_clkput:
+	clk_disable(state->clock[CSIS_CLK_MUX]);
+	s5pcsis_clk_put(state);
+	return ret;
+}
+
+static int s5pcsis_pm_suspend(struct device *dev, bool runtime)
+{
+	struct s5p_platform_mipi_csis *pdata = dev->platform_data;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+	struct csis_state *state = sd_to_csis_state(sd);
+	int ret = 0;
+
+	v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n",
+		 __func__, state->flags);
+
+	mutex_lock(&state->lock);
+	if (state->flags & ST_POWERED) {
+		s5pcsis_stop_stream(state);
+		ret = pdata->phy_enable(state->pdev, false);
+		if (ret)
+			goto unlock;
+		ret = regulator_bulk_disable(CSIS_NUM_SUPPLIES,
+					     state->supplies);
+		if (ret)
+			goto unlock;
+		clk_disable(state->clock[CSIS_CLK_GATE]);
+		state->flags &= ~ST_POWERED;
+		if (!runtime)
+			state->flags |= ST_SUSPENDED;
+	}
+ unlock:
+	mutex_unlock(&state->lock);
+	return ret ? -EAGAIN : 0;
+}
+
+static int s5pcsis_pm_resume(struct device *dev, bool runtime)
+{
+	struct s5p_platform_mipi_csis *pdata = dev->platform_data;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+	struct csis_state *state = sd_to_csis_state(sd);
+	int ret = 0;
+
+	v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n",
+		 __func__, state->flags);
+
+	mutex_lock(&state->lock);
+	if (!runtime && !(state->flags & ST_SUSPENDED))
+		goto unlock;
+
+	if (!(state->flags & ST_POWERED)) {
+		ret = regulator_bulk_enable(CSIS_NUM_SUPPLIES,
+					    state->supplies);
+		if (ret)
+			goto unlock;
+		ret = pdata->phy_enable(state->pdev, true);
+		if (!ret) {
+			state->flags |= ST_POWERED;
+		} else {
+			regulator_bulk_disable(CSIS_NUM_SUPPLIES,
+					       state->supplies);
+			goto unlock;
+		}
+		clk_enable(state->clock[CSIS_CLK_GATE]);
+	}
+	if (state->flags & ST_STREAMING)
+		s5pcsis_start_stream(state);
+
+	state->flags &= ~ST_SUSPENDED;
+ unlock:
+	mutex_unlock(&state->lock);
+	return ret ? -EAGAIN : 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int s5pcsis_suspend(struct device *dev)
+{
+	return s5pcsis_pm_suspend(dev, false);
+}
+
+static int s5pcsis_resume(struct device *dev)
+{
+	return s5pcsis_pm_resume(dev, false);
+}
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int s5pcsis_runtime_suspend(struct device *dev)
+{
+	return s5pcsis_pm_suspend(dev, true);
+}
+
+static int s5pcsis_runtime_resume(struct device *dev)
+{
+	return s5pcsis_pm_resume(dev, true);
+}
+#endif
+
+static int __devexit s5pcsis_remove(struct platform_device *pdev)
+{
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+	struct csis_state *state = sd_to_csis_state(sd);
+
+	pm_runtime_disable(&pdev->dev);
+	s5pcsis_pm_suspend(&pdev->dev, false);
+	clk_disable(state->clock[CSIS_CLK_MUX]);
+	pm_runtime_set_suspended(&pdev->dev);
+	s5pcsis_clk_put(state);
+	regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies);
+
+	media_entity_cleanup(&state->sd.entity);
+
+	return 0;
+}
+
+static const struct dev_pm_ops s5pcsis_pm_ops = {
+	SET_RUNTIME_PM_OPS(s5pcsis_runtime_suspend, s5pcsis_runtime_resume,
+			   NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_suspend, s5pcsis_resume)
+};
+
+static struct platform_driver s5pcsis_driver = {
+	.probe		= s5pcsis_probe,
+	.remove		= __devexit_p(s5pcsis_remove),
+	.driver		= {
+		.name	= CSIS_DRIVER_NAME,
+		.owner	= THIS_MODULE,
+		.pm	= &s5pcsis_pm_ops,
+	},
+};
+
+module_platform_driver(s5pcsis_driver);
+
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC MIPI-CSI2 receiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.h b/drivers/media/platform/s5p-fimc/mipi-csis.h
new file mode 100644
index 0000000..2709286
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/mipi-csis.h
@@ -0,0 +1,25 @@
+/*
+ * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef S5P_MIPI_CSIS_H_
+#define S5P_MIPI_CSIS_H_
+
+#define CSIS_DRIVER_NAME	"s5p-mipi-csis"
+#define CSIS_MAX_ENTITIES	2
+#define CSIS0_MAX_LANES		4
+#define CSIS1_MAX_LANES		2
+
+#define CSIS_PAD_SINK		0
+#define CSIS_PAD_SOURCE		1
+#define CSIS_PADS_NUM		2
+
+#define S5PCSIS_DEF_PIX_WIDTH	640
+#define S5PCSIS_DEF_PIX_HEIGHT	480
+
+#endif
diff --git a/drivers/media/platform/s5p-g2d/Makefile b/drivers/media/platform/s5p-g2d/Makefile
new file mode 100644
index 0000000..2c48c41
--- /dev/null
+++ b/drivers/media/platform/s5p-g2d/Makefile
@@ -0,0 +1,3 @@
+s5p-g2d-objs := g2d.o g2d-hw.o
+
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D)	+= s5p-g2d.o
diff --git a/drivers/media/platform/s5p-g2d/g2d-hw.c b/drivers/media/platform/s5p-g2d/g2d-hw.c
new file mode 100644
index 0000000..5b86cbe
--- /dev/null
+++ b/drivers/media/platform/s5p-g2d/g2d-hw.c
@@ -0,0 +1,109 @@
+/*
+ * Samsung S5P G2D - 2D Graphics Accelerator Driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version
+ */
+
+#include <linux/io.h>
+
+#include "g2d.h"
+#include "g2d-regs.h"
+
+#define w(x, a)	writel((x), d->regs + (a))
+#define r(a)	readl(d->regs + (a))
+
+/* g2d_reset clears all g2d registers */
+void g2d_reset(struct g2d_dev *d)
+{
+	w(1, SOFT_RESET_REG);
+}
+
+void g2d_set_src_size(struct g2d_dev *d, struct g2d_frame *f)
+{
+	u32 n;
+
+	w(f->stride & 0xFFFF, SRC_STRIDE_REG);
+
+	n = f->o_height & 0xFFF;
+	n <<= 16;
+	n |= f->o_width & 0xFFF;
+	w(n, SRC_LEFT_TOP_REG);
+
+	n = f->bottom & 0xFFF;
+	n <<= 16;
+	n |= f->right & 0xFFF;
+	w(n, SRC_RIGHT_BOTTOM_REG);
+
+	w(f->fmt->hw, SRC_COLOR_MODE_REG);
+}
+
+void g2d_set_src_addr(struct g2d_dev *d, dma_addr_t a)
+{
+	w(a, SRC_BASE_ADDR_REG);
+}
+
+void g2d_set_dst_size(struct g2d_dev *d, struct g2d_frame *f)
+{
+	u32 n;
+
+	w(f->stride & 0xFFFF, DST_STRIDE_REG);
+
+	n = f->o_height & 0xFFF;
+	n <<= 16;
+	n |= f->o_width & 0xFFF;
+	w(n, DST_LEFT_TOP_REG);
+
+	n = f->bottom & 0xFFF;
+	n <<= 16;
+	n |= f->right & 0xFFF;
+	w(n, DST_RIGHT_BOTTOM_REG);
+
+	w(f->fmt->hw, DST_COLOR_MODE_REG);
+}
+
+void g2d_set_dst_addr(struct g2d_dev *d, dma_addr_t a)
+{
+	w(a, DST_BASE_ADDR_REG);
+}
+
+void g2d_set_rop4(struct g2d_dev *d, u32 r)
+{
+	w(r, ROP4_REG);
+}
+
+void g2d_set_flip(struct g2d_dev *d, u32 r)
+{
+	w(r, SRC_MSK_DIRECT_REG);
+}
+
+u32 g2d_cmd_stretch(u32 e)
+{
+	e &= 1;
+	return e << 4;
+}
+
+void g2d_set_cmd(struct g2d_dev *d, u32 c)
+{
+	w(c, BITBLT_COMMAND_REG);
+}
+
+void g2d_start(struct g2d_dev *d)
+{
+	/* Clear cache */
+	w(0x7, CACHECTL_REG);
+	/* Enable interrupt */
+	w(1, INTEN_REG);
+	/* Start G2D engine */
+	w(1, BITBLT_START_REG);
+}
+
+void g2d_clear_int(struct g2d_dev *d)
+{
+	w(1, INTC_PEND_REG);
+}
diff --git a/drivers/media/platform/s5p-g2d/g2d-regs.h b/drivers/media/platform/s5p-g2d/g2d-regs.h
new file mode 100644
index 0000000..02e1cf5
--- /dev/null
+++ b/drivers/media/platform/s5p-g2d/g2d-regs.h
@@ -0,0 +1,115 @@
+/*
+ * Samsung S5P G2D - 2D Graphics Accelerator Driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version
+ */
+
+/* General Registers */
+#define SOFT_RESET_REG		0x0000	/* Software reset reg */
+#define INTEN_REG		0x0004	/* Interrupt Enable reg */
+#define INTC_PEND_REG		0x000C	/* Interrupt Control Pending reg */
+#define FIFO_STAT_REG		0x0010	/* Command FIFO Status reg */
+#define AXI_ID_MODE_REG		0x0014	/* AXI Read ID Mode reg */
+#define CACHECTL_REG		0x0018	/* Cache & Buffer clear reg */
+#define AXI_MODE_REG		0x001C	/* AXI Mode reg */
+
+/* Command Registers */
+#define BITBLT_START_REG	0x0100	/* BitBLT Start reg */
+#define BITBLT_COMMAND_REG	0x0104	/* Command reg for BitBLT */
+
+/* Parameter Setting Registers (Rotate & Direction) */
+#define ROTATE_REG		0x0200	/* Rotation reg */
+#define SRC_MSK_DIRECT_REG	0x0204	/* Src and Mask Direction reg */
+#define DST_PAT_DIRECT_REG	0x0208	/* Dest and Pattern Direction reg */
+
+/* Parameter Setting Registers (Src) */
+#define SRC_SELECT_REG		0x0300	/* Src Image Selection reg */
+#define SRC_BASE_ADDR_REG	0x0304	/* Src Image Base Address reg */
+#define SRC_STRIDE_REG		0x0308	/* Src Stride reg */
+#define SRC_COLOR_MODE_REG	0x030C	/* Src Image Color Mode reg */
+#define SRC_LEFT_TOP_REG	0x0310	/* Src Left Top Coordinate reg */
+#define SRC_RIGHT_BOTTOM_REG	0x0314	/* Src Right Bottom Coordinate reg */
+
+/* Parameter Setting Registers (Dest) */
+#define DST_SELECT_REG		0x0400	/* Dest Image Selection reg */
+#define DST_BASE_ADDR_REG	0x0404	/* Dest Image Base Address reg */
+#define DST_STRIDE_REG		0x0408	/* Dest Stride reg */
+#define DST_COLOR_MODE_REG	0x040C	/* Dest Image Color Mode reg */
+#define DST_LEFT_TOP_REG	0x0410	/* Dest Left Top Coordinate reg */
+#define DST_RIGHT_BOTTOM_REG	0x0414	/* Dest Right Bottom Coordinate reg */
+
+/* Parameter Setting Registers (Pattern) */
+#define PAT_BASE_ADDR_REG	0x0500	/* Pattern Image Base Address reg */
+#define PAT_SIZE_REG		0x0504	/* Pattern Image Size reg */
+#define PAT_COLOR_MODE_REG	0x0508	/* Pattern Image Color Mode reg */
+#define PAT_OFFSET_REG		0x050C	/* Pattern Left Top Coordinate reg */
+#define PAT_STRIDE_REG		0x0510	/* Pattern Stride reg */
+
+/* Parameter Setting Registers (Mask) */
+#define MASK_BASE_ADDR_REG	0x0520	/* Mask Base Address reg */
+#define MASK_STRIDE_REG		0x0524	/* Mask Stride reg */
+
+/* Parameter Setting Registers (Clipping Window) */
+#define CW_LT_REG		0x0600	/* LeftTop coordinates of Clip Window */
+#define CW_RB_REG		0x0604	/* RightBottom coordinates of Clip
+								Window */
+
+/* Parameter Setting Registers (ROP & Alpha Setting) */
+#define THIRD_OPERAND_REG	0x0610	/* Third Operand Selection reg */
+#define ROP4_REG		0x0614	/* Raster Operation reg */
+#define ALPHA_REG		0x0618	/* Alpha value, Fading offset value */
+
+/* Parameter Setting Registers (Color) */
+#define FG_COLOR_REG		0x0700	/* Foreground Color reg */
+#define BG_COLOR_REG		0x0704	/* Background Color reg */
+#define BS_COLOR_REG		0x0708	/* Blue Screen Color reg */
+
+/* Parameter Setting Registers (Color Key) */
+#define SRC_COLORKEY_CTRL_REG	0x0710	/* Src Colorkey control reg */
+#define SRC_COLORKEY_DR_MIN_REG	0x0714	/* Src Colorkey Decision Reference
+								Min reg */
+#define SRC_COLORKEY_DR_MAX_REG	0x0718	/* Src Colorkey Decision Reference
+								Max reg */
+#define DST_COLORKEY_CTRL_REG	0x071C	/* Dest Colorkey control reg */
+#define DST_COLORKEY_DR_MIN_REG	0x0720	/* Dest Colorkey Decision Reference
+								Min reg */
+#define DST_COLORKEY_DR_MAX_REG	0x0724	/* Dest Colorkey Decision Reference
+								Max reg */
+
+/* Color mode values */
+
+#define ORDER_XRGB		0
+#define ORDER_RGBX		1
+#define ORDER_XBGR		2
+#define ORDER_BGRX		3
+
+#define MODE_XRGB_8888		0
+#define MODE_ARGB_8888		1
+#define MODE_RGB_565		2
+#define MODE_XRGB_1555		3
+#define MODE_ARGB_1555		4
+#define MODE_XRGB_4444		5
+#define MODE_ARGB_4444		6
+#define MODE_PACKED_RGB_888	7
+
+#define COLOR_MODE(o, m)	(((o) << 4) | (m))
+
+/* ROP4 operation values */
+#define ROP4_COPY		0xCCCC
+#define ROP4_INVERT		0x3333
+
+/* Hardware limits */
+#define MAX_WIDTH		8000
+#define MAX_HEIGHT		8000
+
+#define G2D_TIMEOUT		500
+
+#define DEFAULT_WIDTH		100
+#define DEFAULT_HEIGHT		100
+
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c
new file mode 100644
index 0000000..0edc2df
--- /dev/null
+++ b/drivers/media/platform/s5p-g2d/g2d.c
@@ -0,0 +1,847 @@
+/*
+ * Samsung S5P G2D - 2D Graphics Accelerator Driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/version.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+
+#include <linux/platform_device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "g2d.h"
+#include "g2d-regs.h"
+
+#define fh2ctx(__fh) container_of(__fh, struct g2d_ctx, fh)
+
+static struct g2d_fmt formats[] = {
+	{
+		.name	= "XRGB_8888",
+		.fourcc	= V4L2_PIX_FMT_RGB32,
+		.depth	= 32,
+		.hw	= COLOR_MODE(ORDER_XRGB, MODE_XRGB_8888),
+	},
+	{
+		.name	= "RGB_565",
+		.fourcc	= V4L2_PIX_FMT_RGB565X,
+		.depth	= 16,
+		.hw	= COLOR_MODE(ORDER_XRGB, MODE_RGB_565),
+	},
+	{
+		.name	= "XRGB_1555",
+		.fourcc	= V4L2_PIX_FMT_RGB555X,
+		.depth	= 16,
+		.hw	= COLOR_MODE(ORDER_XRGB, MODE_XRGB_1555),
+	},
+	{
+		.name	= "XRGB_4444",
+		.fourcc	= V4L2_PIX_FMT_RGB444,
+		.depth	= 16,
+		.hw	= COLOR_MODE(ORDER_XRGB, MODE_XRGB_4444),
+	},
+	{
+		.name	= "PACKED_RGB_888",
+		.fourcc	= V4L2_PIX_FMT_RGB24,
+		.depth	= 24,
+		.hw	= COLOR_MODE(ORDER_XRGB, MODE_PACKED_RGB_888),
+	},
+};
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+static struct g2d_frame def_frame = {
+	.width		= DEFAULT_WIDTH,
+	.height		= DEFAULT_HEIGHT,
+	.c_width	= DEFAULT_WIDTH,
+	.c_height	= DEFAULT_HEIGHT,
+	.o_width	= 0,
+	.o_height	= 0,
+	.fmt		= &formats[0],
+	.right		= DEFAULT_WIDTH,
+	.bottom		= DEFAULT_HEIGHT,
+};
+
+static struct g2d_fmt *find_fmt(struct v4l2_format *f)
+{
+	unsigned int i;
+	for (i = 0; i < NUM_FORMATS; i++) {
+		if (formats[i].fourcc == f->fmt.pix.pixelformat)
+			return &formats[i];
+	}
+	return NULL;
+}
+
+
+static struct g2d_frame *get_frame(struct g2d_ctx *ctx,
+							enum v4l2_buf_type type)
+{
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		return &ctx->in;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return &ctx->out;
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+}
+
+static int g2d_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+			   unsigned int *nbuffers, unsigned int *nplanes,
+			   unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct g2d_ctx *ctx = vb2_get_drv_priv(vq);
+	struct g2d_frame *f = get_frame(ctx, vq->type);
+
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
+	sizes[0] = f->size;
+	*nplanes = 1;
+	alloc_ctxs[0] = ctx->dev->alloc_ctx;
+
+	if (*nbuffers == 0)
+		*nbuffers = 1;
+
+	return 0;
+}
+
+static int g2d_buf_prepare(struct vb2_buffer *vb)
+{
+	struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct g2d_frame *f = get_frame(ctx, vb->vb2_queue->type);
+
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+	vb2_set_plane_payload(vb, 0, f->size);
+	return 0;
+}
+
+static void g2d_buf_queue(struct vb2_buffer *vb)
+{
+	struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+
+static struct vb2_ops g2d_qops = {
+	.queue_setup	= g2d_queue_setup,
+	.buf_prepare	= g2d_buf_prepare,
+	.buf_queue	= g2d_buf_queue,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+						struct vb2_queue *dst_vq)
+{
+	struct g2d_ctx *ctx = priv;
+	int ret;
+
+	memset(src_vq, 0, sizeof(*src_vq));
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+	src_vq->drv_priv = ctx;
+	src_vq->ops = &g2d_qops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	memset(dst_vq, 0, sizeof(*dst_vq));
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+	dst_vq->drv_priv = ctx;
+	dst_vq->ops = &g2d_qops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+	return vb2_queue_init(dst_vq);
+}
+
+static int g2d_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct g2d_ctx *ctx = container_of(ctrl->handler, struct g2d_ctx,
+								ctrl_handler);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctx->dev->ctrl_lock, flags);
+	switch (ctrl->id) {
+	case V4L2_CID_COLORFX:
+		if (ctrl->val == V4L2_COLORFX_NEGATIVE)
+			ctx->rop = ROP4_INVERT;
+		else
+			ctx->rop = ROP4_COPY;
+		break;
+
+	case V4L2_CID_HFLIP:
+		ctx->flip = ctx->ctrl_hflip->val | (ctx->ctrl_vflip->val << 1);
+		break;
+
+	}
+	spin_unlock_irqrestore(&ctx->dev->ctrl_lock, flags);
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops g2d_ctrl_ops = {
+	.s_ctrl		= g2d_s_ctrl,
+};
+
+static int g2d_setup_ctrls(struct g2d_ctx *ctx)
+{
+	struct g2d_dev *dev = ctx->dev;
+
+	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
+
+	ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops,
+						V4L2_CID_HFLIP, 0, 1, 1, 0);
+
+	ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops,
+						V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+	v4l2_ctrl_new_std_menu(
+		&ctx->ctrl_handler,
+		&g2d_ctrl_ops,
+		V4L2_CID_COLORFX,
+		V4L2_COLORFX_NEGATIVE,
+		~((1 << V4L2_COLORFX_NONE) | (1 << V4L2_COLORFX_NEGATIVE)),
+		V4L2_COLORFX_NONE);
+
+	if (ctx->ctrl_handler.error) {
+		int err = ctx->ctrl_handler.error;
+		v4l2_err(&dev->v4l2_dev, "g2d_setup_ctrls failed\n");
+		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+		return err;
+	}
+
+	v4l2_ctrl_cluster(2, &ctx->ctrl_hflip);
+
+	return 0;
+}
+
+static int g2d_open(struct file *file)
+{
+	struct g2d_dev *dev = video_drvdata(file);
+	struct g2d_ctx *ctx = NULL;
+	int ret = 0;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+	ctx->dev = dev;
+	/* Set default formats */
+	ctx->in		= def_frame;
+	ctx->out	= def_frame;
+
+	if (mutex_lock_interruptible(&dev->mutex)) {
+		kfree(ctx);
+		return -ERESTARTSYS;
+	}
+	ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
+	if (IS_ERR(ctx->m2m_ctx)) {
+		ret = PTR_ERR(ctx->m2m_ctx);
+		mutex_unlock(&dev->mutex);
+		kfree(ctx);
+		return ret;
+	}
+	v4l2_fh_init(&ctx->fh, video_devdata(file));
+	file->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh);
+
+	g2d_setup_ctrls(ctx);
+
+	/* Write the default values to the ctx struct */
+	v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+
+	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+	mutex_unlock(&dev->mutex);
+
+	v4l2_info(&dev->v4l2_dev, "instance opened\n");
+	return 0;
+}
+
+static int g2d_release(struct file *file)
+{
+	struct g2d_dev *dev = video_drvdata(file);
+	struct g2d_ctx *ctx = fh2ctx(file->private_data);
+
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+	v4l2_info(&dev->v4l2_dev, "instance closed\n");
+	return 0;
+}
+
+
+static int vidioc_querycap(struct file *file, void *priv,
+				struct v4l2_capability *cap)
+{
+	strncpy(cap->driver, G2D_NAME, sizeof(cap->driver) - 1);
+	strncpy(cap->card, G2D_NAME, sizeof(cap->card) - 1);
+	cap->bus_info[0] = 0;
+	cap->version = KERNEL_VERSION(1, 0, 0);
+	/*
+	 * This is only a mem-to-mem video device. The capture and output
+	 * device capability flags are left only for backward compatibility
+	 * and are scheduled for removal.
+	 */
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
+			    V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+	return 0;
+}
+
+static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f)
+{
+	struct g2d_fmt *fmt;
+	if (f->index >= NUM_FORMATS)
+		return -EINVAL;
+	fmt = &formats[f->index];
+	f->pixelformat = fmt->fourcc;
+	strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+	return 0;
+}
+
+static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+	struct g2d_ctx *ctx = prv;
+	struct vb2_queue *vq;
+	struct g2d_frame *frm;
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+	frm = get_frame(ctx, f->type);
+	if (IS_ERR(frm))
+		return PTR_ERR(frm);
+
+	f->fmt.pix.width		= frm->width;
+	f->fmt.pix.height		= frm->height;
+	f->fmt.pix.field		= V4L2_FIELD_NONE;
+	f->fmt.pix.pixelformat		= frm->fmt->fourcc;
+	f->fmt.pix.bytesperline		= (frm->width * frm->fmt->depth) >> 3;
+	f->fmt.pix.sizeimage		= frm->size;
+	return 0;
+}
+
+static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+	struct g2d_fmt *fmt;
+	enum v4l2_field *field;
+
+	fmt = find_fmt(f);
+	if (!fmt)
+		return -EINVAL;
+
+	field = &f->fmt.pix.field;
+	if (*field == V4L2_FIELD_ANY)
+		*field = V4L2_FIELD_NONE;
+	else if (*field != V4L2_FIELD_NONE)
+		return -EINVAL;
+
+	if (f->fmt.pix.width > MAX_WIDTH)
+		f->fmt.pix.width = MAX_WIDTH;
+	if (f->fmt.pix.height > MAX_HEIGHT)
+		f->fmt.pix.height = MAX_HEIGHT;
+
+	if (f->fmt.pix.width < 1)
+		f->fmt.pix.width = 1;
+	if (f->fmt.pix.height < 1)
+		f->fmt.pix.height = 1;
+
+	f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
+	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+	return 0;
+}
+
+static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+	struct g2d_ctx *ctx = prv;
+	struct g2d_dev *dev = ctx->dev;
+	struct vb2_queue *vq;
+	struct g2d_frame *frm;
+	struct g2d_fmt *fmt;
+	int ret = 0;
+
+	/* Adjust all values accordingly to the hardware capabilities
+	 * and chosen format. */
+	ret = vidioc_try_fmt(file, prv, f);
+	if (ret)
+		return ret;
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+	if (vb2_is_busy(vq)) {
+		v4l2_err(&dev->v4l2_dev, "queue (%d) bust\n", f->type);
+		return -EBUSY;
+	}
+	frm = get_frame(ctx, f->type);
+	if (IS_ERR(frm))
+		return PTR_ERR(frm);
+	fmt = find_fmt(f);
+	if (!fmt)
+		return -EINVAL;
+	frm->width	= f->fmt.pix.width;
+	frm->height	= f->fmt.pix.height;
+	frm->size	= f->fmt.pix.sizeimage;
+	/* Reset crop settings */
+	frm->o_width	= 0;
+	frm->o_height	= 0;
+	frm->c_width	= frm->width;
+	frm->c_height	= frm->height;
+	frm->right	= frm->width;
+	frm->bottom	= frm->height;
+	frm->fmt	= fmt;
+	frm->stride	= f->fmt.pix.bytesperline;
+	return 0;
+}
+
+static unsigned int g2d_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct g2d_ctx *ctx = fh2ctx(file->private_data);
+	struct g2d_dev *dev = ctx->dev;
+	unsigned int res;
+
+	mutex_lock(&dev->mutex);
+	res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+	mutex_unlock(&dev->mutex);
+	return res;
+}
+
+static int g2d_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct g2d_ctx *ctx = fh2ctx(file->private_data);
+	struct g2d_dev *dev = ctx->dev;
+	int ret;
+
+	if (mutex_lock_interruptible(&dev->mutex))
+		return -ERESTARTSYS;
+	ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+	mutex_unlock(&dev->mutex);
+	return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			struct v4l2_requestbuffers *reqbufs)
+{
+	struct g2d_ctx *ctx = priv;
+	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+			struct v4l2_buffer *buf)
+{
+	struct g2d_ctx *ctx = priv;
+	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct g2d_ctx *ctx = priv;
+	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct g2d_ctx *ctx = priv;
+	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+
+static int vidioc_streamon(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct g2d_ctx *ctx = priv;
+	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct g2d_ctx *ctx = priv;
+	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_cropcap(struct file *file, void *priv,
+					struct v4l2_cropcap *cr)
+{
+	struct g2d_ctx *ctx = priv;
+	struct g2d_frame *f;
+
+	f = get_frame(ctx, cr->type);
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
+	cr->bounds.left		= 0;
+	cr->bounds.top		= 0;
+	cr->bounds.width	= f->width;
+	cr->bounds.height	= f->height;
+	cr->defrect		= cr->bounds;
+	return 0;
+}
+
+static int vidioc_g_crop(struct file *file, void *prv, struct v4l2_crop *cr)
+{
+	struct g2d_ctx *ctx = prv;
+	struct g2d_frame *f;
+
+	f = get_frame(ctx, cr->type);
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
+	cr->c.left	= f->o_height;
+	cr->c.top	= f->o_width;
+	cr->c.width	= f->c_width;
+	cr->c.height	= f->c_height;
+	return 0;
+}
+
+static int vidioc_try_crop(struct file *file, void *prv, struct v4l2_crop *cr)
+{
+	struct g2d_ctx *ctx = prv;
+	struct g2d_dev *dev = ctx->dev;
+	struct g2d_frame *f;
+
+	f = get_frame(ctx, cr->type);
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
+	if (cr->c.top < 0 || cr->c.left < 0) {
+		v4l2_err(&dev->v4l2_dev,
+			"doesn't support negative values for top & left\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vidioc_s_crop(struct file *file, void *prv, struct v4l2_crop *cr)
+{
+	struct g2d_ctx *ctx = prv;
+	struct g2d_frame *f;
+	int ret;
+
+	ret = vidioc_try_crop(file, prv, cr);
+	if (ret)
+		return ret;
+	f = get_frame(ctx, cr->type);
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
+	f->c_width	= cr->c.width;
+	f->c_height	= cr->c.height;
+	f->o_width	= cr->c.left;
+	f->o_height	= cr->c.top;
+	f->bottom	= f->o_height + f->c_height;
+	f->right	= f->o_width + f->c_width;
+	return 0;
+}
+
+static void g2d_lock(void *prv)
+{
+	struct g2d_ctx *ctx = prv;
+	struct g2d_dev *dev = ctx->dev;
+	mutex_lock(&dev->mutex);
+}
+
+static void g2d_unlock(void *prv)
+{
+	struct g2d_ctx *ctx = prv;
+	struct g2d_dev *dev = ctx->dev;
+	mutex_unlock(&dev->mutex);
+}
+
+static void job_abort(void *prv)
+{
+	struct g2d_ctx *ctx = prv;
+	struct g2d_dev *dev = ctx->dev;
+	int ret;
+
+	if (dev->curr == NULL) /* No job currently running */
+		return;
+
+	ret = wait_event_timeout(dev->irq_queue,
+		dev->curr == NULL,
+		msecs_to_jiffies(G2D_TIMEOUT));
+}
+
+static void device_run(void *prv)
+{
+	struct g2d_ctx *ctx = prv;
+	struct g2d_dev *dev = ctx->dev;
+	struct vb2_buffer *src, *dst;
+	unsigned long flags;
+	u32 cmd = 0;
+
+	dev->curr = ctx;
+
+	src = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+
+	clk_enable(dev->gate);
+	g2d_reset(dev);
+
+	spin_lock_irqsave(&dev->ctrl_lock, flags);
+
+	g2d_set_src_size(dev, &ctx->in);
+	g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(src, 0));
+
+	g2d_set_dst_size(dev, &ctx->out);
+	g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(dst, 0));
+
+	g2d_set_rop4(dev, ctx->rop);
+	g2d_set_flip(dev, ctx->flip);
+
+	if (ctx->in.c_width != ctx->out.c_width ||
+		ctx->in.c_height != ctx->out.c_height)
+		cmd |= g2d_cmd_stretch(1);
+	g2d_set_cmd(dev, cmd);
+	g2d_start(dev);
+
+	spin_unlock_irqrestore(&dev->ctrl_lock, flags);
+}
+
+static irqreturn_t g2d_isr(int irq, void *prv)
+{
+	struct g2d_dev *dev = prv;
+	struct g2d_ctx *ctx = dev->curr;
+	struct vb2_buffer *src, *dst;
+
+	g2d_clear_int(dev);
+	clk_disable(dev->gate);
+
+	BUG_ON(ctx == NULL);
+
+	src = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+	dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+
+	BUG_ON(src == NULL);
+	BUG_ON(dst == NULL);
+
+	v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
+	v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
+	v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx);
+
+	dev->curr = NULL;
+	wake_up(&dev->irq_queue);
+	return IRQ_HANDLED;
+}
+
+static const struct v4l2_file_operations g2d_fops = {
+	.owner		= THIS_MODULE,
+	.open		= g2d_open,
+	.release	= g2d_release,
+	.poll		= g2d_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= g2d_mmap,
+};
+
+static const struct v4l2_ioctl_ops g2d_ioctl_ops = {
+	.vidioc_querycap	= vidioc_querycap,
+
+	.vidioc_enum_fmt_vid_cap	= vidioc_enum_fmt,
+	.vidioc_g_fmt_vid_cap		= vidioc_g_fmt,
+	.vidioc_try_fmt_vid_cap		= vidioc_try_fmt,
+	.vidioc_s_fmt_vid_cap		= vidioc_s_fmt,
+
+	.vidioc_enum_fmt_vid_out	= vidioc_enum_fmt,
+	.vidioc_g_fmt_vid_out		= vidioc_g_fmt,
+	.vidioc_try_fmt_vid_out		= vidioc_try_fmt,
+	.vidioc_s_fmt_vid_out		= vidioc_s_fmt,
+
+	.vidioc_reqbufs			= vidioc_reqbufs,
+	.vidioc_querybuf		= vidioc_querybuf,
+
+	.vidioc_qbuf			= vidioc_qbuf,
+	.vidioc_dqbuf			= vidioc_dqbuf,
+
+	.vidioc_streamon		= vidioc_streamon,
+	.vidioc_streamoff		= vidioc_streamoff,
+
+	.vidioc_g_crop			= vidioc_g_crop,
+	.vidioc_s_crop			= vidioc_s_crop,
+	.vidioc_cropcap			= vidioc_cropcap,
+};
+
+static struct video_device g2d_videodev = {
+	.name		= G2D_NAME,
+	.fops		= &g2d_fops,
+	.ioctl_ops	= &g2d_ioctl_ops,
+	.minor		= -1,
+	.release	= video_device_release,
+};
+
+static struct v4l2_m2m_ops g2d_m2m_ops = {
+	.device_run	= device_run,
+	.job_abort	= job_abort,
+	.lock		= g2d_lock,
+	.unlock		= g2d_unlock,
+};
+
+static int g2d_probe(struct platform_device *pdev)
+{
+	struct g2d_dev *dev;
+	struct video_device *vfd;
+	struct resource *res;
+	int ret = 0;
+
+	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	spin_lock_init(&dev->ctrl_lock);
+	mutex_init(&dev->mutex);
+	atomic_set(&dev->num_inst, 0);
+	init_waitqueue_head(&dev->irq_queue);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	dev->regs = devm_request_and_ioremap(&pdev->dev, res);
+	if (dev->regs == NULL) {
+			dev_err(&pdev->dev, "Failed to obtain io memory\n");
+			return -ENOENT;
+	}
+
+	dev->clk = clk_get(&pdev->dev, "sclk_fimg2d");
+	if (IS_ERR_OR_NULL(dev->clk)) {
+		dev_err(&pdev->dev, "failed to get g2d clock\n");
+		return -ENXIO;
+	}
+
+	ret = clk_prepare(dev->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to prepare g2d clock\n");
+		goto put_clk;
+	}
+
+	dev->gate = clk_get(&pdev->dev, "fimg2d");
+	if (IS_ERR_OR_NULL(dev->gate)) {
+		dev_err(&pdev->dev, "failed to get g2d clock gate\n");
+		ret = -ENXIO;
+		goto unprep_clk;
+	}
+
+	ret = clk_prepare(dev->gate);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to prepare g2d clock gate\n");
+		goto put_clk_gate;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to find IRQ\n");
+		ret = -ENXIO;
+		goto unprep_clk_gate;
+	}
+
+	dev->irq = res->start;
+
+	ret = devm_request_irq(&pdev->dev, dev->irq, g2d_isr,
+						0, pdev->name, dev);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to install IRQ\n");
+		goto put_clk_gate;
+	}
+
+	dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+	if (IS_ERR(dev->alloc_ctx)) {
+		ret = PTR_ERR(dev->alloc_ctx);
+		goto unprep_clk_gate;
+	}
+
+	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+	if (ret)
+		goto alloc_ctx_cleanup;
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+		ret = -ENOMEM;
+		goto unreg_v4l2_dev;
+	}
+	*vfd = g2d_videodev;
+	vfd->lock = &dev->mutex;
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+		goto rel_vdev;
+	}
+	video_set_drvdata(vfd, dev);
+	snprintf(vfd->name, sizeof(vfd->name), "%s", g2d_videodev.name);
+	dev->vfd = vfd;
+	v4l2_info(&dev->v4l2_dev, "device registered as /dev/video%d\n",
+								vfd->num);
+	platform_set_drvdata(pdev, dev);
+	dev->m2m_dev = v4l2_m2m_init(&g2d_m2m_ops);
+	if (IS_ERR(dev->m2m_dev)) {
+		v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
+		ret = PTR_ERR(dev->m2m_dev);
+		goto unreg_video_dev;
+	}
+
+	def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
+
+	return 0;
+
+unreg_video_dev:
+	video_unregister_device(dev->vfd);
+rel_vdev:
+	video_device_release(vfd);
+unreg_v4l2_dev:
+	v4l2_device_unregister(&dev->v4l2_dev);
+alloc_ctx_cleanup:
+	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+unprep_clk_gate:
+	clk_unprepare(dev->gate);
+put_clk_gate:
+	clk_put(dev->gate);
+unprep_clk:
+	clk_unprepare(dev->clk);
+put_clk:
+	clk_put(dev->clk);
+
+	return ret;
+}
+
+static int g2d_remove(struct platform_device *pdev)
+{
+	struct g2d_dev *dev = (struct g2d_dev *)platform_get_drvdata(pdev);
+
+	v4l2_info(&dev->v4l2_dev, "Removing " G2D_NAME);
+	v4l2_m2m_release(dev->m2m_dev);
+	video_unregister_device(dev->vfd);
+	v4l2_device_unregister(&dev->v4l2_dev);
+	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+	clk_unprepare(dev->gate);
+	clk_put(dev->gate);
+	clk_unprepare(dev->clk);
+	clk_put(dev->clk);
+	return 0;
+}
+
+static struct platform_driver g2d_pdrv = {
+	.probe		= g2d_probe,
+	.remove		= g2d_remove,
+	.driver		= {
+		.name = G2D_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+module_platform_driver(g2d_pdrv);
+
+MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
+MODULE_DESCRIPTION("S5P G2D 2d graphics accelerator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/s5p-g2d/g2d.h b/drivers/media/platform/s5p-g2d/g2d.h
new file mode 100644
index 0000000..6b765b0
--- /dev/null
+++ b/drivers/media/platform/s5p-g2d/g2d.h
@@ -0,0 +1,86 @@
+/*
+ * Samsung S5P G2D - 2D Graphics Accelerator Driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version
+ */
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#define G2D_NAME "s5p-g2d"
+
+struct g2d_dev {
+	struct v4l2_device	v4l2_dev;
+	struct v4l2_m2m_dev	*m2m_dev;
+	struct video_device	*vfd;
+	struct mutex		mutex;
+	spinlock_t		ctrl_lock;
+	atomic_t		num_inst;
+	struct vb2_alloc_ctx	*alloc_ctx;
+	void __iomem		*regs;
+	struct clk		*clk;
+	struct clk		*gate;
+	struct g2d_ctx		*curr;
+	int irq;
+	wait_queue_head_t	irq_queue;
+};
+
+struct g2d_frame {
+	/* Original dimensions */
+	u32	width;
+	u32	height;
+	/* Crop size */
+	u32	c_width;
+	u32	c_height;
+	/* Offset */
+	u32	o_width;
+	u32	o_height;
+	/* Image format */
+	struct g2d_fmt *fmt;
+	/* Variables that can calculated once and reused */
+	u32	stride;
+	u32	bottom;
+	u32	right;
+	u32	size;
+};
+
+struct g2d_ctx {
+	struct v4l2_fh fh;
+	struct g2d_dev		*dev;
+	struct v4l2_m2m_ctx     *m2m_ctx;
+	struct g2d_frame	in;
+	struct g2d_frame	out;
+	struct v4l2_ctrl	*ctrl_hflip;
+	struct v4l2_ctrl	*ctrl_vflip;
+	struct v4l2_ctrl_handler ctrl_handler;
+	u32 rop;
+	u32 flip;
+};
+
+struct g2d_fmt {
+	char	*name;
+	u32	fourcc;
+	int	depth;
+	u32	hw;
+};
+
+
+void g2d_reset(struct g2d_dev *d);
+void g2d_set_src_size(struct g2d_dev *d, struct g2d_frame *f);
+void g2d_set_src_addr(struct g2d_dev *d, dma_addr_t a);
+void g2d_set_dst_size(struct g2d_dev *d, struct g2d_frame *f);
+void g2d_set_dst_addr(struct g2d_dev *d, dma_addr_t a);
+void g2d_start(struct g2d_dev *d);
+void g2d_clear_int(struct g2d_dev *d);
+void g2d_set_rop4(struct g2d_dev *d, u32 r);
+void g2d_set_flip(struct g2d_dev *d, u32 r);
+u32 g2d_cmd_stretch(u32 e);
+void g2d_set_cmd(struct g2d_dev *d, u32 c);
+
+
diff --git a/drivers/media/platform/s5p-jpeg/Makefile b/drivers/media/platform/s5p-jpeg/Makefile
new file mode 100644
index 0000000..ddc2900
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/Makefile
@@ -0,0 +1,2 @@
+s5p-jpeg-objs := jpeg-core.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) := s5p-jpeg.o
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
new file mode 100644
index 0000000..72c3e52
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -0,0 +1,1529 @@
+/* linux/drivers/media/platform/s5p-jpeg/jpeg-core.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/gfp.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "jpeg-core.h"
+#include "jpeg-hw.h"
+
+static struct s5p_jpeg_fmt formats_enc[] = {
+	{
+		.name		= "JPEG JFIF",
+		.fourcc		= V4L2_PIX_FMT_JPEG,
+		.colplanes	= 1,
+		.types		= MEM2MEM_CAPTURE,
+	},
+	{
+		.name		= "YUV 4:2:2 packed, YCbYCr",
+		.fourcc		= V4L2_PIX_FMT_YUYV,
+		.depth		= 16,
+		.colplanes	= 1,
+		.types		= MEM2MEM_OUTPUT,
+	},
+	{
+		.name		= "RGB565",
+		.fourcc		= V4L2_PIX_FMT_RGB565,
+		.depth		= 16,
+		.colplanes	= 1,
+		.types		= MEM2MEM_OUTPUT,
+	},
+};
+#define NUM_FORMATS_ENC ARRAY_SIZE(formats_enc)
+
+static struct s5p_jpeg_fmt formats_dec[] = {
+	{
+		.name		= "YUV 4:2:0 planar, YCbCr",
+		.fourcc		= V4L2_PIX_FMT_YUV420,
+		.depth		= 12,
+		.colplanes	= 3,
+		.h_align	= 4,
+		.v_align	= 4,
+		.types		= MEM2MEM_CAPTURE,
+	},
+	{
+		.name		= "YUV 4:2:2 packed, YCbYCr",
+		.fourcc		= V4L2_PIX_FMT_YUYV,
+		.depth		= 16,
+		.colplanes	= 1,
+		.h_align	= 4,
+		.v_align	= 3,
+		.types		= MEM2MEM_CAPTURE,
+	},
+	{
+		.name		= "JPEG JFIF",
+		.fourcc		= V4L2_PIX_FMT_JPEG,
+		.colplanes	= 1,
+		.types		= MEM2MEM_OUTPUT,
+	},
+};
+#define NUM_FORMATS_DEC ARRAY_SIZE(formats_dec)
+
+static const unsigned char qtbl_luminance[4][64] = {
+	{/* level 1 - high quality */
+		 8,  6,  6,  8, 12, 14, 16, 17,
+		 6,  6,  6,  8, 10, 13, 12, 15,
+		 6,  6,  7,  8, 13, 14, 18, 24,
+		 8,  8,  8, 14, 13, 19, 24, 35,
+		12, 10, 13, 13, 20, 26, 34, 39,
+		14, 13, 14, 19, 26, 34, 39, 39,
+		16, 12, 18, 24, 34, 39, 39, 39,
+		17, 15, 24, 35, 39, 39, 39, 39
+	},
+	{/* level 2 */
+		12,  8,  8, 12, 17, 21, 24, 23,
+		 8,  9,  9, 11, 15, 19, 18, 23,
+		 8,  9, 10, 12, 19, 20, 27, 36,
+		12, 11, 12, 21, 20, 28, 36, 53,
+		17, 15, 19, 20, 30, 39, 51, 59,
+		21, 19, 20, 28, 39, 51, 59, 59,
+		24, 18, 27, 36, 51, 59, 59, 59,
+		23, 23, 36, 53, 59, 59, 59, 59
+	},
+	{/* level 3 */
+		16, 11, 11, 16, 23, 27, 31, 30,
+		11, 12, 12, 15, 20, 23, 23, 30,
+		11, 12, 13, 16, 23, 26, 35, 47,
+		16, 15, 16, 23, 26, 37, 47, 64,
+		23, 20, 23, 26, 39, 51, 64, 64,
+		27, 23, 26, 37, 51, 64, 64, 64,
+		31, 23, 35, 47, 64, 64, 64, 64,
+		30, 30, 47, 64, 64, 64, 64, 64
+	},
+	{/*level 4 - low quality */
+		20, 16, 25, 39, 50, 46, 62, 68,
+		16, 18, 23, 38, 38, 53, 65, 68,
+		25, 23, 31, 38, 53, 65, 68, 68,
+		39, 38, 38, 53, 65, 68, 68, 68,
+		50, 38, 53, 65, 68, 68, 68, 68,
+		46, 53, 65, 68, 68, 68, 68, 68,
+		62, 65, 68, 68, 68, 68, 68, 68,
+		68, 68, 68, 68, 68, 68, 68, 68
+	}
+};
+
+static const unsigned char qtbl_chrominance[4][64] = {
+	{/* level 1 - high quality */
+		 9,  8,  9, 11, 14, 17, 19, 24,
+		 8, 10,  9, 11, 14, 13, 17, 22,
+		 9,  9, 13, 14, 13, 15, 23, 26,
+		11, 11, 14, 14, 15, 20, 26, 33,
+		14, 14, 13, 15, 20, 24, 33, 39,
+		17, 13, 15, 20, 24, 32, 39, 39,
+		19, 17, 23, 26, 33, 39, 39, 39,
+		24, 22, 26, 33, 39, 39, 39, 39
+	},
+	{/* level 2 */
+		13, 11, 13, 16, 20, 20, 29, 37,
+		11, 14, 14, 14, 16, 20, 26, 32,
+		13, 14, 15, 17, 20, 23, 35, 40,
+		16, 14, 17, 21, 23, 30, 40, 50,
+		20, 16, 20, 23, 30, 37, 50, 59,
+		20, 20, 23, 30, 37, 48, 59, 59,
+		29, 26, 35, 40, 50, 59, 59, 59,
+		37, 32, 40, 50, 59, 59, 59, 59
+	},
+	{/* level 3 */
+		17, 15, 17, 21, 20, 26, 38, 48,
+		15, 19, 18, 17, 20, 26, 35, 43,
+		17, 18, 20, 22, 26, 30, 46, 53,
+		21, 17, 22, 28, 30, 39, 53, 64,
+		20, 20, 26, 30, 39, 48, 64, 64,
+		26, 26, 30, 39, 48, 63, 64, 64,
+		38, 35, 46, 53, 64, 64, 64, 64,
+		48, 43, 53, 64, 64, 64, 64, 64
+	},
+	{/*level 4 - low quality */
+		21, 25, 32, 38, 54, 68, 68, 68,
+		25, 28, 24, 38, 54, 68, 68, 68,
+		32, 24, 32, 43, 66, 68, 68, 68,
+		38, 38, 43, 53, 68, 68, 68, 68,
+		54, 54, 66, 68, 68, 68, 68, 68,
+		68, 68, 68, 68, 68, 68, 68, 68,
+		68, 68, 68, 68, 68, 68, 68, 68,
+		68, 68, 68, 68, 68, 68, 68, 68
+	}
+};
+
+static const unsigned char hdctbl0[16] = {
+	0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char hdctblg0[12] = {
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb
+};
+static const unsigned char hactbl0[16] = {
+	0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
+};
+static const unsigned char hactblg0[162] = {
+	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
+};
+
+static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
+{
+	return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
+}
+
+static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
+{
+	return container_of(fh, struct s5p_jpeg_ctx, fh);
+}
+
+static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl,
+		   unsigned long tab, int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
+}
+
+static inline void jpeg_set_qtbl_lum(void __iomem *regs, int quality)
+{
+	/* this driver fills quantisation table 0 with data for luma */
+	jpeg_set_qtbl(regs, qtbl_luminance[quality], S5P_JPG_QTBL_CONTENT(0),
+		      ARRAY_SIZE(qtbl_luminance[quality]));
+}
+
+static inline void jpeg_set_qtbl_chr(void __iomem *regs, int quality)
+{
+	/* this driver fills quantisation table 1 with data for chroma */
+	jpeg_set_qtbl(regs, qtbl_chrominance[quality], S5P_JPG_QTBL_CONTENT(1),
+		      ARRAY_SIZE(qtbl_chrominance[quality]));
+}
+
+static inline void jpeg_set_htbl(void __iomem *regs, const unsigned char *htbl,
+		   unsigned long tab, int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
+}
+
+static inline void jpeg_set_hdctbl(void __iomem *regs)
+{
+	/* this driver fills table 0 for this component */
+	jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0), ARRAY_SIZE(hdctbl0));
+}
+
+static inline void jpeg_set_hdctblg(void __iomem *regs)
+{
+	/* this driver fills table 0 for this component */
+	jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0), ARRAY_SIZE(hdctblg0));
+}
+
+static inline void jpeg_set_hactbl(void __iomem *regs)
+{
+	/* this driver fills table 0 for this component */
+	jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0), ARRAY_SIZE(hactbl0));
+}
+
+static inline void jpeg_set_hactblg(void __iomem *regs)
+{
+	/* this driver fills table 0 for this component */
+	jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0), ARRAY_SIZE(hactblg0));
+}
+
+/*
+ * ============================================================================
+ * Device file operations
+ * ============================================================================
+ */
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+		      struct vb2_queue *dst_vq);
+static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
+						 __u32 pixelformat);
+static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
+
+static int s5p_jpeg_open(struct file *file)
+{
+	struct s5p_jpeg *jpeg = video_drvdata(file);
+	struct video_device *vfd = video_devdata(file);
+	struct s5p_jpeg_ctx *ctx;
+	struct s5p_jpeg_fmt *out_fmt;
+	int ret = 0;
+
+	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	if (mutex_lock_interruptible(&jpeg->lock)) {
+		ret = -ERESTARTSYS;
+		goto free;
+	}
+
+	v4l2_fh_init(&ctx->fh, vfd);
+	/* Use separate control handler per file handle */
+	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+	file->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh);
+
+	ctx->jpeg = jpeg;
+	if (vfd == jpeg->vfd_encoder) {
+		ctx->mode = S5P_JPEG_ENCODE;
+		out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_RGB565);
+	} else {
+		ctx->mode = S5P_JPEG_DECODE;
+		out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG);
+	}
+
+	ret = s5p_jpeg_controls_create(ctx);
+	if (ret < 0)
+		goto error;
+
+	ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
+	if (IS_ERR(ctx->m2m_ctx)) {
+		ret = PTR_ERR(ctx->m2m_ctx);
+		goto error;
+	}
+
+	ctx->out_q.fmt = out_fmt;
+	ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV);
+	mutex_unlock(&jpeg->lock);
+	return 0;
+
+error:
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	mutex_unlock(&jpeg->lock);
+free:
+	kfree(ctx);
+	return ret;
+}
+
+static int s5p_jpeg_release(struct file *file)
+{
+	struct s5p_jpeg *jpeg = video_drvdata(file);
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
+
+	mutex_lock(&jpeg->lock);
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+	mutex_unlock(&jpeg->lock);
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+
+	return 0;
+}
+
+static unsigned int s5p_jpeg_poll(struct file *file,
+				 struct poll_table_struct *wait)
+{
+	struct s5p_jpeg *jpeg = video_drvdata(file);
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
+	unsigned int res;
+
+	mutex_lock(&jpeg->lock);
+	res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+	mutex_unlock(&jpeg->lock);
+	return res;
+}
+
+static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct s5p_jpeg *jpeg = video_drvdata(file);
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
+	int ret;
+
+	if (mutex_lock_interruptible(&jpeg->lock))
+		return -ERESTARTSYS;
+	ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+	mutex_unlock(&jpeg->lock);
+	return ret;
+}
+
+static const struct v4l2_file_operations s5p_jpeg_fops = {
+	.owner		= THIS_MODULE,
+	.open		= s5p_jpeg_open,
+	.release	= s5p_jpeg_release,
+	.poll		= s5p_jpeg_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= s5p_jpeg_mmap,
+};
+
+/*
+ * ============================================================================
+ * video ioctl operations
+ * ============================================================================
+ */
+
+static int get_byte(struct s5p_jpeg_buffer *buf)
+{
+	if (buf->curr >= buf->size)
+		return -1;
+
+	return ((unsigned char *)buf->data)[buf->curr++];
+}
+
+static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
+{
+	unsigned int temp;
+	int byte;
+
+	byte = get_byte(buf);
+	if (byte == -1)
+		return -1;
+	temp = byte << 8;
+	byte = get_byte(buf);
+	if (byte == -1)
+		return -1;
+	*word = (unsigned int)byte | temp;
+	return 0;
+}
+
+static void skip(struct s5p_jpeg_buffer *buf, long len)
+{
+	if (len <= 0)
+		return;
+
+	while (len--)
+		get_byte(buf);
+}
+
+static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
+			       unsigned long buffer, unsigned long size)
+{
+	int c, components, notfound;
+	unsigned int height, width, word;
+	long length;
+	struct s5p_jpeg_buffer jpeg_buffer;
+
+	jpeg_buffer.size = size;
+	jpeg_buffer.data = buffer;
+	jpeg_buffer.curr = 0;
+
+	notfound = 1;
+	while (notfound) {
+		c = get_byte(&jpeg_buffer);
+		if (c == -1)
+			break;
+		if (c != 0xff)
+			continue;
+		do
+			c = get_byte(&jpeg_buffer);
+		while (c == 0xff);
+		if (c == -1)
+			break;
+		if (c == 0)
+			continue;
+		length = 0;
+		switch (c) {
+		/* SOF0: baseline JPEG */
+		case SOF0:
+			if (get_word_be(&jpeg_buffer, &word))
+				break;
+			if (get_byte(&jpeg_buffer) == -1)
+				break;
+			if (get_word_be(&jpeg_buffer, &height))
+				break;
+			if (get_word_be(&jpeg_buffer, &width))
+				break;
+			components = get_byte(&jpeg_buffer);
+			if (components == -1)
+				break;
+			notfound = 0;
+
+			skip(&jpeg_buffer, components * 3);
+			break;
+
+		/* skip payload-less markers */
+		case RST ... RST + 7:
+		case SOI:
+		case EOI:
+		case TEM:
+			break;
+
+		/* skip uninteresting payload markers */
+		default:
+			if (get_word_be(&jpeg_buffer, &word))
+				break;
+			length = (long)word - 2;
+			skip(&jpeg_buffer, length);
+			break;
+		}
+	}
+	result->w = width;
+	result->h = height;
+	result->size = components;
+	return !notfound;
+}
+
+static int s5p_jpeg_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+	if (ctx->mode == S5P_JPEG_ENCODE) {
+		strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
+			sizeof(cap->driver));
+		strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
+			sizeof(cap->card));
+	} else {
+		strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder",
+			sizeof(cap->driver));
+		strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
+			sizeof(cap->card));
+	}
+	cap->bus_info[0] = 0;
+	/*
+	 * This is only a mem-to-mem video device. The capture and output
+	 * device capability flags are left only for backward compatibility
+	 * and are scheduled for removal.
+	 */
+	cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M |
+			    V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT;
+	return 0;
+}
+
+static int enum_fmt(struct s5p_jpeg_fmt *formats, int n,
+		    struct v4l2_fmtdesc *f, u32 type)
+{
+	int i, num = 0;
+
+	for (i = 0; i < n; ++i) {
+		if (formats[i].types & type) {
+			/* index-th format of type type found ? */
+			if (num == f->index)
+				break;
+			/* Correct type but haven't reached our index yet,
+			 * just increment per-type index */
+			++num;
+		}
+	}
+
+	/* Format not found */
+	if (i >= n)
+		return -EINVAL;
+
+	strlcpy(f->description, formats[i].name, sizeof(f->description));
+	f->pixelformat = formats[i].fourcc;
+
+	return 0;
+}
+
+static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+	if (ctx->mode == S5P_JPEG_ENCODE)
+		return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
+				MEM2MEM_CAPTURE);
+
+	return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_CAPTURE);
+}
+
+static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+	if (ctx->mode == S5P_JPEG_ENCODE)
+		return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
+				MEM2MEM_OUTPUT);
+
+	return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_OUTPUT);
+}
+
+static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
+					  enum v4l2_buf_type type)
+{
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return &ctx->out_q;
+	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return &ctx->cap_q;
+
+	return NULL;
+}
+
+static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+	struct vb2_queue *vq;
+	struct s5p_jpeg_q_data *q_data = NULL;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
+
+	vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
+		return -EINVAL;
+	q_data = get_q_data(ct, f->type);
+	BUG_ON(q_data == NULL);
+
+	pix->width = q_data->w;
+	pix->height = q_data->h;
+	pix->field = V4L2_FIELD_NONE;
+	pix->pixelformat = q_data->fmt->fourcc;
+	pix->bytesperline = 0;
+	if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
+		u32 bpl = q_data->w;
+		if (q_data->fmt->colplanes == 1)
+			bpl = (bpl * q_data->fmt->depth) >> 3;
+		pix->bytesperline = bpl;
+	}
+	pix->sizeimage = q_data->size;
+
+	return 0;
+}
+
+static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
+						 u32 pixelformat)
+{
+	unsigned int k;
+	struct s5p_jpeg_fmt *formats;
+	int n;
+
+	if (mode == S5P_JPEG_ENCODE) {
+		formats = formats_enc;
+		n = NUM_FORMATS_ENC;
+	} else {
+		formats = formats_dec;
+		n = NUM_FORMATS_DEC;
+	}
+
+	for (k = 0; k < n; k++) {
+		struct s5p_jpeg_fmt *fmt = &formats[k];
+		if (fmt->fourcc == pixelformat)
+			return fmt;
+	}
+
+	return NULL;
+
+}
+
+static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
+				   unsigned int walign,
+				   u32 *h, unsigned int hmin, unsigned int hmax,
+				   unsigned int halign)
+{
+	int width, height, w_step, h_step;
+
+	width = *w;
+	height = *h;
+
+	w_step = 1 << walign;
+	h_step = 1 << halign;
+	v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
+
+	if (*w < width && (*w + w_step) < wmax)
+		*w += w_step;
+	if (*h < height && (*h + h_step) < hmax)
+		*h += h_step;
+
+}
+
+static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
+			  struct s5p_jpeg_ctx *ctx, int q_type)
+{
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+
+	if (pix->field == V4L2_FIELD_ANY)
+		pix->field = V4L2_FIELD_NONE;
+	else if (pix->field != V4L2_FIELD_NONE)
+		return -EINVAL;
+
+	/* V4L2 specification suggests the driver corrects the format struct
+	 * if any of the dimensions is unsupported */
+	if (q_type == MEM2MEM_OUTPUT)
+		jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
+				       S5P_JPEG_MAX_WIDTH, 0,
+				       &pix->height, S5P_JPEG_MIN_HEIGHT,
+				       S5P_JPEG_MAX_HEIGHT, 0);
+	else
+		jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
+				       S5P_JPEG_MAX_WIDTH, fmt->h_align,
+				       &pix->height, S5P_JPEG_MIN_HEIGHT,
+				       S5P_JPEG_MAX_HEIGHT, fmt->v_align);
+
+	if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
+		if (pix->sizeimage <= 0)
+			pix->sizeimage = PAGE_SIZE;
+		pix->bytesperline = 0;
+	} else {
+		u32 bpl = pix->bytesperline;
+
+		if (fmt->colplanes > 1 && bpl < pix->width)
+			bpl = pix->width; /* planar */
+
+		if (fmt->colplanes == 1 && /* packed */
+		    (bpl << 3) * fmt->depth < pix->width)
+			bpl = (pix->width * fmt->depth) >> 3;
+
+		pix->bytesperline = bpl;
+		pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
+	}
+
+	return 0;
+}
+
+static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+	struct s5p_jpeg_fmt *fmt;
+
+	fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
+	if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
+		v4l2_err(&ctx->jpeg->v4l2_dev,
+			 "Fourcc format (0x%08x) invalid.\n",
+			 f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_CAPTURE);
+}
+
+static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+	struct s5p_jpeg_fmt *fmt;
+
+	fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
+	if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
+		v4l2_err(&ctx->jpeg->v4l2_dev,
+			 "Fourcc format (0x%08x) invalid.\n",
+			 f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_OUTPUT);
+}
+
+static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
+{
+	struct vb2_queue *vq;
+	struct s5p_jpeg_q_data *q_data = NULL;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+
+	vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+
+	q_data = get_q_data(ct, f->type);
+	BUG_ON(q_data == NULL);
+
+	if (vb2_is_busy(vq)) {
+		v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
+		return -EBUSY;
+	}
+
+	q_data->fmt = s5p_jpeg_find_format(ct->mode, pix->pixelformat);
+	q_data->w = pix->width;
+	q_data->h = pix->height;
+	if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG)
+		q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
+	else
+		q_data->size = pix->sizeimage;
+
+	return 0;
+}
+
+static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	int ret;
+
+	ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
+	if (ret)
+		return ret;
+
+	return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
+}
+
+static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	int ret;
+
+	ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
+	if (ret)
+		return ret;
+
+	return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
+}
+
+static int s5p_jpeg_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *reqbufs)
+{
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int s5p_jpeg_querybuf(struct file *file, void *priv,
+			   struct v4l2_buffer *buf)
+{
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int s5p_jpeg_dqbuf(struct file *file, void *priv,
+			  struct v4l2_buffer *buf)
+{
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int s5p_jpeg_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type type)
+{
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int s5p_jpeg_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type type)
+{
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static int s5p_jpeg_g_selection(struct file *file, void *priv,
+			 struct v4l2_selection *s)
+{
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+	    s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	/* For JPEG blob active == default == bounds */
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE:
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+		s->r.width = ctx->out_q.w;
+		s->r.height = ctx->out_q.h;
+		break;
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_COMPOSE_PADDED:
+		s->r.width = ctx->cap_q.w;
+		s->r.height = ctx->cap_q.h;
+		break;
+	default:
+		return -EINVAL;
+	}
+	s->r.left = 0;
+	s->r.top = 0;
+	return 0;
+}
+
+/*
+ * V4L2 controls
+ */
+
+static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
+	struct s5p_jpeg *jpeg = ctx->jpeg;
+	unsigned long flags;
+
+	switch (ctrl->id) {
+	case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+		spin_lock_irqsave(&jpeg->slock, flags);
+
+		WARN_ON(ctx->subsampling > S5P_SUBSAMPLING_MODE_GRAY);
+		if (ctx->subsampling > 2)
+			ctrl->val = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
+		else
+			ctrl->val = ctx->subsampling;
+		spin_unlock_irqrestore(&jpeg->slock, flags);
+		break;
+	}
+
+	return 0;
+}
+
+static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctx->jpeg->slock, flags);
+
+	switch (ctrl->id) {
+	case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+		ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - ctrl->val;
+		break;
+	case V4L2_CID_JPEG_RESTART_INTERVAL:
+		ctx->restart_interval = ctrl->val;
+		break;
+	case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+		ctx->subsampling = ctrl->val;
+		break;
+	}
+
+	spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
+	.g_volatile_ctrl	= s5p_jpeg_g_volatile_ctrl,
+	.s_ctrl			= s5p_jpeg_s_ctrl,
+};
+
+static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
+{
+	unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
+	struct v4l2_ctrl *ctrl;
+
+	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
+
+	if (ctx->mode == S5P_JPEG_ENCODE) {
+		v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
+				  V4L2_CID_JPEG_COMPRESSION_QUALITY,
+				  0, 3, 1, 3);
+
+		v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
+				  V4L2_CID_JPEG_RESTART_INTERVAL,
+				  0, 3, 0xffff, 0);
+		mask = ~0x06; /* 422, 420 */
+	}
+
+	ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
+				      V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
+				      V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
+				      V4L2_JPEG_CHROMA_SUBSAMPLING_422);
+
+	if (ctx->ctrl_handler.error)
+		return ctx->ctrl_handler.error;
+
+	if (ctx->mode == S5P_JPEG_DECODE)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
+			V4L2_CTRL_FLAG_READ_ONLY;
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
+	.vidioc_querycap		= s5p_jpeg_querycap,
+
+	.vidioc_enum_fmt_vid_cap	= s5p_jpeg_enum_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_out	= s5p_jpeg_enum_fmt_vid_out,
+
+	.vidioc_g_fmt_vid_cap		= s5p_jpeg_g_fmt,
+	.vidioc_g_fmt_vid_out		= s5p_jpeg_g_fmt,
+
+	.vidioc_try_fmt_vid_cap		= s5p_jpeg_try_fmt_vid_cap,
+	.vidioc_try_fmt_vid_out		= s5p_jpeg_try_fmt_vid_out,
+
+	.vidioc_s_fmt_vid_cap		= s5p_jpeg_s_fmt_vid_cap,
+	.vidioc_s_fmt_vid_out		= s5p_jpeg_s_fmt_vid_out,
+
+	.vidioc_reqbufs			= s5p_jpeg_reqbufs,
+	.vidioc_querybuf		= s5p_jpeg_querybuf,
+
+	.vidioc_qbuf			= s5p_jpeg_qbuf,
+	.vidioc_dqbuf			= s5p_jpeg_dqbuf,
+
+	.vidioc_streamon		= s5p_jpeg_streamon,
+	.vidioc_streamoff		= s5p_jpeg_streamoff,
+
+	.vidioc_g_selection		= s5p_jpeg_g_selection,
+};
+
+/*
+ * ============================================================================
+ * mem2mem callbacks
+ * ============================================================================
+ */
+
+static void s5p_jpeg_device_run(void *priv)
+{
+	struct s5p_jpeg_ctx *ctx = priv;
+	struct s5p_jpeg *jpeg = ctx->jpeg;
+	struct vb2_buffer *src_buf, *dst_buf;
+	unsigned long src_addr, dst_addr;
+
+	src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+	src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+	dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+
+	jpeg_reset(jpeg->regs);
+	jpeg_poweron(jpeg->regs);
+	jpeg_proc_mode(jpeg->regs, ctx->mode);
+	if (ctx->mode == S5P_JPEG_ENCODE) {
+		if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
+			jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565);
+		else
+			jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422);
+		jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
+		jpeg_dri(jpeg->regs, ctx->restart_interval);
+		jpeg_x(jpeg->regs, ctx->out_q.w);
+		jpeg_y(jpeg->regs, ctx->out_q.h);
+		jpeg_imgadr(jpeg->regs, src_addr);
+		jpeg_jpgadr(jpeg->regs, dst_addr);
+
+		/* ultimately comes from sizeimage from userspace */
+		jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
+
+		/* JPEG RGB to YCbCr conversion matrix */
+		jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
+		jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
+		jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
+		jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
+		jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
+		jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
+		jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
+		jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
+		jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
+
+		/*
+		 * JPEG IP allows storing 4 quantization tables
+		 * We fill table 0 for luma and table 1 for chroma
+		 */
+		jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
+		jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
+		/* use table 0 for Y */
+		jpeg_qtbl(jpeg->regs, 1, 0);
+		/* use table 1 for Cb and Cr*/
+		jpeg_qtbl(jpeg->regs, 2, 1);
+		jpeg_qtbl(jpeg->regs, 3, 1);
+
+		/* Y, Cb, Cr use Huffman table 0 */
+		jpeg_htbl_ac(jpeg->regs, 1);
+		jpeg_htbl_dc(jpeg->regs, 1);
+		jpeg_htbl_ac(jpeg->regs, 2);
+		jpeg_htbl_dc(jpeg->regs, 2);
+		jpeg_htbl_ac(jpeg->regs, 3);
+		jpeg_htbl_dc(jpeg->regs, 3);
+	} else { /* S5P_JPEG_DECODE */
+		jpeg_rst_int_enable(jpeg->regs, true);
+		jpeg_data_num_int_enable(jpeg->regs, true);
+		jpeg_final_mcu_num_int_enable(jpeg->regs, true);
+		if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
+			jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
+		else
+			jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
+		jpeg_jpgadr(jpeg->regs, src_addr);
+		jpeg_imgadr(jpeg->regs, dst_addr);
+	}
+
+	jpeg_start(jpeg->regs);
+}
+
+static int s5p_jpeg_job_ready(void *priv)
+{
+	struct s5p_jpeg_ctx *ctx = priv;
+
+	if (ctx->mode == S5P_JPEG_DECODE)
+		return ctx->hdr_parsed;
+	return 1;
+}
+
+static void s5p_jpeg_job_abort(void *priv)
+{
+}
+
+static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
+	.device_run	= s5p_jpeg_device_run,
+	.job_ready	= s5p_jpeg_job_ready,
+	.job_abort	= s5p_jpeg_job_abort,
+};
+
+/*
+ * ============================================================================
+ * Queue operations
+ * ============================================================================
+ */
+
+static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
+			   const struct v4l2_format *fmt,
+			   unsigned int *nbuffers, unsigned int *nplanes,
+			   unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+	struct s5p_jpeg_q_data *q_data = NULL;
+	unsigned int size, count = *nbuffers;
+
+	q_data = get_q_data(ctx, vq->type);
+	BUG_ON(q_data == NULL);
+
+	size = q_data->size;
+
+	/*
+	 * header is parsed during decoding and parsed information stored
+	 * in the context so we do not allow another buffer to overwrite it
+	 */
+	if (ctx->mode == S5P_JPEG_DECODE)
+		count = 1;
+
+	*nbuffers = count;
+	*nplanes = 1;
+	sizes[0] = size;
+	alloc_ctxs[0] = ctx->jpeg->alloc_ctx;
+
+	return 0;
+}
+
+static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
+{
+	struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct s5p_jpeg_q_data *q_data = NULL;
+
+	q_data = get_q_data(ctx, vb->vb2_queue->type);
+	BUG_ON(q_data == NULL);
+
+	if (vb2_plane_size(vb, 0) < q_data->size) {
+		pr_err("%s data will not fit into plane (%lu < %lu)\n",
+				__func__, vb2_plane_size(vb, 0),
+				(long)q_data->size);
+		return -EINVAL;
+	}
+
+	vb2_set_plane_payload(vb, 0, q_data->size);
+
+	return 0;
+}
+
+static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
+{
+	struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+	if (ctx->mode == S5P_JPEG_DECODE &&
+	    vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		struct s5p_jpeg_q_data tmp, *q_data;
+		ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
+		     (unsigned long)vb2_plane_vaddr(vb, 0),
+		     min((unsigned long)ctx->out_q.size,
+			 vb2_get_plane_payload(vb, 0)));
+		if (!ctx->hdr_parsed) {
+			vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+			return;
+		}
+
+		q_data = &ctx->out_q;
+		q_data->w = tmp.w;
+		q_data->h = tmp.h;
+
+		q_data = &ctx->cap_q;
+		q_data->w = tmp.w;
+		q_data->h = tmp.h;
+
+		jpeg_bound_align_image(&q_data->w, S5P_JPEG_MIN_WIDTH,
+				       S5P_JPEG_MAX_WIDTH, q_data->fmt->h_align,
+				       &q_data->h, S5P_JPEG_MIN_HEIGHT,
+				       S5P_JPEG_MAX_HEIGHT, q_data->fmt->v_align
+				      );
+		q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
+	}
+	if (ctx->m2m_ctx)
+		v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static void s5p_jpeg_wait_prepare(struct vb2_queue *vq)
+{
+	struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+
+	mutex_unlock(&ctx->jpeg->lock);
+}
+
+static void s5p_jpeg_wait_finish(struct vb2_queue *vq)
+{
+	struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+
+	mutex_lock(&ctx->jpeg->lock);
+}
+
+static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+	int ret;
+
+	ret = pm_runtime_get_sync(ctx->jpeg->dev);
+
+	return ret > 0 ? 0 : ret;
+}
+
+static int s5p_jpeg_stop_streaming(struct vb2_queue *q)
+{
+	struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+
+	pm_runtime_put(ctx->jpeg->dev);
+
+	return 0;
+}
+
+static struct vb2_ops s5p_jpeg_qops = {
+	.queue_setup		= s5p_jpeg_queue_setup,
+	.buf_prepare		= s5p_jpeg_buf_prepare,
+	.buf_queue		= s5p_jpeg_buf_queue,
+	.wait_prepare		= s5p_jpeg_wait_prepare,
+	.wait_finish		= s5p_jpeg_wait_finish,
+	.start_streaming	= s5p_jpeg_start_streaming,
+	.stop_streaming		= s5p_jpeg_stop_streaming,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+		      struct vb2_queue *dst_vq)
+{
+	struct s5p_jpeg_ctx *ctx = priv;
+	int ret;
+
+	memset(src_vq, 0, sizeof(*src_vq));
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+	src_vq->drv_priv = ctx;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	src_vq->ops = &s5p_jpeg_qops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	memset(dst_vq, 0, sizeof(*dst_vq));
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+	dst_vq->drv_priv = ctx;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->ops = &s5p_jpeg_qops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+	return vb2_queue_init(dst_vq);
+}
+
+/*
+ * ============================================================================
+ * ISR
+ * ============================================================================
+ */
+
+static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
+{
+	struct s5p_jpeg *jpeg = dev_id;
+	struct s5p_jpeg_ctx *curr_ctx;
+	struct vb2_buffer *src_buf, *dst_buf;
+	unsigned long payload_size = 0;
+	enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
+	bool enc_jpeg_too_large = false;
+	bool timer_elapsed = false;
+	bool op_completed = false;
+
+	spin_lock(&jpeg->slock);
+
+	curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
+
+	src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
+	dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+
+	if (curr_ctx->mode == S5P_JPEG_ENCODE)
+		enc_jpeg_too_large = jpeg_enc_stream_stat(jpeg->regs);
+	timer_elapsed = jpeg_timer_stat(jpeg->regs);
+	op_completed = jpeg_result_stat_ok(jpeg->regs);
+	if (curr_ctx->mode == S5P_JPEG_DECODE)
+		op_completed = op_completed && jpeg_stream_stat_ok(jpeg->regs);
+
+	if (enc_jpeg_too_large) {
+		state = VB2_BUF_STATE_ERROR;
+		jpeg_clear_enc_stream_stat(jpeg->regs);
+	} else if (timer_elapsed) {
+		state = VB2_BUF_STATE_ERROR;
+		jpeg_clear_timer_stat(jpeg->regs);
+	} else if (!op_completed) {
+		state = VB2_BUF_STATE_ERROR;
+	} else {
+		payload_size = jpeg_compressed_size(jpeg->regs);
+	}
+
+	v4l2_m2m_buf_done(src_buf, state);
+	if (curr_ctx->mode == S5P_JPEG_ENCODE)
+		vb2_set_plane_payload(dst_buf, 0, payload_size);
+	v4l2_m2m_buf_done(dst_buf, state);
+	v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx);
+
+	curr_ctx->subsampling = jpeg_get_subsampling_mode(jpeg->regs);
+	spin_unlock(&jpeg->slock);
+
+	jpeg_clear_int(jpeg->regs);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * ============================================================================
+ * Driver basic infrastructure
+ * ============================================================================
+ */
+
+static int s5p_jpeg_probe(struct platform_device *pdev)
+{
+	struct s5p_jpeg *jpeg;
+	struct resource *res;
+	int ret;
+
+	/* JPEG IP abstraction struct */
+	jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
+	if (!jpeg)
+		return -ENOMEM;
+
+	mutex_init(&jpeg->lock);
+	spin_lock_init(&jpeg->slock);
+	jpeg->dev = &pdev->dev;
+
+	/* memory-mapped registers */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	jpeg->regs = devm_request_and_ioremap(&pdev->dev, res);
+	if (jpeg->regs == NULL) {
+		dev_err(&pdev->dev, "Failed to obtain io memory\n");
+		return -ENOENT;
+	}
+
+	/* interrupt service routine registration */
+	jpeg->irq = ret = platform_get_irq(pdev, 0);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "cannot find IRQ\n");
+		return ret;
+	}
+
+	ret = devm_request_irq(&pdev->dev, jpeg->irq, s5p_jpeg_irq, 0,
+			dev_name(&pdev->dev), jpeg);
+	if (ret) {
+		dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
+		return ret;
+	}
+
+	/* clocks */
+	jpeg->clk = clk_get(&pdev->dev, "jpeg");
+	if (IS_ERR(jpeg->clk)) {
+		dev_err(&pdev->dev, "cannot get clock\n");
+		ret = PTR_ERR(jpeg->clk);
+		return ret;
+	}
+	dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
+	clk_enable(jpeg->clk);
+
+	/* v4l2 device */
+	ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register v4l2 device\n");
+		goto clk_get_rollback;
+	}
+
+	/* mem2mem device */
+	jpeg->m2m_dev = v4l2_m2m_init(&s5p_jpeg_m2m_ops);
+	if (IS_ERR(jpeg->m2m_dev)) {
+		v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
+		ret = PTR_ERR(jpeg->m2m_dev);
+		goto device_register_rollback;
+	}
+
+	jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+	if (IS_ERR(jpeg->alloc_ctx)) {
+		v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n");
+		ret = PTR_ERR(jpeg->alloc_ctx);
+		goto m2m_init_rollback;
+	}
+
+	/* JPEG encoder /dev/videoX node */
+	jpeg->vfd_encoder = video_device_alloc();
+	if (!jpeg->vfd_encoder) {
+		v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
+		ret = -ENOMEM;
+		goto vb2_allocator_rollback;
+	}
+	strlcpy(jpeg->vfd_encoder->name, S5P_JPEG_M2M_NAME,
+		sizeof(jpeg->vfd_encoder->name));
+	jpeg->vfd_encoder->fops		= &s5p_jpeg_fops;
+	jpeg->vfd_encoder->ioctl_ops	= &s5p_jpeg_ioctl_ops;
+	jpeg->vfd_encoder->minor	= -1;
+	jpeg->vfd_encoder->release	= video_device_release;
+	jpeg->vfd_encoder->lock		= &jpeg->lock;
+	jpeg->vfd_encoder->v4l2_dev	= &jpeg->v4l2_dev;
+
+	ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
+	if (ret) {
+		v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
+		goto enc_vdev_alloc_rollback;
+	}
+
+	video_set_drvdata(jpeg->vfd_encoder, jpeg);
+	v4l2_info(&jpeg->v4l2_dev,
+		  "encoder device registered as /dev/video%d\n",
+		  jpeg->vfd_encoder->num);
+
+	/* JPEG decoder /dev/videoX node */
+	jpeg->vfd_decoder = video_device_alloc();
+	if (!jpeg->vfd_decoder) {
+		v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
+		ret = -ENOMEM;
+		goto enc_vdev_register_rollback;
+	}
+	strlcpy(jpeg->vfd_decoder->name, S5P_JPEG_M2M_NAME,
+		sizeof(jpeg->vfd_decoder->name));
+	jpeg->vfd_decoder->fops		= &s5p_jpeg_fops;
+	jpeg->vfd_decoder->ioctl_ops	= &s5p_jpeg_ioctl_ops;
+	jpeg->vfd_decoder->minor	= -1;
+	jpeg->vfd_decoder->release	= video_device_release;
+	jpeg->vfd_decoder->lock		= &jpeg->lock;
+	jpeg->vfd_decoder->v4l2_dev	= &jpeg->v4l2_dev;
+
+	ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
+	if (ret) {
+		v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
+		goto dec_vdev_alloc_rollback;
+	}
+
+	video_set_drvdata(jpeg->vfd_decoder, jpeg);
+	v4l2_info(&jpeg->v4l2_dev,
+		  "decoder device registered as /dev/video%d\n",
+		  jpeg->vfd_decoder->num);
+
+	/* final statements & power management */
+	platform_set_drvdata(pdev, jpeg);
+
+	pm_runtime_enable(&pdev->dev);
+
+	v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
+
+	return 0;
+
+dec_vdev_alloc_rollback:
+	video_device_release(jpeg->vfd_decoder);
+
+enc_vdev_register_rollback:
+	video_unregister_device(jpeg->vfd_encoder);
+
+enc_vdev_alloc_rollback:
+	video_device_release(jpeg->vfd_encoder);
+
+vb2_allocator_rollback:
+	vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
+
+m2m_init_rollback:
+	v4l2_m2m_release(jpeg->m2m_dev);
+
+device_register_rollback:
+	v4l2_device_unregister(&jpeg->v4l2_dev);
+
+clk_get_rollback:
+	clk_disable(jpeg->clk);
+	clk_put(jpeg->clk);
+
+	return ret;
+}
+
+static int s5p_jpeg_remove(struct platform_device *pdev)
+{
+	struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
+
+	pm_runtime_disable(jpeg->dev);
+
+	video_unregister_device(jpeg->vfd_decoder);
+	video_device_release(jpeg->vfd_decoder);
+	video_unregister_device(jpeg->vfd_encoder);
+	video_device_release(jpeg->vfd_encoder);
+	vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
+	v4l2_m2m_release(jpeg->m2m_dev);
+	v4l2_device_unregister(&jpeg->v4l2_dev);
+
+	clk_disable(jpeg->clk);
+	clk_put(jpeg->clk);
+
+	return 0;
+}
+
+static int s5p_jpeg_runtime_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int s5p_jpeg_runtime_resume(struct device *dev)
+{
+	struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
+	/*
+	 * JPEG IP allows storing two Huffman tables for each component
+	 * We fill table 0 for each component
+	 */
+	jpeg_set_hdctbl(jpeg->regs);
+	jpeg_set_hdctblg(jpeg->regs);
+	jpeg_set_hactbl(jpeg->regs);
+	jpeg_set_hactblg(jpeg->regs);
+	return 0;
+}
+
+static const struct dev_pm_ops s5p_jpeg_pm_ops = {
+	.runtime_suspend = s5p_jpeg_runtime_suspend,
+	.runtime_resume	 = s5p_jpeg_runtime_resume,
+};
+
+static struct platform_driver s5p_jpeg_driver = {
+	.probe = s5p_jpeg_probe,
+	.remove = s5p_jpeg_remove,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = S5P_JPEG_M2M_NAME,
+		.pm = &s5p_jpeg_pm_ops,
+	},
+};
+
+module_platform_driver(s5p_jpeg_driver);
+
+MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
+MODULE_DESCRIPTION("Samsung JPEG codec driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h
new file mode 100644
index 0000000..022b9b9
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h
@@ -0,0 +1,150 @@
+/* linux/drivers/media/platform/s5p-jpeg/jpeg-core.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef JPEG_CORE_H_
+#define JPEG_CORE_H_
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+
+#define S5P_JPEG_M2M_NAME		"s5p-jpeg"
+
+/* JPEG compression quality setting */
+#define S5P_JPEG_COMPR_QUAL_BEST	0
+#define S5P_JPEG_COMPR_QUAL_WORST	3
+
+/* JPEG RGB to YCbCr conversion matrix coefficients */
+#define S5P_JPEG_COEF11			0x4d
+#define S5P_JPEG_COEF12			0x97
+#define S5P_JPEG_COEF13			0x1e
+#define S5P_JPEG_COEF21			0x2c
+#define S5P_JPEG_COEF22			0x57
+#define S5P_JPEG_COEF23			0x83
+#define S5P_JPEG_COEF31			0x83
+#define S5P_JPEG_COEF32			0x6e
+#define S5P_JPEG_COEF33			0x13
+
+/* a selection of JPEG markers */
+#define TEM				0x01
+#define SOF0				0xc0
+#define RST				0xd0
+#define SOI				0xd8
+#define EOI				0xd9
+#define DHP				0xde
+
+/* Flags that indicate a format can be used for capture/output */
+#define MEM2MEM_CAPTURE			(1 << 0)
+#define MEM2MEM_OUTPUT			(1 << 1)
+
+/**
+ * struct s5p_jpeg - JPEG IP abstraction
+ * @lock:		the mutex protecting this structure
+ * @slock:		spinlock protecting the device contexts
+ * @v4l2_dev:		v4l2 device for mem2mem mode
+ * @vfd_encoder:	video device node for encoder mem2mem mode
+ * @vfd_decoder:	video device node for decoder mem2mem mode
+ * @m2m_dev:		v4l2 mem2mem device data
+ * @regs:		JPEG IP registers mapping
+ * @irq:		JPEG IP irq
+ * @clk:		JPEG IP clock
+ * @dev:		JPEG IP struct device
+ * @alloc_ctx:		videobuf2 memory allocator's context
+ */
+struct s5p_jpeg {
+	struct mutex		lock;
+	struct spinlock		slock;
+
+	struct v4l2_device	v4l2_dev;
+	struct video_device	*vfd_encoder;
+	struct video_device	*vfd_decoder;
+	struct v4l2_m2m_dev	*m2m_dev;
+
+	void __iomem		*regs;
+	unsigned int		irq;
+	struct clk		*clk;
+	struct device		*dev;
+	void			*alloc_ctx;
+};
+
+/**
+ * struct jpeg_fmt - driver's internal color format data
+ * @name:	format descritpion
+ * @fourcc:	the fourcc code, 0 if not applicable
+ * @depth:	number of bits per pixel
+ * @colplanes:	number of color planes (1 for packed formats)
+ * @h_align:	horizontal alignment order (align to 2^h_align)
+ * @v_align:	vertical alignment order (align to 2^v_align)
+ * @types:	types of queue this format is applicable to
+ */
+struct s5p_jpeg_fmt {
+	char	*name;
+	u32	fourcc;
+	int	depth;
+	int	colplanes;
+	int	h_align;
+	int	v_align;
+	u32	types;
+};
+
+/**
+ * s5p_jpeg_q_data - parameters of one queue
+ * @fmt:	driver-specific format of this queue
+ * @w:		image width
+ * @h:		image height
+ * @size:	image buffer size in bytes
+ */
+struct s5p_jpeg_q_data {
+	struct s5p_jpeg_fmt	*fmt;
+	u32			w;
+	u32			h;
+	u32			size;
+};
+
+/**
+ * s5p_jpeg_ctx - the device context data
+ * @jpeg:		JPEG IP device for this context
+ * @mode:		compression (encode) operation or decompression (decode)
+ * @compr_quality:	destination image quality in compression (encode) mode
+ * @m2m_ctx:		mem2mem device context
+ * @out_q:		source (output) queue information
+ * @cap_fmt:		destination (capture) queue queue information
+ * @hdr_parsed:		set if header has been parsed during decompression
+ * @ctrl_handler:	controls handler
+ */
+struct s5p_jpeg_ctx {
+	struct s5p_jpeg		*jpeg;
+	unsigned int		mode;
+	unsigned short		compr_quality;
+	unsigned short		restart_interval;
+	unsigned short		subsampling;
+	struct v4l2_m2m_ctx	*m2m_ctx;
+	struct s5p_jpeg_q_data	out_q;
+	struct s5p_jpeg_q_data	cap_q;
+	struct v4l2_fh		fh;
+	bool			hdr_parsed;
+	struct v4l2_ctrl_handler ctrl_handler;
+};
+
+/**
+ * s5p_jpeg_buffer - description of memory containing input JPEG data
+ * @size:	buffer size
+ * @curr:	current position in the buffer
+ * @data:	pointer to the data
+ */
+struct s5p_jpeg_buffer {
+	unsigned long size;
+	unsigned long curr;
+	unsigned long data;
+};
+
+#endif /* JPEG_CORE_H */
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw.h b/drivers/media/platform/s5p-jpeg/jpeg-hw.h
new file mode 100644
index 0000000..b47e887
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw.h
@@ -0,0 +1,357 @@
+/* linux/drivers/media/platform/s5p-jpeg/jpeg-hw.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef JPEG_HW_H_
+#define JPEG_HW_H_
+
+#include <linux/io.h>
+#include <linux/videodev2.h>
+
+#include "jpeg-hw.h"
+#include "jpeg-regs.h"
+
+#define S5P_JPEG_MIN_WIDTH		32
+#define S5P_JPEG_MIN_HEIGHT		32
+#define S5P_JPEG_MAX_WIDTH		8192
+#define S5P_JPEG_MAX_HEIGHT		8192
+#define S5P_JPEG_ENCODE			0
+#define S5P_JPEG_DECODE			1
+#define S5P_JPEG_RAW_IN_565		0
+#define S5P_JPEG_RAW_IN_422		1
+#define S5P_JPEG_RAW_OUT_422		0
+#define S5P_JPEG_RAW_OUT_420		1
+
+static inline void jpeg_reset(void __iomem *regs)
+{
+	unsigned long reg;
+
+	writel(1, regs + S5P_JPG_SW_RESET);
+	reg = readl(regs + S5P_JPG_SW_RESET);
+	/* no other way but polling for when JPEG IP becomes operational */
+	while (reg != 0) {
+		cpu_relax();
+		reg = readl(regs + S5P_JPG_SW_RESET);
+	}
+}
+
+static inline void jpeg_poweron(void __iomem *regs)
+{
+	writel(S5P_POWER_ON, regs + S5P_JPGCLKCON);
+}
+
+static inline void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode)
+{
+	unsigned long reg, m;
+
+	m = S5P_MOD_SEL_565;
+	if (mode == S5P_JPEG_RAW_IN_565)
+		m = S5P_MOD_SEL_565;
+	else if (mode == S5P_JPEG_RAW_IN_422)
+		m = S5P_MOD_SEL_422;
+
+	reg = readl(regs + S5P_JPGCMOD);
+	reg &= ~S5P_MOD_SEL_MASK;
+	reg |= m;
+	writel(reg, regs + S5P_JPGCMOD);
+}
+
+static inline void jpeg_input_raw_y16(void __iomem *regs, bool y16)
+{
+	unsigned long reg;
+
+	reg = readl(regs + S5P_JPGCMOD);
+	if (y16)
+		reg |= S5P_MODE_Y16;
+	else
+		reg &= ~S5P_MODE_Y16_MASK;
+	writel(reg, regs + S5P_JPGCMOD);
+}
+
+static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode)
+{
+	unsigned long reg, m;
+
+	m = S5P_PROC_MODE_DECOMPR;
+	if (mode == S5P_JPEG_ENCODE)
+		m = S5P_PROC_MODE_COMPR;
+	else
+		m = S5P_PROC_MODE_DECOMPR;
+	reg = readl(regs + S5P_JPGMOD);
+	reg &= ~S5P_PROC_MODE_MASK;
+	reg |= m;
+	writel(reg, regs + S5P_JPGMOD);
+}
+
+static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode)
+{
+	unsigned long reg, m;
+
+	if (mode == V4L2_JPEG_CHROMA_SUBSAMPLING_420)
+		m = S5P_SUBSAMPLING_MODE_420;
+	else
+		m = S5P_SUBSAMPLING_MODE_422;
+
+	reg = readl(regs + S5P_JPGMOD);
+	reg &= ~S5P_SUBSAMPLING_MODE_MASK;
+	reg |= m;
+	writel(reg, regs + S5P_JPGMOD);
+}
+
+static inline unsigned int jpeg_get_subsampling_mode(void __iomem *regs)
+{
+	return readl(regs + S5P_JPGMOD) & S5P_SUBSAMPLING_MODE_MASK;
+}
+
+static inline void jpeg_dri(void __iomem *regs, unsigned int dri)
+{
+	unsigned long reg;
+
+	reg = readl(regs + S5P_JPGDRI_U);
+	reg &= ~0xff;
+	reg |= (dri >> 8) & 0xff;
+	writel(reg, regs + S5P_JPGDRI_U);
+
+	reg = readl(regs + S5P_JPGDRI_L);
+	reg &= ~0xff;
+	reg |= dri & 0xff;
+	writel(reg, regs + S5P_JPGDRI_L);
+}
+
+static inline void jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n)
+{
+	unsigned long reg;
+
+	reg = readl(regs + S5P_JPG_QTBL);
+	reg &= ~S5P_QT_NUMt_MASK(t);
+	reg |= (n << S5P_QT_NUMt_SHIFT(t)) & S5P_QT_NUMt_MASK(t);
+	writel(reg, regs + S5P_JPG_QTBL);
+}
+
+static inline void jpeg_htbl_ac(void __iomem *regs, unsigned int t)
+{
+	unsigned long reg;
+
+	reg = readl(regs + S5P_JPG_HTBL);
+	reg &= ~S5P_HT_NUMt_AC_MASK(t);
+	/* this driver uses table 0 for all color components */
+	reg |= (0 << S5P_HT_NUMt_AC_SHIFT(t)) & S5P_HT_NUMt_AC_MASK(t);
+	writel(reg, regs + S5P_JPG_HTBL);
+}
+
+static inline void jpeg_htbl_dc(void __iomem *regs, unsigned int t)
+{
+	unsigned long reg;
+
+	reg = readl(regs + S5P_JPG_HTBL);
+	reg &= ~S5P_HT_NUMt_DC_MASK(t);
+	/* this driver uses table 0 for all color components */
+	reg |= (0 << S5P_HT_NUMt_DC_SHIFT(t)) & S5P_HT_NUMt_DC_MASK(t);
+	writel(reg, regs + S5P_JPG_HTBL);
+}
+
+static inline void jpeg_y(void __iomem *regs, unsigned int y)
+{
+	unsigned long reg;
+
+	reg = readl(regs + S5P_JPGY_U);
+	reg &= ~0xff;
+	reg |= (y >> 8) & 0xff;
+	writel(reg, regs + S5P_JPGY_U);
+
+	reg = readl(regs + S5P_JPGY_L);
+	reg &= ~0xff;
+	reg |= y & 0xff;
+	writel(reg, regs + S5P_JPGY_L);
+}
+
+static inline void jpeg_x(void __iomem *regs, unsigned int x)
+{
+	unsigned long reg;
+
+	reg = readl(regs + S5P_JPGX_U);
+	reg &= ~0xff;
+	reg |= (x >> 8) & 0xff;
+	writel(reg, regs + S5P_JPGX_U);
+
+	reg = readl(regs + S5P_JPGX_L);
+	reg &= ~0xff;
+	reg |= x & 0xff;
+	writel(reg, regs + S5P_JPGX_L);
+}
+
+static inline void jpeg_rst_int_enable(void __iomem *regs, bool enable)
+{
+	unsigned long reg;
+
+	reg = readl(regs + S5P_JPGINTSE);
+	reg &= ~S5P_RSTm_INT_EN_MASK;
+	if (enable)
+		reg |= S5P_RSTm_INT_EN;
+	writel(reg, regs + S5P_JPGINTSE);
+}
+
+static inline void jpeg_data_num_int_enable(void __iomem *regs, bool enable)
+{
+	unsigned long reg;
+
+	reg = readl(regs + S5P_JPGINTSE);
+	reg &= ~S5P_DATA_NUM_INT_EN_MASK;
+	if (enable)
+		reg |= S5P_DATA_NUM_INT_EN;
+	writel(reg, regs + S5P_JPGINTSE);
+}
+
+static inline void jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl)
+{
+	unsigned long reg;
+
+	reg = readl(regs + S5P_JPGINTSE);
+	reg &= ~S5P_FINAL_MCU_NUM_INT_EN_MASK;
+	if (enbl)
+		reg |= S5P_FINAL_MCU_NUM_INT_EN;
+	writel(reg, regs + S5P_JPGINTSE);
+}
+
+static inline void jpeg_timer_enable(void __iomem *regs, unsigned long val)
+{
+	unsigned long reg;
+
+	reg = readl(regs + S5P_JPG_TIMER_SE);
+	reg |= S5P_TIMER_INT_EN;
+	reg &= ~S5P_TIMER_INIT_MASK;
+	reg |= val & S5P_TIMER_INIT_MASK;
+	writel(reg, regs + S5P_JPG_TIMER_SE);
+}
+
+static inline void jpeg_timer_disable(void __iomem *regs)
+{
+	unsigned long reg;
+
+	reg = readl(regs + S5P_JPG_TIMER_SE);
+	reg &= ~S5P_TIMER_INT_EN_MASK;
+	writel(reg, regs + S5P_JPG_TIMER_SE);
+}
+
+static inline int jpeg_timer_stat(void __iomem *regs)
+{
+	return (int)((readl(regs + S5P_JPG_TIMER_ST) & S5P_TIMER_INT_STAT_MASK)
+		     >> S5P_TIMER_INT_STAT_SHIFT);
+}
+
+static inline void jpeg_clear_timer_stat(void __iomem *regs)
+{
+	unsigned long reg;
+
+	reg = readl(regs + S5P_JPG_TIMER_SE);
+	reg &= ~S5P_TIMER_INT_STAT_MASK;
+	writel(reg, regs + S5P_JPG_TIMER_SE);
+}
+
+static inline void jpeg_enc_stream_int(void __iomem *regs, unsigned long size)
+{
+	unsigned long reg;
+
+	reg = readl(regs + S5P_JPG_ENC_STREAM_INTSE);
+	reg &= ~S5P_ENC_STREAM_BOUND_MASK;
+	reg |= S5P_ENC_STREAM_INT_EN;
+	reg |= size & S5P_ENC_STREAM_BOUND_MASK;
+	writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE);
+}
+
+static inline int jpeg_enc_stream_stat(void __iomem *regs)
+{
+	return (int)(readl(regs + S5P_JPG_ENC_STREAM_INTST) &
+		     S5P_ENC_STREAM_INT_STAT_MASK);
+}
+
+static inline void jpeg_clear_enc_stream_stat(void __iomem *regs)
+{
+	unsigned long reg;
+
+	reg = readl(regs + S5P_JPG_ENC_STREAM_INTSE);
+	reg &= ~S5P_ENC_STREAM_INT_MASK;
+	writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE);
+}
+
+static inline void jpeg_outform_raw(void __iomem *regs, unsigned long format)
+{
+	unsigned long reg, f;
+
+	f = S5P_DEC_OUT_FORMAT_422;
+	if (format == S5P_JPEG_RAW_OUT_422)
+		f = S5P_DEC_OUT_FORMAT_422;
+	else if (format == S5P_JPEG_RAW_OUT_420)
+		f = S5P_DEC_OUT_FORMAT_420;
+	reg = readl(regs + S5P_JPG_OUTFORM);
+	reg &= ~S5P_DEC_OUT_FORMAT_MASK;
+	reg |= f;
+	writel(reg, regs + S5P_JPG_OUTFORM);
+}
+
+static inline void jpeg_jpgadr(void __iomem *regs, unsigned long addr)
+{
+	writel(addr, regs + S5P_JPG_JPGADR);
+}
+
+static inline void jpeg_imgadr(void __iomem *regs, unsigned long addr)
+{
+	writel(addr, regs + S5P_JPG_IMGADR);
+}
+
+static inline void jpeg_coef(void __iomem *regs, unsigned int i,
+			     unsigned int j, unsigned int coef)
+{
+	unsigned long reg;
+
+	reg = readl(regs + S5P_JPG_COEF(i));
+	reg &= ~S5P_COEFn_MASK(j);
+	reg |= (coef << S5P_COEFn_SHIFT(j)) & S5P_COEFn_MASK(j);
+	writel(reg, regs + S5P_JPG_COEF(i));
+}
+
+static inline void jpeg_start(void __iomem *regs)
+{
+	writel(1, regs + S5P_JSTART);
+}
+
+static inline int jpeg_result_stat_ok(void __iomem *regs)
+{
+	return (int)((readl(regs + S5P_JPGINTST) & S5P_RESULT_STAT_MASK)
+		     >> S5P_RESULT_STAT_SHIFT);
+}
+
+static inline int jpeg_stream_stat_ok(void __iomem *regs)
+{
+	return !(int)((readl(regs + S5P_JPGINTST) & S5P_STREAM_STAT_MASK)
+		      >> S5P_STREAM_STAT_SHIFT);
+}
+
+static inline void jpeg_clear_int(void __iomem *regs)
+{
+	unsigned long reg;
+
+	reg = readl(regs + S5P_JPGINTST);
+	writel(S5P_INT_RELEASE, regs + S5P_JPGCOM);
+	reg = readl(regs + S5P_JPGOPR);
+}
+
+static inline unsigned int jpeg_compressed_size(void __iomem *regs)
+{
+	unsigned long jpeg_size = 0;
+
+	jpeg_size |= (readl(regs + S5P_JPGCNT_U) & 0xff) << 16;
+	jpeg_size |= (readl(regs + S5P_JPGCNT_M) & 0xff) << 8;
+	jpeg_size |= (readl(regs + S5P_JPGCNT_L) & 0xff);
+
+	return (unsigned int)jpeg_size;
+}
+
+#endif /* JPEG_HW_H_ */
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-regs.h b/drivers/media/platform/s5p-jpeg/jpeg-regs.h
new file mode 100644
index 0000000..38e5081
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-regs.h
@@ -0,0 +1,170 @@
+/* linux/drivers/media/platform/s5p-jpeg/jpeg-regs.h
+ *
+ * Register definition file for Samsung JPEG codec driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef JPEG_REGS_H_
+#define JPEG_REGS_H_
+
+/* JPEG mode register */
+#define S5P_JPGMOD			0x00
+#define S5P_PROC_MODE_MASK		(0x1 << 3)
+#define S5P_PROC_MODE_DECOMPR		(0x1 << 3)
+#define S5P_PROC_MODE_COMPR		(0x0 << 3)
+#define S5P_SUBSAMPLING_MODE_MASK	0x7
+#define S5P_SUBSAMPLING_MODE_444	(0x0 << 0)
+#define S5P_SUBSAMPLING_MODE_422	(0x1 << 0)
+#define S5P_SUBSAMPLING_MODE_420	(0x2 << 0)
+#define S5P_SUBSAMPLING_MODE_GRAY	(0x3 << 0)
+
+/* JPEG operation status register */
+#define S5P_JPGOPR			0x04
+
+/* Quantization tables*/
+#define S5P_JPG_QTBL			0x08
+#define S5P_QT_NUMt_SHIFT(t)		(((t) - 1) << 1)
+#define S5P_QT_NUMt_MASK(t)		(0x3 << S5P_QT_NUMt_SHIFT(t))
+
+/* Huffman tables */
+#define S5P_JPG_HTBL			0x0c
+#define S5P_HT_NUMt_AC_SHIFT(t)		(((t) << 1) - 1)
+#define S5P_HT_NUMt_AC_MASK(t)		(0x1 << S5P_HT_NUMt_AC_SHIFT(t))
+
+#define S5P_HT_NUMt_DC_SHIFT(t)		(((t) - 1) << 1)
+#define S5P_HT_NUMt_DC_MASK(t)		(0x1 << S5P_HT_NUMt_DC_SHIFT(t))
+
+/* JPEG restart interval register upper byte */
+#define S5P_JPGDRI_U			0x10
+
+/* JPEG restart interval register lower byte */
+#define S5P_JPGDRI_L			0x14
+
+/* JPEG vertical resolution register upper byte */
+#define S5P_JPGY_U			0x18
+
+/* JPEG vertical resolution register lower byte */
+#define S5P_JPGY_L			0x1c
+
+/* JPEG horizontal resolution register upper byte */
+#define S5P_JPGX_U			0x20
+
+/* JPEG horizontal resolution register lower byte */
+#define S5P_JPGX_L			0x24
+
+/* JPEG byte count register upper byte */
+#define S5P_JPGCNT_U			0x28
+
+/* JPEG byte count register middle byte */
+#define S5P_JPGCNT_M			0x2c
+
+/* JPEG byte count register lower byte */
+#define S5P_JPGCNT_L			0x30
+
+/* JPEG interrupt setting register */
+#define S5P_JPGINTSE			0x34
+#define S5P_RSTm_INT_EN_MASK		(0x1 << 7)
+#define S5P_RSTm_INT_EN			(0x1 << 7)
+#define S5P_DATA_NUM_INT_EN_MASK	(0x1 << 6)
+#define S5P_DATA_NUM_INT_EN		(0x1 << 6)
+#define S5P_FINAL_MCU_NUM_INT_EN_MASK	(0x1 << 5)
+#define S5P_FINAL_MCU_NUM_INT_EN	(0x1 << 5)
+
+/* JPEG interrupt status register */
+#define S5P_JPGINTST			0x38
+#define S5P_RESULT_STAT_SHIFT		6
+#define S5P_RESULT_STAT_MASK		(0x1 << S5P_RESULT_STAT_SHIFT)
+#define S5P_STREAM_STAT_SHIFT		5
+#define S5P_STREAM_STAT_MASK		(0x1 << S5P_STREAM_STAT_SHIFT)
+
+/* JPEG command register */
+#define S5P_JPGCOM			0x4c
+#define S5P_INT_RELEASE			(0x1 << 2)
+
+/* Raw image data r/w address register */
+#define S5P_JPG_IMGADR			0x50
+
+/* JPEG file r/w address register */
+#define S5P_JPG_JPGADR			0x58
+
+/* Coefficient for RGB-to-YCbCr converter register */
+#define S5P_JPG_COEF(n)			(0x5c + (((n) - 1) << 2))
+#define S5P_COEFn_SHIFT(j)		((3 - (j)) << 3)
+#define S5P_COEFn_MASK(j)		(0xff << S5P_COEFn_SHIFT(j))
+
+/* JPEG color mode register */
+#define S5P_JPGCMOD			0x68
+#define S5P_MOD_SEL_MASK		(0x7 << 5)
+#define S5P_MOD_SEL_422			(0x1 << 5)
+#define S5P_MOD_SEL_565			(0x2 << 5)
+#define S5P_MODE_Y16_MASK		(0x1 << 1)
+#define S5P_MODE_Y16			(0x1 << 1)
+
+/* JPEG clock control register */
+#define S5P_JPGCLKCON			0x6c
+#define S5P_CLK_DOWN_READY		(0x1 << 1)
+#define S5P_POWER_ON			(0x1 << 0)
+
+/* JPEG start register */
+#define S5P_JSTART			0x70
+
+/* JPEG SW reset register */
+#define S5P_JPG_SW_RESET		0x78
+
+/* JPEG timer setting register */
+#define S5P_JPG_TIMER_SE		0x7c
+#define S5P_TIMER_INT_EN_MASK		(0x1 << 31)
+#define S5P_TIMER_INT_EN		(0x1 << 31)
+#define S5P_TIMER_INIT_MASK		0x7fffffff
+
+/* JPEG timer status register */
+#define S5P_JPG_TIMER_ST		0x80
+#define S5P_TIMER_INT_STAT_SHIFT	31
+#define S5P_TIMER_INT_STAT_MASK		(0x1 << S5P_TIMER_INT_STAT_SHIFT)
+#define S5P_TIMER_CNT_SHIFT		0
+#define S5P_TIMER_CNT_MASK		0x7fffffff
+
+/* JPEG decompression output format register */
+#define S5P_JPG_OUTFORM			0x88
+#define S5P_DEC_OUT_FORMAT_MASK		(0x1 << 0)
+#define S5P_DEC_OUT_FORMAT_422		(0x0 << 0)
+#define S5P_DEC_OUT_FORMAT_420		(0x1 << 0)
+
+/* JPEG version register */
+#define S5P_JPG_VERSION			0x8c
+
+/* JPEG compressed stream size interrupt setting register */
+#define S5P_JPG_ENC_STREAM_INTSE	0x98
+#define S5P_ENC_STREAM_INT_MASK		(0x1 << 24)
+#define S5P_ENC_STREAM_INT_EN		(0x1 << 24)
+#define S5P_ENC_STREAM_BOUND_MASK	0xffffff
+
+/* JPEG compressed stream size interrupt status register */
+#define S5P_JPG_ENC_STREAM_INTST	0x9c
+#define S5P_ENC_STREAM_INT_STAT_MASK	0x1
+
+/* JPEG quantizer table register */
+#define S5P_JPG_QTBL_CONTENT(n)		(0x400 + (n) * 0x100)
+
+/* JPEG DC Huffman table register */
+#define S5P_JPG_HDCTBL(n)		(0x800 + (n) * 0x400)
+
+/* JPEG DC Huffman table register */
+#define S5P_JPG_HDCTBLG(n)		(0x840 + (n) * 0x400)
+
+/* JPEG AC Huffman table register */
+#define S5P_JPG_HACTBL(n)		(0x880 + (n) * 0x400)
+
+/* JPEG AC Huffman table register */
+#define S5P_JPG_HACTBLG(n)		(0x8c0 + (n) * 0x400)
+
+#endif /* JPEG_REGS_H_ */
+
diff --git a/drivers/media/platform/s5p-mfc/Makefile b/drivers/media/platform/s5p-mfc/Makefile
new file mode 100644
index 0000000..d066340
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) := s5p-mfc.o
+s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p_mfc_opr.o
+s5p-mfc-y += s5p_mfc_dec.o s5p_mfc_enc.o
+s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_cmd.o
+s5p-mfc-y += s5p_mfc_pm.o s5p_mfc_shm.o
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc.h b/drivers/media/platform/s5p-mfc/regs-mfc.h
new file mode 100644
index 0000000..a19bece
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/regs-mfc.h
@@ -0,0 +1,418 @@
+/*
+ * Register definition file for Samsung MFC V5.1 Interface (FIMV) driver
+ *
+ * Kamil Debski, Copyright (c) 2010 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef _REGS_FIMV_H
+#define _REGS_FIMV_H
+
+#define S5P_FIMV_REG_SIZE	(S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR)
+#define S5P_FIMV_REG_COUNT	((S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) / 4)
+
+/* Number of bits that the buffer address should be shifted for particular
+ * MFC buffers.  */
+#define S5P_FIMV_START_ADDR		0x0000
+#define S5P_FIMV_END_ADDR		0xe008
+
+#define S5P_FIMV_SW_RESET		0x0000
+#define S5P_FIMV_RISC_HOST_INT		0x0008
+
+/* Command from HOST to RISC */
+#define S5P_FIMV_HOST2RISC_CMD		0x0030
+#define S5P_FIMV_HOST2RISC_ARG1		0x0034
+#define S5P_FIMV_HOST2RISC_ARG2		0x0038
+#define S5P_FIMV_HOST2RISC_ARG3		0x003c
+#define S5P_FIMV_HOST2RISC_ARG4		0x0040
+
+/* Command from RISC to HOST */
+#define S5P_FIMV_RISC2HOST_CMD		0x0044
+#define S5P_FIMV_RISC2HOST_CMD_MASK	0x1FFFF
+#define S5P_FIMV_RISC2HOST_ARG1		0x0048
+#define S5P_FIMV_RISC2HOST_ARG2		0x004c
+#define S5P_FIMV_RISC2HOST_ARG3		0x0050
+#define S5P_FIMV_RISC2HOST_ARG4		0x0054
+
+#define S5P_FIMV_FW_VERSION		0x0058
+#define S5P_FIMV_SYS_MEM_SZ		0x005c
+#define S5P_FIMV_FW_STATUS		0x0080
+
+/* Memory controller register */
+#define S5P_FIMV_MC_DRAMBASE_ADR_A	0x0508
+#define S5P_FIMV_MC_DRAMBASE_ADR_B	0x050c
+#define S5P_FIMV_MC_STATUS		0x0510
+
+/* Common register */
+#define S5P_FIMV_COMMON_BASE_A		0x0600
+#define S5P_FIMV_COMMON_BASE_B		0x0700
+
+/* Decoder */
+#define S5P_FIMV_DEC_CHROMA_ADR		(S5P_FIMV_COMMON_BASE_A)
+#define S5P_FIMV_DEC_LUMA_ADR		(S5P_FIMV_COMMON_BASE_B)
+
+/* H.264 decoding */
+#define S5P_FIMV_H264_VERT_NB_MV_ADR	(S5P_FIMV_COMMON_BASE_A + 0x8c)
+					/* vertical neighbor motion vector */
+#define S5P_FIMV_H264_NB_IP_ADR		(S5P_FIMV_COMMON_BASE_A + 0x90)
+					/* neighbor pixels for intra pred */
+#define S5P_FIMV_H264_MV_ADR		(S5P_FIMV_COMMON_BASE_B + 0x80)
+					/* H264 motion vector */
+
+/* MPEG4 decoding */
+#define S5P_FIMV_MPEG4_NB_DCAC_ADR	(S5P_FIMV_COMMON_BASE_A + 0x8c)
+					/* neighbor AC/DC coeff. */
+#define S5P_FIMV_MPEG4_UP_NB_MV_ADR	(S5P_FIMV_COMMON_BASE_A + 0x90)
+					/* upper neighbor motion vector */
+#define S5P_FIMV_MPEG4_SA_MV_ADR	(S5P_FIMV_COMMON_BASE_A + 0x94)
+					/* subseq. anchor motion vector */
+#define S5P_FIMV_MPEG4_OT_LINE_ADR	(S5P_FIMV_COMMON_BASE_A + 0x98)
+					/* overlap transform line */
+#define S5P_FIMV_MPEG4_SP_ADR		(S5P_FIMV_COMMON_BASE_A + 0xa8)
+					/* syntax parser */
+
+/* H.263 decoding */
+#define S5P_FIMV_H263_NB_DCAC_ADR	(S5P_FIMV_COMMON_BASE_A + 0x8c)
+#define S5P_FIMV_H263_UP_NB_MV_ADR	(S5P_FIMV_COMMON_BASE_A + 0x90)
+#define S5P_FIMV_H263_SA_MV_ADR		(S5P_FIMV_COMMON_BASE_A + 0x94)
+#define S5P_FIMV_H263_OT_LINE_ADR	(S5P_FIMV_COMMON_BASE_A + 0x98)
+
+/* VC-1 decoding */
+#define S5P_FIMV_VC1_NB_DCAC_ADR	(S5P_FIMV_COMMON_BASE_A + 0x8c)
+#define S5P_FIMV_VC1_UP_NB_MV_ADR	(S5P_FIMV_COMMON_BASE_A + 0x90)
+#define S5P_FIMV_VC1_SA_MV_ADR		(S5P_FIMV_COMMON_BASE_A + 0x94)
+#define S5P_FIMV_VC1_OT_LINE_ADR	(S5P_FIMV_COMMON_BASE_A + 0x98)
+#define S5P_FIMV_VC1_BITPLANE3_ADR	(S5P_FIMV_COMMON_BASE_A + 0x9c)
+					/* bitplane3 */
+#define S5P_FIMV_VC1_BITPLANE2_ADR	(S5P_FIMV_COMMON_BASE_A + 0xa0)
+					/* bitplane2 */
+#define S5P_FIMV_VC1_BITPLANE1_ADR	(S5P_FIMV_COMMON_BASE_A + 0xa4)
+					/* bitplane1 */
+
+/* Encoder */
+#define S5P_FIMV_ENC_REF0_LUMA_ADR	(S5P_FIMV_COMMON_BASE_A + 0x1c)
+#define S5P_FIMV_ENC_REF1_LUMA_ADR	(S5P_FIMV_COMMON_BASE_A + 0x20)
+					/* reconstructed luma */
+#define S5P_FIMV_ENC_REF0_CHROMA_ADR	(S5P_FIMV_COMMON_BASE_B)
+#define S5P_FIMV_ENC_REF1_CHROMA_ADR	(S5P_FIMV_COMMON_BASE_B + 0x04)
+					/* reconstructed chroma */
+#define S5P_FIMV_ENC_REF2_LUMA_ADR	(S5P_FIMV_COMMON_BASE_B + 0x10)
+#define S5P_FIMV_ENC_REF2_CHROMA_ADR	(S5P_FIMV_COMMON_BASE_B + 0x08)
+#define S5P_FIMV_ENC_REF3_LUMA_ADR	(S5P_FIMV_COMMON_BASE_B + 0x14)
+#define S5P_FIMV_ENC_REF3_CHROMA_ADR	(S5P_FIMV_COMMON_BASE_B + 0x0c)
+
+/* H.264 encoding */
+#define S5P_FIMV_H264_UP_MV_ADR		(S5P_FIMV_COMMON_BASE_A)
+					/* upper motion vector */
+#define S5P_FIMV_H264_NBOR_INFO_ADR	(S5P_FIMV_COMMON_BASE_A + 0x04)
+					/* entropy engine's neighbor info. */
+#define S5P_FIMV_H264_UP_INTRA_MD_ADR	(S5P_FIMV_COMMON_BASE_A + 0x08)
+					/* upper intra MD */
+#define S5P_FIMV_H264_COZERO_FLAG_ADR	(S5P_FIMV_COMMON_BASE_A + 0x10)
+					/* direct cozero flag */
+#define S5P_FIMV_H264_UP_INTRA_PRED_ADR	(S5P_FIMV_COMMON_BASE_B + 0x40)
+					/* upper intra PRED */
+
+/* H.263 encoding */
+#define S5P_FIMV_H263_UP_MV_ADR		(S5P_FIMV_COMMON_BASE_A)
+					/* upper motion vector */
+#define S5P_FIMV_H263_ACDC_COEF_ADR	(S5P_FIMV_COMMON_BASE_A + 0x04)
+					/* upper Q coeff. */
+
+/* MPEG4 encoding */
+#define S5P_FIMV_MPEG4_UP_MV_ADR	(S5P_FIMV_COMMON_BASE_A)
+					/* upper motion vector */
+#define S5P_FIMV_MPEG4_ACDC_COEF_ADR	(S5P_FIMV_COMMON_BASE_A + 0x04)
+					/* upper Q coeff. */
+#define S5P_FIMV_MPEG4_COZERO_FLAG_ADR	(S5P_FIMV_COMMON_BASE_A + 0x10)
+					/* direct cozero flag */
+
+#define S5P_FIMV_ENC_REF_B_LUMA_ADR     0x062c /* ref B Luma addr */
+#define S5P_FIMV_ENC_REF_B_CHROMA_ADR   0x0630 /* ref B Chroma addr */
+
+#define S5P_FIMV_ENC_CUR_LUMA_ADR	0x0718 /* current Luma addr */
+#define S5P_FIMV_ENC_CUR_CHROMA_ADR	0x071C /* current Chroma addr */
+
+/* Codec common register */
+#define S5P_FIMV_ENC_HSIZE_PX		0x0818 /* frame width at encoder */
+#define S5P_FIMV_ENC_VSIZE_PX		0x081c /* frame height at encoder */
+#define S5P_FIMV_ENC_PROFILE		0x0830 /* profile register */
+#define S5P_FIMV_ENC_PROFILE_H264_MAIN			0
+#define S5P_FIMV_ENC_PROFILE_H264_HIGH			1
+#define S5P_FIMV_ENC_PROFILE_H264_BASELINE		2
+#define S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE		0
+#define S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE	1
+#define S5P_FIMV_ENC_PIC_STRUCT		0x083c /* picture field/frame flag */
+#define S5P_FIMV_ENC_LF_CTRL		0x0848 /* loop filter control */
+#define S5P_FIMV_ENC_ALPHA_OFF		0x084c /* loop filter alpha offset */
+#define S5P_FIMV_ENC_BETA_OFF		0x0850 /* loop filter beta offset */
+#define S5P_FIMV_MR_BUSIF_CTRL		0x0854 /* hidden, bus interface ctrl */
+#define S5P_FIMV_ENC_PXL_CACHE_CTRL	0x0a00 /* pixel cache control */
+
+/* Channel & stream interface register */
+#define S5P_FIMV_SI_RTN_CHID		0x2000 /* Return CH inst ID register */
+#define S5P_FIMV_SI_CH0_INST_ID		0x2040 /* codec instance ID */
+#define S5P_FIMV_SI_CH1_INST_ID		0x2080 /* codec instance ID */
+/* Decoder */
+#define S5P_FIMV_SI_VRESOL		0x2004 /* vertical res of decoder */
+#define S5P_FIMV_SI_HRESOL		0x2008 /* horizontal res of decoder */
+#define S5P_FIMV_SI_BUF_NUMBER		0x200c /* number of frames in the
+								decoded pic */
+#define S5P_FIMV_SI_DISPLAY_Y_ADR	0x2010 /* luma addr of displayed pic */
+#define S5P_FIMV_SI_DISPLAY_C_ADR	0x2014 /* chroma addrof displayed pic */
+
+#define S5P_FIMV_SI_CONSUMED_BYTES	0x2018 /* Consumed number of bytes to
+							decode a frame */
+#define S5P_FIMV_SI_DISPLAY_STATUS	0x201c /* status of decoded picture */
+
+#define S5P_FIMV_SI_DECODE_Y_ADR	0x2024 /* luma addr of decoded pic */
+#define S5P_FIMV_SI_DECODE_C_ADR	0x2028 /* chroma addrof decoded pic */
+#define S5P_FIMV_SI_DECODE_STATUS	0x202c /* status of decoded picture */
+
+#define S5P_FIMV_SI_CH0_SB_ST_ADR	0x2044 /* start addr of stream buf */
+#define S5P_FIMV_SI_CH0_SB_FRM_SIZE	0x2048 /* size of stream buf */
+#define S5P_FIMV_SI_CH0_DESC_ADR	0x204c /* addr of descriptor buf */
+#define S5P_FIMV_SI_CH0_CPB_SIZE	0x2058 /* max size of coded pic. buf */
+#define S5P_FIMV_SI_CH0_DESC_SIZE	0x205c /* max size of descriptor buf */
+
+#define S5P_FIMV_SI_CH1_SB_ST_ADR	0x2084 /* start addr of stream buf */
+#define S5P_FIMV_SI_CH1_SB_FRM_SIZE	0x2088 /* size of stream buf */
+#define S5P_FIMV_SI_CH1_DESC_ADR	0x208c /* addr of descriptor buf */
+#define S5P_FIMV_SI_CH1_CPB_SIZE	0x2098 /* max size of coded pic. buf */
+#define S5P_FIMV_SI_CH1_DESC_SIZE	0x209c /* max size of descriptor buf */
+
+#define S5P_FIMV_CRC_LUMA0		0x2030 /* luma crc data per frame
+								(top field) */
+#define S5P_FIMV_CRC_CHROMA0		0x2034 /* chroma crc data per frame
+								(top field) */
+#define S5P_FIMV_CRC_LUMA1		0x2038 /* luma crc data per bottom
+								field */
+#define S5P_FIMV_CRC_CHROMA1		0x203c /* chroma crc data per bottom
+								field */
+
+/* Display status */
+#define S5P_FIMV_DEC_STATUS_DECODING_ONLY		0
+#define S5P_FIMV_DEC_STATUS_DECODING_DISPLAY		1
+#define S5P_FIMV_DEC_STATUS_DISPLAY_ONLY		2
+#define S5P_FIMV_DEC_STATUS_DECODING_EMPTY		3
+#define S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK	7
+#define S5P_FIMV_DEC_STATUS_PROGRESSIVE			(0<<3)
+#define S5P_FIMV_DEC_STATUS_INTERLACE			(1<<3)
+#define S5P_FIMV_DEC_STATUS_INTERLACE_MASK		(1<<3)
+#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_TWO		(0<<4)
+#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_FOUR		(1<<4)
+#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_MASK		(1<<4)
+#define S5P_FIMV_DEC_STATUS_CRC_GENERATED		(1<<5)
+#define S5P_FIMV_DEC_STATUS_CRC_NOT_GENERATED		(0<<5)
+#define S5P_FIMV_DEC_STATUS_CRC_MASK			(1<<5)
+
+#define S5P_FIMV_DEC_STATUS_RESOLUTION_MASK		(3<<4)
+#define S5P_FIMV_DEC_STATUS_RESOLUTION_INC		(1<<4)
+#define S5P_FIMV_DEC_STATUS_RESOLUTION_DEC		(2<<4)
+
+/* Decode frame address */
+#define S5P_FIMV_DECODE_Y_ADR			0x2024
+#define S5P_FIMV_DECODE_C_ADR			0x2028
+
+/* Decoded frame tpe */
+#define S5P_FIMV_DECODE_FRAME_TYPE		0x2020
+#define S5P_FIMV_DECODE_FRAME_MASK		7
+
+#define S5P_FIMV_DECODE_FRAME_SKIPPED		0
+#define S5P_FIMV_DECODE_FRAME_I_FRAME		1
+#define S5P_FIMV_DECODE_FRAME_P_FRAME		2
+#define S5P_FIMV_DECODE_FRAME_B_FRAME		3
+#define S5P_FIMV_DECODE_FRAME_OTHER_FRAME	4
+
+/* Sizes of buffers required for decoding */
+#define S5P_FIMV_DEC_NB_IP_SIZE			(32 * 1024)
+#define S5P_FIMV_DEC_VERT_NB_MV_SIZE		(16 * 1024)
+#define S5P_FIMV_DEC_NB_DCAC_SIZE		(16 * 1024)
+#define S5P_FIMV_DEC_UPNB_MV_SIZE		(68 * 1024)
+#define S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE		(136 * 1024)
+#define S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE     (32 * 1024)
+#define S5P_FIMV_DEC_VC1_BITPLANE_SIZE		(2 * 1024)
+#define S5P_FIMV_DEC_STX_PARSER_SIZE		(68 * 1024)
+
+#define S5P_FIMV_DEC_BUF_ALIGN			(8 * 1024)
+#define S5P_FIMV_ENC_BUF_ALIGN			(8 * 1024)
+#define S5P_FIMV_NV12M_HALIGN			16
+#define S5P_FIMV_NV12M_LVALIGN			16
+#define S5P_FIMV_NV12M_CVALIGN			8
+#define S5P_FIMV_NV12MT_HALIGN			128
+#define S5P_FIMV_NV12MT_VALIGN			32
+#define S5P_FIMV_NV12M_SALIGN			2048
+#define S5P_FIMV_NV12MT_SALIGN			8192
+
+/* Sizes of buffers required for encoding */
+#define S5P_FIMV_ENC_UPMV_SIZE		0x10000
+#define S5P_FIMV_ENC_COLFLG_SIZE	0x10000
+#define S5P_FIMV_ENC_INTRAMD_SIZE	0x10000
+#define S5P_FIMV_ENC_INTRAPRED_SIZE	0x4000
+#define S5P_FIMV_ENC_NBORINFO_SIZE	0x10000
+#define S5P_FIMV_ENC_ACDCCOEF_SIZE	0x10000
+
+/* Encoder */
+#define S5P_FIMV_ENC_SI_STRM_SIZE	0x2004 /* stream size */
+#define S5P_FIMV_ENC_SI_PIC_CNT		0x2008 /* picture count */
+#define S5P_FIMV_ENC_SI_WRITE_PTR	0x200c /* write pointer */
+#define S5P_FIMV_ENC_SI_SLICE_TYPE	0x2010 /* slice type(I/P/B/IDR) */
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_NON_CODED	0
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_I		1
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_P		2
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_B		3
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_SKIPPED	4
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_OTHERS	5
+#define S5P_FIMV_ENCODED_Y_ADDR         0x2014 /* the addr of the encoded
+								luma pic */
+#define S5P_FIMV_ENCODED_C_ADDR         0x2018 /* the addr of the encoded
+								chroma pic */
+
+#define S5P_FIMV_ENC_SI_CH0_SB_ADR	0x2044 /* addr of stream buf */
+#define S5P_FIMV_ENC_SI_CH0_SB_SIZE	0x204c /* size of stream buf */
+#define S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR	0x2050 /* current Luma addr */
+#define S5P_FIMV_ENC_SI_CH0_CUR_C_ADR	0x2054 /* current Chroma addr */
+#define S5P_FIMV_ENC_SI_CH0_FRAME_INS	0x2058 /* frame insertion */
+
+#define S5P_FIMV_ENC_SI_CH1_SB_ADR	0x2084 /* addr of stream buf */
+#define S5P_FIMV_ENC_SI_CH1_SB_SIZE	0x208c /* size of stream buf */
+#define S5P_FIMV_ENC_SI_CH1_CUR_Y_ADR	0x2090 /* current Luma addr */
+#define S5P_FIMV_ENC_SI_CH1_CUR_C_ADR	0x2094 /* current Chroma addr */
+#define S5P_FIMV_ENC_SI_CH1_FRAME_INS	0x2098 /* frame insertion */
+
+#define S5P_FIMV_ENC_PIC_TYPE_CTRL	0xc504 /* pic type level control */
+#define S5P_FIMV_ENC_B_RECON_WRITE_ON	0xc508 /* B frame recon write ctrl */
+#define S5P_FIMV_ENC_MSLICE_CTRL	0xc50c /* multi slice control */
+#define S5P_FIMV_ENC_MSLICE_MB		0xc510 /* MB number in the one slice */
+#define S5P_FIMV_ENC_MSLICE_BIT		0xc514 /* bit count for one slice */
+#define S5P_FIMV_ENC_CIR_CTRL		0xc518 /* number of intra refresh MB */
+#define S5P_FIMV_ENC_MAP_FOR_CUR	0xc51c /* linear or tiled mode */
+#define S5P_FIMV_ENC_PADDING_CTRL	0xc520 /* padding control */
+
+#define S5P_FIMV_ENC_RC_CONFIG		0xc5a0 /* RC config */
+#define S5P_FIMV_ENC_RC_BIT_RATE	0xc5a8 /* bit rate */
+#define S5P_FIMV_ENC_RC_QBOUND		0xc5ac /* max/min QP */
+#define S5P_FIMV_ENC_RC_RPARA		0xc5b0 /* rate control reaction coeff */
+#define S5P_FIMV_ENC_RC_MB_CTRL		0xc5b4 /* MB adaptive scaling */
+
+/* Encoder for H264 only */
+#define S5P_FIMV_ENC_H264_ENTROPY_MODE	0xd004 /* CAVLC or CABAC */
+#define S5P_FIMV_ENC_H264_ALPHA_OFF	0xd008 /* loop filter alpha offset */
+#define S5P_FIMV_ENC_H264_BETA_OFF	0xd00c /* loop filter beta offset */
+#define S5P_FIMV_ENC_H264_NUM_OF_REF	0xd010 /* number of reference for P/B */
+#define S5P_FIMV_ENC_H264_TRANS_FLAG	0xd034 /* 8x8 transform flag in PPS &
+								high profile */
+
+#define S5P_FIMV_ENC_RC_FRAME_RATE	0xd0d0 /* frame rate */
+
+/* Encoder for MPEG4 only */
+#define S5P_FIMV_ENC_MPEG4_QUART_PXL	0xe008 /* qpel interpolation ctrl */
+
+/* Additional */
+#define S5P_FIMV_SI_CH0_DPB_CONF_CTRL   0x2068 /* DPB Config Control Register */
+#define S5P_FIMV_SLICE_INT_MASK		1
+#define S5P_FIMV_SLICE_INT_SHIFT	31
+#define S5P_FIMV_DDELAY_ENA_SHIFT	30
+#define S5P_FIMV_DDELAY_VAL_MASK	0xff
+#define S5P_FIMV_DDELAY_VAL_SHIFT	16
+#define S5P_FIMV_DPB_COUNT_MASK		0xffff
+#define S5P_FIMV_DPB_FLUSH_MASK		1
+#define S5P_FIMV_DPB_FLUSH_SHIFT	14
+
+
+#define S5P_FIMV_SI_CH0_RELEASE_BUF     0x2060 /* DPB release buffer register */
+#define S5P_FIMV_SI_CH0_HOST_WR_ADR	0x2064 /* address of shared memory */
+
+/* Codec numbers  */
+#define S5P_FIMV_CODEC_NONE		-1
+
+#define S5P_FIMV_CODEC_H264_DEC		0
+#define S5P_FIMV_CODEC_VC1_DEC		1
+#define S5P_FIMV_CODEC_MPEG4_DEC	2
+#define S5P_FIMV_CODEC_MPEG2_DEC	3
+#define S5P_FIMV_CODEC_H263_DEC		4
+#define S5P_FIMV_CODEC_VC1RCV_DEC	5
+
+#define S5P_FIMV_CODEC_H264_ENC		16
+#define S5P_FIMV_CODEC_MPEG4_ENC	17
+#define S5P_FIMV_CODEC_H263_ENC		18
+
+/* Channel Control Register */
+#define S5P_FIMV_CH_SEQ_HEADER		1
+#define S5P_FIMV_CH_FRAME_START		2
+#define S5P_FIMV_CH_LAST_FRAME		3
+#define S5P_FIMV_CH_INIT_BUFS		4
+#define S5P_FIMV_CH_FRAME_START_REALLOC	5
+#define S5P_FIMV_CH_MASK		7
+#define S5P_FIMV_CH_SHIFT		16
+
+
+/* Host to RISC command */
+#define S5P_FIMV_H2R_CMD_EMPTY		0
+#define S5P_FIMV_H2R_CMD_OPEN_INSTANCE	1
+#define S5P_FIMV_H2R_CMD_CLOSE_INSTANCE	2
+#define S5P_FIMV_H2R_CMD_SYS_INIT	3
+#define S5P_FIMV_H2R_CMD_FLUSH		4
+#define S5P_FIMV_H2R_CMD_SLEEP		5
+#define S5P_FIMV_H2R_CMD_WAKEUP		6
+
+#define S5P_FIMV_R2H_CMD_EMPTY			0
+#define S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET	1
+#define S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET	2
+#define S5P_FIMV_R2H_CMD_RSV_RET		3
+#define S5P_FIMV_R2H_CMD_SEQ_DONE_RET		4
+#define S5P_FIMV_R2H_CMD_FRAME_DONE_RET		5
+#define S5P_FIMV_R2H_CMD_SLICE_DONE_RET		6
+#define S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET	7
+#define S5P_FIMV_R2H_CMD_SYS_INIT_RET		8
+#define S5P_FIMV_R2H_CMD_FW_STATUS_RET		9
+#define S5P_FIMV_R2H_CMD_SLEEP_RET		10
+#define S5P_FIMV_R2H_CMD_WAKEUP_RET		11
+#define S5P_FIMV_R2H_CMD_FLUSH_RET		12
+#define S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET	15
+#define S5P_FIMV_R2H_CMD_EDFU_INIT_RET		16
+#define S5P_FIMV_R2H_CMD_ERR_RET		32
+
+/* Error handling defines */
+#define S5P_FIMV_ERR_WARNINGS_START		145
+#define S5P_FIMV_ERR_DEC_MASK			0xFFFF
+#define S5P_FIMV_ERR_DEC_SHIFT			0
+#define S5P_FIMV_ERR_DSPL_MASK			0xFFFF0000
+#define S5P_FIMV_ERR_DSPL_SHIFT			16
+
+/* Shared memory registers' offsets */
+
+/* An offset of the start position in the stream when
+ * the start position is not aligned */
+#define S5P_FIMV_SHARED_CROP_INFO_H		0x0020
+#define S5P_FIMV_SHARED_CROP_LEFT_MASK		0xFFFF
+#define S5P_FIMV_SHARED_CROP_LEFT_SHIFT		0
+#define S5P_FIMV_SHARED_CROP_RIGHT_MASK		0xFFFF0000
+#define S5P_FIMV_SHARED_CROP_RIGHT_SHIFT	16
+#define S5P_FIMV_SHARED_CROP_INFO_V		0x0024
+#define S5P_FIMV_SHARED_CROP_TOP_MASK		0xFFFF
+#define S5P_FIMV_SHARED_CROP_TOP_SHIFT		0
+#define S5P_FIMV_SHARED_CROP_BOTTOM_MASK	0xFFFF0000
+#define S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT	16
+#define S5P_FIMV_SHARED_SET_FRAME_TAG		0x0004
+#define S5P_FIMV_SHARED_GET_FRAME_TAG_TOP	0x0008
+#define S5P_FIMV_SHARED_GET_FRAME_TAG_BOT	0x000C
+#define S5P_FIMV_SHARED_START_BYTE_NUM		0x0018
+#define S5P_FIMV_SHARED_RC_VOP_TIMING		0x0030
+#define S5P_FIMV_SHARED_LUMA_DPB_SIZE		0x0064
+#define S5P_FIMV_SHARED_CHROMA_DPB_SIZE		0x0068
+#define S5P_FIMV_SHARED_MV_SIZE			0x006C
+#define S5P_FIMV_SHARED_PIC_TIME_TOP		0x0010
+#define S5P_FIMV_SHARED_PIC_TIME_BOTTOM		0x0014
+#define S5P_FIMV_SHARED_EXT_ENC_CONTROL		0x0028
+#define S5P_FIMV_SHARED_P_B_FRAME_QP		0x0070
+#define S5P_FIMV_SHARED_ASPECT_RATIO_IDC	0x0074
+#define S5P_FIMV_SHARED_EXTENDED_SAR		0x0078
+#define S5P_FIMV_SHARED_H264_I_PERIOD		0x009C
+#define S5P_FIMV_SHARED_RC_CONTROL_CONFIG	0x00A0
+
+#endif /* _REGS_FIMV_H */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
new file mode 100644
index 0000000..e3e616d
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -0,0 +1,1230 @@
+/*
+ * Samsung S5P Multi Format Codec v 5.1
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <media/videobuf2-core.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_ctrl.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_dec.h"
+#include "s5p_mfc_enc.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_opr.h"
+#include "s5p_mfc_pm.h"
+#include "s5p_mfc_shm.h"
+
+#define S5P_MFC_NAME		"s5p-mfc"
+#define S5P_MFC_DEC_NAME	"s5p-mfc-dec"
+#define S5P_MFC_ENC_NAME	"s5p-mfc-enc"
+
+int debug;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages");
+
+/* Helper functions for interrupt processing */
+/* Remove from hw execution round robin */
+static void clear_work_bit(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	spin_lock(&dev->condlock);
+	clear_bit(ctx->num, &dev->ctx_work_bits);
+	spin_unlock(&dev->condlock);
+}
+
+/* Wake up context wait_queue */
+static void wake_up_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason,
+			unsigned int err)
+{
+	ctx->int_cond = 1;
+	ctx->int_type = reason;
+	ctx->int_err = err;
+	wake_up(&ctx->queue);
+}
+
+/* Wake up device wait_queue */
+static void wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason,
+			unsigned int err)
+{
+	dev->int_cond = 1;
+	dev->int_type = reason;
+	dev->int_err = err;
+	wake_up(&dev->queue);
+}
+
+static void s5p_mfc_watchdog(unsigned long arg)
+{
+	struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)arg;
+
+	if (test_bit(0, &dev->hw_lock))
+		atomic_inc(&dev->watchdog_cnt);
+	if (atomic_read(&dev->watchdog_cnt) >= MFC_WATCHDOG_CNT) {
+		/* This means that hw is busy and no interrupts were
+		 * generated by hw for the Nth time of running this
+		 * watchdog timer. This usually means a serious hw
+		 * error. Now it is time to kill all instances and
+		 * reset the MFC. */
+		mfc_err("Time out during waiting for HW\n");
+		queue_work(dev->watchdog_workqueue, &dev->watchdog_work);
+	}
+	dev->watchdog_timer.expires = jiffies +
+					msecs_to_jiffies(MFC_WATCHDOG_INTERVAL);
+	add_timer(&dev->watchdog_timer);
+}
+
+static void s5p_mfc_watchdog_worker(struct work_struct *work)
+{
+	struct s5p_mfc_dev *dev;
+	struct s5p_mfc_ctx *ctx;
+	unsigned long flags;
+	int mutex_locked;
+	int i, ret;
+
+	dev = container_of(work, struct s5p_mfc_dev, watchdog_work);
+
+	mfc_err("Driver timeout error handling\n");
+	/* Lock the mutex that protects open and release.
+	 * This is necessary as they may load and unload firmware. */
+	mutex_locked = mutex_trylock(&dev->mfc_mutex);
+	if (!mutex_locked)
+		mfc_err("Error: some instance may be closing/opening\n");
+	spin_lock_irqsave(&dev->irqlock, flags);
+
+	s5p_mfc_clock_off();
+
+	for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
+		ctx = dev->ctx[i];
+		if (!ctx)
+			continue;
+		ctx->state = MFCINST_ERROR;
+		s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+		s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+		clear_work_bit(ctx);
+		wake_up_ctx(ctx, S5P_FIMV_R2H_CMD_ERR_RET, 0);
+	}
+	clear_bit(0, &dev->hw_lock);
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+	/* Double check if there is at least one instance running.
+	 * If no instance is in memory than no firmware should be present */
+	if (dev->num_inst > 0) {
+		ret = s5p_mfc_reload_firmware(dev);
+		if (ret) {
+			mfc_err("Failed to reload FW\n");
+			goto unlock;
+		}
+		s5p_mfc_clock_on();
+		ret = s5p_mfc_init_hw(dev);
+		if (ret)
+			mfc_err("Failed to reinit FW\n");
+	}
+unlock:
+	if (mutex_locked)
+		mutex_unlock(&dev->mfc_mutex);
+}
+
+static enum s5p_mfc_node_type s5p_mfc_get_node_type(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (!vdev) {
+		mfc_err("failed to get video_device");
+		return MFCNODE_INVALID;
+	}
+	if (vdev->index == 0)
+		return MFCNODE_DECODER;
+	else if (vdev->index == 1)
+		return MFCNODE_ENCODER;
+	return MFCNODE_INVALID;
+}
+
+static void s5p_mfc_clear_int_flags(struct s5p_mfc_dev *dev)
+{
+	mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT);
+	mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD);
+	mfc_write(dev, 0xffff, S5P_FIMV_SI_RTN_CHID);
+}
+
+static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_buf *dst_buf;
+
+	ctx->state = MFCINST_FINISHED;
+	ctx->sequence++;
+	while (!list_empty(&ctx->dst_queue)) {
+		dst_buf = list_entry(ctx->dst_queue.next,
+				     struct s5p_mfc_buf, list);
+		mfc_debug(2, "Cleaning up buffer: %d\n",
+					  dst_buf->b->v4l2_buf.index);
+		vb2_set_plane_payload(dst_buf->b, 0, 0);
+		vb2_set_plane_payload(dst_buf->b, 1, 0);
+		list_del(&dst_buf->list);
+		ctx->dst_queue_cnt--;
+		dst_buf->b->v4l2_buf.sequence = (ctx->sequence++);
+
+		if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) ==
+			s5p_mfc_read_shm(ctx, PIC_TIME_BOT))
+			dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE;
+		else
+			dst_buf->b->v4l2_buf.field = V4L2_FIELD_INTERLACED;
+
+		ctx->dec_dst_flag &= ~(1 << dst_buf->b->v4l2_buf.index);
+		vb2_buffer_done(dst_buf->b, VB2_BUF_STATE_DONE);
+	}
+}
+
+static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	struct s5p_mfc_buf  *dst_buf, *src_buf;
+	size_t dec_y_addr = s5p_mfc_get_dec_y_adr();
+	unsigned int frame_type = s5p_mfc_get_frame_type();
+
+	/* Copy timestamp / timecode from decoded src to dst and set
+	   appropraite flags */
+	src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+	list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
+		if (vb2_dma_contig_plane_dma_addr(dst_buf->b, 0) == dec_y_addr) {
+			memcpy(&dst_buf->b->v4l2_buf.timecode,
+				&src_buf->b->v4l2_buf.timecode,
+				sizeof(struct v4l2_timecode));
+			memcpy(&dst_buf->b->v4l2_buf.timestamp,
+				&src_buf->b->v4l2_buf.timestamp,
+				sizeof(struct timeval));
+			switch (frame_type) {
+			case S5P_FIMV_DECODE_FRAME_I_FRAME:
+				dst_buf->b->v4l2_buf.flags |=
+						V4L2_BUF_FLAG_KEYFRAME;
+				break;
+			case S5P_FIMV_DECODE_FRAME_P_FRAME:
+				dst_buf->b->v4l2_buf.flags |=
+						V4L2_BUF_FLAG_PFRAME;
+				break;
+			case S5P_FIMV_DECODE_FRAME_B_FRAME:
+				dst_buf->b->v4l2_buf.flags |=
+						V4L2_BUF_FLAG_BFRAME;
+				break;
+			}
+			break;
+		}
+	}
+}
+
+static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	struct s5p_mfc_buf  *dst_buf;
+	size_t dspl_y_addr = s5p_mfc_get_dspl_y_adr();
+	unsigned int frame_type = s5p_mfc_get_frame_type();
+	unsigned int index;
+
+	/* If frame is same as previous then skip and do not dequeue */
+	if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) {
+		if (!ctx->after_packed_pb)
+			ctx->sequence++;
+		ctx->after_packed_pb = 0;
+		return;
+	}
+	ctx->sequence++;
+	/* The MFC returns address of the buffer, now we have to
+	 * check which videobuf does it correspond to */
+	list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
+		/* Check if this is the buffer we're looking for */
+		if (vb2_dma_contig_plane_dma_addr(dst_buf->b, 0) == dspl_y_addr) {
+			list_del(&dst_buf->list);
+			ctx->dst_queue_cnt--;
+			dst_buf->b->v4l2_buf.sequence = ctx->sequence;
+			if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) ==
+				s5p_mfc_read_shm(ctx, PIC_TIME_BOT))
+				dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE;
+			else
+				dst_buf->b->v4l2_buf.field =
+							V4L2_FIELD_INTERLACED;
+			vb2_set_plane_payload(dst_buf->b, 0, ctx->luma_size);
+			vb2_set_plane_payload(dst_buf->b, 1, ctx->chroma_size);
+			clear_bit(dst_buf->b->v4l2_buf.index,
+							&ctx->dec_dst_flag);
+
+			vb2_buffer_done(dst_buf->b,
+				err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+
+			index = dst_buf->b->v4l2_buf.index;
+			break;
+		}
+	}
+}
+
+/* Handle frame decoding interrupt */
+static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
+					unsigned int reason, unsigned int err)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	unsigned int dst_frame_status;
+	struct s5p_mfc_buf *src_buf;
+	unsigned long flags;
+	unsigned int res_change;
+
+	unsigned int index;
+
+	dst_frame_status = s5p_mfc_get_dspl_status()
+				& S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK;
+	res_change = s5p_mfc_get_dspl_status()
+				& S5P_FIMV_DEC_STATUS_RESOLUTION_MASK;
+	mfc_debug(2, "Frame Status: %x\n", dst_frame_status);
+	if (ctx->state == MFCINST_RES_CHANGE_INIT)
+		ctx->state = MFCINST_RES_CHANGE_FLUSH;
+	if (res_change) {
+		ctx->state = MFCINST_RES_CHANGE_INIT;
+		s5p_mfc_clear_int_flags(dev);
+		wake_up_ctx(ctx, reason, err);
+		if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+			BUG();
+		s5p_mfc_clock_off();
+		s5p_mfc_try_run(dev);
+		return;
+	}
+	if (ctx->dpb_flush_flag)
+		ctx->dpb_flush_flag = 0;
+
+	spin_lock_irqsave(&dev->irqlock, flags);
+	/* All frames remaining in the buffer have been extracted  */
+	if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_EMPTY) {
+		if (ctx->state == MFCINST_RES_CHANGE_FLUSH) {
+			s5p_mfc_handle_frame_all_extracted(ctx);
+			ctx->state = MFCINST_RES_CHANGE_END;
+			goto leave_handle_frame;
+		} else {
+			s5p_mfc_handle_frame_all_extracted(ctx);
+		}
+	}
+
+	if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY ||
+		dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_ONLY)
+		s5p_mfc_handle_frame_copy_time(ctx);
+
+	/* A frame has been decoded and is in the buffer  */
+	if (dst_frame_status == S5P_FIMV_DEC_STATUS_DISPLAY_ONLY ||
+	    dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY) {
+		s5p_mfc_handle_frame_new(ctx, err);
+	} else {
+		mfc_debug(2, "No frame decode\n");
+	}
+	/* Mark source buffer as complete */
+	if (dst_frame_status != S5P_FIMV_DEC_STATUS_DISPLAY_ONLY
+		&& !list_empty(&ctx->src_queue)) {
+		src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
+								list);
+		ctx->consumed_stream += s5p_mfc_get_consumed_stream();
+		if (ctx->codec_mode != S5P_FIMV_CODEC_H264_DEC &&
+			s5p_mfc_get_frame_type() == S5P_FIMV_DECODE_FRAME_P_FRAME
+					&& ctx->consumed_stream + STUFF_BYTE <
+					src_buf->b->v4l2_planes[0].bytesused) {
+			/* Run MFC again on the same buffer */
+			mfc_debug(2, "Running again the same buffer\n");
+			ctx->after_packed_pb = 1;
+		} else {
+			index = src_buf->b->v4l2_buf.index;
+			mfc_debug(2, "MFC needs next buffer\n");
+			ctx->consumed_stream = 0;
+			list_del(&src_buf->list);
+			ctx->src_queue_cnt--;
+			if (s5p_mfc_err_dec(err) > 0)
+				vb2_buffer_done(src_buf->b, VB2_BUF_STATE_ERROR);
+			else
+				vb2_buffer_done(src_buf->b, VB2_BUF_STATE_DONE);
+		}
+	}
+leave_handle_frame:
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+	if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING)
+				    || ctx->dst_queue_cnt < ctx->dpb_count)
+		clear_work_bit(ctx);
+	s5p_mfc_clear_int_flags(dev);
+	wake_up_ctx(ctx, reason, err);
+	if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+		BUG();
+	s5p_mfc_clock_off();
+	s5p_mfc_try_run(dev);
+}
+
+/* Error handling for interrupt */
+static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx,
+				 unsigned int reason, unsigned int err)
+{
+	struct s5p_mfc_dev *dev;
+	unsigned long flags;
+
+	/* If no context is available then all necessary
+	 * processing has been done. */
+	if (ctx == NULL)
+		return;
+
+	dev = ctx->dev;
+	mfc_err("Interrupt Error: %08x\n", err);
+	s5p_mfc_clear_int_flags(dev);
+	wake_up_dev(dev, reason, err);
+
+	/* Error recovery is dependent on the state of context */
+	switch (ctx->state) {
+	case MFCINST_INIT:
+		/* This error had to happen while acquireing instance */
+	case MFCINST_GOT_INST:
+		/* This error had to happen while parsing the header */
+	case MFCINST_HEAD_PARSED:
+		/* This error had to happen while setting dst buffers */
+	case MFCINST_RETURN_INST:
+		/* This error had to happen while releasing instance */
+		clear_work_bit(ctx);
+		wake_up_ctx(ctx, reason, err);
+		if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+			BUG();
+		s5p_mfc_clock_off();
+		ctx->state = MFCINST_ERROR;
+		break;
+	case MFCINST_FINISHING:
+	case MFCINST_FINISHED:
+	case MFCINST_RUNNING:
+		/* It is higly probable that an error occured
+		 * while decoding a frame */
+		clear_work_bit(ctx);
+		ctx->state = MFCINST_ERROR;
+		/* Mark all dst buffers as having an error */
+		spin_lock_irqsave(&dev->irqlock, flags);
+		s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+		/* Mark all src buffers as having an error */
+		s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+		spin_unlock_irqrestore(&dev->irqlock, flags);
+		if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+			BUG();
+		s5p_mfc_clock_off();
+		break;
+	default:
+		mfc_err("Encountered an error interrupt which had not been handled\n");
+		break;
+	}
+	return;
+}
+
+/* Header parsing interrupt handling */
+static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
+				 unsigned int reason, unsigned int err)
+{
+	struct s5p_mfc_dev *dev;
+	unsigned int guard_width, guard_height;
+
+	if (ctx == NULL)
+		return;
+	dev = ctx->dev;
+	if (ctx->c_ops->post_seq_start) {
+		if (ctx->c_ops->post_seq_start(ctx))
+			mfc_err("post_seq_start() failed\n");
+	} else {
+		ctx->img_width = s5p_mfc_get_img_width();
+		ctx->img_height = s5p_mfc_get_img_height();
+
+		ctx->buf_width = ALIGN(ctx->img_width,
+						S5P_FIMV_NV12MT_HALIGN);
+		ctx->buf_height = ALIGN(ctx->img_height,
+						S5P_FIMV_NV12MT_VALIGN);
+		mfc_debug(2, "SEQ Done: Movie dimensions %dx%d, "
+			"buffer dimensions: %dx%d\n", ctx->img_width,
+				ctx->img_height, ctx->buf_width,
+						ctx->buf_height);
+		if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) {
+			ctx->luma_size = ALIGN(ctx->buf_width *
+				ctx->buf_height, S5P_FIMV_DEC_BUF_ALIGN);
+			ctx->chroma_size = ALIGN(ctx->buf_width *
+					 ALIGN((ctx->img_height >> 1),
+					       S5P_FIMV_NV12MT_VALIGN),
+					       S5P_FIMV_DEC_BUF_ALIGN);
+			ctx->mv_size = ALIGN(ctx->buf_width *
+					ALIGN((ctx->buf_height >> 2),
+					S5P_FIMV_NV12MT_VALIGN),
+					S5P_FIMV_DEC_BUF_ALIGN);
+		} else {
+			guard_width = ALIGN(ctx->img_width + 24,
+					S5P_FIMV_NV12MT_HALIGN);
+			guard_height = ALIGN(ctx->img_height + 16,
+						S5P_FIMV_NV12MT_VALIGN);
+			ctx->luma_size = ALIGN(guard_width *
+				guard_height, S5P_FIMV_DEC_BUF_ALIGN);
+			guard_width = ALIGN(ctx->img_width + 16,
+						S5P_FIMV_NV12MT_HALIGN);
+			guard_height = ALIGN((ctx->img_height >> 1) + 4,
+						S5P_FIMV_NV12MT_VALIGN);
+			ctx->chroma_size = ALIGN(guard_width *
+				guard_height, S5P_FIMV_DEC_BUF_ALIGN);
+			ctx->mv_size = 0;
+		}
+		ctx->dpb_count = s5p_mfc_get_dpb_count();
+		if (ctx->img_width == 0 || ctx->img_height == 0)
+			ctx->state = MFCINST_ERROR;
+		else
+			ctx->state = MFCINST_HEAD_PARSED;
+	}
+	s5p_mfc_clear_int_flags(dev);
+	clear_work_bit(ctx);
+	if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+		BUG();
+	s5p_mfc_clock_off();
+	s5p_mfc_try_run(dev);
+	wake_up_ctx(ctx, reason, err);
+}
+
+/* Header parsing interrupt handling */
+static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
+				 unsigned int reason, unsigned int err)
+{
+	struct s5p_mfc_buf *src_buf;
+	struct s5p_mfc_dev *dev;
+	unsigned long flags;
+
+	if (ctx == NULL)
+		return;
+	dev = ctx->dev;
+	s5p_mfc_clear_int_flags(dev);
+	ctx->int_type = reason;
+	ctx->int_err = err;
+	ctx->int_cond = 1;
+	spin_lock(&dev->condlock);
+	clear_bit(ctx->num, &dev->ctx_work_bits);
+	spin_unlock(&dev->condlock);
+	if (err == 0) {
+		ctx->state = MFCINST_RUNNING;
+		if (!ctx->dpb_flush_flag) {
+			spin_lock_irqsave(&dev->irqlock, flags);
+			if (!list_empty(&ctx->src_queue)) {
+				src_buf = list_entry(ctx->src_queue.next,
+					     struct s5p_mfc_buf, list);
+				list_del(&src_buf->list);
+				ctx->src_queue_cnt--;
+				vb2_buffer_done(src_buf->b,
+						VB2_BUF_STATE_DONE);
+			}
+			spin_unlock_irqrestore(&dev->irqlock, flags);
+		} else {
+			ctx->dpb_flush_flag = 0;
+		}
+		if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+			BUG();
+
+		s5p_mfc_clock_off();
+
+		wake_up(&ctx->queue);
+		s5p_mfc_try_run(dev);
+	} else {
+		if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+			BUG();
+
+		s5p_mfc_clock_off();
+
+		wake_up(&ctx->queue);
+	}
+}
+
+/* Interrupt processing */
+static irqreturn_t s5p_mfc_irq(int irq, void *priv)
+{
+	struct s5p_mfc_dev *dev = priv;
+	struct s5p_mfc_ctx *ctx;
+	unsigned int reason;
+	unsigned int err;
+
+	mfc_debug_enter();
+	/* Reset the timeout watchdog */
+	atomic_set(&dev->watchdog_cnt, 0);
+	ctx = dev->ctx[dev->curr_ctx];
+	/* Get the reason of interrupt and the error code */
+	reason = s5p_mfc_get_int_reason();
+	err = s5p_mfc_get_int_err();
+	mfc_debug(1, "Int reason: %d (err: %08x)\n", reason, err);
+	switch (reason) {
+	case S5P_FIMV_R2H_CMD_ERR_RET:
+		/* An error has occured */
+		if (ctx->state == MFCINST_RUNNING &&
+			s5p_mfc_err_dec(err) >= S5P_FIMV_ERR_WARNINGS_START)
+			s5p_mfc_handle_frame(ctx, reason, err);
+		else
+			s5p_mfc_handle_error(ctx, reason, err);
+		clear_bit(0, &dev->enter_suspend);
+		break;
+
+	case S5P_FIMV_R2H_CMD_SLICE_DONE_RET:
+	case S5P_FIMV_R2H_CMD_FRAME_DONE_RET:
+		if (ctx->c_ops->post_frame_start) {
+			if (ctx->c_ops->post_frame_start(ctx))
+				mfc_err("post_frame_start() failed\n");
+			s5p_mfc_clear_int_flags(dev);
+			wake_up_ctx(ctx, reason, err);
+			if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+				BUG();
+			s5p_mfc_clock_off();
+			s5p_mfc_try_run(dev);
+		} else {
+			s5p_mfc_handle_frame(ctx, reason, err);
+		}
+		break;
+
+	case S5P_FIMV_R2H_CMD_SEQ_DONE_RET:
+		s5p_mfc_handle_seq_done(ctx, reason, err);
+		break;
+
+	case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET:
+		ctx->inst_no = s5p_mfc_get_inst_no();
+		ctx->state = MFCINST_GOT_INST;
+		clear_work_bit(ctx);
+		wake_up(&ctx->queue);
+		goto irq_cleanup_hw;
+
+	case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET:
+		clear_work_bit(ctx);
+		ctx->state = MFCINST_FREE;
+		wake_up(&ctx->queue);
+		goto irq_cleanup_hw;
+
+	case S5P_FIMV_R2H_CMD_SYS_INIT_RET:
+	case S5P_FIMV_R2H_CMD_FW_STATUS_RET:
+	case S5P_FIMV_R2H_CMD_SLEEP_RET:
+	case S5P_FIMV_R2H_CMD_WAKEUP_RET:
+		if (ctx)
+			clear_work_bit(ctx);
+		s5p_mfc_clear_int_flags(dev);
+		wake_up_dev(dev, reason, err);
+		clear_bit(0, &dev->hw_lock);
+		clear_bit(0, &dev->enter_suspend);
+		break;
+
+	case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET:
+		s5p_mfc_handle_init_buffers(ctx, reason, err);
+		break;
+	default:
+		mfc_debug(2, "Unknown int reason\n");
+		s5p_mfc_clear_int_flags(dev);
+	}
+	mfc_debug_leave();
+	return IRQ_HANDLED;
+irq_cleanup_hw:
+	s5p_mfc_clear_int_flags(dev);
+	ctx->int_type = reason;
+	ctx->int_err = err;
+	ctx->int_cond = 1;
+	if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+		mfc_err("Failed to unlock hw\n");
+
+	s5p_mfc_clock_off();
+
+	s5p_mfc_try_run(dev);
+	mfc_debug(2, "Exit via irq_cleanup_hw\n");
+	return IRQ_HANDLED;
+}
+
+/* Open an MFC node */
+static int s5p_mfc_open(struct file *file)
+{
+	struct s5p_mfc_dev *dev = video_drvdata(file);
+	struct s5p_mfc_ctx *ctx = NULL;
+	struct vb2_queue *q;
+	unsigned long flags;
+	int ret = 0;
+
+	mfc_debug_enter();
+	if (mutex_lock_interruptible(&dev->mfc_mutex))
+		return -ERESTARTSYS;
+	dev->num_inst++;	/* It is guarded by mfc_mutex in vfd */
+	/* Allocate memory for context */
+	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+	if (!ctx) {
+		mfc_err("Not enough memory\n");
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+	v4l2_fh_init(&ctx->fh, video_devdata(file));
+	file->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh);
+	ctx->dev = dev;
+	INIT_LIST_HEAD(&ctx->src_queue);
+	INIT_LIST_HEAD(&ctx->dst_queue);
+	ctx->src_queue_cnt = 0;
+	ctx->dst_queue_cnt = 0;
+	/* Get context number */
+	ctx->num = 0;
+	while (dev->ctx[ctx->num]) {
+		ctx->num++;
+		if (ctx->num >= MFC_NUM_CONTEXTS) {
+			mfc_err("Too many open contexts\n");
+			ret = -EBUSY;
+			goto err_no_ctx;
+		}
+	}
+	/* Mark context as idle */
+	spin_lock_irqsave(&dev->condlock, flags);
+	clear_bit(ctx->num, &dev->ctx_work_bits);
+	spin_unlock_irqrestore(&dev->condlock, flags);
+	dev->ctx[ctx->num] = ctx;
+	if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
+		ctx->type = MFCINST_DECODER;
+		ctx->c_ops = get_dec_codec_ops();
+		/* Setup ctrl handler */
+		ret = s5p_mfc_dec_ctrls_setup(ctx);
+		if (ret) {
+			mfc_err("Failed to setup mfc controls\n");
+			goto err_ctrls_setup;
+		}
+	} else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
+		ctx->type = MFCINST_ENCODER;
+		ctx->c_ops = get_enc_codec_ops();
+		/* only for encoder */
+		INIT_LIST_HEAD(&ctx->ref_queue);
+		ctx->ref_queue_cnt = 0;
+		/* Setup ctrl handler */
+		ret = s5p_mfc_enc_ctrls_setup(ctx);
+		if (ret) {
+			mfc_err("Failed to setup mfc controls\n");
+			goto err_ctrls_setup;
+		}
+	} else {
+		ret = -ENOENT;
+		goto err_bad_node;
+	}
+	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+	ctx->inst_no = -1;
+	/* Load firmware if this is the first instance */
+	if (dev->num_inst == 1) {
+		dev->watchdog_timer.expires = jiffies +
+					msecs_to_jiffies(MFC_WATCHDOG_INTERVAL);
+		add_timer(&dev->watchdog_timer);
+		ret = s5p_mfc_power_on();
+		if (ret < 0) {
+			mfc_err("power on failed\n");
+			goto err_pwr_enable;
+		}
+		s5p_mfc_clock_on();
+		ret = s5p_mfc_alloc_and_load_firmware(dev);
+		if (ret)
+			goto err_alloc_fw;
+		/* Init the FW */
+		ret = s5p_mfc_init_hw(dev);
+		if (ret)
+			goto err_init_hw;
+		s5p_mfc_clock_off();
+	}
+	/* Init videobuf2 queue for CAPTURE */
+	q = &ctx->vq_dst;
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	q->drv_priv = &ctx->fh;
+	if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
+		q->io_modes = VB2_MMAP;
+		q->ops = get_dec_queue_ops();
+	} else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
+		q->io_modes = VB2_MMAP | VB2_USERPTR;
+		q->ops = get_enc_queue_ops();
+	} else {
+		ret = -ENOENT;
+		goto err_queue_init;
+	}
+	q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+	ret = vb2_queue_init(q);
+	if (ret) {
+		mfc_err("Failed to initialize videobuf2 queue(capture)\n");
+		goto err_queue_init;
+	}
+	/* Init videobuf2 queue for OUTPUT */
+	q = &ctx->vq_src;
+	q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+	q->io_modes = VB2_MMAP;
+	q->drv_priv = &ctx->fh;
+	if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
+		q->io_modes = VB2_MMAP;
+		q->ops = get_dec_queue_ops();
+	} else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
+		q->io_modes = VB2_MMAP | VB2_USERPTR;
+		q->ops = get_enc_queue_ops();
+	} else {
+		ret = -ENOENT;
+		goto err_queue_init;
+	}
+	q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+	ret = vb2_queue_init(q);
+	if (ret) {
+		mfc_err("Failed to initialize videobuf2 queue(output)\n");
+		goto err_queue_init;
+	}
+	init_waitqueue_head(&ctx->queue);
+	mutex_unlock(&dev->mfc_mutex);
+	mfc_debug_leave();
+	return ret;
+	/* Deinit when failure occured */
+err_queue_init:
+err_init_hw:
+	s5p_mfc_release_firmware(dev);
+err_alloc_fw:
+	dev->ctx[ctx->num] = NULL;
+	del_timer_sync(&dev->watchdog_timer);
+	s5p_mfc_clock_off();
+err_pwr_enable:
+	if (dev->num_inst == 1) {
+		if (s5p_mfc_power_off() < 0)
+			mfc_err("power off failed\n");
+		s5p_mfc_release_firmware(dev);
+	}
+err_ctrls_setup:
+	s5p_mfc_dec_ctrls_delete(ctx);
+err_bad_node:
+err_no_ctx:
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+err_alloc:
+	dev->num_inst--;
+	mutex_unlock(&dev->mfc_mutex);
+	mfc_debug_leave();
+	return ret;
+}
+
+/* Release MFC context */
+static int s5p_mfc_release(struct file *file)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
+	struct s5p_mfc_dev *dev = ctx->dev;
+	unsigned long flags;
+
+	mfc_debug_enter();
+	mutex_lock(&dev->mfc_mutex);
+	s5p_mfc_clock_on();
+	vb2_queue_release(&ctx->vq_src);
+	vb2_queue_release(&ctx->vq_dst);
+	/* Mark context as idle */
+	spin_lock_irqsave(&dev->condlock, flags);
+	clear_bit(ctx->num, &dev->ctx_work_bits);
+	spin_unlock_irqrestore(&dev->condlock, flags);
+	/* If instance was initialised then
+	 * return instance and free reosurces */
+	if (ctx->inst_no != MFC_NO_INSTANCE_SET) {
+		mfc_debug(2, "Has to free instance\n");
+		ctx->state = MFCINST_RETURN_INST;
+		spin_lock_irqsave(&dev->condlock, flags);
+		set_bit(ctx->num, &dev->ctx_work_bits);
+		spin_unlock_irqrestore(&dev->condlock, flags);
+		s5p_mfc_clean_ctx_int_flags(ctx);
+		s5p_mfc_try_run(dev);
+		/* Wait until instance is returned or timeout occured */
+		if (s5p_mfc_wait_for_done_ctx
+		    (ctx, S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET, 0)) {
+			s5p_mfc_clock_off();
+			mfc_err("Err returning instance\n");
+		}
+		mfc_debug(2, "After free instance\n");
+		/* Free resources */
+		s5p_mfc_release_codec_buffers(ctx);
+		s5p_mfc_release_instance_buffer(ctx);
+		if (ctx->type == MFCINST_DECODER)
+			s5p_mfc_release_dec_desc_buffer(ctx);
+
+		ctx->inst_no = MFC_NO_INSTANCE_SET;
+	}
+	/* hardware locking scheme */
+	if (dev->curr_ctx == ctx->num)
+		clear_bit(0, &dev->hw_lock);
+	dev->num_inst--;
+	if (dev->num_inst == 0) {
+		mfc_debug(2, "Last instance - release firmware\n");
+		/* reset <-> F/W release */
+		s5p_mfc_reset(dev);
+		s5p_mfc_release_firmware(dev);
+		del_timer_sync(&dev->watchdog_timer);
+		if (s5p_mfc_power_off() < 0)
+			mfc_err("Power off failed\n");
+	}
+	mfc_debug(2, "Shutting down clock\n");
+	s5p_mfc_clock_off();
+	dev->ctx[ctx->num] = NULL;
+	s5p_mfc_dec_ctrls_delete(ctx);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+	mfc_debug_leave();
+	mutex_unlock(&dev->mfc_mutex);
+	return 0;
+}
+
+/* Poll */
+static unsigned int s5p_mfc_poll(struct file *file,
+				 struct poll_table_struct *wait)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
+	struct s5p_mfc_dev *dev = ctx->dev;
+	struct vb2_queue *src_q, *dst_q;
+	struct vb2_buffer *src_vb = NULL, *dst_vb = NULL;
+	unsigned int rc = 0;
+	unsigned long flags;
+
+	mutex_lock(&dev->mfc_mutex);
+	src_q = &ctx->vq_src;
+	dst_q = &ctx->vq_dst;
+	/*
+	 * There has to be at least one buffer queued on each queued_list, which
+	 * means either in driver already or waiting for driver to claim it
+	 * and start processing.
+	 */
+	if ((!src_q->streaming || list_empty(&src_q->queued_list))
+		&& (!dst_q->streaming || list_empty(&dst_q->queued_list))) {
+		rc = POLLERR;
+		goto end;
+	}
+	mutex_unlock(&dev->mfc_mutex);
+	poll_wait(file, &src_q->done_wq, wait);
+	poll_wait(file, &dst_q->done_wq, wait);
+	mutex_lock(&dev->mfc_mutex);
+	spin_lock_irqsave(&src_q->done_lock, flags);
+	if (!list_empty(&src_q->done_list))
+		src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer,
+								done_entry);
+	if (src_vb && (src_vb->state == VB2_BUF_STATE_DONE
+				|| src_vb->state == VB2_BUF_STATE_ERROR))
+		rc |= POLLOUT | POLLWRNORM;
+	spin_unlock_irqrestore(&src_q->done_lock, flags);
+	spin_lock_irqsave(&dst_q->done_lock, flags);
+	if (!list_empty(&dst_q->done_list))
+		dst_vb = list_first_entry(&dst_q->done_list, struct vb2_buffer,
+								done_entry);
+	if (dst_vb && (dst_vb->state == VB2_BUF_STATE_DONE
+				|| dst_vb->state == VB2_BUF_STATE_ERROR))
+		rc |= POLLIN | POLLRDNORM;
+	spin_unlock_irqrestore(&dst_q->done_lock, flags);
+end:
+	mutex_unlock(&dev->mfc_mutex);
+	return rc;
+}
+
+/* Mmap */
+static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
+	struct s5p_mfc_dev *dev = ctx->dev;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	int ret;
+
+	if (mutex_lock_interruptible(&dev->mfc_mutex))
+		return -ERESTARTSYS;
+	if (offset < DST_QUEUE_OFF_BASE) {
+		mfc_debug(2, "mmaping source\n");
+		ret = vb2_mmap(&ctx->vq_src, vma);
+	} else {		/* capture */
+		mfc_debug(2, "mmaping destination\n");
+		vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT);
+		ret = vb2_mmap(&ctx->vq_dst, vma);
+	}
+	mutex_unlock(&dev->mfc_mutex);
+	return ret;
+}
+
+/* v4l2 ops */
+static const struct v4l2_file_operations s5p_mfc_fops = {
+	.owner = THIS_MODULE,
+	.open = s5p_mfc_open,
+	.release = s5p_mfc_release,
+	.poll = s5p_mfc_poll,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap = s5p_mfc_mmap,
+};
+
+static int match_child(struct device *dev, void *data)
+{
+	if (!dev_name(dev))
+		return 0;
+	return !strcmp(dev_name(dev), (char *)data);
+}
+
+/* MFC probe function */
+static int s5p_mfc_probe(struct platform_device *pdev)
+{
+	struct s5p_mfc_dev *dev;
+	struct video_device *vfd;
+	struct resource *res;
+	int ret;
+
+	pr_debug("%s++\n", __func__);
+	dev = devm_kzalloc(&pdev->dev, sizeof *dev, GFP_KERNEL);
+	if (!dev) {
+		dev_err(&pdev->dev, "Not enough memory for MFC device\n");
+		return -ENOMEM;
+	}
+
+	spin_lock_init(&dev->irqlock);
+	spin_lock_init(&dev->condlock);
+	dev->plat_dev = pdev;
+	if (!dev->plat_dev) {
+		dev_err(&pdev->dev, "No platform data specified\n");
+		return -ENODEV;
+	}
+
+	ret = s5p_mfc_init_pm(dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to get mfc clock source\n");
+		return ret;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	dev->regs_base = devm_request_and_ioremap(&pdev->dev, res);
+	if (dev->regs_base == NULL) {
+		dev_err(&pdev->dev, "Failed to obtain io memory\n");
+		return -ENOENT;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "failed to get irq resource\n");
+		ret = -ENOENT;
+		goto err_res;
+	}
+	dev->irq = res->start;
+	ret = devm_request_irq(&pdev->dev, dev->irq, s5p_mfc_irq,
+					IRQF_DISABLED, pdev->name, dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret);
+		goto err_res;
+	}
+
+	dev->mem_dev_l = device_find_child(&dev->plat_dev->dev, "s5p-mfc-l",
+					   match_child);
+	if (!dev->mem_dev_l) {
+		mfc_err("Mem child (L) device get failed\n");
+		ret = -ENODEV;
+		goto err_res;
+	}
+	dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, "s5p-mfc-r",
+					   match_child);
+	if (!dev->mem_dev_r) {
+		mfc_err("Mem child (R) device get failed\n");
+		ret = -ENODEV;
+		goto err_res;
+	}
+
+	dev->alloc_ctx[0] = vb2_dma_contig_init_ctx(dev->mem_dev_l);
+	if (IS_ERR_OR_NULL(dev->alloc_ctx[0])) {
+		ret = PTR_ERR(dev->alloc_ctx[0]);
+		goto err_res;
+	}
+	dev->alloc_ctx[1] = vb2_dma_contig_init_ctx(dev->mem_dev_r);
+	if (IS_ERR_OR_NULL(dev->alloc_ctx[1])) {
+		ret = PTR_ERR(dev->alloc_ctx[1]);
+		goto err_mem_init_ctx_1;
+	}
+
+	mutex_init(&dev->mfc_mutex);
+
+	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+	if (ret)
+		goto err_v4l2_dev_reg;
+	init_waitqueue_head(&dev->queue);
+
+	/* decoder */
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+		ret = -ENOMEM;
+		goto err_dec_alloc;
+	}
+	vfd->fops	= &s5p_mfc_fops,
+	vfd->ioctl_ops	= get_dec_v4l2_ioctl_ops();
+	vfd->release	= video_device_release,
+	vfd->lock	= &dev->mfc_mutex;
+	vfd->v4l2_dev	= &dev->v4l2_dev;
+	snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME);
+	dev->vfd_dec	= vfd;
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+		video_device_release(vfd);
+		goto err_dec_reg;
+	}
+	v4l2_info(&dev->v4l2_dev,
+		  "decoder registered as /dev/video%d\n", vfd->num);
+	video_set_drvdata(vfd, dev);
+
+	/* encoder */
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+		ret = -ENOMEM;
+		goto err_enc_alloc;
+	}
+	vfd->fops	= &s5p_mfc_fops,
+	vfd->ioctl_ops	= get_enc_v4l2_ioctl_ops();
+	vfd->release	= video_device_release,
+	vfd->lock	= &dev->mfc_mutex;
+	vfd->v4l2_dev	= &dev->v4l2_dev;
+	snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME);
+	dev->vfd_enc	= vfd;
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+		video_device_release(vfd);
+		goto err_enc_reg;
+	}
+	v4l2_info(&dev->v4l2_dev,
+		  "encoder registered as /dev/video%d\n", vfd->num);
+	video_set_drvdata(vfd, dev);
+	platform_set_drvdata(pdev, dev);
+
+	dev->hw_lock = 0;
+	dev->watchdog_workqueue = create_singlethread_workqueue(S5P_MFC_NAME);
+	INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker);
+	atomic_set(&dev->watchdog_cnt, 0);
+	init_timer(&dev->watchdog_timer);
+	dev->watchdog_timer.data = (unsigned long)dev;
+	dev->watchdog_timer.function = s5p_mfc_watchdog;
+
+	pr_debug("%s--\n", __func__);
+	return 0;
+
+/* Deinit MFC if probe had failed */
+err_enc_reg:
+	video_device_release(dev->vfd_enc);
+err_enc_alloc:
+	video_unregister_device(dev->vfd_dec);
+err_dec_reg:
+	video_device_release(dev->vfd_dec);
+err_dec_alloc:
+	v4l2_device_unregister(&dev->v4l2_dev);
+err_v4l2_dev_reg:
+	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
+err_mem_init_ctx_1:
+	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
+err_res:
+	s5p_mfc_final_pm(dev);
+
+	pr_debug("%s-- with error\n", __func__);
+	return ret;
+
+}
+
+/* Remove the driver */
+static int __devexit s5p_mfc_remove(struct platform_device *pdev)
+{
+	struct s5p_mfc_dev *dev = platform_get_drvdata(pdev);
+
+	v4l2_info(&dev->v4l2_dev, "Removing %s\n", pdev->name);
+
+	del_timer_sync(&dev->watchdog_timer);
+	flush_workqueue(dev->watchdog_workqueue);
+	destroy_workqueue(dev->watchdog_workqueue);
+
+	video_unregister_device(dev->vfd_enc);
+	video_unregister_device(dev->vfd_dec);
+	v4l2_device_unregister(&dev->v4l2_dev);
+	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
+	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
+
+	s5p_mfc_final_pm(dev);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int s5p_mfc_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
+	int ret;
+
+	if (m_dev->num_inst == 0)
+		return 0;
+	return s5p_mfc_sleep(m_dev);
+	if (test_and_set_bit(0, &m_dev->enter_suspend) != 0) {
+		mfc_err("Error: going to suspend for a second time\n");
+		return -EIO;
+	}
+
+	/* Check if we're processing then wait if it necessary. */
+	while (test_and_set_bit(0, &m_dev->hw_lock) != 0) {
+		/* Try and lock the HW */
+		/* Wait on the interrupt waitqueue */
+		ret = wait_event_interruptible_timeout(m_dev->queue,
+			m_dev->int_cond || m_dev->ctx[m_dev->curr_ctx]->int_cond,
+			msecs_to_jiffies(MFC_INT_TIMEOUT));
+
+		if (ret == 0) {
+			mfc_err("Waiting for hardware to finish timed out\n");
+			return -EIO;
+		}
+	}
+	return 0;
+}
+
+static int s5p_mfc_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
+
+	if (m_dev->num_inst == 0)
+		return 0;
+	return s5p_mfc_wakeup(m_dev);
+}
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int s5p_mfc_runtime_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
+
+	atomic_set(&m_dev->pm.power, 0);
+	return 0;
+}
+
+static int s5p_mfc_runtime_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
+	int pre_power;
+
+	if (!m_dev->alloc_ctx)
+		return 0;
+	pre_power = atomic_read(&m_dev->pm.power);
+	atomic_set(&m_dev->pm.power, 1);
+	return 0;
+}
+#endif
+
+/* Power management */
+static const struct dev_pm_ops s5p_mfc_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(s5p_mfc_suspend, s5p_mfc_resume)
+	SET_RUNTIME_PM_OPS(s5p_mfc_runtime_suspend, s5p_mfc_runtime_resume,
+			   NULL)
+};
+
+static struct platform_driver s5p_mfc_driver = {
+	.probe	= s5p_mfc_probe,
+	.remove	= __devexit_p(s5p_mfc_remove),
+	.driver	= {
+		.name	= S5P_MFC_NAME,
+		.owner	= THIS_MODULE,
+		.pm	= &s5p_mfc_pm_ops
+	},
+};
+
+module_platform_driver(s5p_mfc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
+MODULE_DESCRIPTION("Samsung S5P Multi Format Codec V4L2 driver");
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c
new file mode 100644
index 0000000..91a4155
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c
@@ -0,0 +1,120 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "regs-mfc.h"
+#include "s5p_mfc_cmd.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+
+/* This function is used to send a command to the MFC */
+static int s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd,
+						struct s5p_mfc_cmd_args *args)
+{
+	int cur_cmd;
+	unsigned long timeout;
+
+	timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
+	/* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */
+	do {
+		if (time_after(jiffies, timeout)) {
+			mfc_err("Timeout while waiting for hardware\n");
+			return -EIO;
+		}
+		cur_cmd = mfc_read(dev, S5P_FIMV_HOST2RISC_CMD);
+	} while (cur_cmd != S5P_FIMV_H2R_CMD_EMPTY);
+	mfc_write(dev, args->arg[0], S5P_FIMV_HOST2RISC_ARG1);
+	mfc_write(dev, args->arg[1], S5P_FIMV_HOST2RISC_ARG2);
+	mfc_write(dev, args->arg[2], S5P_FIMV_HOST2RISC_ARG3);
+	mfc_write(dev, args->arg[3], S5P_FIMV_HOST2RISC_ARG4);
+	/* Issue the command */
+	mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD);
+	return 0;
+}
+
+/* Initialize the MFC */
+int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev)
+{
+	struct s5p_mfc_cmd_args h2r_args;
+
+	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+	h2r_args.arg[0] = dev->fw_size;
+	return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args);
+}
+
+/* Suspend the MFC hardware */
+int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev)
+{
+	struct s5p_mfc_cmd_args h2r_args;
+
+	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+	return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args);
+}
+
+/* Wake up the MFC hardware */
+int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev)
+{
+	struct s5p_mfc_cmd_args h2r_args;
+
+	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+	return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_WAKEUP, &h2r_args);
+}
+
+
+int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	struct s5p_mfc_cmd_args h2r_args;
+	int ret;
+
+	/* Preparing decoding - getting instance number */
+	mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode);
+	dev->curr_ctx = ctx->num;
+	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+	h2r_args.arg[0] = ctx->codec_mode;
+	h2r_args.arg[1] = 0; /* no crc & no pixelcache */
+	h2r_args.arg[2] = ctx->ctx_ofs;
+	h2r_args.arg[3] = ctx->ctx_size;
+	ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE,
+								&h2r_args);
+	if (ret) {
+		mfc_err("Failed to create a new instance\n");
+		ctx->state = MFCINST_ERROR;
+	}
+	return ret;
+}
+
+int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	struct s5p_mfc_cmd_args h2r_args;
+	int ret;
+
+	if (ctx->state == MFCINST_FREE) {
+		mfc_err("Instance already returned\n");
+		ctx->state = MFCINST_ERROR;
+		return -EINVAL;
+	}
+	/* Closing decoding instance  */
+	mfc_debug(2, "Returning instance number %d\n", ctx->inst_no);
+	dev->curr_ctx = ctx->num;
+	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+	h2r_args.arg[0] = ctx->inst_no;
+	ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE,
+								&h2r_args);
+	if (ret) {
+		mfc_err("Failed to return an instance\n");
+		ctx->state = MFCINST_ERROR;
+		return -EINVAL;
+	}
+	return 0;
+}
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h
new file mode 100644
index 0000000..8b090d3
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h
@@ -0,0 +1,30 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef S5P_MFC_CMD_H_
+#define S5P_MFC_CMD_H_
+
+#include "s5p_mfc_common.h"
+
+#define MAX_H2R_ARG	4
+
+struct s5p_mfc_cmd_args {
+	unsigned int	arg[MAX_H2R_ARG];
+};
+
+int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev);
+int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev);
+int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev);
+int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx);
+
+#endif /* S5P_MFC_CMD_H_ */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
new file mode 100644
index 0000000..bd5706a
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
@@ -0,0 +1,570 @@
+/*
+ * Samsung S5P Multi Format Codec v 5.0
+ *
+ * This file contains definitions of enums and structs used by the codec
+ * driver.
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version
+ */
+
+#ifndef S5P_MFC_COMMON_H_
+#define S5P_MFC_COMMON_H_
+
+#include "regs-mfc.h"
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+
+/* Definitions related to MFC memory */
+
+/* Offset base used to differentiate between CAPTURE and OUTPUT
+*  while mmaping */
+#define DST_QUEUE_OFF_BASE      (TASK_SIZE / 2)
+
+/* Offset used by the hardware to store addresses */
+#define MFC_OFFSET_SHIFT	11
+
+#define FIRMWARE_ALIGN		0x20000		/* 128KB */
+#define MFC_H264_CTX_BUF_SIZE	0x96000		/* 600KB per H264 instance */
+#define MFC_CTX_BUF_SIZE	0x2800		/* 10KB per instance */
+#define DESC_BUF_SIZE		0x20000		/* 128KB for DESC buffer */
+#define SHARED_BUF_SIZE		0x2000		/* 8KB for shared buffer */
+
+#define DEF_CPB_SIZE		0x40000		/* 512KB */
+
+#define MFC_BANK1_ALLOC_CTX	0
+#define MFC_BANK2_ALLOC_CTX	1
+
+#define MFC_BANK1_ALIGN_ORDER	13
+#define MFC_BANK2_ALIGN_ORDER	13
+#define MFC_BASE_ALIGN_ORDER	17
+
+#include <media/videobuf2-dma-contig.h>
+
+static inline dma_addr_t s5p_mfc_mem_cookie(void *a, void *b)
+{
+	/* Same functionality as the vb2_dma_contig_plane_paddr */
+	dma_addr_t *paddr = vb2_dma_contig_memops.cookie(b);
+
+	return *paddr;
+}
+
+/* MFC definitions */
+#define MFC_MAX_EXTRA_DPB       5
+#define MFC_MAX_BUFFERS		32
+#define MFC_NUM_CONTEXTS	4
+/* Interrupt timeout */
+#define MFC_INT_TIMEOUT		2000
+/* Busy wait timeout */
+#define MFC_BW_TIMEOUT		500
+/* Watchdog interval */
+#define MFC_WATCHDOG_INTERVAL   1000
+/* After how many executions watchdog should assume lock up */
+#define MFC_WATCHDOG_CNT        10
+#define MFC_NO_INSTANCE_SET	-1
+#define MFC_ENC_CAP_PLANE_COUNT	1
+#define MFC_ENC_OUT_PLANE_COUNT	2
+#define STUFF_BYTE		4
+#define MFC_MAX_CTRLS		64
+
+#define mfc_read(dev, offset)		readl(dev->regs_base + (offset))
+#define mfc_write(dev, data, offset)	writel((data), dev->regs_base + \
+								(offset))
+
+/**
+ * enum s5p_mfc_fmt_type - type of the pixelformat
+ */
+enum s5p_mfc_fmt_type {
+	MFC_FMT_DEC,
+	MFC_FMT_ENC,
+	MFC_FMT_RAW,
+};
+
+/**
+ * enum s5p_mfc_node_type - The type of an MFC device node.
+ */
+enum s5p_mfc_node_type {
+	MFCNODE_INVALID = -1,
+	MFCNODE_DECODER = 0,
+	MFCNODE_ENCODER = 1,
+};
+
+/**
+ * enum s5p_mfc_inst_type - The type of an MFC instance.
+ */
+enum s5p_mfc_inst_type {
+	MFCINST_INVALID,
+	MFCINST_DECODER,
+	MFCINST_ENCODER,
+};
+
+/**
+ * enum s5p_mfc_inst_state - The state of an MFC instance.
+ */
+enum s5p_mfc_inst_state {
+	MFCINST_FREE = 0,
+	MFCINST_INIT = 100,
+	MFCINST_GOT_INST,
+	MFCINST_HEAD_PARSED,
+	MFCINST_BUFS_SET,
+	MFCINST_RUNNING,
+	MFCINST_FINISHING,
+	MFCINST_FINISHED,
+	MFCINST_RETURN_INST,
+	MFCINST_ERROR,
+	MFCINST_ABORT,
+	MFCINST_RES_CHANGE_INIT,
+	MFCINST_RES_CHANGE_FLUSH,
+	MFCINST_RES_CHANGE_END,
+};
+
+/**
+ * enum s5p_mfc_queue_state - The state of buffer queue.
+ */
+enum s5p_mfc_queue_state {
+	QUEUE_FREE,
+	QUEUE_BUFS_REQUESTED,
+	QUEUE_BUFS_QUERIED,
+	QUEUE_BUFS_MMAPED,
+};
+
+/**
+ * enum s5p_mfc_decode_arg - type of frame decoding
+ */
+enum s5p_mfc_decode_arg {
+	MFC_DEC_FRAME,
+	MFC_DEC_LAST_FRAME,
+	MFC_DEC_RES_CHANGE,
+};
+
+struct s5p_mfc_ctx;
+
+/**
+ * struct s5p_mfc_buf - MFC buffer
+ */
+struct s5p_mfc_buf {
+	struct list_head list;
+	struct vb2_buffer *b;
+	union {
+		struct {
+			size_t luma;
+			size_t chroma;
+		} raw;
+		size_t stream;
+	} cookie;
+	int used;
+};
+
+/**
+ * struct s5p_mfc_pm - power management data structure
+ */
+struct s5p_mfc_pm {
+	struct clk	*clock;
+	struct clk	*clock_gate;
+	atomic_t	power;
+	struct device	*device;
+};
+
+/**
+ * struct s5p_mfc_dev - The struct containing driver internal parameters.
+ *
+ * @v4l2_dev:		v4l2_device
+ * @vfd_dec:		video device for decoding
+ * @vfd_enc:		video device for encoding
+ * @plat_dev:		platform device
+ * @mem_dev_l:		child device of the left memory bank (0)
+ * @mem_dev_r:		child device of the right memory bank (1)
+ * @regs_base:		base address of the MFC hw registers
+ * @irq:		irq resource
+ * @dec_ctrl_handler:	control framework handler for decoding
+ * @enc_ctrl_handler:	control framework handler for encoding
+ * @pm:			power management control
+ * @num_inst:		couter of active MFC instances
+ * @irqlock:		lock for operations on videobuf2 queues
+ * @condlock:		lock for changing/checking if a context is ready to be
+ *			processed
+ * @mfc_mutex:		lock for video_device
+ * @int_cond:		variable used by the waitqueue
+ * @int_type:		type of last interrupt
+ * @int_err:		error number for last interrupt
+ * @queue:		waitqueue for waiting for completion of device commands
+ * @fw_size:		size of firmware
+ * @bank1:		address of the beggining of bank 1 memory
+ * @bank2:		address of the beggining of bank 2 memory
+ * @hw_lock:		used for hardware locking
+ * @ctx:		array of driver contexts
+ * @curr_ctx:		number of the currently running context
+ * @ctx_work_bits:	used to mark which contexts are waiting for hardware
+ * @watchdog_cnt:	counter for the watchdog
+ * @watchdog_workqueue:	workqueue for the watchdog
+ * @watchdog_work:	worker for the watchdog
+ * @alloc_ctx:		videobuf2 allocator contexts for two memory banks
+ * @enter_suspend:	flag set when entering suspend
+ *
+ */
+struct s5p_mfc_dev {
+	struct v4l2_device	v4l2_dev;
+	struct video_device	*vfd_dec;
+	struct video_device	*vfd_enc;
+	struct platform_device	*plat_dev;
+	struct device		*mem_dev_l;
+	struct device		*mem_dev_r;
+	void __iomem		*regs_base;
+	int			irq;
+	struct v4l2_ctrl_handler dec_ctrl_handler;
+	struct v4l2_ctrl_handler enc_ctrl_handler;
+	struct s5p_mfc_pm	pm;
+	int num_inst;
+	spinlock_t irqlock;	/* lock when operating on videobuf2 queues */
+	spinlock_t condlock;	/* lock when changing/checking if a context is
+					ready to be processed */
+	struct mutex mfc_mutex; /* video_device lock */
+	int int_cond;
+	int int_type;
+	unsigned int int_err;
+	wait_queue_head_t queue;
+	size_t fw_size;
+	size_t bank1;
+	size_t bank2;
+	unsigned long hw_lock;
+	struct s5p_mfc_ctx *ctx[MFC_NUM_CONTEXTS];
+	int curr_ctx;
+	unsigned long ctx_work_bits;
+	atomic_t watchdog_cnt;
+	struct timer_list watchdog_timer;
+	struct workqueue_struct *watchdog_workqueue;
+	struct work_struct watchdog_work;
+	void *alloc_ctx[2];
+	unsigned long enter_suspend;
+};
+
+/**
+ * struct s5p_mfc_h264_enc_params - encoding parameters for h264
+ */
+struct s5p_mfc_h264_enc_params {
+	enum v4l2_mpeg_video_h264_profile profile;
+	enum v4l2_mpeg_video_h264_loop_filter_mode loop_filter_mode;
+	s8 loop_filter_alpha;
+	s8 loop_filter_beta;
+	enum v4l2_mpeg_video_h264_entropy_mode entropy_mode;
+	u8 max_ref_pic;
+	u8 num_ref_pic_4p;
+	int _8x8_transform;
+	int rc_mb;
+	int rc_mb_dark;
+	int rc_mb_smooth;
+	int rc_mb_static;
+	int rc_mb_activity;
+	int vui_sar;
+	u8 vui_sar_idc;
+	u16 vui_ext_sar_width;
+	u16 vui_ext_sar_height;
+	int open_gop;
+	u16 open_gop_size;
+	u8 rc_frame_qp;
+	u8 rc_min_qp;
+	u8 rc_max_qp;
+	u8 rc_p_frame_qp;
+	u8 rc_b_frame_qp;
+	enum v4l2_mpeg_video_h264_level level_v4l2;
+	int level;
+	u16 cpb_size;
+};
+
+/**
+ * struct s5p_mfc_mpeg4_enc_params - encoding parameters for h263 and mpeg4
+ */
+struct s5p_mfc_mpeg4_enc_params {
+	/* MPEG4 Only */
+	enum v4l2_mpeg_video_mpeg4_profile profile;
+	int quarter_pixel;
+	/* Common for MPEG4, H263 */
+	u16 vop_time_res;
+	u16 vop_frm_delta;
+	u8 rc_frame_qp;
+	u8 rc_min_qp;
+	u8 rc_max_qp;
+	u8 rc_p_frame_qp;
+	u8 rc_b_frame_qp;
+	enum v4l2_mpeg_video_mpeg4_level level_v4l2;
+	int level;
+};
+
+/**
+ * struct s5p_mfc_enc_params - general encoding parameters
+ */
+struct s5p_mfc_enc_params {
+	u16 width;
+	u16 height;
+
+	u16 gop_size;
+	enum v4l2_mpeg_video_multi_slice_mode slice_mode;
+	u16 slice_mb;
+	u32 slice_bit;
+	u16 intra_refresh_mb;
+	int pad;
+	u8 pad_luma;
+	u8 pad_cb;
+	u8 pad_cr;
+	int rc_frame;
+	u32 rc_bitrate;
+	u16 rc_reaction_coeff;
+	u16 vbv_size;
+
+	enum v4l2_mpeg_video_header_mode seq_hdr_mode;
+	enum v4l2_mpeg_mfc51_video_frame_skip_mode frame_skip_mode;
+	int fixed_target_bit;
+
+	u8 num_b_frame;
+	u32 rc_framerate_num;
+	u32 rc_framerate_denom;
+	int interlace;
+
+	union {
+		struct s5p_mfc_h264_enc_params h264;
+		struct s5p_mfc_mpeg4_enc_params mpeg4;
+	} codec;
+
+};
+
+/**
+ * struct s5p_mfc_codec_ops - codec ops, used by encoding
+ */
+struct s5p_mfc_codec_ops {
+	/* initialization routines */
+	int (*pre_seq_start) (struct s5p_mfc_ctx *ctx);
+	int (*post_seq_start) (struct s5p_mfc_ctx *ctx);
+	/* execution routines */
+	int (*pre_frame_start) (struct s5p_mfc_ctx *ctx);
+	int (*post_frame_start) (struct s5p_mfc_ctx *ctx);
+};
+
+#define call_cop(c, op, args...)				\
+	(((c)->c_ops->op) ?					\
+		((c)->c_ops->op(args)) : 0)
+
+/**
+ * struct s5p_mfc_ctx - This struct contains the instance context
+ *
+ * @dev:		pointer to the s5p_mfc_dev of the device
+ * @fh:			struct v4l2_fh
+ * @num:		number of the context that this structure describes
+ * @int_cond:		variable used by the waitqueue
+ * @int_type:		type of the last interrupt
+ * @int_err:		error number received from MFC hw in the interrupt
+ * @queue:		waitqueue that can be used to wait for this context to
+ *			finish
+ * @src_fmt:		source pixelformat information
+ * @dst_fmt:		destination pixelformat information
+ * @vq_src:		vb2 queue for source buffers
+ * @vq_dst:		vb2 queue for destination buffers
+ * @src_queue:		driver internal queue for source buffers
+ * @dst_queue:		driver internal queue for destination buffers
+ * @src_queue_cnt:	number of buffers queued on the source internal queue
+ * @dst_queue_cnt:	number of buffers queued on the dest internal queue
+ * @type:		type of the instance - decoder or encoder
+ * @state:		state of the context
+ * @inst_no:		number of hw instance associated with the context
+ * @img_width:		width of the image that is decoded or encoded
+ * @img_height:		height of the image that is decoded or encoded
+ * @buf_width:		width of the buffer for processed image
+ * @buf_height:		height of the buffer for processed image
+ * @luma_size:		size of a luma plane
+ * @chroma_size:	size of a chroma plane
+ * @mv_size:		size of a motion vectors buffer
+ * @consumed_stream:	number of bytes that have been used so far from the
+ *			decoding buffer
+ * @dpb_flush_flag:	flag used to indicate that a DPB buffers are being
+ *			flushed
+ * @bank1_buf:		handle to memory allocated for temporary buffers from
+ *			memory bank 1
+ * @bank1_phys:		address of the temporary buffers from memory bank 1
+ * @bank1_size:		size of the memory allocated for temporary buffers from
+ *			memory bank 1
+ * @bank2_buf:		handle to memory allocated for temporary buffers from
+ *			memory bank 2
+ * @bank2_phys:		address of the temporary buffers from memory bank 2
+ * @bank2_size:		size of the memory allocated for temporary buffers from
+ *			memory bank 2
+ * @capture_state:	state of the capture buffers queue
+ * @output_state:	state of the output buffers queue
+ * @src_bufs:		information on allocated source buffers
+ * @dst_bufs:		information on allocated destination buffers
+ * @sequence:		counter for the sequence number for v4l2
+ * @dec_dst_flag:	flags for buffers queued in the hardware
+ * @dec_src_buf_size:	size of the buffer for source buffers in decoding
+ * @codec_mode:		number of codec mode used by MFC hw
+ * @slice_interface:	slice interface flag
+ * @loop_filter_mpeg4:	loop filter for MPEG4 flag
+ * @display_delay:	value of the display delay for H264
+ * @display_delay_enable:	display delay for H264 enable flag
+ * @after_packed_pb:	flag used to track buffer when stream is in
+ *			Packed PB format
+ * @dpb_count:		count of the DPB buffers required by MFC hw
+ * @total_dpb_count:	count of DPB buffers with additional buffers
+ *			requested by the application
+ * @ctx_buf:		handle to the memory associated with this context
+ * @ctx_phys:		address of the memory associated with this context
+ * @ctx_size:		size of the memory associated with this context
+ * @desc_buf:		description buffer for decoding handle
+ * @desc_phys:		description buffer for decoding address
+ * @shm_alloc:		handle for the shared memory buffer
+ * @shm:		virtual address for the shared memory buffer
+ * @shm_ofs:		address offset for shared memory
+ * @enc_params:		encoding parameters for MFC
+ * @enc_dst_buf_size:	size of the buffers for encoder output
+ * @frame_type:		used to force the type of the next encoded frame
+ * @ref_queue:		list of the reference buffers for encoding
+ * @ref_queue_cnt:	number of the buffers in the reference list
+ * @c_ops:		ops for encoding
+ * @ctrls:		array of controls, used when adding controls to the
+ *			v4l2 control framework
+ * @ctrl_handler:	handler for v4l2 framework
+ */
+struct s5p_mfc_ctx {
+	struct s5p_mfc_dev *dev;
+	struct v4l2_fh fh;
+
+	int num;
+
+	int int_cond;
+	int int_type;
+	unsigned int int_err;
+	wait_queue_head_t queue;
+
+	struct s5p_mfc_fmt *src_fmt;
+	struct s5p_mfc_fmt *dst_fmt;
+
+	struct vb2_queue vq_src;
+	struct vb2_queue vq_dst;
+
+	struct list_head src_queue;
+	struct list_head dst_queue;
+
+	unsigned int src_queue_cnt;
+	unsigned int dst_queue_cnt;
+
+	enum s5p_mfc_inst_type type;
+	enum s5p_mfc_inst_state state;
+	int inst_no;
+
+	/* Image parameters */
+	int img_width;
+	int img_height;
+	int buf_width;
+	int buf_height;
+
+	int luma_size;
+	int chroma_size;
+	int mv_size;
+
+	unsigned long consumed_stream;
+
+	unsigned int dpb_flush_flag;
+
+	/* Buffers */
+	void *bank1_buf;
+	size_t bank1_phys;
+	size_t bank1_size;
+
+	void *bank2_buf;
+	size_t bank2_phys;
+	size_t bank2_size;
+
+	enum s5p_mfc_queue_state capture_state;
+	enum s5p_mfc_queue_state output_state;
+
+	struct s5p_mfc_buf src_bufs[MFC_MAX_BUFFERS];
+	int src_bufs_cnt;
+	struct s5p_mfc_buf dst_bufs[MFC_MAX_BUFFERS];
+	int dst_bufs_cnt;
+
+	unsigned int sequence;
+	unsigned long dec_dst_flag;
+	size_t dec_src_buf_size;
+
+	/* Control values */
+	int codec_mode;
+	int slice_interface;
+	int loop_filter_mpeg4;
+	int display_delay;
+	int display_delay_enable;
+	int after_packed_pb;
+
+	int dpb_count;
+	int total_dpb_count;
+
+	/* Buffers */
+	void *ctx_buf;
+	size_t ctx_phys;
+	size_t ctx_ofs;
+	size_t ctx_size;
+
+	void *desc_buf;
+	size_t desc_phys;
+
+
+	void *shm_alloc;
+	void *shm;
+	size_t shm_ofs;
+
+	struct s5p_mfc_enc_params enc_params;
+
+	size_t enc_dst_buf_size;
+
+	enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type;
+
+	struct list_head ref_queue;
+	unsigned int ref_queue_cnt;
+
+	struct s5p_mfc_codec_ops *c_ops;
+
+	struct v4l2_ctrl *ctrls[MFC_MAX_CTRLS];
+	struct v4l2_ctrl_handler ctrl_handler;
+};
+
+/*
+ * struct s5p_mfc_fmt -	structure used to store information about pixelformats
+ *			used by the MFC
+ */
+struct s5p_mfc_fmt {
+	char *name;
+	u32 fourcc;
+	u32 codec_mode;
+	enum s5p_mfc_fmt_type type;
+	u32 num_planes;
+};
+
+/**
+ * struct mfc_control -	structure used to store information about MFC controls
+ *			it is used to initialize the control framework.
+ */
+struct mfc_control {
+	__u32			id;
+	enum v4l2_ctrl_type	type;
+	__u8			name[32];  /* Whatever */
+	__s32			minimum;   /* Note signedness */
+	__s32			maximum;
+	__s32			step;
+	__u32			menu_skip_mask;
+	__s32			default_value;
+	__u32			flags;
+	__u32			reserved[2];
+	__u8			is_volatile;
+};
+
+
+#define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh)
+#define ctrl_to_ctx(__ctrl) \
+	container_of((__ctrl)->handler, struct s5p_mfc_ctx, ctrl_handler)
+
+#endif /* S5P_MFC_COMMON_H_ */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
new file mode 100644
index 0000000..4d662f1
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
@@ -0,0 +1,343 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_cmd.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_pm.h"
+
+static void *s5p_mfc_bitproc_buf;
+static size_t s5p_mfc_bitproc_phys;
+static unsigned char *s5p_mfc_bitproc_virt;
+
+/* Allocate and load firmware */
+int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev)
+{
+	struct firmware *fw_blob;
+	size_t bank2_base_phys;
+	void *b_base;
+	int err;
+
+	/* Firmare has to be present as a separate file or compiled
+	 * into kernel. */
+	mfc_debug_enter();
+	err = request_firmware((const struct firmware **)&fw_blob,
+				     "s5p-mfc.fw", dev->v4l2_dev.dev);
+	if (err != 0) {
+		mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
+		return -EINVAL;
+	}
+	dev->fw_size = ALIGN(fw_blob->size, FIRMWARE_ALIGN);
+	if (s5p_mfc_bitproc_buf) {
+		mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n");
+		release_firmware(fw_blob);
+		return -ENOMEM;
+	}
+	s5p_mfc_bitproc_buf = vb2_dma_contig_memops.alloc(
+		dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], dev->fw_size);
+	if (IS_ERR(s5p_mfc_bitproc_buf)) {
+		s5p_mfc_bitproc_buf = NULL;
+		mfc_err("Allocating bitprocessor buffer failed\n");
+		release_firmware(fw_blob);
+		return -ENOMEM;
+	}
+	s5p_mfc_bitproc_phys = s5p_mfc_mem_cookie(
+		dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], s5p_mfc_bitproc_buf);
+	if (s5p_mfc_bitproc_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) {
+		mfc_err("The base memory for bank 1 is not aligned to 128KB\n");
+		vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+		s5p_mfc_bitproc_phys = 0;
+		s5p_mfc_bitproc_buf = NULL;
+		release_firmware(fw_blob);
+		return -EIO;
+	}
+	s5p_mfc_bitproc_virt = vb2_dma_contig_memops.vaddr(s5p_mfc_bitproc_buf);
+	if (!s5p_mfc_bitproc_virt) {
+		mfc_err("Bitprocessor memory remap failed\n");
+		vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+		s5p_mfc_bitproc_phys = 0;
+		s5p_mfc_bitproc_buf = NULL;
+		release_firmware(fw_blob);
+		return -EIO;
+	}
+	dev->bank1 = s5p_mfc_bitproc_phys;
+	b_base = vb2_dma_contig_memops.alloc(
+		dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], 1 << MFC_BANK2_ALIGN_ORDER);
+	if (IS_ERR(b_base)) {
+		vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+		s5p_mfc_bitproc_phys = 0;
+		s5p_mfc_bitproc_buf = NULL;
+		mfc_err("Allocating bank2 base failed\n");
+	release_firmware(fw_blob);
+		return -ENOMEM;
+	}
+	bank2_base_phys = s5p_mfc_mem_cookie(
+		dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base);
+	vb2_dma_contig_memops.put(b_base);
+	if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) {
+		mfc_err("The base memory for bank 2 is not aligned to 128KB\n");
+		vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+		s5p_mfc_bitproc_phys = 0;
+		s5p_mfc_bitproc_buf = NULL;
+		release_firmware(fw_blob);
+		return -EIO;
+	}
+	dev->bank2 = bank2_base_phys;
+	memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size);
+	wmb();
+	release_firmware(fw_blob);
+	mfc_debug_leave();
+	return 0;
+}
+
+/* Reload firmware to MFC */
+int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev)
+{
+	struct firmware *fw_blob;
+	int err;
+
+	/* Firmare has to be present as a separate file or compiled
+	 * into kernel. */
+	mfc_debug_enter();
+	err = request_firmware((const struct firmware **)&fw_blob,
+				     "s5p-mfc.fw", dev->v4l2_dev.dev);
+	if (err != 0) {
+		mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
+		return -EINVAL;
+	}
+	if (fw_blob->size > dev->fw_size) {
+		mfc_err("MFC firmware is too big to be loaded\n");
+		release_firmware(fw_blob);
+		return -ENOMEM;
+	}
+	if (s5p_mfc_bitproc_buf == NULL || s5p_mfc_bitproc_phys == 0) {
+		mfc_err("MFC firmware is not allocated or was not mapped correctly\n");
+		release_firmware(fw_blob);
+		return -EINVAL;
+	}
+	memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size);
+	wmb();
+	release_firmware(fw_blob);
+	mfc_debug_leave();
+	return 0;
+}
+
+/* Release firmware memory */
+int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev)
+{
+	/* Before calling this function one has to make sure
+	 * that MFC is no longer processing */
+	if (!s5p_mfc_bitproc_buf)
+		return -EINVAL;
+	vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+	s5p_mfc_bitproc_virt = NULL;
+	s5p_mfc_bitproc_phys = 0;
+	s5p_mfc_bitproc_buf = NULL;
+	return 0;
+}
+
+/* Reset the device */
+int s5p_mfc_reset(struct s5p_mfc_dev *dev)
+{
+	unsigned int mc_status;
+	unsigned long timeout;
+
+	mfc_debug_enter();
+	/* Stop procedure */
+	/*  reset RISC */
+	mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET);
+	/*  All reset except for MC */
+	mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET);
+	mdelay(10);
+
+	timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
+	/* Check MC status */
+	do {
+		if (time_after(jiffies, timeout)) {
+			mfc_err("Timeout while resetting MFC\n");
+			return -EIO;
+		}
+
+		mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS);
+
+	} while (mc_status & 0x3);
+
+	mfc_write(dev, 0x0, S5P_FIMV_SW_RESET);
+	mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET);
+	mfc_debug_leave();
+	return 0;
+}
+
+static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev)
+{
+	mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A);
+	mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B);
+	mfc_debug(2, "Bank1: %08x, Bank2: %08x\n", dev->bank1, dev->bank2);
+}
+
+static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev)
+{
+	mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID);
+	mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID);
+	mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD);
+	mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD);
+}
+
+/* Initialize hardware */
+int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
+{
+	unsigned int ver;
+	int ret;
+
+	mfc_debug_enter();
+	if (!s5p_mfc_bitproc_buf)
+		return -EINVAL;
+
+	/* 0. MFC reset */
+	mfc_debug(2, "MFC reset..\n");
+	s5p_mfc_clock_on();
+	ret = s5p_mfc_reset(dev);
+	if (ret) {
+		mfc_err("Failed to reset MFC - timeout\n");
+		return ret;
+	}
+	mfc_debug(2, "Done MFC reset..\n");
+	/* 1. Set DRAM base Addr */
+	s5p_mfc_init_memctrl(dev);
+	/* 2. Initialize registers of channel I/F */
+	s5p_mfc_clear_cmds(dev);
+	/* 3. Release reset signal to the RISC */
+	s5p_mfc_clean_dev_int_flags(dev);
+	mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
+	mfc_debug(2, "Will now wait for completion of firmware transfer\n");
+	if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) {
+		mfc_err("Failed to load firmware\n");
+		s5p_mfc_reset(dev);
+		s5p_mfc_clock_off();
+		return -EIO;
+	}
+	s5p_mfc_clean_dev_int_flags(dev);
+	/* 4. Initialize firmware */
+	ret = s5p_mfc_sys_init_cmd(dev);
+	if (ret) {
+		mfc_err("Failed to send command to MFC - timeout\n");
+		s5p_mfc_reset(dev);
+		s5p_mfc_clock_off();
+		return ret;
+	}
+	mfc_debug(2, "Ok, now will write a command to init the system\n");
+	if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SYS_INIT_RET)) {
+		mfc_err("Failed to load firmware\n");
+		s5p_mfc_reset(dev);
+		s5p_mfc_clock_off();
+		return -EIO;
+	}
+	dev->int_cond = 0;
+	if (dev->int_err != 0 || dev->int_type !=
+					S5P_FIMV_R2H_CMD_SYS_INIT_RET) {
+		/* Failure. */
+		mfc_err("Failed to init firmware - error: %d int: %d\n",
+						dev->int_err, dev->int_type);
+		s5p_mfc_reset(dev);
+		s5p_mfc_clock_off();
+		return -EIO;
+	}
+	ver = mfc_read(dev, S5P_FIMV_FW_VERSION);
+	mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n",
+		(ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF);
+	s5p_mfc_clock_off();
+	mfc_debug_leave();
+	return 0;
+}
+
+
+int s5p_mfc_sleep(struct s5p_mfc_dev *dev)
+{
+	int ret;
+
+	mfc_debug_enter();
+	s5p_mfc_clock_on();
+	s5p_mfc_clean_dev_int_flags(dev);
+	ret = s5p_mfc_sleep_cmd(dev);
+	if (ret) {
+		mfc_err("Failed to send command to MFC - timeout\n");
+		return ret;
+	}
+	if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SLEEP_RET)) {
+		mfc_err("Failed to sleep\n");
+		return -EIO;
+	}
+	s5p_mfc_clock_off();
+	dev->int_cond = 0;
+	if (dev->int_err != 0 || dev->int_type !=
+						S5P_FIMV_R2H_CMD_SLEEP_RET) {
+		/* Failure. */
+		mfc_err("Failed to sleep - error: %d int: %d\n", dev->int_err,
+								dev->int_type);
+		return -EIO;
+	}
+	mfc_debug_leave();
+	return ret;
+}
+
+int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
+{
+	int ret;
+
+	mfc_debug_enter();
+	/* 0. MFC reset */
+	mfc_debug(2, "MFC reset..\n");
+	s5p_mfc_clock_on();
+	ret = s5p_mfc_reset(dev);
+	if (ret) {
+		mfc_err("Failed to reset MFC - timeout\n");
+		return ret;
+	}
+	mfc_debug(2, "Done MFC reset..\n");
+	/* 1. Set DRAM base Addr */
+	s5p_mfc_init_memctrl(dev);
+	/* 2. Initialize registers of channel I/F */
+	s5p_mfc_clear_cmds(dev);
+	s5p_mfc_clean_dev_int_flags(dev);
+	/* 3. Initialize firmware */
+	ret = s5p_mfc_wakeup_cmd(dev);
+	if (ret) {
+		mfc_err("Failed to send command to MFC - timeout\n");
+		return ret;
+	}
+	/* 4. Release reset signal to the RISC */
+	mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
+	mfc_debug(2, "Ok, now will write a command to wakeup the system\n");
+	if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_WAKEUP_RET)) {
+		mfc_err("Failed to load firmware\n");
+		return -EIO;
+	}
+	s5p_mfc_clock_off();
+	dev->int_cond = 0;
+	if (dev->int_err != 0 || dev->int_type !=
+						S5P_FIMV_R2H_CMD_WAKEUP_RET) {
+		/* Failure. */
+		mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err,
+								dev->int_type);
+		return -EIO;
+	}
+	mfc_debug_leave();
+	return 0;
+}
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h
new file mode 100644
index 0000000..e1e0c54
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h
@@ -0,0 +1,29 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef S5P_MFC_CTRL_H
+#define S5P_MFC_CTRL_H
+
+#include "s5p_mfc_common.h"
+
+int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev);
+int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev);
+int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_init_hw(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_sleep(struct s5p_mfc_dev *dev);
+int s5p_mfc_wakeup(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_reset(struct s5p_mfc_dev *dev);
+
+#endif /* S5P_MFC_CTRL_H */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h
new file mode 100644
index 0000000..bd5cd4a
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h
@@ -0,0 +1,48 @@
+/*
+ * drivers/media/platform/samsung/mfc5/s5p_mfc_debug.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * This file contains debug macros
+ *
+ * Kamil Debski, Copyright (c) 2011 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef S5P_MFC_DEBUG_H_
+#define S5P_MFC_DEBUG_H_
+
+#define DEBUG
+
+#ifdef DEBUG
+extern int debug;
+
+#define mfc_debug(level, fmt, args...)				\
+	do {							\
+		if (debug >= level)				\
+			printk(KERN_DEBUG "%s:%d: " fmt,	\
+				__func__, __LINE__, ##args);	\
+	} while (0)
+#else
+#define mfc_debug(level, fmt, args...)
+#endif
+
+#define mfc_debug_enter() mfc_debug(5, "enter")
+#define mfc_debug_leave() mfc_debug(5, "leave")
+
+#define mfc_err(fmt, args...)				\
+	do {						\
+		printk(KERN_ERR "%s:%d: " fmt,		\
+		       __func__, __LINE__, ##args);	\
+	} while (0)
+
+#define mfc_info(fmt, args...)				\
+	do {						\
+		printk(KERN_INFO "%s:%d: " fmt,		\
+		       __func__, __LINE__, ##args);	\
+	} while (0)
+
+#endif /* S5P_MFC_DEBUG_H_ */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
new file mode 100644
index 0000000..456f5df
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -0,0 +1,1044 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ * Kamil Debski, <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_dec.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_opr.h"
+#include "s5p_mfc_pm.h"
+#include "s5p_mfc_shm.h"
+
+static struct s5p_mfc_fmt formats[] = {
+	{
+		.name		= "4:2:0 2 Planes 64x32 Tiles",
+		.fourcc		= V4L2_PIX_FMT_NV12MT,
+		.codec_mode	= S5P_FIMV_CODEC_NONE,
+		.type		= MFC_FMT_RAW,
+		.num_planes	= 2,
+	 },
+	{
+		.name = "4:2:0 2 Planes",
+		.fourcc = V4L2_PIX_FMT_NV12M,
+		.codec_mode = S5P_FIMV_CODEC_NONE,
+		.type = MFC_FMT_RAW,
+		.num_planes = 2,
+	},
+	{
+		.name = "H264 Encoded Stream",
+		.fourcc = V4L2_PIX_FMT_H264,
+		.codec_mode = S5P_FIMV_CODEC_H264_DEC,
+		.type = MFC_FMT_DEC,
+		.num_planes = 1,
+	},
+	{
+		.name = "H263 Encoded Stream",
+		.fourcc = V4L2_PIX_FMT_H263,
+		.codec_mode = S5P_FIMV_CODEC_H263_DEC,
+		.type = MFC_FMT_DEC,
+		.num_planes = 1,
+	},
+	{
+		.name = "MPEG1 Encoded Stream",
+		.fourcc = V4L2_PIX_FMT_MPEG1,
+		.codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
+		.type = MFC_FMT_DEC,
+		.num_planes = 1,
+	},
+	{
+		.name = "MPEG2 Encoded Stream",
+		.fourcc = V4L2_PIX_FMT_MPEG2,
+		.codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
+		.type = MFC_FMT_DEC,
+		.num_planes = 1,
+	},
+	{
+		.name = "MPEG4 Encoded Stream",
+		.fourcc = V4L2_PIX_FMT_MPEG4,
+		.codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
+		.type = MFC_FMT_DEC,
+		.num_planes = 1,
+	},
+	{
+		.name = "XviD Encoded Stream",
+		.fourcc = V4L2_PIX_FMT_XVID,
+		.codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
+		.type = MFC_FMT_DEC,
+		.num_planes = 1,
+	},
+	{
+		.name = "VC1 Encoded Stream",
+		.fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
+		.codec_mode = S5P_FIMV_CODEC_VC1_DEC,
+		.type = MFC_FMT_DEC,
+		.num_planes = 1,
+	},
+	{
+		.name = "VC1 RCV Encoded Stream",
+		.fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
+		.codec_mode = S5P_FIMV_CODEC_VC1RCV_DEC,
+		.type = MFC_FMT_DEC,
+		.num_planes = 1,
+	},
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+/* Find selected format description */
+static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t)
+{
+	unsigned int i;
+
+	for (i = 0; i < NUM_FORMATS; i++) {
+		if (formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
+		    formats[i].type == t)
+			return &formats[i];
+	}
+	return NULL;
+}
+
+static struct mfc_control controls[] = {
+	{
+		.id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "H264 Display Delay",
+		.minimum = 0,
+		.maximum = 16383,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "H264 Display Delay Enable",
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "Mpeg4 Loop Filter Enable",
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "Slice Interface Enable",
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Minimum number of cap bufs",
+		.minimum = 1,
+		.maximum = 32,
+		.step = 1,
+		.default_value = 1,
+		.is_volatile = 1,
+	},
+};
+
+#define NUM_CTRLS ARRAY_SIZE(controls)
+
+/* Check whether a context should be run on hardware */
+static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
+{
+	/* Context is to parse header */
+	if (ctx->src_queue_cnt >= 1 && ctx->state == MFCINST_GOT_INST)
+		return 1;
+	/* Context is to decode a frame */
+	if (ctx->src_queue_cnt >= 1 &&
+	    ctx->state == MFCINST_RUNNING &&
+	    ctx->dst_queue_cnt >= ctx->dpb_count)
+		return 1;
+	/* Context is to return last frame */
+	if (ctx->state == MFCINST_FINISHING &&
+	    ctx->dst_queue_cnt >= ctx->dpb_count)
+		return 1;
+	/* Context is to set buffers */
+	if (ctx->src_queue_cnt >= 1 &&
+	    ctx->state == MFCINST_HEAD_PARSED &&
+	    ctx->capture_state == QUEUE_BUFS_MMAPED)
+		return 1;
+	/* Resolution change */
+	if ((ctx->state == MFCINST_RES_CHANGE_INIT ||
+		ctx->state == MFCINST_RES_CHANGE_FLUSH) &&
+		ctx->dst_queue_cnt >= ctx->dpb_count)
+		return 1;
+	if (ctx->state == MFCINST_RES_CHANGE_END &&
+		ctx->src_queue_cnt >= 1)
+		return 1;
+	mfc_debug(2, "ctx is not ready\n");
+	return 0;
+}
+
+static struct s5p_mfc_codec_ops decoder_codec_ops = {
+	.pre_seq_start		= NULL,
+	.post_seq_start		= NULL,
+	.pre_frame_start	= NULL,
+	.post_frame_start	= NULL,
+};
+
+/* Query capabilities of the device */
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	struct s5p_mfc_dev *dev = video_drvdata(file);
+
+	strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
+	strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
+	cap->bus_info[0] = 0;
+	cap->version = KERNEL_VERSION(1, 0, 0);
+	/*
+	 * This is only a mem-to-mem video device. The capture and output
+	 * device capability flags are left only for backward compatibility
+	 * and are scheduled for removal.
+	 */
+	cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING |
+			    V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+			    V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+	return 0;
+}
+
+/* Enumerate format */
+static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
+{
+	struct s5p_mfc_fmt *fmt;
+	int i, j = 0;
+
+	for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+		if (mplane && formats[i].num_planes == 1)
+			continue;
+		else if (!mplane && formats[i].num_planes > 1)
+			continue;
+		if (out && formats[i].type != MFC_FMT_DEC)
+			continue;
+		else if (!out && formats[i].type != MFC_FMT_RAW)
+			continue;
+
+		if (j == f->index)
+			break;
+		++j;
+	}
+	if (i == ARRAY_SIZE(formats))
+		return -EINVAL;
+	fmt = &formats[i];
+	strlcpy(f->description, fmt->name, sizeof(f->description));
+	f->pixelformat = fmt->fourcc;
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
+							struct v4l2_fmtdesc *f)
+{
+	return vidioc_enum_fmt(f, false, false);
+}
+
+static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
+							struct v4l2_fmtdesc *f)
+{
+	return vidioc_enum_fmt(f, true, false);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *prov,
+							struct v4l2_fmtdesc *f)
+{
+	return vidioc_enum_fmt(f, false, true);
+}
+
+static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
+							struct v4l2_fmtdesc *f)
+{
+	return vidioc_enum_fmt(f, true, true);
+}
+
+/* Get format */
+static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+	struct v4l2_pix_format_mplane *pix_mp;
+
+	mfc_debug_enter();
+	pix_mp = &f->fmt.pix_mp;
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+	    (ctx->state == MFCINST_GOT_INST || ctx->state ==
+						MFCINST_RES_CHANGE_END)) {
+		/* If the MFC is parsing the header,
+		 * so wait until it is finished */
+		s5p_mfc_clean_ctx_int_flags(ctx);
+		s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_SEQ_DONE_RET,
+									0);
+	}
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+	    ctx->state >= MFCINST_HEAD_PARSED &&
+	    ctx->state < MFCINST_ABORT) {
+		/* This is run on CAPTURE (decode output) */
+		/* Width and height are set to the dimensions
+		   of the movie, the buffer is bigger and
+		   further processing stages should crop to this
+		   rectangle. */
+		pix_mp->width = ctx->buf_width;
+		pix_mp->height = ctx->buf_height;
+		pix_mp->field = V4L2_FIELD_NONE;
+		pix_mp->num_planes = 2;
+		/* Set pixelformat to the format in which MFC
+		   outputs the decoded frame */
+		pix_mp->pixelformat = V4L2_PIX_FMT_NV12MT;
+		pix_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+		pix_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+		pix_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+		pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		/* This is run on OUTPUT
+		   The buffer contains compressed image
+		   so width and height have no meaning */
+		pix_mp->width = 0;
+		pix_mp->height = 0;
+		pix_mp->field = V4L2_FIELD_NONE;
+		pix_mp->plane_fmt[0].bytesperline = ctx->dec_src_buf_size;
+		pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size;
+		pix_mp->pixelformat = ctx->src_fmt->fourcc;
+		pix_mp->num_planes = ctx->src_fmt->num_planes;
+	} else {
+		mfc_err("Format could not be read\n");
+		mfc_debug(2, "%s-- with error\n", __func__);
+		return -EINVAL;
+	}
+	mfc_debug_leave();
+	return 0;
+}
+
+/* Try format */
+static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+	struct s5p_mfc_fmt *fmt;
+
+	if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		mfc_err("This node supports decoding only\n");
+		return -EINVAL;
+	}
+	fmt = find_format(f, MFC_FMT_DEC);
+	if (!fmt) {
+		mfc_err("Unsupported format\n");
+		return -EINVAL;
+	}
+	if (fmt->type != MFC_FMT_DEC) {
+		mfc_err("\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* Set format */
+static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+	struct s5p_mfc_dev *dev = video_drvdata(file);
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+	int ret = 0;
+	struct s5p_mfc_fmt *fmt;
+	struct v4l2_pix_format_mplane *pix_mp;
+
+	mfc_debug_enter();
+	ret = vidioc_try_fmt(file, priv, f);
+	pix_mp = &f->fmt.pix_mp;
+	if (ret)
+		return ret;
+	if (ctx->vq_src.streaming || ctx->vq_dst.streaming) {
+		v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
+		ret = -EBUSY;
+		goto out;
+	}
+	fmt = find_format(f, MFC_FMT_DEC);
+	if (!fmt || fmt->codec_mode == S5P_FIMV_CODEC_NONE) {
+		mfc_err("Unknown codec\n");
+		ret = -EINVAL;
+		goto out;
+	}
+	if (fmt->type != MFC_FMT_DEC) {
+		mfc_err("Wrong format selected, you should choose "
+					"format for decoding\n");
+		ret = -EINVAL;
+		goto out;
+	}
+	ctx->src_fmt = fmt;
+	ctx->codec_mode = fmt->codec_mode;
+	mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode);
+	pix_mp->height = 0;
+	pix_mp->width = 0;
+	if (pix_mp->plane_fmt[0].sizeimage)
+		ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage;
+	else
+		pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size =
+								DEF_CPB_SIZE;
+	pix_mp->plane_fmt[0].bytesperline = 0;
+	ctx->state = MFCINST_INIT;
+out:
+	mfc_debug_leave();
+	return ret;
+}
+
+/* Reqeust buffers */
+static int vidioc_reqbufs(struct file *file, void *priv,
+					  struct v4l2_requestbuffers *reqbufs)
+{
+	struct s5p_mfc_dev *dev = video_drvdata(file);
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+	int ret = 0;
+	unsigned long flags;
+
+	if (reqbufs->memory != V4L2_MEMORY_MMAP) {
+		mfc_err("Only V4L2_MEMORY_MAP is supported\n");
+		return -EINVAL;
+	}
+	if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		/* Can only request buffers after an instance has been opened.*/
+		if (ctx->state == MFCINST_INIT) {
+			ctx->src_bufs_cnt = 0;
+			if (reqbufs->count == 0) {
+				mfc_debug(2, "Freeing buffers\n");
+				s5p_mfc_clock_on();
+				ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+				s5p_mfc_clock_off();
+				return ret;
+			}
+			/* Decoding */
+			if (ctx->output_state != QUEUE_FREE) {
+				mfc_err("Bufs have already been requested\n");
+				return -EINVAL;
+			}
+			s5p_mfc_clock_on();
+			ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+			s5p_mfc_clock_off();
+			if (ret) {
+				mfc_err("vb2_reqbufs on output failed\n");
+				return ret;
+			}
+			mfc_debug(2, "vb2_reqbufs: %d\n", ret);
+			ctx->output_state = QUEUE_BUFS_REQUESTED;
+		}
+	} else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		ctx->dst_bufs_cnt = 0;
+		if (reqbufs->count == 0) {
+			mfc_debug(2, "Freeing buffers\n");
+			s5p_mfc_clock_on();
+			ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+			s5p_mfc_clock_off();
+			return ret;
+		}
+		if (ctx->capture_state != QUEUE_FREE) {
+			mfc_err("Bufs have already been requested\n");
+			return -EINVAL;
+		}
+		ctx->capture_state = QUEUE_BUFS_REQUESTED;
+		s5p_mfc_clock_on();
+		ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+		s5p_mfc_clock_off();
+		if (ret) {
+			mfc_err("vb2_reqbufs on capture failed\n");
+			return ret;
+		}
+		if (reqbufs->count < ctx->dpb_count) {
+			mfc_err("Not enough buffers allocated\n");
+			reqbufs->count = 0;
+			s5p_mfc_clock_on();
+			ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+			s5p_mfc_clock_off();
+			return -ENOMEM;
+		}
+		ctx->total_dpb_count = reqbufs->count;
+		ret = s5p_mfc_alloc_codec_buffers(ctx);
+		if (ret) {
+			mfc_err("Failed to allocate decoding buffers\n");
+			reqbufs->count = 0;
+			s5p_mfc_clock_on();
+			ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+			s5p_mfc_clock_off();
+			return -ENOMEM;
+		}
+		if (ctx->dst_bufs_cnt == ctx->total_dpb_count) {
+			ctx->capture_state = QUEUE_BUFS_MMAPED;
+		} else {
+			mfc_err("Not all buffers passed to buf_init\n");
+			reqbufs->count = 0;
+			s5p_mfc_clock_on();
+			ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+			s5p_mfc_release_codec_buffers(ctx);
+			s5p_mfc_clock_off();
+			return -ENOMEM;
+		}
+		if (s5p_mfc_ctx_ready(ctx)) {
+			spin_lock_irqsave(&dev->condlock, flags);
+			set_bit(ctx->num, &dev->ctx_work_bits);
+			spin_unlock_irqrestore(&dev->condlock, flags);
+		}
+		s5p_mfc_try_run(dev);
+		s5p_mfc_wait_for_done_ctx(ctx,
+					 S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET, 0);
+	}
+	return ret;
+}
+
+/* Query buffer */
+static int vidioc_querybuf(struct file *file, void *priv,
+						   struct v4l2_buffer *buf)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+	int ret;
+	int i;
+
+	if (buf->memory != V4L2_MEMORY_MMAP) {
+		mfc_err("Only mmaped buffers can be used\n");
+		return -EINVAL;
+	}
+	mfc_debug(2, "State: %d, buf->type: %d\n", ctx->state, buf->type);
+	if (ctx->state == MFCINST_INIT &&
+			buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		ret = vb2_querybuf(&ctx->vq_src, buf);
+	} else if (ctx->state == MFCINST_RUNNING &&
+			buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		ret = vb2_querybuf(&ctx->vq_dst, buf);
+		for (i = 0; i < buf->length; i++)
+			buf->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE;
+	} else {
+		mfc_err("vidioc_querybuf called in an inappropriate state\n");
+		ret = -EINVAL;
+	}
+	mfc_debug_leave();
+	return ret;
+}
+
+/* Queue a buffer */
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+	if (ctx->state == MFCINST_ERROR) {
+		mfc_err("Call on QBUF after unrecoverable error\n");
+		return -EIO;
+	}
+	if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return vb2_qbuf(&ctx->vq_src, buf);
+	else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return vb2_qbuf(&ctx->vq_dst, buf);
+	return -EINVAL;
+}
+
+/* Dequeue a buffer */
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+	if (ctx->state == MFCINST_ERROR) {
+		mfc_err("Call on DQBUF after unrecoverable error\n");
+		return -EIO;
+	}
+	if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
+	else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
+	return -EINVAL;
+}
+
+/* Stream on */
+static int vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type type)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+	struct s5p_mfc_dev *dev = ctx->dev;
+	unsigned long flags;
+	int ret = -EINVAL;
+
+	mfc_debug_enter();
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+
+		if (ctx->state == MFCINST_INIT) {
+			ctx->dst_bufs_cnt = 0;
+			ctx->src_bufs_cnt = 0;
+			ctx->capture_state = QUEUE_FREE;
+			ctx->output_state = QUEUE_FREE;
+			s5p_mfc_alloc_instance_buffer(ctx);
+			s5p_mfc_alloc_dec_temp_buffers(ctx);
+			spin_lock_irqsave(&dev->condlock, flags);
+			set_bit(ctx->num, &dev->ctx_work_bits);
+			spin_unlock_irqrestore(&dev->condlock, flags);
+			s5p_mfc_clean_ctx_int_flags(ctx);
+			s5p_mfc_try_run(dev);
+
+			if (s5p_mfc_wait_for_done_ctx(ctx,
+				S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 0)) {
+				/* Error or timeout */
+				mfc_err("Error getting instance from hardware\n");
+				s5p_mfc_release_instance_buffer(ctx);
+				s5p_mfc_release_dec_desc_buffer(ctx);
+				return -EIO;
+			}
+			mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
+		}
+		ret = vb2_streamon(&ctx->vq_src, type);
+		}
+	else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		ret = vb2_streamon(&ctx->vq_dst, type);
+	mfc_debug_leave();
+	return ret;
+}
+
+/* Stream off, which equals to a pause */
+static int vidioc_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type type)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return vb2_streamoff(&ctx->vq_src, type);
+	else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return vb2_streamoff(&ctx->vq_dst, type);
+	return -EINVAL;
+}
+
+/* Set controls - v4l2 control framework */
+static int s5p_mfc_dec_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY:
+		ctx->display_delay = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE:
+		ctx->display_delay_enable = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
+		ctx->loop_filter_mpeg4 = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
+		ctx->slice_interface = ctrl->val;
+		break;
+	default:
+		mfc_err("Invalid control 0x%08x\n", ctrl->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	switch (ctrl->id) {
+	case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+		if (ctx->state >= MFCINST_HEAD_PARSED &&
+		    ctx->state < MFCINST_ABORT) {
+			ctrl->val = ctx->dpb_count;
+			break;
+		} else if (ctx->state != MFCINST_INIT) {
+			v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n");
+			return -EINVAL;
+		}
+		/* Should wait for the header to be parsed */
+		s5p_mfc_clean_ctx_int_flags(ctx);
+		s5p_mfc_wait_for_done_ctx(ctx,
+				S5P_FIMV_R2H_CMD_SEQ_DONE_RET, 0);
+		if (ctx->state >= MFCINST_HEAD_PARSED &&
+		    ctx->state < MFCINST_ABORT) {
+			ctrl->val = ctx->dpb_count;
+		} else {
+			v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n");
+			return -EINVAL;
+		}
+		break;
+	}
+	return 0;
+}
+
+
+static const struct v4l2_ctrl_ops s5p_mfc_dec_ctrl_ops = {
+	.s_ctrl = s5p_mfc_dec_s_ctrl,
+	.g_volatile_ctrl = s5p_mfc_dec_g_v_ctrl,
+};
+
+/* Get cropping information */
+static int vidioc_g_crop(struct file *file, void *priv,
+		struct v4l2_crop *cr)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+	u32 left, right, top, bottom;
+
+	if (ctx->state != MFCINST_HEAD_PARSED &&
+	ctx->state != MFCINST_RUNNING && ctx->state != MFCINST_FINISHING
+					&& ctx->state != MFCINST_FINISHED) {
+			mfc_err("Cannont set crop\n");
+			return -EINVAL;
+		}
+	if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) {
+		left = s5p_mfc_read_shm(ctx, CROP_INFO_H);
+		right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT;
+		left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK;
+		top = s5p_mfc_read_shm(ctx, CROP_INFO_V);
+		bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT;
+		top = top & S5P_FIMV_SHARED_CROP_TOP_MASK;
+		cr->c.left = left;
+		cr->c.top = top;
+		cr->c.width = ctx->img_width - left - right;
+		cr->c.height = ctx->img_height - top - bottom;
+		mfc_debug(2, "Cropping info [h264]: l=%d t=%d "
+			"w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", left, top,
+			cr->c.width, cr->c.height, right, bottom,
+			ctx->buf_width, ctx->buf_height);
+	} else {
+		cr->c.left = 0;
+		cr->c.top = 0;
+		cr->c.width = ctx->img_width;
+		cr->c.height = ctx->img_height;
+		mfc_debug(2, "Cropping info: w=%d h=%d fw=%d "
+			"fh=%d\n", cr->c.width,	cr->c.height, ctx->buf_width,
+							ctx->buf_height);
+	}
+	return 0;
+}
+
+/* v4l2_ioctl_ops */
+static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
+	.vidioc_querycap = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
+	.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+	.vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
+	.vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
+	.vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
+	.vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
+	.vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
+	.vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt,
+	.vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt,
+	.vidioc_reqbufs = vidioc_reqbufs,
+	.vidioc_querybuf = vidioc_querybuf,
+	.vidioc_qbuf = vidioc_qbuf,
+	.vidioc_dqbuf = vidioc_dqbuf,
+	.vidioc_streamon = vidioc_streamon,
+	.vidioc_streamoff = vidioc_streamoff,
+	.vidioc_g_crop = vidioc_g_crop,
+};
+
+static int s5p_mfc_queue_setup(struct vb2_queue *vq,
+			const struct v4l2_format *fmt, unsigned int *buf_count,
+			unsigned int *plane_count, unsigned int psize[],
+			void *allocators[])
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+
+	/* Video output for decoding (source)
+	 * this can be set after getting an instance */
+	if (ctx->state == MFCINST_INIT &&
+	    vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		/* A single plane is required for input */
+		*plane_count = 1;
+		if (*buf_count < 1)
+			*buf_count = 1;
+		if (*buf_count > MFC_MAX_BUFFERS)
+			*buf_count = MFC_MAX_BUFFERS;
+	/* Video capture for decoding (destination)
+	 * this can be set after the header was parsed */
+	} else if (ctx->state == MFCINST_HEAD_PARSED &&
+		   vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		/* Output plane count is 2 - one for Y and one for CbCr */
+		*plane_count = 2;
+		/* Setup buffer count */
+		if (*buf_count < ctx->dpb_count)
+			*buf_count = ctx->dpb_count;
+		if (*buf_count > ctx->dpb_count + MFC_MAX_EXTRA_DPB)
+			*buf_count = ctx->dpb_count + MFC_MAX_EXTRA_DPB;
+		if (*buf_count > MFC_MAX_BUFFERS)
+			*buf_count = MFC_MAX_BUFFERS;
+	} else {
+		mfc_err("State seems invalid. State = %d, vq->type = %d\n",
+							ctx->state, vq->type);
+		return -EINVAL;
+	}
+	mfc_debug(2, "Buffer count=%d, plane count=%d\n",
+						*buf_count, *plane_count);
+	if (ctx->state == MFCINST_HEAD_PARSED &&
+	    vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		psize[0] = ctx->luma_size;
+		psize[1] = ctx->chroma_size;
+		allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
+		allocators[1] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
+	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+		   ctx->state == MFCINST_INIT) {
+		psize[0] = ctx->dec_src_buf_size;
+		allocators[0] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
+	} else {
+		mfc_err("This video node is dedicated to decoding. Decoding not initalised\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void s5p_mfc_unlock(struct vb2_queue *q)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	mutex_unlock(&dev->mfc_mutex);
+}
+
+static void s5p_mfc_lock(struct vb2_queue *q)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	mutex_lock(&dev->mfc_mutex);
+}
+
+static int s5p_mfc_buf_init(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+	unsigned int i;
+
+	if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		if (ctx->capture_state == QUEUE_BUFS_MMAPED)
+			return 0;
+		for (i = 0; i <= ctx->src_fmt->num_planes ; i++) {
+			if (IS_ERR_OR_NULL(ERR_PTR(
+					vb2_dma_contig_plane_dma_addr(vb, i)))) {
+				mfc_err("Plane mem not allocated\n");
+				return -EINVAL;
+			}
+		}
+		if (vb2_plane_size(vb, 0) < ctx->luma_size ||
+			vb2_plane_size(vb, 1) < ctx->chroma_size) {
+			mfc_err("Plane buffer (CAPTURE) is too small\n");
+			return -EINVAL;
+		}
+		i = vb->v4l2_buf.index;
+		ctx->dst_bufs[i].b = vb;
+		ctx->dst_bufs[i].cookie.raw.luma =
+					vb2_dma_contig_plane_dma_addr(vb, 0);
+		ctx->dst_bufs[i].cookie.raw.chroma =
+					vb2_dma_contig_plane_dma_addr(vb, 1);
+		ctx->dst_bufs_cnt++;
+	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		if (IS_ERR_OR_NULL(ERR_PTR(
+					vb2_dma_contig_plane_dma_addr(vb, 0)))) {
+			mfc_err("Plane memory not allocated\n");
+			return -EINVAL;
+		}
+		if (vb2_plane_size(vb, 0) < ctx->dec_src_buf_size) {
+			mfc_err("Plane buffer (OUTPUT) is too small\n");
+			return -EINVAL;
+		}
+
+		i = vb->v4l2_buf.index;
+		ctx->src_bufs[i].b = vb;
+		ctx->src_bufs[i].cookie.stream =
+					vb2_dma_contig_plane_dma_addr(vb, 0);
+		ctx->src_bufs_cnt++;
+	} else {
+		mfc_err("s5p_mfc_buf_init: unknown queue type\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+	struct s5p_mfc_dev *dev = ctx->dev;
+	unsigned long flags;
+
+	v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+	if (ctx->state == MFCINST_FINISHING ||
+		ctx->state == MFCINST_FINISHED)
+		ctx->state = MFCINST_RUNNING;
+	/* If context is ready then dev = work->data;schedule it to run */
+	if (s5p_mfc_ctx_ready(ctx)) {
+		spin_lock_irqsave(&dev->condlock, flags);
+		set_bit(ctx->num, &dev->ctx_work_bits);
+		spin_unlock_irqrestore(&dev->condlock, flags);
+	}
+	s5p_mfc_try_run(dev);
+	return 0;
+}
+
+static int s5p_mfc_stop_streaming(struct vb2_queue *q)
+{
+	unsigned long flags;
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+	struct s5p_mfc_dev *dev = ctx->dev;
+	int aborted = 0;
+
+	if ((ctx->state == MFCINST_FINISHING ||
+		ctx->state ==  MFCINST_RUNNING) &&
+		dev->curr_ctx == ctx->num && dev->hw_lock) {
+		ctx->state = MFCINST_ABORT;
+		s5p_mfc_wait_for_done_ctx(ctx,
+					S5P_FIMV_R2H_CMD_FRAME_DONE_RET, 0);
+		aborted = 1;
+	}
+	spin_lock_irqsave(&dev->irqlock, flags);
+	if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+		INIT_LIST_HEAD(&ctx->dst_queue);
+		ctx->dst_queue_cnt = 0;
+		ctx->dpb_flush_flag = 1;
+		ctx->dec_dst_flag = 0;
+	}
+	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+		INIT_LIST_HEAD(&ctx->src_queue);
+		ctx->src_queue_cnt = 0;
+	}
+	if (aborted)
+		ctx->state = MFCINST_RUNNING;
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+	return 0;
+}
+
+
+static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+	struct s5p_mfc_dev *dev = ctx->dev;
+	unsigned long flags;
+	struct s5p_mfc_buf *mfc_buf;
+
+	if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index];
+		mfc_buf->used = 0;
+		spin_lock_irqsave(&dev->irqlock, flags);
+		list_add_tail(&mfc_buf->list, &ctx->src_queue);
+		ctx->src_queue_cnt++;
+		spin_unlock_irqrestore(&dev->irqlock, flags);
+	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index];
+		mfc_buf->used = 0;
+		/* Mark destination as available for use by MFC */
+		spin_lock_irqsave(&dev->irqlock, flags);
+		set_bit(vb->v4l2_buf.index, &ctx->dec_dst_flag);
+		list_add_tail(&mfc_buf->list, &ctx->dst_queue);
+		ctx->dst_queue_cnt++;
+		spin_unlock_irqrestore(&dev->irqlock, flags);
+	} else {
+		mfc_err("Unsupported buffer type (%d)\n", vq->type);
+	}
+	if (s5p_mfc_ctx_ready(ctx)) {
+		spin_lock_irqsave(&dev->condlock, flags);
+		set_bit(ctx->num, &dev->ctx_work_bits);
+		spin_unlock_irqrestore(&dev->condlock, flags);
+	}
+	s5p_mfc_try_run(dev);
+}
+
+static struct vb2_ops s5p_mfc_dec_qops = {
+	.queue_setup		= s5p_mfc_queue_setup,
+	.wait_prepare		= s5p_mfc_unlock,
+	.wait_finish		= s5p_mfc_lock,
+	.buf_init		= s5p_mfc_buf_init,
+	.start_streaming	= s5p_mfc_start_streaming,
+	.stop_streaming		= s5p_mfc_stop_streaming,
+	.buf_queue		= s5p_mfc_buf_queue,
+};
+
+struct s5p_mfc_codec_ops *get_dec_codec_ops(void)
+{
+	return &decoder_codec_ops;
+}
+
+struct vb2_ops *get_dec_queue_ops(void)
+{
+	return &s5p_mfc_dec_qops;
+}
+
+const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void)
+{
+	return &s5p_mfc_dec_ioctl_ops;
+}
+
+#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \
+						&& V4L2_CTRL_DRIVER_PRIV(x))
+
+int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx)
+{
+	struct v4l2_ctrl_config cfg;
+	int i;
+
+	v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS);
+	if (ctx->ctrl_handler.error) {
+		mfc_err("v4l2_ctrl_handler_init failed\n");
+		return ctx->ctrl_handler.error;
+	}
+
+	for (i = 0; i < NUM_CTRLS; i++) {
+		if (IS_MFC51_PRIV(controls[i].id)) {
+			memset(&cfg, 0, sizeof(struct v4l2_ctrl_config));
+			cfg.ops = &s5p_mfc_dec_ctrl_ops;
+			cfg.id = controls[i].id;
+			cfg.min = controls[i].minimum;
+			cfg.max = controls[i].maximum;
+			cfg.def = controls[i].default_value;
+			cfg.name = controls[i].name;
+			cfg.type = controls[i].type;
+
+			cfg.step = controls[i].step;
+			cfg.menu_skip_mask = 0;
+
+			ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+					&cfg, NULL);
+		} else {
+			ctx->ctrls[i] = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+					&s5p_mfc_dec_ctrl_ops,
+					controls[i].id, controls[i].minimum,
+					controls[i].maximum, controls[i].step,
+					controls[i].default_value);
+		}
+		if (ctx->ctrl_handler.error) {
+			mfc_err("Adding control (%d) failed\n", i);
+			return ctx->ctrl_handler.error;
+		}
+		if (controls[i].is_volatile && ctx->ctrls[i])
+			ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE;
+	}
+	return 0;
+}
+
+void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx)
+{
+	int i;
+
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+	for (i = 0; i < NUM_CTRLS; i++)
+		ctx->ctrls[i] = NULL;
+}
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h
new file mode 100644
index 0000000..fdf1d99
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h
@@ -0,0 +1,23 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef S5P_MFC_DEC_H_
+#define S5P_MFC_DEC_H_
+
+struct s5p_mfc_codec_ops *get_dec_codec_ops(void);
+struct vb2_ops *get_dec_queue_ops(void);
+const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void);
+struct s5p_mfc_fmt *get_dec_def_fmt(bool src);
+int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx);
+
+#endif /* S5P_MFC_DEC_H_ */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
new file mode 100644
index 0000000..fdeebb0
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -0,0 +1,1834 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * Jeongtae Park	<jtp.park@samsung.com>
+ * Kamil Debski		<k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_enc.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_opr.h"
+
+static struct s5p_mfc_fmt formats[] = {
+	{
+		.name = "4:2:0 2 Planes 64x32 Tiles",
+		.fourcc = V4L2_PIX_FMT_NV12MT,
+		.codec_mode = S5P_FIMV_CODEC_NONE,
+		.type = MFC_FMT_RAW,
+		.num_planes = 2,
+	},
+	{
+		.name = "4:2:0 2 Planes",
+		.fourcc = V4L2_PIX_FMT_NV12M,
+		.codec_mode = S5P_FIMV_CODEC_NONE,
+		.type = MFC_FMT_RAW,
+		.num_planes = 2,
+	},
+	{
+		.name = "H264 Encoded Stream",
+		.fourcc = V4L2_PIX_FMT_H264,
+		.codec_mode = S5P_FIMV_CODEC_H264_ENC,
+		.type = MFC_FMT_ENC,
+		.num_planes = 1,
+	},
+	{
+		.name = "MPEG4 Encoded Stream",
+		.fourcc = V4L2_PIX_FMT_MPEG4,
+		.codec_mode = S5P_FIMV_CODEC_MPEG4_ENC,
+		.type = MFC_FMT_ENC,
+		.num_planes = 1,
+	},
+	{
+		.name = "H263 Encoded Stream",
+		.fourcc = V4L2_PIX_FMT_H263,
+		.codec_mode = S5P_FIMV_CODEC_H263_ENC,
+		.type = MFC_FMT_ENC,
+		.num_planes = 1,
+	},
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t)
+{
+	unsigned int i;
+
+	for (i = 0; i < NUM_FORMATS; i++) {
+		if (formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
+		    formats[i].type == t)
+			return &formats[i];
+	}
+	return NULL;
+}
+
+static struct mfc_control controls[] = {
+	{
+		.id = V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = (1 << 16) - 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+		.maximum = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES,
+		.default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = (1 << 16) - 1,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1900,
+		.maximum = (1 << 30) - 1,
+		.step = 1,
+		.default_value = 1900,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = (1 << 16) - 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "Padding Control Enable",
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Padding Color YUV Value",
+		.minimum = 0,
+		.maximum = (1 << 25) - 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_BITRATE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = (1 << 30) - 1,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Rate Control Reaction Coeff.",
+		.minimum = 1,
+		.maximum = (1 << 16) - 1,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.name = "Force frame type",
+		.minimum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
+		.maximum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED,
+		.default_value = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VBV_SIZE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = (1 << 16) - 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = (1 << 16) - 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+		.maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
+		.default_value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.name = "Frame Skip Enable",
+		.minimum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
+		.maximum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
+		.menu_skip_mask = 0,
+		.default_value = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
+	},
+	{
+		.id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "Fixed Target Bit Enable",
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_B_FRAMES,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 2,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+		.maximum = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH,
+		.default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+		.menu_skip_mask = ~(
+				(1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
+				(1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
+				(1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)
+				),
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+		.maximum = V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
+		.default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+		.maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
+		.default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+		.maximum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY,
+		.default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = -6,
+		.maximum = 6,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = -6,
+		.maximum = 6,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+		.maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+		.default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "The Number of Ref. Pic for P",
+		.minimum = 1,
+		.maximum = 2,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 51,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 51,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 51,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 51,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 51,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "H263 I-Frame QP value",
+		.minimum = 1,
+		.maximum = 31,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "H263 Minimum QP value",
+		.minimum = 1,
+		.maximum = 31,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "H263 Maximum QP value",
+		.minimum = 1,
+		.maximum = 31,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "H263 P frame QP value",
+		.minimum = 1,
+		.maximum = 31,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "H263 B frame QP value",
+		.minimum = 1,
+		.maximum = 31,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "MPEG4 I-Frame QP value",
+		.minimum = 1,
+		.maximum = 31,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "MPEG4 Minimum QP value",
+		.minimum = 1,
+		.maximum = 31,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "MPEG4 Maximum QP value",
+		.minimum = 0,
+		.maximum = 51,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "MPEG4 P frame QP value",
+		.minimum = 1,
+		.maximum = 31,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "MPEG4 B frame QP value",
+		.minimum = 1,
+		.maximum = 31,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "H264 Dark Reg Adaptive RC",
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "H264 Smooth Reg Adaptive RC",
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "H264 Static Reg Adaptive RC",
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "H264 Activity Reg Adaptive RC",
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED,
+		.maximum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED,
+		.default_value = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = (1 << 16) - 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = (1 << 16) - 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = (1 << 16) - 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+		.maximum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE,
+		.default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_QPEL,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+};
+
+#define NUM_CTRLS ARRAY_SIZE(controls)
+static const char * const *mfc51_get_menu(u32 id)
+{
+	static const char * const mfc51_video_frame_skip[] = {
+		"Disabled",
+		"Level Limit",
+		"VBV/CPB Limit",
+		NULL,
+	};
+	static const char * const mfc51_video_force_frame[] = {
+		"Disabled",
+		"I Frame",
+		"Not Coded",
+		NULL,
+	};
+	switch (id) {
+	case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE:
+		return mfc51_video_frame_skip;
+	case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
+		return mfc51_video_force_frame;
+	}
+	return NULL;
+}
+
+static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
+{
+	mfc_debug(2, "src=%d, dst=%d, state=%d\n",
+		  ctx->src_queue_cnt, ctx->dst_queue_cnt, ctx->state);
+	/* context is ready to make header */
+	if (ctx->state == MFCINST_GOT_INST && ctx->dst_queue_cnt >= 1)
+		return 1;
+	/* context is ready to encode a frame */
+	if (ctx->state == MFCINST_RUNNING &&
+		ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1)
+		return 1;
+	/* context is ready to encode remain frames */
+	if (ctx->state == MFCINST_FINISHING &&
+		ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1)
+		return 1;
+	mfc_debug(2, "ctx is not ready\n");
+	return 0;
+}
+
+static void cleanup_ref_queue(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_buf *mb_entry;
+	unsigned long mb_y_addr, mb_c_addr;
+
+	/* move buffers in ref queue to src queue */
+	while (!list_empty(&ctx->ref_queue)) {
+		mb_entry = list_entry((&ctx->ref_queue)->next,
+						struct s5p_mfc_buf, list);
+		mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0);
+		mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1);
+		list_del(&mb_entry->list);
+		ctx->ref_queue_cnt--;
+		list_add_tail(&mb_entry->list, &ctx->src_queue);
+		ctx->src_queue_cnt++;
+	}
+	mfc_debug(2, "enc src count: %d, enc ref count: %d\n",
+		  ctx->src_queue_cnt, ctx->ref_queue_cnt);
+	INIT_LIST_HEAD(&ctx->ref_queue);
+	ctx->ref_queue_cnt = 0;
+}
+
+static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	struct s5p_mfc_buf *dst_mb;
+	unsigned long dst_addr;
+	unsigned int dst_size;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->irqlock, flags);
+	dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+	dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
+	dst_size = vb2_plane_size(dst_mb->b, 0);
+	s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+	return 0;
+}
+
+static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	struct s5p_mfc_enc_params *p = &ctx->enc_params;
+	struct s5p_mfc_buf *dst_mb;
+	unsigned long flags;
+
+	if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) {
+		spin_lock_irqsave(&dev->irqlock, flags);
+		dst_mb = list_entry(ctx->dst_queue.next,
+				struct s5p_mfc_buf, list);
+		list_del(&dst_mb->list);
+		ctx->dst_queue_cnt--;
+		vb2_set_plane_payload(dst_mb->b, 0,
+						s5p_mfc_get_enc_strm_size());
+		vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE);
+		spin_unlock_irqrestore(&dev->irqlock, flags);
+	}
+	ctx->state = MFCINST_RUNNING;
+	if (s5p_mfc_ctx_ready(ctx)) {
+		spin_lock_irqsave(&dev->condlock, flags);
+		set_bit(ctx->num, &dev->ctx_work_bits);
+		spin_unlock_irqrestore(&dev->condlock, flags);
+	}
+	s5p_mfc_try_run(dev);
+	return 0;
+}
+
+static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	struct s5p_mfc_buf *dst_mb;
+	struct s5p_mfc_buf *src_mb;
+	unsigned long flags;
+	unsigned long src_y_addr, src_c_addr, dst_addr;
+	unsigned int dst_size;
+
+	spin_lock_irqsave(&dev->irqlock, flags);
+	src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+	src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0);
+	src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1);
+	s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr);
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+
+	spin_lock_irqsave(&dev->irqlock, flags);
+	dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+	dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
+	dst_size = vb2_plane_size(dst_mb->b, 0);
+	s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+
+	return 0;
+}
+
+static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	struct s5p_mfc_buf *mb_entry;
+	unsigned long enc_y_addr, enc_c_addr;
+	unsigned long mb_y_addr, mb_c_addr;
+	int slice_type;
+	unsigned int strm_size;
+	unsigned long flags;
+
+	slice_type = s5p_mfc_get_enc_slice_type();
+	strm_size = s5p_mfc_get_enc_strm_size();
+	mfc_debug(2, "Encoded slice type: %d", slice_type);
+	mfc_debug(2, "Encoded stream size: %d", strm_size);
+	mfc_debug(2, "Display order: %d",
+		  mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT));
+	spin_lock_irqsave(&dev->irqlock, flags);
+	if (slice_type >= 0) {
+		s5p_mfc_get_enc_frame_buffer(ctx, &enc_y_addr, &enc_c_addr);
+		list_for_each_entry(mb_entry, &ctx->src_queue, list) {
+			mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0);
+			mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1);
+			if ((enc_y_addr == mb_y_addr) &&
+						(enc_c_addr == mb_c_addr)) {
+				list_del(&mb_entry->list);
+				ctx->src_queue_cnt--;
+				vb2_buffer_done(mb_entry->b,
+							VB2_BUF_STATE_DONE);
+				break;
+			}
+		}
+		list_for_each_entry(mb_entry, &ctx->ref_queue, list) {
+			mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0);
+			mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1);
+			if ((enc_y_addr == mb_y_addr) &&
+						(enc_c_addr == mb_c_addr)) {
+				list_del(&mb_entry->list);
+				ctx->ref_queue_cnt--;
+				vb2_buffer_done(mb_entry->b,
+							VB2_BUF_STATE_DONE);
+				break;
+			}
+		}
+	}
+	if ((ctx->src_queue_cnt > 0) && (ctx->state == MFCINST_RUNNING)) {
+		mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
+									list);
+		if (mb_entry->used) {
+			list_del(&mb_entry->list);
+			ctx->src_queue_cnt--;
+			list_add_tail(&mb_entry->list, &ctx->ref_queue);
+			ctx->ref_queue_cnt++;
+		}
+		mfc_debug(2, "enc src count: %d, enc ref count: %d\n",
+			  ctx->src_queue_cnt, ctx->ref_queue_cnt);
+	}
+	if (strm_size > 0) {
+		/* at least one more dest. buffers exist always  */
+		mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf,
+									list);
+		list_del(&mb_entry->list);
+		ctx->dst_queue_cnt--;
+		switch (slice_type) {
+		case S5P_FIMV_ENC_SI_SLICE_TYPE_I:
+			mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+			break;
+		case S5P_FIMV_ENC_SI_SLICE_TYPE_P:
+			mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+			break;
+		case S5P_FIMV_ENC_SI_SLICE_TYPE_B:
+			mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_BFRAME;
+			break;
+		}
+		vb2_set_plane_payload(mb_entry->b, 0, strm_size);
+		vb2_buffer_done(mb_entry->b, VB2_BUF_STATE_DONE);
+	}
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+	if ((ctx->src_queue_cnt == 0) || (ctx->dst_queue_cnt == 0)) {
+		spin_lock(&dev->condlock);
+		clear_bit(ctx->num, &dev->ctx_work_bits);
+		spin_unlock(&dev->condlock);
+	}
+	return 0;
+}
+
+static struct s5p_mfc_codec_ops encoder_codec_ops = {
+	.pre_seq_start		= enc_pre_seq_start,
+	.post_seq_start		= enc_post_seq_start,
+	.pre_frame_start	= enc_pre_frame_start,
+	.post_frame_start	= enc_post_frame_start,
+};
+
+/* Query capabilities of the device */
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	struct s5p_mfc_dev *dev = video_drvdata(file);
+
+	strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
+	strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
+	cap->bus_info[0] = 0;
+	cap->version = KERNEL_VERSION(1, 0, 0);
+	/*
+	 * This is only a mem-to-mem video device. The capture and output
+	 * device capability flags are left only for backward compatibility
+	 * and are scheduled for removal.
+	 */
+	cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING |
+			    V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+			    V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+	return 0;
+}
+
+static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
+{
+	struct s5p_mfc_fmt *fmt;
+	int i, j = 0;
+
+	for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+		if (mplane && formats[i].num_planes == 1)
+			continue;
+		else if (!mplane && formats[i].num_planes > 1)
+			continue;
+		if (out && formats[i].type != MFC_FMT_RAW)
+			continue;
+		else if (!out && formats[i].type != MFC_FMT_ENC)
+			continue;
+		if (j == f->index) {
+			fmt = &formats[i];
+			strlcpy(f->description, fmt->name,
+				sizeof(f->description));
+			f->pixelformat = fmt->fourcc;
+			return 0;
+		}
+		++j;
+	}
+	return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
+				   struct v4l2_fmtdesc *f)
+{
+	return vidioc_enum_fmt(f, false, false);
+}
+
+static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
+					  struct v4l2_fmtdesc *f)
+{
+	return vidioc_enum_fmt(f, true, false);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *prov,
+				   struct v4l2_fmtdesc *f)
+{
+	return vidioc_enum_fmt(f, false, true);
+}
+
+static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
+					  struct v4l2_fmtdesc *f)
+{
+	return vidioc_enum_fmt(f, true, true);
+}
+
+static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+	struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+
+	mfc_debug(2, "f->type = %d ctx->state = %d\n", f->type, ctx->state);
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		/* This is run on output (encoder dest) */
+		pix_fmt_mp->width = 0;
+		pix_fmt_mp->height = 0;
+		pix_fmt_mp->field = V4L2_FIELD_NONE;
+		pix_fmt_mp->pixelformat = ctx->dst_fmt->fourcc;
+		pix_fmt_mp->num_planes = ctx->dst_fmt->num_planes;
+
+		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->enc_dst_buf_size;
+		pix_fmt_mp->plane_fmt[0].sizeimage = ctx->enc_dst_buf_size;
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		/* This is run on capture (encoder src) */
+		pix_fmt_mp->width = ctx->img_width;
+		pix_fmt_mp->height = ctx->img_height;
+
+		pix_fmt_mp->field = V4L2_FIELD_NONE;
+		pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc;
+		pix_fmt_mp->num_planes = ctx->src_fmt->num_planes;
+
+		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+		pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+		pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+	} else {
+		mfc_err("invalid buf type\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+	struct s5p_mfc_fmt *fmt;
+	struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		fmt = find_format(f, MFC_FMT_ENC);
+		if (!fmt) {
+			mfc_err("failed to try output format\n");
+			return -EINVAL;
+		}
+
+		if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) {
+			mfc_err("must be set encoding output size\n");
+			return -EINVAL;
+		}
+
+		pix_fmt_mp->plane_fmt[0].bytesperline =
+			pix_fmt_mp->plane_fmt[0].sizeimage;
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		fmt = find_format(f, MFC_FMT_RAW);
+		if (!fmt) {
+			mfc_err("failed to try output format\n");
+			return -EINVAL;
+		}
+
+		if (fmt->num_planes != pix_fmt_mp->num_planes) {
+			mfc_err("failed to try output format\n");
+			return -EINVAL;
+		}
+		v4l_bound_align_image(&pix_fmt_mp->width, 8, 1920, 1,
+			&pix_fmt_mp->height, 4, 1080, 1, 0);
+	} else {
+		mfc_err("invalid buf type\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+	struct s5p_mfc_dev *dev = video_drvdata(file);
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+	struct s5p_mfc_fmt *fmt;
+	struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+	unsigned long flags;
+	int ret = 0;
+
+	ret = vidioc_try_fmt(file, priv, f);
+	if (ret)
+		return ret;
+	if (ctx->vq_src.streaming || ctx->vq_dst.streaming) {
+		v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
+		ret = -EBUSY;
+		goto out;
+	}
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		fmt = find_format(f, MFC_FMT_ENC);
+		if (!fmt) {
+			mfc_err("failed to set capture format\n");
+			return -EINVAL;
+		}
+		ctx->state = MFCINST_INIT;
+		ctx->dst_fmt = fmt;
+		ctx->codec_mode = ctx->dst_fmt->codec_mode;
+		ctx->enc_dst_buf_size =	pix_fmt_mp->plane_fmt[0].sizeimage;
+		pix_fmt_mp->plane_fmt[0].bytesperline = 0;
+		ctx->dst_bufs_cnt = 0;
+		ctx->capture_state = QUEUE_FREE;
+		s5p_mfc_alloc_instance_buffer(ctx);
+		spin_lock_irqsave(&dev->condlock, flags);
+		set_bit(ctx->num, &dev->ctx_work_bits);
+		spin_unlock_irqrestore(&dev->condlock, flags);
+		s5p_mfc_clean_ctx_int_flags(ctx);
+		s5p_mfc_try_run(dev);
+		if (s5p_mfc_wait_for_done_ctx(ctx, \
+				S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 1)) {
+				/* Error or timeout */
+			mfc_err("Error getting instance from hardware\n");
+			s5p_mfc_release_instance_buffer(ctx);
+			ret = -EIO;
+			goto out;
+		}
+		mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		fmt = find_format(f, MFC_FMT_RAW);
+		if (!fmt) {
+			mfc_err("failed to set output format\n");
+			return -EINVAL;
+		}
+		if (fmt->num_planes != pix_fmt_mp->num_planes) {
+			mfc_err("failed to set output format\n");
+			ret = -EINVAL;
+			goto out;
+		}
+		ctx->src_fmt = fmt;
+		ctx->img_width = pix_fmt_mp->width;
+		ctx->img_height = pix_fmt_mp->height;
+		mfc_debug(2, "codec number: %d\n", ctx->src_fmt->codec_mode);
+		mfc_debug(2, "fmt - w: %d, h: %d, ctx - w: %d, h: %d\n",
+			pix_fmt_mp->width, pix_fmt_mp->height,
+			ctx->img_width, ctx->img_height);
+		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) {
+			ctx->buf_width = ALIGN(ctx->img_width,
+							S5P_FIMV_NV12M_HALIGN);
+			ctx->luma_size = ALIGN(ctx->img_width,
+				S5P_FIMV_NV12M_HALIGN) * ALIGN(ctx->img_height,
+				S5P_FIMV_NV12M_LVALIGN);
+			ctx->chroma_size = ALIGN(ctx->img_width,
+				S5P_FIMV_NV12M_HALIGN) * ALIGN((ctx->img_height
+				>> 1), S5P_FIMV_NV12M_CVALIGN);
+
+			ctx->luma_size = ALIGN(ctx->luma_size,
+							S5P_FIMV_NV12M_SALIGN);
+			ctx->chroma_size = ALIGN(ctx->chroma_size,
+							S5P_FIMV_NV12M_SALIGN);
+
+			pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+			pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+			pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+			pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+
+		} else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) {
+			ctx->buf_width = ALIGN(ctx->img_width,
+							S5P_FIMV_NV12MT_HALIGN);
+			ctx->luma_size = ALIGN(ctx->img_width,
+				S5P_FIMV_NV12MT_HALIGN)	* ALIGN(ctx->img_height,
+				S5P_FIMV_NV12MT_VALIGN);
+			ctx->chroma_size = ALIGN(ctx->img_width,
+				S5P_FIMV_NV12MT_HALIGN) * ALIGN((ctx->img_height
+				>> 1), S5P_FIMV_NV12MT_VALIGN);
+			ctx->luma_size = ALIGN(ctx->luma_size,
+							S5P_FIMV_NV12MT_SALIGN);
+			ctx->chroma_size = ALIGN(ctx->chroma_size,
+							S5P_FIMV_NV12MT_SALIGN);
+
+			pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+			pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+			pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+			pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+		}
+		ctx->src_bufs_cnt = 0;
+		ctx->output_state = QUEUE_FREE;
+	} else {
+		mfc_err("invalid buf type\n");
+		return -EINVAL;
+	}
+out:
+	mfc_debug_leave();
+	return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+					  struct v4l2_requestbuffers *reqbufs)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+	int ret = 0;
+
+	/* if memory is not mmp or userptr return error */
+	if ((reqbufs->memory != V4L2_MEMORY_MMAP) &&
+		(reqbufs->memory != V4L2_MEMORY_USERPTR))
+		return -EINVAL;
+	if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		if (ctx->capture_state != QUEUE_FREE) {
+			mfc_err("invalid capture state: %d\n",
+							ctx->capture_state);
+			return -EINVAL;
+		}
+		ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+		if (ret != 0) {
+			mfc_err("error in vb2_reqbufs() for E(D)\n");
+			return ret;
+		}
+		ctx->capture_state = QUEUE_BUFS_REQUESTED;
+		ret = s5p_mfc_alloc_codec_buffers(ctx);
+		if (ret) {
+			mfc_err("Failed to allocate encoding buffers\n");
+			reqbufs->count = 0;
+			ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+			return -ENOMEM;
+		}
+	} else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		if (ctx->output_state != QUEUE_FREE) {
+			mfc_err("invalid output state: %d\n",
+							ctx->output_state);
+			return -EINVAL;
+		}
+		ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+		if (ret != 0) {
+			mfc_err("error in vb2_reqbufs() for E(S)\n");
+			return ret;
+		}
+		ctx->output_state = QUEUE_BUFS_REQUESTED;
+	} else {
+		mfc_err("invalid buf type\n");
+		return -EINVAL;
+	}
+	return ret;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+						   struct v4l2_buffer *buf)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+	int ret = 0;
+
+	/* if memory is not mmp or userptr return error */
+	if ((buf->memory != V4L2_MEMORY_MMAP) &&
+		(buf->memory != V4L2_MEMORY_USERPTR))
+		return -EINVAL;
+	if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		if (ctx->state != MFCINST_GOT_INST) {
+			mfc_err("invalid context state: %d\n", ctx->state);
+			return -EINVAL;
+		}
+		ret = vb2_querybuf(&ctx->vq_dst, buf);
+		if (ret != 0) {
+			mfc_err("error in vb2_querybuf() for E(D)\n");
+			return ret;
+		}
+		buf->m.planes[0].m.mem_offset += DST_QUEUE_OFF_BASE;
+	} else if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		ret = vb2_querybuf(&ctx->vq_src, buf);
+		if (ret != 0) {
+			mfc_err("error in vb2_querybuf() for E(S)\n");
+			return ret;
+		}
+	} else {
+		mfc_err("invalid buf type\n");
+		return -EINVAL;
+	}
+	return ret;
+}
+
+/* Queue a buffer */
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+	if (ctx->state == MFCINST_ERROR) {
+		mfc_err("Call on QBUF after unrecoverable error\n");
+		return -EIO;
+	}
+	if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return vb2_qbuf(&ctx->vq_src, buf);
+	else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return vb2_qbuf(&ctx->vq_dst, buf);
+	return -EINVAL;
+}
+
+/* Dequeue a buffer */
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+	if (ctx->state == MFCINST_ERROR) {
+		mfc_err("Call on DQBUF after unrecoverable error\n");
+		return -EIO;
+	}
+	if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
+	else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
+	return -EINVAL;
+}
+
+/* Stream on */
+static int vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type type)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return vb2_streamon(&ctx->vq_src, type);
+	else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return vb2_streamon(&ctx->vq_dst, type);
+	return -EINVAL;
+}
+
+/* Stream off, which equals to a pause */
+static int vidioc_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type type)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return vb2_streamoff(&ctx->vq_src, type);
+	else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return vb2_streamoff(&ctx->vq_dst, type);
+	return -EINVAL;
+}
+
+static inline int h264_level(enum v4l2_mpeg_video_h264_level lvl)
+{
+	static unsigned int t[V4L2_MPEG_VIDEO_H264_LEVEL_4_0 + 1] = {
+		/* V4L2_MPEG_VIDEO_H264_LEVEL_1_0   */ 10,
+		/* V4L2_MPEG_VIDEO_H264_LEVEL_1B    */ 9,
+		/* V4L2_MPEG_VIDEO_H264_LEVEL_1_1   */ 11,
+		/* V4L2_MPEG_VIDEO_H264_LEVEL_1_2   */ 12,
+		/* V4L2_MPEG_VIDEO_H264_LEVEL_1_3   */ 13,
+		/* V4L2_MPEG_VIDEO_H264_LEVEL_2_0   */ 20,
+		/* V4L2_MPEG_VIDEO_H264_LEVEL_2_1   */ 21,
+		/* V4L2_MPEG_VIDEO_H264_LEVEL_2_2   */ 22,
+		/* V4L2_MPEG_VIDEO_H264_LEVEL_3_0   */ 30,
+		/* V4L2_MPEG_VIDEO_H264_LEVEL_3_1   */ 31,
+		/* V4L2_MPEG_VIDEO_H264_LEVEL_3_2   */ 32,
+		/* V4L2_MPEG_VIDEO_H264_LEVEL_4_0   */ 40,
+	};
+	return t[lvl];
+}
+
+static inline int mpeg4_level(enum v4l2_mpeg_video_mpeg4_level lvl)
+{
+	static unsigned int t[V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 + 1] = {
+		/* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0    */ 0,
+		/* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B   */ 9,
+		/* V4L2_MPEG_VIDEO_MPEG4_LEVEL_1    */ 1,
+		/* V4L2_MPEG_VIDEO_MPEG4_LEVEL_2    */ 2,
+		/* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3    */ 3,
+		/* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B   */ 7,
+		/* V4L2_MPEG_VIDEO_MPEG4_LEVEL_4    */ 4,
+		/* V4L2_MPEG_VIDEO_MPEG4_LEVEL_5    */ 5,
+	};
+	return t[lvl];
+}
+
+static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar)
+{
+	static unsigned int t[V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED + 1] = {
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED     */ 0,
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1             */ 1,
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11           */ 2,
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11           */ 3,
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11           */ 4,
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33           */ 5,
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11           */ 6,
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11           */ 7,
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11           */ 8,
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33           */ 9,
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11           */ 10,
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11           */ 11,
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33           */ 12,
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99          */ 13,
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3             */ 14,
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2             */ 15,
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1             */ 16,
+		/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED        */ 255,
+	};
+	return t[sar];
+}
+
+static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
+	struct s5p_mfc_dev *dev = ctx->dev;
+	struct s5p_mfc_enc_params *p = &ctx->enc_params;
+	int ret = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+		p->gop_size = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+		p->slice_mode = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+		p->slice_mb = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+		p->slice_bit = ctrl->val * 8;
+		break;
+	case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
+		p->intra_refresh_mb = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_MFC51_VIDEO_PADDING:
+		p->pad = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV:
+		p->pad_luma = (ctrl->val >> 16) & 0xff;
+		p->pad_cb = (ctrl->val >> 8) & 0xff;
+		p->pad_cr = (ctrl->val >> 0) & 0xff;
+		break;
+	case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
+		p->rc_frame = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		p->rc_bitrate = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF:
+		p->rc_reaction_coeff = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
+		ctx->force_frame_type = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VBV_SIZE:
+		p->vbv_size = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:
+		p->codec.h264.cpb_size = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+		p->seq_hdr_mode = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE:
+		p->frame_skip_mode = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT:
+		p->fixed_target_bit = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+		p->num_b_frame = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+			p->codec.h264.profile =
+					S5P_FIMV_ENC_PROFILE_H264_MAIN;
+			break;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+			p->codec.h264.profile =
+					S5P_FIMV_ENC_PROFILE_H264_HIGH;
+			break;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+			p->codec.h264.profile =
+				S5P_FIMV_ENC_PROFILE_H264_BASELINE;
+			break;
+		default:
+			ret = -EINVAL;
+		}
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		p->codec.h264.level_v4l2 = ctrl->val;
+		p->codec.h264.level = h264_level(ctrl->val);
+		if (p->codec.h264.level < 0) {
+			mfc_err("Level number is wrong\n");
+			ret = p->codec.h264.level;
+		}
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+		p->codec.mpeg4.level_v4l2 = ctrl->val;
+		p->codec.mpeg4.level = mpeg4_level(ctrl->val);
+		if (p->codec.mpeg4.level < 0) {
+			mfc_err("Level number is wrong\n");
+			ret = p->codec.mpeg4.level;
+		}
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+		p->codec.h264.loop_filter_mode = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
+		p->codec.h264.loop_filter_alpha = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
+		p->codec.h264.loop_filter_beta = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+		p->codec.h264.entropy_mode = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P:
+		p->codec.h264.num_ref_pic_4p = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
+		p->codec.h264._8x8_transform = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
+		p->codec.h264.rc_mb = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+		p->codec.h264.rc_frame_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+		p->codec.h264.rc_min_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+		p->codec.h264.rc_max_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+		p->codec.h264.rc_p_frame_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+		p->codec.h264.rc_b_frame_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
+		p->codec.mpeg4.rc_frame_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
+		p->codec.mpeg4.rc_min_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
+		p->codec.mpeg4.rc_max_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
+		p->codec.mpeg4.rc_p_frame_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:
+		p->codec.mpeg4.rc_b_frame_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK:
+		p->codec.h264.rc_mb_dark = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH:
+		p->codec.h264.rc_mb_smooth = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC:
+		p->codec.h264.rc_mb_static = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY:
+		p->codec.h264.rc_mb_activity = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
+		p->codec.h264.vui_sar = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
+		p->codec.h264.vui_sar_idc = vui_sar_idc(ctrl->val);
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:
+		p->codec.h264.vui_ext_sar_width = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:
+		p->codec.h264.vui_ext_sar_height = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+		p->codec.h264.open_gop = !ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
+		p->codec.h264.open_gop_size = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
+			p->codec.mpeg4.profile =
+				S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE;
+			break;
+		case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
+			p->codec.mpeg4.profile =
+			S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE;
+			break;
+		default:
+			ret = -EINVAL;
+		}
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
+		p->codec.mpeg4.quarter_pixel = ctrl->val;
+		break;
+	default:
+		v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n",
+							ctrl->id, ctrl->val);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops s5p_mfc_enc_ctrl_ops = {
+	.s_ctrl = s5p_mfc_enc_s_ctrl,
+};
+
+static int vidioc_s_parm(struct file *file, void *priv,
+			 struct v4l2_streamparm *a)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+	if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		ctx->enc_params.rc_framerate_num =
+					a->parm.output.timeperframe.denominator;
+		ctx->enc_params.rc_framerate_denom =
+					a->parm.output.timeperframe.numerator;
+	} else {
+		mfc_err("Setting FPS is only possible for the output queue\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int vidioc_g_parm(struct file *file, void *priv,
+			 struct v4l2_streamparm *a)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+	if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		a->parm.output.timeperframe.denominator =
+					ctx->enc_params.rc_framerate_num;
+		a->parm.output.timeperframe.numerator =
+					ctx->enc_params.rc_framerate_denom;
+	} else {
+		mfc_err("Setting FPS is only possible for the output queue\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = {
+	.vidioc_querycap = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
+	.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+	.vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
+	.vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
+	.vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
+	.vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
+	.vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
+	.vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt,
+	.vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt,
+	.vidioc_reqbufs = vidioc_reqbufs,
+	.vidioc_querybuf = vidioc_querybuf,
+	.vidioc_qbuf = vidioc_qbuf,
+	.vidioc_dqbuf = vidioc_dqbuf,
+	.vidioc_streamon = vidioc_streamon,
+	.vidioc_streamoff = vidioc_streamoff,
+	.vidioc_s_parm = vidioc_s_parm,
+	.vidioc_g_parm = vidioc_g_parm,
+};
+
+static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb)
+{
+	int i;
+
+	if (!fmt)
+		return -EINVAL;
+	if (fmt->num_planes != vb->num_planes) {
+		mfc_err("invalid plane number for the format\n");
+		return -EINVAL;
+	}
+	for (i = 0; i < fmt->num_planes; i++) {
+		if (!vb2_dma_contig_plane_dma_addr(vb, i)) {
+			mfc_err("failed to get plane cookie\n");
+			return -EINVAL;
+		}
+		mfc_debug(2, "index: %d, plane[%d] cookie: 0x%08zx",
+				vb->v4l2_buf.index, i,
+				vb2_dma_contig_plane_dma_addr(vb, i));
+	}
+	return 0;
+}
+
+static int s5p_mfc_queue_setup(struct vb2_queue *vq,
+			const struct v4l2_format *fmt,
+			unsigned int *buf_count, unsigned int *plane_count,
+			unsigned int psize[], void *allocators[])
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+
+	if (ctx->state != MFCINST_GOT_INST) {
+		mfc_err("inavlid state: %d\n", ctx->state);
+		return -EINVAL;
+	}
+	if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		if (ctx->dst_fmt)
+			*plane_count = ctx->dst_fmt->num_planes;
+		else
+			*plane_count = MFC_ENC_CAP_PLANE_COUNT;
+		if (*buf_count < 1)
+			*buf_count = 1;
+		if (*buf_count > MFC_MAX_BUFFERS)
+			*buf_count = MFC_MAX_BUFFERS;
+		psize[0] = ctx->enc_dst_buf_size;
+		allocators[0] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
+	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		if (ctx->src_fmt)
+			*plane_count = ctx->src_fmt->num_planes;
+		else
+			*plane_count = MFC_ENC_OUT_PLANE_COUNT;
+
+		if (*buf_count < 1)
+			*buf_count = 1;
+		if (*buf_count > MFC_MAX_BUFFERS)
+			*buf_count = MFC_MAX_BUFFERS;
+		psize[0] = ctx->luma_size;
+		psize[1] = ctx->chroma_size;
+		allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
+		allocators[1] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
+	} else {
+		mfc_err("inavlid queue type: %d\n", vq->type);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void s5p_mfc_unlock(struct vb2_queue *q)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	mutex_unlock(&dev->mfc_mutex);
+}
+
+static void s5p_mfc_lock(struct vb2_queue *q)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	mutex_lock(&dev->mfc_mutex);
+}
+
+static int s5p_mfc_buf_init(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+	unsigned int i;
+	int ret;
+
+	if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		ret = check_vb_with_fmt(ctx->dst_fmt, vb);
+		if (ret < 0)
+			return ret;
+		i = vb->v4l2_buf.index;
+		ctx->dst_bufs[i].b = vb;
+		ctx->dst_bufs[i].cookie.stream =
+					vb2_dma_contig_plane_dma_addr(vb, 0);
+		ctx->dst_bufs_cnt++;
+	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		ret = check_vb_with_fmt(ctx->src_fmt, vb);
+		if (ret < 0)
+			return ret;
+		i = vb->v4l2_buf.index;
+		ctx->src_bufs[i].b = vb;
+		ctx->src_bufs[i].cookie.raw.luma =
+					vb2_dma_contig_plane_dma_addr(vb, 0);
+		ctx->src_bufs[i].cookie.raw.chroma =
+					vb2_dma_contig_plane_dma_addr(vb, 1);
+		ctx->src_bufs_cnt++;
+	} else {
+		mfc_err("inavlid queue type: %d\n", vq->type);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int s5p_mfc_buf_prepare(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+	int ret;
+
+	if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		ret = check_vb_with_fmt(ctx->dst_fmt, vb);
+		if (ret < 0)
+			return ret;
+		mfc_debug(2, "plane size: %ld, dst size: %d\n",
+			vb2_plane_size(vb, 0), ctx->enc_dst_buf_size);
+		if (vb2_plane_size(vb, 0) < ctx->enc_dst_buf_size) {
+			mfc_err("plane size is too small for capture\n");
+			return -EINVAL;
+		}
+	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		ret = check_vb_with_fmt(ctx->src_fmt, vb);
+		if (ret < 0)
+			return ret;
+		mfc_debug(2, "plane size: %ld, luma size: %d\n",
+			vb2_plane_size(vb, 0), ctx->luma_size);
+		mfc_debug(2, "plane size: %ld, chroma size: %d\n",
+			vb2_plane_size(vb, 1), ctx->chroma_size);
+		if (vb2_plane_size(vb, 0) < ctx->luma_size ||
+		    vb2_plane_size(vb, 1) < ctx->chroma_size) {
+			mfc_err("plane size is too small for output\n");
+			return -EINVAL;
+		}
+	} else {
+		mfc_err("inavlid queue type: %d\n", vq->type);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+	struct s5p_mfc_dev *dev = ctx->dev;
+	unsigned long flags;
+
+	v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+	/* If context is ready then dev = work->data;schedule it to run */
+	if (s5p_mfc_ctx_ready(ctx)) {
+		spin_lock_irqsave(&dev->condlock, flags);
+		set_bit(ctx->num, &dev->ctx_work_bits);
+		spin_unlock_irqrestore(&dev->condlock, flags);
+	}
+	s5p_mfc_try_run(dev);
+	return 0;
+}
+
+static int s5p_mfc_stop_streaming(struct vb2_queue *q)
+{
+	unsigned long flags;
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	if ((ctx->state == MFCINST_FINISHING ||
+		ctx->state == MFCINST_RUNNING) &&
+		dev->curr_ctx == ctx->num && dev->hw_lock) {
+		ctx->state = MFCINST_ABORT;
+		s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_FRAME_DONE_RET,
+					  0);
+	}
+	ctx->state = MFCINST_FINISHED;
+	spin_lock_irqsave(&dev->irqlock, flags);
+	if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+		INIT_LIST_HEAD(&ctx->dst_queue);
+		ctx->dst_queue_cnt = 0;
+	}
+	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		cleanup_ref_queue(ctx);
+		s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+		INIT_LIST_HEAD(&ctx->src_queue);
+		ctx->src_queue_cnt = 0;
+	}
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+	return 0;
+}
+
+static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+	struct s5p_mfc_dev *dev = ctx->dev;
+	unsigned long flags;
+	struct s5p_mfc_buf *mfc_buf;
+
+	if (ctx->state == MFCINST_ERROR) {
+		vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+		cleanup_ref_queue(ctx);
+		return;
+	}
+	if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index];
+		mfc_buf->used = 0;
+		/* Mark destination as available for use by MFC */
+		spin_lock_irqsave(&dev->irqlock, flags);
+		list_add_tail(&mfc_buf->list, &ctx->dst_queue);
+		ctx->dst_queue_cnt++;
+		spin_unlock_irqrestore(&dev->irqlock, flags);
+	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index];
+		mfc_buf->used = 0;
+		spin_lock_irqsave(&dev->irqlock, flags);
+		if (vb->v4l2_planes[0].bytesused == 0) {
+			mfc_debug(1, "change state to FINISHING\n");
+			ctx->state = MFCINST_FINISHING;
+			vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+			cleanup_ref_queue(ctx);
+		} else {
+			list_add_tail(&mfc_buf->list, &ctx->src_queue);
+			ctx->src_queue_cnt++;
+		}
+		spin_unlock_irqrestore(&dev->irqlock, flags);
+	} else {
+		mfc_err("unsupported buffer type (%d)\n", vq->type);
+	}
+	if (s5p_mfc_ctx_ready(ctx)) {
+		spin_lock_irqsave(&dev->condlock, flags);
+		set_bit(ctx->num, &dev->ctx_work_bits);
+		spin_unlock_irqrestore(&dev->condlock, flags);
+	}
+	s5p_mfc_try_run(dev);
+}
+
+static struct vb2_ops s5p_mfc_enc_qops = {
+	.queue_setup		= s5p_mfc_queue_setup,
+	.wait_prepare		= s5p_mfc_unlock,
+	.wait_finish		= s5p_mfc_lock,
+	.buf_init		= s5p_mfc_buf_init,
+	.buf_prepare		= s5p_mfc_buf_prepare,
+	.start_streaming	= s5p_mfc_start_streaming,
+	.stop_streaming		= s5p_mfc_stop_streaming,
+	.buf_queue		= s5p_mfc_buf_queue,
+};
+
+struct s5p_mfc_codec_ops *get_enc_codec_ops(void)
+{
+	return &encoder_codec_ops;
+}
+
+struct vb2_ops *get_enc_queue_ops(void)
+{
+	return &s5p_mfc_enc_qops;
+}
+
+const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void)
+{
+	return &s5p_mfc_enc_ioctl_ops;
+}
+
+#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \
+						&& V4L2_CTRL_DRIVER_PRIV(x))
+
+int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx)
+{
+	struct v4l2_ctrl_config cfg;
+	int i;
+
+	v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS);
+	if (ctx->ctrl_handler.error) {
+		mfc_err("v4l2_ctrl_handler_init failed\n");
+		return ctx->ctrl_handler.error;
+	}
+	for (i = 0; i < NUM_CTRLS; i++) {
+		if (IS_MFC51_PRIV(controls[i].id)) {
+			memset(&cfg, 0, sizeof(struct v4l2_ctrl_config));
+			cfg.ops = &s5p_mfc_enc_ctrl_ops;
+			cfg.id = controls[i].id;
+			cfg.min = controls[i].minimum;
+			cfg.max = controls[i].maximum;
+			cfg.def = controls[i].default_value;
+			cfg.name = controls[i].name;
+			cfg.type = controls[i].type;
+			cfg.flags = 0;
+
+			if (cfg.type == V4L2_CTRL_TYPE_MENU) {
+				cfg.step = 0;
+				cfg.menu_skip_mask = cfg.menu_skip_mask;
+				cfg.qmenu = mfc51_get_menu(cfg.id);
+			} else {
+				cfg.step = controls[i].step;
+				cfg.menu_skip_mask = 0;
+			}
+			ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+					&cfg, NULL);
+		} else {
+			if (controls[i].type == V4L2_CTRL_TYPE_MENU) {
+				ctx->ctrls[i] = v4l2_ctrl_new_std_menu(
+					&ctx->ctrl_handler,
+					&s5p_mfc_enc_ctrl_ops, controls[i].id,
+					controls[i].maximum, 0,
+					controls[i].default_value);
+			} else {
+				ctx->ctrls[i] = v4l2_ctrl_new_std(
+					&ctx->ctrl_handler,
+					&s5p_mfc_enc_ctrl_ops, controls[i].id,
+					controls[i].minimum,
+					controls[i].maximum, controls[i].step,
+					controls[i].default_value);
+			}
+		}
+		if (ctx->ctrl_handler.error) {
+			mfc_err("Adding control (%d) failed\n", i);
+			return ctx->ctrl_handler.error;
+		}
+		if (controls[i].is_volatile && ctx->ctrls[i])
+			ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE;
+	}
+	return 0;
+}
+
+void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx)
+{
+	int i;
+
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+	for (i = 0; i < NUM_CTRLS; i++)
+		ctx->ctrls[i] = NULL;
+}
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h
new file mode 100644
index 0000000..ca9fd66
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h
@@ -0,0 +1,23 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef S5P_MFC_ENC_H_
+#define S5P_MFC_ENC_H_
+
+struct s5p_mfc_codec_ops *get_enc_codec_ops(void);
+struct vb2_ops *get_enc_queue_ops(void);
+const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void);
+struct s5p_mfc_fmt *get_enc_def_fmt(bool src);
+int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx);
+
+#endif /* S5P_MFC_ENC_H_  */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c
new file mode 100644
index 0000000..37860e2
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c
@@ -0,0 +1,92 @@
+/*
+ * drivers/media/platform/samsung/mfc5/s5p_mfc_intr.c
+ *
+ * C file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * This file contains functions used to wait for command completion.
+ *
+ * Kamil Debski, Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_intr.h"
+
+int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command)
+{
+	int ret;
+
+	ret = wait_event_interruptible_timeout(dev->queue,
+		(dev->int_cond && (dev->int_type == command
+		|| dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET)),
+		msecs_to_jiffies(MFC_INT_TIMEOUT));
+	if (ret == 0) {
+		mfc_err("Interrupt (dev->int_type:%d, command:%d) timed out\n",
+							dev->int_type, command);
+		return 1;
+	} else if (ret == -ERESTARTSYS) {
+		mfc_err("Interrupted by a signal\n");
+		return 1;
+	}
+	mfc_debug(1, "Finished waiting (dev->int_type:%d, command: %d)\n",
+							dev->int_type, command);
+	if (dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET)
+		return 1;
+	return 0;
+}
+
+void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev)
+{
+	dev->int_cond = 0;
+	dev->int_type = 0;
+	dev->int_err = 0;
+}
+
+int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx,
+				    int command, int interrupt)
+{
+	int ret;
+
+	if (interrupt) {
+		ret = wait_event_interruptible_timeout(ctx->queue,
+				(ctx->int_cond && (ctx->int_type == command
+			|| ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)),
+					msecs_to_jiffies(MFC_INT_TIMEOUT));
+	} else {
+		ret = wait_event_timeout(ctx->queue,
+				(ctx->int_cond && (ctx->int_type == command
+			|| ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)),
+					msecs_to_jiffies(MFC_INT_TIMEOUT));
+	}
+	if (ret == 0) {
+		mfc_err("Interrupt (ctx->int_type:%d, command:%d) timed out\n",
+							ctx->int_type, command);
+		return 1;
+	} else if (ret == -ERESTARTSYS) {
+		mfc_err("Interrupted by a signal\n");
+		return 1;
+	}
+	mfc_debug(1, "Finished waiting (ctx->int_type:%d, command: %d)\n",
+							ctx->int_type, command);
+	if (ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)
+		return 1;
+	return 0;
+}
+
+void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx)
+{
+	ctx->int_cond = 0;
+	ctx->int_type = 0;
+	ctx->int_err = 0;
+}
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.h
new file mode 100644
index 0000000..18341a8
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.h
@@ -0,0 +1,26 @@
+/*
+ * drivers/media/platform/samsung/mfc5/s5p_mfc_intr.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * It contains waiting functions declarations.
+ *
+ * Kamil Debski, Copyright (C) 2011 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef S5P_MFC_INTR_H_
+#define S5P_MFC_INTR_H_
+
+#include "s5p_mfc_common.h"
+
+int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx,
+			      int command, int interrupt);
+int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command);
+void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev);
+
+#endif /* S5P_MFC_INTR_H_ */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
new file mode 100644
index 0000000..b5fd3d4
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
@@ -0,0 +1,1397 @@
+/*
+ * drivers/media/platform/samsung/mfc5/s5p_mfc_opr.c
+ *
+ * Samsung MFC (Multi Function Codec - FIMV) driver
+ * This file contains hw related functions.
+ *
+ * Kamil Debski, Copyright (c) 2011 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "regs-mfc.h"
+#include "s5p_mfc_cmd.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_ctrl.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_opr.h"
+#include "s5p_mfc_pm.h"
+#include "s5p_mfc_shm.h"
+#include <asm/cacheflush.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#define OFFSETA(x)		(((x) - dev->bank1) >> MFC_OFFSET_SHIFT)
+#define OFFSETB(x)		(((x) - dev->bank2) >> MFC_OFFSET_SHIFT)
+
+/* Allocate temporary buffers for decoding */
+int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx)
+{
+	void *desc_virt;
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	ctx->desc_buf = vb2_dma_contig_memops.alloc(
+			dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], DESC_BUF_SIZE);
+	if (IS_ERR_VALUE((int)ctx->desc_buf)) {
+		ctx->desc_buf = NULL;
+		mfc_err("Allocating DESC buffer failed\n");
+		return -ENOMEM;
+	}
+	ctx->desc_phys = s5p_mfc_mem_cookie(
+			dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->desc_buf);
+	BUG_ON(ctx->desc_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+	desc_virt = vb2_dma_contig_memops.vaddr(ctx->desc_buf);
+	if (desc_virt == NULL) {
+		vb2_dma_contig_memops.put(ctx->desc_buf);
+		ctx->desc_phys = 0;
+		ctx->desc_buf = NULL;
+		mfc_err("Remapping DESC buffer failed\n");
+		return -ENOMEM;
+	}
+	memset(desc_virt, 0, DESC_BUF_SIZE);
+	wmb();
+	return 0;
+}
+
+/* Release temporary buffers for decoding */
+void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx)
+{
+	if (ctx->desc_phys) {
+		vb2_dma_contig_memops.put(ctx->desc_buf);
+		ctx->desc_phys = 0;
+		ctx->desc_buf = NULL;
+	}
+}
+
+/* Allocate codec buffers */
+int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	unsigned int enc_ref_y_size = 0;
+	unsigned int enc_ref_c_size = 0;
+	unsigned int guard_width, guard_height;
+
+	if (ctx->type == MFCINST_DECODER) {
+		mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n",
+			  ctx->luma_size, ctx->chroma_size, ctx->mv_size);
+		mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count);
+	} else if (ctx->type == MFCINST_ENCODER) {
+		enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+			* ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN);
+		enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN);
+
+		if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) {
+			enc_ref_c_size = ALIGN(ctx->img_width,
+						S5P_FIMV_NV12MT_HALIGN)
+						* ALIGN(ctx->img_height >> 1,
+						S5P_FIMV_NV12MT_VALIGN);
+			enc_ref_c_size = ALIGN(enc_ref_c_size,
+							S5P_FIMV_NV12MT_SALIGN);
+		} else {
+			guard_width = ALIGN(ctx->img_width + 16,
+							S5P_FIMV_NV12MT_HALIGN);
+			guard_height = ALIGN((ctx->img_height >> 1) + 4,
+							S5P_FIMV_NV12MT_VALIGN);
+			enc_ref_c_size = ALIGN(guard_width * guard_height,
+					       S5P_FIMV_NV12MT_SALIGN);
+		}
+		mfc_debug(2, "recon luma size: %d chroma size: %d\n",
+			  enc_ref_y_size, enc_ref_c_size);
+	} else {
+		return -EINVAL;
+	}
+	/* Codecs have different memory requirements */
+	switch (ctx->codec_mode) {
+	case S5P_FIMV_CODEC_H264_DEC:
+		ctx->bank1_size =
+		    ALIGN(S5P_FIMV_DEC_NB_IP_SIZE +
+					S5P_FIMV_DEC_VERT_NB_MV_SIZE,
+					S5P_FIMV_DEC_BUF_ALIGN);
+		ctx->bank2_size = ctx->total_dpb_count * ctx->mv_size;
+		break;
+	case S5P_FIMV_CODEC_MPEG4_DEC:
+		ctx->bank1_size =
+		    ALIGN(S5P_FIMV_DEC_NB_DCAC_SIZE +
+				     S5P_FIMV_DEC_UPNB_MV_SIZE +
+				     S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
+				     S5P_FIMV_DEC_STX_PARSER_SIZE +
+				     S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE,
+				     S5P_FIMV_DEC_BUF_ALIGN);
+		ctx->bank2_size = 0;
+		break;
+	case S5P_FIMV_CODEC_VC1RCV_DEC:
+	case S5P_FIMV_CODEC_VC1_DEC:
+		ctx->bank1_size =
+		    ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE +
+			     S5P_FIMV_DEC_UPNB_MV_SIZE +
+			     S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
+			     S5P_FIMV_DEC_NB_DCAC_SIZE +
+			     3 * S5P_FIMV_DEC_VC1_BITPLANE_SIZE,
+			     S5P_FIMV_DEC_BUF_ALIGN);
+		ctx->bank2_size = 0;
+		break;
+	case S5P_FIMV_CODEC_MPEG2_DEC:
+		ctx->bank1_size = 0;
+		ctx->bank2_size = 0;
+		break;
+	case S5P_FIMV_CODEC_H263_DEC:
+		ctx->bank1_size =
+		    ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE +
+			     S5P_FIMV_DEC_UPNB_MV_SIZE +
+			     S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
+			     S5P_FIMV_DEC_NB_DCAC_SIZE,
+			     S5P_FIMV_DEC_BUF_ALIGN);
+		ctx->bank2_size = 0;
+		break;
+	case S5P_FIMV_CODEC_H264_ENC:
+		ctx->bank1_size = (enc_ref_y_size * 2) +
+				   S5P_FIMV_ENC_UPMV_SIZE +
+				   S5P_FIMV_ENC_COLFLG_SIZE +
+				   S5P_FIMV_ENC_INTRAMD_SIZE +
+				   S5P_FIMV_ENC_NBORINFO_SIZE;
+		ctx->bank2_size = (enc_ref_y_size * 2) +
+				   (enc_ref_c_size * 4) +
+				   S5P_FIMV_ENC_INTRAPRED_SIZE;
+		break;
+	case S5P_FIMV_CODEC_MPEG4_ENC:
+		ctx->bank1_size = (enc_ref_y_size * 2) +
+				   S5P_FIMV_ENC_UPMV_SIZE +
+				   S5P_FIMV_ENC_COLFLG_SIZE +
+				   S5P_FIMV_ENC_ACDCCOEF_SIZE;
+		ctx->bank2_size = (enc_ref_y_size * 2) +
+				   (enc_ref_c_size * 4);
+		break;
+	case S5P_FIMV_CODEC_H263_ENC:
+		ctx->bank1_size = (enc_ref_y_size * 2) +
+				   S5P_FIMV_ENC_UPMV_SIZE +
+				   S5P_FIMV_ENC_ACDCCOEF_SIZE;
+		ctx->bank2_size = (enc_ref_y_size * 2) +
+				   (enc_ref_c_size * 4);
+		break;
+	default:
+		break;
+	}
+	/* Allocate only if memory from bank 1 is necessary */
+	if (ctx->bank1_size > 0) {
+		ctx->bank1_buf = vb2_dma_contig_memops.alloc(
+		dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size);
+		if (IS_ERR(ctx->bank1_buf)) {
+			ctx->bank1_buf = NULL;
+			printk(KERN_ERR
+			       "Buf alloc for decoding failed (port A)\n");
+			return -ENOMEM;
+		}
+		ctx->bank1_phys = s5p_mfc_mem_cookie(
+		dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf);
+		BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+	}
+	/* Allocate only if memory from bank 2 is necessary */
+	if (ctx->bank2_size > 0) {
+		ctx->bank2_buf = vb2_dma_contig_memops.alloc(
+		dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_size);
+		if (IS_ERR(ctx->bank2_buf)) {
+			ctx->bank2_buf = NULL;
+			mfc_err("Buf alloc for decoding failed (port B)\n");
+			return -ENOMEM;
+		}
+		ctx->bank2_phys = s5p_mfc_mem_cookie(
+		dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_buf);
+		BUG_ON(ctx->bank2_phys & ((1 << MFC_BANK2_ALIGN_ORDER) - 1));
+	}
+	return 0;
+}
+
+/* Release buffers allocated for codec */
+void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx)
+{
+	if (ctx->bank1_buf) {
+		vb2_dma_contig_memops.put(ctx->bank1_buf);
+		ctx->bank1_buf = NULL;
+		ctx->bank1_phys = 0;
+		ctx->bank1_size = 0;
+	}
+	if (ctx->bank2_buf) {
+		vb2_dma_contig_memops.put(ctx->bank2_buf);
+		ctx->bank2_buf = NULL;
+		ctx->bank2_phys = 0;
+		ctx->bank2_size = 0;
+	}
+}
+
+/* Allocate memory for instance data buffer */
+int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx)
+{
+	void *context_virt;
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC ||
+		ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC)
+		ctx->ctx_size = MFC_H264_CTX_BUF_SIZE;
+	else
+		ctx->ctx_size = MFC_CTX_BUF_SIZE;
+	ctx->ctx_buf = vb2_dma_contig_memops.alloc(
+		dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_size);
+	if (IS_ERR(ctx->ctx_buf)) {
+		mfc_err("Allocating context buffer failed\n");
+		ctx->ctx_phys = 0;
+		ctx->ctx_buf = NULL;
+		return -ENOMEM;
+	}
+	ctx->ctx_phys = s5p_mfc_mem_cookie(
+		dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_buf);
+	BUG_ON(ctx->ctx_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+	ctx->ctx_ofs = OFFSETA(ctx->ctx_phys);
+	context_virt = vb2_dma_contig_memops.vaddr(ctx->ctx_buf);
+	if (context_virt == NULL) {
+		mfc_err("Remapping instance buffer failed\n");
+		vb2_dma_contig_memops.put(ctx->ctx_buf);
+		ctx->ctx_phys = 0;
+		ctx->ctx_buf = NULL;
+		return -ENOMEM;
+	}
+	/* Zero content of the allocated memory */
+	memset(context_virt, 0, ctx->ctx_size);
+	wmb();
+	if (s5p_mfc_init_shm(ctx) < 0) {
+		vb2_dma_contig_memops.put(ctx->ctx_buf);
+		ctx->ctx_phys = 0;
+		ctx->ctx_buf = NULL;
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+/* Release instance buffer */
+void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx)
+{
+	if (ctx->ctx_buf) {
+		vb2_dma_contig_memops.put(ctx->ctx_buf);
+		ctx->ctx_phys = 0;
+		ctx->ctx_buf = NULL;
+	}
+	if (ctx->shm_alloc) {
+		vb2_dma_contig_memops.put(ctx->shm_alloc);
+		ctx->shm_alloc = NULL;
+		ctx->shm = NULL;
+	}
+}
+
+/* Set registers for decoding temporary buffers */
+void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	mfc_write(dev, OFFSETA(ctx->desc_phys), S5P_FIMV_SI_CH0_DESC_ADR);
+	mfc_write(dev, DESC_BUF_SIZE, S5P_FIMV_SI_CH0_DESC_SIZE);
+}
+
+/* Set registers for shared buffer */
+static void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	mfc_write(dev, ctx->shm_ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR);
+}
+
+/* Set registers for decoding stream buffer */
+int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr,
+		  unsigned int start_num_byte, unsigned int buf_size)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	mfc_write(dev, OFFSETA(buf_addr), S5P_FIMV_SI_CH0_SB_ST_ADR);
+	mfc_write(dev, ctx->dec_src_buf_size, S5P_FIMV_SI_CH0_CPB_SIZE);
+	mfc_write(dev, buf_size, S5P_FIMV_SI_CH0_SB_FRM_SIZE);
+	s5p_mfc_write_shm(ctx, start_num_byte, START_BYTE_NUM);
+	return 0;
+}
+
+/* Set decoding frame buffer */
+int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx)
+{
+	unsigned int frame_size, i;
+	unsigned int frame_size_ch, frame_size_mv;
+	struct s5p_mfc_dev *dev = ctx->dev;
+	unsigned int dpb;
+	size_t buf_addr1, buf_addr2;
+	int buf_size1, buf_size2;
+
+	buf_addr1 = ctx->bank1_phys;
+	buf_size1 = ctx->bank1_size;
+	buf_addr2 = ctx->bank2_phys;
+	buf_size2 = ctx->bank2_size;
+	dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) &
+						~S5P_FIMV_DPB_COUNT_MASK;
+	mfc_write(dev, ctx->total_dpb_count | dpb,
+						S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+	s5p_mfc_set_shared_buffer(ctx);
+	switch (ctx->codec_mode) {
+	case S5P_FIMV_CODEC_H264_DEC:
+		mfc_write(dev, OFFSETA(buf_addr1),
+						S5P_FIMV_H264_VERT_NB_MV_ADR);
+		buf_addr1 += S5P_FIMV_DEC_VERT_NB_MV_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_VERT_NB_MV_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_NB_IP_ADR);
+		buf_addr1 += S5P_FIMV_DEC_NB_IP_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_NB_IP_SIZE;
+		break;
+	case S5P_FIMV_CODEC_MPEG4_DEC:
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_NB_DCAC_ADR);
+		buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_NB_MV_ADR);
+		buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SA_MV_ADR);
+		buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SP_ADR);
+		buf_addr1 += S5P_FIMV_DEC_STX_PARSER_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_STX_PARSER_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_OT_LINE_ADR);
+		buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+		break;
+	case S5P_FIMV_CODEC_H263_DEC:
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_OT_LINE_ADR);
+		buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_NB_MV_ADR);
+		buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_SA_MV_ADR);
+		buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_NB_DCAC_ADR);
+		buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
+		break;
+	case S5P_FIMV_CODEC_VC1_DEC:
+	case S5P_FIMV_CODEC_VC1RCV_DEC:
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_NB_DCAC_ADR);
+		buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_OT_LINE_ADR);
+		buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_UP_NB_MV_ADR);
+		buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_SA_MV_ADR);
+		buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE3_ADR);
+		buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE2_ADR);
+		buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE1_ADR);
+		buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+		buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+		break;
+	case S5P_FIMV_CODEC_MPEG2_DEC:
+		break;
+	default:
+		mfc_err("Unknown codec for decoding (%x)\n",
+			ctx->codec_mode);
+		return -EINVAL;
+		break;
+	}
+	frame_size = ctx->luma_size;
+	frame_size_ch = ctx->chroma_size;
+	frame_size_mv = ctx->mv_size;
+	mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size, frame_size_ch,
+								frame_size_mv);
+	for (i = 0; i < ctx->total_dpb_count; i++) {
+		/* Bank2 */
+		mfc_debug(2, "Luma %d: %x\n", i,
+					ctx->dst_bufs[i].cookie.raw.luma);
+		mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma),
+						S5P_FIMV_DEC_LUMA_ADR + i * 4);
+		mfc_debug(2, "\tChroma %d: %x\n", i,
+					ctx->dst_bufs[i].cookie.raw.chroma);
+		mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma),
+					       S5P_FIMV_DEC_CHROMA_ADR + i * 4);
+		if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) {
+			mfc_debug(2, "\tBuf2: %x, size: %d\n",
+							buf_addr2, buf_size2);
+			mfc_write(dev, OFFSETB(buf_addr2),
+						S5P_FIMV_H264_MV_ADR + i * 4);
+			buf_addr2 += frame_size_mv;
+			buf_size2 -= frame_size_mv;
+		}
+	}
+	mfc_debug(2, "Buf1: %u, buf_size1: %d\n", buf_addr1, buf_size1);
+	mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n",
+			buf_size1,  buf_size2, ctx->total_dpb_count);
+	if (buf_size1 < 0 || buf_size2 < 0) {
+		mfc_debug(2, "Not enough memory has been allocated\n");
+		return -ENOMEM;
+	}
+	s5p_mfc_write_shm(ctx, frame_size, ALLOC_LUMA_DPB_SIZE);
+	s5p_mfc_write_shm(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE);
+	if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC)
+		s5p_mfc_write_shm(ctx, frame_size_mv, ALLOC_MV_SIZE);
+	mfc_write(dev, ((S5P_FIMV_CH_INIT_BUFS & S5P_FIMV_CH_MASK)
+					<< S5P_FIMV_CH_SHIFT) | (ctx->inst_no),
+						S5P_FIMV_SI_CH0_INST_ID);
+	return 0;
+}
+
+/* Set registers for encoding stream buffer */
+int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
+		unsigned long addr, unsigned int size)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	mfc_write(dev, OFFSETA(addr), S5P_FIMV_ENC_SI_CH0_SB_ADR);
+	mfc_write(dev, size, S5P_FIMV_ENC_SI_CH0_SB_SIZE);
+	return 0;
+}
+
+void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+		unsigned long y_addr, unsigned long c_addr)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	mfc_write(dev, OFFSETB(y_addr), S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR);
+	mfc_write(dev, OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR);
+}
+
+void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+		unsigned long *y_addr, unsigned long *c_addr)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	*y_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_Y_ADDR)
+							<< MFC_OFFSET_SHIFT);
+	*c_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_C_ADDR)
+							<< MFC_OFFSET_SHIFT);
+}
+
+/* Set encoding ref & codec buffer */
+int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	size_t buf_addr1, buf_addr2;
+	size_t buf_size1, buf_size2;
+	unsigned int enc_ref_y_size, enc_ref_c_size;
+	unsigned int guard_width, guard_height;
+	int i;
+
+	buf_addr1 = ctx->bank1_phys;
+	buf_size1 = ctx->bank1_size;
+	buf_addr2 = ctx->bank2_phys;
+	buf_size2 = ctx->bank2_size;
+	enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+		* ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN);
+	enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN);
+	if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) {
+		enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+			* ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN);
+		enc_ref_c_size = ALIGN(enc_ref_c_size, S5P_FIMV_NV12MT_SALIGN);
+	} else {
+		guard_width = ALIGN(ctx->img_width + 16,
+						S5P_FIMV_NV12MT_HALIGN);
+		guard_height = ALIGN((ctx->img_height >> 1) + 4,
+						S5P_FIMV_NV12MT_VALIGN);
+		enc_ref_c_size = ALIGN(guard_width * guard_height,
+				       S5P_FIMV_NV12MT_SALIGN);
+	}
+	mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2);
+	switch (ctx->codec_mode) {
+	case S5P_FIMV_CODEC_H264_ENC:
+		for (i = 0; i < 2; i++) {
+			mfc_write(dev, OFFSETA(buf_addr1),
+				S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
+			buf_addr1 += enc_ref_y_size;
+			buf_size1 -= enc_ref_y_size;
+
+			mfc_write(dev, OFFSETB(buf_addr2),
+				S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
+			buf_addr2 += enc_ref_y_size;
+			buf_size2 -= enc_ref_y_size;
+		}
+		for (i = 0; i < 4; i++) {
+			mfc_write(dev, OFFSETB(buf_addr2),
+				S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
+			buf_addr2 += enc_ref_c_size;
+			buf_size2 -= enc_ref_c_size;
+		}
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_UP_MV_ADR);
+		buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
+		buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1),
+					S5P_FIMV_H264_COZERO_FLAG_ADR);
+		buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE;
+		buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1),
+					S5P_FIMV_H264_UP_INTRA_MD_ADR);
+		buf_addr1 += S5P_FIMV_ENC_INTRAMD_SIZE;
+		buf_size1 -= S5P_FIMV_ENC_INTRAMD_SIZE;
+		mfc_write(dev, OFFSETB(buf_addr2),
+					S5P_FIMV_H264_UP_INTRA_PRED_ADR);
+		buf_addr2 += S5P_FIMV_ENC_INTRAPRED_SIZE;
+		buf_size2 -= S5P_FIMV_ENC_INTRAPRED_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1),
+					S5P_FIMV_H264_NBOR_INFO_ADR);
+		buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE;
+		buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE;
+		mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+			buf_size1, buf_size2);
+		break;
+	case S5P_FIMV_CODEC_MPEG4_ENC:
+		for (i = 0; i < 2; i++) {
+			mfc_write(dev, OFFSETA(buf_addr1),
+				S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
+			buf_addr1 += enc_ref_y_size;
+			buf_size1 -= enc_ref_y_size;
+			mfc_write(dev, OFFSETB(buf_addr2),
+				S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
+			buf_addr2 += enc_ref_y_size;
+			buf_size2 -= enc_ref_y_size;
+		}
+		for (i = 0; i < 4; i++) {
+			mfc_write(dev, OFFSETB(buf_addr2),
+				S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
+			buf_addr2 += enc_ref_c_size;
+			buf_size2 -= enc_ref_c_size;
+		}
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_MV_ADR);
+		buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
+		buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1),
+						S5P_FIMV_MPEG4_COZERO_FLAG_ADR);
+		buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE;
+		buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1),
+						S5P_FIMV_MPEG4_ACDC_COEF_ADR);
+		buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
+		buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
+		mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+			buf_size1, buf_size2);
+		break;
+	case S5P_FIMV_CODEC_H263_ENC:
+		for (i = 0; i < 2; i++) {
+			mfc_write(dev, OFFSETA(buf_addr1),
+				S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
+			buf_addr1 += enc_ref_y_size;
+			buf_size1 -= enc_ref_y_size;
+			mfc_write(dev, OFFSETB(buf_addr2),
+				S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
+			buf_addr2 += enc_ref_y_size;
+			buf_size2 -= enc_ref_y_size;
+		}
+		for (i = 0; i < 4; i++) {
+			mfc_write(dev, OFFSETB(buf_addr2),
+				S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
+			buf_addr2 += enc_ref_c_size;
+			buf_size2 -= enc_ref_c_size;
+		}
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_MV_ADR);
+		buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
+		buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
+		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR);
+		buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
+		buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
+		mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+			buf_size1, buf_size2);
+		break;
+	default:
+		mfc_err("Unknown codec set for encoding: %d\n",
+			ctx->codec_mode);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	struct s5p_mfc_enc_params *p = &ctx->enc_params;
+	unsigned int reg;
+	unsigned int shm;
+
+	/* width */
+	mfc_write(dev, ctx->img_width, S5P_FIMV_ENC_HSIZE_PX);
+	/* height */
+	mfc_write(dev, ctx->img_height, S5P_FIMV_ENC_VSIZE_PX);
+	/* pictype : enable, IDR period */
+	reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+	reg |= (1 << 18);
+	reg &= ~(0xFFFF);
+	reg |= p->gop_size;
+	mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+	mfc_write(dev, 0, S5P_FIMV_ENC_B_RECON_WRITE_ON);
+	/* multi-slice control */
+	/* multi-slice MB number or bit size */
+	mfc_write(dev, p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL);
+	if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
+		mfc_write(dev, p->slice_mb, S5P_FIMV_ENC_MSLICE_MB);
+	} else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
+		mfc_write(dev, p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT);
+	} else {
+		mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_MB);
+		mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_BIT);
+	}
+	/* cyclic intra refresh */
+	mfc_write(dev, p->intra_refresh_mb, S5P_FIMV_ENC_CIR_CTRL);
+	/* memory structure cur. frame */
+	if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M)
+		mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR);
+	else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT)
+		mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR);
+	/* padding control & value */
+	reg = mfc_read(dev, S5P_FIMV_ENC_PADDING_CTRL);
+	if (p->pad) {
+		/** enable */
+		reg |= (1 << 31);
+		/** cr value */
+		reg &= ~(0xFF << 16);
+		reg |= (p->pad_cr << 16);
+		/** cb value */
+		reg &= ~(0xFF << 8);
+		reg |= (p->pad_cb << 8);
+		/** y value */
+		reg &= ~(0xFF);
+		reg |= (p->pad_luma);
+	} else {
+		/** disable & all value clear */
+		reg = 0;
+	}
+	mfc_write(dev, reg, S5P_FIMV_ENC_PADDING_CTRL);
+	/* rate control config. */
+	reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
+	/** frame-level rate control */
+	reg &= ~(0x1 << 9);
+	reg |= (p->rc_frame << 9);
+	mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
+	/* bit rate */
+	if (p->rc_frame)
+		mfc_write(dev, p->rc_bitrate,
+			S5P_FIMV_ENC_RC_BIT_RATE);
+	else
+		mfc_write(dev, 0, S5P_FIMV_ENC_RC_BIT_RATE);
+	/* reaction coefficient */
+	if (p->rc_frame)
+		mfc_write(dev, p->rc_reaction_coeff, S5P_FIMV_ENC_RC_RPARA);
+	shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+	/* seq header ctrl */
+	shm &= ~(0x1 << 3);
+	shm |= (p->seq_hdr_mode << 3);
+	/* frame skip mode */
+	shm &= ~(0x3 << 1);
+	shm |= (p->frame_skip_mode << 1);
+	s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+	/* fixed target bit */
+	s5p_mfc_write_shm(ctx, p->fixed_target_bit, RC_CONTROL_CONFIG);
+	return 0;
+}
+
+static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	struct s5p_mfc_enc_params *p = &ctx->enc_params;
+	struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264;
+	unsigned int reg;
+	unsigned int shm;
+
+	s5p_mfc_set_enc_params(ctx);
+	/* pictype : number of B */
+	reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+	/* num_b_frame - 0 ~ 2 */
+	reg &= ~(0x3 << 16);
+	reg |= (p->num_b_frame << 16);
+	mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+	/* profile & level */
+	reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE);
+	/* level */
+	reg &= ~(0xFF << 8);
+	reg |= (p_264->level << 8);
+	/* profile - 0 ~ 2 */
+	reg &= ~(0x3F);
+	reg |= p_264->profile;
+	mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE);
+	/* interlace  */
+	mfc_write(dev, p->interlace, S5P_FIMV_ENC_PIC_STRUCT);
+	/* height */
+	if (p->interlace)
+		mfc_write(dev, ctx->img_height >> 1, S5P_FIMV_ENC_VSIZE_PX);
+	/* loopfilter ctrl */
+	mfc_write(dev, p_264->loop_filter_mode, S5P_FIMV_ENC_LF_CTRL);
+	/* loopfilter alpha offset */
+	if (p_264->loop_filter_alpha < 0) {
+		reg = 0x10;
+		reg |= (0xFF - p_264->loop_filter_alpha) + 1;
+	} else {
+		reg = 0x00;
+		reg |= (p_264->loop_filter_alpha & 0xF);
+	}
+	mfc_write(dev, reg, S5P_FIMV_ENC_ALPHA_OFF);
+	/* loopfilter beta offset */
+	if (p_264->loop_filter_beta < 0) {
+		reg = 0x10;
+		reg |= (0xFF - p_264->loop_filter_beta) + 1;
+	} else {
+		reg = 0x00;
+		reg |= (p_264->loop_filter_beta & 0xF);
+	}
+	mfc_write(dev, reg, S5P_FIMV_ENC_BETA_OFF);
+	/* entropy coding mode */
+	if (p_264->entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)
+		mfc_write(dev, 1, S5P_FIMV_ENC_H264_ENTROPY_MODE);
+	else
+		mfc_write(dev, 0, S5P_FIMV_ENC_H264_ENTROPY_MODE);
+	/* number of ref. picture */
+	reg = mfc_read(dev, S5P_FIMV_ENC_H264_NUM_OF_REF);
+	/* num of ref. pictures of P */
+	reg &= ~(0x3 << 5);
+	reg |= (p_264->num_ref_pic_4p << 5);
+	/* max number of ref. pictures */
+	reg &= ~(0x1F);
+	reg |= p_264->max_ref_pic;
+	mfc_write(dev, reg, S5P_FIMV_ENC_H264_NUM_OF_REF);
+	/* 8x8 transform enable */
+	mfc_write(dev, p_264->_8x8_transform, S5P_FIMV_ENC_H264_TRANS_FLAG);
+	/* rate control config. */
+	reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
+	/* macroblock level rate control */
+	reg &= ~(0x1 << 8);
+	reg |= (p_264->rc_mb << 8);
+	/* frame QP */
+	reg &= ~(0x3F);
+	reg |= p_264->rc_frame_qp;
+	mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
+	/* frame rate */
+	if (p->rc_frame && p->rc_framerate_denom)
+		mfc_write(dev, p->rc_framerate_num * 1000
+			/ p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE);
+	else
+		mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
+	/* max & min value of QP */
+	reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND);
+	/* max QP */
+	reg &= ~(0x3F << 8);
+	reg |= (p_264->rc_max_qp << 8);
+	/* min QP */
+	reg &= ~(0x3F);
+	reg |= p_264->rc_min_qp;
+	mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND);
+	/* macroblock adaptive scaling features */
+	if (p_264->rc_mb) {
+		reg = mfc_read(dev, S5P_FIMV_ENC_RC_MB_CTRL);
+		/* dark region */
+		reg &= ~(0x1 << 3);
+		reg |= (p_264->rc_mb_dark << 3);
+		/* smooth region */
+		reg &= ~(0x1 << 2);
+		reg |= (p_264->rc_mb_smooth << 2);
+		/* static region */
+		reg &= ~(0x1 << 1);
+		reg |= (p_264->rc_mb_static << 1);
+		/* high activity region */
+		reg &= ~(0x1);
+		reg |= p_264->rc_mb_activity;
+		mfc_write(dev, reg, S5P_FIMV_ENC_RC_MB_CTRL);
+	}
+	if (!p->rc_frame &&
+	    !p_264->rc_mb) {
+		shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP);
+		shm &= ~(0xFFF);
+		shm |= ((p_264->rc_b_frame_qp & 0x3F) << 6);
+		shm |= (p_264->rc_p_frame_qp & 0x3F);
+		s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP);
+	}
+	/* extended encoder ctrl */
+	shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+	/* AR VUI control */
+	shm &= ~(0x1 << 15);
+	shm |= (p_264->vui_sar << 1);
+	s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+	if (p_264->vui_sar) {
+		/* aspect ration IDC */
+		shm = s5p_mfc_read_shm(ctx, SAMPLE_ASPECT_RATIO_IDC);
+		shm &= ~(0xFF);
+		shm |= p_264->vui_sar_idc;
+		s5p_mfc_write_shm(ctx, shm, SAMPLE_ASPECT_RATIO_IDC);
+		if (p_264->vui_sar_idc == 0xFF) {
+			/* sample  AR info */
+			shm = s5p_mfc_read_shm(ctx, EXTENDED_SAR);
+			shm &= ~(0xFFFFFFFF);
+			shm |= p_264->vui_ext_sar_width << 16;
+			shm |= p_264->vui_ext_sar_height;
+			s5p_mfc_write_shm(ctx, shm, EXTENDED_SAR);
+		}
+	}
+	/* intra picture period for H.264 */
+	shm = s5p_mfc_read_shm(ctx, H264_I_PERIOD);
+	/* control */
+	shm &= ~(0x1 << 16);
+	shm |= (p_264->open_gop << 16);
+	/* value */
+	if (p_264->open_gop) {
+		shm &= ~(0xFFFF);
+		shm |= p_264->open_gop_size;
+	}
+	s5p_mfc_write_shm(ctx, shm, H264_I_PERIOD);
+	/* extended encoder ctrl */
+	shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+	/* vbv buffer size */
+	if (p->frame_skip_mode ==
+			V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
+		shm &= ~(0xFFFF << 16);
+		shm |= (p_264->cpb_size << 16);
+	}
+	s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+	return 0;
+}
+
+static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	struct s5p_mfc_enc_params *p = &ctx->enc_params;
+	struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4;
+	unsigned int reg;
+	unsigned int shm;
+	unsigned int framerate;
+
+	s5p_mfc_set_enc_params(ctx);
+	/* pictype : number of B */
+	reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+	/* num_b_frame - 0 ~ 2 */
+	reg &= ~(0x3 << 16);
+	reg |= (p->num_b_frame << 16);
+	mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+	/* profile & level */
+	reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE);
+	/* level */
+	reg &= ~(0xFF << 8);
+	reg |= (p_mpeg4->level << 8);
+	/* profile - 0 ~ 2 */
+	reg &= ~(0x3F);
+	reg |= p_mpeg4->profile;
+	mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE);
+	/* quarter_pixel */
+	mfc_write(dev, p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL);
+	/* qp */
+	if (!p->rc_frame) {
+		shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP);
+		shm &= ~(0xFFF);
+		shm |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 6);
+		shm |= (p_mpeg4->rc_p_frame_qp & 0x3F);
+		s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP);
+	}
+	/* frame rate */
+	if (p->rc_frame) {
+		if (p->rc_framerate_denom > 0) {
+			framerate = p->rc_framerate_num * 1000 /
+						p->rc_framerate_denom;
+			mfc_write(dev, framerate,
+				S5P_FIMV_ENC_RC_FRAME_RATE);
+			shm = s5p_mfc_read_shm(ctx, RC_VOP_TIMING);
+			shm &= ~(0xFFFFFFFF);
+			shm |= (1 << 31);
+			shm |= ((p->rc_framerate_num & 0x7FFF) << 16);
+			shm |= (p->rc_framerate_denom & 0xFFFF);
+			s5p_mfc_write_shm(ctx, shm, RC_VOP_TIMING);
+		}
+	} else {
+		mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
+	}
+	/* rate control config. */
+	reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
+	/* frame QP */
+	reg &= ~(0x3F);
+	reg |= p_mpeg4->rc_frame_qp;
+	mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
+	/* max & min value of QP */
+	reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND);
+	/* max QP */
+	reg &= ~(0x3F << 8);
+	reg |= (p_mpeg4->rc_max_qp << 8);
+	/* min QP */
+	reg &= ~(0x3F);
+	reg |= p_mpeg4->rc_min_qp;
+	mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND);
+	/* extended encoder ctrl */
+	shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+	/* vbv buffer size */
+	if (p->frame_skip_mode ==
+			V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
+		shm &= ~(0xFFFF << 16);
+		shm |= (p->vbv_size << 16);
+	}
+	s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+	return 0;
+}
+
+static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	struct s5p_mfc_enc_params *p = &ctx->enc_params;
+	struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4;
+	unsigned int reg;
+	unsigned int shm;
+
+	s5p_mfc_set_enc_params(ctx);
+	/* qp */
+	if (!p->rc_frame) {
+		shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP);
+		shm &= ~(0xFFF);
+		shm |= (p_h263->rc_p_frame_qp & 0x3F);
+		s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP);
+	}
+	/* frame rate */
+	if (p->rc_frame && p->rc_framerate_denom)
+		mfc_write(dev, p->rc_framerate_num * 1000
+			/ p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE);
+	else
+		mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
+	/* rate control config. */
+	reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
+	/* frame QP */
+	reg &= ~(0x3F);
+	reg |= p_h263->rc_frame_qp;
+	mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
+	/* max & min value of QP */
+	reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND);
+	/* max QP */
+	reg &= ~(0x3F << 8);
+	reg |= (p_h263->rc_max_qp << 8);
+	/* min QP */
+	reg &= ~(0x3F);
+	reg |= p_h263->rc_min_qp;
+	mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND);
+	/* extended encoder ctrl */
+	shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+	/* vbv buffer size */
+	if (p->frame_skip_mode ==
+			V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
+		shm &= ~(0xFFFF << 16);
+		shm |= (p->vbv_size << 16);
+	}
+	s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+	return 0;
+}
+
+/* Initialize decoding */
+int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	s5p_mfc_set_shared_buffer(ctx);
+	/* Setup loop filter, for decoding this is only valid for MPEG4 */
+	if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_DEC)
+		mfc_write(dev, ctx->loop_filter_mpeg4, S5P_FIMV_ENC_LF_CTRL);
+	else
+		mfc_write(dev, 0, S5P_FIMV_ENC_LF_CTRL);
+	mfc_write(dev, ((ctx->slice_interface & S5P_FIMV_SLICE_INT_MASK) <<
+		S5P_FIMV_SLICE_INT_SHIFT) | (ctx->display_delay_enable <<
+		S5P_FIMV_DDELAY_ENA_SHIFT) | ((ctx->display_delay &
+		S5P_FIMV_DDELAY_VAL_MASK) << S5P_FIMV_DDELAY_VAL_SHIFT),
+		S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+	mfc_write(dev,
+	((S5P_FIMV_CH_SEQ_HEADER & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT)
+				| (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+	return 0;
+}
+
+static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	unsigned int dpb;
+
+	if (flush)
+		dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | (
+			S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT);
+	else
+		dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) &
+			~(S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT);
+	mfc_write(dev, dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+}
+
+/* Decode a single frame */
+int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx,
+					enum s5p_mfc_decode_arg last_frame)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	mfc_write(dev, ctx->dec_dst_flag, S5P_FIMV_SI_CH0_RELEASE_BUF);
+	s5p_mfc_set_shared_buffer(ctx);
+	s5p_mfc_set_flush(ctx, ctx->dpb_flush_flag);
+	/* Issue different commands to instance basing on whether it
+	 * is the last frame or not. */
+	switch (last_frame) {
+	case MFC_DEC_FRAME:
+		mfc_write(dev, ((S5P_FIMV_CH_FRAME_START & S5P_FIMV_CH_MASK) <<
+		S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+		break;
+	case MFC_DEC_LAST_FRAME:
+		mfc_write(dev, ((S5P_FIMV_CH_LAST_FRAME & S5P_FIMV_CH_MASK) <<
+		S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+		break;
+	case MFC_DEC_RES_CHANGE:
+		mfc_write(dev, ((S5P_FIMV_CH_FRAME_START_REALLOC &
+		S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) | (ctx->inst_no),
+		S5P_FIMV_SI_CH0_INST_ID);
+		break;
+	}
+	mfc_debug(2, "Decoding a usual frame\n");
+	return 0;
+}
+
+int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC)
+		s5p_mfc_set_enc_params_h264(ctx);
+	else if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_ENC)
+		s5p_mfc_set_enc_params_mpeg4(ctx);
+	else if (ctx->codec_mode == S5P_FIMV_CODEC_H263_ENC)
+		s5p_mfc_set_enc_params_h263(ctx);
+	else {
+		mfc_err("Unknown codec for encoding (%x)\n",
+			ctx->codec_mode);
+		return -EINVAL;
+	}
+	s5p_mfc_set_shared_buffer(ctx);
+	mfc_write(dev, ((S5P_FIMV_CH_SEQ_HEADER << 16) & 0x70000) |
+		(ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+	return 0;
+}
+
+/* Encode a single frame */
+int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	/* memory structure cur. frame */
+	if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M)
+		mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR);
+	else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT)
+		mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR);
+	s5p_mfc_set_shared_buffer(ctx);
+	mfc_write(dev, (S5P_FIMV_CH_FRAME_START << 16 & 0x70000) |
+		(ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+	return 0;
+}
+
+static int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev)
+{
+	unsigned long flags;
+	int new_ctx;
+	int cnt;
+
+	spin_lock_irqsave(&dev->condlock, flags);
+	new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS;
+	cnt = 0;
+	while (!test_bit(new_ctx, &dev->ctx_work_bits)) {
+		new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS;
+		if (++cnt > MFC_NUM_CONTEXTS) {
+			/* No contexts to run */
+			spin_unlock_irqrestore(&dev->condlock, flags);
+			return -EAGAIN;
+		}
+	}
+	spin_unlock_irqrestore(&dev->condlock, flags);
+	return new_ctx;
+}
+
+static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+
+	s5p_mfc_set_dec_stream_buffer(ctx, 0, 0, 0);
+	dev->curr_ctx = ctx->num;
+	s5p_mfc_clean_ctx_int_flags(ctx);
+	s5p_mfc_decode_one_frame(ctx, MFC_DEC_RES_CHANGE);
+}
+
+static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	struct s5p_mfc_buf *temp_vb;
+	unsigned long flags;
+	unsigned int index;
+
+	spin_lock_irqsave(&dev->irqlock, flags);
+	/* Frames are being decoded */
+	if (list_empty(&ctx->src_queue)) {
+		mfc_debug(2, "No src buffers\n");
+		spin_unlock_irqrestore(&dev->irqlock, flags);
+		return -EAGAIN;
+	}
+	/* Get the next source buffer */
+	temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+	temp_vb->used = 1;
+	s5p_mfc_set_dec_stream_buffer(ctx,
+		vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), ctx->consumed_stream,
+					temp_vb->b->v4l2_planes[0].bytesused);
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+	index = temp_vb->b->v4l2_buf.index;
+	dev->curr_ctx = ctx->num;
+	s5p_mfc_clean_ctx_int_flags(ctx);
+	if (temp_vb->b->v4l2_planes[0].bytesused == 0) {
+		last_frame = MFC_DEC_LAST_FRAME;
+		mfc_debug(2, "Setting ctx->state to FINISHING\n");
+		ctx->state = MFCINST_FINISHING;
+	}
+	s5p_mfc_decode_one_frame(ctx, last_frame);
+	return 0;
+}
+
+static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	unsigned long flags;
+	struct s5p_mfc_buf *dst_mb;
+	struct s5p_mfc_buf *src_mb;
+	unsigned long src_y_addr, src_c_addr, dst_addr;
+	unsigned int dst_size;
+
+	spin_lock_irqsave(&dev->irqlock, flags);
+	if (list_empty(&ctx->src_queue)) {
+		mfc_debug(2, "no src buffers\n");
+		spin_unlock_irqrestore(&dev->irqlock, flags);
+		return -EAGAIN;
+	}
+	if (list_empty(&ctx->dst_queue)) {
+		mfc_debug(2, "no dst buffers\n");
+		spin_unlock_irqrestore(&dev->irqlock, flags);
+		return -EAGAIN;
+	}
+	src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+	src_mb->used = 1;
+	src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0);
+	src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1);
+	s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr);
+	dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+	dst_mb->used = 1;
+	dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
+	dst_size = vb2_plane_size(dst_mb->b, 0);
+	s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+	dev->curr_ctx = ctx->num;
+	s5p_mfc_clean_ctx_int_flags(ctx);
+	s5p_mfc_encode_one_frame(ctx);
+	return 0;
+}
+
+static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	unsigned long flags;
+	struct s5p_mfc_buf *temp_vb;
+
+	/* Initializing decoding - parsing header */
+	spin_lock_irqsave(&dev->irqlock, flags);
+	mfc_debug(2, "Preparing to init decoding\n");
+	temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+	s5p_mfc_set_dec_desc_buffer(ctx);
+	mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused);
+	s5p_mfc_set_dec_stream_buffer(ctx,
+				vb2_dma_contig_plane_dma_addr(temp_vb->b, 0),
+				0, temp_vb->b->v4l2_planes[0].bytesused);
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+	dev->curr_ctx = ctx->num;
+	s5p_mfc_clean_ctx_int_flags(ctx);
+	s5p_mfc_init_decode(ctx);
+}
+
+static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	unsigned long flags;
+	struct s5p_mfc_buf *dst_mb;
+	unsigned long dst_addr;
+	unsigned int dst_size;
+
+	s5p_mfc_set_enc_ref_buffer(ctx);
+	spin_lock_irqsave(&dev->irqlock, flags);
+	dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+	dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
+	dst_size = vb2_plane_size(dst_mb->b, 0);
+	s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+	dev->curr_ctx = ctx->num;
+	s5p_mfc_clean_ctx_int_flags(ctx);
+	s5p_mfc_init_encode(ctx);
+}
+
+static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	unsigned long flags;
+	struct s5p_mfc_buf *temp_vb;
+	int ret;
+
+	/*
+	 * Header was parsed now starting processing
+	 * First set the output frame buffers
+	 */
+	if (ctx->capture_state != QUEUE_BUFS_MMAPED) {
+		mfc_err("It seems that not all destionation buffers were "
+			"mmaped\nMFC requires that all destination are mmaped "
+			"before starting processing\n");
+		return -EAGAIN;
+	}
+	spin_lock_irqsave(&dev->irqlock, flags);
+	if (list_empty(&ctx->src_queue)) {
+		mfc_err("Header has been deallocated in the middle of"
+			" initialization\n");
+		spin_unlock_irqrestore(&dev->irqlock, flags);
+		return -EIO;
+	}
+	temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+	mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused);
+	s5p_mfc_set_dec_stream_buffer(ctx,
+				vb2_dma_contig_plane_dma_addr(temp_vb->b, 0),
+				0, temp_vb->b->v4l2_planes[0].bytesused);
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+	dev->curr_ctx = ctx->num;
+	s5p_mfc_clean_ctx_int_flags(ctx);
+	ret = s5p_mfc_set_dec_frame_buffer(ctx);
+	if (ret) {
+		mfc_err("Failed to alloc frame mem\n");
+		ctx->state = MFCINST_ERROR;
+	}
+	return ret;
+}
+
+/* Try running an operation on hardware */
+void s5p_mfc_try_run(struct s5p_mfc_dev *dev)
+{
+	struct s5p_mfc_ctx *ctx;
+	int new_ctx;
+	unsigned int ret = 0;
+
+	if (test_bit(0, &dev->enter_suspend)) {
+		mfc_debug(1, "Entering suspend so do not schedule any jobs\n");
+		return;
+	}
+	/* Check whether hardware is not running */
+	if (test_and_set_bit(0, &dev->hw_lock) != 0) {
+		/* This is perfectly ok, the scheduled ctx should wait */
+		mfc_debug(1, "Couldn't lock HW\n");
+		return;
+	}
+	/* Choose the context to run */
+	new_ctx = s5p_mfc_get_new_ctx(dev);
+	if (new_ctx < 0) {
+		/* No contexts to run */
+		if (test_and_clear_bit(0, &dev->hw_lock) == 0) {
+			mfc_err("Failed to unlock hardware\n");
+			return;
+		}
+		mfc_debug(1, "No ctx is scheduled to be run\n");
+		return;
+	}
+	ctx = dev->ctx[new_ctx];
+	/* Got context to run in ctx */
+	/*
+	 * Last frame has already been sent to MFC.
+	 * Now obtaining frames from MFC buffer
+	 */
+	s5p_mfc_clock_on();
+	if (ctx->type == MFCINST_DECODER) {
+		s5p_mfc_set_dec_desc_buffer(ctx);
+		switch (ctx->state) {
+		case MFCINST_FINISHING:
+			s5p_mfc_run_dec_frame(ctx, MFC_DEC_LAST_FRAME);
+			break;
+		case MFCINST_RUNNING:
+			ret = s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME);
+			break;
+		case MFCINST_INIT:
+			s5p_mfc_clean_ctx_int_flags(ctx);
+			ret = s5p_mfc_open_inst_cmd(ctx);
+			break;
+		case MFCINST_RETURN_INST:
+			s5p_mfc_clean_ctx_int_flags(ctx);
+			ret = s5p_mfc_close_inst_cmd(ctx);
+			break;
+		case MFCINST_GOT_INST:
+			s5p_mfc_run_init_dec(ctx);
+			break;
+		case MFCINST_HEAD_PARSED:
+			ret = s5p_mfc_run_init_dec_buffers(ctx);
+			mfc_debug(1, "head parsed\n");
+			break;
+		case MFCINST_RES_CHANGE_INIT:
+			s5p_mfc_run_res_change(ctx);
+			break;
+		case MFCINST_RES_CHANGE_FLUSH:
+			s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME);
+			break;
+		case MFCINST_RES_CHANGE_END:
+			mfc_debug(2, "Finished remaining frames after resolution change\n");
+			ctx->capture_state = QUEUE_FREE;
+			mfc_debug(2, "Will re-init the codec\n");
+			s5p_mfc_run_init_dec(ctx);
+			break;
+		default:
+			ret = -EAGAIN;
+		}
+	} else if (ctx->type == MFCINST_ENCODER) {
+		switch (ctx->state) {
+		case MFCINST_FINISHING:
+		case MFCINST_RUNNING:
+			ret = s5p_mfc_run_enc_frame(ctx);
+			break;
+		case MFCINST_INIT:
+			s5p_mfc_clean_ctx_int_flags(ctx);
+			ret = s5p_mfc_open_inst_cmd(ctx);
+			break;
+		case MFCINST_RETURN_INST:
+			s5p_mfc_clean_ctx_int_flags(ctx);
+			ret = s5p_mfc_close_inst_cmd(ctx);
+			break;
+		case MFCINST_GOT_INST:
+			s5p_mfc_run_init_enc(ctx);
+			break;
+		default:
+			ret = -EAGAIN;
+		}
+	} else {
+		mfc_err("Invalid context type: %d\n", ctx->type);
+		ret = -EAGAIN;
+	}
+
+	if (ret) {
+		/* Free hardware lock */
+		if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+			mfc_err("Failed to unlock hardware\n");
+
+		/* This is in deed imporant, as no operation has been
+		 * scheduled, reduce the clock count as no one will
+		 * ever do this, because no interrupt related to this try_run
+		 * will ever come from hardware. */
+		s5p_mfc_clock_off();
+	}
+}
+
+
+void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq)
+{
+	struct s5p_mfc_buf *b;
+	int i;
+
+	while (!list_empty(lh)) {
+		b = list_entry(lh->next, struct s5p_mfc_buf, list);
+		for (i = 0; i < b->b->num_planes; i++)
+			vb2_set_plane_payload(b->b, i, 0);
+		vb2_buffer_done(b->b, VB2_BUF_STATE_ERROR);
+		list_del(&b->list);
+	}
+}
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
new file mode 100644
index 0000000..2ad3def
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
@@ -0,0 +1,93 @@
+/*
+ * drivers/media/platform/samsung/mfc5/s5p_mfc_opr.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * Contains declarations of hw related functions.
+ *
+ * Kamil Debski, Copyright (C) 2011 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef S5P_MFC_OPR_H_
+#define S5P_MFC_OPR_H_
+
+#include "s5p_mfc_common.h"
+
+int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_init_encode(struct s5p_mfc_ctx *mfc_ctx);
+
+/* Decoding functions */
+int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr,
+						  unsigned int start_num_byte,
+						  unsigned int buf_size);
+
+/* Encoding functions */
+void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+		unsigned long y_addr, unsigned long c_addr);
+int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
+		unsigned long addr, unsigned int size);
+void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+		unsigned long *y_addr, unsigned long *c_addr);
+int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *mfc_ctx);
+
+int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx,
+					enum s5p_mfc_decode_arg last_frame);
+int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *mfc_ctx);
+
+/* Memory allocation */
+int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx);
+
+void s5p_mfc_try_run(struct s5p_mfc_dev *dev);
+void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq);
+
+#define s5p_mfc_get_dspl_y_adr()	(readl(dev->regs_base + \
+					S5P_FIMV_SI_DISPLAY_Y_ADR) << \
+					MFC_OFFSET_SHIFT)
+#define s5p_mfc_get_dec_y_adr()		(readl(dev->regs_base + \
+					S5P_FIMV_SI_DECODE_Y_ADR) << \
+					MFC_OFFSET_SHIFT)
+#define s5p_mfc_get_dspl_status()	readl(dev->regs_base + \
+						S5P_FIMV_SI_DISPLAY_STATUS)
+#define s5p_mfc_get_dec_status()	readl(dev->regs_base + \
+						S5P_FIMV_SI_DECODE_STATUS)
+#define s5p_mfc_get_frame_type()	(readl(dev->regs_base + \
+						S5P_FIMV_DECODE_FRAME_TYPE) \
+					& S5P_FIMV_DECODE_FRAME_MASK)
+#define s5p_mfc_get_consumed_stream()	readl(dev->regs_base + \
+						S5P_FIMV_SI_CONSUMED_BYTES)
+#define s5p_mfc_get_int_reason()	(readl(dev->regs_base + \
+					S5P_FIMV_RISC2HOST_CMD) & \
+					S5P_FIMV_RISC2HOST_CMD_MASK)
+#define s5p_mfc_get_int_err()		readl(dev->regs_base + \
+						S5P_FIMV_RISC2HOST_ARG2)
+#define s5p_mfc_err_dec(x)		(((x) & S5P_FIMV_ERR_DEC_MASK) >> \
+							S5P_FIMV_ERR_DEC_SHIFT)
+#define s5p_mfc_err_dspl(x)		(((x) & S5P_FIMV_ERR_DSPL_MASK) >> \
+							S5P_FIMV_ERR_DSPL_SHIFT)
+#define s5p_mfc_get_img_width()		readl(dev->regs_base + \
+						S5P_FIMV_SI_HRESOL)
+#define s5p_mfc_get_img_height()	readl(dev->regs_base + \
+						S5P_FIMV_SI_VRESOL)
+#define s5p_mfc_get_dpb_count()		readl(dev->regs_base + \
+						S5P_FIMV_SI_BUF_NUMBER)
+#define s5p_mfc_get_inst_no()		readl(dev->regs_base + \
+						S5P_FIMV_RISC2HOST_ARG1)
+#define s5p_mfc_get_enc_strm_size()	readl(dev->regs_base + \
+						S5P_FIMV_ENC_SI_STRM_SIZE)
+#define s5p_mfc_get_enc_slice_type()	readl(dev->regs_base + \
+						S5P_FIMV_ENC_SI_SLICE_TYPE)
+
+#endif /* S5P_MFC_OPR_H_ */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
new file mode 100644
index 0000000..0503d14
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
@@ -0,0 +1,137 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#ifdef CONFIG_PM_RUNTIME
+#include <linux/pm_runtime.h>
+#endif
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_pm.h"
+
+#define MFC_CLKNAME		"sclk_mfc"
+#define MFC_GATE_CLK_NAME	"mfc"
+
+#define CLK_DEBUG
+
+static struct s5p_mfc_pm *pm;
+static struct s5p_mfc_dev *p_dev;
+
+#ifdef CLK_DEBUG
+atomic_t clk_ref;
+#endif
+
+int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
+{
+	int ret = 0;
+
+	pm = &dev->pm;
+	p_dev = dev;
+	pm->clock_gate = clk_get(&dev->plat_dev->dev, MFC_GATE_CLK_NAME);
+	if (IS_ERR(pm->clock_gate)) {
+		mfc_err("Failed to get clock-gating control\n");
+		ret = PTR_ERR(pm->clock_gate);
+		goto err_g_ip_clk;
+	}
+
+	ret = clk_prepare(pm->clock_gate);
+	if (ret) {
+		mfc_err("Failed to preapre clock-gating control\n");
+		goto err_p_ip_clk;
+	}
+
+	pm->clock = clk_get(&dev->plat_dev->dev, MFC_CLKNAME);
+	if (IS_ERR(pm->clock)) {
+		mfc_err("Failed to get MFC clock\n");
+		ret = PTR_ERR(pm->clock);
+		goto err_g_ip_clk_2;
+	}
+
+	ret = clk_prepare(pm->clock);
+	if (ret) {
+		mfc_err("Failed to prepare MFC clock\n");
+		goto err_p_ip_clk_2;
+	}
+
+	atomic_set(&pm->power, 0);
+#ifdef CONFIG_PM_RUNTIME
+	pm->device = &dev->plat_dev->dev;
+	pm_runtime_enable(pm->device);
+#endif
+#ifdef CLK_DEBUG
+	atomic_set(&clk_ref, 0);
+#endif
+	return 0;
+err_p_ip_clk_2:
+	clk_put(pm->clock);
+err_g_ip_clk_2:
+	clk_unprepare(pm->clock_gate);
+err_p_ip_clk:
+	clk_put(pm->clock_gate);
+err_g_ip_clk:
+	return ret;
+}
+
+void s5p_mfc_final_pm(struct s5p_mfc_dev *dev)
+{
+	clk_unprepare(pm->clock_gate);
+	clk_put(pm->clock_gate);
+	clk_unprepare(pm->clock);
+	clk_put(pm->clock);
+#ifdef CONFIG_PM_RUNTIME
+	pm_runtime_disable(pm->device);
+#endif
+}
+
+int s5p_mfc_clock_on(void)
+{
+	int ret;
+#ifdef CLK_DEBUG
+	atomic_inc(&clk_ref);
+	mfc_debug(3, "+ %d", atomic_read(&clk_ref));
+#endif
+	ret = clk_enable(pm->clock_gate);
+	return ret;
+}
+
+void s5p_mfc_clock_off(void)
+{
+#ifdef CLK_DEBUG
+	atomic_dec(&clk_ref);
+	mfc_debug(3, "- %d", atomic_read(&clk_ref));
+#endif
+	clk_disable(pm->clock_gate);
+}
+
+int s5p_mfc_power_on(void)
+{
+#ifdef CONFIG_PM_RUNTIME
+	return pm_runtime_get_sync(pm->device);
+#else
+	atomic_set(&pm->power, 1);
+	return 0;
+#endif
+}
+
+int s5p_mfc_power_off(void)
+{
+#ifdef CONFIG_PM_RUNTIME
+	return pm_runtime_put_sync(pm->device);
+#else
+	atomic_set(&pm->power, 0);
+	return 0;
+#endif
+}
+
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.h b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.h
new file mode 100644
index 0000000..875c534
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.h
@@ -0,0 +1,24 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_pm.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef S5P_MFC_PM_H_
+#define S5P_MFC_PM_H_
+
+int s5p_mfc_init_pm(struct s5p_mfc_dev *dev);
+void s5p_mfc_final_pm(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_clock_on(void);
+void s5p_mfc_clock_off(void);
+int s5p_mfc_power_on(void);
+int s5p_mfc_power_off(void);
+
+#endif /* S5P_MFC_PM_H_ */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c
new file mode 100644
index 0000000..b5933d2
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c
@@ -0,0 +1,47 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifdef CONFIG_ARCH_EXYNOS4
+#include <linux/dma-mapping.h>
+#endif
+#include <linux/io.h>
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+
+int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	void *shm_alloc_ctx = dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
+
+	ctx->shm_alloc = vb2_dma_contig_memops.alloc(shm_alloc_ctx,
+							SHARED_BUF_SIZE);
+	if (IS_ERR(ctx->shm_alloc)) {
+		mfc_err("failed to allocate shared memory\n");
+		return PTR_ERR(ctx->shm_alloc);
+	}
+	/* shm_ofs only keeps the offset from base (port a) */
+	ctx->shm_ofs = s5p_mfc_mem_cookie(shm_alloc_ctx, ctx->shm_alloc)
+								- dev->bank1;
+	BUG_ON(ctx->shm_ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+	ctx->shm = vb2_dma_contig_memops.vaddr(ctx->shm_alloc);
+	if (!ctx->shm) {
+		vb2_dma_contig_memops.put(ctx->shm_alloc);
+		ctx->shm_ofs = 0;
+		ctx->shm_alloc = NULL;
+		mfc_err("failed to virt addr of shared memory\n");
+		return -ENOMEM;
+	}
+	memset((void *)ctx->shm, 0, SHARED_BUF_SIZE);
+	wmb();
+	return 0;
+}
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h b/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h
new file mode 100644
index 0000000..416ebd7
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h
@@ -0,0 +1,90 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef S5P_MFC_SHM_H_
+#define S5P_MFC_SHM_H_
+
+enum MFC_SHM_OFS {
+	EXTENEDED_DECODE_STATUS	= 0x00,	/* D */
+	SET_FRAME_TAG		= 0x04, /* D */
+	GET_FRAME_TAG_TOP	= 0x08, /* D */
+	GET_FRAME_TAG_BOT	= 0x0C, /* D */
+	PIC_TIME_TOP		= 0x10, /* D */
+	PIC_TIME_BOT		= 0x14, /* D */
+	START_BYTE_NUM		= 0x18, /* D */
+
+	CROP_INFO_H		= 0x20, /* D */
+	CROP_INFO_V		= 0x24, /* D */
+	EXT_ENC_CONTROL		= 0x28,	/* E */
+	ENC_PARAM_CHANGE	= 0x2C,	/* E */
+	RC_VOP_TIMING		= 0x30,	/* E, MPEG4 */
+	HEC_PERIOD		= 0x34,	/* E, MPEG4 */
+	METADATA_ENABLE		= 0x38, /* C */
+	METADATA_STATUS		= 0x3C, /* C */
+	METADATA_DISPLAY_INDEX	= 0x40,	/* C */
+	EXT_METADATA_START_ADDR	= 0x44, /* C */
+	PUT_EXTRADATA		= 0x48, /* C */
+	EXTRADATA_ADDR		= 0x4C, /* C */
+
+	ALLOC_LUMA_DPB_SIZE	= 0x64,	/* D */
+	ALLOC_CHROMA_DPB_SIZE	= 0x68,	/* D */
+	ALLOC_MV_SIZE		= 0x6C,	/* D */
+	P_B_FRAME_QP		= 0x70,	/* E */
+	SAMPLE_ASPECT_RATIO_IDC	= 0x74, /* E, H.264, depend on
+				ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */
+	EXTENDED_SAR		= 0x78, /* E, H.264, depned on
+				ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */
+	DISP_PIC_PROFILE	= 0x7C, /* D */
+	FLUSH_CMD_TYPE		= 0x80, /* C */
+	FLUSH_CMD_INBUF1	= 0x84, /* C */
+	FLUSH_CMD_INBUF2	= 0x88, /* C */
+	FLUSH_CMD_OUTBUF	= 0x8C, /* E */
+	NEW_RC_BIT_RATE		= 0x90, /* E, format as RC_BIT_RATE(0xC5A8)
+			depend on RC_BIT_RATE_CHANGE in ENC_PARAM_CHANGE */
+	NEW_RC_FRAME_RATE	= 0x94, /* E, format as RC_FRAME_RATE(0xD0D0)
+			depend on RC_FRAME_RATE_CHANGE in ENC_PARAM_CHANGE */
+	NEW_I_PERIOD		= 0x98, /* E, format as I_FRM_CTRL(0xC504)
+			depend on I_PERIOD_CHANGE in ENC_PARAM_CHANGE */
+	H264_I_PERIOD		= 0x9C, /* E, H.264, open GOP */
+	RC_CONTROL_CONFIG	= 0xA0, /* E */
+	BATCH_INPUT_ADDR	= 0xA4, /* E */
+	BATCH_OUTPUT_ADDR	= 0xA8, /* E */
+	BATCH_OUTPUT_SIZE	= 0xAC, /* E */
+	MIN_LUMA_DPB_SIZE	= 0xB0, /* D */
+	DEVICE_FORMAT_ID	= 0xB4, /* C */
+	H264_POC_TYPE		= 0xB8, /* D */
+	MIN_CHROMA_DPB_SIZE	= 0xBC, /* D */
+	DISP_PIC_FRAME_TYPE	= 0xC0, /* D */
+	FREE_LUMA_DPB		= 0xC4, /* D, VC1 MPEG4 */
+	ASPECT_RATIO_INFO	= 0xC8, /* D, MPEG4 */
+	EXTENDED_PAR		= 0xCC, /* D, MPEG4 */
+	DBG_HISTORY_INPUT0	= 0xD0, /* C */
+	DBG_HISTORY_INPUT1	= 0xD4,	/* C */
+	DBG_HISTORY_OUTPUT	= 0xD8,	/* C */
+	HIERARCHICAL_P_QP	= 0xE0, /* E, H.264 */
+};
+
+int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx);
+
+#define s5p_mfc_write_shm(ctx, x, ofs)		\
+	do {					\
+		writel(x, (ctx->shm + ofs));	\
+		wmb();				\
+	} while (0)
+
+static inline u32 s5p_mfc_read_shm(struct s5p_mfc_ctx *ctx, unsigned int ofs)
+{
+	rmb();
+	return readl(ctx->shm + ofs);
+}
+
+#endif /* S5P_MFC_SHM_H_ */
diff --git a/drivers/media/platform/s5p-tv/Kconfig b/drivers/media/platform/s5p-tv/Kconfig
new file mode 100644
index 0000000..ea11a51
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/Kconfig
@@ -0,0 +1,86 @@
+# drivers/media/platform/s5p-tv/Kconfig
+#
+# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+#	http://www.samsung.com/
+# Tomasz Stanislawski <t.stanislaws@samsung.com>
+#
+# Licensed under GPL
+
+config VIDEO_SAMSUNG_S5P_TV
+	bool "Samsung TV driver for S5P platform (experimental)"
+	depends on PLAT_S5P && PM_RUNTIME
+	depends on EXPERIMENTAL
+	default n
+	---help---
+	  Say Y here to enable selecting the TV output devices for
+	  Samsung S5P platform.
+
+if VIDEO_SAMSUNG_S5P_TV
+
+config VIDEO_SAMSUNG_S5P_HDMI
+	tristate "Samsung HDMI Driver"
+	depends on VIDEO_V4L2
+	depends on VIDEO_SAMSUNG_S5P_TV
+	select VIDEO_SAMSUNG_S5P_HDMIPHY
+	help
+	  Say Y here if you want support for the HDMI output
+	  interface in S5P Samsung SoC. The driver can be compiled
+	  as module. It is an auxiliary driver, that exposes a V4L2
+	  subdev for use by other drivers. This driver requires
+	  hdmiphy driver to work correctly.
+
+config VIDEO_SAMSUNG_S5P_HDMI_DEBUG
+	bool "Enable debug for HDMI Driver"
+	depends on VIDEO_SAMSUNG_S5P_HDMI
+	default n
+	help
+	  Enables debugging for HDMI driver.
+
+config VIDEO_SAMSUNG_S5P_HDMIPHY
+	tristate "Samsung HDMIPHY Driver"
+	depends on VIDEO_DEV && VIDEO_V4L2 && I2C
+	depends on VIDEO_SAMSUNG_S5P_TV
+	help
+	  Say Y here if you want support for the physical HDMI
+	  interface in S5P Samsung SoC. The driver can be compiled
+	  as module. It is an I2C driver, that exposes a V4L2
+	  subdev for use by other drivers.
+
+config VIDEO_SAMSUNG_S5P_SII9234
+	tristate "Samsung SII9234 Driver"
+	depends on VIDEO_DEV && VIDEO_V4L2 && I2C
+	depends on VIDEO_SAMSUNG_S5P_TV
+	help
+	  Say Y here if you want support for the MHL interface
+	  in S5P Samsung SoC. The driver can be compiled
+	  as module. It is an I2C driver, that exposes a V4L2
+	  subdev for use by other drivers.
+
+config VIDEO_SAMSUNG_S5P_SDO
+	tristate "Samsung Analog TV Driver"
+	depends on VIDEO_DEV && VIDEO_V4L2
+	depends on VIDEO_SAMSUNG_S5P_TV
+	help
+	  Say Y here if you want support for the analog TV output
+	  interface in S5P Samsung SoC. The driver can be compiled
+	  as module. It is an auxiliary driver, that exposes a V4L2
+	  subdev for use by other drivers. This driver requires
+	  hdmiphy driver to work correctly.
+
+config VIDEO_SAMSUNG_S5P_MIXER
+	tristate "Samsung Mixer and Video Processor Driver"
+	depends on VIDEO_DEV && VIDEO_V4L2
+	depends on VIDEO_SAMSUNG_S5P_TV
+	select VIDEOBUF2_DMA_CONTIG
+	help
+	  Say Y here if you want support for the Mixer in Samsung S5P SoCs.
+	  This device produce image data to one of output interfaces.
+
+config VIDEO_SAMSUNG_S5P_MIXER_DEBUG
+	bool "Enable debug for Mixer Driver"
+	depends on VIDEO_SAMSUNG_S5P_MIXER
+	default n
+	help
+	  Enables debugging for Mixer driver.
+
+endif # VIDEO_SAMSUNG_S5P_TV
diff --git a/drivers/media/platform/s5p-tv/Makefile b/drivers/media/platform/s5p-tv/Makefile
new file mode 100644
index 0000000..7cd4790
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/Makefile
@@ -0,0 +1,19 @@
+# drivers/media/platform/samsung/tvout/Makefile
+#
+# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+#	http://www.samsung.com/
+# Tomasz Stanislawski <t.stanislaws@samsung.com>
+#
+# Licensed under GPL
+
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMIPHY) += s5p-hdmiphy.o
+s5p-hdmiphy-y += hdmiphy_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SII9234) += s5p-sii9234.o
+s5p-sii9234-y += sii9234_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI) += s5p-hdmi.o
+s5p-hdmi-y += hdmi_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SDO) += s5p-sdo.o
+s5p-sdo-y += sdo_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MIXER) += s5p-mixer.o
+s5p-mixer-y += mixer_drv.o mixer_video.o mixer_reg.o mixer_grp_layer.o mixer_vp_layer.o
+
diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c
new file mode 100644
index 0000000..8a9cf43
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/hdmi_drv.c
@@ -0,0 +1,1009 @@
+/*
+ * Samsung HDMI interface driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#define pr_fmt(fmt) "s5p-tv (hdmi_drv): " fmt
+
+#ifdef CONFIG_VIDEO_SAMSUNG_S5P_HDMI_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-subdev.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/bug.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+
+#include <media/s5p_hdmi.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+
+#include "regs-hdmi.h"
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung HDMI");
+MODULE_LICENSE("GPL");
+
+/* default preset configured on probe */
+#define HDMI_DEFAULT_PRESET V4L2_DV_480P59_94
+
+struct hdmi_pulse {
+	u32 beg;
+	u32 end;
+};
+
+struct hdmi_timings {
+	struct hdmi_pulse hact;
+	u32 hsyn_pol; /* 0 - high, 1 - low */
+	struct hdmi_pulse hsyn;
+	u32 interlaced;
+	struct hdmi_pulse vact[2];
+	u32 vsyn_pol; /* 0 - high, 1 - low */
+	u32 vsyn_off;
+	struct hdmi_pulse vsyn[2];
+};
+
+struct hdmi_resources {
+	struct clk *hdmi;
+	struct clk *sclk_hdmi;
+	struct clk *sclk_pixel;
+	struct clk *sclk_hdmiphy;
+	struct clk *hdmiphy;
+	struct regulator_bulk_data *regul_bulk;
+	int regul_count;
+};
+
+struct hdmi_device {
+	/** base address of HDMI registers */
+	void __iomem *regs;
+	/** HDMI interrupt */
+	unsigned int irq;
+	/** pointer to device parent */
+	struct device *dev;
+	/** subdev generated by HDMI device */
+	struct v4l2_subdev sd;
+	/** V4L2 device structure */
+	struct v4l2_device v4l2_dev;
+	/** subdev of HDMIPHY interface */
+	struct v4l2_subdev *phy_sd;
+	/** subdev of MHL interface */
+	struct v4l2_subdev *mhl_sd;
+	/** configuration of current graphic mode */
+	const struct hdmi_timings *cur_conf;
+	/** flag indicating that timings are dirty */
+	int cur_conf_dirty;
+	/** current preset */
+	u32 cur_preset;
+	/** other resources */
+	struct hdmi_resources res;
+};
+
+static struct platform_device_id hdmi_driver_types[] = {
+	{
+		.name		= "s5pv210-hdmi",
+	}, {
+		.name		= "exynos4-hdmi",
+	}, {
+		/* end node */
+	}
+};
+
+static const struct v4l2_subdev_ops hdmi_sd_ops;
+
+static struct hdmi_device *sd_to_hdmi_dev(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct hdmi_device, sd);
+}
+
+static inline
+void hdmi_write(struct hdmi_device *hdev, u32 reg_id, u32 value)
+{
+	writel(value, hdev->regs + reg_id);
+}
+
+static inline
+void hdmi_write_mask(struct hdmi_device *hdev, u32 reg_id, u32 value, u32 mask)
+{
+	u32 old = readl(hdev->regs + reg_id);
+	value = (value & mask) | (old & ~mask);
+	writel(value, hdev->regs + reg_id);
+}
+
+static inline
+void hdmi_writeb(struct hdmi_device *hdev, u32 reg_id, u8 value)
+{
+	writeb(value, hdev->regs + reg_id);
+}
+
+static inline
+void hdmi_writebn(struct hdmi_device *hdev, u32 reg_id, int n, u32 value)
+{
+	switch (n) {
+	default:
+		writeb(value >> 24, hdev->regs + reg_id + 12);
+	case 3:
+		writeb(value >> 16, hdev->regs + reg_id + 8);
+	case 2:
+		writeb(value >>  8, hdev->regs + reg_id + 4);
+	case 1:
+		writeb(value >>  0, hdev->regs + reg_id + 0);
+	}
+}
+
+static inline u32 hdmi_read(struct hdmi_device *hdev, u32 reg_id)
+{
+	return readl(hdev->regs + reg_id);
+}
+
+static irqreturn_t hdmi_irq_handler(int irq, void *dev_data)
+{
+	struct hdmi_device *hdev = dev_data;
+	u32 intc_flag;
+
+	(void)irq;
+	intc_flag = hdmi_read(hdev, HDMI_INTC_FLAG);
+	/* clearing flags for HPD plug/unplug */
+	if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
+		pr_info("unplugged\n");
+		hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
+			HDMI_INTC_FLAG_HPD_UNPLUG);
+	}
+	if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
+		pr_info("plugged\n");
+		hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
+			HDMI_INTC_FLAG_HPD_PLUG);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void hdmi_reg_init(struct hdmi_device *hdev)
+{
+	/* enable HPD interrupts */
+	hdmi_write_mask(hdev, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL |
+		HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
+	/* choose DVI mode */
+	hdmi_write_mask(hdev, HDMI_MODE_SEL,
+		HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
+	hdmi_write_mask(hdev, HDMI_CON_2, ~0,
+		HDMI_DVI_PERAMBLE_EN | HDMI_DVI_BAND_EN);
+	/* disable bluescreen */
+	hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
+	/* choose bluescreen (fecal) color */
+	hdmi_writeb(hdev, HDMI_BLUE_SCREEN_0, 0x12);
+	hdmi_writeb(hdev, HDMI_BLUE_SCREEN_1, 0x34);
+	hdmi_writeb(hdev, HDMI_BLUE_SCREEN_2, 0x56);
+}
+
+static void hdmi_timing_apply(struct hdmi_device *hdev,
+	const struct hdmi_timings *t)
+{
+	/* setting core registers */
+	hdmi_writebn(hdev, HDMI_H_BLANK_0, 2, t->hact.beg);
+	hdmi_writebn(hdev, HDMI_H_SYNC_GEN_0, 3,
+		(t->hsyn_pol << 20) | (t->hsyn.end << 10) | t->hsyn.beg);
+	hdmi_writeb(hdev, HDMI_VSYNC_POL, t->vsyn_pol);
+	hdmi_writebn(hdev, HDMI_V_BLANK_0, 3,
+		(t->vact[0].beg << 11) | t->vact[0].end);
+	hdmi_writebn(hdev, HDMI_V_SYNC_GEN_1_0, 3,
+		(t->vsyn[0].beg << 12) | t->vsyn[0].end);
+	if (t->interlaced) {
+		u32 vsyn_trans = t->hsyn.beg + t->vsyn_off;
+
+		hdmi_writeb(hdev, HDMI_INT_PRO_MODE, 1);
+		hdmi_writebn(hdev, HDMI_H_V_LINE_0, 3,
+			(t->hact.end << 12) | t->vact[1].end);
+		hdmi_writebn(hdev, HDMI_V_BLANK_F_0, 3,
+			(t->vact[1].end << 11) | t->vact[1].beg);
+		hdmi_writebn(hdev, HDMI_V_SYNC_GEN_2_0, 3,
+			(t->vsyn[1].beg << 12) | t->vsyn[1].end);
+		hdmi_writebn(hdev, HDMI_V_SYNC_GEN_3_0, 3,
+			(vsyn_trans << 12) | vsyn_trans);
+	} else {
+		hdmi_writeb(hdev, HDMI_INT_PRO_MODE, 0);
+		hdmi_writebn(hdev, HDMI_H_V_LINE_0, 3,
+			(t->hact.end << 12) | t->vact[0].end);
+	}
+
+	/* Timing generator registers */
+	hdmi_writebn(hdev, HDMI_TG_H_FSZ_L, 2, t->hact.end);
+	hdmi_writebn(hdev, HDMI_TG_HACT_ST_L, 2, t->hact.beg);
+	hdmi_writebn(hdev, HDMI_TG_HACT_SZ_L, 2, t->hact.end - t->hact.beg);
+	hdmi_writebn(hdev, HDMI_TG_VSYNC_L, 2, t->vsyn[0].beg);
+	hdmi_writebn(hdev, HDMI_TG_VACT_ST_L, 2, t->vact[0].beg);
+	hdmi_writebn(hdev, HDMI_TG_VACT_SZ_L, 2,
+		t->vact[0].end - t->vact[0].beg);
+	hdmi_writebn(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, 2, t->vsyn[0].beg);
+	hdmi_writebn(hdev, HDMI_TG_FIELD_TOP_HDMI_L, 2, t->vsyn[0].beg);
+	if (t->interlaced) {
+		hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, HDMI_TG_FIELD_EN);
+		hdmi_writebn(hdev, HDMI_TG_V_FSZ_L, 2, t->vact[1].end);
+		hdmi_writebn(hdev, HDMI_TG_VSYNC2_L, 2, t->vsyn[1].beg);
+		hdmi_writebn(hdev, HDMI_TG_FIELD_CHG_L, 2, t->vact[0].end);
+		hdmi_writebn(hdev, HDMI_TG_VACT_ST2_L, 2, t->vact[1].beg);
+		hdmi_writebn(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, 2, t->vsyn[1].beg);
+		hdmi_writebn(hdev, HDMI_TG_FIELD_BOT_HDMI_L, 2, t->vsyn[1].beg);
+	} else {
+		hdmi_write_mask(hdev, HDMI_TG_CMD, 0, HDMI_TG_FIELD_EN);
+		hdmi_writebn(hdev, HDMI_TG_V_FSZ_L, 2, t->vact[0].end);
+	}
+}
+
+static int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
+{
+	struct device *dev = hdmi_dev->dev;
+	const struct hdmi_timings *conf = hdmi_dev->cur_conf;
+	struct v4l2_dv_preset preset;
+	int ret;
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	/* skip if conf is already synchronized with HW */
+	if (!hdmi_dev->cur_conf_dirty)
+		return 0;
+
+	/* reset hdmiphy */
+	hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
+	mdelay(10);
+	hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT,  0, HDMI_PHY_SW_RSTOUT);
+	mdelay(10);
+
+	/* configure presets */
+	preset.preset = hdmi_dev->cur_preset;
+	ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_preset, &preset);
+	if (ret) {
+		dev_err(dev, "failed to set preset (%u)\n", preset.preset);
+		return ret;
+	}
+
+	/* resetting HDMI core */
+	hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT,  0, HDMI_CORE_SW_RSTOUT);
+	mdelay(10);
+	hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT, ~0, HDMI_CORE_SW_RSTOUT);
+	mdelay(10);
+
+	hdmi_reg_init(hdmi_dev);
+
+	/* setting core registers */
+	hdmi_timing_apply(hdmi_dev, conf);
+
+	hdmi_dev->cur_conf_dirty = 0;
+
+	return 0;
+}
+
+static void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix)
+{
+#define DUMPREG(reg_id) \
+	dev_dbg(hdev->dev, "%s:" #reg_id " = %08x\n", prefix, \
+		readl(hdev->regs + reg_id))
+
+	dev_dbg(hdev->dev, "%s: ---- CONTROL REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_INTC_FLAG);
+	DUMPREG(HDMI_INTC_CON);
+	DUMPREG(HDMI_HPD_STATUS);
+	DUMPREG(HDMI_PHY_RSTOUT);
+	DUMPREG(HDMI_PHY_VPLL);
+	DUMPREG(HDMI_PHY_CMU);
+	DUMPREG(HDMI_CORE_RSTOUT);
+
+	dev_dbg(hdev->dev, "%s: ---- CORE REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_CON_0);
+	DUMPREG(HDMI_CON_1);
+	DUMPREG(HDMI_CON_2);
+	DUMPREG(HDMI_SYS_STATUS);
+	DUMPREG(HDMI_PHY_STATUS);
+	DUMPREG(HDMI_STATUS_EN);
+	DUMPREG(HDMI_HPD);
+	DUMPREG(HDMI_MODE_SEL);
+	DUMPREG(HDMI_HPD_GEN);
+	DUMPREG(HDMI_DC_CONTROL);
+	DUMPREG(HDMI_VIDEO_PATTERN_GEN);
+
+	dev_dbg(hdev->dev, "%s: ---- CORE SYNC REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_H_BLANK_0);
+	DUMPREG(HDMI_H_BLANK_1);
+	DUMPREG(HDMI_V_BLANK_0);
+	DUMPREG(HDMI_V_BLANK_1);
+	DUMPREG(HDMI_V_BLANK_2);
+	DUMPREG(HDMI_H_V_LINE_0);
+	DUMPREG(HDMI_H_V_LINE_1);
+	DUMPREG(HDMI_H_V_LINE_2);
+	DUMPREG(HDMI_VSYNC_POL);
+	DUMPREG(HDMI_INT_PRO_MODE);
+	DUMPREG(HDMI_V_BLANK_F_0);
+	DUMPREG(HDMI_V_BLANK_F_1);
+	DUMPREG(HDMI_V_BLANK_F_2);
+	DUMPREG(HDMI_H_SYNC_GEN_0);
+	DUMPREG(HDMI_H_SYNC_GEN_1);
+	DUMPREG(HDMI_H_SYNC_GEN_2);
+	DUMPREG(HDMI_V_SYNC_GEN_1_0);
+	DUMPREG(HDMI_V_SYNC_GEN_1_1);
+	DUMPREG(HDMI_V_SYNC_GEN_1_2);
+	DUMPREG(HDMI_V_SYNC_GEN_2_0);
+	DUMPREG(HDMI_V_SYNC_GEN_2_1);
+	DUMPREG(HDMI_V_SYNC_GEN_2_2);
+	DUMPREG(HDMI_V_SYNC_GEN_3_0);
+	DUMPREG(HDMI_V_SYNC_GEN_3_1);
+	DUMPREG(HDMI_V_SYNC_GEN_3_2);
+
+	dev_dbg(hdev->dev, "%s: ---- TG REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_TG_CMD);
+	DUMPREG(HDMI_TG_H_FSZ_L);
+	DUMPREG(HDMI_TG_H_FSZ_H);
+	DUMPREG(HDMI_TG_HACT_ST_L);
+	DUMPREG(HDMI_TG_HACT_ST_H);
+	DUMPREG(HDMI_TG_HACT_SZ_L);
+	DUMPREG(HDMI_TG_HACT_SZ_H);
+	DUMPREG(HDMI_TG_V_FSZ_L);
+	DUMPREG(HDMI_TG_V_FSZ_H);
+	DUMPREG(HDMI_TG_VSYNC_L);
+	DUMPREG(HDMI_TG_VSYNC_H);
+	DUMPREG(HDMI_TG_VSYNC2_L);
+	DUMPREG(HDMI_TG_VSYNC2_H);
+	DUMPREG(HDMI_TG_VACT_ST_L);
+	DUMPREG(HDMI_TG_VACT_ST_H);
+	DUMPREG(HDMI_TG_VACT_SZ_L);
+	DUMPREG(HDMI_TG_VACT_SZ_H);
+	DUMPREG(HDMI_TG_FIELD_CHG_L);
+	DUMPREG(HDMI_TG_FIELD_CHG_H);
+	DUMPREG(HDMI_TG_VACT_ST2_L);
+	DUMPREG(HDMI_TG_VACT_ST2_H);
+	DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
+	DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
+	DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
+	DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
+	DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
+	DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
+	DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
+	DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
+#undef DUMPREG
+}
+
+static const struct hdmi_timings hdmi_timings_480p = {
+	.hact = { .beg = 138, .end = 858 },
+	.hsyn_pol = 1,
+	.hsyn = { .beg = 16, .end = 16 + 62 },
+	.interlaced = 0,
+	.vact[0] = { .beg = 42 + 3, .end = 522 + 3 },
+	.vsyn_pol = 1,
+	.vsyn[0] = { .beg = 6 + 3, .end = 12 + 3},
+};
+
+static const struct hdmi_timings hdmi_timings_576p50 = {
+	.hact = { .beg = 144, .end = 864 },
+	.hsyn_pol = 1,
+	.hsyn = { .beg = 12, .end = 12 + 64 },
+	.interlaced = 0,
+	.vact[0] = { .beg = 44 + 5, .end = 620 + 5 },
+	.vsyn_pol = 1,
+	.vsyn[0] = { .beg = 0 + 5, .end = 5 + 5},
+};
+
+static const struct hdmi_timings hdmi_timings_720p60 = {
+	.hact = { .beg = 370, .end = 1650 },
+	.hsyn_pol = 0,
+	.hsyn = { .beg = 110, .end = 110 + 40 },
+	.interlaced = 0,
+	.vact[0] = { .beg = 25 + 5, .end = 745 + 5 },
+	.vsyn_pol = 0,
+	.vsyn[0] = { .beg = 0 + 5, .end = 5 + 5},
+};
+
+static const struct hdmi_timings hdmi_timings_720p50 = {
+	.hact = { .beg = 700, .end = 1980 },
+	.hsyn_pol = 0,
+	.hsyn = { .beg = 440, .end = 440 + 40 },
+	.interlaced = 0,
+	.vact[0] = { .beg = 25 + 5, .end = 745 + 5 },
+	.vsyn_pol = 0,
+	.vsyn[0] = { .beg = 0 + 5, .end = 5 + 5},
+};
+
+static const struct hdmi_timings hdmi_timings_1080p24 = {
+	.hact = { .beg = 830, .end = 2750 },
+	.hsyn_pol = 0,
+	.hsyn = { .beg = 638, .end = 638 + 44 },
+	.interlaced = 0,
+	.vact[0] = { .beg = 41 + 4, .end = 1121 + 4 },
+	.vsyn_pol = 0,
+	.vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
+};
+
+static const struct hdmi_timings hdmi_timings_1080p60 = {
+	.hact = { .beg = 280, .end = 2200 },
+	.hsyn_pol = 0,
+	.hsyn = { .beg = 88, .end = 88 + 44 },
+	.interlaced = 0,
+	.vact[0] = { .beg = 41 + 4, .end = 1121 + 4 },
+	.vsyn_pol = 0,
+	.vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
+};
+
+static const struct hdmi_timings hdmi_timings_1080i60 = {
+	.hact = { .beg = 280, .end = 2200 },
+	.hsyn_pol = 0,
+	.hsyn = { .beg = 88, .end = 88 + 44 },
+	.interlaced = 1,
+	.vact[0] = { .beg = 20 + 2, .end = 560 + 2 },
+	.vact[1] = { .beg = 583 + 2, .end = 1123 + 2 },
+	.vsyn_pol = 0,
+	.vsyn_off = 1100,
+	.vsyn[0] = { .beg = 0 + 2, .end = 5 + 2},
+	.vsyn[1] = { .beg = 562 + 2, .end = 567 + 2},
+};
+
+static const struct hdmi_timings hdmi_timings_1080i50 = {
+	.hact = { .beg = 720, .end = 2640 },
+	.hsyn_pol = 0,
+	.hsyn = { .beg = 528, .end = 528 + 44 },
+	.interlaced = 1,
+	.vact[0] = { .beg = 20 + 2, .end = 560 + 2 },
+	.vact[1] = { .beg = 583 + 2, .end = 1123 + 2 },
+	.vsyn_pol = 0,
+	.vsyn_off = 1320,
+	.vsyn[0] = { .beg = 0 + 2, .end = 5 + 2},
+	.vsyn[1] = { .beg = 562 + 2, .end = 567 + 2},
+};
+
+static const struct hdmi_timings hdmi_timings_1080p50 = {
+	.hact = { .beg = 720, .end = 2640 },
+	.hsyn_pol = 0,
+	.hsyn = { .beg = 528, .end = 528 + 44 },
+	.interlaced = 0,
+	.vact[0] = { .beg = 41 + 4, .end = 1121 + 4 },
+	.vsyn_pol = 0,
+	.vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
+};
+
+static const struct {
+	u32 preset;
+	const struct hdmi_timings *timings;
+} hdmi_timings[] = {
+	{ V4L2_DV_480P59_94, &hdmi_timings_480p },
+	{ V4L2_DV_576P50, &hdmi_timings_576p50 },
+	{ V4L2_DV_720P50, &hdmi_timings_720p50 },
+	{ V4L2_DV_720P59_94, &hdmi_timings_720p60 },
+	{ V4L2_DV_720P60, &hdmi_timings_720p60 },
+	{ V4L2_DV_1080P24, &hdmi_timings_1080p24 },
+	{ V4L2_DV_1080P30, &hdmi_timings_1080p60 },
+	{ V4L2_DV_1080P50, &hdmi_timings_1080p50 },
+	{ V4L2_DV_1080I50, &hdmi_timings_1080i50 },
+	{ V4L2_DV_1080I60, &hdmi_timings_1080i60 },
+	{ V4L2_DV_1080P60, &hdmi_timings_1080p60 },
+};
+
+static const struct hdmi_timings *hdmi_preset2timings(u32 preset)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hdmi_timings); ++i)
+		if (hdmi_timings[i].preset == preset)
+			return  hdmi_timings[i].timings;
+	return NULL;
+}
+
+static int hdmi_streamon(struct hdmi_device *hdev)
+{
+	struct device *dev = hdev->dev;
+	struct hdmi_resources *res = &hdev->res;
+	int ret, tries;
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	ret = hdmi_conf_apply(hdev);
+	if (ret)
+		return ret;
+
+	ret = v4l2_subdev_call(hdev->phy_sd, video, s_stream, 1);
+	if (ret)
+		return ret;
+
+	/* waiting for HDMIPHY's PLL to get to steady state */
+	for (tries = 100; tries; --tries) {
+		u32 val = hdmi_read(hdev, HDMI_PHY_STATUS);
+		if (val & HDMI_PHY_STATUS_READY)
+			break;
+		mdelay(1);
+	}
+	/* steady state not achieved */
+	if (tries == 0) {
+		dev_err(dev, "hdmiphy's pll could not reach steady state.\n");
+		v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
+		hdmi_dumpregs(hdev, "hdmiphy - s_stream");
+		return -EIO;
+	}
+
+	/* starting MHL */
+	ret = v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 1);
+	if (hdev->mhl_sd && ret) {
+		v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
+		hdmi_dumpregs(hdev, "mhl - s_stream");
+		return -EIO;
+	}
+
+	/* hdmiphy clock is used for HDMI in streaming mode */
+	clk_disable(res->sclk_hdmi);
+	clk_set_parent(res->sclk_hdmi, res->sclk_hdmiphy);
+	clk_enable(res->sclk_hdmi);
+
+	/* enable HDMI and timing generator */
+	hdmi_write_mask(hdev, HDMI_CON_0, ~0, HDMI_EN);
+	hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, HDMI_TG_EN);
+	hdmi_dumpregs(hdev, "streamon");
+	return 0;
+}
+
+static int hdmi_streamoff(struct hdmi_device *hdev)
+{
+	struct device *dev = hdev->dev;
+	struct hdmi_resources *res = &hdev->res;
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_EN);
+	hdmi_write_mask(hdev, HDMI_TG_CMD, 0, HDMI_TG_EN);
+
+	/* pixel(vpll) clock is used for HDMI in config mode */
+	clk_disable(res->sclk_hdmi);
+	clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
+	clk_enable(res->sclk_hdmi);
+
+	v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 0);
+	v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
+
+	hdmi_dumpregs(hdev, "streamoff");
+	return 0;
+}
+
+static int hdmi_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+	struct device *dev = hdev->dev;
+
+	dev_dbg(dev, "%s(%d)\n", __func__, enable);
+	if (enable)
+		return hdmi_streamon(hdev);
+	return hdmi_streamoff(hdev);
+}
+
+static void hdmi_resource_poweron(struct hdmi_resources *res)
+{
+	/* turn HDMI power on */
+	regulator_bulk_enable(res->regul_count, res->regul_bulk);
+	/* power-on hdmi physical interface */
+	clk_enable(res->hdmiphy);
+	/* use VPP as parent clock; HDMIPHY is not working yet */
+	clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
+	/* turn clocks on */
+	clk_enable(res->sclk_hdmi);
+}
+
+static void hdmi_resource_poweroff(struct hdmi_resources *res)
+{
+	/* turn clocks off */
+	clk_disable(res->sclk_hdmi);
+	/* power-off hdmiphy */
+	clk_disable(res->hdmiphy);
+	/* turn HDMI power off */
+	regulator_bulk_disable(res->regul_count, res->regul_bulk);
+}
+
+static int hdmi_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+	int ret;
+
+	if (on)
+		ret = pm_runtime_get_sync(hdev->dev);
+	else
+		ret = pm_runtime_put_sync(hdev->dev);
+	/* only values < 0 indicate errors */
+	return IS_ERR_VALUE(ret) ? ret : 0;
+}
+
+static int hdmi_s_dv_preset(struct v4l2_subdev *sd,
+	struct v4l2_dv_preset *preset)
+{
+	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+	struct device *dev = hdev->dev;
+	const struct hdmi_timings *conf;
+
+	conf = hdmi_preset2timings(preset->preset);
+	if (conf == NULL) {
+		dev_err(dev, "preset (%u) not supported\n", preset->preset);
+		return -EINVAL;
+	}
+	hdev->cur_conf = conf;
+	hdev->cur_conf_dirty = 1;
+	hdev->cur_preset = preset->preset;
+	return 0;
+}
+
+static int hdmi_g_dv_preset(struct v4l2_subdev *sd,
+	struct v4l2_dv_preset *preset)
+{
+	memset(preset, 0, sizeof(*preset));
+	preset->preset = sd_to_hdmi_dev(sd)->cur_preset;
+	return 0;
+}
+
+static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
+	  struct v4l2_mbus_framefmt *fmt)
+{
+	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+	const struct hdmi_timings *t = hdev->cur_conf;
+
+	dev_dbg(hdev->dev, "%s\n", __func__);
+	if (!hdev->cur_conf)
+		return -EINVAL;
+	memset(fmt, 0, sizeof *fmt);
+	fmt->width = t->hact.end - t->hact.beg;
+	fmt->height = t->vact[0].end - t->vact[0].beg;
+	fmt->code = V4L2_MBUS_FMT_FIXED; /* means RGB888 */
+	fmt->colorspace = V4L2_COLORSPACE_SRGB;
+	if (t->interlaced) {
+		fmt->field = V4L2_FIELD_INTERLACED;
+		fmt->height *= 2;
+	} else {
+		fmt->field = V4L2_FIELD_NONE;
+	}
+	return 0;
+}
+
+static int hdmi_enum_dv_presets(struct v4l2_subdev *sd,
+	struct v4l2_dv_enum_preset *preset)
+{
+	if (preset->index >= ARRAY_SIZE(hdmi_timings))
+		return -EINVAL;
+	return v4l_fill_dv_preset_info(hdmi_timings[preset->index].preset,
+		preset);
+}
+
+static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
+	.s_power = hdmi_s_power,
+};
+
+static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = {
+	.s_dv_preset = hdmi_s_dv_preset,
+	.g_dv_preset = hdmi_g_dv_preset,
+	.enum_dv_presets = hdmi_enum_dv_presets,
+	.g_mbus_fmt = hdmi_g_mbus_fmt,
+	.s_stream = hdmi_s_stream,
+};
+
+static const struct v4l2_subdev_ops hdmi_sd_ops = {
+	.core = &hdmi_sd_core_ops,
+	.video = &hdmi_sd_video_ops,
+};
+
+static int hdmi_runtime_suspend(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+
+	dev_dbg(dev, "%s\n", __func__);
+	v4l2_subdev_call(hdev->mhl_sd, core, s_power, 0);
+	hdmi_resource_poweroff(&hdev->res);
+	/* flag that device context is lost */
+	hdev->cur_conf_dirty = 1;
+	return 0;
+}
+
+static int hdmi_runtime_resume(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+	int ret = 0;
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	hdmi_resource_poweron(&hdev->res);
+
+	/* starting MHL */
+	ret = v4l2_subdev_call(hdev->mhl_sd, core, s_power, 1);
+	if (hdev->mhl_sd && ret)
+		goto fail;
+
+	dev_dbg(dev, "poweron succeed\n");
+
+	return 0;
+
+fail:
+	hdmi_resource_poweroff(&hdev->res);
+	dev_err(dev, "poweron failed\n");
+
+	return ret;
+}
+
+static const struct dev_pm_ops hdmi_pm_ops = {
+	.runtime_suspend = hdmi_runtime_suspend,
+	.runtime_resume	 = hdmi_runtime_resume,
+};
+
+static void hdmi_resources_cleanup(struct hdmi_device *hdev)
+{
+	struct hdmi_resources *res = &hdev->res;
+
+	dev_dbg(hdev->dev, "HDMI resource cleanup\n");
+	/* put clocks, power */
+	if (res->regul_count)
+		regulator_bulk_free(res->regul_count, res->regul_bulk);
+	/* kfree is NULL-safe */
+	kfree(res->regul_bulk);
+	if (!IS_ERR_OR_NULL(res->hdmiphy))
+		clk_put(res->hdmiphy);
+	if (!IS_ERR_OR_NULL(res->sclk_hdmiphy))
+		clk_put(res->sclk_hdmiphy);
+	if (!IS_ERR_OR_NULL(res->sclk_pixel))
+		clk_put(res->sclk_pixel);
+	if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+		clk_put(res->sclk_hdmi);
+	if (!IS_ERR_OR_NULL(res->hdmi))
+		clk_put(res->hdmi);
+	memset(res, 0, sizeof *res);
+}
+
+static int hdmi_resources_init(struct hdmi_device *hdev)
+{
+	struct device *dev = hdev->dev;
+	struct hdmi_resources *res = &hdev->res;
+	static char *supply[] = {
+		"hdmi-en",
+		"vdd",
+		"vdd_osc",
+		"vdd_pll",
+	};
+	int i, ret;
+
+	dev_dbg(dev, "HDMI resource init\n");
+
+	memset(res, 0, sizeof *res);
+	/* get clocks, power */
+
+	res->hdmi = clk_get(dev, "hdmi");
+	if (IS_ERR_OR_NULL(res->hdmi)) {
+		dev_err(dev, "failed to get clock 'hdmi'\n");
+		goto fail;
+	}
+	res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
+	if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
+		dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
+		goto fail;
+	}
+	res->sclk_pixel = clk_get(dev, "sclk_pixel");
+	if (IS_ERR_OR_NULL(res->sclk_pixel)) {
+		dev_err(dev, "failed to get clock 'sclk_pixel'\n");
+		goto fail;
+	}
+	res->sclk_hdmiphy = clk_get(dev, "sclk_hdmiphy");
+	if (IS_ERR_OR_NULL(res->sclk_hdmiphy)) {
+		dev_err(dev, "failed to get clock 'sclk_hdmiphy'\n");
+		goto fail;
+	}
+	res->hdmiphy = clk_get(dev, "hdmiphy");
+	if (IS_ERR_OR_NULL(res->hdmiphy)) {
+		dev_err(dev, "failed to get clock 'hdmiphy'\n");
+		goto fail;
+	}
+	res->regul_bulk = kcalloc(ARRAY_SIZE(supply),
+				  sizeof(res->regul_bulk[0]), GFP_KERNEL);
+	if (!res->regul_bulk) {
+		dev_err(dev, "failed to get memory for regulators\n");
+		goto fail;
+	}
+	for (i = 0; i < ARRAY_SIZE(supply); ++i) {
+		res->regul_bulk[i].supply = supply[i];
+		res->regul_bulk[i].consumer = NULL;
+	}
+
+	ret = regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
+	if (ret) {
+		dev_err(dev, "failed to get regulators\n");
+		goto fail;
+	}
+	res->regul_count = ARRAY_SIZE(supply);
+
+	return 0;
+fail:
+	dev_err(dev, "HDMI resource init - failed\n");
+	hdmi_resources_cleanup(hdev);
+	return -ENODEV;
+}
+
+static int __devinit hdmi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct i2c_adapter *adapter;
+	struct v4l2_subdev *sd;
+	struct hdmi_device *hdmi_dev = NULL;
+	struct s5p_hdmi_platform_data *pdata = dev->platform_data;
+	int ret;
+
+	dev_dbg(dev, "probe start\n");
+
+	if (!pdata) {
+		dev_err(dev, "platform data is missing\n");
+		ret = -ENODEV;
+		goto fail;
+	}
+
+	hdmi_dev = devm_kzalloc(&pdev->dev, sizeof(*hdmi_dev), GFP_KERNEL);
+	if (!hdmi_dev) {
+		dev_err(dev, "out of memory\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	hdmi_dev->dev = dev;
+
+	ret = hdmi_resources_init(hdmi_dev);
+	if (ret)
+		goto fail;
+
+	/* mapping HDMI registers */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(dev, "get memory resource failed.\n");
+		ret = -ENXIO;
+		goto fail_init;
+	}
+
+	hdmi_dev->regs = devm_ioremap(&pdev->dev, res->start,
+				      resource_size(res));
+	if (hdmi_dev->regs == NULL) {
+		dev_err(dev, "register mapping failed.\n");
+		ret = -ENXIO;
+		goto fail_init;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res == NULL) {
+		dev_err(dev, "get interrupt resource failed.\n");
+		ret = -ENXIO;
+		goto fail_init;
+	}
+
+	ret = devm_request_irq(&pdev->dev, res->start, hdmi_irq_handler, 0,
+			       "hdmi", hdmi_dev);
+	if (ret) {
+		dev_err(dev, "request interrupt failed.\n");
+		goto fail_init;
+	}
+	hdmi_dev->irq = res->start;
+
+	/* setting v4l2 name to prevent WARN_ON in v4l2_device_register */
+	strlcpy(hdmi_dev->v4l2_dev.name, dev_name(dev),
+		sizeof(hdmi_dev->v4l2_dev.name));
+	/* passing NULL owner prevents driver from erasing drvdata */
+	ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev);
+	if (ret) {
+		dev_err(dev, "could not register v4l2 device.\n");
+		goto fail_init;
+	}
+
+	/* testing if hdmiphy info is present */
+	if (!pdata->hdmiphy_info) {
+		dev_err(dev, "hdmiphy info is missing in platform data\n");
+		ret = -ENXIO;
+		goto fail_vdev;
+	}
+
+	adapter = i2c_get_adapter(pdata->hdmiphy_bus);
+	if (adapter == NULL) {
+		dev_err(dev, "hdmiphy adapter request failed\n");
+		ret = -ENXIO;
+		goto fail_vdev;
+	}
+
+	hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev,
+		adapter, pdata->hdmiphy_info, NULL);
+	/* on failure or not adapter is no longer useful */
+	i2c_put_adapter(adapter);
+	if (hdmi_dev->phy_sd == NULL) {
+		dev_err(dev, "missing subdev for hdmiphy\n");
+		ret = -ENODEV;
+		goto fail_vdev;
+	}
+
+	/* initialization of MHL interface if present */
+	if (pdata->mhl_info) {
+		adapter = i2c_get_adapter(pdata->mhl_bus);
+		if (adapter == NULL) {
+			dev_err(dev, "MHL adapter request failed\n");
+			ret = -ENXIO;
+			goto fail_vdev;
+		}
+
+		hdmi_dev->mhl_sd = v4l2_i2c_new_subdev_board(
+			&hdmi_dev->v4l2_dev, adapter,
+			pdata->mhl_info, NULL);
+		/* on failure or not adapter is no longer useful */
+		i2c_put_adapter(adapter);
+		if (hdmi_dev->mhl_sd == NULL) {
+			dev_err(dev, "missing subdev for MHL\n");
+			ret = -ENODEV;
+			goto fail_vdev;
+		}
+	}
+
+	clk_enable(hdmi_dev->res.hdmi);
+
+	pm_runtime_enable(dev);
+
+	sd = &hdmi_dev->sd;
+	v4l2_subdev_init(sd, &hdmi_sd_ops);
+	sd->owner = THIS_MODULE;
+
+	strlcpy(sd->name, "s5p-hdmi", sizeof sd->name);
+	hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET;
+	/* FIXME: missing fail preset is not supported */
+	hdmi_dev->cur_conf = hdmi_preset2timings(hdmi_dev->cur_preset);
+	hdmi_dev->cur_conf_dirty = 1;
+
+	/* storing subdev for call that have only access to struct device */
+	dev_set_drvdata(dev, sd);
+
+	dev_info(dev, "probe successful\n");
+
+	return 0;
+
+fail_vdev:
+	v4l2_device_unregister(&hdmi_dev->v4l2_dev);
+
+fail_init:
+	hdmi_resources_cleanup(hdmi_dev);
+
+fail:
+	dev_err(dev, "probe failed\n");
+	return ret;
+}
+
+static int __devexit hdmi_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct hdmi_device *hdmi_dev = sd_to_hdmi_dev(sd);
+
+	pm_runtime_disable(dev);
+	clk_disable(hdmi_dev->res.hdmi);
+	v4l2_device_unregister(&hdmi_dev->v4l2_dev);
+	disable_irq(hdmi_dev->irq);
+	hdmi_resources_cleanup(hdmi_dev);
+	dev_info(dev, "remove successful\n");
+
+	return 0;
+}
+
+static struct platform_driver hdmi_driver __refdata = {
+	.probe = hdmi_probe,
+	.remove = __devexit_p(hdmi_remove),
+	.id_table = hdmi_driver_types,
+	.driver = {
+		.name = "s5p-hdmi",
+		.owner = THIS_MODULE,
+		.pm = &hdmi_pm_ops,
+	}
+};
+
+module_platform_driver(hdmi_driver);
diff --git a/drivers/media/platform/s5p-tv/hdmiphy_drv.c b/drivers/media/platform/s5p-tv/hdmiphy_drv.c
new file mode 100644
index 0000000..f67b386
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/hdmiphy_drv.c
@@ -0,0 +1,329 @@
+/*
+ * Samsung HDMI Physical interface driver
+ *
+ * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd
+ * Author: Tomasz Stanislawski <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+
+#include <media/v4l2-subdev.h>
+
+MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung HDMI Physical interface driver");
+MODULE_LICENSE("GPL");
+
+struct hdmiphy_conf {
+	unsigned long pixclk;
+	const u8 *data;
+};
+
+struct hdmiphy_ctx {
+	struct v4l2_subdev sd;
+	const struct hdmiphy_conf *conf_tab;
+};
+
+static const struct hdmiphy_conf hdmiphy_conf_s5pv210[] = {
+	{ .pixclk = 27000000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
+		0x6B, 0x10, 0x02, 0x52, 0xDF, 0xF2, 0x54, 0x87,
+		0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00, }
+	},
+	{ .pixclk = 27027000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
+		0x6B, 0x10, 0x02, 0x52, 0xDF, 0xF2, 0x54, 0x87,
+		0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x22, 0x40, 0xE2, 0x26, 0x00, 0x00, 0x00, 0x00, }
+	},
+	{ .pixclk = 74176000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xEF, 0x5B,
+		0x6D, 0x10, 0x01, 0x52, 0xEF, 0xF3, 0x54, 0xB9,
+		0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x22, 0x40, 0xA5, 0x26, 0x01, 0x00, 0x00, 0x00, }
+	},
+	{ .pixclk = 74250000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xF8, 0x40,
+		0x6A, 0x10, 0x01, 0x52, 0xFF, 0xF1, 0x54, 0xBA,
+		0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x22, 0x40, 0xA4, 0x26, 0x01, 0x00, 0x00, 0x00, }
+	},
+	{ /* end marker */ }
+};
+
+static const struct hdmiphy_conf hdmiphy_conf_exynos4210[] = {
+	{ .pixclk = 27000000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
+		0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
+		0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00, }
+	},
+	{ .pixclk = 27027000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
+		0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
+		0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x22, 0x40, 0xE2, 0x26, 0x00, 0x00, 0x00, 0x00, }
+	},
+	{ .pixclk = 74176000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xEF, 0x5B,
+		0x6D, 0x10, 0x01, 0x51, 0xEF, 0xF3, 0x54, 0xB9,
+		0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x22, 0x40, 0xA5, 0x26, 0x01, 0x00, 0x00, 0x00, }
+	},
+	{ .pixclk = 74250000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xF8, 0x40,
+		0x6A, 0x10, 0x01, 0x51, 0xFF, 0xF1, 0x54, 0xBA,
+		0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x22, 0x40, 0xA4, 0x26, 0x01, 0x00, 0x00, 0x00, }
+	},
+	{ .pixclk = 148352000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xEF, 0x5B,
+		0x6D, 0x18, 0x00, 0x51, 0xEF, 0xF3, 0x54, 0xB9,
+		0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x11, 0x40, 0xA5, 0x26, 0x02, 0x00, 0x00, 0x00, }
+	},
+	{ .pixclk = 148500000, .data = (u8 [32]) {
+		0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xF8, 0x40,
+		0x6A, 0x18, 0x00, 0x51, 0xFF, 0xF1, 0x54, 0xBA,
+		0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
+		0x11, 0x40, 0xA4, 0x26, 0x02, 0x00, 0x00, 0x00, }
+	},
+	{ /* end marker */ }
+};
+
+static const struct hdmiphy_conf hdmiphy_conf_exynos4212[] = {
+	{ .pixclk = 27000000, .data = (u8 [32]) {
+		0x01, 0x11, 0x2D, 0x75, 0x00, 0x01, 0x00, 0x08,
+		0x82, 0x00, 0x0E, 0xD9, 0x45, 0xA0, 0x34, 0xC0,
+		0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x71,
+		0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ .pixclk = 27027000, .data = (u8 [32]) {
+		0x01, 0x91, 0x2D, 0x72, 0x00, 0x64, 0x12, 0x08,
+		0x43, 0x20, 0x0E, 0xD9, 0x45, 0xA0, 0x34, 0xC0,
+		0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x71,
+		0x54, 0xE2, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ .pixclk = 74176000, .data = (u8 [32]) {
+		0x01, 0x91, 0x3E, 0x35, 0x00, 0x5B, 0xDE, 0x08,
+		0x82, 0x20, 0x73, 0xD9, 0x45, 0xA0, 0x34, 0xC0,
+		0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x52,
+		0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ .pixclk = 74250000, .data = (u8 [32]) {
+		0x01, 0x91, 0x3E, 0x35, 0x00, 0x40, 0xF0, 0x08,
+		0x82, 0x20, 0x73, 0xD9, 0x45, 0xA0, 0x34, 0xC0,
+		0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x52,
+		0x54, 0xA4, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ .pixclk = 148500000, .data = (u8 [32]) {
+		0x01, 0x91, 0x3E, 0x15, 0x00, 0x40, 0xF0, 0x08,
+		0x82, 0x20, 0x73, 0xD9, 0x45, 0xA0, 0x34, 0xC0,
+		0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0xA4,
+		0x54, 0x4A, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ /* end marker */ }
+};
+
+static const struct hdmiphy_conf hdmiphy_conf_exynos4412[] = {
+	{ .pixclk = 27000000, .data = (u8 [32]) {
+		0x01, 0x11, 0x2D, 0x75, 0x40, 0x01, 0x00, 0x08,
+		0x82, 0x00, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
+		0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86,
+		0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ .pixclk = 27027000, .data = (u8 [32]) {
+		0x01, 0x91, 0x2D, 0x72, 0x40, 0x64, 0x12, 0x08,
+		0x43, 0x20, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
+		0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86,
+		0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ .pixclk = 74176000, .data = (u8 [32]) {
+		0x01, 0x91, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0x08,
+		0x81, 0x20, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
+		0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86,
+		0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ .pixclk = 74250000, .data = (u8 [32]) {
+		0x01, 0x91, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
+		0x81, 0x20, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
+		0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86,
+		0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ .pixclk = 148500000, .data = (u8 [32]) {
+		0x01, 0x91, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
+		0x81, 0x20, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
+		0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86,
+		0x54, 0x4B, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00, }
+	},
+	{ /* end marker */ }
+};
+
+static inline struct hdmiphy_ctx *sd_to_ctx(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct hdmiphy_ctx, sd);
+}
+
+static unsigned long hdmiphy_preset_to_pixclk(u32 preset)
+{
+	static const unsigned long pixclk[] = {
+		[V4L2_DV_480P59_94] =  27000000,
+		[V4L2_DV_576P50]    =  27000000,
+		[V4L2_DV_720P59_94] =  74176000,
+		[V4L2_DV_720P50]    =  74250000,
+		[V4L2_DV_720P60]    =  74250000,
+		[V4L2_DV_1080P24]   =  74250000,
+		[V4L2_DV_1080P30]   =  74250000,
+		[V4L2_DV_1080I50]   =  74250000,
+		[V4L2_DV_1080I60]   =  74250000,
+		[V4L2_DV_1080P50]   = 148500000,
+		[V4L2_DV_1080P60]   = 148500000,
+	};
+	if (preset < ARRAY_SIZE(pixclk))
+		return pixclk[preset];
+	else
+		return 0;
+}
+
+static const u8 *hdmiphy_find_conf(u32 preset, const struct hdmiphy_conf *conf)
+{
+	unsigned long pixclk;
+
+	pixclk = hdmiphy_preset_to_pixclk(preset);
+	if (!pixclk)
+		return NULL;
+
+	for (; conf->pixclk; ++conf)
+		if (conf->pixclk == pixclk)
+			return conf->data;
+	return NULL;
+}
+
+static int hdmiphy_s_power(struct v4l2_subdev *sd, int on)
+{
+	/* to be implemented */
+	return 0;
+}
+
+static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd,
+	struct v4l2_dv_preset *preset)
+{
+	const u8 *data;
+	u8 buffer[32];
+	int ret;
+	struct hdmiphy_ctx *ctx = sd_to_ctx(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct device *dev = &client->dev;
+
+	dev_info(dev, "s_dv_preset(preset = %d)\n", preset->preset);
+	data = hdmiphy_find_conf(preset->preset, ctx->conf_tab);
+	if (!data) {
+		dev_err(dev, "format not supported\n");
+		return -EINVAL;
+	}
+
+	/* storing configuration to the device */
+	memcpy(buffer, data, 32);
+	ret = i2c_master_send(client, buffer, 32);
+	if (ret != 32) {
+		dev_err(dev, "failed to configure HDMIPHY via I2C\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int hdmiphy_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct device *dev = &client->dev;
+	u8 buffer[2];
+	int ret;
+
+	dev_info(dev, "s_stream(%d)\n", enable);
+	/* going to/from configuration from/to operation mode */
+	buffer[0] = 0x1f;
+	buffer[1] = enable ? 0x80 : 0x00;
+
+	ret = i2c_master_send(client, buffer, 2);
+	if (ret != 2) {
+		dev_err(dev, "stream (%d) failed\n", enable);
+		return -EIO;
+	}
+	return 0;
+}
+
+static const struct v4l2_subdev_core_ops hdmiphy_core_ops = {
+	.s_power =  hdmiphy_s_power,
+};
+
+static const struct v4l2_subdev_video_ops hdmiphy_video_ops = {
+	.s_dv_preset = hdmiphy_s_dv_preset,
+	.s_stream =  hdmiphy_s_stream,
+};
+
+static const struct v4l2_subdev_ops hdmiphy_ops = {
+	.core = &hdmiphy_core_ops,
+	.video = &hdmiphy_video_ops,
+};
+
+static int __devinit hdmiphy_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	struct hdmiphy_ctx *ctx;
+
+	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->conf_tab = (struct hdmiphy_conf *)id->driver_data;
+	v4l2_i2c_subdev_init(&ctx->sd, client, &hdmiphy_ops);
+
+	dev_info(&client->dev, "probe successful\n");
+	return 0;
+}
+
+static int __devexit hdmiphy_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct hdmiphy_ctx *ctx = sd_to_ctx(sd);
+
+	kfree(ctx);
+	dev_info(&client->dev, "remove successful\n");
+
+	return 0;
+}
+
+static const struct i2c_device_id hdmiphy_id[] = {
+	{ "hdmiphy", (unsigned long)hdmiphy_conf_exynos4210 },
+	{ "hdmiphy-s5pv210", (unsigned long)hdmiphy_conf_s5pv210 },
+	{ "hdmiphy-exynos4210", (unsigned long)hdmiphy_conf_exynos4210 },
+	{ "hdmiphy-exynos4212", (unsigned long)hdmiphy_conf_exynos4212 },
+	{ "hdmiphy-exynos4412", (unsigned long)hdmiphy_conf_exynos4412 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, hdmiphy_id);
+
+static struct i2c_driver hdmiphy_driver = {
+	.driver = {
+		.name	= "s5p-hdmiphy",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= hdmiphy_probe,
+	.remove		= __devexit_p(hdmiphy_remove),
+	.id_table = hdmiphy_id,
+};
+
+module_i2c_driver(hdmiphy_driver);
diff --git a/drivers/media/platform/s5p-tv/mixer.h b/drivers/media/platform/s5p-tv/mixer.h
new file mode 100644
index 0000000..ddb422e
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/mixer.h
@@ -0,0 +1,365 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#ifndef SAMSUNG_MIXER_H
+#define SAMSUNG_MIXER_H
+
+#ifdef CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG
+	#define DEBUG
+#endif
+
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-core.h>
+
+#include "regs-mixer.h"
+
+/** maximum number of output interfaces */
+#define MXR_MAX_OUTPUTS 2
+/** maximum number of input interfaces (layers) */
+#define MXR_MAX_LAYERS 3
+#define MXR_DRIVER_NAME "s5p-mixer"
+/** maximal number of planes for every layer */
+#define MXR_MAX_PLANES	2
+
+#define MXR_ENABLE 1
+#define MXR_DISABLE 0
+
+/** description of a macroblock for packed formats */
+struct mxr_block {
+	/** vertical number of pixels in macroblock */
+	unsigned int width;
+	/** horizontal number of pixels in macroblock */
+	unsigned int height;
+	/** size of block in bytes */
+	unsigned int size;
+};
+
+/** description of supported format */
+struct mxr_format {
+	/** format name/mnemonic */
+	const char *name;
+	/** fourcc identifier */
+	u32 fourcc;
+	/** colorspace identifier */
+	enum v4l2_colorspace colorspace;
+	/** number of planes in image data */
+	int num_planes;
+	/** description of block for each plane */
+	struct mxr_block plane[MXR_MAX_PLANES];
+	/** number of subframes in image data */
+	int num_subframes;
+	/** specifies to which subframe belong given plane */
+	int plane2subframe[MXR_MAX_PLANES];
+	/** internal code, driver dependant */
+	unsigned long cookie;
+};
+
+/** description of crop configuration for image */
+struct mxr_crop {
+	/** width of layer in pixels */
+	unsigned int full_width;
+	/** height of layer in pixels */
+	unsigned int full_height;
+	/** horizontal offset of first pixel to be displayed */
+	unsigned int x_offset;
+	/** vertical offset of first pixel to be displayed */
+	unsigned int y_offset;
+	/** width of displayed data in pixels */
+	unsigned int width;
+	/** height of displayed data in pixels */
+	unsigned int height;
+	/** indicate which fields are present in buffer */
+	unsigned int field;
+};
+
+/** stages of geometry operations */
+enum mxr_geometry_stage {
+	MXR_GEOMETRY_SINK,
+	MXR_GEOMETRY_COMPOSE,
+	MXR_GEOMETRY_CROP,
+	MXR_GEOMETRY_SOURCE,
+};
+
+/* flag indicating that offset should be 0 */
+#define MXR_NO_OFFSET	0x80000000
+
+/** description of transformation from source to destination image */
+struct mxr_geometry {
+	/** cropping for source image */
+	struct mxr_crop src;
+	/** cropping for destination image */
+	struct mxr_crop dst;
+	/** layer-dependant description of horizontal scaling */
+	unsigned int x_ratio;
+	/** layer-dependant description of vertical scaling */
+	unsigned int y_ratio;
+};
+
+/** instance of a buffer */
+struct mxr_buffer {
+	/** common v4l buffer stuff -- must be first */
+	struct vb2_buffer	vb;
+	/** node for layer's lists */
+	struct list_head	list;
+};
+
+
+/** internal states of layer */
+enum mxr_layer_state {
+	/** layers is not shown */
+	MXR_LAYER_IDLE = 0,
+	/** layer is shown */
+	MXR_LAYER_STREAMING,
+	/** state before STREAMOFF is finished */
+	MXR_LAYER_STREAMING_FINISH,
+};
+
+/** forward declarations */
+struct mxr_device;
+struct mxr_layer;
+
+/** callback for layers operation */
+struct mxr_layer_ops {
+	/* TODO: try to port it to subdev API */
+	/** handler for resource release function */
+	void (*release)(struct mxr_layer *);
+	/** setting buffer to HW */
+	void (*buffer_set)(struct mxr_layer *, struct mxr_buffer *);
+	/** setting format and geometry in HW */
+	void (*format_set)(struct mxr_layer *);
+	/** streaming stop/start */
+	void (*stream_set)(struct mxr_layer *, int);
+	/** adjusting geometry */
+	void (*fix_geometry)(struct mxr_layer *,
+		enum mxr_geometry_stage, unsigned long);
+};
+
+/** layer instance, a single window and content displayed on output */
+struct mxr_layer {
+	/** parent mixer device */
+	struct mxr_device *mdev;
+	/** layer index (unique identifier) */
+	int idx;
+	/** callbacks for layer methods */
+	struct mxr_layer_ops ops;
+	/** format array */
+	const struct mxr_format **fmt_array;
+	/** size of format array */
+	unsigned long fmt_array_size;
+
+	/** lock for protection of list and state fields */
+	spinlock_t enq_slock;
+	/** list for enqueued buffers */
+	struct list_head enq_list;
+	/** buffer currently owned by hardware in temporary registers */
+	struct mxr_buffer *update_buf;
+	/** buffer currently owned by hardware in shadow registers */
+	struct mxr_buffer *shadow_buf;
+	/** state of layer IDLE/STREAMING */
+	enum mxr_layer_state state;
+
+	/** mutex for protection of fields below */
+	struct mutex mutex;
+	/** handler for video node */
+	struct video_device vfd;
+	/** queue for output buffers */
+	struct vb2_queue vb_queue;
+	/** current image format */
+	const struct mxr_format *fmt;
+	/** current geometry of image */
+	struct mxr_geometry geo;
+};
+
+/** description of mixers output interface */
+struct mxr_output {
+	/** name of output */
+	char name[32];
+	/** output subdev */
+	struct v4l2_subdev *sd;
+	/** cookie used for configuration of registers */
+	int cookie;
+};
+
+/** specify source of output subdevs */
+struct mxr_output_conf {
+	/** name of output (connector) */
+	char *output_name;
+	/** name of module that generates output subdev */
+	char *module_name;
+	/** cookie need for mixer HW */
+	int cookie;
+};
+
+struct clk;
+struct regulator;
+
+/** auxiliary resources used my mixer */
+struct mxr_resources {
+	/** interrupt index */
+	int irq;
+	/** pointer to Mixer registers */
+	void __iomem *mxr_regs;
+	/** pointer to Video Processor registers */
+	void __iomem *vp_regs;
+	/** other resources, should used under mxr_device.mutex */
+	struct clk *mixer;
+	struct clk *vp;
+	struct clk *sclk_mixer;
+	struct clk *sclk_hdmi;
+	struct clk *sclk_dac;
+};
+
+/* event flags used  */
+enum mxr_devide_flags {
+	MXR_EVENT_VSYNC = 0,
+	MXR_EVENT_TOP = 1,
+};
+
+/** drivers instance */
+struct mxr_device {
+	/** master device */
+	struct device *dev;
+	/** state of each layer */
+	struct mxr_layer *layer[MXR_MAX_LAYERS];
+	/** state of each output */
+	struct mxr_output *output[MXR_MAX_OUTPUTS];
+	/** number of registered outputs */
+	int output_cnt;
+
+	/* video resources */
+
+	/** V4L2 device */
+	struct v4l2_device v4l2_dev;
+	/** context of allocator */
+	void *alloc_ctx;
+	/** event wait queue */
+	wait_queue_head_t event_queue;
+	/** state flags */
+	unsigned long event_flags;
+
+	/** spinlock for protection of registers */
+	spinlock_t reg_slock;
+
+	/** mutex for protection of fields below */
+	struct mutex mutex;
+	/** number of entities depndant on output configuration */
+	int n_output;
+	/** number of users that do streaming */
+	int n_streamer;
+	/** index of current output */
+	int current_output;
+	/** auxiliary resources used my mixer */
+	struct mxr_resources res;
+};
+
+/** transform device structure into mixer device */
+static inline struct mxr_device *to_mdev(struct device *dev)
+{
+	struct v4l2_device *vdev = dev_get_drvdata(dev);
+	return container_of(vdev, struct mxr_device, v4l2_dev);
+}
+
+/** get current output data, should be called under mdev's mutex */
+static inline struct mxr_output *to_output(struct mxr_device *mdev)
+{
+	return mdev->output[mdev->current_output];
+}
+
+/** get current output subdev, should be called under mdev's mutex */
+static inline struct v4l2_subdev *to_outsd(struct mxr_device *mdev)
+{
+	struct mxr_output *out = to_output(mdev);
+	return out ? out->sd : NULL;
+}
+
+/** forward declaration for mixer platform data */
+struct mxr_platform_data;
+
+/** acquiring common video resources */
+int __devinit mxr_acquire_video(struct mxr_device *mdev,
+	struct mxr_output_conf *output_cont, int output_count);
+
+/** releasing common video resources */
+void mxr_release_video(struct mxr_device *mdev);
+
+struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx);
+struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx);
+struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
+	int idx, char *name, struct mxr_layer_ops *ops);
+
+void mxr_base_layer_release(struct mxr_layer *layer);
+void mxr_layer_release(struct mxr_layer *layer);
+
+int mxr_base_layer_register(struct mxr_layer *layer);
+void mxr_base_layer_unregister(struct mxr_layer *layer);
+
+unsigned long mxr_get_plane_size(const struct mxr_block *blk,
+	unsigned int width, unsigned int height);
+
+/** adds new consumer for mixer's power */
+int __must_check mxr_power_get(struct mxr_device *mdev);
+/** removes consumer for mixer's power */
+void mxr_power_put(struct mxr_device *mdev);
+/** add new client for output configuration */
+void mxr_output_get(struct mxr_device *mdev);
+/** removes new client for output configuration */
+void mxr_output_put(struct mxr_device *mdev);
+/** add new client for streaming */
+void mxr_streamer_get(struct mxr_device *mdev);
+/** removes new client for streaming */
+void mxr_streamer_put(struct mxr_device *mdev);
+/** returns format of data delivared to current output */
+void mxr_get_mbus_fmt(struct mxr_device *mdev,
+	struct v4l2_mbus_framefmt *mbus_fmt);
+
+/* Debug */
+
+#define mxr_err(mdev, fmt, ...)  dev_err(mdev->dev, fmt, ##__VA_ARGS__)
+#define mxr_warn(mdev, fmt, ...) dev_warn(mdev->dev, fmt, ##__VA_ARGS__)
+#define mxr_info(mdev, fmt, ...) dev_info(mdev->dev, fmt, ##__VA_ARGS__)
+
+#ifdef CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG
+	#define mxr_dbg(mdev, fmt, ...)  dev_dbg(mdev->dev, fmt, ##__VA_ARGS__)
+#else
+	#define mxr_dbg(mdev, fmt, ...)  do { (void) mdev; } while (0)
+#endif
+
+/* accessing Mixer's and Video Processor's registers */
+
+void mxr_vsync_set_update(struct mxr_device *mdev, int en);
+void mxr_reg_reset(struct mxr_device *mdev);
+irqreturn_t mxr_irq_handler(int irq, void *dev_data);
+void mxr_reg_s_output(struct mxr_device *mdev, int cookie);
+void mxr_reg_streamon(struct mxr_device *mdev);
+void mxr_reg_streamoff(struct mxr_device *mdev);
+int mxr_reg_wait4vsync(struct mxr_device *mdev);
+void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
+	struct v4l2_mbus_framefmt *fmt);
+void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en);
+void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr);
+void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
+	const struct mxr_format *fmt, const struct mxr_geometry *geo);
+
+void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en);
+void mxr_reg_vp_buffer(struct mxr_device *mdev,
+	dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2]);
+void mxr_reg_vp_format(struct mxr_device *mdev,
+	const struct mxr_format *fmt, const struct mxr_geometry *geo);
+void mxr_reg_dump(struct mxr_device *mdev);
+
+#endif /* SAMSUNG_MIXER_H */
+
diff --git a/drivers/media/platform/s5p-tv/mixer_drv.c b/drivers/media/platform/s5p-tv/mixer_drv.c
new file mode 100644
index 0000000..a15ca05
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/mixer_drv.c
@@ -0,0 +1,487 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung MIXER");
+MODULE_LICENSE("GPL");
+
+/* --------- DRIVER PARAMETERS ---------- */
+
+static struct mxr_output_conf mxr_output_conf[] = {
+	{
+		.output_name = "S5P HDMI connector",
+		.module_name = "s5p-hdmi",
+		.cookie = 1,
+	},
+	{
+		.output_name = "S5P SDO connector",
+		.module_name = "s5p-sdo",
+		.cookie = 0,
+	},
+};
+
+void mxr_get_mbus_fmt(struct mxr_device *mdev,
+	struct v4l2_mbus_framefmt *mbus_fmt)
+{
+	struct v4l2_subdev *sd;
+	int ret;
+
+	mutex_lock(&mdev->mutex);
+	sd = to_outsd(mdev);
+	ret = v4l2_subdev_call(sd, video, g_mbus_fmt, mbus_fmt);
+	WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
+	mutex_unlock(&mdev->mutex);
+}
+
+void mxr_streamer_get(struct mxr_device *mdev)
+{
+	mutex_lock(&mdev->mutex);
+	++mdev->n_streamer;
+	mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
+	if (mdev->n_streamer == 1) {
+		struct v4l2_subdev *sd = to_outsd(mdev);
+		struct v4l2_mbus_framefmt mbus_fmt;
+		struct mxr_resources *res = &mdev->res;
+		int ret;
+
+		if (to_output(mdev)->cookie == 0)
+			clk_set_parent(res->sclk_mixer, res->sclk_dac);
+		else
+			clk_set_parent(res->sclk_mixer, res->sclk_hdmi);
+		mxr_reg_s_output(mdev, to_output(mdev)->cookie);
+
+		ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt);
+		WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
+		ret = v4l2_subdev_call(sd, video, s_stream, 1);
+		WARN(ret, "starting stream failed for output %s\n", sd->name);
+
+		mxr_reg_set_mbus_fmt(mdev, &mbus_fmt);
+		mxr_reg_streamon(mdev);
+		ret = mxr_reg_wait4vsync(mdev);
+		WARN(ret, "failed to get vsync (%d) from output\n", ret);
+	}
+	mutex_unlock(&mdev->mutex);
+	mxr_reg_dump(mdev);
+	/* FIXME: what to do when streaming fails? */
+}
+
+void mxr_streamer_put(struct mxr_device *mdev)
+{
+	mutex_lock(&mdev->mutex);
+	--mdev->n_streamer;
+	mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
+	if (mdev->n_streamer == 0) {
+		int ret;
+		struct v4l2_subdev *sd = to_outsd(mdev);
+
+		mxr_reg_streamoff(mdev);
+		/* vsync applies Mixer setup */
+		ret = mxr_reg_wait4vsync(mdev);
+		WARN(ret, "failed to get vsync (%d) from output\n", ret);
+		ret = v4l2_subdev_call(sd, video, s_stream, 0);
+		WARN(ret, "stopping stream failed for output %s\n", sd->name);
+	}
+	WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n",
+		mdev->n_streamer);
+	mutex_unlock(&mdev->mutex);
+	mxr_reg_dump(mdev);
+}
+
+void mxr_output_get(struct mxr_device *mdev)
+{
+	mutex_lock(&mdev->mutex);
+	++mdev->n_output;
+	mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
+	/* turn on auxiliary driver */
+	if (mdev->n_output == 1)
+		v4l2_subdev_call(to_outsd(mdev), core, s_power, 1);
+	mutex_unlock(&mdev->mutex);
+}
+
+void mxr_output_put(struct mxr_device *mdev)
+{
+	mutex_lock(&mdev->mutex);
+	--mdev->n_output;
+	mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
+	/* turn on auxiliary driver */
+	if (mdev->n_output == 0)
+		v4l2_subdev_call(to_outsd(mdev), core, s_power, 0);
+	WARN(mdev->n_output < 0, "negative number of output users (%d)\n",
+		mdev->n_output);
+	mutex_unlock(&mdev->mutex);
+}
+
+int mxr_power_get(struct mxr_device *mdev)
+{
+	int ret = pm_runtime_get_sync(mdev->dev);
+
+	/* returning 1 means that power is already enabled,
+	 * so zero success be returned */
+	if (IS_ERR_VALUE(ret))
+		return ret;
+	return 0;
+}
+
+void mxr_power_put(struct mxr_device *mdev)
+{
+	pm_runtime_put_sync(mdev->dev);
+}
+
+/* --------- RESOURCE MANAGEMENT -------------*/
+
+static int __devinit mxr_acquire_plat_resources(struct mxr_device *mdev,
+	struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
+	if (res == NULL) {
+		mxr_err(mdev, "get memory resource failed.\n");
+		ret = -ENXIO;
+		goto fail;
+	}
+
+	mdev->res.mxr_regs = ioremap(res->start, resource_size(res));
+	if (mdev->res.mxr_regs == NULL) {
+		mxr_err(mdev, "register mapping failed.\n");
+		ret = -ENXIO;
+		goto fail;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
+	if (res == NULL) {
+		mxr_err(mdev, "get memory resource failed.\n");
+		ret = -ENXIO;
+		goto fail_mxr_regs;
+	}
+
+	mdev->res.vp_regs = ioremap(res->start, resource_size(res));
+	if (mdev->res.vp_regs == NULL) {
+		mxr_err(mdev, "register mapping failed.\n");
+		ret = -ENXIO;
+		goto fail_mxr_regs;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
+	if (res == NULL) {
+		mxr_err(mdev, "get interrupt resource failed.\n");
+		ret = -ENXIO;
+		goto fail_vp_regs;
+	}
+
+	ret = request_irq(res->start, mxr_irq_handler, 0, "s5p-mixer", mdev);
+	if (ret) {
+		mxr_err(mdev, "request interrupt failed.\n");
+		goto fail_vp_regs;
+	}
+	mdev->res.irq = res->start;
+
+	return 0;
+
+fail_vp_regs:
+	iounmap(mdev->res.vp_regs);
+
+fail_mxr_regs:
+	iounmap(mdev->res.mxr_regs);
+
+fail:
+	return ret;
+}
+
+static void mxr_release_plat_resources(struct mxr_device *mdev)
+{
+	free_irq(mdev->res.irq, mdev);
+	iounmap(mdev->res.vp_regs);
+	iounmap(mdev->res.mxr_regs);
+}
+
+static void mxr_release_clocks(struct mxr_device *mdev)
+{
+	struct mxr_resources *res = &mdev->res;
+
+	if (!IS_ERR_OR_NULL(res->sclk_dac))
+		clk_put(res->sclk_dac);
+	if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+		clk_put(res->sclk_hdmi);
+	if (!IS_ERR_OR_NULL(res->sclk_mixer))
+		clk_put(res->sclk_mixer);
+	if (!IS_ERR_OR_NULL(res->vp))
+		clk_put(res->vp);
+	if (!IS_ERR_OR_NULL(res->mixer))
+		clk_put(res->mixer);
+}
+
+static int mxr_acquire_clocks(struct mxr_device *mdev)
+{
+	struct mxr_resources *res = &mdev->res;
+	struct device *dev = mdev->dev;
+
+	res->mixer = clk_get(dev, "mixer");
+	if (IS_ERR_OR_NULL(res->mixer)) {
+		mxr_err(mdev, "failed to get clock 'mixer'\n");
+		goto fail;
+	}
+	res->vp = clk_get(dev, "vp");
+	if (IS_ERR_OR_NULL(res->vp)) {
+		mxr_err(mdev, "failed to get clock 'vp'\n");
+		goto fail;
+	}
+	res->sclk_mixer = clk_get(dev, "sclk_mixer");
+	if (IS_ERR_OR_NULL(res->sclk_mixer)) {
+		mxr_err(mdev, "failed to get clock 'sclk_mixer'\n");
+		goto fail;
+	}
+	res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
+	if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
+		mxr_err(mdev, "failed to get clock 'sclk_hdmi'\n");
+		goto fail;
+	}
+	res->sclk_dac = clk_get(dev, "sclk_dac");
+	if (IS_ERR_OR_NULL(res->sclk_dac)) {
+		mxr_err(mdev, "failed to get clock 'sclk_dac'\n");
+		goto fail;
+	}
+
+	return 0;
+fail:
+	mxr_release_clocks(mdev);
+	return -ENODEV;
+}
+
+static int __devinit mxr_acquire_resources(struct mxr_device *mdev,
+	struct platform_device *pdev)
+{
+	int ret;
+	ret = mxr_acquire_plat_resources(mdev, pdev);
+
+	if (ret)
+		goto fail;
+
+	ret = mxr_acquire_clocks(mdev);
+	if (ret)
+		goto fail_plat;
+
+	mxr_info(mdev, "resources acquired\n");
+	return 0;
+
+fail_plat:
+	mxr_release_plat_resources(mdev);
+fail:
+	mxr_err(mdev, "resources acquire failed\n");
+	return ret;
+}
+
+static void mxr_release_resources(struct mxr_device *mdev)
+{
+	mxr_release_clocks(mdev);
+	mxr_release_plat_resources(mdev);
+	memset(&mdev->res, 0, sizeof mdev->res);
+}
+
+static void mxr_release_layers(struct mxr_device *mdev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mdev->layer); ++i)
+		if (mdev->layer[i])
+			mxr_layer_release(mdev->layer[i]);
+}
+
+static int __devinit mxr_acquire_layers(struct mxr_device *mdev,
+	struct mxr_platform_data *pdata)
+{
+	mdev->layer[0] = mxr_graph_layer_create(mdev, 0);
+	mdev->layer[1] = mxr_graph_layer_create(mdev, 1);
+	mdev->layer[2] = mxr_vp_layer_create(mdev, 0);
+
+	if (!mdev->layer[0] || !mdev->layer[1] || !mdev->layer[2]) {
+		mxr_err(mdev, "failed to acquire layers\n");
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	mxr_release_layers(mdev);
+	return -ENODEV;
+}
+
+/* ---------- POWER MANAGEMENT ----------- */
+
+static int mxr_runtime_resume(struct device *dev)
+{
+	struct mxr_device *mdev = to_mdev(dev);
+	struct mxr_resources *res = &mdev->res;
+
+	mxr_dbg(mdev, "resume - start\n");
+	mutex_lock(&mdev->mutex);
+	/* turn clocks on */
+	clk_enable(res->mixer);
+	clk_enable(res->vp);
+	clk_enable(res->sclk_mixer);
+	/* apply default configuration */
+	mxr_reg_reset(mdev);
+	mxr_dbg(mdev, "resume - finished\n");
+
+	mutex_unlock(&mdev->mutex);
+	return 0;
+}
+
+static int mxr_runtime_suspend(struct device *dev)
+{
+	struct mxr_device *mdev = to_mdev(dev);
+	struct mxr_resources *res = &mdev->res;
+	mxr_dbg(mdev, "suspend - start\n");
+	mutex_lock(&mdev->mutex);
+	/* turn clocks off */
+	clk_disable(res->sclk_mixer);
+	clk_disable(res->vp);
+	clk_disable(res->mixer);
+	mutex_unlock(&mdev->mutex);
+	mxr_dbg(mdev, "suspend - finished\n");
+	return 0;
+}
+
+static const struct dev_pm_ops mxr_pm_ops = {
+	.runtime_suspend = mxr_runtime_suspend,
+	.runtime_resume	 = mxr_runtime_resume,
+};
+
+/* --------- DRIVER INITIALIZATION ---------- */
+
+static int __devinit mxr_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mxr_platform_data *pdata = dev->platform_data;
+	struct mxr_device *mdev;
+	int ret;
+
+	/* mdev does not exist yet so no mxr_dbg is used */
+	dev_info(dev, "probe start\n");
+
+	mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
+	if (!mdev) {
+		mxr_err(mdev, "not enough memory.\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	/* setup pointer to master device */
+	mdev->dev = dev;
+
+	mutex_init(&mdev->mutex);
+	spin_lock_init(&mdev->reg_slock);
+	init_waitqueue_head(&mdev->event_queue);
+
+	/* acquire resources: regs, irqs, clocks, regulators */
+	ret = mxr_acquire_resources(mdev, pdev);
+	if (ret)
+		goto fail_mem;
+
+	/* configure resources for video output */
+	ret = mxr_acquire_video(mdev, mxr_output_conf,
+		ARRAY_SIZE(mxr_output_conf));
+	if (ret)
+		goto fail_resources;
+
+	/* configure layers */
+	ret = mxr_acquire_layers(mdev, pdata);
+	if (ret)
+		goto fail_video;
+
+	pm_runtime_enable(dev);
+
+	mxr_info(mdev, "probe successful\n");
+	return 0;
+
+fail_video:
+	mxr_release_video(mdev);
+
+fail_resources:
+	mxr_release_resources(mdev);
+
+fail_mem:
+	kfree(mdev);
+
+fail:
+	dev_info(dev, "probe failed\n");
+	return ret;
+}
+
+static int __devexit mxr_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mxr_device *mdev = to_mdev(dev);
+
+	pm_runtime_disable(dev);
+
+	mxr_release_layers(mdev);
+	mxr_release_video(mdev);
+	mxr_release_resources(mdev);
+
+	kfree(mdev);
+
+	dev_info(dev, "remove successful\n");
+	return 0;
+}
+
+static struct platform_driver mxr_driver __refdata = {
+	.probe = mxr_probe,
+	.remove = __devexit_p(mxr_remove),
+	.driver = {
+		.name = MXR_DRIVER_NAME,
+		.owner = THIS_MODULE,
+		.pm = &mxr_pm_ops,
+	}
+};
+
+static int __init mxr_init(void)
+{
+	int i, ret;
+	static const char banner[] __initconst =
+		"Samsung TV Mixer driver, "
+		"(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
+	pr_info("%s\n", banner);
+
+	/* Loading auxiliary modules */
+	for (i = 0; i < ARRAY_SIZE(mxr_output_conf); ++i)
+		request_module(mxr_output_conf[i].module_name);
+
+	ret = platform_driver_register(&mxr_driver);
+	if (ret != 0) {
+		pr_err("s5p-tv: registration of MIXER driver failed\n");
+		return -ENXIO;
+	}
+
+	return 0;
+}
+module_init(mxr_init);
+
+static void __exit mxr_exit(void)
+{
+	platform_driver_unregister(&mxr_driver);
+}
+module_exit(mxr_exit);
diff --git a/drivers/media/platform/s5p-tv/mixer_grp_layer.c b/drivers/media/platform/s5p-tv/mixer_grp_layer.c
new file mode 100644
index 0000000..b93a21f
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/mixer_grp_layer.c
@@ -0,0 +1,270 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#include <media/videobuf2-dma-contig.h>
+
+/* FORMAT DEFINITIONS */
+
+static const struct mxr_format mxr_fb_fmt_rgb565 = {
+	.name = "RGB565",
+	.fourcc = V4L2_PIX_FMT_RGB565,
+	.colorspace = V4L2_COLORSPACE_SRGB,
+	.num_planes = 1,
+	.plane = {
+		{ .width = 1, .height = 1, .size = 2 },
+	},
+	.num_subframes = 1,
+	.cookie = 4,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb1555 = {
+	.name = "ARGB1555",
+	.num_planes = 1,
+	.fourcc = V4L2_PIX_FMT_RGB555,
+	.colorspace = V4L2_COLORSPACE_SRGB,
+	.plane = {
+		{ .width = 1, .height = 1, .size = 2 },
+	},
+	.num_subframes = 1,
+	.cookie = 5,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb4444 = {
+	.name = "ARGB4444",
+	.num_planes = 1,
+	.fourcc = V4L2_PIX_FMT_RGB444,
+	.colorspace = V4L2_COLORSPACE_SRGB,
+	.plane = {
+		{ .width = 1, .height = 1, .size = 2 },
+	},
+	.num_subframes = 1,
+	.cookie = 6,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb8888 = {
+	.name = "ARGB8888",
+	.fourcc = V4L2_PIX_FMT_BGR32,
+	.colorspace = V4L2_COLORSPACE_SRGB,
+	.num_planes = 1,
+	.plane = {
+		{ .width = 1, .height = 1, .size = 4 },
+	},
+	.num_subframes = 1,
+	.cookie = 7,
+};
+
+static const struct mxr_format *mxr_graph_format[] = {
+	&mxr_fb_fmt_rgb565,
+	&mxr_fb_fmt_argb1555,
+	&mxr_fb_fmt_argb4444,
+	&mxr_fb_fmt_argb8888,
+};
+
+/* AUXILIARY CALLBACKS */
+
+static void mxr_graph_layer_release(struct mxr_layer *layer)
+{
+	mxr_base_layer_unregister(layer);
+	mxr_base_layer_release(layer);
+}
+
+static void mxr_graph_buffer_set(struct mxr_layer *layer,
+	struct mxr_buffer *buf)
+{
+	dma_addr_t addr = 0;
+
+	if (buf)
+		addr = vb2_dma_contig_plane_dma_addr(&buf->vb, 0);
+	mxr_reg_graph_buffer(layer->mdev, layer->idx, addr);
+}
+
+static void mxr_graph_stream_set(struct mxr_layer *layer, int en)
+{
+	mxr_reg_graph_layer_stream(layer->mdev, layer->idx, en);
+}
+
+static void mxr_graph_format_set(struct mxr_layer *layer)
+{
+	mxr_reg_graph_format(layer->mdev, layer->idx,
+		layer->fmt, &layer->geo);
+}
+
+static inline unsigned int closest(unsigned int x, unsigned int a,
+	unsigned int b, unsigned long flags)
+{
+	unsigned int mid = (a + b) / 2;
+
+	/* choosing closest value with constraints according to table:
+	 * -------------+-----+-----+-----+-------+
+	 * flags	|  0  |  LE |  GE | LE|GE |
+	 * -------------+-----+-----+-----+-------+
+	 * x <= a	|  a  |  a  |  a  |   a   |
+	 * a < x <= mid	|  a  |  a  |  b  |   a   |
+	 * mid < x < b	|  b  |  a  |  b  |   b   |
+	 * b <= x	|  b  |  b  |  b  |   b   |
+	 * -------------+-----+-----+-----+-------+
+	 */
+
+	/* remove all non-constraint flags */
+	flags &= V4L2_SEL_FLAG_LE | V4L2_SEL_FLAG_GE;
+
+	if (x <= a)
+		return  a;
+	if (x >= b)
+		return b;
+	if (flags == V4L2_SEL_FLAG_LE)
+		return a;
+	if (flags == V4L2_SEL_FLAG_GE)
+		return b;
+	if (x <= mid)
+		return a;
+	return b;
+}
+
+static inline unsigned int do_center(unsigned int center,
+	unsigned int size, unsigned int upper, unsigned int flags)
+{
+	unsigned int lower;
+
+	if (flags & MXR_NO_OFFSET)
+		return 0;
+
+	lower = center - min(center, size / 2);
+	return min(lower, upper - size);
+}
+
+static void mxr_graph_fix_geometry(struct mxr_layer *layer,
+	enum mxr_geometry_stage stage, unsigned long flags)
+{
+	struct mxr_geometry *geo = &layer->geo;
+	struct mxr_crop *src = &geo->src;
+	struct mxr_crop *dst = &geo->dst;
+	unsigned int x_center, y_center;
+
+	switch (stage) {
+
+	case MXR_GEOMETRY_SINK: /* nothing to be fixed here */
+		flags = 0;
+		/* fall through */
+
+	case MXR_GEOMETRY_COMPOSE:
+		/* remember center of the area */
+		x_center = dst->x_offset + dst->width / 2;
+		y_center = dst->y_offset + dst->height / 2;
+		/* round up/down to 2 multiple depending on flags */
+		if (flags & V4L2_SEL_FLAG_LE) {
+			dst->width = round_down(dst->width, 2);
+			dst->height = round_down(dst->height, 2);
+		} else {
+			dst->width = round_up(dst->width, 2);
+			dst->height = round_up(dst->height, 2);
+		}
+		/* assure that compose rect is inside display area */
+		dst->width = min(dst->width, dst->full_width);
+		dst->height = min(dst->height, dst->full_height);
+
+		/* ensure that compose is reachable using 2x scaling */
+		dst->width = min(dst->width, 2 * src->full_width);
+		dst->height = min(dst->height, 2 * src->full_height);
+
+		/* setup offsets */
+		dst->x_offset = do_center(x_center, dst->width,
+			dst->full_width, flags);
+		dst->y_offset = do_center(y_center, dst->height,
+			dst->full_height, flags);
+		flags = 0;
+		/* fall through */
+
+	case MXR_GEOMETRY_CROP:
+		/* remember center of the area */
+		x_center = src->x_offset + src->width / 2;
+		y_center = src->y_offset + src->height / 2;
+		/* ensure that cropping area lies inside the buffer */
+		if (src->full_width < dst->width)
+			src->width = dst->width / 2;
+		else
+			src->width = closest(src->width, dst->width / 2,
+				dst->width, flags);
+
+		if (src->width == dst->width)
+			geo->x_ratio = 0;
+		else
+			geo->x_ratio = 1;
+
+		if (src->full_height < dst->height)
+			src->height = dst->height / 2;
+		else
+			src->height = closest(src->height, dst->height / 2,
+				dst->height, flags);
+
+		if (src->height == dst->height)
+			geo->y_ratio = 0;
+		else
+			geo->y_ratio = 1;
+
+		/* setup offsets */
+		src->x_offset = do_center(x_center, src->width,
+			src->full_width, flags);
+		src->y_offset = do_center(y_center, src->height,
+			src->full_height, flags);
+		flags = 0;
+		/* fall through */
+	case MXR_GEOMETRY_SOURCE:
+		src->full_width = clamp_val(src->full_width,
+			src->width + src->x_offset, 32767);
+		src->full_height = clamp_val(src->full_height,
+			src->height + src->y_offset, 2047);
+	};
+}
+
+/* PUBLIC API */
+
+struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx)
+{
+	struct mxr_layer *layer;
+	int ret;
+	struct mxr_layer_ops ops = {
+		.release = mxr_graph_layer_release,
+		.buffer_set = mxr_graph_buffer_set,
+		.stream_set = mxr_graph_stream_set,
+		.format_set = mxr_graph_format_set,
+		.fix_geometry = mxr_graph_fix_geometry,
+	};
+	char name[32];
+
+	sprintf(name, "graph%d", idx);
+
+	layer = mxr_base_layer_create(mdev, idx, name, &ops);
+	if (layer == NULL) {
+		mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
+		goto fail;
+	}
+
+	layer->fmt_array = mxr_graph_format;
+	layer->fmt_array_size = ARRAY_SIZE(mxr_graph_format);
+
+	ret = mxr_base_layer_register(layer);
+	if (ret)
+		goto fail_layer;
+
+	return layer;
+
+fail_layer:
+	mxr_base_layer_release(layer);
+
+fail:
+	return NULL;
+}
+
diff --git a/drivers/media/platform/s5p-tv/mixer_reg.c b/drivers/media/platform/s5p-tv/mixer_reg.c
new file mode 100644
index 0000000..3b1670a
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/mixer_reg.c
@@ -0,0 +1,553 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+#include "regs-mixer.h"
+#include "regs-vp.h"
+
+#include <linux/delay.h>
+
+/* Register access subroutines */
+
+static inline u32 vp_read(struct mxr_device *mdev, u32 reg_id)
+{
+	return readl(mdev->res.vp_regs + reg_id);
+}
+
+static inline void vp_write(struct mxr_device *mdev, u32 reg_id, u32 val)
+{
+	writel(val, mdev->res.vp_regs + reg_id);
+}
+
+static inline void vp_write_mask(struct mxr_device *mdev, u32 reg_id,
+	u32 val, u32 mask)
+{
+	u32 old = vp_read(mdev, reg_id);
+
+	val = (val & mask) | (old & ~mask);
+	writel(val, mdev->res.vp_regs + reg_id);
+}
+
+static inline u32 mxr_read(struct mxr_device *mdev, u32 reg_id)
+{
+	return readl(mdev->res.mxr_regs + reg_id);
+}
+
+static inline void mxr_write(struct mxr_device *mdev, u32 reg_id, u32 val)
+{
+	writel(val, mdev->res.mxr_regs + reg_id);
+}
+
+static inline void mxr_write_mask(struct mxr_device *mdev, u32 reg_id,
+	u32 val, u32 mask)
+{
+	u32 old = mxr_read(mdev, reg_id);
+
+	val = (val & mask) | (old & ~mask);
+	writel(val, mdev->res.mxr_regs + reg_id);
+}
+
+void mxr_vsync_set_update(struct mxr_device *mdev, int en)
+{
+	/* block update on vsync */
+	mxr_write_mask(mdev, MXR_STATUS, en ? MXR_STATUS_SYNC_ENABLE : 0,
+		MXR_STATUS_SYNC_ENABLE);
+	vp_write(mdev, VP_SHADOW_UPDATE, en ? VP_SHADOW_UPDATE_ENABLE : 0);
+}
+
+static void __mxr_reg_vp_reset(struct mxr_device *mdev)
+{
+	int tries = 100;
+
+	vp_write(mdev, VP_SRESET, VP_SRESET_PROCESSING);
+	for (tries = 100; tries; --tries) {
+		/* waiting until VP_SRESET_PROCESSING is 0 */
+		if (~vp_read(mdev, VP_SRESET) & VP_SRESET_PROCESSING)
+			break;
+		mdelay(10);
+	}
+	WARN(tries == 0, "failed to reset Video Processor\n");
+}
+
+static void mxr_reg_vp_default_filter(struct mxr_device *mdev);
+
+void mxr_reg_reset(struct mxr_device *mdev)
+{
+	unsigned long flags;
+	u32 val; /* value stored to register */
+
+	spin_lock_irqsave(&mdev->reg_slock, flags);
+	mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+	/* set output in RGB888 mode */
+	mxr_write(mdev, MXR_CFG, MXR_CFG_OUT_RGB888);
+
+	/* 16 beat burst in DMA */
+	mxr_write_mask(mdev, MXR_STATUS, MXR_STATUS_16_BURST,
+		MXR_STATUS_BURST_MASK);
+
+	/* setting default layer priority: layer1 > video > layer0
+	 * because typical usage scenario would be
+	 * layer0 - framebuffer
+	 * video - video overlay
+	 * layer1 - OSD
+	 */
+	val  = MXR_LAYER_CFG_GRP0_VAL(1);
+	val |= MXR_LAYER_CFG_VP_VAL(2);
+	val |= MXR_LAYER_CFG_GRP1_VAL(3);
+	mxr_write(mdev, MXR_LAYER_CFG, val);
+
+	/* use dark gray background color */
+	mxr_write(mdev, MXR_BG_COLOR0, 0x808080);
+	mxr_write(mdev, MXR_BG_COLOR1, 0x808080);
+	mxr_write(mdev, MXR_BG_COLOR2, 0x808080);
+
+	/* setting graphical layers */
+
+	val  = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
+	val |= MXR_GRP_CFG_BLEND_PRE_MUL; /* premul mode */
+	val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
+
+	/* the same configuration for both layers */
+	mxr_write(mdev, MXR_GRAPHIC_CFG(0), val);
+	mxr_write(mdev, MXR_GRAPHIC_CFG(1), val);
+
+	/* configuration of Video Processor Registers */
+	__mxr_reg_vp_reset(mdev);
+	mxr_reg_vp_default_filter(mdev);
+
+	/* enable all interrupts */
+	mxr_write_mask(mdev, MXR_INT_EN, ~0, MXR_INT_EN_ALL);
+
+	mxr_vsync_set_update(mdev, MXR_ENABLE);
+	spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
+	const struct mxr_format *fmt, const struct mxr_geometry *geo)
+{
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdev->reg_slock, flags);
+	mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+	/* setup format */
+	mxr_write_mask(mdev, MXR_GRAPHIC_CFG(idx),
+		MXR_GRP_CFG_FORMAT_VAL(fmt->cookie), MXR_GRP_CFG_FORMAT_MASK);
+
+	/* setup geometry */
+	mxr_write(mdev, MXR_GRAPHIC_SPAN(idx), geo->src.full_width);
+	val  = MXR_GRP_WH_WIDTH(geo->src.width);
+	val |= MXR_GRP_WH_HEIGHT(geo->src.height);
+	val |= MXR_GRP_WH_H_SCALE(geo->x_ratio);
+	val |= MXR_GRP_WH_V_SCALE(geo->y_ratio);
+	mxr_write(mdev, MXR_GRAPHIC_WH(idx), val);
+
+	/* setup offsets in source image */
+	val  = MXR_GRP_SXY_SX(geo->src.x_offset);
+	val |= MXR_GRP_SXY_SY(geo->src.y_offset);
+	mxr_write(mdev, MXR_GRAPHIC_SXY(idx), val);
+
+	/* setup offsets in display image */
+	val  = MXR_GRP_DXY_DX(geo->dst.x_offset);
+	val |= MXR_GRP_DXY_DY(geo->dst.y_offset);
+	mxr_write(mdev, MXR_GRAPHIC_DXY(idx), val);
+
+	mxr_vsync_set_update(mdev, MXR_ENABLE);
+	spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_vp_format(struct mxr_device *mdev,
+	const struct mxr_format *fmt, const struct mxr_geometry *geo)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdev->reg_slock, flags);
+	mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+	vp_write_mask(mdev, VP_MODE, fmt->cookie, VP_MODE_FMT_MASK);
+
+	/* setting size of input image */
+	vp_write(mdev, VP_IMG_SIZE_Y, VP_IMG_HSIZE(geo->src.full_width) |
+		VP_IMG_VSIZE(geo->src.full_height));
+	/* chroma height has to reduced by 2 to avoid chroma distorions */
+	vp_write(mdev, VP_IMG_SIZE_C, VP_IMG_HSIZE(geo->src.full_width) |
+		VP_IMG_VSIZE(geo->src.full_height / 2));
+
+	vp_write(mdev, VP_SRC_WIDTH, geo->src.width);
+	vp_write(mdev, VP_SRC_HEIGHT, geo->src.height);
+	vp_write(mdev, VP_SRC_H_POSITION,
+		VP_SRC_H_POSITION_VAL(geo->src.x_offset));
+	vp_write(mdev, VP_SRC_V_POSITION, geo->src.y_offset);
+
+	vp_write(mdev, VP_DST_WIDTH, geo->dst.width);
+	vp_write(mdev, VP_DST_H_POSITION, geo->dst.x_offset);
+	if (geo->dst.field == V4L2_FIELD_INTERLACED) {
+		vp_write(mdev, VP_DST_HEIGHT, geo->dst.height / 2);
+		vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset / 2);
+	} else {
+		vp_write(mdev, VP_DST_HEIGHT, geo->dst.height);
+		vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset);
+	}
+
+	vp_write(mdev, VP_H_RATIO, geo->x_ratio);
+	vp_write(mdev, VP_V_RATIO, geo->y_ratio);
+
+	vp_write(mdev, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
+
+	mxr_vsync_set_update(mdev, MXR_ENABLE);
+	spin_unlock_irqrestore(&mdev->reg_slock, flags);
+
+}
+
+void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr)
+{
+	u32 val = addr ? ~0 : 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdev->reg_slock, flags);
+	mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+	if (idx == 0)
+		mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
+	else
+		mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
+	mxr_write(mdev, MXR_GRAPHIC_BASE(idx), addr);
+
+	mxr_vsync_set_update(mdev, MXR_ENABLE);
+	spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_vp_buffer(struct mxr_device *mdev,
+	dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2])
+{
+	u32 val = luma_addr[0] ? ~0 : 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdev->reg_slock, flags);
+	mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+	mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_VP_ENABLE);
+	vp_write_mask(mdev, VP_ENABLE, val, VP_ENABLE_ON);
+	/* TODO: fix tiled mode */
+	vp_write(mdev, VP_TOP_Y_PTR, luma_addr[0]);
+	vp_write(mdev, VP_TOP_C_PTR, chroma_addr[0]);
+	vp_write(mdev, VP_BOT_Y_PTR, luma_addr[1]);
+	vp_write(mdev, VP_BOT_C_PTR, chroma_addr[1]);
+
+	mxr_vsync_set_update(mdev, MXR_ENABLE);
+	spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+static void mxr_irq_layer_handle(struct mxr_layer *layer)
+{
+	struct list_head *head = &layer->enq_list;
+	struct mxr_buffer *done;
+
+	/* skip non-existing layer */
+	if (layer == NULL)
+		return;
+
+	spin_lock(&layer->enq_slock);
+	if (layer->state == MXR_LAYER_IDLE)
+		goto done;
+
+	done = layer->shadow_buf;
+	layer->shadow_buf = layer->update_buf;
+
+	if (list_empty(head)) {
+		if (layer->state != MXR_LAYER_STREAMING)
+			layer->update_buf = NULL;
+	} else {
+		struct mxr_buffer *next;
+		next = list_first_entry(head, struct mxr_buffer, list);
+		list_del(&next->list);
+		layer->update_buf = next;
+	}
+
+	layer->ops.buffer_set(layer, layer->update_buf);
+
+	if (done && done != layer->shadow_buf)
+		vb2_buffer_done(&done->vb, VB2_BUF_STATE_DONE);
+
+done:
+	spin_unlock(&layer->enq_slock);
+}
+
+irqreturn_t mxr_irq_handler(int irq, void *dev_data)
+{
+	struct mxr_device *mdev = dev_data;
+	u32 i, val;
+
+	spin_lock(&mdev->reg_slock);
+	val = mxr_read(mdev, MXR_INT_STATUS);
+
+	/* wake up process waiting for VSYNC */
+	if (val & MXR_INT_STATUS_VSYNC) {
+		set_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
+		/* toggle TOP field event if working in interlaced mode */
+		if (~mxr_read(mdev, MXR_CFG) & MXR_CFG_SCAN_PROGRASSIVE)
+			change_bit(MXR_EVENT_TOP, &mdev->event_flags);
+		wake_up(&mdev->event_queue);
+		/* vsync interrupt use different bit for read and clear */
+		val &= ~MXR_INT_STATUS_VSYNC;
+		val |= MXR_INT_CLEAR_VSYNC;
+	}
+
+	/* clear interrupts */
+	mxr_write(mdev, MXR_INT_STATUS, val);
+
+	spin_unlock(&mdev->reg_slock);
+	/* leave on non-vsync event */
+	if (~val & MXR_INT_CLEAR_VSYNC)
+		return IRQ_HANDLED;
+	/* skip layer update on bottom field */
+	if (!test_bit(MXR_EVENT_TOP, &mdev->event_flags))
+		return IRQ_HANDLED;
+	for (i = 0; i < MXR_MAX_LAYERS; ++i)
+		mxr_irq_layer_handle(mdev->layer[i]);
+	return IRQ_HANDLED;
+}
+
+void mxr_reg_s_output(struct mxr_device *mdev, int cookie)
+{
+	u32 val;
+
+	val = cookie == 0 ? MXR_CFG_DST_SDO : MXR_CFG_DST_HDMI;
+	mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_DST_MASK);
+}
+
+void mxr_reg_streamon(struct mxr_device *mdev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdev->reg_slock, flags);
+	/* single write -> no need to block vsync update */
+
+	/* start MIXER */
+	mxr_write_mask(mdev, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
+	set_bit(MXR_EVENT_TOP, &mdev->event_flags);
+
+	spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_streamoff(struct mxr_device *mdev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdev->reg_slock, flags);
+	/* single write -> no need to block vsync update */
+
+	/* stop MIXER */
+	mxr_write_mask(mdev, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
+
+	spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+int mxr_reg_wait4vsync(struct mxr_device *mdev)
+{
+	int ret;
+
+	clear_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
+	/* TODO: consider adding interruptible */
+	ret = wait_event_timeout(mdev->event_queue,
+		test_bit(MXR_EVENT_VSYNC, &mdev->event_flags),
+		msecs_to_jiffies(1000));
+	if (ret > 0)
+		return 0;
+	if (ret < 0)
+		return ret;
+	mxr_warn(mdev, "no vsync detected - timeout\n");
+	return -ETIME;
+}
+
+void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
+	struct v4l2_mbus_framefmt *fmt)
+{
+	u32 val = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdev->reg_slock, flags);
+	mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+	/* selecting colorspace accepted by output */
+	if (fmt->colorspace == V4L2_COLORSPACE_JPEG)
+		val |= MXR_CFG_OUT_YUV444;
+	else
+		val |= MXR_CFG_OUT_RGB888;
+
+	/* choosing between interlace and progressive mode */
+	if (fmt->field == V4L2_FIELD_INTERLACED)
+		val |= MXR_CFG_SCAN_INTERLACE;
+	else
+		val |= MXR_CFG_SCAN_PROGRASSIVE;
+
+	/* choosing between porper HD and SD mode */
+	if (fmt->height == 480)
+		val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
+	else if (fmt->height == 576)
+		val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
+	else if (fmt->height == 720)
+		val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
+	else if (fmt->height == 1080)
+		val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
+	else
+		WARN(1, "unrecognized mbus height %u!\n", fmt->height);
+
+	mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_SCAN_MASK |
+		MXR_CFG_OUT_MASK);
+
+	val = (fmt->field == V4L2_FIELD_INTERLACED) ? ~0 : 0;
+	vp_write_mask(mdev, VP_MODE, val,
+		VP_MODE_LINE_SKIP | VP_MODE_FIELD_ID_AUTO_TOGGLING);
+
+	mxr_vsync_set_update(mdev, MXR_ENABLE);
+	spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en)
+{
+	/* no extra actions need to be done */
+}
+
+void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en)
+{
+	/* no extra actions need to be done */
+}
+
+static const u8 filter_y_horiz_tap8[] = {
+	0,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
+	-1,	-1,	-1,	-1,	-1,	0,	0,	0,
+	0,	2,	4,	5,	6,	6,	6,	6,
+	6,	5,	5,	4,	3,	2,	1,	1,
+	0,	-6,	-12,	-16,	-18,	-20,	-21,	-20,
+	-20,	-18,	-16,	-13,	-10,	-8,	-5,	-2,
+	127,	126,	125,	121,	114,	107,	99,	89,
+	79,	68,	57,	46,	35,	25,	16,	8,
+};
+
+static const u8 filter_y_vert_tap4[] = {
+	0,	-3,	-6,	-8,	-8,	-8,	-8,	-7,
+	-6,	-5,	-4,	-3,	-2,	-1,	-1,	0,
+	127,	126,	124,	118,	111,	102,	92,	81,
+	70,	59,	48,	37,	27,	19,	11,	5,
+	0,	5,	11,	19,	27,	37,	48,	59,
+	70,	81,	92,	102,	111,	118,	124,	126,
+	0,	0,	-1,	-1,	-2,	-3,	-4,	-5,
+	-6,	-7,	-8,	-8,	-8,	-8,	-6,	-3,
+};
+
+static const u8 filter_cr_horiz_tap4[] = {
+	0,	-3,	-6,	-8,	-8,	-8,	-8,	-7,
+	-6,	-5,	-4,	-3,	-2,	-1,	-1,	0,
+	127,	126,	124,	118,	111,	102,	92,	81,
+	70,	59,	48,	37,	27,	19,	11,	5,
+};
+
+static inline void mxr_reg_vp_filter_set(struct mxr_device *mdev,
+	int reg_id, const u8 *data, unsigned int size)
+{
+	/* assure 4-byte align */
+	BUG_ON(size & 3);
+	for (; size; size -= 4, reg_id += 4, data += 4) {
+		u32 val = (data[0] << 24) |  (data[1] << 16) |
+			(data[2] << 8) | data[3];
+		vp_write(mdev, reg_id, val);
+	}
+}
+
+static void mxr_reg_vp_default_filter(struct mxr_device *mdev)
+{
+	mxr_reg_vp_filter_set(mdev, VP_POLY8_Y0_LL,
+		filter_y_horiz_tap8, sizeof filter_y_horiz_tap8);
+	mxr_reg_vp_filter_set(mdev, VP_POLY4_Y0_LL,
+		filter_y_vert_tap4, sizeof filter_y_vert_tap4);
+	mxr_reg_vp_filter_set(mdev, VP_POLY4_C0_LL,
+		filter_cr_horiz_tap4, sizeof filter_cr_horiz_tap4);
+}
+
+static void mxr_reg_mxr_dump(struct mxr_device *mdev)
+{
+#define DUMPREG(reg_id) \
+do { \
+	mxr_dbg(mdev, #reg_id " = %08x\n", \
+		(u32)readl(mdev->res.mxr_regs + reg_id)); \
+} while (0)
+
+	DUMPREG(MXR_STATUS);
+	DUMPREG(MXR_CFG);
+	DUMPREG(MXR_INT_EN);
+	DUMPREG(MXR_INT_STATUS);
+
+	DUMPREG(MXR_LAYER_CFG);
+	DUMPREG(MXR_VIDEO_CFG);
+
+	DUMPREG(MXR_GRAPHIC0_CFG);
+	DUMPREG(MXR_GRAPHIC0_BASE);
+	DUMPREG(MXR_GRAPHIC0_SPAN);
+	DUMPREG(MXR_GRAPHIC0_WH);
+	DUMPREG(MXR_GRAPHIC0_SXY);
+	DUMPREG(MXR_GRAPHIC0_DXY);
+
+	DUMPREG(MXR_GRAPHIC1_CFG);
+	DUMPREG(MXR_GRAPHIC1_BASE);
+	DUMPREG(MXR_GRAPHIC1_SPAN);
+	DUMPREG(MXR_GRAPHIC1_WH);
+	DUMPREG(MXR_GRAPHIC1_SXY);
+	DUMPREG(MXR_GRAPHIC1_DXY);
+#undef DUMPREG
+}
+
+static void mxr_reg_vp_dump(struct mxr_device *mdev)
+{
+#define DUMPREG(reg_id) \
+do { \
+	mxr_dbg(mdev, #reg_id " = %08x\n", \
+		(u32) readl(mdev->res.vp_regs + reg_id)); \
+} while (0)
+
+
+	DUMPREG(VP_ENABLE);
+	DUMPREG(VP_SRESET);
+	DUMPREG(VP_SHADOW_UPDATE);
+	DUMPREG(VP_FIELD_ID);
+	DUMPREG(VP_MODE);
+	DUMPREG(VP_IMG_SIZE_Y);
+	DUMPREG(VP_IMG_SIZE_C);
+	DUMPREG(VP_PER_RATE_CTRL);
+	DUMPREG(VP_TOP_Y_PTR);
+	DUMPREG(VP_BOT_Y_PTR);
+	DUMPREG(VP_TOP_C_PTR);
+	DUMPREG(VP_BOT_C_PTR);
+	DUMPREG(VP_ENDIAN_MODE);
+	DUMPREG(VP_SRC_H_POSITION);
+	DUMPREG(VP_SRC_V_POSITION);
+	DUMPREG(VP_SRC_WIDTH);
+	DUMPREG(VP_SRC_HEIGHT);
+	DUMPREG(VP_DST_H_POSITION);
+	DUMPREG(VP_DST_V_POSITION);
+	DUMPREG(VP_DST_WIDTH);
+	DUMPREG(VP_DST_HEIGHT);
+	DUMPREG(VP_H_RATIO);
+	DUMPREG(VP_V_RATIO);
+
+#undef DUMPREG
+}
+
+void mxr_reg_dump(struct mxr_device *mdev)
+{
+	mxr_reg_mxr_dump(mdev);
+	mxr_reg_vp_dump(mdev);
+}
+
diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c
new file mode 100644
index 0000000..a9c6be3
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/mixer_video.c
@@ -0,0 +1,1127 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#define pr_fmt(fmt) "s5p-tv (mixer): " fmt
+
+#include "mixer.h"
+
+#include <media/v4l2-ioctl.h>
+#include <linux/videodev2.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/timer.h>
+#include <media/videobuf2-dma-contig.h>
+
+static int find_reg_callback(struct device *dev, void *p)
+{
+	struct v4l2_subdev **sd = p;
+
+	*sd = dev_get_drvdata(dev);
+	/* non-zero value stops iteration */
+	return 1;
+}
+
+static struct v4l2_subdev *find_and_register_subdev(
+	struct mxr_device *mdev, char *module_name)
+{
+	struct device_driver *drv;
+	struct v4l2_subdev *sd = NULL;
+	int ret;
+
+	/* TODO: add waiting until probe is finished */
+	drv = driver_find(module_name, &platform_bus_type);
+	if (!drv) {
+		mxr_warn(mdev, "module %s is missing\n", module_name);
+		return NULL;
+	}
+	/* driver refcnt is increased, it is safe to iterate over devices */
+	ret = driver_for_each_device(drv, NULL, &sd, find_reg_callback);
+	/* ret == 0 means that find_reg_callback was never executed */
+	if (sd == NULL) {
+		mxr_warn(mdev, "module %s provides no subdev!\n", module_name);
+		goto done;
+	}
+	/* v4l2_device_register_subdev detects if sd is NULL */
+	ret = v4l2_device_register_subdev(&mdev->v4l2_dev, sd);
+	if (ret) {
+		mxr_warn(mdev, "failed to register subdev %s\n", sd->name);
+		sd = NULL;
+	}
+
+done:
+	return sd;
+}
+
+int __devinit mxr_acquire_video(struct mxr_device *mdev,
+	struct mxr_output_conf *output_conf, int output_count)
+{
+	struct device *dev = mdev->dev;
+	struct v4l2_device *v4l2_dev = &mdev->v4l2_dev;
+	int i;
+	int ret = 0;
+	struct v4l2_subdev *sd;
+
+	strlcpy(v4l2_dev->name, dev_name(mdev->dev), sizeof(v4l2_dev->name));
+	/* prepare context for V4L2 device */
+	ret = v4l2_device_register(dev, v4l2_dev);
+	if (ret) {
+		mxr_err(mdev, "could not register v4l2 device.\n");
+		goto fail;
+	}
+
+	mdev->alloc_ctx = vb2_dma_contig_init_ctx(mdev->dev);
+	if (IS_ERR_OR_NULL(mdev->alloc_ctx)) {
+		mxr_err(mdev, "could not acquire vb2 allocator\n");
+		goto fail_v4l2_dev;
+	}
+
+	/* registering outputs */
+	mdev->output_cnt = 0;
+	for (i = 0; i < output_count; ++i) {
+		struct mxr_output_conf *conf = &output_conf[i];
+		struct mxr_output *out;
+
+		sd = find_and_register_subdev(mdev, conf->module_name);
+		/* trying to register next output */
+		if (sd == NULL)
+			continue;
+		out = kzalloc(sizeof *out, GFP_KERNEL);
+		if (out == NULL) {
+			mxr_err(mdev, "no memory for '%s'\n",
+				conf->output_name);
+			ret = -ENOMEM;
+			/* registered subdevs are removed in fail_v4l2_dev */
+			goto fail_output;
+		}
+		strlcpy(out->name, conf->output_name, sizeof(out->name));
+		out->sd = sd;
+		out->cookie = conf->cookie;
+		mdev->output[mdev->output_cnt++] = out;
+		mxr_info(mdev, "added output '%s' from module '%s'\n",
+			conf->output_name, conf->module_name);
+		/* checking if maximal number of outputs is reached */
+		if (mdev->output_cnt >= MXR_MAX_OUTPUTS)
+			break;
+	}
+
+	if (mdev->output_cnt == 0) {
+		mxr_err(mdev, "failed to register any output\n");
+		ret = -ENODEV;
+		/* skipping fail_output because there is nothing to free */
+		goto fail_vb2_allocator;
+	}
+
+	return 0;
+
+fail_output:
+	/* kfree is NULL-safe */
+	for (i = 0; i < mdev->output_cnt; ++i)
+		kfree(mdev->output[i]);
+	memset(mdev->output, 0, sizeof mdev->output);
+
+fail_vb2_allocator:
+	/* freeing allocator context */
+	vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
+
+fail_v4l2_dev:
+	/* NOTE: automatically unregister all subdevs */
+	v4l2_device_unregister(v4l2_dev);
+
+fail:
+	return ret;
+}
+
+void mxr_release_video(struct mxr_device *mdev)
+{
+	int i;
+
+	/* kfree is NULL-safe */
+	for (i = 0; i < mdev->output_cnt; ++i)
+		kfree(mdev->output[i]);
+
+	vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
+	v4l2_device_unregister(&mdev->v4l2_dev);
+}
+
+static int mxr_querycap(struct file *file, void *priv,
+	struct v4l2_capability *cap)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+	strlcpy(cap->driver, MXR_DRIVER_NAME, sizeof cap->driver);
+	strlcpy(cap->card, layer->vfd.name, sizeof cap->card);
+	sprintf(cap->bus_info, "%d", layer->idx);
+	cap->version = KERNEL_VERSION(0, 1, 0);
+	cap->capabilities = V4L2_CAP_STREAMING |
+		V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+
+	return 0;
+}
+
+static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo)
+{
+	mxr_dbg(mdev, "src.full_size = (%u, %u)\n",
+		geo->src.full_width, geo->src.full_height);
+	mxr_dbg(mdev, "src.size = (%u, %u)\n",
+		geo->src.width, geo->src.height);
+	mxr_dbg(mdev, "src.offset = (%u, %u)\n",
+		geo->src.x_offset, geo->src.y_offset);
+	mxr_dbg(mdev, "dst.full_size = (%u, %u)\n",
+		geo->dst.full_width, geo->dst.full_height);
+	mxr_dbg(mdev, "dst.size = (%u, %u)\n",
+		geo->dst.width, geo->dst.height);
+	mxr_dbg(mdev, "dst.offset = (%u, %u)\n",
+		geo->dst.x_offset, geo->dst.y_offset);
+	mxr_dbg(mdev, "ratio = (%u, %u)\n",
+		geo->x_ratio, geo->y_ratio);
+}
+
+static void mxr_layer_default_geo(struct mxr_layer *layer)
+{
+	struct mxr_device *mdev = layer->mdev;
+	struct v4l2_mbus_framefmt mbus_fmt;
+
+	memset(&layer->geo, 0, sizeof layer->geo);
+
+	mxr_get_mbus_fmt(mdev, &mbus_fmt);
+
+	layer->geo.dst.full_width = mbus_fmt.width;
+	layer->geo.dst.full_height = mbus_fmt.height;
+	layer->geo.dst.width = layer->geo.dst.full_width;
+	layer->geo.dst.height = layer->geo.dst.full_height;
+	layer->geo.dst.field = mbus_fmt.field;
+
+	layer->geo.src.full_width = mbus_fmt.width;
+	layer->geo.src.full_height = mbus_fmt.height;
+	layer->geo.src.width = layer->geo.src.full_width;
+	layer->geo.src.height = layer->geo.src.full_height;
+
+	mxr_geometry_dump(mdev, &layer->geo);
+	layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0);
+	mxr_geometry_dump(mdev, &layer->geo);
+}
+
+static void mxr_layer_update_output(struct mxr_layer *layer)
+{
+	struct mxr_device *mdev = layer->mdev;
+	struct v4l2_mbus_framefmt mbus_fmt;
+
+	mxr_get_mbus_fmt(mdev, &mbus_fmt);
+	/* checking if update is needed */
+	if (layer->geo.dst.full_width == mbus_fmt.width &&
+		layer->geo.dst.full_height == mbus_fmt.width)
+		return;
+
+	layer->geo.dst.full_width = mbus_fmt.width;
+	layer->geo.dst.full_height = mbus_fmt.height;
+	layer->geo.dst.field = mbus_fmt.field;
+	layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0);
+
+	mxr_geometry_dump(mdev, &layer->geo);
+}
+
+static const struct mxr_format *find_format_by_fourcc(
+	struct mxr_layer *layer, unsigned long fourcc);
+static const struct mxr_format *find_format_by_index(
+	struct mxr_layer *layer, unsigned long index);
+
+static int mxr_enum_fmt(struct file *file, void  *priv,
+	struct v4l2_fmtdesc *f)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+	const struct mxr_format *fmt;
+
+	mxr_dbg(mdev, "%s\n", __func__);
+	fmt = find_format_by_index(layer, f->index);
+	if (fmt == NULL)
+		return -EINVAL;
+
+	strlcpy(f->description, fmt->name, sizeof(f->description));
+	f->pixelformat = fmt->fourcc;
+
+	return 0;
+}
+
+static unsigned int divup(unsigned int divident, unsigned int divisor)
+{
+	return (divident + divisor - 1) / divisor;
+}
+
+unsigned long mxr_get_plane_size(const struct mxr_block *blk,
+	unsigned int width, unsigned int height)
+{
+	unsigned int bl_width = divup(width, blk->width);
+	unsigned int bl_height = divup(height, blk->height);
+
+	return bl_width * bl_height * blk->size;
+}
+
+static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes,
+	const struct mxr_format *fmt, u32 width, u32 height)
+{
+	int i;
+
+	/* checking if nothing to fill */
+	if (!planes)
+		return;
+
+	memset(planes, 0, sizeof(*planes) * fmt->num_subframes);
+	for (i = 0; i < fmt->num_planes; ++i) {
+		struct v4l2_plane_pix_format *plane = planes
+			+ fmt->plane2subframe[i];
+		const struct mxr_block *blk = &fmt->plane[i];
+		u32 bl_width = divup(width, blk->width);
+		u32 bl_height = divup(height, blk->height);
+		u32 sizeimage = bl_width * bl_height * blk->size;
+		u16 bytesperline = bl_width * blk->size / blk->height;
+
+		plane->sizeimage += sizeimage;
+		plane->bytesperline = max(plane->bytesperline, bytesperline);
+	}
+}
+
+static int mxr_g_fmt(struct file *file, void *priv,
+			     struct v4l2_format *f)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+	pix->width = layer->geo.src.full_width;
+	pix->height = layer->geo.src.full_height;
+	pix->field = V4L2_FIELD_NONE;
+	pix->pixelformat = layer->fmt->fourcc;
+	pix->colorspace = layer->fmt->colorspace;
+	mxr_mplane_fill(pix->plane_fmt, layer->fmt, pix->width, pix->height);
+
+	return 0;
+}
+
+static int mxr_s_fmt(struct file *file, void *priv,
+	struct v4l2_format *f)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	const struct mxr_format *fmt;
+	struct v4l2_pix_format_mplane *pix;
+	struct mxr_device *mdev = layer->mdev;
+	struct mxr_geometry *geo = &layer->geo;
+
+	mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
+
+	pix = &f->fmt.pix_mp;
+	fmt = find_format_by_fourcc(layer, pix->pixelformat);
+	if (fmt == NULL) {
+		mxr_warn(mdev, "not recognized fourcc: %08x\n",
+			pix->pixelformat);
+		return -EINVAL;
+	}
+	layer->fmt = fmt;
+	/* set source size to highest accepted value */
+	geo->src.full_width = max(geo->dst.full_width, pix->width);
+	geo->src.full_height = max(geo->dst.full_height, pix->height);
+	layer->ops.fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0);
+	mxr_geometry_dump(mdev, &layer->geo);
+	/* set cropping to total visible screen */
+	geo->src.width = pix->width;
+	geo->src.height = pix->height;
+	geo->src.x_offset = 0;
+	geo->src.y_offset = 0;
+	/* assure consistency of geometry */
+	layer->ops.fix_geometry(layer, MXR_GEOMETRY_CROP, MXR_NO_OFFSET);
+	mxr_geometry_dump(mdev, &layer->geo);
+	/* set full size to lowest possible value */
+	geo->src.full_width = 0;
+	geo->src.full_height = 0;
+	layer->ops.fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0);
+	mxr_geometry_dump(mdev, &layer->geo);
+
+	/* returning results */
+	mxr_g_fmt(file, priv, f);
+
+	return 0;
+}
+
+static int mxr_g_selection(struct file *file, void *fh,
+	struct v4l2_selection *s)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_geometry *geo = &layer->geo;
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+		s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return -EINVAL;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP:
+		s->r.left = geo->src.x_offset;
+		s->r.top = geo->src.y_offset;
+		s->r.width = geo->src.width;
+		s->r.height = geo->src.height;
+		break;
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = geo->src.full_width;
+		s->r.height = geo->src.full_height;
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+	case V4L2_SEL_TGT_COMPOSE_PADDED:
+		s->r.left = geo->dst.x_offset;
+		s->r.top = geo->dst.y_offset;
+		s->r.width = geo->dst.width;
+		s->r.height = geo->dst.height;
+		break;
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = geo->dst.full_width;
+		s->r.height = geo->dst.full_height;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* returns 1 if rectangle 'a' is inside 'b' */
+static int mxr_is_rect_inside(struct v4l2_rect *a, struct v4l2_rect *b)
+{
+	if (a->left < b->left)
+		return 0;
+	if (a->top < b->top)
+		return 0;
+	if (a->left + a->width > b->left + b->width)
+		return 0;
+	if (a->top + a->height > b->top + b->height)
+		return 0;
+	return 1;
+}
+
+static int mxr_s_selection(struct file *file, void *fh,
+	struct v4l2_selection *s)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_geometry *geo = &layer->geo;
+	struct mxr_crop *target = NULL;
+	enum mxr_geometry_stage stage;
+	struct mxr_geometry tmp;
+	struct v4l2_rect res;
+
+	memset(&res, 0, sizeof res);
+
+	mxr_dbg(layer->mdev, "%s: rect: %dx%d@%d,%d\n", __func__,
+		s->r.width, s->r.height, s->r.left, s->r.top);
+
+	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+		s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return -EINVAL;
+
+	switch (s->target) {
+	/* ignore read-only targets */
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		res.width = geo->src.full_width;
+		res.height = geo->src.full_height;
+		break;
+
+	/* ignore read-only targets */
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		res.width = geo->dst.full_width;
+		res.height = geo->dst.full_height;
+		break;
+
+	case V4L2_SEL_TGT_CROP:
+		target = &geo->src;
+		stage = MXR_GEOMETRY_CROP;
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+	case V4L2_SEL_TGT_COMPOSE_PADDED:
+		target = &geo->dst;
+		stage = MXR_GEOMETRY_COMPOSE;
+		break;
+	default:
+		return -EINVAL;
+	}
+	/* apply change and update geometry if needed */
+	if (target) {
+		/* backup current geometry if setup fails */
+		memcpy(&tmp, geo, sizeof tmp);
+
+		/* apply requested selection */
+		target->x_offset = s->r.left;
+		target->y_offset = s->r.top;
+		target->width = s->r.width;
+		target->height = s->r.height;
+
+		layer->ops.fix_geometry(layer, stage, s->flags);
+
+		/* retrieve update selection rectangle */
+		res.left = target->x_offset;
+		res.top = target->y_offset;
+		res.width = target->width;
+		res.height = target->height;
+
+		mxr_geometry_dump(layer->mdev, &layer->geo);
+	}
+
+	/* checking if the rectangle satisfies constraints */
+	if ((s->flags & V4L2_SEL_FLAG_LE) && !mxr_is_rect_inside(&res, &s->r))
+		goto fail;
+	if ((s->flags & V4L2_SEL_FLAG_GE) && !mxr_is_rect_inside(&s->r, &res))
+		goto fail;
+
+	/* return result rectangle */
+	s->r = res;
+
+	return 0;
+fail:
+	/* restore old geometry, which is not touched if target is NULL */
+	if (target)
+		memcpy(geo, &tmp, sizeof tmp);
+	return -ERANGE;
+}
+
+static int mxr_enum_dv_presets(struct file *file, void *fh,
+	struct v4l2_dv_enum_preset *preset)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+	int ret;
+
+	/* lock protects from changing sd_out */
+	mutex_lock(&mdev->mutex);
+	ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_presets, preset);
+	mutex_unlock(&mdev->mutex);
+
+	return ret ? -EINVAL : 0;
+}
+
+static int mxr_s_dv_preset(struct file *file, void *fh,
+	struct v4l2_dv_preset *preset)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+	int ret;
+
+	/* lock protects from changing sd_out */
+	mutex_lock(&mdev->mutex);
+
+	/* preset change cannot be done while there is an entity
+	 * dependant on output configuration
+	 */
+	if (mdev->n_output > 0) {
+		mutex_unlock(&mdev->mutex);
+		return -EBUSY;
+	}
+
+	ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_preset, preset);
+
+	mutex_unlock(&mdev->mutex);
+
+	mxr_layer_update_output(layer);
+
+	/* any failure should return EINVAL according to V4L2 doc */
+	return ret ? -EINVAL : 0;
+}
+
+static int mxr_g_dv_preset(struct file *file, void *fh,
+	struct v4l2_dv_preset *preset)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+	int ret;
+
+	/* lock protects from changing sd_out */
+	mutex_lock(&mdev->mutex);
+	ret = v4l2_subdev_call(to_outsd(mdev), video, g_dv_preset, preset);
+	mutex_unlock(&mdev->mutex);
+
+	return ret ? -EINVAL : 0;
+}
+
+static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+	int ret;
+
+	/* lock protects from changing sd_out */
+	mutex_lock(&mdev->mutex);
+
+	/* standard change cannot be done while there is an entity
+	 * dependant on output configuration
+	 */
+	if (mdev->n_output > 0) {
+		mutex_unlock(&mdev->mutex);
+		return -EBUSY;
+	}
+
+	ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, *norm);
+
+	mutex_unlock(&mdev->mutex);
+
+	mxr_layer_update_output(layer);
+
+	return ret ? -EINVAL : 0;
+}
+
+static int mxr_g_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+	int ret;
+
+	/* lock protects from changing sd_out */
+	mutex_lock(&mdev->mutex);
+	ret = v4l2_subdev_call(to_outsd(mdev), video, g_std_output, norm);
+	mutex_unlock(&mdev->mutex);
+
+	return ret ? -EINVAL : 0;
+}
+
+static int mxr_enum_output(struct file *file, void *fh, struct v4l2_output *a)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+	struct mxr_output *out;
+	struct v4l2_subdev *sd;
+
+	if (a->index >= mdev->output_cnt)
+		return -EINVAL;
+	out = mdev->output[a->index];
+	BUG_ON(out == NULL);
+	sd = out->sd;
+	strlcpy(a->name, out->name, sizeof(a->name));
+
+	/* try to obtain supported tv norms */
+	v4l2_subdev_call(sd, video, g_tvnorms_output, &a->std);
+	a->capabilities = 0;
+	if (sd->ops->video && sd->ops->video->s_dv_preset)
+		a->capabilities |= V4L2_OUT_CAP_PRESETS;
+	if (sd->ops->video && sd->ops->video->s_std_output)
+		a->capabilities |= V4L2_OUT_CAP_STD;
+	a->type = V4L2_OUTPUT_TYPE_ANALOG;
+
+	return 0;
+}
+
+static int mxr_s_output(struct file *file, void *fh, unsigned int i)
+{
+	struct video_device *vfd = video_devdata(file);
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+
+	if (i >= mdev->output_cnt || mdev->output[i] == NULL)
+		return -EINVAL;
+
+	mutex_lock(&mdev->mutex);
+	if (mdev->n_output > 0) {
+		mutex_unlock(&mdev->mutex);
+		return -EBUSY;
+	}
+	mdev->current_output = i;
+	vfd->tvnorms = 0;
+	v4l2_subdev_call(to_outsd(mdev), video, g_tvnorms_output,
+		&vfd->tvnorms);
+	mutex_unlock(&mdev->mutex);
+
+	/* update layers geometry */
+	mxr_layer_update_output(layer);
+
+	mxr_dbg(mdev, "tvnorms = %08llx\n", vfd->tvnorms);
+
+	return 0;
+}
+
+static int mxr_g_output(struct file *file, void *fh, unsigned int *p)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+
+	mutex_lock(&mdev->mutex);
+	*p = mdev->current_output;
+	mutex_unlock(&mdev->mutex);
+
+	return 0;
+}
+
+static int mxr_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *p)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+	return vb2_reqbufs(&layer->vb_queue, p);
+}
+
+static int mxr_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+	return vb2_querybuf(&layer->vb_queue, p);
+}
+
+static int mxr_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d(%d)\n", __func__, __LINE__, p->index);
+	return vb2_qbuf(&layer->vb_queue, p);
+}
+
+static int mxr_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+	return vb2_dqbuf(&layer->vb_queue, p, file->f_flags & O_NONBLOCK);
+}
+
+static int mxr_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+	return vb2_streamon(&layer->vb_queue, i);
+}
+
+static int mxr_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+	return vb2_streamoff(&layer->vb_queue, i);
+}
+
+static const struct v4l2_ioctl_ops mxr_ioctl_ops = {
+	.vidioc_querycap = mxr_querycap,
+	/* format handling */
+	.vidioc_enum_fmt_vid_out = mxr_enum_fmt,
+	.vidioc_s_fmt_vid_out_mplane = mxr_s_fmt,
+	.vidioc_g_fmt_vid_out_mplane = mxr_g_fmt,
+	/* buffer control */
+	.vidioc_reqbufs = mxr_reqbufs,
+	.vidioc_querybuf = mxr_querybuf,
+	.vidioc_qbuf = mxr_qbuf,
+	.vidioc_dqbuf = mxr_dqbuf,
+	/* Streaming control */
+	.vidioc_streamon = mxr_streamon,
+	.vidioc_streamoff = mxr_streamoff,
+	/* Preset functions */
+	.vidioc_enum_dv_presets = mxr_enum_dv_presets,
+	.vidioc_s_dv_preset = mxr_s_dv_preset,
+	.vidioc_g_dv_preset = mxr_g_dv_preset,
+	/* analog TV standard functions */
+	.vidioc_s_std = mxr_s_std,
+	.vidioc_g_std = mxr_g_std,
+	/* Output handling */
+	.vidioc_enum_output = mxr_enum_output,
+	.vidioc_s_output = mxr_s_output,
+	.vidioc_g_output = mxr_g_output,
+	/* selection ioctls */
+	.vidioc_g_selection = mxr_g_selection,
+	.vidioc_s_selection = mxr_s_selection,
+};
+
+static int mxr_video_open(struct file *file)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	struct mxr_device *mdev = layer->mdev;
+	int ret = 0;
+
+	mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
+	if (mutex_lock_interruptible(&layer->mutex))
+		return -ERESTARTSYS;
+	/* assure device probe is finished */
+	wait_for_device_probe();
+	/* creating context for file descriptor */
+	ret = v4l2_fh_open(file);
+	if (ret) {
+		mxr_err(mdev, "v4l2_fh_open failed\n");
+		goto unlock;
+	}
+
+	/* leaving if layer is already initialized */
+	if (!v4l2_fh_is_singular_file(file))
+		goto unlock;
+
+	/* FIXME: should power be enabled on open? */
+	ret = mxr_power_get(mdev);
+	if (ret) {
+		mxr_err(mdev, "power on failed\n");
+		goto fail_fh_open;
+	}
+
+	ret = vb2_queue_init(&layer->vb_queue);
+	if (ret != 0) {
+		mxr_err(mdev, "failed to initialize vb2 queue\n");
+		goto fail_power;
+	}
+	/* set default format, first on the list */
+	layer->fmt = layer->fmt_array[0];
+	/* setup default geometry */
+	mxr_layer_default_geo(layer);
+	mutex_unlock(&layer->mutex);
+
+	return 0;
+
+fail_power:
+	mxr_power_put(mdev);
+
+fail_fh_open:
+	v4l2_fh_release(file);
+
+unlock:
+	mutex_unlock(&layer->mutex);
+
+	return ret;
+}
+
+static unsigned int
+mxr_video_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	unsigned int res;
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+	mutex_lock(&layer->mutex);
+	res = vb2_poll(&layer->vb_queue, file, wait);
+	mutex_unlock(&layer->mutex);
+	return res;
+}
+
+static int mxr_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+	int ret;
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+	if (mutex_lock_interruptible(&layer->mutex))
+		return -ERESTARTSYS;
+	ret = vb2_mmap(&layer->vb_queue, vma);
+	mutex_unlock(&layer->mutex);
+	return ret;
+}
+
+static int mxr_video_release(struct file *file)
+{
+	struct mxr_layer *layer = video_drvdata(file);
+
+	mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+	mutex_lock(&layer->mutex);
+	if (v4l2_fh_is_singular_file(file)) {
+		vb2_queue_release(&layer->vb_queue);
+		mxr_power_put(layer->mdev);
+	}
+	v4l2_fh_release(file);
+	mutex_unlock(&layer->mutex);
+	return 0;
+}
+
+static const struct v4l2_file_operations mxr_fops = {
+	.owner = THIS_MODULE,
+	.open = mxr_video_open,
+	.poll = mxr_video_poll,
+	.mmap = mxr_video_mmap,
+	.release = mxr_video_release,
+	.unlocked_ioctl = video_ioctl2,
+};
+
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt,
+	unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[],
+	void *alloc_ctxs[])
+{
+	struct mxr_layer *layer = vb2_get_drv_priv(vq);
+	const struct mxr_format *fmt = layer->fmt;
+	int i;
+	struct mxr_device *mdev = layer->mdev;
+	struct v4l2_plane_pix_format planes[3];
+
+	mxr_dbg(mdev, "%s\n", __func__);
+	/* checking if format was configured */
+	if (fmt == NULL)
+		return -EINVAL;
+	mxr_dbg(mdev, "fmt = %s\n", fmt->name);
+	mxr_mplane_fill(planes, fmt, layer->geo.src.full_width,
+		layer->geo.src.full_height);
+
+	*nplanes = fmt->num_subframes;
+	for (i = 0; i < fmt->num_subframes; ++i) {
+		alloc_ctxs[i] = layer->mdev->alloc_ctx;
+		sizes[i] = planes[i].sizeimage;
+		mxr_dbg(mdev, "size[%d] = %08x\n", i, sizes[i]);
+	}
+
+	if (*nbuffers == 0)
+		*nbuffers = 1;
+
+	return 0;
+}
+
+static void buf_queue(struct vb2_buffer *vb)
+{
+	struct mxr_buffer *buffer = container_of(vb, struct mxr_buffer, vb);
+	struct mxr_layer *layer = vb2_get_drv_priv(vb->vb2_queue);
+	struct mxr_device *mdev = layer->mdev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&layer->enq_slock, flags);
+	list_add_tail(&buffer->list, &layer->enq_list);
+	spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+	mxr_dbg(mdev, "queuing buffer\n");
+}
+
+static void wait_lock(struct vb2_queue *vq)
+{
+	struct mxr_layer *layer = vb2_get_drv_priv(vq);
+
+	mxr_dbg(layer->mdev, "%s\n", __func__);
+	mutex_lock(&layer->mutex);
+}
+
+static void wait_unlock(struct vb2_queue *vq)
+{
+	struct mxr_layer *layer = vb2_get_drv_priv(vq);
+
+	mxr_dbg(layer->mdev, "%s\n", __func__);
+	mutex_unlock(&layer->mutex);
+}
+
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct mxr_layer *layer = vb2_get_drv_priv(vq);
+	struct mxr_device *mdev = layer->mdev;
+	unsigned long flags;
+
+	mxr_dbg(mdev, "%s\n", __func__);
+
+	if (count == 0) {
+		mxr_dbg(mdev, "no output buffers queued\n");
+		return -EINVAL;
+	}
+
+	/* block any changes in output configuration */
+	mxr_output_get(mdev);
+
+	mxr_layer_update_output(layer);
+	layer->ops.format_set(layer);
+	/* enabling layer in hardware */
+	spin_lock_irqsave(&layer->enq_slock, flags);
+	layer->state = MXR_LAYER_STREAMING;
+	spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+	layer->ops.stream_set(layer, MXR_ENABLE);
+	mxr_streamer_get(mdev);
+
+	return 0;
+}
+
+static void mxr_watchdog(unsigned long arg)
+{
+	struct mxr_layer *layer = (struct mxr_layer *) arg;
+	struct mxr_device *mdev = layer->mdev;
+	unsigned long flags;
+
+	mxr_err(mdev, "watchdog fired for layer %s\n", layer->vfd.name);
+
+	spin_lock_irqsave(&layer->enq_slock, flags);
+
+	if (layer->update_buf == layer->shadow_buf)
+		layer->update_buf = NULL;
+	if (layer->update_buf) {
+		vb2_buffer_done(&layer->update_buf->vb, VB2_BUF_STATE_ERROR);
+		layer->update_buf = NULL;
+	}
+	if (layer->shadow_buf) {
+		vb2_buffer_done(&layer->shadow_buf->vb, VB2_BUF_STATE_ERROR);
+		layer->shadow_buf = NULL;
+	}
+	spin_unlock_irqrestore(&layer->enq_slock, flags);
+}
+
+static int stop_streaming(struct vb2_queue *vq)
+{
+	struct mxr_layer *layer = vb2_get_drv_priv(vq);
+	struct mxr_device *mdev = layer->mdev;
+	unsigned long flags;
+	struct timer_list watchdog;
+	struct mxr_buffer *buf, *buf_tmp;
+
+	mxr_dbg(mdev, "%s\n", __func__);
+
+	spin_lock_irqsave(&layer->enq_slock, flags);
+
+	/* reset list */
+	layer->state = MXR_LAYER_STREAMING_FINISH;
+
+	/* set all buffer to be done */
+	list_for_each_entry_safe(buf, buf_tmp, &layer->enq_list, list) {
+		list_del(&buf->list);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+
+	spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+	/* give 1 seconds to complete to complete last buffers */
+	setup_timer_on_stack(&watchdog, mxr_watchdog,
+		(unsigned long)layer);
+	mod_timer(&watchdog, jiffies + msecs_to_jiffies(1000));
+
+	/* wait until all buffers are goes to done state */
+	vb2_wait_for_all_buffers(vq);
+
+	/* stop timer if all synchronization is done */
+	del_timer_sync(&watchdog);
+	destroy_timer_on_stack(&watchdog);
+
+	/* stopping hardware */
+	spin_lock_irqsave(&layer->enq_slock, flags);
+	layer->state = MXR_LAYER_IDLE;
+	spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+	/* disabling layer in hardware */
+	layer->ops.stream_set(layer, MXR_DISABLE);
+	/* remove one streamer */
+	mxr_streamer_put(mdev);
+	/* allow changes in output configuration */
+	mxr_output_put(mdev);
+	return 0;
+}
+
+static struct vb2_ops mxr_video_qops = {
+	.queue_setup = queue_setup,
+	.buf_queue = buf_queue,
+	.wait_prepare = wait_unlock,
+	.wait_finish = wait_lock,
+	.start_streaming = start_streaming,
+	.stop_streaming = stop_streaming,
+};
+
+/* FIXME: try to put this functions to mxr_base_layer_create */
+int mxr_base_layer_register(struct mxr_layer *layer)
+{
+	struct mxr_device *mdev = layer->mdev;
+	int ret;
+
+	ret = video_register_device(&layer->vfd, VFL_TYPE_GRABBER, -1);
+	if (ret)
+		mxr_err(mdev, "failed to register video device\n");
+	else
+		mxr_info(mdev, "registered layer %s as /dev/video%d\n",
+			layer->vfd.name, layer->vfd.num);
+	return ret;
+}
+
+void mxr_base_layer_unregister(struct mxr_layer *layer)
+{
+	video_unregister_device(&layer->vfd);
+}
+
+void mxr_layer_release(struct mxr_layer *layer)
+{
+	if (layer->ops.release)
+		layer->ops.release(layer);
+}
+
+void mxr_base_layer_release(struct mxr_layer *layer)
+{
+	kfree(layer);
+}
+
+static void mxr_vfd_release(struct video_device *vdev)
+{
+	pr_info("video device release\n");
+}
+
+struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
+	int idx, char *name, struct mxr_layer_ops *ops)
+{
+	struct mxr_layer *layer;
+
+	layer = kzalloc(sizeof *layer, GFP_KERNEL);
+	if (layer == NULL) {
+		mxr_err(mdev, "not enough memory for layer.\n");
+		goto fail;
+	}
+
+	layer->mdev = mdev;
+	layer->idx = idx;
+	layer->ops = *ops;
+
+	spin_lock_init(&layer->enq_slock);
+	INIT_LIST_HEAD(&layer->enq_list);
+	mutex_init(&layer->mutex);
+
+	layer->vfd = (struct video_device) {
+		.minor = -1,
+		.release = mxr_vfd_release,
+		.fops = &mxr_fops,
+		.ioctl_ops = &mxr_ioctl_ops,
+	};
+	strlcpy(layer->vfd.name, name, sizeof(layer->vfd.name));
+	/* let framework control PRIORITY */
+	set_bit(V4L2_FL_USE_FH_PRIO, &layer->vfd.flags);
+
+	video_set_drvdata(&layer->vfd, layer);
+	layer->vfd.lock = &layer->mutex;
+	layer->vfd.v4l2_dev = &mdev->v4l2_dev;
+
+	layer->vb_queue = (struct vb2_queue) {
+		.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+		.io_modes = VB2_MMAP | VB2_USERPTR,
+		.drv_priv = layer,
+		.buf_struct_size = sizeof(struct mxr_buffer),
+		.ops = &mxr_video_qops,
+		.mem_ops = &vb2_dma_contig_memops,
+	};
+
+	return layer;
+
+fail:
+	return NULL;
+}
+
+static const struct mxr_format *find_format_by_fourcc(
+	struct mxr_layer *layer, unsigned long fourcc)
+{
+	int i;
+
+	for (i = 0; i < layer->fmt_array_size; ++i)
+		if (layer->fmt_array[i]->fourcc == fourcc)
+			return layer->fmt_array[i];
+	return NULL;
+}
+
+static const struct mxr_format *find_format_by_index(
+	struct mxr_layer *layer, unsigned long index)
+{
+	if (index >= layer->fmt_array_size)
+		return NULL;
+	return layer->fmt_array[index];
+}
+
diff --git a/drivers/media/platform/s5p-tv/mixer_vp_layer.c b/drivers/media/platform/s5p-tv/mixer_vp_layer.c
new file mode 100644
index 0000000..3d13a63
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/mixer_vp_layer.c
@@ -0,0 +1,241 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#include "regs-vp.h"
+
+#include <media/videobuf2-dma-contig.h>
+
+/* FORMAT DEFINITIONS */
+static const struct mxr_format mxr_fmt_nv12 = {
+	.name = "NV12",
+	.fourcc = V4L2_PIX_FMT_NV12,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	.num_planes = 2,
+	.plane = {
+		{ .width = 1, .height = 1, .size = 1 },
+		{ .width = 2, .height = 2, .size = 2 },
+	},
+	.num_subframes = 1,
+	.cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv21 = {
+	.name = "NV21",
+	.fourcc = V4L2_PIX_FMT_NV21,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	.num_planes = 2,
+	.plane = {
+		{ .width = 1, .height = 1, .size = 1 },
+		{ .width = 2, .height = 2, .size = 2 },
+	},
+	.num_subframes = 1,
+	.cookie = VP_MODE_NV21 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv12m = {
+	.name = "NV12 (mplane)",
+	.fourcc = V4L2_PIX_FMT_NV12M,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	.num_planes = 2,
+	.plane = {
+		{ .width = 1, .height = 1, .size = 1 },
+		{ .width = 2, .height = 2, .size = 2 },
+	},
+	.num_subframes = 2,
+	.plane2subframe = {0, 1},
+	.cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv12mt = {
+	.name = "NV12 tiled (mplane)",
+	.fourcc = V4L2_PIX_FMT_NV12MT,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	.num_planes = 2,
+	.plane = {
+		{ .width = 128, .height = 32, .size = 4096 },
+		{ .width = 128, .height = 32, .size = 2048 },
+	},
+	.num_subframes = 2,
+	.plane2subframe = {0, 1},
+	.cookie = VP_MODE_NV12 | VP_MODE_MEM_TILED,
+};
+
+static const struct mxr_format *mxr_video_format[] = {
+	&mxr_fmt_nv12,
+	&mxr_fmt_nv21,
+	&mxr_fmt_nv12m,
+	&mxr_fmt_nv12mt,
+};
+
+/* AUXILIARY CALLBACKS */
+
+static void mxr_vp_layer_release(struct mxr_layer *layer)
+{
+	mxr_base_layer_unregister(layer);
+	mxr_base_layer_release(layer);
+}
+
+static void mxr_vp_buffer_set(struct mxr_layer *layer,
+	struct mxr_buffer *buf)
+{
+	dma_addr_t luma_addr[2] = {0, 0};
+	dma_addr_t chroma_addr[2] = {0, 0};
+
+	if (buf == NULL) {
+		mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr);
+		return;
+	}
+	luma_addr[0] = vb2_dma_contig_plane_dma_addr(&buf->vb, 0);
+	if (layer->fmt->num_subframes == 2) {
+		chroma_addr[0] = vb2_dma_contig_plane_dma_addr(&buf->vb, 1);
+	} else {
+		/* FIXME: mxr_get_plane_size compute integer division,
+		 * which is slow and should not be performed in interrupt */
+		chroma_addr[0] = luma_addr[0] + mxr_get_plane_size(
+			&layer->fmt->plane[0], layer->geo.src.full_width,
+			layer->geo.src.full_height);
+	}
+	if (layer->fmt->cookie & VP_MODE_MEM_TILED) {
+		luma_addr[1] = luma_addr[0] + 0x40;
+		chroma_addr[1] = chroma_addr[0] + 0x40;
+	} else {
+		luma_addr[1] = luma_addr[0] + layer->geo.src.full_width;
+		chroma_addr[1] = chroma_addr[0];
+	}
+	mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr);
+}
+
+static void mxr_vp_stream_set(struct mxr_layer *layer, int en)
+{
+	mxr_reg_vp_layer_stream(layer->mdev, en);
+}
+
+static void mxr_vp_format_set(struct mxr_layer *layer)
+{
+	mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo);
+}
+
+static inline unsigned int do_center(unsigned int center,
+	unsigned int size, unsigned int upper, unsigned int flags)
+{
+	unsigned int lower;
+
+	if (flags & MXR_NO_OFFSET)
+		return 0;
+
+	lower = center - min(center, size / 2);
+	return min(lower, upper - size);
+}
+
+static void mxr_vp_fix_geometry(struct mxr_layer *layer,
+	enum mxr_geometry_stage stage, unsigned long flags)
+{
+	struct mxr_geometry *geo = &layer->geo;
+	struct mxr_crop *src = &geo->src;
+	struct mxr_crop *dst = &geo->dst;
+	unsigned long x_center, y_center;
+
+	switch (stage) {
+
+	case MXR_GEOMETRY_SINK: /* nothing to be fixed here */
+	case MXR_GEOMETRY_COMPOSE:
+		/* remember center of the area */
+		x_center = dst->x_offset + dst->width / 2;
+		y_center = dst->y_offset + dst->height / 2;
+
+		/* ensure that compose is reachable using 16x scaling */
+		dst->width = clamp(dst->width, 8U, 16 * src->full_width);
+		dst->height = clamp(dst->height, 1U, 16 * src->full_height);
+
+		/* setup offsets */
+		dst->x_offset = do_center(x_center, dst->width,
+			dst->full_width, flags);
+		dst->y_offset = do_center(y_center, dst->height,
+			dst->full_height, flags);
+		flags = 0; /* remove possible MXR_NO_OFFSET flag */
+		/* fall through */
+	case MXR_GEOMETRY_CROP:
+		/* remember center of the area */
+		x_center = src->x_offset + src->width / 2;
+		y_center = src->y_offset + src->height / 2;
+
+		/* ensure scaling is between 0.25x .. 16x */
+		src->width = clamp(src->width, round_up(dst->width / 16, 4),
+			dst->width * 4);
+		src->height = clamp(src->height, round_up(dst->height / 16, 4),
+			dst->height * 4);
+
+		/* hardware limits */
+		src->width = clamp(src->width, 32U, 2047U);
+		src->height = clamp(src->height, 4U, 2047U);
+
+		/* setup offsets */
+		src->x_offset = do_center(x_center, src->width,
+			src->full_width, flags);
+		src->y_offset = do_center(y_center, src->height,
+			src->full_height, flags);
+
+		/* setting scaling ratio */
+		geo->x_ratio = (src->width << 16) / dst->width;
+		geo->y_ratio = (src->height << 16) / dst->height;
+		/* fall through */
+
+	case MXR_GEOMETRY_SOURCE:
+		src->full_width = clamp(src->full_width,
+			ALIGN(src->width + src->x_offset, 8), 8192U);
+		src->full_height = clamp(src->full_height,
+			src->height + src->y_offset, 8192U);
+	};
+}
+
+/* PUBLIC API */
+
+struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx)
+{
+	struct mxr_layer *layer;
+	int ret;
+	struct mxr_layer_ops ops = {
+		.release = mxr_vp_layer_release,
+		.buffer_set = mxr_vp_buffer_set,
+		.stream_set = mxr_vp_stream_set,
+		.format_set = mxr_vp_format_set,
+		.fix_geometry = mxr_vp_fix_geometry,
+	};
+	char name[32];
+
+	sprintf(name, "video%d", idx);
+
+	layer = mxr_base_layer_create(mdev, idx, name, &ops);
+	if (layer == NULL) {
+		mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
+		goto fail;
+	}
+
+	layer->fmt_array = mxr_video_format;
+	layer->fmt_array_size = ARRAY_SIZE(mxr_video_format);
+
+	ret = mxr_base_layer_register(layer);
+	if (ret)
+		goto fail_layer;
+
+	return layer;
+
+fail_layer:
+	mxr_base_layer_release(layer);
+
+fail:
+	return NULL;
+}
+
diff --git a/drivers/media/platform/s5p-tv/regs-hdmi.h b/drivers/media/platform/s5p-tv/regs-hdmi.h
new file mode 100644
index 0000000..a889d1f
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/regs-hdmi.h
@@ -0,0 +1,146 @@
+/* linux/arch/arm/mach-exynos4/include/mach/regs-hdmi.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * HDMI register header file for Samsung TVOUT driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef SAMSUNG_REGS_HDMI_H
+#define SAMSUNG_REGS_HDMI_H
+
+/*
+ * Register part
+*/
+
+#define HDMI_CTRL_BASE(x)		((x) + 0x00000000)
+#define HDMI_CORE_BASE(x)		((x) + 0x00010000)
+#define HDMI_TG_BASE(x)			((x) + 0x00050000)
+
+/* Control registers */
+#define HDMI_INTC_CON			HDMI_CTRL_BASE(0x0000)
+#define HDMI_INTC_FLAG			HDMI_CTRL_BASE(0x0004)
+#define HDMI_HPD_STATUS			HDMI_CTRL_BASE(0x000C)
+#define HDMI_PHY_RSTOUT			HDMI_CTRL_BASE(0x0014)
+#define HDMI_PHY_VPLL			HDMI_CTRL_BASE(0x0018)
+#define HDMI_PHY_CMU			HDMI_CTRL_BASE(0x001C)
+#define HDMI_CORE_RSTOUT		HDMI_CTRL_BASE(0x0020)
+
+/* Core registers */
+#define HDMI_CON_0			HDMI_CORE_BASE(0x0000)
+#define HDMI_CON_1			HDMI_CORE_BASE(0x0004)
+#define HDMI_CON_2			HDMI_CORE_BASE(0x0008)
+#define HDMI_SYS_STATUS			HDMI_CORE_BASE(0x0010)
+#define HDMI_PHY_STATUS			HDMI_CORE_BASE(0x0014)
+#define HDMI_STATUS_EN			HDMI_CORE_BASE(0x0020)
+#define HDMI_HPD			HDMI_CORE_BASE(0x0030)
+#define HDMI_MODE_SEL			HDMI_CORE_BASE(0x0040)
+#define HDMI_BLUE_SCREEN_0		HDMI_CORE_BASE(0x0050)
+#define HDMI_BLUE_SCREEN_1		HDMI_CORE_BASE(0x0054)
+#define HDMI_BLUE_SCREEN_2		HDMI_CORE_BASE(0x0058)
+#define HDMI_H_BLANK_0			HDMI_CORE_BASE(0x00A0)
+#define HDMI_H_BLANK_1			HDMI_CORE_BASE(0x00A4)
+#define HDMI_V_BLANK_0			HDMI_CORE_BASE(0x00B0)
+#define HDMI_V_BLANK_1			HDMI_CORE_BASE(0x00B4)
+#define HDMI_V_BLANK_2			HDMI_CORE_BASE(0x00B8)
+#define HDMI_H_V_LINE_0			HDMI_CORE_BASE(0x00C0)
+#define HDMI_H_V_LINE_1			HDMI_CORE_BASE(0x00C4)
+#define HDMI_H_V_LINE_2			HDMI_CORE_BASE(0x00C8)
+#define HDMI_VSYNC_POL			HDMI_CORE_BASE(0x00E4)
+#define HDMI_INT_PRO_MODE		HDMI_CORE_BASE(0x00E8)
+#define HDMI_V_BLANK_F_0		HDMI_CORE_BASE(0x0110)
+#define HDMI_V_BLANK_F_1		HDMI_CORE_BASE(0x0114)
+#define HDMI_V_BLANK_F_2		HDMI_CORE_BASE(0x0118)
+#define HDMI_H_SYNC_GEN_0		HDMI_CORE_BASE(0x0120)
+#define HDMI_H_SYNC_GEN_1		HDMI_CORE_BASE(0x0124)
+#define HDMI_H_SYNC_GEN_2		HDMI_CORE_BASE(0x0128)
+#define HDMI_V_SYNC_GEN_1_0		HDMI_CORE_BASE(0x0130)
+#define HDMI_V_SYNC_GEN_1_1		HDMI_CORE_BASE(0x0134)
+#define HDMI_V_SYNC_GEN_1_2		HDMI_CORE_BASE(0x0138)
+#define HDMI_V_SYNC_GEN_2_0		HDMI_CORE_BASE(0x0140)
+#define HDMI_V_SYNC_GEN_2_1		HDMI_CORE_BASE(0x0144)
+#define HDMI_V_SYNC_GEN_2_2		HDMI_CORE_BASE(0x0148)
+#define HDMI_V_SYNC_GEN_3_0		HDMI_CORE_BASE(0x0150)
+#define HDMI_V_SYNC_GEN_3_1		HDMI_CORE_BASE(0x0154)
+#define HDMI_V_SYNC_GEN_3_2		HDMI_CORE_BASE(0x0158)
+#define HDMI_AVI_CON			HDMI_CORE_BASE(0x0300)
+#define HDMI_AVI_BYTE(n)		HDMI_CORE_BASE(0x0320 + 4 * (n))
+#define	HDMI_DC_CONTROL			HDMI_CORE_BASE(0x05C0)
+#define HDMI_VIDEO_PATTERN_GEN		HDMI_CORE_BASE(0x05C4)
+#define HDMI_HPD_GEN			HDMI_CORE_BASE(0x05C8)
+
+/* Timing generator registers */
+#define HDMI_TG_CMD			HDMI_TG_BASE(0x0000)
+#define HDMI_TG_H_FSZ_L			HDMI_TG_BASE(0x0018)
+#define HDMI_TG_H_FSZ_H			HDMI_TG_BASE(0x001C)
+#define HDMI_TG_HACT_ST_L		HDMI_TG_BASE(0x0020)
+#define HDMI_TG_HACT_ST_H		HDMI_TG_BASE(0x0024)
+#define HDMI_TG_HACT_SZ_L		HDMI_TG_BASE(0x0028)
+#define HDMI_TG_HACT_SZ_H		HDMI_TG_BASE(0x002C)
+#define HDMI_TG_V_FSZ_L			HDMI_TG_BASE(0x0030)
+#define HDMI_TG_V_FSZ_H			HDMI_TG_BASE(0x0034)
+#define HDMI_TG_VSYNC_L			HDMI_TG_BASE(0x0038)
+#define HDMI_TG_VSYNC_H			HDMI_TG_BASE(0x003C)
+#define HDMI_TG_VSYNC2_L		HDMI_TG_BASE(0x0040)
+#define HDMI_TG_VSYNC2_H		HDMI_TG_BASE(0x0044)
+#define HDMI_TG_VACT_ST_L		HDMI_TG_BASE(0x0048)
+#define HDMI_TG_VACT_ST_H		HDMI_TG_BASE(0x004C)
+#define HDMI_TG_VACT_SZ_L		HDMI_TG_BASE(0x0050)
+#define HDMI_TG_VACT_SZ_H		HDMI_TG_BASE(0x0054)
+#define HDMI_TG_FIELD_CHG_L		HDMI_TG_BASE(0x0058)
+#define HDMI_TG_FIELD_CHG_H		HDMI_TG_BASE(0x005C)
+#define HDMI_TG_VACT_ST2_L		HDMI_TG_BASE(0x0060)
+#define HDMI_TG_VACT_ST2_H		HDMI_TG_BASE(0x0064)
+#define HDMI_TG_VSYNC_TOP_HDMI_L	HDMI_TG_BASE(0x0078)
+#define HDMI_TG_VSYNC_TOP_HDMI_H	HDMI_TG_BASE(0x007C)
+#define HDMI_TG_VSYNC_BOT_HDMI_L	HDMI_TG_BASE(0x0080)
+#define HDMI_TG_VSYNC_BOT_HDMI_H	HDMI_TG_BASE(0x0084)
+#define HDMI_TG_FIELD_TOP_HDMI_L	HDMI_TG_BASE(0x0088)
+#define HDMI_TG_FIELD_TOP_HDMI_H	HDMI_TG_BASE(0x008C)
+#define HDMI_TG_FIELD_BOT_HDMI_L	HDMI_TG_BASE(0x0090)
+#define HDMI_TG_FIELD_BOT_HDMI_H	HDMI_TG_BASE(0x0094)
+
+/*
+ * Bit definition part
+ */
+
+/* HDMI_INTC_CON */
+#define HDMI_INTC_EN_GLOBAL		(1 << 6)
+#define HDMI_INTC_EN_HPD_PLUG		(1 << 3)
+#define HDMI_INTC_EN_HPD_UNPLUG		(1 << 2)
+
+/* HDMI_INTC_FLAG */
+#define HDMI_INTC_FLAG_HPD_PLUG		(1 << 3)
+#define HDMI_INTC_FLAG_HPD_UNPLUG	(1 << 2)
+
+/* HDMI_PHY_RSTOUT */
+#define HDMI_PHY_SW_RSTOUT		(1 << 0)
+
+/* HDMI_CORE_RSTOUT */
+#define HDMI_CORE_SW_RSTOUT		(1 << 0)
+
+/* HDMI_CON_0 */
+#define HDMI_BLUE_SCR_EN		(1 << 5)
+#define HDMI_EN				(1 << 0)
+
+/* HDMI_CON_2 */
+#define HDMI_DVI_PERAMBLE_EN		(1 << 5)
+#define HDMI_DVI_BAND_EN		(1 << 1)
+
+/* HDMI_PHY_STATUS */
+#define HDMI_PHY_STATUS_READY		(1 << 0)
+
+/* HDMI_MODE_SEL */
+#define HDMI_MODE_HDMI_EN		(1 << 1)
+#define HDMI_MODE_DVI_EN		(1 << 0)
+#define HDMI_MODE_MASK			(3 << 0)
+
+/* HDMI_TG_CMD */
+#define HDMI_TG_FIELD_EN		(1 << 1)
+#define HDMI_TG_EN			(1 << 0)
+
+#endif /* SAMSUNG_REGS_HDMI_H */
diff --git a/drivers/media/platform/s5p-tv/regs-mixer.h b/drivers/media/platform/s5p-tv/regs-mixer.h
new file mode 100644
index 0000000..158abb4
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/regs-mixer.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Mixer register header file for Samsung Mixer driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+#ifndef SAMSUNG_REGS_MIXER_H
+#define SAMSUNG_REGS_MIXER_H
+
+/*
+ * Register part
+ */
+#define MXR_STATUS			0x0000
+#define MXR_CFG				0x0004
+#define MXR_INT_EN			0x0008
+#define MXR_INT_STATUS			0x000C
+#define MXR_LAYER_CFG			0x0010
+#define MXR_VIDEO_CFG			0x0014
+#define MXR_GRAPHIC0_CFG		0x0020
+#define MXR_GRAPHIC0_BASE		0x0024
+#define MXR_GRAPHIC0_SPAN		0x0028
+#define MXR_GRAPHIC0_SXY		0x002C
+#define MXR_GRAPHIC0_WH			0x0030
+#define MXR_GRAPHIC0_DXY		0x0034
+#define MXR_GRAPHIC0_BLANK		0x0038
+#define MXR_GRAPHIC1_CFG		0x0040
+#define MXR_GRAPHIC1_BASE		0x0044
+#define MXR_GRAPHIC1_SPAN		0x0048
+#define MXR_GRAPHIC1_SXY		0x004C
+#define MXR_GRAPHIC1_WH			0x0050
+#define MXR_GRAPHIC1_DXY		0x0054
+#define MXR_GRAPHIC1_BLANK		0x0058
+#define MXR_BG_CFG			0x0060
+#define MXR_BG_COLOR0			0x0064
+#define MXR_BG_COLOR1			0x0068
+#define MXR_BG_COLOR2			0x006C
+
+/* for parametrized access to layer registers */
+#define MXR_GRAPHIC_CFG(i)		(0x0020 + (i) * 0x20)
+#define MXR_GRAPHIC_BASE(i)		(0x0024 + (i) * 0x20)
+#define MXR_GRAPHIC_SPAN(i)		(0x0028 + (i) * 0x20)
+#define MXR_GRAPHIC_SXY(i)		(0x002C + (i) * 0x20)
+#define MXR_GRAPHIC_WH(i)		(0x0030 + (i) * 0x20)
+#define MXR_GRAPHIC_DXY(i)		(0x0034 + (i) * 0x20)
+
+/*
+ * Bit definition part
+ */
+
+/* generates mask for range of bits */
+#define MXR_MASK(high_bit, low_bit) \
+	(((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
+
+#define MXR_MASK_VAL(val, high_bit, low_bit) \
+	(((val) << (low_bit)) & MXR_MASK(high_bit, low_bit))
+
+/* bits for MXR_STATUS */
+#define MXR_STATUS_16_BURST		(1 << 7)
+#define MXR_STATUS_BURST_MASK		(1 << 7)
+#define MXR_STATUS_SYNC_ENABLE		(1 << 2)
+#define MXR_STATUS_REG_RUN		(1 << 0)
+
+/* bits for MXR_CFG */
+#define MXR_CFG_OUT_YUV444		(0 << 8)
+#define MXR_CFG_OUT_RGB888		(1 << 8)
+#define MXR_CFG_OUT_MASK		(1 << 8)
+#define MXR_CFG_DST_SDO			(0 << 7)
+#define MXR_CFG_DST_HDMI		(1 << 7)
+#define MXR_CFG_DST_MASK		(1 << 7)
+#define MXR_CFG_SCAN_HD_720		(0 << 6)
+#define MXR_CFG_SCAN_HD_1080		(1 << 6)
+#define MXR_CFG_GRP1_ENABLE		(1 << 5)
+#define MXR_CFG_GRP0_ENABLE		(1 << 4)
+#define MXR_CFG_VP_ENABLE		(1 << 3)
+#define MXR_CFG_SCAN_INTERLACE		(0 << 2)
+#define MXR_CFG_SCAN_PROGRASSIVE	(1 << 2)
+#define MXR_CFG_SCAN_NTSC		(0 << 1)
+#define MXR_CFG_SCAN_PAL		(1 << 1)
+#define MXR_CFG_SCAN_SD			(0 << 0)
+#define MXR_CFG_SCAN_HD			(1 << 0)
+#define MXR_CFG_SCAN_MASK		0x47
+
+/* bits for MXR_GRAPHICn_CFG */
+#define MXR_GRP_CFG_COLOR_KEY_DISABLE	(1 << 21)
+#define MXR_GRP_CFG_BLEND_PRE_MUL	(1 << 20)
+#define MXR_GRP_CFG_FORMAT_VAL(x)	MXR_MASK_VAL(x, 11, 8)
+#define MXR_GRP_CFG_FORMAT_MASK		MXR_GRP_CFG_FORMAT_VAL(~0)
+#define MXR_GRP_CFG_ALPHA_VAL(x)	MXR_MASK_VAL(x, 7, 0)
+
+/* bits for MXR_GRAPHICn_WH */
+#define MXR_GRP_WH_H_SCALE(x)		MXR_MASK_VAL(x, 28, 28)
+#define MXR_GRP_WH_V_SCALE(x)		MXR_MASK_VAL(x, 12, 12)
+#define MXR_GRP_WH_WIDTH(x)		MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_WH_HEIGHT(x)		MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_GRAPHICn_SXY */
+#define MXR_GRP_SXY_SX(x)		MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_SXY_SY(x)		MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_GRAPHICn_DXY */
+#define MXR_GRP_DXY_DX(x)		MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_DXY_DY(x)		MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_INT_EN */
+#define MXR_INT_EN_VSYNC		(1 << 11)
+#define MXR_INT_EN_ALL			(0x0f << 8)
+
+/* bit for MXR_INT_STATUS */
+#define MXR_INT_CLEAR_VSYNC		(1 << 11)
+#define MXR_INT_STATUS_VSYNC		(1 << 0)
+
+/* bit for MXR_LAYER_CFG */
+#define MXR_LAYER_CFG_GRP1_VAL(x)	MXR_MASK_VAL(x, 11, 8)
+#define MXR_LAYER_CFG_GRP0_VAL(x)	MXR_MASK_VAL(x, 7, 4)
+#define MXR_LAYER_CFG_VP_VAL(x)		MXR_MASK_VAL(x, 3, 0)
+
+#endif /* SAMSUNG_REGS_MIXER_H */
+
diff --git a/drivers/media/platform/s5p-tv/regs-sdo.h b/drivers/media/platform/s5p-tv/regs-sdo.h
new file mode 100644
index 0000000..6f22fbf
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/regs-sdo.h
@@ -0,0 +1,63 @@
+/* drivers/media/platform/s5p-tv/regs-sdo.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * SDO register description file
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SAMSUNG_REGS_SDO_H
+#define SAMSUNG_REGS_SDO_H
+
+/*
+ * Register part
+ */
+
+#define SDO_CLKCON			0x0000
+#define SDO_CONFIG			0x0008
+#define SDO_VBI				0x0014
+#define SDO_DAC				0x003C
+#define SDO_CCCON			0x0180
+#define SDO_IRQ				0x0280
+#define SDO_IRQMASK			0x0284
+#define SDO_VERSION			0x03D8
+
+/*
+ * Bit definition part
+ */
+
+/* SDO Clock Control Register (SDO_CLKCON) */
+#define SDO_TVOUT_SW_RESET		(1 << 4)
+#define SDO_TVOUT_CLOCK_READY		(1 << 1)
+#define SDO_TVOUT_CLOCK_ON		(1 << 0)
+
+/* SDO Video Standard Configuration Register (SDO_CONFIG) */
+#define SDO_PROGRESSIVE			(1 << 4)
+#define SDO_NTSC_M			0
+#define SDO_PAL_M			1
+#define SDO_PAL_BGHID			2
+#define SDO_PAL_N			3
+#define SDO_PAL_NC			4
+#define SDO_NTSC_443			8
+#define SDO_PAL_60			9
+#define SDO_STANDARD_MASK		0xf
+
+/* SDO VBI Configuration Register (SDO_VBI) */
+#define SDO_CVBS_WSS_INS		(1 << 14)
+#define SDO_CVBS_CLOSED_CAPTION_MASK	(3 << 12)
+
+/* SDO DAC Configuration Register (SDO_DAC) */
+#define SDO_POWER_ON_DAC		(1 << 0)
+
+/* SDO Color Compensation On/Off Control (SDO_CCCON) */
+#define SDO_COMPENSATION_BHS_ADJ_OFF	(1 << 4)
+#define SDO_COMPENSATION_CVBS_COMP_OFF	(1 << 0)
+
+/* SDO Interrupt Request Register (SDO_IRQ) */
+#define SDO_VSYNC_IRQ_PEND		(1 << 0)
+
+#endif /* SAMSUNG_REGS_SDO_H */
diff --git a/drivers/media/platform/s5p-tv/regs-vp.h b/drivers/media/platform/s5p-tv/regs-vp.h
new file mode 100644
index 0000000..6c63984
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/regs-vp.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * Video processor register header file for Samsung Mixer driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SAMSUNG_REGS_VP_H
+#define SAMSUNG_REGS_VP_H
+
+/*
+ * Register part
+ */
+
+#define VP_ENABLE			0x0000
+#define VP_SRESET			0x0004
+#define VP_SHADOW_UPDATE		0x0008
+#define VP_FIELD_ID			0x000C
+#define VP_MODE				0x0010
+#define VP_IMG_SIZE_Y			0x0014
+#define VP_IMG_SIZE_C			0x0018
+#define VP_PER_RATE_CTRL		0x001C
+#define VP_TOP_Y_PTR			0x0028
+#define VP_BOT_Y_PTR			0x002C
+#define VP_TOP_C_PTR			0x0030
+#define VP_BOT_C_PTR			0x0034
+#define VP_ENDIAN_MODE			0x03CC
+#define VP_SRC_H_POSITION		0x0044
+#define VP_SRC_V_POSITION		0x0048
+#define VP_SRC_WIDTH			0x004C
+#define VP_SRC_HEIGHT			0x0050
+#define VP_DST_H_POSITION		0x0054
+#define VP_DST_V_POSITION		0x0058
+#define VP_DST_WIDTH			0x005C
+#define VP_DST_HEIGHT			0x0060
+#define VP_H_RATIO			0x0064
+#define VP_V_RATIO			0x0068
+#define VP_POLY8_Y0_LL			0x006C
+#define VP_POLY4_Y0_LL			0x00EC
+#define VP_POLY4_C0_LL			0x012C
+
+/*
+ * Bit definition part
+ */
+
+/* generates mask for range of bits */
+
+#define VP_MASK(high_bit, low_bit) \
+	(((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
+
+#define VP_MASK_VAL(val, high_bit, low_bit) \
+	(((val) << (low_bit)) & VP_MASK(high_bit, low_bit))
+
+ /* VP_ENABLE */
+#define VP_ENABLE_ON			(1 << 0)
+
+/* VP_SRESET */
+#define VP_SRESET_PROCESSING		(1 << 0)
+
+/* VP_SHADOW_UPDATE */
+#define VP_SHADOW_UPDATE_ENABLE		(1 << 0)
+
+/* VP_MODE */
+#define VP_MODE_NV12			(0 << 6)
+#define VP_MODE_NV21			(1 << 6)
+#define VP_MODE_LINE_SKIP		(1 << 5)
+#define VP_MODE_MEM_LINEAR		(0 << 4)
+#define VP_MODE_MEM_TILED		(1 << 4)
+#define VP_MODE_FMT_MASK		(5 << 4)
+#define VP_MODE_FIELD_ID_AUTO_TOGGLING	(1 << 2)
+#define VP_MODE_2D_IPC			(1 << 1)
+
+/* VP_IMG_SIZE_Y */
+/* VP_IMG_SIZE_C */
+#define VP_IMG_HSIZE(x)			VP_MASK_VAL(x, 29, 16)
+#define VP_IMG_VSIZE(x)			VP_MASK_VAL(x, 13, 0)
+
+/* VP_SRC_H_POSITION */
+#define VP_SRC_H_POSITION_VAL(x)	VP_MASK_VAL(x, 14, 4)
+
+/* VP_ENDIAN_MODE */
+#define VP_ENDIAN_MODE_LITTLE		(1 << 0)
+
+#endif /* SAMSUNG_REGS_VP_H */
diff --git a/drivers/media/platform/s5p-tv/sdo_drv.c b/drivers/media/platform/s5p-tv/sdo_drv.c
new file mode 100644
index 0000000..ad68bbe
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/sdo_drv.c
@@ -0,0 +1,448 @@
+/*
+ * Samsung Standard Definition Output (SDO) driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-subdev.h>
+
+#include "regs-sdo.h"
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung Standard Definition Output (SDO)");
+MODULE_LICENSE("GPL");
+
+#define SDO_DEFAULT_STD	V4L2_STD_PAL
+
+struct sdo_format {
+	v4l2_std_id id;
+	/* all modes are 720 pixels wide */
+	unsigned int height;
+	unsigned int cookie;
+};
+
+struct sdo_device {
+	/** pointer to device parent */
+	struct device *dev;
+	/** base address of SDO registers */
+	void __iomem *regs;
+	/** SDO interrupt */
+	unsigned int irq;
+	/** DAC source clock */
+	struct clk *sclk_dac;
+	/** DAC clock */
+	struct clk *dac;
+	/** DAC physical interface */
+	struct clk *dacphy;
+	/** clock for control of VPLL */
+	struct clk *fout_vpll;
+	/** regulator for SDO IP power */
+	struct regulator *vdac;
+	/** regulator for SDO plug detection */
+	struct regulator *vdet;
+	/** subdev used as device interface */
+	struct v4l2_subdev sd;
+	/** current format */
+	const struct sdo_format *fmt;
+};
+
+static inline struct sdo_device *sd_to_sdev(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct sdo_device, sd);
+}
+
+static inline
+void sdo_write_mask(struct sdo_device *sdev, u32 reg_id, u32 value, u32 mask)
+{
+	u32 old = readl(sdev->regs + reg_id);
+	value = (value & mask) | (old & ~mask);
+	writel(value, sdev->regs + reg_id);
+}
+
+static inline
+void sdo_write(struct sdo_device *sdev, u32 reg_id, u32 value)
+{
+	writel(value, sdev->regs + reg_id);
+}
+
+static inline
+u32 sdo_read(struct sdo_device *sdev, u32 reg_id)
+{
+	return readl(sdev->regs + reg_id);
+}
+
+static irqreturn_t sdo_irq_handler(int irq, void *dev_data)
+{
+	struct sdo_device *sdev = dev_data;
+
+	/* clear interrupt */
+	sdo_write_mask(sdev, SDO_IRQ, ~0, SDO_VSYNC_IRQ_PEND);
+	return IRQ_HANDLED;
+}
+
+static void sdo_reg_debug(struct sdo_device *sdev)
+{
+#define DBGREG(reg_id) \
+	dev_info(sdev->dev, #reg_id " = %08x\n", \
+		sdo_read(sdev, reg_id))
+
+	DBGREG(SDO_CLKCON);
+	DBGREG(SDO_CONFIG);
+	DBGREG(SDO_VBI);
+	DBGREG(SDO_DAC);
+	DBGREG(SDO_IRQ);
+	DBGREG(SDO_IRQMASK);
+	DBGREG(SDO_VERSION);
+}
+
+static const struct sdo_format sdo_format[] = {
+	{ V4L2_STD_PAL_N,	.height = 576, .cookie = SDO_PAL_N },
+	{ V4L2_STD_PAL_Nc,	.height = 576, .cookie = SDO_PAL_NC },
+	{ V4L2_STD_PAL_M,	.height = 480, .cookie = SDO_PAL_M },
+	{ V4L2_STD_PAL_60,	.height = 480, .cookie = SDO_PAL_60 },
+	{ V4L2_STD_NTSC_443,	.height = 480, .cookie = SDO_NTSC_443 },
+	{ V4L2_STD_PAL,		.height = 576, .cookie = SDO_PAL_BGHID },
+	{ V4L2_STD_NTSC_M,	.height = 480, .cookie = SDO_NTSC_M },
+};
+
+static const struct sdo_format *sdo_find_format(v4l2_std_id id)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(sdo_format); ++i)
+		if (sdo_format[i].id & id)
+			return &sdo_format[i];
+	return NULL;
+}
+
+static int sdo_g_tvnorms_output(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	*std = V4L2_STD_NTSC_M | V4L2_STD_PAL_M | V4L2_STD_PAL |
+		V4L2_STD_PAL_N | V4L2_STD_PAL_Nc |
+		V4L2_STD_NTSC_443 | V4L2_STD_PAL_60;
+	return 0;
+}
+
+static int sdo_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct sdo_device *sdev = sd_to_sdev(sd);
+	const struct sdo_format *fmt;
+	fmt = sdo_find_format(std);
+	if (fmt == NULL)
+		return -EINVAL;
+	sdev->fmt = fmt;
+	return 0;
+}
+
+static int sdo_g_std_output(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	*std = sd_to_sdev(sd)->fmt->id;
+	return 0;
+}
+
+static int sdo_g_mbus_fmt(struct v4l2_subdev *sd,
+	struct v4l2_mbus_framefmt *fmt)
+{
+	struct sdo_device *sdev = sd_to_sdev(sd);
+
+	if (!sdev->fmt)
+		return -ENXIO;
+	/* all modes are 720 pixels wide */
+	fmt->width = 720;
+	fmt->height = sdev->fmt->height;
+	fmt->code = V4L2_MBUS_FMT_FIXED;
+	fmt->field = V4L2_FIELD_INTERLACED;
+	fmt->colorspace = V4L2_COLORSPACE_JPEG;
+	return 0;
+}
+
+static int sdo_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct sdo_device *sdev = sd_to_sdev(sd);
+	struct device *dev = sdev->dev;
+	int ret;
+
+	dev_info(dev, "sdo_s_power(%d)\n", on);
+
+	if (on)
+		ret = pm_runtime_get_sync(dev);
+	else
+		ret = pm_runtime_put_sync(dev);
+
+	/* only values < 0 indicate errors */
+	return IS_ERR_VALUE(ret) ? ret : 0;
+}
+
+static int sdo_streamon(struct sdo_device *sdev)
+{
+	/* set proper clock for Timing Generator */
+	clk_set_rate(sdev->fout_vpll, 54000000);
+	dev_info(sdev->dev, "fout_vpll.rate = %lu\n",
+	clk_get_rate(sdev->fout_vpll));
+	/* enable clock in SDO */
+	sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON);
+	clk_enable(sdev->dacphy);
+	/* enable DAC */
+	sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC);
+	sdo_reg_debug(sdev);
+	return 0;
+}
+
+static int sdo_streamoff(struct sdo_device *sdev)
+{
+	int tries;
+
+	sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC);
+	clk_disable(sdev->dacphy);
+	sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON);
+	for (tries = 100; tries; --tries) {
+		if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY)
+			break;
+		mdelay(1);
+	}
+	if (tries == 0)
+		dev_err(sdev->dev, "failed to stop streaming\n");
+	return tries ? 0 : -EIO;
+}
+
+static int sdo_s_stream(struct v4l2_subdev *sd, int on)
+{
+	struct sdo_device *sdev = sd_to_sdev(sd);
+	return on ? sdo_streamon(sdev) : sdo_streamoff(sdev);
+}
+
+static const struct v4l2_subdev_core_ops sdo_sd_core_ops = {
+	.s_power = sdo_s_power,
+};
+
+static const struct v4l2_subdev_video_ops sdo_sd_video_ops = {
+	.s_std_output = sdo_s_std_output,
+	.g_std_output = sdo_g_std_output,
+	.g_tvnorms_output = sdo_g_tvnorms_output,
+	.g_mbus_fmt = sdo_g_mbus_fmt,
+	.s_stream = sdo_s_stream,
+};
+
+static const struct v4l2_subdev_ops sdo_sd_ops = {
+	.core = &sdo_sd_core_ops,
+	.video = &sdo_sd_video_ops,
+};
+
+static int sdo_runtime_suspend(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct sdo_device *sdev = sd_to_sdev(sd);
+
+	dev_info(dev, "suspend\n");
+	regulator_disable(sdev->vdet);
+	regulator_disable(sdev->vdac);
+	clk_disable(sdev->sclk_dac);
+	return 0;
+}
+
+static int sdo_runtime_resume(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct sdo_device *sdev = sd_to_sdev(sd);
+
+	dev_info(dev, "resume\n");
+	clk_enable(sdev->sclk_dac);
+	regulator_enable(sdev->vdac);
+	regulator_enable(sdev->vdet);
+
+	/* software reset */
+	sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_SW_RESET);
+	mdelay(10);
+	sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_SW_RESET);
+
+	/* setting TV mode */
+	sdo_write_mask(sdev, SDO_CONFIG, sdev->fmt->cookie, SDO_STANDARD_MASK);
+	/* XXX: forcing interlaced mode using undocumented bit */
+	sdo_write_mask(sdev, SDO_CONFIG, 0, SDO_PROGRESSIVE);
+	/* turn all VBI off */
+	sdo_write_mask(sdev, SDO_VBI, 0, SDO_CVBS_WSS_INS |
+		SDO_CVBS_CLOSED_CAPTION_MASK);
+	/* turn all post processing off */
+	sdo_write_mask(sdev, SDO_CCCON, ~0, SDO_COMPENSATION_BHS_ADJ_OFF |
+		SDO_COMPENSATION_CVBS_COMP_OFF);
+	sdo_reg_debug(sdev);
+	return 0;
+}
+
+static const struct dev_pm_ops sdo_pm_ops = {
+	.runtime_suspend = sdo_runtime_suspend,
+	.runtime_resume	 = sdo_runtime_resume,
+};
+
+static int __devinit sdo_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct sdo_device *sdev;
+	struct resource *res;
+	int ret = 0;
+	struct clk *sclk_vpll;
+
+	dev_info(dev, "probe start\n");
+	sdev = devm_kzalloc(&pdev->dev, sizeof *sdev, GFP_KERNEL);
+	if (!sdev) {
+		dev_err(dev, "not enough memory.\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+	sdev->dev = dev;
+
+	/* mapping registers */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(dev, "get memory resource failed.\n");
+		ret = -ENXIO;
+		goto fail;
+	}
+
+	sdev->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (sdev->regs == NULL) {
+		dev_err(dev, "register mapping failed.\n");
+		ret = -ENXIO;
+		goto fail;
+	}
+
+	/* acquiring interrupt */
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res == NULL) {
+		dev_err(dev, "get interrupt resource failed.\n");
+		ret = -ENXIO;
+		goto fail;
+	}
+	ret = devm_request_irq(&pdev->dev, res->start, sdo_irq_handler, 0,
+			       "s5p-sdo", sdev);
+	if (ret) {
+		dev_err(dev, "request interrupt failed.\n");
+		goto fail;
+	}
+	sdev->irq = res->start;
+
+	/* acquire clocks */
+	sdev->sclk_dac = clk_get(dev, "sclk_dac");
+	if (IS_ERR_OR_NULL(sdev->sclk_dac)) {
+		dev_err(dev, "failed to get clock 'sclk_dac'\n");
+		ret = -ENXIO;
+		goto fail;
+	}
+	sdev->dac = clk_get(dev, "dac");
+	if (IS_ERR_OR_NULL(sdev->dac)) {
+		dev_err(dev, "failed to get clock 'dac'\n");
+		ret = -ENXIO;
+		goto fail_sclk_dac;
+	}
+	sdev->dacphy = clk_get(dev, "dacphy");
+	if (IS_ERR_OR_NULL(sdev->dacphy)) {
+		dev_err(dev, "failed to get clock 'dacphy'\n");
+		ret = -ENXIO;
+		goto fail_dac;
+	}
+	sclk_vpll = clk_get(dev, "sclk_vpll");
+	if (IS_ERR_OR_NULL(sclk_vpll)) {
+		dev_err(dev, "failed to get clock 'sclk_vpll'\n");
+		ret = -ENXIO;
+		goto fail_dacphy;
+	}
+	clk_set_parent(sdev->sclk_dac, sclk_vpll);
+	clk_put(sclk_vpll);
+	sdev->fout_vpll = clk_get(dev, "fout_vpll");
+	if (IS_ERR_OR_NULL(sdev->fout_vpll)) {
+		dev_err(dev, "failed to get clock 'fout_vpll'\n");
+		goto fail_dacphy;
+	}
+	dev_info(dev, "fout_vpll.rate = %lu\n", clk_get_rate(sclk_vpll));
+
+	/* acquire regulator */
+	sdev->vdac = devm_regulator_get(dev, "vdd33a_dac");
+	if (IS_ERR_OR_NULL(sdev->vdac)) {
+		dev_err(dev, "failed to get regulator 'vdac'\n");
+		goto fail_fout_vpll;
+	}
+	sdev->vdet = devm_regulator_get(dev, "vdet");
+	if (IS_ERR_OR_NULL(sdev->vdet)) {
+		dev_err(dev, "failed to get regulator 'vdet'\n");
+		goto fail_fout_vpll;
+	}
+
+	/* enable gate for dac clock, because mixer uses it */
+	clk_enable(sdev->dac);
+
+	/* configure power management */
+	pm_runtime_enable(dev);
+
+	/* configuration of interface subdevice */
+	v4l2_subdev_init(&sdev->sd, &sdo_sd_ops);
+	sdev->sd.owner = THIS_MODULE;
+	strlcpy(sdev->sd.name, "s5p-sdo", sizeof sdev->sd.name);
+
+	/* set default format */
+	sdev->fmt = sdo_find_format(SDO_DEFAULT_STD);
+	BUG_ON(sdev->fmt == NULL);
+
+	/* keeping subdev in device's private for use by other drivers */
+	dev_set_drvdata(dev, &sdev->sd);
+
+	dev_info(dev, "probe succeeded\n");
+	return 0;
+
+fail_fout_vpll:
+	clk_put(sdev->fout_vpll);
+fail_dacphy:
+	clk_put(sdev->dacphy);
+fail_dac:
+	clk_put(sdev->dac);
+fail_sclk_dac:
+	clk_put(sdev->sclk_dac);
+fail:
+	dev_info(dev, "probe failed\n");
+	return ret;
+}
+
+static int __devexit sdo_remove(struct platform_device *pdev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev);
+	struct sdo_device *sdev = sd_to_sdev(sd);
+
+	pm_runtime_disable(&pdev->dev);
+	clk_disable(sdev->dac);
+	clk_put(sdev->fout_vpll);
+	clk_put(sdev->dacphy);
+	clk_put(sdev->dac);
+	clk_put(sdev->sclk_dac);
+
+	dev_info(&pdev->dev, "remove successful\n");
+	return 0;
+}
+
+static struct platform_driver sdo_driver __refdata = {
+	.probe = sdo_probe,
+	.remove = __devexit_p(sdo_remove),
+	.driver = {
+		.name = "s5p-sdo",
+		.owner = THIS_MODULE,
+		.pm = &sdo_pm_ops,
+	}
+};
+
+module_platform_driver(sdo_driver);
diff --git a/drivers/media/platform/s5p-tv/sii9234_drv.c b/drivers/media/platform/s5p-tv/sii9234_drv.c
new file mode 100644
index 0000000..716d484
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/sii9234_drv.c
@@ -0,0 +1,413 @@
+/*
+ * Samsung MHL interface driver
+ *
+ * Copyright (C) 2011 Samsung Electronics Co.Ltd
+ * Author: Tomasz Stanislawski <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/freezer.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/machine.h>
+#include <linux/slab.h>
+
+#include <mach/gpio.h>
+#include <plat/gpio-cfg.h>
+
+#include <media/sii9234.h>
+#include <media/v4l2-subdev.h>
+
+MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung MHL interface driver");
+MODULE_LICENSE("GPL");
+
+struct sii9234_context {
+	struct i2c_client *client;
+	struct regulator *power;
+	int gpio_n_reset;
+	struct v4l2_subdev sd;
+};
+
+static inline struct sii9234_context *sd_to_context(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct sii9234_context, sd);
+}
+
+static inline int sii9234_readb(struct i2c_client *client, int addr)
+{
+	return i2c_smbus_read_byte_data(client, addr);
+}
+
+static inline int sii9234_writeb(struct i2c_client *client, int addr, int value)
+{
+	return i2c_smbus_write_byte_data(client, addr, value);
+}
+
+static inline int sii9234_writeb_mask(struct i2c_client *client, int addr,
+	int value, int mask)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, addr);
+	if (ret < 0)
+		return ret;
+	ret = (ret & ~mask) | (value & mask);
+	return i2c_smbus_write_byte_data(client, addr, ret);
+}
+
+static inline int sii9234_readb_idx(struct i2c_client *client, int addr)
+{
+	int ret;
+	ret = i2c_smbus_write_byte_data(client, 0xbc, addr >> 8);
+	if (ret < 0)
+		return ret;
+	ret = i2c_smbus_write_byte_data(client, 0xbd, addr & 0xff);
+	if (ret < 0)
+		return ret;
+	return i2c_smbus_read_byte_data(client, 0xbe);
+}
+
+static inline int sii9234_writeb_idx(struct i2c_client *client, int addr,
+	int value)
+{
+	int ret;
+	ret = i2c_smbus_write_byte_data(client, 0xbc, addr >> 8);
+	if (ret < 0)
+		return ret;
+	ret = i2c_smbus_write_byte_data(client, 0xbd, addr & 0xff);
+	if (ret < 0)
+		return ret;
+	ret = i2c_smbus_write_byte_data(client, 0xbe, value);
+	return ret;
+}
+
+static inline int sii9234_writeb_idx_mask(struct i2c_client *client, int addr,
+	int value, int mask)
+{
+	int ret;
+
+	ret = sii9234_readb_idx(client, addr);
+	if (ret < 0)
+		return ret;
+	ret = (ret & ~mask) | (value & mask);
+	return sii9234_writeb_idx(client, addr, ret);
+}
+
+static int sii9234_reset(struct sii9234_context *ctx)
+{
+	struct i2c_client *client = ctx->client;
+	struct device *dev = &client->dev;
+	int ret, tries;
+
+	gpio_direction_output(ctx->gpio_n_reset, 1);
+	mdelay(1);
+	gpio_direction_output(ctx->gpio_n_reset, 0);
+	mdelay(1);
+	gpio_direction_output(ctx->gpio_n_reset, 1);
+	mdelay(1);
+
+	/* going to TTPI mode */
+	ret = sii9234_writeb(client, 0xc7, 0);
+	if (ret < 0) {
+		dev_err(dev, "failed to set TTPI mode\n");
+		return ret;
+	}
+	for (tries = 0; tries < 100 ; ++tries) {
+		ret = sii9234_readb(client, 0x1b);
+		if (ret > 0)
+			break;
+		if (ret < 0) {
+			dev_err(dev, "failed to reset device\n");
+			return -EIO;
+		}
+		mdelay(1);
+	}
+	if (tries == 100) {
+		dev_err(dev, "maximal number of tries reached\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int sii9234_verify_version(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	int family, rev, tpi_rev, dev_id, sub_id, hdcp, id;
+
+	family = sii9234_readb(client, 0x1b);
+	rev = sii9234_readb(client, 0x1c) & 0x0f;
+	tpi_rev = sii9234_readb(client, 0x1d) & 0x7f;
+	dev_id = sii9234_readb_idx(client, 0x0103);
+	sub_id = sii9234_readb_idx(client, 0x0102);
+	hdcp = sii9234_readb(client, 0x30);
+
+	if (family < 0 || rev < 0 || tpi_rev < 0 || dev_id < 0 ||
+		sub_id < 0 || hdcp < 0) {
+		dev_err(dev, "failed to read chip's version\n");
+		return -EIO;
+	}
+
+	id = (dev_id << 8) | sub_id;
+
+	dev_info(dev, "chip: SiL%02x family: %02x, rev: %02x\n",
+		id, family, rev);
+	dev_info(dev, "tpi_rev:%02x, hdcp: %02x\n", tpi_rev, hdcp);
+	if (id != 0x9234) {
+		dev_err(dev, "not supported chip\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static u8 data[][3] = {
+/* setup from driver created by doonsoo45.kim */
+	{ 0x01, 0x05, 0x04 }, /* Enable Auto soft reset on SCDT = 0 */
+	{ 0x01, 0x08, 0x35 }, /* Power Up TMDS Tx Core */
+	{ 0x01, 0x0d, 0x1c }, /* HDMI Transcode mode enable */
+	{ 0x01, 0x2b, 0x01 }, /* Enable HDCP Compliance workaround */
+	{ 0x01, 0x79, 0x40 }, /* daniel test...MHL_INT */
+	{ 0x01, 0x80, 0x34 }, /* Enable Rx PLL Clock Value */
+	{ 0x01, 0x90, 0x27 }, /* Enable CBUS discovery */
+	{ 0x01, 0x91, 0xe5 }, /* Skip RGND detection */
+	{ 0x01, 0x92, 0x46 }, /* Force MHD mode */
+	{ 0x01, 0x93, 0xdc }, /* Disable CBUS pull-up during RGND measurement */
+	{ 0x01, 0x94, 0x66 }, /* 1.8V CBUS VTH & GND threshold */
+	{ 0x01, 0x95, 0x31 }, /* RGND block & single discovery attempt */
+	{ 0x01, 0x96, 0x22 }, /* use 1K and 2K setting */
+	{ 0x01, 0xa0, 0x10 }, /* SIMG: Term mode */
+	{ 0x01, 0xa1, 0xfc }, /* Disable internal Mobile HD driver */
+	{ 0x01, 0xa3, 0xfa }, /* SIMG: Output Swing  default EB, 3x Clk Mult */
+	{ 0x01, 0xa5, 0x80 }, /* SIMG: RGND Hysterisis, 3x mode for Beast */
+	{ 0x01, 0xa6, 0x0c }, /* SIMG: Swing Offset */
+	{ 0x02, 0x3d, 0x3f }, /* Power up CVCC 1.2V core */
+	{ 0x03, 0x00, 0x00 }, /* SIMG: correcting HW default */
+	{ 0x03, 0x11, 0x01 }, /* Enable TxPLL Clock */
+	{ 0x03, 0x12, 0x15 }, /* Enable Tx Clock Path & Equalizer */
+	{ 0x03, 0x13, 0x60 }, /* SIMG: Set termination value */
+	{ 0x03, 0x14, 0xf0 }, /* SIMG: Change CKDT level */
+	{ 0x03, 0x17, 0x07 }, /* SIMG: PLL Calrefsel */
+	{ 0x03, 0x1a, 0x20 }, /* VCO Cal */
+	{ 0x03, 0x22, 0xe0 }, /* SIMG: Auto EQ */
+	{ 0x03, 0x23, 0xc0 }, /* SIMG: Auto EQ */
+	{ 0x03, 0x24, 0xa0 }, /* SIMG: Auto EQ */
+	{ 0x03, 0x25, 0x80 }, /* SIMG: Auto EQ */
+	{ 0x03, 0x26, 0x60 }, /* SIMG: Auto EQ */
+	{ 0x03, 0x27, 0x40 }, /* SIMG: Auto EQ */
+	{ 0x03, 0x28, 0x20 }, /* SIMG: Auto EQ */
+	{ 0x03, 0x29, 0x00 }, /* SIMG: Auto EQ */
+	{ 0x03, 0x31, 0x0b }, /* SIMG: Rx PLL BW value from I2C BW ~ 4MHz */
+	{ 0x03, 0x45, 0x06 }, /* SIMG: DPLL Mode */
+	{ 0x03, 0x4b, 0x06 }, /* SIMG: Correcting HW default */
+	{ 0x03, 0x4c, 0xa0 }, /* Manual zone control */
+	{ 0x03, 0x4d, 0x02 }, /* SIMG: PLL Mode Value (order is important) */
+};
+
+static int sii9234_set_internal(struct sii9234_context *ctx)
+{
+	struct i2c_client *client = ctx->client;
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(data); ++i) {
+		int addr = (data[i][0] << 8) | data[i][1];
+		ret = sii9234_writeb_idx(client, addr, data[i][2]);
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+static int sii9234_runtime_suspend(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct sii9234_context *ctx = sd_to_context(sd);
+	struct i2c_client *client = ctx->client;
+
+	dev_info(dev, "suspend start\n");
+
+	sii9234_writeb_mask(client, 0x1e, 3, 3);
+	regulator_disable(ctx->power);
+
+	return 0;
+}
+
+static int sii9234_runtime_resume(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct sii9234_context *ctx = sd_to_context(sd);
+	struct i2c_client *client = ctx->client;
+	int ret;
+
+	dev_info(dev, "resume start\n");
+	regulator_enable(ctx->power);
+
+	ret = sii9234_reset(ctx);
+	if (ret)
+		goto fail;
+
+	/* enable tpi */
+	ret = sii9234_writeb_mask(client, 0x1e, 1, 0);
+	if (ret < 0)
+		goto fail;
+	ret = sii9234_set_internal(ctx);
+	if (ret < 0)
+		goto fail;
+
+	return 0;
+
+fail:
+	dev_err(dev, "failed to resume\n");
+	regulator_disable(ctx->power);
+
+	return ret;
+}
+
+static const struct dev_pm_ops sii9234_pm_ops = {
+	.runtime_suspend = sii9234_runtime_suspend,
+	.runtime_resume	 = sii9234_runtime_resume,
+};
+
+static int sii9234_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct sii9234_context *ctx = sd_to_context(sd);
+	int ret;
+
+	if (on)
+		ret = pm_runtime_get_sync(&ctx->client->dev);
+	else
+		ret = pm_runtime_put(&ctx->client->dev);
+	/* only values < 0 indicate errors */
+	return IS_ERR_VALUE(ret) ? ret : 0;
+}
+
+static int sii9234_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct sii9234_context *ctx = sd_to_context(sd);
+
+	/* (dis/en)able TDMS output */
+	sii9234_writeb_mask(ctx->client, 0x1a, enable ? 0 : ~0 , 1 << 4);
+	return 0;
+}
+
+static const struct v4l2_subdev_core_ops sii9234_core_ops = {
+	.s_power =  sii9234_s_power,
+};
+
+static const struct v4l2_subdev_video_ops sii9234_video_ops = {
+	.s_stream =  sii9234_s_stream,
+};
+
+static const struct v4l2_subdev_ops sii9234_ops = {
+	.core = &sii9234_core_ops,
+	.video = &sii9234_video_ops,
+};
+
+static int __devinit sii9234_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct sii9234_platform_data *pdata = dev->platform_data;
+	struct sii9234_context *ctx;
+	int ret;
+
+	ctx = devm_kzalloc(&client->dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		dev_err(dev, "out of memory\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+	ctx->client = client;
+
+	ctx->power = devm_regulator_get(dev, "hdmi-en");
+	if (IS_ERR(ctx->power)) {
+		dev_err(dev, "failed to acquire regulator hdmi-en\n");
+		return PTR_ERR(ctx->power);
+	}
+
+	ctx->gpio_n_reset = pdata->gpio_n_reset;
+	ret = gpio_request(ctx->gpio_n_reset, "MHL_RST");
+	if (ret) {
+		dev_err(dev, "failed to acquire MHL_RST gpio\n");
+		return ret;
+	}
+
+	v4l2_i2c_subdev_init(&ctx->sd, client, &sii9234_ops);
+
+	pm_runtime_enable(dev);
+
+	/* enable device */
+	ret = pm_runtime_get_sync(dev);
+	if (ret)
+		goto fail_pm;
+
+	/* verify chip version */
+	ret = sii9234_verify_version(client);
+	if (ret)
+		goto fail_pm_get;
+
+	/* stop processing */
+	pm_runtime_put(dev);
+
+	dev_info(dev, "probe successful\n");
+
+	return 0;
+
+fail_pm_get:
+	pm_runtime_put_sync(dev);
+
+fail_pm:
+	pm_runtime_disable(dev);
+	gpio_free(ctx->gpio_n_reset);
+
+fail:
+	dev_err(dev, "probe failed\n");
+
+	return ret;
+}
+
+static int __devexit sii9234_remove(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct sii9234_context *ctx = sd_to_context(sd);
+
+	pm_runtime_disable(dev);
+	gpio_free(ctx->gpio_n_reset);
+
+	dev_info(dev, "remove successful\n");
+
+	return 0;
+}
+
+
+static const struct i2c_device_id sii9234_id[] = {
+	{ "SII9234", 0 },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(i2c, sii9234_id);
+static struct i2c_driver sii9234_driver = {
+	.driver = {
+		.name	= "sii9234",
+		.owner	= THIS_MODULE,
+		.pm = &sii9234_pm_ops,
+	},
+	.probe		= sii9234_probe,
+	.remove		= __devexit_p(sii9234_remove),
+	.id_table = sii9234_id,
+};
+
+module_i2c_driver(sii9234_driver);
diff --git a/drivers/media/platform/sh_mobile_ceu_camera.c b/drivers/media/platform/sh_mobile_ceu_camera.c
new file mode 100644
index 0000000..0baaf94
--- /dev/null
+++ b/drivers/media/platform/sh_mobile_ceu_camera.c
@@ -0,0 +1,2331 @@
+/*
+ * V4L2 Driver for SuperH Mobile CEU interface
+ *
+ * Copyright (C) 2008 Magnus Damm
+ *
+ * Based on V4L2 Driver for PXA camera host - "pxa_camera.c",
+ *
+ * Copyright (C) 2006, Sascha Hauer, Pengutronix
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <linux/pm_runtime.h>
+#include <linux/sched.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/soc_camera.h>
+#include <media/sh_mobile_ceu.h>
+#include <media/sh_mobile_csi2.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/v4l2-mediabus.h>
+#include <media/soc_mediabus.h>
+
+/* register offsets for sh7722 / sh7723 */
+
+#define CAPSR  0x00 /* Capture start register */
+#define CAPCR  0x04 /* Capture control register */
+#define CAMCR  0x08 /* Capture interface control register */
+#define CMCYR  0x0c /* Capture interface cycle  register */
+#define CAMOR  0x10 /* Capture interface offset register */
+#define CAPWR  0x14 /* Capture interface width register */
+#define CAIFR  0x18 /* Capture interface input format register */
+#define CSTCR  0x20 /* Camera strobe control register (<= sh7722) */
+#define CSECR  0x24 /* Camera strobe emission count register (<= sh7722) */
+#define CRCNTR 0x28 /* CEU register control register */
+#define CRCMPR 0x2c /* CEU register forcible control register */
+#define CFLCR  0x30 /* Capture filter control register */
+#define CFSZR  0x34 /* Capture filter size clip register */
+#define CDWDR  0x38 /* Capture destination width register */
+#define CDAYR  0x3c /* Capture data address Y register */
+#define CDACR  0x40 /* Capture data address C register */
+#define CDBYR  0x44 /* Capture data bottom-field address Y register */
+#define CDBCR  0x48 /* Capture data bottom-field address C register */
+#define CBDSR  0x4c /* Capture bundle destination size register */
+#define CFWCR  0x5c /* Firewall operation control register */
+#define CLFCR  0x60 /* Capture low-pass filter control register */
+#define CDOCR  0x64 /* Capture data output control register */
+#define CDDCR  0x68 /* Capture data complexity level register */
+#define CDDAR  0x6c /* Capture data complexity level address register */
+#define CEIER  0x70 /* Capture event interrupt enable register */
+#define CETCR  0x74 /* Capture event flag clear register */
+#define CSTSR  0x7c /* Capture status register */
+#define CSRTR  0x80 /* Capture software reset register */
+#define CDSSR  0x84 /* Capture data size register */
+#define CDAYR2 0x90 /* Capture data address Y register 2 */
+#define CDACR2 0x94 /* Capture data address C register 2 */
+#define CDBYR2 0x98 /* Capture data bottom-field address Y register 2 */
+#define CDBCR2 0x9c /* Capture data bottom-field address C register 2 */
+
+#undef DEBUG_GEOMETRY
+#ifdef DEBUG_GEOMETRY
+#define dev_geo	dev_info
+#else
+#define dev_geo	dev_dbg
+#endif
+
+/* per video frame buffer */
+struct sh_mobile_ceu_buffer {
+	struct vb2_buffer vb; /* v4l buffer must be first */
+	struct list_head queue;
+};
+
+struct sh_mobile_ceu_dev {
+	struct soc_camera_host ici;
+	struct soc_camera_device *icd;
+	struct platform_device *csi2_pdev;
+
+	unsigned int irq;
+	void __iomem *base;
+	size_t video_limit;
+	size_t buf_total;
+
+	spinlock_t lock;		/* Protects video buffer lists */
+	struct list_head capture;
+	struct vb2_buffer *active;
+	struct vb2_alloc_ctx *alloc_ctx;
+
+	struct sh_mobile_ceu_info *pdata;
+	struct completion complete;
+
+	u32 cflcr;
+
+	/* static max sizes either from platform data or default */
+	int max_width;
+	int max_height;
+
+	enum v4l2_field field;
+	int sequence;
+
+	unsigned int image_mode:1;
+	unsigned int is_16bit:1;
+	unsigned int frozen:1;
+};
+
+struct sh_mobile_ceu_cam {
+	/* CEU offsets within the camera output, before the CEU scaler */
+	unsigned int ceu_left;
+	unsigned int ceu_top;
+	/* Client output, as seen by the CEU */
+	unsigned int width;
+	unsigned int height;
+	/*
+	 * User window from S_CROP / G_CROP, produced by client cropping and
+	 * scaling, CEU scaling and CEU cropping, mapped back onto the client
+	 * input window
+	 */
+	struct v4l2_rect subrect;
+	/* Camera cropping rectangle */
+	struct v4l2_rect rect;
+	const struct soc_mbus_pixelfmt *extra_fmt;
+	enum v4l2_mbus_pixelcode code;
+};
+
+static struct sh_mobile_ceu_buffer *to_ceu_vb(struct vb2_buffer *vb)
+{
+	return container_of(vb, struct sh_mobile_ceu_buffer, vb);
+}
+
+static void ceu_write(struct sh_mobile_ceu_dev *priv,
+		      unsigned long reg_offs, u32 data)
+{
+	iowrite32(data, priv->base + reg_offs);
+}
+
+static u32 ceu_read(struct sh_mobile_ceu_dev *priv, unsigned long reg_offs)
+{
+	return ioread32(priv->base + reg_offs);
+}
+
+static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev)
+{
+	int i, success = 0;
+	struct soc_camera_device *icd = pcdev->icd;
+
+	ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
+
+	/* wait CSTSR.CPTON bit */
+	for (i = 0; i < 1000; i++) {
+		if (!(ceu_read(pcdev, CSTSR) & 1)) {
+			success++;
+			break;
+		}
+		udelay(1);
+	}
+
+	/* wait CAPSR.CPKIL bit */
+	for (i = 0; i < 1000; i++) {
+		if (!(ceu_read(pcdev, CAPSR) & (1 << 16))) {
+			success++;
+			break;
+		}
+		udelay(1);
+	}
+
+
+	if (2 != success) {
+		dev_warn(icd->pdev, "soft reset time out\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ *  Videobuf operations
+ */
+
+/*
+ * .queue_setup() is called to check, whether the driver can accept the
+ *		  requested number of buffers and to fill in plane sizes
+ *		  for the current frame format if required
+ */
+static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
+			const struct v4l2_format *fmt,
+			unsigned int *count, unsigned int *num_planes,
+			unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+
+	if (fmt) {
+		const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd,
+								fmt->fmt.pix.pixelformat);
+		unsigned int bytes_per_line;
+		int ret;
+
+		if (!xlate)
+			return -EINVAL;
+
+		ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
+					      xlate->host_fmt);
+		if (ret < 0)
+			return ret;
+
+		bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret);
+
+		ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line,
+					  fmt->fmt.pix.height);
+		if (ret < 0)
+			return ret;
+
+		sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret);
+	} else {
+		/* Called from VIDIOC_REQBUFS or in compatibility mode */
+		sizes[0] = icd->sizeimage;
+	}
+
+	alloc_ctxs[0] = pcdev->alloc_ctx;
+
+	if (!vq->num_buffers)
+		pcdev->sequence = 0;
+
+	if (!*count)
+		*count = 2;
+
+	/* If *num_planes != 0, we have already verified *count. */
+	if (pcdev->video_limit && !*num_planes) {
+		size_t size = PAGE_ALIGN(sizes[0]) * *count;
+
+		if (size + pcdev->buf_total > pcdev->video_limit)
+			*count = (pcdev->video_limit - pcdev->buf_total) /
+				PAGE_ALIGN(sizes[0]);
+	}
+
+	*num_planes = 1;
+
+	dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]);
+
+	return 0;
+}
+
+#define CEU_CETCR_MAGIC 0x0317f313 /* acknowledge magical interrupt sources */
+#define CEU_CETCR_IGRW (1 << 4) /* prohibited register access interrupt bit */
+#define CEU_CEIER_CPEIE (1 << 0) /* one-frame capture end interrupt */
+#define CEU_CEIER_VBP   (1 << 20) /* vbp error */
+#define CEU_CAPCR_CTNCP (1 << 16) /* continuous capture mode (if set) */
+#define CEU_CEIER_MASK (CEU_CEIER_CPEIE | CEU_CEIER_VBP)
+
+
+/*
+ * return value doesn't reflex the success/failure to queue the new buffer,
+ * but rather the status of the previous buffer.
+ */
+static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
+{
+	struct soc_camera_device *icd = pcdev->icd;
+	dma_addr_t phys_addr_top, phys_addr_bottom;
+	unsigned long top1, top2;
+	unsigned long bottom1, bottom2;
+	u32 status;
+	bool planar;
+	int ret = 0;
+
+	/*
+	 * The hardware is _very_ picky about this sequence. Especially
+	 * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge
+	 * several not-so-well documented interrupt sources in CETCR.
+	 */
+	ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~CEU_CEIER_MASK);
+	status = ceu_read(pcdev, CETCR);
+	ceu_write(pcdev, CETCR, ~status & CEU_CETCR_MAGIC);
+	if (!pcdev->frozen)
+		ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_MASK);
+	ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~CEU_CAPCR_CTNCP);
+	ceu_write(pcdev, CETCR, CEU_CETCR_MAGIC ^ CEU_CETCR_IGRW);
+
+	/*
+	 * When a VBP interrupt occurs, a capture end interrupt does not occur
+	 * and the image of that frame is not captured correctly. So, soft reset
+	 * is needed here.
+	 */
+	if (status & CEU_CEIER_VBP) {
+		sh_mobile_ceu_soft_reset(pcdev);
+		ret = -EIO;
+	}
+
+	if (pcdev->frozen) {
+		complete(&pcdev->complete);
+		return ret;
+	}
+
+	if (!pcdev->active)
+		return ret;
+
+	if (V4L2_FIELD_INTERLACED_BT == pcdev->field) {
+		top1	= CDBYR;
+		top2	= CDBCR;
+		bottom1	= CDAYR;
+		bottom2	= CDACR;
+	} else {
+		top1	= CDAYR;
+		top2	= CDACR;
+		bottom1	= CDBYR;
+		bottom2	= CDBCR;
+	}
+
+	phys_addr_top = vb2_dma_contig_plane_dma_addr(pcdev->active, 0);
+
+	switch (icd->current_fmt->host_fmt->fourcc) {
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
+		planar = true;
+		break;
+	default:
+		planar = false;
+	}
+
+	ceu_write(pcdev, top1, phys_addr_top);
+	if (V4L2_FIELD_NONE != pcdev->field) {
+		phys_addr_bottom = phys_addr_top + icd->bytesperline;
+		ceu_write(pcdev, bottom1, phys_addr_bottom);
+	}
+
+	if (planar) {
+		phys_addr_top += icd->bytesperline * icd->user_height;
+		ceu_write(pcdev, top2, phys_addr_top);
+		if (V4L2_FIELD_NONE != pcdev->field) {
+			phys_addr_bottom = phys_addr_top + icd->bytesperline;
+			ceu_write(pcdev, bottom2, phys_addr_bottom);
+		}
+	}
+
+	ceu_write(pcdev, CAPSR, 0x1); /* start capture */
+
+	return ret;
+}
+
+static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb)
+{
+	struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
+
+	/* Added list head initialization on alloc */
+	WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb);
+
+	return 0;
+}
+
+static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
+{
+	struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
+	unsigned long size;
+
+	size = icd->sizeimage;
+
+	if (vb2_plane_size(vb, 0) < size) {
+		dev_err(icd->parent, "Buffer #%d too small (%lu < %lu)\n",
+			vb->v4l2_buf.index, vb2_plane_size(vb, 0), size);
+		goto error;
+	}
+
+	vb2_set_plane_payload(vb, 0, size);
+
+	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+		vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
+
+#ifdef DEBUG
+	/*
+	 * This can be useful if you want to see if we actually fill
+	 * the buffer with something
+	 */
+	if (vb2_plane_vaddr(vb, 0))
+		memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0));
+#endif
+
+	spin_lock_irq(&pcdev->lock);
+	list_add_tail(&buf->queue, &pcdev->capture);
+
+	if (!pcdev->active) {
+		/*
+		 * Because there were no active buffer at this moment,
+		 * we are not interested in the return value of
+		 * sh_mobile_ceu_capture here.
+		 */
+		pcdev->active = vb;
+		sh_mobile_ceu_capture(pcdev);
+	}
+	spin_unlock_irq(&pcdev->lock);
+
+	return;
+
+error:
+	vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+}
+
+static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
+{
+	struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+
+	spin_lock_irq(&pcdev->lock);
+
+	if (pcdev->active == vb) {
+		/* disable capture (release DMA buffer), reset */
+		ceu_write(pcdev, CAPSR, 1 << 16);
+		pcdev->active = NULL;
+	}
+
+	/*
+	 * Doesn't hurt also if the list is empty, but it hurts, if queuing the
+	 * buffer failed, and .buf_init() hasn't been called
+	 */
+	if (buf->queue.next)
+		list_del_init(&buf->queue);
+
+	pcdev->buf_total -= PAGE_ALIGN(vb2_plane_size(vb, 0));
+	dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__,
+		pcdev->buf_total);
+
+	spin_unlock_irq(&pcdev->lock);
+}
+
+static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb)
+{
+	struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+
+	pcdev->buf_total += PAGE_ALIGN(vb2_plane_size(vb, 0));
+	dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__,
+		pcdev->buf_total);
+
+	/* This is for locking debugging only */
+	INIT_LIST_HEAD(&to_ceu_vb(vb)->queue);
+	return 0;
+}
+
+static int sh_mobile_ceu_stop_streaming(struct vb2_queue *q)
+{
+	struct soc_camera_device *icd = container_of(q, struct soc_camera_device, vb2_vidq);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	struct list_head *buf_head, *tmp;
+
+	spin_lock_irq(&pcdev->lock);
+
+	pcdev->active = NULL;
+
+	list_for_each_safe(buf_head, tmp, &pcdev->capture)
+		list_del_init(buf_head);
+
+	spin_unlock_irq(&pcdev->lock);
+
+	return sh_mobile_ceu_soft_reset(pcdev);
+}
+
+static struct vb2_ops sh_mobile_ceu_videobuf_ops = {
+	.queue_setup	= sh_mobile_ceu_videobuf_setup,
+	.buf_prepare	= sh_mobile_ceu_videobuf_prepare,
+	.buf_queue	= sh_mobile_ceu_videobuf_queue,
+	.buf_cleanup	= sh_mobile_ceu_videobuf_release,
+	.buf_init	= sh_mobile_ceu_videobuf_init,
+	.wait_prepare	= soc_camera_unlock,
+	.wait_finish	= soc_camera_lock,
+	.stop_streaming	= sh_mobile_ceu_stop_streaming,
+};
+
+static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
+{
+	struct sh_mobile_ceu_dev *pcdev = data;
+	struct vb2_buffer *vb;
+	int ret;
+
+	spin_lock(&pcdev->lock);
+
+	vb = pcdev->active;
+	if (!vb)
+		/* Stale interrupt from a released buffer */
+		goto out;
+
+	list_del_init(&to_ceu_vb(vb)->queue);
+
+	if (!list_empty(&pcdev->capture))
+		pcdev->active = &list_entry(pcdev->capture.next,
+					    struct sh_mobile_ceu_buffer, queue)->vb;
+	else
+		pcdev->active = NULL;
+
+	ret = sh_mobile_ceu_capture(pcdev);
+	do_gettimeofday(&vb->v4l2_buf.timestamp);
+	if (!ret) {
+		vb->v4l2_buf.field = pcdev->field;
+		vb->v4l2_buf.sequence = pcdev->sequence++;
+	}
+	vb2_buffer_done(vb, ret < 0 ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+
+out:
+	spin_unlock(&pcdev->lock);
+
+	return IRQ_HANDLED;
+}
+
+static struct v4l2_subdev *find_csi2(struct sh_mobile_ceu_dev *pcdev)
+{
+	struct v4l2_subdev *sd;
+
+	if (!pcdev->csi2_pdev)
+		return NULL;
+
+	v4l2_device_for_each_subdev(sd, &pcdev->ici.v4l2_dev)
+		if (&pcdev->csi2_pdev->dev == v4l2_get_subdevdata(sd))
+			return sd;
+
+	return NULL;
+}
+
+/* Called with .video_lock held */
+static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	struct v4l2_subdev *csi2_sd;
+	int ret;
+
+	if (pcdev->icd)
+		return -EBUSY;
+
+	dev_info(icd->parent,
+		 "SuperH Mobile CEU driver attached to camera %d\n",
+		 icd->devnum);
+
+	pm_runtime_get_sync(ici->v4l2_dev.dev);
+
+	pcdev->buf_total = 0;
+
+	ret = sh_mobile_ceu_soft_reset(pcdev);
+
+	csi2_sd = find_csi2(pcdev);
+	if (csi2_sd) {
+		csi2_sd->grp_id = soc_camera_grp_id(icd);
+		v4l2_set_subdev_hostdata(csi2_sd, icd);
+	}
+
+	ret = v4l2_subdev_call(csi2_sd, core, s_power, 1);
+	if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) {
+		pm_runtime_put_sync(ici->v4l2_dev.dev);
+		return ret;
+	}
+
+	/*
+	 * -ENODEV is special: either csi2_sd == NULL or the CSI-2 driver
+	 * has not found this soc-camera device among its clients
+	 */
+	if (ret == -ENODEV && csi2_sd)
+		csi2_sd->grp_id = 0;
+	pcdev->icd = icd;
+
+	return 0;
+}
+
+/* Called with .video_lock held */
+static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	struct v4l2_subdev *csi2_sd = find_csi2(pcdev);
+
+	BUG_ON(icd != pcdev->icd);
+
+	v4l2_subdev_call(csi2_sd, core, s_power, 0);
+	if (csi2_sd)
+		csi2_sd->grp_id = 0;
+	/* disable capture, disable interrupts */
+	ceu_write(pcdev, CEIER, 0);
+	sh_mobile_ceu_soft_reset(pcdev);
+
+	/* make sure active buffer is canceled */
+	spin_lock_irq(&pcdev->lock);
+	if (pcdev->active) {
+		list_del_init(&to_ceu_vb(pcdev->active)->queue);
+		vb2_buffer_done(pcdev->active, VB2_BUF_STATE_ERROR);
+		pcdev->active = NULL;
+	}
+	spin_unlock_irq(&pcdev->lock);
+
+	pm_runtime_put_sync(ici->v4l2_dev.dev);
+
+	dev_info(icd->parent,
+		 "SuperH Mobile CEU driver detached from camera %d\n",
+		 icd->devnum);
+
+	pcdev->icd = NULL;
+}
+
+/*
+ * See chapter 29.4.12 "Capture Filter Control Register (CFLCR)"
+ * in SH7722 Hardware Manual
+ */
+static unsigned int size_dst(unsigned int src, unsigned int scale)
+{
+	unsigned int mant_pre = scale >> 12;
+	if (!src || !scale)
+		return src;
+	return ((mant_pre + 2 * (src - 1)) / (2 * mant_pre) - 1) *
+		mant_pre * 4096 / scale + 1;
+}
+
+static u16 calc_scale(unsigned int src, unsigned int *dst)
+{
+	u16 scale;
+
+	if (src == *dst)
+		return 0;
+
+	scale = (src * 4096 / *dst) & ~7;
+
+	while (scale > 4096 && size_dst(src, scale) < *dst)
+		scale -= 8;
+
+	*dst = size_dst(src, scale);
+
+	return scale;
+}
+
+/* rect is guaranteed to not exceed the scaled camera rectangle */
+static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct sh_mobile_ceu_cam *cam = icd->host_priv;
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	unsigned int height, width, cdwdr_width, in_width, in_height;
+	unsigned int left_offset, top_offset;
+	u32 camor;
+
+	dev_geo(icd->parent, "Crop %ux%u@%u:%u\n",
+		icd->user_width, icd->user_height, cam->ceu_left, cam->ceu_top);
+
+	left_offset	= cam->ceu_left;
+	top_offset	= cam->ceu_top;
+
+	WARN_ON(icd->user_width & 3 || icd->user_height & 3);
+
+	width = icd->user_width;
+
+	if (pcdev->image_mode) {
+		in_width = cam->width;
+		if (!pcdev->is_16bit) {
+			in_width *= 2;
+			left_offset *= 2;
+		}
+	} else {
+		unsigned int w_factor;
+
+		switch (icd->current_fmt->host_fmt->packing) {
+		case SOC_MBUS_PACKING_2X8_PADHI:
+			w_factor = 2;
+			break;
+		default:
+			w_factor = 1;
+		}
+
+		in_width = cam->width * w_factor;
+		left_offset *= w_factor;
+	}
+
+	cdwdr_width = icd->bytesperline;
+
+	height = icd->user_height;
+	in_height = cam->height;
+	if (V4L2_FIELD_NONE != pcdev->field) {
+		height = (height / 2) & ~3;
+		in_height /= 2;
+		top_offset /= 2;
+		cdwdr_width *= 2;
+	}
+
+	/* CSI2 special configuration */
+	if (pcdev->pdata->csi2) {
+		in_width = ((in_width - 2) * 2);
+		left_offset *= 2;
+	}
+
+	/* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */
+	camor = left_offset | (top_offset << 16);
+
+	dev_geo(icd->parent,
+		"CAMOR 0x%x, CAPWR 0x%x, CFSZR 0x%x, CDWDR 0x%x\n", camor,
+		(in_height << 16) | in_width, (height << 16) | width,
+		cdwdr_width);
+
+	ceu_write(pcdev, CAMOR, camor);
+	ceu_write(pcdev, CAPWR, (in_height << 16) | in_width);
+	/* CFSZR clipping is applied _after_ the scaling filter (CFLCR) */
+	ceu_write(pcdev, CFSZR, (height << 16) | width);
+	ceu_write(pcdev, CDWDR, cdwdr_width);
+}
+
+static u32 capture_save_reset(struct sh_mobile_ceu_dev *pcdev)
+{
+	u32 capsr = ceu_read(pcdev, CAPSR);
+	ceu_write(pcdev, CAPSR, 1 << 16); /* reset, stop capture */
+	return capsr;
+}
+
+static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr)
+{
+	unsigned long timeout = jiffies + 10 * HZ;
+
+	/*
+	 * Wait until the end of the current frame. It can take a long time,
+	 * but if it has been aborted by a CAPSR reset, it shoule exit sooner.
+	 */
+	while ((ceu_read(pcdev, CSTSR) & 1) && time_before(jiffies, timeout))
+		msleep(1);
+
+	if (time_after(jiffies, timeout)) {
+		dev_err(pcdev->ici.v4l2_dev.dev,
+			"Timeout waiting for frame end! Interface problem?\n");
+		return;
+	}
+
+	/* Wait until reset clears, this shall not hang... */
+	while (ceu_read(pcdev, CAPSR) & (1 << 16))
+		udelay(10);
+
+	/* Anything to restore? */
+	if (capsr & ~(1 << 16))
+		ceu_write(pcdev, CAPSR, capsr);
+}
+
+/* Find the bus subdevice driver, e.g., CSI2 */
+static struct v4l2_subdev *find_bus_subdev(struct sh_mobile_ceu_dev *pcdev,
+					   struct soc_camera_device *icd)
+{
+	if (pcdev->csi2_pdev) {
+		struct v4l2_subdev *csi2_sd = find_csi2(pcdev);
+		if (csi2_sd && csi2_sd->grp_id == soc_camera_grp_id(icd))
+			return csi2_sd;
+	}
+
+	return soc_camera_to_subdev(icd);
+}
+
+#define CEU_BUS_FLAGS (V4L2_MBUS_MASTER |	\
+		V4L2_MBUS_PCLK_SAMPLE_RISING |	\
+		V4L2_MBUS_HSYNC_ACTIVE_HIGH |	\
+		V4L2_MBUS_HSYNC_ACTIVE_LOW |	\
+		V4L2_MBUS_VSYNC_ACTIVE_HIGH |	\
+		V4L2_MBUS_VSYNC_ACTIVE_LOW |	\
+		V4L2_MBUS_DATA_ACTIVE_HIGH)
+
+/* Capture is not running, no interrupts, no locking needed */
+static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	struct v4l2_subdev *sd = find_bus_subdev(pcdev, icd);
+	struct sh_mobile_ceu_cam *cam = icd->host_priv;
+	struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+	unsigned long value, common_flags = CEU_BUS_FLAGS;
+	u32 capsr = capture_save_reset(pcdev);
+	unsigned int yuv_lineskip;
+	int ret;
+
+	/*
+	 * If the client doesn't implement g_mbus_config, we just use our
+	 * platform data
+	 */
+	ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
+	if (!ret) {
+		common_flags = soc_mbus_config_compatible(&cfg,
+							  common_flags);
+		if (!common_flags)
+			return -EINVAL;
+	} else if (ret != -ENOIOCTLCMD) {
+		return ret;
+	}
+
+	/* Make choises, based on platform preferences */
+	if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
+	    (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
+		if (pcdev->pdata->flags & SH_CEU_FLAG_HSYNC_LOW)
+			common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
+		else
+			common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
+	}
+
+	if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
+	    (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
+		if (pcdev->pdata->flags & SH_CEU_FLAG_VSYNC_LOW)
+			common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
+		else
+			common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
+	}
+
+	cfg.flags = common_flags;
+	ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
+	if (ret < 0 && ret != -ENOIOCTLCMD)
+		return ret;
+
+	if (icd->current_fmt->host_fmt->bits_per_sample > 8)
+		pcdev->is_16bit = 1;
+	else
+		pcdev->is_16bit = 0;
+
+	ceu_write(pcdev, CRCNTR, 0);
+	ceu_write(pcdev, CRCMPR, 0);
+
+	value = 0x00000010; /* data fetch by default */
+	yuv_lineskip = 0x10;
+
+	switch (icd->current_fmt->host_fmt->fourcc) {
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+		/* convert 4:2:2 -> 4:2:0 */
+		yuv_lineskip = 0; /* skip for NV12/21, no skip for NV16/61 */
+		/* fall-through */
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
+		switch (cam->code) {
+		case V4L2_MBUS_FMT_UYVY8_2X8:
+			value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */
+			break;
+		case V4L2_MBUS_FMT_VYUY8_2X8:
+			value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */
+			break;
+		case V4L2_MBUS_FMT_YUYV8_2X8:
+			value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */
+			break;
+		case V4L2_MBUS_FMT_YVYU8_2X8:
+			value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */
+			break;
+		default:
+			BUG();
+		}
+	}
+
+	if (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV21 ||
+	    icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV61)
+		value ^= 0x00000100; /* swap U, V to change from NV1x->NVx1 */
+
+	value |= common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0;
+	value |= common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0;
+
+	if (pcdev->pdata->csi2) /* CSI2 mode */
+		value |= 3 << 12;
+	else if (pcdev->is_16bit)
+		value |= 1 << 12;
+	else if (pcdev->pdata->flags & SH_CEU_FLAG_LOWER_8BIT)
+		value |= 2 << 12;
+
+	ceu_write(pcdev, CAMCR, value);
+
+	ceu_write(pcdev, CAPCR, 0x00300000);
+
+	switch (pcdev->field) {
+	case V4L2_FIELD_INTERLACED_TB:
+		value = 0x101;
+		break;
+	case V4L2_FIELD_INTERLACED_BT:
+		value = 0x102;
+		break;
+	default:
+		value = 0;
+		break;
+	}
+	ceu_write(pcdev, CAIFR, value);
+
+	sh_mobile_ceu_set_rect(icd);
+	mdelay(1);
+
+	dev_geo(icd->parent, "CFLCR 0x%x\n", pcdev->cflcr);
+	ceu_write(pcdev, CFLCR, pcdev->cflcr);
+
+	/*
+	 * A few words about byte order (observed in Big Endian mode)
+	 *
+	 * In data fetch mode bytes are received in chunks of 8 bytes.
+	 * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first)
+	 *
+	 * The data is however by default written to memory in reverse order:
+	 * D7, D6, D5, D4, D3, D2, D1, D0 (D7 written to lowest byte)
+	 *
+	 * The lowest three bits of CDOCR allows us to do swapping,
+	 * using 7 we swap the data bytes to match the incoming order:
+	 * D0, D1, D2, D3, D4, D5, D6, D7
+	 */
+	value = 0x00000007 | yuv_lineskip;
+
+	ceu_write(pcdev, CDOCR, value);
+	ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */
+
+	capture_restore(pcdev, capsr);
+
+	/* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */
+	return 0;
+}
+
+static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd,
+				       unsigned char buswidth)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	struct v4l2_subdev *sd = find_bus_subdev(pcdev, icd);
+	unsigned long common_flags = CEU_BUS_FLAGS;
+	struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+	int ret;
+
+	ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
+	if (!ret)
+		common_flags = soc_mbus_config_compatible(&cfg,
+							  common_flags);
+	else if (ret != -ENOIOCTLCMD)
+		return ret;
+
+	if (!common_flags || buswidth > 16)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct soc_mbus_pixelfmt sh_mobile_ceu_formats[] = {
+	{
+		.fourcc			= V4L2_PIX_FMT_NV12,
+		.name			= "NV12",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_1_5X8,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PLANAR_2Y_C,
+	}, {
+		.fourcc			= V4L2_PIX_FMT_NV21,
+		.name			= "NV21",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_1_5X8,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PLANAR_2Y_C,
+	}, {
+		.fourcc			= V4L2_PIX_FMT_NV16,
+		.name			= "NV16",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PLANAR_Y_C,
+	}, {
+		.fourcc			= V4L2_PIX_FMT_NV61,
+		.name			= "NV61",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PLANAR_Y_C,
+	},
+};
+
+/* This will be corrected as we get more formats */
+static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt)
+{
+	return	fmt->packing == SOC_MBUS_PACKING_NONE ||
+		(fmt->bits_per_sample == 8 &&
+		 fmt->packing == SOC_MBUS_PACKING_1_5X8) ||
+		(fmt->bits_per_sample == 8 &&
+		 fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) ||
+		(fmt->bits_per_sample > 8 &&
+		 fmt->packing == SOC_MBUS_PACKING_EXTEND16);
+}
+
+static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect);
+
+static struct soc_camera_device *ctrl_to_icd(struct v4l2_ctrl *ctrl)
+{
+	return container_of(ctrl->handler, struct soc_camera_device,
+							ctrl_handler);
+}
+
+static int sh_mobile_ceu_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct soc_camera_device *icd = ctrl_to_icd(ctrl);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+
+	switch (ctrl->id) {
+	case V4L2_CID_SHARPNESS:
+		switch (icd->current_fmt->host_fmt->fourcc) {
+		case V4L2_PIX_FMT_NV12:
+		case V4L2_PIX_FMT_NV21:
+		case V4L2_PIX_FMT_NV16:
+		case V4L2_PIX_FMT_NV61:
+			ceu_write(pcdev, CLFCR, !ctrl->val);
+			return 0;
+		}
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops sh_mobile_ceu_ctrl_ops = {
+	.s_ctrl = sh_mobile_ceu_s_ctrl,
+};
+
+static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int idx,
+				     struct soc_camera_format_xlate *xlate)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct device *dev = icd->parent;
+	struct soc_camera_host *ici = to_soc_camera_host(dev);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	int ret, k, n;
+	int formats = 0;
+	struct sh_mobile_ceu_cam *cam;
+	enum v4l2_mbus_pixelcode code;
+	const struct soc_mbus_pixelfmt *fmt;
+
+	ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
+	if (ret < 0)
+		/* No more formats */
+		return 0;
+
+	fmt = soc_mbus_get_fmtdesc(code);
+	if (!fmt) {
+		dev_warn(dev, "unsupported format code #%u: %d\n", idx, code);
+		return 0;
+	}
+
+	if (!pcdev->pdata->csi2) {
+		/* Are there any restrictions in the CSI-2 case? */
+		ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample);
+		if (ret < 0)
+			return 0;
+	}
+
+	if (!icd->host_priv) {
+		struct v4l2_mbus_framefmt mf;
+		struct v4l2_rect rect;
+		int shift = 0;
+
+		/* Add our control */
+		v4l2_ctrl_new_std(&icd->ctrl_handler, &sh_mobile_ceu_ctrl_ops,
+				  V4L2_CID_SHARPNESS, 0, 1, 1, 0);
+		if (icd->ctrl_handler.error)
+			return icd->ctrl_handler.error;
+
+		/* FIXME: subwindow is lost between close / open */
+
+		/* Cache current client geometry */
+		ret = client_g_rect(sd, &rect);
+		if (ret < 0)
+			return ret;
+
+		/* First time */
+		ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
+		if (ret < 0)
+			return ret;
+
+		/*
+		 * All currently existing CEU implementations support 2560x1920
+		 * or larger frames. If the sensor is proposing too big a frame,
+		 * don't bother with possibly supportred by the CEU larger
+		 * sizes, just try VGA multiples. If needed, this can be
+		 * adjusted in the future.
+		 */
+		while ((mf.width > pcdev->max_width ||
+			mf.height > pcdev->max_height) && shift < 4) {
+			/* Try 2560x1920, 1280x960, 640x480, 320x240 */
+			mf.width	= 2560 >> shift;
+			mf.height	= 1920 >> shift;
+			ret = v4l2_device_call_until_err(sd->v4l2_dev,
+					soc_camera_grp_id(icd), video,
+					s_mbus_fmt, &mf);
+			if (ret < 0)
+				return ret;
+			shift++;
+		}
+
+		if (shift == 4) {
+			dev_err(dev, "Failed to configure the client below %ux%x\n",
+				mf.width, mf.height);
+			return -EIO;
+		}
+
+		dev_geo(dev, "camera fmt %ux%u\n", mf.width, mf.height);
+
+		cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+		if (!cam)
+			return -ENOMEM;
+
+		/* We are called with current camera crop, initialise subrect with it */
+		cam->rect	= rect;
+		cam->subrect	= rect;
+
+		cam->width	= mf.width;
+		cam->height	= mf.height;
+
+		icd->host_priv = cam;
+	} else {
+		cam = icd->host_priv;
+	}
+
+	/* Beginning of a pass */
+	if (!idx)
+		cam->extra_fmt = NULL;
+
+	switch (code) {
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+	case V4L2_MBUS_FMT_VYUY8_2X8:
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+	case V4L2_MBUS_FMT_YVYU8_2X8:
+		if (cam->extra_fmt)
+			break;
+
+		/*
+		 * Our case is simple so far: for any of the above four camera
+		 * formats we add all our four synthesized NV* formats, so,
+		 * just marking the device with a single flag suffices. If
+		 * the format generation rules are more complex, you would have
+		 * to actually hang your already added / counted formats onto
+		 * the host_priv pointer and check whether the format you're
+		 * going to add now is already there.
+		 */
+		cam->extra_fmt = sh_mobile_ceu_formats;
+
+		n = ARRAY_SIZE(sh_mobile_ceu_formats);
+		formats += n;
+		for (k = 0; xlate && k < n; k++) {
+			xlate->host_fmt	= &sh_mobile_ceu_formats[k];
+			xlate->code	= code;
+			xlate++;
+			dev_dbg(dev, "Providing format %s using code %d\n",
+				sh_mobile_ceu_formats[k].name, code);
+		}
+		break;
+	default:
+		if (!sh_mobile_ceu_packing_supported(fmt))
+			return 0;
+	}
+
+	/* Generic pass-through */
+	formats++;
+	if (xlate) {
+		xlate->host_fmt	= fmt;
+		xlate->code	= code;
+		xlate++;
+		dev_dbg(dev, "Providing format %s in pass-through mode\n",
+			fmt->name);
+	}
+
+	return formats;
+}
+
+static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd)
+{
+	kfree(icd->host_priv);
+	icd->host_priv = NULL;
+}
+
+/* Check if any dimension of r1 is smaller than respective one of r2 */
+static bool is_smaller(struct v4l2_rect *r1, struct v4l2_rect *r2)
+{
+	return r1->width < r2->width || r1->height < r2->height;
+}
+
+/* Check if r1 fails to cover r2 */
+static bool is_inside(struct v4l2_rect *r1, struct v4l2_rect *r2)
+{
+	return r1->left > r2->left || r1->top > r2->top ||
+		r1->left + r1->width < r2->left + r2->width ||
+		r1->top + r1->height < r2->top + r2->height;
+}
+
+static unsigned int scale_down(unsigned int size, unsigned int scale)
+{
+	return (size * 4096 + scale / 2) / scale;
+}
+
+static unsigned int calc_generic_scale(unsigned int input, unsigned int output)
+{
+	return (input * 4096 + output / 2) / output;
+}
+
+/* Get and store current client crop */
+static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect)
+{
+	struct v4l2_crop crop;
+	struct v4l2_cropcap cap;
+	int ret;
+
+	crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	ret = v4l2_subdev_call(sd, video, g_crop, &crop);
+	if (!ret) {
+		*rect = crop.c;
+		return ret;
+	}
+
+	/* Camera driver doesn't support .g_crop(), assume default rectangle */
+	cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+	if (!ret)
+		*rect = cap.defrect;
+
+	return ret;
+}
+
+/* Client crop has changed, update our sub-rectangle to remain within the area */
+static void update_subrect(struct sh_mobile_ceu_cam *cam)
+{
+	struct v4l2_rect *rect = &cam->rect, *subrect = &cam->subrect;
+
+	if (rect->width < subrect->width)
+		subrect->width = rect->width;
+
+	if (rect->height < subrect->height)
+		subrect->height = rect->height;
+
+	if (rect->left > subrect->left)
+		subrect->left = rect->left;
+	else if (rect->left + rect->width >
+		 subrect->left + subrect->width)
+		subrect->left = rect->left + rect->width -
+			subrect->width;
+
+	if (rect->top > subrect->top)
+		subrect->top = rect->top;
+	else if (rect->top + rect->height >
+		 subrect->top + subrect->height)
+		subrect->top = rect->top + rect->height -
+			subrect->height;
+}
+
+/*
+ * The common for both scaling and cropping iterative approach is:
+ * 1. try if the client can produce exactly what requested by the user
+ * 2. if (1) failed, try to double the client image until we get one big enough
+ * 3. if (2) failed, try to request the maximum image
+ */
+static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop,
+			 struct v4l2_crop *cam_crop)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c;
+	struct device *dev = sd->v4l2_dev->dev;
+	struct sh_mobile_ceu_cam *cam = icd->host_priv;
+	struct v4l2_cropcap cap;
+	int ret;
+	unsigned int width, height;
+
+	v4l2_subdev_call(sd, video, s_crop, crop);
+	ret = client_g_rect(sd, cam_rect);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Now cam_crop contains the current camera input rectangle, and it must
+	 * be within camera cropcap bounds
+	 */
+	if (!memcmp(rect, cam_rect, sizeof(*rect))) {
+		/* Even if camera S_CROP failed, but camera rectangle matches */
+		dev_dbg(dev, "Camera S_CROP successful for %dx%d@%d:%d\n",
+			rect->width, rect->height, rect->left, rect->top);
+		cam->rect = *cam_rect;
+		return 0;
+	}
+
+	/* Try to fix cropping, that camera hasn't managed to set */
+	dev_geo(dev, "Fix camera S_CROP for %dx%d@%d:%d to %dx%d@%d:%d\n",
+		cam_rect->width, cam_rect->height,
+		cam_rect->left, cam_rect->top,
+		rect->width, rect->height, rect->left, rect->top);
+
+	/* We need sensor maximum rectangle */
+	ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+	if (ret < 0)
+		return ret;
+
+	/* Put user requested rectangle within sensor bounds */
+	soc_camera_limit_side(&rect->left, &rect->width, cap.bounds.left, 2,
+			      cap.bounds.width);
+	soc_camera_limit_side(&rect->top, &rect->height, cap.bounds.top, 4,
+			      cap.bounds.height);
+
+	/*
+	 * Popular special case - some cameras can only handle fixed sizes like
+	 * QVGA, VGA,... Take care to avoid infinite loop.
+	 */
+	width = max(cam_rect->width, 2);
+	height = max(cam_rect->height, 2);
+
+	/*
+	 * Loop as long as sensor is not covering the requested rectangle and
+	 * is still within its bounds
+	 */
+	while (!ret && (is_smaller(cam_rect, rect) ||
+			is_inside(cam_rect, rect)) &&
+	       (cap.bounds.width > width || cap.bounds.height > height)) {
+
+		width *= 2;
+		height *= 2;
+
+		cam_rect->width = width;
+		cam_rect->height = height;
+
+		/*
+		 * We do not know what capabilities the camera has to set up
+		 * left and top borders. We could try to be smarter in iterating
+		 * them, e.g., if camera current left is to the right of the
+		 * target left, set it to the middle point between the current
+		 * left and minimum left. But that would add too much
+		 * complexity: we would have to iterate each border separately.
+		 * Instead we just drop to the left and top bounds.
+		 */
+		if (cam_rect->left > rect->left)
+			cam_rect->left = cap.bounds.left;
+
+		if (cam_rect->left + cam_rect->width < rect->left + rect->width)
+			cam_rect->width = rect->left + rect->width -
+				cam_rect->left;
+
+		if (cam_rect->top > rect->top)
+			cam_rect->top = cap.bounds.top;
+
+		if (cam_rect->top + cam_rect->height < rect->top + rect->height)
+			cam_rect->height = rect->top + rect->height -
+				cam_rect->top;
+
+		v4l2_subdev_call(sd, video, s_crop, cam_crop);
+		ret = client_g_rect(sd, cam_rect);
+		dev_geo(dev, "Camera S_CROP %d for %dx%d@%d:%d\n", ret,
+			cam_rect->width, cam_rect->height,
+			cam_rect->left, cam_rect->top);
+	}
+
+	/* S_CROP must not modify the rectangle */
+	if (is_smaller(cam_rect, rect) || is_inside(cam_rect, rect)) {
+		/*
+		 * The camera failed to configure a suitable cropping,
+		 * we cannot use the current rectangle, set to max
+		 */
+		*cam_rect = cap.bounds;
+		v4l2_subdev_call(sd, video, s_crop, cam_crop);
+		ret = client_g_rect(sd, cam_rect);
+		dev_geo(dev, "Camera S_CROP %d for max %dx%d@%d:%d\n", ret,
+			cam_rect->width, cam_rect->height,
+			cam_rect->left, cam_rect->top);
+	}
+
+	if (!ret) {
+		cam->rect = *cam_rect;
+		update_subrect(cam);
+	}
+
+	return ret;
+}
+
+/* Iterative s_mbus_fmt, also updates cached client crop on success */
+static int client_s_fmt(struct soc_camera_device *icd,
+			struct v4l2_mbus_framefmt *mf, bool ceu_can_scale)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	struct sh_mobile_ceu_cam *cam = icd->host_priv;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct device *dev = icd->parent;
+	unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h;
+	unsigned int max_width, max_height;
+	struct v4l2_cropcap cap;
+	bool ceu_1to1;
+	int ret;
+
+	ret = v4l2_device_call_until_err(sd->v4l2_dev,
+					 soc_camera_grp_id(icd), video,
+					 s_mbus_fmt, mf);
+	if (ret < 0)
+		return ret;
+
+	dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height);
+
+	if (width == mf->width && height == mf->height) {
+		/* Perfect! The client has done it all. */
+		ceu_1to1 = true;
+		goto update_cache;
+	}
+
+	ceu_1to1 = false;
+	if (!ceu_can_scale)
+		goto update_cache;
+
+	cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+	if (ret < 0)
+		return ret;
+
+	max_width = min(cap.bounds.width, pcdev->max_width);
+	max_height = min(cap.bounds.height, pcdev->max_height);
+
+	/* Camera set a format, but geometry is not precise, try to improve */
+	tmp_w = mf->width;
+	tmp_h = mf->height;
+
+	/* width <= max_width && height <= max_height - guaranteed by try_fmt */
+	while ((width > tmp_w || height > tmp_h) &&
+	       tmp_w < max_width && tmp_h < max_height) {
+		tmp_w = min(2 * tmp_w, max_width);
+		tmp_h = min(2 * tmp_h, max_height);
+		mf->width = tmp_w;
+		mf->height = tmp_h;
+		ret = v4l2_device_call_until_err(sd->v4l2_dev,
+					soc_camera_grp_id(icd), video,
+					s_mbus_fmt, mf);
+		dev_geo(dev, "Camera scaled to %ux%u\n",
+			mf->width, mf->height);
+		if (ret < 0) {
+			/* This shouldn't happen */
+			dev_err(dev, "Client failed to set format: %d\n", ret);
+			return ret;
+		}
+	}
+
+update_cache:
+	/* Update cache */
+	ret = client_g_rect(sd, &cam->rect);
+	if (ret < 0)
+		return ret;
+
+	if (ceu_1to1)
+		cam->subrect = cam->rect;
+	else
+		update_subrect(cam);
+
+	return 0;
+}
+
+/**
+ * @width	- on output: user width, mapped back to input
+ * @height	- on output: user height, mapped back to input
+ * @mf		- in- / output camera output window
+ */
+static int client_scale(struct soc_camera_device *icd,
+			struct v4l2_mbus_framefmt *mf,
+			unsigned int *width, unsigned int *height,
+			bool ceu_can_scale)
+{
+	struct sh_mobile_ceu_cam *cam = icd->host_priv;
+	struct device *dev = icd->parent;
+	struct v4l2_mbus_framefmt mf_tmp = *mf;
+	unsigned int scale_h, scale_v;
+	int ret;
+
+	/*
+	 * 5. Apply iterative camera S_FMT for camera user window (also updates
+	 *    client crop cache and the imaginary sub-rectangle).
+	 */
+	ret = client_s_fmt(icd, &mf_tmp, ceu_can_scale);
+	if (ret < 0)
+		return ret;
+
+	dev_geo(dev, "5: camera scaled to %ux%u\n",
+		mf_tmp.width, mf_tmp.height);
+
+	/* 6. Retrieve camera output window (g_fmt) */
+
+	/* unneeded - it is already in "mf_tmp" */
+
+	/* 7. Calculate new client scales. */
+	scale_h = calc_generic_scale(cam->rect.width, mf_tmp.width);
+	scale_v = calc_generic_scale(cam->rect.height, mf_tmp.height);
+
+	mf->width	= mf_tmp.width;
+	mf->height	= mf_tmp.height;
+	mf->colorspace	= mf_tmp.colorspace;
+
+	/*
+	 * 8. Calculate new CEU crop - apply camera scales to previously
+	 *    updated "effective" crop.
+	 */
+	*width = scale_down(cam->subrect.width, scale_h);
+	*height = scale_down(cam->subrect.height, scale_v);
+
+	dev_geo(dev, "8: new client sub-window %ux%u\n", *width, *height);
+
+	return 0;
+}
+
+/*
+ * CEU can scale and crop, but we don't want to waste bandwidth and kill the
+ * framerate by always requesting the maximum image from the client. See
+ * Documentation/video4linux/sh_mobile_ceu_camera.txt for a description of
+ * scaling and cropping algorithms and for the meaning of referenced here steps.
+ */
+static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
+				  struct v4l2_crop *a)
+{
+	struct v4l2_rect *rect = &a->c;
+	struct device *dev = icd->parent;
+	struct soc_camera_host *ici = to_soc_camera_host(dev);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	struct v4l2_crop cam_crop;
+	struct sh_mobile_ceu_cam *cam = icd->host_priv;
+	struct v4l2_rect *cam_rect = &cam_crop.c;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct v4l2_mbus_framefmt mf;
+	unsigned int scale_cam_h, scale_cam_v, scale_ceu_h, scale_ceu_v,
+		out_width, out_height;
+	int interm_width, interm_height;
+	u32 capsr, cflcr;
+	int ret;
+
+	dev_geo(dev, "S_CROP(%ux%u@%u:%u)\n", rect->width, rect->height,
+		rect->left, rect->top);
+
+	/* During camera cropping its output window can change too, stop CEU */
+	capsr = capture_save_reset(pcdev);
+	dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr);
+
+	/*
+	 * 1. - 2. Apply iterative camera S_CROP for new input window, read back
+	 * actual camera rectangle.
+	 */
+	ret = client_s_crop(icd, a, &cam_crop);
+	if (ret < 0)
+		return ret;
+
+	dev_geo(dev, "1-2: camera cropped to %ux%u@%u:%u\n",
+		cam_rect->width, cam_rect->height,
+		cam_rect->left, cam_rect->top);
+
+	/* On success cam_crop contains current camera crop */
+
+	/* 3. Retrieve camera output window */
+	ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
+	if (ret < 0)
+		return ret;
+
+	if (mf.width > pcdev->max_width || mf.height > pcdev->max_height)
+		return -EINVAL;
+
+	/* 4. Calculate camera scales */
+	scale_cam_h	= calc_generic_scale(cam_rect->width, mf.width);
+	scale_cam_v	= calc_generic_scale(cam_rect->height, mf.height);
+
+	/* Calculate intermediate window */
+	interm_width	= scale_down(rect->width, scale_cam_h);
+	interm_height	= scale_down(rect->height, scale_cam_v);
+
+	if (interm_width < icd->user_width) {
+		u32 new_scale_h;
+
+		new_scale_h = calc_generic_scale(rect->width, icd->user_width);
+
+		mf.width = scale_down(cam_rect->width, new_scale_h);
+	}
+
+	if (interm_height < icd->user_height) {
+		u32 new_scale_v;
+
+		new_scale_v = calc_generic_scale(rect->height, icd->user_height);
+
+		mf.height = scale_down(cam_rect->height, new_scale_v);
+	}
+
+	if (interm_width < icd->user_width || interm_height < icd->user_height) {
+		ret = v4l2_device_call_until_err(sd->v4l2_dev,
+					soc_camera_grp_id(icd), video,
+					s_mbus_fmt, &mf);
+		if (ret < 0)
+			return ret;
+
+		dev_geo(dev, "New camera output %ux%u\n", mf.width, mf.height);
+		scale_cam_h	= calc_generic_scale(cam_rect->width, mf.width);
+		scale_cam_v	= calc_generic_scale(cam_rect->height, mf.height);
+		interm_width	= scale_down(rect->width, scale_cam_h);
+		interm_height	= scale_down(rect->height, scale_cam_v);
+	}
+
+	/* Cache camera output window */
+	cam->width	= mf.width;
+	cam->height	= mf.height;
+
+	if (pcdev->image_mode) {
+		out_width	= min(interm_width, icd->user_width);
+		out_height	= min(interm_height, icd->user_height);
+	} else {
+		out_width	= interm_width;
+		out_height	= interm_height;
+	}
+
+	/*
+	 * 5. Calculate CEU scales from camera scales from results of (5) and
+	 *    the user window
+	 */
+	scale_ceu_h	= calc_scale(interm_width, &out_width);
+	scale_ceu_v	= calc_scale(interm_height, &out_height);
+
+	dev_geo(dev, "5: CEU scales %u:%u\n", scale_ceu_h, scale_ceu_v);
+
+	/* Apply CEU scales. */
+	cflcr = scale_ceu_h | (scale_ceu_v << 16);
+	if (cflcr != pcdev->cflcr) {
+		pcdev->cflcr = cflcr;
+		ceu_write(pcdev, CFLCR, cflcr);
+	}
+
+	icd->user_width	 = out_width & ~3;
+	icd->user_height = out_height & ~3;
+	/* Offsets are applied at the CEU scaling filter input */
+	cam->ceu_left	 = scale_down(rect->left - cam_rect->left, scale_cam_h) & ~1;
+	cam->ceu_top	 = scale_down(rect->top - cam_rect->top, scale_cam_v) & ~1;
+
+	/* 6. Use CEU cropping to crop to the new window. */
+	sh_mobile_ceu_set_rect(icd);
+
+	cam->subrect = *rect;
+
+	dev_geo(dev, "6: CEU cropped to %ux%u@%u:%u\n",
+		icd->user_width, icd->user_height,
+		cam->ceu_left, cam->ceu_top);
+
+	/* Restore capture. The CE bit can be cleared by the hardware */
+	if (pcdev->active)
+		capsr |= 1;
+	capture_restore(pcdev, capsr);
+
+	/* Even if only camera cropping succeeded */
+	return ret;
+}
+
+static int sh_mobile_ceu_get_crop(struct soc_camera_device *icd,
+				  struct v4l2_crop *a)
+{
+	struct sh_mobile_ceu_cam *cam = icd->host_priv;
+
+	a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->c = cam->subrect;
+
+	return 0;
+}
+
+/*
+ * Calculate real client output window by applying new scales to the current
+ * client crop. New scales are calculated from the requested output format and
+ * CEU crop, mapped backed onto the client input (subrect).
+ */
+static void calculate_client_output(struct soc_camera_device *icd,
+		const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf)
+{
+	struct sh_mobile_ceu_cam *cam = icd->host_priv;
+	struct device *dev = icd->parent;
+	struct v4l2_rect *cam_subrect = &cam->subrect;
+	unsigned int scale_v, scale_h;
+
+	if (cam_subrect->width == cam->rect.width &&
+	    cam_subrect->height == cam->rect.height) {
+		/* No sub-cropping */
+		mf->width	= pix->width;
+		mf->height	= pix->height;
+		return;
+	}
+
+	/* 1.-2. Current camera scales and subwin - cached. */
+
+	dev_geo(dev, "2: subwin %ux%u@%u:%u\n",
+		cam_subrect->width, cam_subrect->height,
+		cam_subrect->left, cam_subrect->top);
+
+	/*
+	 * 3. Calculate new combined scales from input sub-window to requested
+	 *    user window.
+	 */
+
+	/*
+	 * TODO: CEU cannot scale images larger than VGA to smaller than SubQCIF
+	 * (128x96) or larger than VGA
+	 */
+	scale_h = calc_generic_scale(cam_subrect->width, pix->width);
+	scale_v = calc_generic_scale(cam_subrect->height, pix->height);
+
+	dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v);
+
+	/*
+	 * 4. Calculate desired client output window by applying combined scales
+	 *    to client (real) input window.
+	 */
+	mf->width	= scale_down(cam->rect.width, scale_h);
+	mf->height	= scale_down(cam->rect.height, scale_v);
+}
+
+/* Similar to set_crop multistage iterative algorithm */
+static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
+				 struct v4l2_format *f)
+{
+	struct device *dev = icd->parent;
+	struct soc_camera_host *ici = to_soc_camera_host(dev);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	struct sh_mobile_ceu_cam *cam = icd->host_priv;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct v4l2_mbus_framefmt mf;
+	__u32 pixfmt = pix->pixelformat;
+	const struct soc_camera_format_xlate *xlate;
+	/* Keep Compiler Happy */
+	unsigned int ceu_sub_width = 0, ceu_sub_height = 0;
+	u16 scale_v, scale_h;
+	int ret;
+	bool image_mode;
+	enum v4l2_field field;
+
+	switch (pix->field) {
+	default:
+		pix->field = V4L2_FIELD_NONE;
+		/* fall-through */
+	case V4L2_FIELD_INTERLACED_TB:
+	case V4L2_FIELD_INTERLACED_BT:
+	case V4L2_FIELD_NONE:
+		field = pix->field;
+		break;
+	case V4L2_FIELD_INTERLACED:
+		field = V4L2_FIELD_INTERLACED_TB;
+		break;
+	}
+
+	xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+	if (!xlate) {
+		dev_warn(dev, "Format %x not found\n", pixfmt);
+		return -EINVAL;
+	}
+
+	/* 1.-4. Calculate desired client output geometry */
+	calculate_client_output(icd, pix, &mf);
+	mf.field	= pix->field;
+	mf.colorspace	= pix->colorspace;
+	mf.code		= xlate->code;
+
+	switch (pixfmt) {
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
+		image_mode = true;
+		break;
+	default:
+		image_mode = false;
+	}
+
+	dev_geo(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code,
+		pix->width, pix->height);
+
+	dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height);
+
+	/* 5. - 9. */
+	ret = client_scale(icd, &mf, &ceu_sub_width, &ceu_sub_height,
+			   image_mode && V4L2_FIELD_NONE == field);
+
+	dev_geo(dev, "5-9: client scale return %d\n", ret);
+
+	/* Done with the camera. Now see if we can improve the result */
+
+	dev_geo(dev, "fmt %ux%u, requested %ux%u\n",
+		mf.width, mf.height, pix->width, pix->height);
+	if (ret < 0)
+		return ret;
+
+	if (mf.code != xlate->code)
+		return -EINVAL;
+
+	/* 9. Prepare CEU crop */
+	cam->width = mf.width;
+	cam->height = mf.height;
+
+	/* 10. Use CEU scaling to scale to the requested user window. */
+
+	/* We cannot scale up */
+	if (pix->width > ceu_sub_width)
+		ceu_sub_width = pix->width;
+
+	if (pix->height > ceu_sub_height)
+		ceu_sub_height = pix->height;
+
+	pix->colorspace = mf.colorspace;
+
+	if (image_mode) {
+		/* Scale pix->{width x height} down to width x height */
+		scale_h		= calc_scale(ceu_sub_width, &pix->width);
+		scale_v		= calc_scale(ceu_sub_height, &pix->height);
+	} else {
+		pix->width	= ceu_sub_width;
+		pix->height	= ceu_sub_height;
+		scale_h		= 0;
+		scale_v		= 0;
+	}
+
+	pcdev->cflcr = scale_h | (scale_v << 16);
+
+	/*
+	 * We have calculated CFLCR, the actual configuration will be performed
+	 * in sh_mobile_ceu_set_bus_param()
+	 */
+
+	dev_geo(dev, "10: W: %u : 0x%x = %u, H: %u : 0x%x = %u\n",
+		ceu_sub_width, scale_h, pix->width,
+		ceu_sub_height, scale_v, pix->height);
+
+	cam->code		= xlate->code;
+	icd->current_fmt	= xlate;
+
+	pcdev->field = field;
+	pcdev->image_mode = image_mode;
+
+	/* CFSZR requirement */
+	pix->width	&= ~3;
+	pix->height	&= ~3;
+
+	return 0;
+}
+
+#define CEU_CHDW_MAX	8188U	/* Maximum line stride */
+
+static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
+				 struct v4l2_format *f)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	const struct soc_camera_format_xlate *xlate;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct v4l2_mbus_framefmt mf;
+	__u32 pixfmt = pix->pixelformat;
+	int width, height;
+	int ret;
+
+	dev_geo(icd->parent, "TRY_FMT(pix=0x%x, %ux%u)\n",
+		 pixfmt, pix->width, pix->height);
+
+	xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+	if (!xlate) {
+		xlate = icd->current_fmt;
+		dev_dbg(icd->parent, "Format %x not found, keeping %x\n",
+			pixfmt, xlate->host_fmt->fourcc);
+		pixfmt = xlate->host_fmt->fourcc;
+		pix->pixelformat = pixfmt;
+		pix->colorspace = icd->colorspace;
+	}
+
+	/* FIXME: calculate using depth and bus width */
+
+	/* CFSZR requires height and width to be 4-pixel aligned */
+	v4l_bound_align_image(&pix->width, 2, pcdev->max_width, 2,
+			      &pix->height, 4, pcdev->max_height, 2, 0);
+
+	width = pix->width;
+	height = pix->height;
+
+	/* limit to sensor capabilities */
+	mf.width	= pix->width;
+	mf.height	= pix->height;
+	mf.field	= pix->field;
+	mf.code		= xlate->code;
+	mf.colorspace	= pix->colorspace;
+
+	ret = v4l2_device_call_until_err(sd->v4l2_dev, soc_camera_grp_id(icd),
+					 video, try_mbus_fmt, &mf);
+	if (ret < 0)
+		return ret;
+
+	pix->width	= mf.width;
+	pix->height	= mf.height;
+	pix->field	= mf.field;
+	pix->colorspace	= mf.colorspace;
+
+	switch (pixfmt) {
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
+		/* FIXME: check against rect_max after converting soc-camera */
+		/* We can scale precisely, need a bigger image from camera */
+		if (pix->width < width || pix->height < height) {
+			/*
+			 * We presume, the sensor behaves sanely, i.e., if
+			 * requested a bigger rectangle, it will not return a
+			 * smaller one.
+			 */
+			mf.width = pcdev->max_width;
+			mf.height = pcdev->max_height;
+			ret = v4l2_device_call_until_err(sd->v4l2_dev,
+					soc_camera_grp_id(icd), video,
+					try_mbus_fmt, &mf);
+			if (ret < 0) {
+				/* Shouldn't actually happen... */
+				dev_err(icd->parent,
+					"FIXME: client try_fmt() = %d\n", ret);
+				return ret;
+			}
+		}
+		/* We will scale exactly */
+		if (mf.width > width)
+			pix->width = width;
+		if (mf.height > height)
+			pix->height = height;
+
+		pix->bytesperline = max(pix->bytesperline, pix->width);
+		pix->bytesperline = min(pix->bytesperline, CEU_CHDW_MAX);
+		pix->bytesperline &= ~3;
+		break;
+
+	default:
+		/* Configurable stride isn't supported in pass-through mode. */
+		pix->bytesperline  = 0;
+	}
+
+	pix->width	&= ~3;
+	pix->height	&= ~3;
+	pix->sizeimage	= 0;
+
+	dev_geo(icd->parent, "%s(): return %d, fmt 0x%x, %ux%u\n",
+		__func__, ret, pix->pixelformat, pix->width, pix->height);
+
+	return ret;
+}
+
+static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd,
+				      struct v4l2_crop *a)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	u32 out_width = icd->user_width, out_height = icd->user_height;
+	int ret;
+
+	/* Freeze queue */
+	pcdev->frozen = 1;
+	/* Wait for frame */
+	ret = wait_for_completion_interruptible(&pcdev->complete);
+	/* Stop the client */
+	ret = v4l2_subdev_call(sd, video, s_stream, 0);
+	if (ret < 0)
+		dev_warn(icd->parent,
+			 "Client failed to stop the stream: %d\n", ret);
+	else
+		/* Do the crop, if it fails, there's nothing more we can do */
+		sh_mobile_ceu_set_crop(icd, a);
+
+	dev_geo(icd->parent, "Output after crop: %ux%u\n", icd->user_width, icd->user_height);
+
+	if (icd->user_width != out_width || icd->user_height != out_height) {
+		struct v4l2_format f = {
+			.type	= V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			.fmt.pix	= {
+				.width		= out_width,
+				.height		= out_height,
+				.pixelformat	= icd->current_fmt->host_fmt->fourcc,
+				.field		= pcdev->field,
+				.colorspace	= icd->colorspace,
+			},
+		};
+		ret = sh_mobile_ceu_set_fmt(icd, &f);
+		if (!ret && (out_width != f.fmt.pix.width ||
+			     out_height != f.fmt.pix.height))
+			ret = -EINVAL;
+		if (!ret) {
+			icd->user_width		= out_width & ~3;
+			icd->user_height	= out_height & ~3;
+			ret = sh_mobile_ceu_set_bus_param(icd);
+		}
+	}
+
+	/* Thaw the queue */
+	pcdev->frozen = 0;
+	spin_lock_irq(&pcdev->lock);
+	sh_mobile_ceu_capture(pcdev);
+	spin_unlock_irq(&pcdev->lock);
+	/* Start the client */
+	ret = v4l2_subdev_call(sd, video, s_stream, 1);
+	return ret;
+}
+
+static unsigned int sh_mobile_ceu_poll(struct file *file, poll_table *pt)
+{
+	struct soc_camera_device *icd = file->private_data;
+
+	return vb2_poll(&icd->vb2_vidq, file, pt);
+}
+
+static int sh_mobile_ceu_querycap(struct soc_camera_host *ici,
+				  struct v4l2_capability *cap)
+{
+	strlcpy(cap->card, "SuperH_Mobile_CEU", sizeof(cap->card));
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+	return 0;
+}
+
+static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q,
+				       struct soc_camera_device *icd)
+{
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	q->io_modes = VB2_MMAP | VB2_USERPTR;
+	q->drv_priv = icd;
+	q->ops = &sh_mobile_ceu_videobuf_ops;
+	q->mem_ops = &vb2_dma_contig_memops;
+	q->buf_struct_size = sizeof(struct sh_mobile_ceu_buffer);
+
+	return vb2_queue_init(q);
+}
+
+static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
+	.owner		= THIS_MODULE,
+	.add		= sh_mobile_ceu_add_device,
+	.remove		= sh_mobile_ceu_remove_device,
+	.get_formats	= sh_mobile_ceu_get_formats,
+	.put_formats	= sh_mobile_ceu_put_formats,
+	.get_crop	= sh_mobile_ceu_get_crop,
+	.set_crop	= sh_mobile_ceu_set_crop,
+	.set_livecrop	= sh_mobile_ceu_set_livecrop,
+	.set_fmt	= sh_mobile_ceu_set_fmt,
+	.try_fmt	= sh_mobile_ceu_try_fmt,
+	.poll		= sh_mobile_ceu_poll,
+	.querycap	= sh_mobile_ceu_querycap,
+	.set_bus_param	= sh_mobile_ceu_set_bus_param,
+	.init_videobuf2	= sh_mobile_ceu_init_videobuf,
+};
+
+struct bus_wait {
+	struct notifier_block	notifier;
+	struct completion	completion;
+	struct device		*dev;
+};
+
+static int bus_notify(struct notifier_block *nb,
+		      unsigned long action, void *data)
+{
+	struct device *dev = data;
+	struct bus_wait *wait = container_of(nb, struct bus_wait, notifier);
+
+	if (wait->dev != dev)
+		return NOTIFY_DONE;
+
+	switch (action) {
+	case BUS_NOTIFY_UNBOUND_DRIVER:
+		/* Protect from module unloading */
+		wait_for_completion(&wait->completion);
+		return NOTIFY_OK;
+	}
+	return NOTIFY_DONE;
+}
+
+static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
+{
+	struct sh_mobile_ceu_dev *pcdev;
+	struct resource *res;
+	void __iomem *base;
+	unsigned int irq;
+	int err = 0;
+	struct bus_wait wait = {
+		.completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion),
+		.notifier.notifier_call = bus_notify,
+	};
+	struct sh_mobile_ceu_companion *csi2;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(pdev, 0);
+	if (!res || (int)irq <= 0) {
+		dev_err(&pdev->dev, "Not enough CEU platform resources.\n");
+		err = -ENODEV;
+		goto exit;
+	}
+
+	pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);
+	if (!pcdev) {
+		dev_err(&pdev->dev, "Could not allocate pcdev\n");
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	INIT_LIST_HEAD(&pcdev->capture);
+	spin_lock_init(&pcdev->lock);
+	init_completion(&pcdev->complete);
+
+	pcdev->pdata = pdev->dev.platform_data;
+	if (!pcdev->pdata) {
+		err = -EINVAL;
+		dev_err(&pdev->dev, "CEU platform data not set.\n");
+		goto exit_kfree;
+	}
+
+	pcdev->max_width = pcdev->pdata->max_width ? : 2560;
+	pcdev->max_height = pcdev->pdata->max_height ? : 1920;
+
+	base = ioremap_nocache(res->start, resource_size(res));
+	if (!base) {
+		err = -ENXIO;
+		dev_err(&pdev->dev, "Unable to ioremap CEU registers.\n");
+		goto exit_kfree;
+	}
+
+	pcdev->irq = irq;
+	pcdev->base = base;
+	pcdev->video_limit = 0; /* only enabled if second resource exists */
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (res) {
+		err = dma_declare_coherent_memory(&pdev->dev, res->start,
+						  res->start,
+						  resource_size(res),
+						  DMA_MEMORY_MAP |
+						  DMA_MEMORY_EXCLUSIVE);
+		if (!err) {
+			dev_err(&pdev->dev, "Unable to declare CEU memory.\n");
+			err = -ENXIO;
+			goto exit_iounmap;
+		}
+
+		pcdev->video_limit = resource_size(res);
+	}
+
+	/* request irq */
+	err = request_irq(pcdev->irq, sh_mobile_ceu_irq, IRQF_DISABLED,
+			  dev_name(&pdev->dev), pcdev);
+	if (err) {
+		dev_err(&pdev->dev, "Unable to register CEU interrupt.\n");
+		goto exit_release_mem;
+	}
+
+	pm_suspend_ignore_children(&pdev->dev, true);
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_resume(&pdev->dev);
+
+	pcdev->ici.priv = pcdev;
+	pcdev->ici.v4l2_dev.dev = &pdev->dev;
+	pcdev->ici.nr = pdev->id;
+	pcdev->ici.drv_name = dev_name(&pdev->dev);
+	pcdev->ici.ops = &sh_mobile_ceu_host_ops;
+	pcdev->ici.capabilities = SOCAM_HOST_CAP_STRIDE;
+
+	pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+	if (IS_ERR(pcdev->alloc_ctx)) {
+		err = PTR_ERR(pcdev->alloc_ctx);
+		goto exit_free_clk;
+	}
+
+	err = soc_camera_host_register(&pcdev->ici);
+	if (err)
+		goto exit_free_ctx;
+
+	/* CSI2 interfacing */
+	csi2 = pcdev->pdata->csi2;
+	if (csi2) {
+		struct platform_device *csi2_pdev =
+			platform_device_alloc("sh-mobile-csi2", csi2->id);
+		struct sh_csi2_pdata *csi2_pdata = csi2->platform_data;
+
+		if (!csi2_pdev) {
+			err = -ENOMEM;
+			goto exit_host_unregister;
+		}
+
+		pcdev->csi2_pdev		= csi2_pdev;
+
+		err = platform_device_add_data(csi2_pdev, csi2_pdata, sizeof(*csi2_pdata));
+		if (err < 0)
+			goto exit_pdev_put;
+
+		csi2_pdata			= csi2_pdev->dev.platform_data;
+		csi2_pdata->v4l2_dev		= &pcdev->ici.v4l2_dev;
+
+		csi2_pdev->resource		= csi2->resource;
+		csi2_pdev->num_resources	= csi2->num_resources;
+
+		err = platform_device_add(csi2_pdev);
+		if (err < 0)
+			goto exit_pdev_put;
+
+		wait.dev = &csi2_pdev->dev;
+
+		err = bus_register_notifier(&platform_bus_type, &wait.notifier);
+		if (err < 0)
+			goto exit_pdev_unregister;
+
+		/*
+		 * From this point the driver module will not unload, until
+		 * we complete the completion.
+		 */
+
+		if (!csi2_pdev->dev.driver) {
+			complete(&wait.completion);
+			/* Either too late, or probing failed */
+			bus_unregister_notifier(&platform_bus_type, &wait.notifier);
+			err = -ENXIO;
+			goto exit_pdev_unregister;
+		}
+
+		/*
+		 * The module is still loaded, in the worst case it is hanging
+		 * in device release on our completion. So, _now_ dereferencing
+		 * the "owner" is safe!
+		 */
+
+		err = try_module_get(csi2_pdev->dev.driver->owner);
+
+		/* Let notifier complete, if it has been locked */
+		complete(&wait.completion);
+		bus_unregister_notifier(&platform_bus_type, &wait.notifier);
+		if (!err) {
+			err = -ENODEV;
+			goto exit_pdev_unregister;
+		}
+	}
+
+	return 0;
+
+exit_pdev_unregister:
+	platform_device_del(pcdev->csi2_pdev);
+exit_pdev_put:
+	pcdev->csi2_pdev->resource = NULL;
+	platform_device_put(pcdev->csi2_pdev);
+exit_host_unregister:
+	soc_camera_host_unregister(&pcdev->ici);
+exit_free_ctx:
+	vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+exit_free_clk:
+	pm_runtime_disable(&pdev->dev);
+	free_irq(pcdev->irq, pcdev);
+exit_release_mem:
+	if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
+		dma_release_declared_memory(&pdev->dev);
+exit_iounmap:
+	iounmap(base);
+exit_kfree:
+	kfree(pcdev);
+exit:
+	return err;
+}
+
+static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev)
+{
+	struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+	struct sh_mobile_ceu_dev *pcdev = container_of(soc_host,
+					struct sh_mobile_ceu_dev, ici);
+	struct platform_device *csi2_pdev = pcdev->csi2_pdev;
+
+	soc_camera_host_unregister(soc_host);
+	pm_runtime_disable(&pdev->dev);
+	free_irq(pcdev->irq, pcdev);
+	if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
+		dma_release_declared_memory(&pdev->dev);
+	iounmap(pcdev->base);
+	vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+	if (csi2_pdev && csi2_pdev->dev.driver) {
+		struct module *csi2_drv = csi2_pdev->dev.driver->owner;
+		platform_device_del(csi2_pdev);
+		csi2_pdev->resource = NULL;
+		platform_device_put(csi2_pdev);
+		module_put(csi2_drv);
+	}
+	kfree(pcdev);
+
+	return 0;
+}
+
+static int sh_mobile_ceu_runtime_nop(struct device *dev)
+{
+	/* Runtime PM callback shared between ->runtime_suspend()
+	 * and ->runtime_resume(). Simply returns success.
+	 *
+	 * This driver re-initializes all registers after
+	 * pm_runtime_get_sync() anyway so there is no need
+	 * to save and restore registers here.
+	 */
+	return 0;
+}
+
+static const struct dev_pm_ops sh_mobile_ceu_dev_pm_ops = {
+	.runtime_suspend = sh_mobile_ceu_runtime_nop,
+	.runtime_resume = sh_mobile_ceu_runtime_nop,
+};
+
+static struct platform_driver sh_mobile_ceu_driver = {
+	.driver 	= {
+		.name	= "sh_mobile_ceu",
+		.pm	= &sh_mobile_ceu_dev_pm_ops,
+	},
+	.probe		= sh_mobile_ceu_probe,
+	.remove		= __devexit_p(sh_mobile_ceu_remove),
+};
+
+static int __init sh_mobile_ceu_init(void)
+{
+	/* Whatever return code */
+	request_module("sh_mobile_csi2");
+	return platform_driver_register(&sh_mobile_ceu_driver);
+}
+
+static void __exit sh_mobile_ceu_exit(void)
+{
+	platform_driver_unregister(&sh_mobile_ceu_driver);
+}
+
+module_init(sh_mobile_ceu_init);
+module_exit(sh_mobile_ceu_exit);
+
+MODULE_DESCRIPTION("SuperH Mobile CEU driver");
+MODULE_AUTHOR("Magnus Damm");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.6");
+MODULE_ALIAS("platform:sh_mobile_ceu");
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c
new file mode 100644
index 0000000..9f62fd8
--- /dev/null
+++ b/drivers/media/platform/sh_vou.c
@@ -0,0 +1,1510 @@
+/*
+ * SuperH Video Output Unit (VOU) driver
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+
+#include <media/sh_vou.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mediabus.h>
+#include <media/videobuf-dma-contig.h>
+
+/* Mirror addresses are not available for all registers */
+#define VOUER	0
+#define VOUCR	4
+#define VOUSTR	8
+#define VOUVCR	0xc
+#define VOUISR	0x10
+#define VOUBCR	0x14
+#define VOUDPR	0x18
+#define VOUDSR	0x1c
+#define VOUVPR	0x20
+#define VOUIR	0x24
+#define VOUSRR	0x28
+#define VOUMSR	0x2c
+#define VOUHIR	0x30
+#define VOUDFR	0x34
+#define VOUAD1R	0x38
+#define VOUAD2R	0x3c
+#define VOUAIR	0x40
+#define VOUSWR	0x44
+#define VOURCR	0x48
+#define VOURPR	0x50
+
+enum sh_vou_status {
+	SH_VOU_IDLE,
+	SH_VOU_INITIALISING,
+	SH_VOU_RUNNING,
+};
+
+#define VOU_MAX_IMAGE_WIDTH	720
+#define VOU_MAX_IMAGE_HEIGHT	576
+
+struct sh_vou_device {
+	struct v4l2_device v4l2_dev;
+	struct video_device *vdev;
+	atomic_t use_count;
+	struct sh_vou_pdata *pdata;
+	spinlock_t lock;
+	void __iomem *base;
+	/* State information */
+	struct v4l2_pix_format pix;
+	struct v4l2_rect rect;
+	struct list_head queue;
+	v4l2_std_id std;
+	int pix_idx;
+	struct videobuf_buffer *active;
+	enum sh_vou_status status;
+	struct mutex fop_lock;
+};
+
+struct sh_vou_file {
+	struct videobuf_queue vbq;
+};
+
+/* Register access routines for sides A, B and mirror addresses */
+static void sh_vou_reg_a_write(struct sh_vou_device *vou_dev, unsigned int reg,
+			       u32 value)
+{
+	__raw_writel(value, vou_dev->base + reg);
+}
+
+static void sh_vou_reg_ab_write(struct sh_vou_device *vou_dev, unsigned int reg,
+				u32 value)
+{
+	__raw_writel(value, vou_dev->base + reg);
+	__raw_writel(value, vou_dev->base + reg + 0x1000);
+}
+
+static void sh_vou_reg_m_write(struct sh_vou_device *vou_dev, unsigned int reg,
+			       u32 value)
+{
+	__raw_writel(value, vou_dev->base + reg + 0x2000);
+}
+
+static u32 sh_vou_reg_a_read(struct sh_vou_device *vou_dev, unsigned int reg)
+{
+	return __raw_readl(vou_dev->base + reg);
+}
+
+static void sh_vou_reg_a_set(struct sh_vou_device *vou_dev, unsigned int reg,
+			     u32 value, u32 mask)
+{
+	u32 old = __raw_readl(vou_dev->base + reg);
+
+	value = (value & mask) | (old & ~mask);
+	__raw_writel(value, vou_dev->base + reg);
+}
+
+static void sh_vou_reg_b_set(struct sh_vou_device *vou_dev, unsigned int reg,
+			     u32 value, u32 mask)
+{
+	sh_vou_reg_a_set(vou_dev, reg + 0x1000, value, mask);
+}
+
+static void sh_vou_reg_ab_set(struct sh_vou_device *vou_dev, unsigned int reg,
+			      u32 value, u32 mask)
+{
+	sh_vou_reg_a_set(vou_dev, reg, value, mask);
+	sh_vou_reg_b_set(vou_dev, reg, value, mask);
+}
+
+struct sh_vou_fmt {
+	u32		pfmt;
+	char		*desc;
+	unsigned char	bpp;
+	unsigned char	rgb;
+	unsigned char	yf;
+	unsigned char	pkf;
+};
+
+/* Further pixel formats can be added */
+static struct sh_vou_fmt vou_fmt[] = {
+	{
+		.pfmt	= V4L2_PIX_FMT_NV12,
+		.bpp	= 12,
+		.desc	= "YVU420 planar",
+		.yf	= 0,
+		.rgb	= 0,
+	},
+	{
+		.pfmt	= V4L2_PIX_FMT_NV16,
+		.bpp	= 16,
+		.desc	= "YVYU planar",
+		.yf	= 1,
+		.rgb	= 0,
+	},
+	{
+		.pfmt	= V4L2_PIX_FMT_RGB24,
+		.bpp	= 24,
+		.desc	= "RGB24",
+		.pkf	= 2,
+		.rgb	= 1,
+	},
+	{
+		.pfmt	= V4L2_PIX_FMT_RGB565,
+		.bpp	= 16,
+		.desc	= "RGB565",
+		.pkf	= 3,
+		.rgb	= 1,
+	},
+	{
+		.pfmt	= V4L2_PIX_FMT_RGB565X,
+		.bpp	= 16,
+		.desc	= "RGB565 byteswapped",
+		.pkf	= 3,
+		.rgb	= 1,
+	},
+};
+
+static void sh_vou_schedule_next(struct sh_vou_device *vou_dev,
+				 struct videobuf_buffer *vb)
+{
+	dma_addr_t addr1, addr2;
+
+	addr1 = videobuf_to_dma_contig(vb);
+	switch (vou_dev->pix.pixelformat) {
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV16:
+		addr2 = addr1 + vou_dev->pix.width * vou_dev->pix.height;
+		break;
+	default:
+		addr2 = 0;
+	}
+
+	sh_vou_reg_m_write(vou_dev, VOUAD1R, addr1);
+	sh_vou_reg_m_write(vou_dev, VOUAD2R, addr2);
+}
+
+static void sh_vou_stream_start(struct sh_vou_device *vou_dev,
+				struct videobuf_buffer *vb)
+{
+	unsigned int row_coeff;
+#ifdef __LITTLE_ENDIAN
+	u32 dataswap = 7;
+#else
+	u32 dataswap = 0;
+#endif
+
+	switch (vou_dev->pix.pixelformat) {
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV16:
+		row_coeff = 1;
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		dataswap ^= 1;
+	case V4L2_PIX_FMT_RGB565X:
+		row_coeff = 2;
+		break;
+	case V4L2_PIX_FMT_RGB24:
+		row_coeff = 3;
+		break;
+	}
+
+	sh_vou_reg_a_write(vou_dev, VOUSWR, dataswap);
+	sh_vou_reg_ab_write(vou_dev, VOUAIR, vou_dev->pix.width * row_coeff);
+	sh_vou_schedule_next(vou_dev, vb);
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	BUG_ON(in_interrupt());
+
+	/* Wait until this buffer is no longer in STATE_QUEUED or STATE_ACTIVE */
+	videobuf_waiton(vq, vb, 0, 0);
+	videobuf_dma_contig_free(vq, vb);
+	vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+/* Locking: caller holds fop_lock mutex */
+static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count,
+			    unsigned int *size)
+{
+	struct video_device *vdev = vq->priv_data;
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+	*size = vou_fmt[vou_dev->pix_idx].bpp * vou_dev->pix.width *
+		vou_dev->pix.height / 8;
+
+	if (*count < 2)
+		*count = 2;
+
+	/* Taking into account maximum frame size, *count will stay >= 2 */
+	if (PAGE_ALIGN(*size) * *count > 4 * 1024 * 1024)
+		*count = 4 * 1024 * 1024 / PAGE_ALIGN(*size);
+
+	dev_dbg(vq->dev, "%s(): count=%d, size=%d\n", __func__, *count, *size);
+
+	return 0;
+}
+
+/* Locking: caller holds fop_lock mutex */
+static int sh_vou_buf_prepare(struct videobuf_queue *vq,
+			      struct videobuf_buffer *vb,
+			      enum v4l2_field field)
+{
+	struct video_device *vdev = vq->priv_data;
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	struct v4l2_pix_format *pix = &vou_dev->pix;
+	int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8;
+	int ret;
+
+	dev_dbg(vq->dev, "%s()\n", __func__);
+
+	if (vb->width	!= pix->width ||
+	    vb->height	!= pix->height ||
+	    vb->field	!= pix->field) {
+		vb->width	= pix->width;
+		vb->height	= pix->height;
+		vb->field	= field;
+		if (vb->state != VIDEOBUF_NEEDS_INIT)
+			free_buffer(vq, vb);
+	}
+
+	vb->size = vb->height * bytes_per_line;
+	if (vb->baddr && vb->bsize < vb->size) {
+		/* User buffer too small */
+		dev_warn(vq->dev, "User buffer too small: [%u] @ %lx\n",
+			 vb->bsize, vb->baddr);
+		return -EINVAL;
+	}
+
+	if (vb->state == VIDEOBUF_NEEDS_INIT) {
+		ret = videobuf_iolock(vq, vb, NULL);
+		if (ret < 0) {
+			dev_warn(vq->dev, "IOLOCK buf-type %d: %d\n",
+				 vb->memory, ret);
+			return ret;
+		}
+		vb->state = VIDEOBUF_PREPARED;
+	}
+
+	dev_dbg(vq->dev,
+		"%s(): fmt #%d, %u bytes per line, phys 0x%x, type %d, state %d\n",
+		__func__, vou_dev->pix_idx, bytes_per_line,
+		videobuf_to_dma_contig(vb), vb->memory, vb->state);
+
+	return 0;
+}
+
+/* Locking: caller holds fop_lock mutex and vq->irqlock spinlock */
+static void sh_vou_buf_queue(struct videobuf_queue *vq,
+			     struct videobuf_buffer *vb)
+{
+	struct video_device *vdev = vq->priv_data;
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+	dev_dbg(vq->dev, "%s()\n", __func__);
+
+	vb->state = VIDEOBUF_QUEUED;
+	list_add_tail(&vb->queue, &vou_dev->queue);
+
+	if (vou_dev->status == SH_VOU_RUNNING) {
+		return;
+	} else if (!vou_dev->active) {
+		vou_dev->active = vb;
+		/* Start from side A: we use mirror addresses, so, set B */
+		sh_vou_reg_a_write(vou_dev, VOURPR, 1);
+		dev_dbg(vq->dev, "%s: first buffer status 0x%x\n", __func__,
+			sh_vou_reg_a_read(vou_dev, VOUSTR));
+		sh_vou_schedule_next(vou_dev, vb);
+		/* Only activate VOU after the second buffer */
+	} else if (vou_dev->active->queue.next == &vb->queue) {
+		/* Second buffer - initialise register side B */
+		sh_vou_reg_a_write(vou_dev, VOURPR, 0);
+		sh_vou_stream_start(vou_dev, vb);
+
+		/* Register side switching with frame VSYNC */
+		sh_vou_reg_a_write(vou_dev, VOURCR, 5);
+		dev_dbg(vq->dev, "%s: second buffer status 0x%x\n", __func__,
+			sh_vou_reg_a_read(vou_dev, VOUSTR));
+
+		/* Enable End-of-Frame (VSYNC) interrupts */
+		sh_vou_reg_a_write(vou_dev, VOUIR, 0x10004);
+		/* Two buffers on the queue - activate the hardware */
+
+		vou_dev->status = SH_VOU_RUNNING;
+		sh_vou_reg_a_write(vou_dev, VOUER, 0x107);
+	}
+}
+
+static void sh_vou_buf_release(struct videobuf_queue *vq,
+			       struct videobuf_buffer *vb)
+{
+	struct video_device *vdev = vq->priv_data;
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	unsigned long flags;
+
+	dev_dbg(vq->dev, "%s()\n", __func__);
+
+	spin_lock_irqsave(&vou_dev->lock, flags);
+
+	if (vou_dev->active == vb) {
+		/* disable output */
+		sh_vou_reg_a_set(vou_dev, VOUER, 0, 1);
+		/* ...but the current frame will complete */
+		sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000);
+		vou_dev->active = NULL;
+	}
+
+	if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED)) {
+		vb->state = VIDEOBUF_ERROR;
+		list_del(&vb->queue);
+	}
+
+	spin_unlock_irqrestore(&vou_dev->lock, flags);
+
+	free_buffer(vq, vb);
+}
+
+static struct videobuf_queue_ops sh_vou_video_qops = {
+	.buf_setup	= sh_vou_buf_setup,
+	.buf_prepare	= sh_vou_buf_prepare,
+	.buf_queue	= sh_vou_buf_queue,
+	.buf_release	= sh_vou_buf_release,
+};
+
+/* Video IOCTLs */
+static int sh_vou_querycap(struct file *file, void  *priv,
+			   struct v4l2_capability *cap)
+{
+	struct sh_vou_file *vou_file = priv;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	strlcpy(cap->card, "SuperH VOU", sizeof(cap->card));
+	cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+	return 0;
+}
+
+/* Enumerate formats, that the device can accept from the user */
+static int sh_vou_enum_fmt_vid_out(struct file *file, void  *priv,
+				   struct v4l2_fmtdesc *fmt)
+{
+	struct sh_vou_file *vou_file = priv;
+
+	if (fmt->index >= ARRAY_SIZE(vou_fmt))
+		return -EINVAL;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	strlcpy(fmt->description, vou_fmt[fmt->index].desc,
+		sizeof(fmt->description));
+	fmt->pixelformat = vou_fmt[fmt->index].pfmt;
+
+	return 0;
+}
+
+static int sh_vou_g_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
+
+	fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	fmt->fmt.pix = vou_dev->pix;
+
+	return 0;
+}
+
+static const unsigned char vou_scale_h_num[] = {1, 9, 2, 9, 4};
+static const unsigned char vou_scale_h_den[] = {1, 8, 1, 4, 1};
+static const unsigned char vou_scale_h_fld[] = {0, 2, 1, 3};
+static const unsigned char vou_scale_v_num[] = {1, 2, 4};
+static const unsigned char vou_scale_v_den[] = {1, 1, 1};
+static const unsigned char vou_scale_v_fld[] = {0, 1};
+
+static void sh_vou_configure_geometry(struct sh_vou_device *vou_dev,
+				      int pix_idx, int w_idx, int h_idx)
+{
+	struct sh_vou_fmt *fmt = vou_fmt + pix_idx;
+	unsigned int black_left, black_top, width_max, height_max,
+		frame_in_height, frame_out_height, frame_out_top;
+	struct v4l2_rect *rect = &vou_dev->rect;
+	struct v4l2_pix_format *pix = &vou_dev->pix;
+	u32 vouvcr = 0, dsr_h, dsr_v;
+
+	if (vou_dev->std & V4L2_STD_525_60) {
+		width_max = 858;
+		height_max = 262;
+	} else {
+		width_max = 864;
+		height_max = 312;
+	}
+
+	frame_in_height = pix->height / 2;
+	frame_out_height = rect->height / 2;
+	frame_out_top = rect->top / 2;
+
+	/*
+	 * Cropping scheme: max useful image is 720x480, and the total video
+	 * area is 858x525 (NTSC) or 864x625 (PAL). AK8813 / 8814 starts
+	 * sampling data beginning with fixed 276th (NTSC) / 288th (PAL) clock,
+	 * of which the first 33 / 25 clocks HSYNC must be held active. This
+	 * has to be configured in CR[HW]. 1 pixel equals 2 clock periods.
+	 * This gives CR[HW] = 16 / 12, VPR[HVP] = 138 / 144, which gives
+	 * exactly 858 - 138 = 864 - 144 = 720! We call the out-of-display area,
+	 * beyond DSR, specified on the left and top by the VPR register "black
+	 * pixels" and out-of-image area (DPR) "background pixels." We fix VPR
+	 * at 138 / 144 : 20, because that's the HSYNC timing, that our first
+	 * client requires, and that's exactly what leaves us 720 pixels for the
+	 * image; we leave VPR[VVP] at default 20 for now, because the client
+	 * doesn't seem to have any special requirements for it. Otherwise we
+	 * could also set it to max - 240 = 22 / 72. Thus VPR depends only on
+	 * the selected standard, and DPR and DSR are selected according to
+	 * cropping. Q: how does the client detect the first valid line? Does
+	 * HSYNC stay inactive during invalid (black) lines?
+	 */
+	black_left = width_max - VOU_MAX_IMAGE_WIDTH;
+	black_top = 20;
+
+	dsr_h = rect->width + rect->left;
+	dsr_v = frame_out_height + frame_out_top;
+
+	dev_dbg(vou_dev->v4l2_dev.dev,
+		"image %ux%u, black %u:%u, offset %u:%u, display %ux%u\n",
+		pix->width, frame_in_height, black_left, black_top,
+		rect->left, frame_out_top, dsr_h, dsr_v);
+
+	/* VOUISR height - half of a frame height in frame mode */
+	sh_vou_reg_ab_write(vou_dev, VOUISR, (pix->width << 16) | frame_in_height);
+	sh_vou_reg_ab_write(vou_dev, VOUVPR, (black_left << 16) | black_top);
+	sh_vou_reg_ab_write(vou_dev, VOUDPR, (rect->left << 16) | frame_out_top);
+	sh_vou_reg_ab_write(vou_dev, VOUDSR, (dsr_h << 16) | dsr_v);
+
+	/*
+	 * if necessary, we could set VOUHIR to
+	 * max(black_left + dsr_h, width_max) here
+	 */
+
+	if (w_idx)
+		vouvcr |= (1 << 15) | (vou_scale_h_fld[w_idx - 1] << 4);
+	if (h_idx)
+		vouvcr |= (1 << 14) | vou_scale_v_fld[h_idx - 1];
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s: scaling 0x%x\n", fmt->desc, vouvcr);
+
+	/* To produce a colour bar for testing set bit 23 of VOUVCR */
+	sh_vou_reg_ab_write(vou_dev, VOUVCR, vouvcr);
+	sh_vou_reg_ab_write(vou_dev, VOUDFR,
+			    fmt->pkf | (fmt->yf << 8) | (fmt->rgb << 16));
+}
+
+struct sh_vou_geometry {
+	struct v4l2_rect output;
+	unsigned int in_width;
+	unsigned int in_height;
+	int scale_idx_h;
+	int scale_idx_v;
+};
+
+/*
+ * Find input geometry, that we can use to produce output, closest to the
+ * requested rectangle, using VOU scaling
+ */
+static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std)
+{
+	/* The compiler cannot know, that best and idx will indeed be set */
+	unsigned int best_err = UINT_MAX, best = 0, img_height_max;
+	int i, idx = 0;
+
+	if (std & V4L2_STD_525_60)
+		img_height_max = 480;
+	else
+		img_height_max = 576;
+
+	/* Image width must be a multiple of 4 */
+	v4l_bound_align_image(&geo->in_width, 0, VOU_MAX_IMAGE_WIDTH, 2,
+			      &geo->in_height, 0, img_height_max, 1, 0);
+
+	/* Select scales to come as close as possible to the output image */
+	for (i = ARRAY_SIZE(vou_scale_h_num) - 1; i >= 0; i--) {
+		unsigned int err;
+		unsigned int found = geo->output.width * vou_scale_h_den[i] /
+			vou_scale_h_num[i];
+
+		if (found > VOU_MAX_IMAGE_WIDTH)
+			/* scales increase */
+			break;
+
+		err = abs(found - geo->in_width);
+		if (err < best_err) {
+			best_err = err;
+			idx = i;
+			best = found;
+		}
+		if (!err)
+			break;
+	}
+
+	geo->in_width = best;
+	geo->scale_idx_h = idx;
+
+	best_err = UINT_MAX;
+
+	/* This loop can be replaced with one division */
+	for (i = ARRAY_SIZE(vou_scale_v_num) - 1; i >= 0; i--) {
+		unsigned int err;
+		unsigned int found = geo->output.height * vou_scale_v_den[i] /
+			vou_scale_v_num[i];
+
+		if (found > img_height_max)
+			/* scales increase */
+			break;
+
+		err = abs(found - geo->in_height);
+		if (err < best_err) {
+			best_err = err;
+			idx = i;
+			best = found;
+		}
+		if (!err)
+			break;
+	}
+
+	geo->in_height = best;
+	geo->scale_idx_v = idx;
+}
+
+/*
+ * Find output geometry, that we can produce, using VOU scaling, closest to
+ * the requested rectangle
+ */
+static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std)
+{
+	unsigned int best_err = UINT_MAX, best, width_max, height_max,
+		img_height_max;
+	int i, idx;
+
+	if (std & V4L2_STD_525_60) {
+		width_max = 858;
+		height_max = 262 * 2;
+		img_height_max = 480;
+	} else {
+		width_max = 864;
+		height_max = 312 * 2;
+		img_height_max = 576;
+	}
+
+	/* Select scales to come as close as possible to the output image */
+	for (i = 0; i < ARRAY_SIZE(vou_scale_h_num); i++) {
+		unsigned int err;
+		unsigned int found = geo->in_width * vou_scale_h_num[i] /
+			vou_scale_h_den[i];
+
+		if (found > VOU_MAX_IMAGE_WIDTH)
+			/* scales increase */
+			break;
+
+		err = abs(found - geo->output.width);
+		if (err < best_err) {
+			best_err = err;
+			idx = i;
+			best = found;
+		}
+		if (!err)
+			break;
+	}
+
+	geo->output.width = best;
+	geo->scale_idx_h = idx;
+	if (geo->output.left + best > width_max)
+		geo->output.left = width_max - best;
+
+	pr_debug("%s(): W %u * %u/%u = %u\n", __func__, geo->in_width,
+		 vou_scale_h_num[idx], vou_scale_h_den[idx], best);
+
+	best_err = UINT_MAX;
+
+	/* This loop can be replaced with one division */
+	for (i = 0; i < ARRAY_SIZE(vou_scale_v_num); i++) {
+		unsigned int err;
+		unsigned int found = geo->in_height * vou_scale_v_num[i] /
+			vou_scale_v_den[i];
+
+		if (found > img_height_max)
+			/* scales increase */
+			break;
+
+		err = abs(found - geo->output.height);
+		if (err < best_err) {
+			best_err = err;
+			idx = i;
+			best = found;
+		}
+		if (!err)
+			break;
+	}
+
+	geo->output.height = best;
+	geo->scale_idx_v = idx;
+	if (geo->output.top + best > height_max)
+		geo->output.top = height_max - best;
+
+	pr_debug("%s(): H %u * %u/%u = %u\n", __func__, geo->in_height,
+		 vou_scale_v_num[idx], vou_scale_v_den[idx], best);
+}
+
+static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+	unsigned int img_height_max;
+	int pix_idx;
+	struct sh_vou_geometry geo;
+	struct v4l2_mbus_framefmt mbfmt = {
+		/* Revisit: is this the correct code? */
+		.code = V4L2_MBUS_FMT_YUYV8_2X8,
+		.field = V4L2_FIELD_INTERLACED,
+		.colorspace = V4L2_COLORSPACE_SMPTE170M,
+	};
+	int ret;
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__,
+		vou_dev->rect.width, vou_dev->rect.height,
+		pix->width, pix->height);
+
+	if (pix->field == V4L2_FIELD_ANY)
+		pix->field = V4L2_FIELD_NONE;
+
+	if (fmt->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+	    pix->field != V4L2_FIELD_NONE)
+		return -EINVAL;
+
+	for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++)
+		if (vou_fmt[pix_idx].pfmt == pix->pixelformat)
+			break;
+
+	if (pix_idx == ARRAY_SIZE(vou_fmt))
+		return -EINVAL;
+
+	if (vou_dev->std & V4L2_STD_525_60)
+		img_height_max = 480;
+	else
+		img_height_max = 576;
+
+	/* Image width must be a multiple of 4 */
+	v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 2,
+			      &pix->height, 0, img_height_max, 1, 0);
+
+	geo.in_width = pix->width;
+	geo.in_height = pix->height;
+	geo.output = vou_dev->rect;
+
+	vou_adjust_output(&geo, vou_dev->std);
+
+	mbfmt.width = geo.output.width;
+	mbfmt.height = geo.output.height;
+	ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
+					 s_mbus_fmt, &mbfmt);
+	/* Must be implemented, so, don't check for -ENOIOCTLCMD */
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__,
+		geo.output.width, geo.output.height, mbfmt.width, mbfmt.height);
+
+	/* Sanity checks */
+	if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
+	    (unsigned)mbfmt.height > img_height_max ||
+	    mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
+		return -EIO;
+
+	if (mbfmt.width != geo.output.width ||
+	    mbfmt.height != geo.output.height) {
+		geo.output.width = mbfmt.width;
+		geo.output.height = mbfmt.height;
+
+		vou_adjust_input(&geo, vou_dev->std);
+	}
+
+	/* We tried to preserve output rectangle, but it could have changed */
+	vou_dev->rect = geo.output;
+	pix->width = geo.in_width;
+	pix->height = geo.in_height;
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u\n", __func__,
+		pix->width, pix->height);
+
+	vou_dev->pix_idx = pix_idx;
+
+	vou_dev->pix = *pix;
+
+	sh_vou_configure_geometry(vou_dev, pix_idx,
+				  geo.scale_idx_h, geo.scale_idx_v);
+
+	return 0;
+}
+
+static int sh_vou_try_fmt_vid_out(struct file *file, void *priv,
+				  struct v4l2_format *fmt)
+{
+	struct sh_vou_file *vou_file = priv;
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+	int i;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	pix->field = V4L2_FIELD_NONE;
+
+	v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 1,
+			      &pix->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+
+	for (i = 0; ARRAY_SIZE(vou_fmt); i++)
+		if (vou_fmt[i].pfmt == pix->pixelformat)
+			return 0;
+
+	pix->pixelformat = vou_fmt[0].pfmt;
+
+	return 0;
+}
+
+static int sh_vou_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *req)
+{
+	struct sh_vou_file *vou_file = priv;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	return videobuf_reqbufs(&vou_file->vbq, req);
+}
+
+static int sh_vou_querybuf(struct file *file, void *priv,
+			   struct v4l2_buffer *b)
+{
+	struct sh_vou_file *vou_file = priv;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	return videobuf_querybuf(&vou_file->vbq, b);
+}
+
+static int sh_vou_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct sh_vou_file *vou_file = priv;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	return videobuf_qbuf(&vou_file->vbq, b);
+}
+
+static int sh_vou_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct sh_vou_file *vou_file = priv;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	return videobuf_dqbuf(&vou_file->vbq, b, file->f_flags & O_NONBLOCK);
+}
+
+static int sh_vou_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type buftype)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	struct sh_vou_file *vou_file = priv;
+	int ret;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0,
+					 video, s_stream, 1);
+	if (ret < 0 && ret != -ENOIOCTLCMD)
+		return ret;
+
+	/* This calls our .buf_queue() (== sh_vou_buf_queue) */
+	return videobuf_streamon(&vou_file->vbq);
+}
+
+static int sh_vou_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type buftype)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	struct sh_vou_file *vou_file = priv;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	/*
+	 * This calls buf_release from host driver's videobuf_queue_ops for all
+	 * remaining buffers. When the last buffer is freed, stop streaming
+	 */
+	videobuf_streamoff(&vou_file->vbq);
+	v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, s_stream, 0);
+
+	return 0;
+}
+
+static u32 sh_vou_ntsc_mode(enum sh_vou_bus_fmt bus_fmt)
+{
+	switch (bus_fmt) {
+	default:
+		pr_warning("%s(): Invalid bus-format code %d, using default 8-bit\n",
+			   __func__, bus_fmt);
+	case SH_VOU_BUS_8BIT:
+		return 1;
+	case SH_VOU_BUS_16BIT:
+		return 0;
+	case SH_VOU_BUS_BT656:
+		return 3;
+	}
+}
+
+static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	int ret;
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, *std_id);
+
+	if (*std_id & ~vdev->tvnorms)
+		return -EINVAL;
+
+	ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
+					 s_std_output, *std_id);
+	/* Shall we continue, if the subdev doesn't support .s_std_output()? */
+	if (ret < 0 && ret != -ENOIOCTLCMD)
+		return ret;
+
+	if (*std_id & V4L2_STD_525_60)
+		sh_vou_reg_ab_set(vou_dev, VOUCR,
+			sh_vou_ntsc_mode(vou_dev->pdata->bus_fmt) << 29, 7 << 29);
+	else
+		sh_vou_reg_ab_set(vou_dev, VOUCR, 5 << 29, 7 << 29);
+
+	vou_dev->std = *std_id;
+
+	return 0;
+}
+
+static int sh_vou_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
+
+	*std = vou_dev->std;
+
+	return 0;
+}
+
+static int sh_vou_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
+
+	a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	a->c = vou_dev->rect;
+
+	return 0;
+}
+
+/* Assume a dull encoder, do all the work ourselves. */
+static int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	struct v4l2_rect *rect = &a->c;
+	struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT};
+	struct v4l2_pix_format *pix = &vou_dev->pix;
+	struct sh_vou_geometry geo;
+	struct v4l2_mbus_framefmt mbfmt = {
+		/* Revisit: is this the correct code? */
+		.code = V4L2_MBUS_FMT_YUYV8_2X8,
+		.field = V4L2_FIELD_INTERLACED,
+		.colorspace = V4L2_COLORSPACE_SMPTE170M,
+	};
+	unsigned int img_height_max;
+	int ret;
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u@%u:%u\n", __func__,
+		rect->width, rect->height, rect->left, rect->top);
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	if (vou_dev->std & V4L2_STD_525_60)
+		img_height_max = 480;
+	else
+		img_height_max = 576;
+
+	v4l_bound_align_image(&rect->width, 0, VOU_MAX_IMAGE_WIDTH, 1,
+			      &rect->height, 0, img_height_max, 1, 0);
+
+	if (rect->width + rect->left > VOU_MAX_IMAGE_WIDTH)
+		rect->left = VOU_MAX_IMAGE_WIDTH - rect->width;
+
+	if (rect->height + rect->top > img_height_max)
+		rect->top = img_height_max - rect->height;
+
+	geo.output = *rect;
+	geo.in_width = pix->width;
+	geo.in_height = pix->height;
+
+	/* Configure the encoder one-to-one, position at 0, ignore errors */
+	sd_crop.c.width = geo.output.width;
+	sd_crop.c.height = geo.output.height;
+	/*
+	 * We first issue a S_CROP, so that the subsequent S_FMT delivers the
+	 * final encoder configuration.
+	 */
+	v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
+				   s_crop, &sd_crop);
+	mbfmt.width = geo.output.width;
+	mbfmt.height = geo.output.height;
+	ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
+					 s_mbus_fmt, &mbfmt);
+	/* Must be implemented, so, don't check for -ENOIOCTLCMD */
+	if (ret < 0)
+		return ret;
+
+	/* Sanity checks */
+	if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
+	    (unsigned)mbfmt.height > img_height_max ||
+	    mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
+		return -EIO;
+
+	geo.output.width = mbfmt.width;
+	geo.output.height = mbfmt.height;
+
+	/*
+	 * No down-scaling. According to the API, current call has precedence:
+	 * http://v4l2spec.bytesex.org/spec/x1904.htm#AEN1954 paragraph two.
+	 */
+	vou_adjust_input(&geo, vou_dev->std);
+
+	/* We tried to preserve output rectangle, but it could have changed */
+	vou_dev->rect = geo.output;
+	pix->width = geo.in_width;
+	pix->height = geo.in_height;
+
+	sh_vou_configure_geometry(vou_dev, vou_dev->pix_idx,
+				  geo.scale_idx_h, geo.scale_idx_v);
+
+	return 0;
+}
+
+/*
+ * Total field: NTSC 858 x 2 * 262/263, PAL 864 x 2 * 312/313, default rectangle
+ * is the initial register values, height takes the interlaced format into
+ * account. The actual image can only go up to 720 x 2 * 240, So, VOUVPR can
+ * actually only meaningfully contain values <= 720 and <= 240 respectively, and
+ * not <= 864 and <= 312.
+ */
+static int sh_vou_cropcap(struct file *file, void *priv,
+			  struct v4l2_cropcap *a)
+{
+	struct sh_vou_file *vou_file = priv;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	a->type				= V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	a->bounds.left			= 0;
+	a->bounds.top			= 0;
+	a->bounds.width			= VOU_MAX_IMAGE_WIDTH;
+	a->bounds.height		= VOU_MAX_IMAGE_HEIGHT;
+	/* Default = max, set VOUDPR = 0, which is not hardware default */
+	a->defrect.left			= 0;
+	a->defrect.top			= 0;
+	a->defrect.width		= VOU_MAX_IMAGE_WIDTH;
+	a->defrect.height		= VOU_MAX_IMAGE_HEIGHT;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static irqreturn_t sh_vou_isr(int irq, void *dev_id)
+{
+	struct sh_vou_device *vou_dev = dev_id;
+	static unsigned long j;
+	struct videobuf_buffer *vb;
+	static int cnt;
+	static int side;
+	u32 irq_status = sh_vou_reg_a_read(vou_dev, VOUIR), masked;
+	u32 vou_status = sh_vou_reg_a_read(vou_dev, VOUSTR);
+
+	if (!(irq_status & 0x300)) {
+		if (printk_timed_ratelimit(&j, 500))
+			dev_warn(vou_dev->v4l2_dev.dev, "IRQ status 0x%x!\n",
+				 irq_status);
+		return IRQ_NONE;
+	}
+
+	spin_lock(&vou_dev->lock);
+	if (!vou_dev->active || list_empty(&vou_dev->queue)) {
+		if (printk_timed_ratelimit(&j, 500))
+			dev_warn(vou_dev->v4l2_dev.dev,
+				 "IRQ without active buffer: %x!\n", irq_status);
+		/* Just ack: buf_release will disable further interrupts */
+		sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x300);
+		spin_unlock(&vou_dev->lock);
+		return IRQ_HANDLED;
+	}
+
+	masked = ~(0x300 & irq_status) & irq_status & 0x30304;
+	dev_dbg(vou_dev->v4l2_dev.dev,
+		"IRQ status 0x%x -> 0x%x, VOU status 0x%x, cnt %d\n",
+		irq_status, masked, vou_status, cnt);
+
+	cnt++;
+	side = vou_status & 0x10000;
+
+	/* Clear only set interrupts */
+	sh_vou_reg_a_write(vou_dev, VOUIR, masked);
+
+	vb = vou_dev->active;
+	list_del(&vb->queue);
+
+	vb->state = VIDEOBUF_DONE;
+	do_gettimeofday(&vb->ts);
+	vb->field_count++;
+	wake_up(&vb->done);
+
+	if (list_empty(&vou_dev->queue)) {
+		/* Stop VOU */
+		dev_dbg(vou_dev->v4l2_dev.dev, "%s: queue empty after %d\n",
+			__func__, cnt);
+		sh_vou_reg_a_set(vou_dev, VOUER, 0, 1);
+		vou_dev->active = NULL;
+		vou_dev->status = SH_VOU_INITIALISING;
+		/* Disable End-of-Frame (VSYNC) interrupts */
+		sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000);
+		spin_unlock(&vou_dev->lock);
+		return IRQ_HANDLED;
+	}
+
+	vou_dev->active = list_entry(vou_dev->queue.next,
+				     struct videobuf_buffer, queue);
+
+	if (vou_dev->active->queue.next != &vou_dev->queue) {
+		struct videobuf_buffer *new = list_entry(vou_dev->active->queue.next,
+						struct videobuf_buffer, queue);
+		sh_vou_schedule_next(vou_dev, new);
+	}
+
+	spin_unlock(&vou_dev->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int sh_vou_hw_init(struct sh_vou_device *vou_dev)
+{
+	struct sh_vou_pdata *pdata = vou_dev->pdata;
+	u32 voucr = sh_vou_ntsc_mode(pdata->bus_fmt) << 29;
+	int i = 100;
+
+	/* Disable all IRQs */
+	sh_vou_reg_a_write(vou_dev, VOUIR, 0);
+
+	/* Reset VOU interfaces - registers unaffected */
+	sh_vou_reg_a_write(vou_dev, VOUSRR, 0x101);
+	while (--i && (sh_vou_reg_a_read(vou_dev, VOUSRR) & 0x101))
+		udelay(1);
+
+	if (!i)
+		return -ETIMEDOUT;
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "Reset took %dus\n", 100 - i);
+
+	if (pdata->flags & SH_VOU_PCLK_FALLING)
+		voucr |= 1 << 28;
+	if (pdata->flags & SH_VOU_HSYNC_LOW)
+		voucr |= 1 << 27;
+	if (pdata->flags & SH_VOU_VSYNC_LOW)
+		voucr |= 1 << 26;
+	sh_vou_reg_ab_set(vou_dev, VOUCR, voucr, 0xfc000000);
+
+	/* Manual register side switching at first */
+	sh_vou_reg_a_write(vou_dev, VOURCR, 4);
+	/* Default - fixed HSYNC length, can be made configurable is required */
+	sh_vou_reg_ab_write(vou_dev, VOUMSR, 0x800000);
+
+	return 0;
+}
+
+/* File operations */
+static int sh_vou_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	struct sh_vou_file *vou_file = kzalloc(sizeof(struct sh_vou_file),
+					       GFP_KERNEL);
+
+	if (!vou_file)
+		return -ENOMEM;
+
+	dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
+
+	file->private_data = vou_file;
+
+	if (mutex_lock_interruptible(&vou_dev->fop_lock))
+		return -ERESTARTSYS;
+	if (atomic_inc_return(&vou_dev->use_count) == 1) {
+		int ret;
+		/* First open */
+		vou_dev->status = SH_VOU_INITIALISING;
+		pm_runtime_get_sync(vdev->v4l2_dev->dev);
+		ret = sh_vou_hw_init(vou_dev);
+		if (ret < 0) {
+			atomic_dec(&vou_dev->use_count);
+			pm_runtime_put(vdev->v4l2_dev->dev);
+			vou_dev->status = SH_VOU_IDLE;
+			mutex_unlock(&vou_dev->fop_lock);
+			return ret;
+		}
+	}
+
+	videobuf_queue_dma_contig_init(&vou_file->vbq, &sh_vou_video_qops,
+				       vou_dev->v4l2_dev.dev, &vou_dev->lock,
+				       V4L2_BUF_TYPE_VIDEO_OUTPUT,
+				       V4L2_FIELD_NONE,
+				       sizeof(struct videobuf_buffer), vdev,
+				       &vou_dev->fop_lock);
+	mutex_unlock(&vou_dev->fop_lock);
+
+	return 0;
+}
+
+static int sh_vou_release(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	struct sh_vou_file *vou_file = file->private_data;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	if (!atomic_dec_return(&vou_dev->use_count)) {
+		mutex_lock(&vou_dev->fop_lock);
+		/* Last close */
+		vou_dev->status = SH_VOU_IDLE;
+		sh_vou_reg_a_set(vou_dev, VOUER, 0, 0x101);
+		pm_runtime_put(vdev->v4l2_dev->dev);
+		mutex_unlock(&vou_dev->fop_lock);
+	}
+
+	file->private_data = NULL;
+	kfree(vou_file);
+
+	return 0;
+}
+
+static int sh_vou_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	struct sh_vou_file *vou_file = file->private_data;
+	int ret;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	if (mutex_lock_interruptible(&vou_dev->fop_lock))
+		return -ERESTARTSYS;
+	ret = videobuf_mmap_mapper(&vou_file->vbq, vma);
+	mutex_unlock(&vou_dev->fop_lock);
+	return ret;
+}
+
+static unsigned int sh_vou_poll(struct file *file, poll_table *wait)
+{
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+	struct sh_vou_file *vou_file = file->private_data;
+	unsigned int res;
+
+	dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+	mutex_lock(&vou_dev->fop_lock);
+	res = videobuf_poll_stream(file, &vou_file->vbq, wait);
+	mutex_unlock(&vou_dev->fop_lock);
+	return res;
+}
+
+static int sh_vou_g_chip_ident(struct file *file, void *fh,
+				   struct v4l2_dbg_chip_ident *id)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+	return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_chip_ident, id);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int sh_vou_g_register(struct file *file, void *fh,
+				 struct v4l2_dbg_register *reg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+	return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_register, reg);
+}
+
+static int sh_vou_s_register(struct file *file, void *fh,
+				 struct v4l2_dbg_register *reg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+	return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, s_register, reg);
+}
+#endif
+
+/* sh_vou display ioctl operations */
+static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = {
+	.vidioc_querycap        	= sh_vou_querycap,
+	.vidioc_enum_fmt_vid_out	= sh_vou_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out		= sh_vou_g_fmt_vid_out,
+	.vidioc_s_fmt_vid_out		= sh_vou_s_fmt_vid_out,
+	.vidioc_try_fmt_vid_out		= sh_vou_try_fmt_vid_out,
+	.vidioc_reqbufs			= sh_vou_reqbufs,
+	.vidioc_querybuf		= sh_vou_querybuf,
+	.vidioc_qbuf			= sh_vou_qbuf,
+	.vidioc_dqbuf			= sh_vou_dqbuf,
+	.vidioc_streamon		= sh_vou_streamon,
+	.vidioc_streamoff		= sh_vou_streamoff,
+	.vidioc_s_std			= sh_vou_s_std,
+	.vidioc_g_std			= sh_vou_g_std,
+	.vidioc_cropcap			= sh_vou_cropcap,
+	.vidioc_g_crop			= sh_vou_g_crop,
+	.vidioc_s_crop			= sh_vou_s_crop,
+	.vidioc_g_chip_ident		= sh_vou_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register		= sh_vou_g_register,
+	.vidioc_s_register		= sh_vou_s_register,
+#endif
+};
+
+static const struct v4l2_file_operations sh_vou_fops = {
+	.owner		= THIS_MODULE,
+	.open		= sh_vou_open,
+	.release	= sh_vou_release,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= sh_vou_mmap,
+	.poll		= sh_vou_poll,
+};
+
+static const struct video_device sh_vou_video_template = {
+	.name		= "sh_vou",
+	.fops		= &sh_vou_fops,
+	.ioctl_ops	= &sh_vou_ioctl_ops,
+	.tvnorms	= V4L2_STD_525_60, /* PAL only supported in 8-bit non-bt656 mode */
+	.current_norm	= V4L2_STD_NTSC_M,
+};
+
+static int __devinit sh_vou_probe(struct platform_device *pdev)
+{
+	struct sh_vou_pdata *vou_pdata = pdev->dev.platform_data;
+	struct v4l2_rect *rect;
+	struct v4l2_pix_format *pix;
+	struct i2c_adapter *i2c_adap;
+	struct video_device *vdev;
+	struct sh_vou_device *vou_dev;
+	struct resource *reg_res, *region;
+	struct v4l2_subdev *subdev;
+	int irq, ret;
+
+	reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(pdev, 0);
+
+	if (!vou_pdata || !reg_res || irq <= 0) {
+		dev_err(&pdev->dev, "Insufficient VOU platform information.\n");
+		return -ENODEV;
+	}
+
+	vou_dev = kzalloc(sizeof(*vou_dev), GFP_KERNEL);
+	if (!vou_dev)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&vou_dev->queue);
+	spin_lock_init(&vou_dev->lock);
+	mutex_init(&vou_dev->fop_lock);
+	atomic_set(&vou_dev->use_count, 0);
+	vou_dev->pdata = vou_pdata;
+	vou_dev->status = SH_VOU_IDLE;
+
+	rect = &vou_dev->rect;
+	pix = &vou_dev->pix;
+
+	/* Fill in defaults */
+	vou_dev->std		= sh_vou_video_template.current_norm;
+	rect->left		= 0;
+	rect->top		= 0;
+	rect->width		= VOU_MAX_IMAGE_WIDTH;
+	rect->height		= 480;
+	pix->width		= VOU_MAX_IMAGE_WIDTH;
+	pix->height		= 480;
+	pix->pixelformat	= V4L2_PIX_FMT_YVYU;
+	pix->field		= V4L2_FIELD_NONE;
+	pix->bytesperline	= VOU_MAX_IMAGE_WIDTH * 2;
+	pix->sizeimage		= VOU_MAX_IMAGE_WIDTH * 2 * 480;
+	pix->colorspace		= V4L2_COLORSPACE_SMPTE170M;
+
+	region = request_mem_region(reg_res->start, resource_size(reg_res),
+				    pdev->name);
+	if (!region) {
+		dev_err(&pdev->dev, "VOU region already claimed\n");
+		ret = -EBUSY;
+		goto ereqmemreg;
+	}
+
+	vou_dev->base = ioremap(reg_res->start, resource_size(reg_res));
+	if (!vou_dev->base) {
+		ret = -ENOMEM;
+		goto emap;
+	}
+
+	ret = request_irq(irq, sh_vou_isr, 0, "vou", vou_dev);
+	if (ret < 0)
+		goto ereqirq;
+
+	ret = v4l2_device_register(&pdev->dev, &vou_dev->v4l2_dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Error registering v4l2 device\n");
+		goto ev4l2devreg;
+	}
+
+	/* Allocate memory for video device */
+	vdev = video_device_alloc();
+	if (vdev == NULL) {
+		ret = -ENOMEM;
+		goto evdevalloc;
+	}
+
+	*vdev = sh_vou_video_template;
+	if (vou_pdata->bus_fmt == SH_VOU_BUS_8BIT)
+		vdev->tvnorms |= V4L2_STD_PAL;
+	vdev->v4l2_dev = &vou_dev->v4l2_dev;
+	vdev->release = video_device_release;
+	vdev->lock = &vou_dev->fop_lock;
+
+	vou_dev->vdev = vdev;
+	video_set_drvdata(vdev, vou_dev);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_resume(&pdev->dev);
+
+	i2c_adap = i2c_get_adapter(vou_pdata->i2c_adap);
+	if (!i2c_adap) {
+		ret = -ENODEV;
+		goto ei2cgadap;
+	}
+
+	ret = sh_vou_hw_init(vou_dev);
+	if (ret < 0)
+		goto ereset;
+
+	subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap,
+			vou_pdata->board_info, NULL);
+	if (!subdev) {
+		ret = -ENOMEM;
+		goto ei2cnd;
+	}
+
+	ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+	if (ret < 0)
+		goto evregdev;
+
+	return 0;
+
+evregdev:
+ei2cnd:
+ereset:
+	i2c_put_adapter(i2c_adap);
+ei2cgadap:
+	video_device_release(vdev);
+	pm_runtime_disable(&pdev->dev);
+evdevalloc:
+	v4l2_device_unregister(&vou_dev->v4l2_dev);
+ev4l2devreg:
+	free_irq(irq, vou_dev);
+ereqirq:
+	iounmap(vou_dev->base);
+emap:
+	release_mem_region(reg_res->start, resource_size(reg_res));
+ereqmemreg:
+	kfree(vou_dev);
+	return ret;
+}
+
+static int __devexit sh_vou_remove(struct platform_device *pdev)
+{
+	int irq = platform_get_irq(pdev, 0);
+	struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+	struct sh_vou_device *vou_dev = container_of(v4l2_dev,
+						struct sh_vou_device, v4l2_dev);
+	struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next,
+					    struct v4l2_subdev, list);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct resource *reg_res;
+
+	if (irq > 0)
+		free_irq(irq, vou_dev);
+	pm_runtime_disable(&pdev->dev);
+	video_unregister_device(vou_dev->vdev);
+	i2c_put_adapter(client->adapter);
+	v4l2_device_unregister(&vou_dev->v4l2_dev);
+	iounmap(vou_dev->base);
+	reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (reg_res)
+		release_mem_region(reg_res->start, resource_size(reg_res));
+	kfree(vou_dev);
+	return 0;
+}
+
+static struct platform_driver __refdata sh_vou = {
+	.remove  = __devexit_p(sh_vou_remove),
+	.driver  = {
+		.name	= "sh-vou",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init sh_vou_init(void)
+{
+	return platform_driver_probe(&sh_vou, sh_vou_probe);
+}
+
+static void __exit sh_vou_exit(void)
+{
+	platform_driver_unregister(&sh_vou);
+}
+
+module_init(sh_vou_init);
+module_exit(sh_vou_exit);
+
+MODULE_DESCRIPTION("SuperH VOU driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.1.0");
+MODULE_ALIAS("platform:sh-vou");
diff --git a/drivers/media/platform/soc_camera.c b/drivers/media/platform/soc_camera.c
new file mode 100644
index 0000000..10b57f8
--- /dev/null
+++ b/drivers/media/platform/soc_camera.c
@@ -0,0 +1,1605 @@
+/*
+ * camera image capture (abstract) bus driver
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This driver provides an interface between platform-specific camera
+ * busses and camera devices. It should be used if the camera is
+ * connected not over a "proper" bus like PCI or USB, but over a
+ * special bus, like, for example, the Quick Capture interface on PXA270
+ * SoCs. Later it should also be used for i.MX31 SoCs from Freescale.
+ * It can handle multiple cameras and / or multiple busses, which can
+ * be used, e.g., in stereo-vision applications.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/vmalloc.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf-core.h>
+#include <media/videobuf2-core.h>
+#include <media/soc_mediabus.h>
+
+/* Default to VGA resolution */
+#define DEFAULT_WIDTH	640
+#define DEFAULT_HEIGHT	480
+
+#define is_streaming(ici, icd)				\
+	(((ici)->ops->init_videobuf) ?			\
+	 (icd)->vb_vidq.streaming :			\
+	 vb2_is_streaming(&(icd)->vb2_vidq))
+
+static LIST_HEAD(hosts);
+static LIST_HEAD(devices);
+static DEFINE_MUTEX(list_lock);		/* Protects the list of hosts */
+
+int soc_camera_power_on(struct device *dev, struct soc_camera_link *icl)
+{
+	int ret = regulator_bulk_enable(icl->num_regulators,
+					icl->regulators);
+	if (ret < 0) {
+		dev_err(dev, "Cannot enable regulators\n");
+		return ret;
+	}
+
+	if (icl->power) {
+		ret = icl->power(dev, 1);
+		if (ret < 0) {
+			dev_err(dev,
+				"Platform failed to power-on the camera.\n");
+			regulator_bulk_disable(icl->num_regulators,
+					       icl->regulators);
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(soc_camera_power_on);
+
+int soc_camera_power_off(struct device *dev, struct soc_camera_link *icl)
+{
+	int ret = 0;
+	int err;
+
+	if (icl->power) {
+		err = icl->power(dev, 0);
+		if (err < 0) {
+			dev_err(dev,
+				"Platform failed to power-off the camera.\n");
+			ret = err;
+		}
+	}
+
+	err = regulator_bulk_disable(icl->num_regulators,
+				     icl->regulators);
+	if (err < 0) {
+		dev_err(dev, "Cannot disable regulators\n");
+		ret = ret ? : err;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(soc_camera_power_off);
+
+static int __soc_camera_power_on(struct soc_camera_device *icd)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	int ret;
+
+	ret = v4l2_subdev_call(sd, core, s_power, 1);
+	if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
+		return ret;
+
+	return 0;
+}
+
+static int __soc_camera_power_off(struct soc_camera_device *icd)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	int ret;
+
+	ret = v4l2_subdev_call(sd, core, s_power, 0);
+	if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
+		return ret;
+
+	return 0;
+}
+
+const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
+	struct soc_camera_device *icd, unsigned int fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < icd->num_user_formats; i++)
+		if (icd->user_formats[i].host_fmt->fourcc == fourcc)
+			return icd->user_formats + i;
+	return NULL;
+}
+EXPORT_SYMBOL(soc_camera_xlate_by_fourcc);
+
+/**
+ * soc_camera_apply_board_flags() - apply platform SOCAM_SENSOR_INVERT_* flags
+ * @icl:	camera platform parameters
+ * @cfg:	media bus configuration
+ * @return:	resulting flags
+ */
+unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl,
+					   const struct v4l2_mbus_config *cfg)
+{
+	unsigned long f, flags = cfg->flags;
+
+	/* If only one of the two polarities is supported, switch to the opposite */
+	if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) {
+		f = flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW);
+		if (f == V4L2_MBUS_HSYNC_ACTIVE_HIGH || f == V4L2_MBUS_HSYNC_ACTIVE_LOW)
+			flags ^= V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW;
+	}
+
+	if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) {
+		f = flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW);
+		if (f == V4L2_MBUS_VSYNC_ACTIVE_HIGH || f == V4L2_MBUS_VSYNC_ACTIVE_LOW)
+			flags ^= V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW;
+	}
+
+	if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) {
+		f = flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING);
+		if (f == V4L2_MBUS_PCLK_SAMPLE_RISING || f == V4L2_MBUS_PCLK_SAMPLE_FALLING)
+			flags ^= V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING;
+	}
+
+	return flags;
+}
+EXPORT_SYMBOL(soc_camera_apply_board_flags);
+
+#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \
+	((x) >> 24) & 0xff
+
+static int soc_camera_try_fmt(struct soc_camera_device *icd,
+			      struct v4l2_format *f)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	const struct soc_camera_format_xlate *xlate;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	int ret;
+
+	dev_dbg(icd->pdev, "TRY_FMT(%c%c%c%c, %ux%u)\n",
+		pixfmtstr(pix->pixelformat), pix->width, pix->height);
+
+	if (pix->pixelformat != V4L2_PIX_FMT_JPEG &&
+	    !(ici->capabilities & SOCAM_HOST_CAP_STRIDE)) {
+		pix->bytesperline = 0;
+		pix->sizeimage = 0;
+	}
+
+	ret = ici->ops->try_fmt(icd, f);
+	if (ret < 0)
+		return ret;
+
+	xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+	if (!xlate)
+		return -EINVAL;
+
+	ret = soc_mbus_bytes_per_line(pix->width, xlate->host_fmt);
+	if (ret < 0)
+		return ret;
+
+	pix->bytesperline = max_t(u32, pix->bytesperline, ret);
+
+	ret = soc_mbus_image_size(xlate->host_fmt, pix->bytesperline,
+				  pix->height);
+	if (ret < 0)
+		return ret;
+
+	pix->sizeimage = max_t(u32, pix->sizeimage, ret);
+
+	return 0;
+}
+
+static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
+				      struct v4l2_format *f)
+{
+	struct soc_camera_device *icd = file->private_data;
+
+	WARN_ON(priv != file->private_data);
+
+	/* Only single-plane capture is supported so far */
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	/* limit format to hardware capabilities */
+	return soc_camera_try_fmt(icd, f);
+}
+
+static int soc_camera_enum_input(struct file *file, void *priv,
+				 struct v4l2_input *inp)
+{
+	if (inp->index != 0)
+		return -EINVAL;
+
+	/* default is camera */
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+	inp->std  = V4L2_STD_UNKNOWN;
+	strcpy(inp->name, "Camera");
+
+	return 0;
+}
+
+static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	*i = 0;
+
+	return 0;
+}
+
+static int soc_camera_s_input(struct file *file, void *priv, unsigned int i)
+{
+	if (i > 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+
+	return v4l2_subdev_call(sd, core, s_std, *a);
+}
+
+static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+
+	return v4l2_subdev_call(sd, core, g_std, a);
+}
+
+static int soc_camera_enum_framesizes(struct file *file, void *fh,
+					 struct v4l2_frmsizeenum *fsize)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+	return ici->ops->enum_framesizes(icd, fsize);
+}
+
+static int soc_camera_reqbufs(struct file *file, void *priv,
+			      struct v4l2_requestbuffers *p)
+{
+	int ret;
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+	WARN_ON(priv != file->private_data);
+
+	if (icd->streamer && icd->streamer != file)
+		return -EBUSY;
+
+	if (ici->ops->init_videobuf) {
+		ret = videobuf_reqbufs(&icd->vb_vidq, p);
+		if (ret < 0)
+			return ret;
+
+		ret = ici->ops->reqbufs(icd, p);
+	} else {
+		ret = vb2_reqbufs(&icd->vb2_vidq, p);
+	}
+
+	if (!ret && !icd->streamer)
+		icd->streamer = file;
+
+	return ret;
+}
+
+static int soc_camera_querybuf(struct file *file, void *priv,
+			       struct v4l2_buffer *p)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+	WARN_ON(priv != file->private_data);
+
+	if (ici->ops->init_videobuf)
+		return videobuf_querybuf(&icd->vb_vidq, p);
+	else
+		return vb2_querybuf(&icd->vb2_vidq, p);
+}
+
+static int soc_camera_qbuf(struct file *file, void *priv,
+			   struct v4l2_buffer *p)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+	WARN_ON(priv != file->private_data);
+
+	if (icd->streamer != file)
+		return -EBUSY;
+
+	if (ici->ops->init_videobuf)
+		return videobuf_qbuf(&icd->vb_vidq, p);
+	else
+		return vb2_qbuf(&icd->vb2_vidq, p);
+}
+
+static int soc_camera_dqbuf(struct file *file, void *priv,
+			    struct v4l2_buffer *p)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+	WARN_ON(priv != file->private_data);
+
+	if (icd->streamer != file)
+		return -EBUSY;
+
+	if (ici->ops->init_videobuf)
+		return videobuf_dqbuf(&icd->vb_vidq, p, file->f_flags & O_NONBLOCK);
+	else
+		return vb2_dqbuf(&icd->vb2_vidq, p, file->f_flags & O_NONBLOCK);
+}
+
+static int soc_camera_create_bufs(struct file *file, void *priv,
+			    struct v4l2_create_buffers *create)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+	/* videobuf2 only */
+	if (ici->ops->init_videobuf)
+		return -EINVAL;
+	else
+		return vb2_create_bufs(&icd->vb2_vidq, create);
+}
+
+static int soc_camera_prepare_buf(struct file *file, void *priv,
+				  struct v4l2_buffer *b)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+	/* videobuf2 only */
+	if (ici->ops->init_videobuf)
+		return -EINVAL;
+	else
+		return vb2_prepare_buf(&icd->vb2_vidq, b);
+}
+
+/* Always entered with .video_lock held */
+static int soc_camera_init_user_formats(struct soc_camera_device *icd)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	unsigned int i, fmts = 0, raw_fmts = 0;
+	int ret;
+	enum v4l2_mbus_pixelcode code;
+
+	while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code))
+		raw_fmts++;
+
+	if (!ici->ops->get_formats)
+		/*
+		 * Fallback mode - the host will have to serve all
+		 * sensor-provided formats one-to-one to the user
+		 */
+		fmts = raw_fmts;
+	else
+		/*
+		 * First pass - only count formats this host-sensor
+		 * configuration can provide
+		 */
+		for (i = 0; i < raw_fmts; i++) {
+			ret = ici->ops->get_formats(icd, i, NULL);
+			if (ret < 0)
+				return ret;
+			fmts += ret;
+		}
+
+	if (!fmts)
+		return -ENXIO;
+
+	icd->user_formats =
+		vmalloc(fmts * sizeof(struct soc_camera_format_xlate));
+	if (!icd->user_formats)
+		return -ENOMEM;
+
+	dev_dbg(icd->pdev, "Found %d supported formats.\n", fmts);
+
+	/* Second pass - actually fill data formats */
+	fmts = 0;
+	for (i = 0; i < raw_fmts; i++)
+		if (!ici->ops->get_formats) {
+			v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &code);
+			icd->user_formats[fmts].host_fmt =
+				soc_mbus_get_fmtdesc(code);
+			if (icd->user_formats[fmts].host_fmt)
+				icd->user_formats[fmts++].code = code;
+		} else {
+			ret = ici->ops->get_formats(icd, i,
+						    &icd->user_formats[fmts]);
+			if (ret < 0)
+				goto egfmt;
+			fmts += ret;
+		}
+
+	icd->num_user_formats = fmts;
+	icd->current_fmt = &icd->user_formats[0];
+
+	return 0;
+
+egfmt:
+	vfree(icd->user_formats);
+	return ret;
+}
+
+/* Always entered with .video_lock held */
+static void soc_camera_free_user_formats(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+	if (ici->ops->put_formats)
+		ici->ops->put_formats(icd);
+	icd->current_fmt = NULL;
+	icd->num_user_formats = 0;
+	vfree(icd->user_formats);
+	icd->user_formats = NULL;
+}
+
+/* Called with .vb_lock held, or from the first open(2), see comment there */
+static int soc_camera_set_fmt(struct soc_camera_device *icd,
+			      struct v4l2_format *f)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	int ret;
+
+	dev_dbg(icd->pdev, "S_FMT(%c%c%c%c, %ux%u)\n",
+		pixfmtstr(pix->pixelformat), pix->width, pix->height);
+
+	/* We always call try_fmt() before set_fmt() or set_crop() */
+	ret = soc_camera_try_fmt(icd, f);
+	if (ret < 0)
+		return ret;
+
+	ret = ici->ops->set_fmt(icd, f);
+	if (ret < 0) {
+		return ret;
+	} else if (!icd->current_fmt ||
+		   icd->current_fmt->host_fmt->fourcc != pix->pixelformat) {
+		dev_err(icd->pdev,
+			"Host driver hasn't set up current format correctly!\n");
+		return -EINVAL;
+	}
+
+	icd->user_width		= pix->width;
+	icd->user_height	= pix->height;
+	icd->bytesperline	= pix->bytesperline;
+	icd->sizeimage		= pix->sizeimage;
+	icd->colorspace		= pix->colorspace;
+	icd->field		= pix->field;
+	if (ici->ops->init_videobuf)
+		icd->vb_vidq.field = pix->field;
+
+	dev_dbg(icd->pdev, "set width: %d height: %d\n",
+		icd->user_width, icd->user_height);
+
+	/* set physical bus parameters */
+	return ici->ops->set_bus_param(icd);
+}
+
+static int soc_camera_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct soc_camera_device *icd = dev_get_drvdata(vdev->parent);
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
+	struct soc_camera_host *ici;
+	int ret;
+
+	if (!to_soc_camera_control(icd))
+		/* No device driver attached */
+		return -ENODEV;
+
+	ici = to_soc_camera_host(icd->parent);
+
+	if (mutex_lock_interruptible(&icd->video_lock))
+		return -ERESTARTSYS;
+	if (!try_module_get(ici->ops->owner)) {
+		dev_err(icd->pdev, "Couldn't lock capture bus driver.\n");
+		ret = -EINVAL;
+		goto emodule;
+	}
+
+	icd->use_count++;
+
+	/* Now we really have to activate the camera */
+	if (icd->use_count == 1) {
+		/* Restore parameters before the last close() per V4L2 API */
+		struct v4l2_format f = {
+			.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			.fmt.pix = {
+				.width		= icd->user_width,
+				.height		= icd->user_height,
+				.field		= icd->field,
+				.colorspace	= icd->colorspace,
+				.pixelformat	=
+					icd->current_fmt->host_fmt->fourcc,
+			},
+		};
+
+		/* The camera could have been already on, try to reset */
+		if (icl->reset)
+			icl->reset(icd->pdev);
+
+		/* Don't mess with the host during probe */
+		mutex_lock(&ici->host_lock);
+		ret = ici->ops->add(icd);
+		mutex_unlock(&ici->host_lock);
+		if (ret < 0) {
+			dev_err(icd->pdev, "Couldn't activate the camera: %d\n", ret);
+			goto eiciadd;
+		}
+
+		ret = __soc_camera_power_on(icd);
+		if (ret < 0)
+			goto epower;
+
+		pm_runtime_enable(&icd->vdev->dev);
+		ret = pm_runtime_resume(&icd->vdev->dev);
+		if (ret < 0 && ret != -ENOSYS)
+			goto eresume;
+
+		/*
+		 * Try to configure with default parameters. Notice: this is the
+		 * very first open, so, we cannot race against other calls,
+		 * apart from someone else calling open() simultaneously, but
+		 * .video_lock is protecting us against it.
+		 */
+		ret = soc_camera_set_fmt(icd, &f);
+		if (ret < 0)
+			goto esfmt;
+
+		if (ici->ops->init_videobuf) {
+			ici->ops->init_videobuf(&icd->vb_vidq, icd);
+		} else {
+			ret = ici->ops->init_videobuf2(&icd->vb2_vidq, icd);
+			if (ret < 0)
+				goto einitvb;
+		}
+		v4l2_ctrl_handler_setup(&icd->ctrl_handler);
+	}
+	mutex_unlock(&icd->video_lock);
+
+	file->private_data = icd;
+	dev_dbg(icd->pdev, "camera device open\n");
+
+	return 0;
+
+	/*
+	 * First four errors are entered with the .video_lock held
+	 * and use_count == 1
+	 */
+einitvb:
+esfmt:
+	pm_runtime_disable(&icd->vdev->dev);
+eresume:
+	__soc_camera_power_off(icd);
+epower:
+	ici->ops->remove(icd);
+eiciadd:
+	icd->use_count--;
+	module_put(ici->ops->owner);
+emodule:
+	mutex_unlock(&icd->video_lock);
+
+	return ret;
+}
+
+static int soc_camera_close(struct file *file)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+	mutex_lock(&icd->video_lock);
+	icd->use_count--;
+	if (!icd->use_count) {
+		pm_runtime_suspend(&icd->vdev->dev);
+		pm_runtime_disable(&icd->vdev->dev);
+
+		if (ici->ops->init_videobuf2)
+			vb2_queue_release(&icd->vb2_vidq);
+		ici->ops->remove(icd);
+
+		__soc_camera_power_off(icd);
+	}
+
+	if (icd->streamer == file)
+		icd->streamer = NULL;
+	mutex_unlock(&icd->video_lock);
+
+	module_put(ici->ops->owner);
+
+	dev_dbg(icd->pdev, "camera device close\n");
+
+	return 0;
+}
+
+static ssize_t soc_camera_read(struct file *file, char __user *buf,
+			       size_t count, loff_t *ppos)
+{
+	struct soc_camera_device *icd = file->private_data;
+	int err = -EINVAL;
+
+	dev_err(icd->pdev, "camera device read not implemented\n");
+
+	return err;
+}
+
+static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	int err;
+
+	dev_dbg(icd->pdev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+
+	if (icd->streamer != file)
+		return -EBUSY;
+
+	if (mutex_lock_interruptible(&icd->video_lock))
+		return -ERESTARTSYS;
+	if (ici->ops->init_videobuf)
+		err = videobuf_mmap_mapper(&icd->vb_vidq, vma);
+	else
+		err = vb2_mmap(&icd->vb2_vidq, vma);
+	mutex_unlock(&icd->video_lock);
+
+	dev_dbg(icd->pdev, "vma start=0x%08lx, size=%ld, ret=%d\n",
+		(unsigned long)vma->vm_start,
+		(unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
+		err);
+
+	return err;
+}
+
+static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	unsigned res = POLLERR;
+
+	if (icd->streamer != file)
+		return POLLERR;
+
+	mutex_lock(&icd->video_lock);
+	if (ici->ops->init_videobuf && list_empty(&icd->vb_vidq.stream))
+		dev_err(icd->pdev, "Trying to poll with no queued buffers!\n");
+	else
+		res = ici->ops->poll(file, pt);
+	mutex_unlock(&icd->video_lock);
+	return res;
+}
+
+void soc_camera_lock(struct vb2_queue *vq)
+{
+	struct soc_camera_device *icd = vb2_get_drv_priv(vq);
+	mutex_lock(&icd->video_lock);
+}
+EXPORT_SYMBOL(soc_camera_lock);
+
+void soc_camera_unlock(struct vb2_queue *vq)
+{
+	struct soc_camera_device *icd = vb2_get_drv_priv(vq);
+	mutex_unlock(&icd->video_lock);
+}
+EXPORT_SYMBOL(soc_camera_unlock);
+
+static struct v4l2_file_operations soc_camera_fops = {
+	.owner		= THIS_MODULE,
+	.open		= soc_camera_open,
+	.release	= soc_camera_close,
+	.unlocked_ioctl	= video_ioctl2,
+	.read		= soc_camera_read,
+	.mmap		= soc_camera_mmap,
+	.poll		= soc_camera_poll,
+};
+
+static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
+				    struct v4l2_format *f)
+{
+	struct soc_camera_device *icd = file->private_data;
+	int ret;
+
+	WARN_ON(priv != file->private_data);
+
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		dev_warn(icd->pdev, "Wrong buf-type %d\n", f->type);
+		return -EINVAL;
+	}
+
+	if (icd->streamer && icd->streamer != file)
+		return -EBUSY;
+
+	if (is_streaming(to_soc_camera_host(icd->parent), icd)) {
+		dev_err(icd->pdev, "S_FMT denied: queue initialised\n");
+		return -EBUSY;
+	}
+
+	ret = soc_camera_set_fmt(icd, f);
+
+	if (!ret && !icd->streamer)
+		icd->streamer = file;
+
+	return ret;
+}
+
+static int soc_camera_enum_fmt_vid_cap(struct file *file, void  *priv,
+				       struct v4l2_fmtdesc *f)
+{
+	struct soc_camera_device *icd = file->private_data;
+	const struct soc_mbus_pixelfmt *format;
+
+	WARN_ON(priv != file->private_data);
+
+	if (f->index >= icd->num_user_formats)
+		return -EINVAL;
+
+	format = icd->user_formats[f->index].host_fmt;
+
+	if (format->name)
+		strlcpy(f->description, format->name, sizeof(f->description));
+	f->pixelformat = format->fourcc;
+	return 0;
+}
+
+static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
+				    struct v4l2_format *f)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+
+	WARN_ON(priv != file->private_data);
+
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	pix->width		= icd->user_width;
+	pix->height		= icd->user_height;
+	pix->bytesperline	= icd->bytesperline;
+	pix->sizeimage		= icd->sizeimage;
+	pix->field		= icd->field;
+	pix->pixelformat	= icd->current_fmt->host_fmt->fourcc;
+	pix->colorspace		= icd->colorspace;
+	dev_dbg(icd->pdev, "current_fmt->fourcc: 0x%08x\n",
+		icd->current_fmt->host_fmt->fourcc);
+	return 0;
+}
+
+static int soc_camera_querycap(struct file *file, void  *priv,
+			       struct v4l2_capability *cap)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+	WARN_ON(priv != file->private_data);
+
+	strlcpy(cap->driver, ici->drv_name, sizeof(cap->driver));
+	return ici->ops->querycap(ici, cap);
+}
+
+static int soc_camera_streamon(struct file *file, void *priv,
+			       enum v4l2_buf_type i)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	int ret;
+
+	WARN_ON(priv != file->private_data);
+
+	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (icd->streamer != file)
+		return -EBUSY;
+
+	/* This calls buf_queue from host driver's videobuf_queue_ops */
+	if (ici->ops->init_videobuf)
+		ret = videobuf_streamon(&icd->vb_vidq);
+	else
+		ret = vb2_streamon(&icd->vb2_vidq, i);
+
+	if (!ret)
+		v4l2_subdev_call(sd, video, s_stream, 1);
+
+	return ret;
+}
+
+static int soc_camera_streamoff(struct file *file, void *priv,
+				enum v4l2_buf_type i)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+	WARN_ON(priv != file->private_data);
+
+	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (icd->streamer != file)
+		return -EBUSY;
+
+	/*
+	 * This calls buf_release from host driver's videobuf_queue_ops for all
+	 * remaining buffers. When the last buffer is freed, stop capture
+	 */
+	if (ici->ops->init_videobuf)
+		videobuf_streamoff(&icd->vb_vidq);
+	else
+		vb2_streamoff(&icd->vb2_vidq, i);
+
+	v4l2_subdev_call(sd, video, s_stream, 0);
+
+	return 0;
+}
+
+static int soc_camera_cropcap(struct file *file, void *fh,
+			      struct v4l2_cropcap *a)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+	return ici->ops->cropcap(icd, a);
+}
+
+static int soc_camera_g_crop(struct file *file, void *fh,
+			     struct v4l2_crop *a)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	int ret;
+
+	ret = ici->ops->get_crop(icd, a);
+
+	return ret;
+}
+
+/*
+ * According to the V4L2 API, drivers shall not update the struct v4l2_crop
+ * argument with the actual geometry, instead, the user shall use G_CROP to
+ * retrieve it.
+ */
+static int soc_camera_s_crop(struct file *file, void *fh,
+			     struct v4l2_crop *a)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct v4l2_rect *rect = &a->c;
+	struct v4l2_crop current_crop;
+	int ret;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	dev_dbg(icd->pdev, "S_CROP(%ux%u@%u:%u)\n",
+		rect->width, rect->height, rect->left, rect->top);
+
+	/* If get_crop fails, we'll let host and / or client drivers decide */
+	ret = ici->ops->get_crop(icd, &current_crop);
+
+	/* Prohibit window size change with initialised buffers */
+	if (ret < 0) {
+		dev_err(icd->pdev,
+			"S_CROP denied: getting current crop failed\n");
+	} else if ((a->c.width == current_crop.c.width &&
+		    a->c.height == current_crop.c.height) ||
+		   !is_streaming(ici, icd)) {
+		/* same size or not streaming - use .set_crop() */
+		ret = ici->ops->set_crop(icd, a);
+	} else if (ici->ops->set_livecrop) {
+		ret = ici->ops->set_livecrop(icd, a);
+	} else {
+		dev_err(icd->pdev,
+			"S_CROP denied: queue initialised and sizes differ\n");
+		ret = -EBUSY;
+	}
+
+	return ret;
+}
+
+static int soc_camera_g_selection(struct file *file, void *fh,
+				  struct v4l2_selection *s)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+	/* With a wrong type no need to try to fall back to cropping */
+	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (!ici->ops->get_selection)
+		return -ENOTTY;
+
+	return ici->ops->get_selection(icd, s);
+}
+
+static int soc_camera_s_selection(struct file *file, void *fh,
+				  struct v4l2_selection *s)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	int ret;
+
+	/* In all these cases cropping emulation will not help */
+	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	    (s->target != V4L2_SEL_TGT_COMPOSE_ACTIVE &&
+	     s->target != V4L2_SEL_TGT_CROP_ACTIVE))
+		return -EINVAL;
+
+	if (s->target == V4L2_SEL_TGT_COMPOSE_ACTIVE) {
+		/* No output size change during a running capture! */
+		if (is_streaming(ici, icd) &&
+		    (icd->user_width != s->r.width ||
+		     icd->user_height != s->r.height))
+			return -EBUSY;
+
+		/*
+		 * Only one user is allowed to change the output format, touch
+		 * buffers, start / stop streaming, poll for data
+		 */
+		if (icd->streamer && icd->streamer != file)
+			return -EBUSY;
+	}
+
+	if (!ici->ops->set_selection)
+		return -ENOTTY;
+
+	ret = ici->ops->set_selection(icd, s);
+	if (!ret &&
+	    s->target == V4L2_SEL_TGT_COMPOSE_ACTIVE) {
+		icd->user_width = s->r.width;
+		icd->user_height = s->r.height;
+		if (!icd->streamer)
+			icd->streamer = file;
+	}
+
+	return ret;
+}
+
+static int soc_camera_g_parm(struct file *file, void *fh,
+			     struct v4l2_streamparm *a)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+	if (ici->ops->get_parm)
+		return ici->ops->get_parm(icd, a);
+
+	return -ENOIOCTLCMD;
+}
+
+static int soc_camera_s_parm(struct file *file, void *fh,
+			     struct v4l2_streamparm *a)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+	if (ici->ops->set_parm)
+		return ici->ops->set_parm(icd, a);
+
+	return -ENOIOCTLCMD;
+}
+
+static int soc_camera_g_chip_ident(struct file *file, void *fh,
+				   struct v4l2_dbg_chip_ident *id)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+
+	return v4l2_subdev_call(sd, core, g_chip_ident, id);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int soc_camera_g_register(struct file *file, void *fh,
+				 struct v4l2_dbg_register *reg)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+
+	return v4l2_subdev_call(sd, core, g_register, reg);
+}
+
+static int soc_camera_s_register(struct file *file, void *fh,
+				 struct v4l2_dbg_register *reg)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+
+	return v4l2_subdev_call(sd, core, s_register, reg);
+}
+#endif
+
+static int soc_camera_probe(struct soc_camera_device *icd);
+
+/* So far this function cannot fail */
+static void scan_add_host(struct soc_camera_host *ici)
+{
+	struct soc_camera_device *icd;
+
+	mutex_lock(&ici->host_lock);
+
+	list_for_each_entry(icd, &devices, list) {
+		if (icd->iface == ici->nr) {
+			int ret;
+
+			icd->parent = ici->v4l2_dev.dev;
+			ret = soc_camera_probe(icd);
+		}
+	}
+
+	mutex_unlock(&ici->host_lock);
+}
+
+#ifdef CONFIG_I2C_BOARDINFO
+static int soc_camera_init_i2c(struct soc_camera_device *icd,
+			       struct soc_camera_link *icl)
+{
+	struct i2c_client *client;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id);
+	struct v4l2_subdev *subdev;
+
+	if (!adap) {
+		dev_err(icd->pdev, "Cannot get I2C adapter #%d. No driver?\n",
+			icl->i2c_adapter_id);
+		goto ei2cga;
+	}
+
+	icl->board_info->platform_data = icl;
+
+	subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
+				icl->board_info, NULL);
+	if (!subdev)
+		goto ei2cnd;
+
+	client = v4l2_get_subdevdata(subdev);
+
+	/* Use to_i2c_client(dev) to recover the i2c client */
+	icd->control = &client->dev;
+
+	return 0;
+ei2cnd:
+	i2c_put_adapter(adap);
+ei2cga:
+	return -ENODEV;
+}
+
+static void soc_camera_free_i2c(struct soc_camera_device *icd)
+{
+	struct i2c_client *client =
+		to_i2c_client(to_soc_camera_control(icd));
+	struct i2c_adapter *adap = client->adapter;
+
+	icd->control = NULL;
+	v4l2_device_unregister_subdev(i2c_get_clientdata(client));
+	i2c_unregister_device(client);
+	i2c_put_adapter(adap);
+}
+#else
+#define soc_camera_init_i2c(icd, icl)	(-ENODEV)
+#define soc_camera_free_i2c(icd)	do {} while (0)
+#endif
+
+static int soc_camera_video_start(struct soc_camera_device *icd);
+static int video_dev_create(struct soc_camera_device *icd);
+/* Called during host-driver probe */
+static int soc_camera_probe(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
+	struct device *control = NULL;
+	struct v4l2_subdev *sd;
+	struct v4l2_mbus_framefmt mf;
+	int ret;
+
+	dev_info(icd->pdev, "Probing %s\n", dev_name(icd->pdev));
+
+	/*
+	 * Currently the subdev with the largest number of controls (13) is
+	 * ov6550. So let's pick 16 as a hint for the control handler. Note
+	 * that this is a hint only: too large and you waste some memory, too
+	 * small and there is a (very) small performance hit when looking up
+	 * controls in the internal hash.
+	 */
+	ret = v4l2_ctrl_handler_init(&icd->ctrl_handler, 16);
+	if (ret < 0)
+		return ret;
+
+	ret = regulator_bulk_get(icd->pdev, icl->num_regulators,
+				 icl->regulators);
+	if (ret < 0)
+		goto ereg;
+
+	/* The camera could have been already on, try to reset */
+	if (icl->reset)
+		icl->reset(icd->pdev);
+
+	ret = ici->ops->add(icd);
+	if (ret < 0)
+		goto eadd;
+
+	/* Must have icd->vdev before registering the device */
+	ret = video_dev_create(icd);
+	if (ret < 0)
+		goto evdc;
+
+	/* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */
+	if (icl->board_info) {
+		ret = soc_camera_init_i2c(icd, icl);
+		if (ret < 0)
+			goto eadddev;
+	} else if (!icl->add_device || !icl->del_device) {
+		ret = -EINVAL;
+		goto eadddev;
+	} else {
+		if (icl->module_name)
+			ret = request_module(icl->module_name);
+
+		ret = icl->add_device(icd);
+		if (ret < 0)
+			goto eadddev;
+
+		/*
+		 * FIXME: this is racy, have to use driver-binding notification,
+		 * when it is available
+		 */
+		control = to_soc_camera_control(icd);
+		if (!control || !control->driver || !dev_get_drvdata(control) ||
+		    !try_module_get(control->driver->owner)) {
+			icl->del_device(icd);
+			ret = -ENODEV;
+			goto enodrv;
+		}
+	}
+
+	sd = soc_camera_to_subdev(icd);
+	sd->grp_id = soc_camera_grp_id(icd);
+	v4l2_set_subdev_hostdata(sd, icd);
+
+	if (v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler))
+		goto ectrl;
+
+	/* At this point client .probe() should have run already */
+	ret = soc_camera_init_user_formats(icd);
+	if (ret < 0)
+		goto eiufmt;
+
+	icd->field = V4L2_FIELD_ANY;
+
+	/*
+	 * ..._video_start() will create a device node, video_register_device()
+	 * itself is protected against concurrent open() calls, but we also have
+	 * to protect our data.
+	 */
+	mutex_lock(&icd->video_lock);
+
+	ret = soc_camera_video_start(icd);
+	if (ret < 0)
+		goto evidstart;
+
+	/* Try to improve our guess of a reasonable window format */
+	if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) {
+		icd->user_width		= mf.width;
+		icd->user_height	= mf.height;
+		icd->colorspace		= mf.colorspace;
+		icd->field		= mf.field;
+	}
+
+	ici->ops->remove(icd);
+
+	mutex_unlock(&icd->video_lock);
+
+	return 0;
+
+evidstart:
+	mutex_unlock(&icd->video_lock);
+	soc_camera_free_user_formats(icd);
+eiufmt:
+ectrl:
+	if (icl->board_info) {
+		soc_camera_free_i2c(icd);
+	} else {
+		icl->del_device(icd);
+		module_put(control->driver->owner);
+	}
+enodrv:
+eadddev:
+	video_device_release(icd->vdev);
+	icd->vdev = NULL;
+evdc:
+	ici->ops->remove(icd);
+eadd:
+	regulator_bulk_free(icl->num_regulators, icl->regulators);
+ereg:
+	v4l2_ctrl_handler_free(&icd->ctrl_handler);
+	return ret;
+}
+
+/*
+ * This is called on device_unregister, which only means we have to disconnect
+ * from the host, but not remove ourselves from the device list
+ */
+static int soc_camera_remove(struct soc_camera_device *icd)
+{
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
+	struct video_device *vdev = icd->vdev;
+
+	BUG_ON(!icd->parent);
+
+	v4l2_ctrl_handler_free(&icd->ctrl_handler);
+	if (vdev) {
+		video_unregister_device(vdev);
+		icd->vdev = NULL;
+	}
+
+	if (icl->board_info) {
+		soc_camera_free_i2c(icd);
+	} else {
+		struct device_driver *drv = to_soc_camera_control(icd)->driver;
+		if (drv) {
+			icl->del_device(icd);
+			module_put(drv->owner);
+		}
+	}
+	soc_camera_free_user_formats(icd);
+
+	regulator_bulk_free(icl->num_regulators, icl->regulators);
+
+	return 0;
+}
+
+static int default_cropcap(struct soc_camera_device *icd,
+			   struct v4l2_cropcap *a)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	return v4l2_subdev_call(sd, video, cropcap, a);
+}
+
+static int default_g_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	return v4l2_subdev_call(sd, video, g_crop, a);
+}
+
+static int default_s_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	return v4l2_subdev_call(sd, video, s_crop, a);
+}
+
+static int default_g_parm(struct soc_camera_device *icd,
+			  struct v4l2_streamparm *parm)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	return v4l2_subdev_call(sd, video, g_parm, parm);
+}
+
+static int default_s_parm(struct soc_camera_device *icd,
+			  struct v4l2_streamparm *parm)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	return v4l2_subdev_call(sd, video, s_parm, parm);
+}
+
+static int default_enum_framesizes(struct soc_camera_device *icd,
+				   struct v4l2_frmsizeenum *fsize)
+{
+	int ret;
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	const struct soc_camera_format_xlate *xlate;
+	__u32 pixfmt = fsize->pixel_format;
+	struct v4l2_frmsizeenum fsize_mbus = *fsize;
+
+	xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+	if (!xlate)
+		return -EINVAL;
+	/* map xlate-code to pixel_format, sensor only handle xlate-code*/
+	fsize_mbus.pixel_format = xlate->code;
+
+	ret = v4l2_subdev_call(sd, video, enum_framesizes, &fsize_mbus);
+	if (ret < 0)
+		return ret;
+
+	*fsize = fsize_mbus;
+	fsize->pixel_format = pixfmt;
+
+	return 0;
+}
+
+int soc_camera_host_register(struct soc_camera_host *ici)
+{
+	struct soc_camera_host *ix;
+	int ret;
+
+	if (!ici || !ici->ops ||
+	    !ici->ops->try_fmt ||
+	    !ici->ops->set_fmt ||
+	    !ici->ops->set_bus_param ||
+	    !ici->ops->querycap ||
+	    ((!ici->ops->init_videobuf ||
+	      !ici->ops->reqbufs) &&
+	     !ici->ops->init_videobuf2) ||
+	    !ici->ops->add ||
+	    !ici->ops->remove ||
+	    !ici->ops->poll ||
+	    !ici->v4l2_dev.dev)
+		return -EINVAL;
+
+	if (!ici->ops->set_crop)
+		ici->ops->set_crop = default_s_crop;
+	if (!ici->ops->get_crop)
+		ici->ops->get_crop = default_g_crop;
+	if (!ici->ops->cropcap)
+		ici->ops->cropcap = default_cropcap;
+	if (!ici->ops->set_parm)
+		ici->ops->set_parm = default_s_parm;
+	if (!ici->ops->get_parm)
+		ici->ops->get_parm = default_g_parm;
+	if (!ici->ops->enum_framesizes)
+		ici->ops->enum_framesizes = default_enum_framesizes;
+
+	mutex_lock(&list_lock);
+	list_for_each_entry(ix, &hosts, list) {
+		if (ix->nr == ici->nr) {
+			ret = -EBUSY;
+			goto edevreg;
+		}
+	}
+
+	ret = v4l2_device_register(ici->v4l2_dev.dev, &ici->v4l2_dev);
+	if (ret < 0)
+		goto edevreg;
+
+	list_add_tail(&ici->list, &hosts);
+	mutex_unlock(&list_lock);
+
+	mutex_init(&ici->host_lock);
+	scan_add_host(ici);
+
+	return 0;
+
+edevreg:
+	mutex_unlock(&list_lock);
+	return ret;
+}
+EXPORT_SYMBOL(soc_camera_host_register);
+
+/* Unregister all clients! */
+void soc_camera_host_unregister(struct soc_camera_host *ici)
+{
+	struct soc_camera_device *icd;
+
+	mutex_lock(&list_lock);
+
+	list_del(&ici->list);
+	list_for_each_entry(icd, &devices, list)
+		if (icd->iface == ici->nr && to_soc_camera_control(icd))
+			soc_camera_remove(icd);
+
+	mutex_unlock(&list_lock);
+
+	v4l2_device_unregister(&ici->v4l2_dev);
+}
+EXPORT_SYMBOL(soc_camera_host_unregister);
+
+/* Image capture device */
+static int soc_camera_device_register(struct soc_camera_device *icd)
+{
+	struct soc_camera_device *ix;
+	int num = -1, i;
+
+	for (i = 0; i < 256 && num < 0; i++) {
+		num = i;
+		/* Check if this index is available on this interface */
+		list_for_each_entry(ix, &devices, list) {
+			if (ix->iface == icd->iface && ix->devnum == i) {
+				num = -1;
+				break;
+			}
+		}
+	}
+
+	if (num < 0)
+		/*
+		 * ok, we have 256 cameras on this host...
+		 * man, stay reasonable...
+		 */
+		return -ENOMEM;
+
+	icd->devnum		= num;
+	icd->use_count		= 0;
+	icd->host_priv		= NULL;
+	mutex_init(&icd->video_lock);
+
+	list_add_tail(&icd->list, &devices);
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
+	.vidioc_querycap	 = soc_camera_querycap,
+	.vidioc_try_fmt_vid_cap  = soc_camera_try_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap    = soc_camera_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap    = soc_camera_s_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap,
+	.vidioc_enum_input	 = soc_camera_enum_input,
+	.vidioc_g_input		 = soc_camera_g_input,
+	.vidioc_s_input		 = soc_camera_s_input,
+	.vidioc_s_std		 = soc_camera_s_std,
+	.vidioc_g_std		 = soc_camera_g_std,
+	.vidioc_enum_framesizes  = soc_camera_enum_framesizes,
+	.vidioc_reqbufs		 = soc_camera_reqbufs,
+	.vidioc_querybuf	 = soc_camera_querybuf,
+	.vidioc_qbuf		 = soc_camera_qbuf,
+	.vidioc_dqbuf		 = soc_camera_dqbuf,
+	.vidioc_create_bufs	 = soc_camera_create_bufs,
+	.vidioc_prepare_buf	 = soc_camera_prepare_buf,
+	.vidioc_streamon	 = soc_camera_streamon,
+	.vidioc_streamoff	 = soc_camera_streamoff,
+	.vidioc_cropcap		 = soc_camera_cropcap,
+	.vidioc_g_crop		 = soc_camera_g_crop,
+	.vidioc_s_crop		 = soc_camera_s_crop,
+	.vidioc_g_selection	 = soc_camera_g_selection,
+	.vidioc_s_selection	 = soc_camera_s_selection,
+	.vidioc_g_parm		 = soc_camera_g_parm,
+	.vidioc_s_parm		 = soc_camera_s_parm,
+	.vidioc_g_chip_ident     = soc_camera_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register	 = soc_camera_g_register,
+	.vidioc_s_register	 = soc_camera_s_register,
+#endif
+};
+
+static int video_dev_create(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct video_device *vdev = video_device_alloc();
+
+	if (!vdev)
+		return -ENOMEM;
+
+	strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
+
+	vdev->parent		= icd->pdev;
+	vdev->current_norm	= V4L2_STD_UNKNOWN;
+	vdev->fops		= &soc_camera_fops;
+	vdev->ioctl_ops		= &soc_camera_ioctl_ops;
+	vdev->release		= video_device_release;
+	vdev->tvnorms		= V4L2_STD_UNKNOWN;
+	vdev->ctrl_handler	= &icd->ctrl_handler;
+	vdev->lock		= &icd->video_lock;
+
+	icd->vdev = vdev;
+
+	return 0;
+}
+
+/*
+ * Called from soc_camera_probe() above (with .video_lock held???)
+ */
+static int soc_camera_video_start(struct soc_camera_device *icd)
+{
+	const struct device_type *type = icd->vdev->dev.type;
+	int ret;
+
+	if (!icd->parent)
+		return -ENODEV;
+
+	ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1);
+	if (ret < 0) {
+		dev_err(icd->pdev, "video_register_device failed: %d\n", ret);
+		return ret;
+	}
+
+	/* Restore device type, possibly set by the subdevice driver */
+	icd->vdev->dev.type = type;
+
+	return 0;
+}
+
+static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
+{
+	struct soc_camera_link *icl = pdev->dev.platform_data;
+	struct soc_camera_device *icd;
+	int ret;
+
+	if (!icl)
+		return -EINVAL;
+
+	icd = kzalloc(sizeof(*icd), GFP_KERNEL);
+	if (!icd)
+		return -ENOMEM;
+
+	icd->iface = icl->bus_id;
+	icd->link = icl;
+	icd->pdev = &pdev->dev;
+	platform_set_drvdata(pdev, icd);
+
+	ret = soc_camera_device_register(icd);
+	if (ret < 0)
+		goto escdevreg;
+
+	icd->user_width		= DEFAULT_WIDTH;
+	icd->user_height	= DEFAULT_HEIGHT;
+
+	return 0;
+
+escdevreg:
+	kfree(icd);
+
+	return ret;
+}
+
+/*
+ * Only called on rmmod for each platform device, since they are not
+ * hot-pluggable. Now we know, that all our users - hosts and devices have
+ * been unloaded already
+ */
+static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev)
+{
+	struct soc_camera_device *icd = platform_get_drvdata(pdev);
+
+	if (!icd)
+		return -EINVAL;
+
+	list_del(&icd->list);
+
+	kfree(icd);
+
+	return 0;
+}
+
+static struct platform_driver __refdata soc_camera_pdrv = {
+	.probe = soc_camera_pdrv_probe,
+	.remove  = __devexit_p(soc_camera_pdrv_remove),
+	.driver  = {
+		.name	= "soc-camera-pdrv",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init soc_camera_init(void)
+{
+	return platform_driver_register(&soc_camera_pdrv);
+}
+
+static void __exit soc_camera_exit(void)
+{
+	platform_driver_unregister(&soc_camera_pdrv);
+}
+
+module_init(soc_camera_init);
+module_exit(soc_camera_exit);
+
+MODULE_DESCRIPTION("Image capture bus driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:soc-camera-pdrv");
diff --git a/drivers/media/platform/soc_camera_platform.c b/drivers/media/platform/soc_camera_platform.c
new file mode 100644
index 0000000..7cf7fd1
--- /dev/null
+++ b/drivers/media/platform/soc_camera_platform.c
@@ -0,0 +1,206 @@
+/*
+ * Generic Platform Camera Driver
+ *
+ * Copyright (C) 2008 Magnus Damm
+ * Based on mt9m001 driver,
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+#include <media/soc_camera.h>
+#include <media/soc_camera_platform.h>
+
+struct soc_camera_platform_priv {
+	struct v4l2_subdev subdev;
+};
+
+static struct soc_camera_platform_priv *get_priv(struct platform_device *pdev)
+{
+	struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
+	return container_of(subdev, struct soc_camera_platform_priv, subdev);
+}
+
+static int soc_camera_platform_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+	return p->set_capture(p, enable);
+}
+
+static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd,
+					struct v4l2_mbus_framefmt *mf)
+{
+	struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+	mf->width	= p->format.width;
+	mf->height	= p->format.height;
+	mf->code	= p->format.code;
+	mf->colorspace	= p->format.colorspace;
+	mf->field	= p->format.field;
+
+	return 0;
+}
+
+static int soc_camera_platform_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+	return soc_camera_set_power(p->icd->control, p->icd->link, on);
+}
+
+static struct v4l2_subdev_core_ops platform_subdev_core_ops = {
+	.s_power = soc_camera_platform_s_power,
+};
+
+static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+					enum v4l2_mbus_pixelcode *code)
+{
+	struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+	if (index)
+		return -EINVAL;
+
+	*code = p->format.code;
+	return 0;
+}
+
+static int soc_camera_platform_g_crop(struct v4l2_subdev *sd,
+				      struct v4l2_crop *a)
+{
+	struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+	a->c.left	= 0;
+	a->c.top	= 0;
+	a->c.width	= p->format.width;
+	a->c.height	= p->format.height;
+	a->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int soc_camera_platform_cropcap(struct v4l2_subdev *sd,
+				       struct v4l2_cropcap *a)
+{
+	struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+	a->bounds.left			= 0;
+	a->bounds.top			= 0;
+	a->bounds.width			= p->format.width;
+	a->bounds.height		= p->format.height;
+	a->defrect			= a->bounds;
+	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int soc_camera_platform_g_mbus_config(struct v4l2_subdev *sd,
+					     struct v4l2_mbus_config *cfg)
+{
+	struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+	cfg->flags = p->mbus_param;
+	cfg->type = p->mbus_type;
+
+	return 0;
+}
+
+static struct v4l2_subdev_video_ops platform_subdev_video_ops = {
+	.s_stream	= soc_camera_platform_s_stream,
+	.enum_mbus_fmt	= soc_camera_platform_enum_fmt,
+	.cropcap	= soc_camera_platform_cropcap,
+	.g_crop		= soc_camera_platform_g_crop,
+	.try_mbus_fmt	= soc_camera_platform_fill_fmt,
+	.g_mbus_fmt	= soc_camera_platform_fill_fmt,
+	.s_mbus_fmt	= soc_camera_platform_fill_fmt,
+	.g_mbus_config	= soc_camera_platform_g_mbus_config,
+};
+
+static struct v4l2_subdev_ops platform_subdev_ops = {
+	.core	= &platform_subdev_core_ops,
+	.video	= &platform_subdev_video_ops,
+};
+
+static int soc_camera_platform_probe(struct platform_device *pdev)
+{
+	struct soc_camera_host *ici;
+	struct soc_camera_platform_priv *priv;
+	struct soc_camera_platform_info *p = pdev->dev.platform_data;
+	struct soc_camera_device *icd;
+	int ret;
+
+	if (!p)
+		return -EINVAL;
+
+	if (!p->icd) {
+		dev_err(&pdev->dev,
+			"Platform has not set soc_camera_device pointer!\n");
+		return -EINVAL;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	icd = p->icd;
+
+	/* soc-camera convention: control's drvdata points to the subdev */
+	platform_set_drvdata(pdev, &priv->subdev);
+	/* Set the control device reference */
+	icd->control = &pdev->dev;
+
+	ici = to_soc_camera_host(icd->parent);
+
+	v4l2_subdev_init(&priv->subdev, &platform_subdev_ops);
+	v4l2_set_subdevdata(&priv->subdev, p);
+	strncpy(priv->subdev.name, dev_name(&pdev->dev), V4L2_SUBDEV_NAME_SIZE);
+
+	ret = v4l2_device_register_subdev(&ici->v4l2_dev, &priv->subdev);
+	if (ret)
+		goto evdrs;
+
+	return ret;
+
+evdrs:
+	platform_set_drvdata(pdev, NULL);
+	kfree(priv);
+	return ret;
+}
+
+static int soc_camera_platform_remove(struct platform_device *pdev)
+{
+	struct soc_camera_platform_priv *priv = get_priv(pdev);
+	struct soc_camera_platform_info *p = v4l2_get_subdevdata(&priv->subdev);
+
+	p->icd->control = NULL;
+	v4l2_device_unregister_subdev(&priv->subdev);
+	platform_set_drvdata(pdev, NULL);
+	kfree(priv);
+	return 0;
+}
+
+static struct platform_driver soc_camera_platform_driver = {
+	.driver 	= {
+		.name	= "soc_camera_platform",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= soc_camera_platform_probe,
+	.remove		= soc_camera_platform_remove,
+};
+
+module_platform_driver(soc_camera_platform_driver);
+
+MODULE_DESCRIPTION("SoC Camera Platform driver");
+MODULE_AUTHOR("Magnus Damm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:soc_camera_platform");
diff --git a/drivers/media/platform/soc_mediabus.c b/drivers/media/platform/soc_mediabus.c
new file mode 100644
index 0000000..a397812
--- /dev/null
+++ b/drivers/media/platform/soc_mediabus.c
@@ -0,0 +1,493 @@
+/*
+ * soc-camera media bus helper routines
+ *
+ * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/soc_mediabus.h>
+
+static const struct soc_mbus_lookup mbus_fmt[] = {
+{
+	.code = V4L2_MBUS_FMT_YUYV8_2X8,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_YUYV,
+		.name			= "YUYV",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_YVYU8_2X8,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_YVYU,
+		.name			= "YVYU",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_UYVY8_2X8,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_UYVY,
+		.name			= "UYVY",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_VYUY8_2X8,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_VYUY,
+		.name			= "VYUY",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_RGB555,
+		.name			= "RGB555",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_RGB555X,
+		.name			= "RGB555X",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_RGB565,
+		.name			= "RGB565",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_RGB565X,
+		.name			= "RGB565X",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_SBGGR8_1X8,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_SBGGR8,
+		.name			= "Bayer 8 BGGR",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_NONE,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_SBGGR10_1X10,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_SBGGR10,
+		.name			= "Bayer 10 BGGR",
+		.bits_per_sample	= 10,
+		.packing		= SOC_MBUS_PACKING_EXTEND16,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_Y8_1X8,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_GREY,
+		.name			= "Grey",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_NONE,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_Y10_1X10,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_Y10,
+		.name			= "Grey 10bit",
+		.bits_per_sample	= 10,
+		.packing		= SOC_MBUS_PACKING_EXTEND16,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_SBGGR10,
+		.name			= "Bayer 10 BGGR",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_SBGGR10,
+		.name			= "Bayer 10 BGGR",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADLO,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_SBGGR10,
+		.name			= "Bayer 10 BGGR",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_SBGGR10,
+		.name			= "Bayer 10 BGGR",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADLO,
+		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_JPEG_1X8,
+	.fmt = {
+		.fourcc                 = V4L2_PIX_FMT_JPEG,
+		.name                   = "JPEG",
+		.bits_per_sample        = 8,
+		.packing                = SOC_MBUS_PACKING_VARIABLE,
+		.order                  = SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_RGB444,
+		.name			= "RGB444",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
+		.order			= SOC_MBUS_ORDER_BE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_YUYV8_1_5X8,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_YUV420,
+		.name			= "YUYV 4:2:0",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_1_5X8,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_YVYU8_1_5X8,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_YVU420,
+		.name			= "YVYU 4:2:0",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_1_5X8,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_UYVY8_1X16,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_UYVY,
+		.name			= "UYVY 16bit",
+		.bits_per_sample	= 16,
+		.packing		= SOC_MBUS_PACKING_EXTEND16,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_VYUY8_1X16,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_VYUY,
+		.name			= "VYUY 16bit",
+		.bits_per_sample	= 16,
+		.packing		= SOC_MBUS_PACKING_EXTEND16,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_YUYV8_1X16,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_YUYV,
+		.name			= "YUYV 16bit",
+		.bits_per_sample	= 16,
+		.packing		= SOC_MBUS_PACKING_EXTEND16,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_YVYU8_1X16,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_YVYU,
+		.name			= "YVYU 16bit",
+		.bits_per_sample	= 16,
+		.packing		= SOC_MBUS_PACKING_EXTEND16,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_SGRBG8_1X8,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_SGRBG8,
+		.name			= "Bayer 8 GRBG",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_NONE,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_SGRBG10DPCM8,
+		.name			= "Bayer 10 BGGR DPCM 8",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_NONE,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_SGBRG10_1X10,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_SGBRG10,
+		.name			= "Bayer 10 GBRG",
+		.bits_per_sample	= 10,
+		.packing		= SOC_MBUS_PACKING_EXTEND16,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_SGRBG10_1X10,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_SGRBG10,
+		.name			= "Bayer 10 GRBG",
+		.bits_per_sample	= 10,
+		.packing		= SOC_MBUS_PACKING_EXTEND16,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_SRGGB10_1X10,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_SRGGB10,
+		.name			= "Bayer 10 RGGB",
+		.bits_per_sample	= 10,
+		.packing		= SOC_MBUS_PACKING_EXTEND16,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_SBGGR12_1X12,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_SBGGR12,
+		.name			= "Bayer 12 BGGR",
+		.bits_per_sample	= 12,
+		.packing		= SOC_MBUS_PACKING_EXTEND16,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_SGBRG12_1X12,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_SGBRG12,
+		.name			= "Bayer 12 GBRG",
+		.bits_per_sample	= 12,
+		.packing		= SOC_MBUS_PACKING_EXTEND16,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_SGRBG12_1X12,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_SGRBG12,
+		.name			= "Bayer 12 GRBG",
+		.bits_per_sample	= 12,
+		.packing		= SOC_MBUS_PACKING_EXTEND16,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+}, {
+	.code = V4L2_MBUS_FMT_SRGGB12_1X12,
+	.fmt = {
+		.fourcc			= V4L2_PIX_FMT_SRGGB12,
+		.name			= "Bayer 12 RGGB",
+		.bits_per_sample	= 12,
+		.packing		= SOC_MBUS_PACKING_EXTEND16,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
+},
+};
+
+int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf,
+			unsigned int *numerator, unsigned int *denominator)
+{
+	switch (mf->packing) {
+	case SOC_MBUS_PACKING_NONE:
+	case SOC_MBUS_PACKING_EXTEND16:
+		*numerator = 1;
+		*denominator = 1;
+		return 0;
+	case SOC_MBUS_PACKING_2X8_PADHI:
+	case SOC_MBUS_PACKING_2X8_PADLO:
+		*numerator = 2;
+		*denominator = 1;
+		return 0;
+	case SOC_MBUS_PACKING_1_5X8:
+		*numerator = 3;
+		*denominator = 2;
+		return 0;
+	case SOC_MBUS_PACKING_VARIABLE:
+		*numerator = 0;
+		*denominator = 1;
+		return 0;
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL(soc_mbus_samples_per_pixel);
+
+s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
+{
+	if (mf->fourcc == V4L2_PIX_FMT_JPEG)
+		return 0;
+
+	if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
+		return width * mf->bits_per_sample / 8;
+
+	switch (mf->packing) {
+	case SOC_MBUS_PACKING_NONE:
+		return width * mf->bits_per_sample / 8;
+	case SOC_MBUS_PACKING_2X8_PADHI:
+	case SOC_MBUS_PACKING_2X8_PADLO:
+	case SOC_MBUS_PACKING_EXTEND16:
+		return width * 2;
+	case SOC_MBUS_PACKING_1_5X8:
+		return width * 3 / 2;
+	case SOC_MBUS_PACKING_VARIABLE:
+		return 0;
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL(soc_mbus_bytes_per_line);
+
+s32 soc_mbus_image_size(const struct soc_mbus_pixelfmt *mf,
+			u32 bytes_per_line, u32 height)
+{
+	if (mf->fourcc == V4L2_PIX_FMT_JPEG)
+		return 0;
+
+	if (mf->layout == SOC_MBUS_LAYOUT_PACKED)
+		return bytes_per_line * height;
+
+	switch (mf->packing) {
+	case SOC_MBUS_PACKING_2X8_PADHI:
+	case SOC_MBUS_PACKING_2X8_PADLO:
+		return bytes_per_line * height * 2;
+	case SOC_MBUS_PACKING_1_5X8:
+		return bytes_per_line * height * 3 / 2;
+	default:
+		return -EINVAL;
+	}
+}
+EXPORT_SYMBOL(soc_mbus_image_size);
+
+const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc(
+	enum v4l2_mbus_pixelcode code,
+	const struct soc_mbus_lookup *lookup,
+	int n)
+{
+	int i;
+
+	for (i = 0; i < n; i++)
+		if (lookup[i].code == code)
+			return &lookup[i].fmt;
+
+	return NULL;
+}
+EXPORT_SYMBOL(soc_mbus_find_fmtdesc);
+
+const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc(
+	enum v4l2_mbus_pixelcode code)
+{
+	return soc_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt));
+}
+EXPORT_SYMBOL(soc_mbus_get_fmtdesc);
+
+unsigned int soc_mbus_config_compatible(const struct v4l2_mbus_config *cfg,
+					unsigned int flags)
+{
+	unsigned long common_flags;
+	bool hsync = true, vsync = true, pclk, data, mode;
+	bool mipi_lanes, mipi_clock;
+
+	common_flags = cfg->flags & flags;
+
+	switch (cfg->type) {
+	case V4L2_MBUS_PARALLEL:
+		hsync = common_flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+					V4L2_MBUS_HSYNC_ACTIVE_LOW);
+		vsync = common_flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH |
+					V4L2_MBUS_VSYNC_ACTIVE_LOW);
+	case V4L2_MBUS_BT656:
+		pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING |
+				       V4L2_MBUS_PCLK_SAMPLE_FALLING);
+		data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH |
+				       V4L2_MBUS_DATA_ACTIVE_LOW);
+		mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE);
+		return (!hsync || !vsync || !pclk || !data || !mode) ?
+			0 : common_flags;
+	case V4L2_MBUS_CSI2:
+		mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES;
+		mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK |
+					     V4L2_MBUS_CSI2_CONTINUOUS_CLOCK);
+		return (!mipi_lanes || !mipi_clock) ? 0 : common_flags;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(soc_mbus_config_compatible);
+
+static int __init soc_mbus_init(void)
+{
+	return 0;
+}
+
+static void __exit soc_mbus_exit(void)
+{
+}
+
+module_init(soc_mbus_init);
+module_exit(soc_mbus_exit);
+
+MODULE_DESCRIPTION("soc-camera media bus interface");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/timblogiw.c b/drivers/media/platform/timblogiw.c
new file mode 100644
index 0000000..02194c0
--- /dev/null
+++ b/drivers/media/platform/timblogiw.c
@@ -0,0 +1,880 @@
+/*
+ * timblogiw.c timberdale FPGA LogiWin Video In driver
+ * Copyright (c) 2009-2010 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Supports:
+ * Timberdale FPGA LogiWin Video In
+ */
+
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/scatterlist.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf-dma-contig.h>
+#include <media/timb_video.h>
+
+#define DRIVER_NAME			"timb-video"
+
+#define TIMBLOGIWIN_NAME		"Timberdale Video-In"
+#define TIMBLOGIW_VERSION_CODE		0x04
+
+#define TIMBLOGIW_LINES_PER_DESC	44
+#define TIMBLOGIW_MAX_VIDEO_MEM		16
+
+#define TIMBLOGIW_HAS_DECODER(lw)	(lw->pdata.encoder.module_name)
+
+
+struct timblogiw {
+	struct video_device		video_dev;
+	struct v4l2_device		v4l2_dev; /* mutual exclusion */
+	struct mutex			lock;
+	struct device			*dev;
+	struct timb_video_platform_data pdata;
+	struct v4l2_subdev		*sd_enc;	/* encoder */
+	bool				opened;
+};
+
+struct timblogiw_tvnorm {
+	v4l2_std_id std;
+	u16     width;
+	u16     height;
+	u8	fps;
+};
+
+struct timblogiw_fh {
+	struct videobuf_queue		vb_vidq;
+	struct timblogiw_tvnorm const	*cur_norm;
+	struct list_head		capture;
+	struct dma_chan			*chan;
+	spinlock_t			queue_lock; /* mutual exclusion */
+	unsigned int			frame_count;
+};
+
+struct timblogiw_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer	vb;
+	struct scatterlist	sg[16];
+	dma_cookie_t		cookie;
+	struct timblogiw_fh	*fh;
+};
+
+const struct timblogiw_tvnorm timblogiw_tvnorms[] = {
+	{
+		.std			= V4L2_STD_PAL,
+		.width			= 720,
+		.height			= 576,
+		.fps			= 25
+	},
+	{
+		.std			= V4L2_STD_NTSC,
+		.width			= 720,
+		.height			= 480,
+		.fps			= 30
+	}
+};
+
+static int timblogiw_bytes_per_line(const struct timblogiw_tvnorm *norm)
+{
+	return norm->width * 2;
+}
+
+
+static int timblogiw_frame_size(const struct timblogiw_tvnorm *norm)
+{
+	return norm->height * timblogiw_bytes_per_line(norm);
+}
+
+static const struct timblogiw_tvnorm *timblogiw_get_norm(const v4l2_std_id std)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(timblogiw_tvnorms); i++)
+		if (timblogiw_tvnorms[i].std & std)
+			return timblogiw_tvnorms + i;
+
+	/* default to first element */
+	return timblogiw_tvnorms;
+}
+
+static void timblogiw_dma_cb(void *data)
+{
+	struct timblogiw_buffer *buf = data;
+	struct timblogiw_fh *fh = buf->fh;
+	struct videobuf_buffer *vb = &buf->vb;
+
+	spin_lock(&fh->queue_lock);
+
+	/* mark the transfer done */
+	buf->cookie = -1;
+
+	fh->frame_count++;
+
+	if (vb->state != VIDEOBUF_ERROR) {
+		list_del(&vb->queue);
+		do_gettimeofday(&vb->ts);
+		vb->field_count = fh->frame_count * 2;
+		vb->state = VIDEOBUF_DONE;
+
+		wake_up(&vb->done);
+	}
+
+	if (!list_empty(&fh->capture)) {
+		vb = list_entry(fh->capture.next, struct videobuf_buffer,
+			queue);
+		vb->state = VIDEOBUF_ACTIVE;
+	}
+
+	spin_unlock(&fh->queue_lock);
+}
+
+static bool timblogiw_dma_filter_fn(struct dma_chan *chan, void *filter_param)
+{
+	return chan->chan_id == (uintptr_t)filter_param;
+}
+
+/* IOCTL functions */
+
+static int timblogiw_g_fmt(struct file *file, void  *priv,
+	struct v4l2_format *format)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct timblogiw *lw = video_get_drvdata(vdev);
+	struct timblogiw_fh *fh = priv;
+
+	dev_dbg(&vdev->dev, "%s entry\n", __func__);
+
+	if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	mutex_lock(&lw->lock);
+
+	format->fmt.pix.width = fh->cur_norm->width;
+	format->fmt.pix.height = fh->cur_norm->height;
+	format->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+	format->fmt.pix.bytesperline = timblogiw_bytes_per_line(fh->cur_norm);
+	format->fmt.pix.sizeimage = timblogiw_frame_size(fh->cur_norm);
+	format->fmt.pix.field = V4L2_FIELD_NONE;
+
+	mutex_unlock(&lw->lock);
+
+	return 0;
+}
+
+static int timblogiw_try_fmt(struct file *file, void  *priv,
+	struct v4l2_format *format)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_pix_format *pix = &format->fmt.pix;
+
+	dev_dbg(&vdev->dev,
+		"%s - width=%d, height=%d, pixelformat=%d, field=%d\n"
+		"bytes per line %d, size image: %d, colorspace: %d\n",
+		__func__,
+		pix->width, pix->height, pix->pixelformat, pix->field,
+		pix->bytesperline, pix->sizeimage, pix->colorspace);
+
+	if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (pix->field != V4L2_FIELD_NONE)
+		return -EINVAL;
+
+	if (pix->pixelformat != V4L2_PIX_FMT_UYVY)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int timblogiw_s_fmt(struct file *file, void  *priv,
+	struct v4l2_format *format)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct timblogiw *lw = video_get_drvdata(vdev);
+	struct timblogiw_fh *fh = priv;
+	struct v4l2_pix_format *pix = &format->fmt.pix;
+	int err;
+
+	mutex_lock(&lw->lock);
+
+	err = timblogiw_try_fmt(file, priv, format);
+	if (err)
+		goto out;
+
+	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+		dev_err(&vdev->dev, "%s queue busy\n", __func__);
+		err = -EBUSY;
+		goto out;
+	}
+
+	pix->width = fh->cur_norm->width;
+	pix->height = fh->cur_norm->height;
+
+out:
+	mutex_unlock(&lw->lock);
+	return err;
+}
+
+static int timblogiw_querycap(struct file *file, void  *priv,
+	struct v4l2_capability *cap)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	dev_dbg(&vdev->dev, "%s: Entry\n",  __func__);
+	memset(cap, 0, sizeof(*cap));
+	strncpy(cap->card, TIMBLOGIWIN_NAME, sizeof(cap->card)-1);
+	strncpy(cap->driver, DRIVER_NAME, sizeof(cap->driver) - 1);
+	strlcpy(cap->bus_info, vdev->name, sizeof(cap->bus_info));
+	cap->version = TIMBLOGIW_VERSION_CODE;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+		V4L2_CAP_READWRITE;
+
+	return 0;
+}
+
+static int timblogiw_enum_fmt(struct file *file, void  *priv,
+	struct v4l2_fmtdesc *fmt)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	dev_dbg(&vdev->dev, "%s, index: %d\n",  __func__, fmt->index);
+
+	if (fmt->index != 0)
+		return -EINVAL;
+	memset(fmt, 0, sizeof(*fmt));
+	fmt->index = 0;
+	fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	strncpy(fmt->description, "4:2:2, packed, YUYV",
+		sizeof(fmt->description)-1);
+	fmt->pixelformat = V4L2_PIX_FMT_UYVY;
+
+	return 0;
+}
+
+static int timblogiw_g_parm(struct file *file, void *priv,
+	struct v4l2_streamparm *sp)
+{
+	struct timblogiw_fh *fh = priv;
+	struct v4l2_captureparm *cp = &sp->parm.capture;
+
+	cp->capability = V4L2_CAP_TIMEPERFRAME;
+	cp->timeperframe.numerator = 1;
+	cp->timeperframe.denominator = fh->cur_norm->fps;
+
+	return 0;
+}
+
+static int timblogiw_reqbufs(struct file *file, void  *priv,
+	struct v4l2_requestbuffers *rb)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct timblogiw_fh *fh = priv;
+
+	dev_dbg(&vdev->dev, "%s: entry\n",  __func__);
+
+	return videobuf_reqbufs(&fh->vb_vidq, rb);
+}
+
+static int timblogiw_querybuf(struct file *file, void  *priv,
+	struct v4l2_buffer *b)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct timblogiw_fh *fh = priv;
+
+	dev_dbg(&vdev->dev, "%s: entry\n",  __func__);
+
+	return videobuf_querybuf(&fh->vb_vidq, b);
+}
+
+static int timblogiw_qbuf(struct file *file, void  *priv, struct v4l2_buffer *b)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct timblogiw_fh *fh = priv;
+
+	dev_dbg(&vdev->dev, "%s: entry\n",  __func__);
+
+	return videobuf_qbuf(&fh->vb_vidq, b);
+}
+
+static int timblogiw_dqbuf(struct file *file, void  *priv,
+	struct v4l2_buffer *b)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct timblogiw_fh *fh = priv;
+
+	dev_dbg(&vdev->dev, "%s: entry\n",  __func__);
+
+	return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
+}
+
+static int timblogiw_g_std(struct file *file, void  *priv, v4l2_std_id *std)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct timblogiw_fh *fh = priv;
+
+	dev_dbg(&vdev->dev, "%s: entry\n",  __func__);
+
+	*std = fh->cur_norm->std;
+	return 0;
+}
+
+static int timblogiw_s_std(struct file *file, void  *priv, v4l2_std_id *std)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct timblogiw *lw = video_get_drvdata(vdev);
+	struct timblogiw_fh *fh = priv;
+	int err = 0;
+
+	dev_dbg(&vdev->dev, "%s: entry\n",  __func__);
+
+	mutex_lock(&lw->lock);
+
+	if (TIMBLOGIW_HAS_DECODER(lw))
+		err = v4l2_subdev_call(lw->sd_enc, core, s_std, *std);
+
+	if (!err)
+		fh->cur_norm = timblogiw_get_norm(*std);
+
+	mutex_unlock(&lw->lock);
+
+	return err;
+}
+
+static int timblogiw_enuminput(struct file *file, void  *priv,
+	struct v4l2_input *inp)
+{
+	struct video_device *vdev = video_devdata(file);
+	int i;
+
+	dev_dbg(&vdev->dev, "%s: Entry\n",  __func__);
+
+	if (inp->index != 0)
+		return -EINVAL;
+
+	inp->index = 0;
+
+	strncpy(inp->name, "Timb input 1", sizeof(inp->name) - 1);
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+
+	inp->std = 0;
+	for (i = 0; i < ARRAY_SIZE(timblogiw_tvnorms); i++)
+		inp->std |= timblogiw_tvnorms[i].std;
+
+	return 0;
+}
+
+static int timblogiw_g_input(struct file *file, void  *priv,
+	unsigned int *input)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	dev_dbg(&vdev->dev, "%s: Entry\n",  __func__);
+
+	*input = 0;
+
+	return 0;
+}
+
+static int timblogiw_s_input(struct file *file, void  *priv, unsigned int input)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	dev_dbg(&vdev->dev, "%s: Entry\n",  __func__);
+
+	if (input != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int timblogiw_streamon(struct file *file, void  *priv, unsigned int type)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct timblogiw_fh *fh = priv;
+
+	dev_dbg(&vdev->dev, "%s: entry\n",  __func__);
+
+	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		dev_dbg(&vdev->dev, "%s - No capture device\n", __func__);
+		return -EINVAL;
+	}
+
+	fh->frame_count = 0;
+	return videobuf_streamon(&fh->vb_vidq);
+}
+
+static int timblogiw_streamoff(struct file *file, void  *priv,
+	unsigned int type)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct timblogiw_fh *fh = priv;
+
+	dev_dbg(&vdev->dev, "%s entry\n",  __func__);
+
+	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	return videobuf_streamoff(&fh->vb_vidq);
+}
+
+static int timblogiw_querystd(struct file *file, void  *priv, v4l2_std_id *std)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct timblogiw *lw = video_get_drvdata(vdev);
+	struct timblogiw_fh *fh = priv;
+
+	dev_dbg(&vdev->dev, "%s entry\n",  __func__);
+
+	if (TIMBLOGIW_HAS_DECODER(lw))
+		return v4l2_subdev_call(lw->sd_enc, video, querystd, std);
+	else {
+		*std = fh->cur_norm->std;
+		return 0;
+	}
+}
+
+static int timblogiw_enum_framesizes(struct file *file, void  *priv,
+	struct v4l2_frmsizeenum *fsize)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct timblogiw_fh *fh = priv;
+
+	dev_dbg(&vdev->dev, "%s - index: %d, format: %d\n",  __func__,
+		fsize->index, fsize->pixel_format);
+
+	if ((fsize->index != 0) ||
+		(fsize->pixel_format != V4L2_PIX_FMT_UYVY))
+		return -EINVAL;
+
+	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+	fsize->discrete.width = fh->cur_norm->width;
+	fsize->discrete.height = fh->cur_norm->height;
+
+	return 0;
+}
+
+/* Video buffer functions */
+
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+	unsigned int *size)
+{
+	struct timblogiw_fh *fh = vq->priv_data;
+
+	*size = timblogiw_frame_size(fh->cur_norm);
+
+	if (!*count)
+		*count = 32;
+
+	while (*size * *count > TIMBLOGIW_MAX_VIDEO_MEM * 1024 * 1024)
+		(*count)--;
+
+	return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+	enum v4l2_field field)
+{
+	struct timblogiw_fh *fh = vq->priv_data;
+	struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer,
+		vb);
+	unsigned int data_size = timblogiw_frame_size(fh->cur_norm);
+	int err = 0;
+
+	if (vb->baddr && vb->bsize < data_size)
+		/* User provided buffer, but it is too small */
+		return -ENOMEM;
+
+	vb->size = data_size;
+	vb->width = fh->cur_norm->width;
+	vb->height = fh->cur_norm->height;
+	vb->field = field;
+
+	if (vb->state == VIDEOBUF_NEEDS_INIT) {
+		int i;
+		unsigned int size;
+		unsigned int bytes_per_desc = TIMBLOGIW_LINES_PER_DESC *
+			timblogiw_bytes_per_line(fh->cur_norm);
+		dma_addr_t addr;
+
+		sg_init_table(buf->sg, ARRAY_SIZE(buf->sg));
+
+		err = videobuf_iolock(vq, vb, NULL);
+		if (err)
+			goto err;
+
+		addr = videobuf_to_dma_contig(vb);
+		for (i = 0, size = 0; size < data_size; i++) {
+			sg_dma_address(buf->sg + i) = addr + size;
+			size += bytes_per_desc;
+			sg_dma_len(buf->sg + i) = (size > data_size) ?
+				(bytes_per_desc - (size - data_size)) :
+				bytes_per_desc;
+		}
+
+		vb->state = VIDEOBUF_PREPARED;
+		buf->cookie = -1;
+		buf->fh = fh;
+	}
+
+	return 0;
+
+err:
+	videobuf_dma_contig_free(vq, vb);
+	vb->state = VIDEOBUF_NEEDS_INIT;
+	return err;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct timblogiw_fh *fh = vq->priv_data;
+	struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer,
+		vb);
+	struct dma_async_tx_descriptor *desc;
+	int sg_elems;
+	int bytes_per_desc = TIMBLOGIW_LINES_PER_DESC *
+		timblogiw_bytes_per_line(fh->cur_norm);
+
+	sg_elems = timblogiw_frame_size(fh->cur_norm) / bytes_per_desc;
+	sg_elems +=
+		(timblogiw_frame_size(fh->cur_norm) % bytes_per_desc) ? 1 : 0;
+
+	if (list_empty(&fh->capture))
+		vb->state = VIDEOBUF_ACTIVE;
+	else
+		vb->state = VIDEOBUF_QUEUED;
+
+	list_add_tail(&vb->queue, &fh->capture);
+
+	spin_unlock_irq(&fh->queue_lock);
+
+	desc = dmaengine_prep_slave_sg(fh->chan,
+		buf->sg, sg_elems, DMA_DEV_TO_MEM,
+		DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
+	if (!desc) {
+		spin_lock_irq(&fh->queue_lock);
+		list_del_init(&vb->queue);
+		vb->state = VIDEOBUF_PREPARED;
+		return;
+	}
+
+	desc->callback_param = buf;
+	desc->callback = timblogiw_dma_cb;
+
+	buf->cookie = desc->tx_submit(desc);
+
+	spin_lock_irq(&fh->queue_lock);
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+	struct videobuf_buffer *vb)
+{
+	struct timblogiw_fh *fh = vq->priv_data;
+	struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer,
+		vb);
+
+	videobuf_waiton(vq, vb, 0, 0);
+	if (buf->cookie >= 0)
+		dma_sync_wait(fh->chan, buf->cookie);
+
+	videobuf_dma_contig_free(vq, vb);
+	vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops timblogiw_video_qops = {
+	.buf_setup      = buffer_setup,
+	.buf_prepare    = buffer_prepare,
+	.buf_queue      = buffer_queue,
+	.buf_release    = buffer_release,
+};
+
+/* Device Operations functions */
+
+static int timblogiw_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct timblogiw *lw = video_get_drvdata(vdev);
+	struct timblogiw_fh *fh;
+	v4l2_std_id std;
+	dma_cap_mask_t mask;
+	int err = 0;
+
+	dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+	mutex_lock(&lw->lock);
+	if (lw->opened) {
+		err = -EBUSY;
+		goto out;
+	}
+
+	if (TIMBLOGIW_HAS_DECODER(lw) && !lw->sd_enc) {
+		struct i2c_adapter *adapt;
+
+		/* find the video decoder */
+		adapt = i2c_get_adapter(lw->pdata.i2c_adapter);
+		if (!adapt) {
+			dev_err(&vdev->dev, "No I2C bus #%d\n",
+				lw->pdata.i2c_adapter);
+			err = -ENODEV;
+			goto out;
+		}
+
+		/* now find the encoder */
+		lw->sd_enc = v4l2_i2c_new_subdev_board(&lw->v4l2_dev, adapt,
+			lw->pdata.encoder.info, NULL);
+
+		i2c_put_adapter(adapt);
+
+		if (!lw->sd_enc) {
+			dev_err(&vdev->dev, "Failed to get encoder: %s\n",
+				lw->pdata.encoder.module_name);
+			err = -ENODEV;
+			goto out;
+		}
+	}
+
+	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+	if (!fh) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	fh->cur_norm = timblogiw_tvnorms;
+	timblogiw_querystd(file, fh, &std);
+	fh->cur_norm = timblogiw_get_norm(std);
+
+	INIT_LIST_HEAD(&fh->capture);
+	spin_lock_init(&fh->queue_lock);
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	dma_cap_set(DMA_PRIVATE, mask);
+
+	/* find the DMA channel */
+	fh->chan = dma_request_channel(mask, timblogiw_dma_filter_fn,
+			(void *)(uintptr_t)lw->pdata.dma_channel);
+	if (!fh->chan) {
+		dev_err(&vdev->dev, "Failed to get DMA channel\n");
+		kfree(fh);
+		err = -ENODEV;
+		goto out;
+	}
+
+	file->private_data = fh;
+	videobuf_queue_dma_contig_init(&fh->vb_vidq,
+		&timblogiw_video_qops, lw->dev, &fh->queue_lock,
+		V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+		sizeof(struct timblogiw_buffer), fh, NULL);
+
+	lw->opened = true;
+out:
+	mutex_unlock(&lw->lock);
+
+	return err;
+}
+
+static int timblogiw_close(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct timblogiw *lw = video_get_drvdata(vdev);
+	struct timblogiw_fh *fh = file->private_data;
+
+	dev_dbg(&vdev->dev, "%s: Entry\n",  __func__);
+
+	videobuf_stop(&fh->vb_vidq);
+	videobuf_mmap_free(&fh->vb_vidq);
+
+	dma_release_channel(fh->chan);
+
+	kfree(fh);
+
+	mutex_lock(&lw->lock);
+	lw->opened = false;
+	mutex_unlock(&lw->lock);
+	return 0;
+}
+
+static ssize_t timblogiw_read(struct file *file, char __user *data,
+	size_t count, loff_t *ppos)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct timblogiw_fh *fh = file->private_data;
+
+	dev_dbg(&vdev->dev, "%s: entry\n",  __func__);
+
+	return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
+		file->f_flags & O_NONBLOCK);
+}
+
+static unsigned int timblogiw_poll(struct file *file,
+	struct poll_table_struct *wait)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct timblogiw_fh *fh = file->private_data;
+
+	dev_dbg(&vdev->dev, "%s: entry\n",  __func__);
+
+	return videobuf_poll_stream(file, &fh->vb_vidq, wait);
+}
+
+static int timblogiw_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct timblogiw_fh *fh = file->private_data;
+
+	dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+	return videobuf_mmap_mapper(&fh->vb_vidq, vma);
+}
+
+/* Platform device functions */
+
+static __devinitconst struct v4l2_ioctl_ops timblogiw_ioctl_ops = {
+	.vidioc_querycap		= timblogiw_querycap,
+	.vidioc_enum_fmt_vid_cap	= timblogiw_enum_fmt,
+	.vidioc_g_fmt_vid_cap		= timblogiw_g_fmt,
+	.vidioc_try_fmt_vid_cap		= timblogiw_try_fmt,
+	.vidioc_s_fmt_vid_cap		= timblogiw_s_fmt,
+	.vidioc_g_parm			= timblogiw_g_parm,
+	.vidioc_reqbufs			= timblogiw_reqbufs,
+	.vidioc_querybuf		= timblogiw_querybuf,
+	.vidioc_qbuf			= timblogiw_qbuf,
+	.vidioc_dqbuf			= timblogiw_dqbuf,
+	.vidioc_g_std			= timblogiw_g_std,
+	.vidioc_s_std			= timblogiw_s_std,
+	.vidioc_enum_input		= timblogiw_enuminput,
+	.vidioc_g_input			= timblogiw_g_input,
+	.vidioc_s_input			= timblogiw_s_input,
+	.vidioc_streamon		= timblogiw_streamon,
+	.vidioc_streamoff		= timblogiw_streamoff,
+	.vidioc_querystd		= timblogiw_querystd,
+	.vidioc_enum_framesizes		= timblogiw_enum_framesizes,
+};
+
+static __devinitconst struct v4l2_file_operations timblogiw_fops = {
+	.owner		= THIS_MODULE,
+	.open		= timblogiw_open,
+	.release	= timblogiw_close,
+	.unlocked_ioctl		= video_ioctl2, /* V4L2 ioctl handler */
+	.mmap		= timblogiw_mmap,
+	.read		= timblogiw_read,
+	.poll		= timblogiw_poll,
+};
+
+static __devinitconst struct video_device timblogiw_template = {
+	.name		= TIMBLOGIWIN_NAME,
+	.fops		= &timblogiw_fops,
+	.ioctl_ops	= &timblogiw_ioctl_ops,
+	.release	= video_device_release_empty,
+	.minor		= -1,
+	.tvnorms	= V4L2_STD_PAL | V4L2_STD_NTSC
+};
+
+static int __devinit timblogiw_probe(struct platform_device *pdev)
+{
+	int err;
+	struct timblogiw *lw = NULL;
+	struct timb_video_platform_data *pdata = pdev->dev.platform_data;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "No platform data\n");
+		err = -EINVAL;
+		goto err;
+	}
+
+	if (!pdata->encoder.module_name)
+		dev_info(&pdev->dev, "Running without decoder\n");
+
+	lw = kzalloc(sizeof(*lw), GFP_KERNEL);
+	if (!lw) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	if (pdev->dev.parent)
+		lw->dev = pdev->dev.parent;
+	else
+		lw->dev = &pdev->dev;
+
+	memcpy(&lw->pdata, pdata, sizeof(lw->pdata));
+
+	mutex_init(&lw->lock);
+
+	lw->video_dev = timblogiw_template;
+
+	strlcpy(lw->v4l2_dev.name, DRIVER_NAME, sizeof(lw->v4l2_dev.name));
+	err = v4l2_device_register(NULL, &lw->v4l2_dev);
+	if (err)
+		goto err_register;
+
+	lw->video_dev.v4l2_dev = &lw->v4l2_dev;
+
+	platform_set_drvdata(pdev, lw);
+	video_set_drvdata(&lw->video_dev, lw);
+
+	err = video_register_device(&lw->video_dev, VFL_TYPE_GRABBER, 0);
+	if (err) {
+		dev_err(&pdev->dev, "Error reg video: %d\n", err);
+		goto err_request;
+	}
+
+
+	return 0;
+
+err_request:
+	platform_set_drvdata(pdev, NULL);
+	v4l2_device_unregister(&lw->v4l2_dev);
+err_register:
+	kfree(lw);
+err:
+	dev_err(&pdev->dev, "Failed to register: %d\n", err);
+
+	return err;
+}
+
+static int __devexit timblogiw_remove(struct platform_device *pdev)
+{
+	struct timblogiw *lw = platform_get_drvdata(pdev);
+
+	video_unregister_device(&lw->video_dev);
+
+	v4l2_device_unregister(&lw->v4l2_dev);
+
+	kfree(lw);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver timblogiw_platform_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= timblogiw_probe,
+	.remove		= __devexit_p(timblogiw_remove),
+};
+
+module_platform_driver(timblogiw_platform_driver);
+
+MODULE_DESCRIPTION(TIMBLOGIWIN_NAME);
+MODULE_AUTHOR("Pelagicore AB <info@pelagicore.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:"DRIVER_NAME);
diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c
new file mode 100644
index 0000000..eb404c2
--- /dev/null
+++ b/drivers/media/platform/via-camera.c
@@ -0,0 +1,1514 @@
+/*
+ * Driver for the VIA Chrome integrated camera controller.
+ *
+ * Copyright 2009,2010 Jonathan Corbet <corbet@lwn.net>
+ * Distributable under the terms of the GNU General Public License, version 2
+ *
+ * This work was supported by the One Laptop Per Child project
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/ov7670.h>
+#include <media/videobuf-dma-sg.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_qos.h>
+#include <linux/via-core.h>
+#include <linux/via-gpio.h>
+#include <linux/via_i2c.h>
+#include <asm/olpc.h>
+
+#include "via-camera.h"
+
+MODULE_ALIAS("platform:viafb-camera");
+MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
+MODULE_DESCRIPTION("VIA framebuffer-based camera controller driver");
+MODULE_LICENSE("GPL");
+
+static bool flip_image;
+module_param(flip_image, bool, 0444);
+MODULE_PARM_DESC(flip_image,
+		"If set, the sensor will be instructed to flip the image "
+		"vertically.");
+
+static bool override_serial;
+module_param(override_serial, bool, 0444);
+MODULE_PARM_DESC(override_serial,
+		"The camera driver will normally refuse to load if "
+		"the XO 1.5 serial port is enabled.  Set this option "
+		"to force-enable the camera.");
+
+/*
+ * Basic window sizes.
+ */
+#define VGA_WIDTH	640
+#define VGA_HEIGHT	480
+#define QCIF_WIDTH	176
+#define	QCIF_HEIGHT	144
+
+/*
+ * The structure describing our camera.
+ */
+enum viacam_opstate { S_IDLE = 0, S_RUNNING = 1 };
+
+struct via_camera {
+	struct v4l2_device v4l2_dev;
+	struct video_device vdev;
+	struct v4l2_subdev *sensor;
+	struct platform_device *platdev;
+	struct viafb_dev *viadev;
+	struct mutex lock;
+	enum viacam_opstate opstate;
+	unsigned long flags;
+	struct pm_qos_request qos_request;
+	/*
+	 * GPIO info for power/reset management
+	 */
+	int power_gpio;
+	int reset_gpio;
+	/*
+	 * I/O memory stuff.
+	 */
+	void __iomem *mmio;	/* Where the registers live */
+	void __iomem *fbmem;	/* Frame buffer memory */
+	u32 fb_offset;		/* Reserved memory offset (FB) */
+	/*
+	 * Capture buffers and related.	 The controller supports
+	 * up to three, so that's what we have here.  These buffers
+	 * live in frame buffer memory, so we don't call them "DMA".
+	 */
+	unsigned int cb_offsets[3];	/* offsets into fb mem */
+	u8 *cb_addrs[3];		/* Kernel-space addresses */
+	int n_cap_bufs;			/* How many are we using? */
+	int next_buf;
+	struct videobuf_queue vb_queue;
+	struct list_head buffer_queue;	/* prot. by reg_lock */
+	/*
+	 * User tracking.
+	 */
+	int users;
+	struct file *owner;
+	/*
+	 * Video format information.  sensor_format is kept in a form
+	 * that we can use to pass to the sensor.  We always run the
+	 * sensor in VGA resolution, though, and let the controller
+	 * downscale things if need be.	 So we keep the "real*
+	 * dimensions separately.
+	 */
+	struct v4l2_pix_format sensor_format;
+	struct v4l2_pix_format user_format;
+	enum v4l2_mbus_pixelcode mbus_code;
+};
+
+/*
+ * Yes, this is a hack, but there's only going to be one of these
+ * on any system we know of.
+ */
+static struct via_camera *via_cam_info;
+
+/*
+ * Flag values, manipulated with bitops
+ */
+#define CF_DMA_ACTIVE	 0	/* A frame is incoming */
+#define CF_CONFIG_NEEDED 1	/* Must configure hardware */
+
+
+/*
+ * Nasty ugly v4l2 boilerplate.
+ */
+#define sensor_call(cam, optype, func, args...) \
+	v4l2_subdev_call(cam->sensor, optype, func, ##args)
+
+/*
+ * Debugging and related.
+ */
+#define cam_err(cam, fmt, arg...) \
+	dev_err(&(cam)->platdev->dev, fmt, ##arg);
+#define cam_warn(cam, fmt, arg...) \
+	dev_warn(&(cam)->platdev->dev, fmt, ##arg);
+#define cam_dbg(cam, fmt, arg...) \
+	dev_dbg(&(cam)->platdev->dev, fmt, ##arg);
+
+/*
+ * Format handling.  This is ripped almost directly from Hans's changes
+ * to cafe_ccic.c.  It's a little unfortunate; until this change, we
+ * didn't need to know anything about the format except its byte depth;
+ * now this information must be managed at this level too.
+ */
+static struct via_format {
+	__u8 *desc;
+	__u32 pixelformat;
+	int bpp;   /* Bytes per pixel */
+	enum v4l2_mbus_pixelcode mbus_code;
+} via_formats[] = {
+	{
+		.desc		= "YUYV 4:2:2",
+		.pixelformat	= V4L2_PIX_FMT_YUYV,
+		.mbus_code	= V4L2_MBUS_FMT_YUYV8_2X8,
+		.bpp		= 2,
+	},
+	/* RGB444 and Bayer should be doable, but have never been
+	   tested with this driver. RGB565 seems to work at the default
+	   resolution, but results in color corruption when being scaled by
+	   viacam_set_scaled(), and is disabled as a result. */
+};
+#define N_VIA_FMTS ARRAY_SIZE(via_formats)
+
+static struct via_format *via_find_format(u32 pixelformat)
+{
+	unsigned i;
+
+	for (i = 0; i < N_VIA_FMTS; i++)
+		if (via_formats[i].pixelformat == pixelformat)
+			return via_formats + i;
+	/* Not found? Then return the first format. */
+	return via_formats;
+}
+
+
+/*--------------------------------------------------------------------------*/
+/*
+ * Sensor power/reset management.  This piece is OLPC-specific for
+ * sure; other configurations will have things connected differently.
+ */
+static int via_sensor_power_setup(struct via_camera *cam)
+{
+	int ret;
+
+	cam->power_gpio = viafb_gpio_lookup("VGPIO3");
+	cam->reset_gpio = viafb_gpio_lookup("VGPIO2");
+	if (cam->power_gpio < 0 || cam->reset_gpio < 0) {
+		dev_err(&cam->platdev->dev, "Unable to find GPIO lines\n");
+		return -EINVAL;
+	}
+	ret = gpio_request(cam->power_gpio, "viafb-camera");
+	if (ret) {
+		dev_err(&cam->platdev->dev, "Unable to request power GPIO\n");
+		return ret;
+	}
+	ret = gpio_request(cam->reset_gpio, "viafb-camera");
+	if (ret) {
+		dev_err(&cam->platdev->dev, "Unable to request reset GPIO\n");
+		gpio_free(cam->power_gpio);
+		return ret;
+	}
+	gpio_direction_output(cam->power_gpio, 0);
+	gpio_direction_output(cam->reset_gpio, 0);
+	return 0;
+}
+
+/*
+ * Power up the sensor and perform the reset dance.
+ */
+static void via_sensor_power_up(struct via_camera *cam)
+{
+	gpio_set_value(cam->power_gpio, 1);
+	gpio_set_value(cam->reset_gpio, 0);
+	msleep(20);  /* Probably excessive */
+	gpio_set_value(cam->reset_gpio, 1);
+	msleep(20);
+}
+
+static void via_sensor_power_down(struct via_camera *cam)
+{
+	gpio_set_value(cam->power_gpio, 0);
+	gpio_set_value(cam->reset_gpio, 0);
+}
+
+
+static void via_sensor_power_release(struct via_camera *cam)
+{
+	via_sensor_power_down(cam);
+	gpio_free(cam->power_gpio);
+	gpio_free(cam->reset_gpio);
+}
+
+/* --------------------------------------------------------------------------*/
+/* Sensor ops */
+
+/*
+ * Manage the ov7670 "flip" bit, which needs special help.
+ */
+static int viacam_set_flip(struct via_camera *cam)
+{
+	struct v4l2_control ctrl;
+
+	memset(&ctrl, 0, sizeof(ctrl));
+	ctrl.id = V4L2_CID_VFLIP;
+	ctrl.value = flip_image;
+	return sensor_call(cam, core, s_ctrl, &ctrl);
+}
+
+/*
+ * Configure the sensor.  It's up to the caller to ensure
+ * that the camera is in the correct operating state.
+ */
+static int viacam_configure_sensor(struct via_camera *cam)
+{
+	struct v4l2_mbus_framefmt mbus_fmt;
+	int ret;
+
+	v4l2_fill_mbus_format(&mbus_fmt, &cam->sensor_format, cam->mbus_code);
+	ret = sensor_call(cam, core, init, 0);
+	if (ret == 0)
+		ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt);
+	/*
+	 * OV7670 does weird things if flip is set *before* format...
+	 */
+	if (ret == 0)
+		ret = viacam_set_flip(cam);
+	return ret;
+}
+
+
+
+/* --------------------------------------------------------------------------*/
+/*
+ * Some simple register accessors; they assume that the lock is held.
+ *
+ * Should we want to support the second capture engine, we could
+ * hide the register difference by adding 0x1000 to registers in the
+ * 0x300-350 range.
+ */
+static inline void viacam_write_reg(struct via_camera *cam,
+		int reg, int value)
+{
+	iowrite32(value, cam->mmio + reg);
+}
+
+static inline int viacam_read_reg(struct via_camera *cam, int reg)
+{
+	return ioread32(cam->mmio + reg);
+}
+
+static inline void viacam_write_reg_mask(struct via_camera *cam,
+		int reg, int value, int mask)
+{
+	int tmp = viacam_read_reg(cam, reg);
+
+	tmp = (tmp & ~mask) | (value & mask);
+	viacam_write_reg(cam, reg, tmp);
+}
+
+
+/* --------------------------------------------------------------------------*/
+/* Interrupt management and handling */
+
+static irqreturn_t viacam_quick_irq(int irq, void *data)
+{
+	struct via_camera *cam = data;
+	irqreturn_t ret = IRQ_NONE;
+	int icv;
+
+	/*
+	 * All we do here is to clear the interrupts and tell
+	 * the handler thread to wake up.
+	 */
+	spin_lock(&cam->viadev->reg_lock);
+	icv = viacam_read_reg(cam, VCR_INTCTRL);
+	if (icv & VCR_IC_EAV) {
+		icv |= VCR_IC_EAV|VCR_IC_EVBI|VCR_IC_FFULL;
+		viacam_write_reg(cam, VCR_INTCTRL, icv);
+		ret = IRQ_WAKE_THREAD;
+	}
+	spin_unlock(&cam->viadev->reg_lock);
+	return ret;
+}
+
+/*
+ * Find the next videobuf buffer which has somebody waiting on it.
+ */
+static struct videobuf_buffer *viacam_next_buffer(struct via_camera *cam)
+{
+	unsigned long flags;
+	struct videobuf_buffer *buf = NULL;
+
+	spin_lock_irqsave(&cam->viadev->reg_lock, flags);
+	if (cam->opstate != S_RUNNING)
+		goto out;
+	if (list_empty(&cam->buffer_queue))
+		goto out;
+	buf = list_entry(cam->buffer_queue.next, struct videobuf_buffer, queue);
+	if (!waitqueue_active(&buf->done)) {/* Nobody waiting */
+		buf = NULL;
+		goto out;
+	}
+	list_del(&buf->queue);
+	buf->state = VIDEOBUF_ACTIVE;
+out:
+	spin_unlock_irqrestore(&cam->viadev->reg_lock, flags);
+	return buf;
+}
+
+/*
+ * The threaded IRQ handler.
+ */
+static irqreturn_t viacam_irq(int irq, void *data)
+{
+	int bufn;
+	struct videobuf_buffer *vb;
+	struct via_camera *cam = data;
+	struct videobuf_dmabuf *vdma;
+
+	/*
+	 * If there is no place to put the data frame, don't bother
+	 * with anything else.
+	 */
+	vb = viacam_next_buffer(cam);
+	if (vb == NULL)
+		goto done;
+	/*
+	 * Figure out which buffer we just completed.
+	 */
+	bufn = (viacam_read_reg(cam, VCR_INTCTRL) & VCR_IC_ACTBUF) >> 3;
+	bufn -= 1;
+	if (bufn < 0)
+		bufn = cam->n_cap_bufs - 1;
+	/*
+	 * Copy over the data and let any waiters know.
+	 */
+	vdma = videobuf_to_dma(vb);
+	viafb_dma_copy_out_sg(cam->cb_offsets[bufn], vdma->sglist, vdma->sglen);
+	vb->state = VIDEOBUF_DONE;
+	vb->size = cam->user_format.sizeimage;
+	wake_up(&vb->done);
+done:
+	return IRQ_HANDLED;
+}
+
+
+/*
+ * These functions must mess around with the general interrupt
+ * control register, which is relevant to much more than just the
+ * camera.  Nothing else uses interrupts, though, as of this writing.
+ * Should that situation change, we'll have to improve support at
+ * the via-core level.
+ */
+static void viacam_int_enable(struct via_camera *cam)
+{
+	viacam_write_reg(cam, VCR_INTCTRL,
+			VCR_IC_INTEN|VCR_IC_EAV|VCR_IC_EVBI|VCR_IC_FFULL);
+	viafb_irq_enable(VDE_I_C0AVEN);
+}
+
+static void viacam_int_disable(struct via_camera *cam)
+{
+	viafb_irq_disable(VDE_I_C0AVEN);
+	viacam_write_reg(cam, VCR_INTCTRL, 0);
+}
+
+
+
+/* --------------------------------------------------------------------------*/
+/* Controller operations */
+
+/*
+ * Set up our capture buffers in framebuffer memory.
+ */
+static int viacam_ctlr_cbufs(struct via_camera *cam)
+{
+	int nbuf = cam->viadev->camera_fbmem_size/cam->sensor_format.sizeimage;
+	int i;
+	unsigned int offset;
+
+	/*
+	 * See how many buffers we can work with.
+	 */
+	if (nbuf >= 3) {
+		cam->n_cap_bufs = 3;
+		viacam_write_reg_mask(cam, VCR_CAPINTC, VCR_CI_3BUFS,
+				VCR_CI_3BUFS);
+	} else if (nbuf == 2) {
+		cam->n_cap_bufs = 2;
+		viacam_write_reg_mask(cam, VCR_CAPINTC, 0, VCR_CI_3BUFS);
+	} else {
+		cam_warn(cam, "Insufficient frame buffer memory\n");
+		return -ENOMEM;
+	}
+	/*
+	 * Set them up.
+	 */
+	offset = cam->fb_offset;
+	for (i = 0; i < cam->n_cap_bufs; i++) {
+		cam->cb_offsets[i] = offset;
+		cam->cb_addrs[i] = cam->fbmem + offset;
+		viacam_write_reg(cam, VCR_VBUF1 + i*4, offset & VCR_VBUF_MASK);
+		offset += cam->sensor_format.sizeimage;
+	}
+	return 0;
+}
+
+/*
+ * Set the scaling register for downscaling the image.
+ *
+ * This register works like this...  Vertical scaling is enabled
+ * by bit 26; if that bit is set, downscaling is controlled by the
+ * value in bits 16:25.	 Those bits are divided by 1024 to get
+ * the scaling factor; setting just bit 25 thus cuts the height
+ * in half.
+ *
+ * Horizontal scaling works about the same, but it's enabled by
+ * bit 11, with bits 0:10 giving the numerator of a fraction
+ * (over 2048) for the scaling value.
+ *
+ * This function is naive in that, if the user departs from
+ * the 3x4 VGA scaling factor, the image will distort.	We
+ * could work around that if it really seemed important.
+ */
+static void viacam_set_scale(struct via_camera *cam)
+{
+	unsigned int avscale;
+	int sf;
+
+	if (cam->user_format.width == VGA_WIDTH)
+		avscale = 0;
+	else {
+		sf = (cam->user_format.width*2048)/VGA_WIDTH;
+		avscale = VCR_AVS_HEN | sf;
+	}
+	if (cam->user_format.height < VGA_HEIGHT) {
+		sf = (1024*cam->user_format.height)/VGA_HEIGHT;
+		avscale |= VCR_AVS_VEN | (sf << 16);
+	}
+	viacam_write_reg(cam, VCR_AVSCALE, avscale);
+}
+
+
+/*
+ * Configure image-related information into the capture engine.
+ */
+static void viacam_ctlr_image(struct via_camera *cam)
+{
+	int cicreg;
+
+	/*
+	 * Disable clock before messing with stuff - from the via
+	 * sample driver.
+	 */
+	viacam_write_reg(cam, VCR_CAPINTC, ~(VCR_CI_ENABLE|VCR_CI_CLKEN));
+	/*
+	 * Set up the controller for VGA resolution, modulo magic
+	 * offsets from the via sample driver.
+	 */
+	viacam_write_reg(cam, VCR_HORRANGE, 0x06200120);
+	viacam_write_reg(cam, VCR_VERTRANGE, 0x01de0000);
+	viacam_set_scale(cam);
+	/*
+	 * Image size info.
+	 */
+	viacam_write_reg(cam, VCR_MAXDATA,
+			(cam->sensor_format.height << 16) |
+			(cam->sensor_format.bytesperline >> 3));
+	viacam_write_reg(cam, VCR_MAXVBI, 0);
+	viacam_write_reg(cam, VCR_VSTRIDE,
+			cam->user_format.bytesperline & VCR_VS_STRIDE);
+	/*
+	 * Set up the capture interface control register,
+	 * everything but the "go" bit.
+	 *
+	 * The FIFO threshold is a bit of a magic number; 8 is what
+	 * VIA's sample code uses.
+	 */
+	cicreg = VCR_CI_CLKEN |
+		0x08000000 |		/* FIFO threshold */
+		VCR_CI_FLDINV |		/* OLPC-specific? */
+		VCR_CI_VREFINV |	/* OLPC-specific? */
+		VCR_CI_DIBOTH |		/* Capture both fields */
+		VCR_CI_CCIR601_8;
+	if (cam->n_cap_bufs == 3)
+		cicreg |= VCR_CI_3BUFS;
+	/*
+	 * YUV formats need different byte swapping than RGB.
+	 */
+	if (cam->user_format.pixelformat == V4L2_PIX_FMT_YUYV)
+		cicreg |= VCR_CI_YUYV;
+	else
+		cicreg |= VCR_CI_UYVY;
+	viacam_write_reg(cam, VCR_CAPINTC, cicreg);
+}
+
+
+static int viacam_config_controller(struct via_camera *cam)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cam->viadev->reg_lock, flags);
+	ret = viacam_ctlr_cbufs(cam);
+	if (!ret)
+		viacam_ctlr_image(cam);
+	spin_unlock_irqrestore(&cam->viadev->reg_lock, flags);
+	clear_bit(CF_CONFIG_NEEDED, &cam->flags);
+	return ret;
+}
+
+/*
+ * Make it start grabbing data.
+ */
+static void viacam_start_engine(struct via_camera *cam)
+{
+	spin_lock_irq(&cam->viadev->reg_lock);
+	cam->next_buf = 0;
+	viacam_write_reg_mask(cam, VCR_CAPINTC, VCR_CI_ENABLE, VCR_CI_ENABLE);
+	viacam_int_enable(cam);
+	(void) viacam_read_reg(cam, VCR_CAPINTC); /* Force post */
+	cam->opstate = S_RUNNING;
+	spin_unlock_irq(&cam->viadev->reg_lock);
+}
+
+
+static void viacam_stop_engine(struct via_camera *cam)
+{
+	spin_lock_irq(&cam->viadev->reg_lock);
+	viacam_int_disable(cam);
+	viacam_write_reg_mask(cam, VCR_CAPINTC, 0, VCR_CI_ENABLE);
+	(void) viacam_read_reg(cam, VCR_CAPINTC); /* Force post */
+	cam->opstate = S_IDLE;
+	spin_unlock_irq(&cam->viadev->reg_lock);
+}
+
+
+/* --------------------------------------------------------------------------*/
+/* Videobuf callback ops */
+
+/*
+ * buffer_setup.  The purpose of this one would appear to be to tell
+ * videobuf how big a single image is.	It's also evidently up to us
+ * to put some sort of limit on the maximum number of buffers allowed.
+ */
+static int viacam_vb_buf_setup(struct videobuf_queue *q,
+		unsigned int *count, unsigned int *size)
+{
+	struct via_camera *cam = q->priv_data;
+
+	*size = cam->user_format.sizeimage;
+	if (*count == 0 || *count > 6)	/* Arbitrary number */
+		*count = 6;
+	return 0;
+}
+
+/*
+ * Prepare a buffer.
+ */
+static int viacam_vb_buf_prepare(struct videobuf_queue *q,
+		struct videobuf_buffer *vb, enum v4l2_field field)
+{
+	struct via_camera *cam = q->priv_data;
+
+	vb->size = cam->user_format.sizeimage;
+	vb->width = cam->user_format.width; /* bytesperline???? */
+	vb->height = cam->user_format.height;
+	vb->field = field;
+	if (vb->state == VIDEOBUF_NEEDS_INIT) {
+		int ret = videobuf_iolock(q, vb, NULL);
+		if (ret)
+			return ret;
+	}
+	vb->state = VIDEOBUF_PREPARED;
+	return 0;
+}
+
+/*
+ * We've got a buffer to put data into.
+ *
+ * FIXME: check for a running engine and valid buffers?
+ */
+static void viacam_vb_buf_queue(struct videobuf_queue *q,
+		struct videobuf_buffer *vb)
+{
+	struct via_camera *cam = q->priv_data;
+
+	/*
+	 * Note that videobuf holds the lock when it calls
+	 * us, so we need not (indeed, cannot) take it here.
+	 */
+	vb->state = VIDEOBUF_QUEUED;
+	list_add_tail(&vb->queue, &cam->buffer_queue);
+}
+
+/*
+ * Free a buffer.
+ */
+static void viacam_vb_buf_release(struct videobuf_queue *q,
+		struct videobuf_buffer *vb)
+{
+	struct via_camera *cam = q->priv_data;
+
+	videobuf_dma_unmap(&cam->platdev->dev, videobuf_to_dma(vb));
+	videobuf_dma_free(videobuf_to_dma(vb));
+	vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static const struct videobuf_queue_ops viacam_vb_ops = {
+	.buf_setup	= viacam_vb_buf_setup,
+	.buf_prepare	= viacam_vb_buf_prepare,
+	.buf_queue	= viacam_vb_buf_queue,
+	.buf_release	= viacam_vb_buf_release,
+};
+
+/* --------------------------------------------------------------------------*/
+/* File operations */
+
+static int viacam_open(struct file *filp)
+{
+	struct via_camera *cam = video_drvdata(filp);
+
+	filp->private_data = cam;
+	/*
+	 * Note the new user.  If this is the first one, we'll also
+	 * need to power up the sensor.
+	 */
+	mutex_lock(&cam->lock);
+	if (cam->users == 0) {
+		int ret = viafb_request_dma();
+
+		if (ret) {
+			mutex_unlock(&cam->lock);
+			return ret;
+		}
+		via_sensor_power_up(cam);
+		set_bit(CF_CONFIG_NEEDED, &cam->flags);
+		/*
+		 * Hook into videobuf.	Evidently this cannot fail.
+		 */
+		videobuf_queue_sg_init(&cam->vb_queue, &viacam_vb_ops,
+				&cam->platdev->dev, &cam->viadev->reg_lock,
+				V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+				sizeof(struct videobuf_buffer), cam, NULL);
+	}
+	(cam->users)++;
+	mutex_unlock(&cam->lock);
+	return 0;
+}
+
+static int viacam_release(struct file *filp)
+{
+	struct via_camera *cam = video_drvdata(filp);
+
+	mutex_lock(&cam->lock);
+	(cam->users)--;
+	/*
+	 * If the "owner" is closing, shut down any ongoing
+	 * operations.
+	 */
+	if (filp == cam->owner) {
+		videobuf_stop(&cam->vb_queue);
+		/*
+		 * We don't hold the spinlock here, but, if release()
+		 * is being called by the owner, nobody else will
+		 * be changing the state.  And an extra stop would
+		 * not hurt anyway.
+		 */
+		if (cam->opstate != S_IDLE)
+			viacam_stop_engine(cam);
+		cam->owner = NULL;
+	}
+	/*
+	 * Last one out needs to turn out the lights.
+	 */
+	if (cam->users == 0) {
+		videobuf_mmap_free(&cam->vb_queue);
+		via_sensor_power_down(cam);
+		viafb_release_dma();
+	}
+	mutex_unlock(&cam->lock);
+	return 0;
+}
+
+/*
+ * Read a frame from the device.
+ */
+static ssize_t viacam_read(struct file *filp, char __user *buffer,
+		size_t len, loff_t *pos)
+{
+	struct via_camera *cam = video_drvdata(filp);
+	int ret;
+
+	mutex_lock(&cam->lock);
+	/*
+	 * Enforce the V4l2 "only one owner gets to read data" rule.
+	 */
+	if (cam->owner && cam->owner != filp) {
+		ret = -EBUSY;
+		goto out_unlock;
+	}
+	cam->owner = filp;
+	/*
+	 * Do we need to configure the hardware?
+	 */
+	if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) {
+		ret = viacam_configure_sensor(cam);
+		if (!ret)
+			ret = viacam_config_controller(cam);
+		if (ret)
+			goto out_unlock;
+	}
+	/*
+	 * Fire up the capture engine, then have videobuf do
+	 * the heavy lifting.  Someday it would be good to avoid
+	 * stopping and restarting the engine each time.
+	 */
+	INIT_LIST_HEAD(&cam->buffer_queue);
+	viacam_start_engine(cam);
+	ret = videobuf_read_stream(&cam->vb_queue, buffer, len, pos, 0,
+			filp->f_flags & O_NONBLOCK);
+	viacam_stop_engine(cam);
+	/* videobuf_stop() ?? */
+
+out_unlock:
+	mutex_unlock(&cam->lock);
+	return ret;
+}
+
+
+static unsigned int viacam_poll(struct file *filp, struct poll_table_struct *pt)
+{
+	struct via_camera *cam = video_drvdata(filp);
+
+	return videobuf_poll_stream(filp, &cam->vb_queue, pt);
+}
+
+
+static int viacam_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct via_camera *cam = video_drvdata(filp);
+
+	return videobuf_mmap_mapper(&cam->vb_queue, vma);
+}
+
+
+
+static const struct v4l2_file_operations viacam_fops = {
+	.owner		= THIS_MODULE,
+	.open		= viacam_open,
+	.release	= viacam_release,
+	.read		= viacam_read,
+	.poll		= viacam_poll,
+	.mmap		= viacam_mmap,
+	.unlocked_ioctl	= video_ioctl2,
+};
+
+/*----------------------------------------------------------------------------*/
+/*
+ * The long list of v4l2 ioctl ops
+ */
+
+static int viacam_g_chip_ident(struct file *file, void *priv,
+		struct v4l2_dbg_chip_ident *ident)
+{
+	struct via_camera *cam = priv;
+
+	ident->ident = V4L2_IDENT_NONE;
+	ident->revision = 0;
+	if (v4l2_chip_match_host(&ident->match)) {
+		ident->ident = V4L2_IDENT_VIA_VX855;
+		return 0;
+	}
+	return sensor_call(cam, core, g_chip_ident, ident);
+}
+
+/*
+ * Control ops are passed through to the sensor.
+ */
+static int viacam_queryctrl(struct file *filp, void *priv,
+		struct v4l2_queryctrl *qc)
+{
+	struct via_camera *cam = priv;
+	int ret;
+
+	mutex_lock(&cam->lock);
+	ret = sensor_call(cam, core, queryctrl, qc);
+	mutex_unlock(&cam->lock);
+	return ret;
+}
+
+
+static int viacam_g_ctrl(struct file *filp, void *priv,
+		struct v4l2_control *ctrl)
+{
+	struct via_camera *cam = priv;
+	int ret;
+
+	mutex_lock(&cam->lock);
+	ret = sensor_call(cam, core, g_ctrl, ctrl);
+	mutex_unlock(&cam->lock);
+	return ret;
+}
+
+
+static int viacam_s_ctrl(struct file *filp, void *priv,
+		struct v4l2_control *ctrl)
+{
+	struct via_camera *cam = priv;
+	int ret;
+
+	mutex_lock(&cam->lock);
+	ret = sensor_call(cam, core, s_ctrl, ctrl);
+	mutex_unlock(&cam->lock);
+	return ret;
+}
+
+/*
+ * Only one input.
+ */
+static int viacam_enum_input(struct file *filp, void *priv,
+		struct v4l2_input *input)
+{
+	if (input->index != 0)
+		return -EINVAL;
+
+	input->type = V4L2_INPUT_TYPE_CAMERA;
+	input->std = V4L2_STD_ALL; /* Not sure what should go here */
+	strcpy(input->name, "Camera");
+	return 0;
+}
+
+static int viacam_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int viacam_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int viacam_s_std(struct file *filp, void *priv, v4l2_std_id *std)
+{
+	return 0;
+}
+
+/*
+ * Video format stuff.	Here is our default format until
+ * user space messes with things.
+ */
+static const struct v4l2_pix_format viacam_def_pix_format = {
+	.width		= VGA_WIDTH,
+	.height		= VGA_HEIGHT,
+	.pixelformat	= V4L2_PIX_FMT_YUYV,
+	.field		= V4L2_FIELD_NONE,
+	.bytesperline	= VGA_WIDTH * 2,
+	.sizeimage	= VGA_WIDTH * VGA_HEIGHT * 2,
+};
+
+static const enum v4l2_mbus_pixelcode via_def_mbus_code = V4L2_MBUS_FMT_YUYV8_2X8;
+
+static int viacam_enum_fmt_vid_cap(struct file *filp, void *priv,
+		struct v4l2_fmtdesc *fmt)
+{
+	if (fmt->index >= N_VIA_FMTS)
+		return -EINVAL;
+	strlcpy(fmt->description, via_formats[fmt->index].desc,
+			sizeof(fmt->description));
+	fmt->pixelformat = via_formats[fmt->index].pixelformat;
+	return 0;
+}
+
+/*
+ * Figure out proper image dimensions, but always force the
+ * sensor to VGA.
+ */
+static void viacam_fmt_pre(struct v4l2_pix_format *userfmt,
+		struct v4l2_pix_format *sensorfmt)
+{
+	*sensorfmt = *userfmt;
+	if (userfmt->width < QCIF_WIDTH || userfmt->height < QCIF_HEIGHT) {
+		userfmt->width = QCIF_WIDTH;
+		userfmt->height = QCIF_HEIGHT;
+	}
+	if (userfmt->width > VGA_WIDTH || userfmt->height > VGA_HEIGHT) {
+		userfmt->width = VGA_WIDTH;
+		userfmt->height = VGA_HEIGHT;
+	}
+	sensorfmt->width = VGA_WIDTH;
+	sensorfmt->height = VGA_HEIGHT;
+}
+
+static void viacam_fmt_post(struct v4l2_pix_format *userfmt,
+		struct v4l2_pix_format *sensorfmt)
+{
+	struct via_format *f = via_find_format(userfmt->pixelformat);
+
+	sensorfmt->bytesperline = sensorfmt->width * f->bpp;
+	sensorfmt->sizeimage = sensorfmt->height * sensorfmt->bytesperline;
+	userfmt->pixelformat = sensorfmt->pixelformat;
+	userfmt->field = sensorfmt->field;
+	userfmt->bytesperline = 2 * userfmt->width;
+	userfmt->sizeimage = userfmt->bytesperline * userfmt->height;
+}
+
+
+/*
+ * The real work of figuring out a workable format.
+ */
+static int viacam_do_try_fmt(struct via_camera *cam,
+		struct v4l2_pix_format *upix, struct v4l2_pix_format *spix)
+{
+	int ret;
+	struct v4l2_mbus_framefmt mbus_fmt;
+	struct via_format *f = via_find_format(upix->pixelformat);
+
+	upix->pixelformat = f->pixelformat;
+	viacam_fmt_pre(upix, spix);
+	v4l2_fill_mbus_format(&mbus_fmt, spix, f->mbus_code);
+	ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt);
+	v4l2_fill_pix_format(spix, &mbus_fmt);
+	viacam_fmt_post(upix, spix);
+	return ret;
+}
+
+
+
+static int viacam_try_fmt_vid_cap(struct file *filp, void *priv,
+		struct v4l2_format *fmt)
+{
+	struct via_camera *cam = priv;
+	struct v4l2_format sfmt;
+	int ret;
+
+	mutex_lock(&cam->lock);
+	ret = viacam_do_try_fmt(cam, &fmt->fmt.pix, &sfmt.fmt.pix);
+	mutex_unlock(&cam->lock);
+	return ret;
+}
+
+
+static int viacam_g_fmt_vid_cap(struct file *filp, void *priv,
+		struct v4l2_format *fmt)
+{
+	struct via_camera *cam = priv;
+
+	mutex_lock(&cam->lock);
+	fmt->fmt.pix = cam->user_format;
+	mutex_unlock(&cam->lock);
+	return 0;
+}
+
+static int viacam_s_fmt_vid_cap(struct file *filp, void *priv,
+		struct v4l2_format *fmt)
+{
+	struct via_camera *cam = priv;
+	int ret;
+	struct v4l2_format sfmt;
+	struct via_format *f = via_find_format(fmt->fmt.pix.pixelformat);
+
+	/*
+	 * Camera must be idle or we can't mess with the
+	 * video setup.
+	 */
+	mutex_lock(&cam->lock);
+	if (cam->opstate != S_IDLE) {
+		ret = -EBUSY;
+		goto out;
+	}
+	/*
+	 * Let the sensor code look over and tweak the
+	 * requested formatting.
+	 */
+	ret = viacam_do_try_fmt(cam, &fmt->fmt.pix, &sfmt.fmt.pix);
+	if (ret)
+		goto out;
+	/*
+	 * OK, let's commit to the new format.
+	 */
+	cam->user_format = fmt->fmt.pix;
+	cam->sensor_format = sfmt.fmt.pix;
+	cam->mbus_code = f->mbus_code;
+	ret = viacam_configure_sensor(cam);
+	if (!ret)
+		ret = viacam_config_controller(cam);
+out:
+	mutex_unlock(&cam->lock);
+	return ret;
+}
+
+static int viacam_querycap(struct file *filp, void *priv,
+		struct v4l2_capability *cap)
+{
+	strcpy(cap->driver, "via-camera");
+	strcpy(cap->card, "via-camera");
+	cap->version = 1;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+	return 0;
+}
+
+/*
+ * Streaming operations - pure videobuf stuff.
+ */
+static int viacam_reqbufs(struct file *filp, void *priv,
+		struct v4l2_requestbuffers *rb)
+{
+	struct via_camera *cam = priv;
+
+	return videobuf_reqbufs(&cam->vb_queue, rb);
+}
+
+static int viacam_querybuf(struct file *filp, void *priv,
+		struct v4l2_buffer *buf)
+{
+	struct via_camera *cam = priv;
+
+	return videobuf_querybuf(&cam->vb_queue, buf);
+}
+
+static int viacam_qbuf(struct file *filp, void *priv, struct v4l2_buffer *buf)
+{
+	struct via_camera *cam = priv;
+
+	return videobuf_qbuf(&cam->vb_queue, buf);
+}
+
+static int viacam_dqbuf(struct file *filp, void *priv, struct v4l2_buffer *buf)
+{
+	struct via_camera *cam = priv;
+
+	return videobuf_dqbuf(&cam->vb_queue, buf, filp->f_flags & O_NONBLOCK);
+}
+
+static int viacam_streamon(struct file *filp, void *priv, enum v4l2_buf_type t)
+{
+	struct via_camera *cam = priv;
+	int ret = 0;
+
+	if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	mutex_lock(&cam->lock);
+	if (cam->opstate != S_IDLE) {
+		ret = -EBUSY;
+		goto out;
+	}
+	/*
+	 * Enforce the V4l2 "only one owner gets to read data" rule.
+	 */
+	if (cam->owner && cam->owner != filp) {
+		ret = -EBUSY;
+		goto out;
+	}
+	cam->owner = filp;
+	/*
+	 * Configure things if need be.
+	 */
+	if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) {
+		ret = viacam_configure_sensor(cam);
+		if (ret)
+			goto out;
+		ret = viacam_config_controller(cam);
+		if (ret)
+			goto out;
+	}
+	/*
+	 * If the CPU goes into C3, the DMA transfer gets corrupted and
+	 * users start filing unsightly bug reports.  Put in a "latency"
+	 * requirement which will keep the CPU out of the deeper sleep
+	 * states.
+	 */
+	pm_qos_add_request(&cam->qos_request, PM_QOS_CPU_DMA_LATENCY, 50);
+	/*
+	 * Fire things up.
+	 */
+	INIT_LIST_HEAD(&cam->buffer_queue);
+	ret = videobuf_streamon(&cam->vb_queue);
+	if (!ret)
+		viacam_start_engine(cam);
+out:
+	mutex_unlock(&cam->lock);
+	return ret;
+}
+
+static int viacam_streamoff(struct file *filp, void *priv, enum v4l2_buf_type t)
+{
+	struct via_camera *cam = priv;
+	int ret;
+
+	if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	mutex_lock(&cam->lock);
+	if (cam->opstate != S_RUNNING) {
+		ret = -EINVAL;
+		goto out;
+	}
+	pm_qos_remove_request(&cam->qos_request);
+	viacam_stop_engine(cam);
+	/*
+	 * Videobuf will recycle all of the outstanding buffers, but
+	 * we should be sure we don't retain any references to
+	 * any of them.
+	 */
+	ret = videobuf_streamoff(&cam->vb_queue);
+	INIT_LIST_HEAD(&cam->buffer_queue);
+out:
+	mutex_unlock(&cam->lock);
+	return ret;
+}
+
+/* G/S_PARM */
+
+static int viacam_g_parm(struct file *filp, void *priv,
+		struct v4l2_streamparm *parm)
+{
+	struct via_camera *cam = priv;
+	int ret;
+
+	mutex_lock(&cam->lock);
+	ret = sensor_call(cam, video, g_parm, parm);
+	mutex_unlock(&cam->lock);
+	parm->parm.capture.readbuffers = cam->n_cap_bufs;
+	return ret;
+}
+
+static int viacam_s_parm(struct file *filp, void *priv,
+		struct v4l2_streamparm *parm)
+{
+	struct via_camera *cam = priv;
+	int ret;
+
+	mutex_lock(&cam->lock);
+	ret = sensor_call(cam, video, s_parm, parm);
+	mutex_unlock(&cam->lock);
+	parm->parm.capture.readbuffers = cam->n_cap_bufs;
+	return ret;
+}
+
+static int viacam_enum_framesizes(struct file *filp, void *priv,
+		struct v4l2_frmsizeenum *sizes)
+{
+	if (sizes->index != 0)
+		return -EINVAL;
+	sizes->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+	sizes->stepwise.min_width = QCIF_WIDTH;
+	sizes->stepwise.min_height = QCIF_HEIGHT;
+	sizes->stepwise.max_width = VGA_WIDTH;
+	sizes->stepwise.max_height = VGA_HEIGHT;
+	sizes->stepwise.step_width = sizes->stepwise.step_height = 1;
+	return 0;
+}
+
+static int viacam_enum_frameintervals(struct file *filp, void *priv,
+		struct v4l2_frmivalenum *interval)
+{
+	struct via_camera *cam = priv;
+	int ret;
+
+	mutex_lock(&cam->lock);
+	ret = sensor_call(cam, video, enum_frameintervals, interval);
+	mutex_unlock(&cam->lock);
+	return ret;
+}
+
+
+
+static const struct v4l2_ioctl_ops viacam_ioctl_ops = {
+	.vidioc_g_chip_ident	= viacam_g_chip_ident,
+	.vidioc_queryctrl	= viacam_queryctrl,
+	.vidioc_g_ctrl		= viacam_g_ctrl,
+	.vidioc_s_ctrl		= viacam_s_ctrl,
+	.vidioc_enum_input	= viacam_enum_input,
+	.vidioc_g_input		= viacam_g_input,
+	.vidioc_s_input		= viacam_s_input,
+	.vidioc_s_std		= viacam_s_std,
+	.vidioc_enum_fmt_vid_cap = viacam_enum_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap = viacam_try_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	= viacam_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= viacam_s_fmt_vid_cap,
+	.vidioc_querycap	= viacam_querycap,
+	.vidioc_reqbufs		= viacam_reqbufs,
+	.vidioc_querybuf	= viacam_querybuf,
+	.vidioc_qbuf		= viacam_qbuf,
+	.vidioc_dqbuf		= viacam_dqbuf,
+	.vidioc_streamon	= viacam_streamon,
+	.vidioc_streamoff	= viacam_streamoff,
+	.vidioc_g_parm		= viacam_g_parm,
+	.vidioc_s_parm		= viacam_s_parm,
+	.vidioc_enum_framesizes = viacam_enum_framesizes,
+	.vidioc_enum_frameintervals = viacam_enum_frameintervals,
+};
+
+/*----------------------------------------------------------------------------*/
+
+/*
+ * Power management.
+ */
+#ifdef CONFIG_PM
+
+static int viacam_suspend(void *priv)
+{
+	struct via_camera *cam = priv;
+	enum viacam_opstate state = cam->opstate;
+
+	if (cam->opstate != S_IDLE) {
+		viacam_stop_engine(cam);
+		cam->opstate = state; /* So resume restarts */
+	}
+
+	return 0;
+}
+
+static int viacam_resume(void *priv)
+{
+	struct via_camera *cam = priv;
+	int ret = 0;
+
+	/*
+	 * Get back to a reasonable operating state.
+	 */
+	via_write_reg_mask(VIASR, 0x78, 0, 0x80);
+	via_write_reg_mask(VIASR, 0x1e, 0xc0, 0xc0);
+	viacam_int_disable(cam);
+	set_bit(CF_CONFIG_NEEDED, &cam->flags);
+	/*
+	 * Make sure the sensor's power state is correct
+	 */
+	if (cam->users > 0)
+		via_sensor_power_up(cam);
+	else
+		via_sensor_power_down(cam);
+	/*
+	 * If it was operating, try to restart it.
+	 */
+	if (cam->opstate != S_IDLE) {
+		mutex_lock(&cam->lock);
+		ret = viacam_configure_sensor(cam);
+		if (!ret)
+			ret = viacam_config_controller(cam);
+		mutex_unlock(&cam->lock);
+		if (!ret)
+			viacam_start_engine(cam);
+	}
+
+	return ret;
+}
+
+static struct viafb_pm_hooks viacam_pm_hooks = {
+	.suspend = viacam_suspend,
+	.resume = viacam_resume
+};
+
+#endif /* CONFIG_PM */
+
+/*
+ * Setup stuff.
+ */
+
+static struct video_device viacam_v4l_template = {
+	.name		= "via-camera",
+	.minor		= -1,
+	.tvnorms	= V4L2_STD_NTSC_M,
+	.current_norm	= V4L2_STD_NTSC_M,
+	.fops		= &viacam_fops,
+	.ioctl_ops	= &viacam_ioctl_ops,
+	.release	= video_device_release_empty, /* Check this */
+};
+
+/*
+ * The OLPC folks put the serial port on the same pin as
+ * the camera.	They also get grumpy if we break the
+ * serial port and keep them from using it.  So we have
+ * to check the serial enable bit and not step on it.
+ */
+#define VIACAM_SERIAL_DEVFN 0x88
+#define VIACAM_SERIAL_CREG 0x46
+#define VIACAM_SERIAL_BIT 0x40
+
+static __devinit bool viacam_serial_is_enabled(void)
+{
+	struct pci_bus *pbus = pci_find_bus(0, 0);
+	u8 cbyte;
+
+	if (!pbus)
+		return false;
+	pci_bus_read_config_byte(pbus, VIACAM_SERIAL_DEVFN,
+			VIACAM_SERIAL_CREG, &cbyte);
+	if ((cbyte & VIACAM_SERIAL_BIT) == 0)
+		return false; /* Not enabled */
+	if (override_serial == 0) {
+		printk(KERN_NOTICE "Via camera: serial port is enabled, " \
+				"refusing to load.\n");
+		printk(KERN_NOTICE "Specify override_serial=1 to force " \
+				"module loading.\n");
+		return true;
+	}
+	printk(KERN_NOTICE "Via camera: overriding serial port\n");
+	pci_bus_write_config_byte(pbus, VIACAM_SERIAL_DEVFN,
+			VIACAM_SERIAL_CREG, cbyte & ~VIACAM_SERIAL_BIT);
+	return false;
+}
+
+static struct ov7670_config sensor_cfg = {
+	/* The XO-1.5 (only known user) clocks the camera at 90MHz. */
+	.clock_speed = 90,
+};
+
+static __devinit int viacam_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct i2c_adapter *sensor_adapter;
+	struct viafb_dev *viadev = pdev->dev.platform_data;
+	struct i2c_board_info ov7670_info = {
+		.type = "ov7670",
+		.addr = 0x42 >> 1,
+		.platform_data = &sensor_cfg,
+	};
+
+	/*
+	 * Note that there are actually two capture channels on
+	 * the device.	We only deal with one for now.	That
+	 * is encoded here; nothing else assumes it's dealing with
+	 * a unique capture device.
+	 */
+	struct via_camera *cam;
+
+	/*
+	 * Ensure that frame buffer memory has been set aside for
+	 * this purpose.  As an arbitrary limit, refuse to work
+	 * with less than two frames of VGA 16-bit data.
+	 *
+	 * If we ever support the second port, we'll need to set
+	 * aside more memory.
+	 */
+	if (viadev->camera_fbmem_size < (VGA_HEIGHT*VGA_WIDTH*4)) {
+		printk(KERN_ERR "viacam: insufficient FB memory reserved\n");
+		return -ENOMEM;
+	}
+	if (viadev->engine_mmio == NULL) {
+		printk(KERN_ERR "viacam: No I/O memory, so no pictures\n");
+		return -ENOMEM;
+	}
+
+	if (machine_is_olpc() && viacam_serial_is_enabled())
+		return -EBUSY;
+
+	/*
+	 * Basic structure initialization.
+	 */
+	cam = kzalloc (sizeof(struct via_camera), GFP_KERNEL);
+	if (cam == NULL)
+		return -ENOMEM;
+	via_cam_info = cam;
+	cam->platdev = pdev;
+	cam->viadev = viadev;
+	cam->users = 0;
+	cam->owner = NULL;
+	cam->opstate = S_IDLE;
+	cam->user_format = cam->sensor_format = viacam_def_pix_format;
+	mutex_init(&cam->lock);
+	INIT_LIST_HEAD(&cam->buffer_queue);
+	cam->mmio = viadev->engine_mmio;
+	cam->fbmem = viadev->fbmem;
+	cam->fb_offset = viadev->camera_fbmem_offset;
+	cam->flags = 1 << CF_CONFIG_NEEDED;
+	cam->mbus_code = via_def_mbus_code;
+	/*
+	 * Tell V4L that we exist.
+	 */
+	ret = v4l2_device_register(&pdev->dev, &cam->v4l2_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to register v4l2 device\n");
+		return ret;
+	}
+	/*
+	 * Convince the system that we can do DMA.
+	 */
+	pdev->dev.dma_mask = &viadev->pdev->dma_mask;
+	dma_set_mask(&pdev->dev, 0xffffffff);
+	/*
+	 * Fire up the capture port.  The write to 0x78 looks purely
+	 * OLPCish; any system will need to tweak 0x1e.
+	 */
+	via_write_reg_mask(VIASR, 0x78, 0, 0x80);
+	via_write_reg_mask(VIASR, 0x1e, 0xc0, 0xc0);
+	/*
+	 * Get the sensor powered up.
+	 */
+	ret = via_sensor_power_setup(cam);
+	if (ret)
+		goto out_unregister;
+	via_sensor_power_up(cam);
+
+	/*
+	 * See if we can't find it on the bus.	The VIA_PORT_31 assumption
+	 * is OLPC-specific.  0x42 assumption is ov7670-specific.
+	 */
+	sensor_adapter = viafb_find_i2c_adapter(VIA_PORT_31);
+	cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, sensor_adapter,
+			&ov7670_info, NULL);
+	if (cam->sensor == NULL) {
+		dev_err(&pdev->dev, "Unable to find the sensor!\n");
+		ret = -ENODEV;
+		goto out_power_down;
+	}
+	/*
+	 * Get the IRQ.
+	 */
+	viacam_int_disable(cam);
+	ret = request_threaded_irq(viadev->pdev->irq, viacam_quick_irq,
+			viacam_irq, IRQF_SHARED, "via-camera", cam);
+	if (ret)
+		goto out_power_down;
+	/*
+	 * Tell V4l2 that we exist.
+	 */
+	cam->vdev = viacam_v4l_template;
+	cam->vdev.v4l2_dev = &cam->v4l2_dev;
+	ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
+	if (ret)
+		goto out_irq;
+	video_set_drvdata(&cam->vdev, cam);
+
+#ifdef CONFIG_PM
+	/*
+	 * Hook into PM events
+	 */
+	viacam_pm_hooks.private = cam;
+	viafb_pm_register(&viacam_pm_hooks);
+#endif
+
+	/* Power the sensor down until somebody opens the device */
+	via_sensor_power_down(cam);
+	return 0;
+
+out_irq:
+	free_irq(viadev->pdev->irq, cam);
+out_power_down:
+	via_sensor_power_release(cam);
+out_unregister:
+	v4l2_device_unregister(&cam->v4l2_dev);
+	return ret;
+}
+
+static __devexit int viacam_remove(struct platform_device *pdev)
+{
+	struct via_camera *cam = via_cam_info;
+	struct viafb_dev *viadev = pdev->dev.platform_data;
+
+	video_unregister_device(&cam->vdev);
+	v4l2_device_unregister(&cam->v4l2_dev);
+	free_irq(viadev->pdev->irq, cam);
+	via_sensor_power_release(cam);
+	via_cam_info = NULL;
+	return 0;
+}
+
+static struct platform_driver viacam_driver = {
+	.driver = {
+		.name = "viafb-camera",
+	},
+	.probe = viacam_probe,
+	.remove = viacam_remove,
+};
+
+module_platform_driver(viacam_driver);
diff --git a/drivers/media/platform/via-camera.h b/drivers/media/platform/via-camera.h
new file mode 100644
index 0000000..b12a4b3
--- /dev/null
+++ b/drivers/media/platform/via-camera.h
@@ -0,0 +1,93 @@
+/*
+ * VIA Camera register definitions.
+ */
+#define VCR_INTCTRL	0x300	/* Capture interrupt control */
+#define   VCR_IC_EAV	  0x0001   /* End of active video status */
+#define	  VCR_IC_EVBI	  0x0002   /* End of VBI status */
+#define   VCR_IC_FBOTFLD  0x0004   /* "flipping" Bottom field is active */
+#define   VCR_IC_ACTBUF	  0x0018   /* Active video buffer  */
+#define   VCR_IC_VSYNC	  0x0020   /* 0 = VB, 1 = active video */
+#define   VCR_IC_BOTFLD	  0x0040   /* Bottom field is active */
+#define   VCR_IC_FFULL	  0x0080   /* FIFO full */
+#define   VCR_IC_INTEN	  0x0100   /* End of active video int. enable */
+#define   VCR_IC_VBIINT	  0x0200   /* End of VBI int enable */
+#define   VCR_IC_VBIBUF	  0x0400   /* Current VBI buffer */
+
+#define VCR_TSC		0x308	/* Transport stream control */
+#define VCR_TSC_ENABLE    0x000001   /* Transport stream input enable */
+#define VCR_TSC_DROPERR   0x000002   /* Drop error packets */
+#define VCR_TSC_METHOD    0x00000c   /* DMA method (non-functional) */
+#define VCR_TSC_COUNT     0x07fff0   /* KByte or packet count */
+#define VCR_TSC_CBMODE	  0x080000   /* Change buffer by byte count */
+#define VCR_TSC_PSSIG	  0x100000   /* Packet starting signal disable */
+#define VCR_TSC_BE	  0x200000   /* MSB first (serial mode) */
+#define VCR_TSC_SERIAL	  0x400000   /* Serial input (0 = parallel) */
+
+#define VCR_CAPINTC	0x310	/* Capture interface control */
+#define   VCR_CI_ENABLE   0x00000001  /* Capture enable */
+#define   VCR_CI_BSS	  0x00000002  /* WTF "bit stream selection" */
+#define   VCR_CI_3BUFS	  0x00000004  /* 1 = 3 buffers, 0 = 2 buffers */
+#define   VCR_CI_VIPEN	  0x00000008  /* VIP enable */
+#define   VCR_CI_CCIR601_8  0	        /* CCIR601 input stream, 8 bit */
+#define   VCR_CI_CCIR656_8  0x00000010  /* ... CCIR656, 8 bit */
+#define   VCR_CI_CCIR601_16 0x00000020  /* ... CCIR601, 16 bit */
+#define   VCR_CI_CCIR656_16 0x00000030  /* ... CCIR656, 16 bit */
+#define   VCR_CI_HDMODE   0x00000040  /* CCIR656-16 hdr decode mode; 1=16b */
+#define   VCR_CI_BSWAP    0x00000080  /* Swap bytes (16-bit) */
+#define   VCR_CI_YUYV	  0	      /* Byte order 0123 */
+#define   VCR_CI_UYVY	  0x00000100  /* Byte order 1032 */
+#define   VCR_CI_YVYU	  0x00000200  /* Byte order 0321 */
+#define   VCR_CI_VYUY	  0x00000300  /* Byte order 3012 */
+#define   VCR_CI_VIPTYPE  0x00000400  /* VIP type */
+#define   VCR_CI_IFSEN    0x00000800  /* Input field signal enable */
+#define   VCR_CI_DIODD	  0	      /* De-interlace odd, 30fps */
+#define   VCR_CI_DIEVEN   0x00001000  /*    ...even field, 30fps */
+#define   VCR_CI_DIBOTH   0x00002000  /*    ...both fields, 60fps */
+#define   VCR_CI_DIBOTH30 0x00003000  /*    ...both fields, 30fps interlace */
+#define   VCR_CI_CONVTYPE 0x00004000  /* 4:2:2 to 4:4:4; 1 = interpolate */
+#define   VCR_CI_CFC	  0x00008000  /* Capture flipping control */
+#define   VCR_CI_FILTER   0x00070000  /* Horiz filter mode select
+					 000 = none
+					 001 = 2 tap
+					 010 = 3 tap
+					 011 = 4 tap
+					 100 = 5 tap */
+#define   VCR_CI_CLKINV   0x00080000  /* Input CLK inverted */
+#define   VCR_CI_VREFINV  0x00100000  /* VREF inverted */
+#define   VCR_CI_HREFINV  0x00200000  /* HREF inverted */
+#define   VCR_CI_FLDINV   0x00400000  /* Field inverted */
+#define   VCR_CI_CLKPIN	  0x00800000  /* Capture clock pin */
+#define   VCR_CI_THRESH   0x0f000000  /* Capture fifo threshold */
+#define   VCR_CI_HRLE     0x10000000  /* Positive edge of HREF */
+#define   VCR_CI_VRLE     0x20000000  /* Positive edge of VREF */
+#define   VCR_CI_OFLDINV  0x40000000  /* Field output inverted */
+#define   VCR_CI_CLKEN    0x80000000  /* Capture clock enable */
+
+#define VCR_HORRANGE	0x314	/* Active video horizontal range */
+#define VCR_VERTRANGE	0x318	/* Active video vertical range */
+#define VCR_AVSCALE	0x31c	/* Active video scaling control */
+#define   VCR_AVS_HEN	  0x00000800   /* Horizontal scale enable */
+#define   VCR_AVS_VEN	  0x04000000   /* Vertical enable */
+#define VCR_VBIHOR	0x320	/* VBI Data horizontal range */
+#define VCR_VBIVERT	0x324	/* VBI data vertical range */
+#define VCR_VBIBUF1	0x328	/* First VBI buffer */
+#define VCR_VBISTRIDE	0x32c	/* VBI stride */
+#define VCR_ANCDATACNT	0x330	/* Ancillary data count setting */
+#define VCR_MAXDATA	0x334	/* Active data count of active video */
+#define VCR_MAXVBI	0x338	/* Maximum data count of VBI */
+#define VCR_CAPDATA	0x33c	/* Capture data count */
+#define VCR_VBUF1	0x340	/* First video buffer */
+#define VCR_VBUF2	0x344	/* Second video buffer */
+#define VCR_VBUF3	0x348	/* Third video buffer */
+#define VCR_VBUF_MASK	0x1ffffff0	/* Bits 28:4 */
+#define VCR_VBIBUF2	0x34c	/* Second VBI buffer */
+#define VCR_VSTRIDE	0x350	/* Stride of video + coring control */
+#define   VCR_VS_STRIDE_SHIFT 4
+#define   VCR_VS_STRIDE   0x00001ff0  /* Stride (8-byte units) */
+#define   VCR_VS_CCD	  0x007f0000  /* Coring compare data */
+#define   VCR_VS_COREEN   0x00800000  /* Coring enable */
+#define VCR_TS0ERR	0x354	/* TS buffer 0 error indicator */
+#define VCR_TS1ERR	0x358	/* TS buffer 0 error indicator */
+#define VCR_TS2ERR	0x35c	/* TS buffer 0 error indicator */
+
+/* Add 0x1000 for the second capture engine registers */
diff --git a/drivers/media/platform/vino.c b/drivers/media/platform/vino.c
new file mode 100644
index 0000000..cc9110c
--- /dev/null
+++ b/drivers/media/platform/vino.c
@@ -0,0 +1,4349 @@
+/*
+ * Driver for the VINO (Video In No Out) system found in SGI Indys.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ * Based on the previous version of the driver for 2.4 kernels by:
+ * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ *
+ * v4l2_device/v4l2_subdev conversion by:
+ * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Note: this conversion is untested! Please contact the linux-media
+ * mailinglist if you can test this, together with the test results.
+ */
+
+/*
+ * TODO:
+ * - remove "mark pages reserved-hacks" from memory allocation code
+ *   and implement fault()
+ * - check decimation, calculating and reporting image size when
+ *   using decimation
+ * - implement read(), user mode buffers and overlay (?)
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/time.h>
+#include <linux/kmod.h>
+
+#include <linux/i2c.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/mutex.h>
+
+#include <asm/paccess.h>
+#include <asm/io.h>
+#include <asm/sgi/ip22.h>
+#include <asm/sgi/mc.h>
+
+#include "vino.h"
+#include "saa7191.h"
+#include "indycam.h"
+
+/* Uncomment the following line to get lots and lots of (mostly useless)
+ * debug info.
+ * Note that the debug output also slows down the driver significantly */
+// #define VINO_DEBUG
+// #define VINO_DEBUG_INT
+
+#define VINO_MODULE_VERSION "0.0.7"
+
+MODULE_DESCRIPTION("SGI VINO Video4Linux2 driver");
+MODULE_VERSION(VINO_MODULE_VERSION);
+MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
+MODULE_LICENSE("GPL");
+
+#ifdef VINO_DEBUG
+#define dprintk(x...) printk("VINO: " x);
+#else
+#define dprintk(x...)
+#endif
+
+#define VINO_NO_CHANNEL			0
+#define VINO_CHANNEL_A			1
+#define VINO_CHANNEL_B			2
+
+#define VINO_PAL_WIDTH			768
+#define VINO_PAL_HEIGHT			576
+#define VINO_NTSC_WIDTH			640
+#define VINO_NTSC_HEIGHT		480
+
+#define VINO_MIN_WIDTH			32
+#define VINO_MIN_HEIGHT			32
+
+#define VINO_CLIPPING_START_ODD_D1	1
+#define VINO_CLIPPING_START_ODD_PAL	15
+#define VINO_CLIPPING_START_ODD_NTSC	12
+
+#define VINO_CLIPPING_START_EVEN_D1	2
+#define VINO_CLIPPING_START_EVEN_PAL	15
+#define VINO_CLIPPING_START_EVEN_NTSC	12
+
+#define VINO_INPUT_CHANNEL_COUNT	3
+
+/* the number is the index for vino_inputs */
+#define VINO_INPUT_NONE			-1
+#define VINO_INPUT_COMPOSITE		0
+#define VINO_INPUT_SVIDEO		1
+#define VINO_INPUT_D1			2
+
+#define VINO_PAGE_RATIO			(PAGE_SIZE / VINO_PAGE_SIZE)
+
+#define VINO_FIFO_THRESHOLD_DEFAULT	16
+
+#define VINO_FRAMEBUFFER_SIZE		((VINO_PAL_WIDTH \
+					  * VINO_PAL_HEIGHT * 4 \
+					  + 3 * PAGE_SIZE) & ~(PAGE_SIZE - 1))
+
+#define VINO_FRAMEBUFFER_COUNT_MAX	8
+
+#define VINO_FRAMEBUFFER_UNUSED		0
+#define VINO_FRAMEBUFFER_IN_USE		1
+#define VINO_FRAMEBUFFER_READY		2
+
+#define VINO_QUEUE_ERROR		-1
+#define VINO_QUEUE_MAGIC		0x20050125
+
+#define VINO_MEMORY_NONE		0
+#define VINO_MEMORY_MMAP		1
+#define VINO_MEMORY_USERPTR		2
+
+#define VINO_DUMMY_DESC_COUNT		4
+#define VINO_DESC_FETCH_DELAY		5	/* microseconds */
+
+#define VINO_MAX_FRAME_SKIP_COUNT	128
+
+/* the number is the index for vino_data_formats */
+#define VINO_DATA_FMT_NONE		-1
+#define VINO_DATA_FMT_GREY		0
+#define VINO_DATA_FMT_RGB332		1
+#define VINO_DATA_FMT_RGB32		2
+#define VINO_DATA_FMT_YUV		3
+
+#define VINO_DATA_FMT_COUNT		4
+
+/* the number is the index for vino_data_norms */
+#define VINO_DATA_NORM_NONE		-1
+#define VINO_DATA_NORM_NTSC		0
+#define VINO_DATA_NORM_PAL		1
+#define VINO_DATA_NORM_SECAM		2
+#define VINO_DATA_NORM_D1		3
+
+#define VINO_DATA_NORM_COUNT		4
+
+/* I2C controller flags */
+#define SGI_I2C_FORCE_IDLE		(0 << 0)
+#define SGI_I2C_NOT_IDLE		(1 << 0)
+#define SGI_I2C_WRITE			(0 << 1)
+#define SGI_I2C_READ			(1 << 1)
+#define SGI_I2C_RELEASE_BUS		(0 << 2)
+#define SGI_I2C_HOLD_BUS		(1 << 2)
+#define SGI_I2C_XFER_DONE		(0 << 4)
+#define SGI_I2C_XFER_BUSY		(1 << 4)
+#define SGI_I2C_ACK			(0 << 5)
+#define SGI_I2C_NACK			(1 << 5)
+#define SGI_I2C_BUS_OK			(0 << 7)
+#define SGI_I2C_BUS_ERR			(1 << 7)
+
+/* Internal data structure definitions */
+
+struct vino_input {
+	char *name;
+	v4l2_std_id std;
+};
+
+struct vino_clipping {
+	unsigned int left, right, top, bottom;
+};
+
+struct vino_data_format {
+	/* the description */
+	char *description;
+	/* bytes per pixel */
+	unsigned int bpp;
+	/* V4L2 fourcc code */
+	__u32 pixelformat;
+	/* V4L2 colorspace (duh!) */
+	enum v4l2_colorspace colorspace;
+};
+
+struct vino_data_norm {
+	char *description;
+	unsigned int width, height;
+	struct vino_clipping odd;
+	struct vino_clipping even;
+
+	v4l2_std_id std;
+	unsigned int fps_min, fps_max;
+	__u32 framelines;
+};
+
+struct vino_descriptor_table {
+	/* the number of PAGE_SIZE sized pages in the buffer */
+	unsigned int page_count;
+	/* virtual (kmalloc'd) pointers to the actual data
+	 * (in PAGE_SIZE chunks, used with mmap streaming) */
+	unsigned long *virtual;
+
+	/* cpu address for the VINO descriptor table
+	 * (contains DMA addresses, VINO_PAGE_SIZE chunks) */
+	unsigned long *dma_cpu;
+	/* dma address for the VINO descriptor table
+	 * (contains DMA addresses, VINO_PAGE_SIZE chunks) */
+	dma_addr_t dma;
+};
+
+struct vino_framebuffer {
+	/* identifier nubmer */
+	unsigned int id;
+	/* the length of the whole buffer */
+	unsigned int size;
+	/* the length of actual data in buffer */
+	unsigned int data_size;
+	/* the data format */
+	unsigned int data_format;
+	/* the state of buffer data */
+	unsigned int state;
+	/* is the buffer mapped in user space? */
+	unsigned int map_count;
+	/* memory offset for mmap() */
+	unsigned int offset;
+	/* frame counter */
+	unsigned int frame_counter;
+	/* timestamp (written when image capture finishes) */
+	struct timeval timestamp;
+
+	struct vino_descriptor_table desc_table;
+
+	spinlock_t state_lock;
+};
+
+struct vino_framebuffer_fifo {
+	unsigned int length;
+
+	unsigned int used;
+	unsigned int head;
+	unsigned int tail;
+
+	unsigned int data[VINO_FRAMEBUFFER_COUNT_MAX];
+};
+
+struct vino_framebuffer_queue {
+	unsigned int magic;
+
+	/* VINO_MEMORY_NONE, VINO_MEMORY_MMAP or VINO_MEMORY_USERPTR */
+	unsigned int type;
+	unsigned int length;
+
+	/* data field of in and out contain index numbers for buffer */
+	struct vino_framebuffer_fifo in;
+	struct vino_framebuffer_fifo out;
+
+	struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_COUNT_MAX];
+
+	spinlock_t queue_lock;
+	struct mutex queue_mutex;
+	wait_queue_head_t frame_wait_queue;
+};
+
+struct vino_interrupt_data {
+	struct timeval timestamp;
+	unsigned int frame_counter;
+	unsigned int skip_count;
+	unsigned int skip;
+};
+
+struct vino_channel_settings {
+	unsigned int channel;
+
+	int input;
+	unsigned int data_format;
+	unsigned int data_norm;
+	struct vino_clipping clipping;
+	unsigned int decimation;
+	unsigned int line_size;
+	unsigned int alpha;
+	unsigned int fps;
+	unsigned int framert_reg;
+
+	unsigned int fifo_threshold;
+
+	struct vino_framebuffer_queue fb_queue;
+
+	/* number of the current field */
+	unsigned int field;
+
+	/* read in progress */
+	int reading;
+	/* streaming is active */
+	int streaming;
+	/* the driver is currently processing the queue */
+	int capturing;
+
+	struct mutex mutex;
+	spinlock_t capture_lock;
+
+	unsigned int users;
+
+	struct vino_interrupt_data int_data;
+
+	/* V4L support */
+	struct video_device *vdev;
+};
+
+struct vino_settings {
+	struct v4l2_device v4l2_dev;
+	struct vino_channel_settings a;
+	struct vino_channel_settings b;
+
+	/* the channel which owns this client:
+	 * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */
+	unsigned int decoder_owner;
+	struct v4l2_subdev *decoder;
+	unsigned int camera_owner;
+	struct v4l2_subdev *camera;
+
+	/* a lock for vino register access */
+	spinlock_t vino_lock;
+	/* a lock for channel input changes */
+	spinlock_t input_lock;
+
+	unsigned long dummy_page;
+	struct vino_descriptor_table dummy_desc_table;
+};
+
+/* Module parameters */
+
+/*
+ * Using vino_pixel_conversion the ABGR32-format pixels supplied
+ * by the VINO chip can be converted to more common formats
+ * like RGBA32 (or probably RGB24 in the future). This way we
+ * can give out data that can be specified correctly with
+ * the V4L2-definitions.
+ *
+ * The pixel format is specified as RGBA32 when no conversion
+ * is used.
+ *
+ * Note that this only affects the 32-bit bit depth.
+ *
+ * Use non-zero value to enable conversion.
+ */
+static int vino_pixel_conversion;
+
+module_param_named(pixelconv, vino_pixel_conversion, int, 0);
+
+MODULE_PARM_DESC(pixelconv,
+		 "enable pixel conversion (non-zero value enables)");
+
+/* Internal data structures */
+
+static struct sgi_vino *vino;
+
+static struct vino_settings *vino_drvdata;
+
+#define camera_call(o, f, args...) \
+	v4l2_subdev_call(vino_drvdata->camera, o, f, ##args)
+#define decoder_call(o, f, args...) \
+	v4l2_subdev_call(vino_drvdata->decoder, o, f, ##args)
+
+static const char *vino_driver_name = "vino";
+static const char *vino_driver_description = "SGI VINO";
+static const char *vino_bus_name = "GIO64 bus";
+static const char *vino_vdev_name_a = "SGI VINO Channel A";
+static const char *vino_vdev_name_b = "SGI VINO Channel B";
+
+static void vino_capture_tasklet(unsigned long channel);
+
+DECLARE_TASKLET(vino_tasklet_a, vino_capture_tasklet, VINO_CHANNEL_A);
+DECLARE_TASKLET(vino_tasklet_b, vino_capture_tasklet, VINO_CHANNEL_B);
+
+static const struct vino_input vino_inputs[] = {
+	{
+		.name		= "Composite",
+		.std		= V4L2_STD_NTSC | V4L2_STD_PAL
+		| V4L2_STD_SECAM,
+	}, {
+		.name		= "S-Video",
+		.std		= V4L2_STD_NTSC | V4L2_STD_PAL
+		| V4L2_STD_SECAM,
+	}, {
+		.name		= "D1/IndyCam",
+		.std		= V4L2_STD_NTSC,
+	}
+};
+
+static const struct vino_data_format vino_data_formats[] = {
+	{
+		.description	= "8-bit greyscale",
+		.bpp		= 1,
+		.pixelformat	= V4L2_PIX_FMT_GREY,
+		.colorspace	= V4L2_COLORSPACE_SMPTE170M,
+	}, {
+		.description	= "8-bit dithered RGB 3-3-2",
+		.bpp		= 1,
+		.pixelformat	= V4L2_PIX_FMT_RGB332,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
+	}, {
+		.description	= "32-bit RGB",
+		.bpp		= 4,
+		.pixelformat	= V4L2_PIX_FMT_RGB32,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
+	}, {
+		.description	= "YUV 4:2:2",
+		.bpp		= 2,
+		.pixelformat	= V4L2_PIX_FMT_YUYV, // XXX: swapped?
+		.colorspace	= V4L2_COLORSPACE_SMPTE170M,
+	}
+};
+
+static const struct vino_data_norm vino_data_norms[] = {
+	{
+		.description	= "NTSC",
+		.std		= V4L2_STD_NTSC,
+		.fps_min	= 6,
+		.fps_max	= 30,
+		.framelines	= 525,
+		.width		= VINO_NTSC_WIDTH,
+		.height		= VINO_NTSC_HEIGHT,
+		.odd		= {
+			.top	= VINO_CLIPPING_START_ODD_NTSC,
+			.left	= 0,
+			.bottom	= VINO_CLIPPING_START_ODD_NTSC
+			+ VINO_NTSC_HEIGHT / 2 - 1,
+			.right	= VINO_NTSC_WIDTH,
+		},
+		.even		= {
+			.top	= VINO_CLIPPING_START_EVEN_NTSC,
+			.left	= 0,
+			.bottom	= VINO_CLIPPING_START_EVEN_NTSC
+			+ VINO_NTSC_HEIGHT / 2 - 1,
+			.right	= VINO_NTSC_WIDTH,
+		},
+	}, {
+		.description	= "PAL",
+		.std		= V4L2_STD_PAL,
+		.fps_min	= 5,
+		.fps_max	= 25,
+		.framelines	= 625,
+		.width		= VINO_PAL_WIDTH,
+		.height		= VINO_PAL_HEIGHT,
+		.odd		= {
+			.top	= VINO_CLIPPING_START_ODD_PAL,
+			.left	= 0,
+			.bottom	= VINO_CLIPPING_START_ODD_PAL
+			+ VINO_PAL_HEIGHT / 2 - 1,
+			.right	= VINO_PAL_WIDTH,
+		},
+		.even		= {
+			.top	= VINO_CLIPPING_START_EVEN_PAL,
+			.left	= 0,
+			.bottom	= VINO_CLIPPING_START_EVEN_PAL
+			+ VINO_PAL_HEIGHT / 2 - 1,
+			.right	= VINO_PAL_WIDTH,
+		},
+	}, {
+		.description	= "SECAM",
+		.std		= V4L2_STD_SECAM,
+		.fps_min	= 5,
+		.fps_max	= 25,
+		.framelines	= 625,
+		.width		= VINO_PAL_WIDTH,
+		.height		= VINO_PAL_HEIGHT,
+		.odd		= {
+			.top	= VINO_CLIPPING_START_ODD_PAL,
+			.left	= 0,
+			.bottom	= VINO_CLIPPING_START_ODD_PAL
+			+ VINO_PAL_HEIGHT / 2 - 1,
+			.right	= VINO_PAL_WIDTH,
+		},
+		.even		= {
+			.top	= VINO_CLIPPING_START_EVEN_PAL,
+			.left	= 0,
+			.bottom	= VINO_CLIPPING_START_EVEN_PAL
+			+ VINO_PAL_HEIGHT / 2 - 1,
+			.right	= VINO_PAL_WIDTH,
+		},
+	}, {
+		.description	= "NTSC/D1",
+		.std		= V4L2_STD_NTSC,
+		.fps_min	= 6,
+		.fps_max	= 30,
+		.framelines	= 525,
+		.width		= VINO_NTSC_WIDTH,
+		.height		= VINO_NTSC_HEIGHT,
+		.odd		= {
+			.top	= VINO_CLIPPING_START_ODD_D1,
+			.left	= 0,
+			.bottom	= VINO_CLIPPING_START_ODD_D1
+			+ VINO_NTSC_HEIGHT / 2 - 1,
+			.right	= VINO_NTSC_WIDTH,
+		},
+		.even		= {
+			.top	= VINO_CLIPPING_START_EVEN_D1,
+			.left	= 0,
+			.bottom	= VINO_CLIPPING_START_EVEN_D1
+			+ VINO_NTSC_HEIGHT / 2 - 1,
+			.right	= VINO_NTSC_WIDTH,
+		},
+	}
+};
+
+#define VINO_INDYCAM_V4L2_CONTROL_COUNT		9
+
+struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
+	{
+		.id = V4L2_CID_AUTOGAIN,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "Automatic Gain Control",
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = INDYCAM_AGC_DEFAULT,
+	}, {
+		.id = V4L2_CID_AUTO_WHITE_BALANCE,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "Automatic White Balance",
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = INDYCAM_AWB_DEFAULT,
+	}, {
+		.id = V4L2_CID_GAIN,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Gain",
+		.minimum = INDYCAM_GAIN_MIN,
+		.maximum = INDYCAM_GAIN_MAX,
+		.step = 1,
+		.default_value = INDYCAM_GAIN_DEFAULT,
+	}, {
+		.id = INDYCAM_CONTROL_RED_SATURATION,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Red Saturation",
+		.minimum = INDYCAM_RED_SATURATION_MIN,
+		.maximum = INDYCAM_RED_SATURATION_MAX,
+		.step = 1,
+		.default_value = INDYCAM_RED_SATURATION_DEFAULT,
+	}, {
+		.id = INDYCAM_CONTROL_BLUE_SATURATION,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Blue Saturation",
+		.minimum = INDYCAM_BLUE_SATURATION_MIN,
+		.maximum = INDYCAM_BLUE_SATURATION_MAX,
+		.step = 1,
+		.default_value = INDYCAM_BLUE_SATURATION_DEFAULT,
+	}, {
+		.id = V4L2_CID_RED_BALANCE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Red Balance",
+		.minimum = INDYCAM_RED_BALANCE_MIN,
+		.maximum = INDYCAM_RED_BALANCE_MAX,
+		.step = 1,
+		.default_value = INDYCAM_RED_BALANCE_DEFAULT,
+	}, {
+		.id = V4L2_CID_BLUE_BALANCE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Blue Balance",
+		.minimum = INDYCAM_BLUE_BALANCE_MIN,
+		.maximum = INDYCAM_BLUE_BALANCE_MAX,
+		.step = 1,
+		.default_value = INDYCAM_BLUE_BALANCE_DEFAULT,
+	}, {
+		.id = V4L2_CID_EXPOSURE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Shutter Control",
+		.minimum = INDYCAM_SHUTTER_MIN,
+		.maximum = INDYCAM_SHUTTER_MAX,
+		.step = 1,
+		.default_value = INDYCAM_SHUTTER_DEFAULT,
+	}, {
+		.id = V4L2_CID_GAMMA,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Gamma",
+		.minimum = INDYCAM_GAMMA_MIN,
+		.maximum = INDYCAM_GAMMA_MAX,
+		.step = 1,
+		.default_value = INDYCAM_GAMMA_DEFAULT,
+	}
+};
+
+#define VINO_SAA7191_V4L2_CONTROL_COUNT		9
+
+struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = {
+	{
+		.id = V4L2_CID_HUE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Hue",
+		.minimum = SAA7191_HUE_MIN,
+		.maximum = SAA7191_HUE_MAX,
+		.step = 1,
+		.default_value = SAA7191_HUE_DEFAULT,
+	}, {
+		.id = SAA7191_CONTROL_BANDPASS,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Luminance Bandpass",
+		.minimum = SAA7191_BANDPASS_MIN,
+		.maximum = SAA7191_BANDPASS_MAX,
+		.step = 1,
+		.default_value = SAA7191_BANDPASS_DEFAULT,
+	}, {
+		.id = SAA7191_CONTROL_BANDPASS_WEIGHT,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Luminance Bandpass Weight",
+		.minimum = SAA7191_BANDPASS_WEIGHT_MIN,
+		.maximum = SAA7191_BANDPASS_WEIGHT_MAX,
+		.step = 1,
+		.default_value = SAA7191_BANDPASS_WEIGHT_DEFAULT,
+	}, {
+		.id = SAA7191_CONTROL_CORING,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "HF Luminance Coring",
+		.minimum = SAA7191_CORING_MIN,
+		.maximum = SAA7191_CORING_MAX,
+		.step = 1,
+		.default_value = SAA7191_CORING_DEFAULT,
+	}, {
+		.id = SAA7191_CONTROL_FORCE_COLOUR,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "Force Colour",
+		.minimum = SAA7191_FORCE_COLOUR_MIN,
+		.maximum = SAA7191_FORCE_COLOUR_MAX,
+		.step = 1,
+		.default_value = SAA7191_FORCE_COLOUR_DEFAULT,
+	}, {
+		.id = SAA7191_CONTROL_CHROMA_GAIN,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Chrominance Gain Control",
+		.minimum = SAA7191_CHROMA_GAIN_MIN,
+		.maximum = SAA7191_CHROMA_GAIN_MAX,
+		.step = 1,
+		.default_value = SAA7191_CHROMA_GAIN_DEFAULT,
+	}, {
+		.id = SAA7191_CONTROL_VTRC,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "VTR Time Constant",
+		.minimum = SAA7191_VTRC_MIN,
+		.maximum = SAA7191_VTRC_MAX,
+		.step = 1,
+		.default_value = SAA7191_VTRC_DEFAULT,
+	}, {
+		.id = SAA7191_CONTROL_LUMA_DELAY,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Luminance Delay Compensation",
+		.minimum = SAA7191_LUMA_DELAY_MIN,
+		.maximum = SAA7191_LUMA_DELAY_MAX,
+		.step = 1,
+		.default_value = SAA7191_LUMA_DELAY_DEFAULT,
+	}, {
+		.id = SAA7191_CONTROL_VNR,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Vertical Noise Reduction",
+		.minimum = SAA7191_VNR_MIN,
+		.maximum = SAA7191_VNR_MAX,
+		.step = 1,
+		.default_value = SAA7191_VNR_DEFAULT,
+	}
+};
+
+/* VINO framebuffer/DMA descriptor management */
+
+static void vino_free_buffer_with_count(struct vino_framebuffer *fb,
+					       unsigned int count)
+{
+	unsigned int i;
+
+	dprintk("vino_free_buffer_with_count(): count = %d\n", count);
+
+	for (i = 0; i < count; i++) {
+		ClearPageReserved(virt_to_page((void *)fb->desc_table.virtual[i]));
+		dma_unmap_single(NULL,
+				 fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
+				 PAGE_SIZE, DMA_FROM_DEVICE);
+		free_page(fb->desc_table.virtual[i]);
+	}
+
+	dma_free_coherent(NULL,
+			  VINO_PAGE_RATIO * (fb->desc_table.page_count + 4) *
+			  sizeof(dma_addr_t), (void *)fb->desc_table.dma_cpu,
+			  fb->desc_table.dma);
+	kfree(fb->desc_table.virtual);
+
+	memset(fb, 0, sizeof(struct vino_framebuffer));
+}
+
+static void vino_free_buffer(struct vino_framebuffer *fb)
+{
+	vino_free_buffer_with_count(fb, fb->desc_table.page_count);
+}
+
+static int vino_allocate_buffer(struct vino_framebuffer *fb,
+				unsigned int size)
+{
+	unsigned int count, i, j;
+	int ret = 0;
+
+	dprintk("vino_allocate_buffer():\n");
+
+	if (size < 1)
+		return -EINVAL;
+
+	memset(fb, 0, sizeof(struct vino_framebuffer));
+
+	count = ((size / PAGE_SIZE) + 4) & ~3;
+
+	dprintk("vino_allocate_buffer(): size = %d, count = %d\n",
+		size, count);
+
+	/* allocate memory for table with virtual (page) addresses */
+	fb->desc_table.virtual =
+		kmalloc(count * sizeof(unsigned long), GFP_KERNEL);
+	if (!fb->desc_table.virtual)
+		return -ENOMEM;
+
+	/* allocate memory for table with dma addresses
+	 * (has space for four extra descriptors) */
+	fb->desc_table.dma_cpu =
+		dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) *
+				   sizeof(dma_addr_t), &fb->desc_table.dma,
+				   GFP_KERNEL | GFP_DMA);
+	if (!fb->desc_table.dma_cpu) {
+		ret = -ENOMEM;
+		goto out_free_virtual;
+	}
+
+	/* allocate pages for the buffer and acquire the according
+	 * dma addresses */
+	for (i = 0; i < count; i++) {
+		dma_addr_t dma_data_addr;
+
+		fb->desc_table.virtual[i] =
+			get_zeroed_page(GFP_KERNEL | GFP_DMA);
+		if (!fb->desc_table.virtual[i]) {
+			ret = -ENOBUFS;
+			break;
+		}
+
+		dma_data_addr =
+			dma_map_single(NULL,
+				       (void *)fb->desc_table.virtual[i],
+				       PAGE_SIZE, DMA_FROM_DEVICE);
+
+		for (j = 0; j < VINO_PAGE_RATIO; j++) {
+			fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] =
+				dma_data_addr + VINO_PAGE_SIZE * j;
+		}
+
+		SetPageReserved(virt_to_page((void *)fb->desc_table.virtual[i]));
+	}
+
+	/* page_count needs to be set anyway, because the descriptor table has
+	 * been allocated according to this number */
+	fb->desc_table.page_count = count;
+
+	if (ret) {
+		/* the descriptor with index i doesn't contain
+		 * a valid address yet */
+		vino_free_buffer_with_count(fb, i);
+		return ret;
+	}
+
+	//fb->size = size;
+	fb->size = count * PAGE_SIZE;
+	fb->data_format = VINO_DATA_FMT_NONE;
+
+	/* set the dma stop-bit for the last (count+1)th descriptor */
+	fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP;
+	return 0;
+
+ out_free_virtual:
+	kfree(fb->desc_table.virtual);
+	return ret;
+}
+
+#if 0
+/* user buffers not fully implemented yet */
+static int vino_prepare_user_buffer(struct vino_framebuffer *fb,
+				     void *user,
+				     unsigned int size)
+{
+	unsigned int count, i, j;
+	int ret = 0;
+
+	dprintk("vino_prepare_user_buffer():\n");
+
+	if (size < 1)
+		return -EINVAL;
+
+	memset(fb, 0, sizeof(struct vino_framebuffer));
+
+	count = ((size / PAGE_SIZE)) & ~3;
+
+	dprintk("vino_prepare_user_buffer(): size = %d, count = %d\n",
+		size, count);
+
+	/* allocate memory for table with virtual (page) addresses */
+	fb->desc_table.virtual = (unsigned long *)
+		kmalloc(count * sizeof(unsigned long), GFP_KERNEL);
+	if (!fb->desc_table.virtual)
+		return -ENOMEM;
+
+	/* allocate memory for table with dma addresses
+	 * (has space for four extra descriptors) */
+	fb->desc_table.dma_cpu =
+		dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) *
+				   sizeof(dma_addr_t), &fb->desc_table.dma,
+				   GFP_KERNEL | GFP_DMA);
+	if (!fb->desc_table.dma_cpu) {
+		ret = -ENOMEM;
+		goto out_free_virtual;
+	}
+
+	/* allocate pages for the buffer and acquire the according
+	 * dma addresses */
+	for (i = 0; i < count; i++) {
+		dma_addr_t dma_data_addr;
+
+		fb->desc_table.virtual[i] =
+			get_zeroed_page(GFP_KERNEL | GFP_DMA);
+		if (!fb->desc_table.virtual[i]) {
+			ret = -ENOBUFS;
+			break;
+		}
+
+		dma_data_addr =
+			dma_map_single(NULL,
+				       (void *)fb->desc_table.virtual[i],
+				       PAGE_SIZE, DMA_FROM_DEVICE);
+
+		for (j = 0; j < VINO_PAGE_RATIO; j++) {
+			fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] =
+				dma_data_addr + VINO_PAGE_SIZE * j;
+		}
+
+		SetPageReserved(virt_to_page((void *)fb->desc_table.virtual[i]));
+	}
+
+	/* page_count needs to be set anyway, because the descriptor table has
+	 * been allocated according to this number */
+	fb->desc_table.page_count = count;
+
+	if (ret) {
+		/* the descriptor with index i doesn't contain
+		 * a valid address yet */
+		vino_free_buffer_with_count(fb, i);
+		return ret;
+	}
+
+	//fb->size = size;
+	fb->size = count * PAGE_SIZE;
+
+	/* set the dma stop-bit for the last (count+1)th descriptor */
+	fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP;
+	return 0;
+
+ out_free_virtual:
+	kfree(fb->desc_table.virtual);
+	return ret;
+}
+#endif
+
+static void vino_sync_buffer(struct vino_framebuffer *fb)
+{
+	int i;
+
+	dprintk("vino_sync_buffer():\n");
+
+	for (i = 0; i < fb->desc_table.page_count; i++)
+		dma_sync_single_for_cpu(NULL,
+					fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
+					PAGE_SIZE, DMA_FROM_DEVICE);
+}
+
+/* Framebuffer fifo functions (need to be locked externally) */
+
+static inline void vino_fifo_init(struct vino_framebuffer_fifo *f,
+			   unsigned int length)
+{
+	f->length = 0;
+	f->used = 0;
+	f->head = 0;
+	f->tail = 0;
+
+	if (length > VINO_FRAMEBUFFER_COUNT_MAX)
+		length = VINO_FRAMEBUFFER_COUNT_MAX;
+
+	f->length = length;
+}
+
+/* returns true/false */
+static inline int vino_fifo_has_id(struct vino_framebuffer_fifo *f,
+				   unsigned int id)
+{
+	unsigned int i;
+
+	for (i = f->head; i == (f->tail - 1); i = (i + 1) % f->length) {
+		if (f->data[i] == id)
+			return 1;
+	}
+
+	return 0;
+}
+
+#if 0
+/* returns true/false */
+static inline int vino_fifo_full(struct vino_framebuffer_fifo *f)
+{
+	return (f->used == f->length);
+}
+#endif
+
+static inline unsigned int vino_fifo_get_used(struct vino_framebuffer_fifo *f)
+{
+	return f->used;
+}
+
+static int vino_fifo_enqueue(struct vino_framebuffer_fifo *f, unsigned int id)
+{
+	if (id >= f->length) {
+		return VINO_QUEUE_ERROR;
+	}
+
+	if (vino_fifo_has_id(f, id)) {
+		return VINO_QUEUE_ERROR;
+	}
+
+	if (f->used < f->length) {
+		f->data[f->tail] = id;
+		f->tail = (f->tail + 1) % f->length;
+		f->used++;
+	} else {
+		return VINO_QUEUE_ERROR;
+	}
+
+	return 0;
+}
+
+static int vino_fifo_peek(struct vino_framebuffer_fifo *f, unsigned int *id)
+{
+	if (f->used > 0) {
+		*id = f->data[f->head];
+	} else {
+		return VINO_QUEUE_ERROR;
+	}
+
+	return 0;
+}
+
+static int vino_fifo_dequeue(struct vino_framebuffer_fifo *f, unsigned int *id)
+{
+	if (f->used > 0) {
+		*id = f->data[f->head];
+		f->head = (f->head + 1) % f->length;
+		f->used--;
+	} else {
+		return VINO_QUEUE_ERROR;
+	}
+
+	return 0;
+}
+
+/* Framebuffer queue functions */
+
+/* execute with queue_lock locked */
+static void vino_queue_free_with_count(struct vino_framebuffer_queue *q,
+				       unsigned int length)
+{
+	unsigned int i;
+
+	q->length = 0;
+	memset(&q->in, 0, sizeof(struct vino_framebuffer_fifo));
+	memset(&q->out, 0, sizeof(struct vino_framebuffer_fifo));
+	for (i = 0; i < length; i++) {
+		dprintk("vino_queue_free_with_count(): freeing buffer %d\n",
+			i);
+		vino_free_buffer(q->buffer[i]);
+		kfree(q->buffer[i]);
+	}
+
+	q->type = VINO_MEMORY_NONE;
+	q->magic = 0;
+}
+
+static void vino_queue_free(struct vino_framebuffer_queue *q)
+{
+	dprintk("vino_queue_free():\n");
+
+	if (q->magic != VINO_QUEUE_MAGIC)
+		return;
+	if (q->type != VINO_MEMORY_MMAP)
+		return;
+
+	mutex_lock(&q->queue_mutex);
+
+	vino_queue_free_with_count(q, q->length);
+
+	mutex_unlock(&q->queue_mutex);
+}
+
+static int vino_queue_init(struct vino_framebuffer_queue *q,
+			   unsigned int *length)
+{
+	unsigned int i;
+	int ret = 0;
+
+	dprintk("vino_queue_init(): length = %d\n", *length);
+
+	if (q->magic == VINO_QUEUE_MAGIC) {
+		dprintk("vino_queue_init(): queue already initialized!\n");
+		return -EINVAL;
+	}
+
+	if (q->type != VINO_MEMORY_NONE) {
+		dprintk("vino_queue_init(): queue already initialized!\n");
+		return -EINVAL;
+	}
+
+	if (*length < 1)
+		return -EINVAL;
+
+	mutex_lock(&q->queue_mutex);
+
+	if (*length > VINO_FRAMEBUFFER_COUNT_MAX)
+		*length = VINO_FRAMEBUFFER_COUNT_MAX;
+
+	q->length = 0;
+
+	for (i = 0; i < *length; i++) {
+		dprintk("vino_queue_init(): allocating buffer %d\n", i);
+		q->buffer[i] = kmalloc(sizeof(struct vino_framebuffer),
+				       GFP_KERNEL);
+		if (!q->buffer[i]) {
+			dprintk("vino_queue_init(): kmalloc() failed\n");
+			ret = -ENOMEM;
+			break;
+		}
+
+		ret = vino_allocate_buffer(q->buffer[i],
+					   VINO_FRAMEBUFFER_SIZE);
+		if (ret) {
+			kfree(q->buffer[i]);
+			dprintk("vino_queue_init(): "
+				"vino_allocate_buffer() failed\n");
+			break;
+		}
+
+		q->buffer[i]->id = i;
+		if (i > 0) {
+			q->buffer[i]->offset = q->buffer[i - 1]->offset +
+				q->buffer[i - 1]->size;
+		} else {
+			q->buffer[i]->offset = 0;
+		}
+
+		spin_lock_init(&q->buffer[i]->state_lock);
+
+		dprintk("vino_queue_init(): buffer = %d, offset = %d, "
+			"size = %d\n", i, q->buffer[i]->offset,
+			q->buffer[i]->size);
+	}
+
+	if (ret) {
+		vino_queue_free_with_count(q, i);
+		*length = 0;
+	} else {
+		q->length = *length;
+		vino_fifo_init(&q->in, q->length);
+		vino_fifo_init(&q->out, q->length);
+		q->type = VINO_MEMORY_MMAP;
+		q->magic = VINO_QUEUE_MAGIC;
+	}
+
+	mutex_unlock(&q->queue_mutex);
+
+	return ret;
+}
+
+static struct vino_framebuffer *vino_queue_add(struct
+					       vino_framebuffer_queue *q,
+					       unsigned int id)
+{
+	struct vino_framebuffer *ret = NULL;
+	unsigned int total;
+	unsigned long flags;
+
+	dprintk("vino_queue_add(): id = %d\n", id);
+
+	if (q->magic != VINO_QUEUE_MAGIC) {
+		return ret;
+	}
+
+	spin_lock_irqsave(&q->queue_lock, flags);
+
+	if (q->length == 0)
+		goto out;
+
+	if (id >= q->length)
+		goto out;
+
+	/* not needed?: if (vino_fifo_full(&q->out)) {
+		goto out;
+		}*/
+	/* check that outgoing queue isn't already full
+	 * (or that it won't become full) */
+	total = vino_fifo_get_used(&q->in) +
+		vino_fifo_get_used(&q->out);
+	if (total >= q->length)
+		goto out;
+
+	if (vino_fifo_enqueue(&q->in, id))
+		goto out;
+
+	ret = q->buffer[id];
+
+out:
+	spin_unlock_irqrestore(&q->queue_lock, flags);
+
+	return ret;
+}
+
+static struct vino_framebuffer *vino_queue_transfer(struct
+						    vino_framebuffer_queue *q)
+{
+	struct vino_framebuffer *ret = NULL;
+	struct vino_framebuffer *fb;
+	int id;
+	unsigned long flags;
+
+	dprintk("vino_queue_transfer():\n");
+
+	if (q->magic != VINO_QUEUE_MAGIC) {
+		return ret;
+	}
+
+	spin_lock_irqsave(&q->queue_lock, flags);
+
+	if (q->length == 0)
+		goto out;
+
+	// now this actually removes an entry from the incoming queue
+	if (vino_fifo_dequeue(&q->in, &id)) {
+		goto out;
+	}
+
+	dprintk("vino_queue_transfer(): id = %d\n", id);
+	fb = q->buffer[id];
+
+	// we have already checked that the outgoing queue is not full, but...
+	if (vino_fifo_enqueue(&q->out, id)) {
+		printk(KERN_ERR "vino_queue_transfer(): "
+		       "outgoing queue is full, this shouldn't happen!\n");
+		goto out;
+	}
+
+	ret = fb;
+out:
+	spin_unlock_irqrestore(&q->queue_lock, flags);
+
+	return ret;
+}
+
+/* returns true/false */
+static int vino_queue_incoming_contains(struct vino_framebuffer_queue *q,
+					unsigned int id)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	if (q->magic != VINO_QUEUE_MAGIC) {
+		return ret;
+	}
+
+	spin_lock_irqsave(&q->queue_lock, flags);
+
+	if (q->length == 0)
+		goto out;
+
+	ret = vino_fifo_has_id(&q->in, id);
+
+out:
+	spin_unlock_irqrestore(&q->queue_lock, flags);
+
+	return ret;
+}
+
+/* returns true/false */
+static int vino_queue_outgoing_contains(struct vino_framebuffer_queue *q,
+					unsigned int id)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	if (q->magic != VINO_QUEUE_MAGIC) {
+		return ret;
+	}
+
+	spin_lock_irqsave(&q->queue_lock, flags);
+
+	if (q->length == 0)
+		goto out;
+
+	ret = vino_fifo_has_id(&q->out, id);
+
+out:
+	spin_unlock_irqrestore(&q->queue_lock, flags);
+
+	return ret;
+}
+
+static int vino_queue_get_incoming(struct vino_framebuffer_queue *q,
+				   unsigned int *used)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	if (q->magic != VINO_QUEUE_MAGIC) {
+		return VINO_QUEUE_ERROR;
+	}
+
+	spin_lock_irqsave(&q->queue_lock, flags);
+
+	if (q->length == 0) {
+		ret = VINO_QUEUE_ERROR;
+		goto out;
+	}
+
+	*used = vino_fifo_get_used(&q->in);
+
+out:
+	spin_unlock_irqrestore(&q->queue_lock, flags);
+
+	return ret;
+}
+
+static int vino_queue_get_outgoing(struct vino_framebuffer_queue *q,
+				   unsigned int *used)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	if (q->magic != VINO_QUEUE_MAGIC) {
+		return VINO_QUEUE_ERROR;
+	}
+
+	spin_lock_irqsave(&q->queue_lock, flags);
+
+	if (q->length == 0) {
+		ret = VINO_QUEUE_ERROR;
+		goto out;
+	}
+
+	*used = vino_fifo_get_used(&q->out);
+
+out:
+	spin_unlock_irqrestore(&q->queue_lock, flags);
+
+	return ret;
+}
+
+#if 0
+static int vino_queue_get_total(struct vino_framebuffer_queue *q,
+				unsigned int *total)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	if (q->magic != VINO_QUEUE_MAGIC) {
+		return VINO_QUEUE_ERROR;
+	}
+
+	spin_lock_irqsave(&q->queue_lock, flags);
+
+	if (q->length == 0) {
+		ret = VINO_QUEUE_ERROR;
+		goto out;
+	}
+
+	*total = vino_fifo_get_used(&q->in) +
+		vino_fifo_get_used(&q->out);
+
+out:
+	spin_unlock_irqrestore(&q->queue_lock, flags);
+
+	return ret;
+}
+#endif
+
+static struct vino_framebuffer *vino_queue_peek(struct
+						vino_framebuffer_queue *q,
+						unsigned int *id)
+{
+	struct vino_framebuffer *ret = NULL;
+	unsigned long flags;
+
+	if (q->magic != VINO_QUEUE_MAGIC) {
+		return ret;
+	}
+
+	spin_lock_irqsave(&q->queue_lock, flags);
+
+	if (q->length == 0)
+		goto out;
+
+	if (vino_fifo_peek(&q->in, id)) {
+		goto out;
+	}
+
+	ret = q->buffer[*id];
+out:
+	spin_unlock_irqrestore(&q->queue_lock, flags);
+
+	return ret;
+}
+
+static struct vino_framebuffer *vino_queue_remove(struct
+						  vino_framebuffer_queue *q,
+						  unsigned int *id)
+{
+	struct vino_framebuffer *ret = NULL;
+	unsigned long flags;
+	dprintk("vino_queue_remove():\n");
+
+	if (q->magic != VINO_QUEUE_MAGIC) {
+		return ret;
+	}
+
+	spin_lock_irqsave(&q->queue_lock, flags);
+
+	if (q->length == 0)
+		goto out;
+
+	if (vino_fifo_dequeue(&q->out, id)) {
+		goto out;
+	}
+
+	dprintk("vino_queue_remove(): id = %d\n", *id);
+	ret = q->buffer[*id];
+out:
+	spin_unlock_irqrestore(&q->queue_lock, flags);
+
+	return ret;
+}
+
+static struct
+vino_framebuffer *vino_queue_get_buffer(struct vino_framebuffer_queue *q,
+					unsigned int id)
+{
+	struct vino_framebuffer *ret = NULL;
+	unsigned long flags;
+
+	if (q->magic != VINO_QUEUE_MAGIC) {
+		return ret;
+	}
+
+	spin_lock_irqsave(&q->queue_lock, flags);
+
+	if (q->length == 0)
+		goto out;
+
+	if (id >= q->length)
+		goto out;
+
+	ret = q->buffer[id];
+ out:
+	spin_unlock_irqrestore(&q->queue_lock, flags);
+
+	return ret;
+}
+
+static unsigned int vino_queue_get_length(struct vino_framebuffer_queue *q)
+{
+	unsigned int length = 0;
+	unsigned long flags;
+
+	if (q->magic != VINO_QUEUE_MAGIC) {
+		return length;
+	}
+
+	spin_lock_irqsave(&q->queue_lock, flags);
+	length = q->length;
+	spin_unlock_irqrestore(&q->queue_lock, flags);
+
+	return length;
+}
+
+static int vino_queue_has_mapped_buffers(struct vino_framebuffer_queue *q)
+{
+	unsigned int i;
+	int ret = 0;
+	unsigned long flags;
+
+	if (q->magic != VINO_QUEUE_MAGIC) {
+		return ret;
+	}
+
+	spin_lock_irqsave(&q->queue_lock, flags);
+	for (i = 0; i < q->length; i++) {
+		if (q->buffer[i]->map_count > 0) {
+			ret = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&q->queue_lock, flags);
+
+	return ret;
+}
+
+/* VINO functions */
+
+/* execute with input_lock locked */
+static void vino_update_line_size(struct vino_channel_settings *vcs)
+{
+	unsigned int w = vcs->clipping.right - vcs->clipping.left;
+	unsigned int d = vcs->decimation;
+	unsigned int bpp = vino_data_formats[vcs->data_format].bpp;
+	unsigned int lsize;
+
+	dprintk("update_line_size(): before: w = %d, d = %d, "
+		"line_size = %d\n", w, d, vcs->line_size);
+
+	/* line size must be multiple of 8 bytes */
+	lsize = (bpp * (w / d)) & ~7;
+	w = (lsize / bpp) * d;
+
+	vcs->clipping.right = vcs->clipping.left + w;
+	vcs->line_size = lsize;
+
+	dprintk("update_line_size(): after: w = %d, d = %d, "
+		"line_size = %d\n", w, d, vcs->line_size);
+}
+
+/* execute with input_lock locked */
+static void vino_set_clipping(struct vino_channel_settings *vcs,
+			      unsigned int x, unsigned int y,
+			      unsigned int w, unsigned int h)
+{
+	unsigned int maxwidth, maxheight;
+	unsigned int d;
+
+	maxwidth = vino_data_norms[vcs->data_norm].width;
+	maxheight = vino_data_norms[vcs->data_norm].height;
+	d = vcs->decimation;
+
+	y &= ~1;	/* odd/even fields */
+
+	if (x > maxwidth) {
+		x = 0;
+	}
+	if (y > maxheight) {
+		y = 0;
+	}
+
+	if (((w / d) < VINO_MIN_WIDTH)
+	    || ((h / d) < VINO_MIN_HEIGHT)) {
+		w = VINO_MIN_WIDTH * d;
+		h = VINO_MIN_HEIGHT * d;
+	}
+
+	if ((x + w) > maxwidth) {
+		w = maxwidth - x;
+		if ((w / d) < VINO_MIN_WIDTH)
+			x = maxwidth - VINO_MIN_WIDTH * d;
+	}
+	if ((y + h) > maxheight) {
+		h = maxheight - y;
+		if ((h / d) < VINO_MIN_HEIGHT)
+			y = maxheight - VINO_MIN_HEIGHT * d;
+	}
+
+	vcs->clipping.left = x;
+	vcs->clipping.top = y;
+	vcs->clipping.right = x + w;
+	vcs->clipping.bottom = y + h;
+
+	vino_update_line_size(vcs);
+
+	dprintk("clipping %d, %d, %d, %d / %d - %d\n",
+		vcs->clipping.left, vcs->clipping.top, vcs->clipping.right,
+		vcs->clipping.bottom, vcs->decimation, vcs->line_size);
+}
+
+/* execute with input_lock locked */
+static inline void vino_set_default_clipping(struct vino_channel_settings *vcs)
+{
+	vino_set_clipping(vcs, 0, 0, vino_data_norms[vcs->data_norm].width,
+			  vino_data_norms[vcs->data_norm].height);
+}
+
+/* execute with input_lock locked */
+static void vino_set_scaling(struct vino_channel_settings *vcs,
+			     unsigned int w, unsigned int h)
+{
+	unsigned int x, y, curw, curh, d;
+
+	x = vcs->clipping.left;
+	y = vcs->clipping.top;
+	curw = vcs->clipping.right - vcs->clipping.left;
+	curh = vcs->clipping.bottom - vcs->clipping.top;
+
+	d = max(curw / w, curh / h);
+
+	dprintk("scaling w: %d, h: %d, curw: %d, curh: %d, d: %d\n",
+		w, h, curw, curh, d);
+
+	if (d < 1) {
+		d = 1;
+	} else if (d > 8) {
+		d = 8;
+	}
+
+	vcs->decimation = d;
+	vino_set_clipping(vcs, x, y, w * d, h * d);
+
+	dprintk("scaling %d, %d, %d, %d / %d - %d\n", vcs->clipping.left,
+		vcs->clipping.top, vcs->clipping.right, vcs->clipping.bottom,
+		vcs->decimation, vcs->line_size);
+}
+
+/* execute with input_lock locked */
+static inline void vino_set_default_scaling(struct vino_channel_settings *vcs)
+{
+	vino_set_scaling(vcs, vcs->clipping.right - vcs->clipping.left,
+			 vcs->clipping.bottom - vcs->clipping.top);
+}
+
+/* execute with input_lock locked */
+static void vino_set_framerate(struct vino_channel_settings *vcs,
+			       unsigned int fps)
+{
+	unsigned int mask;
+
+	switch (vcs->data_norm) {
+	case VINO_DATA_NORM_NTSC:
+	case VINO_DATA_NORM_D1:
+		fps = (unsigned int)(fps / 6) * 6; // FIXME: round!
+
+		if (fps < vino_data_norms[vcs->data_norm].fps_min)
+			fps = vino_data_norms[vcs->data_norm].fps_min;
+		if (fps > vino_data_norms[vcs->data_norm].fps_max)
+			fps = vino_data_norms[vcs->data_norm].fps_max;
+
+		switch (fps) {
+		case 6:
+			mask = 0x003;
+			break;
+		case 12:
+			mask = 0x0c3;
+			break;
+		case 18:
+			mask = 0x333;
+			break;
+		case 24:
+			mask = 0x3ff;
+			break;
+		case 30:
+			mask = 0xfff;
+			break;
+		default:
+			mask = VINO_FRAMERT_FULL;
+		}
+		vcs->framert_reg = VINO_FRAMERT_RT(mask);
+		break;
+	case VINO_DATA_NORM_PAL:
+	case VINO_DATA_NORM_SECAM:
+		fps = (unsigned int)(fps / 5) * 5; // FIXME: round!
+
+		if (fps < vino_data_norms[vcs->data_norm].fps_min)
+			fps = vino_data_norms[vcs->data_norm].fps_min;
+		if (fps > vino_data_norms[vcs->data_norm].fps_max)
+			fps = vino_data_norms[vcs->data_norm].fps_max;
+
+		switch (fps) {
+		case 5:
+			mask = 0x003;
+			break;
+		case 10:
+			mask = 0x0c3;
+			break;
+		case 15:
+			mask = 0x333;
+			break;
+		case 20:
+			mask = 0x0ff;
+			break;
+		case 25:
+			mask = 0x3ff;
+			break;
+		default:
+			mask = VINO_FRAMERT_FULL;
+		}
+		vcs->framert_reg = VINO_FRAMERT_RT(mask) | VINO_FRAMERT_PAL;
+		break;
+	}
+
+	vcs->fps = fps;
+}
+
+/* execute with input_lock locked */
+static inline void vino_set_default_framerate(struct
+					      vino_channel_settings *vcs)
+{
+	vino_set_framerate(vcs, vino_data_norms[vcs->data_norm].fps_max);
+}
+
+/* VINO I2C bus functions */
+
+struct i2c_algo_sgi_data {
+	void *data;	/* private data for lowlevel routines */
+	unsigned (*getctrl)(void *data);
+	void (*setctrl)(void *data, unsigned val);
+	unsigned (*rdata)(void *data);
+	void (*wdata)(void *data, unsigned val);
+
+	int xfer_timeout;
+	int ack_timeout;
+};
+
+static int wait_xfer_done(struct i2c_algo_sgi_data *adap)
+{
+	int i;
+
+	for (i = 0; i < adap->xfer_timeout; i++) {
+		if ((adap->getctrl(adap->data) & SGI_I2C_XFER_BUSY) == 0)
+			return 0;
+		udelay(1);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int wait_ack(struct i2c_algo_sgi_data *adap)
+{
+	int i;
+
+	if (wait_xfer_done(adap))
+		return -ETIMEDOUT;
+	for (i = 0; i < adap->ack_timeout; i++) {
+		if ((adap->getctrl(adap->data) & SGI_I2C_NACK) == 0)
+			return 0;
+		udelay(1);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int force_idle(struct i2c_algo_sgi_data *adap)
+{
+	int i;
+
+	adap->setctrl(adap->data, SGI_I2C_FORCE_IDLE);
+	for (i = 0; i < adap->xfer_timeout; i++) {
+		if ((adap->getctrl(adap->data) & SGI_I2C_NOT_IDLE) == 0)
+			goto out;
+		udelay(1);
+	}
+	return -ETIMEDOUT;
+out:
+	if (adap->getctrl(adap->data) & SGI_I2C_BUS_ERR)
+		return -EIO;
+	return 0;
+}
+
+static int do_address(struct i2c_algo_sgi_data *adap, unsigned int addr,
+		      int rd)
+{
+	if (rd)
+		adap->setctrl(adap->data, SGI_I2C_NOT_IDLE);
+	/* Check if bus is idle, eventually force it to do so */
+	if (adap->getctrl(adap->data) & SGI_I2C_NOT_IDLE)
+		if (force_idle(adap))
+			return -EIO;
+	/* Write out the i2c chip address and specify operation */
+	adap->setctrl(adap->data,
+		      SGI_I2C_HOLD_BUS | SGI_I2C_WRITE | SGI_I2C_NOT_IDLE);
+	if (rd)
+		addr |= 1;
+	adap->wdata(adap->data, addr);
+	if (wait_ack(adap))
+		return -EIO;
+	return 0;
+}
+
+static int i2c_read(struct i2c_algo_sgi_data *adap, unsigned char *buf,
+		    unsigned int len)
+{
+	int i;
+
+	adap->setctrl(adap->data,
+		      SGI_I2C_HOLD_BUS | SGI_I2C_READ | SGI_I2C_NOT_IDLE);
+	for (i = 0; i < len; i++) {
+		if (wait_xfer_done(adap))
+			return -EIO;
+		buf[i] = adap->rdata(adap->data);
+	}
+	adap->setctrl(adap->data, SGI_I2C_RELEASE_BUS | SGI_I2C_FORCE_IDLE);
+
+	return 0;
+
+}
+
+static int i2c_write(struct i2c_algo_sgi_data *adap, unsigned char *buf,
+		     unsigned int len)
+{
+	int i;
+
+	/* We are already in write state */
+	for (i = 0; i < len; i++) {
+		adap->wdata(adap->data, buf[i]);
+		if (wait_ack(adap))
+			return -EIO;
+	}
+	return 0;
+}
+
+static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
+		    int num)
+{
+	struct i2c_algo_sgi_data *adap = i2c_adap->algo_data;
+	struct i2c_msg *p;
+	int i, err = 0;
+
+	for (i = 0; !err && i < num; i++) {
+		p = &msgs[i];
+		err = do_address(adap, p->addr, p->flags & I2C_M_RD);
+		if (err || !p->len)
+			continue;
+		if (p->flags & I2C_M_RD)
+			err = i2c_read(adap, p->buf, p->len);
+		else
+			err = i2c_write(adap, p->buf, p->len);
+	}
+
+	return (err < 0) ? err : i;
+}
+
+static u32 sgi_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm sgi_algo = {
+	.master_xfer	= sgi_xfer,
+	.functionality	= sgi_func,
+};
+
+static unsigned i2c_vino_getctrl(void *data)
+{
+	return vino->i2c_control;
+}
+
+static void i2c_vino_setctrl(void *data, unsigned val)
+{
+	vino->i2c_control = val;
+}
+
+static unsigned i2c_vino_rdata(void *data)
+{
+	return vino->i2c_data;
+}
+
+static void i2c_vino_wdata(void *data, unsigned val)
+{
+	vino->i2c_data = val;
+}
+
+static struct i2c_algo_sgi_data i2c_sgi_vino_data = {
+	.getctrl = &i2c_vino_getctrl,
+	.setctrl = &i2c_vino_setctrl,
+	.rdata   = &i2c_vino_rdata,
+	.wdata   = &i2c_vino_wdata,
+	.xfer_timeout = 200,
+	.ack_timeout  = 1000,
+};
+
+static struct i2c_adapter vino_i2c_adapter = {
+	.name			= "VINO I2C bus",
+	.algo			= &sgi_algo,
+	.algo_data		= &i2c_sgi_vino_data,
+	.owner 			= THIS_MODULE,
+};
+
+/*
+ * Prepare VINO for DMA transfer...
+ * (execute only with vino_lock and input_lock locked)
+ */
+static int vino_dma_setup(struct vino_channel_settings *vcs,
+			  struct vino_framebuffer *fb)
+{
+	u32 ctrl, intr;
+	struct sgi_vino_channel *ch;
+	const struct vino_data_norm *norm;
+
+	dprintk("vino_dma_setup():\n");
+
+	vcs->field = 0;
+	fb->frame_counter = 0;
+
+	ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b;
+	norm = &vino_data_norms[vcs->data_norm];
+
+	ch->page_index = 0;
+	ch->line_count = 0;
+
+	/* VINO line size register is set 8 bytes less than actual */
+	ch->line_size = vcs->line_size - 8;
+
+	/* let VINO know where to transfer data */
+	ch->start_desc_tbl = fb->desc_table.dma;
+	ch->next_4_desc = fb->desc_table.dma;
+
+	/* give vino time to fetch the first four descriptors, 5 usec
+	 * should be more than enough time */
+	udelay(VINO_DESC_FETCH_DELAY);
+
+	dprintk("vino_dma_setup(): start desc = %08x, next 4 desc = %08x\n",
+		ch->start_desc_tbl, ch->next_4_desc);
+
+	/* set the alpha register */
+	ch->alpha = vcs->alpha;
+
+	/* set clipping registers */
+	ch->clip_start = VINO_CLIP_ODD(norm->odd.top + vcs->clipping.top / 2) |
+		VINO_CLIP_EVEN(norm->even.top +
+			       vcs->clipping.top / 2) |
+		VINO_CLIP_X(vcs->clipping.left);
+	ch->clip_end = VINO_CLIP_ODD(norm->odd.top +
+				     vcs->clipping.bottom / 2 - 1) |
+		VINO_CLIP_EVEN(norm->even.top +
+			       vcs->clipping.bottom / 2 - 1) |
+		VINO_CLIP_X(vcs->clipping.right);
+
+	/* set the size of actual content in the buffer (DECIMATION !) */
+	fb->data_size = ((vcs->clipping.right - vcs->clipping.left) /
+			 vcs->decimation) *
+		((vcs->clipping.bottom - vcs->clipping.top) /
+		 vcs->decimation) *
+		vino_data_formats[vcs->data_format].bpp;
+
+	ch->frame_rate = vcs->framert_reg;
+
+	ctrl = vino->control;
+	intr = vino->intr_status;
+
+	if (vcs->channel == VINO_CHANNEL_A) {
+		/* All interrupt conditions for this channel was cleared
+		 * so clear the interrupt status register and enable
+		 * interrupts */
+		intr &=	~VINO_INTSTAT_A;
+		ctrl |= VINO_CTRL_A_INT;
+
+		/* enable synchronization */
+		ctrl |= VINO_CTRL_A_SYNC_ENBL;
+
+		/* enable frame assembly */
+		ctrl |= VINO_CTRL_A_INTERLEAVE_ENBL;
+
+		/* set decimation used */
+		if (vcs->decimation < 2)
+			ctrl &= ~VINO_CTRL_A_DEC_ENBL;
+		else {
+			ctrl |= VINO_CTRL_A_DEC_ENBL;
+			ctrl &= ~VINO_CTRL_A_DEC_SCALE_MASK;
+			ctrl |= (vcs->decimation - 1) <<
+				VINO_CTRL_A_DEC_SCALE_SHIFT;
+		}
+
+		/* select input interface */
+		if (vcs->input == VINO_INPUT_D1)
+			ctrl |= VINO_CTRL_A_SELECT;
+		else
+			ctrl &= ~VINO_CTRL_A_SELECT;
+
+		/* palette */
+		ctrl &= ~(VINO_CTRL_A_LUMA_ONLY | VINO_CTRL_A_RGB |
+			  VINO_CTRL_A_DITHER);
+	} else {
+		intr &= ~VINO_INTSTAT_B;
+		ctrl |= VINO_CTRL_B_INT;
+
+		ctrl |= VINO_CTRL_B_SYNC_ENBL;
+		ctrl |= VINO_CTRL_B_INTERLEAVE_ENBL;
+
+		if (vcs->decimation < 2)
+			ctrl &= ~VINO_CTRL_B_DEC_ENBL;
+		else {
+			ctrl |= VINO_CTRL_B_DEC_ENBL;
+			ctrl &= ~VINO_CTRL_B_DEC_SCALE_MASK;
+			ctrl |= (vcs->decimation - 1) <<
+				VINO_CTRL_B_DEC_SCALE_SHIFT;
+
+		}
+		if (vcs->input == VINO_INPUT_D1)
+			ctrl |= VINO_CTRL_B_SELECT;
+		else
+			ctrl &= ~VINO_CTRL_B_SELECT;
+
+		ctrl &= ~(VINO_CTRL_B_LUMA_ONLY | VINO_CTRL_B_RGB |
+			  VINO_CTRL_B_DITHER);
+	}
+
+	/* set palette */
+	fb->data_format = vcs->data_format;
+
+	switch (vcs->data_format) {
+		case VINO_DATA_FMT_GREY:
+			ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
+				VINO_CTRL_A_LUMA_ONLY : VINO_CTRL_B_LUMA_ONLY;
+			break;
+		case VINO_DATA_FMT_RGB32:
+			ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
+				VINO_CTRL_A_RGB : VINO_CTRL_B_RGB;
+			break;
+		case VINO_DATA_FMT_YUV:
+			/* nothing needs to be done */
+			break;
+		case VINO_DATA_FMT_RGB332:
+			ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
+				VINO_CTRL_A_RGB | VINO_CTRL_A_DITHER :
+				VINO_CTRL_B_RGB | VINO_CTRL_B_DITHER;
+			break;
+	}
+
+	vino->intr_status = intr;
+	vino->control = ctrl;
+
+	return 0;
+}
+
+/* (execute only with vino_lock locked) */
+static inline void vino_dma_start(struct vino_channel_settings *vcs)
+{
+	u32 ctrl = vino->control;
+
+	dprintk("vino_dma_start():\n");
+	ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
+		VINO_CTRL_A_DMA_ENBL : VINO_CTRL_B_DMA_ENBL;
+	vino->control = ctrl;
+}
+
+/* (execute only with vino_lock locked) */
+static inline void vino_dma_stop(struct vino_channel_settings *vcs)
+{
+	u32 ctrl = vino->control;
+
+	ctrl &= (vcs->channel == VINO_CHANNEL_A) ?
+		~VINO_CTRL_A_DMA_ENBL : ~VINO_CTRL_B_DMA_ENBL;
+	ctrl &= (vcs->channel == VINO_CHANNEL_A) ?
+		~VINO_CTRL_A_INT : ~VINO_CTRL_B_INT;
+	vino->control = ctrl;
+	dprintk("vino_dma_stop():\n");
+}
+
+/*
+ * Load dummy page to descriptor registers. This prevents generating of
+ * spurious interrupts. (execute only with vino_lock locked)
+ */
+static void vino_clear_interrupt(struct vino_channel_settings *vcs)
+{
+	struct sgi_vino_channel *ch;
+
+	ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b;
+
+	ch->page_index = 0;
+	ch->line_count = 0;
+
+	ch->start_desc_tbl = vino_drvdata->dummy_desc_table.dma;
+	ch->next_4_desc = vino_drvdata->dummy_desc_table.dma;
+
+	udelay(VINO_DESC_FETCH_DELAY);
+	dprintk("channel %c clear interrupt condition\n",
+	       (vcs->channel == VINO_CHANNEL_A) ? 'A':'B');
+}
+
+static int vino_capture(struct vino_channel_settings *vcs,
+			struct vino_framebuffer *fb)
+{
+	int err = 0;
+	unsigned long flags, flags2;
+
+	spin_lock_irqsave(&fb->state_lock, flags);
+
+	if (fb->state == VINO_FRAMEBUFFER_IN_USE)
+		err = -EBUSY;
+	fb->state = VINO_FRAMEBUFFER_IN_USE;
+
+	spin_unlock_irqrestore(&fb->state_lock, flags);
+
+	if (err)
+		return err;
+
+	spin_lock_irqsave(&vino_drvdata->vino_lock, flags);
+	spin_lock_irqsave(&vino_drvdata->input_lock, flags2);
+
+	vino_dma_setup(vcs, fb);
+	vino_dma_start(vcs);
+
+	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags2);
+	spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags);
+
+	return err;
+}
+
+static
+struct vino_framebuffer *vino_capture_enqueue(struct
+					      vino_channel_settings *vcs,
+					      unsigned int index)
+{
+	struct vino_framebuffer *fb;
+	unsigned long flags;
+
+	dprintk("vino_capture_enqueue():\n");
+
+	spin_lock_irqsave(&vcs->capture_lock, flags);
+
+	fb = vino_queue_add(&vcs->fb_queue, index);
+	if (fb == NULL) {
+		dprintk("vino_capture_enqueue(): vino_queue_add() failed, "
+			"queue full?\n");
+		goto out;
+	}
+out:
+	spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+	return fb;
+}
+
+static int vino_capture_next(struct vino_channel_settings *vcs, int start)
+{
+	struct vino_framebuffer *fb;
+	unsigned int incoming, id;
+	int err = 0;
+	unsigned long flags;
+
+	dprintk("vino_capture_next():\n");
+
+	spin_lock_irqsave(&vcs->capture_lock, flags);
+
+	if (start) {
+		/* start capture only if capture isn't in progress already */
+		if (vcs->capturing) {
+			spin_unlock_irqrestore(&vcs->capture_lock, flags);
+			return 0;
+		}
+
+	} else {
+		/* capture next frame:
+		 * stop capture if capturing is not set */
+		if (!vcs->capturing) {
+			spin_unlock_irqrestore(&vcs->capture_lock, flags);
+			return 0;
+		}
+	}
+
+	err = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
+	if (err) {
+		dprintk("vino_capture_next(): vino_queue_get_incoming() "
+			"failed\n");
+		err = -EINVAL;
+		goto out;
+	}
+	if (incoming == 0) {
+		dprintk("vino_capture_next(): no buffers available\n");
+		goto out;
+	}
+
+	fb = vino_queue_peek(&vcs->fb_queue, &id);
+	if (fb == NULL) {
+		dprintk("vino_capture_next(): vino_queue_peek() failed\n");
+		err = -EINVAL;
+		goto out;
+	}
+
+	if (start) {
+		vcs->capturing = 1;
+	}
+
+	spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+	err = vino_capture(vcs, fb);
+
+	return err;
+
+out:
+	vcs->capturing = 0;
+	spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+	return err;
+}
+
+static inline int vino_is_capturing(struct vino_channel_settings *vcs)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vcs->capture_lock, flags);
+
+	ret = vcs->capturing;
+
+	spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+	return ret;
+}
+
+/* waits until a frame is captured */
+static int vino_wait_for_frame(struct vino_channel_settings *vcs)
+{
+	wait_queue_t wait;
+	int err = 0;
+
+	dprintk("vino_wait_for_frame():\n");
+
+	init_waitqueue_entry(&wait, current);
+	/* add ourselves into wait queue */
+	add_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait);
+
+	/* to ensure that schedule_timeout will return immediately
+	 * if VINO interrupt was triggered meanwhile */
+	schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+	if (signal_pending(current))
+		err = -EINTR;
+
+	remove_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait);
+
+	dprintk("vino_wait_for_frame(): waiting for frame %s\n",
+		err ? "failed" : "ok");
+
+	return err;
+}
+
+/* the function assumes that PAGE_SIZE % 4 == 0 */
+static void vino_convert_to_rgba(struct vino_framebuffer *fb) {
+	unsigned char *pageptr;
+	unsigned int page, i;
+	unsigned char a;
+
+	for (page = 0; page < fb->desc_table.page_count; page++) {
+		pageptr = (unsigned char *)fb->desc_table.virtual[page];
+
+		for (i = 0; i < PAGE_SIZE; i += 4) {
+			a = pageptr[0];
+			pageptr[0] = pageptr[3];
+			pageptr[1] = pageptr[2];
+			pageptr[2] = pageptr[1];
+			pageptr[3] = a;
+			pageptr += 4;
+		}
+	}
+}
+
+/* checks if the buffer is in correct state and syncs data */
+static int vino_check_buffer(struct vino_channel_settings *vcs,
+			     struct vino_framebuffer *fb)
+{
+	int err = 0;
+	unsigned long flags;
+
+	dprintk("vino_check_buffer():\n");
+
+	spin_lock_irqsave(&fb->state_lock, flags);
+	switch (fb->state) {
+	case VINO_FRAMEBUFFER_IN_USE:
+		err = -EIO;
+		break;
+	case VINO_FRAMEBUFFER_READY:
+		vino_sync_buffer(fb);
+		fb->state = VINO_FRAMEBUFFER_UNUSED;
+		break;
+	default:
+		err = -EINVAL;
+	}
+	spin_unlock_irqrestore(&fb->state_lock, flags);
+
+	if (!err) {
+		if (vino_pixel_conversion
+		    && (fb->data_format == VINO_DATA_FMT_RGB32)) {
+			vino_convert_to_rgba(fb);
+		}
+	} else if (err && (err != -EINVAL)) {
+		dprintk("vino_check_buffer(): buffer not ready\n");
+
+		spin_lock_irqsave(&vino_drvdata->vino_lock, flags);
+		vino_dma_stop(vcs);
+		vino_clear_interrupt(vcs);
+		spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags);
+	}
+
+	return err;
+}
+
+/* forcefully terminates capture */
+static void vino_capture_stop(struct vino_channel_settings *vcs)
+{
+	unsigned int incoming = 0, outgoing = 0, id;
+	unsigned long flags, flags2;
+
+	dprintk("vino_capture_stop():\n");
+
+	spin_lock_irqsave(&vcs->capture_lock, flags);
+
+	/* unset capturing to stop queue processing */
+	vcs->capturing = 0;
+
+	spin_lock_irqsave(&vino_drvdata->vino_lock, flags2);
+
+	vino_dma_stop(vcs);
+	vino_clear_interrupt(vcs);
+
+	spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags2);
+
+	/* remove all items from the queue */
+	if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) {
+		dprintk("vino_capture_stop(): "
+			"vino_queue_get_incoming() failed\n");
+		goto out;
+	}
+	while (incoming > 0) {
+		vino_queue_transfer(&vcs->fb_queue);
+
+		if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) {
+			dprintk("vino_capture_stop(): "
+				"vino_queue_get_incoming() failed\n");
+			goto out;
+		}
+	}
+
+	if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
+		dprintk("vino_capture_stop(): "
+			"vino_queue_get_outgoing() failed\n");
+		goto out;
+	}
+	while (outgoing > 0) {
+		vino_queue_remove(&vcs->fb_queue, &id);
+
+		if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
+			dprintk("vino_capture_stop(): "
+				"vino_queue_get_outgoing() failed\n");
+			goto out;
+		}
+	}
+
+out:
+	spin_unlock_irqrestore(&vcs->capture_lock, flags);
+}
+
+#if 0
+static int vino_capture_failed(struct vino_channel_settings *vcs)
+{
+	struct vino_framebuffer *fb;
+	unsigned long flags;
+	unsigned int i;
+	int ret;
+
+	dprintk("vino_capture_failed():\n");
+
+	spin_lock_irqsave(&vino_drvdata->vino_lock, flags);
+
+	vino_dma_stop(vcs);
+	vino_clear_interrupt(vcs);
+
+	spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags);
+
+	ret = vino_queue_get_incoming(&vcs->fb_queue, &i);
+	if (ret == VINO_QUEUE_ERROR) {
+		dprintk("vino_queue_get_incoming() failed\n");
+		return -EINVAL;
+	}
+	if (i == 0) {
+		/* no buffers to process */
+		return 0;
+	}
+
+	fb = vino_queue_peek(&vcs->fb_queue, &i);
+	if (fb == NULL) {
+		dprintk("vino_queue_peek() failed\n");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&fb->state_lock, flags);
+	if (fb->state == VINO_FRAMEBUFFER_IN_USE) {
+		fb->state = VINO_FRAMEBUFFER_UNUSED;
+		vino_queue_transfer(&vcs->fb_queue);
+		vino_queue_remove(&vcs->fb_queue, &i);
+		/* we should actually discard the newest frame,
+		 * but who cares ... */
+	}
+	spin_unlock_irqrestore(&fb->state_lock, flags);
+
+	return 0;
+}
+#endif
+
+static void vino_skip_frame(struct vino_channel_settings *vcs)
+{
+	struct vino_framebuffer *fb;
+	unsigned long flags;
+	unsigned int id;
+
+	spin_lock_irqsave(&vcs->capture_lock, flags);
+	fb = vino_queue_peek(&vcs->fb_queue, &id);
+	if (!fb) {
+		spin_unlock_irqrestore(&vcs->capture_lock, flags);
+		dprintk("vino_skip_frame(): vino_queue_peek() failed!\n");
+		return;
+	}
+	spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+	spin_lock_irqsave(&fb->state_lock, flags);
+	fb->state = VINO_FRAMEBUFFER_UNUSED;
+	spin_unlock_irqrestore(&fb->state_lock, flags);
+
+	vino_capture_next(vcs, 0);
+}
+
+static void vino_frame_done(struct vino_channel_settings *vcs)
+{
+	struct vino_framebuffer *fb;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vcs->capture_lock, flags);
+	fb = vino_queue_transfer(&vcs->fb_queue);
+	if (!fb) {
+		spin_unlock_irqrestore(&vcs->capture_lock, flags);
+		dprintk("vino_frame_done(): vino_queue_transfer() failed!\n");
+		return;
+	}
+	spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+	fb->frame_counter = vcs->int_data.frame_counter;
+	memcpy(&fb->timestamp, &vcs->int_data.timestamp,
+	       sizeof(struct timeval));
+
+	spin_lock_irqsave(&fb->state_lock, flags);
+	if (fb->state == VINO_FRAMEBUFFER_IN_USE)
+		fb->state = VINO_FRAMEBUFFER_READY;
+	spin_unlock_irqrestore(&fb->state_lock, flags);
+
+	wake_up(&vcs->fb_queue.frame_wait_queue);
+
+	vino_capture_next(vcs, 0);
+}
+
+static void vino_capture_tasklet(unsigned long channel) {
+	struct vino_channel_settings *vcs;
+
+	vcs = (channel == VINO_CHANNEL_A)
+		? &vino_drvdata->a : &vino_drvdata->b;
+
+	if (vcs->int_data.skip)
+		vcs->int_data.skip_count++;
+
+	if (vcs->int_data.skip && (vcs->int_data.skip_count
+				   <= VINO_MAX_FRAME_SKIP_COUNT)) {
+		vino_skip_frame(vcs);
+	} else {
+		vcs->int_data.skip_count = 0;
+		vino_frame_done(vcs);
+	}
+}
+
+static irqreturn_t vino_interrupt(int irq, void *dev_id)
+{
+	u32 ctrl, intr;
+	unsigned int fc_a, fc_b;
+	int handled_a = 0, skip_a = 0, done_a = 0;
+	int handled_b = 0, skip_b = 0, done_b = 0;
+
+#ifdef VINO_DEBUG_INT
+	int loop = 0;
+	unsigned int line_count = vino->a.line_count,
+		page_index = vino->a.page_index,
+		field_counter = vino->a.field_counter,
+		start_desc_tbl = vino->a.start_desc_tbl,
+		next_4_desc = vino->a.next_4_desc;
+	unsigned int line_count_2,
+		page_index_2,
+		field_counter_2,
+		start_desc_tbl_2,
+		next_4_desc_2;
+#endif
+
+	spin_lock(&vino_drvdata->vino_lock);
+
+	while ((intr = vino->intr_status)) {
+		fc_a = vino->a.field_counter >> 1;
+		fc_b = vino->b.field_counter >> 1;
+
+		/* handle error-interrupts in some special way ?
+		 * --> skips frames */
+		if (intr & VINO_INTSTAT_A) {
+			if (intr & VINO_INTSTAT_A_EOF) {
+				vino_drvdata->a.field++;
+				if (vino_drvdata->a.field > 1) {
+					vino_dma_stop(&vino_drvdata->a);
+					vino_clear_interrupt(&vino_drvdata->a);
+					vino_drvdata->a.field = 0;
+					done_a = 1;
+				} else {
+					if (vino->a.page_index
+					    != vino_drvdata->a.line_size) {
+						vino->a.line_count = 0;
+						vino->a.page_index =
+							vino_drvdata->
+							a.line_size;
+						vino->a.next_4_desc =
+							vino->a.start_desc_tbl;
+					}
+				}
+				dprintk("channel A end-of-field "
+					"interrupt: %04x\n", intr);
+			} else {
+				vino_dma_stop(&vino_drvdata->a);
+				vino_clear_interrupt(&vino_drvdata->a);
+				vino_drvdata->a.field = 0;
+				skip_a = 1;
+				dprintk("channel A error interrupt: %04x\n",
+					intr);
+			}
+
+#ifdef VINO_DEBUG_INT
+			line_count_2 = vino->a.line_count;
+			page_index_2 = vino->a.page_index;
+			field_counter_2 = vino->a.field_counter;
+			start_desc_tbl_2 = vino->a.start_desc_tbl;
+			next_4_desc_2 = vino->a.next_4_desc;
+
+			printk("intr = %04x, loop = %d, field = %d\n",
+			       intr, loop, vino_drvdata->a.field);
+			printk("1- line count = %04d, page index = %04d, "
+			       "start = %08x, next = %08x\n"
+			       "   fieldc = %d, framec = %d\n",
+			       line_count, page_index, start_desc_tbl,
+			       next_4_desc, field_counter, fc_a);
+			printk("12-line count = %04d, page index = %04d, "
+			       "   start = %08x, next = %08x\n",
+			       line_count_2, page_index_2, start_desc_tbl_2,
+			       next_4_desc_2);
+
+			if (done_a)
+				printk("\n");
+#endif
+		}
+
+		if (intr & VINO_INTSTAT_B) {
+			if (intr & VINO_INTSTAT_B_EOF) {
+				vino_drvdata->b.field++;
+				if (vino_drvdata->b.field > 1) {
+					vino_dma_stop(&vino_drvdata->b);
+					vino_clear_interrupt(&vino_drvdata->b);
+					vino_drvdata->b.field = 0;
+					done_b = 1;
+				}
+				dprintk("channel B end-of-field "
+					"interrupt: %04x\n", intr);
+			} else {
+				vino_dma_stop(&vino_drvdata->b);
+				vino_clear_interrupt(&vino_drvdata->b);
+				vino_drvdata->b.field = 0;
+				skip_b = 1;
+				dprintk("channel B error interrupt: %04x\n",
+					intr);
+			}
+		}
+
+		/* Always remember to clear interrupt status.
+		 * Disable VINO interrupts while we do this. */
+		ctrl = vino->control;
+		vino->control = ctrl & ~(VINO_CTRL_A_INT | VINO_CTRL_B_INT);
+		vino->intr_status = ~intr;
+		vino->control = ctrl;
+
+		spin_unlock(&vino_drvdata->vino_lock);
+
+		if ((!handled_a) && (done_a || skip_a)) {
+			if (!skip_a) {
+				do_gettimeofday(&vino_drvdata->
+						a.int_data.timestamp);
+				vino_drvdata->a.int_data.frame_counter = fc_a;
+			}
+			vino_drvdata->a.int_data.skip = skip_a;
+
+			dprintk("channel A %s, interrupt: %d\n",
+				skip_a ? "skipping frame" : "frame done",
+				intr);
+			tasklet_hi_schedule(&vino_tasklet_a);
+			handled_a = 1;
+		}
+
+		if ((!handled_b) && (done_b || skip_b)) {
+			if (!skip_b) {
+				do_gettimeofday(&vino_drvdata->
+						b.int_data.timestamp);
+				vino_drvdata->b.int_data.frame_counter = fc_b;
+			}
+			vino_drvdata->b.int_data.skip = skip_b;
+
+			dprintk("channel B %s, interrupt: %d\n",
+				skip_b ? "skipping frame" : "frame done",
+				intr);
+			tasklet_hi_schedule(&vino_tasklet_b);
+			handled_b = 1;
+		}
+
+#ifdef VINO_DEBUG_INT
+		loop++;
+#endif
+		spin_lock(&vino_drvdata->vino_lock);
+	}
+
+	spin_unlock(&vino_drvdata->vino_lock);
+
+	return IRQ_HANDLED;
+}
+
+/* VINO video input management */
+
+static int vino_get_saa7191_input(int input)
+{
+	switch (input) {
+	case VINO_INPUT_COMPOSITE:
+		return SAA7191_INPUT_COMPOSITE;
+	case VINO_INPUT_SVIDEO:
+		return SAA7191_INPUT_SVIDEO;
+	default:
+		printk(KERN_ERR "VINO: vino_get_saa7191_input(): "
+		       "invalid input!\n");
+		return -1;
+	}
+}
+
+/* execute with input_lock locked */
+static int vino_is_input_owner(struct vino_channel_settings *vcs)
+{
+	switch(vcs->input) {
+	case VINO_INPUT_COMPOSITE:
+	case VINO_INPUT_SVIDEO:
+		return vino_drvdata->decoder_owner == vcs->channel;
+	case VINO_INPUT_D1:
+		return vino_drvdata->camera_owner == vcs->channel;
+	default:
+		return 0;
+	}
+}
+
+static int vino_acquire_input(struct vino_channel_settings *vcs)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	dprintk("vino_acquire_input():\n");
+
+	spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+	/* First try D1 and then SAA7191 */
+	if (vino_drvdata->camera
+	    && (vino_drvdata->camera_owner == VINO_NO_CHANNEL)) {
+		vino_drvdata->camera_owner = vcs->channel;
+		vcs->input = VINO_INPUT_D1;
+		vcs->data_norm = VINO_DATA_NORM_D1;
+	} else if (vino_drvdata->decoder
+		   && (vino_drvdata->decoder_owner == VINO_NO_CHANNEL)) {
+		int input;
+		int data_norm = 0;
+		v4l2_std_id norm;
+
+		input = VINO_INPUT_COMPOSITE;
+
+		ret = decoder_call(video, s_routing,
+				vino_get_saa7191_input(input), 0, 0);
+		if (ret) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+		/* Don't hold spinlocks while auto-detecting norm
+		 * as it may take a while... */
+
+		ret = decoder_call(video, querystd, &norm);
+		if (!ret) {
+			for (data_norm = 0; data_norm < 3; data_norm++) {
+				if (vino_data_norms[data_norm].std & norm)
+					break;
+			}
+			if (data_norm == 3)
+				data_norm = VINO_DATA_NORM_PAL;
+			ret = decoder_call(core, s_std, norm);
+		}
+
+		spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+		if (ret) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		vino_drvdata->decoder_owner = vcs->channel;
+
+		vcs->input = input;
+		vcs->data_norm = data_norm;
+	} else {
+		vcs->input = (vcs->channel == VINO_CHANNEL_A) ?
+			vino_drvdata->b.input : vino_drvdata->a.input;
+		vcs->data_norm = (vcs->channel == VINO_CHANNEL_A) ?
+			vino_drvdata->b.data_norm : vino_drvdata->a.data_norm;
+	}
+
+	if (vcs->input == VINO_INPUT_NONE) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	vino_set_default_clipping(vcs);
+	vino_set_default_scaling(vcs);
+	vino_set_default_framerate(vcs);
+
+	dprintk("vino_acquire_input(): %s\n", vino_inputs[vcs->input].name);
+
+out:
+	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+	return ret;
+}
+
+static int vino_set_input(struct vino_channel_settings *vcs, int input)
+{
+	struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ?
+		&vino_drvdata->b : &vino_drvdata->a;
+	unsigned long flags;
+	int ret = 0;
+
+	dprintk("vino_set_input():\n");
+
+	spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+	if (vcs->input == input)
+		goto out;
+
+	switch (input) {
+	case VINO_INPUT_COMPOSITE:
+	case VINO_INPUT_SVIDEO:
+		if (!vino_drvdata->decoder) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		if (vino_drvdata->decoder_owner == VINO_NO_CHANNEL) {
+			vino_drvdata->decoder_owner = vcs->channel;
+		}
+
+		if (vino_drvdata->decoder_owner == vcs->channel) {
+			int data_norm = 0;
+			v4l2_std_id norm;
+
+			ret = decoder_call(video, s_routing,
+					vino_get_saa7191_input(input), 0, 0);
+			if (ret) {
+				vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
+				ret = -EINVAL;
+				goto out;
+			}
+
+			spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+			/* Don't hold spinlocks while auto-detecting norm
+			 * as it may take a while... */
+
+			ret = decoder_call(video, querystd, &norm);
+			if (!ret) {
+				for (data_norm = 0; data_norm < 3; data_norm++) {
+					if (vino_data_norms[data_norm].std & norm)
+						break;
+				}
+				if (data_norm == 3)
+					data_norm = VINO_DATA_NORM_PAL;
+				ret = decoder_call(core, s_std, norm);
+			}
+
+			spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+			if (ret) {
+				vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
+				ret = -EINVAL;
+				goto out;
+			}
+
+			vcs->input = input;
+			vcs->data_norm = data_norm;
+		} else {
+			if (input != vcs2->input) {
+				ret = -EBUSY;
+				goto out;
+			}
+
+			vcs->input = input;
+			vcs->data_norm = vcs2->data_norm;
+		}
+
+		if (vino_drvdata->camera_owner == vcs->channel) {
+			/* Transfer the ownership or release the input */
+			if (vcs2->input == VINO_INPUT_D1) {
+				vino_drvdata->camera_owner = vcs2->channel;
+			} else {
+				vino_drvdata->camera_owner = VINO_NO_CHANNEL;
+			}
+		}
+		break;
+	case VINO_INPUT_D1:
+		if (!vino_drvdata->camera) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		if (vino_drvdata->camera_owner == VINO_NO_CHANNEL)
+			vino_drvdata->camera_owner = vcs->channel;
+
+		if (vino_drvdata->decoder_owner == vcs->channel) {
+			/* Transfer the ownership or release the input */
+			if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
+				 (vcs2->input == VINO_INPUT_SVIDEO)) {
+				vino_drvdata->decoder_owner = vcs2->channel;
+			} else {
+				vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
+			}
+		}
+
+		vcs->input = input;
+		vcs->data_norm = VINO_DATA_NORM_D1;
+		break;
+	default:
+		ret = -EINVAL;
+		goto out;
+	}
+
+	vino_set_default_clipping(vcs);
+	vino_set_default_scaling(vcs);
+	vino_set_default_framerate(vcs);
+
+	dprintk("vino_set_input(): %s\n", vino_inputs[vcs->input].name);
+
+out:
+	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+	return ret;
+}
+
+static void vino_release_input(struct vino_channel_settings *vcs)
+{
+	struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ?
+		&vino_drvdata->b : &vino_drvdata->a;
+	unsigned long flags;
+
+	dprintk("vino_release_input():\n");
+
+	spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+	/* Release ownership of the channel
+	 * and if the other channel takes input from
+	 * the same source, transfer the ownership */
+	if (vino_drvdata->camera_owner == vcs->channel) {
+		if (vcs2->input == VINO_INPUT_D1) {
+			vino_drvdata->camera_owner = vcs2->channel;
+		} else {
+			vino_drvdata->camera_owner = VINO_NO_CHANNEL;
+		}
+	} else if (vino_drvdata->decoder_owner == vcs->channel) {
+		if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
+			 (vcs2->input == VINO_INPUT_SVIDEO)) {
+			vino_drvdata->decoder_owner = vcs2->channel;
+		} else {
+			vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
+		}
+	}
+	vcs->input = VINO_INPUT_NONE;
+
+	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+}
+
+/* execute with input_lock locked */
+static int vino_set_data_norm(struct vino_channel_settings *vcs,
+			      unsigned int data_norm,
+			      unsigned long *flags)
+{
+	int err = 0;
+
+	if (data_norm == vcs->data_norm)
+		return 0;
+
+	switch (vcs->input) {
+	case VINO_INPUT_D1:
+		/* only one "norm" supported */
+		if (data_norm != VINO_DATA_NORM_D1)
+			return -EINVAL;
+		break;
+	case VINO_INPUT_COMPOSITE:
+	case VINO_INPUT_SVIDEO: {
+		v4l2_std_id norm;
+
+		if ((data_norm != VINO_DATA_NORM_PAL)
+		    && (data_norm != VINO_DATA_NORM_NTSC)
+		    && (data_norm != VINO_DATA_NORM_SECAM))
+			return -EINVAL;
+
+		spin_unlock_irqrestore(&vino_drvdata->input_lock, *flags);
+
+		/* Don't hold spinlocks while setting norm
+		 * as it may take a while... */
+
+		norm = vino_data_norms[data_norm].std;
+		err = decoder_call(core, s_std, norm);
+
+		spin_lock_irqsave(&vino_drvdata->input_lock, *flags);
+
+		if (err)
+			goto out;
+
+		vcs->data_norm = data_norm;
+
+		vino_set_default_clipping(vcs);
+		vino_set_default_scaling(vcs);
+		vino_set_default_framerate(vcs);
+		break;
+	}
+	default:
+		return -EINVAL;
+	}
+
+out:
+	return err;
+}
+
+/* V4L2 helper functions */
+
+static int vino_find_data_format(__u32 pixelformat)
+{
+	int i;
+
+	for (i = 0; i < VINO_DATA_FMT_COUNT; i++) {
+		if (vino_data_formats[i].pixelformat == pixelformat)
+			return i;
+	}
+
+	return VINO_DATA_FMT_NONE;
+}
+
+static int vino_int_enum_input(struct vino_channel_settings *vcs, __u32 index)
+{
+	int input = VINO_INPUT_NONE;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+	if (vino_drvdata->decoder && vino_drvdata->camera) {
+		switch (index) {
+		case 0:
+			input = VINO_INPUT_COMPOSITE;
+			break;
+		case 1:
+			input = VINO_INPUT_SVIDEO;
+			break;
+		case 2:
+			input = VINO_INPUT_D1;
+			break;
+		}
+	} else if (vino_drvdata->decoder) {
+		switch (index) {
+		case 0:
+			input = VINO_INPUT_COMPOSITE;
+			break;
+		case 1:
+			input = VINO_INPUT_SVIDEO;
+			break;
+		}
+	} else if (vino_drvdata->camera) {
+		switch (index) {
+		case 0:
+			input = VINO_INPUT_D1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+	return input;
+}
+
+/* execute with input_lock locked */
+static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
+{
+	__u32 index = 0;
+	// FIXME: detect when no inputs available
+
+	if (vino_drvdata->decoder && vino_drvdata->camera) {
+		switch (vcs->input) {
+		case VINO_INPUT_COMPOSITE:
+			index = 0;
+			break;
+		case VINO_INPUT_SVIDEO:
+			index = 1;
+			break;
+		case VINO_INPUT_D1:
+			index = 2;
+			break;
+		}
+	} else if (vino_drvdata->decoder) {
+		switch (vcs->input) {
+		case VINO_INPUT_COMPOSITE:
+			index = 0;
+			break;
+		case VINO_INPUT_SVIDEO:
+			index = 1;
+			break;
+		}
+	} else if (vino_drvdata->camera) {
+		switch (vcs->input) {
+		case VINO_INPUT_D1:
+			index = 0;
+			break;
+		}
+	}
+
+	return index;
+}
+
+/* V4L2 ioctls */
+
+static int vino_querycap(struct file *file, void *__fh,
+		struct v4l2_capability *cap)
+{
+	memset(cap, 0, sizeof(struct v4l2_capability));
+
+	strcpy(cap->driver, vino_driver_name);
+	strcpy(cap->card, vino_driver_description);
+	strcpy(cap->bus_info, vino_bus_name);
+	cap->capabilities =
+		V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_STREAMING;
+	// V4L2_CAP_OVERLAY, V4L2_CAP_READWRITE
+	return 0;
+}
+
+static int vino_enum_input(struct file *file, void *__fh,
+			       struct v4l2_input *i)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	__u32 index = i->index;
+	int input;
+	dprintk("requested index = %d\n", index);
+
+	input = vino_int_enum_input(vcs, index);
+	if (input == VINO_INPUT_NONE)
+		return -EINVAL;
+
+	i->type = V4L2_INPUT_TYPE_CAMERA;
+	i->std = vino_inputs[input].std;
+	strcpy(i->name, vino_inputs[input].name);
+
+	if (input == VINO_INPUT_COMPOSITE || input == VINO_INPUT_SVIDEO)
+		decoder_call(video, g_input_status, &i->status);
+	return 0;
+}
+
+static int vino_g_input(struct file *file, void *__fh,
+			     unsigned int *i)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	__u32 index;
+	int input;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+	input = vcs->input;
+	index = vino_find_input_index(vcs);
+	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+	dprintk("input = %d\n", input);
+
+	if (input == VINO_INPUT_NONE) {
+		return -EINVAL;
+	}
+
+	*i = index;
+
+	return 0;
+}
+
+static int vino_s_input(struct file *file, void *__fh,
+			     unsigned int i)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	int input;
+	dprintk("requested input = %d\n", i);
+
+	input = vino_int_enum_input(vcs, i);
+	if (input == VINO_INPUT_NONE)
+		return -EINVAL;
+
+	return vino_set_input(vcs, input);
+}
+
+static int vino_querystd(struct file *file, void *__fh,
+			      v4l2_std_id *std)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	unsigned long flags;
+	int err = 0;
+
+	spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+	switch (vcs->input) {
+	case VINO_INPUT_D1:
+		*std = vino_inputs[vcs->input].std;
+		break;
+	case VINO_INPUT_COMPOSITE:
+	case VINO_INPUT_SVIDEO: {
+		decoder_call(video, querystd, std);
+		break;
+	}
+	default:
+		err = -EINVAL;
+	}
+
+	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+	return err;
+}
+
+static int vino_g_std(struct file *file, void *__fh,
+			   v4l2_std_id *std)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	unsigned long flags;
+
+	spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+	*std = vino_data_norms[vcs->data_norm].std;
+	dprintk("current standard = %d\n", vcs->data_norm);
+
+	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+	return 0;
+}
+
+static int vino_s_std(struct file *file, void *__fh,
+			   v4l2_std_id *std)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+	if (!vino_is_input_owner(vcs)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	/* check if the standard is valid for the current input */
+	if ((*std) & vino_inputs[vcs->input].std) {
+		dprintk("standard accepted\n");
+
+		/* change the video norm for SAA7191
+		 * and accept NTSC for D1 (do nothing) */
+
+		if (vcs->input == VINO_INPUT_D1)
+			goto out;
+
+		if ((*std) & V4L2_STD_PAL) {
+			ret = vino_set_data_norm(vcs, VINO_DATA_NORM_PAL,
+						 &flags);
+		} else if ((*std) & V4L2_STD_NTSC) {
+			ret = vino_set_data_norm(vcs, VINO_DATA_NORM_NTSC,
+						 &flags);
+		} else if ((*std) & V4L2_STD_SECAM) {
+			ret = vino_set_data_norm(vcs, VINO_DATA_NORM_SECAM,
+						 &flags);
+		} else {
+			ret = -EINVAL;
+		}
+
+		if (ret) {
+			ret = -EINVAL;
+		}
+	} else {
+		ret = -EINVAL;
+	}
+
+out:
+	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+	return ret;
+}
+
+static int vino_enum_fmt_vid_cap(struct file *file, void *__fh,
+			      struct v4l2_fmtdesc *fd)
+{
+	dprintk("format index = %d\n", fd->index);
+
+	if (fd->index >= VINO_DATA_FMT_COUNT)
+		return -EINVAL;
+	dprintk("format name = %s\n", vino_data_formats[fd->index].description);
+
+	fd->pixelformat = vino_data_formats[fd->index].pixelformat;
+	strcpy(fd->description, vino_data_formats[fd->index].description);
+	return 0;
+}
+
+static int vino_try_fmt_vid_cap(struct file *file, void *__fh,
+			     struct v4l2_format *f)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	struct vino_channel_settings tempvcs;
+	unsigned long flags;
+	struct v4l2_pix_format *pf = &f->fmt.pix;
+
+	dprintk("requested: w = %d, h = %d\n",
+			pf->width, pf->height);
+
+	spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+	memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings));
+	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+	tempvcs.data_format = vino_find_data_format(pf->pixelformat);
+	if (tempvcs.data_format == VINO_DATA_FMT_NONE) {
+		tempvcs.data_format = VINO_DATA_FMT_GREY;
+		pf->pixelformat =
+			vino_data_formats[tempvcs.data_format].
+			pixelformat;
+	}
+
+	/* data format must be set before clipping/scaling */
+	vino_set_scaling(&tempvcs, pf->width, pf->height);
+
+	dprintk("data format = %s\n",
+			vino_data_formats[tempvcs.data_format].description);
+
+	pf->width = (tempvcs.clipping.right - tempvcs.clipping.left) /
+		tempvcs.decimation;
+	pf->height = (tempvcs.clipping.bottom - tempvcs.clipping.top) /
+		tempvcs.decimation;
+
+	pf->field = V4L2_FIELD_INTERLACED;
+	pf->bytesperline = tempvcs.line_size;
+	pf->sizeimage = tempvcs.line_size *
+		(tempvcs.clipping.bottom - tempvcs.clipping.top) /
+		tempvcs.decimation;
+	pf->colorspace =
+		vino_data_formats[tempvcs.data_format].colorspace;
+
+	pf->priv = 0;
+	return 0;
+}
+
+static int vino_g_fmt_vid_cap(struct file *file, void *__fh,
+			   struct v4l2_format *f)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	unsigned long flags;
+	struct v4l2_pix_format *pf = &f->fmt.pix;
+
+	spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+	pf->width = (vcs->clipping.right - vcs->clipping.left) /
+		vcs->decimation;
+	pf->height = (vcs->clipping.bottom - vcs->clipping.top) /
+		vcs->decimation;
+	pf->pixelformat =
+		vino_data_formats[vcs->data_format].pixelformat;
+
+	pf->field = V4L2_FIELD_INTERLACED;
+	pf->bytesperline = vcs->line_size;
+	pf->sizeimage = vcs->line_size *
+		(vcs->clipping.bottom - vcs->clipping.top) /
+		vcs->decimation;
+	pf->colorspace =
+		vino_data_formats[vcs->data_format].colorspace;
+
+	pf->priv = 0;
+
+	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+	return 0;
+}
+
+static int vino_s_fmt_vid_cap(struct file *file, void *__fh,
+			   struct v4l2_format *f)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	int data_format;
+	unsigned long flags;
+	struct v4l2_pix_format *pf = &f->fmt.pix;
+
+	spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+	data_format = vino_find_data_format(pf->pixelformat);
+
+	if (data_format == VINO_DATA_FMT_NONE) {
+		vcs->data_format = VINO_DATA_FMT_GREY;
+		pf->pixelformat =
+			vino_data_formats[vcs->data_format].
+			pixelformat;
+	} else {
+		vcs->data_format = data_format;
+	}
+
+	/* data format must be set before clipping/scaling */
+	vino_set_scaling(vcs, pf->width, pf->height);
+
+	dprintk("data format = %s\n",
+	       vino_data_formats[vcs->data_format].description);
+
+	pf->width = vcs->clipping.right - vcs->clipping.left;
+	pf->height = vcs->clipping.bottom - vcs->clipping.top;
+
+	pf->field = V4L2_FIELD_INTERLACED;
+	pf->bytesperline = vcs->line_size;
+	pf->sizeimage = vcs->line_size *
+		(vcs->clipping.bottom - vcs->clipping.top) /
+		vcs->decimation;
+	pf->colorspace =
+		vino_data_formats[vcs->data_format].colorspace;
+
+	pf->priv = 0;
+
+	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+	return 0;
+}
+
+static int vino_cropcap(struct file *file, void *__fh,
+			     struct v4l2_cropcap *ccap)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	const struct vino_data_norm *norm;
+	unsigned long flags;
+
+	switch (ccap->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+		norm = &vino_data_norms[vcs->data_norm];
+
+		spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+		ccap->bounds.left = 0;
+		ccap->bounds.top = 0;
+		ccap->bounds.width = norm->width;
+		ccap->bounds.height = norm->height;
+		memcpy(&ccap->defrect, &ccap->bounds,
+		       sizeof(struct v4l2_rect));
+
+		ccap->pixelaspect.numerator = 1;
+		ccap->pixelaspect.denominator = 1;
+		break;
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vino_g_crop(struct file *file, void *__fh,
+			    struct v4l2_crop *c)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	unsigned long flags;
+
+	switch (c->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+		c->c.left = vcs->clipping.left;
+		c->c.top = vcs->clipping.top;
+		c->c.width = vcs->clipping.right - vcs->clipping.left;
+		c->c.height = vcs->clipping.bottom - vcs->clipping.top;
+
+		spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+		break;
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vino_s_crop(struct file *file, void *__fh,
+			    struct v4l2_crop *c)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	unsigned long flags;
+
+	switch (c->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+		vino_set_clipping(vcs, c->c.left, c->c.top,
+				  c->c.width, c->c.height);
+
+		spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+		break;
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vino_g_parm(struct file *file, void *__fh,
+			    struct v4l2_streamparm *sp)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	unsigned long flags;
+	struct v4l2_captureparm *cp = &sp->parm.capture;
+
+	cp->capability = V4L2_CAP_TIMEPERFRAME;
+	cp->timeperframe.numerator = 1;
+
+	spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+	cp->timeperframe.denominator = vcs->fps;
+
+	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+	/* TODO: cp->readbuffers = xxx; */
+
+	return 0;
+}
+
+static int vino_s_parm(struct file *file, void *__fh,
+			    struct v4l2_streamparm *sp)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	unsigned long flags;
+	struct v4l2_captureparm *cp = &sp->parm.capture;
+
+	spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+	if ((cp->timeperframe.numerator == 0) ||
+	    (cp->timeperframe.denominator == 0)) {
+		/* reset framerate */
+		vino_set_default_framerate(vcs);
+	} else {
+		vino_set_framerate(vcs, cp->timeperframe.denominator /
+				   cp->timeperframe.numerator);
+	}
+
+	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+	return 0;
+}
+
+static int vino_reqbufs(struct file *file, void *__fh,
+			     struct v4l2_requestbuffers *rb)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+
+	if (vcs->reading)
+		return -EBUSY;
+
+	/* TODO: check queue type */
+	if (rb->memory != V4L2_MEMORY_MMAP) {
+		dprintk("type not mmap\n");
+		return -EINVAL;
+	}
+
+	dprintk("count = %d\n", rb->count);
+	if (rb->count > 0) {
+		if (vino_is_capturing(vcs)) {
+			dprintk("busy, capturing\n");
+			return -EBUSY;
+		}
+
+		if (vino_queue_has_mapped_buffers(&vcs->fb_queue)) {
+			dprintk("busy, buffers still mapped\n");
+			return -EBUSY;
+		} else {
+			vcs->streaming = 0;
+			vino_queue_free(&vcs->fb_queue);
+			vino_queue_init(&vcs->fb_queue, &rb->count);
+		}
+	} else {
+		vcs->streaming = 0;
+		vino_capture_stop(vcs);
+		vino_queue_free(&vcs->fb_queue);
+	}
+
+	return 0;
+}
+
+static void vino_v4l2_get_buffer_status(struct vino_channel_settings *vcs,
+					struct vino_framebuffer *fb,
+					struct v4l2_buffer *b)
+{
+	if (vino_queue_outgoing_contains(&vcs->fb_queue,
+					 fb->id)) {
+		b->flags &= ~V4L2_BUF_FLAG_QUEUED;
+		b->flags |= V4L2_BUF_FLAG_DONE;
+	} else if (vino_queue_incoming_contains(&vcs->fb_queue,
+				       fb->id)) {
+		b->flags &= ~V4L2_BUF_FLAG_DONE;
+		b->flags |= V4L2_BUF_FLAG_QUEUED;
+	} else {
+		b->flags &= ~(V4L2_BUF_FLAG_DONE |
+			      V4L2_BUF_FLAG_QUEUED);
+	}
+
+	b->flags &= ~(V4L2_BUF_FLAG_TIMECODE);
+
+	if (fb->map_count > 0)
+		b->flags |= V4L2_BUF_FLAG_MAPPED;
+
+	b->index = fb->id;
+	b->memory = (vcs->fb_queue.type == VINO_MEMORY_MMAP) ?
+		V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR;
+	b->m.offset = fb->offset;
+	b->bytesused = fb->data_size;
+	b->length = fb->size;
+	b->field = V4L2_FIELD_INTERLACED;
+	b->sequence = fb->frame_counter;
+	memcpy(&b->timestamp, &fb->timestamp,
+	       sizeof(struct timeval));
+	// b->input ?
+
+	dprintk("buffer %d: length = %d, bytesused = %d, offset = %d\n",
+		fb->id, fb->size, fb->data_size, fb->offset);
+}
+
+static int vino_querybuf(struct file *file, void *__fh,
+			      struct v4l2_buffer *b)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	struct vino_framebuffer *fb;
+
+	if (vcs->reading)
+		return -EBUSY;
+
+	/* TODO: check queue type */
+	if (b->index >= vino_queue_get_length(&vcs->fb_queue)) {
+		dprintk("invalid index = %d\n",
+		       b->index);
+		return -EINVAL;
+	}
+
+	fb = vino_queue_get_buffer(&vcs->fb_queue,
+				   b->index);
+	if (fb == NULL) {
+		dprintk("vino_queue_get_buffer() failed");
+		return -EINVAL;
+	}
+
+	vino_v4l2_get_buffer_status(vcs, fb, b);
+
+	return 0;
+}
+
+static int vino_qbuf(struct file *file, void *__fh,
+			  struct v4l2_buffer *b)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	struct vino_framebuffer *fb;
+	int ret;
+
+	if (vcs->reading)
+		return -EBUSY;
+
+	/* TODO: check queue type */
+	if (b->memory != V4L2_MEMORY_MMAP) {
+		dprintk("type not mmap\n");
+		return -EINVAL;
+	}
+
+	fb = vino_capture_enqueue(vcs, b->index);
+	if (fb == NULL)
+		return -EINVAL;
+
+	vino_v4l2_get_buffer_status(vcs, fb, b);
+
+	if (vcs->streaming) {
+		ret = vino_capture_next(vcs, 1);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int vino_dqbuf(struct file *file, void *__fh,
+			   struct v4l2_buffer *b)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	unsigned int nonblocking = file->f_flags & O_NONBLOCK;
+	struct vino_framebuffer *fb;
+	unsigned int incoming, outgoing;
+	int err;
+
+	if (vcs->reading)
+		return -EBUSY;
+
+	/* TODO: check queue type */
+
+	err = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
+	if (err) {
+		dprintk("vino_queue_get_incoming() failed\n");
+		return -EINVAL;
+	}
+	err = vino_queue_get_outgoing(&vcs->fb_queue, &outgoing);
+	if (err) {
+		dprintk("vino_queue_get_outgoing() failed\n");
+		return -EINVAL;
+	}
+
+	dprintk("incoming = %d, outgoing = %d\n", incoming, outgoing);
+
+	if (outgoing == 0) {
+		if (incoming == 0) {
+			dprintk("no incoming or outgoing buffers\n");
+			return -EINVAL;
+		}
+		if (nonblocking) {
+			dprintk("non-blocking I/O was selected and "
+				"there are no buffers to dequeue\n");
+			return -EAGAIN;
+		}
+
+		err = vino_wait_for_frame(vcs);
+		if (err) {
+			err = vino_wait_for_frame(vcs);
+			if (err) {
+				/* interrupted or no frames captured because of
+				 * frame skipping */
+				/* vino_capture_failed(vcs); */
+				return -EIO;
+			}
+		}
+	}
+
+	fb = vino_queue_remove(&vcs->fb_queue, &b->index);
+	if (fb == NULL) {
+		dprintk("vino_queue_remove() failed\n");
+		return -EINVAL;
+	}
+
+	err = vino_check_buffer(vcs, fb);
+
+	vino_v4l2_get_buffer_status(vcs, fb, b);
+
+	if (err)
+		return -EIO;
+
+	return 0;
+}
+
+static int vino_streamon(struct file *file, void *__fh,
+		enum v4l2_buf_type i)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	unsigned int incoming;
+	int ret;
+	if (vcs->reading)
+		return -EBUSY;
+
+	if (vcs->streaming)
+		return 0;
+
+	// TODO: check queue type
+
+	if (vino_queue_get_length(&vcs->fb_queue) < 1) {
+		dprintk("no buffers allocated\n");
+		return -EINVAL;
+	}
+
+	ret = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
+	if (ret) {
+		dprintk("vino_queue_get_incoming() failed\n");
+		return -EINVAL;
+	}
+
+	vcs->streaming = 1;
+
+	if (incoming > 0) {
+		ret = vino_capture_next(vcs, 1);
+		if (ret) {
+			vcs->streaming = 0;
+
+			dprintk("couldn't start capture\n");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int vino_streamoff(struct file *file, void *__fh,
+		enum v4l2_buf_type i)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	if (vcs->reading)
+		return -EBUSY;
+
+	if (!vcs->streaming)
+		return 0;
+
+	vcs->streaming = 0;
+	vino_capture_stop(vcs);
+
+	return 0;
+}
+
+static int vino_queryctrl(struct file *file, void *__fh,
+			       struct v4l2_queryctrl *queryctrl)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	unsigned long flags;
+	int i;
+	int err = 0;
+
+	spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+	switch (vcs->input) {
+	case VINO_INPUT_D1:
+		for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
+			if (vino_indycam_v4l2_controls[i].id ==
+			    queryctrl->id) {
+				memcpy(queryctrl,
+				       &vino_indycam_v4l2_controls[i],
+				       sizeof(struct v4l2_queryctrl));
+				queryctrl->reserved[0] = 0;
+				goto found;
+			}
+		}
+
+		err =  -EINVAL;
+		break;
+	case VINO_INPUT_COMPOSITE:
+	case VINO_INPUT_SVIDEO:
+		for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
+			if (vino_saa7191_v4l2_controls[i].id ==
+			    queryctrl->id) {
+				memcpy(queryctrl,
+				       &vino_saa7191_v4l2_controls[i],
+				       sizeof(struct v4l2_queryctrl));
+				queryctrl->reserved[0] = 0;
+				goto found;
+			}
+		}
+
+		err =  -EINVAL;
+		break;
+	default:
+		err =  -EINVAL;
+	}
+
+ found:
+	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+	return err;
+}
+
+static int vino_g_ctrl(struct file *file, void *__fh,
+			    struct v4l2_control *control)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	unsigned long flags;
+	int i;
+	int err = 0;
+
+	spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+	switch (vcs->input) {
+	case VINO_INPUT_D1: {
+		err = -EINVAL;
+		for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
+			if (vino_indycam_v4l2_controls[i].id == control->id) {
+				err = 0;
+				break;
+			}
+		}
+
+		if (err)
+			goto out;
+
+		err = camera_call(core, g_ctrl, control);
+		if (err)
+			err = -EINVAL;
+		break;
+	}
+	case VINO_INPUT_COMPOSITE:
+	case VINO_INPUT_SVIDEO: {
+		err = -EINVAL;
+		for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
+			if (vino_saa7191_v4l2_controls[i].id == control->id) {
+				err = 0;
+				break;
+			}
+		}
+
+		if (err)
+			goto out;
+
+		err = decoder_call(core, g_ctrl, control);
+		if (err)
+			err = -EINVAL;
+		break;
+	}
+	default:
+		err =  -EINVAL;
+	}
+
+out:
+	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+	return err;
+}
+
+static int vino_s_ctrl(struct file *file, void *__fh,
+			    struct v4l2_control *control)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	unsigned long flags;
+	int i;
+	int err = 0;
+
+	spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+	if (!vino_is_input_owner(vcs)) {
+		err = -EBUSY;
+		goto out;
+	}
+
+	switch (vcs->input) {
+	case VINO_INPUT_D1: {
+		err = -EINVAL;
+		for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
+			if (vino_indycam_v4l2_controls[i].id == control->id) {
+				err = 0;
+				break;
+			}
+		}
+		if (err)
+			goto out;
+		if (control->value < vino_indycam_v4l2_controls[i].minimum ||
+		    control->value > vino_indycam_v4l2_controls[i].maximum) {
+			err = -ERANGE;
+			goto out;
+		}
+		err = camera_call(core, s_ctrl, control);
+		if (err)
+			err = -EINVAL;
+		break;
+	}
+	case VINO_INPUT_COMPOSITE:
+	case VINO_INPUT_SVIDEO: {
+		err = -EINVAL;
+		for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
+			if (vino_saa7191_v4l2_controls[i].id == control->id) {
+				err = 0;
+				break;
+			}
+		}
+		if (err)
+			goto out;
+		if (control->value < vino_saa7191_v4l2_controls[i].minimum ||
+		    control->value > vino_saa7191_v4l2_controls[i].maximum) {
+			err = -ERANGE;
+			goto out;
+		}
+
+		err = decoder_call(core, s_ctrl, control);
+		if (err)
+			err = -EINVAL;
+		break;
+	}
+	default:
+		err =  -EINVAL;
+	}
+
+out:
+	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+	return err;
+}
+
+/* File operations */
+
+static int vino_open(struct file *file)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	int ret = 0;
+	dprintk("open(): channel = %c\n",
+	       (vcs->channel == VINO_CHANNEL_A) ? 'A' : 'B');
+
+	mutex_lock(&vcs->mutex);
+
+	if (vcs->users) {
+		dprintk("open(): driver busy\n");
+		ret = -EBUSY;
+		goto out;
+	}
+
+	ret = vino_acquire_input(vcs);
+	if (ret) {
+		dprintk("open(): vino_acquire_input() failed\n");
+		goto out;
+	}
+
+	vcs->users++;
+
+ out:
+	mutex_unlock(&vcs->mutex);
+
+	dprintk("open(): %s!\n", ret ? "failed" : "complete");
+
+	return ret;
+}
+
+static int vino_close(struct file *file)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	dprintk("close():\n");
+
+	mutex_lock(&vcs->mutex);
+
+	vcs->users--;
+
+	if (!vcs->users) {
+		vino_release_input(vcs);
+
+		/* stop DMA and free buffers */
+		vino_capture_stop(vcs);
+		vino_queue_free(&vcs->fb_queue);
+	}
+
+	mutex_unlock(&vcs->mutex);
+
+	return 0;
+}
+
+static void vino_vm_open(struct vm_area_struct *vma)
+{
+	struct vino_framebuffer *fb = vma->vm_private_data;
+
+	fb->map_count++;
+	dprintk("vino_vm_open(): count = %d\n", fb->map_count);
+}
+
+static void vino_vm_close(struct vm_area_struct *vma)
+{
+	struct vino_framebuffer *fb = vma->vm_private_data;
+
+	fb->map_count--;
+	dprintk("vino_vm_close(): count = %d\n", fb->map_count);
+}
+
+static const struct vm_operations_struct vino_vm_ops = {
+	.open	= vino_vm_open,
+	.close	= vino_vm_close,
+};
+
+static int vino_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+
+	unsigned long start = vma->vm_start;
+	unsigned long size = vma->vm_end - vma->vm_start;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+	struct vino_framebuffer *fb = NULL;
+	unsigned int i, length;
+	int ret = 0;
+
+	dprintk("mmap():\n");
+
+	// TODO: reject mmap if already mapped
+
+	if (mutex_lock_interruptible(&vcs->mutex))
+		return -EINTR;
+
+	if (vcs->reading) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	// TODO: check queue type
+
+	if (!(vma->vm_flags & VM_WRITE)) {
+		dprintk("mmap(): app bug: PROT_WRITE please\n");
+		ret = -EINVAL;
+		goto out;
+	}
+	if (!(vma->vm_flags & VM_SHARED)) {
+		dprintk("mmap(): app bug: MAP_SHARED please\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* find the correct buffer using offset */
+	length = vino_queue_get_length(&vcs->fb_queue);
+	if (length == 0) {
+		dprintk("mmap(): queue not initialized\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	for (i = 0; i < length; i++) {
+		fb = vino_queue_get_buffer(&vcs->fb_queue, i);
+		if (fb == NULL) {
+			dprintk("mmap(): vino_queue_get_buffer() failed\n");
+			ret = -EINVAL;
+			goto out;
+		}
+
+		if (fb->offset == offset)
+			goto found;
+	}
+
+	dprintk("mmap(): invalid offset = %lu\n", offset);
+	ret = -EINVAL;
+	goto out;
+
+found:
+	dprintk("mmap(): buffer = %d\n", i);
+
+	if (size > (fb->desc_table.page_count * PAGE_SIZE)) {
+		dprintk("mmap(): failed: size = %lu > %lu\n",
+			size, fb->desc_table.page_count * PAGE_SIZE);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	for (i = 0; i < fb->desc_table.page_count; i++) {
+		unsigned long pfn =
+			virt_to_phys((void *)fb->desc_table.virtual[i]) >>
+			PAGE_SHIFT;
+
+		if (size < PAGE_SIZE)
+			break;
+
+		// protection was: PAGE_READONLY
+		if (remap_pfn_range(vma, start, pfn, PAGE_SIZE,
+				    vma->vm_page_prot)) {
+			dprintk("mmap(): remap_pfn_range() failed\n");
+			ret = -EAGAIN;
+			goto out;
+		}
+
+		start += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+
+	fb->map_count = 1;
+
+	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+	vma->vm_flags &= ~VM_IO;
+	vma->vm_private_data = fb;
+	vma->vm_file = file;
+	vma->vm_ops = &vino_vm_ops;
+
+out:
+	mutex_unlock(&vcs->mutex);
+
+	return ret;
+}
+
+static unsigned int vino_poll(struct file *file, poll_table *pt)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	unsigned int outgoing;
+	unsigned int ret = 0;
+
+	// lock mutex (?)
+	// TODO: this has to be corrected for different read modes
+
+	dprintk("poll():\n");
+
+	if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
+		dprintk("poll(): vino_queue_get_outgoing() failed\n");
+		ret = POLLERR;
+		goto error;
+	}
+	if (outgoing > 0)
+		goto over;
+
+	poll_wait(file, &vcs->fb_queue.frame_wait_queue, pt);
+
+	if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
+		dprintk("poll(): vino_queue_get_outgoing() failed\n");
+		ret = POLLERR;
+		goto error;
+	}
+
+over:
+	dprintk("poll(): data %savailable\n",
+		(outgoing > 0) ? "" : "not ");
+
+	if (outgoing > 0)
+		ret = POLLIN | POLLRDNORM;
+
+error:
+	return ret;
+}
+
+static long vino_ioctl(struct file *file,
+		      unsigned int cmd, unsigned long arg)
+{
+	struct vino_channel_settings *vcs = video_drvdata(file);
+	long ret;
+
+	if (mutex_lock_interruptible(&vcs->mutex))
+		return -EINTR;
+
+	ret = video_ioctl2(file, cmd, arg);
+
+	mutex_unlock(&vcs->mutex);
+
+	return ret;
+}
+
+/* Initialization and cleanup */
+
+/* __initdata */
+static int vino_init_stage;
+
+const struct v4l2_ioctl_ops vino_ioctl_ops = {
+	.vidioc_enum_fmt_vid_cap     = vino_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap 	     = vino_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap  	     = vino_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	     = vino_try_fmt_vid_cap,
+	.vidioc_querycap    	     = vino_querycap,
+	.vidioc_enum_input   	     = vino_enum_input,
+	.vidioc_g_input      	     = vino_g_input,
+	.vidioc_s_input      	     = vino_s_input,
+	.vidioc_g_std 		     = vino_g_std,
+	.vidioc_s_std 		     = vino_s_std,
+	.vidioc_querystd             = vino_querystd,
+	.vidioc_cropcap      	     = vino_cropcap,
+	.vidioc_s_crop       	     = vino_s_crop,
+	.vidioc_g_crop       	     = vino_g_crop,
+	.vidioc_s_parm 		     = vino_s_parm,
+	.vidioc_g_parm 		     = vino_g_parm,
+	.vidioc_reqbufs              = vino_reqbufs,
+	.vidioc_querybuf             = vino_querybuf,
+	.vidioc_qbuf                 = vino_qbuf,
+	.vidioc_dqbuf                = vino_dqbuf,
+	.vidioc_streamon             = vino_streamon,
+	.vidioc_streamoff            = vino_streamoff,
+	.vidioc_queryctrl            = vino_queryctrl,
+	.vidioc_g_ctrl               = vino_g_ctrl,
+	.vidioc_s_ctrl               = vino_s_ctrl,
+};
+
+static const struct v4l2_file_operations vino_fops = {
+	.owner		= THIS_MODULE,
+	.open		= vino_open,
+	.release	= vino_close,
+	.unlocked_ioctl	= vino_ioctl,
+	.mmap		= vino_mmap,
+	.poll		= vino_poll,
+};
+
+static struct video_device vdev_template = {
+	.name		= "NOT SET",
+	.fops		= &vino_fops,
+	.ioctl_ops 	= &vino_ioctl_ops,
+	.tvnorms 	= V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
+};
+
+static void vino_module_cleanup(int stage)
+{
+	switch(stage) {
+	case 11:
+		video_unregister_device(vino_drvdata->b.vdev);
+		vino_drvdata->b.vdev = NULL;
+	case 10:
+		video_unregister_device(vino_drvdata->a.vdev);
+		vino_drvdata->a.vdev = NULL;
+	case 9:
+		i2c_del_adapter(&vino_i2c_adapter);
+	case 8:
+		free_irq(SGI_VINO_IRQ, NULL);
+	case 7:
+		if (vino_drvdata->b.vdev) {
+			video_device_release(vino_drvdata->b.vdev);
+			vino_drvdata->b.vdev = NULL;
+		}
+	case 6:
+		if (vino_drvdata->a.vdev) {
+			video_device_release(vino_drvdata->a.vdev);
+			vino_drvdata->a.vdev = NULL;
+		}
+	case 5:
+		/* all entries in dma_cpu dummy table have the same address */
+		dma_unmap_single(NULL,
+				 vino_drvdata->dummy_desc_table.dma_cpu[0],
+				 PAGE_SIZE, DMA_FROM_DEVICE);
+		dma_free_coherent(NULL, VINO_DUMMY_DESC_COUNT
+				  * sizeof(dma_addr_t),
+				  (void *)vino_drvdata->
+				  dummy_desc_table.dma_cpu,
+				  vino_drvdata->dummy_desc_table.dma);
+	case 4:
+		free_page(vino_drvdata->dummy_page);
+	case 3:
+		v4l2_device_unregister(&vino_drvdata->v4l2_dev);
+	case 2:
+		kfree(vino_drvdata);
+	case 1:
+		iounmap(vino);
+	case 0:
+		break;
+	default:
+		dprintk("vino_module_cleanup(): invalid cleanup stage = %d\n",
+			stage);
+	}
+}
+
+static int vino_probe(void)
+{
+	unsigned long rev_id;
+
+	if (ip22_is_fullhouse()) {
+		printk(KERN_ERR "VINO doesn't exist in IP22 Fullhouse\n");
+		return -ENODEV;
+	}
+
+	if (!(sgimc->systemid & SGIMC_SYSID_EPRESENT)) {
+		printk(KERN_ERR "VINO is not found (EISA BUS not present)\n");
+		return -ENODEV;
+	}
+
+	vino = (struct sgi_vino *)ioremap(VINO_BASE, sizeof(struct sgi_vino));
+	if (!vino) {
+		printk(KERN_ERR "VINO: ioremap() failed\n");
+		return -EIO;
+	}
+	vino_init_stage++;
+
+	if (get_dbe(rev_id, &(vino->rev_id))) {
+		printk(KERN_ERR "Failed to read VINO revision register\n");
+		vino_module_cleanup(vino_init_stage);
+		return -ENODEV;
+	}
+
+	if (VINO_ID_VALUE(rev_id) != VINO_CHIP_ID) {
+		printk(KERN_ERR "Unknown VINO chip ID (Rev/ID: 0x%02lx)\n",
+		       rev_id);
+		vino_module_cleanup(vino_init_stage);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "VINO revision %ld found\n", VINO_REV_NUM(rev_id));
+
+	return 0;
+}
+
+static int vino_init(void)
+{
+	dma_addr_t dma_dummy_address;
+	int err;
+	int i;
+
+	vino_drvdata = kzalloc(sizeof(struct vino_settings), GFP_KERNEL);
+	if (!vino_drvdata) {
+		vino_module_cleanup(vino_init_stage);
+		return -ENOMEM;
+	}
+	vino_init_stage++;
+	strlcpy(vino_drvdata->v4l2_dev.name, "vino",
+			sizeof(vino_drvdata->v4l2_dev.name));
+	err = v4l2_device_register(NULL, &vino_drvdata->v4l2_dev);
+	if (err)
+		return err;
+	vino_init_stage++;
+
+	/* create a dummy dma descriptor */
+	vino_drvdata->dummy_page = get_zeroed_page(GFP_KERNEL | GFP_DMA);
+	if (!vino_drvdata->dummy_page) {
+		vino_module_cleanup(vino_init_stage);
+		return -ENOMEM;
+	}
+	vino_init_stage++;
+
+	// TODO: use page_count in dummy_desc_table
+
+	vino_drvdata->dummy_desc_table.dma_cpu =
+		dma_alloc_coherent(NULL,
+		VINO_DUMMY_DESC_COUNT * sizeof(dma_addr_t),
+		&vino_drvdata->dummy_desc_table.dma,
+		GFP_KERNEL | GFP_DMA);
+	if (!vino_drvdata->dummy_desc_table.dma_cpu) {
+		vino_module_cleanup(vino_init_stage);
+		return -ENOMEM;
+	}
+	vino_init_stage++;
+
+	dma_dummy_address = dma_map_single(NULL,
+					   (void *)vino_drvdata->dummy_page,
+					PAGE_SIZE, DMA_FROM_DEVICE);
+	for (i = 0; i < VINO_DUMMY_DESC_COUNT; i++) {
+		vino_drvdata->dummy_desc_table.dma_cpu[i] = dma_dummy_address;
+	}
+
+	/* initialize VINO */
+
+	vino->control = 0;
+	vino->a.next_4_desc = vino_drvdata->dummy_desc_table.dma;
+	vino->b.next_4_desc = vino_drvdata->dummy_desc_table.dma;
+	udelay(VINO_DESC_FETCH_DELAY);
+
+	vino->intr_status = 0;
+
+	vino->a.fifo_thres = VINO_FIFO_THRESHOLD_DEFAULT;
+	vino->b.fifo_thres = VINO_FIFO_THRESHOLD_DEFAULT;
+
+	return 0;
+}
+
+static int vino_init_channel_settings(struct vino_channel_settings *vcs,
+				 unsigned int channel, const char *name)
+{
+	vcs->channel = channel;
+	vcs->input = VINO_INPUT_NONE;
+	vcs->alpha = 0;
+	vcs->users = 0;
+	vcs->data_format = VINO_DATA_FMT_GREY;
+	vcs->data_norm = VINO_DATA_NORM_NTSC;
+	vcs->decimation = 1;
+	vino_set_default_clipping(vcs);
+	vino_set_default_framerate(vcs);
+
+	vcs->capturing = 0;
+
+	mutex_init(&vcs->mutex);
+	spin_lock_init(&vcs->capture_lock);
+
+	mutex_init(&vcs->fb_queue.queue_mutex);
+	spin_lock_init(&vcs->fb_queue.queue_lock);
+	init_waitqueue_head(&vcs->fb_queue.frame_wait_queue);
+
+	vcs->vdev = video_device_alloc();
+	if (!vcs->vdev) {
+		vino_module_cleanup(vino_init_stage);
+		return -ENOMEM;
+	}
+	vino_init_stage++;
+
+	memcpy(vcs->vdev, &vdev_template,
+	       sizeof(struct video_device));
+	strcpy(vcs->vdev->name, name);
+	vcs->vdev->release = video_device_release;
+	vcs->vdev->v4l2_dev = &vino_drvdata->v4l2_dev;
+
+	video_set_drvdata(vcs->vdev, vcs);
+
+	return 0;
+}
+
+static int __init vino_module_init(void)
+{
+	int ret;
+
+	printk(KERN_INFO "SGI VINO driver version %s\n",
+	       VINO_MODULE_VERSION);
+
+	ret = vino_probe();
+	if (ret)
+		return ret;
+
+	ret = vino_init();
+	if (ret)
+		return ret;
+
+	/* initialize data structures */
+
+	spin_lock_init(&vino_drvdata->vino_lock);
+	spin_lock_init(&vino_drvdata->input_lock);
+
+	ret = vino_init_channel_settings(&vino_drvdata->a, VINO_CHANNEL_A,
+				    vino_vdev_name_a);
+	if (ret)
+		return ret;
+
+	ret = vino_init_channel_settings(&vino_drvdata->b, VINO_CHANNEL_B,
+				    vino_vdev_name_b);
+	if (ret)
+		return ret;
+
+	/* initialize hardware and register V4L devices */
+
+	ret = request_irq(SGI_VINO_IRQ, vino_interrupt, 0,
+		vino_driver_description, NULL);
+	if (ret) {
+		printk(KERN_ERR "VINO: requesting IRQ %02d failed\n",
+		       SGI_VINO_IRQ);
+		vino_module_cleanup(vino_init_stage);
+		return -EAGAIN;
+	}
+	vino_init_stage++;
+
+	ret = i2c_add_adapter(&vino_i2c_adapter);
+	if (ret) {
+		printk(KERN_ERR "VINO I2C bus registration failed\n");
+		vino_module_cleanup(vino_init_stage);
+		return ret;
+	}
+	i2c_set_adapdata(&vino_i2c_adapter, &vino_drvdata->v4l2_dev);
+	vino_init_stage++;
+
+	ret = video_register_device(vino_drvdata->a.vdev,
+				    VFL_TYPE_GRABBER, -1);
+	if (ret < 0) {
+		printk(KERN_ERR "VINO channel A Video4Linux-device "
+		       "registration failed\n");
+		vino_module_cleanup(vino_init_stage);
+		return -EINVAL;
+	}
+	vino_init_stage++;
+
+	ret = video_register_device(vino_drvdata->b.vdev,
+				    VFL_TYPE_GRABBER, -1);
+	if (ret < 0) {
+		printk(KERN_ERR "VINO channel B Video4Linux-device "
+		       "registration failed\n");
+		vino_module_cleanup(vino_init_stage);
+		return -EINVAL;
+	}
+	vino_init_stage++;
+
+	vino_drvdata->decoder =
+		v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter,
+			       "saa7191", 0, I2C_ADDRS(0x45));
+	vino_drvdata->camera =
+		v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter,
+			       "indycam", 0, I2C_ADDRS(0x2b));
+
+	dprintk("init complete!\n");
+
+	return 0;
+}
+
+static void __exit vino_module_exit(void)
+{
+	dprintk("exiting, stage = %d ...\n", vino_init_stage);
+	vino_module_cleanup(vino_init_stage);
+	dprintk("cleanup complete, exit!\n");
+}
+
+module_init(vino_module_init);
+module_exit(vino_module_exit);
diff --git a/drivers/media/platform/vino.h b/drivers/media/platform/vino.h
new file mode 100644
index 0000000..de2d615
--- /dev/null
+++ b/drivers/media/platform/vino.h
@@ -0,0 +1,138 @@
+/*
+ * Driver for the VINO (Video In No Out) system found in SGI Indys.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * Copyright (C) 1999 Ulf Karlsson <ulfc@bun.falkenberg.se>
+ * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ */
+
+#ifndef _VINO_H_
+#define _VINO_H_
+
+#define VINO_BASE	0x00080000	/* Vino is in the EISA address space,
+					 * but it is not an EISA bus card */
+#define VINO_PAGE_SIZE	4096
+
+struct sgi_vino_channel {
+	u32 _pad_alpha;
+	volatile u32 alpha;
+
+#define VINO_CLIP_X(x)		((x) & 0x3ff)		/* bits 0:9 */
+#define VINO_CLIP_ODD(x)	(((x) & 0x1ff) << 10)	/* bits 10:18 */
+#define VINO_CLIP_EVEN(x)	(((x) & 0x1ff) << 19)	/* bits 19:27 */
+	u32 _pad_clip_start;
+	volatile u32 clip_start;
+	u32 _pad_clip_end;
+	volatile u32 clip_end;
+
+#define VINO_FRAMERT_FULL	0xfff
+#define VINO_FRAMERT_PAL	(1<<0)			/* 0=NTSC 1=PAL */
+#define VINO_FRAMERT_RT(x)	(((x) & 0xfff) << 1)	/* bits 1:12 */
+	u32 _pad_frame_rate;
+	volatile u32 frame_rate;
+
+	u32 _pad_field_counter;
+	volatile u32 field_counter;
+	u32 _pad_line_size;
+	volatile u32 line_size;
+	u32 _pad_line_count;
+	volatile u32 line_count;
+	u32 _pad_page_index;
+	volatile u32 page_index;
+	u32 _pad_next_4_desc;
+	volatile u32 next_4_desc;
+	u32 _pad_start_desc_tbl;
+	volatile u32 start_desc_tbl;
+
+#define VINO_DESC_JUMP		(1<<30)
+#define VINO_DESC_STOP		(1<<31)
+#define VINO_DESC_VALID		(1<<32)
+	u32 _pad_desc_0;
+	volatile u32 desc_0;
+	u32 _pad_desc_1;
+	volatile u32 desc_1;
+	u32 _pad_desc_2;
+	volatile u32 desc_2;
+	u32 _pad_Bdesc_3;
+	volatile u32 desc_3;
+
+	u32 _pad_fifo_thres;
+	volatile u32 fifo_thres;
+	u32 _pad_fifo_read;
+	volatile u32 fifo_read;
+	u32 _pad_fifo_write;
+	volatile u32 fifo_write;
+};
+
+struct sgi_vino {
+#define VINO_CHIP_ID		0xb
+#define VINO_REV_NUM(x)		((x) & 0x0f)
+#define VINO_ID_VALUE(x)	(((x) & 0xf0) >> 4)
+	u32 _pad_rev_id;
+	volatile u32 rev_id;
+
+#define VINO_CTRL_LITTLE_ENDIAN		(1<<0)
+#define VINO_CTRL_A_EOF_INT		(1<<1)	/* Field transferred int */
+#define VINO_CTRL_A_FIFO_INT		(1<<2)	/* FIFO overflow int */
+#define VINO_CTRL_A_EOD_INT		(1<<3)	/* End of desc table int */
+#define VINO_CTRL_A_INT			(VINO_CTRL_A_EOF_INT | \
+					 VINO_CTRL_A_FIFO_INT | \
+					 VINO_CTRL_A_EOD_INT)
+#define VINO_CTRL_B_EOF_INT		(1<<4)	/* Field transferred int */
+#define VINO_CTRL_B_FIFO_INT		(1<<5)	/* FIFO overflow int */
+#define VINO_CTRL_B_EOD_INT		(1<<6)	/* End of desc table int */
+#define VINO_CTRL_B_INT			(VINO_CTRL_B_EOF_INT | \
+					 VINO_CTRL_B_FIFO_INT | \
+					 VINO_CTRL_B_EOD_INT)
+#define VINO_CTRL_A_DMA_ENBL		(1<<7)
+#define VINO_CTRL_A_INTERLEAVE_ENBL	(1<<8)
+#define VINO_CTRL_A_SYNC_ENBL		(1<<9)
+#define VINO_CTRL_A_SELECT		(1<<10)	/* 1=D1 0=Philips */
+#define VINO_CTRL_A_RGB			(1<<11)	/* 1=RGB 0=YUV */
+#define VINO_CTRL_A_LUMA_ONLY		(1<<12)
+#define VINO_CTRL_A_DEC_ENBL		(1<<13)	/* Decimation */
+#define VINO_CTRL_A_DEC_SCALE_MASK	0x1c000	/* bits 14:17 */
+#define VINO_CTRL_A_DEC_SCALE_SHIFT	(14)
+#define VINO_CTRL_A_DEC_HOR_ONLY	(1<<17)	/* Horizontal only */
+#define VINO_CTRL_A_DITHER		(1<<18)	/* 24 -> 8 bit dither */
+#define VINO_CTRL_B_DMA_ENBL		(1<<19)
+#define VINO_CTRL_B_INTERLEAVE_ENBL	(1<<20)
+#define VINO_CTRL_B_SYNC_ENBL		(1<<21)
+#define VINO_CTRL_B_SELECT		(1<<22)	/* 1=D1 0=Philips */
+#define VINO_CTRL_B_RGB			(1<<23)	/* 1=RGB 0=YUV */
+#define VINO_CTRL_B_LUMA_ONLY		(1<<24)
+#define VINO_CTRL_B_DEC_ENBL		(1<<25)	/* Decimation */
+#define VINO_CTRL_B_DEC_SCALE_MASK	0x1c000000	/* bits 26:28 */
+#define VINO_CTRL_B_DEC_SCALE_SHIFT	(26)
+#define VINO_CTRL_B_DEC_HOR_ONLY	(1<<29)	/* Decimation horizontal only */
+#define VINO_CTRL_B_DITHER		(1<<30)	/* ChanB 24 -> 8 bit dither */
+	u32 _pad_control;
+	volatile u32 control;
+
+#define VINO_INTSTAT_A_EOF		(1<<0)	/* Field transferred int */
+#define VINO_INTSTAT_A_FIFO		(1<<1)	/* FIFO overflow int */
+#define VINO_INTSTAT_A_EOD		(1<<2)	/* End of desc table int */
+#define VINO_INTSTAT_A			(VINO_INTSTAT_A_EOF | \
+					 VINO_INTSTAT_A_FIFO | \
+					 VINO_INTSTAT_A_EOD)
+#define VINO_INTSTAT_B_EOF		(1<<3)	/* Field transferred int */
+#define VINO_INTSTAT_B_FIFO		(1<<4)	/* FIFO overflow int */
+#define VINO_INTSTAT_B_EOD		(1<<5)	/* End of desc table int */
+#define VINO_INTSTAT_B			(VINO_INTSTAT_B_EOF | \
+					 VINO_INTSTAT_B_FIFO | \
+					 VINO_INTSTAT_B_EOD)
+	u32 _pad_intr_status;
+	volatile u32 intr_status;
+
+	u32 _pad_i2c_control;
+	volatile u32 i2c_control;
+	u32 _pad_i2c_data;
+	volatile u32 i2c_data;
+
+	struct sgi_vino_channel a;
+	struct sgi_vino_channel b;
+};
+
+#endif
diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c
new file mode 100644
index 0000000..a6351c4
--- /dev/null
+++ b/drivers/media/platform/vivi.c
@@ -0,0 +1,1409 @@
+/*
+ * Virtual Video driver - This code emulates a real video device with v4l2 api
+ *
+ * Copyright (c) 2006 by:
+ *      Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
+ *      Ted Walther <ted--a.t--enumera.com>
+ *      John Sokol <sokol--a.t--videotechnology.com>
+ *      http://v4l.videotechnology.com/
+ *
+ *      Conversion to videobuf2 by Pawel Osciak & Marek Szyprowski
+ *      Copyright (c) 2010 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the BSD Licence, GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version
+ */
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-common.h>
+
+#define VIVI_MODULE_NAME "vivi"
+
+/* Wake up at about 30 fps */
+#define WAKE_NUMERATOR 30
+#define WAKE_DENOMINATOR 1001
+#define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
+
+#define MAX_WIDTH 1920
+#define MAX_HEIGHT 1200
+
+#define VIVI_VERSION "0.8.1"
+
+MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
+MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(VIVI_VERSION);
+
+static unsigned video_nr = -1;
+module_param(video_nr, uint, 0644);
+MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect");
+
+static unsigned n_devs = 1;
+module_param(n_devs, uint, 0644);
+MODULE_PARM_DESC(n_devs, "number of video devices to create");
+
+static unsigned debug;
+module_param(debug, uint, 0644);
+MODULE_PARM_DESC(debug, "activates debug info");
+
+static unsigned int vid_limit = 16;
+module_param(vid_limit, uint, 0644);
+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
+
+/* Global font descriptor */
+static const u8 *font8x16;
+
+#define dprintk(dev, level, fmt, arg...) \
+	v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
+
+/* ------------------------------------------------------------------
+	Basic structures
+   ------------------------------------------------------------------*/
+
+struct vivi_fmt {
+	char  *name;
+	u32   fourcc;          /* v4l2 format id */
+	u8    depth;
+	bool  is_yuv;
+};
+
+static struct vivi_fmt formats[] = {
+	{
+		.name     = "4:2:2, packed, YUYV",
+		.fourcc   = V4L2_PIX_FMT_YUYV,
+		.depth    = 16,
+		.is_yuv   = true,
+	},
+	{
+		.name     = "4:2:2, packed, UYVY",
+		.fourcc   = V4L2_PIX_FMT_UYVY,
+		.depth    = 16,
+		.is_yuv   = true,
+	},
+	{
+		.name     = "4:2:2, packed, YVYU",
+		.fourcc   = V4L2_PIX_FMT_YVYU,
+		.depth    = 16,
+		.is_yuv   = true,
+	},
+	{
+		.name     = "4:2:2, packed, VYUY",
+		.fourcc   = V4L2_PIX_FMT_VYUY,
+		.depth    = 16,
+		.is_yuv   = true,
+	},
+	{
+		.name     = "RGB565 (LE)",
+		.fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
+		.depth    = 16,
+	},
+	{
+		.name     = "RGB565 (BE)",
+		.fourcc   = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
+		.depth    = 16,
+	},
+	{
+		.name     = "RGB555 (LE)",
+		.fourcc   = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
+		.depth    = 16,
+	},
+	{
+		.name     = "RGB555 (BE)",
+		.fourcc   = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
+		.depth    = 16,
+	},
+	{
+		.name     = "RGB24 (LE)",
+		.fourcc   = V4L2_PIX_FMT_RGB24, /* rgb */
+		.depth    = 24,
+	},
+	{
+		.name     = "RGB24 (BE)",
+		.fourcc   = V4L2_PIX_FMT_BGR24, /* bgr */
+		.depth    = 24,
+	},
+	{
+		.name     = "RGB32 (LE)",
+		.fourcc   = V4L2_PIX_FMT_RGB32, /* argb */
+		.depth    = 32,
+	},
+	{
+		.name     = "RGB32 (BE)",
+		.fourcc   = V4L2_PIX_FMT_BGR32, /* bgra */
+		.depth    = 32,
+	},
+};
+
+static struct vivi_fmt *get_format(struct v4l2_format *f)
+{
+	struct vivi_fmt *fmt;
+	unsigned int k;
+
+	for (k = 0; k < ARRAY_SIZE(formats); k++) {
+		fmt = &formats[k];
+		if (fmt->fourcc == f->fmt.pix.pixelformat)
+			break;
+	}
+
+	if (k == ARRAY_SIZE(formats))
+		return NULL;
+
+	return &formats[k];
+}
+
+/* buffer for one video frame */
+struct vivi_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct vb2_buffer	vb;
+	struct list_head	list;
+	struct vivi_fmt        *fmt;
+};
+
+struct vivi_dmaqueue {
+	struct list_head       active;
+
+	/* thread for generating video stream*/
+	struct task_struct         *kthread;
+	wait_queue_head_t          wq;
+	/* Counters to control fps rate */
+	int                        frame;
+	int                        ini_jiffies;
+};
+
+static LIST_HEAD(vivi_devlist);
+
+struct vivi_dev {
+	struct list_head           vivi_devlist;
+	struct v4l2_device 	   v4l2_dev;
+	struct v4l2_ctrl_handler   ctrl_handler;
+	struct video_device	   vdev;
+
+	/* controls */
+	struct v4l2_ctrl	   *brightness;
+	struct v4l2_ctrl	   *contrast;
+	struct v4l2_ctrl	   *saturation;
+	struct v4l2_ctrl	   *hue;
+	struct {
+		/* autogain/gain cluster */
+		struct v4l2_ctrl	   *autogain;
+		struct v4l2_ctrl	   *gain;
+	};
+	struct v4l2_ctrl	   *volume;
+	struct v4l2_ctrl	   *alpha;
+	struct v4l2_ctrl	   *button;
+	struct v4l2_ctrl	   *boolean;
+	struct v4l2_ctrl	   *int32;
+	struct v4l2_ctrl	   *int64;
+	struct v4l2_ctrl	   *menu;
+	struct v4l2_ctrl	   *string;
+	struct v4l2_ctrl	   *bitmask;
+	struct v4l2_ctrl	   *int_menu;
+
+	spinlock_t                 slock;
+	struct mutex		   mutex;
+
+	struct vivi_dmaqueue       vidq;
+
+	/* Several counters */
+	unsigned 		   ms;
+	unsigned long              jiffies;
+	unsigned		   button_pressed;
+
+	int			   mv_count;	/* Controls bars movement */
+
+	/* Input Number */
+	int			   input;
+
+	/* video capture */
+	struct vivi_fmt            *fmt;
+	unsigned int               width, height;
+	struct vb2_queue	   vb_vidq;
+	unsigned int		   field_count;
+
+	u8			   bars[9][3];
+	u8			   line[MAX_WIDTH * 8];
+	unsigned int		   pixelsize;
+	u8			   alpha_component;
+};
+
+/* ------------------------------------------------------------------
+	DMA and thread functions
+   ------------------------------------------------------------------*/
+
+/* Bars and Colors should match positions */
+
+enum colors {
+	WHITE,
+	AMBER,
+	CYAN,
+	GREEN,
+	MAGENTA,
+	RED,
+	BLUE,
+	BLACK,
+	TEXT_BLACK,
+};
+
+/* R   G   B */
+#define COLOR_WHITE	{204, 204, 204}
+#define COLOR_AMBER	{208, 208,   0}
+#define COLOR_CYAN	{  0, 206, 206}
+#define	COLOR_GREEN	{  0, 239,   0}
+#define COLOR_MAGENTA	{239,   0, 239}
+#define COLOR_RED	{205,   0,   0}
+#define COLOR_BLUE	{  0,   0, 255}
+#define COLOR_BLACK	{  0,   0,   0}
+
+struct bar_std {
+	u8 bar[9][3];
+};
+
+/* Maximum number of bars are 10 - otherwise, the input print code
+   should be modified */
+static struct bar_std bars[] = {
+	{	/* Standard ITU-R color bar sequence */
+		{ COLOR_WHITE, COLOR_AMBER, COLOR_CYAN, COLOR_GREEN,
+		  COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK }
+	}, {
+		{ COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE,
+		  COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, COLOR_AMBER, COLOR_BLACK }
+	}, {
+		{ COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE,
+		  COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, COLOR_CYAN, COLOR_BLACK }
+	}, {
+		{ COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE,
+		  COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, COLOR_GREEN, COLOR_BLACK }
+	},
+};
+
+#define NUM_INPUTS ARRAY_SIZE(bars)
+
+#define TO_Y(r, g, b) \
+	(((16829 * r + 33039 * g + 6416 * b  + 32768) >> 16) + 16)
+/* RGB to  V(Cr) Color transform */
+#define TO_V(r, g, b) \
+	(((28784 * r - 24103 * g - 4681 * b  + 32768) >> 16) + 128)
+/* RGB to  U(Cb) Color transform */
+#define TO_U(r, g, b) \
+	(((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
+
+/* precalculate color bar values to speed up rendering */
+static void precalculate_bars(struct vivi_dev *dev)
+{
+	u8 r, g, b;
+	int k, is_yuv;
+
+	for (k = 0; k < 9; k++) {
+		r = bars[dev->input].bar[k][0];
+		g = bars[dev->input].bar[k][1];
+		b = bars[dev->input].bar[k][2];
+		is_yuv = dev->fmt->is_yuv;
+
+		switch (dev->fmt->fourcc) {
+		case V4L2_PIX_FMT_RGB565:
+		case V4L2_PIX_FMT_RGB565X:
+			r >>= 3;
+			g >>= 2;
+			b >>= 3;
+			break;
+		case V4L2_PIX_FMT_RGB555:
+		case V4L2_PIX_FMT_RGB555X:
+			r >>= 3;
+			g >>= 3;
+			b >>= 3;
+			break;
+		case V4L2_PIX_FMT_YUYV:
+		case V4L2_PIX_FMT_UYVY:
+		case V4L2_PIX_FMT_YVYU:
+		case V4L2_PIX_FMT_VYUY:
+		case V4L2_PIX_FMT_RGB24:
+		case V4L2_PIX_FMT_BGR24:
+		case V4L2_PIX_FMT_RGB32:
+		case V4L2_PIX_FMT_BGR32:
+			break;
+		}
+
+		if (is_yuv) {
+			dev->bars[k][0] = TO_Y(r, g, b);	/* Luma */
+			dev->bars[k][1] = TO_U(r, g, b);	/* Cb */
+			dev->bars[k][2] = TO_V(r, g, b);	/* Cr */
+		} else {
+			dev->bars[k][0] = r;
+			dev->bars[k][1] = g;
+			dev->bars[k][2] = b;
+		}
+	}
+}
+
+#define TSTAMP_MIN_Y	24
+#define TSTAMP_MAX_Y	(TSTAMP_MIN_Y + 15)
+#define TSTAMP_INPUT_X	10
+#define TSTAMP_MIN_X	(54 + TSTAMP_INPUT_X)
+
+/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
+static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos, bool odd)
+{
+	u8 r_y, g_u, b_v;
+	u8 alpha = dev->alpha_component;
+	int color;
+	u8 *p;
+
+	r_y = dev->bars[colorpos][0]; /* R or precalculated Y */
+	g_u = dev->bars[colorpos][1]; /* G or precalculated U */
+	b_v = dev->bars[colorpos][2]; /* B or precalculated V */
+
+	for (color = 0; color < dev->pixelsize; color++) {
+		p = buf + color;
+
+		switch (dev->fmt->fourcc) {
+		case V4L2_PIX_FMT_YUYV:
+			switch (color) {
+			case 0:
+				*p = r_y;
+				break;
+			case 1:
+				*p = odd ? b_v : g_u;
+				break;
+			}
+			break;
+		case V4L2_PIX_FMT_UYVY:
+			switch (color) {
+			case 0:
+				*p = odd ? b_v : g_u;
+				break;
+			case 1:
+				*p = r_y;
+				break;
+			}
+			break;
+		case V4L2_PIX_FMT_YVYU:
+			switch (color) {
+			case 0:
+				*p = r_y;
+				break;
+			case 1:
+				*p = odd ? g_u : b_v;
+				break;
+			}
+			break;
+		case V4L2_PIX_FMT_VYUY:
+			switch (color) {
+			case 0:
+				*p = odd ? g_u : b_v;
+				break;
+			case 1:
+				*p = r_y;
+				break;
+			}
+			break;
+		case V4L2_PIX_FMT_RGB565:
+			switch (color) {
+			case 0:
+				*p = (g_u << 5) | b_v;
+				break;
+			case 1:
+				*p = (r_y << 3) | (g_u >> 3);
+				break;
+			}
+			break;
+		case V4L2_PIX_FMT_RGB565X:
+			switch (color) {
+			case 0:
+				*p = (r_y << 3) | (g_u >> 3);
+				break;
+			case 1:
+				*p = (g_u << 5) | b_v;
+				break;
+			}
+			break;
+		case V4L2_PIX_FMT_RGB555:
+			switch (color) {
+			case 0:
+				*p = (g_u << 5) | b_v;
+				break;
+			case 1:
+				*p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
+				break;
+			}
+			break;
+		case V4L2_PIX_FMT_RGB555X:
+			switch (color) {
+			case 0:
+				*p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
+				break;
+			case 1:
+				*p = (g_u << 5) | b_v;
+				break;
+			}
+			break;
+		case V4L2_PIX_FMT_RGB24:
+			switch (color) {
+			case 0:
+				*p = r_y;
+				break;
+			case 1:
+				*p = g_u;
+				break;
+			case 2:
+				*p = b_v;
+				break;
+			}
+			break;
+		case V4L2_PIX_FMT_BGR24:
+			switch (color) {
+			case 0:
+				*p = b_v;
+				break;
+			case 1:
+				*p = g_u;
+				break;
+			case 2:
+				*p = r_y;
+				break;
+			}
+			break;
+		case V4L2_PIX_FMT_RGB32:
+			switch (color) {
+			case 0:
+				*p = alpha;
+				break;
+			case 1:
+				*p = r_y;
+				break;
+			case 2:
+				*p = g_u;
+				break;
+			case 3:
+				*p = b_v;
+				break;
+			}
+			break;
+		case V4L2_PIX_FMT_BGR32:
+			switch (color) {
+			case 0:
+				*p = b_v;
+				break;
+			case 1:
+				*p = g_u;
+				break;
+			case 2:
+				*p = r_y;
+				break;
+			case 3:
+				*p = alpha;
+				break;
+			}
+			break;
+		}
+	}
+}
+
+static void precalculate_line(struct vivi_dev *dev)
+{
+	int w;
+
+	for (w = 0; w < dev->width * 2; w++) {
+		int colorpos = w / (dev->width / 8) % 8;
+
+		gen_twopix(dev, dev->line + w * dev->pixelsize, colorpos, w & 1);
+	}
+}
+
+static void gen_text(struct vivi_dev *dev, char *basep,
+					int y, int x, char *text)
+{
+	int line;
+
+	/* Checks if it is possible to show string */
+	if (y + 16 >= dev->height || x + strlen(text) * 8 >= dev->width)
+		return;
+
+	/* Print stream time */
+	for (line = y; line < y + 16; line++) {
+		int j = 0;
+		char *pos = basep + line * dev->width * dev->pixelsize + x * dev->pixelsize;
+		char *s;
+
+		for (s = text; *s; s++) {
+			u8 chr = font8x16[*s * 16 + line - y];
+			int i;
+
+			for (i = 0; i < 7; i++, j++) {
+				/* Draw white font on black background */
+				if (chr & (1 << (7 - i)))
+					gen_twopix(dev, pos + j * dev->pixelsize, WHITE, (x+y) & 1);
+				else
+					gen_twopix(dev, pos + j * dev->pixelsize, TEXT_BLACK, (x+y) & 1);
+			}
+		}
+	}
+}
+
+static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
+{
+	int wmax = dev->width;
+	int hmax = dev->height;
+	struct timeval ts;
+	void *vbuf = vb2_plane_vaddr(&buf->vb, 0);
+	unsigned ms;
+	char str[100];
+	int h, line = 1;
+	s32 gain;
+
+	if (!vbuf)
+		return;
+
+	for (h = 0; h < hmax; h++)
+		memcpy(vbuf + h * wmax * dev->pixelsize,
+		       dev->line + (dev->mv_count % wmax) * dev->pixelsize,
+		       wmax * dev->pixelsize);
+
+	/* Updates stream time */
+
+	dev->ms += jiffies_to_msecs(jiffies - dev->jiffies);
+	dev->jiffies = jiffies;
+	ms = dev->ms;
+	snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d ",
+			(ms / (60 * 60 * 1000)) % 24,
+			(ms / (60 * 1000)) % 60,
+			(ms / 1000) % 60,
+			ms % 1000);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
+	snprintf(str, sizeof(str), " %dx%d, input %d ",
+			dev->width, dev->height, dev->input);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
+
+	gain = v4l2_ctrl_g_ctrl(dev->gain);
+	mutex_lock(dev->ctrl_handler.lock);
+	snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
+			dev->brightness->cur.val,
+			dev->contrast->cur.val,
+			dev->saturation->cur.val,
+			dev->hue->cur.val);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
+	snprintf(str, sizeof(str), " autogain %d, gain %3d, volume %3d, alpha 0x%02x ",
+			dev->autogain->cur.val, gain, dev->volume->cur.val,
+			dev->alpha->cur.val);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
+	snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
+			dev->int32->cur.val,
+			dev->int64->cur.val64,
+			dev->bitmask->cur.val);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
+	snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
+			dev->boolean->cur.val,
+			dev->menu->qmenu[dev->menu->cur.val],
+			dev->string->cur.string);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
+	snprintf(str, sizeof(str), " integer_menu %lld, value %d ",
+			dev->int_menu->qmenu_int[dev->int_menu->cur.val],
+			dev->int_menu->cur.val);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
+	mutex_unlock(dev->ctrl_handler.lock);
+	if (dev->button_pressed) {
+		dev->button_pressed--;
+		snprintf(str, sizeof(str), " button pressed!");
+		gen_text(dev, vbuf, line++ * 16, 16, str);
+	}
+
+	dev->mv_count += 2;
+
+	buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
+	dev->field_count++;
+	buf->vb.v4l2_buf.sequence = dev->field_count >> 1;
+	do_gettimeofday(&ts);
+	buf->vb.v4l2_buf.timestamp = ts;
+}
+
+static void vivi_thread_tick(struct vivi_dev *dev)
+{
+	struct vivi_dmaqueue *dma_q = &dev->vidq;
+	struct vivi_buffer *buf;
+	unsigned long flags = 0;
+
+	dprintk(dev, 1, "Thread tick\n");
+
+	spin_lock_irqsave(&dev->slock, flags);
+	if (list_empty(&dma_q->active)) {
+		dprintk(dev, 1, "No active queue to serve\n");
+		spin_unlock_irqrestore(&dev->slock, flags);
+		return;
+	}
+
+	buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
+	list_del(&buf->list);
+	spin_unlock_irqrestore(&dev->slock, flags);
+
+	do_gettimeofday(&buf->vb.v4l2_buf.timestamp);
+
+	/* Fill buffer */
+	vivi_fillbuff(dev, buf);
+	dprintk(dev, 1, "filled buffer %p\n", buf);
+
+	vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+	dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
+}
+
+#define frames_to_ms(frames)					\
+	((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
+
+static void vivi_sleep(struct vivi_dev *dev)
+{
+	struct vivi_dmaqueue *dma_q = &dev->vidq;
+	int timeout;
+	DECLARE_WAITQUEUE(wait, current);
+
+	dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
+		(unsigned long)dma_q);
+
+	add_wait_queue(&dma_q->wq, &wait);
+	if (kthread_should_stop())
+		goto stop_task;
+
+	/* Calculate time to wake up */
+	timeout = msecs_to_jiffies(frames_to_ms(1));
+
+	vivi_thread_tick(dev);
+
+	schedule_timeout_interruptible(timeout);
+
+stop_task:
+	remove_wait_queue(&dma_q->wq, &wait);
+	try_to_freeze();
+}
+
+static int vivi_thread(void *data)
+{
+	struct vivi_dev *dev = data;
+
+	dprintk(dev, 1, "thread started\n");
+
+	set_freezable();
+
+	for (;;) {
+		vivi_sleep(dev);
+
+		if (kthread_should_stop())
+			break;
+	}
+	dprintk(dev, 1, "thread: exit\n");
+	return 0;
+}
+
+static int vivi_start_generating(struct vivi_dev *dev)
+{
+	struct vivi_dmaqueue *dma_q = &dev->vidq;
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	/* Resets frame counters */
+	dev->ms = 0;
+	dev->mv_count = 0;
+	dev->jiffies = jiffies;
+
+	dma_q->frame = 0;
+	dma_q->ini_jiffies = jiffies;
+	dma_q->kthread = kthread_run(vivi_thread, dev, dev->v4l2_dev.name);
+
+	if (IS_ERR(dma_q->kthread)) {
+		v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+		return PTR_ERR(dma_q->kthread);
+	}
+	/* Wakes thread */
+	wake_up_interruptible(&dma_q->wq);
+
+	dprintk(dev, 1, "returning from %s\n", __func__);
+	return 0;
+}
+
+static void vivi_stop_generating(struct vivi_dev *dev)
+{
+	struct vivi_dmaqueue *dma_q = &dev->vidq;
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	/* shutdown control thread */
+	if (dma_q->kthread) {
+		kthread_stop(dma_q->kthread);
+		dma_q->kthread = NULL;
+	}
+
+	/*
+	 * Typical driver might need to wait here until dma engine stops.
+	 * In this case we can abort imiedetly, so it's just a noop.
+	 */
+
+	/* Release all active buffers */
+	while (!list_empty(&dma_q->active)) {
+		struct vivi_buffer *buf;
+		buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
+		list_del(&buf->list);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+		dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
+	}
+}
+/* ------------------------------------------------------------------
+	Videobuf operations
+   ------------------------------------------------------------------*/
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+				unsigned int *nbuffers, unsigned int *nplanes,
+				unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct vivi_dev *dev = vb2_get_drv_priv(vq);
+	unsigned long size;
+
+	if (fmt)
+		size = fmt->fmt.pix.sizeimage;
+	else
+		size = dev->width * dev->height * dev->pixelsize;
+
+	if (size == 0)
+		return -EINVAL;
+
+	if (0 == *nbuffers)
+		*nbuffers = 32;
+
+	while (size * *nbuffers > vid_limit * 1024 * 1024)
+		(*nbuffers)--;
+
+	*nplanes = 1;
+
+	sizes[0] = size;
+
+	/*
+	 * videobuf2-vmalloc allocator is context-less so no need to set
+	 * alloc_ctxs array.
+	 */
+
+	dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__,
+		*nbuffers, size);
+
+	return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+	struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
+	unsigned long size;
+
+	dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field);
+
+	BUG_ON(NULL == dev->fmt);
+
+	/*
+	 * Theses properties only change when queue is idle, see s_fmt.
+	 * The below checks should not be performed here, on each
+	 * buffer_prepare (i.e. on each qbuf). Most of the code in this function
+	 * should thus be moved to buffer_init and s_fmt.
+	 */
+	if (dev->width  < 48 || dev->width  > MAX_WIDTH ||
+	    dev->height < 32 || dev->height > MAX_HEIGHT)
+		return -EINVAL;
+
+	size = dev->width * dev->height * dev->pixelsize;
+	if (vb2_plane_size(vb, 0) < size) {
+		dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n",
+				__func__, vb2_plane_size(vb, 0), size);
+		return -EINVAL;
+	}
+
+	vb2_set_plane_payload(&buf->vb, 0, size);
+
+	buf->fmt = dev->fmt;
+
+	precalculate_bars(dev);
+	precalculate_line(dev);
+
+	return 0;
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+	struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
+	struct vivi_dmaqueue *vidq = &dev->vidq;
+	unsigned long flags = 0;
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	spin_lock_irqsave(&dev->slock, flags);
+	list_add_tail(&buf->list, &vidq->active);
+	spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct vivi_dev *dev = vb2_get_drv_priv(vq);
+	dprintk(dev, 1, "%s\n", __func__);
+	return vivi_start_generating(dev);
+}
+
+/* abort streaming and wait for last buffer */
+static int stop_streaming(struct vb2_queue *vq)
+{
+	struct vivi_dev *dev = vb2_get_drv_priv(vq);
+	dprintk(dev, 1, "%s\n", __func__);
+	vivi_stop_generating(dev);
+	return 0;
+}
+
+static void vivi_lock(struct vb2_queue *vq)
+{
+	struct vivi_dev *dev = vb2_get_drv_priv(vq);
+	mutex_lock(&dev->mutex);
+}
+
+static void vivi_unlock(struct vb2_queue *vq)
+{
+	struct vivi_dev *dev = vb2_get_drv_priv(vq);
+	mutex_unlock(&dev->mutex);
+}
+
+
+static struct vb2_ops vivi_video_qops = {
+	.queue_setup		= queue_setup,
+	.buf_prepare		= buffer_prepare,
+	.buf_queue		= buffer_queue,
+	.start_streaming	= start_streaming,
+	.stop_streaming		= stop_streaming,
+	.wait_prepare		= vivi_unlock,
+	.wait_finish		= vivi_lock,
+};
+
+/* ------------------------------------------------------------------
+	IOCTL vidioc handling
+   ------------------------------------------------------------------*/
+static int vidioc_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *cap)
+{
+	struct vivi_dev *dev = video_drvdata(file);
+
+	strcpy(cap->driver, "vivi");
+	strcpy(cap->card, "vivi");
+	strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
+	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+			    V4L2_CAP_READWRITE;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	struct vivi_fmt *fmt;
+
+	if (f->index >= ARRAY_SIZE(formats))
+		return -EINVAL;
+
+	fmt = &formats[f->index];
+
+	strlcpy(f->description, fmt->name, sizeof(f->description));
+	f->pixelformat = fmt->fourcc;
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivi_dev *dev = video_drvdata(file);
+
+	f->fmt.pix.width        = dev->width;
+	f->fmt.pix.height       = dev->height;
+	f->fmt.pix.field        = V4L2_FIELD_INTERLACED;
+	f->fmt.pix.pixelformat  = dev->fmt->fourcc;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * dev->fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+	if (dev->fmt->is_yuv)
+		f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	else
+		f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct vivi_dev *dev = video_drvdata(file);
+	struct vivi_fmt *fmt;
+
+	fmt = get_format(f);
+	if (!fmt) {
+		dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n",
+			f->fmt.pix.pixelformat);
+		f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+		fmt = get_format(f);
+	}
+
+	f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+	v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2,
+			      &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0);
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+	if (fmt->is_yuv)
+		f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	else
+		f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+	f->fmt.pix.priv = 0;
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivi_dev *dev = video_drvdata(file);
+	struct vb2_queue *q = &dev->vb_vidq;
+
+	int ret = vidioc_try_fmt_vid_cap(file, priv, f);
+	if (ret < 0)
+		return ret;
+
+	if (vb2_is_busy(q)) {
+		dprintk(dev, 1, "%s device busy\n", __func__);
+		return -EBUSY;
+	}
+
+	dev->fmt = get_format(f);
+	dev->pixelsize = dev->fmt->depth / 8;
+	dev->width = f->fmt.pix.width;
+	dev->height = f->fmt.pix.height;
+
+	return 0;
+}
+
+static int vidioc_enum_framesizes(struct file *file, void *fh,
+					 struct v4l2_frmsizeenum *fsize)
+{
+	static const struct v4l2_frmsize_stepwise sizes = {
+		48, MAX_WIDTH, 4,
+		32, MAX_HEIGHT, 1
+	};
+	int i;
+
+	if (fsize->index)
+		return -EINVAL;
+	for (i = 0; i < ARRAY_SIZE(formats); i++)
+		if (formats[i].fourcc == fsize->pixel_format)
+			break;
+	if (i == ARRAY_SIZE(formats))
+		return -EINVAL;
+	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+	fsize->stepwise = sizes;
+	return 0;
+}
+
+/* only one input in this sample driver */
+static int vidioc_enum_input(struct file *file, void *priv,
+				struct v4l2_input *inp)
+{
+	if (inp->index >= NUM_INPUTS)
+		return -EINVAL;
+
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+	sprintf(inp->name, "Camera %u", inp->index);
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct vivi_dev *dev = video_drvdata(file);
+
+	*i = dev->input;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct vivi_dev *dev = video_drvdata(file);
+
+	if (i >= NUM_INPUTS)
+		return -EINVAL;
+
+	if (i == dev->input)
+		return 0;
+
+	dev->input = i;
+	precalculate_bars(dev);
+	precalculate_line(dev);
+	return 0;
+}
+
+/* --- controls ---------------------------------------------- */
+
+static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
+
+	if (ctrl == dev->autogain)
+		dev->gain->val = jiffies & 0xff;
+	return 0;
+}
+
+static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
+
+	switch (ctrl->id) {
+	case V4L2_CID_ALPHA_COMPONENT:
+		dev->alpha_component = ctrl->val;
+		break;
+	default:
+		if (ctrl == dev->button)
+			dev->button_pressed = 30;
+		break;
+	}
+	return 0;
+}
+
+/* ------------------------------------------------------------------
+	File operations for the device
+   ------------------------------------------------------------------*/
+
+static const struct v4l2_ctrl_ops vivi_ctrl_ops = {
+	.g_volatile_ctrl = vivi_g_volatile_ctrl,
+	.s_ctrl = vivi_s_ctrl,
+};
+
+#define VIVI_CID_CUSTOM_BASE	(V4L2_CID_USER_BASE | 0xf000)
+
+static const struct v4l2_ctrl_config vivi_ctrl_button = {
+	.ops = &vivi_ctrl_ops,
+	.id = VIVI_CID_CUSTOM_BASE + 0,
+	.name = "Button",
+	.type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_boolean = {
+	.ops = &vivi_ctrl_ops,
+	.id = VIVI_CID_CUSTOM_BASE + 1,
+	.name = "Boolean",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.min = 0,
+	.max = 1,
+	.step = 1,
+	.def = 1,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_int32 = {
+	.ops = &vivi_ctrl_ops,
+	.id = VIVI_CID_CUSTOM_BASE + 2,
+	.name = "Integer 32 Bits",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 0x80000000,
+	.max = 0x7fffffff,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_int64 = {
+	.ops = &vivi_ctrl_ops,
+	.id = VIVI_CID_CUSTOM_BASE + 3,
+	.name = "Integer 64 Bits",
+	.type = V4L2_CTRL_TYPE_INTEGER64,
+};
+
+static const char * const vivi_ctrl_menu_strings[] = {
+	"Menu Item 0 (Skipped)",
+	"Menu Item 1",
+	"Menu Item 2 (Skipped)",
+	"Menu Item 3",
+	"Menu Item 4",
+	"Menu Item 5 (Skipped)",
+	NULL,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_menu = {
+	.ops = &vivi_ctrl_ops,
+	.id = VIVI_CID_CUSTOM_BASE + 4,
+	.name = "Menu",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.min = 1,
+	.max = 4,
+	.def = 3,
+	.menu_skip_mask = 0x04,
+	.qmenu = vivi_ctrl_menu_strings,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_string = {
+	.ops = &vivi_ctrl_ops,
+	.id = VIVI_CID_CUSTOM_BASE + 5,
+	.name = "String",
+	.type = V4L2_CTRL_TYPE_STRING,
+	.min = 2,
+	.max = 4,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_bitmask = {
+	.ops = &vivi_ctrl_ops,
+	.id = VIVI_CID_CUSTOM_BASE + 6,
+	.name = "Bitmask",
+	.type = V4L2_CTRL_TYPE_BITMASK,
+	.def = 0x80002000,
+	.min = 0,
+	.max = 0x80402010,
+	.step = 0,
+};
+
+static const s64 vivi_ctrl_int_menu_values[] = {
+	1, 1, 2, 3, 5, 8, 13, 21, 42,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_int_menu = {
+	.ops = &vivi_ctrl_ops,
+	.id = VIVI_CID_CUSTOM_BASE + 7,
+	.name = "Integer menu",
+	.type = V4L2_CTRL_TYPE_INTEGER_MENU,
+	.min = 1,
+	.max = 8,
+	.def = 4,
+	.menu_skip_mask = 0x02,
+	.qmenu_int = vivi_ctrl_int_menu_values,
+};
+
+static const struct v4l2_file_operations vivi_fops = {
+	.owner		= THIS_MODULE,
+	.open           = v4l2_fh_open,
+	.release        = vb2_fop_release,
+	.read           = vb2_fop_read,
+	.poll		= vb2_fop_poll,
+	.unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
+	.mmap           = vb2_fop_mmap,
+};
+
+static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
+	.vidioc_querycap      = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
+	.vidioc_enum_framesizes   = vidioc_enum_framesizes,
+	.vidioc_reqbufs       = vb2_ioctl_reqbufs,
+	.vidioc_create_bufs   = vb2_ioctl_create_bufs,
+	.vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
+	.vidioc_querybuf      = vb2_ioctl_querybuf,
+	.vidioc_qbuf          = vb2_ioctl_qbuf,
+	.vidioc_dqbuf         = vb2_ioctl_dqbuf,
+	.vidioc_enum_input    = vidioc_enum_input,
+	.vidioc_g_input       = vidioc_g_input,
+	.vidioc_s_input       = vidioc_s_input,
+	.vidioc_streamon      = vb2_ioctl_streamon,
+	.vidioc_streamoff     = vb2_ioctl_streamoff,
+	.vidioc_log_status    = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static struct video_device vivi_template = {
+	.name		= "vivi",
+	.fops           = &vivi_fops,
+	.ioctl_ops 	= &vivi_ioctl_ops,
+	.release	= video_device_release_empty,
+};
+
+/* -----------------------------------------------------------------
+	Initialization and module stuff
+   ------------------------------------------------------------------*/
+
+static int vivi_release(void)
+{
+	struct vivi_dev *dev;
+	struct list_head *list;
+
+	while (!list_empty(&vivi_devlist)) {
+		list = vivi_devlist.next;
+		list_del(list);
+		dev = list_entry(list, struct vivi_dev, vivi_devlist);
+
+		v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+			video_device_node_name(&dev->vdev));
+		video_unregister_device(&dev->vdev);
+		v4l2_device_unregister(&dev->v4l2_dev);
+		v4l2_ctrl_handler_free(&dev->ctrl_handler);
+		kfree(dev);
+	}
+
+	return 0;
+}
+
+static int __init vivi_create_instance(int inst)
+{
+	struct vivi_dev *dev;
+	struct video_device *vfd;
+	struct v4l2_ctrl_handler *hdl;
+	struct vb2_queue *q;
+	int ret;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
+			"%s-%03d", VIVI_MODULE_NAME, inst);
+	ret = v4l2_device_register(NULL, &dev->v4l2_dev);
+	if (ret)
+		goto free_dev;
+
+	dev->fmt = &formats[0];
+	dev->width = 640;
+	dev->height = 480;
+	dev->pixelsize = dev->fmt->depth / 8;
+	hdl = &dev->ctrl_handler;
+	v4l2_ctrl_handler_init(hdl, 11);
+	dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+			V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
+	dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
+	dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 255, 1, 16);
+	dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 255, 1, 127);
+	dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+			V4L2_CID_HUE, -128, 127, 1, 0);
+	dev->autogain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+	dev->gain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+			V4L2_CID_GAIN, 0, 255, 1, 100);
+	dev->alpha = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+			V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
+	dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
+	dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
+	dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);
+	dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL);
+	dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL);
+	dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
+	dev->bitmask = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_bitmask, NULL);
+	dev->int_menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int_menu, NULL);
+	if (hdl->error) {
+		ret = hdl->error;
+		goto unreg_dev;
+	}
+	v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true);
+	dev->v4l2_dev.ctrl_handler = hdl;
+
+	/* initialize locks */
+	spin_lock_init(&dev->slock);
+
+	/* initialize queue */
+	q = &dev->vb_vidq;
+	memset(q, 0, sizeof(dev->vb_vidq));
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+	q->drv_priv = dev;
+	q->buf_struct_size = sizeof(struct vivi_buffer);
+	q->ops = &vivi_video_qops;
+	q->mem_ops = &vb2_vmalloc_memops;
+
+	vb2_queue_init(q);
+
+	mutex_init(&dev->mutex);
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&dev->vidq.active);
+	init_waitqueue_head(&dev->vidq.wq);
+
+	vfd = &dev->vdev;
+	*vfd = vivi_template;
+	vfd->debug = debug;
+	vfd->v4l2_dev = &dev->v4l2_dev;
+	vfd->queue = q;
+	set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+
+	/*
+	 * Provide a mutex to v4l2 core. It will be used to protect
+	 * all fops and v4l2 ioctls.
+	 */
+	vfd->lock = &dev->mutex;
+	video_set_drvdata(vfd, dev);
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
+	if (ret < 0)
+		goto unreg_dev;
+
+	/* Now that everything is fine, let's add it to device list */
+	list_add_tail(&dev->vivi_devlist, &vivi_devlist);
+
+	v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
+		  video_device_node_name(vfd));
+	return 0;
+
+unreg_dev:
+	v4l2_ctrl_handler_free(hdl);
+	v4l2_device_unregister(&dev->v4l2_dev);
+free_dev:
+	kfree(dev);
+	return ret;
+}
+
+/* This routine allocates from 1 to n_devs virtual drivers.
+
+   The real maximum number of virtual drivers will depend on how many drivers
+   will succeed. This is limited to the maximum number of devices that
+   videodev supports, which is equal to VIDEO_NUM_DEVICES.
+ */
+static int __init vivi_init(void)
+{
+	const struct font_desc *font = find_font("VGA8x16");
+	int ret = 0, i;
+
+	if (font == NULL) {
+		printk(KERN_ERR "vivi: could not find font\n");
+		return -ENODEV;
+	}
+	font8x16 = font->data;
+
+	if (n_devs <= 0)
+		n_devs = 1;
+
+	for (i = 0; i < n_devs; i++) {
+		ret = vivi_create_instance(i);
+		if (ret) {
+			/* If some instantiations succeeded, keep driver */
+			if (i)
+				ret = 0;
+			break;
+		}
+	}
+
+	if (ret < 0) {
+		printk(KERN_ERR "vivi: error %d while loading driver\n", ret);
+		return ret;
+	}
+
+	printk(KERN_INFO "Video Technology Magazine Virtual Video "
+			"Capture Board ver %s successfully loaded.\n",
+			VIVI_VERSION);
+
+	/* n_devs will reflect the actual number of allocated devices */
+	n_devs = i;
+
+	return ret;
+}
+
+static void __exit vivi_exit(void)
+{
+	vivi_release();
+}
+
+module_init(vivi_init);
+module_exit(vivi_exit);
diff --git a/drivers/media/radio/radio-shark.c b/drivers/media/radio/radio-shark.c
index d0b6bb5..72ded29 100644
--- a/drivers/media/radio/radio-shark.c
+++ b/drivers/media/radio/radio-shark.c
@@ -35,6 +35,11 @@
 #include <media/v4l2-device.h>
 #include <sound/tea575x-tuner.h>
 
+#if defined(CONFIG_LEDS_CLASS) || \
+    (defined(CONFIG_LEDS_CLASS_MODULE) && defined(CONFIG_RADIO_SHARK_MODULE))
+#define SHARK_USE_LEDS 1
+#endif
+
 /*
  * Version Information
  */
@@ -56,44 +61,18 @@ MODULE_LICENSE("GPL");
 
 enum { BLUE_LED, BLUE_PULSE_LED, RED_LED, NO_LEDS };
 
-static void shark_led_set_blue(struct led_classdev *led_cdev,
-			       enum led_brightness value);
-static void shark_led_set_blue_pulse(struct led_classdev *led_cdev,
-				     enum led_brightness value);
-static void shark_led_set_red(struct led_classdev *led_cdev,
-			      enum led_brightness value);
-
-static const struct led_classdev shark_led_templates[NO_LEDS] = {
-	[BLUE_LED] = {
-		.name		= "%s:blue:",
-		.brightness	= LED_OFF,
-		.max_brightness = 127,
-		.brightness_set = shark_led_set_blue,
-	},
-	[BLUE_PULSE_LED] = {
-		.name		= "%s:blue-pulse:",
-		.brightness	= LED_OFF,
-		.max_brightness = 255,
-		.brightness_set = shark_led_set_blue_pulse,
-	},
-	[RED_LED] = {
-		.name		= "%s:red:",
-		.brightness	= LED_OFF,
-		.max_brightness = 1,
-		.brightness_set = shark_led_set_red,
-	},
-};
-
 struct shark_device {
 	struct usb_device *usbdev;
 	struct v4l2_device v4l2_dev;
 	struct snd_tea575x tea;
 
+#ifdef SHARK_USE_LEDS
 	struct work_struct led_work;
 	struct led_classdev leds[NO_LEDS];
 	char led_names[NO_LEDS][32];
 	atomic_t brightness[NO_LEDS];
 	unsigned long brightness_new;
+#endif
 
 	u8 *transfer_buffer;
 	u32 last_val;
@@ -175,20 +154,13 @@ static struct snd_tea575x_ops shark_tea_ops = {
 	.read_val  = shark_read_val,
 };
 
+#ifdef SHARK_USE_LEDS
 static void shark_led_work(struct work_struct *work)
 {
 	struct shark_device *shark =
 		container_of(work, struct shark_device, led_work);
 	int i, res, brightness, actual_len;
 
-	/*
-	 * We use the v4l2_dev lock and registered bit to ensure the device
-	 * does not get unplugged and unreffed while we're running.
-	 */
-	mutex_lock(&shark->tea.mutex);
-	if (!video_is_registered(&shark->tea.vd))
-		goto leave;
-
 	for (i = 0; i < 3; i++) {
 		if (!test_and_clear_bit(i, &shark->brightness_new))
 			continue;
@@ -208,8 +180,6 @@ static void shark_led_work(struct work_struct *work)
 			v4l2_err(&shark->v4l2_dev, "set LED %s error: %d\n",
 				 shark->led_names[i], res);
 	}
-leave:
-	mutex_unlock(&shark->tea.mutex);
 }
 
 static void shark_led_set_blue(struct led_classdev *led_cdev,
@@ -245,19 +215,78 @@ static void shark_led_set_red(struct led_classdev *led_cdev,
 	schedule_work(&shark->led_work);
 }
 
+static const struct led_classdev shark_led_templates[NO_LEDS] = {
+	[BLUE_LED] = {
+		.name		= "%s:blue:",
+		.brightness	= LED_OFF,
+		.max_brightness = 127,
+		.brightness_set = shark_led_set_blue,
+	},
+	[BLUE_PULSE_LED] = {
+		.name		= "%s:blue-pulse:",
+		.brightness	= LED_OFF,
+		.max_brightness = 255,
+		.brightness_set = shark_led_set_blue_pulse,
+	},
+	[RED_LED] = {
+		.name		= "%s:red:",
+		.brightness	= LED_OFF,
+		.max_brightness = 1,
+		.brightness_set = shark_led_set_red,
+	},
+};
+
+static int shark_register_leds(struct shark_device *shark, struct device *dev)
+{
+	int i, retval;
+
+	INIT_WORK(&shark->led_work, shark_led_work);
+	for (i = 0; i < NO_LEDS; i++) {
+		shark->leds[i] = shark_led_templates[i];
+		snprintf(shark->led_names[i], sizeof(shark->led_names[0]),
+			 shark->leds[i].name, shark->v4l2_dev.name);
+		shark->leds[i].name = shark->led_names[i];
+		retval = led_classdev_register(dev, &shark->leds[i]);
+		if (retval) {
+			v4l2_err(&shark->v4l2_dev,
+				 "couldn't register led: %s\n",
+				 shark->led_names[i]);
+			return retval;
+		}
+	}
+	return 0;
+}
+
+static void shark_unregister_leds(struct shark_device *shark)
+{
+	int i;
+
+	for (i = 0; i < NO_LEDS; i++)
+		led_classdev_unregister(&shark->leds[i]);
+
+	cancel_work_sync(&shark->led_work);
+}
+#else
+static int shark_register_leds(struct shark_device *shark, struct device *dev)
+{
+	v4l2_warn(&shark->v4l2_dev,
+		  "CONFIG_LED_CLASS not enabled, LED support disabled\n");
+	return 0;
+}
+static inline void shark_unregister_leds(struct shark_device *shark) { }
+#endif
+
 static void usb_shark_disconnect(struct usb_interface *intf)
 {
 	struct v4l2_device *v4l2_dev = usb_get_intfdata(intf);
 	struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev);
-	int i;
 
 	mutex_lock(&shark->tea.mutex);
 	v4l2_device_disconnect(&shark->v4l2_dev);
 	snd_tea575x_exit(&shark->tea);
 	mutex_unlock(&shark->tea.mutex);
 
-	for (i = 0; i < NO_LEDS; i++)
-		led_classdev_unregister(&shark->leds[i]);
+	shark_unregister_leds(shark);
 
 	v4l2_device_put(&shark->v4l2_dev);
 }
@@ -266,7 +295,6 @@ static void usb_shark_release(struct v4l2_device *v4l2_dev)
 {
 	struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev);
 
-	cancel_work_sync(&shark->led_work);
 	v4l2_device_unregister(&shark->v4l2_dev);
 	kfree(shark->transfer_buffer);
 	kfree(shark);
@@ -276,7 +304,7 @@ static int usb_shark_probe(struct usb_interface *intf,
 			   const struct usb_device_id *id)
 {
 	struct shark_device *shark;
-	int i, retval = -ENOMEM;
+	int retval = -ENOMEM;
 
 	shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL);
 	if (!shark)
@@ -286,17 +314,13 @@ static int usb_shark_probe(struct usb_interface *intf,
 	if (!shark->transfer_buffer)
 		goto err_alloc_buffer;
 
-	/*
-	 * Work around a bug in usbhid/hid-core.c, where it leaves a dangling
-	 * pointer in intfdata causing v4l2-device.c to not set it. Which
-	 * results in usb_shark_disconnect() referencing the dangling pointer
-	 *
-	 * REMOVE (as soon as the above bug is fixed, patch submitted)
-	 */
-	usb_set_intfdata(intf, NULL);
+	v4l2_device_set_name(&shark->v4l2_dev, DRV_NAME, &shark_instance);
+
+	retval = shark_register_leds(shark, &intf->dev);
+	if (retval)
+		goto err_reg_leds;
 
 	shark->v4l2_dev.release = usb_shark_release;
-	v4l2_device_set_name(&shark->v4l2_dev, DRV_NAME, &shark_instance);
 	retval = v4l2_device_register(&intf->dev, &shark->v4l2_dev);
 	if (retval) {
 		v4l2_err(&shark->v4l2_dev, "couldn't register v4l2_device\n");
@@ -320,32 +344,13 @@ static int usb_shark_probe(struct usb_interface *intf,
 		goto err_init_tea;
 	}
 
-	INIT_WORK(&shark->led_work, shark_led_work);
-	for (i = 0; i < NO_LEDS; i++) {
-		shark->leds[i] = shark_led_templates[i];
-		snprintf(shark->led_names[i], sizeof(shark->led_names[0]),
-			 shark->leds[i].name, shark->v4l2_dev.name);
-		shark->leds[i].name = shark->led_names[i];
-		/*
-		 * We don't fail the probe if we fail to register the leds,
-		 * because once we've called snd_tea575x_init, the /dev/radio0
-		 * node may be opened from userspace holding a reference to us!
-		 *
-		 * Note we cannot register the leds first instead as
-		 * shark_led_work depends on the v4l2 mutex and registered bit.
-		 */
-		retval = led_classdev_register(&intf->dev, &shark->leds[i]);
-		if (retval)
-			v4l2_err(&shark->v4l2_dev,
-				 "couldn't register led: %s\n",
-				 shark->led_names[i]);
-	}
-
 	return 0;
 
 err_init_tea:
 	v4l2_device_unregister(&shark->v4l2_dev);
 err_reg_dev:
+	shark_unregister_leds(shark);
+err_reg_leds:
 	kfree(shark->transfer_buffer);
 err_alloc_buffer:
 	kfree(shark);
diff --git a/drivers/media/radio/radio-shark2.c b/drivers/media/radio/radio-shark2.c
index b9575de..7c730a0 100644
--- a/drivers/media/radio/radio-shark2.c
+++ b/drivers/media/radio/radio-shark2.c
@@ -35,6 +35,11 @@
 #include <media/v4l2-device.h>
 #include "radio-tea5777.h"
 
+#if defined(CONFIG_LEDS_CLASS) || \
+    (defined(CONFIG_LEDS_CLASS_MODULE) && defined(CONFIG_RADIO_SHARK2_MODULE))
+#define SHARK_USE_LEDS 1
+#endif
+
 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 MODULE_DESCRIPTION("Griffin radioSHARK2, USB radio receiver driver");
 MODULE_LICENSE("GPL");
@@ -43,7 +48,6 @@ static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-
 #define SHARK_IN_EP		0x83
 #define SHARK_OUT_EP		0x05
 
@@ -54,36 +58,18 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 enum { BLUE_LED, RED_LED, NO_LEDS };
 
-static void shark_led_set_blue(struct led_classdev *led_cdev,
-			       enum led_brightness value);
-static void shark_led_set_red(struct led_classdev *led_cdev,
-			      enum led_brightness value);
-
-static const struct led_classdev shark_led_templates[NO_LEDS] = {
-	[BLUE_LED] = {
-		.name		= "%s:blue:",
-		.brightness	= LED_OFF,
-		.max_brightness = 127,
-		.brightness_set = shark_led_set_blue,
-	},
-	[RED_LED] = {
-		.name		= "%s:red:",
-		.brightness	= LED_OFF,
-		.max_brightness = 1,
-		.brightness_set = shark_led_set_red,
-	},
-};
-
 struct shark_device {
 	struct usb_device *usbdev;
 	struct v4l2_device v4l2_dev;
 	struct radio_tea5777 tea;
 
+#ifdef SHARK_USE_LEDS
 	struct work_struct led_work;
 	struct led_classdev leds[NO_LEDS];
 	char led_names[NO_LEDS][32];
 	atomic_t brightness[NO_LEDS];
 	unsigned long brightness_new;
+#endif
 
 	u8 *transfer_buffer;
 };
@@ -100,12 +86,8 @@ static int shark_write_reg(struct radio_tea5777 *tea, u64 reg)
 	for (i = 0; i < 6; i++)
 		shark->transfer_buffer[i + 1] = (reg >> (40 - i * 8)) & 0xff;
 
-	v4l2_dbg(1, debug, tea->v4l2_dev,
-		 "shark2-write: %02x %02x %02x %02x %02x %02x %02x\n",
-		 shark->transfer_buffer[0], shark->transfer_buffer[1],
-		 shark->transfer_buffer[2], shark->transfer_buffer[3],
-		 shark->transfer_buffer[4], shark->transfer_buffer[5],
-		 shark->transfer_buffer[6]);
+	v4l2_dbg(1, debug, tea->v4l2_dev, "shark2-write: %*ph\n",
+		 7, shark->transfer_buffer);
 
 	res = usb_interrupt_msg(shark->usbdev,
 				usb_sndintpipe(shark->usbdev, SHARK_OUT_EP),
@@ -148,9 +130,8 @@ static int shark_read_reg(struct radio_tea5777 *tea, u32 *reg_ret)
 	for (i = 0; i < 3; i++)
 		reg |= shark->transfer_buffer[i] << (16 - i * 8);
 
-	v4l2_dbg(1, debug, tea->v4l2_dev, "shark2-read: %02x %02x %02x\n",
-		 shark->transfer_buffer[0], shark->transfer_buffer[1],
-		 shark->transfer_buffer[2]);
+	v4l2_dbg(1, debug, tea->v4l2_dev, "shark2-read: %*ph\n",
+		 3, shark->transfer_buffer);
 
 	*reg_ret = reg;
 	return 0;
@@ -161,18 +142,12 @@ static struct radio_tea5777_ops shark_tea_ops = {
 	.read_reg  = shark_read_reg,
 };
 
+#ifdef SHARK_USE_LEDS
 static void shark_led_work(struct work_struct *work)
 {
 	struct shark_device *shark =
 		container_of(work, struct shark_device, led_work);
 	int i, res, brightness, actual_len;
-	/*
-	 * We use the v4l2_dev lock and registered bit to ensure the device
-	 * does not get unplugged and unreffed while we're running.
-	 */
-	mutex_lock(&shark->tea.mutex);
-	if (!video_is_registered(&shark->tea.vd))
-		goto leave;
 
 	for (i = 0; i < 2; i++) {
 		if (!test_and_clear_bit(i, &shark->brightness_new))
@@ -191,8 +166,6 @@ static void shark_led_work(struct work_struct *work)
 			v4l2_err(&shark->v4l2_dev, "set LED %s error: %d\n",
 				 shark->led_names[i], res);
 	}
-leave:
-	mutex_unlock(&shark->tea.mutex);
 }
 
 static void shark_led_set_blue(struct led_classdev *led_cdev,
@@ -217,19 +190,72 @@ static void shark_led_set_red(struct led_classdev *led_cdev,
 	schedule_work(&shark->led_work);
 }
 
+static const struct led_classdev shark_led_templates[NO_LEDS] = {
+	[BLUE_LED] = {
+		.name		= "%s:blue:",
+		.brightness	= LED_OFF,
+		.max_brightness = 127,
+		.brightness_set = shark_led_set_blue,
+	},
+	[RED_LED] = {
+		.name		= "%s:red:",
+		.brightness	= LED_OFF,
+		.max_brightness = 1,
+		.brightness_set = shark_led_set_red,
+	},
+};
+
+static int shark_register_leds(struct shark_device *shark, struct device *dev)
+{
+	int i, retval;
+
+	INIT_WORK(&shark->led_work, shark_led_work);
+	for (i = 0; i < NO_LEDS; i++) {
+		shark->leds[i] = shark_led_templates[i];
+		snprintf(shark->led_names[i], sizeof(shark->led_names[0]),
+			 shark->leds[i].name, shark->v4l2_dev.name);
+		shark->leds[i].name = shark->led_names[i];
+		retval = led_classdev_register(dev, &shark->leds[i]);
+		if (retval) {
+			v4l2_err(&shark->v4l2_dev,
+				 "couldn't register led: %s\n",
+				 shark->led_names[i]);
+			return retval;
+		}
+	}
+	return 0;
+}
+
+static void shark_unregister_leds(struct shark_device *shark)
+{
+	int i;
+
+	for (i = 0; i < NO_LEDS; i++)
+		led_classdev_unregister(&shark->leds[i]);
+
+	cancel_work_sync(&shark->led_work);
+}
+#else
+static int shark_register_leds(struct shark_device *shark, struct device *dev)
+{
+	v4l2_warn(&shark->v4l2_dev,
+		  "CONFIG_LED_CLASS not enabled, LED support disabled\n");
+	return 0;
+}
+static inline void shark_unregister_leds(struct shark_device *shark) { }
+#endif
+
 static void usb_shark_disconnect(struct usb_interface *intf)
 {
 	struct v4l2_device *v4l2_dev = usb_get_intfdata(intf);
 	struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev);
-	int i;
 
 	mutex_lock(&shark->tea.mutex);
 	v4l2_device_disconnect(&shark->v4l2_dev);
 	radio_tea5777_exit(&shark->tea);
 	mutex_unlock(&shark->tea.mutex);
 
-	for (i = 0; i < NO_LEDS; i++)
-		led_classdev_unregister(&shark->leds[i]);
+	shark_unregister_leds(shark);
 
 	v4l2_device_put(&shark->v4l2_dev);
 }
@@ -238,7 +264,6 @@ static void usb_shark_release(struct v4l2_device *v4l2_dev)
 {
 	struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev);
 
-	cancel_work_sync(&shark->led_work);
 	v4l2_device_unregister(&shark->v4l2_dev);
 	kfree(shark->transfer_buffer);
 	kfree(shark);
@@ -248,7 +273,7 @@ static int usb_shark_probe(struct usb_interface *intf,
 			   const struct usb_device_id *id)
 {
 	struct shark_device *shark;
-	int i, retval = -ENOMEM;
+	int retval = -ENOMEM;
 
 	shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL);
 	if (!shark)
@@ -258,17 +283,13 @@ static int usb_shark_probe(struct usb_interface *intf,
 	if (!shark->transfer_buffer)
 		goto err_alloc_buffer;
 
-	/*
-	 * Work around a bug in usbhid/hid-core.c, where it leaves a dangling
-	 * pointer in intfdata causing v4l2-device.c to not set it. Which
-	 * results in usb_shark_disconnect() referencing the dangling pointer
-	 *
-	 * REMOVE (as soon as the above bug is fixed, patch submitted)
-	 */
-	usb_set_intfdata(intf, NULL);
+	v4l2_device_set_name(&shark->v4l2_dev, DRV_NAME, &shark_instance);
+
+	retval = shark_register_leds(shark, &intf->dev);
+	if (retval)
+		goto err_reg_leds;
 
 	shark->v4l2_dev.release = usb_shark_release;
-	v4l2_device_set_name(&shark->v4l2_dev, DRV_NAME, &shark_instance);
 	retval = v4l2_device_register(&intf->dev, &shark->v4l2_dev);
 	if (retval) {
 		v4l2_err(&shark->v4l2_dev, "couldn't register v4l2_device\n");
@@ -292,32 +313,13 @@ static int usb_shark_probe(struct usb_interface *intf,
 		goto err_init_tea;
 	}
 
-	INIT_WORK(&shark->led_work, shark_led_work);
-	for (i = 0; i < NO_LEDS; i++) {
-		shark->leds[i] = shark_led_templates[i];
-		snprintf(shark->led_names[i], sizeof(shark->led_names[0]),
-			 shark->leds[i].name, shark->v4l2_dev.name);
-		shark->leds[i].name = shark->led_names[i];
-		/*
-		 * We don't fail the probe if we fail to register the leds,
-		 * because once we've called radio_tea5777_init, the /dev/radio0
-		 * node may be opened from userspace holding a reference to us!
-		 *
-		 * Note we cannot register the leds first instead as
-		 * shark_led_work depends on the v4l2 mutex and registered bit.
-		 */
-		retval = led_classdev_register(&intf->dev, &shark->leds[i]);
-		if (retval)
-			v4l2_err(&shark->v4l2_dev,
-				 "couldn't register led: %s\n",
-				 shark->led_names[i]);
-	}
-
 	return 0;
 
 err_init_tea:
 	v4l2_device_unregister(&shark->v4l2_dev);
 err_reg_dev:
+	shark_unregister_leds(shark);
+err_reg_leds:
 	kfree(shark->transfer_buffer);
 err_alloc_buffer:
 	kfree(shark);
diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c
index c54210c..5f366d1 100644
--- a/drivers/media/radio/radio-si4713.c
+++ b/drivers/media/radio/radio-si4713.c
@@ -268,7 +268,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
 		goto exit;
 	}
 
-	rsdev = kzalloc(sizeof *rsdev, GFP_KERNEL);
+	rsdev = devm_kzalloc(&pdev->dev, sizeof(*rsdev), GFP_KERNEL);
 	if (!rsdev) {
 		dev_err(&pdev->dev, "Failed to alloc video device.\n");
 		rval = -ENOMEM;
@@ -278,7 +278,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
 	rval = v4l2_device_register(&pdev->dev, &rsdev->v4l2_dev);
 	if (rval) {
 		dev_err(&pdev->dev, "Failed to register v4l2 device.\n");
-		goto free_rsdev;
+		goto exit;
 	}
 
 	adapter = i2c_get_adapter(pdata->i2c_bus);
@@ -322,8 +322,6 @@ put_adapter:
 	i2c_put_adapter(adapter);
 unregister_v4l2_dev:
 	v4l2_device_unregister(&rsdev->v4l2_dev);
-free_rsdev:
-	kfree(rsdev);
 exit:
 	return rval;
 }
@@ -342,7 +340,6 @@ static int __exit radio_si4713_pdriver_remove(struct platform_device *pdev)
 	video_unregister_device(rsdev->radio_dev);
 	i2c_put_adapter(client->adapter);
 	v4l2_device_unregister(&rsdev->v4l2_dev);
-	kfree(rsdev);
 
 	return 0;
 }
diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index 7052adc..09fc560 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -157,7 +157,7 @@ static int __devinit timbradio_probe(struct platform_device *pdev)
 		goto err;
 	}
 
-	tr = kzalloc(sizeof(*tr), GFP_KERNEL);
+	tr = devm_kzalloc(&pdev->dev, sizeof(*tr), GFP_KERNEL);
 	if (!tr) {
 		err = -ENOMEM;
 		goto err;
@@ -177,7 +177,7 @@ static int __devinit timbradio_probe(struct platform_device *pdev)
 	strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name));
 	err = v4l2_device_register(NULL, &tr->v4l2_dev);
 	if (err)
-		goto err_v4l2_dev;
+		goto err;
 
 	tr->video_dev.v4l2_dev = &tr->v4l2_dev;
 
@@ -195,8 +195,6 @@ static int __devinit timbradio_probe(struct platform_device *pdev)
 err_video_req:
 	video_device_release_empty(&tr->video_dev);
 	v4l2_device_unregister(&tr->v4l2_dev);
-err_v4l2_dev:
-	kfree(tr);
 err:
 	dev_err(&pdev->dev, "Failed to register: %d\n", err);
 
@@ -212,8 +210,6 @@ static int __devexit timbradio_remove(struct platform_device *pdev)
 
 	v4l2_device_unregister(&tr->v4l2_dev);
 
-	kfree(tr);
-
 	return 0;
 }
 
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
index e8428f5..a22ad1c 100644
--- a/drivers/media/radio/radio-wl1273.c
+++ b/drivers/media/radio/radio-wl1273.c
@@ -1983,9 +1983,6 @@ static int wl1273_fm_radio_remove(struct platform_device *pdev)
 	v4l2_ctrl_handler_free(&radio->ctrl_handler);
 	video_unregister_device(&radio->videodev);
 	v4l2_device_unregister(&radio->v4l2dev);
-	kfree(radio->buffer);
-	kfree(radio->write_buf);
-	kfree(radio);
 
 	return 0;
 }
@@ -2005,7 +2002,7 @@ static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
 		goto pdata_err;
 	}
 
-	radio = kzalloc(sizeof(*radio), GFP_KERNEL);
+	radio = devm_kzalloc(&pdev->dev, sizeof(*radio), GFP_KERNEL);
 	if (!radio) {
 		r = -ENOMEM;
 		goto pdata_err;
@@ -2013,11 +2010,11 @@ static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
 
 	/* RDS buffer allocation */
 	radio->buf_size = rds_buf * RDS_BLOCK_SIZE;
-	radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
+	radio->buffer = devm_kzalloc(&pdev->dev, radio->buf_size, GFP_KERNEL);
 	if (!radio->buffer) {
 		pr_err("Cannot allocate memory for RDS buffer.\n");
 		r = -ENOMEM;
-		goto err_kmalloc;
+		goto pdata_err;
 	}
 
 	radio->core = *core;
@@ -2043,7 +2040,7 @@ static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
 		if (r) {
 			dev_err(radio->dev, WL1273_FM_DRIVER_NAME
 				": Cannot get platform data\n");
-			goto err_resources;
+			goto pdata_err;
 		}
 
 		dev_dbg(radio->dev, "irq: %d\n", radio->core->client->irq);
@@ -2061,13 +2058,13 @@ static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
 		dev_err(radio->dev, WL1273_FM_DRIVER_NAME ": Core WL1273 IRQ"
 			" not configured");
 		r = -EINVAL;
-		goto err_resources;
+		goto pdata_err;
 	}
 
 	init_completion(&radio->busy);
 	init_waitqueue_head(&radio->read_queue);
 
-	radio->write_buf = kmalloc(256, GFP_KERNEL);
+	radio->write_buf = devm_kzalloc(&pdev->dev, 256, GFP_KERNEL);
 	if (!radio->write_buf) {
 		r = -ENOMEM;
 		goto write_buf_err;
@@ -2080,7 +2077,7 @@ static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
 	r = v4l2_device_register(&pdev->dev, &radio->v4l2dev);
 	if (r) {
 		dev_err(&pdev->dev, "Cannot register v4l2_device.\n");
-		goto device_register_err;
+		goto write_buf_err;
 	}
 
 	/* V4L2 configuration */
@@ -2135,16 +2132,10 @@ static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
 handler_init_err:
 	v4l2_ctrl_handler_free(&radio->ctrl_handler);
 	v4l2_device_unregister(&radio->v4l2dev);
-device_register_err:
-	kfree(radio->write_buf);
 write_buf_err:
 	free_irq(radio->core->client->irq, radio);
 err_request_irq:
 	radio->core->pdata->free_resources();
-err_resources:
-	kfree(radio->buffer);
-err_kmalloc:
-	kfree(radio);
 pdata_err:
 	return r;
 }
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index 9e38132..9bb65e1 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -151,6 +151,7 @@ static const struct v4l2_frequency_band bands[] = {
 		.index = 0,
 		.capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
 			    V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
+			    V4L2_TUNER_CAP_FREQ_BANDS |
 			    V4L2_TUNER_CAP_HWSEEK_BOUNDED |
 			    V4L2_TUNER_CAP_HWSEEK_WRAP,
 		.rangelow   =  87500 * 16,
@@ -162,6 +163,7 @@ static const struct v4l2_frequency_band bands[] = {
 		.index = 1,
 		.capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
 			    V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
+			    V4L2_TUNER_CAP_FREQ_BANDS |
 			    V4L2_TUNER_CAP_HWSEEK_BOUNDED |
 			    V4L2_TUNER_CAP_HWSEEK_WRAP,
 		.rangelow   =  76000 * 16,
@@ -173,6 +175,7 @@ static const struct v4l2_frequency_band bands[] = {
 		.index = 2,
 		.capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
 			    V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
+			    V4L2_TUNER_CAP_FREQ_BANDS |
 			    V4L2_TUNER_CAP_HWSEEK_BOUNDED |
 			    V4L2_TUNER_CAP_HWSEEK_WRAP,
 		.rangelow   =  76000 * 16,
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c
index 643a6ff..f867f04 100644
--- a/drivers/media/radio/si470x/radio-si470x-i2c.c
+++ b/drivers/media/radio/si470x/radio-si470x-i2c.c
@@ -225,8 +225,9 @@ int si470x_vidioc_querycap(struct file *file, void *priv,
 {
 	strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
 	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
-	capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
-		V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+	capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE |
+		V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
+	capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS;
 
 	return 0;
 }
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index 146be42..be076f7 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -531,7 +531,7 @@ int si470x_vidioc_querycap(struct file *file, void *priv,
 	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
 	usb_make_path(radio->usbdev, capability->bus_info,
 			sizeof(capability->bus_info));
-	capability->device_caps = V4L2_CAP_HW_FREQ_SEEK |
+	capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE |
 		V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
 	capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
index 49a11ec..db2248e 100644
--- a/drivers/media/radio/wl128x/fmdrv_v4l2.c
+++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c
@@ -56,23 +56,29 @@ static ssize_t fm_v4l2_fops_read(struct file *file, char __user * buf,
 		return -EIO;
 	}
 
-	/* Turn on RDS mode , if it is disabled */
+	if (mutex_lock_interruptible(&fmdev->mutex))
+		return -ERESTARTSYS;
+
+	/* Turn on RDS mode if it is disabled */
 	ret = fm_rx_get_rds_mode(fmdev, &rds_mode);
 	if (ret < 0) {
 		fmerr("Unable to read current rds mode\n");
-		return ret;
+		goto read_unlock;
 	}
 
 	if (rds_mode == FM_RDS_DISABLE) {
 		ret = fmc_set_rds_mode(fmdev, FM_RDS_ENABLE);
 		if (ret < 0) {
 			fmerr("Failed to enable rds mode\n");
-			return ret;
+			goto read_unlock;
 		}
 	}
 
 	/* Copy RDS data from internal buffer to user buffer */
-	return fmc_transfer_rds_from_internal_buff(fmdev, file, buf, count);
+	ret = fmc_transfer_rds_from_internal_buff(fmdev, file, buf, count);
+read_unlock:
+	mutex_unlock(&fmdev->mutex);
+	return ret;
 }
 
 /* Write TX RDS data */
@@ -91,8 +97,11 @@ static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf,
 		return -EFAULT;
 
 	fmdev = video_drvdata(file);
+	if (mutex_lock_interruptible(&fmdev->mutex))
+		return -ERESTARTSYS;
 	fm_tx_set_radio_text(fmdev, rds.text, rds.text_type);
 	fm_tx_set_af(fmdev, rds.af_freq);
+	mutex_unlock(&fmdev->mutex);
 
 	return sizeof(rds);
 }
@@ -103,7 +112,9 @@ static u32 fm_v4l2_fops_poll(struct file *file, struct poll_table_struct *pts)
 	struct fmdev *fmdev;
 
 	fmdev = video_drvdata(file);
+	mutex_lock(&fmdev->mutex);
 	ret = fmc_is_rds_data_available(fmdev, file, pts);
+	mutex_unlock(&fmdev->mutex);
 	if (ret < 0)
 		return POLLIN | POLLRDNORM;
 
@@ -127,10 +138,12 @@ static int fm_v4l2_fops_open(struct file *file)
 
 	fmdev = video_drvdata(file);
 
+	if (mutex_lock_interruptible(&fmdev->mutex))
+		return -ERESTARTSYS;
 	ret = fmc_prepare(fmdev);
 	if (ret < 0) {
 		fmerr("Unable to prepare FM CORE\n");
-		return ret;
+		goto open_unlock;
 	}
 
 	fmdbg("Load FM RX firmware..\n");
@@ -138,10 +151,12 @@ static int fm_v4l2_fops_open(struct file *file)
 	ret = fmc_set_mode(fmdev, FM_MODE_RX);
 	if (ret < 0) {
 		fmerr("Unable to load FM RX firmware\n");
-		return ret;
+		goto open_unlock;
 	}
 	radio_disconnected = 1;
 
+open_unlock:
+	mutex_unlock(&fmdev->mutex);
 	return ret;
 }
 
@@ -156,19 +171,22 @@ static int fm_v4l2_fops_release(struct file *file)
 		return 0;
 	}
 
+	mutex_lock(&fmdev->mutex);
 	ret = fmc_set_mode(fmdev, FM_MODE_OFF);
 	if (ret < 0) {
 		fmerr("Unable to turn off the chip\n");
-		return ret;
+		goto release_unlock;
 	}
 
 	ret = fmc_release(fmdev);
 	if (ret < 0) {
 		fmerr("FM CORE release failed\n");
-		return ret;
+		goto release_unlock;
 	}
 	radio_disconnected = 0;
 
+release_unlock:
+	mutex_unlock(&fmdev->mutex);
 	return ret;
 }
 
@@ -520,10 +538,6 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
 	video_set_drvdata(gradio_dev, fmdev);
 
 	gradio_dev->lock = &fmdev->mutex;
-	/* Locking in file operations other than ioctl should be done
-	   by the driver, not the V4L2 core.
-	   This driver needs auditing so that this flag can be removed. */
-	set_bit(V4L2_FL_LOCK_ALL_FOPS, &gradio_dev->flags);
 
 	/* Register with V4L2 subsystem as RADIO device */
 	if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) {
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 5180390..02ce43c 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -261,15 +261,43 @@ config IR_WINBOND_CIR
 
 config IR_IGUANA
 	tristate "IguanaWorks USB IR Transceiver"
+	depends on USB_ARCH_HAS_HCD
 	depends on RC_CORE
 	select USB
 	---help---
-	   Say Y here if you want to use the IgaunaWorks USB IR Transceiver.
-	   Both infrared receive and send are supported.
+	   Say Y here if you want to use the IguanaWorks USB IR Transceiver.
+	   Both infrared receive and send are supported. If you want to
+	   change the ID or the pin config, use the user space driver from
+	   IguanaWorks.
+
+	   Only firmware 0x0205 and later is supported.
 
 	   To compile this driver as a module, choose M here: the module will
 	   be called iguanair.
 
+config IR_TTUSBIR
+	tristate "TechnoTrend USB IR Receiver"
+	depends on RC_CORE
+	select USB
+	select NEW_LEDS
+	select LEDS_CLASS
+	---help---
+	   Say Y here if you want to use the TechnoTrend USB IR Receiver. The
+	   driver can control the led.
+
+	   To compile this driver as a module, choose M here: the module will
+	   be called ttusbir.
+
+config IR_RX51
+	tristate "Nokia N900 IR transmitter diode"
+	depends on MACH_NOKIA_RX51 && OMAP_DM_TIMER
+	---help---
+	   Say Y or M here if you want to enable support for the IR
+	   transmitter diode built in the Nokia N900 (RX51) device.
+
+	   The driver uses omap DM timers for gereating the carrier
+	   wave and pulses.
+
 config RC_LOOPBACK
 	tristate "Remote Control Loopback Driver"
 	depends on RC_CORE
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index f871d19..56bacf0 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -23,8 +23,10 @@ obj-$(CONFIG_IR_FINTEK) += fintek-cir.o
 obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
 obj-$(CONFIG_IR_ENE) += ene_ir.o
 obj-$(CONFIG_IR_REDRAT3) += redrat3.o
+obj-$(CONFIG_IR_RX51) += ir-rx51.o
 obj-$(CONFIG_IR_STREAMZAP) += streamzap.o
 obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o
 obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o
 obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o
 obj-$(CONFIG_IR_IGUANA) += iguanair.o
+obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 8fa72e2..08aede5 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -331,13 +331,9 @@ static void ati_remote_dump(struct device *dev, unsigned char *data,
 		if (data[0] != (unsigned char)0xff && data[0] != 0x00)
 			dev_warn(dev, "Weird byte 0x%02x\n", data[0]);
 	} else if (len == 4)
-		dev_warn(dev, "Weird key %02x %02x %02x %02x\n",
-		     data[0], data[1], data[2], data[3]);
+		dev_warn(dev, "Weird key %*ph\n", 4, data);
 	else
-		dev_warn(dev,
-			"Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n",
-			len, data[0], data[1], data[2], data[3], data[4],
-			data[5]);
+		dev_warn(dev, "Weird data, len=%d %*ph ...\n", len, 6, data);
 }
 
 /*
@@ -519,8 +515,7 @@ static void ati_remote_input_report(struct urb *urb)
 
 	if (data[1] != ((data[2] + data[3] + 0xd5) & 0xff)) {
 		dbginfo(&ati_remote->interface->dev,
-			"wrong checksum in input: %02x %02x %02x %02x\n",
-			data[0], data[1], data[2], data[3]);
+			"wrong checksum in input: %*ph\n", 4, data);
 		return;
 	}
 
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index ab30c64..52fd769 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -295,6 +295,7 @@ static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
 {
 	DEFINE_IR_RAW_EVENT(rawir);
 	u8 sample;
+	bool event = false;
 	int i;
 
 	for (i = 0; i < fintek->pkts; i++) {
@@ -332,7 +333,9 @@ static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
 			fit_dbg("Storing %s with duration %d",
 				rawir.pulse ? "pulse" : "space",
 				rawir.duration);
-			ir_raw_event_store_with_filter(fintek->rdev, &rawir);
+			if (ir_raw_event_store_with_filter(fintek->rdev,
+									&rawir))
+				event = true;
 			break;
 		}
 
@@ -342,8 +345,10 @@ static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
 
 	fintek->pkts = 0;
 
-	fit_dbg("Calling ir_raw_event_handle");
-	ir_raw_event_handle(fintek->rdev);
+	if (event) {
+		fit_dbg("Calling ir_raw_event_handle");
+		ir_raw_event_handle(fintek->rdev);
+	}
 }
 
 /* copy data from hardware rx register into driver buffer */
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index 5e2eaf8..66ba237 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -35,9 +35,9 @@ struct iguanair {
 	struct device *dev;
 	struct usb_device *udev;
 
-	int pipe_in, pipe_out;
+	int pipe_out;
+	uint16_t version;
 	uint8_t bufsize;
-	uint8_t version[2];
 
 	struct mutex lock;
 
@@ -75,6 +75,7 @@ struct iguanair {
 
 #define MAX_PACKET_SIZE		8u
 #define TIMEOUT			1000
+#define RX_RESOLUTION		21333
 
 struct packet {
 	uint16_t start;
@@ -82,11 +83,6 @@ struct packet {
 	uint8_t cmd;
 };
 
-struct response_packet {
-	struct packet header;
-	uint8_t data[4];
-};
-
 struct send_packet {
 	struct packet header;
 	uint8_t length;
@@ -100,6 +96,25 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
 {
 	if (len >= 4 && ir->buf_in[0] == 0 && ir->buf_in[1] == 0) {
 		switch (ir->buf_in[3]) {
+		case CMD_GET_VERSION:
+			if (len == 6) {
+				ir->version = (ir->buf_in[5] << 8) |
+							ir->buf_in[4];
+				complete(&ir->completion);
+			}
+			break;
+		case CMD_GET_BUFSIZE:
+			if (len >= 5) {
+				ir->bufsize = ir->buf_in[4];
+				complete(&ir->completion);
+			}
+			break;
+		case CMD_GET_FEATURES:
+			if (len > 5) {
+				ir->cycle_overhead = ir->buf_in[5];
+				complete(&ir->completion);
+			}
+			break;
 		case CMD_TX_OVERFLOW:
 			ir->tx_overflow = true;
 		case CMD_RECEIVER_OFF:
@@ -109,6 +124,7 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
 			break;
 		case CMD_RX_OVERFLOW:
 			dev_warn(ir->dev, "receive overflow\n");
+			ir_raw_event_reset(ir->rc);
 			break;
 		default:
 			dev_warn(ir->dev, "control code %02x received\n",
@@ -118,6 +134,7 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
 	} else if (len >= 7) {
 		DEFINE_IR_RAW_EVENT(rawir);
 		unsigned i;
+		bool event = false;
 
 		init_ir_raw_event(&rawir);
 
@@ -128,19 +145,22 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
 			} else {
 				rawir.pulse = (ir->buf_in[i] & 0x80) == 0;
 				rawir.duration = ((ir->buf_in[i] & 0x7f) + 1) *
-									 21330;
+								 RX_RESOLUTION;
 			}
 
-			ir_raw_event_store_with_filter(ir->rc, &rawir);
+			if (ir_raw_event_store_with_filter(ir->rc, &rawir))
+				event = true;
 		}
 
-		ir_raw_event_handle(ir->rc);
+		if (event)
+			ir_raw_event_handle(ir->rc);
 	}
 }
 
 static void iguanair_rx(struct urb *urb)
 {
 	struct iguanair *ir;
+	int rc;
 
 	if (!urb)
 		return;
@@ -166,34 +186,27 @@ static void iguanair_rx(struct urb *urb)
 		break;
 	}
 
-	usb_submit_urb(urb, GFP_ATOMIC);
+	rc = usb_submit_urb(urb, GFP_ATOMIC);
+	if (rc && rc != -ENODEV)
+		dev_warn(ir->dev, "failed to resubmit urb: %d\n", rc);
 }
 
-static int iguanair_send(struct iguanair *ir, void *data, unsigned size,
-			struct response_packet *response, unsigned *res_len)
+static int iguanair_send(struct iguanair *ir, void *data, unsigned size)
 {
-	unsigned offset, len;
 	int rc, transferred;
 
-	for (offset = 0; offset < size; offset += MAX_PACKET_SIZE) {
-		len = min(size - offset, MAX_PACKET_SIZE);
+	INIT_COMPLETION(ir->completion);
 
-		if (ir->tx_overflow)
-			return -EOVERFLOW;
+	rc = usb_interrupt_msg(ir->udev, ir->pipe_out, data, size,
+							&transferred, TIMEOUT);
+	if (rc)
+		return rc;
 
-		rc = usb_interrupt_msg(ir->udev, ir->pipe_out, data + offset,
-						len, &transferred, TIMEOUT);
-		if (rc)
-			return rc;
+	if (transferred != size)
+		return -EIO;
 
-		if (transferred != len)
-			return -EIO;
-	}
-
-	if (response) {
-		rc = usb_interrupt_msg(ir->udev, ir->pipe_in, response,
-					sizeof(*response), res_len, TIMEOUT);
-	}
+	if (wait_for_completion_timeout(&ir->completion, TIMEOUT) == 0)
+		return -ETIMEDOUT;
 
 	return rc;
 }
@@ -201,66 +214,43 @@ static int iguanair_send(struct iguanair *ir, void *data, unsigned size,
 static int iguanair_get_features(struct iguanair *ir)
 {
 	struct packet packet;
-	struct response_packet response;
-	int rc, len;
+	int rc;
 
 	packet.start = 0;
 	packet.direction = DIR_OUT;
 	packet.cmd = CMD_GET_VERSION;
 
-	rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len);
+	rc = iguanair_send(ir, &packet, sizeof(packet));
 	if (rc) {
 		dev_info(ir->dev, "failed to get version\n");
 		goto out;
 	}
 
-	if (len != 6) {
-		dev_info(ir->dev, "failed to get version\n");
-		rc = -EIO;
+	if (ir->version < 0x205) {
+		dev_err(ir->dev, "firmware 0x%04x is too old\n", ir->version);
+		rc = -ENODEV;
 		goto out;
 	}
 
-	ir->version[0] = response.data[0];
-	ir->version[1] = response.data[1];
 	ir->bufsize = 150;
 	ir->cycle_overhead = 65;
 
 	packet.cmd = CMD_GET_BUFSIZE;
 
-	rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len);
+	rc = iguanair_send(ir, &packet, sizeof(packet));
 	if (rc) {
 		dev_info(ir->dev, "failed to get buffer size\n");
 		goto out;
 	}
 
-	if (len != 5) {
-		dev_info(ir->dev, "failed to get buffer size\n");
-		rc = -EIO;
-		goto out;
-	}
-
-	ir->bufsize = response.data[0];
-
-	if (ir->version[0] == 0 || ir->version[1] == 0)
-		goto out;
-
 	packet.cmd = CMD_GET_FEATURES;
 
-	rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len);
+	rc = iguanair_send(ir, &packet, sizeof(packet));
 	if (rc) {
 		dev_info(ir->dev, "failed to get features\n");
 		goto out;
 	}
 
-	if (len < 5) {
-		dev_info(ir->dev, "failed to get features\n");
-		rc = -EIO;
-		goto out;
-	}
-
-	if (len > 5 && ir->version[0] >= 4)
-		ir->cycle_overhead = response.data[1];
-
 out:
 	return rc;
 }
@@ -269,17 +259,11 @@ static int iguanair_receiver(struct iguanair *ir, bool enable)
 {
 	struct packet packet = { 0, DIR_OUT, enable ?
 				CMD_RECEIVER_ON : CMD_RECEIVER_OFF };
-	int rc;
 
-	INIT_COMPLETION(ir->completion);
+	if (enable)
+		ir_raw_event_reset(ir->rc);
 
-	rc = iguanair_send(ir, &packet, sizeof(packet), NULL, NULL);
-	if (rc)
-		return rc;
-
-	wait_for_completion_timeout(&ir->completion, TIMEOUT);
-
-	return 0;
+	return iguanair_send(ir, &packet, sizeof(packet));
 }
 
 /*
@@ -351,7 +335,7 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 {
 	struct iguanair *ir = dev->priv;
 	uint8_t space, *payload;
-	unsigned i, size, rc;
+	unsigned i, size, rc, bytes;
 	struct send_packet *packet;
 
 	mutex_lock(&ir->lock);
@@ -359,17 +343,22 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 	/* convert from us to carrier periods */
 	for (i = size = 0; i < count; i++) {
 		txbuf[i] = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000);
-		size += (txbuf[i] + 126) / 127;
+		bytes = (txbuf[i] + 126) / 127;
+		if (size + bytes > ir->bufsize) {
+			count = i;
+			break;
+		}
+		size += bytes;
 	}
 
-	packet = kmalloc(sizeof(*packet) + size, GFP_KERNEL);
-	if (!packet) {
-		rc = -ENOMEM;
+	if (count == 0) {
+		rc = -EINVAL;
 		goto out;
 	}
 
-	if (size > ir->bufsize) {
-		rc = -E2BIG;
+	packet = kmalloc(sizeof(*packet) + size, GFP_KERNEL);
+	if (!packet) {
+		rc = -ENOMEM;
 		goto out;
 	}
 
@@ -400,34 +389,28 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 		rc = iguanair_receiver(ir, false);
 		if (rc) {
 			dev_warn(ir->dev, "disable receiver before transmit failed\n");
-			goto out;
+			goto out_kfree;
 		}
 	}
 
 	ir->tx_overflow = false;
 
-	INIT_COMPLETION(ir->completion);
+	rc = iguanair_send(ir, packet, size + 8);
 
-	rc = iguanair_send(ir, packet, size + 8, NULL, NULL);
-
-	if (rc == 0) {
-		wait_for_completion_timeout(&ir->completion, TIMEOUT);
-		if (ir->tx_overflow)
-			rc = -EOVERFLOW;
-	}
-
-	ir->tx_overflow = false;
+	if (rc == 0 && ir->tx_overflow)
+		rc = -EOVERFLOW;
 
 	if (ir->receiver_on) {
 		if (iguanair_receiver(ir, true))
 			dev_warn(ir->dev, "re-enable receiver after transmit failed\n");
 	}
 
+out_kfree:
+	kfree(packet);
 out:
 	mutex_unlock(&ir->lock);
-	kfree(packet);
 
-	return rc;
+	return rc ? rc : count;
 }
 
 static int iguanair_open(struct rc_dev *rdev)
@@ -437,8 +420,6 @@ static int iguanair_open(struct rc_dev *rdev)
 
 	mutex_lock(&ir->lock);
 
-	usb_submit_urb(ir->urb_in, GFP_KERNEL);
-
 	BUG_ON(ir->receiver_on);
 
 	rc = iguanair_receiver(ir, true);
@@ -459,11 +440,9 @@ static void iguanair_close(struct rc_dev *rdev)
 
 	rc = iguanair_receiver(ir, false);
 	ir->receiver_on = false;
-	if (rc)
+	if (rc && rc != -ENODEV)
 		dev_warn(ir->dev, "failed to disable receiver: %d\n", rc);
 
-	usb_kill_urb(ir->urb_in);
-
 	mutex_unlock(&ir->lock);
 }
 
@@ -473,22 +452,22 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct iguanair *ir;
 	struct rc_dev *rc;
-	int ret;
+	int ret, pipein;
 	struct usb_host_interface *idesc;
 
 	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
 	rc = rc_allocate_device();
 	if (!ir || !rc) {
-		ret = ENOMEM;
+		ret = -ENOMEM;
 		goto out;
 	}
 
-	ir->buf_in = usb_alloc_coherent(udev, MAX_PACKET_SIZE, GFP_ATOMIC,
+	ir->buf_in = usb_alloc_coherent(udev, MAX_PACKET_SIZE, GFP_KERNEL,
 								&ir->dma_in);
 	ir->urb_in = usb_alloc_urb(0, GFP_KERNEL);
 
 	if (!ir->buf_in || !ir->urb_in) {
-		ret = ENOMEM;
+		ret = -ENOMEM;
 		goto out;
 	}
 
@@ -502,28 +481,29 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
 	ir->rc = rc;
 	ir->dev = &intf->dev;
 	ir->udev = udev;
-	ir->pipe_in = usb_rcvintpipe(udev,
-				idesc->endpoint[0].desc.bEndpointAddress);
 	ir->pipe_out = usb_sndintpipe(udev,
 				idesc->endpoint[1].desc.bEndpointAddress);
 	mutex_init(&ir->lock);
 	init_completion(&ir->completion);
 
-	ret = iguanair_get_features(ir);
+	pipein = usb_rcvintpipe(udev, idesc->endpoint[0].desc.bEndpointAddress);
+	usb_fill_int_urb(ir->urb_in, udev, pipein, ir->buf_in, MAX_PACKET_SIZE,
+							 iguanair_rx, ir, 1);
+	ir->urb_in->transfer_dma = ir->dma_in;
+	ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	ret = usb_submit_urb(ir->urb_in, GFP_KERNEL);
 	if (ret) {
-		dev_warn(&intf->dev, "failed to get device features");
+		dev_warn(&intf->dev, "failed to submit urb: %d\n", ret);
 		goto out;
 	}
 
-	usb_fill_int_urb(ir->urb_in, ir->udev, ir->pipe_in, ir->buf_in,
-		MAX_PACKET_SIZE, iguanair_rx, ir,
-		idesc->endpoint[0].desc.bInterval);
-	ir->urb_in->transfer_dma = ir->dma_in;
-	ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	ret = iguanair_get_features(ir);
+	if (ret)
+		goto out2;
 
 	snprintf(ir->name, sizeof(ir->name),
-		"IguanaWorks USB IR Transceiver version %d.%d",
-		ir->version[0], ir->version[1]);
+		"IguanaWorks USB IR Transceiver version 0x%04x", ir->version);
 
 	usb_make_path(ir->udev, ir->phys, sizeof(ir->phys));
 
@@ -540,21 +520,23 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
 	rc->s_tx_carrier = iguanair_set_tx_carrier;
 	rc->tx_ir = iguanair_tx;
 	rc->driver_name = DRIVER_NAME;
-	rc->map_name = RC_MAP_EMPTY;
+	rc->map_name = RC_MAP_RC6_MCE;
+	rc->timeout = MS_TO_NS(100);
+	rc->rx_resolution = RX_RESOLUTION;
 
 	iguanair_set_tx_carrier(rc, 38000);
 
 	ret = rc_register_device(rc);
 	if (ret < 0) {
 		dev_err(&intf->dev, "failed to register rc device %d", ret);
-		goto out;
+		goto out2;
 	}
 
 	usb_set_intfdata(intf, ir);
 
-	dev_info(&intf->dev, "Registered %s", ir->name);
-
 	return 0;
+out2:
+	usb_kill_urb(ir->urb_in);
 out:
 	if (ir) {
 		usb_free_urb(ir->urb_in);
@@ -570,12 +552,11 @@ static void __devexit iguanair_disconnect(struct usb_interface *intf)
 {
 	struct iguanair *ir = usb_get_intfdata(intf);
 
+	rc_unregister_device(ir->rc);
 	usb_set_intfdata(intf, NULL);
-
 	usb_kill_urb(ir->urb_in);
 	usb_free_urb(ir->urb_in);
 	usb_free_coherent(ir->udev, MAX_PACKET_SIZE, ir->buf_in, ir->dma_in);
-	rc_unregister_device(ir->rc);
 	kfree(ir);
 }
 
@@ -592,6 +573,8 @@ static int iguanair_suspend(struct usb_interface *intf, pm_message_t message)
 			dev_warn(ir->dev, "failed to disable receiver for suspend\n");
 	}
 
+	usb_kill_urb(ir->urb_in);
+
 	mutex_unlock(&ir->lock);
 
 	return rc;
@@ -604,6 +587,10 @@ static int iguanair_resume(struct usb_interface *intf)
 
 	mutex_lock(&ir->lock);
 
+	rc = usb_submit_urb(ir->urb_in, GFP_KERNEL);
+	if (rc)
+		dev_warn(&intf->dev, "failed to submit urb: %d\n", rc);
+
 	if (ir->receiver_on) {
 		rc = iguanair_receiver(ir, true);
 		if (rc)
@@ -627,7 +614,8 @@ static struct usb_driver iguanair_driver = {
 	.suspend = iguanair_suspend,
 	.resume = iguanair_resume,
 	.reset_resume = iguanair_resume,
-	.id_table = iguanair_table
+	.id_table = iguanair_table,
+	.soft_unbind = 1	/* we want to disable receiver on unbind */
 };
 
 module_usb_driver(iguanair_driver);
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 5faba2a..6ad4a07 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -105,8 +105,14 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
 	struct lirc_codec *lirc;
 	struct rc_dev *dev;
 	unsigned int *txbuf; /* buffer with values to transmit */
-	ssize_t ret = 0;
+	ssize_t ret = -EINVAL;
 	size_t count;
+	ktime_t start;
+	s64 towait;
+	unsigned int duration = 0; /* signal duration in us */
+	int i;
+
+	start = ktime_get();
 
 	lirc = lirc_get_pdata(file);
 	if (!lirc)
@@ -129,11 +135,30 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
 		goto out;
 	}
 
-	if (dev->tx_ir)
-		ret = dev->tx_ir(dev, txbuf, count);
+	if (!dev->tx_ir) {
+		ret = -ENOSYS;
+		goto out;
+	}
+
+	ret = dev->tx_ir(dev, txbuf, (u32)n);
+	if (ret < 0)
+		goto out;
+
+	for (i = 0; i < ret; i++)
+		duration += txbuf[i];
 
-	if (ret > 0)
-		ret *= sizeof(unsigned);
+	ret *= sizeof(unsigned int);
+
+	/*
+	 * The lircd gap calculation expects the write function to
+	 * wait for the actual IR signal to be transmitted before
+	 * returning.
+	 */
+	towait = ktime_us_delta(ktime_add_us(start, duration), ktime_get());
+	if (towait > 0) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(usecs_to_jiffies(towait));
+	}
 
 out:
 	kfree(txbuf);
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 3c9431a..2ca509e 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -70,7 +70,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		if (!ev.pulse)
 			break;
 
-		if (eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT / 2)) {
+		if (eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT * 2)) {
 			data->is_nec_x = false;
 			data->necx_repeat = false;
 		} else if (eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2))
@@ -86,7 +86,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		if (ev.pulse)
 			break;
 
-		if (eq_margin(ev.duration, NEC_HEADER_SPACE, NEC_UNIT / 2)) {
+		if (eq_margin(ev.duration, NEC_HEADER_SPACE, NEC_UNIT)) {
 			data->state = STATE_BIT_PULSE;
 			return 0;
 		} else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index a820251..97dc8d1 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -157,7 +157,9 @@ EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
  * This routine (which may be called from an interrupt context) works
  * in similar manner to ir_raw_event_store_edge.
  * This routine is intended for devices with limited internal buffer
- * It automerges samples of same type, and handles timeouts
+ * It automerges samples of same type, and handles timeouts. Returns non-zero
+ * if the event was added, and zero if the event was ignored due to idle
+ * processing.
  */
 int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev)
 {
@@ -184,7 +186,7 @@ int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev)
 	    dev->raw->this_ev.duration >= dev->timeout)
 		ir_raw_event_set_idle(dev, true);
 
-	return 0;
+	return 1;
 }
 EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter);
 
diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c
new file mode 100644
index 0000000..9487dd3
--- /dev/null
+++ b/drivers/media/rc/ir-rx51.c
@@ -0,0 +1,496 @@
+/*
+ *  Copyright (C) 2008 Nokia Corporation
+ *
+ *  Based on lirc_serial.c
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+#include <plat/dmtimer.h>
+#include <plat/clock.h>
+#include <plat/omap-pm.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+#include <media/ir-rx51.h>
+
+#define LIRC_RX51_DRIVER_FEATURES (LIRC_CAN_SET_SEND_DUTY_CYCLE |	\
+				   LIRC_CAN_SET_SEND_CARRIER |		\
+				   LIRC_CAN_SEND_PULSE)
+
+#define DRIVER_NAME "lirc_rx51"
+
+#define WBUF_LEN 256
+
+#define TIMER_MAX_VALUE 0xffffffff
+
+struct lirc_rx51 {
+	struct omap_dm_timer *pwm_timer;
+	struct omap_dm_timer *pulse_timer;
+	struct device	     *dev;
+	struct lirc_rx51_platform_data *pdata;
+	wait_queue_head_t     wqueue;
+
+	unsigned long	fclk_khz;
+	unsigned int	freq;		/* carrier frequency */
+	unsigned int	duty_cycle;	/* carrier duty cycle */
+	unsigned int	irq_num;
+	unsigned int	match;
+	int		wbuf[WBUF_LEN];
+	int		wbuf_index;
+	unsigned long	device_is_open;
+	unsigned int	pwm_timer_num;
+};
+
+static void lirc_rx51_on(struct lirc_rx51 *lirc_rx51)
+{
+	omap_dm_timer_set_pwm(lirc_rx51->pwm_timer, 0, 1,
+			      OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+}
+
+static void lirc_rx51_off(struct lirc_rx51 *lirc_rx51)
+{
+	omap_dm_timer_set_pwm(lirc_rx51->pwm_timer, 0, 1,
+			      OMAP_TIMER_TRIGGER_NONE);
+}
+
+static int init_timing_params(struct lirc_rx51 *lirc_rx51)
+{
+	u32 load, match;
+
+	load = -(lirc_rx51->fclk_khz * 1000 / lirc_rx51->freq);
+	match = -(lirc_rx51->duty_cycle * -load / 100);
+	omap_dm_timer_set_load(lirc_rx51->pwm_timer, 1, load);
+	omap_dm_timer_set_match(lirc_rx51->pwm_timer, 1, match);
+	omap_dm_timer_write_counter(lirc_rx51->pwm_timer, TIMER_MAX_VALUE - 2);
+	omap_dm_timer_start(lirc_rx51->pwm_timer);
+	omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer, 0);
+	omap_dm_timer_start(lirc_rx51->pulse_timer);
+
+	lirc_rx51->match = 0;
+
+	return 0;
+}
+
+#define tics_after(a, b) ((long)(b) - (long)(a) < 0)
+
+static int pulse_timer_set_timeout(struct lirc_rx51 *lirc_rx51, int usec)
+{
+	int counter;
+
+	BUG_ON(usec < 0);
+
+	if (lirc_rx51->match == 0)
+		counter = omap_dm_timer_read_counter(lirc_rx51->pulse_timer);
+	else
+		counter = lirc_rx51->match;
+
+	counter += (u32)(lirc_rx51->fclk_khz * usec / (1000));
+	omap_dm_timer_set_match(lirc_rx51->pulse_timer, 1, counter);
+	omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer,
+				     OMAP_TIMER_INT_MATCH);
+	if (tics_after(omap_dm_timer_read_counter(lirc_rx51->pulse_timer),
+		       counter)) {
+		return 1;
+	}
+	return 0;
+}
+
+static irqreturn_t lirc_rx51_interrupt_handler(int irq, void *ptr)
+{
+	unsigned int retval;
+	struct lirc_rx51 *lirc_rx51 = ptr;
+
+	retval = omap_dm_timer_read_status(lirc_rx51->pulse_timer);
+	if (!retval)
+		return IRQ_NONE;
+
+	if ((retval & ~OMAP_TIMER_INT_MATCH))
+		dev_err_ratelimited(lirc_rx51->dev,
+				": Unexpected interrupt source: %x\n", retval);
+
+	omap_dm_timer_write_status(lirc_rx51->pulse_timer, 7);
+	if (lirc_rx51->wbuf_index < 0) {
+		dev_err_ratelimited(lirc_rx51->dev,
+				": BUG wbuf_index has value of %i\n",
+				lirc_rx51->wbuf_index);
+		goto end;
+	}
+
+	/*
+	 * If we happen to hit an odd latency spike, loop through the
+	 * pulses until we catch up.
+	 */
+	do {
+		if (lirc_rx51->wbuf_index >= WBUF_LEN)
+			goto end;
+		if (lirc_rx51->wbuf[lirc_rx51->wbuf_index] == -1)
+			goto end;
+
+		if (lirc_rx51->wbuf_index % 2)
+			lirc_rx51_off(lirc_rx51);
+		else
+			lirc_rx51_on(lirc_rx51);
+
+		retval = pulse_timer_set_timeout(lirc_rx51,
+					lirc_rx51->wbuf[lirc_rx51->wbuf_index]);
+		lirc_rx51->wbuf_index++;
+
+	} while (retval);
+
+	return IRQ_HANDLED;
+end:
+	/* Stop TX here */
+	lirc_rx51_off(lirc_rx51);
+	lirc_rx51->wbuf_index = -1;
+	omap_dm_timer_stop(lirc_rx51->pwm_timer);
+	omap_dm_timer_stop(lirc_rx51->pulse_timer);
+	omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer, 0);
+	wake_up_interruptible(&lirc_rx51->wqueue);
+
+	return IRQ_HANDLED;
+}
+
+static int lirc_rx51_init_port(struct lirc_rx51 *lirc_rx51)
+{
+	struct clk *clk_fclk;
+	int retval, pwm_timer = lirc_rx51->pwm_timer_num;
+
+	lirc_rx51->pwm_timer = omap_dm_timer_request_specific(pwm_timer);
+	if (lirc_rx51->pwm_timer == NULL) {
+		dev_err(lirc_rx51->dev, ": Error requesting GPT%d timer\n",
+			pwm_timer);
+		return -EBUSY;
+	}
+
+	lirc_rx51->pulse_timer = omap_dm_timer_request();
+	if (lirc_rx51->pulse_timer == NULL) {
+		dev_err(lirc_rx51->dev, ": Error requesting pulse timer\n");
+		retval = -EBUSY;
+		goto err1;
+	}
+
+	omap_dm_timer_set_source(lirc_rx51->pwm_timer, OMAP_TIMER_SRC_SYS_CLK);
+	omap_dm_timer_set_source(lirc_rx51->pulse_timer,
+				OMAP_TIMER_SRC_SYS_CLK);
+
+	omap_dm_timer_enable(lirc_rx51->pwm_timer);
+	omap_dm_timer_enable(lirc_rx51->pulse_timer);
+
+	lirc_rx51->irq_num = omap_dm_timer_get_irq(lirc_rx51->pulse_timer);
+	retval = request_irq(lirc_rx51->irq_num, lirc_rx51_interrupt_handler,
+			     IRQF_DISABLED | IRQF_SHARED,
+			     "lirc_pulse_timer", lirc_rx51);
+	if (retval) {
+		dev_err(lirc_rx51->dev, ": Failed to request interrupt line\n");
+		goto err2;
+	}
+
+	clk_fclk = omap_dm_timer_get_fclk(lirc_rx51->pwm_timer);
+	lirc_rx51->fclk_khz = clk_fclk->rate / 1000;
+
+	return 0;
+
+err2:
+	omap_dm_timer_free(lirc_rx51->pulse_timer);
+err1:
+	omap_dm_timer_free(lirc_rx51->pwm_timer);
+
+	return retval;
+}
+
+static int lirc_rx51_free_port(struct lirc_rx51 *lirc_rx51)
+{
+	omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer, 0);
+	free_irq(lirc_rx51->irq_num, lirc_rx51);
+	lirc_rx51_off(lirc_rx51);
+	omap_dm_timer_disable(lirc_rx51->pwm_timer);
+	omap_dm_timer_disable(lirc_rx51->pulse_timer);
+	omap_dm_timer_free(lirc_rx51->pwm_timer);
+	omap_dm_timer_free(lirc_rx51->pulse_timer);
+	lirc_rx51->wbuf_index = -1;
+
+	return 0;
+}
+
+static ssize_t lirc_rx51_write(struct file *file, const char *buf,
+			  size_t n, loff_t *ppos)
+{
+	int count, i;
+	struct lirc_rx51 *lirc_rx51 = file->private_data;
+
+	if (n % sizeof(int))
+		return -EINVAL;
+
+	count = n / sizeof(int);
+	if ((count > WBUF_LEN) || (count % 2 == 0))
+		return -EINVAL;
+
+	/* Wait any pending transfers to finish */
+	wait_event_interruptible(lirc_rx51->wqueue, lirc_rx51->wbuf_index < 0);
+
+	if (copy_from_user(lirc_rx51->wbuf, buf, n))
+		return -EFAULT;
+
+	/* Sanity check the input pulses */
+	for (i = 0; i < count; i++)
+		if (lirc_rx51->wbuf[i] < 0)
+			return -EINVAL;
+
+	init_timing_params(lirc_rx51);
+	if (count < WBUF_LEN)
+		lirc_rx51->wbuf[count] = -1; /* Insert termination mark */
+
+	/*
+	 * Adjust latency requirements so the device doesn't go in too
+	 * deep sleep states
+	 */
+	lirc_rx51->pdata->set_max_mpu_wakeup_lat(lirc_rx51->dev, 50);
+
+	lirc_rx51_on(lirc_rx51);
+	lirc_rx51->wbuf_index = 1;
+	pulse_timer_set_timeout(lirc_rx51, lirc_rx51->wbuf[0]);
+
+	/*
+	 * Don't return back to the userspace until the transfer has
+	 * finished
+	 */
+	wait_event_interruptible(lirc_rx51->wqueue, lirc_rx51->wbuf_index < 0);
+
+	/* We can sleep again */
+	lirc_rx51->pdata->set_max_mpu_wakeup_lat(lirc_rx51->dev, -1);
+
+	return n;
+}
+
+static long lirc_rx51_ioctl(struct file *filep,
+			unsigned int cmd, unsigned long arg)
+{
+	int result;
+	unsigned long value;
+	unsigned int ivalue;
+	struct lirc_rx51 *lirc_rx51 = filep->private_data;
+
+	switch (cmd) {
+	case LIRC_GET_SEND_MODE:
+		result = put_user(LIRC_MODE_PULSE, (unsigned long *)arg);
+		if (result)
+			return result;
+		break;
+
+	case LIRC_SET_SEND_MODE:
+		result = get_user(value, (unsigned long *)arg);
+		if (result)
+			return result;
+
+		/* only LIRC_MODE_PULSE supported */
+		if (value != LIRC_MODE_PULSE)
+			return -ENOSYS;
+		break;
+
+	case LIRC_GET_REC_MODE:
+		result = put_user(0, (unsigned long *) arg);
+		if (result)
+			return result;
+		break;
+
+	case LIRC_GET_LENGTH:
+		return -ENOSYS;
+		break;
+
+	case LIRC_SET_SEND_DUTY_CYCLE:
+		result = get_user(ivalue, (unsigned int *) arg);
+		if (result)
+			return result;
+
+		if (ivalue <= 0 || ivalue > 100) {
+			dev_err(lirc_rx51->dev, ": invalid duty cycle %d\n",
+				ivalue);
+			return -EINVAL;
+		}
+
+		lirc_rx51->duty_cycle = ivalue;
+		break;
+
+	case LIRC_SET_SEND_CARRIER:
+		result = get_user(ivalue, (unsigned int *) arg);
+		if (result)
+			return result;
+
+		if (ivalue > 500000 || ivalue < 20000) {
+			dev_err(lirc_rx51->dev, ": invalid carrier freq %d\n",
+				ivalue);
+			return -EINVAL;
+		}
+
+		lirc_rx51->freq = ivalue;
+		break;
+
+	case LIRC_GET_FEATURES:
+		result = put_user(LIRC_RX51_DRIVER_FEATURES,
+				  (unsigned long *) arg);
+		if (result)
+			return result;
+		break;
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	return 0;
+}
+
+static int lirc_rx51_open(struct inode *inode, struct file *file)
+{
+	struct lirc_rx51 *lirc_rx51 = lirc_get_pdata(file);
+	BUG_ON(!lirc_rx51);
+
+	file->private_data = lirc_rx51;
+
+	if (test_and_set_bit(1, &lirc_rx51->device_is_open))
+		return -EBUSY;
+
+	return lirc_rx51_init_port(lirc_rx51);
+}
+
+static int lirc_rx51_release(struct inode *inode, struct file *file)
+{
+	struct lirc_rx51 *lirc_rx51 = file->private_data;
+
+	lirc_rx51_free_port(lirc_rx51);
+
+	clear_bit(1, &lirc_rx51->device_is_open);
+
+	return 0;
+}
+
+static struct lirc_rx51 lirc_rx51 = {
+	.freq		= 38000,
+	.duty_cycle	= 50,
+	.wbuf_index	= -1,
+};
+
+static const struct file_operations lirc_fops = {
+	.owner		= THIS_MODULE,
+	.write		= lirc_rx51_write,
+	.unlocked_ioctl	= lirc_rx51_ioctl,
+	.read		= lirc_dev_fop_read,
+	.poll		= lirc_dev_fop_poll,
+	.open		= lirc_rx51_open,
+	.release	= lirc_rx51_release,
+};
+
+static struct lirc_driver lirc_rx51_driver = {
+	.name		= DRIVER_NAME,
+	.minor		= -1,
+	.code_length	= 1,
+	.data		= &lirc_rx51,
+	.fops		= &lirc_fops,
+	.owner		= THIS_MODULE,
+};
+
+#ifdef CONFIG_PM
+
+static int lirc_rx51_suspend(struct platform_device *dev, pm_message_t state)
+{
+	/*
+	 * In case the device is still open, do not suspend. Normally
+	 * this should not be a problem as lircd only keeps the device
+	 * open only for short periods of time. We also don't want to
+	 * get involved with race conditions that might happen if we
+	 * were in a middle of a transmit. Thus, we defer any suspend
+	 * actions until transmit has completed.
+	 */
+	if (test_and_set_bit(1, &lirc_rx51.device_is_open))
+		return -EAGAIN;
+
+	clear_bit(1, &lirc_rx51.device_is_open);
+
+	return 0;
+}
+
+static int lirc_rx51_resume(struct platform_device *dev)
+{
+	return 0;
+}
+
+#else
+
+#define lirc_rx51_suspend	NULL
+#define lirc_rx51_resume	NULL
+
+#endif /* CONFIG_PM */
+
+static int __devinit lirc_rx51_probe(struct platform_device *dev)
+{
+	lirc_rx51_driver.features = LIRC_RX51_DRIVER_FEATURES;
+	lirc_rx51.pdata = dev->dev.platform_data;
+	lirc_rx51.pwm_timer_num = lirc_rx51.pdata->pwm_timer;
+	lirc_rx51.dev = &dev->dev;
+	lirc_rx51_driver.dev = &dev->dev;
+	lirc_rx51_driver.minor = lirc_register_driver(&lirc_rx51_driver);
+	init_waitqueue_head(&lirc_rx51.wqueue);
+
+	if (lirc_rx51_driver.minor < 0) {
+		dev_err(lirc_rx51.dev, ": lirc_register_driver failed: %d\n",
+		       lirc_rx51_driver.minor);
+		return lirc_rx51_driver.minor;
+	}
+	dev_info(lirc_rx51.dev, "registration ok, minor: %d, pwm: %d\n",
+		 lirc_rx51_driver.minor, lirc_rx51.pwm_timer_num);
+
+	return 0;
+}
+
+static int __exit lirc_rx51_remove(struct platform_device *dev)
+{
+	return lirc_unregister_driver(lirc_rx51_driver.minor);
+}
+
+struct platform_driver lirc_rx51_platform_driver = {
+	.probe		= lirc_rx51_probe,
+	.remove		= __exit_p(lirc_rx51_remove),
+	.suspend	= lirc_rx51_suspend,
+	.resume		= lirc_rx51_resume,
+	.remove		= __exit_p(lirc_rx51_remove),
+	.driver		= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init lirc_rx51_init(void)
+{
+	return platform_driver_register(&lirc_rx51_platform_driver);
+}
+module_init(lirc_rx51_init);
+
+static void __exit lirc_rx51_exit(void)
+{
+	platform_driver_unregister(&lirc_rx51_platform_driver);
+}
+module_exit(lirc_rx51_exit);
+
+MODULE_DESCRIPTION("LIRC TX driver for Nokia RX51");
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/keymaps/rc-tt-1500.c b/drivers/media/rc/keymaps/rc-tt-1500.c
index caeff85..80217ff 100644
--- a/drivers/media/rc/keymaps/rc-tt-1500.c
+++ b/drivers/media/rc/keymaps/rc-tt-1500.c
@@ -61,7 +61,7 @@ static struct rc_map_list tt_1500_map = {
 	.map = {
 		.scan    = tt_1500,
 		.size    = ARRAY_SIZE(tt_1500),
-		.rc_type = RC_TYPE_UNKNOWN,	/* Legacy IR type */
+		.rc_type = RC_TYPE_RC5,
 		.name    = RC_MAP_TT_1500,
 	}
 };
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index f38d9a8..a5c6c1c 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -791,10 +791,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 	int i, ret = 0;
 	int cmdcount = 0;
 	unsigned char *cmdbuf; /* MCE command buffer */
-	long signal_duration = 0; /* Singnal length in us */
-	struct timeval start_time, end_time;
-
-	do_gettimeofday(&start_time);
 
 	cmdbuf = kzalloc(sizeof(unsigned) * MCE_CMDBUF_SIZE, GFP_KERNEL);
 	if (!cmdbuf)
@@ -807,7 +803,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 
 	/* Generate mce packet data */
 	for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) {
-		signal_duration += txbuf[i];
 		txbuf[i] = txbuf[i] / MCE_TIME_UNIT;
 
 		do { /* loop to support long pulses/spaces > 127*50us=6.35ms */
@@ -850,19 +845,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 	/* Transmit the command to the mce device */
 	mce_async_out(ir, cmdbuf, cmdcount);
 
-	/*
-	 * The lircd gap calculation expects the write function to
-	 * wait the time it takes for the ircommand to be sent before
-	 * it returns.
-	 */
-	do_gettimeofday(&end_time);
-	signal_duration -= (end_time.tv_usec - start_time.tv_usec) +
-			   (end_time.tv_sec - start_time.tv_sec) * 1000000;
-
-	/* delay with the closest number of ticks */
-	set_current_state(TASK_INTERRUPTIBLE);
-	schedule_timeout(usecs_to_jiffies(signal_duration));
-
 out:
 	kfree(cmdbuf);
 	return ret ? ret : count;
@@ -974,6 +956,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
 static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
 {
 	DEFINE_IR_RAW_EVENT(rawir);
+	bool event = false;
 	int i = 0;
 
 	/* skip meaningless 0xb1 0x60 header bytes on orig receiver */
@@ -1004,7 +987,8 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
 				rawir.pulse ? "pulse" : "space",
 				rawir.duration);
 
-			ir_raw_event_store_with_filter(ir->rc, &rawir);
+			if (ir_raw_event_store_with_filter(ir->rc, &rawir))
+				event = true;
 			break;
 		case CMD_DATA:
 			ir->rem--;
@@ -1032,8 +1016,10 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
 		if (ir->parser_state != CMD_HEADER && !ir->rem)
 			ir->parser_state = CMD_HEADER;
 	}
-	mce_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n");
-	ir_raw_event_handle(ir->rc);
+	if (event) {
+		mce_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n");
+		ir_raw_event_handle(ir->rc);
+	}
 }
 
 static void mceusb_dev_recv(struct urb *urb)
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index fae1615..f9be681 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -105,18 +105,9 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 {
 	struct loopback_dev *lodev = dev->priv;
 	u32 rxmask;
-	unsigned total_duration = 0;
 	unsigned i;
 	DEFINE_IR_RAW_EVENT(rawir);
 
-	for (i = 0; i < count; i++)
-		total_duration += abs(txbuf[i]);
-
-	if (total_duration == 0) {
-		dprintk("invalid tx data, total duration zero\n");
-		return -EINVAL;
-	}
-
 	if (lodev->txcarrier < lodev->rxcarriermin ||
 	    lodev->txcarrier > lodev->rxcarriermax) {
 		dprintk("ignoring tx, carrier out of range\n");
@@ -148,9 +139,6 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 	ir_raw_event_handle(dev);
 
 out:
-	/* Lirc expects this function to take as long as the total duration */
-	set_current_state(TASK_INTERRUPTIBLE);
-	schedule_timeout(usecs_to_jiffies(total_duration));
 	return count;
 }
 
diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c
new file mode 100644
index 0000000..1aee57f
--- /dev/null
+++ b/drivers/media/rc/ttusbir.c
@@ -0,0 +1,407 @@
+/*
+ * TechnoTrend USB IR Receiver
+ *
+ * Copyright (C) 2012 Sean Young <sean@mess.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
+#include <media/rc-core.h>
+
+#define DRIVER_NAME	"ttusbir"
+#define DRIVER_DESC	"TechnoTrend USB IR Receiver"
+/*
+ * The Windows driver uses 8 URBS, the original lirc drivers has a
+ * configurable amount (2 default, 4 max). This device generates about 125
+ * messages per second (!), whether IR is idle or not.
+ */
+#define NUM_URBS	4
+#define NS_PER_BYTE	62500
+#define NS_PER_BIT	(NS_PER_BYTE/8)
+
+struct ttusbir {
+	struct rc_dev *rc;
+	struct device *dev;
+	struct usb_device *udev;
+
+	struct urb *urb[NUM_URBS];
+
+	struct led_classdev led;
+	struct urb *bulk_urb;
+	uint8_t bulk_buffer[5];
+	int bulk_out_endp, iso_in_endp;
+	bool led_on, is_led_on;
+	atomic_t led_complete;
+
+	char phys[64];
+};
+
+static enum led_brightness ttusbir_brightness_get(struct led_classdev *led_dev)
+{
+	struct ttusbir *tt = container_of(led_dev, struct ttusbir, led);
+
+	return tt->led_on ? LED_FULL : LED_OFF;
+}
+
+static void ttusbir_set_led(struct ttusbir *tt)
+{
+	int ret;
+
+	smp_mb();
+
+	if (tt->led_on != tt->is_led_on &&
+				atomic_add_unless(&tt->led_complete, 1, 1)) {
+		tt->bulk_buffer[4] = tt->is_led_on = tt->led_on;
+		ret = usb_submit_urb(tt->bulk_urb, GFP_ATOMIC);
+		if (ret && ret != -ENODEV) {
+			dev_warn(tt->dev, "failed to submit bulk urb: %d\n",
+									ret);
+			atomic_dec(&tt->led_complete);
+		}
+	}
+}
+
+static void ttusbir_brightness_set(struct led_classdev *led_dev, enum
+						led_brightness brightness)
+{
+	struct ttusbir *tt = container_of(led_dev, struct ttusbir, led);
+
+	tt->led_on = brightness != LED_OFF;
+
+	ttusbir_set_led(tt);
+}
+
+/*
+ * The urb cannot be reused until the urb completes
+ */
+static void ttusbir_bulk_complete(struct urb *urb)
+{
+	struct ttusbir *tt = urb->context;
+
+	atomic_dec(&tt->led_complete);
+
+	switch (urb->status) {
+	case 0:
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		usb_unlink_urb(urb);
+		return;
+	case -EPIPE:
+	default:
+		dev_dbg(tt->dev, "Error: urb status = %d\n", urb->status);
+		break;
+	}
+
+	ttusbir_set_led(tt);
+}
+
+/*
+ * The data is one bit per sample, a set bit signifying silence and samples
+ * being MSB first. Bit 0 can contain garbage so take it to be whatever
+ * bit 1 is, so we don't have unexpected edges.
+ */
+static void ttusbir_process_ir_data(struct ttusbir *tt, uint8_t *buf)
+{
+	struct ir_raw_event rawir;
+	unsigned i, v, b;
+	bool event = false;
+
+	init_ir_raw_event(&rawir);
+
+	for (i = 0; i < 128; i++) {
+		v = buf[i] & 0xfe;
+		switch (v) {
+		case 0xfe:
+			rawir.pulse = false;
+			rawir.duration = NS_PER_BYTE;
+			if (ir_raw_event_store_with_filter(tt->rc, &rawir))
+				event = true;
+			break;
+		case 0:
+			rawir.pulse = true;
+			rawir.duration = NS_PER_BYTE;
+			if (ir_raw_event_store_with_filter(tt->rc, &rawir))
+				event = true;
+			break;
+		default:
+			/* one edge per byte */
+			if (v & 2) {
+				b = ffz(v | 1);
+				rawir.pulse = true;
+			} else {
+				b = ffs(v) - 1;
+				rawir.pulse = false;
+			}
+
+			rawir.duration = NS_PER_BIT * (8 - b);
+			if (ir_raw_event_store_with_filter(tt->rc, &rawir))
+				event = true;
+
+			rawir.pulse = !rawir.pulse;
+			rawir.duration = NS_PER_BIT * b;
+			if (ir_raw_event_store_with_filter(tt->rc, &rawir))
+				event = true;
+			break;
+		}
+	}
+
+	/* don't wakeup when there's nothing to do */
+	if (event)
+		ir_raw_event_handle(tt->rc);
+}
+
+static void ttusbir_urb_complete(struct urb *urb)
+{
+	struct ttusbir *tt = urb->context;
+	int rc;
+
+	switch (urb->status) {
+	case 0:
+		ttusbir_process_ir_data(tt, urb->transfer_buffer);
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		usb_unlink_urb(urb);
+		return;
+	case -EPIPE:
+	default:
+		dev_dbg(tt->dev, "Error: urb status = %d\n", urb->status);
+		break;
+	}
+
+	rc = usb_submit_urb(urb, GFP_ATOMIC);
+	if (rc && rc != -ENODEV)
+		dev_warn(tt->dev, "failed to resubmit urb: %d\n", rc);
+}
+
+static int __devinit ttusbir_probe(struct usb_interface *intf,
+						const struct usb_device_id *id)
+{
+	struct ttusbir *tt;
+	struct usb_interface_descriptor *idesc;
+	struct usb_endpoint_descriptor *desc;
+	struct rc_dev *rc;
+	int i, j, ret;
+	int altsetting = -1;
+
+	tt = kzalloc(sizeof(*tt), GFP_KERNEL);
+	rc = rc_allocate_device();
+	if (!tt || !rc) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/* find the correct alt setting */
+	for (i = 0; i < intf->num_altsetting && altsetting == -1; i++) {
+		int bulk_out_endp = -1, iso_in_endp = -1;
+
+		idesc = &intf->altsetting[i].desc;
+
+		for (j = 0; j < idesc->bNumEndpoints; j++) {
+			desc = &intf->altsetting[i].endpoint[j].desc;
+			if (usb_endpoint_dir_in(desc) &&
+					usb_endpoint_xfer_isoc(desc) &&
+					desc->wMaxPacketSize == 0x10)
+				iso_in_endp = j;
+			else if (usb_endpoint_dir_out(desc) &&
+					usb_endpoint_xfer_bulk(desc) &&
+					desc->wMaxPacketSize == 0x20)
+				bulk_out_endp = j;
+
+			if (bulk_out_endp != -1 && iso_in_endp != -1) {
+				tt->bulk_out_endp = bulk_out_endp;
+				tt->iso_in_endp = iso_in_endp;
+				altsetting = i;
+				break;
+			}
+		}
+	}
+
+	if (altsetting == -1) {
+		dev_err(&intf->dev, "cannot find expected altsetting\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	tt->dev = &intf->dev;
+	tt->udev = interface_to_usbdev(intf);
+	tt->rc = rc;
+
+	ret = usb_set_interface(tt->udev, 0, altsetting);
+	if (ret)
+		goto out;
+
+	for (i = 0; i < NUM_URBS; i++) {
+		struct urb *urb = usb_alloc_urb(8, GFP_KERNEL);
+		void *buffer;
+
+		if (!urb) {
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		urb->dev = tt->udev;
+		urb->context = tt;
+		urb->pipe = usb_rcvisocpipe(tt->udev, tt->iso_in_endp);
+		urb->interval = 1;
+		buffer = usb_alloc_coherent(tt->udev, 128, GFP_KERNEL,
+						&urb->transfer_dma);
+		if (!buffer) {
+			usb_free_urb(urb);
+			ret = -ENOMEM;
+			goto out;
+		}
+		urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP | URB_ISO_ASAP;
+		urb->transfer_buffer = buffer;
+		urb->complete = ttusbir_urb_complete;
+		urb->number_of_packets = 8;
+		urb->transfer_buffer_length = 128;
+
+		for (j = 0; j < 8; j++) {
+			urb->iso_frame_desc[j].offset = j * 16;
+			urb->iso_frame_desc[j].length = 16;
+		}
+
+		tt->urb[i] = urb;
+	}
+
+	tt->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!tt->bulk_urb) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	tt->bulk_buffer[0] = 0xaa;
+	tt->bulk_buffer[1] = 0x01;
+	tt->bulk_buffer[2] = 0x05;
+	tt->bulk_buffer[3] = 0x01;
+
+	usb_fill_bulk_urb(tt->bulk_urb, tt->udev, usb_sndbulkpipe(tt->udev,
+		tt->bulk_out_endp), tt->bulk_buffer, sizeof(tt->bulk_buffer),
+						ttusbir_bulk_complete, tt);
+
+	tt->led.name = "ttusbir:yellow:power";
+	tt->led.brightness_set = ttusbir_brightness_set;
+	tt->led.brightness_get = ttusbir_brightness_get;
+	tt->is_led_on = tt->led_on = true;
+	atomic_set(&tt->led_complete, 0);
+	ret = led_classdev_register(&intf->dev, &tt->led);
+	if (ret)
+		goto out;
+
+	usb_make_path(tt->udev, tt->phys, sizeof(tt->phys));
+
+	rc->input_name = DRIVER_DESC;
+	rc->input_phys = tt->phys;
+	usb_to_input_id(tt->udev, &rc->input_id);
+	rc->dev.parent = &intf->dev;
+	rc->driver_type = RC_DRIVER_IR_RAW;
+	rc->allowed_protos = RC_TYPE_ALL;
+	rc->priv = tt;
+	rc->driver_name = DRIVER_NAME;
+	rc->map_name = RC_MAP_TT_1500;
+	rc->timeout = MS_TO_NS(100);
+	/*
+	 * The precision is NS_PER_BIT, but since every 8th bit can be
+	 * overwritten with garbage the accuracy is at best 2 * NS_PER_BIT.
+	 */
+	rc->rx_resolution = NS_PER_BIT;
+
+	ret = rc_register_device(rc);
+	if (ret) {
+		dev_err(&intf->dev, "failed to register rc device %d\n", ret);
+		goto out2;
+	}
+
+	usb_set_intfdata(intf, tt);
+
+	for (i = 0; i < NUM_URBS; i++) {
+		ret = usb_submit_urb(tt->urb[i], GFP_KERNEL);
+		if (ret) {
+			dev_err(tt->dev, "failed to submit urb %d\n", ret);
+			goto out3;
+		}
+	}
+
+	return 0;
+out3:
+	rc_unregister_device(rc);
+out2:
+	led_classdev_unregister(&tt->led);
+out:
+	if (tt) {
+		for (i = 0; i < NUM_URBS && tt->urb[i]; i++) {
+			struct urb *urb = tt->urb[i];
+
+			usb_kill_urb(urb);
+			usb_free_coherent(tt->udev, 128, urb->transfer_buffer,
+							urb->transfer_dma);
+			usb_free_urb(urb);
+		}
+		usb_kill_urb(tt->bulk_urb);
+		usb_free_urb(tt->bulk_urb);
+		kfree(tt);
+	}
+	rc_free_device(rc);
+
+	return ret;
+}
+
+static void __devexit ttusbir_disconnect(struct usb_interface *intf)
+{
+	struct ttusbir *tt = usb_get_intfdata(intf);
+	int i;
+
+	rc_unregister_device(tt->rc);
+	led_classdev_unregister(&tt->led);
+	for (i = 0; i < NUM_URBS; i++) {
+		usb_kill_urb(tt->urb[i]);
+		usb_free_coherent(tt->udev, 128, tt->urb[i]->transfer_buffer,
+						tt->urb[i]->transfer_dma);
+		usb_free_urb(tt->urb[i]);
+	}
+	usb_kill_urb(tt->bulk_urb);
+	usb_free_urb(tt->bulk_urb);
+	usb_set_intfdata(intf, NULL);
+	kfree(tt);
+}
+
+static const struct usb_device_id ttusbir_table[] = {
+	{ USB_DEVICE(0x0b48, 0x2003) },
+	{ }
+};
+
+static struct usb_driver ttusbir_driver = {
+	.name = DRIVER_NAME,
+	.id_table = ttusbir_table,
+	.probe = ttusbir_probe,
+	.disconnect = __devexit_p(ttusbir_disconnect)
+};
+
+module_usb_driver(ttusbir_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Sean Young <sean@mess.org>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, ttusbir_table);
+
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig
new file mode 100644
index 0000000..94c6ff7
--- /dev/null
+++ b/drivers/media/tuners/Kconfig
@@ -0,0 +1,243 @@
+config MEDIA_ATTACH
+	bool "Load and attach frontend and tuner driver modules as needed"
+	depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT
+	depends on MODULES
+	default y if !EXPERT
+	help
+	  Remove the static dependency of DVB card drivers on all
+	  frontend modules for all possible card variants. Instead,
+	  allow the card drivers to only load the frontend modules
+	  they require.
+
+	  Also, tuner module will automatically load a tuner driver
+	  when needed, for analog mode.
+
+	  This saves several KBytes of memory.
+
+	  Note: You will need module-init-tools v3.2 or later for this feature.
+
+	  If unsure say Y.
+
+config MEDIA_TUNER
+	tristate
+	depends on (MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT) && I2C
+	default y
+	select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT && EXPERIMENTAL
+	select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT
+	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
+
+config MEDIA_TUNER_CUSTOMISE
+	bool "Customize analog and hybrid tuner modules to build"
+	depends on MEDIA_TUNER
+	default y if EXPERT
+	help
+	  This allows the user to deselect tuner drivers unnecessary
+	  for their hardware from the build. Use this option with care
+	  as deselecting tuner drivers which are in fact necessary will
+	  result in V4L/DVB devices which cannot be tuned due to lack of
+	  driver support
+
+	  If unsure say N.
+
+menu "Customize TV tuners"
+	visible if MEDIA_TUNER_CUSTOMISE
+	depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT
+
+config MEDIA_TUNER_SIMPLE
+	tristate "Simple tuner support"
+	depends on MEDIA_SUPPORT && I2C
+	select MEDIA_TUNER_TDA9887
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to include support for various simple tuners.
+
+config MEDIA_TUNER_TDA8290
+	tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo"
+	depends on MEDIA_SUPPORT && I2C
+	select MEDIA_TUNER_TDA827X
+	select MEDIA_TUNER_TDA18271
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to include support for Philips TDA8290+8275(a) tuner.
+
+config MEDIA_TUNER_TDA827X
+	tristate "Philips TDA827X silicon tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  A DVB-T silicon tuner module. Say Y when you want to support this tuner.
+
+config MEDIA_TUNER_TDA18271
+	tristate "NXP TDA18271 silicon tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  A silicon tuner module. Say Y when you want to support this tuner.
+
+config MEDIA_TUNER_TDA9887
+	tristate "TDA 9885/6/7 analog IF demodulator"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to include support for Philips TDA9885/6/7
+	  analog IF demodulator.
+
+config MEDIA_TUNER_TEA5761
+	tristate "TEA 5761 radio tuner (EXPERIMENTAL)"
+	depends on MEDIA_SUPPORT && I2C
+	depends on EXPERIMENTAL
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to include support for the Philips TEA5761 radio tuner.
+
+config MEDIA_TUNER_TEA5767
+	tristate "TEA 5767 radio tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to include support for the Philips TEA5767 radio tuner.
+
+config MEDIA_TUNER_MT20XX
+	tristate "Microtune 2032 / 2050 tuners"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to include support for the MT2032 / MT2050 tuner.
+
+config MEDIA_TUNER_MT2060
+	tristate "Microtune MT2060 silicon IF tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  A driver for the silicon IF tuner MT2060 from Microtune.
+
+config MEDIA_TUNER_MT2063
+	tristate "Microtune MT2063 silicon IF tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  A driver for the silicon IF tuner MT2063 from Microtune.
+
+config MEDIA_TUNER_MT2266
+	tristate "Microtune MT2266 silicon tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  A driver for the silicon baseband tuner MT2266 from Microtune.
+
+config MEDIA_TUNER_MT2131
+	tristate "Microtune MT2131 silicon tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  A driver for the silicon baseband tuner MT2131 from Microtune.
+
+config MEDIA_TUNER_QT1010
+	tristate "Quantek QT1010 silicon tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  A driver for the silicon tuner QT1010 from Quantek.
+
+config MEDIA_TUNER_XC2028
+	tristate "XCeive xc2028/xc3028 tuners"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to include support for the xc2028/xc3028 tuners.
+
+config MEDIA_TUNER_XC5000
+	tristate "Xceive XC5000 silicon tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  A driver for the silicon tuner XC5000 from Xceive.
+	  This device is only used inside a SiP called together with a
+	  demodulator for now.
+
+config MEDIA_TUNER_XC4000
+	tristate "Xceive XC4000 silicon tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  A driver for the silicon tuner XC4000 from Xceive.
+	  This device is only used inside a SiP called together with a
+	  demodulator for now.
+
+config MEDIA_TUNER_MXL5005S
+	tristate "MaxLinear MSL5005S silicon tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  A driver for the silicon tuner MXL5005S from MaxLinear.
+
+config MEDIA_TUNER_MXL5007T
+	tristate "MaxLinear MxL5007T silicon tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  A driver for the silicon tuner MxL5007T from MaxLinear.
+
+config MEDIA_TUNER_MC44S803
+	tristate "Freescale MC44S803 Low Power CMOS Broadband tuners"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to support the Freescale MC44S803 based tuners
+
+config MEDIA_TUNER_MAX2165
+	tristate "Maxim MAX2165 silicon tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  A driver for the silicon tuner MAX2165 from Maxim.
+
+config MEDIA_TUNER_TDA18218
+	tristate "NXP TDA18218 silicon tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  NXP TDA18218 silicon tuner driver.
+
+config MEDIA_TUNER_FC0011
+	tristate "Fitipower FC0011 silicon tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Fitipower FC0011 silicon tuner driver.
+
+config MEDIA_TUNER_FC0012
+	tristate "Fitipower FC0012 silicon tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Fitipower FC0012 silicon tuner driver.
+
+config MEDIA_TUNER_FC0013
+	tristate "Fitipower FC0013 silicon tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Fitipower FC0013 silicon tuner driver.
+
+config MEDIA_TUNER_TDA18212
+	tristate "NXP TDA18212 silicon tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  NXP TDA18212 silicon tuner driver.
+
+config MEDIA_TUNER_TUA9001
+	tristate "Infineon TUA 9001 silicon tuner"
+	depends on MEDIA_SUPPORT && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Infineon TUA 9001 silicon tuner driver.
+endmenu
diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile
new file mode 100644
index 0000000..112aeee
--- /dev/null
+++ b/drivers/media/tuners/Makefile
@@ -0,0 +1,37 @@
+#
+# Makefile for common V4L/DVB tuners
+#
+
+tda18271-objs := tda18271-maps.o tda18271-common.o tda18271-fe.o
+
+obj-$(CONFIG_MEDIA_TUNER_XC2028) += tuner-xc2028.o
+obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-simple.o
+# tuner-types will be merged into tuner-simple, in the future
+obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-types.o
+obj-$(CONFIG_MEDIA_TUNER_MT20XX) += mt20xx.o
+obj-$(CONFIG_MEDIA_TUNER_TDA8290) += tda8290.o
+obj-$(CONFIG_MEDIA_TUNER_TEA5767) += tea5767.o
+obj-$(CONFIG_MEDIA_TUNER_TEA5761) += tea5761.o
+obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o
+obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o
+obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o
+obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o
+obj-$(CONFIG_MEDIA_TUNER_XC4000) += xc4000.o
+obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o
+obj-$(CONFIG_MEDIA_TUNER_MT2063) += mt2063.o
+obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o
+obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o
+obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o
+obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o
+obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
+obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
+obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
+obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
+obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
+obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o
+obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
+obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
+obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o
+
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
diff --git a/drivers/media/tuners/fc0011.c b/drivers/media/tuners/fc0011.c
new file mode 100644
index 0000000..e488254
--- /dev/null
+++ b/drivers/media/tuners/fc0011.c
@@ -0,0 +1,524 @@
+/*
+ * Fitipower FC0011 tuner driver
+ *
+ * Copyright (C) 2012 Michael Buesch <m@bues.ch>
+ *
+ * Derived from FC0012 tuner driver:
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "fc0011.h"
+
+
+/* Tuner registers */
+enum {
+	FC11_REG_0,
+	FC11_REG_FA,		/* FA */
+	FC11_REG_FP,		/* FP */
+	FC11_REG_XINHI,		/* XIN high 8 bit */
+	FC11_REG_XINLO,		/* XIN low 8 bit */
+	FC11_REG_VCO,		/* VCO */
+	FC11_REG_VCOSEL,	/* VCO select */
+	FC11_REG_7,		/* Unknown tuner reg 7 */
+	FC11_REG_8,		/* Unknown tuner reg 8 */
+	FC11_REG_9,
+	FC11_REG_10,		/* Unknown tuner reg 10 */
+	FC11_REG_11,		/* Unknown tuner reg 11 */
+	FC11_REG_12,
+	FC11_REG_RCCAL,		/* RC calibrate */
+	FC11_REG_VCOCAL,	/* VCO calibrate */
+	FC11_REG_15,
+	FC11_REG_16,		/* Unknown tuner reg 16 */
+	FC11_REG_17,
+
+	FC11_NR_REGS,		/* Number of registers */
+};
+
+enum FC11_REG_VCOSEL_bits {
+	FC11_VCOSEL_2		= 0x08, /* VCO select 2 */
+	FC11_VCOSEL_1		= 0x10, /* VCO select 1 */
+	FC11_VCOSEL_CLKOUT	= 0x20, /* Fix clock out */
+	FC11_VCOSEL_BW7M	= 0x40, /* 7MHz bw */
+	FC11_VCOSEL_BW6M	= 0x80, /* 6MHz bw */
+};
+
+enum FC11_REG_RCCAL_bits {
+	FC11_RCCAL_FORCE	= 0x10, /* force */
+};
+
+enum FC11_REG_VCOCAL_bits {
+	FC11_VCOCAL_RUN		= 0,	/* VCO calibration run */
+	FC11_VCOCAL_VALUEMASK	= 0x3F,	/* VCO calibration value mask */
+	FC11_VCOCAL_OK		= 0x40,	/* VCO calibration Ok */
+	FC11_VCOCAL_RESET	= 0x80, /* VCO calibration reset */
+};
+
+
+struct fc0011_priv {
+	struct i2c_adapter *i2c;
+	u8 addr;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+
+static int fc0011_writereg(struct fc0011_priv *priv, u8 reg, u8 val)
+{
+	u8 buf[2] = { reg, val };
+	struct i2c_msg msg = { .addr = priv->addr,
+		.flags = 0, .buf = buf, .len = 2 };
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		dev_err(&priv->i2c->dev,
+			"I2C write reg failed, reg: %02x, val: %02x\n",
+			reg, val);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int fc0011_readreg(struct fc0011_priv *priv, u8 reg, u8 *val)
+{
+	u8 dummy;
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->addr,
+		  .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = priv->addr,
+		  .flags = I2C_M_RD, .buf = val ? : &dummy, .len = 1 },
+	};
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		dev_err(&priv->i2c->dev,
+			"I2C read failed, reg: %02x\n", reg);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int fc0011_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static int fc0011_init(struct dvb_frontend *fe)
+{
+	struct fc0011_priv *priv = fe->tuner_priv;
+	int err;
+
+	if (WARN_ON(!fe->callback))
+		return -EINVAL;
+
+	err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
+			   FC0011_FE_CALLBACK_POWER, priv->addr);
+	if (err) {
+		dev_err(&priv->i2c->dev, "Power-on callback failed\n");
+		return err;
+	}
+	err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
+			   FC0011_FE_CALLBACK_RESET, priv->addr);
+	if (err) {
+		dev_err(&priv->i2c->dev, "Reset callback failed\n");
+		return err;
+	}
+
+	return 0;
+}
+
+/* Initiate VCO calibration */
+static int fc0011_vcocal_trigger(struct fc0011_priv *priv)
+{
+	int err;
+
+	err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RESET);
+	if (err)
+		return err;
+	err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+/* Read VCO calibration value */
+static int fc0011_vcocal_read(struct fc0011_priv *priv, u8 *value)
+{
+	int err;
+
+	err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN);
+	if (err)
+		return err;
+	usleep_range(10000, 20000);
+	err = fc0011_readreg(priv, FC11_REG_VCOCAL, value);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int fc0011_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct fc0011_priv *priv = fe->tuner_priv;
+	int err;
+	unsigned int i, vco_retries;
+	u32 freq = p->frequency / 1000;
+	u32 bandwidth = p->bandwidth_hz / 1000;
+	u32 fvco, xin, xdiv, xdivr;
+	u16 frac;
+	u8 fa, fp, vco_sel, vco_cal;
+	u8 regs[FC11_NR_REGS] = { };
+
+	regs[FC11_REG_7] = 0x0F;
+	regs[FC11_REG_8] = 0x3E;
+	regs[FC11_REG_10] = 0xB8;
+	regs[FC11_REG_11] = 0x80;
+	regs[FC11_REG_RCCAL] = 0x04;
+	err = fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]);
+	err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]);
+	err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]);
+	err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]);
+	err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
+	if (err)
+		return -EIO;
+
+	/* Set VCO freq and VCO div */
+	if (freq < 54000) {
+		fvco = freq * 64;
+		regs[FC11_REG_VCO] = 0x82;
+	} else if (freq < 108000) {
+		fvco = freq * 32;
+		regs[FC11_REG_VCO] = 0x42;
+	} else if (freq < 216000) {
+		fvco = freq * 16;
+		regs[FC11_REG_VCO] = 0x22;
+	} else if (freq < 432000) {
+		fvco = freq * 8;
+		regs[FC11_REG_VCO] = 0x12;
+	} else {
+		fvco = freq * 4;
+		regs[FC11_REG_VCO] = 0x0A;
+	}
+
+	/* Calc XIN. The PLL reference frequency is 18 MHz. */
+	xdiv = fvco / 18000;
+	frac = fvco - xdiv * 18000;
+	frac = (frac << 15) / 18000;
+	if (frac >= 16384)
+		frac += 32786;
+	if (!frac)
+		xin = 0;
+	else if (frac < 511)
+		xin = 512;
+	else if (frac < 65026)
+		xin = frac;
+	else
+		xin = 65024;
+	regs[FC11_REG_XINHI] = xin >> 8;
+	regs[FC11_REG_XINLO] = xin;
+
+	/* Calc FP and FA */
+	xdivr = xdiv;
+	if (fvco - xdiv * 18000 >= 9000)
+		xdivr += 1; /* round */
+	fp = xdivr / 8;
+	fa = xdivr - fp * 8;
+	if (fa < 2) {
+		fp -= 1;
+		fa += 8;
+	}
+	if (fp > 0x1F) {
+		fp &= 0x1F;
+		fa &= 0xF;
+	}
+	if (fa >= fp) {
+		dev_warn(&priv->i2c->dev,
+			 "fa %02X >= fp %02X, but trying to continue\n",
+			 (unsigned int)(u8)fa, (unsigned int)(u8)fp);
+	}
+	regs[FC11_REG_FA] = fa;
+	regs[FC11_REG_FP] = fp;
+
+	/* Select bandwidth */
+	switch (bandwidth) {
+	case 8000:
+		break;
+	case 7000:
+		regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW7M;
+		break;
+	default:
+		dev_warn(&priv->i2c->dev, "Unsupported bandwidth %u kHz. "
+			 "Using 6000 kHz.\n",
+			 bandwidth);
+		bandwidth = 6000;
+		/* fallthrough */
+	case 6000:
+		regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW6M;
+		break;
+	}
+
+	/* Pre VCO select */
+	if (fvco < 2320000) {
+		vco_sel = 0;
+		regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+	} else if (fvco < 3080000) {
+		vco_sel = 1;
+		regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+		regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
+	} else {
+		vco_sel = 2;
+		regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+		regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
+	}
+
+	/* Fix for low freqs */
+	if (freq < 45000) {
+		regs[FC11_REG_FA] = 0x6;
+		regs[FC11_REG_FP] = 0x11;
+	}
+
+	/* Clock out fix */
+	regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_CLKOUT;
+
+	/* Write the cached registers */
+	for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) {
+		err = fc0011_writereg(priv, i, regs[i]);
+		if (err)
+			return err;
+	}
+
+	/* VCO calibration */
+	err = fc0011_vcocal_trigger(priv);
+	if (err)
+		return err;
+	err = fc0011_vcocal_read(priv, &vco_cal);
+	if (err)
+		return err;
+	vco_retries = 0;
+	while (!(vco_cal & FC11_VCOCAL_OK) && vco_retries < 3) {
+		/* Reset the tuner and try again */
+		err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
+				   FC0011_FE_CALLBACK_RESET, priv->addr);
+		if (err) {
+			dev_err(&priv->i2c->dev, "Failed to reset tuner\n");
+			return err;
+		}
+		/* Reinit tuner config */
+		err = 0;
+		for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++)
+			err |= fc0011_writereg(priv, i, regs[i]);
+		err |= fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]);
+		err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]);
+		err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]);
+		err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]);
+		err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
+		if (err)
+			return -EIO;
+		/* VCO calibration */
+		err = fc0011_vcocal_trigger(priv);
+		if (err)
+			return err;
+		err = fc0011_vcocal_read(priv, &vco_cal);
+		if (err)
+			return err;
+		vco_retries++;
+	}
+	if (!(vco_cal & FC11_VCOCAL_OK)) {
+		dev_err(&priv->i2c->dev,
+			"Failed to read VCO calibration value (got %02X)\n",
+			(unsigned int)vco_cal);
+		return -EIO;
+	}
+	vco_cal &= FC11_VCOCAL_VALUEMASK;
+
+	switch (vco_sel) {
+	case 0:
+		if (vco_cal < 8) {
+			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
+			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+					      regs[FC11_REG_VCOSEL]);
+			if (err)
+				return err;
+			err = fc0011_vcocal_trigger(priv);
+			if (err)
+				return err;
+		} else {
+			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+					      regs[FC11_REG_VCOSEL]);
+			if (err)
+				return err;
+		}
+		break;
+	case 1:
+		if (vco_cal < 5) {
+			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
+			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+					      regs[FC11_REG_VCOSEL]);
+			if (err)
+				return err;
+			err = fc0011_vcocal_trigger(priv);
+			if (err)
+				return err;
+		} else if (vco_cal <= 48) {
+			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
+			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+					      regs[FC11_REG_VCOSEL]);
+			if (err)
+				return err;
+		} else {
+			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+					      regs[FC11_REG_VCOSEL]);
+			if (err)
+				return err;
+			err = fc0011_vcocal_trigger(priv);
+			if (err)
+				return err;
+		}
+		break;
+	case 2:
+		if (vco_cal > 53) {
+			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
+			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+					      regs[FC11_REG_VCOSEL]);
+			if (err)
+				return err;
+			err = fc0011_vcocal_trigger(priv);
+			if (err)
+				return err;
+		} else {
+			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
+			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+					      regs[FC11_REG_VCOSEL]);
+			if (err)
+				return err;
+		}
+		break;
+	}
+	err = fc0011_vcocal_read(priv, NULL);
+	if (err)
+		return err;
+	usleep_range(10000, 50000);
+
+	err = fc0011_readreg(priv, FC11_REG_RCCAL, &regs[FC11_REG_RCCAL]);
+	if (err)
+		return err;
+	regs[FC11_REG_RCCAL] |= FC11_RCCAL_FORCE;
+	err = fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
+	if (err)
+		return err;
+	err = fc0011_writereg(priv, FC11_REG_16, 0xB);
+	if (err)
+		return err;
+
+	dev_dbg(&priv->i2c->dev, "Tuned to "
+		"fa=%02X fp=%02X xin=%02X%02X vco=%02X vcosel=%02X "
+		"vcocal=%02X(%u) bw=%u\n",
+		(unsigned int)regs[FC11_REG_FA],
+		(unsigned int)regs[FC11_REG_FP],
+		(unsigned int)regs[FC11_REG_XINHI],
+		(unsigned int)regs[FC11_REG_XINLO],
+		(unsigned int)regs[FC11_REG_VCO],
+		(unsigned int)regs[FC11_REG_VCOSEL],
+		(unsigned int)vco_cal, vco_retries,
+		(unsigned int)bandwidth);
+
+	priv->frequency = p->frequency;
+	priv->bandwidth = p->bandwidth_hz;
+
+	return 0;
+}
+
+static int fc0011_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct fc0011_priv *priv = fe->tuner_priv;
+
+	*frequency = priv->frequency;
+
+	return 0;
+}
+
+static int fc0011_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	*frequency = 0;
+
+	return 0;
+}
+
+static int fc0011_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct fc0011_priv *priv = fe->tuner_priv;
+
+	*bandwidth = priv->bandwidth;
+
+	return 0;
+}
+
+static const struct dvb_tuner_ops fc0011_tuner_ops = {
+	.info = {
+		.name		= "Fitipower FC0011",
+
+		.frequency_min	= 45000000,
+		.frequency_max	= 1000000000,
+	},
+
+	.release		= fc0011_release,
+	.init			= fc0011_init,
+
+	.set_params		= fc0011_set_params,
+
+	.get_frequency		= fc0011_get_frequency,
+	.get_if_frequency	= fc0011_get_if_frequency,
+	.get_bandwidth		= fc0011_get_bandwidth,
+};
+
+struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe,
+				   struct i2c_adapter *i2c,
+				   const struct fc0011_config *config)
+{
+	struct fc0011_priv *priv;
+
+	priv = kzalloc(sizeof(struct fc0011_priv), GFP_KERNEL);
+	if (!priv)
+		return NULL;
+
+	priv->i2c = i2c;
+	priv->addr = config->i2c_address;
+
+	fe->tuner_priv = priv;
+	fe->ops.tuner_ops = fc0011_tuner_ops;
+
+	dev_info(&priv->i2c->dev, "Fitipower FC0011 tuner attached\n");
+
+	return fe;
+}
+EXPORT_SYMBOL(fc0011_attach);
+
+MODULE_DESCRIPTION("Fitipower FC0011 silicon tuner driver");
+MODULE_AUTHOR("Michael Buesch <m@bues.ch>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/fc0011.h b/drivers/media/tuners/fc0011.h
new file mode 100644
index 0000000..0ee581f
--- /dev/null
+++ b/drivers/media/tuners/fc0011.h
@@ -0,0 +1,41 @@
+#ifndef LINUX_FC0011_H_
+#define LINUX_FC0011_H_
+
+#include "dvb_frontend.h"
+
+
+/** struct fc0011_config - fc0011 hardware config
+ *
+ * @i2c_address: I2C bus address.
+ */
+struct fc0011_config {
+	u8 i2c_address;
+};
+
+/** enum fc0011_fe_callback_commands - Frontend callbacks
+ *
+ * @FC0011_FE_CALLBACK_POWER: Power on tuner hardware.
+ * @FC0011_FE_CALLBACK_RESET: Request a tuner reset.
+ */
+enum fc0011_fe_callback_commands {
+	FC0011_FE_CALLBACK_POWER,
+	FC0011_FE_CALLBACK_RESET,
+};
+
+#if defined(CONFIG_MEDIA_TUNER_FC0011) ||\
+    defined(CONFIG_MEDIA_TUNER_FC0011_MODULE)
+struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe,
+				   struct i2c_adapter *i2c,
+				   const struct fc0011_config *config);
+#else
+static inline
+struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe,
+				   struct i2c_adapter *i2c,
+				   const struct fc0011_config *config)
+{
+	dev_err(&i2c->dev, "fc0011 driver disabled in Kconfig\n");
+	return NULL;
+}
+#endif
+
+#endif /* LINUX_FC0011_H_ */
diff --git a/drivers/media/tuners/fc0012-priv.h b/drivers/media/tuners/fc0012-priv.h
new file mode 100644
index 0000000..4577c91
--- /dev/null
+++ b/drivers/media/tuners/fc0012-priv.h
@@ -0,0 +1,43 @@
+/*
+ * Fitipower FC0012 tuner driver - private includes
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _FC0012_PRIV_H_
+#define _FC0012_PRIV_H_
+
+#define LOG_PREFIX "fc0012"
+
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct fc0012_priv {
+	struct i2c_adapter *i2c;
+	u8 addr;
+	u8 dual_master;
+	u8 xtal_freq;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+#endif
diff --git a/drivers/media/tuners/fc0012.c b/drivers/media/tuners/fc0012.c
new file mode 100644
index 0000000..308135a
--- /dev/null
+++ b/drivers/media/tuners/fc0012.c
@@ -0,0 +1,467 @@
+/*
+ * Fitipower FC0012 tuner driver
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "fc0012.h"
+#include "fc0012-priv.h"
+
+static int fc0012_writereg(struct fc0012_priv *priv, u8 reg, u8 val)
+{
+	u8 buf[2] = {reg, val};
+	struct i2c_msg msg = {
+		.addr = priv->addr, .flags = 0, .buf = buf, .len = 2
+	};
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		err("I2C write reg failed, reg: %02x, val: %02x", reg, val);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->addr, .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 },
+	};
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		err("I2C read reg failed, reg: %02x", reg);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int fc0012_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int fc0012_init(struct dvb_frontend *fe)
+{
+	struct fc0012_priv *priv = fe->tuner_priv;
+	int i, ret = 0;
+	unsigned char reg[] = {
+		0x00,	/* dummy reg. 0 */
+		0x05,	/* reg. 0x01 */
+		0x10,	/* reg. 0x02 */
+		0x00,	/* reg. 0x03 */
+		0x00,	/* reg. 0x04 */
+		0x0f,	/* reg. 0x05: may also be 0x0a */
+		0x00,	/* reg. 0x06: divider 2, VCO slow */
+		0x00,	/* reg. 0x07: may also be 0x0f */
+		0xff,	/* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
+			   Loop Bw 1/8 */
+		0x6e,	/* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */
+		0xb8,	/* reg. 0x0a: Disable LO Test Buffer */
+		0x82,	/* reg. 0x0b: Output Clock is same as clock frequency,
+			   may also be 0x83 */
+		0xfc,	/* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */
+		0x02,	/* reg. 0x0d: AGC Not Forcing & LNA Forcing, 0x02 for DVB-T */
+		0x00,	/* reg. 0x0e */
+		0x00,	/* reg. 0x0f */
+		0x00,	/* reg. 0x10: may also be 0x0d */
+		0x00,	/* reg. 0x11 */
+		0x1f,	/* reg. 0x12: Set to maximum gain */
+		0x08,	/* reg. 0x13: Set to Middle Gain: 0x08,
+			   Low Gain: 0x00, High Gain: 0x10, enable IX2: 0x80 */
+		0x00,	/* reg. 0x14 */
+		0x04,	/* reg. 0x15: Enable LNA COMPS */
+	};
+
+	switch (priv->xtal_freq) {
+	case FC_XTAL_27_MHZ:
+	case FC_XTAL_28_8_MHZ:
+		reg[0x07] |= 0x20;
+		break;
+	case FC_XTAL_36_MHZ:
+	default:
+		break;
+	}
+
+	if (priv->dual_master)
+		reg[0x0c] |= 0x02;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	for (i = 1; i < sizeof(reg); i++) {
+		ret = fc0012_writereg(priv, i, reg[i]);
+		if (ret)
+			break;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	if (ret)
+		err("fc0012_writereg failed: %d", ret);
+
+	return ret;
+}
+
+static int fc0012_sleep(struct dvb_frontend *fe)
+{
+	/* nothing to do here */
+	return 0;
+}
+
+static int fc0012_set_params(struct dvb_frontend *fe)
+{
+	struct fc0012_priv *priv = fe->tuner_priv;
+	int i, ret = 0;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	u32 freq = p->frequency / 1000;
+	u32 delsys = p->delivery_system;
+	unsigned char reg[7], am, pm, multi, tmp;
+	unsigned long f_vco;
+	unsigned short xtal_freq_khz_2, xin, xdiv;
+	int vco_select = false;
+
+	if (fe->callback) {
+		ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
+			FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1));
+		if (ret)
+			goto exit;
+	}
+
+	switch (priv->xtal_freq) {
+	case FC_XTAL_27_MHZ:
+		xtal_freq_khz_2 = 27000 / 2;
+		break;
+	case FC_XTAL_36_MHZ:
+		xtal_freq_khz_2 = 36000 / 2;
+		break;
+	case FC_XTAL_28_8_MHZ:
+	default:
+		xtal_freq_khz_2 = 28800 / 2;
+		break;
+	}
+
+	/* select frequency divider and the frequency of VCO */
+	if (freq < 37084) {		/* freq * 96 < 3560000 */
+		multi = 96;
+		reg[5] = 0x82;
+		reg[6] = 0x00;
+	} else if (freq < 55625) {	/* freq * 64 < 3560000 */
+		multi = 64;
+		reg[5] = 0x82;
+		reg[6] = 0x02;
+	} else if (freq < 74167) {	/* freq * 48 < 3560000 */
+		multi = 48;
+		reg[5] = 0x42;
+		reg[6] = 0x00;
+	} else if (freq < 111250) {	/* freq * 32 < 3560000 */
+		multi = 32;
+		reg[5] = 0x42;
+		reg[6] = 0x02;
+	} else if (freq < 148334) {	/* freq * 24 < 3560000 */
+		multi = 24;
+		reg[5] = 0x22;
+		reg[6] = 0x00;
+	} else if (freq < 222500) {	/* freq * 16 < 3560000 */
+		multi = 16;
+		reg[5] = 0x22;
+		reg[6] = 0x02;
+	} else if (freq < 296667) {	/* freq * 12 < 3560000 */
+		multi = 12;
+		reg[5] = 0x12;
+		reg[6] = 0x00;
+	} else if (freq < 445000) {	/* freq * 8 < 3560000 */
+		multi = 8;
+		reg[5] = 0x12;
+		reg[6] = 0x02;
+	} else if (freq < 593334) {	/* freq * 6 < 3560000 */
+		multi = 6;
+		reg[5] = 0x0a;
+		reg[6] = 0x00;
+	} else {
+		multi = 4;
+		reg[5] = 0x0a;
+		reg[6] = 0x02;
+	}
+
+	f_vco = freq * multi;
+
+	if (f_vco >= 3060000) {
+		reg[6] |= 0x08;
+		vco_select = true;
+	}
+
+	if (freq >= 45000) {
+		/* From divided value (XDIV) determined the FA and FP value */
+		xdiv = (unsigned short)(f_vco / xtal_freq_khz_2);
+		if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2))
+			xdiv++;
+
+		pm = (unsigned char)(xdiv / 8);
+		am = (unsigned char)(xdiv - (8 * pm));
+
+		if (am < 2) {
+			reg[1] = am + 8;
+			reg[2] = pm - 1;
+		} else {
+			reg[1] = am;
+			reg[2] = pm;
+		}
+	} else {
+		/* fix for frequency less than 45 MHz */
+		reg[1] = 0x06;
+		reg[2] = 0x11;
+	}
+
+	/* fix clock out */
+	reg[6] |= 0x20;
+
+	/* From VCO frequency determines the XIN ( fractional part of Delta
+	   Sigma PLL) and divided value (XDIV) */
+	xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2);
+	xin = (xin << 15) / xtal_freq_khz_2;
+	if (xin >= 16384)
+		xin += 32768;
+
+	reg[3] = xin >> 8;	/* xin with 9 bit resolution */
+	reg[4] = xin & 0xff;
+
+	if (delsys == SYS_DVBT) {
+		reg[6] &= 0x3f;	/* bits 6 and 7 describe the bandwidth */
+		switch (p->bandwidth_hz) {
+		case 6000000:
+			reg[6] |= 0x80;
+			break;
+		case 7000000:
+			reg[6] |= 0x40;
+			break;
+		case 8000000:
+		default:
+			break;
+		}
+	} else {
+		err("%s: modulation type not supported!", __func__);
+		return -EINVAL;
+	}
+
+	/* modified for Realtek demod */
+	reg[5] |= 0x07;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	for (i = 1; i <= 6; i++) {
+		ret = fc0012_writereg(priv, i, reg[i]);
+		if (ret)
+			goto exit;
+	}
+
+	/* VCO Calibration */
+	ret = fc0012_writereg(priv, 0x0e, 0x80);
+	if (!ret)
+		ret = fc0012_writereg(priv, 0x0e, 0x00);
+
+	/* VCO Re-Calibration if needed */
+	if (!ret)
+		ret = fc0012_writereg(priv, 0x0e, 0x00);
+
+	if (!ret) {
+		msleep(10);
+		ret = fc0012_readreg(priv, 0x0e, &tmp);
+	}
+	if (ret)
+		goto exit;
+
+	/* vco selection */
+	tmp &= 0x3f;
+
+	if (vco_select) {
+		if (tmp > 0x3c) {
+			reg[6] &= ~0x08;
+			ret = fc0012_writereg(priv, 0x06, reg[6]);
+			if (!ret)
+				ret = fc0012_writereg(priv, 0x0e, 0x80);
+			if (!ret)
+				ret = fc0012_writereg(priv, 0x0e, 0x00);
+		}
+	} else {
+		if (tmp < 0x02) {
+			reg[6] |= 0x08;
+			ret = fc0012_writereg(priv, 0x06, reg[6]);
+			if (!ret)
+				ret = fc0012_writereg(priv, 0x0e, 0x80);
+			if (!ret)
+				ret = fc0012_writereg(priv, 0x0e, 0x00);
+		}
+	}
+
+	priv->frequency = p->frequency;
+	priv->bandwidth = p->bandwidth_hz;
+
+exit:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+	if (ret)
+		warn("%s: failed: %d", __func__, ret);
+	return ret;
+}
+
+static int fc0012_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct fc0012_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int fc0012_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	/* CHECK: always ? */
+	*frequency = 0;
+	return 0;
+}
+
+static int fc0012_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct fc0012_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+#define INPUT_ADC_LEVEL	-8
+
+static int fc0012_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct fc0012_priv *priv = fe->tuner_priv;
+	int ret;
+	unsigned char tmp;
+	int int_temp, lna_gain, int_lna, tot_agc_gain, power;
+	const int fc0012_lna_gain_table[] = {
+		/* low gain */
+		-63, -58, -99, -73,
+		-63, -65, -54, -60,
+		/* middle gain */
+		 71,  70,  68,  67,
+		 65,  63,  61,  58,
+		/* high gain */
+		197, 191, 188, 186,
+		184, 182, 181, 179,
+	};
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	ret = fc0012_writereg(priv, 0x12, 0x00);
+	if (ret)
+		goto err;
+
+	ret = fc0012_readreg(priv, 0x12, &tmp);
+	if (ret)
+		goto err;
+	int_temp = tmp;
+
+	ret = fc0012_readreg(priv, 0x13, &tmp);
+	if (ret)
+		goto err;
+	lna_gain = tmp & 0x1f;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	if (lna_gain < ARRAY_SIZE(fc0012_lna_gain_table)) {
+		int_lna = fc0012_lna_gain_table[lna_gain];
+		tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 +
+				(int_temp & 0x1f)) * 2;
+		power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10;
+
+		if (power >= 45)
+			*strength = 255;	/* 100% */
+		else if (power < -95)
+			*strength = 0;
+		else
+			*strength = (power + 95) * 255 / 140;
+
+		*strength |= *strength << 8;
+	} else {
+		ret = -1;
+	}
+
+	goto exit;
+
+err:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+exit:
+	if (ret)
+		warn("%s: failed: %d", __func__, ret);
+	return ret;
+}
+
+static const struct dvb_tuner_ops fc0012_tuner_ops = {
+	.info = {
+		.name           = "Fitipower FC0012",
+
+		.frequency_min  = 37000000,	/* estimate */
+		.frequency_max  = 862000000,	/* estimate */
+		.frequency_step = 0,
+	},
+
+	.release	= fc0012_release,
+
+	.init		= fc0012_init,
+	.sleep		= fc0012_sleep,
+
+	.set_params	= fc0012_set_params,
+
+	.get_frequency	= fc0012_get_frequency,
+	.get_if_frequency = fc0012_get_if_frequency,
+	.get_bandwidth	= fc0012_get_bandwidth,
+
+	.get_rf_strength = fc0012_get_rf_strength,
+};
+
+struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c, u8 i2c_address, int dual_master,
+	enum fc001x_xtal_freq xtal_freq)
+{
+	struct fc0012_priv *priv = NULL;
+
+	priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->i2c = i2c;
+	priv->dual_master = dual_master;
+	priv->addr = i2c_address;
+	priv->xtal_freq = xtal_freq;
+
+	info("Fitipower FC0012 successfully attached.");
+
+	fe->tuner_priv = priv;
+
+	memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+
+	return fe;
+}
+EXPORT_SYMBOL(fc0012_attach);
+
+MODULE_DESCRIPTION("Fitipower FC0012 silicon tuner driver");
+MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.6");
diff --git a/drivers/media/tuners/fc0012.h b/drivers/media/tuners/fc0012.h
new file mode 100644
index 0000000..4dbd5ef
--- /dev/null
+++ b/drivers/media/tuners/fc0012.h
@@ -0,0 +1,44 @@
+/*
+ * Fitipower FC0012 tuner driver - include
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _FC0012_H_
+#define _FC0012_H_
+
+#include "dvb_frontend.h"
+#include "fc001x-common.h"
+
+#if defined(CONFIG_MEDIA_TUNER_FC0012) || \
+	(defined(CONFIG_MEDIA_TUNER_FC0012_MODULE) && defined(MODULE))
+extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
+					struct i2c_adapter *i2c,
+					u8 i2c_address, int dual_master,
+					enum fc001x_xtal_freq xtal_freq);
+#else
+static inline struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
+					struct i2c_adapter *i2c,
+					u8 i2c_address, int dual_master,
+					enum fc001x_xtal_freq xtal_freq)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/tuners/fc0013-priv.h b/drivers/media/tuners/fc0013-priv.h
new file mode 100644
index 0000000..bfd49de
--- /dev/null
+++ b/drivers/media/tuners/fc0013-priv.h
@@ -0,0 +1,44 @@
+/*
+ * Fitipower FC0013 tuner driver
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.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.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _FC0013_PRIV_H_
+#define _FC0013_PRIV_H_
+
+#define LOG_PREFIX "fc0013"
+
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct fc0013_priv {
+	struct i2c_adapter *i2c;
+	u8 addr;
+	u8 dual_master;
+	u8 xtal_freq;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+#endif
diff --git a/drivers/media/tuners/fc0013.c b/drivers/media/tuners/fc0013.c
new file mode 100644
index 0000000..bd8f0f1
--- /dev/null
+++ b/drivers/media/tuners/fc0013.c
@@ -0,0 +1,634 @@
+/*
+ * Fitipower FC0013 tuner driver
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
+ * partially based on driver code from Fitipower
+ * Copyright (C) 2010 Fitipower Integrated Technology Inc
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "fc0013.h"
+#include "fc0013-priv.h"
+
+static int fc0013_writereg(struct fc0013_priv *priv, u8 reg, u8 val)
+{
+	u8 buf[2] = {reg, val};
+	struct i2c_msg msg = {
+		.addr = priv->addr, .flags = 0, .buf = buf, .len = 2
+	};
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		err("I2C write reg failed, reg: %02x, val: %02x", reg, val);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int fc0013_readreg(struct fc0013_priv *priv, u8 reg, u8 *val)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->addr, .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 },
+	};
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		err("I2C read reg failed, reg: %02x", reg);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int fc0013_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int fc0013_init(struct dvb_frontend *fe)
+{
+	struct fc0013_priv *priv = fe->tuner_priv;
+	int i, ret = 0;
+	unsigned char reg[] = {
+		0x00,	/* reg. 0x00: dummy */
+		0x09,	/* reg. 0x01 */
+		0x16,	/* reg. 0x02 */
+		0x00,	/* reg. 0x03 */
+		0x00,	/* reg. 0x04 */
+		0x17,	/* reg. 0x05 */
+		0x02,	/* reg. 0x06 */
+		0x0a,	/* reg. 0x07: CHECK */
+		0xff,	/* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
+			   Loop Bw 1/8 */
+		0x6f,	/* reg. 0x09: enable LoopThrough */
+		0xb8,	/* reg. 0x0a: Disable LO Test Buffer */
+		0x82,	/* reg. 0x0b: CHECK */
+		0xfc,	/* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */
+		0x01,	/* reg. 0x0d: AGC Not Forcing & LNA Forcing, may need 0x02 */
+		0x00,	/* reg. 0x0e */
+		0x00,	/* reg. 0x0f */
+		0x00,	/* reg. 0x10 */
+		0x00,	/* reg. 0x11 */
+		0x00,	/* reg. 0x12 */
+		0x00,	/* reg. 0x13 */
+		0x50,	/* reg. 0x14: DVB-t High Gain, UHF.
+			   Middle Gain: 0x48, Low Gain: 0x40 */
+		0x01,	/* reg. 0x15 */
+	};
+
+	switch (priv->xtal_freq) {
+	case FC_XTAL_27_MHZ:
+	case FC_XTAL_28_8_MHZ:
+		reg[0x07] |= 0x20;
+		break;
+	case FC_XTAL_36_MHZ:
+	default:
+		break;
+	}
+
+	if (priv->dual_master)
+		reg[0x0c] |= 0x02;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	for (i = 1; i < sizeof(reg); i++) {
+		ret = fc0013_writereg(priv, i, reg[i]);
+		if (ret)
+			break;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	if (ret)
+		err("fc0013_writereg failed: %d", ret);
+
+	return ret;
+}
+
+static int fc0013_sleep(struct dvb_frontend *fe)
+{
+	/* nothing to do here */
+	return 0;
+}
+
+int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val)
+{
+	struct fc0013_priv *priv = fe->tuner_priv;
+	int ret;
+	u8 rc_cal;
+	int val;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	/* push rc_cal value, get rc_cal value */
+	ret = fc0013_writereg(priv, 0x10, 0x00);
+	if (ret)
+		goto error_out;
+
+	/* get rc_cal value */
+	ret = fc0013_readreg(priv, 0x10, &rc_cal);
+	if (ret)
+		goto error_out;
+
+	rc_cal &= 0x0f;
+
+	val = (int)rc_cal + rc_val;
+
+	/* forcing rc_cal */
+	ret = fc0013_writereg(priv, 0x0d, 0x11);
+	if (ret)
+		goto error_out;
+
+	/* modify rc_cal value */
+	if (val > 15)
+		ret = fc0013_writereg(priv, 0x10, 0x0f);
+	else if (val < 0)
+		ret = fc0013_writereg(priv, 0x10, 0x00);
+	else
+		ret = fc0013_writereg(priv, 0x10, (u8)val);
+
+error_out:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	return ret;
+}
+EXPORT_SYMBOL(fc0013_rc_cal_add);
+
+int fc0013_rc_cal_reset(struct dvb_frontend *fe)
+{
+	struct fc0013_priv *priv = fe->tuner_priv;
+	int ret;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	ret = fc0013_writereg(priv, 0x0d, 0x01);
+	if (!ret)
+		ret = fc0013_writereg(priv, 0x10, 0x00);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	return ret;
+}
+EXPORT_SYMBOL(fc0013_rc_cal_reset);
+
+static int fc0013_set_vhf_track(struct fc0013_priv *priv, u32 freq)
+{
+	int ret;
+	u8 tmp;
+
+	ret = fc0013_readreg(priv, 0x1d, &tmp);
+	if (ret)
+		goto error_out;
+	tmp &= 0xe3;
+	if (freq <= 177500) {		/* VHF Track: 7 */
+		ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c);
+	} else if (freq <= 184500) {	/* VHF Track: 6 */
+		ret = fc0013_writereg(priv, 0x1d, tmp | 0x18);
+	} else if (freq <= 191500) {	/* VHF Track: 5 */
+		ret = fc0013_writereg(priv, 0x1d, tmp | 0x14);
+	} else if (freq <= 198500) {	/* VHF Track: 4 */
+		ret = fc0013_writereg(priv, 0x1d, tmp | 0x10);
+	} else if (freq <= 205500) {	/* VHF Track: 3 */
+		ret = fc0013_writereg(priv, 0x1d, tmp | 0x0c);
+	} else if (freq <= 219500) {	/* VHF Track: 2 */
+		ret = fc0013_writereg(priv, 0x1d, tmp | 0x08);
+	} else if (freq < 300000) {	/* VHF Track: 1 */
+		ret = fc0013_writereg(priv, 0x1d, tmp | 0x04);
+	} else {			/* UHF and GPS */
+		ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c);
+	}
+	if (ret)
+		goto error_out;
+error_out:
+	return ret;
+}
+
+static int fc0013_set_params(struct dvb_frontend *fe)
+{
+	struct fc0013_priv *priv = fe->tuner_priv;
+	int i, ret = 0;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	u32 freq = p->frequency / 1000;
+	u32 delsys = p->delivery_system;
+	unsigned char reg[7], am, pm, multi, tmp;
+	unsigned long f_vco;
+	unsigned short xtal_freq_khz_2, xin, xdiv;
+	int vco_select = false;
+
+	if (fe->callback) {
+		ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
+			FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1));
+		if (ret)
+			goto exit;
+	}
+
+	switch (priv->xtal_freq) {
+	case FC_XTAL_27_MHZ:
+		xtal_freq_khz_2 = 27000 / 2;
+		break;
+	case FC_XTAL_36_MHZ:
+		xtal_freq_khz_2 = 36000 / 2;
+		break;
+	case FC_XTAL_28_8_MHZ:
+	default:
+		xtal_freq_khz_2 = 28800 / 2;
+		break;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	/* set VHF track */
+	ret = fc0013_set_vhf_track(priv, freq);
+	if (ret)
+		goto exit;
+
+	if (freq < 300000) {
+		/* enable VHF filter */
+		ret = fc0013_readreg(priv, 0x07, &tmp);
+		if (ret)
+			goto exit;
+		ret = fc0013_writereg(priv, 0x07, tmp | 0x10);
+		if (ret)
+			goto exit;
+
+		/* disable UHF & disable GPS */
+		ret = fc0013_readreg(priv, 0x14, &tmp);
+		if (ret)
+			goto exit;
+		ret = fc0013_writereg(priv, 0x14, tmp & 0x1f);
+		if (ret)
+			goto exit;
+	} else if (freq <= 862000) {
+		/* disable VHF filter */
+		ret = fc0013_readreg(priv, 0x07, &tmp);
+		if (ret)
+			goto exit;
+		ret = fc0013_writereg(priv, 0x07, tmp & 0xef);
+		if (ret)
+			goto exit;
+
+		/* enable UHF & disable GPS */
+		ret = fc0013_readreg(priv, 0x14, &tmp);
+		if (ret)
+			goto exit;
+		ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x40);
+		if (ret)
+			goto exit;
+	} else {
+		/* disable VHF filter */
+		ret = fc0013_readreg(priv, 0x07, &tmp);
+		if (ret)
+			goto exit;
+		ret = fc0013_writereg(priv, 0x07, tmp & 0xef);
+		if (ret)
+			goto exit;
+
+		/* disable UHF & enable GPS */
+		ret = fc0013_readreg(priv, 0x14, &tmp);
+		if (ret)
+			goto exit;
+		ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x20);
+		if (ret)
+			goto exit;
+	}
+
+	/* select frequency divider and the frequency of VCO */
+	if (freq < 37084) {		/* freq * 96 < 3560000 */
+		multi = 96;
+		reg[5] = 0x82;
+		reg[6] = 0x00;
+	} else if (freq < 55625) {	/* freq * 64 < 3560000 */
+		multi = 64;
+		reg[5] = 0x02;
+		reg[6] = 0x02;
+	} else if (freq < 74167) {	/* freq * 48 < 3560000 */
+		multi = 48;
+		reg[5] = 0x42;
+		reg[6] = 0x00;
+	} else if (freq < 111250) {	/* freq * 32 < 3560000 */
+		multi = 32;
+		reg[5] = 0x82;
+		reg[6] = 0x02;
+	} else if (freq < 148334) {	/* freq * 24 < 3560000 */
+		multi = 24;
+		reg[5] = 0x22;
+		reg[6] = 0x00;
+	} else if (freq < 222500) {	/* freq * 16 < 3560000 */
+		multi = 16;
+		reg[5] = 0x42;
+		reg[6] = 0x02;
+	} else if (freq < 296667) {	/* freq * 12 < 3560000 */
+		multi = 12;
+		reg[5] = 0x12;
+		reg[6] = 0x00;
+	} else if (freq < 445000) {	/* freq * 8 < 3560000 */
+		multi = 8;
+		reg[5] = 0x22;
+		reg[6] = 0x02;
+	} else if (freq < 593334) {	/* freq * 6 < 3560000 */
+		multi = 6;
+		reg[5] = 0x0a;
+		reg[6] = 0x00;
+	} else if (freq < 950000) {	/* freq * 4 < 3800000 */
+		multi = 4;
+		reg[5] = 0x12;
+		reg[6] = 0x02;
+	} else {
+		multi = 2;
+		reg[5] = 0x0a;
+		reg[6] = 0x02;
+	}
+
+	f_vco = freq * multi;
+
+	if (f_vco >= 3060000) {
+		reg[6] |= 0x08;
+		vco_select = true;
+	}
+
+	if (freq >= 45000) {
+		/* From divided value (XDIV) determined the FA and FP value */
+		xdiv = (unsigned short)(f_vco / xtal_freq_khz_2);
+		if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2))
+			xdiv++;
+
+		pm = (unsigned char)(xdiv / 8);
+		am = (unsigned char)(xdiv - (8 * pm));
+
+		if (am < 2) {
+			reg[1] = am + 8;
+			reg[2] = pm - 1;
+		} else {
+			reg[1] = am;
+			reg[2] = pm;
+		}
+	} else {
+		/* fix for frequency less than 45 MHz */
+		reg[1] = 0x06;
+		reg[2] = 0x11;
+	}
+
+	/* fix clock out */
+	reg[6] |= 0x20;
+
+	/* From VCO frequency determines the XIN ( fractional part of Delta
+	   Sigma PLL) and divided value (XDIV) */
+	xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2);
+	xin = (xin << 15) / xtal_freq_khz_2;
+	if (xin >= 16384)
+		xin += 32768;
+
+	reg[3] = xin >> 8;
+	reg[4] = xin & 0xff;
+
+	if (delsys == SYS_DVBT) {
+		reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */
+		switch (p->bandwidth_hz) {
+		case 6000000:
+			reg[6] |= 0x80;
+			break;
+		case 7000000:
+			reg[6] |= 0x40;
+			break;
+		case 8000000:
+		default:
+			break;
+		}
+	} else {
+		err("%s: modulation type not supported!", __func__);
+		return -EINVAL;
+	}
+
+	/* modified for Realtek demod */
+	reg[5] |= 0x07;
+
+	for (i = 1; i <= 6; i++) {
+		ret = fc0013_writereg(priv, i, reg[i]);
+		if (ret)
+			goto exit;
+	}
+
+	ret = fc0013_readreg(priv, 0x11, &tmp);
+	if (ret)
+		goto exit;
+	if (multi == 64)
+		ret = fc0013_writereg(priv, 0x11, tmp | 0x04);
+	else
+		ret = fc0013_writereg(priv, 0x11, tmp & 0xfb);
+	if (ret)
+		goto exit;
+
+	/* VCO Calibration */
+	ret = fc0013_writereg(priv, 0x0e, 0x80);
+	if (!ret)
+		ret = fc0013_writereg(priv, 0x0e, 0x00);
+
+	/* VCO Re-Calibration if needed */
+	if (!ret)
+		ret = fc0013_writereg(priv, 0x0e, 0x00);
+
+	if (!ret) {
+		msleep(10);
+		ret = fc0013_readreg(priv, 0x0e, &tmp);
+	}
+	if (ret)
+		goto exit;
+
+	/* vco selection */
+	tmp &= 0x3f;
+
+	if (vco_select) {
+		if (tmp > 0x3c) {
+			reg[6] &= ~0x08;
+			ret = fc0013_writereg(priv, 0x06, reg[6]);
+			if (!ret)
+				ret = fc0013_writereg(priv, 0x0e, 0x80);
+			if (!ret)
+				ret = fc0013_writereg(priv, 0x0e, 0x00);
+		}
+	} else {
+		if (tmp < 0x02) {
+			reg[6] |= 0x08;
+			ret = fc0013_writereg(priv, 0x06, reg[6]);
+			if (!ret)
+				ret = fc0013_writereg(priv, 0x0e, 0x80);
+			if (!ret)
+				ret = fc0013_writereg(priv, 0x0e, 0x00);
+		}
+	}
+
+	priv->frequency = p->frequency;
+	priv->bandwidth = p->bandwidth_hz;
+
+exit:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+	if (ret)
+		warn("%s: failed: %d", __func__, ret);
+	return ret;
+}
+
+static int fc0013_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct fc0013_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int fc0013_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	/* always ? */
+	*frequency = 0;
+	return 0;
+}
+
+static int fc0013_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct fc0013_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+#define INPUT_ADC_LEVEL	-8
+
+static int fc0013_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct fc0013_priv *priv = fe->tuner_priv;
+	int ret;
+	unsigned char tmp;
+	int int_temp, lna_gain, int_lna, tot_agc_gain, power;
+	const int fc0013_lna_gain_table[] = {
+		/* low gain */
+		-63, -58, -99, -73,
+		-63, -65, -54, -60,
+		/* middle gain */
+		 71,  70,  68,  67,
+		 65,  63,  61,  58,
+		/* high gain */
+		197, 191, 188, 186,
+		184, 182, 181, 179,
+	};
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	ret = fc0013_writereg(priv, 0x13, 0x00);
+	if (ret)
+		goto err;
+
+	ret = fc0013_readreg(priv, 0x13, &tmp);
+	if (ret)
+		goto err;
+	int_temp = tmp;
+
+	ret = fc0013_readreg(priv, 0x14, &tmp);
+	if (ret)
+		goto err;
+	lna_gain = tmp & 0x1f;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	if (lna_gain < ARRAY_SIZE(fc0013_lna_gain_table)) {
+		int_lna = fc0013_lna_gain_table[lna_gain];
+		tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 +
+				(int_temp & 0x1f)) * 2;
+		power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10;
+
+		if (power >= 45)
+			*strength = 255;	/* 100% */
+		else if (power < -95)
+			*strength = 0;
+		else
+			*strength = (power + 95) * 255 / 140;
+
+		*strength |= *strength << 8;
+	} else {
+		ret = -1;
+	}
+
+	goto exit;
+
+err:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+exit:
+	if (ret)
+		warn("%s: failed: %d", __func__, ret);
+	return ret;
+}
+
+static const struct dvb_tuner_ops fc0013_tuner_ops = {
+	.info = {
+		.name		= "Fitipower FC0013",
+
+		.frequency_min	= 37000000,	/* estimate */
+		.frequency_max	= 1680000000,	/* CHECK */
+		.frequency_step	= 0,
+	},
+
+	.release	= fc0013_release,
+
+	.init		= fc0013_init,
+	.sleep		= fc0013_sleep,
+
+	.set_params	= fc0013_set_params,
+
+	.get_frequency	= fc0013_get_frequency,
+	.get_if_frequency = fc0013_get_if_frequency,
+	.get_bandwidth	= fc0013_get_bandwidth,
+
+	.get_rf_strength = fc0013_get_rf_strength,
+};
+
+struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c, u8 i2c_address, int dual_master,
+	enum fc001x_xtal_freq xtal_freq)
+{
+	struct fc0013_priv *priv = NULL;
+
+	priv = kzalloc(sizeof(struct fc0013_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->i2c = i2c;
+	priv->dual_master = dual_master;
+	priv->addr = i2c_address;
+	priv->xtal_freq = xtal_freq;
+
+	info("Fitipower FC0013 successfully attached.");
+
+	fe->tuner_priv = priv;
+
+	memcpy(&fe->ops.tuner_ops, &fc0013_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+
+	return fe;
+}
+EXPORT_SYMBOL(fc0013_attach);
+
+MODULE_DESCRIPTION("Fitipower FC0013 silicon tuner driver");
+MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.2");
diff --git a/drivers/media/tuners/fc0013.h b/drivers/media/tuners/fc0013.h
new file mode 100644
index 0000000..594efd6
--- /dev/null
+++ b/drivers/media/tuners/fc0013.h
@@ -0,0 +1,57 @@
+/*
+ * Fitipower FC0013 tuner driver
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.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.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _FC0013_H_
+#define _FC0013_H_
+
+#include "dvb_frontend.h"
+#include "fc001x-common.h"
+
+#if defined(CONFIG_MEDIA_TUNER_FC0013) || \
+	(defined(CONFIG_MEDIA_TUNER_FC0013_MODULE) && defined(MODULE))
+extern struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe,
+					struct i2c_adapter *i2c,
+					u8 i2c_address, int dual_master,
+					enum fc001x_xtal_freq xtal_freq);
+extern int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val);
+extern int fc0013_rc_cal_reset(struct dvb_frontend *fe);
+#else
+static inline struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe,
+					struct i2c_adapter *i2c,
+					u8 i2c_address, int dual_master,
+					enum fc001x_xtal_freq xtal_freq)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val)
+{
+	return 0;
+}
+
+static inline int fc0013_rc_cal_reset(struct dvb_frontend *fe)
+{
+	return 0;
+}
+#endif
+
+#endif
diff --git a/drivers/media/tuners/fc001x-common.h b/drivers/media/tuners/fc001x-common.h
new file mode 100644
index 0000000..7188181
--- /dev/null
+++ b/drivers/media/tuners/fc001x-common.h
@@ -0,0 +1,39 @@
+/*
+ * Fitipower FC0012 & FC0013 tuner driver - common defines
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _FC001X_COMMON_H_
+#define _FC001X_COMMON_H_
+
+enum fc001x_xtal_freq {
+	FC_XTAL_27_MHZ,		/* 27000000 */
+	FC_XTAL_28_8_MHZ,	/* 28800000 */
+	FC_XTAL_36_MHZ,		/* 36000000 */
+};
+
+/*
+ * enum fc001x_fe_callback_commands - Frontend callbacks
+ *
+ * @FC_FE_CALLBACK_VHF_ENABLE: enable VHF or UHF
+ */
+enum fc001x_fe_callback_commands {
+	FC_FE_CALLBACK_VHF_ENABLE,
+};
+
+#endif
diff --git a/drivers/media/tuners/max2165.c b/drivers/media/tuners/max2165.c
new file mode 100644
index 0000000..ba84936
--- /dev/null
+++ b/drivers/media/tuners/max2165.c
@@ -0,0 +1,433 @@
+/*
+ *  Driver for Maxim MAX2165 silicon tuner
+ *
+ *  Copyright (c) 2009 David T. L. Wong <davidtlwong@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+
+#include "max2165.h"
+#include "max2165_priv.h"
+#include "tuner-i2c.h"
+
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG "max2165: " args); \
+	} while (0)
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+static int max2165_write_reg(struct max2165_priv *priv, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
+
+	msg.addr = priv->config->i2c_address;
+
+	if (debug >= 2)
+		dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data);
+
+	ret = i2c_transfer(priv->i2c, &msg, 1);
+
+	if (ret != 1)
+		dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
+			__func__, reg, data, ret);
+
+	return (ret != 1) ? -EIO : 0;
+}
+
+static int max2165_read_reg(struct max2165_priv *priv, u8 reg, u8 *p_data)
+{
+	int ret;
+	u8 dev_addr = priv->config->i2c_address;
+
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{ .addr = dev_addr, .flags = 0, .buf = b0, .len = 1 },
+		{ .addr = dev_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 },
+	};
+
+	ret = i2c_transfer(priv->i2c, msg, 2);
+	if (ret != 2) {
+		dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret);
+		return -EIO;
+	}
+
+	*p_data = b1[0];
+	if (debug >= 2)
+		dprintk("%s: reg=0x%02X, data=0x%02X\n",
+			__func__, reg, b1[0]);
+	return 0;
+}
+
+static int max2165_mask_write_reg(struct max2165_priv *priv, u8 reg,
+	u8 mask, u8 data)
+{
+	int ret;
+	u8 v;
+
+	data &= mask;
+	ret = max2165_read_reg(priv, reg, &v);
+	if (ret != 0)
+		return ret;
+	v &= ~mask;
+	v |= data;
+	ret = max2165_write_reg(priv, reg, v);
+
+	return ret;
+}
+
+static int max2165_read_rom_table(struct max2165_priv *priv)
+{
+	u8 dat[3];
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		max2165_write_reg(priv, REG_ROM_TABLE_ADDR, i + 1);
+		max2165_read_reg(priv, REG_ROM_TABLE_DATA, &dat[i]);
+	}
+
+	priv->tf_ntch_low_cfg = dat[0] >> 4;
+	priv->tf_ntch_hi_cfg = dat[0] & 0x0F;
+	priv->tf_balun_low_ref = dat[1] & 0x0F;
+	priv->tf_balun_hi_ref = dat[1] >> 4;
+	priv->bb_filter_7mhz_cfg = dat[2] & 0x0F;
+	priv->bb_filter_8mhz_cfg = dat[2] >> 4;
+
+	dprintk("tf_ntch_low_cfg = 0x%X\n", priv->tf_ntch_low_cfg);
+	dprintk("tf_ntch_hi_cfg = 0x%X\n", priv->tf_ntch_hi_cfg);
+	dprintk("tf_balun_low_ref = 0x%X\n", priv->tf_balun_low_ref);
+	dprintk("tf_balun_hi_ref = 0x%X\n", priv->tf_balun_hi_ref);
+	dprintk("bb_filter_7mhz_cfg = 0x%X\n", priv->bb_filter_7mhz_cfg);
+	dprintk("bb_filter_8mhz_cfg = 0x%X\n", priv->bb_filter_8mhz_cfg);
+
+	return 0;
+}
+
+static int max2165_set_osc(struct max2165_priv *priv, u8 osc /*MHz*/)
+{
+	u8 v;
+
+	v = (osc / 2);
+	if (v == 2)
+		v = 0x7;
+	else
+		v -= 8;
+
+	max2165_mask_write_reg(priv, REG_PLL_CFG, 0x07, v);
+
+	return 0;
+}
+
+static int max2165_set_bandwidth(struct max2165_priv *priv, u32 bw)
+{
+	u8 val;
+
+	if (bw == 8000000)
+		val = priv->bb_filter_8mhz_cfg;
+	else
+		val = priv->bb_filter_7mhz_cfg;
+
+	max2165_mask_write_reg(priv, REG_BASEBAND_CTRL, 0xF0, val << 4);
+
+	return 0;
+}
+
+int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction)
+{
+	u32 remainder;
+	u32 q, f = 0;
+	int i;
+
+	if (0 == divisor)
+		return -EINVAL;
+
+	q = dividend / divisor;
+	remainder = dividend - q * divisor;
+
+	for (i = 0; i < 31; i++) {
+		remainder <<= 1;
+		if (remainder >= divisor) {
+			f += 1;
+			remainder -= divisor;
+		}
+		f <<= 1;
+	}
+
+	*quotient = q;
+	*fraction = f;
+
+	return 0;
+}
+
+static int max2165_set_rf(struct max2165_priv *priv, u32 freq)
+{
+	u8 tf;
+	u8 tf_ntch;
+	u32 t;
+	u32 quotient, fraction;
+	int ret;
+
+	/* Set PLL divider according to RF frequency */
+	ret = fixpt_div32(freq / 1000, priv->config->osc_clk * 1000,
+			 &quotient, &fraction);
+	if (ret != 0)
+		return ret;
+
+	/* 20-bit fraction */
+	fraction >>= 12;
+
+	max2165_write_reg(priv, REG_NDIV_INT, quotient);
+	max2165_mask_write_reg(priv, REG_NDIV_FRAC2, 0x0F, fraction >> 16);
+	max2165_write_reg(priv, REG_NDIV_FRAC1, fraction >> 8);
+	max2165_write_reg(priv, REG_NDIV_FRAC0, fraction);
+
+	/* Norch Filter */
+	tf_ntch = (freq < 725000000) ?
+		priv->tf_ntch_low_cfg : priv->tf_ntch_hi_cfg;
+
+	/* Tracking filter balun */
+	t = priv->tf_balun_low_ref;
+	t += (priv->tf_balun_hi_ref - priv->tf_balun_low_ref)
+		* (freq / 1000 - 470000) / (780000 - 470000);
+
+	tf = t;
+	dprintk("tf = %X\n", tf);
+	tf |= tf_ntch << 4;
+
+	max2165_write_reg(priv, REG_TRACK_FILTER, tf);
+
+	return 0;
+}
+
+static void max2165_debug_status(struct max2165_priv *priv)
+{
+	u8 status, autotune;
+	u8 auto_vco_success, auto_vco_active;
+	u8 pll_locked;
+	u8 dc_offset_low, dc_offset_hi;
+	u8 signal_lv_over_threshold;
+	u8 vco, vco_sub_band, adc;
+
+	max2165_read_reg(priv, REG_STATUS, &status);
+	max2165_read_reg(priv, REG_AUTOTUNE, &autotune);
+
+	auto_vco_success = (status >> 6) & 0x01;
+	auto_vco_active = (status >> 5) & 0x01;
+	pll_locked = (status >> 4) & 0x01;
+	dc_offset_low = (status >> 3) & 0x01;
+	dc_offset_hi = (status >> 2) & 0x01;
+	signal_lv_over_threshold = status & 0x01;
+
+	vco = autotune >> 6;
+	vco_sub_band = (autotune >> 3) & 0x7;
+	adc = autotune & 0x7;
+
+	dprintk("auto VCO active: %d, auto VCO success: %d\n",
+		auto_vco_active, auto_vco_success);
+	dprintk("PLL locked: %d\n", pll_locked);
+	dprintk("DC offset low: %d, DC offset high: %d\n",
+		dc_offset_low, dc_offset_hi);
+	dprintk("Signal lvl over threshold: %d\n", signal_lv_over_threshold);
+	dprintk("VCO: %d, VCO Sub-band: %d, ADC: %d\n", vco, vco_sub_band, adc);
+}
+
+static int max2165_set_params(struct dvb_frontend *fe)
+{
+	struct max2165_priv *priv = fe->tuner_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret;
+
+	switch (c->bandwidth_hz) {
+	case 7000000:
+	case 8000000:
+		priv->frequency = c->frequency;
+		break;
+	default:
+		printk(KERN_INFO "MAX2165: bandwidth %d Hz not supported.\n",
+		       c->bandwidth_hz);
+		return -EINVAL;
+	}
+
+	dprintk("%s() frequency=%d\n", __func__, c->frequency);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	max2165_set_bandwidth(priv, c->bandwidth_hz);
+	ret = max2165_set_rf(priv, priv->frequency);
+	mdelay(50);
+	max2165_debug_status(priv);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	if (ret != 0)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int max2165_get_frequency(struct dvb_frontend *fe, u32 *freq)
+{
+	struct max2165_priv *priv = fe->tuner_priv;
+	dprintk("%s()\n", __func__);
+	*freq = priv->frequency;
+	return 0;
+}
+
+static int max2165_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
+{
+	struct max2165_priv *priv = fe->tuner_priv;
+	dprintk("%s()\n", __func__);
+
+	*bw = priv->bandwidth;
+	return 0;
+}
+
+static int max2165_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct max2165_priv *priv = fe->tuner_priv;
+	u16 lock_status = 0;
+
+	dprintk("%s()\n", __func__);
+
+	if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+	max2165_debug_status(priv);
+	*status = lock_status;
+
+	if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return 0;
+}
+
+static int max2165_sleep(struct dvb_frontend *fe)
+{
+	dprintk("%s()\n", __func__);
+	return 0;
+}
+
+static int max2165_init(struct dvb_frontend *fe)
+{
+	struct max2165_priv *priv = fe->tuner_priv;
+	dprintk("%s()\n", __func__);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	/* Setup initial values */
+	/* Fractional Mode on */
+	max2165_write_reg(priv, REG_NDIV_FRAC2, 0x18);
+	/* LNA on */
+	max2165_write_reg(priv, REG_LNA, 0x01);
+	max2165_write_reg(priv, REG_PLL_CFG, 0x7A);
+	max2165_write_reg(priv, REG_TEST, 0x08);
+	max2165_write_reg(priv, REG_SHUTDOWN, 0x40);
+	max2165_write_reg(priv, REG_VCO_CTRL, 0x84);
+	max2165_write_reg(priv, REG_BASEBAND_CTRL, 0xC3);
+	max2165_write_reg(priv, REG_DC_OFFSET_CTRL, 0x75);
+	max2165_write_reg(priv, REG_DC_OFFSET_DAC, 0x00);
+	max2165_write_reg(priv, REG_ROM_TABLE_ADDR, 0x00);
+
+	max2165_set_osc(priv, priv->config->osc_clk);
+
+	max2165_read_rom_table(priv);
+
+	max2165_set_bandwidth(priv, 8000000);
+
+	if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return 0;
+}
+
+static int max2165_release(struct dvb_frontend *fe)
+{
+	struct max2165_priv *priv = fe->tuner_priv;
+	dprintk("%s()\n", __func__);
+
+	kfree(priv);
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static const struct dvb_tuner_ops max2165_tuner_ops = {
+	.info = {
+		.name           = "Maxim MAX2165",
+		.frequency_min  = 470000000,
+		.frequency_max  = 780000000,
+		.frequency_step =     50000,
+	},
+
+	.release	   = max2165_release,
+	.init		   = max2165_init,
+	.sleep		   = max2165_sleep,
+
+	.set_params	   = max2165_set_params,
+	.set_analog_params = NULL,
+	.get_frequency	   = max2165_get_frequency,
+	.get_bandwidth	   = max2165_get_bandwidth,
+	.get_status	   = max2165_get_status
+};
+
+struct dvb_frontend *max2165_attach(struct dvb_frontend *fe,
+				   struct i2c_adapter *i2c,
+				   struct max2165_config *cfg)
+{
+	struct max2165_priv *priv = NULL;
+
+	dprintk("%s(%d-%04x)\n", __func__,
+		i2c ? i2c_adapter_id(i2c) : -1,
+		cfg ? cfg->i2c_address : -1);
+
+	priv = kzalloc(sizeof(struct max2165_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	memcpy(&fe->ops.tuner_ops, &max2165_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+
+	priv->config = cfg;
+	priv->i2c = i2c;
+	fe->tuner_priv = priv;
+
+	max2165_init(fe);
+	max2165_debug_status(priv);
+
+	return fe;
+}
+EXPORT_SYMBOL(max2165_attach);
+
+MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
+MODULE_DESCRIPTION("Maxim MAX2165 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/max2165.h b/drivers/media/tuners/max2165.h
new file mode 100644
index 0000000..c063c36
--- /dev/null
+++ b/drivers/media/tuners/max2165.h
@@ -0,0 +1,48 @@
+/*
+ *  Driver for Maxim MAX2165 silicon tuner
+ *
+ *  Copyright (c) 2009 David T. L. Wong <davidtlwong@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MAX2165_H__
+#define __MAX2165_H__
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct max2165_config {
+	u8 i2c_address;
+	u8 osc_clk; /* in MHz, selectable values: 4,16,18,20,22,24,26,28 */
+};
+
+#if defined(CONFIG_MEDIA_TUNER_MAX2165) || \
+    (defined(CONFIG_MEDIA_TUNER_MAX2165_MODULE) && defined(MODULE))
+extern struct dvb_frontend *max2165_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c,
+	struct max2165_config *cfg);
+#else
+static inline struct dvb_frontend *max2165_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c,
+	struct max2165_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/tuners/max2165_priv.h b/drivers/media/tuners/max2165_priv.h
new file mode 100644
index 0000000..91bbe02
--- /dev/null
+++ b/drivers/media/tuners/max2165_priv.h
@@ -0,0 +1,60 @@
+/*
+ *  Driver for Maxim MAX2165 silicon tuner
+ *
+ *  Copyright (c) 2009 David T. L. Wong <davidtlwong@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MAX2165_PRIV_H__
+#define __MAX2165_PRIV_H__
+
+#define REG_NDIV_INT 0x00
+#define REG_NDIV_FRAC2 0x01
+#define REG_NDIV_FRAC1 0x02
+#define REG_NDIV_FRAC0 0x03
+#define REG_TRACK_FILTER 0x04
+#define REG_LNA 0x05
+#define REG_PLL_CFG 0x06
+#define REG_TEST 0x07
+#define REG_SHUTDOWN 0x08
+#define REG_VCO_CTRL 0x09
+#define REG_BASEBAND_CTRL 0x0A
+#define REG_DC_OFFSET_CTRL 0x0B
+#define REG_DC_OFFSET_DAC 0x0C
+#define REG_ROM_TABLE_ADDR 0x0D
+
+/* Read Only Registers */
+#define REG_ROM_TABLE_DATA 0x10
+#define REG_STATUS 0x11
+#define REG_AUTOTUNE 0x12
+
+struct max2165_priv {
+	struct max2165_config *config;
+	struct i2c_adapter *i2c;
+
+	u32 frequency;
+	u32 bandwidth;
+
+	u8 tf_ntch_low_cfg;
+	u8 tf_ntch_hi_cfg;
+	u8 tf_balun_low_ref;
+	u8 tf_balun_hi_ref;
+	u8 bb_filter_7mhz_cfg;
+	u8 bb_filter_8mhz_cfg;
+};
+
+#endif
diff --git a/drivers/media/tuners/mc44s803.c b/drivers/media/tuners/mc44s803.c
new file mode 100644
index 0000000..5ddce7e
--- /dev/null
+++ b/drivers/media/tuners/mc44s803.c
@@ -0,0 +1,372 @@
+/*
+ *  Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
+ *
+ *  Copyright (c) 2009 Jochen Friedrich <jochen@scram.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+
+#include "mc44s803.h"
+#include "mc44s803_priv.h"
+
+#define mc_printk(level, format, arg...)	\
+	printk(level "mc44s803: " format , ## arg)
+
+/* Writes a single register */
+static int mc44s803_writereg(struct mc44s803_priv *priv, u32 val)
+{
+	u8 buf[3];
+	struct i2c_msg msg = {
+		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 3
+	};
+
+	buf[0] = (val & 0xff0000) >> 16;
+	buf[1] = (val & 0xff00) >> 8;
+	buf[2] = (val & 0xff);
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		mc_printk(KERN_WARNING, "I2C write failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+/* Reads a single register */
+static int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val)
+{
+	u32 wval;
+	u8 buf[3];
+	int ret;
+	struct i2c_msg msg[] = {
+		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
+		  .buf = buf, .len = 3 },
+	};
+
+	wval = MC44S803_REG_SM(MC44S803_REG_DATAREG, MC44S803_ADDR) |
+	       MC44S803_REG_SM(reg, MC44S803_D);
+
+	ret = mc44s803_writereg(priv, wval);
+	if (ret)
+		return ret;
+
+	if (i2c_transfer(priv->i2c, msg, 1) != 1) {
+		mc_printk(KERN_WARNING, "I2C read failed\n");
+		return -EREMOTEIO;
+	}
+
+	*val = (buf[0] << 16) | (buf[1] << 8) | buf[2];
+
+	return 0;
+}
+
+static int mc44s803_release(struct dvb_frontend *fe)
+{
+	struct mc44s803_priv *priv = fe->tuner_priv;
+
+	fe->tuner_priv = NULL;
+	kfree(priv);
+
+	return 0;
+}
+
+static int mc44s803_init(struct dvb_frontend *fe)
+{
+	struct mc44s803_priv *priv = fe->tuner_priv;
+	u32 val;
+	int err;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+/* Reset chip */
+	val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR) |
+	      MC44S803_REG_SM(1, MC44S803_RS);
+
+	err = mc44s803_writereg(priv, val);
+	if (err)
+		goto exit;
+
+	val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR);
+
+	err = mc44s803_writereg(priv, val);
+	if (err)
+		goto exit;
+
+/* Power Up and Start Osc */
+
+	val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
+	      MC44S803_REG_SM(0xC0, MC44S803_REFOSC) |
+	      MC44S803_REG_SM(1, MC44S803_OSCSEL);
+
+	err = mc44s803_writereg(priv, val);
+	if (err)
+		goto exit;
+
+	val = MC44S803_REG_SM(MC44S803_REG_POWER, MC44S803_ADDR) |
+	      MC44S803_REG_SM(0x200, MC44S803_POWER);
+
+	err = mc44s803_writereg(priv, val);
+	if (err)
+		goto exit;
+
+	msleep(10);
+
+	val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
+	      MC44S803_REG_SM(0x40, MC44S803_REFOSC) |
+	      MC44S803_REG_SM(1, MC44S803_OSCSEL);
+
+	err = mc44s803_writereg(priv, val);
+	if (err)
+		goto exit;
+
+	msleep(20);
+
+/* Setup Mixer */
+
+	val = MC44S803_REG_SM(MC44S803_REG_MIXER, MC44S803_ADDR) |
+	      MC44S803_REG_SM(1, MC44S803_TRI_STATE) |
+	      MC44S803_REG_SM(0x7F, MC44S803_MIXER_RES);
+
+	err = mc44s803_writereg(priv, val);
+	if (err)
+		goto exit;
+
+/* Setup Cirquit Adjust */
+
+	val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
+	      MC44S803_REG_SM(1, MC44S803_G1) |
+	      MC44S803_REG_SM(1, MC44S803_G3) |
+	      MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
+	      MC44S803_REG_SM(1, MC44S803_G6) |
+	      MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
+	      MC44S803_REG_SM(0x3, MC44S803_LP) |
+	      MC44S803_REG_SM(1, MC44S803_CLRF) |
+	      MC44S803_REG_SM(1, MC44S803_CLIF);
+
+	err = mc44s803_writereg(priv, val);
+	if (err)
+		goto exit;
+
+	val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
+	      MC44S803_REG_SM(1, MC44S803_G1) |
+	      MC44S803_REG_SM(1, MC44S803_G3) |
+	      MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
+	      MC44S803_REG_SM(1, MC44S803_G6) |
+	      MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
+	      MC44S803_REG_SM(0x3, MC44S803_LP);
+
+	err = mc44s803_writereg(priv, val);
+	if (err)
+		goto exit;
+
+/* Setup Digtune */
+
+	val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
+	      MC44S803_REG_SM(3, MC44S803_XOD);
+
+	err = mc44s803_writereg(priv, val);
+	if (err)
+		goto exit;
+
+/* Setup AGC */
+
+	val = MC44S803_REG_SM(MC44S803_REG_LNAAGC, MC44S803_ADDR) |
+	      MC44S803_REG_SM(1, MC44S803_AT1) |
+	      MC44S803_REG_SM(1, MC44S803_AT2) |
+	      MC44S803_REG_SM(1, MC44S803_AGC_AN_DIG) |
+	      MC44S803_REG_SM(1, MC44S803_AGC_READ_EN) |
+	      MC44S803_REG_SM(1, MC44S803_LNA0);
+
+	err = mc44s803_writereg(priv, val);
+	if (err)
+		goto exit;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+	return 0;
+
+exit:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	mc_printk(KERN_WARNING, "I/O Error\n");
+	return err;
+}
+
+static int mc44s803_set_params(struct dvb_frontend *fe)
+{
+	struct mc44s803_priv *priv = fe->tuner_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 r1, r2, n1, n2, lo1, lo2, freq, val;
+	int err;
+
+	priv->frequency = c->frequency;
+
+	r1 = MC44S803_OSC / 1000000;
+	r2 = MC44S803_OSC /  100000;
+
+	n1 = (c->frequency + MC44S803_IF1 + 500000) / 1000000;
+	freq = MC44S803_OSC / r1 * n1;
+	lo1 = ((60 * n1) + (r1 / 2)) / r1;
+	freq = freq - c->frequency;
+
+	n2 = (freq - MC44S803_IF2 + 50000) / 100000;
+	lo2 = ((60 * n2) + (r2 / 2)) / r2;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	val = MC44S803_REG_SM(MC44S803_REG_REFDIV, MC44S803_ADDR) |
+	      MC44S803_REG_SM(r1-1, MC44S803_R1) |
+	      MC44S803_REG_SM(r2-1, MC44S803_R2) |
+	      MC44S803_REG_SM(1, MC44S803_REFBUF_EN);
+
+	err = mc44s803_writereg(priv, val);
+	if (err)
+		goto exit;
+
+	val = MC44S803_REG_SM(MC44S803_REG_LO1, MC44S803_ADDR) |
+	      MC44S803_REG_SM(n1-2, MC44S803_LO1);
+
+	err = mc44s803_writereg(priv, val);
+	if (err)
+		goto exit;
+
+	val = MC44S803_REG_SM(MC44S803_REG_LO2, MC44S803_ADDR) |
+	      MC44S803_REG_SM(n2-2, MC44S803_LO2);
+
+	err = mc44s803_writereg(priv, val);
+	if (err)
+		goto exit;
+
+	val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
+	      MC44S803_REG_SM(1, MC44S803_DA) |
+	      MC44S803_REG_SM(lo1, MC44S803_LO_REF) |
+	      MC44S803_REG_SM(1, MC44S803_AT);
+
+	err = mc44s803_writereg(priv, val);
+	if (err)
+		goto exit;
+
+	val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
+	      MC44S803_REG_SM(2, MC44S803_DA) |
+	      MC44S803_REG_SM(lo2, MC44S803_LO_REF) |
+	      MC44S803_REG_SM(1, MC44S803_AT);
+
+	err = mc44s803_writereg(priv, val);
+	if (err)
+		goto exit;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return 0;
+
+exit:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	mc_printk(KERN_WARNING, "I/O Error\n");
+	return err;
+}
+
+static int mc44s803_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct mc44s803_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static const struct dvb_tuner_ops mc44s803_tuner_ops = {
+	.info = {
+		.name           = "Freescale MC44S803",
+		.frequency_min  =   48000000,
+		.frequency_max  = 1000000000,
+		.frequency_step =     100000,
+	},
+
+	.release       = mc44s803_release,
+	.init          = mc44s803_init,
+	.set_params    = mc44s803_set_params,
+	.get_frequency = mc44s803_get_frequency
+};
+
+/* This functions tries to identify a MC44S803 tuner by reading the ID
+   register. This is hasty. */
+struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
+	 struct i2c_adapter *i2c, struct mc44s803_config *cfg)
+{
+	struct mc44s803_priv *priv;
+	u32 reg;
+	u8 id;
+	int ret;
+
+	reg = 0;
+
+	priv = kzalloc(sizeof(struct mc44s803_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->cfg = cfg;
+	priv->i2c = i2c;
+	priv->fe  = fe;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	ret = mc44s803_readreg(priv, MC44S803_REG_ID, &reg);
+	if (ret)
+		goto error;
+
+	id = MC44S803_REG_MS(reg, MC44S803_ID);
+
+	if (id != 0x14) {
+		mc_printk(KERN_ERR, "unsupported ID "
+		       "(%x should be 0x14)\n", id);
+		goto error;
+	}
+
+	mc_printk(KERN_INFO, "successfully identified (ID = %x)\n", id);
+	memcpy(&fe->ops.tuner_ops, &mc44s803_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	return fe;
+
+error:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	kfree(priv);
+	return NULL;
+}
+EXPORT_SYMBOL(mc44s803_attach);
+
+MODULE_AUTHOR("Jochen Friedrich");
+MODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/mc44s803.h b/drivers/media/tuners/mc44s803.h
new file mode 100644
index 0000000..34f3892
--- /dev/null
+++ b/drivers/media/tuners/mc44s803.h
@@ -0,0 +1,46 @@
+/*
+ *  Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
+ *
+ *  Copyright (c) 2009 Jochen Friedrich <jochen@scram.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef MC44S803_H
+#define MC44S803_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct mc44s803_config {
+	u8 i2c_address;
+	u8 dig_out;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_MC44S803) || \
+    (defined(CONFIG_MEDIA_TUNER_MC44S803_MODULE) && defined(MODULE))
+extern struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
+	 struct i2c_adapter *i2c, struct mc44s803_config *cfg);
+#else
+static inline struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
+	 struct i2c_adapter *i2c, struct mc44s803_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_MEDIA_TUNER_MC44S803 */
+
+#endif
diff --git a/drivers/media/tuners/mc44s803_priv.h b/drivers/media/tuners/mc44s803_priv.h
new file mode 100644
index 0000000..14a9278
--- /dev/null
+++ b/drivers/media/tuners/mc44s803_priv.h
@@ -0,0 +1,208 @@
+/*
+ *  Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
+ *
+ *  Copyright (c) 2009 Jochen Friedrich <jochen@scram.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef MC44S803_PRIV_H
+#define MC44S803_PRIV_H
+
+/* This driver is based on the information available in the datasheet
+   http://www.freescale.com/files/rf_if/doc/data_sheet/MC44S803.pdf
+
+   SPI or I2C Address : 0xc0-0xc6
+
+   Reg.No | Function
+   -------------------------------------------
+       00 | Power Down
+       01 | Reference Oszillator
+       02 | Reference Dividers
+       03 | Mixer and Reference Buffer
+       04 | Reset/Serial Out
+       05 | LO 1
+       06 | LO 2
+       07 | Circuit Adjust
+       08 | Test
+       09 | Digital Tune
+       0A | LNA AGC
+       0B | Data Register Address
+       0C | Regulator Test
+       0D | VCO Test
+       0E | LNA Gain/Input Power
+       0F | ID Bits
+
+*/
+
+#define MC44S803_OSC 26000000	/* 26 MHz */
+#define MC44S803_IF1 1086000000 /* 1086 MHz */
+#define MC44S803_IF2 36125000	/* 36.125 MHz */
+
+#define MC44S803_REG_POWER	0
+#define MC44S803_REG_REFOSC	1
+#define MC44S803_REG_REFDIV	2
+#define MC44S803_REG_MIXER	3
+#define MC44S803_REG_RESET	4
+#define MC44S803_REG_LO1	5
+#define MC44S803_REG_LO2	6
+#define MC44S803_REG_CIRCADJ	7
+#define MC44S803_REG_TEST	8
+#define MC44S803_REG_DIGTUNE	9
+#define MC44S803_REG_LNAAGC	0x0A
+#define MC44S803_REG_DATAREG	0x0B
+#define MC44S803_REG_REGTEST	0x0C
+#define MC44S803_REG_VCOTEST	0x0D
+#define MC44S803_REG_LNAGAIN	0x0E
+#define MC44S803_REG_ID		0x0F
+
+/* Register definitions */
+#define MC44S803_ADDR		0x0F
+#define MC44S803_ADDR_S		0
+/* REG_POWER */
+#define MC44S803_POWER		0xFFFFF0
+#define MC44S803_POWER_S	4
+/* REG_REFOSC */
+#define MC44S803_REFOSC		0x1FF0
+#define MC44S803_REFOSC_S	4
+#define MC44S803_OSCSEL		0x2000
+#define MC44S803_OSCSEL_S	13
+/* REG_REFDIV */
+#define MC44S803_R2		0x1FF0
+#define MC44S803_R2_S		4
+#define MC44S803_REFBUF_EN	0x2000
+#define MC44S803_REFBUF_EN_S	13
+#define MC44S803_R1		0x7C000
+#define MC44S803_R1_S		14
+/* REG_MIXER */
+#define MC44S803_R3		0x70
+#define MC44S803_R3_S		4
+#define MC44S803_MUX3		0x80
+#define MC44S803_MUX3_S		7
+#define MC44S803_MUX4		0x100
+#define MC44S803_MUX4_S		8
+#define MC44S803_OSC_SCR	0x200
+#define MC44S803_OSC_SCR_S	9
+#define MC44S803_TRI_STATE	0x400
+#define MC44S803_TRI_STATE_S	10
+#define MC44S803_BUF_GAIN	0x800
+#define MC44S803_BUF_GAIN_S	11
+#define MC44S803_BUF_IO		0x1000
+#define MC44S803_BUF_IO_S	12
+#define MC44S803_MIXER_RES	0xFE000
+#define MC44S803_MIXER_RES_S	13
+/* REG_RESET */
+#define MC44S803_RS		0x10
+#define MC44S803_RS_S		4
+#define MC44S803_SO		0x20
+#define MC44S803_SO_S		5
+/* REG_LO1 */
+#define MC44S803_LO1		0xFFF0
+#define MC44S803_LO1_S		4
+/* REG_LO2 */
+#define MC44S803_LO2		0x7FFF0
+#define MC44S803_LO2_S		4
+/* REG_CIRCADJ */
+#define MC44S803_G1		0x20
+#define MC44S803_G1_S		5
+#define MC44S803_G3		0x80
+#define MC44S803_G3_S		7
+#define MC44S803_CIRCADJ_RES	0x300
+#define MC44S803_CIRCADJ_RES_S	8
+#define MC44S803_G6		0x400
+#define MC44S803_G6_S		10
+#define MC44S803_G7		0x800
+#define MC44S803_G7_S		11
+#define MC44S803_S1		0x1000
+#define MC44S803_S1_S		12
+#define MC44S803_LP		0x7E000
+#define MC44S803_LP_S		13
+#define MC44S803_CLRF		0x80000
+#define MC44S803_CLRF_S		19
+#define MC44S803_CLIF		0x100000
+#define MC44S803_CLIF_S		20
+/* REG_TEST */
+/* REG_DIGTUNE */
+#define MC44S803_DA		0xF0
+#define MC44S803_DA_S		4
+#define MC44S803_XOD		0x300
+#define MC44S803_XOD_S		8
+#define MC44S803_RST		0x10000
+#define MC44S803_RST_S		16
+#define MC44S803_LO_REF		0x1FFF00
+#define MC44S803_LO_REF_S	8
+#define MC44S803_AT		0x200000
+#define MC44S803_AT_S		21
+#define MC44S803_MT		0x400000
+#define MC44S803_MT_S		22
+/* REG_LNAAGC */
+#define MC44S803_G		0x3F0
+#define MC44S803_G_S		4
+#define MC44S803_AT1		0x400
+#define MC44S803_AT1_S		10
+#define MC44S803_AT2		0x800
+#define MC44S803_AT2_S		11
+#define MC44S803_HL_GR_EN	0x8000
+#define MC44S803_HL_GR_EN_S	15
+#define MC44S803_AGC_AN_DIG	0x10000
+#define MC44S803_AGC_AN_DIG_S	16
+#define MC44S803_ATTEN_EN	0x20000
+#define MC44S803_ATTEN_EN_S	17
+#define MC44S803_AGC_READ_EN	0x40000
+#define MC44S803_AGC_READ_EN_S	18
+#define MC44S803_LNA0		0x80000
+#define MC44S803_LNA0_S		19
+#define MC44S803_AGC_SEL	0x100000
+#define MC44S803_AGC_SEL_S	20
+#define MC44S803_AT0		0x200000
+#define MC44S803_AT0_S		21
+#define MC44S803_B		0xC00000
+#define MC44S803_B_S		22
+/* REG_DATAREG */
+#define MC44S803_D		0xF0
+#define MC44S803_D_S		4
+/* REG_REGTEST */
+/* REG_VCOTEST */
+/* REG_LNAGAIN */
+#define MC44S803_IF_PWR		0x700
+#define MC44S803_IF_PWR_S	8
+#define MC44S803_RF_PWR		0x3800
+#define MC44S803_RF_PWR_S	11
+#define MC44S803_LNA_GAIN	0xFC000
+#define MC44S803_LNA_GAIN_S	14
+/* REG_ID */
+#define MC44S803_ID		0x3E00
+#define MC44S803_ID_S		9
+
+/* Some macros to read/write fields */
+
+/* First shift, then mask */
+#define MC44S803_REG_SM(_val, _reg)					\
+	(((_val) << _reg##_S) & (_reg))
+
+/* First mask, then shift */
+#define MC44S803_REG_MS(_val, _reg)					\
+	(((_val) & (_reg)) >> _reg##_S)
+
+struct mc44s803_priv {
+	struct mc44s803_config *cfg;
+	struct i2c_adapter *i2c;
+	struct dvb_frontend *fe;
+
+	u32 frequency;
+};
+
+#endif
diff --git a/drivers/media/tuners/mt2060.c b/drivers/media/tuners/mt2060.c
new file mode 100644
index 0000000..13381de
--- /dev/null
+++ b/drivers/media/tuners/mt2060.c
@@ -0,0 +1,403 @@
+/*
+ *  Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
+ *
+ *  Copyright (c) 2006 Olivier DANET <odanet@caramail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+/* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+
+#include "mt2060.h"
+#include "mt2060_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2060: " args); printk("\n"); }} while (0)
+
+// Reads a single register
+static int mt2060_readreg(struct mt2060_priv *priv, u8 reg, u8 *val)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
+		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val,  .len = 1 },
+	};
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		printk(KERN_WARNING "mt2060 I2C read failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+// Writes a single register
+static int mt2060_writereg(struct mt2060_priv *priv, u8 reg, u8 val)
+{
+	u8 buf[2] = { reg, val };
+	struct i2c_msg msg = {
+		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
+	};
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "mt2060 I2C write failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+// Writes a set of consecutive registers
+static int mt2060_writeregs(struct mt2060_priv *priv,u8 *buf, u8 len)
+{
+	struct i2c_msg msg = {
+		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len
+	};
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n",(int)len);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+// Initialisation sequences
+// LNABAND=3, NUM1=0x3C, DIV1=0x74, NUM2=0x1080, DIV2=0x49
+static u8 mt2060_config1[] = {
+	REG_LO1C1,
+	0x3F,	0x74,	0x00,	0x08,	0x93
+};
+
+// FMCG=2, GP2=0, GP1=0
+static u8 mt2060_config2[] = {
+	REG_MISC_CTRL,
+	0x20,	0x1E,	0x30,	0xff,	0x80,	0xff,	0x00,	0x2c,	0x42
+};
+
+//  VGAG=3, V1CSE=1
+
+#ifdef  MT2060_SPURCHECK
+/* The function below calculates the frequency offset between the output frequency if2
+ and the closer cross modulation subcarrier between lo1 and lo2 up to the tenth harmonic */
+static int mt2060_spurcalc(u32 lo1,u32 lo2,u32 if2)
+{
+	int I,J;
+	int dia,diamin,diff;
+	diamin=1000000;
+	for (I = 1; I < 10; I++) {
+		J = ((2*I*lo1)/lo2+1)/2;
+		diff = I*(int)lo1-J*(int)lo2;
+		if (diff < 0) diff=-diff;
+		dia = (diff-(int)if2);
+		if (dia < 0) dia=-dia;
+		if (diamin > dia) diamin=dia;
+	}
+	return diamin;
+}
+
+#define BANDWIDTH 4000 // kHz
+
+/* Calculates the frequency offset to add to avoid spurs. Returns 0 if no offset is needed */
+static int mt2060_spurcheck(u32 lo1,u32 lo2,u32 if2)
+{
+	u32 Spur,Sp1,Sp2;
+	int I,J;
+	I=0;
+	J=1000;
+
+	Spur=mt2060_spurcalc(lo1,lo2,if2);
+	if (Spur < BANDWIDTH) {
+		/* Potential spurs detected */
+		dprintk("Spurs before : f_lo1: %d  f_lo2: %d  (kHz)",
+			(int)lo1,(int)lo2);
+		I=1000;
+		Sp1 = mt2060_spurcalc(lo1+I,lo2+I,if2);
+		Sp2 = mt2060_spurcalc(lo1-I,lo2-I,if2);
+
+		if (Sp1 < Sp2) {
+			J=-J; I=-I; Spur=Sp2;
+		} else
+			Spur=Sp1;
+
+		while (Spur < BANDWIDTH) {
+			I += J;
+			Spur = mt2060_spurcalc(lo1+I,lo2+I,if2);
+		}
+		dprintk("Spurs after  : f_lo1: %d  f_lo2: %d  (kHz)",
+			(int)(lo1+I),(int)(lo2+I));
+	}
+	return I;
+}
+#endif
+
+#define IF2  36150       // IF2 frequency = 36.150 MHz
+#define FREF 16000       // Quartz oscillator 16 MHz
+
+static int mt2060_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct mt2060_priv *priv;
+	int ret=0;
+	int i=0;
+	u32 freq;
+	u8  lnaband;
+	u32 f_lo1,f_lo2;
+	u32 div1,num1,div2,num2;
+	u8  b[8];
+	u32 if1;
+
+	priv = fe->tuner_priv;
+
+	if1 = priv->if1_freq;
+	b[0] = REG_LO1B1;
+	b[1] = 0xFF;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	mt2060_writeregs(priv,b,2);
+
+	freq = c->frequency / 1000; /* Hz -> kHz */
+
+	f_lo1 = freq + if1 * 1000;
+	f_lo1 = (f_lo1 / 250) * 250;
+	f_lo2 = f_lo1 - freq - IF2;
+	// From the Comtech datasheet, the step used is 50kHz. The tuner chip could be more precise
+	f_lo2 = ((f_lo2 + 25) / 50) * 50;
+	priv->frequency =  (f_lo1 - f_lo2 - IF2) * 1000,
+
+#ifdef MT2060_SPURCHECK
+	// LO-related spurs detection and correction
+	num1   = mt2060_spurcheck(f_lo1,f_lo2,IF2);
+	f_lo1 += num1;
+	f_lo2 += num1;
+#endif
+	//Frequency LO1 = 16MHz * (DIV1 + NUM1/64 )
+	num1 = f_lo1 / (FREF / 64);
+	div1 = num1 / 64;
+	num1 &= 0x3f;
+
+	// Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 )
+	num2 = f_lo2 * 64 / (FREF / 128);
+	div2 = num2 / 8192;
+	num2 &= 0x1fff;
+
+	if (freq <=  95000) lnaband = 0xB0; else
+	if (freq <= 180000) lnaband = 0xA0; else
+	if (freq <= 260000) lnaband = 0x90; else
+	if (freq <= 335000) lnaband = 0x80; else
+	if (freq <= 425000) lnaband = 0x70; else
+	if (freq <= 480000) lnaband = 0x60; else
+	if (freq <= 570000) lnaband = 0x50; else
+	if (freq <= 645000) lnaband = 0x40; else
+	if (freq <= 730000) lnaband = 0x30; else
+	if (freq <= 810000) lnaband = 0x20; else lnaband = 0x10;
+
+	b[0] = REG_LO1C1;
+	b[1] = lnaband | ((num1 >>2) & 0x0F);
+	b[2] = div1;
+	b[3] = (num2 & 0x0F)  | ((num1 & 3) << 4);
+	b[4] = num2 >> 4;
+	b[5] = ((num2 >>12) & 1) | (div2 << 1);
+
+	dprintk("IF1: %dMHz",(int)if1);
+	dprintk("PLL freq=%dkHz  f_lo1=%dkHz  f_lo2=%dkHz",(int)freq,(int)f_lo1,(int)f_lo2);
+	dprintk("PLL div1=%d  num1=%d  div2=%d  num2=%d",(int)div1,(int)num1,(int)div2,(int)num2);
+	dprintk("PLL [1..5]: %2x %2x %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3],(int)b[4],(int)b[5]);
+
+	mt2060_writeregs(priv,b,6);
+
+	//Waits for pll lock or timeout
+	i = 0;
+	do {
+		mt2060_readreg(priv,REG_LO_STATUS,b);
+		if ((b[0] & 0x88)==0x88)
+			break;
+		msleep(4);
+		i++;
+	} while (i<10);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	return ret;
+}
+
+static void mt2060_calibrate(struct mt2060_priv *priv)
+{
+	u8 b = 0;
+	int i = 0;
+
+	if (mt2060_writeregs(priv,mt2060_config1,sizeof(mt2060_config1)))
+		return;
+	if (mt2060_writeregs(priv,mt2060_config2,sizeof(mt2060_config2)))
+		return;
+
+	/* initialize the clock output */
+	mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30);
+
+	do {
+		b |= (1 << 6); // FM1SS;
+		mt2060_writereg(priv, REG_LO2C1,b);
+		msleep(20);
+
+		if (i == 0) {
+			b |= (1 << 7); // FM1CA;
+			mt2060_writereg(priv, REG_LO2C1,b);
+			b &= ~(1 << 7); // FM1CA;
+			msleep(20);
+		}
+
+		b &= ~(1 << 6); // FM1SS
+		mt2060_writereg(priv, REG_LO2C1,b);
+
+		msleep(20);
+		i++;
+	} while (i < 9);
+
+	i = 0;
+	while (i++ < 10 && mt2060_readreg(priv, REG_MISC_STAT, &b) == 0 && (b & (1 << 6)) == 0)
+		msleep(20);
+
+	if (i <= 10) {
+		mt2060_readreg(priv, REG_FM_FREQ, &priv->fmfreq); // now find out, what is fmreq used for :)
+		dprintk("calibration was successful: %d", (int)priv->fmfreq);
+	} else
+		dprintk("FMCAL timed out");
+}
+
+static int mt2060_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct mt2060_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int mt2060_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	*frequency = IF2 * 1000;
+	return 0;
+}
+
+static int mt2060_init(struct dvb_frontend *fe)
+{
+	struct mt2060_priv *priv = fe->tuner_priv;
+	int ret;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	ret = mt2060_writereg(priv, REG_VGAG,
+			      (priv->cfg->clock_out << 6) | 0x33);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	return ret;
+}
+
+static int mt2060_sleep(struct dvb_frontend *fe)
+{
+	struct mt2060_priv *priv = fe->tuner_priv;
+	int ret;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	ret = mt2060_writereg(priv, REG_VGAG,
+			      (priv->cfg->clock_out << 6) | 0x30);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	return ret;
+}
+
+static int mt2060_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static const struct dvb_tuner_ops mt2060_tuner_ops = {
+	.info = {
+		.name           = "Microtune MT2060",
+		.frequency_min  =  48000000,
+		.frequency_max  = 860000000,
+		.frequency_step =     50000,
+	},
+
+	.release       = mt2060_release,
+
+	.init          = mt2060_init,
+	.sleep         = mt2060_sleep,
+
+	.set_params    = mt2060_set_params,
+	.get_frequency = mt2060_get_frequency,
+	.get_if_frequency = mt2060_get_if_frequency,
+};
+
+/* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */
+struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1)
+{
+	struct mt2060_priv *priv = NULL;
+	u8 id = 0;
+
+	priv = kzalloc(sizeof(struct mt2060_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->cfg      = cfg;
+	priv->i2c      = i2c;
+	priv->if1_freq = if1;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) {
+		kfree(priv);
+		return NULL;
+	}
+
+	if (id != PART_REV) {
+		kfree(priv);
+		return NULL;
+	}
+	printk(KERN_INFO "MT2060: successfully identified (IF1 = %d)\n", if1);
+	memcpy(&fe->ops.tuner_ops, &mt2060_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+
+	mt2060_calibrate(priv);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	return fe;
+}
+EXPORT_SYMBOL(mt2060_attach);
+
+MODULE_AUTHOR("Olivier DANET");
+MODULE_DESCRIPTION("Microtune MT2060 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/mt2060.h b/drivers/media/tuners/mt2060.h
new file mode 100644
index 0000000..cb60caf
--- /dev/null
+++ b/drivers/media/tuners/mt2060.h
@@ -0,0 +1,43 @@
+/*
+ *  Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
+ *
+ *  Copyright (c) 2006 Olivier DANET <odanet@caramail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef MT2060_H
+#define MT2060_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct mt2060_config {
+	u8 i2c_address;
+	u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
+};
+
+#if defined(CONFIG_MEDIA_TUNER_MT2060) || (defined(CONFIG_MEDIA_TUNER_MT2060_MODULE) && defined(MODULE))
+extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1);
+#else
+static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_MEDIA_TUNER_MT2060
+
+#endif
diff --git a/drivers/media/tuners/mt2060_priv.h b/drivers/media/tuners/mt2060_priv.h
new file mode 100644
index 0000000..2b60de6
--- /dev/null
+++ b/drivers/media/tuners/mt2060_priv.h
@@ -0,0 +1,104 @@
+/*
+ *  Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
+ *
+ *  Copyright (c) 2006 Olivier DANET <odanet@caramail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef MT2060_PRIV_H
+#define MT2060_PRIV_H
+
+// Uncomment the #define below to enable spurs checking. The results where quite unconvincing.
+// #define MT2060_SPURCHECK
+
+/* This driver is based on the information available in the datasheet of the
+   "Comtech SDVBT-3K6M" tuner ( K1000737843.pdf ) which features the MT2060 register map :
+
+   I2C Address : 0x60
+
+   Reg.No |   B7   |   B6   |   B5   |   B4   |   B3   |   B2   |   B1   |   B0   | ( defaults )
+   --------------------------------------------------------------------------------
+       00 | [              PART             ] | [              REV              ] | R  = 0x63
+       01 | [             LNABAND           ] | [              NUM1(5:2)        ] | RW = 0x3F
+       02 | [                               DIV1                                ] | RW = 0x74
+       03 | FM1CA  | FM1SS  | [  NUM1(1:0)  ] | [              NUM2(3:0)        ] | RW = 0x00
+       04 |                                 NUM2(11:4)                          ] | RW = 0x08
+       05 | [                               DIV2                       ] |NUM2(12)| RW = 0x93
+       06 | L1LK   | [        TAD1          ] | L2LK   | [         TAD2         ] | R
+       07 | [                               FMF                                 ] | R
+       08 |   ?    | FMCAL  |   ?    |   ?    |   ?    |   ?    |   ?    | TEMP   | R
+       09 |   0    |   0    | [    FMGC     ] |   0    | GP02   | GP01   |   0    | RW = 0x20
+       0A | ??
+       0B |   0    |   0    |   1    |   1    |   0    |   0    | [   VGAG      ] | RW = 0x30
+       0C | V1CSE  |   1    |   1    |   1    |   1    |   1    |   1    |   1    | RW = 0xFF
+       0D |   1    |   0    | [                      V1CS                       ] | RW = 0xB0
+       0E | ??
+       0F | ??
+       10 | ??
+       11 | [             LOTO              ] |   0    |   0    |   1    |   0    | RW = 0x42
+
+       PART    : Part code      : 6 for MT2060
+       REV     : Revision code  : 3 for current revision
+       LNABAND : Input frequency range : ( See code for details )
+       NUM1 / DIV1 / NUM2 / DIV2 : Frequencies programming ( See code for details )
+       FM1CA  : Calibration Start Bit
+       FM1SS  : Calibration Single Step bit
+       L1LK   : LO1 Lock Detect
+       TAD1   : Tune Line ADC ( ? )
+       L2LK   : LO2 Lock Detect
+       TAD2   : Tune Line ADC ( ? )
+       FMF    : Estimated first IF Center frequency Offset ( ? )
+       FM1CAL : Calibration done bit
+       TEMP   : On chip temperature sensor
+       FMCG   : Mixer 1 Cap Gain ( ? )
+       GP01 / GP02 : Programmable digital outputs. Unconnected pins ?
+       V1CSE  : LO1 VCO Automatic Capacitor Select Enable ( ? )
+       V1CS   : LO1 Capacitor Selection Value ( ? )
+       LOTO   : LO Timeout ( ? )
+       VGAG   : Tuner Output gain
+*/
+
+#define I2C_ADDRESS 0x60
+
+#define REG_PART_REV   0
+#define REG_LO1C1      1
+#define REG_LO1C2      2
+#define REG_LO2C1      3
+#define REG_LO2C2      4
+#define REG_LO2C3      5
+#define REG_LO_STATUS  6
+#define REG_FM_FREQ    7
+#define REG_MISC_STAT  8
+#define REG_MISC_CTRL  9
+#define REG_RESERVED_A 0x0A
+#define REG_VGAG       0x0B
+#define REG_LO1B1      0x0C
+#define REG_LO1B2      0x0D
+#define REG_LOTO       0x11
+
+#define PART_REV 0x63 // The current driver works only with PART=6 and REV=3 chips
+
+struct mt2060_priv {
+	struct mt2060_config *cfg;
+	struct i2c_adapter   *i2c;
+
+	u32 frequency;
+	u16 if1_freq;
+	u8  fmfreq;
+};
+
+#endif
diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c
new file mode 100644
index 0000000..0ed9091
--- /dev/null
+++ b/drivers/media/tuners/mt2063.c
@@ -0,0 +1,2307 @@
+/*
+ * Driver for mt2063 Micronas tuner
+ *
+ * Copyright (c) 2011 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This driver came from a driver originally written by:
+ *		Henry Wang <Henry.wang@AzureWave.com>
+ * Made publicly available by Terratec, at:
+ *	http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
+ * The original driver's license is GPL, as declared with MODULE_LICENSE()
+ *
+ * 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 under version 2 of the License.
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+
+#include "mt2063.h"
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Set Verbosity level");
+
+#define dprintk(level, fmt, arg...) do {				\
+if (debug >= level)							\
+	printk(KERN_DEBUG "mt2063 %s: " fmt, __func__, ## arg);	\
+} while (0)
+
+
+/* positive error codes used internally */
+
+/*  Info: Unavoidable LO-related spur may be present in the output  */
+#define MT2063_SPUR_PRESENT_ERR             (0x00800000)
+
+/*  Info: Mask of bits used for # of LO-related spurs that were avoided during tuning  */
+#define MT2063_SPUR_CNT_MASK                (0x001f0000)
+#define MT2063_SPUR_SHIFT                   (16)
+
+/*  Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */
+#define MT2063_UPC_RANGE                    (0x04000000)
+
+/*  Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */
+#define MT2063_DNC_RANGE                    (0x08000000)
+
+/*
+ *  Constant defining the version of the following structure
+ *  and therefore the API for this code.
+ *
+ *  When compiling the tuner driver, the preprocessor will
+ *  check against this version number to make sure that
+ *  it matches the version that the tuner driver knows about.
+ */
+
+/* DECT Frequency Avoidance */
+#define MT2063_DECT_AVOID_US_FREQS      0x00000001
+
+#define MT2063_DECT_AVOID_EURO_FREQS    0x00000002
+
+#define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0)
+
+#define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0)
+
+enum MT2063_DECT_Avoid_Type {
+	MT2063_NO_DECT_AVOIDANCE = 0,				/* Do not create DECT exclusion zones.     */
+	MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS,	/* Avoid US DECT frequencies.              */
+	MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS,	/* Avoid European DECT frequencies.        */
+	MT2063_AVOID_BOTH					/* Avoid both regions. Not typically used. */
+};
+
+#define MT2063_MAX_ZONES 48
+
+struct MT2063_ExclZone_t {
+	u32 min_;
+	u32 max_;
+	struct MT2063_ExclZone_t *next_;
+};
+
+/*
+ *  Structure of data needed for Spur Avoidance
+ */
+struct MT2063_AvoidSpursData_t {
+	u32 f_ref;
+	u32 f_in;
+	u32 f_LO1;
+	u32 f_if1_Center;
+	u32 f_if1_Request;
+	u32 f_if1_bw;
+	u32 f_LO2;
+	u32 f_out;
+	u32 f_out_bw;
+	u32 f_LO1_Step;
+	u32 f_LO2_Step;
+	u32 f_LO1_FracN_Avoid;
+	u32 f_LO2_FracN_Avoid;
+	u32 f_zif_bw;
+	u32 f_min_LO_Separation;
+	u32 maxH1;
+	u32 maxH2;
+	enum MT2063_DECT_Avoid_Type avoidDECT;
+	u32 bSpurPresent;
+	u32 bSpurAvoided;
+	u32 nSpursFound;
+	u32 nZones;
+	struct MT2063_ExclZone_t *freeZones;
+	struct MT2063_ExclZone_t *usedZones;
+	struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES];
+};
+
+/*
+ * Parameter for function MT2063_SetPowerMask that specifies the power down
+ * of various sections of the MT2063.
+ */
+enum MT2063_Mask_Bits {
+	MT2063_REG_SD = 0x0040,		/* Shutdown regulator                 */
+	MT2063_SRO_SD = 0x0020,		/* Shutdown SRO                       */
+	MT2063_AFC_SD = 0x0010,		/* Shutdown AFC A/D                   */
+	MT2063_PD_SD = 0x0002,		/* Enable power detector shutdown     */
+	MT2063_PDADC_SD = 0x0001,	/* Enable power detector A/D shutdown */
+	MT2063_VCO_SD = 0x8000,		/* Enable VCO shutdown                */
+	MT2063_LTX_SD = 0x4000,		/* Enable LTX shutdown                */
+	MT2063_LT1_SD = 0x2000,		/* Enable LT1 shutdown                */
+	MT2063_LNA_SD = 0x1000,		/* Enable LNA shutdown                */
+	MT2063_UPC_SD = 0x0800,		/* Enable upconverter shutdown        */
+	MT2063_DNC_SD = 0x0400,		/* Enable downconverter shutdown      */
+	MT2063_VGA_SD = 0x0200,		/* Enable VGA shutdown                */
+	MT2063_AMP_SD = 0x0100,		/* Enable AMP shutdown                */
+	MT2063_ALL_SD = 0xFF73,		/* All shutdown bits for this tuner   */
+	MT2063_NONE_SD = 0x0000		/* No shutdown bits                   */
+};
+
+/*
+ *  Possible values for MT2063_DNC_OUTPUT
+ */
+enum MT2063_DNC_Output_Enable {
+	MT2063_DNC_NONE = 0,
+	MT2063_DNC_1,
+	MT2063_DNC_2,
+	MT2063_DNC_BOTH
+};
+
+/*
+ *  Two-wire serial bus subaddresses of the tuner registers.
+ *  Also known as the tuner's register addresses.
+ */
+enum MT2063_Register_Offsets {
+	MT2063_REG_PART_REV = 0,	/*  0x00: Part/Rev Code         */
+	MT2063_REG_LO1CQ_1,		/*  0x01: LO1C Queued Byte 1    */
+	MT2063_REG_LO1CQ_2,		/*  0x02: LO1C Queued Byte 2    */
+	MT2063_REG_LO2CQ_1,		/*  0x03: LO2C Queued Byte 1    */
+	MT2063_REG_LO2CQ_2,		/*  0x04: LO2C Queued Byte 2    */
+	MT2063_REG_LO2CQ_3,		/*  0x05: LO2C Queued Byte 3    */
+	MT2063_REG_RSVD_06,		/*  0x06: Reserved              */
+	MT2063_REG_LO_STATUS,		/*  0x07: LO Status             */
+	MT2063_REG_FIFFC,		/*  0x08: FIFF Center           */
+	MT2063_REG_CLEARTUNE,		/*  0x09: ClearTune Filter      */
+	MT2063_REG_ADC_OUT,		/*  0x0A: ADC_OUT               */
+	MT2063_REG_LO1C_1,		/*  0x0B: LO1C Byte 1           */
+	MT2063_REG_LO1C_2,		/*  0x0C: LO1C Byte 2           */
+	MT2063_REG_LO2C_1,		/*  0x0D: LO2C Byte 1           */
+	MT2063_REG_LO2C_2,		/*  0x0E: LO2C Byte 2           */
+	MT2063_REG_LO2C_3,		/*  0x0F: LO2C Byte 3           */
+	MT2063_REG_RSVD_10,		/*  0x10: Reserved              */
+	MT2063_REG_PWR_1,		/*  0x11: PWR Byte 1            */
+	MT2063_REG_PWR_2,		/*  0x12: PWR Byte 2            */
+	MT2063_REG_TEMP_STATUS,		/*  0x13: Temp Status           */
+	MT2063_REG_XO_STATUS,		/*  0x14: Crystal Status        */
+	MT2063_REG_RF_STATUS,		/*  0x15: RF Attn Status        */
+	MT2063_REG_FIF_STATUS,		/*  0x16: FIF Attn Status       */
+	MT2063_REG_LNA_OV,		/*  0x17: LNA Attn Override     */
+	MT2063_REG_RF_OV,		/*  0x18: RF Attn Override      */
+	MT2063_REG_FIF_OV,		/*  0x19: FIF Attn Override     */
+	MT2063_REG_LNA_TGT,		/*  0x1A: Reserved              */
+	MT2063_REG_PD1_TGT,		/*  0x1B: Pwr Det 1 Target      */
+	MT2063_REG_PD2_TGT,		/*  0x1C: Pwr Det 2 Target      */
+	MT2063_REG_RSVD_1D,		/*  0x1D: Reserved              */
+	MT2063_REG_RSVD_1E,		/*  0x1E: Reserved              */
+	MT2063_REG_RSVD_1F,		/*  0x1F: Reserved              */
+	MT2063_REG_RSVD_20,		/*  0x20: Reserved              */
+	MT2063_REG_BYP_CTRL,		/*  0x21: Bypass Control        */
+	MT2063_REG_RSVD_22,		/*  0x22: Reserved              */
+	MT2063_REG_RSVD_23,		/*  0x23: Reserved              */
+	MT2063_REG_RSVD_24,		/*  0x24: Reserved              */
+	MT2063_REG_RSVD_25,		/*  0x25: Reserved              */
+	MT2063_REG_RSVD_26,		/*  0x26: Reserved              */
+	MT2063_REG_RSVD_27,		/*  0x27: Reserved              */
+	MT2063_REG_FIFF_CTRL,		/*  0x28: FIFF Control          */
+	MT2063_REG_FIFF_OFFSET,		/*  0x29: FIFF Offset           */
+	MT2063_REG_CTUNE_CTRL,		/*  0x2A: Reserved              */
+	MT2063_REG_CTUNE_OV,		/*  0x2B: Reserved              */
+	MT2063_REG_CTRL_2C,		/*  0x2C: Reserved              */
+	MT2063_REG_FIFF_CTRL2,		/*  0x2D: Fiff Control          */
+	MT2063_REG_RSVD_2E,		/*  0x2E: Reserved              */
+	MT2063_REG_DNC_GAIN,		/*  0x2F: DNC Control           */
+	MT2063_REG_VGA_GAIN,		/*  0x30: VGA Gain Ctrl         */
+	MT2063_REG_RSVD_31,		/*  0x31: Reserved              */
+	MT2063_REG_TEMP_SEL,		/*  0x32: Temperature Selection */
+	MT2063_REG_RSVD_33,		/*  0x33: Reserved              */
+	MT2063_REG_RSVD_34,		/*  0x34: Reserved              */
+	MT2063_REG_RSVD_35,		/*  0x35: Reserved              */
+	MT2063_REG_RSVD_36,		/*  0x36: Reserved              */
+	MT2063_REG_RSVD_37,		/*  0x37: Reserved              */
+	MT2063_REG_RSVD_38,		/*  0x38: Reserved              */
+	MT2063_REG_RSVD_39,		/*  0x39: Reserved              */
+	MT2063_REG_RSVD_3A,		/*  0x3A: Reserved              */
+	MT2063_REG_RSVD_3B,		/*  0x3B: Reserved              */
+	MT2063_REG_RSVD_3C,		/*  0x3C: Reserved              */
+	MT2063_REG_END_REGS
+};
+
+struct mt2063_state {
+	struct i2c_adapter *i2c;
+
+	bool init;
+
+	const struct mt2063_config *config;
+	struct dvb_tuner_ops ops;
+	struct dvb_frontend *frontend;
+	struct tuner_state status;
+
+	u32 frequency;
+	u32 srate;
+	u32 bandwidth;
+	u32 reference;
+
+	u32 tuner_id;
+	struct MT2063_AvoidSpursData_t AS_Data;
+	u32 f_IF1_actual;
+	u32 rcvr_mode;
+	u32 ctfilt_sw;
+	u32 CTFiltMax[31];
+	u32 num_regs;
+	u8 reg[MT2063_REG_END_REGS];
+};
+
+/*
+ * mt2063_write - Write data into the I2C bus
+ */
+static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len)
+{
+	struct dvb_frontend *fe = state->frontend;
+	int ret;
+	u8 buf[60];
+	struct i2c_msg msg = {
+		.addr = state->config->tuner_address,
+		.flags = 0,
+		.buf = buf,
+		.len = len + 1
+	};
+
+	dprintk(2, "\n");
+
+	msg.buf[0] = reg;
+	memcpy(msg.buf + 1, data, len);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	ret = i2c_transfer(state->i2c, &msg, 1);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	if (ret < 0)
+		printk(KERN_ERR "%s error ret=%d\n", __func__, ret);
+
+	return ret;
+}
+
+/*
+ * mt2063_write - Write register data into the I2C bus, caching the value
+ */
+static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val)
+{
+	u32 status;
+
+	dprintk(2, "\n");
+
+	if (reg >= MT2063_REG_END_REGS)
+		return -ERANGE;
+
+	status = mt2063_write(state, reg, &val, 1);
+	if (status < 0)
+		return status;
+
+	state->reg[reg] = val;
+
+	return 0;
+}
+
+/*
+ * mt2063_read - Read data from the I2C bus
+ */
+static u32 mt2063_read(struct mt2063_state *state,
+			   u8 subAddress, u8 *pData, u32 cnt)
+{
+	u32 status = 0;	/* Status to be returned        */
+	struct dvb_frontend *fe = state->frontend;
+	u32 i = 0;
+
+	dprintk(2, "addr 0x%02x, cnt %d\n", subAddress, cnt);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	for (i = 0; i < cnt; i++) {
+		u8 b0[] = { subAddress + i };
+		struct i2c_msg msg[] = {
+			{
+				.addr = state->config->tuner_address,
+				.flags = 0,
+				.buf = b0,
+				.len = 1
+			}, {
+				.addr = state->config->tuner_address,
+				.flags = I2C_M_RD,
+				.buf = pData + i,
+				.len = 1
+			}
+		};
+
+		status = i2c_transfer(state->i2c, msg, 2);
+		dprintk(2, "addr 0x%02x, ret = %d, val = 0x%02x\n",
+			   subAddress + i, status, *(pData + i));
+		if (status < 0)
+			break;
+	}
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	if (status < 0)
+		printk(KERN_ERR "Can't read from address 0x%02x,\n",
+		       subAddress + i);
+
+	return status;
+}
+
+/*
+ * FIXME: Is this really needed?
+ */
+static int MT2063_Sleep(struct dvb_frontend *fe)
+{
+	/*
+	 *  ToDo:  Add code here to implement a OS blocking
+	 */
+	msleep(100);
+
+	return 0;
+}
+
+/*
+ * Microtune spur avoidance
+ */
+
+/*  Implement ceiling, floor functions.  */
+#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0))
+#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d))
+
+struct MT2063_FIFZone_t {
+	s32 min_;
+	s32 max_;
+};
+
+static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t
+					    *pAS_Info,
+					    struct MT2063_ExclZone_t *pPrevNode)
+{
+	struct MT2063_ExclZone_t *pNode;
+
+	dprintk(2, "\n");
+
+	/*  Check for a node in the free list  */
+	if (pAS_Info->freeZones != NULL) {
+		/*  Use one from the free list  */
+		pNode = pAS_Info->freeZones;
+		pAS_Info->freeZones = pNode->next_;
+	} else {
+		/*  Grab a node from the array  */
+		pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones];
+	}
+
+	if (pPrevNode != NULL) {
+		pNode->next_ = pPrevNode->next_;
+		pPrevNode->next_ = pNode;
+	} else {		/*  insert at the beginning of the list  */
+
+		pNode->next_ = pAS_Info->usedZones;
+		pAS_Info->usedZones = pNode;
+	}
+
+	pAS_Info->nZones++;
+	return pNode;
+}
+
+static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t
+					    *pAS_Info,
+					    struct MT2063_ExclZone_t *pPrevNode,
+					    struct MT2063_ExclZone_t
+					    *pNodeToRemove)
+{
+	struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_;
+
+	dprintk(2, "\n");
+
+	/*  Make previous node point to the subsequent node  */
+	if (pPrevNode != NULL)
+		pPrevNode->next_ = pNext;
+
+	/*  Add pNodeToRemove to the beginning of the freeZones  */
+	pNodeToRemove->next_ = pAS_Info->freeZones;
+	pAS_Info->freeZones = pNodeToRemove;
+
+	/*  Decrement node count  */
+	pAS_Info->nZones--;
+
+	return pNext;
+}
+
+/*
+ * MT_AddExclZone()
+ *
+ * Add (and merge) an exclusion zone into the list.
+ * If the range (f_min, f_max) is totally outside the
+ * 1st IF BW, ignore the entry.
+ * If the range (f_min, f_max) is negative, ignore the entry.
+ */
+static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info,
+			       u32 f_min, u32 f_max)
+{
+	struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
+	struct MT2063_ExclZone_t *pPrev = NULL;
+	struct MT2063_ExclZone_t *pNext = NULL;
+
+	dprintk(2, "\n");
+
+	/*  Check to see if this overlaps the 1st IF filter  */
+	if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2)))
+	    && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2)))
+	    && (f_min < f_max)) {
+		/*
+		 *                1        2         3      4       5        6
+		 *
+		 *   New entry:  |---|    |--|      |--|    |-|    |---|    |--|
+		 *                or       or        or     or      or
+		 *   Existing:  |--|      |--|      |--|    |---|  |-|      |--|
+		 */
+
+		/*  Check for our place in the list  */
+		while ((pNode != NULL) && (pNode->max_ < f_min)) {
+			pPrev = pNode;
+			pNode = pNode->next_;
+		}
+
+		if ((pNode != NULL) && (pNode->min_ < f_max)) {
+			/*  Combine me with pNode  */
+			if (f_min < pNode->min_)
+				pNode->min_ = f_min;
+			if (f_max > pNode->max_)
+				pNode->max_ = f_max;
+		} else {
+			pNode = InsertNode(pAS_Info, pPrev);
+			pNode->min_ = f_min;
+			pNode->max_ = f_max;
+		}
+
+		/*  Look for merging possibilities  */
+		pNext = pNode->next_;
+		while ((pNext != NULL) && (pNext->min_ < pNode->max_)) {
+			if (pNext->max_ > pNode->max_)
+				pNode->max_ = pNext->max_;
+			/*  Remove pNext, return ptr to pNext->next  */
+			pNext = RemoveNode(pAS_Info, pNode, pNext);
+		}
+	}
+}
+
+/*
+ *  Reset all exclusion zones.
+ *  Add zones to protect the PLL FracN regions near zero
+ */
+static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info)
+{
+	u32 center;
+
+	dprintk(2, "\n");
+
+	pAS_Info->nZones = 0;	/*  this clears the used list  */
+	pAS_Info->usedZones = NULL;	/*  reset ptr                  */
+	pAS_Info->freeZones = NULL;	/*  reset ptr                  */
+
+	center =
+	    pAS_Info->f_ref *
+	    ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 +
+	      pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in;
+	while (center <
+	       pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
+	       pAS_Info->f_LO1_FracN_Avoid) {
+		/*  Exclude LO1 FracN  */
+		MT2063_AddExclZone(pAS_Info,
+				   center - pAS_Info->f_LO1_FracN_Avoid,
+				   center - 1);
+		MT2063_AddExclZone(pAS_Info, center + 1,
+				   center + pAS_Info->f_LO1_FracN_Avoid);
+		center += pAS_Info->f_ref;
+	}
+
+	center =
+	    pAS_Info->f_ref *
+	    ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 -
+	      pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out;
+	while (center <
+	       pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
+	       pAS_Info->f_LO2_FracN_Avoid) {
+		/*  Exclude LO2 FracN  */
+		MT2063_AddExclZone(pAS_Info,
+				   center - pAS_Info->f_LO2_FracN_Avoid,
+				   center - 1);
+		MT2063_AddExclZone(pAS_Info, center + 1,
+				   center + pAS_Info->f_LO2_FracN_Avoid);
+		center += pAS_Info->f_ref;
+	}
+
+	if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
+		/*  Exclude LO1 values that conflict with DECT channels */
+		MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in);	/* Ctr = 1921.536 */
+		MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in);	/* Ctr = 1923.264 */
+		MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in);	/* Ctr = 1924.992 */
+		MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in);	/* Ctr = 1926.720 */
+		MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in);	/* Ctr = 1928.448 */
+	}
+
+	if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
+		MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in);	/* Ctr = 1897.344 */
+		MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in);	/* Ctr = 1895.616 */
+		MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in);	/* Ctr = 1893.888 */
+		MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in);	/* Ctr = 1892.16  */
+		MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in);	/* Ctr = 1890.432 */
+		MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in);	/* Ctr = 1888.704 */
+		MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in);	/* Ctr = 1886.976 */
+		MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in);	/* Ctr = 1885.248 */
+		MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in);	/* Ctr = 1883.52  */
+		MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in);	/* Ctr = 1881.792 */
+	}
+}
+
+/*
+ * MT_ChooseFirstIF - Choose the best available 1st IF
+ *                    If f_Desired is not excluded, choose that first.
+ *                    Otherwise, return the value closest to f_Center that is
+ *                    not excluded
+ */
+static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info)
+{
+	/*
+	 * Update "f_Desired" to be the nearest "combinational-multiple" of
+	 * "f_LO1_Step".
+	 * The resulting number, F_LO1 must be a multiple of f_LO1_Step.
+	 * And F_LO1 is the arithmetic sum of f_in + f_Center.
+	 * Neither f_in, nor f_Center must be a multiple of f_LO1_Step.
+	 * However, the sum must be.
+	 */
+	const u32 f_Desired =
+	    pAS_Info->f_LO1_Step *
+	    ((pAS_Info->f_if1_Request + pAS_Info->f_in +
+	      pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) -
+	    pAS_Info->f_in;
+	const u32 f_Step =
+	    (pAS_Info->f_LO1_Step >
+	     pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info->
+	    f_LO2_Step;
+	u32 f_Center;
+	s32 i;
+	s32 j = 0;
+	u32 bDesiredExcluded = 0;
+	u32 bZeroExcluded = 0;
+	s32 tmpMin, tmpMax;
+	s32 bestDiff;
+	struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
+	struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES];
+
+	dprintk(2, "\n");
+
+	if (pAS_Info->nZones == 0)
+		return f_Desired;
+
+	/*
+	 *  f_Center needs to be an integer multiple of f_Step away
+	 *  from f_Desired
+	 */
+	if (pAS_Info->f_if1_Center > f_Desired)
+		f_Center =
+		    f_Desired +
+		    f_Step *
+		    ((pAS_Info->f_if1_Center - f_Desired +
+		      f_Step / 2) / f_Step);
+	else
+		f_Center =
+		    f_Desired -
+		    f_Step *
+		    ((f_Desired - pAS_Info->f_if1_Center +
+		      f_Step / 2) / f_Step);
+
+	/*
+	 * Take MT_ExclZones, center around f_Center and change the
+	 * resolution to f_Step
+	 */
+	while (pNode != NULL) {
+		/*  floor function  */
+		tmpMin =
+		    floor((s32) (pNode->min_ - f_Center), (s32) f_Step);
+
+		/*  ceil function  */
+		tmpMax =
+		    ceil((s32) (pNode->max_ - f_Center), (s32) f_Step);
+
+		if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired))
+			bDesiredExcluded = 1;
+
+		if ((tmpMin < 0) && (tmpMax > 0))
+			bZeroExcluded = 1;
+
+		/*  See if this zone overlaps the previous  */
+		if ((j > 0) && (tmpMin < zones[j - 1].max_))
+			zones[j - 1].max_ = tmpMax;
+		else {
+			/*  Add new zone  */
+			zones[j].min_ = tmpMin;
+			zones[j].max_ = tmpMax;
+			j++;
+		}
+		pNode = pNode->next_;
+	}
+
+	/*
+	 *  If the desired is okay, return with it
+	 */
+	if (bDesiredExcluded == 0)
+		return f_Desired;
+
+	/*
+	 *  If the desired is excluded and the center is okay, return with it
+	 */
+	if (bZeroExcluded == 0)
+		return f_Center;
+
+	/*  Find the value closest to 0 (f_Center)  */
+	bestDiff = zones[0].min_;
+	for (i = 0; i < j; i++) {
+		if (abs(zones[i].min_) < abs(bestDiff))
+			bestDiff = zones[i].min_;
+		if (abs(zones[i].max_) < abs(bestDiff))
+			bestDiff = zones[i].max_;
+	}
+
+	if (bestDiff < 0)
+		return f_Center - ((u32) (-bestDiff) * f_Step);
+
+	return f_Center + (bestDiff * f_Step);
+}
+
+/**
+ * gcd() - Uses Euclid's algorithm
+ *
+ * @u, @v:	Unsigned values whose GCD is desired.
+ *
+ * Returns THE greatest common divisor of u and v, if either value is 0,
+ * the other value is returned as the result.
+ */
+static u32 MT2063_gcd(u32 u, u32 v)
+{
+	u32 r;
+
+	while (v != 0) {
+		r = u % v;
+		u = v;
+		v = r;
+	}
+
+	return u;
+}
+
+/**
+ * IsSpurInBand() - Checks to see if a spur will be present within the IF's
+ *                  bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW)
+ *
+ *                    ma   mb                                     mc   md
+ *                  <--+-+-+-------------------+-------------------+-+-+-->
+ *                     |   ^                   0                   ^   |
+ *                     ^   b=-fIFOut+fIFBW/2      -b=+fIFOut-fIFBW/2   ^
+ *                     a=-fIFOut-fIFBW/2              -a=+fIFOut+fIFBW/2
+ *
+ *                  Note that some equations are doubled to prevent round-off
+ *                  problems when calculating fIFBW/2
+ *
+ * @pAS_Info:	Avoid Spurs information block
+ * @fm:		If spur, amount f_IF1 has to move negative
+ * @fp:		If spur, amount f_IF1 has to move positive
+ *
+ *  Returns 1 if an LO spur would be present, otherwise 0.
+ */
+static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info,
+			u32 *fm, u32 * fp)
+{
+	/*
+	 **  Calculate LO frequency settings.
+	 */
+	u32 n, n0;
+	const u32 f_LO1 = pAS_Info->f_LO1;
+	const u32 f_LO2 = pAS_Info->f_LO2;
+	const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2;
+	const u32 c = d - pAS_Info->f_out_bw;
+	const u32 f = pAS_Info->f_zif_bw / 2;
+	const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1;
+	s32 f_nsLO1, f_nsLO2;
+	s32 f_Spur;
+	u32 ma, mb, mc, md, me, mf;
+	u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs;
+
+	dprintk(2, "\n");
+
+	*fm = 0;
+
+	/*
+	 ** For each edge (d, c & f), calculate a scale, based on the gcd
+	 ** of f_LO1, f_LO2 and the edge value.  Use the larger of this
+	 ** gcd-based scale factor or f_Scale.
+	 */
+	lo_gcd = MT2063_gcd(f_LO1, f_LO2);
+	gd_Scale = max((u32) MT2063_gcd(lo_gcd, d), f_Scale);
+	hgds = gd_Scale / 2;
+	gc_Scale = max((u32) MT2063_gcd(lo_gcd, c), f_Scale);
+	hgcs = gc_Scale / 2;
+	gf_Scale = max((u32) MT2063_gcd(lo_gcd, f), f_Scale);
+	hgfs = gf_Scale / 2;
+
+	n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2);
+
+	/*  Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic  */
+	for (n = n0; n <= pAS_Info->maxH1; ++n) {
+		md = (n * ((f_LO1 + hgds) / gd_Scale) -
+		      ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
+
+		/*  If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present  */
+		if (md >= pAS_Info->maxH1)
+			break;
+
+		ma = (n * ((f_LO1 + hgds) / gd_Scale) +
+		      ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
+
+		/*  If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic  */
+		if (md == ma)
+			continue;
+
+		mc = (n * ((f_LO1 + hgcs) / gc_Scale) -
+		      ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
+		if (mc != md) {
+			f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale));
+			f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale));
+			f_Spur =
+			    (gc_Scale * (f_nsLO1 - f_nsLO2)) +
+			    n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale);
+
+			*fp = ((f_Spur - (s32) c) / (mc - n)) + 1;
+			*fm = (((s32) d - f_Spur) / (mc - n)) + 1;
+			return 1;
+		}
+
+		/*  Location of Zero-IF-spur to be checked  */
+		me = (n * ((f_LO1 + hgfs) / gf_Scale) +
+		      ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
+		mf = (n * ((f_LO1 + hgfs) / gf_Scale) -
+		      ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
+		if (me != mf) {
+			f_nsLO1 = n * (f_LO1 / gf_Scale);
+			f_nsLO2 = me * (f_LO2 / gf_Scale);
+			f_Spur =
+			    (gf_Scale * (f_nsLO1 - f_nsLO2)) +
+			    n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale);
+
+			*fp = ((f_Spur + (s32) f) / (me - n)) + 1;
+			*fm = (((s32) f - f_Spur) / (me - n)) + 1;
+			return 1;
+		}
+
+		mb = (n * ((f_LO1 + hgcs) / gc_Scale) +
+		      ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
+		if (ma != mb) {
+			f_nsLO1 = n * (f_LO1 / gc_Scale);
+			f_nsLO2 = ma * (f_LO2 / gc_Scale);
+			f_Spur =
+			    (gc_Scale * (f_nsLO1 - f_nsLO2)) +
+			    n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale);
+
+			*fp = (((s32) d + f_Spur) / (ma - n)) + 1;
+			*fm = (-(f_Spur + (s32) c) / (ma - n)) + 1;
+			return 1;
+		}
+	}
+
+	/*  No spurs found  */
+	return 0;
+}
+
+/*
+ * MT_AvoidSpurs() - Main entry point to avoid spurs.
+ *                   Checks for existing spurs in present LO1, LO2 freqs
+ *                   and if present, chooses spur-free LO1, LO2 combination
+ *                   that tunes the same input/output frequencies.
+ */
+static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info)
+{
+	u32 status = 0;
+	u32 fm, fp;		/*  restricted range on LO's        */
+	pAS_Info->bSpurAvoided = 0;
+	pAS_Info->nSpursFound = 0;
+
+	dprintk(2, "\n");
+
+	if (pAS_Info->maxH1 == 0)
+		return 0;
+
+	/*
+	 * Avoid LO Generated Spurs
+	 *
+	 * Make sure that have no LO-related spurs within the IF output
+	 * bandwidth.
+	 *
+	 * If there is an LO spur in this band, start at the current IF1 frequency
+	 * and work out until we find a spur-free frequency or run up against the
+	 * 1st IF SAW band edge.  Use temporary copies of fLO1 and fLO2 so that they
+	 * will be unchanged if a spur-free setting is not found.
+	 */
+	pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
+	if (pAS_Info->bSpurPresent) {
+		u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in;	/*  current attempt at a 1st IF  */
+		u32 zfLO1 = pAS_Info->f_LO1;	/*  current attempt at an LO1 freq  */
+		u32 zfLO2 = pAS_Info->f_LO2;	/*  current attempt at an LO2 freq  */
+		u32 delta_IF1;
+		u32 new_IF1;
+
+		/*
+		 **  Spur was found, attempt to find a spur-free 1st IF
+		 */
+		do {
+			pAS_Info->nSpursFound++;
+
+			/*  Raise f_IF1_upper, if needed  */
+			MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp);
+
+			/*  Choose next IF1 that is closest to f_IF1_CENTER              */
+			new_IF1 = MT2063_ChooseFirstIF(pAS_Info);
+
+			if (new_IF1 > zfIF1) {
+				pAS_Info->f_LO1 += (new_IF1 - zfIF1);
+				pAS_Info->f_LO2 += (new_IF1 - zfIF1);
+			} else {
+				pAS_Info->f_LO1 -= (zfIF1 - new_IF1);
+				pAS_Info->f_LO2 -= (zfIF1 - new_IF1);
+			}
+			zfIF1 = new_IF1;
+
+			if (zfIF1 > pAS_Info->f_if1_Center)
+				delta_IF1 = zfIF1 - pAS_Info->f_if1_Center;
+			else
+				delta_IF1 = pAS_Info->f_if1_Center - zfIF1;
+
+			pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
+		/*
+		 *  Continue while the new 1st IF is still within the 1st IF bandwidth
+		 *  and there is a spur in the band (again)
+		 */
+		} while ((2 * delta_IF1 + pAS_Info->f_out_bw <= pAS_Info->f_if1_bw) && pAS_Info->bSpurPresent);
+
+		/*
+		 * Use the LO-spur free values found.  If the search went all
+		 * the way to the 1st IF band edge and always found spurs, just
+		 * leave the original choice.  It's as "good" as any other.
+		 */
+		if (pAS_Info->bSpurPresent == 1) {
+			status |= MT2063_SPUR_PRESENT_ERR;
+			pAS_Info->f_LO1 = zfLO1;
+			pAS_Info->f_LO2 = zfLO2;
+		} else
+			pAS_Info->bSpurAvoided = 1;
+	}
+
+	status |=
+	    ((pAS_Info->
+	      nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK);
+
+	return status;
+}
+
+/*
+ * Constants used by the tuning algorithm
+ */
+#define MT2063_REF_FREQ          (16000000UL)	/* Reference oscillator Frequency (in Hz) */
+#define MT2063_IF1_BW            (22000000UL)	/* The IF1 filter bandwidth (in Hz) */
+#define MT2063_TUNE_STEP_SIZE       (50000UL)	/* Tune in steps of 50 kHz */
+#define MT2063_SPUR_STEP_HZ        (250000UL)	/* Step size (in Hz) to move IF1 when avoiding spurs */
+#define MT2063_ZIF_BW             (2000000UL)	/* Zero-IF spur-free bandwidth (in Hz) */
+#define MT2063_MAX_HARMONICS_1         (15UL)	/* Highest intra-tuner LO Spur Harmonic to be avoided */
+#define MT2063_MAX_HARMONICS_2          (5UL)	/* Highest inter-tuner LO Spur Harmonic to be avoided */
+#define MT2063_MIN_LO_SEP         (1000000UL)	/* Minimum inter-tuner LO frequency separation */
+#define MT2063_LO1_FRACN_AVOID          (0UL)	/* LO1 FracN numerator avoid region (in Hz) */
+#define MT2063_LO2_FRACN_AVOID     (199999UL)	/* LO2 FracN numerator avoid region (in Hz) */
+#define MT2063_MIN_FIN_FREQ      (44000000UL)	/* Minimum input frequency (in Hz) */
+#define MT2063_MAX_FIN_FREQ    (1100000000UL)	/* Maximum input frequency (in Hz) */
+#define MT2063_MIN_FOUT_FREQ     (36000000UL)	/* Minimum output frequency (in Hz) */
+#define MT2063_MAX_FOUT_FREQ     (57000000UL)	/* Maximum output frequency (in Hz) */
+#define MT2063_MIN_DNC_FREQ    (1293000000UL)	/* Minimum LO2 frequency (in Hz) */
+#define MT2063_MAX_DNC_FREQ    (1614000000UL)	/* Maximum LO2 frequency (in Hz) */
+#define MT2063_MIN_UPC_FREQ    (1396000000UL)	/* Minimum LO1 frequency (in Hz) */
+#define MT2063_MAX_UPC_FREQ    (2750000000UL)	/* Maximum LO1 frequency (in Hz) */
+
+/*
+ *  Define the supported Part/Rev codes for the MT2063
+ */
+#define MT2063_B0       (0x9B)
+#define MT2063_B1       (0x9C)
+#define MT2063_B2       (0x9D)
+#define MT2063_B3       (0x9E)
+
+/**
+ * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked
+ *
+ * @state:	struct mt2063_state pointer
+ *
+ * This function returns 0, if no lock, 1 if locked and a value < 1 if error
+ */
+static unsigned int mt2063_lockStatus(struct mt2063_state *state)
+{
+	const u32 nMaxWait = 100;	/*  wait a maximum of 100 msec   */
+	const u32 nPollRate = 2;	/*  poll status bits every 2 ms */
+	const u32 nMaxLoops = nMaxWait / nPollRate;
+	const u8 LO1LK = 0x80;
+	u8 LO2LK = 0x08;
+	u32 status;
+	u32 nDelays = 0;
+
+	dprintk(2, "\n");
+
+	/*  LO2 Lock bit was in a different place for B0 version  */
+	if (state->tuner_id == MT2063_B0)
+		LO2LK = 0x40;
+
+	do {
+		status = mt2063_read(state, MT2063_REG_LO_STATUS,
+				     &state->reg[MT2063_REG_LO_STATUS], 1);
+
+		if (status < 0)
+			return status;
+
+		if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) ==
+		    (LO1LK | LO2LK)) {
+			return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO;
+		}
+		msleep(nPollRate);	/*  Wait between retries  */
+	} while (++nDelays < nMaxLoops);
+
+	/*
+	 * Got no lock or partial lock
+	 */
+	return 0;
+}
+
+/*
+ *  Constants for setting receiver modes.
+ *  (6 modes defined at this time, enumerated by mt2063_delivery_sys)
+ *  (DNC1GC & DNC2GC are the values, which are used, when the specific
+ *   DNC Output is selected, the other is always off)
+ *
+ *                enum mt2063_delivery_sys
+ * -------------+----------------------------------------------
+ * Mode 0 :     | MT2063_CABLE_QAM
+ * Mode 1 :     | MT2063_CABLE_ANALOG
+ * Mode 2 :     | MT2063_OFFAIR_COFDM
+ * Mode 3 :     | MT2063_OFFAIR_COFDM_SAWLESS
+ * Mode 4 :     | MT2063_OFFAIR_ANALOG
+ * Mode 5 :     | MT2063_OFFAIR_8VSB
+ * --------------+----------------------------------------------
+ *
+ *                |<----------   Mode  -------------->|
+ *    Reg Field   |  0  |  1  |  2  |  3  |  4  |  5  |
+ *    ------------+-----+-----+-----+-----+-----+-----+
+ *    RFAGCen     | OFF | OFF | OFF | OFF | OFF | OFF
+ *    LNARin      |   0 |   0 |   3 |   3 |  3  |  3
+ *    FIFFQen     |   1 |   1 |   1 |   1 |  1  |  1
+ *    FIFFq       |   0 |   0 |   0 |   0 |  0  |  0
+ *    DNC1gc      |   0 |   0 |   0 |   0 |  0  |  0
+ *    DNC2gc      |   0 |   0 |   0 |   0 |  0  |  0
+ *    GCU Auto    |   1 |   1 |   1 |   1 |  1  |  1
+ *    LNA max Atn |  31 |  31 |  31 |  31 | 31  | 31
+ *    LNA Target  |  44 |  43 |  43 |  43 | 43  | 43
+ *    ign  RF Ovl |   0 |   0 |   0 |   0 |  0  |  0
+ *    RF  max Atn |  31 |  31 |  31 |  31 | 31  | 31
+ *    PD1 Target  |  36 |  36 |  38 |  38 | 36  | 38
+ *    ign FIF Ovl |   0 |   0 |   0 |   0 |  0  |  0
+ *    FIF max Atn |   5 |   5 |   5 |   5 |  5  |  5
+ *    PD2 Target  |  40 |  33 |  42 |  42 | 33  | 42
+ */
+
+enum mt2063_delivery_sys {
+	MT2063_CABLE_QAM = 0,
+	MT2063_CABLE_ANALOG,
+	MT2063_OFFAIR_COFDM,
+	MT2063_OFFAIR_COFDM_SAWLESS,
+	MT2063_OFFAIR_ANALOG,
+	MT2063_OFFAIR_8VSB,
+	MT2063_NUM_RCVR_MODES
+};
+
+static const char *mt2063_mode_name[] = {
+	[MT2063_CABLE_QAM]		= "digital cable",
+	[MT2063_CABLE_ANALOG]		= "analog cable",
+	[MT2063_OFFAIR_COFDM]		= "digital offair",
+	[MT2063_OFFAIR_COFDM_SAWLESS]	= "digital offair without SAW",
+	[MT2063_OFFAIR_ANALOG]		= "analog offair",
+	[MT2063_OFFAIR_8VSB]		= "analog offair 8vsb",
+};
+
+static const u8 RFAGCEN[]	= {  0,  0,  0,  0,  0,  0 };
+static const u8 LNARIN[]	= {  0,  0,  3,  3,  3,  3 };
+static const u8 FIFFQEN[]	= {  1,  1,  1,  1,  1,  1 };
+static const u8 FIFFQ[]		= {  0,  0,  0,  0,  0,  0 };
+static const u8 DNC1GC[]	= {  0,  0,  0,  0,  0,  0 };
+static const u8 DNC2GC[]	= {  0,  0,  0,  0,  0,  0 };
+static const u8 ACLNAMAX[]	= { 31, 31, 31, 31, 31, 31 };
+static const u8 LNATGT[]	= { 44, 43, 43, 43, 43, 43 };
+static const u8 RFOVDIS[]	= {  0,  0,  0,  0,  0,  0 };
+static const u8 ACRFMAX[]	= { 31, 31, 31, 31, 31, 31 };
+static const u8 PD1TGT[]	= { 36, 36, 38, 38, 36, 38 };
+static const u8 FIFOVDIS[]	= {  0,  0,  0,  0,  0,  0 };
+static const u8 ACFIFMAX[]	= { 29, 29, 29, 29, 29, 29 };
+static const u8 PD2TGT[]	= { 40, 33, 38, 42, 30, 38 };
+
+/*
+ * mt2063_set_dnc_output_enable()
+ */
+static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state,
+					enum MT2063_DNC_Output_Enable *pValue)
+{
+	dprintk(2, "\n");
+
+	if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) {	/* if DNC1 is off */
+		if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03)	/* if DNC2 is off */
+			*pValue = MT2063_DNC_NONE;
+		else
+			*pValue = MT2063_DNC_2;
+	} else {	/* DNC1 is on */
+		if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03)	/* if DNC2 is off */
+			*pValue = MT2063_DNC_1;
+		else
+			*pValue = MT2063_DNC_BOTH;
+	}
+	return 0;
+}
+
+/*
+ * mt2063_set_dnc_output_enable()
+ */
+static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state,
+					enum MT2063_DNC_Output_Enable nValue)
+{
+	u32 status = 0;	/* Status to be returned        */
+	u8 val = 0;
+
+	dprintk(2, "\n");
+
+	/* selects, which DNC output is used */
+	switch (nValue) {
+	case MT2063_DNC_NONE:
+		val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03;	/* Set DNC1GC=3 */
+		if (state->reg[MT2063_REG_DNC_GAIN] !=
+		    val)
+			status |=
+			    mt2063_setreg(state,
+					  MT2063_REG_DNC_GAIN,
+					  val);
+
+		val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03;	/* Set DNC2GC=3 */
+		if (state->reg[MT2063_REG_VGA_GAIN] !=
+		    val)
+			status |=
+			    mt2063_setreg(state,
+					  MT2063_REG_VGA_GAIN,
+					  val);
+
+		val = (state->reg[MT2063_REG_RSVD_20] & ~0x40);	/* Set PD2MUX=0 */
+		if (state->reg[MT2063_REG_RSVD_20] !=
+		    val)
+			status |=
+			    mt2063_setreg(state,
+					  MT2063_REG_RSVD_20,
+					  val);
+
+		break;
+	case MT2063_DNC_1:
+		val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03);	/* Set DNC1GC=x */
+		if (state->reg[MT2063_REG_DNC_GAIN] !=
+		    val)
+			status |=
+			    mt2063_setreg(state,
+					  MT2063_REG_DNC_GAIN,
+					  val);
+
+		val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03;	/* Set DNC2GC=3 */
+		if (state->reg[MT2063_REG_VGA_GAIN] !=
+		    val)
+			status |=
+			    mt2063_setreg(state,
+					  MT2063_REG_VGA_GAIN,
+					  val);
+
+		val = (state->reg[MT2063_REG_RSVD_20] & ~0x40);	/* Set PD2MUX=0 */
+		if (state->reg[MT2063_REG_RSVD_20] !=
+		    val)
+			status |=
+			    mt2063_setreg(state,
+					  MT2063_REG_RSVD_20,
+					  val);
+
+		break;
+	case MT2063_DNC_2:
+		val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03;	/* Set DNC1GC=3 */
+		if (state->reg[MT2063_REG_DNC_GAIN] !=
+		    val)
+			status |=
+			    mt2063_setreg(state,
+					  MT2063_REG_DNC_GAIN,
+					  val);
+
+		val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03);	/* Set DNC2GC=x */
+		if (state->reg[MT2063_REG_VGA_GAIN] !=
+		    val)
+			status |=
+			    mt2063_setreg(state,
+					  MT2063_REG_VGA_GAIN,
+					  val);
+
+		val = (state->reg[MT2063_REG_RSVD_20] | 0x40);	/* Set PD2MUX=1 */
+		if (state->reg[MT2063_REG_RSVD_20] !=
+		    val)
+			status |=
+			    mt2063_setreg(state,
+					  MT2063_REG_RSVD_20,
+					  val);
+
+		break;
+	case MT2063_DNC_BOTH:
+		val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03);	/* Set DNC1GC=x */
+		if (state->reg[MT2063_REG_DNC_GAIN] !=
+		    val)
+			status |=
+			    mt2063_setreg(state,
+					  MT2063_REG_DNC_GAIN,
+					  val);
+
+		val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03);	/* Set DNC2GC=x */
+		if (state->reg[MT2063_REG_VGA_GAIN] !=
+		    val)
+			status |=
+			    mt2063_setreg(state,
+					  MT2063_REG_VGA_GAIN,
+					  val);
+
+		val = (state->reg[MT2063_REG_RSVD_20] | 0x40);	/* Set PD2MUX=1 */
+		if (state->reg[MT2063_REG_RSVD_20] !=
+		    val)
+			status |=
+			    mt2063_setreg(state,
+					  MT2063_REG_RSVD_20,
+					  val);
+
+		break;
+	default:
+		break;
+	}
+
+	return status;
+}
+
+/*
+ * MT2063_SetReceiverMode() - Set the MT2063 receiver mode, according with
+ * 			      the selected enum mt2063_delivery_sys type.
+ *
+ *  (DNC1GC & DNC2GC are the values, which are used, when the specific
+ *   DNC Output is selected, the other is always off)
+ *
+ * @state:	ptr to mt2063_state structure
+ * @Mode:	desired reciever delivery system
+ *
+ * Note: Register cache must be valid for it to work
+ */
+
+static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
+				  enum mt2063_delivery_sys Mode)
+{
+	u32 status = 0;	/* Status to be returned        */
+	u8 val;
+	u32 longval;
+
+	dprintk(2, "\n");
+
+	if (Mode >= MT2063_NUM_RCVR_MODES)
+		status = -ERANGE;
+
+	/* RFAGCen */
+	if (status >= 0) {
+		val =
+		    (state->
+		     reg[MT2063_REG_PD1_TGT] & (u8) ~0x40) | (RFAGCEN[Mode]
+								   ? 0x40 :
+								   0x00);
+		if (state->reg[MT2063_REG_PD1_TGT] != val)
+			status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
+	}
+
+	/* LNARin */
+	if (status >= 0) {
+		u8 val = (state->reg[MT2063_REG_CTRL_2C] & (u8) ~0x03) |
+			 (LNARIN[Mode] & 0x03);
+		if (state->reg[MT2063_REG_CTRL_2C] != val)
+			status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val);
+	}
+
+	/* FIFFQEN and FIFFQ */
+	if (status >= 0) {
+		val =
+		    (state->
+		     reg[MT2063_REG_FIFF_CTRL2] & (u8) ~0xF0) |
+		    (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
+		if (state->reg[MT2063_REG_FIFF_CTRL2] != val) {
+			status |=
+			    mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val);
+			/* trigger FIFF calibration, needed after changing FIFFQ */
+			val =
+			    (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01);
+			status |=
+			    mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
+			val =
+			    (state->
+			     reg[MT2063_REG_FIFF_CTRL] & (u8) ~0x01);
+			status |=
+			    mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
+		}
+	}
+
+	/* DNC1GC & DNC2GC */
+	status |= mt2063_get_dnc_output_enable(state, &longval);
+	status |= mt2063_set_dnc_output_enable(state, longval);
+
+	/* acLNAmax */
+	if (status >= 0) {
+		u8 val = (state->reg[MT2063_REG_LNA_OV] & (u8) ~0x1F) |
+			 (ACLNAMAX[Mode] & 0x1F);
+		if (state->reg[MT2063_REG_LNA_OV] != val)
+			status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val);
+	}
+
+	/* LNATGT */
+	if (status >= 0) {
+		u8 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x3F) |
+			 (LNATGT[Mode] & 0x3F);
+		if (state->reg[MT2063_REG_LNA_TGT] != val)
+			status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
+	}
+
+	/* ACRF */
+	if (status >= 0) {
+		u8 val = (state->reg[MT2063_REG_RF_OV] & (u8) ~0x1F) |
+			 (ACRFMAX[Mode] & 0x1F);
+		if (state->reg[MT2063_REG_RF_OV] != val)
+			status |= mt2063_setreg(state, MT2063_REG_RF_OV, val);
+	}
+
+	/* PD1TGT */
+	if (status >= 0) {
+		u8 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x3F) |
+			 (PD1TGT[Mode] & 0x3F);
+		if (state->reg[MT2063_REG_PD1_TGT] != val)
+			status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
+	}
+
+	/* FIFATN */
+	if (status >= 0) {
+		u8 val = ACFIFMAX[Mode];
+		if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5)
+			val = 5;
+		val = (state->reg[MT2063_REG_FIF_OV] & (u8) ~0x1F) |
+		      (val & 0x1F);
+		if (state->reg[MT2063_REG_FIF_OV] != val)
+			status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val);
+	}
+
+	/* PD2TGT */
+	if (status >= 0) {
+		u8 val = (state->reg[MT2063_REG_PD2_TGT] & (u8) ~0x3F) |
+		    (PD2TGT[Mode] & 0x3F);
+		if (state->reg[MT2063_REG_PD2_TGT] != val)
+			status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val);
+	}
+
+	/* Ignore ATN Overload */
+	if (status >= 0) {
+		val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x80) |
+		      (RFOVDIS[Mode] ? 0x80 : 0x00);
+		if (state->reg[MT2063_REG_LNA_TGT] != val)
+			status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
+	}
+
+	/* Ignore FIF Overload */
+	if (status >= 0) {
+		val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x80) |
+		      (FIFOVDIS[Mode] ? 0x80 : 0x00);
+		if (state->reg[MT2063_REG_PD1_TGT] != val)
+			status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
+	}
+
+	if (status >= 0) {
+		state->rcvr_mode = Mode;
+		dprintk(1, "mt2063 mode changed to %s\n",
+			mt2063_mode_name[state->rcvr_mode]);
+	}
+
+	return status;
+}
+
+/*
+ * MT2063_ClearPowerMaskBits () - Clears the power-down mask bits for various
+ *				  sections of the MT2063
+ *
+ * @Bits:		Mask bits to be cleared.
+ *
+ * See definition of MT2063_Mask_Bits type for description
+ * of each of the power bits.
+ */
+static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state,
+				     enum MT2063_Mask_Bits Bits)
+{
+	u32 status = 0;
+
+	dprintk(2, "\n");
+	Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD);	/* Only valid bits for this tuner */
+	if ((Bits & 0xFF00) != 0) {
+		state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8);
+		status |=
+		    mt2063_write(state,
+				    MT2063_REG_PWR_2,
+				    &state->reg[MT2063_REG_PWR_2], 1);
+	}
+	if ((Bits & 0xFF) != 0) {
+		state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF);
+		status |=
+		    mt2063_write(state,
+				    MT2063_REG_PWR_1,
+				    &state->reg[MT2063_REG_PWR_1], 1);
+	}
+
+	return status;
+}
+
+/*
+ * MT2063_SoftwareShutdown() - Enables or disables software shutdown function.
+ *			       When Shutdown is 1, any section whose power
+ *			       mask is set will be shutdown.
+ */
+static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown)
+{
+	u32 status;
+
+	dprintk(2, "\n");
+	if (Shutdown == 1)
+		state->reg[MT2063_REG_PWR_1] |= 0x04;
+	else
+		state->reg[MT2063_REG_PWR_1] &= ~0x04;
+
+	status = mt2063_write(state,
+			    MT2063_REG_PWR_1,
+			    &state->reg[MT2063_REG_PWR_1], 1);
+
+	if (Shutdown != 1) {
+		state->reg[MT2063_REG_BYP_CTRL] =
+		    (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40;
+		status |=
+		    mt2063_write(state,
+				    MT2063_REG_BYP_CTRL,
+				    &state->reg[MT2063_REG_BYP_CTRL],
+				    1);
+		state->reg[MT2063_REG_BYP_CTRL] =
+		    (state->reg[MT2063_REG_BYP_CTRL] & 0x9F);
+		status |=
+		    mt2063_write(state,
+				    MT2063_REG_BYP_CTRL,
+				    &state->reg[MT2063_REG_BYP_CTRL],
+				    1);
+	}
+
+	return status;
+}
+
+static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref)
+{
+	return f_ref * (f_LO / f_ref)
+	    + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step);
+}
+
+/**
+ * fLO_FractionalTerm() - Calculates the portion contributed by FracN / denom.
+ *                        This function preserves maximum precision without
+ *                        risk of overflow.  It accurately calculates
+ *                        f_ref * num / denom to within 1 HZ with fixed math.
+ *
+ * @num :	Fractional portion of the multiplier
+ * @denom:	denominator portion of the ratio
+ * @f_Ref:	SRO frequency.
+ *
+ * This calculation handles f_ref as two separate 14-bit fields.
+ * Therefore, a maximum value of 2^28-1 may safely be used for f_ref.
+ * This is the genesis of the magic number "14" and the magic mask value of
+ * 0x03FFF.
+ *
+ * This routine successfully handles denom values up to and including 2^18.
+ *  Returns:        f_ref * num / denom
+ */
+static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom)
+{
+	u32 t1 = (f_ref >> 14) * num;
+	u32 term1 = t1 / denom;
+	u32 loss = t1 % denom;
+	u32 term2 =
+	    (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom;
+	return (term1 << 14) + term2;
+}
+
+/*
+ * CalcLO1Mult()- Calculates Integer divider value and the numerator
+ *                value for a FracN PLL.
+ *
+ *                This function assumes that the f_LO and f_Ref are
+ *                evenly divisible by f_LO_Step.
+ *
+ * @Div:	OUTPUT: Whole number portion of the multiplier
+ * @FracN:	OUTPUT: Fractional portion of the multiplier
+ * @f_LO:	desired LO frequency.
+ * @f_LO_Step:	Minimum step size for the LO (in Hz).
+ * @f_Ref:	SRO frequency.
+ * @f_Avoid:	Range of PLL frequencies to avoid near integer multiples
+ *		of f_Ref (in Hz).
+ *
+ * Returns:        Recalculated LO frequency.
+ */
+static u32 MT2063_CalcLO1Mult(u32 *Div,
+			      u32 *FracN,
+			      u32 f_LO,
+			      u32 f_LO_Step, u32 f_Ref)
+{
+	/*  Calculate the whole number portion of the divider */
+	*Div = f_LO / f_Ref;
+
+	/*  Calculate the numerator value (round to nearest f_LO_Step) */
+	*FracN =
+	    (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
+	     (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
+
+	return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64);
+}
+
+/**
+ * CalcLO2Mult() - Calculates Integer divider value and the numerator
+ *                 value for a FracN PLL.
+ *
+ *                  This function assumes that the f_LO and f_Ref are
+ *                  evenly divisible by f_LO_Step.
+ *
+ * @Div:	OUTPUT: Whole number portion of the multiplier
+ * @FracN:	OUTPUT: Fractional portion of the multiplier
+ * @f_LO:	desired LO frequency.
+ * @f_LO_Step:	Minimum step size for the LO (in Hz).
+ * @f_Ref:	SRO frequency.
+ * @f_Avoid:	Range of PLL frequencies to avoid near
+ *		integer multiples of f_Ref (in Hz).
+ *
+ * Returns: Recalculated LO frequency.
+ */
+static u32 MT2063_CalcLO2Mult(u32 *Div,
+			      u32 *FracN,
+			      u32 f_LO,
+			      u32 f_LO_Step, u32 f_Ref)
+{
+	/*  Calculate the whole number portion of the divider */
+	*Div = f_LO / f_Ref;
+
+	/*  Calculate the numerator value (round to nearest f_LO_Step) */
+	*FracN =
+	    (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
+	     (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
+
+	return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN,
+							    8191);
+}
+
+/*
+ * FindClearTuneFilter() - Calculate the corrrect ClearTune filter to be
+ *			   used for a given input frequency.
+ *
+ * @state:	ptr to tuner data structure
+ * @f_in:	RF input center frequency (in Hz).
+ *
+ * Returns: ClearTune filter number (0-31)
+ */
+static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in)
+{
+	u32 RFBand;
+	u32 idx;		/*  index loop                      */
+
+	/*
+	 **  Find RF Band setting
+	 */
+	RFBand = 31;		/*  def when f_in > all    */
+	for (idx = 0; idx < 31; ++idx) {
+		if (state->CTFiltMax[idx] >= f_in) {
+			RFBand = idx;
+			break;
+		}
+	}
+	return RFBand;
+}
+
+/*
+ * MT2063_Tune() - Change the tuner's tuned frequency to RFin.
+ */
+static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in)
+{				/* RF input center frequency   */
+
+	u32 status = 0;
+	u32 LO1;		/*  1st LO register value           */
+	u32 Num1;		/*  Numerator for LO1 reg. value    */
+	u32 f_IF1;		/*  1st IF requested                */
+	u32 LO2;		/*  2nd LO register value           */
+	u32 Num2;		/*  Numerator for LO2 reg. value    */
+	u32 ofLO1, ofLO2;	/*  last time's LO frequencies      */
+	u8 fiffc = 0x80;	/*  FIFF center freq from tuner     */
+	u32 fiffof;		/*  Offset from FIFF center freq    */
+	const u8 LO1LK = 0x80;	/*  Mask for LO1 Lock bit           */
+	u8 LO2LK = 0x08;	/*  Mask for LO2 Lock bit           */
+	u8 val;
+	u32 RFBand;
+
+	dprintk(2, "\n");
+	/*  Check the input and output frequency ranges                   */
+	if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ))
+		return -EINVAL;
+
+	if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ)
+	    || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ))
+		return -EINVAL;
+
+	/*
+	 * Save original LO1 and LO2 register values
+	 */
+	ofLO1 = state->AS_Data.f_LO1;
+	ofLO2 = state->AS_Data.f_LO2; 
+
+	/*
+	 * Find and set RF Band setting
+	 */
+	if (state->ctfilt_sw == 1) {
+		val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08);
+		if (state->reg[MT2063_REG_CTUNE_CTRL] != val) {
+			status |=
+			    mt2063_setreg(state, MT2063_REG_CTUNE_CTRL, val);
+		}
+		val = state->reg[MT2063_REG_CTUNE_OV];
+		RFBand = FindClearTuneFilter(state, f_in);
+		state->reg[MT2063_REG_CTUNE_OV] =
+		    (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F)
+			      | RFBand);
+		if (state->reg[MT2063_REG_CTUNE_OV] != val) {
+			status |=
+			    mt2063_setreg(state, MT2063_REG_CTUNE_OV, val);
+		}
+	}
+
+	/*
+	 * Read the FIFF Center Frequency from the tuner
+	 */
+	if (status >= 0) {
+		status |=
+		    mt2063_read(state,
+				   MT2063_REG_FIFFC,
+				   &state->reg[MT2063_REG_FIFFC], 1);
+		fiffc = state->reg[MT2063_REG_FIFFC];
+	}
+	/*
+	 * Assign in the requested values
+	 */
+	state->AS_Data.f_in = f_in;
+	/*  Request a 1st IF such that LO1 is on a step size */
+	state->AS_Data.f_if1_Request =
+	    MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in,
+			     state->AS_Data.f_LO1_Step,
+			     state->AS_Data.f_ref) - f_in;
+
+	/*
+	 * Calculate frequency settings.  f_IF1_FREQ + f_in is the
+	 * desired LO1 frequency
+	 */
+	MT2063_ResetExclZones(&state->AS_Data);
+
+	f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data);
+
+	state->AS_Data.f_LO1 =
+	    MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step,
+			     state->AS_Data.f_ref);
+
+	state->AS_Data.f_LO2 =
+	    MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
+			     state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
+
+	/*
+	 * Check for any LO spurs in the output bandwidth and adjust
+	 * the LO settings to avoid them if needed
+	 */
+	status |= MT2063_AvoidSpurs(&state->AS_Data);
+	/*
+	 * MT_AvoidSpurs spurs may have changed the LO1 & LO2 values.
+	 * Recalculate the LO frequencies and the values to be placed
+	 * in the tuning registers.
+	 */
+	state->AS_Data.f_LO1 =
+	    MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1,
+			       state->AS_Data.f_LO1_Step, state->AS_Data.f_ref);
+	state->AS_Data.f_LO2 =
+	    MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
+			     state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
+	state->AS_Data.f_LO2 =
+	    MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2,
+			       state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
+
+	/*
+	 *  Check the upconverter and downconverter frequency ranges
+	 */
+	if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ)
+	    || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ))
+		status |= MT2063_UPC_RANGE;
+	if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ)
+	    || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ))
+		status |= MT2063_DNC_RANGE;
+	/*  LO2 Lock bit was in a different place for B0 version  */
+	if (state->tuner_id == MT2063_B0)
+		LO2LK = 0x40;
+
+	/*
+	 *  If we have the same LO frequencies and we're already locked,
+	 *  then skip re-programming the LO registers.
+	 */
+	if ((ofLO1 != state->AS_Data.f_LO1)
+	    || (ofLO2 != state->AS_Data.f_LO2)
+	    || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) !=
+		(LO1LK | LO2LK))) {
+		/*
+		 * Calculate the FIFFOF register value
+		 *
+		 *           IF1_Actual
+		 * FIFFOF = ------------ - 8 * FIFFC - 4992
+		 *            f_ref/64
+		 */
+		fiffof =
+		    (state->AS_Data.f_LO1 -
+		     f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc -
+		    4992;
+		if (fiffof > 0xFF)
+			fiffof = 0xFF;
+
+		/*
+		 * Place all of the calculated values into the local tuner
+		 * register fields.
+		 */
+		if (status >= 0) {
+			state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF);	/* DIV1q */
+			state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F);	/* NUM1q */
+			state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1)	/* DIV2q */
+								   |(Num2 >> 12));	/* NUM2q (hi) */
+			state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4);	/* NUM2q (mid) */
+			state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F));	/* NUM2q (lo) */
+
+			/*
+			 * Now write out the computed register values
+			 * IMPORTANT: There is a required order for writing
+			 *            (0x05 must follow all the others).
+			 */
+			status |= mt2063_write(state, MT2063_REG_LO1CQ_1, &state->reg[MT2063_REG_LO1CQ_1], 5);	/* 0x01 - 0x05 */
+			if (state->tuner_id == MT2063_B0) {
+				/* Re-write the one-shot bits to trigger the tune operation */
+				status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1);	/* 0x05 */
+			}
+			/* Write out the FIFF offset only if it's changing */
+			if (state->reg[MT2063_REG_FIFF_OFFSET] !=
+			    (u8) fiffof) {
+				state->reg[MT2063_REG_FIFF_OFFSET] =
+				    (u8) fiffof;
+				status |=
+				    mt2063_write(state,
+						    MT2063_REG_FIFF_OFFSET,
+						    &state->
+						    reg[MT2063_REG_FIFF_OFFSET],
+						    1);
+			}
+		}
+
+		/*
+		 * Check for LO's locking
+		 */
+
+		if (status < 0)
+			return status;
+
+		status = mt2063_lockStatus(state);
+		if (status < 0)
+			return status;
+		if (!status)
+			return -EINVAL;		/* Couldn't lock */
+
+		/*
+		 * If we locked OK, assign calculated data to mt2063_state structure
+		 */
+		state->f_IF1_actual = state->AS_Data.f_LO1 - f_in;
+	}
+
+	return status;
+}
+
+static const u8 MT2063B0_defaults[] = {
+	/* Reg,  Value */
+	0x19, 0x05,
+	0x1B, 0x1D,
+	0x1C, 0x1F,
+	0x1D, 0x0F,
+	0x1E, 0x3F,
+	0x1F, 0x0F,
+	0x20, 0x3F,
+	0x22, 0x21,
+	0x23, 0x3F,
+	0x24, 0x20,
+	0x25, 0x3F,
+	0x27, 0xEE,
+	0x2C, 0x27,	/*  bit at 0x20 is cleared below  */
+	0x30, 0x03,
+	0x2C, 0x07,	/*  bit at 0x20 is cleared here   */
+	0x2D, 0x87,
+	0x2E, 0xAA,
+	0x28, 0xE1,	/*  Set the FIFCrst bit here      */
+	0x28, 0xE0,	/*  Clear the FIFCrst bit here    */
+	0x00
+};
+
+/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
+static const u8 MT2063B1_defaults[] = {
+	/* Reg,  Value */
+	0x05, 0xF0,
+	0x11, 0x10,	/* New Enable AFCsd */
+	0x19, 0x05,
+	0x1A, 0x6C,
+	0x1B, 0x24,
+	0x1C, 0x28,
+	0x1D, 0x8F,
+	0x1E, 0x14,
+	0x1F, 0x8F,
+	0x20, 0x57,
+	0x22, 0x21,	/* New - ver 1.03 */
+	0x23, 0x3C,	/* New - ver 1.10 */
+	0x24, 0x20,	/* New - ver 1.03 */
+	0x2C, 0x24,	/*  bit at 0x20 is cleared below  */
+	0x2D, 0x87,	/*  FIFFQ=0  */
+	0x2F, 0xF3,
+	0x30, 0x0C,	/* New - ver 1.11 */
+	0x31, 0x1B,	/* New - ver 1.11 */
+	0x2C, 0x04,	/*  bit at 0x20 is cleared here  */
+	0x28, 0xE1,	/*  Set the FIFCrst bit here      */
+	0x28, 0xE0,	/*  Clear the FIFCrst bit here    */
+	0x00
+};
+
+/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
+static const u8 MT2063B3_defaults[] = {
+	/* Reg,  Value */
+	0x05, 0xF0,
+	0x19, 0x3D,
+	0x2C, 0x24,	/*  bit at 0x20 is cleared below  */
+	0x2C, 0x04,	/*  bit at 0x20 is cleared here  */
+	0x28, 0xE1,	/*  Set the FIFCrst bit here      */
+	0x28, 0xE0,	/*  Clear the FIFCrst bit here    */
+	0x00
+};
+
+static int mt2063_init(struct dvb_frontend *fe)
+{
+	u32 status;
+	struct mt2063_state *state = fe->tuner_priv;
+	u8 all_resets = 0xF0;	/* reset/load bits */
+	const u8 *def = NULL;
+	char *step;
+	u32 FCRUN;
+	s32 maxReads;
+	u32 fcu_osc;
+	u32 i;
+
+	dprintk(2, "\n");
+
+	state->rcvr_mode = MT2063_CABLE_QAM;
+
+	/*  Read the Part/Rev code from the tuner */
+	status = mt2063_read(state, MT2063_REG_PART_REV,
+			     &state->reg[MT2063_REG_PART_REV], 1);
+	if (status < 0) {
+		printk(KERN_ERR "Can't read mt2063 part ID\n");
+		return status;
+	}
+
+	/* Check the part/rev code */
+	switch (state->reg[MT2063_REG_PART_REV]) {
+	case MT2063_B0:
+		step = "B0";
+		break;
+	case MT2063_B1:
+		step = "B1";
+		break;
+	case MT2063_B2:
+		step = "B2";
+		break;
+	case MT2063_B3:
+		step = "B3";
+		break;
+	default:
+		printk(KERN_ERR "mt2063: Unknown mt2063 device ID (0x%02x)\n",
+		       state->reg[MT2063_REG_PART_REV]);
+		return -ENODEV;	/*  Wrong tuner Part/Rev code */
+	}
+
+	/*  Check the 2nd byte of the Part/Rev code from the tuner */
+	status = mt2063_read(state, MT2063_REG_RSVD_3B,
+			     &state->reg[MT2063_REG_RSVD_3B], 1);
+
+	/* b7 != 0 ==> NOT MT2063 */
+	if (status < 0 || ((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) {
+		printk(KERN_ERR "mt2063: Unknown part ID (0x%02x%02x)\n",
+		       state->reg[MT2063_REG_PART_REV],
+		       state->reg[MT2063_REG_RSVD_3B]);
+		return -ENODEV;	/*  Wrong tuner Part/Rev code */
+	}
+
+	printk(KERN_INFO "mt2063: detected a mt2063 %s\n", step);
+
+	/*  Reset the tuner  */
+	status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1);
+	if (status < 0)
+		return status;
+
+	/* change all of the default values that vary from the HW reset values */
+	/*  def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */
+	switch (state->reg[MT2063_REG_PART_REV]) {
+	case MT2063_B3:
+		def = MT2063B3_defaults;
+		break;
+
+	case MT2063_B1:
+		def = MT2063B1_defaults;
+		break;
+
+	case MT2063_B0:
+		def = MT2063B0_defaults;
+		break;
+
+	default:
+		return -ENODEV;
+		break;
+	}
+
+	while (status >= 0 && *def) {
+		u8 reg = *def++;
+		u8 val = *def++;
+		status = mt2063_write(state, reg, &val, 1);
+	}
+	if (status < 0)
+		return status;
+
+	/*  Wait for FIFF location to complete.  */
+	FCRUN = 1;
+	maxReads = 10;
+	while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) {
+		msleep(2);
+		status = mt2063_read(state,
+					 MT2063_REG_XO_STATUS,
+					 &state->
+					 reg[MT2063_REG_XO_STATUS], 1);
+		FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6;
+	}
+
+	if (FCRUN != 0 || status < 0)
+		return -ENODEV;
+
+	status = mt2063_read(state,
+			   MT2063_REG_FIFFC,
+			   &state->reg[MT2063_REG_FIFFC], 1);
+	if (status < 0)
+		return status;
+
+	/* Read back all the registers from the tuner */
+	status = mt2063_read(state,
+				MT2063_REG_PART_REV,
+				state->reg, MT2063_REG_END_REGS);
+	if (status < 0)
+		return status;
+
+	/*  Initialize the tuner state.  */
+	state->tuner_id = state->reg[MT2063_REG_PART_REV];
+	state->AS_Data.f_ref = MT2063_REF_FREQ;
+	state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) *
+				      ((u32) state->reg[MT2063_REG_FIFFC] + 640);
+	state->AS_Data.f_if1_bw = MT2063_IF1_BW;
+	state->AS_Data.f_out = 43750000UL;
+	state->AS_Data.f_out_bw = 6750000UL;
+	state->AS_Data.f_zif_bw = MT2063_ZIF_BW;
+	state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64;
+	state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE;
+	state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1;
+	state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2;
+	state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP;
+	state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center;
+	state->AS_Data.f_LO1 = 2181000000UL;
+	state->AS_Data.f_LO2 = 1486249786UL;
+	state->f_IF1_actual = state->AS_Data.f_if1_Center;
+	state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual;
+	state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID;
+	state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID;
+	state->num_regs = MT2063_REG_END_REGS;
+	state->AS_Data.avoidDECT = MT2063_AVOID_BOTH;
+	state->ctfilt_sw = 0;
+
+	state->CTFiltMax[0] = 69230000;
+	state->CTFiltMax[1] = 105770000;
+	state->CTFiltMax[2] = 140350000;
+	state->CTFiltMax[3] = 177110000;
+	state->CTFiltMax[4] = 212860000;
+	state->CTFiltMax[5] = 241130000;
+	state->CTFiltMax[6] = 274370000;
+	state->CTFiltMax[7] = 309820000;
+	state->CTFiltMax[8] = 342450000;
+	state->CTFiltMax[9] = 378870000;
+	state->CTFiltMax[10] = 416210000;
+	state->CTFiltMax[11] = 456500000;
+	state->CTFiltMax[12] = 495790000;
+	state->CTFiltMax[13] = 534530000;
+	state->CTFiltMax[14] = 572610000;
+	state->CTFiltMax[15] = 598970000;
+	state->CTFiltMax[16] = 635910000;
+	state->CTFiltMax[17] = 672130000;
+	state->CTFiltMax[18] = 714840000;
+	state->CTFiltMax[19] = 739660000;
+	state->CTFiltMax[20] = 770410000;
+	state->CTFiltMax[21] = 814660000;
+	state->CTFiltMax[22] = 846950000;
+	state->CTFiltMax[23] = 867820000;
+	state->CTFiltMax[24] = 915980000;
+	state->CTFiltMax[25] = 947450000;
+	state->CTFiltMax[26] = 983110000;
+	state->CTFiltMax[27] = 1021630000;
+	state->CTFiltMax[28] = 1061870000;
+	state->CTFiltMax[29] = 1098330000;
+	state->CTFiltMax[30] = 1138990000;
+
+	/*
+	 **   Fetch the FCU osc value and use it and the fRef value to
+	 **   scale all of the Band Max values
+	 */
+
+	state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A;
+	status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
+			      &state->reg[MT2063_REG_CTUNE_CTRL], 1);
+	if (status < 0)
+		return status;
+
+	/*  Read the ClearTune filter calibration value  */
+	status = mt2063_read(state, MT2063_REG_FIFFC,
+			     &state->reg[MT2063_REG_FIFFC], 1);
+	if (status < 0)
+		return status;
+
+	fcu_osc = state->reg[MT2063_REG_FIFFC];
+
+	state->reg[MT2063_REG_CTUNE_CTRL] = 0x00;
+	status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
+			      &state->reg[MT2063_REG_CTUNE_CTRL], 1);
+	if (status < 0)
+		return status;
+
+	/*  Adjust each of the values in the ClearTune filter cross-over table  */
+	for (i = 0; i < 31; i++)
+		state->CTFiltMax[i] = (state->CTFiltMax[i] / 768) * (fcu_osc + 640);
+
+	status = MT2063_SoftwareShutdown(state, 1);
+	if (status < 0)
+		return status;
+	status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
+	if (status < 0)
+		return status;
+
+	state->init = true;
+
+	return 0;
+}
+
+static int mt2063_get_status(struct dvb_frontend *fe, u32 *tuner_status)
+{
+	struct mt2063_state *state = fe->tuner_priv;
+	int status;
+
+	dprintk(2, "\n");
+
+	if (!state->init)
+		return -ENODEV;
+
+	*tuner_status = 0;
+	status = mt2063_lockStatus(state);
+	if (status < 0)
+		return status;
+	if (status)
+		*tuner_status = TUNER_STATUS_LOCKED;
+
+	dprintk(1, "Tuner status: %d", *tuner_status);
+
+	return 0;
+}
+
+static int mt2063_release(struct dvb_frontend *fe)
+{
+	struct mt2063_state *state = fe->tuner_priv;
+
+	dprintk(2, "\n");
+
+	fe->tuner_priv = NULL;
+	kfree(state);
+
+	return 0;
+}
+
+static int mt2063_set_analog_params(struct dvb_frontend *fe,
+				    struct analog_parameters *params)
+{
+	struct mt2063_state *state = fe->tuner_priv;
+	s32 pict_car;
+	s32 pict2chanb_vsb;
+	s32 ch_bw;
+	s32 if_mid;
+	s32 rcvr_mode;
+	int status;
+
+	dprintk(2, "\n");
+
+	if (!state->init) {
+		status = mt2063_init(fe);
+		if (status < 0)
+			return status;
+	}
+
+	switch (params->mode) {
+	case V4L2_TUNER_RADIO:
+		pict_car = 38900000;
+		ch_bw = 8000000;
+		pict2chanb_vsb = -(ch_bw / 2);
+		rcvr_mode = MT2063_OFFAIR_ANALOG;
+		break;
+	case V4L2_TUNER_ANALOG_TV:
+		rcvr_mode = MT2063_CABLE_ANALOG;
+		if (params->std & ~V4L2_STD_MN) {
+			pict_car = 38900000;
+			ch_bw = 6000000;
+			pict2chanb_vsb = -1250000;
+		} else if (params->std & V4L2_STD_PAL_G) {
+			pict_car = 38900000;
+			ch_bw = 7000000;
+			pict2chanb_vsb = -1250000;
+		} else {		/* PAL/SECAM standards */
+			pict_car = 38900000;
+			ch_bw = 8000000;
+			pict2chanb_vsb = -1250000;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+	if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
+
+	state->AS_Data.f_LO2_Step = 125000;	/* FIXME: probably 5000 for FM */
+	state->AS_Data.f_out = if_mid;
+	state->AS_Data.f_out_bw = ch_bw + 750000;
+	status = MT2063_SetReceiverMode(state, rcvr_mode);
+	if (status < 0)
+		return status;
+
+	dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n",
+		params->frequency, ch_bw, pict2chanb_vsb);
+
+	status = MT2063_Tune(state, (params->frequency + (pict2chanb_vsb + (ch_bw / 2))));
+	if (status < 0)
+		return status;
+
+	state->frequency = params->frequency;
+	return 0;
+}
+
+/*
+ * As defined on EN 300 429, the DVB-C roll-off factor is 0.15.
+ * So, the amount of the needed bandwith is given by:
+ *	Bw = Symbol_rate * (1 + 0.15)
+ * As such, the maximum symbol rate supported by 6 MHz is given by:
+ *	max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds
+ */
+#define MAX_SYMBOL_RATE_6MHz	5217391
+
+static int mt2063_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct mt2063_state *state = fe->tuner_priv;
+	int status;
+	s32 pict_car;
+	s32 pict2chanb_vsb;
+	s32 ch_bw;
+	s32 if_mid;
+	s32 rcvr_mode;
+
+	if (!state->init) {
+		status = mt2063_init(fe);
+		if (status < 0)
+			return status;
+	}
+
+	dprintk(2, "\n");
+
+	if (c->bandwidth_hz == 0)
+		return -EINVAL;
+	if (c->bandwidth_hz <= 6000000)
+		ch_bw = 6000000;
+	else if (c->bandwidth_hz <= 7000000)
+		ch_bw = 7000000;
+	else
+		ch_bw = 8000000;
+
+	switch (c->delivery_system) {
+	case SYS_DVBT:
+		rcvr_mode = MT2063_OFFAIR_COFDM;
+		pict_car = 36125000;
+		pict2chanb_vsb = -(ch_bw / 2);
+		break;
+	case SYS_DVBC_ANNEX_A:
+	case SYS_DVBC_ANNEX_C:
+		rcvr_mode = MT2063_CABLE_QAM;
+		pict_car = 36125000;
+		pict2chanb_vsb = -(ch_bw / 2);
+		break;
+	default:
+		return -EINVAL;
+	}
+	if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
+
+	state->AS_Data.f_LO2_Step = 125000;	/* FIXME: probably 5000 for FM */
+	state->AS_Data.f_out = if_mid;
+	state->AS_Data.f_out_bw = ch_bw + 750000;
+	status = MT2063_SetReceiverMode(state, rcvr_mode);
+	if (status < 0)
+		return status;
+
+	dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n",
+		c->frequency, ch_bw, pict2chanb_vsb);
+
+	status = MT2063_Tune(state, (c->frequency + (pict2chanb_vsb + (ch_bw / 2))));
+
+	if (status < 0)
+		return status;
+
+	state->frequency = c->frequency;
+	return 0;
+}
+
+static int mt2063_get_if_frequency(struct dvb_frontend *fe, u32 *freq)
+{
+	struct mt2063_state *state = fe->tuner_priv;
+
+	dprintk(2, "\n");
+
+	if (!state->init)
+		return -ENODEV;
+
+	*freq = state->AS_Data.f_out;
+
+	dprintk(1, "IF frequency: %d\n", *freq);
+
+	return 0;
+}
+
+static int mt2063_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
+{
+	struct mt2063_state *state = fe->tuner_priv;
+
+	dprintk(2, "\n");
+
+	if (!state->init)
+		return -ENODEV;
+
+	*bw = state->AS_Data.f_out_bw - 750000;
+
+	dprintk(1, "bandwidth: %d\n", *bw);
+
+	return 0;
+}
+
+static struct dvb_tuner_ops mt2063_ops = {
+	.info = {
+		 .name = "MT2063 Silicon Tuner",
+		 .frequency_min = 45000000,
+		 .frequency_max = 865000000,
+		 .frequency_step = 0,
+		 },
+
+	.init = mt2063_init,
+	.sleep = MT2063_Sleep,
+	.get_status = mt2063_get_status,
+	.set_analog_params = mt2063_set_analog_params,
+	.set_params    = mt2063_set_params,
+	.get_if_frequency = mt2063_get_if_frequency,
+	.get_bandwidth = mt2063_get_bandwidth,
+	.release = mt2063_release,
+};
+
+struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
+				   struct mt2063_config *config,
+				   struct i2c_adapter *i2c)
+{
+	struct mt2063_state *state = NULL;
+
+	dprintk(2, "\n");
+
+	state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	state->config = config;
+	state->i2c = i2c;
+	state->frontend = fe;
+	state->reference = config->refclock / 1000;	/* kHz */
+	fe->tuner_priv = state;
+	fe->ops.tuner_ops = mt2063_ops;
+
+	printk(KERN_INFO "%s: Attaching MT2063\n", __func__);
+	return fe;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(mt2063_attach);
+
+/*
+ * Ancillary routines visible outside mt2063
+ * FIXME: Remove them in favor of using standard tuner callbacks
+ */
+unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe)
+{
+	struct mt2063_state *state = fe->tuner_priv;
+	int err = 0;
+
+	dprintk(2, "\n");
+
+	err = MT2063_SoftwareShutdown(state, 1);
+	if (err < 0)
+		printk(KERN_ERR "%s: Couldn't shutdown\n", __func__);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown);
+
+unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe)
+{
+	struct mt2063_state *state = fe->tuner_priv;
+	int err = 0;
+
+	dprintk(2, "\n");
+
+	err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
+	if (err < 0)
+		printk(KERN_ERR "%s: Invalid parameter\n", __func__);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits);
+
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_DESCRIPTION("MT2063 Silicon tuner");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/mt2063.h b/drivers/media/tuners/mt2063.h
new file mode 100644
index 0000000..3f5cfd9
--- /dev/null
+++ b/drivers/media/tuners/mt2063.h
@@ -0,0 +1,32 @@
+#ifndef __MT2063_H__
+#define __MT2063_H__
+
+#include "dvb_frontend.h"
+
+struct mt2063_config {
+	u8 tuner_address;
+	u32 refclock;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_MT2063) || (defined(CONFIG_MEDIA_TUNER_MT2063_MODULE) && defined(MODULE))
+struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
+				   struct mt2063_config *config,
+				   struct i2c_adapter *i2c);
+
+#else
+
+static inline struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
+				   struct mt2063_config *config,
+				   struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+/* FIXME: Should use the standard DVB attachment interfaces */
+unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe);
+unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe);
+
+#endif /* CONFIG_DVB_MT2063 */
+
+#endif /* __MT2063_H__ */
diff --git a/drivers/media/tuners/mt20xx.c b/drivers/media/tuners/mt20xx.c
new file mode 100644
index 0000000..0e74e97
--- /dev/null
+++ b/drivers/media/tuners/mt20xx.c
@@ -0,0 +1,670 @@
+/*
+ * i2c tv tuner chip device driver
+ * controls microtune tuners, mt2032 + mt2050 at the moment.
+ *
+ * This "mt20xx" module was split apart from the original "tuner" module.
+ */
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include "tuner-i2c.h"
+#include "mt20xx.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+/* ---------------------------------------------------------------------- */
+
+static unsigned int optimize_vco  = 1;
+module_param(optimize_vco,      int, 0644);
+
+static unsigned int tv_antenna    = 1;
+module_param(tv_antenna,        int, 0644);
+
+static unsigned int radio_antenna;
+module_param(radio_antenna,     int, 0644);
+
+/* ---------------------------------------------------------------------- */
+
+#define MT2032 0x04
+#define MT2030 0x06
+#define MT2040 0x07
+#define MT2050 0x42
+
+static char *microtune_part[] = {
+	[ MT2030 ] = "MT2030",
+	[ MT2032 ] = "MT2032",
+	[ MT2040 ] = "MT2040",
+	[ MT2050 ] = "MT2050",
+};
+
+struct microtune_priv {
+	struct tuner_i2c_props i2c_props;
+
+	unsigned int xogc;
+	//unsigned int radio_if2;
+
+	u32 frequency;
+};
+
+static int microtune_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static int microtune_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct microtune_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+// IsSpurInBand()?
+static int mt2032_spurcheck(struct dvb_frontend *fe,
+			    int f1, int f2, int spectrum_from,int spectrum_to)
+{
+	struct microtune_priv *priv = fe->tuner_priv;
+	int n1=1,n2,f;
+
+	f1=f1/1000; //scale to kHz to avoid 32bit overflows
+	f2=f2/1000;
+	spectrum_from/=1000;
+	spectrum_to/=1000;
+
+	tuner_dbg("spurcheck f1=%d f2=%d  from=%d to=%d\n",
+		  f1,f2,spectrum_from,spectrum_to);
+
+	do {
+	    n2=-n1;
+	    f=n1*(f1-f2);
+	    do {
+		n2--;
+		f=f-f2;
+		tuner_dbg("spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f);
+
+		if( (f>spectrum_from) && (f<spectrum_to))
+			tuner_dbg("mt2032 spurcheck triggered: %d\n",n1);
+	    } while ( (f>(f2-spectrum_to)) || (n2>-5));
+	    n1++;
+	} while (n1<5);
+
+	return 1;
+}
+
+static int mt2032_compute_freq(struct dvb_frontend *fe,
+			       unsigned int rfin,
+			       unsigned int if1, unsigned int if2,
+			       unsigned int spectrum_from,
+			       unsigned int spectrum_to,
+			       unsigned char *buf,
+			       int *ret_sel,
+			       unsigned int xogc) //all in Hz
+{
+	struct microtune_priv *priv = fe->tuner_priv;
+	unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
+		desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq;
+
+	fref= 5250 *1000; //5.25MHz
+	desired_lo1=rfin+if1;
+
+	lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000);
+	lo1n=lo1/8;
+	lo1a=lo1-(lo1n*8);
+
+	s=rfin/1000/1000+1090;
+
+	if(optimize_vco) {
+		if(s>1890) sel=0;
+		else if(s>1720) sel=1;
+		else if(s>1530) sel=2;
+		else if(s>1370) sel=3;
+		else sel=4; // >1090
+	}
+	else {
+		if(s>1790) sel=0; // <1958
+		else if(s>1617) sel=1;
+		else if(s>1449) sel=2;
+		else if(s>1291) sel=3;
+		else sel=4; // >1090
+	}
+	*ret_sel=sel;
+
+	lo1freq=(lo1a+8*lo1n)*fref;
+
+	tuner_dbg("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n",
+		  rfin,lo1,lo1n,lo1a,sel,lo1freq);
+
+	desired_lo2=lo1freq-rfin-if2;
+	lo2=(desired_lo2)/fref;
+	lo2n=lo2/8;
+	lo2a=lo2-(lo2n*8);
+	lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith
+	lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000;
+
+	tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n",
+		  rfin,lo2,lo2n,lo2a,lo2num,lo2freq);
+
+	if (lo1a > 7 || lo1n < 17 || lo1n > 48 || lo2a > 7 || lo2n < 17 ||
+			lo2n > 30) {
+		tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n",
+			   lo1a, lo1n, lo2a,lo2n);
+		return(-1);
+	}
+
+	mt2032_spurcheck(fe, lo1freq, desired_lo2,  spectrum_from, spectrum_to);
+	// should recalculate lo1 (one step up/down)
+
+	// set up MT2032 register map for transfer over i2c
+	buf[0]=lo1n-1;
+	buf[1]=lo1a | (sel<<4);
+	buf[2]=0x86; // LOGC
+	buf[3]=0x0f; //reserved
+	buf[4]=0x1f;
+	buf[5]=(lo2n-1) | (lo2a<<5);
+	if(rfin >400*1000*1000)
+		buf[6]=0xe4;
+	else
+		buf[6]=0xf4; // set PKEN per rev 1.2
+	buf[7]=8+xogc;
+	buf[8]=0xc3; //reserved
+	buf[9]=0x4e; //reserved
+	buf[10]=0xec; //reserved
+	buf[11]=(lo2num&0xff);
+	buf[12]=(lo2num>>8) |0x80; // Lo2RST
+
+	return 0;
+}
+
+static int mt2032_check_lo_lock(struct dvb_frontend *fe)
+{
+	struct microtune_priv *priv = fe->tuner_priv;
+	int try,lock=0;
+	unsigned char buf[2];
+
+	for(try=0;try<10;try++) {
+		buf[0]=0x0e;
+		tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+		tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
+		tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]);
+		lock=buf[0] &0x06;
+
+		if (lock==6)
+			break;
+
+		tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]);
+		udelay(1000);
+	}
+	return lock;
+}
+
+static int mt2032_optimize_vco(struct dvb_frontend *fe,int sel,int lock)
+{
+	struct microtune_priv *priv = fe->tuner_priv;
+	unsigned char buf[2];
+	int tad1;
+
+	buf[0]=0x0f;
+	tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+	tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
+	tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]);
+	tad1=buf[0]&0x07;
+
+	if(tad1 ==0) return lock;
+	if(tad1 ==1) return lock;
+
+	if(tad1==2) {
+		if(sel==0)
+			return lock;
+		else sel--;
+	}
+	else {
+		if(sel<4)
+			sel++;
+		else
+			return lock;
+	}
+
+	tuner_dbg("mt2032 optimize_vco: sel=%d\n",sel);
+
+	buf[0]=0x0f;
+	buf[1]=sel;
+	tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
+	lock=mt2032_check_lo_lock(fe);
+	return lock;
+}
+
+
+static void mt2032_set_if_freq(struct dvb_frontend *fe, unsigned int rfin,
+			       unsigned int if1, unsigned int if2,
+			       unsigned int from, unsigned int to)
+{
+	unsigned char buf[21];
+	int lint_try,ret,sel,lock=0;
+	struct microtune_priv *priv = fe->tuner_priv;
+
+	tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",
+		  rfin,if1,if2,from,to);
+
+	buf[0]=0;
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+	tuner_i2c_xfer_recv(&priv->i2c_props,buf,21);
+
+	buf[0]=0;
+	ret=mt2032_compute_freq(fe,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc);
+	if (ret<0)
+		return;
+
+	// send only the relevant registers per Rev. 1.2
+	buf[0]=0;
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,4);
+	buf[5]=5;
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,4);
+	buf[11]=11;
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+11,3);
+	if(ret!=3)
+		tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret);
+
+	// wait for PLLs to lock (per manual), retry LINT if not.
+	for(lint_try=0; lint_try<2; lint_try++) {
+		lock=mt2032_check_lo_lock(fe);
+
+		if(optimize_vco)
+			lock=mt2032_optimize_vco(fe,sel,lock);
+		if(lock==6) break;
+
+		tuner_dbg("mt2032: re-init PLLs by LINT\n");
+		buf[0]=7;
+		buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs
+		tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
+		mdelay(10);
+		buf[1]=8+priv->xogc;
+		tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
+	}
+
+	if (lock!=6)
+		tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n");
+
+	buf[0]=2;
+	buf[1]=0x20; // LOGC for optimal phase noise
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
+	if (ret!=2)
+		tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
+}
+
+
+static int mt2032_set_tv_freq(struct dvb_frontend *fe,
+			      struct analog_parameters *params)
+{
+	int if2,from,to;
+
+	// signal bandwidth and picture carrier
+	if (params->std & V4L2_STD_525_60) {
+		// NTSC
+		from = 40750*1000;
+		to   = 46750*1000;
+		if2  = 45750*1000;
+	} else {
+		// PAL
+		from = 32900*1000;
+		to   = 39900*1000;
+		if2  = 38900*1000;
+	}
+
+	mt2032_set_if_freq(fe, params->frequency*62500,
+			   1090*1000*1000, if2, from, to);
+
+	return 0;
+}
+
+static int mt2032_set_radio_freq(struct dvb_frontend *fe,
+				 struct analog_parameters *params)
+{
+	struct microtune_priv *priv = fe->tuner_priv;
+	int if2;
+
+	if (params->std & V4L2_STD_525_60) {
+		tuner_dbg("pinnacle ntsc\n");
+		if2 = 41300 * 1000;
+	} else {
+		tuner_dbg("pinnacle pal\n");
+		if2 = 33300 * 1000;
+	}
+
+	// per Manual for FM tuning: first if center freq. 1085 MHz
+	mt2032_set_if_freq(fe, params->frequency * 125 / 2,
+			   1085*1000*1000,if2,if2,if2);
+
+	return 0;
+}
+
+static int mt2032_set_params(struct dvb_frontend *fe,
+			     struct analog_parameters *params)
+{
+	struct microtune_priv *priv = fe->tuner_priv;
+	int ret = -EINVAL;
+
+	switch (params->mode) {
+	case V4L2_TUNER_RADIO:
+		ret = mt2032_set_radio_freq(fe, params);
+		priv->frequency = params->frequency * 125 / 2;
+		break;
+	case V4L2_TUNER_ANALOG_TV:
+	case V4L2_TUNER_DIGITAL_TV:
+		ret = mt2032_set_tv_freq(fe, params);
+		priv->frequency = params->frequency * 62500;
+		break;
+	}
+
+	return ret;
+}
+
+static struct dvb_tuner_ops mt2032_tuner_ops = {
+	.set_analog_params = mt2032_set_params,
+	.release           = microtune_release,
+	.get_frequency     = microtune_get_frequency,
+};
+
+// Initialization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
+static int mt2032_init(struct dvb_frontend *fe)
+{
+	struct microtune_priv *priv = fe->tuner_priv;
+	unsigned char buf[21];
+	int ret,xogc,xok=0;
+
+	// Initialize Registers per spec.
+	buf[1]=2; // Index to register 2
+	buf[2]=0xff;
+	buf[3]=0x0f;
+	buf[4]=0x1f;
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+1,4);
+
+	buf[5]=6; // Index register 6
+	buf[6]=0xe4;
+	buf[7]=0x8f;
+	buf[8]=0xc3;
+	buf[9]=0x4e;
+	buf[10]=0xec;
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,6);
+
+	buf[12]=13;  // Index register 13
+	buf[13]=0x32;
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+12,2);
+
+	// Adjust XOGC (register 7), wait for XOK
+	xogc=7;
+	do {
+		tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
+		mdelay(10);
+		buf[0]=0x0e;
+		tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+		tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
+		xok=buf[0]&0x01;
+		tuner_dbg("mt2032: xok = 0x%02x\n",xok);
+		if (xok == 1) break;
+
+		xogc--;
+		tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
+		if (xogc == 3) {
+			xogc=4; // min. 4 per spec
+			break;
+		}
+		buf[0]=0x07;
+		buf[1]=0x88 + xogc;
+		ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
+		if (ret!=2)
+			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
+	} while (xok != 1 );
+	priv->xogc=xogc;
+
+	memcpy(&fe->ops.tuner_ops, &mt2032_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+	return(1);
+}
+
+static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna)
+{
+	struct microtune_priv *priv = fe->tuner_priv;
+	unsigned char buf[2];
+
+	buf[0] = 6;
+	buf[1] = antenna ? 0x11 : 0x10;
+	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
+	tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
+}
+
+static void mt2050_set_if_freq(struct dvb_frontend *fe,unsigned int freq, unsigned int if2)
+{
+	struct microtune_priv *priv = fe->tuner_priv;
+	unsigned int if1=1218*1000*1000;
+	unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b;
+	int ret;
+	unsigned char buf[6];
+
+	tuner_dbg("mt2050_set_if_freq freq=%d if1=%d if2=%d\n",
+		  freq,if1,if2);
+
+	f_lo1=freq+if1;
+	f_lo1=(f_lo1/1000000)*1000000;
+
+	f_lo2=f_lo1-freq-if2;
+	f_lo2=(f_lo2/50000)*50000;
+
+	lo1=f_lo1/4000000;
+	lo2=f_lo2/4000000;
+
+	f_lo1_modulo= f_lo1-(lo1*4000000);
+	f_lo2_modulo= f_lo2-(lo2*4000000);
+
+	num1=4*f_lo1_modulo/4000000;
+	num2=4096*(f_lo2_modulo/1000)/4000;
+
+	// todo spurchecks
+
+	div1a=(lo1/12)-1;
+	div1b=lo1-(div1a+1)*12;
+
+	div2a=(lo2/8)-1;
+	div2b=lo2-(div2a+1)*8;
+
+	if (debug > 1) {
+		tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2);
+		tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n",
+			  num1,num2,div1a,div1b,div2a,div2b);
+	}
+
+	buf[0]=1;
+	buf[1]= 4*div1b + num1;
+	if(freq<275*1000*1000) buf[1] = buf[1]|0x80;
+
+	buf[2]=div1a;
+	buf[3]=32*div2b + num2/256;
+	buf[4]=num2-(num2/256)*256;
+	buf[5]=div2a;
+	if(num2!=0) buf[5]=buf[5]|0x40;
+
+	if (debug > 1) {
+		int i;
+		tuner_dbg("bufs is: ");
+		for(i=0;i<6;i++)
+			printk("%x ",buf[i]);
+		printk("\n");
+	}
+
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,6);
+	if (ret!=6)
+		tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret);
+}
+
+static int mt2050_set_tv_freq(struct dvb_frontend *fe,
+			      struct analog_parameters *params)
+{
+	unsigned int if2;
+
+	if (params->std & V4L2_STD_525_60) {
+		// NTSC
+		if2 = 45750*1000;
+	} else {
+		// PAL
+		if2 = 38900*1000;
+	}
+	if (V4L2_TUNER_DIGITAL_TV == params->mode) {
+		// DVB (pinnacle 300i)
+		if2 = 36150*1000;
+	}
+	mt2050_set_if_freq(fe, params->frequency*62500, if2);
+	mt2050_set_antenna(fe, tv_antenna);
+
+	return 0;
+}
+
+static int mt2050_set_radio_freq(struct dvb_frontend *fe,
+				 struct analog_parameters *params)
+{
+	struct microtune_priv *priv = fe->tuner_priv;
+	int if2;
+
+	if (params->std & V4L2_STD_525_60) {
+		tuner_dbg("pinnacle ntsc\n");
+		if2 = 41300 * 1000;
+	} else {
+		tuner_dbg("pinnacle pal\n");
+		if2 = 33300 * 1000;
+	}
+
+	mt2050_set_if_freq(fe, params->frequency * 125 / 2, if2);
+	mt2050_set_antenna(fe, radio_antenna);
+
+	return 0;
+}
+
+static int mt2050_set_params(struct dvb_frontend *fe,
+			     struct analog_parameters *params)
+{
+	struct microtune_priv *priv = fe->tuner_priv;
+	int ret = -EINVAL;
+
+	switch (params->mode) {
+	case V4L2_TUNER_RADIO:
+		ret = mt2050_set_radio_freq(fe, params);
+		priv->frequency = params->frequency * 125 / 2;
+		break;
+	case V4L2_TUNER_ANALOG_TV:
+	case V4L2_TUNER_DIGITAL_TV:
+		ret = mt2050_set_tv_freq(fe, params);
+		priv->frequency = params->frequency * 62500;
+		break;
+	}
+
+	return ret;
+}
+
+static struct dvb_tuner_ops mt2050_tuner_ops = {
+	.set_analog_params = mt2050_set_params,
+	.release           = microtune_release,
+	.get_frequency     = microtune_get_frequency,
+};
+
+static int mt2050_init(struct dvb_frontend *fe)
+{
+	struct microtune_priv *priv = fe->tuner_priv;
+	unsigned char buf[2];
+
+	buf[0] = 6;
+	buf[1] = 0x10;
+	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); /* power */
+
+	buf[0] = 0x0f;
+	buf[1] = 0x0f;
+	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); /* m1lo */
+
+	buf[0] = 0x0d;
+	tuner_i2c_xfer_send(&priv->i2c_props, buf, 1);
+	tuner_i2c_xfer_recv(&priv->i2c_props, buf, 1);
+
+	tuner_dbg("mt2050: sro is %x\n", buf[0]);
+
+	memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+	return 0;
+}
+
+struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
+				      struct i2c_adapter* i2c_adap,
+				      u8 i2c_addr)
+{
+	struct microtune_priv *priv = NULL;
+	char *name;
+	unsigned char buf[21];
+	int company_code;
+
+	priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+	fe->tuner_priv = priv;
+
+	priv->i2c_props.addr = i2c_addr;
+	priv->i2c_props.adap = i2c_adap;
+	priv->i2c_props.name = "mt20xx";
+
+	//priv->radio_if2 = 10700 * 1000;	/* 10.7MHz - FM radio */
+
+	memset(buf,0,sizeof(buf));
+
+	name = "unknown";
+
+	tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+	tuner_i2c_xfer_recv(&priv->i2c_props,buf,21);
+	if (debug) {
+		int i;
+		tuner_dbg("MT20xx hexdump:");
+		for(i=0;i<21;i++) {
+			printk(" %02x",buf[i]);
+			if(((i+1)%8)==0) printk(" ");
+		}
+		printk("\n");
+	}
+	company_code = buf[0x11] << 8 | buf[0x12];
+	tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n",
+		   company_code,buf[0x13],buf[0x14]);
+
+
+	if (buf[0x13] < ARRAY_SIZE(microtune_part) &&
+	    NULL != microtune_part[buf[0x13]])
+		name = microtune_part[buf[0x13]];
+	switch (buf[0x13]) {
+	case MT2032:
+		mt2032_init(fe);
+		break;
+	case MT2050:
+		mt2050_init(fe);
+		break;
+	default:
+		tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n",
+			   name);
+		return NULL;
+	}
+
+	strlcpy(fe->ops.tuner_ops.info.name, name,
+		sizeof(fe->ops.tuner_ops.info.name));
+	tuner_info("microtune %s found, OK\n",name);
+	return fe;
+}
+
+EXPORT_SYMBOL_GPL(microtune_attach);
+
+MODULE_DESCRIPTION("Microtune tuner driver");
+MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
+MODULE_LICENSE("GPL");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/tuners/mt20xx.h b/drivers/media/tuners/mt20xx.h
new file mode 100644
index 0000000..259553a
--- /dev/null
+++ b/drivers/media/tuners/mt20xx.h
@@ -0,0 +1,37 @@
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MT20XX_H__
+#define __MT20XX_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_MEDIA_TUNER_MT20XX) || (defined(CONFIG_MEDIA_TUNER_MT20XX_MODULE) && defined(MODULE))
+extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
+					     struct i2c_adapter* i2c_adap,
+					     u8 i2c_addr);
+#else
+static inline struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
+					     struct i2c_adapter* i2c_adap,
+					     u8 i2c_addr)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* __MT20XX_H__ */
diff --git a/drivers/media/tuners/mt2131.c b/drivers/media/tuners/mt2131.c
new file mode 100644
index 0000000..f83b0c1
--- /dev/null
+++ b/drivers/media/tuners/mt2131.c
@@ -0,0 +1,301 @@
+/*
+ *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+
+#include "mt2131.h"
+#include "mt2131_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+	printk(KERN_INFO "%s: " fmt, "mt2131", ## arg)
+
+static u8 mt2131_config1[] = {
+	0x01,
+	0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88,
+	0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32,
+	0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80,
+	0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00
+};
+
+static u8 mt2131_config2[] = {
+	0x10,
+	0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04
+};
+
+static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->cfg->i2c_address, .flags = 0,
+		  .buf = &reg, .len = 1 },
+		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
+		  .buf = val,  .len = 1 },
+	};
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		printk(KERN_WARNING "mt2131 I2C read failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val)
+{
+	u8 buf[2] = { reg, val };
+	struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0,
+			       .buf = buf, .len = 2 };
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "mt2131 I2C write failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len)
+{
+	struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+			       .flags = 0, .buf = buf, .len = len };
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n",
+		       (int)len);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int mt2131_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct mt2131_priv *priv;
+	int ret=0, i;
+	u32 freq;
+	u8  if_band_center;
+	u32 f_lo1, f_lo2;
+	u32 div1, num1, div2, num2;
+	u8  b[8];
+	u8 lockval = 0;
+
+	priv = fe->tuner_priv;
+
+	freq = c->frequency / 1000;  /* Hz -> kHz */
+	dprintk(1, "%s() freq=%d\n", __func__, freq);
+
+	f_lo1 = freq + MT2131_IF1 * 1000;
+	f_lo1 = (f_lo1 / 250) * 250;
+	f_lo2 = f_lo1 - freq - MT2131_IF2;
+
+	priv->frequency =  (f_lo1 - f_lo2 - MT2131_IF2) * 1000;
+
+	/* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */
+	num1 = f_lo1 * 64 / (MT2131_FREF / 128);
+	div1 = num1 / 8192;
+	num1 &= 0x1fff;
+
+	/* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */
+	num2 = f_lo2 * 64 / (MT2131_FREF / 128);
+	div2 = num2 / 8192;
+	num2 &= 0x1fff;
+
+	if (freq <=   82500) if_band_center = 0x00; else
+	if (freq <=  137500) if_band_center = 0x01; else
+	if (freq <=  192500) if_band_center = 0x02; else
+	if (freq <=  247500) if_band_center = 0x03; else
+	if (freq <=  302500) if_band_center = 0x04; else
+	if (freq <=  357500) if_band_center = 0x05; else
+	if (freq <=  412500) if_band_center = 0x06; else
+	if (freq <=  467500) if_band_center = 0x07; else
+	if (freq <=  522500) if_band_center = 0x08; else
+	if (freq <=  577500) if_band_center = 0x09; else
+	if (freq <=  632500) if_band_center = 0x0A; else
+	if (freq <=  687500) if_band_center = 0x0B; else
+	if (freq <=  742500) if_band_center = 0x0C; else
+	if (freq <=  797500) if_band_center = 0x0D; else
+	if (freq <=  852500) if_band_center = 0x0E; else
+	if (freq <=  907500) if_band_center = 0x0F; else
+	if (freq <=  962500) if_band_center = 0x10; else
+	if (freq <= 1017500) if_band_center = 0x11; else
+	if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13;
+
+	b[0] = 1;
+	b[1] = (num1 >> 5) & 0xFF;
+	b[2] = (num1 & 0x1F);
+	b[3] = div1;
+	b[4] = (num2 >> 5) & 0xFF;
+	b[5] = num2 & 0x1F;
+	b[6] = div2;
+
+	dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2);
+	dprintk(1, "PLL freq=%dkHz  band=%d\n", (int)freq, (int)if_band_center);
+	dprintk(1, "PLL f_lo1=%dkHz  f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2);
+	dprintk(1, "PLL div1=%d  num1=%d  div2=%d  num2=%d\n",
+		(int)div1, (int)num1, (int)div2, (int)num2);
+	dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n",
+		(int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5],
+		(int)b[6]);
+
+	ret = mt2131_writeregs(priv,b,7);
+	if (ret < 0)
+		return ret;
+
+	mt2131_writereg(priv, 0x0b, if_band_center);
+
+	/* Wait for lock */
+	i = 0;
+	do {
+		mt2131_readreg(priv, 0x08, &lockval);
+		if ((lockval & 0x88) == 0x88)
+			break;
+		msleep(4);
+		i++;
+	} while (i < 10);
+
+	return ret;
+}
+
+static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct mt2131_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __func__);
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int mt2131_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct mt2131_priv *priv = fe->tuner_priv;
+	u8 lock_status = 0;
+	u8 afc_status = 0;
+
+	*status = 0;
+
+	mt2131_readreg(priv, 0x08, &lock_status);
+	if ((lock_status & 0x88) == 0x88)
+		*status = TUNER_STATUS_LOCKED;
+
+	mt2131_readreg(priv, 0x09, &afc_status);
+	dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n",
+		__func__, lock_status, afc_status);
+
+	return 0;
+}
+
+static int mt2131_init(struct dvb_frontend *fe)
+{
+	struct mt2131_priv *priv = fe->tuner_priv;
+	int ret;
+	dprintk(1, "%s()\n", __func__);
+
+	if ((ret = mt2131_writeregs(priv, mt2131_config1,
+				    sizeof(mt2131_config1))) < 0)
+		return ret;
+
+	mt2131_writereg(priv, 0x0b, 0x09);
+	mt2131_writereg(priv, 0x15, 0x47);
+	mt2131_writereg(priv, 0x07, 0xf2);
+	mt2131_writereg(priv, 0x0b, 0x01);
+
+	if ((ret = mt2131_writeregs(priv, mt2131_config2,
+				    sizeof(mt2131_config2))) < 0)
+		return ret;
+
+	return ret;
+}
+
+static int mt2131_release(struct dvb_frontend *fe)
+{
+	dprintk(1, "%s()\n", __func__);
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static const struct dvb_tuner_ops mt2131_tuner_ops = {
+	.info = {
+		.name           = "Microtune MT2131",
+		.frequency_min  =  48000000,
+		.frequency_max  = 860000000,
+		.frequency_step =     50000,
+	},
+
+	.release       = mt2131_release,
+	.init          = mt2131_init,
+
+	.set_params    = mt2131_set_params,
+	.get_frequency = mt2131_get_frequency,
+	.get_status    = mt2131_get_status
+};
+
+struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe,
+				    struct i2c_adapter *i2c,
+				    struct mt2131_config *cfg, u16 if1)
+{
+	struct mt2131_priv *priv = NULL;
+	u8 id = 0;
+
+	dprintk(1, "%s()\n", __func__);
+
+	priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->cfg = cfg;
+	priv->i2c = i2c;
+
+	if (mt2131_readreg(priv, 0, &id) != 0) {
+		kfree(priv);
+		return NULL;
+	}
+	if ( (id != 0x3E) && (id != 0x3F) ) {
+		printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n",
+		       cfg->i2c_address);
+		kfree(priv);
+		return NULL;
+	}
+
+	printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n",
+	       cfg->i2c_address);
+	memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+	return fe;
+}
+EXPORT_SYMBOL(mt2131_attach);
+
+MODULE_AUTHOR("Steven Toth");
+MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/tuners/mt2131.h b/drivers/media/tuners/mt2131.h
new file mode 100644
index 0000000..6632de6
--- /dev/null
+++ b/drivers/media/tuners/mt2131.h
@@ -0,0 +1,54 @@
+/*
+ *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MT2131_H__
+#define __MT2131_H__
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct mt2131_config {
+	u8 i2c_address;
+	u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
+};
+
+#if defined(CONFIG_MEDIA_TUNER_MT2131) || (defined(CONFIG_MEDIA_TUNER_MT2131_MODULE) && defined(MODULE))
+extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
+					  struct i2c_adapter *i2c,
+					  struct mt2131_config *cfg,
+					  u16 if1);
+#else
+static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
+						 struct i2c_adapter *i2c,
+						 struct mt2131_config *cfg,
+						 u16 if1)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_MEDIA_TUNER_MT2131 */
+
+#endif /* __MT2131_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/tuners/mt2131_priv.h b/drivers/media/tuners/mt2131_priv.h
new file mode 100644
index 0000000..62aeedf
--- /dev/null
+++ b/drivers/media/tuners/mt2131_priv.h
@@ -0,0 +1,48 @@
+/*
+ *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MT2131_PRIV_H__
+#define __MT2131_PRIV_H__
+
+/* Regs */
+#define MT2131_PWR              0x07
+#define MT2131_UPC_1            0x0b
+#define MT2131_AGC_RL           0x10
+#define MT2131_MISC_2           0x15
+
+/* frequency values in KHz */
+#define MT2131_IF1              1220
+#define MT2131_IF2              44000
+#define MT2131_FREF             16000
+
+struct mt2131_priv {
+	struct mt2131_config *cfg;
+	struct i2c_adapter   *i2c;
+
+	u32 frequency;
+};
+
+#endif /* __MT2131_PRIV_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/tuners/mt2266.c b/drivers/media/tuners/mt2266.c
new file mode 100644
index 0000000..bca4d75
--- /dev/null
+++ b/drivers/media/tuners/mt2266.c
@@ -0,0 +1,353 @@
+/*
+ *  Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
+ *
+ *  Copyright (c) 2007 Olivier DANET <odanet@caramail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "mt2266.h"
+
+#define I2C_ADDRESS 0x60
+
+#define REG_PART_REV   0
+#define REG_TUNE       1
+#define REG_BAND       6
+#define REG_BANDWIDTH  8
+#define REG_LOCK       0x12
+
+#define PART_REV 0x85
+
+struct mt2266_priv {
+	struct mt2266_config *cfg;
+	struct i2c_adapter   *i2c;
+
+	u32 frequency;
+	u32 bandwidth;
+	u8 band;
+};
+
+#define MT2266_VHF 1
+#define MT2266_UHF 0
+
+/* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0)
+
+// Reads a single register
+static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
+		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val,  .len = 1 },
+	};
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		printk(KERN_WARNING "MT2266 I2C read failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+// Writes a single register
+static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val)
+{
+	u8 buf[2] = { reg, val };
+	struct i2c_msg msg = {
+		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
+	};
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "MT2266 I2C write failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+// Writes a set of consecutive registers
+static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len)
+{
+	struct i2c_msg msg = {
+		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len
+	};
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+// Initialisation sequences
+static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28,
+				 0x00, 0x52, 0x99, 0x3f };
+
+static u8 mt2266_init2[] = {
+    0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4,
+    0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14,
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff,
+    0xff, 0x00, 0x77, 0x0f, 0x2d
+};
+
+static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22,
+						0x22, 0x22, 0x22, 0x22 };
+
+static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32,
+						0x32, 0x32, 0x32, 0x32 };
+
+static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7,
+						0xa7, 0xa7, 0xa7, 0xa7 };
+
+static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64,
+			   0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 };
+
+static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5,
+			   0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f };
+
+#define FREF 30000       // Quartz oscillator 30 MHz
+
+static int mt2266_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct mt2266_priv *priv;
+	int ret=0;
+	u32 freq;
+	u32 tune;
+	u8  lnaband;
+	u8  b[10];
+	int i;
+	u8 band;
+
+	priv = fe->tuner_priv;
+
+	freq = priv->frequency / 1000; /* Hz -> kHz */
+	if (freq < 470000 && freq > 230000)
+		return -EINVAL; /* Gap between VHF and UHF bands */
+
+	priv->frequency = c->frequency;
+	tune = 2 * freq * (8192/16) / (FREF/16);
+	band = (freq < 300000) ? MT2266_VHF : MT2266_UHF;
+	if (band == MT2266_VHF)
+		tune *= 2;
+
+	switch (c->bandwidth_hz) {
+	case 6000000:
+		mt2266_writeregs(priv, mt2266_init_6mhz,
+				 sizeof(mt2266_init_6mhz));
+		break;
+	case 8000000:
+		mt2266_writeregs(priv, mt2266_init_8mhz,
+				 sizeof(mt2266_init_8mhz));
+		break;
+	case 7000000:
+	default:
+		mt2266_writeregs(priv, mt2266_init_7mhz,
+				 sizeof(mt2266_init_7mhz));
+		break;
+	}
+	priv->bandwidth = c->bandwidth_hz;
+
+	if (band == MT2266_VHF && priv->band == MT2266_UHF) {
+		dprintk("Switch from UHF to VHF");
+		mt2266_writereg(priv, 0x05, 0x04);
+		mt2266_writereg(priv, 0x19, 0x61);
+		mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf));
+	} else if (band == MT2266_UHF && priv->band == MT2266_VHF) {
+		dprintk("Switch from VHF to UHF");
+		mt2266_writereg(priv, 0x05, 0x52);
+		mt2266_writereg(priv, 0x19, 0x61);
+		mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf));
+	}
+	msleep(10);
+
+	if (freq <= 495000)
+		lnaband = 0xEE;
+	else if (freq <= 525000)
+		lnaband = 0xDD;
+	else if (freq <= 550000)
+		lnaband = 0xCC;
+	else if (freq <= 580000)
+		lnaband = 0xBB;
+	else if (freq <= 605000)
+		lnaband = 0xAA;
+	else if (freq <= 630000)
+		lnaband = 0x99;
+	else if (freq <= 655000)
+		lnaband = 0x88;
+	else if (freq <= 685000)
+		lnaband = 0x77;
+	else if (freq <= 710000)
+		lnaband = 0x66;
+	else if (freq <= 735000)
+		lnaband = 0x55;
+	else if (freq <= 765000)
+		lnaband = 0x44;
+	else if (freq <= 802000)
+		lnaband = 0x33;
+	else if (freq <= 840000)
+		lnaband = 0x22;
+	else
+		lnaband = 0x11;
+
+	b[0] = REG_TUNE;
+	b[1] = (tune >> 8) & 0x1F;
+	b[2] = tune & 0xFF;
+	b[3] = tune >> 13;
+	mt2266_writeregs(priv,b,4);
+
+	dprintk("set_parms: tune=%d band=%d %s",
+		(int) tune, (int) lnaband,
+		(band == MT2266_UHF) ? "UHF" : "VHF");
+	dprintk("set_parms: [1..3]: %2x %2x %2x",
+		(int) b[1], (int) b[2], (int)b[3]);
+
+	if (band == MT2266_UHF) {
+		b[0] = 0x05;
+		b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62;
+		b[2] = lnaband;
+		mt2266_writeregs(priv, b, 3);
+	}
+
+	/* Wait for pll lock or timeout */
+	i = 0;
+	do {
+		mt2266_readreg(priv,REG_LOCK,b);
+		if (b[0] & 0x40)
+			break;
+		msleep(10);
+		i++;
+	} while (i<10);
+	dprintk("Lock when i=%i",(int)i);
+
+	if (band == MT2266_UHF && priv->band == MT2266_VHF)
+		mt2266_writereg(priv, 0x05, 0x62);
+
+	priv->band = band;
+
+	return ret;
+}
+
+static void mt2266_calibrate(struct mt2266_priv *priv)
+{
+	mt2266_writereg(priv, 0x11, 0x03);
+	mt2266_writereg(priv, 0x11, 0x01);
+	mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1));
+	mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2));
+	mt2266_writereg(priv, 0x33, 0x5e);
+	mt2266_writereg(priv, 0x10, 0x10);
+	mt2266_writereg(priv, 0x10, 0x00);
+	mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz));
+	msleep(25);
+	mt2266_writereg(priv, 0x17, 0x6d);
+	mt2266_writereg(priv, 0x1c, 0x00);
+	msleep(75);
+	mt2266_writereg(priv, 0x17, 0x6d);
+	mt2266_writereg(priv, 0x1c, 0xff);
+}
+
+static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct mt2266_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct mt2266_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+static int mt2266_init(struct dvb_frontend *fe)
+{
+	int ret;
+	struct mt2266_priv *priv = fe->tuner_priv;
+	ret = mt2266_writereg(priv, 0x17, 0x6d);
+	if (ret < 0)
+		return ret;
+	ret = mt2266_writereg(priv, 0x1c, 0xff);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+static int mt2266_sleep(struct dvb_frontend *fe)
+{
+	struct mt2266_priv *priv = fe->tuner_priv;
+	mt2266_writereg(priv, 0x17, 0x6d);
+	mt2266_writereg(priv, 0x1c, 0x00);
+	return 0;
+}
+
+static int mt2266_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static const struct dvb_tuner_ops mt2266_tuner_ops = {
+	.info = {
+		.name           = "Microtune MT2266",
+		.frequency_min  = 174000000,
+		.frequency_max  = 862000000,
+		.frequency_step =     50000,
+	},
+	.release       = mt2266_release,
+	.init          = mt2266_init,
+	.sleep         = mt2266_sleep,
+	.set_params    = mt2266_set_params,
+	.get_frequency = mt2266_get_frequency,
+	.get_bandwidth = mt2266_get_bandwidth
+};
+
+struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
+{
+	struct mt2266_priv *priv = NULL;
+	u8 id = 0;
+
+	priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->cfg      = cfg;
+	priv->i2c      = i2c;
+	priv->band     = MT2266_UHF;
+
+	if (mt2266_readreg(priv, 0, &id)) {
+		kfree(priv);
+		return NULL;
+	}
+	if (id != PART_REV) {
+		kfree(priv);
+		return NULL;
+	}
+	printk(KERN_INFO "MT2266: successfully identified\n");
+	memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+	mt2266_calibrate(priv);
+	return fe;
+}
+EXPORT_SYMBOL(mt2266_attach);
+
+MODULE_AUTHOR("Olivier DANET");
+MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/mt2266.h b/drivers/media/tuners/mt2266.h
new file mode 100644
index 0000000..4d08388
--- /dev/null
+++ b/drivers/media/tuners/mt2266.h
@@ -0,0 +1,37 @@
+/*
+ *  Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
+ *
+ *  Copyright (c) 2007 Olivier DANET <odanet@caramail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#ifndef MT2266_H
+#define MT2266_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct mt2266_config {
+	u8 i2c_address;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_MT2266) || (defined(CONFIG_MEDIA_TUNER_MT2266_MODULE) && defined(MODULE))
+extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg);
+#else
+static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_MEDIA_TUNER_MT2266
+
+#endif
diff --git a/drivers/media/tuners/mxl5005s.c b/drivers/media/tuners/mxl5005s.c
new file mode 100644
index 0000000..6133315
--- /dev/null
+++ b/drivers/media/tuners/mxl5005s.c
@@ -0,0 +1,4109 @@
+/*
+    MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
+
+    Copyright (C) 2008 MaxLinear
+    Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
+      Functions:
+	mxl5005s_reset()
+	mxl5005s_writereg()
+	mxl5005s_writeregs()
+	mxl5005s_init()
+	mxl5005s_reconfigure()
+	mxl5005s_AssignTunerMode()
+	mxl5005s_set_params()
+	mxl5005s_get_frequency()
+	mxl5005s_get_bandwidth()
+	mxl5005s_release()
+	mxl5005s_attach()
+
+    Copyright (C) 2008 Realtek
+    Copyright (C) 2008 Jan Hoogenraad
+      Functions:
+	mxl5005s_SetRfFreqHz()
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/*
+    History of this driver (Steven Toth):
+      I was given a public release of a linux driver that included
+      support for the MaxLinear MXL5005S silicon tuner. Analysis of
+      the tuner driver showed clearly three things.
+
+      1. The tuner driver didn't support the LinuxTV tuner API
+	 so the code Realtek added had to be removed.
+
+      2. A significant amount of the driver is reference driver code
+	 from MaxLinear, I felt it was important to identify and
+	 preserve this.
+
+      3. New code has to be added to interface correctly with the
+	 LinuxTV API, as a regular kernel module.
+
+      Other than the reference driver enum's, I've clearly marked
+      sections of the code and retained the copyright of the
+      respective owners.
+*/
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "mxl5005s.h"
+
+static int debug;
+
+#define dprintk(level, arg...) do {    \
+	if (level <= debug)            \
+		printk(arg);    \
+	} while (0)
+
+#define TUNER_REGS_NUM          104
+#define INITCTRL_NUM            40
+
+#ifdef _MXL_PRODUCTION
+#define CHCTRL_NUM              39
+#else
+#define CHCTRL_NUM              36
+#endif
+
+#define MXLCTRL_NUM             189
+#define MASTER_CONTROL_ADDR     9
+
+/* Enumeration of Master Control Register State */
+enum master_control_state {
+	MC_LOAD_START = 1,
+	MC_POWER_DOWN,
+	MC_SYNTH_RESET,
+	MC_SEQ_OFF
+};
+
+/* Enumeration of MXL5005 Tuner Modulation Type */
+enum {
+	MXL_DEFAULT_MODULATION = 0,
+	MXL_DVBT,
+	MXL_ATSC,
+	MXL_QAM,
+	MXL_ANALOG_CABLE,
+	MXL_ANALOG_OTA
+};
+
+/* MXL5005 Tuner Register Struct */
+struct TunerReg {
+	u16 Reg_Num;	/* Tuner Register Address */
+	u16 Reg_Val;	/* Current sw programmed value waiting to be written */
+};
+
+enum {
+	/* Initialization Control Names */
+	DN_IQTN_AMP_CUT = 1,       /* 1 */
+	BB_MODE,                   /* 2 */
+	BB_BUF,                    /* 3 */
+	BB_BUF_OA,                 /* 4 */
+	BB_ALPF_BANDSELECT,        /* 5 */
+	BB_IQSWAP,                 /* 6 */
+	BB_DLPF_BANDSEL,           /* 7 */
+	RFSYN_CHP_GAIN,            /* 8 */
+	RFSYN_EN_CHP_HIGAIN,       /* 9 */
+	AGC_IF,                    /* 10 */
+	AGC_RF,                    /* 11 */
+	IF_DIVVAL,                 /* 12 */
+	IF_VCO_BIAS,               /* 13 */
+	CHCAL_INT_MOD_IF,          /* 14 */
+	CHCAL_FRAC_MOD_IF,         /* 15 */
+	DRV_RES_SEL,               /* 16 */
+	I_DRIVER,                  /* 17 */
+	EN_AAF,                    /* 18 */
+	EN_3P,                     /* 19 */
+	EN_AUX_3P,                 /* 20 */
+	SEL_AAF_BAND,              /* 21 */
+	SEQ_ENCLK16_CLK_OUT,       /* 22 */
+	SEQ_SEL4_16B,              /* 23 */
+	XTAL_CAPSELECT,            /* 24 */
+	IF_SEL_DBL,                /* 25 */
+	RFSYN_R_DIV,               /* 26 */
+	SEQ_EXTSYNTHCALIF,         /* 27 */
+	SEQ_EXTDCCAL,              /* 28 */
+	AGC_EN_RSSI,               /* 29 */
+	RFA_ENCLKRFAGC,            /* 30 */
+	RFA_RSSI_REFH,             /* 31 */
+	RFA_RSSI_REF,              /* 32 */
+	RFA_RSSI_REFL,             /* 33 */
+	RFA_FLR,                   /* 34 */
+	RFA_CEIL,                  /* 35 */
+	SEQ_EXTIQFSMPULSE,         /* 36 */
+	OVERRIDE_1,                /* 37 */
+	BB_INITSTATE_DLPF_TUNE,    /* 38 */
+	TG_R_DIV,                  /* 39 */
+	EN_CHP_LIN_B,              /* 40 */
+
+	/* Channel Change Control Names */
+	DN_POLY = 51,              /* 51 */
+	DN_RFGAIN,                 /* 52 */
+	DN_CAP_RFLPF,              /* 53 */
+	DN_EN_VHFUHFBAR,           /* 54 */
+	DN_GAIN_ADJUST,            /* 55 */
+	DN_IQTNBUF_AMP,            /* 56 */
+	DN_IQTNGNBFBIAS_BST,       /* 57 */
+	RFSYN_EN_OUTMUX,           /* 58 */
+	RFSYN_SEL_VCO_OUT,         /* 59 */
+	RFSYN_SEL_VCO_HI,          /* 60 */
+	RFSYN_SEL_DIVM,            /* 61 */
+	RFSYN_RF_DIV_BIAS,         /* 62 */
+	DN_SEL_FREQ,               /* 63 */
+	RFSYN_VCO_BIAS,            /* 64 */
+	CHCAL_INT_MOD_RF,          /* 65 */
+	CHCAL_FRAC_MOD_RF,         /* 66 */
+	RFSYN_LPF_R,               /* 67 */
+	CHCAL_EN_INT_RF,           /* 68 */
+	TG_LO_DIVVAL,              /* 69 */
+	TG_LO_SELVAL,              /* 70 */
+	TG_DIV_VAL,                /* 71 */
+	TG_VCO_BIAS,               /* 72 */
+	SEQ_EXTPOWERUP,            /* 73 */
+	OVERRIDE_2,                /* 74 */
+	OVERRIDE_3,                /* 75 */
+	OVERRIDE_4,                /* 76 */
+	SEQ_FSM_PULSE,             /* 77 */
+	GPIO_4B,                   /* 78 */
+	GPIO_3B,                   /* 79 */
+	GPIO_4,                    /* 80 */
+	GPIO_3,                    /* 81 */
+	GPIO_1B,                   /* 82 */
+	DAC_A_ENABLE,              /* 83 */
+	DAC_B_ENABLE,              /* 84 */
+	DAC_DIN_A,                 /* 85 */
+	DAC_DIN_B,                 /* 86 */
+#ifdef _MXL_PRODUCTION
+	RFSYN_EN_DIV,              /* 87 */
+	RFSYN_DIVM,                /* 88 */
+	DN_BYPASS_AGC_I2C          /* 89 */
+#endif
+};
+
+/*
+ * The following context is source code provided by MaxLinear.
+ * MaxLinear source code - Common_MXL.h (?)
+ */
+
+/* Constants */
+#define MXL5005S_REG_WRITING_TABLE_LEN_MAX	104
+#define MXL5005S_LATCH_BYTE			0xfe
+
+/* Register address, MSB, and LSB */
+#define MXL5005S_BB_IQSWAP_ADDR			59
+#define MXL5005S_BB_IQSWAP_MSB			0
+#define MXL5005S_BB_IQSWAP_LSB			0
+
+#define MXL5005S_BB_DLPF_BANDSEL_ADDR		53
+#define MXL5005S_BB_DLPF_BANDSEL_MSB		4
+#define MXL5005S_BB_DLPF_BANDSEL_LSB		3
+
+/* Standard modes */
+enum {
+	MXL5005S_STANDARD_DVBT,
+	MXL5005S_STANDARD_ATSC,
+};
+#define MXL5005S_STANDARD_MODE_NUM		2
+
+/* Bandwidth modes */
+enum {
+	MXL5005S_BANDWIDTH_6MHZ = 6000000,
+	MXL5005S_BANDWIDTH_7MHZ = 7000000,
+	MXL5005S_BANDWIDTH_8MHZ = 8000000,
+};
+#define MXL5005S_BANDWIDTH_MODE_NUM		3
+
+/* MXL5005 Tuner Control Struct */
+struct TunerControl {
+	u16 Ctrl_Num;	/* Control Number */
+	u16 size;	/* Number of bits to represent Value */
+	u16 addr[25];	/* Array of Tuner Register Address for each bit pos */
+	u16 bit[25];	/* Array of bit pos in Reg Addr for each bit pos */
+	u16 val[25];	/* Binary representation of Value */
+};
+
+/* MXL5005 Tuner Struct */
+struct mxl5005s_state {
+	u8	Mode;		/* 0: Analog Mode ; 1: Digital Mode */
+	u8	IF_Mode;	/* for Analog Mode, 0: zero IF; 1: low IF */
+	u32	Chan_Bandwidth;	/* filter  channel bandwidth (6, 7, 8) */
+	u32	IF_OUT;		/* Desired IF Out Frequency */
+	u16	IF_OUT_LOAD;	/* IF Out Load Resistor (200/300 Ohms) */
+	u32	RF_IN;		/* RF Input Frequency */
+	u32	Fxtal;		/* XTAL Frequency */
+	u8	AGC_Mode;	/* AGC Mode 0: Dual AGC; 1: Single AGC */
+	u16	TOP;		/* Value: take over point */
+	u8	CLOCK_OUT;	/* 0: turn off clk out; 1: turn on clock out */
+	u8	DIV_OUT;	/* 4MHz or 16MHz */
+	u8	CAPSELECT;	/* 0: disable On-Chip pulling cap; 1: enable */
+	u8	EN_RSSI;	/* 0: disable RSSI; 1: enable RSSI */
+
+	/* Modulation Type; */
+	/* 0 - Default;	1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */
+	u8	Mod_Type;
+
+	/* Tracking Filter Type */
+	/* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */
+	u8	TF_Type;
+
+	/* Calculated Settings */
+	u32	RF_LO;		/* Synth RF LO Frequency */
+	u32	IF_LO;		/* Synth IF LO Frequency */
+	u32	TG_LO;		/* Synth TG_LO Frequency */
+
+	/* Pointers to ControlName Arrays */
+	u16	Init_Ctrl_Num;		/* Number of INIT Control Names */
+	struct TunerControl
+		Init_Ctrl[INITCTRL_NUM]; /* INIT Control Names Array Pointer */
+
+	u16	CH_Ctrl_Num;		/* Number of CH Control Names */
+	struct TunerControl
+		CH_Ctrl[CHCTRL_NUM];	/* CH Control Name Array Pointer */
+
+	u16	MXL_Ctrl_Num;		/* Number of MXL Control Names */
+	struct TunerControl
+		MXL_Ctrl[MXLCTRL_NUM];	/* MXL Control Name Array Pointer */
+
+	/* Pointer to Tuner Register Array */
+	u16	TunerRegs_Num;		/* Number of Tuner Registers */
+	struct TunerReg
+		TunerRegs[TUNER_REGS_NUM]; /* Tuner Register Array Pointer */
+
+	/* Linux driver framework specific */
+	struct mxl5005s_config *config;
+	struct dvb_frontend *frontend;
+	struct i2c_adapter *i2c;
+
+	/* Cache values */
+	u32 current_mode;
+
+};
+
+static u16 MXL_GetMasterControl(u8 *MasterReg, int state);
+static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value);
+static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value);
+static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit,
+	u8 bitVal);
+static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum,
+	u8 *RegVal, int *count);
+static u32 MXL_Ceiling(u32 value, u32 resolution);
+static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal);
+static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum,
+	u32 value, u16 controlGroup);
+static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val);
+static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum,
+	u8 *RegVal, int *count);
+static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq);
+static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe);
+static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe);
+static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum,
+	u8 *RegVal, int *count);
+static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable,
+	u8 *datatable, u8 len);
+static u16 MXL_IFSynthInit(struct dvb_frontend *fe);
+static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type,
+	u32 bandwidth);
+static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type,
+	u32 bandwidth);
+
+/* ----------------------------------------------------------------
+ * Begin: Custom code salvaged from the Realtek driver.
+ * Copyright (C) 2008 Realtek
+ * Copyright (C) 2008 Jan Hoogenraad
+ * This code is placed under the terms of the GNU General Public License
+ *
+ * Released by Realtek under GPLv2.
+ * Thanks to Realtek for a lot of support we received !
+ *
+ *  Revision: 080314 - original version
+ */
+
+static int mxl5005s_SetRfFreqHz(struct dvb_frontend *fe, unsigned long RfFreqHz)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	unsigned char AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
+	unsigned char ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
+	int TableLen;
+
+	u32 IfDivval = 0;
+	unsigned char MasterControlByte;
+
+	dprintk(1, "%s() freq=%ld\n", __func__, RfFreqHz);
+
+	/* Set MxL5005S tuner RF frequency according to example code. */
+
+	/* Tuner RF frequency setting stage 0 */
+	MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET);
+	AddrTable[0] = MASTER_CONTROL_ADDR;
+	ByteTable[0] |= state->config->AgcMasterByte;
+
+	mxl5005s_writeregs(fe, AddrTable, ByteTable, 1);
+
+	/* Tuner RF frequency setting stage 1 */
+	MXL_TuneRF(fe, RfFreqHz);
+
+	MXL_ControlRead(fe, IF_DIVVAL, &IfDivval);
+
+	MXL_ControlWrite(fe, SEQ_FSM_PULSE, 0);
+	MXL_ControlWrite(fe, SEQ_EXTPOWERUP, 1);
+	MXL_ControlWrite(fe, IF_DIVVAL, 8);
+	MXL_GetCHRegister(fe, AddrTable, ByteTable, &TableLen);
+
+	MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START);
+	AddrTable[TableLen] = MASTER_CONTROL_ADDR ;
+	ByteTable[TableLen] = MasterControlByte |
+		state->config->AgcMasterByte;
+	TableLen += 1;
+
+	mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen);
+
+	/* Wait 30 ms. */
+	msleep(150);
+
+	/* Tuner RF frequency setting stage 2 */
+	MXL_ControlWrite(fe, SEQ_FSM_PULSE, 1);
+	MXL_ControlWrite(fe, IF_DIVVAL, IfDivval);
+	MXL_GetCHRegister_ZeroIF(fe, AddrTable, ByteTable, &TableLen);
+
+	MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START);
+	AddrTable[TableLen] = MASTER_CONTROL_ADDR ;
+	ByteTable[TableLen] = MasterControlByte |
+		state->config->AgcMasterByte ;
+	TableLen += 1;
+
+	mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen);
+
+	msleep(100);
+
+	return 0;
+}
+/* End: Custom code taken from the Realtek driver */
+
+/* ----------------------------------------------------------------
+ * Begin: Reference driver code found in the Realtek driver.
+ * Copyright (C) 2008 MaxLinear
+ */
+static u16 MXL5005_RegisterInit(struct dvb_frontend *fe)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	state->TunerRegs_Num = TUNER_REGS_NUM ;
+
+	state->TunerRegs[0].Reg_Num = 9 ;
+	state->TunerRegs[0].Reg_Val = 0x40 ;
+
+	state->TunerRegs[1].Reg_Num = 11 ;
+	state->TunerRegs[1].Reg_Val = 0x19 ;
+
+	state->TunerRegs[2].Reg_Num = 12 ;
+	state->TunerRegs[2].Reg_Val = 0x60 ;
+
+	state->TunerRegs[3].Reg_Num = 13 ;
+	state->TunerRegs[3].Reg_Val = 0x00 ;
+
+	state->TunerRegs[4].Reg_Num = 14 ;
+	state->TunerRegs[4].Reg_Val = 0x00 ;
+
+	state->TunerRegs[5].Reg_Num = 15 ;
+	state->TunerRegs[5].Reg_Val = 0xC0 ;
+
+	state->TunerRegs[6].Reg_Num = 16 ;
+	state->TunerRegs[6].Reg_Val = 0x00 ;
+
+	state->TunerRegs[7].Reg_Num = 17 ;
+	state->TunerRegs[7].Reg_Val = 0x00 ;
+
+	state->TunerRegs[8].Reg_Num = 18 ;
+	state->TunerRegs[8].Reg_Val = 0x00 ;
+
+	state->TunerRegs[9].Reg_Num = 19 ;
+	state->TunerRegs[9].Reg_Val = 0x34 ;
+
+	state->TunerRegs[10].Reg_Num = 21 ;
+	state->TunerRegs[10].Reg_Val = 0x00 ;
+
+	state->TunerRegs[11].Reg_Num = 22 ;
+	state->TunerRegs[11].Reg_Val = 0x6B ;
+
+	state->TunerRegs[12].Reg_Num = 23 ;
+	state->TunerRegs[12].Reg_Val = 0x35 ;
+
+	state->TunerRegs[13].Reg_Num = 24 ;
+	state->TunerRegs[13].Reg_Val = 0x70 ;
+
+	state->TunerRegs[14].Reg_Num = 25 ;
+	state->TunerRegs[14].Reg_Val = 0x3E ;
+
+	state->TunerRegs[15].Reg_Num = 26 ;
+	state->TunerRegs[15].Reg_Val = 0x82 ;
+
+	state->TunerRegs[16].Reg_Num = 31 ;
+	state->TunerRegs[16].Reg_Val = 0x00 ;
+
+	state->TunerRegs[17].Reg_Num = 32 ;
+	state->TunerRegs[17].Reg_Val = 0x40 ;
+
+	state->TunerRegs[18].Reg_Num = 33 ;
+	state->TunerRegs[18].Reg_Val = 0x53 ;
+
+	state->TunerRegs[19].Reg_Num = 34 ;
+	state->TunerRegs[19].Reg_Val = 0x81 ;
+
+	state->TunerRegs[20].Reg_Num = 35 ;
+	state->TunerRegs[20].Reg_Val = 0xC9 ;
+
+	state->TunerRegs[21].Reg_Num = 36 ;
+	state->TunerRegs[21].Reg_Val = 0x01 ;
+
+	state->TunerRegs[22].Reg_Num = 37 ;
+	state->TunerRegs[22].Reg_Val = 0x00 ;
+
+	state->TunerRegs[23].Reg_Num = 41 ;
+	state->TunerRegs[23].Reg_Val = 0x00 ;
+
+	state->TunerRegs[24].Reg_Num = 42 ;
+	state->TunerRegs[24].Reg_Val = 0xF8 ;
+
+	state->TunerRegs[25].Reg_Num = 43 ;
+	state->TunerRegs[25].Reg_Val = 0x43 ;
+
+	state->TunerRegs[26].Reg_Num = 44 ;
+	state->TunerRegs[26].Reg_Val = 0x20 ;
+
+	state->TunerRegs[27].Reg_Num = 45 ;
+	state->TunerRegs[27].Reg_Val = 0x80 ;
+
+	state->TunerRegs[28].Reg_Num = 46 ;
+	state->TunerRegs[28].Reg_Val = 0x88 ;
+
+	state->TunerRegs[29].Reg_Num = 47 ;
+	state->TunerRegs[29].Reg_Val = 0x86 ;
+
+	state->TunerRegs[30].Reg_Num = 48 ;
+	state->TunerRegs[30].Reg_Val = 0x00 ;
+
+	state->TunerRegs[31].Reg_Num = 49 ;
+	state->TunerRegs[31].Reg_Val = 0x00 ;
+
+	state->TunerRegs[32].Reg_Num = 53 ;
+	state->TunerRegs[32].Reg_Val = 0x94 ;
+
+	state->TunerRegs[33].Reg_Num = 54 ;
+	state->TunerRegs[33].Reg_Val = 0xFA ;
+
+	state->TunerRegs[34].Reg_Num = 55 ;
+	state->TunerRegs[34].Reg_Val = 0x92 ;
+
+	state->TunerRegs[35].Reg_Num = 56 ;
+	state->TunerRegs[35].Reg_Val = 0x80 ;
+
+	state->TunerRegs[36].Reg_Num = 57 ;
+	state->TunerRegs[36].Reg_Val = 0x41 ;
+
+	state->TunerRegs[37].Reg_Num = 58 ;
+	state->TunerRegs[37].Reg_Val = 0xDB ;
+
+	state->TunerRegs[38].Reg_Num = 59 ;
+	state->TunerRegs[38].Reg_Val = 0x00 ;
+
+	state->TunerRegs[39].Reg_Num = 60 ;
+	state->TunerRegs[39].Reg_Val = 0x00 ;
+
+	state->TunerRegs[40].Reg_Num = 61 ;
+	state->TunerRegs[40].Reg_Val = 0x00 ;
+
+	state->TunerRegs[41].Reg_Num = 62 ;
+	state->TunerRegs[41].Reg_Val = 0x00 ;
+
+	state->TunerRegs[42].Reg_Num = 65 ;
+	state->TunerRegs[42].Reg_Val = 0xF8 ;
+
+	state->TunerRegs[43].Reg_Num = 66 ;
+	state->TunerRegs[43].Reg_Val = 0xE4 ;
+
+	state->TunerRegs[44].Reg_Num = 67 ;
+	state->TunerRegs[44].Reg_Val = 0x90 ;
+
+	state->TunerRegs[45].Reg_Num = 68 ;
+	state->TunerRegs[45].Reg_Val = 0xC0 ;
+
+	state->TunerRegs[46].Reg_Num = 69 ;
+	state->TunerRegs[46].Reg_Val = 0x01 ;
+
+	state->TunerRegs[47].Reg_Num = 70 ;
+	state->TunerRegs[47].Reg_Val = 0x50 ;
+
+	state->TunerRegs[48].Reg_Num = 71 ;
+	state->TunerRegs[48].Reg_Val = 0x06 ;
+
+	state->TunerRegs[49].Reg_Num = 72 ;
+	state->TunerRegs[49].Reg_Val = 0x00 ;
+
+	state->TunerRegs[50].Reg_Num = 73 ;
+	state->TunerRegs[50].Reg_Val = 0x20 ;
+
+	state->TunerRegs[51].Reg_Num = 76 ;
+	state->TunerRegs[51].Reg_Val = 0xBB ;
+
+	state->TunerRegs[52].Reg_Num = 77 ;
+	state->TunerRegs[52].Reg_Val = 0x13 ;
+
+	state->TunerRegs[53].Reg_Num = 81 ;
+	state->TunerRegs[53].Reg_Val = 0x04 ;
+
+	state->TunerRegs[54].Reg_Num = 82 ;
+	state->TunerRegs[54].Reg_Val = 0x75 ;
+
+	state->TunerRegs[55].Reg_Num = 83 ;
+	state->TunerRegs[55].Reg_Val = 0x00 ;
+
+	state->TunerRegs[56].Reg_Num = 84 ;
+	state->TunerRegs[56].Reg_Val = 0x00 ;
+
+	state->TunerRegs[57].Reg_Num = 85 ;
+	state->TunerRegs[57].Reg_Val = 0x00 ;
+
+	state->TunerRegs[58].Reg_Num = 91 ;
+	state->TunerRegs[58].Reg_Val = 0x70 ;
+
+	state->TunerRegs[59].Reg_Num = 92 ;
+	state->TunerRegs[59].Reg_Val = 0x00 ;
+
+	state->TunerRegs[60].Reg_Num = 93 ;
+	state->TunerRegs[60].Reg_Val = 0x00 ;
+
+	state->TunerRegs[61].Reg_Num = 94 ;
+	state->TunerRegs[61].Reg_Val = 0x00 ;
+
+	state->TunerRegs[62].Reg_Num = 95 ;
+	state->TunerRegs[62].Reg_Val = 0x0C ;
+
+	state->TunerRegs[63].Reg_Num = 96 ;
+	state->TunerRegs[63].Reg_Val = 0x00 ;
+
+	state->TunerRegs[64].Reg_Num = 97 ;
+	state->TunerRegs[64].Reg_Val = 0x00 ;
+
+	state->TunerRegs[65].Reg_Num = 98 ;
+	state->TunerRegs[65].Reg_Val = 0xE2 ;
+
+	state->TunerRegs[66].Reg_Num = 99 ;
+	state->TunerRegs[66].Reg_Val = 0x00 ;
+
+	state->TunerRegs[67].Reg_Num = 100 ;
+	state->TunerRegs[67].Reg_Val = 0x00 ;
+
+	state->TunerRegs[68].Reg_Num = 101 ;
+	state->TunerRegs[68].Reg_Val = 0x12 ;
+
+	state->TunerRegs[69].Reg_Num = 102 ;
+	state->TunerRegs[69].Reg_Val = 0x80 ;
+
+	state->TunerRegs[70].Reg_Num = 103 ;
+	state->TunerRegs[70].Reg_Val = 0x32 ;
+
+	state->TunerRegs[71].Reg_Num = 104 ;
+	state->TunerRegs[71].Reg_Val = 0xB4 ;
+
+	state->TunerRegs[72].Reg_Num = 105 ;
+	state->TunerRegs[72].Reg_Val = 0x60 ;
+
+	state->TunerRegs[73].Reg_Num = 106 ;
+	state->TunerRegs[73].Reg_Val = 0x83 ;
+
+	state->TunerRegs[74].Reg_Num = 107 ;
+	state->TunerRegs[74].Reg_Val = 0x84 ;
+
+	state->TunerRegs[75].Reg_Num = 108 ;
+	state->TunerRegs[75].Reg_Val = 0x9C ;
+
+	state->TunerRegs[76].Reg_Num = 109 ;
+	state->TunerRegs[76].Reg_Val = 0x02 ;
+
+	state->TunerRegs[77].Reg_Num = 110 ;
+	state->TunerRegs[77].Reg_Val = 0x81 ;
+
+	state->TunerRegs[78].Reg_Num = 111 ;
+	state->TunerRegs[78].Reg_Val = 0xC0 ;
+
+	state->TunerRegs[79].Reg_Num = 112 ;
+	state->TunerRegs[79].Reg_Val = 0x10 ;
+
+	state->TunerRegs[80].Reg_Num = 131 ;
+	state->TunerRegs[80].Reg_Val = 0x8A ;
+
+	state->TunerRegs[81].Reg_Num = 132 ;
+	state->TunerRegs[81].Reg_Val = 0x10 ;
+
+	state->TunerRegs[82].Reg_Num = 133 ;
+	state->TunerRegs[82].Reg_Val = 0x24 ;
+
+	state->TunerRegs[83].Reg_Num = 134 ;
+	state->TunerRegs[83].Reg_Val = 0x00 ;
+
+	state->TunerRegs[84].Reg_Num = 135 ;
+	state->TunerRegs[84].Reg_Val = 0x00 ;
+
+	state->TunerRegs[85].Reg_Num = 136 ;
+	state->TunerRegs[85].Reg_Val = 0x7E ;
+
+	state->TunerRegs[86].Reg_Num = 137 ;
+	state->TunerRegs[86].Reg_Val = 0x40 ;
+
+	state->TunerRegs[87].Reg_Num = 138 ;
+	state->TunerRegs[87].Reg_Val = 0x38 ;
+
+	state->TunerRegs[88].Reg_Num = 146 ;
+	state->TunerRegs[88].Reg_Val = 0xF6 ;
+
+	state->TunerRegs[89].Reg_Num = 147 ;
+	state->TunerRegs[89].Reg_Val = 0x1A ;
+
+	state->TunerRegs[90].Reg_Num = 148 ;
+	state->TunerRegs[90].Reg_Val = 0x62 ;
+
+	state->TunerRegs[91].Reg_Num = 149 ;
+	state->TunerRegs[91].Reg_Val = 0x33 ;
+
+	state->TunerRegs[92].Reg_Num = 150 ;
+	state->TunerRegs[92].Reg_Val = 0x80 ;
+
+	state->TunerRegs[93].Reg_Num = 156 ;
+	state->TunerRegs[93].Reg_Val = 0x56 ;
+
+	state->TunerRegs[94].Reg_Num = 157 ;
+	state->TunerRegs[94].Reg_Val = 0x17 ;
+
+	state->TunerRegs[95].Reg_Num = 158 ;
+	state->TunerRegs[95].Reg_Val = 0xA9 ;
+
+	state->TunerRegs[96].Reg_Num = 159 ;
+	state->TunerRegs[96].Reg_Val = 0x00 ;
+
+	state->TunerRegs[97].Reg_Num = 160 ;
+	state->TunerRegs[97].Reg_Val = 0x00 ;
+
+	state->TunerRegs[98].Reg_Num = 161 ;
+	state->TunerRegs[98].Reg_Val = 0x00 ;
+
+	state->TunerRegs[99].Reg_Num = 162 ;
+	state->TunerRegs[99].Reg_Val = 0x40 ;
+
+	state->TunerRegs[100].Reg_Num = 166 ;
+	state->TunerRegs[100].Reg_Val = 0xAE ;
+
+	state->TunerRegs[101].Reg_Num = 167 ;
+	state->TunerRegs[101].Reg_Val = 0x1B ;
+
+	state->TunerRegs[102].Reg_Num = 168 ;
+	state->TunerRegs[102].Reg_Val = 0xF2 ;
+
+	state->TunerRegs[103].Reg_Num = 195 ;
+	state->TunerRegs[103].Reg_Val = 0x00 ;
+
+	return 0 ;
+}
+
+static u16 MXL5005_ControlInit(struct dvb_frontend *fe)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	state->Init_Ctrl_Num = INITCTRL_NUM;
+
+	state->Init_Ctrl[0].Ctrl_Num = DN_IQTN_AMP_CUT ;
+	state->Init_Ctrl[0].size = 1 ;
+	state->Init_Ctrl[0].addr[0] = 73;
+	state->Init_Ctrl[0].bit[0] = 7;
+	state->Init_Ctrl[0].val[0] = 0;
+
+	state->Init_Ctrl[1].Ctrl_Num = BB_MODE ;
+	state->Init_Ctrl[1].size = 1 ;
+	state->Init_Ctrl[1].addr[0] = 53;
+	state->Init_Ctrl[1].bit[0] = 2;
+	state->Init_Ctrl[1].val[0] = 1;
+
+	state->Init_Ctrl[2].Ctrl_Num = BB_BUF ;
+	state->Init_Ctrl[2].size = 2 ;
+	state->Init_Ctrl[2].addr[0] = 53;
+	state->Init_Ctrl[2].bit[0] = 1;
+	state->Init_Ctrl[2].val[0] = 0;
+	state->Init_Ctrl[2].addr[1] = 57;
+	state->Init_Ctrl[2].bit[1] = 0;
+	state->Init_Ctrl[2].val[1] = 1;
+
+	state->Init_Ctrl[3].Ctrl_Num = BB_BUF_OA ;
+	state->Init_Ctrl[3].size = 1 ;
+	state->Init_Ctrl[3].addr[0] = 53;
+	state->Init_Ctrl[3].bit[0] = 0;
+	state->Init_Ctrl[3].val[0] = 0;
+
+	state->Init_Ctrl[4].Ctrl_Num = BB_ALPF_BANDSELECT ;
+	state->Init_Ctrl[4].size = 3 ;
+	state->Init_Ctrl[4].addr[0] = 53;
+	state->Init_Ctrl[4].bit[0] = 5;
+	state->Init_Ctrl[4].val[0] = 0;
+	state->Init_Ctrl[4].addr[1] = 53;
+	state->Init_Ctrl[4].bit[1] = 6;
+	state->Init_Ctrl[4].val[1] = 0;
+	state->Init_Ctrl[4].addr[2] = 53;
+	state->Init_Ctrl[4].bit[2] = 7;
+	state->Init_Ctrl[4].val[2] = 1;
+
+	state->Init_Ctrl[5].Ctrl_Num = BB_IQSWAP ;
+	state->Init_Ctrl[5].size = 1 ;
+	state->Init_Ctrl[5].addr[0] = 59;
+	state->Init_Ctrl[5].bit[0] = 0;
+	state->Init_Ctrl[5].val[0] = 0;
+
+	state->Init_Ctrl[6].Ctrl_Num = BB_DLPF_BANDSEL ;
+	state->Init_Ctrl[6].size = 2 ;
+	state->Init_Ctrl[6].addr[0] = 53;
+	state->Init_Ctrl[6].bit[0] = 3;
+	state->Init_Ctrl[6].val[0] = 0;
+	state->Init_Ctrl[6].addr[1] = 53;
+	state->Init_Ctrl[6].bit[1] = 4;
+	state->Init_Ctrl[6].val[1] = 1;
+
+	state->Init_Ctrl[7].Ctrl_Num = RFSYN_CHP_GAIN ;
+	state->Init_Ctrl[7].size = 4 ;
+	state->Init_Ctrl[7].addr[0] = 22;
+	state->Init_Ctrl[7].bit[0] = 4;
+	state->Init_Ctrl[7].val[0] = 0;
+	state->Init_Ctrl[7].addr[1] = 22;
+	state->Init_Ctrl[7].bit[1] = 5;
+	state->Init_Ctrl[7].val[1] = 1;
+	state->Init_Ctrl[7].addr[2] = 22;
+	state->Init_Ctrl[7].bit[2] = 6;
+	state->Init_Ctrl[7].val[2] = 1;
+	state->Init_Ctrl[7].addr[3] = 22;
+	state->Init_Ctrl[7].bit[3] = 7;
+	state->Init_Ctrl[7].val[3] = 0;
+
+	state->Init_Ctrl[8].Ctrl_Num = RFSYN_EN_CHP_HIGAIN ;
+	state->Init_Ctrl[8].size = 1 ;
+	state->Init_Ctrl[8].addr[0] = 22;
+	state->Init_Ctrl[8].bit[0] = 2;
+	state->Init_Ctrl[8].val[0] = 0;
+
+	state->Init_Ctrl[9].Ctrl_Num = AGC_IF ;
+	state->Init_Ctrl[9].size = 4 ;
+	state->Init_Ctrl[9].addr[0] = 76;
+	state->Init_Ctrl[9].bit[0] = 0;
+	state->Init_Ctrl[9].val[0] = 1;
+	state->Init_Ctrl[9].addr[1] = 76;
+	state->Init_Ctrl[9].bit[1] = 1;
+	state->Init_Ctrl[9].val[1] = 1;
+	state->Init_Ctrl[9].addr[2] = 76;
+	state->Init_Ctrl[9].bit[2] = 2;
+	state->Init_Ctrl[9].val[2] = 0;
+	state->Init_Ctrl[9].addr[3] = 76;
+	state->Init_Ctrl[9].bit[3] = 3;
+	state->Init_Ctrl[9].val[3] = 1;
+
+	state->Init_Ctrl[10].Ctrl_Num = AGC_RF ;
+	state->Init_Ctrl[10].size = 4 ;
+	state->Init_Ctrl[10].addr[0] = 76;
+	state->Init_Ctrl[10].bit[0] = 4;
+	state->Init_Ctrl[10].val[0] = 1;
+	state->Init_Ctrl[10].addr[1] = 76;
+	state->Init_Ctrl[10].bit[1] = 5;
+	state->Init_Ctrl[10].val[1] = 1;
+	state->Init_Ctrl[10].addr[2] = 76;
+	state->Init_Ctrl[10].bit[2] = 6;
+	state->Init_Ctrl[10].val[2] = 0;
+	state->Init_Ctrl[10].addr[3] = 76;
+	state->Init_Ctrl[10].bit[3] = 7;
+	state->Init_Ctrl[10].val[3] = 1;
+
+	state->Init_Ctrl[11].Ctrl_Num = IF_DIVVAL ;
+	state->Init_Ctrl[11].size = 5 ;
+	state->Init_Ctrl[11].addr[0] = 43;
+	state->Init_Ctrl[11].bit[0] = 3;
+	state->Init_Ctrl[11].val[0] = 0;
+	state->Init_Ctrl[11].addr[1] = 43;
+	state->Init_Ctrl[11].bit[1] = 4;
+	state->Init_Ctrl[11].val[1] = 0;
+	state->Init_Ctrl[11].addr[2] = 43;
+	state->Init_Ctrl[11].bit[2] = 5;
+	state->Init_Ctrl[11].val[2] = 0;
+	state->Init_Ctrl[11].addr[3] = 43;
+	state->Init_Ctrl[11].bit[3] = 6;
+	state->Init_Ctrl[11].val[3] = 1;
+	state->Init_Ctrl[11].addr[4] = 43;
+	state->Init_Ctrl[11].bit[4] = 7;
+	state->Init_Ctrl[11].val[4] = 0;
+
+	state->Init_Ctrl[12].Ctrl_Num = IF_VCO_BIAS ;
+	state->Init_Ctrl[12].size = 6 ;
+	state->Init_Ctrl[12].addr[0] = 44;
+	state->Init_Ctrl[12].bit[0] = 2;
+	state->Init_Ctrl[12].val[0] = 0;
+	state->Init_Ctrl[12].addr[1] = 44;
+	state->Init_Ctrl[12].bit[1] = 3;
+	state->Init_Ctrl[12].val[1] = 0;
+	state->Init_Ctrl[12].addr[2] = 44;
+	state->Init_Ctrl[12].bit[2] = 4;
+	state->Init_Ctrl[12].val[2] = 0;
+	state->Init_Ctrl[12].addr[3] = 44;
+	state->Init_Ctrl[12].bit[3] = 5;
+	state->Init_Ctrl[12].val[3] = 1;
+	state->Init_Ctrl[12].addr[4] = 44;
+	state->Init_Ctrl[12].bit[4] = 6;
+	state->Init_Ctrl[12].val[4] = 0;
+	state->Init_Ctrl[12].addr[5] = 44;
+	state->Init_Ctrl[12].bit[5] = 7;
+	state->Init_Ctrl[12].val[5] = 0;
+
+	state->Init_Ctrl[13].Ctrl_Num = CHCAL_INT_MOD_IF ;
+	state->Init_Ctrl[13].size = 7 ;
+	state->Init_Ctrl[13].addr[0] = 11;
+	state->Init_Ctrl[13].bit[0] = 0;
+	state->Init_Ctrl[13].val[0] = 1;
+	state->Init_Ctrl[13].addr[1] = 11;
+	state->Init_Ctrl[13].bit[1] = 1;
+	state->Init_Ctrl[13].val[1] = 0;
+	state->Init_Ctrl[13].addr[2] = 11;
+	state->Init_Ctrl[13].bit[2] = 2;
+	state->Init_Ctrl[13].val[2] = 0;
+	state->Init_Ctrl[13].addr[3] = 11;
+	state->Init_Ctrl[13].bit[3] = 3;
+	state->Init_Ctrl[13].val[3] = 1;
+	state->Init_Ctrl[13].addr[4] = 11;
+	state->Init_Ctrl[13].bit[4] = 4;
+	state->Init_Ctrl[13].val[4] = 1;
+	state->Init_Ctrl[13].addr[5] = 11;
+	state->Init_Ctrl[13].bit[5] = 5;
+	state->Init_Ctrl[13].val[5] = 0;
+	state->Init_Ctrl[13].addr[6] = 11;
+	state->Init_Ctrl[13].bit[6] = 6;
+	state->Init_Ctrl[13].val[6] = 0;
+
+	state->Init_Ctrl[14].Ctrl_Num = CHCAL_FRAC_MOD_IF ;
+	state->Init_Ctrl[14].size = 16 ;
+	state->Init_Ctrl[14].addr[0] = 13;
+	state->Init_Ctrl[14].bit[0] = 0;
+	state->Init_Ctrl[14].val[0] = 0;
+	state->Init_Ctrl[14].addr[1] = 13;
+	state->Init_Ctrl[14].bit[1] = 1;
+	state->Init_Ctrl[14].val[1] = 0;
+	state->Init_Ctrl[14].addr[2] = 13;
+	state->Init_Ctrl[14].bit[2] = 2;
+	state->Init_Ctrl[14].val[2] = 0;
+	state->Init_Ctrl[14].addr[3] = 13;
+	state->Init_Ctrl[14].bit[3] = 3;
+	state->Init_Ctrl[14].val[3] = 0;
+	state->Init_Ctrl[14].addr[4] = 13;
+	state->Init_Ctrl[14].bit[4] = 4;
+	state->Init_Ctrl[14].val[4] = 0;
+	state->Init_Ctrl[14].addr[5] = 13;
+	state->Init_Ctrl[14].bit[5] = 5;
+	state->Init_Ctrl[14].val[5] = 0;
+	state->Init_Ctrl[14].addr[6] = 13;
+	state->Init_Ctrl[14].bit[6] = 6;
+	state->Init_Ctrl[14].val[6] = 0;
+	state->Init_Ctrl[14].addr[7] = 13;
+	state->Init_Ctrl[14].bit[7] = 7;
+	state->Init_Ctrl[14].val[7] = 0;
+	state->Init_Ctrl[14].addr[8] = 12;
+	state->Init_Ctrl[14].bit[8] = 0;
+	state->Init_Ctrl[14].val[8] = 0;
+	state->Init_Ctrl[14].addr[9] = 12;
+	state->Init_Ctrl[14].bit[9] = 1;
+	state->Init_Ctrl[14].val[9] = 0;
+	state->Init_Ctrl[14].addr[10] = 12;
+	state->Init_Ctrl[14].bit[10] = 2;
+	state->Init_Ctrl[14].val[10] = 0;
+	state->Init_Ctrl[14].addr[11] = 12;
+	state->Init_Ctrl[14].bit[11] = 3;
+	state->Init_Ctrl[14].val[11] = 0;
+	state->Init_Ctrl[14].addr[12] = 12;
+	state->Init_Ctrl[14].bit[12] = 4;
+	state->Init_Ctrl[14].val[12] = 0;
+	state->Init_Ctrl[14].addr[13] = 12;
+	state->Init_Ctrl[14].bit[13] = 5;
+	state->Init_Ctrl[14].val[13] = 1;
+	state->Init_Ctrl[14].addr[14] = 12;
+	state->Init_Ctrl[14].bit[14] = 6;
+	state->Init_Ctrl[14].val[14] = 1;
+	state->Init_Ctrl[14].addr[15] = 12;
+	state->Init_Ctrl[14].bit[15] = 7;
+	state->Init_Ctrl[14].val[15] = 0;
+
+	state->Init_Ctrl[15].Ctrl_Num = DRV_RES_SEL ;
+	state->Init_Ctrl[15].size = 3 ;
+	state->Init_Ctrl[15].addr[0] = 147;
+	state->Init_Ctrl[15].bit[0] = 2;
+	state->Init_Ctrl[15].val[0] = 0;
+	state->Init_Ctrl[15].addr[1] = 147;
+	state->Init_Ctrl[15].bit[1] = 3;
+	state->Init_Ctrl[15].val[1] = 1;
+	state->Init_Ctrl[15].addr[2] = 147;
+	state->Init_Ctrl[15].bit[2] = 4;
+	state->Init_Ctrl[15].val[2] = 1;
+
+	state->Init_Ctrl[16].Ctrl_Num = I_DRIVER ;
+	state->Init_Ctrl[16].size = 2 ;
+	state->Init_Ctrl[16].addr[0] = 147;
+	state->Init_Ctrl[16].bit[0] = 0;
+	state->Init_Ctrl[16].val[0] = 0;
+	state->Init_Ctrl[16].addr[1] = 147;
+	state->Init_Ctrl[16].bit[1] = 1;
+	state->Init_Ctrl[16].val[1] = 1;
+
+	state->Init_Ctrl[17].Ctrl_Num = EN_AAF ;
+	state->Init_Ctrl[17].size = 1 ;
+	state->Init_Ctrl[17].addr[0] = 147;
+	state->Init_Ctrl[17].bit[0] = 7;
+	state->Init_Ctrl[17].val[0] = 0;
+
+	state->Init_Ctrl[18].Ctrl_Num = EN_3P ;
+	state->Init_Ctrl[18].size = 1 ;
+	state->Init_Ctrl[18].addr[0] = 147;
+	state->Init_Ctrl[18].bit[0] = 6;
+	state->Init_Ctrl[18].val[0] = 0;
+
+	state->Init_Ctrl[19].Ctrl_Num = EN_AUX_3P ;
+	state->Init_Ctrl[19].size = 1 ;
+	state->Init_Ctrl[19].addr[0] = 156;
+	state->Init_Ctrl[19].bit[0] = 0;
+	state->Init_Ctrl[19].val[0] = 0;
+
+	state->Init_Ctrl[20].Ctrl_Num = SEL_AAF_BAND ;
+	state->Init_Ctrl[20].size = 1 ;
+	state->Init_Ctrl[20].addr[0] = 147;
+	state->Init_Ctrl[20].bit[0] = 5;
+	state->Init_Ctrl[20].val[0] = 0;
+
+	state->Init_Ctrl[21].Ctrl_Num = SEQ_ENCLK16_CLK_OUT ;
+	state->Init_Ctrl[21].size = 1 ;
+	state->Init_Ctrl[21].addr[0] = 137;
+	state->Init_Ctrl[21].bit[0] = 4;
+	state->Init_Ctrl[21].val[0] = 0;
+
+	state->Init_Ctrl[22].Ctrl_Num = SEQ_SEL4_16B ;
+	state->Init_Ctrl[22].size = 1 ;
+	state->Init_Ctrl[22].addr[0] = 137;
+	state->Init_Ctrl[22].bit[0] = 7;
+	state->Init_Ctrl[22].val[0] = 0;
+
+	state->Init_Ctrl[23].Ctrl_Num = XTAL_CAPSELECT ;
+	state->Init_Ctrl[23].size = 1 ;
+	state->Init_Ctrl[23].addr[0] = 91;
+	state->Init_Ctrl[23].bit[0] = 5;
+	state->Init_Ctrl[23].val[0] = 1;
+
+	state->Init_Ctrl[24].Ctrl_Num = IF_SEL_DBL ;
+	state->Init_Ctrl[24].size = 1 ;
+	state->Init_Ctrl[24].addr[0] = 43;
+	state->Init_Ctrl[24].bit[0] = 0;
+	state->Init_Ctrl[24].val[0] = 1;
+
+	state->Init_Ctrl[25].Ctrl_Num = RFSYN_R_DIV ;
+	state->Init_Ctrl[25].size = 2 ;
+	state->Init_Ctrl[25].addr[0] = 22;
+	state->Init_Ctrl[25].bit[0] = 0;
+	state->Init_Ctrl[25].val[0] = 1;
+	state->Init_Ctrl[25].addr[1] = 22;
+	state->Init_Ctrl[25].bit[1] = 1;
+	state->Init_Ctrl[25].val[1] = 1;
+
+	state->Init_Ctrl[26].Ctrl_Num = SEQ_EXTSYNTHCALIF ;
+	state->Init_Ctrl[26].size = 1 ;
+	state->Init_Ctrl[26].addr[0] = 134;
+	state->Init_Ctrl[26].bit[0] = 2;
+	state->Init_Ctrl[26].val[0] = 0;
+
+	state->Init_Ctrl[27].Ctrl_Num = SEQ_EXTDCCAL ;
+	state->Init_Ctrl[27].size = 1 ;
+	state->Init_Ctrl[27].addr[0] = 137;
+	state->Init_Ctrl[27].bit[0] = 3;
+	state->Init_Ctrl[27].val[0] = 0;
+
+	state->Init_Ctrl[28].Ctrl_Num = AGC_EN_RSSI ;
+	state->Init_Ctrl[28].size = 1 ;
+	state->Init_Ctrl[28].addr[0] = 77;
+	state->Init_Ctrl[28].bit[0] = 7;
+	state->Init_Ctrl[28].val[0] = 0;
+
+	state->Init_Ctrl[29].Ctrl_Num = RFA_ENCLKRFAGC ;
+	state->Init_Ctrl[29].size = 1 ;
+	state->Init_Ctrl[29].addr[0] = 166;
+	state->Init_Ctrl[29].bit[0] = 7;
+	state->Init_Ctrl[29].val[0] = 1;
+
+	state->Init_Ctrl[30].Ctrl_Num = RFA_RSSI_REFH ;
+	state->Init_Ctrl[30].size = 3 ;
+	state->Init_Ctrl[30].addr[0] = 166;
+	state->Init_Ctrl[30].bit[0] = 0;
+	state->Init_Ctrl[30].val[0] = 0;
+	state->Init_Ctrl[30].addr[1] = 166;
+	state->Init_Ctrl[30].bit[1] = 1;
+	state->Init_Ctrl[30].val[1] = 1;
+	state->Init_Ctrl[30].addr[2] = 166;
+	state->Init_Ctrl[30].bit[2] = 2;
+	state->Init_Ctrl[30].val[2] = 1;
+
+	state->Init_Ctrl[31].Ctrl_Num = RFA_RSSI_REF ;
+	state->Init_Ctrl[31].size = 3 ;
+	state->Init_Ctrl[31].addr[0] = 166;
+	state->Init_Ctrl[31].bit[0] = 3;
+	state->Init_Ctrl[31].val[0] = 1;
+	state->Init_Ctrl[31].addr[1] = 166;
+	state->Init_Ctrl[31].bit[1] = 4;
+	state->Init_Ctrl[31].val[1] = 0;
+	state->Init_Ctrl[31].addr[2] = 166;
+	state->Init_Ctrl[31].bit[2] = 5;
+	state->Init_Ctrl[31].val[2] = 1;
+
+	state->Init_Ctrl[32].Ctrl_Num = RFA_RSSI_REFL ;
+	state->Init_Ctrl[32].size = 3 ;
+	state->Init_Ctrl[32].addr[0] = 167;
+	state->Init_Ctrl[32].bit[0] = 0;
+	state->Init_Ctrl[32].val[0] = 1;
+	state->Init_Ctrl[32].addr[1] = 167;
+	state->Init_Ctrl[32].bit[1] = 1;
+	state->Init_Ctrl[32].val[1] = 1;
+	state->Init_Ctrl[32].addr[2] = 167;
+	state->Init_Ctrl[32].bit[2] = 2;
+	state->Init_Ctrl[32].val[2] = 0;
+
+	state->Init_Ctrl[33].Ctrl_Num = RFA_FLR ;
+	state->Init_Ctrl[33].size = 4 ;
+	state->Init_Ctrl[33].addr[0] = 168;
+	state->Init_Ctrl[33].bit[0] = 0;
+	state->Init_Ctrl[33].val[0] = 0;
+	state->Init_Ctrl[33].addr[1] = 168;
+	state->Init_Ctrl[33].bit[1] = 1;
+	state->Init_Ctrl[33].val[1] = 1;
+	state->Init_Ctrl[33].addr[2] = 168;
+	state->Init_Ctrl[33].bit[2] = 2;
+	state->Init_Ctrl[33].val[2] = 0;
+	state->Init_Ctrl[33].addr[3] = 168;
+	state->Init_Ctrl[33].bit[3] = 3;
+	state->Init_Ctrl[33].val[3] = 0;
+
+	state->Init_Ctrl[34].Ctrl_Num = RFA_CEIL ;
+	state->Init_Ctrl[34].size = 4 ;
+	state->Init_Ctrl[34].addr[0] = 168;
+	state->Init_Ctrl[34].bit[0] = 4;
+	state->Init_Ctrl[34].val[0] = 1;
+	state->Init_Ctrl[34].addr[1] = 168;
+	state->Init_Ctrl[34].bit[1] = 5;
+	state->Init_Ctrl[34].val[1] = 1;
+	state->Init_Ctrl[34].addr[2] = 168;
+	state->Init_Ctrl[34].bit[2] = 6;
+	state->Init_Ctrl[34].val[2] = 1;
+	state->Init_Ctrl[34].addr[3] = 168;
+	state->Init_Ctrl[34].bit[3] = 7;
+	state->Init_Ctrl[34].val[3] = 1;
+
+	state->Init_Ctrl[35].Ctrl_Num = SEQ_EXTIQFSMPULSE ;
+	state->Init_Ctrl[35].size = 1 ;
+	state->Init_Ctrl[35].addr[0] = 135;
+	state->Init_Ctrl[35].bit[0] = 0;
+	state->Init_Ctrl[35].val[0] = 0;
+
+	state->Init_Ctrl[36].Ctrl_Num = OVERRIDE_1 ;
+	state->Init_Ctrl[36].size = 1 ;
+	state->Init_Ctrl[36].addr[0] = 56;
+	state->Init_Ctrl[36].bit[0] = 3;
+	state->Init_Ctrl[36].val[0] = 0;
+
+	state->Init_Ctrl[37].Ctrl_Num = BB_INITSTATE_DLPF_TUNE ;
+	state->Init_Ctrl[37].size = 7 ;
+	state->Init_Ctrl[37].addr[0] = 59;
+	state->Init_Ctrl[37].bit[0] = 1;
+	state->Init_Ctrl[37].val[0] = 0;
+	state->Init_Ctrl[37].addr[1] = 59;
+	state->Init_Ctrl[37].bit[1] = 2;
+	state->Init_Ctrl[37].val[1] = 0;
+	state->Init_Ctrl[37].addr[2] = 59;
+	state->Init_Ctrl[37].bit[2] = 3;
+	state->Init_Ctrl[37].val[2] = 0;
+	state->Init_Ctrl[37].addr[3] = 59;
+	state->Init_Ctrl[37].bit[3] = 4;
+	state->Init_Ctrl[37].val[3] = 0;
+	state->Init_Ctrl[37].addr[4] = 59;
+	state->Init_Ctrl[37].bit[4] = 5;
+	state->Init_Ctrl[37].val[4] = 0;
+	state->Init_Ctrl[37].addr[5] = 59;
+	state->Init_Ctrl[37].bit[5] = 6;
+	state->Init_Ctrl[37].val[5] = 0;
+	state->Init_Ctrl[37].addr[6] = 59;
+	state->Init_Ctrl[37].bit[6] = 7;
+	state->Init_Ctrl[37].val[6] = 0;
+
+	state->Init_Ctrl[38].Ctrl_Num = TG_R_DIV ;
+	state->Init_Ctrl[38].size = 6 ;
+	state->Init_Ctrl[38].addr[0] = 32;
+	state->Init_Ctrl[38].bit[0] = 2;
+	state->Init_Ctrl[38].val[0] = 0;
+	state->Init_Ctrl[38].addr[1] = 32;
+	state->Init_Ctrl[38].bit[1] = 3;
+	state->Init_Ctrl[38].val[1] = 0;
+	state->Init_Ctrl[38].addr[2] = 32;
+	state->Init_Ctrl[38].bit[2] = 4;
+	state->Init_Ctrl[38].val[2] = 0;
+	state->Init_Ctrl[38].addr[3] = 32;
+	state->Init_Ctrl[38].bit[3] = 5;
+	state->Init_Ctrl[38].val[3] = 0;
+	state->Init_Ctrl[38].addr[4] = 32;
+	state->Init_Ctrl[38].bit[4] = 6;
+	state->Init_Ctrl[38].val[4] = 1;
+	state->Init_Ctrl[38].addr[5] = 32;
+	state->Init_Ctrl[38].bit[5] = 7;
+	state->Init_Ctrl[38].val[5] = 0;
+
+	state->Init_Ctrl[39].Ctrl_Num = EN_CHP_LIN_B ;
+	state->Init_Ctrl[39].size = 1 ;
+	state->Init_Ctrl[39].addr[0] = 25;
+	state->Init_Ctrl[39].bit[0] = 3;
+	state->Init_Ctrl[39].val[0] = 1;
+
+
+	state->CH_Ctrl_Num = CHCTRL_NUM ;
+
+	state->CH_Ctrl[0].Ctrl_Num = DN_POLY ;
+	state->CH_Ctrl[0].size = 2 ;
+	state->CH_Ctrl[0].addr[0] = 68;
+	state->CH_Ctrl[0].bit[0] = 6;
+	state->CH_Ctrl[0].val[0] = 1;
+	state->CH_Ctrl[0].addr[1] = 68;
+	state->CH_Ctrl[0].bit[1] = 7;
+	state->CH_Ctrl[0].val[1] = 1;
+
+	state->CH_Ctrl[1].Ctrl_Num = DN_RFGAIN ;
+	state->CH_Ctrl[1].size = 2 ;
+	state->CH_Ctrl[1].addr[0] = 70;
+	state->CH_Ctrl[1].bit[0] = 6;
+	state->CH_Ctrl[1].val[0] = 1;
+	state->CH_Ctrl[1].addr[1] = 70;
+	state->CH_Ctrl[1].bit[1] = 7;
+	state->CH_Ctrl[1].val[1] = 0;
+
+	state->CH_Ctrl[2].Ctrl_Num = DN_CAP_RFLPF ;
+	state->CH_Ctrl[2].size = 9 ;
+	state->CH_Ctrl[2].addr[0] = 69;
+	state->CH_Ctrl[2].bit[0] = 5;
+	state->CH_Ctrl[2].val[0] = 0;
+	state->CH_Ctrl[2].addr[1] = 69;
+	state->CH_Ctrl[2].bit[1] = 6;
+	state->CH_Ctrl[2].val[1] = 0;
+	state->CH_Ctrl[2].addr[2] = 69;
+	state->CH_Ctrl[2].bit[2] = 7;
+	state->CH_Ctrl[2].val[2] = 0;
+	state->CH_Ctrl[2].addr[3] = 68;
+	state->CH_Ctrl[2].bit[3] = 0;
+	state->CH_Ctrl[2].val[3] = 0;
+	state->CH_Ctrl[2].addr[4] = 68;
+	state->CH_Ctrl[2].bit[4] = 1;
+	state->CH_Ctrl[2].val[4] = 0;
+	state->CH_Ctrl[2].addr[5] = 68;
+	state->CH_Ctrl[2].bit[5] = 2;
+	state->CH_Ctrl[2].val[5] = 0;
+	state->CH_Ctrl[2].addr[6] = 68;
+	state->CH_Ctrl[2].bit[6] = 3;
+	state->CH_Ctrl[2].val[6] = 0;
+	state->CH_Ctrl[2].addr[7] = 68;
+	state->CH_Ctrl[2].bit[7] = 4;
+	state->CH_Ctrl[2].val[7] = 0;
+	state->CH_Ctrl[2].addr[8] = 68;
+	state->CH_Ctrl[2].bit[8] = 5;
+	state->CH_Ctrl[2].val[8] = 0;
+
+	state->CH_Ctrl[3].Ctrl_Num = DN_EN_VHFUHFBAR ;
+	state->CH_Ctrl[3].size = 1 ;
+	state->CH_Ctrl[3].addr[0] = 70;
+	state->CH_Ctrl[3].bit[0] = 5;
+	state->CH_Ctrl[3].val[0] = 0;
+
+	state->CH_Ctrl[4].Ctrl_Num = DN_GAIN_ADJUST ;
+	state->CH_Ctrl[4].size = 3 ;
+	state->CH_Ctrl[4].addr[0] = 73;
+	state->CH_Ctrl[4].bit[0] = 4;
+	state->CH_Ctrl[4].val[0] = 0;
+	state->CH_Ctrl[4].addr[1] = 73;
+	state->CH_Ctrl[4].bit[1] = 5;
+	state->CH_Ctrl[4].val[1] = 1;
+	state->CH_Ctrl[4].addr[2] = 73;
+	state->CH_Ctrl[4].bit[2] = 6;
+	state->CH_Ctrl[4].val[2] = 0;
+
+	state->CH_Ctrl[5].Ctrl_Num = DN_IQTNBUF_AMP ;
+	state->CH_Ctrl[5].size = 4 ;
+	state->CH_Ctrl[5].addr[0] = 70;
+	state->CH_Ctrl[5].bit[0] = 0;
+	state->CH_Ctrl[5].val[0] = 0;
+	state->CH_Ctrl[5].addr[1] = 70;
+	state->CH_Ctrl[5].bit[1] = 1;
+	state->CH_Ctrl[5].val[1] = 0;
+	state->CH_Ctrl[5].addr[2] = 70;
+	state->CH_Ctrl[5].bit[2] = 2;
+	state->CH_Ctrl[5].val[2] = 0;
+	state->CH_Ctrl[5].addr[3] = 70;
+	state->CH_Ctrl[5].bit[3] = 3;
+	state->CH_Ctrl[5].val[3] = 0;
+
+	state->CH_Ctrl[6].Ctrl_Num = DN_IQTNGNBFBIAS_BST ;
+	state->CH_Ctrl[6].size = 1 ;
+	state->CH_Ctrl[6].addr[0] = 70;
+	state->CH_Ctrl[6].bit[0] = 4;
+	state->CH_Ctrl[6].val[0] = 1;
+
+	state->CH_Ctrl[7].Ctrl_Num = RFSYN_EN_OUTMUX ;
+	state->CH_Ctrl[7].size = 1 ;
+	state->CH_Ctrl[7].addr[0] = 111;
+	state->CH_Ctrl[7].bit[0] = 4;
+	state->CH_Ctrl[7].val[0] = 0;
+
+	state->CH_Ctrl[8].Ctrl_Num = RFSYN_SEL_VCO_OUT ;
+	state->CH_Ctrl[8].size = 1 ;
+	state->CH_Ctrl[8].addr[0] = 111;
+	state->CH_Ctrl[8].bit[0] = 7;
+	state->CH_Ctrl[8].val[0] = 1;
+
+	state->CH_Ctrl[9].Ctrl_Num = RFSYN_SEL_VCO_HI ;
+	state->CH_Ctrl[9].size = 1 ;
+	state->CH_Ctrl[9].addr[0] = 111;
+	state->CH_Ctrl[9].bit[0] = 6;
+	state->CH_Ctrl[9].val[0] = 1;
+
+	state->CH_Ctrl[10].Ctrl_Num = RFSYN_SEL_DIVM ;
+	state->CH_Ctrl[10].size = 1 ;
+	state->CH_Ctrl[10].addr[0] = 111;
+	state->CH_Ctrl[10].bit[0] = 5;
+	state->CH_Ctrl[10].val[0] = 0;
+
+	state->CH_Ctrl[11].Ctrl_Num = RFSYN_RF_DIV_BIAS ;
+	state->CH_Ctrl[11].size = 2 ;
+	state->CH_Ctrl[11].addr[0] = 110;
+	state->CH_Ctrl[11].bit[0] = 0;
+	state->CH_Ctrl[11].val[0] = 1;
+	state->CH_Ctrl[11].addr[1] = 110;
+	state->CH_Ctrl[11].bit[1] = 1;
+	state->CH_Ctrl[11].val[1] = 0;
+
+	state->CH_Ctrl[12].Ctrl_Num = DN_SEL_FREQ ;
+	state->CH_Ctrl[12].size = 3 ;
+	state->CH_Ctrl[12].addr[0] = 69;
+	state->CH_Ctrl[12].bit[0] = 2;
+	state->CH_Ctrl[12].val[0] = 0;
+	state->CH_Ctrl[12].addr[1] = 69;
+	state->CH_Ctrl[12].bit[1] = 3;
+	state->CH_Ctrl[12].val[1] = 0;
+	state->CH_Ctrl[12].addr[2] = 69;
+	state->CH_Ctrl[12].bit[2] = 4;
+	state->CH_Ctrl[12].val[2] = 0;
+
+	state->CH_Ctrl[13].Ctrl_Num = RFSYN_VCO_BIAS ;
+	state->CH_Ctrl[13].size = 6 ;
+	state->CH_Ctrl[13].addr[0] = 110;
+	state->CH_Ctrl[13].bit[0] = 2;
+	state->CH_Ctrl[13].val[0] = 0;
+	state->CH_Ctrl[13].addr[1] = 110;
+	state->CH_Ctrl[13].bit[1] = 3;
+	state->CH_Ctrl[13].val[1] = 0;
+	state->CH_Ctrl[13].addr[2] = 110;
+	state->CH_Ctrl[13].bit[2] = 4;
+	state->CH_Ctrl[13].val[2] = 0;
+	state->CH_Ctrl[13].addr[3] = 110;
+	state->CH_Ctrl[13].bit[3] = 5;
+	state->CH_Ctrl[13].val[3] = 0;
+	state->CH_Ctrl[13].addr[4] = 110;
+	state->CH_Ctrl[13].bit[4] = 6;
+	state->CH_Ctrl[13].val[4] = 0;
+	state->CH_Ctrl[13].addr[5] = 110;
+	state->CH_Ctrl[13].bit[5] = 7;
+	state->CH_Ctrl[13].val[5] = 1;
+
+	state->CH_Ctrl[14].Ctrl_Num = CHCAL_INT_MOD_RF ;
+	state->CH_Ctrl[14].size = 7 ;
+	state->CH_Ctrl[14].addr[0] = 14;
+	state->CH_Ctrl[14].bit[0] = 0;
+	state->CH_Ctrl[14].val[0] = 0;
+	state->CH_Ctrl[14].addr[1] = 14;
+	state->CH_Ctrl[14].bit[1] = 1;
+	state->CH_Ctrl[14].val[1] = 0;
+	state->CH_Ctrl[14].addr[2] = 14;
+	state->CH_Ctrl[14].bit[2] = 2;
+	state->CH_Ctrl[14].val[2] = 0;
+	state->CH_Ctrl[14].addr[3] = 14;
+	state->CH_Ctrl[14].bit[3] = 3;
+	state->CH_Ctrl[14].val[3] = 0;
+	state->CH_Ctrl[14].addr[4] = 14;
+	state->CH_Ctrl[14].bit[4] = 4;
+	state->CH_Ctrl[14].val[4] = 0;
+	state->CH_Ctrl[14].addr[5] = 14;
+	state->CH_Ctrl[14].bit[5] = 5;
+	state->CH_Ctrl[14].val[5] = 0;
+	state->CH_Ctrl[14].addr[6] = 14;
+	state->CH_Ctrl[14].bit[6] = 6;
+	state->CH_Ctrl[14].val[6] = 0;
+
+	state->CH_Ctrl[15].Ctrl_Num = CHCAL_FRAC_MOD_RF ;
+	state->CH_Ctrl[15].size = 18 ;
+	state->CH_Ctrl[15].addr[0] = 17;
+	state->CH_Ctrl[15].bit[0] = 6;
+	state->CH_Ctrl[15].val[0] = 0;
+	state->CH_Ctrl[15].addr[1] = 17;
+	state->CH_Ctrl[15].bit[1] = 7;
+	state->CH_Ctrl[15].val[1] = 0;
+	state->CH_Ctrl[15].addr[2] = 16;
+	state->CH_Ctrl[15].bit[2] = 0;
+	state->CH_Ctrl[15].val[2] = 0;
+	state->CH_Ctrl[15].addr[3] = 16;
+	state->CH_Ctrl[15].bit[3] = 1;
+	state->CH_Ctrl[15].val[3] = 0;
+	state->CH_Ctrl[15].addr[4] = 16;
+	state->CH_Ctrl[15].bit[4] = 2;
+	state->CH_Ctrl[15].val[4] = 0;
+	state->CH_Ctrl[15].addr[5] = 16;
+	state->CH_Ctrl[15].bit[5] = 3;
+	state->CH_Ctrl[15].val[5] = 0;
+	state->CH_Ctrl[15].addr[6] = 16;
+	state->CH_Ctrl[15].bit[6] = 4;
+	state->CH_Ctrl[15].val[6] = 0;
+	state->CH_Ctrl[15].addr[7] = 16;
+	state->CH_Ctrl[15].bit[7] = 5;
+	state->CH_Ctrl[15].val[7] = 0;
+	state->CH_Ctrl[15].addr[8] = 16;
+	state->CH_Ctrl[15].bit[8] = 6;
+	state->CH_Ctrl[15].val[8] = 0;
+	state->CH_Ctrl[15].addr[9] = 16;
+	state->CH_Ctrl[15].bit[9] = 7;
+	state->CH_Ctrl[15].val[9] = 0;
+	state->CH_Ctrl[15].addr[10] = 15;
+	state->CH_Ctrl[15].bit[10] = 0;
+	state->CH_Ctrl[15].val[10] = 0;
+	state->CH_Ctrl[15].addr[11] = 15;
+	state->CH_Ctrl[15].bit[11] = 1;
+	state->CH_Ctrl[15].val[11] = 0;
+	state->CH_Ctrl[15].addr[12] = 15;
+	state->CH_Ctrl[15].bit[12] = 2;
+	state->CH_Ctrl[15].val[12] = 0;
+	state->CH_Ctrl[15].addr[13] = 15;
+	state->CH_Ctrl[15].bit[13] = 3;
+	state->CH_Ctrl[15].val[13] = 0;
+	state->CH_Ctrl[15].addr[14] = 15;
+	state->CH_Ctrl[15].bit[14] = 4;
+	state->CH_Ctrl[15].val[14] = 0;
+	state->CH_Ctrl[15].addr[15] = 15;
+	state->CH_Ctrl[15].bit[15] = 5;
+	state->CH_Ctrl[15].val[15] = 0;
+	state->CH_Ctrl[15].addr[16] = 15;
+	state->CH_Ctrl[15].bit[16] = 6;
+	state->CH_Ctrl[15].val[16] = 1;
+	state->CH_Ctrl[15].addr[17] = 15;
+	state->CH_Ctrl[15].bit[17] = 7;
+	state->CH_Ctrl[15].val[17] = 1;
+
+	state->CH_Ctrl[16].Ctrl_Num = RFSYN_LPF_R ;
+	state->CH_Ctrl[16].size = 5 ;
+	state->CH_Ctrl[16].addr[0] = 112;
+	state->CH_Ctrl[16].bit[0] = 0;
+	state->CH_Ctrl[16].val[0] = 0;
+	state->CH_Ctrl[16].addr[1] = 112;
+	state->CH_Ctrl[16].bit[1] = 1;
+	state->CH_Ctrl[16].val[1] = 0;
+	state->CH_Ctrl[16].addr[2] = 112;
+	state->CH_Ctrl[16].bit[2] = 2;
+	state->CH_Ctrl[16].val[2] = 0;
+	state->CH_Ctrl[16].addr[3] = 112;
+	state->CH_Ctrl[16].bit[3] = 3;
+	state->CH_Ctrl[16].val[3] = 0;
+	state->CH_Ctrl[16].addr[4] = 112;
+	state->CH_Ctrl[16].bit[4] = 4;
+	state->CH_Ctrl[16].val[4] = 1;
+
+	state->CH_Ctrl[17].Ctrl_Num = CHCAL_EN_INT_RF ;
+	state->CH_Ctrl[17].size = 1 ;
+	state->CH_Ctrl[17].addr[0] = 14;
+	state->CH_Ctrl[17].bit[0] = 7;
+	state->CH_Ctrl[17].val[0] = 0;
+
+	state->CH_Ctrl[18].Ctrl_Num = TG_LO_DIVVAL ;
+	state->CH_Ctrl[18].size = 4 ;
+	state->CH_Ctrl[18].addr[0] = 107;
+	state->CH_Ctrl[18].bit[0] = 3;
+	state->CH_Ctrl[18].val[0] = 0;
+	state->CH_Ctrl[18].addr[1] = 107;
+	state->CH_Ctrl[18].bit[1] = 4;
+	state->CH_Ctrl[18].val[1] = 0;
+	state->CH_Ctrl[18].addr[2] = 107;
+	state->CH_Ctrl[18].bit[2] = 5;
+	state->CH_Ctrl[18].val[2] = 0;
+	state->CH_Ctrl[18].addr[3] = 107;
+	state->CH_Ctrl[18].bit[3] = 6;
+	state->CH_Ctrl[18].val[3] = 0;
+
+	state->CH_Ctrl[19].Ctrl_Num = TG_LO_SELVAL ;
+	state->CH_Ctrl[19].size = 3 ;
+	state->CH_Ctrl[19].addr[0] = 107;
+	state->CH_Ctrl[19].bit[0] = 7;
+	state->CH_Ctrl[19].val[0] = 1;
+	state->CH_Ctrl[19].addr[1] = 106;
+	state->CH_Ctrl[19].bit[1] = 0;
+	state->CH_Ctrl[19].val[1] = 1;
+	state->CH_Ctrl[19].addr[2] = 106;
+	state->CH_Ctrl[19].bit[2] = 1;
+	state->CH_Ctrl[19].val[2] = 1;
+
+	state->CH_Ctrl[20].Ctrl_Num = TG_DIV_VAL ;
+	state->CH_Ctrl[20].size = 11 ;
+	state->CH_Ctrl[20].addr[0] = 109;
+	state->CH_Ctrl[20].bit[0] = 2;
+	state->CH_Ctrl[20].val[0] = 0;
+	state->CH_Ctrl[20].addr[1] = 109;
+	state->CH_Ctrl[20].bit[1] = 3;
+	state->CH_Ctrl[20].val[1] = 0;
+	state->CH_Ctrl[20].addr[2] = 109;
+	state->CH_Ctrl[20].bit[2] = 4;
+	state->CH_Ctrl[20].val[2] = 0;
+	state->CH_Ctrl[20].addr[3] = 109;
+	state->CH_Ctrl[20].bit[3] = 5;
+	state->CH_Ctrl[20].val[3] = 0;
+	state->CH_Ctrl[20].addr[4] = 109;
+	state->CH_Ctrl[20].bit[4] = 6;
+	state->CH_Ctrl[20].val[4] = 0;
+	state->CH_Ctrl[20].addr[5] = 109;
+	state->CH_Ctrl[20].bit[5] = 7;
+	state->CH_Ctrl[20].val[5] = 0;
+	state->CH_Ctrl[20].addr[6] = 108;
+	state->CH_Ctrl[20].bit[6] = 0;
+	state->CH_Ctrl[20].val[6] = 0;
+	state->CH_Ctrl[20].addr[7] = 108;
+	state->CH_Ctrl[20].bit[7] = 1;
+	state->CH_Ctrl[20].val[7] = 0;
+	state->CH_Ctrl[20].addr[8] = 108;
+	state->CH_Ctrl[20].bit[8] = 2;
+	state->CH_Ctrl[20].val[8] = 1;
+	state->CH_Ctrl[20].addr[9] = 108;
+	state->CH_Ctrl[20].bit[9] = 3;
+	state->CH_Ctrl[20].val[9] = 1;
+	state->CH_Ctrl[20].addr[10] = 108;
+	state->CH_Ctrl[20].bit[10] = 4;
+	state->CH_Ctrl[20].val[10] = 1;
+
+	state->CH_Ctrl[21].Ctrl_Num = TG_VCO_BIAS ;
+	state->CH_Ctrl[21].size = 6 ;
+	state->CH_Ctrl[21].addr[0] = 106;
+	state->CH_Ctrl[21].bit[0] = 2;
+	state->CH_Ctrl[21].val[0] = 0;
+	state->CH_Ctrl[21].addr[1] = 106;
+	state->CH_Ctrl[21].bit[1] = 3;
+	state->CH_Ctrl[21].val[1] = 0;
+	state->CH_Ctrl[21].addr[2] = 106;
+	state->CH_Ctrl[21].bit[2] = 4;
+	state->CH_Ctrl[21].val[2] = 0;
+	state->CH_Ctrl[21].addr[3] = 106;
+	state->CH_Ctrl[21].bit[3] = 5;
+	state->CH_Ctrl[21].val[3] = 0;
+	state->CH_Ctrl[21].addr[4] = 106;
+	state->CH_Ctrl[21].bit[4] = 6;
+	state->CH_Ctrl[21].val[4] = 0;
+	state->CH_Ctrl[21].addr[5] = 106;
+	state->CH_Ctrl[21].bit[5] = 7;
+	state->CH_Ctrl[21].val[5] = 1;
+
+	state->CH_Ctrl[22].Ctrl_Num = SEQ_EXTPOWERUP ;
+	state->CH_Ctrl[22].size = 1 ;
+	state->CH_Ctrl[22].addr[0] = 138;
+	state->CH_Ctrl[22].bit[0] = 4;
+	state->CH_Ctrl[22].val[0] = 1;
+
+	state->CH_Ctrl[23].Ctrl_Num = OVERRIDE_2 ;
+	state->CH_Ctrl[23].size = 1 ;
+	state->CH_Ctrl[23].addr[0] = 17;
+	state->CH_Ctrl[23].bit[0] = 5;
+	state->CH_Ctrl[23].val[0] = 0;
+
+	state->CH_Ctrl[24].Ctrl_Num = OVERRIDE_3 ;
+	state->CH_Ctrl[24].size = 1 ;
+	state->CH_Ctrl[24].addr[0] = 111;
+	state->CH_Ctrl[24].bit[0] = 3;
+	state->CH_Ctrl[24].val[0] = 0;
+
+	state->CH_Ctrl[25].Ctrl_Num = OVERRIDE_4 ;
+	state->CH_Ctrl[25].size = 1 ;
+	state->CH_Ctrl[25].addr[0] = 112;
+	state->CH_Ctrl[25].bit[0] = 7;
+	state->CH_Ctrl[25].val[0] = 0;
+
+	state->CH_Ctrl[26].Ctrl_Num = SEQ_FSM_PULSE ;
+	state->CH_Ctrl[26].size = 1 ;
+	state->CH_Ctrl[26].addr[0] = 136;
+	state->CH_Ctrl[26].bit[0] = 7;
+	state->CH_Ctrl[26].val[0] = 0;
+
+	state->CH_Ctrl[27].Ctrl_Num = GPIO_4B ;
+	state->CH_Ctrl[27].size = 1 ;
+	state->CH_Ctrl[27].addr[0] = 149;
+	state->CH_Ctrl[27].bit[0] = 7;
+	state->CH_Ctrl[27].val[0] = 0;
+
+	state->CH_Ctrl[28].Ctrl_Num = GPIO_3B ;
+	state->CH_Ctrl[28].size = 1 ;
+	state->CH_Ctrl[28].addr[0] = 149;
+	state->CH_Ctrl[28].bit[0] = 6;
+	state->CH_Ctrl[28].val[0] = 0;
+
+	state->CH_Ctrl[29].Ctrl_Num = GPIO_4 ;
+	state->CH_Ctrl[29].size = 1 ;
+	state->CH_Ctrl[29].addr[0] = 149;
+	state->CH_Ctrl[29].bit[0] = 5;
+	state->CH_Ctrl[29].val[0] = 1;
+
+	state->CH_Ctrl[30].Ctrl_Num = GPIO_3 ;
+	state->CH_Ctrl[30].size = 1 ;
+	state->CH_Ctrl[30].addr[0] = 149;
+	state->CH_Ctrl[30].bit[0] = 4;
+	state->CH_Ctrl[30].val[0] = 1;
+
+	state->CH_Ctrl[31].Ctrl_Num = GPIO_1B ;
+	state->CH_Ctrl[31].size = 1 ;
+	state->CH_Ctrl[31].addr[0] = 149;
+	state->CH_Ctrl[31].bit[0] = 3;
+	state->CH_Ctrl[31].val[0] = 0;
+
+	state->CH_Ctrl[32].Ctrl_Num = DAC_A_ENABLE ;
+	state->CH_Ctrl[32].size = 1 ;
+	state->CH_Ctrl[32].addr[0] = 93;
+	state->CH_Ctrl[32].bit[0] = 1;
+	state->CH_Ctrl[32].val[0] = 0;
+
+	state->CH_Ctrl[33].Ctrl_Num = DAC_B_ENABLE ;
+	state->CH_Ctrl[33].size = 1 ;
+	state->CH_Ctrl[33].addr[0] = 93;
+	state->CH_Ctrl[33].bit[0] = 0;
+	state->CH_Ctrl[33].val[0] = 0;
+
+	state->CH_Ctrl[34].Ctrl_Num = DAC_DIN_A ;
+	state->CH_Ctrl[34].size = 6 ;
+	state->CH_Ctrl[34].addr[0] = 92;
+	state->CH_Ctrl[34].bit[0] = 2;
+	state->CH_Ctrl[34].val[0] = 0;
+	state->CH_Ctrl[34].addr[1] = 92;
+	state->CH_Ctrl[34].bit[1] = 3;
+	state->CH_Ctrl[34].val[1] = 0;
+	state->CH_Ctrl[34].addr[2] = 92;
+	state->CH_Ctrl[34].bit[2] = 4;
+	state->CH_Ctrl[34].val[2] = 0;
+	state->CH_Ctrl[34].addr[3] = 92;
+	state->CH_Ctrl[34].bit[3] = 5;
+	state->CH_Ctrl[34].val[3] = 0;
+	state->CH_Ctrl[34].addr[4] = 92;
+	state->CH_Ctrl[34].bit[4] = 6;
+	state->CH_Ctrl[34].val[4] = 0;
+	state->CH_Ctrl[34].addr[5] = 92;
+	state->CH_Ctrl[34].bit[5] = 7;
+	state->CH_Ctrl[34].val[5] = 0;
+
+	state->CH_Ctrl[35].Ctrl_Num = DAC_DIN_B ;
+	state->CH_Ctrl[35].size = 6 ;
+	state->CH_Ctrl[35].addr[0] = 93;
+	state->CH_Ctrl[35].bit[0] = 2;
+	state->CH_Ctrl[35].val[0] = 0;
+	state->CH_Ctrl[35].addr[1] = 93;
+	state->CH_Ctrl[35].bit[1] = 3;
+	state->CH_Ctrl[35].val[1] = 0;
+	state->CH_Ctrl[35].addr[2] = 93;
+	state->CH_Ctrl[35].bit[2] = 4;
+	state->CH_Ctrl[35].val[2] = 0;
+	state->CH_Ctrl[35].addr[3] = 93;
+	state->CH_Ctrl[35].bit[3] = 5;
+	state->CH_Ctrl[35].val[3] = 0;
+	state->CH_Ctrl[35].addr[4] = 93;
+	state->CH_Ctrl[35].bit[4] = 6;
+	state->CH_Ctrl[35].val[4] = 0;
+	state->CH_Ctrl[35].addr[5] = 93;
+	state->CH_Ctrl[35].bit[5] = 7;
+	state->CH_Ctrl[35].val[5] = 0;
+
+#ifdef _MXL_PRODUCTION
+	state->CH_Ctrl[36].Ctrl_Num = RFSYN_EN_DIV ;
+	state->CH_Ctrl[36].size = 1 ;
+	state->CH_Ctrl[36].addr[0] = 109;
+	state->CH_Ctrl[36].bit[0] = 1;
+	state->CH_Ctrl[36].val[0] = 1;
+
+	state->CH_Ctrl[37].Ctrl_Num = RFSYN_DIVM ;
+	state->CH_Ctrl[37].size = 2 ;
+	state->CH_Ctrl[37].addr[0] = 112;
+	state->CH_Ctrl[37].bit[0] = 5;
+	state->CH_Ctrl[37].val[0] = 0;
+	state->CH_Ctrl[37].addr[1] = 112;
+	state->CH_Ctrl[37].bit[1] = 6;
+	state->CH_Ctrl[37].val[1] = 0;
+
+	state->CH_Ctrl[38].Ctrl_Num = DN_BYPASS_AGC_I2C ;
+	state->CH_Ctrl[38].size = 1 ;
+	state->CH_Ctrl[38].addr[0] = 65;
+	state->CH_Ctrl[38].bit[0] = 1;
+	state->CH_Ctrl[38].val[0] = 0;
+#endif
+
+	return 0 ;
+}
+
+static void InitTunerControls(struct dvb_frontend *fe)
+{
+	MXL5005_RegisterInit(fe);
+	MXL5005_ControlInit(fe);
+#ifdef _MXL_INTERNAL
+	MXL5005_MXLControlInit(fe);
+#endif
+}
+
+static u16 MXL5005_TunerConfig(struct dvb_frontend *fe,
+	u8	Mode,		/* 0: Analog Mode ; 1: Digital Mode */
+	u8	IF_mode,	/* for Analog Mode, 0: zero IF; 1: low IF */
+	u32	Bandwidth,	/* filter  channel bandwidth (6, 7, 8) */
+	u32	IF_out,		/* Desired IF Out Frequency */
+	u32	Fxtal,		/* XTAL Frequency */
+	u8	AGC_Mode,	/* AGC Mode - Dual AGC: 0, Single AGC: 1 */
+	u16	TOP,		/* 0: Dual AGC; Value: take over point */
+	u16	IF_OUT_LOAD,	/* IF Out Load Resistor (200 / 300 Ohms) */
+	u8	CLOCK_OUT, 	/* 0: turn off clk out; 1: turn on clock out */
+	u8	DIV_OUT,	/* 0: Div-1; 1: Div-4 */
+	u8	CAPSELECT, 	/* 0: disable On-Chip pulling cap; 1: enable */
+	u8	EN_RSSI, 	/* 0: disable RSSI; 1: enable RSSI */
+
+	/* Modulation Type; */
+	/* 0 - Default;	1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */
+	u8	Mod_Type,
+
+	/* Tracking Filter */
+	/* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */
+	u8	TF_Type
+	)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u16 status = 0;
+
+	state->Mode = Mode;
+	state->IF_Mode = IF_mode;
+	state->Chan_Bandwidth = Bandwidth;
+	state->IF_OUT = IF_out;
+	state->Fxtal = Fxtal;
+	state->AGC_Mode = AGC_Mode;
+	state->TOP = TOP;
+	state->IF_OUT_LOAD = IF_OUT_LOAD;
+	state->CLOCK_OUT = CLOCK_OUT;
+	state->DIV_OUT = DIV_OUT;
+	state->CAPSELECT = CAPSELECT;
+	state->EN_RSSI = EN_RSSI;
+	state->Mod_Type = Mod_Type;
+	state->TF_Type = TF_Type;
+
+	/* Initialize all the controls and registers */
+	InitTunerControls(fe);
+
+	/* Synthesizer LO frequency calculation */
+	MXL_SynthIFLO_Calc(fe);
+
+	return status;
+}
+
+static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	if (state->Mode == 1) /* Digital Mode */
+		state->IF_LO = state->IF_OUT;
+	else /* Analog Mode */ {
+		if (state->IF_Mode == 0) /* Analog Zero IF mode */
+			state->IF_LO = state->IF_OUT + 400000;
+		else /* Analog Low IF mode */
+			state->IF_LO = state->IF_OUT + state->Chan_Bandwidth/2;
+	}
+}
+
+static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+
+	if (state->Mode == 1) /* Digital Mode */ {
+			/* remove 20.48MHz setting for 2.6.10 */
+			state->RF_LO = state->RF_IN;
+			/* change for 2.6.6 */
+			state->TG_LO = state->RF_IN - 750000;
+	} else /* Analog Mode */ {
+		if (state->IF_Mode == 0) /* Analog Zero IF mode */ {
+			state->RF_LO = state->RF_IN - 400000;
+			state->TG_LO = state->RF_IN - 1750000;
+		} else /* Analog Low IF mode */ {
+			state->RF_LO = state->RF_IN - state->Chan_Bandwidth/2;
+			state->TG_LO = state->RF_IN -
+				state->Chan_Bandwidth + 500000;
+		}
+	}
+}
+
+static u16 MXL_OverwriteICDefault(struct dvb_frontend *fe)
+{
+	u16 status = 0;
+
+	status += MXL_ControlWrite(fe, OVERRIDE_1, 1);
+	status += MXL_ControlWrite(fe, OVERRIDE_2, 1);
+	status += MXL_ControlWrite(fe, OVERRIDE_3, 1);
+	status += MXL_ControlWrite(fe, OVERRIDE_4, 1);
+
+	return status;
+}
+
+static u16 MXL_BlockInit(struct dvb_frontend *fe)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u16 status = 0;
+
+	status += MXL_OverwriteICDefault(fe);
+
+	/* Downconverter Control Dig Ana */
+	status += MXL_ControlWrite(fe, DN_IQTN_AMP_CUT, state->Mode ? 1 : 0);
+
+	/* Filter Control  Dig  Ana */
+	status += MXL_ControlWrite(fe, BB_MODE, state->Mode ? 0 : 1);
+	status += MXL_ControlWrite(fe, BB_BUF, state->Mode ? 3 : 2);
+	status += MXL_ControlWrite(fe, BB_BUF_OA, state->Mode ? 1 : 0);
+	status += MXL_ControlWrite(fe, BB_IQSWAP, state->Mode ? 0 : 1);
+	status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 0);
+
+	/* Initialize Low-Pass Filter */
+	if (state->Mode) { /* Digital Mode */
+		switch (state->Chan_Bandwidth) {
+		case 8000000:
+			status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 0);
+			break;
+		case 7000000:
+			status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 2);
+			break;
+		case 6000000:
+			status += MXL_ControlWrite(fe,
+					BB_DLPF_BANDSEL, 3);
+			break;
+		}
+	} else { /* Analog Mode */
+		switch (state->Chan_Bandwidth) {
+		case 8000000:	/* Low Zero */
+			status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT,
+					(state->IF_Mode ? 0 : 3));
+			break;
+		case 7000000:
+			status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT,
+					(state->IF_Mode ? 1 : 4));
+			break;
+		case 6000000:
+			status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT,
+					(state->IF_Mode ? 2 : 5));
+			break;
+		}
+	}
+
+	/* Charge Pump Control Dig  Ana */
+	status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, state->Mode ? 5 : 8);
+	status += MXL_ControlWrite(fe,
+		RFSYN_EN_CHP_HIGAIN, state->Mode ? 1 : 1);
+	status += MXL_ControlWrite(fe, EN_CHP_LIN_B, state->Mode ? 0 : 0);
+
+	/* AGC TOP Control */
+	if (state->AGC_Mode == 0) /* Dual AGC */ {
+		status += MXL_ControlWrite(fe, AGC_IF, 15);
+		status += MXL_ControlWrite(fe, AGC_RF, 15);
+	} else /*  Single AGC Mode Dig  Ana */
+		status += MXL_ControlWrite(fe, AGC_RF, state->Mode ? 15 : 12);
+
+	if (state->TOP == 55) /* TOP == 5.5 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x0);
+
+	if (state->TOP == 72) /* TOP == 7.2 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x1);
+
+	if (state->TOP == 92) /* TOP == 9.2 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x2);
+
+	if (state->TOP == 110) /* TOP == 11.0 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x3);
+
+	if (state->TOP == 129) /* TOP == 12.9 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x4);
+
+	if (state->TOP == 147) /* TOP == 14.7 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x5);
+
+	if (state->TOP == 168) /* TOP == 16.8 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x6);
+
+	if (state->TOP == 194) /* TOP == 19.4 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x7);
+
+	if (state->TOP == 212) /* TOP == 21.2 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0x9);
+
+	if (state->TOP == 232) /* TOP == 23.2 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0xA);
+
+	if (state->TOP == 252) /* TOP == 25.2 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0xB);
+
+	if (state->TOP == 271) /* TOP == 27.1 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0xC);
+
+	if (state->TOP == 292) /* TOP == 29.2 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0xD);
+
+	if (state->TOP == 317) /* TOP == 31.7 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0xE);
+
+	if (state->TOP == 349) /* TOP == 34.9 */
+		status += MXL_ControlWrite(fe, AGC_IF, 0xF);
+
+	/* IF Synthesizer Control */
+	status += MXL_IFSynthInit(fe);
+
+	/* IF UpConverter Control */
+	if (state->IF_OUT_LOAD == 200) {
+		status += MXL_ControlWrite(fe, DRV_RES_SEL, 6);
+		status += MXL_ControlWrite(fe, I_DRIVER, 2);
+	}
+	if (state->IF_OUT_LOAD == 300) {
+		status += MXL_ControlWrite(fe, DRV_RES_SEL, 4);
+		status += MXL_ControlWrite(fe, I_DRIVER, 1);
+	}
+
+	/* Anti-Alias Filtering Control
+	 * initialise Anti-Aliasing Filter
+	 */
+	if (state->Mode) { /* Digital Mode */
+		if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 6280000UL) {
+			status += MXL_ControlWrite(fe, EN_AAF, 1);
+			status += MXL_ControlWrite(fe, EN_3P, 1);
+			status += MXL_ControlWrite(fe, EN_AUX_3P, 1);
+			status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0);
+		}
+		if ((state->IF_OUT == 36125000UL) ||
+			(state->IF_OUT == 36150000UL)) {
+			status += MXL_ControlWrite(fe, EN_AAF, 1);
+			status += MXL_ControlWrite(fe, EN_3P, 1);
+			status += MXL_ControlWrite(fe, EN_AUX_3P, 1);
+			status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1);
+		}
+		if (state->IF_OUT > 36150000UL) {
+			status += MXL_ControlWrite(fe, EN_AAF, 0);
+			status += MXL_ControlWrite(fe, EN_3P, 1);
+			status += MXL_ControlWrite(fe, EN_AUX_3P, 1);
+			status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1);
+		}
+	} else { /* Analog Mode */
+		if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 5000000UL) {
+			status += MXL_ControlWrite(fe, EN_AAF, 1);
+			status += MXL_ControlWrite(fe, EN_3P, 1);
+			status += MXL_ControlWrite(fe, EN_AUX_3P, 1);
+			status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0);
+		}
+		if (state->IF_OUT > 5000000UL) {
+			status += MXL_ControlWrite(fe, EN_AAF, 0);
+			status += MXL_ControlWrite(fe, EN_3P, 0);
+			status += MXL_ControlWrite(fe, EN_AUX_3P, 0);
+			status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0);
+		}
+	}
+
+	/* Demod Clock Out */
+	if (state->CLOCK_OUT)
+		status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 1);
+	else
+		status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 0);
+
+	if (state->DIV_OUT == 1)
+		status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 1);
+	if (state->DIV_OUT == 0)
+		status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 0);
+
+	/* Crystal Control */
+	if (state->CAPSELECT)
+		status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 1);
+	else
+		status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 0);
+
+	if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL)
+		status += MXL_ControlWrite(fe, IF_SEL_DBL, 1);
+	if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL)
+		status += MXL_ControlWrite(fe, IF_SEL_DBL, 0);
+
+	if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL)
+		status += MXL_ControlWrite(fe, RFSYN_R_DIV, 3);
+	if (state->Fxtal > 22000000UL && state->Fxtal <= 32000000UL)
+		status += MXL_ControlWrite(fe, RFSYN_R_DIV, 0);
+
+	/* Misc Controls */
+	if (state->Mode == 0 && state->IF_Mode == 1) /* Analog LowIF mode */
+		status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 0);
+	else
+		status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 1);
+
+	/* status += MXL_ControlRead(fe, IF_DIVVAL, &IF_DIVVAL_Val); */
+
+	/* Set TG_R_DIV */
+	status += MXL_ControlWrite(fe, TG_R_DIV,
+		MXL_Ceiling(state->Fxtal, 1000000));
+
+	/* Apply Default value to BB_INITSTATE_DLPF_TUNE */
+
+	/* RSSI Control */
+	if (state->EN_RSSI) {
+		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
+		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+		/* RSSI reference point */
+		status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 3);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1);
+
+		/* TOP point */
+		status += MXL_ControlWrite(fe, RFA_FLR, 0);
+		status += MXL_ControlWrite(fe, RFA_CEIL, 12);
+	}
+
+	/* Modulation type bit settings
+	 * Override the control values preset
+	 */
+	if (state->Mod_Type == MXL_DVBT) /* DVB-T Mode */ {
+		state->AGC_Mode = 1; /* Single AGC Mode */
+
+		/* Enable RSSI */
+		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
+		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+		/* RSSI reference point */
+		status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1);
+
+		/* TOP point */
+		status += MXL_ControlWrite(fe, RFA_FLR, 2);
+		status += MXL_ControlWrite(fe, RFA_CEIL, 13);
+		if (state->IF_OUT <= 6280000UL)	/* Low IF */
+			status += MXL_ControlWrite(fe, BB_IQSWAP, 0);
+		else /* High IF */
+			status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
+
+	}
+	if (state->Mod_Type == MXL_ATSC) /* ATSC Mode */ {
+		state->AGC_Mode = 1;	/* Single AGC Mode */
+
+		/* Enable RSSI */
+		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
+		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+		/* RSSI reference point */
+		status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 4);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1);
+
+		/* TOP point */
+		status += MXL_ControlWrite(fe, RFA_FLR, 2);
+		status += MXL_ControlWrite(fe, RFA_CEIL, 13);
+		status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 1);
+		/* Low Zero */
+		status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5);
+
+		if (state->IF_OUT <= 6280000UL)	/* Low IF */
+			status += MXL_ControlWrite(fe, BB_IQSWAP, 0);
+		else /* High IF */
+			status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
+	}
+	if (state->Mod_Type == MXL_QAM) /* QAM Mode */ {
+		state->Mode = MXL_DIGITAL_MODE;
+
+		/* state->AGC_Mode = 1; */ /* Single AGC Mode */
+
+		/* Disable RSSI */	/* change here for v2.6.5 */
+		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0);
+		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+		/* RSSI reference point */
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2);
+		/* change here for v2.6.5 */
+		status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
+
+		if (state->IF_OUT <= 6280000UL)	/* Low IF */
+			status += MXL_ControlWrite(fe, BB_IQSWAP, 0);
+		else /* High IF */
+			status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
+		status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2);
+
+	}
+	if (state->Mod_Type == MXL_ANALOG_CABLE) {
+		/* Analog Cable Mode */
+		/* state->Mode = MXL_DIGITAL_MODE; */
+
+		state->AGC_Mode = 1; /* Single AGC Mode */
+
+		/* Disable RSSI */
+		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0);
+		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+		/* change for 2.6.3 */
+		status += MXL_ControlWrite(fe, AGC_IF, 1);
+		status += MXL_ControlWrite(fe, AGC_RF, 15);
+		status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
+	}
+
+	if (state->Mod_Type == MXL_ANALOG_OTA) {
+		/* Analog OTA Terrestrial mode add for 2.6.7 */
+		/* state->Mode = MXL_ANALOG_MODE; */
+
+		/* Enable RSSI */
+		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
+		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+		/* RSSI reference point */
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3);
+		status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2);
+		status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
+		status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
+	}
+
+	/* RSSI disable */
+	if (state->EN_RSSI == 0) {
+		status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+		status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0);
+		status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+	}
+
+	return status;
+}
+
+static u16 MXL_IFSynthInit(struct dvb_frontend *fe)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u16 status = 0 ;
+	u32	Fref = 0 ;
+	u32	Kdbl, intModVal ;
+	u32	fracModVal ;
+	Kdbl = 2 ;
+
+	if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL)
+		Kdbl = 2 ;
+	if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL)
+		Kdbl = 1 ;
+
+	/* IF Synthesizer Control */
+	if (state->Mode == 0 && state->IF_Mode == 1) /* Analog Low IF mode */ {
+		if (state->IF_LO == 41000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+			Fref = 328000000UL ;
+		}
+		if (state->IF_LO == 47000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 376000000UL ;
+		}
+		if (state->IF_LO == 54000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x10);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+			Fref = 324000000UL ;
+		}
+		if (state->IF_LO == 60000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x10);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 360000000UL ;
+		}
+		if (state->IF_LO == 39250000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+			Fref = 314000000UL ;
+		}
+		if (state->IF_LO == 39650000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+			Fref = 317200000UL ;
+		}
+		if (state->IF_LO == 40150000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+			Fref = 321200000UL ;
+		}
+		if (state->IF_LO == 40650000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+			Fref = 325200000UL ;
+		}
+	}
+
+	if (state->Mode || (state->Mode == 0 && state->IF_Mode == 0)) {
+		if (state->IF_LO == 57000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x10);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 342000000UL ;
+		}
+		if (state->IF_LO == 44000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 352000000UL ;
+		}
+		if (state->IF_LO == 43750000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 350000000UL ;
+		}
+		if (state->IF_LO == 36650000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 366500000UL ;
+		}
+		if (state->IF_LO == 36150000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 361500000UL ;
+		}
+		if (state->IF_LO == 36000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 360000000UL ;
+		}
+		if (state->IF_LO == 35250000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 352500000UL ;
+		}
+		if (state->IF_LO == 34750000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 347500000UL ;
+		}
+		if (state->IF_LO == 6280000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x07);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 376800000UL ;
+		}
+		if (state->IF_LO == 5000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x09);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 360000000UL ;
+		}
+		if (state->IF_LO == 4500000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x06);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 360000000UL ;
+		}
+		if (state->IF_LO == 4570000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x06);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 365600000UL ;
+		}
+		if (state->IF_LO == 4000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x05);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 360000000UL ;
+		}
+		if (state->IF_LO == 57400000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x10);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 344400000UL ;
+		}
+		if (state->IF_LO == 44400000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 355200000UL ;
+		}
+		if (state->IF_LO == 44150000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x08);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 353200000UL ;
+		}
+		if (state->IF_LO == 37050000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 370500000UL ;
+		}
+		if (state->IF_LO == 36550000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 365500000UL ;
+		}
+		if (state->IF_LO == 36125000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x04);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 361250000UL ;
+		}
+		if (state->IF_LO == 6000000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x07);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 360000000UL ;
+		}
+		if (state->IF_LO == 5400000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x07);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+			Fref = 324000000UL ;
+		}
+		if (state->IF_LO == 5380000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x07);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+			Fref = 322800000UL ;
+		}
+		if (state->IF_LO == 5200000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x09);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 374400000UL ;
+		}
+		if (state->IF_LO == 4900000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x09);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 352800000UL ;
+		}
+		if (state->IF_LO == 4400000UL) {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x06);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 352000000UL ;
+		}
+		if (state->IF_LO == 4063000UL)  /* add for 2.6.8 */ {
+			status += MXL_ControlWrite(fe, IF_DIVVAL,   0x05);
+			status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+			Fref = 365670000UL ;
+		}
+	}
+	/* CHCAL_INT_MOD_IF */
+	/* CHCAL_FRAC_MOD_IF */
+	intModVal = Fref / (state->Fxtal * Kdbl/2);
+	status += MXL_ControlWrite(fe, CHCAL_INT_MOD_IF, intModVal);
+
+	fracModVal = (2<<15)*(Fref/1000 - (state->Fxtal/1000 * Kdbl/2) *
+		intModVal);
+
+	fracModVal = fracModVal / ((state->Fxtal * Kdbl/2)/1000);
+	status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_IF, fracModVal);
+
+	return status ;
+}
+
+static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u16 status = 0;
+	u32 divider_val, E3, E4, E5, E5A;
+	u32 Fmax, Fmin, FmaxBin, FminBin;
+	u32 Kdbl_RF = 2;
+	u32 tg_divval;
+	u32 tg_lo;
+
+	u32 Fref_TG;
+	u32 Fvco;
+
+	state->RF_IN = RF_Freq;
+
+	MXL_SynthRFTGLO_Calc(fe);
+
+	if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL)
+		Kdbl_RF = 2;
+	if (state->Fxtal > 22000000 && state->Fxtal <= 32000000)
+		Kdbl_RF = 1;
+
+	/* Downconverter Controls
+	 * Look-Up Table Implementation for:
+	 *	DN_POLY
+	 *	DN_RFGAIN
+	 *	DN_CAP_RFLPF
+	 *	DN_EN_VHFUHFBAR
+	 *	DN_GAIN_ADJUST
+	 *  Change the boundary reference from RF_IN to RF_LO
+	 */
+	if (state->RF_LO < 40000000UL)
+		return -1;
+
+	if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) {
+		status += MXL_ControlWrite(fe, DN_POLY,              2);
+		status += MXL_ControlWrite(fe, DN_RFGAIN,            3);
+		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         423);
+		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      1);
+		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       1);
+	}
+	if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) {
+		status += MXL_ControlWrite(fe, DN_POLY,              3);
+		status += MXL_ControlWrite(fe, DN_RFGAIN,            3);
+		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         222);
+		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      1);
+		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       1);
+	}
+	if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) {
+		status += MXL_ControlWrite(fe, DN_POLY,              3);
+		status += MXL_ControlWrite(fe, DN_RFGAIN,            3);
+		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         147);
+		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      1);
+		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       2);
+	}
+	if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) {
+		status += MXL_ControlWrite(fe, DN_POLY,              3);
+		status += MXL_ControlWrite(fe, DN_RFGAIN,            3);
+		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         9);
+		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      1);
+		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       2);
+	}
+	if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) {
+		status += MXL_ControlWrite(fe, DN_POLY,              3);
+		status += MXL_ControlWrite(fe, DN_RFGAIN,            3);
+		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         0);
+		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      1);
+		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       3);
+	}
+	if (state->RF_LO > 300000000UL && state->RF_LO <= 650000000UL) {
+		status += MXL_ControlWrite(fe, DN_POLY,              3);
+		status += MXL_ControlWrite(fe, DN_RFGAIN,            1);
+		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         0);
+		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      0);
+		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       3);
+	}
+	if (state->RF_LO > 650000000UL && state->RF_LO <= 900000000UL) {
+		status += MXL_ControlWrite(fe, DN_POLY,              3);
+		status += MXL_ControlWrite(fe, DN_RFGAIN,            2);
+		status += MXL_ControlWrite(fe, DN_CAP_RFLPF,         0);
+		status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR,      0);
+		status += MXL_ControlWrite(fe, DN_GAIN_ADJUST,       3);
+	}
+	if (state->RF_LO > 900000000UL)
+		return -1;
+
+	/*	DN_IQTNBUF_AMP */
+	/*	DN_IQTNGNBFBIAS_BST */
+	if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 300000000UL && state->RF_LO <= 400000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 400000000UL && state->RF_LO <= 450000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 450000000UL && state->RF_LO <= 500000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 500000000UL && state->RF_LO <= 550000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 550000000UL && state->RF_LO <= 600000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 600000000UL && state->RF_LO <= 650000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 650000000UL && state->RF_LO <= 700000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 700000000UL && state->RF_LO <= 750000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 750000000UL && state->RF_LO <= 800000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       1);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  0);
+	}
+	if (state->RF_LO > 800000000UL && state->RF_LO <= 850000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       10);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  1);
+	}
+	if (state->RF_LO > 850000000UL && state->RF_LO <= 900000000UL) {
+		status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP,       10);
+		status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST,  1);
+	}
+
+	/*
+	 * Set RF Synth and LO Path Control
+	 *
+	 * Look-Up table implementation for:
+	 *	RFSYN_EN_OUTMUX
+	 *	RFSYN_SEL_VCO_OUT
+	 *	RFSYN_SEL_VCO_HI
+	 *  RFSYN_SEL_DIVM
+	 *	RFSYN_RF_DIV_BIAS
+	 *	DN_SEL_FREQ
+	 *
+	 * Set divider_val, Fmax, Fmix to use in Equations
+	 */
+	FminBin = 28000000UL ;
+	FmaxBin = 42500000UL ;
+	if (state->RF_LO >= 40000000UL && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         1);
+		divider_val = 64 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 42500000UL ;
+	FmaxBin = 56000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         1);
+		divider_val = 64 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 56000000UL ;
+	FmaxBin = 85000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         1);
+		divider_val = 32 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 85000000UL ;
+	FmaxBin = 112000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         1);
+		divider_val = 32 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 112000000UL ;
+	FmaxBin = 170000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         2);
+		divider_val = 16 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 170000000UL ;
+	FmaxBin = 225000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         2);
+		divider_val = 16 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 225000000UL ;
+	FmaxBin = 300000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         4);
+		divider_val = 8 ;
+		Fmax = 340000000UL ;
+		Fmin = FminBin ;
+	}
+	FminBin = 300000000UL ;
+	FmaxBin = 340000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         0);
+		divider_val = 8 ;
+		Fmax = FmaxBin ;
+		Fmin = 225000000UL ;
+	}
+	FminBin = 340000000UL ;
+	FmaxBin = 450000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      0);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   2);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         0);
+		divider_val = 8 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 450000000UL ;
+	FmaxBin = 680000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      1);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         0);
+		divider_val = 4 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 680000000UL ;
+	FmaxBin = 900000000UL ;
+	if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX,     0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT,   1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI,    1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM,      1);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS,   1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ,         0);
+		divider_val = 4 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+
+	/*	CHCAL_INT_MOD_RF
+	 *	CHCAL_FRAC_MOD_RF
+	 *	RFSYN_LPF_R
+	 *	CHCAL_EN_INT_RF
+	 */
+	/* Equation E3 RFSYN_VCO_BIAS */
+	E3 = (((Fmax-state->RF_LO)/1000)*32)/((Fmax-Fmin)/1000) + 8 ;
+	status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, E3);
+
+	/* Equation E4 CHCAL_INT_MOD_RF */
+	E4 = (state->RF_LO*divider_val/1000)/(2*state->Fxtal*Kdbl_RF/1000);
+	MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, E4);
+
+	/* Equation E5 CHCAL_FRAC_MOD_RF CHCAL_EN_INT_RF */
+	E5 = ((2<<17)*(state->RF_LO/10000*divider_val -
+		(E4*(2*state->Fxtal*Kdbl_RF)/10000))) /
+		(2*state->Fxtal*Kdbl_RF/10000);
+
+	status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5);
+
+	/* Equation E5A RFSYN_LPF_R */
+	E5A = (((Fmax - state->RF_LO)/1000)*4/((Fmax-Fmin)/1000)) + 1 ;
+	status += MXL_ControlWrite(fe, RFSYN_LPF_R, E5A);
+
+	/* Euqation E5B CHCAL_EN_INIT_RF */
+	status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, ((E5 == 0) ? 1 : 0));
+	/*if (E5 == 0)
+	 *	status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, 1);
+	 *else
+	 *	status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5);
+	 */
+
+	/*
+	 * Set TG Synth
+	 *
+	 * Look-Up table implementation for:
+	 *	TG_LO_DIVVAL
+	 *	TG_LO_SELVAL
+	 *
+	 * Set divider_val, Fmax, Fmix to use in Equations
+	 */
+	if (state->TG_LO < 33000000UL)
+		return -1;
+
+	FminBin = 33000000UL ;
+	FmaxBin = 50000000UL ;
+	if (state->TG_LO >= FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x6);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x0);
+		divider_val = 36 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 50000000UL ;
+	FmaxBin = 67000000UL ;
+	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x1);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x0);
+		divider_val = 24 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 67000000UL ;
+	FmaxBin = 100000000UL ;
+	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0xC);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x2);
+		divider_val = 18 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 100000000UL ;
+	FmaxBin = 150000000UL ;
+	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x8);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x2);
+		divider_val = 12 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 150000000UL ;
+	FmaxBin = 200000000UL ;
+	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x0);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x2);
+		divider_val = 8 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 200000000UL ;
+	FmaxBin = 300000000UL ;
+	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x8);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x3);
+		divider_val = 6 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 300000000UL ;
+	FmaxBin = 400000000UL ;
+	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x0);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x3);
+		divider_val = 4 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 400000000UL ;
+	FmaxBin = 600000000UL ;
+	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x8);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x7);
+		divider_val = 3 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+	FminBin = 600000000UL ;
+	FmaxBin = 900000000UL ;
+	if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+		status += MXL_ControlWrite(fe, TG_LO_DIVVAL,	0x0);
+		status += MXL_ControlWrite(fe, TG_LO_SELVAL,	0x7);
+		divider_val = 2 ;
+		Fmax = FmaxBin ;
+		Fmin = FminBin ;
+	}
+
+	/* TG_DIV_VAL */
+	tg_divval = (state->TG_LO*divider_val/100000) *
+		(MXL_Ceiling(state->Fxtal, 1000000) * 100) /
+		(state->Fxtal/1000);
+
+	status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval);
+
+	if (state->TG_LO > 600000000UL)
+		status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval + 1);
+
+	Fmax = 1800000000UL ;
+	Fmin = 1200000000UL ;
+
+	/* prevent overflow of 32 bit unsigned integer, use
+	 * following equation. Edit for v2.6.4
+	 */
+	/* Fref_TF = Fref_TG * 1000 */
+	Fref_TG = (state->Fxtal/1000) / MXL_Ceiling(state->Fxtal, 1000000);
+
+	/* Fvco = Fvco/10 */
+	Fvco = (state->TG_LO/10000) * divider_val * Fref_TG;
+
+	tg_lo = (((Fmax/10 - Fvco)/100)*32) / ((Fmax-Fmin)/1000)+8;
+
+	/* below equation is same as above but much harder to debug.
+	 *
+	 * static u32 MXL_GetXtalInt(u32 Xtal_Freq)
+	 * {
+	 *	if ((Xtal_Freq % 1000000) == 0)
+	 *		return (Xtal_Freq / 10000);
+	 *	else
+	 *		return (((Xtal_Freq / 1000000) + 1)*100);
+	 * }
+	 *
+	 * u32 Xtal_Int = MXL_GetXtalInt(state->Fxtal);
+	 * tg_lo = ( ((Fmax/10000 * Xtal_Int)/100) -
+	 * ((state->TG_LO/10000)*divider_val *
+	 * (state->Fxtal/10000)/100) )*32/((Fmax-Fmin)/10000 *
+	 * Xtal_Int/100) + 8;
+	 */
+
+	status += MXL_ControlWrite(fe, TG_VCO_BIAS , tg_lo);
+
+	/* add for 2.6.5 Special setting for QAM */
+	if (state->Mod_Type == MXL_QAM) {
+		if (state->config->qam_gain != 0)
+			status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN,
+						   state->config->qam_gain);
+		else if (state->RF_IN < 680000000)
+			status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
+		else
+			status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2);
+	}
+
+	/* Off Chip Tracking Filter Control */
+	if (state->TF_Type == MXL_TF_OFF) {
+		/* Tracking Filter Off State; turn off all the banks */
+		status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+		status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+		status += MXL_SetGPIO(fe, 3, 1); /* Bank1 Off */
+		status += MXL_SetGPIO(fe, 1, 1); /* Bank2 Off */
+		status += MXL_SetGPIO(fe, 4, 1); /* Bank3 Off */
+	}
+
+	if (state->TF_Type == MXL_TF_C) /* Tracking Filter type C */ {
+		status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+		status += MXL_ControlWrite(fe, DAC_DIN_A, 0);
+
+		if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+			status += MXL_SetGPIO(fe, 3, 0);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+		}
+		if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+		}
+		if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+		}
+		if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 0);
+		}
+		if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 29);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 0);
+		}
+		if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 0);
+		}
+		if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 16);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+		}
+		if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 7);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+		}
+		if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+		}
+	}
+
+	if (state->TF_Type == MXL_TF_C_H) {
+
+		/* Tracking Filter type C-H for Hauppauge only */
+		status += MXL_ControlWrite(fe, DAC_DIN_A, 0);
+
+		if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+		}
+		if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+			status += MXL_SetGPIO(fe, 1, 1);
+		}
+		if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+			status += MXL_SetGPIO(fe, 1, 0);
+		}
+		if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+		}
+		if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+		}
+		if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+		}
+		if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+		}
+		if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+		}
+		if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) {
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+		}
+	}
+
+	if (state->TF_Type == MXL_TF_D) { /* Tracking Filter type D */
+
+		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+		if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+	}
+
+	if (state->TF_Type == MXL_TF_D_L) {
+
+		/* Tracking Filter type D-L for Lumanate ONLY change 2.6.3 */
+		status += MXL_ControlWrite(fe, DAC_DIN_A, 0);
+
+		/* if UHF and terrestrial => Turn off Tracking Filter */
+		if (state->RF_IN >= 471000000 &&
+			(state->RF_IN - 471000000)%6000000 != 0) {
+			/* Turn off all the banks */
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+			status += MXL_ControlWrite(fe, AGC_IF, 10);
+		} else {
+			/* if VHF or cable => Turn on Tracking Filter */
+			if (state->RF_IN >= 43000000 &&
+				state->RF_IN < 140000000) {
+
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+				status += MXL_SetGPIO(fe, 4, 1);
+				status += MXL_SetGPIO(fe, 1, 1);
+				status += MXL_SetGPIO(fe, 3, 0);
+			}
+			if (state->RF_IN >= 140000000 &&
+				state->RF_IN < 240000000) {
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+				status += MXL_SetGPIO(fe, 4, 1);
+				status += MXL_SetGPIO(fe, 1, 0);
+				status += MXL_SetGPIO(fe, 3, 0);
+			}
+			if (state->RF_IN >= 240000000 &&
+				state->RF_IN < 340000000) {
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+				status += MXL_SetGPIO(fe, 4, 0);
+				status += MXL_SetGPIO(fe, 1, 1);
+				status += MXL_SetGPIO(fe, 3, 0);
+			}
+			if (state->RF_IN >= 340000000 &&
+				state->RF_IN < 430000000) {
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+				status += MXL_SetGPIO(fe, 4, 0);
+				status += MXL_SetGPIO(fe, 1, 0);
+				status += MXL_SetGPIO(fe, 3, 1);
+			}
+			if (state->RF_IN >= 430000000 &&
+				state->RF_IN < 470000000) {
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+				status += MXL_SetGPIO(fe, 4, 1);
+				status += MXL_SetGPIO(fe, 1, 0);
+				status += MXL_SetGPIO(fe, 3, 1);
+			}
+			if (state->RF_IN >= 470000000 &&
+				state->RF_IN < 570000000) {
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+				status += MXL_SetGPIO(fe, 4, 0);
+				status += MXL_SetGPIO(fe, 1, 0);
+				status += MXL_SetGPIO(fe, 3, 1);
+			}
+			if (state->RF_IN >= 570000000 &&
+				state->RF_IN < 620000000) {
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+				status += MXL_SetGPIO(fe, 4, 0);
+				status += MXL_SetGPIO(fe, 1, 1);
+				status += MXL_SetGPIO(fe, 3, 1);
+			}
+			if (state->RF_IN >= 620000000 &&
+				state->RF_IN < 760000000) {
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+				status += MXL_SetGPIO(fe, 4, 0);
+				status += MXL_SetGPIO(fe, 1, 1);
+				status += MXL_SetGPIO(fe, 3, 1);
+			}
+			if (state->RF_IN >= 760000000 &&
+				state->RF_IN <= 900000000) {
+				status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+				status += MXL_SetGPIO(fe, 4, 1);
+				status += MXL_SetGPIO(fe, 1, 1);
+				status += MXL_SetGPIO(fe, 3, 1);
+			}
+		}
+	}
+
+	if (state->TF_Type == MXL_TF_E) /* Tracking Filter type E */ {
+
+		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+		if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+	}
+
+	if (state->TF_Type == MXL_TF_F) {
+
+		/* Tracking Filter type F */
+		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+		if (state->RF_IN >= 43000000 && state->RF_IN < 160000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 160000000 && state->RF_IN < 210000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 210000000 && state->RF_IN < 300000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 300000000 && state->RF_IN < 390000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 390000000 && state->RF_IN < 515000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 515000000 && state->RF_IN < 650000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 650000000 && state->RF_IN <= 900000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+	}
+
+	if (state->TF_Type == MXL_TF_E_2) {
+
+		/* Tracking Filter type E_2 */
+		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+		if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+	}
+
+	if (state->TF_Type == MXL_TF_G) {
+
+		/* Tracking Filter type G add for v2.6.8 */
+		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+		if (state->RF_IN >= 50000000 && state->RF_IN < 190000000) {
+
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 190000000 && state->RF_IN < 280000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 280000000 && state->RF_IN < 350000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 400000000 && state->RF_IN < 470000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 640000000 && state->RF_IN < 820000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 820000000 && state->RF_IN <= 900000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+	}
+
+	if (state->TF_Type == MXL_TF_E_NA) {
+
+		/* Tracking Filter type E-NA for Empia ONLY change for 2.6.8 */
+		status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+		/* if UHF and terrestrial=> Turn off Tracking Filter */
+		if (state->RF_IN >= 471000000 &&
+			(state->RF_IN - 471000000)%6000000 != 0) {
+
+			/* Turn off all the banks */
+			status += MXL_SetGPIO(fe, 3, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+
+			/* 2.6.12 Turn on RSSI */
+			status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+			status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+			status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
+			status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+			/* RSSI reference point */
+			status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5);
+			status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3);
+			status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2);
+
+			/* following parameter is from analog OTA mode,
+			 * can be change to seek better performance */
+			status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
+		} else {
+		/* if VHF or Cable =>  Turn on Tracking Filter */
+
+		/* 2.6.12 Turn off RSSI */
+		status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0);
+
+		/* change back from above condition */
+		status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5);
+
+
+		if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) {
+
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 0);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 0);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 0);
+		}
+		if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) {
+			status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+			status += MXL_SetGPIO(fe, 4, 1);
+			status += MXL_SetGPIO(fe, 1, 1);
+			status += MXL_SetGPIO(fe, 3, 1);
+		}
+		}
+	}
+	return status ;
+}
+
+static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val)
+{
+	u16 status = 0;
+
+	if (GPIO_Num == 1)
+		status += MXL_ControlWrite(fe, GPIO_1B, GPIO_Val ? 0 : 1);
+
+	/* GPIO2 is not available */
+
+	if (GPIO_Num == 3) {
+		if (GPIO_Val == 1) {
+			status += MXL_ControlWrite(fe, GPIO_3, 0);
+			status += MXL_ControlWrite(fe, GPIO_3B, 0);
+		}
+		if (GPIO_Val == 0) {
+			status += MXL_ControlWrite(fe, GPIO_3, 1);
+			status += MXL_ControlWrite(fe, GPIO_3B, 1);
+		}
+		if (GPIO_Val == 3) { /* tri-state */
+			status += MXL_ControlWrite(fe, GPIO_3, 0);
+			status += MXL_ControlWrite(fe, GPIO_3B, 1);
+		}
+	}
+	if (GPIO_Num == 4) {
+		if (GPIO_Val == 1) {
+			status += MXL_ControlWrite(fe, GPIO_4, 0);
+			status += MXL_ControlWrite(fe, GPIO_4B, 0);
+		}
+		if (GPIO_Val == 0) {
+			status += MXL_ControlWrite(fe, GPIO_4, 1);
+			status += MXL_ControlWrite(fe, GPIO_4B, 1);
+		}
+		if (GPIO_Val == 3) { /* tri-state */
+			status += MXL_ControlWrite(fe, GPIO_4, 0);
+			status += MXL_ControlWrite(fe, GPIO_4B, 1);
+		}
+	}
+
+	return status;
+}
+
+static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value)
+{
+	u16 status = 0;
+
+	/* Will write ALL Matching Control Name */
+	/* Write Matching INIT Control */
+	status += MXL_ControlWrite_Group(fe, ControlNum, value, 1);
+	/* Write Matching CH Control */
+	status += MXL_ControlWrite_Group(fe, ControlNum, value, 2);
+#ifdef _MXL_INTERNAL
+	/* Write Matching MXL Control */
+	status += MXL_ControlWrite_Group(fe, ControlNum, value, 3);
+#endif
+	return status;
+}
+
+static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum,
+	u32 value, u16 controlGroup)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u16 i, j, k;
+	u32 highLimit;
+	u32 ctrlVal;
+
+	if (controlGroup == 1) /* Initial Control */ {
+
+		for (i = 0; i < state->Init_Ctrl_Num; i++) {
+
+			if (controlNum == state->Init_Ctrl[i].Ctrl_Num) {
+
+				highLimit = 1 << state->Init_Ctrl[i].size;
+				if (value < highLimit) {
+					for (j = 0; j < state->Init_Ctrl[i].size; j++) {
+						state->Init_Ctrl[i].val[j] = (u8)((value >> j) & 0x01);
+						MXL_RegWriteBit(fe, (u8)(state->Init_Ctrl[i].addr[j]),
+							(u8)(state->Init_Ctrl[i].bit[j]),
+							(u8)((value>>j) & 0x01));
+					}
+					ctrlVal = 0;
+					for (k = 0; k < state->Init_Ctrl[i].size; k++)
+						ctrlVal += state->Init_Ctrl[i].val[k] * (1 << k);
+				} else
+					return -1;
+			}
+		}
+	}
+	if (controlGroup == 2) /* Chan change Control */ {
+
+		for (i = 0; i < state->CH_Ctrl_Num; i++) {
+
+			if (controlNum == state->CH_Ctrl[i].Ctrl_Num) {
+
+				highLimit = 1 << state->CH_Ctrl[i].size;
+				if (value < highLimit) {
+					for (j = 0; j < state->CH_Ctrl[i].size; j++) {
+						state->CH_Ctrl[i].val[j] = (u8)((value >> j) & 0x01);
+						MXL_RegWriteBit(fe, (u8)(state->CH_Ctrl[i].addr[j]),
+							(u8)(state->CH_Ctrl[i].bit[j]),
+							(u8)((value>>j) & 0x01));
+					}
+					ctrlVal = 0;
+					for (k = 0; k < state->CH_Ctrl[i].size; k++)
+						ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k);
+				} else
+					return -1;
+			}
+		}
+	}
+#ifdef _MXL_INTERNAL
+	if (controlGroup == 3) /* Maxlinear Control */ {
+
+		for (i = 0; i < state->MXL_Ctrl_Num; i++) {
+
+			if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) {
+
+				highLimit = (1 << state->MXL_Ctrl[i].size);
+				if (value < highLimit) {
+					for (j = 0; j < state->MXL_Ctrl[i].size; j++) {
+						state->MXL_Ctrl[i].val[j] = (u8)((value >> j) & 0x01);
+						MXL_RegWriteBit(fe, (u8)(state->MXL_Ctrl[i].addr[j]),
+							(u8)(state->MXL_Ctrl[i].bit[j]),
+							(u8)((value>>j) & 0x01));
+					}
+					ctrlVal = 0;
+					for (k = 0; k < state->MXL_Ctrl[i].size; k++)
+						ctrlVal += state->
+							MXL_Ctrl[i].val[k] *
+							(1 << k);
+				} else
+					return -1;
+			}
+		}
+	}
+#endif
+	return 0 ; /* successful return */
+}
+
+static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	int i ;
+
+	for (i = 0; i < 104; i++) {
+		if (RegNum == state->TunerRegs[i].Reg_Num) {
+			*RegVal = (u8)(state->TunerRegs[i].Reg_Val);
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u32 ctrlVal ;
+	u16 i, k ;
+
+	for (i = 0; i < state->Init_Ctrl_Num ; i++) {
+
+		if (controlNum == state->Init_Ctrl[i].Ctrl_Num) {
+
+			ctrlVal = 0;
+			for (k = 0; k < state->Init_Ctrl[i].size; k++)
+				ctrlVal += state->Init_Ctrl[i].val[k] * (1<<k);
+			*value = ctrlVal;
+			return 0;
+		}
+	}
+
+	for (i = 0; i < state->CH_Ctrl_Num ; i++) {
+
+		if (controlNum == state->CH_Ctrl[i].Ctrl_Num) {
+
+			ctrlVal = 0;
+			for (k = 0; k < state->CH_Ctrl[i].size; k++)
+				ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k);
+			*value = ctrlVal;
+			return 0;
+
+		}
+	}
+
+#ifdef _MXL_INTERNAL
+	for (i = 0; i < state->MXL_Ctrl_Num ; i++) {
+
+		if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) {
+
+			ctrlVal = 0;
+			for (k = 0; k < state->MXL_Ctrl[i].size; k++)
+				ctrlVal += state->MXL_Ctrl[i].val[k] * (1<<k);
+			*value = ctrlVal;
+			return 0;
+
+		}
+	}
+#endif
+	return 1;
+}
+
+static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit,
+	u8 bitVal)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	int i ;
+
+	const u8 AND_MAP[8] = {
+		0xFE, 0xFD, 0xFB, 0xF7,
+		0xEF, 0xDF, 0xBF, 0x7F } ;
+
+	const u8 OR_MAP[8] = {
+		0x01, 0x02, 0x04, 0x08,
+		0x10, 0x20, 0x40, 0x80 } ;
+
+	for (i = 0; i < state->TunerRegs_Num; i++) {
+		if (state->TunerRegs[i].Reg_Num == address) {
+			if (bitVal)
+				state->TunerRegs[i].Reg_Val |= OR_MAP[bit];
+			else
+				state->TunerRegs[i].Reg_Val &= AND_MAP[bit];
+			break ;
+		}
+	}
+}
+
+static u32 MXL_Ceiling(u32 value, u32 resolution)
+{
+	return value / resolution + (value % resolution > 0 ? 1 : 0);
+}
+
+/* Retrieve the Initialzation Registers */
+static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum,
+	u8 *RegVal, int *count)
+{
+	u16 status = 0;
+	int i ;
+
+	u8 RegAddr[] = {
+		11, 12, 13, 22, 32, 43, 44, 53, 56, 59, 73,
+		76, 77, 91, 134, 135, 137, 147,
+		156, 166, 167, 168, 25 };
+
+	*count = ARRAY_SIZE(RegAddr);
+
+	status += MXL_BlockInit(fe);
+
+	for (i = 0 ; i < *count; i++) {
+		RegNum[i] = RegAddr[i];
+		status += MXL_RegRead(fe, RegNum[i], &RegVal[i]);
+	}
+
+	return status;
+}
+
+static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal,
+	int *count)
+{
+	u16 status = 0;
+	int i ;
+
+/* add 77, 166, 167, 168 register for 2.6.12 */
+#ifdef _MXL_PRODUCTION
+	u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 65, 68, 69, 70, 73, 92, 93, 106,
+	   107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ;
+#else
+	u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 68, 69, 70, 73, 92, 93, 106,
+	   107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ;
+	/*
+	u8 RegAddr[171];
+	for (i = 0; i <= 170; i++)
+		RegAddr[i] = i;
+	*/
+#endif
+
+	*count = ARRAY_SIZE(RegAddr);
+
+	for (i = 0 ; i < *count; i++) {
+		RegNum[i] = RegAddr[i];
+		status += MXL_RegRead(fe, RegNum[i], &RegVal[i]);
+	}
+
+	return status;
+}
+
+static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum,
+	u8 *RegVal, int *count)
+{
+	u16 status = 0;
+	int i;
+
+	u8 RegAddr[] = {43, 136};
+
+	*count = ARRAY_SIZE(RegAddr);
+
+	for (i = 0; i < *count; i++) {
+		RegNum[i] = RegAddr[i];
+		status += MXL_RegRead(fe, RegNum[i], &RegVal[i]);
+	}
+
+	return status;
+}
+
+static u16 MXL_GetMasterControl(u8 *MasterReg, int state)
+{
+	if (state == 1) /* Load_Start */
+		*MasterReg = 0xF3;
+	if (state == 2) /* Power_Down */
+		*MasterReg = 0x41;
+	if (state == 3) /* Synth_Reset */
+		*MasterReg = 0xB1;
+	if (state == 4) /* Seq_Off */
+		*MasterReg = 0xF1;
+
+	return 0;
+}
+
+#ifdef _MXL_PRODUCTION
+static u16 MXL_VCORange_Test(struct dvb_frontend *fe, int VCO_Range)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u16 status = 0 ;
+
+	if (VCO_Range == 1) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1);
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+		status += MXL_ControlWrite(fe, RFSYN_DIVM, 1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
+		if (state->Mode == 0 && state->IF_Mode == 1) {
+			/* Analog Low IF Mode */
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 180224);
+		}
+		if (state->Mode == 0 && state->IF_Mode == 0) {
+			/* Analog Zero IF Mode */
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 222822);
+		}
+		if (state->Mode == 1) /* Digital Mode */ {
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 229376);
+		}
+	}
+
+	if (VCO_Range == 2) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1);
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+		status += MXL_ControlWrite(fe, RFSYN_DIVM, 1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+		status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+		status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41);
+		if (state->Mode == 0 && state->IF_Mode == 1) {
+			/* Analog Low IF Mode */
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 206438);
+		}
+		if (state->Mode == 0 && state->IF_Mode == 0) {
+			/* Analog Zero IF Mode */
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 206438);
+		}
+		if (state->Mode == 1) /* Digital Mode */ {
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 16384);
+		}
+	}
+
+	if (VCO_Range == 3) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1);
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+		status += MXL_ControlWrite(fe, RFSYN_DIVM, 1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+		status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+		status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42);
+		if (state->Mode == 0 && state->IF_Mode == 1) {
+			/* Analog Low IF Mode */
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 173670);
+		}
+		if (state->Mode == 0 && state->IF_Mode == 0) {
+			/* Analog Zero IF Mode */
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 173670);
+		}
+		if (state->Mode == 1) /* Digital Mode */ {
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 245760);
+		}
+	}
+
+	if (VCO_Range == 4) {
+		status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1);
+		status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+		status += MXL_ControlWrite(fe, RFSYN_DIVM, 1);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+		status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+		status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
+		status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+		status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+		status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27);
+		if (state->Mode == 0 && state->IF_Mode == 1) {
+			/* Analog Low IF Mode */
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 206438);
+		}
+		if (state->Mode == 0 && state->IF_Mode == 0) {
+			/* Analog Zero IF Mode */
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 206438);
+		}
+		if (state->Mode == 1) /* Digital Mode */ {
+			status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+			status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+			status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27);
+			status += MXL_ControlWrite(fe,
+				CHCAL_FRAC_MOD_RF, 212992);
+		}
+	}
+
+	return status;
+}
+
+static u16 MXL_Hystersis_Test(struct dvb_frontend *fe, int Hystersis)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u16 status = 0;
+
+	if (Hystersis == 1)
+		status += MXL_ControlWrite(fe, DN_BYPASS_AGC_I2C, 1);
+
+	return status;
+}
+#endif
+/* End: Reference driver code found in the Realtek driver that
+ * is copyright MaxLinear */
+
+/* ----------------------------------------------------------------
+ * Begin: Everything after here is new code to adapt the
+ * proprietary Realtek driver into a Linux API tuner.
+ * Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+ */
+static int mxl5005s_reset(struct dvb_frontend *fe)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	int ret = 0;
+
+	u8 buf[2] = { 0xff, 0x00 };
+	struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0,
+			       .buf = buf, .len = 2 };
+
+	dprintk(2, "%s()\n", __func__);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "mxl5005s I2C reset failed\n");
+		ret = -EREMOTEIO;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return ret;
+}
+
+/* Write a single byte to a single reg, latch the value if required by
+ * following the transaction with the latch byte.
+ */
+static int mxl5005s_writereg(struct dvb_frontend *fe, u8 reg, u8 val, int latch)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	u8 buf[3] = { reg, val, MXL5005S_LATCH_BYTE };
+	struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0,
+			       .buf = buf, .len = 3 };
+
+	if (latch == 0)
+		msg.len = 2;
+
+	dprintk(2, "%s(0x%x, 0x%x, 0x%x)\n", __func__, reg, val, msg.addr);
+
+	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "mxl5005s I2C write failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable,
+	u8 *datatable, u8 len)
+{
+	int ret = 0, i;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	for (i = 0 ; i < len-1; i++) {
+		ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 0);
+		if (ret < 0)
+			break;
+	}
+
+	ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 1);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return ret;
+}
+
+static int mxl5005s_init(struct dvb_frontend *fe)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+
+	dprintk(1, "%s()\n", __func__);
+	state->current_mode = MXL_QAM;
+	return mxl5005s_reconfigure(fe, MXL_QAM, MXL5005S_BANDWIDTH_6MHZ);
+}
+
+static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type,
+	u32 bandwidth)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+
+	u8 AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
+	u8 ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
+	int TableLen;
+
+	dprintk(1, "%s(type=%d, bw=%d)\n", __func__, mod_type, bandwidth);
+
+	mxl5005s_reset(fe);
+
+	/* Tuner initialization stage 0 */
+	MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET);
+	AddrTable[0] = MASTER_CONTROL_ADDR;
+	ByteTable[0] |= state->config->AgcMasterByte;
+
+	mxl5005s_writeregs(fe, AddrTable, ByteTable, 1);
+
+	mxl5005s_AssignTunerMode(fe, mod_type, bandwidth);
+
+	/* Tuner initialization stage 1 */
+	MXL_GetInitRegister(fe, AddrTable, ByteTable, &TableLen);
+
+	mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen);
+
+	return 0;
+}
+
+static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type,
+	u32 bandwidth)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	struct mxl5005s_config *c = state->config;
+
+	InitTunerControls(fe);
+
+	/* Set MxL5005S parameters. */
+	MXL5005_TunerConfig(
+		fe,
+		c->mod_mode,
+		c->if_mode,
+		bandwidth,
+		c->if_freq,
+		c->xtal_freq,
+		c->agc_mode,
+		c->top,
+		c->output_load,
+		c->clock_out,
+		c->div_out,
+		c->cap_select,
+		c->rssi_enable,
+		mod_type,
+		c->tracking_filter);
+
+	return 0;
+}
+
+static int mxl5005s_set_params(struct dvb_frontend *fe)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 delsys = c->delivery_system;
+	u32 bw = c->bandwidth_hz;
+	u32 req_mode, req_bw = 0;
+	int ret;
+
+	dprintk(1, "%s()\n", __func__);
+
+	switch (delsys) {
+	case SYS_ATSC:
+		req_mode = MXL_ATSC;
+		req_bw  = MXL5005S_BANDWIDTH_6MHZ;
+		break;
+	case SYS_DVBC_ANNEX_B:
+		req_mode = MXL_QAM;
+		req_bw  = MXL5005S_BANDWIDTH_6MHZ;
+		break;
+	default:	/* Assume DVB-T */
+		req_mode = MXL_DVBT;
+		switch (bw) {
+		case 6000000:
+			req_bw = MXL5005S_BANDWIDTH_6MHZ;
+			break;
+		case 7000000:
+			req_bw = MXL5005S_BANDWIDTH_7MHZ;
+			break;
+		case 8000000:
+		case 0:
+			req_bw = MXL5005S_BANDWIDTH_8MHZ;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	/* Change tuner for new modulation type if reqd */
+	if (req_mode != state->current_mode ||
+	    req_bw != state->Chan_Bandwidth) {
+		state->current_mode = req_mode;
+		ret = mxl5005s_reconfigure(fe, req_mode, req_bw);
+
+	} else
+		ret = 0;
+
+	if (ret == 0) {
+		dprintk(1, "%s() freq=%d\n", __func__, c->frequency);
+		ret = mxl5005s_SetRfFreqHz(fe, c->frequency);
+	}
+
+	return ret;
+}
+
+static int mxl5005s_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	dprintk(1, "%s()\n", __func__);
+
+	*frequency = state->RF_IN;
+
+	return 0;
+}
+
+static int mxl5005s_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct mxl5005s_state *state = fe->tuner_priv;
+	dprintk(1, "%s()\n", __func__);
+
+	*bandwidth = state->Chan_Bandwidth;
+
+	return 0;
+}
+
+static int mxl5005s_release(struct dvb_frontend *fe)
+{
+	dprintk(1, "%s()\n", __func__);
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static const struct dvb_tuner_ops mxl5005s_tuner_ops = {
+	.info = {
+		.name           = "MaxLinear MXL5005S",
+		.frequency_min  =  48000000,
+		.frequency_max  = 860000000,
+		.frequency_step =     50000,
+	},
+
+	.release       = mxl5005s_release,
+	.init          = mxl5005s_init,
+
+	.set_params    = mxl5005s_set_params,
+	.get_frequency = mxl5005s_get_frequency,
+	.get_bandwidth = mxl5005s_get_bandwidth,
+};
+
+struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
+				     struct i2c_adapter *i2c,
+				     struct mxl5005s_config *config)
+{
+	struct mxl5005s_state *state = NULL;
+	dprintk(1, "%s()\n", __func__);
+
+	state = kzalloc(sizeof(struct mxl5005s_state), GFP_KERNEL);
+	if (state == NULL)
+		return NULL;
+
+	state->frontend = fe;
+	state->config = config;
+	state->i2c = i2c;
+
+	printk(KERN_INFO "MXL5005S: Attached at address 0x%02x\n",
+		config->i2c_address);
+
+	memcpy(&fe->ops.tuner_ops, &mxl5005s_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = state;
+	return fe;
+}
+EXPORT_SYMBOL(mxl5005s_attach);
+
+MODULE_DESCRIPTION("MaxLinear MXL5005S silicon tuner driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/mxl5005s.h b/drivers/media/tuners/mxl5005s.h
new file mode 100644
index 0000000..fc8a1ff
--- /dev/null
+++ b/drivers/media/tuners/mxl5005s.h
@@ -0,0 +1,135 @@
+/*
+    MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
+
+    Copyright (C) 2008 MaxLinear
+    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __MXL5005S_H
+#define __MXL5005S_H
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+struct mxl5005s_config {
+
+	/* 7 bit i2c address */
+	u8 i2c_address;
+
+#define IF_FREQ_4570000HZ    4570000
+#define IF_FREQ_4571429HZ    4571429
+#define IF_FREQ_5380000HZ    5380000
+#define IF_FREQ_36000000HZ  36000000
+#define IF_FREQ_36125000HZ  36125000
+#define IF_FREQ_36166667HZ  36166667
+#define IF_FREQ_44000000HZ  44000000
+	u32 if_freq;
+
+#define CRYSTAL_FREQ_4000000HZ    4000000
+#define CRYSTAL_FREQ_16000000HZ  16000000
+#define CRYSTAL_FREQ_25000000HZ  25000000
+#define CRYSTAL_FREQ_28800000HZ  28800000
+	u32 xtal_freq;
+
+#define MXL_DUAL_AGC   0
+#define MXL_SINGLE_AGC 1
+	u8 agc_mode;
+
+#define MXL_TF_DEFAULT	0
+#define MXL_TF_OFF	1
+#define MXL_TF_C	2
+#define MXL_TF_C_H	3
+#define MXL_TF_D	4
+#define MXL_TF_D_L	5
+#define MXL_TF_E	6
+#define MXL_TF_F	7
+#define MXL_TF_E_2	8
+#define MXL_TF_E_NA	9
+#define MXL_TF_G	10
+	u8 tracking_filter;
+
+#define MXL_RSSI_DISABLE	0
+#define MXL_RSSI_ENABLE		1
+	u8 rssi_enable;
+
+#define MXL_CAP_SEL_DISABLE	0
+#define MXL_CAP_SEL_ENABLE	1
+	u8 cap_select;
+
+#define MXL_DIV_OUT_1	0
+#define MXL_DIV_OUT_4	1
+	u8 div_out;
+
+#define MXL_CLOCK_OUT_DISABLE	0
+#define MXL_CLOCK_OUT_ENABLE	1
+	u8 clock_out;
+
+#define MXL5005S_IF_OUTPUT_LOAD_200_OHM 200
+#define MXL5005S_IF_OUTPUT_LOAD_300_OHM 300
+	u32 output_load;
+
+#define MXL5005S_TOP_5P5   55
+#define MXL5005S_TOP_7P2   72
+#define MXL5005S_TOP_9P2   92
+#define MXL5005S_TOP_11P0 110
+#define MXL5005S_TOP_12P9 129
+#define MXL5005S_TOP_14P7 147
+#define MXL5005S_TOP_16P8 168
+#define MXL5005S_TOP_19P4 194
+#define MXL5005S_TOP_21P2 212
+#define MXL5005S_TOP_23P2 232
+#define MXL5005S_TOP_25P2 252
+#define MXL5005S_TOP_27P1 271
+#define MXL5005S_TOP_29P2 292
+#define MXL5005S_TOP_31P7 317
+#define MXL5005S_TOP_34P9 349
+	u32 top;
+
+#define MXL_ANALOG_MODE  0
+#define MXL_DIGITAL_MODE 1
+	u8 mod_mode;
+
+#define MXL_ZERO_IF 0
+#define MXL_LOW_IF  1
+	u8 if_mode;
+
+	/* Some boards need to override the built-in logic for determining
+	   the gain when in QAM mode (the HVR-1600 is one such case) */
+	u8 qam_gain;
+
+	/* Stuff I don't know what to do with */
+	u8 AgcMasterByte;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_MXL5005S) || \
+	(defined(CONFIG_MEDIA_TUNER_MXL5005S_MODULE) && defined(MODULE))
+extern struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
+					    struct i2c_adapter *i2c,
+					    struct mxl5005s_config *config);
+#else
+static inline struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
+					    struct i2c_adapter *i2c,
+					    struct mxl5005s_config *config)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_TUNER_MXL5005S */
+
+#endif /* __MXL5005S_H */
+
diff --git a/drivers/media/tuners/mxl5007t.c b/drivers/media/tuners/mxl5007t.c
new file mode 100644
index 0000000..69e453e
--- /dev/null
+++ b/drivers/media/tuners/mxl5007t.c
@@ -0,0 +1,928 @@
+/*
+ *  mxl5007t.c - driver for the MaxLinear MxL5007T silicon tuner
+ *
+ *  Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include "tuner-i2c.h"
+#include "mxl5007t.h"
+
+static DEFINE_MUTEX(mxl5007t_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
+static int mxl5007t_debug;
+module_param_named(debug, mxl5007t_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level");
+
+/* ------------------------------------------------------------------------- */
+
+#define mxl_printk(kern, fmt, arg...) \
+	printk(kern "%s: " fmt "\n", __func__, ##arg)
+
+#define mxl_err(fmt, arg...) \
+	mxl_printk(KERN_ERR, "%d: " fmt, __LINE__, ##arg)
+
+#define mxl_warn(fmt, arg...) \
+	mxl_printk(KERN_WARNING, fmt, ##arg)
+
+#define mxl_info(fmt, arg...) \
+	mxl_printk(KERN_INFO, fmt, ##arg)
+
+#define mxl_debug(fmt, arg...)				\
+({							\
+	if (mxl5007t_debug)				\
+		mxl_printk(KERN_DEBUG, fmt, ##arg);	\
+})
+
+#define mxl_fail(ret)							\
+({									\
+	int __ret;							\
+	__ret = (ret < 0);						\
+	if (__ret)							\
+		mxl_printk(KERN_ERR, "error %d on line %d",		\
+			   ret, __LINE__);				\
+	__ret;								\
+})
+
+/* ------------------------------------------------------------------------- */
+
+#define MHz 1000000
+
+enum mxl5007t_mode {
+	MxL_MODE_ISDBT     =    0,
+	MxL_MODE_DVBT      =    1,
+	MxL_MODE_ATSC      =    2,
+	MxL_MODE_CABLE     = 0x10,
+};
+
+enum mxl5007t_chip_version {
+	MxL_UNKNOWN_ID     = 0x00,
+	MxL_5007_V1_F1     = 0x11,
+	MxL_5007_V1_F2     = 0x12,
+	MxL_5007_V4        = 0x14,
+	MxL_5007_V2_100_F1 = 0x21,
+	MxL_5007_V2_100_F2 = 0x22,
+	MxL_5007_V2_200_F1 = 0x23,
+	MxL_5007_V2_200_F2 = 0x24,
+};
+
+struct reg_pair_t {
+	u8 reg;
+	u8 val;
+};
+
+/* ------------------------------------------------------------------------- */
+
+static struct reg_pair_t init_tab[] = {
+	{ 0x02, 0x06 },
+	{ 0x03, 0x48 },
+	{ 0x05, 0x04 },
+	{ 0x06, 0x10 },
+	{ 0x2e, 0x15 }, /* OVERRIDE */
+	{ 0x30, 0x10 }, /* OVERRIDE */
+	{ 0x45, 0x58 }, /* OVERRIDE */
+	{ 0x48, 0x19 }, /* OVERRIDE */
+	{ 0x52, 0x03 }, /* OVERRIDE */
+	{ 0x53, 0x44 }, /* OVERRIDE */
+	{ 0x6a, 0x4b }, /* OVERRIDE */
+	{ 0x76, 0x00 }, /* OVERRIDE */
+	{ 0x78, 0x18 }, /* OVERRIDE */
+	{ 0x7a, 0x17 }, /* OVERRIDE */
+	{ 0x85, 0x06 }, /* OVERRIDE */
+	{ 0x01, 0x01 }, /* TOP_MASTER_ENABLE */
+	{ 0, 0 }
+};
+
+static struct reg_pair_t init_tab_cable[] = {
+	{ 0x02, 0x06 },
+	{ 0x03, 0x48 },
+	{ 0x05, 0x04 },
+	{ 0x06, 0x10 },
+	{ 0x09, 0x3f },
+	{ 0x0a, 0x3f },
+	{ 0x0b, 0x3f },
+	{ 0x2e, 0x15 }, /* OVERRIDE */
+	{ 0x30, 0x10 }, /* OVERRIDE */
+	{ 0x45, 0x58 }, /* OVERRIDE */
+	{ 0x48, 0x19 }, /* OVERRIDE */
+	{ 0x52, 0x03 }, /* OVERRIDE */
+	{ 0x53, 0x44 }, /* OVERRIDE */
+	{ 0x6a, 0x4b }, /* OVERRIDE */
+	{ 0x76, 0x00 }, /* OVERRIDE */
+	{ 0x78, 0x18 }, /* OVERRIDE */
+	{ 0x7a, 0x17 }, /* OVERRIDE */
+	{ 0x85, 0x06 }, /* OVERRIDE */
+	{ 0x01, 0x01 }, /* TOP_MASTER_ENABLE */
+	{ 0, 0 }
+};
+
+/* ------------------------------------------------------------------------- */
+
+static struct reg_pair_t reg_pair_rftune[] = {
+	{ 0x0f, 0x00 }, /* abort tune */
+	{ 0x0c, 0x15 },
+	{ 0x0d, 0x40 },
+	{ 0x0e, 0x0e },
+	{ 0x1f, 0x87 }, /* OVERRIDE */
+	{ 0x20, 0x1f }, /* OVERRIDE */
+	{ 0x21, 0x87 }, /* OVERRIDE */
+	{ 0x22, 0x1f }, /* OVERRIDE */
+	{ 0x80, 0x01 }, /* freq dependent */
+	{ 0x0f, 0x01 }, /* start tune */
+	{ 0, 0 }
+};
+
+/* ------------------------------------------------------------------------- */
+
+struct mxl5007t_state {
+	struct list_head hybrid_tuner_instance_list;
+	struct tuner_i2c_props i2c_props;
+
+	struct mutex lock;
+
+	struct mxl5007t_config *config;
+
+	enum mxl5007t_chip_version chip_id;
+
+	struct reg_pair_t tab_init[ARRAY_SIZE(init_tab)];
+	struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)];
+	struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)];
+
+	enum mxl5007t_if_freq if_freq;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* called by _init and _rftun to manipulate the register arrays */
+
+static void set_reg_bits(struct reg_pair_t *reg_pair, u8 reg, u8 mask, u8 val)
+{
+	unsigned int i = 0;
+
+	while (reg_pair[i].reg || reg_pair[i].val) {
+		if (reg_pair[i].reg == reg) {
+			reg_pair[i].val &= ~mask;
+			reg_pair[i].val |= val;
+		}
+		i++;
+
+	}
+	return;
+}
+
+static void copy_reg_bits(struct reg_pair_t *reg_pair1,
+			  struct reg_pair_t *reg_pair2)
+{
+	unsigned int i, j;
+
+	i = j = 0;
+
+	while (reg_pair1[i].reg || reg_pair1[i].val) {
+		while (reg_pair2[j].reg || reg_pair2[j].val) {
+			if (reg_pair1[i].reg != reg_pair2[j].reg) {
+				j++;
+				continue;
+			}
+			reg_pair2[j].val = reg_pair1[i].val;
+			break;
+		}
+		i++;
+	}
+	return;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void mxl5007t_set_mode_bits(struct mxl5007t_state *state,
+				   enum mxl5007t_mode mode,
+				   s32 if_diff_out_level)
+{
+	switch (mode) {
+	case MxL_MODE_ATSC:
+		set_reg_bits(state->tab_init, 0x06, 0x1f, 0x12);
+		break;
+	case MxL_MODE_DVBT:
+		set_reg_bits(state->tab_init, 0x06, 0x1f, 0x11);
+		break;
+	case MxL_MODE_ISDBT:
+		set_reg_bits(state->tab_init, 0x06, 0x1f, 0x10);
+		break;
+	case MxL_MODE_CABLE:
+		set_reg_bits(state->tab_init_cable, 0x09, 0xff, 0xc1);
+		set_reg_bits(state->tab_init_cable, 0x0a, 0xff,
+			     8 - if_diff_out_level);
+		set_reg_bits(state->tab_init_cable, 0x0b, 0xff, 0x17);
+		break;
+	default:
+		mxl_fail(-EINVAL);
+	}
+	return;
+}
+
+static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state,
+				      enum mxl5007t_if_freq if_freq,
+				      int invert_if)
+{
+	u8 val;
+
+	switch (if_freq) {
+	case MxL_IF_4_MHZ:
+		val = 0x00;
+		break;
+	case MxL_IF_4_5_MHZ:
+		val = 0x02;
+		break;
+	case MxL_IF_4_57_MHZ:
+		val = 0x03;
+		break;
+	case MxL_IF_5_MHZ:
+		val = 0x04;
+		break;
+	case MxL_IF_5_38_MHZ:
+		val = 0x05;
+		break;
+	case MxL_IF_6_MHZ:
+		val = 0x06;
+		break;
+	case MxL_IF_6_28_MHZ:
+		val = 0x07;
+		break;
+	case MxL_IF_9_1915_MHZ:
+		val = 0x08;
+		break;
+	case MxL_IF_35_25_MHZ:
+		val = 0x09;
+		break;
+	case MxL_IF_36_15_MHZ:
+		val = 0x0a;
+		break;
+	case MxL_IF_44_MHZ:
+		val = 0x0b;
+		break;
+	default:
+		mxl_fail(-EINVAL);
+		return;
+	}
+	set_reg_bits(state->tab_init, 0x02, 0x0f, val);
+
+	/* set inverted IF or normal IF */
+	set_reg_bits(state->tab_init, 0x02, 0x10, invert_if ? 0x10 : 0x00);
+
+	state->if_freq = if_freq;
+
+	return;
+}
+
+static void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state,
+					enum mxl5007t_xtal_freq xtal_freq)
+{
+	switch (xtal_freq) {
+	case MxL_XTAL_16_MHZ:
+		/* select xtal freq & ref freq */
+		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x00);
+		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x00);
+		break;
+	case MxL_XTAL_20_MHZ:
+		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x10);
+		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x01);
+		break;
+	case MxL_XTAL_20_25_MHZ:
+		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x20);
+		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x02);
+		break;
+	case MxL_XTAL_20_48_MHZ:
+		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x30);
+		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x03);
+		break;
+	case MxL_XTAL_24_MHZ:
+		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x40);
+		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x04);
+		break;
+	case MxL_XTAL_25_MHZ:
+		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x50);
+		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x05);
+		break;
+	case MxL_XTAL_25_14_MHZ:
+		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x60);
+		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x06);
+		break;
+	case MxL_XTAL_27_MHZ:
+		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x70);
+		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x07);
+		break;
+	case MxL_XTAL_28_8_MHZ:
+		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x80);
+		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x08);
+		break;
+	case MxL_XTAL_32_MHZ:
+		set_reg_bits(state->tab_init, 0x03, 0xf0, 0x90);
+		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x09);
+		break;
+	case MxL_XTAL_40_MHZ:
+		set_reg_bits(state->tab_init, 0x03, 0xf0, 0xa0);
+		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0a);
+		break;
+	case MxL_XTAL_44_MHZ:
+		set_reg_bits(state->tab_init, 0x03, 0xf0, 0xb0);
+		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0b);
+		break;
+	case MxL_XTAL_48_MHZ:
+		set_reg_bits(state->tab_init, 0x03, 0xf0, 0xc0);
+		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0c);
+		break;
+	case MxL_XTAL_49_3811_MHZ:
+		set_reg_bits(state->tab_init, 0x03, 0xf0, 0xd0);
+		set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0d);
+		break;
+	default:
+		mxl_fail(-EINVAL);
+		return;
+	}
+
+	return;
+}
+
+static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state,
+						  enum mxl5007t_mode mode)
+{
+	struct mxl5007t_config *cfg = state->config;
+
+	memcpy(&state->tab_init, &init_tab, sizeof(init_tab));
+	memcpy(&state->tab_init_cable, &init_tab_cable, sizeof(init_tab_cable));
+
+	mxl5007t_set_mode_bits(state, mode, cfg->if_diff_out_level);
+	mxl5007t_set_if_freq_bits(state, cfg->if_freq_hz, cfg->invert_if);
+	mxl5007t_set_xtal_freq_bits(state, cfg->xtal_freq_hz);
+
+	set_reg_bits(state->tab_init, 0x04, 0x01, cfg->loop_thru_enable);
+	set_reg_bits(state->tab_init, 0x03, 0x08, cfg->clk_out_enable << 3);
+	set_reg_bits(state->tab_init, 0x03, 0x07, cfg->clk_out_amp);
+
+	if (mode >= MxL_MODE_CABLE) {
+		copy_reg_bits(state->tab_init, state->tab_init_cable);
+		return state->tab_init_cable;
+	} else
+		return state->tab_init;
+}
+
+/* ------------------------------------------------------------------------- */
+
+enum mxl5007t_bw_mhz {
+	MxL_BW_6MHz = 6,
+	MxL_BW_7MHz = 7,
+	MxL_BW_8MHz = 8,
+};
+
+static void mxl5007t_set_bw_bits(struct mxl5007t_state *state,
+				 enum mxl5007t_bw_mhz bw)
+{
+	u8 val;
+
+	switch (bw) {
+	case MxL_BW_6MHz:
+		val = 0x15; /* set DIG_MODEINDEX, DIG_MODEINDEX_A,
+			     * and DIG_MODEINDEX_CSF */
+		break;
+	case MxL_BW_7MHz:
+		val = 0x2a;
+		break;
+	case MxL_BW_8MHz:
+		val = 0x3f;
+		break;
+	default:
+		mxl_fail(-EINVAL);
+		return;
+	}
+	set_reg_bits(state->tab_rftune, 0x0c, 0x3f, val);
+
+	return;
+}
+
+static struct
+reg_pair_t *mxl5007t_calc_rf_tune_regs(struct mxl5007t_state *state,
+				       u32 rf_freq, enum mxl5007t_bw_mhz bw)
+{
+	u32 dig_rf_freq = 0;
+	u32 temp;
+	u32 frac_divider = 1000000;
+	unsigned int i;
+
+	memcpy(&state->tab_rftune, &reg_pair_rftune, sizeof(reg_pair_rftune));
+
+	mxl5007t_set_bw_bits(state, bw);
+
+	/* Convert RF frequency into 16 bits =>
+	 * 10 bit integer (MHz) + 6 bit fraction */
+	dig_rf_freq = rf_freq / MHz;
+
+	temp = rf_freq % MHz;
+
+	for (i = 0; i < 6; i++) {
+		dig_rf_freq <<= 1;
+		frac_divider /= 2;
+		if (temp > frac_divider) {
+			temp -= frac_divider;
+			dig_rf_freq++;
+		}
+	}
+
+	/* add to have shift center point by 7.8124 kHz */
+	if (temp > 7812)
+		dig_rf_freq++;
+
+	set_reg_bits(state->tab_rftune, 0x0d, 0xff, (u8) dig_rf_freq);
+	set_reg_bits(state->tab_rftune, 0x0e, 0xff, (u8) (dig_rf_freq >> 8));
+
+	if (rf_freq >= 333000000)
+		set_reg_bits(state->tab_rftune, 0x80, 0x40, 0x40);
+
+	return state->tab_rftune;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int mxl5007t_write_reg(struct mxl5007t_state *state, u8 reg, u8 val)
+{
+	u8 buf[] = { reg, val };
+	struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0,
+			       .buf = buf, .len = 2 };
+	int ret;
+
+	ret = i2c_transfer(state->i2c_props.adap, &msg, 1);
+	if (ret != 1) {
+		mxl_err("failed!");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int mxl5007t_write_regs(struct mxl5007t_state *state,
+			       struct reg_pair_t *reg_pair)
+{
+	unsigned int i = 0;
+	int ret = 0;
+
+	while ((ret == 0) && (reg_pair[i].reg || reg_pair[i].val)) {
+		ret = mxl5007t_write_reg(state,
+					 reg_pair[i].reg, reg_pair[i].val);
+		i++;
+	}
+	return ret;
+}
+
+static int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val)
+{
+	u8 buf[2] = { 0xfb, reg };
+	struct i2c_msg msg[] = {
+		{ .addr = state->i2c_props.addr, .flags = 0,
+		  .buf = buf, .len = 2 },
+		{ .addr = state->i2c_props.addr, .flags = I2C_M_RD,
+		  .buf = val, .len = 1 },
+	};
+	int ret;
+
+	ret = i2c_transfer(state->i2c_props.adap, msg, 2);
+	if (ret != 2) {
+		mxl_err("failed!");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int mxl5007t_soft_reset(struct mxl5007t_state *state)
+{
+	u8 d = 0xff;
+	struct i2c_msg msg = {
+		.addr = state->i2c_props.addr, .flags = 0,
+		.buf = &d, .len = 1
+	};
+	int ret = i2c_transfer(state->i2c_props.adap, &msg, 1);
+
+	if (ret != 1) {
+		mxl_err("failed!");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int mxl5007t_tuner_init(struct mxl5007t_state *state,
+			       enum mxl5007t_mode mode)
+{
+	struct reg_pair_t *init_regs;
+	int ret;
+
+	ret = mxl5007t_soft_reset(state);
+	if (mxl_fail(ret))
+		goto fail;
+
+	/* calculate initialization reg array */
+	init_regs = mxl5007t_calc_init_regs(state, mode);
+
+	ret = mxl5007t_write_regs(state, init_regs);
+	if (mxl_fail(ret))
+		goto fail;
+	mdelay(1);
+fail:
+	return ret;
+}
+
+static int mxl5007t_tuner_rf_tune(struct mxl5007t_state *state, u32 rf_freq_hz,
+				  enum mxl5007t_bw_mhz bw)
+{
+	struct reg_pair_t *rf_tune_regs;
+	int ret;
+
+	/* calculate channel change reg array */
+	rf_tune_regs = mxl5007t_calc_rf_tune_regs(state, rf_freq_hz, bw);
+
+	ret = mxl5007t_write_regs(state, rf_tune_regs);
+	if (mxl_fail(ret))
+		goto fail;
+	msleep(3);
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int mxl5007t_synth_lock_status(struct mxl5007t_state *state,
+				      int *rf_locked, int *ref_locked)
+{
+	u8 d;
+	int ret;
+
+	*rf_locked = 0;
+	*ref_locked = 0;
+
+	ret = mxl5007t_read_reg(state, 0xd8, &d);
+	if (mxl_fail(ret))
+		goto fail;
+
+	if ((d & 0x0c) == 0x0c)
+		*rf_locked = 1;
+
+	if ((d & 0x03) == 0x03)
+		*ref_locked = 1;
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct mxl5007t_state *state = fe->tuner_priv;
+	int rf_locked, ref_locked, ret;
+
+	*status = 0;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	ret = mxl5007t_synth_lock_status(state, &rf_locked, &ref_locked);
+	if (mxl_fail(ret))
+		goto fail;
+	mxl_debug("%s%s", rf_locked ? "rf locked " : "",
+		  ref_locked ? "ref locked" : "");
+
+	if ((rf_locked) || (ref_locked))
+		*status |= TUNER_STATUS_LOCKED;
+fail:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int mxl5007t_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 delsys = c->delivery_system;
+	struct mxl5007t_state *state = fe->tuner_priv;
+	enum mxl5007t_bw_mhz bw;
+	enum mxl5007t_mode mode;
+	int ret;
+	u32 freq = c->frequency;
+
+	switch (delsys) {
+	case SYS_ATSC:
+		mode = MxL_MODE_ATSC;
+		bw = MxL_BW_6MHz;
+		break;
+	case SYS_DVBC_ANNEX_B:
+		mode = MxL_MODE_CABLE;
+		bw = MxL_BW_6MHz;
+		break;
+	case SYS_DVBT:
+	case SYS_DVBT2:
+		mode = MxL_MODE_DVBT;
+		switch (c->bandwidth_hz) {
+		case 6000000:
+			bw = MxL_BW_6MHz;
+			break;
+		case 7000000:
+			bw = MxL_BW_7MHz;
+			break;
+		case 8000000:
+			bw = MxL_BW_8MHz;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		mxl_err("modulation type not supported!");
+		return -EINVAL;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	mutex_lock(&state->lock);
+
+	ret = mxl5007t_tuner_init(state, mode);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl5007t_tuner_rf_tune(state, freq, bw);
+	if (mxl_fail(ret))
+		goto fail;
+
+	state->frequency = freq;
+	state->bandwidth = c->bandwidth_hz;
+fail:
+	mutex_unlock(&state->lock);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int mxl5007t_init(struct dvb_frontend *fe)
+{
+	struct mxl5007t_state *state = fe->tuner_priv;
+	int ret;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	/* wake from standby */
+	ret = mxl5007t_write_reg(state, 0x01, 0x01);
+	mxl_fail(ret);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return ret;
+}
+
+static int mxl5007t_sleep(struct dvb_frontend *fe)
+{
+	struct mxl5007t_state *state = fe->tuner_priv;
+	int ret;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	/* enter standby mode */
+	ret = mxl5007t_write_reg(state, 0x01, 0x00);
+	mxl_fail(ret);
+	ret = mxl5007t_write_reg(state, 0x0f, 0x00);
+	mxl_fail(ret);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int mxl5007t_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct mxl5007t_state *state = fe->tuner_priv;
+	*frequency = state->frequency;
+	return 0;
+}
+
+static int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct mxl5007t_state *state = fe->tuner_priv;
+	*bandwidth = state->bandwidth;
+	return 0;
+}
+
+static int mxl5007t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct mxl5007t_state *state = fe->tuner_priv;
+
+	*frequency = 0;
+
+	switch (state->if_freq) {
+	case MxL_IF_4_MHZ:
+		*frequency = 4000000;
+		break;
+	case MxL_IF_4_5_MHZ:
+		*frequency = 4500000;
+		break;
+	case MxL_IF_4_57_MHZ:
+		*frequency = 4570000;
+		break;
+	case MxL_IF_5_MHZ:
+		*frequency = 5000000;
+		break;
+	case MxL_IF_5_38_MHZ:
+		*frequency = 5380000;
+		break;
+	case MxL_IF_6_MHZ:
+		*frequency = 6000000;
+		break;
+	case MxL_IF_6_28_MHZ:
+		*frequency = 6280000;
+		break;
+	case MxL_IF_9_1915_MHZ:
+		*frequency = 9191500;
+		break;
+	case MxL_IF_35_25_MHZ:
+		*frequency = 35250000;
+		break;
+	case MxL_IF_36_15_MHZ:
+		*frequency = 36150000;
+		break;
+	case MxL_IF_44_MHZ:
+		*frequency = 44000000;
+		break;
+	}
+	return 0;
+}
+
+static int mxl5007t_release(struct dvb_frontend *fe)
+{
+	struct mxl5007t_state *state = fe->tuner_priv;
+
+	mutex_lock(&mxl5007t_list_mutex);
+
+	if (state)
+		hybrid_tuner_release_state(state);
+
+	mutex_unlock(&mxl5007t_list_mutex);
+
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static struct dvb_tuner_ops mxl5007t_tuner_ops = {
+	.info = {
+		.name = "MaxLinear MxL5007T",
+	},
+	.init              = mxl5007t_init,
+	.sleep             = mxl5007t_sleep,
+	.set_params        = mxl5007t_set_params,
+	.get_status        = mxl5007t_get_status,
+	.get_frequency     = mxl5007t_get_frequency,
+	.get_bandwidth     = mxl5007t_get_bandwidth,
+	.release           = mxl5007t_release,
+	.get_if_frequency  = mxl5007t_get_if_frequency,
+};
+
+static int mxl5007t_get_chip_id(struct mxl5007t_state *state)
+{
+	char *name;
+	int ret;
+	u8 id;
+
+	ret = mxl5007t_read_reg(state, 0xd9, &id);
+	if (mxl_fail(ret))
+		goto fail;
+
+	switch (id) {
+	case MxL_5007_V1_F1:
+		name = "MxL5007.v1.f1";
+		break;
+	case MxL_5007_V1_F2:
+		name = "MxL5007.v1.f2";
+		break;
+	case MxL_5007_V2_100_F1:
+		name = "MxL5007.v2.100.f1";
+		break;
+	case MxL_5007_V2_100_F2:
+		name = "MxL5007.v2.100.f2";
+		break;
+	case MxL_5007_V2_200_F1:
+		name = "MxL5007.v2.200.f1";
+		break;
+	case MxL_5007_V2_200_F2:
+		name = "MxL5007.v2.200.f2";
+		break;
+	case MxL_5007_V4:
+		name = "MxL5007T.v4";
+		break;
+	default:
+		name = "MxL5007T";
+		printk(KERN_WARNING "%s: unknown rev (%02x)\n", __func__, id);
+		id = MxL_UNKNOWN_ID;
+	}
+	state->chip_id = id;
+	mxl_info("%s detected @ %d-%04x", name,
+		 i2c_adapter_id(state->i2c_props.adap),
+		 state->i2c_props.addr);
+	return 0;
+fail:
+	mxl_warn("unable to identify device @ %d-%04x",
+		 i2c_adapter_id(state->i2c_props.adap),
+		 state->i2c_props.addr);
+
+	state->chip_id = MxL_UNKNOWN_ID;
+	return ret;
+}
+
+struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
+				     struct i2c_adapter *i2c, u8 addr,
+				     struct mxl5007t_config *cfg)
+{
+	struct mxl5007t_state *state = NULL;
+	int instance, ret;
+
+	mutex_lock(&mxl5007t_list_mutex);
+	instance = hybrid_tuner_request_state(struct mxl5007t_state, state,
+					      hybrid_tuner_instance_list,
+					      i2c, addr, "mxl5007t");
+	switch (instance) {
+	case 0:
+		goto fail;
+	case 1:
+		/* new tuner instance */
+		state->config = cfg;
+
+		mutex_init(&state->lock);
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		ret = mxl5007t_get_chip_id(state);
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+
+		/* check return value of mxl5007t_get_chip_id */
+		if (mxl_fail(ret))
+			goto fail;
+		break;
+	default:
+		/* existing tuner instance */
+		break;
+	}
+	fe->tuner_priv = state;
+	mutex_unlock(&mxl5007t_list_mutex);
+
+	memcpy(&fe->ops.tuner_ops, &mxl5007t_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+	return fe;
+fail:
+	mutex_unlock(&mxl5007t_list_mutex);
+
+	mxl5007t_release(fe);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(mxl5007t_attach);
+MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.2");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/tuners/mxl5007t.h b/drivers/media/tuners/mxl5007t.h
new file mode 100644
index 0000000..aa3eea0
--- /dev/null
+++ b/drivers/media/tuners/mxl5007t.h
@@ -0,0 +1,104 @@
+/*
+ *  mxl5007t.h - driver for the MaxLinear MxL5007T silicon tuner
+ *
+ *  Copyright (C) 2008 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MXL5007T_H__
+#define __MXL5007T_H__
+
+#include "dvb_frontend.h"
+
+/* ------------------------------------------------------------------------- */
+
+enum mxl5007t_if_freq {
+	MxL_IF_4_MHZ,      /*  4000000 */
+	MxL_IF_4_5_MHZ,    /*  4500000 */
+	MxL_IF_4_57_MHZ,   /*  4570000 */
+	MxL_IF_5_MHZ,      /*  5000000 */
+	MxL_IF_5_38_MHZ,   /*  5380000 */
+	MxL_IF_6_MHZ,      /*  6000000 */
+	MxL_IF_6_28_MHZ,   /*  6280000 */
+	MxL_IF_9_1915_MHZ, /*  9191500 */
+	MxL_IF_35_25_MHZ,  /* 35250000 */
+	MxL_IF_36_15_MHZ,  /* 36150000 */
+	MxL_IF_44_MHZ,     /* 44000000 */
+};
+
+enum mxl5007t_xtal_freq {
+	MxL_XTAL_16_MHZ,      /* 16000000 */
+	MxL_XTAL_20_MHZ,      /* 20000000 */
+	MxL_XTAL_20_25_MHZ,   /* 20250000 */
+	MxL_XTAL_20_48_MHZ,   /* 20480000 */
+	MxL_XTAL_24_MHZ,      /* 24000000 */
+	MxL_XTAL_25_MHZ,      /* 25000000 */
+	MxL_XTAL_25_14_MHZ,   /* 25140000 */
+	MxL_XTAL_27_MHZ,      /* 27000000 */
+	MxL_XTAL_28_8_MHZ,    /* 28800000 */
+	MxL_XTAL_32_MHZ,      /* 32000000 */
+	MxL_XTAL_40_MHZ,      /* 40000000 */
+	MxL_XTAL_44_MHZ,      /* 44000000 */
+	MxL_XTAL_48_MHZ,      /* 48000000 */
+	MxL_XTAL_49_3811_MHZ, /* 49381100 */
+};
+
+enum mxl5007t_clkout_amp {
+	MxL_CLKOUT_AMP_0_94V = 0,
+	MxL_CLKOUT_AMP_0_53V = 1,
+	MxL_CLKOUT_AMP_0_37V = 2,
+	MxL_CLKOUT_AMP_0_28V = 3,
+	MxL_CLKOUT_AMP_0_23V = 4,
+	MxL_CLKOUT_AMP_0_20V = 5,
+	MxL_CLKOUT_AMP_0_17V = 6,
+	MxL_CLKOUT_AMP_0_15V = 7,
+};
+
+struct mxl5007t_config {
+	s32 if_diff_out_level;
+	enum mxl5007t_clkout_amp clk_out_amp;
+	enum mxl5007t_xtal_freq xtal_freq_hz;
+	enum mxl5007t_if_freq if_freq_hz;
+	unsigned int invert_if:1;
+	unsigned int loop_thru_enable:1;
+	unsigned int clk_out_enable:1;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_MXL5007T) || (defined(CONFIG_MEDIA_TUNER_MXL5007T_MODULE) && defined(MODULE))
+extern struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
+					    struct i2c_adapter *i2c, u8 addr,
+					    struct mxl5007t_config *cfg);
+#else
+static inline struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
+						   struct i2c_adapter *i2c,
+						   u8 addr,
+						   struct mxl5007t_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* __MXL5007T_H__ */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/drivers/media/tuners/qt1010.c b/drivers/media/tuners/qt1010.c
new file mode 100644
index 0000000..bdc39e1
--- /dev/null
+++ b/drivers/media/tuners/qt1010.c
@@ -0,0 +1,480 @@
+/*
+ *  Driver for Quantek QT1010 silicon tuner
+ *
+ *  Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ *                     Aapo Tahkola <aet@rasterburn.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include "qt1010.h"
+#include "qt1010_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "QT1010: " args); \
+	} while (0)
+
+/* read single register */
+static int qt1010_readreg(struct qt1010_priv *priv, u8 reg, u8 *val)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->cfg->i2c_address,
+		  .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = priv->cfg->i2c_address,
+		  .flags = I2C_M_RD, .buf = val, .len = 1 },
+	};
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		printk(KERN_WARNING "qt1010 I2C read failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+/* write single register */
+static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val)
+{
+	u8 buf[2] = { reg, val };
+	struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+			       .flags = 0, .buf = buf, .len = 2 };
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "qt1010 I2C write failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+/* dump all registers */
+static void qt1010_dump_regs(struct qt1010_priv *priv)
+{
+	u8 reg, val;
+
+	for (reg = 0; ; reg++) {
+		if (reg % 16 == 0) {
+			if (reg)
+				printk(KERN_CONT "\n");
+			printk(KERN_DEBUG "%02x:", reg);
+		}
+		if (qt1010_readreg(priv, reg, &val) == 0)
+			printk(KERN_CONT " %02x", val);
+		else
+			printk(KERN_CONT " --");
+		if (reg == 0x2f)
+			break;
+	}
+	printk(KERN_CONT "\n");
+}
+
+static int qt1010_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct qt1010_priv *priv;
+	int err;
+	u32 freq, div, mod1, mod2;
+	u8 i, tmpval, reg05;
+	qt1010_i2c_oper_t rd[48] = {
+		{ QT1010_WR, 0x01, 0x80 },
+		{ QT1010_WR, 0x02, 0x3f },
+		{ QT1010_WR, 0x05, 0xff }, /* 02 c write */
+		{ QT1010_WR, 0x06, 0x44 },
+		{ QT1010_WR, 0x07, 0xff }, /* 04 c write */
+		{ QT1010_WR, 0x08, 0x08 },
+		{ QT1010_WR, 0x09, 0xff }, /* 06 c write */
+		{ QT1010_WR, 0x0a, 0xff }, /* 07 c write */
+		{ QT1010_WR, 0x0b, 0xff }, /* 08 c write */
+		{ QT1010_WR, 0x0c, 0xe1 },
+		{ QT1010_WR, 0x1a, 0xff }, /* 10 c write */
+		{ QT1010_WR, 0x1b, 0x00 },
+		{ QT1010_WR, 0x1c, 0x89 },
+		{ QT1010_WR, 0x11, 0xff }, /* 13 c write */
+		{ QT1010_WR, 0x12, 0xff }, /* 14 c write */
+		{ QT1010_WR, 0x22, 0xff }, /* 15 c write */
+		{ QT1010_WR, 0x1e, 0x00 },
+		{ QT1010_WR, 0x1e, 0xd0 },
+		{ QT1010_RD, 0x22, 0xff }, /* 16 c read */
+		{ QT1010_WR, 0x1e, 0x00 },
+		{ QT1010_RD, 0x05, 0xff }, /* 20 c read */
+		{ QT1010_RD, 0x22, 0xff }, /* 21 c read */
+		{ QT1010_WR, 0x23, 0xd0 },
+		{ QT1010_WR, 0x1e, 0x00 },
+		{ QT1010_WR, 0x1e, 0xe0 },
+		{ QT1010_RD, 0x23, 0xff }, /* 25 c read */
+		{ QT1010_RD, 0x23, 0xff }, /* 26 c read */
+		{ QT1010_WR, 0x1e, 0x00 },
+		{ QT1010_WR, 0x24, 0xd0 },
+		{ QT1010_WR, 0x1e, 0x00 },
+		{ QT1010_WR, 0x1e, 0xf0 },
+		{ QT1010_RD, 0x24, 0xff }, /* 31 c read */
+		{ QT1010_WR, 0x1e, 0x00 },
+		{ QT1010_WR, 0x14, 0x7f },
+		{ QT1010_WR, 0x15, 0x7f },
+		{ QT1010_WR, 0x05, 0xff }, /* 35 c write */
+		{ QT1010_WR, 0x06, 0x00 },
+		{ QT1010_WR, 0x15, 0x1f },
+		{ QT1010_WR, 0x16, 0xff },
+		{ QT1010_WR, 0x18, 0xff },
+		{ QT1010_WR, 0x1f, 0xff }, /* 40 c write */
+		{ QT1010_WR, 0x20, 0xff }, /* 41 c write */
+		{ QT1010_WR, 0x21, 0x53 },
+		{ QT1010_WR, 0x25, 0xff }, /* 43 c write */
+		{ QT1010_WR, 0x26, 0x15 },
+		{ QT1010_WR, 0x00, 0xff }, /* 45 c write */
+		{ QT1010_WR, 0x02, 0x00 },
+		{ QT1010_WR, 0x01, 0x00 }
+	};
+
+#define FREQ1 32000000 /* 32 MHz */
+#define FREQ2  4000000 /* 4 MHz Quartz oscillator in the stick? */
+
+	priv = fe->tuner_priv;
+	freq = c->frequency;
+	div = (freq + QT1010_OFFSET) / QT1010_STEP;
+	freq = (div * QT1010_STEP) - QT1010_OFFSET;
+	mod1 = (freq + QT1010_OFFSET) % FREQ1;
+	mod2 = (freq + QT1010_OFFSET) % FREQ2;
+	priv->frequency = freq;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	/* reg 05 base value */
+	if      (freq < 290000000) reg05 = 0x14; /* 290 MHz */
+	else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */
+	else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */
+	else                       reg05 = 0x74;
+
+	/* 0x5 */
+	rd[2].val = reg05;
+
+	/* 07 - set frequency: 32 MHz scale */
+	rd[4].val = (freq + QT1010_OFFSET) / FREQ1;
+
+	/* 09 - changes every 8/24 MHz */
+	if (mod1 < 8000000) rd[6].val = 0x1d;
+	else                rd[6].val = 0x1c;
+
+	/* 0a - set frequency: 4 MHz scale (max 28 MHz) */
+	if      (mod1 < 1*FREQ2) rd[7].val = 0x09; /*  +0 MHz */
+	else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /*  +4 MHz */
+	else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /*  +8 MHz */
+	else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */
+	else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */
+	else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */
+	else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */
+	else                     rd[7].val = 0x0a; /* +28 MHz */
+
+	/* 0b - changes every 2/2 MHz */
+	if (mod2 < 2000000) rd[8].val = 0x45;
+	else                rd[8].val = 0x44;
+
+	/* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/
+	tmpval = 0x78; /* byte, overflows intentionally */
+	rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08);
+
+	/* 11 */
+	rd[13].val = 0xfd; /* TODO: correct value calculation */
+
+	/* 12 */
+	rd[14].val = 0x91; /* TODO: correct value calculation */
+
+	/* 22 */
+	if      (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */
+	else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */
+	else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */
+	else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */
+	else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */
+	else                       rd[15].val = 0xd0;
+
+	/* 05 */
+	rd[35].val = (reg05 & 0xf0);
+
+	/* 1f */
+	if      (mod1 <  8000000) tmpval = 0x00;
+	else if (mod1 < 12000000) tmpval = 0x01;
+	else if (mod1 < 16000000) tmpval = 0x02;
+	else if (mod1 < 24000000) tmpval = 0x03;
+	else if (mod1 < 28000000) tmpval = 0x04;
+	else                      tmpval = 0x05;
+	rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval);
+
+	/* 20 */
+	if      (mod1 <  8000000) tmpval = 0x00;
+	else if (mod1 < 12000000) tmpval = 0x01;
+	else if (mod1 < 20000000) tmpval = 0x02;
+	else if (mod1 < 24000000) tmpval = 0x03;
+	else if (mod1 < 28000000) tmpval = 0x04;
+	else                      tmpval = 0x05;
+	rd[41].val = (priv->reg20_init_val + 0x0d + tmpval);
+
+	/* 25 */
+	rd[43].val = priv->reg25_init_val;
+
+	/* 00 */
+	rd[45].val = 0x92; /* TODO: correct value calculation */
+
+	dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \
+		"1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \
+		"20:%02x 25:%02x 00:%02x", \
+		freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \
+		rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \
+		rd[40].val, rd[41].val, rd[43].val, rd[45].val);
+
+	for (i = 0; i < ARRAY_SIZE(rd); i++) {
+		if (rd[i].oper == QT1010_WR) {
+			err = qt1010_writereg(priv, rd[i].reg, rd[i].val);
+		} else { /* read is required to proper locking */
+			err = qt1010_readreg(priv, rd[i].reg, &tmpval);
+		}
+		if (err) return err;
+	}
+
+	if (debug)
+		qt1010_dump_regs(priv);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	return 0;
+}
+
+static int qt1010_init_meas1(struct qt1010_priv *priv,
+			     u8 oper, u8 reg, u8 reg_init_val, u8 *retval)
+{
+	u8 i, val1, val2;
+	int err;
+
+	qt1010_i2c_oper_t i2c_data[] = {
+		{ QT1010_WR, reg, reg_init_val },
+		{ QT1010_WR, 0x1e, 0x00 },
+		{ QT1010_WR, 0x1e, oper },
+		{ QT1010_RD, reg, 0xff }
+	};
+
+	for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
+		if (i2c_data[i].oper == QT1010_WR) {
+			err = qt1010_writereg(priv, i2c_data[i].reg,
+					      i2c_data[i].val);
+		} else {
+			err = qt1010_readreg(priv, i2c_data[i].reg, &val2);
+		}
+		if (err) return err;
+	}
+
+	do {
+		val1 = val2;
+		err = qt1010_readreg(priv, reg, &val2);
+		if (err) return err;
+		dprintk("compare reg:%02x %02x %02x", reg, val1, val2);
+	} while (val1 != val2);
+	*retval = val1;
+
+	return qt1010_writereg(priv, 0x1e, 0x00);
+}
+
+static int qt1010_init_meas2(struct qt1010_priv *priv,
+			    u8 reg_init_val, u8 *retval)
+{
+	u8 i, val;
+	int err;
+	qt1010_i2c_oper_t i2c_data[] = {
+		{ QT1010_WR, 0x07, reg_init_val },
+		{ QT1010_WR, 0x22, 0xd0 },
+		{ QT1010_WR, 0x1e, 0x00 },
+		{ QT1010_WR, 0x1e, 0xd0 },
+		{ QT1010_RD, 0x22, 0xff },
+		{ QT1010_WR, 0x1e, 0x00 },
+		{ QT1010_WR, 0x22, 0xff }
+	};
+	for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
+		if (i2c_data[i].oper == QT1010_WR) {
+			err = qt1010_writereg(priv, i2c_data[i].reg,
+					      i2c_data[i].val);
+		} else {
+			err = qt1010_readreg(priv, i2c_data[i].reg, &val);
+		}
+		if (err) return err;
+	}
+	*retval = val;
+	return 0;
+}
+
+static int qt1010_init(struct dvb_frontend *fe)
+{
+	struct qt1010_priv *priv = fe->tuner_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int err = 0;
+	u8 i, tmpval, *valptr = NULL;
+
+	qt1010_i2c_oper_t i2c_data[] = {
+		{ QT1010_WR, 0x01, 0x80 },
+		{ QT1010_WR, 0x0d, 0x84 },
+		{ QT1010_WR, 0x0e, 0xb7 },
+		{ QT1010_WR, 0x2a, 0x23 },
+		{ QT1010_WR, 0x2c, 0xdc },
+		{ QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */
+		{ QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */
+		{ QT1010_WR, 0x2b, 0x70 },
+		{ QT1010_WR, 0x2a, 0x23 },
+		{ QT1010_M1, 0x26, 0x08 },
+		{ QT1010_M1, 0x82, 0xff },
+		{ QT1010_WR, 0x05, 0x14 },
+		{ QT1010_WR, 0x06, 0x44 },
+		{ QT1010_WR, 0x07, 0x28 },
+		{ QT1010_WR, 0x08, 0x0b },
+		{ QT1010_WR, 0x11, 0xfd },
+		{ QT1010_M1, 0x22, 0x0d },
+		{ QT1010_M1, 0xd0, 0xff },
+		{ QT1010_WR, 0x06, 0x40 },
+		{ QT1010_WR, 0x16, 0xf0 },
+		{ QT1010_WR, 0x02, 0x38 },
+		{ QT1010_WR, 0x03, 0x18 },
+		{ QT1010_WR, 0x20, 0xe0 },
+		{ QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */
+		{ QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */
+		{ QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */
+		{ QT1010_WR, 0x03, 0x19 },
+		{ QT1010_WR, 0x02, 0x3f },
+		{ QT1010_WR, 0x21, 0x53 },
+		{ QT1010_RD, 0x21, 0xff },
+		{ QT1010_WR, 0x11, 0xfd },
+		{ QT1010_WR, 0x05, 0x34 },
+		{ QT1010_WR, 0x06, 0x44 },
+		{ QT1010_WR, 0x08, 0x08 }
+	};
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
+		switch (i2c_data[i].oper) {
+		case QT1010_WR:
+			err = qt1010_writereg(priv, i2c_data[i].reg,
+					      i2c_data[i].val);
+			break;
+		case QT1010_RD:
+			if (i2c_data[i].val == 0x20)
+				valptr = &priv->reg20_init_val;
+			else
+				valptr = &tmpval;
+			err = qt1010_readreg(priv, i2c_data[i].reg, valptr);
+			break;
+		case QT1010_M1:
+			if (i2c_data[i].val == 0x25)
+				valptr = &priv->reg25_init_val;
+			else if (i2c_data[i].val == 0x1f)
+				valptr = &priv->reg1f_init_val;
+			else
+				valptr = &tmpval;
+			err = qt1010_init_meas1(priv, i2c_data[i+1].reg,
+						i2c_data[i].reg,
+						i2c_data[i].val, valptr);
+			i++;
+			break;
+		}
+		if (err) return err;
+	}
+
+	for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */
+		if ((err = qt1010_init_meas2(priv, i, &tmpval)))
+			return err;
+
+	c->frequency = 545000000; /* Sigmatek DVB-110 545000000 */
+				      /* MSI Megasky 580 GL861 533000000 */
+	return qt1010_set_params(fe);
+}
+
+static int qt1010_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct qt1010_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int qt1010_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	*frequency = 36125000;
+	return 0;
+}
+
+static const struct dvb_tuner_ops qt1010_tuner_ops = {
+	.info = {
+		.name           = "Quantek QT1010",
+		.frequency_min  = QT1010_MIN_FREQ,
+		.frequency_max  = QT1010_MAX_FREQ,
+		.frequency_step = QT1010_STEP,
+	},
+
+	.release       = qt1010_release,
+	.init          = qt1010_init,
+	/* TODO: implement sleep */
+
+	.set_params    = qt1010_set_params,
+	.get_frequency = qt1010_get_frequency,
+	.get_if_frequency = qt1010_get_if_frequency,
+};
+
+struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe,
+				    struct i2c_adapter *i2c,
+				    struct qt1010_config *cfg)
+{
+	struct qt1010_priv *priv = NULL;
+	u8 id;
+
+	priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->cfg = cfg;
+	priv->i2c = i2c;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+
+	/* Try to detect tuner chip. Probably this is not correct register. */
+	if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) {
+		kfree(priv);
+		return NULL;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	printk(KERN_INFO "Quantek QT1010 successfully identified.\n");
+	memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+	return fe;
+}
+EXPORT_SYMBOL(qt1010_attach);
+
+MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/qt1010.h b/drivers/media/tuners/qt1010.h
new file mode 100644
index 0000000..807fb7b
--- /dev/null
+++ b/drivers/media/tuners/qt1010.h
@@ -0,0 +1,53 @@
+/*
+ *  Driver for Quantek QT1010 silicon tuner
+ *
+ *  Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ *                     Aapo Tahkola <aet@rasterburn.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef QT1010_H
+#define QT1010_H
+
+#include "dvb_frontend.h"
+
+struct qt1010_config {
+	u8 i2c_address;
+};
+
+/**
+ * Attach a qt1010 tuner to the supplied frontend structure.
+ *
+ * @param fe   frontend to attach to
+ * @param i2c  i2c adapter to use
+ * @param cfg  tuner hw based configuration
+ * @return fe  pointer on success, NULL on failure
+ */
+#if defined(CONFIG_MEDIA_TUNER_QT1010) || (defined(CONFIG_MEDIA_TUNER_QT1010_MODULE) && defined(MODULE))
+extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
+					  struct i2c_adapter *i2c,
+					  struct qt1010_config *cfg);
+#else
+static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
+						 struct i2c_adapter *i2c,
+						 struct qt1010_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_MEDIA_TUNER_QT1010
+
+#endif
diff --git a/drivers/media/tuners/qt1010_priv.h b/drivers/media/tuners/qt1010_priv.h
new file mode 100644
index 0000000..2c42d3f
--- /dev/null
+++ b/drivers/media/tuners/qt1010_priv.h
@@ -0,0 +1,104 @@
+/*
+ *  Driver for Quantek QT1010 silicon tuner
+ *
+ *  Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ *                     Aapo Tahkola <aet@rasterburn.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef QT1010_PRIV_H
+#define QT1010_PRIV_H
+
+/*
+reg def meaning
+=== === =======
+00  00  ?
+01  a0  ? operation start/stop; start=80, stop=00
+02  00  ?
+03  19  ?
+04  00  ?
+05  00  ? maybe band selection
+06  00  ?
+07  2b  set frequency: 32 MHz scale, n*32 MHz
+08  0b  ?
+09  10  ? changes every 8/24 MHz; values 1d/1c
+0a  08  set frequency: 4 MHz scale, n*4 MHz
+0b  41  ? changes every 2/2 MHz; values 45/45
+0c  e1  ?
+0d  94  ?
+0e  b6  ?
+0f  2c  ?
+10  10  ?
+11  f1  ? maybe device specified adjustment
+12  11  ? maybe device specified adjustment
+13  3f  ?
+14  1f  ?
+15  3f  ?
+16  ff  ?
+17  ff  ?
+18  f7  ?
+19  80  ?
+1a  d0  set frequency: 125 kHz scale, n*125 kHz
+1b  00  ?
+1c  89  ?
+1d  00  ?
+1e  00  ? looks like operation register; write cmd here, read result from 1f-26
+1f  20  ? chip initialization
+20  e0  ? chip initialization
+21  20  ?
+22  d0  ?
+23  d0  ?
+24  d0  ?
+25  40  ? chip initialization
+26  08  ?
+27  29  ?
+28  55  ?
+29  39  ?
+2a  13  ?
+2b  01  ?
+2c  ea  ?
+2d  00  ?
+2e  00  ? not used?
+2f  00  ? not used?
+*/
+
+#define QT1010_STEP         125000 /*  125 kHz used by Windows drivers,
+				      hw could be more precise but we don't
+				      know how to use */
+#define QT1010_MIN_FREQ   48000000 /*   48 MHz */
+#define QT1010_MAX_FREQ  860000000 /*  860 MHz */
+#define QT1010_OFFSET   1246000000 /* 1246 MHz */
+
+#define QT1010_WR 0
+#define QT1010_RD 1
+#define QT1010_M1 3
+
+typedef struct {
+	u8 oper, reg, val;
+} qt1010_i2c_oper_t;
+
+struct qt1010_priv {
+	struct qt1010_config *cfg;
+	struct i2c_adapter   *i2c;
+
+	u8 reg1f_init_val;
+	u8 reg20_init_val;
+	u8 reg25_init_val;
+
+	u32 frequency;
+};
+
+#endif
diff --git a/drivers/media/tuners/tda18212.c b/drivers/media/tuners/tda18212.c
new file mode 100644
index 0000000..5d9f028
--- /dev/null
+++ b/drivers/media/tuners/tda18212.c
@@ -0,0 +1,319 @@
+/*
+ * NXP TDA18212HN silicon tuner driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "tda18212.h"
+
+struct tda18212_priv {
+	struct tda18212_config *cfg;
+	struct i2c_adapter *i2c;
+
+	u32 if_frequency;
+};
+
+/* write multiple registers */
+static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
+	int len)
+{
+	int ret;
+	u8 buf[len+1];
+	struct i2c_msg msg[1] = {
+		{
+			.addr = priv->cfg->i2c_address,
+			.flags = 0,
+			.len = sizeof(buf),
+			.buf = buf,
+		}
+	};
+
+	buf[0] = reg;
+	memcpy(&buf[1], val, len);
+
+	ret = i2c_transfer(priv->i2c, msg, 1);
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \
+				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+/* read multiple registers */
+static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
+	int len)
+{
+	int ret;
+	u8 buf[len];
+	struct i2c_msg msg[2] = {
+		{
+			.addr = priv->cfg->i2c_address,
+			.flags = 0,
+			.len = 1,
+			.buf = &reg,
+		}, {
+			.addr = priv->cfg->i2c_address,
+			.flags = I2C_M_RD,
+			.len = sizeof(buf),
+			.buf = buf,
+		}
+	};
+
+	ret = i2c_transfer(priv->i2c, msg, 2);
+	if (ret == 2) {
+		memcpy(val, buf, len);
+		ret = 0;
+	} else {
+		dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \
+				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+
+	return ret;
+}
+
+/* write single register */
+static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val)
+{
+	return tda18212_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val)
+{
+	return tda18212_rd_regs(priv, reg, val, 1);
+}
+
+#if 0 /* keep, useful when developing driver */
+static void tda18212_dump_regs(struct tda18212_priv *priv)
+{
+	int i;
+	u8 buf[256];
+
+	#define TDA18212_RD_LEN 32
+	for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN)
+		tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN);
+
+	print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf,
+		sizeof(buf), true);
+
+	return;
+}
+#endif
+
+static int tda18212_set_params(struct dvb_frontend *fe)
+{
+	struct tda18212_priv *priv = fe->tuner_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i;
+	u32 if_khz;
+	u8 buf[9];
+	#define DVBT_6   0
+	#define DVBT_7   1
+	#define DVBT_8   2
+	#define DVBT2_6  3
+	#define DVBT2_7  4
+	#define DVBT2_8  5
+	#define DVBC_6   6
+	#define DVBC_8   7
+	static const u8 bw_params[][3] = {
+		     /* reg:   0f    13    23 */
+		[DVBT_6]  = { 0xb3, 0x20, 0x03 },
+		[DVBT_7]  = { 0xb3, 0x31, 0x01 },
+		[DVBT_8]  = { 0xb3, 0x22, 0x01 },
+		[DVBT2_6] = { 0xbc, 0x20, 0x03 },
+		[DVBT2_7] = { 0xbc, 0x72, 0x03 },
+		[DVBT2_8] = { 0xbc, 0x22, 0x01 },
+		[DVBC_6]  = { 0x92, 0x50, 0x03 },
+		[DVBC_8]  = { 0x92, 0x53, 0x03 },
+	};
+
+	dev_dbg(&priv->i2c->dev,
+			"%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n",
+			__func__, c->delivery_system, c->frequency,
+			c->bandwidth_hz);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	switch (c->delivery_system) {
+	case SYS_DVBT:
+		switch (c->bandwidth_hz) {
+		case 6000000:
+			if_khz = priv->cfg->if_dvbt_6;
+			i = DVBT_6;
+			break;
+		case 7000000:
+			if_khz = priv->cfg->if_dvbt_7;
+			i = DVBT_7;
+			break;
+		case 8000000:
+			if_khz = priv->cfg->if_dvbt_8;
+			i = DVBT_8;
+			break;
+		default:
+			ret = -EINVAL;
+			goto error;
+		}
+		break;
+	case SYS_DVBT2:
+		switch (c->bandwidth_hz) {
+		case 6000000:
+			if_khz = priv->cfg->if_dvbt2_6;
+			i = DVBT2_6;
+			break;
+		case 7000000:
+			if_khz = priv->cfg->if_dvbt2_7;
+			i = DVBT2_7;
+			break;
+		case 8000000:
+			if_khz = priv->cfg->if_dvbt2_8;
+			i = DVBT2_8;
+			break;
+		default:
+			ret = -EINVAL;
+			goto error;
+		}
+		break;
+	case SYS_DVBC_ANNEX_A:
+	case SYS_DVBC_ANNEX_C:
+		if_khz = priv->cfg->if_dvbc;
+		i = DVBC_8;
+		break;
+	default:
+		ret = -EINVAL;
+		goto error;
+	}
+
+	ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]);
+	if (ret)
+		goto error;
+
+	ret = tda18212_wr_reg(priv, 0x06, 0x00);
+	if (ret)
+		goto error;
+
+	ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]);
+	if (ret)
+		goto error;
+
+	buf[0] = 0x02;
+	buf[1] = bw_params[i][1];
+	buf[2] = 0x03; /* default value */
+	buf[3] = DIV_ROUND_CLOSEST(if_khz, 50);
+	buf[4] = ((c->frequency / 1000) >> 16) & 0xff;
+	buf[5] = ((c->frequency / 1000) >>  8) & 0xff;
+	buf[6] = ((c->frequency / 1000) >>  0) & 0xff;
+	buf[7] = 0xc1;
+	buf[8] = 0x01;
+	ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf));
+	if (ret)
+		goto error;
+
+	/* actual IF rounded as it is on register */
+	priv->if_frequency = buf[3] * 50 * 1000;
+
+exit:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	return ret;
+
+error:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	goto exit;
+}
+
+static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tda18212_priv *priv = fe->tuner_priv;
+
+	*frequency = priv->if_frequency;
+
+	return 0;
+}
+
+static int tda18212_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static const struct dvb_tuner_ops tda18212_tuner_ops = {
+	.info = {
+		.name           = "NXP TDA18212",
+
+		.frequency_min  =  48000000,
+		.frequency_max  = 864000000,
+		.frequency_step =      1000,
+	},
+
+	.release       = tda18212_release,
+
+	.set_params    = tda18212_set_params,
+	.get_if_frequency = tda18212_get_if_frequency,
+};
+
+struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c, struct tda18212_config *cfg)
+{
+	struct tda18212_priv *priv = NULL;
+	int ret;
+	u8 uninitialized_var(val);
+
+	priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->cfg = cfg;
+	priv->i2c = i2c;
+	fe->tuner_priv = priv;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	/* check if the tuner is there */
+	ret = tda18212_rd_reg(priv, 0x00, &val);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	dev_dbg(&priv->i2c->dev, "%s: ret=%d chip id=%02x\n", __func__, ret,
+			val);
+	if (ret || val != 0xc7) {
+		kfree(priv);
+		return NULL;
+	}
+
+	dev_info(&priv->i2c->dev,
+			"%s: NXP TDA18212HN successfully identified\n",
+			KBUILD_MODNAME);
+
+	memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+
+	return fe;
+}
+EXPORT_SYMBOL(tda18212_attach);
+
+MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/tda18212.h b/drivers/media/tuners/tda18212.h
new file mode 100644
index 0000000..9bd5da4
--- /dev/null
+++ b/drivers/media/tuners/tda18212.h
@@ -0,0 +1,52 @@
+/*
+ * NXP TDA18212HN silicon tuner driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef TDA18212_H
+#define TDA18212_H
+
+#include "dvb_frontend.h"
+
+struct tda18212_config {
+	u8 i2c_address;
+
+	u16 if_dvbt_6;
+	u16 if_dvbt_7;
+	u16 if_dvbt_8;
+	u16 if_dvbt2_5;
+	u16 if_dvbt2_6;
+	u16 if_dvbt2_7;
+	u16 if_dvbt2_8;
+	u16 if_dvbc;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_TDA18212) || \
+	(defined(CONFIG_MEDIA_TUNER_TDA18212_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c, struct tda18212_config *cfg);
+#else
+static inline struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c, struct tda18212_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/tuners/tda18218.c b/drivers/media/tuners/tda18218.c
new file mode 100644
index 0000000..8a6f9ca
--- /dev/null
+++ b/drivers/media/tuners/tda18218.c
@@ -0,0 +1,342 @@
+/*
+ * NXP TDA18218HN silicon tuner driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "tda18218.h"
+#include "tda18218_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+/* write multiple registers */
+static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
+{
+	int ret = 0;
+	u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max;
+	struct i2c_msg msg[1] = {
+		{
+			.addr = priv->cfg->i2c_address,
+			.flags = 0,
+			.buf = buf,
+		}
+	};
+
+	msg_len_max = priv->cfg->i2c_wr_max - 1;
+	quotient = len / msg_len_max;
+	remainder = len % msg_len_max;
+	msg_len = msg_len_max;
+	for (i = 0; (i <= quotient && remainder); i++) {
+		if (i == quotient)  /* set len of the last msg */
+			msg_len = remainder;
+
+		msg[0].len = msg_len + 1;
+		buf[0] = reg + i * msg_len_max;
+		memcpy(&buf[1], &val[i * msg_len_max], msg_len);
+
+		ret = i2c_transfer(priv->i2c, msg, 1);
+		if (ret != 1)
+			break;
+	}
+
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+
+	return ret;
+}
+
+/* read multiple registers */
+static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
+{
+	int ret;
+	u8 buf[reg+len]; /* we must start read always from reg 0x00 */
+	struct i2c_msg msg[2] = {
+		{
+			.addr = priv->cfg->i2c_address,
+			.flags = 0,
+			.len = 1,
+			.buf = "\x00",
+		}, {
+			.addr = priv->cfg->i2c_address,
+			.flags = I2C_M_RD,
+			.len = sizeof(buf),
+			.buf = buf,
+		}
+	};
+
+	ret = i2c_transfer(priv->i2c, msg, 2);
+	if (ret == 2) {
+		memcpy(val, &buf[reg], len);
+		ret = 0;
+	} else {
+		warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+
+	return ret;
+}
+
+/* write single register */
+static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val)
+{
+	return tda18218_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+
+static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val)
+{
+	return tda18218_rd_regs(priv, reg, val, 1);
+}
+
+static int tda18218_set_params(struct dvb_frontend *fe)
+{
+	struct tda18218_priv *priv = fe->tuner_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 bw = c->bandwidth_hz;
+	int ret;
+	u8 buf[3], i, BP_Filter, LP_Fc;
+	u32 LO_Frac;
+	/* TODO: find out correct AGC algorithm */
+	u8 agc[][2] = {
+		{ R20_AGC11, 0x60 },
+		{ R23_AGC21, 0x02 },
+		{ R20_AGC11, 0xa0 },
+		{ R23_AGC21, 0x09 },
+		{ R20_AGC11, 0xe0 },
+		{ R23_AGC21, 0x0c },
+		{ R20_AGC11, 0x40 },
+		{ R23_AGC21, 0x01 },
+		{ R20_AGC11, 0x80 },
+		{ R23_AGC21, 0x08 },
+		{ R20_AGC11, 0xc0 },
+		{ R23_AGC21, 0x0b },
+		{ R24_AGC22, 0x1c },
+		{ R24_AGC22, 0x0c },
+	};
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	/* low-pass filter cut-off frequency */
+	if (bw <= 6000000) {
+		LP_Fc = 0;
+		priv->if_frequency = 3000000;
+	} else if (bw <= 7000000) {
+		LP_Fc = 1;
+		priv->if_frequency = 3500000;
+	} else {
+		LP_Fc = 2;
+		priv->if_frequency = 4000000;
+	}
+
+	LO_Frac = c->frequency + priv->if_frequency;
+
+	/* band-pass filter */
+	if (LO_Frac < 188000000)
+		BP_Filter = 3;
+	else if (LO_Frac < 253000000)
+		BP_Filter = 4;
+	else if (LO_Frac < 343000000)
+		BP_Filter = 5;
+	else
+		BP_Filter = 6;
+
+	buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */
+	buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */
+	buf[2] = priv->regs[R1C_AGC2B];
+	ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3);
+	if (ret)
+		goto error;
+
+	buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */
+	buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */
+	buf[2] = (LO_Frac / 1000) << 4 |
+		(priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */
+	ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3);
+	if (ret)
+		goto error;
+
+	buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */
+	ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
+	if (ret)
+		goto error;
+
+	buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */
+	ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
+	if (ret)
+		goto error;
+
+	/* trigger AGC */
+	for (i = 0; i < ARRAY_SIZE(agc); i++) {
+		ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]);
+		if (ret)
+			goto error;
+	}
+
+error:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	if (ret)
+		dbg("%s: failed ret:%d", __func__, ret);
+
+	return ret;
+}
+
+static int tda18218_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tda18218_priv *priv = fe->tuner_priv;
+	*frequency = priv->if_frequency;
+	dbg("%s: if=%d", __func__, *frequency);
+	return 0;
+}
+
+static int tda18218_sleep(struct dvb_frontend *fe)
+{
+	struct tda18218_priv *priv = fe->tuner_priv;
+	int ret;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	/* standby */
+	ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	if (ret)
+		dbg("%s: failed ret:%d", __func__, ret);
+
+	return ret;
+}
+
+static int tda18218_init(struct dvb_frontend *fe)
+{
+	struct tda18218_priv *priv = fe->tuner_priv;
+	int ret;
+
+	/* TODO: calibrations */
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	if (ret)
+		dbg("%s: failed ret:%d", __func__, ret);
+
+	return ret;
+}
+
+static int tda18218_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static const struct dvb_tuner_ops tda18218_tuner_ops = {
+	.info = {
+		.name           = "NXP TDA18218",
+
+		.frequency_min  = 174000000,
+		.frequency_max  = 864000000,
+		.frequency_step =      1000,
+	},
+
+	.release       = tda18218_release,
+	.init          = tda18218_init,
+	.sleep         = tda18218_sleep,
+
+	.set_params    = tda18218_set_params,
+
+	.get_if_frequency = tda18218_get_if_frequency,
+};
+
+struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c, struct tda18218_config *cfg)
+{
+	struct tda18218_priv *priv = NULL;
+	u8 uninitialized_var(val);
+	int ret;
+	/* chip default registers values */
+	static u8 def_regs[] = {
+		0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40,
+		0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00,
+		0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01,
+		0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9,
+		0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00,
+		0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6
+	};
+
+	priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->cfg = cfg;
+	priv->i2c = i2c;
+	fe->tuner_priv = priv;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	/* check if the tuner is there */
+	ret = tda18218_rd_reg(priv, R00_ID, &val);
+	dbg("%s: ret:%d chip ID:%02x", __func__, ret, val);
+	if (ret || val != def_regs[R00_ID]) {
+		kfree(priv);
+		return NULL;
+	}
+
+	info("NXP TDA18218HN successfully identified.");
+
+	memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+	memcpy(priv->regs, def_regs, sizeof(def_regs));
+
+	/* loop-through enabled chip default register values */
+	if (priv->cfg->loop_through) {
+		priv->regs[R17_PD1] = 0xb0;
+		priv->regs[R18_PD2] = 0x59;
+	}
+
+	/* standby */
+	ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
+	if (ret)
+		dbg("%s: failed ret:%d", __func__, ret);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	return fe;
+}
+EXPORT_SYMBOL(tda18218_attach);
+
+MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/tda18218.h b/drivers/media/tuners/tda18218.h
new file mode 100644
index 0000000..b4180d1
--- /dev/null
+++ b/drivers/media/tuners/tda18218.h
@@ -0,0 +1,45 @@
+/*
+ * NXP TDA18218HN silicon tuner driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef TDA18218_H
+#define TDA18218_H
+
+#include "dvb_frontend.h"
+
+struct tda18218_config {
+	u8 i2c_address;
+	u8 i2c_wr_max;
+	u8 loop_through:1;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_TDA18218) || \
+	(defined(CONFIG_MEDIA_TUNER_TDA18218_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c, struct tda18218_config *cfg);
+#else
+static inline struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c, struct tda18218_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/tuners/tda18218_priv.h b/drivers/media/tuners/tda18218_priv.h
new file mode 100644
index 0000000..dc52b72
--- /dev/null
+++ b/drivers/media/tuners/tda18218_priv.h
@@ -0,0 +1,108 @@
+/*
+ * NXP TDA18218HN silicon tuner driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef TDA18218_PRIV_H
+#define TDA18218_PRIV_H
+
+#define LOG_PREFIX "tda18218"
+
+#undef dbg
+#define dbg(f, arg...) \
+	if (debug) \
+		printk(KERN_DEBUG   LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+#define R00_ID         0x00	/* ID byte */
+#define R01_R1         0x01	/* Read byte 1 */
+#define R02_R2         0x02	/* Read byte 2 */
+#define R03_R3         0x03	/* Read byte 3 */
+#define R04_R4         0x04	/* Read byte 4 */
+#define R05_R5         0x05	/* Read byte 5 */
+#define R06_R6         0x06	/* Read byte 6 */
+#define R07_MD1        0x07	/* Main divider byte 1 */
+#define R08_PSM1       0x08	/* PSM byte 1 */
+#define R09_MD2        0x09	/* Main divider byte 2 */
+#define R0A_MD3        0x0a	/* Main divider byte 1 */
+#define R0B_MD4        0x0b	/* Main divider byte 4 */
+#define R0C_MD5        0x0c	/* Main divider byte 5 */
+#define R0D_MD6        0x0d	/* Main divider byte 6 */
+#define R0E_MD7        0x0e	/* Main divider byte 7 */
+#define R0F_MD8        0x0f	/* Main divider byte 8 */
+#define R10_CD1        0x10	/* Call divider byte 1 */
+#define R11_CD2        0x11	/* Call divider byte 2 */
+#define R12_CD3        0x12	/* Call divider byte 3 */
+#define R13_CD4        0x13	/* Call divider byte 4 */
+#define R14_CD5        0x14	/* Call divider byte 5 */
+#define R15_CD6        0x15	/* Call divider byte 6 */
+#define R16_CD7        0x16	/* Call divider byte 7 */
+#define R17_PD1        0x17	/* Power-down byte 1 */
+#define R18_PD2        0x18	/* Power-down byte 2 */
+#define R19_XTOUT      0x19	/* XTOUT byte */
+#define R1A_IF1        0x1a	/* IF byte 1 */
+#define R1B_IF2        0x1b	/* IF byte 2 */
+#define R1C_AGC2B      0x1c	/* AGC2b byte */
+#define R1D_PSM2       0x1d	/* PSM byte 2 */
+#define R1E_PSM3       0x1e	/* PSM byte 3 */
+#define R1F_PSM4       0x1f	/* PSM byte 4 */
+#define R20_AGC11      0x20	/* AGC1 byte 1 */
+#define R21_AGC12      0x21	/* AGC1 byte 2 */
+#define R22_AGC13      0x22	/* AGC1 byte 3 */
+#define R23_AGC21      0x23	/* AGC2 byte 1 */
+#define R24_AGC22      0x24	/* AGC2 byte 2 */
+#define R25_AAGC       0x25	/* Analog AGC byte */
+#define R26_RC         0x26	/* RC byte */
+#define R27_RSSI       0x27	/* RSSI byte */
+#define R28_IRCAL1     0x28	/* IR CAL byte 1 */
+#define R29_IRCAL2     0x29	/* IR CAL byte 2 */
+#define R2A_IRCAL3     0x2a	/* IR CAL byte 3 */
+#define R2B_IRCAL4     0x2b	/* IR CAL byte 4 */
+#define R2C_RFCAL1     0x2c	/* RF CAL byte 1 */
+#define R2D_RFCAL2     0x2d	/* RF CAL byte 2 */
+#define R2E_RFCAL3     0x2e	/* RF CAL byte 3 */
+#define R2F_RFCAL4     0x2f	/* RF CAL byte 4 */
+#define R30_RFCAL5     0x30	/* RF CAL byte 5 */
+#define R31_RFCAL6     0x31	/* RF CAL byte 6 */
+#define R32_RFCAL7     0x32	/* RF CAL byte 7 */
+#define R33_RFCAL8     0x33	/* RF CAL byte 8 */
+#define R34_RFCAL9     0x34	/* RF CAL byte 9 */
+#define R35_RFCAL10    0x35	/* RF CAL byte 10 */
+#define R36_RFCALRAM1  0x36	/* RF CAL RAM byte 1 */
+#define R37_RFCALRAM2  0x37	/* RF CAL RAM byte 2 */
+#define R38_MARGIN     0x38	/* Margin byte */
+#define R39_FMAX1      0x39	/* Fmax byte 1 */
+#define R3A_FMAX2      0x3a	/* Fmax byte 2 */
+
+#define TDA18218_NUM_REGS 59
+
+struct tda18218_priv {
+	struct tda18218_config *cfg;
+	struct i2c_adapter *i2c;
+
+	u32 if_frequency;
+
+	u8 regs[TDA18218_NUM_REGS];
+};
+
+#endif
diff --git a/drivers/media/tuners/tda18271-common.c b/drivers/media/tuners/tda18271-common.c
new file mode 100644
index 0000000..39c6457
--- /dev/null
+++ b/drivers/media/tuners/tda18271-common.c
@@ -0,0 +1,703 @@
+/*
+    tda18271-common.c - driver for the Philips / NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "tda18271-priv.h"
+
+static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	enum tda18271_i2c_gate gate;
+	int ret = 0;
+
+	switch (priv->gate) {
+	case TDA18271_GATE_DIGITAL:
+	case TDA18271_GATE_ANALOG:
+		gate = priv->gate;
+		break;
+	case TDA18271_GATE_AUTO:
+	default:
+		switch (priv->mode) {
+		case TDA18271_DIGITAL:
+			gate = TDA18271_GATE_DIGITAL;
+			break;
+		case TDA18271_ANALOG:
+		default:
+			gate = TDA18271_GATE_ANALOG;
+			break;
+		}
+	}
+
+	switch (gate) {
+	case TDA18271_GATE_ANALOG:
+		if (fe->ops.analog_ops.i2c_gate_ctrl)
+			ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable);
+		break;
+	case TDA18271_GATE_DIGITAL:
+		if (fe->ops.i2c_gate_ctrl)
+			ret = fe->ops.i2c_gate_ctrl(fe, enable);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+};
+
+/*---------------------------------------------------------------------*/
+
+static void tda18271_dump_regs(struct dvb_frontend *fe, int extended)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	tda_reg("=== TDA18271 REG DUMP ===\n");
+	tda_reg("ID_BYTE            = 0x%02x\n", 0xff & regs[R_ID]);
+	tda_reg("THERMO_BYTE        = 0x%02x\n", 0xff & regs[R_TM]);
+	tda_reg("POWER_LEVEL_BYTE   = 0x%02x\n", 0xff & regs[R_PL]);
+	tda_reg("EASY_PROG_BYTE_1   = 0x%02x\n", 0xff & regs[R_EP1]);
+	tda_reg("EASY_PROG_BYTE_2   = 0x%02x\n", 0xff & regs[R_EP2]);
+	tda_reg("EASY_PROG_BYTE_3   = 0x%02x\n", 0xff & regs[R_EP3]);
+	tda_reg("EASY_PROG_BYTE_4   = 0x%02x\n", 0xff & regs[R_EP4]);
+	tda_reg("EASY_PROG_BYTE_5   = 0x%02x\n", 0xff & regs[R_EP5]);
+	tda_reg("CAL_POST_DIV_BYTE  = 0x%02x\n", 0xff & regs[R_CPD]);
+	tda_reg("CAL_DIV_BYTE_1     = 0x%02x\n", 0xff & regs[R_CD1]);
+	tda_reg("CAL_DIV_BYTE_2     = 0x%02x\n", 0xff & regs[R_CD2]);
+	tda_reg("CAL_DIV_BYTE_3     = 0x%02x\n", 0xff & regs[R_CD3]);
+	tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]);
+	tda_reg("MAIN_DIV_BYTE_1    = 0x%02x\n", 0xff & regs[R_MD1]);
+	tda_reg("MAIN_DIV_BYTE_2    = 0x%02x\n", 0xff & regs[R_MD2]);
+	tda_reg("MAIN_DIV_BYTE_3    = 0x%02x\n", 0xff & regs[R_MD3]);
+
+	/* only dump extended regs if DBG_ADV is set */
+	if (!(tda18271_debug & DBG_ADV))
+		return;
+
+	/* W indicates write-only registers.
+	 * Register dump for write-only registers shows last value written. */
+
+	tda_reg("EXTENDED_BYTE_1    = 0x%02x\n", 0xff & regs[R_EB1]);
+	tda_reg("EXTENDED_BYTE_2    = 0x%02x\n", 0xff & regs[R_EB2]);
+	tda_reg("EXTENDED_BYTE_3    = 0x%02x\n", 0xff & regs[R_EB3]);
+	tda_reg("EXTENDED_BYTE_4    = 0x%02x\n", 0xff & regs[R_EB4]);
+	tda_reg("EXTENDED_BYTE_5    = 0x%02x\n", 0xff & regs[R_EB5]);
+	tda_reg("EXTENDED_BYTE_6    = 0x%02x\n", 0xff & regs[R_EB6]);
+	tda_reg("EXTENDED_BYTE_7    = 0x%02x\n", 0xff & regs[R_EB7]);
+	tda_reg("EXTENDED_BYTE_8    = 0x%02x\n", 0xff & regs[R_EB8]);
+	tda_reg("EXTENDED_BYTE_9  W = 0x%02x\n", 0xff & regs[R_EB9]);
+	tda_reg("EXTENDED_BYTE_10   = 0x%02x\n", 0xff & regs[R_EB10]);
+	tda_reg("EXTENDED_BYTE_11   = 0x%02x\n", 0xff & regs[R_EB11]);
+	tda_reg("EXTENDED_BYTE_12   = 0x%02x\n", 0xff & regs[R_EB12]);
+	tda_reg("EXTENDED_BYTE_13   = 0x%02x\n", 0xff & regs[R_EB13]);
+	tda_reg("EXTENDED_BYTE_14   = 0x%02x\n", 0xff & regs[R_EB14]);
+	tda_reg("EXTENDED_BYTE_15   = 0x%02x\n", 0xff & regs[R_EB15]);
+	tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]);
+	tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]);
+	tda_reg("EXTENDED_BYTE_18   = 0x%02x\n", 0xff & regs[R_EB18]);
+	tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]);
+	tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]);
+	tda_reg("EXTENDED_BYTE_21   = 0x%02x\n", 0xff & regs[R_EB21]);
+	tda_reg("EXTENDED_BYTE_22   = 0x%02x\n", 0xff & regs[R_EB22]);
+	tda_reg("EXTENDED_BYTE_23   = 0x%02x\n", 0xff & regs[R_EB23]);
+}
+
+int tda18271_read_regs(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	unsigned char buf = 0x00;
+	int ret;
+	struct i2c_msg msg[] = {
+		{ .addr = priv->i2c_props.addr, .flags = 0,
+		  .buf = &buf, .len = 1 },
+		{ .addr = priv->i2c_props.addr, .flags = I2C_M_RD,
+		  .buf = regs, .len = 16 }
+	};
+
+	tda18271_i2c_gate_ctrl(fe, 1);
+
+	/* read all registers */
+	ret = i2c_transfer(priv->i2c_props.adap, msg, 2);
+
+	tda18271_i2c_gate_ctrl(fe, 0);
+
+	if (ret != 2)
+		tda_err("ERROR: i2c_transfer returned: %d\n", ret);
+
+	if (tda18271_debug & DBG_REG)
+		tda18271_dump_regs(fe, 0);
+
+	return (ret == 2 ? 0 : ret);
+}
+
+int tda18271_read_extended(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	unsigned char regdump[TDA18271_NUM_REGS];
+	unsigned char buf = 0x00;
+	int ret, i;
+	struct i2c_msg msg[] = {
+		{ .addr = priv->i2c_props.addr, .flags = 0,
+		  .buf = &buf, .len = 1 },
+		{ .addr = priv->i2c_props.addr, .flags = I2C_M_RD,
+		  .buf = regdump, .len = TDA18271_NUM_REGS }
+	};
+
+	tda18271_i2c_gate_ctrl(fe, 1);
+
+	/* read all registers */
+	ret = i2c_transfer(priv->i2c_props.adap, msg, 2);
+
+	tda18271_i2c_gate_ctrl(fe, 0);
+
+	if (ret != 2)
+		tda_err("ERROR: i2c_transfer returned: %d\n", ret);
+
+	for (i = 0; i < TDA18271_NUM_REGS; i++) {
+		/* don't update write-only registers */
+		if ((i != R_EB9)  &&
+		    (i != R_EB16) &&
+		    (i != R_EB17) &&
+		    (i != R_EB19) &&
+		    (i != R_EB20))
+		regs[i] = regdump[i];
+	}
+
+	if (tda18271_debug & DBG_REG)
+		tda18271_dump_regs(fe, 1);
+
+	return (ret == 2 ? 0 : ret);
+}
+
+int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	unsigned char buf[TDA18271_NUM_REGS + 1];
+	struct i2c_msg msg = { .addr = priv->i2c_props.addr, .flags = 0,
+			       .buf = buf };
+	int i, ret = 1, max;
+
+	BUG_ON((len == 0) || (idx + len > sizeof(buf)));
+
+
+	switch (priv->small_i2c) {
+	case TDA18271_03_BYTE_CHUNK_INIT:
+		max = 3;
+		break;
+	case TDA18271_08_BYTE_CHUNK_INIT:
+		max = 8;
+		break;
+	case TDA18271_16_BYTE_CHUNK_INIT:
+		max = 16;
+		break;
+	case TDA18271_39_BYTE_CHUNK_INIT:
+	default:
+		max = 39;
+	}
+
+	tda18271_i2c_gate_ctrl(fe, 1);
+	while (len) {
+		if (max > len)
+			max = len;
+
+		buf[0] = idx;
+		for (i = 1; i <= max; i++)
+			buf[i] = regs[idx - 1 + i];
+
+		msg.len = max + 1;
+
+		/* write registers */
+		ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
+		if (ret != 1)
+			break;
+
+		idx += max;
+		len -= max;
+	}
+	tda18271_i2c_gate_ctrl(fe, 0);
+
+	if (ret != 1)
+		tda_err("ERROR: idx = 0x%x, len = %d, "
+			"i2c_transfer returned: %d\n", idx, max, ret);
+
+	return (ret == 1 ? 0 : ret);
+}
+
+/*---------------------------------------------------------------------*/
+
+int tda18271_charge_pump_source(struct dvb_frontend *fe,
+				enum tda18271_pll pll, int force)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	int r_cp = (pll == TDA18271_CAL_PLL) ? R_EB7 : R_EB4;
+
+	regs[r_cp] &= ~0x20;
+	regs[r_cp] |= ((force & 1) << 5);
+
+	return tda18271_write_regs(fe, r_cp, 1);
+}
+
+int tda18271_init_regs(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	tda_dbg("initializing registers for device @ %d-%04x\n",
+		i2c_adapter_id(priv->i2c_props.adap),
+		priv->i2c_props.addr);
+
+	/* initialize registers */
+	switch (priv->id) {
+	case TDA18271HDC1:
+		regs[R_ID]   = 0x83;
+		break;
+	case TDA18271HDC2:
+		regs[R_ID]   = 0x84;
+		break;
+	};
+
+	regs[R_TM]   = 0x08;
+	regs[R_PL]   = 0x80;
+	regs[R_EP1]  = 0xc6;
+	regs[R_EP2]  = 0xdf;
+	regs[R_EP3]  = 0x16;
+	regs[R_EP4]  = 0x60;
+	regs[R_EP5]  = 0x80;
+	regs[R_CPD]  = 0x80;
+	regs[R_CD1]  = 0x00;
+	regs[R_CD2]  = 0x00;
+	regs[R_CD3]  = 0x00;
+	regs[R_MPD]  = 0x00;
+	regs[R_MD1]  = 0x00;
+	regs[R_MD2]  = 0x00;
+	regs[R_MD3]  = 0x00;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		regs[R_EB1]  = 0xff;
+		break;
+	case TDA18271HDC2:
+		regs[R_EB1]  = 0xfc;
+		break;
+	};
+
+	regs[R_EB2]  = 0x01;
+	regs[R_EB3]  = 0x84;
+	regs[R_EB4]  = 0x41;
+	regs[R_EB5]  = 0x01;
+	regs[R_EB6]  = 0x84;
+	regs[R_EB7]  = 0x40;
+	regs[R_EB8]  = 0x07;
+	regs[R_EB9]  = 0x00;
+	regs[R_EB10] = 0x00;
+	regs[R_EB11] = 0x96;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		regs[R_EB12] = 0x0f;
+		break;
+	case TDA18271HDC2:
+		regs[R_EB12] = 0x33;
+		break;
+	};
+
+	regs[R_EB13] = 0xc1;
+	regs[R_EB14] = 0x00;
+	regs[R_EB15] = 0x8f;
+	regs[R_EB16] = 0x00;
+	regs[R_EB17] = 0x00;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		regs[R_EB18] = 0x00;
+		break;
+	case TDA18271HDC2:
+		regs[R_EB18] = 0x8c;
+		break;
+	};
+
+	regs[R_EB19] = 0x00;
+	regs[R_EB20] = 0x20;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		regs[R_EB21] = 0x33;
+		break;
+	case TDA18271HDC2:
+		regs[R_EB21] = 0xb3;
+		break;
+	};
+
+	regs[R_EB22] = 0x48;
+	regs[R_EB23] = 0xb0;
+
+	tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
+
+	/* setup agc1 gain */
+	regs[R_EB17] = 0x00;
+	tda18271_write_regs(fe, R_EB17, 1);
+	regs[R_EB17] = 0x03;
+	tda18271_write_regs(fe, R_EB17, 1);
+	regs[R_EB17] = 0x43;
+	tda18271_write_regs(fe, R_EB17, 1);
+	regs[R_EB17] = 0x4c;
+	tda18271_write_regs(fe, R_EB17, 1);
+
+	/* setup agc2 gain */
+	if ((priv->id) == TDA18271HDC1) {
+		regs[R_EB20] = 0xa0;
+		tda18271_write_regs(fe, R_EB20, 1);
+		regs[R_EB20] = 0xa7;
+		tda18271_write_regs(fe, R_EB20, 1);
+		regs[R_EB20] = 0xe7;
+		tda18271_write_regs(fe, R_EB20, 1);
+		regs[R_EB20] = 0xec;
+		tda18271_write_regs(fe, R_EB20, 1);
+	}
+
+	/* image rejection calibration */
+
+	/* low-band */
+	regs[R_EP3] = 0x1f;
+	regs[R_EP4] = 0x66;
+	regs[R_EP5] = 0x81;
+	regs[R_CPD] = 0xcc;
+	regs[R_CD1] = 0x6c;
+	regs[R_CD2] = 0x00;
+	regs[R_CD3] = 0x00;
+	regs[R_MPD] = 0xcd;
+	regs[R_MD1] = 0x77;
+	regs[R_MD2] = 0x08;
+	regs[R_MD3] = 0x00;
+
+	tda18271_write_regs(fe, R_EP3, 11);
+
+	if ((priv->id) == TDA18271HDC2) {
+		/* main pll cp source on */
+		tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1);
+		msleep(1);
+
+		/* main pll cp source off */
+		tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0);
+	}
+
+	msleep(5); /* pll locking */
+
+	/* launch detector */
+	tda18271_write_regs(fe, R_EP1, 1);
+	msleep(5); /* wanted low measurement */
+
+	regs[R_EP5] = 0x85;
+	regs[R_CPD] = 0xcb;
+	regs[R_CD1] = 0x66;
+	regs[R_CD2] = 0x70;
+
+	tda18271_write_regs(fe, R_EP3, 7);
+	msleep(5); /* pll locking */
+
+	/* launch optimization algorithm */
+	tda18271_write_regs(fe, R_EP2, 1);
+	msleep(30); /* image low optimization completion */
+
+	/* mid-band */
+	regs[R_EP5] = 0x82;
+	regs[R_CPD] = 0xa8;
+	regs[R_CD2] = 0x00;
+	regs[R_MPD] = 0xa9;
+	regs[R_MD1] = 0x73;
+	regs[R_MD2] = 0x1a;
+
+	tda18271_write_regs(fe, R_EP3, 11);
+	msleep(5); /* pll locking */
+
+	/* launch detector */
+	tda18271_write_regs(fe, R_EP1, 1);
+	msleep(5); /* wanted mid measurement */
+
+	regs[R_EP5] = 0x86;
+	regs[R_CPD] = 0xa8;
+	regs[R_CD1] = 0x66;
+	regs[R_CD2] = 0xa0;
+
+	tda18271_write_regs(fe, R_EP3, 7);
+	msleep(5); /* pll locking */
+
+	/* launch optimization algorithm */
+	tda18271_write_regs(fe, R_EP2, 1);
+	msleep(30); /* image mid optimization completion */
+
+	/* high-band */
+	regs[R_EP5] = 0x83;
+	regs[R_CPD] = 0x98;
+	regs[R_CD1] = 0x65;
+	regs[R_CD2] = 0x00;
+	regs[R_MPD] = 0x99;
+	regs[R_MD1] = 0x71;
+	regs[R_MD2] = 0xcd;
+
+	tda18271_write_regs(fe, R_EP3, 11);
+	msleep(5); /* pll locking */
+
+	/* launch detector */
+	tda18271_write_regs(fe, R_EP1, 1);
+	msleep(5); /* wanted high measurement */
+
+	regs[R_EP5] = 0x87;
+	regs[R_CD1] = 0x65;
+	regs[R_CD2] = 0x50;
+
+	tda18271_write_regs(fe, R_EP3, 7);
+	msleep(5); /* pll locking */
+
+	/* launch optimization algorithm */
+	tda18271_write_regs(fe, R_EP2, 1);
+	msleep(30); /* image high optimization completion */
+
+	/* return to normal mode */
+	regs[R_EP4] = 0x64;
+	tda18271_write_regs(fe, R_EP4, 1);
+
+	/* synchronize */
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	return 0;
+}
+
+/*---------------------------------------------------------------------*/
+
+/*
+ *  Standby modes, EP3 [7:5]
+ *
+ *  | SM  || SM_LT || SM_XT || mode description
+ *  |=====\\=======\\=======\\===================================
+ *  |  0  ||   0   ||   0   || normal mode
+ *  |-----||-------||-------||-----------------------------------
+ *  |     ||       ||       || standby mode w/ slave tuner output
+ *  |  1  ||   0   ||   0   || & loop thru & xtal oscillator on
+ *  |-----||-------||-------||-----------------------------------
+ *  |  1  ||   1   ||   0   || standby mode w/ xtal oscillator on
+ *  |-----||-------||-------||-----------------------------------
+ *  |  1  ||   1   ||   1   || power off
+ *
+ */
+
+int tda18271_set_standby_mode(struct dvb_frontend *fe,
+			      int sm, int sm_lt, int sm_xt)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	if (tda18271_debug & DBG_ADV)
+		tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt);
+
+	regs[R_EP3]  &= ~0xe0; /* clear sm, sm_lt, sm_xt */
+	regs[R_EP3]  |= (sm    ? (1 << 7) : 0) |
+			(sm_lt ? (1 << 6) : 0) |
+			(sm_xt ? (1 << 5) : 0);
+
+	return tda18271_write_regs(fe, R_EP3, 1);
+}
+
+/*---------------------------------------------------------------------*/
+
+int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq)
+{
+	/* sets main post divider & divider bytes, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 d, pd;
+	u32 div;
+
+	int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d);
+	if (tda_fail(ret))
+		goto fail;
+
+	regs[R_MPD]   = (0x7f & pd);
+
+	div =  ((d * (freq / 1000)) << 7) / 125;
+
+	regs[R_MD1]   = 0x7f & (div >> 16);
+	regs[R_MD2]   = 0xff & (div >> 8);
+	regs[R_MD3]   = 0xff & div;
+fail:
+	return ret;
+}
+
+int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq)
+{
+	/* sets cal post divider & divider bytes, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 d, pd;
+	u32 div;
+
+	int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d);
+	if (tda_fail(ret))
+		goto fail;
+
+	regs[R_CPD]   = pd;
+
+	div =  ((d * (freq / 1000)) << 7) / 125;
+
+	regs[R_CD1]   = 0x7f & (div >> 16);
+	regs[R_CD2]   = 0xff & (div >> 8);
+	regs[R_CD3]   = 0xff & div;
+fail:
+	return ret;
+}
+
+/*---------------------------------------------------------------------*/
+
+int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets bp filter bits, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val);
+	if (tda_fail(ret))
+		goto fail;
+
+	regs[R_EP1]  &= ~0x07; /* clear bp filter bits */
+	regs[R_EP1]  |= (0x07 & val);
+fail:
+	return ret;
+}
+
+int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets K & M bits, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val);
+	if (tda_fail(ret))
+		goto fail;
+
+	regs[R_EB13] &= ~0x7c; /* clear k & m bits */
+	regs[R_EB13] |= (0x7c & val);
+fail:
+	return ret;
+}
+
+int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets rf band bits, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val);
+	if (tda_fail(ret))
+		goto fail;
+
+	regs[R_EP2]  &= ~0xe0; /* clear rf band bits */
+	regs[R_EP2]  |= (0xe0 & (val << 5));
+fail:
+	return ret;
+}
+
+int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets gain taper bits, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val);
+	if (tda_fail(ret))
+		goto fail;
+
+	regs[R_EP2]  &= ~0x1f; /* clear gain taper bits */
+	regs[R_EP2]  |= (0x1f & val);
+fail:
+	return ret;
+}
+
+int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets IR Meas bits, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val);
+	if (tda_fail(ret))
+		goto fail;
+
+	regs[R_EP5] &= ~0x07;
+	regs[R_EP5] |= (0x07 & val);
+fail:
+	return ret;
+}
+
+int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets rf cal byte (RFC_Cprog), but does not write it */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	int ret = tda18271_lookup_map(fe, RF_CAL, freq, &val);
+	/* The TDA18271HD/C1 rf_cal map lookup is expected to go out of range
+	 * for frequencies above 61.1 MHz.  In these cases, the internal RF
+	 * tracking filters calibration mechanism is used.
+	 *
+	 * There is no need to warn the user about this.
+	 */
+	if (ret < 0)
+		goto fail;
+
+	regs[R_EB14] = val;
+fail:
+	return ret;
+}
+
+int _tda_printk(struct tda18271_priv *state, const char *level,
+		const char *func, const char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+	int rtn;
+
+	va_start(args, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+	if (state)
+		rtn = printk("%s%s: [%d-%04x|%c] %pV",
+			     level, func, i2c_adapter_id(state->i2c_props.adap),
+			     state->i2c_props.addr,
+			     (state->role == TDA18271_MASTER) ? 'M' : 'S',
+			     &vaf);
+	else
+		rtn = printk("%s%s: %pV", level, func, &vaf);
+
+	va_end(args);
+
+	return rtn;
+}
diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c
new file mode 100644
index 0000000..2e67f44
--- /dev/null
+++ b/drivers/media/tuners/tda18271-fe.c
@@ -0,0 +1,1345 @@
+/*
+    tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include "tda18271-priv.h"
+
+int tda18271_debug;
+module_param_named(debug, tda18271_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level "
+		 "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))");
+
+static int tda18271_cal_on_startup = -1;
+module_param_named(cal, tda18271_cal_on_startup, int, 0644);
+MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup");
+
+static DEFINE_MUTEX(tda18271_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
+/*---------------------------------------------------------------------*/
+
+static int tda18271_toggle_output(struct dvb_frontend *fe, int standby)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+
+	int ret = tda18271_set_standby_mode(fe, standby ? 1 : 0,
+			priv->output_opt & TDA18271_OUTPUT_LT_OFF ? 1 : 0,
+			priv->output_opt & TDA18271_OUTPUT_XT_OFF ? 1 : 0);
+
+	if (tda_fail(ret))
+		goto fail;
+
+	tda_dbg("%s mode: xtal oscillator %s, slave tuner loop thru %s\n",
+		standby ? "standby" : "active",
+		priv->output_opt & TDA18271_OUTPUT_XT_OFF ? "off" : "on",
+		priv->output_opt & TDA18271_OUTPUT_LT_OFF ? "off" : "on");
+fail:
+	return ret;
+}
+
+/*---------------------------------------------------------------------*/
+
+static inline int charge_pump_source(struct dvb_frontend *fe, int force)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	return tda18271_charge_pump_source(fe,
+					   (priv->role == TDA18271_SLAVE) ?
+					   TDA18271_CAL_PLL :
+					   TDA18271_MAIN_PLL, force);
+}
+
+static inline void tda18271_set_if_notch(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
+		break;
+	case TDA18271_DIGITAL:
+		regs[R_MPD]  |= 0x80; /* IF notch = 1 */
+		break;
+	}
+}
+
+static int tda18271_channel_configuration(struct dvb_frontend *fe,
+					  struct tda18271_std_map_item *map,
+					  u32 freq, u32 bw)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	int ret;
+	u32 N;
+
+	/* update TV broadcast parameters */
+
+	/* set standard */
+	regs[R_EP3]  &= ~0x1f; /* clear std bits */
+	regs[R_EP3]  |= (map->agc_mode << 3) | map->std;
+
+	if (priv->id == TDA18271HDC2) {
+		/* set rfagc to high speed mode */
+		regs[R_EP3] &= ~0x04;
+	}
+
+	/* set cal mode to normal */
+	regs[R_EP4]  &= ~0x03;
+
+	/* update IF output level */
+	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
+	regs[R_EP4]  |= (map->if_lvl << 2);
+
+	/* update FM_RFn */
+	regs[R_EP4]  &= ~0x80;
+	regs[R_EP4]  |= map->fm_rfn << 7;
+
+	/* update rf top / if top */
+	regs[R_EB22]  = 0x00;
+	regs[R_EB22] |= map->rfagc_top;
+	ret = tda18271_write_regs(fe, R_EB22, 1);
+	if (tda_fail(ret))
+		goto fail;
+
+	/* --------------------------------------------------------------- */
+
+	/* disable Power Level Indicator */
+	regs[R_EP1]  |= 0x40;
+
+	/* make sure thermometer is off */
+	regs[R_TM]   &= ~0x10;
+
+	/* frequency dependent parameters */
+
+	tda18271_calc_ir_measure(fe, &freq);
+
+	tda18271_calc_bp_filter(fe, &freq);
+
+	tda18271_calc_rf_band(fe, &freq);
+
+	tda18271_calc_gain_taper(fe, &freq);
+
+	/* --------------------------------------------------------------- */
+
+	/* dual tuner and agc1 extra configuration */
+
+	switch (priv->role) {
+	case TDA18271_MASTER:
+		regs[R_EB1]  |= 0x04; /* main vco */
+		break;
+	case TDA18271_SLAVE:
+		regs[R_EB1]  &= ~0x04; /* cal vco */
+		break;
+	}
+
+	/* agc1 always active */
+	regs[R_EB1]  &= ~0x02;
+
+	/* agc1 has priority on agc2 */
+	regs[R_EB1]  &= ~0x01;
+
+	ret = tda18271_write_regs(fe, R_EB1, 1);
+	if (tda_fail(ret))
+		goto fail;
+
+	/* --------------------------------------------------------------- */
+
+	N = map->if_freq * 1000 + freq;
+
+	switch (priv->role) {
+	case TDA18271_MASTER:
+		tda18271_calc_main_pll(fe, N);
+		tda18271_set_if_notch(fe);
+		tda18271_write_regs(fe, R_MPD, 4);
+		break;
+	case TDA18271_SLAVE:
+		tda18271_calc_cal_pll(fe, N);
+		tda18271_write_regs(fe, R_CPD, 4);
+
+		regs[R_MPD] = regs[R_CPD] & 0x7f;
+		tda18271_set_if_notch(fe);
+		tda18271_write_regs(fe, R_MPD, 1);
+		break;
+	}
+
+	ret = tda18271_write_regs(fe, R_TM, 7);
+	if (tda_fail(ret))
+		goto fail;
+
+	/* force charge pump source */
+	charge_pump_source(fe, 1);
+
+	msleep(1);
+
+	/* return pll to normal operation */
+	charge_pump_source(fe, 0);
+
+	msleep(20);
+
+	if (priv->id == TDA18271HDC2) {
+		/* set rfagc to normal speed mode */
+		if (map->fm_rfn)
+			regs[R_EP3] &= ~0x04;
+		else
+			regs[R_EP3] |= 0x04;
+		ret = tda18271_write_regs(fe, R_EP3, 1);
+	}
+fail:
+	return ret;
+}
+
+static int tda18271_read_thermometer(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	int tm;
+
+	/* switch thermometer on */
+	regs[R_TM]   |= 0x10;
+	tda18271_write_regs(fe, R_TM, 1);
+
+	/* read thermometer info */
+	tda18271_read_regs(fe);
+
+	if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) ||
+	    (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) {
+
+		if ((regs[R_TM] & 0x20) == 0x20)
+			regs[R_TM] &= ~0x20;
+		else
+			regs[R_TM] |= 0x20;
+
+		tda18271_write_regs(fe, R_TM, 1);
+
+		msleep(10); /* temperature sensing */
+
+		/* read thermometer info */
+		tda18271_read_regs(fe);
+	}
+
+	tm = tda18271_lookup_thermometer(fe);
+
+	/* switch thermometer off */
+	regs[R_TM]   &= ~0x10;
+	tda18271_write_regs(fe, R_TM, 1);
+
+	/* set CAL mode to normal */
+	regs[R_EP4]  &= ~0x03;
+	tda18271_write_regs(fe, R_EP4, 1);
+
+	return tm;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe,
+						     u32 freq)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
+	unsigned char *regs = priv->tda18271_regs;
+	int i, ret;
+	u8 tm_current, dc_over_dt, rf_tab;
+	s32 rfcal_comp, approx;
+
+	/* power up */
+	ret = tda18271_set_standby_mode(fe, 0, 0, 0);
+	if (tda_fail(ret))
+		goto fail;
+
+	/* read die current temperature */
+	tm_current = tda18271_read_thermometer(fe);
+
+	/* frequency dependent parameters */
+
+	tda18271_calc_rf_cal(fe, &freq);
+	rf_tab = regs[R_EB14];
+
+	i = tda18271_lookup_rf_band(fe, &freq, NULL);
+	if (tda_fail(i))
+		return i;
+
+	if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) {
+		approx = map[i].rf_a1 * (s32)(freq / 1000 - map[i].rf1) +
+			map[i].rf_b1 + rf_tab;
+	} else {
+		approx = map[i].rf_a2 * (s32)(freq / 1000 - map[i].rf2) +
+			map[i].rf_b2 + rf_tab;
+	}
+
+	if (approx < 0)
+		approx = 0;
+	if (approx > 255)
+		approx = 255;
+
+	tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt);
+
+	/* calculate temperature compensation */
+	rfcal_comp = dc_over_dt * (s32)(tm_current - priv->tm_rfcal) / 1000;
+
+	regs[R_EB14] = (unsigned char)(approx + rfcal_comp);
+	ret = tda18271_write_regs(fe, R_EB14, 1);
+fail:
+	return ret;
+}
+
+static int tda18271_por(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	int ret;
+
+	/* power up detector 1 */
+	regs[R_EB12] &= ~0x20;
+	ret = tda18271_write_regs(fe, R_EB12, 1);
+	if (tda_fail(ret))
+		goto fail;
+
+	regs[R_EB18] &= ~0x80; /* turn agc1 loop on */
+	regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
+	ret = tda18271_write_regs(fe, R_EB18, 1);
+	if (tda_fail(ret))
+		goto fail;
+
+	regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */
+
+	/* POR mode */
+	ret = tda18271_set_standby_mode(fe, 1, 0, 0);
+	if (tda_fail(ret))
+		goto fail;
+
+	/* disable 1.5 MHz low pass filter */
+	regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */
+	regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */
+	ret = tda18271_write_regs(fe, R_EB21, 3);
+fail:
+	return ret;
+}
+
+static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u32 N;
+
+	/* set CAL mode to normal */
+	regs[R_EP4]  &= ~0x03;
+	tda18271_write_regs(fe, R_EP4, 1);
+
+	/* switch off agc1 */
+	regs[R_EP3]  |= 0x40; /* sm_lt = 1 */
+
+	regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */
+	tda18271_write_regs(fe, R_EB18, 1);
+
+	/* frequency dependent parameters */
+
+	tda18271_calc_bp_filter(fe, &freq);
+	tda18271_calc_gain_taper(fe, &freq);
+	tda18271_calc_rf_band(fe, &freq);
+	tda18271_calc_km(fe, &freq);
+
+	tda18271_write_regs(fe, R_EP1, 3);
+	tda18271_write_regs(fe, R_EB13, 1);
+
+	/* main pll charge pump source */
+	tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1);
+
+	/* cal pll charge pump source */
+	tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 1);
+
+	/* force dcdc converter to 0 V */
+	regs[R_EB14] = 0x00;
+	tda18271_write_regs(fe, R_EB14, 1);
+
+	/* disable plls lock */
+	regs[R_EB20] &= ~0x20;
+	tda18271_write_regs(fe, R_EB20, 1);
+
+	/* set CAL mode to RF tracking filter calibration */
+	regs[R_EP4]  |= 0x03;
+	tda18271_write_regs(fe, R_EP4, 2);
+
+	/* --------------------------------------------------------------- */
+
+	/* set the internal calibration signal */
+	N = freq;
+
+	tda18271_calc_cal_pll(fe, N);
+	tda18271_write_regs(fe, R_CPD, 4);
+
+	/* downconvert internal calibration */
+	N += 1000000;
+
+	tda18271_calc_main_pll(fe, N);
+	tda18271_write_regs(fe, R_MPD, 4);
+
+	msleep(5);
+
+	tda18271_write_regs(fe, R_EP2, 1);
+	tda18271_write_regs(fe, R_EP1, 1);
+	tda18271_write_regs(fe, R_EP2, 1);
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	/* --------------------------------------------------------------- */
+
+	/* normal operation for the main pll */
+	tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0);
+
+	/* normal operation for the cal pll  */
+	tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 0);
+
+	msleep(10); /* plls locking */
+
+	/* launch the rf tracking filters calibration */
+	regs[R_EB20]  |= 0x20;
+	tda18271_write_regs(fe, R_EB20, 1);
+
+	msleep(60); /* calibration */
+
+	/* --------------------------------------------------------------- */
+
+	/* set CAL mode to normal */
+	regs[R_EP4]  &= ~0x03;
+
+	/* switch on agc1 */
+	regs[R_EP3]  &= ~0x40; /* sm_lt = 0 */
+
+	regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
+	tda18271_write_regs(fe, R_EB18, 1);
+
+	tda18271_write_regs(fe, R_EP3, 2);
+
+	/* synchronization */
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	/* get calibration result */
+	tda18271_read_extended(fe);
+
+	return regs[R_EB14];
+}
+
+static int tda18271_powerscan(struct dvb_frontend *fe,
+			      u32 *freq_in, u32 *freq_out)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	int sgn, bcal, count, wait, ret;
+	u8 cid_target;
+	u16 count_limit;
+	u32 freq;
+
+	freq = *freq_in;
+
+	tda18271_calc_rf_band(fe, &freq);
+	tda18271_calc_rf_cal(fe, &freq);
+	tda18271_calc_gain_taper(fe, &freq);
+	tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit);
+
+	tda18271_write_regs(fe, R_EP2, 1);
+	tda18271_write_regs(fe, R_EB14, 1);
+
+	/* downconvert frequency */
+	freq += 1000000;
+
+	tda18271_calc_main_pll(fe, freq);
+	tda18271_write_regs(fe, R_MPD, 4);
+
+	msleep(5); /* pll locking */
+
+	/* detection mode */
+	regs[R_EP4]  &= ~0x03;
+	regs[R_EP4]  |= 0x01;
+	tda18271_write_regs(fe, R_EP4, 1);
+
+	/* launch power detection measurement */
+	tda18271_write_regs(fe, R_EP2, 1);
+
+	/* read power detection info, stored in EB10 */
+	ret = tda18271_read_extended(fe);
+	if (tda_fail(ret))
+		return ret;
+
+	/* algorithm initialization */
+	sgn = 1;
+	*freq_out = *freq_in;
+	bcal = 0;
+	count = 0;
+	wait = false;
+
+	while ((regs[R_EB10] & 0x3f) < cid_target) {
+		/* downconvert updated freq to 1 MHz */
+		freq = *freq_in + (sgn * count) + 1000000;
+
+		tda18271_calc_main_pll(fe, freq);
+		tda18271_write_regs(fe, R_MPD, 4);
+
+		if (wait) {
+			msleep(5); /* pll locking */
+			wait = false;
+		} else
+			udelay(100); /* pll locking */
+
+		/* launch power detection measurement */
+		tda18271_write_regs(fe, R_EP2, 1);
+
+		/* read power detection info, stored in EB10 */
+		ret = tda18271_read_extended(fe);
+		if (tda_fail(ret))
+			return ret;
+
+		count += 200;
+
+		if (count <= count_limit)
+			continue;
+
+		if (sgn <= 0)
+			break;
+
+		sgn = -1 * sgn;
+		count = 200;
+		wait = true;
+	}
+
+	if ((regs[R_EB10] & 0x3f) >= cid_target) {
+		bcal = 1;
+		*freq_out = freq - 1000000;
+	} else
+		bcal = 0;
+
+	tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n",
+		bcal, *freq_in, *freq_out, freq);
+
+	return bcal;
+}
+
+static int tda18271_powerscan_init(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	int ret;
+
+	/* set standard to digital */
+	regs[R_EP3]  &= ~0x1f; /* clear std bits */
+	regs[R_EP3]  |= 0x12;
+
+	/* set cal mode to normal */
+	regs[R_EP4]  &= ~0x03;
+
+	/* update IF output level */
+	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
+
+	ret = tda18271_write_regs(fe, R_EP3, 2);
+	if (tda_fail(ret))
+		goto fail;
+
+	regs[R_EB18] &= ~0x03; /* set agc1_gain to   6 dB */
+	ret = tda18271_write_regs(fe, R_EB18, 1);
+	if (tda_fail(ret))
+		goto fail;
+
+	regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */
+
+	/* 1.5 MHz low pass filter */
+	regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */
+	regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */
+
+	ret = tda18271_write_regs(fe, R_EB21, 3);
+fail:
+	return ret;
+}
+
+static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
+	unsigned char *regs = priv->tda18271_regs;
+	int bcal, rf, i;
+	s32 divisor, dividend;
+#define RF1 0
+#define RF2 1
+#define RF3 2
+	u32 rf_default[3];
+	u32 rf_freq[3];
+	s32 prog_cal[3];
+	s32 prog_tab[3];
+
+	i = tda18271_lookup_rf_band(fe, &freq, NULL);
+
+	if (tda_fail(i))
+		return i;
+
+	rf_default[RF1] = 1000 * map[i].rf1_def;
+	rf_default[RF2] = 1000 * map[i].rf2_def;
+	rf_default[RF3] = 1000 * map[i].rf3_def;
+
+	for (rf = RF1; rf <= RF3; rf++) {
+		if (0 == rf_default[rf])
+			return 0;
+		tda_cal("freq = %d, rf = %d\n", freq, rf);
+
+		/* look for optimized calibration frequency */
+		bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]);
+		if (tda_fail(bcal))
+			return bcal;
+
+		tda18271_calc_rf_cal(fe, &rf_freq[rf]);
+		prog_tab[rf] = (s32)regs[R_EB14];
+
+		if (1 == bcal)
+			prog_cal[rf] =
+				(s32)tda18271_calibrate_rf(fe, rf_freq[rf]);
+		else
+			prog_cal[rf] = prog_tab[rf];
+
+		switch (rf) {
+		case RF1:
+			map[i].rf_a1 = 0;
+			map[i].rf_b1 = (prog_cal[RF1] - prog_tab[RF1]);
+			map[i].rf1   = rf_freq[RF1] / 1000;
+			break;
+		case RF2:
+			dividend = (prog_cal[RF2] - prog_tab[RF2] -
+				    prog_cal[RF1] + prog_tab[RF1]);
+			divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000;
+			map[i].rf_a1 = (dividend / divisor);
+			map[i].rf2   = rf_freq[RF2] / 1000;
+			break;
+		case RF3:
+			dividend = (prog_cal[RF3] - prog_tab[RF3] -
+				    prog_cal[RF2] + prog_tab[RF2]);
+			divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000;
+			map[i].rf_a2 = (dividend / divisor);
+			map[i].rf_b2 = (prog_cal[RF2] - prog_tab[RF2]);
+			map[i].rf3   = rf_freq[RF3] / 1000;
+			break;
+		default:
+			BUG();
+		}
+	}
+
+	return 0;
+}
+
+static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned int i;
+	int ret;
+
+	tda_info("tda18271: performing RF tracking filter calibration\n");
+
+	/* wait for die temperature stabilization */
+	msleep(200);
+
+	ret = tda18271_powerscan_init(fe);
+	if (tda_fail(ret))
+		goto fail;
+
+	/* rf band calibration */
+	for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++) {
+		ret =
+		tda18271_rf_tracking_filters_init(fe, 1000 *
+						  priv->rf_cal_state[i].rfmax);
+		if (tda_fail(ret))
+			goto fail;
+	}
+
+	priv->tm_rfcal = tda18271_read_thermometer(fe);
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda18271c2_rf_cal_init(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	int ret;
+
+	/* test RF_CAL_OK to see if we need init */
+	if ((regs[R_EP1] & 0x10) == 0)
+		priv->cal_initialized = false;
+
+	if (priv->cal_initialized)
+		return 0;
+
+	ret = tda18271_calc_rf_filter_curve(fe);
+	if (tda_fail(ret))
+		goto fail;
+
+	ret = tda18271_por(fe);
+	if (tda_fail(ret))
+		goto fail;
+
+	tda_info("tda18271: RF tracking filter calibration complete\n");
+
+	priv->cal_initialized = true;
+	goto end;
+fail:
+	tda_info("tda18271: RF tracking filter calibration failed!\n");
+end:
+	return ret;
+}
+
+static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe,
+						     u32 freq, u32 bw)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	int ret;
+	u32 N = 0;
+
+	/* calculate bp filter */
+	tda18271_calc_bp_filter(fe, &freq);
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	regs[R_EB4]  &= 0x07;
+	regs[R_EB4]  |= 0x60;
+	tda18271_write_regs(fe, R_EB4, 1);
+
+	regs[R_EB7]   = 0x60;
+	tda18271_write_regs(fe, R_EB7, 1);
+
+	regs[R_EB14]  = 0x00;
+	tda18271_write_regs(fe, R_EB14, 1);
+
+	regs[R_EB20]  = 0xcc;
+	tda18271_write_regs(fe, R_EB20, 1);
+
+	/* set cal mode to RF tracking filter calibration */
+	regs[R_EP4]  |= 0x03;
+
+	/* calculate cal pll */
+
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		N = freq - 1250000;
+		break;
+	case TDA18271_DIGITAL:
+		N = freq + bw / 2;
+		break;
+	}
+
+	tda18271_calc_cal_pll(fe, N);
+
+	/* calculate main pll */
+
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		N = freq - 250000;
+		break;
+	case TDA18271_DIGITAL:
+		N = freq + bw / 2 + 1000000;
+		break;
+	}
+
+	tda18271_calc_main_pll(fe, N);
+
+	ret = tda18271_write_regs(fe, R_EP3, 11);
+	if (tda_fail(ret))
+		return ret;
+
+	msleep(5); /* RF tracking filter calibration initialization */
+
+	/* search for K,M,CO for RF calibration */
+	tda18271_calc_km(fe, &freq);
+	tda18271_write_regs(fe, R_EB13, 1);
+
+	/* search for rf band */
+	tda18271_calc_rf_band(fe, &freq);
+
+	/* search for gain taper */
+	tda18271_calc_gain_taper(fe, &freq);
+
+	tda18271_write_regs(fe, R_EP2, 1);
+	tda18271_write_regs(fe, R_EP1, 1);
+	tda18271_write_regs(fe, R_EP2, 1);
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	regs[R_EB4]  &= 0x07;
+	regs[R_EB4]  |= 0x40;
+	tda18271_write_regs(fe, R_EB4, 1);
+
+	regs[R_EB7]   = 0x40;
+	tda18271_write_regs(fe, R_EB7, 1);
+	msleep(10); /* pll locking */
+
+	regs[R_EB20]  = 0xec;
+	tda18271_write_regs(fe, R_EB20, 1);
+	msleep(60); /* RF tracking filter calibration completion */
+
+	regs[R_EP4]  &= ~0x03; /* set cal mode to normal */
+	tda18271_write_regs(fe, R_EP4, 1);
+
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	/* RF tracking filter correction for VHF_Low band */
+	if (0 == tda18271_calc_rf_cal(fe, &freq))
+		tda18271_write_regs(fe, R_EB14, 1);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda18271_ir_cal_init(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	int ret;
+
+	ret = tda18271_read_regs(fe);
+	if (tda_fail(ret))
+		goto fail;
+
+	/* test IR_CAL_OK to see if we need init */
+	if ((regs[R_EP1] & 0x08) == 0)
+		ret = tda18271_init_regs(fe);
+fail:
+	return ret;
+}
+
+static int tda18271_init(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	int ret;
+
+	mutex_lock(&priv->lock);
+
+	/* full power up */
+	ret = tda18271_set_standby_mode(fe, 0, 0, 0);
+	if (tda_fail(ret))
+		goto fail;
+
+	/* initialization */
+	ret = tda18271_ir_cal_init(fe);
+	if (tda_fail(ret))
+		goto fail;
+
+	if (priv->id == TDA18271HDC2)
+		tda18271c2_rf_cal_init(fe);
+fail:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int tda18271_sleep(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	int ret;
+
+	mutex_lock(&priv->lock);
+
+	/* enter standby mode, with required output features enabled */
+	ret = tda18271_toggle_output(fe, 1);
+
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda18271_agc(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	int ret = 0;
+
+	switch (priv->config) {
+	case 0:
+		/* no external agc configuration required */
+		if (tda18271_debug & DBG_ADV)
+			tda_dbg("no agc configuration provided\n");
+		break;
+	case 3:
+		/* switch with GPIO of saa713x */
+		tda_dbg("invoking callback\n");
+		if (fe->callback)
+			ret = fe->callback(priv->i2c_props.adap->algo_data,
+					   DVB_FRONTEND_COMPONENT_TUNER,
+					   TDA18271_CALLBACK_CMD_AGC_ENABLE,
+					   priv->mode);
+		break;
+	case 1:
+	case 2:
+	default:
+		/* n/a - currently not supported */
+		tda_err("unsupported configuration: %d\n", priv->config);
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int tda18271_tune(struct dvb_frontend *fe,
+			 struct tda18271_std_map_item *map, u32 freq, u32 bw)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	int ret;
+
+	tda_dbg("freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d\n",
+		freq, map->if_freq, bw, map->agc_mode, map->std);
+
+	ret = tda18271_agc(fe);
+	if (tda_fail(ret))
+		tda_warn("failed to configure agc\n");
+
+	ret = tda18271_init(fe);
+	if (tda_fail(ret))
+		goto fail;
+
+	mutex_lock(&priv->lock);
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		tda18271c1_rf_tracking_filter_calibration(fe, freq, bw);
+		break;
+	case TDA18271HDC2:
+		tda18271c2_rf_tracking_filters_correction(fe, freq);
+		break;
+	}
+	ret = tda18271_channel_configuration(fe, map, freq, bw);
+
+	mutex_unlock(&priv->lock);
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda18271_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 delsys = c->delivery_system;
+	u32 bw = c->bandwidth_hz;
+	u32 freq = c->frequency;
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_std_map *std_map = &priv->std;
+	struct tda18271_std_map_item *map;
+	int ret;
+
+	priv->mode = TDA18271_DIGITAL;
+
+	switch (delsys) {
+	case SYS_ATSC:
+		map = &std_map->atsc_6;
+		bw = 6000000;
+		break;
+	case SYS_ISDBT:
+	case SYS_DVBT:
+	case SYS_DVBT2:
+		if (bw <= 6000000) {
+			map = &std_map->dvbt_6;
+		} else if (bw <= 7000000) {
+			map = &std_map->dvbt_7;
+		} else {
+			map = &std_map->dvbt_8;
+		}
+		break;
+	case SYS_DVBC_ANNEX_B:
+		bw = 6000000;
+		/* falltrough */
+	case SYS_DVBC_ANNEX_A:
+	case SYS_DVBC_ANNEX_C:
+		if (bw <= 6000000) {
+			map = &std_map->qam_6;
+		} else if (bw <= 7000000) {
+			map = &std_map->qam_7;
+		} else {
+			map = &std_map->qam_8;
+		}
+		break;
+	default:
+		tda_warn("modulation type not supported!\n");
+		return -EINVAL;
+	}
+
+	/* When tuning digital, the analog demod must be tri-stated */
+	if (fe->ops.analog_ops.standby)
+		fe->ops.analog_ops.standby(fe);
+
+	ret = tda18271_tune(fe, map, freq, bw);
+
+	if (tda_fail(ret))
+		goto fail;
+
+	priv->if_freq   = map->if_freq;
+	priv->frequency = freq;
+	priv->bandwidth = bw;
+fail:
+	return ret;
+}
+
+static int tda18271_set_analog_params(struct dvb_frontend *fe,
+				      struct analog_parameters *params)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_std_map *std_map = &priv->std;
+	struct tda18271_std_map_item *map;
+	char *mode;
+	int ret;
+	u32 freq = params->frequency * 125 *
+		((params->mode == V4L2_TUNER_RADIO) ? 1 : 1000) / 2;
+
+	priv->mode = TDA18271_ANALOG;
+
+	if (params->mode == V4L2_TUNER_RADIO) {
+		map = &std_map->fm_radio;
+		mode = "fm";
+	} else if (params->std & V4L2_STD_MN) {
+		map = &std_map->atv_mn;
+		mode = "MN";
+	} else if (params->std & V4L2_STD_B) {
+		map = &std_map->atv_b;
+		mode = "B";
+	} else if (params->std & V4L2_STD_GH) {
+		map = &std_map->atv_gh;
+		mode = "GH";
+	} else if (params->std & V4L2_STD_PAL_I) {
+		map = &std_map->atv_i;
+		mode = "I";
+	} else if (params->std & V4L2_STD_DK) {
+		map = &std_map->atv_dk;
+		mode = "DK";
+	} else if (params->std & V4L2_STD_SECAM_L) {
+		map = &std_map->atv_l;
+		mode = "L";
+	} else if (params->std & V4L2_STD_SECAM_LC) {
+		map = &std_map->atv_lc;
+		mode = "L'";
+	} else {
+		map = &std_map->atv_i;
+		mode = "xx";
+	}
+
+	tda_dbg("setting tda18271 to system %s\n", mode);
+
+	ret = tda18271_tune(fe, map, freq, 0);
+
+	if (tda_fail(ret))
+		goto fail;
+
+	priv->if_freq   = map->if_freq;
+	priv->frequency = freq;
+	priv->bandwidth = 0;
+fail:
+	return ret;
+}
+
+static int tda18271_release(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+
+	mutex_lock(&tda18271_list_mutex);
+
+	if (priv)
+		hybrid_tuner_release_state(priv);
+
+	mutex_unlock(&tda18271_list_mutex);
+
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+static int tda18271_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	*frequency = (u32)priv->if_freq * 1000;
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+#define tda18271_update_std(std_cfg, name) do {				\
+	if (map->std_cfg.if_freq +					\
+		map->std_cfg.agc_mode + map->std_cfg.std +		\
+		map->std_cfg.if_lvl + map->std_cfg.rfagc_top > 0) {	\
+		tda_dbg("Using custom std config for %s\n", name);	\
+		memcpy(&std->std_cfg, &map->std_cfg,			\
+			sizeof(struct tda18271_std_map_item));		\
+	} } while (0)
+
+#define tda18271_dump_std_item(std_cfg, name) do {			\
+	tda_dbg("(%s) if_freq = %d, agc_mode = %d, std = %d, "		\
+		"if_lvl = %d, rfagc_top = 0x%02x\n",			\
+		name, std->std_cfg.if_freq,				\
+		std->std_cfg.agc_mode, std->std_cfg.std,		\
+		std->std_cfg.if_lvl, std->std_cfg.rfagc_top);		\
+	} while (0)
+
+static int tda18271_dump_std_map(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_std_map *std = &priv->std;
+
+	tda_dbg("========== STANDARD MAP SETTINGS ==========\n");
+	tda18271_dump_std_item(fm_radio, "  fm  ");
+	tda18271_dump_std_item(atv_b,  "atv b ");
+	tda18271_dump_std_item(atv_dk, "atv dk");
+	tda18271_dump_std_item(atv_gh, "atv gh");
+	tda18271_dump_std_item(atv_i,  "atv i ");
+	tda18271_dump_std_item(atv_l,  "atv l ");
+	tda18271_dump_std_item(atv_lc, "atv l'");
+	tda18271_dump_std_item(atv_mn, "atv mn");
+	tda18271_dump_std_item(atsc_6, "atsc 6");
+	tda18271_dump_std_item(dvbt_6, "dvbt 6");
+	tda18271_dump_std_item(dvbt_7, "dvbt 7");
+	tda18271_dump_std_item(dvbt_8, "dvbt 8");
+	tda18271_dump_std_item(qam_6,  "qam 6 ");
+	tda18271_dump_std_item(qam_8,  "qam 8 ");
+
+	return 0;
+}
+
+static int tda18271_update_std_map(struct dvb_frontend *fe,
+				   struct tda18271_std_map *map)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_std_map *std = &priv->std;
+
+	if (!map)
+		return -EINVAL;
+
+	tda18271_update_std(fm_radio, "fm");
+	tda18271_update_std(atv_b,  "atv b");
+	tda18271_update_std(atv_dk, "atv dk");
+	tda18271_update_std(atv_gh, "atv gh");
+	tda18271_update_std(atv_i,  "atv i");
+	tda18271_update_std(atv_l,  "atv l");
+	tda18271_update_std(atv_lc, "atv l'");
+	tda18271_update_std(atv_mn, "atv mn");
+	tda18271_update_std(atsc_6, "atsc 6");
+	tda18271_update_std(dvbt_6, "dvbt 6");
+	tda18271_update_std(dvbt_7, "dvbt 7");
+	tda18271_update_std(dvbt_8, "dvbt 8");
+	tda18271_update_std(qam_6,  "qam 6");
+	tda18271_update_std(qam_8,  "qam 8");
+
+	return 0;
+}
+
+static int tda18271_get_id(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	char *name;
+
+	mutex_lock(&priv->lock);
+	tda18271_read_regs(fe);
+	mutex_unlock(&priv->lock);
+
+	switch (regs[R_ID] & 0x7f) {
+	case 3:
+		name = "TDA18271HD/C1";
+		priv->id = TDA18271HDC1;
+		break;
+	case 4:
+		name = "TDA18271HD/C2";
+		priv->id = TDA18271HDC2;
+		break;
+	default:
+		tda_info("Unknown device (%i) detected @ %d-%04x, device not supported.\n",
+			 regs[R_ID], i2c_adapter_id(priv->i2c_props.adap),
+			 priv->i2c_props.addr);
+		return -EINVAL;
+	}
+
+	tda_info("%s detected @ %d-%04x\n", name,
+		 i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr);
+
+	return 0;
+}
+
+static int tda18271_setup_configuration(struct dvb_frontend *fe,
+					struct tda18271_config *cfg)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+
+	priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
+	priv->role = (cfg) ? cfg->role : TDA18271_MASTER;
+	priv->config = (cfg) ? cfg->config : 0;
+	priv->small_i2c = (cfg) ?
+		cfg->small_i2c : TDA18271_39_BYTE_CHUNK_INIT;
+	priv->output_opt = (cfg) ?
+		cfg->output_opt : TDA18271_OUTPUT_LT_XT_ON;
+
+	return 0;
+}
+
+static inline int tda18271_need_cal_on_startup(struct tda18271_config *cfg)
+{
+	/* tda18271_cal_on_startup == -1 when cal module option is unset */
+	return ((tda18271_cal_on_startup == -1) ?
+		/* honor configuration setting */
+		((cfg) && (cfg->rf_cal_on_startup)) :
+		/* module option overrides configuration setting */
+		(tda18271_cal_on_startup)) ? 1 : 0;
+}
+
+static int tda18271_set_config(struct dvb_frontend *fe, void *priv_cfg)
+{
+	struct tda18271_config *cfg = (struct tda18271_config *) priv_cfg;
+
+	tda18271_setup_configuration(fe, cfg);
+
+	if (tda18271_need_cal_on_startup(cfg))
+		tda18271_init(fe);
+
+	/* override default std map with values in config struct */
+	if ((cfg) && (cfg->std_map))
+		tda18271_update_std_map(fe, cfg->std_map);
+
+	return 0;
+}
+
+static const struct dvb_tuner_ops tda18271_tuner_ops = {
+	.info = {
+		.name = "NXP TDA18271HD",
+		.frequency_min  =  45000000,
+		.frequency_max  = 864000000,
+		.frequency_step =     62500
+	},
+	.init              = tda18271_init,
+	.sleep             = tda18271_sleep,
+	.set_params        = tda18271_set_params,
+	.set_analog_params = tda18271_set_analog_params,
+	.release           = tda18271_release,
+	.set_config        = tda18271_set_config,
+	.get_frequency     = tda18271_get_frequency,
+	.get_bandwidth     = tda18271_get_bandwidth,
+	.get_if_frequency  = tda18271_get_if_frequency,
+};
+
+struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
+				     struct i2c_adapter *i2c,
+				     struct tda18271_config *cfg)
+{
+	struct tda18271_priv *priv = NULL;
+	int instance, ret;
+
+	mutex_lock(&tda18271_list_mutex);
+
+	instance = hybrid_tuner_request_state(struct tda18271_priv, priv,
+					      hybrid_tuner_instance_list,
+					      i2c, addr, "tda18271");
+	switch (instance) {
+	case 0:
+		goto fail;
+	case 1:
+		/* new tuner instance */
+		fe->tuner_priv = priv;
+
+		tda18271_setup_configuration(fe, cfg);
+
+		priv->cal_initialized = false;
+		mutex_init(&priv->lock);
+
+		ret = tda18271_get_id(fe);
+		if (tda_fail(ret))
+			goto fail;
+
+		ret = tda18271_assign_map_layout(fe);
+		if (tda_fail(ret))
+			goto fail;
+
+		mutex_lock(&priv->lock);
+		tda18271_init_regs(fe);
+
+		if ((tda18271_need_cal_on_startup(cfg)) &&
+		    (priv->id == TDA18271HDC2))
+			tda18271c2_rf_cal_init(fe);
+
+		mutex_unlock(&priv->lock);
+		break;
+	default:
+		/* existing tuner instance */
+		fe->tuner_priv = priv;
+
+		/* allow dvb driver to override configuration settings */
+		if (cfg) {
+			if (cfg->gate != TDA18271_GATE_ANALOG)
+				priv->gate = cfg->gate;
+			if (cfg->role)
+				priv->role = cfg->role;
+			if (cfg->config)
+				priv->config = cfg->config;
+			if (cfg->small_i2c)
+				priv->small_i2c = cfg->small_i2c;
+			if (cfg->output_opt)
+				priv->output_opt = cfg->output_opt;
+			if (cfg->std_map)
+				tda18271_update_std_map(fe, cfg->std_map);
+		}
+		if (tda18271_need_cal_on_startup(cfg))
+			tda18271_init(fe);
+		break;
+	}
+
+	/* override default std map with values in config struct */
+	if ((cfg) && (cfg->std_map))
+		tda18271_update_std_map(fe, cfg->std_map);
+
+	mutex_unlock(&tda18271_list_mutex);
+
+	memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+	if (tda18271_debug & (DBG_MAP | DBG_ADV))
+		tda18271_dump_std_map(fe);
+
+	return fe;
+fail:
+	mutex_unlock(&tda18271_list_mutex);
+
+	tda18271_release(fe);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(tda18271_attach);
+MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.4");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/tuners/tda18271-maps.c b/drivers/media/tuners/tda18271-maps.c
new file mode 100644
index 0000000..fb881c6
--- /dev/null
+++ b/drivers/media/tuners/tda18271-maps.c
@@ -0,0 +1,1317 @@
+/*
+    tda18271-maps.c - driver for the Philips / NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "tda18271-priv.h"
+
+struct tda18271_pll_map {
+	u32 lomax;
+	u8 pd; /* post div */
+	u8 d;  /*      div */
+};
+
+struct tda18271_map {
+	u32 rfmax;
+	u8  val;
+};
+
+/*---------------------------------------------------------------------*/
+
+static struct tda18271_pll_map tda18271c1_main_pll[] = {
+	{ .lomax =  32000, .pd = 0x5f, .d = 0xf0 },
+	{ .lomax =  35000, .pd = 0x5e, .d = 0xe0 },
+	{ .lomax =  37000, .pd = 0x5d, .d = 0xd0 },
+	{ .lomax =  41000, .pd = 0x5c, .d = 0xc0 },
+	{ .lomax =  44000, .pd = 0x5b, .d = 0xb0 },
+	{ .lomax =  49000, .pd = 0x5a, .d = 0xa0 },
+	{ .lomax =  54000, .pd = 0x59, .d = 0x90 },
+	{ .lomax =  61000, .pd = 0x58, .d = 0x80 },
+	{ .lomax =  65000, .pd = 0x4f, .d = 0x78 },
+	{ .lomax =  70000, .pd = 0x4e, .d = 0x70 },
+	{ .lomax =  75000, .pd = 0x4d, .d = 0x68 },
+	{ .lomax =  82000, .pd = 0x4c, .d = 0x60 },
+	{ .lomax =  89000, .pd = 0x4b, .d = 0x58 },
+	{ .lomax =  98000, .pd = 0x4a, .d = 0x50 },
+	{ .lomax = 109000, .pd = 0x49, .d = 0x48 },
+	{ .lomax = 123000, .pd = 0x48, .d = 0x40 },
+	{ .lomax = 131000, .pd = 0x3f, .d = 0x3c },
+	{ .lomax = 141000, .pd = 0x3e, .d = 0x38 },
+	{ .lomax = 151000, .pd = 0x3d, .d = 0x34 },
+	{ .lomax = 164000, .pd = 0x3c, .d = 0x30 },
+	{ .lomax = 179000, .pd = 0x3b, .d = 0x2c },
+	{ .lomax = 197000, .pd = 0x3a, .d = 0x28 },
+	{ .lomax = 219000, .pd = 0x39, .d = 0x24 },
+	{ .lomax = 246000, .pd = 0x38, .d = 0x20 },
+	{ .lomax = 263000, .pd = 0x2f, .d = 0x1e },
+	{ .lomax = 282000, .pd = 0x2e, .d = 0x1c },
+	{ .lomax = 303000, .pd = 0x2d, .d = 0x1a },
+	{ .lomax = 329000, .pd = 0x2c, .d = 0x18 },
+	{ .lomax = 359000, .pd = 0x2b, .d = 0x16 },
+	{ .lomax = 395000, .pd = 0x2a, .d = 0x14 },
+	{ .lomax = 438000, .pd = 0x29, .d = 0x12 },
+	{ .lomax = 493000, .pd = 0x28, .d = 0x10 },
+	{ .lomax = 526000, .pd = 0x1f, .d = 0x0f },
+	{ .lomax = 564000, .pd = 0x1e, .d = 0x0e },
+	{ .lomax = 607000, .pd = 0x1d, .d = 0x0d },
+	{ .lomax = 658000, .pd = 0x1c, .d = 0x0c },
+	{ .lomax = 718000, .pd = 0x1b, .d = 0x0b },
+	{ .lomax = 790000, .pd = 0x1a, .d = 0x0a },
+	{ .lomax = 877000, .pd = 0x19, .d = 0x09 },
+	{ .lomax = 987000, .pd = 0x18, .d = 0x08 },
+	{ .lomax =      0, .pd = 0x00, .d = 0x00 }, /* end */
+};
+
+static struct tda18271_pll_map tda18271c2_main_pll[] = {
+	{ .lomax =  33125, .pd = 0x57, .d = 0xf0 },
+	{ .lomax =  35500, .pd = 0x56, .d = 0xe0 },
+	{ .lomax =  38188, .pd = 0x55, .d = 0xd0 },
+	{ .lomax =  41375, .pd = 0x54, .d = 0xc0 },
+	{ .lomax =  45125, .pd = 0x53, .d = 0xb0 },
+	{ .lomax =  49688, .pd = 0x52, .d = 0xa0 },
+	{ .lomax =  55188, .pd = 0x51, .d = 0x90 },
+	{ .lomax =  62125, .pd = 0x50, .d = 0x80 },
+	{ .lomax =  66250, .pd = 0x47, .d = 0x78 },
+	{ .lomax =  71000, .pd = 0x46, .d = 0x70 },
+	{ .lomax =  76375, .pd = 0x45, .d = 0x68 },
+	{ .lomax =  82750, .pd = 0x44, .d = 0x60 },
+	{ .lomax =  90250, .pd = 0x43, .d = 0x58 },
+	{ .lomax =  99375, .pd = 0x42, .d = 0x50 },
+	{ .lomax = 110375, .pd = 0x41, .d = 0x48 },
+	{ .lomax = 124250, .pd = 0x40, .d = 0x40 },
+	{ .lomax = 132500, .pd = 0x37, .d = 0x3c },
+	{ .lomax = 142000, .pd = 0x36, .d = 0x38 },
+	{ .lomax = 152750, .pd = 0x35, .d = 0x34 },
+	{ .lomax = 165500, .pd = 0x34, .d = 0x30 },
+	{ .lomax = 180500, .pd = 0x33, .d = 0x2c },
+	{ .lomax = 198750, .pd = 0x32, .d = 0x28 },
+	{ .lomax = 220750, .pd = 0x31, .d = 0x24 },
+	{ .lomax = 248500, .pd = 0x30, .d = 0x20 },
+	{ .lomax = 265000, .pd = 0x27, .d = 0x1e },
+	{ .lomax = 284000, .pd = 0x26, .d = 0x1c },
+	{ .lomax = 305500, .pd = 0x25, .d = 0x1a },
+	{ .lomax = 331000, .pd = 0x24, .d = 0x18 },
+	{ .lomax = 361000, .pd = 0x23, .d = 0x16 },
+	{ .lomax = 397500, .pd = 0x22, .d = 0x14 },
+	{ .lomax = 441500, .pd = 0x21, .d = 0x12 },
+	{ .lomax = 497000, .pd = 0x20, .d = 0x10 },
+	{ .lomax = 530000, .pd = 0x17, .d = 0x0f },
+	{ .lomax = 568000, .pd = 0x16, .d = 0x0e },
+	{ .lomax = 611000, .pd = 0x15, .d = 0x0d },
+	{ .lomax = 662000, .pd = 0x14, .d = 0x0c },
+	{ .lomax = 722000, .pd = 0x13, .d = 0x0b },
+	{ .lomax = 795000, .pd = 0x12, .d = 0x0a },
+	{ .lomax = 883000, .pd = 0x11, .d = 0x09 },
+	{ .lomax = 994000, .pd = 0x10, .d = 0x08 },
+	{ .lomax =      0, .pd = 0x00, .d = 0x00 }, /* end */
+};
+
+static struct tda18271_pll_map tda18271c1_cal_pll[] = {
+	{ .lomax =   33000, .pd = 0xdd, .d = 0xd0 },
+	{ .lomax =   36000, .pd = 0xdc, .d = 0xc0 },
+	{ .lomax =   40000, .pd = 0xdb, .d = 0xb0 },
+	{ .lomax =   44000, .pd = 0xda, .d = 0xa0 },
+	{ .lomax =   49000, .pd = 0xd9, .d = 0x90 },
+	{ .lomax =   55000, .pd = 0xd8, .d = 0x80 },
+	{ .lomax =   63000, .pd = 0xd3, .d = 0x70 },
+	{ .lomax =   67000, .pd = 0xcd, .d = 0x68 },
+	{ .lomax =   73000, .pd = 0xcc, .d = 0x60 },
+	{ .lomax =   80000, .pd = 0xcb, .d = 0x58 },
+	{ .lomax =   88000, .pd = 0xca, .d = 0x50 },
+	{ .lomax =   98000, .pd = 0xc9, .d = 0x48 },
+	{ .lomax =  110000, .pd = 0xc8, .d = 0x40 },
+	{ .lomax =  126000, .pd = 0xc3, .d = 0x38 },
+	{ .lomax =  135000, .pd = 0xbd, .d = 0x34 },
+	{ .lomax =  147000, .pd = 0xbc, .d = 0x30 },
+	{ .lomax =  160000, .pd = 0xbb, .d = 0x2c },
+	{ .lomax =  176000, .pd = 0xba, .d = 0x28 },
+	{ .lomax =  196000, .pd = 0xb9, .d = 0x24 },
+	{ .lomax =  220000, .pd = 0xb8, .d = 0x20 },
+	{ .lomax =  252000, .pd = 0xb3, .d = 0x1c },
+	{ .lomax =  271000, .pd = 0xad, .d = 0x1a },
+	{ .lomax =  294000, .pd = 0xac, .d = 0x18 },
+	{ .lomax =  321000, .pd = 0xab, .d = 0x16 },
+	{ .lomax =  353000, .pd = 0xaa, .d = 0x14 },
+	{ .lomax =  392000, .pd = 0xa9, .d = 0x12 },
+	{ .lomax =  441000, .pd = 0xa8, .d = 0x10 },
+	{ .lomax =  505000, .pd = 0xa3, .d = 0x0e },
+	{ .lomax =  543000, .pd = 0x9d, .d = 0x0d },
+	{ .lomax =  589000, .pd = 0x9c, .d = 0x0c },
+	{ .lomax =  642000, .pd = 0x9b, .d = 0x0b },
+	{ .lomax =  707000, .pd = 0x9a, .d = 0x0a },
+	{ .lomax =  785000, .pd = 0x99, .d = 0x09 },
+	{ .lomax =  883000, .pd = 0x98, .d = 0x08 },
+	{ .lomax = 1010000, .pd = 0x93, .d = 0x07 },
+	{ .lomax =       0, .pd = 0x00, .d = 0x00 }, /* end */
+};
+
+static struct tda18271_pll_map tda18271c2_cal_pll[] = {
+	{ .lomax =   33813, .pd = 0xdd, .d = 0xd0 },
+	{ .lomax =   36625, .pd = 0xdc, .d = 0xc0 },
+	{ .lomax =   39938, .pd = 0xdb, .d = 0xb0 },
+	{ .lomax =   43938, .pd = 0xda, .d = 0xa0 },
+	{ .lomax =   48813, .pd = 0xd9, .d = 0x90 },
+	{ .lomax =   54938, .pd = 0xd8, .d = 0x80 },
+	{ .lomax =   62813, .pd = 0xd3, .d = 0x70 },
+	{ .lomax =   67625, .pd = 0xcd, .d = 0x68 },
+	{ .lomax =   73250, .pd = 0xcc, .d = 0x60 },
+	{ .lomax =   79875, .pd = 0xcb, .d = 0x58 },
+	{ .lomax =   87875, .pd = 0xca, .d = 0x50 },
+	{ .lomax =   97625, .pd = 0xc9, .d = 0x48 },
+	{ .lomax =  109875, .pd = 0xc8, .d = 0x40 },
+	{ .lomax =  125625, .pd = 0xc3, .d = 0x38 },
+	{ .lomax =  135250, .pd = 0xbd, .d = 0x34 },
+	{ .lomax =  146500, .pd = 0xbc, .d = 0x30 },
+	{ .lomax =  159750, .pd = 0xbb, .d = 0x2c },
+	{ .lomax =  175750, .pd = 0xba, .d = 0x28 },
+	{ .lomax =  195250, .pd = 0xb9, .d = 0x24 },
+	{ .lomax =  219750, .pd = 0xb8, .d = 0x20 },
+	{ .lomax =  251250, .pd = 0xb3, .d = 0x1c },
+	{ .lomax =  270500, .pd = 0xad, .d = 0x1a },
+	{ .lomax =  293000, .pd = 0xac, .d = 0x18 },
+	{ .lomax =  319500, .pd = 0xab, .d = 0x16 },
+	{ .lomax =  351500, .pd = 0xaa, .d = 0x14 },
+	{ .lomax =  390500, .pd = 0xa9, .d = 0x12 },
+	{ .lomax =  439500, .pd = 0xa8, .d = 0x10 },
+	{ .lomax =  502500, .pd = 0xa3, .d = 0x0e },
+	{ .lomax =  541000, .pd = 0x9d, .d = 0x0d },
+	{ .lomax =  586000, .pd = 0x9c, .d = 0x0c },
+	{ .lomax =  639000, .pd = 0x9b, .d = 0x0b },
+	{ .lomax =  703000, .pd = 0x9a, .d = 0x0a },
+	{ .lomax =  781000, .pd = 0x99, .d = 0x09 },
+	{ .lomax =  879000, .pd = 0x98, .d = 0x08 },
+	{ .lomax =       0, .pd = 0x00, .d = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271_bp_filter[] = {
+	{ .rfmax =  62000, .val = 0x00 },
+	{ .rfmax =  84000, .val = 0x01 },
+	{ .rfmax = 100000, .val = 0x02 },
+	{ .rfmax = 140000, .val = 0x03 },
+	{ .rfmax = 170000, .val = 0x04 },
+	{ .rfmax = 180000, .val = 0x05 },
+	{ .rfmax = 865000, .val = 0x06 },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271c1_km[] = {
+	{ .rfmax =  61100, .val = 0x74 },
+	{ .rfmax = 350000, .val = 0x40 },
+	{ .rfmax = 720000, .val = 0x30 },
+	{ .rfmax = 865000, .val = 0x40 },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271c2_km[] = {
+	{ .rfmax =  47900, .val = 0x38 },
+	{ .rfmax =  61100, .val = 0x44 },
+	{ .rfmax = 350000, .val = 0x30 },
+	{ .rfmax = 720000, .val = 0x24 },
+	{ .rfmax = 865000, .val = 0x3c },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271_rf_band[] = {
+	{ .rfmax =  47900, .val = 0x00 },
+	{ .rfmax =  61100, .val = 0x01 },
+	{ .rfmax = 152600, .val = 0x02 },
+	{ .rfmax = 164700, .val = 0x03 },
+	{ .rfmax = 203500, .val = 0x04 },
+	{ .rfmax = 457800, .val = 0x05 },
+	{ .rfmax = 865000, .val = 0x06 },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271_gain_taper[] = {
+	{ .rfmax =  45400, .val = 0x1f },
+	{ .rfmax =  45800, .val = 0x1e },
+	{ .rfmax =  46200, .val = 0x1d },
+	{ .rfmax =  46700, .val = 0x1c },
+	{ .rfmax =  47100, .val = 0x1b },
+	{ .rfmax =  47500, .val = 0x1a },
+	{ .rfmax =  47900, .val = 0x19 },
+	{ .rfmax =  49600, .val = 0x17 },
+	{ .rfmax =  51200, .val = 0x16 },
+	{ .rfmax =  52900, .val = 0x15 },
+	{ .rfmax =  54500, .val = 0x14 },
+	{ .rfmax =  56200, .val = 0x13 },
+	{ .rfmax =  57800, .val = 0x12 },
+	{ .rfmax =  59500, .val = 0x11 },
+	{ .rfmax =  61100, .val = 0x10 },
+	{ .rfmax =  67600, .val = 0x0d },
+	{ .rfmax =  74200, .val = 0x0c },
+	{ .rfmax =  80700, .val = 0x0b },
+	{ .rfmax =  87200, .val = 0x0a },
+	{ .rfmax =  93800, .val = 0x09 },
+	{ .rfmax = 100300, .val = 0x08 },
+	{ .rfmax = 106900, .val = 0x07 },
+	{ .rfmax = 113400, .val = 0x06 },
+	{ .rfmax = 119900, .val = 0x05 },
+	{ .rfmax = 126500, .val = 0x04 },
+	{ .rfmax = 133000, .val = 0x03 },
+	{ .rfmax = 139500, .val = 0x02 },
+	{ .rfmax = 146100, .val = 0x01 },
+	{ .rfmax = 152600, .val = 0x00 },
+	{ .rfmax = 154300, .val = 0x1f },
+	{ .rfmax = 156100, .val = 0x1e },
+	{ .rfmax = 157800, .val = 0x1d },
+	{ .rfmax = 159500, .val = 0x1c },
+	{ .rfmax = 161200, .val = 0x1b },
+	{ .rfmax = 163000, .val = 0x1a },
+	{ .rfmax = 164700, .val = 0x19 },
+	{ .rfmax = 170200, .val = 0x17 },
+	{ .rfmax = 175800, .val = 0x16 },
+	{ .rfmax = 181300, .val = 0x15 },
+	{ .rfmax = 186900, .val = 0x14 },
+	{ .rfmax = 192400, .val = 0x13 },
+	{ .rfmax = 198000, .val = 0x12 },
+	{ .rfmax = 203500, .val = 0x11 },
+	{ .rfmax = 216200, .val = 0x14 },
+	{ .rfmax = 228900, .val = 0x13 },
+	{ .rfmax = 241600, .val = 0x12 },
+	{ .rfmax = 254400, .val = 0x11 },
+	{ .rfmax = 267100, .val = 0x10 },
+	{ .rfmax = 279800, .val = 0x0f },
+	{ .rfmax = 292500, .val = 0x0e },
+	{ .rfmax = 305200, .val = 0x0d },
+	{ .rfmax = 317900, .val = 0x0c },
+	{ .rfmax = 330700, .val = 0x0b },
+	{ .rfmax = 343400, .val = 0x0a },
+	{ .rfmax = 356100, .val = 0x09 },
+	{ .rfmax = 368800, .val = 0x08 },
+	{ .rfmax = 381500, .val = 0x07 },
+	{ .rfmax = 394200, .val = 0x06 },
+	{ .rfmax = 406900, .val = 0x05 },
+	{ .rfmax = 419700, .val = 0x04 },
+	{ .rfmax = 432400, .val = 0x03 },
+	{ .rfmax = 445100, .val = 0x02 },
+	{ .rfmax = 457800, .val = 0x01 },
+	{ .rfmax = 476300, .val = 0x19 },
+	{ .rfmax = 494800, .val = 0x18 },
+	{ .rfmax = 513300, .val = 0x17 },
+	{ .rfmax = 531800, .val = 0x16 },
+	{ .rfmax = 550300, .val = 0x15 },
+	{ .rfmax = 568900, .val = 0x14 },
+	{ .rfmax = 587400, .val = 0x13 },
+	{ .rfmax = 605900, .val = 0x12 },
+	{ .rfmax = 624400, .val = 0x11 },
+	{ .rfmax = 642900, .val = 0x10 },
+	{ .rfmax = 661400, .val = 0x0f },
+	{ .rfmax = 679900, .val = 0x0e },
+	{ .rfmax = 698400, .val = 0x0d },
+	{ .rfmax = 716900, .val = 0x0c },
+	{ .rfmax = 735400, .val = 0x0b },
+	{ .rfmax = 753900, .val = 0x0a },
+	{ .rfmax = 772500, .val = 0x09 },
+	{ .rfmax = 791000, .val = 0x08 },
+	{ .rfmax = 809500, .val = 0x07 },
+	{ .rfmax = 828000, .val = 0x06 },
+	{ .rfmax = 846500, .val = 0x05 },
+	{ .rfmax = 865000, .val = 0x04 },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271c1_rf_cal[] = {
+	{ .rfmax = 41000, .val = 0x1e },
+	{ .rfmax = 43000, .val = 0x30 },
+	{ .rfmax = 45000, .val = 0x43 },
+	{ .rfmax = 46000, .val = 0x4d },
+	{ .rfmax = 47000, .val = 0x54 },
+	{ .rfmax = 47900, .val = 0x64 },
+	{ .rfmax = 49100, .val = 0x20 },
+	{ .rfmax = 50000, .val = 0x22 },
+	{ .rfmax = 51000, .val = 0x2a },
+	{ .rfmax = 53000, .val = 0x32 },
+	{ .rfmax = 55000, .val = 0x35 },
+	{ .rfmax = 56000, .val = 0x3c },
+	{ .rfmax = 57000, .val = 0x3f },
+	{ .rfmax = 58000, .val = 0x48 },
+	{ .rfmax = 59000, .val = 0x4d },
+	{ .rfmax = 60000, .val = 0x58 },
+	{ .rfmax = 61100, .val = 0x5f },
+	{ .rfmax =     0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271c2_rf_cal[] = {
+	{ .rfmax =  41000, .val = 0x0f },
+	{ .rfmax =  43000, .val = 0x1c },
+	{ .rfmax =  45000, .val = 0x2f },
+	{ .rfmax =  46000, .val = 0x39 },
+	{ .rfmax =  47000, .val = 0x40 },
+	{ .rfmax =  47900, .val = 0x50 },
+	{ .rfmax =  49100, .val = 0x16 },
+	{ .rfmax =  50000, .val = 0x18 },
+	{ .rfmax =  51000, .val = 0x20 },
+	{ .rfmax =  53000, .val = 0x28 },
+	{ .rfmax =  55000, .val = 0x2b },
+	{ .rfmax =  56000, .val = 0x32 },
+	{ .rfmax =  57000, .val = 0x35 },
+	{ .rfmax =  58000, .val = 0x3e },
+	{ .rfmax =  59000, .val = 0x43 },
+	{ .rfmax =  60000, .val = 0x4e },
+	{ .rfmax =  61100, .val = 0x55 },
+	{ .rfmax =  63000, .val = 0x0f },
+	{ .rfmax =  64000, .val = 0x11 },
+	{ .rfmax =  65000, .val = 0x12 },
+	{ .rfmax =  66000, .val = 0x15 },
+	{ .rfmax =  67000, .val = 0x16 },
+	{ .rfmax =  68000, .val = 0x17 },
+	{ .rfmax =  70000, .val = 0x19 },
+	{ .rfmax =  71000, .val = 0x1c },
+	{ .rfmax =  72000, .val = 0x1d },
+	{ .rfmax =  73000, .val = 0x1f },
+	{ .rfmax =  74000, .val = 0x20 },
+	{ .rfmax =  75000, .val = 0x21 },
+	{ .rfmax =  76000, .val = 0x24 },
+	{ .rfmax =  77000, .val = 0x25 },
+	{ .rfmax =  78000, .val = 0x27 },
+	{ .rfmax =  80000, .val = 0x28 },
+	{ .rfmax =  81000, .val = 0x29 },
+	{ .rfmax =  82000, .val = 0x2d },
+	{ .rfmax =  83000, .val = 0x2e },
+	{ .rfmax =  84000, .val = 0x2f },
+	{ .rfmax =  85000, .val = 0x31 },
+	{ .rfmax =  86000, .val = 0x33 },
+	{ .rfmax =  87000, .val = 0x34 },
+	{ .rfmax =  88000, .val = 0x35 },
+	{ .rfmax =  89000, .val = 0x37 },
+	{ .rfmax =  90000, .val = 0x38 },
+	{ .rfmax =  91000, .val = 0x39 },
+	{ .rfmax =  93000, .val = 0x3c },
+	{ .rfmax =  94000, .val = 0x3e },
+	{ .rfmax =  95000, .val = 0x3f },
+	{ .rfmax =  96000, .val = 0x40 },
+	{ .rfmax =  97000, .val = 0x42 },
+	{ .rfmax =  99000, .val = 0x45 },
+	{ .rfmax = 100000, .val = 0x46 },
+	{ .rfmax = 102000, .val = 0x48 },
+	{ .rfmax = 103000, .val = 0x4a },
+	{ .rfmax = 105000, .val = 0x4d },
+	{ .rfmax = 106000, .val = 0x4e },
+	{ .rfmax = 107000, .val = 0x50 },
+	{ .rfmax = 108000, .val = 0x51 },
+	{ .rfmax = 110000, .val = 0x54 },
+	{ .rfmax = 111000, .val = 0x56 },
+	{ .rfmax = 112000, .val = 0x57 },
+	{ .rfmax = 113000, .val = 0x58 },
+	{ .rfmax = 114000, .val = 0x59 },
+	{ .rfmax = 115000, .val = 0x5c },
+	{ .rfmax = 116000, .val = 0x5d },
+	{ .rfmax = 117000, .val = 0x5f },
+	{ .rfmax = 119000, .val = 0x60 },
+	{ .rfmax = 120000, .val = 0x64 },
+	{ .rfmax = 121000, .val = 0x65 },
+	{ .rfmax = 122000, .val = 0x66 },
+	{ .rfmax = 123000, .val = 0x68 },
+	{ .rfmax = 124000, .val = 0x69 },
+	{ .rfmax = 125000, .val = 0x6c },
+	{ .rfmax = 126000, .val = 0x6d },
+	{ .rfmax = 127000, .val = 0x6e },
+	{ .rfmax = 128000, .val = 0x70 },
+	{ .rfmax = 129000, .val = 0x71 },
+	{ .rfmax = 130000, .val = 0x75 },
+	{ .rfmax = 131000, .val = 0x77 },
+	{ .rfmax = 132000, .val = 0x78 },
+	{ .rfmax = 133000, .val = 0x7b },
+	{ .rfmax = 134000, .val = 0x7e },
+	{ .rfmax = 135000, .val = 0x81 },
+	{ .rfmax = 136000, .val = 0x82 },
+	{ .rfmax = 137000, .val = 0x87 },
+	{ .rfmax = 138000, .val = 0x88 },
+	{ .rfmax = 139000, .val = 0x8d },
+	{ .rfmax = 140000, .val = 0x8e },
+	{ .rfmax = 141000, .val = 0x91 },
+	{ .rfmax = 142000, .val = 0x95 },
+	{ .rfmax = 143000, .val = 0x9a },
+	{ .rfmax = 144000, .val = 0x9d },
+	{ .rfmax = 145000, .val = 0xa1 },
+	{ .rfmax = 146000, .val = 0xa2 },
+	{ .rfmax = 147000, .val = 0xa4 },
+	{ .rfmax = 148000, .val = 0xa9 },
+	{ .rfmax = 149000, .val = 0xae },
+	{ .rfmax = 150000, .val = 0xb0 },
+	{ .rfmax = 151000, .val = 0xb1 },
+	{ .rfmax = 152000, .val = 0xb7 },
+	{ .rfmax = 152600, .val = 0xbd },
+	{ .rfmax = 154000, .val = 0x20 },
+	{ .rfmax = 155000, .val = 0x22 },
+	{ .rfmax = 156000, .val = 0x24 },
+	{ .rfmax = 157000, .val = 0x25 },
+	{ .rfmax = 158000, .val = 0x27 },
+	{ .rfmax = 159000, .val = 0x29 },
+	{ .rfmax = 160000, .val = 0x2c },
+	{ .rfmax = 161000, .val = 0x2d },
+	{ .rfmax = 163000, .val = 0x2e },
+	{ .rfmax = 164000, .val = 0x2f },
+	{ .rfmax = 164700, .val = 0x30 },
+	{ .rfmax = 166000, .val = 0x11 },
+	{ .rfmax = 167000, .val = 0x12 },
+	{ .rfmax = 168000, .val = 0x13 },
+	{ .rfmax = 169000, .val = 0x14 },
+	{ .rfmax = 170000, .val = 0x15 },
+	{ .rfmax = 172000, .val = 0x16 },
+	{ .rfmax = 173000, .val = 0x17 },
+	{ .rfmax = 174000, .val = 0x18 },
+	{ .rfmax = 175000, .val = 0x1a },
+	{ .rfmax = 176000, .val = 0x1b },
+	{ .rfmax = 178000, .val = 0x1d },
+	{ .rfmax = 179000, .val = 0x1e },
+	{ .rfmax = 180000, .val = 0x1f },
+	{ .rfmax = 181000, .val = 0x20 },
+	{ .rfmax = 182000, .val = 0x21 },
+	{ .rfmax = 183000, .val = 0x22 },
+	{ .rfmax = 184000, .val = 0x24 },
+	{ .rfmax = 185000, .val = 0x25 },
+	{ .rfmax = 186000, .val = 0x26 },
+	{ .rfmax = 187000, .val = 0x27 },
+	{ .rfmax = 188000, .val = 0x29 },
+	{ .rfmax = 189000, .val = 0x2a },
+	{ .rfmax = 190000, .val = 0x2c },
+	{ .rfmax = 191000, .val = 0x2d },
+	{ .rfmax = 192000, .val = 0x2e },
+	{ .rfmax = 193000, .val = 0x2f },
+	{ .rfmax = 194000, .val = 0x30 },
+	{ .rfmax = 195000, .val = 0x33 },
+	{ .rfmax = 196000, .val = 0x35 },
+	{ .rfmax = 198000, .val = 0x36 },
+	{ .rfmax = 200000, .val = 0x38 },
+	{ .rfmax = 201000, .val = 0x3c },
+	{ .rfmax = 202000, .val = 0x3d },
+	{ .rfmax = 203500, .val = 0x3e },
+	{ .rfmax = 206000, .val = 0x0e },
+	{ .rfmax = 208000, .val = 0x0f },
+	{ .rfmax = 212000, .val = 0x10 },
+	{ .rfmax = 216000, .val = 0x11 },
+	{ .rfmax = 217000, .val = 0x12 },
+	{ .rfmax = 218000, .val = 0x13 },
+	{ .rfmax = 220000, .val = 0x14 },
+	{ .rfmax = 222000, .val = 0x15 },
+	{ .rfmax = 225000, .val = 0x16 },
+	{ .rfmax = 228000, .val = 0x17 },
+	{ .rfmax = 231000, .val = 0x18 },
+	{ .rfmax = 234000, .val = 0x19 },
+	{ .rfmax = 235000, .val = 0x1a },
+	{ .rfmax = 236000, .val = 0x1b },
+	{ .rfmax = 237000, .val = 0x1c },
+	{ .rfmax = 240000, .val = 0x1d },
+	{ .rfmax = 242000, .val = 0x1e },
+	{ .rfmax = 244000, .val = 0x1f },
+	{ .rfmax = 247000, .val = 0x20 },
+	{ .rfmax = 249000, .val = 0x21 },
+	{ .rfmax = 252000, .val = 0x22 },
+	{ .rfmax = 253000, .val = 0x23 },
+	{ .rfmax = 254000, .val = 0x24 },
+	{ .rfmax = 256000, .val = 0x25 },
+	{ .rfmax = 259000, .val = 0x26 },
+	{ .rfmax = 262000, .val = 0x27 },
+	{ .rfmax = 264000, .val = 0x28 },
+	{ .rfmax = 267000, .val = 0x29 },
+	{ .rfmax = 269000, .val = 0x2a },
+	{ .rfmax = 271000, .val = 0x2b },
+	{ .rfmax = 273000, .val = 0x2c },
+	{ .rfmax = 275000, .val = 0x2d },
+	{ .rfmax = 277000, .val = 0x2e },
+	{ .rfmax = 279000, .val = 0x2f },
+	{ .rfmax = 282000, .val = 0x30 },
+	{ .rfmax = 284000, .val = 0x31 },
+	{ .rfmax = 286000, .val = 0x32 },
+	{ .rfmax = 287000, .val = 0x33 },
+	{ .rfmax = 290000, .val = 0x34 },
+	{ .rfmax = 293000, .val = 0x35 },
+	{ .rfmax = 295000, .val = 0x36 },
+	{ .rfmax = 297000, .val = 0x37 },
+	{ .rfmax = 300000, .val = 0x38 },
+	{ .rfmax = 303000, .val = 0x39 },
+	{ .rfmax = 305000, .val = 0x3a },
+	{ .rfmax = 306000, .val = 0x3b },
+	{ .rfmax = 307000, .val = 0x3c },
+	{ .rfmax = 310000, .val = 0x3d },
+	{ .rfmax = 312000, .val = 0x3e },
+	{ .rfmax = 315000, .val = 0x3f },
+	{ .rfmax = 318000, .val = 0x40 },
+	{ .rfmax = 320000, .val = 0x41 },
+	{ .rfmax = 323000, .val = 0x42 },
+	{ .rfmax = 324000, .val = 0x43 },
+	{ .rfmax = 325000, .val = 0x44 },
+	{ .rfmax = 327000, .val = 0x45 },
+	{ .rfmax = 331000, .val = 0x46 },
+	{ .rfmax = 334000, .val = 0x47 },
+	{ .rfmax = 337000, .val = 0x48 },
+	{ .rfmax = 339000, .val = 0x49 },
+	{ .rfmax = 340000, .val = 0x4a },
+	{ .rfmax = 341000, .val = 0x4b },
+	{ .rfmax = 343000, .val = 0x4c },
+	{ .rfmax = 345000, .val = 0x4d },
+	{ .rfmax = 349000, .val = 0x4e },
+	{ .rfmax = 352000, .val = 0x4f },
+	{ .rfmax = 353000, .val = 0x50 },
+	{ .rfmax = 355000, .val = 0x51 },
+	{ .rfmax = 357000, .val = 0x52 },
+	{ .rfmax = 359000, .val = 0x53 },
+	{ .rfmax = 361000, .val = 0x54 },
+	{ .rfmax = 362000, .val = 0x55 },
+	{ .rfmax = 364000, .val = 0x56 },
+	{ .rfmax = 368000, .val = 0x57 },
+	{ .rfmax = 370000, .val = 0x58 },
+	{ .rfmax = 372000, .val = 0x59 },
+	{ .rfmax = 375000, .val = 0x5a },
+	{ .rfmax = 376000, .val = 0x5b },
+	{ .rfmax = 377000, .val = 0x5c },
+	{ .rfmax = 379000, .val = 0x5d },
+	{ .rfmax = 382000, .val = 0x5e },
+	{ .rfmax = 384000, .val = 0x5f },
+	{ .rfmax = 385000, .val = 0x60 },
+	{ .rfmax = 386000, .val = 0x61 },
+	{ .rfmax = 388000, .val = 0x62 },
+	{ .rfmax = 390000, .val = 0x63 },
+	{ .rfmax = 393000, .val = 0x64 },
+	{ .rfmax = 394000, .val = 0x65 },
+	{ .rfmax = 396000, .val = 0x66 },
+	{ .rfmax = 397000, .val = 0x67 },
+	{ .rfmax = 398000, .val = 0x68 },
+	{ .rfmax = 400000, .val = 0x69 },
+	{ .rfmax = 402000, .val = 0x6a },
+	{ .rfmax = 403000, .val = 0x6b },
+	{ .rfmax = 407000, .val = 0x6c },
+	{ .rfmax = 408000, .val = 0x6d },
+	{ .rfmax = 409000, .val = 0x6e },
+	{ .rfmax = 410000, .val = 0x6f },
+	{ .rfmax = 411000, .val = 0x70 },
+	{ .rfmax = 412000, .val = 0x71 },
+	{ .rfmax = 413000, .val = 0x72 },
+	{ .rfmax = 414000, .val = 0x73 },
+	{ .rfmax = 417000, .val = 0x74 },
+	{ .rfmax = 418000, .val = 0x75 },
+	{ .rfmax = 420000, .val = 0x76 },
+	{ .rfmax = 422000, .val = 0x77 },
+	{ .rfmax = 423000, .val = 0x78 },
+	{ .rfmax = 424000, .val = 0x79 },
+	{ .rfmax = 427000, .val = 0x7a },
+	{ .rfmax = 428000, .val = 0x7b },
+	{ .rfmax = 429000, .val = 0x7d },
+	{ .rfmax = 432000, .val = 0x7f },
+	{ .rfmax = 434000, .val = 0x80 },
+	{ .rfmax = 435000, .val = 0x81 },
+	{ .rfmax = 436000, .val = 0x83 },
+	{ .rfmax = 437000, .val = 0x84 },
+	{ .rfmax = 438000, .val = 0x85 },
+	{ .rfmax = 439000, .val = 0x86 },
+	{ .rfmax = 440000, .val = 0x87 },
+	{ .rfmax = 441000, .val = 0x88 },
+	{ .rfmax = 442000, .val = 0x89 },
+	{ .rfmax = 445000, .val = 0x8a },
+	{ .rfmax = 446000, .val = 0x8b },
+	{ .rfmax = 447000, .val = 0x8c },
+	{ .rfmax = 448000, .val = 0x8e },
+	{ .rfmax = 449000, .val = 0x8f },
+	{ .rfmax = 450000, .val = 0x90 },
+	{ .rfmax = 452000, .val = 0x91 },
+	{ .rfmax = 453000, .val = 0x93 },
+	{ .rfmax = 454000, .val = 0x94 },
+	{ .rfmax = 456000, .val = 0x96 },
+	{ .rfmax = 457800, .val = 0x98 },
+	{ .rfmax = 461000, .val = 0x11 },
+	{ .rfmax = 468000, .val = 0x12 },
+	{ .rfmax = 472000, .val = 0x13 },
+	{ .rfmax = 473000, .val = 0x14 },
+	{ .rfmax = 474000, .val = 0x15 },
+	{ .rfmax = 481000, .val = 0x16 },
+	{ .rfmax = 486000, .val = 0x17 },
+	{ .rfmax = 491000, .val = 0x18 },
+	{ .rfmax = 498000, .val = 0x19 },
+	{ .rfmax = 499000, .val = 0x1a },
+	{ .rfmax = 501000, .val = 0x1b },
+	{ .rfmax = 506000, .val = 0x1c },
+	{ .rfmax = 511000, .val = 0x1d },
+	{ .rfmax = 516000, .val = 0x1e },
+	{ .rfmax = 520000, .val = 0x1f },
+	{ .rfmax = 521000, .val = 0x20 },
+	{ .rfmax = 525000, .val = 0x21 },
+	{ .rfmax = 529000, .val = 0x22 },
+	{ .rfmax = 533000, .val = 0x23 },
+	{ .rfmax = 539000, .val = 0x24 },
+	{ .rfmax = 541000, .val = 0x25 },
+	{ .rfmax = 547000, .val = 0x26 },
+	{ .rfmax = 549000, .val = 0x27 },
+	{ .rfmax = 551000, .val = 0x28 },
+	{ .rfmax = 556000, .val = 0x29 },
+	{ .rfmax = 561000, .val = 0x2a },
+	{ .rfmax = 563000, .val = 0x2b },
+	{ .rfmax = 565000, .val = 0x2c },
+	{ .rfmax = 569000, .val = 0x2d },
+	{ .rfmax = 571000, .val = 0x2e },
+	{ .rfmax = 577000, .val = 0x2f },
+	{ .rfmax = 580000, .val = 0x30 },
+	{ .rfmax = 582000, .val = 0x31 },
+	{ .rfmax = 584000, .val = 0x32 },
+	{ .rfmax = 588000, .val = 0x33 },
+	{ .rfmax = 591000, .val = 0x34 },
+	{ .rfmax = 596000, .val = 0x35 },
+	{ .rfmax = 598000, .val = 0x36 },
+	{ .rfmax = 603000, .val = 0x37 },
+	{ .rfmax = 604000, .val = 0x38 },
+	{ .rfmax = 606000, .val = 0x39 },
+	{ .rfmax = 612000, .val = 0x3a },
+	{ .rfmax = 615000, .val = 0x3b },
+	{ .rfmax = 617000, .val = 0x3c },
+	{ .rfmax = 621000, .val = 0x3d },
+	{ .rfmax = 622000, .val = 0x3e },
+	{ .rfmax = 625000, .val = 0x3f },
+	{ .rfmax = 632000, .val = 0x40 },
+	{ .rfmax = 633000, .val = 0x41 },
+	{ .rfmax = 634000, .val = 0x42 },
+	{ .rfmax = 642000, .val = 0x43 },
+	{ .rfmax = 643000, .val = 0x44 },
+	{ .rfmax = 647000, .val = 0x45 },
+	{ .rfmax = 650000, .val = 0x46 },
+	{ .rfmax = 652000, .val = 0x47 },
+	{ .rfmax = 657000, .val = 0x48 },
+	{ .rfmax = 661000, .val = 0x49 },
+	{ .rfmax = 662000, .val = 0x4a },
+	{ .rfmax = 665000, .val = 0x4b },
+	{ .rfmax = 667000, .val = 0x4c },
+	{ .rfmax = 670000, .val = 0x4d },
+	{ .rfmax = 673000, .val = 0x4e },
+	{ .rfmax = 676000, .val = 0x4f },
+	{ .rfmax = 677000, .val = 0x50 },
+	{ .rfmax = 681000, .val = 0x51 },
+	{ .rfmax = 683000, .val = 0x52 },
+	{ .rfmax = 686000, .val = 0x53 },
+	{ .rfmax = 688000, .val = 0x54 },
+	{ .rfmax = 689000, .val = 0x55 },
+	{ .rfmax = 691000, .val = 0x56 },
+	{ .rfmax = 695000, .val = 0x57 },
+	{ .rfmax = 698000, .val = 0x58 },
+	{ .rfmax = 703000, .val = 0x59 },
+	{ .rfmax = 704000, .val = 0x5a },
+	{ .rfmax = 705000, .val = 0x5b },
+	{ .rfmax = 707000, .val = 0x5c },
+	{ .rfmax = 710000, .val = 0x5d },
+	{ .rfmax = 712000, .val = 0x5e },
+	{ .rfmax = 717000, .val = 0x5f },
+	{ .rfmax = 718000, .val = 0x60 },
+	{ .rfmax = 721000, .val = 0x61 },
+	{ .rfmax = 722000, .val = 0x62 },
+	{ .rfmax = 723000, .val = 0x63 },
+	{ .rfmax = 725000, .val = 0x64 },
+	{ .rfmax = 727000, .val = 0x65 },
+	{ .rfmax = 730000, .val = 0x66 },
+	{ .rfmax = 732000, .val = 0x67 },
+	{ .rfmax = 735000, .val = 0x68 },
+	{ .rfmax = 740000, .val = 0x69 },
+	{ .rfmax = 741000, .val = 0x6a },
+	{ .rfmax = 742000, .val = 0x6b },
+	{ .rfmax = 743000, .val = 0x6c },
+	{ .rfmax = 745000, .val = 0x6d },
+	{ .rfmax = 747000, .val = 0x6e },
+	{ .rfmax = 748000, .val = 0x6f },
+	{ .rfmax = 750000, .val = 0x70 },
+	{ .rfmax = 752000, .val = 0x71 },
+	{ .rfmax = 754000, .val = 0x72 },
+	{ .rfmax = 757000, .val = 0x73 },
+	{ .rfmax = 758000, .val = 0x74 },
+	{ .rfmax = 760000, .val = 0x75 },
+	{ .rfmax = 763000, .val = 0x76 },
+	{ .rfmax = 764000, .val = 0x77 },
+	{ .rfmax = 766000, .val = 0x78 },
+	{ .rfmax = 767000, .val = 0x79 },
+	{ .rfmax = 768000, .val = 0x7a },
+	{ .rfmax = 773000, .val = 0x7b },
+	{ .rfmax = 774000, .val = 0x7c },
+	{ .rfmax = 776000, .val = 0x7d },
+	{ .rfmax = 777000, .val = 0x7e },
+	{ .rfmax = 778000, .val = 0x7f },
+	{ .rfmax = 779000, .val = 0x80 },
+	{ .rfmax = 781000, .val = 0x81 },
+	{ .rfmax = 783000, .val = 0x82 },
+	{ .rfmax = 784000, .val = 0x83 },
+	{ .rfmax = 785000, .val = 0x84 },
+	{ .rfmax = 786000, .val = 0x85 },
+	{ .rfmax = 793000, .val = 0x86 },
+	{ .rfmax = 794000, .val = 0x87 },
+	{ .rfmax = 795000, .val = 0x88 },
+	{ .rfmax = 797000, .val = 0x89 },
+	{ .rfmax = 799000, .val = 0x8a },
+	{ .rfmax = 801000, .val = 0x8b },
+	{ .rfmax = 802000, .val = 0x8c },
+	{ .rfmax = 803000, .val = 0x8d },
+	{ .rfmax = 804000, .val = 0x8e },
+	{ .rfmax = 810000, .val = 0x90 },
+	{ .rfmax = 811000, .val = 0x91 },
+	{ .rfmax = 812000, .val = 0x92 },
+	{ .rfmax = 814000, .val = 0x93 },
+	{ .rfmax = 816000, .val = 0x94 },
+	{ .rfmax = 817000, .val = 0x96 },
+	{ .rfmax = 818000, .val = 0x97 },
+	{ .rfmax = 820000, .val = 0x98 },
+	{ .rfmax = 821000, .val = 0x99 },
+	{ .rfmax = 822000, .val = 0x9a },
+	{ .rfmax = 828000, .val = 0x9b },
+	{ .rfmax = 829000, .val = 0x9d },
+	{ .rfmax = 830000, .val = 0x9f },
+	{ .rfmax = 831000, .val = 0xa0 },
+	{ .rfmax = 833000, .val = 0xa1 },
+	{ .rfmax = 835000, .val = 0xa2 },
+	{ .rfmax = 836000, .val = 0xa3 },
+	{ .rfmax = 837000, .val = 0xa4 },
+	{ .rfmax = 838000, .val = 0xa6 },
+	{ .rfmax = 840000, .val = 0xa8 },
+	{ .rfmax = 842000, .val = 0xa9 },
+	{ .rfmax = 845000, .val = 0xaa },
+	{ .rfmax = 846000, .val = 0xab },
+	{ .rfmax = 847000, .val = 0xad },
+	{ .rfmax = 848000, .val = 0xae },
+	{ .rfmax = 852000, .val = 0xaf },
+	{ .rfmax = 853000, .val = 0xb0 },
+	{ .rfmax = 858000, .val = 0xb1 },
+	{ .rfmax = 860000, .val = 0xb2 },
+	{ .rfmax = 861000, .val = 0xb3 },
+	{ .rfmax = 862000, .val = 0xb4 },
+	{ .rfmax = 863000, .val = 0xb6 },
+	{ .rfmax = 864000, .val = 0xb8 },
+	{ .rfmax = 865000, .val = 0xb9 },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271_ir_measure[] = {
+	{ .rfmax =  30000, .val = 4 },
+	{ .rfmax = 200000, .val = 5 },
+	{ .rfmax = 600000, .val = 6 },
+	{ .rfmax = 865000, .val = 7 },
+	{ .rfmax =      0, .val = 0 }, /* end */
+};
+
+static struct tda18271_map tda18271_rf_cal_dc_over_dt[] = {
+	{ .rfmax =  47900, .val = 0x00 },
+	{ .rfmax =  55000, .val = 0x00 },
+	{ .rfmax =  61100, .val = 0x0a },
+	{ .rfmax =  64000, .val = 0x0a },
+	{ .rfmax =  82000, .val = 0x14 },
+	{ .rfmax =  84000, .val = 0x19 },
+	{ .rfmax = 119000, .val = 0x1c },
+	{ .rfmax = 124000, .val = 0x20 },
+	{ .rfmax = 129000, .val = 0x2a },
+	{ .rfmax = 134000, .val = 0x32 },
+	{ .rfmax = 139000, .val = 0x39 },
+	{ .rfmax = 144000, .val = 0x3e },
+	{ .rfmax = 149000, .val = 0x3f },
+	{ .rfmax = 152600, .val = 0x40 },
+	{ .rfmax = 154000, .val = 0x40 },
+	{ .rfmax = 164700, .val = 0x41 },
+	{ .rfmax = 203500, .val = 0x32 },
+	{ .rfmax = 353000, .val = 0x19 },
+	{ .rfmax = 356000, .val = 0x1a },
+	{ .rfmax = 359000, .val = 0x1b },
+	{ .rfmax = 363000, .val = 0x1c },
+	{ .rfmax = 366000, .val = 0x1d },
+	{ .rfmax = 369000, .val = 0x1e },
+	{ .rfmax = 373000, .val = 0x1f },
+	{ .rfmax = 376000, .val = 0x20 },
+	{ .rfmax = 379000, .val = 0x21 },
+	{ .rfmax = 383000, .val = 0x22 },
+	{ .rfmax = 386000, .val = 0x23 },
+	{ .rfmax = 389000, .val = 0x24 },
+	{ .rfmax = 393000, .val = 0x25 },
+	{ .rfmax = 396000, .val = 0x26 },
+	{ .rfmax = 399000, .val = 0x27 },
+	{ .rfmax = 402000, .val = 0x28 },
+	{ .rfmax = 404000, .val = 0x29 },
+	{ .rfmax = 407000, .val = 0x2a },
+	{ .rfmax = 409000, .val = 0x2b },
+	{ .rfmax = 412000, .val = 0x2c },
+	{ .rfmax = 414000, .val = 0x2d },
+	{ .rfmax = 417000, .val = 0x2e },
+	{ .rfmax = 419000, .val = 0x2f },
+	{ .rfmax = 422000, .val = 0x30 },
+	{ .rfmax = 424000, .val = 0x31 },
+	{ .rfmax = 427000, .val = 0x32 },
+	{ .rfmax = 429000, .val = 0x33 },
+	{ .rfmax = 432000, .val = 0x34 },
+	{ .rfmax = 434000, .val = 0x35 },
+	{ .rfmax = 437000, .val = 0x36 },
+	{ .rfmax = 439000, .val = 0x37 },
+	{ .rfmax = 442000, .val = 0x38 },
+	{ .rfmax = 444000, .val = 0x39 },
+	{ .rfmax = 447000, .val = 0x3a },
+	{ .rfmax = 449000, .val = 0x3b },
+	{ .rfmax = 457800, .val = 0x3c },
+	{ .rfmax = 465000, .val = 0x0f },
+	{ .rfmax = 477000, .val = 0x12 },
+	{ .rfmax = 483000, .val = 0x14 },
+	{ .rfmax = 502000, .val = 0x19 },
+	{ .rfmax = 508000, .val = 0x1b },
+	{ .rfmax = 519000, .val = 0x1c },
+	{ .rfmax = 522000, .val = 0x1d },
+	{ .rfmax = 524000, .val = 0x1e },
+	{ .rfmax = 534000, .val = 0x1f },
+	{ .rfmax = 549000, .val = 0x20 },
+	{ .rfmax = 554000, .val = 0x22 },
+	{ .rfmax = 584000, .val = 0x24 },
+	{ .rfmax = 589000, .val = 0x26 },
+	{ .rfmax = 658000, .val = 0x27 },
+	{ .rfmax = 664000, .val = 0x2c },
+	{ .rfmax = 669000, .val = 0x2d },
+	{ .rfmax = 699000, .val = 0x2e },
+	{ .rfmax = 704000, .val = 0x30 },
+	{ .rfmax = 709000, .val = 0x31 },
+	{ .rfmax = 714000, .val = 0x32 },
+	{ .rfmax = 724000, .val = 0x33 },
+	{ .rfmax = 729000, .val = 0x36 },
+	{ .rfmax = 739000, .val = 0x38 },
+	{ .rfmax = 744000, .val = 0x39 },
+	{ .rfmax = 749000, .val = 0x3b },
+	{ .rfmax = 754000, .val = 0x3c },
+	{ .rfmax = 759000, .val = 0x3d },
+	{ .rfmax = 764000, .val = 0x3e },
+	{ .rfmax = 769000, .val = 0x3f },
+	{ .rfmax = 774000, .val = 0x40 },
+	{ .rfmax = 779000, .val = 0x41 },
+	{ .rfmax = 784000, .val = 0x43 },
+	{ .rfmax = 789000, .val = 0x46 },
+	{ .rfmax = 794000, .val = 0x48 },
+	{ .rfmax = 799000, .val = 0x4b },
+	{ .rfmax = 804000, .val = 0x4f },
+	{ .rfmax = 809000, .val = 0x54 },
+	{ .rfmax = 814000, .val = 0x59 },
+	{ .rfmax = 819000, .val = 0x5d },
+	{ .rfmax = 824000, .val = 0x61 },
+	{ .rfmax = 829000, .val = 0x68 },
+	{ .rfmax = 834000, .val = 0x6e },
+	{ .rfmax = 839000, .val = 0x75 },
+	{ .rfmax = 844000, .val = 0x7e },
+	{ .rfmax = 849000, .val = 0x82 },
+	{ .rfmax = 854000, .val = 0x84 },
+	{ .rfmax = 859000, .val = 0x8f },
+	{ .rfmax = 865000, .val = 0x9a },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+/*---------------------------------------------------------------------*/
+
+struct tda18271_thermo_map {
+	u8 d;
+	u8 r0;
+	u8 r1;
+};
+
+static struct tda18271_thermo_map tda18271_thermometer[] = {
+	{ .d = 0x00, .r0 = 60, .r1 =  92 },
+	{ .d = 0x01, .r0 = 62, .r1 =  94 },
+	{ .d = 0x02, .r0 = 66, .r1 =  98 },
+	{ .d = 0x03, .r0 = 64, .r1 =  96 },
+	{ .d = 0x04, .r0 = 74, .r1 = 106 },
+	{ .d = 0x05, .r0 = 72, .r1 = 104 },
+	{ .d = 0x06, .r0 = 68, .r1 = 100 },
+	{ .d = 0x07, .r0 = 70, .r1 = 102 },
+	{ .d = 0x08, .r0 = 90, .r1 = 122 },
+	{ .d = 0x09, .r0 = 88, .r1 = 120 },
+	{ .d = 0x0a, .r0 = 84, .r1 = 116 },
+	{ .d = 0x0b, .r0 = 86, .r1 = 118 },
+	{ .d = 0x0c, .r0 = 76, .r1 = 108 },
+	{ .d = 0x0d, .r0 = 78, .r1 = 110 },
+	{ .d = 0x0e, .r0 = 82, .r1 = 114 },
+	{ .d = 0x0f, .r0 = 80, .r1 = 112 },
+	{ .d = 0x00, .r0 =  0, .r1 =   0 }, /* end */
+};
+
+int tda18271_lookup_thermometer(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	int val, i = 0;
+
+	while (tda18271_thermometer[i].d < (regs[R_TM] & 0x0f)) {
+		if (tda18271_thermometer[i + 1].d == 0)
+			break;
+		i++;
+	}
+
+	if ((regs[R_TM] & 0x20) == 0x20)
+		val = tda18271_thermometer[i].r1;
+	else
+		val = tda18271_thermometer[i].r0;
+
+	tda_map("(%d) tm = %d\n", i, val);
+
+	return val;
+}
+
+/*---------------------------------------------------------------------*/
+
+struct tda18271_cid_target_map {
+	u32 rfmax;
+	u8  target;
+	u16 limit;
+};
+
+static struct tda18271_cid_target_map tda18271_cid_target[] = {
+	{ .rfmax =  46000, .target = 0x04, .limit =  1800 },
+	{ .rfmax =  52200, .target = 0x0a, .limit =  1500 },
+	{ .rfmax =  70100, .target = 0x01, .limit =  4000 },
+	{ .rfmax = 136800, .target = 0x18, .limit =  4000 },
+	{ .rfmax = 156700, .target = 0x18, .limit =  4000 },
+	{ .rfmax = 186250, .target = 0x0a, .limit =  4000 },
+	{ .rfmax = 230000, .target = 0x0a, .limit =  4000 },
+	{ .rfmax = 345000, .target = 0x18, .limit =  4000 },
+	{ .rfmax = 426000, .target = 0x0e, .limit =  4000 },
+	{ .rfmax = 489500, .target = 0x1e, .limit =  4000 },
+	{ .rfmax = 697500, .target = 0x32, .limit =  4000 },
+	{ .rfmax = 842000, .target = 0x3a, .limit =  4000 },
+	{ .rfmax =      0, .target = 0x00, .limit =     0 }, /* end */
+};
+
+int tda18271_lookup_cid_target(struct dvb_frontend *fe,
+			       u32 *freq, u8 *cid_target, u16 *count_limit)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	int i = 0;
+
+	while ((tda18271_cid_target[i].rfmax * 1000) < *freq) {
+		if (tda18271_cid_target[i + 1].rfmax == 0)
+			break;
+		i++;
+	}
+	*cid_target  = tda18271_cid_target[i].target;
+	*count_limit = tda18271_cid_target[i].limit;
+
+	tda_map("(%d) cid_target = %02x, count_limit = %d\n", i,
+		tda18271_cid_target[i].target, tda18271_cid_target[i].limit);
+
+	return 0;
+}
+
+/*---------------------------------------------------------------------*/
+
+static struct tda18271_rf_tracking_filter_cal tda18271_rf_band_template[] = {
+	{ .rfmax =  47900, .rfband = 0x00,
+	  .rf1_def =  46000, .rf2_def =      0, .rf3_def =      0 },
+	{ .rfmax =  61100, .rfband = 0x01,
+	  .rf1_def =  52200, .rf2_def =      0, .rf3_def =      0 },
+	{ .rfmax = 152600, .rfband = 0x02,
+	  .rf1_def =  70100, .rf2_def = 136800, .rf3_def =      0 },
+	{ .rfmax = 164700, .rfband = 0x03,
+	  .rf1_def = 156700, .rf2_def =      0, .rf3_def =      0 },
+	{ .rfmax = 203500, .rfband = 0x04,
+	  .rf1_def = 186250, .rf2_def =      0, .rf3_def =      0 },
+	{ .rfmax = 457800, .rfband = 0x05,
+	  .rf1_def = 230000, .rf2_def = 345000, .rf3_def = 426000 },
+	{ .rfmax = 865000, .rfband = 0x06,
+	  .rf1_def = 489500, .rf2_def = 697500, .rf3_def = 842000 },
+	{ .rfmax =      0, .rfband = 0x00,
+	  .rf1_def =      0, .rf2_def =      0, .rf3_def =      0 }, /* end */
+};
+
+int tda18271_lookup_rf_band(struct dvb_frontend *fe, u32 *freq, u8 *rf_band)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
+	int i = 0;
+
+	while ((map[i].rfmax * 1000) < *freq) {
+		if (tda18271_debug & DBG_ADV)
+			tda_map("(%d) rfmax = %d < freq = %d, "
+				"rf1_def = %d, rf2_def = %d, rf3_def = %d, "
+				"rf1 = %d, rf2 = %d, rf3 = %d, "
+				"rf_a1 = %d, rf_a2 = %d, "
+				"rf_b1 = %d, rf_b2 = %d\n",
+				i, map[i].rfmax * 1000, *freq,
+				map[i].rf1_def, map[i].rf2_def, map[i].rf3_def,
+				map[i].rf1, map[i].rf2, map[i].rf3,
+				map[i].rf_a1, map[i].rf_a2,
+				map[i].rf_b1, map[i].rf_b2);
+		if (map[i].rfmax == 0)
+			return -EINVAL;
+		i++;
+	}
+	if (rf_band)
+		*rf_band = map[i].rfband;
+
+	tda_map("(%d) rf_band = %02x\n", i, map[i].rfband);
+
+	return i;
+}
+
+/*---------------------------------------------------------------------*/
+
+struct tda18271_map_layout {
+	struct tda18271_pll_map *main_pll;
+	struct tda18271_pll_map *cal_pll;
+
+	struct tda18271_map *rf_cal;
+	struct tda18271_map *rf_cal_kmco;
+	struct tda18271_map *rf_cal_dc_over_dt;
+
+	struct tda18271_map *bp_filter;
+	struct tda18271_map *rf_band;
+	struct tda18271_map *gain_taper;
+	struct tda18271_map *ir_measure;
+};
+
+/*---------------------------------------------------------------------*/
+
+int tda18271_lookup_pll_map(struct dvb_frontend *fe,
+			    enum tda18271_map_type map_type,
+			    u32 *freq, u8 *post_div, u8 *div)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_pll_map *map = NULL;
+	unsigned int i = 0;
+	char *map_name;
+	int ret = 0;
+
+	BUG_ON(!priv->maps);
+
+	switch (map_type) {
+	case MAIN_PLL:
+		map = priv->maps->main_pll;
+		map_name = "main_pll";
+		break;
+	case CAL_PLL:
+		map = priv->maps->cal_pll;
+		map_name = "cal_pll";
+		break;
+	default:
+		/* we should never get here */
+		map_name = "undefined";
+		break;
+	}
+
+	if (!map) {
+		tda_warn("%s map is not set!\n", map_name);
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	while ((map[i].lomax * 1000) < *freq) {
+		if (map[i + 1].lomax == 0) {
+			tda_map("%s: frequency (%d) out of range\n",
+				map_name, *freq);
+			ret = -ERANGE;
+			break;
+		}
+		i++;
+	}
+	*post_div = map[i].pd;
+	*div      = map[i].d;
+
+	tda_map("(%d) %s: post div = 0x%02x, div = 0x%02x\n",
+		i, map_name, *post_div, *div);
+fail:
+	return ret;
+}
+
+int tda18271_lookup_map(struct dvb_frontend *fe,
+			enum tda18271_map_type map_type,
+			u32 *freq, u8 *val)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_map *map = NULL;
+	unsigned int i = 0;
+	char *map_name;
+	int ret = 0;
+
+	BUG_ON(!priv->maps);
+
+	switch (map_type) {
+	case BP_FILTER:
+		map = priv->maps->bp_filter;
+		map_name = "bp_filter";
+		break;
+	case RF_CAL_KMCO:
+		map = priv->maps->rf_cal_kmco;
+		map_name = "km";
+		break;
+	case RF_BAND:
+		map = priv->maps->rf_band;
+		map_name = "rf_band";
+		break;
+	case GAIN_TAPER:
+		map = priv->maps->gain_taper;
+		map_name = "gain_taper";
+		break;
+	case RF_CAL:
+		map = priv->maps->rf_cal;
+		map_name = "rf_cal";
+		break;
+	case IR_MEASURE:
+		map = priv->maps->ir_measure;
+		map_name = "ir_measure";
+		break;
+	case RF_CAL_DC_OVER_DT:
+		map = priv->maps->rf_cal_dc_over_dt;
+		map_name = "rf_cal_dc_over_dt";
+		break;
+	default:
+		/* we should never get here */
+		map_name = "undefined";
+		break;
+	}
+
+	if (!map) {
+		tda_warn("%s map is not set!\n", map_name);
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	while ((map[i].rfmax * 1000) < *freq) {
+		if (map[i + 1].rfmax == 0) {
+			tda_map("%s: frequency (%d) out of range\n",
+				map_name, *freq);
+			ret = -ERANGE;
+			break;
+		}
+		i++;
+	}
+	*val = map[i].val;
+
+	tda_map("(%d) %s: 0x%02x\n", i, map_name, *val);
+fail:
+	return ret;
+}
+
+/*---------------------------------------------------------------------*/
+
+static struct tda18271_std_map tda18271c1_std_map = {
+	.fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */
+	.atv_b    = { .if_freq = 6750, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+	.atv_dk   = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
+	.atv_gh   = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
+	.atv_i    = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
+	.atv_l    = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
+	.atv_lc   = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 7,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
+	.atv_mn   = { .if_freq = 5750, .fm_rfn = 0, .agc_mode = 1, .std = 5,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */
+	.atsc_6   = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
+	.dvbt_6   = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
+	.dvbt_7   = { .if_freq = 3800, .fm_rfn = 0, .agc_mode = 3, .std = 5,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
+	.dvbt_8   = { .if_freq = 4300, .fm_rfn = 0, .agc_mode = 3, .std = 6,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */
+	.qam_6    = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
+	.qam_7    = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */
+	.qam_8    = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */
+};
+
+static struct tda18271_std_map tda18271c2_std_map = {
+	.fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */
+	.atv_b    = { .if_freq = 6000, .fm_rfn = 0, .agc_mode = 1, .std = 5,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */
+	.atv_dk   = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+	.atv_gh   = { .if_freq = 7100, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+	.atv_i    = { .if_freq = 7250, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+	.atv_l    = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+	.atv_lc   = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+	.atv_mn   = { .if_freq = 5400, .fm_rfn = 0, .agc_mode = 1, .std = 4,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0c */
+	.atsc_6   = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
+	.dvbt_6   = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
+	.dvbt_7   = { .if_freq = 3500, .fm_rfn = 0, .agc_mode = 3, .std = 4,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
+	.dvbt_8   = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
+	.qam_6    = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
+	.qam_7    = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */
+	.qam_8    = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */
+};
+
+/*---------------------------------------------------------------------*/
+
+static struct tda18271_map_layout tda18271c1_map_layout = {
+	.main_pll          = tda18271c1_main_pll,
+	.cal_pll           = tda18271c1_cal_pll,
+
+	.rf_cal            = tda18271c1_rf_cal,
+	.rf_cal_kmco       = tda18271c1_km,
+
+	.bp_filter         = tda18271_bp_filter,
+	.rf_band           = tda18271_rf_band,
+	.gain_taper        = tda18271_gain_taper,
+	.ir_measure        = tda18271_ir_measure,
+};
+
+static struct tda18271_map_layout tda18271c2_map_layout = {
+	.main_pll          = tda18271c2_main_pll,
+	.cal_pll           = tda18271c2_cal_pll,
+
+	.rf_cal            = tda18271c2_rf_cal,
+	.rf_cal_kmco       = tda18271c2_km,
+
+	.rf_cal_dc_over_dt = tda18271_rf_cal_dc_over_dt,
+
+	.bp_filter         = tda18271_bp_filter,
+	.rf_band           = tda18271_rf_band,
+	.gain_taper        = tda18271_gain_taper,
+	.ir_measure        = tda18271_ir_measure,
+};
+
+int tda18271_assign_map_layout(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	int ret = 0;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		priv->maps = &tda18271c1_map_layout;
+		memcpy(&priv->std, &tda18271c1_std_map,
+		       sizeof(struct tda18271_std_map));
+		break;
+	case TDA18271HDC2:
+		priv->maps = &tda18271c2_map_layout;
+		memcpy(&priv->std, &tda18271c2_std_map,
+		       sizeof(struct tda18271_std_map));
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	memcpy(priv->rf_cal_state, &tda18271_rf_band_template,
+	       sizeof(tda18271_rf_band_template));
+
+	return ret;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/tuners/tda18271-priv.h b/drivers/media/tuners/tda18271-priv.h
new file mode 100644
index 0000000..454c152
--- /dev/null
+++ b/drivers/media/tuners/tda18271-priv.h
@@ -0,0 +1,236 @@
+/*
+    tda18271-priv.h - private header for the NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TDA18271_PRIV_H__
+#define __TDA18271_PRIV_H__
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include "tuner-i2c.h"
+#include "tda18271.h"
+
+#define R_ID     0x00	/* ID byte                */
+#define R_TM     0x01	/* Thermo byte            */
+#define R_PL     0x02	/* Power level byte       */
+#define R_EP1    0x03	/* Easy Prog byte 1       */
+#define R_EP2    0x04	/* Easy Prog byte 2       */
+#define R_EP3    0x05	/* Easy Prog byte 3       */
+#define R_EP4    0x06	/* Easy Prog byte 4       */
+#define R_EP5    0x07	/* Easy Prog byte 5       */
+#define R_CPD    0x08	/* Cal Post-Divider byte  */
+#define R_CD1    0x09	/* Cal Divider byte 1     */
+#define R_CD2    0x0a	/* Cal Divider byte 2     */
+#define R_CD3    0x0b	/* Cal Divider byte 3     */
+#define R_MPD    0x0c	/* Main Post-Divider byte */
+#define R_MD1    0x0d	/* Main Divider byte 1    */
+#define R_MD2    0x0e	/* Main Divider byte 2    */
+#define R_MD3    0x0f	/* Main Divider byte 3    */
+#define R_EB1    0x10	/* Extended byte 1        */
+#define R_EB2    0x11	/* Extended byte 2        */
+#define R_EB3    0x12	/* Extended byte 3        */
+#define R_EB4    0x13	/* Extended byte 4        */
+#define R_EB5    0x14	/* Extended byte 5        */
+#define R_EB6    0x15	/* Extended byte 6        */
+#define R_EB7    0x16	/* Extended byte 7        */
+#define R_EB8    0x17	/* Extended byte 8        */
+#define R_EB9    0x18	/* Extended byte 9        */
+#define R_EB10   0x19	/* Extended byte 10       */
+#define R_EB11   0x1a	/* Extended byte 11       */
+#define R_EB12   0x1b	/* Extended byte 12       */
+#define R_EB13   0x1c	/* Extended byte 13       */
+#define R_EB14   0x1d	/* Extended byte 14       */
+#define R_EB15   0x1e	/* Extended byte 15       */
+#define R_EB16   0x1f	/* Extended byte 16       */
+#define R_EB17   0x20	/* Extended byte 17       */
+#define R_EB18   0x21	/* Extended byte 18       */
+#define R_EB19   0x22	/* Extended byte 19       */
+#define R_EB20   0x23	/* Extended byte 20       */
+#define R_EB21   0x24	/* Extended byte 21       */
+#define R_EB22   0x25	/* Extended byte 22       */
+#define R_EB23   0x26	/* Extended byte 23       */
+
+#define TDA18271_NUM_REGS 39
+
+/*---------------------------------------------------------------------*/
+
+struct tda18271_rf_tracking_filter_cal {
+	u32 rfmax;
+	u8  rfband;
+	u32 rf1_def;
+	u32 rf2_def;
+	u32 rf3_def;
+	u32 rf1;
+	u32 rf2;
+	u32 rf3;
+	s32 rf_a1;
+	s32 rf_b1;
+	s32 rf_a2;
+	s32 rf_b2;
+};
+
+enum tda18271_pll {
+	TDA18271_MAIN_PLL,
+	TDA18271_CAL_PLL,
+};
+
+struct tda18271_map_layout;
+
+enum tda18271_ver {
+	TDA18271HDC1,
+	TDA18271HDC2,
+};
+
+struct tda18271_priv {
+	unsigned char tda18271_regs[TDA18271_NUM_REGS];
+
+	struct list_head	hybrid_tuner_instance_list;
+	struct tuner_i2c_props	i2c_props;
+
+	enum tda18271_mode mode;
+	enum tda18271_role role;
+	enum tda18271_i2c_gate gate;
+	enum tda18271_ver id;
+	enum tda18271_output_options output_opt;
+	enum tda18271_small_i2c small_i2c;
+
+	unsigned int config; /* interface to saa713x / tda829x */
+	unsigned int cal_initialized:1;
+
+	u8 tm_rfcal;
+
+	struct tda18271_map_layout *maps;
+	struct tda18271_std_map std;
+	struct tda18271_rf_tracking_filter_cal rf_cal_state[8];
+
+	struct mutex lock;
+
+	u16 if_freq;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+/*---------------------------------------------------------------------*/
+
+extern int tda18271_debug;
+
+#define DBG_INFO 1
+#define DBG_MAP  2
+#define DBG_REG  4
+#define DBG_ADV  8
+#define DBG_CAL  16
+
+__attribute__((format(printf, 4, 5)))
+int _tda_printk(struct tda18271_priv *state, const char *level,
+		const char *func, const char *fmt, ...);
+
+#define tda_printk(st, lvl, fmt, arg...)			\
+	_tda_printk(st, lvl, __func__, fmt, ##arg)
+
+#define tda_dprintk(st, lvl, fmt, arg...)			\
+do {								\
+	if (tda18271_debug & lvl)				\
+		tda_printk(st, KERN_DEBUG, fmt, ##arg);		\
+} while (0)
+
+#define tda_info(fmt, arg...)	pr_info(fmt, ##arg)
+#define tda_warn(fmt, arg...)	tda_printk(priv, KERN_WARNING, fmt, ##arg)
+#define tda_err(fmt, arg...)	tda_printk(priv, KERN_ERR,     fmt, ##arg)
+#define tda_dbg(fmt, arg...)	tda_dprintk(priv, DBG_INFO,    fmt, ##arg)
+#define tda_map(fmt, arg...)	tda_dprintk(priv, DBG_MAP,     fmt, ##arg)
+#define tda_reg(fmt, arg...)	tda_dprintk(priv, DBG_REG,     fmt, ##arg)
+#define tda_cal(fmt, arg...)	tda_dprintk(priv, DBG_CAL,     fmt, ##arg)
+
+#define tda_fail(ret)							     \
+({									     \
+	int __ret;							     \
+	__ret = (ret < 0);						     \
+	if (__ret)							     \
+		tda_printk(priv, KERN_ERR,				     \
+			   "error %d on line %d\n", ret, __LINE__);	     \
+	__ret;								     \
+})
+
+/*---------------------------------------------------------------------*/
+
+enum tda18271_map_type {
+	/* tda18271_pll_map */
+	MAIN_PLL,
+	CAL_PLL,
+	/* tda18271_map */
+	RF_CAL,
+	RF_CAL_KMCO,
+	RF_CAL_DC_OVER_DT,
+	BP_FILTER,
+	RF_BAND,
+	GAIN_TAPER,
+	IR_MEASURE,
+};
+
+extern int tda18271_lookup_pll_map(struct dvb_frontend *fe,
+				   enum tda18271_map_type map_type,
+				   u32 *freq, u8 *post_div, u8 *div);
+extern int tda18271_lookup_map(struct dvb_frontend *fe,
+			       enum tda18271_map_type map_type,
+			       u32 *freq, u8 *val);
+
+extern int tda18271_lookup_thermometer(struct dvb_frontend *fe);
+
+extern int tda18271_lookup_rf_band(struct dvb_frontend *fe,
+				   u32 *freq, u8 *rf_band);
+
+extern int tda18271_lookup_cid_target(struct dvb_frontend *fe,
+				      u32 *freq, u8 *cid_target,
+				      u16 *count_limit);
+
+extern int tda18271_assign_map_layout(struct dvb_frontend *fe);
+
+/*---------------------------------------------------------------------*/
+
+extern int tda18271_read_regs(struct dvb_frontend *fe);
+extern int tda18271_read_extended(struct dvb_frontend *fe);
+extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len);
+extern int tda18271_init_regs(struct dvb_frontend *fe);
+
+extern int tda18271_charge_pump_source(struct dvb_frontend *fe,
+				       enum tda18271_pll pll, int force);
+extern int tda18271_set_standby_mode(struct dvb_frontend *fe,
+				     int sm, int sm_lt, int sm_xt);
+
+extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq);
+extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq);
+
+extern int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq);
+
+#endif /* __TDA18271_PRIV_H__ */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/tuners/tda18271.h b/drivers/media/tuners/tda18271.h
new file mode 100644
index 0000000..640bae4
--- /dev/null
+++ b/drivers/media/tuners/tda18271.h
@@ -0,0 +1,134 @@
+/*
+    tda18271.h - header for the Philips / NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TDA18271_H__
+#define __TDA18271_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+struct tda18271_std_map_item {
+	u16 if_freq;
+
+	/* EP3[4:3] */
+	unsigned int agc_mode:2;
+	/* EP3[2:0] */
+	unsigned int std:3;
+	/* EP4[7] */
+	unsigned int fm_rfn:1;
+	/* EP4[4:2] */
+	unsigned int if_lvl:3;
+	/* EB22[6:0] */
+	unsigned int rfagc_top:7;
+};
+
+struct tda18271_std_map {
+	struct tda18271_std_map_item fm_radio;
+	struct tda18271_std_map_item atv_b;
+	struct tda18271_std_map_item atv_dk;
+	struct tda18271_std_map_item atv_gh;
+	struct tda18271_std_map_item atv_i;
+	struct tda18271_std_map_item atv_l;
+	struct tda18271_std_map_item atv_lc;
+	struct tda18271_std_map_item atv_mn;
+	struct tda18271_std_map_item atsc_6;
+	struct tda18271_std_map_item dvbt_6;
+	struct tda18271_std_map_item dvbt_7;
+	struct tda18271_std_map_item dvbt_8;
+	struct tda18271_std_map_item qam_6;
+	struct tda18271_std_map_item qam_7;
+	struct tda18271_std_map_item qam_8;
+};
+
+enum tda18271_role {
+	TDA18271_MASTER = 0,
+	TDA18271_SLAVE,
+};
+
+enum tda18271_i2c_gate {
+	TDA18271_GATE_AUTO = 0,
+	TDA18271_GATE_ANALOG,
+	TDA18271_GATE_DIGITAL,
+};
+
+enum tda18271_output_options {
+	/* slave tuner output & loop thru & xtal oscillator always on */
+	TDA18271_OUTPUT_LT_XT_ON = 0,
+
+	/* slave tuner output loop thru off */
+	TDA18271_OUTPUT_LT_OFF = 1,
+
+	/* xtal oscillator off */
+	TDA18271_OUTPUT_XT_OFF = 2,
+};
+
+enum tda18271_small_i2c {
+	TDA18271_39_BYTE_CHUNK_INIT = 0,
+	TDA18271_16_BYTE_CHUNK_INIT = 16,
+	TDA18271_08_BYTE_CHUNK_INIT = 8,
+	TDA18271_03_BYTE_CHUNK_INIT = 3,
+};
+
+struct tda18271_config {
+	/* override default if freq / std settings (optional) */
+	struct tda18271_std_map *std_map;
+
+	/* master / slave tuner: master uses main pll, slave uses cal pll */
+	enum tda18271_role role;
+
+	/* use i2c gate provided by analog or digital demod */
+	enum tda18271_i2c_gate gate;
+
+	/* output options that can be disabled */
+	enum tda18271_output_options output_opt;
+
+	/* some i2c providers can't write all 39 registers at once */
+	enum tda18271_small_i2c small_i2c;
+
+	/* force rf tracking filter calibration on startup */
+	unsigned int rf_cal_on_startup:1;
+
+	/* interface to saa713x / tda829x */
+	unsigned int config;
+};
+
+#define TDA18271_CALLBACK_CMD_AGC_ENABLE 0
+
+enum tda18271_mode {
+	TDA18271_ANALOG = 0,
+	TDA18271_DIGITAL,
+};
+
+#if defined(CONFIG_MEDIA_TUNER_TDA18271) || (defined(CONFIG_MEDIA_TUNER_TDA18271_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
+					    struct i2c_adapter *i2c,
+					    struct tda18271_config *cfg);
+#else
+static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe,
+						   u8 addr,
+						   struct i2c_adapter *i2c,
+						   struct tda18271_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* __TDA18271_H__ */
diff --git a/drivers/media/tuners/tda827x.c b/drivers/media/tuners/tda827x.c
new file mode 100644
index 0000000..a0d1762
--- /dev/null
+++ b/drivers/media/tuners/tda827x.c
@@ -0,0 +1,917 @@
+/*
+ *
+ * (c) 2005 Hartmut Hackmann
+ * (c) 2007 Michael Krufky
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/types.h>
+#include <linux/dvb/frontend.h>
+#include <linux/videodev2.h>
+
+#include "tda827x.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+#define dprintk(args...) \
+	do {					    \
+		if (debug) printk(KERN_DEBUG "tda827x: " args); \
+	} while (0)
+
+struct tda827x_priv {
+	int i2c_addr;
+	struct i2c_adapter *i2c_adap;
+	struct tda827x_config *cfg;
+
+	unsigned int sgIF;
+	unsigned char lpsel;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+static void tda827x_set_std(struct dvb_frontend *fe,
+			    struct analog_parameters *params)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	char *mode;
+
+	priv->lpsel = 0;
+	if (params->std & V4L2_STD_MN) {
+		priv->sgIF = 92;
+		priv->lpsel = 1;
+		mode = "MN";
+	} else if (params->std & V4L2_STD_B) {
+		priv->sgIF = 108;
+		mode = "B";
+	} else if (params->std & V4L2_STD_GH) {
+		priv->sgIF = 124;
+		mode = "GH";
+	} else if (params->std & V4L2_STD_PAL_I) {
+		priv->sgIF = 124;
+		mode = "I";
+	} else if (params->std & V4L2_STD_DK) {
+		priv->sgIF = 124;
+		mode = "DK";
+	} else if (params->std & V4L2_STD_SECAM_L) {
+		priv->sgIF = 124;
+		mode = "L";
+	} else if (params->std & V4L2_STD_SECAM_LC) {
+		priv->sgIF = 20;
+		mode = "LC";
+	} else {
+		priv->sgIF = 124;
+		mode = "xx";
+	}
+
+	if (params->mode == V4L2_TUNER_RADIO) {
+		priv->sgIF = 88; /* if frequency is 5.5 MHz */
+		dprintk("setting tda827x to radio FM\n");
+	} else
+		dprintk("setting tda827x to system %s\n", mode);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+struct tda827x_data {
+	u32 lomax;
+	u8  spd;
+	u8  bs;
+	u8  bp;
+	u8  cp;
+	u8  gc3;
+	u8 div1p5;
+};
+
+static const struct tda827x_data tda827x_table[] = {
+	{ .lomax =  62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
+	{ .lomax =  66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
+	{ .lomax =  76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
+	{ .lomax =  84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
+	{ .lomax =  93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax =  98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
+	{ .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
+	{ .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0},
+	{ .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
+	{ .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
+	{ .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
+	{ .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
+	{ .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
+	{ .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
+	{ .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
+	{ .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
+	{ .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
+	{ .lomax =         0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}
+};
+
+static int tuner_transfer(struct dvb_frontend *fe,
+			  struct i2c_msg *msg,
+			  const int size)
+{
+	int rc;
+	struct tda827x_priv *priv = fe->tuner_priv;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	rc = i2c_transfer(priv->i2c_adap, msg, size);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	if (rc >= 0 && rc != size)
+		return -EIO;
+
+	return rc;
+}
+
+static int tda827xo_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct tda827x_priv *priv = fe->tuner_priv;
+	u8 buf[14];
+	int rc;
+
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = buf, .len = sizeof(buf) };
+	int i, tuner_freq, if_freq;
+	u32 N;
+
+	dprintk("%s:\n", __func__);
+	if (c->bandwidth_hz == 0) {
+		if_freq = 5000000;
+	} else if (c->bandwidth_hz <= 6000000) {
+		if_freq = 4000000;
+	} else if (c->bandwidth_hz <= 7000000) {
+		if_freq = 4500000;
+	} else {	/* 8 MHz */
+		if_freq = 5000000;
+	}
+	tuner_freq = c->frequency;
+
+	i = 0;
+	while (tda827x_table[i].lomax < tuner_freq) {
+		if (tda827x_table[i + 1].lomax == 0)
+			break;
+		i++;
+	}
+
+	tuner_freq += if_freq;
+
+	N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2);
+	buf[0] = 0;
+	buf[1] = (N>>8) | 0x40;
+	buf[2] = N & 0xff;
+	buf[3] = 0;
+	buf[4] = 0x52;
+	buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) +
+				(tda827x_table[i].bs << 3) +
+				tda827x_table[i].bp;
+	buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f;
+	buf[7] = 0xbf;
+	buf[8] = 0x2a;
+	buf[9] = 0x05;
+	buf[10] = 0xff;
+	buf[11] = 0x00;
+	buf[12] = 0x00;
+	buf[13] = 0x40;
+
+	msg.len = 14;
+	rc = tuner_transfer(fe, &msg, 1);
+	if (rc < 0)
+		goto err;
+
+	msleep(500);
+	/* correct CP value */
+	buf[0] = 0x30;
+	buf[1] = 0x50 + tda827x_table[i].cp;
+	msg.len = 2;
+
+	rc = tuner_transfer(fe, &msg, 1);
+	if (rc < 0)
+		goto err;
+
+	priv->frequency = c->frequency;
+	priv->bandwidth = c->bandwidth_hz;
+
+	return 0;
+
+err:
+	printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n",
+	       __func__, priv->i2c_addr << 1);
+	return rc;
+}
+
+static int tda827xo_sleep(struct dvb_frontend *fe)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	static u8 buf[] = { 0x30, 0xd0 };
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = buf, .len = sizeof(buf) };
+
+	dprintk("%s:\n", __func__);
+	tuner_transfer(fe, &msg, 1);
+
+	if (priv->cfg && priv->cfg->sleep)
+		priv->cfg->sleep(fe);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda827xo_set_analog_params(struct dvb_frontend *fe,
+				      struct analog_parameters *params)
+{
+	unsigned char tuner_reg[8];
+	unsigned char reg2[2];
+	u32 N;
+	int i;
+	struct tda827x_priv *priv = fe->tuner_priv;
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 };
+	unsigned int freq = params->frequency;
+
+	tda827x_set_std(fe, params);
+
+	if (params->mode == V4L2_TUNER_RADIO)
+		freq = freq / 1000;
+
+	N = freq + priv->sgIF;
+
+	i = 0;
+	while (tda827x_table[i].lomax < N * 62500) {
+		if (tda827x_table[i + 1].lomax == 0)
+			break;
+		i++;
+	}
+
+	N = N << tda827x_table[i].spd;
+
+	tuner_reg[0] = 0;
+	tuner_reg[1] = (unsigned char)(N>>8);
+	tuner_reg[2] = (unsigned char) N;
+	tuner_reg[3] = 0x40;
+	tuner_reg[4] = 0x52 + (priv->lpsel << 5);
+	tuner_reg[5] = (tda827x_table[i].spd    << 6) +
+		       (tda827x_table[i].div1p5 << 5) +
+		       (tda827x_table[i].bs     << 3) + tda827x_table[i].bp;
+	tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4);
+	tuner_reg[7] = 0x8f;
+
+	msg.buf = tuner_reg;
+	msg.len = 8;
+	tuner_transfer(fe, &msg, 1);
+
+	msg.buf = reg2;
+	msg.len = 2;
+	reg2[0] = 0x80;
+	reg2[1] = 0;
+	tuner_transfer(fe, &msg, 1);
+
+	reg2[0] = 0x60;
+	reg2[1] = 0xbf;
+	tuner_transfer(fe, &msg, 1);
+
+	reg2[0] = 0x30;
+	reg2[1] = tuner_reg[4] + 0x80;
+	tuner_transfer(fe, &msg, 1);
+
+	msleep(1);
+	reg2[0] = 0x30;
+	reg2[1] = tuner_reg[4] + 4;
+	tuner_transfer(fe, &msg, 1);
+
+	msleep(1);
+	reg2[0] = 0x30;
+	reg2[1] = tuner_reg[4];
+	tuner_transfer(fe, &msg, 1);
+
+	msleep(550);
+	reg2[0] = 0x30;
+	reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp;
+	tuner_transfer(fe, &msg, 1);
+
+	reg2[0] = 0x60;
+	reg2[1] = 0x3f;
+	tuner_transfer(fe, &msg, 1);
+
+	reg2[0] = 0x80;
+	reg2[1] = 0x08;   /* Vsync en */
+	tuner_transfer(fe, &msg, 1);
+
+	priv->frequency = params->frequency;
+
+	return 0;
+}
+
+static void tda827xo_agcf(struct dvb_frontend *fe)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	unsigned char data[] = { 0x80, 0x0c };
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = data, .len = 2};
+
+	tuner_transfer(fe, &msg, 1);
+}
+
+/* ------------------------------------------------------------------ */
+
+struct tda827xa_data {
+	u32 lomax;
+	u8  svco;
+	u8  spd;
+	u8  scr;
+	u8  sbs;
+	u8  gc3;
+};
+
+static struct tda827xa_data tda827xa_dvbt[] = {
+	{ .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1},
+	{ .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+	{ .lomax =  81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+	{ .lomax =  97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+	{ .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
+	{ .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
+	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
+};
+
+static struct tda827xa_data tda827xa_dvbc[] = {
+	{ .lomax =  50125000, .svco = 2, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3},
+	{ .lomax =  58500000, .svco = 3, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3},
+	{ .lomax =  69250000, .svco = 0, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
+	{ .lomax =  83625000, .svco = 1, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
+	{ .lomax =  97500000, .svco = 2, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
+	{ .lomax = 100250000, .svco = 2, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1},
+	{ .lomax = 117000000, .svco = 3, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1},
+	{ .lomax = 138500000, .svco = 0, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
+	{ .lomax = 167250000, .svco = 1, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
+	{ .lomax = 187000000, .svco = 2, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
+	{ .lomax = 200500000, .svco = 2, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 1},
+	{ .lomax = 234000000, .svco = 3, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 3},
+	{ .lomax = 277000000, .svco = 0, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 3},
+	{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 1},
+	{ .lomax = 334500000, .svco = 1, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3},
+	{ .lomax = 401000000, .svco = 2, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3},
+	{ .lomax = 468000000, .svco = 3, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 1},
+	{ .lomax = 535000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
+	{ .lomax = 554000000, .svco = 0, .spd = 0, .scr = 2, .sbs = 3, .gc3 = 1},
+	{ .lomax = 638000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
+	{ .lomax = 669000000, .svco = 1, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
+	{ .lomax = 720000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
+	{ .lomax = 802000000, .svco = 2, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
+	{ .lomax = 835000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
+	{ .lomax = 885000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
+	{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
+	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
+};
+
+static struct tda827xa_data tda827xa_analog[] = {
+	{ .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},
+	{ .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
+	{ .lomax =  81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
+	{ .lomax =  97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
+	{ .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3},
+	{ .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3},
+	{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
+	{ .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
+	{ .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
+	{ .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
+	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
+};
+
+static int tda827xa_sleep(struct dvb_frontend *fe)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	static u8 buf[] = { 0x30, 0x90 };
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = buf, .len = sizeof(buf) };
+
+	dprintk("%s:\n", __func__);
+
+	tuner_transfer(fe, &msg, 1);
+
+	if (priv->cfg && priv->cfg->sleep)
+		priv->cfg->sleep(fe);
+
+	return 0;
+}
+
+static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
+			      struct analog_parameters *params)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	unsigned char buf[] = {0x22, 0x01};
+	int arg;
+	int gp_func;
+	struct i2c_msg msg = { .flags = 0, .buf = buf, .len = sizeof(buf) };
+
+	if (NULL == priv->cfg) {
+		dprintk("tda827x_config not defined, cannot set LNA gain!\n");
+		return;
+	}
+	msg.addr = priv->cfg->switch_addr;
+	if (priv->cfg->config) {
+		if (high)
+			dprintk("setting LNA to high gain\n");
+		else
+			dprintk("setting LNA to low gain\n");
+	}
+	switch (priv->cfg->config) {
+	case 0: /* no LNA */
+		break;
+	case 1: /* switch is GPIO 0 of tda8290 */
+	case 2:
+		if (params == NULL) {
+			gp_func = 0;
+			arg  = 0;
+		} else {
+			/* turn Vsync on */
+			gp_func = 1;
+			if (params->std & V4L2_STD_MN)
+				arg = 1;
+			else
+				arg = 0;
+		}
+		if (fe->callback)
+			fe->callback(priv->i2c_adap->algo_data,
+				     DVB_FRONTEND_COMPONENT_TUNER,
+				     gp_func, arg);
+		buf[1] = high ? 0 : 1;
+		if (priv->cfg->config == 2)
+			buf[1] = high ? 1 : 0;
+		tuner_transfer(fe, &msg, 1);
+		break;
+	case 3: /* switch with GPIO of saa713x */
+		if (fe->callback)
+			fe->callback(priv->i2c_adap->algo_data,
+				     DVB_FRONTEND_COMPONENT_TUNER, 0, high);
+		break;
+	}
+}
+
+static int tda827xa_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct tda827x_priv *priv = fe->tuner_priv;
+	struct tda827xa_data *frequency_map = tda827xa_dvbt;
+	u8 buf[11];
+
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = buf, .len = sizeof(buf) };
+
+	int i, tuner_freq, if_freq, rc;
+	u32 N;
+
+	dprintk("%s:\n", __func__);
+
+	tda827xa_lna_gain(fe, 1, NULL);
+	msleep(20);
+
+	if (c->bandwidth_hz == 0) {
+		if_freq = 5000000;
+	} else if (c->bandwidth_hz <= 6000000) {
+		if_freq = 4000000;
+	} else if (c->bandwidth_hz <= 7000000) {
+		if_freq = 4500000;
+	} else {	/* 8 MHz */
+		if_freq = 5000000;
+	}
+	tuner_freq = c->frequency;
+
+	switch (c->delivery_system) {
+	case SYS_DVBC_ANNEX_A:
+	case SYS_DVBC_ANNEX_C:
+		dprintk("%s select tda827xa_dvbc\n", __func__);
+		frequency_map = tda827xa_dvbc;
+		break;
+	default:
+		break;
+	}
+
+	i = 0;
+	while (frequency_map[i].lomax < tuner_freq) {
+		if (frequency_map[i + 1].lomax == 0)
+			break;
+		i++;
+	}
+
+	tuner_freq += if_freq;
+
+	N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd;
+	buf[0] = 0;            // subaddress
+	buf[1] = N >> 8;
+	buf[2] = N & 0xff;
+	buf[3] = 0;
+	buf[4] = 0x16;
+	buf[5] = (frequency_map[i].spd << 5) + (frequency_map[i].svco << 3) +
+			frequency_map[i].sbs;
+	buf[6] = 0x4b + (frequency_map[i].gc3 << 4);
+	buf[7] = 0x1c;
+	buf[8] = 0x06;
+	buf[9] = 0x24;
+	buf[10] = 0x00;
+	msg.len = 11;
+	rc = tuner_transfer(fe, &msg, 1);
+	if (rc < 0)
+		goto err;
+
+	buf[0] = 0x90;
+	buf[1] = 0xff;
+	buf[2] = 0x60;
+	buf[3] = 0x00;
+	buf[4] = 0x59;  // lpsel, for 6MHz + 2
+	msg.len = 5;
+	rc = tuner_transfer(fe, &msg, 1);
+	if (rc < 0)
+		goto err;
+
+	buf[0] = 0xa0;
+	buf[1] = 0x40;
+	msg.len = 2;
+	rc = tuner_transfer(fe, &msg, 1);
+	if (rc < 0)
+		goto err;
+
+	msleep(11);
+	msg.flags = I2C_M_RD;
+	rc = tuner_transfer(fe, &msg, 1);
+	if (rc < 0)
+		goto err;
+	msg.flags = 0;
+
+	buf[1] >>= 4;
+	dprintk("tda8275a AGC2 gain is: %d\n", buf[1]);
+	if ((buf[1]) < 2) {
+		tda827xa_lna_gain(fe, 0, NULL);
+		buf[0] = 0x60;
+		buf[1] = 0x0c;
+		rc = tuner_transfer(fe, &msg, 1);
+		if (rc < 0)
+			goto err;
+	}
+
+	buf[0] = 0xc0;
+	buf[1] = 0x99;    // lpsel, for 6MHz + 2
+	rc = tuner_transfer(fe, &msg, 1);
+	if (rc < 0)
+		goto err;
+
+	buf[0] = 0x60;
+	buf[1] = 0x3c;
+	rc = tuner_transfer(fe, &msg, 1);
+	if (rc < 0)
+		goto err;
+
+	/* correct CP value */
+	buf[0] = 0x30;
+	buf[1] = 0x10 + frequency_map[i].scr;
+	rc = tuner_transfer(fe, &msg, 1);
+	if (rc < 0)
+		goto err;
+
+	msleep(163);
+	buf[0] = 0xc0;
+	buf[1] = 0x39;  // lpsel, for 6MHz + 2
+	rc = tuner_transfer(fe, &msg, 1);
+	if (rc < 0)
+		goto err;
+
+	msleep(3);
+	/* freeze AGC1 */
+	buf[0] = 0x50;
+	buf[1] = 0x4f + (frequency_map[i].gc3 << 4);
+	rc = tuner_transfer(fe, &msg, 1);
+	if (rc < 0)
+		goto err;
+
+	priv->frequency = c->frequency;
+	priv->bandwidth = c->bandwidth_hz;
+
+	return 0;
+
+err:
+	printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n",
+	       __func__, priv->i2c_addr << 1);
+	return rc;
+}
+
+
+static int tda827xa_set_analog_params(struct dvb_frontend *fe,
+				      struct analog_parameters *params)
+{
+	unsigned char tuner_reg[11];
+	u32 N;
+	int i;
+	struct tda827x_priv *priv = fe->tuner_priv;
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = tuner_reg, .len = sizeof(tuner_reg) };
+	unsigned int freq = params->frequency;
+
+	tda827x_set_std(fe, params);
+
+	tda827xa_lna_gain(fe, 1, params);
+	msleep(10);
+
+	if (params->mode == V4L2_TUNER_RADIO)
+		freq = freq / 1000;
+
+	N = freq + priv->sgIF;
+
+	i = 0;
+	while (tda827xa_analog[i].lomax < N * 62500) {
+		if (tda827xa_analog[i + 1].lomax == 0)
+			break;
+		i++;
+	}
+
+	N = N << tda827xa_analog[i].spd;
+
+	tuner_reg[0] = 0;
+	tuner_reg[1] = (unsigned char)(N>>8);
+	tuner_reg[2] = (unsigned char) N;
+	tuner_reg[3] = 0;
+	tuner_reg[4] = 0x16;
+	tuner_reg[5] = (tda827xa_analog[i].spd << 5) +
+		       (tda827xa_analog[i].svco << 3) +
+			tda827xa_analog[i].sbs;
+	tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
+	tuner_reg[7] = 0x1c;
+	tuner_reg[8] = 4;
+	tuner_reg[9] = 0x20;
+	tuner_reg[10] = 0x00;
+	msg.len = 11;
+	tuner_transfer(fe, &msg, 1);
+
+	tuner_reg[0] = 0x90;
+	tuner_reg[1] = 0xff;
+	tuner_reg[2] = 0xe0;
+	tuner_reg[3] = 0;
+	tuner_reg[4] = 0x99 + (priv->lpsel << 1);
+	msg.len = 5;
+	tuner_transfer(fe, &msg, 1);
+
+	tuner_reg[0] = 0xa0;
+	tuner_reg[1] = 0xc0;
+	msg.len = 2;
+	tuner_transfer(fe, &msg, 1);
+
+	tuner_reg[0] = 0x30;
+	tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
+	tuner_transfer(fe, &msg, 1);
+
+	msg.flags = I2C_M_RD;
+	tuner_transfer(fe, &msg, 1);
+	msg.flags = 0;
+	tuner_reg[1] >>= 4;
+	dprintk("AGC2 gain is: %d\n", tuner_reg[1]);
+	if (tuner_reg[1] < 1)
+		tda827xa_lna_gain(fe, 0, params);
+
+	msleep(100);
+	tuner_reg[0] = 0x60;
+	tuner_reg[1] = 0x3c;
+	tuner_transfer(fe, &msg, 1);
+
+	msleep(163);
+	tuner_reg[0] = 0x50;
+	tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
+	tuner_transfer(fe, &msg, 1);
+
+	tuner_reg[0] = 0x80;
+	tuner_reg[1] = 0x28;
+	tuner_transfer(fe, &msg, 1);
+
+	tuner_reg[0] = 0xb0;
+	tuner_reg[1] = 0x01;
+	tuner_transfer(fe, &msg, 1);
+
+	tuner_reg[0] = 0xc0;
+	tuner_reg[1] = 0x19 + (priv->lpsel << 1);
+	tuner_transfer(fe, &msg, 1);
+
+	priv->frequency = params->frequency;
+
+	return 0;
+}
+
+static void tda827xa_agcf(struct dvb_frontend *fe)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	unsigned char data[] = {0x80, 0x2c};
+	struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0,
+			      .buf = data, .len = 2};
+	tuner_transfer(fe, &msg, 1);
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda827x_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+static int tda827x_init(struct dvb_frontend *fe)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	dprintk("%s:\n", __func__);
+	if (priv->cfg && priv->cfg->init)
+		priv->cfg->init(fe);
+
+	return 0;
+}
+
+static int tda827x_probe_version(struct dvb_frontend *fe);
+
+static int tda827x_initial_init(struct dvb_frontend *fe)
+{
+	int ret;
+	ret = tda827x_probe_version(fe);
+	if (ret)
+		return ret;
+	return fe->ops.tuner_ops.init(fe);
+}
+
+static int tda827x_initial_sleep(struct dvb_frontend *fe)
+{
+	int ret;
+	ret = tda827x_probe_version(fe);
+	if (ret)
+		return ret;
+	return fe->ops.tuner_ops.sleep(fe);
+}
+
+static struct dvb_tuner_ops tda827xo_tuner_ops = {
+	.info = {
+		.name = "Philips TDA827X",
+		.frequency_min  =  55000000,
+		.frequency_max  = 860000000,
+		.frequency_step =    250000
+	},
+	.release = tda827x_release,
+	.init = tda827x_initial_init,
+	.sleep = tda827x_initial_sleep,
+	.set_params = tda827xo_set_params,
+	.set_analog_params = tda827xo_set_analog_params,
+	.get_frequency = tda827x_get_frequency,
+	.get_bandwidth = tda827x_get_bandwidth,
+};
+
+static struct dvb_tuner_ops tda827xa_tuner_ops = {
+	.info = {
+		.name = "Philips TDA827XA",
+		.frequency_min  =  44000000,
+		.frequency_max  = 906000000,
+		.frequency_step =     62500
+	},
+	.release = tda827x_release,
+	.init = tda827x_init,
+	.sleep = tda827xa_sleep,
+	.set_params = tda827xa_set_params,
+	.set_analog_params = tda827xa_set_analog_params,
+	.get_frequency = tda827x_get_frequency,
+	.get_bandwidth = tda827x_get_bandwidth,
+};
+
+static int tda827x_probe_version(struct dvb_frontend *fe)
+{
+	u8 data;
+	int rc;
+	struct tda827x_priv *priv = fe->tuner_priv;
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD,
+			       .buf = &data, .len = 1 };
+
+	rc = tuner_transfer(fe, &msg, 1);
+
+	if (rc < 0) {
+		printk("%s: could not read from tuner at addr: 0x%02x\n",
+		       __func__, msg.addr << 1);
+		return rc;
+	}
+	if ((data & 0x3c) == 0) {
+		dprintk("tda827x tuner found\n");
+		fe->ops.tuner_ops.init  = tda827x_init;
+		fe->ops.tuner_ops.sleep = tda827xo_sleep;
+		if (priv->cfg)
+			priv->cfg->agcf = tda827xo_agcf;
+	} else {
+		dprintk("tda827xa tuner found\n");
+		memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops));
+		if (priv->cfg)
+			priv->cfg->agcf = tda827xa_agcf;
+	}
+	return 0;
+}
+
+struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr,
+				    struct i2c_adapter *i2c,
+				    struct tda827x_config *cfg)
+{
+	struct tda827x_priv *priv = NULL;
+
+	dprintk("%s:\n", __func__);
+	priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->i2c_addr = addr;
+	priv->i2c_adap = i2c;
+	priv->cfg = cfg;
+	memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops));
+	fe->tuner_priv = priv;
+
+	dprintk("type set to %s\n", fe->ops.tuner_ops.info.name);
+
+	return fe;
+}
+EXPORT_SYMBOL_GPL(tda827x_attach);
+
+MODULE_DESCRIPTION("DVB TDA827x driver");
+MODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann@t-online.de>");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
+MODULE_LICENSE("GPL");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/tuners/tda827x.h b/drivers/media/tuners/tda827x.h
new file mode 100644
index 0000000..7d72ce0
--- /dev/null
+++ b/drivers/media/tuners/tda827x.h
@@ -0,0 +1,68 @@
+  /*
+     DVB Driver for Philips tda827x / tda827xa Silicon tuners
+
+     (c) 2005 Hartmut Hackmann
+     (c) 2007 Michael Krufky
+
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+     the Free Software Foundation; either version 2 of the License, or
+     (at your option) any later version.
+
+     This program is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+     GNU General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, write to the Free Software
+     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+  */
+
+#ifndef __DVB_TDA827X_H__
+#define __DVB_TDA827X_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+struct tda827x_config
+{
+	/* saa7134 - provided callbacks */
+	int (*init) (struct dvb_frontend *fe);
+	int (*sleep) (struct dvb_frontend *fe);
+
+	/* interface to tda829x driver */
+	unsigned int config;
+	int 	     switch_addr;
+
+	void (*agcf)(struct dvb_frontend *fe);
+};
+
+
+/**
+ * Attach a tda827x tuner to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param addr i2c address of the tuner.
+ * @param i2c i2c adapter to use.
+ * @param cfg optional callback function pointers.
+ * @return FE pointer on success, NULL on failure.
+ */
+#if defined(CONFIG_MEDIA_TUNER_TDA827X) || (defined(CONFIG_MEDIA_TUNER_TDA827X_MODULE) && defined(MODULE))
+extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr,
+					   struct i2c_adapter *i2c,
+					   struct tda827x_config *cfg);
+#else
+static inline struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe,
+						  int addr,
+						  struct i2c_adapter *i2c,
+						  struct tda827x_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_MEDIA_TUNER_TDA827X
+
+#endif // __DVB_TDA827X_H__
diff --git a/drivers/media/tuners/tda8290.c b/drivers/media/tuners/tda8290.c
new file mode 100644
index 0000000..8c48521
--- /dev/null
+++ b/drivers/media/tuners/tda8290.c
@@ -0,0 +1,874 @@
+/*
+
+   i2c tv tuner chip device driver
+   controls the philips tda8290+75 tuner chip combo.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   This "tda8290" module was split apart from the original "tuner" module.
+*/
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include "tuner-i2c.h"
+#include "tda8290.h"
+#include "tda827x.h"
+#include "tda18271.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+static int deemphasis_50;
+module_param(deemphasis_50, int, 0644);
+MODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis");
+
+/* ---------------------------------------------------------------------- */
+
+struct tda8290_priv {
+	struct tuner_i2c_props i2c_props;
+
+	unsigned char tda8290_easy_mode;
+
+	unsigned char tda827x_addr;
+
+	unsigned char ver;
+#define TDA8290   1
+#define TDA8295   2
+#define TDA8275   4
+#define TDA8275A  8
+#define TDA18271 16
+
+	struct tda827x_config cfg;
+};
+
+/*---------------------------------------------------------------------*/
+
+static int tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+
+	unsigned char  enable[2] = { 0x21, 0xC0 };
+	unsigned char disable[2] = { 0x21, 0x00 };
+	unsigned char *msg;
+
+	if (close) {
+		msg = enable;
+		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
+		/* let the bridge stabilize */
+		msleep(20);
+	} else {
+		msg = disable;
+		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
+	}
+
+	return 0;
+}
+
+static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+
+	unsigned char  enable[2] = { 0x45, 0xc1 };
+	unsigned char disable[2] = { 0x46, 0x00 };
+	unsigned char buf[3] = { 0x45, 0x01, 0x00 };
+	unsigned char *msg;
+
+	if (close) {
+		msg = enable;
+		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
+		/* let the bridge stabilize */
+		msleep(20);
+	} else {
+		msg = disable;
+		tuner_i2c_xfer_send_recv(&priv->i2c_props, msg, 1, &msg[1], 1);
+
+		buf[2] = msg[1];
+		buf[2] &= ~0x04;
+		tuner_i2c_xfer_send(&priv->i2c_props, buf, 3);
+		msleep(5);
+
+		msg[1] |= 0x04;
+		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
+	}
+
+	return 0;
+}
+
+/*---------------------------------------------------------------------*/
+
+static void set_audio(struct dvb_frontend *fe,
+		      struct analog_parameters *params)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+	char* mode;
+
+	if (params->std & V4L2_STD_MN) {
+		priv->tda8290_easy_mode = 0x01;
+		mode = "MN";
+	} else if (params->std & V4L2_STD_B) {
+		priv->tda8290_easy_mode = 0x02;
+		mode = "B";
+	} else if (params->std & V4L2_STD_GH) {
+		priv->tda8290_easy_mode = 0x04;
+		mode = "GH";
+	} else if (params->std & V4L2_STD_PAL_I) {
+		priv->tda8290_easy_mode = 0x08;
+		mode = "I";
+	} else if (params->std & V4L2_STD_DK) {
+		priv->tda8290_easy_mode = 0x10;
+		mode = "DK";
+	} else if (params->std & V4L2_STD_SECAM_L) {
+		priv->tda8290_easy_mode = 0x20;
+		mode = "L";
+	} else if (params->std & V4L2_STD_SECAM_LC) {
+		priv->tda8290_easy_mode = 0x40;
+		mode = "LC";
+	} else {
+		priv->tda8290_easy_mode = 0x10;
+		mode = "xx";
+	}
+
+	if (params->mode == V4L2_TUNER_RADIO) {
+		/* Set TDA8295 to FM radio; Start TDA8290 with MN values */
+		priv->tda8290_easy_mode = (priv->ver & TDA8295) ? 0x80 : 0x01;
+		tuner_dbg("setting to radio FM\n");
+	} else {
+		tuner_dbg("setting tda829x to system %s\n", mode);
+	}
+}
+
+static struct {
+	unsigned char seq[2];
+} fm_mode[] = {
+	{ { 0x01, 0x81} },	/* Put device into expert mode */
+	{ { 0x03, 0x48} },	/* Disable NOTCH and VIDEO filters */
+	{ { 0x04, 0x04} },	/* Disable color carrier filter (SSIF) */
+	{ { 0x05, 0x04} },	/* ADC headroom */
+	{ { 0x06, 0x10} },	/* group delay flat */
+
+	{ { 0x07, 0x00} },	/* use the same radio DTO values as a tda8295 */
+	{ { 0x08, 0x00} },
+	{ { 0x09, 0x80} },
+	{ { 0x0a, 0xda} },
+	{ { 0x0b, 0x4b} },
+	{ { 0x0c, 0x68} },
+
+	{ { 0x0d, 0x00} },	/* PLL off, no video carrier detect */
+	{ { 0x14, 0x00} },	/* disable auto mute if no video */
+};
+
+static void tda8290_set_params(struct dvb_frontend *fe,
+			       struct analog_parameters *params)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+
+	unsigned char soft_reset[]  = { 0x00, 0x00 };
+	unsigned char easy_mode[]   = { 0x01, priv->tda8290_easy_mode };
+	unsigned char expert_mode[] = { 0x01, 0x80 };
+	unsigned char agc_out_on[]  = { 0x02, 0x00 };
+	unsigned char gainset_off[] = { 0x28, 0x14 };
+	unsigned char if_agc_spd[]  = { 0x0f, 0x88 };
+	unsigned char adc_head_6[]  = { 0x05, 0x04 };
+	unsigned char adc_head_9[]  = { 0x05, 0x02 };
+	unsigned char adc_head_12[] = { 0x05, 0x01 };
+	unsigned char pll_bw_nom[]  = { 0x0d, 0x47 };
+	unsigned char pll_bw_low[]  = { 0x0d, 0x27 };
+	unsigned char gainset_2[]   = { 0x28, 0x64 };
+	unsigned char agc_rst_on[]  = { 0x0e, 0x0b };
+	unsigned char agc_rst_off[] = { 0x0e, 0x09 };
+	unsigned char if_agc_set[]  = { 0x0f, 0x81 };
+	unsigned char addr_adc_sat  = 0x1a;
+	unsigned char addr_agc_stat = 0x1d;
+	unsigned char addr_pll_stat = 0x1b;
+	unsigned char adc_sat, agc_stat,
+		      pll_stat;
+	int i;
+
+	set_audio(fe, params);
+
+	if (priv->cfg.config)
+		tuner_dbg("tda827xa config is 0x%02x\n", priv->cfg.config);
+	tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
+	msleep(1);
+
+	if (params->mode == V4L2_TUNER_RADIO) {
+		unsigned char deemphasis[]  = { 0x13, 1 };
+
+		/* FIXME: allow using a different deemphasis */
+
+		if (deemphasis_50)
+			deemphasis[1] = 2;
+
+		for (i = 0; i < ARRAY_SIZE(fm_mode); i++)
+			tuner_i2c_xfer_send(&priv->i2c_props, fm_mode[i].seq, 2);
+
+		tuner_i2c_xfer_send(&priv->i2c_props, deemphasis, 2);
+	} else {
+		expert_mode[1] = priv->tda8290_easy_mode + 0x80;
+		tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
+		tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
+		tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
+		if (priv->tda8290_easy_mode & 0x60)
+			tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
+		else
+			tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
+		tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
+	}
+
+
+	tda8290_i2c_bridge(fe, 1);
+
+	if (fe->ops.tuner_ops.set_analog_params)
+		fe->ops.tuner_ops.set_analog_params(fe, params);
+
+	for (i = 0; i < 3; i++) {
+		tuner_i2c_xfer_send_recv(&priv->i2c_props,
+					 &addr_pll_stat, 1, &pll_stat, 1);
+		if (pll_stat & 0x80) {
+			tuner_i2c_xfer_send_recv(&priv->i2c_props,
+						 &addr_adc_sat, 1,
+						 &adc_sat, 1);
+			tuner_i2c_xfer_send_recv(&priv->i2c_props,
+						 &addr_agc_stat, 1,
+						 &agc_stat, 1);
+			tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat);
+			break;
+		} else {
+			tuner_dbg("tda8290 not locked, no signal?\n");
+			msleep(100);
+		}
+	}
+	/* adjust headroom resp. gain */
+	if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) {
+		tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n",
+			   agc_stat, adc_sat, pll_stat & 0x80);
+		tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2);
+		msleep(100);
+		tuner_i2c_xfer_send_recv(&priv->i2c_props,
+					 &addr_agc_stat, 1, &agc_stat, 1);
+		tuner_i2c_xfer_send_recv(&priv->i2c_props,
+					 &addr_pll_stat, 1, &pll_stat, 1);
+		if ((agc_stat > 115) || !(pll_stat & 0x80)) {
+			tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
+				   agc_stat, pll_stat & 0x80);
+			if (priv->cfg.agcf)
+				priv->cfg.agcf(fe);
+			msleep(100);
+			tuner_i2c_xfer_send_recv(&priv->i2c_props,
+						 &addr_agc_stat, 1,
+						 &agc_stat, 1);
+			tuner_i2c_xfer_send_recv(&priv->i2c_props,
+						 &addr_pll_stat, 1,
+						 &pll_stat, 1);
+			if((agc_stat > 115) || !(pll_stat & 0x80)) {
+				tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat);
+				tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2);
+				tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_low, 2);
+				msleep(100);
+			}
+		}
+	}
+
+	/* l/ l' deadlock? */
+	if(priv->tda8290_easy_mode & 0x60) {
+		tuner_i2c_xfer_send_recv(&priv->i2c_props,
+					 &addr_adc_sat, 1,
+					 &adc_sat, 1);
+		tuner_i2c_xfer_send_recv(&priv->i2c_props,
+					 &addr_pll_stat, 1,
+					 &pll_stat, 1);
+		if ((adc_sat > 20) || !(pll_stat & 0x80)) {
+			tuner_dbg("trying to resolve SECAM L deadlock\n");
+			tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2);
+			msleep(40);
+			tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_off, 2);
+		}
+	}
+
+	tda8290_i2c_bridge(fe, 0);
+	tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2);
+}
+
+/*---------------------------------------------------------------------*/
+
+static void tda8295_power(struct dvb_frontend *fe, int enable)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+	unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */
+
+	tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1);
+
+	if (enable)
+		buf[1] = 0x01;
+	else
+		buf[1] = 0x03;
+
+	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
+}
+
+static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+	unsigned char buf[] = { 0x01, 0x00 };
+
+	tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1);
+
+	if (enable)
+		buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */
+	else
+		buf[1] = 0x00; /* reset active bit */
+
+	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
+}
+
+static void tda8295_set_video_std(struct dvb_frontend *fe)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+	unsigned char buf[] = { 0x00, priv->tda8290_easy_mode };
+
+	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
+
+	tda8295_set_easy_mode(fe, 1);
+	msleep(20);
+	tda8295_set_easy_mode(fe, 0);
+}
+
+/*---------------------------------------------------------------------*/
+
+static void tda8295_agc1_out(struct dvb_frontend *fe, int enable)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+	unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */
+
+	tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1);
+
+	if (enable)
+		buf[1] &= ~0x40;
+	else
+		buf[1] |= 0x40;
+
+	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
+}
+
+static void tda8295_agc2_out(struct dvb_frontend *fe, int enable)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+	unsigned char set_gpio_cf[]    = { 0x44, 0x00 };
+	unsigned char set_gpio_val[]   = { 0x46, 0x00 };
+
+	tuner_i2c_xfer_send_recv(&priv->i2c_props,
+				 &set_gpio_cf[0], 1, &set_gpio_cf[1], 1);
+	tuner_i2c_xfer_send_recv(&priv->i2c_props,
+				 &set_gpio_val[0], 1, &set_gpio_val[1], 1);
+
+	set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */
+
+	if (enable) {
+		set_gpio_cf[1]  |= 0x01; /* config GPIO_0 as Open Drain Out */
+		set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */
+	}
+	tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2);
+}
+
+static int tda8295_has_signal(struct dvb_frontend *fe)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+
+	unsigned char hvpll_stat = 0x26;
+	unsigned char ret;
+
+	tuner_i2c_xfer_send_recv(&priv->i2c_props, &hvpll_stat, 1, &ret, 1);
+	return (ret & 0x01) ? 65535 : 0;
+}
+
+/*---------------------------------------------------------------------*/
+
+static void tda8295_set_params(struct dvb_frontend *fe,
+			       struct analog_parameters *params)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+
+	unsigned char blanking_mode[]     = { 0x1d, 0x00 };
+
+	set_audio(fe, params);
+
+	tuner_dbg("%s: freq = %d\n", __func__, params->frequency);
+
+	tda8295_power(fe, 1);
+	tda8295_agc1_out(fe, 1);
+
+	tuner_i2c_xfer_send_recv(&priv->i2c_props,
+				 &blanking_mode[0], 1, &blanking_mode[1], 1);
+
+	tda8295_set_video_std(fe);
+
+	blanking_mode[1] = 0x03;
+	tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2);
+	msleep(20);
+
+	tda8295_i2c_bridge(fe, 1);
+
+	if (fe->ops.tuner_ops.set_analog_params)
+		fe->ops.tuner_ops.set_analog_params(fe, params);
+
+	if (priv->cfg.agcf)
+		priv->cfg.agcf(fe);
+
+	if (tda8295_has_signal(fe))
+		tuner_dbg("tda8295 is locked\n");
+	else
+		tuner_dbg("tda8295 not locked, no signal?\n");
+
+	tda8295_i2c_bridge(fe, 0);
+}
+
+/*---------------------------------------------------------------------*/
+
+static int tda8290_has_signal(struct dvb_frontend *fe)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+
+	unsigned char i2c_get_afc[1] = { 0x1B };
+	unsigned char afc = 0;
+
+	tuner_i2c_xfer_send_recv(&priv->i2c_props,
+				 i2c_get_afc, ARRAY_SIZE(i2c_get_afc), &afc, 1);
+	return (afc & 0x80)? 65535:0;
+}
+
+/*---------------------------------------------------------------------*/
+
+static void tda8290_standby(struct dvb_frontend *fe)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+
+	unsigned char cb1[] = { 0x30, 0xD0 };
+	unsigned char tda8290_standby[] = { 0x00, 0x02 };
+	unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
+	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
+
+	tda8290_i2c_bridge(fe, 1);
+	if (priv->ver & TDA8275A)
+		cb1[1] = 0x90;
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
+	tda8290_i2c_bridge(fe, 0);
+	tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2);
+}
+
+static void tda8295_standby(struct dvb_frontend *fe)
+{
+	tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */
+
+	tda8295_power(fe, 0);
+}
+
+static void tda8290_init_if(struct dvb_frontend *fe)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+
+	unsigned char set_VS[] = { 0x30, 0x6F };
+	unsigned char set_GP00_CF[] = { 0x20, 0x01 };
+	unsigned char set_GP01_CF[] = { 0x20, 0x0B };
+
+	if ((priv->cfg.config == 1) || (priv->cfg.config == 2))
+		tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2);
+	else
+		tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2);
+}
+
+static void tda8295_init_if(struct dvb_frontend *fe)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+
+	static unsigned char set_adc_ctl[]       = { 0x33, 0x14 };
+	static unsigned char set_adc_ctl2[]      = { 0x34, 0x00 };
+	static unsigned char set_pll_reg6[]      = { 0x3e, 0x63 };
+	static unsigned char set_pll_reg0[]      = { 0x38, 0x23 };
+	static unsigned char set_pll_reg7[]      = { 0x3f, 0x01 };
+	static unsigned char set_pll_reg10[]     = { 0x42, 0x61 };
+	static unsigned char set_gpio_reg0[]     = { 0x44, 0x0b };
+
+	tda8295_power(fe, 1);
+
+	tda8295_set_easy_mode(fe, 0);
+	tda8295_set_video_std(fe);
+
+	tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2);
+
+	tda8295_agc1_out(fe, 0);
+	tda8295_agc2_out(fe, 0);
+}
+
+static void tda8290_init_tuner(struct dvb_frontend *fe)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+	unsigned char tda8275_init[]  = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
+					  0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
+	unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
+					  0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
+	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0,
+			      .buf=tda8275_init, .len = 14};
+	if (priv->ver & TDA8275A)
+		msg.buf = tda8275a_init;
+
+	tda8290_i2c_bridge(fe, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
+	tda8290_i2c_bridge(fe, 0);
+}
+
+/*---------------------------------------------------------------------*/
+
+static void tda829x_release(struct dvb_frontend *fe)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+
+	/* only try to release the tuner if we've
+	 * attached it from within this module */
+	if (priv->ver & (TDA18271 | TDA8275 | TDA8275A))
+		if (fe->ops.tuner_ops.release)
+			fe->ops.tuner_ops.release(fe);
+
+	kfree(fe->analog_demod_priv);
+	fe->analog_demod_priv = NULL;
+}
+
+static struct tda18271_config tda829x_tda18271_config = {
+	.gate    = TDA18271_GATE_ANALOG,
+};
+
+static int tda829x_find_tuner(struct dvb_frontend *fe)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+	struct analog_demod_ops *analog_ops = &fe->ops.analog_ops;
+	int i, ret, tuners_found;
+	u32 tuner_addrs;
+	u8 data;
+	struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 };
+
+	if (!analog_ops->i2c_gate_ctrl) {
+		printk(KERN_ERR "tda8290: no gate control were provided!\n");
+
+		return -EINVAL;
+	}
+
+	analog_ops->i2c_gate_ctrl(fe, 1);
+
+	/* probe for tuner chip */
+	tuners_found = 0;
+	tuner_addrs = 0;
+	for (i = 0x60; i <= 0x63; i++) {
+		msg.addr = i;
+		ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
+		if (ret == 1) {
+			tuners_found++;
+			tuner_addrs = (tuner_addrs << 8) + i;
+		}
+	}
+	/* if there is more than one tuner, we expect the right one is
+	   behind the bridge and we choose the highest address that doesn't
+	   give a response now
+	 */
+
+	analog_ops->i2c_gate_ctrl(fe, 0);
+
+	if (tuners_found > 1)
+		for (i = 0; i < tuners_found; i++) {
+			msg.addr = tuner_addrs  & 0xff;
+			ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
+			if (ret == 1)
+				tuner_addrs = tuner_addrs >> 8;
+			else
+				break;
+		}
+
+	if (tuner_addrs == 0) {
+		tuner_addrs = 0x60;
+		tuner_info("could not clearly identify tuner address, "
+			   "defaulting to %x\n", tuner_addrs);
+	} else {
+		tuner_addrs = tuner_addrs & 0xff;
+		tuner_info("setting tuner address to %x\n", tuner_addrs);
+	}
+	priv->tda827x_addr = tuner_addrs;
+	msg.addr = tuner_addrs;
+
+	analog_ops->i2c_gate_ctrl(fe, 1);
+	ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
+
+	if (ret != 1) {
+		tuner_warn("tuner access failed!\n");
+		analog_ops->i2c_gate_ctrl(fe, 0);
+		return -EREMOTEIO;
+	}
+
+	if ((data == 0x83) || (data == 0x84)) {
+		priv->ver |= TDA18271;
+		tda829x_tda18271_config.config = priv->cfg.config;
+		dvb_attach(tda18271_attach, fe, priv->tda827x_addr,
+			   priv->i2c_props.adap, &tda829x_tda18271_config);
+	} else {
+		if ((data & 0x3c) == 0)
+			priv->ver |= TDA8275;
+		else
+			priv->ver |= TDA8275A;
+
+		dvb_attach(tda827x_attach, fe, priv->tda827x_addr,
+			   priv->i2c_props.adap, &priv->cfg);
+		priv->cfg.switch_addr = priv->i2c_props.addr;
+	}
+	if (fe->ops.tuner_ops.init)
+		fe->ops.tuner_ops.init(fe);
+
+	if (fe->ops.tuner_ops.sleep)
+		fe->ops.tuner_ops.sleep(fe);
+
+	analog_ops->i2c_gate_ctrl(fe, 0);
+
+	return 0;
+}
+
+static int tda8290_probe(struct tuner_i2c_props *i2c_props)
+{
+#define TDA8290_ID 0x89
+	u8 reg = 0x1f, id;
+	struct i2c_msg msg_read[] = {
+		{ .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = &reg },
+		{ .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id },
+	};
+
+	/* detect tda8290 */
+	if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) {
+		printk(KERN_WARNING "%s: couldn't read register 0x%02x\n",
+			       __func__, reg);
+		return -ENODEV;
+	}
+
+	if (id == TDA8290_ID) {
+		if (debug)
+			printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n",
+			       __func__, i2c_adapter_id(i2c_props->adap),
+			       i2c_props->addr);
+		return 0;
+	}
+	return -ENODEV;
+}
+
+static int tda8295_probe(struct tuner_i2c_props *i2c_props)
+{
+#define TDA8295_ID 0x8a
+#define TDA8295C2_ID 0x8b
+	u8 reg = 0x2f, id;
+	struct i2c_msg msg_read[] = {
+		{ .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = &reg },
+		{ .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id },
+	};
+
+	/* detect tda8295 */
+	if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) {
+		printk(KERN_WARNING "%s: couldn't read register 0x%02x\n",
+			       __func__, reg);
+		return -ENODEV;
+	}
+
+	if ((id & 0xfe) == TDA8295_ID) {
+		if (debug)
+			printk(KERN_DEBUG "%s: %s detected @ %d-%04x\n",
+			       __func__, (id == TDA8295_ID) ?
+			       "tda8295c1" : "tda8295c2",
+			       i2c_adapter_id(i2c_props->adap),
+			       i2c_props->addr);
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+static struct analog_demod_ops tda8290_ops = {
+	.set_params     = tda8290_set_params,
+	.has_signal     = tda8290_has_signal,
+	.standby        = tda8290_standby,
+	.release        = tda829x_release,
+	.i2c_gate_ctrl  = tda8290_i2c_bridge,
+};
+
+static struct analog_demod_ops tda8295_ops = {
+	.set_params     = tda8295_set_params,
+	.has_signal     = tda8295_has_signal,
+	.standby        = tda8295_standby,
+	.release        = tda829x_release,
+	.i2c_gate_ctrl  = tda8295_i2c_bridge,
+};
+
+struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
+				    struct i2c_adapter *i2c_adap, u8 i2c_addr,
+				    struct tda829x_config *cfg)
+{
+	struct tda8290_priv *priv = NULL;
+	char *name;
+
+	priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+	fe->analog_demod_priv = priv;
+
+	priv->i2c_props.addr     = i2c_addr;
+	priv->i2c_props.adap     = i2c_adap;
+	priv->i2c_props.name     = "tda829x";
+	if (cfg)
+		priv->cfg.config         = cfg->lna_cfg;
+
+	if (tda8290_probe(&priv->i2c_props) == 0) {
+		priv->ver = TDA8290;
+		memcpy(&fe->ops.analog_ops, &tda8290_ops,
+		       sizeof(struct analog_demod_ops));
+	}
+
+	if (tda8295_probe(&priv->i2c_props) == 0) {
+		priv->ver = TDA8295;
+		memcpy(&fe->ops.analog_ops, &tda8295_ops,
+		       sizeof(struct analog_demod_ops));
+	}
+
+	if (!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) {
+		tda8295_power(fe, 1);
+		if (tda829x_find_tuner(fe) < 0)
+			goto fail;
+	}
+
+	switch (priv->ver) {
+	case TDA8290:
+		name = "tda8290";
+		break;
+	case TDA8295:
+		name = "tda8295";
+		break;
+	case TDA8290 | TDA8275:
+		name = "tda8290+75";
+		break;
+	case TDA8295 | TDA8275:
+		name = "tda8295+75";
+		break;
+	case TDA8290 | TDA8275A:
+		name = "tda8290+75a";
+		break;
+	case TDA8295 | TDA8275A:
+		name = "tda8295+75a";
+		break;
+	case TDA8290 | TDA18271:
+		name = "tda8290+18271";
+		break;
+	case TDA8295 | TDA18271:
+		name = "tda8295+18271";
+		break;
+	default:
+		goto fail;
+	}
+	tuner_info("type set to %s\n", name);
+
+	fe->ops.analog_ops.info.name = name;
+
+	if (priv->ver & TDA8290) {
+		if (priv->ver & (TDA8275 | TDA8275A))
+			tda8290_init_tuner(fe);
+		tda8290_init_if(fe);
+	} else if (priv->ver & TDA8295)
+		tda8295_init_if(fe);
+
+	return fe;
+
+fail:
+	memset(&fe->ops.analog_ops, 0, sizeof(struct analog_demod_ops));
+
+	tda829x_release(fe);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(tda829x_attach);
+
+int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
+{
+	struct tuner_i2c_props i2c_props = {
+		.adap = i2c_adap,
+		.addr = i2c_addr,
+	};
+
+	unsigned char soft_reset[]   = { 0x00, 0x00 };
+	unsigned char easy_mode_b[]  = { 0x01, 0x02 };
+	unsigned char easy_mode_g[]  = { 0x01, 0x04 };
+	unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 };
+	unsigned char addr_dto_lsb = 0x07;
+	unsigned char data;
+#define PROBE_BUFFER_SIZE 8
+	unsigned char buf[PROBE_BUFFER_SIZE];
+	int i;
+
+	/* rule out tda9887, which would return the same byte repeatedly */
+	tuner_i2c_xfer_send_recv(&i2c_props,
+				 soft_reset, 1, buf, PROBE_BUFFER_SIZE);
+	for (i = 1; i < PROBE_BUFFER_SIZE; i++) {
+		if (buf[i] != buf[0])
+			break;
+	}
+
+	/* all bytes are equal, not a tda829x - probably a tda9887 */
+	if (i == PROBE_BUFFER_SIZE)
+		return -ENODEV;
+
+	if ((tda8290_probe(&i2c_props) == 0) ||
+	    (tda8295_probe(&i2c_props) == 0))
+		return 0;
+
+	/* fall back to old probing method */
+	tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2);
+	tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
+	tuner_i2c_xfer_send_recv(&i2c_props, &addr_dto_lsb, 1, &data, 1);
+	if (data == 0) {
+		tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2);
+		tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
+		tuner_i2c_xfer_send_recv(&i2c_props,
+					 &addr_dto_lsb, 1, &data, 1);
+		if (data == 0x7b) {
+			return 0;
+		}
+	}
+	tuner_i2c_xfer_send(&i2c_props, restore_9886, 3);
+	return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(tda829x_probe);
+
+MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver");
+MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky");
+MODULE_LICENSE("GPL");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/tuners/tda8290.h b/drivers/media/tuners/tda8290.h
new file mode 100644
index 0000000..7e288b2
--- /dev/null
+++ b/drivers/media/tuners/tda8290.h
@@ -0,0 +1,56 @@
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TDA8290_H__
+#define __TDA8290_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+struct tda829x_config {
+	unsigned int lna_cfg;
+
+	unsigned int probe_tuner:1;
+#define TDA829X_PROBE_TUNER 0
+#define TDA829X_DONT_PROBE  1
+};
+
+#if defined(CONFIG_MEDIA_TUNER_TDA8290) || (defined(CONFIG_MEDIA_TUNER_TDA8290_MODULE) && defined(MODULE))
+extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr);
+
+extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
+					   struct i2c_adapter *i2c_adap,
+					   u8 i2c_addr,
+					   struct tda829x_config *cfg);
+#else
+static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -EINVAL;
+}
+
+static inline struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
+						  struct i2c_adapter *i2c_adap,
+						  u8 i2c_addr,
+						  struct tda829x_config *cfg)
+{
+	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+	       __func__);
+	return NULL;
+}
+#endif
+
+#endif /* __TDA8290_H__ */
diff --git a/drivers/media/tuners/tda9887.c b/drivers/media/tuners/tda9887.c
new file mode 100644
index 0000000..cdb645d
--- /dev/null
+++ b/drivers/media/tuners/tda9887.c
@@ -0,0 +1,717 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include "tuner-i2c.h"
+#include "tda9887.h"
+
+
+/* Chips:
+   TDA9885 (PAL, NTSC)
+   TDA9886 (PAL, SECAM, NTSC)
+   TDA9887 (PAL, SECAM, NTSC, FM Radio)
+
+   Used as part of several tuners
+*/
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+static DEFINE_MUTEX(tda9887_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
+struct tda9887_priv {
+	struct tuner_i2c_props i2c_props;
+	struct list_head hybrid_tuner_instance_list;
+
+	unsigned char 	   data[4];
+	unsigned int       config;
+	unsigned int       mode;
+	unsigned int       audmode;
+	v4l2_std_id        std;
+
+	bool               standby;
+};
+
+/* ---------------------------------------------------------------------- */
+
+#define UNSET       (-1U)
+
+struct tvnorm {
+	v4l2_std_id       std;
+	char              *name;
+	unsigned char     b;
+	unsigned char     c;
+	unsigned char     e;
+};
+
+/* ---------------------------------------------------------------------- */
+
+//
+// TDA defines
+//
+
+//// first reg (b)
+#define cVideoTrapBypassOFF     0x00    // bit b0
+#define cVideoTrapBypassON      0x01    // bit b0
+
+#define cAutoMuteFmInactive     0x00    // bit b1
+#define cAutoMuteFmActive       0x02    // bit b1
+
+#define cIntercarrier           0x00    // bit b2
+#define cQSS                    0x04    // bit b2
+
+#define cPositiveAmTV           0x00    // bit b3:4
+#define cFmRadio                0x08    // bit b3:4
+#define cNegativeFmTV           0x10    // bit b3:4
+
+
+#define cForcedMuteAudioON      0x20    // bit b5
+#define cForcedMuteAudioOFF     0x00    // bit b5
+
+#define cOutputPort1Active      0x00    // bit b6
+#define cOutputPort1Inactive    0x40    // bit b6
+
+#define cOutputPort2Active      0x00    // bit b7
+#define cOutputPort2Inactive    0x80    // bit b7
+
+
+//// second reg (c)
+#define cDeemphasisOFF          0x00    // bit c5
+#define cDeemphasisON           0x20    // bit c5
+
+#define cDeemphasis75           0x00    // bit c6
+#define cDeemphasis50           0x40    // bit c6
+
+#define cAudioGain0             0x00    // bit c7
+#define cAudioGain6             0x80    // bit c7
+
+#define cTopMask                0x1f    // bit c0:4
+#define cTopDefault		0x10 	// bit c0:4
+
+//// third reg (e)
+#define cAudioIF_4_5             0x00    // bit e0:1
+#define cAudioIF_5_5             0x01    // bit e0:1
+#define cAudioIF_6_0             0x02    // bit e0:1
+#define cAudioIF_6_5             0x03    // bit e0:1
+
+
+#define cVideoIFMask		0x1c	// bit e2:4
+/* Video IF selection in TV Mode (bit B3=0) */
+#define cVideoIF_58_75           0x00    // bit e2:4
+#define cVideoIF_45_75           0x04    // bit e2:4
+#define cVideoIF_38_90           0x08    // bit e2:4
+#define cVideoIF_38_00           0x0C    // bit e2:4
+#define cVideoIF_33_90           0x10    // bit e2:4
+#define cVideoIF_33_40           0x14    // bit e2:4
+#define cRadioIF_45_75           0x18    // bit e2:4
+#define cRadioIF_38_90           0x1C    // bit e2:4
+
+/* IF1 selection in Radio Mode (bit B3=1) */
+#define cRadioIF_33_30		0x00	// bit e2,4 (also 0x10,0x14)
+#define cRadioIF_41_30		0x04	// bit e2,4
+
+/* Output of AFC pin in radio mode when bit E7=1 */
+#define cRadioAGC_SIF		0x00	// bit e3
+#define cRadioAGC_FM		0x08	// bit e3
+
+#define cTunerGainNormal         0x00    // bit e5
+#define cTunerGainLow            0x20    // bit e5
+
+#define cGating_18               0x00    // bit e6
+#define cGating_36               0x40    // bit e6
+
+#define cAgcOutON                0x80    // bit e7
+#define cAgcOutOFF               0x00    // bit e7
+
+/* ---------------------------------------------------------------------- */
+
+static struct tvnorm tvnorms[] = {
+	{
+		.std   = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
+		.name  = "PAL-BGHN",
+		.b     = ( cNegativeFmTV  |
+			   cQSS           ),
+		.c     = ( cDeemphasisON  |
+			   cDeemphasis50  |
+			   cTopDefault),
+		.e     = ( cGating_36     |
+			   cAudioIF_5_5   |
+			   cVideoIF_38_90 ),
+	},{
+		.std   = V4L2_STD_PAL_I,
+		.name  = "PAL-I",
+		.b     = ( cNegativeFmTV  |
+			   cQSS           ),
+		.c     = ( cDeemphasisON  |
+			   cDeemphasis50  |
+			   cTopDefault),
+		.e     = ( cGating_36     |
+			   cAudioIF_6_0   |
+			   cVideoIF_38_90 ),
+	},{
+		.std   = V4L2_STD_PAL_DK,
+		.name  = "PAL-DK",
+		.b     = ( cNegativeFmTV  |
+			   cQSS           ),
+		.c     = ( cDeemphasisON  |
+			   cDeemphasis50  |
+			   cTopDefault),
+		.e     = ( cGating_36     |
+			   cAudioIF_6_5   |
+			   cVideoIF_38_90 ),
+	},{
+		.std   = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
+		.name  = "PAL-M/Nc",
+		.b     = ( cNegativeFmTV  |
+			   cQSS           ),
+		.c     = ( cDeemphasisON  |
+			   cDeemphasis75  |
+			   cTopDefault),
+		.e     = ( cGating_36     |
+			   cAudioIF_4_5   |
+			   cVideoIF_45_75 ),
+	},{
+		.std   = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
+		.name  = "SECAM-BGH",
+		.b     = ( cNegativeFmTV  |
+			   cQSS           ),
+		.c     = ( cTopDefault),
+		.e     = ( cAudioIF_5_5   |
+			   cVideoIF_38_90 ),
+	},{
+		.std   = V4L2_STD_SECAM_L,
+		.name  = "SECAM-L",
+		.b     = ( cPositiveAmTV  |
+			   cQSS           ),
+		.c     = ( cTopDefault),
+		.e     = ( cGating_36	  |
+			   cAudioIF_6_5   |
+			   cVideoIF_38_90 ),
+	},{
+		.std   = V4L2_STD_SECAM_LC,
+		.name  = "SECAM-L'",
+		.b     = ( cOutputPort2Inactive |
+			   cPositiveAmTV  |
+			   cQSS           ),
+		.c     = ( cTopDefault),
+		.e     = ( cGating_36	  |
+			   cAudioIF_6_5   |
+			   cVideoIF_33_90 ),
+	},{
+		.std   = V4L2_STD_SECAM_DK,
+		.name  = "SECAM-DK",
+		.b     = ( cNegativeFmTV  |
+			   cQSS           ),
+		.c     = ( cDeemphasisON  |
+			   cDeemphasis50  |
+			   cTopDefault),
+		.e     = ( cGating_36     |
+			   cAudioIF_6_5   |
+			   cVideoIF_38_90 ),
+	},{
+		.std   = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
+		.name  = "NTSC-M",
+		.b     = ( cNegativeFmTV  |
+			   cQSS           ),
+		.c     = ( cDeemphasisON  |
+			   cDeemphasis75  |
+			   cTopDefault),
+		.e     = ( cGating_36     |
+			   cAudioIF_4_5   |
+			   cVideoIF_45_75 ),
+	},{
+		.std   = V4L2_STD_NTSC_M_JP,
+		.name  = "NTSC-M-JP",
+		.b     = ( cNegativeFmTV  |
+			   cQSS           ),
+		.c     = ( cDeemphasisON  |
+			   cDeemphasis50  |
+			   cTopDefault),
+		.e     = ( cGating_36     |
+			   cAudioIF_4_5   |
+			   cVideoIF_58_75 ),
+	}
+};
+
+static struct tvnorm radio_stereo = {
+	.name = "Radio Stereo",
+	.b    = ( cFmRadio       |
+		  cQSS           ),
+	.c    = ( cDeemphasisOFF |
+		  cAudioGain6    |
+		  cTopDefault),
+	.e    = ( cTunerGainLow  |
+		  cAudioIF_5_5   |
+		  cRadioIF_38_90 ),
+};
+
+static struct tvnorm radio_mono = {
+	.name = "Radio Mono",
+	.b    = ( cFmRadio       |
+		  cQSS           ),
+	.c    = ( cDeemphasisON  |
+		  cDeemphasis75  |
+		  cTopDefault),
+	.e    = ( cTunerGainLow  |
+		  cAudioIF_5_5   |
+		  cRadioIF_38_90 ),
+};
+
+/* ---------------------------------------------------------------------- */
+
+static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf)
+{
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+
+	static char *afc[16] = {
+		"- 12.5 kHz",
+		"- 37.5 kHz",
+		"- 62.5 kHz",
+		"- 87.5 kHz",
+		"-112.5 kHz",
+		"-137.5 kHz",
+		"-162.5 kHz",
+		"-187.5 kHz [min]",
+		"+187.5 kHz [max]",
+		"+162.5 kHz",
+		"+137.5 kHz",
+		"+112.5 kHz",
+		"+ 87.5 kHz",
+		"+ 62.5 kHz",
+		"+ 37.5 kHz",
+		"+ 12.5 kHz",
+	};
+	tuner_info("read: 0x%2x\n", buf[0]);
+	tuner_info("  after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
+	tuner_info("  afc            : %s\n", afc[(buf[0] >> 1) & 0x0f]);
+	tuner_info("  fmif level     : %s\n", (buf[0] & 0x20) ? "high" : "low");
+	tuner_info("  afc window     : %s\n", (buf[0] & 0x40) ? "in" : "out");
+	tuner_info("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
+}
+
+static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf)
+{
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+
+	static char *sound[4] = {
+		"AM/TV",
+		"FM/radio",
+		"FM/TV",
+		"FM/radio"
+	};
+	static char *adjust[32] = {
+		"-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9",
+		"-8",  "-7",  "-6",  "-5",  "-4",  "-3",  "-2",  "-1",
+		"0",   "+1",  "+2",  "+3",  "+4",  "+5",  "+6",  "+7",
+		"+8",  "+9",  "+10", "+11", "+12", "+13", "+14", "+15"
+	};
+	static char *deemph[4] = {
+		"no", "no", "75", "50"
+	};
+	static char *carrier[4] = {
+		"4.5 MHz",
+		"5.5 MHz",
+		"6.0 MHz",
+		"6.5 MHz / AM"
+	};
+	static char *vif[8] = {
+		"58.75 MHz",
+		"45.75 MHz",
+		"38.9 MHz",
+		"38.0 MHz",
+		"33.9 MHz",
+		"33.4 MHz",
+		"45.75 MHz + pin13",
+		"38.9 MHz + pin13",
+	};
+	static char *rif[4] = {
+		"44 MHz",
+		"52 MHz",
+		"52 MHz",
+		"44 MHz",
+	};
+
+	tuner_info("write: byte B 0x%02x\n", buf[1]);
+	tuner_info("  B0   video mode      : %s\n",
+		   (buf[1] & 0x01) ? "video trap" : "sound trap");
+	tuner_info("  B1   auto mute fm    : %s\n",
+		   (buf[1] & 0x02) ? "yes" : "no");
+	tuner_info("  B2   carrier mode    : %s\n",
+		   (buf[1] & 0x04) ? "QSS" : "Intercarrier");
+	tuner_info("  B3-4 tv sound/radio  : %s\n",
+		   sound[(buf[1] & 0x18) >> 3]);
+	tuner_info("  B5   force mute audio: %s\n",
+		   (buf[1] & 0x20) ? "yes" : "no");
+	tuner_info("  B6   output port 1   : %s\n",
+		   (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
+	tuner_info("  B7   output port 2   : %s\n",
+		   (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
+
+	tuner_info("write: byte C 0x%02x\n", buf[2]);
+	tuner_info("  C0-4 top adjustment  : %s dB\n",
+		   adjust[buf[2] & 0x1f]);
+	tuner_info("  C5-6 de-emphasis     : %s\n",
+		   deemph[(buf[2] & 0x60) >> 5]);
+	tuner_info("  C7   audio gain      : %s\n",
+		   (buf[2] & 0x80) ? "-6" : "0");
+
+	tuner_info("write: byte E 0x%02x\n", buf[3]);
+	tuner_info("  E0-1 sound carrier   : %s\n",
+		   carrier[(buf[3] & 0x03)]);
+	tuner_info("  E6   l pll gating   : %s\n",
+		   (buf[3] & 0x40) ? "36" : "13");
+
+	if (buf[1] & 0x08) {
+		/* radio */
+		tuner_info("  E2-4 video if        : %s\n",
+			   rif[(buf[3] & 0x0c) >> 2]);
+		tuner_info("  E7   vif agc output  : %s\n",
+			   (buf[3] & 0x80)
+			   ? ((buf[3] & 0x10) ? "fm-agc radio" :
+						"sif-agc radio")
+			   : "fm radio carrier afc");
+	} else {
+		/* video */
+		tuner_info("  E2-4 video if        : %s\n",
+			   vif[(buf[3] & 0x1c) >> 2]);
+		tuner_info("  E5   tuner gain      : %s\n",
+			   (buf[3] & 0x80)
+			   ? ((buf[3] & 0x20) ? "external" : "normal")
+			   : ((buf[3] & 0x20) ? "minimum"  : "normal"));
+		tuner_info("  E7   vif agc output  : %s\n",
+			   (buf[3] & 0x80) ? ((buf[3] & 0x20)
+				? "pin3 port, pin22 vif agc out"
+				: "pin22 port, pin3 vif acg ext in")
+				: "pin3+pin22 port");
+	}
+	tuner_info("--\n");
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tda9887_set_tvnorm(struct dvb_frontend *fe)
+{
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+	struct tvnorm *norm = NULL;
+	char *buf = priv->data;
+	int i;
+
+	if (priv->mode == V4L2_TUNER_RADIO) {
+		if (priv->audmode == V4L2_TUNER_MODE_MONO)
+			norm = &radio_mono;
+		else
+			norm = &radio_stereo;
+	} else {
+		for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
+			if (tvnorms[i].std & priv->std) {
+				norm = tvnorms+i;
+				break;
+			}
+		}
+	}
+	if (NULL == norm) {
+		tuner_dbg("Unsupported tvnorm entry - audio muted\n");
+		return -1;
+	}
+
+	tuner_dbg("configure for: %s\n", norm->name);
+	buf[1] = norm->b;
+	buf[2] = norm->c;
+	buf[3] = norm->e;
+	return 0;
+}
+
+static unsigned int port1  = UNSET;
+static unsigned int port2  = UNSET;
+static unsigned int qss    = UNSET;
+static unsigned int adjust = UNSET;
+
+module_param(port1, int, 0644);
+module_param(port2, int, 0644);
+module_param(qss, int, 0644);
+module_param(adjust, int, 0644);
+
+static int tda9887_set_insmod(struct dvb_frontend *fe)
+{
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+	char *buf = priv->data;
+
+	if (UNSET != port1) {
+		if (port1)
+			buf[1] |= cOutputPort1Inactive;
+		else
+			buf[1] &= ~cOutputPort1Inactive;
+	}
+	if (UNSET != port2) {
+		if (port2)
+			buf[1] |= cOutputPort2Inactive;
+		else
+			buf[1] &= ~cOutputPort2Inactive;
+	}
+
+	if (UNSET != qss) {
+		if (qss)
+			buf[1] |= cQSS;
+		else
+			buf[1] &= ~cQSS;
+	}
+
+	if (adjust < 0x20) {
+		buf[2] &= ~cTopMask;
+		buf[2] |= adjust;
+	}
+	return 0;
+}
+
+static int tda9887_do_config(struct dvb_frontend *fe)
+{
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+	char *buf = priv->data;
+
+	if (priv->config & TDA9887_PORT1_ACTIVE)
+		buf[1] &= ~cOutputPort1Inactive;
+	if (priv->config & TDA9887_PORT1_INACTIVE)
+		buf[1] |= cOutputPort1Inactive;
+	if (priv->config & TDA9887_PORT2_ACTIVE)
+		buf[1] &= ~cOutputPort2Inactive;
+	if (priv->config & TDA9887_PORT2_INACTIVE)
+		buf[1] |= cOutputPort2Inactive;
+
+	if (priv->config & TDA9887_QSS)
+		buf[1] |= cQSS;
+	if (priv->config & TDA9887_INTERCARRIER)
+		buf[1] &= ~cQSS;
+
+	if (priv->config & TDA9887_AUTOMUTE)
+		buf[1] |= cAutoMuteFmActive;
+	if (priv->config & TDA9887_DEEMPHASIS_MASK) {
+		buf[2] &= ~0x60;
+		switch (priv->config & TDA9887_DEEMPHASIS_MASK) {
+		case TDA9887_DEEMPHASIS_NONE:
+			buf[2] |= cDeemphasisOFF;
+			break;
+		case TDA9887_DEEMPHASIS_50:
+			buf[2] |= cDeemphasisON | cDeemphasis50;
+			break;
+		case TDA9887_DEEMPHASIS_75:
+			buf[2] |= cDeemphasisON | cDeemphasis75;
+			break;
+		}
+	}
+	if (priv->config & TDA9887_TOP_SET) {
+		buf[2] &= ~cTopMask;
+		buf[2] |= (priv->config >> 8) & cTopMask;
+	}
+	if ((priv->config & TDA9887_INTERCARRIER_NTSC) &&
+	    (priv->std & V4L2_STD_NTSC))
+		buf[1] &= ~cQSS;
+	if (priv->config & TDA9887_GATING_18)
+		buf[3] &= ~cGating_36;
+
+	if (priv->mode == V4L2_TUNER_RADIO) {
+		if (priv->config & TDA9887_RIF_41_3) {
+			buf[3] &= ~cVideoIFMask;
+			buf[3] |= cRadioIF_41_30;
+		}
+		if (priv->config & TDA9887_GAIN_NORMAL)
+			buf[3] &= ~cTunerGainLow;
+	}
+
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tda9887_status(struct dvb_frontend *fe)
+{
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+	unsigned char buf[1];
+	int rc;
+
+	memset(buf,0,sizeof(buf));
+	if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1)))
+		tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc);
+	dump_read_message(fe, buf);
+	return 0;
+}
+
+static void tda9887_configure(struct dvb_frontend *fe)
+{
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+	int rc;
+
+	memset(priv->data,0,sizeof(priv->data));
+	tda9887_set_tvnorm(fe);
+
+	/* A note on the port settings:
+	   These settings tend to depend on the specifics of the board.
+	   By default they are set to inactive (bit value 1) by this driver,
+	   overwriting any changes made by the tvnorm. This means that it
+	   is the responsibility of the module using the tda9887 to set
+	   these values in case of changes in the tvnorm.
+	   In many cases port 2 should be made active (0) when selecting
+	   SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.
+
+	   For the other standards the tda9887 application note says that
+	   the ports should be set to active (0), but, again, that may
+	   differ depending on the precise hardware configuration.
+	 */
+	priv->data[1] |= cOutputPort1Inactive;
+	priv->data[1] |= cOutputPort2Inactive;
+
+	tda9887_do_config(fe);
+	tda9887_set_insmod(fe);
+
+	if (priv->standby)
+		priv->data[1] |= cForcedMuteAudioON;
+
+	tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
+		  priv->data[1], priv->data[2], priv->data[3]);
+	if (debug > 1)
+		dump_write_message(fe, priv->data);
+
+	if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))
+		tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc);
+
+	if (debug > 2) {
+		msleep_interruptible(1000);
+		tda9887_status(fe);
+	}
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void tda9887_tuner_status(struct dvb_frontend *fe)
+{
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+	tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n",
+		   priv->data[1], priv->data[2], priv->data[3]);
+}
+
+static int tda9887_get_afc(struct dvb_frontend *fe)
+{
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+	static int AFC_BITS_2_kHz[] = {
+		-12500,  -37500,  -62500,  -97500,
+		-112500, -137500, -162500, -187500,
+		187500,  162500,  137500,  112500,
+		97500 ,  62500,   37500 ,  12500
+	};
+	int afc=0;
+	__u8 reg = 0;
+
+	if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,&reg,1))
+		afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
+
+	return afc;
+}
+
+static void tda9887_standby(struct dvb_frontend *fe)
+{
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+
+	priv->standby = true;
+
+	tda9887_configure(fe);
+}
+
+static void tda9887_set_params(struct dvb_frontend *fe,
+			       struct analog_parameters *params)
+{
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+
+	priv->standby = false;
+	priv->mode    = params->mode;
+	priv->audmode = params->audmode;
+	priv->std     = params->std;
+	tda9887_configure(fe);
+}
+
+static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg)
+{
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+
+	priv->config = *(unsigned int *)priv_cfg;
+	tda9887_configure(fe);
+
+	return 0;
+}
+
+static void tda9887_release(struct dvb_frontend *fe)
+{
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+
+	mutex_lock(&tda9887_list_mutex);
+
+	if (priv)
+		hybrid_tuner_release_state(priv);
+
+	mutex_unlock(&tda9887_list_mutex);
+
+	fe->analog_demod_priv = NULL;
+}
+
+static struct analog_demod_ops tda9887_ops = {
+	.info		= {
+		.name	= "tda9887",
+	},
+	.set_params     = tda9887_set_params,
+	.standby        = tda9887_standby,
+	.tuner_status   = tda9887_tuner_status,
+	.get_afc        = tda9887_get_afc,
+	.release        = tda9887_release,
+	.set_config     = tda9887_set_config,
+};
+
+struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
+				    struct i2c_adapter *i2c_adap,
+				    u8 i2c_addr)
+{
+	struct tda9887_priv *priv = NULL;
+	int instance;
+
+	mutex_lock(&tda9887_list_mutex);
+
+	instance = hybrid_tuner_request_state(struct tda9887_priv, priv,
+					      hybrid_tuner_instance_list,
+					      i2c_adap, i2c_addr, "tda9887");
+	switch (instance) {
+	case 0:
+		mutex_unlock(&tda9887_list_mutex);
+		return NULL;
+	case 1:
+		fe->analog_demod_priv = priv;
+		priv->standby = true;
+		tuner_info("tda988[5/6/7] found\n");
+		break;
+	default:
+		fe->analog_demod_priv = priv;
+		break;
+	}
+
+	mutex_unlock(&tda9887_list_mutex);
+
+	memcpy(&fe->ops.analog_ops, &tda9887_ops,
+	       sizeof(struct analog_demod_ops));
+
+	return fe;
+}
+EXPORT_SYMBOL_GPL(tda9887_attach);
+
+MODULE_LICENSE("GPL");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/tuners/tda9887.h b/drivers/media/tuners/tda9887.h
new file mode 100644
index 0000000..acc419e
--- /dev/null
+++ b/drivers/media/tuners/tda9887.h
@@ -0,0 +1,38 @@
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TDA9887_H__
+#define __TDA9887_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/* ------------------------------------------------------------------------ */
+#if defined(CONFIG_MEDIA_TUNER_TDA9887) || (defined(CONFIG_MEDIA_TUNER_TDA9887_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
+					   struct i2c_adapter *i2c_adap,
+					   u8 i2c_addr);
+#else
+static inline struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
+						  struct i2c_adapter *i2c_adap,
+						  u8 i2c_addr)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* __TDA9887_H__ */
diff --git a/drivers/media/tuners/tea5761.c b/drivers/media/tuners/tea5761.c
new file mode 100644
index 0000000..bf78cb9
--- /dev/null
+++ b/drivers/media/tuners/tea5761.c
@@ -0,0 +1,348 @@
+/*
+ * For Philips TEA5761 FM Chip
+ * I2C address is allways 0x20 (0x10 at 7-bit mode).
+ *
+ * Copyright (c) 2005-2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNUv2 General Public License
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <media/tuner.h>
+#include "tuner-i2c.h"
+#include "tea5761.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+struct tea5761_priv {
+	struct tuner_i2c_props i2c_props;
+
+	u32 frequency;
+	bool standby;
+};
+
+/*****************************************************************************/
+
+/***************************
+ * TEA5761HN I2C registers *
+ ***************************/
+
+/* INTREG - Read: bytes 0 and 1 / Write: byte 0 */
+
+	/* first byte for reading */
+#define TEA5761_INTREG_IFFLAG		0x10
+#define TEA5761_INTREG_LEVFLAG		0x8
+#define TEA5761_INTREG_FRRFLAG		0x2
+#define TEA5761_INTREG_BLFLAG		0x1
+
+	/* second byte for reading / byte for writing */
+#define TEA5761_INTREG_IFMSK		0x10
+#define TEA5761_INTREG_LEVMSK		0x8
+#define TEA5761_INTREG_FRMSK		0x2
+#define TEA5761_INTREG_BLMSK		0x1
+
+/* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */
+
+	/* First byte */
+#define TEA5761_FRQSET_SEARCH_UP 0x80		/* 1=Station search from botton to up */
+#define TEA5761_FRQSET_SEARCH_MODE 0x40		/* 1=Search mode */
+
+	/* Bits 0-5 for divider MSB */
+
+	/* Second byte */
+	/* Bits 0-7 for divider LSB */
+
+/* TNCTRL - Read: bytes 4 and 5 / Write: Bytes 3 and 4 */
+
+	/* first byte */
+
+#define TEA5761_TNCTRL_PUPD_0	0x40	/* Power UP/Power Down MSB */
+#define TEA5761_TNCTRL_BLIM	0X20	/* 1= Japan Frequencies, 0= European frequencies */
+#define TEA5761_TNCTRL_SWPM	0x10	/* 1= software port is FRRFLAG */
+#define TEA5761_TNCTRL_IFCTC	0x08	/* 1= IF count time 15.02 ms, 0= IF count time 2.02 ms */
+#define TEA5761_TNCTRL_AFM	0x04
+#define TEA5761_TNCTRL_SMUTE	0x02	/* 1= Soft mute */
+#define TEA5761_TNCTRL_SNC	0x01
+
+	/* second byte */
+
+#define TEA5761_TNCTRL_MU	0x80	/* 1=Hard mute */
+#define TEA5761_TNCTRL_SSL_1	0x40
+#define TEA5761_TNCTRL_SSL_0	0x20
+#define TEA5761_TNCTRL_HLSI	0x10
+#define TEA5761_TNCTRL_MST	0x08	/* 1 = mono */
+#define TEA5761_TNCTRL_SWP	0x04
+#define TEA5761_TNCTRL_DTC	0x02	/* 1 = deemphasis 50 us, 0 = deemphasis 75 us */
+#define TEA5761_TNCTRL_AHLSI	0x01
+
+/* FRQCHECK - Read: bytes 6 and 7  */
+	/* First byte */
+
+	/* Bits 0-5 for divider MSB */
+
+	/* Second byte */
+	/* Bits 0-7 for divider LSB */
+
+/* TUNCHECK - Read: bytes 8 and 9  */
+
+	/* First byte */
+#define TEA5761_TUNCHECK_IF_MASK	0x7e	/* IF count */
+#define TEA5761_TUNCHECK_TUNTO		0x01
+
+	/* Second byte */
+#define TEA5761_TUNCHECK_LEV_MASK	0xf0	/* Level Count */
+#define TEA5761_TUNCHECK_LD		0x08
+#define TEA5761_TUNCHECK_STEREO		0x04
+
+/* TESTREG - Read: bytes 10 and 11 / Write: bytes 5 and 6 */
+
+	/* All zero = no test mode */
+
+/* MANID - Read: bytes 12 and 13 */
+
+	/* First byte - should be 0x10 */
+#define TEA5767_MANID_VERSION_MASK	0xf0	/* Version = 1 */
+#define TEA5767_MANID_ID_MSB_MASK	0x0f	/* Manufacurer ID - should be 0 */
+
+	/* Second byte - Should be 0x2b */
+
+#define TEA5767_MANID_ID_LSB_MASK	0xfe	/* Manufacturer ID - should be 0x15 */
+#define TEA5767_MANID_IDAV		0x01	/* 1 = Chip has ID, 0 = Chip has no ID */
+
+/* Chip ID - Read: bytes 14 and 15 */
+
+	/* First byte - should be 0x57 */
+
+	/* Second byte - should be 0x61 */
+
+/*****************************************************************************/
+
+#define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */
+static void tea5761_status_dump(unsigned char *buffer)
+{
+	unsigned int div, frq;
+
+	div = ((buffer[2] & 0x3f) << 8) | buffer[3];
+
+	frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4;	/* Freq in KHz */
+
+	printk(KERN_INFO "tea5761: Frequency %d.%03d KHz (divider = 0x%04x)\n",
+	       frq / 1000, frq % 1000, div);
+}
+
+/* Freq should be specifyed at 62.5 Hz */
+static int __set_radio_freq(struct dvb_frontend *fe,
+			    unsigned int freq,
+			    bool mono)
+{
+	struct tea5761_priv *priv = fe->tuner_priv;
+	unsigned int frq = freq;
+	unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 };
+	unsigned div;
+	int rc;
+
+	tuner_dbg("radio freq counter %d\n", frq);
+
+	if (priv->standby) {
+		tuner_dbg("TEA5761 set to standby mode\n");
+		buffer[5] |= TEA5761_TNCTRL_MU;
+	} else {
+		buffer[4] |= TEA5761_TNCTRL_PUPD_0;
+	}
+
+
+	if (mono) {
+		tuner_dbg("TEA5761 set to mono\n");
+		buffer[5] |= TEA5761_TNCTRL_MST;
+	} else {
+		tuner_dbg("TEA5761 set to stereo\n");
+	}
+
+	div = (1000 * (frq * 4 / 16 + 700 + 225) ) >> 15;
+	buffer[1] = (div >> 8) & 0x3f;
+	buffer[2] = div & 0xff;
+
+	if (debug)
+		tea5761_status_dump(buffer);
+
+	if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7)))
+		tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+	priv->frequency = frq * 125 / 2;
+
+	return 0;
+}
+
+static int set_radio_freq(struct dvb_frontend *fe,
+			  struct analog_parameters *params)
+{
+	struct tea5761_priv *priv = fe->analog_demod_priv;
+
+	priv->standby = false;
+
+	return __set_radio_freq(fe, params->frequency,
+				params->audmode == V4L2_TUNER_MODE_MONO);
+}
+
+static int set_radio_sleep(struct dvb_frontend *fe)
+{
+	struct tea5761_priv *priv = fe->analog_demod_priv;
+
+	priv->standby = true;
+
+	return __set_radio_freq(fe, priv->frequency, false);
+}
+
+static int tea5761_read_status(struct dvb_frontend *fe, char *buffer)
+{
+	struct tea5761_priv *priv = fe->tuner_priv;
+	int rc;
+
+	memset(buffer, 0, 16);
+	if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) {
+		tuner_warn("i2c i/o error: rc == %d (should be 16)\n", rc);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static inline int tea5761_signal(struct dvb_frontend *fe, const char *buffer)
+{
+	struct tea5761_priv *priv = fe->tuner_priv;
+
+	int signal = ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4));
+
+	tuner_dbg("Signal strength: %d\n", signal);
+
+	return signal;
+}
+
+static inline int tea5761_stereo(struct dvb_frontend *fe, const char *buffer)
+{
+	struct tea5761_priv *priv = fe->tuner_priv;
+
+	int stereo = buffer[9] & TEA5761_TUNCHECK_STEREO;
+
+	tuner_dbg("Radio ST GET = %02x\n", stereo);
+
+	return (stereo ? V4L2_TUNER_SUB_STEREO : 0);
+}
+
+static int tea5761_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	unsigned char buffer[16];
+
+	*status = 0;
+
+	if (0 == tea5761_read_status(fe, buffer)) {
+		if (tea5761_signal(fe, buffer))
+			*status = TUNER_STATUS_LOCKED;
+		if (tea5761_stereo(fe, buffer))
+			*status |= TUNER_STATUS_STEREO;
+	}
+
+	return 0;
+}
+
+static int tea5761_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	unsigned char buffer[16];
+
+	*strength = 0;
+
+	if (0 == tea5761_read_status(fe, buffer))
+		*strength = tea5761_signal(fe, buffer);
+
+	return 0;
+}
+
+int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
+{
+	unsigned char buffer[16];
+	int rc;
+	struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr };
+
+	if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) {
+		printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc);
+		return -EINVAL;
+	}
+
+	if ((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061)) {
+		printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x."
+				    " It is not a TEA5761\n",
+				    buffer[13], buffer[14], buffer[15]);
+		return -EINVAL;
+	}
+	printk(KERN_WARNING "tea5761: TEA%02x%02x detected. "
+			    "Manufacturer ID= 0x%02x\n",
+			    buffer[14], buffer[15], buffer[13]);
+
+	return 0;
+}
+
+static int tea5761_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tea5761_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static struct dvb_tuner_ops tea5761_tuner_ops = {
+	.info = {
+		.name           = "tea5761", // Philips TEA5761HN FM Radio
+	},
+	.set_analog_params = set_radio_freq,
+	.sleep		   = set_radio_sleep,
+	.release           = tea5761_release,
+	.get_frequency     = tea5761_get_frequency,
+	.get_status        = tea5761_get_status,
+	.get_rf_strength   = tea5761_get_rf_strength,
+};
+
+struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
+				    struct i2c_adapter* i2c_adap,
+				    u8 i2c_addr)
+{
+	struct tea5761_priv *priv = NULL;
+
+	if (tea5761_autodetection(i2c_adap, i2c_addr) != 0)
+		return NULL;
+
+	priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+	fe->tuner_priv = priv;
+
+	priv->i2c_props.addr = i2c_addr;
+	priv->i2c_props.adap = i2c_adap;
+	priv->i2c_props.name = "tea5761";
+
+	memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+	tuner_info("type set to %s\n", "Philips TEA5761HN FM Radio");
+
+	return fe;
+}
+
+
+EXPORT_SYMBOL_GPL(tea5761_attach);
+EXPORT_SYMBOL_GPL(tea5761_autodetection);
+
+MODULE_DESCRIPTION("Philips TEA5761 FM tuner driver");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/tea5761.h b/drivers/media/tuners/tea5761.h
new file mode 100644
index 0000000..2e2ff82
--- /dev/null
+++ b/drivers/media/tuners/tea5761.h
@@ -0,0 +1,47 @@
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TEA5761_H__
+#define __TEA5761_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE))
+extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
+
+extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
+					   struct i2c_adapter* i2c_adap,
+					   u8 i2c_addr);
+#else
+static inline int tea5761_autodetection(struct i2c_adapter* i2c_adap,
+					u8 i2c_addr)
+{
+	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+	       __func__);
+	return -EINVAL;
+}
+
+static inline struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
+						   struct i2c_adapter* i2c_adap,
+						   u8 i2c_addr)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* __TEA5761_H__ */
diff --git a/drivers/media/tuners/tea5767.c b/drivers/media/tuners/tea5767.c
new file mode 100644
index 0000000..36e85d8
--- /dev/null
+++ b/drivers/media/tuners/tea5767.c
@@ -0,0 +1,475 @@
+/*
+ * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview
+ * I2C address is allways 0xC0.
+ *
+ *
+ * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License
+ *
+ * tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa
+ * from their contributions on DScaler.
+ */
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include "tuner-i2c.h"
+#include "tea5767.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+/*****************************************************************************/
+
+struct tea5767_priv {
+	struct tuner_i2c_props	i2c_props;
+	u32			frequency;
+	struct tea5767_ctrl	ctrl;
+};
+
+/*****************************************************************************/
+
+/******************************
+ * Write mode register values *
+ ******************************/
+
+/* First register */
+#define TEA5767_MUTE		0x80	/* Mutes output */
+#define TEA5767_SEARCH		0x40	/* Activates station search */
+/* Bits 0-5 for divider MSB */
+
+/* Second register */
+/* Bits 0-7 for divider LSB */
+
+/* Third register */
+
+/* Station search from botton to up */
+#define TEA5767_SEARCH_UP	0x80
+
+/* Searches with ADC output = 10 */
+#define TEA5767_SRCH_HIGH_LVL	0x60
+
+/* Searches with ADC output = 10 */
+#define TEA5767_SRCH_MID_LVL	0x40
+
+/* Searches with ADC output = 5 */
+#define TEA5767_SRCH_LOW_LVL	0x20
+
+/* if on, div=4*(Frf+Fif)/Fref otherwise, div=4*(Frf-Fif)/Freq) */
+#define TEA5767_HIGH_LO_INJECT	0x10
+
+/* Disable stereo */
+#define TEA5767_MONO		0x08
+
+/* Disable right channel and turns to mono */
+#define TEA5767_MUTE_RIGHT	0x04
+
+/* Disable left channel and turns to mono */
+#define TEA5767_MUTE_LEFT	0x02
+
+#define TEA5767_PORT1_HIGH	0x01
+
+/* Fourth register */
+#define TEA5767_PORT2_HIGH	0x80
+/* Chips stops working. Only I2C bus remains on */
+#define TEA5767_STDBY		0x40
+
+/* Japan freq (76-108 MHz. If disabled, 87.5-108 MHz */
+#define TEA5767_JAPAN_BAND	0x20
+
+/* Unselected means 32.768 KHz freq as reference. Otherwise Xtal at 13 MHz */
+#define TEA5767_XTAL_32768	0x10
+
+/* Cuts weak signals */
+#define TEA5767_SOFT_MUTE	0x08
+
+/* Activates high cut control */
+#define TEA5767_HIGH_CUT_CTRL	0x04
+
+/* Activates stereo noise control */
+#define TEA5767_ST_NOISE_CTL	0x02
+
+/* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */
+#define TEA5767_SRCH_IND	0x01
+
+/* Fifth register */
+
+/* By activating, it will use Xtal at 13 MHz as reference for divider */
+#define TEA5767_PLLREF_ENABLE	0x80
+
+/* By activating, deemphasis=50, or else, deemphasis of 50us */
+#define TEA5767_DEEMPH_75	0X40
+
+/*****************************
+ * Read mode register values *
+ *****************************/
+
+/* First register */
+#define TEA5767_READY_FLAG_MASK	0x80
+#define TEA5767_BAND_LIMIT_MASK	0X40
+/* Bits 0-5 for divider MSB after search or preset */
+
+/* Second register */
+/* Bits 0-7 for divider LSB after search or preset */
+
+/* Third register */
+#define TEA5767_STEREO_MASK	0x80
+#define TEA5767_IF_CNTR_MASK	0x7f
+
+/* Fourth register */
+#define TEA5767_ADC_LEVEL_MASK	0xf0
+
+/* should be 0 */
+#define TEA5767_CHIP_ID_MASK	0x0f
+
+/* Fifth register */
+/* Reserved for future extensions */
+#define TEA5767_RESERVED_MASK	0xff
+
+/*****************************************************************************/
+
+static void tea5767_status_dump(struct tea5767_priv *priv,
+				unsigned char *buffer)
+{
+	unsigned int div, frq;
+
+	if (TEA5767_READY_FLAG_MASK & buffer[0])
+		tuner_info("Ready Flag ON\n");
+	else
+		tuner_info("Ready Flag OFF\n");
+
+	if (TEA5767_BAND_LIMIT_MASK & buffer[0])
+		tuner_info("Tuner at band limit\n");
+	else
+		tuner_info("Tuner not at band limit\n");
+
+	div = ((buffer[0] & 0x3f) << 8) | buffer[1];
+
+	switch (priv->ctrl.xtal_freq) {
+	case TEA5767_HIGH_LO_13MHz:
+		frq = (div * 50000 - 700000 - 225000) / 4;	/* Freq in KHz */
+		break;
+	case TEA5767_LOW_LO_13MHz:
+		frq = (div * 50000 + 700000 + 225000) / 4;	/* Freq in KHz */
+		break;
+	case TEA5767_LOW_LO_32768:
+		frq = (div * 32768 + 700000 + 225000) / 4;	/* Freq in KHz */
+		break;
+	case TEA5767_HIGH_LO_32768:
+	default:
+		frq = (div * 32768 - 700000 - 225000) / 4;	/* Freq in KHz */
+		break;
+	}
+	buffer[0] = (div >> 8) & 0x3f;
+	buffer[1] = div & 0xff;
+
+	tuner_info("Frequency %d.%03d KHz (divider = 0x%04x)\n",
+		   frq / 1000, frq % 1000, div);
+
+	if (TEA5767_STEREO_MASK & buffer[2])
+		tuner_info("Stereo\n");
+	else
+		tuner_info("Mono\n");
+
+	tuner_info("IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK);
+
+	tuner_info("ADC Level = %d\n",
+		   (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4);
+
+	tuner_info("Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK));
+
+	tuner_info("Reserved = 0x%02x\n",
+		   (buffer[4] & TEA5767_RESERVED_MASK));
+}
+
+/* Freq should be specifyed at 62.5 Hz */
+static int set_radio_freq(struct dvb_frontend *fe,
+			  struct analog_parameters *params)
+{
+	struct tea5767_priv *priv = fe->tuner_priv;
+	unsigned int frq = params->frequency;
+	unsigned char buffer[5];
+	unsigned div;
+	int rc;
+
+	tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000);
+
+	buffer[2] = 0;
+
+	if (priv->ctrl.port1)
+		buffer[2] |= TEA5767_PORT1_HIGH;
+
+	if (params->audmode == V4L2_TUNER_MODE_MONO) {
+		tuner_dbg("TEA5767 set to mono\n");
+		buffer[2] |= TEA5767_MONO;
+	} else {
+		tuner_dbg("TEA5767 set to stereo\n");
+	}
+
+
+	buffer[3] = 0;
+
+	if (priv->ctrl.port2)
+		buffer[3] |= TEA5767_PORT2_HIGH;
+
+	if (priv->ctrl.high_cut)
+		buffer[3] |= TEA5767_HIGH_CUT_CTRL;
+
+	if (priv->ctrl.st_noise)
+		buffer[3] |= TEA5767_ST_NOISE_CTL;
+
+	if (priv->ctrl.soft_mute)
+		buffer[3] |= TEA5767_SOFT_MUTE;
+
+	if (priv->ctrl.japan_band)
+		buffer[3] |= TEA5767_JAPAN_BAND;
+
+	buffer[4] = 0;
+
+	if (priv->ctrl.deemph_75)
+		buffer[4] |= TEA5767_DEEMPH_75;
+
+	if (priv->ctrl.pllref)
+		buffer[4] |= TEA5767_PLLREF_ENABLE;
+
+
+	/* Rounds freq to next decimal value - for 62.5 KHz step */
+	/* frq = 20*(frq/16)+radio_frq[frq%16]; */
+
+	switch (priv->ctrl.xtal_freq) {
+	case TEA5767_HIGH_LO_13MHz:
+		tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n");
+		buffer[2] |= TEA5767_HIGH_LO_INJECT;
+		div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000;
+		break;
+	case TEA5767_LOW_LO_13MHz:
+		tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n");
+
+		div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000;
+		break;
+	case TEA5767_LOW_LO_32768:
+		tuner_dbg("radio LOW LO inject xtal @ 32,768 MHz\n");
+		buffer[3] |= TEA5767_XTAL_32768;
+		/* const 700=4000*175 Khz - to adjust freq to right value */
+		div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15;
+		break;
+	case TEA5767_HIGH_LO_32768:
+	default:
+		tuner_dbg("radio HIGH LO inject xtal @ 32,768 MHz\n");
+
+		buffer[2] |= TEA5767_HIGH_LO_INJECT;
+		buffer[3] |= TEA5767_XTAL_32768;
+		div = ((frq * (4000 / 16) + 700000 + 225000) + 16384) >> 15;
+		break;
+	}
+	buffer[0] = (div >> 8) & 0x3f;
+	buffer[1] = div & 0xff;
+
+	if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5)))
+		tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+	if (debug) {
+		if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5)))
+			tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+		else
+			tea5767_status_dump(priv, buffer);
+	}
+
+	priv->frequency = frq * 125 / 2;
+
+	return 0;
+}
+
+static int tea5767_read_status(struct dvb_frontend *fe, char *buffer)
+{
+	struct tea5767_priv *priv = fe->tuner_priv;
+	int rc;
+
+	memset(buffer, 0, 5);
+	if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) {
+		tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static inline int tea5767_signal(struct dvb_frontend *fe, const char *buffer)
+{
+	struct tea5767_priv *priv = fe->tuner_priv;
+
+	int signal = ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8);
+
+	tuner_dbg("Signal strength: %d\n", signal);
+
+	return signal;
+}
+
+static inline int tea5767_stereo(struct dvb_frontend *fe, const char *buffer)
+{
+	struct tea5767_priv *priv = fe->tuner_priv;
+
+	int stereo = buffer[2] & TEA5767_STEREO_MASK;
+
+	tuner_dbg("Radio ST GET = %02x\n", stereo);
+
+	return (stereo ? V4L2_TUNER_SUB_STEREO : 0);
+}
+
+static int tea5767_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	unsigned char buffer[5];
+
+	*status = 0;
+
+	if (0 == tea5767_read_status(fe, buffer)) {
+		if (tea5767_signal(fe, buffer))
+			*status = TUNER_STATUS_LOCKED;
+		if (tea5767_stereo(fe, buffer))
+			*status |= TUNER_STATUS_STEREO;
+	}
+
+	return 0;
+}
+
+static int tea5767_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	unsigned char buffer[5];
+
+	*strength = 0;
+
+	if (0 == tea5767_read_status(fe, buffer))
+		*strength = tea5767_signal(fe, buffer);
+
+	return 0;
+}
+
+static int tea5767_standby(struct dvb_frontend *fe)
+{
+	unsigned char buffer[5];
+	struct tea5767_priv *priv = fe->tuner_priv;
+	unsigned div, rc;
+
+	div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */
+	buffer[0] = (div >> 8) & 0x3f;
+	buffer[1] = div & 0xff;
+	buffer[2] = TEA5767_PORT1_HIGH;
+	buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL |
+		    TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY;
+	buffer[4] = 0;
+
+	if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5)))
+		tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+	return 0;
+}
+
+int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
+{
+	struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr };
+	unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+	int rc;
+
+	if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) {
+		printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc);
+		return -EINVAL;
+	}
+
+	/* If all bytes are the same then it's a TV tuner and not a tea5767 */
+	if (buffer[0] == buffer[1] && buffer[0] == buffer[2] &&
+	    buffer[0] == buffer[3] && buffer[0] == buffer[4]) {
+		printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n");
+		return -EINVAL;
+	}
+
+	/*  Status bytes:
+	 *  Byte 4: bit 3:1 : CI (Chip Identification) == 0
+	 *          bit 0   : internally set to 0
+	 *  Byte 5: bit 7:0 : == 0
+	 */
+	if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) {
+		printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n");
+		return -EINVAL;
+	}
+
+
+	return 0;
+}
+
+static int tea5767_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tea5767_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+
+	return 0;
+}
+
+static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg)
+{
+	struct tea5767_priv *priv = fe->tuner_priv;
+
+	memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl));
+
+	return 0;
+}
+
+static struct dvb_tuner_ops tea5767_tuner_ops = {
+	.info = {
+		.name           = "tea5767", // Philips TEA5767HN FM Radio
+	},
+
+	.set_analog_params = set_radio_freq,
+	.set_config	   = tea5767_set_config,
+	.sleep             = tea5767_standby,
+	.release           = tea5767_release,
+	.get_frequency     = tea5767_get_frequency,
+	.get_status        = tea5767_get_status,
+	.get_rf_strength   = tea5767_get_rf_strength,
+};
+
+struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
+				    struct i2c_adapter* i2c_adap,
+				    u8 i2c_addr)
+{
+	struct tea5767_priv *priv = NULL;
+
+	priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+	fe->tuner_priv = priv;
+
+	priv->i2c_props.addr  = i2c_addr;
+	priv->i2c_props.adap  = i2c_adap;
+	priv->i2c_props.name  = "tea5767";
+
+	priv->ctrl.xtal_freq  = TEA5767_HIGH_LO_32768;
+	priv->ctrl.port1      = 1;
+	priv->ctrl.port2      = 1;
+	priv->ctrl.high_cut   = 1;
+	priv->ctrl.st_noise   = 1;
+	priv->ctrl.japan_band = 1;
+
+	memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+	tuner_info("type set to %s\n", "Philips TEA5767HN FM Radio");
+
+	return fe;
+}
+
+EXPORT_SYMBOL_GPL(tea5767_attach);
+EXPORT_SYMBOL_GPL(tea5767_autodetection);
+
+MODULE_DESCRIPTION("Philips TEA5767 FM tuner driver");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/tea5767.h b/drivers/media/tuners/tea5767.h
new file mode 100644
index 0000000..d30ab1b
--- /dev/null
+++ b/drivers/media/tuners/tea5767.h
@@ -0,0 +1,66 @@
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TEA5767_H__
+#define __TEA5767_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+enum tea5767_xtal {
+	TEA5767_LOW_LO_32768    = 0,
+	TEA5767_HIGH_LO_32768   = 1,
+	TEA5767_LOW_LO_13MHz    = 2,
+	TEA5767_HIGH_LO_13MHz   = 3,
+};
+
+struct tea5767_ctrl {
+	unsigned int		port1:1;
+	unsigned int		port2:1;
+	unsigned int		high_cut:1;
+	unsigned int		st_noise:1;
+	unsigned int		soft_mute:1;
+	unsigned int		japan_band:1;
+	unsigned int		deemph_75:1;
+	unsigned int		pllref:1;
+	enum tea5767_xtal	xtal_freq;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_TEA5767) || (defined(CONFIG_MEDIA_TUNER_TEA5767_MODULE) && defined(MODULE))
+extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
+
+extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
+					   struct i2c_adapter* i2c_adap,
+					   u8 i2c_addr);
+#else
+static inline int tea5767_autodetection(struct i2c_adapter* i2c_adap,
+					u8 i2c_addr)
+{
+	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+	       __func__);
+	return -EINVAL;
+}
+
+static inline struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
+						   struct i2c_adapter* i2c_adap,
+						   u8 i2c_addr)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* __TEA5767_H__ */
diff --git a/drivers/media/tuners/tua9001.c b/drivers/media/tuners/tua9001.c
new file mode 100644
index 0000000..de26070
--- /dev/null
+++ b/drivers/media/tuners/tua9001.c
@@ -0,0 +1,215 @@
+/*
+ * Infineon TUA 9001 silicon tuner driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "tua9001.h"
+#include "tua9001_priv.h"
+
+/* write register */
+static int tua9001_wr_reg(struct tua9001_priv *priv, u8 reg, u16 val)
+{
+	int ret;
+	u8 buf[3] = { reg, (val >> 8) & 0xff, (val >> 0) & 0xff };
+	struct i2c_msg msg[1] = {
+		{
+			.addr = priv->cfg->i2c_addr,
+			.flags = 0,
+			.len = sizeof(buf),
+			.buf = buf,
+		}
+	};
+
+	ret = i2c_transfer(priv->i2c, msg, 1);
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		printk(KERN_WARNING "%s: I2C wr failed=%d reg=%02x\n",
+				__func__, ret, reg);
+		ret = -EREMOTEIO;
+	}
+
+	return ret;
+}
+
+static int tua9001_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static int tua9001_init(struct dvb_frontend *fe)
+{
+	struct tua9001_priv *priv = fe->tuner_priv;
+	int ret = 0;
+	u8 i;
+	struct reg_val data[] = {
+		{ 0x1e, 0x6512 },
+		{ 0x25, 0xb888 },
+		{ 0x39, 0x5460 },
+		{ 0x3b, 0x00c0 },
+		{ 0x3a, 0xf000 },
+		{ 0x08, 0x0000 },
+		{ 0x32, 0x0030 },
+		{ 0x41, 0x703a },
+		{ 0x40, 0x1c78 },
+		{ 0x2c, 0x1c00 },
+		{ 0x36, 0xc013 },
+		{ 0x37, 0x6f18 },
+		{ 0x27, 0x0008 },
+		{ 0x2a, 0x0001 },
+		{ 0x34, 0x0a40 },
+	};
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */
+
+	for (i = 0; i < ARRAY_SIZE(data); i++) {
+		ret = tua9001_wr_reg(priv, data[i].reg, data[i].val);
+		if (ret)
+			break;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */
+
+	if (ret < 0)
+		pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int tua9001_set_params(struct dvb_frontend *fe)
+{
+	struct tua9001_priv *priv = fe->tuner_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i;
+	u16 val;
+	u32 frequency;
+	struct reg_val data[2];
+
+	pr_debug("%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n",
+			__func__, c->delivery_system, c->frequency,
+			c->bandwidth_hz);
+
+	switch (c->delivery_system) {
+	case SYS_DVBT:
+		switch (c->bandwidth_hz) {
+		case 8000000:
+			val  = 0x0000;
+			break;
+		case 7000000:
+			val  = 0x1000;
+			break;
+		case 6000000:
+			val  = 0x2000;
+			break;
+		case 5000000:
+			val  = 0x3000;
+			break;
+		default:
+			ret = -EINVAL;
+			goto err;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		goto err;
+	}
+
+	data[0].reg = 0x04;
+	data[0].val = val;
+
+	frequency = (c->frequency - 150000000);
+	frequency /= 100;
+	frequency *= 48;
+	frequency /= 10000;
+
+	data[1].reg = 0x1f;
+	data[1].val = frequency;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */
+
+	for (i = 0; i < ARRAY_SIZE(data); i++) {
+		ret = tua9001_wr_reg(priv, data[i].reg, data[i].val);
+		if (ret < 0)
+			break;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */
+
+err:
+	if (ret < 0)
+		pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	*frequency = 0; /* Zero-IF */
+
+	return 0;
+}
+
+static const struct dvb_tuner_ops tua9001_tuner_ops = {
+	.info = {
+		.name           = "Infineon TUA 9001",
+
+		.frequency_min  = 170000000,
+		.frequency_max  = 862000000,
+		.frequency_step = 0,
+	},
+
+	.release = tua9001_release,
+
+	.init = tua9001_init,
+	.set_params = tua9001_set_params,
+
+	.get_if_frequency = tua9001_get_if_frequency,
+};
+
+struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe,
+		struct i2c_adapter *i2c, struct tua9001_config *cfg)
+{
+	struct tua9001_priv *priv = NULL;
+
+	priv = kzalloc(sizeof(struct tua9001_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->cfg = cfg;
+	priv->i2c = i2c;
+
+	printk(KERN_INFO "Infineon TUA 9001 successfully attached.");
+
+	memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops,
+			sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+	return fe;
+}
+EXPORT_SYMBOL(tua9001_attach);
+
+MODULE_DESCRIPTION("Infineon TUA 9001 silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/tua9001.h b/drivers/media/tuners/tua9001.h
new file mode 100644
index 0000000..38d6ae7
--- /dev/null
+++ b/drivers/media/tuners/tua9001.h
@@ -0,0 +1,46 @@
+/*
+ * Infineon TUA 9001 silicon tuner driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef TUA9001_H
+#define TUA9001_H
+
+#include "dvb_frontend.h"
+
+struct tua9001_config {
+	/*
+	 * I2C address
+	 */
+	u8 i2c_addr;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_TUA9001) || \
+	(defined(CONFIG_MEDIA_TUNER_TUA9001_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe,
+		struct i2c_adapter *i2c, struct tua9001_config *cfg);
+#else
+static inline struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe,
+		struct i2c_adapter *i2c, struct tua9001_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/tuners/tua9001_priv.h b/drivers/media/tuners/tua9001_priv.h
new file mode 100644
index 0000000..73cc1ce
--- /dev/null
+++ b/drivers/media/tuners/tua9001_priv.h
@@ -0,0 +1,34 @@
+/*
+ * Infineon TUA 9001 silicon tuner driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef TUA9001_PRIV_H
+#define TUA9001_PRIV_H
+
+struct reg_val {
+	u8 reg;
+	u16 val;
+};
+
+struct tua9001_priv {
+	struct tua9001_config *cfg;
+	struct i2c_adapter *i2c;
+};
+
+#endif
diff --git a/drivers/media/tuners/tuner-i2c.h b/drivers/media/tuners/tuner-i2c.h
new file mode 100644
index 0000000..18f0056
--- /dev/null
+++ b/drivers/media/tuners/tuner-i2c.h
@@ -0,0 +1,182 @@
+/*
+    tuner-i2c.h - i2c interface for different tuners
+
+    Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TUNER_I2C_H__
+#define __TUNER_I2C_H__
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+struct tuner_i2c_props {
+	u8 addr;
+	struct i2c_adapter *adap;
+
+	/* used for tuner instance management */
+	int count;
+	char *name;
+};
+
+static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len)
+{
+	struct i2c_msg msg = { .addr = props->addr, .flags = 0,
+			       .buf = buf, .len = len };
+	int ret = i2c_transfer(props->adap, &msg, 1);
+
+	return (ret == 1) ? len : ret;
+}
+
+static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, int len)
+{
+	struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD,
+			       .buf = buf, .len = len };
+	int ret = i2c_transfer(props->adap, &msg, 1);
+
+	return (ret == 1) ? len : ret;
+}
+
+static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props,
+					   char *obuf, int olen,
+					   char *ibuf, int ilen)
+{
+	struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0,
+				    .buf = obuf, .len = olen },
+				  { .addr = props->addr, .flags = I2C_M_RD,
+				    .buf = ibuf, .len = ilen } };
+	int ret = i2c_transfer(props->adap, msg, 2);
+
+	return (ret == 2) ? ilen : ret;
+}
+
+/* Callers must declare as a global for the module:
+ *
+ * static LIST_HEAD(hybrid_tuner_instance_list);
+ *
+ * hybrid_tuner_instance_list should be the third argument
+ * passed into hybrid_tuner_request_state().
+ *
+ * state structure must contain the following:
+ *
+ * 	struct list_head	hybrid_tuner_instance_list;
+ *	struct tuner_i2c_props	i2c_props;
+ *
+ * hybrid_tuner_instance_list (both within state structure and globally)
+ * is only required if the driver is using hybrid_tuner_request_state
+ * and hybrid_tuner_release_state to manage state sharing between
+ * multiple instances of hybrid tuners.
+ */
+
+#define tuner_printk(kernlvl, i2cprops, fmt, arg...) do {		\
+	printk(kernlvl "%s %d-%04x: " fmt, i2cprops.name,		\
+			i2cprops.adap ?					\
+				i2c_adapter_id(i2cprops.adap) : -1,	\
+			i2cprops.addr, ##arg);				\
+	 } while (0)
+
+/* TO DO: convert all callers of these macros to pass in
+ * struct tuner_i2c_props, then remove the macro wrappers */
+
+#define __tuner_warn(i2cprops, fmt, arg...) do {			\
+	tuner_printk(KERN_WARNING, i2cprops, fmt, ##arg);		\
+	} while (0)
+
+#define __tuner_info(i2cprops, fmt, arg...) do {			\
+	tuner_printk(KERN_INFO, i2cprops, fmt, ##arg);			\
+	} while (0)
+
+#define __tuner_err(i2cprops, fmt, arg...) do {				\
+	tuner_printk(KERN_ERR, i2cprops, fmt, ##arg);			\
+	} while (0)
+
+#define __tuner_dbg(i2cprops, fmt, arg...) do {				\
+	if ((debug))							\
+		tuner_printk(KERN_DEBUG, i2cprops, fmt, ##arg);		\
+	} while (0)
+
+#define tuner_warn(fmt, arg...) __tuner_warn(priv->i2c_props, fmt, ##arg)
+#define tuner_info(fmt, arg...) __tuner_info(priv->i2c_props, fmt, ##arg)
+#define tuner_err(fmt, arg...) __tuner_err(priv->i2c_props, fmt, ##arg)
+#define tuner_dbg(fmt, arg...) __tuner_dbg(priv->i2c_props, fmt, ##arg)
+
+/****************************************************************************/
+
+/* The return value of hybrid_tuner_request_state indicates the number of
+ * instances using this tuner object.
+ *
+ * 0 - no instances, indicates an error - kzalloc must have failed
+ *
+ * 1 - one instance, indicates that the tuner object was created successfully
+ *
+ * 2 (or more) instances, indicates that an existing tuner object was found
+ */
+
+#define hybrid_tuner_request_state(type, state, list, i2cadap, i2caddr, devname)\
+({									\
+	int __ret = 0;							\
+	list_for_each_entry(state, &list, hybrid_tuner_instance_list) {	\
+		if (((i2cadap) && (state->i2c_props.adap)) &&		\
+		    ((i2c_adapter_id(state->i2c_props.adap) ==		\
+		      i2c_adapter_id(i2cadap)) &&			\
+		     (i2caddr == state->i2c_props.addr))) {		\
+			__tuner_info(state->i2c_props,			\
+				     "attaching existing instance\n");	\
+			state->i2c_props.count++;			\
+			__ret = state->i2c_props.count;			\
+			break;						\
+		}							\
+	}								\
+	if (0 == __ret) {						\
+		state = kzalloc(sizeof(type), GFP_KERNEL);		\
+		if (NULL == state)					\
+			goto __fail;					\
+		state->i2c_props.addr = i2caddr;			\
+		state->i2c_props.adap = i2cadap;			\
+		state->i2c_props.name = devname;			\
+		__tuner_info(state->i2c_props,				\
+			     "creating new instance\n");		\
+		list_add_tail(&state->hybrid_tuner_instance_list, &list);\
+		state->i2c_props.count++;				\
+		__ret = state->i2c_props.count;				\
+	}								\
+__fail:									\
+	__ret;								\
+})
+
+#define hybrid_tuner_release_state(state)				\
+({									\
+	int __ret;							\
+	state->i2c_props.count--;					\
+	__ret = state->i2c_props.count;					\
+	if (!state->i2c_props.count) {					\
+		__tuner_info(state->i2c_props, "destroying instance\n");\
+		list_del(&state->hybrid_tuner_instance_list);		\
+		kfree(state);						\
+	}								\
+	__ret;								\
+})
+
+#define hybrid_tuner_report_instance_count(state)			\
+({									\
+	int __ret = 0;							\
+	if (state)							\
+		__ret = state->i2c_props.count;				\
+	__ret;								\
+})
+
+#endif /* __TUNER_I2C_H__ */
diff --git a/drivers/media/tuners/tuner-simple.c b/drivers/media/tuners/tuner-simple.c
new file mode 100644
index 0000000..39e7e58
--- /dev/null
+++ b/drivers/media/tuners/tuner-simple.c
@@ -0,0 +1,1155 @@
+/*
+ * i2c tv tuner chip device driver
+ * controls all those simple 4-control-bytes style tuners.
+ *
+ * This "tuner-simple" module was split apart from the original "tuner" module.
+ */
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/tuner.h>
+#include <media/v4l2-common.h>
+#include <media/tuner-types.h>
+#include "tuner-i2c.h"
+#include "tuner-simple.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+#define TUNER_SIMPLE_MAX 64
+static unsigned int simple_devcount;
+
+static int offset;
+module_param(offset, int, 0664);
+MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner");
+
+static unsigned int atv_input[TUNER_SIMPLE_MAX] = \
+			{ [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
+static unsigned int dtv_input[TUNER_SIMPLE_MAX] = \
+			{ [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
+module_param_array(atv_input, int, NULL, 0644);
+module_param_array(dtv_input, int, NULL, 0644);
+MODULE_PARM_DESC(atv_input, "specify atv rf input, 0 for autoselect");
+MODULE_PARM_DESC(dtv_input, "specify dtv rf input, 0 for autoselect");
+
+/* ---------------------------------------------------------------------- */
+
+/* tv standard selection for Temic 4046 FM5
+   this value takes the low bits of control byte 2
+   from datasheet Rev.01, Feb.00
+     standard     BG      I       L       L2      D
+     picture IF   38.9    38.9    38.9    33.95   38.9
+     sound 1      33.4    32.9    32.4    40.45   32.4
+     sound 2      33.16
+     NICAM        33.05   32.348  33.05           33.05
+ */
+#define TEMIC_SET_PAL_I         0x05
+#define TEMIC_SET_PAL_DK        0x09
+#define TEMIC_SET_PAL_L         0x0a /* SECAM ? */
+#define TEMIC_SET_PAL_L2        0x0b /* change IF ! */
+#define TEMIC_SET_PAL_BG        0x0c
+
+/* tv tuner system standard selection for Philips FQ1216ME
+   this value takes the low bits of control byte 2
+   from datasheet "1999 Nov 16" (supersedes "1999 Mar 23")
+     standard 		BG	DK	I	L	L`
+     picture carrier	38.90	38.90	38.90	38.90	33.95
+     colour		34.47	34.47	34.47	34.47	38.38
+     sound 1		33.40	32.40	32.90	32.40	40.45
+     sound 2		33.16	-	-	-	-
+     NICAM		33.05	33.05	32.35	33.05	39.80
+ */
+#define PHILIPS_SET_PAL_I	0x01 /* Bit 2 always zero !*/
+#define PHILIPS_SET_PAL_BGDK	0x09
+#define PHILIPS_SET_PAL_L2	0x0a
+#define PHILIPS_SET_PAL_L	0x0b
+
+/* system switching for Philips FI1216MF MK2
+   from datasheet "1996 Jul 09",
+    standard         BG     L      L'
+    picture carrier  38.90  38.90  33.95
+    colour	     34.47  34.37  38.38
+    sound 1          33.40  32.40  40.45
+    sound 2          33.16  -      -
+    NICAM            33.05  33.05  39.80
+ */
+#define PHILIPS_MF_SET_STD_BG	0x01 /* Bit 2 must be zero, Bit 3 is system output */
+#define PHILIPS_MF_SET_STD_L	0x03 /* Used on Secam France */
+#define PHILIPS_MF_SET_STD_LC	0x02 /* Used on SECAM L' */
+
+/* Control byte */
+
+#define TUNER_RATIO_MASK        0x06 /* Bit cb1:cb2 */
+#define TUNER_RATIO_SELECT_50   0x00
+#define TUNER_RATIO_SELECT_32   0x02
+#define TUNER_RATIO_SELECT_166  0x04
+#define TUNER_RATIO_SELECT_62   0x06
+
+#define TUNER_CHARGE_PUMP       0x40  /* Bit cb6 */
+
+/* Status byte */
+
+#define TUNER_POR	  0x80
+#define TUNER_FL          0x40
+#define TUNER_MODE        0x38
+#define TUNER_AFC         0x07
+#define TUNER_SIGNAL      0x07
+#define TUNER_STEREO      0x10
+
+#define TUNER_PLL_LOCKED   0x40
+#define TUNER_STEREO_MK3   0x04
+
+static DEFINE_MUTEX(tuner_simple_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
+struct tuner_simple_priv {
+	unsigned int nr;
+	u16 last_div;
+
+	struct tuner_i2c_props i2c_props;
+	struct list_head hybrid_tuner_instance_list;
+
+	unsigned int type;
+	struct tunertype *tun;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+/* ---------------------------------------------------------------------- */
+
+static int tuner_read_status(struct dvb_frontend *fe)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	unsigned char byte;
+
+	if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1))
+		return 0;
+
+	return byte;
+}
+
+static inline int tuner_signal(const int status)
+{
+	return (status & TUNER_SIGNAL) << 13;
+}
+
+static inline int tuner_stereo(const int type, const int status)
+{
+	switch (type) {
+	case TUNER_PHILIPS_FM1216ME_MK3:
+	case TUNER_PHILIPS_FM1236_MK3:
+	case TUNER_PHILIPS_FM1256_IH3:
+	case TUNER_LG_NTSC_TAPE:
+	case TUNER_TCL_MF02GIP_5N:
+		return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
+	case TUNER_PHILIPS_FM1216MK5:
+		return status | TUNER_STEREO;
+	default:
+		return status & TUNER_STEREO;
+	}
+}
+
+static inline int tuner_islocked(const int status)
+{
+	return (status & TUNER_FL);
+}
+
+static inline int tuner_afcstatus(const int status)
+{
+	return (status & TUNER_AFC) - 2;
+}
+
+
+static int simple_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	int tuner_status;
+
+	if (priv->i2c_props.adap == NULL)
+		return -EINVAL;
+
+	tuner_status = tuner_read_status(fe);
+
+	*status = 0;
+
+	if (tuner_islocked(tuner_status))
+		*status = TUNER_STATUS_LOCKED;
+	if (tuner_stereo(priv->type, tuner_status))
+		*status |= TUNER_STATUS_STEREO;
+
+	tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status));
+
+	return 0;
+}
+
+static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	int signal;
+
+	if (priv->i2c_props.adap == NULL)
+		return -EINVAL;
+
+	signal = tuner_signal(tuner_read_status(fe));
+
+	*strength = signal;
+
+	tuner_dbg("Signal strength: %d\n", signal);
+
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static inline char *tuner_param_name(enum param_type type)
+{
+	char *name;
+
+	switch (type) {
+	case TUNER_PARAM_TYPE_RADIO:
+		name = "radio";
+		break;
+	case TUNER_PARAM_TYPE_PAL:
+		name = "pal";
+		break;
+	case TUNER_PARAM_TYPE_SECAM:
+		name = "secam";
+		break;
+	case TUNER_PARAM_TYPE_NTSC:
+		name = "ntsc";
+		break;
+	case TUNER_PARAM_TYPE_DIGITAL:
+		name = "digital";
+		break;
+	default:
+		name = "unknown";
+		break;
+	}
+	return name;
+}
+
+static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe,
+						enum param_type desired_type)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	struct tunertype *tun = priv->tun;
+	int i;
+
+	for (i = 0; i < tun->count; i++)
+		if (desired_type == tun->params[i].type)
+			break;
+
+	/* use default tuner params if desired_type not available */
+	if (i == tun->count) {
+		tuner_dbg("desired params (%s) undefined for tuner %d\n",
+			  tuner_param_name(desired_type), priv->type);
+		i = 0;
+	}
+
+	tuner_dbg("using tuner params #%d (%s)\n", i,
+		  tuner_param_name(tun->params[i].type));
+
+	return &tun->params[i];
+}
+
+static int simple_config_lookup(struct dvb_frontend *fe,
+				struct tuner_params *t_params,
+				unsigned *frequency, u8 *config, u8 *cb)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	int i;
+
+	for (i = 0; i < t_params->count; i++) {
+		if (*frequency > t_params->ranges[i].limit)
+			continue;
+		break;
+	}
+	if (i == t_params->count) {
+		tuner_dbg("frequency out of range (%d > %d)\n",
+			  *frequency, t_params->ranges[i - 1].limit);
+		*frequency = t_params->ranges[--i].limit;
+	}
+	*config = t_params->ranges[i].config;
+	*cb     = t_params->ranges[i].cb;
+
+	tuner_dbg("freq = %d.%02d (%d), range = %d, "
+		  "config = 0x%02x, cb = 0x%02x\n",
+		  *frequency / 16, *frequency % 16 * 100 / 16, *frequency,
+		  i, *config, *cb);
+
+	return i;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void simple_set_rf_input(struct dvb_frontend *fe,
+				u8 *config, u8 *cb, unsigned int rf)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+
+	switch (priv->type) {
+	case TUNER_PHILIPS_TUV1236D:
+		switch (rf) {
+		case 1:
+			*cb |= 0x08;
+			break;
+		default:
+			*cb &= ~0x08;
+			break;
+		}
+		break;
+	case TUNER_PHILIPS_FCV1236D:
+		switch (rf) {
+		case 1:
+			*cb |= 0x01;
+			break;
+		default:
+			*cb &= ~0x01;
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static int simple_std_setup(struct dvb_frontend *fe,
+			    struct analog_parameters *params,
+			    u8 *config, u8 *cb)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	int rc;
+
+	/* tv norm specific stuff for multi-norm tuners */
+	switch (priv->type) {
+	case TUNER_PHILIPS_SECAM: /* FI1216MF */
+		/* 0x01 -> ??? no change ??? */
+		/* 0x02 -> PAL BDGHI / SECAM L */
+		/* 0x04 -> ??? PAL others / SECAM others ??? */
+		*cb &= ~0x03;
+		if (params->std & V4L2_STD_SECAM_L)
+			/* also valid for V4L2_STD_SECAM */
+			*cb |= PHILIPS_MF_SET_STD_L;
+		else if (params->std & V4L2_STD_SECAM_LC)
+			*cb |= PHILIPS_MF_SET_STD_LC;
+		else /* V4L2_STD_B|V4L2_STD_GH */
+			*cb |= PHILIPS_MF_SET_STD_BG;
+		break;
+
+	case TUNER_TEMIC_4046FM5:
+		*cb &= ~0x0f;
+
+		if (params->std & V4L2_STD_PAL_BG) {
+			*cb |= TEMIC_SET_PAL_BG;
+
+		} else if (params->std & V4L2_STD_PAL_I) {
+			*cb |= TEMIC_SET_PAL_I;
+
+		} else if (params->std & V4L2_STD_PAL_DK) {
+			*cb |= TEMIC_SET_PAL_DK;
+
+		} else if (params->std & V4L2_STD_SECAM_L) {
+			*cb |= TEMIC_SET_PAL_L;
+
+		}
+		break;
+
+	case TUNER_PHILIPS_FQ1216ME:
+		*cb &= ~0x0f;
+
+		if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
+			*cb |= PHILIPS_SET_PAL_BGDK;
+
+		} else if (params->std & V4L2_STD_PAL_I) {
+			*cb |= PHILIPS_SET_PAL_I;
+
+		} else if (params->std & V4L2_STD_SECAM_L) {
+			*cb |= PHILIPS_SET_PAL_L;
+
+		}
+		break;
+
+	case TUNER_PHILIPS_FCV1236D:
+		/* 0x00 -> ATSC antenna input 1 */
+		/* 0x01 -> ATSC antenna input 2 */
+		/* 0x02 -> NTSC antenna input 1 */
+		/* 0x03 -> NTSC antenna input 2 */
+		*cb &= ~0x03;
+		if (!(params->std & V4L2_STD_ATSC))
+			*cb |= 2;
+		break;
+
+	case TUNER_MICROTUNE_4042FI5:
+		/* Set the charge pump for fast tuning */
+		*config |= TUNER_CHARGE_PUMP;
+		break;
+
+	case TUNER_PHILIPS_TUV1236D:
+	{
+		struct tuner_i2c_props i2c = priv->i2c_props;
+		/* 0x40 -> ATSC antenna input 1 */
+		/* 0x48 -> ATSC antenna input 2 */
+		/* 0x00 -> NTSC antenna input 1 */
+		/* 0x08 -> NTSC antenna input 2 */
+		u8 buffer[4] = { 0x14, 0x00, 0x17, 0x00};
+		*cb &= ~0x40;
+		if (params->std & V4L2_STD_ATSC) {
+			*cb |= 0x40;
+			buffer[1] = 0x04;
+		}
+		/* set to the correct mode (analog or digital) */
+		i2c.addr = 0x0a;
+		rc = tuner_i2c_xfer_send(&i2c, &buffer[0], 2);
+		if (2 != rc)
+			tuner_warn("i2c i/o error: rc == %d "
+				   "(should be 2)\n", rc);
+		rc = tuner_i2c_xfer_send(&i2c, &buffer[2], 2);
+		if (2 != rc)
+			tuner_warn("i2c i/o error: rc == %d "
+				   "(should be 2)\n", rc);
+		break;
+	}
+	}
+	if (atv_input[priv->nr])
+		simple_set_rf_input(fe, config, cb, atv_input[priv->nr]);
+
+	return 0;
+}
+
+static int simple_set_aux_byte(struct dvb_frontend *fe, u8 config, u8 aux)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	int rc;
+	u8 buffer[2];
+
+	buffer[0] = (config & ~0x38) | 0x18;
+	buffer[1] = aux;
+
+	tuner_dbg("setting aux byte: 0x%02x 0x%02x\n", buffer[0], buffer[1]);
+
+	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
+	if (2 != rc)
+		tuner_warn("i2c i/o error: rc == %d (should be 2)\n", rc);
+
+	return rc == 2 ? 0 : rc;
+}
+
+static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
+			    u16 div, u8 config, u8 cb)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	int rc;
+
+	switch (priv->type) {
+	case TUNER_LG_TDVS_H06XF:
+		simple_set_aux_byte(fe, config, 0x20);
+		break;
+	case TUNER_PHILIPS_FQ1216LME_MK3:
+		simple_set_aux_byte(fe, config, 0x60); /* External AGC */
+		break;
+	case TUNER_MICROTUNE_4042FI5:
+	{
+		/* FIXME - this may also work for other tuners */
+		unsigned long timeout = jiffies + msecs_to_jiffies(1);
+		u8 status_byte = 0;
+
+		/* Wait until the PLL locks */
+		for (;;) {
+			if (time_after(jiffies, timeout))
+				return 0;
+			rc = tuner_i2c_xfer_recv(&priv->i2c_props,
+						 &status_byte, 1);
+			if (1 != rc) {
+				tuner_warn("i2c i/o read error: rc == %d "
+					   "(should be 1)\n", rc);
+				break;
+			}
+			if (status_byte & TUNER_PLL_LOCKED)
+				break;
+			udelay(10);
+		}
+
+		/* Set the charge pump for optimized phase noise figure */
+		config &= ~TUNER_CHARGE_PUMP;
+		buffer[0] = (div>>8) & 0x7f;
+		buffer[1] = div      & 0xff;
+		buffer[2] = config;
+		buffer[3] = cb;
+		tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
+			  buffer[0], buffer[1], buffer[2], buffer[3]);
+
+		rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
+		if (4 != rc)
+			tuner_warn("i2c i/o error: rc == %d "
+				   "(should be 4)\n", rc);
+		break;
+	}
+	}
+
+	return 0;
+}
+
+static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+
+	switch (priv->type) {
+	case TUNER_TENA_9533_DI:
+	case TUNER_YMEC_TVF_5533MF:
+		tuner_dbg("This tuner doesn't have FM. "
+			  "Most cards have a TEA5767 for FM\n");
+		return 0;
+	case TUNER_PHILIPS_FM1216ME_MK3:
+	case TUNER_PHILIPS_FM1236_MK3:
+	case TUNER_PHILIPS_FMD1216ME_MK3:
+	case TUNER_PHILIPS_FMD1216MEX_MK3:
+	case TUNER_LG_NTSC_TAPE:
+	case TUNER_PHILIPS_FM1256_IH3:
+	case TUNER_TCL_MF02GIP_5N:
+		buffer[3] = 0x19;
+		break;
+	case TUNER_PHILIPS_FM1216MK5:
+		buffer[2] = 0x88;
+		buffer[3] = 0x09;
+		break;
+	case TUNER_TNF_5335MF:
+		buffer[3] = 0x11;
+		break;
+	case TUNER_LG_PAL_FM:
+		buffer[3] = 0xa5;
+		break;
+	case TUNER_THOMSON_DTT761X:
+		buffer[3] = 0x39;
+		break;
+	case TUNER_PHILIPS_FQ1216LME_MK3:
+	case TUNER_PHILIPS_FQ1236_MK5:
+		tuner_err("This tuner doesn't have FM\n");
+		/* Set the low band for sanity, since it covers 88-108 MHz */
+		buffer[3] = 0x01;
+		break;
+	case TUNER_MICROTUNE_4049FM5:
+	default:
+		buffer[3] = 0xa4;
+		break;
+	}
+
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int simple_set_tv_freq(struct dvb_frontend *fe,
+			      struct analog_parameters *params)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	u8 config, cb;
+	u16 div;
+	u8 buffer[4];
+	int rc, IFPCoff, i;
+	enum param_type desired_type;
+	struct tuner_params *t_params;
+
+	/* IFPCoff = Video Intermediate Frequency - Vif:
+		940  =16*58.75  NTSC/J (Japan)
+		732  =16*45.75  M/N STD
+		704  =16*44     ATSC (at DVB code)
+		632  =16*39.50  I U.K.
+		622.4=16*38.90  B/G D/K I, L STD
+		592  =16*37.00  D China
+		590  =16.36.875 B Australia
+		543.2=16*33.95  L' STD
+		171.2=16*10.70  FM Radio (at set_radio_freq)
+	*/
+
+	if (params->std == V4L2_STD_NTSC_M_JP) {
+		IFPCoff      = 940;
+		desired_type = TUNER_PARAM_TYPE_NTSC;
+	} else if ((params->std & V4L2_STD_MN) &&
+		  !(params->std & ~V4L2_STD_MN)) {
+		IFPCoff      = 732;
+		desired_type = TUNER_PARAM_TYPE_NTSC;
+	} else if (params->std == V4L2_STD_SECAM_LC) {
+		IFPCoff      = 543;
+		desired_type = TUNER_PARAM_TYPE_SECAM;
+	} else {
+		IFPCoff      = 623;
+		desired_type = TUNER_PARAM_TYPE_PAL;
+	}
+
+	t_params = simple_tuner_params(fe, desired_type);
+
+	i = simple_config_lookup(fe, t_params, &params->frequency,
+				 &config, &cb);
+
+	div = params->frequency + IFPCoff + offset;
+
+	tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, "
+		  "Offset=%d.%02d MHz, div=%0d\n",
+		  params->frequency / 16, params->frequency % 16 * 100 / 16,
+		  IFPCoff / 16, IFPCoff % 16 * 100 / 16,
+		  offset / 16, offset % 16 * 100 / 16, div);
+
+	/* tv norm specific stuff for multi-norm tuners */
+	simple_std_setup(fe, params, &config, &cb);
+
+	if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
+		buffer[0] = config;
+		buffer[1] = cb;
+		buffer[2] = (div>>8) & 0x7f;
+		buffer[3] = div      & 0xff;
+	} else {
+		buffer[0] = (div>>8) & 0x7f;
+		buffer[1] = div      & 0xff;
+		buffer[2] = config;
+		buffer[3] = cb;
+	}
+	priv->last_div = div;
+	if (t_params->has_tda9887) {
+		struct v4l2_priv_tun_config tda9887_cfg;
+		int tda_config = 0;
+		int is_secam_l = (params->std & (V4L2_STD_SECAM_L |
+						 V4L2_STD_SECAM_LC)) &&
+			!(params->std & ~(V4L2_STD_SECAM_L |
+					  V4L2_STD_SECAM_LC));
+
+		tda9887_cfg.tuner = TUNER_TDA9887;
+		tda9887_cfg.priv  = &tda_config;
+
+		if (params->std == V4L2_STD_SECAM_LC) {
+			if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
+				tda_config |= TDA9887_PORT1_ACTIVE;
+			if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)
+				tda_config |= TDA9887_PORT2_ACTIVE;
+		} else {
+			if (t_params->port1_active)
+				tda_config |= TDA9887_PORT1_ACTIVE;
+			if (t_params->port2_active)
+				tda_config |= TDA9887_PORT2_ACTIVE;
+		}
+		if (t_params->intercarrier_mode)
+			tda_config |= TDA9887_INTERCARRIER;
+		if (is_secam_l) {
+			if (i == 0 && t_params->default_top_secam_low)
+				tda_config |= TDA9887_TOP(t_params->default_top_secam_low);
+			else if (i == 1 && t_params->default_top_secam_mid)
+				tda_config |= TDA9887_TOP(t_params->default_top_secam_mid);
+			else if (t_params->default_top_secam_high)
+				tda_config |= TDA9887_TOP(t_params->default_top_secam_high);
+		} else {
+			if (i == 0 && t_params->default_top_low)
+				tda_config |= TDA9887_TOP(t_params->default_top_low);
+			else if (i == 1 && t_params->default_top_mid)
+				tda_config |= TDA9887_TOP(t_params->default_top_mid);
+			else if (t_params->default_top_high)
+				tda_config |= TDA9887_TOP(t_params->default_top_high);
+		}
+		if (t_params->default_pll_gating_18)
+			tda_config |= TDA9887_GATING_18;
+		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
+				    &tda9887_cfg);
+	}
+	tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
+		  buffer[0], buffer[1], buffer[2], buffer[3]);
+
+	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
+	if (4 != rc)
+		tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
+
+	simple_post_tune(fe, &buffer[0], div, config, cb);
+
+	return 0;
+}
+
+static int simple_set_radio_freq(struct dvb_frontend *fe,
+				 struct analog_parameters *params)
+{
+	struct tunertype *tun;
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	u8 buffer[4];
+	u16 div;
+	int rc, j;
+	struct tuner_params *t_params;
+	unsigned int freq = params->frequency;
+
+	tun = priv->tun;
+
+	for (j = tun->count-1; j > 0; j--)
+		if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO)
+			break;
+	/* default t_params (j=0) will be used if desired type wasn't found */
+	t_params = &tun->params[j];
+
+	/* Select Radio 1st IF used */
+	switch (t_params->radio_if) {
+	case 0: /* 10.7 MHz */
+		freq += (unsigned int)(10.7*16000);
+		break;
+	case 1: /* 33.3 MHz */
+		freq += (unsigned int)(33.3*16000);
+		break;
+	case 2: /* 41.3 MHz */
+		freq += (unsigned int)(41.3*16000);
+		break;
+	default:
+		tuner_warn("Unsupported radio_if value %d\n",
+			   t_params->radio_if);
+		return 0;
+	}
+
+	buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
+		    TUNER_RATIO_SELECT_50; /* 50 kHz step */
+
+	/* Bandswitch byte */
+	simple_radio_bandswitch(fe, &buffer[0]);
+
+	/* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
+	   freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
+	   freq * (1/800) */
+	div = (freq + 400) / 800;
+
+	if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
+		buffer[0] = buffer[2];
+		buffer[1] = buffer[3];
+		buffer[2] = (div>>8) & 0x7f;
+		buffer[3] = div      & 0xff;
+	} else {
+		buffer[0] = (div>>8) & 0x7f;
+		buffer[1] = div      & 0xff;
+	}
+
+	tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
+	       buffer[0], buffer[1], buffer[2], buffer[3]);
+	priv->last_div = div;
+
+	if (t_params->has_tda9887) {
+		int config = 0;
+		struct v4l2_priv_tun_config tda9887_cfg;
+
+		tda9887_cfg.tuner = TUNER_TDA9887;
+		tda9887_cfg.priv = &config;
+
+		if (t_params->port1_active &&
+		    !t_params->port1_fm_high_sensitivity)
+			config |= TDA9887_PORT1_ACTIVE;
+		if (t_params->port2_active &&
+		    !t_params->port2_fm_high_sensitivity)
+			config |= TDA9887_PORT2_ACTIVE;
+		if (t_params->intercarrier_mode)
+			config |= TDA9887_INTERCARRIER;
+/*		if (t_params->port1_set_for_fm_mono)
+			config &= ~TDA9887_PORT1_ACTIVE;*/
+		if (t_params->fm_gain_normal)
+			config |= TDA9887_GAIN_NORMAL;
+		if (t_params->radio_if == 2)
+			config |= TDA9887_RIF_41_3;
+		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
+				    &tda9887_cfg);
+	}
+	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
+	if (4 != rc)
+		tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
+
+	/* Write AUX byte */
+	switch (priv->type) {
+	case TUNER_PHILIPS_FM1216ME_MK3:
+		buffer[2] = 0x98;
+		buffer[3] = 0x20; /* set TOP AGC */
+		rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
+		if (4 != rc)
+			tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
+		break;
+	}
+
+	return 0;
+}
+
+static int simple_set_params(struct dvb_frontend *fe,
+			     struct analog_parameters *params)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	int ret = -EINVAL;
+
+	if (priv->i2c_props.adap == NULL)
+		return -EINVAL;
+
+	switch (params->mode) {
+	case V4L2_TUNER_RADIO:
+		ret = simple_set_radio_freq(fe, params);
+		priv->frequency = params->frequency * 125 / 2;
+		break;
+	case V4L2_TUNER_ANALOG_TV:
+	case V4L2_TUNER_DIGITAL_TV:
+		ret = simple_set_tv_freq(fe, params);
+		priv->frequency = params->frequency * 62500;
+		break;
+	}
+	priv->bandwidth = 0;
+
+	return ret;
+}
+
+static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
+			   const u32 delsys,
+			   const u32 frequency,
+			   const u32 bandwidth)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+
+	switch (priv->type) {
+	case TUNER_PHILIPS_FMD1216ME_MK3:
+	case TUNER_PHILIPS_FMD1216MEX_MK3:
+		if (bandwidth == 8000000 &&
+		    frequency >= 158870000)
+			buf[3] |= 0x08;
+		break;
+	case TUNER_PHILIPS_TD1316:
+		/* determine band */
+		buf[3] |= (frequency < 161000000) ? 1 :
+			  (frequency < 444000000) ? 2 : 4;
+
+		/* setup PLL filter */
+		if (bandwidth == 8000000)
+			buf[3] |= 1 << 3;
+		break;
+	case TUNER_PHILIPS_TUV1236D:
+	case TUNER_PHILIPS_FCV1236D:
+	{
+		unsigned int new_rf;
+
+		if (dtv_input[priv->nr])
+			new_rf = dtv_input[priv->nr];
+		else
+			switch (delsys) {
+			case SYS_DVBC_ANNEX_B:
+				new_rf = 1;
+				break;
+			case SYS_ATSC:
+			default:
+				new_rf = 0;
+				break;
+			}
+		simple_set_rf_input(fe, &buf[2], &buf[3], new_rf);
+		break;
+	}
+	default:
+		break;
+	}
+}
+
+static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
+				const u32 delsys,
+				const u32 freq,
+				const u32 bw)
+{
+	/* This function returns the tuned frequency on success, 0 on error */
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	struct tunertype *tun = priv->tun;
+	static struct tuner_params *t_params;
+	u8 config, cb;
+	u32 div;
+	int ret;
+	u32 frequency = freq / 62500;
+
+	if (!tun->stepsize) {
+		/* tuner-core was loaded before the digital tuner was
+		 * configured and somehow picked the wrong tuner type */
+		tuner_err("attempt to treat tuner %d (%s) as digital tuner "
+			  "without stepsize defined.\n",
+			  priv->type, priv->tun->name);
+		return 0; /* failure */
+	}
+
+	t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL);
+	ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb);
+	if (ret < 0)
+		return 0; /* failure */
+
+	div = ((frequency + t_params->iffreq) * 62500 + offset +
+	       tun->stepsize/2) / tun->stepsize;
+
+	buf[0] = div >> 8;
+	buf[1] = div & 0xff;
+	buf[2] = config;
+	buf[3] = cb;
+
+	simple_set_dvb(fe, buf, delsys, freq, bw);
+
+	tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
+		  tun->name, div, buf[0], buf[1], buf[2], buf[3]);
+
+	/* calculate the frequency we set it to */
+	return (div * tun->stepsize) - t_params->iffreq;
+}
+
+static int simple_dvb_calc_regs(struct dvb_frontend *fe,
+				u8 *buf, int buf_len)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 delsys = c->delivery_system;
+	u32 bw = c->bandwidth_hz;
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	u32 frequency;
+
+	if (buf_len < 5)
+		return -EINVAL;
+
+	frequency = simple_dvb_configure(fe, buf+1, delsys, c->frequency, bw);
+	if (frequency == 0)
+		return -EINVAL;
+
+	buf[0] = priv->i2c_props.addr;
+
+	priv->frequency = frequency;
+	priv->bandwidth = c->bandwidth_hz;
+
+	return 5;
+}
+
+static int simple_dvb_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 delsys = c->delivery_system;
+	u32 bw = c->bandwidth_hz;
+	u32 freq = c->frequency;
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	u32 frequency;
+	u32 prev_freq, prev_bw;
+	int ret;
+	u8 buf[5];
+
+	if (priv->i2c_props.adap == NULL)
+		return -EINVAL;
+
+	prev_freq = priv->frequency;
+	prev_bw   = priv->bandwidth;
+
+	frequency = simple_dvb_configure(fe, buf+1, delsys, freq, bw);
+	if (frequency == 0)
+		return -EINVAL;
+
+	buf[0] = priv->i2c_props.addr;
+
+	priv->frequency = frequency;
+	priv->bandwidth = bw;
+
+	/* put analog demod in standby when tuning digital */
+	if (fe->ops.analog_ops.standby)
+		fe->ops.analog_ops.standby(fe);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	/* buf[0] contains the i2c address, but *
+	 * we already have it in i2c_props.addr */
+	ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4);
+	if (ret != 4)
+		goto fail;
+
+	return 0;
+fail:
+	/* calc_regs sets frequency and bandwidth. if we failed, unset them */
+	priv->frequency = prev_freq;
+	priv->bandwidth = prev_bw;
+
+	return ret;
+}
+
+static int simple_init(struct dvb_frontend *fe)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+
+	if (priv->i2c_props.adap == NULL)
+		return -EINVAL;
+
+	if (priv->tun->initdata) {
+		int ret;
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		ret = tuner_i2c_xfer_send(&priv->i2c_props,
+					  priv->tun->initdata + 1,
+					  priv->tun->initdata[0]);
+		if (ret != priv->tun->initdata[0])
+			return ret;
+	}
+
+	return 0;
+}
+
+static int simple_sleep(struct dvb_frontend *fe)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+
+	if (priv->i2c_props.adap == NULL)
+		return -EINVAL;
+
+	if (priv->tun->sleepdata) {
+		int ret;
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		ret = tuner_i2c_xfer_send(&priv->i2c_props,
+					  priv->tun->sleepdata + 1,
+					  priv->tun->sleepdata[0]);
+		if (ret != priv->tun->sleepdata[0])
+			return ret;
+	}
+
+	return 0;
+}
+
+static int simple_release(struct dvb_frontend *fe)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+
+	mutex_lock(&tuner_simple_list_mutex);
+
+	if (priv)
+		hybrid_tuner_release_state(priv);
+
+	mutex_unlock(&tuner_simple_list_mutex);
+
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+static struct dvb_tuner_ops simple_tuner_ops = {
+	.init              = simple_init,
+	.sleep             = simple_sleep,
+	.set_analog_params = simple_set_params,
+	.set_params        = simple_dvb_set_params,
+	.calc_regs         = simple_dvb_calc_regs,
+	.release           = simple_release,
+	.get_frequency     = simple_get_frequency,
+	.get_bandwidth     = simple_get_bandwidth,
+	.get_status        = simple_get_status,
+	.get_rf_strength   = simple_get_rf_strength,
+};
+
+struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
+					 struct i2c_adapter *i2c_adap,
+					 u8 i2c_addr,
+					 unsigned int type)
+{
+	struct tuner_simple_priv *priv = NULL;
+	int instance;
+
+	if (type >= tuner_count) {
+		printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n",
+		       __func__, type, tuner_count-1);
+		return NULL;
+	}
+
+	/* If i2c_adap is set, check that the tuner is at the correct address.
+	 * Otherwise, if i2c_adap is NULL, the tuner will be programmed directly
+	 * by the digital demod via calc_regs.
+	 */
+	if (i2c_adap != NULL) {
+		u8 b[1];
+		struct i2c_msg msg = {
+			.addr = i2c_addr, .flags = I2C_M_RD,
+			.buf = b, .len = 1,
+		};
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		if (1 != i2c_transfer(i2c_adap, &msg, 1))
+			printk(KERN_WARNING "tuner-simple %d-%04x: "
+			       "unable to probe %s, proceeding anyway.",
+			       i2c_adapter_id(i2c_adap), i2c_addr,
+			       tuners[type].name);
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	mutex_lock(&tuner_simple_list_mutex);
+
+	instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv,
+					      hybrid_tuner_instance_list,
+					      i2c_adap, i2c_addr,
+					      "tuner-simple");
+	switch (instance) {
+	case 0:
+		mutex_unlock(&tuner_simple_list_mutex);
+		return NULL;
+	case 1:
+		fe->tuner_priv = priv;
+
+		priv->type = type;
+		priv->tun  = &tuners[type];
+		priv->nr   = simple_devcount++;
+		break;
+	default:
+		fe->tuner_priv = priv;
+		break;
+	}
+
+	mutex_unlock(&tuner_simple_list_mutex);
+
+	memcpy(&fe->ops.tuner_ops, &simple_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+	if (type != priv->type)
+		tuner_warn("couldn't set type to %d. Using %d (%s) instead\n",
+			    type, priv->type, priv->tun->name);
+	else
+		tuner_info("type set to %d (%s)\n",
+			   priv->type, priv->tun->name);
+
+	if ((debug) || ((atv_input[priv->nr] > 0) ||
+			(dtv_input[priv->nr] > 0))) {
+		if (0 == atv_input[priv->nr])
+			tuner_info("tuner %d atv rf input will be "
+				   "autoselected\n", priv->nr);
+		else
+			tuner_info("tuner %d atv rf input will be "
+				   "set to input %d (insmod option)\n",
+				   priv->nr, atv_input[priv->nr]);
+		if (0 == dtv_input[priv->nr])
+			tuner_info("tuner %d dtv rf input will be "
+				   "autoselected\n", priv->nr);
+		else
+			tuner_info("tuner %d dtv rf input will be "
+				   "set to input %d (insmod option)\n",
+				   priv->nr, dtv_input[priv->nr]);
+	}
+
+	strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name,
+		sizeof(fe->ops.tuner_ops.info.name));
+
+	return fe;
+}
+EXPORT_SYMBOL_GPL(simple_tuner_attach);
+
+MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver");
+MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
+MODULE_LICENSE("GPL");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/tuners/tuner-simple.h b/drivers/media/tuners/tuner-simple.h
new file mode 100644
index 0000000..381fa5d
--- /dev/null
+++ b/drivers/media/tuners/tuner-simple.h
@@ -0,0 +1,39 @@
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TUNER_SIMPLE_H__
+#define __TUNER_SIMPLE_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_MEDIA_TUNER_SIMPLE) || (defined(CONFIG_MEDIA_TUNER_SIMPLE_MODULE) && defined(MODULE))
+extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
+						struct i2c_adapter *i2c_adap,
+						u8 i2c_addr,
+						unsigned int type);
+#else
+static inline struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
+						       struct i2c_adapter *i2c_adap,
+						       u8 i2c_addr,
+						       unsigned int type)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* __TUNER_SIMPLE_H__ */
diff --git a/drivers/media/tuners/tuner-types.c b/drivers/media/tuners/tuner-types.c
new file mode 100644
index 0000000..2da4440
--- /dev/null
+++ b/drivers/media/tuners/tuner-types.c
@@ -0,0 +1,1883 @@
+/*
+ *
+ * i2c tv tuner chip device type database.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <media/tuner.h>
+#include <media/tuner-types.h>
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ *	The floats in the tuner struct are computed at compile time
+ *	by gcc and cast back to integers. Thus we don't violate the
+ *	"no float in kernel" rule.
+ *
+ *	A tuner_range may be referenced by multiple tuner_params structs.
+ *	There are many duplicates in here. Reusing tuner_range structs,
+ *	rather than defining new ones for each tuner, will cut down on
+ *	memory usage, and is preferred when possible.
+ *
+ *	Each tuner_params array may contain one or more elements, one
+ *	for each video standard.
+ *
+ *	FIXME: tuner_params struct contains an element, tda988x. We must
+ *	set this for all tuners that contain a tda988x chip, and then we
+ *	can remove this setting from the various card structs.
+ *
+ *	FIXME: Right now, all tuners are using the first tuner_params[]
+ *	array element for analog mode. In the future, we will be merging
+ *	similar tuner definitions together, such that each tuner definition
+ *	will have a tuner_params struct for each available video standard.
+ *	At that point, the tuner_params[] array element will be chosen
+ *	based on the video standard in use.
+ */
+
+/* The following was taken from dvb-pll.c: */
+
+/* Set AGC TOP value to 103 dBuV:
+ *	0x80 = Control Byte
+ *	0x40 = 250 uA charge pump (irrelevant)
+ *	0x18 = Aux Byte to follow
+ *	0x06 = 64.5 kHz divider (irrelevant)
+ *	0x01 = Disable Vt (aka sleep)
+ *
+ *	0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA)
+ *	0x50 = AGC Take over point = 103 dBuV
+ */
+static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 };
+
+/*	0x04 = 166.67 kHz divider
+ *
+ *	0x80 = AGC Time constant 50ms Iagc = 9 uA
+ *	0x20 = AGC Take over point = 112 dBuV
+ */
+static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 };
+
+/* 0-9 */
+/* ------------ TUNER_TEMIC_PAL - TEMIC PAL ------------ */
+
+static struct tuner_range tuner_temic_pal_ranges[] = {
+	{ 16 * 140.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 463.25 /*MHz*/, 0x8e, 0x04, },
+	{ 16 * 999.99        , 0x8e, 0x01, },
+};
+
+static struct tuner_params tuner_temic_pal_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_temic_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_PHILIPS_PAL_I - Philips PAL_I ------------ */
+
+static struct tuner_range tuner_philips_pal_i_ranges[] = {
+	{ 16 * 140.25 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
+};
+
+static struct tuner_params tuner_philips_pal_i_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_philips_pal_i_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_pal_i_ranges),
+	},
+};
+
+/* ------------ TUNER_PHILIPS_NTSC - Philips NTSC ------------ */
+
+static struct tuner_range tuner_philips_ntsc_ranges[] = {
+	{ 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 451.25 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
+};
+
+static struct tuner_params tuner_philips_ntsc_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_philips_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_ntsc_ranges),
+		.cb_first_if_lower_freq = 1,
+	},
+};
+
+/* ------------ TUNER_PHILIPS_SECAM - Philips SECAM ------------ */
+
+static struct tuner_range tuner_philips_secam_ranges[] = {
+	{ 16 * 168.25 /*MHz*/, 0x8e, 0xa7, },
+	{ 16 * 447.25 /*MHz*/, 0x8e, 0x97, },
+	{ 16 * 999.99        , 0x8e, 0x37, },
+};
+
+static struct tuner_params tuner_philips_secam_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_SECAM,
+		.ranges = tuner_philips_secam_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_secam_ranges),
+		.cb_first_if_lower_freq = 1,
+	},
+};
+
+/* ------------ TUNER_PHILIPS_PAL - Philips PAL ------------ */
+
+static struct tuner_range tuner_philips_pal_ranges[] = {
+	{ 16 * 168.25 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 447.25 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
+};
+
+static struct tuner_params tuner_philips_pal_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_philips_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_pal_ranges),
+		.cb_first_if_lower_freq = 1,
+	},
+};
+
+/* ------------ TUNER_TEMIC_NTSC - TEMIC NTSC ------------ */
+
+static struct tuner_range tuner_temic_ntsc_ranges[] = {
+	{ 16 * 157.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 463.25 /*MHz*/, 0x8e, 0x04, },
+	{ 16 * 999.99        , 0x8e, 0x01, },
+};
+
+static struct tuner_params tuner_temic_ntsc_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_temic_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_ntsc_ranges),
+	},
+};
+
+/* ------------ TUNER_TEMIC_PAL_I - TEMIC PAL_I ------------ */
+
+static struct tuner_range tuner_temic_pal_i_ranges[] = {
+	{ 16 * 170.00 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 450.00 /*MHz*/, 0x8e, 0x04, },
+	{ 16 * 999.99        , 0x8e, 0x01, },
+};
+
+static struct tuner_params tuner_temic_pal_i_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_temic_pal_i_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_pal_i_ranges),
+	},
+};
+
+/* ------------ TUNER_TEMIC_4036FY5_NTSC - TEMIC NTSC ------------ */
+
+static struct tuner_range tuner_temic_4036fy5_ntsc_ranges[] = {
+	{ 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
+};
+
+static struct tuner_params tuner_temic_4036fy5_ntsc_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_temic_4036fy5_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_ranges),
+	},
+};
+
+/* ------------ TUNER_ALPS_TSBH1_NTSC - TEMIC NTSC ------------ */
+
+static struct tuner_range tuner_alps_tsb_1_ranges[] = {
+	{ 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 385.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
+};
+
+static struct tuner_params tuner_alps_tsbh1_ntsc_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_alps_tsb_1_ranges,
+		.count  = ARRAY_SIZE(tuner_alps_tsb_1_ranges),
+	},
+};
+
+/* 10-19 */
+/* ------------ TUNER_ALPS_TSBE1_PAL - TEMIC PAL ------------ */
+
+static struct tuner_params tuner_alps_tsb_1_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_alps_tsb_1_ranges,
+		.count  = ARRAY_SIZE(tuner_alps_tsb_1_ranges),
+	},
+};
+
+/* ------------ TUNER_ALPS_TSBB5_PAL_I - Alps PAL_I ------------ */
+
+static struct tuner_range tuner_alps_tsb_5_pal_ranges[] = {
+	{ 16 * 133.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 351.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
+};
+
+static struct tuner_params tuner_alps_tsbb5_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_alps_tsb_5_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_ALPS_TSBE5_PAL - Alps PAL ------------ */
+
+static struct tuner_params tuner_alps_tsbe5_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_alps_tsb_5_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_ALPS_TSBC5_PAL - Alps PAL ------------ */
+
+static struct tuner_params tuner_alps_tsbc5_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_alps_tsb_5_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_TEMIC_4006FH5_PAL - TEMIC PAL ------------ */
+
+static struct tuner_range tuner_lg_pal_ranges[] = {
+	{ 16 * 170.00 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 450.00 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
+};
+
+static struct tuner_params tuner_temic_4006fh5_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_lg_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_ALPS_TSHC6_NTSC - Alps NTSC ------------ */
+
+static struct tuner_range tuner_alps_tshc6_ntsc_ranges[] = {
+	{ 16 * 137.25 /*MHz*/, 0x8e, 0x14, },
+	{ 16 * 385.25 /*MHz*/, 0x8e, 0x12, },
+	{ 16 * 999.99        , 0x8e, 0x11, },
+};
+
+static struct tuner_params tuner_alps_tshc6_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_alps_tshc6_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_alps_tshc6_ntsc_ranges),
+	},
+};
+
+/* ------------ TUNER_TEMIC_PAL_DK - TEMIC PAL ------------ */
+
+static struct tuner_range tuner_temic_pal_dk_ranges[] = {
+	{ 16 * 168.25 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 456.25 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
+};
+
+static struct tuner_params tuner_temic_pal_dk_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_temic_pal_dk_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_pal_dk_ranges),
+	},
+};
+
+/* ------------ TUNER_PHILIPS_NTSC_M - Philips NTSC ------------ */
+
+static struct tuner_range tuner_philips_ntsc_m_ranges[] = {
+	{ 16 * 160.00 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
+};
+
+static struct tuner_params tuner_philips_ntsc_m_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_philips_ntsc_m_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_ntsc_m_ranges),
+	},
+};
+
+/* ------------ TUNER_TEMIC_4066FY5_PAL_I - TEMIC PAL_I ------------ */
+
+static struct tuner_range tuner_temic_40x6f_5_pal_ranges[] = {
+	{ 16 * 169.00 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
+};
+
+static struct tuner_params tuner_temic_4066fy5_pal_i_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_temic_40x6f_5_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_TEMIC_4006FN5_MULTI_PAL - TEMIC PAL ------------ */
+
+static struct tuner_params tuner_temic_4006fn5_multi_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_temic_40x6f_5_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
+	},
+};
+
+/* 20-29 */
+/* ------------ TUNER_TEMIC_4009FR5_PAL - TEMIC PAL ------------ */
+
+static struct tuner_range tuner_temic_4009f_5_pal_ranges[] = {
+	{ 16 * 141.00 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 464.00 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
+};
+
+static struct tuner_params tuner_temic_4009f_5_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_temic_4009f_5_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_TEMIC_4039FR5_NTSC - TEMIC NTSC ------------ */
+
+static struct tuner_range tuner_temic_4x3x_f_5_ntsc_ranges[] = {
+	{ 16 * 158.00 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 453.00 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
+};
+
+static struct tuner_params tuner_temic_4039fr5_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_temic_4x3x_f_5_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges),
+	},
+};
+
+/* ------------ TUNER_TEMIC_4046FM5 - TEMIC PAL ------------ */
+
+static struct tuner_params tuner_temic_4046fm5_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_temic_40x6f_5_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_PHILIPS_PAL_DK - Philips PAL ------------ */
+
+static struct tuner_params tuner_philips_pal_dk_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_lg_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_PHILIPS_FQ1216ME - Philips PAL ------------ */
+
+static struct tuner_params tuner_philips_fq1216me_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_lg_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
+		.has_tda9887 = 1,
+		.port1_active = 1,
+		.port2_active = 1,
+		.port2_invert_for_secam_lc = 1,
+	},
+};
+
+/* ------------ TUNER_LG_PAL_I_FM - LGINNOTEK PAL_I ------------ */
+
+static struct tuner_params tuner_lg_pal_i_fm_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_lg_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_LG_PAL_I - LGINNOTEK PAL_I ------------ */
+
+static struct tuner_params tuner_lg_pal_i_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_lg_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_LG_NTSC_FM - LGINNOTEK NTSC ------------ */
+
+static struct tuner_range tuner_lg_ntsc_fm_ranges[] = {
+	{ 16 * 210.00 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 497.00 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
+};
+
+static struct tuner_params tuner_lg_ntsc_fm_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_lg_ntsc_fm_ranges,
+		.count  = ARRAY_SIZE(tuner_lg_ntsc_fm_ranges),
+	},
+};
+
+/* ------------ TUNER_LG_PAL_FM - LGINNOTEK PAL ------------ */
+
+static struct tuner_params tuner_lg_pal_fm_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_lg_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_LG_PAL - LGINNOTEK PAL ------------ */
+
+static struct tuner_params tuner_lg_pal_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_lg_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
+	},
+};
+
+/* 30-39 */
+/* ------------ TUNER_TEMIC_4009FN5_MULTI_PAL_FM - TEMIC PAL ------------ */
+
+static struct tuner_params tuner_temic_4009_fn5_multi_pal_fm_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_temic_4009f_5_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_SHARP_2U5JF5540_NTSC - SHARP NTSC ------------ */
+
+static struct tuner_range tuner_sharp_2u5jf5540_ntsc_ranges[] = {
+	{ 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 317.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
+};
+
+static struct tuner_params tuner_sharp_2u5jf5540_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_sharp_2u5jf5540_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_sharp_2u5jf5540_ntsc_ranges),
+	},
+};
+
+/* ------------ TUNER_Samsung_PAL_TCPM9091PD27 - Samsung PAL ------------ */
+
+static struct tuner_range tuner_samsung_pal_tcpm9091pd27_ranges[] = {
+	{ 16 * 169 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 464 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99     , 0x8e, 0x30, },
+};
+
+static struct tuner_params tuner_samsung_pal_tcpm9091pd27_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_samsung_pal_tcpm9091pd27_ranges,
+		.count  = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_ranges),
+	},
+};
+
+/* ------------ TUNER_TEMIC_4106FH5 - TEMIC PAL ------------ */
+
+static struct tuner_params tuner_temic_4106fh5_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_temic_4009f_5_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_TEMIC_4012FY5 - TEMIC PAL ------------ */
+
+static struct tuner_params tuner_temic_4012fy5_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_temic_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_TEMIC_4136FY5 - TEMIC NTSC ------------ */
+
+static struct tuner_params tuner_temic_4136_fy5_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_temic_4x3x_f_5_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges),
+	},
+};
+
+/* ------------ TUNER_LG_PAL_NEW_TAPC - LGINNOTEK PAL ------------ */
+
+static struct tuner_range tuner_lg_new_tapc_ranges[] = {
+	{ 16 * 170.00 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 450.00 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
+};
+
+static struct tuner_params tuner_lg_pal_new_tapc_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_lg_new_tapc_ranges,
+		.count  = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
+	},
+};
+
+/* ------------ TUNER_PHILIPS_FM1216ME_MK3 - Philips PAL ------------ */
+
+static struct tuner_range tuner_fm1216me_mk3_pal_ranges[] = {
+	{ 16 * 158.00 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 442.00 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x04, },
+};
+
+static struct tuner_params tuner_fm1216me_mk3_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_fm1216me_mk3_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges),
+		.cb_first_if_lower_freq = 1,
+		.has_tda9887 = 1,
+		.port1_active = 1,
+		.port2_active = 1,
+		.port2_invert_for_secam_lc = 1,
+		.port1_fm_high_sensitivity = 1,
+		.default_top_mid = -2,
+		.default_top_secam_mid = -2,
+		.default_top_secam_high = -2,
+	},
+};
+
+/* ------------ TUNER_PHILIPS_FM1216MK5 - Philips PAL ------------ */
+
+static struct tuner_range tuner_fm1216mk5_pal_ranges[] = {
+	{ 16 * 158.00 /*MHz*/, 0xce, 0x01, },
+	{ 16 * 441.00 /*MHz*/, 0xce, 0x02, },
+	{ 16 * 864.00        , 0xce, 0x04, },
+};
+
+static struct tuner_params tuner_fm1216mk5_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_fm1216mk5_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_fm1216mk5_pal_ranges),
+		.cb_first_if_lower_freq = 1,
+		.has_tda9887 = 1,
+		.port1_active = 1,
+		.port2_active = 1,
+		.port2_invert_for_secam_lc = 1,
+		.port1_fm_high_sensitivity = 1,
+		.default_top_mid = -2,
+		.default_top_secam_mid = -2,
+		.default_top_secam_high = -2,
+	},
+};
+
+/* ------------ TUNER_LG_NTSC_NEW_TAPC - LGINNOTEK NTSC ------------ */
+
+static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_lg_new_tapc_ranges,
+		.count  = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
+	},
+};
+
+/* 40-49 */
+/* ------------ TUNER_HITACHI_NTSC - HITACHI NTSC ------------ */
+
+static struct tuner_params tuner_hitachi_ntsc_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_lg_new_tapc_ranges,
+		.count  = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
+	},
+};
+
+/* ------------ TUNER_PHILIPS_PAL_MK - Philips PAL ------------ */
+
+static struct tuner_range tuner_philips_pal_mk_pal_ranges[] = {
+	{ 16 * 140.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 463.25 /*MHz*/, 0x8e, 0xc2, },
+	{ 16 * 999.99        , 0x8e, 0xcf, },
+};
+
+static struct tuner_params tuner_philips_pal_mk_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_philips_pal_mk_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_pal_mk_pal_ranges),
+	},
+};
+
+/* ---- TUNER_PHILIPS_FCV1236D - Philips FCV1236D (ATSC/NTSC) ---- */
+
+static struct tuner_range tuner_philips_fcv1236d_ntsc_ranges[] = {
+	{ 16 * 157.25 /*MHz*/, 0x8e, 0xa2, },
+	{ 16 * 451.25 /*MHz*/, 0x8e, 0x92, },
+	{ 16 * 999.99        , 0x8e, 0x32, },
+};
+
+static struct tuner_range tuner_philips_fcv1236d_atsc_ranges[] = {
+	{ 16 * 159.00 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 453.00 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
+};
+
+static struct tuner_params tuner_philips_fcv1236d_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_philips_fcv1236d_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_fcv1236d_ntsc_ranges),
+	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_philips_fcv1236d_atsc_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_fcv1236d_atsc_ranges),
+		.iffreq = 16 * 44.00,
+	},
+};
+
+/* ------------ TUNER_PHILIPS_FM1236_MK3 - Philips NTSC ------------ */
+
+static struct tuner_range tuner_fm1236_mk3_ntsc_ranges[] = {
+	{ 16 * 160.00 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 442.00 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x04, },
+};
+
+static struct tuner_params tuner_fm1236_mk3_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_fm1236_mk3_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
+		.cb_first_if_lower_freq = 1,
+		.has_tda9887 = 1,
+		.port1_active = 1,
+		.port2_active = 1,
+		.port1_fm_high_sensitivity = 1,
+	},
+};
+
+/* ------------ TUNER_PHILIPS_4IN1 - Philips NTSC ------------ */
+
+static struct tuner_params tuner_philips_4in1_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_fm1236_mk3_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
+	},
+};
+
+/* ------------ TUNER_MICROTUNE_4049FM5 - Microtune PAL ------------ */
+
+static struct tuner_params tuner_microtune_4049_fm5_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_temic_4009f_5_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
+		.has_tda9887 = 1,
+		.port1_invert_for_secam_lc = 1,
+		.default_pll_gating_18 = 1,
+		.fm_gain_normal=1,
+		.radio_if = 1, /* 33.3 MHz */
+	},
+};
+
+/* ------------ TUNER_PANASONIC_VP27 - Panasonic NTSC ------------ */
+
+static struct tuner_range tuner_panasonic_vp27_ntsc_ranges[] = {
+	{ 16 * 160.00 /*MHz*/, 0xce, 0x01, },
+	{ 16 * 454.00 /*MHz*/, 0xce, 0x02, },
+	{ 16 * 999.99        , 0xce, 0x08, },
+};
+
+static struct tuner_params tuner_panasonic_vp27_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_panasonic_vp27_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges),
+		.has_tda9887 = 1,
+		.intercarrier_mode = 1,
+		.default_top_low = -3,
+		.default_top_mid = -3,
+		.default_top_high = -3,
+	},
+};
+
+/* ------------ TUNER_TNF_8831BGFF - Philips PAL ------------ */
+
+static struct tuner_range tuner_tnf_8831bgff_pal_ranges[] = {
+	{ 16 * 161.25 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
+};
+
+static struct tuner_params tuner_tnf_8831bgff_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_tnf_8831bgff_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_tnf_8831bgff_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_MICROTUNE_4042FI5 - Microtune NTSC ------------ */
+
+static struct tuner_range tuner_microtune_4042fi5_ntsc_ranges[] = {
+	{ 16 * 162.00 /*MHz*/, 0x8e, 0xa2, },
+	{ 16 * 457.00 /*MHz*/, 0x8e, 0x94, },
+	{ 16 * 999.99        , 0x8e, 0x31, },
+};
+
+static struct tuner_range tuner_microtune_4042fi5_atsc_ranges[] = {
+	{ 16 * 162.00 /*MHz*/, 0x8e, 0xa1, },
+	{ 16 * 457.00 /*MHz*/, 0x8e, 0x91, },
+	{ 16 * 999.99        , 0x8e, 0x31, },
+};
+
+static struct tuner_params tuner_microtune_4042fi5_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_microtune_4042fi5_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_microtune_4042fi5_ntsc_ranges),
+	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_microtune_4042fi5_atsc_ranges,
+		.count  = ARRAY_SIZE(tuner_microtune_4042fi5_atsc_ranges),
+		.iffreq = 16 * 44.00 /*MHz*/,
+	},
+};
+
+/* 50-59 */
+/* ------------ TUNER_TCL_2002N - TCL NTSC ------------ */
+
+static struct tuner_range tuner_tcl_2002n_ntsc_ranges[] = {
+	{ 16 * 172.00 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 448.00 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
+};
+
+static struct tuner_params tuner_tcl_2002n_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_tcl_2002n_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_tcl_2002n_ntsc_ranges),
+		.cb_first_if_lower_freq = 1,
+	},
+};
+
+/* ------------ TUNER_PHILIPS_FM1256_IH3 - Philips PAL ------------ */
+
+static struct tuner_params tuner_philips_fm1256_ih3_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_fm1236_mk3_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
+		.radio_if = 1, /* 33.3 MHz */
+	},
+};
+
+/* ------------ TUNER_THOMSON_DTT7610 - THOMSON ATSC ------------ */
+
+/* single range used for both ntsc and atsc */
+static struct tuner_range tuner_thomson_dtt7610_ntsc_ranges[] = {
+	{ 16 * 157.25 /*MHz*/, 0x8e, 0x39, },
+	{ 16 * 454.00 /*MHz*/, 0x8e, 0x3a, },
+	{ 16 * 999.99        , 0x8e, 0x3c, },
+};
+
+static struct tuner_params tuner_thomson_dtt7610_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_thomson_dtt7610_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges),
+	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_thomson_dtt7610_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges),
+		.iffreq = 16 * 44.00 /*MHz*/,
+	},
+};
+
+/* ------------ TUNER_PHILIPS_FQ1286 - Philips NTSC ------------ */
+
+static struct tuner_range tuner_philips_fq1286_ntsc_ranges[] = {
+	{ 16 * 160.00 /*MHz*/, 0x8e, 0x41, },
+	{ 16 * 454.00 /*MHz*/, 0x8e, 0x42, },
+	{ 16 * 999.99        , 0x8e, 0x04, },
+};
+
+static struct tuner_params tuner_philips_fq1286_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_philips_fq1286_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_fq1286_ntsc_ranges),
+	},
+};
+
+/* ------------ TUNER_TCL_2002MB - TCL PAL ------------ */
+
+static struct tuner_range tuner_tcl_2002mb_pal_ranges[] = {
+	{ 16 * 170.00 /*MHz*/, 0xce, 0x01, },
+	{ 16 * 450.00 /*MHz*/, 0xce, 0x02, },
+	{ 16 * 999.99        , 0xce, 0x08, },
+};
+
+static struct tuner_params tuner_tcl_2002mb_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_tcl_2002mb_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_tcl_2002mb_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_PHILIPS_FQ1216AME_MK4 - Philips PAL ------------ */
+
+static struct tuner_range tuner_philips_fq12_6a___mk4_pal_ranges[] = {
+	{ 16 * 160.00 /*MHz*/, 0xce, 0x01, },
+	{ 16 * 442.00 /*MHz*/, 0xce, 0x02, },
+	{ 16 * 999.99        , 0xce, 0x04, },
+};
+
+static struct tuner_params tuner_philips_fq1216ame_mk4_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_philips_fq12_6a___mk4_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_pal_ranges),
+		.has_tda9887 = 1,
+		.port1_active = 1,
+		.port2_invert_for_secam_lc = 1,
+		.default_top_mid = -2,
+		.default_top_secam_low = -2,
+		.default_top_secam_mid = -2,
+		.default_top_secam_high = -2,
+	},
+};
+
+/* ------------ TUNER_PHILIPS_FQ1236A_MK4 - Philips NTSC ------------ */
+
+static struct tuner_params tuner_philips_fq1236a_mk4_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_fm1236_mk3_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
+	},
+};
+
+/* ------------ TUNER_YMEC_TVF_8531MF - Philips NTSC ------------ */
+
+static struct tuner_params tuner_ymec_tvf_8531mf_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_philips_ntsc_m_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_ntsc_m_ranges),
+	},
+};
+
+/* ------------ TUNER_YMEC_TVF_5533MF - Philips NTSC ------------ */
+
+static struct tuner_range tuner_ymec_tvf_5533mf_ntsc_ranges[] = {
+	{ 16 * 160.00 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 454.00 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x04, },
+};
+
+static struct tuner_params tuner_ymec_tvf_5533mf_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_ymec_tvf_5533mf_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_ymec_tvf_5533mf_ntsc_ranges),
+	},
+};
+
+/* 60-69 */
+/* ------------ TUNER_THOMSON_DTT761X - THOMSON ATSC ------------ */
+/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
+
+static struct tuner_range tuner_thomson_dtt761x_ntsc_ranges[] = {
+	{ 16 * 145.25 /*MHz*/, 0x8e, 0x39, },
+	{ 16 * 415.25 /*MHz*/, 0x8e, 0x3a, },
+	{ 16 * 999.99        , 0x8e, 0x3c, },
+};
+
+static struct tuner_range tuner_thomson_dtt761x_atsc_ranges[] = {
+	{ 16 * 147.00 /*MHz*/, 0x8e, 0x39, },
+	{ 16 * 417.00 /*MHz*/, 0x8e, 0x3a, },
+	{ 16 * 999.99        , 0x8e, 0x3c, },
+};
+
+static struct tuner_params tuner_thomson_dtt761x_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_thomson_dtt761x_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges),
+		.has_tda9887 = 1,
+		.fm_gain_normal = 1,
+		.radio_if = 2, /* 41.3 MHz */
+	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_thomson_dtt761x_atsc_ranges,
+		.count  = ARRAY_SIZE(tuner_thomson_dtt761x_atsc_ranges),
+		.iffreq = 16 * 44.00, /*MHz*/
+	},
+};
+
+/* ------------ TUNER_TENA_9533_DI - Philips PAL ------------ */
+
+static struct tuner_range tuner_tena_9533_di_pal_ranges[] = {
+	{ 16 * 160.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 464.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x04, },
+};
+
+static struct tuner_params tuner_tena_9533_di_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_tena_9533_di_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_TENA_TNF_5337 - Tena tnf5337MFD STD M/N ------------ */
+
+static struct tuner_range tuner_tena_tnf_5337_ntsc_ranges[] = {
+	{ 16 * 166.25 /*MHz*/, 0x86, 0x01, },
+	{ 16 * 466.25 /*MHz*/, 0x86, 0x02, },
+	{ 16 * 999.99        , 0x86, 0x08, },
+};
+
+static struct tuner_params tuner_tena_tnf_5337_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_tena_tnf_5337_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_tena_tnf_5337_ntsc_ranges),
+	},
+};
+
+/* ------------ TUNER_PHILIPS_FMD1216ME(X)_MK3 - Philips PAL ------------ */
+
+static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = {
+	{ 16 * 160.00 /*MHz*/, 0x86, 0x51, },
+	{ 16 * 442.00 /*MHz*/, 0x86, 0x52, },
+	{ 16 * 999.99        , 0x86, 0x54, },
+};
+
+static struct tuner_range tuner_philips_fmd1216me_mk3_dvb_ranges[] = {
+	{ 16 * 143.87 /*MHz*/, 0xbc, 0x41 },
+	{ 16 * 158.87 /*MHz*/, 0xf4, 0x41 },
+	{ 16 * 329.87 /*MHz*/, 0xbc, 0x42 },
+	{ 16 * 441.87 /*MHz*/, 0xf4, 0x42 },
+	{ 16 * 625.87 /*MHz*/, 0xbc, 0x44 },
+	{ 16 * 803.87 /*MHz*/, 0xf4, 0x44 },
+	{ 16 * 999.99        , 0xfc, 0x44 },
+};
+
+static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_philips_fmd1216me_mk3_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges),
+		.has_tda9887 = 1,
+		.port1_active = 1,
+		.port2_active = 1,
+		.port2_fm_high_sensitivity = 1,
+		.port2_invert_for_secam_lc = 1,
+		.port1_set_for_fm_mono = 1,
+	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_philips_fmd1216me_mk3_dvb_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges),
+		.iffreq = 16 * 36.125, /*MHz*/
+	},
+};
+
+static struct tuner_params tuner_philips_fmd1216mex_mk3_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_philips_fmd1216me_mk3_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges),
+		.has_tda9887 = 1,
+		.port1_active = 1,
+		.port2_active = 1,
+		.port2_fm_high_sensitivity = 1,
+		.port2_invert_for_secam_lc = 1,
+		.port1_set_for_fm_mono = 1,
+		.radio_if = 1,
+		.fm_gain_normal = 1,
+	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_philips_fmd1216me_mk3_dvb_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges),
+		.iffreq = 16 * 36.125, /*MHz*/
+	},
+};
+
+/* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */
+
+static struct tuner_range tuner_tua6034_ntsc_ranges[] = {
+	{ 16 * 165.00 /*MHz*/, 0x8e, 0x01 },
+	{ 16 * 450.00 /*MHz*/, 0x8e, 0x02 },
+	{ 16 * 999.99        , 0x8e, 0x04 },
+};
+
+static struct tuner_range tuner_tua6034_atsc_ranges[] = {
+	{ 16 * 165.00 /*MHz*/, 0xce, 0x01 },
+	{ 16 * 450.00 /*MHz*/, 0xce, 0x02 },
+	{ 16 * 999.99        , 0xce, 0x04 },
+};
+
+static struct tuner_params tuner_lg_tdvs_h06xf_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_tua6034_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_tua6034_ntsc_ranges),
+	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_tua6034_atsc_ranges,
+		.count  = ARRAY_SIZE(tuner_tua6034_atsc_ranges),
+		.iffreq = 16 * 44.00,
+	},
+};
+
+/* ------------ TUNER_YMEC_TVF66T5_B_DFF - Philips PAL ------------ */
+
+static struct tuner_range tuner_ymec_tvf66t5_b_dff_pal_ranges[] = {
+	{ 16 * 160.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 464.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
+};
+
+static struct tuner_params tuner_ymec_tvf66t5_b_dff_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_ymec_tvf66t5_b_dff_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_pal_ranges),
+	},
+};
+
+/* ------------ TUNER_LG_NTSC_TALN_MINI - LGINNOTEK NTSC ------------ */
+
+static struct tuner_range tuner_lg_taln_ntsc_ranges[] = {
+	{ 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 373.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
+};
+
+static struct tuner_range tuner_lg_taln_pal_secam_ranges[] = {
+	{ 16 * 150.00 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 425.00 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
+};
+
+static struct tuner_params tuner_lg_taln_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_lg_taln_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_lg_taln_ntsc_ranges),
+	},{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_lg_taln_pal_secam_ranges,
+		.count  = ARRAY_SIZE(tuner_lg_taln_pal_secam_ranges),
+	},
+};
+
+/* ------------ TUNER_PHILIPS_TD1316 - Philips PAL ------------ */
+
+static struct tuner_range tuner_philips_td1316_pal_ranges[] = {
+	{ 16 * 160.00 /*MHz*/, 0xc8, 0xa1, },
+	{ 16 * 442.00 /*MHz*/, 0xc8, 0xa2, },
+	{ 16 * 999.99        , 0xc8, 0xa4, },
+};
+
+static struct tuner_range tuner_philips_td1316_dvb_ranges[] = {
+	{ 16 *  93.834 /*MHz*/, 0xca, 0x60, },
+	{ 16 * 123.834 /*MHz*/, 0xca, 0xa0, },
+	{ 16 * 163.834 /*MHz*/, 0xca, 0xc0, },
+	{ 16 * 253.834 /*MHz*/, 0xca, 0x60, },
+	{ 16 * 383.834 /*MHz*/, 0xca, 0xa0, },
+	{ 16 * 443.834 /*MHz*/, 0xca, 0xc0, },
+	{ 16 * 583.834 /*MHz*/, 0xca, 0x60, },
+	{ 16 * 793.834 /*MHz*/, 0xca, 0xa0, },
+	{ 16 * 999.999        , 0xca, 0xe0, },
+};
+
+static struct tuner_params tuner_philips_td1316_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_philips_td1316_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_td1316_pal_ranges),
+	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_philips_td1316_dvb_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_td1316_dvb_ranges),
+		.iffreq = 16 * 36.166667 /*MHz*/,
+	},
+};
+
+/* ------------ TUNER_PHILIPS_TUV1236D - Philips ATSC ------------ */
+
+static struct tuner_range tuner_tuv1236d_ntsc_ranges[] = {
+	{ 16 * 157.25 /*MHz*/, 0xce, 0x01, },
+	{ 16 * 454.00 /*MHz*/, 0xce, 0x02, },
+	{ 16 * 999.99        , 0xce, 0x04, },
+};
+
+static struct tuner_range tuner_tuv1236d_atsc_ranges[] = {
+	{ 16 * 157.25 /*MHz*/, 0xc6, 0x41, },
+	{ 16 * 454.00 /*MHz*/, 0xc6, 0x42, },
+	{ 16 * 999.99        , 0xc6, 0x44, },
+};
+
+static struct tuner_params tuner_tuv1236d_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_tuv1236d_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_tuv1236d_ntsc_ranges),
+	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_tuv1236d_atsc_ranges,
+		.count  = ARRAY_SIZE(tuner_tuv1236d_atsc_ranges),
+		.iffreq = 16 * 44.00,
+	},
+};
+
+/* ------------ TUNER_TNF_xxx5  - Texas Instruments--------- */
+/* This is known to work with Tenna TVF58t5-MFF and TVF5835 MFF
+ *	but it is expected to work also with other Tenna/Ymec
+ *	models based on TI SN 761677 chip on both PAL and NTSC
+ */
+
+static struct tuner_range tuner_tnf_5335_d_if_pal_ranges[] = {
+	{ 16 * 168.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 471.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
+};
+
+static struct tuner_range tuner_tnf_5335mf_ntsc_ranges[] = {
+	{ 16 * 169.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 469.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
+};
+
+static struct tuner_params tuner_tnf_5335mf_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_tnf_5335mf_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_tnf_5335mf_ntsc_ranges),
+	},
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_tnf_5335_d_if_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_tnf_5335_d_if_pal_ranges),
+	},
+};
+
+/* 70-79 */
+/* ------------ TUNER_SAMSUNG_TCPN_2121P30A - Samsung NTSC ------------ */
+
+/* '+ 4' turns on the Low Noise Amplifier */
+static struct tuner_range tuner_samsung_tcpn_2121p30a_ntsc_ranges[] = {
+	{ 16 * 130.00 /*MHz*/, 0xce, 0x01 + 4, },
+	{ 16 * 364.50 /*MHz*/, 0xce, 0x02 + 4, },
+	{ 16 * 999.99        , 0xce, 0x08 + 4, },
+};
+
+static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges),
+	},
+};
+
+/* ------------ TUNER_THOMSON_FE6600 - DViCO Hybrid PAL ------------ */
+
+static struct tuner_range tuner_thomson_fe6600_pal_ranges[] = {
+	{ 16 * 160.00 /*MHz*/, 0xfe, 0x11, },
+	{ 16 * 442.00 /*MHz*/, 0xf6, 0x12, },
+	{ 16 * 999.99        , 0xf6, 0x18, },
+};
+
+static struct tuner_range tuner_thomson_fe6600_dvb_ranges[] = {
+	{ 16 * 250.00 /*MHz*/, 0xb4, 0x12, },
+	{ 16 * 455.00 /*MHz*/, 0xfe, 0x11, },
+	{ 16 * 775.50 /*MHz*/, 0xbc, 0x18, },
+	{ 16 * 999.99        , 0xf4, 0x18, },
+};
+
+static struct tuner_params tuner_thomson_fe6600_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_thomson_fe6600_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_thomson_fe6600_pal_ranges),
+	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_thomson_fe6600_dvb_ranges,
+		.count  = ARRAY_SIZE(tuner_thomson_fe6600_dvb_ranges),
+		.iffreq = 16 * 36.125 /*MHz*/,
+	},
+};
+
+/* ------------ TUNER_SAMSUNG_TCPG_6121P30A - Samsung PAL ------------ */
+
+/* '+ 4' turns on the Low Noise Amplifier */
+static struct tuner_range tuner_samsung_tcpg_6121p30a_pal_ranges[] = {
+	{ 16 * 146.25 /*MHz*/, 0xce, 0x01 + 4, },
+	{ 16 * 428.50 /*MHz*/, 0xce, 0x02 + 4, },
+	{ 16 * 999.99        , 0xce, 0x08 + 4, },
+};
+
+static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_samsung_tcpg_6121p30a_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_pal_ranges),
+		.has_tda9887 = 1,
+		.port1_active = 1,
+		.port2_active = 1,
+		.port2_invert_for_secam_lc = 1,
+	},
+};
+
+/* ------------ TUNER_TCL_MF02GIP-5N-E - TCL MF02GIP-5N ------------ */
+
+static struct tuner_range tuner_tcl_mf02gip_5n_ntsc_ranges[] = {
+	{ 16 * 172.00 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 448.00 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x04, },
+};
+
+static struct tuner_params tuner_tcl_mf02gip_5n_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_tcl_mf02gip_5n_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_tcl_mf02gip_5n_ntsc_ranges),
+		.cb_first_if_lower_freq = 1,
+	},
+};
+
+/* 80-89 */
+/* --------- TUNER_PHILIPS_FQ1216LME_MK3 -- active loopthrough, no FM ------- */
+
+static struct tuner_params tuner_fq1216lme_mk3_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_fm1216me_mk3_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges),
+		.cb_first_if_lower_freq = 1, /* not specified, but safe to do */
+		.has_tda9887 = 1, /* TDA9886 */
+		.port1_active = 1,
+		.port2_active = 1,
+		.port2_invert_for_secam_lc = 1,
+		.default_top_low = 4,
+		.default_top_mid = 4,
+		.default_top_high = 4,
+		.default_top_secam_low = 4,
+		.default_top_secam_mid = 4,
+		.default_top_secam_high = 4,
+	},
+};
+
+/* ----- TUNER_PARTSNIC_PTI_5NF05 - Partsnic (Daewoo) PTI-5NF05 NTSC ----- */
+
+static struct tuner_range tuner_partsnic_pti_5nf05_ranges[] = {
+	/* The datasheet specified channel ranges and the bandswitch byte */
+	/* The control byte value of 0x8e is just a guess */
+	{ 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, /* Channels    2 -    B */
+	{ 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, /* Channels    C - W+11 */
+	{ 16 * 999.99        , 0x8e, 0x08, }, /* Channels W+12 -   69 */
+};
+
+static struct tuner_params tuner_partsnic_pti_5nf05_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_partsnic_pti_5nf05_ranges,
+		.count  = ARRAY_SIZE(tuner_partsnic_pti_5nf05_ranges),
+		.cb_first_if_lower_freq = 1, /* not specified but safe to do */
+	},
+};
+
+/* --------- TUNER_PHILIPS_CU1216L - DVB-C NIM ------------------------- */
+
+static struct tuner_range tuner_cu1216l_ranges[] = {
+	{ 16 * 160.25 /*MHz*/, 0xce, 0x01 },
+	{ 16 * 444.25 /*MHz*/, 0xce, 0x02 },
+	{ 16 * 999.99        , 0xce, 0x04 },
+};
+
+static struct tuner_params tuner_philips_cu1216l_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_cu1216l_ranges,
+		.count  = ARRAY_SIZE(tuner_cu1216l_ranges),
+		.iffreq = 16 * 36.125, /*MHz*/
+	},
+};
+
+/* ---------------------- TUNER_SONY_BTF_PXN01Z ------------------------ */
+
+static struct tuner_range tuner_sony_btf_pxn01z_ranges[] = {
+	{ 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 367.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x04, },
+};
+
+static struct tuner_params tuner_sony_btf_pxn01z_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_sony_btf_pxn01z_ranges,
+		.count  = ARRAY_SIZE(tuner_sony_btf_pxn01z_ranges),
+	},
+};
+
+/* ------------ TUNER_PHILIPS_FQ1236_MK5 - Philips NTSC ------------ */
+
+static struct tuner_params tuner_philips_fq1236_mk5_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_NTSC,
+		.ranges = tuner_fm1236_mk3_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
+		.has_tda9887 = 1, /* TDA9885, no FM radio */
+	},
+};
+
+/* --------------------------------------------------------------------- */
+
+struct tunertype tuners[] = {
+	/* 0-9 */
+	[TUNER_TEMIC_PAL] = { /* TEMIC PAL */
+		.name   = "Temic PAL (4002 FH5)",
+		.params = tuner_temic_pal_params,
+		.count  = ARRAY_SIZE(tuner_temic_pal_params),
+	},
+	[TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */
+		.name   = "Philips PAL_I (FI1246 and compatibles)",
+		.params = tuner_philips_pal_i_params,
+		.count  = ARRAY_SIZE(tuner_philips_pal_i_params),
+	},
+	[TUNER_PHILIPS_NTSC] = { /* Philips NTSC */
+		.name   = "Philips NTSC (FI1236,FM1236 and compatibles)",
+		.params = tuner_philips_ntsc_params,
+		.count  = ARRAY_SIZE(tuner_philips_ntsc_params),
+	},
+	[TUNER_PHILIPS_SECAM] = { /* Philips SECAM */
+		.name   = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)",
+		.params = tuner_philips_secam_params,
+		.count  = ARRAY_SIZE(tuner_philips_secam_params),
+	},
+	[TUNER_ABSENT] = { /* Tuner Absent */
+		.name   = "NoTuner",
+	},
+	[TUNER_PHILIPS_PAL] = { /* Philips PAL */
+		.name   = "Philips PAL_BG (FI1216 and compatibles)",
+		.params = tuner_philips_pal_params,
+		.count  = ARRAY_SIZE(tuner_philips_pal_params),
+	},
+	[TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */
+		.name   = "Temic NTSC (4032 FY5)",
+		.params = tuner_temic_ntsc_params,
+		.count  = ARRAY_SIZE(tuner_temic_ntsc_params),
+	},
+	[TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */
+		.name   = "Temic PAL_I (4062 FY5)",
+		.params = tuner_temic_pal_i_params,
+		.count  = ARRAY_SIZE(tuner_temic_pal_i_params),
+	},
+	[TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */
+		.name   = "Temic NTSC (4036 FY5)",
+		.params = tuner_temic_4036fy5_ntsc_params,
+		.count  = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_params),
+	},
+	[TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */
+		.name   = "Alps HSBH1",
+		.params = tuner_alps_tsbh1_ntsc_params,
+		.count  = ARRAY_SIZE(tuner_alps_tsbh1_ntsc_params),
+	},
+
+	/* 10-19 */
+	[TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */
+		.name   = "Alps TSBE1",
+		.params = tuner_alps_tsb_1_params,
+		.count  = ARRAY_SIZE(tuner_alps_tsb_1_params),
+	},
+	[TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */
+		.name   = "Alps TSBB5",
+		.params = tuner_alps_tsbb5_params,
+		.count  = ARRAY_SIZE(tuner_alps_tsbb5_params),
+	},
+	[TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */
+		.name   = "Alps TSBE5",
+		.params = tuner_alps_tsbe5_params,
+		.count  = ARRAY_SIZE(tuner_alps_tsbe5_params),
+	},
+	[TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */
+		.name   = "Alps TSBC5",
+		.params = tuner_alps_tsbc5_params,
+		.count  = ARRAY_SIZE(tuner_alps_tsbc5_params),
+	},
+	[TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */
+		.name   = "Temic PAL_BG (4006FH5)",
+		.params = tuner_temic_4006fh5_params,
+		.count  = ARRAY_SIZE(tuner_temic_4006fh5_params),
+	},
+	[TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */
+		.name   = "Alps TSCH6",
+		.params = tuner_alps_tshc6_params,
+		.count  = ARRAY_SIZE(tuner_alps_tshc6_params),
+	},
+	[TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */
+		.name   = "Temic PAL_DK (4016 FY5)",
+		.params = tuner_temic_pal_dk_params,
+		.count  = ARRAY_SIZE(tuner_temic_pal_dk_params),
+	},
+	[TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */
+		.name   = "Philips NTSC_M (MK2)",
+		.params = tuner_philips_ntsc_m_params,
+		.count  = ARRAY_SIZE(tuner_philips_ntsc_m_params),
+	},
+	[TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */
+		.name   = "Temic PAL_I (4066 FY5)",
+		.params = tuner_temic_4066fy5_pal_i_params,
+		.count  = ARRAY_SIZE(tuner_temic_4066fy5_pal_i_params),
+	},
+	[TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */
+		.name   = "Temic PAL* auto (4006 FN5)",
+		.params = tuner_temic_4006fn5_multi_params,
+		.count  = ARRAY_SIZE(tuner_temic_4006fn5_multi_params),
+	},
+
+	/* 20-29 */
+	[TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */
+		.name   = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)",
+		.params = tuner_temic_4009f_5_params,
+		.count  = ARRAY_SIZE(tuner_temic_4009f_5_params),
+	},
+	[TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */
+		.name   = "Temic NTSC (4039 FR5)",
+		.params = tuner_temic_4039fr5_params,
+		.count  = ARRAY_SIZE(tuner_temic_4039fr5_params),
+	},
+	[TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */
+		.name   = "Temic PAL/SECAM multi (4046 FM5)",
+		.params = tuner_temic_4046fm5_params,
+		.count  = ARRAY_SIZE(tuner_temic_4046fm5_params),
+	},
+	[TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */
+		.name   = "Philips PAL_DK (FI1256 and compatibles)",
+		.params = tuner_philips_pal_dk_params,
+		.count  = ARRAY_SIZE(tuner_philips_pal_dk_params),
+	},
+	[TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */
+		.name   = "Philips PAL/SECAM multi (FQ1216ME)",
+		.params = tuner_philips_fq1216me_params,
+		.count  = ARRAY_SIZE(tuner_philips_fq1216me_params),
+	},
+	[TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */
+		.name   = "LG PAL_I+FM (TAPC-I001D)",
+		.params = tuner_lg_pal_i_fm_params,
+		.count  = ARRAY_SIZE(tuner_lg_pal_i_fm_params),
+	},
+	[TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */
+		.name   = "LG PAL_I (TAPC-I701D)",
+		.params = tuner_lg_pal_i_params,
+		.count  = ARRAY_SIZE(tuner_lg_pal_i_params),
+	},
+	[TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */
+		.name   = "LG NTSC+FM (TPI8NSR01F)",
+		.params = tuner_lg_ntsc_fm_params,
+		.count  = ARRAY_SIZE(tuner_lg_ntsc_fm_params),
+	},
+	[TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */
+		.name   = "LG PAL_BG+FM (TPI8PSB01D)",
+		.params = tuner_lg_pal_fm_params,
+		.count  = ARRAY_SIZE(tuner_lg_pal_fm_params),
+	},
+	[TUNER_LG_PAL] = { /* LGINNOTEK PAL */
+		.name   = "LG PAL_BG (TPI8PSB11D)",
+		.params = tuner_lg_pal_params,
+		.count  = ARRAY_SIZE(tuner_lg_pal_params),
+	},
+
+	/* 30-39 */
+	[TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */
+		.name   = "Temic PAL* auto + FM (4009 FN5)",
+		.params = tuner_temic_4009_fn5_multi_pal_fm_params,
+		.count  = ARRAY_SIZE(tuner_temic_4009_fn5_multi_pal_fm_params),
+	},
+	[TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */
+		.name   = "SHARP NTSC_JP (2U5JF5540)",
+		.params = tuner_sharp_2u5jf5540_params,
+		.count  = ARRAY_SIZE(tuner_sharp_2u5jf5540_params),
+	},
+	[TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */
+		.name   = "Samsung PAL TCPM9091PD27",
+		.params = tuner_samsung_pal_tcpm9091pd27_params,
+		.count  = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_params),
+	},
+	[TUNER_MT2032] = { /* Microtune PAL|NTSC */
+		.name   = "MT20xx universal",
+		/* see mt20xx.c for details */ },
+	[TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */
+		.name   = "Temic PAL_BG (4106 FH5)",
+		.params = tuner_temic_4106fh5_params,
+		.count  = ARRAY_SIZE(tuner_temic_4106fh5_params),
+	},
+	[TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */
+		.name   = "Temic PAL_DK/SECAM_L (4012 FY5)",
+		.params = tuner_temic_4012fy5_params,
+		.count  = ARRAY_SIZE(tuner_temic_4012fy5_params),
+	},
+	[TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */
+		.name   = "Temic NTSC (4136 FY5)",
+		.params = tuner_temic_4136_fy5_params,
+		.count  = ARRAY_SIZE(tuner_temic_4136_fy5_params),
+	},
+	[TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */
+		.name   = "LG PAL (newer TAPC series)",
+		.params = tuner_lg_pal_new_tapc_params,
+		.count  = ARRAY_SIZE(tuner_lg_pal_new_tapc_params),
+	},
+	[TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */
+		.name   = "Philips PAL/SECAM multi (FM1216ME MK3)",
+		.params = tuner_fm1216me_mk3_params,
+		.count  = ARRAY_SIZE(tuner_fm1216me_mk3_params),
+	},
+	[TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */
+		.name   = "LG NTSC (newer TAPC series)",
+		.params = tuner_lg_ntsc_new_tapc_params,
+		.count  = ARRAY_SIZE(tuner_lg_ntsc_new_tapc_params),
+	},
+
+	/* 40-49 */
+	[TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */
+		.name   = "HITACHI V7-J180AT",
+		.params = tuner_hitachi_ntsc_params,
+		.count  = ARRAY_SIZE(tuner_hitachi_ntsc_params),
+	},
+	[TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */
+		.name   = "Philips PAL_MK (FI1216 MK)",
+		.params = tuner_philips_pal_mk_params,
+		.count  = ARRAY_SIZE(tuner_philips_pal_mk_params),
+	},
+	[TUNER_PHILIPS_FCV1236D] = { /* Philips ATSC */
+		.name   = "Philips FCV1236D ATSC/NTSC dual in",
+		.params = tuner_philips_fcv1236d_params,
+		.count  = ARRAY_SIZE(tuner_philips_fcv1236d_params),
+		.min = 16 *  53.00,
+		.max = 16 * 803.00,
+		.stepsize = 62500,
+	},
+	[TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */
+		.name   = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)",
+		.params = tuner_fm1236_mk3_params,
+		.count  = ARRAY_SIZE(tuner_fm1236_mk3_params),
+	},
+	[TUNER_PHILIPS_4IN1] = { /* Philips NTSC */
+		.name   = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)",
+		.params = tuner_philips_4in1_params,
+		.count  = ARRAY_SIZE(tuner_philips_4in1_params),
+	},
+	[TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */
+		.name   = "Microtune 4049 FM5",
+		.params = tuner_microtune_4049_fm5_params,
+		.count  = ARRAY_SIZE(tuner_microtune_4049_fm5_params),
+	},
+	[TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */
+		.name   = "Panasonic VP27s/ENGE4324D",
+		.params = tuner_panasonic_vp27_params,
+		.count  = ARRAY_SIZE(tuner_panasonic_vp27_params),
+	},
+	[TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */
+		.name   = "LG NTSC (TAPE series)",
+		.params = tuner_fm1236_mk3_params,
+		.count  = ARRAY_SIZE(tuner_fm1236_mk3_params),
+	},
+	[TUNER_TNF_8831BGFF] = { /* Philips PAL */
+		.name   = "Tenna TNF 8831 BGFF)",
+		.params = tuner_tnf_8831bgff_params,
+		.count  = ARRAY_SIZE(tuner_tnf_8831bgff_params),
+	},
+	[TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */
+		.name   = "Microtune 4042 FI5 ATSC/NTSC dual in",
+		.params = tuner_microtune_4042fi5_params,
+		.count  = ARRAY_SIZE(tuner_microtune_4042fi5_params),
+		.min    = 16 *  57.00,
+		.max    = 16 * 858.00,
+		.stepsize = 62500,
+	},
+
+	/* 50-59 */
+	[TUNER_TCL_2002N] = { /* TCL NTSC */
+		.name   = "TCL 2002N",
+		.params = tuner_tcl_2002n_params,
+		.count  = ARRAY_SIZE(tuner_tcl_2002n_params),
+	},
+	[TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */
+		.name   = "Philips PAL/SECAM_D (FM 1256 I-H3)",
+		.params = tuner_philips_fm1256_ih3_params,
+		.count  = ARRAY_SIZE(tuner_philips_fm1256_ih3_params),
+	},
+	[TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */
+		.name   = "Thomson DTT 7610 (ATSC/NTSC)",
+		.params = tuner_thomson_dtt7610_params,
+		.count  = ARRAY_SIZE(tuner_thomson_dtt7610_params),
+		.min    = 16 *  44.00,
+		.max    = 16 * 958.00,
+		.stepsize = 62500,
+	},
+	[TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */
+		.name   = "Philips FQ1286",
+		.params = tuner_philips_fq1286_params,
+		.count  = ARRAY_SIZE(tuner_philips_fq1286_params),
+	},
+	[TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */
+		.name   = "Philips/NXP TDA 8290/8295 + 8275/8275A/18271",
+		/* see tda8290.c for details */ },
+	[TUNER_TCL_2002MB] = { /* TCL PAL */
+		.name   = "TCL 2002MB",
+		.params = tuner_tcl_2002mb_params,
+		.count  = ARRAY_SIZE(tuner_tcl_2002mb_params),
+	},
+	[TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */
+		.name   = "Philips PAL/SECAM multi (FQ1216AME MK4)",
+		.params = tuner_philips_fq1216ame_mk4_params,
+		.count  = ARRAY_SIZE(tuner_philips_fq1216ame_mk4_params),
+	},
+	[TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */
+		.name   = "Philips FQ1236A MK4",
+		.params = tuner_philips_fq1236a_mk4_params,
+		.count  = ARRAY_SIZE(tuner_philips_fq1236a_mk4_params),
+	},
+	[TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */
+		.name   = "Ymec TVision TVF-8531MF/8831MF/8731MF",
+		.params = tuner_ymec_tvf_8531mf_params,
+		.count  = ARRAY_SIZE(tuner_ymec_tvf_8531mf_params),
+	},
+	[TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */
+		.name   = "Ymec TVision TVF-5533MF",
+		.params = tuner_ymec_tvf_5533mf_params,
+		.count  = ARRAY_SIZE(tuner_ymec_tvf_5533mf_params),
+	},
+
+	/* 60-69 */
+	[TUNER_THOMSON_DTT761X] = { /* THOMSON ATSC */
+		/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
+		.name   = "Thomson DTT 761X (ATSC/NTSC)",
+		.params = tuner_thomson_dtt761x_params,
+		.count  = ARRAY_SIZE(tuner_thomson_dtt761x_params),
+		.min    = 16 *  57.00,
+		.max    = 16 * 863.00,
+		.stepsize = 62500,
+		.initdata = tua603x_agc103,
+	},
+	[TUNER_TENA_9533_DI] = { /* Philips PAL */
+		.name   = "Tena TNF9533-D/IF/TNF9533-B/DF",
+		.params = tuner_tena_9533_di_params,
+		.count  = ARRAY_SIZE(tuner_tena_9533_di_params),
+	},
+	[TUNER_TEA5767] = { /* Philips RADIO */
+		.name   = "Philips TEA5767HN FM Radio",
+		/* see tea5767.c for details */
+	},
+	[TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */
+		.name   = "Philips FMD1216ME MK3 Hybrid Tuner",
+		.params = tuner_philips_fmd1216me_mk3_params,
+		.count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params),
+		.min = 16 *  50.87,
+		.max = 16 * 858.00,
+		.stepsize = 166667,
+		.initdata = tua603x_agc112,
+		.sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
+	},
+	[TUNER_LG_TDVS_H06XF] = { /* LGINNOTEK ATSC */
+		.name   = "LG TDVS-H06xF", /* H061F, H062F & H064F */
+		.params = tuner_lg_tdvs_h06xf_params,
+		.count  = ARRAY_SIZE(tuner_lg_tdvs_h06xf_params),
+		.min    = 16 *  54.00,
+		.max    = 16 * 863.00,
+		.stepsize = 62500,
+		.initdata = tua603x_agc103,
+	},
+	[TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */
+		.name   = "Ymec TVF66T5-B/DFF",
+		.params = tuner_ymec_tvf66t5_b_dff_params,
+		.count  = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_params),
+	},
+	[TUNER_LG_TALN] = { /* LGINNOTEK NTSC / PAL / SECAM */
+		.name   = "LG TALN series",
+		.params = tuner_lg_taln_params,
+		.count  = ARRAY_SIZE(tuner_lg_taln_params),
+	},
+	[TUNER_PHILIPS_TD1316] = { /* Philips PAL */
+		.name   = "Philips TD1316 Hybrid Tuner",
+		.params = tuner_philips_td1316_params,
+		.count  = ARRAY_SIZE(tuner_philips_td1316_params),
+		.min    = 16 *  87.00,
+		.max    = 16 * 895.00,
+		.stepsize = 166667,
+	},
+	[TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */
+		.name   = "Philips TUV1236D ATSC/NTSC dual in",
+		.params = tuner_tuv1236d_params,
+		.count  = ARRAY_SIZE(tuner_tuv1236d_params),
+		.min    = 16 *  54.00,
+		.max    = 16 * 864.00,
+		.stepsize = 62500,
+	},
+	[TUNER_TNF_5335MF] = { /* Tenna PAL/NTSC */
+		.name   = "Tena TNF 5335 and similar models",
+		.params = tuner_tnf_5335mf_params,
+		.count  = ARRAY_SIZE(tuner_tnf_5335mf_params),
+	},
+
+	/* 70-79 */
+	[TUNER_SAMSUNG_TCPN_2121P30A] = { /* Samsung NTSC */
+		.name   = "Samsung TCPN 2121P30A",
+		.params = tuner_samsung_tcpn_2121p30a_params,
+		.count  = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params),
+	},
+	[TUNER_XC2028] = { /* Xceive 2028 */
+		.name   = "Xceive xc2028/xc3028 tuner",
+		/* see tuner-xc2028.c for details */
+	},
+	[TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */
+		.name   = "Thomson FE6600",
+		.params = tuner_thomson_fe6600_params,
+		.count  = ARRAY_SIZE(tuner_thomson_fe6600_params),
+		.min    = 16 *  44.25,
+		.max    = 16 * 858.00,
+		.stepsize = 166667,
+	},
+	[TUNER_SAMSUNG_TCPG_6121P30A] = { /* Samsung PAL */
+		.name   = "Samsung TCPG 6121P30A",
+		.params = tuner_samsung_tcpg_6121p30a_params,
+		.count  = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_params),
+	},
+	[TUNER_TDA9887] = { /* Philips TDA 9887 IF PLL Demodulator.
+				This chip is part of some modern tuners */
+		.name   = "Philips TDA988[5,6,7] IF PLL Demodulator",
+		/* see tda9887.c for details */
+	},
+	[TUNER_TEA5761] = { /* Philips RADIO */
+		.name   = "Philips TEA5761 FM Radio",
+		/* see tea5767.c for details */
+	},
+	[TUNER_XC5000] = { /* Xceive 5000 */
+		.name   = "Xceive 5000 tuner",
+		/* see xc5000.c for details */
+	},
+	[TUNER_XC4000] = { /* Xceive 4000 */
+		.name   = "Xceive 4000 tuner",
+		/* see xc4000.c for details */
+	},
+	[TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */
+		.name   = "TCL tuner MF02GIP-5N-E",
+		.params = tuner_tcl_mf02gip_5n_params,
+		.count  = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params),
+	},
+	[TUNER_PHILIPS_FMD1216MEX_MK3] = { /* Philips PAL */
+		.name   = "Philips FMD1216MEX MK3 Hybrid Tuner",
+		.params = tuner_philips_fmd1216mex_mk3_params,
+		.count  = ARRAY_SIZE(tuner_philips_fmd1216mex_mk3_params),
+		.min = 16 *  50.87,
+		.max = 16 * 858.00,
+		.stepsize = 166667,
+		.initdata = tua603x_agc112,
+		.sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
+	},
+		[TUNER_PHILIPS_FM1216MK5] = { /* Philips PAL */
+		.name   = "Philips PAL/SECAM multi (FM1216 MK5)",
+		.params = tuner_fm1216mk5_params,
+		.count  = ARRAY_SIZE(tuner_fm1216mk5_params),
+	},
+
+	/* 80-89 */
+	[TUNER_PHILIPS_FQ1216LME_MK3] = { /* PAL/SECAM, Loop-thru, no FM */
+		.name = "Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough",
+		.params = tuner_fq1216lme_mk3_params,
+		.count  = ARRAY_SIZE(tuner_fq1216lme_mk3_params),
+	},
+
+	[TUNER_PARTSNIC_PTI_5NF05] = {
+		.name = "Partsnic (Daewoo) PTI-5NF05",
+		.params = tuner_partsnic_pti_5nf05_params,
+		.count  = ARRAY_SIZE(tuner_partsnic_pti_5nf05_params),
+	},
+	[TUNER_PHILIPS_CU1216L] = {
+		.name = "Philips CU1216L",
+		.params = tuner_philips_cu1216l_params,
+		.count  = ARRAY_SIZE(tuner_philips_cu1216l_params),
+		.stepsize = 62500,
+	},
+	[TUNER_NXP_TDA18271] = {
+		.name   = "NXP TDA18271",
+		/* see tda18271-fe.c for details */
+	},
+	[TUNER_SONY_BTF_PXN01Z] = {
+		.name   = "Sony BTF-Pxn01Z",
+		.params = tuner_sony_btf_pxn01z_params,
+		.count  = ARRAY_SIZE(tuner_sony_btf_pxn01z_params),
+	},
+	[TUNER_PHILIPS_FQ1236_MK5] = { /* NTSC, TDA9885, no FM radio */
+		.name   = "Philips FQ1236 MK5",
+		.params = tuner_philips_fq1236_mk5_params,
+		.count  = ARRAY_SIZE(tuner_philips_fq1236_mk5_params),
+	},
+	[TUNER_TENA_TNF_5337] = { /* Tena 5337 MFD */
+		.name   = "Tena TNF5337 MFD",
+		.params = tuner_tena_tnf_5337_params,
+		.count  = ARRAY_SIZE(tuner_tena_tnf_5337_params),
+	},
+	[TUNER_XC5000C] = { /* Xceive 5000C */
+		.name   = "Xceive 5000C tuner",
+		/* see xc5000.c for details */
+	},
+};
+EXPORT_SYMBOL(tuners);
+
+unsigned const int tuner_count = ARRAY_SIZE(tuners);
+EXPORT_SYMBOL(tuner_count);
+
+MODULE_DESCRIPTION("Simple tuner device type database");
+MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/tuner-xc2028-types.h b/drivers/media/tuners/tuner-xc2028-types.h
new file mode 100644
index 0000000..74dc46a
--- /dev/null
+++ b/drivers/media/tuners/tuner-xc2028-types.h
@@ -0,0 +1,141 @@
+/* tuner-xc2028_types
+ *
+ * This file includes internal tipes to be used inside tuner-xc2028.
+ * Shouldn't be included outside tuner-xc2028
+ *
+ * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
+/* xc3028 firmware types */
+
+/* BASE firmware should be loaded before any other firmware */
+#define BASE		(1<<0)
+#define BASE_TYPES	(BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1)
+
+/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */
+#define F8MHZ		(1<<1)
+
+/* Multichannel Television Sound (MTS)
+   Those firmwares are capable of using xc2038 DSP to decode audio and
+   produce a baseband audio output on some pins of the chip.
+   There are MTS firmwares for the most used video standards. It should be
+   required to use MTS firmwares, depending on the way audio is routed into
+   the bridge chip
+ */
+#define MTS		(1<<2)
+
+/* FIXME: I have no idea what's the difference between
+   D2620 and D2633 firmwares
+ */
+#define D2620		(1<<3)
+#define D2633		(1<<4)
+
+/* DTV firmwares for 6, 7 and 8 MHz
+   DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS
+   DTV8 - 8MHz - DVB-C/DVB-T
+ */
+#define DTV6           (1 << 5)
+#define QAM            (1 << 6)
+#define DTV7		(1<<7)
+#define DTV78		(1<<8)
+#define DTV8		(1<<9)
+
+#define DTV_TYPES	(D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC)
+
+/* There's a FM | BASE firmware + FM specific firmware (std=0) */
+#define	FM		(1<<10)
+
+#define STD_SPECIFIC_TYPES (MTS|FM|LCD|NOGD)
+
+/* Applies only for FM firmware
+   Makes it use RF input 1 (pin #2) instead of input 2 (pin #4)
+ */
+#define INPUT1		(1<<11)
+
+
+/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
+	and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
+	There are variants both with and without NOGD
+	Those firmwares produce better result with LCD displays
+ */
+#define LCD		(1<<12)
+
+/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
+	and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
+	The NOGD firmwares don't have group delay compensation filter
+ */
+#define NOGD		(1<<13)
+
+/* Old firmwares were broken into init0 and init1 */
+#define INIT1		(1<<14)
+
+/* SCODE firmware selects particular behaviours */
+#define MONO           (1 << 15)
+#define ATSC           (1 << 16)
+#define IF             (1 << 17)
+#define LG60           (1 << 18)
+#define ATI638         (1 << 19)
+#define OREN538        (1 << 20)
+#define OREN36         (1 << 21)
+#define TOYOTA388      (1 << 22)
+#define TOYOTA794      (1 << 23)
+#define DIBCOM52       (1 << 24)
+#define ZARLINK456     (1 << 25)
+#define CHINA          (1 << 26)
+#define F6MHZ          (1 << 27)
+#define INPUT2         (1 << 28)
+#define SCODE          (1 << 29)
+
+/* This flag identifies that the scode table has a new format */
+#define HAS_IF         (1 << 30)
+
+/* There are different scode tables for MTS and non-MTS.
+   The MTS firmwares support mono only
+  */
+#define SCODE_TYPES (SCODE | MTS)
+
+
+/* Newer types not defined on videodev2.h.
+   The original idea were to move all those types to videodev2.h, but
+   it seemed overkill, since, with the exception of SECAM/K3, the other
+   types seem to be autodetected.
+   It is not clear where secam/k3 is used, nor we have a feedback of this
+   working or being autodetected by the standard secam firmware.
+ */
+
+#define V4L2_STD_SECAM_K3	(0x04000000)
+
+/* Audio types */
+
+#define V4L2_STD_A2_A		(1LL<<32)
+#define V4L2_STD_A2_B		(1LL<<33)
+#define V4L2_STD_NICAM_A	(1LL<<34)
+#define V4L2_STD_NICAM_B	(1LL<<35)
+#define V4L2_STD_AM		(1LL<<36)
+#define V4L2_STD_BTSC		(1LL<<37)
+#define V4L2_STD_EIAJ		(1LL<<38)
+
+#define V4L2_STD_A2		(V4L2_STD_A2_A    | V4L2_STD_A2_B)
+#define V4L2_STD_NICAM		(V4L2_STD_NICAM_A | V4L2_STD_NICAM_B)
+
+/* To preserve backward compatibilty,
+   (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported
+ */
+
+#define V4L2_STD_AUDIO		(V4L2_STD_A2    | \
+				 V4L2_STD_NICAM | \
+				 V4L2_STD_AM    | \
+				 V4L2_STD_BTSC  | \
+				 V4L2_STD_EIAJ)
+
+/* Used standards with audio restrictions */
+
+#define V4L2_STD_PAL_BG_A2_A	(V4L2_STD_PAL_BG | V4L2_STD_A2_A)
+#define V4L2_STD_PAL_BG_A2_B	(V4L2_STD_PAL_BG | V4L2_STD_A2_B)
+#define V4L2_STD_PAL_BG_NICAM_A	(V4L2_STD_PAL_BG | V4L2_STD_NICAM_A)
+#define V4L2_STD_PAL_BG_NICAM_B	(V4L2_STD_PAL_BG | V4L2_STD_NICAM_B)
+#define V4L2_STD_PAL_DK_A2	(V4L2_STD_PAL_DK | V4L2_STD_A2)
+#define V4L2_STD_PAL_DK_NICAM	(V4L2_STD_PAL_DK | V4L2_STD_NICAM)
+#define V4L2_STD_SECAM_L_NICAM	(V4L2_STD_SECAM_L | V4L2_STD_NICAM)
+#define V4L2_STD_SECAM_L_AM	(V4L2_STD_SECAM_L | V4L2_STD_AM)
diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c
new file mode 100644
index 0000000..7bcb6b0
--- /dev/null
+++ b/drivers/media/tuners/tuner-xc2028.c
@@ -0,0 +1,1509 @@
+/* tuner-xc2028
+ *
+ * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org)
+ *
+ * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com)
+ *       - frontend interface
+ *
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
+#include <linux/i2c.h>
+#include <asm/div64.h>
+#include <linux/firmware.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <media/tuner.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+#include "tuner-i2c.h"
+#include "tuner-xc2028.h"
+#include "tuner-xc2028-types.h"
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+/* Registers (Write-only) */
+#define XREG_INIT         0x00
+#define XREG_RF_FREQ      0x02
+#define XREG_POWER_DOWN   0x08
+
+/* Registers (Read-only) */
+#define XREG_FREQ_ERROR   0x01
+#define XREG_LOCK         0x02
+#define XREG_VERSION      0x04
+#define XREG_PRODUCT_ID   0x08
+#define XREG_HSYNC_FREQ   0x10
+#define XREG_FRAME_LINES  0x20
+#define XREG_SNR          0x40
+
+#define XREG_ADC_ENV      0x0100
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+static int no_poweroff;
+module_param(no_poweroff, int, 0644);
+MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
+	"1 keep device energized and with tuner ready all the times.\n"
+	"  Faster, but consumes more power and keeps the device hotter\n");
+
+static char audio_std[8];
+module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
+MODULE_PARM_DESC(audio_std,
+	"Audio standard. XC3028 audio decoder explicitly "
+	"needs to know what audio\n"
+	"standard is needed for some video standards with audio A2 or NICAM.\n"
+	"The valid values are:\n"
+	"A2\n"
+	"A2/A\n"
+	"A2/B\n"
+	"NICAM\n"
+	"NICAM/A\n"
+	"NICAM/B\n");
+
+static char firmware_name[30];
+module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
+MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
+				"default firmware name\n");
+
+static LIST_HEAD(hybrid_tuner_instance_list);
+static DEFINE_MUTEX(xc2028_list_mutex);
+
+/* struct for storing firmware table */
+struct firmware_description {
+	unsigned int  type;
+	v4l2_std_id   id;
+	__u16         int_freq;
+	unsigned char *ptr;
+	unsigned int  size;
+};
+
+struct firmware_properties {
+	unsigned int	type;
+	v4l2_std_id	id;
+	v4l2_std_id	std_req;
+	__u16		int_freq;
+	unsigned int	scode_table;
+	int 		scode_nr;
+};
+
+enum xc2028_state {
+	XC2028_NO_FIRMWARE = 0,
+	XC2028_WAITING_FIRMWARE,
+	XC2028_ACTIVE,
+	XC2028_SLEEP,
+	XC2028_NODEV,
+};
+
+struct xc2028_data {
+	struct list_head        hybrid_tuner_instance_list;
+	struct tuner_i2c_props  i2c_props;
+	__u32			frequency;
+
+	enum xc2028_state	state;
+	const char		*fname;
+
+	struct firmware_description *firm;
+	int			firm_size;
+	__u16			firm_version;
+
+	__u16			hwmodel;
+	__u16			hwvers;
+
+	struct xc2028_ctrl	ctrl;
+
+	struct firmware_properties cur_fw;
+
+	struct mutex lock;
+};
+
+#define i2c_send(priv, buf, size) ({					\
+	int _rc;							\
+	_rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size);		\
+	if (size != _rc)						\
+		tuner_info("i2c output error: rc = %d (should be %d)\n",\
+			   _rc, (int)size);				\
+	if (priv->ctrl.msleep)						\
+		msleep(priv->ctrl.msleep);				\
+	_rc;								\
+})
+
+#define i2c_rcv(priv, buf, size) ({					\
+	int _rc;							\
+	_rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size);		\
+	if (size != _rc)						\
+		tuner_err("i2c input error: rc = %d (should be %d)\n",	\
+			   _rc, (int)size); 				\
+	_rc;								\
+})
+
+#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({		\
+	int _rc;							\
+	_rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize,	\
+				       ibuf, isize);			\
+	if (isize != _rc)						\
+		tuner_err("i2c input error: rc = %d (should be %d)\n",	\
+			   _rc, (int)isize); 				\
+	if (priv->ctrl.msleep)						\
+		msleep(priv->ctrl.msleep);				\
+	_rc;								\
+})
+
+#define send_seq(priv, data...)	({					\
+	static u8 _val[] = data;					\
+	int _rc;							\
+	if (sizeof(_val) !=						\
+			(_rc = tuner_i2c_xfer_send(&priv->i2c_props,	\
+						_val, sizeof(_val)))) {	\
+		tuner_err("Error on line %d: %d\n", __LINE__, _rc);	\
+	} else if (priv->ctrl.msleep)					\
+		msleep(priv->ctrl.msleep);				\
+	_rc;								\
+})
+
+static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
+{
+	unsigned char buf[2];
+	unsigned char ibuf[2];
+
+	tuner_dbg("%s %04x called\n", __func__, reg);
+
+	buf[0] = reg >> 8;
+	buf[1] = (unsigned char) reg;
+
+	if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2)
+		return -EIO;
+
+	*val = (ibuf[1]) | (ibuf[0] << 8);
+	return 0;
+}
+
+#define dump_firm_type(t) 	dump_firm_type_and_int_freq(t, 0)
+static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
+{
+	 if (type & BASE)
+		printk("BASE ");
+	 if (type & INIT1)
+		printk("INIT1 ");
+	 if (type & F8MHZ)
+		printk("F8MHZ ");
+	 if (type & MTS)
+		printk("MTS ");
+	 if (type & D2620)
+		printk("D2620 ");
+	 if (type & D2633)
+		printk("D2633 ");
+	 if (type & DTV6)
+		printk("DTV6 ");
+	 if (type & QAM)
+		printk("QAM ");
+	 if (type & DTV7)
+		printk("DTV7 ");
+	 if (type & DTV78)
+		printk("DTV78 ");
+	 if (type & DTV8)
+		printk("DTV8 ");
+	 if (type & FM)
+		printk("FM ");
+	 if (type & INPUT1)
+		printk("INPUT1 ");
+	 if (type & LCD)
+		printk("LCD ");
+	 if (type & NOGD)
+		printk("NOGD ");
+	 if (type & MONO)
+		printk("MONO ");
+	 if (type & ATSC)
+		printk("ATSC ");
+	 if (type & IF)
+		printk("IF ");
+	 if (type & LG60)
+		printk("LG60 ");
+	 if (type & ATI638)
+		printk("ATI638 ");
+	 if (type & OREN538)
+		printk("OREN538 ");
+	 if (type & OREN36)
+		printk("OREN36 ");
+	 if (type & TOYOTA388)
+		printk("TOYOTA388 ");
+	 if (type & TOYOTA794)
+		printk("TOYOTA794 ");
+	 if (type & DIBCOM52)
+		printk("DIBCOM52 ");
+	 if (type & ZARLINK456)
+		printk("ZARLINK456 ");
+	 if (type & CHINA)
+		printk("CHINA ");
+	 if (type & F6MHZ)
+		printk("F6MHZ ");
+	 if (type & INPUT2)
+		printk("INPUT2 ");
+	 if (type & SCODE)
+		printk("SCODE ");
+	 if (type & HAS_IF)
+		printk("HAS_IF_%d ", int_freq);
+}
+
+static  v4l2_std_id parse_audio_std_option(void)
+{
+	if (strcasecmp(audio_std, "A2") == 0)
+		return V4L2_STD_A2;
+	if (strcasecmp(audio_std, "A2/A") == 0)
+		return V4L2_STD_A2_A;
+	if (strcasecmp(audio_std, "A2/B") == 0)
+		return V4L2_STD_A2_B;
+	if (strcasecmp(audio_std, "NICAM") == 0)
+		return V4L2_STD_NICAM;
+	if (strcasecmp(audio_std, "NICAM/A") == 0)
+		return V4L2_STD_NICAM_A;
+	if (strcasecmp(audio_std, "NICAM/B") == 0)
+		return V4L2_STD_NICAM_B;
+
+	return 0;
+}
+
+static int check_device_status(struct xc2028_data *priv)
+{
+	switch (priv->state) {
+	case XC2028_NO_FIRMWARE:
+	case XC2028_WAITING_FIRMWARE:
+		return -EAGAIN;
+	case XC2028_ACTIVE:
+	case XC2028_SLEEP:
+		return 0;
+	case XC2028_NODEV:
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static void free_firmware(struct xc2028_data *priv)
+{
+	int i;
+	tuner_dbg("%s called\n", __func__);
+
+	if (!priv->firm)
+		return;
+
+	for (i = 0; i < priv->firm_size; i++)
+		kfree(priv->firm[i].ptr);
+
+	kfree(priv->firm);
+
+	priv->firm = NULL;
+	priv->firm_size = 0;
+	priv->state = XC2028_NO_FIRMWARE;
+
+	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+}
+
+static int load_all_firmwares(struct dvb_frontend *fe,
+			      const struct firmware *fw)
+{
+	struct xc2028_data    *priv = fe->tuner_priv;
+	const unsigned char   *p, *endp;
+	int                   rc = 0;
+	int		      n, n_array;
+	char		      name[33];
+
+	tuner_dbg("%s called\n", __func__);
+
+	p = fw->data;
+	endp = p + fw->size;
+
+	if (fw->size < sizeof(name) - 1 + 2 + 2) {
+		tuner_err("Error: firmware file %s has invalid size!\n",
+			  priv->fname);
+		goto corrupt;
+	}
+
+	memcpy(name, p, sizeof(name) - 1);
+	name[sizeof(name) - 1] = 0;
+	p += sizeof(name) - 1;
+
+	priv->firm_version = get_unaligned_le16(p);
+	p += 2;
+
+	n_array = get_unaligned_le16(p);
+	p += 2;
+
+	tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
+		   n_array, priv->fname, name,
+		   priv->firm_version >> 8, priv->firm_version & 0xff);
+
+	priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL);
+	if (priv->firm == NULL) {
+		tuner_err("Not enough memory to load firmware file.\n");
+		rc = -ENOMEM;
+		goto err;
+	}
+	priv->firm_size = n_array;
+
+	n = -1;
+	while (p < endp) {
+		__u32 type, size;
+		v4l2_std_id id;
+		__u16 int_freq = 0;
+
+		n++;
+		if (n >= n_array) {
+			tuner_err("More firmware images in file than "
+				  "were expected!\n");
+			goto corrupt;
+		}
+
+		/* Checks if there's enough bytes to read */
+		if (endp - p < sizeof(type) + sizeof(id) + sizeof(size))
+			goto header;
+
+		type = get_unaligned_le32(p);
+		p += sizeof(type);
+
+		id = get_unaligned_le64(p);
+		p += sizeof(id);
+
+		if (type & HAS_IF) {
+			int_freq = get_unaligned_le16(p);
+			p += sizeof(int_freq);
+			if (endp - p < sizeof(size))
+				goto header;
+		}
+
+		size = get_unaligned_le32(p);
+		p += sizeof(size);
+
+		if (!size || size > endp - p) {
+			tuner_err("Firmware type ");
+			dump_firm_type(type);
+			printk("(%x), id %llx is corrupted "
+			       "(size=%d, expected %d)\n",
+			       type, (unsigned long long)id,
+			       (unsigned)(endp - p), size);
+			goto corrupt;
+		}
+
+		priv->firm[n].ptr = kzalloc(size, GFP_KERNEL);
+		if (priv->firm[n].ptr == NULL) {
+			tuner_err("Not enough memory to load firmware file.\n");
+			rc = -ENOMEM;
+			goto err;
+		}
+		tuner_dbg("Reading firmware type ");
+		if (debug) {
+			dump_firm_type_and_int_freq(type, int_freq);
+			printk("(%x), id %llx, size=%d.\n",
+			       type, (unsigned long long)id, size);
+		}
+
+		memcpy(priv->firm[n].ptr, p, size);
+		priv->firm[n].type = type;
+		priv->firm[n].id   = id;
+		priv->firm[n].size = size;
+		priv->firm[n].int_freq = int_freq;
+
+		p += size;
+	}
+
+	if (n + 1 != priv->firm_size) {
+		tuner_err("Firmware file is incomplete!\n");
+		goto corrupt;
+	}
+
+	goto done;
+
+header:
+	tuner_err("Firmware header is incomplete!\n");
+corrupt:
+	rc = -EINVAL;
+	tuner_err("Error: firmware file is corrupted!\n");
+
+err:
+	tuner_info("Releasing partially loaded firmware file.\n");
+	free_firmware(priv);
+
+done:
+	if (rc == 0)
+		tuner_dbg("Firmware files loaded.\n");
+	else
+		priv->state = XC2028_NODEV;
+
+	return rc;
+}
+
+static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
+			 v4l2_std_id *id)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	int                 i, best_i = -1, best_nr_matches = 0;
+	unsigned int        type_mask = 0;
+
+	tuner_dbg("%s called, want type=", __func__);
+	if (debug) {
+		dump_firm_type(type);
+		printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
+	}
+
+	if (!priv->firm) {
+		tuner_err("Error! firmware not loaded\n");
+		return -EINVAL;
+	}
+
+	if (((type & ~SCODE) == 0) && (*id == 0))
+		*id = V4L2_STD_PAL;
+
+	if (type & BASE)
+		type_mask = BASE_TYPES;
+	else if (type & SCODE) {
+		type &= SCODE_TYPES;
+		type_mask = SCODE_TYPES & ~HAS_IF;
+	} else if (type & DTV_TYPES)
+		type_mask = DTV_TYPES;
+	else if (type & STD_SPECIFIC_TYPES)
+		type_mask = STD_SPECIFIC_TYPES;
+
+	type &= type_mask;
+
+	if (!(type & SCODE))
+		type_mask = ~0;
+
+	/* Seek for exact match */
+	for (i = 0; i < priv->firm_size; i++) {
+		if ((type == (priv->firm[i].type & type_mask)) &&
+		    (*id == priv->firm[i].id))
+			goto found;
+	}
+
+	/* Seek for generic video standard match */
+	for (i = 0; i < priv->firm_size; i++) {
+		v4l2_std_id match_mask;
+		int nr_matches;
+
+		if (type != (priv->firm[i].type & type_mask))
+			continue;
+
+		match_mask = *id & priv->firm[i].id;
+		if (!match_mask)
+			continue;
+
+		if ((*id & match_mask) == *id)
+			goto found; /* Supports all the requested standards */
+
+		nr_matches = hweight64(match_mask);
+		if (nr_matches > best_nr_matches) {
+			best_nr_matches = nr_matches;
+			best_i = i;
+		}
+	}
+
+	if (best_nr_matches > 0) {
+		tuner_dbg("Selecting best matching firmware (%d bits) for "
+			  "type=", best_nr_matches);
+		dump_firm_type(type);
+		printk("(%x), id %016llx:\n", type, (unsigned long long)*id);
+		i = best_i;
+		goto found;
+	}
+
+	/*FIXME: Would make sense to seek for type "hint" match ? */
+
+	i = -ENOENT;
+	goto ret;
+
+found:
+	*id = priv->firm[i].id;
+
+ret:
+	tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found");
+	if (debug) {
+		dump_firm_type(type);
+		printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
+	}
+	return i;
+}
+
+static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+
+	/* analog side (tuner-core) uses i2c_adap->algo_data.
+	 * digital side is not guaranteed to have algo_data defined.
+	 *
+	 * digital side will always have fe->dvb defined.
+	 * analog side (tuner-core) doesn't (yet) define fe->dvb.
+	 */
+
+	return (!fe->callback) ? -EINVAL :
+		fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+				fe->dvb->priv : priv->i2c_props.adap->algo_data,
+			     DVB_FRONTEND_COMPONENT_TUNER, cmd, arg);
+}
+
+static int load_firmware(struct dvb_frontend *fe, unsigned int type,
+			 v4l2_std_id *id)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	int                pos, rc;
+	unsigned char      *p, *endp, buf[priv->ctrl.max_len];
+
+	tuner_dbg("%s called\n", __func__);
+
+	pos = seek_firmware(fe, type, id);
+	if (pos < 0)
+		return pos;
+
+	tuner_info("Loading firmware for type=");
+	dump_firm_type(priv->firm[pos].type);
+	printk("(%x), id %016llx.\n", priv->firm[pos].type,
+	       (unsigned long long)*id);
+
+	p = priv->firm[pos].ptr;
+	endp = p + priv->firm[pos].size;
+
+	while (p < endp) {
+		__u16 size;
+
+		/* Checks if there's enough bytes to read */
+		if (p + sizeof(size) > endp) {
+			tuner_err("Firmware chunk size is wrong\n");
+			return -EINVAL;
+		}
+
+		size = le16_to_cpu(*(__u16 *) p);
+		p += sizeof(size);
+
+		if (size == 0xffff)
+			return 0;
+
+		if (!size) {
+			/* Special callback command received */
+			rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
+			if (rc < 0) {
+				tuner_err("Error at RESET code %d\n",
+					   (*p) & 0x7f);
+				return -EINVAL;
+			}
+			continue;
+		}
+		if (size >= 0xff00) {
+			switch (size) {
+			case 0xff00:
+				rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0);
+				if (rc < 0) {
+					tuner_err("Error at RESET code %d\n",
+						  (*p) & 0x7f);
+					return -EINVAL;
+				}
+				break;
+			default:
+				tuner_info("Invalid RESET code %d\n",
+					   size & 0x7f);
+				return -EINVAL;
+
+			}
+			continue;
+		}
+
+		/* Checks for a sleep command */
+		if (size & 0x8000) {
+			msleep(size & 0x7fff);
+			continue;
+		}
+
+		if ((size + p > endp)) {
+			tuner_err("missing bytes: need %d, have %d\n",
+				   size, (int)(endp - p));
+			return -EINVAL;
+		}
+
+		buf[0] = *p;
+		p++;
+		size--;
+
+		/* Sends message chunks */
+		while (size > 0) {
+			int len = (size < priv->ctrl.max_len - 1) ?
+				   size : priv->ctrl.max_len - 1;
+
+			memcpy(buf + 1, p, len);
+
+			rc = i2c_send(priv, buf, len + 1);
+			if (rc < 0) {
+				tuner_err("%d returned from send\n", rc);
+				return -EINVAL;
+			}
+
+			p += len;
+			size -= len;
+		}
+
+		/* silently fail if the frontend doesn't support I2C flush */
+		rc = do_tuner_callback(fe, XC2028_I2C_FLUSH, 0);
+		if ((rc < 0) && (rc != -EINVAL)) {
+			tuner_err("error executing flush: %d\n", rc);
+			return rc;
+		}
+	}
+	return 0;
+}
+
+static int load_scode(struct dvb_frontend *fe, unsigned int type,
+			 v4l2_std_id *id, __u16 int_freq, int scode)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	int                pos, rc;
+	unsigned char	   *p;
+
+	tuner_dbg("%s called\n", __func__);
+
+	if (!int_freq) {
+		pos = seek_firmware(fe, type, id);
+		if (pos < 0)
+			return pos;
+	} else {
+		for (pos = 0; pos < priv->firm_size; pos++) {
+			if ((priv->firm[pos].int_freq == int_freq) &&
+			    (priv->firm[pos].type & HAS_IF))
+				break;
+		}
+		if (pos == priv->firm_size)
+			return -ENOENT;
+	}
+
+	p = priv->firm[pos].ptr;
+
+	if (priv->firm[pos].type & HAS_IF) {
+		if (priv->firm[pos].size != 12 * 16 || scode >= 16)
+			return -EINVAL;
+		p += 12 * scode;
+	} else {
+		/* 16 SCODE entries per file; each SCODE entry is 12 bytes and
+		 * has a 2-byte size header in the firmware format. */
+		if (priv->firm[pos].size != 14 * 16 || scode >= 16 ||
+		    le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12)
+			return -EINVAL;
+		p += 14 * scode + 2;
+	}
+
+	tuner_info("Loading SCODE for type=");
+	dump_firm_type_and_int_freq(priv->firm[pos].type,
+				    priv->firm[pos].int_freq);
+	printk("(%x), id %016llx.\n", priv->firm[pos].type,
+	       (unsigned long long)*id);
+
+	if (priv->firm_version < 0x0202)
+		rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00});
+	else
+		rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00});
+	if (rc < 0)
+		return -EIO;
+
+	rc = i2c_send(priv, p, 12);
+	if (rc < 0)
+		return -EIO;
+
+	rc = send_seq(priv, {0x00, 0x8c});
+	if (rc < 0)
+		return -EIO;
+
+	return 0;
+}
+
+static int check_firmware(struct dvb_frontend *fe, unsigned int type,
+			  v4l2_std_id std, __u16 int_freq)
+{
+	struct xc2028_data         *priv = fe->tuner_priv;
+	struct firmware_properties new_fw;
+	int			   rc, retry_count = 0;
+	u16			   version, hwmodel;
+	v4l2_std_id		   std0;
+
+	tuner_dbg("%s called\n", __func__);
+
+	rc = check_device_status(priv);
+	if (rc < 0)
+		return rc;
+
+	if (priv->ctrl.mts && !(type & FM))
+		type |= MTS;
+
+retry:
+	new_fw.type = type;
+	new_fw.id = std;
+	new_fw.std_req = std;
+	new_fw.scode_table = SCODE | priv->ctrl.scode_table;
+	new_fw.scode_nr = 0;
+	new_fw.int_freq = int_freq;
+
+	tuner_dbg("checking firmware, user requested type=");
+	if (debug) {
+		dump_firm_type(new_fw.type);
+		printk("(%x), id %016llx, ", new_fw.type,
+		       (unsigned long long)new_fw.std_req);
+		if (!int_freq) {
+			printk("scode_tbl ");
+			dump_firm_type(priv->ctrl.scode_table);
+			printk("(%x), ", priv->ctrl.scode_table);
+		} else
+			printk("int_freq %d, ", new_fw.int_freq);
+		printk("scode_nr %d\n", new_fw.scode_nr);
+	}
+
+	/*
+	 * No need to reload base firmware if it matches and if the tuner
+	 * is not at sleep mode
+	 */
+	if ((priv->state == XC2028_ACTIVE) &&
+	    (((BASE | new_fw.type) & BASE_TYPES) ==
+	    (priv->cur_fw.type & BASE_TYPES))) {
+		tuner_dbg("BASE firmware not changed.\n");
+		goto skip_base;
+	}
+
+	/* Updating BASE - forget about all currently loaded firmware */
+	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+
+	/* Reset is needed before loading firmware */
+	rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
+	if (rc < 0)
+		goto fail;
+
+	/* BASE firmwares are all std0 */
+	std0 = 0;
+	rc = load_firmware(fe, BASE | new_fw.type, &std0);
+	if (rc < 0) {
+		tuner_err("Error %d while loading base firmware\n",
+			  rc);
+		goto fail;
+	}
+
+	/* Load INIT1, if needed */
+	tuner_dbg("Load init1 firmware, if exists\n");
+
+	rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0);
+	if (rc == -ENOENT)
+		rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ,
+				   &std0);
+	if (rc < 0 && rc != -ENOENT) {
+		tuner_err("Error %d while loading init1 firmware\n",
+			  rc);
+		goto fail;
+	}
+
+skip_base:
+	/*
+	 * No need to reload standard specific firmware if base firmware
+	 * was not reloaded and requested video standards have not changed.
+	 */
+	if (priv->cur_fw.type == (BASE | new_fw.type) &&
+	    priv->cur_fw.std_req == std) {
+		tuner_dbg("Std-specific firmware already loaded.\n");
+		goto skip_std_specific;
+	}
+
+	/* Reloading std-specific firmware forces a SCODE update */
+	priv->cur_fw.scode_table = 0;
+
+	rc = load_firmware(fe, new_fw.type, &new_fw.id);
+	if (rc == -ENOENT)
+		rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id);
+
+	if (rc < 0)
+		goto fail;
+
+skip_std_specific:
+	if (priv->cur_fw.scode_table == new_fw.scode_table &&
+	    priv->cur_fw.scode_nr == new_fw.scode_nr) {
+		tuner_dbg("SCODE firmware already loaded.\n");
+		goto check_device;
+	}
+
+	if (new_fw.type & FM)
+		goto check_device;
+
+	/* Load SCODE firmware, if exists */
+	tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr);
+
+	rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
+			new_fw.int_freq, new_fw.scode_nr);
+
+check_device:
+	if (xc2028_get_reg(priv, 0x0004, &version) < 0 ||
+	    xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) {
+		tuner_err("Unable to read tuner registers.\n");
+		goto fail;
+	}
+
+	tuner_dbg("Device is Xceive %d version %d.%d, "
+		  "firmware version %d.%d\n",
+		  hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
+		  (version & 0xf0) >> 4, version & 0xf);
+
+
+	if (priv->ctrl.read_not_reliable)
+		goto read_not_reliable;
+
+	/* Check firmware version against what we downloaded. */
+	if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) {
+		if (!priv->ctrl.read_not_reliable) {
+			tuner_err("Incorrect readback of firmware version.\n");
+			goto fail;
+		} else {
+			tuner_err("Returned an incorrect version. However, "
+				  "read is not reliable enough. Ignoring it.\n");
+			hwmodel = 3028;
+		}
+	}
+
+	/* Check that the tuner hardware model remains consistent over time. */
+	if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) {
+		priv->hwmodel = hwmodel;
+		priv->hwvers  = version & 0xff00;
+	} else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
+		   priv->hwvers != (version & 0xff00)) {
+		tuner_err("Read invalid device hardware information - tuner "
+			  "hung?\n");
+		goto fail;
+	}
+
+read_not_reliable:
+	memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
+
+	/*
+	 * By setting BASE in cur_fw.type only after successfully loading all
+	 * firmwares, we can:
+	 * 1. Identify that BASE firmware with type=0 has been loaded;
+	 * 2. Tell whether BASE firmware was just changed the next time through.
+	 */
+	priv->cur_fw.type |= BASE;
+	priv->state = XC2028_ACTIVE;
+
+	return 0;
+
+fail:
+	priv->state = XC2028_SLEEP;
+
+	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+	if (retry_count < 8) {
+		msleep(50);
+		retry_count++;
+		tuner_dbg("Retrying firmware load\n");
+		goto retry;
+	}
+
+	if (rc == -ENOENT)
+		rc = -EINVAL;
+	return rc;
+}
+
+static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	u16                 frq_lock, signal = 0;
+	int                 rc, i;
+
+	tuner_dbg("%s called\n", __func__);
+
+	rc = check_device_status(priv);
+	if (rc < 0)
+		return rc;
+
+	mutex_lock(&priv->lock);
+
+	/* Sync Lock Indicator */
+	for (i = 0; i < 3; i++) {
+		rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
+		if (rc < 0)
+			goto ret;
+
+		if (frq_lock)
+			break;
+		msleep(6);
+	}
+
+	/* Frequency didn't lock */
+	if (frq_lock == 2)
+		goto ret;
+
+	/* Get SNR of the video signal */
+	rc = xc2028_get_reg(priv, XREG_SNR, &signal);
+	if (rc < 0)
+		goto ret;
+
+	/* Signal level is 3 bits only */
+
+	signal = ((1 << 12) - 1) | ((signal & 0x07) << 12);
+
+ret:
+	mutex_unlock(&priv->lock);
+
+	*strength = signal;
+
+	tuner_dbg("signal strength is %d\n", signal);
+
+	return rc;
+}
+
+static int xc2028_get_afc(struct dvb_frontend *fe, s32 *afc)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	int i, rc;
+	u16 frq_lock = 0;
+	s16 afc_reg = 0;
+
+	rc = check_device_status(priv);
+	if (rc < 0)
+		return rc;
+
+	mutex_lock(&priv->lock);
+
+	/* Sync Lock Indicator */
+	for (i = 0; i < 3; i++) {
+		rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
+		if (rc < 0)
+			goto ret;
+
+		if (frq_lock)
+			break;
+		msleep(6);
+	}
+
+	/* Frequency didn't lock */
+	if (frq_lock == 2)
+		goto ret;
+
+	/* Get AFC */
+	rc = xc2028_get_reg(priv, XREG_FREQ_ERROR, &afc_reg);
+	if (rc < 0)
+		goto ret;
+
+	*afc = afc_reg * 15625; /* Hz */
+
+	tuner_dbg("AFC is %d Hz\n", *afc);
+
+ret:
+	mutex_unlock(&priv->lock);
+
+	return rc;
+}
+
+#define DIV 15625
+
+static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
+			    enum v4l2_tuner_type new_type,
+			    unsigned int type,
+			    v4l2_std_id std,
+			    u16 int_freq)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	int		   rc = -EINVAL;
+	unsigned char	   buf[4];
+	u32		   div, offset = 0;
+
+	tuner_dbg("%s called\n", __func__);
+
+	mutex_lock(&priv->lock);
+
+	tuner_dbg("should set frequency %d kHz\n", freq / 1000);
+
+	if (check_firmware(fe, type, std, int_freq) < 0)
+		goto ret;
+
+	/* On some cases xc2028 can disable video output, if
+	 * very weak signals are received. By sending a soft
+	 * reset, this is re-enabled. So, it is better to always
+	 * send a soft reset before changing channels, to be sure
+	 * that xc2028 will be in a safe state.
+	 * Maybe this might also be needed for DTV.
+	 */
+	switch (new_type) {
+	case V4L2_TUNER_ANALOG_TV:
+		rc = send_seq(priv, {0x00, 0x00});
+
+		/* Analog mode requires offset = 0 */
+		break;
+	case V4L2_TUNER_RADIO:
+		/* Radio mode requires offset = 0 */
+		break;
+	case V4L2_TUNER_DIGITAL_TV:
+		/*
+		 * Digital modes require an offset to adjust to the
+		 * proper frequency. The offset depends on what
+		 * firmware version is used.
+		 */
+
+		/*
+		 * Adjust to the center frequency. This is calculated by the
+		 * formula: offset = 1.25MHz - BW/2
+		 * For DTV 7/8, the firmware uses BW = 8000, so it needs a
+		 * further adjustment to get the frequency center on VHF
+		 */
+
+		/*
+		 * The firmware DTV78 used to work fine in UHF band (8 MHz
+		 * bandwidth) but not at all in VHF band (7 MHz bandwidth).
+		 * The real problem was connected to the formula used to
+		 * calculate the center frequency offset in VHF band.
+		 * In fact, removing the 500KHz adjustment fixed the problem.
+		 * This is coherent to what was implemented for the DTV7
+		 * firmware.
+		 * In the end, now the center frequency is the same for all 3
+		 * firmwares (DTV7, DTV8, DTV78) and doesn't depend on channel
+		 * bandwidth.
+		 */
+
+		if (priv->cur_fw.type & DTV6)
+			offset = 1750000;
+		else	/* DTV7 or DTV8 or DTV78 */
+			offset = 2750000;
+
+		/*
+		 * xc3028 additional "magic"
+		 * Depending on the firmware version, it needs some adjustments
+		 * to properly centralize the frequency. This seems to be
+		 * needed to compensate the SCODE table adjustments made by
+		 * newer firmwares
+		 */
+
+		/*
+		 * The proper adjustment would be to do it at s-code table.
+		 * However, this didn't work, as reported by
+		 * Robert Lowery <rglowery@exemail.com.au>
+		 */
+
+#if 0
+		/*
+		 * Still need tests for XC3028L (firmware 3.2 or upper)
+		 * So, for now, let's just comment the per-firmware
+		 * version of this change. Reports with xc3028l working
+		 * with and without the lines bellow are welcome
+		 */
+
+		if (priv->firm_version < 0x0302) {
+			if (priv->cur_fw.type & DTV7)
+				offset += 500000;
+		} else {
+			if (priv->cur_fw.type & DTV7)
+				offset -= 300000;
+			else if (type != ATSC) /* DVB @6MHz, DTV 8 and DTV 7/8 */
+				offset += 200000;
+		}
+#endif
+	}
+
+	div = (freq - offset + DIV / 2) / DIV;
+
+	/* CMD= Set frequency */
+	if (priv->firm_version < 0x0202)
+		rc = send_seq(priv, {0x00, XREG_RF_FREQ, 0x00, 0x00});
+	else
+		rc = send_seq(priv, {0x80, XREG_RF_FREQ, 0x00, 0x00});
+	if (rc < 0)
+		goto ret;
+
+	/* Return code shouldn't be checked.
+	   The reset CLK is needed only with tm6000.
+	   Driver should work fine even if this fails.
+	 */
+	if (priv->ctrl.msleep)
+		msleep(priv->ctrl.msleep);
+	do_tuner_callback(fe, XC2028_RESET_CLK, 1);
+
+	msleep(10);
+
+	buf[0] = 0xff & (div >> 24);
+	buf[1] = 0xff & (div >> 16);
+	buf[2] = 0xff & (div >> 8);
+	buf[3] = 0xff & (div);
+
+	rc = i2c_send(priv, buf, sizeof(buf));
+	if (rc < 0)
+		goto ret;
+	msleep(100);
+
+	priv->frequency = freq;
+
+	tuner_dbg("divisor= %*ph (freq=%d.%03d)\n", 4, buf,
+	       freq / 1000000, (freq % 1000000) / 1000);
+
+	rc = 0;
+
+ret:
+	mutex_unlock(&priv->lock);
+
+	return rc;
+}
+
+static int xc2028_set_analog_freq(struct dvb_frontend *fe,
+			      struct analog_parameters *p)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	unsigned int       type=0;
+
+	tuner_dbg("%s called\n", __func__);
+
+	if (p->mode == V4L2_TUNER_RADIO) {
+		type |= FM;
+		if (priv->ctrl.input1)
+			type |= INPUT1;
+		return generic_set_freq(fe, (625l * p->frequency) / 10,
+				V4L2_TUNER_RADIO, type, 0, 0);
+	}
+
+	/* if std is not defined, choose one */
+	if (!p->std)
+		p->std = V4L2_STD_MN;
+
+	/* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */
+	if (!(p->std & V4L2_STD_MN))
+		type |= F8MHZ;
+
+	/* Add audio hack to std mask */
+	p->std |= parse_audio_std_option();
+
+	return generic_set_freq(fe, 62500l * p->frequency,
+				V4L2_TUNER_ANALOG_TV, type, p->std, 0);
+}
+
+static int xc2028_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 delsys = c->delivery_system;
+	u32 bw = c->bandwidth_hz;
+	struct xc2028_data *priv = fe->tuner_priv;
+	int rc;
+	unsigned int       type = 0;
+	u16                demod = 0;
+
+	tuner_dbg("%s called\n", __func__);
+
+	rc = check_device_status(priv);
+	if (rc < 0)
+		return rc;
+
+	switch (delsys) {
+	case SYS_DVBT:
+	case SYS_DVBT2:
+		/*
+		 * The only countries with 6MHz seem to be Taiwan/Uruguay.
+		 * Both seem to require QAM firmware for OFDM decoding
+		 * Tested in Taiwan by Terry Wu <terrywu2009@gmail.com>
+		 */
+		if (bw <= 6000000)
+			type |= QAM;
+
+		switch (priv->ctrl.type) {
+		case XC2028_D2633:
+			type |= D2633;
+			break;
+		case XC2028_D2620:
+			type |= D2620;
+			break;
+		case XC2028_AUTO:
+		default:
+			/* Zarlink seems to need D2633 */
+			if (priv->ctrl.demod == XC3028_FE_ZARLINK456)
+				type |= D2633;
+			else
+				type |= D2620;
+		}
+		break;
+	case SYS_ATSC:
+		/* The only ATSC firmware (at least on v2.7) is D2633 */
+		type |= ATSC | D2633;
+		break;
+	/* DVB-S and pure QAM (FE_QAM) are not supported */
+	default:
+		return -EINVAL;
+	}
+
+	if (bw <= 6000000) {
+		type |= DTV6;
+		priv->ctrl.vhfbw7 = 0;
+		priv->ctrl.uhfbw8 = 0;
+	} else if (bw <= 7000000) {
+		if (c->frequency < 470000000)
+			priv->ctrl.vhfbw7 = 1;
+		else
+			priv->ctrl.uhfbw8 = 0;
+		type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7;
+		type |= F8MHZ;
+	} else {
+		if (c->frequency < 470000000)
+			priv->ctrl.vhfbw7 = 0;
+		else
+			priv->ctrl.uhfbw8 = 1;
+		type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8;
+		type |= F8MHZ;
+	}
+
+	/* All S-code tables need a 200kHz shift */
+	if (priv->ctrl.demod) {
+		demod = priv->ctrl.demod;
+
+		/*
+		 * Newer firmwares require a 200 kHz offset only for ATSC
+		 */
+		if (type == ATSC || priv->firm_version < 0x0302)
+			demod += 200;
+		/*
+		 * The DTV7 S-code table needs a 700 kHz shift.
+		 *
+		 * DTV7 is only used in Australia.  Germany or Italy may also
+		 * use this firmware after initialization, but a tune to a UHF
+		 * channel should then cause DTV78 to be used.
+		 *
+		 * Unfortunately, on real-field tests, the s-code offset
+		 * didn't work as expected, as reported by
+		 * Robert Lowery <rglowery@exemail.com.au>
+		 */
+	}
+
+	return generic_set_freq(fe, c->frequency,
+				V4L2_TUNER_DIGITAL_TV, type, 0, demod);
+}
+
+static int xc2028_sleep(struct dvb_frontend *fe)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	int rc;
+
+	rc = check_device_status(priv);
+	if (rc < 0)
+		return rc;
+
+	/* Avoid firmware reload on slow devices or if PM disabled */
+	if (no_poweroff || priv->ctrl.disable_power_mgmt)
+		return 0;
+
+	tuner_dbg("Putting xc2028/3028 into poweroff mode.\n");
+	if (debug > 1) {
+		tuner_dbg("Printing sleep stack trace:\n");
+		dump_stack();
+	}
+
+	mutex_lock(&priv->lock);
+
+	if (priv->firm_version < 0x0202)
+		rc = send_seq(priv, {0x00, XREG_POWER_DOWN, 0x00, 0x00});
+	else
+		rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00});
+
+	priv->state = XC2028_SLEEP;
+
+	mutex_unlock(&priv->lock);
+
+	return rc;
+}
+
+static int xc2028_dvb_release(struct dvb_frontend *fe)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+
+	tuner_dbg("%s called\n", __func__);
+
+	mutex_lock(&xc2028_list_mutex);
+
+	/* only perform final cleanup if this is the last instance */
+	if (hybrid_tuner_report_instance_count(priv) == 1) {
+		free_firmware(priv);
+		kfree(priv->ctrl.fname);
+		priv->ctrl.fname = NULL;
+	}
+
+	if (priv)
+		hybrid_tuner_release_state(priv);
+
+	mutex_unlock(&xc2028_list_mutex);
+
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	int rc;
+
+	tuner_dbg("%s called\n", __func__);
+
+	rc = check_device_status(priv);
+	if (rc < 0)
+		return rc;
+
+	*frequency = priv->frequency;
+
+	return 0;
+}
+
+static void load_firmware_cb(const struct firmware *fw,
+			     void *context)
+{
+	struct dvb_frontend *fe = context;
+	struct xc2028_data *priv = fe->tuner_priv;
+	int rc;
+
+	tuner_dbg("request_firmware_nowait(): %s\n", fw ? "OK" : "error");
+	if (!fw) {
+		tuner_err("Could not load firmware %s.\n", priv->fname);
+		priv->state = XC2028_NODEV;
+		return;
+	}
+
+	rc = load_all_firmwares(fe, fw);
+
+	release_firmware(fw);
+
+	if (rc < 0)
+		return;
+	priv->state = XC2028_SLEEP;
+}
+
+static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	struct xc2028_ctrl *p    = priv_cfg;
+	int                 rc   = 0;
+
+	tuner_dbg("%s called\n", __func__);
+
+	mutex_lock(&priv->lock);
+
+	/*
+	 * Copy the config data.
+	 * For the firmware name, keep a local copy of the string,
+	 * in order to avoid troubles during device release.
+	 */
+	if (priv->ctrl.fname)
+		kfree(priv->ctrl.fname);
+	memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
+	if (p->fname) {
+		priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
+		if (priv->ctrl.fname == NULL)
+			rc = -ENOMEM;
+	}
+
+	/*
+	 * If firmware name changed, frees firmware. As free_firmware will
+	 * reset the status to NO_FIRMWARE, this forces a new request_firmware
+	 */
+	if (!firmware_name[0] && p->fname &&
+	    priv->fname && strcmp(p->fname, priv->fname))
+		free_firmware(priv);
+
+	if (priv->ctrl.max_len < 9)
+		priv->ctrl.max_len = 13;
+
+	if (priv->state == XC2028_NO_FIRMWARE) {
+		if (!firmware_name[0])
+			priv->fname = priv->ctrl.fname;
+		else
+			priv->fname = firmware_name;
+
+		rc = request_firmware_nowait(THIS_MODULE, 1,
+					     priv->fname,
+					     priv->i2c_props.adap->dev.parent,
+					     GFP_KERNEL,
+					     fe, load_firmware_cb);
+		if (rc < 0) {
+			tuner_err("Failed to request firmware %s\n",
+				  priv->fname);
+			priv->state = XC2028_NODEV;
+		} else
+			priv->state = XC2028_WAITING_FIRMWARE;
+	}
+	mutex_unlock(&priv->lock);
+
+	return rc;
+}
+
+static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
+	.info = {
+		 .name = "Xceive XC3028",
+		 .frequency_min = 42000000,
+		 .frequency_max = 864000000,
+		 .frequency_step = 50000,
+		 },
+
+	.set_config	   = xc2028_set_config,
+	.set_analog_params = xc2028_set_analog_freq,
+	.release           = xc2028_dvb_release,
+	.get_frequency     = xc2028_get_frequency,
+	.get_rf_strength   = xc2028_signal,
+	.get_afc           = xc2028_get_afc,
+	.set_params        = xc2028_set_params,
+	.sleep             = xc2028_sleep,
+};
+
+struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
+				   struct xc2028_config *cfg)
+{
+	struct xc2028_data *priv;
+	int instance;
+
+	if (debug)
+		printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n");
+
+	if (NULL == cfg)
+		return NULL;
+
+	if (!fe) {
+		printk(KERN_ERR "xc2028: No frontend!\n");
+		return NULL;
+	}
+
+	mutex_lock(&xc2028_list_mutex);
+
+	instance = hybrid_tuner_request_state(struct xc2028_data, priv,
+					      hybrid_tuner_instance_list,
+					      cfg->i2c_adap, cfg->i2c_addr,
+					      "xc2028");
+	switch (instance) {
+	case 0:
+		/* memory allocation failure */
+		goto fail;
+		break;
+	case 1:
+		/* new tuner instance */
+		priv->ctrl.max_len = 13;
+
+		mutex_init(&priv->lock);
+
+		fe->tuner_priv = priv;
+		break;
+	case 2:
+		/* existing tuner instance */
+		fe->tuner_priv = priv;
+		break;
+	}
+
+	memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
+	       sizeof(xc2028_dvb_tuner_ops));
+
+	tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner");
+
+	if (cfg->ctrl)
+		xc2028_set_config(fe, cfg->ctrl);
+
+	mutex_unlock(&xc2028_list_mutex);
+
+	return fe;
+fail:
+	mutex_unlock(&xc2028_list_mutex);
+
+	xc2028_dvb_release(fe);
+	return NULL;
+}
+
+EXPORT_SYMBOL(xc2028_attach);
+
+MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver");
+MODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE);
+MODULE_FIRMWARE(XC3028L_DEFAULT_FIRMWARE);
diff --git a/drivers/media/tuners/tuner-xc2028.h b/drivers/media/tuners/tuner-xc2028.h
new file mode 100644
index 0000000..9ebfb2d
--- /dev/null
+++ b/drivers/media/tuners/tuner-xc2028.h
@@ -0,0 +1,72 @@
+/* tuner-xc2028
+ *
+ * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
+#ifndef __TUNER_XC2028_H__
+#define __TUNER_XC2028_H__
+
+#include "dvb_frontend.h"
+
+#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw"
+#define XC3028L_DEFAULT_FIRMWARE "xc3028L-v36.fw"
+
+/*      Dmoduler		IF (kHz) */
+#define	XC3028_FE_DEFAULT	0		/* Don't load SCODE */
+#define XC3028_FE_LG60		6000
+#define	XC3028_FE_ATI638	6380
+#define	XC3028_FE_OREN538	5380
+#define	XC3028_FE_OREN36	3600
+#define	XC3028_FE_TOYOTA388	3880
+#define	XC3028_FE_TOYOTA794	7940
+#define	XC3028_FE_DIBCOM52	5200
+#define	XC3028_FE_ZARLINK456	4560
+#define	XC3028_FE_CHINA		5200
+
+enum firmware_type {
+	XC2028_AUTO = 0,        /* By default, auto-detects */
+	XC2028_D2633,
+	XC2028_D2620,
+};
+
+struct xc2028_ctrl {
+	char			*fname;
+	int			max_len;
+	int			msleep;
+	unsigned int		scode_table;
+	unsigned int		mts   :1;
+	unsigned int		input1:1;
+	unsigned int		vhfbw7:1;
+	unsigned int		uhfbw8:1;
+	unsigned int		disable_power_mgmt:1;
+	unsigned int            read_not_reliable:1;
+	unsigned int		demod;
+	enum firmware_type	type:2;
+};
+
+struct xc2028_config {
+	struct i2c_adapter *i2c_adap;
+	u8 		   i2c_addr;
+	struct xc2028_ctrl *ctrl;
+};
+
+/* xc2028 commands for callback */
+#define XC2028_TUNER_RESET	0
+#define XC2028_RESET_CLK	1
+#define XC2028_I2C_FLUSH	2
+
+#if defined(CONFIG_MEDIA_TUNER_XC2028) || (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE))
+extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
+					  struct xc2028_config *cfg);
+#else
+static inline struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
+						 struct xc2028_config *cfg)
+{
+	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+	       __func__);
+	return NULL;
+}
+#endif
+
+#endif /* __TUNER_XC2028_H__ */
diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c
new file mode 100644
index 0000000..4937712
--- /dev/null
+++ b/drivers/media/tuners/xc4000.c
@@ -0,0 +1,1757 @@
+/*
+ *  Driver for Xceive XC4000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Xceive Corporation
+ *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
+ *  Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *  Copyright (c) 2009 Davide Ferri <d.ferri@zero11.it>
+ *  Copyright (c) 2010 Istvan Varga <istvan_v@mailbox.hu>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <asm/unaligned.h>
+
+#include "dvb_frontend.h"
+
+#include "xc4000.h"
+#include "tuner-i2c.h"
+#include "tuner-xc2028-types.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debugging level (0 to 2, default: 0 (off)).");
+
+static int no_poweroff;
+module_param(no_poweroff, int, 0644);
+MODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, "
+	"0 (default): use device-specific default mode).");
+
+static int audio_std;
+module_param(audio_std, int, 0644);
+MODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly "
+	"needs to know what audio standard is needed for some video standards "
+	"with audio A2 or NICAM. The valid settings are a sum of:\n"
+	" 1: use NICAM/B or A2/B instead of NICAM/A or A2/A\n"
+	" 2: use A2 instead of NICAM or BTSC\n"
+	" 4: use SECAM/K3 instead of K1\n"
+	" 8: use PAL-D/K audio for SECAM-D/K\n"
+	"16: use FM radio input 1 instead of input 2\n"
+	"32: use mono audio (the lower three bits are ignored)");
+
+static char firmware_name[30];
+module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
+MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
+	"default firmware name.");
+
+static DEFINE_MUTEX(xc4000_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
+#define dprintk(level, fmt, arg...) if (debug >= level) \
+	printk(KERN_INFO "%s: " fmt, "xc4000", ## arg)
+
+/* struct for storing firmware table */
+struct firmware_description {
+	unsigned int  type;
+	v4l2_std_id   id;
+	__u16         int_freq;
+	unsigned char *ptr;
+	unsigned int  size;
+};
+
+struct firmware_properties {
+	unsigned int	type;
+	v4l2_std_id	id;
+	v4l2_std_id	std_req;
+	__u16		int_freq;
+	unsigned int	scode_table;
+	int		scode_nr;
+};
+
+struct xc4000_priv {
+	struct tuner_i2c_props i2c_props;
+	struct list_head hybrid_tuner_instance_list;
+	struct firmware_description *firm;
+	int	firm_size;
+	u32	if_khz;
+	u32	freq_hz;
+	u32	bandwidth;
+	u8	video_standard;
+	u8	rf_mode;
+	u8	default_pm;
+	u8	dvb_amplitude;
+	u8	set_smoothedcvbs;
+	u8	ignore_i2c_write_errors;
+	__u16	firm_version;
+	struct firmware_properties cur_fw;
+	__u16	hwmodel;
+	__u16	hwvers;
+	struct mutex	lock;
+};
+
+#define XC4000_AUDIO_STD_B		 1
+#define XC4000_AUDIO_STD_A2		 2
+#define XC4000_AUDIO_STD_K3		 4
+#define XC4000_AUDIO_STD_L		 8
+#define XC4000_AUDIO_STD_INPUT1		16
+#define XC4000_AUDIO_STD_MONO		32
+
+#define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.fw"
+
+/* Misc Defines */
+#define MAX_TV_STANDARD			24
+#define XC_MAX_I2C_WRITE_LENGTH		64
+#define XC_POWERED_DOWN			0x80000000U
+
+/* Signal Types */
+#define XC_RF_MODE_AIR			0
+#define XC_RF_MODE_CABLE		1
+
+/* Product id */
+#define XC_PRODUCT_ID_FW_NOT_LOADED	0x2000
+#define XC_PRODUCT_ID_XC4000		0x0FA0
+#define XC_PRODUCT_ID_XC4100		0x1004
+
+/* Registers (Write-only) */
+#define XREG_INIT         0x00
+#define XREG_VIDEO_MODE   0x01
+#define XREG_AUDIO_MODE   0x02
+#define XREG_RF_FREQ      0x03
+#define XREG_D_CODE       0x04
+#define XREG_DIRECTSITTING_MODE 0x05
+#define XREG_SEEK_MODE    0x06
+#define XREG_POWER_DOWN   0x08
+#define XREG_SIGNALSOURCE 0x0A
+#define XREG_SMOOTHEDCVBS 0x0E
+#define XREG_AMPLITUDE    0x10
+
+/* Registers (Read-only) */
+#define XREG_ADC_ENV      0x00
+#define XREG_QUALITY      0x01
+#define XREG_FRAME_LINES  0x02
+#define XREG_HSYNC_FREQ   0x03
+#define XREG_LOCK         0x04
+#define XREG_FREQ_ERROR   0x05
+#define XREG_SNR          0x06
+#define XREG_VERSION      0x07
+#define XREG_PRODUCT_ID   0x08
+#define XREG_SIGNAL_LEVEL 0x0A
+#define XREG_NOISE_LEVEL  0x0B
+
+/*
+   Basic firmware description. This will remain with
+   the driver for documentation purposes.
+
+   This represents an I2C firmware file encoded as a
+   string of unsigned char. Format is as follows:
+
+   char[0  ]=len0_MSB  -> len = len_MSB * 256 + len_LSB
+   char[1  ]=len0_LSB  -> length of first write transaction
+   char[2  ]=data0 -> first byte to be sent
+   char[3  ]=data1
+   char[4  ]=data2
+   char[   ]=...
+   char[M  ]=dataN  -> last byte to be sent
+   char[M+1]=len1_MSB  -> len = len_MSB * 256 + len_LSB
+   char[M+2]=len1_LSB  -> length of second write transaction
+   char[M+3]=data0
+   char[M+4]=data1
+   ...
+   etc.
+
+   The [len] value should be interpreted as follows:
+
+   len= len_MSB _ len_LSB
+   len=1111_1111_1111_1111   : End of I2C_SEQUENCE
+   len=0000_0000_0000_0000   : Reset command: Do hardware reset
+   len=0NNN_NNNN_NNNN_NNNN   : Normal transaction: number of bytes = {1:32767)
+   len=1WWW_WWWW_WWWW_WWWW   : Wait command: wait for {1:32767} ms
+
+   For the RESET and WAIT commands, the two following bytes will contain
+   immediately the length of the following transaction.
+*/
+
+struct XC_TV_STANDARD {
+	const char  *Name;
+	u16	    audio_mode;
+	u16	    video_mode;
+	u16	    int_freq;
+};
+
+/* Tuner standards */
+#define XC4000_MN_NTSC_PAL_BTSC		0
+#define XC4000_MN_NTSC_PAL_A2		1
+#define XC4000_MN_NTSC_PAL_EIAJ		2
+#define XC4000_MN_NTSC_PAL_Mono		3
+#define XC4000_BG_PAL_A2		4
+#define XC4000_BG_PAL_NICAM		5
+#define XC4000_BG_PAL_MONO		6
+#define XC4000_I_PAL_NICAM		7
+#define XC4000_I_PAL_NICAM_MONO		8
+#define XC4000_DK_PAL_A2		9
+#define XC4000_DK_PAL_NICAM		10
+#define XC4000_DK_PAL_MONO		11
+#define XC4000_DK_SECAM_A2DK1		12
+#define XC4000_DK_SECAM_A2LDK3		13
+#define XC4000_DK_SECAM_A2MONO		14
+#define XC4000_DK_SECAM_NICAM		15
+#define XC4000_L_SECAM_NICAM		16
+#define XC4000_LC_SECAM_NICAM		17
+#define XC4000_DTV6			18
+#define XC4000_DTV8			19
+#define XC4000_DTV7_8			20
+#define XC4000_DTV7			21
+#define XC4000_FM_Radio_INPUT2		22
+#define XC4000_FM_Radio_INPUT1		23
+
+static struct XC_TV_STANDARD xc4000_standard[MAX_TV_STANDARD] = {
+	{"M/N-NTSC/PAL-BTSC",	0x0000, 0x80A0, 4500},
+	{"M/N-NTSC/PAL-A2",	0x0000, 0x80A0, 4600},
+	{"M/N-NTSC/PAL-EIAJ",	0x0040, 0x80A0, 4500},
+	{"M/N-NTSC/PAL-Mono",	0x0078, 0x80A0, 4500},
+	{"B/G-PAL-A2",		0x0000, 0x8159, 5640},
+	{"B/G-PAL-NICAM",	0x0004, 0x8159, 5740},
+	{"B/G-PAL-MONO",	0x0078, 0x8159, 5500},
+	{"I-PAL-NICAM",		0x0080, 0x8049, 6240},
+	{"I-PAL-NICAM-MONO",	0x0078, 0x8049, 6000},
+	{"D/K-PAL-A2",		0x0000, 0x8049, 6380},
+	{"D/K-PAL-NICAM",	0x0080, 0x8049, 6200},
+	{"D/K-PAL-MONO",	0x0078, 0x8049, 6500},
+	{"D/K-SECAM-A2 DK1",	0x0000, 0x8049, 6340},
+	{"D/K-SECAM-A2 L/DK3",	0x0000, 0x8049, 6000},
+	{"D/K-SECAM-A2 MONO",	0x0078, 0x8049, 6500},
+	{"D/K-SECAM-NICAM",	0x0080, 0x8049, 6200},
+	{"L-SECAM-NICAM",	0x8080, 0x0009, 6200},
+	{"L'-SECAM-NICAM",	0x8080, 0x4009, 6200},
+	{"DTV6",		0x00C0, 0x8002,    0},
+	{"DTV8",		0x00C0, 0x800B,    0},
+	{"DTV7/8",		0x00C0, 0x801B,    0},
+	{"DTV7",		0x00C0, 0x8007,    0},
+	{"FM Radio-INPUT2",	0x0008, 0x9800, 10700},
+	{"FM Radio-INPUT1",	0x0008, 0x9000, 10700}
+};
+
+static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val);
+static int xc4000_tuner_reset(struct dvb_frontend *fe);
+static void xc_debug_dump(struct xc4000_priv *priv);
+
+static int xc_send_i2c_data(struct xc4000_priv *priv, u8 *buf, int len)
+{
+	struct i2c_msg msg = { .addr = priv->i2c_props.addr,
+			       .flags = 0, .buf = buf, .len = len };
+	if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
+		if (priv->ignore_i2c_write_errors == 0) {
+			printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n",
+			       len);
+			if (len == 4) {
+				printk(KERN_ERR "bytes %*ph\n", 4, buf);
+			}
+			return -EREMOTEIO;
+		}
+	}
+	return 0;
+}
+
+static int xc4000_tuner_reset(struct dvb_frontend *fe)
+{
+	struct xc4000_priv *priv = fe->tuner_priv;
+	int ret;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (fe->callback) {
+		ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+					   fe->dvb->priv :
+					   priv->i2c_props.adap->algo_data,
+					   DVB_FRONTEND_COMPONENT_TUNER,
+					   XC4000_TUNER_RESET, 0);
+		if (ret) {
+			printk(KERN_ERR "xc4000: reset failed\n");
+			return -EREMOTEIO;
+		}
+	} else {
+		printk(KERN_ERR "xc4000: no tuner reset callback function, "
+				"fatal\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int xc_write_reg(struct xc4000_priv *priv, u16 regAddr, u16 i2cData)
+{
+	u8 buf[4];
+	int result;
+
+	buf[0] = (regAddr >> 8) & 0xFF;
+	buf[1] = regAddr & 0xFF;
+	buf[2] = (i2cData >> 8) & 0xFF;
+	buf[3] = i2cData & 0xFF;
+	result = xc_send_i2c_data(priv, buf, 4);
+
+	return result;
+}
+
+static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
+{
+	struct xc4000_priv *priv = fe->tuner_priv;
+
+	int i, nbytes_to_send, result;
+	unsigned int len, pos, index;
+	u8 buf[XC_MAX_I2C_WRITE_LENGTH];
+
+	index = 0;
+	while ((i2c_sequence[index] != 0xFF) ||
+		(i2c_sequence[index + 1] != 0xFF)) {
+		len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
+		if (len == 0x0000) {
+			/* RESET command */
+			/* NOTE: this is ignored, as the reset callback was */
+			/* already called by check_firmware() */
+			index += 2;
+		} else if (len & 0x8000) {
+			/* WAIT command */
+			msleep(len & 0x7FFF);
+			index += 2;
+		} else {
+			/* Send i2c data whilst ensuring individual transactions
+			 * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
+			 */
+			index += 2;
+			buf[0] = i2c_sequence[index];
+			buf[1] = i2c_sequence[index + 1];
+			pos = 2;
+			while (pos < len) {
+				if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2)
+					nbytes_to_send =
+						XC_MAX_I2C_WRITE_LENGTH;
+				else
+					nbytes_to_send = (len - pos + 2);
+				for (i = 2; i < nbytes_to_send; i++) {
+					buf[i] = i2c_sequence[index + pos +
+						i - 2];
+				}
+				result = xc_send_i2c_data(priv, buf,
+					nbytes_to_send);
+
+				if (result != 0)
+					return result;
+
+				pos += nbytes_to_send - 2;
+			}
+			index += len;
+		}
+	}
+	return 0;
+}
+
+static int xc_set_tv_standard(struct xc4000_priv *priv,
+	u16 video_mode, u16 audio_mode)
+{
+	int ret;
+	dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode);
+	dprintk(1, "%s() Standard = %s\n",
+		__func__,
+		xc4000_standard[priv->video_standard].Name);
+
+	/* Don't complain when the request fails because of i2c stretching */
+	priv->ignore_i2c_write_errors = 1;
+
+	ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode);
+	if (ret == 0)
+		ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode);
+
+	priv->ignore_i2c_write_errors = 0;
+
+	return ret;
+}
+
+static int xc_set_signal_source(struct xc4000_priv *priv, u16 rf_mode)
+{
+	dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
+		rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
+
+	if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) {
+		rf_mode = XC_RF_MODE_CABLE;
+		printk(KERN_ERR
+			"%s(), Invalid mode, defaulting to CABLE",
+			__func__);
+	}
+	return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
+}
+
+static const struct dvb_tuner_ops xc4000_tuner_ops;
+
+static int xc_set_rf_frequency(struct xc4000_priv *priv, u32 freq_hz)
+{
+	u16 freq_code;
+
+	dprintk(1, "%s(%u)\n", __func__, freq_hz);
+
+	if ((freq_hz > xc4000_tuner_ops.info.frequency_max) ||
+	    (freq_hz < xc4000_tuner_ops.info.frequency_min))
+		return -EINVAL;
+
+	freq_code = (u16)(freq_hz / 15625);
+
+	/* WAS: Starting in firmware version 1.1.44, Xceive recommends using the
+	   FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
+	   only be used for fast scanning for channel lock) */
+	/* WAS: XREG_FINERFREQ */
+	return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
+}
+
+static int xc_get_adc_envelope(struct xc4000_priv *priv, u16 *adc_envelope)
+{
+	return xc4000_readreg(priv, XREG_ADC_ENV, adc_envelope);
+}
+
+static int xc_get_frequency_error(struct xc4000_priv *priv, u32 *freq_error_hz)
+{
+	int result;
+	u16 regData;
+	u32 tmp;
+
+	result = xc4000_readreg(priv, XREG_FREQ_ERROR, &regData);
+	if (result != 0)
+		return result;
+
+	tmp = (u32)regData & 0xFFFFU;
+	tmp = (tmp < 0x8000U ? tmp : 0x10000U - tmp);
+	(*freq_error_hz) = tmp * 15625;
+	return result;
+}
+
+static int xc_get_lock_status(struct xc4000_priv *priv, u16 *lock_status)
+{
+	return xc4000_readreg(priv, XREG_LOCK, lock_status);
+}
+
+static int xc_get_version(struct xc4000_priv *priv,
+	u8 *hw_majorversion, u8 *hw_minorversion,
+	u8 *fw_majorversion, u8 *fw_minorversion)
+{
+	u16 data;
+	int result;
+
+	result = xc4000_readreg(priv, XREG_VERSION, &data);
+	if (result != 0)
+		return result;
+
+	(*hw_majorversion) = (data >> 12) & 0x0F;
+	(*hw_minorversion) = (data >>  8) & 0x0F;
+	(*fw_majorversion) = (data >>  4) & 0x0F;
+	(*fw_minorversion) = data & 0x0F;
+
+	return 0;
+}
+
+static int xc_get_hsync_freq(struct xc4000_priv *priv, u32 *hsync_freq_hz)
+{
+	u16 regData;
+	int result;
+
+	result = xc4000_readreg(priv, XREG_HSYNC_FREQ, &regData);
+	if (result != 0)
+		return result;
+
+	(*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
+	return result;
+}
+
+static int xc_get_frame_lines(struct xc4000_priv *priv, u16 *frame_lines)
+{
+	return xc4000_readreg(priv, XREG_FRAME_LINES, frame_lines);
+}
+
+static int xc_get_quality(struct xc4000_priv *priv, u16 *quality)
+{
+	return xc4000_readreg(priv, XREG_QUALITY, quality);
+}
+
+static int xc_get_signal_level(struct xc4000_priv *priv, u16 *signal)
+{
+	return xc4000_readreg(priv, XREG_SIGNAL_LEVEL, signal);
+}
+
+static int xc_get_noise_level(struct xc4000_priv *priv, u16 *noise)
+{
+	return xc4000_readreg(priv, XREG_NOISE_LEVEL, noise);
+}
+
+static u16 xc_wait_for_lock(struct xc4000_priv *priv)
+{
+	u16	lock_state = 0;
+	int	watchdog_count = 40;
+
+	while ((lock_state == 0) && (watchdog_count > 0)) {
+		xc_get_lock_status(priv, &lock_state);
+		if (lock_state != 1) {
+			msleep(5);
+			watchdog_count--;
+		}
+	}
+	return lock_state;
+}
+
+static int xc_tune_channel(struct xc4000_priv *priv, u32 freq_hz)
+{
+	int	found = 1;
+	int	result;
+
+	dprintk(1, "%s(%u)\n", __func__, freq_hz);
+
+	/* Don't complain when the request fails because of i2c stretching */
+	priv->ignore_i2c_write_errors = 1;
+	result = xc_set_rf_frequency(priv, freq_hz);
+	priv->ignore_i2c_write_errors = 0;
+
+	if (result != 0)
+		return 0;
+
+	/* wait for lock only in analog TV mode */
+	if ((priv->cur_fw.type & (FM | DTV6 | DTV7 | DTV78 | DTV8)) == 0) {
+		if (xc_wait_for_lock(priv) != 1)
+			found = 0;
+	}
+
+	/* Wait for stats to stabilize.
+	 * Frame Lines needs two frame times after initial lock
+	 * before it is valid.
+	 */
+	msleep(debug ? 100 : 10);
+
+	if (debug)
+		xc_debug_dump(priv);
+
+	return found;
+}
+
+static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val)
+{
+	u8 buf[2] = { reg >> 8, reg & 0xff };
+	u8 bval[2] = { 0, 0 };
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->i2c_props.addr,
+			.flags = 0, .buf = &buf[0], .len = 2 },
+		{ .addr = priv->i2c_props.addr,
+			.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
+	};
+
+	if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
+		printk(KERN_ERR "xc4000: I2C read failed\n");
+		return -EREMOTEIO;
+	}
+
+	*val = (bval[0] << 8) | bval[1];
+	return 0;
+}
+
+#define dump_firm_type(t)	dump_firm_type_and_int_freq(t, 0)
+static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
+{
+	 if (type & BASE)
+		printk(KERN_CONT "BASE ");
+	 if (type & INIT1)
+		printk(KERN_CONT "INIT1 ");
+	 if (type & F8MHZ)
+		printk(KERN_CONT "F8MHZ ");
+	 if (type & MTS)
+		printk(KERN_CONT "MTS ");
+	 if (type & D2620)
+		printk(KERN_CONT "D2620 ");
+	 if (type & D2633)
+		printk(KERN_CONT "D2633 ");
+	 if (type & DTV6)
+		printk(KERN_CONT "DTV6 ");
+	 if (type & QAM)
+		printk(KERN_CONT "QAM ");
+	 if (type & DTV7)
+		printk(KERN_CONT "DTV7 ");
+	 if (type & DTV78)
+		printk(KERN_CONT "DTV78 ");
+	 if (type & DTV8)
+		printk(KERN_CONT "DTV8 ");
+	 if (type & FM)
+		printk(KERN_CONT "FM ");
+	 if (type & INPUT1)
+		printk(KERN_CONT "INPUT1 ");
+	 if (type & LCD)
+		printk(KERN_CONT "LCD ");
+	 if (type & NOGD)
+		printk(KERN_CONT "NOGD ");
+	 if (type & MONO)
+		printk(KERN_CONT "MONO ");
+	 if (type & ATSC)
+		printk(KERN_CONT "ATSC ");
+	 if (type & IF)
+		printk(KERN_CONT "IF ");
+	 if (type & LG60)
+		printk(KERN_CONT "LG60 ");
+	 if (type & ATI638)
+		printk(KERN_CONT "ATI638 ");
+	 if (type & OREN538)
+		printk(KERN_CONT "OREN538 ");
+	 if (type & OREN36)
+		printk(KERN_CONT "OREN36 ");
+	 if (type & TOYOTA388)
+		printk(KERN_CONT "TOYOTA388 ");
+	 if (type & TOYOTA794)
+		printk(KERN_CONT "TOYOTA794 ");
+	 if (type & DIBCOM52)
+		printk(KERN_CONT "DIBCOM52 ");
+	 if (type & ZARLINK456)
+		printk(KERN_CONT "ZARLINK456 ");
+	 if (type & CHINA)
+		printk(KERN_CONT "CHINA ");
+	 if (type & F6MHZ)
+		printk(KERN_CONT "F6MHZ ");
+	 if (type & INPUT2)
+		printk(KERN_CONT "INPUT2 ");
+	 if (type & SCODE)
+		printk(KERN_CONT "SCODE ");
+	 if (type & HAS_IF)
+		printk(KERN_CONT "HAS_IF_%d ", int_freq);
+}
+
+static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
+			 v4l2_std_id *id)
+{
+	struct xc4000_priv *priv = fe->tuner_priv;
+	int		i, best_i = -1;
+	unsigned int	best_nr_diffs = 255U;
+
+	if (!priv->firm) {
+		printk(KERN_ERR "Error! firmware not loaded\n");
+		return -EINVAL;
+	}
+
+	if (((type & ~SCODE) == 0) && (*id == 0))
+		*id = V4L2_STD_PAL;
+
+	/* Seek for generic video standard match */
+	for (i = 0; i < priv->firm_size; i++) {
+		v4l2_std_id	id_diff_mask =
+			(priv->firm[i].id ^ (*id)) & (*id);
+		unsigned int	type_diff_mask =
+			(priv->firm[i].type ^ type)
+			& (BASE_TYPES | DTV_TYPES | LCD | NOGD | MONO | SCODE);
+		unsigned int	nr_diffs;
+
+		if (type_diff_mask
+		    & (BASE | INIT1 | FM | DTV6 | DTV7 | DTV78 | DTV8 | SCODE))
+			continue;
+
+		nr_diffs = hweight64(id_diff_mask) + hweight32(type_diff_mask);
+		if (!nr_diffs)	/* Supports all the requested standards */
+			goto found;
+
+		if (nr_diffs < best_nr_diffs) {
+			best_nr_diffs = nr_diffs;
+			best_i = i;
+		}
+	}
+
+	/* FIXME: Would make sense to seek for type "hint" match ? */
+	if (best_i < 0) {
+		i = -ENOENT;
+		goto ret;
+	}
+
+	if (best_nr_diffs > 0U) {
+		printk(KERN_WARNING
+		       "Selecting best matching firmware (%u bits differ) for "
+		       "type=(%x), id %016llx:\n",
+		       best_nr_diffs, type, (unsigned long long)*id);
+		i = best_i;
+	}
+
+found:
+	*id = priv->firm[i].id;
+
+ret:
+	if (debug) {
+		printk(KERN_DEBUG "%s firmware for type=",
+		       (i < 0) ? "Can't find" : "Found");
+		dump_firm_type(type);
+		printk(KERN_DEBUG "(%x), id %016llx.\n", type, (unsigned long long)*id);
+	}
+	return i;
+}
+
+static int load_firmware(struct dvb_frontend *fe, unsigned int type,
+			 v4l2_std_id *id)
+{
+	struct xc4000_priv *priv = fe->tuner_priv;
+	int                pos, rc;
+	unsigned char      *p;
+
+	pos = seek_firmware(fe, type, id);
+	if (pos < 0)
+		return pos;
+
+	p = priv->firm[pos].ptr;
+
+	/* Don't complain when the request fails because of i2c stretching */
+	priv->ignore_i2c_write_errors = 1;
+
+	rc = xc_load_i2c_sequence(fe, p);
+
+	priv->ignore_i2c_write_errors = 0;
+
+	return rc;
+}
+
+static int xc4000_fwupload(struct dvb_frontend *fe)
+{
+	struct xc4000_priv *priv = fe->tuner_priv;
+	const struct firmware *fw   = NULL;
+	const unsigned char   *p, *endp;
+	int                   rc = 0;
+	int		      n, n_array;
+	char		      name[33];
+	const char	      *fname;
+
+	if (firmware_name[0] != '\0')
+		fname = firmware_name;
+	else
+		fname = XC4000_DEFAULT_FIRMWARE;
+
+	dprintk(1, "Reading firmware %s\n", fname);
+	rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent);
+	if (rc < 0) {
+		if (rc == -ENOENT)
+			printk(KERN_ERR "Error: firmware %s not found.\n", fname);
+		else
+			printk(KERN_ERR "Error %d while requesting firmware %s\n",
+			       rc, fname);
+
+		return rc;
+	}
+	p = fw->data;
+	endp = p + fw->size;
+
+	if (fw->size < sizeof(name) - 1 + 2 + 2) {
+		printk(KERN_ERR "Error: firmware file %s has invalid size!\n",
+		       fname);
+		goto corrupt;
+	}
+
+	memcpy(name, p, sizeof(name) - 1);
+	name[sizeof(name) - 1] = '\0';
+	p += sizeof(name) - 1;
+
+	priv->firm_version = get_unaligned_le16(p);
+	p += 2;
+
+	n_array = get_unaligned_le16(p);
+	p += 2;
+
+	dprintk(1, "Loading %d firmware images from %s, type: %s, ver %d.%d\n",
+		n_array, fname, name,
+		priv->firm_version >> 8, priv->firm_version & 0xff);
+
+	priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL);
+	if (priv->firm == NULL) {
+		printk(KERN_ERR "Not enough memory to load firmware file.\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	priv->firm_size = n_array;
+
+	n = -1;
+	while (p < endp) {
+		__u32 type, size;
+		v4l2_std_id id;
+		__u16 int_freq = 0;
+
+		n++;
+		if (n >= n_array) {
+			printk(KERN_ERR "More firmware images in file than "
+			       "were expected!\n");
+			goto corrupt;
+		}
+
+		/* Checks if there's enough bytes to read */
+		if (endp - p < sizeof(type) + sizeof(id) + sizeof(size))
+			goto header;
+
+		type = get_unaligned_le32(p);
+		p += sizeof(type);
+
+		id = get_unaligned_le64(p);
+		p += sizeof(id);
+
+		if (type & HAS_IF) {
+			int_freq = get_unaligned_le16(p);
+			p += sizeof(int_freq);
+			if (endp - p < sizeof(size))
+				goto header;
+		}
+
+		size = get_unaligned_le32(p);
+		p += sizeof(size);
+
+		if (!size || size > endp - p) {
+			printk(KERN_ERR "Firmware type (%x), id %llx is corrupted (size=%d, expected %d)\n",
+			       type, (unsigned long long)id,
+			       (unsigned)(endp - p), size);
+			goto corrupt;
+		}
+
+		priv->firm[n].ptr = kzalloc(size, GFP_KERNEL);
+		if (priv->firm[n].ptr == NULL) {
+			printk(KERN_ERR "Not enough memory to load firmware file.\n");
+			rc = -ENOMEM;
+			goto done;
+		}
+
+		if (debug) {
+			printk(KERN_DEBUG "Reading firmware type ");
+			dump_firm_type_and_int_freq(type, int_freq);
+			printk(KERN_DEBUG "(%x), id %llx, size=%d.\n",
+			       type, (unsigned long long)id, size);
+		}
+
+		memcpy(priv->firm[n].ptr, p, size);
+		priv->firm[n].type = type;
+		priv->firm[n].id   = id;
+		priv->firm[n].size = size;
+		priv->firm[n].int_freq = int_freq;
+
+		p += size;
+	}
+
+	if (n + 1 != priv->firm_size) {
+		printk(KERN_ERR "Firmware file is incomplete!\n");
+		goto corrupt;
+	}
+
+	goto done;
+
+header:
+	printk(KERN_ERR "Firmware header is incomplete!\n");
+corrupt:
+	rc = -EINVAL;
+	printk(KERN_ERR "Error: firmware file is corrupted!\n");
+
+done:
+	release_firmware(fw);
+	if (rc == 0)
+		dprintk(1, "Firmware files loaded.\n");
+
+	return rc;
+}
+
+static int load_scode(struct dvb_frontend *fe, unsigned int type,
+			 v4l2_std_id *id, __u16 int_freq, int scode)
+{
+	struct xc4000_priv *priv = fe->tuner_priv;
+	int		pos, rc;
+	unsigned char	*p;
+	u8		scode_buf[13];
+	u8		indirect_mode[5];
+
+	dprintk(1, "%s called int_freq=%d\n", __func__, int_freq);
+
+	if (!int_freq) {
+		pos = seek_firmware(fe, type, id);
+		if (pos < 0)
+			return pos;
+	} else {
+		for (pos = 0; pos < priv->firm_size; pos++) {
+			if ((priv->firm[pos].int_freq == int_freq) &&
+			    (priv->firm[pos].type & HAS_IF))
+				break;
+		}
+		if (pos == priv->firm_size)
+			return -ENOENT;
+	}
+
+	p = priv->firm[pos].ptr;
+
+	if (priv->firm[pos].size != 12 * 16 || scode >= 16)
+		return -EINVAL;
+	p += 12 * scode;
+
+	if (debug) {
+		tuner_info("Loading SCODE for type=");
+		dump_firm_type_and_int_freq(priv->firm[pos].type,
+					    priv->firm[pos].int_freq);
+		printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type,
+		       (unsigned long long)*id);
+	}
+
+	scode_buf[0] = 0x00;
+	memcpy(&scode_buf[1], p, 12);
+
+	/* Enter direct-mode */
+	rc = xc_write_reg(priv, XREG_DIRECTSITTING_MODE, 0);
+	if (rc < 0) {
+		printk(KERN_ERR "failed to put device into direct mode!\n");
+		return -EIO;
+	}
+
+	rc = xc_send_i2c_data(priv, scode_buf, 13);
+	if (rc != 0) {
+		/* Even if the send failed, make sure we set back to indirect
+		   mode */
+		printk(KERN_ERR "Failed to set scode %d\n", rc);
+	}
+
+	/* Switch back to indirect-mode */
+	memset(indirect_mode, 0, sizeof(indirect_mode));
+	indirect_mode[4] = 0x88;
+	xc_send_i2c_data(priv, indirect_mode, sizeof(indirect_mode));
+	msleep(10);
+
+	return 0;
+}
+
+static int check_firmware(struct dvb_frontend *fe, unsigned int type,
+			  v4l2_std_id std, __u16 int_freq)
+{
+	struct xc4000_priv         *priv = fe->tuner_priv;
+	struct firmware_properties new_fw;
+	int			   rc = 0, is_retry = 0;
+	u16			   hwmodel;
+	v4l2_std_id		   std0;
+	u8			   hw_major, hw_minor, fw_major, fw_minor;
+
+	dprintk(1, "%s called\n", __func__);
+
+	if (!priv->firm) {
+		rc = xc4000_fwupload(fe);
+		if (rc < 0)
+			return rc;
+	}
+
+retry:
+	new_fw.type = type;
+	new_fw.id = std;
+	new_fw.std_req = std;
+	new_fw.scode_table = SCODE;
+	new_fw.scode_nr = 0;
+	new_fw.int_freq = int_freq;
+
+	dprintk(1, "checking firmware, user requested type=");
+	if (debug) {
+		dump_firm_type(new_fw.type);
+		printk(KERN_CONT "(%x), id %016llx, ", new_fw.type,
+		       (unsigned long long)new_fw.std_req);
+		if (!int_freq)
+			printk(KERN_CONT "scode_tbl ");
+		else
+			printk(KERN_CONT "int_freq %d, ", new_fw.int_freq);
+		printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr);
+	}
+
+	/* No need to reload base firmware if it matches */
+	if (priv->cur_fw.type & BASE) {
+		dprintk(1, "BASE firmware not changed.\n");
+		goto skip_base;
+	}
+
+	/* Updating BASE - forget about all currently loaded firmware */
+	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+
+	/* Reset is needed before loading firmware */
+	rc = xc4000_tuner_reset(fe);
+	if (rc < 0)
+		goto fail;
+
+	/* BASE firmwares are all std0 */
+	std0 = 0;
+	rc = load_firmware(fe, BASE, &std0);
+	if (rc < 0) {
+		printk(KERN_ERR "Error %d while loading base firmware\n", rc);
+		goto fail;
+	}
+
+	/* Load INIT1, if needed */
+	dprintk(1, "Load init1 firmware, if exists\n");
+
+	rc = load_firmware(fe, BASE | INIT1, &std0);
+	if (rc == -ENOENT)
+		rc = load_firmware(fe, BASE | INIT1, &std0);
+	if (rc < 0 && rc != -ENOENT) {
+		tuner_err("Error %d while loading init1 firmware\n",
+			  rc);
+		goto fail;
+	}
+
+skip_base:
+	/*
+	 * No need to reload standard specific firmware if base firmware
+	 * was not reloaded and requested video standards have not changed.
+	 */
+	if (priv->cur_fw.type == (BASE | new_fw.type) &&
+	    priv->cur_fw.std_req == std) {
+		dprintk(1, "Std-specific firmware already loaded.\n");
+		goto skip_std_specific;
+	}
+
+	/* Reloading std-specific firmware forces a SCODE update */
+	priv->cur_fw.scode_table = 0;
+
+	/* Load the standard firmware */
+	rc = load_firmware(fe, new_fw.type, &new_fw.id);
+
+	if (rc < 0)
+		goto fail;
+
+skip_std_specific:
+	if (priv->cur_fw.scode_table == new_fw.scode_table &&
+	    priv->cur_fw.scode_nr == new_fw.scode_nr) {
+		dprintk(1, "SCODE firmware already loaded.\n");
+		goto check_device;
+	}
+
+	/* Load SCODE firmware, if exists */
+	rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
+			new_fw.int_freq, new_fw.scode_nr);
+	if (rc != 0)
+		dprintk(1, "load scode failed %d\n", rc);
+
+check_device:
+	rc = xc4000_readreg(priv, XREG_PRODUCT_ID, &hwmodel);
+
+	if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major,
+			   &fw_minor) != 0) {
+		printk(KERN_ERR "Unable to read tuner registers.\n");
+		goto fail;
+	}
+
+	dprintk(1, "Device is Xceive %d version %d.%d, "
+		"firmware version %d.%d\n",
+		hwmodel, hw_major, hw_minor, fw_major, fw_minor);
+
+	/* Check firmware version against what we downloaded. */
+	if (priv->firm_version != ((fw_major << 8) | fw_minor)) {
+		printk(KERN_WARNING
+		       "Incorrect readback of firmware version %d.%d.\n",
+		       fw_major, fw_minor);
+		goto fail;
+	}
+
+	/* Check that the tuner hardware model remains consistent over time. */
+	if (priv->hwmodel == 0 &&
+	    (hwmodel == XC_PRODUCT_ID_XC4000 ||
+	     hwmodel == XC_PRODUCT_ID_XC4100)) {
+		priv->hwmodel = hwmodel;
+		priv->hwvers = (hw_major << 8) | hw_minor;
+	} else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
+		   priv->hwvers != ((hw_major << 8) | hw_minor)) {
+		printk(KERN_WARNING
+		       "Read invalid device hardware information - tuner "
+		       "hung?\n");
+		goto fail;
+	}
+
+	memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
+
+	/*
+	 * By setting BASE in cur_fw.type only after successfully loading all
+	 * firmwares, we can:
+	 * 1. Identify that BASE firmware with type=0 has been loaded;
+	 * 2. Tell whether BASE firmware was just changed the next time through.
+	 */
+	priv->cur_fw.type |= BASE;
+
+	return 0;
+
+fail:
+	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+	if (!is_retry) {
+		msleep(50);
+		is_retry = 1;
+		dprintk(1, "Retrying firmware load\n");
+		goto retry;
+	}
+
+	if (rc == -ENOENT)
+		rc = -EINVAL;
+	return rc;
+}
+
+static void xc_debug_dump(struct xc4000_priv *priv)
+{
+	u16	adc_envelope;
+	u32	freq_error_hz = 0;
+	u16	lock_status;
+	u32	hsync_freq_hz = 0;
+	u16	frame_lines;
+	u16	quality;
+	u16	signal = 0;
+	u16	noise = 0;
+	u8	hw_majorversion = 0, hw_minorversion = 0;
+	u8	fw_majorversion = 0, fw_minorversion = 0;
+
+	xc_get_adc_envelope(priv, &adc_envelope);
+	dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
+
+	xc_get_frequency_error(priv, &freq_error_hz);
+	dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
+
+	xc_get_lock_status(priv, &lock_status);
+	dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
+		lock_status);
+
+	xc_get_version(priv, &hw_majorversion, &hw_minorversion,
+		       &fw_majorversion, &fw_minorversion);
+	dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
+		hw_majorversion, hw_minorversion,
+		fw_majorversion, fw_minorversion);
+
+	if (priv->video_standard < XC4000_DTV6) {
+		xc_get_hsync_freq(priv, &hsync_freq_hz);
+		dprintk(1, "*** Horizontal sync frequency = %d Hz\n",
+			hsync_freq_hz);
+
+		xc_get_frame_lines(priv, &frame_lines);
+		dprintk(1, "*** Frame lines = %d\n", frame_lines);
+	}
+
+	xc_get_quality(priv, &quality);
+	dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
+
+	xc_get_signal_level(priv, &signal);
+	dprintk(1, "*** Signal level = -%ddB (%d)\n", signal >> 8, signal);
+
+	xc_get_noise_level(priv, &noise);
+	dprintk(1, "*** Noise level = %ddB (%d)\n", noise >> 8, noise);
+}
+
+static int xc4000_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 delsys = c->delivery_system;
+	u32 bw = c->bandwidth_hz;
+	struct xc4000_priv *priv = fe->tuner_priv;
+	unsigned int type;
+	int	ret = -EREMOTEIO;
+
+	dprintk(1, "%s() frequency=%d (Hz)\n", __func__, c->frequency);
+
+	mutex_lock(&priv->lock);
+
+	switch (delsys) {
+	case SYS_ATSC:
+		dprintk(1, "%s() VSB modulation\n", __func__);
+		priv->rf_mode = XC_RF_MODE_AIR;
+		priv->freq_hz = c->frequency - 1750000;
+		priv->video_standard = XC4000_DTV6;
+		type = DTV6;
+		break;
+	case SYS_DVBC_ANNEX_B:
+		dprintk(1, "%s() QAM modulation\n", __func__);
+		priv->rf_mode = XC_RF_MODE_CABLE;
+		priv->freq_hz = c->frequency - 1750000;
+		priv->video_standard = XC4000_DTV6;
+		type = DTV6;
+		break;
+	case SYS_DVBT:
+	case SYS_DVBT2:
+		dprintk(1, "%s() OFDM\n", __func__);
+		if (bw == 0) {
+			if (c->frequency < 400000000) {
+				priv->freq_hz = c->frequency - 2250000;
+			} else {
+				priv->freq_hz = c->frequency - 2750000;
+			}
+			priv->video_standard = XC4000_DTV7_8;
+			type = DTV78;
+		} else if (bw <= 6000000) {
+			priv->video_standard = XC4000_DTV6;
+			priv->freq_hz = c->frequency - 1750000;
+			type = DTV6;
+		} else if (bw <= 7000000) {
+			priv->video_standard = XC4000_DTV7;
+			priv->freq_hz = c->frequency - 2250000;
+			type = DTV7;
+		} else {
+			priv->video_standard = XC4000_DTV8;
+			priv->freq_hz = c->frequency - 2750000;
+			type = DTV8;
+		}
+		priv->rf_mode = XC_RF_MODE_AIR;
+		break;
+	default:
+		printk(KERN_ERR "xc4000 delivery system not supported!\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	dprintk(1, "%s() frequency=%d (compensated)\n",
+		__func__, priv->freq_hz);
+
+	/* Make sure the correct firmware type is loaded */
+	if (check_firmware(fe, type, 0, priv->if_khz) != 0)
+		goto fail;
+
+	priv->bandwidth = c->bandwidth_hz;
+
+	ret = xc_set_signal_source(priv, priv->rf_mode);
+	if (ret != 0) {
+		printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n",
+		       priv->rf_mode);
+		goto fail;
+	} else {
+		u16	video_mode, audio_mode;
+		video_mode = xc4000_standard[priv->video_standard].video_mode;
+		audio_mode = xc4000_standard[priv->video_standard].audio_mode;
+		if (type == DTV6 && priv->firm_version != 0x0102)
+			video_mode |= 0x0001;
+		ret = xc_set_tv_standard(priv, video_mode, audio_mode);
+		if (ret != 0) {
+			printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n");
+			/* DJH - do not return when it fails... */
+			/* goto fail; */
+		}
+	}
+
+	if (xc_write_reg(priv, XREG_D_CODE, 0) == 0)
+		ret = 0;
+	if (priv->dvb_amplitude != 0) {
+		if (xc_write_reg(priv, XREG_AMPLITUDE,
+				 (priv->firm_version != 0x0102 ||
+				  priv->dvb_amplitude != 134 ?
+				  priv->dvb_amplitude : 132)) != 0)
+			ret = -EREMOTEIO;
+	}
+	if (priv->set_smoothedcvbs != 0) {
+		if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0)
+			ret = -EREMOTEIO;
+	}
+	if (ret != 0) {
+		printk(KERN_ERR "xc4000: setting registers failed\n");
+		/* goto fail; */
+	}
+
+	xc_tune_channel(priv, priv->freq_hz);
+
+	ret = 0;
+
+fail:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int xc4000_set_analog_params(struct dvb_frontend *fe,
+	struct analog_parameters *params)
+{
+	struct xc4000_priv *priv = fe->tuner_priv;
+	unsigned int type = 0;
+	int	ret = -EREMOTEIO;
+
+	if (params->mode == V4L2_TUNER_RADIO) {
+		dprintk(1, "%s() frequency=%d (in units of 62.5Hz)\n",
+			__func__, params->frequency);
+
+		mutex_lock(&priv->lock);
+
+		params->std = 0;
+		priv->freq_hz = params->frequency * 125L / 2;
+
+		if (audio_std & XC4000_AUDIO_STD_INPUT1) {
+			priv->video_standard = XC4000_FM_Radio_INPUT1;
+			type = FM | INPUT1;
+		} else {
+			priv->video_standard = XC4000_FM_Radio_INPUT2;
+			type = FM | INPUT2;
+		}
+
+		goto tune_channel;
+	}
+
+	dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
+		__func__, params->frequency);
+
+	mutex_lock(&priv->lock);
+
+	/* params->frequency is in units of 62.5khz */
+	priv->freq_hz = params->frequency * 62500;
+
+	params->std &= V4L2_STD_ALL;
+	/* if std is not defined, choose one */
+	if (!params->std)
+		params->std = V4L2_STD_PAL_BG;
+
+	if (audio_std & XC4000_AUDIO_STD_MONO)
+		type = MONO;
+
+	if (params->std & V4L2_STD_MN) {
+		params->std = V4L2_STD_MN;
+		if (audio_std & XC4000_AUDIO_STD_MONO) {
+			priv->video_standard = XC4000_MN_NTSC_PAL_Mono;
+		} else if (audio_std & XC4000_AUDIO_STD_A2) {
+			params->std |= V4L2_STD_A2;
+			priv->video_standard = XC4000_MN_NTSC_PAL_A2;
+		} else {
+			params->std |= V4L2_STD_BTSC;
+			priv->video_standard = XC4000_MN_NTSC_PAL_BTSC;
+		}
+		goto tune_channel;
+	}
+
+	if (params->std & V4L2_STD_PAL_BG) {
+		params->std = V4L2_STD_PAL_BG;
+		if (audio_std & XC4000_AUDIO_STD_MONO) {
+			priv->video_standard = XC4000_BG_PAL_MONO;
+		} else if (!(audio_std & XC4000_AUDIO_STD_A2)) {
+			if (!(audio_std & XC4000_AUDIO_STD_B)) {
+				params->std |= V4L2_STD_NICAM_A;
+				priv->video_standard = XC4000_BG_PAL_NICAM;
+			} else {
+				params->std |= V4L2_STD_NICAM_B;
+				priv->video_standard = XC4000_BG_PAL_NICAM;
+			}
+		} else {
+			if (!(audio_std & XC4000_AUDIO_STD_B)) {
+				params->std |= V4L2_STD_A2_A;
+				priv->video_standard = XC4000_BG_PAL_A2;
+			} else {
+				params->std |= V4L2_STD_A2_B;
+				priv->video_standard = XC4000_BG_PAL_A2;
+			}
+		}
+		goto tune_channel;
+	}
+
+	if (params->std & V4L2_STD_PAL_I) {
+		/* default to NICAM audio standard */
+		params->std = V4L2_STD_PAL_I | V4L2_STD_NICAM;
+		if (audio_std & XC4000_AUDIO_STD_MONO)
+			priv->video_standard = XC4000_I_PAL_NICAM_MONO;
+		else
+			priv->video_standard = XC4000_I_PAL_NICAM;
+		goto tune_channel;
+	}
+
+	if (params->std & V4L2_STD_PAL_DK) {
+		params->std = V4L2_STD_PAL_DK;
+		if (audio_std & XC4000_AUDIO_STD_MONO) {
+			priv->video_standard = XC4000_DK_PAL_MONO;
+		} else if (audio_std & XC4000_AUDIO_STD_A2) {
+			params->std |= V4L2_STD_A2;
+			priv->video_standard = XC4000_DK_PAL_A2;
+		} else {
+			params->std |= V4L2_STD_NICAM;
+			priv->video_standard = XC4000_DK_PAL_NICAM;
+		}
+		goto tune_channel;
+	}
+
+	if (params->std & V4L2_STD_SECAM_DK) {
+		/* default to A2 audio standard */
+		params->std = V4L2_STD_SECAM_DK | V4L2_STD_A2;
+		if (audio_std & XC4000_AUDIO_STD_L) {
+			type = 0;
+			priv->video_standard = XC4000_DK_SECAM_NICAM;
+		} else if (audio_std & XC4000_AUDIO_STD_MONO) {
+			priv->video_standard = XC4000_DK_SECAM_A2MONO;
+		} else if (audio_std & XC4000_AUDIO_STD_K3) {
+			params->std |= V4L2_STD_SECAM_K3;
+			priv->video_standard = XC4000_DK_SECAM_A2LDK3;
+		} else {
+			priv->video_standard = XC4000_DK_SECAM_A2DK1;
+		}
+		goto tune_channel;
+	}
+
+	if (params->std & V4L2_STD_SECAM_L) {
+		/* default to NICAM audio standard */
+		type = 0;
+		params->std = V4L2_STD_SECAM_L | V4L2_STD_NICAM;
+		priv->video_standard = XC4000_L_SECAM_NICAM;
+		goto tune_channel;
+	}
+
+	if (params->std & V4L2_STD_SECAM_LC) {
+		/* default to NICAM audio standard */
+		type = 0;
+		params->std = V4L2_STD_SECAM_LC | V4L2_STD_NICAM;
+		priv->video_standard = XC4000_LC_SECAM_NICAM;
+		goto tune_channel;
+	}
+
+tune_channel:
+	/* FIXME: it could be air. */
+	priv->rf_mode = XC_RF_MODE_CABLE;
+
+	if (check_firmware(fe, type, params->std,
+			   xc4000_standard[priv->video_standard].int_freq) != 0)
+		goto fail;
+
+	ret = xc_set_signal_source(priv, priv->rf_mode);
+	if (ret != 0) {
+		printk(KERN_ERR
+		       "xc4000: xc_set_signal_source(%d) failed\n",
+		       priv->rf_mode);
+		goto fail;
+	} else {
+		u16	video_mode, audio_mode;
+		video_mode = xc4000_standard[priv->video_standard].video_mode;
+		audio_mode = xc4000_standard[priv->video_standard].audio_mode;
+		if (priv->video_standard < XC4000_BG_PAL_A2) {
+			if (type & NOGD)
+				video_mode &= 0xFF7F;
+		} else if (priv->video_standard < XC4000_I_PAL_NICAM) {
+			if (priv->firm_version == 0x0102)
+				video_mode &= 0xFEFF;
+			if (audio_std & XC4000_AUDIO_STD_B)
+				video_mode |= 0x0080;
+		}
+		ret = xc_set_tv_standard(priv, video_mode, audio_mode);
+		if (ret != 0) {
+			printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n");
+			goto fail;
+		}
+	}
+
+	if (xc_write_reg(priv, XREG_D_CODE, 0) == 0)
+		ret = 0;
+	if (xc_write_reg(priv, XREG_AMPLITUDE, 1) != 0)
+		ret = -EREMOTEIO;
+	if (priv->set_smoothedcvbs != 0) {
+		if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0)
+			ret = -EREMOTEIO;
+	}
+	if (ret != 0) {
+		printk(KERN_ERR "xc4000: setting registers failed\n");
+		goto fail;
+	}
+
+	xc_tune_channel(priv, priv->freq_hz);
+
+	ret = 0;
+
+fail:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int xc4000_get_signal(struct dvb_frontend *fe, u16 *strength)
+{
+	struct xc4000_priv *priv = fe->tuner_priv;
+	u16 value = 0;
+	int rc;
+
+	mutex_lock(&priv->lock);
+	rc = xc4000_readreg(priv, XREG_SIGNAL_LEVEL, &value);
+	mutex_unlock(&priv->lock);
+
+	if (rc < 0)
+		goto ret;
+
+	/* Informations from real testing of DVB-T and radio part,
+	   coeficient for one dB is 0xff.
+	 */
+	tuner_dbg("Signal strength: -%ddB (%05d)\n", value >> 8, value);
+
+	/* all known digital modes */
+	if ((priv->video_standard == XC4000_DTV6) ||
+	    (priv->video_standard == XC4000_DTV7) ||
+	    (priv->video_standard == XC4000_DTV7_8) ||
+	    (priv->video_standard == XC4000_DTV8))
+		goto digital;
+
+	/* Analog mode has NOISE LEVEL important, signal
+	   depends only on gain of antenna and amplifiers,
+	   but it doesn't tell anything about real quality
+	   of reception.
+	 */
+	mutex_lock(&priv->lock);
+	rc = xc4000_readreg(priv, XREG_NOISE_LEVEL, &value);
+	mutex_unlock(&priv->lock);
+
+	tuner_dbg("Noise level: %ddB (%05d)\n", value >> 8, value);
+
+	/* highest noise level: 32dB */
+	if (value >= 0x2000) {
+		value = 0;
+	} else {
+		value = ~value << 3;
+	}
+
+	goto ret;
+
+	/* Digital mode has SIGNAL LEVEL important and real
+	   noise level is stored in demodulator registers.
+	 */
+digital:
+	/* best signal: -50dB */
+	if (value <= 0x3200) {
+		value = 0xffff;
+	/* minimum: -114dB - should be 0x7200 but real zero is 0x713A */
+	} else if (value >= 0x713A) {
+		value = 0;
+	} else {
+		value = ~(value - 0x3200) << 2;
+	}
+
+ret:
+	*strength = value;
+
+	return rc;
+}
+
+static int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq)
+{
+	struct xc4000_priv *priv = fe->tuner_priv;
+
+	*freq = priv->freq_hz;
+
+	if (debug) {
+		mutex_lock(&priv->lock);
+		if ((priv->cur_fw.type
+		     & (BASE | FM | DTV6 | DTV7 | DTV78 | DTV8)) == BASE) {
+			u16	snr = 0;
+			if (xc4000_readreg(priv, XREG_SNR, &snr) == 0) {
+				mutex_unlock(&priv->lock);
+				dprintk(1, "%s() freq = %u, SNR = %d\n",
+					__func__, *freq, snr);
+				return 0;
+			}
+		}
+		mutex_unlock(&priv->lock);
+	}
+
+	dprintk(1, "%s()\n", __func__);
+
+	return 0;
+}
+
+static int xc4000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
+{
+	struct xc4000_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __func__);
+
+	*bw = priv->bandwidth;
+	return 0;
+}
+
+static int xc4000_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct xc4000_priv *priv = fe->tuner_priv;
+	u16	lock_status = 0;
+
+	mutex_lock(&priv->lock);
+
+	if (priv->cur_fw.type & BASE)
+		xc_get_lock_status(priv, &lock_status);
+
+	*status = (lock_status == 1 ?
+		   TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO : 0);
+	if (priv->cur_fw.type & (DTV6 | DTV7 | DTV78 | DTV8))
+		*status &= (~TUNER_STATUS_STEREO);
+
+	mutex_unlock(&priv->lock);
+
+	dprintk(2, "%s() lock_status = %d\n", __func__, lock_status);
+
+	return 0;
+}
+
+static int xc4000_sleep(struct dvb_frontend *fe)
+{
+	struct xc4000_priv *priv = fe->tuner_priv;
+	int	ret = 0;
+
+	dprintk(1, "%s()\n", __func__);
+
+	mutex_lock(&priv->lock);
+
+	/* Avoid firmware reload on slow devices */
+	if ((no_poweroff == 2 ||
+	     (no_poweroff == 0 && priv->default_pm != 0)) &&
+	    (priv->cur_fw.type & BASE) != 0) {
+		/* force reset and firmware reload */
+		priv->cur_fw.type = XC_POWERED_DOWN;
+
+		if (xc_write_reg(priv, XREG_POWER_DOWN, 0) != 0) {
+			printk(KERN_ERR
+			       "xc4000: %s() unable to shutdown tuner\n",
+			       __func__);
+			ret = -EREMOTEIO;
+		}
+		msleep(20);
+	}
+
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int xc4000_init(struct dvb_frontend *fe)
+{
+	dprintk(1, "%s()\n", __func__);
+
+	return 0;
+}
+
+static int xc4000_release(struct dvb_frontend *fe)
+{
+	struct xc4000_priv *priv = fe->tuner_priv;
+
+	dprintk(1, "%s()\n", __func__);
+
+	mutex_lock(&xc4000_list_mutex);
+
+	if (priv)
+		hybrid_tuner_release_state(priv);
+
+	mutex_unlock(&xc4000_list_mutex);
+
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static const struct dvb_tuner_ops xc4000_tuner_ops = {
+	.info = {
+		.name           = "Xceive XC4000",
+		.frequency_min  =    1000000,
+		.frequency_max  = 1023000000,
+		.frequency_step =      50000,
+	},
+
+	.release	   = xc4000_release,
+	.init		   = xc4000_init,
+	.sleep		   = xc4000_sleep,
+
+	.set_params	   = xc4000_set_params,
+	.set_analog_params = xc4000_set_analog_params,
+	.get_frequency	   = xc4000_get_frequency,
+	.get_rf_strength   = xc4000_get_signal,
+	.get_bandwidth	   = xc4000_get_bandwidth,
+	.get_status	   = xc4000_get_status
+};
+
+struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
+				   struct i2c_adapter *i2c,
+				   struct xc4000_config *cfg)
+{
+	struct xc4000_priv *priv = NULL;
+	int	instance;
+	u16	id = 0;
+
+	dprintk(1, "%s(%d-%04x)\n", __func__,
+		i2c ? i2c_adapter_id(i2c) : -1,
+		cfg ? cfg->i2c_address : -1);
+
+	mutex_lock(&xc4000_list_mutex);
+
+	instance = hybrid_tuner_request_state(struct xc4000_priv, priv,
+					      hybrid_tuner_instance_list,
+					      i2c, cfg->i2c_address, "xc4000");
+	switch (instance) {
+	case 0:
+		goto fail;
+		break;
+	case 1:
+		/* new tuner instance */
+		priv->bandwidth = 6000000;
+		/* set default configuration */
+		priv->if_khz = 4560;
+		priv->default_pm = 0;
+		priv->dvb_amplitude = 134;
+		priv->set_smoothedcvbs = 1;
+		mutex_init(&priv->lock);
+		fe->tuner_priv = priv;
+		break;
+	default:
+		/* existing tuner instance */
+		fe->tuner_priv = priv;
+		break;
+	}
+
+	if (cfg->if_khz != 0) {
+		/* copy configuration if provided by the caller */
+		priv->if_khz = cfg->if_khz;
+		priv->default_pm = cfg->default_pm;
+		priv->dvb_amplitude = cfg->dvb_amplitude;
+		priv->set_smoothedcvbs = cfg->set_smoothedcvbs;
+	}
+
+	/* Check if firmware has been loaded. It is possible that another
+	   instance of the driver has loaded the firmware.
+	 */
+
+	if (instance == 1) {
+		if (xc4000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
+			goto fail;
+	} else {
+		id = ((priv->cur_fw.type & BASE) != 0 ?
+		      priv->hwmodel : XC_PRODUCT_ID_FW_NOT_LOADED);
+	}
+
+	switch (id) {
+	case XC_PRODUCT_ID_XC4000:
+	case XC_PRODUCT_ID_XC4100:
+		printk(KERN_INFO
+			"xc4000: Successfully identified at address 0x%02x\n",
+			cfg->i2c_address);
+		printk(KERN_INFO
+			"xc4000: Firmware has been loaded previously\n");
+		break;
+	case XC_PRODUCT_ID_FW_NOT_LOADED:
+		printk(KERN_INFO
+			"xc4000: Successfully identified at address 0x%02x\n",
+			cfg->i2c_address);
+		printk(KERN_INFO
+			"xc4000: Firmware has not been loaded previously\n");
+		break;
+	default:
+		printk(KERN_ERR
+			"xc4000: Device not found at addr 0x%02x (0x%x)\n",
+			cfg->i2c_address, id);
+		goto fail;
+	}
+
+	mutex_unlock(&xc4000_list_mutex);
+
+	memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+
+	if (instance == 1) {
+		int	ret;
+		mutex_lock(&priv->lock);
+		ret = xc4000_fwupload(fe);
+		mutex_unlock(&priv->lock);
+		if (ret != 0)
+			goto fail2;
+	}
+
+	return fe;
+fail:
+	mutex_unlock(&xc4000_list_mutex);
+fail2:
+	xc4000_release(fe);
+	return NULL;
+}
+EXPORT_SYMBOL(xc4000_attach);
+
+MODULE_AUTHOR("Steven Toth, Davide Ferri");
+MODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/xc4000.h b/drivers/media/tuners/xc4000.h
new file mode 100644
index 0000000..e6a44d1
--- /dev/null
+++ b/drivers/media/tuners/xc4000.h
@@ -0,0 +1,67 @@
+/*
+ *  Driver for Xceive XC4000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __XC4000_H__
+#define __XC4000_H__
+
+#include <linux/firmware.h>
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct xc4000_config {
+	u8	i2c_address;
+	/* if non-zero, power management is enabled by default */
+	u8	default_pm;
+	/* value to be written to XREG_AMPLITUDE in DVB-T mode (0: no write) */
+	u8	dvb_amplitude;
+	/* if non-zero, register 0x0E is set to filter analog TV video output */
+	u8	set_smoothedcvbs;
+	/* IF for DVB-T */
+	u32	if_khz;
+};
+
+/* xc4000 callback command */
+#define XC4000_TUNER_RESET		0
+
+/* For each bridge framework, when it attaches either analog or digital,
+ * it has to store a reference back to its _core equivalent structure,
+ * so that it can service the hardware by steering gpio's etc.
+ * Each bridge implementation is different so cast devptr accordingly.
+ * The xc4000 driver cares not for this value, other than ensuring
+ * it's passed back to a bridge during tuner_callback().
+ */
+
+#if defined(CONFIG_MEDIA_TUNER_XC4000) || (defined(CONFIG_MEDIA_TUNER_XC4000_MODULE) && defined(MODULE))
+extern struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
+					  struct i2c_adapter *i2c,
+					  struct xc4000_config *cfg);
+#else
+static inline struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
+						 struct i2c_adapter *i2c,
+						 struct xc4000_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c
new file mode 100644
index 0000000..dc93cf3
--- /dev/null
+++ b/drivers/media/tuners/xc5000.c
@@ -0,0 +1,1366 @@
+/*
+ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Xceive Corporation
+ *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
+ *  Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "xc5000.h"
+#include "tuner-i2c.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+static int no_poweroff;
+module_param(no_poweroff, int, 0644);
+MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
+	"\t\t1 keep device energized and with tuner ready all the times.\n"
+	"\t\tFaster, but consumes more power and keeps the device hotter");
+
+static DEFINE_MUTEX(xc5000_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
+#define dprintk(level, fmt, arg...) if (debug >= level) \
+	printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
+
+struct xc5000_priv {
+	struct tuner_i2c_props i2c_props;
+	struct list_head hybrid_tuner_instance_list;
+
+	u32 if_khz;
+	u16 xtal_khz;
+	u32 freq_hz;
+	u32 bandwidth;
+	u8  video_standard;
+	u8  rf_mode;
+	u8  radio_input;
+
+	int chip_id;
+	u16 pll_register_no;
+	u8 init_status_supported;
+	u8 fw_checksum_supported;
+};
+
+/* Misc Defines */
+#define MAX_TV_STANDARD			24
+#define XC_MAX_I2C_WRITE_LENGTH		64
+
+/* Signal Types */
+#define XC_RF_MODE_AIR			0
+#define XC_RF_MODE_CABLE		1
+
+/* Result codes */
+#define XC_RESULT_SUCCESS		0
+#define XC_RESULT_RESET_FAILURE		1
+#define XC_RESULT_I2C_WRITE_FAILURE	2
+#define XC_RESULT_I2C_READ_FAILURE	3
+#define XC_RESULT_OUT_OF_RANGE		5
+
+/* Product id */
+#define XC_PRODUCT_ID_FW_NOT_LOADED	0x2000
+#define XC_PRODUCT_ID_FW_LOADED 	0x1388
+
+/* Registers */
+#define XREG_INIT         0x00
+#define XREG_VIDEO_MODE   0x01
+#define XREG_AUDIO_MODE   0x02
+#define XREG_RF_FREQ      0x03
+#define XREG_D_CODE       0x04
+#define XREG_IF_OUT       0x05
+#define XREG_SEEK_MODE    0x07
+#define XREG_POWER_DOWN   0x0A /* Obsolete */
+/* Set the output amplitude - SIF for analog, DTVP/DTVN for digital */
+#define XREG_OUTPUT_AMP   0x0B
+#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
+#define XREG_SMOOTHEDCVBS 0x0E
+#define XREG_XTALFREQ     0x0F
+#define XREG_FINERFREQ    0x10
+#define XREG_DDIMODE      0x11
+
+#define XREG_ADC_ENV      0x00
+#define XREG_QUALITY      0x01
+#define XREG_FRAME_LINES  0x02
+#define XREG_HSYNC_FREQ   0x03
+#define XREG_LOCK         0x04
+#define XREG_FREQ_ERROR   0x05
+#define XREG_SNR          0x06
+#define XREG_VERSION      0x07
+#define XREG_PRODUCT_ID   0x08
+#define XREG_BUSY         0x09
+#define XREG_BUILD        0x0D
+#define XREG_TOTALGAIN    0x0F
+#define XREG_FW_CHECKSUM  0x12
+#define XREG_INIT_STATUS  0x13
+
+/*
+   Basic firmware description. This will remain with
+   the driver for documentation purposes.
+
+   This represents an I2C firmware file encoded as a
+   string of unsigned char. Format is as follows:
+
+   char[0  ]=len0_MSB  -> len = len_MSB * 256 + len_LSB
+   char[1  ]=len0_LSB  -> length of first write transaction
+   char[2  ]=data0 -> first byte to be sent
+   char[3  ]=data1
+   char[4  ]=data2
+   char[   ]=...
+   char[M  ]=dataN  -> last byte to be sent
+   char[M+1]=len1_MSB  -> len = len_MSB * 256 + len_LSB
+   char[M+2]=len1_LSB  -> length of second write transaction
+   char[M+3]=data0
+   char[M+4]=data1
+   ...
+   etc.
+
+   The [len] value should be interpreted as follows:
+
+   len= len_MSB _ len_LSB
+   len=1111_1111_1111_1111   : End of I2C_SEQUENCE
+   len=0000_0000_0000_0000   : Reset command: Do hardware reset
+   len=0NNN_NNNN_NNNN_NNNN   : Normal transaction: number of bytes = {1:32767)
+   len=1WWW_WWWW_WWWW_WWWW   : Wait command: wait for {1:32767} ms
+
+   For the RESET and WAIT commands, the two following bytes will contain
+   immediately the length of the following transaction.
+
+*/
+struct XC_TV_STANDARD {
+	char *Name;
+	u16 AudioMode;
+	u16 VideoMode;
+};
+
+/* Tuner standards */
+#define MN_NTSC_PAL_BTSC	0
+#define MN_NTSC_PAL_A2		1
+#define MN_NTSC_PAL_EIAJ	2
+#define MN_NTSC_PAL_Mono	3
+#define BG_PAL_A2		4
+#define BG_PAL_NICAM		5
+#define BG_PAL_MONO		6
+#define I_PAL_NICAM		7
+#define I_PAL_NICAM_MONO	8
+#define DK_PAL_A2		9
+#define DK_PAL_NICAM		10
+#define DK_PAL_MONO		11
+#define DK_SECAM_A2DK1		12
+#define DK_SECAM_A2LDK3 	13
+#define DK_SECAM_A2MONO 	14
+#define L_SECAM_NICAM		15
+#define LC_SECAM_NICAM		16
+#define DTV6			17
+#define DTV8			18
+#define DTV7_8			19
+#define DTV7			20
+#define FM_Radio_INPUT2 	21
+#define FM_Radio_INPUT1 	22
+#define FM_Radio_INPUT1_MONO	23
+
+static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
+	{"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
+	{"M/N-NTSC/PAL-A2",   0x0600, 0x8020},
+	{"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020},
+	{"M/N-NTSC/PAL-Mono", 0x0478, 0x8020},
+	{"B/G-PAL-A2",        0x0A00, 0x8049},
+	{"B/G-PAL-NICAM",     0x0C04, 0x8049},
+	{"B/G-PAL-MONO",      0x0878, 0x8059},
+	{"I-PAL-NICAM",       0x1080, 0x8009},
+	{"I-PAL-NICAM-MONO",  0x0E78, 0x8009},
+	{"D/K-PAL-A2",        0x1600, 0x8009},
+	{"D/K-PAL-NICAM",     0x0E80, 0x8009},
+	{"D/K-PAL-MONO",      0x1478, 0x8009},
+	{"D/K-SECAM-A2 DK1",  0x1200, 0x8009},
+	{"D/K-SECAM-A2 L/DK3", 0x0E00, 0x8009},
+	{"D/K-SECAM-A2 MONO", 0x1478, 0x8009},
+	{"L-SECAM-NICAM",     0x8E82, 0x0009},
+	{"L'-SECAM-NICAM",    0x8E82, 0x4009},
+	{"DTV6",              0x00C0, 0x8002},
+	{"DTV8",              0x00C0, 0x800B},
+	{"DTV7/8",            0x00C0, 0x801B},
+	{"DTV7",              0x00C0, 0x8007},
+	{"FM Radio-INPUT2",   0x9802, 0x9002},
+	{"FM Radio-INPUT1",   0x0208, 0x9002},
+	{"FM Radio-INPUT1_MONO", 0x0278, 0x9002}
+};
+
+
+struct xc5000_fw_cfg {
+	char *name;
+	u16 size;
+	u16 pll_reg;
+	u8 init_status_supported;
+	u8 fw_checksum_supported;
+};
+
+#define XC5000A_FIRMWARE "dvb-fe-xc5000-1.6.114.fw"
+static const struct xc5000_fw_cfg xc5000a_1_6_114 = {
+	.name = XC5000A_FIRMWARE,
+	.size = 12401,
+	.pll_reg = 0x806c,
+};
+
+#define XC5000C_FIRMWARE "dvb-fe-xc5000c-4.1.30.7.fw"
+static const struct xc5000_fw_cfg xc5000c_41_024_5 = {
+	.name = XC5000C_FIRMWARE,
+	.size = 16497,
+	.pll_reg = 0x13,
+	.init_status_supported = 1,
+	.fw_checksum_supported = 1,
+};
+
+static inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id)
+{
+	switch (chip_id) {
+	default:
+	case XC5000A:
+		return &xc5000a_1_6_114;
+	case XC5000C:
+		return &xc5000c_41_024_5;
+	}
+}
+
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force);
+static int xc5000_is_firmware_loaded(struct dvb_frontend *fe);
+static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val);
+static int xc5000_TunerReset(struct dvb_frontend *fe);
+
+static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
+{
+	struct i2c_msg msg = { .addr = priv->i2c_props.addr,
+			       .flags = 0, .buf = buf, .len = len };
+
+	if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
+		printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len);
+		return XC_RESULT_I2C_WRITE_FAILURE;
+	}
+	return XC_RESULT_SUCCESS;
+}
+
+#if 0
+/* This routine is never used because the only time we read data from the
+   i2c bus is when we read registers, and we want that to be an atomic i2c
+   transaction in case we are on a multi-master bus */
+static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
+{
+	struct i2c_msg msg = { .addr = priv->i2c_props.addr,
+		.flags = I2C_M_RD, .buf = buf, .len = len };
+
+	if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
+		printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+#endif
+
+static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
+{
+	u8 buf[2] = { reg >> 8, reg & 0xff };
+	u8 bval[2] = { 0, 0 };
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->i2c_props.addr,
+			.flags = 0, .buf = &buf[0], .len = 2 },
+		{ .addr = priv->i2c_props.addr,
+			.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
+	};
+
+	if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
+		printk(KERN_WARNING "xc5000: I2C read failed\n");
+		return -EREMOTEIO;
+	}
+
+	*val = (bval[0] << 8) | bval[1];
+	return XC_RESULT_SUCCESS;
+}
+
+static void xc_wait(int wait_ms)
+{
+	msleep(wait_ms);
+}
+
+static int xc5000_TunerReset(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (fe->callback) {
+		ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+					   fe->dvb->priv :
+					   priv->i2c_props.adap->algo_data,
+					   DVB_FRONTEND_COMPONENT_TUNER,
+					   XC5000_TUNER_RESET, 0);
+		if (ret) {
+			printk(KERN_ERR "xc5000: reset failed\n");
+			return XC_RESULT_RESET_FAILURE;
+		}
+	} else {
+		printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
+		return XC_RESULT_RESET_FAILURE;
+	}
+	return XC_RESULT_SUCCESS;
+}
+
+static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
+{
+	u8 buf[4];
+	int WatchDogTimer = 100;
+	int result;
+
+	buf[0] = (regAddr >> 8) & 0xFF;
+	buf[1] = regAddr & 0xFF;
+	buf[2] = (i2cData >> 8) & 0xFF;
+	buf[3] = i2cData & 0xFF;
+	result = xc_send_i2c_data(priv, buf, 4);
+	if (result == XC_RESULT_SUCCESS) {
+		/* wait for busy flag to clear */
+		while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) {
+			result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf);
+			if (result == XC_RESULT_SUCCESS) {
+				if ((buf[0] == 0) && (buf[1] == 0)) {
+					/* busy flag cleared */
+					break;
+				} else {
+					xc_wait(5); /* wait 5 ms */
+					WatchDogTimer--;
+				}
+			}
+		}
+	}
+	if (WatchDogTimer <= 0)
+		result = XC_RESULT_I2C_WRITE_FAILURE;
+
+	return result;
+}
+
+static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+
+	int i, nbytes_to_send, result;
+	unsigned int len, pos, index;
+	u8 buf[XC_MAX_I2C_WRITE_LENGTH];
+
+	index = 0;
+	while ((i2c_sequence[index] != 0xFF) ||
+		(i2c_sequence[index + 1] != 0xFF)) {
+		len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
+		if (len == 0x0000) {
+			/* RESET command */
+			result = xc5000_TunerReset(fe);
+			index += 2;
+			if (result != XC_RESULT_SUCCESS)
+				return result;
+		} else if (len & 0x8000) {
+			/* WAIT command */
+			xc_wait(len & 0x7FFF);
+			index += 2;
+		} else {
+			/* Send i2c data whilst ensuring individual transactions
+			 * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
+			 */
+			index += 2;
+			buf[0] = i2c_sequence[index];
+			buf[1] = i2c_sequence[index + 1];
+			pos = 2;
+			while (pos < len) {
+				if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2)
+					nbytes_to_send =
+						XC_MAX_I2C_WRITE_LENGTH;
+				else
+					nbytes_to_send = (len - pos + 2);
+				for (i = 2; i < nbytes_to_send; i++) {
+					buf[i] = i2c_sequence[index + pos +
+						i - 2];
+				}
+				result = xc_send_i2c_data(priv, buf,
+					nbytes_to_send);
+
+				if (result != XC_RESULT_SUCCESS)
+					return result;
+
+				pos += nbytes_to_send - 2;
+			}
+			index += len;
+		}
+	}
+	return XC_RESULT_SUCCESS;
+}
+
+static int xc_initialize(struct xc5000_priv *priv)
+{
+	dprintk(1, "%s()\n", __func__);
+	return xc_write_reg(priv, XREG_INIT, 0);
+}
+
+static int xc_SetTVStandard(struct xc5000_priv *priv,
+	u16 VideoMode, u16 AudioMode)
+{
+	int ret;
+	dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, VideoMode, AudioMode);
+	dprintk(1, "%s() Standard = %s\n",
+		__func__,
+		XC5000_Standard[priv->video_standard].Name);
+
+	ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode);
+	if (ret == XC_RESULT_SUCCESS)
+		ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode);
+
+	return ret;
+}
+
+static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
+{
+	dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
+		rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
+
+	if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) {
+		rf_mode = XC_RF_MODE_CABLE;
+		printk(KERN_ERR
+			"%s(), Invalid mode, defaulting to CABLE",
+			__func__);
+	}
+	return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
+}
+
+static const struct dvb_tuner_ops xc5000_tuner_ops;
+
+static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
+{
+	u16 freq_code;
+
+	dprintk(1, "%s(%u)\n", __func__, freq_hz);
+
+	if ((freq_hz > xc5000_tuner_ops.info.frequency_max) ||
+		(freq_hz < xc5000_tuner_ops.info.frequency_min))
+		return XC_RESULT_OUT_OF_RANGE;
+
+	freq_code = (u16)(freq_hz / 15625);
+
+	/* Starting in firmware version 1.1.44, Xceive recommends using the
+	   FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
+	   only be used for fast scanning for channel lock) */
+	return xc_write_reg(priv, XREG_FINERFREQ, freq_code);
+}
+
+
+static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz)
+{
+	u32 freq_code = (freq_khz * 1024)/1000;
+	dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n",
+		__func__, freq_khz, freq_code);
+
+	return xc_write_reg(priv, XREG_IF_OUT, freq_code);
+}
+
+
+static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
+{
+	return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope);
+}
+
+static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
+{
+	int result;
+	u16 regData;
+	u32 tmp;
+
+	result = xc5000_readreg(priv, XREG_FREQ_ERROR, &regData);
+	if (result != XC_RESULT_SUCCESS)
+		return result;
+
+	tmp = (u32)regData;
+	(*freq_error_hz) = (tmp * 15625) / 1000;
+	return result;
+}
+
+static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status)
+{
+	return xc5000_readreg(priv, XREG_LOCK, lock_status);
+}
+
+static int xc_get_version(struct xc5000_priv *priv,
+	u8 *hw_majorversion, u8 *hw_minorversion,
+	u8 *fw_majorversion, u8 *fw_minorversion)
+{
+	u16 data;
+	int result;
+
+	result = xc5000_readreg(priv, XREG_VERSION, &data);
+	if (result != XC_RESULT_SUCCESS)
+		return result;
+
+	(*hw_majorversion) = (data >> 12) & 0x0F;
+	(*hw_minorversion) = (data >>  8) & 0x0F;
+	(*fw_majorversion) = (data >>  4) & 0x0F;
+	(*fw_minorversion) = data & 0x0F;
+
+	return 0;
+}
+
+static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev)
+{
+	return xc5000_readreg(priv, XREG_BUILD, buildrev);
+}
+
+static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
+{
+	u16 regData;
+	int result;
+
+	result = xc5000_readreg(priv, XREG_HSYNC_FREQ, &regData);
+	if (result != XC_RESULT_SUCCESS)
+		return result;
+
+	(*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
+	return result;
+}
+
+static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines)
+{
+	return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines);
+}
+
+static int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
+{
+	return xc5000_readreg(priv, XREG_QUALITY, quality);
+}
+
+static int xc_get_analogsnr(struct xc5000_priv *priv, u16 *snr)
+{
+	return xc5000_readreg(priv, XREG_SNR, snr);
+}
+
+static int xc_get_totalgain(struct xc5000_priv *priv, u16 *totalgain)
+{
+	return xc5000_readreg(priv, XREG_TOTALGAIN, totalgain);
+}
+
+static u16 WaitForLock(struct xc5000_priv *priv)
+{
+	u16 lockState = 0;
+	int watchDogCount = 40;
+
+	while ((lockState == 0) && (watchDogCount > 0)) {
+		xc_get_lock_status(priv, &lockState);
+		if (lockState != 1) {
+			xc_wait(5);
+			watchDogCount--;
+		}
+	}
+	return lockState;
+}
+
+#define XC_TUNE_ANALOG  0
+#define XC_TUNE_DIGITAL 1
+static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode)
+{
+	int found = 0;
+
+	dprintk(1, "%s(%u)\n", __func__, freq_hz);
+
+	if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
+		return 0;
+
+	if (mode == XC_TUNE_ANALOG) {
+		if (WaitForLock(priv) == 1)
+			found = 1;
+	}
+
+	return found;
+}
+
+static int xc_set_xtal(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret = XC_RESULT_SUCCESS;
+
+	switch (priv->chip_id) {
+	default:
+	case XC5000A:
+		/* 32.000 MHz xtal is default */
+		break;
+	case XC5000C:
+		switch (priv->xtal_khz) {
+		default:
+		case 32000:
+			/* 32.000 MHz xtal is default */
+			break;
+		case 31875:
+			/* 31.875 MHz xtal configuration */
+			ret = xc_write_reg(priv, 0x000f, 0x8081);
+			break;
+		}
+		break;
+	}
+	return ret;
+}
+
+static int xc5000_fwupload(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	const struct firmware *fw;
+	int ret;
+	const struct xc5000_fw_cfg *desired_fw =
+		xc5000_assign_firmware(priv->chip_id);
+	priv->pll_register_no = desired_fw->pll_reg;
+	priv->init_status_supported = desired_fw->init_status_supported;
+	priv->fw_checksum_supported = desired_fw->fw_checksum_supported;
+
+	/* request the firmware, this will block and timeout */
+	printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
+		desired_fw->name);
+
+	ret = request_firmware(&fw, desired_fw->name,
+		priv->i2c_props.adap->dev.parent);
+	if (ret) {
+		printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
+		ret = XC_RESULT_RESET_FAILURE;
+		goto out;
+	} else {
+		printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n",
+		       fw->size);
+		ret = XC_RESULT_SUCCESS;
+	}
+
+	if (fw->size != desired_fw->size) {
+		printk(KERN_ERR "xc5000: firmware incorrect size\n");
+		ret = XC_RESULT_RESET_FAILURE;
+	} else {
+		printk(KERN_INFO "xc5000: firmware uploading...\n");
+		ret = xc_load_i2c_sequence(fe,  fw->data);
+		if (XC_RESULT_SUCCESS == ret)
+			ret = xc_set_xtal(fe);
+		if (XC_RESULT_SUCCESS == ret)
+			printk(KERN_INFO "xc5000: firmware upload complete...\n");
+		else
+			printk(KERN_ERR "xc5000: firmware upload failed...\n");
+	}
+
+out:
+	release_firmware(fw);
+	return ret;
+}
+
+static void xc_debug_dump(struct xc5000_priv *priv)
+{
+	u16 adc_envelope;
+	u32 freq_error_hz = 0;
+	u16 lock_status;
+	u32 hsync_freq_hz = 0;
+	u16 frame_lines;
+	u16 quality;
+	u16 snr;
+	u16 totalgain;
+	u8 hw_majorversion = 0, hw_minorversion = 0;
+	u8 fw_majorversion = 0, fw_minorversion = 0;
+	u16 fw_buildversion = 0;
+	u16 regval;
+
+	/* Wait for stats to stabilize.
+	 * Frame Lines needs two frame times after initial lock
+	 * before it is valid.
+	 */
+	xc_wait(100);
+
+	xc_get_ADC_Envelope(priv,  &adc_envelope);
+	dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
+
+	xc_get_frequency_error(priv, &freq_error_hz);
+	dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
+
+	xc_get_lock_status(priv,  &lock_status);
+	dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
+		lock_status);
+
+	xc_get_version(priv,  &hw_majorversion, &hw_minorversion,
+		&fw_majorversion, &fw_minorversion);
+	xc_get_buildversion(priv,  &fw_buildversion);
+	dprintk(1, "*** HW: V%d.%d, FW: V %d.%d.%d\n",
+		hw_majorversion, hw_minorversion,
+		fw_majorversion, fw_minorversion, fw_buildversion);
+
+	xc_get_hsync_freq(priv,  &hsync_freq_hz);
+	dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz);
+
+	xc_get_frame_lines(priv,  &frame_lines);
+	dprintk(1, "*** Frame lines = %d\n", frame_lines);
+
+	xc_get_quality(priv,  &quality);
+	dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality & 0x07);
+
+	xc_get_analogsnr(priv,  &snr);
+	dprintk(1, "*** Unweighted analog SNR = %d dB\n", snr & 0x3f);
+
+	xc_get_totalgain(priv,  &totalgain);
+	dprintk(1, "*** Total gain = %d.%d dB\n", totalgain / 256,
+		(totalgain % 256) * 100 / 256);
+
+	if (priv->pll_register_no) {
+		xc5000_readreg(priv, priv->pll_register_no, &regval);
+		dprintk(1, "*** PLL lock status = 0x%04x\n", regval);
+	}
+}
+
+static int xc5000_set_params(struct dvb_frontend *fe)
+{
+	int ret, b;
+	struct xc5000_priv *priv = fe->tuner_priv;
+	u32 bw = fe->dtv_property_cache.bandwidth_hz;
+	u32 freq = fe->dtv_property_cache.frequency;
+	u32 delsys  = fe->dtv_property_cache.delivery_system;
+
+	if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) {
+		dprintk(1, "Unable to load firmware and init tuner\n");
+		return -EINVAL;
+	}
+
+	dprintk(1, "%s() frequency=%d (Hz)\n", __func__, freq);
+
+	switch (delsys) {
+	case SYS_ATSC:
+		dprintk(1, "%s() VSB modulation\n", __func__);
+		priv->rf_mode = XC_RF_MODE_AIR;
+		priv->freq_hz = freq - 1750000;
+		priv->video_standard = DTV6;
+		break;
+	case SYS_DVBC_ANNEX_B:
+		dprintk(1, "%s() QAM modulation\n", __func__);
+		priv->rf_mode = XC_RF_MODE_CABLE;
+		priv->freq_hz = freq - 1750000;
+		priv->video_standard = DTV6;
+		break;
+	case SYS_ISDBT:
+		/* All ISDB-T are currently for 6 MHz bw */
+		if (!bw)
+			bw = 6000000;
+		/* fall to OFDM handling */
+	case SYS_DMBTH:
+	case SYS_DVBT:
+	case SYS_DVBT2:
+		dprintk(1, "%s() OFDM\n", __func__);
+		switch (bw) {
+		case 6000000:
+			priv->video_standard = DTV6;
+			priv->freq_hz = freq - 1750000;
+			break;
+		case 7000000:
+			priv->video_standard = DTV7;
+			priv->freq_hz = freq - 2250000;
+			break;
+		case 8000000:
+			priv->video_standard = DTV8;
+			priv->freq_hz = freq - 2750000;
+			break;
+		default:
+			printk(KERN_ERR "xc5000 bandwidth not set!\n");
+			return -EINVAL;
+		}
+		priv->rf_mode = XC_RF_MODE_AIR;
+	case SYS_DVBC_ANNEX_A:
+	case SYS_DVBC_ANNEX_C:
+		dprintk(1, "%s() QAM modulation\n", __func__);
+		priv->rf_mode = XC_RF_MODE_CABLE;
+		if (bw <= 6000000) {
+			priv->video_standard = DTV6;
+			priv->freq_hz = freq - 1750000;
+			b = 6;
+		} else if (bw <= 7000000) {
+			priv->video_standard = DTV7;
+			priv->freq_hz = freq - 2250000;
+			b = 7;
+		} else {
+			priv->video_standard = DTV7_8;
+			priv->freq_hz = freq - 2750000;
+			b = 8;
+		}
+		dprintk(1, "%s() Bandwidth %dMHz (%d)\n", __func__,
+			b, bw);
+		break;
+	default:
+		printk(KERN_ERR "xc5000: delivery system is not supported!\n");
+		return -EINVAL;
+	}
+
+	dprintk(1, "%s() frequency=%d (compensated to %d)\n",
+		__func__, freq, priv->freq_hz);
+
+	ret = xc_SetSignalSource(priv, priv->rf_mode);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR
+			"xc5000: xc_SetSignalSource(%d) failed\n",
+			priv->rf_mode);
+		return -EREMOTEIO;
+	}
+
+	ret = xc_SetTVStandard(priv,
+		XC5000_Standard[priv->video_standard].VideoMode,
+		XC5000_Standard[priv->video_standard].AudioMode);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+		return -EREMOTEIO;
+	}
+
+	ret = xc_set_IF_frequency(priv, priv->if_khz);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
+		       priv->if_khz);
+		return -EIO;
+	}
+
+	xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a);
+
+	xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
+
+	if (debug)
+		xc_debug_dump(priv);
+
+	priv->bandwidth = bw;
+
+	return 0;
+}
+
+static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+	u16 id;
+
+	ret = xc5000_readreg(priv, XREG_PRODUCT_ID, &id);
+	if (ret == XC_RESULT_SUCCESS) {
+		if (id == XC_PRODUCT_ID_FW_NOT_LOADED)
+			ret = XC_RESULT_RESET_FAILURE;
+		else
+			ret = XC_RESULT_SUCCESS;
+	}
+
+	dprintk(1, "%s() returns %s id = 0x%x\n", __func__,
+		ret == XC_RESULT_SUCCESS ? "True" : "False", id);
+	return ret;
+}
+
+static int xc5000_set_tv_freq(struct dvb_frontend *fe,
+	struct analog_parameters *params)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	u16 pll_lock_status;
+	int ret;
+
+	dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
+		__func__, params->frequency);
+
+	/* Fix me: it could be air. */
+	priv->rf_mode = params->mode;
+	if (params->mode > XC_RF_MODE_CABLE)
+		priv->rf_mode = XC_RF_MODE_CABLE;
+
+	/* params->frequency is in units of 62.5khz */
+	priv->freq_hz = params->frequency * 62500;
+
+	/* FIX ME: Some video standards may have several possible audio
+		   standards. We simply default to one of them here.
+	 */
+	if (params->std & V4L2_STD_MN) {
+		/* default to BTSC audio standard */
+		priv->video_standard = MN_NTSC_PAL_BTSC;
+		goto tune_channel;
+	}
+
+	if (params->std & V4L2_STD_PAL_BG) {
+		/* default to NICAM audio standard */
+		priv->video_standard = BG_PAL_NICAM;
+		goto tune_channel;
+	}
+
+	if (params->std & V4L2_STD_PAL_I) {
+		/* default to NICAM audio standard */
+		priv->video_standard = I_PAL_NICAM;
+		goto tune_channel;
+	}
+
+	if (params->std & V4L2_STD_PAL_DK) {
+		/* default to NICAM audio standard */
+		priv->video_standard = DK_PAL_NICAM;
+		goto tune_channel;
+	}
+
+	if (params->std & V4L2_STD_SECAM_DK) {
+		/* default to A2 DK1 audio standard */
+		priv->video_standard = DK_SECAM_A2DK1;
+		goto tune_channel;
+	}
+
+	if (params->std & V4L2_STD_SECAM_L) {
+		priv->video_standard = L_SECAM_NICAM;
+		goto tune_channel;
+	}
+
+	if (params->std & V4L2_STD_SECAM_LC) {
+		priv->video_standard = LC_SECAM_NICAM;
+		goto tune_channel;
+	}
+
+tune_channel:
+	ret = xc_SetSignalSource(priv, priv->rf_mode);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR
+			"xc5000: xc_SetSignalSource(%d) failed\n",
+			priv->rf_mode);
+		return -EREMOTEIO;
+	}
+
+	ret = xc_SetTVStandard(priv,
+		XC5000_Standard[priv->video_standard].VideoMode,
+		XC5000_Standard[priv->video_standard].AudioMode);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+		return -EREMOTEIO;
+	}
+
+	xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09);
+
+	xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
+
+	if (debug)
+		xc_debug_dump(priv);
+
+	if (priv->pll_register_no != 0) {
+		msleep(20);
+		xc5000_readreg(priv, priv->pll_register_no, &pll_lock_status);
+		if (pll_lock_status > 63) {
+			/* PLL is unlocked, force reload of the firmware */
+			dprintk(1, "xc5000: PLL not locked (0x%x).  Reloading...\n",
+				pll_lock_status);
+			if (xc_load_fw_and_init_tuner(fe, 1) != XC_RESULT_SUCCESS) {
+				printk(KERN_ERR "xc5000: Unable to reload fw\n");
+				return -EREMOTEIO;
+			}
+			goto tune_channel;
+		}
+	}
+
+	return 0;
+}
+
+static int xc5000_set_radio_freq(struct dvb_frontend *fe,
+	struct analog_parameters *params)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret = -EINVAL;
+	u8 radio_input;
+
+	dprintk(1, "%s() frequency=%d (in units of khz)\n",
+		__func__, params->frequency);
+
+	if (priv->radio_input == XC5000_RADIO_NOT_CONFIGURED) {
+		dprintk(1, "%s() radio input not configured\n", __func__);
+		return -EINVAL;
+	}
+
+	if (priv->radio_input == XC5000_RADIO_FM1)
+		radio_input = FM_Radio_INPUT1;
+	else if  (priv->radio_input == XC5000_RADIO_FM2)
+		radio_input = FM_Radio_INPUT2;
+	else if  (priv->radio_input == XC5000_RADIO_FM1_MONO)
+		radio_input = FM_Radio_INPUT1_MONO;
+	else {
+		dprintk(1, "%s() unknown radio input %d\n", __func__,
+			priv->radio_input);
+		return -EINVAL;
+	}
+
+	priv->freq_hz = params->frequency * 125 / 2;
+
+	priv->rf_mode = XC_RF_MODE_AIR;
+
+	ret = xc_SetTVStandard(priv, XC5000_Standard[radio_input].VideoMode,
+			       XC5000_Standard[radio_input].AudioMode);
+
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+		return -EREMOTEIO;
+	}
+
+	ret = xc_SetSignalSource(priv, priv->rf_mode);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR
+			"xc5000: xc_SetSignalSource(%d) failed\n",
+			priv->rf_mode);
+		return -EREMOTEIO;
+	}
+
+	if ((priv->radio_input == XC5000_RADIO_FM1) ||
+				(priv->radio_input == XC5000_RADIO_FM2))
+		xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09);
+	else if  (priv->radio_input == XC5000_RADIO_FM1_MONO)
+		xc_write_reg(priv, XREG_OUTPUT_AMP, 0x06);
+
+	xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
+
+	return 0;
+}
+
+static int xc5000_set_analog_params(struct dvb_frontend *fe,
+			     struct analog_parameters *params)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret = -EINVAL;
+
+	if (priv->i2c_props.adap == NULL)
+		return -EINVAL;
+
+	if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) {
+		dprintk(1, "Unable to load firmware and init tuner\n");
+		return -EINVAL;
+	}
+
+	switch (params->mode) {
+	case V4L2_TUNER_RADIO:
+		ret = xc5000_set_radio_freq(fe, params);
+		break;
+	case V4L2_TUNER_ANALOG_TV:
+	case V4L2_TUNER_DIGITAL_TV:
+		ret = xc5000_set_tv_freq(fe, params);
+		break;
+	}
+
+	return ret;
+}
+
+
+static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __func__);
+	*freq = priv->freq_hz;
+	return 0;
+}
+
+static int xc5000_get_if_frequency(struct dvb_frontend *fe, u32 *freq)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __func__);
+	*freq = priv->if_khz * 1000;
+	return 0;
+}
+
+static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __func__);
+
+	*bw = priv->bandwidth;
+	return 0;
+}
+
+static int xc5000_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	u16 lock_status = 0;
+
+	xc_get_lock_status(priv, &lock_status);
+
+	dprintk(1, "%s() lock_status = 0x%08x\n", __func__, lock_status);
+
+	*status = lock_status;
+
+	return 0;
+}
+
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret = XC_RESULT_SUCCESS;
+	u16 pll_lock_status;
+	u16 fw_ck;
+
+	if (force || xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
+
+fw_retry:
+
+		ret = xc5000_fwupload(fe);
+		if (ret != XC_RESULT_SUCCESS)
+			return ret;
+
+		msleep(20);
+
+		if (priv->fw_checksum_supported) {
+			if (xc5000_readreg(priv, XREG_FW_CHECKSUM, &fw_ck)
+			    != XC_RESULT_SUCCESS) {
+				dprintk(1, "%s() FW checksum reading failed.\n",
+					__func__);
+				goto fw_retry;
+			}
+
+			if (fw_ck == 0) {
+				dprintk(1, "%s() FW checksum failed = 0x%04x\n",
+					__func__, fw_ck);
+				goto fw_retry;
+			}
+		}
+
+		/* Start the tuner self-calibration process */
+		ret |= xc_initialize(priv);
+
+		if (ret != XC_RESULT_SUCCESS)
+			goto fw_retry;
+
+		/* Wait for calibration to complete.
+		 * We could continue but XC5000 will clock stretch subsequent
+		 * I2C transactions until calibration is complete.  This way we
+		 * don't have to rely on clock stretching working.
+		 */
+		xc_wait(100);
+
+		if (priv->init_status_supported) {
+			if (xc5000_readreg(priv, XREG_INIT_STATUS, &fw_ck) != XC_RESULT_SUCCESS) {
+				dprintk(1, "%s() FW failed reading init status.\n",
+					__func__);
+				goto fw_retry;
+			}
+
+			if (fw_ck == 0) {
+				dprintk(1, "%s() FW init status failed = 0x%04x\n", __func__, fw_ck);
+				goto fw_retry;
+			}
+		}
+
+		if (priv->pll_register_no) {
+			xc5000_readreg(priv, priv->pll_register_no,
+				       &pll_lock_status);
+			if (pll_lock_status > 63) {
+				/* PLL is unlocked, force reload of the firmware */
+				printk(KERN_ERR "xc5000: PLL not running after fwload.\n");
+				goto fw_retry;
+			}
+		}
+
+		/* Default to "CABLE" mode */
+		ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
+	}
+
+	return ret;
+}
+
+static int xc5000_sleep(struct dvb_frontend *fe)
+{
+	int ret;
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* Avoid firmware reload on slow devices */
+	if (no_poweroff)
+		return 0;
+
+	/* According to Xceive technical support, the "powerdown" register
+	   was removed in newer versions of the firmware.  The "supported"
+	   way to sleep the tuner is to pull the reset pin low for 10ms */
+	ret = xc5000_TunerReset(fe);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR
+			"xc5000: %s() unable to shutdown tuner\n",
+			__func__);
+		return -EREMOTEIO;
+	} else
+		return XC_RESULT_SUCCESS;
+}
+
+static int xc5000_init(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __func__);
+
+	if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: Unable to initialise tuner\n");
+		return -EREMOTEIO;
+	}
+
+	if (debug)
+		xc_debug_dump(priv);
+
+	return 0;
+}
+
+static int xc5000_release(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+
+	dprintk(1, "%s()\n", __func__);
+
+	mutex_lock(&xc5000_list_mutex);
+
+	if (priv)
+		hybrid_tuner_release_state(priv);
+
+	mutex_unlock(&xc5000_list_mutex);
+
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	struct xc5000_config *p = priv_cfg;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (p->if_khz)
+		priv->if_khz = p->if_khz;
+
+	if (p->radio_input)
+		priv->radio_input = p->radio_input;
+
+	return 0;
+}
+
+
+static const struct dvb_tuner_ops xc5000_tuner_ops = {
+	.info = {
+		.name           = "Xceive XC5000",
+		.frequency_min  =    1000000,
+		.frequency_max  = 1023000000,
+		.frequency_step =      50000,
+	},
+
+	.release	   = xc5000_release,
+	.init		   = xc5000_init,
+	.sleep		   = xc5000_sleep,
+
+	.set_config	   = xc5000_set_config,
+	.set_params	   = xc5000_set_params,
+	.set_analog_params = xc5000_set_analog_params,
+	.get_frequency	   = xc5000_get_frequency,
+	.get_if_frequency  = xc5000_get_if_frequency,
+	.get_bandwidth	   = xc5000_get_bandwidth,
+	.get_status	   = xc5000_get_status
+};
+
+struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
+				   struct i2c_adapter *i2c,
+				   const struct xc5000_config *cfg)
+{
+	struct xc5000_priv *priv = NULL;
+	int instance;
+	u16 id = 0;
+
+	dprintk(1, "%s(%d-%04x)\n", __func__,
+		i2c ? i2c_adapter_id(i2c) : -1,
+		cfg ? cfg->i2c_address : -1);
+
+	mutex_lock(&xc5000_list_mutex);
+
+	instance = hybrid_tuner_request_state(struct xc5000_priv, priv,
+					      hybrid_tuner_instance_list,
+					      i2c, cfg->i2c_address, "xc5000");
+	switch (instance) {
+	case 0:
+		goto fail;
+		break;
+	case 1:
+		/* new tuner instance */
+		priv->bandwidth = 6000000;
+		fe->tuner_priv = priv;
+		break;
+	default:
+		/* existing tuner instance */
+		fe->tuner_priv = priv;
+		break;
+	}
+
+	if (priv->if_khz == 0) {
+		/* If the IF hasn't been set yet, use the value provided by
+		   the caller (occurs in hybrid devices where the analog
+		   call to xc5000_attach occurs before the digital side) */
+		priv->if_khz = cfg->if_khz;
+	}
+
+	if (priv->xtal_khz == 0)
+		priv->xtal_khz = cfg->xtal_khz;
+
+	if (priv->radio_input == 0)
+		priv->radio_input = cfg->radio_input;
+
+	/* don't override chip id if it's already been set
+	   unless explicitly specified */
+	if ((priv->chip_id == 0) || (cfg->chip_id))
+		/* use default chip id if none specified, set to 0 so
+		   it can be overridden if this is a hybrid driver */
+		priv->chip_id = (cfg->chip_id) ? cfg->chip_id : 0;
+
+	/* Check if firmware has been loaded. It is possible that another
+	   instance of the driver has loaded the firmware.
+	 */
+	if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS)
+		goto fail;
+
+	switch (id) {
+	case XC_PRODUCT_ID_FW_LOADED:
+		printk(KERN_INFO
+			"xc5000: Successfully identified at address 0x%02x\n",
+			cfg->i2c_address);
+		printk(KERN_INFO
+			"xc5000: Firmware has been loaded previously\n");
+		break;
+	case XC_PRODUCT_ID_FW_NOT_LOADED:
+		printk(KERN_INFO
+			"xc5000: Successfully identified at address 0x%02x\n",
+			cfg->i2c_address);
+		printk(KERN_INFO
+			"xc5000: Firmware has not been loaded previously\n");
+		break;
+	default:
+		printk(KERN_ERR
+			"xc5000: Device not found at addr 0x%02x (0x%x)\n",
+			cfg->i2c_address, id);
+		goto fail;
+	}
+
+	mutex_unlock(&xc5000_list_mutex);
+
+	memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+
+	return fe;
+fail:
+	mutex_unlock(&xc5000_list_mutex);
+
+	xc5000_release(fe);
+	return NULL;
+}
+EXPORT_SYMBOL(xc5000_attach);
+
+MODULE_AUTHOR("Steven Toth");
+MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(XC5000A_FIRMWARE);
+MODULE_FIRMWARE(XC5000C_FIRMWARE);
diff --git a/drivers/media/tuners/xc5000.h b/drivers/media/tuners/xc5000.h
new file mode 100644
index 0000000..b1a5474
--- /dev/null
+++ b/drivers/media/tuners/xc5000.h
@@ -0,0 +1,74 @@
+/*
+ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __XC5000_H__
+#define __XC5000_H__
+
+#include <linux/firmware.h>
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+#define XC5000A 1
+#define XC5000C 2
+
+struct xc5000_config {
+	u8   i2c_address;
+	u32  if_khz;
+	u8   radio_input;
+	u16  xtal_khz;
+
+	int chip_id;
+};
+
+/* xc5000 callback command */
+#define XC5000_TUNER_RESET		0
+
+/* Possible Radio inputs */
+#define XC5000_RADIO_NOT_CONFIGURED		0
+#define XC5000_RADIO_FM1			1
+#define XC5000_RADIO_FM2			2
+#define XC5000_RADIO_FM1_MONO			3
+
+/* For each bridge framework, when it attaches either analog or digital,
+ * it has to store a reference back to its _core equivalent structure,
+ * so that it can service the hardware by steering gpio's etc.
+ * Each bridge implementation is different so cast devptr accordingly.
+ * The xc5000 driver cares not for this value, other than ensuring
+ * it's passed back to a bridge during tuner_callback().
+ */
+
+#if defined(CONFIG_MEDIA_TUNER_XC5000) || \
+    (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
+extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
+					  struct i2c_adapter *i2c,
+					  const struct xc5000_config *cfg);
+#else
+static inline struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
+						 struct i2c_adapter *i2c,
+						 const struct xc5000_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig
new file mode 100644
index 0000000..069a3c1
--- /dev/null
+++ b/drivers/media/usb/Kconfig
@@ -0,0 +1,53 @@
+#
+# USB media device configuration
+#
+
+menu "Media USB Adapters"
+	visible if USB && MEDIA_SUPPORT
+
+if MEDIA_CAMERA_SUPPORT
+	comment "Webcam devices"
+source "drivers/media/usb/uvc/Kconfig"
+source "drivers/media/usb/gspca/Kconfig"
+source "drivers/media/usb/pwc/Kconfig"
+source "drivers/media/usb/cpia2/Kconfig"
+source "drivers/media/usb/zr364xx/Kconfig"
+source "drivers/media/usb/stkwebcam/Kconfig"
+source "drivers/media/usb/s2255/Kconfig"
+source "drivers/media/usb/sn9c102/Kconfig"
+endif
+
+if MEDIA_ANALOG_TV_SUPPORT
+	comment "Analog TV USB devices"
+source "drivers/media/usb/au0828/Kconfig"
+source "drivers/media/usb/pvrusb2/Kconfig"
+source "drivers/media/usb/hdpvr/Kconfig"
+source "drivers/media/usb/tlg2300/Kconfig"
+source "drivers/media/usb/usbvision/Kconfig"
+source "drivers/media/usb/stk1160/Kconfig"
+
+endif
+
+if (MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT)
+	comment "Analog/digital TV USB devices"
+source "drivers/media/usb/cx231xx/Kconfig"
+source "drivers/media/usb/tm6000/Kconfig"
+endif
+
+
+if I2C && MEDIA_DIGITAL_TV_SUPPORT
+	comment "Digital TV USB devices"
+source "drivers/media/usb/dvb-usb/Kconfig"
+source "drivers/media/usb/dvb-usb-v2/Kconfig"
+source "drivers/media/usb/ttusb-budget/Kconfig"
+source "drivers/media/usb/ttusb-dec/Kconfig"
+source "drivers/media/usb/siano/Kconfig"
+source "drivers/media/usb/b2c2/Kconfig"
+endif
+
+if (MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT)
+	comment "Webcam, TV (analog/digital) USB devices"
+source "drivers/media/usb/em28xx/Kconfig"
+endif
+
+endmenu
diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile
new file mode 100644
index 0000000..7f51d7e
--- /dev/null
+++ b/drivers/media/usb/Makefile
@@ -0,0 +1,22 @@
+#
+# Makefile for the USB media device drivers
+#
+
+# DVB USB-only drivers
+obj-y += ttusb-dec/ ttusb-budget/ dvb-usb/ dvb-usb-v2/ siano/ b2c2/
+obj-y += zr364xx/ stkwebcam/ s2255/
+
+obj-$(CONFIG_USB_VIDEO_CLASS)	+= uvc/
+obj-$(CONFIG_USB_GSPCA)         += gspca/
+obj-$(CONFIG_USB_PWC)           += pwc/
+obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
+obj-$(CONFIG_USB_SN9C102)       += sn9c102/
+obj-$(CONFIG_VIDEO_AU0828) += au0828/
+obj-$(CONFIG_VIDEO_HDPVR)	+= hdpvr/
+obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
+obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/
+obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
+obj-$(CONFIG_VIDEO_STK1160) += stk1160/
+obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
+obj-$(CONFIG_VIDEO_TM6000) += tm6000/
+obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig
new file mode 100644
index 0000000..23f7fd2
--- /dev/null
+++ b/drivers/media/usb/au0828/Kconfig
@@ -0,0 +1,18 @@
+
+config VIDEO_AU0828
+	tristate "Auvitek AU0828 support"
+	depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2
+	depends on DVB_CAPTURE_DRIVERS
+	select I2C_ALGOBIT
+	select VIDEO_TVEEPROM
+	select VIDEOBUF_VMALLOC
+	select DVB_AU8522_DTV if !DVB_FE_CUSTOMISE
+	select DVB_AU8522_V4L if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+	---help---
+	  This is a video4linux driver for Auvitek's USB device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called au0828
diff --git a/drivers/media/usb/au0828/Makefile b/drivers/media/usb/au0828/Makefile
new file mode 100644
index 0000000..98cc20c
--- /dev/null
+++ b/drivers/media/usb/au0828/Makefile
@@ -0,0 +1,9 @@
+au0828-objs	:= au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o au0828-vbi.o
+
+obj-$(CONFIG_VIDEO_AU0828) += au0828.o
+
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+
+ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c
new file mode 100644
index 0000000..448361c
--- /dev/null
+++ b/drivers/media/usb/au0828/au0828-cards.c
@@ -0,0 +1,339 @@
+/*
+ *  Driver for the Auvitek USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "au0828.h"
+#include "au0828-cards.h"
+#include "au8522.h"
+#include "media/tuner.h"
+#include "media/v4l2-common.h"
+
+void hvr950q_cs5340_audio(void *priv, int enable)
+{
+	/* Because the HVR-950q shares an i2s bus between the cs5340 and the
+	   au8522, we need to hold cs5340 in reset when using the au8522 */
+	struct au0828_dev *dev = priv;
+	if (enable == 1)
+		au0828_set(dev, REG_000, 0x10);
+	else
+		au0828_clear(dev, REG_000, 0x10);
+}
+
+struct au0828_board au0828_boards[] = {
+	[AU0828_BOARD_UNKNOWN] = {
+		.name	= "Unknown board",
+		.tuner_type = UNSET,
+		.tuner_addr = ADDR_UNSET,
+	},
+	[AU0828_BOARD_HAUPPAUGE_HVR850] = {
+		.name	= "Hauppauge HVR850",
+		.tuner_type = TUNER_XC5000,
+		.tuner_addr = 0x61,
+		.i2c_clk_divider = AU0828_I2C_CLK_20KHZ,
+		.input = {
+			{
+				.type = AU0828_VMUX_TELEVISION,
+				.vmux = AU8522_COMPOSITE_CH4_SIF,
+				.amux = AU8522_AUDIO_SIF,
+			},
+			{
+				.type = AU0828_VMUX_COMPOSITE,
+				.vmux = AU8522_COMPOSITE_CH1,
+				.amux = AU8522_AUDIO_NONE,
+				.audio_setup = hvr950q_cs5340_audio,
+			},
+			{
+				.type = AU0828_VMUX_SVIDEO,
+				.vmux = AU8522_SVIDEO_CH13,
+				.amux = AU8522_AUDIO_NONE,
+				.audio_setup = hvr950q_cs5340_audio,
+			},
+		},
+	},
+	[AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
+		.name	= "Hauppauge HVR950Q",
+		.tuner_type = TUNER_XC5000,
+		.tuner_addr = 0x61,
+		/* The au0828 hardware i2c implementation does not properly
+		   support the xc5000's i2c clock stretching.  So we need to
+		   lower the clock frequency enough where the 15us clock
+		   stretch fits inside of a normal clock cycle, or else the
+		   au0828 fails to set the STOP bit.  A 30 KHz clock puts the
+		   clock pulse width at 18us */
+		.i2c_clk_divider = AU0828_I2C_CLK_20KHZ,
+		.input = {
+			{
+				.type = AU0828_VMUX_TELEVISION,
+				.vmux = AU8522_COMPOSITE_CH4_SIF,
+				.amux = AU8522_AUDIO_SIF,
+			},
+			{
+				.type = AU0828_VMUX_COMPOSITE,
+				.vmux = AU8522_COMPOSITE_CH1,
+				.amux = AU8522_AUDIO_NONE,
+				.audio_setup = hvr950q_cs5340_audio,
+			},
+			{
+				.type = AU0828_VMUX_SVIDEO,
+				.vmux = AU8522_SVIDEO_CH13,
+				.amux = AU8522_AUDIO_NONE,
+				.audio_setup = hvr950q_cs5340_audio,
+			},
+		},
+	},
+	[AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = {
+		.name	= "Hauppauge HVR950Q rev xxF8",
+		.tuner_type = UNSET,
+		.tuner_addr = ADDR_UNSET,
+		.i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
+	},
+	[AU0828_BOARD_DVICO_FUSIONHDTV7] = {
+		.name	= "DViCO FusionHDTV USB",
+		.tuner_type = UNSET,
+		.tuner_addr = ADDR_UNSET,
+		.i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
+	},
+	[AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
+		.name = "Hauppauge Woodbury",
+		.tuner_type = UNSET,
+		.tuner_addr = ADDR_UNSET,
+		.i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
+	},
+};
+
+/* Tuner callback function for au0828 boards. Currently only needed
+ * for HVR1500Q, which has an xc5000 tuner.
+ */
+int au0828_tuner_callback(void *priv, int component, int command, int arg)
+{
+	struct au0828_dev *dev = priv;
+
+	dprintk(1, "%s()\n", __func__);
+
+	switch (dev->boardnr) {
+	case AU0828_BOARD_HAUPPAUGE_HVR850:
+	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+	case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+	case AU0828_BOARD_DVICO_FUSIONHDTV7:
+		if (command == 0) {
+			/* Tuner Reset Command from xc5000 */
+			/* Drive the tuner into reset and out */
+			au0828_clear(dev, REG_001, 2);
+			mdelay(10);
+			au0828_set(dev, REG_001, 2);
+			mdelay(10);
+			return 0;
+		} else {
+			printk(KERN_ERR
+				"%s(): Unknown command.\n", __func__);
+			return -EINVAL;
+		}
+		break;
+	}
+
+	return 0; /* Should never be here */
+}
+
+static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
+{
+	struct tveeprom tv;
+
+	tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
+	dev->board.tuner_type = tv.tuner_type;
+
+	/* Make sure we support the board model */
+	switch (tv.model) {
+	case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */
+	case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
+	case 72101: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
+	case 72201: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+	case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+	case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+	case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+	case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
+	case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
+	case 72261: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+	case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and analog video */
+	case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
+		break;
+	default:
+		printk(KERN_WARNING "%s: warning: "
+		       "unknown hauppauge model #%d\n", __func__, tv.model);
+		break;
+	}
+
+	printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+	       __func__, tv.model);
+}
+
+void au0828_card_setup(struct au0828_dev *dev)
+{
+	static u8 eeprom[256];
+	struct tuner_setup tun_setup;
+	struct v4l2_subdev *sd;
+	unsigned int mode_mask = T_ANALOG_TV;
+
+	dprintk(1, "%s()\n", __func__);
+
+	memcpy(&dev->board, &au0828_boards[dev->boardnr], sizeof(dev->board));
+
+	if (dev->i2c_rc == 0) {
+		dev->i2c_client.addr = 0xa0 >> 1;
+		tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom));
+	}
+
+	switch (dev->boardnr) {
+	case AU0828_BOARD_HAUPPAUGE_HVR850:
+	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+	case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+	case AU0828_BOARD_HAUPPAUGE_WOODBURY:
+		if (dev->i2c_rc == 0)
+			hauppauge_eeprom(dev, eeprom+0xa0);
+		break;
+	}
+
+	if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
+		/* Load the analog demodulator driver (note this would need to
+		   be abstracted out if we ever need to support a different
+		   demod) */
+		sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+				"au8522", 0x8e >> 1, NULL);
+		if (sd == NULL)
+			printk(KERN_ERR "analog subdev registration failed\n");
+	}
+
+	/* Setup tuners */
+	if (dev->board.tuner_type != TUNER_ABSENT) {
+		/* Load the tuner module, which does the attach */
+		sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+				"tuner", dev->board.tuner_addr, NULL);
+		if (sd == NULL)
+			printk(KERN_ERR "tuner subdev registration fail\n");
+
+		tun_setup.mode_mask      = mode_mask;
+		tun_setup.type           = dev->board.tuner_type;
+		tun_setup.addr           = dev->board.tuner_addr;
+		tun_setup.tuner_callback = au0828_tuner_callback;
+		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr,
+				     &tun_setup);
+	}
+}
+
+/*
+ * The bridge has between 8 and 12 gpios.
+ * Regs 1 and 0 deal with output enables.
+ * Regs 3 and 2 deal with direction.
+ */
+void au0828_gpio_setup(struct au0828_dev *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+
+	switch (dev->boardnr) {
+	case AU0828_BOARD_HAUPPAUGE_HVR850:
+	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+	case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+	case AU0828_BOARD_HAUPPAUGE_WOODBURY:
+		/* GPIO's
+		 * 4 - CS5340
+		 * 5 - AU8522 Demodulator
+		 * 6 - eeprom W/P
+		 * 7 - power supply
+		 * 9 - XC5000 Tuner
+		 */
+
+		/* Into reset */
+		au0828_write(dev, REG_003, 0x02);
+		au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
+		au0828_write(dev, REG_001, 0x0);
+		au0828_write(dev, REG_000, 0x0);
+		msleep(100);
+
+		/* Out of reset (leave the cs5340 in reset until needed) */
+		au0828_write(dev, REG_003, 0x02);
+		au0828_write(dev, REG_001, 0x02);
+		au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
+		au0828_write(dev, REG_000, 0x80 | 0x40 | 0x20);
+
+		msleep(250);
+		break;
+	case AU0828_BOARD_DVICO_FUSIONHDTV7:
+		/* GPIO's
+		 * 6 - ?
+		 * 8 - AU8522 Demodulator
+		 * 9 - XC5000 Tuner
+		 */
+
+		/* Into reset */
+		au0828_write(dev, REG_003, 0x02);
+		au0828_write(dev, REG_002, 0xa0);
+		au0828_write(dev, REG_001, 0x0);
+		au0828_write(dev, REG_000, 0x0);
+		msleep(100);
+
+		/* Out of reset */
+		au0828_write(dev, REG_003, 0x02);
+		au0828_write(dev, REG_002, 0xa0);
+		au0828_write(dev, REG_001, 0x02);
+		au0828_write(dev, REG_000, 0xa0);
+		msleep(250);
+		break;
+	}
+}
+
+/* table of devices that work with this driver */
+struct usb_device_id au0828_usb_id_table[] = {
+	{ USB_DEVICE(0x2040, 0x7200),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x7240),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 },
+	{ USB_DEVICE(0x0fe9, 0xd620),
+		.driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 },
+	{ USB_DEVICE(0x2040, 0x7210),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x7217),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x721b),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x721e),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x721f),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x7280),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x0fd9, 0x0008),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x7201),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
+	{ USB_DEVICE(0x2040, 0x7211),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
+	{ USB_DEVICE(0x2040, 0x7281),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
+	{ USB_DEVICE(0x05e1, 0x0480),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
+	{ USB_DEVICE(0x2040, 0x8200),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
+	{ USB_DEVICE(0x2040, 0x7260),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x7213),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(usb, au0828_usb_id_table);
diff --git a/drivers/media/usb/au0828/au0828-cards.h b/drivers/media/usb/au0828/au0828-cards.h
new file mode 100644
index 0000000..48a1882
--- /dev/null
+++ b/drivers/media/usb/au0828/au0828-cards.h
@@ -0,0 +1,27 @@
+/*
+ *  Driver for the Auvitek USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define AU0828_BOARD_UNKNOWN		0
+#define AU0828_BOARD_HAUPPAUGE_HVR950Q	1
+#define AU0828_BOARD_HAUPPAUGE_HVR850 	2
+#define AU0828_BOARD_DVICO_FUSIONHDTV7	3
+#define AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL	4
+#define AU0828_BOARD_HAUPPAUGE_WOODBURY	5
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
new file mode 100644
index 0000000..745a80a
--- /dev/null
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -0,0 +1,282 @@
+/*
+ *  Driver for the Auvitek USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/mutex.h>
+
+#include "au0828.h"
+
+/*
+ * 1 = General debug messages
+ * 2 = USB handling
+ * 4 = I2C related
+ * 8 = Bridge related
+ */
+int au0828_debug;
+module_param_named(debug, au0828_debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+static unsigned int disable_usb_speed_check;
+module_param(disable_usb_speed_check, int, 0444);
+MODULE_PARM_DESC(disable_usb_speed_check,
+		 "override min bandwidth requirement of 480M bps");
+
+#define _AU0828_BULKPIPE 0x03
+#define _BULKPIPESIZE 0xffff
+
+static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+			    u16 index);
+static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+	u16 index, unsigned char *cp, u16 size);
+
+/* USB Direction */
+#define CMD_REQUEST_IN		0x00
+#define CMD_REQUEST_OUT		0x01
+
+u32 au0828_readreg(struct au0828_dev *dev, u16 reg)
+{
+	u8 result = 0;
+
+	recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, &result, 1);
+	dprintk(8, "%s(0x%04x) = 0x%02x\n", __func__, reg, result);
+
+	return result;
+}
+
+u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
+{
+	dprintk(8, "%s(0x%04x, 0x%02x)\n", __func__, reg, val);
+	return send_control_msg(dev, CMD_REQUEST_OUT, val, reg);
+}
+
+static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+	u16 index)
+{
+	int status = -ENODEV;
+
+	if (dev->usbdev) {
+
+		/* cp must be memory that has been allocated by kmalloc */
+		status = usb_control_msg(dev->usbdev,
+				usb_sndctrlpipe(dev->usbdev, 0),
+				request,
+				USB_DIR_OUT | USB_TYPE_VENDOR |
+					USB_RECIP_DEVICE,
+				value, index, NULL, 0, 1000);
+
+		status = min(status, 0);
+
+		if (status < 0) {
+			printk(KERN_ERR "%s() Failed sending control message, error %d.\n",
+				__func__, status);
+		}
+
+	}
+
+	return status;
+}
+
+static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+	u16 index, unsigned char *cp, u16 size)
+{
+	int status = -ENODEV;
+	mutex_lock(&dev->mutex);
+	if (dev->usbdev) {
+		status = usb_control_msg(dev->usbdev,
+				usb_rcvctrlpipe(dev->usbdev, 0),
+				request,
+				USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+				value, index,
+				dev->ctrlmsg, size, 1000);
+
+		status = min(status, 0);
+
+		if (status < 0) {
+			printk(KERN_ERR "%s() Failed receiving control message, error %d.\n",
+				__func__, status);
+		}
+
+		/* the host controller requires heap allocated memory, which
+		   is why we didn't just pass "cp" into usb_control_msg */
+		memcpy(cp, dev->ctrlmsg, size);
+	}
+	mutex_unlock(&dev->mutex);
+	return status;
+}
+
+static void au0828_usb_disconnect(struct usb_interface *interface)
+{
+	struct au0828_dev *dev = usb_get_intfdata(interface);
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* Digital TV */
+	au0828_dvb_unregister(dev);
+
+	if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
+		au0828_analog_unregister(dev);
+
+	/* I2C */
+	au0828_i2c_unregister(dev);
+
+	v4l2_device_unregister(&dev->v4l2_dev);
+
+	usb_set_intfdata(interface, NULL);
+
+	mutex_lock(&dev->mutex);
+	dev->usbdev = NULL;
+	mutex_unlock(&dev->mutex);
+
+	kfree(dev);
+
+}
+
+static int au0828_usb_probe(struct usb_interface *interface,
+	const struct usb_device_id *id)
+{
+	int ifnum, retval;
+	struct au0828_dev *dev;
+	struct usb_device *usbdev = interface_to_usbdev(interface);
+
+	ifnum = interface->altsetting->desc.bInterfaceNumber;
+
+	if (ifnum != 0)
+		return -ENODEV;
+
+	dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__,
+		le16_to_cpu(usbdev->descriptor.idVendor),
+		le16_to_cpu(usbdev->descriptor.idProduct),
+		ifnum);
+
+	/*
+	 * Make sure we have 480 Mbps of bandwidth, otherwise things like
+	 * video stream wouldn't likely work, since 12 Mbps is generally
+	 * not enough even for most Digital TV streams.
+	 */
+	if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
+		printk(KERN_ERR "au0828: Device initialization failed.\n");
+		printk(KERN_ERR "au0828: Device must be connected to a "
+		       "high-speed USB 2.0 port.\n");
+		return -ENODEV;
+	}
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL) {
+		printk(KERN_ERR "%s() Unable to allocate memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&dev->lock);
+	mutex_lock(&dev->lock);
+	mutex_init(&dev->mutex);
+	mutex_init(&dev->dvb.lock);
+	dev->usbdev = usbdev;
+	dev->boardnr = id->driver_info;
+
+	/* Create the v4l2_device */
+	retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
+	if (retval) {
+		printk(KERN_ERR "%s() v4l2_device_register failed\n",
+		       __func__);
+		mutex_unlock(&dev->lock);
+		kfree(dev);
+		return -EIO;
+	}
+
+	/* Power Up the bridge */
+	au0828_write(dev, REG_600, 1 << 4);
+
+	/* Bring up the GPIO's and supporting devices */
+	au0828_gpio_setup(dev);
+
+	/* I2C */
+	au0828_i2c_register(dev);
+
+	/* Setup */
+	au0828_card_setup(dev);
+
+	/* Analog TV */
+	if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
+		au0828_analog_register(dev, interface);
+
+	/* Digital TV */
+	au0828_dvb_register(dev);
+
+	/* Store the pointer to the au0828_dev so it can be accessed in
+	   au0828_usb_disconnect */
+	usb_set_intfdata(interface, dev);
+
+	printk(KERN_INFO "Registered device AU0828 [%s]\n",
+		dev->board.name == NULL ? "Unset" : dev->board.name);
+
+	mutex_unlock(&dev->lock);
+
+	return 0;
+}
+
+static struct usb_driver au0828_usb_driver = {
+	.name		= DRIVER_NAME,
+	.probe		= au0828_usb_probe,
+	.disconnect	= au0828_usb_disconnect,
+	.id_table	= au0828_usb_id_table,
+};
+
+static int __init au0828_init(void)
+{
+	int ret;
+
+	if (au0828_debug & 1)
+		printk(KERN_INFO "%s() Debugging is enabled\n", __func__);
+
+	if (au0828_debug & 2)
+		printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__);
+
+	if (au0828_debug & 4)
+		printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__);
+
+	if (au0828_debug & 8)
+		printk(KERN_INFO "%s() Bridge Debugging is enabled\n",
+		       __func__);
+
+	printk(KERN_INFO "au0828 driver loaded\n");
+
+	ret = usb_register(&au0828_usb_driver);
+	if (ret)
+		printk(KERN_ERR "usb_register failed, error = %d\n", ret);
+
+	return ret;
+}
+
+static void __exit au0828_exit(void)
+{
+	usb_deregister(&au0828_usb_driver);
+}
+
+module_init(au0828_init);
+module_exit(au0828_exit);
+
+MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
+MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.2");
diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c
new file mode 100644
index 0000000..b328f65
--- /dev/null
+++ b/drivers/media/usb/au0828/au0828-dvb.c
@@ -0,0 +1,500 @@
+/*
+ *  Driver for the Auvitek USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/suspend.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+
+#include "au0828.h"
+#include "au8522.h"
+#include "xc5000.h"
+#include "mxl5007t.h"
+#include "tda18271.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define _AU0828_BULKPIPE 0x83
+#define _BULKPIPESIZE 0xe522
+
+static u8 hauppauge_hvr950q_led_states[] = {
+	0x00, /* off */
+	0x02, /* yellow */
+	0x04, /* green */
+};
+
+static struct au8522_led_config hauppauge_hvr950q_led_cfg = {
+	.gpio_output = 0x00e0,
+	.gpio_output_enable  = 0x6006,
+	.gpio_output_disable = 0x0660,
+
+	.gpio_leds = 0x00e2,
+	.led_states  = hauppauge_hvr950q_led_states,
+	.num_led_states = sizeof(hauppauge_hvr950q_led_states),
+
+	.vsb8_strong   = 20 /* dB */ * 10,
+	.qam64_strong  = 25 /* dB */ * 10,
+	.qam256_strong = 32 /* dB */ * 10,
+};
+
+static struct au8522_config hauppauge_hvr950q_config = {
+	.demod_address = 0x8e >> 1,
+	.status_mode   = AU8522_DEMODLOCKING,
+	.qam_if        = AU8522_IF_6MHZ,
+	.vsb_if        = AU8522_IF_6MHZ,
+	.led_cfg       = &hauppauge_hvr950q_led_cfg,
+};
+
+static struct au8522_config fusionhdtv7usb_config = {
+	.demod_address = 0x8e >> 1,
+	.status_mode   = AU8522_DEMODLOCKING,
+	.qam_if        = AU8522_IF_6MHZ,
+	.vsb_if        = AU8522_IF_6MHZ,
+};
+
+static struct au8522_config hauppauge_woodbury_config = {
+	.demod_address = 0x8e >> 1,
+	.status_mode   = AU8522_DEMODLOCKING,
+	.qam_if        = AU8522_IF_4MHZ,
+	.vsb_if        = AU8522_IF_3_25MHZ,
+};
+
+static struct xc5000_config hauppauge_xc5000a_config = {
+	.i2c_address      = 0x61,
+	.if_khz           = 6000,
+	.chip_id          = XC5000A,
+};
+
+static struct xc5000_config hauppauge_xc5000c_config = {
+	.i2c_address      = 0x61,
+	.if_khz           = 6000,
+	.chip_id          = XC5000C,
+};
+
+static struct mxl5007t_config mxl5007t_hvr950q_config = {
+	.xtal_freq_hz = MxL_XTAL_24_MHZ,
+	.if_freq_hz = MxL_IF_6_MHZ,
+};
+
+static struct tda18271_config hauppauge_woodbury_tunerconfig = {
+	.gate    = TDA18271_GATE_DIGITAL,
+};
+
+static void au0828_restart_dvb_streaming(struct work_struct *work);
+
+/*-------------------------------------------------------------------*/
+static void urb_completion(struct urb *purb)
+{
+	struct au0828_dev *dev = purb->context;
+	int ptype = usb_pipetype(purb->pipe);
+	unsigned char *ptr;
+
+	dprintk(2, "%s()\n", __func__);
+
+	if (!dev)
+		return;
+
+	if (dev->urb_streaming == 0)
+		return;
+
+	if (ptype != PIPE_BULK) {
+		printk(KERN_ERR "%s() Unsupported URB type %d\n",
+		       __func__, ptype);
+		return;
+	}
+
+	/* See if the stream is corrupted (to work around a hardware
+	   bug where the stream gets misaligned */
+	ptr = purb->transfer_buffer;
+	if (purb->actual_length > 0 && ptr[0] != 0x47) {
+		dprintk(1, "Need to restart streaming %02x len=%d!\n",
+			ptr[0], purb->actual_length);
+		schedule_work(&dev->restart_streaming);
+		return;
+	}
+
+	/* Feed the transport payload into the kernel demux */
+	dvb_dmx_swfilter_packets(&dev->dvb.demux,
+		purb->transfer_buffer, purb->actual_length / 188);
+
+	/* Clean the buffer before we requeue */
+	memset(purb->transfer_buffer, 0, URB_BUFSIZE);
+
+	/* Requeue URB */
+	usb_submit_urb(purb, GFP_ATOMIC);
+}
+
+static int stop_urb_transfer(struct au0828_dev *dev)
+{
+	int i;
+
+	dprintk(2, "%s()\n", __func__);
+
+	dev->urb_streaming = 0;
+	for (i = 0; i < URB_COUNT; i++) {
+		usb_kill_urb(dev->urbs[i]);
+		kfree(dev->urbs[i]->transfer_buffer);
+		usb_free_urb(dev->urbs[i]);
+	}
+
+	return 0;
+}
+
+static int start_urb_transfer(struct au0828_dev *dev)
+{
+	struct urb *purb;
+	int i, ret = -ENOMEM;
+
+	dprintk(2, "%s()\n", __func__);
+
+	if (dev->urb_streaming) {
+		dprintk(2, "%s: bulk xfer already running!\n", __func__);
+		return 0;
+	}
+
+	for (i = 0; i < URB_COUNT; i++) {
+
+		dev->urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
+		if (!dev->urbs[i])
+			goto err;
+
+		purb = dev->urbs[i];
+
+		purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL);
+		if (!purb->transfer_buffer) {
+			usb_free_urb(purb);
+			dev->urbs[i] = NULL;
+			goto err;
+		}
+
+		purb->status = -EINPROGRESS;
+		usb_fill_bulk_urb(purb,
+				  dev->usbdev,
+				  usb_rcvbulkpipe(dev->usbdev,
+					_AU0828_BULKPIPE),
+				  purb->transfer_buffer,
+				  URB_BUFSIZE,
+				  urb_completion,
+				  dev);
+
+	}
+
+	for (i = 0; i < URB_COUNT; i++) {
+		ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC);
+		if (ret != 0) {
+			stop_urb_transfer(dev);
+			printk(KERN_ERR "%s: failed urb submission, "
+			       "err = %d\n", __func__, ret);
+			return ret;
+		}
+	}
+
+	dev->urb_streaming = 1;
+	ret = 0;
+
+err:
+	return ret;
+}
+
+static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
+	struct au0828_dvb *dvb = &dev->dvb;
+	int ret = 0;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (!demux->dmx.frontend)
+		return -EINVAL;
+
+	if (dvb) {
+		mutex_lock(&dvb->lock);
+		if (dvb->feeding++ == 0) {
+			/* Start transport */
+			au0828_write(dev, 0x608, 0x90);
+			au0828_write(dev, 0x609, 0x72);
+			au0828_write(dev, 0x60a, 0x71);
+			au0828_write(dev, 0x60b, 0x01);
+			ret = start_urb_transfer(dev);
+		}
+		mutex_unlock(&dvb->lock);
+	}
+
+	return ret;
+}
+
+static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
+	struct au0828_dvb *dvb = &dev->dvb;
+	int ret = 0;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (dvb) {
+		mutex_lock(&dvb->lock);
+		if (--dvb->feeding == 0) {
+			/* Stop transport */
+			ret = stop_urb_transfer(dev);
+			au0828_write(dev, 0x60b, 0x00);
+		}
+		mutex_unlock(&dvb->lock);
+	}
+
+	return ret;
+}
+
+static void au0828_restart_dvb_streaming(struct work_struct *work)
+{
+	struct au0828_dev *dev = container_of(work, struct au0828_dev,
+					      restart_streaming);
+	struct au0828_dvb *dvb = &dev->dvb;
+	int ret;
+
+	if (dev->urb_streaming == 0)
+		return;
+
+	dprintk(1, "Restarting streaming...!\n");
+
+	mutex_lock(&dvb->lock);
+
+	/* Stop transport */
+	ret = stop_urb_transfer(dev);
+	au0828_write(dev, 0x608, 0x00);
+	au0828_write(dev, 0x609, 0x00);
+	au0828_write(dev, 0x60a, 0x00);
+	au0828_write(dev, 0x60b, 0x00);
+
+	/* Start transport */
+	au0828_write(dev, 0x608, 0x90);
+	au0828_write(dev, 0x609, 0x72);
+	au0828_write(dev, 0x60a, 0x71);
+	au0828_write(dev, 0x60b, 0x01);
+	ret = start_urb_transfer(dev);
+
+	mutex_unlock(&dvb->lock);
+}
+
+static int dvb_register(struct au0828_dev *dev)
+{
+	struct au0828_dvb *dvb = &dev->dvb;
+	int result;
+
+	dprintk(1, "%s()\n", __func__);
+
+	INIT_WORK(&dev->restart_streaming, au0828_restart_dvb_streaming);
+
+	/* register adapter */
+	result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE,
+				      &dev->usbdev->dev, adapter_nr);
+	if (result < 0) {
+		printk(KERN_ERR "%s: dvb_register_adapter failed "
+		       "(errno = %d)\n", DRIVER_NAME, result);
+		goto fail_adapter;
+	}
+	dvb->adapter.priv = dev;
+
+	/* register frontend */
+	result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+	if (result < 0) {
+		printk(KERN_ERR "%s: dvb_register_frontend failed "
+		       "(errno = %d)\n", DRIVER_NAME, result);
+		goto fail_frontend;
+	}
+
+	/* register demux stuff */
+	dvb->demux.dmx.capabilities =
+		DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+		DMX_MEMORY_BASED_FILTERING;
+	dvb->demux.priv       = dev;
+	dvb->demux.filternum  = 256;
+	dvb->demux.feednum    = 256;
+	dvb->demux.start_feed = au0828_dvb_start_feed;
+	dvb->demux.stop_feed  = au0828_dvb_stop_feed;
+	result = dvb_dmx_init(&dvb->demux);
+	if (result < 0) {
+		printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n",
+		       DRIVER_NAME, result);
+		goto fail_dmx;
+	}
+
+	dvb->dmxdev.filternum    = 256;
+	dvb->dmxdev.demux        = &dvb->demux.dmx;
+	dvb->dmxdev.capabilities = 0;
+	result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+	if (result < 0) {
+		printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n",
+		       DRIVER_NAME, result);
+		goto fail_dmxdev;
+	}
+
+	dvb->fe_hw.source = DMX_FRONTEND_0;
+	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	if (result < 0) {
+		printk(KERN_ERR "%s: add_frontend failed "
+		       "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result);
+		goto fail_fe_hw;
+	}
+
+	dvb->fe_mem.source = DMX_MEMORY_FE;
+	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+	if (result < 0) {
+		printk(KERN_ERR "%s: add_frontend failed "
+		       "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result);
+		goto fail_fe_mem;
+	}
+
+	result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	if (result < 0) {
+		printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n",
+		       DRIVER_NAME, result);
+		goto fail_fe_conn;
+	}
+
+	/* register network adapter */
+	dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+	return 0;
+
+fail_fe_conn:
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+fail_fe_mem:
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+fail_fe_hw:
+	dvb_dmxdev_release(&dvb->dmxdev);
+fail_dmxdev:
+	dvb_dmx_release(&dvb->demux);
+fail_dmx:
+	dvb_unregister_frontend(dvb->frontend);
+fail_frontend:
+	dvb_frontend_detach(dvb->frontend);
+	dvb_unregister_adapter(&dvb->adapter);
+fail_adapter:
+	return result;
+}
+
+void au0828_dvb_unregister(struct au0828_dev *dev)
+{
+	struct au0828_dvb *dvb = &dev->dvb;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (dvb->frontend == NULL)
+		return;
+
+	dvb_net_release(&dvb->net);
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	dvb_dmxdev_release(&dvb->dmxdev);
+	dvb_dmx_release(&dvb->demux);
+	dvb_unregister_frontend(dvb->frontend);
+	dvb_frontend_detach(dvb->frontend);
+	dvb_unregister_adapter(&dvb->adapter);
+}
+
+/* All the DVB attach calls go here, this function get's modified
+ * for each new card. No other function in this file needs
+ * to change.
+ */
+int au0828_dvb_register(struct au0828_dev *dev)
+{
+	struct au0828_dvb *dvb = &dev->dvb;
+	int ret;
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* init frontend */
+	switch (dev->boardnr) {
+	case AU0828_BOARD_HAUPPAUGE_HVR850:
+	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+		dvb->frontend = dvb_attach(au8522_attach,
+				&hauppauge_hvr950q_config,
+				&dev->i2c_adap);
+		if (dvb->frontend != NULL)
+			switch (dev->board.tuner_type) {
+			default:
+			case TUNER_XC5000:
+				dvb_attach(xc5000_attach, dvb->frontend,
+					   &dev->i2c_adap,
+					   &hauppauge_xc5000a_config);
+				break;
+			case TUNER_XC5000C:
+				dvb_attach(xc5000_attach, dvb->frontend,
+					   &dev->i2c_adap,
+					   &hauppauge_xc5000c_config);
+				break;
+			}
+		break;
+	case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+		dvb->frontend = dvb_attach(au8522_attach,
+				&hauppauge_hvr950q_config,
+				&dev->i2c_adap);
+		if (dvb->frontend != NULL)
+			dvb_attach(mxl5007t_attach, dvb->frontend,
+				   &dev->i2c_adap, 0x60,
+				   &mxl5007t_hvr950q_config);
+		break;
+	case AU0828_BOARD_HAUPPAUGE_WOODBURY:
+		dvb->frontend = dvb_attach(au8522_attach,
+				&hauppauge_woodbury_config,
+				&dev->i2c_adap);
+		if (dvb->frontend != NULL)
+			dvb_attach(tda18271_attach, dvb->frontend,
+				   0x60, &dev->i2c_adap,
+				   &hauppauge_woodbury_tunerconfig);
+		break;
+	case AU0828_BOARD_DVICO_FUSIONHDTV7:
+		dvb->frontend = dvb_attach(au8522_attach,
+				&fusionhdtv7usb_config,
+				&dev->i2c_adap);
+		if (dvb->frontend != NULL) {
+			dvb_attach(xc5000_attach, dvb->frontend,
+				&dev->i2c_adap,
+				&hauppauge_xc5000a_config);
+		}
+		break;
+	default:
+		printk(KERN_WARNING "The frontend of your DVB/ATSC card "
+		       "isn't supported yet\n");
+		break;
+	}
+	if (NULL == dvb->frontend) {
+		printk(KERN_ERR "%s() Frontend initialization failed\n",
+		       __func__);
+		return -1;
+	}
+	/* define general-purpose callback pointer */
+	dvb->frontend->callback = au0828_tuner_callback;
+
+	/* register everything */
+	ret = dvb_register(dev);
+	if (ret < 0) {
+		if (dvb->frontend->ops.release)
+			dvb->frontend->ops.release(dvb->frontend);
+		return ret;
+	}
+
+	return 0;
+}
diff --git a/drivers/media/usb/au0828/au0828-i2c.c b/drivers/media/usb/au0828/au0828-i2c.c
new file mode 100644
index 0000000..4ded17f
--- /dev/null
+++ b/drivers/media/usb/au0828/au0828-i2c.c
@@ -0,0 +1,401 @@
+/*
+ *  Driver for the Auvitek AU0828 USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "au0828.h"
+#include "media/tuner.h"
+#include <media/v4l2-common.h>
+
+static int i2c_scan;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+#define I2C_WAIT_DELAY 25
+#define I2C_WAIT_RETRY 1000
+
+static inline int i2c_slave_did_write_ack(struct i2c_adapter *i2c_adap)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	return au0828_read(dev, AU0828_I2C_STATUS_201) &
+		AU0828_I2C_STATUS_NO_WRITE_ACK ? 0 : 1;
+}
+
+static inline int i2c_slave_did_read_ack(struct i2c_adapter *i2c_adap)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	return au0828_read(dev, AU0828_I2C_STATUS_201) &
+		AU0828_I2C_STATUS_NO_READ_ACK ? 0 : 1;
+}
+
+static int i2c_wait_read_ack(struct i2c_adapter *i2c_adap)
+{
+	int count;
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		if (!i2c_slave_did_read_ack(i2c_adap))
+			break;
+		udelay(I2C_WAIT_DELAY);
+	}
+
+	if (I2C_WAIT_RETRY == count)
+		return 0;
+
+	return 1;
+}
+
+static inline int i2c_is_read_busy(struct i2c_adapter *i2c_adap)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	return au0828_read(dev, AU0828_I2C_STATUS_201) &
+		AU0828_I2C_STATUS_READ_DONE ? 0 : 1;
+}
+
+static int i2c_wait_read_done(struct i2c_adapter *i2c_adap)
+{
+	int count;
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		if (!i2c_is_read_busy(i2c_adap))
+			break;
+		udelay(I2C_WAIT_DELAY);
+	}
+
+	if (I2C_WAIT_RETRY == count)
+		return 0;
+
+	return 1;
+}
+
+static inline int i2c_is_write_done(struct i2c_adapter *i2c_adap)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	return au0828_read(dev, AU0828_I2C_STATUS_201) &
+		AU0828_I2C_STATUS_WRITE_DONE ? 1 : 0;
+}
+
+static int i2c_wait_write_done(struct i2c_adapter *i2c_adap)
+{
+	int count;
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		if (i2c_is_write_done(i2c_adap))
+			break;
+		udelay(I2C_WAIT_DELAY);
+	}
+
+	if (I2C_WAIT_RETRY == count)
+		return 0;
+
+	return 1;
+}
+
+static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	return au0828_read(dev, AU0828_I2C_STATUS_201) &
+		AU0828_I2C_STATUS_BUSY ? 1 : 0;
+}
+
+static int i2c_wait_done(struct i2c_adapter *i2c_adap)
+{
+	int count;
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		if (!i2c_is_busy(i2c_adap))
+			break;
+		udelay(I2C_WAIT_DELAY);
+	}
+
+	if (I2C_WAIT_RETRY == count)
+		return 0;
+
+	return 1;
+}
+
+/* FIXME: Implement join handling correctly */
+static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
+	const struct i2c_msg *msg, int joined_rlen)
+{
+	int i, strobe = 0;
+	struct au0828_dev *dev = i2c_adap->algo_data;
+
+	dprintk(4, "%s()\n", __func__);
+
+	au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
+
+	/* Set the I2C clock */
+	if (((dev->board.tuner_type == TUNER_XC5000) ||
+	     (dev->board.tuner_type == TUNER_XC5000C)) &&
+	    (dev->board.tuner_addr == msg->addr) &&
+	    (msg->len == 64)) {
+		/* Hack to speed up firmware load.  The xc5000 lets us do up
+		   to 400 KHz when in firmware download mode */
+		au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
+			     AU0828_I2C_CLK_250KHZ);
+	} else {
+		/* Use the i2c clock speed in the board configuration */
+		au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
+			     dev->board.i2c_clk_divider);
+	}
+
+	/* Hardware needs 8 bit addresses */
+	au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1);
+
+	dprintk(4, "SEND: %02x\n", msg->addr);
+
+	/* Deal with i2c_scan */
+	if (msg->len == 0) {
+		/* The analog tuner detection code makes use of the SMBUS_QUICK
+		   message (which involves a zero length i2c write).  To avoid
+		   checking the status register when we didn't strobe out any
+		   actual bytes to the bus, just do a read check.  This is
+		   consistent with how I saw i2c device checking done in the
+		   USB trace of the Windows driver */
+		au0828_write(dev, AU0828_I2C_TRIGGER_200,
+			     AU0828_I2C_TRIGGER_READ);
+
+		if (!i2c_wait_done(i2c_adap))
+			return -EIO;
+
+		if (i2c_wait_read_ack(i2c_adap))
+			return -EIO;
+
+		return 0;
+	}
+
+	for (i = 0; i < msg->len;) {
+
+		dprintk(4, " %02x\n", msg->buf[i]);
+
+		au0828_write(dev, AU0828_I2C_WRITE_FIFO_205, msg->buf[i]);
+
+		strobe++;
+		i++;
+
+		if ((strobe >= 4) || (i >= msg->len)) {
+
+			/* Strobe the byte into the bus */
+			if (i < msg->len)
+				au0828_write(dev, AU0828_I2C_TRIGGER_200,
+					     AU0828_I2C_TRIGGER_WRITE |
+					     AU0828_I2C_TRIGGER_HOLD);
+			else
+				au0828_write(dev, AU0828_I2C_TRIGGER_200,
+					     AU0828_I2C_TRIGGER_WRITE);
+
+			/* Reset strobe trigger */
+			strobe = 0;
+
+			if (!i2c_wait_write_done(i2c_adap))
+				return -EIO;
+
+		}
+
+	}
+	if (!i2c_wait_done(i2c_adap))
+		return -EIO;
+
+	dprintk(4, "\n");
+
+	return msg->len;
+}
+
+/* FIXME: Implement join handling correctly */
+static int i2c_readbytes(struct i2c_adapter *i2c_adap,
+	const struct i2c_msg *msg, int joined)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	int i;
+
+	dprintk(4, "%s()\n", __func__);
+
+	au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
+
+	/* Set the I2C clock */
+	au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
+		     dev->board.i2c_clk_divider);
+
+	/* Hardware needs 8 bit addresses */
+	au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1);
+
+	dprintk(4, " RECV:\n");
+
+	/* Deal with i2c_scan */
+	if (msg->len == 0) {
+		au0828_write(dev, AU0828_I2C_TRIGGER_200,
+			     AU0828_I2C_TRIGGER_READ);
+
+		if (i2c_wait_read_ack(i2c_adap))
+			return -EIO;
+		return 0;
+	}
+
+	for (i = 0; i < msg->len;) {
+
+		i++;
+
+		if (i < msg->len)
+			au0828_write(dev, AU0828_I2C_TRIGGER_200,
+				     AU0828_I2C_TRIGGER_READ |
+				     AU0828_I2C_TRIGGER_HOLD);
+		else
+			au0828_write(dev, AU0828_I2C_TRIGGER_200,
+				     AU0828_I2C_TRIGGER_READ);
+
+		if (!i2c_wait_read_done(i2c_adap))
+			return -EIO;
+
+		msg->buf[i-1] = au0828_read(dev, AU0828_I2C_READ_FIFO_209) &
+			0xff;
+
+		dprintk(4, " %02x\n", msg->buf[i-1]);
+	}
+	if (!i2c_wait_done(i2c_adap))
+		return -EIO;
+
+	dprintk(4, "\n");
+
+	return msg->len;
+}
+
+static int i2c_xfer(struct i2c_adapter *i2c_adap,
+		    struct i2c_msg *msgs, int num)
+{
+	int i, retval = 0;
+
+	dprintk(4, "%s(num = %d)\n", __func__, num);
+
+	for (i = 0; i < num; i++) {
+		dprintk(4, "%s(num = %d) addr = 0x%02x  len = 0x%x\n",
+			__func__, num, msgs[i].addr, msgs[i].len);
+		if (msgs[i].flags & I2C_M_RD) {
+			/* read */
+			retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
+		} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
+			   msgs[i].addr == msgs[i + 1].addr) {
+			/* write then read from same address */
+			retval = i2c_sendbytes(i2c_adap, &msgs[i],
+					       msgs[i + 1].len);
+			if (retval < 0)
+				goto err;
+			i++;
+			retval = i2c_readbytes(i2c_adap, &msgs[i], 1);
+		} else {
+			/* write */
+			retval = i2c_sendbytes(i2c_adap, &msgs[i], 0);
+		}
+		if (retval < 0)
+			goto err;
+	}
+	return num;
+
+err:
+	return retval;
+}
+
+static u32 au0828_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm au0828_i2c_algo_template = {
+	.master_xfer	= i2c_xfer,
+	.functionality	= au0828_functionality,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_adapter au0828_i2c_adap_template = {
+	.name              = DRIVER_NAME,
+	.owner             = THIS_MODULE,
+	.algo              = &au0828_i2c_algo_template,
+};
+
+static struct i2c_client au0828_i2c_client_template = {
+	.name	= "au0828 internal",
+};
+
+static char *i2c_devs[128] = {
+	[0x8e >> 1] = "au8522",
+	[0xa0 >> 1] = "eeprom",
+	[0xc2 >> 1] = "tuner/xc5000",
+};
+
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+	unsigned char buf;
+	int i, rc;
+
+	for (i = 0; i < 128; i++) {
+		c->addr = i;
+		rc = i2c_master_recv(c, &buf, 0);
+		if (rc < 0)
+			continue;
+		printk(KERN_INFO "%s: i2c scan: found device @ 0x%x  [%s]\n",
+		       name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+	}
+}
+
+/* init + register i2c adapter */
+int au0828_i2c_register(struct au0828_dev *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+
+	memcpy(&dev->i2c_adap, &au0828_i2c_adap_template,
+	       sizeof(dev->i2c_adap));
+	memcpy(&dev->i2c_algo, &au0828_i2c_algo_template,
+	       sizeof(dev->i2c_algo));
+	memcpy(&dev->i2c_client, &au0828_i2c_client_template,
+	       sizeof(dev->i2c_client));
+
+	dev->i2c_adap.dev.parent = &dev->usbdev->dev;
+
+	strlcpy(dev->i2c_adap.name, DRIVER_NAME,
+		sizeof(dev->i2c_adap.name));
+
+	dev->i2c_adap.algo = &dev->i2c_algo;
+	dev->i2c_adap.algo_data = dev;
+	i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
+	i2c_add_adapter(&dev->i2c_adap);
+
+	dev->i2c_client.adapter = &dev->i2c_adap;
+
+	if (0 == dev->i2c_rc) {
+		printk(KERN_INFO "%s: i2c bus registered\n", DRIVER_NAME);
+		if (i2c_scan)
+			do_i2c_scan(DRIVER_NAME, &dev->i2c_client);
+	} else
+		printk(KERN_INFO "%s: i2c bus register FAILED\n", DRIVER_NAME);
+
+	return dev->i2c_rc;
+}
+
+int au0828_i2c_unregister(struct au0828_dev *dev)
+{
+	i2c_del_adapter(&dev->i2c_adap);
+	return 0;
+}
+
diff --git a/drivers/media/usb/au0828/au0828-reg.h b/drivers/media/usb/au0828/au0828-reg.h
new file mode 100644
index 0000000..2140f4c
--- /dev/null
+++ b/drivers/media/usb/au0828/au0828-reg.h
@@ -0,0 +1,66 @@
+/*
+ *  Driver for the Auvitek USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* We'll start to rename these registers once we have a better
+ * understanding of their meaning.
+ */
+#define REG_000 0x000
+#define REG_001 0x001
+#define REG_002 0x002
+#define REG_003 0x003
+
+#define AU0828_SENSORCTRL_100 0x100
+#define AU0828_SENSORCTRL_VBI_103 0x103
+
+/* I2C registers */
+#define AU0828_I2C_TRIGGER_200		0x200
+#define AU0828_I2C_STATUS_201		0x201
+#define AU0828_I2C_CLK_DIVIDER_202	0x202
+#define AU0828_I2C_DEST_ADDR_203	0x203
+#define AU0828_I2C_WRITE_FIFO_205	0x205
+#define AU0828_I2C_READ_FIFO_209	0x209
+#define AU0828_I2C_MULTIBYTE_MODE_2FF	0x2ff
+
+/* Audio registers */
+#define AU0828_AUDIOCTRL_50C 0x50C
+
+#define REG_600 0x600
+
+/*********************************************************************/
+/* Here are constants for values associated with the above registers */
+
+/* I2C Trigger (Reg 0x200) */
+#define AU0828_I2C_TRIGGER_WRITE	0x01
+#define AU0828_I2C_TRIGGER_READ		0x20
+#define AU0828_I2C_TRIGGER_HOLD		0x40
+
+/* I2C Status (Reg 0x201) */
+#define AU0828_I2C_STATUS_READ_DONE	0x01
+#define AU0828_I2C_STATUS_NO_READ_ACK	0x02
+#define AU0828_I2C_STATUS_WRITE_DONE	0x04
+#define AU0828_I2C_STATUS_NO_WRITE_ACK	0x08
+#define AU0828_I2C_STATUS_BUSY		0x10
+
+/* I2C Clock Divider (Reg 0x202) */
+#define AU0828_I2C_CLK_250KHZ 0x07
+#define AU0828_I2C_CLK_100KHZ 0x14
+#define AU0828_I2C_CLK_30KHZ  0x40
+#define AU0828_I2C_CLK_20KHZ  0x60
diff --git a/drivers/media/usb/au0828/au0828-vbi.c b/drivers/media/usb/au0828/au0828-vbi.c
new file mode 100644
index 0000000..63f5930
--- /dev/null
+++ b/drivers/media/usb/au0828/au0828-vbi.c
@@ -0,0 +1,138 @@
+/*
+   au0828-vbi.c - VBI driver for au0828
+
+   Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+
+   This work was sponsored by GetWellNetwork Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#include "au0828.h"
+
+static unsigned int vbibufs = 5;
+module_param(vbibufs, int, 0644);
+MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
+
+/* ------------------------------------------------------------------ */
+
+static void
+free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf)
+{
+	struct au0828_fh     *fh  = vq->priv_data;
+	struct au0828_dev    *dev = fh->dev;
+	unsigned long flags = 0;
+	if (in_interrupt())
+		BUG();
+
+	/* We used to wait for the buffer to finish here, but this didn't work
+	   because, as we were keeping the state as VIDEOBUF_QUEUED,
+	   videobuf_queue_cancel marked it as finished for us.
+	   (Also, it could wedge forever if the hardware was misconfigured.)
+
+	   This should be safe; by the time we get here, the buffer isn't
+	   queued anymore. If we ever start marking the buffers as
+	   VIDEOBUF_ACTIVE, it won't be, though.
+	*/
+	spin_lock_irqsave(&dev->slock, flags);
+	if (dev->isoc_ctl.vbi_buf == buf)
+		dev->isoc_ctl.vbi_buf = NULL;
+	spin_unlock_irqrestore(&dev->slock, flags);
+
+	videobuf_vmalloc_free(&buf->vb);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+	struct au0828_fh     *fh  = q->priv_data;
+	struct au0828_dev    *dev = fh->dev;
+
+	*size = dev->vbi_width * dev->vbi_height * 2;
+
+	if (0 == *count)
+		*count = vbibufs;
+	if (*count < 2)
+		*count = 2;
+	if (*count > 32)
+		*count = 32;
+	return 0;
+}
+
+static int
+vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+	    enum v4l2_field field)
+{
+	struct au0828_fh     *fh  = q->priv_data;
+	struct au0828_dev    *dev = fh->dev;
+	struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
+	int                  rc = 0;
+
+	buf->vb.size = dev->vbi_width * dev->vbi_height * 2;
+
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+		return -EINVAL;
+
+	buf->vb.width  = dev->vbi_width;
+	buf->vb.height = dev->vbi_height;
+	buf->vb.field  = field;
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		rc = videobuf_iolock(q, &buf->vb, NULL);
+		if (rc < 0)
+			goto fail;
+	}
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+fail:
+	free_buffer(q, buf);
+	return rc;
+}
+
+static void
+vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct au0828_buffer    *buf     = container_of(vb,
+							struct au0828_buffer,
+							vb);
+	struct au0828_fh        *fh      = vq->priv_data;
+	struct au0828_dev       *dev     = fh->dev;
+	struct au0828_dmaqueue  *vbiq    = &dev->vbiq;
+
+	buf->vb.state = VIDEOBUF_QUEUED;
+	list_add_tail(&buf->vb.queue, &vbiq->active);
+}
+
+static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
+	free_buffer(q, buf);
+}
+
+struct videobuf_queue_ops au0828_vbi_qops = {
+	.buf_setup    = vbi_setup,
+	.buf_prepare  = vbi_prepare,
+	.buf_queue    = vbi_queue,
+	.buf_release  = vbi_release,
+};
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
new file mode 100644
index 0000000..fa0fa9a
--- /dev/null
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -0,0 +1,2034 @@
+/*
+ * Auvitek AU0828 USB Bridge (Analog video support)
+ *
+ * Copyright (C) 2009 Devin Heitmueller <dheitmueller@linuxtv.org>
+ * Copyright (C) 2005-2008 Auvitek International, Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * As published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/* Developer Notes:
+ *
+ * VBI support is not yet working
+ * The hardware scaler supported is unimplemented
+ * AC97 audio support is unimplemented (only i2s audio mode)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/suspend.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/tuner.h>
+#include "au0828.h"
+#include "au0828-reg.h"
+
+static DEFINE_MUTEX(au0828_sysfs_lock);
+
+/* ------------------------------------------------------------------
+	Videobuf operations
+   ------------------------------------------------------------------*/
+
+static unsigned int isoc_debug;
+module_param(isoc_debug, int, 0644);
+MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
+
+#define au0828_isocdbg(fmt, arg...) \
+do {\
+	if (isoc_debug) { \
+		printk(KERN_INFO "au0828 %s :"fmt, \
+		       __func__ , ##arg);	   \
+	} \
+  } while (0)
+
+static inline void print_err_status(struct au0828_dev *dev,
+				    int packet, int status)
+{
+	char *errmsg = "Unknown";
+
+	switch (status) {
+	case -ENOENT:
+		errmsg = "unlinked synchronuously";
+		break;
+	case -ECONNRESET:
+		errmsg = "unlinked asynchronuously";
+		break;
+	case -ENOSR:
+		errmsg = "Buffer error (overrun)";
+		break;
+	case -EPIPE:
+		errmsg = "Stalled (device not responding)";
+		break;
+	case -EOVERFLOW:
+		errmsg = "Babble (bad cable?)";
+		break;
+	case -EPROTO:
+		errmsg = "Bit-stuff error (bad cable?)";
+		break;
+	case -EILSEQ:
+		errmsg = "CRC/Timeout (could be anything)";
+		break;
+	case -ETIME:
+		errmsg = "Device does not respond";
+		break;
+	}
+	if (packet < 0) {
+		au0828_isocdbg("URB status %d [%s].\n",	status, errmsg);
+	} else {
+		au0828_isocdbg("URB packet %d, status %d [%s].\n",
+			       packet, status, errmsg);
+	}
+}
+
+static int check_dev(struct au0828_dev *dev)
+{
+	if (dev->dev_state & DEV_DISCONNECTED) {
+		printk(KERN_INFO "v4l2 ioctl: device not present\n");
+		return -ENODEV;
+	}
+
+	if (dev->dev_state & DEV_MISCONFIGURED) {
+		printk(KERN_INFO "v4l2 ioctl: device is misconfigured; "
+		       "close and open it again\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+/*
+ * IRQ callback, called by URB callback
+ */
+static void au0828_irq_callback(struct urb *urb)
+{
+	struct au0828_dmaqueue  *dma_q = urb->context;
+	struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
+	unsigned long flags = 0;
+	int i;
+
+	switch (urb->status) {
+	case 0:             /* success */
+	case -ETIMEDOUT:    /* NAK */
+		break;
+	case -ECONNRESET:   /* kill */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		au0828_isocdbg("au0828_irq_callback called: status kill\n");
+		return;
+	default:            /* unknown error */
+		au0828_isocdbg("urb completition error %d.\n", urb->status);
+		break;
+	}
+
+	/* Copy data from URB */
+	spin_lock_irqsave(&dev->slock, flags);
+	dev->isoc_ctl.isoc_copy(dev, urb);
+	spin_unlock_irqrestore(&dev->slock, flags);
+
+	/* Reset urb buffers */
+	for (i = 0; i < urb->number_of_packets; i++) {
+		urb->iso_frame_desc[i].status = 0;
+		urb->iso_frame_desc[i].actual_length = 0;
+	}
+	urb->status = 0;
+
+	urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (urb->status) {
+		au0828_isocdbg("urb resubmit failed (error=%i)\n",
+			       urb->status);
+	}
+}
+
+/*
+ * Stop and Deallocate URBs
+ */
+void au0828_uninit_isoc(struct au0828_dev *dev)
+{
+	struct urb *urb;
+	int i;
+
+	au0828_isocdbg("au0828: called au0828_uninit_isoc\n");
+
+	dev->isoc_ctl.nfields = -1;
+	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+		urb = dev->isoc_ctl.urb[i];
+		if (urb) {
+			if (!irqs_disabled())
+				usb_kill_urb(urb);
+			else
+				usb_unlink_urb(urb);
+
+			if (dev->isoc_ctl.transfer_buffer[i]) {
+				usb_free_coherent(dev->usbdev,
+					urb->transfer_buffer_length,
+					dev->isoc_ctl.transfer_buffer[i],
+					urb->transfer_dma);
+			}
+			usb_free_urb(urb);
+			dev->isoc_ctl.urb[i] = NULL;
+		}
+		dev->isoc_ctl.transfer_buffer[i] = NULL;
+	}
+
+	kfree(dev->isoc_ctl.urb);
+	kfree(dev->isoc_ctl.transfer_buffer);
+
+	dev->isoc_ctl.urb = NULL;
+	dev->isoc_ctl.transfer_buffer = NULL;
+	dev->isoc_ctl.num_bufs = 0;
+}
+
+/*
+ * Allocate URBs and start IRQ
+ */
+int au0828_init_isoc(struct au0828_dev *dev, int max_packets,
+		     int num_bufs, int max_pkt_size,
+		     int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb))
+{
+	struct au0828_dmaqueue *dma_q = &dev->vidq;
+	int i;
+	int sb_size, pipe;
+	struct urb *urb;
+	int j, k;
+	int rc;
+
+	au0828_isocdbg("au0828: called au0828_prepare_isoc\n");
+
+	/* De-allocates all pending stuff */
+	au0828_uninit_isoc(dev);
+
+	dev->isoc_ctl.isoc_copy = isoc_copy;
+	dev->isoc_ctl.num_bufs = num_bufs;
+
+	dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs,  GFP_KERNEL);
+	if (!dev->isoc_ctl.urb) {
+		au0828_isocdbg("cannot alloc memory for usb buffers\n");
+		return -ENOMEM;
+	}
+
+	dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
+					      GFP_KERNEL);
+	if (!dev->isoc_ctl.transfer_buffer) {
+		au0828_isocdbg("cannot allocate memory for usb transfer\n");
+		kfree(dev->isoc_ctl.urb);
+		return -ENOMEM;
+	}
+
+	dev->isoc_ctl.max_pkt_size = max_pkt_size;
+	dev->isoc_ctl.buf = NULL;
+
+	sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
+
+	/* allocate urbs and transfer buffers */
+	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+		urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+		if (!urb) {
+			au0828_isocdbg("cannot alloc isoc_ctl.urb %i\n", i);
+			au0828_uninit_isoc(dev);
+			return -ENOMEM;
+		}
+		dev->isoc_ctl.urb[i] = urb;
+
+		dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->usbdev,
+			sb_size, GFP_KERNEL, &urb->transfer_dma);
+		if (!dev->isoc_ctl.transfer_buffer[i]) {
+			printk("unable to allocate %i bytes for transfer"
+					" buffer %i%s\n",
+					sb_size, i,
+					in_interrupt() ? " while in int" : "");
+			au0828_uninit_isoc(dev);
+			return -ENOMEM;
+		}
+		memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+
+		pipe = usb_rcvisocpipe(dev->usbdev,
+				       dev->isoc_in_endpointaddr),
+
+		usb_fill_int_urb(urb, dev->usbdev, pipe,
+				 dev->isoc_ctl.transfer_buffer[i], sb_size,
+				 au0828_irq_callback, dma_q, 1);
+
+		urb->number_of_packets = max_packets;
+		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+
+		k = 0;
+		for (j = 0; j < max_packets; j++) {
+			urb->iso_frame_desc[j].offset = k;
+			urb->iso_frame_desc[j].length =
+						dev->isoc_ctl.max_pkt_size;
+			k += dev->isoc_ctl.max_pkt_size;
+		}
+	}
+
+	init_waitqueue_head(&dma_q->wq);
+
+	/* submit urbs and enables IRQ */
+	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+		rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+		if (rc) {
+			au0828_isocdbg("submit of urb %i failed (error=%i)\n",
+				       i, rc);
+			au0828_uninit_isoc(dev);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void buffer_filled(struct au0828_dev *dev,
+				  struct au0828_dmaqueue *dma_q,
+				  struct au0828_buffer *buf)
+{
+	/* Advice that buffer was filled */
+	au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+
+	buf->vb.state = VIDEOBUF_DONE;
+	buf->vb.field_count++;
+	do_gettimeofday(&buf->vb.ts);
+
+	dev->isoc_ctl.buf = NULL;
+
+	list_del(&buf->vb.queue);
+	wake_up(&buf->vb.done);
+}
+
+static inline void vbi_buffer_filled(struct au0828_dev *dev,
+				     struct au0828_dmaqueue *dma_q,
+				     struct au0828_buffer *buf)
+{
+	/* Advice that buffer was filled */
+	au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+
+	buf->vb.state = VIDEOBUF_DONE;
+	buf->vb.field_count++;
+	do_gettimeofday(&buf->vb.ts);
+
+	dev->isoc_ctl.vbi_buf = NULL;
+
+	list_del(&buf->vb.queue);
+	wake_up(&buf->vb.done);
+}
+
+/*
+ * Identify the buffer header type and properly handles
+ */
+static void au0828_copy_video(struct au0828_dev *dev,
+			      struct au0828_dmaqueue  *dma_q,
+			      struct au0828_buffer *buf,
+			      unsigned char *p,
+			      unsigned char *outp, unsigned long len)
+{
+	void *fieldstart, *startwrite, *startread;
+	int  linesdone, currlinedone, offset, lencopy, remain;
+	int bytesperline = dev->width << 1; /* Assumes 16-bit depth @@@@ */
+
+	if (len == 0)
+		return;
+
+	if (dma_q->pos + len > buf->vb.size)
+		len = buf->vb.size - dma_q->pos;
+
+	startread = p;
+	remain = len;
+
+	/* Interlaces frame */
+	if (buf->top_field)
+		fieldstart = outp;
+	else
+		fieldstart = outp + bytesperline;
+
+	linesdone = dma_q->pos / bytesperline;
+	currlinedone = dma_q->pos % bytesperline;
+	offset = linesdone * bytesperline * 2 + currlinedone;
+	startwrite = fieldstart + offset;
+	lencopy = bytesperline - currlinedone;
+	lencopy = lencopy > remain ? remain : lencopy;
+
+	if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+		au0828_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
+			       ((char *)startwrite + lencopy) -
+			       ((char *)outp + buf->vb.size));
+		remain = (char *)outp + buf->vb.size - (char *)startwrite;
+		lencopy = remain;
+	}
+	if (lencopy <= 0)
+		return;
+	memcpy(startwrite, startread, lencopy);
+
+	remain -= lencopy;
+
+	while (remain > 0) {
+		startwrite += lencopy + bytesperline;
+		startread += lencopy;
+		if (bytesperline > remain)
+			lencopy = remain;
+		else
+			lencopy = bytesperline;
+
+		if ((char *)startwrite + lencopy > (char *)outp +
+		    buf->vb.size) {
+			au0828_isocdbg("Overflow %zi bytes past buf end (2)\n",
+				       ((char *)startwrite + lencopy) -
+				       ((char *)outp + buf->vb.size));
+			lencopy = remain = (char *)outp + buf->vb.size -
+					   (char *)startwrite;
+		}
+		if (lencopy <= 0)
+			break;
+
+		memcpy(startwrite, startread, lencopy);
+
+		remain -= lencopy;
+	}
+
+	if (offset > 1440) {
+		/* We have enough data to check for greenscreen */
+		if (outp[0] < 0x60 && outp[1440] < 0x60)
+			dev->greenscreen_detected = 1;
+	}
+
+	dma_q->pos += len;
+}
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_buf(struct au0828_dmaqueue *dma_q,
+				struct au0828_buffer **buf)
+{
+	struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
+
+	if (list_empty(&dma_q->active)) {
+		au0828_isocdbg("No active queue to serve\n");
+		dev->isoc_ctl.buf = NULL;
+		*buf = NULL;
+		return;
+	}
+
+	/* Get the next buffer */
+	*buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue);
+	dev->isoc_ctl.buf = *buf;
+
+	return;
+}
+
+static void au0828_copy_vbi(struct au0828_dev *dev,
+			      struct au0828_dmaqueue  *dma_q,
+			      struct au0828_buffer *buf,
+			      unsigned char *p,
+			      unsigned char *outp, unsigned long len)
+{
+	unsigned char *startwrite, *startread;
+	int bytesperline;
+	int i, j = 0;
+
+	if (dev == NULL) {
+		au0828_isocdbg("dev is null\n");
+		return;
+	}
+
+	if (dma_q == NULL) {
+		au0828_isocdbg("dma_q is null\n");
+		return;
+	}
+	if (buf == NULL)
+		return;
+	if (p == NULL) {
+		au0828_isocdbg("p is null\n");
+		return;
+	}
+	if (outp == NULL) {
+		au0828_isocdbg("outp is null\n");
+		return;
+	}
+
+	bytesperline = dev->vbi_width;
+
+	if (dma_q->pos + len > buf->vb.size)
+		len = buf->vb.size - dma_q->pos;
+
+	startread = p;
+	startwrite = outp + (dma_q->pos / 2);
+
+	/* Make sure the bottom field populates the second half of the frame */
+	if (buf->top_field == 0)
+		startwrite += bytesperline * dev->vbi_height;
+
+	for (i = 0; i < len; i += 2)
+		startwrite[j++] = startread[i+1];
+
+	dma_q->pos += len;
+}
+
+
+/*
+ * video-buf generic routine to get the next available VBI buffer
+ */
+static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q,
+				    struct au0828_buffer **buf)
+{
+	struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vbiq);
+	char *outp;
+
+	if (list_empty(&dma_q->active)) {
+		au0828_isocdbg("No active queue to serve\n");
+		dev->isoc_ctl.vbi_buf = NULL;
+		*buf = NULL;
+		return;
+	}
+
+	/* Get the next buffer */
+	*buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue);
+	/* Cleans up buffer - Useful for testing for frame/URB loss */
+	outp = videobuf_to_vmalloc(&(*buf)->vb);
+	memset(outp, 0x00, (*buf)->vb.size);
+
+	dev->isoc_ctl.vbi_buf = *buf;
+
+	return;
+}
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
+{
+	struct au0828_buffer    *buf;
+	struct au0828_buffer    *vbi_buf;
+	struct au0828_dmaqueue  *dma_q = urb->context;
+	struct au0828_dmaqueue  *vbi_dma_q = &dev->vbiq;
+	unsigned char *outp = NULL;
+	unsigned char *vbioutp = NULL;
+	int i, len = 0, rc = 1;
+	unsigned char *p;
+	unsigned char fbyte;
+	unsigned int vbi_field_size;
+	unsigned int remain, lencopy;
+
+	if (!dev)
+		return 0;
+
+	if ((dev->dev_state & DEV_DISCONNECTED) ||
+	    (dev->dev_state & DEV_MISCONFIGURED))
+		return 0;
+
+	if (urb->status < 0) {
+		print_err_status(dev, -1, urb->status);
+		if (urb->status == -ENOENT)
+			return 0;
+	}
+
+	buf = dev->isoc_ctl.buf;
+	if (buf != NULL)
+		outp = videobuf_to_vmalloc(&buf->vb);
+
+	vbi_buf = dev->isoc_ctl.vbi_buf;
+	if (vbi_buf != NULL)
+		vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		int status = urb->iso_frame_desc[i].status;
+
+		if (status < 0) {
+			print_err_status(dev, i, status);
+			if (urb->iso_frame_desc[i].status != -EPROTO)
+				continue;
+		}
+
+		if (urb->iso_frame_desc[i].actual_length <= 0)
+			continue;
+
+		if (urb->iso_frame_desc[i].actual_length >
+						dev->max_pkt_size) {
+			au0828_isocdbg("packet bigger than packet size");
+			continue;
+		}
+
+		p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+		fbyte = p[0];
+		len = urb->iso_frame_desc[i].actual_length - 4;
+		p += 4;
+
+		if (fbyte & 0x80) {
+			len -= 4;
+			p += 4;
+			au0828_isocdbg("Video frame %s\n",
+				       (fbyte & 0x40) ? "odd" : "even");
+			if (fbyte & 0x40) {
+				/* VBI */
+				if (vbi_buf != NULL)
+					vbi_buffer_filled(dev,
+							  vbi_dma_q,
+							  vbi_buf);
+				vbi_get_next_buf(vbi_dma_q, &vbi_buf);
+				if (vbi_buf == NULL)
+					vbioutp = NULL;
+				else
+					vbioutp = videobuf_to_vmalloc(
+						&vbi_buf->vb);
+
+				/* Video */
+				if (buf != NULL)
+					buffer_filled(dev, dma_q, buf);
+				get_next_buf(dma_q, &buf);
+				if (buf == NULL)
+					outp = NULL;
+				else
+					outp = videobuf_to_vmalloc(&buf->vb);
+
+				/* As long as isoc traffic is arriving, keep
+				   resetting the timer */
+				if (dev->vid_timeout_running)
+					mod_timer(&dev->vid_timeout,
+						  jiffies + (HZ / 10));
+				if (dev->vbi_timeout_running)
+					mod_timer(&dev->vbi_timeout,
+						  jiffies + (HZ / 10));
+			}
+
+			if (buf != NULL) {
+				if (fbyte & 0x40)
+					buf->top_field = 1;
+				else
+					buf->top_field = 0;
+			}
+
+			if (vbi_buf != NULL) {
+				if (fbyte & 0x40)
+					vbi_buf->top_field = 1;
+				else
+					vbi_buf->top_field = 0;
+			}
+
+			dev->vbi_read = 0;
+			vbi_dma_q->pos = 0;
+			dma_q->pos = 0;
+		}
+
+		vbi_field_size = dev->vbi_width * dev->vbi_height * 2;
+		if (dev->vbi_read < vbi_field_size) {
+			remain  = vbi_field_size - dev->vbi_read;
+			if (len < remain)
+				lencopy = len;
+			else
+				lencopy = remain;
+
+			if (vbi_buf != NULL)
+				au0828_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
+						vbioutp, len);
+
+			len -= lencopy;
+			p += lencopy;
+			dev->vbi_read += lencopy;
+		}
+
+		if (dev->vbi_read >= vbi_field_size && buf != NULL)
+			au0828_copy_video(dev, dma_q, buf, p, outp, len);
+	}
+	return rc;
+}
+
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+	     unsigned int *size)
+{
+	struct au0828_fh *fh = vq->priv_data;
+	*size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3;
+
+	if (0 == *count)
+		*count = AU0828_DEF_BUF;
+
+	if (*count < AU0828_MIN_BUF)
+		*count = AU0828_MIN_BUF;
+	return 0;
+}
+
+/* This is called *without* dev->slock held; please keep it that way */
+static void free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf)
+{
+	struct au0828_fh     *fh  = vq->priv_data;
+	struct au0828_dev    *dev = fh->dev;
+	unsigned long flags = 0;
+	if (in_interrupt())
+		BUG();
+
+	/* We used to wait for the buffer to finish here, but this didn't work
+	   because, as we were keeping the state as VIDEOBUF_QUEUED,
+	   videobuf_queue_cancel marked it as finished for us.
+	   (Also, it could wedge forever if the hardware was misconfigured.)
+
+	   This should be safe; by the time we get here, the buffer isn't
+	   queued anymore. If we ever start marking the buffers as
+	   VIDEOBUF_ACTIVE, it won't be, though.
+	*/
+	spin_lock_irqsave(&dev->slock, flags);
+	if (dev->isoc_ctl.buf == buf)
+		dev->isoc_ctl.buf = NULL;
+	spin_unlock_irqrestore(&dev->slock, flags);
+
+	videobuf_vmalloc_free(&buf->vb);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+						enum v4l2_field field)
+{
+	struct au0828_fh     *fh  = vq->priv_data;
+	struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
+	struct au0828_dev    *dev = fh->dev;
+	int                  rc = 0, urb_init = 0;
+
+	buf->vb.size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3;
+
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+		return -EINVAL;
+
+	buf->vb.width  = dev->width;
+	buf->vb.height = dev->height;
+	buf->vb.field  = field;
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		rc = videobuf_iolock(vq, &buf->vb, NULL);
+		if (rc < 0) {
+			printk(KERN_INFO "videobuf_iolock failed\n");
+			goto fail;
+		}
+	}
+
+	if (!dev->isoc_ctl.num_bufs)
+		urb_init = 1;
+
+	if (urb_init) {
+		rc = au0828_init_isoc(dev, AU0828_ISO_PACKETS_PER_URB,
+				      AU0828_MAX_ISO_BUFS, dev->max_pkt_size,
+				      au0828_isoc_copy);
+		if (rc < 0) {
+			printk(KERN_INFO "au0828_init_isoc failed\n");
+			goto fail;
+		}
+	}
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+fail:
+	free_buffer(vq, buf);
+	return rc;
+}
+
+static void
+buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct au0828_buffer    *buf     = container_of(vb,
+							struct au0828_buffer,
+							vb);
+	struct au0828_fh        *fh      = vq->priv_data;
+	struct au0828_dev       *dev     = fh->dev;
+	struct au0828_dmaqueue  *vidq    = &dev->vidq;
+
+	buf->vb.state = VIDEOBUF_QUEUED;
+	list_add_tail(&buf->vb.queue, &vidq->active);
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+				struct videobuf_buffer *vb)
+{
+	struct au0828_buffer   *buf  = container_of(vb,
+						    struct au0828_buffer,
+						    vb);
+
+	free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops au0828_video_qops = {
+	.buf_setup      = buffer_setup,
+	.buf_prepare    = buffer_prepare,
+	.buf_queue      = buffer_queue,
+	.buf_release    = buffer_release,
+};
+
+/* ------------------------------------------------------------------
+   V4L2 interface
+   ------------------------------------------------------------------*/
+
+static int au0828_i2s_init(struct au0828_dev *dev)
+{
+	/* Enable i2s mode */
+	au0828_writereg(dev, AU0828_AUDIOCTRL_50C, 0x01);
+	return 0;
+}
+
+/*
+ * Auvitek au0828 analog stream enable
+ * Please set interface0 to AS5 before enable the stream
+ */
+int au0828_analog_stream_enable(struct au0828_dev *d)
+{
+	dprintk(1, "au0828_analog_stream_enable called\n");
+	au0828_writereg(d, AU0828_SENSORCTRL_VBI_103, 0x00);
+	au0828_writereg(d, 0x106, 0x00);
+	/* set x position */
+	au0828_writereg(d, 0x110, 0x00);
+	au0828_writereg(d, 0x111, 0x00);
+	au0828_writereg(d, 0x114, 0xa0);
+	au0828_writereg(d, 0x115, 0x05);
+	/* set y position */
+	au0828_writereg(d, 0x112, 0x00);
+	au0828_writereg(d, 0x113, 0x00);
+	au0828_writereg(d, 0x116, 0xf2);
+	au0828_writereg(d, 0x117, 0x00);
+	au0828_writereg(d, AU0828_SENSORCTRL_100, 0xb3);
+
+	return 0;
+}
+
+int au0828_analog_stream_disable(struct au0828_dev *d)
+{
+	dprintk(1, "au0828_analog_stream_disable called\n");
+	au0828_writereg(d, AU0828_SENSORCTRL_100, 0x0);
+	return 0;
+}
+
+void au0828_analog_stream_reset(struct au0828_dev *dev)
+{
+	dprintk(1, "au0828_analog_stream_reset called\n");
+	au0828_writereg(dev, AU0828_SENSORCTRL_100, 0x0);
+	mdelay(30);
+	au0828_writereg(dev, AU0828_SENSORCTRL_100, 0xb3);
+}
+
+/*
+ * Some operations needs to stop current streaming
+ */
+static int au0828_stream_interrupt(struct au0828_dev *dev)
+{
+	int ret = 0;
+
+	dev->stream_state = STREAM_INTERRUPT;
+	if (dev->dev_state == DEV_DISCONNECTED)
+		return -ENODEV;
+	else if (ret) {
+		dev->dev_state = DEV_MISCONFIGURED;
+		dprintk(1, "%s device is misconfigured!\n", __func__);
+		return ret;
+	}
+	return 0;
+}
+
+/*
+ * au0828_release_resources
+ * unregister v4l2 devices
+ */
+void au0828_analog_unregister(struct au0828_dev *dev)
+{
+	dprintk(1, "au0828_release_resources called\n");
+	mutex_lock(&au0828_sysfs_lock);
+
+	if (dev->vdev)
+		video_unregister_device(dev->vdev);
+	if (dev->vbi_dev)
+		video_unregister_device(dev->vbi_dev);
+
+	mutex_unlock(&au0828_sysfs_lock);
+}
+
+
+/* Usage lock check functions */
+static int res_get(struct au0828_fh *fh, unsigned int bit)
+{
+	struct au0828_dev    *dev = fh->dev;
+
+	if (fh->resources & bit)
+		/* have it already allocated */
+		return 1;
+
+	/* is it free? */
+	if (dev->resources & bit) {
+		/* no, someone else uses it */
+		return 0;
+	}
+	/* it's free, grab it */
+	fh->resources  |= bit;
+	dev->resources |= bit;
+	dprintk(1, "res: get %d\n", bit);
+
+	return 1;
+}
+
+static int res_check(struct au0828_fh *fh, unsigned int bit)
+{
+	return fh->resources & bit;
+}
+
+static int res_locked(struct au0828_dev *dev, unsigned int bit)
+{
+	return dev->resources & bit;
+}
+
+static void res_free(struct au0828_fh *fh, unsigned int bits)
+{
+	struct au0828_dev    *dev = fh->dev;
+
+	BUG_ON((fh->resources & bits) != bits);
+
+	fh->resources  &= ~bits;
+	dev->resources &= ~bits;
+	dprintk(1, "res: put %d\n", bits);
+}
+
+static int get_ressource(struct au0828_fh *fh)
+{
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return AU0828_RESOURCE_VIDEO;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		return AU0828_RESOURCE_VBI;
+	default:
+		BUG();
+		return 0;
+	}
+}
+
+/* This function ensures that video frames continue to be delivered even if
+   the ITU-656 input isn't receiving any data (thereby preventing applications
+   such as tvtime from hanging) */
+void au0828_vid_buffer_timeout(unsigned long data)
+{
+	struct au0828_dev *dev = (struct au0828_dev *) data;
+	struct au0828_dmaqueue *dma_q = &dev->vidq;
+	struct au0828_buffer *buf;
+	unsigned char *vid_data;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&dev->slock, flags);
+
+	buf = dev->isoc_ctl.buf;
+	if (buf != NULL) {
+		vid_data = videobuf_to_vmalloc(&buf->vb);
+		memset(vid_data, 0x00, buf->vb.size); /* Blank green frame */
+		buffer_filled(dev, dma_q, buf);
+	}
+	get_next_buf(dma_q, &buf);
+
+	if (dev->vid_timeout_running == 1)
+		mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
+
+	spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+void au0828_vbi_buffer_timeout(unsigned long data)
+{
+	struct au0828_dev *dev = (struct au0828_dev *) data;
+	struct au0828_dmaqueue *dma_q = &dev->vbiq;
+	struct au0828_buffer *buf;
+	unsigned char *vbi_data;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&dev->slock, flags);
+
+	buf = dev->isoc_ctl.vbi_buf;
+	if (buf != NULL) {
+		vbi_data = videobuf_to_vmalloc(&buf->vb);
+		memset(vbi_data, 0x00, buf->vb.size);
+		vbi_buffer_filled(dev, dma_q, buf);
+	}
+	vbi_get_next_buf(dma_q, &buf);
+
+	if (dev->vbi_timeout_running == 1)
+		mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+	spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+
+static int au0828_v4l2_open(struct file *filp)
+{
+	int ret = 0;
+	struct video_device *vdev = video_devdata(filp);
+	struct au0828_dev *dev = video_drvdata(filp);
+	struct au0828_fh *fh;
+	int type;
+
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_GRABBER:
+		type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		break;
+	case VFL_TYPE_VBI:
+		type = V4L2_BUF_TYPE_VBI_CAPTURE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL);
+	if (NULL == fh) {
+		dprintk(1, "Failed allocate au0828_fh struct!\n");
+		return -ENOMEM;
+	}
+
+	fh->type = type;
+	fh->dev = dev;
+	filp->private_data = fh;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+		/* set au0828 interface0 to AS5 here again */
+		ret = usb_set_interface(dev->usbdev, 0, 5);
+		if (ret < 0) {
+			printk(KERN_INFO "Au0828 can't set alternate to 5!\n");
+			return -EBUSY;
+		}
+		dev->width = NTSC_STD_W;
+		dev->height = NTSC_STD_H;
+		dev->frame_size = dev->width * dev->height * 2;
+		dev->field_size = dev->width * dev->height;
+		dev->bytesperline = dev->width * 2;
+
+		au0828_analog_stream_enable(dev);
+		au0828_analog_stream_reset(dev);
+
+		/* If we were doing ac97 instead of i2s, it would go here...*/
+		au0828_i2s_init(dev);
+
+		dev->stream_state = STREAM_OFF;
+		dev->dev_state |= DEV_INITIALIZED;
+	}
+
+	dev->users++;
+
+	videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops,
+				    NULL, &dev->slock,
+				    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+				    V4L2_FIELD_INTERLACED,
+				    sizeof(struct au0828_buffer), fh,
+				    &dev->lock);
+
+	/* VBI Setup */
+	dev->vbi_width = 720;
+	dev->vbi_height = 1;
+	videobuf_queue_vmalloc_init(&fh->vb_vbiq, &au0828_vbi_qops,
+				    NULL, &dev->slock,
+				    V4L2_BUF_TYPE_VBI_CAPTURE,
+				    V4L2_FIELD_SEQ_TB,
+				    sizeof(struct au0828_buffer), fh,
+				    &dev->lock);
+	return ret;
+}
+
+static int au0828_v4l2_close(struct file *filp)
+{
+	int ret;
+	struct au0828_fh *fh = filp->private_data;
+	struct au0828_dev *dev = fh->dev;
+
+	if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
+		/* Cancel timeout thread in case they didn't call streamoff */
+		dev->vid_timeout_running = 0;
+		del_timer_sync(&dev->vid_timeout);
+
+		videobuf_stop(&fh->vb_vidq);
+		res_free(fh, AU0828_RESOURCE_VIDEO);
+	}
+
+	if (res_check(fh, AU0828_RESOURCE_VBI)) {
+		/* Cancel timeout thread in case they didn't call streamoff */
+		dev->vbi_timeout_running = 0;
+		del_timer_sync(&dev->vbi_timeout);
+
+		videobuf_stop(&fh->vb_vbiq);
+		res_free(fh, AU0828_RESOURCE_VBI);
+	}
+
+	if (dev->users == 1) {
+		if (dev->dev_state & DEV_DISCONNECTED) {
+			au0828_analog_unregister(dev);
+			kfree(dev);
+			return 0;
+		}
+
+		au0828_analog_stream_disable(dev);
+
+		au0828_uninit_isoc(dev);
+
+		/* Save some power by putting tuner to sleep */
+		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+
+		/* When close the device, set the usb intf0 into alt0 to free
+		   USB bandwidth */
+		ret = usb_set_interface(dev->usbdev, 0, 0);
+		if (ret < 0)
+			printk(KERN_INFO "Au0828 can't set alternate to 0!\n");
+	}
+
+	videobuf_mmap_free(&fh->vb_vidq);
+	videobuf_mmap_free(&fh->vb_vbiq);
+	kfree(fh);
+	dev->users--;
+	wake_up_interruptible_nr(&dev->open, 1);
+	return 0;
+}
+
+static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct au0828_fh *fh = filp->private_data;
+	struct au0828_dev *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		if (res_locked(dev, AU0828_RESOURCE_VIDEO))
+			return -EBUSY;
+
+		return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
+					filp->f_flags & O_NONBLOCK);
+	}
+
+	if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+		if (!res_get(fh, AU0828_RESOURCE_VBI))
+			return -EBUSY;
+
+		if (dev->vbi_timeout_running == 0) {
+			/* Handle case where caller tries to read without
+			   calling streamon first */
+			dev->vbi_timeout_running = 1;
+			mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+		}
+
+		return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
+					    filp->f_flags & O_NONBLOCK);
+	}
+
+	return 0;
+}
+
+static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait)
+{
+	struct au0828_fh *fh = filp->private_data;
+	struct au0828_dev *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		if (!res_get(fh, AU0828_RESOURCE_VIDEO))
+			return POLLERR;
+		return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+	} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+		if (!res_get(fh, AU0828_RESOURCE_VBI))
+			return POLLERR;
+		return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
+	} else {
+		return POLLERR;
+	}
+}
+
+static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct au0828_fh *fh    = filp->private_data;
+	struct au0828_dev *dev   = fh->dev;
+	int		 rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+	else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
+
+	return rc;
+}
+
+static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
+			     struct v4l2_format *format)
+{
+	int ret;
+	int width = format->fmt.pix.width;
+	int height = format->fmt.pix.height;
+
+	if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	/* If they are demanding a format other than the one we support,
+	   bail out (tvtime asks for UYVY and then retries with YUYV) */
+	if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY)
+		return -EINVAL;
+
+	/* format->fmt.pix.width only support 720 and height 480 */
+	if (width != 720)
+		width = 720;
+	if (height != 480)
+		height = 480;
+
+	format->fmt.pix.width = width;
+	format->fmt.pix.height = height;
+	format->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+	format->fmt.pix.bytesperline = width * 2;
+	format->fmt.pix.sizeimage = width * height * 2;
+	format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	format->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+	if (cmd == VIDIOC_TRY_FMT)
+		return 0;
+
+	/* maybe set new image format, driver current only support 720*480 */
+	dev->width = width;
+	dev->height = height;
+	dev->frame_size = width * height * 2;
+	dev->field_size = width * height;
+	dev->bytesperline = width * 2;
+
+	if (dev->stream_state == STREAM_ON) {
+		dprintk(1, "VIDIOC_SET_FMT: interrupting stream!\n");
+		ret = au0828_stream_interrupt(dev);
+		if (ret != 0) {
+			dprintk(1, "error interrupting video stream!\n");
+			return ret;
+		}
+	}
+
+	/* set au0828 interface0 to AS5 here again */
+	ret = usb_set_interface(dev->usbdev, 0, 5);
+	if (ret < 0) {
+		printk(KERN_INFO "Au0828 can't set alt setting to 5!\n");
+		return -EBUSY;
+	}
+
+	au0828_analog_stream_enable(dev);
+
+	return 0;
+}
+
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+			    struct v4l2_queryctrl *qc)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
+	if (qc->type)
+		return 0;
+	else
+		return -EINVAL;
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+			   struct v4l2_capability *cap)
+{
+	struct au0828_fh *fh  = priv;
+	struct au0828_dev *dev = fh->dev;
+
+	strlcpy(cap->driver, "au0828", sizeof(cap->driver));
+	strlcpy(cap->card, dev->board.name, sizeof(cap->card));
+	strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
+
+	/*set the device capabilities */
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_VBI_CAPTURE |
+		V4L2_CAP_AUDIO |
+		V4L2_CAP_READWRITE |
+		V4L2_CAP_STREAMING |
+		V4L2_CAP_TUNER;
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	if (f->index)
+		return -EINVAL;
+
+	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	strcpy(f->description, "Packed YUV2");
+
+	f->flags = 0;
+	f->pixelformat = V4L2_PIX_FMT_UYVY;
+
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct au0828_fh *fh  = priv;
+	struct au0828_dev *dev = fh->dev;
+
+	f->fmt.pix.width = dev->width;
+	f->fmt.pix.height = dev->height;
+	f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+	f->fmt.pix.bytesperline = dev->bytesperline;
+	f->fmt.pix.sizeimage = dev->frame_size;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* NTSC/PAL */
+	f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct au0828_fh *fh  = priv;
+	struct au0828_dev *dev = fh->dev;
+
+	return au0828_set_format(dev, VIDIOC_TRY_FMT, f);
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct au0828_fh *fh  = priv;
+	struct au0828_dev *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+		printk(KERN_INFO "%s queue busy\n", __func__);
+		rc = -EBUSY;
+		goto out;
+	}
+
+	rc = au0828_set_format(dev, VIDIOC_S_FMT, f);
+out:
+	return rc;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+
+	if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+		dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
+
+	/* FIXME: when we support something other than NTSC, we are going to
+	   have to make the au0828 bridge adjust the size of its capture
+	   buffer, which is currently hardcoded at 720x480 */
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, *norm);
+	dev->std_set_in_tuner_core = 1;
+
+	if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+		dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+
+	return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+				struct v4l2_input *input)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+	unsigned int tmp;
+
+	static const char *inames[] = {
+		[AU0828_VMUX_UNDEFINED] = "Undefined",
+		[AU0828_VMUX_COMPOSITE] = "Composite",
+		[AU0828_VMUX_SVIDEO] = "S-Video",
+		[AU0828_VMUX_CABLE] = "Cable TV",
+		[AU0828_VMUX_TELEVISION] = "Television",
+		[AU0828_VMUX_DVB] = "DVB",
+		[AU0828_VMUX_DEBUG] = "tv debug"
+	};
+
+	tmp = input->index;
+
+	if (tmp >= AU0828_MAX_INPUT)
+		return -EINVAL;
+	if (AUVI_INPUT(tmp).type == 0)
+		return -EINVAL;
+
+	input->index = tmp;
+	strcpy(input->name, inames[AUVI_INPUT(tmp).type]);
+	if ((AUVI_INPUT(tmp).type == AU0828_VMUX_TELEVISION) ||
+	    (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE))
+		input->type |= V4L2_INPUT_TYPE_TUNER;
+	else
+		input->type |= V4L2_INPUT_TYPE_CAMERA;
+
+	input->std = dev->vdev->tvnorms;
+
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+	*i = dev->ctrl_input;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+	int i;
+
+	dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
+		index);
+	if (index >= AU0828_MAX_INPUT)
+		return -EINVAL;
+	if (AUVI_INPUT(index).type == 0)
+		return -EINVAL;
+	dev->ctrl_input = index;
+
+	switch (AUVI_INPUT(index).type) {
+	case AU0828_VMUX_SVIDEO:
+		dev->input_type = AU0828_VMUX_SVIDEO;
+		break;
+	case AU0828_VMUX_COMPOSITE:
+		dev->input_type = AU0828_VMUX_COMPOSITE;
+		break;
+	case AU0828_VMUX_TELEVISION:
+		dev->input_type = AU0828_VMUX_TELEVISION;
+		break;
+	default:
+		dprintk(1, "VIDIOC_S_INPUT unknown input type set [%d]\n",
+			AUVI_INPUT(index).type);
+		break;
+	}
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
+			AUVI_INPUT(index).vmux, 0, 0);
+
+	for (i = 0; i < AU0828_MAX_INPUT; i++) {
+		int enable = 0;
+		if (AUVI_INPUT(i).audio_setup == NULL)
+			continue;
+
+		if (i == index)
+			enable = 1;
+		else
+			enable = 0;
+		if (enable) {
+			(AUVI_INPUT(i).audio_setup)(dev, enable);
+		} else {
+			/* Make sure we leave it turned on if some
+			   other input is routed to this callback */
+			if ((AUVI_INPUT(i).audio_setup) !=
+			    ((AUVI_INPUT(index).audio_setup))) {
+				(AUVI_INPUT(i).audio_setup)(dev, enable);
+			}
+		}
+	}
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
+			AUVI_INPUT(index).amux, 0, 0);
+	return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+	unsigned int index = a->index;
+
+	if (a->index > 1)
+		return -EINVAL;
+
+	index = dev->ctrl_ainput;
+	if (index == 0)
+		strcpy(a->name, "Television");
+	else
+		strcpy(a->name, "Line in");
+
+	a->capability = V4L2_AUDCAP_STEREO;
+	a->index = index;
+	return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+	if (a->index != dev->ctrl_ainput)
+		return -EINVAL;
+	return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *ctrl)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
+	return 0;
+
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
+	return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+
+	if (t->index != 0)
+		return -EINVAL;
+
+	strcpy(t->name, "Auvitek tuner");
+	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+	return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+
+	if (t->index != 0)
+		return -EINVAL;
+
+	t->type = V4L2_TUNER_ANALOG_TV;
+
+	if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+		dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+
+	if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+		dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+
+	dprintk(1, "VIDIOC_S_TUNER: signal = %x, afc = %x\n", t->signal,
+		t->afc);
+
+	return 0;
+
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *freq)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+
+	freq->type = V4L2_TUNER_ANALOG_TV;
+	freq->frequency = dev->ctrl_freq;
+	return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *freq)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+
+	if (freq->tuner != 0)
+		return -EINVAL;
+	if (freq->type != V4L2_TUNER_ANALOG_TV)
+		return -EINVAL;
+
+	dev->ctrl_freq = freq->frequency;
+
+	if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+		dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
+
+	if (dev->std_set_in_tuner_core == 0) {
+	  /* If we've never sent the standard in tuner core, do so now.  We
+	     don't do this at device probe because we don't want to incur
+	     the cost of a firmware load */
+	  v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std,
+			       dev->vdev->tvnorms);
+	  dev->std_set_in_tuner_core = 1;
+	}
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq);
+
+	if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+		dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+
+	au0828_analog_stream_reset(dev);
+
+	return 0;
+}
+
+
+/* RAW VBI ioctls */
+
+static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+				struct v4l2_format *format)
+{
+	struct au0828_fh      *fh  = priv;
+	struct au0828_dev     *dev = fh->dev;
+
+	format->fmt.vbi.samples_per_line = dev->vbi_width;
+	format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+	format->fmt.vbi.offset = 0;
+	format->fmt.vbi.flags = 0;
+	format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
+
+	format->fmt.vbi.count[0] = dev->vbi_height;
+	format->fmt.vbi.count[1] = dev->vbi_height;
+	format->fmt.vbi.start[0] = 21;
+	format->fmt.vbi.start[1] = 284;
+
+	return 0;
+}
+
+static int vidioc_g_chip_ident(struct file *file, void *priv,
+	       struct v4l2_dbg_chip_ident *chip)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+	chip->ident = V4L2_IDENT_NONE;
+	chip->revision = 0;
+
+	if (v4l2_chip_match_host(&chip->match)) {
+		chip->ident = V4L2_IDENT_AU0828;
+		return 0;
+	}
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
+	if (chip->ident == V4L2_IDENT_NONE)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int vidioc_cropcap(struct file *file, void *priv,
+			  struct v4l2_cropcap *cc)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+
+	if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	cc->bounds.left = 0;
+	cc->bounds.top = 0;
+	cc->bounds.width = dev->width;
+	cc->bounds.height = dev->height;
+
+	cc->defrect = cc->bounds;
+
+	cc->pixelaspect.numerator = 54;
+	cc->pixelaspect.denominator = 59;
+
+	return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type type)
+{
+	struct au0828_fh      *fh  = priv;
+	struct au0828_dev     *dev = fh->dev;
+	int                   rc = -EINVAL;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (unlikely(type != fh->type))
+		return -EINVAL;
+
+	dprintk(1, "vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
+		fh, type, fh->resources, dev->resources);
+
+	if (unlikely(!res_get(fh, get_ressource(fh))))
+		return -EBUSY;
+
+	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		au0828_analog_stream_enable(dev);
+		v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
+	}
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		rc = videobuf_streamon(&fh->vb_vidq);
+		dev->vid_timeout_running = 1;
+		mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
+	} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+		rc = videobuf_streamon(&fh->vb_vbiq);
+		dev->vbi_timeout_running = 1;
+		mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+	}
+
+	return rc;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type type)
+{
+	struct au0828_fh      *fh  = priv;
+	struct au0828_dev     *dev = fh->dev;
+	int                   rc;
+	int                   i;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
+		return -EINVAL;
+	if (type != fh->type)
+		return -EINVAL;
+
+	dprintk(1, "vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
+		fh, type, fh->resources, dev->resources);
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		dev->vid_timeout_running = 0;
+		del_timer_sync(&dev->vid_timeout);
+
+		v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+		rc = au0828_stream_interrupt(dev);
+		if (rc != 0)
+			return rc;
+
+		for (i = 0; i < AU0828_MAX_INPUT; i++) {
+			if (AUVI_INPUT(i).audio_setup == NULL)
+				continue;
+			(AUVI_INPUT(i).audio_setup)(dev, 0);
+		}
+
+		if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
+			videobuf_streamoff(&fh->vb_vidq);
+			res_free(fh, AU0828_RESOURCE_VIDEO);
+		}
+	} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+		dev->vbi_timeout_running = 0;
+		del_timer_sync(&dev->vbi_timeout);
+
+		if (res_check(fh, AU0828_RESOURCE_VBI)) {
+			videobuf_streamoff(&fh->vb_vbiq);
+			res_free(fh, AU0828_RESOURCE_VBI);
+		}
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *priv,
+			     struct v4l2_dbg_register *reg)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+
+	switch (reg->match.type) {
+	case V4L2_CHIP_MATCH_I2C_DRIVER:
+		v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
+		return 0;
+	default:
+		if (!v4l2_chip_match_host(&reg->match))
+			return -EINVAL;
+	}
+
+	reg->val = au0828_read(dev, reg->reg);
+	return 0;
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+			     struct v4l2_dbg_register *reg)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+
+	switch (reg->match.type) {
+	case V4L2_CHIP_MATCH_I2C_DRIVER:
+		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
+		return 0;
+	default:
+		if (!v4l2_chip_match_host(&reg->match))
+			return -EINVAL;
+	}
+	return au0828_writereg(dev, reg->reg, reg->val);
+}
+#endif
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *rb)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		rc = videobuf_reqbufs(&fh->vb_vidq, rb);
+	else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		rc = videobuf_reqbufs(&fh->vb_vbiq, rb);
+
+	return rc;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+			   struct v4l2_buffer *b)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		rc = videobuf_querybuf(&fh->vb_vidq, b);
+	else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		rc = videobuf_querybuf(&fh->vb_vbiq, b);
+
+	return rc;
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		rc = videobuf_qbuf(&fh->vb_vidq, b);
+	else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		rc = videobuf_qbuf(&fh->vb_vbiq, b);
+
+	return rc;
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct au0828_fh *fh = priv;
+	struct au0828_dev *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	/* Workaround for a bug in the au0828 hardware design that sometimes
+	   results in the colorspace being inverted */
+	if (dev->greenscreen_detected == 1) {
+		dprintk(1, "Detected green frame.  Resetting stream...\n");
+		au0828_analog_stream_reset(dev);
+		dev->greenscreen_detected = 0;
+	}
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		rc = videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
+	else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		rc = videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags & O_NONBLOCK);
+
+	return rc;
+}
+
+static struct v4l2_file_operations au0828_v4l_fops = {
+	.owner      = THIS_MODULE,
+	.open       = au0828_v4l2_open,
+	.release    = au0828_v4l2_close,
+	.read       = au0828_v4l2_read,
+	.poll       = au0828_v4l2_poll,
+	.mmap       = au0828_v4l2_mmap,
+	.unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+	.vidioc_querycap            = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap    = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap       = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap     = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap       = vidioc_s_fmt_vid_cap,
+	.vidioc_g_fmt_vbi_cap       = vidioc_g_fmt_vbi_cap,
+	.vidioc_s_fmt_vbi_cap       = vidioc_g_fmt_vbi_cap,
+	.vidioc_g_audio             = vidioc_g_audio,
+	.vidioc_s_audio             = vidioc_s_audio,
+	.vidioc_cropcap             = vidioc_cropcap,
+	.vidioc_reqbufs             = vidioc_reqbufs,
+	.vidioc_querybuf            = vidioc_querybuf,
+	.vidioc_qbuf                = vidioc_qbuf,
+	.vidioc_dqbuf               = vidioc_dqbuf,
+	.vidioc_s_std               = vidioc_s_std,
+	.vidioc_enum_input          = vidioc_enum_input,
+	.vidioc_g_input             = vidioc_g_input,
+	.vidioc_s_input             = vidioc_s_input,
+	.vidioc_queryctrl           = vidioc_queryctrl,
+	.vidioc_g_ctrl              = vidioc_g_ctrl,
+	.vidioc_s_ctrl              = vidioc_s_ctrl,
+	.vidioc_streamon            = vidioc_streamon,
+	.vidioc_streamoff           = vidioc_streamoff,
+	.vidioc_g_tuner             = vidioc_g_tuner,
+	.vidioc_s_tuner             = vidioc_s_tuner,
+	.vidioc_g_frequency         = vidioc_g_frequency,
+	.vidioc_s_frequency         = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register          = vidioc_g_register,
+	.vidioc_s_register          = vidioc_s_register,
+#endif
+	.vidioc_g_chip_ident        = vidioc_g_chip_ident,
+};
+
+static const struct video_device au0828_video_template = {
+	.fops                       = &au0828_v4l_fops,
+	.release                    = video_device_release,
+	.ioctl_ops 		    = &video_ioctl_ops,
+	.tvnorms                    = V4L2_STD_NTSC_M,
+	.current_norm               = V4L2_STD_NTSC_M,
+};
+
+/**************************************************************************/
+
+int au0828_analog_register(struct au0828_dev *dev,
+			   struct usb_interface *interface)
+{
+	int retval = -ENOMEM;
+	struct usb_host_interface *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	int i, ret;
+
+	dprintk(1, "au0828_analog_register called!\n");
+
+	/* set au0828 usb interface0 to as5 */
+	retval = usb_set_interface(dev->usbdev,
+			interface->cur_altsetting->desc.bInterfaceNumber, 5);
+	if (retval != 0) {
+		printk(KERN_INFO "Failure setting usb interface0 to as5\n");
+		return retval;
+	}
+
+	/* Figure out which endpoint has the isoc interface */
+	iface_desc = interface->cur_altsetting;
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
+		endpoint = &iface_desc->endpoint[i].desc;
+		if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+		     == USB_DIR_IN) &&
+		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+		     == USB_ENDPOINT_XFER_ISOC)) {
+
+			/* we find our isoc in endpoint */
+			u16 tmp = le16_to_cpu(endpoint->wMaxPacketSize);
+			dev->max_pkt_size = (tmp & 0x07ff) *
+				(((tmp & 0x1800) >> 11) + 1);
+			dev->isoc_in_endpointaddr = endpoint->bEndpointAddress;
+		}
+	}
+	if (!(dev->isoc_in_endpointaddr)) {
+		printk(KERN_INFO "Could not locate isoc endpoint\n");
+		kfree(dev);
+		return -ENODEV;
+	}
+
+	init_waitqueue_head(&dev->open);
+	spin_lock_init(&dev->slock);
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&dev->vidq.active);
+	INIT_LIST_HEAD(&dev->vidq.queued);
+	INIT_LIST_HEAD(&dev->vbiq.active);
+	INIT_LIST_HEAD(&dev->vbiq.queued);
+
+	dev->vid_timeout.function = au0828_vid_buffer_timeout;
+	dev->vid_timeout.data = (unsigned long) dev;
+	init_timer(&dev->vid_timeout);
+
+	dev->vbi_timeout.function = au0828_vbi_buffer_timeout;
+	dev->vbi_timeout.data = (unsigned long) dev;
+	init_timer(&dev->vbi_timeout);
+
+	dev->width = NTSC_STD_W;
+	dev->height = NTSC_STD_H;
+	dev->field_size = dev->width * dev->height;
+	dev->frame_size = dev->field_size << 1;
+	dev->bytesperline = dev->width << 1;
+	dev->ctrl_ainput = 0;
+
+	/* allocate and fill v4l2 video struct */
+	dev->vdev = video_device_alloc();
+	if (NULL == dev->vdev) {
+		dprintk(1, "Can't allocate video_device.\n");
+		return -ENOMEM;
+	}
+
+	/* allocate the VBI struct */
+	dev->vbi_dev = video_device_alloc();
+	if (NULL == dev->vbi_dev) {
+		dprintk(1, "Can't allocate vbi_device.\n");
+		ret = -ENOMEM;
+		goto err_vdev;
+	}
+
+	/* Fill the video capture device struct */
+	*dev->vdev = au0828_video_template;
+	dev->vdev->parent = &dev->usbdev->dev;
+	dev->vdev->lock = &dev->lock;
+	strcpy(dev->vdev->name, "au0828a video");
+
+	/* Setup the VBI device */
+	*dev->vbi_dev = au0828_video_template;
+	dev->vbi_dev->parent = &dev->usbdev->dev;
+	dev->vbi_dev->lock = &dev->lock;
+	strcpy(dev->vbi_dev->name, "au0828a vbi");
+
+	/* Register the v4l2 device */
+	video_set_drvdata(dev->vdev, dev);
+	retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1);
+	if (retval != 0) {
+		dprintk(1, "unable to register video device (error = %d).\n",
+			retval);
+		ret = -ENODEV;
+		goto err_vbi_dev;
+	}
+
+	/* Register the vbi device */
+	video_set_drvdata(dev->vbi_dev, dev);
+	retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1);
+	if (retval != 0) {
+		dprintk(1, "unable to register vbi device (error = %d).\n",
+			retval);
+		ret = -ENODEV;
+		goto err_vbi_dev;
+	}
+
+	dprintk(1, "%s completed!\n", __func__);
+
+	return 0;
+
+err_vbi_dev:
+	video_device_release(dev->vbi_dev);
+err_vdev:
+	video_device_release(dev->vdev);
+	return ret;
+}
+
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h
new file mode 100644
index 0000000..66a56ef
--- /dev/null
+++ b/drivers/media/usb/au0828/au0828.h
@@ -0,0 +1,304 @@
+/*
+ *  Driver for the Auvitek AU0828 USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <media/tveeprom.h>
+
+/* Analog */
+#include <linux/videodev2.h>
+#include <media/videobuf-vmalloc.h>
+#include <media/v4l2-device.h>
+
+/* DVB */
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+
+#include "au0828-reg.h"
+#include "au0828-cards.h"
+
+#define DRIVER_NAME "au0828"
+#define URB_COUNT   16
+#define URB_BUFSIZE (0xe522)
+
+/* Analog constants */
+#define NTSC_STD_W      720
+#define NTSC_STD_H      480
+
+#define AU0828_INTERLACED_DEFAULT       1
+#define V4L2_CID_PRIVATE_SHARPNESS  (V4L2_CID_PRIVATE_BASE + 0)
+
+/* Defination for AU0828 USB transfer */
+#define AU0828_MAX_ISO_BUFS    12  /* maybe resize this value in the future */
+#define AU0828_ISO_PACKETS_PER_URB      128
+
+#define AU0828_MIN_BUF 4
+#define AU0828_DEF_BUF 8
+
+#define AU0828_MAX_INPUT        4
+
+/* au0828 resource types (used for res_get/res_lock etc */
+#define AU0828_RESOURCE_VIDEO 0x01
+#define AU0828_RESOURCE_VBI   0x02
+
+enum au0828_itype {
+	AU0828_VMUX_UNDEFINED = 0,
+	AU0828_VMUX_COMPOSITE,
+	AU0828_VMUX_SVIDEO,
+	AU0828_VMUX_CABLE,
+	AU0828_VMUX_TELEVISION,
+	AU0828_VMUX_DVB,
+	AU0828_VMUX_DEBUG
+};
+
+struct au0828_input {
+	enum au0828_itype type;
+	unsigned int vmux;
+	unsigned int amux;
+	void (*audio_setup) (void *priv, int enable);
+};
+
+struct au0828_board {
+	char *name;
+	unsigned int tuner_type;
+	unsigned char tuner_addr;
+	unsigned char i2c_clk_divider;
+	struct au0828_input input[AU0828_MAX_INPUT];
+
+};
+
+struct au0828_dvb {
+	struct mutex lock;
+	struct dvb_adapter adapter;
+	struct dvb_frontend *frontend;
+	struct dvb_demux demux;
+	struct dmxdev dmxdev;
+	struct dmx_frontend fe_hw;
+	struct dmx_frontend fe_mem;
+	struct dvb_net net;
+	int feeding;
+};
+
+enum au0828_stream_state {
+	STREAM_OFF,
+	STREAM_INTERRUPT,
+	STREAM_ON
+};
+
+#define AUVI_INPUT(nr) (dev->board.input[nr])
+
+/* device state */
+enum au0828_dev_state {
+	DEV_INITIALIZED = 0x01,
+	DEV_DISCONNECTED = 0x02,
+	DEV_MISCONFIGURED = 0x04
+};
+
+struct au0828_fh {
+	struct au0828_dev *dev;
+	unsigned int  resources;
+
+	struct videobuf_queue        vb_vidq;
+	struct videobuf_queue        vb_vbiq;
+	enum v4l2_buf_type           type;
+};
+
+struct au0828_usb_isoc_ctl {
+		/* max packet size of isoc transaction */
+	int				max_pkt_size;
+
+		/* number of allocated urbs */
+	int				num_bufs;
+
+		/* urb for isoc transfers */
+	struct urb			**urb;
+
+		/* transfer buffers for isoc transfer */
+	char				**transfer_buffer;
+
+		/* Last buffer command and region */
+	u8				cmd;
+	int				pos, size, pktsize;
+
+		/* Last field: ODD or EVEN? */
+	int				field;
+
+		/* Stores incomplete commands */
+	u32				tmp_buf;
+	int				tmp_buf_len;
+
+		/* Stores already requested buffers */
+	struct au0828_buffer		*buf;
+	struct au0828_buffer		*vbi_buf;
+
+		/* Stores the number of received fields */
+	int				nfields;
+
+		/* isoc urb callback */
+	int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb);
+
+};
+
+/* buffer for one video frame */
+struct au0828_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+
+	struct list_head frame;
+	int top_field;
+	int receiving;
+};
+
+struct au0828_dmaqueue {
+	struct list_head       active;
+	struct list_head       queued;
+
+	wait_queue_head_t          wq;
+
+	/* Counters to control buffer fill */
+	int                        pos;
+};
+
+struct au0828_dev {
+	struct mutex mutex;
+	struct usb_device	*usbdev;
+	int			boardnr;
+	struct au0828_board	board;
+	u8			ctrlmsg[64];
+
+	/* I2C */
+	struct i2c_adapter		i2c_adap;
+	struct i2c_algorithm		i2c_algo;
+	struct i2c_client		i2c_client;
+	u32 				i2c_rc;
+
+	/* Digital */
+	struct au0828_dvb		dvb;
+	struct work_struct              restart_streaming;
+
+	/* Analog */
+	struct v4l2_device v4l2_dev;
+	int users;
+	unsigned int resources;	/* resources in use */
+	struct video_device *vdev;
+	struct video_device *vbi_dev;
+	struct timer_list vid_timeout;
+	int vid_timeout_running;
+	struct timer_list vbi_timeout;
+	int vbi_timeout_running;
+	int width;
+	int height;
+	int vbi_width;
+	int vbi_height;
+	u32 vbi_read;
+	u32 field_size;
+	u32 frame_size;
+	u32 bytesperline;
+	int type;
+	u8 ctrl_ainput;
+	__u8 isoc_in_endpointaddr;
+	u8 isoc_init_ok;
+	int greenscreen_detected;
+	unsigned int frame_count;
+	int ctrl_freq;
+	int input_type;
+	int std_set_in_tuner_core;
+	unsigned int ctrl_input;
+	enum au0828_dev_state dev_state;
+	enum au0828_stream_state stream_state;
+	wait_queue_head_t open;
+
+	struct mutex lock;
+
+	/* Isoc control struct */
+	struct au0828_dmaqueue vidq;
+	struct au0828_dmaqueue vbiq;
+	struct au0828_usb_isoc_ctl isoc_ctl;
+	spinlock_t slock;
+
+	/* usb transfer */
+	int alt;		/* alternate */
+	int max_pkt_size;	/* max packet size of isoc transaction */
+	int num_alt;		/* Number of alternative settings */
+	unsigned int *alt_max_pkt_size;	/* array of wMaxPacketSize */
+	struct urb *urb[AU0828_MAX_ISO_BUFS];	/* urb for isoc transfers */
+	char *transfer_buffer[AU0828_MAX_ISO_BUFS];/* transfer buffers for isoc
+						   transfer */
+
+	/* USB / URB Related */
+	int		urb_streaming;
+	struct urb	*urbs[URB_COUNT];
+};
+
+/* ----------------------------------------------------------- */
+#define au0828_read(dev, reg) au0828_readreg(dev, reg)
+#define au0828_write(dev, reg, value) au0828_writereg(dev, reg, value)
+#define au0828_andor(dev, reg, mask, value) 				\
+	 au0828_writereg(dev, reg, 					\
+	(au0828_readreg(dev, reg) & ~(mask)) | ((value) & (mask)))
+
+#define au0828_set(dev, reg, bit) au0828_andor(dev, (reg), (bit), (bit))
+#define au0828_clear(dev, reg, bit) au0828_andor(dev, (reg), (bit), 0)
+
+/* ----------------------------------------------------------- */
+/* au0828-core.c */
+extern u32 au0828_read(struct au0828_dev *dev, u16 reg);
+extern u32 au0828_write(struct au0828_dev *dev, u16 reg, u32 val);
+extern int au0828_debug;
+
+/* ----------------------------------------------------------- */
+/* au0828-cards.c */
+extern struct au0828_board au0828_boards[];
+extern struct usb_device_id au0828_usb_id_table[];
+extern void au0828_gpio_setup(struct au0828_dev *dev);
+extern int au0828_tuner_callback(void *priv, int component,
+				 int command, int arg);
+extern void au0828_card_setup(struct au0828_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* au0828-i2c.c */
+extern int au0828_i2c_register(struct au0828_dev *dev);
+extern int au0828_i2c_unregister(struct au0828_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* au0828-video.c */
+int au0828_analog_register(struct au0828_dev *dev,
+			   struct usb_interface *interface);
+int au0828_analog_stream_disable(struct au0828_dev *d);
+void au0828_analog_unregister(struct au0828_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* au0828-dvb.c */
+extern int au0828_dvb_register(struct au0828_dev *dev);
+extern void au0828_dvb_unregister(struct au0828_dev *dev);
+
+/* au0828-vbi.c */
+extern struct videobuf_queue_ops au0828_vbi_qops;
+
+#define dprintk(level, fmt, arg...)\
+	do { if (au0828_debug & level)\
+		printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
+	} while (0)
diff --git a/drivers/media/usb/b2c2/Kconfig b/drivers/media/usb/b2c2/Kconfig
new file mode 100644
index 0000000..3af7c41
--- /dev/null
+++ b/drivers/media/usb/b2c2/Kconfig
@@ -0,0 +1,6 @@
+config DVB_B2C2_FLEXCOP_USB
+	tristate "Technisat/B2C2 Air/Sky/Cable2PC USB"
+	help
+	  Support for the Air/Sky/Cable2PC USB1.1 box (DVB/ATSC) by Technisat/B2C2,
+
+	  Say Y if you own such a device and want to use it.
diff --git a/drivers/media/usb/b2c2/Makefile b/drivers/media/usb/b2c2/Makefile
new file mode 100644
index 0000000..2778c19
--- /dev/null
+++ b/drivers/media/usb/b2c2/Makefile
@@ -0,0 +1,5 @@
+b2c2-flexcop-usb-objs := flexcop-usb.o
+obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
+
+ccflags-y += -Idrivers/media/dvb-core/
+ccflags-y += -Idrivers/media/common/b2c2/
diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c
new file mode 100644
index 0000000..8b6275f
--- /dev/null
+++ b/drivers/media/usb/b2c2/flexcop-usb.c
@@ -0,0 +1,587 @@
+/*
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-usb.c - covers the USB part
+ * see flexcop.c for copyright information
+ */
+#define FC_LOG_PREFIX "flexcop_usb"
+#include "flexcop-usb.h"
+#include "flexcop-common.h"
+
+/* Version information */
+#define DRIVER_VERSION "0.1"
+#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver"
+#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
+
+/* debug */
+#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
+#define dprintk(level,args...) \
+	do { if ((debug & level)) printk(args); } while (0)
+
+#define debug_dump(b, l, method) do {\
+	int i; \
+	for (i = 0; i < l; i++) \
+		method("%02x ", b[i]); \
+	method("\n"); \
+} while (0)
+
+#define DEBSTATUS ""
+#else
+#define dprintk(level, args...)
+#define debug_dump(b, l, method)
+#define DEBSTATUS " (debugging is not enabled)"
+#endif
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,"
+		"ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS);
+#undef DEBSTATUS
+
+#define deb_info(args...) dprintk(0x01, args)
+#define deb_ts(args...) dprintk(0x02, args)
+#define deb_ctrl(args...) dprintk(0x04, args)
+#define deb_i2c(args...) dprintk(0x08, args)
+#define deb_v8(args...) dprintk(0x10, args)
+
+/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits
+ * in the IBI address, to make the V8 code simpler.
+ * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (the six bits used)
+ *                  in general: 0000 0HHH 000L LL00
+ * IBI ADDRESS FORMAT:                    RHHH BLLL
+ *
+ * where R is the read(1)/write(0) bit, B is the busy bit
+ * and HHH and LLL are the two sets of three bits from the PCI address.
+ */
+#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) \
+	(((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
+#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) \
+	(((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
+
+/*
+ * DKT 020228
+ * - forget about this VENDOR_BUFFER_SIZE, read and write register
+ *   deal with DWORD or 4 bytes, that should be should from now on
+ * - from now on, we don't support anything older than firm 1.00
+ *   I eliminated the write register as a 2 trip of writing hi word and lo word
+ *   and force this to write only 4 bytes at a time.
+ *   NOTE: this should work with all the firmware from 1.00 and newer
+ */
+static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI, u32 *val, u8 read)
+{
+	struct flexcop_usb *fc_usb = fc->bus_specific;
+	u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG;
+	u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR;
+	u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) |
+		(read ? 0x80 : 0);
+
+	int len = usb_control_msg(fc_usb->udev,
+			read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT,
+			request,
+			request_type, /* 0xc0 read or 0x40 write */
+			wAddress,
+			0,
+			val,
+			sizeof(u32),
+			B2C2_WAIT_FOR_OPERATION_RDW * HZ);
+
+	if (len != sizeof(u32)) {
+		err("error while %s dword from %d (%d).", read ? "reading" :
+				"writing", wAddress, wRegOffsPCI);
+		return -EIO;
+	}
+	return 0;
+}
+/*
+ * DKT 010817 - add support for V8 memory read/write and flash update
+ */
+static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
+		flexcop_usb_request_t req, u8 page, u16 wAddress,
+		u8 *pbBuffer, u32 buflen)
+{
+	u8 request_type = USB_TYPE_VENDOR;
+	u16 wIndex;
+	int nWaitTime, pipe, len;
+	wIndex = page << 8;
+
+	switch (req) {
+	case B2C2_USB_READ_V8_MEM:
+		nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
+		request_type |= USB_DIR_IN;
+		pipe = B2C2_USB_CTRL_PIPE_IN;
+		break;
+	case B2C2_USB_WRITE_V8_MEM:
+		wIndex |= pbBuffer[0];
+		request_type |= USB_DIR_OUT;
+		nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE;
+		pipe = B2C2_USB_CTRL_PIPE_OUT;
+		break;
+	case B2C2_USB_FLASH_BLOCK:
+		request_type |= USB_DIR_OUT;
+		nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH;
+		pipe = B2C2_USB_CTRL_PIPE_OUT;
+		break;
+	default:
+		deb_info("unsupported request for v8_mem_req %x.\n", req);
+		return -EINVAL;
+	}
+	deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n", request_type, req,
+			wAddress, wIndex, buflen);
+
+	len = usb_control_msg(fc_usb->udev, pipe,
+			req,
+			request_type,
+			wAddress,
+			wIndex,
+			pbBuffer,
+			buflen,
+			nWaitTime * HZ);
+
+	debug_dump(pbBuffer, len, deb_v8);
+	return len == buflen ? 0 : -EIO;
+}
+
+#define bytes_left_to_read_on_page(paddr,buflen) \
+	((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \
+	 ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)))
+
+static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
+		flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start,
+		u32 addr, int extended, u8 *buf, u32 len)
+{
+	int i,ret = 0;
+	u16 wMax;
+	u32 pagechunk = 0;
+
+	switch(req) {
+	case B2C2_USB_READ_V8_MEM:
+		wMax = USB_MEM_READ_MAX;
+		break;
+	case B2C2_USB_WRITE_V8_MEM:
+		wMax = USB_MEM_WRITE_MAX;
+		break;
+	case B2C2_USB_FLASH_BLOCK:
+		wMax = USB_FLASH_MAX;
+		break;
+	default:
+		return -EINVAL;
+		break;
+	}
+	for (i = 0; i < len;) {
+		pagechunk =
+			wMax < bytes_left_to_read_on_page(addr, len) ?
+				wMax :
+				bytes_left_to_read_on_page(addr, len);
+		deb_info("%x\n",
+			(addr & V8_MEMORY_PAGE_MASK) |
+				(V8_MEMORY_EXTENDED*extended));
+
+		ret = flexcop_usb_v8_memory_req(fc_usb, req,
+			page_start + (addr / V8_MEMORY_PAGE_SIZE),
+			(addr & V8_MEMORY_PAGE_MASK) |
+				(V8_MEMORY_EXTENDED*extended),
+			&buf[i], pagechunk);
+
+		if (ret < 0)
+			return ret;
+		addr += pagechunk;
+		len -= pagechunk;
+	}
+	return 0;
+}
+
+static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended)
+{
+	return flexcop_usb_memory_req(fc->bus_specific, B2C2_USB_READ_V8_MEM,
+		V8_MEMORY_PAGE_FLASH, 0x1f010, 1,
+		fc->dvb_adapter.proposed_mac, 6);
+}
+
+#if 0
+static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set,
+		flexcop_usb_utility_function_t func, u8 extra, u16 wIndex,
+		u16 buflen, u8 *pvBuffer)
+{
+	u16 wValue;
+	u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR;
+	int nWaitTime = 2,
+	    pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, len;
+	wValue = (func << 8) | extra;
+
+	len = usb_control_msg(fc_usb->udev,pipe,
+			B2C2_USB_UTILITY,
+			request_type,
+			wValue,
+			wIndex,
+			pvBuffer,
+			buflen,
+			nWaitTime * HZ);
+	return len == buflen ? 0 : -EIO;
+}
+#endif
+
+/* usb i2c stuff */
+static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
+		flexcop_usb_request_t req, flexcop_usb_i2c_function_t func,
+		u8 chipaddr, u8 addr, u8 *buf, u8 buflen)
+{
+	struct flexcop_usb *fc_usb = i2c->fc->bus_specific;
+	u16 wValue, wIndex;
+	int nWaitTime,pipe,len;
+	u8 request_type = USB_TYPE_VENDOR;
+
+	switch (func) {
+	case USB_FUNC_I2C_WRITE:
+	case USB_FUNC_I2C_MULTIWRITE:
+	case USB_FUNC_I2C_REPEATWRITE:
+		/* DKT 020208 - add this to support special case of DiSEqC */
+	case USB_FUNC_I2C_CHECKWRITE:
+		pipe = B2C2_USB_CTRL_PIPE_OUT;
+		nWaitTime = 2;
+		request_type |= USB_DIR_OUT;
+		break;
+	case USB_FUNC_I2C_READ:
+	case USB_FUNC_I2C_REPEATREAD:
+		pipe = B2C2_USB_CTRL_PIPE_IN;
+		nWaitTime = 2;
+		request_type |= USB_DIR_IN;
+		break;
+	default:
+		deb_info("unsupported function for i2c_req %x\n", func);
+		return -EINVAL;
+	}
+	wValue = (func << 8) | (i2c->port << 4);
+	wIndex = (chipaddr << 8 ) | addr;
+
+	deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",
+			func, request_type, req,
+			wValue & 0xff, wValue >> 8,
+			wIndex & 0xff, wIndex >> 8);
+
+	len = usb_control_msg(fc_usb->udev,pipe,
+			req,
+			request_type,
+			wValue,
+			wIndex,
+			buf,
+			buflen,
+			nWaitTime * HZ);
+	return len == buflen ? 0 : -EREMOTEIO;
+}
+
+/* actual bus specific access functions,
+   make sure prototype are/will be equal to pci */
+static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc,
+	flexcop_ibi_register reg)
+{
+	flexcop_ibi_value val;
+	val.raw = 0;
+	flexcop_usb_readwrite_dw(fc, reg, &val.raw, 1);
+	return val;
+}
+
+static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc,
+		flexcop_ibi_register reg, flexcop_ibi_value val)
+{
+	return flexcop_usb_readwrite_dw(fc, reg, &val.raw, 0);
+}
+
+static int flexcop_usb_i2c_request(struct flexcop_i2c_adapter *i2c,
+		flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
+{
+	if (op == FC_READ)
+		return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
+				USB_FUNC_I2C_READ, chipaddr, addr, buf, len);
+	else
+		return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
+				USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len);
+}
+
+static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb,
+	u8 *buffer, int buffer_length)
+{
+	u8 *b;
+	int l;
+
+	deb_ts("tmp_buffer_length=%d, buffer_length=%d\n",
+		fc_usb->tmp_buffer_length, buffer_length);
+
+	if (fc_usb->tmp_buffer_length > 0) {
+		memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer,
+				buffer_length);
+		fc_usb->tmp_buffer_length += buffer_length;
+		b = fc_usb->tmp_buffer;
+		l = fc_usb->tmp_buffer_length;
+	} else {
+		b=buffer;
+		l=buffer_length;
+	}
+
+	while (l >= 190) {
+		if (*b == 0xff) {
+			switch (*(b+1) & 0x03) {
+			case 0x01: /* media packet */
+				if (*(b+2) == 0x47)
+					flexcop_pass_dmx_packets(
+							fc_usb->fc_dev, b+2, 1);
+				else
+					deb_ts("not ts packet %*ph\n", 4, b+2);
+				b += 190;
+				l -= 190;
+				break;
+			default:
+				deb_ts("wrong packet type\n");
+				l = 0;
+				break;
+			}
+		} else {
+			deb_ts("wrong header\n");
+			l = 0;
+		}
+	}
+
+	if (l>0)
+		memcpy(fc_usb->tmp_buffer, b, l);
+	fc_usb->tmp_buffer_length = l;
+}
+
+static void flexcop_usb_urb_complete(struct urb *urb)
+{
+	struct flexcop_usb *fc_usb = urb->context;
+	int i;
+
+	if (urb->actual_length > 0)
+		deb_ts("urb completed, bufsize: %d actlen; %d\n",
+			urb->transfer_buffer_length, urb->actual_length);
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		if (urb->iso_frame_desc[i].status < 0) {
+			err("iso frame descriptor %d has an error: %d\n", i,
+				urb->iso_frame_desc[i].status);
+		} else
+			if (urb->iso_frame_desc[i].actual_length > 0) {
+				deb_ts("passed %d bytes to the demux\n",
+					urb->iso_frame_desc[i].actual_length);
+
+				flexcop_usb_process_frame(fc_usb,
+					urb->transfer_buffer +
+						urb->iso_frame_desc[i].offset,
+					urb->iso_frame_desc[i].actual_length);
+			}
+		urb->iso_frame_desc[i].status = 0;
+		urb->iso_frame_desc[i].actual_length = 0;
+	}
+	usb_submit_urb(urb,GFP_ATOMIC);
+}
+
+static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff)
+{
+	/* submit/kill iso packets */
+	return 0;
+}
+
+static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
+{
+	int i;
+	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
+		if (fc_usb->iso_urb[i] != NULL) {
+			deb_ts("unlinking/killing urb no. %d\n",i);
+			usb_kill_urb(fc_usb->iso_urb[i]);
+			usb_free_urb(fc_usb->iso_urb[i]);
+		}
+
+	if (fc_usb->iso_buffer != NULL)
+		pci_free_consistent(NULL,
+			fc_usb->buffer_size, fc_usb->iso_buffer,
+			fc_usb->dma_addr);
+}
+
+static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
+{
+	u16 frame_size = le16_to_cpu(
+		fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize);
+	int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO *
+		frame_size, i, j, ret;
+	int buffer_offset = 0;
+
+	deb_ts("creating %d iso-urbs with %d frames "
+			"each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB,
+			B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize);
+
+	fc_usb->iso_buffer = pci_alloc_consistent(NULL,
+			bufsize, &fc_usb->dma_addr);
+	if (fc_usb->iso_buffer == NULL)
+		return -ENOMEM;
+
+	memset(fc_usb->iso_buffer, 0, bufsize);
+	fc_usb->buffer_size = bufsize;
+
+	/* creating iso urbs */
+	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
+		fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,
+			GFP_ATOMIC);
+		if (fc_usb->iso_urb[i] == NULL) {
+			ret = -ENOMEM;
+			goto urb_error;
+		}
+	}
+
+	/* initialising and submitting iso urbs */
+	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
+		int frame_offset = 0;
+		struct urb *urb = fc_usb->iso_urb[i];
+		deb_ts("initializing and submitting urb no. %d "
+			"(buf_offset: %d).\n", i, buffer_offset);
+
+		urb->dev = fc_usb->udev;
+		urb->context = fc_usb;
+		urb->complete = flexcop_usb_urb_complete;
+		urb->pipe = B2C2_USB_DATA_PIPE;
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->interval = 1;
+		urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO;
+		urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO;
+		urb->transfer_buffer = fc_usb->iso_buffer + buffer_offset;
+
+		buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO;
+		for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) {
+			deb_ts("urb no: %d, frame: %d, frame_offset: %d\n",
+					i, j, frame_offset);
+			urb->iso_frame_desc[j].offset = frame_offset;
+			urb->iso_frame_desc[j].length = frame_size;
+			frame_offset += frame_size;
+		}
+
+		if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) {
+			err("submitting urb %d failed with %d.", i, ret);
+			goto urb_error;
+		}
+		deb_ts("submitted urb no. %d.\n",i);
+	}
+
+	/* SRAM */
+	flexcop_sram_set_dest(fc_usb->fc_dev, FC_SRAM_DEST_MEDIA |
+			FC_SRAM_DEST_NET | FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI,
+			FC_SRAM_DEST_TARGET_WAN_USB);
+	flexcop_wan_set_speed(fc_usb->fc_dev, FC_WAN_SPEED_8MBITS);
+	flexcop_sram_ctrl(fc_usb->fc_dev, 1, 1, 1);
+	return 0;
+
+urb_error:
+	flexcop_usb_transfer_exit(fc_usb);
+	return ret;
+}
+
+static int flexcop_usb_init(struct flexcop_usb *fc_usb)
+{
+	/* use the alternate setting with the larges buffer */
+	usb_set_interface(fc_usb->udev,0,1);
+	switch (fc_usb->udev->speed) {
+	case USB_SPEED_LOW:
+		err("cannot handle USB speed because it is too slow.");
+		return -ENODEV;
+		break;
+	case USB_SPEED_FULL:
+		info("running at FULL speed.");
+		break;
+	case USB_SPEED_HIGH:
+		info("running at HIGH speed.");
+		break;
+	case USB_SPEED_UNKNOWN: /* fall through */
+	default:
+		err("cannot handle USB speed because it is unknown.");
+		return -ENODEV;
+	}
+	usb_set_intfdata(fc_usb->uintf, fc_usb);
+	return 0;
+}
+
+static void flexcop_usb_exit(struct flexcop_usb *fc_usb)
+{
+	usb_set_intfdata(fc_usb->uintf, NULL);
+}
+
+static int flexcop_usb_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct flexcop_usb *fc_usb = NULL;
+	struct flexcop_device *fc = NULL;
+	int ret;
+
+	if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) {
+		err("out of memory\n");
+		return -ENOMEM;
+	}
+
+	/* general flexcop init */
+	fc_usb = fc->bus_specific;
+	fc_usb->fc_dev = fc;
+
+	fc->read_ibi_reg  = flexcop_usb_read_ibi_reg;
+	fc->write_ibi_reg = flexcop_usb_write_ibi_reg;
+	fc->i2c_request = flexcop_usb_i2c_request;
+	fc->get_mac_addr = flexcop_usb_get_mac_addr;
+
+	fc->stream_control = flexcop_usb_stream_control;
+
+	fc->pid_filtering = 1;
+	fc->bus_type = FC_USB;
+
+	fc->dev = &udev->dev;
+	fc->owner = THIS_MODULE;
+
+	/* bus specific part */
+	fc_usb->udev = udev;
+	fc_usb->uintf = intf;
+	if ((ret = flexcop_usb_init(fc_usb)) != 0)
+		goto err_kfree;
+
+	/* init flexcop */
+	if ((ret = flexcop_device_initialize(fc)) != 0)
+		goto err_usb_exit;
+
+	/* xfer init */
+	if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0)
+		goto err_fc_exit;
+
+	info("%s successfully initialized and connected.", DRIVER_NAME);
+	return 0;
+
+err_fc_exit:
+	flexcop_device_exit(fc);
+err_usb_exit:
+	flexcop_usb_exit(fc_usb);
+err_kfree:
+	flexcop_device_kfree(fc);
+	return ret;
+}
+
+static void flexcop_usb_disconnect(struct usb_interface *intf)
+{
+	struct flexcop_usb *fc_usb = usb_get_intfdata(intf);
+	flexcop_usb_transfer_exit(fc_usb);
+	flexcop_device_exit(fc_usb->fc_dev);
+	flexcop_usb_exit(fc_usb);
+	flexcop_device_kfree(fc_usb->fc_dev);
+	info("%s successfully deinitialized and disconnected.", DRIVER_NAME);
+}
+
+static struct usb_device_id flexcop_usb_table [] = {
+	{ USB_DEVICE(0x0af7, 0x0101) },
+	{ }
+};
+MODULE_DEVICE_TABLE (usb, flexcop_usb_table);
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver flexcop_usb_driver = {
+	.name		= "b2c2_flexcop_usb",
+	.probe		= flexcop_usb_probe,
+	.disconnect = flexcop_usb_disconnect,
+	.id_table	= flexcop_usb_table,
+};
+
+module_usb_driver(flexcop_usb_driver);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_NAME);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/b2c2/flexcop-usb.h b/drivers/media/usb/b2c2/flexcop-usb.h
new file mode 100644
index 0000000..92529a9
--- /dev/null
+++ b/drivers/media/usb/b2c2/flexcop-usb.h
@@ -0,0 +1,111 @@
+/*
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-usb.h - header file for the USB part
+ * see flexcop.c for copyright information
+ */
+#ifndef __FLEXCOP_USB_H_INCLUDED__
+#define __FLEXCOP_USB_H_INCLUDED__
+
+#include <linux/usb.h>
+
+/* transfer parameters */
+#define B2C2_USB_FRAMES_PER_ISO 4
+#define B2C2_USB_NUM_ISO_URB 4
+
+#define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(fc_usb->udev, 0)
+#define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(fc_usb->udev, 0)
+#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(fc_usb->udev, 0x81)
+
+struct flexcop_usb {
+	struct usb_device *udev;
+	struct usb_interface *uintf;
+
+	u8 *iso_buffer;
+	int buffer_size;
+	dma_addr_t dma_addr;
+
+	struct urb *iso_urb[B2C2_USB_NUM_ISO_URB];
+	struct flexcop_device *fc_dev;
+
+	u8 tmp_buffer[1023+190];
+	int tmp_buffer_length;
+};
+
+#if 0
+/* request types TODO What is its use?*/
+typedef enum {
+
+} flexcop_usb_request_type_t;
+#endif
+
+/* request */
+typedef enum {
+	B2C2_USB_WRITE_V8_MEM = 0x04,
+	B2C2_USB_READ_V8_MEM  = 0x05,
+	B2C2_USB_READ_REG     = 0x08,
+	B2C2_USB_WRITE_REG    = 0x0A,
+	B2C2_USB_WRITEREGHI   = 0x0B,
+	B2C2_USB_FLASH_BLOCK  = 0x10,
+	B2C2_USB_I2C_REQUEST  = 0x11,
+	B2C2_USB_UTILITY      = 0x12,
+} flexcop_usb_request_t;
+
+/* function definition for I2C_REQUEST */
+typedef enum {
+	USB_FUNC_I2C_WRITE       = 0x01,
+	USB_FUNC_I2C_MULTIWRITE  = 0x02,
+	USB_FUNC_I2C_READ        = 0x03,
+	USB_FUNC_I2C_REPEATWRITE = 0x04,
+	USB_FUNC_GET_DESCRIPTOR  = 0x05,
+	USB_FUNC_I2C_REPEATREAD  = 0x06,
+	/* DKT 020208 - add this to support special case of DiSEqC */
+	USB_FUNC_I2C_CHECKWRITE  = 0x07,
+	USB_FUNC_I2C_CHECKRESULT = 0x08,
+} flexcop_usb_i2c_function_t;
+
+/* function definition for UTILITY request 0x12
+ * DKT 020304 - new utility function */
+typedef enum {
+	UTILITY_SET_FILTER          = 0x01,
+	UTILITY_DATA_ENABLE         = 0x02,
+	UTILITY_FLEX_MULTIWRITE     = 0x03,
+	UTILITY_SET_BUFFER_SIZE     = 0x04,
+	UTILITY_FLEX_OPERATOR       = 0x05,
+	UTILITY_FLEX_RESET300_START = 0x06,
+	UTILITY_FLEX_RESET300_STOP  = 0x07,
+	UTILITY_FLEX_RESET300       = 0x08,
+	UTILITY_SET_ISO_SIZE        = 0x09,
+	UTILITY_DATA_RESET          = 0x0A,
+	UTILITY_GET_DATA_STATUS     = 0x10,
+	UTILITY_GET_V8_REG          = 0x11,
+	/* DKT 020326 - add function for v1.14 */
+	UTILITY_SRAM_WRITE          = 0x12,
+	UTILITY_SRAM_READ           = 0x13,
+	UTILITY_SRAM_TESTFILL       = 0x14,
+	UTILITY_SRAM_TESTSET        = 0x15,
+	UTILITY_SRAM_TESTVERIFY     = 0x16,
+} flexcop_usb_utility_function_t;
+
+#define B2C2_WAIT_FOR_OPERATION_RW (1*HZ)
+#define B2C2_WAIT_FOR_OPERATION_RDW (3*HZ)
+#define B2C2_WAIT_FOR_OPERATION_WDW (1*HZ)
+
+#define B2C2_WAIT_FOR_OPERATION_V8READ (3*HZ)
+#define B2C2_WAIT_FOR_OPERATION_V8WRITE (3*HZ)
+#define B2C2_WAIT_FOR_OPERATION_V8FLASH (3*HZ)
+
+typedef enum {
+	V8_MEMORY_PAGE_DVB_CI = 0x20,
+	V8_MEMORY_PAGE_DVB_DS = 0x40,
+	V8_MEMORY_PAGE_MULTI2 = 0x60,
+	V8_MEMORY_PAGE_FLASH  = 0x80
+} flexcop_usb_mem_page_t;
+
+#define V8_MEMORY_EXTENDED (1 << 15)
+#define USB_MEM_READ_MAX   32
+#define USB_MEM_WRITE_MAX   1
+#define USB_FLASH_MAX       8
+#define V8_MEMORY_PAGE_SIZE 0x8000 /* 32K */
+#define V8_MEMORY_PAGE_MASK 0x7FFF
+
+#endif
diff --git a/drivers/media/usb/cpia2/Kconfig b/drivers/media/usb/cpia2/Kconfig
new file mode 100644
index 0000000..66e9283
--- /dev/null
+++ b/drivers/media/usb/cpia2/Kconfig
@@ -0,0 +1,9 @@
+config VIDEO_CPIA2
+	tristate "CPiA2 Video For Linux"
+	depends on VIDEO_DEV && USB && VIDEO_V4L2
+	---help---
+	  This is the video4linux driver for cameras based on Vision's CPiA2
+	  (Colour Processor Interface ASIC), such as the Digital Blue QX5
+	  Microscope. If you have one of these cameras, say Y here
+
+	  This driver is also available as a module (cpia2).
diff --git a/drivers/media/usb/cpia2/Makefile b/drivers/media/usb/cpia2/Makefile
new file mode 100644
index 0000000..828cf1b
--- /dev/null
+++ b/drivers/media/usb/cpia2/Makefile
@@ -0,0 +1,3 @@
+cpia2-objs	:= cpia2_v4l.o cpia2_usb.o cpia2_core.o
+
+obj-$(CONFIG_VIDEO_CPIA2) += cpia2.o
diff --git a/drivers/media/usb/cpia2/cpia2.h b/drivers/media/usb/cpia2/cpia2.h
new file mode 100644
index 0000000..cdef677
--- /dev/null
+++ b/drivers/media/usb/cpia2/cpia2.h
@@ -0,0 +1,487 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2.h
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *
+ *  Contact:  steve.miller@st.com
+ *
+ *  Description:
+ *     This is a USB driver for CPiA2 based video cameras.
+ *
+ *     This driver is modelled on the cpia usb driver by
+ *     Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************************/
+
+#ifndef __CPIA2_H__
+#define __CPIA2_H__
+
+#include <linux/videodev2.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#include "cpia2_registers.h"
+
+/* define for verbose debug output */
+//#define _CPIA2_DEBUG_
+
+/***
+ * Image defines
+ ***/
+
+/*  Misc constants */
+#define ALLOW_CORRUPT 0		/* Causes collater to discard checksum */
+
+/* USB Transfer mode */
+#define XFER_ISOC 0
+#define XFER_BULK 1
+
+/* USB Alternates */
+#define USBIF_CMDONLY 0
+#define USBIF_BULK 1
+#define USBIF_ISO_1 2	/*  128 bytes/ms */
+#define USBIF_ISO_2 3	/*  384 bytes/ms */
+#define USBIF_ISO_3 4	/*  640 bytes/ms */
+#define USBIF_ISO_4 5	/*  768 bytes/ms */
+#define USBIF_ISO_5 6	/*  896 bytes/ms */
+#define USBIF_ISO_6 7	/* 1023 bytes/ms */
+
+/* Flicker Modes */
+#define NEVER_FLICKER   0
+#define FLICKER_60      60
+#define FLICKER_50      50
+
+/* Debug flags */
+#define DEBUG_NONE          0
+#define DEBUG_REG           0x00000001
+#define DEBUG_DUMP_PATCH    0x00000002
+#define DEBUG_DUMP_REGS     0x00000004
+
+/***
+ * Video frame sizes
+ ***/
+enum {
+	VIDEOSIZE_VGA = 0,	/* 640x480 */
+	VIDEOSIZE_CIF,		/* 352x288 */
+	VIDEOSIZE_QVGA,		/* 320x240 */
+	VIDEOSIZE_QCIF,		/* 176x144 */
+	VIDEOSIZE_288_216,
+	VIDEOSIZE_256_192,
+	VIDEOSIZE_224_168,
+	VIDEOSIZE_192_144,
+};
+
+#define STV_IMAGE_CIF_ROWS    288
+#define STV_IMAGE_CIF_COLS    352
+
+#define STV_IMAGE_QCIF_ROWS   144
+#define STV_IMAGE_QCIF_COLS   176
+
+#define STV_IMAGE_VGA_ROWS    480
+#define STV_IMAGE_VGA_COLS    640
+
+#define STV_IMAGE_QVGA_ROWS   240
+#define STV_IMAGE_QVGA_COLS   320
+
+#define JPEG_MARKER_COM (1<<6)	/* Comment segment */
+
+/***
+ * Enums
+ ***/
+/* Sensor types available with cpia2 asics */
+enum sensors {
+	CPIA2_SENSOR_410,
+	CPIA2_SENSOR_500
+};
+
+/* Asic types available in the CPiA2 architecture */
+#define  CPIA2_ASIC_672 0x67
+
+/* Device types (stv672, stv676, etc) */
+#define  DEVICE_STV_672   0x0001
+#define  DEVICE_STV_676   0x0002
+
+enum frame_status {
+	FRAME_EMPTY,
+	FRAME_READING,		/* In the process of being grabbed into */
+	FRAME_READY,		/* Ready to be read */
+	FRAME_ERROR,
+};
+
+/***
+ * Register access (for USB request byte)
+ ***/
+enum {
+	CAMERAACCESS_SYSTEM = 0,
+	CAMERAACCESS_VC,
+	CAMERAACCESS_VP,
+	CAMERAACCESS_IDATA
+};
+
+#define CAMERAACCESS_TYPE_BLOCK    0x00
+#define CAMERAACCESS_TYPE_RANDOM   0x04
+#define CAMERAACCESS_TYPE_MASK     0x08
+#define CAMERAACCESS_TYPE_REPEAT   0x0C
+
+#define TRANSFER_READ 0
+#define TRANSFER_WRITE 1
+
+#define DEFAULT_ALT   USBIF_ISO_6
+#define DEFAULT_BRIGHTNESS 0x46
+#define DEFAULT_CONTRAST 0x93
+#define DEFAULT_SATURATION 0x7f
+
+/* Power state */
+#define HI_POWER_MODE CPIA2_SYSTEM_CONTROL_HIGH_POWER
+#define LO_POWER_MODE CPIA2_SYSTEM_CONTROL_LOW_POWER
+
+
+/********
+ * Commands
+ *******/
+enum {
+	CPIA2_CMD_NONE = 0,
+	CPIA2_CMD_GET_VERSION,
+	CPIA2_CMD_GET_PNP_ID,
+	CPIA2_CMD_GET_ASIC_TYPE,
+	CPIA2_CMD_GET_SENSOR,
+	CPIA2_CMD_GET_VP_DEVICE,
+	CPIA2_CMD_GET_VP_BRIGHTNESS,
+	CPIA2_CMD_SET_VP_BRIGHTNESS,
+	CPIA2_CMD_GET_CONTRAST,
+	CPIA2_CMD_SET_CONTRAST,
+	CPIA2_CMD_GET_VP_SATURATION,
+	CPIA2_CMD_SET_VP_SATURATION,
+	CPIA2_CMD_GET_VP_GPIO_DIRECTION,
+	CPIA2_CMD_SET_VP_GPIO_DIRECTION,
+	CPIA2_CMD_GET_VP_GPIO_DATA,
+	CPIA2_CMD_SET_VP_GPIO_DATA,
+	CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION,
+	CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+	CPIA2_CMD_GET_VC_MP_GPIO_DATA,
+	CPIA2_CMD_SET_VC_MP_GPIO_DATA,
+	CPIA2_CMD_ENABLE_PACKET_CTRL,
+	CPIA2_CMD_GET_FLICKER_MODES,
+	CPIA2_CMD_SET_FLICKER_MODES,
+	CPIA2_CMD_RESET_FIFO,	/* clear fifo and enable stream block */
+	CPIA2_CMD_SET_HI_POWER,
+	CPIA2_CMD_SET_LOW_POWER,
+	CPIA2_CMD_CLEAR_V2W_ERR,
+	CPIA2_CMD_SET_USER_MODE,
+	CPIA2_CMD_GET_USER_MODE,
+	CPIA2_CMD_FRAMERATE_REQ,
+	CPIA2_CMD_SET_COMPRESSION_STATE,
+	CPIA2_CMD_GET_WAKEUP,
+	CPIA2_CMD_SET_WAKEUP,
+	CPIA2_CMD_GET_PW_CONTROL,
+	CPIA2_CMD_SET_PW_CONTROL,
+	CPIA2_CMD_GET_SYSTEM_CTRL,
+	CPIA2_CMD_SET_SYSTEM_CTRL,
+	CPIA2_CMD_GET_VP_SYSTEM_STATE,
+	CPIA2_CMD_GET_VP_SYSTEM_CTRL,
+	CPIA2_CMD_SET_VP_SYSTEM_CTRL,
+	CPIA2_CMD_GET_VP_EXP_MODES,
+	CPIA2_CMD_SET_VP_EXP_MODES,
+	CPIA2_CMD_GET_DEVICE_CONFIG,
+	CPIA2_CMD_SET_DEVICE_CONFIG,
+	CPIA2_CMD_SET_SERIAL_ADDR,
+	CPIA2_CMD_SET_SENSOR_CR1,
+	CPIA2_CMD_GET_VC_CONTROL,
+	CPIA2_CMD_SET_VC_CONTROL,
+	CPIA2_CMD_SET_TARGET_KB,
+	CPIA2_CMD_SET_DEF_JPEG_OPT,
+	CPIA2_CMD_REHASH_VP4,
+	CPIA2_CMD_GET_USER_EFFECTS,
+	CPIA2_CMD_SET_USER_EFFECTS
+};
+
+enum user_cmd {
+	COMMAND_NONE = 0x00000001,
+	COMMAND_SET_FPS = 0x00000002,
+	COMMAND_SET_COLOR_PARAMS = 0x00000004,
+	COMMAND_GET_COLOR_PARAMS = 0x00000008,
+	COMMAND_SET_FORMAT = 0x00000010,	/* size, etc */
+	COMMAND_SET_FLICKER = 0x00000020
+};
+
+/***
+ * Some defines specific to the 676 chip
+ ***/
+#define CAMACC_CIF      0x01
+#define CAMACC_VGA      0x02
+#define CAMACC_QCIF     0x04
+#define CAMACC_QVGA     0x08
+
+
+struct cpia2_register {
+	u8 index;
+	u8 value;
+};
+
+struct cpia2_reg_mask {
+	u8 index;
+	u8 and_mask;
+	u8 or_mask;
+	u8 fill;
+};
+
+struct cpia2_command {
+	u32 command;
+	u8 req_mode;		/* (Block or random) | registerBank */
+	u8 reg_count;
+	u8 direction;
+	u8 start;
+	union reg_types {
+		struct cpia2_register registers[32];
+		struct cpia2_reg_mask masks[16];
+		u8 block_data[64];
+		u8 *patch_data;	/* points to function defined block */
+	} buffer;
+};
+
+struct camera_params {
+	struct {
+		u8 firmware_revision_hi; /* For system register set (bank 0) */
+		u8 firmware_revision_lo;
+		u8 asic_id;	/* Video Compressor set (bank 1) */
+		u8 asic_rev;
+		u8 vp_device_hi;	/* Video Processor set (bank 2) */
+		u8 vp_device_lo;
+		u8 sensor_flags;
+		u8 sensor_rev;
+	} version;
+
+	struct {
+		u32 device_type;     /* enumerated from vendor/product ids.
+				      * Currently, either STV_672 or STV_676 */
+		u16 vendor;
+		u16 product;
+		u16 device_revision;
+	} pnp_id;
+
+	struct {
+		u8 brightness;	/* CPIA2_VP_EXPOSURE_TARGET */
+		u8 contrast;	/* Note: this is CPIA2_VP_YRANGE */
+		u8 saturation;	/*  CPIA2_VP_SATURATION */
+	} color_params;
+
+	struct {
+		u8 cam_register;
+		u8 flicker_mode_req;	/* 1 if flicker on, else never flicker */
+	} flicker_control;
+
+	struct {
+		u8 jpeg_options;
+		u8 creep_period;
+		u8 user_squeeze;
+		u8 inhibit_htables;
+	} compression;
+
+	struct {
+		u8 ohsize;	/* output image size */
+		u8 ovsize;
+		u8 hcrop;	/* cropping start_pos/4 */
+		u8 vcrop;
+		u8 hphase;	/* scaling registers */
+		u8 vphase;
+		u8 hispan;
+		u8 vispan;
+		u8 hicrop;
+		u8 vicrop;
+		u8 hifraction;
+		u8 vifraction;
+	} image_size;
+
+	struct {
+		int width;	/* actual window width */
+		int height;	/* actual window height */
+	} roi;
+
+	struct {
+		u8 video_mode;
+		u8 frame_rate;
+		u8 video_size;	/* Not a register, just a convenience for cropped sizes */
+		u8 gpio_direction;
+		u8 gpio_data;
+		u8 system_ctrl;
+		u8 system_state;
+		u8 lowlight_boost;	/* Bool: 0 = off, 1 = on */
+		u8 device_config;
+		u8 exposure_modes;
+		u8 user_effects;
+	} vp_params;
+
+	struct {
+		u8 pw_control;
+		u8 wakeup;
+		u8 vc_control;
+		u8 vc_mp_direction;
+		u8 vc_mp_data;
+		u8 quality;
+	} vc_params;
+
+	struct {
+		u8 power_mode;
+		u8 system_ctrl;
+		u8 stream_mode;	/* This is the current alternate for usb drivers */
+		u8 allow_corrupt;
+	} camera_state;
+};
+
+#define NUM_SBUF    2
+
+struct cpia2_sbuf {
+	char *data;
+	struct urb *urb;
+};
+
+struct framebuf {
+	struct timeval timestamp;
+	unsigned long seq;
+	int num;
+	int length;
+	int max_length;
+	volatile enum frame_status status;
+	u8 *data;
+	struct framebuf *next;
+};
+
+struct camera_data {
+	/* locks */
+	struct v4l2_device v4l2_dev;
+	struct mutex v4l2_lock;	/* serialize file operations */
+	struct v4l2_ctrl_handler hdl;
+	struct {
+		/* Lights control cluster */
+		struct v4l2_ctrl *top_light;
+		struct v4l2_ctrl *bottom_light;
+	};
+	struct v4l2_ctrl *usb_alt;
+
+	/* camera status */
+	int first_image_seen;
+	enum sensors sensor_type;
+	u8 flush;
+	struct v4l2_fh *stream_fh;
+	u8 mmapped;
+	int streaming;		/* 0 = no, 1 = yes */
+	int xfer_mode;		/* XFER_BULK or XFER_ISOC */
+	struct camera_params params;	/* camera settings */
+
+	/* v4l */
+	int video_size;			/* VIDEO_SIZE_ */
+	struct video_device vdev;	/* v4l videodev */
+	u32 width;
+	u32 height;			/* Its size */
+	__u32 pixelformat;       /* Format fourcc      */
+
+	/* USB */
+	struct usb_device *dev;
+	unsigned char iface;
+	unsigned int cur_alt;
+	unsigned int old_alt;
+	struct cpia2_sbuf sbuf[NUM_SBUF];	/* Double buffering */
+
+	wait_queue_head_t wq_stream;
+
+	/* Buffering */
+	u32 frame_size;
+	int num_frames;
+	unsigned long frame_count;
+	u8 *frame_buffer;	/* frame buffer data */
+	struct framebuf *buffers;
+	struct framebuf * volatile curbuff;
+	struct framebuf *workbuff;
+
+	/* MJPEG Extension */
+	int APPn;		/* Number of APP segment to be written, must be 0..15 */
+	int APP_len;		/* Length of data in JPEG APPn segment */
+	char APP_data[60];	/* Data in the JPEG APPn segment. */
+
+	int COM_len;		/* Length of data in JPEG COM segment */
+	char COM_data[60];	/* Data in JPEG COM segment */
+};
+
+/* v4l */
+int cpia2_register_camera(struct camera_data *cam);
+void cpia2_unregister_camera(struct camera_data *cam);
+void cpia2_camera_release(struct v4l2_device *v4l2_dev);
+
+/* core */
+int cpia2_reset_camera(struct camera_data *cam);
+int cpia2_set_low_power(struct camera_data *cam);
+void cpia2_dbg_dump_registers(struct camera_data *cam);
+int cpia2_match_video_size(int width, int height);
+void cpia2_set_camera_state(struct camera_data *cam);
+void cpia2_save_camera_state(struct camera_data *cam);
+void cpia2_set_color_params(struct camera_data *cam);
+void cpia2_set_brightness(struct camera_data *cam, unsigned char value);
+void cpia2_set_contrast(struct camera_data *cam, unsigned char value);
+void cpia2_set_saturation(struct camera_data *cam, unsigned char value);
+int cpia2_set_flicker_mode(struct camera_data *cam, int mode);
+void cpia2_set_format(struct camera_data *cam);
+int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd);
+int cpia2_do_command(struct camera_data *cam,
+		     unsigned int command,
+		     unsigned char direction, unsigned char param);
+struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf);
+int cpia2_init_camera(struct camera_data *cam);
+int cpia2_allocate_buffers(struct camera_data *cam);
+void cpia2_free_buffers(struct camera_data *cam);
+long cpia2_read(struct camera_data *cam,
+		char __user *buf, unsigned long count, int noblock);
+unsigned int cpia2_poll(struct camera_data *cam,
+			struct file *filp, poll_table *wait);
+int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma);
+void cpia2_set_property_flip(struct camera_data *cam, int prop_val);
+void cpia2_set_property_mirror(struct camera_data *cam, int prop_val);
+int cpia2_set_gpio(struct camera_data *cam, unsigned char setting);
+int cpia2_set_fps(struct camera_data *cam, int framerate);
+
+/* usb */
+int cpia2_usb_init(void);
+void cpia2_usb_cleanup(void);
+int cpia2_usb_transfer_cmd(struct camera_data *cam, void *registers,
+			   u8 request, u8 start, u8 count, u8 direction);
+int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate);
+int cpia2_usb_stream_stop(struct camera_data *cam);
+int cpia2_usb_stream_pause(struct camera_data *cam);
+int cpia2_usb_stream_resume(struct camera_data *cam);
+int cpia2_usb_change_streaming_alternate(struct camera_data *cam,
+					 unsigned int alt);
+
+
+/* ----------------------- debug functions ---------------------- */
+#ifdef _CPIA2_DEBUG_
+#define ALOG(lev, fmt, args...) printk(lev "%s:%d %s(): " fmt, __FILE__, __LINE__, __func__, ## args)
+#define LOG(fmt, args...) ALOG(KERN_INFO, fmt, ## args)
+#define ERR(fmt, args...) ALOG(KERN_ERR, fmt, ## args)
+#define DBG(fmt, args...) ALOG(KERN_DEBUG, fmt, ## args)
+#else
+#define ALOG(fmt,args...) printk(fmt,##args)
+#define LOG(fmt,args...) ALOG(KERN_INFO "cpia2: "fmt,##args)
+#define ERR(fmt,args...) ALOG(KERN_ERR "cpia2: "fmt,##args)
+#define DBG(fmn,args...) do {} while(0)
+#endif
+/* No function or lineno, for shorter lines */
+#define KINFO(fmt, args...) printk(KERN_INFO fmt,##args)
+
+#endif
diff --git a/drivers/media/usb/cpia2/cpia2_core.c b/drivers/media/usb/cpia2/cpia2_core.c
new file mode 100644
index 0000000..187012c
--- /dev/null
+++ b/drivers/media/usb/cpia2/cpia2_core.c
@@ -0,0 +1,2417 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2_core.c
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *      Contact:  steve.miller@st.com
+ *
+ *  Description:
+ *     This is a USB driver for CPia2 based video cameras.
+ *     The infrastructure of this driver is based on the cpia usb driver by
+ *     Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Stripped of 2.4 stuff ready for main kernel submit by
+ *		Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ ****************************************************************************/
+
+#include "cpia2.h"
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+
+#define FIRMWARE "cpia2/stv0672_vp4.bin"
+MODULE_FIRMWARE(FIRMWARE);
+
+/* #define _CPIA2_DEBUG_ */
+
+#ifdef _CPIA2_DEBUG_
+
+static const char *block_name[] = {
+	"System",
+	"VC",
+	"VP",
+	"IDATA"
+};
+#endif
+
+static unsigned int debugs_on;	/* default 0 - DEBUG_REG */
+
+
+/******************************************************************************
+ *
+ *  Forward Declarations
+ *
+ *****************************************************************************/
+static int apply_vp_patch(struct camera_data *cam);
+static int set_default_user_mode(struct camera_data *cam);
+static int set_vw_size(struct camera_data *cam, int size);
+static int configure_sensor(struct camera_data *cam,
+			    int reqwidth, int reqheight);
+static int config_sensor_410(struct camera_data *cam,
+			    int reqwidth, int reqheight);
+static int config_sensor_500(struct camera_data *cam,
+			    int reqwidth, int reqheight);
+static int set_all_properties(struct camera_data *cam);
+static void wake_system(struct camera_data *cam);
+static void set_lowlight_boost(struct camera_data *cam);
+static void reset_camera_struct(struct camera_data *cam);
+static int cpia2_set_high_power(struct camera_data *cam);
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+	unsigned long kva, ret;
+
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+	ret = __pa(kva);
+	return ret;
+}
+
+static void *rvmalloc(unsigned long size)
+{
+	void *mem;
+	unsigned long adr;
+
+	/* Round it off to PAGE_SIZE */
+	size = PAGE_ALIGN(size);
+
+	mem = vmalloc_32(size);
+	if (!mem)
+		return NULL;
+
+	memset(mem, 0, size);	/* Clear the ram out, no junk to the user */
+	adr = (unsigned long) mem;
+
+	while ((long)size > 0) {
+		SetPageReserved(vmalloc_to_page((void *)adr));
+		adr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+	return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+	unsigned long adr;
+
+	if (!mem)
+		return;
+
+	size = PAGE_ALIGN(size);
+
+	adr = (unsigned long) mem;
+	while ((long)size > 0) {
+		ClearPageReserved(vmalloc_to_page((void *)adr));
+		adr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+	vfree(mem);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_do_command
+ *
+ *  Send an arbitrary command to the camera.  For commands that read from
+ *  the camera, copy the buffers into the proper param structures.
+ *****************************************************************************/
+int cpia2_do_command(struct camera_data *cam,
+		     u32 command, u8 direction, u8 param)
+{
+	int retval = 0;
+	struct cpia2_command cmd;
+	unsigned int device = cam->params.pnp_id.device_type;
+
+	cmd.command = command;
+	cmd.reg_count = 2;	/* default */
+	cmd.direction = direction;
+
+	/***
+	 * Set up the command.
+	 ***/
+	switch (command) {
+	case CPIA2_CMD_GET_VERSION:
+		cmd.req_mode =
+		    CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+		cmd.start = CPIA2_SYSTEM_DEVICE_HI;
+		break;
+	case CPIA2_CMD_GET_PNP_ID:
+		cmd.req_mode =
+		    CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+		cmd.reg_count = 8;
+		cmd.start = CPIA2_SYSTEM_DESCRIP_VID_HI;
+		break;
+	case CPIA2_CMD_GET_ASIC_TYPE:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+		cmd.start = CPIA2_VC_ASIC_ID;
+		break;
+	case CPIA2_CMD_GET_SENSOR:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.start = CPIA2_VP_SENSOR_FLAGS;
+		break;
+	case CPIA2_CMD_GET_VP_DEVICE:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.start = CPIA2_VP_DEVICEH;
+		break;
+	case CPIA2_CMD_SET_VP_BRIGHTNESS:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VP_BRIGHTNESS:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		if (device == DEVICE_STV_672)
+			cmd.start = CPIA2_VP4_EXPOSURE_TARGET;
+		else
+			cmd.start = CPIA2_VP5_EXPOSURE_TARGET;
+		break;
+	case CPIA2_CMD_SET_CONTRAST:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_CONTRAST:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_YRANGE;
+		break;
+	case CPIA2_CMD_SET_VP_SATURATION:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VP_SATURATION:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		if (device == DEVICE_STV_672)
+			cmd.start = CPIA2_VP_SATURATION;
+		else
+			cmd.start = CPIA2_VP5_MCUVSATURATION;
+		break;
+	case CPIA2_CMD_SET_VP_GPIO_DATA:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VP_GPIO_DATA:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_GPIO_DATA;
+		break;
+	case CPIA2_CMD_SET_VP_GPIO_DIRECTION:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VP_GPIO_DIRECTION:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_GPIO_DIRECTION;
+		break;
+	case CPIA2_CMD_SET_VC_MP_GPIO_DATA:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VC_MP_GPIO_DATA:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VC_MP_DATA;
+		break;
+	case CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VC_MP_DIR;
+		break;
+	case CPIA2_CMD_ENABLE_PACKET_CTRL:
+		cmd.req_mode =
+		    CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+		cmd.start = CPIA2_SYSTEM_INT_PACKET_CTRL;
+		cmd.reg_count = 1;
+		cmd.buffer.block_data[0] = param;
+		break;
+	case CPIA2_CMD_SET_FLICKER_MODES:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_FLICKER_MODES:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_FLICKER_MODES;
+		break;
+	case CPIA2_CMD_RESET_FIFO:	/* clear fifo and enable stream block */
+		cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+		cmd.reg_count = 2;
+		cmd.start = 0;
+		cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL;
+		cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC |
+		    CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT;
+		cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL;
+		cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC |
+		    CPIA2_VC_ST_CTRL_DST_USB |
+		    CPIA2_VC_ST_CTRL_EOF_DETECT |
+		    CPIA2_VC_ST_CTRL_FIFO_ENABLE;
+		break;
+	case CPIA2_CMD_SET_HI_POWER:
+		cmd.req_mode =
+		    CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM;
+		cmd.reg_count = 2;
+		cmd.buffer.registers[0].index =
+		    CPIA2_SYSTEM_SYSTEM_CONTROL;
+		cmd.buffer.registers[1].index =
+		    CPIA2_SYSTEM_SYSTEM_CONTROL;
+		cmd.buffer.registers[0].value = CPIA2_SYSTEM_CONTROL_CLEAR_ERR;
+		cmd.buffer.registers[1].value =
+		    CPIA2_SYSTEM_CONTROL_HIGH_POWER;
+		break;
+	case CPIA2_CMD_SET_LOW_POWER:
+		cmd.req_mode =
+		    CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
+		cmd.buffer.block_data[0] = 0;
+		break;
+	case CPIA2_CMD_CLEAR_V2W_ERR:
+		cmd.req_mode =
+		    CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
+		cmd.buffer.block_data[0] = CPIA2_SYSTEM_CONTROL_CLEAR_ERR;
+		break;
+	case CPIA2_CMD_SET_USER_MODE:   /* Then fall through */
+		cmd.buffer.block_data[0] = param;
+	case CPIA2_CMD_GET_USER_MODE:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		if (device == DEVICE_STV_672)
+			cmd.start = CPIA2_VP4_USER_MODE;
+		else
+			cmd.start = CPIA2_VP5_USER_MODE;
+		break;
+	case CPIA2_CMD_FRAMERATE_REQ:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		if (device == DEVICE_STV_672)
+			cmd.start = CPIA2_VP4_FRAMERATE_REQUEST;
+		else
+			cmd.start = CPIA2_VP5_FRAMERATE_REQUEST;
+		cmd.buffer.block_data[0] = param;
+		break;
+	case CPIA2_CMD_SET_WAKEUP:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_WAKEUP:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VC_WAKEUP;
+		break;
+	case CPIA2_CMD_SET_PW_CONTROL:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_PW_CONTROL:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VC_PW_CTRL;
+		break;
+	case CPIA2_CMD_GET_VP_SYSTEM_STATE:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_SYSTEMSTATE;
+		break;
+	case CPIA2_CMD_SET_SYSTEM_CTRL:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_SYSTEM_CTRL:
+		cmd.req_mode =
+		    CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
+		break;
+	case CPIA2_CMD_SET_VP_SYSTEM_CTRL:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VP_SYSTEM_CTRL:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_SYSTEMCTRL;
+		break;
+	case CPIA2_CMD_SET_VP_EXP_MODES:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VP_EXP_MODES:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_EXPOSURE_MODES;
+		break;
+	case CPIA2_CMD_SET_DEVICE_CONFIG:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_DEVICE_CONFIG:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_DEVICE_CONFIG;
+		break;
+	case CPIA2_CMD_SET_SERIAL_ADDR:
+		cmd.buffer.block_data[0] = param;
+		cmd.req_mode =
+		    CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_SYSTEM_VP_SERIAL_ADDR;
+		break;
+	case CPIA2_CMD_SET_SENSOR_CR1:
+		cmd.buffer.block_data[0] = param;
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_SENSOR_CR1;
+		break;
+	case CPIA2_CMD_SET_VC_CONTROL:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VC_CONTROL:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VC_VC_CTRL;
+		break;
+	case CPIA2_CMD_SET_TARGET_KB:
+		cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+		cmd.reg_count = 1;
+		cmd.buffer.registers[0].index = CPIA2_VC_VC_TARGET_KB;
+		cmd.buffer.registers[0].value = param;
+		break;
+	case CPIA2_CMD_SET_DEF_JPEG_OPT:
+		cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+		cmd.reg_count = 4;
+		cmd.buffer.registers[0].index = CPIA2_VC_VC_JPEG_OPT;
+		cmd.buffer.registers[0].value =
+		    CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE;
+		cmd.buffer.registers[1].index = CPIA2_VC_VC_USER_SQUEEZE;
+		cmd.buffer.registers[1].value = 20;
+		cmd.buffer.registers[2].index = CPIA2_VC_VC_CREEP_PERIOD;
+		cmd.buffer.registers[2].value = 2;
+		cmd.buffer.registers[3].index = CPIA2_VC_VC_JPEG_OPT;
+		cmd.buffer.registers[3].value = CPIA2_VC_VC_JPEG_OPT_DEFAULT;
+		break;
+	case CPIA2_CMD_REHASH_VP4:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_REHASH_VALUES;
+		cmd.buffer.block_data[0] = param;
+		break;
+	case CPIA2_CMD_SET_USER_EFFECTS:  /* Note: Be careful with this as
+					     this register can also affect
+					     flicker modes */
+		cmd.buffer.block_data[0] = param;      /* Then fall through */
+	case CPIA2_CMD_GET_USER_EFFECTS:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		if (device == DEVICE_STV_672)
+			cmd.start = CPIA2_VP4_USER_EFFECTS;
+		else
+			cmd.start = CPIA2_VP5_USER_EFFECTS;
+		break;
+	default:
+		LOG("DoCommand received invalid command\n");
+		return -EINVAL;
+	}
+
+	retval = cpia2_send_command(cam, &cmd);
+	if (retval) {
+		return retval;
+	}
+
+	/***
+	 * Now copy any results from a read into the appropriate param struct.
+	 ***/
+	switch (command) {
+	case CPIA2_CMD_GET_VERSION:
+		cam->params.version.firmware_revision_hi =
+		    cmd.buffer.block_data[0];
+		cam->params.version.firmware_revision_lo =
+		    cmd.buffer.block_data[1];
+		break;
+	case CPIA2_CMD_GET_PNP_ID:
+		cam->params.pnp_id.vendor = (cmd.buffer.block_data[0] << 8) |
+					    cmd.buffer.block_data[1];
+		cam->params.pnp_id.product = (cmd.buffer.block_data[2] << 8) |
+					     cmd.buffer.block_data[3];
+		cam->params.pnp_id.device_revision =
+			(cmd.buffer.block_data[4] << 8) |
+			cmd.buffer.block_data[5];
+		if (cam->params.pnp_id.vendor == 0x553) {
+			if (cam->params.pnp_id.product == 0x100) {
+				cam->params.pnp_id.device_type = DEVICE_STV_672;
+			} else if (cam->params.pnp_id.product == 0x140 ||
+				   cam->params.pnp_id.product == 0x151) {
+				cam->params.pnp_id.device_type = DEVICE_STV_676;
+			}
+		}
+		break;
+	case CPIA2_CMD_GET_ASIC_TYPE:
+		cam->params.version.asic_id = cmd.buffer.block_data[0];
+		cam->params.version.asic_rev = cmd.buffer.block_data[1];
+		break;
+	case CPIA2_CMD_GET_SENSOR:
+		cam->params.version.sensor_flags = cmd.buffer.block_data[0];
+		cam->params.version.sensor_rev = cmd.buffer.block_data[1];
+		break;
+	case CPIA2_CMD_GET_VP_DEVICE:
+		cam->params.version.vp_device_hi = cmd.buffer.block_data[0];
+		cam->params.version.vp_device_lo = cmd.buffer.block_data[1];
+		break;
+	case CPIA2_CMD_GET_VP_GPIO_DATA:
+		cam->params.vp_params.gpio_data = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_VP_GPIO_DIRECTION:
+		cam->params.vp_params.gpio_direction = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION:
+		cam->params.vc_params.vc_mp_direction =cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_VC_MP_GPIO_DATA:
+		cam->params.vc_params.vc_mp_data = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_FLICKER_MODES:
+		cam->params.flicker_control.cam_register =
+			cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_WAKEUP:
+		cam->params.vc_params.wakeup = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_PW_CONTROL:
+		cam->params.vc_params.pw_control = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_SYSTEM_CTRL:
+		cam->params.camera_state.system_ctrl = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_VP_SYSTEM_STATE:
+		cam->params.vp_params.system_state = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_VP_SYSTEM_CTRL:
+		cam->params.vp_params.system_ctrl = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_VP_EXP_MODES:
+		cam->params.vp_params.exposure_modes = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_DEVICE_CONFIG:
+		cam->params.vp_params.device_config = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_VC_CONTROL:
+		cam->params.vc_params.vc_control = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_USER_MODE:
+		cam->params.vp_params.video_mode = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_USER_EFFECTS:
+		cam->params.vp_params.user_effects = cmd.buffer.block_data[0];
+		break;
+	default:
+		break;
+	}
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_send_command
+ *
+ *****************************************************************************/
+
+#define DIR(cmd) ((cmd->direction == TRANSFER_WRITE) ? "Write" : "Read")
+#define BINDEX(cmd) (cmd->req_mode & 0x03)
+
+int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd)
+{
+	u8 count;
+	u8 start;
+	u8 *buffer;
+	int retval;
+
+	switch (cmd->req_mode & 0x0c) {
+	case CAMERAACCESS_TYPE_RANDOM:
+		count = cmd->reg_count * sizeof(struct cpia2_register);
+		start = 0;
+		buffer = (u8 *) & cmd->buffer;
+		if (debugs_on & DEBUG_REG)
+			DBG("%s Random: Register block %s\n", DIR(cmd),
+			    block_name[BINDEX(cmd)]);
+		break;
+	case CAMERAACCESS_TYPE_BLOCK:
+		count = cmd->reg_count;
+		start = cmd->start;
+		buffer = cmd->buffer.block_data;
+		if (debugs_on & DEBUG_REG)
+			DBG("%s Block: Register block %s\n", DIR(cmd),
+			    block_name[BINDEX(cmd)]);
+		break;
+	case CAMERAACCESS_TYPE_MASK:
+		count = cmd->reg_count * sizeof(struct cpia2_reg_mask);
+		start = 0;
+		buffer = (u8 *) & cmd->buffer;
+		if (debugs_on & DEBUG_REG)
+			DBG("%s Mask: Register block %s\n", DIR(cmd),
+			    block_name[BINDEX(cmd)]);
+		break;
+	case CAMERAACCESS_TYPE_REPEAT:	/* For patch blocks only */
+		count = cmd->reg_count;
+		start = cmd->start;
+		buffer = cmd->buffer.block_data;
+		if (debugs_on & DEBUG_REG)
+			DBG("%s Repeat: Register block %s\n", DIR(cmd),
+			    block_name[BINDEX(cmd)]);
+		break;
+	default:
+		LOG("%s: invalid request mode\n",__func__);
+		return -EINVAL;
+	}
+
+	retval = cpia2_usb_transfer_cmd(cam,
+					buffer,
+					cmd->req_mode,
+					start, count, cmd->direction);
+#ifdef _CPIA2_DEBUG_
+	if (debugs_on & DEBUG_REG) {
+		int i;
+		for (i = 0; i < cmd->reg_count; i++) {
+			if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_BLOCK)
+				KINFO("%s Block: [0x%02X] = 0x%02X\n",
+				    DIR(cmd), start + i, buffer[i]);
+			if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_RANDOM)
+				KINFO("%s Random: [0x%02X] = 0x%02X\n",
+				    DIR(cmd), cmd->buffer.registers[i].index,
+				    cmd->buffer.registers[i].value);
+		}
+	}
+#endif
+
+	return retval;
+};
+
+/*************
+ * Functions to implement camera functionality
+ *************/
+/******************************************************************************
+ *
+ *  cpia2_get_version_info
+ *
+ *****************************************************************************/
+static void cpia2_get_version_info(struct camera_data *cam)
+{
+	cpia2_do_command(cam, CPIA2_CMD_GET_VERSION, TRANSFER_READ, 0);
+	cpia2_do_command(cam, CPIA2_CMD_GET_PNP_ID, TRANSFER_READ, 0);
+	cpia2_do_command(cam, CPIA2_CMD_GET_ASIC_TYPE, TRANSFER_READ, 0);
+	cpia2_do_command(cam, CPIA2_CMD_GET_SENSOR, TRANSFER_READ, 0);
+	cpia2_do_command(cam, CPIA2_CMD_GET_VP_DEVICE, TRANSFER_READ, 0);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_reset_camera
+ *
+ *  Called at least during the open process, sets up initial params.
+ *****************************************************************************/
+int cpia2_reset_camera(struct camera_data *cam)
+{
+	u8 tmp_reg;
+	int retval = 0;
+	int target_kb;
+	int i;
+	struct cpia2_command cmd;
+
+	/***
+	 * VC setup
+	 ***/
+	retval = configure_sensor(cam,
+				  cam->params.roi.width,
+				  cam->params.roi.height);
+	if (retval < 0) {
+		ERR("Couldn't configure sensor, error=%d\n", retval);
+		return retval;
+	}
+
+	/* Clear FIFO and route/enable stream block */
+	cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+	cmd.direction = TRANSFER_WRITE;
+	cmd.reg_count = 2;
+	cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL;
+	cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC |
+		CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT;
+	cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL;
+	cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC |
+		CPIA2_VC_ST_CTRL_DST_USB |
+		CPIA2_VC_ST_CTRL_EOF_DETECT | CPIA2_VC_ST_CTRL_FIFO_ENABLE;
+
+	cpia2_send_command(cam, &cmd);
+
+	cpia2_set_high_power(cam);
+
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+		/* Enable button notification */
+		cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM;
+		cmd.buffer.registers[0].index = CPIA2_SYSTEM_INT_PACKET_CTRL;
+		cmd.buffer.registers[0].value =
+			CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX;
+		cmd.reg_count = 1;
+		cpia2_send_command(cam, &cmd);
+	}
+
+	schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+		retval = apply_vp_patch(cam);
+
+	/* wait for vp to go to sleep */
+	schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+	/***
+	 * If this is a 676, apply VP5 fixes before we start streaming
+	 ***/
+	if (cam->params.pnp_id.device_type == DEVICE_STV_676) {
+		cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
+
+		/* The following writes improve the picture */
+		cmd.buffer.registers[0].index = CPIA2_VP5_MYBLACK_LEVEL;
+		cmd.buffer.registers[0].value = 0; /* reduce from the default
+						    * rec 601 pedestal of 16 */
+		cmd.buffer.registers[1].index = CPIA2_VP5_MCYRANGE;
+		cmd.buffer.registers[1].value = 0x92; /* increase from 100% to
+						       * (256/256 - 31) to fill
+						       * available range */
+		cmd.buffer.registers[2].index = CPIA2_VP5_MYCEILING;
+		cmd.buffer.registers[2].value = 0xFF; /* Increase from the
+						       * default rec 601 ceiling
+						       * of 240 */
+		cmd.buffer.registers[3].index = CPIA2_VP5_MCUVSATURATION;
+		cmd.buffer.registers[3].value = 0xFF; /* Increase from the rec
+						       * 601 100% level (128)
+						       * to 145-192 */
+		cmd.buffer.registers[4].index = CPIA2_VP5_ANTIFLKRSETUP;
+		cmd.buffer.registers[4].value = 0x80;  /* Inhibit the
+							* anti-flicker */
+
+		/* The following 4 writes are a fix to allow QVGA to work at 30 fps */
+		cmd.buffer.registers[5].index = CPIA2_VP_RAM_ADDR_H;
+		cmd.buffer.registers[5].value = 0x01;
+		cmd.buffer.registers[6].index = CPIA2_VP_RAM_ADDR_L;
+		cmd.buffer.registers[6].value = 0xE3;
+		cmd.buffer.registers[7].index = CPIA2_VP_RAM_DATA;
+		cmd.buffer.registers[7].value = 0x02;
+		cmd.buffer.registers[8].index = CPIA2_VP_RAM_DATA;
+		cmd.buffer.registers[8].value = 0xFC;
+
+		cmd.direction = TRANSFER_WRITE;
+		cmd.reg_count = 9;
+
+		cpia2_send_command(cam, &cmd);
+	}
+
+	/* Activate all settings and start the data stream */
+	/* Set user mode */
+	set_default_user_mode(cam);
+
+	/* Give VP time to wake up */
+	schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+	set_all_properties(cam);
+
+	cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0);
+	DBG("After SetAllProperties(cam), user mode is 0x%0X\n",
+	    cam->params.vp_params.video_mode);
+
+	/***
+	 * Set audio regulator off.  This and the code to set the compresison
+	 * state are too complex to form a CPIA2_CMD_, and seem to be somewhat
+	 * intertwined.  This stuff came straight from the windows driver.
+	 ***/
+	/* Turn AutoExposure off in VP and enable the serial bridge to the sensor */
+	cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0);
+	tmp_reg = cam->params.vp_params.system_ctrl;
+	cmd.buffer.registers[0].value = tmp_reg &
+		(tmp_reg & (CPIA2_VP_SYSTEMCTRL_HK_CONTROL ^ 0xFF));
+
+	cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0);
+	cmd.buffer.registers[1].value = cam->params.vp_params.device_config |
+					CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE;
+	cmd.buffer.registers[0].index = CPIA2_VP_SYSTEMCTRL;
+	cmd.buffer.registers[1].index = CPIA2_VP_DEVICE_CONFIG;
+	cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
+	cmd.reg_count = 2;
+	cmd.direction = TRANSFER_WRITE;
+	cmd.start = 0;
+	cpia2_send_command(cam, &cmd);
+
+	/* Set the correct I2C address in the CPiA-2 system register */
+	cpia2_do_command(cam,
+			 CPIA2_CMD_SET_SERIAL_ADDR,
+			 TRANSFER_WRITE,
+			 CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR);
+
+	/* Now have sensor access - set bit to turn the audio regulator off */
+	cpia2_do_command(cam,
+			 CPIA2_CMD_SET_SENSOR_CR1,
+			 TRANSFER_WRITE, CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR);
+
+	/* Set the correct I2C address in the CPiA-2 system register */
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+		cpia2_do_command(cam,
+				 CPIA2_CMD_SET_SERIAL_ADDR,
+				 TRANSFER_WRITE,
+				 CPIA2_SYSTEM_VP_SERIAL_ADDR_VP); // 0x88
+	else
+		cpia2_do_command(cam,
+				 CPIA2_CMD_SET_SERIAL_ADDR,
+				 TRANSFER_WRITE,
+				 CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP); // 0x8a
+
+	/* increase signal drive strength */
+	if (cam->params.pnp_id.device_type == DEVICE_STV_676)
+		cpia2_do_command(cam,
+				 CPIA2_CMD_SET_VP_EXP_MODES,
+				 TRANSFER_WRITE,
+				 CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP);
+
+	/* Start autoexposure */
+	cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0);
+	cmd.buffer.registers[0].value = cam->params.vp_params.device_config &
+				  (CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE ^ 0xFF);
+
+	cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0);
+	cmd.buffer.registers[1].value =
+	    cam->params.vp_params.system_ctrl | CPIA2_VP_SYSTEMCTRL_HK_CONTROL;
+
+	cmd.buffer.registers[0].index = CPIA2_VP_DEVICE_CONFIG;
+	cmd.buffer.registers[1].index = CPIA2_VP_SYSTEMCTRL;
+	cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
+	cmd.reg_count = 2;
+	cmd.direction = TRANSFER_WRITE;
+
+	cpia2_send_command(cam, &cmd);
+
+	/* Set compression state */
+	cpia2_do_command(cam, CPIA2_CMD_GET_VC_CONTROL, TRANSFER_READ, 0);
+	if (cam->params.compression.inhibit_htables) {
+		tmp_reg = cam->params.vc_params.vc_control |
+			  CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES;
+	} else  {
+		tmp_reg = cam->params.vc_params.vc_control &
+			  ~CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES;
+	}
+	cpia2_do_command(cam, CPIA2_CMD_SET_VC_CONTROL, TRANSFER_WRITE,tmp_reg);
+
+	/* Set target size (kb) on vc
+	   This is a heuristic based on the quality parameter and the raw
+	   framesize in kB divided by 16 (the compression factor when the
+	   quality is 100%) */
+	target_kb = (cam->width * cam->height * 2 / 16384) *
+				cam->params.vc_params.quality / 100;
+	if (target_kb < 1)
+		target_kb = 1;
+	cpia2_do_command(cam, CPIA2_CMD_SET_TARGET_KB,
+			 TRANSFER_WRITE, target_kb);
+
+	/* Wiggle VC Reset */
+	/***
+	 * First read and wait a bit.
+	 ***/
+	for (i = 0; i < 50; i++) {
+		cpia2_do_command(cam, CPIA2_CMD_GET_PW_CONTROL,
+				 TRANSFER_READ, 0);
+	}
+
+	tmp_reg = cam->params.vc_params.pw_control;
+	tmp_reg &= ~CPIA2_VC_PW_CTRL_VC_RESET_N;
+
+	cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg);
+
+	tmp_reg |= CPIA2_VC_PW_CTRL_VC_RESET_N;
+	cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg);
+
+	cpia2_do_command(cam, CPIA2_CMD_SET_DEF_JPEG_OPT, TRANSFER_WRITE, 0);
+
+	cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0);
+	DBG("After VC RESET, user mode is 0x%0X\n",
+	    cam->params.vp_params.video_mode);
+
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_high_power
+ *
+ *****************************************************************************/
+static int cpia2_set_high_power(struct camera_data *cam)
+{
+	int i;
+	for (i = 0; i <= 50; i++) {
+		/* Read system status */
+		cpia2_do_command(cam,CPIA2_CMD_GET_SYSTEM_CTRL,TRANSFER_READ,0);
+
+		/* If there is an error, clear it */
+		if(cam->params.camera_state.system_ctrl &
+		   CPIA2_SYSTEM_CONTROL_V2W_ERR)
+			cpia2_do_command(cam, CPIA2_CMD_CLEAR_V2W_ERR,
+					 TRANSFER_WRITE, 0);
+
+		/* Try to set high power mode */
+		cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL,
+				 TRANSFER_WRITE, 1);
+
+		/* Try to read something in VP to check if everything is awake */
+		cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_STATE,
+				 TRANSFER_READ, 0);
+		if (cam->params.vp_params.system_state &
+		    CPIA2_VP_SYSTEMSTATE_HK_ALIVE) {
+			break;
+		} else if (i == 50) {
+			cam->params.camera_state.power_mode = LO_POWER_MODE;
+			ERR("Camera did not wake up\n");
+			return -EIO;
+		}
+	}
+
+	DBG("System now in high power state\n");
+	cam->params.camera_state.power_mode = HI_POWER_MODE;
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_low_power
+ *
+ *****************************************************************************/
+int cpia2_set_low_power(struct camera_data *cam)
+{
+	cam->params.camera_state.power_mode = LO_POWER_MODE;
+	cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL, TRANSFER_WRITE, 0);
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  apply_vp_patch
+ *
+ *****************************************************************************/
+static int cpia2_send_onebyte_command(struct camera_data *cam,
+				      struct cpia2_command *cmd,
+				      u8 start, u8 datum)
+{
+	cmd->buffer.block_data[0] = datum;
+	cmd->start = start;
+	cmd->reg_count = 1;
+	return cpia2_send_command(cam, cmd);
+}
+
+static int apply_vp_patch(struct camera_data *cam)
+{
+	const struct firmware *fw;
+	const char fw_name[] = FIRMWARE;
+	int i, ret;
+	struct cpia2_command cmd;
+
+	ret = request_firmware(&fw, fw_name, &cam->dev->dev);
+	if (ret) {
+		printk(KERN_ERR "cpia2: failed to load VP patch \"%s\"\n",
+		       fw_name);
+		return ret;
+	}
+
+	cmd.req_mode = CAMERAACCESS_TYPE_REPEAT | CAMERAACCESS_VP;
+	cmd.direction = TRANSFER_WRITE;
+
+	/* First send the start address... */
+	cpia2_send_onebyte_command(cam, &cmd, 0x0A, fw->data[0]); /* hi */
+	cpia2_send_onebyte_command(cam, &cmd, 0x0B, fw->data[1]); /* lo */
+
+	/* ... followed by the data payload */
+	for (i = 2; i < fw->size; i += 64) {
+		cmd.start = 0x0C; /* Data */
+		cmd.reg_count = min_t(int, 64, fw->size - i);
+		memcpy(cmd.buffer.block_data, &fw->data[i], cmd.reg_count);
+		cpia2_send_command(cam, &cmd);
+	}
+
+	/* Next send the start address... */
+	cpia2_send_onebyte_command(cam, &cmd, 0x0A, fw->data[0]); /* hi */
+	cpia2_send_onebyte_command(cam, &cmd, 0x0B, fw->data[1]); /* lo */
+
+	/* ... followed by the 'goto' command */
+	cpia2_send_onebyte_command(cam, &cmd, 0x0D, 1);
+
+	release_firmware(fw);
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  set_default_user_mode
+ *
+ *****************************************************************************/
+static int set_default_user_mode(struct camera_data *cam)
+{
+	unsigned char user_mode;
+	unsigned char frame_rate;
+	int width = cam->params.roi.width;
+	int height = cam->params.roi.height;
+
+	switch (cam->params.version.sensor_flags) {
+	case CPIA2_VP_SENSOR_FLAGS_404:
+	case CPIA2_VP_SENSOR_FLAGS_407:
+	case CPIA2_VP_SENSOR_FLAGS_409:
+	case CPIA2_VP_SENSOR_FLAGS_410:
+		if ((width > STV_IMAGE_QCIF_COLS)
+		    || (height > STV_IMAGE_QCIF_ROWS)) {
+			user_mode = CPIA2_VP_USER_MODE_CIF;
+		} else {
+			user_mode = CPIA2_VP_USER_MODE_QCIFDS;
+		}
+		frame_rate = CPIA2_VP_FRAMERATE_30;
+		break;
+	case CPIA2_VP_SENSOR_FLAGS_500:
+		if ((width > STV_IMAGE_CIF_COLS)
+		    || (height > STV_IMAGE_CIF_ROWS)) {
+			user_mode = CPIA2_VP_USER_MODE_VGA;
+		} else {
+			user_mode = CPIA2_VP_USER_MODE_QVGADS;
+		}
+		if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+			frame_rate = CPIA2_VP_FRAMERATE_15;
+		else
+			frame_rate = CPIA2_VP_FRAMERATE_30;
+		break;
+	default:
+		LOG("%s: Invalid sensor flag value 0x%0X\n",__func__,
+		    cam->params.version.sensor_flags);
+		return -EINVAL;
+	}
+
+	DBG("Sensor flag = 0x%0x, user mode = 0x%0x, frame rate = 0x%X\n",
+	    cam->params.version.sensor_flags, user_mode, frame_rate);
+	cpia2_do_command(cam, CPIA2_CMD_SET_USER_MODE, TRANSFER_WRITE,
+			 user_mode);
+	if(cam->params.vp_params.frame_rate > 0 &&
+	   frame_rate > cam->params.vp_params.frame_rate)
+		frame_rate = cam->params.vp_params.frame_rate;
+
+	cpia2_set_fps(cam, frame_rate);
+
+//	if (cam->params.pnp_id.device_type == DEVICE_STV_676)
+//		cpia2_do_command(cam,
+//				 CPIA2_CMD_SET_VP_SYSTEM_CTRL,
+//				 TRANSFER_WRITE,
+//				 CPIA2_VP_SYSTEMCTRL_HK_CONTROL |
+//				 CPIA2_VP_SYSTEMCTRL_POWER_CONTROL);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_match_video_size
+ *
+ *  return the best match, where 'best' is as always
+ *  the largest that is not bigger than what is requested.
+ *****************************************************************************/
+int cpia2_match_video_size(int width, int height)
+{
+	if (width >= STV_IMAGE_VGA_COLS && height >= STV_IMAGE_VGA_ROWS)
+		return VIDEOSIZE_VGA;
+
+	if (width >= STV_IMAGE_CIF_COLS && height >= STV_IMAGE_CIF_ROWS)
+		return VIDEOSIZE_CIF;
+
+	if (width >= STV_IMAGE_QVGA_COLS && height >= STV_IMAGE_QVGA_ROWS)
+		return VIDEOSIZE_QVGA;
+
+	if (width >= 288 && height >= 216)
+		return VIDEOSIZE_288_216;
+
+	if (width >= 256 && height >= 192)
+		return VIDEOSIZE_256_192;
+
+	if (width >= 224 && height >= 168)
+		return VIDEOSIZE_224_168;
+
+	if (width >= 192 && height >= 144)
+		return VIDEOSIZE_192_144;
+
+	if (width >= STV_IMAGE_QCIF_COLS && height >= STV_IMAGE_QCIF_ROWS)
+		return VIDEOSIZE_QCIF;
+
+	return -1;
+}
+
+/******************************************************************************
+ *
+ *  SetVideoSize
+ *
+ *****************************************************************************/
+static int set_vw_size(struct camera_data *cam, int size)
+{
+	int retval = 0;
+
+	cam->params.vp_params.video_size = size;
+
+	switch (size) {
+	case VIDEOSIZE_VGA:
+		DBG("Setting size to VGA\n");
+		cam->params.roi.width = STV_IMAGE_VGA_COLS;
+		cam->params.roi.height = STV_IMAGE_VGA_ROWS;
+		cam->width = STV_IMAGE_VGA_COLS;
+		cam->height = STV_IMAGE_VGA_ROWS;
+		break;
+	case VIDEOSIZE_CIF:
+		DBG("Setting size to CIF\n");
+		cam->params.roi.width = STV_IMAGE_CIF_COLS;
+		cam->params.roi.height = STV_IMAGE_CIF_ROWS;
+		cam->width = STV_IMAGE_CIF_COLS;
+		cam->height = STV_IMAGE_CIF_ROWS;
+		break;
+	case VIDEOSIZE_QVGA:
+		DBG("Setting size to QVGA\n");
+		cam->params.roi.width = STV_IMAGE_QVGA_COLS;
+		cam->params.roi.height = STV_IMAGE_QVGA_ROWS;
+		cam->width = STV_IMAGE_QVGA_COLS;
+		cam->height = STV_IMAGE_QVGA_ROWS;
+		break;
+	case VIDEOSIZE_288_216:
+		cam->params.roi.width = 288;
+		cam->params.roi.height = 216;
+		cam->width = 288;
+		cam->height = 216;
+		break;
+	case VIDEOSIZE_256_192:
+		cam->width = 256;
+		cam->height = 192;
+		cam->params.roi.width = 256;
+		cam->params.roi.height = 192;
+		break;
+	case VIDEOSIZE_224_168:
+		cam->width = 224;
+		cam->height = 168;
+		cam->params.roi.width = 224;
+		cam->params.roi.height = 168;
+		break;
+	case VIDEOSIZE_192_144:
+		cam->width = 192;
+		cam->height = 144;
+		cam->params.roi.width = 192;
+		cam->params.roi.height = 144;
+		break;
+	case VIDEOSIZE_QCIF:
+		DBG("Setting size to QCIF\n");
+		cam->params.roi.width = STV_IMAGE_QCIF_COLS;
+		cam->params.roi.height = STV_IMAGE_QCIF_ROWS;
+		cam->width = STV_IMAGE_QCIF_COLS;
+		cam->height = STV_IMAGE_QCIF_ROWS;
+		break;
+	default:
+		retval = -EINVAL;
+	}
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  configure_sensor
+ *
+ *****************************************************************************/
+static int configure_sensor(struct camera_data *cam,
+			    int req_width, int req_height)
+{
+	int retval;
+
+	switch (cam->params.version.sensor_flags) {
+	case CPIA2_VP_SENSOR_FLAGS_404:
+	case CPIA2_VP_SENSOR_FLAGS_407:
+	case CPIA2_VP_SENSOR_FLAGS_409:
+	case CPIA2_VP_SENSOR_FLAGS_410:
+		retval = config_sensor_410(cam, req_width, req_height);
+		break;
+	case CPIA2_VP_SENSOR_FLAGS_500:
+		retval = config_sensor_500(cam, req_width, req_height);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  config_sensor_410
+ *
+ *****************************************************************************/
+static int config_sensor_410(struct camera_data *cam,
+			    int req_width, int req_height)
+{
+	struct cpia2_command cmd;
+	int i = 0;
+	int image_size;
+	int image_type;
+	int width = req_width;
+	int height = req_height;
+
+	/***
+	 *  Make sure size doesn't exceed CIF.
+	 ***/
+	if (width > STV_IMAGE_CIF_COLS)
+		width = STV_IMAGE_CIF_COLS;
+	if (height > STV_IMAGE_CIF_ROWS)
+		height = STV_IMAGE_CIF_ROWS;
+
+	image_size = cpia2_match_video_size(width, height);
+
+	DBG("Config 410: width = %d, height = %d\n", width, height);
+	DBG("Image size returned is %d\n", image_size);
+	if (image_size >= 0) {
+		set_vw_size(cam, image_size);
+		width = cam->params.roi.width;
+		height = cam->params.roi.height;
+
+		DBG("After set_vw_size(), width = %d, height = %d\n",
+		    width, height);
+		if (width <= 176 && height <= 144) {
+			DBG("image type = VIDEOSIZE_QCIF\n");
+			image_type = VIDEOSIZE_QCIF;
+		}
+		else if (width <= 320 && height <= 240) {
+			DBG("image type = VIDEOSIZE_QVGA\n");
+			image_type = VIDEOSIZE_QVGA;
+		}
+		else {
+			DBG("image type = VIDEOSIZE_CIF\n");
+			image_type = VIDEOSIZE_CIF;
+		}
+	} else {
+		ERR("ConfigSensor410 failed\n");
+		return -EINVAL;
+	}
+
+	cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+	cmd.direction = TRANSFER_WRITE;
+
+	/* VC Format */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT;
+	if (image_type == VIDEOSIZE_CIF) {
+		cmd.buffer.registers[i++].value =
+		    (u8) (CPIA2_VC_VC_FORMAT_UFIRST |
+			  CPIA2_VC_VC_FORMAT_SHORTLINE);
+	} else {
+		cmd.buffer.registers[i++].value =
+		    (u8) CPIA2_VC_VC_FORMAT_UFIRST;
+	}
+
+	/* VC Clocks */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS;
+	if (image_type == VIDEOSIZE_QCIF) {
+		if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+			cmd.buffer.registers[i++].value=
+				(u8)(CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 |
+				     CPIA2_VC_VC_672_CLOCKS_SCALING |
+				     CPIA2_VC_VC_CLOCKS_LOGDIV2);
+			DBG("VC_Clocks (0xc4) should be B\n");
+		}
+		else {
+			cmd.buffer.registers[i++].value=
+				(u8)(CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 |
+				     CPIA2_VC_VC_CLOCKS_LOGDIV2);
+		}
+	} else {
+		if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+			cmd.buffer.registers[i++].value =
+			   (u8) (CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 |
+				 CPIA2_VC_VC_CLOCKS_LOGDIV0);
+		}
+		else {
+			cmd.buffer.registers[i++].value =
+			   (u8) (CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 |
+				 CPIA2_VC_VC_676_CLOCKS_SCALING |
+				 CPIA2_VC_VC_CLOCKS_LOGDIV0);
+		}
+	}
+	DBG("VC_Clocks (0xc4) = 0x%0X\n", cmd.buffer.registers[i-1].value);
+
+	/* Input reqWidth from VC */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value =
+		    (u8) (STV_IMAGE_QCIF_COLS / 4);
+	else
+		cmd.buffer.registers[i++].value =
+		    (u8) (STV_IMAGE_CIF_COLS / 4);
+
+	/* Timings */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 0;
+	else
+		cmd.buffer.registers[i++].value = (u8) 1;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 208;
+	else
+		cmd.buffer.registers[i++].value = (u8) 160;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 0;
+	else
+		cmd.buffer.registers[i++].value = (u8) 1;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 160;
+	else
+		cmd.buffer.registers[i++].value = (u8) 64;
+
+	/* Output Image Size */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE;
+	cmd.buffer.registers[i++].value = cam->params.roi.width / 4;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE;
+	cmd.buffer.registers[i++].value = cam->params.roi.height / 4;
+
+	/* Cropping */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2);
+	else
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2);
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2);
+	else
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2);
+
+	/* Scaling registers (defaults) */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE;
+	cmd.buffer.registers[i++].value = (u8) 0;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE;
+	cmd.buffer.registers[i++].value = (u8) 0;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN;
+	cmd.buffer.registers[i++].value = (u8) 31;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN;
+	cmd.buffer.registers[i++].value = (u8) 31;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP;
+	cmd.buffer.registers[i++].value = (u8) 0;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP;
+	cmd.buffer.registers[i++].value = (u8) 0;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT;
+	cmd.buffer.registers[i++].value = (u8) 0x81;	/* = 8/1 = 8 (HIBYTE/LOBYTE) */
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT;
+	cmd.buffer.registers[i++].value = (u8) 0x81;	/* = 8/1 = 8 (HIBYTE/LOBYTE) */
+
+	cmd.reg_count = i;
+
+	cpia2_send_command(cam, &cmd);
+
+	return i;
+}
+
+
+/******************************************************************************
+ *
+ *  config_sensor_500(cam)
+ *
+ *****************************************************************************/
+static int config_sensor_500(struct camera_data *cam,
+			     int req_width, int req_height)
+{
+	struct cpia2_command cmd;
+	int i = 0;
+	int image_size = VIDEOSIZE_CIF;
+	int image_type = VIDEOSIZE_VGA;
+	int width = req_width;
+	int height = req_height;
+	unsigned int device = cam->params.pnp_id.device_type;
+
+	image_size = cpia2_match_video_size(width, height);
+
+	if (width > STV_IMAGE_CIF_COLS || height > STV_IMAGE_CIF_ROWS)
+		image_type = VIDEOSIZE_VGA;
+	else if (width > STV_IMAGE_QVGA_COLS || height > STV_IMAGE_QVGA_ROWS)
+		image_type = VIDEOSIZE_CIF;
+	else if (width > STV_IMAGE_QCIF_COLS || height > STV_IMAGE_QCIF_ROWS)
+		image_type = VIDEOSIZE_QVGA;
+	else
+		image_type = VIDEOSIZE_QCIF;
+
+	if (image_size >= 0) {
+		set_vw_size(cam, image_size);
+		width = cam->params.roi.width;
+		height = cam->params.roi.height;
+	} else {
+		ERR("ConfigSensor500 failed\n");
+		return -EINVAL;
+	}
+
+	DBG("image_size = %d, width = %d, height = %d, type = %d\n",
+	    image_size, width, height, image_type);
+
+	cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+	cmd.direction = TRANSFER_WRITE;
+	i = 0;
+
+	/* VC Format */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT;
+	cmd.buffer.registers[i].value = (u8) CPIA2_VC_VC_FORMAT_UFIRST;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i].value |= (u8) CPIA2_VC_VC_FORMAT_DECIMATING;
+	i++;
+
+	/* VC Clocks */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS;
+	if (device == DEVICE_STV_672) {
+		if (image_type == VIDEOSIZE_VGA)
+			cmd.buffer.registers[i].value =
+				(u8)CPIA2_VC_VC_CLOCKS_LOGDIV1;
+		else
+			cmd.buffer.registers[i].value =
+				(u8)(CPIA2_VC_VC_672_CLOCKS_SCALING |
+				     CPIA2_VC_VC_CLOCKS_LOGDIV3);
+	} else {
+		if (image_type == VIDEOSIZE_VGA)
+			cmd.buffer.registers[i].value =
+				(u8)CPIA2_VC_VC_CLOCKS_LOGDIV0;
+		else
+			cmd.buffer.registers[i].value =
+				(u8)(CPIA2_VC_VC_676_CLOCKS_SCALING |
+				     CPIA2_VC_VC_CLOCKS_LOGDIV2);
+	}
+	i++;
+
+	DBG("VC_CLOCKS = 0x%X\n", cmd.buffer.registers[i-1].value);
+
+	/* Input width from VP */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO;
+	if (image_type == VIDEOSIZE_VGA)
+		cmd.buffer.registers[i].value =
+		    (u8) (STV_IMAGE_VGA_COLS / 4);
+	else
+		cmd.buffer.registers[i].value =
+		    (u8) (STV_IMAGE_QVGA_COLS / 4);
+	i++;
+	DBG("Input width = %d\n", cmd.buffer.registers[i-1].value);
+
+	/* Timings */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI;
+	if (image_type == VIDEOSIZE_VGA)
+		cmd.buffer.registers[i++].value = (u8) 2;
+	else
+		cmd.buffer.registers[i++].value = (u8) 1;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO;
+	if (image_type == VIDEOSIZE_VGA)
+		cmd.buffer.registers[i++].value = (u8) 250;
+	else if (image_type == VIDEOSIZE_QVGA)
+		cmd.buffer.registers[i++].value = (u8) 125;
+	else
+		cmd.buffer.registers[i++].value = (u8) 160;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI;
+	if (image_type == VIDEOSIZE_VGA)
+		cmd.buffer.registers[i++].value = (u8) 2;
+	else
+		cmd.buffer.registers[i++].value = (u8) 1;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO;
+	if (image_type == VIDEOSIZE_VGA)
+		cmd.buffer.registers[i++].value = (u8) 12;
+	else if (image_type == VIDEOSIZE_QVGA)
+		cmd.buffer.registers[i++].value = (u8) 64;
+	else
+		cmd.buffer.registers[i++].value = (u8) 6;
+
+	/* Output Image Size */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = STV_IMAGE_CIF_COLS  / 4;
+	else
+		cmd.buffer.registers[i++].value = width / 4;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = STV_IMAGE_CIF_ROWS  / 4;
+	else
+		cmd.buffer.registers[i++].value = height / 4;
+
+	/* Cropping */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP;
+	if (image_type == VIDEOSIZE_VGA)
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_VGA_COLS / 4) - (width / 4)) / 2);
+	else if (image_type == VIDEOSIZE_QVGA)
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_QVGA_COLS / 4) - (width / 4)) / 2);
+	else if (image_type == VIDEOSIZE_CIF)
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2);
+	else /*if (image_type == VIDEOSIZE_QCIF)*/
+		cmd.buffer.registers[i++].value =
+			(u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2);
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP;
+	if (image_type == VIDEOSIZE_VGA)
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_VGA_ROWS / 4) - (height / 4)) / 2);
+	else if (image_type == VIDEOSIZE_QVGA)
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_QVGA_ROWS / 4) - (height / 4)) / 2);
+	else if (image_type == VIDEOSIZE_CIF)
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2);
+	else /*if (image_type == VIDEOSIZE_QCIF)*/
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2);
+
+	/* Scaling registers (defaults) */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE;
+	if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 36;
+	else
+		cmd.buffer.registers[i++].value = (u8) 0;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE;
+	if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 32;
+	else
+		cmd.buffer.registers[i++].value = (u8) 0;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN;
+	if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 26;
+	else
+		cmd.buffer.registers[i++].value = (u8) 31;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN;
+	if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 21;
+	else
+		cmd.buffer.registers[i++].value = (u8) 31;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP;
+	cmd.buffer.registers[i++].value = (u8) 0;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP;
+	cmd.buffer.registers[i++].value = (u8) 0;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT;
+	if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 0x2B;	/* 2/11 */
+	else
+		cmd.buffer.registers[i++].value = (u8) 0x81;	/* 8/1 */
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT;
+	if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 0x13;	/* 1/3 */
+	else
+		cmd.buffer.registers[i++].value = (u8) 0x81;	/* 8/1 */
+
+	cmd.reg_count = i;
+
+	cpia2_send_command(cam, &cmd);
+
+	return i;
+}
+
+
+/******************************************************************************
+ *
+ *  setallproperties
+ *
+ *  This sets all user changeable properties to the values in cam->params.
+ *****************************************************************************/
+static int set_all_properties(struct camera_data *cam)
+{
+	/**
+	 * Don't set target_kb here, it will be set later.
+	 * framerate and user_mode were already set (set_default_user_mode).
+	 **/
+
+	cpia2_usb_change_streaming_alternate(cam,
+					  cam->params.camera_state.stream_mode);
+
+	cpia2_do_command(cam,
+			 CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+			 TRANSFER_WRITE, cam->params.vp_params.gpio_direction);
+	cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, TRANSFER_WRITE,
+			 cam->params.vp_params.gpio_data);
+
+	v4l2_ctrl_handler_setup(&cam->hdl);
+
+	wake_system(cam);
+
+	set_lowlight_boost(cam);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_save_camera_state
+ *
+ *****************************************************************************/
+void cpia2_save_camera_state(struct camera_data *cam)
+{
+	cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
+	cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, TRANSFER_READ,
+			 0);
+	cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DATA, TRANSFER_READ, 0);
+	/* Don't get framerate or target_kb. Trust the values we already have */
+}
+
+
+/******************************************************************************
+ *
+ *  cpia2_set_flicker_mode
+ *
+ *****************************************************************************/
+int cpia2_set_flicker_mode(struct camera_data *cam, int mode)
+{
+	unsigned char cam_reg;
+	int err = 0;
+
+	if(cam->params.pnp_id.device_type != DEVICE_STV_672)
+		return -EINVAL;
+
+	/* Set the appropriate bits in FLICKER_MODES, preserving the rest */
+	if((err = cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES,
+				   TRANSFER_READ, 0)))
+		return err;
+	cam_reg = cam->params.flicker_control.cam_register;
+
+	switch(mode) {
+	case NEVER_FLICKER:
+		cam_reg |= CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
+		cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ;
+		break;
+	case FLICKER_60:
+		cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
+		cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ;
+		break;
+	case FLICKER_50:
+		cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
+		cam_reg |= CPIA2_VP_FLICKER_MODES_50HZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if((err = cpia2_do_command(cam, CPIA2_CMD_SET_FLICKER_MODES,
+				   TRANSFER_WRITE, cam_reg)))
+		return err;
+
+	/* Set the appropriate bits in EXP_MODES, preserving the rest */
+	if((err = cpia2_do_command(cam, CPIA2_CMD_GET_VP_EXP_MODES,
+				   TRANSFER_READ, 0)))
+		return err;
+	cam_reg = cam->params.vp_params.exposure_modes;
+
+	if (mode == NEVER_FLICKER) {
+		cam_reg |= CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER;
+	} else {
+		cam_reg &= ~CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER;
+	}
+
+	if((err = cpia2_do_command(cam, CPIA2_CMD_SET_VP_EXP_MODES,
+				   TRANSFER_WRITE, cam_reg)))
+		return err;
+
+	if((err = cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4,
+				   TRANSFER_WRITE, 1)))
+		return err;
+
+	switch(mode) {
+	case NEVER_FLICKER:
+	case FLICKER_60:
+	case FLICKER_50:
+		cam->params.flicker_control.flicker_mode_req = mode;
+		break;
+	default:
+		err = -EINVAL;
+	}
+
+	return err;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_property_flip
+ *
+ *****************************************************************************/
+void cpia2_set_property_flip(struct camera_data *cam, int prop_val)
+{
+	unsigned char cam_reg;
+
+	cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
+	cam_reg = cam->params.vp_params.user_effects;
+
+	if (prop_val)
+	{
+		cam_reg |= CPIA2_VP_USER_EFFECTS_FLIP;
+	}
+	else
+	{
+		cam_reg &= ~CPIA2_VP_USER_EFFECTS_FLIP;
+	}
+	cam->params.vp_params.user_effects = cam_reg;
+	cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
+			 cam_reg);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_property_mirror
+ *
+ *****************************************************************************/
+void cpia2_set_property_mirror(struct camera_data *cam, int prop_val)
+{
+	unsigned char cam_reg;
+
+	cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
+	cam_reg = cam->params.vp_params.user_effects;
+
+	if (prop_val)
+	{
+		cam_reg |= CPIA2_VP_USER_EFFECTS_MIRROR;
+	}
+	else
+	{
+		cam_reg &= ~CPIA2_VP_USER_EFFECTS_MIRROR;
+	}
+	cam->params.vp_params.user_effects = cam_reg;
+	cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
+			 cam_reg);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_gpio
+ *
+ *****************************************************************************/
+int cpia2_set_gpio(struct camera_data *cam, unsigned char setting)
+{
+	int ret;
+
+	/* Set the microport direction (register 0x90, should be defined
+	 * already) to 1 (user output), and set the microport data (0x91) to
+	 * the value in the ioctl argument.
+	 */
+
+	ret = cpia2_do_command(cam,
+			       CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+			       CPIA2_VC_MP_DIR_OUTPUT,
+			       255);
+	if (ret < 0)
+		return ret;
+	cam->params.vp_params.gpio_direction = 255;
+
+	ret = cpia2_do_command(cam,
+			       CPIA2_CMD_SET_VC_MP_GPIO_DATA,
+			       CPIA2_VC_MP_DIR_OUTPUT,
+			       setting);
+	if (ret < 0)
+		return ret;
+	cam->params.vp_params.gpio_data = setting;
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_fps
+ *
+ *****************************************************************************/
+int cpia2_set_fps(struct camera_data *cam, int framerate)
+{
+	int retval;
+
+	switch(framerate) {
+		case CPIA2_VP_FRAMERATE_30:
+		case CPIA2_VP_FRAMERATE_25:
+			if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+			   cam->params.version.sensor_flags ==
+						    CPIA2_VP_SENSOR_FLAGS_500) {
+				return -EINVAL;
+			}
+			/* Fall through */
+		case CPIA2_VP_FRAMERATE_15:
+		case CPIA2_VP_FRAMERATE_12_5:
+		case CPIA2_VP_FRAMERATE_7_5:
+		case CPIA2_VP_FRAMERATE_6_25:
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+	    framerate == CPIA2_VP_FRAMERATE_15)
+		framerate = 0; /* Work around bug in VP4 */
+
+	retval = cpia2_do_command(cam,
+				 CPIA2_CMD_FRAMERATE_REQ,
+				 TRANSFER_WRITE,
+				 framerate);
+
+	if(retval == 0)
+		cam->params.vp_params.frame_rate = framerate;
+
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_brightness
+ *
+ *****************************************************************************/
+void cpia2_set_brightness(struct camera_data *cam, unsigned char value)
+{
+	/***
+	 * Don't let the register be set to zero - bug in VP4 - flash of full
+	 * brightness
+	 ***/
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672 && value == 0)
+		value++;
+	DBG("Setting brightness to %d (0x%0x)\n", value, value);
+	cpia2_do_command(cam, CPIA2_CMD_SET_VP_BRIGHTNESS, TRANSFER_WRITE, value);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_contrast
+ *
+ *****************************************************************************/
+void cpia2_set_contrast(struct camera_data *cam, unsigned char value)
+{
+	DBG("Setting contrast to %d (0x%0x)\n", value, value);
+	cpia2_do_command(cam, CPIA2_CMD_SET_CONTRAST, TRANSFER_WRITE, value);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_saturation
+ *
+ *****************************************************************************/
+void cpia2_set_saturation(struct camera_data *cam, unsigned char value)
+{
+	DBG("Setting saturation to %d (0x%0x)\n", value, value);
+	cpia2_do_command(cam,CPIA2_CMD_SET_VP_SATURATION, TRANSFER_WRITE,value);
+}
+
+/******************************************************************************
+ *
+ *  wake_system
+ *
+ *****************************************************************************/
+static void wake_system(struct camera_data *cam)
+{
+	cpia2_do_command(cam, CPIA2_CMD_SET_WAKEUP, TRANSFER_WRITE, 0);
+}
+
+/******************************************************************************
+ *
+ *  set_lowlight_boost
+ *
+ *  Valid for STV500 sensor only
+ *****************************************************************************/
+static void set_lowlight_boost(struct camera_data *cam)
+{
+	struct cpia2_command cmd;
+
+	if (cam->params.pnp_id.device_type != DEVICE_STV_672 ||
+	    cam->params.version.sensor_flags != CPIA2_VP_SENSOR_FLAGS_500)
+		return;
+
+	cmd.direction = TRANSFER_WRITE;
+	cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+	cmd.reg_count = 3;
+	cmd.start = CPIA2_VP_RAM_ADDR_H;
+
+	cmd.buffer.block_data[0] = 0;	/* High byte of address to write to */
+	cmd.buffer.block_data[1] = 0x59;	/* Low byte of address to write to */
+	cmd.buffer.block_data[2] = 0;	/* High byte of data to write */
+
+	cpia2_send_command(cam, &cmd);
+
+	if (cam->params.vp_params.lowlight_boost) {
+		cmd.buffer.block_data[0] = 0x02;	/* Low byte data to write */
+	} else {
+		cmd.buffer.block_data[0] = 0x06;
+	}
+	cmd.start = CPIA2_VP_RAM_DATA;
+	cmd.reg_count = 1;
+	cpia2_send_command(cam, &cmd);
+
+	/* Rehash the VP4 values */
+	cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4, TRANSFER_WRITE, 1);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_format
+ *
+ *  Assumes that new size is already set in param struct.
+ *****************************************************************************/
+void cpia2_set_format(struct camera_data *cam)
+{
+	cam->flush = true;
+
+	cpia2_usb_stream_pause(cam);
+
+	/* reset camera to new size */
+	cpia2_set_low_power(cam);
+	cpia2_reset_camera(cam);
+	cam->flush = false;
+
+	cpia2_dbg_dump_registers(cam);
+
+	cpia2_usb_stream_resume(cam);
+}
+
+/******************************************************************************
+ *
+ * cpia2_dbg_dump_registers
+ *
+ *****************************************************************************/
+void cpia2_dbg_dump_registers(struct camera_data *cam)
+{
+#ifdef _CPIA2_DEBUG_
+	struct cpia2_command cmd;
+
+	if (!(debugs_on & DEBUG_DUMP_REGS))
+		return;
+
+	cmd.direction = TRANSFER_READ;
+
+	/* Start with bank 0 (SYSTEM) */
+	cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+	cmd.reg_count = 3;
+	cmd.start = 0;
+	cpia2_send_command(cam, &cmd);
+	printk(KERN_DEBUG "System Device Hi      = 0x%X\n",
+	       cmd.buffer.block_data[0]);
+	printk(KERN_DEBUG "System Device Lo      = 0x%X\n",
+	       cmd.buffer.block_data[1]);
+	printk(KERN_DEBUG "System_system control = 0x%X\n",
+	       cmd.buffer.block_data[2]);
+
+	/* Bank 1 (VC) */
+	cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+	cmd.reg_count = 4;
+	cmd.start = 0x80;
+	cpia2_send_command(cam, &cmd);
+	printk(KERN_DEBUG "ASIC_ID       = 0x%X\n",
+	       cmd.buffer.block_data[0]);
+	printk(KERN_DEBUG "ASIC_REV      = 0x%X\n",
+	       cmd.buffer.block_data[1]);
+	printk(KERN_DEBUG "PW_CONTRL     = 0x%X\n",
+	       cmd.buffer.block_data[2]);
+	printk(KERN_DEBUG "WAKEUP        = 0x%X\n",
+	       cmd.buffer.block_data[3]);
+
+	cmd.start = 0xA0;	/* ST_CTRL */
+	cmd.reg_count = 1;
+	cpia2_send_command(cam, &cmd);
+	printk(KERN_DEBUG "Stream ctrl   = 0x%X\n",
+	       cmd.buffer.block_data[0]);
+
+	cmd.start = 0xA4;	/* Stream status */
+	cpia2_send_command(cam, &cmd);
+	printk(KERN_DEBUG "Stream status = 0x%X\n",
+	       cmd.buffer.block_data[0]);
+
+	cmd.start = 0xA8;	/* USB status */
+	cmd.reg_count = 3;
+	cpia2_send_command(cam, &cmd);
+	printk(KERN_DEBUG "USB_CTRL      = 0x%X\n",
+	       cmd.buffer.block_data[0]);
+	printk(KERN_DEBUG "USB_STRM      = 0x%X\n",
+	       cmd.buffer.block_data[1]);
+	printk(KERN_DEBUG "USB_STATUS    = 0x%X\n",
+	       cmd.buffer.block_data[2]);
+
+	cmd.start = 0xAF;	/* USB settings */
+	cmd.reg_count = 1;
+	cpia2_send_command(cam, &cmd);
+	printk(KERN_DEBUG "USB settings  = 0x%X\n",
+	       cmd.buffer.block_data[0]);
+
+	cmd.start = 0xC0;	/* VC stuff */
+	cmd.reg_count = 26;
+	cpia2_send_command(cam, &cmd);
+	printk(KERN_DEBUG "VC Control    = 0x%0X\n",
+	       cmd.buffer.block_data[0]);
+	printk(KERN_DEBUG "VC Format     = 0x%0X\n",
+	       cmd.buffer.block_data[3]);
+	printk(KERN_DEBUG "VC Clocks     = 0x%0X\n",
+	       cmd.buffer.block_data[4]);
+	printk(KERN_DEBUG "VC IHSize     = 0x%0X\n",
+	       cmd.buffer.block_data[5]);
+	printk(KERN_DEBUG "VC Xlim Hi    = 0x%0X\n",
+	       cmd.buffer.block_data[6]);
+	printk(KERN_DEBUG "VC XLim Lo    = 0x%0X\n",
+	       cmd.buffer.block_data[7]);
+	printk(KERN_DEBUG "VC YLim Hi    = 0x%0X\n",
+	       cmd.buffer.block_data[8]);
+	printk(KERN_DEBUG "VC YLim Lo    = 0x%0X\n",
+	       cmd.buffer.block_data[9]);
+	printk(KERN_DEBUG "VC OHSize     = 0x%0X\n",
+	       cmd.buffer.block_data[10]);
+	printk(KERN_DEBUG "VC OVSize     = 0x%0X\n",
+	       cmd.buffer.block_data[11]);
+	printk(KERN_DEBUG "VC HCrop      = 0x%0X\n",
+	       cmd.buffer.block_data[12]);
+	printk(KERN_DEBUG "VC VCrop      = 0x%0X\n",
+	       cmd.buffer.block_data[13]);
+	printk(KERN_DEBUG "VC HPhase     = 0x%0X\n",
+	       cmd.buffer.block_data[14]);
+	printk(KERN_DEBUG "VC VPhase     = 0x%0X\n",
+	       cmd.buffer.block_data[15]);
+	printk(KERN_DEBUG "VC HIspan     = 0x%0X\n",
+	       cmd.buffer.block_data[16]);
+	printk(KERN_DEBUG "VC VIspan     = 0x%0X\n",
+	       cmd.buffer.block_data[17]);
+	printk(KERN_DEBUG "VC HiCrop     = 0x%0X\n",
+	       cmd.buffer.block_data[18]);
+	printk(KERN_DEBUG "VC ViCrop     = 0x%0X\n",
+	       cmd.buffer.block_data[19]);
+	printk(KERN_DEBUG "VC HiFract    = 0x%0X\n",
+	       cmd.buffer.block_data[20]);
+	printk(KERN_DEBUG "VC ViFract    = 0x%0X\n",
+	       cmd.buffer.block_data[21]);
+	printk(KERN_DEBUG "VC JPeg Opt   = 0x%0X\n",
+	       cmd.buffer.block_data[22]);
+	printk(KERN_DEBUG "VC Creep Per  = 0x%0X\n",
+	       cmd.buffer.block_data[23]);
+	printk(KERN_DEBUG "VC User Sq.   = 0x%0X\n",
+	       cmd.buffer.block_data[24]);
+	printk(KERN_DEBUG "VC Target KB  = 0x%0X\n",
+	       cmd.buffer.block_data[25]);
+
+	/*** VP ***/
+	cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+	cmd.reg_count = 14;
+	cmd.start = 0;
+	cpia2_send_command(cam, &cmd);
+
+	printk(KERN_DEBUG "VP Dev Hi     = 0x%0X\n",
+	       cmd.buffer.block_data[0]);
+	printk(KERN_DEBUG "VP Dev Lo     = 0x%0X\n",
+	       cmd.buffer.block_data[1]);
+	printk(KERN_DEBUG "VP Sys State  = 0x%0X\n",
+	       cmd.buffer.block_data[2]);
+	printk(KERN_DEBUG "VP Sys Ctrl   = 0x%0X\n",
+	       cmd.buffer.block_data[3]);
+	printk(KERN_DEBUG "VP Sensor flg = 0x%0X\n",
+	       cmd.buffer.block_data[5]);
+	printk(KERN_DEBUG "VP Sensor Rev = 0x%0X\n",
+	       cmd.buffer.block_data[6]);
+	printk(KERN_DEBUG "VP Dev Config = 0x%0X\n",
+	       cmd.buffer.block_data[7]);
+	printk(KERN_DEBUG "VP GPIO_DIR   = 0x%0X\n",
+	       cmd.buffer.block_data[8]);
+	printk(KERN_DEBUG "VP GPIO_DATA  = 0x%0X\n",
+	       cmd.buffer.block_data[9]);
+	printk(KERN_DEBUG "VP Ram ADDR H = 0x%0X\n",
+	       cmd.buffer.block_data[10]);
+	printk(KERN_DEBUG "VP Ram ADDR L = 0x%0X\n",
+	       cmd.buffer.block_data[11]);
+	printk(KERN_DEBUG "VP RAM Data   = 0x%0X\n",
+	       cmd.buffer.block_data[12]);
+	printk(KERN_DEBUG "Do Call       = 0x%0X\n",
+	       cmd.buffer.block_data[13]);
+
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+		cmd.reg_count = 9;
+		cmd.start = 0x0E;
+		cpia2_send_command(cam, &cmd);
+		printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n",
+		       cmd.buffer.block_data[0]);
+		printk(KERN_DEBUG "VP Patch Rev  = 0x%0X\n",
+		       cmd.buffer.block_data[1]);
+		printk(KERN_DEBUG "VP Vid Mode   = 0x%0X\n",
+		       cmd.buffer.block_data[2]);
+		printk(KERN_DEBUG "VP Framerate  = 0x%0X\n",
+		       cmd.buffer.block_data[3]);
+		printk(KERN_DEBUG "VP UserEffect = 0x%0X\n",
+		       cmd.buffer.block_data[4]);
+		printk(KERN_DEBUG "VP White Bal  = 0x%0X\n",
+		       cmd.buffer.block_data[5]);
+		printk(KERN_DEBUG "VP WB thresh  = 0x%0X\n",
+		       cmd.buffer.block_data[6]);
+		printk(KERN_DEBUG "VP Exp Modes  = 0x%0X\n",
+		       cmd.buffer.block_data[7]);
+		printk(KERN_DEBUG "VP Exp Target = 0x%0X\n",
+		       cmd.buffer.block_data[8]);
+
+		cmd.reg_count = 1;
+		cmd.start = 0x1B;
+		cpia2_send_command(cam, &cmd);
+		printk(KERN_DEBUG "VP FlickerMds = 0x%0X\n",
+		       cmd.buffer.block_data[0]);
+	} else {
+		cmd.reg_count = 8 ;
+		cmd.start = 0x0E;
+		cpia2_send_command(cam, &cmd);
+		printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n",
+		       cmd.buffer.block_data[0]);
+		printk(KERN_DEBUG "VP Patch Rev  = 0x%0X\n",
+		       cmd.buffer.block_data[1]);
+		printk(KERN_DEBUG "VP Vid Mode   = 0x%0X\n",
+		       cmd.buffer.block_data[5]);
+		printk(KERN_DEBUG "VP Framerate  = 0x%0X\n",
+		       cmd.buffer.block_data[6]);
+		printk(KERN_DEBUG "VP UserEffect = 0x%0X\n",
+		       cmd.buffer.block_data[7]);
+
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP5_EXPOSURE_TARGET;
+		cpia2_send_command(cam, &cmd);
+		printk(KERN_DEBUG "VP5 Exp Target= 0x%0X\n",
+		       cmd.buffer.block_data[0]);
+
+		cmd.reg_count = 4;
+		cmd.start = 0x3A;
+		cpia2_send_command(cam, &cmd);
+		printk(KERN_DEBUG "VP5 MY Black  = 0x%0X\n",
+		       cmd.buffer.block_data[0]);
+		printk(KERN_DEBUG "VP5 MCY Range = 0x%0X\n",
+		       cmd.buffer.block_data[1]);
+		printk(KERN_DEBUG "VP5 MYCEILING = 0x%0X\n",
+		       cmd.buffer.block_data[2]);
+		printk(KERN_DEBUG "VP5 MCUV Sat  = 0x%0X\n",
+		       cmd.buffer.block_data[3]);
+	}
+#endif
+}
+
+/******************************************************************************
+ *
+ *  reset_camera_struct
+ *
+ *  Sets all values to the defaults
+ *****************************************************************************/
+static void reset_camera_struct(struct camera_data *cam)
+{
+	/***
+	 * The following parameter values are the defaults from the register map.
+	 ***/
+	cam->params.vp_params.lowlight_boost = 0;
+
+	/* FlickerModes */
+	cam->params.flicker_control.flicker_mode_req = NEVER_FLICKER;
+
+	/* jpeg params */
+	cam->params.compression.jpeg_options = CPIA2_VC_VC_JPEG_OPT_DEFAULT;
+	cam->params.compression.creep_period = 2;
+	cam->params.compression.user_squeeze = 20;
+	cam->params.compression.inhibit_htables = false;
+
+	/* gpio params */
+	cam->params.vp_params.gpio_direction = 0;	/* write, the default safe mode */
+	cam->params.vp_params.gpio_data = 0;
+
+	/* Target kb params */
+	cam->params.vc_params.quality = 100;
+
+	/***
+	 * Set Sensor FPS as fast as possible.
+	 ***/
+	if(cam->params.pnp_id.device_type == DEVICE_STV_672) {
+		if(cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
+			cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_15;
+		else
+			cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30;
+	} else {
+		cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30;
+	}
+
+	/***
+	 * Set default video mode as large as possible :
+	 * for vga sensor set to vga, for cif sensor set to CIF.
+	 ***/
+	if (cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) {
+		cam->sensor_type = CPIA2_SENSOR_500;
+		cam->video_size = VIDEOSIZE_VGA;
+		cam->params.roi.width = STV_IMAGE_VGA_COLS;
+		cam->params.roi.height = STV_IMAGE_VGA_ROWS;
+	} else {
+		cam->sensor_type = CPIA2_SENSOR_410;
+		cam->video_size = VIDEOSIZE_CIF;
+		cam->params.roi.width = STV_IMAGE_CIF_COLS;
+		cam->params.roi.height = STV_IMAGE_CIF_ROWS;
+	}
+
+	cam->width = cam->params.roi.width;
+	cam->height = cam->params.roi.height;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_init_camera_struct
+ *
+ *  Initializes camera struct, does not call reset to fill in defaults.
+ *****************************************************************************/
+struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf)
+{
+	struct camera_data *cam;
+
+	cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+
+	if (!cam) {
+		ERR("couldn't kmalloc cpia2 struct\n");
+		return NULL;
+	}
+
+	cam->v4l2_dev.release = cpia2_camera_release;
+	if (v4l2_device_register(&intf->dev, &cam->v4l2_dev) < 0) {
+		v4l2_err(&cam->v4l2_dev, "couldn't register v4l2_device\n");
+		kfree(cam);
+		return NULL;
+	}
+
+	mutex_init(&cam->v4l2_lock);
+	init_waitqueue_head(&cam->wq_stream);
+
+	return cam;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_init_camera
+ *
+ *  Initializes camera.
+ *****************************************************************************/
+int cpia2_init_camera(struct camera_data *cam)
+{
+	DBG("Start\n");
+
+	cam->mmapped = false;
+
+	/* Get sensor and asic types before reset. */
+	cpia2_set_high_power(cam);
+	cpia2_get_version_info(cam);
+	if (cam->params.version.asic_id != CPIA2_ASIC_672) {
+		ERR("Device IO error (asicID has incorrect value of 0x%X\n",
+		    cam->params.version.asic_id);
+		return -ENODEV;
+	}
+
+	/* Set GPIO direction and data to a safe state. */
+	cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+			 TRANSFER_WRITE, 0);
+	cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA,
+			 TRANSFER_WRITE, 0);
+
+	/* resetting struct requires version info for sensor and asic types */
+	reset_camera_struct(cam);
+
+	cpia2_set_low_power(cam);
+
+	DBG("End\n");
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_allocate_buffers
+ *
+ *****************************************************************************/
+int cpia2_allocate_buffers(struct camera_data *cam)
+{
+	int i;
+
+	if(!cam->buffers) {
+		u32 size = cam->num_frames*sizeof(struct framebuf);
+		cam->buffers = kmalloc(size, GFP_KERNEL);
+		if(!cam->buffers) {
+			ERR("couldn't kmalloc frame buffer structures\n");
+			return -ENOMEM;
+		}
+	}
+
+	if(!cam->frame_buffer) {
+		cam->frame_buffer = rvmalloc(cam->frame_size*cam->num_frames);
+		if (!cam->frame_buffer) {
+			ERR("couldn't vmalloc frame buffer data area\n");
+			kfree(cam->buffers);
+			cam->buffers = NULL;
+			return -ENOMEM;
+		}
+	}
+
+	for(i=0; i<cam->num_frames-1; ++i) {
+		cam->buffers[i].next = &cam->buffers[i+1];
+		cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size;
+		cam->buffers[i].status = FRAME_EMPTY;
+		cam->buffers[i].length = 0;
+		cam->buffers[i].max_length = 0;
+		cam->buffers[i].num = i;
+	}
+	cam->buffers[i].next = cam->buffers;
+	cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size;
+	cam->buffers[i].status = FRAME_EMPTY;
+	cam->buffers[i].length = 0;
+	cam->buffers[i].max_length = 0;
+	cam->buffers[i].num = i;
+	cam->curbuff = cam->buffers;
+	cam->workbuff = cam->curbuff->next;
+	DBG("buffers=%p, curbuff=%p, workbuff=%p\n", cam->buffers, cam->curbuff,
+	    cam->workbuff);
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_free_buffers
+ *
+ *****************************************************************************/
+void cpia2_free_buffers(struct camera_data *cam)
+{
+	if(cam->buffers) {
+		kfree(cam->buffers);
+		cam->buffers = NULL;
+	}
+	if(cam->frame_buffer) {
+		rvfree(cam->frame_buffer, cam->frame_size*cam->num_frames);
+		cam->frame_buffer = NULL;
+	}
+}
+
+/******************************************************************************
+ *
+ *  cpia2_read
+ *
+ *****************************************************************************/
+long cpia2_read(struct camera_data *cam,
+		char __user *buf, unsigned long count, int noblock)
+{
+	struct framebuf *frame;
+
+	if (!count)
+		return 0;
+
+	if (!buf) {
+		ERR("%s: buffer NULL\n",__func__);
+		return -EINVAL;
+	}
+
+	if (!cam) {
+		ERR("%s: Internal error, camera_data NULL!\n",__func__);
+		return -EINVAL;
+	}
+
+	if (!cam->streaming) {
+		/* Start streaming */
+		cpia2_usb_stream_start(cam,
+				       cam->params.camera_state.stream_mode);
+	}
+
+	/* Copy cam->curbuff in case it changes while we're processing */
+	frame = cam->curbuff;
+	if (noblock && frame->status != FRAME_READY) {
+		return -EAGAIN;
+	}
+
+	if (frame->status != FRAME_READY) {
+		mutex_unlock(&cam->v4l2_lock);
+		wait_event_interruptible(cam->wq_stream,
+			       !video_is_registered(&cam->vdev) ||
+			       (frame = cam->curbuff)->status == FRAME_READY);
+		mutex_lock(&cam->v4l2_lock);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+		if (!video_is_registered(&cam->vdev))
+			return 0;
+	}
+
+	/* copy data to user space */
+	if (frame->length > count)
+		return -EFAULT;
+	if (copy_to_user(buf, frame->data, frame->length))
+		return -EFAULT;
+
+	count = frame->length;
+
+	frame->status = FRAME_EMPTY;
+
+	return count;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_poll
+ *
+ *****************************************************************************/
+unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
+			poll_table *wait)
+{
+	unsigned int status = v4l2_ctrl_poll(filp, wait);
+
+	if ((poll_requested_events(wait) & (POLLIN | POLLRDNORM)) &&
+			!cam->streaming) {
+		/* Start streaming */
+		cpia2_usb_stream_start(cam,
+				       cam->params.camera_state.stream_mode);
+	}
+
+	poll_wait(filp, &cam->wq_stream, wait);
+
+	if (cam->curbuff->status == FRAME_READY)
+		status |= POLLIN | POLLRDNORM;
+
+	return status;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_remap_buffer
+ *
+ *****************************************************************************/
+int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
+{
+	const char *adr = (const char *)vma->vm_start;
+	unsigned long size = vma->vm_end-vma->vm_start;
+	unsigned long start_offset = vma->vm_pgoff << PAGE_SHIFT;
+	unsigned long start = (unsigned long) adr;
+	unsigned long page, pos;
+
+	DBG("mmap offset:%ld size:%ld\n", start_offset, size);
+
+	if (!video_is_registered(&cam->vdev))
+		return -ENODEV;
+
+	if (size > cam->frame_size*cam->num_frames  ||
+	    (start_offset % cam->frame_size) != 0 ||
+	    (start_offset+size > cam->frame_size*cam->num_frames))
+		return -EINVAL;
+
+	pos = ((unsigned long) (cam->frame_buffer)) + start_offset;
+	while (size > 0) {
+		page = kvirt_to_pa(pos);
+		if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED))
+			return -EAGAIN;
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+
+	cam->mmapped = true;
+	return 0;
+}
diff --git a/drivers/media/usb/cpia2/cpia2_registers.h b/drivers/media/usb/cpia2/cpia2_registers.h
new file mode 100644
index 0000000..3bbec51
--- /dev/null
+++ b/drivers/media/usb/cpia2/cpia2_registers.h
@@ -0,0 +1,476 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2registers.h
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *
+ *  Description:
+ *     Definitions for the CPia2 register set
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************************/
+
+#ifndef CPIA2_REGISTER_HEADER
+#define CPIA2_REGISTER_HEADER
+
+/***
+ * System register set (Bank 0)
+ ***/
+#define CPIA2_SYSTEM_DEVICE_HI                     0x00
+#define CPIA2_SYSTEM_DEVICE_LO                     0x01
+
+#define CPIA2_SYSTEM_SYSTEM_CONTROL                0x02
+#define CPIA2_SYSTEM_CONTROL_LOW_POWER       0x00
+#define CPIA2_SYSTEM_CONTROL_HIGH_POWER      0x01
+#define CPIA2_SYSTEM_CONTROL_SUSPEND         0x02
+#define CPIA2_SYSTEM_CONTROL_V2W_ERR         0x10
+#define CPIA2_SYSTEM_CONTROL_RB_ERR          0x10
+#define CPIA2_SYSTEM_CONTROL_CLEAR_ERR       0x80
+
+#define CPIA2_SYSTEM_INT_PACKET_CTRL                0x04
+#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX 0x01
+#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_EOF   0x02
+#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_INT1  0x04
+
+#define CPIA2_SYSTEM_CACHE_CTRL                     0x05
+#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_RESET      0x01
+#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_FLUSH      0x02
+
+#define CPIA2_SYSTEM_SERIAL_CTRL                    0x06
+#define CPIA2_SYSTEM_SERIAL_CTRL_NULL_CMD        0x00
+#define CPIA2_SYSTEM_SERIAL_CTRL_START_CMD       0x01
+#define CPIA2_SYSTEM_SERIAL_CTRL_STOP_CMD        0x02
+#define CPIA2_SYSTEM_SERIAL_CTRL_WRITE_CMD       0x03
+#define CPIA2_SYSTEM_SERIAL_CTRL_READ_ACK_CMD    0x04
+#define CPIA2_SYSTEM_SERIAL_CTRL_READ_NACK_CMD   0x05
+
+#define CPIA2_SYSTEM_SERIAL_DATA                     0x07
+
+#define CPIA2_SYSTEM_VP_SERIAL_ADDR                  0x08
+
+/***
+ * I2C addresses for various devices in CPiA2
+ ***/
+#define CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR           0x20
+#define CPIA2_SYSTEM_VP_SERIAL_ADDR_VP               0x88
+#define CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP           0x8A
+
+#define CPIA2_SYSTEM_SPARE_REG1                      0x09
+#define CPIA2_SYSTEM_SPARE_REG2                      0x0A
+#define CPIA2_SYSTEM_SPARE_REG3                      0x0B
+
+#define CPIA2_SYSTEM_MC_PORT_0                       0x0C
+#define CPIA2_SYSTEM_MC_PORT_1                       0x0D
+#define CPIA2_SYSTEM_MC_PORT_2                       0x0E
+#define CPIA2_SYSTEM_MC_PORT_3                       0x0F
+
+#define CPIA2_SYSTEM_STATUS_PKT                      0x20
+#define CPIA2_SYSTEM_STATUS_PKT_END                  0x27
+
+#define CPIA2_SYSTEM_DESCRIP_VID_HI                  0x30
+#define CPIA2_SYSTEM_DESCRIP_VID_LO                  0x31
+#define CPIA2_SYSTEM_DESCRIP_PID_HI                  0x32
+#define CPIA2_SYSTEM_DESCRIP_PID_LO                  0x33
+
+#define CPIA2_SYSTEM_FW_VERSION_HI                   0x34
+#define CPIA2_SYSTEM_FW_VERSION_LO                   0x35
+
+#define CPIA2_SYSTEM_CACHE_START_INDEX               0x80
+#define CPIA2_SYSTEM_CACHE_MAX_WRITES                0x10
+
+/***
+ * VC register set (Bank 1)
+ ***/
+#define CPIA2_VC_ASIC_ID                 0x80
+
+#define CPIA2_VC_ASIC_REV                0x81
+
+#define CPIA2_VC_PW_CTRL                 0x82
+#define CPIA2_VC_PW_CTRL_COLDSTART      0x01
+#define CPIA2_VC_PW_CTRL_CP_CLK_EN      0x02
+#define CPIA2_VC_PW_CTRL_VP_RESET_N     0x04
+#define CPIA2_VC_PW_CTRL_VC_CLK_EN      0x08
+#define CPIA2_VC_PW_CTRL_VC_RESET_N     0x10
+#define CPIA2_VC_PW_CTRL_GOTO_SUSPEND   0x20
+#define CPIA2_VC_PW_CTRL_UDC_SUSPEND    0x40
+#define CPIA2_VC_PW_CTRL_PWR_DOWN       0x80
+
+#define CPIA2_VC_WAKEUP                   0x83
+#define CPIA2_VC_WAKEUP_SW_ENABLE       0x01
+#define CPIA2_VC_WAKEUP_XX_ENABLE       0x02
+#define CPIA2_VC_WAKEUP_SW_ATWAKEUP     0x04
+#define CPIA2_VC_WAKEUP_XX_ATWAKEUP     0x08
+
+#define CPIA2_VC_CLOCK_CTRL               0x84
+#define CPIA2_VC_CLOCK_CTRL_TESTUP72    0x01
+
+#define CPIA2_VC_INT_ENABLE                0x88
+#define CPIA2_VC_INT_ENABLE_XX_IE       0x01
+#define CPIA2_VC_INT_ENABLE_SW_IE       0x02
+#define CPIA2_VC_INT_ENABLE_VC_IE       0x04
+#define CPIA2_VC_INT_ENABLE_USBDATA_IE  0x08
+#define CPIA2_VC_INT_ENABLE_USBSETUP_IE 0x10
+#define CPIA2_VC_INT_ENABLE_USBCFG_IE   0x20
+
+#define CPIA2_VC_INT_FLAG                  0x89
+#define CPIA2_VC_INT_ENABLE_XX_FLAG       0x01
+#define CPIA2_VC_INT_ENABLE_SW_FLAG       0x02
+#define CPIA2_VC_INT_ENABLE_VC_FLAG       0x04
+#define CPIA2_VC_INT_ENABLE_USBDATA_FLAG  0x08
+#define CPIA2_VC_INT_ENABLE_USBSETUP_FLAG 0x10
+#define CPIA2_VC_INT_ENABLE_USBCFG_FLAG   0x20
+#define CPIA2_VC_INT_ENABLE_SET_RESET_BIT 0x80
+
+#define CPIA2_VC_INT_STATE                 0x8A
+#define CPIA2_VC_INT_STATE_XX_STATE     0x01
+#define CPIA2_VC_INT_STATE_SW_STATE     0x02
+
+#define CPIA2_VC_MP_DIR                    0x90
+#define CPIA2_VC_MP_DIR_INPUT           0x00
+#define CPIA2_VC_MP_DIR_OUTPUT          0x01
+
+#define CPIA2_VC_MP_DATA                   0x91
+
+#define CPIA2_VC_DP_CTRL                   0x98
+#define CPIA2_VC_DP_CTRL_MODE_0         0x00
+#define CPIA2_VC_DP_CTRL_MODE_A         0x01
+#define CPIA2_VC_DP_CTRL_MODE_B         0x02
+#define CPIA2_VC_DP_CTRL_MODE_C         0x03
+#define CPIA2_VC_DP_CTRL_FAKE_FST       0x04
+
+#define CPIA2_VC_AD_CTRL                   0x99
+#define CPIA2_VC_AD_CTRL_SRC_0          0x00
+#define CPIA2_VC_AD_CTRL_SRC_DIGI_A     0x01
+#define CPIA2_VC_AD_CTRL_SRC_REG        0x02
+#define CPIA2_VC_AD_CTRL_DST_USB        0x00
+#define CPIA2_VC_AD_CTRL_DST_REG        0x04
+
+#define CPIA2_VC_AD_TEST_IN                0x9B
+
+#define CPIA2_VC_AD_TEST_OUT               0x9C
+
+#define CPIA2_VC_AD_STATUS                 0x9D
+#define CPIA2_VC_AD_STATUS_EMPTY        0x01
+#define CPIA2_VC_AD_STATUS_FULL         0x02
+
+#define CPIA2_VC_DP_DATA                   0x9E
+
+#define CPIA2_VC_ST_CTRL                   0xA0
+#define CPIA2_VC_ST_CTRL_SRC_VC         0x00
+#define CPIA2_VC_ST_CTRL_SRC_DP         0x01
+#define CPIA2_VC_ST_CTRL_SRC_REG        0x02
+
+#define CPIA2_VC_ST_CTRL_RAW_SELECT     0x04
+
+#define CPIA2_VC_ST_CTRL_DST_USB        0x00
+#define CPIA2_VC_ST_CTRL_DST_DP         0x08
+#define CPIA2_VC_ST_CTRL_DST_REG        0x10
+
+#define CPIA2_VC_ST_CTRL_FIFO_ENABLE    0x20
+#define CPIA2_VC_ST_CTRL_EOF_DETECT     0x40
+
+#define CPIA2_VC_ST_TEST                   0xA1
+#define CPIA2_VC_ST_TEST_MODE_MANUAL    0x00
+#define CPIA2_VC_ST_TEST_MODE_INCREMENT 0x02
+
+#define CPIA2_VC_ST_TEST_AUTO_FILL      0x08
+
+#define CPIA2_VC_ST_TEST_REPEAT_FIFO    0x10
+
+#define CPIA2_VC_ST_TEST_IN                0xA2
+
+#define CPIA2_VC_ST_TEST_OUT               0xA3
+
+#define CPIA2_VC_ST_STATUS                 0xA4
+#define CPIA2_VC_ST_STATUS_EMPTY        0x01
+#define CPIA2_VC_ST_STATUS_FULL         0x02
+
+#define CPIA2_VC_ST_FRAME_DETECT_1         0xA5
+
+#define CPIA2_VC_ST_FRAME_DETECT_2         0xA6
+
+#define CPIA2_VC_USB_CTRL                    0xA8
+#define CPIA2_VC_USB_CTRL_CMD_STALLED      0x01
+#define CPIA2_VC_USB_CTRL_CMD_READY        0x02
+#define CPIA2_VC_USB_CTRL_CMD_STATUS       0x04
+#define CPIA2_VC_USB_CTRL_CMD_STATUS_DIR   0x08
+#define CPIA2_VC_USB_CTRL_CMD_NO_CLASH     0x10
+#define CPIA2_VC_USB_CTRL_CMD_MICRO_ACCESS 0x80
+
+#define CPIA2_VC_USB_STRM                  0xA9
+#define CPIA2_VC_USB_STRM_ISO_ENABLE    0x01
+#define CPIA2_VC_USB_STRM_BLK_ENABLE    0x02
+#define CPIA2_VC_USB_STRM_INT_ENABLE    0x04
+#define CPIA2_VC_USB_STRM_AUD_ENABLE    0x08
+
+#define CPIA2_VC_USB_STATUS                   0xAA
+#define CPIA2_VC_USB_STATUS_CMD_IN_PROGRESS  0x01
+#define CPIA2_VC_USB_STATUS_CMD_STATUS_STALL 0x02
+#define CPIA2_VC_USB_STATUS_CMD_HANDSHAKE    0x04
+#define CPIA2_VC_USB_STATUS_CMD_OVERRIDE     0x08
+#define CPIA2_VC_USB_STATUS_CMD_FIFO_BUSY    0x10
+#define CPIA2_VC_USB_STATUS_BULK_REPEAT_TXN  0x20
+#define CPIA2_VC_USB_STATUS_CONFIG_DONE      0x40
+#define CPIA2_VC_USB_STATUS_USB_SUSPEND      0x80
+
+#define CPIA2_VC_USB_CMDW                   0xAB
+
+#define CPIA2_VC_USB_DATARW                 0xAC
+
+#define CPIA2_VC_USB_INFO                   0xAD
+
+#define CPIA2_VC_USB_CONFIG                 0xAE
+
+#define CPIA2_VC_USB_SETTINGS                  0xAF
+#define CPIA2_VC_USB_SETTINGS_CONFIG_MASK    0x03
+#define CPIA2_VC_USB_SETTINGS_INTERFACE_MASK 0x0C
+#define CPIA2_VC_USB_SETTINGS_ALTERNATE_MASK 0x70
+
+#define CPIA2_VC_USB_ISOLIM                  0xB0
+
+#define CPIA2_VC_USB_ISOFAILS                0xB1
+
+#define CPIA2_VC_USB_ISOMAXPKTHI             0xB2
+
+#define CPIA2_VC_USB_ISOMAXPKTLO             0xB3
+
+#define CPIA2_VC_V2W_CTRL                    0xB8
+#define CPIA2_VC_V2W_SELECT               0x01
+
+#define CPIA2_VC_V2W_SCL                     0xB9
+
+#define CPIA2_VC_V2W_SDA                     0xBA
+
+#define CPIA2_VC_VC_CTRL                     0xC0
+#define CPIA2_VC_VC_CTRL_RUN              0x01
+#define CPIA2_VC_VC_CTRL_SINGLESHOT       0x02
+#define CPIA2_VC_VC_CTRL_IDLING           0x04
+#define CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES 0x10
+#define CPIA2_VC_VC_CTRL_INHIBIT_Q_TABLES 0x20
+#define CPIA2_VC_VC_CTRL_INHIBIT_PRIVATE  0x40
+
+#define CPIA2_VC_VC_RESTART_IVAL_HI          0xC1
+
+#define CPIA2_VC_VC_RESTART_IVAL_LO          0xC2
+
+#define CPIA2_VC_VC_FORMAT                   0xC3
+#define CPIA2_VC_VC_FORMAT_UFIRST         0x01
+#define CPIA2_VC_VC_FORMAT_MONO           0x02
+#define CPIA2_VC_VC_FORMAT_DECIMATING     0x04
+#define CPIA2_VC_VC_FORMAT_SHORTLINE      0x08
+#define CPIA2_VC_VC_FORMAT_SELFTEST       0x10
+
+#define CPIA2_VC_VC_CLOCKS                         0xC4
+#define CPIA2_VC_VC_CLOCKS_CLKDIV_MASK        0x03
+#define CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3   0x04
+#define CPIA2_VC_VC_672_CLOCKS_SCALING        0x08
+#define CPIA2_VC_VC_CLOCKS_LOGDIV0        0x00
+#define CPIA2_VC_VC_CLOCKS_LOGDIV1        0x01
+#define CPIA2_VC_VC_CLOCKS_LOGDIV2        0x02
+#define CPIA2_VC_VC_CLOCKS_LOGDIV3        0x03
+#define CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3   0x08
+#define CPIA2_VC_VC_676_CLOCKS_SCALING	      0x10
+
+#define CPIA2_VC_VC_IHSIZE_LO                0xC5
+
+#define CPIA2_VC_VC_XLIM_HI                  0xC6
+
+#define CPIA2_VC_VC_XLIM_LO                  0xC7
+
+#define CPIA2_VC_VC_YLIM_HI                  0xC8
+
+#define CPIA2_VC_VC_YLIM_LO                  0xC9
+
+#define CPIA2_VC_VC_OHSIZE                   0xCA
+
+#define CPIA2_VC_VC_OVSIZE                   0xCB
+
+#define CPIA2_VC_VC_HCROP                    0xCC
+
+#define CPIA2_VC_VC_VCROP                    0xCD
+
+#define CPIA2_VC_VC_HPHASE                   0xCE
+
+#define CPIA2_VC_VC_VPHASE                   0xCF
+
+#define CPIA2_VC_VC_HISPAN                   0xD0
+
+#define CPIA2_VC_VC_VISPAN                   0xD1
+
+#define CPIA2_VC_VC_HICROP                   0xD2
+
+#define CPIA2_VC_VC_VICROP                   0xD3
+
+#define CPIA2_VC_VC_HFRACT                   0xD4
+#define CPIA2_VC_VC_HFRACT_DEN_MASK       0x0F
+#define CPIA2_VC_VC_HFRACT_NUM_MASK       0xF0
+
+#define CPIA2_VC_VC_VFRACT                   0xD5
+#define CPIA2_VC_VC_VFRACT_DEN_MASK       0x0F
+#define CPIA2_VC_VC_VFRACT_NUM_MASK       0xF0
+
+#define CPIA2_VC_VC_JPEG_OPT                      0xD6
+#define CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE     0x01
+#define CPIA2_VC_VC_JPEG_OPT_NO_DC_AUTO_SQUEEZE 0x02
+#define CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE       0x04
+#define CPIA2_VC_VC_JPEG_OPT_DEFAULT      (CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE|\
+					   CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE)
+
+
+#define CPIA2_VC_VC_CREEP_PERIOD             0xD7
+#define CPIA2_VC_VC_USER_SQUEEZE             0xD8
+#define CPIA2_VC_VC_TARGET_KB                0xD9
+
+#define CPIA2_VC_VC_AUTO_SQUEEZE             0xE6
+
+
+/***
+ * VP register set (Bank 2)
+ ***/
+#define CPIA2_VP_DEVICEH                             0
+#define CPIA2_VP_DEVICEL                             1
+
+#define CPIA2_VP_SYSTEMSTATE                         0x02
+#define CPIA2_VP_SYSTEMSTATE_HK_ALIVE             0x01
+
+#define CPIA2_VP_SYSTEMCTRL                          0x03
+#define CPIA2_VP_SYSTEMCTRL_REQ_CLEAR_ERROR       0x80
+#define CPIA2_VP_SYSTEMCTRL_POWER_DOWN_PLL        0x20
+#define CPIA2_VP_SYSTEMCTRL_REQ_SUSPEND_STATE     0x10
+#define CPIA2_VP_SYSTEMCTRL_REQ_SERIAL_WAKEUP     0x08
+#define CPIA2_VP_SYSTEMCTRL_REQ_AUTOLOAD          0x04
+#define CPIA2_VP_SYSTEMCTRL_HK_CONTROL            0x02
+#define CPIA2_VP_SYSTEMCTRL_POWER_CONTROL         0x01
+
+#define CPIA2_VP_SENSOR_FLAGS                        0x05
+#define CPIA2_VP_SENSOR_FLAGS_404                 0x01
+#define CPIA2_VP_SENSOR_FLAGS_407                 0x02
+#define CPIA2_VP_SENSOR_FLAGS_409                 0x04
+#define CPIA2_VP_SENSOR_FLAGS_410                 0x08
+#define CPIA2_VP_SENSOR_FLAGS_500                 0x10
+
+#define CPIA2_VP_SENSOR_REV                          0x06
+
+#define CPIA2_VP_DEVICE_CONFIG                       0x07
+#define CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE      0x01
+
+#define CPIA2_VP_GPIO_DIRECTION                      0x08
+#define CPIA2_VP_GPIO_READ                        0xFF
+#define CPIA2_VP_GPIO_WRITE                       0x00
+
+#define CPIA2_VP_GPIO_DATA                           0x09
+
+#define CPIA2_VP_RAM_ADDR_H                          0x0A
+#define CPIA2_VP_RAM_ADDR_L                          0x0B
+#define CPIA2_VP_RAM_DATA                            0x0C
+
+#define CPIA2_VP_PATCH_REV                           0x0F
+
+#define CPIA2_VP4_USER_MODE                           0x10
+#define CPIA2_VP5_USER_MODE                           0x13
+#define CPIA2_VP_USER_MODE_CIF                    0x01
+#define CPIA2_VP_USER_MODE_QCIFDS                 0x02
+#define CPIA2_VP_USER_MODE_QCIFPTC                0x04
+#define CPIA2_VP_USER_MODE_QVGADS                 0x08
+#define CPIA2_VP_USER_MODE_QVGAPTC                0x10
+#define CPIA2_VP_USER_MODE_VGA                    0x20
+
+#define CPIA2_VP4_FRAMERATE_REQUEST                    0x11
+#define CPIA2_VP5_FRAMERATE_REQUEST                    0x14
+#define CPIA2_VP_FRAMERATE_60                     0x80
+#define CPIA2_VP_FRAMERATE_50                     0x40
+#define CPIA2_VP_FRAMERATE_30                     0x20
+#define CPIA2_VP_FRAMERATE_25                     0x10
+#define CPIA2_VP_FRAMERATE_15                     0x08
+#define CPIA2_VP_FRAMERATE_12_5                   0x04
+#define CPIA2_VP_FRAMERATE_7_5                    0x02
+#define CPIA2_VP_FRAMERATE_6_25                   0x01
+
+#define CPIA2_VP4_USER_EFFECTS                         0x12
+#define CPIA2_VP5_USER_EFFECTS                         0x15
+#define CPIA2_VP_USER_EFFECTS_COLBARS             0x01
+#define CPIA2_VP_USER_EFFECTS_COLBARS_GRAD        0x02
+#define CPIA2_VP_USER_EFFECTS_MIRROR              0x04
+#define CPIA2_VP_USER_EFFECTS_FLIP                0x40  // VP5 only
+
+/* NOTE: CPIA2_VP_EXPOSURE_MODES shares the same register as VP5 User
+ * Effects */
+#define CPIA2_VP_EXPOSURE_MODES                       0x15
+#define CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER   0x20
+#define CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP       0x10
+
+#define CPIA2_VP4_EXPOSURE_TARGET                     0x16    // VP4
+#define CPIA2_VP5_EXPOSURE_TARGET		      0x20    // VP5
+
+#define CPIA2_VP_FLICKER_MODES                        0x1B
+#define CPIA2_VP_FLICKER_MODES_50HZ               0x80
+#define CPIA2_VP_FLICKER_MODES_CUSTOM_FLT_FFREQ   0x40
+#define CPIA2_VP_FLICKER_MODES_NEVER_FLICKER      0x20
+#define CPIA2_VP_FLICKER_MODES_INHIBIT_RUB        0x10
+#define CPIA2_VP_FLICKER_MODES_ADJUST_LINE_FREQ   0x08
+#define CPIA2_VP_FLICKER_MODES_CUSTOM_INT_FFREQ   0x04
+
+#define CPIA2_VP_UMISC                                0x1D
+#define CPIA2_VP_UMISC_FORCE_MONO                 0x80
+#define CPIA2_VP_UMISC_FORCE_ID_MASK              0x40
+#define CPIA2_VP_UMISC_INHIBIT_AUTO_FGS           0x20
+#define CPIA2_VP_UMISC_INHIBIT_AUTO_DIMS          0x08
+#define CPIA2_VP_UMISC_OPT_FOR_SENSOR_DS          0x04
+#define CPIA2_VP_UMISC_INHIBIT_AUTO_MODE_INT      0x02
+
+#define CPIA2_VP5_ANTIFLKRSETUP                       0x22  //34
+
+#define CPIA2_VP_INTERPOLATION                        0x24
+#define CPIA2_VP_INTERPOLATION_EVEN_FIRST         0x40
+#define CPIA2_VP_INTERPOLATION_HJOG               0x20
+#define CPIA2_VP_INTERPOLATION_VJOG               0x10
+
+#define CPIA2_VP_GAMMA                                0x25
+#define CPIA2_VP_DEFAULT_GAMMA                    0x10
+
+#define CPIA2_VP_YRANGE                               0x26
+
+#define CPIA2_VP_SATURATION                           0x27
+
+#define CPIA2_VP5_MYBLACK_LEVEL                       0x3A   //58
+#define CPIA2_VP5_MCYRANGE                            0x3B   //59
+#define CPIA2_VP5_MYCEILING                           0x3C   //60
+#define CPIA2_VP5_MCUVSATURATION                      0x3D   //61
+
+
+#define CPIA2_VP_REHASH_VALUES                        0x60
+
+
+/***
+ * Common sensor registers
+ ***/
+#define CPIA2_SENSOR_DEVICE_H                         0x00
+#define CPIA2_SENSOR_DEVICE_L                         0x01
+
+#define CPIA2_SENSOR_DATA_FORMAT                      0x16
+#define CPIA2_SENSOR_DATA_FORMAT_HMIRROR      0x08
+#define CPIA2_SENSOR_DATA_FORMAT_VMIRROR      0x10
+
+#define CPIA2_SENSOR_CR1                              0x76
+#define CPIA2_SENSOR_CR1_STAND_BY             0x01
+#define CPIA2_SENSOR_CR1_DOWN_RAMP_GEN        0x02
+#define CPIA2_SENSOR_CR1_DOWN_COLUMN_ADC      0x04
+#define CPIA2_SENSOR_CR1_DOWN_CAB_REGULATOR   0x08
+#define CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR 0x10
+#define CPIA2_SENSOR_CR1_DOWN_VRT_AMP         0x20
+#define CPIA2_SENSOR_CR1_DOWN_BAND_GAP        0x40
+
+#endif
diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c
new file mode 100644
index 0000000..95b5d6e
--- /dev/null
+++ b/drivers/media/usb/cpia2/cpia2_usb.c
@@ -0,0 +1,955 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2_usb.c
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *      Contact:  steve.miller@st.com
+ *
+ *  Description:
+ *     This is a USB driver for CPia2 based video cameras.
+ *     The infrastructure of this driver is based on the cpia usb driver by
+ *     Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Stripped of 2.4 stuff ready for main kernel submit by
+ *		Alan Cox <alan@lxorguk.ukuu.org.uk>
+ ****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/module.h>
+
+#include "cpia2.h"
+
+static int frame_sizes[] = {
+	0,	// USBIF_CMDONLY
+	0, 	// USBIF_BULK
+	128, 	// USBIF_ISO_1
+	384, 	// USBIF_ISO_2
+	640, 	// USBIF_ISO_3
+	768, 	// USBIF_ISO_4
+	896, 	// USBIF_ISO_5
+	1023, 	// USBIF_ISO_6
+};
+
+#define FRAMES_PER_DESC    10
+#define FRAME_SIZE_PER_DESC   frame_sizes[cam->cur_alt]
+
+static void process_frame(struct camera_data *cam);
+static void cpia2_usb_complete(struct urb *urb);
+static int cpia2_usb_probe(struct usb_interface *intf,
+			   const struct usb_device_id *id);
+static void cpia2_usb_disconnect(struct usb_interface *intf);
+static int cpia2_usb_suspend(struct usb_interface *intf, pm_message_t message);
+static int cpia2_usb_resume(struct usb_interface *intf);
+
+static void free_sbufs(struct camera_data *cam);
+static void add_APPn(struct camera_data *cam);
+static void add_COM(struct camera_data *cam);
+static int submit_urbs(struct camera_data *cam);
+static int set_alternate(struct camera_data *cam, unsigned int alt);
+static int configure_transfer_mode(struct camera_data *cam, unsigned int alt);
+
+static struct usb_device_id cpia2_id_table[] = {
+	{USB_DEVICE(0x0553, 0x0100)},
+	{USB_DEVICE(0x0553, 0x0140)},
+	{USB_DEVICE(0x0553, 0x0151)},  /* STV0676 */
+	{}			/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, cpia2_id_table);
+
+static struct usb_driver cpia2_driver = {
+	.name		= "cpia2",
+	.probe		= cpia2_usb_probe,
+	.disconnect	= cpia2_usb_disconnect,
+	.suspend	= cpia2_usb_suspend,
+	.resume		= cpia2_usb_resume,
+	.reset_resume	= cpia2_usb_resume,
+	.id_table	= cpia2_id_table
+};
+
+
+/******************************************************************************
+ *
+ *  process_frame
+ *
+ *****************************************************************************/
+static void process_frame(struct camera_data *cam)
+{
+	static int frame_count;
+
+	unsigned char *inbuff = cam->workbuff->data;
+
+	DBG("Processing frame #%d, current:%d\n",
+	    cam->workbuff->num, cam->curbuff->num);
+
+	if(cam->workbuff->length > cam->workbuff->max_length)
+		cam->workbuff->max_length = cam->workbuff->length;
+
+	if ((inbuff[0] == 0xFF) && (inbuff[1] == 0xD8)) {
+		frame_count++;
+	} else {
+		cam->workbuff->status = FRAME_ERROR;
+		DBG("Start of frame not found\n");
+		return;
+	}
+
+	/***
+	 * Now the output buffer should have a JPEG image in it.
+	 ***/
+	if(!cam->first_image_seen) {
+		/* Always skip the first image after streaming
+		 * starts. It is almost certainly corrupt. */
+		cam->first_image_seen = 1;
+		cam->workbuff->status = FRAME_EMPTY;
+		return;
+	}
+	if (cam->workbuff->length > 3) {
+		if(cam->mmapped &&
+		   cam->workbuff->length < cam->workbuff->max_length) {
+			/* No junk in the buffers */
+			memset(cam->workbuff->data+cam->workbuff->length,
+			       0, cam->workbuff->max_length-
+				  cam->workbuff->length);
+		}
+		cam->workbuff->max_length = cam->workbuff->length;
+		cam->workbuff->status = FRAME_READY;
+
+		if(!cam->mmapped && cam->num_frames > 2) {
+			/* During normal reading, the most recent
+			 * frame will be read.  If the current frame
+			 * hasn't started reading yet, it will never
+			 * be read, so mark it empty.  If the buffer is
+			 * mmapped, or we have few buffers, we need to
+			 * wait for the user to free the buffer.
+			 *
+			 * NOTE: This is not entirely foolproof with 3
+			 * buffers, but it would take an EXTREMELY
+			 * overloaded system to cause problems (possible
+			 * image data corruption).  Basically, it would
+			 * need to take more time to execute cpia2_read
+			 * than it would for the camera to send
+			 * cam->num_frames-2 frames before problems
+			 * could occur.
+			 */
+			cam->curbuff->status = FRAME_EMPTY;
+		}
+		cam->curbuff = cam->workbuff;
+		cam->workbuff = cam->workbuff->next;
+		DBG("Changed buffers, work:%d, current:%d\n",
+		    cam->workbuff->num, cam->curbuff->num);
+		return;
+	} else {
+		DBG("Not enough data for an image.\n");
+	}
+
+	cam->workbuff->status = FRAME_ERROR;
+	return;
+}
+
+/******************************************************************************
+ *
+ *  add_APPn
+ *
+ *  Adds a user specified APPn record
+ *****************************************************************************/
+static void add_APPn(struct camera_data *cam)
+{
+	if(cam->APP_len > 0) {
+		cam->workbuff->data[cam->workbuff->length++] = 0xFF;
+		cam->workbuff->data[cam->workbuff->length++] = 0xE0+cam->APPn;
+		cam->workbuff->data[cam->workbuff->length++] = 0;
+		cam->workbuff->data[cam->workbuff->length++] = cam->APP_len+2;
+		memcpy(cam->workbuff->data+cam->workbuff->length,
+		       cam->APP_data, cam->APP_len);
+		cam->workbuff->length += cam->APP_len;
+	}
+}
+
+/******************************************************************************
+ *
+ *  add_COM
+ *
+ *  Adds a user specified COM record
+ *****************************************************************************/
+static void add_COM(struct camera_data *cam)
+{
+	if(cam->COM_len > 0) {
+		cam->workbuff->data[cam->workbuff->length++] = 0xFF;
+		cam->workbuff->data[cam->workbuff->length++] = 0xFE;
+		cam->workbuff->data[cam->workbuff->length++] = 0;
+		cam->workbuff->data[cam->workbuff->length++] = cam->COM_len+2;
+		memcpy(cam->workbuff->data+cam->workbuff->length,
+		       cam->COM_data, cam->COM_len);
+		cam->workbuff->length += cam->COM_len;
+	}
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_complete
+ *
+ *  callback when incoming packet is received
+ *****************************************************************************/
+static void cpia2_usb_complete(struct urb *urb)
+{
+	int i;
+	unsigned char *cdata;
+	static int frame_ready = false;
+	struct camera_data *cam = (struct camera_data *) urb->context;
+
+	if (urb->status!=0) {
+		if (!(urb->status == -ENOENT ||
+		      urb->status == -ECONNRESET ||
+		      urb->status == -ESHUTDOWN))
+		{
+			DBG("urb->status = %d!\n", urb->status);
+		}
+		DBG("Stopping streaming\n");
+		return;
+	}
+
+	if (!cam->streaming || !video_is_registered(&cam->vdev)) {
+		LOG("Will now stop the streaming: streaming = %d, present=%d\n",
+		    cam->streaming, video_is_registered(&cam->vdev));
+		return;
+	}
+
+	/***
+	 * Packet collater
+	 ***/
+	//DBG("Collating %d packets\n", urb->number_of_packets);
+	for (i = 0; i < urb->number_of_packets; i++) {
+		u16 checksum, iso_checksum;
+		int j;
+		int n = urb->iso_frame_desc[i].actual_length;
+		int st = urb->iso_frame_desc[i].status;
+
+		if(cam->workbuff->status == FRAME_READY) {
+			struct framebuf *ptr;
+			/* Try to find an available buffer */
+			DBG("workbuff full, searching\n");
+			for (ptr = cam->workbuff->next;
+			     ptr != cam->workbuff;
+			     ptr = ptr->next)
+			{
+				if (ptr->status == FRAME_EMPTY) {
+					ptr->status = FRAME_READING;
+					ptr->length = 0;
+					break;
+				}
+			}
+			if (ptr == cam->workbuff)
+				break; /* No READING or EMPTY buffers left */
+
+			cam->workbuff = ptr;
+		}
+
+		if (cam->workbuff->status == FRAME_EMPTY ||
+		    cam->workbuff->status == FRAME_ERROR) {
+			cam->workbuff->status = FRAME_READING;
+			cam->workbuff->length = 0;
+		}
+
+		//DBG("   Packet %d length = %d, status = %d\n", i, n, st);
+		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+		if (st) {
+			LOG("cpia2 data error: [%d] len=%d, status = %d\n",
+			    i, n, st);
+			if(!ALLOW_CORRUPT)
+				cam->workbuff->status = FRAME_ERROR;
+			continue;
+		}
+
+		if(n<=2)
+			continue;
+
+		checksum = 0;
+		for(j=0; j<n-2; ++j)
+			checksum += cdata[j];
+		iso_checksum = cdata[j] + cdata[j+1]*256;
+		if(checksum != iso_checksum) {
+			LOG("checksum mismatch: [%d] len=%d, calculated = %x, checksum = %x\n",
+			    i, n, (int)checksum, (int)iso_checksum);
+			if(!ALLOW_CORRUPT) {
+				cam->workbuff->status = FRAME_ERROR;
+				continue;
+			}
+		}
+		n -= 2;
+
+		if(cam->workbuff->status != FRAME_READING) {
+			if((0xFF == cdata[0] && 0xD8 == cdata[1]) ||
+			   (0xD8 == cdata[0] && 0xFF == cdata[1] &&
+			    0 != cdata[2])) {
+				/* frame is skipped, but increment total
+				 * frame count anyway */
+				cam->frame_count++;
+			}
+			DBG("workbuff not reading, status=%d\n",
+			    cam->workbuff->status);
+			continue;
+		}
+
+		if (cam->frame_size < cam->workbuff->length + n) {
+			ERR("buffer overflow! length: %d, n: %d\n",
+			    cam->workbuff->length, n);
+			cam->workbuff->status = FRAME_ERROR;
+			if(cam->workbuff->length > cam->workbuff->max_length)
+				cam->workbuff->max_length =
+					cam->workbuff->length;
+			continue;
+		}
+
+		if (cam->workbuff->length == 0) {
+			int data_offset;
+			if ((0xD8 == cdata[0]) && (0xFF == cdata[1])) {
+				data_offset = 1;
+			} else if((0xFF == cdata[0]) && (0xD8 == cdata[1])
+				  && (0xFF == cdata[2])) {
+				data_offset = 2;
+			} else {
+				DBG("Ignoring packet, not beginning!\n");
+				continue;
+			}
+			DBG("Start of frame pattern found\n");
+			do_gettimeofday(&cam->workbuff->timestamp);
+			cam->workbuff->seq = cam->frame_count++;
+			cam->workbuff->data[0] = 0xFF;
+			cam->workbuff->data[1] = 0xD8;
+			cam->workbuff->length = 2;
+			add_APPn(cam);
+			add_COM(cam);
+			memcpy(cam->workbuff->data+cam->workbuff->length,
+			       cdata+data_offset, n-data_offset);
+			cam->workbuff->length += n-data_offset;
+		} else if (cam->workbuff->length > 0) {
+			memcpy(cam->workbuff->data + cam->workbuff->length,
+			       cdata, n);
+			cam->workbuff->length += n;
+		}
+
+		if ((cam->workbuff->length >= 3) &&
+		    (cam->workbuff->data[cam->workbuff->length - 3] == 0xFF) &&
+		    (cam->workbuff->data[cam->workbuff->length - 2] == 0xD9) &&
+		    (cam->workbuff->data[cam->workbuff->length - 1] == 0xFF)) {
+			frame_ready = true;
+			cam->workbuff->data[cam->workbuff->length - 1] = 0;
+			cam->workbuff->length -= 1;
+		} else if ((cam->workbuff->length >= 2) &&
+		   (cam->workbuff->data[cam->workbuff->length - 2] == 0xFF) &&
+		   (cam->workbuff->data[cam->workbuff->length - 1] == 0xD9)) {
+			frame_ready = true;
+		}
+
+		if (frame_ready) {
+			DBG("Workbuff image size = %d\n",cam->workbuff->length);
+			process_frame(cam);
+
+			frame_ready = false;
+
+			if (waitqueue_active(&cam->wq_stream))
+				wake_up_interruptible(&cam->wq_stream);
+		}
+	}
+
+	if(cam->streaming) {
+		/* resubmit */
+		urb->dev = cam->dev;
+		if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
+			ERR("%s: usb_submit_urb ret %d!\n", __func__, i);
+	}
+}
+
+/******************************************************************************
+ *
+ * configure_transfer_mode
+ *
+ *****************************************************************************/
+static int configure_transfer_mode(struct camera_data *cam, unsigned int alt)
+{
+	static unsigned char iso_regs[8][4] = {
+		{0x00, 0x00, 0x00, 0x00},
+		{0x00, 0x00, 0x00, 0x00},
+		{0xB9, 0x00, 0x00, 0x7E},
+		{0xB9, 0x00, 0x01, 0x7E},
+		{0xB9, 0x00, 0x02, 0x7E},
+		{0xB9, 0x00, 0x02, 0xFE},
+		{0xB9, 0x00, 0x03, 0x7E},
+		{0xB9, 0x00, 0x03, 0xFD}
+	};
+	struct cpia2_command cmd;
+	unsigned char reg;
+
+	if (!video_is_registered(&cam->vdev))
+		return -ENODEV;
+
+	/***
+	 * Write the isoc registers according to the alternate selected
+	 ***/
+	cmd.direction = TRANSFER_WRITE;
+	cmd.buffer.block_data[0] = iso_regs[alt][0];
+	cmd.buffer.block_data[1] = iso_regs[alt][1];
+	cmd.buffer.block_data[2] = iso_regs[alt][2];
+	cmd.buffer.block_data[3] = iso_regs[alt][3];
+	cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+	cmd.start = CPIA2_VC_USB_ISOLIM;
+	cmd.reg_count = 4;
+	cpia2_send_command(cam, &cmd);
+
+	/***
+	 * Enable relevant streams before starting polling.
+	 * First read USB Stream Config Register.
+	 ***/
+	cmd.direction = TRANSFER_READ;
+	cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+	cmd.start = CPIA2_VC_USB_STRM;
+	cmd.reg_count = 1;
+	cpia2_send_command(cam, &cmd);
+	reg = cmd.buffer.block_data[0];
+
+	/* Clear iso, bulk, and int */
+	reg &= ~(CPIA2_VC_USB_STRM_BLK_ENABLE |
+		 CPIA2_VC_USB_STRM_ISO_ENABLE |
+		 CPIA2_VC_USB_STRM_INT_ENABLE);
+
+	if (alt == USBIF_BULK) {
+		DBG("Enabling bulk xfer\n");
+		reg |= CPIA2_VC_USB_STRM_BLK_ENABLE;	/* Enable Bulk */
+		cam->xfer_mode = XFER_BULK;
+	} else if (alt >= USBIF_ISO_1) {
+		DBG("Enabling ISOC xfer\n");
+		reg |= CPIA2_VC_USB_STRM_ISO_ENABLE;
+		cam->xfer_mode = XFER_ISOC;
+	}
+
+	cmd.buffer.block_data[0] = reg;
+	cmd.direction = TRANSFER_WRITE;
+	cmd.start = CPIA2_VC_USB_STRM;
+	cmd.reg_count = 1;
+	cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+	cpia2_send_command(cam, &cmd);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_usb_change_streaming_alternate
+ *
+ *****************************************************************************/
+int cpia2_usb_change_streaming_alternate(struct camera_data *cam,
+					 unsigned int alt)
+{
+	int ret = 0;
+
+	if(alt < USBIF_ISO_1 || alt > USBIF_ISO_6)
+		return -EINVAL;
+
+	if(alt == cam->params.camera_state.stream_mode)
+		return 0;
+
+	cpia2_usb_stream_pause(cam);
+
+	configure_transfer_mode(cam, alt);
+
+	cam->params.camera_state.stream_mode = alt;
+
+	/* Reset the camera to prevent image quality degradation */
+	cpia2_reset_camera(cam);
+
+	cpia2_usb_stream_resume(cam);
+
+	return ret;
+}
+
+/******************************************************************************
+ *
+ * set_alternate
+ *
+ *****************************************************************************/
+static int set_alternate(struct camera_data *cam, unsigned int alt)
+{
+	int ret = 0;
+
+	if(alt == cam->cur_alt)
+		return 0;
+
+	if (cam->cur_alt != USBIF_CMDONLY) {
+		DBG("Changing from alt %d to %d\n", cam->cur_alt, USBIF_CMDONLY);
+		ret = usb_set_interface(cam->dev, cam->iface, USBIF_CMDONLY);
+		if (ret != 0)
+			return ret;
+	}
+	if (alt != USBIF_CMDONLY) {
+		DBG("Changing from alt %d to %d\n", USBIF_CMDONLY, alt);
+		ret = usb_set_interface(cam->dev, cam->iface, alt);
+		if (ret != 0)
+			return ret;
+	}
+
+	cam->old_alt = cam->cur_alt;
+	cam->cur_alt = alt;
+
+	return ret;
+}
+
+/******************************************************************************
+ *
+ * free_sbufs
+ *
+ * Free all cam->sbuf[]. All non-NULL .data and .urb members that are non-NULL
+ * are assumed to be allocated. Non-NULL .urb members are also assumed to be
+ * submitted (and must therefore be killed before they are freed).
+ *****************************************************************************/
+static void free_sbufs(struct camera_data *cam)
+{
+	int i;
+
+	for (i = 0; i < NUM_SBUF; i++) {
+		if(cam->sbuf[i].urb) {
+			usb_kill_urb(cam->sbuf[i].urb);
+			usb_free_urb(cam->sbuf[i].urb);
+			cam->sbuf[i].urb = NULL;
+		}
+		if(cam->sbuf[i].data) {
+			kfree(cam->sbuf[i].data);
+			cam->sbuf[i].data = NULL;
+		}
+	}
+}
+
+/*******
+* Convenience functions
+*******/
+/****************************************************************************
+ *
+ *  write_packet
+ *
+ ***************************************************************************/
+static int write_packet(struct usb_device *udev,
+			u8 request, u8 * registers, u16 start, size_t size)
+{
+	if (!registers || size <= 0)
+		return -EINVAL;
+
+	return usb_control_msg(udev,
+			       usb_sndctrlpipe(udev, 0),
+			       request,
+			       USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			       start,	/* value */
+			       0,	/* index */
+			       registers,	/* buffer */
+			       size,
+			       HZ);
+}
+
+/****************************************************************************
+ *
+ *  read_packet
+ *
+ ***************************************************************************/
+static int read_packet(struct usb_device *udev,
+		       u8 request, u8 * registers, u16 start, size_t size)
+{
+	if (!registers || size <= 0)
+		return -EINVAL;
+
+	return usb_control_msg(udev,
+			       usb_rcvctrlpipe(udev, 0),
+			       request,
+			       USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE,
+			       start,	/* value */
+			       0,	/* index */
+			       registers,	/* buffer */
+			       size,
+			       HZ);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_transfer_cmd
+ *
+ *****************************************************************************/
+int cpia2_usb_transfer_cmd(struct camera_data *cam,
+			   void *registers,
+			   u8 request, u8 start, u8 count, u8 direction)
+{
+	int err = 0;
+	struct usb_device *udev = cam->dev;
+
+	if (!udev) {
+		ERR("%s: Internal driver error: udev is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!registers) {
+		ERR("%s: Internal driver error: register array is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if (direction == TRANSFER_READ) {
+		err = read_packet(udev, request, (u8 *)registers, start, count);
+		if (err > 0)
+			err = 0;
+	} else if (direction == TRANSFER_WRITE) {
+		err =write_packet(udev, request, (u8 *)registers, start, count);
+		if (err < 0) {
+			LOG("Control message failed, err val = %d\n", err);
+			LOG("Message: request = 0x%0X, start = 0x%0X\n",
+			    request, start);
+			LOG("Message: count = %d, register[0] = 0x%0X\n",
+			    count, ((unsigned char *) registers)[0]);
+		} else
+			err=0;
+	} else {
+		LOG("Unexpected first byte of direction: %d\n",
+		       direction);
+		return -EINVAL;
+	}
+
+	if(err != 0)
+		LOG("Unexpected error: %d\n", err);
+	return err;
+}
+
+
+/******************************************************************************
+ *
+ *  submit_urbs
+ *
+ *****************************************************************************/
+static int submit_urbs(struct camera_data *cam)
+{
+	struct urb *urb;
+	int fx, err, i, j;
+
+	for(i=0; i<NUM_SBUF; ++i) {
+		if (cam->sbuf[i].data)
+			continue;
+		cam->sbuf[i].data =
+		    kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+		if (!cam->sbuf[i].data) {
+			while (--i >= 0) {
+				kfree(cam->sbuf[i].data);
+				cam->sbuf[i].data = NULL;
+			}
+			return -ENOMEM;
+		}
+	}
+
+	/* We double buffer the Isoc lists, and also know the polling
+	 * interval is every frame (1 == (1 << (bInterval -1))).
+	 */
+	for(i=0; i<NUM_SBUF; ++i) {
+		if(cam->sbuf[i].urb) {
+			continue;
+		}
+		urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
+		if (!urb) {
+			ERR("%s: usb_alloc_urb error!\n", __func__);
+			for (j = 0; j < i; j++)
+				usb_free_urb(cam->sbuf[j].urb);
+			return -ENOMEM;
+		}
+
+		cam->sbuf[i].urb = urb;
+		urb->dev = cam->dev;
+		urb->context = cam;
+		urb->pipe = usb_rcvisocpipe(cam->dev, 1 /*ISOC endpoint*/);
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->transfer_buffer = cam->sbuf[i].data;
+		urb->complete = cpia2_usb_complete;
+		urb->number_of_packets = FRAMES_PER_DESC;
+		urb->interval = 1;
+		urb->transfer_buffer_length =
+			FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+
+		for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+			urb->iso_frame_desc[fx].offset =
+				FRAME_SIZE_PER_DESC * fx;
+			urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+		}
+	}
+
+
+	/* Queue the ISO urbs, and resubmit in the completion handler */
+	for(i=0; i<NUM_SBUF; ++i) {
+		err = usb_submit_urb(cam->sbuf[i].urb, GFP_KERNEL);
+		if (err) {
+			ERR("usb_submit_urb[%d]() = %d\n", i, err);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_stream_start
+ *
+ *****************************************************************************/
+int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate)
+{
+	int ret;
+	int old_alt;
+
+	if(cam->streaming)
+		return 0;
+
+	if (cam->flush) {
+		int i;
+		DBG("Flushing buffers\n");
+		for(i=0; i<cam->num_frames; ++i) {
+			cam->buffers[i].status = FRAME_EMPTY;
+			cam->buffers[i].length = 0;
+		}
+		cam->curbuff = &cam->buffers[0];
+		cam->workbuff = cam->curbuff->next;
+		cam->flush = false;
+	}
+
+	old_alt = cam->params.camera_state.stream_mode;
+	cam->params.camera_state.stream_mode = 0;
+	ret = cpia2_usb_change_streaming_alternate(cam, alternate);
+	if (ret < 0) {
+		int ret2;
+		ERR("cpia2_usb_change_streaming_alternate() = %d!\n", ret);
+		cam->params.camera_state.stream_mode = old_alt;
+		ret2 = set_alternate(cam, USBIF_CMDONLY);
+		if (ret2 < 0) {
+			ERR("cpia2_usb_change_streaming_alternate(%d) =%d has already "
+			    "failed. Then tried to call "
+			    "set_alternate(USBIF_CMDONLY) = %d.\n",
+			    alternate, ret, ret2);
+		}
+	} else {
+		cam->frame_count = 0;
+		cam->streaming = 1;
+		ret = cpia2_usb_stream_resume(cam);
+	}
+	return ret;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_stream_pause
+ *
+ *****************************************************************************/
+int cpia2_usb_stream_pause(struct camera_data *cam)
+{
+	int ret = 0;
+	if(cam->streaming) {
+		free_sbufs(cam);
+		ret = set_alternate(cam, USBIF_CMDONLY);
+	}
+	return ret;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_stream_resume
+ *
+ *****************************************************************************/
+int cpia2_usb_stream_resume(struct camera_data *cam)
+{
+	int ret = 0;
+	if(cam->streaming) {
+		cam->first_image_seen = 0;
+		ret = set_alternate(cam, cam->params.camera_state.stream_mode);
+		if(ret == 0) {
+			/* for some reason the user effects need to be set
+			   again when starting streaming. */
+			cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
+					cam->params.vp_params.user_effects);
+			ret = submit_urbs(cam);
+		}
+	}
+	return ret;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_stream_stop
+ *
+ *****************************************************************************/
+int cpia2_usb_stream_stop(struct camera_data *cam)
+{
+	int ret;
+
+	ret = cpia2_usb_stream_pause(cam);
+	cam->streaming = 0;
+	configure_transfer_mode(cam, 0);
+	return ret;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_probe
+ *
+ *  Probe and initialize.
+ *****************************************************************************/
+static int cpia2_usb_probe(struct usb_interface *intf,
+			   const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct usb_interface_descriptor *interface;
+	struct camera_data *cam;
+	int ret;
+
+	/* A multi-config CPiA2 camera? */
+	if (udev->descriptor.bNumConfigurations != 1)
+		return -ENODEV;
+	interface = &intf->cur_altsetting->desc;
+
+	/* If we get to this point, we found a CPiA2 camera */
+	LOG("CPiA2 USB camera found\n");
+
+	cam = cpia2_init_camera_struct(intf);
+	if (cam == NULL)
+		return -ENOMEM;
+
+	cam->dev = udev;
+	cam->iface = interface->bInterfaceNumber;
+
+	ret = set_alternate(cam, USBIF_CMDONLY);
+	if (ret < 0) {
+		ERR("%s: usb_set_interface error (ret = %d)\n", __func__, ret);
+		kfree(cam);
+		return ret;
+	}
+
+
+	if((ret = cpia2_init_camera(cam)) < 0) {
+		ERR("%s: failed to initialize cpia2 camera (ret = %d)\n", __func__, ret);
+		kfree(cam);
+		return ret;
+	}
+	LOG("  CPiA Version: %d.%02d (%d.%d)\n",
+	       cam->params.version.firmware_revision_hi,
+	       cam->params.version.firmware_revision_lo,
+	       cam->params.version.asic_id,
+	       cam->params.version.asic_rev);
+	LOG("  CPiA PnP-ID: %04x:%04x:%04x\n",
+	       cam->params.pnp_id.vendor,
+	       cam->params.pnp_id.product,
+	       cam->params.pnp_id.device_revision);
+	LOG("  SensorID: %d.(version %d)\n",
+	       cam->params.version.sensor_flags,
+	       cam->params.version.sensor_rev);
+
+	usb_set_intfdata(intf, cam);
+
+	ret = cpia2_register_camera(cam);
+	if (ret < 0) {
+		ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret);
+		kfree(cam);
+		return ret;
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_disconnect
+ *
+ *****************************************************************************/
+static void cpia2_usb_disconnect(struct usb_interface *intf)
+{
+	struct camera_data *cam = usb_get_intfdata(intf);
+	usb_set_intfdata(intf, NULL);
+
+	DBG("Stopping stream\n");
+	cpia2_usb_stream_stop(cam);
+
+	mutex_lock(&cam->v4l2_lock);
+	DBG("Unregistering camera\n");
+	cpia2_unregister_camera(cam);
+	v4l2_device_disconnect(&cam->v4l2_dev);
+	mutex_unlock(&cam->v4l2_lock);
+	v4l2_device_put(&cam->v4l2_dev);
+
+	if(cam->buffers) {
+		DBG("Wakeup waiting processes\n");
+		cam->curbuff->status = FRAME_READY;
+		cam->curbuff->length = 0;
+		if (waitqueue_active(&cam->wq_stream))
+			wake_up_interruptible(&cam->wq_stream);
+	}
+
+	DBG("Releasing interface\n");
+	usb_driver_release_interface(&cpia2_driver, intf);
+
+	LOG("CPiA2 camera disconnected.\n");
+}
+
+static int cpia2_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct camera_data *cam = usb_get_intfdata(intf);
+
+	mutex_lock(&cam->v4l2_lock);
+	if (cam->streaming) {
+		cpia2_usb_stream_stop(cam);
+		cam->streaming = 1;
+	}
+	mutex_unlock(&cam->v4l2_lock);
+
+	dev_info(&intf->dev, "going into suspend..\n");
+	return 0;
+}
+
+/* Resume device - start device. */
+static int cpia2_usb_resume(struct usb_interface *intf)
+{
+	struct camera_data *cam = usb_get_intfdata(intf);
+
+	mutex_lock(&cam->v4l2_lock);
+	v4l2_ctrl_handler_setup(&cam->hdl);
+	if (cam->streaming) {
+		cam->streaming = 0;
+		cpia2_usb_stream_start(cam,
+				cam->params.camera_state.stream_mode);
+	}
+	mutex_unlock(&cam->v4l2_lock);
+
+	dev_info(&intf->dev, "coming out of suspend..\n");
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  usb_cpia2_init
+ *
+ *****************************************************************************/
+int cpia2_usb_init(void)
+{
+	return usb_register(&cpia2_driver);
+}
+
+/******************************************************************************
+ *
+ *  usb_cpia_cleanup
+ *
+ *****************************************************************************/
+void cpia2_usb_cleanup(void)
+{
+	schedule_timeout(2 * HZ);
+	usb_deregister(&cpia2_driver);
+}
diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c
new file mode 100644
index 0000000..5ca6f44
--- /dev/null
+++ b/drivers/media/usb/cpia2/cpia2_v4l.c
@@ -0,0 +1,1267 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2_v4l.c
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *      Contact:  steve.miller@st.com
+ *  Copyright 2001,2005, Scott J. Bertin <scottbertin@yahoo.com>
+ *
+ *  Description:
+ *     This is a USB driver for CPia2 based video cameras.
+ *     The infrastructure of this driver is based on the cpia usb driver by
+ *     Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Stripped of 2.4 stuff ready for main kernel submit by
+ *		Alan Cox <alan@lxorguk.ukuu.org.uk>
+ ****************************************************************************/
+
+#define CPIA_VERSION "3.0.1"
+
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/videodev2.h>
+#include <linux/stringify.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+
+#include "cpia2.h"
+
+static int video_nr = -1;
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr, "video device to register (0=/dev/video0, etc)");
+
+static int buffer_size = 68 * 1024;
+module_param(buffer_size, int, 0);
+MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)");
+
+static int num_buffers = 3;
+module_param(num_buffers, int, 0);
+MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-"
+		 __stringify(VIDEO_MAX_FRAME) ", default 3)");
+
+static int alternate = DEFAULT_ALT;
+module_param(alternate, int, 0);
+MODULE_PARM_DESC(alternate, "USB Alternate (" __stringify(USBIF_ISO_1) "-"
+		 __stringify(USBIF_ISO_6) ", default "
+		 __stringify(DEFAULT_ALT) ")");
+
+static int flicker_mode;
+module_param(flicker_mode, int, 0);
+MODULE_PARM_DESC(flicker_mode, "Flicker frequency (0 (disabled), " __stringify(50) " or "
+		 __stringify(60) ", default 0)");
+
+MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>");
+MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras");
+MODULE_SUPPORTED_DEVICE("video");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CPIA_VERSION);
+
+#define ABOUT "V4L-Driver for Vision CPiA2 based cameras"
+#define CPIA2_CID_USB_ALT (V4L2_CID_USER_BASE | 0xf000)
+
+/******************************************************************************
+ *
+ *  cpia2_open
+ *
+ *****************************************************************************/
+static int cpia2_open(struct file *file)
+{
+	struct camera_data *cam = video_drvdata(file);
+	int retval;
+
+	if (mutex_lock_interruptible(&cam->v4l2_lock))
+		return -ERESTARTSYS;
+	retval = v4l2_fh_open(file);
+	if (retval)
+		goto open_unlock;
+
+	if (v4l2_fh_is_singular_file(file)) {
+		if (cpia2_allocate_buffers(cam)) {
+			v4l2_fh_release(file);
+			retval = -ENOMEM;
+			goto open_unlock;
+		}
+
+		/* reset the camera */
+		if (cpia2_reset_camera(cam) < 0) {
+			v4l2_fh_release(file);
+			retval = -EIO;
+			goto open_unlock;
+		}
+
+		cam->APP_len = 0;
+		cam->COM_len = 0;
+	}
+
+	cpia2_dbg_dump_registers(cam);
+open_unlock:
+	mutex_unlock(&cam->v4l2_lock);
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_close
+ *
+ *****************************************************************************/
+static int cpia2_close(struct file *file)
+{
+	struct video_device *dev = video_devdata(file);
+	struct camera_data *cam = video_get_drvdata(dev);
+
+	mutex_lock(&cam->v4l2_lock);
+	if (video_is_registered(&cam->vdev) && v4l2_fh_is_singular_file(file)) {
+		cpia2_usb_stream_stop(cam);
+
+		/* save camera state for later open */
+		cpia2_save_camera_state(cam);
+
+		cpia2_set_low_power(cam);
+		cpia2_free_buffers(cam);
+	}
+
+	if (cam->stream_fh == file->private_data) {
+		cam->stream_fh = NULL;
+		cam->mmapped = 0;
+	}
+	mutex_unlock(&cam->v4l2_lock);
+	return v4l2_fh_release(file);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_v4l_read
+ *
+ *****************************************************************************/
+static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
+			      loff_t *off)
+{
+	struct camera_data *cam = video_drvdata(file);
+	int noblock = file->f_flags&O_NONBLOCK;
+	ssize_t ret;
+
+	if(!cam)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&cam->v4l2_lock))
+		return -ERESTARTSYS;
+	ret = cpia2_read(cam, buf, count, noblock);
+	mutex_unlock(&cam->v4l2_lock);
+	return ret;
+}
+
+
+/******************************************************************************
+ *
+ *  cpia2_v4l_poll
+ *
+ *****************************************************************************/
+static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait)
+{
+	struct camera_data *cam = video_drvdata(filp);
+	unsigned int res;
+
+	mutex_lock(&cam->v4l2_lock);
+	res = cpia2_poll(cam, filp, wait);
+	mutex_unlock(&cam->v4l2_lock);
+	return res;
+}
+
+
+static int sync(struct camera_data *cam, int frame_nr)
+{
+	struct framebuf *frame = &cam->buffers[frame_nr];
+
+	while (1) {
+		if (frame->status == FRAME_READY)
+			return 0;
+
+		if (!cam->streaming) {
+			frame->status = FRAME_READY;
+			frame->length = 0;
+			return 0;
+		}
+
+		mutex_unlock(&cam->v4l2_lock);
+		wait_event_interruptible(cam->wq_stream,
+					 !cam->streaming ||
+					 frame->status == FRAME_READY);
+		mutex_lock(&cam->v4l2_lock);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+		if (!video_is_registered(&cam->vdev))
+			return -ENOTTY;
+	}
+}
+
+/******************************************************************************
+ *
+ *  ioctl_querycap
+ *
+ *  V4L2 device capabilities
+ *
+ *****************************************************************************/
+
+static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *vc)
+{
+	struct camera_data *cam = video_drvdata(file);
+
+	strcpy(vc->driver, "cpia2");
+
+	if (cam->params.pnp_id.product == 0x151)
+		strcpy(vc->card, "QX5 Microscope");
+	else
+		strcpy(vc->card, "CPiA2 Camera");
+	switch (cam->params.pnp_id.device_type) {
+	case DEVICE_STV_672:
+		strcat(vc->card, " (672/");
+		break;
+	case DEVICE_STV_676:
+		strcat(vc->card, " (676/");
+		break;
+	default:
+		strcat(vc->card, " (XXX/");
+		break;
+	}
+	switch (cam->params.version.sensor_flags) {
+	case CPIA2_VP_SENSOR_FLAGS_404:
+		strcat(vc->card, "404)");
+		break;
+	case CPIA2_VP_SENSOR_FLAGS_407:
+		strcat(vc->card, "407)");
+		break;
+	case CPIA2_VP_SENSOR_FLAGS_409:
+		strcat(vc->card, "409)");
+		break;
+	case CPIA2_VP_SENSOR_FLAGS_410:
+		strcat(vc->card, "410)");
+		break;
+	case CPIA2_VP_SENSOR_FLAGS_500:
+		strcat(vc->card, "500)");
+		break;
+	default:
+		strcat(vc->card, "XXX)");
+		break;
+	}
+
+	if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0)
+		memset(vc->bus_info,0, sizeof(vc->bus_info));
+
+	vc->device_caps = V4L2_CAP_VIDEO_CAPTURE |
+			   V4L2_CAP_READWRITE |
+			   V4L2_CAP_STREAMING;
+	vc->capabilities = vc->device_caps |
+			   V4L2_CAP_DEVICE_CAPS;
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_input
+ *
+ *  V4L2 input get/set/enumerate
+ *
+ *****************************************************************************/
+
+static int cpia2_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+	if (i->index)
+		return -EINVAL;
+	strcpy(i->name, "Camera");
+	i->type = V4L2_INPUT_TYPE_CAMERA;
+	return 0;
+}
+
+static int cpia2_g_input(struct file *file, void *fh, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int cpia2_s_input(struct file *file, void *fh, unsigned int i)
+{
+	return i ? -EINVAL : 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_enum_fmt
+ *
+ *  V4L2 format enumerate
+ *
+ *****************************************************************************/
+
+static int cpia2_enum_fmt_vid_cap(struct file *file, void *fh,
+					    struct v4l2_fmtdesc *f)
+{
+	int index = f->index;
+
+	if (index < 0 || index > 1)
+	       return -EINVAL;
+
+	memset(f, 0, sizeof(*f));
+	f->index = index;
+	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	f->flags = V4L2_FMT_FLAG_COMPRESSED;
+	switch(index) {
+	case 0:
+		strcpy(f->description, "MJPEG");
+		f->pixelformat = V4L2_PIX_FMT_MJPEG;
+		break;
+	case 1:
+		strcpy(f->description, "JPEG");
+		f->pixelformat = V4L2_PIX_FMT_JPEG;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_try_fmt
+ *
+ *  V4L2 format try
+ *
+ *****************************************************************************/
+
+static int cpia2_try_fmt_vid_cap(struct file *file, void *fh,
+					  struct v4l2_format *f)
+{
+	struct camera_data *cam = video_drvdata(file);
+
+	if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG &&
+	    f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
+	       return -EINVAL;
+
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage = cam->frame_size;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+	f->fmt.pix.priv = 0;
+
+	switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) {
+	case VIDEOSIZE_VGA:
+		f->fmt.pix.width = 640;
+		f->fmt.pix.height = 480;
+		break;
+	case VIDEOSIZE_CIF:
+		f->fmt.pix.width = 352;
+		f->fmt.pix.height = 288;
+		break;
+	case VIDEOSIZE_QVGA:
+		f->fmt.pix.width = 320;
+		f->fmt.pix.height = 240;
+		break;
+	case VIDEOSIZE_288_216:
+		f->fmt.pix.width = 288;
+		f->fmt.pix.height = 216;
+		break;
+	case VIDEOSIZE_256_192:
+		f->fmt.pix.width = 256;
+		f->fmt.pix.height = 192;
+		break;
+	case VIDEOSIZE_224_168:
+		f->fmt.pix.width = 224;
+		f->fmt.pix.height = 168;
+		break;
+	case VIDEOSIZE_192_144:
+		f->fmt.pix.width = 192;
+		f->fmt.pix.height = 144;
+		break;
+	case VIDEOSIZE_QCIF:
+	default:
+		f->fmt.pix.width = 176;
+		f->fmt.pix.height = 144;
+		break;
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_set_fmt
+ *
+ *  V4L2 format set
+ *
+ *****************************************************************************/
+
+static int cpia2_s_fmt_vid_cap(struct file *file, void *_fh,
+					struct v4l2_format *f)
+{
+	struct camera_data *cam = video_drvdata(file);
+	int err, frame;
+
+	err = cpia2_try_fmt_vid_cap(file, _fh, f);
+	if(err != 0)
+		return err;
+
+	cam->pixelformat = f->fmt.pix.pixelformat;
+
+	/* NOTE: This should be set to 1 for MJPEG, but some apps don't handle
+	 * the missing Huffman table properly. */
+	cam->params.compression.inhibit_htables = 0;
+		/*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/
+
+	/* we set the video window to something smaller or equal to what
+	 * is requested by the user???
+	 */
+	DBG("Requested width = %d, height = %d\n",
+	    f->fmt.pix.width, f->fmt.pix.height);
+	if (f->fmt.pix.width != cam->width ||
+	    f->fmt.pix.height != cam->height) {
+		cam->width = f->fmt.pix.width;
+		cam->height = f->fmt.pix.height;
+		cam->params.roi.width = f->fmt.pix.width;
+		cam->params.roi.height = f->fmt.pix.height;
+		cpia2_set_format(cam);
+	}
+
+	for (frame = 0; frame < cam->num_frames; ++frame) {
+		if (cam->buffers[frame].status == FRAME_READING)
+			if ((err = sync(cam, frame)) < 0)
+				return err;
+
+		cam->buffers[frame].status = FRAME_EMPTY;
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_get_fmt
+ *
+ *  V4L2 format get
+ *
+ *****************************************************************************/
+
+static int cpia2_g_fmt_vid_cap(struct file *file, void *fh,
+					struct v4l2_format *f)
+{
+	struct camera_data *cam = video_drvdata(file);
+
+	f->fmt.pix.width = cam->width;
+	f->fmt.pix.height = cam->height;
+	f->fmt.pix.pixelformat = cam->pixelformat;
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage = cam->frame_size;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+	f->fmt.pix.priv = 0;
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_cropcap
+ *
+ *  V4L2 query cropping capabilities
+ *  NOTE: cropping is currently disabled
+ *
+ *****************************************************************************/
+
+static int cpia2_cropcap(struct file *file, void *fh, struct v4l2_cropcap *c)
+{
+	struct camera_data *cam = video_drvdata(file);
+
+	if (c->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+	       return -EINVAL;
+
+	c->bounds.left = 0;
+	c->bounds.top = 0;
+	c->bounds.width = cam->width;
+	c->bounds.height = cam->height;
+	c->defrect.left = 0;
+	c->defrect.top = 0;
+	c->defrect.width = cam->width;
+	c->defrect.height = cam->height;
+	c->pixelaspect.numerator = 1;
+	c->pixelaspect.denominator = 1;
+
+	return 0;
+}
+
+struct framerate_info {
+	int value;
+	struct v4l2_fract period;
+};
+
+static const struct framerate_info framerate_controls[] = {
+	{ CPIA2_VP_FRAMERATE_6_25, { 4, 25 } },
+	{ CPIA2_VP_FRAMERATE_7_5,  { 2, 15 } },
+	{ CPIA2_VP_FRAMERATE_12_5, { 2, 25 } },
+	{ CPIA2_VP_FRAMERATE_15,   { 1, 15 } },
+	{ CPIA2_VP_FRAMERATE_25,   { 1, 25 } },
+	{ CPIA2_VP_FRAMERATE_30,   { 1, 30 } },
+};
+
+static int cpia2_g_parm(struct file *file, void *fh, struct v4l2_streamparm *p)
+{
+	struct camera_data *cam = video_drvdata(file);
+	struct v4l2_captureparm *cap = &p->parm.capture;
+	int i;
+
+	if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	cap->capability = V4L2_CAP_TIMEPERFRAME;
+	cap->readbuffers = cam->num_frames;
+	for (i = 0; i < ARRAY_SIZE(framerate_controls); i++)
+		if (cam->params.vp_params.frame_rate == framerate_controls[i].value) {
+			cap->timeperframe = framerate_controls[i].period;
+			break;
+		}
+	return 0;
+}
+
+static int cpia2_s_parm(struct file *file, void *fh, struct v4l2_streamparm *p)
+{
+	struct camera_data *cam = video_drvdata(file);
+	struct v4l2_captureparm *cap = &p->parm.capture;
+	struct v4l2_fract tpf = cap->timeperframe;
+	int max = ARRAY_SIZE(framerate_controls) - 1;
+	int ret;
+	int i;
+
+	ret = cpia2_g_parm(file, fh, p);
+	if (ret || !tpf.denominator || !tpf.numerator)
+		return ret;
+
+	/* Maximum 15 fps for this model */
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+	    cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
+		max -= 2;
+	for (i = 0; i <= max; i++) {
+		struct v4l2_fract f1 = tpf;
+		struct v4l2_fract f2 = framerate_controls[i].period;
+
+		f1.numerator *= f2.denominator;
+		f2.numerator *= f1.denominator;
+		if (f1.numerator >= f2.numerator)
+			break;
+	}
+	if (i > max)
+		i = max;
+	cap->timeperframe = framerate_controls[i].period;
+	return cpia2_set_fps(cam, framerate_controls[i].value);
+}
+
+static const struct {
+	u32 width;
+	u32 height;
+} cpia2_framesizes[] = {
+	{ 640, 480 },
+	{ 352, 288 },
+	{ 320, 240 },
+	{ 288, 216 },
+	{ 256, 192 },
+	{ 224, 168 },
+	{ 192, 144 },
+	{ 176, 144 },
+};
+
+static int cpia2_enum_framesizes(struct file *file, void *fh,
+					 struct v4l2_frmsizeenum *fsize)
+{
+
+	if (fsize->pixel_format != V4L2_PIX_FMT_MJPEG &&
+	    fsize->pixel_format != V4L2_PIX_FMT_JPEG)
+		return -EINVAL;
+	if (fsize->index >= ARRAY_SIZE(cpia2_framesizes))
+		return -EINVAL;
+	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+	fsize->discrete.width = cpia2_framesizes[fsize->index].width;
+	fsize->discrete.height = cpia2_framesizes[fsize->index].height;
+
+	return 0;
+}
+
+static int cpia2_enum_frameintervals(struct file *file, void *fh,
+					   struct v4l2_frmivalenum *fival)
+{
+	struct camera_data *cam = video_drvdata(file);
+	int max = ARRAY_SIZE(framerate_controls) - 1;
+	int i;
+
+	if (fival->pixel_format != V4L2_PIX_FMT_MJPEG &&
+	    fival->pixel_format != V4L2_PIX_FMT_JPEG)
+		return -EINVAL;
+
+	/* Maximum 15 fps for this model */
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+	    cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
+		max -= 2;
+	if (fival->index > max)
+		return -EINVAL;
+	for (i = 0; i < ARRAY_SIZE(cpia2_framesizes); i++)
+		if (fival->width == cpia2_framesizes[i].width &&
+		    fival->height == cpia2_framesizes[i].height)
+			break;
+	if (i == ARRAY_SIZE(cpia2_framesizes))
+		return -EINVAL;
+	fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+	fival->discrete = framerate_controls[fival->index].period;
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_s_ctrl
+ *
+ *  V4L2 set the value of a control variable
+ *
+ *****************************************************************************/
+
+static int cpia2_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct camera_data *cam =
+		container_of(ctrl->handler, struct camera_data, hdl);
+	static const int flicker_table[] = {
+		NEVER_FLICKER,
+		FLICKER_50,
+		FLICKER_60,
+	};
+
+	DBG("Set control id:%d, value:%d\n", ctrl->id, ctrl->val);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		cpia2_set_brightness(cam, ctrl->val);
+		break;
+	case V4L2_CID_CONTRAST:
+		cpia2_set_contrast(cam, ctrl->val);
+		break;
+	case V4L2_CID_SATURATION:
+		cpia2_set_saturation(cam, ctrl->val);
+		break;
+	case V4L2_CID_HFLIP:
+		cpia2_set_property_mirror(cam, ctrl->val);
+		break;
+	case V4L2_CID_VFLIP:
+		cpia2_set_property_flip(cam, ctrl->val);
+		break;
+	case V4L2_CID_POWER_LINE_FREQUENCY:
+		return cpia2_set_flicker_mode(cam, flicker_table[ctrl->val]);
+	case V4L2_CID_ILLUMINATORS_1:
+		return cpia2_set_gpio(cam, (cam->top_light->val << 6) |
+					   (cam->bottom_light->val << 7));
+	case V4L2_CID_JPEG_ACTIVE_MARKER:
+		cam->params.compression.inhibit_htables =
+			!(ctrl->val & V4L2_JPEG_ACTIVE_MARKER_DHT);
+		break;
+	case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+		cam->params.vc_params.quality = ctrl->val;
+		break;
+	case CPIA2_CID_USB_ALT:
+		cam->params.camera_state.stream_mode = ctrl->val;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_g_jpegcomp
+ *
+ *  V4L2 get the JPEG compression parameters
+ *
+ *****************************************************************************/
+
+static int cpia2_g_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms)
+{
+	struct camera_data *cam = video_drvdata(file);
+
+	memset(parms, 0, sizeof(*parms));
+
+	parms->quality = 80; // TODO: Can this be made meaningful?
+
+	parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI;
+	if(!cam->params.compression.inhibit_htables) {
+		parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT;
+	}
+
+	parms->APPn = cam->APPn;
+	parms->APP_len = cam->APP_len;
+	if(cam->APP_len > 0) {
+		memcpy(parms->APP_data, cam->APP_data, cam->APP_len);
+		parms->jpeg_markers |= V4L2_JPEG_MARKER_APP;
+	}
+
+	parms->COM_len = cam->COM_len;
+	if(cam->COM_len > 0) {
+		memcpy(parms->COM_data, cam->COM_data, cam->COM_len);
+		parms->jpeg_markers |= JPEG_MARKER_COM;
+	}
+
+	DBG("G_JPEGCOMP APP_len:%d COM_len:%d\n",
+	    parms->APP_len, parms->COM_len);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_s_jpegcomp
+ *
+ *  V4L2 set the JPEG compression parameters
+ *  NOTE: quality and some jpeg_markers are ignored.
+ *
+ *****************************************************************************/
+
+static int cpia2_s_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms)
+{
+	struct camera_data *cam = video_drvdata(file);
+
+	DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n",
+	    parms->APP_len, parms->COM_len);
+
+	cam->params.compression.inhibit_htables =
+		!(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT);
+	parms->jpeg_markers &= V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI |
+			       V4L2_JPEG_MARKER_DHT;
+
+	if(parms->APP_len != 0) {
+		if(parms->APP_len > 0 &&
+		   parms->APP_len <= sizeof(cam->APP_data) &&
+		   parms->APPn >= 0 && parms->APPn <= 15) {
+			cam->APPn = parms->APPn;
+			cam->APP_len = parms->APP_len;
+			memcpy(cam->APP_data, parms->APP_data, parms->APP_len);
+		} else {
+			LOG("Bad APPn Params n=%d len=%d\n",
+			    parms->APPn, parms->APP_len);
+			return -EINVAL;
+		}
+	} else {
+		cam->APP_len = 0;
+	}
+
+	if(parms->COM_len != 0) {
+		if(parms->COM_len > 0 &&
+		   parms->COM_len <= sizeof(cam->COM_data)) {
+			cam->COM_len = parms->COM_len;
+			memcpy(cam->COM_data, parms->COM_data, parms->COM_len);
+		} else {
+			LOG("Bad COM_len=%d\n", parms->COM_len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_reqbufs
+ *
+ *  V4L2 Initiate memory mapping.
+ *  NOTE: The user's request is ignored. For now the buffers are fixed.
+ *
+ *****************************************************************************/
+
+static int cpia2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req)
+{
+	struct camera_data *cam = video_drvdata(file);
+
+	if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	   req->memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+
+	DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames);
+	req->count = cam->num_frames;
+	memset(&req->reserved, 0, sizeof(req->reserved));
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_querybuf
+ *
+ *  V4L2 Query memory buffer status.
+ *
+ *****************************************************************************/
+
+static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+	struct camera_data *cam = video_drvdata(file);
+
+	if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	   buf->index > cam->num_frames)
+		return -EINVAL;
+
+	buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
+	buf->length = cam->frame_size;
+
+	buf->memory = V4L2_MEMORY_MMAP;
+
+	if(cam->mmapped)
+		buf->flags = V4L2_BUF_FLAG_MAPPED;
+	else
+		buf->flags = 0;
+
+	switch (cam->buffers[buf->index].status) {
+	case FRAME_EMPTY:
+	case FRAME_ERROR:
+	case FRAME_READING:
+		buf->bytesused = 0;
+		buf->flags = V4L2_BUF_FLAG_QUEUED;
+		break;
+	case FRAME_READY:
+		buf->bytesused = cam->buffers[buf->index].length;
+		buf->timestamp = cam->buffers[buf->index].timestamp;
+		buf->sequence = cam->buffers[buf->index].seq;
+		buf->flags = V4L2_BUF_FLAG_DONE;
+		break;
+	}
+
+	DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n",
+	     buf->index, buf->m.offset, buf->flags, buf->sequence,
+	     buf->bytesused);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_qbuf
+ *
+ *  V4L2 User is freeing buffer
+ *
+ *****************************************************************************/
+
+static int cpia2_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+	struct camera_data *cam = video_drvdata(file);
+
+	if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	   buf->memory != V4L2_MEMORY_MMAP ||
+	   buf->index > cam->num_frames)
+		return -EINVAL;
+
+	DBG("QBUF #%d\n", buf->index);
+
+	if(cam->buffers[buf->index].status == FRAME_READY)
+		cam->buffers[buf->index].status = FRAME_EMPTY;
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  find_earliest_filled_buffer
+ *
+ *  Helper for ioctl_dqbuf. Find the next ready buffer.
+ *
+ *****************************************************************************/
+
+static int find_earliest_filled_buffer(struct camera_data *cam)
+{
+	int i;
+	int found = -1;
+	for (i=0; i<cam->num_frames; i++) {
+		if(cam->buffers[i].status == FRAME_READY) {
+			if(found < 0) {
+				found = i;
+			} else {
+				/* find which buffer is earlier */
+				struct timeval *tv1, *tv2;
+				tv1 = &cam->buffers[i].timestamp;
+				tv2 = &cam->buffers[found].timestamp;
+				if(tv1->tv_sec < tv2->tv_sec ||
+				   (tv1->tv_sec == tv2->tv_sec &&
+				    tv1->tv_usec < tv2->tv_usec))
+					found = i;
+			}
+		}
+	}
+	return found;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_dqbuf
+ *
+ *  V4L2 User is asking for a filled buffer.
+ *
+ *****************************************************************************/
+
+static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+	struct camera_data *cam = video_drvdata(file);
+	int frame;
+
+	if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	   buf->memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+
+	frame = find_earliest_filled_buffer(cam);
+
+	if(frame < 0 && file->f_flags&O_NONBLOCK)
+		return -EAGAIN;
+
+	if(frame < 0) {
+		/* Wait for a frame to become available */
+		struct framebuf *cb=cam->curbuff;
+		mutex_unlock(&cam->v4l2_lock);
+		wait_event_interruptible(cam->wq_stream,
+					 !video_is_registered(&cam->vdev) ||
+					 (cb=cam->curbuff)->status == FRAME_READY);
+		mutex_lock(&cam->v4l2_lock);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+		if (!video_is_registered(&cam->vdev))
+			return -ENOTTY;
+		frame = cb->num;
+	}
+
+
+	buf->index = frame;
+	buf->bytesused = cam->buffers[buf->index].length;
+	buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
+	buf->field = V4L2_FIELD_NONE;
+	buf->timestamp = cam->buffers[buf->index].timestamp;
+	buf->sequence = cam->buffers[buf->index].seq;
+	buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
+	buf->length = cam->frame_size;
+	buf->reserved2 = 0;
+	buf->reserved = 0;
+	memset(&buf->timecode, 0, sizeof(buf->timecode));
+
+	DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index,
+	    cam->buffers[buf->index].status, buf->sequence, buf->bytesused);
+
+	return 0;
+}
+
+static int cpia2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
+{
+	struct camera_data *cam = video_drvdata(file);
+	int ret = -EINVAL;
+
+	DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming);
+	if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (!cam->streaming) {
+		ret = cpia2_usb_stream_start(cam,
+				cam->params.camera_state.stream_mode);
+		if (!ret)
+			v4l2_ctrl_grab(cam->usb_alt, true);
+	}
+	return ret;
+}
+
+static int cpia2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
+{
+	struct camera_data *cam = video_drvdata(file);
+	int ret = -EINVAL;
+
+	DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming);
+	if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (cam->streaming) {
+		ret = cpia2_usb_stream_stop(cam);
+		if (!ret)
+			v4l2_ctrl_grab(cam->usb_alt, false);
+	}
+	return ret;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_mmap
+ *
+ *****************************************************************************/
+static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
+{
+	struct camera_data *cam = video_drvdata(file);
+	int retval;
+
+	if (mutex_lock_interruptible(&cam->v4l2_lock))
+		return -ERESTARTSYS;
+	retval = cpia2_remap_buffer(cam, area);
+
+	if(!retval)
+		cam->stream_fh = file->private_data;
+	mutex_unlock(&cam->v4l2_lock);
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  reset_camera_struct_v4l
+ *
+ *  Sets all values to the defaults
+ *****************************************************************************/
+static void reset_camera_struct_v4l(struct camera_data *cam)
+{
+	cam->width = cam->params.roi.width;
+	cam->height = cam->params.roi.height;
+
+	cam->frame_size = buffer_size;
+	cam->num_frames = num_buffers;
+
+	/* Flicker modes */
+	cam->params.flicker_control.flicker_mode_req = flicker_mode;
+
+	/* stream modes */
+	cam->params.camera_state.stream_mode = alternate;
+
+	cam->pixelformat = V4L2_PIX_FMT_JPEG;
+}
+
+static const struct v4l2_ioctl_ops cpia2_ioctl_ops = {
+	.vidioc_querycap		    = cpia2_querycap,
+	.vidioc_enum_input		    = cpia2_enum_input,
+	.vidioc_g_input			    = cpia2_g_input,
+	.vidioc_s_input			    = cpia2_s_input,
+	.vidioc_enum_fmt_vid_cap	    = cpia2_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap		    = cpia2_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap		    = cpia2_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap		    = cpia2_try_fmt_vid_cap,
+	.vidioc_g_jpegcomp		    = cpia2_g_jpegcomp,
+	.vidioc_s_jpegcomp		    = cpia2_s_jpegcomp,
+	.vidioc_cropcap			    = cpia2_cropcap,
+	.vidioc_reqbufs			    = cpia2_reqbufs,
+	.vidioc_querybuf		    = cpia2_querybuf,
+	.vidioc_qbuf			    = cpia2_qbuf,
+	.vidioc_dqbuf			    = cpia2_dqbuf,
+	.vidioc_streamon		    = cpia2_streamon,
+	.vidioc_streamoff		    = cpia2_streamoff,
+	.vidioc_s_parm			    = cpia2_s_parm,
+	.vidioc_g_parm			    = cpia2_g_parm,
+	.vidioc_enum_framesizes		    = cpia2_enum_framesizes,
+	.vidioc_enum_frameintervals	    = cpia2_enum_frameintervals,
+	.vidioc_subscribe_event		    = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event	    = v4l2_event_unsubscribe,
+};
+
+/***
+ * The v4l video device structure initialized for this device
+ ***/
+static const struct v4l2_file_operations cpia2_fops = {
+	.owner		= THIS_MODULE,
+	.open		= cpia2_open,
+	.release	= cpia2_close,
+	.read		= cpia2_v4l_read,
+	.poll		= cpia2_v4l_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= cpia2_mmap,
+};
+
+static struct video_device cpia2_template = {
+	/* I could not find any place for the old .initialize initializer?? */
+	.name =		"CPiA2 Camera",
+	.fops =		&cpia2_fops,
+	.ioctl_ops =	&cpia2_ioctl_ops,
+	.release =	video_device_release_empty,
+};
+
+void cpia2_camera_release(struct v4l2_device *v4l2_dev)
+{
+	struct camera_data *cam =
+		container_of(v4l2_dev, struct camera_data, v4l2_dev);
+
+	v4l2_ctrl_handler_free(&cam->hdl);
+	v4l2_device_unregister(&cam->v4l2_dev);
+	kfree(cam);
+}
+
+static const struct v4l2_ctrl_ops cpia2_ctrl_ops = {
+	.s_ctrl = cpia2_s_ctrl,
+};
+
+/******************************************************************************
+ *
+ *  cpia2_register_camera
+ *
+ *****************************************************************************/
+int cpia2_register_camera(struct camera_data *cam)
+{
+	struct v4l2_ctrl_handler *hdl = &cam->hdl;
+	struct v4l2_ctrl_config cpia2_usb_alt = {
+		.ops = &cpia2_ctrl_ops,
+		.id = CPIA2_CID_USB_ALT,
+		.name = "USB Alternate",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.min = USBIF_ISO_1,
+		.max = USBIF_ISO_6,
+		.step = 1,
+	};
+	int ret;
+
+	v4l2_ctrl_handler_init(hdl, 12);
+	v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+			V4L2_CID_BRIGHTNESS,
+			cam->params.pnp_id.device_type == DEVICE_STV_672 ? 1 : 0,
+			255, 1, DEFAULT_BRIGHTNESS);
+	v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 255, 1, DEFAULT_CONTRAST);
+	v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 255, 1, DEFAULT_SATURATION);
+	v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+			V4L2_CID_HFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+			V4L2_CID_JPEG_ACTIVE_MARKER, 0,
+			V4L2_JPEG_ACTIVE_MARKER_DHT, 0,
+			V4L2_JPEG_ACTIVE_MARKER_DHT);
+	v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+			V4L2_CID_JPEG_COMPRESSION_QUALITY, 1,
+			100, 1, 100);
+	cpia2_usb_alt.def = alternate;
+	cam->usb_alt = v4l2_ctrl_new_custom(hdl, &cpia2_usb_alt, NULL);
+	/* VP5 Only */
+	if (cam->params.pnp_id.device_type != DEVICE_STV_672)
+		v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+	/* Flicker control only valid for 672 */
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+		v4l2_ctrl_new_std_menu(hdl, &cpia2_ctrl_ops,
+			V4L2_CID_POWER_LINE_FREQUENCY,
+			V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, 0);
+	/* Light control only valid for the QX5 Microscope */
+	if (cam->params.pnp_id.product == 0x151) {
+		cam->top_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+				V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0);
+		cam->bottom_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+				V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0);
+		v4l2_ctrl_cluster(2, &cam->top_light);
+	}
+
+	if (hdl->error) {
+		ret = hdl->error;
+		v4l2_ctrl_handler_free(hdl);
+		return ret;
+	}
+
+	cam->vdev = cpia2_template;
+	video_set_drvdata(&cam->vdev, cam);
+	cam->vdev.lock = &cam->v4l2_lock;
+	cam->vdev.ctrl_handler = hdl;
+	cam->vdev.v4l2_dev = &cam->v4l2_dev;
+	set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags);
+
+	reset_camera_struct_v4l(cam);
+
+	/* register v4l device */
+	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
+		ERR("video_register_device failed\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_unregister_camera
+ *
+ *****************************************************************************/
+void cpia2_unregister_camera(struct camera_data *cam)
+{
+	video_unregister_device(&cam->vdev);
+}
+
+/******************************************************************************
+ *
+ *  check_parameters
+ *
+ *  Make sure that all user-supplied parameters are sensible
+ *****************************************************************************/
+static void __init check_parameters(void)
+{
+	if(buffer_size < PAGE_SIZE) {
+		buffer_size = PAGE_SIZE;
+		LOG("buffer_size too small, setting to %d\n", buffer_size);
+	} else if(buffer_size > 1024*1024) {
+		/* arbitrary upper limiit */
+		buffer_size = 1024*1024;
+		LOG("buffer_size ridiculously large, setting to %d\n",
+		    buffer_size);
+	} else {
+		buffer_size += PAGE_SIZE-1;
+		buffer_size &= ~(PAGE_SIZE-1);
+	}
+
+	if(num_buffers < 1) {
+		num_buffers = 1;
+		LOG("num_buffers too small, setting to %d\n", num_buffers);
+	} else if(num_buffers > VIDEO_MAX_FRAME) {
+		num_buffers = VIDEO_MAX_FRAME;
+		LOG("num_buffers too large, setting to %d\n", num_buffers);
+	}
+
+	if(alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) {
+		alternate = DEFAULT_ALT;
+		LOG("alternate specified is invalid, using %d\n", alternate);
+	}
+
+	if (flicker_mode != 0 && flicker_mode != FLICKER_50 && flicker_mode != FLICKER_60) {
+		flicker_mode = 0;
+		LOG("Flicker mode specified is invalid, using %d\n",
+		    flicker_mode);
+	}
+
+	DBG("Using %d buffers, each %d bytes, alternate=%d\n",
+	    num_buffers, buffer_size, alternate);
+}
+
+/************   Module Stuff ***************/
+
+
+/******************************************************************************
+ *
+ * cpia2_init/module_init
+ *
+ *****************************************************************************/
+static int __init cpia2_init(void)
+{
+	LOG("%s v%s\n",
+	    ABOUT, CPIA_VERSION);
+	check_parameters();
+	cpia2_usb_init();
+	return 0;
+}
+
+
+/******************************************************************************
+ *
+ * cpia2_exit/module_exit
+ *
+ *****************************************************************************/
+static void __exit cpia2_exit(void)
+{
+	cpia2_usb_cleanup();
+	schedule_timeout(2 * HZ);
+}
+
+module_init(cpia2_init);
+module_exit(cpia2_exit);
diff --git a/drivers/media/usb/cx231xx/Kconfig b/drivers/media/usb/cx231xx/Kconfig
new file mode 100644
index 0000000..446f692
--- /dev/null
+++ b/drivers/media/usb/cx231xx/Kconfig
@@ -0,0 +1,51 @@
+config VIDEO_CX231XX
+	tristate "Conexant cx231xx USB video capture support"
+	depends on VIDEO_DEV && I2C
+	select VIDEO_TUNER
+	select VIDEO_TVEEPROM
+	depends on RC_CORE
+	select VIDEOBUF_VMALLOC
+	select VIDEO_CX25840
+	select VIDEO_CX2341X
+
+	---help---
+	  This is a video4linux driver for Conexant 231xx USB based TV cards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx231xx
+
+config VIDEO_CX231XX_RC
+	bool "Conexant cx231xx Remote Controller additional support"
+	depends on RC_CORE
+	depends on VIDEO_CX231XX
+	default y
+	---help---
+	  cx231xx hardware has a builtin RX/TX support. However, a few
+	  designs opted to not use it, but, instead, some other hardware.
+	  This module enables the usage of those other hardware, like the
+	  ones used with ISDB-T boards.
+
+	  On most cases, all you need for IR is mceusb module.
+
+config VIDEO_CX231XX_ALSA
+	tristate "Conexant Cx231xx ALSA audio module"
+	depends on VIDEO_CX231XX && SND
+	select SND_PCM
+
+	---help---
+	  This is an ALSA driver for Cx231xx USB based TV cards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx231xx-alsa
+
+config VIDEO_CX231XX_DVB
+	tristate "DVB/ATSC Support for Cx231xx based TV cards"
+	depends on VIDEO_CX231XX && DVB_CORE && DVB_CAPTURE_DRIVERS
+	select VIDEOBUF_DVB
+	select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+	select DVB_MB86A20S if !DVB_FE_CUSTOMISE
+
+	---help---
+	  This adds support for DVB cards based on the
+	  Conexant cx231xx chips.
diff --git a/drivers/media/usb/cx231xx/Makefile b/drivers/media/usb/cx231xx/Makefile
new file mode 100644
index 0000000..52cf769
--- /dev/null
+++ b/drivers/media/usb/cx231xx/Makefile
@@ -0,0 +1,15 @@
+cx231xx-y += cx231xx-video.o cx231xx-i2c.o cx231xx-cards.o cx231xx-core.o
+cx231xx-y += cx231xx-avcore.o cx231xx-417.o cx231xx-pcb-cfg.o cx231xx-vbi.o
+cx231xx-$(CONFIG_VIDEO_CX231XX_RC) += cx231xx-input.o
+
+cx231xx-alsa-objs := cx231xx-audio.o
+
+obj-$(CONFIG_VIDEO_CX231XX) += cx231xx.o
+obj-$(CONFIG_VIDEO_CX231XX_ALSA) += cx231xx-alsa.o
+obj-$(CONFIG_VIDEO_CX231XX_DVB) += cx231xx-dvb.o
+
+ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+ccflags-y += -Idrivers/media/usb/dvb-usb
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
new file mode 100644
index 0000000..b024e51
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -0,0 +1,2197 @@
+/*
+ *
+ *  Support for a cx23417 mpeg encoder via cx231xx host port.
+ *
+ *    (c) 2004 Jelle Foks <jelle@foks.us>
+ *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
+ *    (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *      - CX23885/7/8 support
+ *
+ *  Includes parts from the ivtv driver( http://ivtv.sourceforge.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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/vmalloc.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/cx2341x.h>
+#include <linux/usb.h>
+
+#include "cx231xx.h"
+/*#include "cx23885-ioctl.h"*/
+
+#define CX231xx_FIRM_IMAGE_SIZE 376836
+#define CX231xx_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
+
+/* for polaris ITVC */
+#define ITVC_WRITE_DIR          0x03FDFC00
+#define ITVC_READ_DIR            0x0001FC00
+
+#define  MCI_MEMORY_DATA_BYTE0          0x00
+#define  MCI_MEMORY_DATA_BYTE1          0x08
+#define  MCI_MEMORY_DATA_BYTE2          0x10
+#define  MCI_MEMORY_DATA_BYTE3          0x18
+
+#define  MCI_MEMORY_ADDRESS_BYTE2       0x20
+#define  MCI_MEMORY_ADDRESS_BYTE1       0x28
+#define  MCI_MEMORY_ADDRESS_BYTE0       0x30
+
+#define  MCI_REGISTER_DATA_BYTE0        0x40
+#define  MCI_REGISTER_DATA_BYTE1        0x48
+#define  MCI_REGISTER_DATA_BYTE2        0x50
+#define  MCI_REGISTER_DATA_BYTE3        0x58
+
+#define  MCI_REGISTER_ADDRESS_BYTE0     0x60
+#define  MCI_REGISTER_ADDRESS_BYTE1     0x68
+
+#define  MCI_REGISTER_MODE              0x70
+
+/* Read and write modes for polaris ITVC */
+#define  MCI_MODE_REGISTER_READ         0x000
+#define  MCI_MODE_REGISTER_WRITE        0x100
+#define  MCI_MODE_MEMORY_READ           0x000
+#define  MCI_MODE_MEMORY_WRITE          0x4000
+
+static unsigned int mpegbufs = 8;
+module_param(mpegbufs, int, 0644);
+MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32");
+static unsigned int mpeglines = 128;
+module_param(mpeglines, int, 0644);
+MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
+static unsigned int mpeglinesize = 512;
+module_param(mpeglinesize, int, 0644);
+MODULE_PARM_DESC(mpeglinesize,
+	"number of bytes in each line of an MPEG buffer, range 512-1024");
+
+static unsigned int v4l_debug = 1;
+module_param(v4l_debug, int, 0644);
+MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
+struct cx231xx_dmaqueue *dma_qq;
+#define dprintk(level, fmt, arg...)\
+	do { if (v4l_debug >= level) \
+		printk(KERN_INFO "%s: " fmt, \
+		(dev) ? dev->name : "cx231xx[?]", ## arg); \
+	} while (0)
+
+static struct cx231xx_tvnorm cx231xx_tvnorms[] = {
+	{
+		.name      = "NTSC-M",
+		.id        = V4L2_STD_NTSC_M,
+	}, {
+		.name      = "NTSC-JP",
+		.id        = V4L2_STD_NTSC_M_JP,
+	}, {
+		.name      = "PAL-BG",
+		.id        = V4L2_STD_PAL_BG,
+	}, {
+		.name      = "PAL-DK",
+		.id        = V4L2_STD_PAL_DK,
+	}, {
+		.name      = "PAL-I",
+		.id        = V4L2_STD_PAL_I,
+	}, {
+		.name      = "PAL-M",
+		.id        = V4L2_STD_PAL_M,
+	}, {
+		.name      = "PAL-N",
+		.id        = V4L2_STD_PAL_N,
+	}, {
+		.name      = "PAL-Nc",
+		.id        = V4L2_STD_PAL_Nc,
+	}, {
+		.name      = "PAL-60",
+		.id        = V4L2_STD_PAL_60,
+	}, {
+		.name      = "SECAM-L",
+		.id        = V4L2_STD_SECAM_L,
+	}, {
+		.name      = "SECAM-DK",
+		.id        = V4L2_STD_SECAM_DK,
+	}
+};
+
+/* ------------------------------------------------------------------ */
+enum cx231xx_capture_type {
+	CX231xx_MPEG_CAPTURE,
+	CX231xx_RAW_CAPTURE,
+	CX231xx_RAW_PASSTHRU_CAPTURE
+};
+enum cx231xx_capture_bits {
+	CX231xx_RAW_BITS_NONE             = 0x00,
+	CX231xx_RAW_BITS_YUV_CAPTURE      = 0x01,
+	CX231xx_RAW_BITS_PCM_CAPTURE      = 0x02,
+	CX231xx_RAW_BITS_VBI_CAPTURE      = 0x04,
+	CX231xx_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
+	CX231xx_RAW_BITS_TO_HOST_CAPTURE  = 0x10
+};
+enum cx231xx_capture_end {
+	CX231xx_END_AT_GOP, /* stop at the end of gop, generate irq */
+	CX231xx_END_NOW, /* stop immediately, no irq */
+};
+enum cx231xx_framerate {
+	CX231xx_FRAMERATE_NTSC_30, /* NTSC: 30fps */
+	CX231xx_FRAMERATE_PAL_25   /* PAL: 25fps */
+};
+enum cx231xx_stream_port {
+	CX231xx_OUTPUT_PORT_MEMORY,
+	CX231xx_OUTPUT_PORT_STREAMING,
+	CX231xx_OUTPUT_PORT_SERIAL
+};
+enum cx231xx_data_xfer_status {
+	CX231xx_MORE_BUFFERS_FOLLOW,
+	CX231xx_LAST_BUFFER,
+};
+enum cx231xx_picture_mask {
+	CX231xx_PICTURE_MASK_NONE,
+	CX231xx_PICTURE_MASK_I_FRAMES,
+	CX231xx_PICTURE_MASK_I_P_FRAMES = 0x3,
+	CX231xx_PICTURE_MASK_ALL_FRAMES = 0x7,
+};
+enum cx231xx_vbi_mode_bits {
+	CX231xx_VBI_BITS_SLICED,
+	CX231xx_VBI_BITS_RAW,
+};
+enum cx231xx_vbi_insertion_bits {
+	CX231xx_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
+	CX231xx_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
+	CX231xx_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
+	CX231xx_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
+	CX231xx_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
+};
+enum cx231xx_dma_unit {
+	CX231xx_DMA_BYTES,
+	CX231xx_DMA_FRAMES,
+};
+enum cx231xx_dma_transfer_status_bits {
+	CX231xx_DMA_TRANSFER_BITS_DONE = 0x01,
+	CX231xx_DMA_TRANSFER_BITS_ERROR = 0x04,
+	CX231xx_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
+};
+enum cx231xx_pause {
+	CX231xx_PAUSE_ENCODING,
+	CX231xx_RESUME_ENCODING,
+};
+enum cx231xx_copyright {
+	CX231xx_COPYRIGHT_OFF,
+	CX231xx_COPYRIGHT_ON,
+};
+enum cx231xx_notification_type {
+	CX231xx_NOTIFICATION_REFRESH,
+};
+enum cx231xx_notification_status {
+	CX231xx_NOTIFICATION_OFF,
+	CX231xx_NOTIFICATION_ON,
+};
+enum cx231xx_notification_mailbox {
+	CX231xx_NOTIFICATION_NO_MAILBOX = -1,
+};
+enum cx231xx_field1_lines {
+	CX231xx_FIELD1_SAA7114 = 0x00EF, /* 239 */
+	CX231xx_FIELD1_SAA7115 = 0x00F0, /* 240 */
+	CX231xx_FIELD1_MICRONAS = 0x0105, /* 261 */
+};
+enum cx231xx_field2_lines {
+	CX231xx_FIELD2_SAA7114 = 0x00EF, /* 239 */
+	CX231xx_FIELD2_SAA7115 = 0x00F0, /* 240 */
+	CX231xx_FIELD2_MICRONAS = 0x0106, /* 262 */
+};
+enum cx231xx_custom_data_type {
+	CX231xx_CUSTOM_EXTENSION_USR_DATA,
+	CX231xx_CUSTOM_PRIVATE_PACKET,
+};
+enum cx231xx_mute {
+	CX231xx_UNMUTE,
+	CX231xx_MUTE,
+};
+enum cx231xx_mute_video_mask {
+	CX231xx_MUTE_VIDEO_V_MASK = 0x0000FF00,
+	CX231xx_MUTE_VIDEO_U_MASK = 0x00FF0000,
+	CX231xx_MUTE_VIDEO_Y_MASK = 0xFF000000,
+};
+enum cx231xx_mute_video_shift {
+	CX231xx_MUTE_VIDEO_V_SHIFT = 8,
+	CX231xx_MUTE_VIDEO_U_SHIFT = 16,
+	CX231xx_MUTE_VIDEO_Y_SHIFT = 24,
+};
+
+/* defines below are from ivtv-driver.h */
+#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
+
+/* Firmware API commands */
+#define IVTV_API_STD_TIMEOUT 500
+
+/* Registers */
+/* IVTV_REG_OFFSET */
+#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)
+#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)
+#define IVTV_REG_SPU (0x9050)
+#define IVTV_REG_HW_BLOCKS (0x9054)
+#define IVTV_REG_VPU (0x9058)
+#define IVTV_REG_APU (0xA064)
+
+/*
+ * Bit definitions for MC417_RWD and MC417_OEN registers
+ *
+ * bits 31-16
+ *+-----------+
+ *| Reserved  |
+ *|+-----------+
+ *|  bit 15  bit 14  bit 13 bit 12  bit 11  bit 10  bit 9   bit 8
+ *|+-------+-------+-------+-------+-------+-------+-------+-------+
+ *|| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0|
+ *|+-------+-------+-------+-------+-------+-------+-------+-------+
+ *| bit 7   bit 6   bit 5   bit 4   bit 3   bit 2   bit 1   bit 0
+ *|+-------+-------+-------+-------+-------+-------+-------+-------+
+ *||MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0|
+ *|+-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define MC417_MIWR	0x8000
+#define MC417_MIRD	0x4000
+#define MC417_MICS	0x2000
+#define MC417_MIRDY	0x1000
+#define MC417_MIADDR	0x0F00
+#define MC417_MIDATA	0x00FF
+
+
+/* Bit definitions for MC417_CTL register ****
+ *bits 31-6   bits 5-4   bit 3    bits 2-1       Bit 0
+ *+--------+-------------+--------+--------------+------------+
+ *|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN|
+ *+--------+-------------+--------+--------------+------------+
+ */
+#define MC417_SPD_CTL(x)	(((x) << 4) & 0x00000030)
+#define MC417_GPIO_SEL(x)	(((x) << 1) & 0x00000006)
+#define MC417_UART_GPIO_EN	0x00000001
+
+/* Values for speed control */
+#define MC417_SPD_CTL_SLOW	0x1
+#define MC417_SPD_CTL_MEDIUM	0x0
+#define MC417_SPD_CTL_FAST	0x3     /* b'1x, but we use b'11 */
+
+/* Values for GPIO select */
+#define MC417_GPIO_SEL_GPIO3	0x3
+#define MC417_GPIO_SEL_GPIO2	0x2
+#define MC417_GPIO_SEL_GPIO1	0x1
+#define MC417_GPIO_SEL_GPIO0	0x0
+
+
+#define CX23417_GPIO_MASK 0xFC0003FF
+static int setITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 value)
+{
+	int status = 0;
+	u32 _gpio_direction = 0;
+
+	_gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
+	_gpio_direction = _gpio_direction|gpio_direction;
+	status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
+			 (u8 *)&value, 4, 0, 0);
+	return status;
+}
+static int getITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 *pValue)
+{
+	int status = 0;
+	u32 _gpio_direction = 0;
+
+	_gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
+	_gpio_direction = _gpio_direction|gpio_direction;
+
+	status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
+		 (u8 *)pValue, 4, 0, 1);
+	return status;
+}
+
+static int waitForMciComplete(struct cx231xx *dev)
+{
+	u32 gpio;
+	u32 gpio_driection = 0;
+	u8 count = 0;
+	getITVCReg(dev, gpio_driection, &gpio);
+
+	while (!(gpio&0x020000)) {
+		msleep(10);
+
+		getITVCReg(dev, gpio_driection, &gpio);
+
+		if (count++ > 100) {
+			dprintk(3, "ERROR: Timeout - gpio=%x\n", gpio);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int mc417_register_write(struct cx231xx *dev, u16 address, u32 value)
+{
+	u32 temp;
+	int status = 0;
+
+	temp = 0x82|MCI_REGISTER_DATA_BYTE0|((value&0x000000FF)<<8);
+	temp = temp<<10;
+	status = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	if (status < 0)
+		return status;
+	temp = temp|((0x05)<<10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/*write data byte 1;*/
+	temp = 0x82|MCI_REGISTER_DATA_BYTE1|(value&0x0000FF00);
+	temp = temp<<10;
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	temp = temp|((0x05)<<10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/*write data byte 2;*/
+	temp = 0x82|MCI_REGISTER_DATA_BYTE2|((value&0x00FF0000)>>8);
+	temp = temp<<10;
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	temp = temp|((0x05)<<10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/*write data byte 3;*/
+	temp = 0x82|MCI_REGISTER_DATA_BYTE3|((value&0xFF000000)>>16);
+	temp = temp<<10;
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	temp = temp|((0x05)<<10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/*write address byte 0;*/
+	temp = 0x82|MCI_REGISTER_ADDRESS_BYTE0|((address&0x000000FF)<<8);
+	temp = temp<<10;
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	temp = temp|((0x05)<<10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/*write address byte 1;*/
+	temp = 0x82|MCI_REGISTER_ADDRESS_BYTE1|(address&0x0000FF00);
+	temp = temp<<10;
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	temp = temp|((0x05)<<10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/*Write that the mode is write.*/
+	temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_WRITE;
+	temp = temp<<10;
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	temp = temp|((0x05)<<10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	return waitForMciComplete(dev);
+}
+
+static int mc417_register_read(struct cx231xx *dev, u16 address, u32 *value)
+{
+	/*write address byte 0;*/
+	u32 temp;
+	u32 return_value = 0;
+	int ret = 0;
+
+	temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
+	temp = temp << 10;
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	temp = temp | ((0x05) << 10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/*write address byte 1;*/
+	temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0xFF00);
+	temp = temp << 10;
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	temp = temp | ((0x05) << 10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/*write that the mode is read;*/
+	temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_READ;
+	temp = temp << 10;
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	temp = temp | ((0x05) << 10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/*wait for the MIRDY line to be asserted ,
+	signalling that the read is done;*/
+	ret = waitForMciComplete(dev);
+
+	/*switch the DATA- GPIO to input mode;*/
+
+	/*Read data byte 0;*/
+	temp = (0x82 | MCI_REGISTER_DATA_BYTE0) << 10;
+	setITVCReg(dev, ITVC_READ_DIR, temp);
+	temp = ((0x81 | MCI_REGISTER_DATA_BYTE0) << 10);
+	setITVCReg(dev, ITVC_READ_DIR, temp);
+	getITVCReg(dev, ITVC_READ_DIR, &temp);
+	return_value |= ((temp & 0x03FC0000) >> 18);
+	setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+
+	/* Read data byte 1;*/
+	temp = (0x82 | MCI_REGISTER_DATA_BYTE1) << 10;
+	setITVCReg(dev, ITVC_READ_DIR, temp);
+	temp = ((0x81 | MCI_REGISTER_DATA_BYTE1) << 10);
+	setITVCReg(dev, ITVC_READ_DIR, temp);
+	getITVCReg(dev, ITVC_READ_DIR, &temp);
+
+	return_value |= ((temp & 0x03FC0000) >> 10);
+	setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+
+	/*Read data byte 2;*/
+	temp = (0x82 | MCI_REGISTER_DATA_BYTE2) << 10;
+	setITVCReg(dev, ITVC_READ_DIR, temp);
+	temp = ((0x81 | MCI_REGISTER_DATA_BYTE2) << 10);
+	setITVCReg(dev, ITVC_READ_DIR, temp);
+	getITVCReg(dev, ITVC_READ_DIR, &temp);
+	return_value |= ((temp & 0x03FC0000) >> 2);
+	setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+
+	/*Read data byte 3;*/
+	temp = (0x82 | MCI_REGISTER_DATA_BYTE3) << 10;
+	setITVCReg(dev, ITVC_READ_DIR, temp);
+	temp = ((0x81 | MCI_REGISTER_DATA_BYTE3) << 10);
+	setITVCReg(dev, ITVC_READ_DIR, temp);
+	getITVCReg(dev, ITVC_READ_DIR, &temp);
+	return_value |= ((temp & 0x03FC0000) << 6);
+	setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+
+	*value  = return_value;
+
+
+	return ret;
+}
+
+static int mc417_memory_write(struct cx231xx *dev, u32 address, u32 value)
+{
+	/*write data byte 0;*/
+
+	u32 temp;
+	int ret = 0;
+
+	temp = 0x82 | MCI_MEMORY_DATA_BYTE0|((value & 0x000000FF) << 8);
+	temp = temp << 10;
+	ret = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	if (ret < 0)
+		return ret;
+	temp = temp | ((0x05) << 10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/*write data byte 1;*/
+	temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00);
+	temp = temp << 10;
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	temp = temp | ((0x05) << 10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/*write data byte 2;*/
+	temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8);
+	temp = temp<<10;
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	temp = temp|((0x05)<<10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/*write data byte 3;*/
+	temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16);
+	temp = temp<<10;
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	temp = temp|((0x05)<<10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/* write address byte 2;*/
+	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
+		((address & 0x003F0000)>>8);
+	temp = temp<<10;
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	temp = temp|((0x05)<<10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/* write address byte 1;*/
+	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+	temp = temp<<10;
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	temp = temp|((0x05)<<10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/* write address byte 0;*/
+	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8);
+	temp = temp<<10;
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	temp = temp|((0x05)<<10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/*wait for MIRDY line;*/
+	waitForMciComplete(dev);
+
+	return 0;
+}
+
+static int mc417_memory_read(struct cx231xx *dev, u32 address, u32 *value)
+{
+	u32 temp = 0;
+	u32 return_value = 0;
+	int ret = 0;
+
+	/*write address byte 2;*/
+	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_READ |
+		((address & 0x003F0000)>>8);
+	temp = temp<<10;
+	ret = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	if (ret < 0)
+		return ret;
+	temp = temp|((0x05)<<10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/*write address byte 1*/
+	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+	temp = temp<<10;
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	temp = temp|((0x05)<<10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/*write address byte 0*/
+	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF)<<8);
+	temp = temp<<10;
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+	temp = temp|((0x05)<<10);
+	setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+	/*Wait for MIRDY line*/
+	ret = waitForMciComplete(dev);
+
+
+	/*Read data byte 3;*/
+	temp = (0x82|MCI_MEMORY_DATA_BYTE3)<<10;
+	setITVCReg(dev, ITVC_READ_DIR, temp);
+	temp = ((0x81|MCI_MEMORY_DATA_BYTE3)<<10);
+	setITVCReg(dev, ITVC_READ_DIR, temp);
+	getITVCReg(dev, ITVC_READ_DIR, &temp);
+	return_value |= ((temp&0x03FC0000)<<6);
+	setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+
+	/*Read data byte 2;*/
+	temp = (0x82|MCI_MEMORY_DATA_BYTE2)<<10;
+	setITVCReg(dev, ITVC_READ_DIR, temp);
+	temp = ((0x81|MCI_MEMORY_DATA_BYTE2)<<10);
+	setITVCReg(dev, ITVC_READ_DIR, temp);
+	getITVCReg(dev, ITVC_READ_DIR, &temp);
+	return_value |= ((temp&0x03FC0000)>>2);
+	setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+
+	/* Read data byte 1;*/
+	temp = (0x82|MCI_MEMORY_DATA_BYTE1)<<10;
+	setITVCReg(dev, ITVC_READ_DIR, temp);
+	temp = ((0x81|MCI_MEMORY_DATA_BYTE1)<<10);
+	setITVCReg(dev, ITVC_READ_DIR, temp);
+	getITVCReg(dev, ITVC_READ_DIR, &temp);
+	return_value |= ((temp&0x03FC0000)>>10);
+	setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+
+	/*Read data byte 0;*/
+	temp = (0x82|MCI_MEMORY_DATA_BYTE0)<<10;
+	setITVCReg(dev, ITVC_READ_DIR, temp);
+	temp = ((0x81|MCI_MEMORY_DATA_BYTE0)<<10);
+	setITVCReg(dev, ITVC_READ_DIR, temp);
+	getITVCReg(dev, ITVC_READ_DIR, &temp);
+	return_value |= ((temp&0x03FC0000)>>18);
+	setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+
+	*value  = return_value;
+	return ret;
+}
+
+/* ------------------------------------------------------------------ */
+
+/* MPEG encoder API */
+static char *cmd_to_str(int cmd)
+{
+	switch (cmd) {
+	case CX2341X_ENC_PING_FW:
+		return  "PING_FW";
+	case CX2341X_ENC_START_CAPTURE:
+		return  "START_CAPTURE";
+	case CX2341X_ENC_STOP_CAPTURE:
+		return  "STOP_CAPTURE";
+	case CX2341X_ENC_SET_AUDIO_ID:
+		return  "SET_AUDIO_ID";
+	case CX2341X_ENC_SET_VIDEO_ID:
+		return  "SET_VIDEO_ID";
+	case CX2341X_ENC_SET_PCR_ID:
+		return  "SET_PCR_PID";
+	case CX2341X_ENC_SET_FRAME_RATE:
+		return  "SET_FRAME_RATE";
+	case CX2341X_ENC_SET_FRAME_SIZE:
+		return  "SET_FRAME_SIZE";
+	case CX2341X_ENC_SET_BIT_RATE:
+		return  "SET_BIT_RATE";
+	case CX2341X_ENC_SET_GOP_PROPERTIES:
+		return  "SET_GOP_PROPERTIES";
+	case CX2341X_ENC_SET_ASPECT_RATIO:
+		return  "SET_ASPECT_RATIO";
+	case CX2341X_ENC_SET_DNR_FILTER_MODE:
+		return  "SET_DNR_FILTER_PROPS";
+	case CX2341X_ENC_SET_DNR_FILTER_PROPS:
+		return  "SET_DNR_FILTER_PROPS";
+	case CX2341X_ENC_SET_CORING_LEVELS:
+		return  "SET_CORING_LEVELS";
+	case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
+		return  "SET_SPATIAL_FILTER_TYPE";
+	case CX2341X_ENC_SET_VBI_LINE:
+		return  "SET_VBI_LINE";
+	case CX2341X_ENC_SET_STREAM_TYPE:
+		return  "SET_STREAM_TYPE";
+	case CX2341X_ENC_SET_OUTPUT_PORT:
+		return  "SET_OUTPUT_PORT";
+	case CX2341X_ENC_SET_AUDIO_PROPERTIES:
+		return  "SET_AUDIO_PROPERTIES";
+	case CX2341X_ENC_HALT_FW:
+		return  "HALT_FW";
+	case CX2341X_ENC_GET_VERSION:
+		return  "GET_VERSION";
+	case CX2341X_ENC_SET_GOP_CLOSURE:
+		return  "SET_GOP_CLOSURE";
+	case CX2341X_ENC_GET_SEQ_END:
+		return  "GET_SEQ_END";
+	case CX2341X_ENC_SET_PGM_INDEX_INFO:
+		return  "SET_PGM_INDEX_INFO";
+	case CX2341X_ENC_SET_VBI_CONFIG:
+		return  "SET_VBI_CONFIG";
+	case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
+		return  "SET_DMA_BLOCK_SIZE";
+	case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
+		return  "GET_PREV_DMA_INFO_MB_10";
+	case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
+		return  "GET_PREV_DMA_INFO_MB_9";
+	case CX2341X_ENC_SCHED_DMA_TO_HOST:
+		return  "SCHED_DMA_TO_HOST";
+	case CX2341X_ENC_INITIALIZE_INPUT:
+		return  "INITIALIZE_INPUT";
+	case CX2341X_ENC_SET_FRAME_DROP_RATE:
+		return  "SET_FRAME_DROP_RATE";
+	case CX2341X_ENC_PAUSE_ENCODER:
+		return  "PAUSE_ENCODER";
+	case CX2341X_ENC_REFRESH_INPUT:
+		return  "REFRESH_INPUT";
+	case CX2341X_ENC_SET_COPYRIGHT:
+		return  "SET_COPYRIGHT";
+	case CX2341X_ENC_SET_EVENT_NOTIFICATION:
+		return  "SET_EVENT_NOTIFICATION";
+	case CX2341X_ENC_SET_NUM_VSYNC_LINES:
+		return  "SET_NUM_VSYNC_LINES";
+	case CX2341X_ENC_SET_PLACEHOLDER:
+		return  "SET_PLACEHOLDER";
+	case CX2341X_ENC_MUTE_VIDEO:
+		return  "MUTE_VIDEO";
+	case CX2341X_ENC_MUTE_AUDIO:
+		return  "MUTE_AUDIO";
+	case CX2341X_ENC_MISC:
+		return  "MISC";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static int cx231xx_mbox_func(void *priv,
+			     u32 command,
+			     int in,
+			     int out,
+			     u32 data[CX2341X_MBOX_MAX_DATA])
+{
+	struct cx231xx *dev = priv;
+	unsigned long timeout;
+	u32 value, flag, retval = 0;
+	int i;
+
+	dprintk(3, "%s: command(0x%X) = %s\n", __func__, command,
+		cmd_to_str(command));
+
+	/* this may not be 100% safe if we can't read any memory location
+	   without side effects */
+	mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
+	if (value != 0x12345678) {
+		dprintk(3,
+			"Firmware and/or mailbox pointer not initialized "
+			"or corrupted, signature = 0x%x, cmd = %s\n", value,
+			cmd_to_str(command));
+		return -1;
+	}
+
+	/* This read looks at 32 bits, but flag is only 8 bits.
+	 * Seems we also bail if CMD or TIMEOUT bytes are set???
+	 */
+	mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+	if (flag) {
+		dprintk(3, "ERROR: Mailbox appears to be in use "
+			"(%x), cmd = %s\n", flag, cmd_to_str(command));
+		return -1;
+	}
+
+	flag |= 1; /* tell 'em we're working on it */
+	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+	/* write command + args + fill remaining with zeros */
+	/* command code */
+	mc417_memory_write(dev, dev->cx23417_mailbox + 1, command);
+	mc417_memory_write(dev, dev->cx23417_mailbox + 3,
+		IVTV_API_STD_TIMEOUT); /* timeout */
+	for (i = 0; i < in; i++) {
+		mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]);
+		dprintk(3, "API Input %d = %d\n", i, data[i]);
+	}
+	for (; i < CX2341X_MBOX_MAX_DATA; i++)
+		mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0);
+
+	flag |= 3; /* tell 'em we're done writing */
+	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+	/* wait for firmware to handle the API command */
+	timeout = jiffies + msecs_to_jiffies(10);
+	for (;;) {
+		mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+		if (0 != (flag & 4))
+			break;
+		if (time_after(jiffies, timeout)) {
+			dprintk(3, "ERROR: API Mailbox timeout\n");
+			return -1;
+		}
+		udelay(10);
+	}
+
+	/* read output values */
+	for (i = 0; i < out; i++) {
+		mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i);
+		dprintk(3, "API Output %d = %d\n", i, data[i]);
+	}
+
+	mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval);
+	dprintk(3, "API result = %d\n", retval);
+
+	flag = 0;
+	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+	return retval;
+}
+
+/* We don't need to call the API often, so using just one
+ * mailbox will probably suffice
+ */
+static int cx231xx_api_cmd(struct cx231xx *dev,
+			   u32 command,
+			   u32 inputcnt,
+			   u32 outputcnt,
+			   ...)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	va_list vargs;
+	int i, err;
+
+	dprintk(3, "%s() cmds = 0x%08x\n", __func__, command);
+
+	va_start(vargs, outputcnt);
+	for (i = 0; i < inputcnt; i++)
+		data[i] = va_arg(vargs, int);
+
+	err = cx231xx_mbox_func(dev, command, inputcnt, outputcnt, data);
+	for (i = 0; i < outputcnt; i++) {
+		int *vptr = va_arg(vargs, int *);
+		*vptr = data[i];
+	}
+	va_end(vargs);
+
+	return err;
+}
+
+static int cx231xx_find_mailbox(struct cx231xx *dev)
+{
+	u32 signature[4] = {
+		0x12345678, 0x34567812, 0x56781234, 0x78123456
+	};
+	int signaturecnt = 0;
+	u32 value;
+	int i;
+	int ret = 0;
+
+	dprintk(2, "%s()\n", __func__);
+
+	for (i = 0; i < 0x100; i++) {/*CX231xx_FIRM_IMAGE_SIZE*/
+		ret = mc417_memory_read(dev, i, &value);
+		if (ret < 0)
+			return ret;
+		if (value == signature[signaturecnt])
+			signaturecnt++;
+		else
+			signaturecnt = 0;
+		if (4 == signaturecnt) {
+			dprintk(1, "Mailbox signature found at 0x%x\n", i+1);
+			return i+1;
+		}
+	}
+	dprintk(3, "Mailbox signature values not found!\n");
+	return -1;
+}
+
+static void mciWriteMemoryToGPIO(struct cx231xx *dev, u32 address, u32 value,
+		u32 *p_fw_image)
+{
+
+	u32 temp = 0;
+	int i = 0;
+
+	temp = 0x82|MCI_MEMORY_DATA_BYTE0|((value&0x000000FF)<<8);
+	temp = temp<<10;
+	*p_fw_image = temp;
+	p_fw_image++;
+	temp = temp|((0x05)<<10);
+	*p_fw_image = temp;
+	p_fw_image++;
+
+	/*write data byte 1;*/
+	temp = 0x82|MCI_MEMORY_DATA_BYTE1|(value&0x0000FF00);
+	temp = temp<<10;
+	*p_fw_image = temp;
+	p_fw_image++;
+	temp = temp|((0x05)<<10);
+	*p_fw_image = temp;
+	p_fw_image++;
+
+	/*write data byte 2;*/
+	temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8);
+	temp = temp<<10;
+	*p_fw_image = temp;
+	p_fw_image++;
+	temp = temp|((0x05)<<10);
+	*p_fw_image = temp;
+	p_fw_image++;
+
+	/*write data byte 3;*/
+	temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16);
+	temp = temp<<10;
+	*p_fw_image = temp;
+	p_fw_image++;
+	temp = temp|((0x05)<<10);
+	*p_fw_image = temp;
+	p_fw_image++;
+
+	/* write address byte 2;*/
+	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
+		((address & 0x003F0000)>>8);
+	temp = temp<<10;
+	*p_fw_image = temp;
+	p_fw_image++;
+	temp = temp|((0x05)<<10);
+	*p_fw_image = temp;
+	p_fw_image++;
+
+	/* write address byte 1;*/
+	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+	temp = temp<<10;
+	*p_fw_image = temp;
+	p_fw_image++;
+	temp = temp|((0x05)<<10);
+	*p_fw_image = temp;
+	p_fw_image++;
+
+	/* write address byte 0;*/
+	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8);
+	temp = temp<<10;
+	*p_fw_image = temp;
+	p_fw_image++;
+	temp = temp|((0x05)<<10);
+	*p_fw_image = temp;
+	p_fw_image++;
+
+	for (i = 0; i < 6; i++) {
+		*p_fw_image = 0xFFFFFFFF;
+		p_fw_image++;
+	}
+}
+
+
+static int cx231xx_load_firmware(struct cx231xx *dev)
+{
+	static const unsigned char magic[8] = {
+		0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
+	};
+	const struct firmware *firmware;
+	int i, retval = 0;
+	u32 value = 0;
+	u32 gpio_output = 0;
+	/*u32 checksum = 0;*/
+	/*u32 *dataptr;*/
+	u32 transfer_size = 0;
+	u32 fw_data = 0;
+	u32 address = 0;
+	/*u32 current_fw[800];*/
+	u32 *p_current_fw, *p_fw;
+	u32 *p_fw_data;
+	int frame = 0;
+	u16 _buffer_size = 4096;
+	u8 *p_buffer;
+
+	p_current_fw = vmalloc(1884180 * 4);
+	p_fw = p_current_fw;
+	if (p_current_fw == NULL) {
+		dprintk(2, "FAIL!!!\n");
+		return -1;
+	}
+
+	p_buffer = vmalloc(4096);
+	if (p_buffer == NULL) {
+		dprintk(2, "FAIL!!!\n");
+		return -1;
+	}
+
+	dprintk(2, "%s()\n", __func__);
+
+	/* Save GPIO settings before reset of APU */
+	retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
+	retval |= mc417_memory_read(dev, 0x900C, &value);
+
+	retval  = mc417_register_write(dev,
+		IVTV_REG_VPU, 0xFFFFFFED);
+	retval |= mc417_register_write(dev,
+		IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+	retval |= mc417_register_write(dev,
+		IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800);
+	retval |= mc417_register_write(dev,
+		IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
+	retval |= mc417_register_write(dev,
+		IVTV_REG_APU, 0);
+
+	if (retval != 0) {
+		printk(KERN_ERR "%s: Error with mc417_register_write\n",
+			__func__);
+		return -1;
+	}
+
+	retval = request_firmware(&firmware, CX231xx_FIRM_IMAGE_NAME,
+				  &dev->udev->dev);
+
+	if (retval != 0) {
+		printk(KERN_ERR
+			"ERROR: Hotplug firmware request failed (%s).\n",
+			CX231xx_FIRM_IMAGE_NAME);
+		printk(KERN_ERR "Please fix your hotplug setup, the board will "
+			"not work without firmware loaded!\n");
+		return -1;
+	}
+
+	if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) {
+		printk(KERN_ERR "ERROR: Firmware size mismatch "
+			"(have %zd, expected %d)\n",
+			firmware->size, CX231xx_FIRM_IMAGE_SIZE);
+		release_firmware(firmware);
+		return -1;
+	}
+
+	if (0 != memcmp(firmware->data, magic, 8)) {
+		printk(KERN_ERR
+			"ERROR: Firmware magic mismatch, wrong file?\n");
+		release_firmware(firmware);
+		return -1;
+	}
+
+	initGPIO(dev);
+
+	/* transfer to the chip */
+	dprintk(2, "Loading firmware to GPIO...\n");
+	p_fw_data = (u32 *)firmware->data;
+	dprintk(2, "firmware->size=%zd\n", firmware->size);
+	for (transfer_size = 0; transfer_size < firmware->size;
+		 transfer_size += 4) {
+		fw_data = *p_fw_data;
+
+		 mciWriteMemoryToGPIO(dev, address, fw_data, p_current_fw);
+		address = address + 1;
+		p_current_fw += 20;
+		p_fw_data += 1;
+	}
+
+	/*download the firmware by ep5-out*/
+
+	for (frame = 0; frame < (int)(CX231xx_FIRM_IMAGE_SIZE*20/_buffer_size);
+	     frame++) {
+		for (i = 0; i < _buffer_size; i++) {
+			*(p_buffer + i) = (u8)(*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x000000FF);
+			i++;
+			*(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x0000FF00) >> 8);
+			i++;
+			*(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x00FF0000) >> 16);
+			i++;
+			*(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0xFF000000) >> 24);
+		}
+		cx231xx_ep5_bulkout(dev, p_buffer, _buffer_size);
+	}
+
+	p_current_fw = p_fw;
+	vfree(p_current_fw);
+	p_current_fw = NULL;
+	uninitGPIO(dev);
+	release_firmware(firmware);
+	dprintk(1, "Firmware upload successful.\n");
+
+	retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
+		IVTV_CMD_HW_BLOCKS_RST);
+	if (retval < 0) {
+		printk(KERN_ERR "%s: Error with mc417_register_write\n",
+			__func__);
+		return retval;
+	}
+	/* F/W power up disturbs the GPIOs, restore state */
+	retval |= mc417_register_write(dev, 0x9020, gpio_output);
+	retval |= mc417_register_write(dev, 0x900C, value);
+
+	retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
+	retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
+
+	if (retval < 0) {
+		printk(KERN_ERR "%s: Error with mc417_register_write\n",
+			__func__);
+		return retval;
+	}
+	return 0;
+}
+
+static void cx231xx_417_check_encoder(struct cx231xx *dev)
+{
+	u32 status, seq;
+
+	status = 0;
+	seq = 0;
+	cx231xx_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq);
+	dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq);
+}
+
+static void cx231xx_codec_settings(struct cx231xx *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+
+	/* assign frame size */
+	cx231xx_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+				dev->ts1.height, dev->ts1.width);
+
+	dev->mpeg_params.width = dev->ts1.width;
+	dev->mpeg_params.height = dev->ts1.height;
+
+	cx2341x_update(dev, cx231xx_mbox_func, NULL, &dev->mpeg_params);
+
+	cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
+	cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
+}
+
+static int cx231xx_initialize_codec(struct cx231xx *dev)
+{
+	int version;
+	int retval;
+	u32 i;
+	u32 val = 0;
+
+	dprintk(1, "%s()\n", __func__);
+	cx231xx_disable656(dev);
+	retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
+	if (retval < 0) {
+		dprintk(2, "%s() PING OK\n", __func__);
+		retval = cx231xx_load_firmware(dev);
+		if (retval < 0) {
+			printk(KERN_ERR "%s() f/w load failed\n", __func__);
+			return retval;
+		}
+		retval = cx231xx_find_mailbox(dev);
+		if (retval < 0) {
+			printk(KERN_ERR "%s() mailbox < 0, error\n",
+				__func__);
+			return -1;
+		}
+		dev->cx23417_mailbox = retval;
+		retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
+		if (retval < 0) {
+			printk(KERN_ERR
+				"ERROR: cx23417 firmware ping failed!\n");
+			return -1;
+		}
+		retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
+			&version);
+		if (retval < 0) {
+			printk(KERN_ERR "ERROR: cx23417 firmware get encoder :"
+				"version failed!\n");
+			return -1;
+		}
+		dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
+		msleep(200);
+	}
+
+	for (i = 0; i < 1; i++) {
+		retval = mc417_register_read(dev, 0x20f8, &val);
+		dprintk(3, "***before enable656() VIM Capture Lines =%d ***\n",
+				 val);
+		if (retval < 0)
+			return retval;
+	}
+
+	cx231xx_enable656(dev);
+			/* stop mpeg capture */
+			cx231xx_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE,
+				 3, 0, 1, 3, 4);
+
+	cx231xx_codec_settings(dev);
+	msleep(60);
+
+/*	cx231xx_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
+		CX231xx_FIELD1_SAA7115, CX231xx_FIELD2_SAA7115);
+	cx231xx_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
+		CX231xx_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0);
+*/
+
+#if 0
+	/* TODO */
+	u32 data[7];
+
+	/* Setup to capture VBI */
+	data[0] = 0x0001BD00;
+	data[1] = 1;          /* frames per interrupt */
+	data[2] = 4;          /* total bufs */
+	data[3] = 0x91559155; /* start codes */
+	data[4] = 0x206080C0; /* stop codes */
+	data[5] = 6;          /* lines */
+	data[6] = 64;         /* BPL */
+
+	cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
+		data[2], data[3], data[4], data[5], data[6]);
+
+	for (i = 2; i <= 24; i++) {
+		int valid;
+
+		valid = ((i >= 19) && (i <= 21));
+		cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i,
+				valid, 0 , 0, 0);
+		cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
+				i | 0x80000000, valid, 0, 0, 0);
+	}
+#endif
+/*	cx231xx_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX231xx_UNMUTE);
+	msleep(60);
+*/
+	/* initialize the video input */
+	retval = cx231xx_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
+	if (retval < 0)
+		return retval;
+	msleep(60);
+
+	/* Enable VIP style pixel invalidation so we work with scaled mode */
+	mc417_memory_write(dev, 2120, 0x00000080);
+
+	/* start capturing to the host interface */
+	retval = cx231xx_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
+		CX231xx_MPEG_CAPTURE, CX231xx_RAW_BITS_NONE);
+	if (retval < 0)
+		return retval;
+	msleep(10);
+
+	for (i = 0; i < 1; i++) {
+		mc417_register_read(dev, 0x20f8, &val);
+	dprintk(3, "***VIM Capture Lines =%d ***\n", val);
+	}
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int bb_buf_setup(struct videobuf_queue *q,
+	unsigned int *count, unsigned int *size)
+{
+	struct cx231xx_fh *fh = q->priv_data;
+
+	fh->dev->ts1.ts_packet_size  = mpeglinesize;
+	fh->dev->ts1.ts_packet_count = mpeglines;
+
+	*size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
+	*count = mpegbufs;
+
+	return 0;
+}
+static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
+{
+	struct cx231xx_fh *fh = vq->priv_data;
+	struct cx231xx *dev = fh->dev;
+	unsigned long flags = 0;
+
+	if (in_interrupt())
+		BUG();
+
+	spin_lock_irqsave(&dev->video_mode.slock, flags);
+	if (dev->USE_ISO) {
+		if (dev->video_mode.isoc_ctl.buf == buf)
+			dev->video_mode.isoc_ctl.buf = NULL;
+	} else {
+		if (dev->video_mode.bulk_ctl.buf == buf)
+			dev->video_mode.bulk_ctl.buf = NULL;
+	}
+	spin_unlock_irqrestore(&dev->video_mode.slock, flags);
+	videobuf_waiton(vq, &buf->vb, 0, 0);
+	videobuf_vmalloc_free(&buf->vb);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *urb,
+		struct cx231xx_dmaqueue *dma_q)
+{
+		void *vbuf;
+		struct cx231xx_buffer *buf;
+		u32 tail_data = 0;
+		char *p_data;
+
+		if (dma_q->mpeg_buffer_done == 0) {
+			if (list_empty(&dma_q->active))
+				return;
+
+			buf = list_entry(dma_q->active.next,
+					struct cx231xx_buffer, vb.queue);
+			dev->video_mode.isoc_ctl.buf = buf;
+			dma_q->mpeg_buffer_done = 1;
+		}
+		/* Fill buffer */
+		buf = dev->video_mode.isoc_ctl.buf;
+		vbuf = videobuf_to_vmalloc(&buf->vb);
+
+		if ((dma_q->mpeg_buffer_completed+len) <
+		   mpeglines*mpeglinesize) {
+			if (dma_q->add_ps_package_head ==
+			   CX231XX_NEED_ADD_PS_PACKAGE_HEAD) {
+				memcpy(vbuf+dma_q->mpeg_buffer_completed,
+				       dma_q->ps_head, 3);
+				dma_q->mpeg_buffer_completed =
+				  dma_q->mpeg_buffer_completed + 3;
+				dma_q->add_ps_package_head =
+				  CX231XX_NONEED_PS_PACKAGE_HEAD;
+			}
+			memcpy(vbuf+dma_q->mpeg_buffer_completed, data, len);
+			dma_q->mpeg_buffer_completed =
+			  dma_q->mpeg_buffer_completed + len;
+		} else {
+			dma_q->mpeg_buffer_done = 0;
+
+			tail_data =
+			  mpeglines*mpeglinesize - dma_q->mpeg_buffer_completed;
+			memcpy(vbuf+dma_q->mpeg_buffer_completed,
+			       data, tail_data);
+
+			buf->vb.state = VIDEOBUF_DONE;
+			buf->vb.field_count++;
+			do_gettimeofday(&buf->vb.ts);
+			list_del(&buf->vb.queue);
+			wake_up(&buf->vb.done);
+			dma_q->mpeg_buffer_completed = 0;
+
+			if (len - tail_data > 0) {
+				p_data = data + tail_data;
+				dma_q->left_data_count = len - tail_data;
+				memcpy(dma_q->p_left_data,
+				       p_data, len - tail_data);
+			}
+
+		}
+
+	    return;
+}
+
+static void buffer_filled(char *data, int len, struct urb *urb,
+		struct cx231xx_dmaqueue *dma_q)
+{
+		void *vbuf;
+		struct cx231xx_buffer *buf;
+
+		if (list_empty(&dma_q->active))
+			return;
+
+
+		buf = list_entry(dma_q->active.next,
+				 struct cx231xx_buffer, vb.queue);
+
+
+		/* Fill buffer */
+		vbuf = videobuf_to_vmalloc(&buf->vb);
+		memcpy(vbuf, data, len);
+		buf->vb.state = VIDEOBUF_DONE;
+		buf->vb.field_count++;
+		do_gettimeofday(&buf->vb.ts);
+		list_del(&buf->vb.queue);
+		wake_up(&buf->vb.done);
+
+	    return;
+}
+static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
+{
+	struct cx231xx_dmaqueue *dma_q = urb->context;
+	unsigned char *p_buffer;
+	u32 buffer_size = 0;
+	u32 i = 0;
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		if (dma_q->left_data_count > 0) {
+			buffer_copy(dev, dma_q->p_left_data,
+				    dma_q->left_data_count, urb, dma_q);
+			dma_q->mpeg_buffer_completed = dma_q->left_data_count;
+			dma_q->left_data_count = 0;
+		}
+
+		p_buffer = urb->transfer_buffer +
+				urb->iso_frame_desc[i].offset;
+		buffer_size = urb->iso_frame_desc[i].actual_length;
+
+		if (buffer_size > 0)
+			buffer_copy(dev, p_buffer, buffer_size, urb, dma_q);
+	}
+
+	return 0;
+}
+static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
+{
+
+	/*char *outp;*/
+	/*struct cx231xx_buffer *buf;*/
+	struct cx231xx_dmaqueue *dma_q = urb->context;
+	unsigned char *p_buffer, *buffer;
+	u32 buffer_size = 0;
+
+	p_buffer = urb->transfer_buffer;
+	buffer_size = urb->actual_length;
+
+	buffer = kmalloc(buffer_size, GFP_ATOMIC);
+
+	memcpy(buffer, dma_q->ps_head, 3);
+	memcpy(buffer+3, p_buffer, buffer_size-3);
+	memcpy(dma_q->ps_head, p_buffer+buffer_size-3, 3);
+
+	p_buffer = buffer;
+	buffer_filled(p_buffer, buffer_size, urb, dma_q);
+
+	kfree(buffer);
+	return 0;
+}
+
+static int bb_buf_prepare(struct videobuf_queue *q,
+	struct videobuf_buffer *vb, enum v4l2_field field)
+{
+	struct cx231xx_fh *fh = q->priv_data;
+	struct cx231xx_buffer *buf =
+	    container_of(vb, struct cx231xx_buffer, vb);
+	struct cx231xx *dev = fh->dev;
+	int rc = 0, urb_init = 0;
+	int size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
+
+	dma_qq = &dev->video_mode.vidq;
+
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+		return -EINVAL;
+	buf->vb.width = fh->dev->ts1.ts_packet_size;
+	buf->vb.height = fh->dev->ts1.ts_packet_count;
+	buf->vb.size = size;
+	buf->vb.field = field;
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		rc = videobuf_iolock(q, &buf->vb, NULL);
+		if (rc < 0)
+			goto fail;
+	}
+
+	if (dev->USE_ISO) {
+		if (!dev->video_mode.isoc_ctl.num_bufs)
+			urb_init = 1;
+	} else {
+		if (!dev->video_mode.bulk_ctl.num_bufs)
+			urb_init = 1;
+	}
+	/*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n",
+		urb_init, dev->video_mode.max_pkt_size);*/
+	dev->mode_tv = 1;
+
+	if (urb_init) {
+		rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+		rc = cx231xx_unmute_audio(dev);
+		if (dev->USE_ISO) {
+			cx231xx_set_alt_setting(dev, INDEX_TS1, 4);
+			rc = cx231xx_init_isoc(dev, mpeglines,
+				       mpegbufs,
+				       dev->ts1_mode.max_pkt_size,
+				       cx231xx_isoc_copy);
+		} else {
+			cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
+			rc = cx231xx_init_bulk(dev, mpeglines,
+				       mpegbufs,
+				       dev->ts1_mode.max_pkt_size,
+				       cx231xx_bulk_copy);
+		}
+		if (rc < 0)
+			goto fail;
+	}
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+fail:
+	free_buffer(q, buf);
+	return rc;
+}
+
+static void bb_buf_queue(struct videobuf_queue *q,
+	struct videobuf_buffer *vb)
+{
+	struct cx231xx_fh *fh = q->priv_data;
+
+	struct cx231xx_buffer *buf =
+	    container_of(vb, struct cx231xx_buffer, vb);
+	struct cx231xx *dev = fh->dev;
+	struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
+
+	buf->vb.state = VIDEOBUF_QUEUED;
+	list_add_tail(&buf->vb.queue, &vidq->active);
+
+}
+
+static void bb_buf_release(struct videobuf_queue *q,
+	struct videobuf_buffer *vb)
+{
+	struct cx231xx_buffer *buf =
+	    container_of(vb, struct cx231xx_buffer, vb);
+	/*struct cx231xx_fh *fh = q->priv_data;*/
+	/*struct cx231xx *dev = (struct cx231xx *)fh->dev;*/
+
+	free_buffer(q, buf);
+}
+
+static struct videobuf_queue_ops cx231xx_qops = {
+	.buf_setup    = bb_buf_setup,
+	.buf_prepare  = bb_buf_prepare,
+	.buf_queue    = bb_buf_queue,
+	.buf_release  = bb_buf_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+static const u32 *ctrl_classes[] = {
+	cx2341x_mpeg_ctrls,
+	NULL
+};
+
+static int cx231xx_queryctrl(struct cx231xx *dev,
+	struct v4l2_queryctrl *qctrl)
+{
+	qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+	if (qctrl->id == 0)
+		return -EINVAL;
+
+	/* MPEG V4L2 controls */
+	if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
+		qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+
+	return 0;
+}
+
+static int cx231xx_querymenu(struct cx231xx *dev,
+	struct v4l2_querymenu *qmenu)
+{
+	struct v4l2_queryctrl qctrl;
+
+	qctrl.id = qmenu->id;
+	cx231xx_queryctrl(dev, &qctrl);
+	return v4l2_ctrl_query_menu(qmenu, &qctrl,
+		cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id));
+}
+
+static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm)
+{
+	struct cx231xx_fh  *fh  = file->private_data;
+	struct cx231xx *dev = fh->dev;
+
+	*norm = dev->encodernorm.id;
+	return 0;
+}
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct cx231xx_fh  *fh  = file->private_data;
+	struct cx231xx *dev = fh->dev;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(cx231xx_tvnorms); i++)
+		if (*id & cx231xx_tvnorms[i].id)
+			break;
+	if (i == ARRAY_SIZE(cx231xx_tvnorms))
+		return -EINVAL;
+	dev->encodernorm = cx231xx_tvnorms[i];
+
+	if (dev->encodernorm.id & 0xb000) {
+		dprintk(3, "encodernorm set to NTSC\n");
+		dev->norm = V4L2_STD_NTSC;
+		dev->ts1.height = 480;
+		dev->mpeg_params.is_50hz = 0;
+	} else {
+		dprintk(3, "encodernorm set to PAL\n");
+		dev->norm = V4L2_STD_PAL_B;
+		dev->ts1.height = 576;
+		dev->mpeg_params.is_50hz = 1;
+	}
+	call_all(dev, core, s_std, dev->norm);
+	/* do mode control overrides */
+	cx231xx_do_mode_ctrl_overrides(dev);
+
+	dprintk(3, "exit vidioc_s_std() i=0x%x\n", i);
+	return 0;
+}
+static int vidioc_g_audio(struct file *file, void *fh,
+					struct v4l2_audio *a)
+{
+		struct v4l2_audio *vin = a;
+
+		int ret = -EINVAL;
+		if (vin->index > 0)
+			return ret;
+		strncpy(vin->name, "VideoGrabber Audio", 14);
+		vin->capability = V4L2_AUDCAP_STEREO;
+return 0;
+}
+static int vidioc_enumaudio(struct file *file, void *fh,
+					struct v4l2_audio *a)
+{
+		struct v4l2_audio *vin = a;
+
+		int ret = -EINVAL;
+
+		if (vin->index > 0)
+			return ret;
+		strncpy(vin->name, "VideoGrabber Audio", 14);
+		vin->capability = V4L2_AUDCAP_STEREO;
+
+
+return 0;
+}
+static const char *iname[] = {
+	[CX231XX_VMUX_COMPOSITE1] = "Composite1",
+	[CX231XX_VMUX_SVIDEO]     = "S-Video",
+	[CX231XX_VMUX_TELEVISION] = "Television",
+	[CX231XX_VMUX_CABLE]      = "Cable TV",
+	[CX231XX_VMUX_DVB]        = "DVB",
+	[CX231XX_VMUX_DEBUG]      = "for debug only",
+};
+static int vidioc_enum_input(struct file *file, void *priv,
+				struct v4l2_input *i)
+{
+	struct cx231xx_fh  *fh  = file->private_data;
+	struct cx231xx *dev = fh->dev;
+	struct cx231xx_input *input;
+	int n;
+	dprintk(3, "enter vidioc_enum_input()i->index=%d\n", i->index);
+
+	if (i->index >= 4)
+		return -EINVAL;
+
+
+	input = &cx231xx_boards[dev->model].input[i->index];
+
+	if (input->type == 0)
+		return -EINVAL;
+
+	/* FIXME
+	 * strcpy(i->name, input->name); */
+
+	n = i->index;
+	strcpy(i->name, iname[INPUT(n)->type]);
+
+	if (input->type == CX231XX_VMUX_TELEVISION ||
+	    input->type == CX231XX_VMUX_CABLE)
+		i->type = V4L2_INPUT_TYPE_TUNER;
+	else
+		i->type  = V4L2_INPUT_TYPE_CAMERA;
+
+
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return  0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct cx231xx_fh  *fh  = file->private_data;
+	struct cx231xx *dev = fh->dev;
+
+	dprintk(3, "enter vidioc_s_input() i=%d\n", i);
+
+	mutex_lock(&dev->lock);
+
+	video_mux(dev, i);
+
+	mutex_unlock(&dev->lock);
+
+	if (i >= 4)
+		return -EINVAL;
+	dev->input = i;
+	dprintk(3, "exit vidioc_s_input()\n");
+	return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+
+
+	return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctl)
+{
+	struct cx231xx_fh  *fh  = file->private_data;
+	struct cx231xx *dev = fh->dev;
+	dprintk(3, "enter vidioc_s_ctrl()\n");
+	/* Update the A/V core */
+	call_all(dev, core, s_ctrl, ctl);
+	dprintk(3, "exit vidioc_s_ctrl()\n");
+	return 0;
+}
+static struct v4l2_capability pvr_capability = {
+	.driver         = "cx231xx",
+	.card           = "VideoGrabber",
+	.bus_info       = "usb",
+	.version        = 1,
+	.capabilities   = (V4L2_CAP_VIDEO_CAPTURE |
+			   V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
+			 V4L2_CAP_STREAMING | V4L2_CAP_READWRITE),
+};
+static int vidioc_querycap(struct file *file, void  *priv,
+				struct v4l2_capability *cap)
+{
+
+
+
+		memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+
+	if (f->index != 0)
+		return -EINVAL;
+
+	strlcpy(f->description, "MPEG", sizeof(f->description));
+	f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct cx231xx_fh  *fh  = file->private_data;
+	struct cx231xx *dev = fh->dev;
+	dprintk(3, "enter vidioc_g_fmt_vid_cap()\n");
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage    =
+		dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+	f->fmt.pix.colorspace   = 0;
+	f->fmt.pix.width        = dev->ts1.width;
+	f->fmt.pix.height       = dev->ts1.height;
+	f->fmt.pix.field        = fh->vidq.field;
+	dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+		dev->ts1.width, dev->ts1.height, fh->vidq.field);
+	dprintk(3, "exit vidioc_g_fmt_vid_cap()\n");
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct cx231xx_fh  *fh  = file->private_data;
+	struct cx231xx *dev = fh->dev;
+	dprintk(3, "enter vidioc_try_fmt_vid_cap()\n");
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage    =
+		dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+	f->fmt.pix.colorspace   = 0;
+	dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+		dev->ts1.width, dev->ts1.height, fh->vidq.field);
+	dprintk(3, "exit vidioc_try_fmt_vid_cap()\n");
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+
+	return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+				struct v4l2_requestbuffers *p)
+{
+	struct cx231xx_fh  *fh  = file->private_data;
+
+	return videobuf_reqbufs(&fh->vidq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+				struct v4l2_buffer *p)
+{
+	struct cx231xx_fh  *fh  = file->private_data;
+
+	return videobuf_querybuf(&fh->vidq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv,
+				struct v4l2_buffer *p)
+{
+	struct cx231xx_fh  *fh  = file->private_data;
+
+	return videobuf_qbuf(&fh->vidq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct cx231xx_fh  *fh  = priv;
+
+	return videobuf_dqbuf(&fh->vidq, b, file->f_flags & O_NONBLOCK);
+}
+
+
+static int vidioc_streamon(struct file *file, void *priv,
+				enum v4l2_buf_type i)
+{
+	struct cx231xx_fh  *fh  = file->private_data;
+
+	struct cx231xx *dev = fh->dev;
+	dprintk(3, "enter vidioc_streamon()\n");
+		cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
+		cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+		if (dev->USE_ISO)
+			cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
+				       CX231XX_NUM_BUFS,
+				       dev->video_mode.max_pkt_size,
+				       cx231xx_isoc_copy);
+		else {
+			cx231xx_init_bulk(dev, 320,
+				       5,
+				       dev->ts1_mode.max_pkt_size,
+				       cx231xx_bulk_copy);
+		}
+	dprintk(3, "exit vidioc_streamon()\n");
+	return videobuf_streamon(&fh->vidq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct cx231xx_fh  *fh  = file->private_data;
+
+	return videobuf_streamoff(&fh->vidq);
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+				struct v4l2_ext_controls *f)
+{
+	struct cx231xx_fh  *fh  = priv;
+	struct cx231xx *dev = fh->dev;
+	dprintk(3, "enter vidioc_g_ext_ctrls()\n");
+	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+		return -EINVAL;
+	dprintk(3, "exit vidioc_g_ext_ctrls()\n");
+	return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS);
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+				struct v4l2_ext_controls *f)
+{
+	struct cx231xx_fh  *fh  = priv;
+	struct cx231xx *dev = fh->dev;
+	struct cx2341x_mpeg_params p;
+	int err;
+	dprintk(3, "enter vidioc_s_ext_ctrls()\n");
+	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+		return -EINVAL;
+
+	p = dev->mpeg_params;
+	err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
+	if (err == 0) {
+		err = cx2341x_update(dev, cx231xx_mbox_func,
+			&dev->mpeg_params, &p);
+		dev->mpeg_params = p;
+	}
+
+	return err;
+
+
+return 0;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+				struct v4l2_ext_controls *f)
+{
+	struct cx231xx_fh  *fh  = priv;
+	struct cx231xx *dev = fh->dev;
+	struct cx2341x_mpeg_params p;
+	int err;
+	dprintk(3, "enter vidioc_try_ext_ctrls()\n");
+	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+		return -EINVAL;
+
+	p = dev->mpeg_params;
+	err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
+	dprintk(3, "exit vidioc_try_ext_ctrls() err=%d\n", err);
+	return err;
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+	struct cx231xx_fh  *fh  = priv;
+	struct cx231xx *dev = fh->dev;
+	char name[32 + 2];
+
+	snprintf(name, sizeof(name), "%s/2", dev->name);
+	dprintk(3,
+		"%s/2: ============  START LOG STATUS  ============\n",
+	       dev->name);
+	call_all(dev, core, log_status);
+	cx2341x_log_status(&dev->mpeg_params, name);
+	dprintk(3,
+		"%s/2: =============  END LOG STATUS  =============\n",
+	       dev->name);
+	return 0;
+}
+
+static int vidioc_querymenu(struct file *file, void *priv,
+				struct v4l2_querymenu *a)
+{
+	struct cx231xx_fh  *fh  = priv;
+	struct cx231xx *dev = fh->dev;
+	dprintk(3, "enter vidioc_querymenu()\n");
+	dprintk(3, "exit vidioc_querymenu()\n");
+	return cx231xx_querymenu(dev, a);
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+				struct v4l2_queryctrl *c)
+{
+	struct cx231xx_fh  *fh  = priv;
+	struct cx231xx *dev = fh->dev;
+	dprintk(3, "enter vidioc_queryctrl()\n");
+	dprintk(3, "exit vidioc_queryctrl()\n");
+	return cx231xx_queryctrl(dev, c);
+}
+
+static int mpeg_open(struct file *file)
+{
+	int minor = video_devdata(file)->minor;
+	struct cx231xx *h, *dev = NULL;
+	/*struct list_head *list;*/
+	struct cx231xx_fh *fh;
+	/*u32 value = 0;*/
+
+	dprintk(2, "%s()\n", __func__);
+
+	list_for_each_entry(h, &cx231xx_devlist, devlist) {
+		if (h->v4l_device->minor == minor)
+			dev = h;
+	}
+
+	if (dev == NULL)
+		return -ENODEV;
+
+	mutex_lock(&dev->lock);
+
+	/* allocate + initialize per filehandle data */
+	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+	if (NULL == fh) {
+		mutex_unlock(&dev->lock);
+		return -ENOMEM;
+	}
+
+	file->private_data = fh;
+	fh->dev      = dev;
+
+
+	videobuf_queue_vmalloc_init(&fh->vidq, &cx231xx_qops,
+			    NULL, &dev->video_mode.slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED,
+			    sizeof(struct cx231xx_buffer), fh, NULL);
+/*
+	videobuf_queue_sg_init(&fh->vidq, &cx231xx_qops,
+			    &dev->udev->dev, &dev->ts1.slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			    V4L2_FIELD_INTERLACED,
+			    sizeof(struct cx231xx_buffer),
+			    fh, NULL);
+*/
+
+
+	cx231xx_set_alt_setting(dev, INDEX_VANC, 1);
+	cx231xx_set_gpio_value(dev, 2, 0);
+
+	cx231xx_initialize_codec(dev);
+
+	mutex_unlock(&dev->lock);
+	cx231xx_start_TS1(dev);
+
+	return 0;
+}
+
+static int mpeg_release(struct file *file)
+{
+	struct cx231xx_fh  *fh  = file->private_data;
+	struct cx231xx *dev = fh->dev;
+
+	dprintk(3, "mpeg_release()! dev=0x%p\n", dev);
+
+	if (!dev) {
+		dprintk(3, "abort!!!\n");
+		return 0;
+	}
+
+	mutex_lock(&dev->lock);
+
+	cx231xx_stop_TS1(dev);
+
+		/* do this before setting alternate! */
+		if (dev->USE_ISO)
+			cx231xx_uninit_isoc(dev);
+		else
+			cx231xx_uninit_bulk(dev);
+		cx231xx_set_mode(dev, CX231XX_SUSPEND);
+
+		cx231xx_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+				CX231xx_END_NOW, CX231xx_MPEG_CAPTURE,
+				CX231xx_RAW_BITS_NONE);
+
+	/* FIXME: Review this crap */
+	/* Shut device down on last close */
+	if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
+		if (atomic_dec_return(&dev->v4l_reader_count) == 0) {
+			/* stop mpeg capture */
+
+			msleep(500);
+			cx231xx_417_check_encoder(dev);
+
+		}
+	}
+
+	if (fh->vidq.streaming)
+		videobuf_streamoff(&fh->vidq);
+	if (fh->vidq.reading)
+		videobuf_read_stop(&fh->vidq);
+
+	videobuf_mmap_free(&fh->vidq);
+	file->private_data = NULL;
+	kfree(fh);
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static ssize_t mpeg_read(struct file *file, char __user *data,
+	size_t count, loff_t *ppos)
+{
+	struct cx231xx_fh *fh = file->private_data;
+	struct cx231xx *dev = fh->dev;
+
+
+	/* Deal w/ A/V decoder * and mpeg encoder sync issues. */
+	/* Start mpeg encoder on first read. */
+	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+		if (atomic_inc_return(&dev->v4l_reader_count) == 1) {
+			if (cx231xx_initialize_codec(dev) < 0)
+				return -EINVAL;
+		}
+	}
+
+	return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
+				    file->f_flags & O_NONBLOCK);
+}
+
+static unsigned int mpeg_poll(struct file *file,
+	struct poll_table_struct *wait)
+{
+	struct cx231xx_fh *fh = file->private_data;
+	/*struct cx231xx *dev = fh->dev;*/
+
+	/*dprintk(2, "%s\n", __func__);*/
+
+	return videobuf_poll_stream(file, &fh->vidq, wait);
+}
+
+static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct cx231xx_fh *fh = file->private_data;
+	struct cx231xx *dev = fh->dev;
+
+	dprintk(2, "%s()\n", __func__);
+
+	return videobuf_mmap_mapper(&fh->vidq, vma);
+}
+
+static struct v4l2_file_operations mpeg_fops = {
+	.owner	       = THIS_MODULE,
+	.open	       = mpeg_open,
+	.release       = mpeg_release,
+	.read	       = mpeg_read,
+	.poll          = mpeg_poll,
+	.mmap	       = mpeg_mmap,
+	.ioctl	       = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
+	.vidioc_s_std		 = vidioc_s_std,
+	.vidioc_g_std		 = vidioc_g_std,
+	.vidioc_enum_input	 = vidioc_enum_input,
+	.vidioc_enumaudio	 = vidioc_enumaudio,
+	.vidioc_g_audio		 = vidioc_g_audio,
+	.vidioc_g_input		 = vidioc_g_input,
+	.vidioc_s_input		 = vidioc_s_input,
+	.vidioc_g_tuner		 = vidioc_g_tuner,
+	.vidioc_s_tuner		 = vidioc_s_tuner,
+	.vidioc_g_frequency	 = vidioc_g_frequency,
+	.vidioc_s_frequency	 = vidioc_s_frequency,
+	.vidioc_s_ctrl		 = vidioc_s_ctrl,
+	.vidioc_querycap	 = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	 = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	 = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	 = vidioc_s_fmt_vid_cap,
+	.vidioc_reqbufs		 = vidioc_reqbufs,
+	.vidioc_querybuf	 = vidioc_querybuf,
+	.vidioc_qbuf		 = vidioc_qbuf,
+	.vidioc_dqbuf		 = vidioc_dqbuf,
+	.vidioc_streamon	 = vidioc_streamon,
+	.vidioc_streamoff	 = vidioc_streamoff,
+	.vidioc_g_ext_ctrls	 = vidioc_g_ext_ctrls,
+	.vidioc_s_ext_ctrls	 = vidioc_s_ext_ctrls,
+	.vidioc_try_ext_ctrls	 = vidioc_try_ext_ctrls,
+	.vidioc_log_status	 = vidioc_log_status,
+	.vidioc_querymenu	 = vidioc_querymenu,
+	.vidioc_queryctrl	 = vidioc_queryctrl,
+/*	.vidioc_g_chip_ident	 = cx231xx_g_chip_ident,*/
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/*	.vidioc_g_register	 = cx231xx_g_register,*/
+/*	.vidioc_s_register	 = cx231xx_s_register,*/
+#endif
+};
+
+static struct video_device cx231xx_mpeg_template = {
+	.name          = "cx231xx",
+	.fops          = &mpeg_fops,
+	.ioctl_ops     = &mpeg_ioctl_ops,
+	.minor         = -1,
+	.tvnorms       = CX231xx_NORMS,
+	.current_norm  = V4L2_STD_NTSC_M,
+};
+
+void cx231xx_417_unregister(struct cx231xx *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+	dprintk(3, "%s()\n", __func__);
+
+	if (dev->v4l_device) {
+		if (-1 != dev->v4l_device->minor)
+			video_unregister_device(dev->v4l_device);
+		else
+			video_device_release(dev->v4l_device);
+		dev->v4l_device = NULL;
+	}
+}
+
+static struct video_device *cx231xx_video_dev_alloc(
+	struct cx231xx *dev,
+	struct usb_device *usbdev,
+	struct video_device *template,
+	char *type)
+{
+	struct video_device *vfd;
+
+	dprintk(1, "%s()\n", __func__);
+	vfd = video_device_alloc();
+	if (NULL == vfd)
+		return NULL;
+	*vfd = *template;
+	vfd->minor = -1;
+	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
+		type, cx231xx_boards[dev->model].name);
+
+	vfd->v4l2_dev = &dev->v4l2_dev;
+	vfd->release = video_device_release;
+
+	return vfd;
+
+}
+
+int cx231xx_417_register(struct cx231xx *dev)
+{
+	/* FIXME: Port1 hardcoded here */
+	int err = -ENODEV;
+	struct cx231xx_tsport *tsport = &dev->ts1;
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* Set default TV standard */
+	dev->encodernorm = cx231xx_tvnorms[0];
+
+	if (dev->encodernorm.id & V4L2_STD_525_60)
+		tsport->height = 480;
+	else
+		tsport->height = 576;
+
+	tsport->width = 720;
+	cx2341x_fill_defaults(&dev->mpeg_params);
+	dev->norm = V4L2_STD_NTSC;
+
+	dev->mpeg_params.port = CX2341X_PORT_SERIAL;
+
+	/* Allocate and initialize V4L video device */
+	dev->v4l_device = cx231xx_video_dev_alloc(dev,
+		dev->udev, &cx231xx_mpeg_template, "mpeg");
+	err = video_register_device(dev->v4l_device,
+		VFL_TYPE_GRABBER, -1);
+	if (err < 0) {
+		dprintk(3, "%s: can't register mpeg device\n", dev->name);
+		return err;
+	}
+
+	dprintk(3, "%s: registered device video%d [mpeg]\n",
+	       dev->name, dev->v4l_device->num);
+
+	return 0;
+}
+
+MODULE_FIRMWARE(CX231xx_FIRM_IMAGE_NAME);
diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c
new file mode 100644
index 0000000..b4c99c7
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-audio.c
@@ -0,0 +1,780 @@
+/*
+ *  Conexant Cx231xx audio extension
+ *
+ *  Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+ *       Based on em28xx driver
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/init.h>
+#include <linux/sound.h>
+#include <linux/spinlock.h>
+#include <linux/soundcard.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <media/v4l2-common.h>
+#include "cx231xx.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "activates debug info");
+
+#define dprintk(fmt, arg...) do {					\
+		if (debug)						\
+			printk(KERN_INFO "cx231xx-audio %s: " fmt,	\
+				__func__, ##arg); 			\
+	} while (0)
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+
+static int cx231xx_isoc_audio_deinit(struct cx231xx *dev)
+{
+	int i;
+
+	dprintk("Stopping isoc\n");
+
+	for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
+		if (dev->adev.urb[i]) {
+			if (!irqs_disabled())
+				usb_kill_urb(dev->adev.urb[i]);
+			else
+				usb_unlink_urb(dev->adev.urb[i]);
+
+			usb_free_urb(dev->adev.urb[i]);
+			dev->adev.urb[i] = NULL;
+
+			kfree(dev->adev.transfer_buffer[i]);
+			dev->adev.transfer_buffer[i] = NULL;
+		}
+	}
+
+	return 0;
+}
+
+static int cx231xx_bulk_audio_deinit(struct cx231xx *dev)
+{
+	int i;
+
+	dprintk("Stopping bulk\n");
+
+	for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
+		if (dev->adev.urb[i]) {
+			if (!irqs_disabled())
+				usb_kill_urb(dev->adev.urb[i]);
+			else
+				usb_unlink_urb(dev->adev.urb[i]);
+
+			usb_free_urb(dev->adev.urb[i]);
+			dev->adev.urb[i] = NULL;
+
+			kfree(dev->adev.transfer_buffer[i]);
+			dev->adev.transfer_buffer[i] = NULL;
+		}
+	}
+
+	return 0;
+}
+
+static void cx231xx_audio_isocirq(struct urb *urb)
+{
+	struct cx231xx *dev = urb->context;
+	int i;
+	unsigned int oldptr;
+	int period_elapsed = 0;
+	int status;
+	unsigned char *cp;
+	unsigned int stride;
+	struct snd_pcm_substream *substream;
+	struct snd_pcm_runtime *runtime;
+
+	if (dev->state & DEV_DISCONNECTED)
+		return;
+
+	switch (urb->status) {
+	case 0:		/* success */
+	case -ETIMEDOUT:	/* NAK */
+		break;
+	case -ECONNRESET:	/* kill */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	default:		/* error */
+		dprintk("urb completition error %d.\n", urb->status);
+		break;
+	}
+
+	if (atomic_read(&dev->stream_started) == 0)
+		return;
+
+	if (dev->adev.capture_pcm_substream) {
+		substream = dev->adev.capture_pcm_substream;
+		runtime = substream->runtime;
+		stride = runtime->frame_bits >> 3;
+
+		for (i = 0; i < urb->number_of_packets; i++) {
+			int length = urb->iso_frame_desc[i].actual_length /
+				     stride;
+			cp = (unsigned char *)urb->transfer_buffer +
+					      urb->iso_frame_desc[i].offset;
+
+			if (!length)
+				continue;
+
+			oldptr = dev->adev.hwptr_done_capture;
+			if (oldptr + length >= runtime->buffer_size) {
+				unsigned int cnt;
+
+				cnt = runtime->buffer_size - oldptr;
+				memcpy(runtime->dma_area + oldptr * stride, cp,
+				       cnt * stride);
+				memcpy(runtime->dma_area, cp + cnt * stride,
+				       length * stride - cnt * stride);
+			} else {
+				memcpy(runtime->dma_area + oldptr * stride, cp,
+				       length * stride);
+			}
+
+			snd_pcm_stream_lock(substream);
+
+			dev->adev.hwptr_done_capture += length;
+			if (dev->adev.hwptr_done_capture >=
+						runtime->buffer_size)
+				dev->adev.hwptr_done_capture -=
+						runtime->buffer_size;
+
+			dev->adev.capture_transfer_done += length;
+			if (dev->adev.capture_transfer_done >=
+				runtime->period_size) {
+				dev->adev.capture_transfer_done -=
+						runtime->period_size;
+				period_elapsed = 1;
+			}
+			snd_pcm_stream_unlock(substream);
+		}
+		if (period_elapsed)
+			snd_pcm_period_elapsed(substream);
+	}
+	urb->status = 0;
+
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status < 0) {
+		cx231xx_errdev("resubmit of audio urb failed (error=%i)\n",
+			       status);
+	}
+	return;
+}
+
+static void cx231xx_audio_bulkirq(struct urb *urb)
+{
+	struct cx231xx *dev = urb->context;
+	unsigned int oldptr;
+	int period_elapsed = 0;
+	int status;
+	unsigned char *cp;
+	unsigned int stride;
+	struct snd_pcm_substream *substream;
+	struct snd_pcm_runtime *runtime;
+
+	if (dev->state & DEV_DISCONNECTED)
+		return;
+
+	switch (urb->status) {
+	case 0:		/* success */
+	case -ETIMEDOUT:	/* NAK */
+		break;
+	case -ECONNRESET:	/* kill */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	default:		/* error */
+		dprintk("urb completition error %d.\n", urb->status);
+		break;
+	}
+
+	if (atomic_read(&dev->stream_started) == 0)
+		return;
+
+	if (dev->adev.capture_pcm_substream) {
+		substream = dev->adev.capture_pcm_substream;
+		runtime = substream->runtime;
+		stride = runtime->frame_bits >> 3;
+
+		if (1) {
+			int length = urb->actual_length /
+				     stride;
+			cp = (unsigned char *)urb->transfer_buffer;
+
+			oldptr = dev->adev.hwptr_done_capture;
+			if (oldptr + length >= runtime->buffer_size) {
+				unsigned int cnt;
+
+				cnt = runtime->buffer_size - oldptr;
+				memcpy(runtime->dma_area + oldptr * stride, cp,
+				       cnt * stride);
+				memcpy(runtime->dma_area, cp + cnt * stride,
+				       length * stride - cnt * stride);
+			} else {
+				memcpy(runtime->dma_area + oldptr * stride, cp,
+				       length * stride);
+			}
+
+			snd_pcm_stream_lock(substream);
+
+			dev->adev.hwptr_done_capture += length;
+			if (dev->adev.hwptr_done_capture >=
+						runtime->buffer_size)
+				dev->adev.hwptr_done_capture -=
+						runtime->buffer_size;
+
+			dev->adev.capture_transfer_done += length;
+			if (dev->adev.capture_transfer_done >=
+				runtime->period_size) {
+				dev->adev.capture_transfer_done -=
+						runtime->period_size;
+				period_elapsed = 1;
+			}
+			snd_pcm_stream_unlock(substream);
+		}
+		if (period_elapsed)
+			snd_pcm_period_elapsed(substream);
+	}
+	urb->status = 0;
+
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status < 0) {
+		cx231xx_errdev("resubmit of audio urb failed (error=%i)\n",
+			       status);
+	}
+	return;
+}
+
+static int cx231xx_init_audio_isoc(struct cx231xx *dev)
+{
+	int i, errCode;
+	int sb_size;
+
+	cx231xx_info("%s: Starting ISO AUDIO transfers\n", __func__);
+
+	if (dev->state & DEV_DISCONNECTED)
+		return -ENODEV;
+
+	sb_size = CX231XX_ISO_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
+
+	for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
+		struct urb *urb;
+		int j, k;
+
+		dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
+		if (!dev->adev.transfer_buffer[i])
+			return -ENOMEM;
+
+		memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
+		urb = usb_alloc_urb(CX231XX_ISO_NUM_AUDIO_PACKETS, GFP_ATOMIC);
+		if (!urb) {
+			cx231xx_errdev("usb_alloc_urb failed!\n");
+			for (j = 0; j < i; j++) {
+				usb_free_urb(dev->adev.urb[j]);
+				kfree(dev->adev.transfer_buffer[j]);
+			}
+			return -ENOMEM;
+		}
+
+		urb->dev = dev->udev;
+		urb->context = dev;
+		urb->pipe = usb_rcvisocpipe(dev->udev,
+						dev->adev.end_point_addr);
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->transfer_buffer = dev->adev.transfer_buffer[i];
+		urb->interval = 1;
+		urb->complete = cx231xx_audio_isocirq;
+		urb->number_of_packets = CX231XX_ISO_NUM_AUDIO_PACKETS;
+		urb->transfer_buffer_length = sb_size;
+
+		for (j = k = 0; j < CX231XX_ISO_NUM_AUDIO_PACKETS;
+			j++, k += dev->adev.max_pkt_size) {
+			urb->iso_frame_desc[j].offset = k;
+			urb->iso_frame_desc[j].length = dev->adev.max_pkt_size;
+		}
+		dev->adev.urb[i] = urb;
+	}
+
+	for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
+		errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
+		if (errCode < 0) {
+			cx231xx_isoc_audio_deinit(dev);
+			return errCode;
+		}
+	}
+
+	return errCode;
+}
+
+static int cx231xx_init_audio_bulk(struct cx231xx *dev)
+{
+	int i, errCode;
+	int sb_size;
+
+	cx231xx_info("%s: Starting BULK AUDIO transfers\n", __func__);
+
+	if (dev->state & DEV_DISCONNECTED)
+		return -ENODEV;
+
+	sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
+
+	for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
+		struct urb *urb;
+		int j;
+
+		dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
+		if (!dev->adev.transfer_buffer[i])
+			return -ENOMEM;
+
+		memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
+		urb = usb_alloc_urb(CX231XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
+		if (!urb) {
+			cx231xx_errdev("usb_alloc_urb failed!\n");
+			for (j = 0; j < i; j++) {
+				usb_free_urb(dev->adev.urb[j]);
+				kfree(dev->adev.transfer_buffer[j]);
+			}
+			return -ENOMEM;
+		}
+
+		urb->dev = dev->udev;
+		urb->context = dev;
+		urb->pipe = usb_rcvbulkpipe(dev->udev,
+						dev->adev.end_point_addr);
+		urb->transfer_flags = 0;
+		urb->transfer_buffer = dev->adev.transfer_buffer[i];
+		urb->complete = cx231xx_audio_bulkirq;
+		urb->transfer_buffer_length = sb_size;
+
+		dev->adev.urb[i] = urb;
+
+	}
+
+	for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
+		errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
+		if (errCode < 0) {
+			cx231xx_bulk_audio_deinit(dev);
+			return errCode;
+		}
+	}
+
+	return errCode;
+}
+
+static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
+					size_t size)
+{
+	struct snd_pcm_runtime *runtime = subs->runtime;
+
+	dprintk("Allocating vbuffer\n");
+	if (runtime->dma_area) {
+		if (runtime->dma_bytes > size)
+			return 0;
+
+		vfree(runtime->dma_area);
+	}
+	runtime->dma_area = vmalloc(size);
+	if (!runtime->dma_area)
+		return -ENOMEM;
+
+	runtime->dma_bytes = size;
+
+	return 0;
+}
+
+static struct snd_pcm_hardware snd_cx231xx_hw_capture = {
+	.info = SNDRV_PCM_INFO_BLOCK_TRANSFER 	|
+	    SNDRV_PCM_INFO_MMAP 		|
+	    SNDRV_PCM_INFO_INTERLEAVED 		|
+	    SNDRV_PCM_INFO_MMAP_VALID,
+
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+	.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
+
+	.rate_min = 48000,
+	.rate_max = 48000,
+	.channels_min = 2,
+	.channels_max = 2,
+	.buffer_bytes_max = 62720 * 8,	/* just about the value in usbaudio.c */
+	.period_bytes_min = 64,		/* 12544/2, */
+	.period_bytes_max = 12544,
+	.periods_min = 2,
+	.periods_max = 98,		/* 12544, */
+};
+
+static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream)
+{
+	struct cx231xx *dev = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int ret = 0;
+
+	dprintk("opening device and trying to acquire exclusive lock\n");
+
+	if (!dev) {
+		cx231xx_errdev("BUG: cx231xx can't find device struct."
+			       " Can't proceed with open\n");
+		return -ENODEV;
+	}
+
+	if (dev->state & DEV_DISCONNECTED) {
+		cx231xx_errdev("Can't open. the device was removed.\n");
+		return -ENODEV;
+	}
+
+	/* Sets volume, mute, etc */
+	dev->mute = 0;
+
+	/* set alternate setting for audio interface */
+	/* 1 - 48000 samples per sec */
+	mutex_lock(&dev->lock);
+	if (dev->USE_ISO)
+		ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1);
+	else
+		ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0);
+	mutex_unlock(&dev->lock);
+	if (ret < 0) {
+		cx231xx_errdev("failed to set alternate setting !\n");
+
+		return ret;
+	}
+
+	runtime->hw = snd_cx231xx_hw_capture;
+
+	mutex_lock(&dev->lock);
+	/* inform hardware to start streaming */
+	ret = cx231xx_capture_start(dev, 1, Audio);
+
+	dev->adev.users++;
+	mutex_unlock(&dev->lock);
+
+	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	dev->adev.capture_pcm_substream = substream;
+	runtime->private_data = dev;
+
+	return 0;
+}
+
+static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
+{
+	int ret;
+	struct cx231xx *dev = snd_pcm_substream_chip(substream);
+
+	dprintk("closing device\n");
+
+	/* inform hardware to stop streaming */
+	mutex_lock(&dev->lock);
+	ret = cx231xx_capture_start(dev, 0, Audio);
+
+	/* set alternate setting for audio interface */
+	/* 1 - 48000 samples per sec */
+	ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0);
+	if (ret < 0) {
+		cx231xx_errdev("failed to set alternate setting !\n");
+
+		mutex_unlock(&dev->lock);
+		return ret;
+	}
+
+	dev->mute = 1;
+	dev->adev.users--;
+	mutex_unlock(&dev->lock);
+
+	if (dev->adev.users == 0 && dev->adev.shutdown == 1) {
+		dprintk("audio users: %d\n", dev->adev.users);
+		dprintk("disabling audio stream!\n");
+		dev->adev.shutdown = 0;
+		dprintk("released lock\n");
+		if (atomic_read(&dev->stream_started) > 0) {
+			atomic_set(&dev->stream_started, 0);
+			schedule_work(&dev->wq_trigger);
+		}
+	}
+	return 0;
+}
+
+static int snd_cx231xx_hw_capture_params(struct snd_pcm_substream *substream,
+					 struct snd_pcm_hw_params *hw_params)
+{
+	int ret;
+
+	dprintk("Setting capture parameters\n");
+
+	ret = snd_pcm_alloc_vmalloc_buffer(substream,
+					   params_buffer_bytes(hw_params));
+#if 0
+	/* TODO: set up cx231xx audio chip to deliver the correct audio format,
+	   current default is 48000hz multiplexed => 96000hz mono
+	   which shouldn't matter since analogue TV only supports mono */
+	unsigned int channels, rate, format;
+
+	format = params_format(hw_params);
+	rate = params_rate(hw_params);
+	channels = params_channels(hw_params);
+#endif
+
+	return ret;
+}
+
+static int snd_cx231xx_hw_capture_free(struct snd_pcm_substream *substream)
+{
+	struct cx231xx *dev = snd_pcm_substream_chip(substream);
+
+	dprintk("Stop capture, if needed\n");
+
+	if (atomic_read(&dev->stream_started) > 0) {
+		atomic_set(&dev->stream_started, 0);
+		schedule_work(&dev->wq_trigger);
+	}
+
+	return 0;
+}
+
+static int snd_cx231xx_prepare(struct snd_pcm_substream *substream)
+{
+	struct cx231xx *dev = snd_pcm_substream_chip(substream);
+
+	dev->adev.hwptr_done_capture = 0;
+	dev->adev.capture_transfer_done = 0;
+
+	return 0;
+}
+
+static void audio_trigger(struct work_struct *work)
+{
+	struct cx231xx *dev = container_of(work, struct cx231xx, wq_trigger);
+
+	if (atomic_read(&dev->stream_started)) {
+		dprintk("starting capture");
+		if (is_fw_load(dev) == 0)
+			cx25840_call(dev, core, load_fw);
+		if (dev->USE_ISO)
+			cx231xx_init_audio_isoc(dev);
+		else
+			cx231xx_init_audio_bulk(dev);
+	} else {
+		dprintk("stopping capture");
+		cx231xx_isoc_audio_deinit(dev);
+	}
+}
+
+static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream,
+				       int cmd)
+{
+	struct cx231xx *dev = snd_pcm_substream_chip(substream);
+	int retval = 0;
+
+	if (dev->state & DEV_DISCONNECTED)
+		return -ENODEV;
+
+	spin_lock(&dev->adev.slock);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		atomic_set(&dev->stream_started, 1);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		atomic_set(&dev->stream_started, 0);
+		break;
+	default:
+		retval = -EINVAL;
+		break;
+	}
+	spin_unlock(&dev->adev.slock);
+
+	schedule_work(&dev->wq_trigger);
+
+	return retval;
+}
+
+static snd_pcm_uframes_t snd_cx231xx_capture_pointer(struct snd_pcm_substream
+						     *substream)
+{
+	struct cx231xx *dev;
+	unsigned long flags;
+	snd_pcm_uframes_t hwptr_done;
+
+	dev = snd_pcm_substream_chip(substream);
+
+	spin_lock_irqsave(&dev->adev.slock, flags);
+	hwptr_done = dev->adev.hwptr_done_capture;
+	spin_unlock_irqrestore(&dev->adev.slock, flags);
+
+	return hwptr_done;
+}
+
+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
+					     unsigned long offset)
+{
+	void *pageptr = subs->runtime->dma_area + offset;
+
+	return vmalloc_to_page(pageptr);
+}
+
+static struct snd_pcm_ops snd_cx231xx_pcm_capture = {
+	.open = snd_cx231xx_capture_open,
+	.close = snd_cx231xx_pcm_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_cx231xx_hw_capture_params,
+	.hw_free = snd_cx231xx_hw_capture_free,
+	.prepare = snd_cx231xx_prepare,
+	.trigger = snd_cx231xx_capture_trigger,
+	.pointer = snd_cx231xx_capture_pointer,
+	.page = snd_pcm_get_vmalloc_page,
+};
+
+static int cx231xx_audio_init(struct cx231xx *dev)
+{
+	struct cx231xx_audio *adev = &dev->adev;
+	struct snd_pcm *pcm;
+	struct snd_card *card;
+	static int devnr;
+	int err;
+	struct usb_interface *uif;
+	int i, isoc_pipe = 0;
+
+	if (dev->has_alsa_audio != 1) {
+		/* This device does not support the extension (in this case
+		   the device is expecting the snd-usb-audio module or
+		   doesn't have analog audio support at all) */
+		return 0;
+	}
+
+	cx231xx_info("cx231xx-audio.c: probing for cx231xx "
+		     "non standard usbaudio\n");
+
+	err = snd_card_create(index[devnr], "Cx231xx Audio", THIS_MODULE,
+			      0, &card);
+	if (err < 0)
+		return err;
+
+	spin_lock_init(&adev->slock);
+	err = snd_pcm_new(card, "Cx231xx Audio", 0, 0, 1, &pcm);
+	if (err < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+			&snd_cx231xx_pcm_capture);
+	pcm->info_flags = 0;
+	pcm->private_data = dev;
+	strcpy(pcm->name, "Conexant cx231xx Capture");
+	snd_card_set_dev(card, &dev->udev->dev);
+	strcpy(card->driver, "Cx231xx-Audio");
+	strcpy(card->shortname, "Cx231xx Audio");
+	strcpy(card->longname, "Conexant cx231xx Audio");
+
+	INIT_WORK(&dev->wq_trigger, audio_trigger);
+
+	err = snd_card_register(card);
+	if (err < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	adev->sndcard = card;
+	adev->udev = dev->udev;
+
+	/* compute alternate max packet sizes for Audio */
+	uif =
+	    dev->udev->actconfig->interface[dev->current_pcb_config.
+					    hs_config_info[0].interface_info.
+					    audio_index + 1];
+
+	adev->end_point_addr =
+	    le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc.
+			bEndpointAddress);
+
+	adev->num_alt = uif->num_altsetting;
+	cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
+		     adev->end_point_addr, adev->num_alt);
+	adev->alt_max_pkt_size = kmalloc(32 * adev->num_alt, GFP_KERNEL);
+
+	if (adev->alt_max_pkt_size == NULL) {
+		cx231xx_errdev("out of memory!\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < adev->num_alt; i++) {
+		u16 tmp =
+		    le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.
+				wMaxPacketSize);
+		adev->alt_max_pkt_size[i] =
+		    (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+		cx231xx_info("Alternate setting %i, max size= %i\n", i,
+			     adev->alt_max_pkt_size[i]);
+	}
+
+	return 0;
+}
+
+static int cx231xx_audio_fini(struct cx231xx *dev)
+{
+	if (dev == NULL)
+		return 0;
+
+	if (dev->has_alsa_audio != 1) {
+		/* This device does not support the extension (in this case
+		   the device is expecting the snd-usb-audio module or
+		   doesn't have analog audio support at all) */
+		return 0;
+	}
+
+	if (dev->adev.sndcard) {
+		snd_card_free(dev->adev.sndcard);
+		kfree(dev->adev.alt_max_pkt_size);
+		dev->adev.sndcard = NULL;
+	}
+
+	return 0;
+}
+
+static struct cx231xx_ops audio_ops = {
+	.id = CX231XX_AUDIO,
+	.name = "Cx231xx Audio Extension",
+	.init = cx231xx_audio_init,
+	.fini = cx231xx_audio_fini,
+};
+
+static int __init cx231xx_alsa_register(void)
+{
+	return cx231xx_register_extension(&audio_ops);
+}
+
+static void __exit cx231xx_alsa_unregister(void)
+{
+	cx231xx_unregister_extension(&audio_ops);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>");
+MODULE_DESCRIPTION("Cx231xx Audio driver");
+
+module_init(cx231xx_alsa_register);
+module_exit(cx231xx_alsa_unregister);
diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c
new file mode 100644
index 0000000..447148e
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c
@@ -0,0 +1,3087 @@
+/*
+   cx231xx_avcore.c - driver for Conexant Cx23100/101/102
+		      USB video capture devices
+
+   Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+
+   This program contains the specific code to control the avdecoder chip and
+   other related usb control functions for cx231xx based chipset.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <media/tuner.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "cx231xx.h"
+#include "cx231xx-dif.h"
+
+#define TUNER_MODE_FM_RADIO 0
+/******************************************************************************
+			-: BLOCK ARRANGEMENT :-
+	I2S block ----------------------|
+	[I2S audio]			|
+					|
+	Analog Front End --> Direct IF -|-> Cx25840 --> Audio
+	[video & audio]			|   [Audio]
+					|
+					|-> Cx25840 --> Video
+					    [Video]
+
+*******************************************************************************/
+/******************************************************************************
+ *                    VERVE REGISTER                                          *
+ *									      *
+ ******************************************************************************/
+static int verve_write_byte(struct cx231xx *dev, u8 saddr, u8 data)
+{
+	return cx231xx_write_i2c_data(dev, VERVE_I2C_ADDRESS,
+					saddr, 1, data, 1);
+}
+
+static int verve_read_byte(struct cx231xx *dev, u8 saddr, u8 *data)
+{
+	int status;
+	u32 temp = 0;
+
+	status = cx231xx_read_i2c_data(dev, VERVE_I2C_ADDRESS,
+					saddr, 1, &temp, 1);
+	*data = (u8) temp;
+	return status;
+}
+void initGPIO(struct cx231xx *dev)
+{
+	u32 _gpio_direction = 0;
+	u32 value = 0;
+	u8 val = 0;
+
+	_gpio_direction = _gpio_direction & 0xFC0003FF;
+	_gpio_direction = _gpio_direction | 0x03FDFC00;
+	cx231xx_send_gpio_cmd(dev, _gpio_direction, (u8 *)&value, 4, 0, 0);
+
+	verve_read_byte(dev, 0x07, &val);
+	cx231xx_info(" verve_read_byte address0x07=0x%x\n", val);
+	verve_write_byte(dev, 0x07, 0xF4);
+	verve_read_byte(dev, 0x07, &val);
+	cx231xx_info(" verve_read_byte address0x07=0x%x\n", val);
+
+	cx231xx_capture_start(dev, 1, Vbi);
+
+	cx231xx_mode_register(dev, EP_MODE_SET, 0x0500FE00);
+	cx231xx_mode_register(dev, GBULK_BIT_EN, 0xFFFDFFFF);
+
+}
+void uninitGPIO(struct cx231xx *dev)
+{
+	u8 value[4] = { 0, 0, 0, 0 };
+
+	cx231xx_capture_start(dev, 0, Vbi);
+	verve_write_byte(dev, 0x07, 0x14);
+	cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+			0x68, value, 4);
+}
+
+/******************************************************************************
+ *                    A F E - B L O C K    C O N T R O L   functions          *
+ * 				[ANALOG FRONT END]			      *
+ ******************************************************************************/
+static int afe_write_byte(struct cx231xx *dev, u16 saddr, u8 data)
+{
+	return cx231xx_write_i2c_data(dev, AFE_DEVICE_ADDRESS,
+					saddr, 2, data, 1);
+}
+
+static int afe_read_byte(struct cx231xx *dev, u16 saddr, u8 *data)
+{
+	int status;
+	u32 temp = 0;
+
+	status = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
+					saddr, 2, &temp, 1);
+	*data = (u8) temp;
+	return status;
+}
+
+int cx231xx_afe_init_super_block(struct cx231xx *dev, u32 ref_count)
+{
+	int status = 0;
+	u8 temp = 0;
+	u8 afe_power_status = 0;
+	int i = 0;
+
+	/* super block initialize */
+	temp = (u8) (ref_count & 0xff);
+	status = afe_write_byte(dev, SUP_BLK_TUNE2, temp);
+	if (status < 0)
+		return status;
+
+	status = afe_read_byte(dev, SUP_BLK_TUNE2, &afe_power_status);
+	if (status < 0)
+		return status;
+
+	temp = (u8) ((ref_count & 0x300) >> 8);
+	temp |= 0x40;
+	status = afe_write_byte(dev, SUP_BLK_TUNE1, temp);
+	if (status < 0)
+		return status;
+
+	status = afe_write_byte(dev, SUP_BLK_PLL2, 0x0f);
+	if (status < 0)
+		return status;
+
+	/* enable pll     */
+	while (afe_power_status != 0x18) {
+		status = afe_write_byte(dev, SUP_BLK_PWRDN, 0x18);
+		if (status < 0) {
+			cx231xx_info(
+			": Init Super Block failed in send cmd\n");
+			break;
+		}
+
+		status = afe_read_byte(dev, SUP_BLK_PWRDN, &afe_power_status);
+		afe_power_status &= 0xff;
+		if (status < 0) {
+			cx231xx_info(
+			": Init Super Block failed in receive cmd\n");
+			break;
+		}
+		i++;
+		if (i == 10) {
+			cx231xx_info(
+			": Init Super Block force break in loop !!!!\n");
+			status = -1;
+			break;
+		}
+	}
+
+	if (status < 0)
+		return status;
+
+	/* start tuning filter */
+	status = afe_write_byte(dev, SUP_BLK_TUNE3, 0x40);
+	if (status < 0)
+		return status;
+
+	msleep(5);
+
+	/* exit tuning */
+	status = afe_write_byte(dev, SUP_BLK_TUNE3, 0x00);
+
+	return status;
+}
+
+int cx231xx_afe_init_channels(struct cx231xx *dev)
+{
+	int status = 0;
+
+	/* power up all 3 channels, clear pd_buffer */
+	status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1, 0x00);
+	status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, 0x00);
+	status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, 0x00);
+
+	/* Enable quantizer calibration */
+	status = afe_write_byte(dev, ADC_COM_QUANT, 0x02);
+
+	/* channel initialize, force modulator (fb) reset */
+	status = afe_write_byte(dev, ADC_FB_FRCRST_CH1, 0x17);
+	status = afe_write_byte(dev, ADC_FB_FRCRST_CH2, 0x17);
+	status = afe_write_byte(dev, ADC_FB_FRCRST_CH3, 0x17);
+
+	/* start quantilizer calibration  */
+	status = afe_write_byte(dev, ADC_CAL_ATEST_CH1, 0x10);
+	status = afe_write_byte(dev, ADC_CAL_ATEST_CH2, 0x10);
+	status = afe_write_byte(dev, ADC_CAL_ATEST_CH3, 0x10);
+	msleep(5);
+
+	/* exit modulator (fb) reset */
+	status = afe_write_byte(dev, ADC_FB_FRCRST_CH1, 0x07);
+	status = afe_write_byte(dev, ADC_FB_FRCRST_CH2, 0x07);
+	status = afe_write_byte(dev, ADC_FB_FRCRST_CH3, 0x07);
+
+	/* enable the pre_clamp in each channel for single-ended input */
+	status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH1, 0xf0);
+	status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH2, 0xf0);
+	status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH3, 0xf0);
+
+	/* use diode instead of resistor, so set term_en to 0, res_en to 0  */
+	status = cx231xx_reg_mask_write(dev, AFE_DEVICE_ADDRESS, 8,
+				   ADC_QGAIN_RES_TRM_CH1, 3, 7, 0x00);
+	status = cx231xx_reg_mask_write(dev, AFE_DEVICE_ADDRESS, 8,
+				   ADC_QGAIN_RES_TRM_CH2, 3, 7, 0x00);
+	status = cx231xx_reg_mask_write(dev, AFE_DEVICE_ADDRESS, 8,
+				   ADC_QGAIN_RES_TRM_CH3, 3, 7, 0x00);
+
+	/* dynamic element matching off */
+	status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH1, 0x03);
+	status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH2, 0x03);
+	status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH3, 0x03);
+
+	return status;
+}
+
+int cx231xx_afe_setup_AFE_for_baseband(struct cx231xx *dev)
+{
+	u8 c_value = 0;
+	int status = 0;
+
+	status = afe_read_byte(dev, ADC_PWRDN_CLAMP_CH2, &c_value);
+	c_value &= (~(0x50));
+	status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, c_value);
+
+	return status;
+}
+
+/*
+	The Analog Front End in Cx231xx has 3 channels. These
+	channels are used to share between different inputs
+	like tuner, s-video and composite inputs.
+
+	channel 1 ----- pin 1  to pin4(in reg is 1-4)
+	channel 2 ----- pin 5  to pin8(in reg is 5-8)
+	channel 3 ----- pin 9 to pin 12(in reg is 9-11)
+*/
+int cx231xx_afe_set_input_mux(struct cx231xx *dev, u32 input_mux)
+{
+	u8 ch1_setting = (u8) input_mux;
+	u8 ch2_setting = (u8) (input_mux >> 8);
+	u8 ch3_setting = (u8) (input_mux >> 16);
+	int status = 0;
+	u8 value = 0;
+
+	if (ch1_setting != 0) {
+		status = afe_read_byte(dev, ADC_INPUT_CH1, &value);
+		value &= ~INPUT_SEL_MASK;
+		value |= (ch1_setting - 1) << 4;
+		value &= 0xff;
+		status = afe_write_byte(dev, ADC_INPUT_CH1, value);
+	}
+
+	if (ch2_setting != 0) {
+		status = afe_read_byte(dev, ADC_INPUT_CH2, &value);
+		value &= ~INPUT_SEL_MASK;
+		value |= (ch2_setting - 1) << 4;
+		value &= 0xff;
+		status = afe_write_byte(dev, ADC_INPUT_CH2, value);
+	}
+
+	/* For ch3_setting, the value to put in the register is
+	   7 less than the input number */
+	if (ch3_setting != 0) {
+		status = afe_read_byte(dev, ADC_INPUT_CH3, &value);
+		value &= ~INPUT_SEL_MASK;
+		value |= (ch3_setting - 1) << 4;
+		value &= 0xff;
+		status = afe_write_byte(dev, ADC_INPUT_CH3, value);
+	}
+
+	return status;
+}
+
+int cx231xx_afe_set_mode(struct cx231xx *dev, enum AFE_MODE mode)
+{
+	int status = 0;
+
+	/*
+	* FIXME: We need to implement the AFE code for LOW IF and for HI IF.
+	* Currently, only baseband works.
+	*/
+
+	switch (mode) {
+	case AFE_MODE_LOW_IF:
+		cx231xx_Setup_AFE_for_LowIF(dev);
+		break;
+	case AFE_MODE_BASEBAND:
+		status = cx231xx_afe_setup_AFE_for_baseband(dev);
+		break;
+	case AFE_MODE_EU_HI_IF:
+		/* SetupAFEforEuHiIF(); */
+		break;
+	case AFE_MODE_US_HI_IF:
+		/* SetupAFEforUsHiIF(); */
+		break;
+	case AFE_MODE_JAPAN_HI_IF:
+		/* SetupAFEforJapanHiIF(); */
+		break;
+	}
+
+	if ((mode != dev->afe_mode) &&
+		(dev->video_input == CX231XX_VMUX_TELEVISION))
+		status = cx231xx_afe_adjust_ref_count(dev,
+						     CX231XX_VMUX_TELEVISION);
+
+	dev->afe_mode = mode;
+
+	return status;
+}
+
+int cx231xx_afe_update_power_control(struct cx231xx *dev,
+					enum AV_MODE avmode)
+{
+	u8 afe_power_status = 0;
+	int status = 0;
+
+	switch (dev->model) {
+	case CX231XX_BOARD_CNXT_CARRAERA:
+	case CX231XX_BOARD_CNXT_RDE_250:
+	case CX231XX_BOARD_CNXT_SHELBY:
+	case CX231XX_BOARD_CNXT_RDU_250:
+	case CX231XX_BOARD_CNXT_RDE_253S:
+	case CX231XX_BOARD_CNXT_RDU_253S:
+	case CX231XX_BOARD_CNXT_VIDEO_GRABBER:
+	case CX231XX_BOARD_HAUPPAUGE_EXETER:
+	case CX231XX_BOARD_HAUPPAUGE_USBLIVE2:
+	case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+	case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
+	case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
+		if (avmode == POLARIS_AVMODE_ANALOGT_TV) {
+			while (afe_power_status != (FLD_PWRDN_TUNING_BIAS |
+						FLD_PWRDN_ENABLE_PLL)) {
+				status = afe_write_byte(dev, SUP_BLK_PWRDN,
+							FLD_PWRDN_TUNING_BIAS |
+							FLD_PWRDN_ENABLE_PLL);
+				status |= afe_read_byte(dev, SUP_BLK_PWRDN,
+							&afe_power_status);
+				if (status < 0)
+					break;
+			}
+
+			status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1,
+							0x00);
+			status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2,
+							0x00);
+			status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3,
+							0x00);
+		} else if (avmode == POLARIS_AVMODE_DIGITAL) {
+			status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1,
+							0x70);
+			status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2,
+							0x70);
+			status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3,
+							0x70);
+
+			status |= afe_read_byte(dev, SUP_BLK_PWRDN,
+						  &afe_power_status);
+			afe_power_status |= FLD_PWRDN_PD_BANDGAP |
+						FLD_PWRDN_PD_BIAS |
+						FLD_PWRDN_PD_TUNECK;
+			status |= afe_write_byte(dev, SUP_BLK_PWRDN,
+						   afe_power_status);
+		} else if (avmode == POLARIS_AVMODE_ENXTERNAL_AV) {
+			while (afe_power_status != (FLD_PWRDN_TUNING_BIAS |
+						FLD_PWRDN_ENABLE_PLL)) {
+				status = afe_write_byte(dev, SUP_BLK_PWRDN,
+							FLD_PWRDN_TUNING_BIAS |
+							FLD_PWRDN_ENABLE_PLL);
+				status |= afe_read_byte(dev, SUP_BLK_PWRDN,
+							&afe_power_status);
+				if (status < 0)
+					break;
+			}
+
+			status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1,
+						0x00);
+			status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2,
+						0x00);
+			status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3,
+						0x00);
+		} else {
+			cx231xx_info("Invalid AV mode input\n");
+			status = -1;
+		}
+		break;
+	default:
+		if (avmode == POLARIS_AVMODE_ANALOGT_TV) {
+			while (afe_power_status != (FLD_PWRDN_TUNING_BIAS |
+						FLD_PWRDN_ENABLE_PLL)) {
+				status = afe_write_byte(dev, SUP_BLK_PWRDN,
+							FLD_PWRDN_TUNING_BIAS |
+							FLD_PWRDN_ENABLE_PLL);
+				status |= afe_read_byte(dev, SUP_BLK_PWRDN,
+							&afe_power_status);
+				if (status < 0)
+					break;
+			}
+
+			status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1,
+							0x40);
+			status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2,
+							0x40);
+			status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3,
+							0x00);
+		} else if (avmode == POLARIS_AVMODE_DIGITAL) {
+			status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1,
+							0x70);
+			status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2,
+							0x70);
+			status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3,
+							0x70);
+
+			status |= afe_read_byte(dev, SUP_BLK_PWRDN,
+						       &afe_power_status);
+			afe_power_status |= FLD_PWRDN_PD_BANDGAP |
+						FLD_PWRDN_PD_BIAS |
+						FLD_PWRDN_PD_TUNECK;
+			status |= afe_write_byte(dev, SUP_BLK_PWRDN,
+							afe_power_status);
+		} else if (avmode == POLARIS_AVMODE_ENXTERNAL_AV) {
+			while (afe_power_status != (FLD_PWRDN_TUNING_BIAS |
+						FLD_PWRDN_ENABLE_PLL)) {
+				status = afe_write_byte(dev, SUP_BLK_PWRDN,
+							FLD_PWRDN_TUNING_BIAS |
+							FLD_PWRDN_ENABLE_PLL);
+				status |= afe_read_byte(dev, SUP_BLK_PWRDN,
+							&afe_power_status);
+				if (status < 0)
+					break;
+			}
+
+			status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1,
+							0x00);
+			status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2,
+							0x00);
+			status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3,
+							0x40);
+		} else {
+			cx231xx_info("Invalid AV mode input\n");
+			status = -1;
+		}
+	}			/* switch  */
+
+	return status;
+}
+
+int cx231xx_afe_adjust_ref_count(struct cx231xx *dev, u32 video_input)
+{
+	u8 input_mode = 0;
+	u8 ntf_mode = 0;
+	int status = 0;
+
+	dev->video_input = video_input;
+
+	if (video_input == CX231XX_VMUX_TELEVISION) {
+		status = afe_read_byte(dev, ADC_INPUT_CH3, &input_mode);
+		status = afe_read_byte(dev, ADC_NTF_PRECLMP_EN_CH3,
+					&ntf_mode);
+	} else {
+		status = afe_read_byte(dev, ADC_INPUT_CH1, &input_mode);
+		status = afe_read_byte(dev, ADC_NTF_PRECLMP_EN_CH1,
+					&ntf_mode);
+	}
+
+	input_mode = (ntf_mode & 0x3) | ((input_mode & 0x6) << 1);
+
+	switch (input_mode) {
+	case SINGLE_ENDED:
+		dev->afe_ref_count = 0x23C;
+		break;
+	case LOW_IF:
+		dev->afe_ref_count = 0x24C;
+		break;
+	case EU_IF:
+		dev->afe_ref_count = 0x258;
+		break;
+	case US_IF:
+		dev->afe_ref_count = 0x260;
+		break;
+	default:
+		break;
+	}
+
+	status = cx231xx_afe_init_super_block(dev, dev->afe_ref_count);
+
+	return status;
+}
+
+/******************************************************************************
+ *     V I D E O / A U D I O    D E C O D E R    C O N T R O L   functions    *
+ ******************************************************************************/
+static int vid_blk_write_byte(struct cx231xx *dev, u16 saddr, u8 data)
+{
+	return cx231xx_write_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+					saddr, 2, data, 1);
+}
+
+static int vid_blk_read_byte(struct cx231xx *dev, u16 saddr, u8 *data)
+{
+	int status;
+	u32 temp = 0;
+
+	status = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+					saddr, 2, &temp, 1);
+	*data = (u8) temp;
+	return status;
+}
+
+static int vid_blk_write_word(struct cx231xx *dev, u16 saddr, u32 data)
+{
+	return cx231xx_write_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+					saddr, 2, data, 4);
+}
+
+static int vid_blk_read_word(struct cx231xx *dev, u16 saddr, u32 *data)
+{
+	return cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+					saddr, 2, data, 4);
+}
+int cx231xx_check_fw(struct cx231xx *dev)
+{
+	u8 temp = 0;
+	int status = 0;
+	status = vid_blk_read_byte(dev, DL_CTL_ADDRESS_LOW, &temp);
+	if (status < 0)
+		return status;
+	else
+		return temp;
+
+}
+
+int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input)
+{
+	int status = 0;
+
+	switch (INPUT(input)->type) {
+	case CX231XX_VMUX_COMPOSITE1:
+	case CX231XX_VMUX_SVIDEO:
+		if ((dev->current_pcb_config.type == USB_BUS_POWER) &&
+		    (dev->power_mode != POLARIS_AVMODE_ENXTERNAL_AV)) {
+			/* External AV */
+			status = cx231xx_set_power_mode(dev,
+					POLARIS_AVMODE_ENXTERNAL_AV);
+			if (status < 0) {
+				cx231xx_errdev("%s: set_power_mode : Failed to"
+						" set Power - errCode [%d]!\n",
+						__func__, status);
+				return status;
+			}
+		}
+		status = cx231xx_set_decoder_video_input(dev,
+							 INPUT(input)->type,
+							 INPUT(input)->vmux);
+		break;
+	case CX231XX_VMUX_TELEVISION:
+	case CX231XX_VMUX_CABLE:
+		if ((dev->current_pcb_config.type == USB_BUS_POWER) &&
+		    (dev->power_mode != POLARIS_AVMODE_ANALOGT_TV)) {
+			/* Tuner */
+			status = cx231xx_set_power_mode(dev,
+						POLARIS_AVMODE_ANALOGT_TV);
+			if (status < 0) {
+				cx231xx_errdev("%s: set_power_mode:Failed"
+					" to set Power - errCode [%d]!\n",
+					__func__, status);
+				return status;
+			}
+		}
+		if (dev->tuner_type == TUNER_NXP_TDA18271)
+			status = cx231xx_set_decoder_video_input(dev,
+							CX231XX_VMUX_TELEVISION,
+							INPUT(input)->vmux);
+		else
+			status = cx231xx_set_decoder_video_input(dev,
+							CX231XX_VMUX_COMPOSITE1,
+							INPUT(input)->vmux);
+
+		break;
+	default:
+		cx231xx_errdev("%s: set_power_mode : Unknown Input %d !\n",
+		     __func__, INPUT(input)->type);
+		break;
+	}
+
+	/* save the selection */
+	dev->video_input = input;
+
+	return status;
+}
+
+int cx231xx_set_decoder_video_input(struct cx231xx *dev,
+				u8 pin_type, u8 input)
+{
+	int status = 0;
+	u32 value = 0;
+
+	if (pin_type != dev->video_input) {
+		status = cx231xx_afe_adjust_ref_count(dev, pin_type);
+		if (status < 0) {
+			cx231xx_errdev("%s: adjust_ref_count :Failed to set"
+				"AFE input mux - errCode [%d]!\n",
+				__func__, status);
+			return status;
+		}
+	}
+
+	/* call afe block to set video inputs */
+	status = cx231xx_afe_set_input_mux(dev, input);
+	if (status < 0) {
+		cx231xx_errdev("%s: set_input_mux :Failed to set"
+				" AFE input mux - errCode [%d]!\n",
+				__func__, status);
+		return status;
+	}
+
+	switch (pin_type) {
+	case CX231XX_VMUX_COMPOSITE1:
+		status = vid_blk_read_word(dev, AFE_CTRL, &value);
+		value |= (0 << 13) | (1 << 4);
+		value &= ~(1 << 5);
+
+		/* set [24:23] [22:15] to 0  */
+		value &= (~(0x1ff8000));
+		/* set FUNC_MODE[24:23] = 2 IF_MOD[22:15] = 0  */
+		value |= 0x1000000;
+		status = vid_blk_write_word(dev, AFE_CTRL, value);
+
+		status = vid_blk_read_word(dev, OUT_CTRL1, &value);
+		value |= (1 << 7);
+		status = vid_blk_write_word(dev, OUT_CTRL1, value);
+
+		/* Set output mode */
+		status = cx231xx_read_modify_write_i2c_dword(dev,
+							VID_BLK_I2C_ADDRESS,
+							OUT_CTRL1,
+							FLD_OUT_MODE,
+							dev->board.output_mode);
+
+		/* Tell DIF object to go to baseband mode  */
+		status = cx231xx_dif_set_standard(dev, DIF_USE_BASEBAND);
+		if (status < 0) {
+			cx231xx_errdev("%s: cx231xx_dif set to By pass"
+						   " mode- errCode [%d]!\n",
+				__func__, status);
+			return status;
+		}
+
+		/* Read the DFE_CTRL1 register */
+		status = vid_blk_read_word(dev, DFE_CTRL1, &value);
+
+		/* enable the VBI_GATE_EN */
+		value |= FLD_VBI_GATE_EN;
+
+		/* Enable the auto-VGA enable */
+		value |= FLD_VGA_AUTO_EN;
+
+		/* Write it back */
+		status = vid_blk_write_word(dev, DFE_CTRL1, value);
+
+		/* Disable auto config of registers */
+		status = cx231xx_read_modify_write_i2c_dword(dev,
+					VID_BLK_I2C_ADDRESS,
+					MODE_CTRL, FLD_ACFG_DIS,
+					cx231xx_set_field(FLD_ACFG_DIS, 1));
+
+		/* Set CVBS input mode */
+		status = cx231xx_read_modify_write_i2c_dword(dev,
+			VID_BLK_I2C_ADDRESS,
+			MODE_CTRL, FLD_INPUT_MODE,
+			cx231xx_set_field(FLD_INPUT_MODE, INPUT_MODE_CVBS_0));
+		break;
+	case CX231XX_VMUX_SVIDEO:
+		/* Disable the use of  DIF */
+
+		status = vid_blk_read_word(dev, AFE_CTRL, &value);
+
+		/* set [24:23] [22:15] to 0 */
+		value &= (~(0x1ff8000));
+		/* set FUNC_MODE[24:23] = 2
+		IF_MOD[22:15] = 0 DCR_BYP_CH2[4:4] = 1; */
+		value |= 0x1000010;
+		status = vid_blk_write_word(dev, AFE_CTRL, value);
+
+		/* Tell DIF object to go to baseband mode */
+		status = cx231xx_dif_set_standard(dev, DIF_USE_BASEBAND);
+		if (status < 0) {
+			cx231xx_errdev("%s: cx231xx_dif set to By pass"
+						   " mode- errCode [%d]!\n",
+				__func__, status);
+			return status;
+		}
+
+		/* Read the DFE_CTRL1 register */
+		status = vid_blk_read_word(dev, DFE_CTRL1, &value);
+
+		/* enable the VBI_GATE_EN */
+		value |= FLD_VBI_GATE_EN;
+
+		/* Enable the auto-VGA enable */
+		value |= FLD_VGA_AUTO_EN;
+
+		/* Write it back */
+		status = vid_blk_write_word(dev, DFE_CTRL1, value);
+
+		/* Disable auto config of registers  */
+		status =  cx231xx_read_modify_write_i2c_dword(dev,
+					VID_BLK_I2C_ADDRESS,
+					MODE_CTRL, FLD_ACFG_DIS,
+					cx231xx_set_field(FLD_ACFG_DIS, 1));
+
+		/* Set YC input mode */
+		status = cx231xx_read_modify_write_i2c_dword(dev,
+			VID_BLK_I2C_ADDRESS,
+			MODE_CTRL,
+			FLD_INPUT_MODE,
+			cx231xx_set_field(FLD_INPUT_MODE, INPUT_MODE_YC_1));
+
+		/* Chroma to ADC2 */
+		status = vid_blk_read_word(dev, AFE_CTRL, &value);
+		value |= FLD_CHROMA_IN_SEL;	/* set the chroma in select */
+
+		/* Clear VGA_SEL_CH2 and VGA_SEL_CH3 (bits 7 and 8)
+		   This sets them to use video
+		   rather than audio.  Only one of the two will be in use. */
+		value &= ~(FLD_VGA_SEL_CH2 | FLD_VGA_SEL_CH3);
+
+		status = vid_blk_write_word(dev, AFE_CTRL, value);
+
+		status = cx231xx_afe_set_mode(dev, AFE_MODE_BASEBAND);
+		break;
+	case CX231XX_VMUX_TELEVISION:
+	case CX231XX_VMUX_CABLE:
+	default:
+		/* TODO: Test if this is also needed for xc2028/xc3028 */
+		if (dev->board.tuner_type == TUNER_XC5000) {
+			/* Disable the use of  DIF   */
+
+			status = vid_blk_read_word(dev, AFE_CTRL, &value);
+			value |= (0 << 13) | (1 << 4);
+			value &= ~(1 << 5);
+
+			/* set [24:23] [22:15] to 0 */
+			value &= (~(0x1FF8000));
+			/* set FUNC_MODE[24:23] = 2 IF_MOD[22:15] = 0 */
+			value |= 0x1000000;
+			status = vid_blk_write_word(dev, AFE_CTRL, value);
+
+			status = vid_blk_read_word(dev, OUT_CTRL1, &value);
+			value |= (1 << 7);
+			status = vid_blk_write_word(dev, OUT_CTRL1, value);
+
+			/* Set output mode */
+			status = cx231xx_read_modify_write_i2c_dword(dev,
+							VID_BLK_I2C_ADDRESS,
+							OUT_CTRL1, FLD_OUT_MODE,
+							dev->board.output_mode);
+
+			/* Tell DIF object to go to baseband mode */
+			status = cx231xx_dif_set_standard(dev,
+							  DIF_USE_BASEBAND);
+			if (status < 0) {
+				cx231xx_errdev("%s: cx231xx_dif set to By pass"
+						" mode- errCode [%d]!\n",
+						__func__, status);
+				return status;
+			}
+
+			/* Read the DFE_CTRL1 register */
+			status = vid_blk_read_word(dev, DFE_CTRL1, &value);
+
+			/* enable the VBI_GATE_EN */
+			value |= FLD_VBI_GATE_EN;
+
+			/* Enable the auto-VGA enable */
+			value |= FLD_VGA_AUTO_EN;
+
+			/* Write it back */
+			status = vid_blk_write_word(dev, DFE_CTRL1, value);
+
+			/* Disable auto config of registers */
+			status = cx231xx_read_modify_write_i2c_dword(dev,
+					VID_BLK_I2C_ADDRESS,
+					MODE_CTRL, FLD_ACFG_DIS,
+					cx231xx_set_field(FLD_ACFG_DIS, 1));
+
+			/* Set CVBS input mode */
+			status = cx231xx_read_modify_write_i2c_dword(dev,
+				VID_BLK_I2C_ADDRESS,
+				MODE_CTRL, FLD_INPUT_MODE,
+				cx231xx_set_field(FLD_INPUT_MODE,
+						INPUT_MODE_CVBS_0));
+		} else {
+			/* Enable the DIF for the tuner */
+
+			/* Reinitialize the DIF */
+			status = cx231xx_dif_set_standard(dev, dev->norm);
+			if (status < 0) {
+				cx231xx_errdev("%s: cx231xx_dif set to By pass"
+						" mode- errCode [%d]!\n",
+						__func__, status);
+				return status;
+			}
+
+			/* Make sure bypass is cleared */
+			status = vid_blk_read_word(dev, DIF_MISC_CTRL, &value);
+
+			/* Clear the bypass bit */
+			value &= ~FLD_DIF_DIF_BYPASS;
+
+			/* Enable the use of the DIF block */
+			status = vid_blk_write_word(dev, DIF_MISC_CTRL, value);
+
+			/* Read the DFE_CTRL1 register */
+			status = vid_blk_read_word(dev, DFE_CTRL1, &value);
+
+			/* Disable the VBI_GATE_EN */
+			value &= ~FLD_VBI_GATE_EN;
+
+			/* Enable the auto-VGA enable, AGC, and
+			   set the skip count to 2 */
+			value |= FLD_VGA_AUTO_EN | FLD_AGC_AUTO_EN | 0x00200000;
+
+			/* Write it back */
+			status = vid_blk_write_word(dev, DFE_CTRL1, value);
+
+			/* Wait until AGC locks up */
+			msleep(1);
+
+			/* Disable the auto-VGA enable AGC */
+			value &= ~(FLD_VGA_AUTO_EN);
+
+			/* Write it back */
+			status = vid_blk_write_word(dev, DFE_CTRL1, value);
+
+			/* Enable Polaris B0 AGC output */
+			status = vid_blk_read_word(dev, PIN_CTRL, &value);
+			value |= (FLD_OEF_AGC_RF) |
+				 (FLD_OEF_AGC_IFVGA) |
+				 (FLD_OEF_AGC_IF);
+			status = vid_blk_write_word(dev, PIN_CTRL, value);
+
+			/* Set output mode */
+			status = cx231xx_read_modify_write_i2c_dword(dev,
+						VID_BLK_I2C_ADDRESS,
+						OUT_CTRL1, FLD_OUT_MODE,
+						dev->board.output_mode);
+
+			/* Disable auto config of registers */
+			status = cx231xx_read_modify_write_i2c_dword(dev,
+					VID_BLK_I2C_ADDRESS,
+					MODE_CTRL, FLD_ACFG_DIS,
+					cx231xx_set_field(FLD_ACFG_DIS, 1));
+
+			/* Set CVBS input mode */
+			status = cx231xx_read_modify_write_i2c_dword(dev,
+				VID_BLK_I2C_ADDRESS,
+				MODE_CTRL, FLD_INPUT_MODE,
+				cx231xx_set_field(FLD_INPUT_MODE,
+						INPUT_MODE_CVBS_0));
+
+			/* Set some bits in AFE_CTRL so that channel 2 or 3
+			 * is ready to receive audio */
+			/* Clear clamp for channels 2 and 3      (bit 16-17) */
+			/* Clear droop comp                      (bit 19-20) */
+			/* Set VGA_SEL (for audio control)       (bit 7-8) */
+			status = vid_blk_read_word(dev, AFE_CTRL, &value);
+
+			/*Set Func mode:01-DIF 10-baseband 11-YUV*/
+			value &= (~(FLD_FUNC_MODE));
+			value |= 0x800000;
+
+			value |= FLD_VGA_SEL_CH3 | FLD_VGA_SEL_CH2;
+
+			status = vid_blk_write_word(dev, AFE_CTRL, value);
+
+			if (dev->tuner_type == TUNER_NXP_TDA18271) {
+				status = vid_blk_read_word(dev, PIN_CTRL,
+				 &value);
+				status = vid_blk_write_word(dev, PIN_CTRL,
+				 (value & 0xFFFFFFEF));
+			}
+
+			break;
+
+		}
+		break;
+	}
+
+	/* Set raw VBI mode */
+	status = cx231xx_read_modify_write_i2c_dword(dev,
+				VID_BLK_I2C_ADDRESS,
+				OUT_CTRL1, FLD_VBIHACTRAW_EN,
+				cx231xx_set_field(FLD_VBIHACTRAW_EN, 1));
+
+	status = vid_blk_read_word(dev, OUT_CTRL1, &value);
+	if (value & 0x02) {
+		value |= (1 << 19);
+		status = vid_blk_write_word(dev, OUT_CTRL1, value);
+	}
+
+	return status;
+}
+
+void cx231xx_enable656(struct cx231xx *dev)
+{
+	u8 temp = 0;
+	/*enable TS1 data[0:7] as output to export 656*/
+
+	vid_blk_write_byte(dev, TS1_PIN_CTL0, 0xFF);
+
+	/*enable TS1 clock as output to export 656*/
+
+	vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp);
+	temp = temp|0x04;
+
+	vid_blk_write_byte(dev, TS1_PIN_CTL1, temp);
+}
+EXPORT_SYMBOL_GPL(cx231xx_enable656);
+
+void cx231xx_disable656(struct cx231xx *dev)
+{
+	u8 temp = 0;
+
+	vid_blk_write_byte(dev, TS1_PIN_CTL0, 0x00);
+
+	vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp);
+	temp = temp&0xFB;
+
+	vid_blk_write_byte(dev, TS1_PIN_CTL1, temp);
+}
+EXPORT_SYMBOL_GPL(cx231xx_disable656);
+
+/*
+ * Handle any video-mode specific overrides that are different
+ * on a per video standards basis after touching the MODE_CTRL
+ * register which resets many values for autodetect
+ */
+int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev)
+{
+	int status = 0;
+
+	cx231xx_info("do_mode_ctrl_overrides : 0x%x\n",
+		     (unsigned int)dev->norm);
+
+	/* Change the DFE_CTRL3 bp_percent to fix flagging */
+	status = vid_blk_write_word(dev, DFE_CTRL3, 0xCD3F0280);
+
+	if (dev->norm & (V4L2_STD_NTSC | V4L2_STD_PAL_M)) {
+		cx231xx_info("do_mode_ctrl_overrides NTSC\n");
+
+		/* Move the close caption lines out of active video,
+		   adjust the active video start point */
+		status = cx231xx_read_modify_write_i2c_dword(dev,
+							VID_BLK_I2C_ADDRESS,
+							VERT_TIM_CTRL,
+							FLD_VBLANK_CNT, 0x18);
+		status = cx231xx_read_modify_write_i2c_dword(dev,
+							VID_BLK_I2C_ADDRESS,
+							VERT_TIM_CTRL,
+							FLD_VACTIVE_CNT,
+							0x1E7000);
+		status = cx231xx_read_modify_write_i2c_dword(dev,
+							VID_BLK_I2C_ADDRESS,
+							VERT_TIM_CTRL,
+							FLD_V656BLANK_CNT,
+							0x1C000000);
+
+		status = cx231xx_read_modify_write_i2c_dword(dev,
+							VID_BLK_I2C_ADDRESS,
+							HORIZ_TIM_CTRL,
+							FLD_HBLANK_CNT,
+							cx231xx_set_field
+							(FLD_HBLANK_CNT, 0x79));
+
+	} else if (dev->norm & V4L2_STD_SECAM) {
+		cx231xx_info("do_mode_ctrl_overrides SECAM\n");
+		status =  cx231xx_read_modify_write_i2c_dword(dev,
+							VID_BLK_I2C_ADDRESS,
+							VERT_TIM_CTRL,
+							FLD_VBLANK_CNT, 0x20);
+		status = cx231xx_read_modify_write_i2c_dword(dev,
+							VID_BLK_I2C_ADDRESS,
+							VERT_TIM_CTRL,
+							FLD_VACTIVE_CNT,
+							cx231xx_set_field
+							(FLD_VACTIVE_CNT,
+							 0x244));
+		status = cx231xx_read_modify_write_i2c_dword(dev,
+							VID_BLK_I2C_ADDRESS,
+							VERT_TIM_CTRL,
+							FLD_V656BLANK_CNT,
+							cx231xx_set_field
+							(FLD_V656BLANK_CNT,
+							0x24));
+		/* Adjust the active video horizontal start point */
+		status = cx231xx_read_modify_write_i2c_dword(dev,
+							VID_BLK_I2C_ADDRESS,
+							HORIZ_TIM_CTRL,
+							FLD_HBLANK_CNT,
+							cx231xx_set_field
+							(FLD_HBLANK_CNT, 0x85));
+	} else {
+		cx231xx_info("do_mode_ctrl_overrides PAL\n");
+		status = cx231xx_read_modify_write_i2c_dword(dev,
+							VID_BLK_I2C_ADDRESS,
+							VERT_TIM_CTRL,
+							FLD_VBLANK_CNT, 0x20);
+		status = cx231xx_read_modify_write_i2c_dword(dev,
+							VID_BLK_I2C_ADDRESS,
+							VERT_TIM_CTRL,
+							FLD_VACTIVE_CNT,
+							cx231xx_set_field
+							(FLD_VACTIVE_CNT,
+							 0x244));
+		status = cx231xx_read_modify_write_i2c_dword(dev,
+							VID_BLK_I2C_ADDRESS,
+							VERT_TIM_CTRL,
+							FLD_V656BLANK_CNT,
+							cx231xx_set_field
+							(FLD_V656BLANK_CNT,
+							0x24));
+		/* Adjust the active video horizontal start point */
+		status = cx231xx_read_modify_write_i2c_dword(dev,
+							VID_BLK_I2C_ADDRESS,
+							HORIZ_TIM_CTRL,
+							FLD_HBLANK_CNT,
+							cx231xx_set_field
+							(FLD_HBLANK_CNT, 0x85));
+
+	}
+
+	return status;
+}
+
+int cx231xx_unmute_audio(struct cx231xx *dev)
+{
+	return vid_blk_write_byte(dev, PATH1_VOL_CTL, 0x24);
+}
+EXPORT_SYMBOL_GPL(cx231xx_unmute_audio);
+
+int stopAudioFirmware(struct cx231xx *dev)
+{
+	return vid_blk_write_byte(dev, DL_CTL_CONTROL, 0x03);
+}
+
+int restartAudioFirmware(struct cx231xx *dev)
+{
+	return vid_blk_write_byte(dev, DL_CTL_CONTROL, 0x13);
+}
+
+int cx231xx_set_audio_input(struct cx231xx *dev, u8 input)
+{
+	int status = 0;
+	enum AUDIO_INPUT ainput = AUDIO_INPUT_LINE;
+
+	switch (INPUT(input)->amux) {
+	case CX231XX_AMUX_VIDEO:
+		ainput = AUDIO_INPUT_TUNER_TV;
+		break;
+	case CX231XX_AMUX_LINE_IN:
+		status = cx231xx_i2s_blk_set_audio_input(dev, input);
+		ainput = AUDIO_INPUT_LINE;
+		break;
+	default:
+		break;
+	}
+
+	status = cx231xx_set_audio_decoder_input(dev, ainput);
+
+	return status;
+}
+
+int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
+				    enum AUDIO_INPUT audio_input)
+{
+	u32 dwval;
+	int status;
+	u8 gen_ctrl;
+	u32 value = 0;
+
+	/* Put it in soft reset   */
+	status = vid_blk_read_byte(dev, GENERAL_CTL, &gen_ctrl);
+	gen_ctrl |= 1;
+	status = vid_blk_write_byte(dev, GENERAL_CTL, gen_ctrl);
+
+	switch (audio_input) {
+	case AUDIO_INPUT_LINE:
+		/* setup AUD_IO control from Merlin paralle output */
+		value = cx231xx_set_field(FLD_AUD_CHAN1_SRC,
+					  AUD_CHAN_SRC_PARALLEL);
+		status = vid_blk_write_word(dev, AUD_IO_CTRL, value);
+
+		/* setup input to Merlin, SRC2 connect to AC97
+		   bypass upsample-by-2, slave mode, sony mode, left justify
+		   adr 091c, dat 01000000 */
+		status = vid_blk_read_word(dev, AC97_CTL, &dwval);
+
+		status = vid_blk_write_word(dev, AC97_CTL,
+					   (dwval | FLD_AC97_UP2X_BYPASS));
+
+		/* select the parallel1 and SRC3 */
+		status = vid_blk_write_word(dev, BAND_OUT_SEL,
+				cx231xx_set_field(FLD_SRC3_IN_SEL, 0x0) |
+				cx231xx_set_field(FLD_SRC3_CLK_SEL, 0x0) |
+				cx231xx_set_field(FLD_PARALLEL1_SRC_SEL, 0x0));
+
+		/* unmute all, AC97 in, independence mode
+		   adr 08d0, data 0x00063073 */
+		status = vid_blk_write_word(dev, DL_CTL, 0x3000001);
+		status = vid_blk_write_word(dev, PATH1_CTL1, 0x00063073);
+
+		/* set AVC maximum threshold, adr 08d4, dat ffff0024 */
+		status = vid_blk_read_word(dev, PATH1_VOL_CTL, &dwval);
+		status = vid_blk_write_word(dev, PATH1_VOL_CTL,
+					   (dwval | FLD_PATH1_AVC_THRESHOLD));
+
+		/* set SC maximum threshold, adr 08ec, dat ffffb3a3 */
+		status = vid_blk_read_word(dev, PATH1_SC_CTL, &dwval);
+		status = vid_blk_write_word(dev, PATH1_SC_CTL,
+					   (dwval | FLD_PATH1_SC_THRESHOLD));
+		break;
+
+	case AUDIO_INPUT_TUNER_TV:
+	default:
+		status = stopAudioFirmware(dev);
+		/* Setup SRC sources and clocks */
+		status = vid_blk_write_word(dev, BAND_OUT_SEL,
+			cx231xx_set_field(FLD_SRC6_IN_SEL, 0x00)         |
+			cx231xx_set_field(FLD_SRC6_CLK_SEL, 0x01)        |
+			cx231xx_set_field(FLD_SRC5_IN_SEL, 0x00)         |
+			cx231xx_set_field(FLD_SRC5_CLK_SEL, 0x02)        |
+			cx231xx_set_field(FLD_SRC4_IN_SEL, 0x02)         |
+			cx231xx_set_field(FLD_SRC4_CLK_SEL, 0x03)        |
+			cx231xx_set_field(FLD_SRC3_IN_SEL, 0x00)         |
+			cx231xx_set_field(FLD_SRC3_CLK_SEL, 0x00)        |
+			cx231xx_set_field(FLD_BASEBAND_BYPASS_CTL, 0x00) |
+			cx231xx_set_field(FLD_AC97_SRC_SEL, 0x03)        |
+			cx231xx_set_field(FLD_I2S_SRC_SEL, 0x00)         |
+			cx231xx_set_field(FLD_PARALLEL2_SRC_SEL, 0x02)   |
+			cx231xx_set_field(FLD_PARALLEL1_SRC_SEL, 0x01));
+
+		/* Setup the AUD_IO control */
+		status = vid_blk_write_word(dev, AUD_IO_CTRL,
+			cx231xx_set_field(FLD_I2S_PORT_DIR, 0x00)  |
+			cx231xx_set_field(FLD_I2S_OUT_SRC, 0x00)   |
+			cx231xx_set_field(FLD_AUD_CHAN3_SRC, 0x00) |
+			cx231xx_set_field(FLD_AUD_CHAN2_SRC, 0x00) |
+			cx231xx_set_field(FLD_AUD_CHAN1_SRC, 0x03));
+
+		status = vid_blk_write_word(dev, PATH1_CTL1, 0x1F063870);
+
+		/* setAudioStandard(_audio_standard); */
+		status = vid_blk_write_word(dev, PATH1_CTL1, 0x00063870);
+
+		status = restartAudioFirmware(dev);
+
+		switch (dev->board.tuner_type) {
+		case TUNER_XC5000:
+			/* SIF passthrough at 28.6363 MHz sample rate */
+			status = cx231xx_read_modify_write_i2c_dword(dev,
+					VID_BLK_I2C_ADDRESS,
+					CHIP_CTRL,
+					FLD_SIF_EN,
+					cx231xx_set_field(FLD_SIF_EN, 1));
+			break;
+		case TUNER_NXP_TDA18271:
+			/* Normal mode: SIF passthrough at 14.32 MHz */
+			status = cx231xx_read_modify_write_i2c_dword(dev,
+					VID_BLK_I2C_ADDRESS,
+					CHIP_CTRL,
+					FLD_SIF_EN,
+					cx231xx_set_field(FLD_SIF_EN, 0));
+			break;
+		default:
+			/* This is just a casual suggestion to people adding
+			   new boards in case they use a tuner type we don't
+			   currently know about */
+			printk(KERN_INFO "Unknown tuner type configuring SIF");
+			break;
+		}
+		break;
+
+	case AUDIO_INPUT_TUNER_FM:
+		/*  use SIF for FM radio
+		   setupFM();
+		   setAudioStandard(_audio_standard);
+		 */
+		break;
+
+	case AUDIO_INPUT_MUTE:
+		status = vid_blk_write_word(dev, PATH1_CTL1, 0x1F011012);
+		break;
+	}
+
+	/* Take it out of soft reset */
+	status = vid_blk_read_byte(dev, GENERAL_CTL, &gen_ctrl);
+	gen_ctrl &= ~1;
+	status = vid_blk_write_byte(dev, GENERAL_CTL, gen_ctrl);
+
+	return status;
+}
+
+/******************************************************************************
+ *                    C H I P Specific  C O N T R O L   functions             *
+ ******************************************************************************/
+int cx231xx_init_ctrl_pin_status(struct cx231xx *dev)
+{
+	u32 value;
+	int status = 0;
+
+	status = vid_blk_read_word(dev, PIN_CTRL, &value);
+	value |= (~dev->board.ctl_pin_status_mask);
+	status = vid_blk_write_word(dev, PIN_CTRL, value);
+
+	return status;
+}
+
+int cx231xx_set_agc_analog_digital_mux_select(struct cx231xx *dev,
+					      u8 analog_or_digital)
+{
+	int status = 0;
+
+	/* first set the direction to output */
+	status = cx231xx_set_gpio_direction(dev,
+					    dev->board.
+					    agc_analog_digital_select_gpio, 1);
+
+	/* 0 - demod ; 1 - Analog mode */
+	status = cx231xx_set_gpio_value(dev,
+				   dev->board.agc_analog_digital_select_gpio,
+				   analog_or_digital);
+
+	return status;
+}
+
+int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3)
+{
+	u8 value[4] = { 0, 0, 0, 0 };
+	int status = 0;
+	bool current_is_port_3;
+
+	if (dev->board.dont_use_port_3)
+		is_port_3 = false;
+	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
+				       PWR_CTL_EN, value, 4);
+	if (status < 0)
+		return status;
+
+	current_is_port_3 = value[0] & I2C_DEMOD_EN ? true : false;
+
+	/* Just return, if already using the right port */
+	if (current_is_port_3 == is_port_3)
+		return 0;
+
+	if (is_port_3)
+		value[0] |= I2C_DEMOD_EN;
+	else
+		value[0] &= ~I2C_DEMOD_EN;
+
+	cx231xx_info("Changing the i2c master port to %d\n",
+		     is_port_3 ?  3 : 1);
+
+	status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+					PWR_CTL_EN, value, 4);
+
+	return status;
+
+}
+EXPORT_SYMBOL_GPL(cx231xx_enable_i2c_port_3);
+
+void update_HH_register_after_set_DIF(struct cx231xx *dev)
+{
+/*
+	u8 status = 0;
+	u32 value = 0;
+
+	vid_blk_write_word(dev, PIN_CTRL, 0xA0FFF82F);
+	vid_blk_write_word(dev, DIF_MISC_CTRL, 0x0A203F11);
+	vid_blk_write_word(dev, DIF_SRC_PHASE_INC, 0x1BEFBF06);
+
+	status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
+	vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390);
+	status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL,  &value);
+*/
+}
+
+void cx231xx_dump_HH_reg(struct cx231xx *dev)
+{
+	u32 value = 0;
+	u16  i = 0;
+
+	value = 0x45005390;
+	vid_blk_write_word(dev, 0x104, value);
+
+	for (i = 0x100; i < 0x140; i++) {
+		vid_blk_read_word(dev, i, &value);
+		cx231xx_info("reg0x%x=0x%x\n", i, value);
+		i = i+3;
+	}
+
+	for (i = 0x300; i < 0x400; i++) {
+		vid_blk_read_word(dev, i, &value);
+		cx231xx_info("reg0x%x=0x%x\n", i, value);
+		i = i+3;
+	}
+
+	for (i = 0x400; i < 0x440; i++) {
+		vid_blk_read_word(dev, i,  &value);
+		cx231xx_info("reg0x%x=0x%x\n", i, value);
+		i = i+3;
+	}
+
+	vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
+	cx231xx_info("AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
+	vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390);
+	vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
+	cx231xx_info("AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
+}
+
+void cx231xx_dump_SC_reg(struct cx231xx *dev)
+{
+	u8 value[4] = { 0, 0, 0, 0 };
+	cx231xx_info("cx231xx_dump_SC_reg!\n");
+
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", BOARD_CFG_STAT, value[0],
+				 value[1], value[2], value[3]);
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS_MODE_REG,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS_MODE_REG, value[0],
+				 value[1], value[2], value[3]);
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_CFG_REG,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_CFG_REG, value[0],
+				 value[1], value[2], value[3]);
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_LENGTH_REG,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_LENGTH_REG, value[0],
+				 value[1], value[2], value[3]);
+
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_CFG_REG,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_CFG_REG, value[0],
+				 value[1], value[2], value[3]);
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_LENGTH_REG,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_LENGTH_REG, value[0],
+				 value[1], value[2], value[3]);
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", EP_MODE_SET, value[0],
+				 value[1], value[2], value[3]);
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN1,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN1, value[0],
+				 value[1], value[2], value[3]);
+
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN2,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN2, value[0],
+				 value[1], value[2], value[3]);
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN3,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN3, value[0],
+				 value[1], value[2], value[3]);
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK0,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK0, value[0],
+				 value[1], value[2], value[3]);
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK1,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK1, value[0],
+				 value[1], value[2], value[3]);
+
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK2,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK2, value[0],
+				 value[1], value[2], value[3]);
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_GAIN,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_GAIN, value[0],
+				 value[1], value[2], value[3]);
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_CAR_REG,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_CAR_REG, value[0],
+				 value[1], value[2], value[3]);
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG1,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG1, value[0],
+				 value[1], value[2], value[3]);
+
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG2,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG2, value[0],
+				 value[1], value[2], value[3]);
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
+				 value, 4);
+	cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN, value[0],
+				 value[1], value[2], value[3]);
+
+
+}
+
+void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev)
+
+{
+	u8 value = 0;
+
+	afe_read_byte(dev, ADC_STATUS2_CH3, &value);
+	value = (value & 0xFE)|0x01;
+	afe_write_byte(dev, ADC_STATUS2_CH3, value);
+
+	afe_read_byte(dev, ADC_STATUS2_CH3, &value);
+	value = (value & 0xFE)|0x00;
+	afe_write_byte(dev, ADC_STATUS2_CH3, value);
+
+
+/*
+	config colibri to lo-if mode
+
+	FIXME: ntf_mode = 2'b00 by default. But set 0x1 would reduce
+		the diff IF input by half,
+
+		for low-if agc defect
+*/
+
+	afe_read_byte(dev, ADC_NTF_PRECLMP_EN_CH3, &value);
+	value = (value & 0xFC)|0x00;
+	afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH3, value);
+
+	afe_read_byte(dev, ADC_INPUT_CH3, &value);
+	value = (value & 0xF9)|0x02;
+	afe_write_byte(dev, ADC_INPUT_CH3, value);
+
+	afe_read_byte(dev, ADC_FB_FRCRST_CH3, &value);
+	value = (value & 0xFB)|0x04;
+	afe_write_byte(dev, ADC_FB_FRCRST_CH3, value);
+
+	afe_read_byte(dev, ADC_DCSERVO_DEM_CH3, &value);
+	value = (value & 0xFC)|0x03;
+	afe_write_byte(dev, ADC_DCSERVO_DEM_CH3, value);
+
+	afe_read_byte(dev, ADC_CTRL_DAC1_CH3, &value);
+	value = (value & 0xFB)|0x04;
+	afe_write_byte(dev, ADC_CTRL_DAC1_CH3, value);
+
+	afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value);
+	value = (value & 0xF8)|0x06;
+	afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value);
+
+	afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value);
+	value = (value & 0x8F)|0x40;
+	afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value);
+
+	afe_read_byte(dev, ADC_PWRDN_CLAMP_CH3, &value);
+	value = (value & 0xDF)|0x20;
+	afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, value);
+}
+
+void cx231xx_set_Colibri_For_LowIF(struct cx231xx *dev, u32 if_freq,
+		 u8 spectral_invert, u32 mode)
+{
+	u32 colibri_carrier_offset = 0;
+	u32 func_mode = 0x01; /* Device has a DIF if this function is called */
+	u32 standard = 0;
+	u8 value[4] = { 0, 0, 0, 0 };
+
+	cx231xx_info("Enter cx231xx_set_Colibri_For_LowIF()\n");
+	value[0] = (u8) 0x6F;
+	value[1] = (u8) 0x6F;
+	value[2] = (u8) 0x6F;
+	value[3] = (u8) 0x6F;
+	cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+					PWR_CTL_EN, value, 4);
+
+	/*Set colibri for low IF*/
+	cx231xx_afe_set_mode(dev, AFE_MODE_LOW_IF);
+
+	/* Set C2HH for low IF operation.*/
+	standard = dev->norm;
+	cx231xx_dif_configure_C2HH_for_low_IF(dev, dev->active_mode,
+						       func_mode, standard);
+
+	/* Get colibri offsets.*/
+	colibri_carrier_offset = cx231xx_Get_Colibri_CarrierOffset(mode,
+								   standard);
+
+	cx231xx_info("colibri_carrier_offset=%d, standard=0x%x\n",
+		     colibri_carrier_offset, standard);
+
+	/* Set the band Pass filter for DIF*/
+	cx231xx_set_DIF_bandpass(dev, (if_freq+colibri_carrier_offset),
+				 spectral_invert, mode);
+}
+
+u32 cx231xx_Get_Colibri_CarrierOffset(u32 mode, u32 standerd)
+{
+	u32 colibri_carrier_offset = 0;
+
+	if (mode == TUNER_MODE_FM_RADIO) {
+		colibri_carrier_offset = 1100000;
+	} else if (standerd & (V4L2_STD_MN | V4L2_STD_NTSC_M_JP)) {
+		colibri_carrier_offset = 4832000;  /*4.83MHz	*/
+	} else if (standerd & (V4L2_STD_PAL_B | V4L2_STD_PAL_G)) {
+		colibri_carrier_offset = 2700000;  /*2.70MHz       */
+	} else if (standerd & (V4L2_STD_PAL_D | V4L2_STD_PAL_I
+			| V4L2_STD_SECAM)) {
+		colibri_carrier_offset = 2100000;  /*2.10MHz	*/
+	}
+
+	return colibri_carrier_offset;
+}
+
+void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq,
+		 u8 spectral_invert, u32 mode)
+{
+	unsigned long pll_freq_word;
+	u32 dif_misc_ctrl_value = 0;
+	u64 pll_freq_u64 = 0;
+	u32 i = 0;
+
+	cx231xx_info("if_freq=%d;spectral_invert=0x%x;mode=0x%x\n",
+			 if_freq, spectral_invert, mode);
+
+
+	if (mode == TUNER_MODE_FM_RADIO) {
+		pll_freq_word = 0x905A1CAC;
+		vid_blk_write_word(dev, DIF_PLL_FREQ_WORD,  pll_freq_word);
+
+	} else /*KSPROPERTY_TUNER_MODE_TV*/{
+		/* Calculate the PLL frequency word based on the adjusted if_freq*/
+		pll_freq_word = if_freq;
+		pll_freq_u64 = (u64)pll_freq_word << 28L;
+		do_div(pll_freq_u64, 50000000);
+		pll_freq_word = (u32)pll_freq_u64;
+		/*pll_freq_word = 0x3463497;*/
+		vid_blk_write_word(dev, DIF_PLL_FREQ_WORD,  pll_freq_word);
+
+	if (spectral_invert) {
+		if_freq -= 400000;
+		/* Enable Spectral Invert*/
+		vid_blk_read_word(dev, DIF_MISC_CTRL,
+					&dif_misc_ctrl_value);
+		dif_misc_ctrl_value = dif_misc_ctrl_value | 0x00200000;
+		vid_blk_write_word(dev, DIF_MISC_CTRL,
+					dif_misc_ctrl_value);
+	} else {
+		if_freq += 400000;
+		/* Disable Spectral Invert*/
+		vid_blk_read_word(dev, DIF_MISC_CTRL,
+					&dif_misc_ctrl_value);
+		dif_misc_ctrl_value = dif_misc_ctrl_value & 0xFFDFFFFF;
+		vid_blk_write_word(dev, DIF_MISC_CTRL,
+					dif_misc_ctrl_value);
+	}
+
+	if_freq = (if_freq/100000)*100000;
+
+	if (if_freq < 3000000)
+		if_freq = 3000000;
+
+	if (if_freq > 16000000)
+		if_freq = 16000000;
+	}
+
+	cx231xx_info("Enter IF=%zd\n",
+			ARRAY_SIZE(Dif_set_array));
+	for (i = 0; i < ARRAY_SIZE(Dif_set_array); i++) {
+		if (Dif_set_array[i].if_freq == if_freq) {
+			vid_blk_write_word(dev,
+			Dif_set_array[i].register_address, Dif_set_array[i].value);
+		}
+	}
+}
+
+/******************************************************************************
+ *                 D I F - B L O C K    C O N T R O L   functions             *
+ ******************************************************************************/
+int cx231xx_dif_configure_C2HH_for_low_IF(struct cx231xx *dev, u32 mode,
+					  u32 function_mode, u32 standard)
+{
+	int status = 0;
+
+
+	if (mode == V4L2_TUNER_RADIO) {
+		/* C2HH */
+		/* lo if big signal */
+		status = cx231xx_reg_mask_write(dev,
+				VID_BLK_I2C_ADDRESS, 32,
+				AFE_CTRL_C2HH_SRC_CTRL, 30, 31, 0x1);
+		/* FUNC_MODE = DIF */
+		status = cx231xx_reg_mask_write(dev,
+				VID_BLK_I2C_ADDRESS, 32,
+				AFE_CTRL_C2HH_SRC_CTRL, 23, 24, function_mode);
+		/* IF_MODE */
+		status = cx231xx_reg_mask_write(dev,
+				VID_BLK_I2C_ADDRESS, 32,
+				AFE_CTRL_C2HH_SRC_CTRL, 15, 22, 0xFF);
+		/* no inv */
+		status = cx231xx_reg_mask_write(dev,
+				VID_BLK_I2C_ADDRESS, 32,
+				AFE_CTRL_C2HH_SRC_CTRL, 9, 9, 0x1);
+	} else if (standard != DIF_USE_BASEBAND) {
+		if (standard & V4L2_STD_MN) {
+			/* lo if big signal */
+			status = cx231xx_reg_mask_write(dev,
+					VID_BLK_I2C_ADDRESS, 32,
+					AFE_CTRL_C2HH_SRC_CTRL, 30, 31, 0x1);
+			/* FUNC_MODE = DIF */
+			status = cx231xx_reg_mask_write(dev,
+					VID_BLK_I2C_ADDRESS, 32,
+					AFE_CTRL_C2HH_SRC_CTRL, 23, 24,
+					function_mode);
+			/* IF_MODE */
+			status = cx231xx_reg_mask_write(dev,
+					VID_BLK_I2C_ADDRESS, 32,
+					AFE_CTRL_C2HH_SRC_CTRL, 15, 22, 0xb);
+			/* no inv */
+			status = cx231xx_reg_mask_write(dev,
+					VID_BLK_I2C_ADDRESS, 32,
+					AFE_CTRL_C2HH_SRC_CTRL, 9, 9, 0x1);
+			/* 0x124, AUD_CHAN1_SRC = 0x3 */
+			status = cx231xx_reg_mask_write(dev,
+					VID_BLK_I2C_ADDRESS, 32,
+					AUD_IO_CTRL, 0, 31, 0x00000003);
+		} else if ((standard == V4L2_STD_PAL_I) |
+			(standard & V4L2_STD_PAL_D) |
+			(standard & V4L2_STD_SECAM)) {
+			/* C2HH setup */
+			/* lo if big signal */
+			status = cx231xx_reg_mask_write(dev,
+					VID_BLK_I2C_ADDRESS, 32,
+					AFE_CTRL_C2HH_SRC_CTRL, 30, 31, 0x1);
+			/* FUNC_MODE = DIF */
+			status = cx231xx_reg_mask_write(dev,
+					VID_BLK_I2C_ADDRESS, 32,
+					AFE_CTRL_C2HH_SRC_CTRL, 23, 24,
+					function_mode);
+			/* IF_MODE */
+			status = cx231xx_reg_mask_write(dev,
+					VID_BLK_I2C_ADDRESS, 32,
+					AFE_CTRL_C2HH_SRC_CTRL, 15, 22, 0xF);
+			/* no inv */
+			status = cx231xx_reg_mask_write(dev,
+					VID_BLK_I2C_ADDRESS, 32,
+					AFE_CTRL_C2HH_SRC_CTRL, 9, 9, 0x1);
+		} else {
+			/* default PAL BG */
+			/* C2HH setup */
+			/* lo if big signal */
+			status = cx231xx_reg_mask_write(dev,
+					VID_BLK_I2C_ADDRESS, 32,
+					AFE_CTRL_C2HH_SRC_CTRL, 30, 31, 0x1);
+			/* FUNC_MODE = DIF */
+			status = cx231xx_reg_mask_write(dev,
+					VID_BLK_I2C_ADDRESS, 32,
+					AFE_CTRL_C2HH_SRC_CTRL, 23, 24,
+					function_mode);
+			/* IF_MODE */
+			status = cx231xx_reg_mask_write(dev,
+					VID_BLK_I2C_ADDRESS, 32,
+					AFE_CTRL_C2HH_SRC_CTRL, 15, 22, 0xE);
+			/* no inv */
+			status = cx231xx_reg_mask_write(dev,
+					VID_BLK_I2C_ADDRESS, 32,
+					AFE_CTRL_C2HH_SRC_CTRL, 9, 9, 0x1);
+		}
+	}
+
+	return status;
+}
+
+int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard)
+{
+	int status = 0;
+	u32 dif_misc_ctrl_value = 0;
+	u32 func_mode = 0;
+
+	cx231xx_info("%s: setStandard to %x\n", __func__, standard);
+
+	status = vid_blk_read_word(dev, DIF_MISC_CTRL, &dif_misc_ctrl_value);
+	if (standard != DIF_USE_BASEBAND)
+		dev->norm = standard;
+
+	switch (dev->model) {
+	case CX231XX_BOARD_CNXT_CARRAERA:
+	case CX231XX_BOARD_CNXT_RDE_250:
+	case CX231XX_BOARD_CNXT_SHELBY:
+	case CX231XX_BOARD_CNXT_RDU_250:
+	case CX231XX_BOARD_CNXT_VIDEO_GRABBER:
+	case CX231XX_BOARD_HAUPPAUGE_EXETER:
+		func_mode = 0x03;
+		break;
+	case CX231XX_BOARD_CNXT_RDE_253S:
+	case CX231XX_BOARD_CNXT_RDU_253S:
+	case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
+	case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
+		func_mode = 0x01;
+		break;
+	default:
+		func_mode = 0x01;
+	}
+
+	status = cx231xx_dif_configure_C2HH_for_low_IF(dev, dev->active_mode,
+						  func_mode, standard);
+
+	if (standard == DIF_USE_BASEBAND) {	/* base band */
+		/* There is a different SRC_PHASE_INC value
+		   for baseband vs. DIF */
+		status = vid_blk_write_word(dev, DIF_SRC_PHASE_INC, 0xDF7DF83);
+		status = vid_blk_read_word(dev, DIF_MISC_CTRL,
+						&dif_misc_ctrl_value);
+		dif_misc_ctrl_value |= FLD_DIF_DIF_BYPASS;
+		status = vid_blk_write_word(dev, DIF_MISC_CTRL,
+						dif_misc_ctrl_value);
+	} else if (standard & V4L2_STD_PAL_D) {
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL, 0, 31, 0x6503bc0c);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL1, 0, 31, 0xbd038c85);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL2, 0, 31, 0x1db4640a);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL3, 0, 31, 0x00008800);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_IF_REF, 0, 31, 0x444C1380);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_CTRL_IF, 0, 31, 0xDA302600);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_CTRL_INT, 0, 31, 0xDA261700);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_CTRL_RF, 0, 31, 0xDA262600);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_IF_INT_CURRENT, 0, 31,
+					   0x26001700);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_RF_CURRENT, 0, 31,
+					   0x00002660);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_VIDEO_AGC_CTRL, 0, 31,
+					   0x72500800);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_VID_AUD_OVERRIDE, 0, 31,
+					   0x27000100);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AV_SEP_CTRL, 0, 31, 0x3F3934EA);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_COMP_FLT_CTRL, 0, 31,
+					   0x00000000);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_SRC_PHASE_INC, 0, 31,
+					   0x1befbf06);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_SRC_GAIN_CONTROL, 0, 31,
+					   0x000035e8);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_RPT_VARIANCE, 0, 31, 0x00000000);
+		/* Save the Spec Inversion value */
+		dif_misc_ctrl_value &= FLD_DIF_SPEC_INV;
+		dif_misc_ctrl_value |= 0x3a023F11;
+	} else if (standard & V4L2_STD_PAL_I) {
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL, 0, 31, 0x6503bc0c);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL1, 0, 31, 0xbd038c85);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL2, 0, 31, 0x1db4640a);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL3, 0, 31, 0x00008800);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_IF_REF, 0, 31, 0x444C1380);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_CTRL_IF, 0, 31, 0xDA302600);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_CTRL_INT, 0, 31, 0xDA261700);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_CTRL_RF, 0, 31, 0xDA262600);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_IF_INT_CURRENT, 0, 31,
+					   0x26001700);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_RF_CURRENT, 0, 31,
+					   0x00002660);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_VIDEO_AGC_CTRL, 0, 31,
+					   0x72500800);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_VID_AUD_OVERRIDE, 0, 31,
+					   0x27000100);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AV_SEP_CTRL, 0, 31, 0x5F39A934);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_COMP_FLT_CTRL, 0, 31,
+					   0x00000000);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_SRC_PHASE_INC, 0, 31,
+					   0x1befbf06);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_SRC_GAIN_CONTROL, 0, 31,
+					   0x000035e8);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_RPT_VARIANCE, 0, 31, 0x00000000);
+		/* Save the Spec Inversion value */
+		dif_misc_ctrl_value &= FLD_DIF_SPEC_INV;
+		dif_misc_ctrl_value |= 0x3a033F11;
+	} else if (standard & V4L2_STD_PAL_M) {
+		/* improved Low Frequency Phase Noise */
+		status = vid_blk_write_word(dev, DIF_PLL_CTRL, 0xFF01FF0C);
+		status = vid_blk_write_word(dev, DIF_PLL_CTRL1, 0xbd038c85);
+		status = vid_blk_write_word(dev, DIF_PLL_CTRL2, 0x1db4640a);
+		status = vid_blk_write_word(dev, DIF_PLL_CTRL3, 0x00008800);
+		status = vid_blk_write_word(dev, DIF_AGC_IF_REF, 0x444C1380);
+		status = vid_blk_write_word(dev, DIF_AGC_IF_INT_CURRENT,
+						0x26001700);
+		status = vid_blk_write_word(dev, DIF_AGC_RF_CURRENT,
+						0x00002660);
+		status = vid_blk_write_word(dev, DIF_VIDEO_AGC_CTRL,
+						0x72500800);
+		status = vid_blk_write_word(dev, DIF_VID_AUD_OVERRIDE,
+						0x27000100);
+		status = vid_blk_write_word(dev, DIF_AV_SEP_CTRL, 0x012c405d);
+		status = vid_blk_write_word(dev, DIF_COMP_FLT_CTRL,
+						0x009f50c1);
+		status = vid_blk_write_word(dev, DIF_SRC_PHASE_INC,
+						0x1befbf06);
+		status = vid_blk_write_word(dev, DIF_SRC_GAIN_CONTROL,
+						0x000035e8);
+		status = vid_blk_write_word(dev, DIF_SOFT_RST_CTRL_REVB,
+						0x00000000);
+		/* Save the Spec Inversion value */
+		dif_misc_ctrl_value &= FLD_DIF_SPEC_INV;
+		dif_misc_ctrl_value |= 0x3A0A3F10;
+	} else if (standard & (V4L2_STD_PAL_N | V4L2_STD_PAL_Nc)) {
+		/* improved Low Frequency Phase Noise */
+		status = vid_blk_write_word(dev, DIF_PLL_CTRL, 0xFF01FF0C);
+		status = vid_blk_write_word(dev, DIF_PLL_CTRL1, 0xbd038c85);
+		status = vid_blk_write_word(dev, DIF_PLL_CTRL2, 0x1db4640a);
+		status = vid_blk_write_word(dev, DIF_PLL_CTRL3, 0x00008800);
+		status = vid_blk_write_word(dev, DIF_AGC_IF_REF, 0x444C1380);
+		status = vid_blk_write_word(dev, DIF_AGC_IF_INT_CURRENT,
+						0x26001700);
+		status = vid_blk_write_word(dev, DIF_AGC_RF_CURRENT,
+						0x00002660);
+		status = vid_blk_write_word(dev, DIF_VIDEO_AGC_CTRL,
+						0x72500800);
+		status = vid_blk_write_word(dev, DIF_VID_AUD_OVERRIDE,
+						0x27000100);
+		status = vid_blk_write_word(dev, DIF_AV_SEP_CTRL,
+						0x012c405d);
+		status = vid_blk_write_word(dev, DIF_COMP_FLT_CTRL,
+						0x009f50c1);
+		status = vid_blk_write_word(dev, DIF_SRC_PHASE_INC,
+						0x1befbf06);
+		status = vid_blk_write_word(dev, DIF_SRC_GAIN_CONTROL,
+						0x000035e8);
+		status = vid_blk_write_word(dev, DIF_SOFT_RST_CTRL_REVB,
+						0x00000000);
+		/* Save the Spec Inversion value */
+		dif_misc_ctrl_value &= FLD_DIF_SPEC_INV;
+		dif_misc_ctrl_value = 0x3A093F10;
+	} else if (standard &
+		  (V4L2_STD_SECAM_B | V4L2_STD_SECAM_D | V4L2_STD_SECAM_G |
+		   V4L2_STD_SECAM_K | V4L2_STD_SECAM_K1)) {
+
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL, 0, 31, 0x6503bc0c);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL1, 0, 31, 0xbd038c85);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL2, 0, 31, 0x1db4640a);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL3, 0, 31, 0x00008800);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_IF_REF, 0, 31, 0x888C0380);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_CTRL_IF, 0, 31, 0xe0262600);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_CTRL_INT, 0, 31, 0xc2171700);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_CTRL_RF, 0, 31, 0xc2262600);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_IF_INT_CURRENT, 0, 31,
+					   0x26001700);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_RF_CURRENT, 0, 31,
+					   0x00002660);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_VID_AUD_OVERRIDE, 0, 31,
+					   0x27000100);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AV_SEP_CTRL, 0, 31, 0x3F3530ec);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_COMP_FLT_CTRL, 0, 31,
+					   0x00000000);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_SRC_PHASE_INC, 0, 31,
+					   0x1befbf06);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_SRC_GAIN_CONTROL, 0, 31,
+					   0x000035e8);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_RPT_VARIANCE, 0, 31, 0x00000000);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_VIDEO_AGC_CTRL, 0, 31,
+					   0xf4000000);
+
+		/* Save the Spec Inversion value */
+		dif_misc_ctrl_value &= FLD_DIF_SPEC_INV;
+		dif_misc_ctrl_value |= 0x3a023F11;
+	} else if (standard & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) {
+		/* Is it SECAM_L1? */
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL, 0, 31, 0x6503bc0c);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL1, 0, 31, 0xbd038c85);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL2, 0, 31, 0x1db4640a);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL3, 0, 31, 0x00008800);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_IF_REF, 0, 31, 0x888C0380);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_CTRL_IF, 0, 31, 0xe0262600);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_CTRL_INT, 0, 31, 0xc2171700);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_CTRL_RF, 0, 31, 0xc2262600);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_IF_INT_CURRENT, 0, 31,
+					   0x26001700);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_RF_CURRENT, 0, 31,
+					   0x00002660);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_VID_AUD_OVERRIDE, 0, 31,
+					   0x27000100);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AV_SEP_CTRL, 0, 31, 0x3F3530ec);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_COMP_FLT_CTRL, 0, 31,
+					   0x00000000);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_SRC_PHASE_INC, 0, 31,
+					   0x1befbf06);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_SRC_GAIN_CONTROL, 0, 31,
+					   0x000035e8);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_RPT_VARIANCE, 0, 31, 0x00000000);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_VIDEO_AGC_CTRL, 0, 31,
+					   0xf2560000);
+
+		/* Save the Spec Inversion value */
+		dif_misc_ctrl_value &= FLD_DIF_SPEC_INV;
+		dif_misc_ctrl_value |= 0x3a023F11;
+
+	} else if (standard & V4L2_STD_NTSC_M) {
+		/* V4L2_STD_NTSC_M (75 IRE Setup) Or
+		   V4L2_STD_NTSC_M_JP (Japan,  0 IRE Setup) */
+
+		/* For NTSC the centre frequency of video coming out of
+		   sidewinder is around 7.1MHz or 3.6MHz depending on the
+		   spectral inversion. so for a non spectrally inverted channel
+		   the pll freq word is 0x03420c49
+		 */
+
+		status = vid_blk_write_word(dev, DIF_PLL_CTRL, 0x6503BC0C);
+		status = vid_blk_write_word(dev, DIF_PLL_CTRL1, 0xBD038C85);
+		status = vid_blk_write_word(dev, DIF_PLL_CTRL2, 0x1DB4640A);
+		status = vid_blk_write_word(dev, DIF_PLL_CTRL3, 0x00008800);
+		status = vid_blk_write_word(dev, DIF_AGC_IF_REF, 0x444C0380);
+		status = vid_blk_write_word(dev, DIF_AGC_IF_INT_CURRENT,
+						0x26001700);
+		status = vid_blk_write_word(dev, DIF_AGC_RF_CURRENT,
+						0x00002660);
+		status = vid_blk_write_word(dev, DIF_VIDEO_AGC_CTRL,
+						0x04000800);
+		status = vid_blk_write_word(dev, DIF_VID_AUD_OVERRIDE,
+						0x27000100);
+		status = vid_blk_write_word(dev, DIF_AV_SEP_CTRL, 0x01296e1f);
+
+		status = vid_blk_write_word(dev, DIF_COMP_FLT_CTRL,
+						0x009f50c1);
+		status = vid_blk_write_word(dev, DIF_SRC_PHASE_INC,
+						0x1befbf06);
+		status = vid_blk_write_word(dev, DIF_SRC_GAIN_CONTROL,
+						0x000035e8);
+
+		status = vid_blk_write_word(dev, DIF_AGC_CTRL_IF, 0xC2262600);
+		status = vid_blk_write_word(dev, DIF_AGC_CTRL_INT,
+						0xC2262600);
+		status = vid_blk_write_word(dev, DIF_AGC_CTRL_RF, 0xC2262600);
+
+		/* Save the Spec Inversion value */
+		dif_misc_ctrl_value &= FLD_DIF_SPEC_INV;
+		dif_misc_ctrl_value |= 0x3a003F10;
+	} else {
+		/* default PAL BG */
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL, 0, 31, 0x6503bc0c);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL1, 0, 31, 0xbd038c85);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL2, 0, 31, 0x1db4640a);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_PLL_CTRL3, 0, 31, 0x00008800);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_IF_REF, 0, 31, 0x444C1380);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_CTRL_IF, 0, 31, 0xDA302600);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_CTRL_INT, 0, 31, 0xDA261700);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_CTRL_RF, 0, 31, 0xDA262600);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_IF_INT_CURRENT, 0, 31,
+					   0x26001700);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AGC_RF_CURRENT, 0, 31,
+					   0x00002660);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_VIDEO_AGC_CTRL, 0, 31,
+					   0x72500800);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_VID_AUD_OVERRIDE, 0, 31,
+					   0x27000100);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_AV_SEP_CTRL, 0, 31, 0x3F3530EC);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_COMP_FLT_CTRL, 0, 31,
+					   0x00A653A8);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_SRC_PHASE_INC, 0, 31,
+					   0x1befbf06);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_SRC_GAIN_CONTROL, 0, 31,
+					   0x000035e8);
+		status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32,
+					   DIF_RPT_VARIANCE, 0, 31, 0x00000000);
+		/* Save the Spec Inversion value */
+		dif_misc_ctrl_value &= FLD_DIF_SPEC_INV;
+		dif_misc_ctrl_value |= 0x3a013F11;
+	}
+
+	/* The AGC values should be the same for all standards,
+	   AUD_SRC_SEL[19] should always be disabled    */
+	dif_misc_ctrl_value &= ~FLD_DIF_AUD_SRC_SEL;
+
+	/* It is still possible to get Set Standard calls even when we
+	   are in FM mode.
+	   This is done to override the value for FM. */
+	if (dev->active_mode == V4L2_TUNER_RADIO)
+		dif_misc_ctrl_value = 0x7a080000;
+
+	/* Write the calculated value for misc ontrol register      */
+	status = vid_blk_write_word(dev, DIF_MISC_CTRL, dif_misc_ctrl_value);
+
+	return status;
+}
+
+int cx231xx_tuner_pre_channel_change(struct cx231xx *dev)
+{
+	int status = 0;
+	u32 dwval;
+
+	/* Set the RF and IF k_agc values to 3 */
+	status = vid_blk_read_word(dev, DIF_AGC_IF_REF, &dwval);
+	dwval &= ~(FLD_DIF_K_AGC_RF | FLD_DIF_K_AGC_IF);
+	dwval |= 0x33000000;
+
+	status = vid_blk_write_word(dev, DIF_AGC_IF_REF, dwval);
+
+	return status;
+}
+
+int cx231xx_tuner_post_channel_change(struct cx231xx *dev)
+{
+	int status = 0;
+	u32 dwval;
+	cx231xx_info("cx231xx_tuner_post_channel_change  dev->tuner_type =0%d\n",
+		     dev->tuner_type);
+	/* Set the RF and IF k_agc values to 4 for PAL/NTSC and 8 for
+	 * SECAM L/B/D standards */
+	status = vid_blk_read_word(dev, DIF_AGC_IF_REF, &dwval);
+	dwval &= ~(FLD_DIF_K_AGC_RF | FLD_DIF_K_AGC_IF);
+
+	if (dev->norm & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_B |
+			 V4L2_STD_SECAM_D)) {
+			if (dev->tuner_type == TUNER_NXP_TDA18271) {
+				dwval &= ~FLD_DIF_IF_REF;
+				dwval |= 0x88000300;
+			} else
+				dwval |= 0x88000000;
+		} else {
+			if (dev->tuner_type == TUNER_NXP_TDA18271) {
+				dwval &= ~FLD_DIF_IF_REF;
+				dwval |= 0xCC000300;
+			} else
+				dwval |= 0x44000000;
+		}
+
+	status = vid_blk_write_word(dev, DIF_AGC_IF_REF, dwval);
+
+	return status;
+}
+
+/******************************************************************************
+ *        	    I 2 S - B L O C K    C O N T R O L   functions            *
+ ******************************************************************************/
+int cx231xx_i2s_blk_initialize(struct cx231xx *dev)
+{
+	int status = 0;
+	u32 value;
+
+	status = cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+				       CH_PWR_CTRL1, 1, &value, 1);
+	/* enables clock to delta-sigma and decimation filter */
+	value |= 0x80;
+	status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+					CH_PWR_CTRL1, 1, value, 1);
+	/* power up all channel */
+	status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+					CH_PWR_CTRL2, 1, 0x00, 1);
+
+	return status;
+}
+
+int cx231xx_i2s_blk_update_power_control(struct cx231xx *dev,
+					enum AV_MODE avmode)
+{
+	int status = 0;
+	u32 value = 0;
+
+	if (avmode != POLARIS_AVMODE_ENXTERNAL_AV) {
+		status = cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+					  CH_PWR_CTRL2, 1, &value, 1);
+		value |= 0xfe;
+		status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+						CH_PWR_CTRL2, 1, value, 1);
+	} else {
+		status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+						CH_PWR_CTRL2, 1, 0x00, 1);
+	}
+
+	return status;
+}
+
+/* set i2s_blk for audio input types */
+int cx231xx_i2s_blk_set_audio_input(struct cx231xx *dev, u8 audio_input)
+{
+	int status = 0;
+
+	switch (audio_input) {
+	case CX231XX_AMUX_LINE_IN:
+		status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+						CH_PWR_CTRL2, 1, 0x00, 1);
+		status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+						CH_PWR_CTRL1, 1, 0x80, 1);
+		break;
+	case CX231XX_AMUX_VIDEO:
+	default:
+		break;
+	}
+
+	dev->ctl_ainput = audio_input;
+
+	return status;
+}
+
+/******************************************************************************
+ *                  P O W E R      C O N T R O L   functions                  *
+ ******************************************************************************/
+int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
+{
+	u8 value[4] = { 0, 0, 0, 0 };
+	u32 tmp = 0;
+	int status = 0;
+
+	if (dev->power_mode != mode)
+		dev->power_mode = mode;
+	else {
+		cx231xx_info(" setPowerMode::mode = %d, No Change req.\n",
+			     mode);
+		return 0;
+	}
+
+	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, value,
+				       4);
+	if (status < 0)
+		return status;
+
+	tmp = *((u32 *) value);
+
+	switch (mode) {
+	case POLARIS_AVMODE_ENXTERNAL_AV:
+
+		tmp &= (~PWR_MODE_MASK);
+
+		tmp |= PWR_AV_EN;
+		value[0] = (u8) tmp;
+		value[1] = (u8) (tmp >> 8);
+		value[2] = (u8) (tmp >> 16);
+		value[3] = (u8) (tmp >> 24);
+		status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+						PWR_CTL_EN, value, 4);
+		msleep(PWR_SLEEP_INTERVAL);
+
+		tmp |= PWR_ISO_EN;
+		value[0] = (u8) tmp;
+		value[1] = (u8) (tmp >> 8);
+		value[2] = (u8) (tmp >> 16);
+		value[3] = (u8) (tmp >> 24);
+		status =
+		    cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, PWR_CTL_EN,
+					   value, 4);
+		msleep(PWR_SLEEP_INTERVAL);
+
+		tmp |= POLARIS_AVMODE_ENXTERNAL_AV;
+		value[0] = (u8) tmp;
+		value[1] = (u8) (tmp >> 8);
+		value[2] = (u8) (tmp >> 16);
+		value[3] = (u8) (tmp >> 24);
+		status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+						PWR_CTL_EN, value, 4);
+
+		/* reset state of xceive tuner */
+		dev->xc_fw_load_done = 0;
+		break;
+
+	case POLARIS_AVMODE_ANALOGT_TV:
+
+		tmp |= PWR_DEMOD_EN;
+		tmp |= (I2C_DEMOD_EN);
+		value[0] = (u8) tmp;
+		value[1] = (u8) (tmp >> 8);
+		value[2] = (u8) (tmp >> 16);
+		value[3] = (u8) (tmp >> 24);
+		status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+						PWR_CTL_EN, value, 4);
+		msleep(PWR_SLEEP_INTERVAL);
+
+		if (!(tmp & PWR_TUNER_EN)) {
+			tmp |= (PWR_TUNER_EN);
+			value[0] = (u8) tmp;
+			value[1] = (u8) (tmp >> 8);
+			value[2] = (u8) (tmp >> 16);
+			value[3] = (u8) (tmp >> 24);
+			status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+							PWR_CTL_EN, value, 4);
+			msleep(PWR_SLEEP_INTERVAL);
+		}
+
+		if (!(tmp & PWR_AV_EN)) {
+			tmp |= PWR_AV_EN;
+			value[0] = (u8) tmp;
+			value[1] = (u8) (tmp >> 8);
+			value[2] = (u8) (tmp >> 16);
+			value[3] = (u8) (tmp >> 24);
+			status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+							PWR_CTL_EN, value, 4);
+			msleep(PWR_SLEEP_INTERVAL);
+		}
+		if (!(tmp & PWR_ISO_EN)) {
+			tmp |= PWR_ISO_EN;
+			value[0] = (u8) tmp;
+			value[1] = (u8) (tmp >> 8);
+			value[2] = (u8) (tmp >> 16);
+			value[3] = (u8) (tmp >> 24);
+			status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+							PWR_CTL_EN, value, 4);
+			msleep(PWR_SLEEP_INTERVAL);
+		}
+
+		if (!(tmp & POLARIS_AVMODE_ANALOGT_TV)) {
+			tmp |= POLARIS_AVMODE_ANALOGT_TV;
+			value[0] = (u8) tmp;
+			value[1] = (u8) (tmp >> 8);
+			value[2] = (u8) (tmp >> 16);
+			value[3] = (u8) (tmp >> 24);
+			status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+							PWR_CTL_EN, value, 4);
+			msleep(PWR_SLEEP_INTERVAL);
+		}
+
+		if (dev->board.tuner_type != TUNER_ABSENT) {
+			/* Enable tuner */
+			cx231xx_enable_i2c_port_3(dev, true);
+
+			/* reset the Tuner */
+			if (dev->board.tuner_gpio)
+				cx231xx_gpio_set(dev, dev->board.tuner_gpio);
+
+			if (dev->cx231xx_reset_analog_tuner)
+				dev->cx231xx_reset_analog_tuner(dev);
+		}
+
+		break;
+
+	case POLARIS_AVMODE_DIGITAL:
+		if (!(tmp & PWR_TUNER_EN)) {
+			tmp |= (PWR_TUNER_EN);
+			value[0] = (u8) tmp;
+			value[1] = (u8) (tmp >> 8);
+			value[2] = (u8) (tmp >> 16);
+			value[3] = (u8) (tmp >> 24);
+			status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+							PWR_CTL_EN, value, 4);
+			msleep(PWR_SLEEP_INTERVAL);
+		}
+		if (!(tmp & PWR_AV_EN)) {
+			tmp |= PWR_AV_EN;
+			value[0] = (u8) tmp;
+			value[1] = (u8) (tmp >> 8);
+			value[2] = (u8) (tmp >> 16);
+			value[3] = (u8) (tmp >> 24);
+			status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+							PWR_CTL_EN, value, 4);
+			msleep(PWR_SLEEP_INTERVAL);
+		}
+		if (!(tmp & PWR_ISO_EN)) {
+			tmp |= PWR_ISO_EN;
+			value[0] = (u8) tmp;
+			value[1] = (u8) (tmp >> 8);
+			value[2] = (u8) (tmp >> 16);
+			value[3] = (u8) (tmp >> 24);
+			status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+							PWR_CTL_EN, value, 4);
+			msleep(PWR_SLEEP_INTERVAL);
+		}
+
+		tmp &= (~PWR_AV_MODE);
+		tmp |= POLARIS_AVMODE_DIGITAL | I2C_DEMOD_EN;
+		value[0] = (u8) tmp;
+		value[1] = (u8) (tmp >> 8);
+		value[2] = (u8) (tmp >> 16);
+		value[3] = (u8) (tmp >> 24);
+		status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+						PWR_CTL_EN, value, 4);
+		msleep(PWR_SLEEP_INTERVAL);
+
+		if (!(tmp & PWR_DEMOD_EN)) {
+			tmp |= PWR_DEMOD_EN;
+			value[0] = (u8) tmp;
+			value[1] = (u8) (tmp >> 8);
+			value[2] = (u8) (tmp >> 16);
+			value[3] = (u8) (tmp >> 24);
+			status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+							PWR_CTL_EN, value, 4);
+			msleep(PWR_SLEEP_INTERVAL);
+		}
+
+		if (dev->board.tuner_type != TUNER_ABSENT) {
+			/*
+			 * Enable tuner
+			 *	Hauppauge Exeter seems to need to do something different!
+			 */
+			if (dev->model == CX231XX_BOARD_HAUPPAUGE_EXETER)
+				cx231xx_enable_i2c_port_3(dev, false);
+			else
+				cx231xx_enable_i2c_port_3(dev, true);
+
+			/* reset the Tuner */
+			if (dev->board.tuner_gpio)
+				cx231xx_gpio_set(dev, dev->board.tuner_gpio);
+
+			if (dev->cx231xx_reset_analog_tuner)
+				dev->cx231xx_reset_analog_tuner(dev);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	msleep(PWR_SLEEP_INTERVAL);
+
+	/* For power saving, only enable Pwr_resetout_n
+	   when digital TV is selected. */
+	if (mode == POLARIS_AVMODE_DIGITAL) {
+		tmp |= PWR_RESETOUT_EN;
+		value[0] = (u8) tmp;
+		value[1] = (u8) (tmp >> 8);
+		value[2] = (u8) (tmp >> 16);
+		value[3] = (u8) (tmp >> 24);
+		status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+						PWR_CTL_EN, value, 4);
+		msleep(PWR_SLEEP_INTERVAL);
+	}
+
+	/* update power control for afe */
+	status = cx231xx_afe_update_power_control(dev, mode);
+
+	/* update power control for i2s_blk */
+	status = cx231xx_i2s_blk_update_power_control(dev, mode);
+
+	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, value,
+				       4);
+
+	return status;
+}
+
+int cx231xx_power_suspend(struct cx231xx *dev)
+{
+	u8 value[4] = { 0, 0, 0, 0 };
+	u32 tmp = 0;
+	int status = 0;
+
+	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
+				       value, 4);
+	if (status > 0)
+		return status;
+
+	tmp = *((u32 *) value);
+	tmp &= (~PWR_MODE_MASK);
+
+	value[0] = (u8) tmp;
+	value[1] = (u8) (tmp >> 8);
+	value[2] = (u8) (tmp >> 16);
+	value[3] = (u8) (tmp >> 24);
+	status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, PWR_CTL_EN,
+					value, 4);
+
+	return status;
+}
+
+/******************************************************************************
+ *                  S T R E A M    C O N T R O L   functions                  *
+ ******************************************************************************/
+int cx231xx_start_stream(struct cx231xx *dev, u32 ep_mask)
+{
+	u8 value[4] = { 0x0, 0x0, 0x0, 0x0 };
+	u32 tmp = 0;
+	int status = 0;
+
+	cx231xx_info("cx231xx_start_stream():: ep_mask = %x\n", ep_mask);
+	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET,
+				       value, 4);
+	if (status < 0)
+		return status;
+
+	tmp = *((u32 *) value);
+	tmp |= ep_mask;
+	value[0] = (u8) tmp;
+	value[1] = (u8) (tmp >> 8);
+	value[2] = (u8) (tmp >> 16);
+	value[3] = (u8) (tmp >> 24);
+
+	status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, EP_MODE_SET,
+					value, 4);
+
+	return status;
+}
+
+int cx231xx_stop_stream(struct cx231xx *dev, u32 ep_mask)
+{
+	u8 value[4] = { 0x0, 0x0, 0x0, 0x0 };
+	u32 tmp = 0;
+	int status = 0;
+
+	cx231xx_info("cx231xx_stop_stream():: ep_mask = %x\n", ep_mask);
+	status =
+	    cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET, value, 4);
+	if (status < 0)
+		return status;
+
+	tmp = *((u32 *) value);
+	tmp &= (~ep_mask);
+	value[0] = (u8) tmp;
+	value[1] = (u8) (tmp >> 8);
+	value[2] = (u8) (tmp >> 16);
+	value[3] = (u8) (tmp >> 24);
+
+	status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, EP_MODE_SET,
+					value, 4);
+
+	return status;
+}
+
+int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type)
+{
+	int status = 0;
+	u32 value = 0;
+	u8 val[4] = { 0, 0, 0, 0 };
+
+	if (dev->udev->speed == USB_SPEED_HIGH) {
+		switch (media_type) {
+		case Audio:
+			cx231xx_info("%s: Audio enter HANC\n", __func__);
+			status =
+			    cx231xx_mode_register(dev, TS_MODE_REG, 0x9300);
+			break;
+
+		case Vbi:
+			cx231xx_info("%s: set vanc registers\n", __func__);
+			status = cx231xx_mode_register(dev, TS_MODE_REG, 0x300);
+			break;
+
+		case Sliced_cc:
+			cx231xx_info("%s: set hanc registers\n", __func__);
+			status =
+			    cx231xx_mode_register(dev, TS_MODE_REG, 0x1300);
+			break;
+
+		case Raw_Video:
+			cx231xx_info("%s: set video registers\n", __func__);
+			status = cx231xx_mode_register(dev, TS_MODE_REG, 0x100);
+			break;
+
+		case TS1_serial_mode:
+			cx231xx_info("%s: set ts1 registers", __func__);
+
+		if (dev->board.has_417) {
+			cx231xx_info(" MPEG\n");
+			value &= 0xFFFFFFFC;
+			value |= 0x3;
+
+			status = cx231xx_mode_register(dev, TS_MODE_REG, value);
+
+			val[0] = 0x04;
+			val[1] = 0xA3;
+			val[2] = 0x3B;
+			val[3] = 0x00;
+			status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+				 TS1_CFG_REG, val, 4);
+
+			val[0] = 0x00;
+			val[1] = 0x08;
+			val[2] = 0x00;
+			val[3] = 0x08;
+			status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+				 TS1_LENGTH_REG, val, 4);
+
+		} else {
+			cx231xx_info(" BDA\n");
+			status = cx231xx_mode_register(dev, TS_MODE_REG, 0x101);
+			status = cx231xx_mode_register(dev, TS1_CFG_REG, 0x010);
+		}
+			break;
+
+		case TS1_parallel_mode:
+			cx231xx_info("%s: set ts1 parallel mode registers\n",
+				     __func__);
+			status = cx231xx_mode_register(dev, TS_MODE_REG, 0x100);
+			status = cx231xx_mode_register(dev, TS1_CFG_REG, 0x400);
+			break;
+		}
+	} else {
+		status = cx231xx_mode_register(dev, TS_MODE_REG, 0x101);
+	}
+
+	return status;
+}
+
+int cx231xx_capture_start(struct cx231xx *dev, int start, u8 media_type)
+{
+	int rc = -1;
+	u32 ep_mask = -1;
+	struct pcb_config *pcb_config;
+
+	/* get EP for media type */
+	pcb_config = (struct pcb_config *)&dev->current_pcb_config;
+
+	if (pcb_config->config_num) {
+		switch (media_type) {
+		case Raw_Video:
+			ep_mask = ENABLE_EP4;	/* ep4  [00:1000] */
+			break;
+		case Audio:
+			ep_mask = ENABLE_EP3;	/* ep3  [00:0100] */
+			break;
+		case Vbi:
+			ep_mask = ENABLE_EP5;	/* ep5 [01:0000] */
+			break;
+		case Sliced_cc:
+			ep_mask = ENABLE_EP6;	/* ep6 [10:0000] */
+			break;
+		case TS1_serial_mode:
+		case TS1_parallel_mode:
+			ep_mask = ENABLE_EP1;	/* ep1 [00:0001] */
+			break;
+		case TS2:
+			ep_mask = ENABLE_EP2;	/* ep2 [00:0010] */
+			break;
+		}
+	}
+
+	if (start) {
+		rc = cx231xx_initialize_stream_xfer(dev, media_type);
+
+		if (rc < 0)
+			return rc;
+
+		/* enable video capture */
+		if (ep_mask > 0)
+			rc = cx231xx_start_stream(dev, ep_mask);
+	} else {
+		/* disable video capture */
+		if (ep_mask > 0)
+			rc = cx231xx_stop_stream(dev, ep_mask);
+	}
+
+	if (dev->mode == CX231XX_ANALOG_MODE)
+		;/* do any in Analog mode */
+	else
+		;/* do any in digital mode */
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(cx231xx_capture_start);
+
+/*****************************************************************************
+*                   G P I O   B I T control functions                        *
+******************************************************************************/
+int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val)
+{
+	int status = 0;
+
+	status = cx231xx_send_gpio_cmd(dev, gpio_bit, gpio_val, 4, 0, 0);
+
+	return status;
+}
+
+int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val)
+{
+	int status = 0;
+
+	status = cx231xx_send_gpio_cmd(dev, gpio_bit, gpio_val, 4, 0, 1);
+
+	return status;
+}
+
+/*
+* cx231xx_set_gpio_direction
+*      Sets the direction of the GPIO pin to input or output
+*
+* Parameters :
+*      pin_number : The GPIO Pin number to program the direction for
+*                   from 0 to 31
+*      pin_value : The Direction of the GPIO Pin under reference.
+*                      0 = Input direction
+*                      1 = Output direction
+*/
+int cx231xx_set_gpio_direction(struct cx231xx *dev,
+			       int pin_number, int pin_value)
+{
+	int status = 0;
+	u32 value = 0;
+
+	/* Check for valid pin_number - if 32 , bail out */
+	if (pin_number >= 32)
+		return -EINVAL;
+
+	/* input */
+	if (pin_value == 0)
+		value = dev->gpio_dir & (~(1 << pin_number));	/* clear */
+	else
+		value = dev->gpio_dir | (1 << pin_number);
+
+	status = cx231xx_set_gpio_bit(dev, value, (u8 *) &dev->gpio_val);
+
+	/* cache the value for future */
+	dev->gpio_dir = value;
+
+	return status;
+}
+
+/*
+* cx231xx_set_gpio_value
+*      Sets the value of the GPIO pin to Logic high or low. The Pin under
+*      reference should ALREADY BE SET IN OUTPUT MODE !!!!!!!!!
+*
+* Parameters :
+*      pin_number : The GPIO Pin number to program the direction for
+*      pin_value : The value of the GPIO Pin under reference.
+*                      0 = set it to 0
+*                      1 = set it to 1
+*/
+int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value)
+{
+	int status = 0;
+	u32 value = 0;
+
+	/* Check for valid pin_number - if 0xFF , bail out */
+	if (pin_number >= 32)
+		return -EINVAL;
+
+	/* first do a sanity check - if the Pin is not output, make it output */
+	if ((dev->gpio_dir & (1 << pin_number)) == 0x00) {
+		/* It was in input mode */
+		value = dev->gpio_dir | (1 << pin_number);
+		dev->gpio_dir = value;
+		status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+					      (u8 *) &dev->gpio_val);
+		value = 0;
+	}
+
+	if (pin_value == 0)
+		value = dev->gpio_val & (~(1 << pin_number));
+	else
+		value = dev->gpio_val | (1 << pin_number);
+
+	/* store the value */
+	dev->gpio_val = value;
+
+	/* toggle bit0 of GP_IO */
+	status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+	return status;
+}
+
+/*****************************************************************************
+*                      G P I O I2C related functions                         *
+******************************************************************************/
+int cx231xx_gpio_i2c_start(struct cx231xx *dev)
+{
+	int status = 0;
+
+	/* set SCL to output 1 ; set SDA to output 1 */
+	dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio;
+	dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio;
+	dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
+	dev->gpio_val |= 1 << dev->board.tuner_sda_gpio;
+
+	status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+	if (status < 0)
+		return -EINVAL;
+
+	/* set SCL to output 1; set SDA to output 0 */
+	dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
+	dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
+
+	status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+	if (status < 0)
+		return -EINVAL;
+
+	/* set SCL to output 0; set SDA to output 0      */
+	dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+	dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
+
+	status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+	if (status < 0)
+		return -EINVAL;
+
+	return status;
+}
+
+int cx231xx_gpio_i2c_end(struct cx231xx *dev)
+{
+	int status = 0;
+
+	/* set SCL to output 0; set SDA to output 0      */
+	dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio;
+	dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio;
+
+	dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+	dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
+
+	status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+	if (status < 0)
+		return -EINVAL;
+
+	/* set SCL to output 1; set SDA to output 0      */
+	dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
+	dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
+
+	status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+	if (status < 0)
+		return -EINVAL;
+
+	/* set SCL to input ,release SCL cable control
+	   set SDA to input ,release SDA cable control */
+	dev->gpio_dir &= ~(1 << dev->board.tuner_scl_gpio);
+	dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio);
+
+	status =
+	    cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+	if (status < 0)
+		return -EINVAL;
+
+	return status;
+}
+
+int cx231xx_gpio_i2c_write_byte(struct cx231xx *dev, u8 data)
+{
+	int status = 0;
+	u8 i;
+
+	/* set SCL to output ; set SDA to output */
+	dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio;
+	dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio;
+
+	for (i = 0; i < 8; i++) {
+		if (((data << i) & 0x80) == 0) {
+			/* set SCL to output 0; set SDA to output 0     */
+			dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+			dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
+			status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+						      (u8 *)&dev->gpio_val);
+
+			/* set SCL to output 1; set SDA to output 0     */
+			dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
+			status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+						      (u8 *)&dev->gpio_val);
+
+			/* set SCL to output 0; set SDA to output 0     */
+			dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+			status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+						      (u8 *)&dev->gpio_val);
+		} else {
+			/* set SCL to output 0; set SDA to output 1     */
+			dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+			dev->gpio_val |= 1 << dev->board.tuner_sda_gpio;
+			status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+						      (u8 *)&dev->gpio_val);
+
+			/* set SCL to output 1; set SDA to output 1     */
+			dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
+			status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+						      (u8 *)&dev->gpio_val);
+
+			/* set SCL to output 0; set SDA to output 1     */
+			dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+			status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+						      (u8 *)&dev->gpio_val);
+		}
+	}
+	return status;
+}
+
+int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 *buf)
+{
+	u8 value = 0;
+	int status = 0;
+	u32 gpio_logic_value = 0;
+	u8 i;
+
+	/* read byte */
+	for (i = 0; i < 8; i++) {	/* send write I2c addr */
+
+		/* set SCL to output 0; set SDA to input */
+		dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+		status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+					      (u8 *)&dev->gpio_val);
+
+		/* set SCL to output 1; set SDA to input */
+		dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
+		status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
+					      (u8 *)&dev->gpio_val);
+
+		/* get SDA data bit */
+		gpio_logic_value = dev->gpio_val;
+		status = cx231xx_get_gpio_bit(dev, dev->gpio_dir,
+					      (u8 *)&dev->gpio_val);
+		if ((dev->gpio_val & (1 << dev->board.tuner_sda_gpio)) != 0)
+			value |= (1 << (8 - i - 1));
+
+		dev->gpio_val = gpio_logic_value;
+	}
+
+	/* set SCL to output 0,finish the read latest SCL signal.
+	   !!!set SDA to input, never to modify SDA direction at
+	   the same times */
+	dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+	status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+	/* store the value */
+	*buf = value & 0xff;
+
+	return status;
+}
+
+int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev)
+{
+	int status = 0;
+	u32 gpio_logic_value = 0;
+	int nCnt = 10;
+	int nInit = nCnt;
+
+	/* clock stretch; set SCL to input; set SDA to input;
+	   get SCL value till SCL = 1 */
+	dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio);
+	dev->gpio_dir &= ~(1 << dev->board.tuner_scl_gpio);
+
+	gpio_logic_value = dev->gpio_val;
+	status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+	do {
+		msleep(2);
+		status = cx231xx_get_gpio_bit(dev, dev->gpio_dir,
+					      (u8 *)&dev->gpio_val);
+		nCnt--;
+	} while (((dev->gpio_val &
+			  (1 << dev->board.tuner_scl_gpio)) == 0) &&
+			 (nCnt > 0));
+
+	if (nCnt == 0)
+		cx231xx_info("No ACK after %d msec -GPIO I2C failed!",
+			     nInit * 10);
+
+	/*
+	 * readAck
+	 * through clock stretch, slave has given a SCL signal,
+	 * so the SDA data can be directly read.
+	 */
+	status = cx231xx_get_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+	if ((dev->gpio_val & 1 << dev->board.tuner_sda_gpio) == 0) {
+		dev->gpio_val = gpio_logic_value;
+		dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
+		status = 0;
+	} else {
+		dev->gpio_val = gpio_logic_value;
+		dev->gpio_val |= (1 << dev->board.tuner_sda_gpio);
+	}
+
+	/* read SDA end, set the SCL to output 0, after this operation,
+	   SDA direction can be changed. */
+	dev->gpio_val = gpio_logic_value;
+	dev->gpio_dir |= (1 << dev->board.tuner_scl_gpio);
+	dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+	status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+	return status;
+}
+
+int cx231xx_gpio_i2c_write_ack(struct cx231xx *dev)
+{
+	int status = 0;
+
+	/* set SDA to ouput */
+	dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio;
+	status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+	/* set SCL = 0 (output); set SDA = 0 (output) */
+	dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
+	dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+	status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+	/* set SCL = 1 (output); set SDA = 0 (output) */
+	dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
+	status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+	/* set SCL = 0 (output); set SDA = 0 (output) */
+	dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+	status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+	/* set SDA to input,and then the slave will read data from SDA. */
+	dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio);
+	status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+	return status;
+}
+
+int cx231xx_gpio_i2c_write_nak(struct cx231xx *dev)
+{
+	int status = 0;
+
+	/* set scl to output ; set sda to input */
+	dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio;
+	dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio);
+	status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+	/* set scl to output 0; set sda to input */
+	dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
+	status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+	/* set scl to output 1; set sda to input */
+	dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
+	status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+
+	return status;
+}
+
+/*****************************************************************************
+*                      G P I O I2C related functions                         *
+******************************************************************************/
+/* cx231xx_gpio_i2c_read
+ * Function to read data from gpio based I2C interface
+ */
+int cx231xx_gpio_i2c_read(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len)
+{
+	int status = 0;
+	int i = 0;
+
+	/* get the lock */
+	mutex_lock(&dev->gpio_i2c_lock);
+
+	/* start */
+	status = cx231xx_gpio_i2c_start(dev);
+
+	/* write dev_addr */
+	status = cx231xx_gpio_i2c_write_byte(dev, (dev_addr << 1) + 1);
+
+	/* readAck */
+	status = cx231xx_gpio_i2c_read_ack(dev);
+
+	/* read data */
+	for (i = 0; i < len; i++) {
+		/* read data */
+		buf[i] = 0;
+		status = cx231xx_gpio_i2c_read_byte(dev, &buf[i]);
+
+		if ((i + 1) != len) {
+			/* only do write ack if we more length */
+			status = cx231xx_gpio_i2c_write_ack(dev);
+		}
+	}
+
+	/* write NAK - inform reads are complete */
+	status = cx231xx_gpio_i2c_write_nak(dev);
+
+	/* write end */
+	status = cx231xx_gpio_i2c_end(dev);
+
+	/* release the lock */
+	mutex_unlock(&dev->gpio_i2c_lock);
+
+	return status;
+}
+
+/* cx231xx_gpio_i2c_write
+ * Function to write data to gpio based I2C interface
+ */
+int cx231xx_gpio_i2c_write(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len)
+{
+	int i = 0;
+
+	/* get the lock */
+	mutex_lock(&dev->gpio_i2c_lock);
+
+	/* start */
+	cx231xx_gpio_i2c_start(dev);
+
+	/* write dev_addr */
+	cx231xx_gpio_i2c_write_byte(dev, dev_addr << 1);
+
+	/* read Ack */
+	cx231xx_gpio_i2c_read_ack(dev);
+
+	for (i = 0; i < len; i++) {
+		/* Write data */
+		cx231xx_gpio_i2c_write_byte(dev, buf[i]);
+
+		/* read Ack */
+		cx231xx_gpio_i2c_read_ack(dev);
+	}
+
+	/* write End */
+	cx231xx_gpio_i2c_end(dev);
+
+	/* release the lock */
+	mutex_unlock(&dev->gpio_i2c_lock);
+
+	return 0;
+}
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
new file mode 100644
index 0000000..02d4d36
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -0,0 +1,1370 @@
+/*
+   cx231xx-cards.c - driver for Conexant Cx23100/101/102
+				USB video capture devices
+
+   Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+				Based on em28xx driver
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/usb.h>
+#include <media/tuner.h>
+#include <media/tveeprom.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+
+#include <media/cx25840.h>
+#include "dvb-usb-ids.h"
+#include "xc5000.h"
+#include "tda18271.h"
+
+#include "cx231xx.h"
+
+static int tuner = -1;
+module_param(tuner, int, 0444);
+MODULE_PARM_DESC(tuner, "tuner type");
+
+static int transfer_mode = 1;
+module_param(transfer_mode, int, 0444);
+MODULE_PARM_DESC(transfer_mode, "transfer mode (1-ISO or 0-BULK)");
+
+static unsigned int disable_ir;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
+
+/* Bitmask marking allocated devices from 0 to CX231XX_MAXBOARDS */
+static unsigned long cx231xx_devused;
+
+/*
+ *  Reset sequences for analog/digital modes
+ */
+
+static struct cx231xx_reg_seq RDE250_XCV_TUNER[] = {
+	{0x03, 0x01, 10},
+	{0x03, 0x00, 30},
+	{0x03, 0x01, 10},
+	{-1, -1, -1},
+};
+
+/*
+ *  Board definitions
+ */
+struct cx231xx_board cx231xx_boards[] = {
+	[CX231XX_BOARD_UNKNOWN] = {
+		.name = "Unknown CX231xx video grabber",
+		.tuner_type = TUNER_ABSENT,
+		.input = {{
+				.type = CX231XX_VMUX_TELEVISION,
+				.vmux = CX231XX_VIN_3_1,
+				.amux = CX231XX_AMUX_VIDEO,
+				.gpio = NULL,
+			}, {
+				.type = CX231XX_VMUX_COMPOSITE1,
+				.vmux = CX231XX_VIN_2_1,
+				.amux = CX231XX_AMUX_LINE_IN,
+				.gpio = NULL,
+			}, {
+				.type = CX231XX_VMUX_SVIDEO,
+				.vmux = CX231XX_VIN_1_1 |
+					(CX231XX_VIN_1_2 << 8) |
+					CX25840_SVIDEO_ON,
+				.amux = CX231XX_AMUX_LINE_IN,
+				.gpio = NULL,
+			}
+		},
+	},
+	[CX231XX_BOARD_CNXT_CARRAERA] = {
+		.name = "Conexant Hybrid TV - CARRAERA",
+		.tuner_type = TUNER_XC5000,
+		.tuner_addr = 0x61,
+		.tuner_gpio = RDE250_XCV_TUNER,
+		.tuner_sif_gpio = 0x05,
+		.tuner_scl_gpio = 0x1a,
+		.tuner_sda_gpio = 0x1b,
+		.decoder = CX231XX_AVDECODER,
+		.output_mode = OUT_MODE_VIP11,
+		.demod_xfer_mode = 0,
+		.ctl_pin_status_mask = 0xFFFFFFC4,
+		.agc_analog_digital_select_gpio = 0x0c,
+		.gpio_pin_status_mask = 0x4001000,
+		.tuner_i2c_master = 1,
+		.demod_i2c_master = 2,
+		.has_dvb = 1,
+		.demod_addr = 0x02,
+		.norm = V4L2_STD_PAL,
+
+		.input = {{
+				.type = CX231XX_VMUX_TELEVISION,
+				.vmux = CX231XX_VIN_3_1,
+				.amux = CX231XX_AMUX_VIDEO,
+				.gpio = NULL,
+			}, {
+				.type = CX231XX_VMUX_COMPOSITE1,
+				.vmux = CX231XX_VIN_2_1,
+				.amux = CX231XX_AMUX_LINE_IN,
+				.gpio = NULL,
+			}, {
+				.type = CX231XX_VMUX_SVIDEO,
+				.vmux = CX231XX_VIN_1_1 |
+					(CX231XX_VIN_1_2 << 8) |
+					CX25840_SVIDEO_ON,
+				.amux = CX231XX_AMUX_LINE_IN,
+				.gpio = NULL,
+			}
+		},
+	},
+	[CX231XX_BOARD_CNXT_SHELBY] = {
+		.name = "Conexant Hybrid TV - SHELBY",
+		.tuner_type = TUNER_XC5000,
+		.tuner_addr = 0x61,
+		.tuner_gpio = RDE250_XCV_TUNER,
+		.tuner_sif_gpio = 0x05,
+		.tuner_scl_gpio = 0x1a,
+		.tuner_sda_gpio = 0x1b,
+		.decoder = CX231XX_AVDECODER,
+		.output_mode = OUT_MODE_VIP11,
+		.demod_xfer_mode = 0,
+		.ctl_pin_status_mask = 0xFFFFFFC4,
+		.agc_analog_digital_select_gpio = 0x0c,
+		.gpio_pin_status_mask = 0x4001000,
+		.tuner_i2c_master = 1,
+		.demod_i2c_master = 2,
+		.has_dvb = 1,
+		.demod_addr = 0x32,
+		.norm = V4L2_STD_NTSC,
+
+		.input = {{
+				.type = CX231XX_VMUX_TELEVISION,
+				.vmux = CX231XX_VIN_3_1,
+				.amux = CX231XX_AMUX_VIDEO,
+				.gpio = NULL,
+			}, {
+				.type = CX231XX_VMUX_COMPOSITE1,
+				.vmux = CX231XX_VIN_2_1,
+				.amux = CX231XX_AMUX_LINE_IN,
+				.gpio = NULL,
+			}, {
+				.type = CX231XX_VMUX_SVIDEO,
+				.vmux = CX231XX_VIN_1_1 |
+					(CX231XX_VIN_1_2 << 8) |
+					CX25840_SVIDEO_ON,
+				.amux = CX231XX_AMUX_LINE_IN,
+				.gpio = NULL,
+			}
+		},
+	},
+	[CX231XX_BOARD_CNXT_RDE_253S] = {
+		.name = "Conexant Hybrid TV - RDE253S",
+		.tuner_type = TUNER_NXP_TDA18271,
+		.tuner_addr = 0x60,
+		.tuner_gpio = RDE250_XCV_TUNER,
+		.tuner_sif_gpio = 0x05,
+		.tuner_scl_gpio = 0x1a,
+		.tuner_sda_gpio = 0x1b,
+		.decoder = CX231XX_AVDECODER,
+		.output_mode = OUT_MODE_VIP11,
+		.demod_xfer_mode = 0,
+		.ctl_pin_status_mask = 0xFFFFFFC4,
+		.agc_analog_digital_select_gpio = 0x1c,
+		.gpio_pin_status_mask = 0x4001000,
+		.tuner_i2c_master = 1,
+		.demod_i2c_master = 2,
+		.has_dvb = 1,
+		.demod_addr = 0x02,
+		.norm = V4L2_STD_PAL,
+
+		.input = {{
+				.type = CX231XX_VMUX_TELEVISION,
+				.vmux = CX231XX_VIN_3_1,
+				.amux = CX231XX_AMUX_VIDEO,
+				.gpio = NULL,
+			}, {
+				.type = CX231XX_VMUX_COMPOSITE1,
+				.vmux = CX231XX_VIN_2_1,
+				.amux = CX231XX_AMUX_LINE_IN,
+				.gpio = NULL,
+			}, {
+				.type = CX231XX_VMUX_SVIDEO,
+				.vmux = CX231XX_VIN_1_1 |
+					(CX231XX_VIN_1_2 << 8) |
+					CX25840_SVIDEO_ON,
+				.amux = CX231XX_AMUX_LINE_IN,
+				.gpio = NULL,
+			}
+		},
+	},
+
+	[CX231XX_BOARD_CNXT_RDU_253S] = {
+		.name = "Conexant Hybrid TV - RDU253S",
+		.tuner_type = TUNER_NXP_TDA18271,
+		.tuner_addr = 0x60,
+		.tuner_gpio = RDE250_XCV_TUNER,
+		.tuner_sif_gpio = 0x05,
+		.tuner_scl_gpio = 0x1a,
+		.tuner_sda_gpio = 0x1b,
+		.decoder = CX231XX_AVDECODER,
+		.output_mode = OUT_MODE_VIP11,
+		.demod_xfer_mode = 0,
+		.ctl_pin_status_mask = 0xFFFFFFC4,
+		.agc_analog_digital_select_gpio = 0x1c,
+		.gpio_pin_status_mask = 0x4001000,
+		.tuner_i2c_master = 1,
+		.demod_i2c_master = 2,
+		.has_dvb = 1,
+		.demod_addr = 0x02,
+		.norm = V4L2_STD_PAL,
+
+		.input = {{
+				.type = CX231XX_VMUX_TELEVISION,
+				.vmux = CX231XX_VIN_3_1,
+				.amux = CX231XX_AMUX_VIDEO,
+				.gpio = NULL,
+			}, {
+				.type = CX231XX_VMUX_COMPOSITE1,
+				.vmux = CX231XX_VIN_2_1,
+				.amux = CX231XX_AMUX_LINE_IN,
+				.gpio = NULL,
+			}, {
+				.type = CX231XX_VMUX_SVIDEO,
+				.vmux = CX231XX_VIN_1_1 |
+					(CX231XX_VIN_1_2 << 8) |
+					CX25840_SVIDEO_ON,
+				.amux = CX231XX_AMUX_LINE_IN,
+				.gpio = NULL,
+			}
+		},
+	},
+	[CX231XX_BOARD_CNXT_VIDEO_GRABBER] = {
+		.name = "Conexant VIDEO GRABBER",
+		.tuner_type = TUNER_ABSENT,
+		.decoder = CX231XX_AVDECODER,
+		.output_mode = OUT_MODE_VIP11,
+		.ctl_pin_status_mask = 0xFFFFFFC4,
+		.agc_analog_digital_select_gpio = 0x1c,
+		.gpio_pin_status_mask = 0x4001000,
+		.norm = V4L2_STD_PAL,
+		.no_alt_vanc = 1,
+		.external_av = 1,
+		.has_417 = 1,
+
+		.input = {{
+				.type = CX231XX_VMUX_COMPOSITE1,
+				.vmux = CX231XX_VIN_2_1,
+				.amux = CX231XX_AMUX_LINE_IN,
+				.gpio = NULL,
+			}, {
+				.type = CX231XX_VMUX_SVIDEO,
+				.vmux = CX231XX_VIN_1_1 |
+					(CX231XX_VIN_1_2 << 8) |
+					CX25840_SVIDEO_ON,
+				.amux = CX231XX_AMUX_LINE_IN,
+				.gpio = NULL,
+			}
+		},
+	},
+	[CX231XX_BOARD_CNXT_RDE_250] = {
+		.name = "Conexant Hybrid TV - rde 250",
+		.tuner_type = TUNER_XC5000,
+		.tuner_addr = 0x61,
+		.tuner_gpio = RDE250_XCV_TUNER,
+		.tuner_sif_gpio = 0x05,
+		.tuner_scl_gpio = 0x1a,
+		.tuner_sda_gpio = 0x1b,
+		.decoder = CX231XX_AVDECODER,
+		.output_mode = OUT_MODE_VIP11,
+		.demod_xfer_mode = 0,
+		.ctl_pin_status_mask = 0xFFFFFFC4,
+		.agc_analog_digital_select_gpio = 0x0c,
+		.gpio_pin_status_mask = 0x4001000,
+		.tuner_i2c_master = 1,
+		.demod_i2c_master = 2,
+		.has_dvb = 1,
+		.demod_addr = 0x02,
+		.norm = V4L2_STD_PAL,
+
+		.input = {{
+				.type = CX231XX_VMUX_TELEVISION,
+				.vmux = CX231XX_VIN_2_1,
+				.amux = CX231XX_AMUX_VIDEO,
+				.gpio = NULL,
+			}
+		},
+	},
+	[CX231XX_BOARD_CNXT_RDU_250] = {
+		.name = "Conexant Hybrid TV - RDU 250",
+		.tuner_type = TUNER_XC5000,
+		.tuner_addr = 0x61,
+		.tuner_gpio = RDE250_XCV_TUNER,
+		.tuner_sif_gpio = 0x05,
+		.tuner_scl_gpio = 0x1a,
+		.tuner_sda_gpio = 0x1b,
+		.decoder = CX231XX_AVDECODER,
+		.output_mode = OUT_MODE_VIP11,
+		.demod_xfer_mode = 0,
+		.ctl_pin_status_mask = 0xFFFFFFC4,
+		.agc_analog_digital_select_gpio = 0x0c,
+		.gpio_pin_status_mask = 0x4001000,
+		.tuner_i2c_master = 1,
+		.demod_i2c_master = 2,
+		.has_dvb = 1,
+		.demod_addr = 0x32,
+		.norm = V4L2_STD_NTSC,
+
+		.input = {{
+				.type = CX231XX_VMUX_TELEVISION,
+				.vmux = CX231XX_VIN_2_1,
+				.amux = CX231XX_AMUX_VIDEO,
+				.gpio = NULL,
+			}
+		},
+	},
+	[CX231XX_BOARD_HAUPPAUGE_EXETER] = {
+		.name = "Hauppauge EXETER",
+		.tuner_type = TUNER_NXP_TDA18271,
+		.tuner_addr = 0x60,
+		.tuner_gpio = RDE250_XCV_TUNER,
+		.tuner_sif_gpio = 0x05,
+		.tuner_scl_gpio = 0x1a,
+		.tuner_sda_gpio = 0x1b,
+		.decoder = CX231XX_AVDECODER,
+		.output_mode = OUT_MODE_VIP11,
+		.demod_xfer_mode = 0,
+		.ctl_pin_status_mask = 0xFFFFFFC4,
+		.agc_analog_digital_select_gpio = 0x0c,
+		.gpio_pin_status_mask = 0x4001000,
+		.tuner_i2c_master = 1,
+		.demod_i2c_master = 2,
+		.has_dvb = 1,
+		.demod_addr = 0x0e,
+		.norm = V4L2_STD_NTSC,
+
+		.input = {{
+			.type = CX231XX_VMUX_TELEVISION,
+			.vmux = CX231XX_VIN_3_1,
+			.amux = CX231XX_AMUX_VIDEO,
+			.gpio = NULL,
+		}, {
+			.type = CX231XX_VMUX_COMPOSITE1,
+			.vmux = CX231XX_VIN_2_1,
+			.amux = CX231XX_AMUX_LINE_IN,
+			.gpio = NULL,
+		}, {
+			.type = CX231XX_VMUX_SVIDEO,
+			.vmux = CX231XX_VIN_1_1 |
+				(CX231XX_VIN_1_2 << 8) |
+				CX25840_SVIDEO_ON,
+			.amux = CX231XX_AMUX_LINE_IN,
+			.gpio = NULL,
+		} },
+	},
+	[CX231XX_BOARD_HAUPPAUGE_USBLIVE2] = {
+		.name = "Hauppauge USB Live 2",
+		.tuner_type = TUNER_ABSENT,
+		.decoder = CX231XX_AVDECODER,
+		.output_mode = OUT_MODE_VIP11,
+		.demod_xfer_mode = 0,
+		.ctl_pin_status_mask = 0xFFFFFFC4,
+		.agc_analog_digital_select_gpio = 0x0c,
+		.gpio_pin_status_mask = 0x4001000,
+		.norm = V4L2_STD_NTSC,
+		.no_alt_vanc = 1,
+		.external_av = 1,
+		.dont_use_port_3 = 1,
+		.input = {{
+			.type = CX231XX_VMUX_COMPOSITE1,
+			.vmux = CX231XX_VIN_2_1,
+			.amux = CX231XX_AMUX_LINE_IN,
+			.gpio = NULL,
+		}, {
+			.type = CX231XX_VMUX_SVIDEO,
+			.vmux = CX231XX_VIN_1_1 |
+				(CX231XX_VIN_1_2 << 8) |
+				CX25840_SVIDEO_ON,
+			.amux = CX231XX_AMUX_LINE_IN,
+			.gpio = NULL,
+		} },
+	},
+	[CX231XX_BOARD_KWORLD_UB430_USB_HYBRID] = {
+		.name = "Kworld UB430 USB Hybrid",
+		.tuner_type = TUNER_NXP_TDA18271,
+		.tuner_addr = 0x60,
+		.decoder = CX231XX_AVDECODER,
+		.output_mode = OUT_MODE_VIP11,
+		.demod_xfer_mode = 0,
+		.ctl_pin_status_mask = 0xFFFFFFC4,
+		.agc_analog_digital_select_gpio = 0x11,	/* According with PV cxPolaris.inf file */
+		.tuner_sif_gpio = -1,
+		.tuner_scl_gpio = -1,
+		.tuner_sda_gpio = -1,
+		.gpio_pin_status_mask = 0x4001000,
+		.tuner_i2c_master = 2,
+		.demod_i2c_master = 1,
+		.ir_i2c_master = 2,
+		.has_dvb = 1,
+		.demod_addr = 0x10,
+		.norm = V4L2_STD_PAL_M,
+		.input = {{
+			.type = CX231XX_VMUX_TELEVISION,
+			.vmux = CX231XX_VIN_3_1,
+			.amux = CX231XX_AMUX_VIDEO,
+			.gpio = NULL,
+		}, {
+			.type = CX231XX_VMUX_COMPOSITE1,
+			.vmux = CX231XX_VIN_2_1,
+			.amux = CX231XX_AMUX_LINE_IN,
+			.gpio = NULL,
+		}, {
+			.type = CX231XX_VMUX_SVIDEO,
+			.vmux = CX231XX_VIN_1_1 |
+				(CX231XX_VIN_1_2 << 8) |
+				CX25840_SVIDEO_ON,
+			.amux = CX231XX_AMUX_LINE_IN,
+			.gpio = NULL,
+		} },
+	},
+	[CX231XX_BOARD_PV_PLAYTV_USB_HYBRID] = {
+		.name = "Pixelview PlayTV USB Hybrid",
+		.tuner_type = TUNER_NXP_TDA18271,
+		.tuner_addr = 0x60,
+		.decoder = CX231XX_AVDECODER,
+		.output_mode = OUT_MODE_VIP11,
+		.demod_xfer_mode = 0,
+		.ctl_pin_status_mask = 0xFFFFFFC4,
+		.agc_analog_digital_select_gpio = 0x00,	/* According with PV cxPolaris.inf file */
+		.tuner_sif_gpio = -1,
+		.tuner_scl_gpio = -1,
+		.tuner_sda_gpio = -1,
+		.gpio_pin_status_mask = 0x4001000,
+		.tuner_i2c_master = 2,
+		.demod_i2c_master = 1,
+		.ir_i2c_master = 2,
+		.rc_map_name = RC_MAP_PIXELVIEW_002T,
+		.has_dvb = 1,
+		.demod_addr = 0x10,
+		.norm = V4L2_STD_PAL_M,
+		.input = {{
+			.type = CX231XX_VMUX_TELEVISION,
+			.vmux = CX231XX_VIN_3_1,
+			.amux = CX231XX_AMUX_VIDEO,
+			.gpio = NULL,
+		}, {
+			.type = CX231XX_VMUX_COMPOSITE1,
+			.vmux = CX231XX_VIN_2_1,
+			.amux = CX231XX_AMUX_LINE_IN,
+			.gpio = NULL,
+		}, {
+			.type = CX231XX_VMUX_SVIDEO,
+			.vmux = CX231XX_VIN_1_1 |
+				(CX231XX_VIN_1_2 << 8) |
+				CX25840_SVIDEO_ON,
+			.amux = CX231XX_AMUX_LINE_IN,
+			.gpio = NULL,
+		} },
+	},
+	[CX231XX_BOARD_PV_XCAPTURE_USB] = {
+		.name = "Pixelview Xcapture USB",
+		.tuner_type = TUNER_ABSENT,
+		.decoder = CX231XX_AVDECODER,
+		.output_mode = OUT_MODE_VIP11,
+		.demod_xfer_mode = 0,
+		.ctl_pin_status_mask = 0xFFFFFFC4,
+		.agc_analog_digital_select_gpio = 0x0c,
+		.gpio_pin_status_mask = 0x4001000,
+		.norm = V4L2_STD_NTSC,
+		.no_alt_vanc = 1,
+		.external_av = 1,
+		.dont_use_port_3 = 1,
+
+		.input = {{
+				.type = CX231XX_VMUX_COMPOSITE1,
+				.vmux = CX231XX_VIN_2_1,
+				.amux = CX231XX_AMUX_LINE_IN,
+				.gpio = NULL,
+			}, {
+				.type = CX231XX_VMUX_SVIDEO,
+				.vmux = CX231XX_VIN_1_1 |
+					(CX231XX_VIN_1_2 << 8) |
+					CX25840_SVIDEO_ON,
+				.amux = CX231XX_AMUX_LINE_IN,
+				.gpio = NULL,
+			}
+		},
+	},
+
+	[CX231XX_BOARD_ICONBIT_U100] = {
+		.name = "Iconbit Analog Stick U100 FM",
+		.tuner_type = TUNER_ABSENT,
+		.decoder = CX231XX_AVDECODER,
+		.output_mode = OUT_MODE_VIP11,
+		.demod_xfer_mode = 0,
+		.ctl_pin_status_mask = 0xFFFFFFC4,
+		.agc_analog_digital_select_gpio = 0x1C,
+		.gpio_pin_status_mask = 0x4001000,
+
+		.input = {{
+			.type = CX231XX_VMUX_COMPOSITE1,
+			.vmux = CX231XX_VIN_2_1,
+			.amux = CX231XX_AMUX_LINE_IN,
+			.gpio = NULL,
+		}, {
+			.type = CX231XX_VMUX_SVIDEO,
+			.vmux = CX231XX_VIN_1_1 |
+				(CX231XX_VIN_1_2 << 8) |
+				CX25840_SVIDEO_ON,
+			.amux = CX231XX_AMUX_LINE_IN,
+			.gpio = NULL,
+		} },
+	},
+	[CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL] = {
+		.name = "Hauppauge WinTV USB2 FM (PAL)",
+		.tuner_type = TUNER_NXP_TDA18271,
+		.tuner_addr = 0x60,
+		.tuner_gpio = RDE250_XCV_TUNER,
+		.tuner_sif_gpio = 0x05,
+		.tuner_scl_gpio = 0x1a,
+		.tuner_sda_gpio = 0x1b,
+		.decoder = CX231XX_AVDECODER,
+		.output_mode = OUT_MODE_VIP11,
+		.ctl_pin_status_mask = 0xFFFFFFC4,
+		.agc_analog_digital_select_gpio = 0x0c,
+		.gpio_pin_status_mask = 0x4001000,
+		.tuner_i2c_master = 1,
+		.norm = V4L2_STD_PAL,
+
+		.input = {{
+			.type = CX231XX_VMUX_TELEVISION,
+			.vmux = CX231XX_VIN_3_1,
+			.amux = CX231XX_AMUX_VIDEO,
+			.gpio = NULL,
+		}, {
+			.type = CX231XX_VMUX_COMPOSITE1,
+			.vmux = CX231XX_VIN_2_1,
+			.amux = CX231XX_AMUX_LINE_IN,
+			.gpio = NULL,
+		}, {
+			.type = CX231XX_VMUX_SVIDEO,
+			.vmux = CX231XX_VIN_1_1 |
+				(CX231XX_VIN_1_2 << 8) |
+				CX25840_SVIDEO_ON,
+			.amux = CX231XX_AMUX_LINE_IN,
+			.gpio = NULL,
+		} },
+	},
+	[CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC] = {
+		.name = "Hauppauge WinTV USB2 FM (NTSC)",
+		.tuner_type = TUNER_NXP_TDA18271,
+		.tuner_addr = 0x60,
+		.tuner_gpio = RDE250_XCV_TUNER,
+		.tuner_sif_gpio = 0x05,
+		.tuner_scl_gpio = 0x1a,
+		.tuner_sda_gpio = 0x1b,
+		.decoder = CX231XX_AVDECODER,
+		.output_mode = OUT_MODE_VIP11,
+		.ctl_pin_status_mask = 0xFFFFFFC4,
+		.agc_analog_digital_select_gpio = 0x0c,
+		.gpio_pin_status_mask = 0x4001000,
+		.tuner_i2c_master = 1,
+		.norm = V4L2_STD_NTSC,
+
+		.input = {{
+			.type = CX231XX_VMUX_TELEVISION,
+			.vmux = CX231XX_VIN_3_1,
+			.amux = CX231XX_AMUX_VIDEO,
+			.gpio = NULL,
+		}, {
+			.type = CX231XX_VMUX_COMPOSITE1,
+			.vmux = CX231XX_VIN_2_1,
+			.amux = CX231XX_AMUX_LINE_IN,
+			.gpio = NULL,
+		}, {
+			.type = CX231XX_VMUX_SVIDEO,
+			.vmux = CX231XX_VIN_1_1 |
+				(CX231XX_VIN_1_2 << 8) |
+				CX25840_SVIDEO_ON,
+			.amux = CX231XX_AMUX_LINE_IN,
+			.gpio = NULL,
+		} },
+	},
+};
+const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
+
+/* table of devices that work with this driver */
+struct usb_device_id cx231xx_id_table[] = {
+	{USB_DEVICE(0x0572, 0x5A3C),
+	 .driver_info = CX231XX_BOARD_UNKNOWN},
+	{USB_DEVICE(0x0572, 0x58A2),
+	 .driver_info = CX231XX_BOARD_CNXT_CARRAERA},
+	{USB_DEVICE(0x0572, 0x58A1),
+	 .driver_info = CX231XX_BOARD_CNXT_SHELBY},
+	{USB_DEVICE(0x0572, 0x58A4),
+	 .driver_info = CX231XX_BOARD_CNXT_RDE_253S},
+	{USB_DEVICE(0x0572, 0x58A5),
+	 .driver_info = CX231XX_BOARD_CNXT_RDU_253S},
+	{USB_DEVICE(0x0572, 0x58A6),
+	 .driver_info = CX231XX_BOARD_CNXT_VIDEO_GRABBER},
+	{USB_DEVICE(0x0572, 0x589E),
+	 .driver_info = CX231XX_BOARD_CNXT_RDE_250},
+	{USB_DEVICE(0x0572, 0x58A0),
+	 .driver_info = CX231XX_BOARD_CNXT_RDU_250},
+	{USB_DEVICE(0x2040, 0xb110),
+	 .driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL},
+	{USB_DEVICE(0x2040, 0xb111),
+	 .driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC},
+	{USB_DEVICE(0x2040, 0xb120),
+	 .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
+	{USB_DEVICE(0x2040, 0xb140),
+	 .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
+	{USB_DEVICE(0x2040, 0xc200),
+	 .driver_info = CX231XX_BOARD_HAUPPAUGE_USBLIVE2},
+	{USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x4000, 0x4001),
+	 .driver_info = CX231XX_BOARD_PV_PLAYTV_USB_HYBRID},
+	{USB_DEVICE(USB_VID_PIXELVIEW, 0x5014),
+	 .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB},
+	{USB_DEVICE(0x1b80, 0xe424),
+	 .driver_info = CX231XX_BOARD_KWORLD_UB430_USB_HYBRID},
+	{USB_DEVICE(0x1f4d, 0x0237),
+	 .driver_info = CX231XX_BOARD_ICONBIT_U100},
+	{},
+};
+
+MODULE_DEVICE_TABLE(usb, cx231xx_id_table);
+
+/* cx231xx_tuner_callback
+ * will be used to reset XC5000 tuner using GPIO pin
+ */
+
+int cx231xx_tuner_callback(void *ptr, int component, int command, int arg)
+{
+	int rc = 0;
+	struct cx231xx *dev = ptr;
+
+	if (dev->tuner_type == TUNER_XC5000) {
+		if (command == XC5000_TUNER_RESET) {
+			cx231xx_info
+				("Tuner CB: RESET: cmd %d : tuner type %d \n",
+				 command, dev->tuner_type);
+			cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit,
+					       1);
+			msleep(10);
+			cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit,
+					       0);
+			msleep(330);
+			cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit,
+					       1);
+			msleep(10);
+		}
+	} else if (dev->tuner_type == TUNER_NXP_TDA18271) {
+		switch (command) {
+		case TDA18271_CALLBACK_CMD_AGC_ENABLE:
+			if (dev->model == CX231XX_BOARD_PV_PLAYTV_USB_HYBRID)
+				rc = cx231xx_set_agc_analog_digital_mux_select(dev, arg);
+			break;
+		default:
+			rc = -EINVAL;
+			break;
+		}
+	}
+	return rc;
+}
+EXPORT_SYMBOL_GPL(cx231xx_tuner_callback);
+
+void cx231xx_reset_out(struct cx231xx *dev)
+{
+	cx231xx_set_gpio_value(dev, CX23417_RESET, 1);
+	msleep(200);
+	cx231xx_set_gpio_value(dev, CX23417_RESET, 0);
+	msleep(200);
+	cx231xx_set_gpio_value(dev, CX23417_RESET, 1);
+}
+void cx231xx_enable_OSC(struct cx231xx *dev)
+{
+	cx231xx_set_gpio_value(dev, CX23417_OSC_EN, 1);
+}
+void cx231xx_sleep_s5h1432(struct cx231xx *dev)
+{
+	cx231xx_set_gpio_value(dev, SLEEP_S5H1432, 0);
+}
+
+static inline void cx231xx_set_model(struct cx231xx *dev)
+{
+	memcpy(&dev->board, &cx231xx_boards[dev->model], sizeof(dev->board));
+}
+
+/* Since cx231xx_pre_card_setup() requires a proper dev->model,
+ * this won't work for boards with generic PCI IDs
+ */
+void cx231xx_pre_card_setup(struct cx231xx *dev)
+{
+
+	cx231xx_set_model(dev);
+
+	cx231xx_info("Identified as %s (card=%d)\n",
+		     dev->board.name, dev->model);
+
+	/* set the direction for GPIO pins */
+	if (dev->board.tuner_gpio) {
+		cx231xx_set_gpio_direction(dev, dev->board.tuner_gpio->bit, 1);
+		cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit, 1);
+	}
+	if (dev->board.tuner_sif_gpio >= 0)
+		cx231xx_set_gpio_direction(dev, dev->board.tuner_sif_gpio, 1);
+
+	/* request some modules if any required */
+
+	/* set the mode to Analog mode initially */
+	cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
+
+	/* Unlock device */
+	/* cx231xx_set_mode(dev, CX231XX_SUSPEND); */
+
+}
+
+static void cx231xx_config_tuner(struct cx231xx *dev)
+{
+	struct tuner_setup tun_setup;
+	struct v4l2_frequency f;
+
+	if (dev->tuner_type == TUNER_ABSENT)
+		return;
+
+	tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+	tun_setup.type = dev->tuner_type;
+	tun_setup.addr = dev->tuner_addr;
+	tun_setup.tuner_callback = cx231xx_tuner_callback;
+
+	tuner_call(dev, tuner, s_type_addr, &tun_setup);
+
+#if 0
+	if (tun_setup.type == TUNER_XC5000) {
+		static struct xc2028_ctrl ctrl = {
+			.fname = XC5000_DEFAULT_FIRMWARE,
+			.max_len = 64,
+			.demod = 0;
+		};
+		struct v4l2_priv_tun_config cfg = {
+			.tuner = dev->tuner_type,
+			.priv = &ctrl,
+		};
+		tuner_call(dev, tuner, s_config, &cfg);
+	}
+#endif
+	/* configure tuner */
+	f.tuner = 0;
+	f.type = V4L2_TUNER_ANALOG_TV;
+	f.frequency = 9076;	/* just a magic number */
+	dev->ctl_freq = f.frequency;
+	call_all(dev, tuner, s_frequency, &f);
+
+}
+
+void cx231xx_card_setup(struct cx231xx *dev)
+{
+
+	cx231xx_set_model(dev);
+
+	dev->tuner_type = cx231xx_boards[dev->model].tuner_type;
+	if (cx231xx_boards[dev->model].tuner_addr)
+		dev->tuner_addr = cx231xx_boards[dev->model].tuner_addr;
+
+	/* request some modules */
+	if (dev->board.decoder == CX231XX_AVDECODER) {
+		dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+					&dev->i2c_bus[0].i2c_adap,
+					"cx25840", 0x88 >> 1, NULL);
+		if (dev->sd_cx25840 == NULL)
+			cx231xx_info("cx25840 subdev registration failure\n");
+		cx25840_call(dev, core, load_fw);
+
+	}
+
+	/* Initialize the tuner */
+	if (dev->board.tuner_type != TUNER_ABSENT) {
+		dev->sd_tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+						    &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+						    "tuner",
+						    dev->tuner_addr, NULL);
+		if (dev->sd_tuner == NULL)
+			cx231xx_info("tuner subdev registration failure\n");
+		else
+			cx231xx_config_tuner(dev);
+	}
+}
+
+/*
+ * cx231xx_config()
+ * inits registers with sane defaults
+ */
+int cx231xx_config(struct cx231xx *dev)
+{
+	/* TBD need to add cx231xx specific code */
+	dev->mute = 1;		/* maybe not the right place... */
+	dev->volume = 0x1f;
+
+	return 0;
+}
+
+/*
+ * cx231xx_config_i2c()
+ * configure i2c attached devices
+ */
+void cx231xx_config_i2c(struct cx231xx *dev)
+{
+	/* u32 input = INPUT(dev->video_input)->vmux; */
+
+	call_all(dev, video, s_stream, 1);
+}
+
+/*
+ * cx231xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+void cx231xx_release_resources(struct cx231xx *dev)
+{
+	cx231xx_release_analog_resources(dev);
+
+	cx231xx_remove_from_devlist(dev);
+
+	cx231xx_ir_exit(dev);
+
+	/* Release I2C buses */
+	cx231xx_dev_uninit(dev);
+
+	/* delete v4l2 device */
+	v4l2_device_unregister(&dev->v4l2_dev);
+
+	usb_put_dev(dev->udev);
+
+	/* Mark device as unused */
+	clear_bit(dev->devno, &cx231xx_devused);
+
+	kfree(dev->video_mode.alt_max_pkt_size);
+	kfree(dev->vbi_mode.alt_max_pkt_size);
+	kfree(dev->sliced_cc_mode.alt_max_pkt_size);
+	kfree(dev->ts1_mode.alt_max_pkt_size);
+	kfree(dev);
+}
+
+/*
+ * cx231xx_init_dev()
+ * allocates and inits the device structs, registers i2c bus and v4l device
+ */
+static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
+			    int minor)
+{
+	int retval = -ENOMEM;
+	int errCode;
+	unsigned int maxh, maxw;
+
+	dev->udev = udev;
+	mutex_init(&dev->lock);
+	mutex_init(&dev->ctrl_urb_lock);
+	mutex_init(&dev->gpio_i2c_lock);
+	mutex_init(&dev->i2c_lock);
+
+	spin_lock_init(&dev->video_mode.slock);
+	spin_lock_init(&dev->vbi_mode.slock);
+	spin_lock_init(&dev->sliced_cc_mode.slock);
+
+	init_waitqueue_head(&dev->open);
+	init_waitqueue_head(&dev->wait_frame);
+	init_waitqueue_head(&dev->wait_stream);
+
+	dev->cx231xx_read_ctrl_reg = cx231xx_read_ctrl_reg;
+	dev->cx231xx_write_ctrl_reg = cx231xx_write_ctrl_reg;
+	dev->cx231xx_send_usb_command = cx231xx_send_usb_command;
+	dev->cx231xx_gpio_i2c_read = cx231xx_gpio_i2c_read;
+	dev->cx231xx_gpio_i2c_write = cx231xx_gpio_i2c_write;
+
+	/* Query cx231xx to find what pcb config it is related to */
+	initialize_cx231xx(dev);
+
+	/*To workaround error number=-71 on EP0 for VideoGrabber,
+		 need set alt here.*/
+	if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER ||
+	    dev->model == CX231XX_BOARD_HAUPPAUGE_USBLIVE2) {
+		cx231xx_set_alt_setting(dev, INDEX_VIDEO, 3);
+		cx231xx_set_alt_setting(dev, INDEX_VANC, 1);
+	}
+	/* Cx231xx pre card setup */
+	cx231xx_pre_card_setup(dev);
+
+	errCode = cx231xx_config(dev);
+	if (errCode) {
+		cx231xx_errdev("error configuring device\n");
+		return -ENOMEM;
+	}
+
+	/* set default norm */
+	dev->norm = dev->board.norm;
+
+	/* register i2c bus */
+	errCode = cx231xx_dev_init(dev);
+	if (errCode < 0) {
+		cx231xx_dev_uninit(dev);
+		cx231xx_errdev("%s: cx231xx_i2c_register - errCode [%d]!\n",
+			       __func__, errCode);
+		return errCode;
+	}
+
+	/* Do board specific init */
+	cx231xx_card_setup(dev);
+
+	/* configure the device */
+	cx231xx_config_i2c(dev);
+
+	maxw = norm_maxw(dev);
+	maxh = norm_maxh(dev);
+
+	/* set default image size */
+	dev->width = maxw;
+	dev->height = maxh;
+	dev->interlaced = 0;
+	dev->video_input = 0;
+
+	errCode = cx231xx_config(dev);
+	if (errCode < 0) {
+		cx231xx_errdev("%s: cx231xx_config - errCode [%d]!\n",
+			       __func__, errCode);
+		return errCode;
+	}
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&dev->video_mode.vidq.active);
+	INIT_LIST_HEAD(&dev->video_mode.vidq.queued);
+
+	/* init vbi dma queues */
+	INIT_LIST_HEAD(&dev->vbi_mode.vidq.active);
+	INIT_LIST_HEAD(&dev->vbi_mode.vidq.queued);
+
+	/* Reset other chips required if they are tied up with GPIO pins */
+	cx231xx_add_into_devlist(dev);
+
+	if (dev->board.has_417) {
+		printk(KERN_INFO "attach 417 %d\n", dev->model);
+		if (cx231xx_417_register(dev) < 0) {
+			printk(KERN_ERR
+				"%s() Failed to register 417 on VID_B\n",
+			       __func__);
+		}
+	}
+
+	retval = cx231xx_register_analog_devices(dev);
+	if (retval < 0) {
+		cx231xx_release_resources(dev);
+		return retval;
+	}
+
+	cx231xx_ir_init(dev);
+
+	cx231xx_init_extension(dev);
+
+	return 0;
+}
+
+#if defined(CONFIG_MODULES) && defined(MODULE)
+static void request_module_async(struct work_struct *work)
+{
+	struct cx231xx *dev = container_of(work,
+					   struct cx231xx, request_module_wk);
+
+	if (dev->has_alsa_audio)
+		request_module("cx231xx-alsa");
+
+	if (dev->board.has_dvb)
+		request_module("cx231xx-dvb");
+
+}
+
+static void request_modules(struct cx231xx *dev)
+{
+	INIT_WORK(&dev->request_module_wk, request_module_async);
+	schedule_work(&dev->request_module_wk);
+}
+
+static void flush_request_modules(struct cx231xx *dev)
+{
+	flush_work_sync(&dev->request_module_wk);
+}
+#else
+#define request_modules(dev)
+#define flush_request_modules(dev)
+#endif /* CONFIG_MODULES */
+
+/*
+ * cx231xx_usb_probe()
+ * checks for supported devices
+ */
+static int cx231xx_usb_probe(struct usb_interface *interface,
+			     const struct usb_device_id *id)
+{
+	struct usb_device *udev;
+	struct usb_interface *uif;
+	struct cx231xx *dev = NULL;
+	int retval = -ENODEV;
+	int nr = 0, ifnum;
+	int i, isoc_pipe = 0;
+	char *speed;
+	struct usb_interface_assoc_descriptor *assoc_desc;
+
+	udev = usb_get_dev(interface_to_usbdev(interface));
+	ifnum = interface->altsetting[0].desc.bInterfaceNumber;
+
+	/*
+	 * Interface number 0 - IR interface (handled by mceusb driver)
+	 * Interface number 1 - AV interface (handled by this driver)
+	 */
+	if (ifnum != 1)
+		return -ENODEV;
+
+	/* Check to see next free device and mark as used */
+	do {
+		nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS);
+		if (nr >= CX231XX_MAXBOARDS) {
+			/* No free device slots */
+			cx231xx_err(DRIVER_NAME ": Supports only %i devices.\n",
+					CX231XX_MAXBOARDS);
+			return -ENOMEM;
+		}
+	} while (test_and_set_bit(nr, &cx231xx_devused));
+
+	/* allocate memory for our device state and initialize it */
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL) {
+		cx231xx_err(DRIVER_NAME ": out of memory!\n");
+		clear_bit(nr, &cx231xx_devused);
+		return -ENOMEM;
+	}
+
+	snprintf(dev->name, 29, "cx231xx #%d", nr);
+	dev->devno = nr;
+	dev->model = id->driver_info;
+	dev->video_mode.alt = -1;
+
+	dev->interface_count++;
+	/* reset gpio dir and value */
+	dev->gpio_dir = 0;
+	dev->gpio_val = 0;
+	dev->xc_fw_load_done = 0;
+	dev->has_alsa_audio = 1;
+	dev->power_mode = -1;
+	atomic_set(&dev->devlist_count, 0);
+
+	/* 0 - vbi ; 1 -sliced cc mode */
+	dev->vbi_or_sliced_cc_mode = 0;
+
+	/* get maximum no.of IAD interfaces */
+	assoc_desc = udev->actconfig->intf_assoc[0];
+	dev->max_iad_interface_count = assoc_desc->bInterfaceCount;
+
+	/* init CIR module TBD */
+
+	/*mode_tv: digital=1 or analog=0*/
+	dev->mode_tv = 0;
+
+	dev->USE_ISO = transfer_mode;
+
+	switch (udev->speed) {
+	case USB_SPEED_LOW:
+		speed = "1.5";
+		break;
+	case USB_SPEED_UNKNOWN:
+	case USB_SPEED_FULL:
+		speed = "12";
+		break;
+	case USB_SPEED_HIGH:
+		speed = "480";
+		break;
+	default:
+		speed = "unknown";
+	}
+
+	cx231xx_info("New device %s %s @ %s Mbps "
+	     "(%04x:%04x) with %d interfaces\n",
+	     udev->manufacturer ? udev->manufacturer : "",
+	     udev->product ? udev->product : "",
+	     speed,
+	     le16_to_cpu(udev->descriptor.idVendor),
+	     le16_to_cpu(udev->descriptor.idProduct),
+	     dev->max_iad_interface_count);
+
+	/* increment interface count */
+	dev->interface_count++;
+
+	/* get device number */
+	nr = dev->devno;
+
+	assoc_desc = udev->actconfig->intf_assoc[0];
+	if (assoc_desc->bFirstInterface != ifnum) {
+		cx231xx_err(DRIVER_NAME ": Not found "
+			    "matching IAD interface\n");
+		clear_bit(dev->devno, &cx231xx_devused);
+		kfree(dev);
+		dev = NULL;
+		return -ENODEV;
+	}
+
+	cx231xx_info("registering interface %d\n", ifnum);
+
+	/* save our data pointer in this interface device */
+	usb_set_intfdata(interface, dev);
+
+	/*
+	 * AV device initialization - only done at the last interface
+	 */
+
+	/* Create v4l2 device */
+	retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
+	if (retval) {
+		cx231xx_errdev("v4l2_device_register failed\n");
+		clear_bit(dev->devno, &cx231xx_devused);
+		kfree(dev);
+		dev = NULL;
+		return -EIO;
+	}
+	/* allocate device struct */
+	retval = cx231xx_init_dev(dev, udev, nr);
+	if (retval) {
+		clear_bit(dev->devno, &cx231xx_devused);
+		v4l2_device_unregister(&dev->v4l2_dev);
+		kfree(dev);
+		dev = NULL;
+		usb_set_intfdata(interface, NULL);
+
+		return retval;
+	}
+
+	/* compute alternate max packet sizes for video */
+	uif = udev->actconfig->interface[dev->current_pcb_config.
+		       hs_config_info[0].interface_info.video_index + 1];
+
+	dev->video_mode.end_point_addr = le16_to_cpu(uif->altsetting[0].
+			endpoint[isoc_pipe].desc.bEndpointAddress);
+
+	dev->video_mode.num_alt = uif->num_altsetting;
+	cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
+		     dev->video_mode.end_point_addr,
+		     dev->video_mode.num_alt);
+	dev->video_mode.alt_max_pkt_size =
+		kmalloc(32 * dev->video_mode.num_alt, GFP_KERNEL);
+
+	if (dev->video_mode.alt_max_pkt_size == NULL) {
+		cx231xx_errdev("out of memory!\n");
+		clear_bit(dev->devno, &cx231xx_devused);
+		v4l2_device_unregister(&dev->v4l2_dev);
+		kfree(dev);
+		dev = NULL;
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < dev->video_mode.num_alt; i++) {
+		u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].
+				desc.wMaxPacketSize);
+		dev->video_mode.alt_max_pkt_size[i] =
+		    (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+		cx231xx_info("Alternate setting %i, max size= %i\n", i,
+			     dev->video_mode.alt_max_pkt_size[i]);
+	}
+
+	/* compute alternate max packet sizes for vbi */
+	uif = udev->actconfig->interface[dev->current_pcb_config.
+				       hs_config_info[0].interface_info.
+				       vanc_index + 1];
+
+	dev->vbi_mode.end_point_addr =
+	    le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc.
+			bEndpointAddress);
+
+	dev->vbi_mode.num_alt = uif->num_altsetting;
+	cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
+		     dev->vbi_mode.end_point_addr,
+		     dev->vbi_mode.num_alt);
+	dev->vbi_mode.alt_max_pkt_size =
+	    kmalloc(32 * dev->vbi_mode.num_alt, GFP_KERNEL);
+
+	if (dev->vbi_mode.alt_max_pkt_size == NULL) {
+		cx231xx_errdev("out of memory!\n");
+		clear_bit(dev->devno, &cx231xx_devused);
+		v4l2_device_unregister(&dev->v4l2_dev);
+		kfree(dev);
+		dev = NULL;
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < dev->vbi_mode.num_alt; i++) {
+		u16 tmp =
+		    le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].
+				desc.wMaxPacketSize);
+		dev->vbi_mode.alt_max_pkt_size[i] =
+		    (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+		cx231xx_info("Alternate setting %i, max size= %i\n", i,
+			     dev->vbi_mode.alt_max_pkt_size[i]);
+	}
+
+	/* compute alternate max packet sizes for sliced CC */
+	uif = udev->actconfig->interface[dev->current_pcb_config.
+				       hs_config_info[0].interface_info.
+				       hanc_index + 1];
+
+	dev->sliced_cc_mode.end_point_addr =
+	    le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc.
+			bEndpointAddress);
+
+	dev->sliced_cc_mode.num_alt = uif->num_altsetting;
+	cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
+		     dev->sliced_cc_mode.end_point_addr,
+		     dev->sliced_cc_mode.num_alt);
+	dev->sliced_cc_mode.alt_max_pkt_size =
+		kmalloc(32 * dev->sliced_cc_mode.num_alt, GFP_KERNEL);
+
+	if (dev->sliced_cc_mode.alt_max_pkt_size == NULL) {
+		cx231xx_errdev("out of memory!\n");
+		clear_bit(dev->devno, &cx231xx_devused);
+		v4l2_device_unregister(&dev->v4l2_dev);
+		kfree(dev);
+		dev = NULL;
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < dev->sliced_cc_mode.num_alt; i++) {
+		u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].
+				desc.wMaxPacketSize);
+		dev->sliced_cc_mode.alt_max_pkt_size[i] =
+		    (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+		cx231xx_info("Alternate setting %i, max size= %i\n", i,
+			     dev->sliced_cc_mode.alt_max_pkt_size[i]);
+	}
+
+	if (dev->current_pcb_config.ts1_source != 0xff) {
+		/* compute alternate max packet sizes for TS1 */
+		uif = udev->actconfig->interface[dev->current_pcb_config.
+					       hs_config_info[0].
+					       interface_info.
+					       ts1_index + 1];
+
+		dev->ts1_mode.end_point_addr =
+		    le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].
+				desc.bEndpointAddress);
+
+		dev->ts1_mode.num_alt = uif->num_altsetting;
+		cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
+			     dev->ts1_mode.end_point_addr,
+			     dev->ts1_mode.num_alt);
+		dev->ts1_mode.alt_max_pkt_size =
+			kmalloc(32 * dev->ts1_mode.num_alt, GFP_KERNEL);
+
+		if (dev->ts1_mode.alt_max_pkt_size == NULL) {
+			cx231xx_errdev("out of memory!\n");
+			clear_bit(dev->devno, &cx231xx_devused);
+			v4l2_device_unregister(&dev->v4l2_dev);
+			kfree(dev);
+			dev = NULL;
+			return -ENOMEM;
+		}
+
+		for (i = 0; i < dev->ts1_mode.num_alt; i++) {
+			u16 tmp = le16_to_cpu(uif->altsetting[i].
+						endpoint[isoc_pipe].desc.
+						wMaxPacketSize);
+			dev->ts1_mode.alt_max_pkt_size[i] =
+			    (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+			cx231xx_info("Alternate setting %i, max size= %i\n", i,
+				     dev->ts1_mode.alt_max_pkt_size[i]);
+		}
+	}
+
+	if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER) {
+		cx231xx_enable_OSC(dev);
+		cx231xx_reset_out(dev);
+		cx231xx_set_alt_setting(dev, INDEX_VIDEO, 3);
+	}
+
+	if (dev->model == CX231XX_BOARD_CNXT_RDE_253S)
+		cx231xx_sleep_s5h1432(dev);
+
+	/* load other modules required */
+	request_modules(dev);
+
+	return 0;
+}
+
+/*
+ * cx231xx_usb_disconnect()
+ * called when the device gets diconencted
+ * video device will be unregistered on v4l2_close in case it is still open
+ */
+static void cx231xx_usb_disconnect(struct usb_interface *interface)
+{
+	struct cx231xx *dev;
+
+	dev = usb_get_intfdata(interface);
+	usb_set_intfdata(interface, NULL);
+
+	if (!dev)
+		return;
+
+	if (!dev->udev)
+		return;
+
+	dev->state |= DEV_DISCONNECTED;
+
+	flush_request_modules(dev);
+
+	/* wait until all current v4l2 io is finished then deallocate
+	   resources */
+	mutex_lock(&dev->lock);
+
+	wake_up_interruptible_all(&dev->open);
+
+	if (dev->users) {
+		cx231xx_warn
+		    ("device %s is open! Deregistration and memory "
+		     "deallocation are deferred on close.\n",
+		     video_device_node_name(dev->vdev));
+
+		/* Even having users, it is safe to remove the RC i2c driver */
+		cx231xx_ir_exit(dev);
+
+		if (dev->USE_ISO)
+			cx231xx_uninit_isoc(dev);
+		else
+			cx231xx_uninit_bulk(dev);
+		wake_up_interruptible(&dev->wait_frame);
+		wake_up_interruptible(&dev->wait_stream);
+	} else {
+	}
+
+	cx231xx_close_extension(dev);
+
+	mutex_unlock(&dev->lock);
+
+	if (!dev->users)
+		cx231xx_release_resources(dev);
+}
+
+static struct usb_driver cx231xx_usb_driver = {
+	.name = "cx231xx",
+	.probe = cx231xx_usb_probe,
+	.disconnect = cx231xx_usb_disconnect,
+	.id_table = cx231xx_id_table,
+};
+
+module_usb_driver(cx231xx_usb_driver);
diff --git a/drivers/media/usb/cx231xx/cx231xx-conf-reg.h b/drivers/media/usb/cx231xx/cx231xx-conf-reg.h
new file mode 100644
index 0000000..25593f2
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-conf-reg.h
@@ -0,0 +1,495 @@
+/*
+   cx231xx_conf-reg.h - driver for Conexant Cx23100/101/102 USB
+			video capture devices
+
+   Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _POLARIS_REG_H_
+#define _POLARIS_REG_H_
+
+#define BOARD_CFG_STAT          0x0
+#define TS_MODE_REG             0x4
+#define TS1_CFG_REG             0x8
+#define TS1_LENGTH_REG          0xc
+#define TS2_CFG_REG             0x10
+#define TS2_LENGTH_REG          0x14
+#define EP_MODE_SET             0x18
+#define CIR_PWR_PTN1            0x1c
+#define CIR_PWR_PTN2            0x20
+#define CIR_PWR_PTN3            0x24
+#define CIR_PWR_MASK0           0x28
+#define CIR_PWR_MASK1           0x2c
+#define CIR_PWR_MASK2           0x30
+#define CIR_GAIN                0x34
+#define CIR_CAR_REG             0x38
+#define CIR_OT_CFG1             0x40
+#define CIR_OT_CFG2             0x44
+#define GBULK_BIT_EN            0x68
+#define PWR_CTL_EN              0x74
+
+/* Polaris Endpoints capture mask for register EP_MODE_SET */
+#define ENABLE_EP1              0x01   /* Bit[0]=1 */
+#define ENABLE_EP2              0x02   /* Bit[1]=1 */
+#define ENABLE_EP3              0x04   /* Bit[2]=1 */
+#define ENABLE_EP4              0x08   /* Bit[3]=1 */
+#define ENABLE_EP5              0x10   /* Bit[4]=1 */
+#define ENABLE_EP6              0x20   /* Bit[5]=1 */
+
+/* Bit definition for register PWR_CTL_EN */
+#define PWR_MODE_MASK           0x17f
+#define PWR_AV_EN               0x08   /* bit3 */
+#define PWR_ISO_EN              0x40   /* bit6 */
+#define PWR_AV_MODE             0x30   /* bit4,5  */
+#define PWR_TUNER_EN            0x04   /* bit2 */
+#define PWR_DEMOD_EN            0x02   /* bit1 */
+#define I2C_DEMOD_EN            0x01   /* bit0 */
+#define PWR_RESETOUT_EN         0x100  /* bit8 */
+
+enum AV_MODE{
+	POLARIS_AVMODE_DEFAULT = 0,
+	POLARIS_AVMODE_DIGITAL = 0x10,
+	POLARIS_AVMODE_ANALOGT_TV = 0x20,
+	POLARIS_AVMODE_ENXTERNAL_AV = 0x30,
+
+};
+
+/* Colibri Registers */
+
+#define SINGLE_ENDED            0x0
+#define LOW_IF                  0x4
+#define EU_IF                   0x9
+#define US_IF                   0xa
+
+#define SUP_BLK_TUNE1           0x00
+#define SUP_BLK_TUNE2           0x01
+#define SUP_BLK_TUNE3           0x02
+#define SUP_BLK_XTAL            0x03
+#define SUP_BLK_PLL1            0x04
+#define SUP_BLK_PLL2            0x05
+#define SUP_BLK_PLL3            0x06
+#define SUP_BLK_REF             0x07
+#define SUP_BLK_PWRDN           0x08
+#define SUP_BLK_TESTPAD         0x09
+#define ADC_COM_INT5_STAB_REF   0x0a
+#define ADC_COM_QUANT           0x0b
+#define ADC_COM_BIAS1           0x0c
+#define ADC_COM_BIAS2           0x0d
+#define ADC_COM_BIAS3           0x0e
+#define TESTBUS_CTRL            0x12
+
+#define FLD_PWRDN_TUNING_BIAS	0x10
+#define FLD_PWRDN_ENABLE_PLL	0x08
+#define FLD_PWRDN_PD_BANDGAP	0x04
+#define FLD_PWRDN_PD_BIAS	0x02
+#define FLD_PWRDN_PD_TUNECK	0x01
+
+
+#define ADC_STATUS_CH1          0x20
+#define ADC_STATUS_CH2          0x40
+#define ADC_STATUS_CH3          0x60
+
+#define ADC_STATUS2_CH1         0x21
+#define ADC_STATUS2_CH2         0x41
+#define ADC_STATUS2_CH3         0x61
+
+#define ADC_CAL_ATEST_CH1       0x22
+#define ADC_CAL_ATEST_CH2       0x42
+#define ADC_CAL_ATEST_CH3       0x62
+
+#define ADC_PWRDN_CLAMP_CH1     0x23
+#define ADC_PWRDN_CLAMP_CH2     0x43
+#define ADC_PWRDN_CLAMP_CH3     0x63
+
+#define ADC_CTRL_DAC23_CH1      0x24
+#define ADC_CTRL_DAC23_CH2      0x44
+#define ADC_CTRL_DAC23_CH3      0x64
+
+#define ADC_CTRL_DAC1_CH1       0x25
+#define ADC_CTRL_DAC1_CH2       0x45
+#define ADC_CTRL_DAC1_CH3       0x65
+
+#define ADC_DCSERVO_DEM_CH1     0x26
+#define ADC_DCSERVO_DEM_CH2     0x46
+#define ADC_DCSERVO_DEM_CH3     0x66
+
+#define ADC_FB_FRCRST_CH1       0x27
+#define ADC_FB_FRCRST_CH2       0x47
+#define ADC_FB_FRCRST_CH3       0x67
+
+#define ADC_INPUT_CH1           0x28
+#define ADC_INPUT_CH2           0x48
+#define ADC_INPUT_CH3           0x68
+#define INPUT_SEL_MASK          0x30   /* [5:4] in_sel */
+
+#define ADC_NTF_PRECLMP_EN_CH1  0x29
+#define ADC_NTF_PRECLMP_EN_CH2  0x49
+#define ADC_NTF_PRECLMP_EN_CH3  0x69
+
+#define ADC_QGAIN_RES_TRM_CH1   0x2a
+#define ADC_QGAIN_RES_TRM_CH2   0x4a
+#define ADC_QGAIN_RES_TRM_CH3   0x6a
+
+#define ADC_SOC_PRECLMP_TERM_CH1    0x2b
+#define ADC_SOC_PRECLMP_TERM_CH2    0x4b
+#define ADC_SOC_PRECLMP_TERM_CH3    0x6b
+
+#define TESTBUS_CTRL_CH1        0x32
+#define TESTBUS_CTRL_CH2        0x52
+#define TESTBUS_CTRL_CH3        0x72
+
+/******************************************************************************
+			    * DIF registers *
+ ******************************************************************************/
+#define      DIRECT_IF_REVB_BASE  0x00300
+
+/*****************************************************************************/
+#define      DIF_PLL_FREQ_WORD        (DIRECT_IF_REVB_BASE + 0x00000000)
+/*****************************************************************************/
+#define      FLD_DIF_PLL_LOCK                           0x80000000
+/*  Reserved                                [30:29] */
+#define      FLD_DIF_PLL_FREE_RUN                       0x10000000
+#define      FLD_DIF_PLL_FREQ                           0x0fffffff
+
+/*****************************************************************************/
+#define      DIF_PLL_CTRL             (DIRECT_IF_REVB_BASE + 0x00000004)
+/*****************************************************************************/
+#define      FLD_DIF_KD_PD                              0xff000000
+/*  Reserved                             [23:20] */
+#define      FLD_DIF_KDS_PD                             0x000f0000
+#define      FLD_DIF_KI_PD                              0x0000ff00
+/*  Reserved                             [7:4] */
+#define      FLD_DIF_KIS_PD                             0x0000000f
+
+/*****************************************************************************/
+#define      DIF_PLL_CTRL1            (DIRECT_IF_REVB_BASE + 0x00000008)
+/*****************************************************************************/
+#define      FLD_DIF_KD_FD                              0xff000000
+/*  Reserved                             [23:20] */
+#define      FLD_DIF_KDS_FD                             0x000f0000
+#define      FLD_DIF_KI_FD                              0x0000ff00
+#define      FLD_DIF_SIG_PROP_SZ                        0x000000f0
+#define      FLD_DIF_KIS_FD                             0x0000000f
+
+/*****************************************************************************/
+#define      DIF_PLL_CTRL2            (DIRECT_IF_REVB_BASE + 0x0000000c)
+/*****************************************************************************/
+#define      FLD_DIF_PLL_AGC_REF                        0xfff00000
+#define      FLD_DIF_PLL_AGC_KI                         0x000f0000
+/*  Reserved                             [15] */
+#define      FLD_DIF_FREQ_LIMIT                         0x00007000
+#define      FLD_DIF_K_FD                               0x00000f00
+#define      FLD_DIF_DOWNSMPL_FD                        0x000000ff
+
+/*****************************************************************************/
+#define      DIF_PLL_CTRL3            (DIRECT_IF_REVB_BASE + 0x00000010)
+/*****************************************************************************/
+/*  Reserved                             [31:16] */
+#define      FLD_DIF_PLL_AGC_EN                         0x00008000
+/*  Reserved                             [14:12] */
+#define      FLD_DIF_PLL_MAN_GAIN                       0x00000fff
+
+/*****************************************************************************/
+#define      DIF_AGC_IF_REF           (DIRECT_IF_REVB_BASE + 0x00000014)
+/*****************************************************************************/
+#define      FLD_DIF_K_AGC_RF                           0xf0000000
+#define      FLD_DIF_K_AGC_IF                           0x0f000000
+#define      FLD_DIF_K_AGC_INT                          0x00f00000
+/*  Reserved                             [19:12] */
+#define      FLD_DIF_IF_REF                             0x00000fff
+
+/*****************************************************************************/
+#define      DIF_AGC_CTRL_IF          (DIRECT_IF_REVB_BASE + 0x00000018)
+/*****************************************************************************/
+#define      FLD_DIF_IF_MAX                             0xff000000
+#define      FLD_DIF_IF_MIN                             0x00ff0000
+#define      FLD_DIF_IF_AGC                             0x0000ffff
+
+/*****************************************************************************/
+#define      DIF_AGC_CTRL_INT         (DIRECT_IF_REVB_BASE + 0x0000001c)
+/*****************************************************************************/
+#define      FLD_DIF_INT_MAX                            0xff000000
+#define      FLD_DIF_INT_MIN                            0x00ff0000
+#define      FLD_DIF_INT_AGC                            0x0000ffff
+
+/*****************************************************************************/
+#define      DIF_AGC_CTRL_RF          (DIRECT_IF_REVB_BASE + 0x00000020)
+/*****************************************************************************/
+#define      FLD_DIF_RF_MAX                             0xff000000
+#define      FLD_DIF_RF_MIN                             0x00ff0000
+#define      FLD_DIF_RF_AGC                             0x0000ffff
+
+/*****************************************************************************/
+#define      DIF_AGC_IF_INT_CURRENT   (DIRECT_IF_REVB_BASE + 0x00000024)
+/*****************************************************************************/
+#define      FLD_DIF_IF_AGC_IN                          0xffff0000
+#define      FLD_DIF_INT_AGC_IN                         0x0000ffff
+
+/*****************************************************************************/
+#define      DIF_AGC_RF_CURRENT       (DIRECT_IF_REVB_BASE + 0x00000028)
+/*****************************************************************************/
+/*  Reserved                            [31:16] */
+#define      FLD_DIF_RF_AGC_IN                          0x0000ffff
+
+/*****************************************************************************/
+#define      DIF_VIDEO_AGC_CTRL       (DIRECT_IF_REVB_BASE + 0x0000002c)
+/*****************************************************************************/
+#define      FLD_DIF_AFD                                0xc0000000
+#define      FLD_DIF_K_VID_AGC                          0x30000000
+#define      FLD_DIF_LINE_LENGTH                        0x0fff0000
+#define      FLD_DIF_AGC_GAIN                           0x0000ffff
+
+/*****************************************************************************/
+#define      DIF_VID_AUD_OVERRIDE     (DIRECT_IF_REVB_BASE + 0x00000030)
+/*****************************************************************************/
+#define      FLD_DIF_AUDIO_AGC_OVERRIDE                 0x80000000
+/*  Reserved                             [30:30] */
+#define      FLD_DIF_AUDIO_MAN_GAIN                     0x3f000000
+/*  Reserved                             [23:17] */
+#define      FLD_DIF_VID_AGC_OVERRIDE                   0x00010000
+#define      FLD_DIF_VID_MAN_GAIN                       0x0000ffff
+
+/*****************************************************************************/
+#define      DIF_AV_SEP_CTRL          (DIRECT_IF_REVB_BASE + 0x00000034)
+/*****************************************************************************/
+#define      FLD_DIF_LPF_FREQ                           0xc0000000
+#define      FLD_DIF_AV_PHASE_INC                       0x3f000000
+#define      FLD_DIF_AUDIO_FREQ                         0x00ffffff
+
+/*****************************************************************************/
+#define      DIF_COMP_FLT_CTRL        (DIRECT_IF_REVB_BASE + 0x00000038)
+/*****************************************************************************/
+/*  Reserved                            [31:24] */
+#define      FLD_DIF_IIR23_R2                           0x00ff0000
+#define      FLD_DIF_IIR23_R1                           0x0000ff00
+#define      FLD_DIF_IIR1_R1                            0x000000ff
+
+/*****************************************************************************/
+#define      DIF_MISC_CTRL            (DIRECT_IF_REVB_BASE + 0x0000003c)
+/*****************************************************************************/
+#define      FLD_DIF_DIF_BYPASS                         0x80000000
+#define      FLD_DIF_FM_NYQ_GAIN                        0x40000000
+#define      FLD_DIF_RF_AGC_ENA                         0x20000000
+#define      FLD_DIF_INT_AGC_ENA                        0x10000000
+#define      FLD_DIF_IF_AGC_ENA                         0x08000000
+#define      FLD_DIF_FORCE_RF_IF_LOCK                   0x04000000
+#define      FLD_DIF_VIDEO_AGC_ENA                      0x02000000
+#define      FLD_DIF_RF_AGC_INV                         0x01000000
+#define      FLD_DIF_INT_AGC_INV                        0x00800000
+#define      FLD_DIF_IF_AGC_INV                         0x00400000
+#define      FLD_DIF_SPEC_INV                           0x00200000
+#define      FLD_DIF_AUD_FULL_BW                        0x00100000
+#define      FLD_DIF_AUD_SRC_SEL                        0x00080000
+/*  Reserved                             [18] */
+#define      FLD_DIF_IF_FREQ                            0x00030000
+/*  Reserved                             [15:14] */
+#define      FLD_DIF_TIP_OFFSET                         0x00003f00
+/*  Reserved                             [7:5] */
+#define      FLD_DIF_DITHER_ENA                         0x00000010
+/*  Reserved                             [3:1] */
+#define      FLD_DIF_RF_IF_LOCK                         0x00000001
+
+/*****************************************************************************/
+#define      DIF_SRC_PHASE_INC        (DIRECT_IF_REVB_BASE + 0x00000040)
+/*****************************************************************************/
+/*  Reserved                             [31:29] */
+#define      FLD_DIF_PHASE_INC                          0x1fffffff
+
+/*****************************************************************************/
+#define      DIF_SRC_GAIN_CONTROL     (DIRECT_IF_REVB_BASE + 0x00000044)
+/*****************************************************************************/
+/*  Reserved                             [31:16] */
+#define      FLD_DIF_SRC_KI                             0x0000ff00
+#define      FLD_DIF_SRC_KD                             0x000000ff
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF01          (DIRECT_IF_REVB_BASE + 0x00000048)
+/*****************************************************************************/
+/*  Reserved                             [31:19] */
+#define      FLD_DIF_BPF_COEFF_0                        0x00070000
+/*  Reserved                             [15:4] */
+#define      FLD_DIF_BPF_COEFF_1                        0x0000000f
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF23          (DIRECT_IF_REVB_BASE + 0x0000004c)
+/*****************************************************************************/
+/*  Reserved                             [31:22] */
+#define      FLD_DIF_BPF_COEFF_2                        0x003f0000
+/*  Reserved                             [15:7] */
+#define      FLD_DIF_BPF_COEFF_3                        0x0000007f
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF45          (DIRECT_IF_REVB_BASE + 0x00000050)
+/*****************************************************************************/
+/*  Reserved                             [31:24] */
+#define      FLD_DIF_BPF_COEFF_4                        0x00ff0000
+/*  Reserved                             [15:8] */
+#define      FLD_DIF_BPF_COEFF_5                        0x000000ff
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF67          (DIRECT_IF_REVB_BASE + 0x00000054)
+/*****************************************************************************/
+/*  Reserved                             [31:25] */
+#define      FLD_DIF_BPF_COEFF_6                        0x01ff0000
+/*  Reserved                             [15:9] */
+#define      FLD_DIF_BPF_COEFF_7                        0x000001ff
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF89          (DIRECT_IF_REVB_BASE + 0x00000058)
+/*****************************************************************************/
+/*  Reserved                             [31:26] */
+#define      FLD_DIF_BPF_COEFF_8                        0x03ff0000
+/*  Reserved                             [15:10] */
+#define      FLD_DIF_BPF_COEFF_9                        0x000003ff
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF1011        (DIRECT_IF_REVB_BASE + 0x0000005c)
+/*****************************************************************************/
+/*  Reserved                             [31:27] */
+#define      FLD_DIF_BPF_COEFF_10                       0x07ff0000
+/*  Reserved                             [15:11] */
+#define      FLD_DIF_BPF_COEFF_11                       0x000007ff
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF1213        (DIRECT_IF_REVB_BASE + 0x00000060)
+/*****************************************************************************/
+/*  Reserved                             [31:27] */
+#define      FLD_DIF_BPF_COEFF_12                       0x07ff0000
+/*  Reserved                             [15:12] */
+#define      FLD_DIF_BPF_COEFF_13                       0x00000fff
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF1415        (DIRECT_IF_REVB_BASE + 0x00000064)
+/*****************************************************************************/
+/*  Reserved                             [31:28] */
+#define      FLD_DIF_BPF_COEFF_14                       0x0fff0000
+/*  Reserved                             [15:12] */
+#define      FLD_DIF_BPF_COEFF_15                       0x00000fff
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF1617        (DIRECT_IF_REVB_BASE + 0x00000068)
+/*****************************************************************************/
+/*  Reserved                             [31:29] */
+#define      FLD_DIF_BPF_COEFF_16                       0x1fff0000
+/*  Reserved                             [15:13] */
+#define      FLD_DIF_BPF_COEFF_17                       0x00001fff
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF1819        (DIRECT_IF_REVB_BASE + 0x0000006c)
+/*****************************************************************************/
+/*  Reserved                             [31:29] */
+#define      FLD_DIF_BPF_COEFF_18                       0x1fff0000
+/*  Reserved                             [15:13] */
+#define      FLD_DIF_BPF_COEFF_19                       0x00001fff
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF2021        (DIRECT_IF_REVB_BASE + 0x00000070)
+/*****************************************************************************/
+/*  Reserved                             [31:29] */
+#define      FLD_DIF_BPF_COEFF_20                       0x1fff0000
+/*  Reserved                             [15:14] */
+#define      FLD_DIF_BPF_COEFF_21                       0x00003fff
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF2223        (DIRECT_IF_REVB_BASE + 0x00000074)
+/*****************************************************************************/
+/*  Reserved                             [31:30] */
+#define      FLD_DIF_BPF_COEFF_22                       0x3fff0000
+/*  Reserved                             [15:14] */
+#define      FLD_DIF_BPF_COEFF_23                       0x00003fff
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF2425        (DIRECT_IF_REVB_BASE + 0x00000078)
+/*****************************************************************************/
+/*  Reserved                             [31:30] */
+#define      FLD_DIF_BPF_COEFF_24                       0x3fff0000
+/*  Reserved                             [15:14] */
+#define      FLD_DIF_BPF_COEFF_25                       0x00003fff
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF2627        (DIRECT_IF_REVB_BASE + 0x0000007c)
+/*****************************************************************************/
+/*  Reserved                             [31:30] */
+#define      FLD_DIF_BPF_COEFF_26                       0x3fff0000
+/*  Reserved                             [15:14] */
+#define      FLD_DIF_BPF_COEFF_27                       0x00003fff
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF2829        (DIRECT_IF_REVB_BASE + 0x00000080)
+/*****************************************************************************/
+/*  Reserved                             [31:30] */
+#define      FLD_DIF_BPF_COEFF_28                       0x3fff0000
+/*  Reserved                             [15:14] */
+#define      FLD_DIF_BPF_COEFF_29                       0x00003fff
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF3031        (DIRECT_IF_REVB_BASE + 0x00000084)
+/*****************************************************************************/
+/*  Reserved                             [31:30] */
+#define      FLD_DIF_BPF_COEFF_30                       0x3fff0000
+/*  Reserved                             [15:14] */
+#define      FLD_DIF_BPF_COEFF_31                       0x00003fff
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF3233        (DIRECT_IF_REVB_BASE + 0x00000088)
+/*****************************************************************************/
+/*  Reserved                             [31:30] */
+#define      FLD_DIF_BPF_COEFF_32                       0x3fff0000
+/*  Reserved                             [15:14] */
+#define      FLD_DIF_BPF_COEFF_33                       0x00003fff
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF3435        (DIRECT_IF_REVB_BASE + 0x0000008c)
+/*****************************************************************************/
+/*  Reserved                             [31:30] */
+#define      FLD_DIF_BPF_COEFF_34                       0x3fff0000
+/*  Reserved                             [15:14] */
+#define      FLD_DIF_BPF_COEFF_35                       0x00003fff
+
+/*****************************************************************************/
+#define      DIF_BPF_COEFF36          (DIRECT_IF_REVB_BASE + 0x00000090)
+/*****************************************************************************/
+/*  Reserved                             [31:30] */
+#define      FLD_DIF_BPF_COEFF_36                       0x3fff0000
+/*  Reserved                             [15:0] */
+
+/*****************************************************************************/
+#define      DIF_RPT_VARIANCE         (DIRECT_IF_REVB_BASE + 0x00000094)
+/*****************************************************************************/
+/*  Reserved                             [31:20] */
+#define      FLD_DIF_RPT_VARIANCE                       0x000fffff
+
+/*****************************************************************************/
+#define      DIF_SOFT_RST_CTRL_REVB       (DIRECT_IF_REVB_BASE + 0x00000098)
+/*****************************************************************************/
+/*  Reserved                             [31:8] */
+#define      FLD_DIF_DIF_SOFT_RST                       0x00000080
+#define      FLD_DIF_DIF_REG_RST_MSK                    0x00000040
+#define      FLD_DIF_AGC_RST_MSK                        0x00000020
+#define      FLD_DIF_CMP_RST_MSK                        0x00000010
+#define      FLD_DIF_AVS_RST_MSK                        0x00000008
+#define      FLD_DIF_NYQ_RST_MSK                        0x00000004
+#define      FLD_DIF_DIF_SRC_RST_MSK                    0x00000002
+#define      FLD_DIF_PLL_RST_MSK                        0x00000001
+
+/*****************************************************************************/
+#define      DIF_PLL_FREQ_ERR         (DIRECT_IF_REVB_BASE + 0x0000009c)
+/*****************************************************************************/
+/*  Reserved                             [31:25] */
+#define      FLD_DIF_CTL_IP                             0x01ffffff
+
+#endif
diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c
new file mode 100644
index 0000000..05358d4
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -0,0 +1,1736 @@
+/*
+   cx231xx-core.c - driver for Conexant Cx23100/101/102
+				USB video capture devices
+
+   Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+				Based on em28xx driver
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/vmalloc.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+
+#include "cx231xx.h"
+#include "cx231xx-reg.h"
+
+/* #define ENABLE_DEBUG_ISOC_FRAMES */
+
+static unsigned int core_debug;
+module_param(core_debug, int, 0644);
+MODULE_PARM_DESC(core_debug, "enable debug messages [core]");
+
+#define cx231xx_coredbg(fmt, arg...) do {\
+	if (core_debug) \
+		printk(KERN_INFO "%s %s :"fmt, \
+			 dev->name, __func__ , ##arg); } while (0)
+
+static unsigned int reg_debug;
+module_param(reg_debug, int, 0644);
+MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
+
+static int alt = CX231XX_PINOUT;
+module_param(alt, int, 0644);
+MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
+
+#define cx231xx_isocdbg(fmt, arg...) do {\
+	if (core_debug) \
+		printk(KERN_INFO "%s %s :"fmt, \
+			 dev->name, __func__ , ##arg); } while (0)
+
+/*****************************************************************
+*             Device control list functions     				 *
+******************************************************************/
+
+LIST_HEAD(cx231xx_devlist);
+static DEFINE_MUTEX(cx231xx_devlist_mutex);
+
+/*
+ * cx231xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+void cx231xx_remove_from_devlist(struct cx231xx *dev)
+{
+	if (dev == NULL)
+		return;
+	if (dev->udev == NULL)
+		return;
+
+	if (atomic_read(&dev->devlist_count) > 0) {
+		mutex_lock(&cx231xx_devlist_mutex);
+		list_del(&dev->devlist);
+		atomic_dec(&dev->devlist_count);
+		mutex_unlock(&cx231xx_devlist_mutex);
+	}
+};
+
+void cx231xx_add_into_devlist(struct cx231xx *dev)
+{
+	mutex_lock(&cx231xx_devlist_mutex);
+	list_add_tail(&dev->devlist, &cx231xx_devlist);
+	atomic_inc(&dev->devlist_count);
+	mutex_unlock(&cx231xx_devlist_mutex);
+};
+
+static LIST_HEAD(cx231xx_extension_devlist);
+
+int cx231xx_register_extension(struct cx231xx_ops *ops)
+{
+	struct cx231xx *dev = NULL;
+
+	mutex_lock(&cx231xx_devlist_mutex);
+	list_add_tail(&ops->next, &cx231xx_extension_devlist);
+	list_for_each_entry(dev, &cx231xx_devlist, devlist)
+		ops->init(dev);
+
+	printk(KERN_INFO DRIVER_NAME ": %s initialized\n", ops->name);
+	mutex_unlock(&cx231xx_devlist_mutex);
+	return 0;
+}
+EXPORT_SYMBOL(cx231xx_register_extension);
+
+void cx231xx_unregister_extension(struct cx231xx_ops *ops)
+{
+	struct cx231xx *dev = NULL;
+
+	mutex_lock(&cx231xx_devlist_mutex);
+	list_for_each_entry(dev, &cx231xx_devlist, devlist)
+		ops->fini(dev);
+
+
+	printk(KERN_INFO DRIVER_NAME ": %s removed\n", ops->name);
+	list_del(&ops->next);
+	mutex_unlock(&cx231xx_devlist_mutex);
+}
+EXPORT_SYMBOL(cx231xx_unregister_extension);
+
+void cx231xx_init_extension(struct cx231xx *dev)
+{
+	struct cx231xx_ops *ops = NULL;
+
+	mutex_lock(&cx231xx_devlist_mutex);
+	if (!list_empty(&cx231xx_extension_devlist)) {
+		list_for_each_entry(ops, &cx231xx_extension_devlist, next) {
+			if (ops->init)
+				ops->init(dev);
+		}
+	}
+	mutex_unlock(&cx231xx_devlist_mutex);
+}
+
+void cx231xx_close_extension(struct cx231xx *dev)
+{
+	struct cx231xx_ops *ops = NULL;
+
+	mutex_lock(&cx231xx_devlist_mutex);
+	if (!list_empty(&cx231xx_extension_devlist)) {
+		list_for_each_entry(ops, &cx231xx_extension_devlist, next) {
+			if (ops->fini)
+				ops->fini(dev);
+		}
+	}
+	mutex_unlock(&cx231xx_devlist_mutex);
+}
+
+/****************************************************************
+*               U S B related functions                         *
+*****************************************************************/
+int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus,
+			     struct cx231xx_i2c_xfer_data *req_data)
+{
+	int status = 0;
+	struct cx231xx *dev = i2c_bus->dev;
+	struct VENDOR_REQUEST_IN ven_req;
+
+	u8 saddr_len = 0;
+	u8 _i2c_period = 0;
+	u8 _i2c_nostop = 0;
+	u8 _i2c_reserve = 0;
+
+	if (dev->state & DEV_DISCONNECTED)
+		return -ENODEV;
+
+	/* Get the I2C period, nostop and reserve parameters */
+	_i2c_period = i2c_bus->i2c_period;
+	_i2c_nostop = i2c_bus->i2c_nostop;
+	_i2c_reserve = i2c_bus->i2c_reserve;
+
+	saddr_len = req_data->saddr_len;
+
+	/* Set wValue */
+	if (saddr_len == 1)	/* need check saddr_len == 0  */
+		ven_req.wValue =
+		    req_data->
+		    dev_addr << 9 | _i2c_period << 4 | saddr_len << 2 |
+		    _i2c_nostop << 1 | I2C_SYNC | _i2c_reserve << 6;
+	else
+		ven_req.wValue =
+		    req_data->
+		    dev_addr << 9 | _i2c_period << 4 | saddr_len << 2 |
+		    _i2c_nostop << 1 | I2C_SYNC | _i2c_reserve << 6;
+
+	/* set channel number */
+	if (req_data->direction & I2C_M_RD) {
+		/* channel number, for read,spec required channel_num +4 */
+		ven_req.bRequest = i2c_bus->nr + 4;
+	} else
+		ven_req.bRequest = i2c_bus->nr;	/* channel number,  */
+
+	/* set index value */
+	switch (saddr_len) {
+	case 0:
+		ven_req.wIndex = 0;	/* need check */
+		break;
+	case 1:
+		ven_req.wIndex = (req_data->saddr_dat & 0xff);
+		break;
+	case 2:
+		ven_req.wIndex = req_data->saddr_dat;
+		break;
+	}
+
+	/* set wLength value */
+	ven_req.wLength = req_data->buf_size;
+
+	/* set bData value */
+	ven_req.bData = 0;
+
+	/* set the direction */
+	if (req_data->direction) {
+		ven_req.direction = USB_DIR_IN;
+		memset(req_data->p_buffer, 0x00, ven_req.wLength);
+	} else
+		ven_req.direction = USB_DIR_OUT;
+
+	/* set the buffer for read / write */
+	ven_req.pBuff = req_data->p_buffer;
+
+
+	/* call common vendor command request */
+	status = cx231xx_send_vendor_cmd(dev, &ven_req);
+	if (status < 0) {
+		cx231xx_info
+		    ("UsbInterface::sendCommand, failed with status -%d\n",
+		     status);
+	}
+
+	return status;
+}
+EXPORT_SYMBOL_GPL(cx231xx_send_usb_command);
+
+/*
+ * Sends/Receives URB control messages, assuring to use a kalloced buffer
+ * for all operations (dev->urb_buf), to avoid using stacked buffers, as
+ * they aren't safe for usage with USB, due to DMA restrictions.
+ * Also implements the debug code for control URB's.
+ */
+static int __usb_control_msg(struct cx231xx *dev, unsigned int pipe,
+	__u8 request, __u8 requesttype, __u16 value, __u16 index,
+	void *data, __u16 size, int timeout)
+{
+	int rc, i;
+
+	if (reg_debug) {
+		printk(KERN_DEBUG "%s: (pipe 0x%08x): "
+				"%s:  %02x %02x %02x %02x %02x %02x %02x %02x ",
+				dev->name,
+				pipe,
+				(requesttype & USB_DIR_IN) ? "IN" : "OUT",
+				requesttype,
+				request,
+				value & 0xff, value >> 8,
+				index & 0xff, index >> 8,
+				size & 0xff, size >> 8);
+		if (!(requesttype & USB_DIR_IN)) {
+			printk(KERN_CONT ">>>");
+			for (i = 0; i < size; i++)
+				printk(KERN_CONT " %02x",
+				       ((unsigned char *)data)[i]);
+		}
+	}
+
+	/* Do the real call to usb_control_msg */
+	mutex_lock(&dev->ctrl_urb_lock);
+	if (!(requesttype & USB_DIR_IN) && size)
+		memcpy(dev->urb_buf, data, size);
+	rc = usb_control_msg(dev->udev, pipe, request, requesttype, value,
+			     index, dev->urb_buf, size, timeout);
+	if ((requesttype & USB_DIR_IN) && size)
+		memcpy(data, dev->urb_buf, size);
+	mutex_unlock(&dev->ctrl_urb_lock);
+
+	if (reg_debug) {
+		if (unlikely(rc < 0)) {
+			printk(KERN_CONT "FAILED!\n");
+			return rc;
+		}
+
+		if ((requesttype & USB_DIR_IN)) {
+			printk(KERN_CONT "<<<");
+			for (i = 0; i < size; i++)
+				printk(KERN_CONT " %02x",
+				       ((unsigned char *)data)[i]);
+		}
+		printk(KERN_CONT "\n");
+	}
+
+	return rc;
+}
+
+
+/*
+ * cx231xx_read_ctrl_reg()
+ * reads data from the usb device specifying bRequest and wValue
+ */
+int cx231xx_read_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg,
+			  char *buf, int len)
+{
+	u8 val = 0;
+	int ret;
+	int pipe = usb_rcvctrlpipe(dev->udev, 0);
+
+	if (dev->state & DEV_DISCONNECTED)
+		return -ENODEV;
+
+	if (len > URB_MAX_CTRL_SIZE)
+		return -EINVAL;
+
+	switch (len) {
+	case 1:
+		val = ENABLE_ONE_BYTE;
+		break;
+	case 2:
+		val = ENABLE_TWE_BYTE;
+		break;
+	case 3:
+		val = ENABLE_THREE_BYTE;
+		break;
+	case 4:
+		val = ENABLE_FOUR_BYTE;
+		break;
+	default:
+		val = 0xFF;	/* invalid option */
+	}
+
+	if (val == 0xFF)
+		return -EINVAL;
+
+	ret = __usb_control_msg(dev, pipe, req,
+			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      val, reg, buf, len, HZ);
+	return ret;
+}
+
+int cx231xx_send_vendor_cmd(struct cx231xx *dev,
+				struct VENDOR_REQUEST_IN *ven_req)
+{
+	int ret;
+	int pipe = 0;
+	int unsend_size = 0;
+	u8 *pdata;
+
+	if (dev->state & DEV_DISCONNECTED)
+		return -ENODEV;
+
+	if ((ven_req->wLength > URB_MAX_CTRL_SIZE))
+		return -EINVAL;
+
+	if (ven_req->direction)
+		pipe = usb_rcvctrlpipe(dev->udev, 0);
+	else
+		pipe = usb_sndctrlpipe(dev->udev, 0);
+
+	/*
+	 * If the cx23102 read more than 4 bytes with i2c bus,
+	 * need chop to 4 byte per request
+	 */
+	if ((ven_req->wLength > 4) && ((ven_req->bRequest == 0x4) ||
+					(ven_req->bRequest == 0x5) ||
+					(ven_req->bRequest == 0x6))) {
+		unsend_size = 0;
+		pdata = ven_req->pBuff;
+
+
+		unsend_size = ven_req->wLength;
+
+		/* the first package */
+		ven_req->wValue = ven_req->wValue & 0xFFFB;
+		ven_req->wValue = (ven_req->wValue & 0xFFBD) | 0x2;
+		ret = __usb_control_msg(dev, pipe, ven_req->bRequest,
+			ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			ven_req->wValue, ven_req->wIndex, pdata,
+			0x0004, HZ);
+		unsend_size = unsend_size - 4;
+
+		/* the middle package */
+		ven_req->wValue = (ven_req->wValue & 0xFFBD) | 0x42;
+		while (unsend_size - 4 > 0) {
+			pdata = pdata + 4;
+			ret = __usb_control_msg(dev, pipe,
+				ven_req->bRequest,
+				ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+				ven_req->wValue, ven_req->wIndex, pdata,
+				0x0004, HZ);
+			unsend_size = unsend_size - 4;
+		}
+
+		/* the last package */
+		ven_req->wValue = (ven_req->wValue & 0xFFBD) | 0x40;
+		pdata = pdata + 4;
+		ret = __usb_control_msg(dev, pipe, ven_req->bRequest,
+			ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			ven_req->wValue, ven_req->wIndex, pdata,
+			unsend_size, HZ);
+	} else {
+		ret = __usb_control_msg(dev, pipe, ven_req->bRequest,
+				ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+				ven_req->wValue, ven_req->wIndex,
+				ven_req->pBuff, ven_req->wLength, HZ);
+	}
+
+	return ret;
+}
+
+/*
+ * cx231xx_write_ctrl_reg()
+ * sends data to the usb device, specifying bRequest
+ */
+int cx231xx_write_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg, char *buf,
+			   int len)
+{
+	u8 val = 0;
+	int ret;
+	int pipe = usb_sndctrlpipe(dev->udev, 0);
+
+	if (dev->state & DEV_DISCONNECTED)
+		return -ENODEV;
+
+	if ((len < 1) || (len > URB_MAX_CTRL_SIZE))
+		return -EINVAL;
+
+	switch (len) {
+	case 1:
+		val = ENABLE_ONE_BYTE;
+		break;
+	case 2:
+		val = ENABLE_TWE_BYTE;
+		break;
+	case 3:
+		val = ENABLE_THREE_BYTE;
+		break;
+	case 4:
+		val = ENABLE_FOUR_BYTE;
+		break;
+	default:
+		val = 0xFF;	/* invalid option */
+	}
+
+	if (val == 0xFF)
+		return -EINVAL;
+
+	if (reg_debug) {
+		int byte;
+
+		cx231xx_isocdbg("(pipe 0x%08x): "
+			"OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>",
+			pipe,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			req, 0, val, reg & 0xff,
+			reg >> 8, len & 0xff, len >> 8);
+
+		for (byte = 0; byte < len; byte++)
+			cx231xx_isocdbg(" %02x", (unsigned char)buf[byte]);
+		cx231xx_isocdbg("\n");
+	}
+
+	ret = __usb_control_msg(dev, pipe, req,
+			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      val, reg, buf, len, HZ);
+
+	return ret;
+}
+
+/****************************************************************
+*           USB Alternate Setting functions                     *
+*****************************************************************/
+
+int cx231xx_set_video_alternate(struct cx231xx *dev)
+{
+	int errCode, prev_alt = dev->video_mode.alt;
+	unsigned int min_pkt_size = dev->width * 2 + 4;
+	u32 usb_interface_index = 0;
+
+	/* When image size is bigger than a certain value,
+	   the frame size should be increased, otherwise, only
+	   green screen will be received.
+	 */
+	if (dev->width * 2 * dev->height > 720 * 240 * 2)
+		min_pkt_size *= 2;
+
+	if (dev->width > 360) {
+		/* resolutions: 720,704,640 */
+		dev->video_mode.alt = 3;
+	} else if (dev->width > 180) {
+		/* resolutions: 360,352,320,240 */
+		dev->video_mode.alt = 2;
+	} else if (dev->width > 0) {
+		/* resolutions: 180,176,160,128,88 */
+		dev->video_mode.alt = 1;
+	} else {
+		/* Change to alt0 BULK to release USB bandwidth */
+		dev->video_mode.alt = 0;
+	}
+
+	if (dev->USE_ISO == 0)
+		dev->video_mode.alt = 0;
+
+	cx231xx_coredbg("dev->video_mode.alt= %d\n", dev->video_mode.alt);
+
+	/* Get the correct video interface Index */
+	usb_interface_index =
+	    dev->current_pcb_config.hs_config_info[0].interface_info.
+	    video_index + 1;
+
+	if (dev->video_mode.alt != prev_alt) {
+		cx231xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
+				min_pkt_size, dev->video_mode.alt);
+
+		if (dev->video_mode.alt_max_pkt_size != NULL)
+			dev->video_mode.max_pkt_size =
+			dev->video_mode.alt_max_pkt_size[dev->video_mode.alt];
+		cx231xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
+				dev->video_mode.alt,
+				dev->video_mode.max_pkt_size);
+		errCode =
+		    usb_set_interface(dev->udev, usb_interface_index,
+				      dev->video_mode.alt);
+		if (errCode < 0) {
+			cx231xx_errdev
+			    ("cannot change alt number to %d (error=%i)\n",
+			     dev->video_mode.alt, errCode);
+			return errCode;
+		}
+	}
+	return 0;
+}
+
+int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt)
+{
+	int status = 0;
+	u32 usb_interface_index = 0;
+	u32 max_pkt_size = 0;
+
+	switch (index) {
+	case INDEX_TS1:
+		usb_interface_index =
+		    dev->current_pcb_config.hs_config_info[0].interface_info.
+		    ts1_index + 1;
+		dev->ts1_mode.alt = alt;
+		if (dev->ts1_mode.alt_max_pkt_size != NULL)
+			max_pkt_size = dev->ts1_mode.max_pkt_size =
+			    dev->ts1_mode.alt_max_pkt_size[dev->ts1_mode.alt];
+		break;
+	case INDEX_TS2:
+		usb_interface_index =
+		    dev->current_pcb_config.hs_config_info[0].interface_info.
+		    ts2_index + 1;
+		break;
+	case INDEX_AUDIO:
+		usb_interface_index =
+		    dev->current_pcb_config.hs_config_info[0].interface_info.
+		    audio_index + 1;
+		dev->adev.alt = alt;
+		if (dev->adev.alt_max_pkt_size != NULL)
+			max_pkt_size = dev->adev.max_pkt_size =
+			    dev->adev.alt_max_pkt_size[dev->adev.alt];
+		break;
+	case INDEX_VIDEO:
+		usb_interface_index =
+		    dev->current_pcb_config.hs_config_info[0].interface_info.
+		    video_index + 1;
+		dev->video_mode.alt = alt;
+		if (dev->video_mode.alt_max_pkt_size != NULL)
+			max_pkt_size = dev->video_mode.max_pkt_size =
+			    dev->video_mode.alt_max_pkt_size[dev->video_mode.
+							     alt];
+		break;
+	case INDEX_VANC:
+		if (dev->board.no_alt_vanc)
+			return 0;
+		usb_interface_index =
+		    dev->current_pcb_config.hs_config_info[0].interface_info.
+		    vanc_index + 1;
+		dev->vbi_mode.alt = alt;
+		if (dev->vbi_mode.alt_max_pkt_size != NULL)
+			max_pkt_size = dev->vbi_mode.max_pkt_size =
+			    dev->vbi_mode.alt_max_pkt_size[dev->vbi_mode.alt];
+		break;
+	case INDEX_HANC:
+		usb_interface_index =
+		    dev->current_pcb_config.hs_config_info[0].interface_info.
+		    hanc_index + 1;
+		dev->sliced_cc_mode.alt = alt;
+		if (dev->sliced_cc_mode.alt_max_pkt_size != NULL)
+			max_pkt_size = dev->sliced_cc_mode.max_pkt_size =
+			    dev->sliced_cc_mode.alt_max_pkt_size[dev->
+								 sliced_cc_mode.
+								 alt];
+		break;
+	default:
+		break;
+	}
+
+	if (alt > 0 && max_pkt_size == 0) {
+		cx231xx_errdev
+		("can't change interface %d alt no. to %d: Max. Pkt size = 0\n",
+		usb_interface_index, alt);
+		/*To workaround error number=-71 on EP0 for videograbber,
+		 need add following codes.*/
+		if (dev->board.no_alt_vanc)
+			return -1;
+	}
+
+	cx231xx_coredbg("setting alternate %d with wMaxPacketSize=%u,"
+			"Interface = %d\n", alt, max_pkt_size,
+			usb_interface_index);
+
+	if (usb_interface_index > 0) {
+		status = usb_set_interface(dev->udev, usb_interface_index, alt);
+		if (status < 0) {
+			cx231xx_errdev
+			("can't change interface %d alt no. to %d (err=%i)\n",
+			usb_interface_index, alt, status);
+			return status;
+		}
+	}
+
+	return status;
+}
+EXPORT_SYMBOL_GPL(cx231xx_set_alt_setting);
+
+int cx231xx_gpio_set(struct cx231xx *dev, struct cx231xx_reg_seq *gpio)
+{
+	int rc = 0;
+
+	if (!gpio)
+		return rc;
+
+	/* Send GPIO reset sequences specified at board entry */
+	while (gpio->sleep >= 0) {
+		rc = cx231xx_set_gpio_value(dev, gpio->bit, gpio->val);
+		if (rc < 0)
+			return rc;
+
+		if (gpio->sleep > 0)
+			msleep(gpio->sleep);
+
+		gpio++;
+	}
+	return rc;
+}
+
+int cx231xx_demod_reset(struct cx231xx *dev)
+{
+
+	u8 status = 0;
+	u8 value[4] = { 0, 0, 0, 0 };
+
+	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
+				 value, 4);
+
+	cx231xx_coredbg("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN,
+			value[0], value[1], value[2], value[3]);
+
+	cx231xx_coredbg("Enter cx231xx_demod_reset()\n");
+
+		value[1] = (u8) 0x3;
+		status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+						PWR_CTL_EN, value, 4);
+			msleep(10);
+
+		value[1] = (u8) 0x0;
+		status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+						PWR_CTL_EN, value, 4);
+			msleep(10);
+
+		value[1] = (u8) 0x3;
+		status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+						PWR_CTL_EN, value, 4);
+			msleep(10);
+
+
+
+	status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
+				 value, 4);
+
+	cx231xx_coredbg("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN,
+			value[0], value[1], value[2], value[3]);
+
+	return status;
+}
+EXPORT_SYMBOL_GPL(cx231xx_demod_reset);
+int is_fw_load(struct cx231xx *dev)
+{
+	return cx231xx_check_fw(dev);
+}
+EXPORT_SYMBOL_GPL(is_fw_load);
+
+int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode)
+{
+	int errCode = 0;
+
+	if (dev->mode == set_mode)
+		return 0;
+
+	if (set_mode == CX231XX_SUSPEND) {
+		/* Set the chip in power saving mode */
+		dev->mode = set_mode;
+	}
+
+	/* Resource is locked */
+	if (dev->mode != CX231XX_SUSPEND)
+		return -EINVAL;
+
+	dev->mode = set_mode;
+
+	if (dev->mode == CX231XX_DIGITAL_MODE)/* Set Digital power mode */ {
+	/* set AGC mode to Digital */
+		switch (dev->model) {
+		case CX231XX_BOARD_CNXT_CARRAERA:
+		case CX231XX_BOARD_CNXT_RDE_250:
+		case CX231XX_BOARD_CNXT_SHELBY:
+		case CX231XX_BOARD_CNXT_RDU_250:
+		errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
+			break;
+		case CX231XX_BOARD_CNXT_RDE_253S:
+		case CX231XX_BOARD_CNXT_RDU_253S:
+			errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1);
+			break;
+		case CX231XX_BOARD_HAUPPAUGE_EXETER:
+			errCode = cx231xx_set_power_mode(dev,
+						POLARIS_AVMODE_DIGITAL);
+			break;
+		default:
+			break;
+		}
+	} else/* Set Analog Power mode */ {
+	/* set AGC mode to Analog */
+		switch (dev->model) {
+		case CX231XX_BOARD_CNXT_CARRAERA:
+		case CX231XX_BOARD_CNXT_RDE_250:
+		case CX231XX_BOARD_CNXT_SHELBY:
+		case CX231XX_BOARD_CNXT_RDU_250:
+		errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1);
+			break;
+		case CX231XX_BOARD_CNXT_RDE_253S:
+		case CX231XX_BOARD_CNXT_RDU_253S:
+		case CX231XX_BOARD_HAUPPAUGE_EXETER:
+		case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+		case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
+		case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
+		errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
+			break;
+		default:
+			break;
+		}
+	}
+
+	return errCode ? -EINVAL : 0;
+}
+EXPORT_SYMBOL_GPL(cx231xx_set_mode);
+
+int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size)
+{
+	int errCode = 0;
+	int actlen, ret = -ENOMEM;
+	u32 *buffer;
+
+	buffer = kzalloc(4096, GFP_KERNEL);
+	if (buffer == NULL) {
+		cx231xx_info("out of mem\n");
+		return -ENOMEM;
+	}
+	memcpy(&buffer[0], firmware, 4096);
+
+	ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 5),
+			buffer, 4096, &actlen, 2000);
+
+	if (ret)
+		cx231xx_info("bulk message failed: %d (%d/%d)", ret,
+				size, actlen);
+	else {
+		errCode = actlen != size ? -1 : 0;
+	}
+	kfree(buffer);
+	return errCode;
+}
+
+/*****************************************************************
+*                URB Streaming functions                         *
+******************************************************************/
+
+/*
+ * IRQ callback, called by URB callback
+ */
+static void cx231xx_isoc_irq_callback(struct urb *urb)
+{
+	struct cx231xx_dmaqueue *dma_q = urb->context;
+	struct cx231xx_video_mode *vmode =
+	    container_of(dma_q, struct cx231xx_video_mode, vidq);
+	struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
+	int i;
+
+	switch (urb->status) {
+	case 0:		/* success */
+	case -ETIMEDOUT:	/* NAK */
+		break;
+	case -ECONNRESET:	/* kill */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	default:		/* error */
+		cx231xx_isocdbg("urb completition error %d.\n", urb->status);
+		break;
+	}
+
+	/* Copy data from URB */
+	spin_lock(&dev->video_mode.slock);
+	dev->video_mode.isoc_ctl.isoc_copy(dev, urb);
+	spin_unlock(&dev->video_mode.slock);
+
+	/* Reset urb buffers */
+	for (i = 0; i < urb->number_of_packets; i++) {
+		urb->iso_frame_desc[i].status = 0;
+		urb->iso_frame_desc[i].actual_length = 0;
+	}
+
+	urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (urb->status) {
+		cx231xx_isocdbg("urb resubmit failed (error=%i)\n",
+				urb->status);
+	}
+}
+/*****************************************************************
+*                URB Streaming functions                         *
+******************************************************************/
+
+/*
+ * IRQ callback, called by URB callback
+ */
+static void cx231xx_bulk_irq_callback(struct urb *urb)
+{
+	struct cx231xx_dmaqueue *dma_q = urb->context;
+	struct cx231xx_video_mode *vmode =
+	    container_of(dma_q, struct cx231xx_video_mode, vidq);
+	struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
+
+	switch (urb->status) {
+	case 0:		/* success */
+	case -ETIMEDOUT:	/* NAK */
+		break;
+	case -ECONNRESET:	/* kill */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	default:		/* error */
+		cx231xx_isocdbg("urb completition error %d.\n", urb->status);
+		break;
+	}
+
+	/* Copy data from URB */
+	spin_lock(&dev->video_mode.slock);
+	dev->video_mode.bulk_ctl.bulk_copy(dev, urb);
+	spin_unlock(&dev->video_mode.slock);
+
+	/* Reset urb buffers */
+	urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (urb->status) {
+		cx231xx_isocdbg("urb resubmit failed (error=%i)\n",
+				urb->status);
+	}
+}
+/*
+ * Stop and Deallocate URBs
+ */
+void cx231xx_uninit_isoc(struct cx231xx *dev)
+{
+	struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq;
+	struct urb *urb;
+	int i;
+
+	cx231xx_isocdbg("cx231xx: called cx231xx_uninit_isoc\n");
+
+	dev->video_mode.isoc_ctl.nfields = -1;
+	for (i = 0; i < dev->video_mode.isoc_ctl.num_bufs; i++) {
+		urb = dev->video_mode.isoc_ctl.urb[i];
+		if (urb) {
+			if (!irqs_disabled())
+				usb_kill_urb(urb);
+			else
+				usb_unlink_urb(urb);
+
+			if (dev->video_mode.isoc_ctl.transfer_buffer[i]) {
+				usb_free_coherent(dev->udev,
+						  urb->transfer_buffer_length,
+						  dev->video_mode.isoc_ctl.
+						  transfer_buffer[i],
+						  urb->transfer_dma);
+			}
+			usb_free_urb(urb);
+			dev->video_mode.isoc_ctl.urb[i] = NULL;
+		}
+		dev->video_mode.isoc_ctl.transfer_buffer[i] = NULL;
+	}
+
+	kfree(dev->video_mode.isoc_ctl.urb);
+	kfree(dev->video_mode.isoc_ctl.transfer_buffer);
+	kfree(dma_q->p_left_data);
+
+	dev->video_mode.isoc_ctl.urb = NULL;
+	dev->video_mode.isoc_ctl.transfer_buffer = NULL;
+	dev->video_mode.isoc_ctl.num_bufs = 0;
+	dma_q->p_left_data = NULL;
+
+	if (dev->mode_tv == 0)
+		cx231xx_capture_start(dev, 0, Raw_Video);
+	else
+		cx231xx_capture_start(dev, 0, TS1_serial_mode);
+
+
+}
+EXPORT_SYMBOL_GPL(cx231xx_uninit_isoc);
+
+/*
+ * Stop and Deallocate URBs
+ */
+void cx231xx_uninit_bulk(struct cx231xx *dev)
+{
+	struct urb *urb;
+	int i;
+
+	cx231xx_isocdbg("cx231xx: called cx231xx_uninit_bulk\n");
+
+	dev->video_mode.bulk_ctl.nfields = -1;
+	for (i = 0; i < dev->video_mode.bulk_ctl.num_bufs; i++) {
+		urb = dev->video_mode.bulk_ctl.urb[i];
+		if (urb) {
+			if (!irqs_disabled())
+				usb_kill_urb(urb);
+			else
+				usb_unlink_urb(urb);
+
+			if (dev->video_mode.bulk_ctl.transfer_buffer[i]) {
+				usb_free_coherent(dev->udev,
+						urb->transfer_buffer_length,
+						dev->video_mode.isoc_ctl.
+						transfer_buffer[i],
+						urb->transfer_dma);
+			}
+			usb_free_urb(urb);
+			dev->video_mode.bulk_ctl.urb[i] = NULL;
+		}
+		dev->video_mode.bulk_ctl.transfer_buffer[i] = NULL;
+	}
+
+	kfree(dev->video_mode.bulk_ctl.urb);
+	kfree(dev->video_mode.bulk_ctl.transfer_buffer);
+
+	dev->video_mode.bulk_ctl.urb = NULL;
+	dev->video_mode.bulk_ctl.transfer_buffer = NULL;
+	dev->video_mode.bulk_ctl.num_bufs = 0;
+
+	if (dev->mode_tv == 0)
+		cx231xx_capture_start(dev, 0, Raw_Video);
+	else
+		cx231xx_capture_start(dev, 0, TS1_serial_mode);
+
+
+}
+EXPORT_SYMBOL_GPL(cx231xx_uninit_bulk);
+
+/*
+ * Allocate URBs and start IRQ
+ */
+int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
+		      int num_bufs, int max_pkt_size,
+		      int (*isoc_copy) (struct cx231xx *dev, struct urb *urb))
+{
+	struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq;
+	int i;
+	int sb_size, pipe;
+	struct urb *urb;
+	int j, k;
+	int rc;
+
+	/* De-allocates all pending stuff */
+	cx231xx_uninit_isoc(dev);
+
+	dma_q->p_left_data = kzalloc(4096, GFP_KERNEL);
+	if (dma_q->p_left_data == NULL) {
+		cx231xx_info("out of mem\n");
+		return -ENOMEM;
+	}
+
+
+
+	dev->video_mode.isoc_ctl.isoc_copy = isoc_copy;
+	dev->video_mode.isoc_ctl.num_bufs = num_bufs;
+	dma_q->pos = 0;
+	dma_q->is_partial_line = 0;
+	dma_q->last_sav = 0;
+	dma_q->current_field = -1;
+	dma_q->field1_done = 0;
+	dma_q->lines_per_field = dev->height / 2;
+	dma_q->bytes_left_in_line = dev->width << 1;
+	dma_q->lines_completed = 0;
+	dma_q->mpeg_buffer_done = 0;
+	dma_q->left_data_count = 0;
+	dma_q->mpeg_buffer_completed = 0;
+	dma_q->add_ps_package_head = CX231XX_NEED_ADD_PS_PACKAGE_HEAD;
+	dma_q->ps_head[0] = 0x00;
+	dma_q->ps_head[1] = 0x00;
+	dma_q->ps_head[2] = 0x01;
+	dma_q->ps_head[3] = 0xBA;
+	for (i = 0; i < 8; i++)
+		dma_q->partial_buf[i] = 0;
+
+	dev->video_mode.isoc_ctl.urb =
+	    kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
+	if (!dev->video_mode.isoc_ctl.urb) {
+		cx231xx_errdev("cannot alloc memory for usb buffers\n");
+		return -ENOMEM;
+	}
+
+	dev->video_mode.isoc_ctl.transfer_buffer =
+	    kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
+	if (!dev->video_mode.isoc_ctl.transfer_buffer) {
+		cx231xx_errdev("cannot allocate memory for usbtransfer\n");
+		kfree(dev->video_mode.isoc_ctl.urb);
+		return -ENOMEM;
+	}
+
+	dev->video_mode.isoc_ctl.max_pkt_size = max_pkt_size;
+	dev->video_mode.isoc_ctl.buf = NULL;
+
+	sb_size = max_packets * dev->video_mode.isoc_ctl.max_pkt_size;
+
+	if (dev->mode_tv == 1)
+		dev->video_mode.end_point_addr = 0x81;
+	else
+		dev->video_mode.end_point_addr = 0x84;
+
+
+	/* allocate urbs and transfer buffers */
+	for (i = 0; i < dev->video_mode.isoc_ctl.num_bufs; i++) {
+		urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+		if (!urb) {
+			cx231xx_err("cannot alloc isoc_ctl.urb %i\n", i);
+			cx231xx_uninit_isoc(dev);
+			return -ENOMEM;
+		}
+		dev->video_mode.isoc_ctl.urb[i] = urb;
+
+		dev->video_mode.isoc_ctl.transfer_buffer[i] =
+		    usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL,
+				       &urb->transfer_dma);
+		if (!dev->video_mode.isoc_ctl.transfer_buffer[i]) {
+			cx231xx_err("unable to allocate %i bytes for transfer"
+				    " buffer %i%s\n",
+				    sb_size, i,
+				    in_interrupt() ? " while in int" : "");
+			cx231xx_uninit_isoc(dev);
+			return -ENOMEM;
+		}
+		memset(dev->video_mode.isoc_ctl.transfer_buffer[i], 0, sb_size);
+
+		pipe =
+		    usb_rcvisocpipe(dev->udev, dev->video_mode.end_point_addr);
+
+		usb_fill_int_urb(urb, dev->udev, pipe,
+				 dev->video_mode.isoc_ctl.transfer_buffer[i],
+				 sb_size, cx231xx_isoc_irq_callback, dma_q, 1);
+
+		urb->number_of_packets = max_packets;
+		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+
+		k = 0;
+		for (j = 0; j < max_packets; j++) {
+			urb->iso_frame_desc[j].offset = k;
+			urb->iso_frame_desc[j].length =
+			    dev->video_mode.isoc_ctl.max_pkt_size;
+			k += dev->video_mode.isoc_ctl.max_pkt_size;
+		}
+	}
+
+	init_waitqueue_head(&dma_q->wq);
+
+	/* submit urbs and enables IRQ */
+	for (i = 0; i < dev->video_mode.isoc_ctl.num_bufs; i++) {
+		rc = usb_submit_urb(dev->video_mode.isoc_ctl.urb[i],
+				    GFP_ATOMIC);
+		if (rc) {
+			cx231xx_err("submit of urb %i failed (error=%i)\n", i,
+				    rc);
+			cx231xx_uninit_isoc(dev);
+			return rc;
+		}
+	}
+
+	if (dev->mode_tv == 0)
+		cx231xx_capture_start(dev, 1, Raw_Video);
+	else
+		cx231xx_capture_start(dev, 1, TS1_serial_mode);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cx231xx_init_isoc);
+
+/*
+ * Allocate URBs and start IRQ
+ */
+int cx231xx_init_bulk(struct cx231xx *dev, int max_packets,
+		      int num_bufs, int max_pkt_size,
+		      int (*bulk_copy) (struct cx231xx *dev, struct urb *urb))
+{
+	struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq;
+	int i;
+	int sb_size, pipe;
+	struct urb *urb;
+	int rc;
+
+	dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
+
+	cx231xx_coredbg("Setting Video mux to %d\n", dev->video_input);
+
+	video_mux(dev, dev->video_input);
+
+	/* De-allocates all pending stuff */
+	cx231xx_uninit_bulk(dev);
+
+	dev->video_mode.bulk_ctl.bulk_copy = bulk_copy;
+	dev->video_mode.bulk_ctl.num_bufs = num_bufs;
+	dma_q->pos = 0;
+	dma_q->is_partial_line = 0;
+	dma_q->last_sav = 0;
+	dma_q->current_field = -1;
+	dma_q->field1_done = 0;
+	dma_q->lines_per_field = dev->height / 2;
+	dma_q->bytes_left_in_line = dev->width << 1;
+	dma_q->lines_completed = 0;
+	dma_q->mpeg_buffer_done = 0;
+	dma_q->left_data_count = 0;
+	dma_q->mpeg_buffer_completed = 0;
+	dma_q->ps_head[0] = 0x00;
+	dma_q->ps_head[1] = 0x00;
+	dma_q->ps_head[2] = 0x01;
+	dma_q->ps_head[3] = 0xBA;
+	for (i = 0; i < 8; i++)
+		dma_q->partial_buf[i] = 0;
+
+	dev->video_mode.bulk_ctl.urb =
+	    kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
+	if (!dev->video_mode.bulk_ctl.urb) {
+		cx231xx_errdev("cannot alloc memory for usb buffers\n");
+		return -ENOMEM;
+	}
+
+	dev->video_mode.bulk_ctl.transfer_buffer =
+	    kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
+	if (!dev->video_mode.bulk_ctl.transfer_buffer) {
+		cx231xx_errdev("cannot allocate memory for usbtransfer\n");
+		kfree(dev->video_mode.bulk_ctl.urb);
+		return -ENOMEM;
+	}
+
+	dev->video_mode.bulk_ctl.max_pkt_size = max_pkt_size;
+	dev->video_mode.bulk_ctl.buf = NULL;
+
+	sb_size = max_packets * dev->video_mode.bulk_ctl.max_pkt_size;
+
+	if (dev->mode_tv == 1)
+		dev->video_mode.end_point_addr = 0x81;
+	else
+		dev->video_mode.end_point_addr = 0x84;
+
+
+	/* allocate urbs and transfer buffers */
+	for (i = 0; i < dev->video_mode.bulk_ctl.num_bufs; i++) {
+		urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!urb) {
+			cx231xx_err("cannot alloc bulk_ctl.urb %i\n", i);
+			cx231xx_uninit_bulk(dev);
+			return -ENOMEM;
+		}
+		dev->video_mode.bulk_ctl.urb[i] = urb;
+		urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+
+		dev->video_mode.bulk_ctl.transfer_buffer[i] =
+		    usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL,
+				     &urb->transfer_dma);
+		if (!dev->video_mode.bulk_ctl.transfer_buffer[i]) {
+			cx231xx_err("unable to allocate %i bytes for transfer"
+				    " buffer %i%s\n",
+				    sb_size, i,
+				    in_interrupt() ? " while in int" : "");
+			cx231xx_uninit_bulk(dev);
+			return -ENOMEM;
+		}
+		memset(dev->video_mode.bulk_ctl.transfer_buffer[i], 0, sb_size);
+
+		pipe = usb_rcvbulkpipe(dev->udev,
+				 dev->video_mode.end_point_addr);
+		usb_fill_bulk_urb(urb, dev->udev, pipe,
+				  dev->video_mode.bulk_ctl.transfer_buffer[i],
+				  sb_size, cx231xx_bulk_irq_callback, dma_q);
+	}
+
+	init_waitqueue_head(&dma_q->wq);
+
+	/* submit urbs and enables IRQ */
+	for (i = 0; i < dev->video_mode.bulk_ctl.num_bufs; i++) {
+		rc = usb_submit_urb(dev->video_mode.bulk_ctl.urb[i],
+				    GFP_ATOMIC);
+		if (rc) {
+			cx231xx_err("submit of urb %i failed (error=%i)\n", i,
+				    rc);
+			cx231xx_uninit_bulk(dev);
+			return rc;
+		}
+	}
+
+	if (dev->mode_tv == 0)
+		cx231xx_capture_start(dev, 1, Raw_Video);
+	else
+		cx231xx_capture_start(dev, 1, TS1_serial_mode);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cx231xx_init_bulk);
+void cx231xx_stop_TS1(struct cx231xx *dev)
+{
+	u8 val[4] = { 0, 0, 0, 0 };
+
+	val[0] = 0x00;
+	val[1] = 0x03;
+	val[2] = 0x00;
+	val[3] = 0x00;
+	cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+			TS_MODE_REG, val, 4);
+
+	val[0] = 0x00;
+	val[1] = 0x70;
+	val[2] = 0x04;
+	val[3] = 0x00;
+	cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+			TS1_CFG_REG, val, 4);
+}
+/* EXPORT_SYMBOL_GPL(cx231xx_stop_TS1); */
+void cx231xx_start_TS1(struct cx231xx *dev)
+{
+	u8 val[4] = { 0, 0, 0, 0 };
+
+	val[0] = 0x03;
+	val[1] = 0x03;
+	val[2] = 0x00;
+	val[3] = 0x00;
+	cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+			TS_MODE_REG, val, 4);
+
+	val[0] = 0x04;
+	val[1] = 0xA3;
+	val[2] = 0x3B;
+	val[3] = 0x00;
+	cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+			TS1_CFG_REG, val, 4);
+}
+/* EXPORT_SYMBOL_GPL(cx231xx_start_TS1); */
+/*****************************************************************
+*             Device Init/UnInit functions                       *
+******************************************************************/
+int cx231xx_dev_init(struct cx231xx *dev)
+{
+	int errCode = 0;
+
+	/* Initialize I2C bus */
+
+	/* External Master 1 Bus */
+	dev->i2c_bus[0].nr = 0;
+	dev->i2c_bus[0].dev = dev;
+	dev->i2c_bus[0].i2c_period = I2C_SPEED_100K;	/* 100 KHz */
+	dev->i2c_bus[0].i2c_nostop = 0;
+	dev->i2c_bus[0].i2c_reserve = 0;
+
+	/* External Master 2 Bus */
+	dev->i2c_bus[1].nr = 1;
+	dev->i2c_bus[1].dev = dev;
+	dev->i2c_bus[1].i2c_period = I2C_SPEED_100K;	/* 100 KHz */
+	dev->i2c_bus[1].i2c_nostop = 0;
+	dev->i2c_bus[1].i2c_reserve = 0;
+
+	/* Internal Master 3 Bus */
+	dev->i2c_bus[2].nr = 2;
+	dev->i2c_bus[2].dev = dev;
+	dev->i2c_bus[2].i2c_period = I2C_SPEED_100K;	/* 100kHz */
+	dev->i2c_bus[2].i2c_nostop = 0;
+	dev->i2c_bus[2].i2c_reserve = 0;
+
+	/* register I2C buses */
+	cx231xx_i2c_register(&dev->i2c_bus[0]);
+	cx231xx_i2c_register(&dev->i2c_bus[1]);
+	cx231xx_i2c_register(&dev->i2c_bus[2]);
+
+	/* init hardware */
+	/* Note : with out calling set power mode function,
+	afe can not be set up correctly */
+	if (dev->board.external_av) {
+		errCode = cx231xx_set_power_mode(dev,
+				 POLARIS_AVMODE_ENXTERNAL_AV);
+		if (errCode < 0) {
+			cx231xx_errdev
+			("%s: Failed to set Power - errCode [%d]!\n",
+			__func__, errCode);
+			return errCode;
+		}
+	} else {
+		errCode = cx231xx_set_power_mode(dev,
+				 POLARIS_AVMODE_ANALOGT_TV);
+		if (errCode < 0) {
+			cx231xx_errdev
+			("%s: Failed to set Power - errCode [%d]!\n",
+			__func__, errCode);
+			return errCode;
+		}
+	}
+
+	/* reset the Tuner, if it is a Xceive tuner */
+	if ((dev->board.tuner_type == TUNER_XC5000) ||
+	    (dev->board.tuner_type == TUNER_XC2028))
+			cx231xx_gpio_set(dev, dev->board.tuner_gpio);
+
+	/* initialize Colibri block */
+	errCode = cx231xx_afe_init_super_block(dev, 0x23c);
+	if (errCode < 0) {
+		cx231xx_errdev
+		    ("%s: cx231xx_afe init super block - errCode [%d]!\n",
+		     __func__, errCode);
+		return errCode;
+	}
+	errCode = cx231xx_afe_init_channels(dev);
+	if (errCode < 0) {
+		cx231xx_errdev
+		    ("%s: cx231xx_afe init channels - errCode [%d]!\n",
+		     __func__, errCode);
+		return errCode;
+	}
+
+	/* Set DIF in By pass mode */
+	errCode = cx231xx_dif_set_standard(dev, DIF_USE_BASEBAND);
+	if (errCode < 0) {
+		cx231xx_errdev
+		    ("%s: cx231xx_dif set to By pass mode - errCode [%d]!\n",
+		     __func__, errCode);
+		return errCode;
+	}
+
+	/* I2S block related functions */
+	errCode = cx231xx_i2s_blk_initialize(dev);
+	if (errCode < 0) {
+		cx231xx_errdev
+		    ("%s: cx231xx_i2s block initialize - errCode [%d]!\n",
+		     __func__, errCode);
+		return errCode;
+	}
+
+	/* init control pins */
+	errCode = cx231xx_init_ctrl_pin_status(dev);
+	if (errCode < 0) {
+		cx231xx_errdev("%s: cx231xx_init ctrl pins - errCode [%d]!\n",
+			       __func__, errCode);
+		return errCode;
+	}
+
+	/* set AGC mode to Analog */
+	switch (dev->model) {
+	case CX231XX_BOARD_CNXT_CARRAERA:
+	case CX231XX_BOARD_CNXT_RDE_250:
+	case CX231XX_BOARD_CNXT_SHELBY:
+	case CX231XX_BOARD_CNXT_RDU_250:
+	errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1);
+		break;
+	case CX231XX_BOARD_CNXT_RDE_253S:
+	case CX231XX_BOARD_CNXT_RDU_253S:
+	case CX231XX_BOARD_HAUPPAUGE_EXETER:
+	case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+	case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
+	case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
+	errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
+		break;
+	default:
+		break;
+	}
+	if (errCode < 0) {
+		cx231xx_errdev
+		    ("%s: cx231xx_AGC mode to Analog - errCode [%d]!\n",
+		     __func__, errCode);
+		return errCode;
+	}
+
+	/* set all alternate settings to zero initially */
+	cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0);
+	cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
+	cx231xx_set_alt_setting(dev, INDEX_HANC, 0);
+	if (dev->board.has_dvb)
+		cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
+
+	/* set the I2C master port to 3 on channel 1 */
+	errCode = cx231xx_enable_i2c_port_3(dev, true);
+
+	return errCode;
+}
+EXPORT_SYMBOL_GPL(cx231xx_dev_init);
+
+void cx231xx_dev_uninit(struct cx231xx *dev)
+{
+	/* Un Initialize I2C bus */
+	cx231xx_i2c_unregister(&dev->i2c_bus[2]);
+	cx231xx_i2c_unregister(&dev->i2c_bus[1]);
+	cx231xx_i2c_unregister(&dev->i2c_bus[0]);
+}
+EXPORT_SYMBOL_GPL(cx231xx_dev_uninit);
+
+/*****************************************************************
+*              G P I O related functions                         *
+******************************************************************/
+int cx231xx_send_gpio_cmd(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val,
+			  u8 len, u8 request, u8 direction)
+{
+	int status = 0;
+	struct VENDOR_REQUEST_IN ven_req;
+
+	/* Set wValue */
+	ven_req.wValue = (u16) (gpio_bit >> 16 & 0xffff);
+
+	/* set request */
+	if (!request) {
+		if (direction)
+			ven_req.bRequest = VRT_GET_GPIO;	/* 0x8 gpio */
+		else
+			ven_req.bRequest = VRT_SET_GPIO;	/* 0x9 gpio */
+	} else {
+		if (direction)
+			ven_req.bRequest = VRT_GET_GPIE;	/* 0xa gpie */
+		else
+			ven_req.bRequest = VRT_SET_GPIE;	/* 0xb gpie */
+	}
+
+	/* set index value */
+	ven_req.wIndex = (u16) (gpio_bit & 0xffff);
+
+	/* set wLength value */
+	ven_req.wLength = len;
+
+	/* set bData value */
+	ven_req.bData = 0;
+
+	/* set the buffer for read / write */
+	ven_req.pBuff = gpio_val;
+
+	/* set the direction */
+	if (direction) {
+		ven_req.direction = USB_DIR_IN;
+		memset(ven_req.pBuff, 0x00, ven_req.wLength);
+	} else
+		ven_req.direction = USB_DIR_OUT;
+
+
+	/* call common vendor command request */
+	status = cx231xx_send_vendor_cmd(dev, &ven_req);
+	if (status < 0) {
+		cx231xx_info
+		    ("UsbInterface::sendCommand, failed with status -%d\n",
+		     status);
+	}
+
+	return status;
+}
+EXPORT_SYMBOL_GPL(cx231xx_send_gpio_cmd);
+
+/*****************************************************************
+ *    C O N T R O L - Register R E A D / W R I T E functions     *
+ *****************************************************************/
+int cx231xx_mode_register(struct cx231xx *dev, u16 address, u32 mode)
+{
+	u8 value[4] = { 0x0, 0x0, 0x0, 0x0 };
+	u32 tmp = 0;
+	int status = 0;
+
+	status =
+	    cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, address, value, 4);
+	if (status < 0)
+		return status;
+
+	tmp = *((u32 *) value);
+	tmp |= mode;
+
+	value[0] = (u8) tmp;
+	value[1] = (u8) (tmp >> 8);
+	value[2] = (u8) (tmp >> 16);
+	value[3] = (u8) (tmp >> 24);
+
+	status =
+	    cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, address, value, 4);
+
+	return status;
+}
+
+/*****************************************************************
+ *            I 2 C Internal C O N T R O L   functions           *
+ *****************************************************************/
+int cx231xx_read_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr,
+			  u8 saddr_len, u32 *data, u8 data_len, int master)
+{
+	int status = 0;
+	struct cx231xx_i2c_xfer_data req_data;
+	u8 value[64] = "0";
+
+	if (saddr_len == 0)
+		saddr = 0;
+	else if (saddr_len == 1)
+		saddr &= 0xff;
+
+	/* prepare xfer_data struct */
+	req_data.dev_addr = dev_addr >> 1;
+	req_data.direction = I2C_M_RD;
+	req_data.saddr_len = saddr_len;
+	req_data.saddr_dat = saddr;
+	req_data.buf_size = data_len;
+	req_data.p_buffer = (u8 *) value;
+
+	/* usb send command */
+	if (master == 0)
+		status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0],
+					 &req_data);
+	else if (master == 1)
+		status = dev->cx231xx_send_usb_command(&dev->i2c_bus[1],
+					 &req_data);
+	else if (master == 2)
+		status = dev->cx231xx_send_usb_command(&dev->i2c_bus[2],
+					 &req_data);
+
+	if (status >= 0) {
+		/* Copy the data read back to main buffer */
+		if (data_len == 1)
+			*data = value[0];
+		else if (data_len == 4)
+			*data =
+			    value[0] | value[1] << 8 | value[2] << 16 | value[3]
+			    << 24;
+		else if (data_len > 4)
+			*data = value[saddr];
+	}
+
+	return status;
+}
+
+int cx231xx_write_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr,
+			   u8 saddr_len, u32 data, u8 data_len, int master)
+{
+	int status = 0;
+	u8 value[4] = { 0, 0, 0, 0 };
+	struct cx231xx_i2c_xfer_data req_data;
+
+	value[0] = (u8) data;
+	value[1] = (u8) (data >> 8);
+	value[2] = (u8) (data >> 16);
+	value[3] = (u8) (data >> 24);
+
+	if (saddr_len == 0)
+		saddr = 0;
+	else if (saddr_len == 1)
+		saddr &= 0xff;
+
+	/* prepare xfer_data struct */
+	req_data.dev_addr = dev_addr >> 1;
+	req_data.direction = 0;
+	req_data.saddr_len = saddr_len;
+	req_data.saddr_dat = saddr;
+	req_data.buf_size = data_len;
+	req_data.p_buffer = value;
+
+	/* usb send command */
+	if (master == 0)
+		status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0],
+				 &req_data);
+	else if (master == 1)
+		status = dev->cx231xx_send_usb_command(&dev->i2c_bus[1],
+				 &req_data);
+	else if (master == 2)
+		status = dev->cx231xx_send_usb_command(&dev->i2c_bus[2],
+				 &req_data);
+
+	return status;
+}
+
+int cx231xx_read_i2c_data(struct cx231xx *dev, u8 dev_addr, u16 saddr,
+			  u8 saddr_len, u32 *data, u8 data_len)
+{
+	int status = 0;
+	struct cx231xx_i2c_xfer_data req_data;
+	u8 value[4] = { 0, 0, 0, 0 };
+
+	if (saddr_len == 0)
+		saddr = 0;
+	else if (saddr_len == 1)
+		saddr &= 0xff;
+
+	/* prepare xfer_data struct */
+	req_data.dev_addr = dev_addr >> 1;
+	req_data.direction = I2C_M_RD;
+	req_data.saddr_len = saddr_len;
+	req_data.saddr_dat = saddr;
+	req_data.buf_size = data_len;
+	req_data.p_buffer = (u8 *) value;
+
+	/* usb send command */
+	status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0], &req_data);
+
+	if (status >= 0) {
+		/* Copy the data read back to main buffer */
+		if (data_len == 1)
+			*data = value[0];
+		else
+			*data =
+			    value[0] | value[1] << 8 | value[2] << 16 | value[3]
+			    << 24;
+	}
+
+	return status;
+}
+
+int cx231xx_write_i2c_data(struct cx231xx *dev, u8 dev_addr, u16 saddr,
+			   u8 saddr_len, u32 data, u8 data_len)
+{
+	int status = 0;
+	u8 value[4] = { 0, 0, 0, 0 };
+	struct cx231xx_i2c_xfer_data req_data;
+
+	value[0] = (u8) data;
+	value[1] = (u8) (data >> 8);
+	value[2] = (u8) (data >> 16);
+	value[3] = (u8) (data >> 24);
+
+	if (saddr_len == 0)
+		saddr = 0;
+	else if (saddr_len == 1)
+		saddr &= 0xff;
+
+	/* prepare xfer_data struct */
+	req_data.dev_addr = dev_addr >> 1;
+	req_data.direction = 0;
+	req_data.saddr_len = saddr_len;
+	req_data.saddr_dat = saddr;
+	req_data.buf_size = data_len;
+	req_data.p_buffer = value;
+
+	/* usb send command */
+	status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0], &req_data);
+
+	return status;
+}
+
+int cx231xx_reg_mask_write(struct cx231xx *dev, u8 dev_addr, u8 size,
+			   u16 register_address, u8 bit_start, u8 bit_end,
+			   u32 value)
+{
+	int status = 0;
+	u32 tmp;
+	u32 mask = 0;
+	int i;
+
+	if (bit_start > (size - 1) || bit_end > (size - 1))
+		return -1;
+
+	if (size == 8) {
+		status =
+		    cx231xx_read_i2c_data(dev, dev_addr, register_address, 2,
+					  &tmp, 1);
+	} else {
+		status =
+		    cx231xx_read_i2c_data(dev, dev_addr, register_address, 2,
+					  &tmp, 4);
+	}
+
+	if (status < 0)
+		return status;
+
+	mask = 1 << bit_end;
+	for (i = bit_end; i > bit_start && i > 0; i--)
+		mask = mask + (1 << (i - 1));
+
+	value <<= bit_start;
+
+	if (size == 8) {
+		tmp &= ~mask;
+		tmp |= value;
+		tmp &= 0xff;
+		status =
+		    cx231xx_write_i2c_data(dev, dev_addr, register_address, 2,
+					   tmp, 1);
+	} else {
+		tmp &= ~mask;
+		tmp |= value;
+		status =
+		    cx231xx_write_i2c_data(dev, dev_addr, register_address, 2,
+					   tmp, 4);
+	}
+
+	return status;
+}
+
+int cx231xx_read_modify_write_i2c_dword(struct cx231xx *dev, u8 dev_addr,
+					u16 saddr, u32 mask, u32 value)
+{
+	u32 temp;
+	int status = 0;
+
+	status = cx231xx_read_i2c_data(dev, dev_addr, saddr, 2, &temp, 4);
+
+	if (status < 0)
+		return status;
+
+	temp &= ~mask;
+	temp |= value;
+
+	status = cx231xx_write_i2c_data(dev, dev_addr, saddr, 2, temp, 4);
+
+	return status;
+}
+
+u32 cx231xx_set_field(u32 field_mask, u32 data)
+{
+	u32 temp;
+
+	for (temp = field_mask; (temp & 1) == 0; temp >>= 1)
+		data <<= 1;
+
+	return data;
+}
diff --git a/drivers/media/usb/cx231xx/cx231xx-dif.h b/drivers/media/usb/cx231xx/cx231xx-dif.h
new file mode 100644
index 0000000..2b63c2f
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-dif.h
@@ -0,0 +1,3178 @@
+/*
+ *  cx231xx-dif.h - driver for Conexant Cx23100/101/102 USB video capture devices
+ *
+ *  Copyright {C} 2009 <Bill.Liu@conexant.com>
+ *
+ *  This program is free software, you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY, without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program, if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _CX231XX_DIF_H
+#define _CX231XX_DIF_H
+
+#include "cx231xx-reg.h"
+
+struct dif_settings{
+	u32 if_freq;
+	u32 register_address;
+	u32 value;
+};
+
+static struct dif_settings Dif_set_array[] = {
+
+/*case 3000000:*/
+/* BEGIN - DIF BPF register values from 30_quant.dat*/
+{3000000, DIF_BPF_COEFF01,    0x00000002},
+{3000000, DIF_BPF_COEFF23,    0x00080012},
+{3000000, DIF_BPF_COEFF45,    0x001e0024},
+{3000000, DIF_BPF_COEFF67,    0x001bfff8},
+{3000000, DIF_BPF_COEFF89,    0xffb4ff50},
+{3000000, DIF_BPF_COEFF1011,  0xfed8fe68},
+{3000000, DIF_BPF_COEFF1213,  0xfe24fe34},
+{3000000, DIF_BPF_COEFF1415,  0xfebaffc7},
+{3000000, DIF_BPF_COEFF1617,  0x014d031f},
+{3000000, DIF_BPF_COEFF1819,  0x04f0065d},
+{3000000, DIF_BPF_COEFF2021,  0x07010688},
+{3000000, DIF_BPF_COEFF2223,  0x04c901d6},
+{3000000, DIF_BPF_COEFF2425,  0xfe00f9d3},
+{3000000, DIF_BPF_COEFF2627,  0xf600f342},
+{3000000, DIF_BPF_COEFF2829,  0xf235f337},
+{3000000, DIF_BPF_COEFF3031,  0xf64efb22},
+{3000000, DIF_BPF_COEFF3233,  0x0105070f},
+{3000000, DIF_BPF_COEFF3435,  0x0c460fce},
+{3000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 30_quant.dat*/
+
+
+/*case 3100000:*/
+/* BEGIN - DIF BPF register values from 31_quant.dat*/
+{3100000, DIF_BPF_COEFF01,    0x00000001},
+{3100000, DIF_BPF_COEFF23,    0x00070012},
+{3100000, DIF_BPF_COEFF45,    0x00220032},
+{3100000, DIF_BPF_COEFF67,    0x00370026},
+{3100000, DIF_BPF_COEFF89,    0xfff0ff91},
+{3100000, DIF_BPF_COEFF1011,  0xff0efe7c},
+{3100000, DIF_BPF_COEFF1213,  0xfe01fdcc},
+{3100000, DIF_BPF_COEFF1415,  0xfe0afedb},
+{3100000, DIF_BPF_COEFF1617,  0x00440224},
+{3100000, DIF_BPF_COEFF1819,  0x0434060c},
+{3100000, DIF_BPF_COEFF2021,  0x0738074e},
+{3100000, DIF_BPF_COEFF2223,  0x06090361},
+{3100000, DIF_BPF_COEFF2425,  0xff99fb39},
+{3100000, DIF_BPF_COEFF2627,  0xf6fef3b6},
+{3100000, DIF_BPF_COEFF2829,  0xf21af2a5},
+{3100000, DIF_BPF_COEFF3031,  0xf573fa33},
+{3100000, DIF_BPF_COEFF3233,  0x0034067d},
+{3100000, DIF_BPF_COEFF3435,  0x0bfb0fb9},
+{3100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 31_quant.dat*/
+
+
+/*case 3200000:*/
+/* BEGIN - DIF BPF register values from 32_quant.dat*/
+{3200000, DIF_BPF_COEFF01,    0x00000000},
+{3200000, DIF_BPF_COEFF23,    0x0004000e},
+{3200000, DIF_BPF_COEFF45,    0x00200038},
+{3200000, DIF_BPF_COEFF67,    0x004c004f},
+{3200000, DIF_BPF_COEFF89,    0x002fffdf},
+{3200000, DIF_BPF_COEFF1011,  0xff5cfeb6},
+{3200000, DIF_BPF_COEFF1213,  0xfe0dfd92},
+{3200000, DIF_BPF_COEFF1415,  0xfd7ffe03},
+{3200000, DIF_BPF_COEFF1617,  0xff36010a},
+{3200000, DIF_BPF_COEFF1819,  0x03410575},
+{3200000, DIF_BPF_COEFF2021,  0x072607d2},
+{3200000, DIF_BPF_COEFF2223,  0x071804d5},
+{3200000, DIF_BPF_COEFF2425,  0x0134fcb7},
+{3200000, DIF_BPF_COEFF2627,  0xf81ff451},
+{3200000, DIF_BPF_COEFF2829,  0xf223f22e},
+{3200000, DIF_BPF_COEFF3031,  0xf4a7f94b},
+{3200000, DIF_BPF_COEFF3233,  0xff6405e8},
+{3200000, DIF_BPF_COEFF3435,  0x0bae0fa4},
+{3200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 32_quant.dat*/
+
+
+/*case 3300000:*/
+/* BEGIN - DIF BPF register values from 33_quant.dat*/
+{3300000, DIF_BPF_COEFF01,    0x0000ffff},
+{3300000, DIF_BPF_COEFF23,    0x00000008},
+{3300000, DIF_BPF_COEFF45,    0x001a0036},
+{3300000, DIF_BPF_COEFF67,    0x0056006d},
+{3300000, DIF_BPF_COEFF89,    0x00670030},
+{3300000, DIF_BPF_COEFF1011,  0xffbdff10},
+{3300000, DIF_BPF_COEFF1213,  0xfe46fd8d},
+{3300000, DIF_BPF_COEFF1415,  0xfd25fd4f},
+{3300000, DIF_BPF_COEFF1617,  0xfe35ffe0},
+{3300000, DIF_BPF_COEFF1819,  0x0224049f},
+{3300000, DIF_BPF_COEFF2021,  0x06c9080e},
+{3300000, DIF_BPF_COEFF2223,  0x07ef0627},
+{3300000, DIF_BPF_COEFF2425,  0x02c9fe45},
+{3300000, DIF_BPF_COEFF2627,  0xf961f513},
+{3300000, DIF_BPF_COEFF2829,  0xf250f1d2},
+{3300000, DIF_BPF_COEFF3031,  0xf3ecf869},
+{3300000, DIF_BPF_COEFF3233,  0xfe930552},
+{3300000, DIF_BPF_COEFF3435,  0x0b5f0f8f},
+{3300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 33_quant.dat*/
+
+
+/*case 3400000:*/
+/* BEGIN - DIF BPF register values from 34_quant.dat*/
+{3400000, DIF_BPF_COEFF01,    0xfffffffe},
+{3400000, DIF_BPF_COEFF23,    0xfffd0001},
+{3400000, DIF_BPF_COEFF45,    0x000f002c},
+{3400000, DIF_BPF_COEFF67,    0x0054007d},
+{3400000, DIF_BPF_COEFF89,    0x0093007c},
+{3400000, DIF_BPF_COEFF1011,  0x0024ff82},
+{3400000, DIF_BPF_COEFF1213,  0xfea6fdbb},
+{3400000, DIF_BPF_COEFF1415,  0xfd03fcca},
+{3400000, DIF_BPF_COEFF1617,  0xfd51feb9},
+{3400000, DIF_BPF_COEFF1819,  0x00eb0392},
+{3400000, DIF_BPF_COEFF2021,  0x06270802},
+{3400000, DIF_BPF_COEFF2223,  0x08880750},
+{3400000, DIF_BPF_COEFF2425,  0x044dffdb},
+{3400000, DIF_BPF_COEFF2627,  0xfabdf5f8},
+{3400000, DIF_BPF_COEFF2829,  0xf2a0f193},
+{3400000, DIF_BPF_COEFF3031,  0xf342f78f},
+{3400000, DIF_BPF_COEFF3233,  0xfdc404b9},
+{3400000, DIF_BPF_COEFF3435,  0x0b0e0f78},
+{3400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 34_quant.dat*/
+
+
+/*case 3500000:*/
+/* BEGIN - DIF BPF register values from 35_quant.dat*/
+{3500000, DIF_BPF_COEFF01,    0xfffffffd},
+{3500000, DIF_BPF_COEFF23,    0xfffafff9},
+{3500000, DIF_BPF_COEFF45,    0x0002001b},
+{3500000, DIF_BPF_COEFF67,    0x0046007d},
+{3500000, DIF_BPF_COEFF89,    0x00ad00ba},
+{3500000, DIF_BPF_COEFF1011,  0x00870000},
+{3500000, DIF_BPF_COEFF1213,  0xff26fe1a},
+{3500000, DIF_BPF_COEFF1415,  0xfd1bfc7e},
+{3500000, DIF_BPF_COEFF1617,  0xfc99fda4},
+{3500000, DIF_BPF_COEFF1819,  0xffa5025c},
+{3500000, DIF_BPF_COEFF2021,  0x054507ad},
+{3500000, DIF_BPF_COEFF2223,  0x08dd0847},
+{3500000, DIF_BPF_COEFF2425,  0x05b80172},
+{3500000, DIF_BPF_COEFF2627,  0xfc2ef6ff},
+{3500000, DIF_BPF_COEFF2829,  0xf313f170},
+{3500000, DIF_BPF_COEFF3031,  0xf2abf6bd},
+{3500000, DIF_BPF_COEFF3233,  0xfcf6041f},
+{3500000, DIF_BPF_COEFF3435,  0x0abc0f61},
+{3500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 35_quant.dat*/
+
+
+/*case 3600000:*/
+/* BEGIN - DIF BPF register values from 36_quant.dat*/
+{3600000, DIF_BPF_COEFF01,    0xfffffffd},
+{3600000, DIF_BPF_COEFF23,    0xfff8fff3},
+{3600000, DIF_BPF_COEFF45,    0xfff50006},
+{3600000, DIF_BPF_COEFF67,    0x002f006c},
+{3600000, DIF_BPF_COEFF89,    0x00b200e3},
+{3600000, DIF_BPF_COEFF1011,  0x00dc007e},
+{3600000, DIF_BPF_COEFF1213,  0xffb9fea0},
+{3600000, DIF_BPF_COEFF1415,  0xfd6bfc71},
+{3600000, DIF_BPF_COEFF1617,  0xfc17fcb1},
+{3600000, DIF_BPF_COEFF1819,  0xfe65010b},
+{3600000, DIF_BPF_COEFF2021,  0x042d0713},
+{3600000, DIF_BPF_COEFF2223,  0x08ec0906},
+{3600000, DIF_BPF_COEFF2425,  0x07020302},
+{3600000, DIF_BPF_COEFF2627,  0xfdaff823},
+{3600000, DIF_BPF_COEFF2829,  0xf3a7f16a},
+{3600000, DIF_BPF_COEFF3031,  0xf228f5f5},
+{3600000, DIF_BPF_COEFF3233,  0xfc2a0384},
+{3600000, DIF_BPF_COEFF3435,  0x0a670f4a},
+{3600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 36_quant.dat*/
+
+
+/*case 3700000:*/
+/* BEGIN - DIF BPF register values from 37_quant.dat*/
+{3700000, DIF_BPF_COEFF01,    0x0000fffd},
+{3700000, DIF_BPF_COEFF23,    0xfff7ffef},
+{3700000, DIF_BPF_COEFF45,    0xffe9fff1},
+{3700000, DIF_BPF_COEFF67,    0x0010004d},
+{3700000, DIF_BPF_COEFF89,    0x00a100f2},
+{3700000, DIF_BPF_COEFF1011,  0x011a00f0},
+{3700000, DIF_BPF_COEFF1213,  0x0053ff44},
+{3700000, DIF_BPF_COEFF1415,  0xfdedfca2},
+{3700000, DIF_BPF_COEFF1617,  0xfbd3fbef},
+{3700000, DIF_BPF_COEFF1819,  0xfd39ffae},
+{3700000, DIF_BPF_COEFF2021,  0x02ea0638},
+{3700000, DIF_BPF_COEFF2223,  0x08b50987},
+{3700000, DIF_BPF_COEFF2425,  0x08230483},
+{3700000, DIF_BPF_COEFF2627,  0xff39f960},
+{3700000, DIF_BPF_COEFF2829,  0xf45bf180},
+{3700000, DIF_BPF_COEFF3031,  0xf1b8f537},
+{3700000, DIF_BPF_COEFF3233,  0xfb6102e7},
+{3700000, DIF_BPF_COEFF3435,  0x0a110f32},
+{3700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 37_quant.dat*/
+
+
+/*case 3800000:*/
+/* BEGIN - DIF BPF register values from 38_quant.dat*/
+{3800000, DIF_BPF_COEFF01,    0x0000fffe},
+{3800000, DIF_BPF_COEFF23,    0xfff9ffee},
+{3800000, DIF_BPF_COEFF45,    0xffe1ffdd},
+{3800000, DIF_BPF_COEFF67,    0xfff00024},
+{3800000, DIF_BPF_COEFF89,    0x007c00e5},
+{3800000, DIF_BPF_COEFF1011,  0x013a014a},
+{3800000, DIF_BPF_COEFF1213,  0x00e6fff8},
+{3800000, DIF_BPF_COEFF1415,  0xfe98fd0f},
+{3800000, DIF_BPF_COEFF1617,  0xfbd3fb67},
+{3800000, DIF_BPF_COEFF1819,  0xfc32fe54},
+{3800000, DIF_BPF_COEFF2021,  0x01880525},
+{3800000, DIF_BPF_COEFF2223,  0x083909c7},
+{3800000, DIF_BPF_COEFF2425,  0x091505ee},
+{3800000, DIF_BPF_COEFF2627,  0x00c7fab3},
+{3800000, DIF_BPF_COEFF2829,  0xf52df1b4},
+{3800000, DIF_BPF_COEFF3031,  0xf15df484},
+{3800000, DIF_BPF_COEFF3233,  0xfa9b0249},
+{3800000, DIF_BPF_COEFF3435,  0x09ba0f19},
+{3800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 38_quant.dat*/
+
+
+/*case 3900000:*/
+/* BEGIN - DIF BPF register values from 39_quant.dat*/
+{3900000, DIF_BPF_COEFF01,    0x00000000},
+{3900000, DIF_BPF_COEFF23,    0xfffbfff0},
+{3900000, DIF_BPF_COEFF45,    0xffdeffcf},
+{3900000, DIF_BPF_COEFF67,    0xffd1fff6},
+{3900000, DIF_BPF_COEFF89,    0x004800be},
+{3900000, DIF_BPF_COEFF1011,  0x01390184},
+{3900000, DIF_BPF_COEFF1213,  0x016300ac},
+{3900000, DIF_BPF_COEFF1415,  0xff5efdb1},
+{3900000, DIF_BPF_COEFF1617,  0xfc17fb23},
+{3900000, DIF_BPF_COEFF1819,  0xfb5cfd0d},
+{3900000, DIF_BPF_COEFF2021,  0x001703e4},
+{3900000, DIF_BPF_COEFF2223,  0x077b09c4},
+{3900000, DIF_BPF_COEFF2425,  0x09d2073c},
+{3900000, DIF_BPF_COEFF2627,  0x0251fc18},
+{3900000, DIF_BPF_COEFF2829,  0xf61cf203},
+{3900000, DIF_BPF_COEFF3031,  0xf118f3dc},
+{3900000, DIF_BPF_COEFF3233,  0xf9d801aa},
+{3900000, DIF_BPF_COEFF3435,  0x09600eff},
+{3900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 39_quant.dat*/
+
+
+/*case 4000000:*/
+/* BEGIN - DIF BPF register values from 40_quant.dat*/
+{4000000, DIF_BPF_COEFF01,    0x00000001},
+{4000000, DIF_BPF_COEFF23,    0xfffefff4},
+{4000000, DIF_BPF_COEFF45,    0xffe1ffc8},
+{4000000, DIF_BPF_COEFF67,    0xffbaffca},
+{4000000, DIF_BPF_COEFF89,    0x000b0082},
+{4000000, DIF_BPF_COEFF1011,  0x01170198},
+{4000000, DIF_BPF_COEFF1213,  0x01c10152},
+{4000000, DIF_BPF_COEFF1415,  0x0030fe7b},
+{4000000, DIF_BPF_COEFF1617,  0xfc99fb24},
+{4000000, DIF_BPF_COEFF1819,  0xfac3fbe9},
+{4000000, DIF_BPF_COEFF2021,  0xfea5027f},
+{4000000, DIF_BPF_COEFF2223,  0x0683097f},
+{4000000, DIF_BPF_COEFF2425,  0x0a560867},
+{4000000, DIF_BPF_COEFF2627,  0x03d2fd89},
+{4000000, DIF_BPF_COEFF2829,  0xf723f26f},
+{4000000, DIF_BPF_COEFF3031,  0xf0e8f341},
+{4000000, DIF_BPF_COEFF3233,  0xf919010a},
+{4000000, DIF_BPF_COEFF3435,  0x09060ee5},
+{4000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 40_quant.dat*/
+
+
+/*case 4100000:*/
+/* BEGIN - DIF BPF register values from 41_quant.dat*/
+{4100000, DIF_BPF_COEFF01,    0x00010002},
+{4100000, DIF_BPF_COEFF23,    0x0002fffb},
+{4100000, DIF_BPF_COEFF45,    0xffe8ffca},
+{4100000, DIF_BPF_COEFF67,    0xffacffa4},
+{4100000, DIF_BPF_COEFF89,    0xffcd0036},
+{4100000, DIF_BPF_COEFF1011,  0x00d70184},
+{4100000, DIF_BPF_COEFF1213,  0x01f601dc},
+{4100000, DIF_BPF_COEFF1415,  0x00ffff60},
+{4100000, DIF_BPF_COEFF1617,  0xfd51fb6d},
+{4100000, DIF_BPF_COEFF1819,  0xfa6efaf5},
+{4100000, DIF_BPF_COEFF2021,  0xfd410103},
+{4100000, DIF_BPF_COEFF2223,  0x055708f9},
+{4100000, DIF_BPF_COEFF2425,  0x0a9e0969},
+{4100000, DIF_BPF_COEFF2627,  0x0543ff02},
+{4100000, DIF_BPF_COEFF2829,  0xf842f2f5},
+{4100000, DIF_BPF_COEFF3031,  0xf0cef2b2},
+{4100000, DIF_BPF_COEFF3233,  0xf85e006b},
+{4100000, DIF_BPF_COEFF3435,  0x08aa0ecb},
+{4100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 41_quant.dat*/
+
+
+/*case 4200000:*/
+/* BEGIN - DIF BPF register values from 42_quant.dat*/
+{4200000, DIF_BPF_COEFF01,    0x00010003},
+{4200000, DIF_BPF_COEFF23,    0x00050003},
+{4200000, DIF_BPF_COEFF45,    0xfff3ffd3},
+{4200000, DIF_BPF_COEFF67,    0xffaaff8b},
+{4200000, DIF_BPF_COEFF89,    0xff95ffe5},
+{4200000, DIF_BPF_COEFF1011,  0x0080014a},
+{4200000, DIF_BPF_COEFF1213,  0x01fe023f},
+{4200000, DIF_BPF_COEFF1415,  0x01ba0050},
+{4200000, DIF_BPF_COEFF1617,  0xfe35fbf8},
+{4200000, DIF_BPF_COEFF1819,  0xfa62fa3b},
+{4200000, DIF_BPF_COEFF2021,  0xfbf9ff7e},
+{4200000, DIF_BPF_COEFF2223,  0x04010836},
+{4200000, DIF_BPF_COEFF2425,  0x0aa90a3d},
+{4200000, DIF_BPF_COEFF2627,  0x069f007f},
+{4200000, DIF_BPF_COEFF2829,  0xf975f395},
+{4200000, DIF_BPF_COEFF3031,  0xf0cbf231},
+{4200000, DIF_BPF_COEFF3233,  0xf7a9ffcb},
+{4200000, DIF_BPF_COEFF3435,  0x084c0eaf},
+{4200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 42_quant.dat*/
+
+
+/*case 4300000:*/
+/* BEGIN - DIF BPF register values from 43_quant.dat*/
+{4300000, DIF_BPF_COEFF01,    0x00010003},
+{4300000, DIF_BPF_COEFF23,    0x0008000a},
+{4300000, DIF_BPF_COEFF45,    0x0000ffe4},
+{4300000, DIF_BPF_COEFF67,    0xffb4ff81},
+{4300000, DIF_BPF_COEFF89,    0xff6aff96},
+{4300000, DIF_BPF_COEFF1011,  0x001c00f0},
+{4300000, DIF_BPF_COEFF1213,  0x01d70271},
+{4300000, DIF_BPF_COEFF1415,  0x0254013b},
+{4300000, DIF_BPF_COEFF1617,  0xff36fcbd},
+{4300000, DIF_BPF_COEFF1819,  0xfa9ff9c5},
+{4300000, DIF_BPF_COEFF2021,  0xfadbfdfe},
+{4300000, DIF_BPF_COEFF2223,  0x028c073b},
+{4300000, DIF_BPF_COEFF2425,  0x0a750adf},
+{4300000, DIF_BPF_COEFF2627,  0x07e101fa},
+{4300000, DIF_BPF_COEFF2829,  0xfab8f44e},
+{4300000, DIF_BPF_COEFF3031,  0xf0ddf1be},
+{4300000, DIF_BPF_COEFF3233,  0xf6f9ff2b},
+{4300000, DIF_BPF_COEFF3435,  0x07ed0e94},
+{4300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 43_quant.dat*/
+
+
+/*case 4400000:*/
+/* BEGIN - DIF BPF register values from 44_quant.dat*/
+{4400000, DIF_BPF_COEFF01,    0x00000003},
+{4400000, DIF_BPF_COEFF23,    0x0009000f},
+{4400000, DIF_BPF_COEFF45,    0x000efff8},
+{4400000, DIF_BPF_COEFF67,    0xffc9ff87},
+{4400000, DIF_BPF_COEFF89,    0xff52ff54},
+{4400000, DIF_BPF_COEFF1011,  0xffb5007e},
+{4400000, DIF_BPF_COEFF1213,  0x01860270},
+{4400000, DIF_BPF_COEFF1415,  0x02c00210},
+{4400000, DIF_BPF_COEFF1617,  0x0044fdb2},
+{4400000, DIF_BPF_COEFF1819,  0xfb22f997},
+{4400000, DIF_BPF_COEFF2021,  0xf9f2fc90},
+{4400000, DIF_BPF_COEFF2223,  0x0102060f},
+{4400000, DIF_BPF_COEFF2425,  0x0a050b4c},
+{4400000, DIF_BPF_COEFF2627,  0x0902036e},
+{4400000, DIF_BPF_COEFF2829,  0xfc0af51e},
+{4400000, DIF_BPF_COEFF3031,  0xf106f15a},
+{4400000, DIF_BPF_COEFF3233,  0xf64efe8b},
+{4400000, DIF_BPF_COEFF3435,  0x078d0e77},
+{4400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 44_quant.dat*/
+
+
+/*case 4500000:*/
+/* BEGIN - DIF BPF register values from 45_quant.dat*/
+{4500000, DIF_BPF_COEFF01,    0x00000002},
+{4500000, DIF_BPF_COEFF23,    0x00080012},
+{4500000, DIF_BPF_COEFF45,    0x0019000e},
+{4500000, DIF_BPF_COEFF67,    0xffe5ff9e},
+{4500000, DIF_BPF_COEFF89,    0xff4fff25},
+{4500000, DIF_BPF_COEFF1011,  0xff560000},
+{4500000, DIF_BPF_COEFF1213,  0x0112023b},
+{4500000, DIF_BPF_COEFF1415,  0x02f702c0},
+{4500000, DIF_BPF_COEFF1617,  0x014dfec8},
+{4500000, DIF_BPF_COEFF1819,  0xfbe5f9b3},
+{4500000, DIF_BPF_COEFF2021,  0xf947fb41},
+{4500000, DIF_BPF_COEFF2223,  0xff7004b9},
+{4500000, DIF_BPF_COEFF2425,  0x095a0b81},
+{4500000, DIF_BPF_COEFF2627,  0x0a0004d8},
+{4500000, DIF_BPF_COEFF2829,  0xfd65f603},
+{4500000, DIF_BPF_COEFF3031,  0xf144f104},
+{4500000, DIF_BPF_COEFF3233,  0xf5aafdec},
+{4500000, DIF_BPF_COEFF3435,  0x072b0e5a},
+{4500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 45_quant.dat*/
+
+
+/*case 4600000:*/
+/* BEGIN - DIF BPF register values from 46_quant.dat*/
+{4600000, DIF_BPF_COEFF01,    0x00000001},
+{4600000, DIF_BPF_COEFF23,    0x00060012},
+{4600000, DIF_BPF_COEFF45,    0x00200022},
+{4600000, DIF_BPF_COEFF67,    0x0005ffc1},
+{4600000, DIF_BPF_COEFF89,    0xff61ff10},
+{4600000, DIF_BPF_COEFF1011,  0xff09ff82},
+{4600000, DIF_BPF_COEFF1213,  0x008601d7},
+{4600000, DIF_BPF_COEFF1415,  0x02f50340},
+{4600000, DIF_BPF_COEFF1617,  0x0241fff0},
+{4600000, DIF_BPF_COEFF1819,  0xfcddfa19},
+{4600000, DIF_BPF_COEFF2021,  0xf8e2fa1e},
+{4600000, DIF_BPF_COEFF2223,  0xfde30343},
+{4600000, DIF_BPF_COEFF2425,  0x08790b7f},
+{4600000, DIF_BPF_COEFF2627,  0x0ad50631},
+{4600000, DIF_BPF_COEFF2829,  0xfec7f6fc},
+{4600000, DIF_BPF_COEFF3031,  0xf198f0bd},
+{4600000, DIF_BPF_COEFF3233,  0xf50dfd4e},
+{4600000, DIF_BPF_COEFF3435,  0x06c90e3d},
+{4600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 46_quant.dat*/
+
+
+/*case 4700000:*/
+/* BEGIN - DIF BPF register values from 47_quant.dat*/
+{4700000, DIF_BPF_COEFF01,    0x0000ffff},
+{4700000, DIF_BPF_COEFF23,    0x0003000f},
+{4700000, DIF_BPF_COEFF45,    0x00220030},
+{4700000, DIF_BPF_COEFF67,    0x0025ffed},
+{4700000, DIF_BPF_COEFF89,    0xff87ff15},
+{4700000, DIF_BPF_COEFF1011,  0xfed6ff10},
+{4700000, DIF_BPF_COEFF1213,  0xffed014c},
+{4700000, DIF_BPF_COEFF1415,  0x02b90386},
+{4700000, DIF_BPF_COEFF1617,  0x03110119},
+{4700000, DIF_BPF_COEFF1819,  0xfdfefac4},
+{4700000, DIF_BPF_COEFF2021,  0xf8c6f92f},
+{4700000, DIF_BPF_COEFF2223,  0xfc6701b7},
+{4700000, DIF_BPF_COEFF2425,  0x07670b44},
+{4700000, DIF_BPF_COEFF2627,  0x0b7e0776},
+{4700000, DIF_BPF_COEFF2829,  0x002df807},
+{4700000, DIF_BPF_COEFF3031,  0xf200f086},
+{4700000, DIF_BPF_COEFF3233,  0xf477fcb1},
+{4700000, DIF_BPF_COEFF3435,  0x06650e1e},
+{4700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 47_quant.dat*/
+
+
+/*case 4800000:*/
+/* BEGIN - DIF BPF register values from 48_quant.dat*/
+{4800000, DIF_BPF_COEFF01,    0xfffffffe},
+{4800000, DIF_BPF_COEFF23,    0xffff0009},
+{4800000, DIF_BPF_COEFF45,    0x001e0038},
+{4800000, DIF_BPF_COEFF67,    0x003f001b},
+{4800000, DIF_BPF_COEFF89,    0xffbcff36},
+{4800000, DIF_BPF_COEFF1011,  0xfec2feb6},
+{4800000, DIF_BPF_COEFF1213,  0xff5600a5},
+{4800000, DIF_BPF_COEFF1415,  0x0248038d},
+{4800000, DIF_BPF_COEFF1617,  0x03b00232},
+{4800000, DIF_BPF_COEFF1819,  0xff39fbab},
+{4800000, DIF_BPF_COEFF2021,  0xf8f4f87f},
+{4800000, DIF_BPF_COEFF2223,  0xfb060020},
+{4800000, DIF_BPF_COEFF2425,  0x062a0ad2},
+{4800000, DIF_BPF_COEFF2627,  0x0bf908a3},
+{4800000, DIF_BPF_COEFF2829,  0x0192f922},
+{4800000, DIF_BPF_COEFF3031,  0xf27df05e},
+{4800000, DIF_BPF_COEFF3233,  0xf3e8fc14},
+{4800000, DIF_BPF_COEFF3435,  0x06000e00},
+{4800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 48_quant.dat*/
+
+
+/*case 4900000:*/
+/* BEGIN - DIF BPF register values from 49_quant.dat*/
+{4900000, DIF_BPF_COEFF01,    0xfffffffd},
+{4900000, DIF_BPF_COEFF23,    0xfffc0002},
+{4900000, DIF_BPF_COEFF45,    0x00160037},
+{4900000, DIF_BPF_COEFF67,    0x00510046},
+{4900000, DIF_BPF_COEFF89,    0xfff9ff6d},
+{4900000, DIF_BPF_COEFF1011,  0xfed0fe7c},
+{4900000, DIF_BPF_COEFF1213,  0xfecefff0},
+{4900000, DIF_BPF_COEFF1415,  0x01aa0356},
+{4900000, DIF_BPF_COEFF1617,  0x0413032b},
+{4900000, DIF_BPF_COEFF1819,  0x007ffcc5},
+{4900000, DIF_BPF_COEFF2021,  0xf96cf812},
+{4900000, DIF_BPF_COEFF2223,  0xf9cefe87},
+{4900000, DIF_BPF_COEFF2425,  0x04c90a2c},
+{4900000, DIF_BPF_COEFF2627,  0x0c4309b4},
+{4900000, DIF_BPF_COEFF2829,  0x02f3fa4a},
+{4900000, DIF_BPF_COEFF3031,  0xf30ef046},
+{4900000, DIF_BPF_COEFF3233,  0xf361fb7a},
+{4900000, DIF_BPF_COEFF3435,  0x059b0de0},
+{4900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 49_quant.dat*/
+
+
+/*case 5000000:*/
+/* BEGIN - DIF BPF register values from 50_quant.dat*/
+{5000000, DIF_BPF_COEFF01,    0xfffffffd},
+{5000000, DIF_BPF_COEFF23,    0xfff9fffa},
+{5000000, DIF_BPF_COEFF45,    0x000a002d},
+{5000000, DIF_BPF_COEFF67,    0x00570067},
+{5000000, DIF_BPF_COEFF89,    0x0037ffb5},
+{5000000, DIF_BPF_COEFF1011,  0xfefffe68},
+{5000000, DIF_BPF_COEFF1213,  0xfe62ff3d},
+{5000000, DIF_BPF_COEFF1415,  0x00ec02e3},
+{5000000, DIF_BPF_COEFF1617,  0x043503f6},
+{5000000, DIF_BPF_COEFF1819,  0x01befe05},
+{5000000, DIF_BPF_COEFF2021,  0xfa27f7ee},
+{5000000, DIF_BPF_COEFF2223,  0xf8c6fcf8},
+{5000000, DIF_BPF_COEFF2425,  0x034c0954},
+{5000000, DIF_BPF_COEFF2627,  0x0c5c0aa4},
+{5000000, DIF_BPF_COEFF2829,  0x044cfb7e},
+{5000000, DIF_BPF_COEFF3031,  0xf3b1f03f},
+{5000000, DIF_BPF_COEFF3233,  0xf2e2fae1},
+{5000000, DIF_BPF_COEFF3435,  0x05340dc0},
+{5000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 50_quant.dat*/
+
+
+/*case 5100000:*/
+/* BEGIN - DIF BPF register values from 51_quant.dat*/
+{5100000, DIF_BPF_COEFF01,    0x0000fffd},
+{5100000, DIF_BPF_COEFF23,    0xfff8fff4},
+{5100000, DIF_BPF_COEFF45,    0xfffd001e},
+{5100000, DIF_BPF_COEFF67,    0x0051007b},
+{5100000, DIF_BPF_COEFF89,    0x006e0006},
+{5100000, DIF_BPF_COEFF1011,  0xff48fe7c},
+{5100000, DIF_BPF_COEFF1213,  0xfe1bfe9a},
+{5100000, DIF_BPF_COEFF1415,  0x001d023e},
+{5100000, DIF_BPF_COEFF1617,  0x04130488},
+{5100000, DIF_BPF_COEFF1819,  0x02e6ff5b},
+{5100000, DIF_BPF_COEFF2021,  0xfb1ef812},
+{5100000, DIF_BPF_COEFF2223,  0xf7f7fb7f},
+{5100000, DIF_BPF_COEFF2425,  0x01bc084e},
+{5100000, DIF_BPF_COEFF2627,  0x0c430b72},
+{5100000, DIF_BPF_COEFF2829,  0x059afcba},
+{5100000, DIF_BPF_COEFF3031,  0xf467f046},
+{5100000, DIF_BPF_COEFF3233,  0xf26cfa4a},
+{5100000, DIF_BPF_COEFF3435,  0x04cd0da0},
+{5100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 51_quant.dat*/
+
+
+/*case 5200000:*/
+/* BEGIN - DIF BPF register values from 52_quant.dat*/
+{5200000, DIF_BPF_COEFF01,    0x0000fffe},
+{5200000, DIF_BPF_COEFF23,    0xfff8ffef},
+{5200000, DIF_BPF_COEFF45,    0xfff00009},
+{5200000, DIF_BPF_COEFF67,    0x003f007f},
+{5200000, DIF_BPF_COEFF89,    0x00980056},
+{5200000, DIF_BPF_COEFF1011,  0xffa5feb6},
+{5200000, DIF_BPF_COEFF1213,  0xfe00fe15},
+{5200000, DIF_BPF_COEFF1415,  0xff4b0170},
+{5200000, DIF_BPF_COEFF1617,  0x03b004d7},
+{5200000, DIF_BPF_COEFF1819,  0x03e800b9},
+{5200000, DIF_BPF_COEFF2021,  0xfc48f87f},
+{5200000, DIF_BPF_COEFF2223,  0xf768fa23},
+{5200000, DIF_BPF_COEFF2425,  0x0022071f},
+{5200000, DIF_BPF_COEFF2627,  0x0bf90c1b},
+{5200000, DIF_BPF_COEFF2829,  0x06dafdfd},
+{5200000, DIF_BPF_COEFF3031,  0xf52df05e},
+{5200000, DIF_BPF_COEFF3233,  0xf1fef9b5},
+{5200000, DIF_BPF_COEFF3435,  0x04640d7f},
+{5200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 52_quant.dat*/
+
+
+/*case 5300000:*/
+/* BEGIN - DIF BPF register values from 53_quant.dat*/
+{5300000, DIF_BPF_COEFF01,    0x0000ffff},
+{5300000, DIF_BPF_COEFF23,    0xfff9ffee},
+{5300000, DIF_BPF_COEFF45,    0xffe6fff3},
+{5300000, DIF_BPF_COEFF67,    0x00250072},
+{5300000, DIF_BPF_COEFF89,    0x00af009c},
+{5300000, DIF_BPF_COEFF1011,  0x000cff10},
+{5300000, DIF_BPF_COEFF1213,  0xfe13fdb8},
+{5300000, DIF_BPF_COEFF1415,  0xfe870089},
+{5300000, DIF_BPF_COEFF1617,  0x031104e1},
+{5300000, DIF_BPF_COEFF1819,  0x04b8020f},
+{5300000, DIF_BPF_COEFF2021,  0xfd98f92f},
+{5300000, DIF_BPF_COEFF2223,  0xf71df8f0},
+{5300000, DIF_BPF_COEFF2425,  0xfe8805ce},
+{5300000, DIF_BPF_COEFF2627,  0x0b7e0c9c},
+{5300000, DIF_BPF_COEFF2829,  0x0808ff44},
+{5300000, DIF_BPF_COEFF3031,  0xf603f086},
+{5300000, DIF_BPF_COEFF3233,  0xf19af922},
+{5300000, DIF_BPF_COEFF3435,  0x03fb0d5e},
+{5300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 53_quant.dat*/
+
+
+/*case 5400000:*/
+/* BEGIN - DIF BPF register values from 54_quant.dat*/
+{5400000, DIF_BPF_COEFF01,    0x00000001},
+{5400000, DIF_BPF_COEFF23,    0xfffcffef},
+{5400000, DIF_BPF_COEFF45,    0xffe0ffe0},
+{5400000, DIF_BPF_COEFF67,    0x00050056},
+{5400000, DIF_BPF_COEFF89,    0x00b000d1},
+{5400000, DIF_BPF_COEFF1011,  0x0071ff82},
+{5400000, DIF_BPF_COEFF1213,  0xfe53fd8c},
+{5400000, DIF_BPF_COEFF1415,  0xfddfff99},
+{5400000, DIF_BPF_COEFF1617,  0x024104a3},
+{5400000, DIF_BPF_COEFF1819,  0x054a034d},
+{5400000, DIF_BPF_COEFF2021,  0xff01fa1e},
+{5400000, DIF_BPF_COEFF2223,  0xf717f7ed},
+{5400000, DIF_BPF_COEFF2425,  0xfcf50461},
+{5400000, DIF_BPF_COEFF2627,  0x0ad50cf4},
+{5400000, DIF_BPF_COEFF2829,  0x0921008d},
+{5400000, DIF_BPF_COEFF3031,  0xf6e7f0bd},
+{5400000, DIF_BPF_COEFF3233,  0xf13ff891},
+{5400000, DIF_BPF_COEFF3435,  0x03920d3b},
+{5400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 54_quant.dat*/
+
+
+/*case 5500000:*/
+/* BEGIN - DIF BPF register values from 55_quant.dat*/
+{5500000, DIF_BPF_COEFF01,    0x00010002},
+{5500000, DIF_BPF_COEFF23,    0xfffffff3},
+{5500000, DIF_BPF_COEFF45,    0xffdeffd1},
+{5500000, DIF_BPF_COEFF67,    0xffe5002f},
+{5500000, DIF_BPF_COEFF89,    0x009c00ed},
+{5500000, DIF_BPF_COEFF1011,  0x00cb0000},
+{5500000, DIF_BPF_COEFF1213,  0xfebafd94},
+{5500000, DIF_BPF_COEFF1415,  0xfd61feb0},
+{5500000, DIF_BPF_COEFF1617,  0x014d0422},
+{5500000, DIF_BPF_COEFF1819,  0x05970464},
+{5500000, DIF_BPF_COEFF2021,  0x0074fb41},
+{5500000, DIF_BPF_COEFF2223,  0xf759f721},
+{5500000, DIF_BPF_COEFF2425,  0xfb7502de},
+{5500000, DIF_BPF_COEFF2627,  0x0a000d21},
+{5500000, DIF_BPF_COEFF2829,  0x0a2201d4},
+{5500000, DIF_BPF_COEFF3031,  0xf7d9f104},
+{5500000, DIF_BPF_COEFF3233,  0xf0edf804},
+{5500000, DIF_BPF_COEFF3435,  0x03280d19},
+{5500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 55_quant.dat*/
+
+
+/*case 5600000:*/
+/* BEGIN - DIF BPF register values from 56_quant.dat*/
+{5600000, DIF_BPF_COEFF01,    0x00010003},
+{5600000, DIF_BPF_COEFF23,    0x0003fffa},
+{5600000, DIF_BPF_COEFF45,    0xffe3ffc9},
+{5600000, DIF_BPF_COEFF67,    0xffc90002},
+{5600000, DIF_BPF_COEFF89,    0x007500ef},
+{5600000, DIF_BPF_COEFF1011,  0x010e007e},
+{5600000, DIF_BPF_COEFF1213,  0xff3dfdcf},
+{5600000, DIF_BPF_COEFF1415,  0xfd16fddd},
+{5600000, DIF_BPF_COEFF1617,  0x00440365},
+{5600000, DIF_BPF_COEFF1819,  0x059b0548},
+{5600000, DIF_BPF_COEFF2021,  0x01e3fc90},
+{5600000, DIF_BPF_COEFF2223,  0xf7dff691},
+{5600000, DIF_BPF_COEFF2425,  0xfa0f014d},
+{5600000, DIF_BPF_COEFF2627,  0x09020d23},
+{5600000, DIF_BPF_COEFF2829,  0x0b0a0318},
+{5600000, DIF_BPF_COEFF3031,  0xf8d7f15a},
+{5600000, DIF_BPF_COEFF3233,  0xf0a5f779},
+{5600000, DIF_BPF_COEFF3435,  0x02bd0cf6},
+{5600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 56_quant.dat*/
+
+
+/*case 5700000:*/
+/* BEGIN - DIF BPF register values from 57_quant.dat*/
+{5700000, DIF_BPF_COEFF01,    0x00010003},
+{5700000, DIF_BPF_COEFF23,    0x00060001},
+{5700000, DIF_BPF_COEFF45,    0xffecffc9},
+{5700000, DIF_BPF_COEFF67,    0xffb4ffd4},
+{5700000, DIF_BPF_COEFF89,    0x004000d5},
+{5700000, DIF_BPF_COEFF1011,  0x013600f0},
+{5700000, DIF_BPF_COEFF1213,  0xffd3fe39},
+{5700000, DIF_BPF_COEFF1415,  0xfd04fd31},
+{5700000, DIF_BPF_COEFF1617,  0xff360277},
+{5700000, DIF_BPF_COEFF1819,  0x055605ef},
+{5700000, DIF_BPF_COEFF2021,  0x033efdfe},
+{5700000, DIF_BPF_COEFF2223,  0xf8a5f642},
+{5700000, DIF_BPF_COEFF2425,  0xf8cbffb6},
+{5700000, DIF_BPF_COEFF2627,  0x07e10cfb},
+{5700000, DIF_BPF_COEFF2829,  0x0bd50456},
+{5700000, DIF_BPF_COEFF3031,  0xf9dff1be},
+{5700000, DIF_BPF_COEFF3233,  0xf067f6f2},
+{5700000, DIF_BPF_COEFF3435,  0x02520cd2},
+{5700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 57_quant.dat*/
+
+
+/*case 5800000:*/
+/* BEGIN - DIF BPF register values from 58_quant.dat*/
+{5800000, DIF_BPF_COEFF01,    0x00000003},
+{5800000, DIF_BPF_COEFF23,    0x00080009},
+{5800000, DIF_BPF_COEFF45,    0xfff8ffd2},
+{5800000, DIF_BPF_COEFF67,    0xffaaffac},
+{5800000, DIF_BPF_COEFF89,    0x000200a3},
+{5800000, DIF_BPF_COEFF1011,  0x013c014a},
+{5800000, DIF_BPF_COEFF1213,  0x006dfec9},
+{5800000, DIF_BPF_COEFF1415,  0xfd2bfcb7},
+{5800000, DIF_BPF_COEFF1617,  0xfe350165},
+{5800000, DIF_BPF_COEFF1819,  0x04cb0651},
+{5800000, DIF_BPF_COEFF2021,  0x0477ff7e},
+{5800000, DIF_BPF_COEFF2223,  0xf9a5f635},
+{5800000, DIF_BPF_COEFF2425,  0xf7b1fe20},
+{5800000, DIF_BPF_COEFF2627,  0x069f0ca8},
+{5800000, DIF_BPF_COEFF2829,  0x0c81058b},
+{5800000, DIF_BPF_COEFF3031,  0xfaf0f231},
+{5800000, DIF_BPF_COEFF3233,  0xf033f66d},
+{5800000, DIF_BPF_COEFF3435,  0x01e60cae},
+{5800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 58_quant.dat*/
+
+
+/*case 5900000:*/
+/* BEGIN - DIF BPF register values from 59_quant.dat*/
+{5900000, DIF_BPF_COEFF01,    0x00000002},
+{5900000, DIF_BPF_COEFF23,    0x0009000e},
+{5900000, DIF_BPF_COEFF45,    0x0005ffe1},
+{5900000, DIF_BPF_COEFF67,    0xffacff90},
+{5900000, DIF_BPF_COEFF89,    0xffc5005f},
+{5900000, DIF_BPF_COEFF1011,  0x01210184},
+{5900000, DIF_BPF_COEFF1213,  0x00fcff72},
+{5900000, DIF_BPF_COEFF1415,  0xfd8afc77},
+{5900000, DIF_BPF_COEFF1617,  0xfd51003f},
+{5900000, DIF_BPF_COEFF1819,  0x04020669},
+{5900000, DIF_BPF_COEFF2021,  0x05830103},
+{5900000, DIF_BPF_COEFF2223,  0xfad7f66b},
+{5900000, DIF_BPF_COEFF2425,  0xf6c8fc93},
+{5900000, DIF_BPF_COEFF2627,  0x05430c2b},
+{5900000, DIF_BPF_COEFF2829,  0x0d0d06b5},
+{5900000, DIF_BPF_COEFF3031,  0xfc08f2b2},
+{5900000, DIF_BPF_COEFF3233,  0xf00af5ec},
+{5900000, DIF_BPF_COEFF3435,  0x017b0c89},
+{5900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 59_quant.dat*/
+
+
+/*case 6000000:*/
+/* BEGIN - DIF BPF register values from 60_quant.dat*/
+{6000000, DIF_BPF_COEFF01,    0x00000001},
+{6000000, DIF_BPF_COEFF23,    0x00070012},
+{6000000, DIF_BPF_COEFF45,    0x0012fff5},
+{6000000, DIF_BPF_COEFF67,    0xffbaff82},
+{6000000, DIF_BPF_COEFF89,    0xff8e000f},
+{6000000, DIF_BPF_COEFF1011,  0x00e80198},
+{6000000, DIF_BPF_COEFF1213,  0x01750028},
+{6000000, DIF_BPF_COEFF1415,  0xfe18fc75},
+{6000000, DIF_BPF_COEFF1617,  0xfc99ff15},
+{6000000, DIF_BPF_COEFF1819,  0x03050636},
+{6000000, DIF_BPF_COEFF2021,  0x0656027f},
+{6000000, DIF_BPF_COEFF2223,  0xfc32f6e2},
+{6000000, DIF_BPF_COEFF2425,  0xf614fb17},
+{6000000, DIF_BPF_COEFF2627,  0x03d20b87},
+{6000000, DIF_BPF_COEFF2829,  0x0d7707d2},
+{6000000, DIF_BPF_COEFF3031,  0xfd26f341},
+{6000000, DIF_BPF_COEFF3233,  0xefeaf56f},
+{6000000, DIF_BPF_COEFF3435,  0x010f0c64},
+{6000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 60_quant.dat*/
+
+
+/*case 6100000:*/
+/* BEGIN - DIF BPF register values from 61_quant.dat*/
+{6100000, DIF_BPF_COEFF01,    0xffff0000},
+{6100000, DIF_BPF_COEFF23,    0x00050012},
+{6100000, DIF_BPF_COEFF45,    0x001c000b},
+{6100000, DIF_BPF_COEFF67,    0xffd1ff84},
+{6100000, DIF_BPF_COEFF89,    0xff66ffbe},
+{6100000, DIF_BPF_COEFF1011,  0x00960184},
+{6100000, DIF_BPF_COEFF1213,  0x01cd00da},
+{6100000, DIF_BPF_COEFF1415,  0xfeccfcb2},
+{6100000, DIF_BPF_COEFF1617,  0xfc17fdf9},
+{6100000, DIF_BPF_COEFF1819,  0x01e005bc},
+{6100000, DIF_BPF_COEFF2021,  0x06e703e4},
+{6100000, DIF_BPF_COEFF2223,  0xfdabf798},
+{6100000, DIF_BPF_COEFF2425,  0xf599f9b3},
+{6100000, DIF_BPF_COEFF2627,  0x02510abd},
+{6100000, DIF_BPF_COEFF2829,  0x0dbf08df},
+{6100000, DIF_BPF_COEFF3031,  0xfe48f3dc},
+{6100000, DIF_BPF_COEFF3233,  0xefd5f4f6},
+{6100000, DIF_BPF_COEFF3435,  0x00a20c3e},
+{6100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 61_quant.dat*/
+
+
+/*case 6200000:*/
+/* BEGIN - DIF BPF register values from 62_quant.dat*/
+{6200000, DIF_BPF_COEFF01,    0xfffffffe},
+{6200000, DIF_BPF_COEFF23,    0x0002000f},
+{6200000, DIF_BPF_COEFF45,    0x0021001f},
+{6200000, DIF_BPF_COEFF67,    0xfff0ff97},
+{6200000, DIF_BPF_COEFF89,    0xff50ff74},
+{6200000, DIF_BPF_COEFF1011,  0x0034014a},
+{6200000, DIF_BPF_COEFF1213,  0x01fa0179},
+{6200000, DIF_BPF_COEFF1415,  0xff97fd2a},
+{6200000, DIF_BPF_COEFF1617,  0xfbd3fcfa},
+{6200000, DIF_BPF_COEFF1819,  0x00a304fe},
+{6200000, DIF_BPF_COEFF2021,  0x07310525},
+{6200000, DIF_BPF_COEFF2223,  0xff37f886},
+{6200000, DIF_BPF_COEFF2425,  0xf55cf86e},
+{6200000, DIF_BPF_COEFF2627,  0x00c709d0},
+{6200000, DIF_BPF_COEFF2829,  0x0de209db},
+{6200000, DIF_BPF_COEFF3031,  0xff6df484},
+{6200000, DIF_BPF_COEFF3233,  0xefcbf481},
+{6200000, DIF_BPF_COEFF3435,  0x00360c18},
+{6200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 62_quant.dat*/
+
+
+/*case 6300000:*/
+/* BEGIN - DIF BPF register values from 63_quant.dat*/
+{6300000, DIF_BPF_COEFF01,    0xfffffffd},
+{6300000, DIF_BPF_COEFF23,    0xfffe000a},
+{6300000, DIF_BPF_COEFF45,    0x0021002f},
+{6300000, DIF_BPF_COEFF67,    0x0010ffb8},
+{6300000, DIF_BPF_COEFF89,    0xff50ff3b},
+{6300000, DIF_BPF_COEFF1011,  0xffcc00f0},
+{6300000, DIF_BPF_COEFF1213,  0x01fa01fa},
+{6300000, DIF_BPF_COEFF1415,  0x0069fdd4},
+{6300000, DIF_BPF_COEFF1617,  0xfbd3fc26},
+{6300000, DIF_BPF_COEFF1819,  0xff5d0407},
+{6300000, DIF_BPF_COEFF2021,  0x07310638},
+{6300000, DIF_BPF_COEFF2223,  0x00c9f9a8},
+{6300000, DIF_BPF_COEFF2425,  0xf55cf74e},
+{6300000, DIF_BPF_COEFF2627,  0xff3908c3},
+{6300000, DIF_BPF_COEFF2829,  0x0de20ac3},
+{6300000, DIF_BPF_COEFF3031,  0x0093f537},
+{6300000, DIF_BPF_COEFF3233,  0xefcbf410},
+{6300000, DIF_BPF_COEFF3435,  0xffca0bf2},
+{6300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 63_quant.dat*/
+
+
+/*case 6400000:*/
+/* BEGIN - DIF BPF register values from 64_quant.dat*/
+{6400000, DIF_BPF_COEFF01,    0xfffffffd},
+{6400000, DIF_BPF_COEFF23,    0xfffb0003},
+{6400000, DIF_BPF_COEFF45,    0x001c0037},
+{6400000, DIF_BPF_COEFF67,    0x002fffe2},
+{6400000, DIF_BPF_COEFF89,    0xff66ff17},
+{6400000, DIF_BPF_COEFF1011,  0xff6a007e},
+{6400000, DIF_BPF_COEFF1213,  0x01cd0251},
+{6400000, DIF_BPF_COEFF1415,  0x0134fea5},
+{6400000, DIF_BPF_COEFF1617,  0xfc17fb8b},
+{6400000, DIF_BPF_COEFF1819,  0xfe2002e0},
+{6400000, DIF_BPF_COEFF2021,  0x06e70713},
+{6400000, DIF_BPF_COEFF2223,  0x0255faf5},
+{6400000, DIF_BPF_COEFF2425,  0xf599f658},
+{6400000, DIF_BPF_COEFF2627,  0xfdaf0799},
+{6400000, DIF_BPF_COEFF2829,  0x0dbf0b96},
+{6400000, DIF_BPF_COEFF3031,  0x01b8f5f5},
+{6400000, DIF_BPF_COEFF3233,  0xefd5f3a3},
+{6400000, DIF_BPF_COEFF3435,  0xff5e0bca},
+{6400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 64_quant.dat*/
+
+
+/*case 6500000:*/
+/* BEGIN - DIF BPF register values from 65_quant.dat*/
+{6500000, DIF_BPF_COEFF01,    0x0000fffd},
+{6500000, DIF_BPF_COEFF23,    0xfff9fffb},
+{6500000, DIF_BPF_COEFF45,    0x00120037},
+{6500000, DIF_BPF_COEFF67,    0x00460010},
+{6500000, DIF_BPF_COEFF89,    0xff8eff0f},
+{6500000, DIF_BPF_COEFF1011,  0xff180000},
+{6500000, DIF_BPF_COEFF1213,  0x01750276},
+{6500000, DIF_BPF_COEFF1415,  0x01e8ff8d},
+{6500000, DIF_BPF_COEFF1617,  0xfc99fb31},
+{6500000, DIF_BPF_COEFF1819,  0xfcfb0198},
+{6500000, DIF_BPF_COEFF2021,  0x065607ad},
+{6500000, DIF_BPF_COEFF2223,  0x03cefc64},
+{6500000, DIF_BPF_COEFF2425,  0xf614f592},
+{6500000, DIF_BPF_COEFF2627,  0xfc2e0656},
+{6500000, DIF_BPF_COEFF2829,  0x0d770c52},
+{6500000, DIF_BPF_COEFF3031,  0x02daf6bd},
+{6500000, DIF_BPF_COEFF3233,  0xefeaf33b},
+{6500000, DIF_BPF_COEFF3435,  0xfef10ba3},
+{6500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 65_quant.dat*/
+
+
+/*case 6600000:*/
+/* BEGIN - DIF BPF register values from 66_quant.dat*/
+{6600000, DIF_BPF_COEFF01,    0x0000fffe},
+{6600000, DIF_BPF_COEFF23,    0xfff7fff5},
+{6600000, DIF_BPF_COEFF45,    0x0005002f},
+{6600000, DIF_BPF_COEFF67,    0x0054003c},
+{6600000, DIF_BPF_COEFF89,    0xffc5ff22},
+{6600000, DIF_BPF_COEFF1011,  0xfedfff82},
+{6600000, DIF_BPF_COEFF1213,  0x00fc0267},
+{6600000, DIF_BPF_COEFF1415,  0x0276007e},
+{6600000, DIF_BPF_COEFF1617,  0xfd51fb1c},
+{6600000, DIF_BPF_COEFF1819,  0xfbfe003e},
+{6600000, DIF_BPF_COEFF2021,  0x05830802},
+{6600000, DIF_BPF_COEFF2223,  0x0529fdec},
+{6600000, DIF_BPF_COEFF2425,  0xf6c8f4fe},
+{6600000, DIF_BPF_COEFF2627,  0xfabd04ff},
+{6600000, DIF_BPF_COEFF2829,  0x0d0d0cf6},
+{6600000, DIF_BPF_COEFF3031,  0x03f8f78f},
+{6600000, DIF_BPF_COEFF3233,  0xf00af2d7},
+{6600000, DIF_BPF_COEFF3435,  0xfe850b7b},
+{6600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 66_quant.dat*/
+
+
+/*case 6700000:*/
+/* BEGIN - DIF BPF register values from 67_quant.dat*/
+{6700000, DIF_BPF_COEFF01,    0x0000ffff},
+{6700000, DIF_BPF_COEFF23,    0xfff8fff0},
+{6700000, DIF_BPF_COEFF45,    0xfff80020},
+{6700000, DIF_BPF_COEFF67,    0x00560060},
+{6700000, DIF_BPF_COEFF89,    0x0002ff4e},
+{6700000, DIF_BPF_COEFF1011,  0xfec4ff10},
+{6700000, DIF_BPF_COEFF1213,  0x006d0225},
+{6700000, DIF_BPF_COEFF1415,  0x02d50166},
+{6700000, DIF_BPF_COEFF1617,  0xfe35fb4e},
+{6700000, DIF_BPF_COEFF1819,  0xfb35fee1},
+{6700000, DIF_BPF_COEFF2021,  0x0477080e},
+{6700000, DIF_BPF_COEFF2223,  0x065bff82},
+{6700000, DIF_BPF_COEFF2425,  0xf7b1f4a0},
+{6700000, DIF_BPF_COEFF2627,  0xf9610397},
+{6700000, DIF_BPF_COEFF2829,  0x0c810d80},
+{6700000, DIF_BPF_COEFF3031,  0x0510f869},
+{6700000, DIF_BPF_COEFF3233,  0xf033f278},
+{6700000, DIF_BPF_COEFF3435,  0xfe1a0b52},
+{6700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 67_quant.dat*/
+
+
+/*case 6800000:*/
+/* BEGIN - DIF BPF register values from 68_quant.dat*/
+{6800000, DIF_BPF_COEFF01,    0x00010000},
+{6800000, DIF_BPF_COEFF23,    0xfffaffee},
+{6800000, DIF_BPF_COEFF45,    0xffec000c},
+{6800000, DIF_BPF_COEFF67,    0x004c0078},
+{6800000, DIF_BPF_COEFF89,    0x0040ff8e},
+{6800000, DIF_BPF_COEFF1011,  0xfecafeb6},
+{6800000, DIF_BPF_COEFF1213,  0xffd301b6},
+{6800000, DIF_BPF_COEFF1415,  0x02fc0235},
+{6800000, DIF_BPF_COEFF1617,  0xff36fbc5},
+{6800000, DIF_BPF_COEFF1819,  0xfaaafd90},
+{6800000, DIF_BPF_COEFF2021,  0x033e07d2},
+{6800000, DIF_BPF_COEFF2223,  0x075b011b},
+{6800000, DIF_BPF_COEFF2425,  0xf8cbf47a},
+{6800000, DIF_BPF_COEFF2627,  0xf81f0224},
+{6800000, DIF_BPF_COEFF2829,  0x0bd50def},
+{6800000, DIF_BPF_COEFF3031,  0x0621f94b},
+{6800000, DIF_BPF_COEFF3233,  0xf067f21e},
+{6800000, DIF_BPF_COEFF3435,  0xfdae0b29},
+{6800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 68_quant.dat*/
+
+
+/*case 6900000:*/
+/* BEGIN - DIF BPF register values from 69_quant.dat*/
+{6900000, DIF_BPF_COEFF01,    0x00010001},
+{6900000, DIF_BPF_COEFF23,    0xfffdffef},
+{6900000, DIF_BPF_COEFF45,    0xffe3fff6},
+{6900000, DIF_BPF_COEFF67,    0x0037007f},
+{6900000, DIF_BPF_COEFF89,    0x0075ffdc},
+{6900000, DIF_BPF_COEFF1011,  0xfef2fe7c},
+{6900000, DIF_BPF_COEFF1213,  0xff3d0122},
+{6900000, DIF_BPF_COEFF1415,  0x02ea02dd},
+{6900000, DIF_BPF_COEFF1617,  0x0044fc79},
+{6900000, DIF_BPF_COEFF1819,  0xfa65fc5d},
+{6900000, DIF_BPF_COEFF2021,  0x01e3074e},
+{6900000, DIF_BPF_COEFF2223,  0x082102ad},
+{6900000, DIF_BPF_COEFF2425,  0xfa0ff48c},
+{6900000, DIF_BPF_COEFF2627,  0xf6fe00a9},
+{6900000, DIF_BPF_COEFF2829,  0x0b0a0e43},
+{6900000, DIF_BPF_COEFF3031,  0x0729fa33},
+{6900000, DIF_BPF_COEFF3233,  0xf0a5f1c9},
+{6900000, DIF_BPF_COEFF3435,  0xfd430b00},
+{6900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 69_quant.dat*/
+
+
+/*case 7000000:*/
+/* BEGIN - DIF BPF register values from 70_quant.dat*/
+{7000000, DIF_BPF_COEFF01,    0x00010002},
+{7000000, DIF_BPF_COEFF23,    0x0001fff3},
+{7000000, DIF_BPF_COEFF45,    0xffdeffe2},
+{7000000, DIF_BPF_COEFF67,    0x001b0076},
+{7000000, DIF_BPF_COEFF89,    0x009c002d},
+{7000000, DIF_BPF_COEFF1011,  0xff35fe68},
+{7000000, DIF_BPF_COEFF1213,  0xfeba0076},
+{7000000, DIF_BPF_COEFF1415,  0x029f0352},
+{7000000, DIF_BPF_COEFF1617,  0x014dfd60},
+{7000000, DIF_BPF_COEFF1819,  0xfa69fb53},
+{7000000, DIF_BPF_COEFF2021,  0x00740688},
+{7000000, DIF_BPF_COEFF2223,  0x08a7042d},
+{7000000, DIF_BPF_COEFF2425,  0xfb75f4d6},
+{7000000, DIF_BPF_COEFF2627,  0xf600ff2d},
+{7000000, DIF_BPF_COEFF2829,  0x0a220e7a},
+{7000000, DIF_BPF_COEFF3031,  0x0827fb22},
+{7000000, DIF_BPF_COEFF3233,  0xf0edf17a},
+{7000000, DIF_BPF_COEFF3435,  0xfcd80ad6},
+{7000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 70_quant.dat*/
+
+
+/*case 7100000:*/
+/* BEGIN - DIF BPF register values from 71_quant.dat*/
+{7100000, DIF_BPF_COEFF01,    0x00000003},
+{7100000, DIF_BPF_COEFF23,    0x0004fff9},
+{7100000, DIF_BPF_COEFF45,    0xffe0ffd2},
+{7100000, DIF_BPF_COEFF67,    0xfffb005e},
+{7100000, DIF_BPF_COEFF89,    0x00b0007a},
+{7100000, DIF_BPF_COEFF1011,  0xff8ffe7c},
+{7100000, DIF_BPF_COEFF1213,  0xfe53ffc1},
+{7100000, DIF_BPF_COEFF1415,  0x0221038c},
+{7100000, DIF_BPF_COEFF1617,  0x0241fe6e},
+{7100000, DIF_BPF_COEFF1819,  0xfab6fa80},
+{7100000, DIF_BPF_COEFF2021,  0xff010587},
+{7100000, DIF_BPF_COEFF2223,  0x08e90590},
+{7100000, DIF_BPF_COEFF2425,  0xfcf5f556},
+{7100000, DIF_BPF_COEFF2627,  0xf52bfdb3},
+{7100000, DIF_BPF_COEFF2829,  0x09210e95},
+{7100000, DIF_BPF_COEFF3031,  0x0919fc15},
+{7100000, DIF_BPF_COEFF3233,  0xf13ff12f},
+{7100000, DIF_BPF_COEFF3435,  0xfc6e0aab},
+{7100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 71_quant.dat*/
+
+
+/*case 7200000:*/
+/* BEGIN - DIF BPF register values from 72_quant.dat*/
+{7200000, DIF_BPF_COEFF01,    0x00000003},
+{7200000, DIF_BPF_COEFF23,    0x00070000},
+{7200000, DIF_BPF_COEFF45,    0xffe6ffc9},
+{7200000, DIF_BPF_COEFF67,    0xffdb0039},
+{7200000, DIF_BPF_COEFF89,    0x00af00b8},
+{7200000, DIF_BPF_COEFF1011,  0xfff4feb6},
+{7200000, DIF_BPF_COEFF1213,  0xfe13ff10},
+{7200000, DIF_BPF_COEFF1415,  0x01790388},
+{7200000, DIF_BPF_COEFF1617,  0x0311ff92},
+{7200000, DIF_BPF_COEFF1819,  0xfb48f9ed},
+{7200000, DIF_BPF_COEFF2021,  0xfd980453},
+{7200000, DIF_BPF_COEFF2223,  0x08e306cd},
+{7200000, DIF_BPF_COEFF2425,  0xfe88f60a},
+{7200000, DIF_BPF_COEFF2627,  0xf482fc40},
+{7200000, DIF_BPF_COEFF2829,  0x08080e93},
+{7200000, DIF_BPF_COEFF3031,  0x09fdfd0c},
+{7200000, DIF_BPF_COEFF3233,  0xf19af0ea},
+{7200000, DIF_BPF_COEFF3435,  0xfc050a81},
+{7200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 72_quant.dat*/
+
+
+/*case 7300000:*/
+/* BEGIN - DIF BPF register values from 73_quant.dat*/
+{7300000, DIF_BPF_COEFF01,    0x00000002},
+{7300000, DIF_BPF_COEFF23,    0x00080008},
+{7300000, DIF_BPF_COEFF45,    0xfff0ffc9},
+{7300000, DIF_BPF_COEFF67,    0xffc1000d},
+{7300000, DIF_BPF_COEFF89,    0x009800e2},
+{7300000, DIF_BPF_COEFF1011,  0x005bff10},
+{7300000, DIF_BPF_COEFF1213,  0xfe00fe74},
+{7300000, DIF_BPF_COEFF1415,  0x00b50345},
+{7300000, DIF_BPF_COEFF1617,  0x03b000bc},
+{7300000, DIF_BPF_COEFF1819,  0xfc18f9a1},
+{7300000, DIF_BPF_COEFF2021,  0xfc4802f9},
+{7300000, DIF_BPF_COEFF2223,  0x089807dc},
+{7300000, DIF_BPF_COEFF2425,  0x0022f6f0},
+{7300000, DIF_BPF_COEFF2627,  0xf407fada},
+{7300000, DIF_BPF_COEFF2829,  0x06da0e74},
+{7300000, DIF_BPF_COEFF3031,  0x0ad3fe06},
+{7300000, DIF_BPF_COEFF3233,  0xf1fef0ab},
+{7300000, DIF_BPF_COEFF3435,  0xfb9c0a55},
+{7300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 73_quant.dat*/
+
+
+/*case 7400000:*/
+/* BEGIN - DIF BPF register values from 74_quant.dat*/
+{7400000, DIF_BPF_COEFF01,    0x00000001},
+{7400000, DIF_BPF_COEFF23,    0x0008000e},
+{7400000, DIF_BPF_COEFF45,    0xfffdffd0},
+{7400000, DIF_BPF_COEFF67,    0xffafffdf},
+{7400000, DIF_BPF_COEFF89,    0x006e00f2},
+{7400000, DIF_BPF_COEFF1011,  0x00b8ff82},
+{7400000, DIF_BPF_COEFF1213,  0xfe1bfdf8},
+{7400000, DIF_BPF_COEFF1415,  0xffe302c8},
+{7400000, DIF_BPF_COEFF1617,  0x041301dc},
+{7400000, DIF_BPF_COEFF1819,  0xfd1af99e},
+{7400000, DIF_BPF_COEFF2021,  0xfb1e0183},
+{7400000, DIF_BPF_COEFF2223,  0x080908b5},
+{7400000, DIF_BPF_COEFF2425,  0x01bcf801},
+{7400000, DIF_BPF_COEFF2627,  0xf3bdf985},
+{7400000, DIF_BPF_COEFF2829,  0x059a0e38},
+{7400000, DIF_BPF_COEFF3031,  0x0b99ff03},
+{7400000, DIF_BPF_COEFF3233,  0xf26cf071},
+{7400000, DIF_BPF_COEFF3435,  0xfb330a2a},
+{7400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 74_quant.dat*/
+
+
+/*case 7500000:*/
+/* BEGIN - DIF BPF register values from 75_quant.dat*/
+{7500000, DIF_BPF_COEFF01,    0xffff0000},
+{7500000, DIF_BPF_COEFF23,    0x00070011},
+{7500000, DIF_BPF_COEFF45,    0x000affdf},
+{7500000, DIF_BPF_COEFF67,    0xffa9ffb5},
+{7500000, DIF_BPF_COEFF89,    0x003700e6},
+{7500000, DIF_BPF_COEFF1011,  0x01010000},
+{7500000, DIF_BPF_COEFF1213,  0xfe62fda8},
+{7500000, DIF_BPF_COEFF1415,  0xff140219},
+{7500000, DIF_BPF_COEFF1617,  0x043502e1},
+{7500000, DIF_BPF_COEFF1819,  0xfe42f9e6},
+{7500000, DIF_BPF_COEFF2021,  0xfa270000},
+{7500000, DIF_BPF_COEFF2223,  0x073a0953},
+{7500000, DIF_BPF_COEFF2425,  0x034cf939},
+{7500000, DIF_BPF_COEFF2627,  0xf3a4f845},
+{7500000, DIF_BPF_COEFF2829,  0x044c0de1},
+{7500000, DIF_BPF_COEFF3031,  0x0c4f0000},
+{7500000, DIF_BPF_COEFF3233,  0xf2e2f03c},
+{7500000, DIF_BPF_COEFF3435,  0xfacc09fe},
+{7500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 75_quant.dat*/
+
+
+/*case 7600000:*/
+/* BEGIN - DIF BPF register values from 76_quant.dat*/
+{7600000, DIF_BPF_COEFF01,    0xffffffff},
+{7600000, DIF_BPF_COEFF23,    0x00040012},
+{7600000, DIF_BPF_COEFF45,    0x0016fff3},
+{7600000, DIF_BPF_COEFF67,    0xffafff95},
+{7600000, DIF_BPF_COEFF89,    0xfff900c0},
+{7600000, DIF_BPF_COEFF1011,  0x0130007e},
+{7600000, DIF_BPF_COEFF1213,  0xfecefd89},
+{7600000, DIF_BPF_COEFF1415,  0xfe560146},
+{7600000, DIF_BPF_COEFF1617,  0x041303bc},
+{7600000, DIF_BPF_COEFF1819,  0xff81fa76},
+{7600000, DIF_BPF_COEFF2021,  0xf96cfe7d},
+{7600000, DIF_BPF_COEFF2223,  0x063209b1},
+{7600000, DIF_BPF_COEFF2425,  0x04c9fa93},
+{7600000, DIF_BPF_COEFF2627,  0xf3bdf71e},
+{7600000, DIF_BPF_COEFF2829,  0x02f30d6e},
+{7600000, DIF_BPF_COEFF3031,  0x0cf200fd},
+{7600000, DIF_BPF_COEFF3233,  0xf361f00e},
+{7600000, DIF_BPF_COEFF3435,  0xfa6509d1},
+{7600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 76_quant.dat*/
+
+
+/*case 7700000:*/
+/* BEGIN - DIF BPF register values from 77_quant.dat*/
+{7700000, DIF_BPF_COEFF01,    0xfffffffe},
+{7700000, DIF_BPF_COEFF23,    0x00010010},
+{7700000, DIF_BPF_COEFF45,    0x001e0008},
+{7700000, DIF_BPF_COEFF67,    0xffc1ff84},
+{7700000, DIF_BPF_COEFF89,    0xffbc0084},
+{7700000, DIF_BPF_COEFF1011,  0x013e00f0},
+{7700000, DIF_BPF_COEFF1213,  0xff56fd9f},
+{7700000, DIF_BPF_COEFF1415,  0xfdb8005c},
+{7700000, DIF_BPF_COEFF1617,  0x03b00460},
+{7700000, DIF_BPF_COEFF1819,  0x00c7fb45},
+{7700000, DIF_BPF_COEFF2021,  0xf8f4fd07},
+{7700000, DIF_BPF_COEFF2223,  0x04fa09ce},
+{7700000, DIF_BPF_COEFF2425,  0x062afc07},
+{7700000, DIF_BPF_COEFF2627,  0xf407f614},
+{7700000, DIF_BPF_COEFF2829,  0x01920ce0},
+{7700000, DIF_BPF_COEFF3031,  0x0d8301fa},
+{7700000, DIF_BPF_COEFF3233,  0xf3e8efe5},
+{7700000, DIF_BPF_COEFF3435,  0xfa0009a4},
+{7700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 77_quant.dat*/
+
+
+/*case 7800000:*/
+/* BEGIN - DIF BPF register values from 78_quant.dat*/
+{7800000, DIF_BPF_COEFF01,    0x0000fffd},
+{7800000, DIF_BPF_COEFF23,    0xfffd000b},
+{7800000, DIF_BPF_COEFF45,    0x0022001d},
+{7800000, DIF_BPF_COEFF67,    0xffdbff82},
+{7800000, DIF_BPF_COEFF89,    0xff870039},
+{7800000, DIF_BPF_COEFF1011,  0x012a014a},
+{7800000, DIF_BPF_COEFF1213,  0xffedfde7},
+{7800000, DIF_BPF_COEFF1415,  0xfd47ff6b},
+{7800000, DIF_BPF_COEFF1617,  0x031104c6},
+{7800000, DIF_BPF_COEFF1819,  0x0202fc4c},
+{7800000, DIF_BPF_COEFF2021,  0xf8c6fbad},
+{7800000, DIF_BPF_COEFF2223,  0x039909a7},
+{7800000, DIF_BPF_COEFF2425,  0x0767fd8e},
+{7800000, DIF_BPF_COEFF2627,  0xf482f52b},
+{7800000, DIF_BPF_COEFF2829,  0x002d0c39},
+{7800000, DIF_BPF_COEFF3031,  0x0e0002f4},
+{7800000, DIF_BPF_COEFF3233,  0xf477efc2},
+{7800000, DIF_BPF_COEFF3435,  0xf99b0977},
+{7800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 78_quant.dat*/
+
+
+/*case 7900000:*/
+/* BEGIN - DIF BPF register values from 79_quant.dat*/
+{7900000, DIF_BPF_COEFF01,    0x0000fffd},
+{7900000, DIF_BPF_COEFF23,    0xfffa0004},
+{7900000, DIF_BPF_COEFF45,    0x0020002d},
+{7900000, DIF_BPF_COEFF67,    0xfffbff91},
+{7900000, DIF_BPF_COEFF89,    0xff61ffe8},
+{7900000, DIF_BPF_COEFF1011,  0x00f70184},
+{7900000, DIF_BPF_COEFF1213,  0x0086fe5c},
+{7900000, DIF_BPF_COEFF1415,  0xfd0bfe85},
+{7900000, DIF_BPF_COEFF1617,  0x024104e5},
+{7900000, DIF_BPF_COEFF1819,  0x0323fd7d},
+{7900000, DIF_BPF_COEFF2021,  0xf8e2fa79},
+{7900000, DIF_BPF_COEFF2223,  0x021d093f},
+{7900000, DIF_BPF_COEFF2425,  0x0879ff22},
+{7900000, DIF_BPF_COEFF2627,  0xf52bf465},
+{7900000, DIF_BPF_COEFF2829,  0xfec70b79},
+{7900000, DIF_BPF_COEFF3031,  0x0e6803eb},
+{7900000, DIF_BPF_COEFF3233,  0xf50defa5},
+{7900000, DIF_BPF_COEFF3435,  0xf937094a},
+{7900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 79_quant.dat*/
+
+
+/*case 8000000:*/
+/* BEGIN - DIF BPF register values from 80_quant.dat*/
+{8000000, DIF_BPF_COEFF01,    0x0000fffe},
+{8000000, DIF_BPF_COEFF23,    0xfff8fffd},
+{8000000, DIF_BPF_COEFF45,    0x00190036},
+{8000000, DIF_BPF_COEFF67,    0x001bffaf},
+{8000000, DIF_BPF_COEFF89,    0xff4fff99},
+{8000000, DIF_BPF_COEFF1011,  0x00aa0198},
+{8000000, DIF_BPF_COEFF1213,  0x0112fef3},
+{8000000, DIF_BPF_COEFF1415,  0xfd09fdb9},
+{8000000, DIF_BPF_COEFF1617,  0x014d04be},
+{8000000, DIF_BPF_COEFF1819,  0x041bfecc},
+{8000000, DIF_BPF_COEFF2021,  0xf947f978},
+{8000000, DIF_BPF_COEFF2223,  0x00900897},
+{8000000, DIF_BPF_COEFF2425,  0x095a00b9},
+{8000000, DIF_BPF_COEFF2627,  0xf600f3c5},
+{8000000, DIF_BPF_COEFF2829,  0xfd650aa3},
+{8000000, DIF_BPF_COEFF3031,  0x0ebc04de},
+{8000000, DIF_BPF_COEFF3233,  0xf5aaef8e},
+{8000000, DIF_BPF_COEFF3435,  0xf8d5091c},
+{8000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 80_quant.dat*/
+
+
+/*case 8100000:*/
+/* BEGIN - DIF BPF register values from 81_quant.dat*/
+{8100000, DIF_BPF_COEFF01,    0x0000ffff},
+{8100000, DIF_BPF_COEFF23,    0xfff7fff6},
+{8100000, DIF_BPF_COEFF45,    0x000e0038},
+{8100000, DIF_BPF_COEFF67,    0x0037ffd7},
+{8100000, DIF_BPF_COEFF89,    0xff52ff56},
+{8100000, DIF_BPF_COEFF1011,  0x004b0184},
+{8100000, DIF_BPF_COEFF1213,  0x0186ffa1},
+{8100000, DIF_BPF_COEFF1415,  0xfd40fd16},
+{8100000, DIF_BPF_COEFF1617,  0x00440452},
+{8100000, DIF_BPF_COEFF1819,  0x04de0029},
+{8100000, DIF_BPF_COEFF2021,  0xf9f2f8b2},
+{8100000, DIF_BPF_COEFF2223,  0xfefe07b5},
+{8100000, DIF_BPF_COEFF2425,  0x0a05024d},
+{8100000, DIF_BPF_COEFF2627,  0xf6fef34d},
+{8100000, DIF_BPF_COEFF2829,  0xfc0a09b8},
+{8100000, DIF_BPF_COEFF3031,  0x0efa05cd},
+{8100000, DIF_BPF_COEFF3233,  0xf64eef7d},
+{8100000, DIF_BPF_COEFF3435,  0xf87308ed},
+{8100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 81_quant.dat*/
+
+
+/*case 8200000:*/
+/* BEGIN - DIF BPF register values from 82_quant.dat*/
+{8200000, DIF_BPF_COEFF01,    0x00010000},
+{8200000, DIF_BPF_COEFF23,    0xfff8fff0},
+{8200000, DIF_BPF_COEFF45,    0x00000031},
+{8200000, DIF_BPF_COEFF67,    0x004c0005},
+{8200000, DIF_BPF_COEFF89,    0xff6aff27},
+{8200000, DIF_BPF_COEFF1011,  0xffe4014a},
+{8200000, DIF_BPF_COEFF1213,  0x01d70057},
+{8200000, DIF_BPF_COEFF1415,  0xfdacfca6},
+{8200000, DIF_BPF_COEFF1617,  0xff3603a7},
+{8200000, DIF_BPF_COEFF1819,  0x05610184},
+{8200000, DIF_BPF_COEFF2021,  0xfadbf82e},
+{8200000, DIF_BPF_COEFF2223,  0xfd74069f},
+{8200000, DIF_BPF_COEFF2425,  0x0a7503d6},
+{8200000, DIF_BPF_COEFF2627,  0xf81ff2ff},
+{8200000, DIF_BPF_COEFF2829,  0xfab808b9},
+{8200000, DIF_BPF_COEFF3031,  0x0f2306b5},
+{8200000, DIF_BPF_COEFF3233,  0xf6f9ef72},
+{8200000, DIF_BPF_COEFF3435,  0xf81308bf},
+{8200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 82_quant.dat*/
+
+
+/*case 8300000:*/
+/* BEGIN - DIF BPF register values from 83_quant.dat*/
+{8300000, DIF_BPF_COEFF01,    0x00010001},
+{8300000, DIF_BPF_COEFF23,    0xfffbffee},
+{8300000, DIF_BPF_COEFF45,    0xfff30022},
+{8300000, DIF_BPF_COEFF67,    0x00560032},
+{8300000, DIF_BPF_COEFF89,    0xff95ff10},
+{8300000, DIF_BPF_COEFF1011,  0xff8000f0},
+{8300000, DIF_BPF_COEFF1213,  0x01fe0106},
+{8300000, DIF_BPF_COEFF1415,  0xfe46fc71},
+{8300000, DIF_BPF_COEFF1617,  0xfe3502c7},
+{8300000, DIF_BPF_COEFF1819,  0x059e02ce},
+{8300000, DIF_BPF_COEFF2021,  0xfbf9f7f2},
+{8300000, DIF_BPF_COEFF2223,  0xfbff055b},
+{8300000, DIF_BPF_COEFF2425,  0x0aa9054c},
+{8300000, DIF_BPF_COEFF2627,  0xf961f2db},
+{8300000, DIF_BPF_COEFF2829,  0xf97507aa},
+{8300000, DIF_BPF_COEFF3031,  0x0f350797},
+{8300000, DIF_BPF_COEFF3233,  0xf7a9ef6d},
+{8300000, DIF_BPF_COEFF3435,  0xf7b40890},
+{8300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 83_quant.dat*/
+
+
+/*case 8400000:*/
+/* BEGIN - DIF BPF register values from 84_quant.dat*/
+{8400000, DIF_BPF_COEFF01,    0x00010002},
+{8400000, DIF_BPF_COEFF23,    0xfffeffee},
+{8400000, DIF_BPF_COEFF45,    0xffe8000f},
+{8400000, DIF_BPF_COEFF67,    0x00540058},
+{8400000, DIF_BPF_COEFF89,    0xffcdff14},
+{8400000, DIF_BPF_COEFF1011,  0xff29007e},
+{8400000, DIF_BPF_COEFF1213,  0x01f6019e},
+{8400000, DIF_BPF_COEFF1415,  0xff01fc7c},
+{8400000, DIF_BPF_COEFF1617,  0xfd5101bf},
+{8400000, DIF_BPF_COEFF1819,  0x059203f6},
+{8400000, DIF_BPF_COEFF2021,  0xfd41f7fe},
+{8400000, DIF_BPF_COEFF2223,  0xfaa903f3},
+{8400000, DIF_BPF_COEFF2425,  0x0a9e06a9},
+{8400000, DIF_BPF_COEFF2627,  0xfabdf2e2},
+{8400000, DIF_BPF_COEFF2829,  0xf842068b},
+{8400000, DIF_BPF_COEFF3031,  0x0f320871},
+{8400000, DIF_BPF_COEFF3233,  0xf85eef6e},
+{8400000, DIF_BPF_COEFF3435,  0xf7560860},
+{8400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 84_quant.dat*/
+
+
+/*case 8500000:*/
+/* BEGIN - DIF BPF register values from 85_quant.dat*/
+{8500000, DIF_BPF_COEFF01,    0x00000003},
+{8500000, DIF_BPF_COEFF23,    0x0002fff2},
+{8500000, DIF_BPF_COEFF45,    0xffe1fff9},
+{8500000, DIF_BPF_COEFF67,    0x00460073},
+{8500000, DIF_BPF_COEFF89,    0x000bff34},
+{8500000, DIF_BPF_COEFF1011,  0xfee90000},
+{8500000, DIF_BPF_COEFF1213,  0x01c10215},
+{8500000, DIF_BPF_COEFF1415,  0xffd0fcc5},
+{8500000, DIF_BPF_COEFF1617,  0xfc99009d},
+{8500000, DIF_BPF_COEFF1819,  0x053d04f1},
+{8500000, DIF_BPF_COEFF2021,  0xfea5f853},
+{8500000, DIF_BPF_COEFF2223,  0xf97d0270},
+{8500000, DIF_BPF_COEFF2425,  0x0a5607e4},
+{8500000, DIF_BPF_COEFF2627,  0xfc2ef314},
+{8500000, DIF_BPF_COEFF2829,  0xf723055f},
+{8500000, DIF_BPF_COEFF3031,  0x0f180943},
+{8500000, DIF_BPF_COEFF3233,  0xf919ef75},
+{8500000, DIF_BPF_COEFF3435,  0xf6fa0830},
+{8500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 85_quant.dat*/
+
+
+/*case 8600000:*/
+/* BEGIN - DIF BPF register values from 86_quant.dat*/
+{8600000, DIF_BPF_COEFF01,    0x00000003},
+{8600000, DIF_BPF_COEFF23,    0x0005fff8},
+{8600000, DIF_BPF_COEFF45,    0xffdeffe4},
+{8600000, DIF_BPF_COEFF67,    0x002f007f},
+{8600000, DIF_BPF_COEFF89,    0x0048ff6b},
+{8600000, DIF_BPF_COEFF1011,  0xfec7ff82},
+{8600000, DIF_BPF_COEFF1213,  0x0163025f},
+{8600000, DIF_BPF_COEFF1415,  0x00a2fd47},
+{8600000, DIF_BPF_COEFF1617,  0xfc17ff73},
+{8600000, DIF_BPF_COEFF1819,  0x04a405b2},
+{8600000, DIF_BPF_COEFF2021,  0x0017f8ed},
+{8600000, DIF_BPF_COEFF2223,  0xf88500dc},
+{8600000, DIF_BPF_COEFF2425,  0x09d208f9},
+{8600000, DIF_BPF_COEFF2627,  0xfdaff370},
+{8600000, DIF_BPF_COEFF2829,  0xf61c0429},
+{8600000, DIF_BPF_COEFF3031,  0x0ee80a0b},
+{8600000, DIF_BPF_COEFF3233,  0xf9d8ef82},
+{8600000, DIF_BPF_COEFF3435,  0xf6a00800},
+{8600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 86_quant.dat*/
+
+
+/*case 8700000:*/
+/* BEGIN - DIF BPF register values from 87_quant.dat*/
+{8700000, DIF_BPF_COEFF01,    0x00000003},
+{8700000, DIF_BPF_COEFF23,    0x0007ffff},
+{8700000, DIF_BPF_COEFF45,    0xffe1ffd4},
+{8700000, DIF_BPF_COEFF67,    0x0010007a},
+{8700000, DIF_BPF_COEFF89,    0x007cffb2},
+{8700000, DIF_BPF_COEFF1011,  0xfec6ff10},
+{8700000, DIF_BPF_COEFF1213,  0x00e60277},
+{8700000, DIF_BPF_COEFF1415,  0x0168fdf9},
+{8700000, DIF_BPF_COEFF1617,  0xfbd3fe50},
+{8700000, DIF_BPF_COEFF1819,  0x03ce0631},
+{8700000, DIF_BPF_COEFF2021,  0x0188f9c8},
+{8700000, DIF_BPF_COEFF2223,  0xf7c7ff43},
+{8700000, DIF_BPF_COEFF2425,  0x091509e3},
+{8700000, DIF_BPF_COEFF2627,  0xff39f3f6},
+{8700000, DIF_BPF_COEFF2829,  0xf52d02ea},
+{8700000, DIF_BPF_COEFF3031,  0x0ea30ac9},
+{8700000, DIF_BPF_COEFF3233,  0xfa9bef95},
+{8700000, DIF_BPF_COEFF3435,  0xf64607d0},
+{8700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 87_quant.dat*/
+
+
+/*case 8800000:*/
+/* BEGIN - DIF BPF register values from 88_quant.dat*/
+{8800000, DIF_BPF_COEFF01,    0x00000002},
+{8800000, DIF_BPF_COEFF23,    0x00090007},
+{8800000, DIF_BPF_COEFF45,    0xffe9ffca},
+{8800000, DIF_BPF_COEFF67,    0xfff00065},
+{8800000, DIF_BPF_COEFF89,    0x00a10003},
+{8800000, DIF_BPF_COEFF1011,  0xfee6feb6},
+{8800000, DIF_BPF_COEFF1213,  0x0053025b},
+{8800000, DIF_BPF_COEFF1415,  0x0213fed0},
+{8800000, DIF_BPF_COEFF1617,  0xfbd3fd46},
+{8800000, DIF_BPF_COEFF1819,  0x02c70668},
+{8800000, DIF_BPF_COEFF2021,  0x02eafadb},
+{8800000, DIF_BPF_COEFF2223,  0xf74bfdae},
+{8800000, DIF_BPF_COEFF2425,  0x08230a9c},
+{8800000, DIF_BPF_COEFF2627,  0x00c7f4a3},
+{8800000, DIF_BPF_COEFF2829,  0xf45b01a6},
+{8800000, DIF_BPF_COEFF3031,  0x0e480b7c},
+{8800000, DIF_BPF_COEFF3233,  0xfb61efae},
+{8800000, DIF_BPF_COEFF3435,  0xf5ef079f},
+{8800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 88_quant.dat*/
+
+
+/*case 8900000:*/
+/* BEGIN - DIF BPF register values from 89_quant.dat*/
+{8900000, DIF_BPF_COEFF01,    0xffff0000},
+{8900000, DIF_BPF_COEFF23,    0x0008000d},
+{8900000, DIF_BPF_COEFF45,    0xfff5ffc8},
+{8900000, DIF_BPF_COEFF67,    0xffd10043},
+{8900000, DIF_BPF_COEFF89,    0x00b20053},
+{8900000, DIF_BPF_COEFF1011,  0xff24fe7c},
+{8900000, DIF_BPF_COEFF1213,  0xffb9020c},
+{8900000, DIF_BPF_COEFF1415,  0x0295ffbb},
+{8900000, DIF_BPF_COEFF1617,  0xfc17fc64},
+{8900000, DIF_BPF_COEFF1819,  0x019b0654},
+{8900000, DIF_BPF_COEFF2021,  0x042dfc1c},
+{8900000, DIF_BPF_COEFF2223,  0xf714fc2a},
+{8900000, DIF_BPF_COEFF2425,  0x07020b21},
+{8900000, DIF_BPF_COEFF2627,  0x0251f575},
+{8900000, DIF_BPF_COEFF2829,  0xf3a7005e},
+{8900000, DIF_BPF_COEFF3031,  0x0dd80c24},
+{8900000, DIF_BPF_COEFF3233,  0xfc2aefcd},
+{8900000, DIF_BPF_COEFF3435,  0xf599076e},
+{8900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 89_quant.dat*/
+
+
+/*case 9000000:*/
+/* BEGIN - DIF BPF register values from 90_quant.dat*/
+{9000000, DIF_BPF_COEFF01,    0xffffffff},
+{9000000, DIF_BPF_COEFF23,    0x00060011},
+{9000000, DIF_BPF_COEFF45,    0x0002ffcf},
+{9000000, DIF_BPF_COEFF67,    0xffba0018},
+{9000000, DIF_BPF_COEFF89,    0x00ad009a},
+{9000000, DIF_BPF_COEFF1011,  0xff79fe68},
+{9000000, DIF_BPF_COEFF1213,  0xff260192},
+{9000000, DIF_BPF_COEFF1415,  0x02e500ab},
+{9000000, DIF_BPF_COEFF1617,  0xfc99fbb6},
+{9000000, DIF_BPF_COEFF1819,  0x005b05f7},
+{9000000, DIF_BPF_COEFF2021,  0x0545fd81},
+{9000000, DIF_BPF_COEFF2223,  0xf723fabf},
+{9000000, DIF_BPF_COEFF2425,  0x05b80b70},
+{9000000, DIF_BPF_COEFF2627,  0x03d2f669},
+{9000000, DIF_BPF_COEFF2829,  0xf313ff15},
+{9000000, DIF_BPF_COEFF3031,  0x0d550cbf},
+{9000000, DIF_BPF_COEFF3233,  0xfcf6eff2},
+{9000000, DIF_BPF_COEFF3435,  0xf544073d},
+{9000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 90_quant.dat*/
+
+
+/*case 9100000:*/
+/* BEGIN - DIF BPF register values from 91_quant.dat*/
+{9100000, DIF_BPF_COEFF01,    0xfffffffe},
+{9100000, DIF_BPF_COEFF23,    0x00030012},
+{9100000, DIF_BPF_COEFF45,    0x000fffdd},
+{9100000, DIF_BPF_COEFF67,    0xffacffea},
+{9100000, DIF_BPF_COEFF89,    0x009300cf},
+{9100000, DIF_BPF_COEFF1011,  0xffdcfe7c},
+{9100000, DIF_BPF_COEFF1213,  0xfea600f7},
+{9100000, DIF_BPF_COEFF1415,  0x02fd0190},
+{9100000, DIF_BPF_COEFF1617,  0xfd51fb46},
+{9100000, DIF_BPF_COEFF1819,  0xff150554},
+{9100000, DIF_BPF_COEFF2021,  0x0627fefd},
+{9100000, DIF_BPF_COEFF2223,  0xf778f978},
+{9100000, DIF_BPF_COEFF2425,  0x044d0b87},
+{9100000, DIF_BPF_COEFF2627,  0x0543f77d},
+{9100000, DIF_BPF_COEFF2829,  0xf2a0fdcf},
+{9100000, DIF_BPF_COEFF3031,  0x0cbe0d4e},
+{9100000, DIF_BPF_COEFF3233,  0xfdc4f01d},
+{9100000, DIF_BPF_COEFF3435,  0xf4f2070b},
+{9100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 91_quant.dat*/
+
+
+/*case 9200000:*/
+/* BEGIN - DIF BPF register values from 92_quant.dat*/
+{9200000, DIF_BPF_COEFF01,    0x0000fffd},
+{9200000, DIF_BPF_COEFF23,    0x00000010},
+{9200000, DIF_BPF_COEFF45,    0x001afff0},
+{9200000, DIF_BPF_COEFF67,    0xffaaffbf},
+{9200000, DIF_BPF_COEFF89,    0x006700ed},
+{9200000, DIF_BPF_COEFF1011,  0x0043feb6},
+{9200000, DIF_BPF_COEFF1213,  0xfe460047},
+{9200000, DIF_BPF_COEFF1415,  0x02db0258},
+{9200000, DIF_BPF_COEFF1617,  0xfe35fb1b},
+{9200000, DIF_BPF_COEFF1819,  0xfddc0473},
+{9200000, DIF_BPF_COEFF2021,  0x06c90082},
+{9200000, DIF_BPF_COEFF2223,  0xf811f85e},
+{9200000, DIF_BPF_COEFF2425,  0x02c90b66},
+{9200000, DIF_BPF_COEFF2627,  0x069ff8ad},
+{9200000, DIF_BPF_COEFF2829,  0xf250fc8d},
+{9200000, DIF_BPF_COEFF3031,  0x0c140dcf},
+{9200000, DIF_BPF_COEFF3233,  0xfe93f04d},
+{9200000, DIF_BPF_COEFF3435,  0xf4a106d9},
+{9200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 92_quant.dat*/
+
+
+/*case 9300000:*/
+/* BEGIN - DIF BPF register values from 93_quant.dat*/
+{9300000, DIF_BPF_COEFF01,    0x0000fffd},
+{9300000, DIF_BPF_COEFF23,    0xfffc000c},
+{9300000, DIF_BPF_COEFF45,    0x00200006},
+{9300000, DIF_BPF_COEFF67,    0xffb4ff9c},
+{9300000, DIF_BPF_COEFF89,    0x002f00ef},
+{9300000, DIF_BPF_COEFF1011,  0x00a4ff10},
+{9300000, DIF_BPF_COEFF1213,  0xfe0dff92},
+{9300000, DIF_BPF_COEFF1415,  0x028102f7},
+{9300000, DIF_BPF_COEFF1617,  0xff36fb37},
+{9300000, DIF_BPF_COEFF1819,  0xfcbf035e},
+{9300000, DIF_BPF_COEFF2021,  0x07260202},
+{9300000, DIF_BPF_COEFF2223,  0xf8e8f778},
+{9300000, DIF_BPF_COEFF2425,  0x01340b0d},
+{9300000, DIF_BPF_COEFF2627,  0x07e1f9f4},
+{9300000, DIF_BPF_COEFF2829,  0xf223fb51},
+{9300000, DIF_BPF_COEFF3031,  0x0b590e42},
+{9300000, DIF_BPF_COEFF3233,  0xff64f083},
+{9300000, DIF_BPF_COEFF3435,  0xf45206a7},
+{9300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 93_quant.dat*/
+
+
+/*case 9400000:*/
+/* BEGIN - DIF BPF register values from 94_quant.dat*/
+{9400000, DIF_BPF_COEFF01,    0x0000fffd},
+{9400000, DIF_BPF_COEFF23,    0xfff90005},
+{9400000, DIF_BPF_COEFF45,    0x0022001a},
+{9400000, DIF_BPF_COEFF67,    0xffc9ff86},
+{9400000, DIF_BPF_COEFF89,    0xfff000d7},
+{9400000, DIF_BPF_COEFF1011,  0x00f2ff82},
+{9400000, DIF_BPF_COEFF1213,  0xfe01fee5},
+{9400000, DIF_BPF_COEFF1415,  0x01f60362},
+{9400000, DIF_BPF_COEFF1617,  0x0044fb99},
+{9400000, DIF_BPF_COEFF1819,  0xfbcc0222},
+{9400000, DIF_BPF_COEFF2021,  0x07380370},
+{9400000, DIF_BPF_COEFF2223,  0xf9f7f6cc},
+{9400000, DIF_BPF_COEFF2425,  0xff990a7e},
+{9400000, DIF_BPF_COEFF2627,  0x0902fb50},
+{9400000, DIF_BPF_COEFF2829,  0xf21afa1f},
+{9400000, DIF_BPF_COEFF3031,  0x0a8d0ea6},
+{9400000, DIF_BPF_COEFF3233,  0x0034f0bf},
+{9400000, DIF_BPF_COEFF3435,  0xf4050675},
+{9400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 94_quant.dat*/
+
+
+/*case 9500000:*/
+/* BEGIN - DIF BPF register values from 95_quant.dat*/
+{9500000, DIF_BPF_COEFF01,    0x0000fffe},
+{9500000, DIF_BPF_COEFF23,    0xfff8fffe},
+{9500000, DIF_BPF_COEFF45,    0x001e002b},
+{9500000, DIF_BPF_COEFF67,    0xffe5ff81},
+{9500000, DIF_BPF_COEFF89,    0xffb400a5},
+{9500000, DIF_BPF_COEFF1011,  0x01280000},
+{9500000, DIF_BPF_COEFF1213,  0xfe24fe50},
+{9500000, DIF_BPF_COEFF1415,  0x01460390},
+{9500000, DIF_BPF_COEFF1617,  0x014dfc3a},
+{9500000, DIF_BPF_COEFF1819,  0xfb1000ce},
+{9500000, DIF_BPF_COEFF2021,  0x070104bf},
+{9500000, DIF_BPF_COEFF2223,  0xfb37f65f},
+{9500000, DIF_BPF_COEFF2425,  0xfe0009bc},
+{9500000, DIF_BPF_COEFF2627,  0x0a00fcbb},
+{9500000, DIF_BPF_COEFF2829,  0xf235f8f8},
+{9500000, DIF_BPF_COEFF3031,  0x09b20efc},
+{9500000, DIF_BPF_COEFF3233,  0x0105f101},
+{9500000, DIF_BPF_COEFF3435,  0xf3ba0642},
+{9500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 95_quant.dat*/
+
+
+/*case 9600000:*/
+/* BEGIN - DIF BPF register values from 96_quant.dat*/
+{9600000, DIF_BPF_COEFF01,    0x0001ffff},
+{9600000, DIF_BPF_COEFF23,    0xfff8fff7},
+{9600000, DIF_BPF_COEFF45,    0x00150036},
+{9600000, DIF_BPF_COEFF67,    0x0005ff8c},
+{9600000, DIF_BPF_COEFF89,    0xff810061},
+{9600000, DIF_BPF_COEFF1011,  0x013d007e},
+{9600000, DIF_BPF_COEFF1213,  0xfe71fddf},
+{9600000, DIF_BPF_COEFF1415,  0x007c0380},
+{9600000, DIF_BPF_COEFF1617,  0x0241fd13},
+{9600000, DIF_BPF_COEFF1819,  0xfa94ff70},
+{9600000, DIF_BPF_COEFF2021,  0x068005e2},
+{9600000, DIF_BPF_COEFF2223,  0xfc9bf633},
+{9600000, DIF_BPF_COEFF2425,  0xfc7308ca},
+{9600000, DIF_BPF_COEFF2627,  0x0ad5fe30},
+{9600000, DIF_BPF_COEFF2829,  0xf274f7e0},
+{9600000, DIF_BPF_COEFF3031,  0x08c90f43},
+{9600000, DIF_BPF_COEFF3233,  0x01d4f147},
+{9600000, DIF_BPF_COEFF3435,  0xf371060f},
+{9600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 96_quant.dat*/
+
+
+/*case 9700000:*/
+/* BEGIN - DIF BPF register values from 97_quant.dat*/
+{9700000, DIF_BPF_COEFF01,    0x00010001},
+{9700000, DIF_BPF_COEFF23,    0xfff9fff1},
+{9700000, DIF_BPF_COEFF45,    0x00090038},
+{9700000, DIF_BPF_COEFF67,    0x0025ffa7},
+{9700000, DIF_BPF_COEFF89,    0xff5e0012},
+{9700000, DIF_BPF_COEFF1011,  0x013200f0},
+{9700000, DIF_BPF_COEFF1213,  0xfee3fd9b},
+{9700000, DIF_BPF_COEFF1415,  0xffaa0331},
+{9700000, DIF_BPF_COEFF1617,  0x0311fe15},
+{9700000, DIF_BPF_COEFF1819,  0xfa60fe18},
+{9700000, DIF_BPF_COEFF2021,  0x05bd06d1},
+{9700000, DIF_BPF_COEFF2223,  0xfe1bf64a},
+{9700000, DIF_BPF_COEFF2425,  0xfafa07ae},
+{9700000, DIF_BPF_COEFF2627,  0x0b7effab},
+{9700000, DIF_BPF_COEFF2829,  0xf2d5f6d7},
+{9700000, DIF_BPF_COEFF3031,  0x07d30f7a},
+{9700000, DIF_BPF_COEFF3233,  0x02a3f194},
+{9700000, DIF_BPF_COEFF3435,  0xf32905dc},
+{9700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 97_quant.dat*/
+
+
+/*case 9800000:*/
+/* BEGIN - DIF BPF register values from 98_quant.dat*/
+{9800000, DIF_BPF_COEFF01,    0x00010002},
+{9800000, DIF_BPF_COEFF23,    0xfffcffee},
+{9800000, DIF_BPF_COEFF45,    0xfffb0032},
+{9800000, DIF_BPF_COEFF67,    0x003fffcd},
+{9800000, DIF_BPF_COEFF89,    0xff4effc1},
+{9800000, DIF_BPF_COEFF1011,  0x0106014a},
+{9800000, DIF_BPF_COEFF1213,  0xff6efd8a},
+{9800000, DIF_BPF_COEFF1415,  0xfedd02aa},
+{9800000, DIF_BPF_COEFF1617,  0x03b0ff34},
+{9800000, DIF_BPF_COEFF1819,  0xfa74fcd7},
+{9800000, DIF_BPF_COEFF2021,  0x04bf0781},
+{9800000, DIF_BPF_COEFF2223,  0xffaaf6a3},
+{9800000, DIF_BPF_COEFF2425,  0xf99e066b},
+{9800000, DIF_BPF_COEFF2627,  0x0bf90128},
+{9800000, DIF_BPF_COEFF2829,  0xf359f5e1},
+{9800000, DIF_BPF_COEFF3031,  0x06d20fa2},
+{9800000, DIF_BPF_COEFF3233,  0x0370f1e5},
+{9800000, DIF_BPF_COEFF3435,  0xf2e405a8},
+{9800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 98_quant.dat*/
+
+
+/*case 9900000:*/
+/* BEGIN - DIF BPF register values from 99_quant.dat*/
+{9900000, DIF_BPF_COEFF01,    0x00000003},
+{9900000, DIF_BPF_COEFF23,    0xffffffee},
+{9900000, DIF_BPF_COEFF45,    0xffef0024},
+{9900000, DIF_BPF_COEFF67,    0x0051fffa},
+{9900000, DIF_BPF_COEFF89,    0xff54ff77},
+{9900000, DIF_BPF_COEFF1011,  0x00be0184},
+{9900000, DIF_BPF_COEFF1213,  0x0006fdad},
+{9900000, DIF_BPF_COEFF1415,  0xfe2701f3},
+{9900000, DIF_BPF_COEFF1617,  0x0413005e},
+{9900000, DIF_BPF_COEFF1819,  0xfad1fbba},
+{9900000, DIF_BPF_COEFF2021,  0x039007ee},
+{9900000, DIF_BPF_COEFF2223,  0x013bf73d},
+{9900000, DIF_BPF_COEFF2425,  0xf868050a},
+{9900000, DIF_BPF_COEFF2627,  0x0c4302a1},
+{9900000, DIF_BPF_COEFF2829,  0xf3fdf4fe},
+{9900000, DIF_BPF_COEFF3031,  0x05c70fba},
+{9900000, DIF_BPF_COEFF3233,  0x043bf23c},
+{9900000, DIF_BPF_COEFF3435,  0xf2a10575},
+{9900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 99_quant.dat*/
+
+
+/*case 10000000:*/
+/* BEGIN - DIF BPF register values from 100_quant.dat*/
+{10000000, DIF_BPF_COEFF01,    0x00000003},
+{10000000, DIF_BPF_COEFF23,    0x0003fff1},
+{10000000, DIF_BPF_COEFF45,    0xffe50011},
+{10000000, DIF_BPF_COEFF67,    0x00570027},
+{10000000, DIF_BPF_COEFF89,    0xff70ff3c},
+{10000000, DIF_BPF_COEFF1011,  0x00620198},
+{10000000, DIF_BPF_COEFF1213,  0x009efe01},
+{10000000, DIF_BPF_COEFF1415,  0xfd95011a},
+{10000000, DIF_BPF_COEFF1617,  0x04350183},
+{10000000, DIF_BPF_COEFF1819,  0xfb71fad0},
+{10000000, DIF_BPF_COEFF2021,  0x023c0812},
+{10000000, DIF_BPF_COEFF2223,  0x02c3f811},
+{10000000, DIF_BPF_COEFF2425,  0xf75e0390},
+{10000000, DIF_BPF_COEFF2627,  0x0c5c0411},
+{10000000, DIF_BPF_COEFF2829,  0xf4c1f432},
+{10000000, DIF_BPF_COEFF3031,  0x04b30fc1},
+{10000000, DIF_BPF_COEFF3233,  0x0503f297},
+{10000000, DIF_BPF_COEFF3435,  0xf2610541},
+{10000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 100_quant.dat*/
+
+
+/*case 10100000:*/
+/* BEGIN - DIF BPF register values from 101_quant.dat*/
+{10100000, DIF_BPF_COEFF01,    0x00000003},
+{10100000, DIF_BPF_COEFF23,    0x0006fff7},
+{10100000, DIF_BPF_COEFF45,    0xffdffffc},
+{10100000, DIF_BPF_COEFF67,    0x00510050},
+{10100000, DIF_BPF_COEFF89,    0xff9dff18},
+{10100000, DIF_BPF_COEFF1011,  0xfffc0184},
+{10100000, DIF_BPF_COEFF1213,  0x0128fe80},
+{10100000, DIF_BPF_COEFF1415,  0xfd32002e},
+{10100000, DIF_BPF_COEFF1617,  0x04130292},
+{10100000, DIF_BPF_COEFF1819,  0xfc4dfa21},
+{10100000, DIF_BPF_COEFF2021,  0x00d107ee},
+{10100000, DIF_BPF_COEFF2223,  0x0435f91c},
+{10100000, DIF_BPF_COEFF2425,  0xf6850205},
+{10100000, DIF_BPF_COEFF2627,  0x0c430573},
+{10100000, DIF_BPF_COEFF2829,  0xf5a1f37d},
+{10100000, DIF_BPF_COEFF3031,  0x03990fba},
+{10100000, DIF_BPF_COEFF3233,  0x05c7f2f8},
+{10100000, DIF_BPF_COEFF3435,  0xf222050d},
+{10100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 101_quant.dat*/
+
+
+/*case 10200000:*/
+/* BEGIN - DIF BPF register values from 102_quant.dat*/
+{10200000, DIF_BPF_COEFF01,    0x00000002},
+{10200000, DIF_BPF_COEFF23,    0x0008fffe},
+{10200000, DIF_BPF_COEFF45,    0xffdfffe7},
+{10200000, DIF_BPF_COEFF67,    0x003f006e},
+{10200000, DIF_BPF_COEFF89,    0xffd6ff0f},
+{10200000, DIF_BPF_COEFF1011,  0xff96014a},
+{10200000, DIF_BPF_COEFF1213,  0x0197ff1f},
+{10200000, DIF_BPF_COEFF1415,  0xfd05ff3e},
+{10200000, DIF_BPF_COEFF1617,  0x03b0037c},
+{10200000, DIF_BPF_COEFF1819,  0xfd59f9b7},
+{10200000, DIF_BPF_COEFF2021,  0xff5d0781},
+{10200000, DIF_BPF_COEFF2223,  0x0585fa56},
+{10200000, DIF_BPF_COEFF2425,  0xf5e4006f},
+{10200000, DIF_BPF_COEFF2627,  0x0bf906c4},
+{10200000, DIF_BPF_COEFF2829,  0xf69df2e0},
+{10200000, DIF_BPF_COEFF3031,  0x02790fa2},
+{10200000, DIF_BPF_COEFF3233,  0x0688f35d},
+{10200000, DIF_BPF_COEFF3435,  0xf1e604d8},
+{10200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 102_quant.dat*/
+
+
+/*case 10300000:*/
+/* BEGIN - DIF BPF register values from 103_quant.dat*/
+{10300000, DIF_BPF_COEFF01,    0xffff0001},
+{10300000, DIF_BPF_COEFF23,    0x00090005},
+{10300000, DIF_BPF_COEFF45,    0xffe4ffd6},
+{10300000, DIF_BPF_COEFF67,    0x0025007e},
+{10300000, DIF_BPF_COEFF89,    0x0014ff20},
+{10300000, DIF_BPF_COEFF1011,  0xff3c00f0},
+{10300000, DIF_BPF_COEFF1213,  0x01e1ffd0},
+{10300000, DIF_BPF_COEFF1415,  0xfd12fe5c},
+{10300000, DIF_BPF_COEFF1617,  0x03110433},
+{10300000, DIF_BPF_COEFF1819,  0xfe88f996},
+{10300000, DIF_BPF_COEFF2021,  0xfdf106d1},
+{10300000, DIF_BPF_COEFF2223,  0x06aafbb7},
+{10300000, DIF_BPF_COEFF2425,  0xf57efed8},
+{10300000, DIF_BPF_COEFF2627,  0x0b7e07ff},
+{10300000, DIF_BPF_COEFF2829,  0xf7b0f25e},
+{10300000, DIF_BPF_COEFF3031,  0x01560f7a},
+{10300000, DIF_BPF_COEFF3233,  0x0745f3c7},
+{10300000, DIF_BPF_COEFF3435,  0xf1ac04a4},
+{10300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 103_quant.dat*/
+
+
+/*case 10400000:*/
+/* BEGIN - DIF BPF register values from 104_quant.dat*/
+{10400000, DIF_BPF_COEFF01,    0xffffffff},
+{10400000, DIF_BPF_COEFF23,    0x0008000c},
+{10400000, DIF_BPF_COEFF45,    0xffedffcb},
+{10400000, DIF_BPF_COEFF67,    0x0005007d},
+{10400000, DIF_BPF_COEFF89,    0x0050ff4c},
+{10400000, DIF_BPF_COEFF1011,  0xfef6007e},
+{10400000, DIF_BPF_COEFF1213,  0x01ff0086},
+{10400000, DIF_BPF_COEFF1415,  0xfd58fd97},
+{10400000, DIF_BPF_COEFF1617,  0x024104ad},
+{10400000, DIF_BPF_COEFF1819,  0xffcaf9c0},
+{10400000, DIF_BPF_COEFF2021,  0xfc9905e2},
+{10400000, DIF_BPF_COEFF2223,  0x079afd35},
+{10400000, DIF_BPF_COEFF2425,  0xf555fd46},
+{10400000, DIF_BPF_COEFF2627,  0x0ad50920},
+{10400000, DIF_BPF_COEFF2829,  0xf8d9f1f6},
+{10400000, DIF_BPF_COEFF3031,  0x00310f43},
+{10400000, DIF_BPF_COEFF3233,  0x07fdf435},
+{10400000, DIF_BPF_COEFF3435,  0xf174046f},
+{10400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 104_quant.dat*/
+
+
+/*case 10500000:*/
+/* BEGIN - DIF BPF register values from 105_quant.dat*/
+{10500000, DIF_BPF_COEFF01,    0xfffffffe},
+{10500000, DIF_BPF_COEFF23,    0x00050011},
+{10500000, DIF_BPF_COEFF45,    0xfffaffc8},
+{10500000, DIF_BPF_COEFF67,    0xffe5006b},
+{10500000, DIF_BPF_COEFF89,    0x0082ff8c},
+{10500000, DIF_BPF_COEFF1011,  0xfecc0000},
+{10500000, DIF_BPF_COEFF1213,  0x01f00130},
+{10500000, DIF_BPF_COEFF1415,  0xfdd2fcfc},
+{10500000, DIF_BPF_COEFF1617,  0x014d04e3},
+{10500000, DIF_BPF_COEFF1819,  0x010efa32},
+{10500000, DIF_BPF_COEFF2021,  0xfb6404bf},
+{10500000, DIF_BPF_COEFF2223,  0x084efec5},
+{10500000, DIF_BPF_COEFF2425,  0xf569fbc2},
+{10500000, DIF_BPF_COEFF2627,  0x0a000a23},
+{10500000, DIF_BPF_COEFF2829,  0xfa15f1ab},
+{10500000, DIF_BPF_COEFF3031,  0xff0b0efc},
+{10500000, DIF_BPF_COEFF3233,  0x08b0f4a7},
+{10500000, DIF_BPF_COEFF3435,  0xf13f043a},
+{10500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 105_quant.dat*/
+
+
+/*case 10600000:*/
+/* BEGIN - DIF BPF register values from 106_quant.dat*/
+{10600000, DIF_BPF_COEFF01,    0x0000fffd},
+{10600000, DIF_BPF_COEFF23,    0x00020012},
+{10600000, DIF_BPF_COEFF45,    0x0007ffcd},
+{10600000, DIF_BPF_COEFF67,    0xffc9004c},
+{10600000, DIF_BPF_COEFF89,    0x00a4ffd9},
+{10600000, DIF_BPF_COEFF1011,  0xfec3ff82},
+{10600000, DIF_BPF_COEFF1213,  0x01b401c1},
+{10600000, DIF_BPF_COEFF1415,  0xfe76fc97},
+{10600000, DIF_BPF_COEFF1617,  0x004404d2},
+{10600000, DIF_BPF_COEFF1819,  0x0245fae8},
+{10600000, DIF_BPF_COEFF2021,  0xfa5f0370},
+{10600000, DIF_BPF_COEFF2223,  0x08c1005f},
+{10600000, DIF_BPF_COEFF2425,  0xf5bcfa52},
+{10600000, DIF_BPF_COEFF2627,  0x09020b04},
+{10600000, DIF_BPF_COEFF2829,  0xfb60f17b},
+{10600000, DIF_BPF_COEFF3031,  0xfde70ea6},
+{10600000, DIF_BPF_COEFF3233,  0x095df51e},
+{10600000, DIF_BPF_COEFF3435,  0xf10c0405},
+{10600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 106_quant.dat*/
+
+
+/*case 10700000:*/
+/* BEGIN - DIF BPF register values from 107_quant.dat*/
+{10700000, DIF_BPF_COEFF01,    0x0000fffd},
+{10700000, DIF_BPF_COEFF23,    0xffff0011},
+{10700000, DIF_BPF_COEFF45,    0x0014ffdb},
+{10700000, DIF_BPF_COEFF67,    0xffb40023},
+{10700000, DIF_BPF_COEFF89,    0x00b2002a},
+{10700000, DIF_BPF_COEFF1011,  0xfedbff10},
+{10700000, DIF_BPF_COEFF1213,  0x0150022d},
+{10700000, DIF_BPF_COEFF1415,  0xff38fc6f},
+{10700000, DIF_BPF_COEFF1617,  0xff36047b},
+{10700000, DIF_BPF_COEFF1819,  0x035efbda},
+{10700000, DIF_BPF_COEFF2021,  0xf9940202},
+{10700000, DIF_BPF_COEFF2223,  0x08ee01f5},
+{10700000, DIF_BPF_COEFF2425,  0xf649f8fe},
+{10700000, DIF_BPF_COEFF2627,  0x07e10bc2},
+{10700000, DIF_BPF_COEFF2829,  0xfcb6f169},
+{10700000, DIF_BPF_COEFF3031,  0xfcc60e42},
+{10700000, DIF_BPF_COEFF3233,  0x0a04f599},
+{10700000, DIF_BPF_COEFF3435,  0xf0db03d0},
+{10700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 107_quant.dat*/
+
+
+/*case 10800000:*/
+/* BEGIN - DIF BPF register values from 108_quant.dat*/
+{10800000, DIF_BPF_COEFF01,    0x0000fffd},
+{10800000, DIF_BPF_COEFF23,    0xfffb000d},
+{10800000, DIF_BPF_COEFF45,    0x001dffed},
+{10800000, DIF_BPF_COEFF67,    0xffaafff5},
+{10800000, DIF_BPF_COEFF89,    0x00aa0077},
+{10800000, DIF_BPF_COEFF1011,  0xff13feb6},
+{10800000, DIF_BPF_COEFF1213,  0x00ce026b},
+{10800000, DIF_BPF_COEFF1415,  0x000afc85},
+{10800000, DIF_BPF_COEFF1617,  0xfe3503e3},
+{10800000, DIF_BPF_COEFF1819,  0x044cfcfb},
+{10800000, DIF_BPF_COEFF2021,  0xf90c0082},
+{10800000, DIF_BPF_COEFF2223,  0x08d5037f},
+{10800000, DIF_BPF_COEFF2425,  0xf710f7cc},
+{10800000, DIF_BPF_COEFF2627,  0x069f0c59},
+{10800000, DIF_BPF_COEFF2829,  0xfe16f173},
+{10800000, DIF_BPF_COEFF3031,  0xfbaa0dcf},
+{10800000, DIF_BPF_COEFF3233,  0x0aa5f617},
+{10800000, DIF_BPF_COEFF3435,  0xf0ad039b},
+{10800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 108_quant.dat*/
+
+
+/*case 10900000:*/
+/* BEGIN - DIF BPF register values from 109_quant.dat*/
+{10900000, DIF_BPF_COEFF01,    0x0000fffe},
+{10900000, DIF_BPF_COEFF23,    0xfff90006},
+{10900000, DIF_BPF_COEFF45,    0x00210003},
+{10900000, DIF_BPF_COEFF67,    0xffacffc8},
+{10900000, DIF_BPF_COEFF89,    0x008e00b6},
+{10900000, DIF_BPF_COEFF1011,  0xff63fe7c},
+{10900000, DIF_BPF_COEFF1213,  0x003a0275},
+{10900000, DIF_BPF_COEFF1415,  0x00dafcda},
+{10900000, DIF_BPF_COEFF1617,  0xfd510313},
+{10900000, DIF_BPF_COEFF1819,  0x0501fe40},
+{10900000, DIF_BPF_COEFF2021,  0xf8cbfefd},
+{10900000, DIF_BPF_COEFF2223,  0x087604f0},
+{10900000, DIF_BPF_COEFF2425,  0xf80af6c2},
+{10900000, DIF_BPF_COEFF2627,  0x05430cc8},
+{10900000, DIF_BPF_COEFF2829,  0xff7af19a},
+{10900000, DIF_BPF_COEFF3031,  0xfa940d4e},
+{10900000, DIF_BPF_COEFF3233,  0x0b3ff699},
+{10900000, DIF_BPF_COEFF3435,  0xf0810365},
+{10900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 109_quant.dat*/
+
+
+/*case 11000000:*/
+/* BEGIN - DIF BPF register values from 110_quant.dat*/
+{11000000, DIF_BPF_COEFF01,    0x0001ffff},
+{11000000, DIF_BPF_COEFF23,    0xfff8ffff},
+{11000000, DIF_BPF_COEFF45,    0x00210018},
+{11000000, DIF_BPF_COEFF67,    0xffbaffa3},
+{11000000, DIF_BPF_COEFF89,    0x006000e1},
+{11000000, DIF_BPF_COEFF1011,  0xffc4fe68},
+{11000000, DIF_BPF_COEFF1213,  0xffa0024b},
+{11000000, DIF_BPF_COEFF1415,  0x019afd66},
+{11000000, DIF_BPF_COEFF1617,  0xfc990216},
+{11000000, DIF_BPF_COEFF1819,  0x0575ff99},
+{11000000, DIF_BPF_COEFF2021,  0xf8d4fd81},
+{11000000, DIF_BPF_COEFF2223,  0x07d40640},
+{11000000, DIF_BPF_COEFF2425,  0xf932f5e6},
+{11000000, DIF_BPF_COEFF2627,  0x03d20d0d},
+{11000000, DIF_BPF_COEFF2829,  0x00dff1de},
+{11000000, DIF_BPF_COEFF3031,  0xf9860cbf},
+{11000000, DIF_BPF_COEFF3233,  0x0bd1f71e},
+{11000000, DIF_BPF_COEFF3435,  0xf058032f},
+{11000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 110_quant.dat*/
+
+
+/*case 11100000:*/
+/* BEGIN - DIF BPF register values from 111_quant.dat*/
+{11100000, DIF_BPF_COEFF01,    0x00010000},
+{11100000, DIF_BPF_COEFF23,    0xfff8fff8},
+{11100000, DIF_BPF_COEFF45,    0x001b0029},
+{11100000, DIF_BPF_COEFF67,    0xffd1ff8a},
+{11100000, DIF_BPF_COEFF89,    0x002600f2},
+{11100000, DIF_BPF_COEFF1011,  0x002cfe7c},
+{11100000, DIF_BPF_COEFF1213,  0xff0f01f0},
+{11100000, DIF_BPF_COEFF1415,  0x023bfe20},
+{11100000, DIF_BPF_COEFF1617,  0xfc1700fa},
+{11100000, DIF_BPF_COEFF1819,  0x05a200f7},
+{11100000, DIF_BPF_COEFF2021,  0xf927fc1c},
+{11100000, DIF_BPF_COEFF2223,  0x06f40765},
+{11100000, DIF_BPF_COEFF2425,  0xfa82f53b},
+{11100000, DIF_BPF_COEFF2627,  0x02510d27},
+{11100000, DIF_BPF_COEFF2829,  0x0243f23d},
+{11100000, DIF_BPF_COEFF3031,  0xf8810c24},
+{11100000, DIF_BPF_COEFF3233,  0x0c5cf7a7},
+{11100000, DIF_BPF_COEFF3435,  0xf03102fa},
+{11100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 111_quant.dat*/
+
+
+/*case 11200000:*/
+/* BEGIN - DIF BPF register values from 112_quant.dat*/
+{11200000, DIF_BPF_COEFF01,    0x00010002},
+{11200000, DIF_BPF_COEFF23,    0xfffafff2},
+{11200000, DIF_BPF_COEFF45,    0x00110035},
+{11200000, DIF_BPF_COEFF67,    0xfff0ff81},
+{11200000, DIF_BPF_COEFF89,    0xffe700e7},
+{11200000, DIF_BPF_COEFF1011,  0x008ffeb6},
+{11200000, DIF_BPF_COEFF1213,  0xfe94016d},
+{11200000, DIF_BPF_COEFF1415,  0x02b0fefb},
+{11200000, DIF_BPF_COEFF1617,  0xfbd3ffd1},
+{11200000, DIF_BPF_COEFF1819,  0x05850249},
+{11200000, DIF_BPF_COEFF2021,  0xf9c1fadb},
+{11200000, DIF_BPF_COEFF2223,  0x05de0858},
+{11200000, DIF_BPF_COEFF2425,  0xfbf2f4c4},
+{11200000, DIF_BPF_COEFF2627,  0x00c70d17},
+{11200000, DIF_BPF_COEFF2829,  0x03a0f2b8},
+{11200000, DIF_BPF_COEFF3031,  0xf7870b7c},
+{11200000, DIF_BPF_COEFF3233,  0x0cdff833},
+{11200000, DIF_BPF_COEFF3435,  0xf00d02c4},
+{11200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 112_quant.dat*/
+
+
+/*case 11300000:*/
+/* BEGIN - DIF BPF register values from 113_quant.dat*/
+{11300000, DIF_BPF_COEFF01,    0x00000003},
+{11300000, DIF_BPF_COEFF23,    0xfffdffee},
+{11300000, DIF_BPF_COEFF45,    0x00040038},
+{11300000, DIF_BPF_COEFF67,    0x0010ff88},
+{11300000, DIF_BPF_COEFF89,    0xffac00c2},
+{11300000, DIF_BPF_COEFF1011,  0x00e2ff10},
+{11300000, DIF_BPF_COEFF1213,  0xfe3900cb},
+{11300000, DIF_BPF_COEFF1415,  0x02f1ffe9},
+{11300000, DIF_BPF_COEFF1617,  0xfbd3feaa},
+{11300000, DIF_BPF_COEFF1819,  0x05210381},
+{11300000, DIF_BPF_COEFF2021,  0xfa9cf9c8},
+{11300000, DIF_BPF_COEFF2223,  0x04990912},
+{11300000, DIF_BPF_COEFF2425,  0xfd7af484},
+{11300000, DIF_BPF_COEFF2627,  0xff390cdb},
+{11300000, DIF_BPF_COEFF2829,  0x04f4f34d},
+{11300000, DIF_BPF_COEFF3031,  0xf69a0ac9},
+{11300000, DIF_BPF_COEFF3233,  0x0d5af8c1},
+{11300000, DIF_BPF_COEFF3435,  0xefec028e},
+{11300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 113_quant.dat*/
+
+
+/*case 11400000:*/
+/* BEGIN - DIF BPF register values from 114_quant.dat*/
+{11400000, DIF_BPF_COEFF01,    0x00000003},
+{11400000, DIF_BPF_COEFF23,    0x0000ffee},
+{11400000, DIF_BPF_COEFF45,    0xfff60033},
+{11400000, DIF_BPF_COEFF67,    0x002fff9f},
+{11400000, DIF_BPF_COEFF89,    0xff7b0087},
+{11400000, DIF_BPF_COEFF1011,  0x011eff82},
+{11400000, DIF_BPF_COEFF1213,  0xfe080018},
+{11400000, DIF_BPF_COEFF1415,  0x02f900d8},
+{11400000, DIF_BPF_COEFF1617,  0xfc17fd96},
+{11400000, DIF_BPF_COEFF1819,  0x04790490},
+{11400000, DIF_BPF_COEFF2021,  0xfbadf8ed},
+{11400000, DIF_BPF_COEFF2223,  0x032f098e},
+{11400000, DIF_BPF_COEFF2425,  0xff10f47d},
+{11400000, DIF_BPF_COEFF2627,  0xfdaf0c75},
+{11400000, DIF_BPF_COEFF2829,  0x063cf3fc},
+{11400000, DIF_BPF_COEFF3031,  0xf5ba0a0b},
+{11400000, DIF_BPF_COEFF3233,  0x0dccf952},
+{11400000, DIF_BPF_COEFF3435,  0xefcd0258},
+{11400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 114_quant.dat*/
+
+
+/*case 11500000:*/
+/* BEGIN - DIF BPF register values from 115_quant.dat*/
+{11500000, DIF_BPF_COEFF01,    0x00000003},
+{11500000, DIF_BPF_COEFF23,    0x0004fff1},
+{11500000, DIF_BPF_COEFF45,    0xffea0026},
+{11500000, DIF_BPF_COEFF67,    0x0046ffc3},
+{11500000, DIF_BPF_COEFF89,    0xff5a003c},
+{11500000, DIF_BPF_COEFF1011,  0x013b0000},
+{11500000, DIF_BPF_COEFF1213,  0xfe04ff63},
+{11500000, DIF_BPF_COEFF1415,  0x02c801b8},
+{11500000, DIF_BPF_COEFF1617,  0xfc99fca6},
+{11500000, DIF_BPF_COEFF1819,  0x0397056a},
+{11500000, DIF_BPF_COEFF2021,  0xfcecf853},
+{11500000, DIF_BPF_COEFF2223,  0x01ad09c9},
+{11500000, DIF_BPF_COEFF2425,  0x00acf4ad},
+{11500000, DIF_BPF_COEFF2627,  0xfc2e0be7},
+{11500000, DIF_BPF_COEFF2829,  0x0773f4c2},
+{11500000, DIF_BPF_COEFF3031,  0xf4e90943},
+{11500000, DIF_BPF_COEFF3233,  0x0e35f9e6},
+{11500000, DIF_BPF_COEFF3435,  0xefb10221},
+{11500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 115_quant.dat*/
+
+
+/*case 11600000:*/
+/* BEGIN - DIF BPF register values from 116_quant.dat*/
+{11600000, DIF_BPF_COEFF01,    0x00000002},
+{11600000, DIF_BPF_COEFF23,    0x0007fff6},
+{11600000, DIF_BPF_COEFF45,    0xffe20014},
+{11600000, DIF_BPF_COEFF67,    0x0054ffee},
+{11600000, DIF_BPF_COEFF89,    0xff4effeb},
+{11600000, DIF_BPF_COEFF1011,  0x0137007e},
+{11600000, DIF_BPF_COEFF1213,  0xfe2efebb},
+{11600000, DIF_BPF_COEFF1415,  0x0260027a},
+{11600000, DIF_BPF_COEFF1617,  0xfd51fbe6},
+{11600000, DIF_BPF_COEFF1819,  0x02870605},
+{11600000, DIF_BPF_COEFF2021,  0xfe4af7fe},
+{11600000, DIF_BPF_COEFF2223,  0x001d09c1},
+{11600000, DIF_BPF_COEFF2425,  0x0243f515},
+{11600000, DIF_BPF_COEFF2627,  0xfabd0b32},
+{11600000, DIF_BPF_COEFF2829,  0x0897f59e},
+{11600000, DIF_BPF_COEFF3031,  0xf4280871},
+{11600000, DIF_BPF_COEFF3233,  0x0e95fa7c},
+{11600000, DIF_BPF_COEFF3435,  0xef9701eb},
+{11600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 116_quant.dat*/
+
+
+/*case 11700000:*/
+/* BEGIN - DIF BPF register values from 117_quant.dat*/
+{11700000, DIF_BPF_COEFF01,    0xffff0001},
+{11700000, DIF_BPF_COEFF23,    0x0008fffd},
+{11700000, DIF_BPF_COEFF45,    0xffdeffff},
+{11700000, DIF_BPF_COEFF67,    0x0056001d},
+{11700000, DIF_BPF_COEFF89,    0xff57ff9c},
+{11700000, DIF_BPF_COEFF1011,  0x011300f0},
+{11700000, DIF_BPF_COEFF1213,  0xfe82fe2e},
+{11700000, DIF_BPF_COEFF1415,  0x01ca0310},
+{11700000, DIF_BPF_COEFF1617,  0xfe35fb62},
+{11700000, DIF_BPF_COEFF1819,  0x0155065a},
+{11700000, DIF_BPF_COEFF2021,  0xffbaf7f2},
+{11700000, DIF_BPF_COEFF2223,  0xfe8c0977},
+{11700000, DIF_BPF_COEFF2425,  0x03cef5b2},
+{11700000, DIF_BPF_COEFF2627,  0xf9610a58},
+{11700000, DIF_BPF_COEFF2829,  0x09a5f68f},
+{11700000, DIF_BPF_COEFF3031,  0xf3790797},
+{11700000, DIF_BPF_COEFF3233,  0x0eebfb14},
+{11700000, DIF_BPF_COEFF3435,  0xef8001b5},
+{11700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 117_quant.dat*/
+
+
+/*case 11800000:*/
+/* BEGIN - DIF BPF register values from 118_quant.dat*/
+{11800000, DIF_BPF_COEFF01,    0xffff0000},
+{11800000, DIF_BPF_COEFF23,    0x00080004},
+{11800000, DIF_BPF_COEFF45,    0xffe0ffe9},
+{11800000, DIF_BPF_COEFF67,    0x004c0047},
+{11800000, DIF_BPF_COEFF89,    0xff75ff58},
+{11800000, DIF_BPF_COEFF1011,  0x00d1014a},
+{11800000, DIF_BPF_COEFF1213,  0xfef9fdc8},
+{11800000, DIF_BPF_COEFF1415,  0x0111036f},
+{11800000, DIF_BPF_COEFF1617,  0xff36fb21},
+{11800000, DIF_BPF_COEFF1819,  0x00120665},
+{11800000, DIF_BPF_COEFF2021,  0x012df82e},
+{11800000, DIF_BPF_COEFF2223,  0xfd0708ec},
+{11800000, DIF_BPF_COEFF2425,  0x0542f682},
+{11800000, DIF_BPF_COEFF2627,  0xf81f095c},
+{11800000, DIF_BPF_COEFF2829,  0x0a9af792},
+{11800000, DIF_BPF_COEFF3031,  0xf2db06b5},
+{11800000, DIF_BPF_COEFF3233,  0x0f38fbad},
+{11800000, DIF_BPF_COEFF3435,  0xef6c017e},
+{11800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 118_quant.dat*/
+
+
+/*case 11900000:*/
+/* BEGIN - DIF BPF register values from 119_quant.dat*/
+{11900000, DIF_BPF_COEFF01,    0xffffffff},
+{11900000, DIF_BPF_COEFF23,    0x0007000b},
+{11900000, DIF_BPF_COEFF45,    0xffe7ffd8},
+{11900000, DIF_BPF_COEFF67,    0x00370068},
+{11900000, DIF_BPF_COEFF89,    0xffa4ff28},
+{11900000, DIF_BPF_COEFF1011,  0x00790184},
+{11900000, DIF_BPF_COEFF1213,  0xff87fd91},
+{11900000, DIF_BPF_COEFF1415,  0x00430392},
+{11900000, DIF_BPF_COEFF1617,  0x0044fb26},
+{11900000, DIF_BPF_COEFF1819,  0xfece0626},
+{11900000, DIF_BPF_COEFF2021,  0x0294f8b2},
+{11900000, DIF_BPF_COEFF2223,  0xfb990825},
+{11900000, DIF_BPF_COEFF2425,  0x0698f77f},
+{11900000, DIF_BPF_COEFF2627,  0xf6fe0842},
+{11900000, DIF_BPF_COEFF2829,  0x0b73f8a7},
+{11900000, DIF_BPF_COEFF3031,  0xf25105cd},
+{11900000, DIF_BPF_COEFF3233,  0x0f7bfc48},
+{11900000, DIF_BPF_COEFF3435,  0xef5a0148},
+{11900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 119_quant.dat*/
+
+
+/*case 12000000:*/
+/* BEGIN - DIF BPF register values from 120_quant.dat*/
+{12000000, DIF_BPF_COEFF01,    0x0000fffe},
+{12000000, DIF_BPF_COEFF23,    0x00050010},
+{12000000, DIF_BPF_COEFF45,    0xfff2ffcc},
+{12000000, DIF_BPF_COEFF67,    0x001b007b},
+{12000000, DIF_BPF_COEFF89,    0xffdfff10},
+{12000000, DIF_BPF_COEFF1011,  0x00140198},
+{12000000, DIF_BPF_COEFF1213,  0x0020fd8e},
+{12000000, DIF_BPF_COEFF1415,  0xff710375},
+{12000000, DIF_BPF_COEFF1617,  0x014dfb73},
+{12000000, DIF_BPF_COEFF1819,  0xfd9a059f},
+{12000000, DIF_BPF_COEFF2021,  0x03e0f978},
+{12000000, DIF_BPF_COEFF2223,  0xfa4e0726},
+{12000000, DIF_BPF_COEFF2425,  0x07c8f8a7},
+{12000000, DIF_BPF_COEFF2627,  0xf600070c},
+{12000000, DIF_BPF_COEFF2829,  0x0c2ff9c9},
+{12000000, DIF_BPF_COEFF3031,  0xf1db04de},
+{12000000, DIF_BPF_COEFF3233,  0x0fb4fce5},
+{12000000, DIF_BPF_COEFF3435,  0xef4b0111},
+{12000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 120_quant.dat*/
+
+
+/*case 12100000:*/
+/* BEGIN - DIF BPF register values from 121_quant.dat*/
+{12100000, DIF_BPF_COEFF01,    0x0000fffd},
+{12100000, DIF_BPF_COEFF23,    0x00010012},
+{12100000, DIF_BPF_COEFF45,    0xffffffc8},
+{12100000, DIF_BPF_COEFF67,    0xfffb007e},
+{12100000, DIF_BPF_COEFF89,    0x001dff14},
+{12100000, DIF_BPF_COEFF1011,  0xffad0184},
+{12100000, DIF_BPF_COEFF1213,  0x00b7fdbe},
+{12100000, DIF_BPF_COEFF1415,  0xfea9031b},
+{12100000, DIF_BPF_COEFF1617,  0x0241fc01},
+{12100000, DIF_BPF_COEFF1819,  0xfc8504d6},
+{12100000, DIF_BPF_COEFF2021,  0x0504fa79},
+{12100000, DIF_BPF_COEFF2223,  0xf93005f6},
+{12100000, DIF_BPF_COEFF2425,  0x08caf9f2},
+{12100000, DIF_BPF_COEFF2627,  0xf52b05c0},
+{12100000, DIF_BPF_COEFF2829,  0x0ccbfaf9},
+{12100000, DIF_BPF_COEFF3031,  0xf17903eb},
+{12100000, DIF_BPF_COEFF3233,  0x0fe3fd83},
+{12100000, DIF_BPF_COEFF3435,  0xef3f00db},
+{12100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 121_quant.dat*/
+
+
+/*case 12200000:*/
+/* BEGIN - DIF BPF register values from 122_quant.dat*/
+{12200000, DIF_BPF_COEFF01,    0x0000fffd},
+{12200000, DIF_BPF_COEFF23,    0xfffe0011},
+{12200000, DIF_BPF_COEFF45,    0x000cffcc},
+{12200000, DIF_BPF_COEFF67,    0xffdb0071},
+{12200000, DIF_BPF_COEFF89,    0x0058ff32},
+{12200000, DIF_BPF_COEFF1011,  0xff4f014a},
+{12200000, DIF_BPF_COEFF1213,  0x013cfe1f},
+{12200000, DIF_BPF_COEFF1415,  0xfdfb028a},
+{12200000, DIF_BPF_COEFF1617,  0x0311fcc9},
+{12200000, DIF_BPF_COEFF1819,  0xfb9d03d6},
+{12200000, DIF_BPF_COEFF2021,  0x05f4fbad},
+{12200000, DIF_BPF_COEFF2223,  0xf848049d},
+{12200000, DIF_BPF_COEFF2425,  0x0999fb5b},
+{12200000, DIF_BPF_COEFF2627,  0xf4820461},
+{12200000, DIF_BPF_COEFF2829,  0x0d46fc32},
+{12200000, DIF_BPF_COEFF3031,  0xf12d02f4},
+{12200000, DIF_BPF_COEFF3233,  0x1007fe21},
+{12200000, DIF_BPF_COEFF3435,  0xef3600a4},
+{12200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 122_quant.dat*/
+
+
+/*case 12300000:*/
+/* BEGIN - DIF BPF register values from 123_quant.dat*/
+{12300000, DIF_BPF_COEFF01,    0x0000fffe},
+{12300000, DIF_BPF_COEFF23,    0xfffa000e},
+{12300000, DIF_BPF_COEFF45,    0x0017ffd9},
+{12300000, DIF_BPF_COEFF67,    0xffc10055},
+{12300000, DIF_BPF_COEFF89,    0x0088ff68},
+{12300000, DIF_BPF_COEFF1011,  0xff0400f0},
+{12300000, DIF_BPF_COEFF1213,  0x01a6fea7},
+{12300000, DIF_BPF_COEFF1415,  0xfd7501cc},
+{12300000, DIF_BPF_COEFF1617,  0x03b0fdc0},
+{12300000, DIF_BPF_COEFF1819,  0xfaef02a8},
+{12300000, DIF_BPF_COEFF2021,  0x06a7fd07},
+{12300000, DIF_BPF_COEFF2223,  0xf79d0326},
+{12300000, DIF_BPF_COEFF2425,  0x0a31fcda},
+{12300000, DIF_BPF_COEFF2627,  0xf40702f3},
+{12300000, DIF_BPF_COEFF2829,  0x0d9ffd72},
+{12300000, DIF_BPF_COEFF3031,  0xf0f601fa},
+{12300000, DIF_BPF_COEFF3233,  0x1021fec0},
+{12300000, DIF_BPF_COEFF3435,  0xef2f006d},
+{12300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 123_quant.dat*/
+
+
+/*case 12400000:*/
+/* BEGIN - DIF BPF register values from 124_quant.dat*/
+{12400000, DIF_BPF_COEFF01,    0x0001ffff},
+{12400000, DIF_BPF_COEFF23,    0xfff80007},
+{12400000, DIF_BPF_COEFF45,    0x001fffeb},
+{12400000, DIF_BPF_COEFF67,    0xffaf002d},
+{12400000, DIF_BPF_COEFF89,    0x00a8ffb0},
+{12400000, DIF_BPF_COEFF1011,  0xfed3007e},
+{12400000, DIF_BPF_COEFF1213,  0x01e9ff4c},
+{12400000, DIF_BPF_COEFF1415,  0xfd2000ee},
+{12400000, DIF_BPF_COEFF1617,  0x0413fed8},
+{12400000, DIF_BPF_COEFF1819,  0xfa82015c},
+{12400000, DIF_BPF_COEFF2021,  0x0715fe7d},
+{12400000, DIF_BPF_COEFF2223,  0xf7340198},
+{12400000, DIF_BPF_COEFF2425,  0x0a8dfe69},
+{12400000, DIF_BPF_COEFF2627,  0xf3bd017c},
+{12400000, DIF_BPF_COEFF2829,  0x0dd5feb8},
+{12400000, DIF_BPF_COEFF3031,  0xf0d500fd},
+{12400000, DIF_BPF_COEFF3233,  0x1031ff60},
+{12400000, DIF_BPF_COEFF3435,  0xef2b0037},
+{12400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 124_quant.dat*/
+
+
+/*case 12500000:*/
+/* BEGIN - DIF BPF register values from 125_quant.dat*/
+{12500000, DIF_BPF_COEFF01,    0x00010000},
+{12500000, DIF_BPF_COEFF23,    0xfff70000},
+{12500000, DIF_BPF_COEFF45,    0x00220000},
+{12500000, DIF_BPF_COEFF67,    0xffa90000},
+{12500000, DIF_BPF_COEFF89,    0x00b30000},
+{12500000, DIF_BPF_COEFF1011,  0xfec20000},
+{12500000, DIF_BPF_COEFF1213,  0x02000000},
+{12500000, DIF_BPF_COEFF1415,  0xfd030000},
+{12500000, DIF_BPF_COEFF1617,  0x04350000},
+{12500000, DIF_BPF_COEFF1819,  0xfa5e0000},
+{12500000, DIF_BPF_COEFF2021,  0x073b0000},
+{12500000, DIF_BPF_COEFF2223,  0xf7110000},
+{12500000, DIF_BPF_COEFF2425,  0x0aac0000},
+{12500000, DIF_BPF_COEFF2627,  0xf3a40000},
+{12500000, DIF_BPF_COEFF2829,  0x0de70000},
+{12500000, DIF_BPF_COEFF3031,  0xf0c90000},
+{12500000, DIF_BPF_COEFF3233,  0x10360000},
+{12500000, DIF_BPF_COEFF3435,  0xef290000},
+{12500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 125_quant.dat*/
+
+
+/*case 12600000:*/
+/* BEGIN - DIF BPF register values from 126_quant.dat*/
+{12600000, DIF_BPF_COEFF01,    0x00010001},
+{12600000, DIF_BPF_COEFF23,    0xfff8fff9},
+{12600000, DIF_BPF_COEFF45,    0x001f0015},
+{12600000, DIF_BPF_COEFF67,    0xffafffd3},
+{12600000, DIF_BPF_COEFF89,    0x00a80050},
+{12600000, DIF_BPF_COEFF1011,  0xfed3ff82},
+{12600000, DIF_BPF_COEFF1213,  0x01e900b4},
+{12600000, DIF_BPF_COEFF1415,  0xfd20ff12},
+{12600000, DIF_BPF_COEFF1617,  0x04130128},
+{12600000, DIF_BPF_COEFF1819,  0xfa82fea4},
+{12600000, DIF_BPF_COEFF2021,  0x07150183},
+{12600000, DIF_BPF_COEFF2223,  0xf734fe68},
+{12600000, DIF_BPF_COEFF2425,  0x0a8d0197},
+{12600000, DIF_BPF_COEFF2627,  0xf3bdfe84},
+{12600000, DIF_BPF_COEFF2829,  0x0dd50148},
+{12600000, DIF_BPF_COEFF3031,  0xf0d5ff03},
+{12600000, DIF_BPF_COEFF3233,  0x103100a0},
+{12600000, DIF_BPF_COEFF3435,  0xef2bffc9},
+{12600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 126_quant.dat*/
+
+
+/*case 12700000:*/
+/* BEGIN - DIF BPF register values from 127_quant.dat*/
+{12700000, DIF_BPF_COEFF01,    0x00000002},
+{12700000, DIF_BPF_COEFF23,    0xfffafff2},
+{12700000, DIF_BPF_COEFF45,    0x00170027},
+{12700000, DIF_BPF_COEFF67,    0xffc1ffab},
+{12700000, DIF_BPF_COEFF89,    0x00880098},
+{12700000, DIF_BPF_COEFF1011,  0xff04ff10},
+{12700000, DIF_BPF_COEFF1213,  0x01a60159},
+{12700000, DIF_BPF_COEFF1415,  0xfd75fe34},
+{12700000, DIF_BPF_COEFF1617,  0x03b00240},
+{12700000, DIF_BPF_COEFF1819,  0xfaeffd58},
+{12700000, DIF_BPF_COEFF2021,  0x06a702f9},
+{12700000, DIF_BPF_COEFF2223,  0xf79dfcda},
+{12700000, DIF_BPF_COEFF2425,  0x0a310326},
+{12700000, DIF_BPF_COEFF2627,  0xf407fd0d},
+{12700000, DIF_BPF_COEFF2829,  0x0d9f028e},
+{12700000, DIF_BPF_COEFF3031,  0xf0f6fe06},
+{12700000, DIF_BPF_COEFF3233,  0x10210140},
+{12700000, DIF_BPF_COEFF3435,  0xef2fff93},
+{12700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 127_quant.dat*/
+
+
+/*case 12800000:*/
+/* BEGIN - DIF BPF register values from 128_quant.dat*/
+{12800000, DIF_BPF_COEFF01,    0x00000003},
+{12800000, DIF_BPF_COEFF23,    0xfffeffef},
+{12800000, DIF_BPF_COEFF45,    0x000c0034},
+{12800000, DIF_BPF_COEFF67,    0xffdbff8f},
+{12800000, DIF_BPF_COEFF89,    0x005800ce},
+{12800000, DIF_BPF_COEFF1011,  0xff4ffeb6},
+{12800000, DIF_BPF_COEFF1213,  0x013c01e1},
+{12800000, DIF_BPF_COEFF1415,  0xfdfbfd76},
+{12800000, DIF_BPF_COEFF1617,  0x03110337},
+{12800000, DIF_BPF_COEFF1819,  0xfb9dfc2a},
+{12800000, DIF_BPF_COEFF2021,  0x05f40453},
+{12800000, DIF_BPF_COEFF2223,  0xf848fb63},
+{12800000, DIF_BPF_COEFF2425,  0x099904a5},
+{12800000, DIF_BPF_COEFF2627,  0xf482fb9f},
+{12800000, DIF_BPF_COEFF2829,  0x0d4603ce},
+{12800000, DIF_BPF_COEFF3031,  0xf12dfd0c},
+{12800000, DIF_BPF_COEFF3233,  0x100701df},
+{12800000, DIF_BPF_COEFF3435,  0xef36ff5c},
+{12800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 128_quant.dat*/
+
+
+/*case 12900000:*/
+/* BEGIN - DIF BPF register values from 129_quant.dat*/
+{12900000, DIF_BPF_COEFF01,    0x00000003},
+{12900000, DIF_BPF_COEFF23,    0x0001ffee},
+{12900000, DIF_BPF_COEFF45,    0xffff0038},
+{12900000, DIF_BPF_COEFF67,    0xfffbff82},
+{12900000, DIF_BPF_COEFF89,    0x001d00ec},
+{12900000, DIF_BPF_COEFF1011,  0xffadfe7c},
+{12900000, DIF_BPF_COEFF1213,  0x00b70242},
+{12900000, DIF_BPF_COEFF1415,  0xfea9fce5},
+{12900000, DIF_BPF_COEFF1617,  0x024103ff},
+{12900000, DIF_BPF_COEFF1819,  0xfc85fb2a},
+{12900000, DIF_BPF_COEFF2021,  0x05040587},
+{12900000, DIF_BPF_COEFF2223,  0xf930fa0a},
+{12900000, DIF_BPF_COEFF2425,  0x08ca060e},
+{12900000, DIF_BPF_COEFF2627,  0xf52bfa40},
+{12900000, DIF_BPF_COEFF2829,  0x0ccb0507},
+{12900000, DIF_BPF_COEFF3031,  0xf179fc15},
+{12900000, DIF_BPF_COEFF3233,  0x0fe3027d},
+{12900000, DIF_BPF_COEFF3435,  0xef3fff25},
+{12900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 129_quant.dat*/
+
+
+/*case 113000000:*/
+/* BEGIN - DIF BPF register values from 130_quant.dat*/
+{13000000, DIF_BPF_COEFF01,    0x00000002},
+{13000000, DIF_BPF_COEFF23,    0x0005fff0},
+{13000000, DIF_BPF_COEFF45,    0xfff20034},
+{13000000, DIF_BPF_COEFF67,    0x001bff85},
+{13000000, DIF_BPF_COEFF89,    0xffdf00f0},
+{13000000, DIF_BPF_COEFF1011,  0x0014fe68},
+{13000000, DIF_BPF_COEFF1213,  0x00200272},
+{13000000, DIF_BPF_COEFF1415,  0xff71fc8b},
+{13000000, DIF_BPF_COEFF1617,  0x014d048d},
+{13000000, DIF_BPF_COEFF1819,  0xfd9afa61},
+{13000000, DIF_BPF_COEFF2021,  0x03e00688},
+{13000000, DIF_BPF_COEFF2223,  0xfa4ef8da},
+{13000000, DIF_BPF_COEFF2425,  0x07c80759},
+{13000000, DIF_BPF_COEFF2627,  0xf600f8f4},
+{13000000, DIF_BPF_COEFF2829,  0x0c2f0637},
+{13000000, DIF_BPF_COEFF3031,  0xf1dbfb22},
+{13000000, DIF_BPF_COEFF3233,  0x0fb4031b},
+{13000000, DIF_BPF_COEFF3435,  0xef4bfeef},
+{13000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 130_quant.dat*/
+
+
+/*case 13100000:*/
+/* BEGIN - DIF BPF register values from 131_quant.dat*/
+{13100000, DIF_BPF_COEFF01,    0xffff0001},
+{13100000, DIF_BPF_COEFF23,    0x0007fff5},
+{13100000, DIF_BPF_COEFF45,    0xffe70028},
+{13100000, DIF_BPF_COEFF67,    0x0037ff98},
+{13100000, DIF_BPF_COEFF89,    0xffa400d8},
+{13100000, DIF_BPF_COEFF1011,  0x0079fe7c},
+{13100000, DIF_BPF_COEFF1213,  0xff87026f},
+{13100000, DIF_BPF_COEFF1415,  0x0043fc6e},
+{13100000, DIF_BPF_COEFF1617,  0x004404da},
+{13100000, DIF_BPF_COEFF1819,  0xfecef9da},
+{13100000, DIF_BPF_COEFF2021,  0x0294074e},
+{13100000, DIF_BPF_COEFF2223,  0xfb99f7db},
+{13100000, DIF_BPF_COEFF2425,  0x06980881},
+{13100000, DIF_BPF_COEFF2627,  0xf6fef7be},
+{13100000, DIF_BPF_COEFF2829,  0x0b730759},
+{13100000, DIF_BPF_COEFF3031,  0xf251fa33},
+{13100000, DIF_BPF_COEFF3233,  0x0f7b03b8},
+{13100000, DIF_BPF_COEFF3435,  0xef5afeb8},
+{13100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 131_quant.dat*/
+
+
+/*case 13200000:*/
+/* BEGIN - DIF BPF register values from 132_quant.dat*/
+{13200000, DIF_BPF_COEFF01,    0xffff0000},
+{13200000, DIF_BPF_COEFF23,    0x0008fffc},
+{13200000, DIF_BPF_COEFF45,    0xffe00017},
+{13200000, DIF_BPF_COEFF67,    0x004cffb9},
+{13200000, DIF_BPF_COEFF89,    0xff7500a8},
+{13200000, DIF_BPF_COEFF1011,  0x00d1feb6},
+{13200000, DIF_BPF_COEFF1213,  0xfef90238},
+{13200000, DIF_BPF_COEFF1415,  0x0111fc91},
+{13200000, DIF_BPF_COEFF1617,  0xff3604df},
+{13200000, DIF_BPF_COEFF1819,  0x0012f99b},
+{13200000, DIF_BPF_COEFF2021,  0x012d07d2},
+{13200000, DIF_BPF_COEFF2223,  0xfd07f714},
+{13200000, DIF_BPF_COEFF2425,  0x0542097e},
+{13200000, DIF_BPF_COEFF2627,  0xf81ff6a4},
+{13200000, DIF_BPF_COEFF2829,  0x0a9a086e},
+{13200000, DIF_BPF_COEFF3031,  0xf2dbf94b},
+{13200000, DIF_BPF_COEFF3233,  0x0f380453},
+{13200000, DIF_BPF_COEFF3435,  0xef6cfe82},
+{13200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 132_quant.dat*/
+
+
+/*case 13300000:*/
+/* BEGIN - DIF BPF register values from 133_quant.dat*/
+{13300000, DIF_BPF_COEFF01,    0xffffffff},
+{13300000, DIF_BPF_COEFF23,    0x00080003},
+{13300000, DIF_BPF_COEFF45,    0xffde0001},
+{13300000, DIF_BPF_COEFF67,    0x0056ffe3},
+{13300000, DIF_BPF_COEFF89,    0xff570064},
+{13300000, DIF_BPF_COEFF1011,  0x0113ff10},
+{13300000, DIF_BPF_COEFF1213,  0xfe8201d2},
+{13300000, DIF_BPF_COEFF1415,  0x01cafcf0},
+{13300000, DIF_BPF_COEFF1617,  0xfe35049e},
+{13300000, DIF_BPF_COEFF1819,  0x0155f9a6},
+{13300000, DIF_BPF_COEFF2021,  0xffba080e},
+{13300000, DIF_BPF_COEFF2223,  0xfe8cf689},
+{13300000, DIF_BPF_COEFF2425,  0x03ce0a4e},
+{13300000, DIF_BPF_COEFF2627,  0xf961f5a8},
+{13300000, DIF_BPF_COEFF2829,  0x09a50971},
+{13300000, DIF_BPF_COEFF3031,  0xf379f869},
+{13300000, DIF_BPF_COEFF3233,  0x0eeb04ec},
+{13300000, DIF_BPF_COEFF3435,  0xef80fe4b},
+{13300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 133_quant.dat*/
+
+
+/*case 13400000:*/
+/* BEGIN - DIF BPF register values from 134_quant.dat*/
+{13400000, DIF_BPF_COEFF01,    0x0000fffe},
+{13400000, DIF_BPF_COEFF23,    0x0007000a},
+{13400000, DIF_BPF_COEFF45,    0xffe2ffec},
+{13400000, DIF_BPF_COEFF67,    0x00540012},
+{13400000, DIF_BPF_COEFF89,    0xff4e0015},
+{13400000, DIF_BPF_COEFF1011,  0x0137ff82},
+{13400000, DIF_BPF_COEFF1213,  0xfe2e0145},
+{13400000, DIF_BPF_COEFF1415,  0x0260fd86},
+{13400000, DIF_BPF_COEFF1617,  0xfd51041a},
+{13400000, DIF_BPF_COEFF1819,  0x0287f9fb},
+{13400000, DIF_BPF_COEFF2021,  0xfe4a0802},
+{13400000, DIF_BPF_COEFF2223,  0x001df63f},
+{13400000, DIF_BPF_COEFF2425,  0x02430aeb},
+{13400000, DIF_BPF_COEFF2627,  0xfabdf4ce},
+{13400000, DIF_BPF_COEFF2829,  0x08970a62},
+{13400000, DIF_BPF_COEFF3031,  0xf428f78f},
+{13400000, DIF_BPF_COEFF3233,  0x0e950584},
+{13400000, DIF_BPF_COEFF3435,  0xef97fe15},
+{13400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 134_quant.dat*/
+
+
+/*case 13500000:*/
+/* BEGIN - DIF BPF register values from 135_quant.dat*/
+{13500000, DIF_BPF_COEFF01,    0x0000fffd},
+{13500000, DIF_BPF_COEFF23,    0x0004000f},
+{13500000, DIF_BPF_COEFF45,    0xffeaffda},
+{13500000, DIF_BPF_COEFF67,    0x0046003d},
+{13500000, DIF_BPF_COEFF89,    0xff5affc4},
+{13500000, DIF_BPF_COEFF1011,  0x013b0000},
+{13500000, DIF_BPF_COEFF1213,  0xfe04009d},
+{13500000, DIF_BPF_COEFF1415,  0x02c8fe48},
+{13500000, DIF_BPF_COEFF1617,  0xfc99035a},
+{13500000, DIF_BPF_COEFF1819,  0x0397fa96},
+{13500000, DIF_BPF_COEFF2021,  0xfcec07ad},
+{13500000, DIF_BPF_COEFF2223,  0x01adf637},
+{13500000, DIF_BPF_COEFF2425,  0x00ac0b53},
+{13500000, DIF_BPF_COEFF2627,  0xfc2ef419},
+{13500000, DIF_BPF_COEFF2829,  0x07730b3e},
+{13500000, DIF_BPF_COEFF3031,  0xf4e9f6bd},
+{13500000, DIF_BPF_COEFF3233,  0x0e35061a},
+{13500000, DIF_BPF_COEFF3435,  0xefb1fddf},
+{13500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 135_quant.dat*/
+
+
+/*case 13600000:*/
+/* BEGIN - DIF BPF register values from 136_quant.dat*/
+{13600000, DIF_BPF_COEFF01,    0x0000fffd},
+{13600000, DIF_BPF_COEFF23,    0x00000012},
+{13600000, DIF_BPF_COEFF45,    0xfff6ffcd},
+{13600000, DIF_BPF_COEFF67,    0x002f0061},
+{13600000, DIF_BPF_COEFF89,    0xff7bff79},
+{13600000, DIF_BPF_COEFF1011,  0x011e007e},
+{13600000, DIF_BPF_COEFF1213,  0xfe08ffe8},
+{13600000, DIF_BPF_COEFF1415,  0x02f9ff28},
+{13600000, DIF_BPF_COEFF1617,  0xfc17026a},
+{13600000, DIF_BPF_COEFF1819,  0x0479fb70},
+{13600000, DIF_BPF_COEFF2021,  0xfbad0713},
+{13600000, DIF_BPF_COEFF2223,  0x032ff672},
+{13600000, DIF_BPF_COEFF2425,  0xff100b83},
+{13600000, DIF_BPF_COEFF2627,  0xfdaff38b},
+{13600000, DIF_BPF_COEFF2829,  0x063c0c04},
+{13600000, DIF_BPF_COEFF3031,  0xf5baf5f5},
+{13600000, DIF_BPF_COEFF3233,  0x0dcc06ae},
+{13600000, DIF_BPF_COEFF3435,  0xefcdfda8},
+{13600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 136_quant.dat*/
+
+
+/*case 13700000:*/
+/* BEGIN - DIF BPF register values from 137_quant.dat*/
+{13700000, DIF_BPF_COEFF01,    0x0000fffd},
+{13700000, DIF_BPF_COEFF23,    0xfffd0012},
+{13700000, DIF_BPF_COEFF45,    0x0004ffc8},
+{13700000, DIF_BPF_COEFF67,    0x00100078},
+{13700000, DIF_BPF_COEFF89,    0xffacff3e},
+{13700000, DIF_BPF_COEFF1011,  0x00e200f0},
+{13700000, DIF_BPF_COEFF1213,  0xfe39ff35},
+{13700000, DIF_BPF_COEFF1415,  0x02f10017},
+{13700000, DIF_BPF_COEFF1617,  0xfbd30156},
+{13700000, DIF_BPF_COEFF1819,  0x0521fc7f},
+{13700000, DIF_BPF_COEFF2021,  0xfa9c0638},
+{13700000, DIF_BPF_COEFF2223,  0x0499f6ee},
+{13700000, DIF_BPF_COEFF2425,  0xfd7a0b7c},
+{13700000, DIF_BPF_COEFF2627,  0xff39f325},
+{13700000, DIF_BPF_COEFF2829,  0x04f40cb3},
+{13700000, DIF_BPF_COEFF3031,  0xf69af537},
+{13700000, DIF_BPF_COEFF3233,  0x0d5a073f},
+{13700000, DIF_BPF_COEFF3435,  0xefecfd72},
+{13700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 137_quant.dat*/
+
+
+/*case 13800000:*/
+/* BEGIN - DIF BPF register values from 138_quant.dat*/
+{13800000, DIF_BPF_COEFF01,    0x0001fffe},
+{13800000, DIF_BPF_COEFF23,    0xfffa000e},
+{13800000, DIF_BPF_COEFF45,    0x0011ffcb},
+{13800000, DIF_BPF_COEFF67,    0xfff0007f},
+{13800000, DIF_BPF_COEFF89,    0xffe7ff19},
+{13800000, DIF_BPF_COEFF1011,  0x008f014a},
+{13800000, DIF_BPF_COEFF1213,  0xfe94fe93},
+{13800000, DIF_BPF_COEFF1415,  0x02b00105},
+{13800000, DIF_BPF_COEFF1617,  0xfbd3002f},
+{13800000, DIF_BPF_COEFF1819,  0x0585fdb7},
+{13800000, DIF_BPF_COEFF2021,  0xf9c10525},
+{13800000, DIF_BPF_COEFF2223,  0x05def7a8},
+{13800000, DIF_BPF_COEFF2425,  0xfbf20b3c},
+{13800000, DIF_BPF_COEFF2627,  0x00c7f2e9},
+{13800000, DIF_BPF_COEFF2829,  0x03a00d48},
+{13800000, DIF_BPF_COEFF3031,  0xf787f484},
+{13800000, DIF_BPF_COEFF3233,  0x0cdf07cd},
+{13800000, DIF_BPF_COEFF3435,  0xf00dfd3c},
+{13800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 138_quant.dat*/
+
+
+/*case 13900000:*/
+/* BEGIN - DIF BPF register values from 139_quant.dat*/
+{13900000, DIF_BPF_COEFF01,    0x00010000},
+{13900000, DIF_BPF_COEFF23,    0xfff80008},
+{13900000, DIF_BPF_COEFF45,    0x001bffd7},
+{13900000, DIF_BPF_COEFF67,    0xffd10076},
+{13900000, DIF_BPF_COEFF89,    0x0026ff0e},
+{13900000, DIF_BPF_COEFF1011,  0x002c0184},
+{13900000, DIF_BPF_COEFF1213,  0xff0ffe10},
+{13900000, DIF_BPF_COEFF1415,  0x023b01e0},
+{13900000, DIF_BPF_COEFF1617,  0xfc17ff06},
+{13900000, DIF_BPF_COEFF1819,  0x05a2ff09},
+{13900000, DIF_BPF_COEFF2021,  0xf92703e4},
+{13900000, DIF_BPF_COEFF2223,  0x06f4f89b},
+{13900000, DIF_BPF_COEFF2425,  0xfa820ac5},
+{13900000, DIF_BPF_COEFF2627,  0x0251f2d9},
+{13900000, DIF_BPF_COEFF2829,  0x02430dc3},
+{13900000, DIF_BPF_COEFF3031,  0xf881f3dc},
+{13900000, DIF_BPF_COEFF3233,  0x0c5c0859},
+{13900000, DIF_BPF_COEFF3435,  0xf031fd06},
+{13900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 139_quant.dat*/
+
+
+/*case 14000000:*/
+/* BEGIN - DIF BPF register values from 140_quant.dat*/
+{14000000, DIF_BPF_COEFF01,    0x00010001},
+{14000000, DIF_BPF_COEFF23,    0xfff80001},
+{14000000, DIF_BPF_COEFF45,    0x0021ffe8},
+{14000000, DIF_BPF_COEFF67,    0xffba005d},
+{14000000, DIF_BPF_COEFF89,    0x0060ff1f},
+{14000000, DIF_BPF_COEFF1011,  0xffc40198},
+{14000000, DIF_BPF_COEFF1213,  0xffa0fdb5},
+{14000000, DIF_BPF_COEFF1415,  0x019a029a},
+{14000000, DIF_BPF_COEFF1617,  0xfc99fdea},
+{14000000, DIF_BPF_COEFF1819,  0x05750067},
+{14000000, DIF_BPF_COEFF2021,  0xf8d4027f},
+{14000000, DIF_BPF_COEFF2223,  0x07d4f9c0},
+{14000000, DIF_BPF_COEFF2425,  0xf9320a1a},
+{14000000, DIF_BPF_COEFF2627,  0x03d2f2f3},
+{14000000, DIF_BPF_COEFF2829,  0x00df0e22},
+{14000000, DIF_BPF_COEFF3031,  0xf986f341},
+{14000000, DIF_BPF_COEFF3233,  0x0bd108e2},
+{14000000, DIF_BPF_COEFF3435,  0xf058fcd1},
+{14000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 140_quant.dat*/
+
+
+/*case 14100000:*/
+/* BEGIN - DIF BPF register values from 141_quant.dat*/
+{14100000, DIF_BPF_COEFF01,    0x00000002},
+{14100000, DIF_BPF_COEFF23,    0xfff9fffa},
+{14100000, DIF_BPF_COEFF45,    0x0021fffd},
+{14100000, DIF_BPF_COEFF67,    0xffac0038},
+{14100000, DIF_BPF_COEFF89,    0x008eff4a},
+{14100000, DIF_BPF_COEFF1011,  0xff630184},
+{14100000, DIF_BPF_COEFF1213,  0x003afd8b},
+{14100000, DIF_BPF_COEFF1415,  0x00da0326},
+{14100000, DIF_BPF_COEFF1617,  0xfd51fced},
+{14100000, DIF_BPF_COEFF1819,  0x050101c0},
+{14100000, DIF_BPF_COEFF2021,  0xf8cb0103},
+{14100000, DIF_BPF_COEFF2223,  0x0876fb10},
+{14100000, DIF_BPF_COEFF2425,  0xf80a093e},
+{14100000, DIF_BPF_COEFF2627,  0x0543f338},
+{14100000, DIF_BPF_COEFF2829,  0xff7a0e66},
+{14100000, DIF_BPF_COEFF3031,  0xfa94f2b2},
+{14100000, DIF_BPF_COEFF3233,  0x0b3f0967},
+{14100000, DIF_BPF_COEFF3435,  0xf081fc9b},
+{14100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 141_quant.dat*/
+
+
+/*case 14200000:*/
+/* BEGIN - DIF BPF register values from 142_quant.dat*/
+{14200000, DIF_BPF_COEFF01,    0x00000003},
+{14200000, DIF_BPF_COEFF23,    0xfffbfff3},
+{14200000, DIF_BPF_COEFF45,    0x001d0013},
+{14200000, DIF_BPF_COEFF67,    0xffaa000b},
+{14200000, DIF_BPF_COEFF89,    0x00aaff89},
+{14200000, DIF_BPF_COEFF1011,  0xff13014a},
+{14200000, DIF_BPF_COEFF1213,  0x00cefd95},
+{14200000, DIF_BPF_COEFF1415,  0x000a037b},
+{14200000, DIF_BPF_COEFF1617,  0xfe35fc1d},
+{14200000, DIF_BPF_COEFF1819,  0x044c0305},
+{14200000, DIF_BPF_COEFF2021,  0xf90cff7e},
+{14200000, DIF_BPF_COEFF2223,  0x08d5fc81},
+{14200000, DIF_BPF_COEFF2425,  0xf7100834},
+{14200000, DIF_BPF_COEFF2627,  0x069ff3a7},
+{14200000, DIF_BPF_COEFF2829,  0xfe160e8d},
+{14200000, DIF_BPF_COEFF3031,  0xfbaaf231},
+{14200000, DIF_BPF_COEFF3233,  0x0aa509e9},
+{14200000, DIF_BPF_COEFF3435,  0xf0adfc65},
+{14200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 142_quant.dat*/
+
+
+/*case 14300000:*/
+/* BEGIN - DIF BPF register values from 143_quant.dat*/
+{14300000, DIF_BPF_COEFF01,    0x00000003},
+{14300000, DIF_BPF_COEFF23,    0xffffffef},
+{14300000, DIF_BPF_COEFF45,    0x00140025},
+{14300000, DIF_BPF_COEFF67,    0xffb4ffdd},
+{14300000, DIF_BPF_COEFF89,    0x00b2ffd6},
+{14300000, DIF_BPF_COEFF1011,  0xfedb00f0},
+{14300000, DIF_BPF_COEFF1213,  0x0150fdd3},
+{14300000, DIF_BPF_COEFF1415,  0xff380391},
+{14300000, DIF_BPF_COEFF1617,  0xff36fb85},
+{14300000, DIF_BPF_COEFF1819,  0x035e0426},
+{14300000, DIF_BPF_COEFF2021,  0xf994fdfe},
+{14300000, DIF_BPF_COEFF2223,  0x08eefe0b},
+{14300000, DIF_BPF_COEFF2425,  0xf6490702},
+{14300000, DIF_BPF_COEFF2627,  0x07e1f43e},
+{14300000, DIF_BPF_COEFF2829,  0xfcb60e97},
+{14300000, DIF_BPF_COEFF3031,  0xfcc6f1be},
+{14300000, DIF_BPF_COEFF3233,  0x0a040a67},
+{14300000, DIF_BPF_COEFF3435,  0xf0dbfc30},
+{14300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 143_quant.dat*/
+
+
+/*case 14400000:*/
+/* BEGIN - DIF BPF register values from 144_quant.dat*/
+{14400000, DIF_BPF_COEFF01,    0x00000003},
+{14400000, DIF_BPF_COEFF23,    0x0002ffee},
+{14400000, DIF_BPF_COEFF45,    0x00070033},
+{14400000, DIF_BPF_COEFF67,    0xffc9ffb4},
+{14400000, DIF_BPF_COEFF89,    0x00a40027},
+{14400000, DIF_BPF_COEFF1011,  0xfec3007e},
+{14400000, DIF_BPF_COEFF1213,  0x01b4fe3f},
+{14400000, DIF_BPF_COEFF1415,  0xfe760369},
+{14400000, DIF_BPF_COEFF1617,  0x0044fb2e},
+{14400000, DIF_BPF_COEFF1819,  0x02450518},
+{14400000, DIF_BPF_COEFF2021,  0xfa5ffc90},
+{14400000, DIF_BPF_COEFF2223,  0x08c1ffa1},
+{14400000, DIF_BPF_COEFF2425,  0xf5bc05ae},
+{14400000, DIF_BPF_COEFF2627,  0x0902f4fc},
+{14400000, DIF_BPF_COEFF2829,  0xfb600e85},
+{14400000, DIF_BPF_COEFF3031,  0xfde7f15a},
+{14400000, DIF_BPF_COEFF3233,  0x095d0ae2},
+{14400000, DIF_BPF_COEFF3435,  0xf10cfbfb},
+{14400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 144_quant.dat*/
+
+
+/*case 14500000:*/
+/* BEGIN - DIF BPF register values from 145_quant.dat*/
+{14500000, DIF_BPF_COEFF01,    0xffff0002},
+{14500000, DIF_BPF_COEFF23,    0x0005ffef},
+{14500000, DIF_BPF_COEFF45,    0xfffa0038},
+{14500000, DIF_BPF_COEFF67,    0xffe5ff95},
+{14500000, DIF_BPF_COEFF89,    0x00820074},
+{14500000, DIF_BPF_COEFF1011,  0xfecc0000},
+{14500000, DIF_BPF_COEFF1213,  0x01f0fed0},
+{14500000, DIF_BPF_COEFF1415,  0xfdd20304},
+{14500000, DIF_BPF_COEFF1617,  0x014dfb1d},
+{14500000, DIF_BPF_COEFF1819,  0x010e05ce},
+{14500000, DIF_BPF_COEFF2021,  0xfb64fb41},
+{14500000, DIF_BPF_COEFF2223,  0x084e013b},
+{14500000, DIF_BPF_COEFF2425,  0xf569043e},
+{14500000, DIF_BPF_COEFF2627,  0x0a00f5dd},
+{14500000, DIF_BPF_COEFF2829,  0xfa150e55},
+{14500000, DIF_BPF_COEFF3031,  0xff0bf104},
+{14500000, DIF_BPF_COEFF3233,  0x08b00b59},
+{14500000, DIF_BPF_COEFF3435,  0xf13ffbc6},
+{14500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 145_quant.dat*/
+
+
+/*case 14600000:*/
+/* BEGIN - DIF BPF register values from 146_quant.dat*/
+{14600000, DIF_BPF_COEFF01,    0xffff0001},
+{14600000, DIF_BPF_COEFF23,    0x0008fff4},
+{14600000, DIF_BPF_COEFF45,    0xffed0035},
+{14600000, DIF_BPF_COEFF67,    0x0005ff83},
+{14600000, DIF_BPF_COEFF89,    0x005000b4},
+{14600000, DIF_BPF_COEFF1011,  0xfef6ff82},
+{14600000, DIF_BPF_COEFF1213,  0x01ffff7a},
+{14600000, DIF_BPF_COEFF1415,  0xfd580269},
+{14600000, DIF_BPF_COEFF1617,  0x0241fb53},
+{14600000, DIF_BPF_COEFF1819,  0xffca0640},
+{14600000, DIF_BPF_COEFF2021,  0xfc99fa1e},
+{14600000, DIF_BPF_COEFF2223,  0x079a02cb},
+{14600000, DIF_BPF_COEFF2425,  0xf55502ba},
+{14600000, DIF_BPF_COEFF2627,  0x0ad5f6e0},
+{14600000, DIF_BPF_COEFF2829,  0xf8d90e0a},
+{14600000, DIF_BPF_COEFF3031,  0x0031f0bd},
+{14600000, DIF_BPF_COEFF3233,  0x07fd0bcb},
+{14600000, DIF_BPF_COEFF3435,  0xf174fb91},
+{14600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 146_quant.dat*/
+
+
+/*case 14700000:*/
+/* BEGIN - DIF BPF register values from 147_quant.dat*/
+{14700000, DIF_BPF_COEFF01,    0xffffffff},
+{14700000, DIF_BPF_COEFF23,    0x0009fffb},
+{14700000, DIF_BPF_COEFF45,    0xffe4002a},
+{14700000, DIF_BPF_COEFF67,    0x0025ff82},
+{14700000, DIF_BPF_COEFF89,    0x001400e0},
+{14700000, DIF_BPF_COEFF1011,  0xff3cff10},
+{14700000, DIF_BPF_COEFF1213,  0x01e10030},
+{14700000, DIF_BPF_COEFF1415,  0xfd1201a4},
+{14700000, DIF_BPF_COEFF1617,  0x0311fbcd},
+{14700000, DIF_BPF_COEFF1819,  0xfe88066a},
+{14700000, DIF_BPF_COEFF2021,  0xfdf1f92f},
+{14700000, DIF_BPF_COEFF2223,  0x06aa0449},
+{14700000, DIF_BPF_COEFF2425,  0xf57e0128},
+{14700000, DIF_BPF_COEFF2627,  0x0b7ef801},
+{14700000, DIF_BPF_COEFF2829,  0xf7b00da2},
+{14700000, DIF_BPF_COEFF3031,  0x0156f086},
+{14700000, DIF_BPF_COEFF3233,  0x07450c39},
+{14700000, DIF_BPF_COEFF3435,  0xf1acfb5c},
+{14700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 147_quant.dat*/
+
+
+/*case 14800000:*/
+/* BEGIN - DIF BPF register values from 148_quant.dat*/
+{14800000, DIF_BPF_COEFF01,    0x0000fffe},
+{14800000, DIF_BPF_COEFF23,    0x00080002},
+{14800000, DIF_BPF_COEFF45,    0xffdf0019},
+{14800000, DIF_BPF_COEFF67,    0x003fff92},
+{14800000, DIF_BPF_COEFF89,    0xffd600f1},
+{14800000, DIF_BPF_COEFF1011,  0xff96feb6},
+{14800000, DIF_BPF_COEFF1213,  0x019700e1},
+{14800000, DIF_BPF_COEFF1415,  0xfd0500c2},
+{14800000, DIF_BPF_COEFF1617,  0x03b0fc84},
+{14800000, DIF_BPF_COEFF1819,  0xfd590649},
+{14800000, DIF_BPF_COEFF2021,  0xff5df87f},
+{14800000, DIF_BPF_COEFF2223,  0x058505aa},
+{14800000, DIF_BPF_COEFF2425,  0xf5e4ff91},
+{14800000, DIF_BPF_COEFF2627,  0x0bf9f93c},
+{14800000, DIF_BPF_COEFF2829,  0xf69d0d20},
+{14800000, DIF_BPF_COEFF3031,  0x0279f05e},
+{14800000, DIF_BPF_COEFF3233,  0x06880ca3},
+{14800000, DIF_BPF_COEFF3435,  0xf1e6fb28},
+{14800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 148_quant.dat*/
+
+
+/*case 14900000:*/
+/* BEGIN - DIF BPF register values from 149_quant.dat*/
+{14900000, DIF_BPF_COEFF01,    0x0000fffd},
+{14900000, DIF_BPF_COEFF23,    0x00060009},
+{14900000, DIF_BPF_COEFF45,    0xffdf0004},
+{14900000, DIF_BPF_COEFF67,    0x0051ffb0},
+{14900000, DIF_BPF_COEFF89,    0xff9d00e8},
+{14900000, DIF_BPF_COEFF1011,  0xfffcfe7c},
+{14900000, DIF_BPF_COEFF1213,  0x01280180},
+{14900000, DIF_BPF_COEFF1415,  0xfd32ffd2},
+{14900000, DIF_BPF_COEFF1617,  0x0413fd6e},
+{14900000, DIF_BPF_COEFF1819,  0xfc4d05df},
+{14900000, DIF_BPF_COEFF2021,  0x00d1f812},
+{14900000, DIF_BPF_COEFF2223,  0x043506e4},
+{14900000, DIF_BPF_COEFF2425,  0xf685fdfb},
+{14900000, DIF_BPF_COEFF2627,  0x0c43fa8d},
+{14900000, DIF_BPF_COEFF2829,  0xf5a10c83},
+{14900000, DIF_BPF_COEFF3031,  0x0399f046},
+{14900000, DIF_BPF_COEFF3233,  0x05c70d08},
+{14900000, DIF_BPF_COEFF3435,  0xf222faf3},
+{14900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 149_quant.dat*/
+
+
+/*case 15000000:*/
+/* BEGIN - DIF BPF register values from 150_quant.dat*/
+{15000000, DIF_BPF_COEFF01,    0x0000fffd},
+{15000000, DIF_BPF_COEFF23,    0x0003000f},
+{15000000, DIF_BPF_COEFF45,    0xffe5ffef},
+{15000000, DIF_BPF_COEFF67,    0x0057ffd9},
+{15000000, DIF_BPF_COEFF89,    0xff7000c4},
+{15000000, DIF_BPF_COEFF1011,  0x0062fe68},
+{15000000, DIF_BPF_COEFF1213,  0x009e01ff},
+{15000000, DIF_BPF_COEFF1415,  0xfd95fee6},
+{15000000, DIF_BPF_COEFF1617,  0x0435fe7d},
+{15000000, DIF_BPF_COEFF1819,  0xfb710530},
+{15000000, DIF_BPF_COEFF2021,  0x023cf7ee},
+{15000000, DIF_BPF_COEFF2223,  0x02c307ef},
+{15000000, DIF_BPF_COEFF2425,  0xf75efc70},
+{15000000, DIF_BPF_COEFF2627,  0x0c5cfbef},
+{15000000, DIF_BPF_COEFF2829,  0xf4c10bce},
+{15000000, DIF_BPF_COEFF3031,  0x04b3f03f},
+{15000000, DIF_BPF_COEFF3233,  0x05030d69},
+{15000000, DIF_BPF_COEFF3435,  0xf261fabf},
+{15000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 150_quant.dat*/
+
+
+/*case 15100000:*/
+/* BEGIN - DIF BPF register values from 151_quant.dat*/
+{15100000, DIF_BPF_COEFF01,    0x0000fffd},
+{15100000, DIF_BPF_COEFF23,    0xffff0012},
+{15100000, DIF_BPF_COEFF45,    0xffefffdc},
+{15100000, DIF_BPF_COEFF67,    0x00510006},
+{15100000, DIF_BPF_COEFF89,    0xff540089},
+{15100000, DIF_BPF_COEFF1011,  0x00befe7c},
+{15100000, DIF_BPF_COEFF1213,  0x00060253},
+{15100000, DIF_BPF_COEFF1415,  0xfe27fe0d},
+{15100000, DIF_BPF_COEFF1617,  0x0413ffa2},
+{15100000, DIF_BPF_COEFF1819,  0xfad10446},
+{15100000, DIF_BPF_COEFF2021,  0x0390f812},
+{15100000, DIF_BPF_COEFF2223,  0x013b08c3},
+{15100000, DIF_BPF_COEFF2425,  0xf868faf6},
+{15100000, DIF_BPF_COEFF2627,  0x0c43fd5f},
+{15100000, DIF_BPF_COEFF2829,  0xf3fd0b02},
+{15100000, DIF_BPF_COEFF3031,  0x05c7f046},
+{15100000, DIF_BPF_COEFF3233,  0x043b0dc4},
+{15100000, DIF_BPF_COEFF3435,  0xf2a1fa8b},
+{15100000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 151_quant.dat*/
+
+
+/*case 15200000:*/
+/* BEGIN - DIF BPF register values from 152_quant.dat*/
+{15200000, DIF_BPF_COEFF01,    0x0001fffe},
+{15200000, DIF_BPF_COEFF23,    0xfffc0012},
+{15200000, DIF_BPF_COEFF45,    0xfffbffce},
+{15200000, DIF_BPF_COEFF67,    0x003f0033},
+{15200000, DIF_BPF_COEFF89,    0xff4e003f},
+{15200000, DIF_BPF_COEFF1011,  0x0106feb6},
+{15200000, DIF_BPF_COEFF1213,  0xff6e0276},
+{15200000, DIF_BPF_COEFF1415,  0xfeddfd56},
+{15200000, DIF_BPF_COEFF1617,  0x03b000cc},
+{15200000, DIF_BPF_COEFF1819,  0xfa740329},
+{15200000, DIF_BPF_COEFF2021,  0x04bff87f},
+{15200000, DIF_BPF_COEFF2223,  0xffaa095d},
+{15200000, DIF_BPF_COEFF2425,  0xf99ef995},
+{15200000, DIF_BPF_COEFF2627,  0x0bf9fed8},
+{15200000, DIF_BPF_COEFF2829,  0xf3590a1f},
+{15200000, DIF_BPF_COEFF3031,  0x06d2f05e},
+{15200000, DIF_BPF_COEFF3233,  0x03700e1b},
+{15200000, DIF_BPF_COEFF3435,  0xf2e4fa58},
+{15200000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 152_quant.dat*/
+
+
+/*case 115300000:*/
+/* BEGIN - DIF BPF register values from 153_quant.dat*/
+{15300000, DIF_BPF_COEFF01,    0x0001ffff},
+{15300000, DIF_BPF_COEFF23,    0xfff9000f},
+{15300000, DIF_BPF_COEFF45,    0x0009ffc8},
+{15300000, DIF_BPF_COEFF67,    0x00250059},
+{15300000, DIF_BPF_COEFF89,    0xff5effee},
+{15300000, DIF_BPF_COEFF1011,  0x0132ff10},
+{15300000, DIF_BPF_COEFF1213,  0xfee30265},
+{15300000, DIF_BPF_COEFF1415,  0xffaafccf},
+{15300000, DIF_BPF_COEFF1617,  0x031101eb},
+{15300000, DIF_BPF_COEFF1819,  0xfa6001e8},
+{15300000, DIF_BPF_COEFF2021,  0x05bdf92f},
+{15300000, DIF_BPF_COEFF2223,  0xfe1b09b6},
+{15300000, DIF_BPF_COEFF2425,  0xfafaf852},
+{15300000, DIF_BPF_COEFF2627,  0x0b7e0055},
+{15300000, DIF_BPF_COEFF2829,  0xf2d50929},
+{15300000, DIF_BPF_COEFF3031,  0x07d3f086},
+{15300000, DIF_BPF_COEFF3233,  0x02a30e6c},
+{15300000, DIF_BPF_COEFF3435,  0xf329fa24},
+{15300000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 153_quant.dat*/
+
+
+/*case 115400000:*/
+/* BEGIN - DIF BPF register values from 154_quant.dat*/
+{15400000, DIF_BPF_COEFF01,    0x00010001},
+{15400000, DIF_BPF_COEFF23,    0xfff80009},
+{15400000, DIF_BPF_COEFF45,    0x0015ffca},
+{15400000, DIF_BPF_COEFF67,    0x00050074},
+{15400000, DIF_BPF_COEFF89,    0xff81ff9f},
+{15400000, DIF_BPF_COEFF1011,  0x013dff82},
+{15400000, DIF_BPF_COEFF1213,  0xfe710221},
+{15400000, DIF_BPF_COEFF1415,  0x007cfc80},
+{15400000, DIF_BPF_COEFF1617,  0x024102ed},
+{15400000, DIF_BPF_COEFF1819,  0xfa940090},
+{15400000, DIF_BPF_COEFF2021,  0x0680fa1e},
+{15400000, DIF_BPF_COEFF2223,  0xfc9b09cd},
+{15400000, DIF_BPF_COEFF2425,  0xfc73f736},
+{15400000, DIF_BPF_COEFF2627,  0x0ad501d0},
+{15400000, DIF_BPF_COEFF2829,  0xf2740820},
+{15400000, DIF_BPF_COEFF3031,  0x08c9f0bd},
+{15400000, DIF_BPF_COEFF3233,  0x01d40eb9},
+{15400000, DIF_BPF_COEFF3435,  0xf371f9f1},
+{15400000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 154_quant.dat*/
+
+
+/*case 115500000:*/
+/* BEGIN - DIF BPF register values from 155_quant.dat*/
+{15500000, DIF_BPF_COEFF01,    0x00000002},
+{15500000, DIF_BPF_COEFF23,    0xfff80002},
+{15500000, DIF_BPF_COEFF45,    0x001effd5},
+{15500000, DIF_BPF_COEFF67,    0xffe5007f},
+{15500000, DIF_BPF_COEFF89,    0xffb4ff5b},
+{15500000, DIF_BPF_COEFF1011,  0x01280000},
+{15500000, DIF_BPF_COEFF1213,  0xfe2401b0},
+{15500000, DIF_BPF_COEFF1415,  0x0146fc70},
+{15500000, DIF_BPF_COEFF1617,  0x014d03c6},
+{15500000, DIF_BPF_COEFF1819,  0xfb10ff32},
+{15500000, DIF_BPF_COEFF2021,  0x0701fb41},
+{15500000, DIF_BPF_COEFF2223,  0xfb3709a1},
+{15500000, DIF_BPF_COEFF2425,  0xfe00f644},
+{15500000, DIF_BPF_COEFF2627,  0x0a000345},
+{15500000, DIF_BPF_COEFF2829,  0xf2350708},
+{15500000, DIF_BPF_COEFF3031,  0x09b2f104},
+{15500000, DIF_BPF_COEFF3233,  0x01050eff},
+{15500000, DIF_BPF_COEFF3435,  0xf3baf9be},
+{15500000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 155_quant.dat*/
+
+
+/*case 115600000:*/
+/* BEGIN - DIF BPF register values from 156_quant.dat*/
+{15600000, DIF_BPF_COEFF01,    0x00000003},
+{15600000, DIF_BPF_COEFF23,    0xfff9fffb},
+{15600000, DIF_BPF_COEFF45,    0x0022ffe6},
+{15600000, DIF_BPF_COEFF67,    0xffc9007a},
+{15600000, DIF_BPF_COEFF89,    0xfff0ff29},
+{15600000, DIF_BPF_COEFF1011,  0x00f2007e},
+{15600000, DIF_BPF_COEFF1213,  0xfe01011b},
+{15600000, DIF_BPF_COEFF1415,  0x01f6fc9e},
+{15600000, DIF_BPF_COEFF1617,  0x00440467},
+{15600000, DIF_BPF_COEFF1819,  0xfbccfdde},
+{15600000, DIF_BPF_COEFF2021,  0x0738fc90},
+{15600000, DIF_BPF_COEFF2223,  0xf9f70934},
+{15600000, DIF_BPF_COEFF2425,  0xff99f582},
+{15600000, DIF_BPF_COEFF2627,  0x090204b0},
+{15600000, DIF_BPF_COEFF2829,  0xf21a05e1},
+{15600000, DIF_BPF_COEFF3031,  0x0a8df15a},
+{15600000, DIF_BPF_COEFF3233,  0x00340f41},
+{15600000, DIF_BPF_COEFF3435,  0xf405f98b},
+{15600000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 156_quant.dat*/
+
+
+/*case 115700000:*/
+/* BEGIN - DIF BPF register values from 157_quant.dat*/
+{15700000, DIF_BPF_COEFF01,    0x00000003},
+{15700000, DIF_BPF_COEFF23,    0xfffcfff4},
+{15700000, DIF_BPF_COEFF45,    0x0020fffa},
+{15700000, DIF_BPF_COEFF67,    0xffb40064},
+{15700000, DIF_BPF_COEFF89,    0x002fff11},
+{15700000, DIF_BPF_COEFF1011,  0x00a400f0},
+{15700000, DIF_BPF_COEFF1213,  0xfe0d006e},
+{15700000, DIF_BPF_COEFF1415,  0x0281fd09},
+{15700000, DIF_BPF_COEFF1617,  0xff3604c9},
+{15700000, DIF_BPF_COEFF1819,  0xfcbffca2},
+{15700000, DIF_BPF_COEFF2021,  0x0726fdfe},
+{15700000, DIF_BPF_COEFF2223,  0xf8e80888},
+{15700000, DIF_BPF_COEFF2425,  0x0134f4f3},
+{15700000, DIF_BPF_COEFF2627,  0x07e1060c},
+{15700000, DIF_BPF_COEFF2829,  0xf22304af},
+{15700000, DIF_BPF_COEFF3031,  0x0b59f1be},
+{15700000, DIF_BPF_COEFF3233,  0xff640f7d},
+{15700000, DIF_BPF_COEFF3435,  0xf452f959},
+{15700000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 157_quant.dat*/
+
+
+/*case 115800000:*/
+/* BEGIN - DIF BPF register values from 158_quant.dat*/
+{15800000, DIF_BPF_COEFF01,    0x00000003},
+{15800000, DIF_BPF_COEFF23,    0x0000fff0},
+{15800000, DIF_BPF_COEFF45,    0x001a0010},
+{15800000, DIF_BPF_COEFF67,    0xffaa0041},
+{15800000, DIF_BPF_COEFF89,    0x0067ff13},
+{15800000, DIF_BPF_COEFF1011,  0x0043014a},
+{15800000, DIF_BPF_COEFF1213,  0xfe46ffb9},
+{15800000, DIF_BPF_COEFF1415,  0x02dbfda8},
+{15800000, DIF_BPF_COEFF1617,  0xfe3504e5},
+{15800000, DIF_BPF_COEFF1819,  0xfddcfb8d},
+{15800000, DIF_BPF_COEFF2021,  0x06c9ff7e},
+{15800000, DIF_BPF_COEFF2223,  0xf81107a2},
+{15800000, DIF_BPF_COEFF2425,  0x02c9f49a},
+{15800000, DIF_BPF_COEFF2627,  0x069f0753},
+{15800000, DIF_BPF_COEFF2829,  0xf2500373},
+{15800000, DIF_BPF_COEFF3031,  0x0c14f231},
+{15800000, DIF_BPF_COEFF3233,  0xfe930fb3},
+{15800000, DIF_BPF_COEFF3435,  0xf4a1f927},
+{15800000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 158_quant.dat*/
+
+
+/*case 115900000:*/
+/* BEGIN - DIF BPF register values from 159_quant.dat*/
+{15900000, DIF_BPF_COEFF01,    0xffff0002},
+{15900000, DIF_BPF_COEFF23,    0x0003ffee},
+{15900000, DIF_BPF_COEFF45,    0x000f0023},
+{15900000, DIF_BPF_COEFF67,    0xffac0016},
+{15900000, DIF_BPF_COEFF89,    0x0093ff31},
+{15900000, DIF_BPF_COEFF1011,  0xffdc0184},
+{15900000, DIF_BPF_COEFF1213,  0xfea6ff09},
+{15900000, DIF_BPF_COEFF1415,  0x02fdfe70},
+{15900000, DIF_BPF_COEFF1617,  0xfd5104ba},
+{15900000, DIF_BPF_COEFF1819,  0xff15faac},
+{15900000, DIF_BPF_COEFF2021,  0x06270103},
+{15900000, DIF_BPF_COEFF2223,  0xf7780688},
+{15900000, DIF_BPF_COEFF2425,  0x044df479},
+{15900000, DIF_BPF_COEFF2627,  0x05430883},
+{15900000, DIF_BPF_COEFF2829,  0xf2a00231},
+{15900000, DIF_BPF_COEFF3031,  0x0cbef2b2},
+{15900000, DIF_BPF_COEFF3233,  0xfdc40fe3},
+{15900000, DIF_BPF_COEFF3435,  0xf4f2f8f5},
+{15900000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 159_quant.dat*/
+
+
+/*case 116000000:*/
+/* BEGIN - DIF BPF register values from 160_quant.dat*/
+{16000000, DIF_BPF_COEFF01,    0xffff0001},
+{16000000, DIF_BPF_COEFF23,    0x0006ffef},
+{16000000, DIF_BPF_COEFF45,    0x00020031},
+{16000000, DIF_BPF_COEFF67,    0xffbaffe8},
+{16000000, DIF_BPF_COEFF89,    0x00adff66},
+{16000000, DIF_BPF_COEFF1011,  0xff790198},
+{16000000, DIF_BPF_COEFF1213,  0xff26fe6e},
+{16000000, DIF_BPF_COEFF1415,  0x02e5ff55},
+{16000000, DIF_BPF_COEFF1617,  0xfc99044a},
+{16000000, DIF_BPF_COEFF1819,  0x005bfa09},
+{16000000, DIF_BPF_COEFF2021,  0x0545027f},
+{16000000, DIF_BPF_COEFF2223,  0xf7230541},
+{16000000, DIF_BPF_COEFF2425,  0x05b8f490},
+{16000000, DIF_BPF_COEFF2627,  0x03d20997},
+{16000000, DIF_BPF_COEFF2829,  0xf31300eb},
+{16000000, DIF_BPF_COEFF3031,  0x0d55f341},
+{16000000, DIF_BPF_COEFF3233,  0xfcf6100e},
+{16000000, DIF_BPF_COEFF3435,  0xf544f8c3},
+{16000000, DIF_BPF_COEFF36,    0x110d0000},
+/* END - DIF BPF register values from 160_quant.dat*/
+};
+
+#endif
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
new file mode 100644
index 0000000..7c4e360
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -0,0 +1,796 @@
+/*
+ DVB device driver for cx231xx
+
+ Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+		Based on em28xx driver
+
+ This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include "cx231xx.h"
+#include <media/v4l2-common.h>
+#include <media/videobuf-vmalloc.h>
+
+#include "xc5000.h"
+#include "s5h1432.h"
+#include "tda18271.h"
+#include "s5h1411.h"
+#include "lgdt3305.h"
+#include "mb86a20s.h"
+
+MODULE_DESCRIPTION("driver for cx231xx based DVB cards");
+MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages [dvb]");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define dprintk(level, fmt, arg...) do {			\
+if (debug >= level) 						\
+	printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg);	\
+} while (0)
+
+#define CX231XX_DVB_NUM_BUFS 5
+#define CX231XX_DVB_MAX_PACKETSIZE 564
+#define CX231XX_DVB_MAX_PACKETS 64
+
+struct cx231xx_dvb {
+	struct dvb_frontend *frontend;
+
+	/* feed count management */
+	struct mutex lock;
+	int nfeeds;
+
+	/* general boilerplate stuff */
+	struct dvb_adapter adapter;
+	struct dvb_demux demux;
+	struct dmxdev dmxdev;
+	struct dmx_frontend fe_hw;
+	struct dmx_frontend fe_mem;
+	struct dvb_net net;
+};
+
+static struct s5h1432_config dvico_s5h1432_config = {
+	.output_mode   = S5H1432_SERIAL_OUTPUT,
+	.gpio          = S5H1432_GPIO_ON,
+	.qam_if        = S5H1432_IF_4000,
+	.vsb_if        = S5H1432_IF_4000,
+	.inversion     = S5H1432_INVERSION_OFF,
+	.status_mode   = S5H1432_DEMODLOCKING,
+	.mpeg_timing   = S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct tda18271_std_map cnxt_rde253s_tda18271_std_map = {
+	.dvbt_6   = { .if_freq = 4000, .agc_mode = 3, .std = 4,
+		      .if_lvl = 1, .rfagc_top = 0x37, },
+	.dvbt_7   = { .if_freq = 4000, .agc_mode = 3, .std = 5,
+		      .if_lvl = 1, .rfagc_top = 0x37, },
+	.dvbt_8   = { .if_freq = 4000, .agc_mode = 3, .std = 6,
+		      .if_lvl = 1, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_std_map mb86a20s_tda18271_config = {
+	.dvbt_6   = { .if_freq = 3300, .agc_mode = 3, .std = 4,
+		      .if_lvl = 7, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config cnxt_rde253s_tunerconfig = {
+	.std_map = &cnxt_rde253s_tda18271_std_map,
+	.gate    = TDA18271_GATE_ANALOG,
+};
+
+static struct s5h1411_config tda18271_s5h1411_config = {
+	.output_mode   = S5H1411_SERIAL_OUTPUT,
+	.gpio          = S5H1411_GPIO_OFF,
+	.vsb_if        = S5H1411_IF_3250,
+	.qam_if        = S5H1411_IF_4000,
+	.inversion     = S5H1411_INVERSION_ON,
+	.status_mode   = S5H1411_DEMODLOCKING,
+	.mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+static struct s5h1411_config xc5000_s5h1411_config = {
+	.output_mode   = S5H1411_SERIAL_OUTPUT,
+	.gpio          = S5H1411_GPIO_OFF,
+	.vsb_if        = S5H1411_IF_3250,
+	.qam_if        = S5H1411_IF_3250,
+	.inversion     = S5H1411_INVERSION_OFF,
+	.status_mode   = S5H1411_DEMODLOCKING,
+	.mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct lgdt3305_config hcw_lgdt3305_config = {
+	.i2c_addr           = 0x0e,
+	.mpeg_mode          = LGDT3305_MPEG_SERIAL,
+	.tpclk_edge         = LGDT3305_TPCLK_FALLING_EDGE,
+	.tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
+	.deny_i2c_rptr      = 1,
+	.spectral_inversion = 1,
+	.qam_if_khz         = 4000,
+	.vsb_if_khz         = 3250,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+	.atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 4,
+		      .if_lvl = 1, .rfagc_top = 0x58, },
+	.qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 5,
+		      .if_lvl = 1, .rfagc_top = 0x58, },
+};
+
+static struct tda18271_config hcw_tda18271_config = {
+	.std_map = &hauppauge_tda18271_std_map,
+	.gate    = TDA18271_GATE_DIGITAL,
+};
+
+static const struct mb86a20s_config pv_mb86a20s_config = {
+	.demod_address = 0x10,
+	.is_serial = true,
+};
+
+static struct tda18271_config pv_tda18271_config = {
+	.std_map = &mb86a20s_tda18271_config,
+	.gate    = TDA18271_GATE_DIGITAL,
+	.small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
+};
+
+static inline void print_err_status(struct cx231xx *dev, int packet, int status)
+{
+	char *errmsg = "Unknown";
+
+	switch (status) {
+	case -ENOENT:
+		errmsg = "unlinked synchronuously";
+		break;
+	case -ECONNRESET:
+		errmsg = "unlinked asynchronuously";
+		break;
+	case -ENOSR:
+		errmsg = "Buffer error (overrun)";
+		break;
+	case -EPIPE:
+		errmsg = "Stalled (device not responding)";
+		break;
+	case -EOVERFLOW:
+		errmsg = "Babble (bad cable?)";
+		break;
+	case -EPROTO:
+		errmsg = "Bit-stuff error (bad cable?)";
+		break;
+	case -EILSEQ:
+		errmsg = "CRC/Timeout (could be anything)";
+		break;
+	case -ETIME:
+		errmsg = "Device does not respond";
+		break;
+	}
+	if (packet < 0) {
+		dprintk(1, "URB status %d [%s].\n", status, errmsg);
+	} else {
+		dprintk(1, "URB packet %d, status %d [%s].\n",
+			packet, status, errmsg);
+	}
+}
+
+static inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb)
+{
+	int i;
+
+	if (!dev)
+		return 0;
+
+	if (dev->state & DEV_DISCONNECTED)
+		return 0;
+
+	if (urb->status < 0) {
+		print_err_status(dev, -1, urb->status);
+		if (urb->status == -ENOENT)
+			return 0;
+	}
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		int status = urb->iso_frame_desc[i].status;
+
+		if (status < 0) {
+			print_err_status(dev, i, status);
+			if (urb->iso_frame_desc[i].status != -EPROTO)
+				continue;
+		}
+
+		dvb_dmx_swfilter(&dev->dvb->demux,
+				 urb->transfer_buffer +
+				urb->iso_frame_desc[i].offset,
+				urb->iso_frame_desc[i].actual_length);
+	}
+
+	return 0;
+}
+
+static inline int dvb_bulk_copy(struct cx231xx *dev, struct urb *urb)
+{
+	if (!dev)
+		return 0;
+
+	if (dev->state & DEV_DISCONNECTED)
+		return 0;
+
+	if (urb->status < 0) {
+		print_err_status(dev, -1, urb->status);
+		if (urb->status == -ENOENT)
+			return 0;
+	}
+
+	/* Feed the transport payload into the kernel demux */
+	dvb_dmx_swfilter(&dev->dvb->demux,
+		urb->transfer_buffer, urb->actual_length);
+
+	return 0;
+}
+
+static int start_streaming(struct cx231xx_dvb *dvb)
+{
+	int rc;
+	struct cx231xx *dev = dvb->adapter.priv;
+
+	if (dev->USE_ISO) {
+		cx231xx_info("DVB transfer mode is ISO.\n");
+		mutex_lock(&dev->i2c_lock);
+		cx231xx_enable_i2c_port_3(dev, false);
+		cx231xx_set_alt_setting(dev, INDEX_TS1, 4);
+		cx231xx_enable_i2c_port_3(dev, true);
+		mutex_unlock(&dev->i2c_lock);
+		rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+		if (rc < 0)
+			return rc;
+		dev->mode_tv = 1;
+		return cx231xx_init_isoc(dev, CX231XX_DVB_MAX_PACKETS,
+					CX231XX_DVB_NUM_BUFS,
+					dev->ts1_mode.max_pkt_size,
+					dvb_isoc_copy);
+	} else {
+		cx231xx_info("DVB transfer mode is BULK.\n");
+		cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
+		rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+		if (rc < 0)
+			return rc;
+		dev->mode_tv = 1;
+		return cx231xx_init_bulk(dev, CX231XX_DVB_MAX_PACKETS,
+					CX231XX_DVB_NUM_BUFS,
+					dev->ts1_mode.max_pkt_size,
+					dvb_bulk_copy);
+	}
+
+}
+
+static int stop_streaming(struct cx231xx_dvb *dvb)
+{
+	struct cx231xx *dev = dvb->adapter.priv;
+
+	if (dev->USE_ISO)
+		cx231xx_uninit_isoc(dev);
+	else
+		cx231xx_uninit_bulk(dev);
+
+	cx231xx_set_mode(dev, CX231XX_SUSPEND);
+
+	return 0;
+}
+
+static int start_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct cx231xx_dvb *dvb = demux->priv;
+	int rc, ret;
+
+	if (!demux->dmx.frontend)
+		return -EINVAL;
+
+	mutex_lock(&dvb->lock);
+	dvb->nfeeds++;
+	rc = dvb->nfeeds;
+
+	if (dvb->nfeeds == 1) {
+		ret = start_streaming(dvb);
+		if (ret < 0)
+			rc = ret;
+	}
+
+	mutex_unlock(&dvb->lock);
+	return rc;
+}
+
+static int stop_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct cx231xx_dvb *dvb = demux->priv;
+	int err = 0;
+
+	mutex_lock(&dvb->lock);
+	dvb->nfeeds--;
+
+	if (0 == dvb->nfeeds)
+		err = stop_streaming(dvb);
+
+	mutex_unlock(&dvb->lock);
+	return err;
+}
+
+/* ------------------------------------------------------------------ */
+static int cx231xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+	struct cx231xx *dev = fe->dvb->priv;
+
+	if (acquire)
+		return cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+	else
+		return cx231xx_set_mode(dev, CX231XX_SUSPEND);
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct xc5000_config cnxt_rde250_tunerconfig = {
+	.i2c_address = 0x61,
+	.if_khz = 4000,
+};
+static struct xc5000_config cnxt_rdu250_tunerconfig = {
+	.i2c_address = 0x61,
+	.if_khz = 3250,
+};
+
+/* ------------------------------------------------------------------ */
+#if 0
+static int attach_xc5000(u8 addr, struct cx231xx *dev)
+{
+
+	struct dvb_frontend *fe;
+	struct xc5000_config cfg;
+
+	memset(&cfg, 0, sizeof(cfg));
+	cfg.i2c_adap = &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap;
+	cfg.i2c_addr = addr;
+
+	if (!dev->dvb->frontend) {
+		printk(KERN_ERR "%s/2: dvb frontend not attached. "
+		       "Can't attach xc5000\n", dev->name);
+		return -EINVAL;
+	}
+
+	fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg);
+	if (!fe) {
+		printk(KERN_ERR "%s/2: xc5000 attach failed\n", dev->name);
+		dvb_frontend_detach(dev->dvb->frontend);
+		dev->dvb->frontend = NULL;
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "%s/2: xc5000 attached\n", dev->name);
+
+	return 0;
+}
+#endif
+
+int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
+{
+	int status = 0;
+
+	if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
+
+		struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
+
+		if (dops->set_analog_params != NULL) {
+			struct analog_parameters params;
+
+			params.frequency = freq;
+			params.std = dev->norm;
+			params.mode = 0;	/* 0- Air; 1 - cable */
+			/*params.audmode = ;       */
+
+			/* Set the analog parameters to set the frequency */
+			dops->set_analog_params(dev->dvb->frontend, &params);
+		}
+
+	}
+
+	return status;
+}
+
+int cx231xx_reset_analog_tuner(struct cx231xx *dev)
+{
+	int status = 0;
+
+	if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
+
+		struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
+
+		if (dops->init != NULL && !dev->xc_fw_load_done) {
+
+			cx231xx_info("Reloading firmware for XC5000\n");
+			status = dops->init(dev->dvb->frontend);
+			if (status == 0) {
+				dev->xc_fw_load_done = 1;
+				cx231xx_info
+				    ("XC5000 firmware download completed\n");
+			} else {
+				dev->xc_fw_load_done = 0;
+				cx231xx_info
+				    ("XC5000 firmware download failed !!!\n");
+			}
+		}
+
+	}
+
+	return status;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int register_dvb(struct cx231xx_dvb *dvb,
+			struct module *module,
+			struct cx231xx *dev, struct device *device)
+{
+	int result;
+
+	mutex_init(&dvb->lock);
+
+	/* register adapter */
+	result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
+				      adapter_nr);
+	if (result < 0) {
+		printk(KERN_WARNING
+		       "%s: dvb_register_adapter failed (errno = %d)\n",
+		       dev->name, result);
+		goto fail_adapter;
+	}
+
+	/* Ensure all frontends negotiate bus access */
+	dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
+
+	dvb->adapter.priv = dev;
+
+	/* register frontend */
+	result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+	if (result < 0) {
+		printk(KERN_WARNING
+		       "%s: dvb_register_frontend failed (errno = %d)\n",
+		       dev->name, result);
+		goto fail_frontend;
+	}
+
+	/* register demux stuff */
+	dvb->demux.dmx.capabilities =
+	    DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+	    DMX_MEMORY_BASED_FILTERING;
+	dvb->demux.priv = dvb;
+	dvb->demux.filternum = 256;
+	dvb->demux.feednum = 256;
+	dvb->demux.start_feed = start_feed;
+	dvb->demux.stop_feed = stop_feed;
+
+	result = dvb_dmx_init(&dvb->demux);
+	if (result < 0) {
+		printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
+		       dev->name, result);
+		goto fail_dmx;
+	}
+
+	dvb->dmxdev.filternum = 256;
+	dvb->dmxdev.demux = &dvb->demux.dmx;
+	dvb->dmxdev.capabilities = 0;
+	result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+	if (result < 0) {
+		printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
+		       dev->name, result);
+		goto fail_dmxdev;
+	}
+
+	dvb->fe_hw.source = DMX_FRONTEND_0;
+	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	if (result < 0) {
+		printk(KERN_WARNING
+		       "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
+		       dev->name, result);
+		goto fail_fe_hw;
+	}
+
+	dvb->fe_mem.source = DMX_MEMORY_FE;
+	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+	if (result < 0) {
+		printk(KERN_WARNING
+		       "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
+		       dev->name, result);
+		goto fail_fe_mem;
+	}
+
+	result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	if (result < 0) {
+		printk(KERN_WARNING
+		       "%s: connect_frontend failed (errno = %d)\n", dev->name,
+		       result);
+		goto fail_fe_conn;
+	}
+
+	/* register network adapter */
+	dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+	return 0;
+
+fail_fe_conn:
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+fail_fe_mem:
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+fail_fe_hw:
+	dvb_dmxdev_release(&dvb->dmxdev);
+fail_dmxdev:
+	dvb_dmx_release(&dvb->demux);
+fail_dmx:
+	dvb_unregister_frontend(dvb->frontend);
+fail_frontend:
+	dvb_frontend_detach(dvb->frontend);
+	dvb_unregister_adapter(&dvb->adapter);
+fail_adapter:
+	return result;
+}
+
+static void unregister_dvb(struct cx231xx_dvb *dvb)
+{
+	dvb_net_release(&dvb->net);
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	dvb_dmxdev_release(&dvb->dmxdev);
+	dvb_dmx_release(&dvb->demux);
+	dvb_unregister_frontend(dvb->frontend);
+	dvb_frontend_detach(dvb->frontend);
+	dvb_unregister_adapter(&dvb->adapter);
+}
+
+static int dvb_init(struct cx231xx *dev)
+{
+	int result = 0;
+	struct cx231xx_dvb *dvb;
+
+	if (!dev->board.has_dvb) {
+		/* This device does not support the extension */
+		return 0;
+	}
+
+	dvb = kzalloc(sizeof(struct cx231xx_dvb), GFP_KERNEL);
+
+	if (dvb == NULL) {
+		printk(KERN_INFO "cx231xx_dvb: memory allocation failed\n");
+		return -ENOMEM;
+	}
+	dev->dvb = dvb;
+	dev->cx231xx_set_analog_freq = cx231xx_set_analog_freq;
+	dev->cx231xx_reset_analog_tuner = cx231xx_reset_analog_tuner;
+
+	mutex_lock(&dev->lock);
+	cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+	cx231xx_demod_reset(dev);
+	/* init frontend */
+	switch (dev->model) {
+	case CX231XX_BOARD_CNXT_CARRAERA:
+	case CX231XX_BOARD_CNXT_RDE_250:
+
+		dev->dvb->frontend = dvb_attach(s5h1432_attach,
+					&dvico_s5h1432_config,
+					&dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
+
+		if (dev->dvb->frontend == NULL) {
+			printk(DRIVER_NAME
+			       ": Failed to attach s5h1432 front end\n");
+			result = -EINVAL;
+			goto out_free;
+		}
+
+		/* define general-purpose callback pointer */
+		dvb->frontend->callback = cx231xx_tuner_callback;
+
+		if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
+			       &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+			       &cnxt_rde250_tunerconfig)) {
+			result = -EINVAL;
+			goto out_free;
+		}
+
+		break;
+	case CX231XX_BOARD_CNXT_SHELBY:
+	case CX231XX_BOARD_CNXT_RDU_250:
+
+		dev->dvb->frontend = dvb_attach(s5h1411_attach,
+					       &xc5000_s5h1411_config,
+					       &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
+
+		if (dev->dvb->frontend == NULL) {
+			printk(DRIVER_NAME
+			       ": Failed to attach s5h1411 front end\n");
+			result = -EINVAL;
+			goto out_free;
+		}
+
+		/* define general-purpose callback pointer */
+		dvb->frontend->callback = cx231xx_tuner_callback;
+
+		if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
+			       &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+			       &cnxt_rdu250_tunerconfig)) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		break;
+	case CX231XX_BOARD_CNXT_RDE_253S:
+
+		dev->dvb->frontend = dvb_attach(s5h1432_attach,
+					&dvico_s5h1432_config,
+					&dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
+
+		if (dev->dvb->frontend == NULL) {
+			printk(DRIVER_NAME
+			       ": Failed to attach s5h1432 front end\n");
+			result = -EINVAL;
+			goto out_free;
+		}
+
+		/* define general-purpose callback pointer */
+		dvb->frontend->callback = cx231xx_tuner_callback;
+
+		if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
+			       0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+			       &cnxt_rde253s_tunerconfig)) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		break;
+	case CX231XX_BOARD_CNXT_RDU_253S:
+
+		dev->dvb->frontend = dvb_attach(s5h1411_attach,
+					       &tda18271_s5h1411_config,
+					       &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
+
+		if (dev->dvb->frontend == NULL) {
+			printk(DRIVER_NAME
+			       ": Failed to attach s5h1411 front end\n");
+			result = -EINVAL;
+			goto out_free;
+		}
+
+		/* define general-purpose callback pointer */
+		dvb->frontend->callback = cx231xx_tuner_callback;
+
+		if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
+			       0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+			       &cnxt_rde253s_tunerconfig)) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		break;
+	case CX231XX_BOARD_HAUPPAUGE_EXETER:
+
+		printk(KERN_INFO "%s: looking for tuner / demod on i2c bus: %d\n",
+		       __func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap));
+
+		dev->dvb->frontend = dvb_attach(lgdt3305_attach,
+						&hcw_lgdt3305_config,
+						&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap);
+
+		if (dev->dvb->frontend == NULL) {
+			printk(DRIVER_NAME
+			       ": Failed to attach LG3305 front end\n");
+			result = -EINVAL;
+			goto out_free;
+		}
+
+		/* define general-purpose callback pointer */
+		dvb->frontend->callback = cx231xx_tuner_callback;
+
+		dvb_attach(tda18271_attach, dev->dvb->frontend,
+			   0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+			   &hcw_tda18271_config);
+		break;
+
+	case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+	case CX231XX_BOARD_KWORLD_UB430_USB_HYBRID:
+
+		printk(KERN_INFO "%s: looking for demod on i2c bus: %d\n",
+		       __func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap));
+
+		dev->dvb->frontend = dvb_attach(mb86a20s_attach,
+						&pv_mb86a20s_config,
+						&dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
+
+		if (dev->dvb->frontend == NULL) {
+			printk(DRIVER_NAME
+			       ": Failed to attach mb86a20s demod\n");
+			result = -EINVAL;
+			goto out_free;
+		}
+
+		/* define general-purpose callback pointer */
+		dvb->frontend->callback = cx231xx_tuner_callback;
+
+		dvb_attach(tda18271_attach, dev->dvb->frontend,
+			   0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+			   &pv_tda18271_config);
+		break;
+
+	default:
+		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
+		       " isn't supported yet\n", dev->name);
+		break;
+	}
+	if (NULL == dvb->frontend) {
+		printk(KERN_ERR
+		       "%s/2: frontend initialization failed\n", dev->name);
+		result = -EINVAL;
+		goto out_free;
+	}
+
+	/* register everything */
+	result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
+
+	if (result < 0)
+		goto out_free;
+
+
+	printk(KERN_INFO "Successfully loaded cx231xx-dvb\n");
+
+ret:
+	cx231xx_set_mode(dev, CX231XX_SUSPEND);
+	mutex_unlock(&dev->lock);
+	return result;
+
+out_free:
+	kfree(dvb);
+	dev->dvb = NULL;
+	goto ret;
+}
+
+static int dvb_fini(struct cx231xx *dev)
+{
+	if (!dev->board.has_dvb) {
+		/* This device does not support the extension */
+		return 0;
+	}
+
+	if (dev->dvb) {
+		unregister_dvb(dev->dvb);
+		dev->dvb = NULL;
+	}
+
+	return 0;
+}
+
+static struct cx231xx_ops dvb_ops = {
+	.id = CX231XX_DVB,
+	.name = "Cx231xx dvb Extension",
+	.init = dvb_init,
+	.fini = dvb_fini,
+};
+
+static int __init cx231xx_dvb_register(void)
+{
+	return cx231xx_register_extension(&dvb_ops);
+}
+
+static void __exit cx231xx_dvb_unregister(void)
+{
+	cx231xx_unregister_extension(&dvb_ops);
+}
+
+module_init(cx231xx_dvb_register);
+module_exit(cx231xx_dvb_unregister);
diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c
new file mode 100644
index 0000000..781feed
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c
@@ -0,0 +1,532 @@
+/*
+   cx231xx-i2c.c - driver for Conexant Cx23100/101/102 USB video capture devices
+
+   Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+		Based on em28xx driver
+		Based on Cx23885 driver
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+
+#include "cx231xx.h"
+
+/* ----------------------------------------------------------- */
+
+static unsigned int i2c_scan;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+static unsigned int i2c_debug;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+#define dprintk1(lvl, fmt, args...)			\
+do {							\
+	if (i2c_debug >= lvl) {				\
+		printk(fmt, ##args);			\
+		}					\
+} while (0)
+
+#define dprintk2(lvl, fmt, args...)			\
+do {							\
+	if (i2c_debug >= lvl) {				\
+		printk(KERN_DEBUG "%s at %s: " fmt,	\
+		       dev->name, __func__ , ##args);	\
+      } 						\
+} while (0)
+
+static inline bool is_tuner(struct cx231xx *dev, struct cx231xx_i2c *bus,
+			const struct i2c_msg *msg, int tuner_type)
+{
+	if (bus->nr != dev->board.tuner_i2c_master)
+		return false;
+
+	if (msg->addr != dev->board.tuner_addr)
+		return false;
+
+	if (dev->tuner_type != tuner_type)
+		return false;
+
+	return true;
+}
+
+/*
+ * cx231xx_i2c_send_bytes()
+ */
+int cx231xx_i2c_send_bytes(struct i2c_adapter *i2c_adap,
+			   const struct i2c_msg *msg)
+{
+	struct cx231xx_i2c *bus = i2c_adap->algo_data;
+	struct cx231xx *dev = bus->dev;
+	struct cx231xx_i2c_xfer_data req_data;
+	int status = 0;
+	u16 size = 0;
+	u8 loop = 0;
+	u8 saddr_len = 1;
+	u8 *buf_ptr = NULL;
+	u16 saddr = 0;
+	u8 need_gpio = 0;
+
+	if (is_tuner(dev, bus, msg, TUNER_XC5000)) {
+		size = msg->len;
+
+		if (size == 2) {	/* register write sub addr */
+			/* Just writing sub address will cause problem
+			* to XC5000. So ignore the request */
+			return 0;
+		} else if (size == 4) {	/* register write with sub addr */
+			if (msg->len >= 2)
+				saddr = msg->buf[0] << 8 | msg->buf[1];
+			else if (msg->len == 1)
+				saddr = msg->buf[0];
+
+			switch (saddr) {
+			case 0x0000:	/* start tuner calibration mode */
+				need_gpio = 1;
+				/* FW Loading is done */
+				dev->xc_fw_load_done = 1;
+				break;
+			case 0x000D:	/* Set signal source */
+			case 0x0001:	/* Set TV standard - Video */
+			case 0x0002:	/* Set TV standard - Audio */
+			case 0x0003:	/* Set RF Frequency */
+				need_gpio = 1;
+				break;
+			default:
+				if (dev->xc_fw_load_done)
+					need_gpio = 1;
+				break;
+			}
+
+			if (need_gpio) {
+				dprintk1(1,
+				"GPIO WRITE: addr 0x%x, len %d, saddr 0x%x\n",
+				msg->addr, msg->len, saddr);
+
+				return dev->cx231xx_gpio_i2c_write(dev,
+								   msg->addr,
+								   msg->buf,
+								   msg->len);
+			}
+		}
+
+		/* special case for Xc5000 tuner case */
+		saddr_len = 1;
+
+		/* adjust the length to correct length */
+		size -= saddr_len;
+		buf_ptr = (u8 *) (msg->buf + 1);
+
+		do {
+			/* prepare xfer_data struct */
+			req_data.dev_addr = msg->addr;
+			req_data.direction = msg->flags;
+			req_data.saddr_len = saddr_len;
+			req_data.saddr_dat = msg->buf[0];
+			req_data.buf_size = size > 16 ? 16 : size;
+			req_data.p_buffer = (u8 *) (buf_ptr + loop * 16);
+
+			bus->i2c_nostop = (size > 16) ? 1 : 0;
+			bus->i2c_reserve = (loop == 0) ? 0 : 1;
+
+			/* usb send command */
+			status = dev->cx231xx_send_usb_command(bus, &req_data);
+			loop++;
+
+			if (size >= 16)
+				size -= 16;
+			else
+				size = 0;
+
+		} while (size > 0);
+
+		bus->i2c_nostop = 0;
+		bus->i2c_reserve = 0;
+
+	} else {		/* regular case */
+
+		/* prepare xfer_data struct */
+		req_data.dev_addr = msg->addr;
+		req_data.direction = msg->flags;
+		req_data.saddr_len = 0;
+		req_data.saddr_dat = 0;
+		req_data.buf_size = msg->len;
+		req_data.p_buffer = msg->buf;
+
+		/* usb send command */
+		status = dev->cx231xx_send_usb_command(bus, &req_data);
+	}
+
+	return status < 0 ? status : 0;
+}
+
+/*
+ * cx231xx_i2c_recv_bytes()
+ * read a byte from the i2c device
+ */
+static int cx231xx_i2c_recv_bytes(struct i2c_adapter *i2c_adap,
+				  const struct i2c_msg *msg)
+{
+	struct cx231xx_i2c *bus = i2c_adap->algo_data;
+	struct cx231xx *dev = bus->dev;
+	struct cx231xx_i2c_xfer_data req_data;
+	int status = 0;
+	u16 saddr = 0;
+	u8 need_gpio = 0;
+
+	if (is_tuner(dev, bus, msg, TUNER_XC5000)) {
+		if (msg->len == 2)
+			saddr = msg->buf[0] << 8 | msg->buf[1];
+		else if (msg->len == 1)
+			saddr = msg->buf[0];
+
+		if (dev->xc_fw_load_done) {
+
+			switch (saddr) {
+			case 0x0009:	/* BUSY check */
+				dprintk1(1,
+				"GPIO R E A D: Special case BUSY check \n");
+				/*Try read BUSY register, just set it to zero*/
+				msg->buf[0] = 0;
+				if (msg->len == 2)
+					msg->buf[1] = 0;
+				return 0;
+			case 0x0004:	/* read Lock status */
+				need_gpio = 1;
+				break;
+
+			}
+
+			if (need_gpio) {
+				/* this is a special case to handle Xceive tuner
+				clock stretch issue with gpio based I2C */
+
+				dprintk1(1,
+				"GPIO R E A D: addr 0x%x, len %d, saddr 0x%x\n",
+				msg->addr, msg->len,
+				msg->buf[0] << 8 | msg->buf[1]);
+
+				status =
+				    dev->cx231xx_gpio_i2c_write(dev, msg->addr,
+								msg->buf,
+								msg->len);
+				status =
+				    dev->cx231xx_gpio_i2c_read(dev, msg->addr,
+							       msg->buf,
+							       msg->len);
+				return status;
+			}
+		}
+
+		/* prepare xfer_data struct */
+		req_data.dev_addr = msg->addr;
+		req_data.direction = msg->flags;
+		req_data.saddr_len = msg->len;
+		req_data.saddr_dat = msg->buf[0] << 8 | msg->buf[1];
+		req_data.buf_size = msg->len;
+		req_data.p_buffer = msg->buf;
+
+		/* usb send command */
+		status = dev->cx231xx_send_usb_command(bus, &req_data);
+
+	} else {
+
+		/* prepare xfer_data struct */
+		req_data.dev_addr = msg->addr;
+		req_data.direction = msg->flags;
+		req_data.saddr_len = 0;
+		req_data.saddr_dat = 0;
+		req_data.buf_size = msg->len;
+		req_data.p_buffer = msg->buf;
+
+		/* usb send command */
+		status = dev->cx231xx_send_usb_command(bus, &req_data);
+	}
+
+	return status < 0 ? status : 0;
+}
+
+/*
+ * cx231xx_i2c_recv_bytes_with_saddr()
+ * read a byte from the i2c device
+ */
+static int cx231xx_i2c_recv_bytes_with_saddr(struct i2c_adapter *i2c_adap,
+					     const struct i2c_msg *msg1,
+					     const struct i2c_msg *msg2)
+{
+	struct cx231xx_i2c *bus = i2c_adap->algo_data;
+	struct cx231xx *dev = bus->dev;
+	struct cx231xx_i2c_xfer_data req_data;
+	int status = 0;
+	u16 saddr = 0;
+	u8 need_gpio = 0;
+
+	if (msg1->len == 2)
+		saddr = msg1->buf[0] << 8 | msg1->buf[1];
+	else if (msg1->len == 1)
+		saddr = msg1->buf[0];
+
+	if (is_tuner(dev, bus, msg2, TUNER_XC5000)) {
+		if ((msg2->len < 16)) {
+
+			dprintk1(1,
+			"i2c_read: addr 0x%x, len %d, saddr 0x%x, len %d\n",
+			msg2->addr, msg2->len, saddr, msg1->len);
+
+			switch (saddr) {
+			case 0x0008:	/* read FW load status */
+				need_gpio = 1;
+				break;
+			case 0x0004:	/* read Lock status */
+				need_gpio = 1;
+				break;
+			}
+
+			if (need_gpio) {
+				status =
+				    dev->cx231xx_gpio_i2c_write(dev, msg1->addr,
+								msg1->buf,
+								msg1->len);
+				status =
+				    dev->cx231xx_gpio_i2c_read(dev, msg2->addr,
+							       msg2->buf,
+							       msg2->len);
+				return status;
+			}
+		}
+	}
+
+	/* prepare xfer_data struct */
+	req_data.dev_addr = msg2->addr;
+	req_data.direction = msg2->flags;
+	req_data.saddr_len = msg1->len;
+	req_data.saddr_dat = saddr;
+	req_data.buf_size = msg2->len;
+	req_data.p_buffer = msg2->buf;
+
+	/* usb send command */
+	status = dev->cx231xx_send_usb_command(bus, &req_data);
+
+	return status < 0 ? status : 0;
+}
+
+/*
+ * cx231xx_i2c_check_for_device()
+ * check if there is a i2c_device at the supplied address
+ */
+static int cx231xx_i2c_check_for_device(struct i2c_adapter *i2c_adap,
+					const struct i2c_msg *msg)
+{
+	struct cx231xx_i2c *bus = i2c_adap->algo_data;
+	struct cx231xx *dev = bus->dev;
+	struct cx231xx_i2c_xfer_data req_data;
+	int status = 0;
+
+	/* prepare xfer_data struct */
+	req_data.dev_addr = msg->addr;
+	req_data.direction = msg->flags;
+	req_data.saddr_len = 0;
+	req_data.saddr_dat = 0;
+	req_data.buf_size = 0;
+	req_data.p_buffer = NULL;
+
+	/* usb send command */
+	status = dev->cx231xx_send_usb_command(bus, &req_data);
+
+	return status < 0 ? status : 0;
+}
+
+/*
+ * cx231xx_i2c_xfer()
+ * the main i2c transfer function
+ */
+static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
+			    struct i2c_msg msgs[], int num)
+{
+	struct cx231xx_i2c *bus = i2c_adap->algo_data;
+	struct cx231xx *dev = bus->dev;
+	int addr, rc, i, byte;
+
+	if (num <= 0)
+		return 0;
+	mutex_lock(&dev->i2c_lock);
+	for (i = 0; i < num; i++) {
+
+		addr = msgs[i].addr >> 1;
+
+		dprintk2(2, "%s %s addr=%x len=%d:",
+			 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
+			 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
+		if (!msgs[i].len) {
+			/* no len: check only for device presence */
+			rc = cx231xx_i2c_check_for_device(i2c_adap, &msgs[i]);
+			if (rc < 0) {
+				dprintk2(2, " no device\n");
+				mutex_unlock(&dev->i2c_lock);
+				return rc;
+			}
+
+		} else if (msgs[i].flags & I2C_M_RD) {
+			/* read bytes */
+			rc = cx231xx_i2c_recv_bytes(i2c_adap, &msgs[i]);
+			if (i2c_debug >= 2) {
+				for (byte = 0; byte < msgs[i].len; byte++)
+					printk(" %02x", msgs[i].buf[byte]);
+			}
+		} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
+			   msgs[i].addr == msgs[i + 1].addr
+			   && (msgs[i].len <= 2) && (bus->nr < 3)) {
+			/* read bytes */
+			rc = cx231xx_i2c_recv_bytes_with_saddr(i2c_adap,
+							       &msgs[i],
+							       &msgs[i + 1]);
+			if (i2c_debug >= 2) {
+				for (byte = 0; byte < msgs[i].len; byte++)
+					printk(" %02x", msgs[i].buf[byte]);
+			}
+			i++;
+		} else {
+			/* write bytes */
+			if (i2c_debug >= 2) {
+				for (byte = 0; byte < msgs[i].len; byte++)
+					printk(" %02x", msgs[i].buf[byte]);
+			}
+			rc = cx231xx_i2c_send_bytes(i2c_adap, &msgs[i]);
+		}
+		if (rc < 0)
+			goto err;
+		if (i2c_debug >= 2)
+			printk("\n");
+	}
+	mutex_unlock(&dev->i2c_lock);
+	return num;
+err:
+	dprintk2(2, " ERROR: %i\n", rc);
+	mutex_unlock(&dev->i2c_lock);
+	return rc;
+}
+
+/* ----------------------------------------------------------- */
+
+/*
+ * functionality()
+ */
+static u32 functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm cx231xx_algo = {
+	.master_xfer = cx231xx_i2c_xfer,
+	.functionality = functionality,
+};
+
+static struct i2c_adapter cx231xx_adap_template = {
+	.owner = THIS_MODULE,
+	.name = "cx231xx",
+	.algo = &cx231xx_algo,
+};
+
+static struct i2c_client cx231xx_client_template = {
+	.name = "cx231xx internal",
+};
+
+/* ----------------------------------------------------------- */
+
+/*
+ * i2c_devs
+ * incomplete list of known devices
+ */
+static char *i2c_devs[128] = {
+	[0x60 >> 1] = "colibri",
+	[0x88 >> 1] = "hammerhead",
+	[0x8e >> 1] = "CIR",
+	[0x32 >> 1] = "GeminiIII",
+	[0x02 >> 1] = "Aquarius",
+	[0xa0 >> 1] = "eeprom",
+	[0xc0 >> 1] = "tuner",
+	[0xc2 >> 1] = "tuner",
+};
+
+/*
+ * cx231xx_do_i2c_scan()
+ * check i2c address range for devices
+ */
+void cx231xx_do_i2c_scan(struct cx231xx *dev, struct i2c_client *c)
+{
+	unsigned char buf;
+	int i, rc;
+
+	cx231xx_info(": Checking for I2C devices ..\n");
+	for (i = 0; i < 128; i++) {
+		c->addr = i;
+		rc = i2c_master_recv(c, &buf, 0);
+		if (rc < 0)
+			continue;
+		cx231xx_info("%s: i2c scan: found device @ 0x%x  [%s]\n",
+			     dev->name, i << 1,
+			     i2c_devs[i] ? i2c_devs[i] : "???");
+	}
+	cx231xx_info(": Completed Checking for I2C devices.\n");
+}
+
+/*
+ * cx231xx_i2c_register()
+ * register i2c bus
+ */
+int cx231xx_i2c_register(struct cx231xx_i2c *bus)
+{
+	struct cx231xx *dev = bus->dev;
+
+	BUG_ON(!dev->cx231xx_send_usb_command);
+
+	bus->i2c_adap = cx231xx_adap_template;
+	bus->i2c_client = cx231xx_client_template;
+	bus->i2c_adap.dev.parent = &dev->udev->dev;
+
+	strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name));
+
+	bus->i2c_adap.algo_data = bus;
+	i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev);
+	i2c_add_adapter(&bus->i2c_adap);
+
+	bus->i2c_client.adapter = &bus->i2c_adap;
+
+	if (0 == bus->i2c_rc) {
+		if (i2c_scan)
+			cx231xx_do_i2c_scan(dev, &bus->i2c_client);
+	} else
+		cx231xx_warn("%s: i2c bus %d register FAILED\n",
+			     dev->name, bus->nr);
+
+	return bus->i2c_rc;
+}
+
+/*
+ * cx231xx_i2c_unregister()
+ * unregister i2c_bus
+ */
+int cx231xx_i2c_unregister(struct cx231xx_i2c *bus)
+{
+	i2c_del_adapter(&bus->i2c_adap);
+	return 0;
+}
diff --git a/drivers/media/usb/cx231xx/cx231xx-input.c b/drivers/media/usb/cx231xx/cx231xx-input.c
new file mode 100644
index 0000000..96176e9
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-input.c
@@ -0,0 +1,119 @@
+/*
+ *   cx231xx IR glue driver
+ *
+ *   Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ *   Polaris (cx231xx) has its support for IR's with a design close to MCE.
+ *   however, a few designs are using an external I2C chip for IR, instead
+ *   of using the one provided by the chip.
+ *   This driver provides support for those extra devices
+ *
+ *   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 version 2.
+ *
+ *   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 "cx231xx.h"
+#include <linux/usb.h>
+#include <linux/slab.h>
+
+#define MODULE_NAME "cx231xx-input"
+
+static int get_key_isdbt(struct IR_i2c *ir, u32 *ir_key,
+			 u32 *ir_raw)
+{
+	int	rc;
+	u8	cmd, scancode;
+
+	dev_dbg(&ir->rc->input_dev->dev, "%s\n", __func__);
+
+		/* poll IR chip */
+	rc = i2c_master_recv(ir->c, &cmd, 1);
+	if (rc < 0)
+		return rc;
+	if (rc != 1)
+		return -EIO;
+
+	/* it seems that 0xFE indicates that a button is still hold
+	   down, while 0xff indicates that no button is hold
+	   down. 0xfe sequences are sometimes interrupted by 0xFF */
+
+	if (cmd == 0xff)
+		return 0;
+
+	scancode =
+		 ((cmd & 0x01) ? 0x80 : 0) |
+		 ((cmd & 0x02) ? 0x40 : 0) |
+		 ((cmd & 0x04) ? 0x20 : 0) |
+		 ((cmd & 0x08) ? 0x10 : 0) |
+		 ((cmd & 0x10) ? 0x08 : 0) |
+		 ((cmd & 0x20) ? 0x04 : 0) |
+		 ((cmd & 0x40) ? 0x02 : 0) |
+		 ((cmd & 0x80) ? 0x01 : 0);
+
+	dev_dbg(&ir->rc->input_dev->dev, "cmd %02x, scan = %02x\n",
+		cmd, scancode);
+
+	*ir_key = scancode;
+	*ir_raw = scancode;
+	return 1;
+}
+
+int cx231xx_ir_init(struct cx231xx *dev)
+{
+	struct i2c_board_info info;
+	u8 ir_i2c_bus;
+
+	dev_dbg(&dev->udev->dev, "%s\n", __func__);
+
+	/* Only initialize if a rc keycode map is defined */
+	if (!cx231xx_boards[dev->model].rc_map_name)
+		return -ENODEV;
+
+	request_module("ir-kbd-i2c");
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	memset(&dev->init_data, 0, sizeof(dev->init_data));
+	dev->init_data.rc_dev = rc_allocate_device();
+	if (!dev->init_data.rc_dev)
+		return -ENOMEM;
+
+	dev->init_data.name = cx231xx_boards[dev->model].name;
+
+	strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+	info.platform_data = &dev->init_data;
+
+	/*
+	 * Board-dependent values
+	 *
+	 * For now, there's just one type of hardware design using
+	 * an i2c device.
+	 */
+	dev->init_data.get_key = get_key_isdbt;
+	dev->init_data.ir_codes = cx231xx_boards[dev->model].rc_map_name;
+	/* The i2c micro-controller only outputs the cmd part of NEC protocol */
+	dev->init_data.rc_dev->scanmask = 0xff;
+	dev->init_data.rc_dev->driver_name = "cx231xx";
+	dev->init_data.type = RC_TYPE_NEC;
+	info.addr = 0x30;
+
+	/* Load and bind ir-kbd-i2c */
+	ir_i2c_bus = cx231xx_boards[dev->model].ir_i2c_master;
+	dev_dbg(&dev->udev->dev, "Trying to bind ir at bus %d, addr 0x%02x\n",
+		ir_i2c_bus, info.addr);
+	dev->ir_i2c_client = i2c_new_device(&dev->i2c_bus[ir_i2c_bus].i2c_adap, &info);
+
+	return 0;
+}
+
+void cx231xx_ir_exit(struct cx231xx *dev)
+{
+	if (dev->ir_i2c_client)
+		i2c_unregister_device(dev->ir_i2c_client);
+	dev->ir_i2c_client = NULL;
+}
diff --git a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
new file mode 100644
index 0000000..7473c33
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
@@ -0,0 +1,795 @@
+/*
+   cx231xx-pcb-config.c - driver for Conexant
+		Cx23100/101/102 USB video capture devices
+
+   Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cx231xx.h"
+#include "cx231xx-conf-reg.h"
+
+static unsigned int pcb_debug;
+module_param(pcb_debug, int, 0644);
+MODULE_PARM_DESC(pcb_debug, "enable pcb config debug messages [video]");
+
+/******************************************************************************/
+
+struct pcb_config cx231xx_Scenario[] = {
+	{
+	 INDEX_SELFPOWER_DIGITAL_ONLY,	/* index */
+	 USB_SELF_POWER,	/* power_type */
+	 0,			/* speed , not decide yet */
+	 MOD_DIGITAL,		/* mode */
+	 SOURCE_TS_BDA,		/* ts1_source, digital tv only */
+	 NOT_SUPPORTED,		/* ts2_source  */
+	 NOT_SUPPORTED,		/* analog source */
+
+	 0,			/* digital_index  */
+	 0,			/* analog index */
+	 0,			/* dif_index   */
+	 0,			/* external_index */
+
+	 1,			/* only one configuration */
+	 {
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index */
+	    1,			/* ts1 index */
+	    NOT_SUPPORTED,	/* TS2 index */
+	    NOT_SUPPORTED,	/* AUDIO */
+	    NOT_SUPPORTED,	/* VIDEO */
+	    NOT_SUPPORTED,	/* VANC */
+	    NOT_SUPPORTED,	/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   ,
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 ,
+	 /* full-speed config */
+	 {
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index */
+	    1,			/* ts1 index */
+	    NOT_SUPPORTED,	/* TS2 index */
+	    NOT_SUPPORTED,	/* AUDIO */
+	    NOT_SUPPORTED,	/* VIDEO */
+	    NOT_SUPPORTED,	/* VANC */
+	    NOT_SUPPORTED,	/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 }
+	,
+
+	{
+	 INDEX_SELFPOWER_DUAL_DIGITAL,	/* index */
+	 USB_SELF_POWER,	/* power_type */
+	 0,			/* speed , not decide yet */
+	 MOD_DIGITAL,		/* mode */
+	 SOURCE_TS_BDA,		/* ts1_source, digital tv only */
+	 0,			/* ts2_source,need update from register */
+	 NOT_SUPPORTED,		/* analog source */
+	 0,			/* digital_index  */
+	 0,			/* analog index */
+	 0,			/* dif_index */
+	 0,			/* external_index */
+
+	 1,			/* only one configuration */
+	 {
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index */
+	    1,			/* ts1 index */
+	    2,			/* TS2 index */
+	    NOT_SUPPORTED,	/* AUDIO */
+	    NOT_SUPPORTED,	/* VIDEO */
+	    NOT_SUPPORTED,	/* VANC */
+	    NOT_SUPPORTED,	/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 ,
+	 /* full-speed */
+	 {
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index */
+	    1,			/* ts1 index */
+	    2,			/* TS2 index */
+	    NOT_SUPPORTED,	/* AUDIO */
+	    NOT_SUPPORTED,	/* VIDEO */
+	    NOT_SUPPORTED,	/* VANC */
+	    NOT_SUPPORTED,	/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 }
+	,
+
+	{
+	 INDEX_SELFPOWER_ANALOG_ONLY,	/* index */
+	 USB_SELF_POWER,	/* power_type */
+	 0,			/* speed , not decide yet */
+	 MOD_ANALOG | MOD_DIF | MOD_EXTERNAL,	/* mode ,analog tv only */
+	 NOT_SUPPORTED,		/* ts1_source, NOT SUPPORT */
+	 NOT_SUPPORTED,		/* ts2_source,NOT SUPPORT */
+	 0,			/* analog source, need update */
+
+	 0,			/* digital_index  */
+	 0,			/* analog index */
+	 0,			/* dif_index */
+	 0,			/* external_index */
+
+	 1,			/* only one configuration */
+	 {
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index */
+	    NOT_SUPPORTED,	/* ts1 index */
+	    NOT_SUPPORTED,	/* TS2 index */
+	    1,			/* AUDIO */
+	    2,			/* VIDEO */
+	    3,			/* VANC */
+	    4,			/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 ,
+	 /* full-speed */
+	 {
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index */
+	    NOT_SUPPORTED,	/* ts1 index */
+	    NOT_SUPPORTED,	/* TS2 index */
+	    1,			/* AUDIO */
+	    2,			/* VIDEO */
+	    NOT_SUPPORTED,	/* VANC */
+	    NOT_SUPPORTED,	/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 }
+	,
+
+	{
+	 INDEX_SELFPOWER_DUAL,	/* index */
+	 USB_SELF_POWER,	/* power_type */
+	 0,			/* speed , not decide yet */
+	 /* mode ,analog tv and digital path */
+	 MOD_ANALOG | MOD_DIF | MOD_DIGITAL | MOD_EXTERNAL,
+	 0,			/* ts1_source,will update in register */
+	 NOT_SUPPORTED,		/* ts2_source,NOT SUPPORT */
+	 0,			/* analog source need update */
+	 0,			/* digital_index  */
+	 0,			/* analog index */
+	 0,			/* dif_index */
+	 0,			/* external_index */
+	 1,			/* only one configuration */
+	 {
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index */
+	    1,			/* ts1 index */
+	    NOT_SUPPORTED,	/* TS2 index */
+	    2,			/* AUDIO */
+	    3,			/* VIDEO */
+	    4,			/* VANC */
+	    5,			/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 ,
+	 /* full-speed */
+	 {
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index */
+	    1,			/* ts1 index */
+	    NOT_SUPPORTED,	/* TS2 index */
+	    2,			/* AUDIO */
+	    3,			/* VIDEO */
+	    NOT_SUPPORTED,	/* VANC */
+	    NOT_SUPPORTED,	/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 }
+	,
+
+	{
+	 INDEX_SELFPOWER_TRIPLE,	/* index */
+	 USB_SELF_POWER,	/* power_type */
+	 0,			/* speed , not decide yet */
+	 /* mode ,analog tv and digital path */
+	 MOD_ANALOG | MOD_DIF | MOD_DIGITAL | MOD_EXTERNAL,
+	 0,			/* ts1_source, update in register */
+	 0,			/* ts2_source,update in register */
+	 0,			/* analog source, need update */
+
+	 0,			/* digital_index  */
+	 0,			/* analog index */
+	 0,			/* dif_index */
+	 0,			/* external_index */
+	 1,			/* only one configuration */
+	 {
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index */
+	    1,			/* ts1 index */
+	    2,			/* TS2 index */
+	    3,			/* AUDIO */
+	    4,			/* VIDEO */
+	    5,			/* VANC */
+	    6,			/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 ,
+	 /* full-speed */
+	 {
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index */
+	    1,			/* ts1 index */
+	    2,			/* TS2 index */
+	    3,			/* AUDIO */
+	    4,			/* VIDEO */
+	    NOT_SUPPORTED,	/* VANC */
+	    NOT_SUPPORTED,	/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 }
+	,
+
+	{
+	 INDEX_SELFPOWER_COMPRESSOR,	/* index */
+	 USB_SELF_POWER,	/* power_type */
+	 0,			/* speed , not decide yet */
+	 /* mode ,analog tv AND DIGITAL path */
+	 MOD_ANALOG | MOD_DIF | MOD_DIGITAL | MOD_EXTERNAL,
+	 NOT_SUPPORTED,		/* ts1_source, disable */
+	 SOURCE_TS_BDA,		/* ts2_source */
+	 0,			/* analog source,need update */
+	 0,			/* digital_index  */
+	 0,			/* analog index */
+	 0,			/* dif_index */
+	 0,			/* external_index */
+	 1,			/* only one configuration */
+	 {
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index */
+	    NOT_SUPPORTED,	/* ts1 index */
+	    1,			/* TS2 index */
+	    2,			/* AUDIO */
+	    3,			/* VIDEO */
+	    4,			/* VANC */
+	    5,			/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 ,
+	 /* full-speed  */
+	 {
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index */
+	    NOT_SUPPORTED,	/* ts1 index */
+	    1,			/* TS2 index */
+	    2,			/* AUDIO */
+	    3,			/* VIDEO */
+	    NOT_SUPPORTED,	/* VANC */
+	    NOT_SUPPORTED,	/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 }
+	,
+
+	{
+	 INDEX_BUSPOWER_DIGITAL_ONLY,	/* index */
+	 USB_BUS_POWER,		/* power_type */
+	 0,			/* speed , not decide yet */
+	 MOD_DIGITAL,		/* mode ,analog tv AND DIGITAL path */
+	 SOURCE_TS_BDA,		/* ts1_source, disable */
+	 NOT_SUPPORTED,		/* ts2_source */
+	 NOT_SUPPORTED,		/* analog source */
+
+	 0,			/* digital_index  */
+	 0,			/* analog index */
+	 0,			/* dif_index */
+	 0,			/* external_index */
+
+	 1,			/* only one configuration */
+	 {
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index  = 2 */
+	    1,			/* ts1 index */
+	    NOT_SUPPORTED,	/* TS2 index */
+	    NOT_SUPPORTED,	/* AUDIO */
+	    NOT_SUPPORTED,	/* VIDEO */
+	    NOT_SUPPORTED,	/* VANC */
+	    NOT_SUPPORTED,	/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 ,
+	 /* full-speed */
+	 {
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index  = 2 */
+	    1,			/* ts1 index */
+	    NOT_SUPPORTED,	/* TS2 index */
+	    NOT_SUPPORTED,	/* AUDIO */
+	    NOT_SUPPORTED,	/* VIDEO */
+	    NOT_SUPPORTED,	/* VANC */
+	    NOT_SUPPORTED,	/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 }
+	,
+	{
+	 INDEX_BUSPOWER_ANALOG_ONLY,	/* index */
+	 USB_BUS_POWER,		/* power_type */
+	 0,			/* speed , not decide yet */
+	 MOD_ANALOG,		/* mode ,analog tv AND DIGITAL path */
+	 NOT_SUPPORTED,		/* ts1_source, disable */
+	 NOT_SUPPORTED,		/* ts2_source */
+	 SOURCE_ANALOG,		/* analog source--analog */
+	 0,			/* digital_index  */
+	 0,			/* analog index */
+	 0,			/* dif_index */
+	 0,			/* external_index */
+	 1,			/* only one configuration */
+	 {
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index */
+	    NOT_SUPPORTED,	/* ts1 index */
+	    NOT_SUPPORTED,	/* TS2 index */
+	    1,			/* AUDIO */
+	    2,			/* VIDEO */
+	    3,			/* VANC */
+	    4,			/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 ,
+	 {			/* full-speed */
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index */
+	    NOT_SUPPORTED,	/* ts1 index */
+	    NOT_SUPPORTED,	/* TS2 index */
+	    1,			/* AUDIO */
+	    2,			/* VIDEO */
+	    NOT_SUPPORTED,	/* VANC */
+	    NOT_SUPPORTED,	/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 }
+	,
+	{
+	 INDEX_BUSPOWER_DIF_ONLY,	/* index */
+	 USB_BUS_POWER,		/* power_type */
+	 0,			/* speed , not decide yet */
+	 /* mode ,analog tv AND DIGITAL path */
+	 MOD_DIF | MOD_ANALOG | MOD_DIGITAL | MOD_EXTERNAL,
+	 SOURCE_TS_BDA,		/* ts1_source, disable */
+	 NOT_SUPPORTED,		/* ts2_source */
+	 SOURCE_DIF | SOURCE_ANALOG | SOURCE_EXTERNAL,	/* analog source, dif */
+	 0,			/* digital_index  */
+	 0,			/* analog index */
+	 0,			/* dif_index */
+	 0,			/* external_index */
+	 1,			/* only one configuration */
+	 {
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index */
+	    1,			/* ts1 index */
+	    NOT_SUPPORTED,	/* TS2 index */
+	    2,			/* AUDIO */
+	    3,			/* VIDEO */
+	    4,			/* VANC */
+	    5,			/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 ,
+	 {			/* full speed */
+	  {
+	   0,			/* config index */
+	   {
+	    0,			/* interrupt ep index */
+	    1,			/* ts1 index */
+	    NOT_SUPPORTED,	/* TS2 index */
+	    2,			/* AUDIO */
+	    3,			/* VIDEO */
+	    NOT_SUPPORTED,	/* VANC */
+	    NOT_SUPPORTED,	/* HANC */
+	    NOT_SUPPORTED	/* ir_index */
+	    }
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  ,
+	  {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED,
+			   NOT_SUPPORTED}
+	   }
+	  }
+	 }
+	,
+
+};
+
+/*****************************************************************/
+
+u32 initialize_cx231xx(struct cx231xx *dev)
+{
+	u32 config_info = 0;
+	struct pcb_config *p_pcb_info;
+	u8 usb_speed = 1;	/* from register,1--HS, 0--FS  */
+	u8 data[4] = { 0, 0, 0, 0 };
+	u32 ts1_source = 0;
+	u32 ts2_source = 0;
+	u32 analog_source = 0;
+	u8 _current_scenario_idx = 0xff;
+
+	ts1_source = SOURCE_TS_BDA;
+	ts2_source = SOURCE_TS_BDA;
+
+	/* read board config register to find out which
+	pcb config it is related to */
+	cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT, data, 4);
+
+	config_info = *((u32 *) data);
+	usb_speed = (u8) (config_info & 0x1);
+
+	/* Verify this device belongs to Bus power or Self power device */
+	if (config_info & BUS_POWER) {	/* bus-power */
+		switch (config_info & BUSPOWER_MASK) {
+		case TS1_PORT | BUS_POWER:
+			cx231xx_Scenario[INDEX_BUSPOWER_DIGITAL_ONLY].speed =
+			    usb_speed;
+			p_pcb_info =
+			    &cx231xx_Scenario[INDEX_BUSPOWER_DIGITAL_ONLY];
+			_current_scenario_idx = INDEX_BUSPOWER_DIGITAL_ONLY;
+			break;
+		case AVDEC_ENABLE | BUS_POWER:
+			cx231xx_Scenario[INDEX_BUSPOWER_ANALOG_ONLY].speed =
+			    usb_speed;
+			p_pcb_info =
+			    &cx231xx_Scenario[INDEX_BUSPOWER_ANALOG_ONLY];
+			_current_scenario_idx = INDEX_BUSPOWER_ANALOG_ONLY;
+			break;
+		case AVDEC_ENABLE | BUS_POWER | TS1_PORT:
+			cx231xx_Scenario[INDEX_BUSPOWER_DIF_ONLY].speed =
+			    usb_speed;
+			p_pcb_info = &cx231xx_Scenario[INDEX_BUSPOWER_DIF_ONLY];
+			_current_scenario_idx = INDEX_BUSPOWER_DIF_ONLY;
+			break;
+		default:
+			cx231xx_info("bad config in buspower!!!!\n");
+			cx231xx_info("config_info=%x\n",
+				     (config_info & BUSPOWER_MASK));
+			return 1;
+		}
+	} else {		/* self-power */
+
+		switch (config_info & SELFPOWER_MASK) {
+		case TS1_PORT | SELF_POWER:
+			cx231xx_Scenario[INDEX_SELFPOWER_DIGITAL_ONLY].speed =
+			    usb_speed;
+			p_pcb_info =
+			    &cx231xx_Scenario[INDEX_SELFPOWER_DIGITAL_ONLY];
+			_current_scenario_idx = INDEX_SELFPOWER_DIGITAL_ONLY;
+			break;
+		case TS1_TS2_PORT | SELF_POWER:
+			cx231xx_Scenario[INDEX_SELFPOWER_DUAL_DIGITAL].speed =
+			    usb_speed;
+			cx231xx_Scenario[INDEX_SELFPOWER_DUAL_DIGITAL].
+			    ts2_source = ts2_source;
+			p_pcb_info =
+			    &cx231xx_Scenario[INDEX_SELFPOWER_DUAL_DIGITAL];
+			_current_scenario_idx = INDEX_SELFPOWER_DUAL_DIGITAL;
+			break;
+		case AVDEC_ENABLE | SELF_POWER:
+			cx231xx_Scenario[INDEX_SELFPOWER_ANALOG_ONLY].speed =
+			    usb_speed;
+			cx231xx_Scenario[INDEX_SELFPOWER_ANALOG_ONLY].
+			    analog_source = analog_source;
+			p_pcb_info =
+			    &cx231xx_Scenario[INDEX_SELFPOWER_ANALOG_ONLY];
+			_current_scenario_idx = INDEX_SELFPOWER_ANALOG_ONLY;
+			break;
+		case AVDEC_ENABLE | TS1_PORT | SELF_POWER:
+			cx231xx_Scenario[INDEX_SELFPOWER_DUAL].speed =
+			    usb_speed;
+			cx231xx_Scenario[INDEX_SELFPOWER_DUAL].ts1_source =
+			    ts1_source;
+			cx231xx_Scenario[INDEX_SELFPOWER_DUAL].analog_source =
+			    analog_source;
+			p_pcb_info = &cx231xx_Scenario[INDEX_SELFPOWER_DUAL];
+			_current_scenario_idx = INDEX_SELFPOWER_DUAL;
+			break;
+		case AVDEC_ENABLE | TS1_TS2_PORT | SELF_POWER:
+			cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE].speed =
+			    usb_speed;
+			cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE].ts1_source =
+			    ts1_source;
+			cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE].ts2_source =
+			    ts2_source;
+			cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE].analog_source =
+			    analog_source;
+			p_pcb_info = &cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE];
+			_current_scenario_idx = INDEX_SELFPOWER_TRIPLE;
+			break;
+		case AVDEC_ENABLE | TS1VIP_TS2_PORT | SELF_POWER:
+			cx231xx_Scenario[INDEX_SELFPOWER_COMPRESSOR].speed =
+			    usb_speed;
+			cx231xx_Scenario[INDEX_SELFPOWER_COMPRESSOR].
+			    analog_source = analog_source;
+			p_pcb_info =
+			    &cx231xx_Scenario[INDEX_SELFPOWER_COMPRESSOR];
+			_current_scenario_idx = INDEX_SELFPOWER_COMPRESSOR;
+			break;
+		default:
+			cx231xx_info("bad senario!!!!!\n");
+			cx231xx_info("config_info=%x\n",
+				     (config_info & SELFPOWER_MASK));
+			return 1;
+		}
+	}
+
+	dev->current_scenario_idx = _current_scenario_idx;
+
+	memcpy(&dev->current_pcb_config, p_pcb_info,
+		   sizeof(struct pcb_config));
+
+	if (pcb_debug) {
+		cx231xx_info("SC(0x00) register = 0x%x\n", config_info);
+		cx231xx_info("scenario %d\n",
+			    (dev->current_pcb_config.index) + 1);
+		cx231xx_info("type=%x\n", dev->current_pcb_config.type);
+		cx231xx_info("mode=%x\n", dev->current_pcb_config.mode);
+		cx231xx_info("speed=%x\n", dev->current_pcb_config.speed);
+		cx231xx_info("ts1_source=%x\n",
+			     dev->current_pcb_config.ts1_source);
+		cx231xx_info("ts2_source=%x\n",
+			     dev->current_pcb_config.ts2_source);
+		cx231xx_info("analog_source=%x\n",
+			     dev->current_pcb_config.analog_source);
+	}
+
+	return 0;
+}
diff --git a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h
new file mode 100644
index 0000000..f5e46e8
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h
@@ -0,0 +1,231 @@
+/*
+   cx231xx-pcb-cfg.h - driver for Conexant
+		Cx23100/101/102 USB video capture devices
+
+   Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _PCB_CONFIG_H_
+#define _PCB_CONFIG_H_
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+/***************************************************************************
+				* Class Information *
+***************************************************************************/
+#define CLASS_DEFAULT       0xFF
+
+enum VENDOR_REQUEST_TYPE {
+	/* Set/Get I2C */
+	VRT_SET_I2C0 = 0x0,
+	VRT_SET_I2C1 = 0x1,
+	VRT_SET_I2C2 = 0x2,
+	VRT_GET_I2C0 = 0x4,
+	VRT_GET_I2C1 = 0x5,
+	VRT_GET_I2C2 = 0x6,
+
+	/* Set/Get GPIO */
+	VRT_SET_GPIO = 0x8,
+	VRT_GET_GPIO = 0x9,
+
+	/* Set/Get GPIE */
+	VRT_SET_GPIE = 0xA,
+	VRT_GET_GPIE = 0xB,
+
+	/* Set/Get Register Control/Status */
+	VRT_SET_REGISTER = 0xC,
+	VRT_GET_REGISTER = 0xD,
+
+	/* Get Extended Compat ID Descriptor */
+	VRT_GET_EXTCID_DESC = 0xFF,
+};
+
+enum BYTE_ENABLE_MASK {
+	ENABLE_ONE_BYTE = 0x1,
+	ENABLE_TWE_BYTE = 0x3,
+	ENABLE_THREE_BYTE = 0x7,
+	ENABLE_FOUR_BYTE = 0xF,
+};
+
+#define SPEED_MASK      0x1
+enum USB_SPEED{
+	FULL_SPEED = 0x0,	/* 0: full speed */
+	HIGH_SPEED = 0x1	/* 1: high speed */
+};
+
+enum _true_false{
+	FALSE = 0,
+	TRUE = 1
+};
+
+#define TS_MASK         0x6
+enum TS_PORT{
+	NO_TS_PORT = 0x0,	/* 2'b00: Neither port used. PCB not a Hybrid,
+				   only offers Analog TV or Video */
+	TS1_PORT = 0x4,		/* 2'b10: TS1 Input (Hybrid mode :
+				Digital or External Analog/Compressed source) */
+	TS1_TS2_PORT = 0x6,	/* 2'b11: TS1 & TS2 Inputs
+				(Dual inputs from Digital and/or
+				External Analog/Compressed sources) */
+	TS1_EXT_CLOCK = 0x6,	/* 2'b11: TS1 & TS2 as selector
+						to external clock */
+	TS1VIP_TS2_PORT = 0x2	/* 2'b01: TS1 used as 656/VIP Output,
+				   TS2 Input (from Compressor) */
+};
+
+#define EAVP_MASK       0x8
+enum EAV_PRESENT{
+	NO_EXTERNAL_AV = 0x0,	/* 0: No External A/V inputs
+						(no need for i2s blcok),
+						Analog Tuner must be present */
+	EXTERNAL_AV = 0x8	/* 1: External A/V inputs
+						present (requires i2s blk) */
+};
+
+#define ATM_MASK        0x30
+enum AT_MODE{
+	DIF_TUNER = 0x30,	/* 2'b11: IF Tuner (requires use of DIF) */
+	BASEBAND_SOUND = 0x20,	/* 2'b10: Baseband Composite &
+						Sound-IF Signals present */
+	NO_TUNER = 0x10		/* 2'b0x: No Analog Tuner present */
+};
+
+#define PWR_SEL_MASK    0x40
+enum POWE_TYPE{
+	SELF_POWER = 0x0,	/* 0: self power */
+	BUS_POWER = 0x40	/* 1: bus power */
+};
+
+enum USB_POWE_TYPE{
+	USB_SELF_POWER = 0,
+	USB_BUS_POWER
+};
+
+#define BO_0_MASK       0x80
+enum AVDEC_STATUS{
+	AVDEC_DISABLE = 0x0,	/* 0: A/V Decoder Disabled */
+	AVDEC_ENABLE = 0x80	/* 1: A/V Decoder Enabled */
+};
+
+#define BO_1_MASK       0x100
+
+#define BUSPOWER_MASK   0xC4	/* for Polaris spec 0.8 */
+#define SELFPOWER_MASK  0x86
+
+/***************************************************************************/
+#define NOT_DECIDE_YET  0xFE
+#define NOT_SUPPORTED   0xFF
+
+/***************************************************************************
+				* for mod field use *
+***************************************************************************/
+#define MOD_DIGITAL     0x1
+#define MOD_ANALOG      0x2
+#define MOD_DIF         0x4
+#define MOD_EXTERNAL    0x8
+#define CAP_ALL_MOD     0x0f
+
+/***************************************************************************
+				* source define *
+***************************************************************************/
+#define SOURCE_DIGITAL          0x1
+#define SOURCE_ANALOG           0x2
+#define SOURCE_DIF              0x4
+#define SOURCE_EXTERNAL         0x8
+#define SOURCE_TS_BDA			0x10
+#define SOURCE_TS_ENCODE		0x20
+#define SOURCE_TS_EXTERNAL   	0x40
+
+/***************************************************************************
+				* interface information define *
+***************************************************************************/
+struct INTERFACE_INFO {
+	u8 interrupt_index;
+	u8 ts1_index;
+	u8 ts2_index;
+	u8 audio_index;
+	u8 video_index;
+	u8 vanc_index;		/* VBI */
+	u8 hanc_index;		/* Sliced CC */
+	u8 ir_index;
+};
+
+enum INDEX_INTERFACE_INFO{
+	INDEX_INTERRUPT = 0x0,
+	INDEX_TS1,
+	INDEX_TS2,
+	INDEX_AUDIO,
+	INDEX_VIDEO,
+	INDEX_VANC,
+	INDEX_HANC,
+	INDEX_IR,
+};
+
+/***************************************************************************
+				* configuration information define *
+***************************************************************************/
+struct CONFIG_INFO {
+	u8 config_index;
+	struct INTERFACE_INFO interface_info;
+};
+
+struct pcb_config {
+	u8 index;
+	u8 type;		/* bus power or self power,
+					   self power--0, bus_power--1 */
+	u8 speed;		/* usb speed, 2.0--1, 1.1--0 */
+	u8 mode;		/* digital , anlog, dif or external A/V */
+	u32 ts1_source;		/* three source -- BDA,External,encode */
+	u32 ts2_source;
+	u32 analog_source;
+	u8 digital_index;	/* bus-power used */
+	u8 analog_index;	/* bus-power used */
+	u8 dif_index;		/* bus-power used */
+	u8 external_index;	/* bus-power used */
+	u8 config_num;		/* current config num, 0,1,2,
+						   for self-power, always 0 */
+	struct CONFIG_INFO hs_config_info[3];
+	struct CONFIG_INFO fs_config_info[3];
+};
+
+enum INDEX_PCB_CONFIG{
+	INDEX_SELFPOWER_DIGITAL_ONLY = 0x0,
+	INDEX_SELFPOWER_DUAL_DIGITAL,
+	INDEX_SELFPOWER_ANALOG_ONLY,
+	INDEX_SELFPOWER_DUAL,
+	INDEX_SELFPOWER_TRIPLE,
+	INDEX_SELFPOWER_COMPRESSOR,
+	INDEX_BUSPOWER_DIGITAL_ONLY,
+	INDEX_BUSPOWER_ANALOG_ONLY,
+	INDEX_BUSPOWER_DIF_ONLY,
+	INDEX_BUSPOWER_EXTERNAL_ONLY,
+	INDEX_BUSPOWER_EXTERNAL_ANALOG,
+	INDEX_BUSPOWER_EXTERNAL_DIF,
+	INDEX_BUSPOWER_EXTERNAL_DIGITAL,
+	INDEX_BUSPOWER_DIGITAL_ANALOG,
+	INDEX_BUSPOWER_DIGITAL_DIF,
+	INDEX_BUSPOWER_DIGITAL_ANALOG_EXTERNAL,
+	INDEX_BUSPOWER_DIGITAL_DIF_EXTERNAL,
+};
+
+/***************************************************************************/
+struct cx231xx;
+
+u32 initialize_cx231xx(struct cx231xx *p_dev);
+
+#endif
diff --git a/drivers/media/usb/cx231xx/cx231xx-reg.h b/drivers/media/usb/cx231xx/cx231xx-reg.h
new file mode 100644
index 0000000..750c5d3
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-reg.h
@@ -0,0 +1,1564 @@
+/*
+   cx231xx-reg.h - driver for Conexant Cx23100/101/102
+	       USB video capture devices
+
+   Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _CX231XX_REG_H
+#define _CX231XX_REG_H
+
+/*****************************************************************************
+				* VBI codes *
+*****************************************************************************/
+
+#define SAV_ACTIVE_VIDEO_FIELD1		0x80
+#define EAV_ACTIVE_VIDEO_FIELD1		0x90
+
+#define SAV_ACTIVE_VIDEO_FIELD2		0xc0
+#define EAV_ACTIVE_VIDEO_FIELD2		0xd0
+
+#define SAV_VBLANK_FIELD1		0xa0
+#define EAV_VBLANK_FIELD1		0xb0
+
+#define SAV_VBLANK_FIELD2		0xe0
+#define EAV_VBLANK_FIELD2		0xf0
+
+#define SAV_VBI_FIELD1			0x20
+#define EAV_VBI_FIELD1			0x30
+
+#define SAV_VBI_FIELD2			0x60
+#define EAV_VBI_FIELD2			0x70
+
+/*****************************************************************************/
+/* Audio ADC Registers */
+#define CH_PWR_CTRL1			0x0000000e
+#define CH_PWR_CTRL2			0x0000000f
+/*****************************************************************************/
+
+#define      HOST_REG1                0x000
+#define      FLD_FORCE_CHIP_SEL       0x80
+#define      FLD_AUTO_INC_DIS         0x20
+#define      FLD_PREFETCH_EN          0x10
+/* Reserved [2:3] */
+#define      FLD_DIGITAL_PWR_DN       0x02
+#define      FLD_SLEEP                0x01
+
+/*****************************************************************************/
+#define      HOST_REG2                0x001
+
+/*****************************************************************************/
+#define      HOST_REG3                0x002
+
+/*****************************************************************************/
+/* added for polaris */
+#define      GPIO_PIN_CTL0            0x3
+#define      GPIO_PIN_CTL1            0x4
+#define      GPIO_PIN_CTL2            0x5
+#define      GPIO_PIN_CTL3            0x6
+#define      TS1_PIN_CTL0             0x7
+#define      TS1_PIN_CTL1             0x8
+/*****************************************************************************/
+
+#define      FLD_CLK_IN_EN            0x80
+#define      FLD_XTAL_CTRL            0x70
+#define      FLD_BB_CLK_MODE          0x0C
+#define      FLD_REF_DIV_PLL          0x02
+#define      FLD_REF_SEL_PLL1         0x01
+
+/*****************************************************************************/
+#define      CHIP_CTRL                0x100
+/* Reserved [27] */
+/* Reserved [31:21] */
+#define      FLD_CHIP_ACFG_DIS        0x00100000
+/* Reserved [19] */
+#define      FLD_DUAL_MODE_ADC2       0x00040000
+#define      FLD_SIF_EN               0x00020000
+#define      FLD_SOFT_RST             0x00010000
+#define      FLD_DEVICE_ID            0x0000ffff
+
+/*****************************************************************************/
+#define      AFE_CTRL                 0x104
+#define      AFE_CTRL_C2HH_SRC_CTRL   0x104
+#define      FLD_DIF_OUT_SEL          0xc0000000
+#define      FLD_AUX_PLL_CLK_ALT_SEL  0x3c000000
+#define      FLD_UV_ORDER_MODE        0x02000000
+#define      FLD_FUNC_MODE            0x01800000
+#define      FLD_ROT1_PHASE_CTL       0x007f8000
+#define      FLD_AUD_IN_SEL           0x00004000
+#define      FLD_LUMA_IN_SEL          0x00002000
+#define      FLD_CHROMA_IN_SEL        0x00001000
+/* reserve [11:10] */
+#define      FLD_INV_SPEC_DIS         0x00000200
+#define      FLD_VGA_SEL_CH3          0x00000100
+#define      FLD_VGA_SEL_CH2          0x00000080
+#define      FLD_VGA_SEL_CH1          0x00000040
+#define      FLD_DCR_BYP_CH1          0x00000020
+#define      FLD_DCR_BYP_CH2          0x00000010
+#define      FLD_DCR_BYP_CH3          0x00000008
+#define      FLD_EN_12DB_CH3          0x00000004
+#define      FLD_EN_12DB_CH2          0x00000002
+#define      FLD_EN_12DB_CH1          0x00000001
+
+/* redefine in Cx231xx */
+/*****************************************************************************/
+#define      DC_CTRL1                 0x108
+/* reserve [31:30] */
+#define      FLD_CLAMP_LVL_CH1        0x3fff8000
+#define      FLD_CLAMP_LVL_CH2        0x00007fff
+/*****************************************************************************/
+
+/*****************************************************************************/
+#define      DC_CTRL2                 0x10c
+/* reserve [31:28] */
+#define      FLD_CLAMP_LVL_CH3        0x00fffe00
+#define      FLD_CLAMP_WIND_LENTH     0x000001e0
+#define      FLD_C2HH_SAT_MIN         0x0000001e
+#define      FLD_FLT_BYP_SEL          0x00000001
+/*****************************************************************************/
+
+/*****************************************************************************/
+#define      DC_CTRL3                 0x110
+/* reserve [31:16] */
+#define      FLD_ERR_GAIN_CTL         0x00070000
+#define      FLD_LPF_MIN              0x0000ffff
+/*****************************************************************************/
+
+/*****************************************************************************/
+#define      DC_CTRL4                 0x114
+/* reserve [31:31] */
+#define      FLD_INTG_CH1             0x7fffffff
+/*****************************************************************************/
+
+/*****************************************************************************/
+#define      DC_CTRL5                 0x118
+/* reserve [31:31] */
+#define      FLD_INTG_CH2             0x7fffffff
+/*****************************************************************************/
+
+/*****************************************************************************/
+#define      DC_CTRL6                 0x11c
+/* reserve [31:31] */
+#define      FLD_INTG_CH3             0x7fffffff
+/*****************************************************************************/
+
+/*****************************************************************************/
+#define      PIN_CTRL                 0x120
+#define      FLD_OEF_AGC_RF           0x00000001
+#define      FLD_OEF_AGC_IFVGA        0x00000002
+#define      FLD_OEF_AGC_IF           0x00000004
+#define      FLD_REG_BO_PUD           0x80000000
+#define      FLD_IR_IRQ_STAT          0x40000000
+#define      FLD_AUD_IRQ_STAT         0x20000000
+#define      FLD_VID_IRQ_STAT         0x10000000
+/* Reserved [27:26] */
+#define      FLD_IRQ_N_OUT_EN         0x02000000
+#define      FLD_IRQ_N_POLAR          0x01000000
+/* Reserved [23:6] */
+#define      FLD_OE_AUX_PLL_CLK       0x00000020
+#define      FLD_OE_I2S_BCLK          0x00000010
+#define      FLD_OE_I2S_WCLK          0x00000008
+#define      FLD_OE_AGC_IF            0x00000004
+#define      FLD_OE_AGC_IFVGA         0x00000002
+#define      FLD_OE_AGC_RF            0x00000001
+
+/*****************************************************************************/
+#define      AUD_IO_CTRL              0x124
+/* Reserved [31:8] */
+#define      FLD_I2S_PORT_DIR         0x00000080
+#define      FLD_I2S_OUT_SRC          0x00000040
+#define      FLD_AUD_CHAN3_SRC        0x00000030
+#define      FLD_AUD_CHAN2_SRC        0x0000000c
+#define      FLD_AUD_CHAN1_SRC        0x00000003
+
+/*****************************************************************************/
+#define      AUD_LOCK1                0x128
+#define      FLD_AUD_LOCK_KI_SHIFT    0xc0000000
+#define      FLD_AUD_LOCK_KD_SHIFT    0x30000000
+/* Reserved [27:25] */
+#define      FLD_EN_AV_LOCK           0x01000000
+#define      FLD_VID_COUNT            0x00ffffff
+
+/*****************************************************************************/
+#define      AUD_LOCK2                0x12c
+#define      FLD_AUD_LOCK_KI_MULT     0xf0000000
+#define      FLD_AUD_LOCK_KD_MULT     0x0F000000
+/* Reserved [23:22] */
+#define      FLD_AUD_LOCK_FREQ_SHIFT  0x00300000
+#define      FLD_AUD_COUNT            0x000fffff
+
+/*****************************************************************************/
+#define      AFE_DIAG_CTRL1           0x134
+/* Reserved [31:16] */
+#define      FLD_CUV_DLY_LENGTH       0x0000ff00
+#define      FLD_YC_DLY_LENGTH        0x000000ff
+
+/*****************************************************************************/
+/* Poalris redefine */
+#define      AFE_DIAG_CTRL3           0x138
+/* Reserved [31:26] */
+#define      FLD_AUD_DUAL_FLAG_POL    0x02000000
+#define      FLD_VID_DUAL_FLAG_POL    0x01000000
+/* Reserved [23:23] */
+#define      FLD_COL_CLAMP_DIS_CH1    0x00400000
+#define      FLD_COL_CLAMP_DIS_CH2    0x00200000
+#define      FLD_COL_CLAMP_DIS_CH3    0x00100000
+
+#define      TEST_CTRL1               0x144
+/* Reserved [31:29] */
+#define      FLD_LBIST_EN             0x10000000
+/* Reserved [27:10] */
+#define      FLD_FI_BIST_INTR_R       0x0000200
+#define      FLD_FI_BIST_INTR_L       0x0000100
+#define      FLD_BIST_FAIL_AUD_PLL    0x0000080
+#define      FLD_BIST_INTR_AUD_PLL    0x0000040
+#define      FLD_BIST_FAIL_VID_PLL    0x0000020
+#define      FLD_BIST_INTR_VID_PLL    0x0000010
+/* Reserved [3:1] */
+#define      FLD_CIR_TEST_DIS         0x00000001
+
+/*****************************************************************************/
+#define      TEST_CTRL2               0x148
+#define      FLD_TSXCLK_POL_CTL       0x80000000
+#define      FLD_ISO_CTL_SEL          0x40000000
+#define      FLD_ISO_CTL_EN           0x20000000
+#define      FLD_BIST_DEBUGZ          0x10000000
+#define      FLD_AUD_BIST_TEST_H      0x0f000000
+/* Reserved [23:22] */
+#define      FLD_FLTRN_BIST_TEST_H    0x00020000
+#define      FLD_VID_BIST_TEST_H      0x00010000
+/* Reserved [19:17] */
+#define      FLD_BIST_TEST_H          0x00010000
+/* Reserved [15:13] */
+#define      FLD_TAB_EN               0x00001000
+/* Reserved [11:0] */
+
+/*****************************************************************************/
+#define      BIST_STAT                0x14c
+#define      FLD_AUD_BIST_FAIL_H      0xfff00000
+#define      FLD_FLTRN_BIST_FAIL_H    0x00180000
+#define      FLD_VID_BIST_FAIL_H      0x00070000
+#define      FLD_AUD_BIST_TST_DONE    0x0000fff0
+#define      FLD_FLTRN_BIST_TST_DONE  0x00000008
+#define      FLD_VID_BIST_TST_DONE    0x00000007
+
+/*****************************************************************************/
+/* DirectIF registers definition have been moved to DIF_reg.h                */
+/*****************************************************************************/
+#define      MODE_CTRL                0x400
+#define      FLD_AFD_PAL60_DIS        0x20000000
+#define      FLD_AFD_FORCE_SECAM      0x10000000
+#define      FLD_AFD_FORCE_PALNC      0x08000000
+#define      FLD_AFD_FORCE_PAL        0x04000000
+#define      FLD_AFD_PALM_SEL         0x03000000
+#define      FLD_CKILL_MODE           0x00300000
+#define      FLD_COMB_NOTCH_MODE      0x00c00000       /* bit[19:18] */
+#define      FLD_CLR_LOCK_STAT        0x00020000
+#define      FLD_FAST_LOCK_MD         0x00010000
+#define      FLD_WCEN                 0x00008000
+#define      FLD_CAGCEN               0x00004000
+#define      FLD_CKILLEN              0x00002000
+#define      FLD_AUTO_SC_LOCK         0x00001000
+#define      FLD_MAN_SC_FAST_LOCK     0x00000800
+#define      FLD_INPUT_MODE           0x00000600
+#define      FLD_AFD_ACQUIRE          0x00000100
+#define      FLD_AFD_NTSC_SEL         0x00000080
+#define      FLD_AFD_PAL_SEL          0x00000040
+#define      FLD_ACFG_DIS             0x00000020
+#define      FLD_SQ_PIXEL             0x00000010
+#define      FLD_VID_FMT_SEL          0x0000000f
+
+/*****************************************************************************/
+#define      OUT_CTRL1                0x404
+#define      FLD_POLAR                0x7f000000
+/* Reserved [23] */
+#define      FLD_RND_MODE             0x00600000
+#define      FLD_VIPCLAMP_EN          0x00100000
+#define      FLD_VIPBLANK_EN          0x00080000
+#define      FLD_VIP_OPT_AL           0x00040000
+#define      FLD_IDID0_SOURCE         0x00020000
+#define      FLD_DCMODE               0x00010000
+#define      FLD_CLK_GATING           0x0000c000
+#define      FLD_CLK_INVERT           0x00002000
+#define      FLD_HSFMT                0x00001000
+#define      FLD_VALIDFMT             0x00000800
+#define      FLD_ACTFMT               0x00000400
+#define      FLD_SWAPRAW              0x00000200
+#define      FLD_CLAMPRAW_EN          0x00000100
+#define      FLD_BLUE_FIELD_EN        0x00000080
+#define      FLD_BLUE_FIELD_ACT       0x00000040
+#define      FLD_TASKBIT_VAL          0x00000020
+#define      FLD_ANC_DATA_EN          0x00000010
+#define      FLD_VBIHACTRAW_EN        0x00000008
+#define      FLD_MODE10B              0x00000004
+#define      FLD_OUT_MODE             0x00000003
+
+/*****************************************************************************/
+#define      OUT_CTRL2                0x408
+#define      FLD_AUD_GRP              0xc0000000
+#define      FLD_SAMPLE_RATE          0x30000000
+#define      FLD_AUD_ANC_EN           0x08000000
+#define      FLD_EN_C                 0x04000000
+#define      FLD_EN_B                 0x02000000
+#define      FLD_EN_A                 0x01000000
+/* Reserved [23:20] */
+#define      FLD_IDID1_LSB            0x000c0000
+#define      FLD_IDID0_LSB            0x00030000
+#define      FLD_IDID1_MSB            0x0000ff00
+#define      FLD_IDID0_MSB            0x000000ff
+
+/*****************************************************************************/
+#define      GEN_STAT                 0x40c
+#define      FLD_VCR_DETECT           0x00800000
+#define      FLD_SPECIAL_PLAY_N       0x00400000
+#define      FLD_VPRES                0x00200000
+#define      FLD_AGC_LOCK             0x00100000
+#define      FLD_CSC_LOCK             0x00080000
+#define      FLD_VLOCK                0x00040000
+#define      FLD_SRC_LOCK             0x00020000
+#define      FLD_HLOCK                0x00010000
+#define      FLD_VSYNC_N              0x00008000
+#define      FLD_SRC_FIFO_UFLOW       0x00004000
+#define      FLD_SRC_FIFO_OFLOW       0x00002000
+#define      FLD_FIELD                0x00001000
+#define      FLD_AFD_FMT_STAT         0x00000f00
+#define      FLD_MV_TYPE2_PAIR        0x00000080
+#define      FLD_MV_T3CS              0x00000040
+#define      FLD_MV_CS                0x00000020
+#define      FLD_MV_PSP               0x00000010
+/* Reserved [3] */
+#define      FLD_MV_CDAT              0x00000003
+
+/*****************************************************************************/
+#define      INT_STAT_MASK            0x410
+#define      FLD_COMB_3D_FIFO_MSK     0x80000000
+#define      FLD_WSS_DAT_AVAIL_MSK    0x40000000
+#define      FLD_GS2_DAT_AVAIL_MSK    0x20000000
+#define      FLD_GS1_DAT_AVAIL_MSK    0x10000000
+#define      FLD_CC_DAT_AVAIL_MSK     0x08000000
+#define      FLD_VPRES_CHANGE_MSK     0x04000000
+#define      FLD_MV_CHANGE_MSK        0x02000000
+#define      FLD_END_VBI_EVEN_MSK     0x01000000
+#define      FLD_END_VBI_ODD_MSK      0x00800000
+#define      FLD_FMT_CHANGE_MSK       0x00400000
+#define      FLD_VSYNC_TRAIL_MSK      0x00200000
+#define      FLD_HLOCK_CHANGE_MSK     0x00100000
+#define      FLD_VLOCK_CHANGE_MSK     0x00080000
+#define      FLD_CSC_LOCK_CHANGE_MSK  0x00040000
+#define      FLD_SRC_FIFO_UFLOW_MSK   0x00020000
+#define      FLD_SRC_FIFO_OFLOW_MSK   0x00010000
+#define      FLD_COMB_3D_FIFO_STAT    0x00008000
+#define      FLD_WSS_DAT_AVAIL_STAT   0x00004000
+#define      FLD_GS2_DAT_AVAIL_STAT   0x00002000
+#define      FLD_GS1_DAT_AVAIL_STAT   0x00001000
+#define      FLD_CC_DAT_AVAIL_STAT    0x00000800
+#define      FLD_VPRES_CHANGE_STAT    0x00000400
+#define      FLD_MV_CHANGE_STAT       0x00000200
+#define      FLD_END_VBI_EVEN_STAT    0x00000100
+#define      FLD_END_VBI_ODD_STAT     0x00000080
+#define      FLD_FMT_CHANGE_STAT      0x00000040
+#define      FLD_VSYNC_TRAIL_STAT     0x00000020
+#define      FLD_HLOCK_CHANGE_STAT    0x00000010
+#define      FLD_VLOCK_CHANGE_STAT    0x00000008
+#define      FLD_CSC_LOCK_CHANGE_STAT 0x00000004
+#define      FLD_SRC_FIFO_UFLOW_STAT  0x00000002
+#define      FLD_SRC_FIFO_OFLOW_STAT  0x00000001
+
+/*****************************************************************************/
+#define      LUMA_CTRL                0x414
+#define      BRIGHTNESS_CTRL_BYTE     0x414
+#define      CONTRAST_CTRL_BYTE       0x415
+#define      LUMA_CTRL_BYTE_3         0x416
+#define      FLD_LUMA_CORE_SEL        0x00c00000
+#define      FLD_RANGE                0x00300000
+/* Reserved [19] */
+#define      FLD_PEAK_EN              0x00040000
+#define      FLD_PEAK_SEL             0x00030000
+#define      FLD_CNTRST               0x0000ff00
+#define      FLD_BRITE                0x000000ff
+
+/*****************************************************************************/
+#define      HSCALE_CTRL              0x418
+#define      FLD_HFILT                0x03000000
+#define      FLD_HSCALE               0x00ffffff
+
+/*****************************************************************************/
+#define      VSCALE_CTRL              0x41c
+#define      FLD_LINE_AVG_DIS         0x01000000
+/* Reserved [23:20] */
+#define      FLD_VS_INTRLACE          0x00080000
+#define      FLD_VFILT                0x00070000
+/* Reserved [15:13] */
+#define      FLD_VSCALE               0x00001fff
+
+/*****************************************************************************/
+#define      CHROMA_CTRL              0x420
+#define      USAT_CTRL_BYTE           0x420
+#define      VSAT_CTRL_BYTE           0x421
+#define      HUE_CTRL_BYTE            0x422
+#define      FLD_C_LPF_EN             0x20000000
+#define      FLD_CHR_DELAY            0x1c000000
+#define      FLD_C_CORE_SEL           0x03000000
+#define      FLD_HUE                  0x00ff0000
+#define      FLD_VSAT                 0x0000ff00
+#define      FLD_USAT                 0x000000ff
+
+/*****************************************************************************/
+#define      VBI_LINE_CTRL1           0x424
+#define      FLD_VBI_MD_LINE4         0xff000000
+#define      FLD_VBI_MD_LINE3         0x00ff0000
+#define      FLD_VBI_MD_LINE2         0x0000ff00
+#define      FLD_VBI_MD_LINE1         0x000000ff
+
+/*****************************************************************************/
+#define      VBI_LINE_CTRL2           0x428
+#define      FLD_VBI_MD_LINE8         0xff000000
+#define      FLD_VBI_MD_LINE7         0x00ff0000
+#define      FLD_VBI_MD_LINE6         0x0000ff00
+#define      FLD_VBI_MD_LINE5         0x000000ff
+
+/*****************************************************************************/
+#define      VBI_LINE_CTRL3           0x42c
+#define      FLD_VBI_MD_LINE12        0xff000000
+#define      FLD_VBI_MD_LINE11        0x00ff0000
+#define      FLD_VBI_MD_LINE10        0x0000ff00
+#define      FLD_VBI_MD_LINE9         0x000000ff
+
+/*****************************************************************************/
+#define      VBI_LINE_CTRL4           0x430
+#define      FLD_VBI_MD_LINE16        0xff000000
+#define      FLD_VBI_MD_LINE15        0x00ff0000
+#define      FLD_VBI_MD_LINE14        0x0000ff00
+#define      FLD_VBI_MD_LINE13        0x000000ff
+
+/*****************************************************************************/
+#define      VBI_LINE_CTRL5           0x434
+#define      FLD_VBI_MD_LINE17        0x000000ff
+
+/*****************************************************************************/
+#define      VBI_FC_CFG               0x438
+#define      FLD_FC_ALT2              0xff000000
+#define      FLD_FC_ALT1              0x00ff0000
+#define      FLD_FC_ALT2_TYPE         0x0000f000
+#define      FLD_FC_ALT1_TYPE         0x00000f00
+/* Reserved [7:1] */
+#define      FLD_FC_SEARCH_MODE       0x00000001
+
+/*****************************************************************************/
+#define      VBI_MISC_CFG1            0x43c
+#define      FLD_TTX_PKTADRU          0xfff00000
+#define      FLD_TTX_PKTADRL          0x000fff00
+/* Reserved [7:6] */
+#define      FLD_MOJI_PACK_DIS        0x00000020
+#define      FLD_VPS_DEC_DIS          0x00000010
+#define      FLD_CRI_MARG_SCALE       0x0000000c
+#define      FLD_EDGE_RESYNC_EN       0x00000002
+#define      FLD_ADAPT_SLICE_DIS      0x00000001
+
+/*****************************************************************************/
+#define      VBI_MISC_CFG2            0x440
+#define      FLD_HAMMING_TYPE         0x0f000000
+/* Reserved [23:20] */
+#define      FLD_WSS_FIFO_RST         0x00080000
+#define      FLD_GS2_FIFO_RST         0x00040000
+#define      FLD_GS1_FIFO_RST         0x00020000
+#define      FLD_CC_FIFO_RST          0x00010000
+/* Reserved [15:12] */
+#define      FLD_VBI3_SDID            0x00000f00
+#define      FLD_VBI2_SDID            0x000000f0
+#define      FLD_VBI1_SDID            0x0000000f
+
+/*****************************************************************************/
+#define      VBI_PAY1                 0x444
+#define      FLD_GS1_FIFO_DAT         0xFF000000
+#define      FLD_GS1_STAT             0x00FF0000
+#define      FLD_CC_FIFO_DAT          0x0000FF00
+#define      FLD_CC_STAT              0x000000FF
+
+/*****************************************************************************/
+#define      VBI_PAY2                 0x448
+#define      FLD_WSS_FIFO_DAT         0xff000000
+#define      FLD_WSS_STAT             0x00ff0000
+#define      FLD_GS2_FIFO_DAT         0x0000ff00
+#define      FLD_GS2_STAT             0x000000ff
+
+/*****************************************************************************/
+#define      VBI_CUST1_CFG1           0x44c
+/* Reserved [31] */
+#define      FLD_VBI1_CRIWIN          0x7f000000
+#define      FLD_VBI1_SLICE_DIST      0x00f00000
+#define      FLD_VBI1_BITINC          0x000fff00
+#define      FLD_VBI1_HDELAY          0x000000ff
+
+/*****************************************************************************/
+#define      VBI_CUST1_CFG2           0x450
+#define      FLD_VBI1_FC_LENGTH       0x1f000000
+#define      FLD_VBI1_FRAME_CODE      0x00ffffff
+
+/*****************************************************************************/
+#define      VBI_CUST1_CFG3           0x454
+#define      FLD_VBI1_HAM_EN          0x80000000
+#define      FLD_VBI1_FIFO_MODE       0x70000000
+#define      FLD_VBI1_FORMAT_TYPE     0x0f000000
+#define      FLD_VBI1_PAYLD_LENGTH    0x00ff0000
+#define      FLD_VBI1_CRI_LENGTH      0x0000f000
+#define      FLD_VBI1_CRI_MARGIN      0x00000f00
+#define      FLD_VBI1_CRI_TIME        0x000000ff
+
+/*****************************************************************************/
+#define      VBI_CUST2_CFG1           0x458
+/* Reserved [31] */
+#define      FLD_VBI2_CRIWIN          0x7f000000
+#define      FLD_VBI2_SLICE_DIST      0x00f00000
+#define      FLD_VBI2_BITINC          0x000fff00
+#define      FLD_VBI2_HDELAY          0x000000ff
+
+/*****************************************************************************/
+#define      VBI_CUST2_CFG2           0x45c
+#define      FLD_VBI2_FC_LENGTH       0x1f000000
+#define      FLD_VBI2_FRAME_CODE      0x00ffffff
+
+/*****************************************************************************/
+#define      VBI_CUST2_CFG3           0x460
+#define      FLD_VBI2_HAM_EN          0x80000000
+#define      FLD_VBI2_FIFO_MODE       0x70000000
+#define      FLD_VBI2_FORMAT_TYPE     0x0f000000
+#define      FLD_VBI2_PAYLD_LENGTH    0x00ff0000
+#define      FLD_VBI2_CRI_LENGTH      0x0000f000
+#define      FLD_VBI2_CRI_MARGIN      0x00000f00
+#define      FLD_VBI2_CRI_TIME        0x000000ff
+
+/*****************************************************************************/
+#define      VBI_CUST3_CFG1           0x464
+/* Reserved [31] */
+#define      FLD_VBI3_CRIWIN          0x7f000000
+#define      FLD_VBI3_SLICE_DIST      0x00f00000
+#define      FLD_VBI3_BITINC          0x000fff00
+#define      FLD_VBI3_HDELAY          0x000000ff
+
+/*****************************************************************************/
+#define      VBI_CUST3_CFG2           0x468
+#define      FLD_VBI3_FC_LENGTH       0x1f000000
+#define      FLD_VBI3_FRAME_CODE      0x00ffffff
+
+/*****************************************************************************/
+#define      VBI_CUST3_CFG3           0x46c
+#define      FLD_VBI3_HAM_EN          0x80000000
+#define      FLD_VBI3_FIFO_MODE       0x70000000
+#define      FLD_VBI3_FORMAT_TYPE     0x0f000000
+#define      FLD_VBI3_PAYLD_LENGTH    0x00ff0000
+#define      FLD_VBI3_CRI_LENGTH      0x0000f000
+#define      FLD_VBI3_CRI_MARGIN      0x00000f00
+#define      FLD_VBI3_CRI_TIME        0x000000ff
+
+/*****************************************************************************/
+#define      HORIZ_TIM_CTRL           0x470
+#define      FLD_BGDEL_CNT            0xff000000
+/* Reserved [23:22] */
+#define      FLD_HACTIVE_CNT          0x003ff000
+/* Reserved [11:10] */
+#define      FLD_HBLANK_CNT           0x000003ff
+
+/*****************************************************************************/
+#define      VERT_TIM_CTRL            0x474
+#define      FLD_V656BLANK_CNT        0xff000000
+/* Reserved [23:22] */
+#define      FLD_VACTIVE_CNT          0x003ff000
+/* Reserved [11:10] */
+#define      FLD_VBLANK_CNT           0x000003ff
+
+/*****************************************************************************/
+#define      SRC_COMB_CFG             0x478
+#define      FLD_CCOMB_2LN_CHECK      0x80000000
+#define      FLD_CCOMB_3LN_EN         0x40000000
+#define      FLD_CCOMB_2LN_EN         0x20000000
+#define      FLD_CCOMB_3D_EN          0x10000000
+/* Reserved [27] */
+#define      FLD_LCOMB_3LN_EN         0x04000000
+#define      FLD_LCOMB_2LN_EN         0x02000000
+#define      FLD_LCOMB_3D_EN          0x01000000
+#define      FLD_LUMA_LPF_SEL         0x00c00000
+#define      FLD_UV_LPF_SEL           0x00300000
+#define      FLD_BLEND_SLOPE          0x000f0000
+#define      FLD_CCOMB_REDUCE_EN      0x00008000
+/* Reserved [14:10] */
+#define      FLD_SRC_DECIM_RATIO      0x000003ff
+
+/*****************************************************************************/
+#define      CHROMA_VBIOFF_CFG        0x47c
+#define      FLD_VBI_VOFFSET          0x1f000000
+/* Reserved [23:20] */
+#define      FLD_SC_STEP              0x000fffff
+
+/*****************************************************************************/
+#define      FIELD_COUNT              0x480
+#define      FLD_FIELD_COUNT_FLD      0x000003ff
+
+/*****************************************************************************/
+#define      MISC_TIM_CTRL            0x484
+#define      FLD_DEBOUNCE_COUNT       0xc0000000
+#define      FLD_VT_LINE_CNT_HYST     0x30000000
+/* Reserved [27] */
+#define      FLD_AFD_STAT             0x07ff0000
+#define      FLD_VPRES_VERT_EN        0x00008000
+/* Reserved [14:12] */
+#define      FLD_HR32                 0x00000800
+#define      FLD_TDALGN               0x00000400
+#define      FLD_TDFIELD              0x00000200
+/* Reserved [8:6] */
+#define      FLD_TEMPDEC              0x0000003f
+
+/*****************************************************************************/
+#define      DFE_CTRL1                0x488
+#define      FLD_CLAMP_AUTO_EN        0x80000000
+#define      FLD_AGC_AUTO_EN          0x40000000
+#define      FLD_VGA_CRUSH_EN         0x20000000
+#define      FLD_VGA_AUTO_EN          0x10000000
+#define      FLD_VBI_GATE_EN          0x08000000
+#define      FLD_CLAMP_LEVEL          0x07000000
+/* Reserved [23:22] */
+#define      FLD_CLAMP_SKIP_CNT       0x00300000
+#define      FLD_AGC_GAIN             0x000fff00
+/* Reserved [7:6] */
+#define      FLD_VGA_GAIN             0x0000003f
+
+/*****************************************************************************/
+#define      DFE_CTRL2                0x48c
+#define      FLD_VGA_ACQUIRE_RANGE    0x00ff0000
+#define      FLD_VGA_TRACK_RANGE      0x0000ff00
+#define      FLD_VGA_SYNC             0x000000ff
+
+/*****************************************************************************/
+#define      DFE_CTRL3                0x490
+#define      FLD_BP_PERCENT           0xff000000
+#define      FLD_DFT_THRESHOLD        0x00ff0000
+/* Reserved [15:12] */
+#define      FLD_SYNC_WIDTH_SEL       0x00000600
+#define      FLD_BP_LOOP_GAIN         0x00000300
+#define      FLD_SYNC_LOOP_GAIN       0x000000c0
+/* Reserved [5:4] */
+#define      FLD_AGC_LOOP_GAIN        0x0000000c
+#define      FLD_DCC_LOOP_GAIN        0x00000003
+
+/*****************************************************************************/
+#define      PLL_CTRL                 0x494
+#define      FLD_PLL_KD               0xff000000
+#define      FLD_PLL_KI               0x00ff0000
+#define      FLD_PLL_MAX_OFFSET       0x0000ffff
+
+/*****************************************************************************/
+#define      HTL_CTRL                 0x498
+/* Reserved [31:24] */
+#define      FLD_AUTO_LOCK_SPD        0x00080000
+#define      FLD_MAN_FAST_LOCK        0x00040000
+#define      FLD_HTL_15K_EN           0x00020000
+#define      FLD_HTL_500K_EN          0x00010000
+#define      FLD_HTL_KD               0x0000ff00
+#define      FLD_HTL_KI               0x000000ff
+
+/*****************************************************************************/
+#define      COMB_CTRL                0x49c
+#define      FLD_COMB_PHASE_LIMIT     0xff000000
+#define      FLD_CCOMB_ERR_LIMIT      0x00ff0000
+#define      FLD_LUMA_THRESHOLD       0x0000ff00
+#define      FLD_LCOMB_ERR_LIMIT      0x000000ff
+
+/*****************************************************************************/
+#define      CRUSH_CTRL               0x4a0
+#define      FLD_WTW_EN               0x00400000
+#define      FLD_CRUSH_FREQ           0x00200000
+#define      FLD_MAJ_SEL_EN           0x00100000
+#define      FLD_MAJ_SEL              0x000c0000
+/* Reserved [17:15] */
+#define      FLD_SYNC_TIP_REDUCE      0x00007e00
+/* Reserved [8:6] */
+#define      FLD_SYNC_TIP_INC         0x0000003f
+
+/*****************************************************************************/
+#define      SOFT_RST_CTRL            0x4a4
+#define      FLD_VD_SOFT_RST          0x00008000
+/* Reserved [14:12] */
+#define      FLD_REG_RST_MSK          0x00000800
+#define      FLD_VOF_RST_MSK          0x00000400
+#define      FLD_MVDET_RST_MSK        0x00000200
+#define      FLD_VBI_RST_MSK          0x00000100
+#define      FLD_SCALE_RST_MSK        0x00000080
+#define      FLD_CHROMA_RST_MSK       0x00000040
+#define      FLD_LUMA_RST_MSK         0x00000020
+#define      FLD_VTG_RST_MSK          0x00000010
+#define      FLD_YCSEP_RST_MSK        0x00000008
+#define      FLD_SRC_RST_MSK          0x00000004
+#define      FLD_DFE_RST_MSK          0x00000002
+/* Reserved [0] */
+
+/*****************************************************************************/
+#define      MV_DT_CTRL1              0x4a8
+/* Reserved [31:29] */
+#define      FLD_PSP_STOP_LINE        0x1f000000
+/* Reserved [23:21] */
+#define      FLD_PSP_STRT_LINE        0x001f0000
+/* Reserved [15] */
+#define      FLD_PSP_LLIMW            0x00007f00
+/* Reserved [7] */
+#define      FLD_PSP_ULIMW            0x0000007f
+
+/*****************************************************************************/
+#define      MV_DT_CTRL2              0x4aC
+#define      FLD_CS_STOPWIN           0xff000000
+#define      FLD_CS_STRTWIN           0x00ff0000
+#define      FLD_CS_WIDTH             0x0000ff00
+#define      FLD_PSP_SPEC_VAL         0x000000ff
+
+/*****************************************************************************/
+#define      MV_DT_CTRL3              0x4B0
+#define      FLD_AUTO_RATE_DIS        0x80000000
+#define      FLD_HLOCK_DIS            0x40000000
+#define      FLD_SEL_FIELD_CNT        0x20000000
+#define      FLD_CS_TYPE2_SEL         0x10000000
+#define      FLD_CS_LINE_THRSH_SEL    0x08000000
+#define      FLD_CS_ATHRESH_SEL       0x04000000
+#define      FLD_PSP_SPEC_SEL         0x02000000
+#define      FLD_PSP_LINES_SEL        0x01000000
+#define      FLD_FIELD_CNT            0x00f00000
+#define      FLD_CS_TYPE2_CNT         0x000fc000
+#define      FLD_CS_LINE_CNT          0x00003f00
+#define      FLD_CS_ATHRESH_LEV       0x000000ff
+
+/*****************************************************************************/
+#define      CHIP_VERSION             0x4b4
+/* Cx231xx redefine  */
+#define      VERSION                  0x4b4
+#define      FLD_REV_ID               0x000000ff
+
+/*****************************************************************************/
+#define      MISC_DIAG_CTRL           0x4b8
+/* Reserved [31:24] */
+#define      FLD_SC_CONVERGE_THRESH   0x00ff0000
+#define      FLD_CCOMB_ERR_LIMIT_3D   0x0000ff00
+#define      FLD_LCOMB_ERR_LIMIT_3D   0x000000ff
+
+/*****************************************************************************/
+#define      VBI_PASS_CTRL            0x4bc
+#define      FLD_VBI_PASS_MD          0x00200000
+#define      FLD_VBI_SETUP_DIS        0x00100000
+#define      FLD_PASS_LINE_CTRL       0x000fffff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define      VCR_DET_CTRL             0x4c0
+#define      FLD_EN_FIELD_PHASE_DET   0x80000000
+#define      FLD_EN_HEAD_SW_DET       0x40000000
+#define      FLD_FIELD_PHASE_LENGTH   0x01ff0000
+/* Reserved [29:25] */
+#define      FLD_FIELD_PHASE_DELAY    0x0000ff00
+#define      FLD_FIELD_PHASE_LIMIT    0x000000f0
+#define      FLD_HEAD_SW_DET_LIMIT    0x0000000f
+
+/*****************************************************************************/
+#define      DL_CTL                   0x800
+#define      DL_CTL_ADDRESS_LOW       0x800    /* Byte 1 in DL_CTL */
+#define      DL_CTL_ADDRESS_HIGH      0x801    /* Byte 2 in DL_CTL */
+#define      DL_CTL_DATA              0x802    /* Byte 3 in DL_CTL */
+#define      DL_CTL_CONTROL           0x803    /* Byte 4 in DL_CTL */
+/* Reserved [31:5] */
+#define      FLD_START_8051           0x10000000
+#define      FLD_DL_ENABLE            0x08000000
+#define      FLD_DL_AUTO_INC          0x04000000
+#define      FLD_DL_MAP               0x03000000
+
+/*****************************************************************************/
+#define      STD_DET_STATUS           0x804
+#define      FLD_SPARE_STATUS1        0xff000000
+#define      FLD_SPARE_STATUS0        0x00ff0000
+#define      FLD_MOD_DET_STATUS1      0x0000ff00
+#define      FLD_MOD_DET_STATUS0      0x000000ff
+
+/*****************************************************************************/
+#define      AUD_BUILD_NUM            0x806
+#define      AUD_VER_NUM              0x807
+#define      STD_DET_CTL              0x808
+#define      STD_DET_CTL_AUD_CTL      0x808    /* Byte 1 in STD_DET_CTL */
+#define      STD_DET_CTL_PREF_MODE    0x809    /* Byte 2 in STD_DET_CTL */
+#define      FLD_SPARE_CTL0           0xff000000
+#define      FLD_DIS_DBX              0x00800000
+#define      FLD_DIS_BTSC             0x00400000
+#define      FLD_DIS_NICAM_A2         0x00200000
+#define      FLD_VIDEO_PRESENT        0x00100000
+#define      FLD_DW8051_VIDEO_FORMAT  0x000f0000
+#define      FLD_PREF_DEC_MODE        0x0000ff00
+#define      FLD_AUD_CONFIG           0x000000ff
+
+/*****************************************************************************/
+#define      DW8051_INT               0x80c
+#define      FLD_VIDEO_PRESENT_CHANGE 0x80000000
+#define      FLD_VIDEO_CHANGE         0x40000000
+#define      FLD_RDS_READY            0x20000000
+#define      FLD_AC97_INT             0x10000000
+#define      FLD_NICAM_BIT_ERROR_TOO_HIGH         0x08000000
+#define      FLD_NICAM_LOCK           0x04000000
+#define      FLD_NICAM_UNLOCK         0x02000000
+#define      FLD_DFT4_TH_CMP          0x01000000
+/* Reserved [23:22] */
+#define      FLD_LOCK_IND_INT         0x00200000
+#define      FLD_DFT3_TH_CMP          0x00100000
+#define      FLD_DFT2_TH_CMP          0x00080000
+#define      FLD_DFT1_TH_CMP          0x00040000
+#define      FLD_FM2_DFT_TH_CMP       0x00020000
+#define      FLD_FM1_DFT_TH_CMP       0x00010000
+#define      FLD_VIDEO_PRESENT_EN     0x00008000
+#define      FLD_VIDEO_CHANGE_EN      0x00004000
+#define      FLD_RDS_READY_EN         0x00002000
+#define      FLD_AC97_INT_EN          0x00001000
+#define      FLD_NICAM_BIT_ERROR_TOO_HIGH_EN      0x00000800
+#define      FLD_NICAM_LOCK_EN        0x00000400
+#define      FLD_NICAM_UNLOCK_EN      0x00000200
+#define      FLD_DFT4_TH_CMP_EN       0x00000100
+/* Reserved [7] */
+#define      FLD_DW8051_INT6_CTL1     0x00000040
+#define      FLD_DW8051_INT5_CTL1     0x00000020
+#define      FLD_DW8051_INT4_CTL1     0x00000010
+#define      FLD_DW8051_INT3_CTL1     0x00000008
+#define      FLD_DW8051_INT2_CTL1     0x00000004
+#define      FLD_DW8051_INT1_CTL1     0x00000002
+#define      FLD_DW8051_INT0_CTL1     0x00000001
+
+/*****************************************************************************/
+#define      GENERAL_CTL              0x810
+#define      FLD_RDS_INT              0x80000000
+#define      FLD_NBER_INT             0x40000000
+#define      FLD_NLL_INT              0x20000000
+#define      FLD_IFL_INT              0x10000000
+#define      FLD_FDL_INT              0x08000000
+#define      FLD_AFC_INT              0x04000000
+#define      FLD_AMC_INT              0x02000000
+#define      FLD_AC97_INT_CTL         0x01000000
+#define      FLD_RDS_INT_DIS          0x00800000
+#define      FLD_NBER_INT_DIS         0x00400000
+#define      FLD_NLL_INT_DIS          0x00200000
+#define      FLD_IFL_INT_DIS          0x00100000
+#define      FLD_FDL_INT_DIS          0x00080000
+#define      FLD_FC_INT_DIS           0x00040000
+#define      FLD_AMC_INT_DIS          0x00020000
+#define      FLD_AC97_INT_DIS         0x00010000
+#define      FLD_REV_NUM              0x0000ff00
+/* Reserved [7:5] */
+#define      FLD_DBX_SOFT_RESET_REG   0x00000010
+#define      FLD_AD_SOFT_RESET_REG    0x00000008
+#define      FLD_SRC_SOFT_RESET_REG   0x00000004
+#define      FLD_CDMOD_SOFT_RESET     0x00000002
+#define      FLD_8051_SOFT_RESET      0x00000001
+
+/*****************************************************************************/
+#define      AAGC_CTL                 0x814
+#define      FLD_AFE_12DB_EN          0x80000000
+#define      FLD_AAGC_DEFAULT_EN      0x40000000
+#define      FLD_AAGC_DEFAULT         0x3f000000
+/* Reserved [23] */
+#define      FLD_AAGC_GAIN            0x00600000
+#define      FLD_AAGC_TH              0x001f0000
+/* Reserved [15:14] */
+#define      FLD_AAGC_HYST2           0x00003f00
+/* Reserved [7:6] */
+#define      FLD_AAGC_HYST1           0x0000003f
+
+/*****************************************************************************/
+#define      IF_SRC_CTL               0x818
+#define      FLD_DBX_BYPASS           0x80000000
+/* Reserved [30:25] */
+#define      FLD_IF_SRC_MODE          0x01000000
+/* Reserved [23:18] */
+#define      FLD_IF_SRC_PHASE_INC     0x0001ffff
+
+/*****************************************************************************/
+#define      ANALOG_DEMOD_CTL         0x81c
+#define      FLD_ROT1_PHACC_PROG      0xffff0000
+/* Reserved [15] */
+#define      FLD_FM1_DELAY_FIX        0x00007000
+#define      FLD_PDF4_SHIFT           0x00000c00
+#define      FLD_PDF3_SHIFT           0x00000300
+#define      FLD_PDF2_SHIFT           0x000000c0
+#define      FLD_PDF1_SHIFT           0x00000030
+#define      FLD_FMBYPASS_MODE2       0x00000008
+#define      FLD_FMBYPASS_MODE1       0x00000004
+#define      FLD_NICAM_MODE           0x00000002
+#define      FLD_BTSC_FMRADIO_MODE    0x00000001
+
+/*****************************************************************************/
+#define      ROT_FREQ_CTL             0x820
+#define      FLD_ROT3_PHACC_PROG      0xffff0000
+#define      FLD_ROT2_PHACC_PROG      0x0000ffff
+
+/*****************************************************************************/
+#define      FM_CTL                   0x824
+#define      FLD_FM2_DC_FB_SHIFT      0xf0000000
+#define      FLD_FM2_DC_INT_SHIFT     0x0f000000
+#define      FLD_FM2_AFC_RESET        0x00800000
+#define      FLD_FM2_DC_PASS_IN       0x00400000
+#define      FLD_FM2_DAGC_SHIFT       0x00380000
+#define      FLD_FM2_CORDIC_SHIFT     0x00070000
+#define      FLD_FM1_DC_FB_SHIFT      0x0000f000
+#define      FLD_FM1_DC_INT_SHIFT     0x00000f00
+#define      FLD_FM1_AFC_RESET        0x00000080
+#define      FLD_FM1_DC_PASS_IN       0x00000040
+#define      FLD_FM1_DAGC_SHIFT       0x00000038
+#define      FLD_FM1_CORDIC_SHIFT     0x00000007
+
+/*****************************************************************************/
+#define      LPF_PDF_CTL              0x828
+/* Reserved [31:30] */
+#define      FLD_LPF32_SHIFT1         0x30000000
+#define      FLD_LPF32_SHIFT2         0x0c000000
+#define      FLD_LPF160_SHIFTA        0x03000000
+#define      FLD_LPF160_SHIFTB        0x00c00000
+#define      FLD_LPF160_SHIFTC        0x00300000
+#define      FLD_LPF32_COEF_SEL2      0x000c0000
+#define      FLD_LPF32_COEF_SEL1      0x00030000
+#define      FLD_LPF160_COEF_SELC     0x0000c000
+#define      FLD_LPF160_COEF_SELB     0x00003000
+#define      FLD_LPF160_COEF_SELA     0x00000c00
+#define      FLD_LPF160_IN_EN_REG     0x00000300
+#define      FLD_PDF4_PDF_SEL         0x000000c0
+#define      FLD_PDF3_PDF_SEL         0x00000030
+#define      FLD_PDF2_PDF_SEL         0x0000000c
+#define      FLD_PDF1_PDF_SEL         0x00000003
+
+/*****************************************************************************/
+#define      DFT1_CTL1                0x82c
+#define      FLD_DFT1_DWELL           0xffff0000
+#define      FLD_DFT1_FREQ            0x0000ffff
+
+/*****************************************************************************/
+#define      DFT1_CTL2                0x830
+#define      FLD_DFT1_THRESHOLD       0xffffff00
+#define      FLD_DFT1_CMP_CTL         0x00000080
+#define      FLD_DFT1_AVG             0x00000070
+/* Reserved [3:1] */
+#define      FLD_DFT1_START           0x00000001
+
+/*****************************************************************************/
+#define      DFT1_STATUS              0x834
+#define      FLD_DFT1_DONE            0x80000000
+#define      FLD_DFT1_TH_CMP_STAT     0x40000000
+#define      FLD_DFT1_RESULT          0x3fffffff
+
+/*****************************************************************************/
+#define      DFT2_CTL1                0x838
+#define      FLD_DFT2_DWELL           0xffff0000
+#define      FLD_DFT2_FREQ            0x0000ffff
+
+/*****************************************************************************/
+#define      DFT2_CTL2                0x83C
+#define      FLD_DFT2_THRESHOLD       0xffffff00
+#define      FLD_DFT2_CMP_CTL         0x00000080
+#define      FLD_DFT2_AVG             0x00000070
+/* Reserved [3:1] */
+#define      FLD_DFT2_START           0x00000001
+
+/*****************************************************************************/
+#define      DFT2_STATUS              0x840
+#define      FLD_DFT2_DONE            0x80000000
+#define      FLD_DFT2_TH_CMP_STAT     0x40000000
+#define      FLD_DFT2_RESULT          0x3fffffff
+
+/*****************************************************************************/
+#define      DFT3_CTL1                0x844
+#define      FLD_DFT3_DWELL           0xffff0000
+#define      FLD_DFT3_FREQ            0x0000ffff
+
+/*****************************************************************************/
+#define      DFT3_CTL2                0x848
+#define      FLD_DFT3_THRESHOLD       0xffffff00
+#define      FLD_DFT3_CMP_CTL         0x00000080
+#define      FLD_DFT3_AVG             0x00000070
+/* Reserved [3:1] */
+#define      FLD_DFT3_START           0x00000001
+
+/*****************************************************************************/
+#define      DFT3_STATUS              0x84c
+#define      FLD_DFT3_DONE            0x80000000
+#define      FLD_DFT3_TH_CMP_STAT     0x40000000
+#define      FLD_DFT3_RESULT          0x3fffffff
+
+/*****************************************************************************/
+#define      DFT4_CTL1                0x850
+#define      FLD_DFT4_DWELL           0xffff0000
+#define      FLD_DFT4_FREQ            0x0000ffff
+
+/*****************************************************************************/
+#define      DFT4_CTL2                0x854
+#define      FLD_DFT4_THRESHOLD       0xffffff00
+#define      FLD_DFT4_CMP_CTL         0x00000080
+#define      FLD_DFT4_AVG             0x00000070
+/* Reserved [3:1] */
+#define      FLD_DFT4_START           0x00000001
+
+/*****************************************************************************/
+#define      DFT4_STATUS              0x858
+#define      FLD_DFT4_DONE            0x80000000
+#define      FLD_DFT4_TH_CMP_STAT     0x40000000
+#define      FLD_DFT4_RESULT          0x3fffffff
+
+/*****************************************************************************/
+#define      AM_MTS_DET               0x85c
+#define      FLD_AM_MTS_MODE          0x80000000
+/* Reserved [30:26] */
+#define      FLD_AM_SUB               0x02000000
+#define      FLD_AM_GAIN_EN           0x01000000
+/* Reserved [23:16] */
+#define      FLD_AMMTS_GAIN_SCALE     0x0000e000
+#define      FLD_MTS_PDF_SHIFT        0x00001800
+#define      FLD_AM_REG_GAIN          0x00000700
+#define      FLD_AGC_REF              0x000000ff
+
+/*****************************************************************************/
+#define      ANALOG_MUX_CTL           0x860
+/* Reserved [31:29] */
+#define      FLD_MUX21_SEL            0x10000000
+#define      FLD_MUX20_SEL            0x08000000
+#define      FLD_MUX19_SEL            0x04000000
+#define      FLD_MUX18_SEL            0x02000000
+#define      FLD_MUX17_SEL            0x01000000
+#define      FLD_MUX16_SEL            0x00800000
+#define      FLD_MUX15_SEL            0x00400000
+#define      FLD_MUX14_SEL            0x00300000
+#define      FLD_MUX13_SEL            0x000C0000
+#define      FLD_MUX12_SEL            0x00020000
+#define      FLD_MUX11_SEL            0x00018000
+#define      FLD_MUX10_SEL            0x00004000
+#define      FLD_MUX9_SEL             0x00002000
+#define      FLD_MUX8_SEL             0x00001000
+#define      FLD_MUX7_SEL             0x00000800
+#define      FLD_MUX6_SEL             0x00000600
+#define      FLD_MUX5_SEL             0x00000100
+#define      FLD_MUX4_SEL             0x000000c0
+#define      FLD_MUX3_SEL             0x00000030
+#define      FLD_MUX2_SEL             0x0000000c
+#define      FLD_MUX1_SEL             0x00000003
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define      DPLL_CTRL1               0x864
+#define      DIG_PLL_CTL1             0x864
+
+#define      FLD_PLL_STATUS           0x07000000
+#define      FLD_BANDWIDTH_SELECT     0x00030000
+#define      FLD_PLL_SHIFT_REG        0x00007000
+#define      FLD_PHASE_SHIFT          0x000007ff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define      DPLL_CTRL2               0x868
+#define      DIG_PLL_CTL2             0x868
+#define      FLD_PLL_UNLOCK_THR       0xff000000
+#define      FLD_PLL_LOCK_THR         0x00ff0000
+/* Reserved [15:8] */
+#define      FLD_AM_PDF_SEL2          0x000000c0
+#define      FLD_AM_PDF_SEL1          0x00000030
+#define      FLD_DPLL_FSM_CTRL        0x0000000c
+/* Reserved [1] */
+#define      FLD_PLL_PILOT_DET        0x00000001
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define      DPLL_CTRL3               0x86c
+#define      DIG_PLL_CTL3             0x86c
+#define      FLD_DISABLE_LOOP         0x01000000
+#define      FLD_A1_DS1_SEL           0x000c0000
+#define      FLD_A1_DS2_SEL           0x00030000
+#define      FLD_A1_KI                0x0000ff00
+#define      FLD_A1_KD                0x000000ff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define      DPLL_CTRL4               0x870
+#define      DIG_PLL_CTL4             0x870
+#define      FLD_A2_DS1_SEL           0x000c0000
+#define      FLD_A2_DS2_SEL           0x00030000
+#define      FLD_A2_KI                0x0000ff00
+#define      FLD_A2_KD                0x000000ff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define      DPLL_CTRL5               0x874
+#define      DIG_PLL_CTL5             0x874
+#define      FLD_TRK_DS1_SEL          0x000c0000
+#define      FLD_TRK_DS2_SEL          0x00030000
+#define      FLD_TRK_KI               0x0000ff00
+#define      FLD_TRK_KD               0x000000ff
+
+/*****************************************************************************/
+#define      DEEMPH_GAIN_CTL          0x878
+#define      FLD_DEEMPH2_GAIN         0xFFFF0000
+#define      FLD_DEEMPH1_GAIN         0x0000FFFF
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define      DEEMPH_COEFF1            0x87c
+#define      DEEMPH_COEF1             0x87c
+#define      FLD_DEEMPH_B0            0xffff0000
+#define      FLD_DEEMPH_A0            0x0000ffff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define      DEEMPH_COEFF2            0x880
+#define      DEEMPH_COEF2             0x880
+#define      FLD_DEEMPH_B1            0xFFFF0000
+#define      FLD_DEEMPH_A1            0x0000FFFF
+
+/*****************************************************************************/
+#define      DBX1_CTL1                0x884
+#define      FLD_DBX1_WBE_GAIN        0xffff0000
+#define      FLD_DBX1_IN_GAIN         0x0000ffff
+
+/*****************************************************************************/
+#define      DBX1_CTL2                0x888
+#define      FLD_DBX1_SE_BYPASS       0xffff0000
+#define      FLD_DBX1_SE_GAIN         0x0000ffff
+
+/*****************************************************************************/
+#define      DBX1_RMS_SE              0x88C
+#define      FLD_DBX1_RMS_WBE         0xffff0000
+#define      FLD_DBX1_RMS_SE_FLD      0x0000ffff
+
+/*****************************************************************************/
+#define      DBX2_CTL1                0x890
+#define      FLD_DBX2_WBE_GAIN        0xffff0000
+#define      FLD_DBX2_IN_GAIN         0x0000ffff
+
+/*****************************************************************************/
+#define      DBX2_CTL2                0x894
+#define      FLD_DBX2_SE_BYPASS       0xffff0000
+#define      FLD_DBX2_SE_GAIN         0x0000ffff
+
+/*****************************************************************************/
+#define      DBX2_RMS_SE              0x898
+#define      FLD_DBX2_RMS_WBE         0xffff0000
+#define      FLD_DBX2_RMS_SE_FLD      0x0000ffff
+
+/*****************************************************************************/
+#define      AM_FM_DIFF               0x89c
+/* Reserved [31] */
+#define      FLD_FM_DIFF_OUT          0x7fff0000
+/* Reserved [15] */
+#define      FLD_AM_DIFF_OUT          0x00007fff
+
+/*****************************************************************************/
+#define      NICAM_FAW                0x8a0
+#define      FLD_FAWDETWINEND         0xFc000000
+#define      FLD_FAWDETWINSTR         0x03ff0000
+/* Reserved [15:12] */
+#define      FLD_FAWDETTHRSHLD3       0x00000f00
+#define      FLD_FAWDETTHRSHLD2       0x000000f0
+#define      FLD_FAWDETTHRSHLD1       0x0000000f
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define      DEEMPH_GAIN              0x8a4
+#define      NICAM_DEEMPHGAIN         0x8a4
+/* Reserved [31:18] */
+#define      FLD_DEEMPHGAIN           0x0003ffff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define      DEEMPH_NUMER1            0x8a8
+#define      NICAM_DEEMPHNUMER1       0x8a8
+/* Reserved [31:18] */
+#define      FLD_DEEMPHNUMER1         0x0003ffff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define      DEEMPH_NUMER2            0x8ac
+#define      NICAM_DEEMPHNUMER2       0x8ac
+/* Reserved [31:18] */
+#define      FLD_DEEMPHNUMER2         0x0003ffff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define      DEEMPH_DENOM1            0x8b0
+#define      NICAM_DEEMPHDENOM1       0x8b0
+/* Reserved [31:18] */
+#define      FLD_DEEMPHDENOM1         0x0003ffff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define      DEEMPH_DENOM2            0x8b4
+#define      NICAM_DEEMPHDENOM2       0x8b4
+/* Reserved [31:18] */
+#define      FLD_DEEMPHDENOM2         0x0003ffff
+
+/*****************************************************************************/
+#define      NICAM_ERRLOG_CTL1        0x8B8
+/* Reserved [31:28] */
+#define      FLD_ERRINTRPTTHSHLD1     0x0fff0000
+/* Reserved [15:12] */
+#define      FLD_ERRLOGPERIOD         0x00000fff
+
+/*****************************************************************************/
+#define      NICAM_ERRLOG_CTL2        0x8bc
+/* Reserved [31:28] */
+#define      FLD_ERRINTRPTTHSHLD3     0x0fff0000
+/* Reserved [15:12] */
+#define      FLD_ERRINTRPTTHSHLD2     0x00000fff
+
+/*****************************************************************************/
+#define      NICAM_ERRLOG_STS1        0x8c0
+/* Reserved [31:28] */
+#define      FLD_ERRLOG2              0x0fff0000
+/* Reserved [15:12] */
+#define      FLD_ERRLOG1              0x00000fff
+
+/*****************************************************************************/
+#define      NICAM_ERRLOG_STS2        0x8c4
+/* Reserved [31:12] */
+#define      FLD_ERRLOG3              0x00000fff
+
+/*****************************************************************************/
+#define      NICAM_STATUS             0x8c8
+/* Reserved [31:20] */
+#define      FLD_NICAM_CIB            0x000c0000
+#define      FLD_NICAM_LOCK_STAT      0x00020000
+#define      FLD_NICAM_MUTE           0x00010000
+#define      FLD_NICAMADDIT_DATA      0x0000ffe0
+#define      FLD_NICAMCNTRL           0x0000001f
+
+/*****************************************************************************/
+#define      DEMATRIX_CTL             0x8cc
+#define      FLD_AC97_IN_SHIFT        0xf0000000
+#define      FLD_I2S_IN_SHIFT         0x0f000000
+#define      FLD_DEMATRIX_SEL_CTL     0x00ff0000
+/* Reserved [15:11] */
+#define      FLD_DMTRX_BYPASS         0x00000400
+#define      FLD_DEMATRIX_MODE        0x00000300
+/* Reserved [7:6] */
+#define      FLD_PH_DBX_SEL           0x00000020
+#define      FLD_PH_CH_SEL            0x00000010
+#define      FLD_PHASE_FIX            0x0000000f
+
+/*****************************************************************************/
+#define      PATH1_CTL1               0x8d0
+/* Reserved [31:29] */
+#define      FLD_PATH1_MUTE_CTL       0x1f000000
+/* Reserved [23:22] */
+#define      FLD_PATH1_AVC_CG         0x00300000
+#define      FLD_PATH1_AVC_RT         0x000f0000
+#define      FLD_PATH1_AVC_AT         0x0000f000
+#define      FLD_PATH1_AVC_STEREO     0x00000800
+#define      FLD_PATH1_AVC_CR         0x00000700
+#define      FLD_PATH1_AVC_RMS_CON    0x000000f0
+#define      FLD_PATH1_SEL_CTL        0x0000000f
+
+/*****************************************************************************/
+#define      PATH1_VOL_CTL            0x8d4
+#define      FLD_PATH1_AVC_THRESHOLD  0x7fff0000
+#define      FLD_PATH1_BAL_LEFT       0x00008000
+#define      FLD_PATH1_BAL_LEVEL      0x00007f00
+#define      FLD_PATH1_VOLUME         0x000000ff
+
+/*****************************************************************************/
+#define      PATH1_EQ_CTL             0x8d8
+/* Reserved [31:30] */
+#define      FLD_PATH1_EQ_TREBLE_VOL  0x3f000000
+/* Reserved [23:22] */
+#define      FLD_PATH1_EQ_MID_VOL     0x003f0000
+/* Reserved [15:14] */
+#define      FLD_PATH1_EQ_BASS_VOL    0x00003f00
+/* Reserved [7:1] */
+#define      FLD_PATH1_EQ_BAND_SEL    0x00000001
+
+/*****************************************************************************/
+#define      PATH1_SC_CTL             0x8dc
+#define      FLD_PATH1_SC_THRESHOLD   0x7fff0000
+#define      FLD_PATH1_SC_RT          0x0000f000
+#define      FLD_PATH1_SC_AT          0x00000f00
+#define      FLD_PATH1_SC_STEREO      0x00000080
+#define      FLD_PATH1_SC_CR          0x00000070
+#define      FLD_PATH1_SC_RMS_CON     0x0000000f
+
+/*****************************************************************************/
+#define      PATH2_CTL1               0x8e0
+/* Reserved [31:26] */
+#define      FLD_PATH2_MUTE_CTL       0x03000000
+/* Reserved [23:22] */
+#define      FLD_PATH2_AVC_CG         0x00300000
+#define      FLD_PATH2_AVC_RT         0x000f0000
+#define      FLD_PATH2_AVC_AT         0x0000f000
+#define      FLD_PATH2_AVC_STEREO     0x00000800
+#define      FLD_PATH2_AVC_CR         0x00000700
+#define      FLD_PATH2_AVC_RMS_CON    0x000000f0
+#define      FLD_PATH2_SEL_CTL        0x0000000f
+
+/*****************************************************************************/
+#define      PATH2_VOL_CTL            0x8e4
+#define      FLD_PATH2_AVC_THRESHOLD  0xffff0000
+#define      FLD_PATH2_BAL_LEFT       0x00008000
+#define      FLD_PATH2_BAL_LEVEL      0x00007f00
+#define      FLD_PATH2_VOLUME         0x000000ff
+
+/*****************************************************************************/
+#define      PATH2_EQ_CTL             0x8e8
+/* Reserved [31:30] */
+#define      FLD_PATH2_EQ_TREBLE_VOL  0x3f000000
+/* Reserved [23:22] */
+#define      FLD_PATH2_EQ_MID_VOL     0x003f0000
+/* Reserved [15:14] */
+#define      FLD_PATH2_EQ_BASS_VOL    0x00003f00
+/* Reserved [7:1] */
+#define      FLD_PATH2_EQ_BAND_SEL    0x00000001
+
+/*****************************************************************************/
+#define      PATH2_SC_CTL             0x8eC
+#define      FLD_PATH2_SC_THRESHOLD   0xffff0000
+#define      FLD_PATH2_SC_RT          0x0000f000
+#define      FLD_PATH2_SC_AT          0x00000f00
+#define      FLD_PATH2_SC_STEREO      0x00000080
+#define      FLD_PATH2_SC_CR          0x00000070
+#define      FLD_PATH2_SC_RMS_CON     0x0000000f
+
+/*****************************************************************************/
+#define      SRC_CTL                  0x8f0
+#define      FLD_SRC_STATUS           0xffffff00
+#define      FLD_FIFO_LF_EN           0x000000fc
+#define      FLD_BYPASS_LI            0x00000002
+#define      FLD_BYPASS_PF            0x00000001
+
+/*****************************************************************************/
+#define      SRC_LF_COEF              0x8f4
+#define      FLD_LOOP_FILTER_COEF2    0xffff0000
+#define      FLD_LOOP_FILTER_COEF1    0x0000ffff
+
+/*****************************************************************************/
+#define      SRC1_CTL                 0x8f8
+/* Reserved [31:28] */
+#define      FLD_SRC1_FIFO_RD_TH      0x0f000000
+/* Reserved [23:18] */
+#define      FLD_SRC1_PHASE_INC       0x0003ffff
+
+/*****************************************************************************/
+#define      SRC2_CTL                 0x8fc
+/* Reserved [31:28] */
+#define      FLD_SRC2_FIFO_RD_TH      0x0f000000
+/* Reserved [23:18] */
+#define      FLD_SRC2_PHASE_INC       0x0003ffff
+
+/*****************************************************************************/
+#define      SRC3_CTL                 0x900
+/* Reserved [31:28] */
+#define      FLD_SRC3_FIFO_RD_TH      0x0f000000
+/* Reserved [23:18] */
+#define      FLD_SRC3_PHASE_INC       0x0003ffff
+
+/*****************************************************************************/
+#define      SRC4_CTL                 0x904
+/* Reserved [31:28] */
+#define      FLD_SRC4_FIFO_RD_TH      0x0f000000
+/* Reserved [23:18] */
+#define      FLD_SRC4_PHASE_INC       0x0003ffff
+
+/*****************************************************************************/
+#define      SRC5_CTL                 0x908
+/* Reserved [31:28] */
+#define      FLD_SRC5_FIFO_RD_TH      0x0f000000
+/* Reserved [23:18] */
+#define      FLD_SRC5_PHASE_INC       0x0003ffff
+
+/*****************************************************************************/
+#define      SRC6_CTL                 0x90c
+/* Reserved [31:28] */
+#define      FLD_SRC6_FIFO_RD_TH      0x0f000000
+/* Reserved [23:18] */
+#define      FLD_SRC6_PHASE_INC       0x0003ffff
+
+/*****************************************************************************/
+#define      BAND_OUT_SEL             0x910
+#define      FLD_SRC6_IN_SEL          0xc0000000
+#define      FLD_SRC6_CLK_SEL         0x30000000
+#define      FLD_SRC5_IN_SEL          0x0c000000
+#define      FLD_SRC5_CLK_SEL         0x03000000
+#define      FLD_SRC4_IN_SEL          0x00c00000
+#define      FLD_SRC4_CLK_SEL         0x00300000
+#define      FLD_SRC3_IN_SEL          0x000c0000
+#define      FLD_SRC3_CLK_SEL         0x00030000
+#define      FLD_BASEBAND_BYPASS_CTL  0x0000ff00
+#define      FLD_AC97_SRC_SEL         0x000000c0
+#define      FLD_I2S_SRC_SEL          0x00000030
+#define      FLD_PARALLEL2_SRC_SEL    0x0000000c
+#define      FLD_PARALLEL1_SRC_SEL    0x00000003
+
+/*****************************************************************************/
+#define      I2S_IN_CTL               0x914
+/* Reserved [31:11] */
+#define      FLD_I2S_UP2X_BW20K       0x00000400
+#define      FLD_I2S_UP2X_BYPASS      0x00000200
+#define      FLD_I2S_IN_MASTER_MODE   0x00000100
+#define      FLD_I2S_IN_SONY_MODE     0x00000080
+#define      FLD_I2S_IN_RIGHT_JUST    0x00000040
+#define      FLD_I2S_IN_WS_SEL        0x00000020
+#define      FLD_I2S_IN_BCN_DEL       0x0000001f
+
+/*****************************************************************************/
+#define      I2S_OUT_CTL              0x918
+/* Reserved [31:17] */
+#define      FLD_I2S_OUT_SOFT_RESET_EN  0x00010000
+/* Reserved [15:9] */
+#define      FLD_I2S_OUT_MASTER_MODE  0x00000100
+#define      FLD_I2S_OUT_SONY_MODE    0x00000080
+#define      FLD_I2S_OUT_RIGHT_JUST   0x00000040
+#define      FLD_I2S_OUT_WS_SEL       0x00000020
+#define      FLD_I2S_OUT_BCN_DEL      0x0000001f
+
+/*****************************************************************************/
+#define      AC97_CTL                 0x91c
+/* Reserved [31:26] */
+#define      FLD_AC97_UP2X_BW20K      0x02000000
+#define      FLD_AC97_UP2X_BYPASS     0x01000000
+/* Reserved [23:17] */
+#define      FLD_AC97_RST_ACL         0x00010000
+/* Reserved [15:9] */
+#define      FLD_AC97_WAKE_UP_SYNC    0x00000100
+/* Reserved [7:1] */
+#define      FLD_AC97_SHUTDOWN        0x00000001
+
+/* Cx231xx redefine */
+#define      QPSK_IAGC_CTL1  		0x94c
+#define      QPSK_IAGC_CTL2  		0x950
+#define      QPSK_FEPR_FREQ  		0x954
+#define      QPSK_BTL_CTL1  		0x958
+#define      QPSK_BTL_CTL2  		0x95c
+#define      QPSK_CTL_CTL1  		0x960
+#define      QPSK_CTL_CTL2  		0x964
+#define      QPSK_MF_FAGC_CTL 		0x968
+#define      QPSK_EQ_CTL  		0x96c
+#define      QPSK_LOCK_CTL  		0x970
+
+/*****************************************************************************/
+#define      FM1_DFT_CTL              0x9a8
+#define      FLD_FM1_DFT_THRESHOLD    0xffff0000
+/* Reserved [15:8] */
+#define      FLD_FM1_DFT_CMP_CTL      0x00000080
+#define      FLD_FM1_DFT_AVG          0x00000070
+/* Reserved [3:1] */
+#define      FLD_FM1_DFT_START        0x00000001
+
+/*****************************************************************************/
+#define      FM1_DFT_STATUS           0x9ac
+#define      FLD_FM1_DFT_DONE         0x80000000
+/* Reserved [30:19] */
+#define      FLD_FM_DFT_TH_CMP        0x00040000
+#define      FLD_FM1_DFT              0x0003ffff
+
+/*****************************************************************************/
+#define      FM2_DFT_CTL              0x9b0
+#define      FLD_FM2_DFT_THRESHOLD    0xffff0000
+/* Reserved [15:8] */
+#define      FLD_FM2_DFT_CMP_CTL      0x00000080
+#define      FLD_FM2_DFT_AVG          0x00000070
+/* Reserved [3:1] */
+#define      FLD_FM2_DFT_START        0x00000001
+
+/*****************************************************************************/
+#define      FM2_DFT_STATUS           0x9b4
+#define      FLD_FM2_DFT_DONE         0x80000000
+/* Reserved [30:19] */
+#define      FLD_FM2_DFT_TH_CMP_STAT  0x00040000
+#define      FLD_FM2_DFT              0x0003ffff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define      AAGC_STATUS_REG          0x9b8
+#define      AAGC_STATUS              0x9b8
+/* Reserved [31:27] */
+#define      FLD_FM2_DAGC_OUT         0x07000000
+/* Reserved [23:19] */
+#define      FLD_FM1_DAGC_OUT         0x00070000
+/* Reserved [15:6] */
+#define      FLD_AFE_VGA_OUT          0x0000003f
+
+/*****************************************************************************/
+#define      MTS_GAIN_STATUS          0x9bc
+/* Reserved [31:14] */
+#define      FLD_MTS_GAIN             0x00003fff
+
+#define      RDS_OUT                  0x9c0
+#define      FLD_RDS_Q                0xffff0000
+#define      FLD_RDS_I                0x0000ffff
+
+/*****************************************************************************/
+#define      AUTOCONFIG_REG           0x9c4
+/* Reserved [31:4] */
+#define      FLD_AUTOCONFIG_MODE      0x0000000f
+
+#define      FM_AFC                   0x9c8
+#define      FLD_FM2_AFC              0xffff0000
+#define      FLD_FM1_AFC              0x0000ffff
+
+/*****************************************************************************/
+/* Cx231xx redefine */
+#define      NEW_SPARE                0x9cc
+#define      NEW_SPARE_REG            0x9cc
+
+/*****************************************************************************/
+#define      DBX_ADJ                  0x9d0
+/* Reserved [31:28] */
+#define      FLD_DBX2_ADJ             0x0fff0000
+/* Reserved [15:12] */
+#define      FLD_DBX1_ADJ             0x00000fff
+
+#define      VID_FMT_AUTO              0
+#define      VID_FMT_NTSC_M            1
+#define      VID_FMT_NTSC_J            2
+#define      VID_FMT_NTSC_443          3
+#define      VID_FMT_PAL_BDGHI         4
+#define      VID_FMT_PAL_M             5
+#define      VID_FMT_PAL_N             6
+#define      VID_FMT_PAL_NC            7
+#define      VID_FMT_PAL_60            8
+#define      VID_FMT_SECAM             12
+#define      VID_FMT_SECAM_60          13
+
+#define      INPUT_MODE_CVBS_0         0       /* INPUT_MODE_VALUE(0) */
+#define      INPUT_MODE_YC_1           1       /* INPUT_MODE_VALUE(1) */
+#define      INPUT_MODE_YC2_2          2       /* INPUT_MODE_VALUE(2) */
+#define      INPUT_MODE_YUV_3          3       /* INPUT_MODE_VALUE(3) */
+
+#define      LUMA_LPF_LOW_BANDPASS     0       /* 0.6Mhz LPF BW */
+#define      LUMA_LPF_MEDIUM_BANDPASS  1       /* 1.0Mhz LPF BW */
+#define      LUMA_LPF_HIGH_BANDPASS    2       /* 1.5Mhz LPF BW */
+
+#define      UV_LPF_LOW_BANDPASS       0       /* 0.6Mhz LPF BW */
+#define      UV_LPF_MEDIUM_BANDPASS    1       /* 1.0Mhz LPF BW */
+#define      UV_LPF_HIGH_BANDPASS      2       /* 1.5Mhz LPF BW */
+
+#define      TWO_TAP_FILT              0
+#define      THREE_TAP_FILT            1
+#define      FOUR_TAP_FILT             2
+#define      FIVE_TAP_FILT             3
+
+#define      AUD_CHAN_SRC_PARALLEL     0
+#define      AUD_CHAN_SRC_I2S_INPUT    1
+#define      AUD_CHAN_SRC_FLATIRON     2
+#define      AUD_CHAN_SRC_PARALLEL3    3
+
+#define      OUT_MODE_601              0
+#define      OUT_MODE_656              1
+#define      OUT_MODE_VIP11            2
+#define      OUT_MODE_VIP20            3
+
+#define      PHASE_INC_49MHZ          0x0df22
+#define      PHASE_INC_56MHZ          0x0fa5b
+#define      PHASE_INC_28MHZ          0x010000
+
+#endif
diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c
new file mode 100644
index 0000000..ac7db52
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c
@@ -0,0 +1,710 @@
+/*
+   cx231xx_vbi.c - driver for Conexant Cx23100/101/102 USB video capture devices
+
+   Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+	Based on cx88 driver
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/msp3400.h>
+#include <media/tuner.h>
+
+#include "cx231xx.h"
+#include "cx231xx-vbi.h"
+
+static inline void print_err_status(struct cx231xx *dev, int packet, int status)
+{
+	char *errmsg = "Unknown";
+
+	switch (status) {
+	case -ENOENT:
+		errmsg = "unlinked synchronuously";
+		break;
+	case -ECONNRESET:
+		errmsg = "unlinked asynchronuously";
+		break;
+	case -ENOSR:
+		errmsg = "Buffer error (overrun)";
+		break;
+	case -EPIPE:
+		errmsg = "Stalled (device not responding)";
+		break;
+	case -EOVERFLOW:
+		errmsg = "Babble (bad cable?)";
+		break;
+	case -EPROTO:
+		errmsg = "Bit-stuff error (bad cable?)";
+		break;
+	case -EILSEQ:
+		errmsg = "CRC/Timeout (could be anything)";
+		break;
+	case -ETIME:
+		errmsg = "Device does not respond";
+		break;
+	}
+	if (packet < 0) {
+		cx231xx_err(DRIVER_NAME "URB status %d [%s].\n", status,
+			    errmsg);
+	} else {
+		cx231xx_err(DRIVER_NAME "URB packet %d, status %d [%s].\n",
+			    packet, status, errmsg);
+	}
+}
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int cx231xx_isoc_vbi_copy(struct cx231xx *dev, struct urb *urb)
+{
+	struct cx231xx_dmaqueue *dma_q = urb->context;
+	int rc = 1;
+	unsigned char *p_buffer;
+	u32 bytes_parsed = 0, buffer_size = 0;
+	u8 sav_eav = 0;
+
+	if (!dev)
+		return 0;
+
+	if (dev->state & DEV_DISCONNECTED)
+		return 0;
+
+	if (urb->status < 0) {
+		print_err_status(dev, -1, urb->status);
+		if (urb->status == -ENOENT)
+			return 0;
+	}
+
+	/* get buffer pointer and length */
+	p_buffer = urb->transfer_buffer;
+	buffer_size = urb->actual_length;
+
+	if (buffer_size > 0) {
+		bytes_parsed = 0;
+
+		if (dma_q->is_partial_line) {
+			/* Handle the case where we were working on a partial
+			   line */
+			sav_eav = dma_q->last_sav;
+		} else {
+			/* Check for a SAV/EAV overlapping the
+			   buffer boundary */
+
+			sav_eav = cx231xx_find_boundary_SAV_EAV(p_buffer,
+							  dma_q->partial_buf,
+							  &bytes_parsed);
+		}
+
+		sav_eav &= 0xF0;
+		/* Get the first line if we have some portion of an SAV/EAV from
+		   the last buffer or a partial line */
+		if (sav_eav) {
+			bytes_parsed += cx231xx_get_vbi_line(dev, dma_q,
+				sav_eav,		       /* SAV/EAV */
+				p_buffer + bytes_parsed,       /* p_buffer */
+				buffer_size - bytes_parsed);   /* buffer size */
+		}
+
+		/* Now parse data that is completely in this buffer */
+		dma_q->is_partial_line = 0;
+
+		while (bytes_parsed < buffer_size) {
+			u32 bytes_used = 0;
+
+			sav_eav = cx231xx_find_next_SAV_EAV(
+				p_buffer + bytes_parsed,	/* p_buffer */
+				buffer_size - bytes_parsed, /* buffer size */
+				&bytes_used);	/* bytes used to get SAV/EAV */
+
+			bytes_parsed += bytes_used;
+
+			sav_eav &= 0xF0;
+			if (sav_eav && (bytes_parsed < buffer_size)) {
+				bytes_parsed += cx231xx_get_vbi_line(dev,
+					dma_q, sav_eav,	/* SAV/EAV */
+					p_buffer+bytes_parsed, /* p_buffer */
+					buffer_size-bytes_parsed);/*buf size*/
+			}
+		}
+
+		/* Save the last four bytes of the buffer so we can
+		check the buffer boundary condition next time */
+		memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4);
+		bytes_parsed = 0;
+	}
+
+	return rc;
+}
+
+/* ------------------------------------------------------------------
+	Vbi buf operations
+   ------------------------------------------------------------------*/
+
+static int
+vbi_buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+		 unsigned int *size)
+{
+	struct cx231xx_fh *fh = vq->priv_data;
+	struct cx231xx *dev = fh->dev;
+	u32 height = 0;
+
+	height = ((dev->norm & V4L2_STD_625_50) ?
+		  PAL_VBI_LINES : NTSC_VBI_LINES);
+
+	*size = (dev->width * height * 2 * 2);
+	if (0 == *count)
+		*count = CX231XX_DEF_VBI_BUF;
+
+	if (*count < CX231XX_MIN_BUF)
+		*count = CX231XX_MIN_BUF;
+
+	return 0;
+}
+
+/* This is called *without* dev->slock held; please keep it that way */
+static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
+{
+	struct cx231xx_fh *fh = vq->priv_data;
+	struct cx231xx *dev = fh->dev;
+	unsigned long flags = 0;
+	if (in_interrupt())
+		BUG();
+
+	/* We used to wait for the buffer to finish here, but this didn't work
+	   because, as we were keeping the state as VIDEOBUF_QUEUED,
+	   videobuf_queue_cancel marked it as finished for us.
+	   (Also, it could wedge forever if the hardware was misconfigured.)
+
+	   This should be safe; by the time we get here, the buffer isn't
+	   queued anymore. If we ever start marking the buffers as
+	   VIDEOBUF_ACTIVE, it won't be, though.
+	 */
+	spin_lock_irqsave(&dev->vbi_mode.slock, flags);
+	if (dev->vbi_mode.bulk_ctl.buf == buf)
+		dev->vbi_mode.bulk_ctl.buf = NULL;
+	spin_unlock_irqrestore(&dev->vbi_mode.slock, flags);
+
+	videobuf_vmalloc_free(&buf->vb);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+vbi_buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+		   enum v4l2_field field)
+{
+	struct cx231xx_fh *fh = vq->priv_data;
+	struct cx231xx_buffer *buf =
+	    container_of(vb, struct cx231xx_buffer, vb);
+	struct cx231xx *dev = fh->dev;
+	int rc = 0, urb_init = 0;
+	u32 height = 0;
+
+	height = ((dev->norm & V4L2_STD_625_50) ?
+		  PAL_VBI_LINES : NTSC_VBI_LINES);
+	buf->vb.size = ((dev->width << 1) * height * 2);
+
+	if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+		return -EINVAL;
+
+	buf->vb.width = dev->width;
+	buf->vb.height = height;
+	buf->vb.field = field;
+	buf->vb.field = V4L2_FIELD_SEQ_TB;
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		rc = videobuf_iolock(vq, &buf->vb, NULL);
+		if (rc < 0)
+			goto fail;
+	}
+
+	if (!dev->vbi_mode.bulk_ctl.num_bufs)
+		urb_init = 1;
+
+	if (urb_init) {
+		rc = cx231xx_init_vbi_isoc(dev, CX231XX_NUM_VBI_PACKETS,
+					   CX231XX_NUM_VBI_BUFS,
+					   dev->vbi_mode.alt_max_pkt_size[0],
+					   cx231xx_isoc_vbi_copy);
+		if (rc < 0)
+			goto fail;
+	}
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+fail:
+	free_buffer(vq, buf);
+	return rc;
+}
+
+static void
+vbi_buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct cx231xx_buffer *buf =
+	    container_of(vb, struct cx231xx_buffer, vb);
+	struct cx231xx_fh *fh = vq->priv_data;
+	struct cx231xx *dev = fh->dev;
+	struct cx231xx_dmaqueue *vidq = &dev->vbi_mode.vidq;
+
+	buf->vb.state = VIDEOBUF_QUEUED;
+	list_add_tail(&buf->vb.queue, &vidq->active);
+
+}
+
+static void vbi_buffer_release(struct videobuf_queue *vq,
+			       struct videobuf_buffer *vb)
+{
+	struct cx231xx_buffer *buf =
+	    container_of(vb, struct cx231xx_buffer, vb);
+
+
+	free_buffer(vq, buf);
+}
+
+struct videobuf_queue_ops cx231xx_vbi_qops = {
+	.buf_setup   = vbi_buffer_setup,
+	.buf_prepare = vbi_buffer_prepare,
+	.buf_queue   = vbi_buffer_queue,
+	.buf_release = vbi_buffer_release,
+};
+
+/* ------------------------------------------------------------------
+	URB control
+   ------------------------------------------------------------------*/
+
+/*
+ * IRQ callback, called by URB callback
+ */
+static void cx231xx_irq_vbi_callback(struct urb *urb)
+{
+	struct cx231xx_dmaqueue *dma_q = urb->context;
+	struct cx231xx_video_mode *vmode =
+	    container_of(dma_q, struct cx231xx_video_mode, vidq);
+	struct cx231xx *dev = container_of(vmode, struct cx231xx, vbi_mode);
+
+	switch (urb->status) {
+	case 0:		/* success */
+	case -ETIMEDOUT:	/* NAK */
+		break;
+	case -ECONNRESET:	/* kill */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	default:		/* error */
+		cx231xx_err(DRIVER_NAME "urb completition error %d.\n",
+			    urb->status);
+		break;
+	}
+
+	/* Copy data from URB */
+	spin_lock(&dev->vbi_mode.slock);
+	dev->vbi_mode.bulk_ctl.bulk_copy(dev, urb);
+	spin_unlock(&dev->vbi_mode.slock);
+
+	/* Reset status */
+	urb->status = 0;
+
+	urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (urb->status) {
+		cx231xx_err(DRIVER_NAME "urb resubmit failed (error=%i)\n",
+			    urb->status);
+	}
+}
+
+/*
+ * Stop and Deallocate URBs
+ */
+void cx231xx_uninit_vbi_isoc(struct cx231xx *dev)
+{
+	struct urb *urb;
+	int i;
+
+	cx231xx_info(DRIVER_NAME "cx231xx: called cx231xx_uninit_vbi_isoc\n");
+
+	dev->vbi_mode.bulk_ctl.nfields = -1;
+	for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) {
+		urb = dev->vbi_mode.bulk_ctl.urb[i];
+		if (urb) {
+			if (!irqs_disabled())
+				usb_kill_urb(urb);
+			else
+				usb_unlink_urb(urb);
+
+			if (dev->vbi_mode.bulk_ctl.transfer_buffer[i]) {
+
+				kfree(dev->vbi_mode.bulk_ctl.
+				      transfer_buffer[i]);
+				dev->vbi_mode.bulk_ctl.transfer_buffer[i] =
+				    NULL;
+			}
+			usb_free_urb(urb);
+			dev->vbi_mode.bulk_ctl.urb[i] = NULL;
+		}
+		dev->vbi_mode.bulk_ctl.transfer_buffer[i] = NULL;
+	}
+
+	kfree(dev->vbi_mode.bulk_ctl.urb);
+	kfree(dev->vbi_mode.bulk_ctl.transfer_buffer);
+
+	dev->vbi_mode.bulk_ctl.urb = NULL;
+	dev->vbi_mode.bulk_ctl.transfer_buffer = NULL;
+	dev->vbi_mode.bulk_ctl.num_bufs = 0;
+
+	cx231xx_capture_start(dev, 0, Vbi);
+}
+EXPORT_SYMBOL_GPL(cx231xx_uninit_vbi_isoc);
+
+/*
+ * Allocate URBs and start IRQ
+ */
+int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
+			  int num_bufs, int max_pkt_size,
+			  int (*bulk_copy) (struct cx231xx *dev,
+					    struct urb *urb))
+{
+	struct cx231xx_dmaqueue *dma_q = &dev->vbi_mode.vidq;
+	int i;
+	int sb_size, pipe;
+	struct urb *urb;
+	int rc;
+
+	cx231xx_info(DRIVER_NAME "cx231xx: called cx231xx_prepare_isoc\n");
+
+	/* De-allocates all pending stuff */
+	cx231xx_uninit_vbi_isoc(dev);
+
+	/* clear if any halt */
+	usb_clear_halt(dev->udev,
+		       usb_rcvbulkpipe(dev->udev,
+				       dev->vbi_mode.end_point_addr));
+
+	dev->vbi_mode.bulk_ctl.bulk_copy = bulk_copy;
+	dev->vbi_mode.bulk_ctl.num_bufs = num_bufs;
+	dma_q->pos = 0;
+	dma_q->is_partial_line = 0;
+	dma_q->last_sav = 0;
+	dma_q->current_field = -1;
+	dma_q->bytes_left_in_line = dev->width << 1;
+	dma_q->lines_per_field = ((dev->norm & V4L2_STD_625_50) ?
+				  PAL_VBI_LINES : NTSC_VBI_LINES);
+	dma_q->lines_completed = 0;
+	for (i = 0; i < 8; i++)
+		dma_q->partial_buf[i] = 0;
+
+	dev->vbi_mode.bulk_ctl.urb = kzalloc(sizeof(void *) * num_bufs,
+					     GFP_KERNEL);
+	if (!dev->vbi_mode.bulk_ctl.urb) {
+		cx231xx_errdev("cannot alloc memory for usb buffers\n");
+		return -ENOMEM;
+	}
+
+	dev->vbi_mode.bulk_ctl.transfer_buffer =
+	    kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
+	if (!dev->vbi_mode.bulk_ctl.transfer_buffer) {
+		cx231xx_errdev("cannot allocate memory for usbtransfer\n");
+		kfree(dev->vbi_mode.bulk_ctl.urb);
+		return -ENOMEM;
+	}
+
+	dev->vbi_mode.bulk_ctl.max_pkt_size = max_pkt_size;
+	dev->vbi_mode.bulk_ctl.buf = NULL;
+
+	sb_size = max_packets * dev->vbi_mode.bulk_ctl.max_pkt_size;
+
+	/* allocate urbs and transfer buffers */
+	for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) {
+
+		urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!urb) {
+			cx231xx_err(DRIVER_NAME
+				    ": cannot alloc bulk_ctl.urb %i\n", i);
+			cx231xx_uninit_vbi_isoc(dev);
+			return -ENOMEM;
+		}
+		dev->vbi_mode.bulk_ctl.urb[i] = urb;
+		urb->transfer_flags = 0;
+
+		dev->vbi_mode.bulk_ctl.transfer_buffer[i] =
+		    kzalloc(sb_size, GFP_KERNEL);
+		if (!dev->vbi_mode.bulk_ctl.transfer_buffer[i]) {
+			cx231xx_err(DRIVER_NAME
+				    ": unable to allocate %i bytes for transfer"
+				    " buffer %i%s\n", sb_size, i,
+				    in_interrupt() ? " while in int" : "");
+			cx231xx_uninit_vbi_isoc(dev);
+			return -ENOMEM;
+		}
+
+		pipe = usb_rcvbulkpipe(dev->udev, dev->vbi_mode.end_point_addr);
+		usb_fill_bulk_urb(urb, dev->udev, pipe,
+				  dev->vbi_mode.bulk_ctl.transfer_buffer[i],
+				  sb_size, cx231xx_irq_vbi_callback, dma_q);
+	}
+
+	init_waitqueue_head(&dma_q->wq);
+
+	/* submit urbs and enables IRQ */
+	for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) {
+		rc = usb_submit_urb(dev->vbi_mode.bulk_ctl.urb[i], GFP_ATOMIC);
+		if (rc) {
+			cx231xx_err(DRIVER_NAME
+				    ": submit of urb %i failed (error=%i)\n", i,
+				    rc);
+			cx231xx_uninit_vbi_isoc(dev);
+			return rc;
+		}
+	}
+
+	cx231xx_capture_start(dev, 1, Vbi);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cx231xx_init_vbi_isoc);
+
+u32 cx231xx_get_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+			 u8 sav_eav, u8 *p_buffer, u32 buffer_size)
+{
+	u32 bytes_copied = 0;
+	int current_field = -1;
+
+	switch (sav_eav) {
+
+	case SAV_VBI_FIELD1:
+		current_field = 1;
+		break;
+
+	case SAV_VBI_FIELD2:
+		current_field = 2;
+		break;
+	default:
+		break;
+	}
+
+	if (current_field < 0)
+		return bytes_copied;
+
+	dma_q->last_sav = sav_eav;
+
+	bytes_copied =
+	    cx231xx_copy_vbi_line(dev, dma_q, p_buffer, buffer_size,
+				  current_field);
+
+	return bytes_copied;
+}
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void vbi_buffer_filled(struct cx231xx *dev,
+				     struct cx231xx_dmaqueue *dma_q,
+				     struct cx231xx_buffer *buf)
+{
+	/* Advice that buffer was filled */
+	/* cx231xx_info(DRIVER_NAME "[%p/%d] wakeup\n", buf, buf->vb.i); */
+
+	buf->vb.state = VIDEOBUF_DONE;
+	buf->vb.field_count++;
+	do_gettimeofday(&buf->vb.ts);
+
+	dev->vbi_mode.bulk_ctl.buf = NULL;
+
+	list_del(&buf->vb.queue);
+	wake_up(&buf->vb.done);
+}
+
+u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+			  u8 *p_line, u32 length, int field_number)
+{
+	u32 bytes_to_copy;
+	struct cx231xx_buffer *buf;
+	u32 _line_size = dev->width * 2;
+
+	if (dma_q->current_field == -1) {
+		/* Just starting up */
+		cx231xx_reset_vbi_buffer(dev, dma_q);
+	}
+
+	if (dma_q->current_field != field_number)
+		dma_q->lines_completed = 0;
+
+	/* get the buffer pointer */
+	buf = dev->vbi_mode.bulk_ctl.buf;
+
+	/* Remember the field number for next time */
+	dma_q->current_field = field_number;
+
+	bytes_to_copy = dma_q->bytes_left_in_line;
+	if (bytes_to_copy > length)
+		bytes_to_copy = length;
+
+	if (dma_q->lines_completed >= dma_q->lines_per_field) {
+		dma_q->bytes_left_in_line -= bytes_to_copy;
+		dma_q->is_partial_line =
+		    (dma_q->bytes_left_in_line == 0) ? 0 : 1;
+		return 0;
+	}
+
+	dma_q->is_partial_line = 1;
+
+	/* If we don't have a buffer, just return the number of bytes we would
+	   have copied if we had a buffer. */
+	if (!buf) {
+		dma_q->bytes_left_in_line -= bytes_to_copy;
+		dma_q->is_partial_line =
+		    (dma_q->bytes_left_in_line == 0) ? 0 : 1;
+		return bytes_to_copy;
+	}
+
+	/* copy the data to video buffer */
+	cx231xx_do_vbi_copy(dev, dma_q, p_line, bytes_to_copy);
+
+	dma_q->pos += bytes_to_copy;
+	dma_q->bytes_left_in_line -= bytes_to_copy;
+
+	if (dma_q->bytes_left_in_line == 0) {
+
+		dma_q->bytes_left_in_line = _line_size;
+		dma_q->lines_completed++;
+		dma_q->is_partial_line = 0;
+
+		if (cx231xx_is_vbi_buffer_done(dev, dma_q) && buf) {
+
+			vbi_buffer_filled(dev, dma_q, buf);
+
+			dma_q->pos = 0;
+			dma_q->lines_completed = 0;
+			cx231xx_reset_vbi_buffer(dev, dma_q);
+		}
+	}
+
+	return bytes_to_copy;
+}
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q,
+				    struct cx231xx_buffer **buf)
+{
+	struct cx231xx_video_mode *vmode =
+	    container_of(dma_q, struct cx231xx_video_mode, vidq);
+	struct cx231xx *dev = container_of(vmode, struct cx231xx, vbi_mode);
+	char *outp;
+
+	if (list_empty(&dma_q->active)) {
+		cx231xx_err(DRIVER_NAME ": No active queue to serve\n");
+		dev->vbi_mode.bulk_ctl.buf = NULL;
+		*buf = NULL;
+		return;
+	}
+
+	/* Get the next buffer */
+	*buf = list_entry(dma_q->active.next, struct cx231xx_buffer, vb.queue);
+
+	/* Cleans up buffer - Useful for testing for frame/URB loss */
+	outp = videobuf_to_vmalloc(&(*buf)->vb);
+	memset(outp, 0, (*buf)->vb.size);
+
+	dev->vbi_mode.bulk_ctl.buf = *buf;
+
+	return;
+}
+
+void cx231xx_reset_vbi_buffer(struct cx231xx *dev,
+			      struct cx231xx_dmaqueue *dma_q)
+{
+	struct cx231xx_buffer *buf;
+
+	buf = dev->vbi_mode.bulk_ctl.buf;
+
+	if (buf == NULL) {
+		/* first try to get the buffer */
+		get_next_vbi_buf(dma_q, &buf);
+
+		dma_q->pos = 0;
+		dma_q->current_field = -1;
+	}
+
+	dma_q->bytes_left_in_line = dev->width << 1;
+	dma_q->lines_completed = 0;
+}
+
+int cx231xx_do_vbi_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+			u8 *p_buffer, u32 bytes_to_copy)
+{
+	u8 *p_out_buffer = NULL;
+	u32 current_line_bytes_copied = 0;
+	struct cx231xx_buffer *buf;
+	u32 _line_size = dev->width << 1;
+	void *startwrite;
+	int offset, lencopy;
+
+	buf = dev->vbi_mode.bulk_ctl.buf;
+
+	if (buf == NULL)
+		return -EINVAL;
+
+	p_out_buffer = videobuf_to_vmalloc(&buf->vb);
+
+	if (dma_q->bytes_left_in_line != _line_size) {
+		current_line_bytes_copied =
+		    _line_size - dma_q->bytes_left_in_line;
+	}
+
+	offset = (dma_q->lines_completed * _line_size) +
+		 current_line_bytes_copied;
+
+	if (dma_q->current_field == 2) {
+		/* Populate the second half of the frame */
+		offset += (dev->width * 2 * dma_q->lines_per_field);
+	}
+
+	/* prepare destination address */
+	startwrite = p_out_buffer + offset;
+
+	lencopy = dma_q->bytes_left_in_line > bytes_to_copy ?
+		  bytes_to_copy : dma_q->bytes_left_in_line;
+
+	memcpy(startwrite, p_buffer, lencopy);
+
+	return 0;
+}
+
+u8 cx231xx_is_vbi_buffer_done(struct cx231xx *dev,
+			      struct cx231xx_dmaqueue *dma_q)
+{
+	u32 height = 0;
+
+	height = ((dev->norm & V4L2_STD_625_50) ?
+		  PAL_VBI_LINES : NTSC_VBI_LINES);
+	if (dma_q->lines_completed == height && dma_q->current_field == 2)
+		return 1;
+	else
+		return 0;
+}
diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.h b/drivers/media/usb/cx231xx/cx231xx-vbi.h
new file mode 100644
index 0000000..16c7d20
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-vbi.h
@@ -0,0 +1,65 @@
+/*
+   cx231xx_vbi.h - driver for Conexant Cx23100/101/102 USB video capture devices
+
+   Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+		Based on cx88 driver
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _CX231XX_VBI_H
+#define _CX231XX_VBI_H
+
+extern struct videobuf_queue_ops cx231xx_vbi_qops;
+
+#define   NTSC_VBI_START_LINE 10	/* line 10 - 21 */
+#define   NTSC_VBI_END_LINE   21
+#define   NTSC_VBI_LINES	  (NTSC_VBI_END_LINE-NTSC_VBI_START_LINE+1)
+
+#define   PAL_VBI_START_LINE  6
+#define   PAL_VBI_END_LINE    23
+#define   PAL_VBI_LINES       (PAL_VBI_END_LINE-PAL_VBI_START_LINE+1)
+
+#define   VBI_STRIDE            1440
+#define   VBI_SAMPLES_PER_LINE  1440
+
+#define   CX231XX_NUM_VBI_PACKETS       4
+#define   CX231XX_NUM_VBI_BUFS          5
+
+/* stream functions */
+int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
+			  int num_bufs, int max_pkt_size,
+			  int (*bulk_copy) (struct cx231xx *dev,
+					    struct urb *urb));
+
+void cx231xx_uninit_vbi_isoc(struct cx231xx *dev);
+
+/* vbi data copy functions */
+u32 cx231xx_get_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+			 u8 sav_eav, u8 *p_buffer, u32 buffer_size);
+
+u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+			  u8 *p_line, u32 length, int field_number);
+
+void cx231xx_reset_vbi_buffer(struct cx231xx *dev,
+			      struct cx231xx_dmaqueue *dma_q);
+
+int cx231xx_do_vbi_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+			u8 *p_buffer, u32 bytes_to_copy);
+
+u8 cx231xx_is_vbi_buffer_done(struct cx231xx *dev,
+			      struct cx231xx_dmaqueue *dma_q);
+
+#endif
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
new file mode 100644
index 0000000..790b28d
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -0,0 +1,2670 @@
+/*
+   cx231xx-video.c - driver for Conexant Cx23100/101/102
+		     USB video capture devices
+
+   Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+	Based on em28xx driver
+	Based on cx23885 driver
+	Based on cx88 driver
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/msp3400.h>
+#include <media/tuner.h>
+
+#include "dvb_frontend.h"
+
+#include "cx231xx.h"
+#include "cx231xx-vbi.h"
+
+#define CX231XX_VERSION "0.0.2"
+
+#define DRIVER_AUTHOR   "Srinivasa Deevi <srinivasa.deevi@conexant.com>"
+#define DRIVER_DESC     "Conexant cx231xx based USB video device driver"
+
+#define cx231xx_videodbg(fmt, arg...) do {\
+	if (video_debug) \
+		printk(KERN_INFO "%s %s :"fmt, \
+			 dev->name, __func__ , ##arg); } while (0)
+
+static unsigned int isoc_debug;
+module_param(isoc_debug, int, 0644);
+MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
+
+#define cx231xx_isocdbg(fmt, arg...) \
+do {\
+	if (isoc_debug) { \
+		printk(KERN_INFO "%s %s :"fmt, \
+			 dev->name, __func__ , ##arg); \
+	} \
+  } while (0)
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CX231XX_VERSION);
+
+static unsigned int card[]     = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int video_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int vbi_nr[]   = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(card, int, NULL, 0444);
+module_param_array(video_nr, int, NULL, 0444);
+module_param_array(vbi_nr, int, NULL, 0444);
+module_param_array(radio_nr, int, NULL, 0444);
+
+MODULE_PARM_DESC(card, "card type");
+MODULE_PARM_DESC(video_nr, "video device numbers");
+MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
+MODULE_PARM_DESC(radio_nr, "radio device numbers");
+
+static unsigned int video_debug;
+module_param(video_debug, int, 0644);
+MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
+
+/* supported video standards */
+static struct cx231xx_fmt format[] = {
+	{
+	 .name = "16bpp YUY2, 4:2:2, packed",
+	 .fourcc = V4L2_PIX_FMT_YUYV,
+	 .depth = 16,
+	 .reg = 0,
+	 },
+};
+
+/* supported controls */
+/* Common to all boards */
+
+/* ------------------------------------------------------------------- */
+
+static const struct v4l2_queryctrl no_ctl = {
+	.name = "42",
+	.flags = V4L2_CTRL_FLAG_DISABLED,
+};
+
+static struct cx231xx_ctrl cx231xx_ctls[] = {
+	/* --- video --- */
+	{
+		.v = {
+			.id = V4L2_CID_BRIGHTNESS,
+			.name = "Brightness",
+			.minimum = 0x00,
+			.maximum = 0xff,
+			.step = 1,
+			.default_value = 0x7f,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+		.off = 128,
+		.reg = LUMA_CTRL,
+		.mask = 0x00ff,
+		.shift = 0,
+	}, {
+		.v = {
+			.id = V4L2_CID_CONTRAST,
+			.name = "Contrast",
+			.minimum = 0,
+			.maximum = 0xff,
+			.step = 1,
+			.default_value = 0x3f,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+		.off = 0,
+		.reg = LUMA_CTRL,
+		.mask = 0xff00,
+		.shift = 8,
+	}, {
+		.v = {
+			.id = V4L2_CID_HUE,
+			.name = "Hue",
+			.minimum = 0,
+			.maximum = 0xff,
+			.step = 1,
+			.default_value = 0x7f,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+		.off = 128,
+		.reg = CHROMA_CTRL,
+		.mask = 0xff0000,
+		.shift = 16,
+	}, {
+	/* strictly, this only describes only U saturation.
+	* V saturation is handled specially through code.
+	*/
+		.v = {
+			.id = V4L2_CID_SATURATION,
+			.name = "Saturation",
+			.minimum = 0,
+			.maximum = 0xff,
+			.step = 1,
+			.default_value = 0x7f,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+		.off = 0,
+		.reg = CHROMA_CTRL,
+		.mask = 0x00ff,
+		.shift = 0,
+	}, {
+		/* --- audio --- */
+		.v = {
+			.id = V4L2_CID_AUDIO_MUTE,
+			.name = "Mute",
+			.minimum = 0,
+			.maximum = 1,
+			.default_value = 1,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+		},
+		.reg = PATH1_CTL1,
+		.mask = (0x1f << 24),
+		.shift = 24,
+	}, {
+		.v = {
+			.id = V4L2_CID_AUDIO_VOLUME,
+			.name = "Volume",
+			.minimum = 0,
+			.maximum = 0x3f,
+			.step = 1,
+			.default_value = 0x3f,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+		.reg = PATH1_VOL_CTL,
+		.mask = 0xff,
+		.shift = 0,
+	}
+};
+static const int CX231XX_CTLS = ARRAY_SIZE(cx231xx_ctls);
+
+static const u32 cx231xx_user_ctrls[] = {
+	V4L2_CID_USER_CLASS,
+	V4L2_CID_BRIGHTNESS,
+	V4L2_CID_CONTRAST,
+	V4L2_CID_SATURATION,
+	V4L2_CID_HUE,
+	V4L2_CID_AUDIO_VOLUME,
+#if 0
+	V4L2_CID_AUDIO_BALANCE,
+#endif
+	V4L2_CID_AUDIO_MUTE,
+	0
+};
+
+static const u32 *ctrl_classes[] = {
+	cx231xx_user_ctrls,
+	NULL
+};
+
+/* ------------------------------------------------------------------
+	Video buffer and parser functions
+   ------------------------------------------------------------------*/
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void buffer_filled(struct cx231xx *dev,
+				 struct cx231xx_dmaqueue *dma_q,
+				 struct cx231xx_buffer *buf)
+{
+	/* Advice that buffer was filled */
+	cx231xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+	buf->vb.state = VIDEOBUF_DONE;
+	buf->vb.field_count++;
+	do_gettimeofday(&buf->vb.ts);
+
+	if (dev->USE_ISO)
+		dev->video_mode.isoc_ctl.buf = NULL;
+	else
+		dev->video_mode.bulk_ctl.buf = NULL;
+
+	list_del(&buf->vb.queue);
+	wake_up(&buf->vb.done);
+}
+
+static inline void print_err_status(struct cx231xx *dev, int packet, int status)
+{
+	char *errmsg = "Unknown";
+
+	switch (status) {
+	case -ENOENT:
+		errmsg = "unlinked synchronuously";
+		break;
+	case -ECONNRESET:
+		errmsg = "unlinked asynchronuously";
+		break;
+	case -ENOSR:
+		errmsg = "Buffer error (overrun)";
+		break;
+	case -EPIPE:
+		errmsg = "Stalled (device not responding)";
+		break;
+	case -EOVERFLOW:
+		errmsg = "Babble (bad cable?)";
+		break;
+	case -EPROTO:
+		errmsg = "Bit-stuff error (bad cable?)";
+		break;
+	case -EILSEQ:
+		errmsg = "CRC/Timeout (could be anything)";
+		break;
+	case -ETIME:
+		errmsg = "Device does not respond";
+		break;
+	}
+	if (packet < 0) {
+		cx231xx_isocdbg("URB status %d [%s].\n", status, errmsg);
+	} else {
+		cx231xx_isocdbg("URB packet %d, status %d [%s].\n",
+				packet, status, errmsg);
+	}
+}
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q,
+				struct cx231xx_buffer **buf)
+{
+	struct cx231xx_video_mode *vmode =
+	    container_of(dma_q, struct cx231xx_video_mode, vidq);
+	struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
+
+	char *outp;
+
+	if (list_empty(&dma_q->active)) {
+		cx231xx_isocdbg("No active queue to serve\n");
+		if (dev->USE_ISO)
+			dev->video_mode.isoc_ctl.buf = NULL;
+		else
+			dev->video_mode.bulk_ctl.buf = NULL;
+		*buf = NULL;
+		return;
+	}
+
+	/* Get the next buffer */
+	*buf = list_entry(dma_q->active.next, struct cx231xx_buffer, vb.queue);
+
+	/* Cleans up buffer - Useful for testing for frame/URB loss */
+	outp = videobuf_to_vmalloc(&(*buf)->vb);
+	memset(outp, 0, (*buf)->vb.size);
+
+	if (dev->USE_ISO)
+		dev->video_mode.isoc_ctl.buf = *buf;
+	else
+		dev->video_mode.bulk_ctl.buf = *buf;
+
+	return;
+}
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
+{
+	struct cx231xx_dmaqueue *dma_q = urb->context;
+	int i, rc = 1;
+	unsigned char *p_buffer;
+	u32 bytes_parsed = 0, buffer_size = 0;
+	u8 sav_eav = 0;
+
+	if (!dev)
+		return 0;
+
+	if (dev->state & DEV_DISCONNECTED)
+		return 0;
+
+	if (urb->status < 0) {
+		print_err_status(dev, -1, urb->status);
+		if (urb->status == -ENOENT)
+			return 0;
+	}
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		int status = urb->iso_frame_desc[i].status;
+
+		if (status < 0) {
+			print_err_status(dev, i, status);
+			if (urb->iso_frame_desc[i].status != -EPROTO)
+				continue;
+		}
+
+		if (urb->iso_frame_desc[i].actual_length <= 0) {
+			/* cx231xx_isocdbg("packet %d is empty",i); - spammy */
+			continue;
+		}
+		if (urb->iso_frame_desc[i].actual_length >
+		    dev->video_mode.max_pkt_size) {
+			cx231xx_isocdbg("packet bigger than packet size");
+			continue;
+		}
+
+		/*  get buffer pointer and length */
+		p_buffer = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+		buffer_size = urb->iso_frame_desc[i].actual_length;
+		bytes_parsed = 0;
+
+		if (dma_q->is_partial_line) {
+			/* Handle the case of a partial line */
+			sav_eav = dma_q->last_sav;
+		} else {
+			/* Check for a SAV/EAV overlapping
+				the buffer boundary */
+			sav_eav =
+			    cx231xx_find_boundary_SAV_EAV(p_buffer,
+							  dma_q->partial_buf,
+							  &bytes_parsed);
+		}
+
+		sav_eav &= 0xF0;
+		/* Get the first line if we have some portion of an SAV/EAV from
+		   the last buffer or a partial line  */
+		if (sav_eav) {
+			bytes_parsed += cx231xx_get_video_line(dev, dma_q,
+				sav_eav,	/* SAV/EAV */
+				p_buffer + bytes_parsed,	/* p_buffer */
+				buffer_size - bytes_parsed);/* buf size */
+		}
+
+		/* Now parse data that is completely in this buffer */
+		/* dma_q->is_partial_line = 0;  */
+
+		while (bytes_parsed < buffer_size) {
+			u32 bytes_used = 0;
+
+			sav_eav = cx231xx_find_next_SAV_EAV(
+				p_buffer + bytes_parsed,	/* p_buffer */
+				buffer_size - bytes_parsed,	/* buf size */
+				&bytes_used);/* bytes used to get SAV/EAV */
+
+			bytes_parsed += bytes_used;
+
+			sav_eav &= 0xF0;
+			if (sav_eav && (bytes_parsed < buffer_size)) {
+				bytes_parsed += cx231xx_get_video_line(dev,
+					dma_q, sav_eav,	/* SAV/EAV */
+					p_buffer + bytes_parsed,/* p_buffer */
+					buffer_size - bytes_parsed);/*buf size*/
+			}
+		}
+
+		/* Save the last four bytes of the buffer so we can check the
+		   buffer boundary condition next time */
+		memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4);
+		bytes_parsed = 0;
+
+	}
+	return rc;
+}
+
+static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
+{
+	struct cx231xx_dmaqueue *dma_q = urb->context;
+	int rc = 1;
+	unsigned char *p_buffer;
+	u32 bytes_parsed = 0, buffer_size = 0;
+	u8 sav_eav = 0;
+
+	if (!dev)
+		return 0;
+
+	if (dev->state & DEV_DISCONNECTED)
+		return 0;
+
+	if (urb->status < 0) {
+		print_err_status(dev, -1, urb->status);
+		if (urb->status == -ENOENT)
+			return 0;
+	}
+
+	if (1) {
+
+		/*  get buffer pointer and length */
+		p_buffer = urb->transfer_buffer;
+		buffer_size = urb->actual_length;
+		bytes_parsed = 0;
+
+		if (dma_q->is_partial_line) {
+			/* Handle the case of a partial line */
+			sav_eav = dma_q->last_sav;
+		} else {
+			/* Check for a SAV/EAV overlapping
+				the buffer boundary */
+			sav_eav =
+			    cx231xx_find_boundary_SAV_EAV(p_buffer,
+							  dma_q->partial_buf,
+							  &bytes_parsed);
+		}
+
+		sav_eav &= 0xF0;
+		/* Get the first line if we have some portion of an SAV/EAV from
+		   the last buffer or a partial line  */
+		if (sav_eav) {
+			bytes_parsed += cx231xx_get_video_line(dev, dma_q,
+				sav_eav,	/* SAV/EAV */
+				p_buffer + bytes_parsed,	/* p_buffer */
+				buffer_size - bytes_parsed);/* buf size */
+		}
+
+		/* Now parse data that is completely in this buffer */
+		/* dma_q->is_partial_line = 0;  */
+
+		while (bytes_parsed < buffer_size) {
+			u32 bytes_used = 0;
+
+			sav_eav = cx231xx_find_next_SAV_EAV(
+				p_buffer + bytes_parsed,	/* p_buffer */
+				buffer_size - bytes_parsed,	/* buf size */
+				&bytes_used);/* bytes used to get SAV/EAV */
+
+			bytes_parsed += bytes_used;
+
+			sav_eav &= 0xF0;
+			if (sav_eav && (bytes_parsed < buffer_size)) {
+				bytes_parsed += cx231xx_get_video_line(dev,
+					dma_q, sav_eav,	/* SAV/EAV */
+					p_buffer + bytes_parsed,/* p_buffer */
+					buffer_size - bytes_parsed);/*buf size*/
+			}
+		}
+
+		/* Save the last four bytes of the buffer so we can check the
+		   buffer boundary condition next time */
+		memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4);
+		bytes_parsed = 0;
+
+	}
+	return rc;
+}
+
+
+u8 cx231xx_find_boundary_SAV_EAV(u8 *p_buffer, u8 *partial_buf,
+				 u32 *p_bytes_used)
+{
+	u32 bytes_used;
+	u8 boundary_bytes[8];
+	u8 sav_eav = 0;
+
+	*p_bytes_used = 0;
+
+	/* Create an array of the last 4 bytes of the last buffer and the first
+	   4 bytes of the current buffer. */
+
+	memcpy(boundary_bytes, partial_buf, 4);
+	memcpy(boundary_bytes + 4, p_buffer, 4);
+
+	/* Check for the SAV/EAV in the boundary buffer */
+	sav_eav = cx231xx_find_next_SAV_EAV((u8 *)&boundary_bytes, 8,
+					    &bytes_used);
+
+	if (sav_eav) {
+		/* found a boundary SAV/EAV.  Updates the bytes used to reflect
+		   only those used in the new buffer */
+		*p_bytes_used = bytes_used - 4;
+	}
+
+	return sav_eav;
+}
+
+u8 cx231xx_find_next_SAV_EAV(u8 *p_buffer, u32 buffer_size, u32 *p_bytes_used)
+{
+	u32 i;
+	u8 sav_eav = 0;
+
+	/*
+	 * Don't search if the buffer size is less than 4.  It causes a page
+	 * fault since buffer_size - 4 evaluates to a large number in that
+	 * case.
+	 */
+	if (buffer_size < 4) {
+		*p_bytes_used = buffer_size;
+		return 0;
+	}
+
+	for (i = 0; i < (buffer_size - 3); i++) {
+
+		if ((p_buffer[i] == 0xFF) &&
+		    (p_buffer[i + 1] == 0x00) && (p_buffer[i + 2] == 0x00)) {
+
+			*p_bytes_used = i + 4;
+			sav_eav = p_buffer[i + 3];
+			return sav_eav;
+		}
+	}
+
+	*p_bytes_used = buffer_size;
+	return 0;
+}
+
+u32 cx231xx_get_video_line(struct cx231xx *dev,
+			   struct cx231xx_dmaqueue *dma_q, u8 sav_eav,
+			   u8 *p_buffer, u32 buffer_size)
+{
+	u32 bytes_copied = 0;
+	int current_field = -1;
+
+	switch (sav_eav) {
+	case SAV_ACTIVE_VIDEO_FIELD1:
+		/* looking for skipped line which occurred in PAL 720x480 mode.
+		   In this case, there will be no active data contained
+		   between the SAV and EAV */
+		if ((buffer_size > 3) && (p_buffer[0] == 0xFF) &&
+		    (p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) &&
+		    ((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) ||
+		     (p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) ||
+		     (p_buffer[3] == EAV_VBLANK_FIELD1) ||
+		     (p_buffer[3] == EAV_VBLANK_FIELD2)))
+			return bytes_copied;
+		current_field = 1;
+		break;
+
+	case SAV_ACTIVE_VIDEO_FIELD2:
+		/* looking for skipped line which occurred in PAL 720x480 mode.
+		   In this case, there will be no active data contained between
+		   the SAV and EAV */
+		if ((buffer_size > 3) && (p_buffer[0] == 0xFF) &&
+		    (p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) &&
+		    ((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) ||
+		     (p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) ||
+		     (p_buffer[3] == EAV_VBLANK_FIELD1)       ||
+		     (p_buffer[3] == EAV_VBLANK_FIELD2)))
+			return bytes_copied;
+		current_field = 2;
+		break;
+	}
+
+	dma_q->last_sav = sav_eav;
+
+	bytes_copied = cx231xx_copy_video_line(dev, dma_q, p_buffer,
+					       buffer_size, current_field);
+
+	return bytes_copied;
+}
+
+u32 cx231xx_copy_video_line(struct cx231xx *dev,
+			    struct cx231xx_dmaqueue *dma_q, u8 *p_line,
+			    u32 length, int field_number)
+{
+	u32 bytes_to_copy;
+	struct cx231xx_buffer *buf;
+	u32 _line_size = dev->width * 2;
+
+	if (dma_q->current_field != field_number)
+		cx231xx_reset_video_buffer(dev, dma_q);
+
+	/* get the buffer pointer */
+	if (dev->USE_ISO)
+		buf = dev->video_mode.isoc_ctl.buf;
+	else
+		buf = dev->video_mode.bulk_ctl.buf;
+
+	/* Remember the field number for next time */
+	dma_q->current_field = field_number;
+
+	bytes_to_copy = dma_q->bytes_left_in_line;
+	if (bytes_to_copy > length)
+		bytes_to_copy = length;
+
+	if (dma_q->lines_completed >= dma_q->lines_per_field) {
+		dma_q->bytes_left_in_line -= bytes_to_copy;
+		dma_q->is_partial_line = (dma_q->bytes_left_in_line == 0) ?
+					  0 : 1;
+		return 0;
+	}
+
+	dma_q->is_partial_line = 1;
+
+	/* If we don't have a buffer, just return the number of bytes we would
+	   have copied if we had a buffer. */
+	if (!buf) {
+		dma_q->bytes_left_in_line -= bytes_to_copy;
+		dma_q->is_partial_line = (dma_q->bytes_left_in_line == 0)
+					 ? 0 : 1;
+		return bytes_to_copy;
+	}
+
+	/* copy the data to video buffer */
+	cx231xx_do_copy(dev, dma_q, p_line, bytes_to_copy);
+
+	dma_q->pos += bytes_to_copy;
+	dma_q->bytes_left_in_line -= bytes_to_copy;
+
+	if (dma_q->bytes_left_in_line == 0) {
+		dma_q->bytes_left_in_line = _line_size;
+		dma_q->lines_completed++;
+		dma_q->is_partial_line = 0;
+
+		if (cx231xx_is_buffer_done(dev, dma_q) && buf) {
+			buffer_filled(dev, dma_q, buf);
+
+			dma_q->pos = 0;
+			buf = NULL;
+			dma_q->lines_completed = 0;
+		}
+	}
+
+	return bytes_to_copy;
+}
+
+void cx231xx_reset_video_buffer(struct cx231xx *dev,
+				struct cx231xx_dmaqueue *dma_q)
+{
+	struct cx231xx_buffer *buf;
+
+	/* handle the switch from field 1 to field 2 */
+	if (dma_q->current_field == 1) {
+		if (dma_q->lines_completed >= dma_q->lines_per_field)
+			dma_q->field1_done = 1;
+		else
+			dma_q->field1_done = 0;
+	}
+
+	if (dev->USE_ISO)
+		buf = dev->video_mode.isoc_ctl.buf;
+	else
+		buf = dev->video_mode.bulk_ctl.buf;
+
+	if (buf == NULL) {
+		/* first try to get the buffer */
+		get_next_buf(dma_q, &buf);
+
+		dma_q->pos = 0;
+		dma_q->field1_done = 0;
+		dma_q->current_field = -1;
+	}
+
+	/* reset the counters */
+	dma_q->bytes_left_in_line = dev->width << 1;
+	dma_q->lines_completed = 0;
+}
+
+int cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+		    u8 *p_buffer, u32 bytes_to_copy)
+{
+	u8 *p_out_buffer = NULL;
+	u32 current_line_bytes_copied = 0;
+	struct cx231xx_buffer *buf;
+	u32 _line_size = dev->width << 1;
+	void *startwrite;
+	int offset, lencopy;
+
+	if (dev->USE_ISO)
+		buf = dev->video_mode.isoc_ctl.buf;
+	else
+		buf = dev->video_mode.bulk_ctl.buf;
+
+	if (buf == NULL)
+		return -1;
+
+	p_out_buffer = videobuf_to_vmalloc(&buf->vb);
+
+	current_line_bytes_copied = _line_size - dma_q->bytes_left_in_line;
+
+	/* Offset field 2 one line from the top of the buffer */
+	offset = (dma_q->current_field == 1) ? 0 : _line_size;
+
+	/* Offset for field 2 */
+	startwrite = p_out_buffer + offset;
+
+	/* lines already completed in the current field */
+	startwrite += (dma_q->lines_completed * _line_size * 2);
+
+	/* bytes already completed in the current line */
+	startwrite += current_line_bytes_copied;
+
+	lencopy = dma_q->bytes_left_in_line > bytes_to_copy ?
+		  bytes_to_copy : dma_q->bytes_left_in_line;
+
+	if ((u8 *)(startwrite + lencopy) > (u8 *)(p_out_buffer + buf->vb.size))
+		return 0;
+
+	/* The below copies the UYVY data straight into video buffer */
+	cx231xx_swab((u16 *) p_buffer, (u16 *) startwrite, (u16) lencopy);
+
+	return 0;
+}
+
+void cx231xx_swab(u16 *from, u16 *to, u16 len)
+{
+	u16 i;
+
+	if (len <= 0)
+		return;
+
+	for (i = 0; i < len / 2; i++)
+		to[i] = (from[i] << 8) | (from[i] >> 8);
+}
+
+u8 cx231xx_is_buffer_done(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q)
+{
+	u8 buffer_complete = 0;
+
+	/* Dual field stream */
+	buffer_complete = ((dma_q->current_field == 2) &&
+			   (dma_q->lines_completed >= dma_q->lines_per_field) &&
+			    dma_q->field1_done);
+
+	return buffer_complete;
+}
+
+/* ------------------------------------------------------------------
+	Videobuf operations
+   ------------------------------------------------------------------*/
+
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+{
+	struct cx231xx_fh *fh = vq->priv_data;
+	struct cx231xx *dev = fh->dev;
+
+	*size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)>>3;
+	if (0 == *count)
+		*count = CX231XX_DEF_BUF;
+
+	if (*count < CX231XX_MIN_BUF)
+		*count = CX231XX_MIN_BUF;
+
+	return 0;
+}
+
+/* This is called *without* dev->slock held; please keep it that way */
+static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
+{
+	struct cx231xx_fh *fh = vq->priv_data;
+	struct cx231xx *dev = fh->dev;
+	unsigned long flags = 0;
+
+	if (in_interrupt())
+		BUG();
+
+	/* We used to wait for the buffer to finish here, but this didn't work
+	   because, as we were keeping the state as VIDEOBUF_QUEUED,
+	   videobuf_queue_cancel marked it as finished for us.
+	   (Also, it could wedge forever if the hardware was misconfigured.)
+
+	   This should be safe; by the time we get here, the buffer isn't
+	   queued anymore. If we ever start marking the buffers as
+	   VIDEOBUF_ACTIVE, it won't be, though.
+	 */
+	spin_lock_irqsave(&dev->video_mode.slock, flags);
+	if (dev->USE_ISO) {
+		if (dev->video_mode.isoc_ctl.buf == buf)
+			dev->video_mode.isoc_ctl.buf = NULL;
+	} else {
+		if (dev->video_mode.bulk_ctl.buf == buf)
+			dev->video_mode.bulk_ctl.buf = NULL;
+	}
+	spin_unlock_irqrestore(&dev->video_mode.slock, flags);
+
+	videobuf_vmalloc_free(&buf->vb);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+	       enum v4l2_field field)
+{
+	struct cx231xx_fh *fh = vq->priv_data;
+	struct cx231xx_buffer *buf =
+	    container_of(vb, struct cx231xx_buffer, vb);
+	struct cx231xx *dev = fh->dev;
+	int rc = 0, urb_init = 0;
+
+	/* The only currently supported format is 16 bits/pixel */
+	buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth
+			+ 7) >> 3;
+	if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+		return -EINVAL;
+
+	buf->vb.width = dev->width;
+	buf->vb.height = dev->height;
+	buf->vb.field = field;
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		rc = videobuf_iolock(vq, &buf->vb, NULL);
+		if (rc < 0)
+			goto fail;
+	}
+
+	if (dev->USE_ISO) {
+		if (!dev->video_mode.isoc_ctl.num_bufs)
+			urb_init = 1;
+	} else {
+		if (!dev->video_mode.bulk_ctl.num_bufs)
+			urb_init = 1;
+	}
+	/*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n",
+		urb_init, dev->video_mode.max_pkt_size);*/
+	if (urb_init) {
+		dev->mode_tv = 0;
+		if (dev->USE_ISO)
+			rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
+				       CX231XX_NUM_BUFS,
+				       dev->video_mode.max_pkt_size,
+				       cx231xx_isoc_copy);
+		else
+			rc = cx231xx_init_bulk(dev, CX231XX_NUM_PACKETS,
+				       CX231XX_NUM_BUFS,
+				       dev->video_mode.max_pkt_size,
+				       cx231xx_bulk_copy);
+		if (rc < 0)
+			goto fail;
+	}
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+fail:
+	free_buffer(vq, buf);
+	return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct cx231xx_buffer *buf =
+	    container_of(vb, struct cx231xx_buffer, vb);
+	struct cx231xx_fh *fh = vq->priv_data;
+	struct cx231xx *dev = fh->dev;
+	struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
+
+	buf->vb.state = VIDEOBUF_QUEUED;
+	list_add_tail(&buf->vb.queue, &vidq->active);
+
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+			   struct videobuf_buffer *vb)
+{
+	struct cx231xx_buffer *buf =
+	    container_of(vb, struct cx231xx_buffer, vb);
+	struct cx231xx_fh *fh = vq->priv_data;
+	struct cx231xx *dev = (struct cx231xx *)fh->dev;
+
+	cx231xx_isocdbg("cx231xx: called buffer_release\n");
+
+	free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops cx231xx_video_qops = {
+	.buf_setup = buffer_setup,
+	.buf_prepare = buffer_prepare,
+	.buf_queue = buffer_queue,
+	.buf_release = buffer_release,
+};
+
+/*********************  v4l2 interface  **************************************/
+
+void video_mux(struct cx231xx *dev, int index)
+{
+	dev->video_input = index;
+	dev->ctl_ainput = INPUT(index)->amux;
+
+	cx231xx_set_video_input_mux(dev, index);
+
+	cx25840_call(dev, video, s_routing, INPUT(index)->vmux, 0, 0);
+
+	cx231xx_set_audio_input(dev, dev->ctl_ainput);
+
+	cx231xx_info("video_mux : %d\n", index);
+
+	/* do mode control overrides if required */
+	cx231xx_do_mode_ctrl_overrides(dev);
+}
+
+/* Usage lock check functions */
+static int res_get(struct cx231xx_fh *fh)
+{
+	struct cx231xx *dev = fh->dev;
+	int rc = 0;
+
+	/* This instance already has stream_on */
+	if (fh->stream_on)
+		return rc;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		if (dev->stream_on)
+			return -EBUSY;
+		dev->stream_on = 1;
+	} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+		if (dev->vbi_stream_on)
+			return -EBUSY;
+		dev->vbi_stream_on = 1;
+	} else
+		return -EINVAL;
+
+	fh->stream_on = 1;
+
+	return rc;
+}
+
+static int res_check(struct cx231xx_fh *fh)
+{
+	return fh->stream_on;
+}
+
+static void res_free(struct cx231xx_fh *fh)
+{
+	struct cx231xx *dev = fh->dev;
+
+	fh->stream_on = 0;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		dev->stream_on = 0;
+	if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		dev->vbi_stream_on = 0;
+}
+
+static int check_dev(struct cx231xx *dev)
+{
+	if (dev->state & DEV_DISCONNECTED) {
+		cx231xx_errdev("v4l2 ioctl: device not present\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+/* ------------------------------------------------------------------
+	IOCTL vidioc handling
+   ------------------------------------------------------------------*/
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+
+	f->fmt.pix.width = dev->width;
+	f->fmt.pix.height = dev->height;
+	f->fmt.pix.pixelformat = dev->format->fourcc;
+	f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
+	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+	f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+	return 0;
+}
+
+static struct cx231xx_fmt *format_by_fourcc(unsigned int fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(format); i++)
+		if (format[i].fourcc == fourcc)
+			return &format[i];
+
+	return NULL;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	unsigned int width = f->fmt.pix.width;
+	unsigned int height = f->fmt.pix.height;
+	unsigned int maxw = norm_maxw(dev);
+	unsigned int maxh = norm_maxh(dev);
+	struct cx231xx_fmt *fmt;
+
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	if (!fmt) {
+		cx231xx_videodbg("Fourcc format (%08x) invalid.\n",
+				 f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	/* width must even because of the YUYV format
+	   height must be even because of interlacing */
+	v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0);
+
+	f->fmt.pix.width = width;
+	f->fmt.pix.height = height;
+	f->fmt.pix.pixelformat = fmt->fourcc;
+	f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
+	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+	struct cx231xx_fmt *fmt;
+	struct v4l2_mbus_framefmt mbus_fmt;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	vidioc_try_fmt_vid_cap(file, priv, f);
+
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	if (!fmt)
+		return -EINVAL;
+
+	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+		cx231xx_errdev("%s queue busy\n", __func__);
+		return -EBUSY;
+	}
+
+	if (dev->stream_on && !fh->stream_on) {
+		cx231xx_errdev("%s device in use by another fh\n", __func__);
+		return -EBUSY;
+	}
+
+	/* set new image size */
+	dev->width = f->fmt.pix.width;
+	dev->height = f->fmt.pix.height;
+	dev->format = fmt;
+
+	v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+	call_all(dev, video, s_mbus_fmt, &mbus_fmt);
+	v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
+
+	return rc;
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+
+	*id = dev->norm;
+	return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	struct v4l2_mbus_framefmt mbus_fmt;
+	struct v4l2_format f;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	cx231xx_info("vidioc_s_std : 0x%x\n", (unsigned int)*norm);
+
+	dev->norm = *norm;
+
+	/* Adjusts width/height, if needed */
+	f.fmt.pix.width = dev->width;
+	f.fmt.pix.height = dev->height;
+	vidioc_try_fmt_vid_cap(file, priv, &f);
+
+	call_all(dev, core, s_std, dev->norm);
+
+	/* We need to reset basic properties in the decoder related to
+	   resolution (since a standard change effects things like the number
+	   of lines in VACT, etc) */
+	v4l2_fill_mbus_format(&mbus_fmt, &f.fmt.pix, V4L2_MBUS_FMT_FIXED);
+	call_all(dev, video, s_mbus_fmt, &mbus_fmt);
+	v4l2_fill_pix_format(&f.fmt.pix, &mbus_fmt);
+
+	/* set new image size */
+	dev->width = f.fmt.pix.width;
+	dev->height = f.fmt.pix.height;
+
+	/* do mode control overrides */
+	cx231xx_do_mode_ctrl_overrides(dev);
+
+	return 0;
+}
+
+static const char *iname[] = {
+	[CX231XX_VMUX_COMPOSITE1] = "Composite1",
+	[CX231XX_VMUX_SVIDEO]     = "S-Video",
+	[CX231XX_VMUX_TELEVISION] = "Television",
+	[CX231XX_VMUX_CABLE]      = "Cable TV",
+	[CX231XX_VMUX_DVB]        = "DVB",
+	[CX231XX_VMUX_DEBUG]      = "for debug only",
+};
+
+static int vidioc_enum_input(struct file *file, void *priv,
+			     struct v4l2_input *i)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	u32 gen_stat;
+	unsigned int ret, n;
+
+	n = i->index;
+	if (n >= MAX_CX231XX_INPUT)
+		return -EINVAL;
+	if (0 == INPUT(n)->type)
+		return -EINVAL;
+
+	i->index = n;
+	i->type = V4L2_INPUT_TYPE_CAMERA;
+
+	strcpy(i->name, iname[INPUT(n)->type]);
+
+	if ((CX231XX_VMUX_TELEVISION == INPUT(n)->type) ||
+	    (CX231XX_VMUX_CABLE == INPUT(n)->type))
+		i->type = V4L2_INPUT_TYPE_TUNER;
+
+	i->std = dev->vdev->tvnorms;
+
+	/* If they are asking about the active input, read signal status */
+	if (n == dev->video_input) {
+		ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+					    GEN_STAT, 2, &gen_stat, 4);
+		if (ret > 0) {
+			if ((gen_stat & FLD_VPRES) == 0x00)
+				i->status |= V4L2_IN_ST_NO_SIGNAL;
+			if ((gen_stat & FLD_HLOCK) == 0x00)
+				i->status |= V4L2_IN_ST_NO_H_LOCK;
+		}
+	}
+
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+
+	*i = dev->video_input;
+
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+
+	dev->mode_tv = 0;
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (i >= MAX_CX231XX_INPUT)
+		return -EINVAL;
+	if (0 == INPUT(i)->type)
+		return -EINVAL;
+
+	video_mux(dev, i);
+
+	if (INPUT(i)->type == CX231XX_VMUX_TELEVISION ||
+	    INPUT(i)->type == CX231XX_VMUX_CABLE) {
+		/* There's a tuner, so reset the standard and put it on the
+		   last known frequency (since it was probably powered down
+		   until now */
+		call_all(dev, core, s_std, dev->norm);
+	}
+
+	return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+
+	switch (a->index) {
+	case CX231XX_AMUX_VIDEO:
+		strcpy(a->name, "Television");
+		break;
+	case CX231XX_AMUX_LINE_IN:
+		strcpy(a->name, "Line In");
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	a->index = dev->ctl_ainput;
+	a->capability = V4L2_AUDCAP_STEREO;
+
+	return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int status = 0;
+
+	/* Doesn't allow manual routing */
+	if (a->index != dev->ctl_ainput)
+		return -EINVAL;
+
+	dev->ctl_ainput = INPUT(a->index)->amux;
+	status = cx231xx_set_audio_input(dev, dev->ctl_ainput);
+
+	return status;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+			    struct v4l2_queryctrl *qc)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int id = qc->id;
+	int i;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	qc->id = v4l2_ctrl_next(ctrl_classes, qc->id);
+	if (unlikely(qc->id == 0))
+		return -EINVAL;
+
+	memset(qc, 0, sizeof(*qc));
+
+	qc->id = id;
+
+	if (qc->id < V4L2_CID_BASE || qc->id >= V4L2_CID_LASTP1)
+		return -EINVAL;
+
+	for (i = 0; i < CX231XX_CTLS; i++)
+		if (cx231xx_ctls[i].v.id == qc->id)
+			break;
+
+	if (i == CX231XX_CTLS) {
+		*qc = no_ctl;
+		return 0;
+	}
+	*qc = cx231xx_ctls[i].v;
+
+	call_all(dev, core, queryctrl, qc);
+
+	if (qc->type)
+		return 0;
+	else
+		return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *ctrl)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	call_all(dev, core, g_ctrl, ctrl);
+	return rc;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *ctrl)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	call_all(dev, core, s_ctrl, ctrl);
+	return rc;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (0 != t->index)
+		return -EINVAL;
+
+	strcpy(t->name, "Tuner");
+
+	t->type = V4L2_TUNER_ANALOG_TV;
+	t->capability = V4L2_TUNER_CAP_NORM;
+	t->rangehigh = 0xffffffffUL;
+	t->signal = 0xffff;	/* LOCKED */
+
+	return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (0 != t->index)
+		return -EINVAL;
+#if 0
+	call_all(dev, tuner, s_tuner, t);
+#endif
+	return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+			      struct v4l2_frequency *f)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+
+	f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+	f->frequency = dev->ctl_freq;
+
+	call_all(dev, tuner, g_frequency, f);
+
+	return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+			      struct v4l2_frequency *f)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+	u32 if_frequency = 5400000;
+
+	cx231xx_info("Enter vidioc_s_frequency()f->frequency=%d;f->type=%d\n",
+		 f->frequency, f->type);
+	/*cx231xx_info("f->type:  1-radio 2-analogTV 3-digitalTV\n");*/
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (0 != f->tuner)
+		return -EINVAL;
+
+	if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
+		return -EINVAL;
+	if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
+		return -EINVAL;
+
+	/* set pre channel change settings in DIF first */
+	rc = cx231xx_tuner_pre_channel_change(dev);
+
+	dev->ctl_freq = f->frequency;
+	call_all(dev, tuner, s_frequency, f);
+
+	/* set post channel change settings in DIF first */
+	rc = cx231xx_tuner_post_channel_change(dev);
+
+	if (dev->tuner_type == TUNER_NXP_TDA18271) {
+		if (dev->norm & (V4L2_STD_MN | V4L2_STD_NTSC_443))
+			if_frequency = 5400000;  /*5.4MHz	*/
+		else if (dev->norm & V4L2_STD_B)
+			if_frequency = 6000000;  /*6.0MHz	*/
+		else if (dev->norm & (V4L2_STD_PAL_DK | V4L2_STD_SECAM_DK))
+			if_frequency = 6900000;  /*6.9MHz	*/
+		else if (dev->norm & V4L2_STD_GH)
+			if_frequency = 7100000;  /*7.1MHz	*/
+		else if (dev->norm & V4L2_STD_PAL_I)
+			if_frequency = 7250000;  /*7.25MHz	*/
+		else if (dev->norm & V4L2_STD_SECAM_L)
+			if_frequency = 6900000;  /*6.9MHz	*/
+		else if (dev->norm & V4L2_STD_SECAM_LC)
+			if_frequency = 1250000;  /*1.25MHz	*/
+
+		cx231xx_info("if_frequency is set to %d\n", if_frequency);
+		cx231xx_set_Colibri_For_LowIF(dev, if_frequency, 1, 1);
+
+		update_HH_register_after_set_DIF(dev);
+	}
+
+	cx231xx_info("Set New FREQUENCY to %d\n", f->frequency);
+
+	return rc;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+
+/*
+  -R, --list-registers=type=<host/i2cdrv/i2caddr>,
+				chip=<chip>[,min=<addr>,max=<addr>]
+		     dump registers from <min> to <max> [VIDIOC_DBG_G_REGISTER]
+  -r, --set-register=type=<host/i2cdrv/i2caddr>,
+				chip=<chip>,reg=<addr>,val=<val>
+		     set the register [VIDIOC_DBG_S_REGISTER]
+
+  if type == host, then <chip> is the hosts chip ID (default 0)
+  if type == i2cdrv (default), then <chip> is the I2C driver name or ID
+  if type == i2caddr, then <chip> is the 7-bit I2C address
+*/
+
+static int vidioc_g_register(struct file *file, void *priv,
+			     struct v4l2_dbg_register *reg)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int ret = 0;
+	u8 value[4] = { 0, 0, 0, 0 };
+	u32 data = 0;
+
+	switch (reg->match.type) {
+	case V4L2_CHIP_MATCH_HOST:
+		switch (reg->match.addr) {
+		case 0:	/* Cx231xx - internal registers */
+			ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
+						  (u16)reg->reg, value, 4);
+			reg->val = value[0] | value[1] << 8 |
+				   value[2] << 16 | value[3] << 24;
+			break;
+		case 1:	/* AFE - read byte */
+			ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
+						  (u16)reg->reg, 2, &data, 1);
+			reg->val = le32_to_cpu(data & 0xff);
+			break;
+		case 14: /* AFE - read dword */
+			ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
+						  (u16)reg->reg, 2, &data, 4);
+			reg->val = le32_to_cpu(data);
+			break;
+		case 2:	/* Video Block - read byte */
+			ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+						  (u16)reg->reg, 2, &data, 1);
+			reg->val = le32_to_cpu(data & 0xff);
+			break;
+		case 24: /* Video Block - read dword */
+			ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+						  (u16)reg->reg, 2, &data, 4);
+			reg->val = le32_to_cpu(data);
+			break;
+		case 3:	/* I2S block - read byte */
+			ret = cx231xx_read_i2c_data(dev,
+						    I2S_BLK_DEVICE_ADDRESS,
+						    (u16)reg->reg, 1,
+						    &data, 1);
+			reg->val = le32_to_cpu(data & 0xff);
+			break;
+		case 34: /* I2S Block - read dword */
+			ret =
+			    cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+						  (u16)reg->reg, 1, &data, 4);
+			reg->val = le32_to_cpu(data);
+			break;
+		}
+		return ret < 0 ? ret : 0;
+
+	case V4L2_CHIP_MATCH_I2C_DRIVER:
+		call_all(dev, core, g_register, reg);
+		return 0;
+	case V4L2_CHIP_MATCH_I2C_ADDR:/*for register debug*/
+		switch (reg->match.addr) {
+		case 0:	/* Cx231xx - internal registers */
+			ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
+						  (u16)reg->reg, value, 4);
+			reg->val = value[0] | value[1] << 8 |
+				   value[2] << 16 | value[3] << 24;
+
+			break;
+		case 0x600:/* AFE - read byte */
+			ret = cx231xx_read_i2c_master(dev, AFE_DEVICE_ADDRESS,
+						 (u16)reg->reg, 2,
+						 &data, 1 , 0);
+			reg->val = le32_to_cpu(data & 0xff);
+			break;
+
+		case 0x880:/* Video Block - read byte */
+			if (reg->reg < 0x0b) {
+				ret = cx231xx_read_i2c_master(dev,
+						VID_BLK_I2C_ADDRESS,
+						 (u16)reg->reg, 2,
+						 &data, 1 , 0);
+				reg->val = le32_to_cpu(data & 0xff);
+			} else {
+				ret = cx231xx_read_i2c_master(dev,
+						VID_BLK_I2C_ADDRESS,
+						 (u16)reg->reg, 2,
+						 &data, 4 , 0);
+				reg->val = le32_to_cpu(data);
+			}
+			break;
+		case 0x980:
+			ret = cx231xx_read_i2c_master(dev,
+						I2S_BLK_DEVICE_ADDRESS,
+						(u16)reg->reg, 1,
+						&data, 1 , 0);
+			reg->val = le32_to_cpu(data & 0xff);
+			break;
+		case 0x400:
+			ret =
+			    cx231xx_read_i2c_master(dev, 0x40,
+						  (u16)reg->reg, 1,
+						 &data, 1 , 0);
+			reg->val = le32_to_cpu(data & 0xff);
+			break;
+		case 0xc01:
+			ret =
+				cx231xx_read_i2c_master(dev, 0xc0,
+						(u16)reg->reg, 2,
+						 &data, 38, 1);
+			reg->val = le32_to_cpu(data);
+			break;
+		case 0x022:
+			ret =
+				cx231xx_read_i2c_master(dev, 0x02,
+						(u16)reg->reg, 1,
+						 &data, 1, 2);
+			reg->val = le32_to_cpu(data & 0xff);
+			break;
+		case 0x322:
+			ret = cx231xx_read_i2c_master(dev,
+						0x32,
+						 (u16)reg->reg, 1,
+						 &data, 4 , 2);
+				reg->val = le32_to_cpu(data);
+			break;
+		case 0x342:
+			ret = cx231xx_read_i2c_master(dev,
+						0x34,
+						 (u16)reg->reg, 1,
+						 &data, 4 , 2);
+				reg->val = le32_to_cpu(data);
+			break;
+
+		default:
+			cx231xx_info("no match device address!!\n");
+			break;
+			}
+		return ret < 0 ? ret : 0;
+		/*return -EINVAL;*/
+	default:
+		if (!v4l2_chip_match_host(&reg->match))
+			return -EINVAL;
+	}
+
+	call_all(dev, core, g_register, reg);
+
+	return ret;
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+			     struct v4l2_dbg_register *reg)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int ret = 0;
+	__le64 buf;
+	u32 value;
+	u8 data[4] = { 0, 0, 0, 0 };
+
+	buf = cpu_to_le64(reg->val);
+
+	switch (reg->match.type) {
+	case V4L2_CHIP_MATCH_HOST:
+		{
+			value = (u32) buf & 0xffffffff;
+
+			switch (reg->match.addr) {
+			case 0:	/* cx231xx internal registers */
+				data[0] = (u8) value;
+				data[1] = (u8) (value >> 8);
+				data[2] = (u8) (value >> 16);
+				data[3] = (u8) (value >> 24);
+				ret = cx231xx_write_ctrl_reg(dev,
+							   VRT_SET_REGISTER,
+							   (u16)reg->reg, data,
+							   4);
+				break;
+			case 1:	/* AFE - read byte */
+				ret = cx231xx_write_i2c_data(dev,
+							AFE_DEVICE_ADDRESS,
+							(u16)reg->reg, 2,
+							value, 1);
+				break;
+			case 14: /* AFE - read dword */
+				ret = cx231xx_write_i2c_data(dev,
+							AFE_DEVICE_ADDRESS,
+							(u16)reg->reg, 2,
+							value, 4);
+				break;
+			case 2:	/* Video Block - read byte */
+				ret =
+				    cx231xx_write_i2c_data(dev,
+							VID_BLK_I2C_ADDRESS,
+							(u16)reg->reg, 2,
+							value, 1);
+				break;
+			case 24: /* Video Block - read dword */
+				ret =
+				    cx231xx_write_i2c_data(dev,
+							VID_BLK_I2C_ADDRESS,
+							(u16)reg->reg, 2,
+							value, 4);
+				break;
+			case 3:	/* I2S block - read byte */
+				ret =
+				    cx231xx_write_i2c_data(dev,
+							I2S_BLK_DEVICE_ADDRESS,
+							(u16)reg->reg, 1,
+							value, 1);
+				break;
+			case 34: /* I2S block - read dword */
+				ret =
+				    cx231xx_write_i2c_data(dev,
+							I2S_BLK_DEVICE_ADDRESS,
+							(u16)reg->reg, 1,
+							value, 4);
+				break;
+			}
+		}
+		return ret < 0 ? ret : 0;
+	case V4L2_CHIP_MATCH_I2C_ADDR:
+		{
+			value = (u32) buf & 0xffffffff;
+
+			switch (reg->match.addr) {
+			case 0:/*cx231xx internal registers*/
+					data[0] = (u8) value;
+					data[1] = (u8) (value >> 8);
+					data[2] = (u8) (value >> 16);
+					data[3] = (u8) (value >> 24);
+					ret = cx231xx_write_ctrl_reg(dev,
+							   VRT_SET_REGISTER,
+							   (u16)reg->reg, data,
+							   4);
+					break;
+			case 0x600:/* AFE - read byte */
+					ret = cx231xx_write_i2c_master(dev,
+							AFE_DEVICE_ADDRESS,
+							(u16)reg->reg, 2,
+							value, 1 , 0);
+					break;
+
+			case 0x880:/* Video Block - read byte */
+					if (reg->reg < 0x0b)
+						cx231xx_write_i2c_master(dev,
+							VID_BLK_I2C_ADDRESS,
+							(u16)reg->reg, 2,
+							value, 1, 0);
+					else
+						cx231xx_write_i2c_master(dev,
+							VID_BLK_I2C_ADDRESS,
+							(u16)reg->reg, 2,
+							value, 4, 0);
+					break;
+			case 0x980:
+					ret =
+						cx231xx_write_i2c_master(dev,
+							I2S_BLK_DEVICE_ADDRESS,
+							(u16)reg->reg, 1,
+							value, 1, 0);
+					break;
+			case 0x400:
+					ret =
+						cx231xx_write_i2c_master(dev,
+							0x40,
+							(u16)reg->reg, 1,
+							value, 1, 0);
+					break;
+			case 0xc01:
+					ret =
+						cx231xx_write_i2c_master(dev,
+							 0xc0,
+							 (u16)reg->reg, 1,
+							 value, 1, 1);
+					break;
+
+			case 0x022:
+					ret =
+						cx231xx_write_i2c_master(dev,
+							0x02,
+							(u16)reg->reg, 1,
+							value, 1, 2);
+			case 0x322:
+					ret =
+						cx231xx_write_i2c_master(dev,
+							0x32,
+							(u16)reg->reg, 1,
+							value, 4, 2);
+					break;
+
+			case 0x342:
+					ret =
+						cx231xx_write_i2c_master(dev,
+							0x34,
+							(u16)reg->reg, 1,
+							value, 4, 2);
+					break;
+			default:
+				cx231xx_info("no match device address, "
+					"the value is %x\n", reg->match.addr);
+					break;
+
+					}
+
+		}
+	default:
+		break;
+	}
+
+	call_all(dev, core, s_register, reg);
+
+	return ret;
+}
+#endif
+
+static int vidioc_cropcap(struct file *file, void *priv,
+			  struct v4l2_cropcap *cc)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+
+	if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	cc->bounds.left = 0;
+	cc->bounds.top = 0;
+	cc->bounds.width = dev->width;
+	cc->bounds.height = dev->height;
+	cc->defrect = cc->bounds;
+	cc->pixelaspect.numerator = 54;	/* 4:3 FIXME: remove magic numbers */
+	cc->pixelaspect.denominator = 59;
+
+	return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type type)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	rc = res_get(fh);
+
+	if (likely(rc >= 0))
+		rc = videobuf_streamon(&fh->vb_vidq);
+
+	call_all(dev, video, s_stream, 1);
+
+	return rc;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type type)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
+		return -EINVAL;
+	if (type != fh->type)
+		return -EINVAL;
+
+	cx25840_call(dev, video, s_stream, 0);
+
+	videobuf_streamoff(&fh->vb_vidq);
+	res_free(fh);
+
+	return 0;
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+
+	strlcpy(cap->driver, "cx231xx", sizeof(cap->driver));
+	strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
+	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+
+	cap->capabilities = V4L2_CAP_VBI_CAPTURE |
+#if 0
+		V4L2_CAP_SLICED_VBI_CAPTURE |
+#endif
+		V4L2_CAP_VIDEO_CAPTURE	|
+		V4L2_CAP_AUDIO		|
+		V4L2_CAP_READWRITE	|
+		V4L2_CAP_STREAMING;
+
+	if (dev->tuner_type != TUNER_ABSENT)
+		cap->capabilities |= V4L2_CAP_TUNER;
+
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	if (unlikely(f->index >= ARRAY_SIZE(format)))
+		return -EINVAL;
+
+	strlcpy(f->description, format[f->index].name, sizeof(f->description));
+	f->pixelformat = format[f->index].fourcc;
+
+	return 0;
+}
+
+/* Sliced VBI ioctls */
+static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
+				       struct v4l2_format *f)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	f->fmt.sliced.service_set = 0;
+
+	call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced);
+
+	if (f->fmt.sliced.service_set == 0)
+		rc = -EINVAL;
+
+	return rc;
+}
+
+static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
+					 struct v4l2_format *f)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced);
+
+	if (f->fmt.sliced.service_set == 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+/* RAW VBI ioctls */
+
+static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	f->fmt.vbi.sampling_rate = 6750000 * 4;
+	f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
+	f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+	f->fmt.vbi.offset = 0;
+	f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ?
+	    PAL_VBI_START_LINE : NTSC_VBI_START_LINE;
+	f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ?
+	    PAL_VBI_LINES : NTSC_VBI_LINES;
+	f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ?
+	    PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263;
+	f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
+
+	return 0;
+
+}
+
+static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+
+	if (dev->vbi_stream_on && !fh->stream_on) {
+		cx231xx_errdev("%s device in use by another fh\n", __func__);
+		return -EBUSY;
+	}
+
+	f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+	f->fmt.vbi.sampling_rate = 6750000 * 4;
+	f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
+	f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+	f->fmt.vbi.offset = 0;
+	f->fmt.vbi.flags = 0;
+	f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ?
+	    PAL_VBI_START_LINE : NTSC_VBI_START_LINE;
+	f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ?
+	    PAL_VBI_LINES : NTSC_VBI_LINES;
+	f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ?
+	    PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263;
+	f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
+
+	return 0;
+
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *rb)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	return videobuf_reqbufs(&fh->vb_vidq, rb);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	return videobuf_querybuf(&fh->vb_vidq, b);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	return videobuf_qbuf(&fh->vb_vidq, b);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct cx231xx_fh *fh = priv;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
+}
+
+/* ----------------------------------------------------------- */
+/* RADIO ESPECIFIC IOCTLS                                      */
+/* ----------------------------------------------------------- */
+
+static int radio_querycap(struct file *file, void *priv,
+			  struct v4l2_capability *cap)
+{
+	struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
+
+	strlcpy(cap->driver, "cx231xx", sizeof(cap->driver));
+	strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
+	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+
+	cap->capabilities = V4L2_CAP_TUNER;
+	return 0;
+}
+
+static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+	struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
+
+	if (unlikely(t->index > 0))
+		return -EINVAL;
+
+	strcpy(t->name, "Radio");
+	t->type = V4L2_TUNER_RADIO;
+
+	call_all(dev, tuner, s_tuner, t);
+
+	return 0;
+}
+
+static int radio_enum_input(struct file *file, void *priv, struct v4l2_input *i)
+{
+	if (i->index != 0)
+		return -EINVAL;
+	strcpy(i->name, "Radio");
+	i->type = V4L2_INPUT_TYPE_TUNER;
+
+	return 0;
+}
+
+static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	if (unlikely(a->index))
+		return -EINVAL;
+
+	strcpy(a->name, "Radio");
+	return 0;
+}
+
+static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+	struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
+
+	if (0 != t->index)
+		return -EINVAL;
+
+	call_all(dev, tuner, s_tuner, t);
+
+	return 0;
+}
+
+static int radio_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+	return 0;
+}
+
+static int radio_s_input(struct file *file, void *fh, unsigned int i)
+{
+	return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+			   struct v4l2_queryctrl *c)
+{
+	int i;
+
+	if (c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1)
+		return -EINVAL;
+	if (c->id == V4L2_CID_AUDIO_MUTE) {
+		for (i = 0; i < CX231XX_CTLS; i++) {
+			if (cx231xx_ctls[i].v.id == c->id)
+				break;
+		}
+		if (i == CX231XX_CTLS)
+			return -EINVAL;
+		*c = cx231xx_ctls[i].v;
+	} else
+		*c = no_ctl;
+	return 0;
+}
+
+/*
+ * cx231xx_v4l2_open()
+ * inits the device and starts isoc transfer
+ */
+static int cx231xx_v4l2_open(struct file *filp)
+{
+	int errCode = 0, radio = 0;
+	struct video_device *vdev = video_devdata(filp);
+	struct cx231xx *dev = video_drvdata(filp);
+	struct cx231xx_fh *fh;
+	enum v4l2_buf_type fh_type = 0;
+
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_GRABBER:
+		fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		break;
+	case VFL_TYPE_VBI:
+		fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
+		break;
+	case VFL_TYPE_RADIO:
+		radio = 1;
+		break;
+	}
+
+	cx231xx_videodbg("open dev=%s type=%s users=%d\n",
+			 video_device_node_name(vdev), v4l2_type_names[fh_type],
+			 dev->users);
+
+#if 0
+	errCode = cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
+	if (errCode < 0) {
+		cx231xx_errdev
+		    ("Device locked on digital mode. Can't open analog\n");
+		return -EBUSY;
+	}
+#endif
+
+	fh = kzalloc(sizeof(struct cx231xx_fh), GFP_KERNEL);
+	if (!fh) {
+		cx231xx_errdev("cx231xx-video.c: Out of memory?!\n");
+		return -ENOMEM;
+	}
+	if (mutex_lock_interruptible(&dev->lock)) {
+		kfree(fh);
+		return -ERESTARTSYS;
+	}
+	fh->dev = dev;
+	fh->radio = radio;
+	fh->type = fh_type;
+	filp->private_data = fh;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+		dev->width = norm_maxw(dev);
+		dev->height = norm_maxh(dev);
+
+		/* Power up in Analog TV mode */
+		if (dev->board.external_av)
+			cx231xx_set_power_mode(dev,
+				 POLARIS_AVMODE_ENXTERNAL_AV);
+		else
+			cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV);
+
+#if 0
+		cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
+#endif
+
+		/* set video alternate setting */
+		cx231xx_set_video_alternate(dev);
+
+		/* Needed, since GPIO might have disabled power of
+		   some i2c device */
+		cx231xx_config_i2c(dev);
+
+		/* device needs to be initialized before isoc transfer */
+		dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
+
+	}
+	if (fh->radio) {
+		cx231xx_videodbg("video_open: setting radio device\n");
+
+		/* cx231xx_start_radio(dev); */
+
+		call_all(dev, tuner, s_radio);
+	}
+
+	dev->users++;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_video_qops,
+					    NULL, &dev->video_mode.slock,
+					    fh->type, V4L2_FIELD_INTERLACED,
+					    sizeof(struct cx231xx_buffer),
+					    fh, &dev->lock);
+	if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+		/* Set the required alternate setting  VBI interface works in
+		   Bulk mode only */
+		cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
+
+		videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_vbi_qops,
+					    NULL, &dev->vbi_mode.slock,
+					    fh->type, V4L2_FIELD_SEQ_TB,
+					    sizeof(struct cx231xx_buffer),
+					    fh, &dev->lock);
+	}
+	mutex_unlock(&dev->lock);
+
+	return errCode;
+}
+
+/*
+ * cx231xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+void cx231xx_release_analog_resources(struct cx231xx *dev)
+{
+
+	/*FIXME: I2C IR should be disconnected */
+
+	if (dev->radio_dev) {
+		if (video_is_registered(dev->radio_dev))
+			video_unregister_device(dev->radio_dev);
+		else
+			video_device_release(dev->radio_dev);
+		dev->radio_dev = NULL;
+	}
+	if (dev->vbi_dev) {
+		cx231xx_info("V4L2 device %s deregistered\n",
+			     video_device_node_name(dev->vbi_dev));
+		if (video_is_registered(dev->vbi_dev))
+			video_unregister_device(dev->vbi_dev);
+		else
+			video_device_release(dev->vbi_dev);
+		dev->vbi_dev = NULL;
+	}
+	if (dev->vdev) {
+		cx231xx_info("V4L2 device %s deregistered\n",
+			     video_device_node_name(dev->vdev));
+
+		if (dev->board.has_417)
+			cx231xx_417_unregister(dev);
+
+		if (video_is_registered(dev->vdev))
+			video_unregister_device(dev->vdev);
+		else
+			video_device_release(dev->vdev);
+		dev->vdev = NULL;
+	}
+}
+
+/*
+ * cx231xx_close()
+ * stops streaming and deallocates all resources allocated by the v4l2
+ * calls and ioctls
+ */
+static int cx231xx_close(struct file *filp)
+{
+	struct cx231xx_fh *fh = filp->private_data;
+	struct cx231xx *dev = fh->dev;
+
+	cx231xx_videodbg("users=%d\n", dev->users);
+
+	cx231xx_videodbg("users=%d\n", dev->users);
+	if (res_check(fh))
+		res_free(fh);
+
+	/*
+	 * To workaround error number=-71 on EP0 for VideoGrabber,
+	 *	 need exclude following.
+	 * FIXME: It is probably safe to remove most of these, as we're
+	 * now avoiding the alternate setting for INDEX_VANC
+	 */
+	if (!dev->board.no_alt_vanc)
+		if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+			videobuf_stop(&fh->vb_vidq);
+			videobuf_mmap_free(&fh->vb_vidq);
+
+			/* the device is already disconnect,
+			   free the remaining resources */
+			if (dev->state & DEV_DISCONNECTED) {
+				if (atomic_read(&dev->devlist_count) > 0) {
+					cx231xx_release_resources(dev);
+					fh->dev = NULL;
+					return 0;
+				}
+				return 0;
+			}
+
+			/* do this before setting alternate! */
+			cx231xx_uninit_vbi_isoc(dev);
+
+			/* set alternate 0 */
+			if (!dev->vbi_or_sliced_cc_mode)
+				cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
+			else
+				cx231xx_set_alt_setting(dev, INDEX_HANC, 0);
+
+			kfree(fh);
+			dev->users--;
+			wake_up_interruptible_nr(&dev->open, 1);
+			return 0;
+		}
+
+	dev->users--;
+	if (!dev->users) {
+		videobuf_stop(&fh->vb_vidq);
+		videobuf_mmap_free(&fh->vb_vidq);
+
+		/* the device is already disconnect,
+		   free the remaining resources */
+		if (dev->state & DEV_DISCONNECTED) {
+			cx231xx_release_resources(dev);
+			fh->dev = NULL;
+			return 0;
+		}
+
+		/* Save some power by putting tuner to sleep */
+		call_all(dev, core, s_power, 0);
+
+		/* do this before setting alternate! */
+		if (dev->USE_ISO)
+			cx231xx_uninit_isoc(dev);
+		else
+			cx231xx_uninit_bulk(dev);
+		cx231xx_set_mode(dev, CX231XX_SUSPEND);
+
+		/* set alternate 0 */
+		cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0);
+	}
+	kfree(fh);
+	wake_up_interruptible_nr(&dev->open, 1);
+	return 0;
+}
+
+static int cx231xx_v4l2_close(struct file *filp)
+{
+	struct cx231xx_fh *fh = filp->private_data;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+
+	mutex_lock(&dev->lock);
+	rc = cx231xx_close(filp);
+	mutex_unlock(&dev->lock);
+	return rc;
+}
+
+/*
+ * cx231xx_v4l2_read()
+ * will allocate buffers when called for the first time
+ */
+static ssize_t
+cx231xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
+		  loff_t *pos)
+{
+	struct cx231xx_fh *fh = filp->private_data;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if ((fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
+	    (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)) {
+		rc = res_get(fh);
+
+		if (unlikely(rc < 0))
+			return rc;
+
+		if (mutex_lock_interruptible(&dev->lock))
+			return -ERESTARTSYS;
+		rc = videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
+					    filp->f_flags & O_NONBLOCK);
+		mutex_unlock(&dev->lock);
+		return rc;
+	}
+	return 0;
+}
+
+/*
+ * cx231xx_v4l2_poll()
+ * will allocate buffers when called for the first time
+ */
+static unsigned int cx231xx_v4l2_poll(struct file *filp, poll_table *wait)
+{
+	struct cx231xx_fh *fh = filp->private_data;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	rc = res_get(fh);
+
+	if (unlikely(rc < 0))
+		return POLLERR;
+
+	if ((V4L2_BUF_TYPE_VIDEO_CAPTURE == fh->type) ||
+	    (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)) {
+		unsigned int res;
+
+		mutex_lock(&dev->lock);
+		res = videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+		mutex_unlock(&dev->lock);
+		return res;
+	}
+	return POLLERR;
+}
+
+/*
+ * cx231xx_v4l2_mmap()
+ */
+static int cx231xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct cx231xx_fh *fh = filp->private_data;
+	struct cx231xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	rc = res_get(fh);
+
+	if (unlikely(rc < 0))
+		return rc;
+
+	if (mutex_lock_interruptible(&dev->lock))
+		return -ERESTARTSYS;
+	rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+	mutex_unlock(&dev->lock);
+
+	cx231xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
+			 (unsigned long)vma->vm_start,
+			 (unsigned long)vma->vm_end -
+			 (unsigned long)vma->vm_start, rc);
+
+	return rc;
+}
+
+static const struct v4l2_file_operations cx231xx_v4l_fops = {
+	.owner   = THIS_MODULE,
+	.open    = cx231xx_v4l2_open,
+	.release = cx231xx_v4l2_close,
+	.read    = cx231xx_v4l2_read,
+	.poll    = cx231xx_v4l2_poll,
+	.mmap    = cx231xx_v4l2_mmap,
+	.unlocked_ioctl   = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+	.vidioc_querycap               = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap       = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap          = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap        = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap          = vidioc_s_fmt_vid_cap,
+	.vidioc_g_fmt_vbi_cap          = vidioc_g_fmt_vbi_cap,
+	.vidioc_try_fmt_vbi_cap        = vidioc_try_fmt_vbi_cap,
+	.vidioc_s_fmt_vbi_cap          = vidioc_try_fmt_vbi_cap,
+	.vidioc_g_audio                =  vidioc_g_audio,
+	.vidioc_s_audio                = vidioc_s_audio,
+	.vidioc_cropcap                = vidioc_cropcap,
+	.vidioc_g_fmt_sliced_vbi_cap   = vidioc_g_fmt_sliced_vbi_cap,
+	.vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
+	.vidioc_reqbufs                = vidioc_reqbufs,
+	.vidioc_querybuf               = vidioc_querybuf,
+	.vidioc_qbuf                   = vidioc_qbuf,
+	.vidioc_dqbuf                  = vidioc_dqbuf,
+	.vidioc_s_std                  = vidioc_s_std,
+	.vidioc_g_std                  = vidioc_g_std,
+	.vidioc_enum_input             = vidioc_enum_input,
+	.vidioc_g_input                = vidioc_g_input,
+	.vidioc_s_input                = vidioc_s_input,
+	.vidioc_queryctrl              = vidioc_queryctrl,
+	.vidioc_g_ctrl                 = vidioc_g_ctrl,
+	.vidioc_s_ctrl                 = vidioc_s_ctrl,
+	.vidioc_streamon               = vidioc_streamon,
+	.vidioc_streamoff              = vidioc_streamoff,
+	.vidioc_g_tuner                = vidioc_g_tuner,
+	.vidioc_s_tuner                = vidioc_s_tuner,
+	.vidioc_g_frequency            = vidioc_g_frequency,
+	.vidioc_s_frequency            = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register             = vidioc_g_register,
+	.vidioc_s_register             = vidioc_s_register,
+#endif
+};
+
+static struct video_device cx231xx_vbi_template;
+
+static const struct video_device cx231xx_video_template = {
+	.fops         = &cx231xx_v4l_fops,
+	.release      = video_device_release,
+	.ioctl_ops    = &video_ioctl_ops,
+	.tvnorms      = V4L2_STD_ALL,
+	.current_norm = V4L2_STD_PAL,
+};
+
+static const struct v4l2_file_operations radio_fops = {
+	.owner   = THIS_MODULE,
+	.open   = cx231xx_v4l2_open,
+	.release = cx231xx_v4l2_close,
+	.ioctl   = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops radio_ioctl_ops = {
+	.vidioc_querycap    = radio_querycap,
+	.vidioc_g_tuner     = radio_g_tuner,
+	.vidioc_enum_input  = radio_enum_input,
+	.vidioc_g_audio     = radio_g_audio,
+	.vidioc_s_tuner     = radio_s_tuner,
+	.vidioc_s_audio     = radio_s_audio,
+	.vidioc_s_input     = radio_s_input,
+	.vidioc_queryctrl   = radio_queryctrl,
+	.vidioc_g_ctrl      = vidioc_g_ctrl,
+	.vidioc_s_ctrl      = vidioc_s_ctrl,
+	.vidioc_g_frequency = vidioc_g_frequency,
+	.vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register  = vidioc_g_register,
+	.vidioc_s_register  = vidioc_s_register,
+#endif
+};
+
+static struct video_device cx231xx_radio_template = {
+	.name      = "cx231xx-radio",
+	.fops      = &radio_fops,
+	.ioctl_ops = &radio_ioctl_ops,
+};
+
+/******************************** usb interface ******************************/
+
+static struct video_device *cx231xx_vdev_init(struct cx231xx *dev,
+		const struct video_device
+		*template, const char *type_name)
+{
+	struct video_device *vfd;
+
+	vfd = video_device_alloc();
+	if (NULL == vfd)
+		return NULL;
+
+	*vfd = *template;
+	vfd->v4l2_dev = &dev->v4l2_dev;
+	vfd->release = video_device_release;
+	vfd->debug = video_debug;
+	vfd->lock = &dev->lock;
+
+	snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
+
+	video_set_drvdata(vfd, dev);
+	return vfd;
+}
+
+int cx231xx_register_analog_devices(struct cx231xx *dev)
+{
+	int ret;
+
+	cx231xx_info("%s: v4l2 driver version %s\n",
+		     dev->name, CX231XX_VERSION);
+
+	/* set default norm */
+	/*dev->norm = cx231xx_video_template.current_norm; */
+	dev->width = norm_maxw(dev);
+	dev->height = norm_maxh(dev);
+	dev->interlaced = 0;
+
+	/* Analog specific initialization */
+	dev->format = &format[0];
+
+	/* Set the initial input */
+	video_mux(dev, dev->video_input);
+
+	/* Audio defaults */
+	dev->mute = 1;
+	dev->volume = 0x1f;
+
+	/* enable vbi capturing */
+	/* write code here...  */
+
+	/* allocate and fill video video_device struct */
+	dev->vdev = cx231xx_vdev_init(dev, &cx231xx_video_template, "video");
+	if (!dev->vdev) {
+		cx231xx_errdev("cannot allocate video_device.\n");
+		return -ENODEV;
+	}
+
+	/* register v4l2 video video_device */
+	ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
+				    video_nr[dev->devno]);
+	if (ret) {
+		cx231xx_errdev("unable to register video device (error=%i).\n",
+			       ret);
+		return ret;
+	}
+
+	cx231xx_info("%s/0: registered device %s [v4l2]\n",
+		     dev->name, video_device_node_name(dev->vdev));
+
+	/* Initialize VBI template */
+	memcpy(&cx231xx_vbi_template, &cx231xx_video_template,
+	       sizeof(cx231xx_vbi_template));
+	strcpy(cx231xx_vbi_template.name, "cx231xx-vbi");
+
+	/* Allocate and fill vbi video_device struct */
+	dev->vbi_dev = cx231xx_vdev_init(dev, &cx231xx_vbi_template, "vbi");
+
+	/* register v4l2 vbi video_device */
+	ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+				    vbi_nr[dev->devno]);
+	if (ret < 0) {
+		cx231xx_errdev("unable to register vbi device\n");
+		return ret;
+	}
+
+	cx231xx_info("%s/0: registered device %s\n",
+		     dev->name, video_device_node_name(dev->vbi_dev));
+
+	if (cx231xx_boards[dev->model].radio.type == CX231XX_RADIO) {
+		dev->radio_dev = cx231xx_vdev_init(dev, &cx231xx_radio_template,
+						   "radio");
+		if (!dev->radio_dev) {
+			cx231xx_errdev("cannot allocate video_device.\n");
+			return -ENODEV;
+		}
+		ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+					    radio_nr[dev->devno]);
+		if (ret < 0) {
+			cx231xx_errdev("can't register radio device\n");
+			return ret;
+		}
+		cx231xx_info("Registered radio device as %s\n",
+			     video_device_node_name(dev->radio_dev));
+	}
+
+	cx231xx_info("V4L2 device registered as %s and %s\n",
+		     video_device_node_name(dev->vdev),
+		     video_device_node_name(dev->vbi_dev));
+
+	return 0;
+}
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
new file mode 100644
index 0000000..a89d020
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -0,0 +1,1012 @@
+/*
+   cx231xx.h - driver for Conexant Cx23100/101/102 USB video capture devices
+
+   Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+	Based on em28xx driver
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _CX231XX_H
+#define _CX231XX_H
+
+#include <linux/videodev2.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+
+#include <media/cx2341x.h>
+
+#include <media/videobuf-vmalloc.h>
+#include <media/v4l2-device.h>
+#include <media/rc-core.h>
+#include <media/ir-kbd-i2c.h>
+#include <media/videobuf-dvb.h>
+
+#include "cx231xx-reg.h"
+#include "cx231xx-pcb-cfg.h"
+#include "cx231xx-conf-reg.h"
+
+#define DRIVER_NAME                     "cx231xx"
+#define PWR_SLEEP_INTERVAL              10
+
+/* I2C addresses for control block in Cx231xx */
+#define     AFE_DEVICE_ADDRESS		0x60
+#define     I2S_BLK_DEVICE_ADDRESS	0x98
+#define     VID_BLK_I2C_ADDRESS		0x88
+#define     VERVE_I2C_ADDRESS           0x40
+#define     DIF_USE_BASEBAND            0xFFFFFFFF
+
+/* Boards supported by driver */
+#define CX231XX_BOARD_UNKNOWN		    0
+#define CX231XX_BOARD_CNXT_CARRAERA	1
+#define CX231XX_BOARD_CNXT_SHELBY	2
+#define CX231XX_BOARD_CNXT_RDE_253S	3
+#define CX231XX_BOARD_CNXT_RDU_253S	4
+#define CX231XX_BOARD_CNXT_VIDEO_GRABBER	5
+#define CX231XX_BOARD_CNXT_RDE_250	6
+#define CX231XX_BOARD_CNXT_RDU_250	7
+#define CX231XX_BOARD_HAUPPAUGE_EXETER  8
+#define CX231XX_BOARD_HAUPPAUGE_USBLIVE2 9
+#define CX231XX_BOARD_PV_PLAYTV_USB_HYBRID 10
+#define CX231XX_BOARD_PV_XCAPTURE_USB 11
+#define CX231XX_BOARD_KWORLD_UB430_USB_HYBRID 12
+#define CX231XX_BOARD_ICONBIT_U100 13
+#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL 14
+#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC 15
+
+/* Limits minimum and default number of buffers */
+#define CX231XX_MIN_BUF                 4
+#define CX231XX_DEF_BUF                 12
+#define CX231XX_DEF_VBI_BUF             6
+
+#define VBI_LINE_COUNT                  17
+#define VBI_LINE_LENGTH                 1440
+
+/*Limits the max URB message size */
+#define URB_MAX_CTRL_SIZE               80
+
+/* Params for validated field */
+#define CX231XX_BOARD_NOT_VALIDATED     1
+#define CX231XX_BOARD_VALIDATED		0
+
+/* maximum number of cx231xx boards */
+#define CX231XX_MAXBOARDS               8
+
+/* maximum number of frames that can be queued */
+#define CX231XX_NUM_FRAMES              5
+
+/* number of buffers for isoc transfers */
+#define CX231XX_NUM_BUFS                8
+
+/* number of packets for each buffer
+   windows requests only 40 packets .. so we better do the same
+   this is what I found out for all alternate numbers there!
+ */
+#define CX231XX_NUM_PACKETS             40
+
+/* default alternate; 0 means choose the best */
+#define CX231XX_PINOUT                  0
+
+#define CX231XX_INTERLACED_DEFAULT      1
+
+/* time to wait when stopping the isoc transfer */
+#define CX231XX_URB_TIMEOUT		\
+		msecs_to_jiffies(CX231XX_NUM_BUFS * CX231XX_NUM_PACKETS)
+
+#define CX231xx_NORMS (\
+	V4L2_STD_NTSC_M |  V4L2_STD_NTSC_M_JP |  V4L2_STD_NTSC_443 | \
+	V4L2_STD_PAL_BG |  V4L2_STD_PAL_DK    |  V4L2_STD_PAL_I    | \
+	V4L2_STD_PAL_M  |  V4L2_STD_PAL_N     |  V4L2_STD_PAL_Nc   | \
+	V4L2_STD_PAL_60 |  V4L2_STD_SECAM_L   |  V4L2_STD_SECAM_DK)
+
+#define SLEEP_S5H1432    30
+#define CX23417_OSC_EN   8
+#define CX23417_RESET    9
+
+struct cx23417_fmt {
+	char  *name;
+	u32   fourcc;          /* v4l2 format id */
+	int   depth;
+	int   flags;
+	u32   cxformat;
+};
+enum cx231xx_mode {
+	CX231XX_SUSPEND,
+	CX231XX_ANALOG_MODE,
+	CX231XX_DIGITAL_MODE,
+};
+
+enum cx231xx_std_mode {
+	CX231XX_TV_AIR = 0,
+	CX231XX_TV_CABLE
+};
+
+enum cx231xx_stream_state {
+	STREAM_OFF,
+	STREAM_INTERRUPT,
+	STREAM_ON,
+};
+
+struct cx231xx;
+
+struct cx231xx_isoc_ctl {
+	/* max packet size of isoc transaction */
+	int max_pkt_size;
+
+	/* number of allocated urbs */
+	int num_bufs;
+
+	/* urb for isoc transfers */
+	struct urb **urb;
+
+	/* transfer buffers for isoc transfer */
+	char **transfer_buffer;
+
+	/* Last buffer command and region */
+	u8 cmd;
+	int pos, size, pktsize;
+
+	/* Last field: ODD or EVEN? */
+	int field;
+
+	/* Stores incomplete commands */
+	u32 tmp_buf;
+	int tmp_buf_len;
+
+	/* Stores already requested buffers */
+	struct cx231xx_buffer *buf;
+
+	/* Stores the number of received fields */
+	int nfields;
+
+	/* isoc urb callback */
+	int (*isoc_copy) (struct cx231xx *dev, struct urb *urb);
+};
+
+struct cx231xx_bulk_ctl {
+	/* max packet size of bulk transaction */
+	int max_pkt_size;
+
+	/* number of allocated urbs */
+	int num_bufs;
+
+	/* urb for bulk transfers */
+	struct urb **urb;
+
+	/* transfer buffers for bulk transfer */
+	char **transfer_buffer;
+
+	/* Last buffer command and region */
+	u8 cmd;
+	int pos, size, pktsize;
+
+	/* Last field: ODD or EVEN? */
+	int field;
+
+	/* Stores incomplete commands */
+	u32 tmp_buf;
+	int tmp_buf_len;
+
+	/* Stores already requested buffers */
+	struct cx231xx_buffer *buf;
+
+	/* Stores the number of received fields */
+	int nfields;
+
+	/* bulk urb callback */
+	int (*bulk_copy) (struct cx231xx *dev, struct urb *urb);
+};
+
+struct cx231xx_fmt {
+	char *name;
+	u32 fourcc;		/* v4l2 format id */
+	int depth;
+	int reg;
+};
+
+/* buffer for one video frame */
+struct cx231xx_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+
+	struct list_head frame;
+	int top_field;
+	int receiving;
+};
+
+enum ps_package_head {
+	CX231XX_NEED_ADD_PS_PACKAGE_HEAD = 0,
+	CX231XX_NONEED_PS_PACKAGE_HEAD
+};
+
+struct cx231xx_dmaqueue {
+	struct list_head active;
+	struct list_head queued;
+
+	wait_queue_head_t wq;
+
+	/* Counters to control buffer fill */
+	int pos;
+	u8 is_partial_line;
+	u8 partial_buf[8];
+	u8 last_sav;
+	int current_field;
+	u32 bytes_left_in_line;
+	u32 lines_completed;
+	u8 field1_done;
+	u32 lines_per_field;
+
+	/*Mpeg2 control buffer*/
+	u8 *p_left_data;
+	u32 left_data_count;
+	u8 mpeg_buffer_done;
+	u32 mpeg_buffer_completed;
+	enum ps_package_head add_ps_package_head;
+	char ps_head[10];
+};
+
+/* inputs */
+
+#define MAX_CX231XX_INPUT               4
+
+enum cx231xx_itype {
+	CX231XX_VMUX_COMPOSITE1 = 1,
+	CX231XX_VMUX_SVIDEO,
+	CX231XX_VMUX_TELEVISION,
+	CX231XX_VMUX_CABLE,
+	CX231XX_RADIO,
+	CX231XX_VMUX_DVB,
+	CX231XX_VMUX_DEBUG
+};
+
+enum cx231xx_v_input {
+	CX231XX_VIN_1_1 = 0x1,
+	CX231XX_VIN_2_1,
+	CX231XX_VIN_3_1,
+	CX231XX_VIN_4_1,
+	CX231XX_VIN_1_2 = 0x01,
+	CX231XX_VIN_2_2,
+	CX231XX_VIN_3_2,
+	CX231XX_VIN_1_3 = 0x1,
+	CX231XX_VIN_2_3,
+	CX231XX_VIN_3_3,
+};
+
+/* cx231xx has two audio inputs: tuner and line in */
+enum cx231xx_amux {
+	/* This is the only entry for cx231xx tuner input */
+	CX231XX_AMUX_VIDEO,	/* cx231xx tuner */
+	CX231XX_AMUX_LINE_IN,	/* Line In */
+};
+
+struct cx231xx_reg_seq {
+	unsigned char bit;
+	unsigned char val;
+	int sleep;
+};
+
+struct cx231xx_input {
+	enum cx231xx_itype type;
+	unsigned int vmux;
+	enum cx231xx_amux amux;
+	struct cx231xx_reg_seq *gpio;
+};
+
+#define INPUT(nr) (&cx231xx_boards[dev->model].input[nr])
+
+enum cx231xx_decoder {
+	CX231XX_NODECODER,
+	CX231XX_AVDECODER
+};
+
+enum CX231XX_I2C_MASTER_PORT {
+	I2C_0 = 0,
+	I2C_1 = 1,
+	I2C_2 = 2,
+	I2C_3 = 3
+};
+
+struct cx231xx_board {
+	char *name;
+	int vchannels;
+	int tuner_type;
+	int tuner_addr;
+	v4l2_std_id norm;	/* tv norm */
+
+	/* demod related */
+	int demod_addr;
+	u8 demod_xfer_mode;	/* 0 - Serial; 1 - parallel */
+
+	/* GPIO Pins */
+	struct cx231xx_reg_seq *dvb_gpio;
+	struct cx231xx_reg_seq *suspend_gpio;
+	struct cx231xx_reg_seq *tuner_gpio;
+		/* Negative means don't use it */
+	s8 tuner_sif_gpio;
+	s8 tuner_scl_gpio;
+	s8 tuner_sda_gpio;
+
+	/* PIN ctrl */
+	u32 ctl_pin_status_mask;
+	u8 agc_analog_digital_select_gpio;
+	u32 gpio_pin_status_mask;
+
+	/* i2c masters */
+	u8 tuner_i2c_master;
+	u8 demod_i2c_master;
+	u8 ir_i2c_master;
+
+	/* for devices with I2C chips for IR */
+	char *rc_map_name;
+
+	unsigned int max_range_640_480:1;
+	unsigned int has_dvb:1;
+	unsigned int has_417:1;
+	unsigned int valid:1;
+	unsigned int no_alt_vanc:1;
+	unsigned int external_av:1;
+	unsigned int dont_use_port_3:1;
+
+	unsigned char xclk, i2c_speed;
+
+	enum cx231xx_decoder decoder;
+	int output_mode;
+
+	struct cx231xx_input input[MAX_CX231XX_INPUT];
+	struct cx231xx_input radio;
+	struct rc_map *ir_codes;
+};
+
+/* device states */
+enum cx231xx_dev_state {
+	DEV_INITIALIZED = 0x01,
+	DEV_DISCONNECTED = 0x02,
+};
+
+enum AFE_MODE {
+	AFE_MODE_LOW_IF,
+	AFE_MODE_BASEBAND,
+	AFE_MODE_EU_HI_IF,
+	AFE_MODE_US_HI_IF,
+	AFE_MODE_JAPAN_HI_IF
+};
+
+enum AUDIO_INPUT {
+	AUDIO_INPUT_MUTE,
+	AUDIO_INPUT_LINE,
+	AUDIO_INPUT_TUNER_TV,
+	AUDIO_INPUT_SPDIF,
+	AUDIO_INPUT_TUNER_FM
+};
+
+#define CX231XX_AUDIO_BUFS              5
+#define CX231XX_NUM_AUDIO_PACKETS       16
+#define CX231XX_ISO_NUM_AUDIO_PACKETS	64
+
+/* cx231xx extensions */
+#define CX231XX_AUDIO                   0x10
+#define CX231XX_DVB                     0x20
+
+struct cx231xx_audio {
+	char name[50];
+	char *transfer_buffer[CX231XX_AUDIO_BUFS];
+	struct urb *urb[CX231XX_AUDIO_BUFS];
+	struct usb_device *udev;
+	unsigned int capture_transfer_done;
+	struct snd_pcm_substream *capture_pcm_substream;
+
+	unsigned int hwptr_done_capture;
+	struct snd_card *sndcard;
+
+	int users, shutdown;
+	/* locks */
+	spinlock_t slock;
+
+	int alt;		/* alternate */
+	int max_pkt_size;	/* max packet size of isoc transaction */
+	int num_alt;		/* Number of alternative settings */
+	unsigned int *alt_max_pkt_size;	/* array of wMaxPacketSize */
+	u16 end_point_addr;
+};
+
+struct cx231xx;
+
+struct cx231xx_fh {
+	struct cx231xx *dev;
+	unsigned int stream_on:1;	/* Locks streams */
+	int radio;
+
+	struct videobuf_queue vb_vidq;
+
+	enum v4l2_buf_type type;
+
+
+
+/*following is copyed from cx23885.h*/
+	u32                        resources;
+
+	/* video overlay */
+	struct v4l2_window         win;
+	struct v4l2_clip           *clips;
+	unsigned int               nclips;
+
+	/* video capture */
+	struct cx23417_fmt         *fmt;
+	unsigned int               width, height;
+
+	/* vbi capture */
+	struct videobuf_queue      vidq;
+	struct videobuf_queue      vbiq;
+
+	/* MPEG Encoder specifics ONLY */
+
+	atomic_t                   v4l_reading;
+};
+
+/*****************************************************************/
+/* set/get i2c */
+/* 00--1Mb/s, 01-400kb/s, 10--100kb/s, 11--5Mb/s */
+#define I2C_SPEED_1M            0x0
+#define I2C_SPEED_400K          0x1
+#define I2C_SPEED_100K          0x2
+#define I2C_SPEED_5M            0x3
+
+/* 0-- STOP transaction */
+#define I2C_STOP                0x0
+/* 1-- do not transmit STOP at end of transaction */
+#define I2C_NOSTOP              0x1
+/* 1--allow slave to insert clock wait states */
+#define I2C_SYNC                0x1
+
+struct cx231xx_i2c {
+	struct cx231xx *dev;
+
+	int nr;
+
+	/* i2c i/o */
+	struct i2c_adapter i2c_adap;
+	struct i2c_client i2c_client;
+	u32 i2c_rc;
+
+	/* different settings for each bus */
+	u8 i2c_period;
+	u8 i2c_nostop;
+	u8 i2c_reserve;
+};
+
+struct cx231xx_i2c_xfer_data {
+	u8 dev_addr;
+	u8 direction;		/* 1 - IN, 0 - OUT */
+	u8 saddr_len;		/* sub address len */
+	u16 saddr_dat;		/* sub addr data */
+	u8 buf_size;		/* buffer size */
+	u8 *p_buffer;		/* pointer to the buffer */
+};
+
+struct VENDOR_REQUEST_IN {
+	u8 bRequest;
+	u16 wValue;
+	u16 wIndex;
+	u16 wLength;
+	u8 direction;
+	u8 bData;
+	u8 *pBuff;
+};
+
+struct cx231xx_tvnorm {
+	char		*name;
+	v4l2_std_id	id;
+	u32		cxiformat;
+	u32		cxoformat;
+};
+
+struct cx231xx_ctrl {
+	struct v4l2_queryctrl v;
+	u32 off;
+	u32 reg;
+	u32 mask;
+	u32 shift;
+};
+
+enum TRANSFER_TYPE {
+	Raw_Video = 0,
+	Audio,
+	Vbi,			/* VANC */
+	Sliced_cc,		/* HANC */
+	TS1_serial_mode,
+	TS2,
+	TS1_parallel_mode
+} ;
+
+struct cx231xx_video_mode {
+	/* Isoc control struct */
+	struct cx231xx_dmaqueue vidq;
+	struct cx231xx_isoc_ctl isoc_ctl;
+	struct cx231xx_bulk_ctl bulk_ctl;
+	/* locks */
+	spinlock_t slock;
+
+	/* usb transfer */
+	int alt;		/* alternate */
+	int max_pkt_size;	/* max packet size of isoc transaction */
+	int num_alt;		/* Number of alternative settings */
+	unsigned int *alt_max_pkt_size;	/* array of wMaxPacketSize */
+	u16 end_point_addr;
+};
+/*
+struct cx23885_dmaqueue {
+	struct list_head       active;
+	struct list_head       queued;
+	struct timer_list      timeout;
+	struct btcx_riscmem    stopper;
+	u32                    count;
+};
+*/
+struct cx231xx_tsport {
+	struct cx231xx *dev;
+
+	int                        nr;
+	int                        sram_chno;
+
+	struct videobuf_dvb_frontends frontends;
+
+	/* dma queues */
+
+	u32                        ts_packet_size;
+	u32                        ts_packet_count;
+
+	int                        width;
+	int                        height;
+
+	/* locks */
+	spinlock_t                 slock;
+
+	/* registers */
+	u32                        reg_gpcnt;
+	u32                        reg_gpcnt_ctl;
+	u32                        reg_dma_ctl;
+	u32                        reg_lngth;
+	u32                        reg_hw_sop_ctrl;
+	u32                        reg_gen_ctrl;
+	u32                        reg_bd_pkt_status;
+	u32                        reg_sop_status;
+	u32                        reg_fifo_ovfl_stat;
+	u32                        reg_vld_misc;
+	u32                        reg_ts_clk_en;
+	u32                        reg_ts_int_msk;
+	u32                        reg_ts_int_stat;
+	u32                        reg_src_sel;
+
+	/* Default register vals */
+	int                        pci_irqmask;
+	u32                        dma_ctl_val;
+	u32                        ts_int_msk_val;
+	u32                        gen_ctrl_val;
+	u32                        ts_clk_en_val;
+	u32                        src_sel_val;
+	u32                        vld_misc_val;
+	u32                        hw_sop_ctrl_val;
+
+	/* Allow a single tsport to have multiple frontends */
+	u32                        num_frontends;
+	void                       *port_priv;
+};
+
+/* main device struct */
+struct cx231xx {
+	/* generic device properties */
+	char name[30];		/* name (including minor) of the device */
+	int model;		/* index in the device_data struct */
+	int devno;		/* marks the number of this device */
+
+	struct cx231xx_board board;
+
+	/* For I2C IR support */
+	struct IR_i2c_init_data    init_data;
+	struct i2c_client          *ir_i2c_client;
+
+	unsigned int stream_on:1;	/* Locks streams */
+	unsigned int vbi_stream_on:1;	/* Locks streams for VBI */
+	unsigned int has_audio_class:1;
+	unsigned int has_alsa_audio:1;
+
+	struct cx231xx_fmt *format;
+
+	struct v4l2_device v4l2_dev;
+	struct v4l2_subdev *sd_cx25840;
+	struct v4l2_subdev *sd_tuner;
+
+	struct work_struct wq_trigger;		/* Trigger to start/stop audio for alsa module */
+	atomic_t	   stream_started;	/* stream should be running if true */
+
+	struct list_head devlist;
+
+	int tuner_type;		/* type of the tuner */
+	int tuner_addr;		/* tuner address */
+
+	/* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
+	struct cx231xx_i2c i2c_bus[3];
+	unsigned int xc_fw_load_done:1;
+	/* locks */
+	struct mutex gpio_i2c_lock;
+	struct mutex i2c_lock;
+
+	/* video for linux */
+	int users;		/* user count for exclusive use */
+	struct video_device *vdev;	/* video for linux device struct */
+	v4l2_std_id norm;	/* selected tv norm */
+	int ctl_freq;		/* selected frequency */
+	unsigned int ctl_ainput;	/* selected audio input */
+	int mute;
+	int volume;
+
+	/* frame properties */
+	int width;		/* current frame width */
+	int height;		/* current frame height */
+	int interlaced;		/* 1=interlace fileds, 0=just top fileds */
+
+	struct cx231xx_audio adev;
+
+	/* states */
+	enum cx231xx_dev_state state;
+
+	struct work_struct request_module_wk;
+
+	/* locks */
+	struct mutex lock;
+	struct mutex ctrl_urb_lock;	/* protects urb_buf */
+	struct list_head inqueue, outqueue;
+	wait_queue_head_t open, wait_frame, wait_stream;
+	struct video_device *vbi_dev;
+	struct video_device *radio_dev;
+
+	unsigned char eedata[256];
+
+	struct cx231xx_video_mode video_mode;
+	struct cx231xx_video_mode vbi_mode;
+	struct cx231xx_video_mode sliced_cc_mode;
+	struct cx231xx_video_mode ts1_mode;
+
+	atomic_t devlist_count;
+
+	struct usb_device *udev;	/* the usb device */
+	char urb_buf[URB_MAX_CTRL_SIZE];	/* urb control msg buffer */
+
+	/* helper funcs that call usb_control_msg */
+	int (*cx231xx_read_ctrl_reg) (struct cx231xx *dev, u8 req, u16 reg,
+				      char *buf, int len);
+	int (*cx231xx_write_ctrl_reg) (struct cx231xx *dev, u8 req, u16 reg,
+				       char *buf, int len);
+	int (*cx231xx_send_usb_command) (struct cx231xx_i2c *i2c_bus,
+				struct cx231xx_i2c_xfer_data *req_data);
+	int (*cx231xx_gpio_i2c_read) (struct cx231xx *dev, u8 dev_addr,
+				      u8 *buf, u8 len);
+	int (*cx231xx_gpio_i2c_write) (struct cx231xx *dev, u8 dev_addr,
+				       u8 *buf, u8 len);
+
+	int (*cx231xx_set_analog_freq) (struct cx231xx *dev, u32 freq);
+	int (*cx231xx_reset_analog_tuner) (struct cx231xx *dev);
+
+	enum cx231xx_mode mode;
+
+	struct cx231xx_dvb *dvb;
+
+	/* Cx231xx supported PCB config's */
+	struct pcb_config current_pcb_config;
+	u8 current_scenario_idx;
+	u8 interface_count;
+	u8 max_iad_interface_count;
+
+	/* GPIO related register direction and values */
+	u32 gpio_dir;
+	u32 gpio_val;
+
+	/* Power Modes */
+	int power_mode;
+
+	/* afe parameters */
+	enum AFE_MODE afe_mode;
+	u32 afe_ref_count;
+
+	/* video related parameters */
+	u32 video_input;
+	u32 active_mode;
+	u8 vbi_or_sliced_cc_mode;	/* 0 - vbi ; 1 - sliced cc mode */
+	enum cx231xx_std_mode std_mode;	/* 0 - Air; 1 - cable */
+
+	/*mode: digital=1 or analog=0*/
+	u8 mode_tv;
+
+	u8 USE_ISO;
+	struct cx231xx_tvnorm      encodernorm;
+	struct cx231xx_tsport      ts1, ts2;
+	struct cx2341x_mpeg_params mpeg_params;
+	struct video_device        *v4l_device;
+	atomic_t                   v4l_reader_count;
+	u32                        freq;
+	unsigned int               input;
+	u32                        cx23417_mailbox;
+	u32                        __iomem *lmmio;
+	u8                         __iomem *bmmio;
+};
+
+extern struct list_head cx231xx_devlist;
+
+#define cx25840_call(cx231xx, o, f, args...) \
+	v4l2_subdev_call(cx231xx->sd_cx25840, o, f, ##args)
+#define tuner_call(cx231xx, o, f, args...) \
+	v4l2_subdev_call(cx231xx->sd_tuner, o, f, ##args)
+#define call_all(dev, o, f, args...) \
+	v4l2_device_call_until_err(&dev->v4l2_dev, 0, o, f, ##args)
+
+struct cx231xx_ops {
+	struct list_head next;
+	char *name;
+	int id;
+	int (*init) (struct cx231xx *);
+	int (*fini) (struct cx231xx *);
+};
+
+/* call back functions in dvb module */
+int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq);
+int cx231xx_reset_analog_tuner(struct cx231xx *dev);
+
+/* Provided by cx231xx-i2c.c */
+void cx231xx_do_i2c_scan(struct cx231xx *dev, struct i2c_client *c);
+int cx231xx_i2c_register(struct cx231xx_i2c *bus);
+int cx231xx_i2c_unregister(struct cx231xx_i2c *bus);
+
+/* Internal block control functions */
+int cx231xx_read_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr,
+		 u8 saddr_len, u32 *data, u8 data_len, int master);
+int cx231xx_write_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr,
+		 u8 saddr_len, u32 data, u8 data_len, int master);
+int cx231xx_read_i2c_data(struct cx231xx *dev, u8 dev_addr,
+			  u16 saddr, u8 saddr_len, u32 *data, u8 data_len);
+int cx231xx_write_i2c_data(struct cx231xx *dev, u8 dev_addr,
+			   u16 saddr, u8 saddr_len, u32 data, u8 data_len);
+int cx231xx_reg_mask_write(struct cx231xx *dev, u8 dev_addr, u8 size,
+			   u16 register_address, u8 bit_start, u8 bit_end,
+			   u32 value);
+int cx231xx_read_modify_write_i2c_dword(struct cx231xx *dev, u8 dev_addr,
+					u16 saddr, u32 mask, u32 value);
+u32 cx231xx_set_field(u32 field_mask, u32 data);
+
+/*verve r/w*/
+void initGPIO(struct cx231xx *dev);
+void uninitGPIO(struct cx231xx *dev);
+/* afe related functions */
+int cx231xx_afe_init_super_block(struct cx231xx *dev, u32 ref_count);
+int cx231xx_afe_init_channels(struct cx231xx *dev);
+int cx231xx_afe_setup_AFE_for_baseband(struct cx231xx *dev);
+int cx231xx_afe_set_input_mux(struct cx231xx *dev, u32 input_mux);
+int cx231xx_afe_set_mode(struct cx231xx *dev, enum AFE_MODE mode);
+int cx231xx_afe_update_power_control(struct cx231xx *dev,
+					enum AV_MODE avmode);
+int cx231xx_afe_adjust_ref_count(struct cx231xx *dev, u32 video_input);
+
+/* i2s block related functions */
+int cx231xx_i2s_blk_initialize(struct cx231xx *dev);
+int cx231xx_i2s_blk_update_power_control(struct cx231xx *dev,
+					enum AV_MODE avmode);
+int cx231xx_i2s_blk_set_audio_input(struct cx231xx *dev, u8 audio_input);
+
+/* DIF related functions */
+int cx231xx_dif_configure_C2HH_for_low_IF(struct cx231xx *dev, u32 mode,
+					  u32 function_mode, u32 standard);
+void cx231xx_set_Colibri_For_LowIF(struct cx231xx *dev, u32 if_freq,
+					 u8 spectral_invert, u32 mode);
+u32 cx231xx_Get_Colibri_CarrierOffset(u32 mode, u32 standerd);
+void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq,
+					 u8 spectral_invert, u32 mode);
+void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev);
+void reset_s5h1432_demod(struct cx231xx *dev);
+void cx231xx_dump_HH_reg(struct cx231xx *dev);
+void update_HH_register_after_set_DIF(struct cx231xx *dev);
+void cx231xx_dump_SC_reg(struct cx231xx *dev);
+
+
+
+int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard);
+int cx231xx_tuner_pre_channel_change(struct cx231xx *dev);
+int cx231xx_tuner_post_channel_change(struct cx231xx *dev);
+
+/* video parser functions */
+u8 cx231xx_find_next_SAV_EAV(u8 *p_buffer, u32 buffer_size,
+			     u32 *p_bytes_used);
+u8 cx231xx_find_boundary_SAV_EAV(u8 *p_buffer, u8 *partial_buf,
+				 u32 *p_bytes_used);
+int cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+		    u8 *p_buffer, u32 bytes_to_copy);
+void cx231xx_reset_video_buffer(struct cx231xx *dev,
+				struct cx231xx_dmaqueue *dma_q);
+u8 cx231xx_is_buffer_done(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q);
+u32 cx231xx_copy_video_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+			    u8 *p_line, u32 length, int field_number);
+u32 cx231xx_get_video_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+			   u8 sav_eav, u8 *p_buffer, u32 buffer_size);
+void cx231xx_swab(u16 *from, u16 *to, u16 len);
+
+/* Provided by cx231xx-core.c */
+
+u32 cx231xx_request_buffers(struct cx231xx *dev, u32 count);
+void cx231xx_queue_unusedframes(struct cx231xx *dev);
+void cx231xx_release_buffers(struct cx231xx *dev);
+
+/* read from control pipe */
+int cx231xx_read_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg,
+			  char *buf, int len);
+
+/* write to control pipe */
+int cx231xx_write_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg,
+			   char *buf, int len);
+int cx231xx_mode_register(struct cx231xx *dev, u16 address, u32 mode);
+
+int cx231xx_send_vendor_cmd(struct cx231xx *dev,
+				struct VENDOR_REQUEST_IN *ven_req);
+int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus,
+				struct cx231xx_i2c_xfer_data *req_data);
+
+/* Gpio related functions */
+int cx231xx_send_gpio_cmd(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val,
+			  u8 len, u8 request, u8 direction);
+int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val);
+int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val);
+int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value);
+int cx231xx_set_gpio_direction(struct cx231xx *dev, int pin_number,
+			       int pin_value);
+
+int cx231xx_gpio_i2c_start(struct cx231xx *dev);
+int cx231xx_gpio_i2c_end(struct cx231xx *dev);
+int cx231xx_gpio_i2c_write_byte(struct cx231xx *dev, u8 data);
+int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 *buf);
+int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev);
+int cx231xx_gpio_i2c_write_ack(struct cx231xx *dev);
+int cx231xx_gpio_i2c_write_nak(struct cx231xx *dev);
+
+int cx231xx_gpio_i2c_read(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len);
+int cx231xx_gpio_i2c_write(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len);
+
+/* audio related functions */
+int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
+				    enum AUDIO_INPUT audio_input);
+
+int cx231xx_capture_start(struct cx231xx *dev, int start, u8 media_type);
+int cx231xx_set_video_alternate(struct cx231xx *dev);
+int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt);
+int is_fw_load(struct cx231xx *dev);
+int cx231xx_check_fw(struct cx231xx *dev);
+int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
+		      int num_bufs, int max_pkt_size,
+		      int (*isoc_copy) (struct cx231xx *dev,
+					struct urb *urb));
+int cx231xx_init_bulk(struct cx231xx *dev, int max_packets,
+		      int num_bufs, int max_pkt_size,
+		      int (*bulk_copy) (struct cx231xx *dev,
+					struct urb *urb));
+void cx231xx_stop_TS1(struct cx231xx *dev);
+void cx231xx_start_TS1(struct cx231xx *dev);
+void cx231xx_uninit_isoc(struct cx231xx *dev);
+void cx231xx_uninit_bulk(struct cx231xx *dev);
+int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode);
+int cx231xx_unmute_audio(struct cx231xx *dev);
+int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size);
+void cx231xx_disable656(struct cx231xx *dev);
+void cx231xx_enable656(struct cx231xx *dev);
+int cx231xx_demod_reset(struct cx231xx *dev);
+int cx231xx_gpio_set(struct cx231xx *dev, struct cx231xx_reg_seq *gpio);
+
+/* Device list functions */
+void cx231xx_release_resources(struct cx231xx *dev);
+void cx231xx_release_analog_resources(struct cx231xx *dev);
+int cx231xx_register_analog_devices(struct cx231xx *dev);
+void cx231xx_remove_from_devlist(struct cx231xx *dev);
+void cx231xx_add_into_devlist(struct cx231xx *dev);
+void cx231xx_init_extension(struct cx231xx *dev);
+void cx231xx_close_extension(struct cx231xx *dev);
+
+/* hardware init functions */
+int cx231xx_dev_init(struct cx231xx *dev);
+void cx231xx_dev_uninit(struct cx231xx *dev);
+void cx231xx_config_i2c(struct cx231xx *dev);
+int cx231xx_config(struct cx231xx *dev);
+
+/* Stream control functions */
+int cx231xx_start_stream(struct cx231xx *dev, u32 ep_mask);
+int cx231xx_stop_stream(struct cx231xx *dev, u32 ep_mask);
+
+int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type);
+
+/* Power control functions */
+int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode);
+int cx231xx_power_suspend(struct cx231xx *dev);
+
+/* chip specific control functions */
+int cx231xx_init_ctrl_pin_status(struct cx231xx *dev);
+int cx231xx_set_agc_analog_digital_mux_select(struct cx231xx *dev,
+					      u8 analog_or_digital);
+int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3);
+
+/* video audio decoder related functions */
+void video_mux(struct cx231xx *dev, int index);
+int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input);
+int cx231xx_set_decoder_video_input(struct cx231xx *dev, u8 pin_type, u8 input);
+int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev);
+int cx231xx_set_audio_input(struct cx231xx *dev, u8 input);
+
+/* Provided by cx231xx-video.c */
+int cx231xx_register_extension(struct cx231xx_ops *dev);
+void cx231xx_unregister_extension(struct cx231xx_ops *dev);
+void cx231xx_init_extension(struct cx231xx *dev);
+void cx231xx_close_extension(struct cx231xx *dev);
+
+/* Provided by cx231xx-cards.c */
+extern void cx231xx_pre_card_setup(struct cx231xx *dev);
+extern void cx231xx_card_setup(struct cx231xx *dev);
+extern struct cx231xx_board cx231xx_boards[];
+extern struct usb_device_id cx231xx_id_table[];
+extern const unsigned int cx231xx_bcount;
+int cx231xx_tuner_callback(void *ptr, int component, int command, int arg);
+
+/* cx23885-417.c                                               */
+extern int cx231xx_417_register(struct cx231xx *dev);
+extern void cx231xx_417_unregister(struct cx231xx *dev);
+
+/* cx23885-input.c                                             */
+
+#if defined(CONFIG_VIDEO_CX231XX_RC)
+int cx231xx_ir_init(struct cx231xx *dev);
+void cx231xx_ir_exit(struct cx231xx *dev);
+#else
+#define cx231xx_ir_init(dev)	(0)
+#define cx231xx_ir_exit(dev)	(0)
+#endif
+
+
+/* printk macros */
+
+#define cx231xx_err(fmt, arg...) do {\
+	printk(KERN_ERR fmt , ##arg); } while (0)
+
+#define cx231xx_errdev(fmt, arg...) do {\
+	printk(KERN_ERR "%s: "fmt,\
+			dev->name , ##arg); } while (0)
+
+#define cx231xx_info(fmt, arg...) do {\
+	printk(KERN_INFO "%s: "fmt,\
+			dev->name , ##arg); } while (0)
+#define cx231xx_warn(fmt, arg...) do {\
+	printk(KERN_WARNING "%s: "fmt,\
+			dev->name , ##arg); } while (0)
+
+static inline unsigned int norm_maxw(struct cx231xx *dev)
+{
+	if (dev->board.max_range_640_480)
+		return 640;
+	else
+		return 720;
+}
+
+static inline unsigned int norm_maxh(struct cx231xx *dev)
+{
+	if (dev->board.max_range_640_480)
+		return 480;
+	else
+		return (dev->norm & V4L2_STD_625_50) ? 576 : 480;
+}
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig
new file mode 100644
index 0000000..276374f
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/Kconfig
@@ -0,0 +1,146 @@
+config DVB_USB_V2
+	tristate "Support for various USB DVB devices v2"
+	depends on DVB_CORE && USB && I2C && RC_CORE
+	help
+	  By enabling this you will be able to choose the various supported
+	  USB1.1 and USB2.0 DVB devices.
+
+	  Almost every USB device needs a firmware, please look into
+	  <file:Documentation/dvb/README.dvb-usb>.
+
+	  For a complete list of supported USB devices see the LinuxTV DVB Wiki:
+	  <http://www.linuxtv.org/wiki/index.php/DVB_USB>
+
+	  Say Y if you own a USB DVB device.
+
+config DVB_USB_CYPRESS_FIRMWARE
+	tristate "Cypress firmware helper routines"
+	depends on DVB_USB_V2
+
+config DVB_USB_AF9015
+	tristate "Afatech AF9015 DVB-T USB2.0 support"
+	depends on DVB_USB_V2
+	select DVB_AF9013
+	select DVB_PLL              if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MT2060   if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_QT1010   if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
+
+config DVB_USB_AF9035
+	tristate "Afatech AF9035 DVB-T USB2.0 support"
+	depends on DVB_USB_V2
+	select DVB_AF9033
+	select MEDIA_TUNER_TUA9001 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_FC0011 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to support the Afatech AF9035 based DVB USB receiver.
+
+config DVB_USB_ANYSEE
+	tristate "Anysee DVB-T/C USB2.0 support"
+	depends on DVB_USB_V2
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select DVB_MT352 if !DVB_FE_CUSTOMISE
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_TDA18212 if !MEDIA_TUNER_CUSTOMISE
+	select DVB_CX24116 if !DVB_FE_CUSTOMISE
+	select DVB_STV0900 if !DVB_FE_CUSTOMISE
+	select DVB_STV6110 if !DVB_FE_CUSTOMISE
+	select DVB_ISL6423 if !DVB_FE_CUSTOMISE
+	select DVB_CXD2820R if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support the Anysee E30, Anysee E30 Plus or
+	  Anysee E30 C Plus DVB USB2.0 receiver.
+
+config DVB_USB_AU6610
+	tristate "Alcor Micro AU6610 USB2.0 support"
+	depends on DVB_USB_V2
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
+
+config DVB_USB_AZ6007
+	tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support"
+	depends on DVB_USB_V2
+	select DVB_USB_CYPRESS_FIRMWARE
+	select DVB_DRXK if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MT2063 if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support the AZ6007 receivers like Terratec H7.
+
+config DVB_USB_CE6230
+	tristate "Intel CE6230 DVB-T USB2.0 support"
+	depends on DVB_USB_V2
+	select DVB_ZL10353
+	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver
+
+config DVB_USB_EC168
+	tristate "E3C EC168 DVB-T USB2.0 support"
+	depends on DVB_USB_V2
+	select DVB_EC100
+	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to support the E3C EC168 DVB-T USB2.0 receiver.
+
+config DVB_USB_GL861
+	tristate "Genesys Logic GL861 USB2.0 support"
+	depends on DVB_USB_V2
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
+	  receiver with USB ID 0db0:5581.
+
+config DVB_USB_IT913X
+	tristate "ITE IT913X DVB-T USB2.0 support"
+	depends on DVB_USB_V2
+	select DVB_IT913X_FE
+	help
+	  Say Y here to support the ITE IT913X DVB-T USB2.0
+
+config DVB_USB_LME2510
+	tristate "LME DM04/QQBOX DVB-S USB2.0 support"
+	depends on DVB_USB_V2
+	select DVB_TDA10086 if !DVB_FE_CUSTOMISE
+	select DVB_TDA826X if !DVB_FE_CUSTOMISE
+	select DVB_STV0288 if !DVB_FE_CUSTOMISE
+	select DVB_IX2505V if !DVB_FE_CUSTOMISE
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select DVB_M88RS2000 if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support the LME DM04/QQBOX DVB-S USB2.0
+
+config DVB_USB_MXL111SF
+	tristate "MxL111SF DTV USB2.0 support"
+	depends on DVB_USB_V2
+	select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
+	select DVB_LG2160 if !DVB_FE_CUSTOMISE
+	select VIDEO_TVEEPROM
+	help
+	  Say Y here to support the MxL111SF USB2.0 DTV receiver.
+
+config DVB_USB_RTL28XXU
+	tristate "Realtek RTL28xxU DVB USB support"
+	depends on DVB_USB_V2 && EXPERIMENTAL
+	select DVB_RTL2830
+	select DVB_RTL2832
+	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_FC0012 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_FC0013 if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to support the Realtek RTL28xxU DVB USB receiver.
+
diff --git a/drivers/media/usb/dvb-usb-v2/Makefile b/drivers/media/usb/dvb-usb-v2/Makefile
new file mode 100644
index 0000000..58027fd
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/Makefile
@@ -0,0 +1,49 @@
+dvb_usbv2-objs := dvb_usb_core.o dvb_usb_urb.o usb_urb.o
+obj-$(CONFIG_DVB_USB_V2) += dvb_usbv2.o
+
+dvb_usb_cypress_firmware-objs := cypress_firmware.o
+obj-$(CONFIG_DVB_USB_CYPRESS_FIRMWARE) += dvb_usb_cypress_firmware.o
+
+dvb-usb-af9015-objs := af9015.o
+obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
+
+dvb-usb-af9035-objs := af9035.o
+obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o
+
+dvb-usb-anysee-objs := anysee.o
+obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
+
+dvb-usb-au6610-objs := au6610.o
+obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o
+
+dvb-usb-az6007-objs := az6007.o
+obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o
+
+dvb-usb-ce6230-objs := ce6230.o
+obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o
+
+dvb-usb-ec168-objs := ec168.o
+obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
+
+dvb-usb-it913x-objs := it913x.o
+obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o
+
+dvb-usb-lmedm04-objs := lmedm04.o
+obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o
+
+dvb-usb-gl861-objs := gl861.o
+obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o
+
+dvb-usb-mxl111sf-objs += mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o
+dvb-usb-mxl111sf-objs += mxl111sf-gpio.o
+obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o
+obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o
+obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o
+
+dvb-usb-rtl28xxu-objs := rtl28xxu.o
+obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
+
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
+ccflags-y += -I$(srctree)/drivers/media/tuners
+
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c
new file mode 100644
index 0000000..9afceed
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/af9015.c
@@ -0,0 +1,1435 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "af9015.h"
+
+static int dvb_usb_af9015_debug;
+module_param_named(debug, dvb_usb_af9015_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+static int dvb_usb_af9015_remote;
+module_param_named(remote, dvb_usb_af9015_remote, int, 0644);
+MODULE_PARM_DESC(remote, "select remote");
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
+{
+#define BUF_LEN 63
+#define REQ_HDR_LEN 8 /* send header size */
+#define ACK_HDR_LEN 2 /* rece header size */
+	struct af9015_state *state = d_to_priv(d);
+	int ret, wlen, rlen;
+	u8 buf[BUF_LEN];
+	u8 write = 1;
+
+	buf[0] = req->cmd;
+	buf[1] = state->seq++;
+	buf[2] = req->i2c_addr;
+	buf[3] = req->addr >> 8;
+	buf[4] = req->addr & 0xff;
+	buf[5] = req->mbox;
+	buf[6] = req->addr_len;
+	buf[7] = req->data_len;
+
+	switch (req->cmd) {
+	case GET_CONFIG:
+	case READ_MEMORY:
+	case RECONNECT_USB:
+		write = 0;
+		break;
+	case READ_I2C:
+		write = 0;
+		buf[2] |= 0x01; /* set I2C direction */
+	case WRITE_I2C:
+		buf[0] = READ_WRITE_I2C;
+		break;
+	case WRITE_MEMORY:
+		if (((req->addr & 0xff00) == 0xff00) ||
+		    ((req->addr & 0xff00) == 0xae00))
+			buf[0] = WRITE_VIRTUAL_MEMORY;
+	case WRITE_VIRTUAL_MEMORY:
+	case COPY_FIRMWARE:
+	case DOWNLOAD_FIRMWARE:
+	case BOOT:
+		break;
+	default:
+		err("unknown command:%d", req->cmd);
+		ret = -1;
+		goto error;
+	}
+
+	/* buffer overflow check */
+	if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) ||
+		(!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) {
+		err("too much data; cmd:%d len:%d", req->cmd, req->data_len);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	/* write receives seq + status = 2 bytes
+	   read receives seq + status + data = 2 + N bytes */
+	wlen = REQ_HDR_LEN;
+	rlen = ACK_HDR_LEN;
+	if (write) {
+		wlen += req->data_len;
+		memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len);
+	} else {
+		rlen += req->data_len;
+	}
+
+	/* no ack for these packets */
+	if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB)
+		rlen = 0;
+
+	ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen);
+	if (ret)
+		goto error;
+
+	/* check status */
+	if (rlen && buf[1]) {
+		err("command failed:%d", buf[1]);
+		ret = -1;
+		goto error;
+	}
+
+	/* read request, copy returned data to return buf */
+	if (!write)
+		memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len);
+error:
+	return ret;
+}
+
+static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val,
+	u8 len)
+{
+	struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
+		val};
+	return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len)
+{
+	struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
+		val};
+	return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val)
+{
+	return af9015_write_regs(d, addr, &val, 1);
+}
+
+static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val)
+{
+	return af9015_read_regs(d, addr, val, 1);
+}
+
+static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
+	u8 val)
+{
+	struct af9015_state *state = d_to_priv(d);
+	struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val};
+
+	if (addr == state->af9013_config[0].i2c_addr ||
+	    addr == state->af9013_config[1].i2c_addr)
+		req.addr_len = 3;
+
+	return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
+	u8 *val)
+{
+	struct af9015_state *state = d_to_priv(d);
+	struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val};
+
+	if (addr == state->af9013_config[0].i2c_addr ||
+	    addr == state->af9013_config[1].i2c_addr)
+		req.addr_len = 3;
+
+	return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op)
+{
+	int ret;
+	u8 val, mask = 0x01;
+
+	ret = af9015_read_reg(d, addr, &val);
+	if (ret)
+		return ret;
+
+	mask <<= bit;
+	if (op) {
+		/* set bit */
+		val |= mask;
+	} else {
+		/* clear bit */
+		mask ^= 0xff;
+		val &= mask;
+	}
+
+	return af9015_write_reg(d, addr, val);
+}
+
+static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
+{
+	return af9015_do_reg_bit(d, addr, bit, 1);
+}
+
+static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
+{
+	return af9015_do_reg_bit(d, addr, bit, 0);
+}
+
+static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+	int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct af9015_state *state = d_to_priv(d);
+	int ret = 0, i = 0;
+	u16 addr;
+	u8 uninitialized_var(mbox), addr_len;
+	struct req_t req;
+
+/*
+The bus lock is needed because there is two tuners both using same I2C-address.
+Due to that the only way to select correct tuner is use demodulator I2C-gate.
+
+................................................
+. AF9015 includes integrated AF9013 demodulator.
+. ____________                   ____________  .                ____________
+.|     uC     |                 |   demod    | .               |    tuner   |
+.|------------|                 |------------| .               |------------|
+.|   AF9015   |                 |  AF9013/5  | .               |   MXL5003  |
+.|            |--+----I2C-------|-----/ -----|-.-----I2C-------|            |
+.|            |  |              | addr 0x38  | .               |  addr 0xc6 |
+.|____________|  |              |____________| .               |____________|
+.................|..............................
+		 |               ____________                   ____________
+		 |              |   demod    |                 |    tuner   |
+		 |              |------------|                 |------------|
+		 |              |   AF9013   |                 |   MXL5003  |
+		 +----I2C-------|-----/ -----|-------I2C-------|            |
+				| addr 0x3a  |                 |  addr 0xc6 |
+				|____________|                 |____________|
+*/
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	while (i < num) {
+		if (msg[i].addr == state->af9013_config[0].i2c_addr ||
+		    msg[i].addr == state->af9013_config[1].i2c_addr) {
+			addr = msg[i].buf[0] << 8;
+			addr += msg[i].buf[1];
+			mbox = msg[i].buf[2];
+			addr_len = 3;
+		} else {
+			addr = msg[i].buf[0];
+			addr_len = 1;
+			/* mbox is don't care in that case */
+		}
+
+		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+			if (msg[i].len > 3 || msg[i+1].len > 61) {
+				ret = -EOPNOTSUPP;
+				goto error;
+			}
+			if (msg[i].addr == state->af9013_config[0].i2c_addr)
+				req.cmd = READ_MEMORY;
+			else
+				req.cmd = READ_I2C;
+			req.i2c_addr = msg[i].addr;
+			req.addr = addr;
+			req.mbox = mbox;
+			req.addr_len = addr_len;
+			req.data_len = msg[i+1].len;
+			req.data = &msg[i+1].buf[0];
+			ret = af9015_ctrl_msg(d, &req);
+			i += 2;
+		} else if (msg[i].flags & I2C_M_RD) {
+			if (msg[i].len > 61) {
+				ret = -EOPNOTSUPP;
+				goto error;
+			}
+			if (msg[i].addr == state->af9013_config[0].i2c_addr) {
+				ret = -EINVAL;
+				goto error;
+			}
+			req.cmd = READ_I2C;
+			req.i2c_addr = msg[i].addr;
+			req.addr = addr;
+			req.mbox = mbox;
+			req.addr_len = addr_len;
+			req.data_len = msg[i].len;
+			req.data = &msg[i].buf[0];
+			ret = af9015_ctrl_msg(d, &req);
+			i += 1;
+		} else {
+			if (msg[i].len > 21) {
+				ret = -EOPNOTSUPP;
+				goto error;
+			}
+			if (msg[i].addr == state->af9013_config[0].i2c_addr)
+				req.cmd = WRITE_MEMORY;
+			else
+				req.cmd = WRITE_I2C;
+			req.i2c_addr = msg[i].addr;
+			req.addr = addr;
+			req.mbox = mbox;
+			req.addr_len = addr_len;
+			req.data_len = msg[i].len-addr_len;
+			req.data = &msg[i].buf[addr_len];
+			ret = af9015_ctrl_msg(d, &req);
+			i += 1;
+		}
+		if (ret)
+			goto error;
+
+	}
+	ret = i;
+
+error:
+	mutex_unlock(&d->i2c_mutex);
+
+	return ret;
+}
+
+static u32 af9015_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm af9015_i2c_algo = {
+	.master_xfer = af9015_i2c_xfer,
+	.functionality = af9015_i2c_func,
+};
+
+static int af9015_identify_state(struct dvb_usb_device *d, const char **name)
+{
+	int ret;
+	u8 reply;
+	struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply};
+
+	ret = af9015_ctrl_msg(d, &req);
+	if (ret)
+		return ret;
+
+	deb_info("%s: reply:%02x\n", __func__, reply);
+	if (reply == 0x02)
+		ret = WARM;
+	else
+		ret = COLD;
+
+	return ret;
+}
+
+static int af9015_download_firmware(struct dvb_usb_device *d,
+	const struct firmware *fw)
+{
+	struct af9015_state *state = d_to_priv(d);
+	int i, len, remaining, ret;
+	struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL};
+	u16 checksum = 0;
+
+	deb_info("%s:\n", __func__);
+
+	/* calc checksum */
+	for (i = 0; i < fw->size; i++)
+		checksum += fw->data[i];
+
+	state->firmware_size = fw->size;
+	state->firmware_checksum = checksum;
+
+	#define FW_ADDR 0x5100 /* firmware start address */
+	#define LEN_MAX 55 /* max packet size */
+	for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) {
+		len = remaining;
+		if (len > LEN_MAX)
+			len = LEN_MAX;
+
+		req.data_len = len;
+		req.data = (u8 *) &fw->data[fw->size - remaining];
+		req.addr = FW_ADDR + fw->size - remaining;
+
+		ret = af9015_ctrl_msg(d, &req);
+		if (ret) {
+			err("firmware download failed:%d", ret);
+			goto error;
+		}
+	}
+
+	/* firmware loaded, request boot */
+	req.cmd = BOOT;
+	req.data_len = 0;
+	ret = af9015_ctrl_msg(d, &req);
+	if (ret) {
+		err("firmware boot failed:%d", ret);
+		goto error;
+	}
+
+error:
+	return ret;
+}
+
+/* hash (and dump) eeprom */
+static int af9015_eeprom_hash(struct dvb_usb_device *d)
+{
+	struct af9015_state *state = d_to_priv(d);
+	int ret;
+	static const unsigned int eeprom_size = 256;
+	unsigned int reg;
+	u8 val, *eeprom;
+	struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
+
+	eeprom = kmalloc(eeprom_size, GFP_KERNEL);
+	if (eeprom == NULL)
+		return -ENOMEM;
+
+	for (reg = 0; reg < eeprom_size; reg++) {
+		req.addr = reg;
+		ret = af9015_ctrl_msg(d, &req);
+		if (ret)
+			goto free;
+
+		eeprom[reg] = val;
+	}
+
+	if (dvb_usb_af9015_debug & 0x01)
+		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, eeprom,
+				eeprom_size);
+
+	BUG_ON(eeprom_size % 4);
+
+	state->eeprom_sum = 0;
+	for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) {
+		state->eeprom_sum *= GOLDEN_RATIO_PRIME_32;
+		state->eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]);
+	}
+
+	deb_info("%s: eeprom sum=%.8x\n", __func__, state->eeprom_sum);
+
+	ret = 0;
+free:
+	kfree(eeprom);
+	return ret;
+}
+
+static int af9015_read_config(struct dvb_usb_device *d)
+{
+	struct af9015_state *state = d_to_priv(d);
+	int ret;
+	u8 val, i, offset = 0;
+	struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
+
+	deb_info("%s:\n", __func__);
+
+	/* IR remote controller */
+	req.addr = AF9015_EEPROM_IR_MODE;
+	/* first message will timeout often due to possible hw bug */
+	for (i = 0; i < 4; i++) {
+		ret = af9015_ctrl_msg(d, &req);
+		if (!ret)
+			break;
+	}
+	if (ret)
+		goto error;
+
+	ret = af9015_eeprom_hash(d);
+	if (ret)
+		goto error;
+
+	deb_info("%s: IR mode=%d\n", __func__, val);
+	state->ir_mode = val;
+
+	/* TS mode - one or two receivers */
+	req.addr = AF9015_EEPROM_TS_MODE;
+	ret = af9015_ctrl_msg(d, &req);
+	if (ret)
+		goto error;
+
+	state->dual_mode = val;
+	deb_info("%s: TS mode=%d\n", __func__, state->dual_mode);
+
+	/* disable 2nd adapter because we don't have PID-filters */
+	if (d->udev->speed == USB_SPEED_FULL)
+		state->dual_mode = 0;
+
+	if (state->dual_mode) {
+		/* read 2nd demodulator I2C address */
+		req.addr = AF9015_EEPROM_DEMOD2_I2C;
+		ret = af9015_ctrl_msg(d, &req);
+		if (ret)
+			goto error;
+
+		state->af9013_config[1].i2c_addr = val;
+	}
+
+	for (i = 0; i < state->dual_mode + 1; i++) {
+		if (i == 1)
+			offset = AF9015_EEPROM_OFFSET;
+		/* xtal */
+		req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset;
+		ret = af9015_ctrl_msg(d, &req);
+		if (ret)
+			goto error;
+		switch (val) {
+		case 0:
+			state->af9013_config[i].clock = 28800000;
+			break;
+		case 1:
+			state->af9013_config[i].clock = 20480000;
+			break;
+		case 2:
+			state->af9013_config[i].clock = 28000000;
+			break;
+		case 3:
+			state->af9013_config[i].clock = 25000000;
+			break;
+		};
+		deb_info("%s: [%d] xtal=%d set clock=%d\n", __func__, i,
+				val, state->af9013_config[i].clock);
+
+		/* IF frequency */
+		req.addr = AF9015_EEPROM_IF1H + offset;
+		ret = af9015_ctrl_msg(d, &req);
+		if (ret)
+			goto error;
+
+		state->af9013_config[i].if_frequency = val << 8;
+
+		req.addr = AF9015_EEPROM_IF1L + offset;
+		ret = af9015_ctrl_msg(d, &req);
+		if (ret)
+			goto error;
+
+		state->af9013_config[i].if_frequency += val;
+		state->af9013_config[i].if_frequency *= 1000;
+		deb_info("%s: [%d] IF frequency=%d\n", __func__, i,
+				state->af9013_config[i].if_frequency);
+
+		/* MT2060 IF1 */
+		req.addr = AF9015_EEPROM_MT2060_IF1H  + offset;
+		ret = af9015_ctrl_msg(d, &req);
+		if (ret)
+			goto error;
+		state->mt2060_if1[i] = val << 8;
+		req.addr = AF9015_EEPROM_MT2060_IF1L + offset;
+		ret = af9015_ctrl_msg(d, &req);
+		if (ret)
+			goto error;
+		state->mt2060_if1[i] += val;
+		deb_info("%s: [%d] MT2060 IF1=%d\n", __func__, i,
+				state->mt2060_if1[i]);
+
+		/* tuner */
+		req.addr =  AF9015_EEPROM_TUNER_ID1 + offset;
+		ret = af9015_ctrl_msg(d, &req);
+		if (ret)
+			goto error;
+		switch (val) {
+		case AF9013_TUNER_ENV77H11D5:
+		case AF9013_TUNER_MT2060:
+		case AF9013_TUNER_QT1010:
+		case AF9013_TUNER_UNKNOWN:
+		case AF9013_TUNER_MT2060_2:
+		case AF9013_TUNER_TDA18271:
+		case AF9013_TUNER_QT1010A:
+		case AF9013_TUNER_TDA18218:
+			state->af9013_config[i].spec_inv = 1;
+			break;
+		case AF9013_TUNER_MXL5003D:
+		case AF9013_TUNER_MXL5005D:
+		case AF9013_TUNER_MXL5005R:
+		case AF9013_TUNER_MXL5007T:
+			state->af9013_config[i].spec_inv = 0;
+			break;
+		case AF9013_TUNER_MC44S803:
+			state->af9013_config[i].gpio[1] = AF9013_GPIO_LO;
+			state->af9013_config[i].spec_inv = 1;
+			break;
+		default:
+			warn("tuner id=%d not supported, please report!", val);
+			return -ENODEV;
+		};
+
+		state->af9013_config[i].tuner = val;
+		deb_info("%s: [%d] tuner id=%d\n", __func__, i, val);
+	}
+
+error:
+	if (ret)
+		err("eeprom read failed=%d", ret);
+
+	/* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM
+	   content :-( Override some wrong values here. Ditto for the
+	   AVerTV Red HD+ (A850T) device. */
+	if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA &&
+		((le16_to_cpu(d->udev->descriptor.idProduct) ==
+			USB_PID_AVERMEDIA_A850) ||
+		(le16_to_cpu(d->udev->descriptor.idProduct) ==
+			USB_PID_AVERMEDIA_A850T))) {
+		deb_info("%s: AverMedia A850: overriding config\n", __func__);
+		/* disable dual mode */
+		state->dual_mode = 0;
+
+		/* set correct IF */
+		state->af9013_config[0].if_frequency = 4570000;
+	}
+
+	return ret;
+}
+
+static int af9015_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
+		struct usb_data_stream_properties *stream)
+{
+	deb_info("%s: adap=%d\n", __func__, fe_to_adap(fe)->id);
+
+	if (fe_to_d(fe)->udev->speed == USB_SPEED_FULL)
+		stream->u.bulk.buffersize = TS_USB11_FRAME_SIZE;
+
+	return 0;
+}
+
+static int af9015_get_adapter_count(struct dvb_usb_device *d)
+{
+	struct af9015_state *state = d_to_priv(d);
+	return state->dual_mode + 1;
+}
+
+/* override demod callbacks for resource locking */
+static int af9015_af9013_set_frontend(struct dvb_frontend *fe)
+{
+	int ret;
+	struct af9015_state *state = fe_to_priv(fe);
+
+	if (mutex_lock_interruptible(&state->fe_mutex))
+		return -EAGAIN;
+
+	ret = state->set_frontend[fe_to_adap(fe)->id](fe);
+
+	mutex_unlock(&state->fe_mutex);
+
+	return ret;
+}
+
+/* override demod callbacks for resource locking */
+static int af9015_af9013_read_status(struct dvb_frontend *fe,
+	fe_status_t *status)
+{
+	int ret;
+	struct af9015_state *state = fe_to_priv(fe);
+
+	if (mutex_lock_interruptible(&state->fe_mutex))
+		return -EAGAIN;
+
+	ret = state->read_status[fe_to_adap(fe)->id](fe, status);
+
+	mutex_unlock(&state->fe_mutex);
+
+	return ret;
+}
+
+/* override demod callbacks for resource locking */
+static int af9015_af9013_init(struct dvb_frontend *fe)
+{
+	int ret;
+	struct af9015_state *state = fe_to_priv(fe);
+
+	if (mutex_lock_interruptible(&state->fe_mutex))
+		return -EAGAIN;
+
+	ret = state->init[fe_to_adap(fe)->id](fe);
+
+	mutex_unlock(&state->fe_mutex);
+
+	return ret;
+}
+
+/* override demod callbacks for resource locking */
+static int af9015_af9013_sleep(struct dvb_frontend *fe)
+{
+	int ret;
+	struct af9015_state *state = fe_to_priv(fe);
+
+	if (mutex_lock_interruptible(&state->fe_mutex))
+		return -EAGAIN;
+
+	ret = state->sleep[fe_to_adap(fe)->id](fe);
+
+	mutex_unlock(&state->fe_mutex);
+
+	return ret;
+}
+
+/* override tuner callbacks for resource locking */
+static int af9015_tuner_init(struct dvb_frontend *fe)
+{
+	int ret;
+	struct af9015_state *state = fe_to_priv(fe);
+
+	if (mutex_lock_interruptible(&state->fe_mutex))
+		return -EAGAIN;
+
+	ret = state->tuner_init[fe_to_adap(fe)->id](fe);
+
+	mutex_unlock(&state->fe_mutex);
+
+	return ret;
+}
+
+/* override tuner callbacks for resource locking */
+static int af9015_tuner_sleep(struct dvb_frontend *fe)
+{
+	int ret;
+	struct af9015_state *state = fe_to_priv(fe);
+
+	if (mutex_lock_interruptible(&state->fe_mutex))
+		return -EAGAIN;
+
+	ret = state->tuner_sleep[fe_to_adap(fe)->id](fe);
+
+	mutex_unlock(&state->fe_mutex);
+
+	return ret;
+}
+
+static int af9015_copy_firmware(struct dvb_usb_device *d)
+{
+	struct af9015_state *state = d_to_priv(d);
+	int ret;
+	u8 fw_params[4];
+	u8 val, i;
+	struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params),
+		fw_params };
+	deb_info("%s:\n", __func__);
+
+	fw_params[0] = state->firmware_size >> 8;
+	fw_params[1] = state->firmware_size & 0xff;
+	fw_params[2] = state->firmware_checksum >> 8;
+	fw_params[3] = state->firmware_checksum & 0xff;
+
+	/* wait 2nd demodulator ready */
+	msleep(100);
+
+	ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr,
+			0x98be, &val);
+	if (ret)
+		goto error;
+	else
+		deb_info("%s: firmware status:%02x\n", __func__, val);
+
+	if (val == 0x0c) /* fw is running, no need for download */
+		goto exit;
+
+	/* set I2C master clock to fast (to speed up firmware copy) */
+	ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */
+	if (ret)
+		goto error;
+
+	msleep(50);
+
+	/* copy firmware */
+	ret = af9015_ctrl_msg(d, &req);
+	if (ret)
+		err("firmware copy cmd failed:%d", ret);
+	deb_info("%s: firmware copy done\n", __func__);
+
+	/* set I2C master clock back to normal */
+	ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */
+	if (ret)
+		goto error;
+
+	/* request boot firmware */
+	ret = af9015_write_reg_i2c(d, state->af9013_config[1].i2c_addr,
+			0xe205, 1);
+	deb_info("%s: firmware boot cmd status:%d\n", __func__, ret);
+	if (ret)
+		goto error;
+
+	for (i = 0; i < 15; i++) {
+		msleep(100);
+
+		/* check firmware status */
+		ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr,
+				0x98be, &val);
+		deb_info("%s: firmware status cmd status:%d fw status:%02x\n",
+			__func__, ret, val);
+		if (ret)
+			goto error;
+
+		if (val == 0x0c || val == 0x04) /* success or fail */
+			break;
+	}
+
+	if (val == 0x04) {
+		err("firmware did not run");
+		ret = -1;
+	} else if (val != 0x0c) {
+		err("firmware boot timeout");
+		ret = -1;
+	}
+
+error:
+exit:
+	return ret;
+}
+
+static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	struct af9015_state *state = adap_to_priv(adap);
+
+	if (adap->id == 0) {
+		state->af9013_config[0].ts_mode = AF9013_TS_USB;
+		memcpy(state->af9013_config[0].api_version, "\x0\x1\x9\x0", 4);
+		state->af9013_config[0].gpio[0] = AF9013_GPIO_HI;
+		state->af9013_config[0].gpio[3] = AF9013_GPIO_TUNER_ON;
+	} else if (adap->id == 1) {
+		state->af9013_config[1].ts_mode = AF9013_TS_SERIAL;
+		memcpy(state->af9013_config[1].api_version, "\x0\x1\x9\x0", 4);
+		state->af9013_config[1].gpio[0] = AF9013_GPIO_TUNER_ON;
+		state->af9013_config[1].gpio[1] = AF9013_GPIO_LO;
+
+		/* copy firmware to 2nd demodulator */
+		if (state->dual_mode) {
+			ret = af9015_copy_firmware(adap_to_d(adap));
+			if (ret) {
+				err("firmware copy to 2nd frontend " \
+					"failed, will disable it");
+				state->dual_mode = 0;
+				return -ENODEV;
+			}
+		} else {
+			return -ENODEV;
+		}
+	}
+
+	/* attach demodulator */
+	adap->fe[0] = dvb_attach(af9013_attach,
+		&state->af9013_config[adap->id], &adap_to_d(adap)->i2c_adap);
+
+	/*
+	 * AF9015 firmware does not like if it gets interrupted by I2C adapter
+	 * request on some critical phases. During normal operation I2C adapter
+	 * is used only 2nd demodulator and tuner on dual tuner devices.
+	 * Override demodulator callbacks and use mutex for limit access to
+	 * those "critical" paths to keep AF9015 happy.
+	 */
+	if (adap->fe[0]) {
+		state->set_frontend[adap->id] =
+			adap->fe[0]->ops.set_frontend;
+		adap->fe[0]->ops.set_frontend =
+			af9015_af9013_set_frontend;
+
+		state->read_status[adap->id] =
+			adap->fe[0]->ops.read_status;
+		adap->fe[0]->ops.read_status =
+			af9015_af9013_read_status;
+
+		state->init[adap->id] = adap->fe[0]->ops.init;
+		adap->fe[0]->ops.init = af9015_af9013_init;
+
+		state->sleep[adap->id] = adap->fe[0]->ops.sleep;
+		adap->fe[0]->ops.sleep = af9015_af9013_sleep;
+	}
+
+	return adap->fe[0] == NULL ? -ENODEV : 0;
+}
+
+static struct mt2060_config af9015_mt2060_config = {
+	.i2c_address = 0xc0,
+	.clock_out = 0,
+};
+
+static struct qt1010_config af9015_qt1010_config = {
+	.i2c_address = 0xc4,
+};
+
+static struct tda18271_config af9015_tda18271_config = {
+	.gate = TDA18271_GATE_DIGITAL,
+	.small_i2c = TDA18271_16_BYTE_CHUNK_INIT,
+};
+
+static struct mxl5005s_config af9015_mxl5003_config = {
+	.i2c_address     = 0xc6,
+	.if_freq         = IF_FREQ_4570000HZ,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_DEFAULT,
+	.rssi_enable     = MXL_RSSI_ENABLE,
+	.cap_select      = MXL_CAP_SEL_ENABLE,
+	.div_out         = MXL_DIV_OUT_4,
+	.clock_out       = MXL_CLOCK_OUT_DISABLE,
+	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+	.top		 = MXL5005S_TOP_25P2,
+	.mod_mode        = MXL_DIGITAL_MODE,
+	.if_mode         = MXL_ZERO_IF,
+	.AgcMasterByte   = 0x00,
+};
+
+static struct mxl5005s_config af9015_mxl5005_config = {
+	.i2c_address     = 0xc6,
+	.if_freq         = IF_FREQ_4570000HZ,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_OFF,
+	.rssi_enable     = MXL_RSSI_ENABLE,
+	.cap_select      = MXL_CAP_SEL_ENABLE,
+	.div_out         = MXL_DIV_OUT_4,
+	.clock_out       = MXL_CLOCK_OUT_DISABLE,
+	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+	.top		 = MXL5005S_TOP_25P2,
+	.mod_mode        = MXL_DIGITAL_MODE,
+	.if_mode         = MXL_ZERO_IF,
+	.AgcMasterByte   = 0x00,
+};
+
+static struct mc44s803_config af9015_mc44s803_config = {
+	.i2c_address = 0xc0,
+	.dig_out = 1,
+};
+
+static struct tda18218_config af9015_tda18218_config = {
+	.i2c_address = 0xc0,
+	.i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */
+};
+
+static struct mxl5007t_config af9015_mxl5007t_config = {
+	.xtal_freq_hz = MxL_XTAL_24_MHZ,
+	.if_freq_hz = MxL_IF_4_57_MHZ,
+};
+
+static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct af9015_state *state = adap_to_priv(adap);
+	int ret;
+	deb_info("%s:\n", __func__);
+
+	switch (state->af9013_config[adap->id].tuner) {
+	case AF9013_TUNER_MT2060:
+	case AF9013_TUNER_MT2060_2:
+		ret = dvb_attach(mt2060_attach, adap->fe[0],
+			&adap_to_d(adap)->i2c_adap, &af9015_mt2060_config,
+			state->mt2060_if1[adap->id])
+			== NULL ? -ENODEV : 0;
+		break;
+	case AF9013_TUNER_QT1010:
+	case AF9013_TUNER_QT1010A:
+		ret = dvb_attach(qt1010_attach, adap->fe[0],
+			&adap_to_d(adap)->i2c_adap,
+			&af9015_qt1010_config) == NULL ? -ENODEV : 0;
+		break;
+	case AF9013_TUNER_TDA18271:
+		ret = dvb_attach(tda18271_attach, adap->fe[0], 0xc0,
+			&adap_to_d(adap)->i2c_adap,
+			&af9015_tda18271_config) == NULL ? -ENODEV : 0;
+		break;
+	case AF9013_TUNER_TDA18218:
+		ret = dvb_attach(tda18218_attach, adap->fe[0],
+			&adap_to_d(adap)->i2c_adap,
+			&af9015_tda18218_config) == NULL ? -ENODEV : 0;
+		break;
+	case AF9013_TUNER_MXL5003D:
+		ret = dvb_attach(mxl5005s_attach, adap->fe[0],
+			&adap_to_d(adap)->i2c_adap,
+			&af9015_mxl5003_config) == NULL ? -ENODEV : 0;
+		break;
+	case AF9013_TUNER_MXL5005D:
+	case AF9013_TUNER_MXL5005R:
+		ret = dvb_attach(mxl5005s_attach, adap->fe[0],
+			&adap_to_d(adap)->i2c_adap,
+			&af9015_mxl5005_config) == NULL ? -ENODEV : 0;
+		break;
+	case AF9013_TUNER_ENV77H11D5:
+		ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0xc0,
+			&adap_to_d(adap)->i2c_adap,
+			DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
+		break;
+	case AF9013_TUNER_MC44S803:
+		ret = dvb_attach(mc44s803_attach, adap->fe[0],
+			&adap_to_d(adap)->i2c_adap,
+			&af9015_mc44s803_config) == NULL ? -ENODEV : 0;
+		break;
+	case AF9013_TUNER_MXL5007T:
+		ret = dvb_attach(mxl5007t_attach, adap->fe[0],
+			&adap_to_d(adap)->i2c_adap,
+			0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0;
+		break;
+	case AF9013_TUNER_UNKNOWN:
+	default:
+		ret = -ENODEV;
+		err("Unknown tuner id:%d",
+			state->af9013_config[adap->id].tuner);
+	}
+
+	if (adap->fe[0]->ops.tuner_ops.init) {
+		state->tuner_init[adap->id] =
+			adap->fe[0]->ops.tuner_ops.init;
+		adap->fe[0]->ops.tuner_ops.init = af9015_tuner_init;
+	}
+
+	if (adap->fe[0]->ops.tuner_ops.sleep) {
+		state->tuner_sleep[adap->id] =
+			adap->fe[0]->ops.tuner_ops.sleep;
+		adap->fe[0]->ops.tuner_ops.sleep = af9015_tuner_sleep;
+	}
+
+	return ret;
+}
+
+static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	int ret;
+	deb_info("%s: onoff:%d\n", __func__, onoff);
+
+	if (onoff)
+		ret = af9015_set_reg_bit(adap_to_d(adap), 0xd503, 0);
+	else
+		ret = af9015_clear_reg_bit(adap_to_d(adap), 0xd503, 0);
+
+	return ret;
+}
+
+static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+	int onoff)
+{
+	int ret;
+	u8 idx;
+
+	deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n",
+		__func__, index, pid, onoff);
+
+	ret = af9015_write_reg(adap_to_d(adap), 0xd505, (pid & 0xff));
+	if (ret)
+		goto error;
+
+	ret = af9015_write_reg(adap_to_d(adap), 0xd506, (pid >> 8));
+	if (ret)
+		goto error;
+
+	idx = ((index & 0x1f) | (1 << 5));
+	ret = af9015_write_reg(adap_to_d(adap), 0xd504, idx);
+
+error:
+	return ret;
+}
+
+static int af9015_init_endpoint(struct dvb_usb_device *d)
+{
+	struct af9015_state *state = d_to_priv(d);
+	int ret;
+	u16 frame_size;
+	u8  packet_size;
+	deb_info("%s: USB speed:%d\n", __func__, d->udev->speed);
+
+	if (d->udev->speed == USB_SPEED_FULL) {
+		frame_size = TS_USB11_FRAME_SIZE/4;
+		packet_size = TS_USB11_MAX_PACKET_SIZE/4;
+	} else {
+		frame_size = TS_USB20_FRAME_SIZE/4;
+		packet_size = TS_USB20_MAX_PACKET_SIZE/4;
+	}
+
+	ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */
+	if (ret)
+		goto error;
+	ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */
+	if (ret)
+		goto error;
+	ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */
+	if (ret)
+		goto error;
+	ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */
+	if (ret)
+		goto error;
+	ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */
+	if (ret)
+		goto error;
+	if (state->dual_mode) {
+		ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */
+		if (ret)
+			goto error;
+	}
+	ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */
+	if (ret)
+		goto error;
+	if (state->dual_mode) {
+		ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */
+		if (ret)
+			goto error;
+	}
+	/* EP4 xfer length */
+	ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff);
+	if (ret)
+		goto error;
+	ret = af9015_write_reg(d, 0xdd89, frame_size >> 8);
+	if (ret)
+		goto error;
+	/* EP5 xfer length */
+	ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff);
+	if (ret)
+		goto error;
+	ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8);
+	if (ret)
+		goto error;
+	ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */
+	if (ret)
+		goto error;
+	ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */
+	if (ret)
+		goto error;
+	ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */
+	if (ret)
+		goto error;
+	if (state->dual_mode) {
+		ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */
+		if (ret)
+			goto error;
+	}
+
+	/* enable / disable mp2if2 */
+	if (state->dual_mode)
+		ret = af9015_set_reg_bit(d, 0xd50b, 0);
+	else
+		ret = af9015_clear_reg_bit(d, 0xd50b, 0);
+
+error:
+	if (ret)
+		err("endpoint init failed:%d", ret);
+	return ret;
+}
+
+static int af9015_init(struct dvb_usb_device *d)
+{
+	struct af9015_state *state = d_to_priv(d);
+	int ret;
+	deb_info("%s:\n", __func__);
+
+	mutex_init(&state->fe_mutex);
+
+	/* init RC canary */
+	ret = af9015_write_reg(d, 0x98e9, 0xff);
+	if (ret)
+		goto error;
+
+	ret = af9015_init_endpoint(d);
+	if (ret)
+		goto error;
+
+error:
+	return ret;
+}
+
+struct af9015_rc_setup {
+	unsigned int id;
+	char *rc_codes;
+};
+
+static char *af9015_rc_setup_match(unsigned int id,
+	const struct af9015_rc_setup *table)
+{
+	for (; table->rc_codes; table++)
+		if (table->id == id)
+			return table->rc_codes;
+	return NULL;
+}
+
+static const struct af9015_rc_setup af9015_rc_setup_modparam[] = {
+	{ AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M },
+	{ AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II },
+	{ AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND },
+	{ AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE },
+	{ AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS },
+	{ }
+};
+
+static const struct af9015_rc_setup af9015_rc_setup_hashes[] = {
+	{ 0xb8feb708, RC_MAP_MSI_DIGIVOX_II },
+	{ 0xa3703d00, RC_MAP_ALINK_DTU_M },
+	{ 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */
+	{ 0x5d49e3db, RC_MAP_DIGITTRADE }, /* LC-Power LC-USB-DVBT */
+	{ }
+};
+
+static int af9015_rc_query(struct dvb_usb_device *d)
+{
+	struct af9015_state *state = d_to_priv(d);
+	int ret;
+	u8 buf[17];
+
+	deb_info("%s:\n", __func__);
+
+	/* read registers needed to detect remote controller code */
+	ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf));
+	if (ret)
+		goto error;
+
+	/* If any of these are non-zero, assume invalid data */
+	if (buf[1] || buf[2] || buf[3])
+		return ret;
+
+	/* Check for repeat of previous code */
+	if ((state->rc_repeat != buf[6] || buf[0]) &&
+			!memcmp(&buf[12], state->rc_last, 4)) {
+		deb_rc("%s: key repeated\n", __func__);
+		rc_keydown(d->rc_dev, state->rc_keycode, 0);
+		state->rc_repeat = buf[6];
+		return ret;
+	}
+
+	/* Only process key if canary killed */
+	if (buf[16] != 0xff && buf[0] != 0x01) {
+		deb_rc("%s: key pressed %*ph\n", __func__, 4, buf + 12);
+
+		/* Reset the canary */
+		ret = af9015_write_reg(d, 0x98e9, 0xff);
+		if (ret)
+			goto error;
+
+		/* Remember this key */
+		memcpy(state->rc_last, &buf[12], 4);
+		if (buf[14] == (u8) ~buf[15]) {
+			if (buf[12] == (u8) ~buf[13]) {
+				/* NEC */
+				state->rc_keycode = buf[12] << 8 | buf[14];
+			} else {
+				/* NEC extended*/
+				state->rc_keycode = buf[12] << 16 |
+					buf[13] << 8 | buf[14];
+			}
+		} else {
+			/* 32 bit NEC */
+			state->rc_keycode = buf[12] << 24 | buf[13] << 16 |
+					buf[14] << 8 | buf[15];
+		}
+		rc_keydown(d->rc_dev, state->rc_keycode, 0);
+	} else {
+		deb_rc("%s: no key press\n", __func__);
+		/* Invalidate last keypress */
+		/* Not really needed, but helps with debug */
+		state->rc_last[2] = state->rc_last[3];
+	}
+
+	state->rc_repeat = buf[6];
+	state->rc_failed = false;
+
+error:
+	if (ret) {
+		err("%s: failed:%d", __func__, ret);
+
+		/* allow random errors as dvb-usb will stop polling on error */
+		if (!state->rc_failed)
+			ret = 0;
+
+		state->rc_failed = true;
+	}
+
+	return ret;
+}
+
+static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+	struct af9015_state *state = d_to_priv(d);
+	u16 vid = le16_to_cpu(d->udev->descriptor.idVendor);
+
+	if (state->ir_mode == AF9015_IR_MODE_DISABLED)
+		return 0;
+
+	/* try to load remote based module param */
+	if (!rc->map_name)
+		rc->map_name = af9015_rc_setup_match(dvb_usb_af9015_remote,
+				af9015_rc_setup_modparam);
+
+	/* try to load remote based eeprom hash */
+	if (!rc->map_name)
+		rc->map_name = af9015_rc_setup_match(state->eeprom_sum,
+				af9015_rc_setup_hashes);
+
+	/* try to load remote based USB iManufacturer string */
+	if (!rc->map_name && vid == USB_VID_AFATECH) {
+		/* Check USB manufacturer and product strings and try
+		   to determine correct remote in case of chip vendor
+		   reference IDs are used.
+		   DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */
+		char manufacturer[10];
+		memset(manufacturer, 0, sizeof(manufacturer));
+		usb_string(d->udev, d->udev->descriptor.iManufacturer,
+			manufacturer, sizeof(manufacturer));
+		if (!strcmp("MSI", manufacturer)) {
+			/* iManufacturer 1 MSI
+			   iProduct      2 MSI K-VOX */
+			rc->map_name = af9015_rc_setup_match(
+					AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
+					af9015_rc_setup_modparam);
+		}
+	}
+
+	/* load empty to enable rc */
+	if (!rc->map_name)
+		rc->map_name = RC_MAP_EMPTY;
+
+	rc->allowed_protos = RC_TYPE_NEC;
+	rc->query = af9015_rc_query;
+	rc->interval = 500;
+
+	return 0;
+}
+
+/* interface 0 is used by DVB-T receiver and
+   interface 1 is for remote controller (HID) */
+static struct dvb_usb_device_properties af9015_props = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+	.size_of_priv = sizeof(struct af9015_state),
+
+	.generic_bulk_ctrl_endpoint = 0x02,
+	.generic_bulk_ctrl_endpoint_response = 0x81,
+
+	.identify_state = af9015_identify_state,
+	.firmware = "dvb-usb-af9015.fw",
+	.download_firmware = af9015_download_firmware,
+
+	.i2c_algo = &af9015_i2c_algo,
+	.read_config = af9015_read_config,
+	.frontend_attach = af9015_af9013_frontend_attach,
+	.tuner_attach = af9015_tuner_attach,
+	.init = af9015_init,
+	.get_rc_config = af9015_get_rc_config,
+	.get_stream_config = af9015_get_stream_config,
+
+	.get_adapter_count = af9015_get_adapter_count,
+	.adapter = {
+		{
+			.caps = DVB_USB_ADAP_HAS_PID_FILTER |
+				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+			.pid_filter_count = 32,
+			.pid_filter = af9015_pid_filter,
+			.pid_filter_ctrl = af9015_pid_filter_ctrl,
+
+			.stream = DVB_USB_STREAM_BULK(0x84, 8, TS_USB20_FRAME_SIZE),
+		}, {
+			.stream = DVB_USB_STREAM_BULK(0x85, 8, TS_USB20_FRAME_SIZE),
+		},
+	},
+};
+
+static const struct usb_device_id af9015_id_table[] = {
+	{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015,
+		&af9015_props, "Afatech AF9015 reference design", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016,
+		&af9015_props, "Afatech AF9015 reference design", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD,
+		&af9015_props, "Leadtek WinFast DTV Dongle Gold", RC_MAP_LEADTEK_Y04G0051) },
+	{ DVB_USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E,
+		&af9015_props, "Pinnacle PCTV 71e", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U,
+		&af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN,
+		&af9015_props, "DigitalNow TinyTwin", RC_MAP_AZUREWAVE_AD_TU700) },
+	{ DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700,
+		&af9015_props, "TwinHan AzureWave AD-TU700(704J)", RC_MAP_AZUREWAVE_AD_TU700) },
+	{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2,
+		&af9015_props, "TerraTec Cinergy T USB XE", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T,
+		&af9015_props, "KWorld PlusTV Dual DVB-T PCI (DVB-T PC160-2T)", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X,
+		&af9015_props, "AVerMedia AVerTV DVB-T Volar X", RC_MAP_AVERMEDIA_M135A) },
+	{ DVB_USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380,
+		&af9015_props, "Xtensions XD-380", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO,
+		&af9015_props, "MSI DIGIVOX Duo", RC_MAP_MSI_DIGIVOX_III) },
+	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2,
+		&af9015_props, "Fujitsu-Siemens Slim Mobile USB DVB-T", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_TELESTAR,  USB_PID_TELESTAR_STARSTICK_2,
+		&af9015_props, "Telestar Starstick 2", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309,
+		&af9015_props, "AVerMedia A309", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III,
+		&af9015_props, "MSI Digi VOX mini III", RC_MAP_MSI_DIGIVOX_III) },
+	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U,
+		&af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2,
+		&af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3,
+		&af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT,
+		&af9015_props, "TrekStor DVB-T USB Stick", RC_MAP_TREKSTOR) },
+	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850,
+		&af9015_props, "AverMedia AVerTV Volar Black HD (A850)", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805,
+		&af9015_props, "AverMedia AVerTV Volar GPS 805 (A805)", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU,
+		&af9015_props, "Conceptronic USB2.0 DVB-T CTVDIGRCU V3.0", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810,
+		&af9015_props, "KWorld Digial MC-810", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03,
+		&af9015_props, "Genius TVGo DVB-T03", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2,
+		&af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T,
+		&af9015_props, "KWorld PlusTV DVB-T PCI Pro Card (DVB-T PC160-T)", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20,
+		&af9015_props, "Sveon STV20 Tuner USB DVB-T HDTV", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2,
+		&af9015_props, "DigitalNow TinyTwin v2", RC_MAP_DIGITALNOW_TINYTWIN) },
+	{ DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS,
+		&af9015_props, "Leadtek WinFast DTV2000DS", RC_MAP_LEADTEK_Y04G0051) },
+	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T,
+		&af9015_props, "KWorld USB DVB-T Stick Mobile (UB383-T)", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4,
+		&af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M,
+		&af9015_props, "AverMedia AVerTV Volar M (A815Mac)", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC,
+		&af9015_props, "TerraTec Cinergy T Stick RC", RC_MAP_TERRATEC_SLIM_2) },
+	{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC,
+		&af9015_props, "TerraTec Cinergy T Stick Dual RC", RC_MAP_TERRATEC_SLIM) },
+	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T,
+		&af9015_props, "AverMedia AVerTV Red HD+ (A850T)", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3,
+		&af9015_props, "DigitalNow TinyTwin v3", RC_MAP_DIGITALNOW_TINYTWIN) },
+	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22,
+		&af9015_props, "Sveon STV22 Dual USB DVB-T Tuner HDTV", RC_MAP_MSI_DIGIVOX_III) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, af9015_id_table);
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver af9015_usb_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = af9015_id_table,
+	.probe = dvb_usbv2_probe,
+	.disconnect = dvb_usbv2_disconnect,
+	.suspend = dvb_usbv2_suspend,
+	.resume = dvb_usbv2_resume,
+	.reset_resume = dvb_usbv2_reset_resume,
+	.no_dynamic_id = 1,
+	.soft_unbind = 1,
+};
+
+module_usb_driver(af9015_usb_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Afatech AF9015 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.h b/drivers/media/usb/dvb-usb-v2/af9015.h
new file mode 100644
index 0000000..c6b304d
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/af9015.h
@@ -0,0 +1,170 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef AF9015_H
+#define AF9015_H
+
+#include <linux/hash.h>
+#include "dvb_usb.h"
+#include "af9013.h"
+#include "dvb-pll.h"
+#include "mt2060.h"
+#include "qt1010.h"
+#include "tda18271.h"
+#include "mxl5005s.h"
+#include "mc44s803.h"
+#include "tda18218.h"
+#include "mxl5007t.h"
+
+#define DVB_USB_LOG_PREFIX "af9015"
+
+#ifdef CONFIG_DVB_USB_DEBUG
+#define dprintk(var, level, args...) \
+	do { if ((var & level)) printk(args); } while (0)
+#define DVB_USB_DEBUG_STATUS
+#else
+#define dprintk(args...)
+#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)"
+#endif
+
+#define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args)
+#define deb_rc(args...)   dprintk(dvb_usb_af9015_debug, 0x02, args)
+
+#undef err
+#define err(format, arg...) \
+	printk(KERN_ERR     DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) \
+	printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+
+/* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0.
+   We use smaller - about 1/4 from the original, 5 and 87. */
+#define TS_PACKET_SIZE            188
+
+#define TS_USB20_PACKET_COUNT      87
+#define TS_USB20_FRAME_SIZE       (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT)
+
+#define TS_USB11_PACKET_COUNT       5
+#define TS_USB11_FRAME_SIZE       (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT)
+
+#define TS_USB20_MAX_PACKET_SIZE  512
+#define TS_USB11_MAX_PACKET_SIZE   64
+
+#define AF9015_I2C_EEPROM  0xa0
+#define AF9015_I2C_DEMOD   0x38
+#define AF9015_USB_TIMEOUT 2000
+
+/* EEPROM locations */
+#define AF9015_EEPROM_IR_MODE        0x18
+#define AF9015_EEPROM_IR_REMOTE_TYPE 0x34
+#define AF9015_EEPROM_TS_MODE        0x31
+#define AF9015_EEPROM_DEMOD2_I2C     0x32
+
+#define AF9015_EEPROM_SAW_BW1        0x35
+#define AF9015_EEPROM_XTAL_TYPE1     0x36
+#define AF9015_EEPROM_SPEC_INV1      0x37
+#define AF9015_EEPROM_IF1L           0x38
+#define AF9015_EEPROM_IF1H           0x39
+#define AF9015_EEPROM_MT2060_IF1L    0x3a
+#define AF9015_EEPROM_MT2060_IF1H    0x3b
+#define AF9015_EEPROM_TUNER_ID1      0x3c
+
+#define AF9015_EEPROM_SAW_BW2        0x45
+#define AF9015_EEPROM_XTAL_TYPE2     0x46
+#define AF9015_EEPROM_SPEC_INV2      0x47
+#define AF9015_EEPROM_IF2L           0x48
+#define AF9015_EEPROM_IF2H           0x49
+#define AF9015_EEPROM_MT2060_IF2L    0x4a
+#define AF9015_EEPROM_MT2060_IF2H    0x4b
+#define AF9015_EEPROM_TUNER_ID2      0x4c
+
+#define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1)
+
+struct req_t {
+	u8  cmd;       /* [0] */
+	/*  seq */     /* [1] */
+	u8  i2c_addr;  /* [2] */
+	u16 addr;      /* [3|4] */
+	u8  mbox;      /* [5] */
+	u8  addr_len;  /* [6] */
+	u8  data_len;  /* [7] */
+	u8  *data;
+};
+
+enum af9015_cmd {
+	GET_CONFIG           = 0x10,
+	DOWNLOAD_FIRMWARE    = 0x11,
+	BOOT                 = 0x13,
+	READ_MEMORY          = 0x20,
+	WRITE_MEMORY         = 0x21,
+	READ_WRITE_I2C       = 0x22,
+	COPY_FIRMWARE        = 0x23,
+	RECONNECT_USB        = 0x5a,
+	WRITE_VIRTUAL_MEMORY = 0x26,
+	GET_IR_CODE          = 0x27,
+	READ_I2C,
+	WRITE_I2C,
+};
+
+enum af9015_ir_mode {
+	AF9015_IR_MODE_DISABLED = 0,
+	AF9015_IR_MODE_HID,
+	AF9015_IR_MODE_RLC,
+	AF9015_IR_MODE_RC6,
+	AF9015_IR_MODE_POLLING, /* just guess */
+};
+
+struct af9015_state {
+	u8 ir_mode;
+	u8 rc_repeat;
+	u32 rc_keycode;
+	u8 rc_last[4];
+	bool rc_failed;
+	u8 dual_mode;
+	u8 seq; /* packet sequence number */
+	u16 mt2060_if1[2];
+	u16 firmware_size;
+	u16 firmware_checksum;
+	u32 eeprom_sum;
+	struct af9013_config af9013_config[2];
+
+	/* for demod callback override */
+	int (*set_frontend[2]) (struct dvb_frontend *fe);
+	int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status);
+	int (*init[2]) (struct dvb_frontend *fe);
+	int (*sleep[2]) (struct dvb_frontend *fe);
+	int (*tuner_init[2]) (struct dvb_frontend *fe);
+	int (*tuner_sleep[2]) (struct dvb_frontend *fe);
+	struct mutex fe_mutex;
+};
+
+enum af9015_remote {
+	AF9015_REMOTE_NONE                    = 0,
+/* 1 */	AF9015_REMOTE_A_LINK_DTU_M,
+	AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
+	AF9015_REMOTE_MYGICTV_U718,
+	AF9015_REMOTE_DIGITTRADE_DVB_T,
+/* 5 */	AF9015_REMOTE_AVERMEDIA_KS,
+};
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
new file mode 100644
index 0000000..b700444
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -0,0 +1,1087 @@
+/*
+ * Afatech AF9035 DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "af9035.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static u16 af9035_checksum(const u8 *buf, size_t len)
+{
+	size_t i;
+	u16 checksum = 0;
+
+	for (i = 1; i < len; i++) {
+		if (i % 2)
+			checksum += buf[i] << 8;
+		else
+			checksum += buf[i];
+	}
+	checksum = ~checksum;
+
+	return checksum;
+}
+
+static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
+{
+#define BUF_LEN 64
+#define REQ_HDR_LEN 4 /* send header size */
+#define ACK_HDR_LEN 3 /* rece header size */
+#define CHECKSUM_LEN 2
+#define USB_TIMEOUT 2000
+	struct state *state = d_to_priv(d);
+	int ret, wlen, rlen;
+	u8 buf[BUF_LEN];
+	u16 checksum, tmp_checksum;
+
+	/* buffer overflow check */
+	if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) ||
+		req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) {
+		pr_debug("%s: too much data wlen=%d rlen=%d\n", __func__,
+				req->wlen, req->rlen);
+		return -EINVAL;
+	}
+
+	buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1;
+	buf[1] = req->mbox;
+	buf[2] = req->cmd;
+	buf[3] = state->seq++;
+	memcpy(&buf[REQ_HDR_LEN], req->wbuf, req->wlen);
+
+	wlen = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN;
+	rlen = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN;
+
+	/* calc and add checksum */
+	checksum = af9035_checksum(buf, buf[0] - 1);
+	buf[buf[0] - 1] = (checksum >> 8);
+	buf[buf[0] - 0] = (checksum & 0xff);
+
+	/* no ack for these packets */
+	if (req->cmd == CMD_FW_DL)
+		rlen = 0;
+
+	ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen);
+	if (ret)
+		goto err;
+
+	/* no ack for those packets */
+	if (req->cmd == CMD_FW_DL)
+		goto exit;
+
+	/* verify checksum */
+	checksum = af9035_checksum(buf, rlen - 2);
+	tmp_checksum = (buf[rlen - 2] << 8) | buf[rlen - 1];
+	if (tmp_checksum != checksum) {
+		pr_err("%s: command=%02x checksum mismatch (%04x != %04x)\n",
+				KBUILD_MODNAME, req->cmd, tmp_checksum,
+				checksum);
+		ret = -EIO;
+		goto err;
+	}
+
+	/* check status */
+	if (buf[2]) {
+		pr_debug("%s: command=%02x failed fw error=%d\n", __func__,
+				req->cmd, buf[2]);
+		ret = -EIO;
+		goto err;
+	}
+
+	/* read request, copy returned data to return buf */
+	if (req->rlen)
+		memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen);
+
+exit:
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+/* write multiple registers */
+static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len)
+{
+	u8 wbuf[6 + len];
+	u8 mbox = (reg >> 16) & 0xff;
+	struct usb_req req = { CMD_MEM_WR, mbox, sizeof(wbuf), wbuf, 0, NULL };
+
+	wbuf[0] = len;
+	wbuf[1] = 2;
+	wbuf[2] = 0;
+	wbuf[3] = 0;
+	wbuf[4] = (reg >> 8) & 0xff;
+	wbuf[5] = (reg >> 0) & 0xff;
+	memcpy(&wbuf[6], val, len);
+
+	return af9035_ctrl_msg(d, &req);
+}
+
+/* read multiple registers */
+static int af9035_rd_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len)
+{
+	u8 wbuf[] = { len, 2, 0, 0, (reg >> 8) & 0xff, reg & 0xff };
+	u8 mbox = (reg >> 16) & 0xff;
+	struct usb_req req = { CMD_MEM_RD, mbox, sizeof(wbuf), wbuf, len, val };
+
+	return af9035_ctrl_msg(d, &req);
+}
+
+/* write single register */
+static int af9035_wr_reg(struct dvb_usb_device *d, u32 reg, u8 val)
+{
+	return af9035_wr_regs(d, reg, &val, 1);
+}
+
+/* read single register */
+static int af9035_rd_reg(struct dvb_usb_device *d, u32 reg, u8 *val)
+{
+	return af9035_rd_regs(d, reg, val, 1);
+}
+
+/* write single register with mask */
+static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val,
+		u8 mask)
+{
+	int ret;
+	u8 tmp;
+
+	/* no need for read if whole reg is written */
+	if (mask != 0xff) {
+		ret = af9035_rd_regs(d, reg, &tmp, 1);
+		if (ret)
+			return ret;
+
+		val &= mask;
+		tmp &= ~mask;
+		val |= tmp;
+	}
+
+	return af9035_wr_regs(d, reg, &val, 1);
+}
+
+static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
+		struct i2c_msg msg[], int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct state *state = d_to_priv(d);
+	int ret;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	/*
+	 * I2C sub header is 5 bytes long. Meaning of those bytes are:
+	 * 0: data len
+	 * 1: I2C addr << 1
+	 * 2: reg addr len
+	 *    byte 3 and 4 can be used as reg addr
+	 * 3: reg addr MSB
+	 *    used when reg addr len is set to 2
+	 * 4: reg addr LSB
+	 *    used when reg addr len is set to 1 or 2
+	 *
+	 * For the simplify we do not use register addr at all.
+	 * NOTE: As a firmware knows tuner type there is very small possibility
+	 * there could be some tuner I2C hacks done by firmware and this may
+	 * lead problems if firmware expects those bytes are used.
+	 */
+	if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
+			(msg[1].flags & I2C_M_RD)) {
+		if (msg[0].len > 40 || msg[1].len > 40) {
+			/* TODO: correct limits > 40 */
+			ret = -EOPNOTSUPP;
+		} else if (msg[0].addr == state->af9033_config[0].i2c_addr) {
+			/* integrated demod */
+			u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
+					msg[0].buf[2];
+			ret = af9035_rd_regs(d, reg, &msg[1].buf[0],
+					msg[1].len);
+		} else {
+			/* I2C */
+			u8 buf[5 + msg[0].len];
+			struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf),
+					buf, msg[1].len, msg[1].buf };
+			buf[0] = msg[1].len;
+			buf[1] = msg[0].addr << 1;
+			buf[2] = 0x00; /* reg addr len */
+			buf[3] = 0x00; /* reg addr MSB */
+			buf[4] = 0x00; /* reg addr LSB */
+			memcpy(&buf[5], msg[0].buf, msg[0].len);
+			ret = af9035_ctrl_msg(d, &req);
+		}
+	} else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
+		if (msg[0].len > 40) {
+			/* TODO: correct limits > 40 */
+			ret = -EOPNOTSUPP;
+		} else if (msg[0].addr == state->af9033_config[0].i2c_addr) {
+			/* integrated demod */
+			u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
+					msg[0].buf[2];
+			ret = af9035_wr_regs(d, reg, &msg[0].buf[3],
+					msg[0].len - 3);
+		} else {
+			/* I2C */
+			u8 buf[5 + msg[0].len];
+			struct usb_req req = { CMD_I2C_WR, 0, sizeof(buf), buf,
+					0, NULL };
+			buf[0] = msg[0].len;
+			buf[1] = msg[0].addr << 1;
+			buf[2] = 0x00; /* reg addr len */
+			buf[3] = 0x00; /* reg addr MSB */
+			buf[4] = 0x00; /* reg addr LSB */
+			memcpy(&buf[5], msg[0].buf, msg[0].len);
+			ret = af9035_ctrl_msg(d, &req);
+		}
+	} else {
+		/*
+		 * We support only two kind of I2C transactions:
+		 * 1) 1 x read + 1 x write
+		 * 2) 1 x write
+		 */
+		ret = -EOPNOTSUPP;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+
+	if (ret < 0)
+		return ret;
+	else
+		return num;
+}
+
+static u32 af9035_i2c_functionality(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm af9035_i2c_algo = {
+	.master_xfer = af9035_i2c_master_xfer,
+	.functionality = af9035_i2c_functionality,
+};
+
+static int af9035_identify_state(struct dvb_usb_device *d, const char **name)
+{
+	int ret;
+	u8 wbuf[1] = { 1 };
+	u8 rbuf[4];
+	struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf,
+			sizeof(rbuf), rbuf };
+
+	ret = af9035_ctrl_msg(d, &req);
+	if (ret < 0)
+		goto err;
+
+	pr_debug("%s: reply=%*ph\n", __func__, 4, rbuf);
+	if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])
+		ret = WARM;
+	else
+		ret = COLD;
+
+	return ret;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9035_download_firmware(struct dvb_usb_device *d,
+		const struct firmware *fw)
+{
+	int ret, i, j, len;
+	u8 wbuf[1];
+	u8 rbuf[4];
+	struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
+	struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL };
+	struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
+	u8 hdr_core;
+	u16 hdr_addr, hdr_data_len, hdr_checksum;
+	#define MAX_DATA 58
+	#define HDR_SIZE 7
+
+	/*
+	 * Thanks to Daniel Glöckner <daniel-gl@gmx.net> about that info!
+	 *
+	 * byte 0: MCS 51 core
+	 *  There are two inside the AF9035 (1=Link and 2=OFDM) with separate
+	 *  address spaces
+	 * byte 1-2: Big endian destination address
+	 * byte 3-4: Big endian number of data bytes following the header
+	 * byte 5-6: Big endian header checksum, apparently ignored by the chip
+	 *  Calculated as ~(h[0]*256+h[1]+h[2]*256+h[3]+h[4]*256)
+	 */
+
+	for (i = fw->size; i > HDR_SIZE;) {
+		hdr_core = fw->data[fw->size - i + 0];
+		hdr_addr = fw->data[fw->size - i + 1] << 8;
+		hdr_addr |= fw->data[fw->size - i + 2] << 0;
+		hdr_data_len = fw->data[fw->size - i + 3] << 8;
+		hdr_data_len |= fw->data[fw->size - i + 4] << 0;
+		hdr_checksum = fw->data[fw->size - i + 5] << 8;
+		hdr_checksum |= fw->data[fw->size - i + 6] << 0;
+
+		pr_debug("%s: core=%d addr=%04x data_len=%d checksum=%04x\n",
+				__func__, hdr_core, hdr_addr, hdr_data_len,
+				hdr_checksum);
+
+		if (((hdr_core != 1) && (hdr_core != 2)) ||
+				(hdr_data_len > i)) {
+			pr_debug("%s: bad firmware\n", __func__);
+			break;
+		}
+
+		/* download begin packet */
+		req.cmd = CMD_FW_DL_BEGIN;
+		ret = af9035_ctrl_msg(d, &req);
+		if (ret < 0)
+			goto err;
+
+		/* download firmware packet(s) */
+		for (j = HDR_SIZE + hdr_data_len; j > 0; j -= MAX_DATA) {
+			len = j;
+			if (len > MAX_DATA)
+				len = MAX_DATA;
+			req_fw_dl.wlen = len;
+			req_fw_dl.wbuf = (u8 *) &fw->data[fw->size - i +
+					HDR_SIZE + hdr_data_len - j];
+			ret = af9035_ctrl_msg(d, &req_fw_dl);
+			if (ret < 0)
+				goto err;
+		}
+
+		/* download end packet */
+		req.cmd = CMD_FW_DL_END;
+		ret = af9035_ctrl_msg(d, &req);
+		if (ret < 0)
+			goto err;
+
+		i -= hdr_data_len + HDR_SIZE;
+
+		pr_debug("%s: data uploaded=%zu\n", __func__, fw->size - i);
+	}
+
+	/* firmware loaded, request boot */
+	req.cmd = CMD_FW_BOOT;
+	ret = af9035_ctrl_msg(d, &req);
+	if (ret < 0)
+		goto err;
+
+	/* ensure firmware starts */
+	wbuf[0] = 1;
+	ret = af9035_ctrl_msg(d, &req_fw_ver);
+	if (ret < 0)
+		goto err;
+
+	if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
+		pr_err("%s: firmware did not run\n", KBUILD_MODNAME);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	pr_info("%s: firmware version=%d.%d.%d.%d", KBUILD_MODNAME,
+			rbuf[0], rbuf[1], rbuf[2], rbuf[3]);
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9035_download_firmware_it9135(struct dvb_usb_device *d,
+		const struct firmware *fw)
+{
+	int ret, i, i_prev;
+	u8 wbuf[1];
+	u8 rbuf[4];
+	struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
+	struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL };
+	struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
+	#define HDR_SIZE 7
+
+	/*
+	 * There seems to be following firmware header. Meaning of bytes 0-3
+	 * is unknown.
+	 *
+	 * 0: 3
+	 * 1: 0, 1
+	 * 2: 0
+	 * 3: 1, 2, 3
+	 * 4: addr MSB
+	 * 5: addr LSB
+	 * 6: count of data bytes ?
+	 */
+
+	for (i = HDR_SIZE, i_prev = 0; i <= fw->size; i++) {
+		if (i == fw->size ||
+				(fw->data[i + 0] == 0x03 &&
+				(fw->data[i + 1] == 0x00 ||
+				fw->data[i + 1] == 0x01) &&
+				fw->data[i + 2] == 0x00)) {
+			req_fw_dl.wlen = i - i_prev;
+			req_fw_dl.wbuf = (u8 *) &fw->data[i_prev];
+			i_prev = i;
+			ret = af9035_ctrl_msg(d, &req_fw_dl);
+			if (ret < 0)
+				goto err;
+
+			pr_debug("%s: data uploaded=%d\n", __func__, i);
+		}
+	}
+
+	/* firmware loaded, request boot */
+	req.cmd = CMD_FW_BOOT;
+	ret = af9035_ctrl_msg(d, &req);
+	if (ret < 0)
+		goto err;
+
+	/* ensure firmware starts */
+	wbuf[0] = 1;
+	ret = af9035_ctrl_msg(d, &req_fw_ver);
+	if (ret < 0)
+		goto err;
+
+	if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
+		pr_err("%s: firmware did not run\n", KBUILD_MODNAME);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	pr_info("%s: firmware version=%d.%d.%d.%d", KBUILD_MODNAME,
+			rbuf[0], rbuf[1], rbuf[2], rbuf[3]);
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9035_read_config(struct dvb_usb_device *d)
+{
+	struct state *state = d_to_priv(d);
+	int ret, i, eeprom_shift = 0;
+	u8 tmp;
+	u16 tmp16;
+
+	/* check if there is dual tuners */
+	ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp);
+	if (ret < 0)
+		goto err;
+
+	state->dual_mode = tmp;
+	pr_debug("%s: dual mode=%d\n", __func__, state->dual_mode);
+
+	for (i = 0; i < state->dual_mode + 1; i++) {
+		/* tuner */
+		ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp);
+		if (ret < 0)
+			goto err;
+
+		state->af9033_config[i].tuner = tmp;
+		pr_debug("%s: [%d]tuner=%02x\n", __func__, i, tmp);
+
+		switch (tmp) {
+		case AF9033_TUNER_TUA9001:
+		case AF9033_TUNER_FC0011:
+		case AF9033_TUNER_MXL5007T:
+		case AF9033_TUNER_TDA18218:
+			state->af9033_config[i].spec_inv = 1;
+			break;
+		default:
+			pr_info("%s: tuner ID=%02x not supported, please " \
+					"report!", KBUILD_MODNAME, tmp);
+		};
+
+		/* tuner IF frequency */
+		ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp);
+		if (ret < 0)
+			goto err;
+
+		tmp16 = tmp;
+
+		ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_H + eeprom_shift, &tmp);
+		if (ret < 0)
+			goto err;
+
+		tmp16 |= tmp << 8;
+
+		pr_debug("%s: [%d]IF=%d\n", __func__, i, tmp16);
+
+		eeprom_shift = 0x10; /* shift for the 2nd tuner params */
+	}
+
+	/* get demod clock */
+	ret = af9035_rd_reg(d, 0x00d800, &tmp);
+	if (ret < 0)
+		goto err;
+
+	tmp = (tmp >> 0) & 0x0f;
+
+	for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++)
+		state->af9033_config[i].clock = clock_lut[tmp];
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9035_read_config_it9135(struct dvb_usb_device *d)
+{
+	struct state *state = d_to_priv(d);
+	int ret, i;
+	u8 tmp;
+
+	state->dual_mode = false;
+
+	/* get demod clock */
+	ret = af9035_rd_reg(d, 0x00d800, &tmp);
+	if (ret < 0)
+		goto err;
+
+	tmp = (tmp >> 0) & 0x0f;
+
+	for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++)
+		state->af9033_config[i].clock = clock_lut_it9135[tmp];
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9035_fc0011_tuner_callback(struct dvb_usb_device *d,
+		int cmd, int arg)
+{
+	int ret;
+
+	switch (cmd) {
+	case FC0011_FE_CALLBACK_POWER:
+		/* Tuner enable */
+		ret = af9035_wr_reg_mask(d, 0xd8eb, 1, 1);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg_mask(d, 0xd8ec, 1, 1);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg_mask(d, 0xd8ed, 1, 1);
+		if (ret < 0)
+			goto err;
+
+		/* LED */
+		ret = af9035_wr_reg_mask(d, 0xd8d0, 1, 1);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg_mask(d, 0xd8d1, 1, 1);
+		if (ret < 0)
+			goto err;
+
+		usleep_range(10000, 50000);
+		break;
+	case FC0011_FE_CALLBACK_RESET:
+		ret = af9035_wr_reg(d, 0xd8e9, 1);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg(d, 0xd8e8, 1);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg(d, 0xd8e7, 1);
+		if (ret < 0)
+			goto err;
+
+		usleep_range(10000, 20000);
+
+		ret = af9035_wr_reg(d, 0xd8e7, 0);
+		if (ret < 0)
+			goto err;
+
+		usleep_range(10000, 20000);
+		break;
+	default:
+		ret = -EINVAL;
+		goto err;
+	}
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9035_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
+{
+	struct state *state = d_to_priv(d);
+
+	switch (state->af9033_config[0].tuner) {
+	case AF9033_TUNER_FC0011:
+		return af9035_fc0011_tuner_callback(d, cmd, arg);
+	default:
+		break;
+	}
+
+	return -ENODEV;
+}
+
+static int af9035_frontend_callback(void *adapter_priv, int component,
+				    int cmd, int arg)
+{
+	struct i2c_adapter *adap = adapter_priv;
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+
+	switch (component) {
+	case DVB_FRONTEND_COMPONENT_TUNER:
+		return af9035_tuner_callback(d, cmd, arg);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct state *state = adap_to_priv(adap);
+	struct dvb_usb_device *d = adap_to_d(adap);
+	int ret;
+
+	if (!state->af9033_config[adap->id].tuner) {
+		/* unsupported tuner */
+		ret = -ENODEV;
+		goto err;
+	}
+
+	if (adap->id == 0) {
+		state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
+		state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL;
+
+		ret = af9035_wr_reg(d, 0x00417f,
+				state->af9033_config[1].i2c_addr);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg(d, 0x00d81a,
+				state->dual_mode);
+		if (ret < 0)
+			goto err;
+	}
+
+	/* attach demodulator */
+	adap->fe[0] = dvb_attach(af9033_attach,
+			&state->af9033_config[adap->id], &d->i2c_adap);
+	if (adap->fe[0] == NULL) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	/* disable I2C-gate */
+	adap->fe[0]->ops.i2c_gate_ctrl = NULL;
+	adap->fe[0]->callback = af9035_frontend_callback;
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static struct tua9001_config af9035_tua9001_config = {
+	.i2c_addr = 0x60,
+};
+
+static const struct fc0011_config af9035_fc0011_config = {
+	.i2c_address = 0x60,
+};
+
+static struct mxl5007t_config af9035_mxl5007t_config = {
+	.xtal_freq_hz = MxL_XTAL_24_MHZ,
+	.if_freq_hz = MxL_IF_4_57_MHZ,
+	.invert_if = 0,
+	.loop_thru_enable = 0,
+	.clk_out_enable = 0,
+	.clk_out_amp = MxL_CLKOUT_AMP_0_94V,
+};
+
+static struct tda18218_config af9035_tda18218_config = {
+	.i2c_address = 0x60,
+	.i2c_wr_max = 21,
+};
+
+static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct state *state = adap_to_priv(adap);
+	struct dvb_usb_device *d = adap_to_d(adap);
+	int ret;
+	struct dvb_frontend *fe;
+
+	switch (state->af9033_config[adap->id].tuner) {
+	case AF9033_TUNER_TUA9001:
+		/* AF9035 gpiot3 = TUA9001 RESETN
+		   AF9035 gpiot2 = TUA9001 RXEN */
+
+		/* configure gpiot2 and gpiot2 as output */
+		ret = af9035_wr_reg_mask(d, 0x00d8ec, 0x01, 0x01);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg_mask(d, 0x00d8ed, 0x01, 0x01);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg_mask(d, 0x00d8e8, 0x01, 0x01);
+		if (ret < 0)
+			goto err;
+
+		ret = af9035_wr_reg_mask(d, 0x00d8e9, 0x01, 0x01);
+		if (ret < 0)
+			goto err;
+
+		/* reset tuner */
+		ret = af9035_wr_reg_mask(d, 0x00d8e7, 0x00, 0x01);
+		if (ret < 0)
+			goto err;
+
+		usleep_range(2000, 20000);
+
+		ret = af9035_wr_reg_mask(d, 0x00d8e7, 0x01, 0x01);
+		if (ret < 0)
+			goto err;
+
+		/* activate tuner RX */
+		/* TODO: use callback for TUA9001 RXEN */
+		ret = af9035_wr_reg_mask(d, 0x00d8eb, 0x01, 0x01);
+		if (ret < 0)
+			goto err;
+
+		/* attach tuner */
+		fe = dvb_attach(tua9001_attach, adap->fe[0],
+				&d->i2c_adap, &af9035_tua9001_config);
+		break;
+	case AF9033_TUNER_FC0011:
+		fe = dvb_attach(fc0011_attach, adap->fe[0],
+				&d->i2c_adap, &af9035_fc0011_config);
+		break;
+	case AF9033_TUNER_MXL5007T:
+		ret = af9035_wr_reg(d, 0x00d8e0, 1);
+		if (ret < 0)
+			goto err;
+		ret = af9035_wr_reg(d, 0x00d8e1, 1);
+		if (ret < 0)
+			goto err;
+		ret = af9035_wr_reg(d, 0x00d8df, 0);
+		if (ret < 0)
+			goto err;
+
+		msleep(30);
+
+		ret = af9035_wr_reg(d, 0x00d8df, 1);
+		if (ret < 0)
+			goto err;
+
+		msleep(300);
+
+		ret = af9035_wr_reg(d, 0x00d8c0, 1);
+		if (ret < 0)
+			goto err;
+		ret = af9035_wr_reg(d, 0x00d8c1, 1);
+		if (ret < 0)
+			goto err;
+		ret = af9035_wr_reg(d, 0x00d8bf, 0);
+		if (ret < 0)
+			goto err;
+		ret = af9035_wr_reg(d, 0x00d8b4, 1);
+		if (ret < 0)
+			goto err;
+		ret = af9035_wr_reg(d, 0x00d8b5, 1);
+		if (ret < 0)
+			goto err;
+		ret = af9035_wr_reg(d, 0x00d8b3, 1);
+		if (ret < 0)
+			goto err;
+
+		/* attach tuner */
+		fe = dvb_attach(mxl5007t_attach, adap->fe[0],
+				&d->i2c_adap, 0x60, &af9035_mxl5007t_config);
+		break;
+	case AF9033_TUNER_TDA18218:
+		/* attach tuner */
+		fe = dvb_attach(tda18218_attach, adap->fe[0],
+				&d->i2c_adap, &af9035_tda18218_config);
+		break;
+	default:
+		fe = NULL;
+	}
+
+	if (fe == NULL) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9035_init(struct dvb_usb_device *d)
+{
+	struct state *state = d_to_priv(d);
+	int ret, i;
+	u16 frame_size = 87 * 188 / 4;
+	u8  packet_size = 512 / 4;
+	struct reg_val_mask tab[] = {
+		{ 0x80f99d, 0x01, 0x01 },
+		{ 0x80f9a4, 0x01, 0x01 },
+		{ 0x00dd11, 0x00, 0x20 },
+		{ 0x00dd11, 0x00, 0x40 },
+		{ 0x00dd13, 0x00, 0x20 },
+		{ 0x00dd13, 0x00, 0x40 },
+		{ 0x00dd11, 0x20, 0x20 },
+		{ 0x00dd88, (frame_size >> 0) & 0xff, 0xff},
+		{ 0x00dd89, (frame_size >> 8) & 0xff, 0xff},
+		{ 0x00dd0c, packet_size, 0xff},
+		{ 0x00dd11, state->dual_mode << 6, 0x40 },
+		{ 0x00dd8a, (frame_size >> 0) & 0xff, 0xff},
+		{ 0x00dd8b, (frame_size >> 8) & 0xff, 0xff},
+		{ 0x00dd0d, packet_size, 0xff },
+		{ 0x80f9a3, 0x00, 0x01 },
+		{ 0x80f9cd, 0x00, 0x01 },
+		{ 0x80f99d, 0x00, 0x01 },
+		{ 0x80f9a4, 0x00, 0x01 },
+	};
+
+	pr_debug("%s: USB speed=%d frame_size=%04x packet_size=%02x\n",
+		__func__, d->udev->speed, frame_size, packet_size);
+
+	/* init endpoints */
+	for (i = 0; i < ARRAY_SIZE(tab); i++) {
+		ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val,
+				tab[i].mask);
+		if (ret < 0)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9035_rc_query(struct dvb_usb_device *d)
+{
+	unsigned int key;
+	unsigned char b[4];
+	int ret;
+	struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b };
+
+	ret = af9035_ctrl_msg(d, &req);
+	if (ret < 0)
+		goto err;
+
+	if ((b[2] + b[3]) == 0xff) {
+		if ((b[0] + b[1]) == 0xff) {
+			/* NEC */
+			key = b[0] << 8 | b[2];
+		} else {
+			/* ext. NEC */
+			key = b[0] << 16 | b[1] << 8 | b[2];
+		}
+	} else {
+		key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
+	}
+
+	rc_keydown(d->rc_dev, key, 0);
+
+err:
+	/* ignore errors */
+	return 0;
+}
+
+static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+	int ret;
+	u8 tmp;
+
+	ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp);
+	if (ret < 0)
+		goto err;
+
+	pr_debug("%s: ir_mode=%02x\n", __func__, tmp);
+
+	/* don't activate rc if in HID mode or if not available */
+	if (tmp == 5) {
+		ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp);
+		if (ret < 0)
+			goto err;
+
+		pr_debug("%s: ir_type=%02x\n", __func__, tmp);
+
+		switch (tmp) {
+		case 0: /* NEC */
+		default:
+			rc->allowed_protos = RC_TYPE_NEC;
+			break;
+		case 1: /* RC6 */
+			rc->allowed_protos = RC_TYPE_RC6;
+			break;
+		}
+
+		rc->query = af9035_rc_query;
+		rc->interval = 500;
+
+		/* load empty to enable rc */
+		if (!rc->map_name)
+			rc->map_name = RC_MAP_EMPTY;
+	}
+
+	return 0;
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+/* interface 0 is used by DVB-T receiver and
+   interface 1 is for remote controller (HID) */
+static const struct dvb_usb_device_properties af9035_props = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+	.size_of_priv = sizeof(struct state),
+
+	.generic_bulk_ctrl_endpoint = 0x02,
+	.generic_bulk_ctrl_endpoint_response = 0x81,
+
+	.identify_state = af9035_identify_state,
+	.firmware = "dvb-usb-af9035-02.fw",
+	.download_firmware = af9035_download_firmware,
+
+	.i2c_algo = &af9035_i2c_algo,
+	.read_config = af9035_read_config,
+	.frontend_attach = af9035_frontend_attach,
+	.tuner_attach = af9035_tuner_attach,
+	.init = af9035_init,
+	.get_rc_config = af9035_get_rc_config,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188),
+		}, {
+			.stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188),
+		},
+	},
+};
+
+static const struct dvb_usb_device_properties it9135_props = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+	.size_of_priv = sizeof(struct state),
+
+	.generic_bulk_ctrl_endpoint = 0x02,
+	.generic_bulk_ctrl_endpoint_response = 0x81,
+
+	.identify_state = af9035_identify_state,
+	.firmware = "dvb-usb-it9135-01.fw",
+	.download_firmware = af9035_download_firmware_it9135,
+
+	.i2c_algo = &af9035_i2c_algo,
+	.read_config = af9035_read_config_it9135,
+	.frontend_attach = af9035_frontend_attach,
+	.tuner_attach = af9035_tuner_attach,
+	.init = af9035_init,
+	.get_rc_config = af9035_get_rc_config,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188),
+		}, {
+			.stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188),
+		},
+	},
+};
+
+static const struct usb_device_id af9035_id_table[] = {
+	{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035,
+		&af9035_props, "Afatech AF9035 reference design", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000,
+		&af9035_props, "Afatech AF9035 reference design", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1001,
+		&af9035_props, "Afatech AF9035 reference design", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1002,
+		&af9035_props, "Afatech AF9035 reference design", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1003,
+		&af9035_props, "Afatech AF9035 reference design", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK,
+		&af9035_props, "TerraTec Cinergy T Stick", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835,
+		&af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835,
+		&af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867,
+		&af9035_props, "AVerMedia HD Volar (A867)", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867,
+		&af9035_props, "AVerMedia HD Volar (A867)", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR,
+		&af9035_props, "AVerMedia Twinstar (A825)", NULL) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, af9035_id_table);
+
+static struct usb_driver af9035_usb_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = af9035_id_table,
+	.probe = dvb_usbv2_probe,
+	.disconnect = dvb_usbv2_disconnect,
+	.suspend = dvb_usbv2_suspend,
+	.resume = dvb_usbv2_resume,
+	.reset_resume = dvb_usbv2_reset_resume,
+	.no_dynamic_id = 1,
+	.soft_unbind = 1,
+};
+
+module_usb_driver(af9035_usb_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Afatech AF9035 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h
new file mode 100644
index 0000000..59ff69e
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/af9035.h
@@ -0,0 +1,111 @@
+/*
+ * Afatech AF9035 DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef AF9035_H
+#define AF9035_H
+
+#include "dvb_usb.h"
+#include "af9033.h"
+#include "tua9001.h"
+#include "fc0011.h"
+#include "mxl5007t.h"
+#include "tda18218.h"
+
+struct reg_val {
+	u32 reg;
+	u8  val;
+};
+
+struct reg_val_mask {
+	u32 reg;
+	u8  val;
+	u8  mask;
+};
+
+struct usb_req {
+	u8  cmd;
+	u8  mbox;
+	u8  wlen;
+	u8  *wbuf;
+	u8  rlen;
+	u8  *rbuf;
+};
+
+struct state {
+	u8 seq; /* packet sequence number */
+	bool dual_mode;
+
+	struct af9033_config af9033_config[2];
+};
+
+u32 clock_lut[] = {
+	20480000, /*      FPGA */
+	16384000, /* 16.38 MHz */
+	20480000, /* 20.48 MHz */
+	36000000, /* 36.00 MHz */
+	30000000, /* 30.00 MHz */
+	26000000, /* 26.00 MHz */
+	28000000, /* 28.00 MHz */
+	32000000, /* 32.00 MHz */
+	34000000, /* 34.00 MHz */
+	24000000, /* 24.00 MHz */
+	22000000, /* 22.00 MHz */
+	12000000, /* 12.00 MHz */
+};
+
+u32 clock_lut_it9135[] = {
+	12000000, /* 12.00 MHz */
+	20480000, /* 20.48 MHz */
+	36000000, /* 36.00 MHz */
+	30000000, /* 30.00 MHz */
+	26000000, /* 26.00 MHz */
+	28000000, /* 28.00 MHz */
+	32000000, /* 32.00 MHz */
+	34000000, /* 34.00 MHz */
+	24000000, /* 24.00 MHz */
+	22000000, /* 22.00 MHz */
+};
+
+/* EEPROM locations */
+#define EEPROM_IR_MODE            0x430d
+#define EEPROM_DUAL_MODE          0x4326
+#define EEPROM_IR_TYPE            0x4329
+#define EEPROM_1_IFFREQ_L         0x432d
+#define EEPROM_1_IFFREQ_H         0x432e
+#define EEPROM_1_TUNER_ID         0x4331
+#define EEPROM_2_IFFREQ_L         0x433d
+#define EEPROM_2_IFFREQ_H         0x433e
+#define EEPROM_2_TUNER_ID         0x4341
+
+/* USB commands */
+#define CMD_MEM_RD                  0x00
+#define CMD_MEM_WR                  0x01
+#define CMD_I2C_RD                  0x02
+#define CMD_I2C_WR                  0x03
+#define CMD_IR_GET                  0x18
+#define CMD_FW_DL                   0x21
+#define CMD_FW_QUERYINFO            0x22
+#define CMD_FW_BOOT                 0x23
+#define CMD_FW_DL_BEGIN             0x24
+#define CMD_FW_DL_END               0x25
+#define CMD_FW_SCATTER_WR           0x29
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c
new file mode 100644
index 0000000..b430bca
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/anysee.c
@@ -0,0 +1,1327 @@
+/*
+ * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * TODO:
+ * - add smart card reader support for Conditional Access (CA)
+ *
+ * Card reader in Anysee is nothing more than ISO 7816 card reader.
+ * There is no hardware CAM in any Anysee device sold.
+ * In my understanding it should be implemented by making own module
+ * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
+ * module registers serial interface that can be used to communicate
+ * with any ISO 7816 smart card.
+ *
+ * Any help according to implement serial smart card reader support
+ * is highly welcome!
+ */
+
+#include "anysee.h"
+#include "dvb-pll.h"
+#include "tda1002x.h"
+#include "mt352.h"
+#include "mt352_priv.h"
+#include "zl10353.h"
+#include "tda18212.h"
+#include "cx24116.h"
+#include "stv0900.h"
+#include "stv6110.h"
+#include "isl6423.h"
+#include "cxd2820r.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+static DEFINE_MUTEX(anysee_usb_mutex);
+
+static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
+	u8 *rbuf, u8 rlen)
+{
+	struct anysee_state *state = d_to_priv(d);
+	int act_len, ret, i;
+	u8 buf[64];
+
+	memcpy(&buf[0], sbuf, slen);
+	buf[60] = state->seq++;
+
+	mutex_lock(&anysee_usb_mutex);
+
+	dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, slen, buf);
+
+	/* We need receive one message more after dvb_usb_generic_rw due
+	   to weird transaction flow, which is 1 x send + 2 x receive. */
+	ret = dvb_usbv2_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf));
+	if (ret)
+		goto error_unlock;
+
+	/* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32
+	 * (EPIPE, Broken pipe). Function supports currently msleep() as a
+	 * parameter but I would not like to use it, since according to
+	 * Documentation/timers/timers-howto.txt it should not be used such
+	 * short, under < 20ms, sleeps. Repeating failed message would be
+	 * better choice as not to add unwanted delays...
+	 * Fixing that correctly is one of those or both;
+	 * 1) use repeat if possible
+	 * 2) add suitable delay
+	 */
+
+	/* get answer, retry few times if error returned */
+	for (i = 0; i < 3; i++) {
+		/* receive 2nd answer */
+		ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
+			d->props->generic_bulk_ctrl_endpoint), buf, sizeof(buf),
+			&act_len, 2000);
+
+		if (ret) {
+			dev_dbg(&d->udev->dev, "%s: recv bulk message " \
+					"failed=%d\n", __func__, ret);
+		} else {
+			dev_dbg(&d->udev->dev, "%s: <<< %*ph\n", __func__,
+					rlen, buf);
+
+			if (buf[63] != 0x4f)
+				dev_dbg(&d->udev->dev, "%s: cmd failed\n",
+						__func__);
+
+			break;
+		}
+	}
+
+	if (ret) {
+		/* all retries failed, it is fatal */
+		dev_err(&d->udev->dev, "%s: recv bulk message failed=%d\n",
+				KBUILD_MODNAME, ret);
+		goto error_unlock;
+	}
+
+	/* read request, copy returned data to return buf */
+	if (rbuf && rlen)
+		memcpy(rbuf, buf, rlen);
+
+error_unlock:
+	mutex_unlock(&anysee_usb_mutex);
+
+	return ret;
+}
+
+static int anysee_read_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
+{
+	u8 buf[] = {CMD_REG_READ, reg >> 8, reg & 0xff, 0x01};
+	int ret;
+	ret = anysee_ctrl_msg(d, buf, sizeof(buf), val, 1);
+	dev_dbg(&d->udev->dev, "%s: reg=%04x val=%02x\n", __func__, reg, *val);
+	return ret;
+}
+
+static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val)
+{
+	u8 buf[] = {CMD_REG_WRITE, reg >> 8, reg & 0xff, 0x01, val};
+	dev_dbg(&d->udev->dev, "%s: reg=%04x val=%02x\n", __func__, reg, val);
+	return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+}
+
+/* write single register with mask */
+static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val,
+	u8 mask)
+{
+	int ret;
+	u8 tmp;
+
+	/* no need for read if whole reg is written */
+	if (mask != 0xff) {
+		ret = anysee_read_reg(d, reg, &tmp);
+		if (ret)
+			return ret;
+
+		val &= mask;
+		tmp &= ~mask;
+		val |= tmp;
+	}
+
+	return anysee_write_reg(d, reg, val);
+}
+
+/* read single register with mask */
+static int anysee_rd_reg_mask(struct dvb_usb_device *d, u16 reg, u8 *val,
+	u8 mask)
+{
+	int ret, i;
+	u8 tmp;
+
+	ret = anysee_read_reg(d, reg, &tmp);
+	if (ret)
+		return ret;
+
+	tmp &= mask;
+
+	/* find position of the first bit */
+	for (i = 0; i < 8; i++) {
+		if ((mask >> i) & 0x01)
+			break;
+	}
+	*val = tmp >> i;
+
+	return 0;
+}
+
+static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id)
+{
+	u8 buf[] = {CMD_GET_HW_INFO};
+	return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3);
+}
+
+static int anysee_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+	u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00};
+	dev_dbg(&fe_to_d(fe)->udev->dev, "%s: onoff=%d\n", __func__, onoff);
+	return anysee_ctrl_msg(fe_to_d(fe), buf, sizeof(buf), NULL, 0);
+}
+
+static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval)
+{
+	u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x01, mode, interval};
+	dev_dbg(&d->udev->dev, "%s: state=%d interval=%d\n", __func__,
+			mode, interval);
+	return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+}
+
+static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff)
+{
+	u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x02, onoff};
+	dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
+	return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+}
+
+/* I2C */
+static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+	int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int ret = 0, inc, i = 0;
+	u8 buf[52]; /* 4 + 48 (I2C WR USB command header + I2C WR max) */
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	while (i < num) {
+		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+			if (msg[i].len > 2 || msg[i+1].len > 60) {
+				ret = -EOPNOTSUPP;
+				break;
+			}
+			buf[0] = CMD_I2C_READ;
+			buf[1] = (msg[i].addr << 1) | 0x01;
+			buf[2] = msg[i].buf[0];
+			buf[3] = msg[i].buf[1];
+			buf[4] = msg[i].len-1;
+			buf[5] = msg[i+1].len;
+			ret = anysee_ctrl_msg(d, buf, 6, msg[i+1].buf,
+				msg[i+1].len);
+			inc = 2;
+		} else {
+			if (msg[i].len > 48) {
+				ret = -EOPNOTSUPP;
+				break;
+			}
+			buf[0] = CMD_I2C_WRITE;
+			buf[1] = (msg[i].addr << 1);
+			buf[2] = msg[i].len;
+			buf[3] = 0x01;
+			memcpy(&buf[4], msg[i].buf, msg[i].len);
+			ret = anysee_ctrl_msg(d, buf, 4 + msg[i].len, NULL, 0);
+			inc = 1;
+		}
+		if (ret)
+			break;
+
+		i += inc;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+
+	return ret ? ret : i;
+}
+
+static u32 anysee_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm anysee_i2c_algo = {
+	.master_xfer   = anysee_master_xfer,
+	.functionality = anysee_i2c_func,
+};
+
+static int anysee_mt352_demod_init(struct dvb_frontend *fe)
+{
+	static u8 clock_config[]   = { CLOCK_CTL,  0x38, 0x28 };
+	static u8 reset[]          = { RESET,      0x80 };
+	static u8 adc_ctl_1_cfg[]  = { ADC_CTL_1,  0x40 };
+	static u8 agc_cfg[]        = { AGC_TARGET, 0x28, 0x20 };
+	static u8 gpp_ctl_cfg[]    = { GPP_CTL,    0x33 };
+	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(200);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+	return 0;
+}
+
+/* Callbacks for DVB USB */
+static struct tda10023_config anysee_tda10023_config = {
+	.demod_address = (0x1a >> 1),
+	.invert = 0,
+	.xtal   = 16000000,
+	.pll_m  = 11,
+	.pll_p  = 3,
+	.pll_n  = 1,
+	.output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C,
+	.deltaf = 0xfeeb,
+};
+
+static struct mt352_config anysee_mt352_config = {
+	.demod_address = (0x1e >> 1),
+	.demod_init    = anysee_mt352_demod_init,
+};
+
+static struct zl10353_config anysee_zl10353_config = {
+	.demod_address = (0x1e >> 1),
+	.parallel_ts = 1,
+};
+
+static struct zl10353_config anysee_zl10353_tda18212_config2 = {
+	.demod_address = (0x1e >> 1),
+	.parallel_ts = 1,
+	.disable_i2c_gate_ctrl = 1,
+	.no_tuner = 1,
+	.if2 = 41500,
+};
+
+static struct zl10353_config anysee_zl10353_tda18212_config = {
+	.demod_address = (0x18 >> 1),
+	.parallel_ts = 1,
+	.disable_i2c_gate_ctrl = 1,
+	.no_tuner = 1,
+	.if2 = 41500,
+};
+
+static struct tda10023_config anysee_tda10023_tda18212_config = {
+	.demod_address = (0x1a >> 1),
+	.xtal   = 16000000,
+	.pll_m  = 12,
+	.pll_p  = 3,
+	.pll_n  = 1,
+	.output_mode = TDA10023_OUTPUT_MODE_PARALLEL_B,
+	.deltaf = 0xba02,
+};
+
+static struct tda18212_config anysee_tda18212_config = {
+	.i2c_address = (0xc0 >> 1),
+	.if_dvbt_6 = 4150,
+	.if_dvbt_7 = 4150,
+	.if_dvbt_8 = 4150,
+	.if_dvbc = 5000,
+};
+
+static struct tda18212_config anysee_tda18212_config2 = {
+	.i2c_address = 0x60 /* (0xc0 >> 1) */,
+	.if_dvbt_6 = 3550,
+	.if_dvbt_7 = 3700,
+	.if_dvbt_8 = 4150,
+	.if_dvbt2_6 = 3250,
+	.if_dvbt2_7 = 4000,
+	.if_dvbt2_8 = 4000,
+	.if_dvbc = 5000,
+};
+
+static struct cx24116_config anysee_cx24116_config = {
+	.demod_address = (0xaa >> 1),
+	.mpg_clk_pos_pol = 0x00,
+	.i2c_wr_max = 48,
+};
+
+static struct stv0900_config anysee_stv0900_config = {
+	.demod_address = (0xd0 >> 1),
+	.demod_mode = 0,
+	.xtal = 8000000,
+	.clkmode = 3,
+	.diseqc_mode = 2,
+	.tun1_maddress = 0,
+	.tun1_adc = 1, /* 1 Vpp */
+	.path1_mode = 3,
+};
+
+static struct stv6110_config anysee_stv6110_config = {
+	.i2c_address = (0xc0 >> 1),
+	.mclk = 16000000,
+	.clk_div = 1,
+};
+
+static struct isl6423_config anysee_isl6423_config = {
+	.current_max = SEC_CURRENT_800m,
+	.curlim  = SEC_CURRENT_LIM_OFF,
+	.mod_extern = 1,
+	.addr = (0x10 >> 1),
+};
+
+static struct cxd2820r_config anysee_cxd2820r_config = {
+	.i2c_address = 0x6d, /* (0xda >> 1) */
+	.ts_mode = 0x38,
+};
+
+/*
+ * New USB device strings: Mfr=1, Product=2, SerialNumber=0
+ * Manufacturer: AMT.CO.KR
+ *
+ * E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=????????
+ * PCB: ?
+ * parts: DNOS404ZH102A(MT352, DTT7579(?))
+ *
+ * E30 VID=04b4 PID=861f HW=2 FW=2.1 "anysee-T(LP)"
+ * PCB: PCB 507T (rev1.61)
+ * parts: DNOS404ZH103A(ZL10353, DTT7579(?))
+ * OEA=0a OEB=00 OEC=00 OED=ff OEE=00
+ * IOA=45 IOB=ff IOC=00 IOD=ff IOE=00
+ *
+ * E30 Plus VID=04b4 PID=861f HW=6 FW=1.0 "anysee"
+ * PCB: 507CD (rev1.1)
+ * parts: DNOS404ZH103A(ZL10353, DTT7579(?)), CST56I01
+ * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe
+ * IOA=4f IOB=ff IOC=00 IOD=06 IOE=01
+ * IOD[0] ZL10353 1=enabled
+ * IOA[7] TS 0=enabled
+ * tuner is not behind ZL10353 I2C-gate (no care if gate disabled or not)
+ *
+ * E30 C Plus VID=04b4 PID=861f HW=10 FW=1.0 "anysee-DC(LP)"
+ * PCB: 507DC (rev0.2)
+ * parts: TDA10023, DTOS403IH102B TM, CST56I01
+ * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe
+ * IOA=4f IOB=ff IOC=00 IOD=26 IOE=01
+ * IOD[0] TDA10023 1=enabled
+ *
+ * E30 S2 Plus VID=04b4 PID=861f HW=11 FW=0.1 "anysee-S2(LP)"
+ * PCB: 507SI (rev2.1)
+ * parts: BS2N10WCC01(CX24116, CX24118), ISL6423, TDA8024
+ * OEA=80 OEB=00 OEC=ff OED=ff OEE=fe
+ * IOA=4d IOB=ff IOC=00 IOD=26 IOE=01
+ * IOD[0] CX24116 1=enabled
+ *
+ * E30 C Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
+ * PCB: 507FA (rev0.4)
+ * parts: TDA10023, DTOS403IH102B TM, TDA8024
+ * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff
+ * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0
+ * IOD[5] TDA10023 1=enabled
+ * IOE[0] tuner 1=enabled
+ *
+ * E30 Combo Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
+ * PCB: 507FA (rev1.1)
+ * parts: ZL10353, TDA10023, DTOS403IH102B TM, TDA8024
+ * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff
+ * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0
+ * DVB-C:
+ * IOD[5] TDA10023 1=enabled
+ * IOE[0] tuner 1=enabled
+ * DVB-T:
+ * IOD[0] ZL10353 1=enabled
+ * IOE[0] tuner 0=enabled
+ * tuner is behind ZL10353 I2C-gate
+ *
+ * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)"
+ * PCB: 508TC (rev0.6)
+ * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212)
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
+ * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4
+ * IOA[7] TS 1=enabled
+ * IOE[4] TDA18212 1=enabled
+ * DVB-C:
+ * IOD[6] ZL10353 0=disabled
+ * IOD[5] TDA10023 1=enabled
+ * IOE[0] IF 1=enabled
+ * DVB-T:
+ * IOD[5] TDA10023 0=disabled
+ * IOD[6] ZL10353 1=enabled
+ * IOE[0] IF 0=enabled
+ *
+ * E7 S2 VID=1c73 PID=861f HW=19 FW=0.4 AMTCI=0.5 "anysee-E7S2(LP)"
+ * PCB: 508S2 (rev0.7)
+ * parts: DNBU10512IST(STV0903, STV6110), ISL6423
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
+ * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4
+ * IOA[7] TS 1=enabled
+ * IOE[5] STV0903 1=enabled
+ *
+ * E7 T2C VID=1c73 PID=861f HW=20 FW=0.1 AMTCI=0.5 "anysee-E7T2C(LP)"
+ * PCB: 508T2C (rev0.3)
+ * parts: DNOQ44QCH106A(CXD2820R, TDA18212), TDA8024
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
+ * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4
+ * IOA[7] TS 1=enabled
+ * IOE[5] CXD2820R 1=enabled
+ *
+ * E7 PTC VID=1c73 PID=861f HW=21 FW=0.1 AMTCI=?? "anysee-E7PTC(LP)"
+ * PCB: 508PTC (rev0.5)
+ * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212)
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
+ * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4
+ * IOA[7] TS 1=enabled
+ * IOE[4] TDA18212 1=enabled
+ * DVB-C:
+ * IOD[6] ZL10353 0=disabled
+ * IOD[5] TDA10023 1=enabled
+ * IOE[0] IF 1=enabled
+ * DVB-T:
+ * IOD[5] TDA10023 0=disabled
+ * IOD[6] ZL10353 1=enabled
+ * IOE[0] IF 0=enabled
+ *
+ * E7 PS2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)"
+ * PCB: 508PS2 (rev0.4)
+ * parts: DNBU10512IST(STV0903, STV6110), ISL6423
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
+ * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4
+ * IOA[7] TS 1=enabled
+ * IOE[5] STV0903 1=enabled
+ */
+
+static int anysee_read_config(struct dvb_usb_device *d)
+{
+	struct anysee_state *state = d_to_priv(d);
+	int ret;
+	u8 hw_info[3];
+
+	/*
+	 * Check which hardware we have.
+	 * We must do this call two times to get reliable values (hw/fw bug).
+	 */
+	ret = anysee_get_hw_info(d, hw_info);
+	if (ret)
+		goto error;
+
+	ret = anysee_get_hw_info(d, hw_info);
+	if (ret)
+		goto error;
+
+	/*
+	 * Meaning of these info bytes are guessed.
+	 */
+	dev_info(&d->udev->dev, "%s: firmware version %d.%d hardware id %d\n",
+			KBUILD_MODNAME, hw_info[1], hw_info[2], hw_info[0]);
+
+	state->hw = hw_info[0];
+error:
+	return ret;
+}
+
+/* external I2C gate used for DNOD44CDH086A(TDA18212) tuner module */
+static int anysee_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	/* enable / disable tuner access on IOE[4] */
+	return anysee_wr_reg_mask(fe_to_d(fe), REG_IOE, (enable << 4), 0x10);
+}
+
+static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff)
+{
+	struct anysee_state *state = fe_to_priv(fe);
+	struct dvb_usb_device *d = fe_to_d(fe);
+	int ret;
+	dev_dbg(&d->udev->dev, "%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+
+	/* no frontend sleep control */
+	if (onoff == 0)
+		return 0;
+
+	switch (state->hw) {
+	case ANYSEE_HW_507FA: /* 15 */
+		/* E30 Combo Plus */
+		/* E30 C Plus */
+
+		if (fe->id == 0)  {
+			/* disable DVB-T demod on IOD[0] */
+			ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 0), 0x01);
+			if (ret)
+				goto error;
+
+			/* enable DVB-C demod on IOD[5] */
+			ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20);
+			if (ret)
+				goto error;
+
+			/* enable DVB-C tuner on IOE[0] */
+			ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 0), 0x01);
+			if (ret)
+				goto error;
+		} else {
+			/* disable DVB-C demod on IOD[5] */
+			ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20);
+			if (ret)
+				goto error;
+
+			/* enable DVB-T demod on IOD[0] */
+			ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01);
+			if (ret)
+				goto error;
+
+			/* enable DVB-T tuner on IOE[0] */
+			ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 0), 0x01);
+			if (ret)
+				goto error;
+		}
+
+		break;
+	case ANYSEE_HW_508TC: /* 18 */
+	case ANYSEE_HW_508PTC: /* 21 */
+		/* E7 TC */
+		/* E7 PTC */
+
+		if (fe->id == 0)  {
+			/* disable DVB-T demod on IOD[6] */
+			ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 6), 0x40);
+			if (ret)
+				goto error;
+
+			/* enable DVB-C demod on IOD[5] */
+			ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20);
+			if (ret)
+				goto error;
+
+			/* enable IF route on IOE[0] */
+			ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 0), 0x01);
+			if (ret)
+				goto error;
+		} else {
+			/* disable DVB-C demod on IOD[5] */
+			ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20);
+			if (ret)
+				goto error;
+
+			/* enable DVB-T demod on IOD[6] */
+			ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 6), 0x40);
+			if (ret)
+				goto error;
+
+			/* enable IF route on IOE[0] */
+			ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 0), 0x01);
+			if (ret)
+				goto error;
+		}
+
+		break;
+	default:
+		ret = 0;
+	}
+
+error:
+	return ret;
+}
+
+static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct anysee_state *state = adap_to_priv(adap);
+	struct dvb_usb_device *d = adap_to_d(adap);
+	int ret;
+	u8 tmp;
+	struct i2c_msg msg[2] = {
+		{
+			.addr = anysee_tda18212_config.i2c_address,
+			.flags = 0,
+			.len = 1,
+			.buf = "\x00",
+		}, {
+			.addr = anysee_tda18212_config.i2c_address,
+			.flags = I2C_M_RD,
+			.len = 1,
+			.buf = &tmp,
+		}
+	};
+
+	switch (state->hw) {
+	case ANYSEE_HW_507T: /* 2 */
+		/* E30 */
+
+		/* attach demod */
+		adap->fe[0] = dvb_attach(mt352_attach, &anysee_mt352_config,
+				&d->i2c_adap);
+		if (adap->fe[0])
+			break;
+
+		/* attach demod */
+		adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config,
+				&d->i2c_adap);
+
+		break;
+	case ANYSEE_HW_507CD: /* 6 */
+		/* E30 Plus */
+
+		/* enable DVB-T demod on IOD[0] */
+		ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01);
+		if (ret)
+			goto error;
+
+		/* enable transport stream on IOA[7] */
+		ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80);
+		if (ret)
+			goto error;
+
+		/* attach demod */
+		adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config,
+				&d->i2c_adap);
+
+		break;
+	case ANYSEE_HW_507DC: /* 10 */
+		/* E30 C Plus */
+
+		/* enable DVB-C demod on IOD[0] */
+		ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01);
+		if (ret)
+			goto error;
+
+		/* attach demod */
+		adap->fe[0] = dvb_attach(tda10023_attach,
+				&anysee_tda10023_config, &d->i2c_adap, 0x48);
+
+		break;
+	case ANYSEE_HW_507SI: /* 11 */
+		/* E30 S2 Plus */
+
+		/* enable DVB-S/S2 demod on IOD[0] */
+		ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01);
+		if (ret)
+			goto error;
+
+		/* attach demod */
+		adap->fe[0] = dvb_attach(cx24116_attach, &anysee_cx24116_config,
+				&d->i2c_adap);
+
+		break;
+	case ANYSEE_HW_507FA: /* 15 */
+		/* E30 Combo Plus */
+		/* E30 C Plus */
+
+		/* enable tuner on IOE[4] */
+		ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 4), 0x10);
+		if (ret)
+			goto error;
+
+		/* probe TDA18212 */
+		tmp = 0;
+		ret = i2c_transfer(&d->i2c_adap, msg, 2);
+		if (ret == 2 && tmp == 0xc7)
+			dev_dbg(&d->udev->dev, "%s: TDA18212 found\n",
+					__func__);
+		else
+			tmp = 0;
+
+		/* disable tuner on IOE[4] */
+		ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 4), 0x10);
+		if (ret)
+			goto error;
+
+		/* disable DVB-T demod on IOD[0] */
+		ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 0), 0x01);
+		if (ret)
+			goto error;
+
+		/* enable DVB-C demod on IOD[5] */
+		ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20);
+		if (ret)
+			goto error;
+
+		/* attach demod */
+		if (tmp == 0xc7) {
+			/* TDA18212 config */
+			adap->fe[0] = dvb_attach(tda10023_attach,
+					&anysee_tda10023_tda18212_config,
+					&d->i2c_adap, 0x48);
+
+			/* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
+			if (adap->fe[0])
+				adap->fe[0]->ops.i2c_gate_ctrl =
+						anysee_i2c_gate_ctrl;
+		} else {
+			/* PLL config */
+			adap->fe[0] = dvb_attach(tda10023_attach,
+					&anysee_tda10023_config,
+					&d->i2c_adap, 0x48);
+		}
+
+		/* break out if first frontend attaching fails */
+		if (!adap->fe[0])
+			break;
+
+		/* disable DVB-C demod on IOD[5] */
+		ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20);
+		if (ret)
+			goto error;
+
+		/* enable DVB-T demod on IOD[0] */
+		ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01);
+		if (ret)
+			goto error;
+
+		/* attach demod */
+		if (tmp == 0xc7) {
+			/* TDA18212 config */
+			adap->fe[1] = dvb_attach(zl10353_attach,
+					&anysee_zl10353_tda18212_config2,
+					&d->i2c_adap);
+
+			/* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
+			if (adap->fe[1])
+				adap->fe[1]->ops.i2c_gate_ctrl =
+						anysee_i2c_gate_ctrl;
+		} else {
+			/* PLL config */
+			adap->fe[1] = dvb_attach(zl10353_attach,
+					&anysee_zl10353_config,
+					&d->i2c_adap);
+		}
+
+		break;
+	case ANYSEE_HW_508TC: /* 18 */
+	case ANYSEE_HW_508PTC: /* 21 */
+		/* E7 TC */
+		/* E7 PTC */
+
+		/* disable DVB-T demod on IOD[6] */
+		ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 6), 0x40);
+		if (ret)
+			goto error;
+
+		/* enable DVB-C demod on IOD[5] */
+		ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20);
+		if (ret)
+			goto error;
+
+		/* attach demod */
+		adap->fe[0] = dvb_attach(tda10023_attach,
+				&anysee_tda10023_tda18212_config,
+				&d->i2c_adap, 0x48);
+
+		/* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
+		if (adap->fe[0])
+			adap->fe[0]->ops.i2c_gate_ctrl = anysee_i2c_gate_ctrl;
+
+		/* break out if first frontend attaching fails */
+		if (!adap->fe[0])
+			break;
+
+		/* disable DVB-C demod on IOD[5] */
+		ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20);
+		if (ret)
+			goto error;
+
+		/* enable DVB-T demod on IOD[6] */
+		ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 6), 0x40);
+		if (ret)
+			goto error;
+
+		/* attach demod */
+		adap->fe[1] = dvb_attach(zl10353_attach,
+				&anysee_zl10353_tda18212_config,
+				&d->i2c_adap);
+
+		/* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
+		if (adap->fe[1])
+			adap->fe[1]->ops.i2c_gate_ctrl = anysee_i2c_gate_ctrl;
+
+		state->has_ci = true;
+
+		break;
+	case ANYSEE_HW_508S2: /* 19 */
+	case ANYSEE_HW_508PS2: /* 22 */
+		/* E7 S2 */
+		/* E7 PS2 */
+
+		/* enable DVB-S/S2 demod on IOE[5] */
+		ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 5), 0x20);
+		if (ret)
+			goto error;
+
+		/* attach demod */
+		adap->fe[0] = dvb_attach(stv0900_attach,
+				&anysee_stv0900_config, &d->i2c_adap, 0);
+
+		state->has_ci = true;
+
+		break;
+	case ANYSEE_HW_508T2C: /* 20 */
+		/* E7 T2C */
+
+		/* enable DVB-T/T2/C demod on IOE[5] */
+		ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 5), 0x20);
+		if (ret)
+			goto error;
+
+		/* attach demod */
+		adap->fe[0] = dvb_attach(cxd2820r_attach,
+				&anysee_cxd2820r_config, &d->i2c_adap);
+
+		state->has_ci = true;
+
+		break;
+	}
+
+	if (!adap->fe[0]) {
+		/* we have no frontend :-( */
+		ret = -ENODEV;
+		dev_err(&d->udev->dev, "%s: Unsupported Anysee version. " \
+				"Please report the " \
+				"<linux-media@vger.kernel.org>.\n",
+				KBUILD_MODNAME);
+	}
+error:
+	return ret;
+}
+
+static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct anysee_state *state = adap_to_priv(adap);
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct dvb_frontend *fe;
+	int ret;
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	switch (state->hw) {
+	case ANYSEE_HW_507T: /* 2 */
+		/* E30 */
+
+		/* attach tuner */
+		fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), NULL,
+				DVB_PLL_THOMSON_DTT7579);
+
+		break;
+	case ANYSEE_HW_507CD: /* 6 */
+		/* E30 Plus */
+
+		/* attach tuner */
+		fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1),
+				&d->i2c_adap, DVB_PLL_THOMSON_DTT7579);
+
+		break;
+	case ANYSEE_HW_507DC: /* 10 */
+		/* E30 C Plus */
+
+		/* attach tuner */
+		fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1),
+				&d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+
+		break;
+	case ANYSEE_HW_507SI: /* 11 */
+		/* E30 S2 Plus */
+
+		/* attach LNB controller */
+		fe = dvb_attach(isl6423_attach, adap->fe[0], &d->i2c_adap,
+				&anysee_isl6423_config);
+
+		break;
+	case ANYSEE_HW_507FA: /* 15 */
+		/* E30 Combo Plus */
+		/* E30 C Plus */
+
+		/* Try first attach TDA18212 silicon tuner on IOE[4], if that
+		 * fails attach old simple PLL. */
+
+		/* attach tuner */
+		fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
+				&anysee_tda18212_config);
+
+		if (fe && adap->fe[1]) {
+			/* attach tuner for 2nd FE */
+			fe = dvb_attach(tda18212_attach, adap->fe[1],
+					&d->i2c_adap, &anysee_tda18212_config);
+			break;
+		} else if (fe) {
+			break;
+		}
+
+		/* attach tuner */
+		fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1),
+				&d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+
+		if (fe && adap->fe[1]) {
+			/* attach tuner for 2nd FE */
+			fe = dvb_attach(dvb_pll_attach, adap->fe[0],
+					(0xc0 >> 1), &d->i2c_adap,
+					DVB_PLL_SAMSUNG_DTOS403IH102A);
+		}
+
+		break;
+	case ANYSEE_HW_508TC: /* 18 */
+	case ANYSEE_HW_508PTC: /* 21 */
+		/* E7 TC */
+		/* E7 PTC */
+
+		/* attach tuner */
+		fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
+				&anysee_tda18212_config);
+
+		if (fe) {
+			/* attach tuner for 2nd FE */
+			fe = dvb_attach(tda18212_attach, adap->fe[1],
+					&d->i2c_adap, &anysee_tda18212_config);
+		}
+
+		break;
+	case ANYSEE_HW_508S2: /* 19 */
+	case ANYSEE_HW_508PS2: /* 22 */
+		/* E7 S2 */
+		/* E7 PS2 */
+
+		/* attach tuner */
+		fe = dvb_attach(stv6110_attach, adap->fe[0],
+				&anysee_stv6110_config, &d->i2c_adap);
+
+		if (fe) {
+			/* attach LNB controller */
+			fe = dvb_attach(isl6423_attach, adap->fe[0],
+					&d->i2c_adap, &anysee_isl6423_config);
+		}
+
+		break;
+
+	case ANYSEE_HW_508T2C: /* 20 */
+		/* E7 T2C */
+
+		/* attach tuner */
+		fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
+				&anysee_tda18212_config2);
+
+		break;
+	default:
+		fe = NULL;
+	}
+
+	if (fe)
+		ret = 0;
+	else
+		ret = -ENODEV;
+
+	return ret;
+}
+
+static int anysee_rc_query(struct dvb_usb_device *d)
+{
+	u8 buf[] = {CMD_GET_IR_CODE};
+	u8 ircode[2];
+	int ret;
+
+	/* Remote controller is basic NEC using address byte 0x08.
+	   Anysee device RC query returns only two bytes, status and code,
+	   address byte is dropped. Also it does not return any value for
+	   NEC RCs having address byte other than 0x08. Due to that, we
+	   cannot use that device as standard NEC receiver.
+	   It could be possible make hack which reads whole code directly
+	   from device memory... */
+
+	ret = anysee_ctrl_msg(d, buf, sizeof(buf), ircode, sizeof(ircode));
+	if (ret)
+		return ret;
+
+	if (ircode[0]) {
+		dev_dbg(&d->udev->dev, "%s: key pressed %02x\n", __func__,
+				ircode[1]);
+		rc_keydown(d->rc_dev, 0x08 << 8 | ircode[1], 0);
+	}
+
+	return 0;
+}
+
+static int anysee_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+	rc->allowed_protos = RC_TYPE_NEC;
+	rc->query          = anysee_rc_query;
+	rc->interval       = 250;  /* windows driver uses 500ms */
+
+	return 0;
+}
+
+static int anysee_ci_read_attribute_mem(struct dvb_ca_en50221 *ci, int slot,
+	int addr)
+{
+	struct dvb_usb_device *d = ci->data;
+	int ret;
+	u8 buf[] = {CMD_CI, 0x02, 0x40 | addr >> 8, addr & 0xff, 0x00, 1};
+	u8 val;
+
+	ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1);
+	if (ret)
+		return ret;
+
+	return val;
+}
+
+static int anysee_ci_write_attribute_mem(struct dvb_ca_en50221 *ci, int slot,
+	int addr, u8 val)
+{
+	struct dvb_usb_device *d = ci->data;
+	int ret;
+	u8 buf[] = {CMD_CI, 0x03, 0x40 | addr >> 8, addr & 0xff, 0x00, 1, val};
+
+	ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int anysee_ci_read_cam_control(struct dvb_ca_en50221 *ci, int slot,
+	u8 addr)
+{
+	struct dvb_usb_device *d = ci->data;
+	int ret;
+	u8 buf[] = {CMD_CI, 0x04, 0x40, addr, 0x00, 1};
+	u8 val;
+
+	ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1);
+	if (ret)
+		return ret;
+
+	return val;
+}
+
+static int anysee_ci_write_cam_control(struct dvb_ca_en50221 *ci, int slot,
+	u8 addr, u8 val)
+{
+	struct dvb_usb_device *d = ci->data;
+	int ret;
+	u8 buf[] = {CMD_CI, 0x05, 0x40, addr, 0x00, 1, val};
+
+	ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int anysee_ci_slot_reset(struct dvb_ca_en50221 *ci, int slot)
+{
+	struct dvb_usb_device *d = ci->data;
+	int ret;
+	struct anysee_state *state = d_to_priv(d);
+
+	state->ci_cam_ready = jiffies + msecs_to_jiffies(1000);
+
+	ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80);
+	if (ret)
+		return ret;
+
+	msleep(300);
+
+	ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int anysee_ci_slot_shutdown(struct dvb_ca_en50221 *ci, int slot)
+{
+	struct dvb_usb_device *d = ci->data;
+	int ret;
+
+	ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80);
+	if (ret)
+		return ret;
+
+	msleep(30);
+
+	ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int anysee_ci_slot_ts_enable(struct dvb_ca_en50221 *ci, int slot)
+{
+	struct dvb_usb_device *d = ci->data;
+	int ret;
+
+	ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 1), 0x02);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int anysee_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot,
+	int open)
+{
+	struct dvb_usb_device *d = ci->data;
+	struct anysee_state *state = d_to_priv(d);
+	int ret;
+	u8 tmp;
+
+	ret = anysee_rd_reg_mask(d, REG_IOC, &tmp, 0x40);
+	if (ret)
+		return ret;
+
+	if (tmp == 0) {
+		ret = DVB_CA_EN50221_POLL_CAM_PRESENT;
+		if (time_after(jiffies, state->ci_cam_ready))
+			ret |= DVB_CA_EN50221_POLL_CAM_READY;
+	}
+
+	return ret;
+}
+
+static int anysee_ci_init(struct dvb_usb_device *d)
+{
+	struct anysee_state *state = d_to_priv(d);
+	int ret;
+
+	state->ci.owner               = THIS_MODULE;
+	state->ci.read_attribute_mem  = anysee_ci_read_attribute_mem;
+	state->ci.write_attribute_mem = anysee_ci_write_attribute_mem;
+	state->ci.read_cam_control    = anysee_ci_read_cam_control;
+	state->ci.write_cam_control   = anysee_ci_write_cam_control;
+	state->ci.slot_reset          = anysee_ci_slot_reset;
+	state->ci.slot_shutdown       = anysee_ci_slot_shutdown;
+	state->ci.slot_ts_enable      = anysee_ci_slot_ts_enable;
+	state->ci.poll_slot_status    = anysee_ci_poll_slot_status;
+	state->ci.data                = d;
+
+	ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80);
+	if (ret)
+		return ret;
+
+	ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 2)|(0 << 1)|(0 << 0), 0x07);
+	if (ret)
+		return ret;
+
+	ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 2)|(1 << 1)|(1 << 0), 0x07);
+	if (ret)
+		return ret;
+
+	ret = dvb_ca_en50221_init(&d->adapter[0].dvb_adap, &state->ci, 0, 1);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void anysee_ci_release(struct dvb_usb_device *d)
+{
+	struct anysee_state *state = d_to_priv(d);
+
+	/* detach CI */
+	if (state->has_ci)
+		dvb_ca_en50221_release(&state->ci);
+
+	return;
+}
+
+static int anysee_init(struct dvb_usb_device *d)
+{
+	struct anysee_state *state = d_to_priv(d);
+	int ret;
+
+	/* There is one interface with two alternate settings.
+	   Alternate setting 0 is for bulk transfer.
+	   Alternate setting 1 is for isochronous transfer.
+	   We use bulk transfer (alternate setting 0). */
+	ret = usb_set_interface(d->udev, 0, 0);
+	if (ret)
+		return ret;
+
+	/* LED light */
+	ret = anysee_led_ctrl(d, 0x01, 0x03);
+	if (ret)
+		return ret;
+
+	/* enable IR */
+	ret = anysee_ir_ctrl(d, 1);
+	if (ret)
+		return ret;
+
+	/* attach CI */
+	if (state->has_ci) {
+		ret = anysee_ci_init(d);
+		if (ret) {
+			state->has_ci = false;
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void anysee_exit(struct dvb_usb_device *d)
+{
+	return anysee_ci_release(d);
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties anysee_props = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+	.size_of_priv = sizeof(struct anysee_state),
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+	.generic_bulk_ctrl_endpoint_response = 0x81,
+
+	.i2c_algo         = &anysee_i2c_algo,
+	.read_config      = anysee_read_config,
+	.frontend_attach  = anysee_frontend_attach,
+	.tuner_attach     = anysee_tuner_attach,
+	.init             = anysee_init,
+	.get_rc_config    = anysee_get_rc_config,
+	.frontend_ctrl    = anysee_frontend_ctrl,
+	.streaming_ctrl   = anysee_streaming_ctrl,
+	.exit             = anysee_exit,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.stream = DVB_USB_STREAM_BULK(0x82, 8, 16 * 512),
+		}
+	}
+};
+
+static const struct usb_device_id anysee_id_table[] = {
+	{ DVB_USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE,
+		&anysee_props, "Anysee", RC_MAP_ANYSEE) },
+	{ DVB_USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE,
+		&anysee_props, "Anysee", RC_MAP_ANYSEE) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, anysee_id_table);
+
+static struct usb_driver anysee_usb_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = anysee_id_table,
+	.probe = dvb_usbv2_probe,
+	.disconnect = dvb_usbv2_disconnect,
+	.suspend = dvb_usbv2_suspend,
+	.resume = dvb_usbv2_resume,
+	.reset_resume = dvb_usbv2_reset_resume,
+	.no_dynamic_id = 1,
+	.soft_unbind = 1,
+};
+
+module_usb_driver(anysee_usb_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.h b/drivers/media/usb/dvb-usb-v2/anysee.h
new file mode 100644
index 0000000..4ab4676
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/anysee.h
@@ -0,0 +1,325 @@
+/*
+ * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * TODO:
+ * - add smart card reader support for Conditional Access (CA)
+ *
+ * Card reader in Anysee is nothing more than ISO 7816 card reader.
+ * There is no hardware CAM in any Anysee device sold.
+ * In my understanding it should be implemented by making own module
+ * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
+ * module registers serial interface that can be used to communicate
+ * with any ISO 7816 smart card.
+ *
+ * Any help according to implement serial smart card reader support
+ * is highly welcome!
+ */
+
+#ifndef _DVB_USB_ANYSEE_H_
+#define _DVB_USB_ANYSEE_H_
+
+#define DVB_USB_LOG_PREFIX "anysee"
+#include "dvb_usb.h"
+#include "dvb_ca_en50221.h"
+
+enum cmd {
+	CMD_I2C_READ            = 0x33,
+	CMD_I2C_WRITE           = 0x31,
+	CMD_REG_READ            = 0xb0,
+	CMD_REG_WRITE           = 0xb1,
+	CMD_STREAMING_CTRL      = 0x12,
+	CMD_LED_AND_IR_CTRL     = 0x16,
+	CMD_GET_IR_CODE         = 0x41,
+	CMD_GET_HW_INFO         = 0x19,
+	CMD_SMARTCARD           = 0x34,
+	CMD_CI                  = 0x37,
+};
+
+struct anysee_state {
+	u8 hw; /* PCB ID */
+	u8 seq;
+	u8 fe_id:1; /* frondend ID */
+	u8 has_ci:1;
+	struct dvb_ca_en50221 ci;
+	unsigned long ci_cam_ready; /* jiffies */
+};
+
+#define ANYSEE_HW_507T    2 /* E30 */
+#define ANYSEE_HW_507CD   6 /* E30 Plus */
+#define ANYSEE_HW_507DC  10 /* E30 C Plus */
+#define ANYSEE_HW_507SI  11 /* E30 S2 Plus */
+#define ANYSEE_HW_507FA  15 /* E30 Combo Plus / E30 C Plus */
+#define ANYSEE_HW_508TC  18 /* E7 TC */
+#define ANYSEE_HW_508S2  19 /* E7 S2 */
+#define ANYSEE_HW_508T2C 20 /* E7 T2C */
+#define ANYSEE_HW_508PTC 21 /* E7 PTC Plus */
+#define ANYSEE_HW_508PS2 22 /* E7 PS2 Plus */
+
+#define REG_IOA       0x80 /* Port A (bit addressable) */
+#define REG_IOB       0x90 /* Port B (bit addressable) */
+#define REG_IOC       0xa0 /* Port C (bit addressable) */
+#define REG_IOD       0xb0 /* Port D (bit addressable) */
+#define REG_IOE       0xb1 /* Port E (NOT bit addressable) */
+#define REG_OEA       0xb2 /* Port A Output Enable */
+#define REG_OEB       0xb3 /* Port B Output Enable */
+#define REG_OEC       0xb4 /* Port C Output Enable */
+#define REG_OED       0xb5 /* Port D Output Enable */
+#define REG_OEE       0xb6 /* Port E Output Enable */
+
+#endif
+
+/***************************************************************************
+ * USB API description (reverse engineered)
+ ***************************************************************************
+
+Transaction flow:
+=================
+BULK[00001] >>> REQUEST PACKET 64 bytes
+BULK[00081] <<< REPLY PACKET #1 64 bytes (PREVIOUS TRANSACTION REPLY)
+BULK[00081] <<< REPLY PACKET #2 64 bytes (CURRENT TRANSACTION REPLY)
+
+General reply packet(s) are always used if not own reply defined.
+
+============================================================================
+| 00-63 | GENERAL REPLY PACKET #1 (PREVIOUS REPLY)
+============================================================================
+|    00 | reply data (if any) from previous transaction
+|       | Just same reply packet as returned during previous transaction.
+|       | Needed only if reply is missed in previous transaction.
+|       | Just skip normally.
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | GENERAL REPLY PACKET #2 (CURRENT REPLY)
+============================================================================
+|    00 | reply data (if any)
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | I2C WRITE REQUEST PACKET
+============================================================================
+|    00 | 0x31 I2C write command
+----------------------------------------------------------------------------
+|    01 | i2c address
+----------------------------------------------------------------------------
+|    02 | data length
+|       | 0x02 (for typical I2C reg / val pair)
+----------------------------------------------------------------------------
+|    03 | 0x01
+----------------------------------------------------------------------------
+| 04-   | data
+----------------------------------------------------------------------------
+|   -59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | I2C READ REQUEST PACKET
+============================================================================
+|    00 | 0x33 I2C read command
+----------------------------------------------------------------------------
+|    01 | i2c address + 1
+----------------------------------------------------------------------------
+|    02 | register
+----------------------------------------------------------------------------
+|    03 | 0x00
+----------------------------------------------------------------------------
+|    04 | 0x00
+----------------------------------------------------------------------------
+|    05 | data length
+----------------------------------------------------------------------------
+| 06-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | USB CONTROLLER REGISTER WRITE REQUEST PACKET
+============================================================================
+|    00 | 0xb1 register write command
+----------------------------------------------------------------------------
+| 01-02 | register
+----------------------------------------------------------------------------
+|    03 | 0x01
+----------------------------------------------------------------------------
+|    04 | value
+----------------------------------------------------------------------------
+| 05-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | USB CONTROLLER REGISTER READ REQUEST PACKET
+============================================================================
+|    00 | 0xb0 register read command
+----------------------------------------------------------------------------
+| 01-02 | register
+----------------------------------------------------------------------------
+|    03 | 0x01
+----------------------------------------------------------------------------
+| 04-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | LED CONTROL REQUEST PACKET
+============================================================================
+|    00 | 0x16 LED and IR control command
+----------------------------------------------------------------------------
+|    01 | 0x01 (LED)
+----------------------------------------------------------------------------
+|    03 | 0x00 blink
+|       | 0x01 lights continuously
+----------------------------------------------------------------------------
+|    04 | blink interval
+|       | 0x00 fastest (looks like LED lights continuously)
+|       | 0xff slowest
+----------------------------------------------------------------------------
+| 05-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | IR CONTROL REQUEST PACKET
+============================================================================
+|    00 | 0x16 LED and IR control command
+----------------------------------------------------------------------------
+|    01 | 0x02 (IR)
+----------------------------------------------------------------------------
+|    03 | 0x00 IR disabled
+|       | 0x01 IR enabled
+----------------------------------------------------------------------------
+| 04-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | STREAMING CONTROL REQUEST PACKET
+============================================================================
+|    00 | 0x12 streaming control command
+----------------------------------------------------------------------------
+|    01 | 0x00 streaming disabled
+|       | 0x01 streaming enabled
+----------------------------------------------------------------------------
+|    02 | 0x00
+----------------------------------------------------------------------------
+| 03-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | REMOTE CONTROL REQUEST PACKET
+============================================================================
+|    00 | 0x41 remote control command
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | REMOTE CONTROL REPLY PACKET
+============================================================================
+|    00 | 0x00 code not received
+|       | 0x01 code received
+----------------------------------------------------------------------------
+|    01 | remote control code
+----------------------------------------------------------------------------
+| 02-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | GET HARDWARE INFO REQUEST PACKET
+============================================================================
+|    00 | 0x19 get hardware info command
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | GET HARDWARE INFO REPLY PACKET
+============================================================================
+|    00 | hardware id
+----------------------------------------------------------------------------
+| 01-02 | firmware version
+----------------------------------------------------------------------------
+| 03-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | SMART CARD READER PACKET
+============================================================================
+|    00 | 0x34 smart card reader command
+----------------------------------------------------------------------------
+|    xx |
+----------------------------------------------------------------------------
+| xx-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+*/
diff --git a/drivers/media/usb/dvb-usb-v2/au6610.c b/drivers/media/usb/dvb-usb-v2/au6610.c
new file mode 100644
index 0000000..05f2a86
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/au6610.c
@@ -0,0 +1,206 @@
+/*
+ * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
+ *
+ * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "au6610.h"
+#include "zl10353.h"
+#include "qt1010.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
+			  u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+	int ret;
+	u16 index;
+	u8 *usb_buf;
+
+	/*
+	 * allocate enough for all known requests,
+	 * read returns 5 and write 6 bytes
+	 */
+	usb_buf = kmalloc(6, GFP_KERNEL);
+	if (!usb_buf)
+		return -ENOMEM;
+
+	switch (wlen) {
+	case 1:
+		index = wbuf[0] << 8;
+		break;
+	case 2:
+		index = wbuf[0] << 8;
+		index += wbuf[1];
+		break;
+	default:
+		pr_err("%s: wlen = %d, aborting\n", KBUILD_MODNAME, wlen);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
+			      USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index,
+			      usb_buf, 6, AU6610_USB_TIMEOUT);
+	if (ret < 0)
+		goto error;
+
+	switch (operation) {
+	case AU6610_REQ_I2C_READ:
+	case AU6610_REQ_USB_READ:
+		/* requested value is always 5th byte in buffer */
+		rbuf[0] = usb_buf[4];
+	}
+error:
+	kfree(usb_buf);
+	return ret;
+}
+
+static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr,
+			  u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+	u8 request;
+	u8 wo = (rbuf == NULL || rlen == 0); /* write-only */
+
+	if (wo) {
+		request = AU6610_REQ_I2C_WRITE;
+	} else { /* rw */
+		request = AU6610_REQ_I2C_READ;
+	}
+
+	return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen);
+}
+
+
+/* I2C */
+static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+			   int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int i;
+
+	if (num > 2)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		/* write/read request */
+		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+			if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
+					   msg[i].len, msg[i+1].buf,
+					   msg[i+1].len) < 0)
+				break;
+			i++;
+		} else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
+					       msg[i].len, NULL, 0) < 0)
+				break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return i;
+}
+
+
+static u32 au6610_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm au6610_i2c_algo = {
+	.master_xfer   = au6610_i2c_xfer,
+	.functionality = au6610_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static struct zl10353_config au6610_zl10353_config = {
+	.demod_address = 0x0f,
+	.no_tuner = 1,
+	.parallel_ts = 1,
+};
+
+static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	adap->fe[0] = dvb_attach(zl10353_attach, &au6610_zl10353_config,
+			&adap_to_d(adap)->i2c_adap);
+	if (adap->fe[0] == NULL)
+		return -ENODEV;
+
+	return 0;
+}
+
+static struct qt1010_config au6610_qt1010_config = {
+	.i2c_address = 0x62
+};
+
+static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	return dvb_attach(qt1010_attach, adap->fe[0],
+			&adap_to_d(adap)->i2c_adap,
+			&au6610_qt1010_config) == NULL ? -ENODEV : 0;
+}
+
+static int au6610_init(struct dvb_usb_device *d)
+{
+	/* TODO: this functionality belongs likely to the streaming control */
+	/* bInterfaceNumber 0, bAlternateSetting 5 */
+	return usb_set_interface(d->udev, 0, 5);
+}
+
+static struct dvb_usb_device_properties au6610_props = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+
+	.i2c_algo = &au6610_i2c_algo,
+	.frontend_attach = au6610_zl10353_frontend_attach,
+	.tuner_attach = au6610_qt1010_tuner_attach,
+	.init = au6610_init,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.stream = DVB_USB_STREAM_ISOC(0x82, 5, 40, 942, 1),
+		},
+	},
+};
+
+static const struct usb_device_id au6610_id_table[] = {
+	{ DVB_USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110,
+		&au6610_props, "Sigmatek DVB-110", NULL) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, au6610_id_table);
+
+static struct usb_driver au6610_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = au6610_id_table,
+	.probe = dvb_usbv2_probe,
+	.disconnect = dvb_usbv2_disconnect,
+	.suspend = dvb_usbv2_suspend,
+	.resume = dvb_usbv2_resume,
+	.no_dynamic_id = 1,
+	.soft_unbind = 1,
+};
+
+module_usb_driver(au6610_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/au6610.h b/drivers/media/usb/dvb-usb-v2/au6610.h
new file mode 100644
index 0000000..ea337bf
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/au6610.h
@@ -0,0 +1,32 @@
+/*
+ * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
+ *
+ * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef AU6610_H
+#define AU6610_H
+#include "dvb_usb.h"
+
+#define AU6610_REQ_I2C_WRITE	0x14
+#define AU6610_REQ_I2C_READ	0x13
+#define AU6610_REQ_USB_WRITE	0x16
+#define AU6610_REQ_USB_READ	0x15
+
+#define AU6610_USB_TIMEOUT 1000
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c
new file mode 100644
index 0000000..54f1221
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/az6007.c
@@ -0,0 +1,919 @@
+/*
+ * Driver for AzureWave 6007 DVB-C/T USB2.0 and clones
+ *
+ * Copyright (c) Henry Wang <Henry.wang@AzureWave.com>
+ *
+ * This driver was made publicly available by Terratec, at:
+ *	http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
+ * The original driver's license is GPL, as declared with MODULE_LICENSE()
+ *
+ * Copyright (c) 2010-2012 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *	Driver modified by in order to work with upstream drxk driver, and
+ *	tons of bugs got fixed, and converted to use dvb-usb-v2.
+ *
+ * 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 under version 2 of the License.
+ *
+ * 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 "drxk.h"
+#include "mt2063.h"
+#include "dvb_ca_en50221.h"
+#include "dvb_usb.h"
+#include "cypress_firmware.h"
+
+#define AZ6007_FIRMWARE "dvb-usb-terratec-h7-az6007.fw"
+
+static int az6007_xfer_debug;
+module_param_named(xfer_debug, az6007_xfer_debug, int, 0644);
+MODULE_PARM_DESC(xfer_debug, "Enable xfer debug");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* Known requests (Cypress FX2 firmware + az6007 "private" ones*/
+
+#define FX2_OED			0xb5
+#define AZ6007_READ_DATA	0xb7
+#define AZ6007_I2C_RD		0xb9
+#define AZ6007_POWER		0xbc
+#define AZ6007_I2C_WR		0xbd
+#define FX2_SCON1		0xc0
+#define AZ6007_TS_THROUGH	0xc7
+#define AZ6007_READ_IR		0xb4
+
+struct az6007_device_state {
+	struct mutex		mutex;
+	struct mutex		ca_mutex;
+	struct dvb_ca_en50221	ca;
+	unsigned		warm:1;
+	int			(*gate_ctrl) (struct dvb_frontend *, int);
+	unsigned char		data[4096];
+};
+
+static struct drxk_config terratec_h7_drxk = {
+	.adr = 0x29,
+	.parallel_ts = true,
+	.dynamic_clk = true,
+	.single_master = true,
+	.enable_merr_cfg = true,
+	.no_i2c_bridge = false,
+	.chunk_size = 64,
+	.mpeg_out_clk_strength = 0x02,
+	.qam_demod_parameter_count = 2,
+	.microcode_name = "dvb-usb-terratec-h7-drxk.fw",
+};
+
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct az6007_device_state *st = fe_to_priv(fe);
+	struct dvb_usb_adapter *adap = fe->sec_priv;
+	int status = 0;
+
+	pr_debug("%s: %s\n", __func__, enable ? "enable" : "disable");
+
+	if (!adap || !st)
+		return -EINVAL;
+
+	if (enable)
+		status = st->gate_ctrl(fe, 1);
+	else
+		status = st->gate_ctrl(fe, 0);
+
+	return status;
+}
+
+static struct mt2063_config az6007_mt2063_config = {
+	.tuner_address = 0x60,
+	.refclock = 36125000,
+};
+
+static int __az6007_read(struct usb_device *udev, u8 req, u16 value,
+			    u16 index, u8 *b, int blen)
+{
+	int ret;
+
+	ret = usb_control_msg(udev,
+			      usb_rcvctrlpipe(udev, 0),
+			      req,
+			      USB_TYPE_VENDOR | USB_DIR_IN,
+			      value, index, b, blen, 5000);
+	if (ret < 0) {
+		pr_warn("usb read operation failed. (%d)\n", ret);
+		return -EIO;
+	}
+
+	if (az6007_xfer_debug) {
+		printk(KERN_DEBUG "az6007: IN  req: %02x, value: %04x, index: %04x\n",
+		       req, value, index);
+		print_hex_dump_bytes("az6007: payload: ",
+				     DUMP_PREFIX_NONE, b, blen);
+	}
+
+	return ret;
+}
+
+static int az6007_read(struct dvb_usb_device *d, u8 req, u16 value,
+			    u16 index, u8 *b, int blen)
+{
+	struct az6007_device_state *st = d->priv;
+	int ret;
+
+	if (mutex_lock_interruptible(&st->mutex) < 0)
+		return -EAGAIN;
+
+	ret = __az6007_read(d->udev, req, value, index, b, blen);
+
+	mutex_unlock(&st->mutex);
+
+	return ret;
+}
+
+static int __az6007_write(struct usb_device *udev, u8 req, u16 value,
+			     u16 index, u8 *b, int blen)
+{
+	int ret;
+
+	if (az6007_xfer_debug) {
+		printk(KERN_DEBUG "az6007: OUT req: %02x, value: %04x, index: %04x\n",
+		       req, value, index);
+		print_hex_dump_bytes("az6007: payload: ",
+				     DUMP_PREFIX_NONE, b, blen);
+	}
+
+	if (blen > 64) {
+		pr_err("az6007: tried to write %d bytes, but I2C max size is 64 bytes\n",
+		       blen);
+		return -EOPNOTSUPP;
+	}
+
+	ret = usb_control_msg(udev,
+			      usb_sndctrlpipe(udev, 0),
+			      req,
+			      USB_TYPE_VENDOR | USB_DIR_OUT,
+			      value, index, b, blen, 5000);
+	if (ret != blen) {
+		pr_err("usb write operation failed. (%d)\n", ret);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int az6007_write(struct dvb_usb_device *d, u8 req, u16 value,
+			    u16 index, u8 *b, int blen)
+{
+	struct az6007_device_state *st = d->priv;
+	int ret;
+
+	if (mutex_lock_interruptible(&st->mutex) < 0)
+		return -EAGAIN;
+
+	ret = __az6007_write(d->udev, req, value, index, b, blen);
+
+	mutex_unlock(&st->mutex);
+
+	return ret;
+}
+
+static int az6007_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+	struct dvb_usb_device *d = fe_to_d(fe);
+
+	pr_debug("%s: %s\n", __func__, onoff ? "enable" : "disable");
+
+	return az6007_write(d, 0xbc, onoff, 0, NULL, 0);
+}
+
+/* remote control stuff (does not work with my box) */
+static int az6007_rc_query(struct dvb_usb_device *d)
+{
+	struct az6007_device_state *st = d_to_priv(d);
+	unsigned code = 0;
+
+	az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10);
+
+	if (st->data[1] == 0x44)
+		return 0;
+
+	if ((st->data[1] ^ st->data[2]) == 0xff)
+		code = st->data[1];
+	else
+		code = st->data[1] << 8 | st->data[2];
+
+	if ((st->data[3] ^ st->data[4]) == 0xff)
+		code = code << 8 | st->data[3];
+	else
+		code = code << 16 | st->data[3] << 8 | st->data[4];
+
+	rc_keydown(d->rc_dev, code, st->data[5]);
+
+	return 0;
+}
+
+static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
+					int slot,
+					int address)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6007_device_state *state = d_to_priv(d);
+
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+	u8 *b;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	b = kmalloc(12, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
+
+	mutex_lock(&state->ca_mutex);
+
+	req = 0xC1;
+	value = address;
+	index = 0;
+	blen = 1;
+
+	ret = az6007_read(d, req, value, index, b, blen);
+	if (ret < 0) {
+		pr_warn("usb in operation failed. (%d)\n", ret);
+		ret = -EINVAL;
+	} else {
+		ret = b[0];
+	}
+
+	mutex_unlock(&state->ca_mutex);
+	kfree(b);
+	return ret;
+}
+
+static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
+					 int slot,
+					 int address,
+					 u8 value)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6007_device_state *state = d_to_priv(d);
+
+	int ret;
+	u8 req;
+	u16 value1;
+	u16 index;
+	int blen;
+
+	pr_debug("%s(), slot %d\n", __func__, slot);
+	if (slot != 0)
+		return -EINVAL;
+
+	mutex_lock(&state->ca_mutex);
+	req = 0xC2;
+	value1 = address;
+	index = value;
+	blen = 0;
+
+	ret = az6007_write(d, req, value1, index, NULL, blen);
+	if (ret != 0)
+		pr_warn("usb out operation failed. (%d)\n", ret);
+
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca,
+				      int slot,
+				      u8 address)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6007_device_state *state = d_to_priv(d);
+
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+	u8 *b;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	b = kmalloc(12, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
+
+	mutex_lock(&state->ca_mutex);
+
+	req = 0xC3;
+	value = address;
+	index = 0;
+	blen = 2;
+
+	ret = az6007_read(d, req, value, index, b, blen);
+	if (ret < 0) {
+		pr_warn("usb in operation failed. (%d)\n", ret);
+		ret = -EINVAL;
+	} else {
+		if (b[0] == 0)
+			pr_warn("Read CI IO error\n");
+
+		ret = b[1];
+		pr_debug("read cam data = %x from 0x%x\n", b[1], value);
+	}
+
+	mutex_unlock(&state->ca_mutex);
+	kfree(b);
+	return ret;
+}
+
+static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca,
+				       int slot,
+				       u8 address,
+				       u8 value)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6007_device_state *state = d_to_priv(d);
+
+	int ret;
+	u8 req;
+	u16 value1;
+	u16 index;
+	int blen;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	mutex_lock(&state->ca_mutex);
+	req = 0xC4;
+	value1 = address;
+	index = value;
+	blen = 0;
+
+	ret = az6007_write(d, req, value1, index, NULL, blen);
+	if (ret != 0) {
+		pr_warn("usb out operation failed. (%d)\n", ret);
+		goto failed;
+	}
+
+failed:
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+	u8 *b;
+
+	b = kmalloc(12, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
+
+	req = 0xC8;
+	value = 0;
+	index = 0;
+	blen = 1;
+
+	ret = az6007_read(d, req, value, index, b, blen);
+	if (ret < 0) {
+		pr_warn("usb in operation failed. (%d)\n", ret);
+		ret = -EIO;
+	} else{
+		ret = b[0];
+	}
+	kfree(b);
+	return ret;
+}
+
+static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6007_device_state *state = d_to_priv(d);
+
+	int ret, i;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+
+	mutex_lock(&state->ca_mutex);
+
+	req = 0xC6;
+	value = 1;
+	index = 0;
+	blen = 0;
+
+	ret = az6007_write(d, req, value, index, NULL, blen);
+	if (ret != 0) {
+		pr_warn("usb out operation failed. (%d)\n", ret);
+		goto failed;
+	}
+
+	msleep(500);
+	req = 0xC6;
+	value = 0;
+	index = 0;
+	blen = 0;
+
+	ret = az6007_write(d, req, value, index, NULL, blen);
+	if (ret != 0) {
+		pr_warn("usb out operation failed. (%d)\n", ret);
+		goto failed;
+	}
+
+	for (i = 0; i < 15; i++) {
+		msleep(100);
+
+		if (CI_CamReady(ca, slot)) {
+			pr_debug("CAM Ready\n");
+			break;
+		}
+	}
+	msleep(5000);
+
+failed:
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+	return 0;
+}
+
+static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6007_device_state *state = d_to_priv(d);
+
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+
+	pr_debug("%s()\n", __func__);
+	mutex_lock(&state->ca_mutex);
+	req = 0xC7;
+	value = 1;
+	index = 0;
+	blen = 0;
+
+	ret = az6007_write(d, req, value, index, NULL, blen);
+	if (ret != 0) {
+		pr_warn("usb out operation failed. (%d)\n", ret);
+		goto failed;
+	}
+
+failed:
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6007_device_state *state = d_to_priv(d);
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+	u8 *b;
+
+	b = kmalloc(12, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
+	mutex_lock(&state->ca_mutex);
+
+	req = 0xC5;
+	value = 0;
+	index = 0;
+	blen = 1;
+
+	ret = az6007_read(d, req, value, index, b, blen);
+	if (ret < 0) {
+		pr_warn("usb in operation failed. (%d)\n", ret);
+		ret = -EIO;
+	} else
+		ret = 0;
+
+	if (!ret && b[0] == 1) {
+		ret = DVB_CA_EN50221_POLL_CAM_PRESENT |
+		      DVB_CA_EN50221_POLL_CAM_READY;
+	}
+
+	mutex_unlock(&state->ca_mutex);
+	kfree(b);
+	return ret;
+}
+
+
+static void az6007_ci_uninit(struct dvb_usb_device *d)
+{
+	struct az6007_device_state *state;
+
+	pr_debug("%s()\n", __func__);
+
+	if (NULL == d)
+		return;
+
+	state = d_to_priv(d);
+	if (NULL == state)
+		return;
+
+	if (NULL == state->ca.data)
+		return;
+
+	dvb_ca_en50221_release(&state->ca);
+
+	memset(&state->ca, 0, sizeof(state->ca));
+}
+
+
+static int az6007_ci_init(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct az6007_device_state *state = adap_to_priv(adap);
+	int ret;
+
+	pr_debug("%s()\n", __func__);
+
+	mutex_init(&state->ca_mutex);
+	state->ca.owner			= THIS_MODULE;
+	state->ca.read_attribute_mem	= az6007_ci_read_attribute_mem;
+	state->ca.write_attribute_mem	= az6007_ci_write_attribute_mem;
+	state->ca.read_cam_control	= az6007_ci_read_cam_control;
+	state->ca.write_cam_control	= az6007_ci_write_cam_control;
+	state->ca.slot_reset		= az6007_ci_slot_reset;
+	state->ca.slot_shutdown		= az6007_ci_slot_shutdown;
+	state->ca.slot_ts_enable	= az6007_ci_slot_ts_enable;
+	state->ca.poll_slot_status	= az6007_ci_poll_slot_status;
+	state->ca.data			= d;
+
+	ret = dvb_ca_en50221_init(&adap->dvb_adap,
+				  &state->ca,
+				  0, /* flags */
+				  1);/* n_slots */
+	if (ret != 0) {
+		pr_err("Cannot initialize CI: Error %d.\n", ret);
+		memset(&state->ca, 0, sizeof(state->ca));
+		return ret;
+	}
+
+	pr_debug("CI initialized.\n");
+
+	return 0;
+}
+
+static int az6007_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6])
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct az6007_device_state *st = adap_to_priv(adap);
+	int ret;
+
+	ret = az6007_read(d, AZ6007_READ_DATA, 6, 0, st->data, 6);
+	memcpy(mac, st->data, 6);
+
+	if (ret > 0)
+		pr_debug("%s: mac is %pM\n", __func__, mac);
+
+	return ret;
+}
+
+static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct az6007_device_state *st = adap_to_priv(adap);
+	struct dvb_usb_device *d = adap_to_d(adap);
+
+	pr_debug("attaching demod drxk\n");
+
+	adap->fe[0] = dvb_attach(drxk_attach, &terratec_h7_drxk,
+				 &d->i2c_adap);
+	if (!adap->fe[0])
+		return -EINVAL;
+
+	adap->fe[0]->sec_priv = adap;
+	st->gate_ctrl = adap->fe[0]->ops.i2c_gate_ctrl;
+	adap->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+
+	az6007_ci_init(adap);
+
+	return 0;
+}
+
+static int az6007_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+
+	pr_debug("attaching tuner mt2063\n");
+
+	/* Attach mt2063 to DVB-C frontend */
+	if (adap->fe[0]->ops.i2c_gate_ctrl)
+		adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 1);
+	if (!dvb_attach(mt2063_attach, adap->fe[0],
+			&az6007_mt2063_config,
+			&d->i2c_adap))
+		return -EINVAL;
+
+	if (adap->fe[0]->ops.i2c_gate_ctrl)
+		adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 0);
+
+	return 0;
+}
+
+static int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	struct az6007_device_state *state = d_to_priv(d);
+	int ret;
+
+	pr_debug("%s()\n", __func__);
+
+	if (!state->warm) {
+		mutex_init(&state->mutex);
+
+		ret = az6007_write(d, AZ6007_POWER, 0, 2, NULL, 0);
+		if (ret < 0)
+			return ret;
+		msleep(60);
+		ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0);
+		if (ret < 0)
+			return ret;
+		msleep(100);
+		ret = az6007_write(d, AZ6007_POWER, 1, 3, NULL, 0);
+		if (ret < 0)
+			return ret;
+		msleep(20);
+		ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0);
+		if (ret < 0)
+			return ret;
+
+		msleep(400);
+		ret = az6007_write(d, FX2_SCON1, 0, 3, NULL, 0);
+		if (ret < 0)
+			return ret;
+		msleep(150);
+		ret = az6007_write(d, FX2_SCON1, 1, 3, NULL, 0);
+		if (ret < 0)
+			return ret;
+		msleep(430);
+		ret = az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0);
+		if (ret < 0)
+			return ret;
+
+		state->warm = true;
+
+		return 0;
+	}
+
+	if (!onoff)
+		return 0;
+
+	az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0);
+	az6007_write(d, AZ6007_TS_THROUGH, 0, 0, NULL, 0);
+
+	return 0;
+}
+
+/* I2C */
+static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+			   int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct az6007_device_state *st = d_to_priv(d);
+	int i, j, len;
+	int ret = 0;
+	u16 index;
+	u16 value;
+	int length;
+	u8 req, addr;
+
+	if (mutex_lock_interruptible(&st->mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		addr = msgs[i].addr << 1;
+		if (((i + 1) < num)
+		    && (msgs[i].len == 1)
+		    && ((msgs[i].flags & I2C_M_RD) != I2C_M_RD)
+		    && (msgs[i + 1].flags & I2C_M_RD)
+		    && (msgs[i].addr == msgs[i + 1].addr)) {
+			/*
+			 * A write + read xfer for the same address, where
+			 * the first xfer has just 1 byte length.
+			 * Need to join both into one operation
+			 */
+			if (az6007_xfer_debug)
+				printk(KERN_DEBUG "az6007: I2C W/R addr=0x%x len=%d/%d\n",
+				       addr, msgs[i].len, msgs[i + 1].len);
+			req = AZ6007_I2C_RD;
+			index = msgs[i].buf[0];
+			value = addr | (1 << 8);
+			length = 6 + msgs[i + 1].len;
+			len = msgs[i + 1].len;
+			ret = __az6007_read(d->udev, req, value, index,
+					    st->data, length);
+			if (ret >= len) {
+				for (j = 0; j < len; j++)
+					msgs[i + 1].buf[j] = st->data[j + 5];
+			} else
+				ret = -EIO;
+			i++;
+		} else if (!(msgs[i].flags & I2C_M_RD)) {
+			/* write bytes */
+			if (az6007_xfer_debug)
+				printk(KERN_DEBUG "az6007: I2C W addr=0x%x len=%d\n",
+				       addr, msgs[i].len);
+			req = AZ6007_I2C_WR;
+			index = msgs[i].buf[0];
+			value = addr | (1 << 8);
+			length = msgs[i].len - 1;
+			len = msgs[i].len - 1;
+			for (j = 0; j < len; j++)
+				st->data[j] = msgs[i].buf[j + 1];
+			ret =  __az6007_write(d->udev, req, value, index,
+					      st->data, length);
+		} else {
+			/* read bytes */
+			if (az6007_xfer_debug)
+				printk(KERN_DEBUG "az6007: I2C R addr=0x%x len=%d\n",
+				       addr, msgs[i].len);
+			req = AZ6007_I2C_RD;
+			index = msgs[i].buf[0];
+			value = addr;
+			length = msgs[i].len + 6;
+			len = msgs[i].len;
+			ret = __az6007_read(d->udev, req, value, index,
+					    st->data, length);
+			for (j = 0; j < len; j++)
+				msgs[i].buf[j] = st->data[j + 5];
+		}
+		if (ret < 0)
+			goto err;
+	}
+err:
+	mutex_unlock(&st->mutex);
+
+	if (ret < 0) {
+		pr_info("%s ERROR: %i\n", __func__, ret);
+		return ret;
+	}
+	return num;
+}
+
+static u32 az6007_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm az6007_i2c_algo = {
+	.master_xfer = az6007_i2c_xfer,
+	.functionality = az6007_i2c_func,
+};
+
+static int az6007_identify_state(struct dvb_usb_device *d, const char **name)
+{
+	int ret;
+	u8 *mac;
+
+	pr_debug("Identifying az6007 state\n");
+
+	mac = kmalloc(6, GFP_ATOMIC);
+	if (!mac)
+		return -ENOMEM;
+
+	/* Try to read the mac address */
+	ret = __az6007_read(d->udev, AZ6007_READ_DATA, 6, 0, mac, 6);
+	if (ret == 6)
+		ret = WARM;
+	else
+		ret = COLD;
+
+	kfree(mac);
+
+	if (ret == COLD) {
+		__az6007_write(d->udev, 0x09, 1, 0, NULL, 0);
+		__az6007_write(d->udev, 0x00, 0, 0, NULL, 0);
+		__az6007_write(d->udev, 0x00, 0, 0, NULL, 0);
+	}
+
+	pr_debug("Device is on %s state\n",
+		 ret == WARM ? "warm" : "cold");
+	return ret;
+}
+
+static void az6007_usb_disconnect(struct usb_interface *intf)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+	az6007_ci_uninit(d);
+	dvb_usbv2_disconnect(intf);
+}
+
+static int az6007_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+	pr_debug("Getting az6007 Remote Control properties\n");
+
+	rc->allowed_protos = RC_TYPE_NEC;
+	rc->query          = az6007_rc_query;
+	rc->interval       = 400;
+
+	return 0;
+}
+
+static int az6007_download_firmware(struct dvb_usb_device *d,
+	const struct firmware *fw)
+{
+	pr_debug("Loading az6007 firmware\n");
+
+	return usbv2_cypress_load_firmware(d->udev, fw, CYPRESS_FX2);
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties az6007_props = {
+	.driver_name         = KBUILD_MODNAME,
+	.owner               = THIS_MODULE,
+	.firmware            = AZ6007_FIRMWARE,
+
+	.adapter_nr          = adapter_nr,
+	.size_of_priv        = sizeof(struct az6007_device_state),
+	.i2c_algo            = &az6007_i2c_algo,
+	.tuner_attach        = az6007_tuner_attach,
+	.frontend_attach     = az6007_frontend_attach,
+	.streaming_ctrl      = az6007_streaming_ctrl,
+	.get_rc_config       = az6007_get_rc_config,
+	.read_mac_address    = az6007_read_mac_addr,
+	.download_firmware   = az6007_download_firmware,
+	.identify_state	     = az6007_identify_state,
+	.power_ctrl          = az6007_power_ctrl,
+	.num_adapters        = 1,
+	.adapter             = {
+		{ .stream = DVB_USB_STREAM_BULK(0x02, 10, 4096), }
+	}
+};
+
+static struct usb_device_id az6007_usb_table[] = {
+	{DVB_USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007,
+		&az6007_props, "Azurewave 6007", RC_MAP_EMPTY)},
+	{DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7,
+		&az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
+	{DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2,
+		&az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
+	{0},
+};
+
+MODULE_DEVICE_TABLE(usb, az6007_usb_table);
+
+static int az6007_suspend(struct usb_interface *intf, pm_message_t msg)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+
+	az6007_ci_uninit(d);
+	return dvb_usbv2_suspend(intf, msg);
+}
+
+static int az6007_resume(struct usb_interface *intf)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+	struct dvb_usb_adapter *adap = &d->adapter[0];
+
+	az6007_ci_init(adap);
+	return dvb_usbv2_resume(intf);
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver az6007_usb_driver = {
+	.name		= KBUILD_MODNAME,
+	.id_table	= az6007_usb_table,
+	.probe		= dvb_usbv2_probe,
+	.disconnect	= az6007_usb_disconnect,
+	.no_dynamic_id	= 1,
+	.soft_unbind	= 1,
+	/*
+	 * FIXME: need to implement reset_resume, likely with
+	 * dvb-usb-v2 core support
+	 */
+	.suspend	= az6007_suspend,
+	.resume		= az6007_resume,
+};
+
+module_usb_driver(az6007_usb_driver);
+
+MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(AZ6007_FIRMWARE);
diff --git a/drivers/media/usb/dvb-usb-v2/ce6230.c b/drivers/media/usb/dvb-usb-v2/ce6230.c
new file mode 100644
index 0000000..819db9c
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/ce6230.c
@@ -0,0 +1,288 @@
+/*
+ * Intel CE6230 DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "ce6230.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
+{
+	int ret;
+	unsigned int pipe;
+	u8 request;
+	u8 requesttype;
+	u16 value;
+	u16 index;
+	u8 *buf;
+
+	request = req->cmd;
+	value = req->value;
+	index = req->index;
+
+	switch (req->cmd) {
+	case I2C_READ:
+	case DEMOD_READ:
+	case REG_READ:
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+		break;
+	case I2C_WRITE:
+	case DEMOD_WRITE:
+	case REG_WRITE:
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+		break;
+	default:
+		pr_debug("%s: unknown command=%02x\n", __func__, req->cmd);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	buf = kmalloc(req->data_len, GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
+		/* write */
+		memcpy(buf, req->data, req->data_len);
+		pipe = usb_sndctrlpipe(d->udev, 0);
+	} else {
+		/* read */
+		pipe = usb_rcvctrlpipe(d->udev, 0);
+	}
+
+	msleep(1); /* avoid I2C errors */
+
+	ret = usb_control_msg(d->udev, pipe, request, requesttype, value, index,
+			buf, req->data_len, CE6230_USB_TIMEOUT);
+
+	ce6230_debug_dump(request, requesttype, value, index, buf,
+			req->data_len);
+
+	if (ret < 0)
+		pr_err("%s: usb_control_msg() failed=%d\n", KBUILD_MODNAME,
+				ret);
+	else
+		ret = 0;
+
+	/* read request, copy returned data to return buf */
+	if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
+		memcpy(req->data, buf, req->data_len);
+
+	kfree(buf);
+error:
+	return ret;
+}
+
+/* I2C */
+static struct zl10353_config ce6230_zl10353_config;
+
+static int ce6230_i2c_master_xfer(struct i2c_adapter *adap,
+		struct i2c_msg msg[], int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int ret = 0, i = 0;
+	struct usb_req req;
+
+	if (num > 2)
+		return -EOPNOTSUPP;
+
+	memset(&req, 0, sizeof(req));
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	while (i < num) {
+		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+			if (msg[i].addr ==
+				ce6230_zl10353_config.demod_address) {
+				req.cmd = DEMOD_READ;
+				req.value = msg[i].addr >> 1;
+				req.index = msg[i].buf[0];
+				req.data_len = msg[i+1].len;
+				req.data = &msg[i+1].buf[0];
+				ret = ce6230_ctrl_msg(d, &req);
+			} else {
+				pr_err("%s: I2C read not implemented\n",
+						KBUILD_MODNAME);
+				ret = -EOPNOTSUPP;
+			}
+			i += 2;
+		} else {
+			if (msg[i].addr ==
+				ce6230_zl10353_config.demod_address) {
+				req.cmd = DEMOD_WRITE;
+				req.value = msg[i].addr >> 1;
+				req.index = msg[i].buf[0];
+				req.data_len = msg[i].len-1;
+				req.data = &msg[i].buf[1];
+				ret = ce6230_ctrl_msg(d, &req);
+			} else {
+				req.cmd = I2C_WRITE;
+				req.value = 0x2000 + (msg[i].addr >> 1);
+				req.index = 0x0000;
+				req.data_len = msg[i].len;
+				req.data = &msg[i].buf[0];
+				ret = ce6230_ctrl_msg(d, &req);
+			}
+			i += 1;
+		}
+		if (ret)
+			break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return ret ? ret : i;
+}
+
+static u32 ce6230_i2c_functionality(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm ce6230_i2c_algorithm = {
+	.master_xfer   = ce6230_i2c_master_xfer,
+	.functionality = ce6230_i2c_functionality,
+};
+
+/* Callbacks for DVB USB */
+static struct zl10353_config ce6230_zl10353_config = {
+	.demod_address = 0x1e,
+	.adc_clock = 450000,
+	.if2 = 45700,
+	.no_tuner = 1,
+	.parallel_ts = 1,
+	.clock_ctl_1 = 0x34,
+	.pll_0 = 0x0e,
+};
+
+static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	pr_debug("%s:\n", __func__);
+
+	adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
+			&adap_to_d(adap)->i2c_adap);
+	if (adap->fe[0] == NULL)
+		return -ENODEV;
+
+	return 0;
+}
+
+static struct mxl5005s_config ce6230_mxl5003s_config = {
+	.i2c_address     = 0xc6,
+	.if_freq         = IF_FREQ_4570000HZ,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_DEFAULT,
+	.rssi_enable     = MXL_RSSI_ENABLE,
+	.cap_select      = MXL_CAP_SEL_ENABLE,
+	.div_out         = MXL_DIV_OUT_4,
+	.clock_out       = MXL_CLOCK_OUT_DISABLE,
+	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+	.top		 = MXL5005S_TOP_25P2,
+	.mod_mode        = MXL_DIGITAL_MODE,
+	.if_mode         = MXL_ZERO_IF,
+	.AgcMasterByte   = 0x00,
+};
+
+static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	int ret;
+
+	pr_debug("%s:\n", __func__);
+
+	ret = dvb_attach(mxl5005s_attach, adap->fe[0],
+			&adap_to_d(adap)->i2c_adap,
+			&ce6230_mxl5003s_config) == NULL ? -ENODEV : 0;
+	return ret;
+}
+
+static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	int ret;
+
+	pr_debug("%s: onoff=%d\n", __func__, onoff);
+
+	/* InterfaceNumber 1 / AlternateSetting 0     idle
+	   InterfaceNumber 1 / AlternateSetting 1     streaming */
+	ret = usb_set_interface(d->udev, 1, onoff);
+	if (ret)
+		pr_err("%s: usb_set_interface() failed=%d\n", KBUILD_MODNAME,
+				ret);
+
+	return ret;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties ce6230_props = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+	.bInterfaceNumber = 1,
+
+	.i2c_algo = &ce6230_i2c_algorithm,
+	.power_ctrl = ce6230_power_ctrl,
+	.frontend_attach = ce6230_zl10353_frontend_attach,
+	.tuner_attach = ce6230_mxl5003s_tuner_attach,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.stream = {
+				.type = USB_BULK,
+				.count = 6,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = (16 * 512),
+					}
+				}
+			},
+		}
+	},
+};
+
+static const struct usb_device_id ce6230_id_table[] = {
+	{ DVB_USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500,
+		&ce6230_props, "Intel CE9500 reference design", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310,
+		&ce6230_props, "AVerMedia A310 USB 2.0 DVB-T tuner", NULL) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, ce6230_id_table);
+
+static struct usb_driver ce6230_usb_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = ce6230_id_table,
+	.probe = dvb_usbv2_probe,
+	.disconnect = dvb_usbv2_disconnect,
+	.suspend = dvb_usbv2_suspend,
+	.resume = dvb_usbv2_resume,
+	.reset_resume = dvb_usbv2_reset_resume,
+	.no_dynamic_id = 1,
+	.soft_unbind = 1,
+};
+
+module_usb_driver(ce6230_usb_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Intel CE6230 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/ce6230.h b/drivers/media/usb/dvb-usb-v2/ce6230.h
new file mode 100644
index 0000000..42d7544
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/ce6230.h
@@ -0,0 +1,61 @@
+/*
+ * Intel CE6230 DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef CE6230_H
+#define CE6230_H
+
+#include "dvb_usb.h"
+#include "zl10353.h"
+#include "mxl5005s.h"
+
+#define ce6230_debug_dump(r, t, v, i, b, l) { \
+	char *direction; \
+	if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
+		direction = ">>>"; \
+	else \
+		direction = "<<<"; \
+	pr_debug("%s: %02x %02x %02x %02x %02x %02x %02x %02x %s [%d bytes]\n", \
+			 __func__, t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, \
+			l & 0xff, l >> 8, direction, l); \
+}
+
+#define CE6230_USB_TIMEOUT 1000
+
+struct usb_req {
+	u8  cmd;       /* [1] */
+	u16 value;     /* [2|3] */
+	u16 index;     /* [4|5] */
+	u16 data_len;  /* [6|7] */
+	u8  *data;
+};
+
+enum ce6230_cmd {
+	CONFIG_READ          = 0xd0, /* rd 0 (unclear) */
+	UNKNOWN_WRITE        = 0xc7, /* wr 7 (unclear) */
+	I2C_READ             = 0xd9, /* rd 9 (unclear) */
+	I2C_WRITE            = 0xca, /* wr a */
+	DEMOD_READ           = 0xdb, /* rd b */
+	DEMOD_WRITE          = 0xcc, /* wr c */
+	REG_READ             = 0xde, /* rd e */
+	REG_WRITE            = 0xcf, /* wr f */
+};
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/cypress_firmware.c b/drivers/media/usb/dvb-usb-v2/cypress_firmware.c
new file mode 100644
index 0000000..9f7c970
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/cypress_firmware.c
@@ -0,0 +1,125 @@
+/*  cypress_firmware.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for downloading the firmware to Cypress FX 1
+ * and 2 based devices.
+ *
+ */
+
+#include "dvb_usb.h"
+#include "cypress_firmware.h"
+
+struct usb_cypress_controller {
+	u8 id;
+	const char *name;	/* name of the usb controller */
+	u16 cs_reg;		/* needs to be restarted,
+				 * when the firmware has been downloaded */
+};
+
+static const struct usb_cypress_controller cypress[] = {
+	{ .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cs_reg = 0x7f92 },
+	{ .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cs_reg = 0x7f92 },
+	{ .id = CYPRESS_FX2,    .name = "Cypress FX2",    .cs_reg = 0xe600 },
+};
+
+/*
+ * load a firmware packet to the device
+ */
+static int usb_cypress_writemem(struct usb_device *udev, u16 addr, u8 *data,
+		u8 len)
+{
+	return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
+}
+
+int usbv2_cypress_load_firmware(struct usb_device *udev,
+		const struct firmware *fw, int type)
+{
+	struct hexline hx;
+	u8 reset;
+	int ret, pos = 0;
+
+	/* stop the CPU */
+	reset = 1;
+	ret = usb_cypress_writemem(udev, cypress[type].cs_reg, &reset, 1);
+	if (ret != 1)
+		pr_err("%s: could not stop the USB controller CPU",
+				KBUILD_MODNAME);
+
+	while ((ret = dvb_usbv2_get_hexline(fw, &hx, &pos)) > 0) {
+		pr_debug("%s: writing to address %04x (buffer: %02x %02x)\n",
+				__func__, hx.addr, hx.len, hx.chk);
+
+		ret = usb_cypress_writemem(udev, hx.addr, hx.data, hx.len);
+		if (ret != hx.len) {
+			pr_err("%s: error while transferring firmware " \
+					"(transferred size=%d, block size=%d)",
+					KBUILD_MODNAME, ret, hx.len);
+			ret = -EINVAL;
+			break;
+		}
+	}
+	if (ret < 0) {
+		pr_err("%s: firmware download failed at %d with %d",
+				KBUILD_MODNAME, pos, ret);
+		return ret;
+	}
+
+	if (ret == 0) {
+		/* restart the CPU */
+		reset = 0;
+		if (ret || usb_cypress_writemem(
+				udev, cypress[type].cs_reg, &reset, 1) != 1) {
+			pr_err("%s: could not restart the USB controller CPU",
+					KBUILD_MODNAME);
+			ret = -EINVAL;
+		}
+	} else
+		ret = -EIO;
+
+	return ret;
+}
+EXPORT_SYMBOL(usbv2_cypress_load_firmware);
+
+int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx,
+		int *pos)
+{
+	u8 *b = (u8 *) &fw->data[*pos];
+	int data_offs = 4;
+
+	if (*pos >= fw->size)
+		return 0;
+
+	memset(hx, 0, sizeof(struct hexline));
+
+	hx->len = b[0];
+
+	if ((*pos + hx->len + 4) >= fw->size)
+		return -EINVAL;
+
+	hx->addr = b[1] | (b[2] << 8);
+	hx->type = b[3];
+
+	if (hx->type == 0x04) {
+		/* b[4] and b[5] are the Extended linear address record data
+		 * field */
+		hx->addr |= (b[4] << 24) | (b[5] << 16);
+		/*
+		hx->len -= 2;
+		data_offs += 2;
+		*/
+	}
+	memcpy(hx->data, &b[data_offs], hx->len);
+	hx->chk = b[hx->len + data_offs];
+
+	*pos += hx->len + 5;
+
+	return *pos;
+}
+EXPORT_SYMBOL(dvb_usbv2_get_hexline);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Cypress firmware download");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/cypress_firmware.h b/drivers/media/usb/dvb-usb-v2/cypress_firmware.h
new file mode 100644
index 0000000..80085fd
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/cypress_firmware.h
@@ -0,0 +1,31 @@
+/* cypress_firmware.h is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for downloading the firmware to Cypress FX 1
+ * and 2 based devices.
+ *
+ */
+
+#ifndef CYPRESS_FIRMWARE_H
+#define CYPRESS_FIRMWARE_H
+
+#define CYPRESS_AN2135  0
+#define CYPRESS_AN2235  1
+#define CYPRESS_FX2     2
+
+/* commonly used firmware download types and function */
+struct hexline {
+	u8 len;
+	u32 addr;
+	u8 type;
+	u8 data[255];
+	u8 chk;
+};
+extern int usbv2_cypress_load_firmware(struct usb_device *,
+		const struct firmware *, int);
+extern int dvb_usbv2_get_hexline(const struct firmware *,
+		struct hexline *, int *);
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
new file mode 100644
index 0000000..5a53c62
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
@@ -0,0 +1,392 @@
+/*
+ * DVB USB framework
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DVB_USB_H
+#define DVB_USB_H
+
+#include <linux/usb/input.h>
+#include <linux/firmware.h>
+#include <media/rc-core.h>
+
+#include "dvb_frontend.h"
+#include "dvb_demux.h"
+#include "dvb_net.h"
+#include "dmxdev.h"
+#include "dvb-usb-ids.h"
+
+/*
+ * device file: /dev/dvb/adapter[0-1]/frontend[0-2]
+ *
+ * |-- device
+ * |   |-- adapter0
+ * |   |   |-- frontend0
+ * |   |   |-- frontend1
+ * |   |   `-- frontend2
+ * |   `-- adapter1
+ * |       |-- frontend0
+ * |       |-- frontend1
+ * |       `-- frontend2
+ *
+ *
+ * Commonly used variable names:
+ * d = pointer to device (struct dvb_usb_device *)
+ * adap = pointer to adapter (struct dvb_usb_adapter *)
+ * fe = pointer to frontend (struct dvb_frontend *)
+ *
+ * Use macros defined in that file to resolve needed pointers.
+ */
+
+/* helper macros for every DVB USB driver use */
+#define adap_to_d(adap) (container_of(adap, struct dvb_usb_device, \
+		adapter[adap->id]))
+#define adap_to_priv(adap) (adap_to_d(adap)->priv)
+#define fe_to_adap(fe) ((struct dvb_usb_adapter *) ((fe)->dvb->priv))
+#define fe_to_d(fe) (adap_to_d(fe_to_adap(fe)))
+#define fe_to_priv(fe) (fe_to_d(fe)->priv)
+#define d_to_priv(d) (d->priv)
+
+#define DVB_USB_STREAM_BULK(endpoint_, count_, size_) { \
+	.type = USB_BULK, \
+	.count = count_, \
+	.endpoint = endpoint_, \
+	.u = { \
+		.bulk = { \
+			.buffersize = size_, \
+		} \
+	} \
+}
+
+#define DVB_USB_STREAM_ISOC(endpoint_, count_, frames_, size_, interval_) { \
+	.type = USB_ISOC, \
+	.count = count_, \
+	.endpoint = endpoint_, \
+	.u = { \
+		.isoc = { \
+			.framesperurb = frames_, \
+			.framesize = size_,\
+			.interval = interval_, \
+		} \
+	} \
+}
+
+#define DVB_USB_DEVICE(vend, prod, props_, name_, rc) \
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
+	.idVendor = (vend), \
+	.idProduct = (prod), \
+	.driver_info = (kernel_ulong_t) &((const struct dvb_usb_driver_info) { \
+		.props = (props_), \
+		.name = (name_), \
+		.rc_map = (rc), \
+	})
+
+struct dvb_usb_device;
+struct dvb_usb_adapter;
+
+/**
+ * structure for carrying all needed data from the device driver to the general
+ * dvb usb routines
+ * @name: device name
+ * @rc_map: name of rc codes table
+ * @props: structure containing all device properties
+ */
+struct dvb_usb_driver_info {
+	const char *name;
+	const char *rc_map;
+	const struct dvb_usb_device_properties *props;
+};
+
+/**
+ * structure for remote controller configuration
+ * @map_name: name of rc codes table
+ * @allowed_protos: protocol(s) supported by the driver
+ * @change_protocol: callback to change protocol
+ * @query: called to query an event from the device
+ * @interval: time in ms between two queries
+ * @driver_type: used to point if a device supports raw mode
+ * @bulk_mode: device supports bulk mode for rc (disable polling mode)
+ */
+struct dvb_usb_rc {
+	const char *map_name;
+	u64 allowed_protos;
+	int (*change_protocol)(struct rc_dev *dev, u64 rc_type);
+	int (*query) (struct dvb_usb_device *d);
+	unsigned int interval;
+	const enum rc_driver_type driver_type;
+	bool bulk_mode;
+};
+
+/**
+ * usb streaming configration for adapter
+ * @type: urb type
+ * @count: count of used urbs
+ * @endpoint: stream usb endpoint number
+ */
+struct usb_data_stream_properties {
+#define USB_BULK  1
+#define USB_ISOC  2
+	u8 type;
+	u8 count;
+	u8 endpoint;
+
+	union {
+		struct {
+			unsigned int buffersize; /* per URB */
+		} bulk;
+		struct {
+			int framesperurb;
+			int framesize;
+			int interval;
+		} isoc;
+	} u;
+};
+
+/**
+ * properties of dvb usb device adapter
+ * @caps: adapter capabilities
+ * @pid_filter_count: pid count of adapter pid-filter
+ * @pid_filter_ctrl: called to enable/disable pid-filter
+ * @pid_filter: called to set/unset pid for filtering
+ * @stream: adapter usb stream configuration
+ */
+#define MAX_NO_OF_FE_PER_ADAP 3
+struct dvb_usb_adapter_properties {
+#define DVB_USB_ADAP_HAS_PID_FILTER               0x01
+#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02
+#define DVB_USB_ADAP_NEED_PID_FILTERING           0x04
+	u8 caps;
+
+	u8 pid_filter_count;
+	int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int);
+	int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int);
+
+	struct usb_data_stream_properties stream;
+};
+
+/**
+ * struct dvb_usb_device_properties - properties of a dvb-usb-device
+ * @driver_name: name of the owning driver module
+ * @owner: owner of the dvb_adapter
+ * @adapter_nr: values from the DVB_DEFINE_MOD_OPT_ADAPTER_NR() macro
+ * @bInterfaceNumber: usb interface number driver binds
+ * @size_of_priv: bytes allocated for the driver private data
+ * @generic_bulk_ctrl_endpoint: bulk control endpoint number for sent
+ * @generic_bulk_ctrl_endpoint_response: bulk control endpoint number for
+ *  receive
+ * @generic_bulk_ctrl_delay: delay between bulk control sent and receive message
+ * @identify_state: called to determine the firmware state (cold or warm) and
+ *  return possible firmware file name to be loaded
+ * @firmware: name of the firmware file to be loaded
+ * @download_firmware: called to download the firmware
+ * @i2c_algo: i2c_algorithm if the device has i2c-adapter
+ * @num_adapters: dvb usb device adapter count
+ * @get_adapter_count: called to resolve adapter count
+ * @adapter: array of all adapter properties of device
+ * @power_ctrl: called to enable/disable power of the device
+ * @read_config: called to resolve device configuration
+ * @read_mac_address: called to resolve adapter mac-address
+ * @frontend_attach: called to attach the possible frontends
+ * @tuner_attach: called to attach the possible tuners
+ * @frontend_ctrl: called to power on/off active frontend
+ * @streaming_ctrl: called to start/stop the usb streaming of adapter
+ * @init: called after adapters are created in order to finalize device
+ *  configuration
+ * @exit: called when driver is unloaded
+ * @get_rc_config: called to resolve used remote controller configuration
+ * @get_stream_config: called to resolve input and output stream configuration
+ *  of the adapter just before streaming is started. input stream is transport
+ *  stream from the demodulator and output stream is usb stream to host.
+ */
+#define MAX_NO_OF_ADAPTER_PER_DEVICE 2
+struct dvb_usb_device_properties {
+	const char *driver_name;
+	struct module *owner;
+	short *adapter_nr;
+
+	u8 bInterfaceNumber;
+	unsigned int size_of_priv;
+	u8 generic_bulk_ctrl_endpoint;
+	u8 generic_bulk_ctrl_endpoint_response;
+	unsigned int generic_bulk_ctrl_delay;
+
+#define WARM                  0
+#define COLD                  1
+	int (*identify_state) (struct dvb_usb_device *, const char **);
+	const char *firmware;
+#define RECONNECTS_USB        1
+	int (*download_firmware) (struct dvb_usb_device *,
+			const struct firmware *);
+
+	struct i2c_algorithm *i2c_algo;
+
+	unsigned int num_adapters;
+	int (*get_adapter_count) (struct dvb_usb_device *);
+	struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
+	int (*power_ctrl) (struct dvb_usb_device *, int);
+	int (*read_config) (struct dvb_usb_device *d);
+	int (*read_mac_address) (struct dvb_usb_adapter *, u8 []);
+	int (*frontend_attach) (struct dvb_usb_adapter *);
+	int (*tuner_attach) (struct dvb_usb_adapter *);
+	int (*frontend_ctrl) (struct dvb_frontend *, int);
+	int (*streaming_ctrl) (struct dvb_frontend *, int);
+	int (*init) (struct dvb_usb_device *);
+	void (*exit) (struct dvb_usb_device *);
+	int (*get_rc_config) (struct dvb_usb_device *, struct dvb_usb_rc *);
+#define DVB_USB_FE_TS_TYPE_188        0
+#define DVB_USB_FE_TS_TYPE_204        1
+#define DVB_USB_FE_TS_TYPE_RAW        2
+	int (*get_stream_config) (struct dvb_frontend *,  u8 *,
+			struct usb_data_stream_properties *);
+};
+
+/**
+ * generic object of an usb stream
+ * @buf_num: number of buffer allocated
+ * @buf_size: size of each buffer in buf_list
+ * @buf_list: array containing all allocate buffers for streaming
+ * @dma_addr: list of dma_addr_t for each buffer in buf_list
+ *
+ * @urbs_initialized: number of URBs initialized
+ * @urbs_submitted: number of URBs submitted
+ */
+#define MAX_NO_URBS_FOR_DATA_STREAM 10
+struct usb_data_stream {
+	struct usb_device *udev;
+	struct usb_data_stream_properties props;
+
+#define USB_STATE_INIT    0x00
+#define USB_STATE_URB_BUF 0x01
+	u8 state;
+
+	void (*complete) (struct usb_data_stream *, u8 *, size_t);
+
+	struct urb    *urb_list[MAX_NO_URBS_FOR_DATA_STREAM];
+	int            buf_num;
+	unsigned long  buf_size;
+	u8            *buf_list[MAX_NO_URBS_FOR_DATA_STREAM];
+	dma_addr_t     dma_addr[MAX_NO_URBS_FOR_DATA_STREAM];
+
+	int urbs_initialized;
+	int urbs_submitted;
+
+	void *user_priv;
+};
+
+/**
+ * dvb adapter object on dvb usb device
+ * @props: pointer to adapter properties
+ * @stream: adapter the usb data stream
+ * @id: index of this adapter (starting with 0)
+ * @ts_type: transport stream, input stream, type
+ * @suspend_resume_active: set when there is ongoing suspend / resume
+ * @pid_filtering: is hardware pid_filtering used or not
+ * @feed_count: current feed count
+ * @max_feed_count: maimum feed count device can handle
+ * @dvb_adap: adapter dvb_adapter
+ * @dmxdev: adapter dmxdev
+ * @demux: adapter software demuxer
+ * @dvb_net: adapter dvb_net interfaces
+ * @sync_mutex: mutex used to sync control and streaming of the adapter
+ * @fe: adapter frontends
+ * @fe_init: rerouted frontend-init function
+ * @fe_sleep: rerouted frontend-sleep function
+ */
+struct dvb_usb_adapter {
+	const struct dvb_usb_adapter_properties *props;
+	struct usb_data_stream stream;
+	u8 id;
+	u8 ts_type;
+	bool suspend_resume_active;
+	bool pid_filtering;
+	u8 feed_count;
+	u8 max_feed_count;
+	s8 active_fe;
+
+	/* dvb */
+	struct dvb_adapter   dvb_adap;
+	struct dmxdev        dmxdev;
+	struct dvb_demux     demux;
+	struct dvb_net       dvb_net;
+	struct mutex         sync_mutex;
+
+	struct dvb_frontend *fe[MAX_NO_OF_FE_PER_ADAP];
+	int (*fe_init[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *);
+	int (*fe_sleep[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *);
+};
+
+/**
+ * dvb usb device object
+ * @props: device properties
+ * @name: device name
+ * @rc_map: name of rc codes table
+ * @udev: pointer to the device's struct usb_device
+ * @intf: pointer to the device's usb interface
+ * @rc: remote controller configuration
+ * @probe_work: work to defer .probe()
+ * @powered: indicated whether the device is power or not
+ * @usb_mutex: mutex for usb control messages
+ * @i2c_mutex: mutex for i2c-transfers
+ * @i2c_adap: device's i2c-adapter
+ * @rc_dev: rc device for the remote control
+ * @rc_query_work: work for polling remote
+ * @priv: private data of the actual driver (allocate by dvb usb, size defined
+ *  in size_of_priv of dvb_usb_properties).
+ */
+struct dvb_usb_device {
+	const struct dvb_usb_device_properties *props;
+	const char *name;
+	const char *rc_map;
+
+	struct usb_device *udev;
+	struct usb_interface *intf;
+	struct dvb_usb_rc rc;
+	struct work_struct probe_work;
+	pid_t work_pid;
+	int powered;
+
+	/* locking */
+	struct mutex usb_mutex;
+
+	/* i2c */
+	struct mutex i2c_mutex;
+	struct i2c_adapter i2c_adap;
+
+	struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
+
+	/* remote control */
+	struct rc_dev *rc_dev;
+	char rc_phys[64];
+	struct delayed_work rc_query_work;
+
+	void *priv;
+};
+
+extern int dvb_usbv2_probe(struct usb_interface *,
+		const struct usb_device_id *);
+extern void dvb_usbv2_disconnect(struct usb_interface *);
+extern int dvb_usbv2_suspend(struct usb_interface *, pm_message_t);
+extern int dvb_usbv2_resume(struct usb_interface *);
+extern int dvb_usbv2_reset_resume(struct usb_interface *);
+
+/* the generic read/write method for device control */
+extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16);
+extern int dvb_usbv2_generic_write(struct dvb_usb_device *, u8 *, u16);
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_common.h b/drivers/media/usb/dvb-usb-v2/dvb_usb_common.h
new file mode 100644
index 0000000..45f0709
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_common.h
@@ -0,0 +1,35 @@
+/*
+ * DVB USB framework
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DVB_USB_COMMON_H
+#define DVB_USB_COMMON_H
+
+#include "dvb_usb.h"
+
+/* commonly used  methods */
+extern int usb_urb_initv2(struct usb_data_stream *stream,
+		const struct usb_data_stream_properties *props);
+extern int usb_urb_exitv2(struct usb_data_stream *stream);
+extern int usb_urb_submitv2(struct usb_data_stream *stream,
+		struct usb_data_stream_properties *props);
+extern int usb_urb_killv2(struct usb_data_stream *stream);
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
new file mode 100644
index 0000000..e2d73e1
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -0,0 +1,1046 @@
+/*
+ * DVB USB framework
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dvb_usb_common.h"
+
+int dvb_usbv2_disable_rc_polling;
+module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644);
+MODULE_PARM_DESC(disable_rc_polling,
+		"disable remote control polling (default: 0)");
+static int dvb_usb_force_pid_filter_usage;
+module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage,
+		int, 0444);
+MODULE_PARM_DESC(force_pid_filter_usage, "force all DVB USB devices to use a " \
+		"PID filter, if any (default: 0)");
+
+static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *name)
+{
+	int ret;
+	const struct firmware *fw;
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	if (!d->props->download_firmware) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	ret = request_firmware(&fw, name, &d->udev->dev);
+	if (ret < 0) {
+		dev_err(&d->udev->dev, "%s: Did not find the firmware file "\
+				"'%s'. Please see linux/Documentation/dvb/ " \
+				"for more details on firmware-problems. " \
+				"Status %d\n", KBUILD_MODNAME, name, ret);
+		goto err;
+	}
+
+	dev_info(&d->udev->dev, "%s: downloading firmware from file '%s'\n",
+			KBUILD_MODNAME, name);
+
+	ret = d->props->download_firmware(d, fw);
+	release_firmware(fw);
+	if (ret < 0)
+		goto err;
+
+	return ret;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int dvb_usbv2_i2c_init(struct dvb_usb_device *d)
+{
+	int ret;
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	if (!d->props->i2c_algo)
+		return 0;
+
+	strlcpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name));
+	d->i2c_adap.algo = d->props->i2c_algo;
+	d->i2c_adap.dev.parent = &d->udev->dev;
+	i2c_set_adapdata(&d->i2c_adap, d);
+
+	ret = i2c_add_adapter(&d->i2c_adap);
+	if (ret < 0) {
+		d->i2c_adap.algo = NULL;
+		dev_err(&d->udev->dev, "%s: i2c_add_adapter() failed=%d\n",
+				KBUILD_MODNAME, ret);
+		goto err;
+	}
+
+	return 0;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int dvb_usbv2_i2c_exit(struct dvb_usb_device *d)
+{
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	if (d->i2c_adap.algo)
+		i2c_del_adapter(&d->i2c_adap);
+
+	return 0;
+}
+
+static void dvb_usb_read_remote_control(struct work_struct *work)
+{
+	struct dvb_usb_device *d = container_of(work,
+			struct dvb_usb_device, rc_query_work.work);
+	int ret;
+
+	/*
+	 * When the parameter has been set to 1 via sysfs while the
+	 * driver was running, or when bulk mode is enabled after IR init.
+	 */
+	if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode)
+		return;
+
+	ret = d->rc.query(d);
+	if (ret < 0) {
+		dev_err(&d->udev->dev, "%s: rc.query() failed=%d\n",
+				KBUILD_MODNAME, ret);
+		return; /* stop polling */
+	}
+
+	schedule_delayed_work(&d->rc_query_work,
+			msecs_to_jiffies(d->rc.interval));
+}
+
+static int dvb_usbv2_remote_init(struct dvb_usb_device *d)
+{
+	int ret;
+	struct rc_dev *dev;
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config)
+		return 0;
+
+	d->rc.map_name = d->rc_map;
+	ret = d->props->get_rc_config(d, &d->rc);
+	if (ret < 0)
+		goto err;
+
+	/* disable rc when there is no keymap defined */
+	if (!d->rc.map_name)
+		return 0;
+
+	dev = rc_allocate_device();
+	if (!dev) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	dev->dev.parent = &d->udev->dev;
+	dev->input_name = d->name;
+	usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
+	strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
+	dev->input_phys = d->rc_phys;
+	usb_to_input_id(d->udev, &dev->input_id);
+	/* TODO: likely RC-core should took const char * */
+	dev->driver_name = (char *) d->props->driver_name;
+	dev->map_name = d->rc.map_name;
+	dev->driver_type = d->rc.driver_type;
+	dev->allowed_protos = d->rc.allowed_protos;
+	dev->change_protocol = d->rc.change_protocol;
+	dev->priv = d;
+
+	ret = rc_register_device(dev);
+	if (ret < 0) {
+		rc_free_device(dev);
+		goto err;
+	}
+
+	d->rc_dev = dev;
+
+	/* start polling if needed */
+	if (d->rc.query && !d->rc.bulk_mode) {
+		/* initialize a work queue for handling polling */
+		INIT_DELAYED_WORK(&d->rc_query_work,
+				dvb_usb_read_remote_control);
+		dev_info(&d->udev->dev, "%s: schedule remote query interval " \
+				"to %d msecs\n", KBUILD_MODNAME,
+				d->rc.interval);
+		schedule_delayed_work(&d->rc_query_work,
+				msecs_to_jiffies(d->rc.interval));
+	}
+
+	return 0;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int dvb_usbv2_remote_exit(struct dvb_usb_device *d)
+{
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	if (d->rc_dev) {
+		cancel_delayed_work_sync(&d->rc_query_work);
+		rc_unregister_device(d->rc_dev);
+		d->rc_dev = NULL;
+	}
+
+	return 0;
+}
+
+static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buf,
+		size_t len)
+{
+	struct dvb_usb_adapter *adap = stream->user_priv;
+	dvb_dmx_swfilter(&adap->demux, buf, len);
+}
+
+static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buf,
+		size_t len)
+{
+	struct dvb_usb_adapter *adap = stream->user_priv;
+	dvb_dmx_swfilter_204(&adap->demux, buf, len);
+}
+
+static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, u8 *buf,
+		size_t len)
+{
+	struct dvb_usb_adapter *adap = stream->user_priv;
+	dvb_dmx_swfilter_raw(&adap->demux, buf, len);
+}
+
+int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap)
+{
+	dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__,
+			adap->id);
+
+	adap->stream.udev = adap_to_d(adap)->udev;
+	adap->stream.user_priv = adap;
+	adap->stream.complete = dvb_usb_data_complete;
+
+	return usb_urb_initv2(&adap->stream, &adap->props->stream);
+}
+
+int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap)
+{
+	dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__,
+			adap->id);
+
+	return usb_urb_exitv2(&adap->stream);
+}
+
+static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed,
+		int count)
+{
+	struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
+	struct dvb_usb_device *d = adap_to_d(adap);
+	int ret;
+	dev_dbg(&d->udev->dev, "%s: adap=%d active_fe=%d feed_type=%d " \
+			"setting pid [%s]: %04x (%04d) at index %d '%s'\n",
+			__func__, adap->id, adap->active_fe, dvbdmxfeed->type,
+			adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid,
+			dvbdmxfeed->pid, dvbdmxfeed->index,
+			(count == 1) ? "on" : "off");
+
+	if (adap->active_fe == -1)
+		return -EINVAL;
+
+	adap->feed_count += count;
+
+	/* stop feeding if it is last pid */
+	if (adap->feed_count == 0) {
+		dev_dbg(&d->udev->dev, "%s: stop feeding\n", __func__);
+		usb_urb_killv2(&adap->stream);
+
+		if (d->props->streaming_ctrl) {
+			ret = d->props->streaming_ctrl(
+					adap->fe[adap->active_fe], 0);
+			if (ret < 0) {
+				dev_err(&d->udev->dev, "%s: streaming_ctrl() " \
+						"failed=%d\n", KBUILD_MODNAME,
+						ret);
+				goto err_mutex_unlock;
+			}
+		}
+		mutex_unlock(&adap->sync_mutex);
+	}
+
+	/* activate the pid on the device pid filter */
+	if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+			adap->pid_filtering &&
+			adap->props->pid_filter)
+		ret = adap->props->pid_filter(adap, dvbdmxfeed->index,
+				dvbdmxfeed->pid, (count == 1) ? 1 : 0);
+			if (ret < 0)
+				dev_err(&d->udev->dev, "%s: pid_filter() " \
+						"failed=%d\n", KBUILD_MODNAME,
+						ret);
+
+	/* start feeding if it is first pid */
+	if (adap->feed_count == 1 && count == 1) {
+		struct usb_data_stream_properties stream_props;
+		mutex_lock(&adap->sync_mutex);
+		dev_dbg(&d->udev->dev, "%s: start feeding\n", __func__);
+
+		/* resolve input and output streaming paramters */
+		if (d->props->get_stream_config) {
+			memcpy(&stream_props, &adap->props->stream,
+				sizeof(struct usb_data_stream_properties));
+			ret = d->props->get_stream_config(
+					adap->fe[adap->active_fe],
+					&adap->ts_type, &stream_props);
+			if (ret < 0)
+				goto err_mutex_unlock;
+		} else {
+			stream_props = adap->props->stream;
+		}
+
+		switch (adap->ts_type) {
+		case DVB_USB_FE_TS_TYPE_204:
+			adap->stream.complete = dvb_usb_data_complete_204;
+			break;
+		case DVB_USB_FE_TS_TYPE_RAW:
+			adap->stream.complete = dvb_usb_data_complete_raw;
+			break;
+		case DVB_USB_FE_TS_TYPE_188:
+		default:
+			adap->stream.complete = dvb_usb_data_complete;
+			break;
+		}
+
+		usb_urb_submitv2(&adap->stream, &stream_props);
+
+		if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+				adap->props->caps &
+				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
+				adap->props->pid_filter_ctrl) {
+			ret = adap->props->pid_filter_ctrl(adap,
+					adap->pid_filtering);
+			if (ret < 0) {
+				dev_err(&d->udev->dev, "%s: " \
+						"pid_filter_ctrl() failed=%d\n",
+						KBUILD_MODNAME, ret);
+				goto err_mutex_unlock;
+			}
+		}
+
+		if (d->props->streaming_ctrl) {
+			ret = d->props->streaming_ctrl(
+					adap->fe[adap->active_fe], 1);
+			if (ret < 0) {
+				dev_err(&d->udev->dev, "%s: streaming_ctrl() " \
+						"failed=%d\n", KBUILD_MODNAME,
+						ret);
+				goto err_mutex_unlock;
+			}
+		}
+	}
+
+	return 0;
+err_mutex_unlock:
+	mutex_unlock(&adap->sync_mutex);
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	return dvb_usb_ctrl_feed(dvbdmxfeed, 1);
+}
+
+static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	return dvb_usb_ctrl_feed(dvbdmxfeed, -1);
+}
+
+int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	struct dvb_usb_device *d = adap_to_d(adap);
+	dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id);
+
+	ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner,
+			&d->udev->dev, d->props->adapter_nr);
+	if (ret < 0) {
+		dev_dbg(&d->udev->dev, "%s: dvb_register_adapter() failed=%d\n",
+				__func__, ret);
+		goto err_dvb_register_adapter;
+	}
+
+	adap->dvb_adap.priv = adap;
+
+	if (d->props->read_mac_address) {
+		ret = d->props->read_mac_address(adap,
+				adap->dvb_adap.proposed_mac);
+		if (ret < 0)
+			goto err_dvb_dmx_init;
+
+		dev_info(&d->udev->dev, "%s: MAC address: %pM\n",
+				KBUILD_MODNAME, adap->dvb_adap.proposed_mac);
+	}
+
+	adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+	adap->demux.priv             = adap;
+	adap->demux.filternum        = 0;
+	adap->demux.filternum        = adap->max_feed_count;
+	adap->demux.feednum          = adap->demux.filternum;
+	adap->demux.start_feed       = dvb_usb_start_feed;
+	adap->demux.stop_feed        = dvb_usb_stop_feed;
+	adap->demux.write_to_decoder = NULL;
+	ret = dvb_dmx_init(&adap->demux);
+	if (ret < 0) {
+		dev_err(&d->udev->dev, "%s: dvb_dmx_init() failed=%d\n",
+				KBUILD_MODNAME, ret);
+		goto err_dvb_dmx_init;
+	}
+
+	adap->dmxdev.filternum       = adap->demux.filternum;
+	adap->dmxdev.demux           = &adap->demux.dmx;
+	adap->dmxdev.capabilities    = 0;
+	ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap);
+	if (ret < 0) {
+		dev_err(&d->udev->dev, "%s: dvb_dmxdev_init() failed=%d\n",
+				KBUILD_MODNAME, ret);
+		goto err_dvb_dmxdev_init;
+	}
+
+	ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx);
+	if (ret < 0) {
+		dev_err(&d->udev->dev, "%s: dvb_net_init() failed=%d\n",
+				KBUILD_MODNAME, ret);
+		goto err_dvb_net_init;
+	}
+
+	mutex_init(&adap->sync_mutex);
+
+	return 0;
+err_dvb_net_init:
+	dvb_dmxdev_release(&adap->dmxdev);
+err_dvb_dmxdev_init:
+	dvb_dmx_release(&adap->demux);
+err_dvb_dmx_init:
+	dvb_unregister_adapter(&adap->dvb_adap);
+err_dvb_register_adapter:
+	adap->dvb_adap.priv = NULL;
+	return ret;
+}
+
+int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap)
+{
+	dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__,
+			adap->id);
+
+	if (adap->dvb_adap.priv) {
+		dvb_net_release(&adap->dvb_net);
+		adap->demux.dmx.close(&adap->demux.dmx);
+		dvb_dmxdev_release(&adap->dmxdev);
+		dvb_dmx_release(&adap->demux);
+		dvb_unregister_adapter(&adap->dvb_adap);
+	}
+
+	return 0;
+}
+
+int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	int ret;
+
+	if (onoff)
+		d->powered++;
+	else
+		d->powered--;
+
+	if (d->powered == 0 || (onoff && d->powered == 1)) {
+		/* when switching from 1 to 0 or from 0 to 1 */
+		dev_dbg(&d->udev->dev, "%s: power=%d\n", __func__, onoff);
+		if (d->props->power_ctrl) {
+			ret = d->props->power_ctrl(d, onoff);
+			if (ret < 0)
+				goto err;
+		}
+	}
+
+	return 0;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int dvb_usb_fe_init(struct dvb_frontend *fe)
+{
+	int ret;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dvb_usb_device *d = adap_to_d(adap);
+	dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id,
+			fe->id);
+
+	if (!adap->suspend_resume_active) {
+		adap->active_fe = fe->id;
+		mutex_lock(&adap->sync_mutex);
+	}
+
+	ret = dvb_usbv2_device_power_ctrl(d, 1);
+	if (ret < 0)
+		goto err;
+
+	if (d->props->frontend_ctrl) {
+		ret = d->props->frontend_ctrl(fe, 1);
+		if (ret < 0)
+			goto err;
+	}
+
+	if (adap->fe_init[fe->id]) {
+		ret = adap->fe_init[fe->id](fe);
+		if (ret < 0)
+			goto err;
+	}
+err:
+	if (!adap->suspend_resume_active)
+		mutex_unlock(&adap->sync_mutex);
+
+	dev_dbg(&d->udev->dev, "%s: ret=%d\n", __func__, ret);
+	return ret;
+}
+
+static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
+{
+	int ret;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dvb_usb_device *d = adap_to_d(adap);
+	dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id,
+			fe->id);
+
+	if (!adap->suspend_resume_active)
+		mutex_lock(&adap->sync_mutex);
+
+	if (adap->fe_sleep[fe->id]) {
+		ret = adap->fe_sleep[fe->id](fe);
+		if (ret < 0)
+			goto err;
+	}
+
+	if (d->props->frontend_ctrl) {
+		ret = d->props->frontend_ctrl(fe, 0);
+		if (ret < 0)
+			goto err;
+	}
+
+	ret = dvb_usbv2_device_power_ctrl(d, 0);
+	if (ret < 0)
+		goto err;
+err:
+	if (!adap->suspend_resume_active) {
+		adap->active_fe = -1;
+		mutex_unlock(&adap->sync_mutex);
+	}
+
+	dev_dbg(&d->udev->dev, "%s: ret=%d\n", __func__, ret);
+	return ret;
+}
+
+int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap)
+{
+	int ret, i, count_registered = 0;
+	struct dvb_usb_device *d = adap_to_d(adap);
+	dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id);
+
+	memset(adap->fe, 0, sizeof(adap->fe));
+	adap->active_fe = -1;
+
+	if (d->props->frontend_attach) {
+		ret = d->props->frontend_attach(adap);
+		if (ret < 0) {
+			dev_dbg(&d->udev->dev, "%s: frontend_attach() " \
+					"failed=%d\n", __func__, ret);
+			goto err_dvb_frontend_detach;
+		}
+	} else {
+		dev_dbg(&d->udev->dev, "%s: frontend_attach() do not exists\n",
+				__func__);
+		ret = 0;
+		goto err;
+	}
+
+	for (i = 0; i < MAX_NO_OF_FE_PER_ADAP && adap->fe[i]; i++) {
+		adap->fe[i]->id = i;
+		/* re-assign sleep and wakeup functions */
+		adap->fe_init[i] = adap->fe[i]->ops.init;
+		adap->fe[i]->ops.init = dvb_usb_fe_init;
+		adap->fe_sleep[i] = adap->fe[i]->ops.sleep;
+		adap->fe[i]->ops.sleep = dvb_usb_fe_sleep;
+
+		ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]);
+		if (ret < 0) {
+			dev_err(&d->udev->dev, "%s: frontend%d registration " \
+					"failed\n", KBUILD_MODNAME, i);
+			goto err_dvb_unregister_frontend;
+		}
+
+		count_registered++;
+	}
+
+	if (d->props->tuner_attach) {
+		ret = d->props->tuner_attach(adap);
+		if (ret < 0) {
+			dev_dbg(&d->udev->dev, "%s: tuner_attach() failed=%d\n",
+					__func__, ret);
+			goto err_dvb_unregister_frontend;
+		}
+	}
+
+	return 0;
+
+err_dvb_unregister_frontend:
+	for (i = count_registered - 1; i >= 0; i--)
+		dvb_unregister_frontend(adap->fe[i]);
+
+err_dvb_frontend_detach:
+	for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) {
+		if (adap->fe[i])
+			dvb_frontend_detach(adap->fe[i]);
+	}
+
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap)
+{
+	int i;
+	dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__,
+			adap->id);
+
+	for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) {
+		if (adap->fe[i]) {
+			dvb_unregister_frontend(adap->fe[i]);
+			dvb_frontend_detach(adap->fe[i]);
+		}
+	}
+
+	return 0;
+}
+
+static int dvb_usbv2_adapter_init(struct dvb_usb_device *d)
+{
+	struct dvb_usb_adapter *adap;
+	int ret, i, adapter_count;
+
+	/* resolve adapter count */
+	adapter_count = d->props->num_adapters;
+	if (d->props->get_adapter_count) {
+		ret = d->props->get_adapter_count(d);
+		if (ret < 0)
+			goto err;
+
+		adapter_count = ret;
+	}
+
+	for (i = 0; i < adapter_count; i++) {
+		adap = &d->adapter[i];
+		adap->id = i;
+		adap->props = &d->props->adapter[i];
+
+		/* speed - when running at FULL speed we need a HW PID filter */
+		if (d->udev->speed == USB_SPEED_FULL &&
+				!(adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
+			dev_err(&d->udev->dev, "%s: this USB2.0 device " \
+					"cannot be run on a USB1.1 port (it " \
+					"lacks a hardware PID filter)\n",
+					KBUILD_MODNAME);
+			ret = -ENODEV;
+			goto err;
+		} else if ((d->udev->speed == USB_SPEED_FULL &&
+				adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
+				(adap->props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
+			dev_info(&d->udev->dev, "%s: will use the device's " \
+					"hardware PID filter " \
+					"(table count: %d)\n", KBUILD_MODNAME,
+					adap->props->pid_filter_count);
+			adap->pid_filtering  = 1;
+			adap->max_feed_count = adap->props->pid_filter_count;
+		} else {
+			dev_info(&d->udev->dev, "%s: will pass the complete " \
+					"MPEG2 transport stream to the " \
+					"software demuxer\n", KBUILD_MODNAME);
+			adap->pid_filtering  = 0;
+			adap->max_feed_count = 255;
+		}
+
+		if (!adap->pid_filtering && dvb_usb_force_pid_filter_usage &&
+				adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) {
+			dev_info(&d->udev->dev, "%s: PID filter enabled by " \
+					"module option\n", KBUILD_MODNAME);
+			adap->pid_filtering  = 1;
+			adap->max_feed_count = adap->props->pid_filter_count;
+		}
+
+		ret = dvb_usbv2_adapter_stream_init(adap);
+		if (ret)
+			goto err;
+
+		ret = dvb_usbv2_adapter_dvb_init(adap);
+		if (ret)
+			goto err;
+
+		ret = dvb_usbv2_adapter_frontend_init(adap);
+		if (ret)
+			goto err;
+
+		/* use exclusive FE lock if there is multiple shared FEs */
+		if (adap->fe[1])
+			adap->dvb_adap.mfe_shared = 1;
+	}
+
+	return 0;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d)
+{
+	int i;
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) {
+		if (d->adapter[i].props) {
+			dvb_usbv2_adapter_frontend_exit(&d->adapter[i]);
+			dvb_usbv2_adapter_dvb_exit(&d->adapter[i]);
+			dvb_usbv2_adapter_stream_exit(&d->adapter[i]);
+		}
+	}
+
+	return 0;
+}
+
+/* general initialization functions */
+static int dvb_usbv2_exit(struct dvb_usb_device *d)
+{
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	dvb_usbv2_remote_exit(d);
+	dvb_usbv2_adapter_exit(d);
+	dvb_usbv2_i2c_exit(d);
+	kfree(d->priv);
+	kfree(d);
+
+	return 0;
+}
+
+static int dvb_usbv2_init(struct dvb_usb_device *d)
+{
+	int ret;
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	dvb_usbv2_device_power_ctrl(d, 1);
+
+	if (d->props->read_config) {
+		ret = d->props->read_config(d);
+		if (ret < 0)
+			goto err;
+	}
+
+	ret = dvb_usbv2_i2c_init(d);
+	if (ret < 0)
+		goto err;
+
+	ret = dvb_usbv2_adapter_init(d);
+	if (ret < 0)
+		goto err;
+
+	if (d->props->init) {
+		ret = d->props->init(d);
+		if (ret < 0)
+			goto err;
+	}
+
+	ret = dvb_usbv2_remote_init(d);
+	if (ret < 0)
+		goto err;
+
+	dvb_usbv2_device_power_ctrl(d, 0);
+
+	return 0;
+err:
+	dvb_usbv2_device_power_ctrl(d, 0);
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+/*
+ * udev, which is used for the firmware downloading, requires we cannot
+ * block during module_init(). module_init() calls USB probe() which
+ * is this routine. Due to that we delay actual operation using workqueue
+ * and return always success here.
+ */
+static void dvb_usbv2_init_work(struct work_struct *work)
+{
+	int ret;
+	struct dvb_usb_device *d =
+			container_of(work, struct dvb_usb_device, probe_work);
+
+	d->work_pid = current->pid;
+	dev_dbg(&d->udev->dev, "%s: work_pid=%d\n", __func__, d->work_pid);
+
+	if (d->props->size_of_priv) {
+		d->priv = kzalloc(d->props->size_of_priv, GFP_KERNEL);
+		if (!d->priv) {
+			dev_err(&d->udev->dev, "%s: kzalloc() failed\n",
+					KBUILD_MODNAME);
+			ret = -ENOMEM;
+			goto err_usb_driver_release_interface;
+		}
+	}
+
+	if (d->props->identify_state) {
+		const char *name = NULL;
+		ret = d->props->identify_state(d, &name);
+		if (ret == 0) {
+			;
+		} else if (ret == COLD) {
+			dev_info(&d->udev->dev, "%s: found a '%s' in cold " \
+					"state\n", KBUILD_MODNAME, d->name);
+
+			if (!name)
+				name = d->props->firmware;
+
+			ret = dvb_usbv2_download_firmware(d, name);
+			if (ret == 0) {
+				/* device is warm, continue initialization */
+				;
+			} else if (ret == RECONNECTS_USB) {
+				/*
+				 * USB core will call disconnect() and then
+				 * probe() as device reconnects itself from the
+				 * USB bus. disconnect() will release all driver
+				 * resources and probe() is called for 'new'
+				 * device. As 'new' device is warm we should
+				 * never go here again.
+				 */
+				return;
+			} else {
+				/*
+				 * Unexpected error. We must unregister driver
+				 * manually from the device, because device is
+				 * already register by returning from probe()
+				 * with success. usb_driver_release_interface()
+				 * finally calls disconnect() in order to free
+				 * resources.
+				 */
+				goto err_usb_driver_release_interface;
+			}
+		} else {
+			goto err_usb_driver_release_interface;
+		}
+	}
+
+	dev_info(&d->udev->dev, "%s: found a '%s' in warm state\n",
+			KBUILD_MODNAME, d->name);
+
+	ret = dvb_usbv2_init(d);
+	if (ret < 0)
+		goto err_usb_driver_release_interface;
+
+	dev_info(&d->udev->dev, "%s: '%s' successfully initialized and " \
+			"connected\n", KBUILD_MODNAME, d->name);
+
+	return;
+err_usb_driver_release_interface:
+	dev_info(&d->udev->dev, "%s: '%s' error while loading driver (%d)\n",
+			KBUILD_MODNAME, d->name, ret);
+	usb_driver_release_interface(to_usb_driver(d->intf->dev.driver),
+			d->intf);
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return;
+}
+
+int dvb_usbv2_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	int ret;
+	struct dvb_usb_device *d;
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct dvb_usb_driver_info *driver_info =
+			(struct dvb_usb_driver_info *) id->driver_info;
+
+	dev_dbg(&udev->dev, "%s: bInterfaceNumber=%d\n", __func__,
+			intf->cur_altsetting->desc.bInterfaceNumber);
+
+	if (!id->driver_info) {
+		dev_err(&udev->dev, "%s: driver_info failed\n", KBUILD_MODNAME);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL);
+	if (!d) {
+		dev_err(&udev->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	d->name = driver_info->name;
+	d->rc_map = driver_info->rc_map;
+	d->udev = udev;
+	d->intf = intf;
+	d->props = driver_info->props;
+
+	if (d->intf->cur_altsetting->desc.bInterfaceNumber !=
+			d->props->bInterfaceNumber) {
+		ret = -ENODEV;
+		goto err_kfree;
+	}
+
+	mutex_init(&d->usb_mutex);
+	mutex_init(&d->i2c_mutex);
+	INIT_WORK(&d->probe_work, dvb_usbv2_init_work);
+	usb_set_intfdata(intf, d);
+	ret = schedule_work(&d->probe_work);
+	if (ret < 0) {
+		dev_err(&d->udev->dev, "%s: schedule_work() failed\n",
+				KBUILD_MODNAME);
+		goto err_kfree;
+	}
+
+	return 0;
+err_kfree:
+	kfree(d);
+err:
+	dev_dbg(&udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+EXPORT_SYMBOL(dvb_usbv2_probe);
+
+void dvb_usbv2_disconnect(struct usb_interface *intf)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+	const char *name = d->name;
+	struct device dev = d->udev->dev;
+	dev_dbg(&d->udev->dev, "%s: pid=%d work_pid=%d\n", __func__,
+			current->pid, d->work_pid);
+
+	/* ensure initialization work is finished until release resources */
+	if (d->work_pid != current->pid)
+		cancel_work_sync(&d->probe_work);
+
+	if (d->props->exit)
+		d->props->exit(d);
+
+	dvb_usbv2_exit(d);
+
+	dev_info(&dev, "%s: '%s' successfully deinitialized and disconnected\n",
+			KBUILD_MODNAME, name);
+}
+EXPORT_SYMBOL(dvb_usbv2_disconnect);
+
+int dvb_usbv2_suspend(struct usb_interface *intf, pm_message_t msg)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+	int ret = 0, i, active_fe;
+	struct dvb_frontend *fe;
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	/* stop remote controller poll */
+	if (d->rc.query && !d->rc.bulk_mode)
+		cancel_delayed_work_sync(&d->rc_query_work);
+
+	for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) {
+		active_fe = d->adapter[i].active_fe;
+		if (d->adapter[i].dvb_adap.priv && active_fe != -1) {
+			fe = d->adapter[i].fe[active_fe];
+			d->adapter[i].suspend_resume_active = true;
+
+			if (d->props->streaming_ctrl)
+				d->props->streaming_ctrl(fe, 0);
+
+			/* stop usb streaming */
+			usb_urb_killv2(&d->adapter[i].stream);
+
+			ret = dvb_frontend_suspend(fe);
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(dvb_usbv2_suspend);
+
+static int dvb_usbv2_resume_common(struct dvb_usb_device *d)
+{
+	int ret = 0, i, active_fe;
+	struct dvb_frontend *fe;
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	for (i = 0; i < MAX_NO_OF_ADAPTER_PER_DEVICE; i++) {
+		active_fe = d->adapter[i].active_fe;
+		if (d->adapter[i].dvb_adap.priv && active_fe != -1) {
+			fe = d->adapter[i].fe[active_fe];
+
+			ret = dvb_frontend_resume(fe);
+
+			/* resume usb streaming */
+			usb_urb_submitv2(&d->adapter[i].stream, NULL);
+
+			if (d->props->streaming_ctrl)
+				d->props->streaming_ctrl(fe, 1);
+
+			d->adapter[i].suspend_resume_active = false;
+		}
+	}
+
+	/* start remote controller poll */
+	if (d->rc.query && !d->rc.bulk_mode)
+		schedule_delayed_work(&d->rc_query_work,
+				msecs_to_jiffies(d->rc.interval));
+
+	return ret;
+}
+
+int dvb_usbv2_resume(struct usb_interface *intf)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	return dvb_usbv2_resume_common(d);
+}
+EXPORT_SYMBOL(dvb_usbv2_resume);
+
+int dvb_usbv2_reset_resume(struct usb_interface *intf)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+	int ret;
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	dvb_usbv2_device_power_ctrl(d, 1);
+
+	if (d->props->init)
+		d->props->init(d);
+
+	ret = dvb_usbv2_resume_common(d);
+
+	dvb_usbv2_device_power_ctrl(d, 0);
+
+	return ret;
+}
+EXPORT_SYMBOL(dvb_usbv2_reset_resume);
+
+MODULE_VERSION("2.0");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("DVB USB common");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
new file mode 100644
index 0000000..0431bee
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
@@ -0,0 +1,77 @@
+/*
+ * DVB USB framework
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dvb_usb_common.h"
+
+int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
+		u16 rlen)
+{
+	int ret, actual_length;
+
+	if (!d || !wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint ||
+			!d->props->generic_bulk_ctrl_endpoint_response) {
+		dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, -EINVAL);
+		return -EINVAL;
+	}
+
+	ret = mutex_lock_interruptible(&d->usb_mutex);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, wlen, wbuf);
+
+	ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev,
+			d->props->generic_bulk_ctrl_endpoint), wbuf, wlen,
+			&actual_length, 2000);
+	if (ret < 0)
+		dev_err(&d->udev->dev, "%s: usb_bulk_msg() failed=%d\n",
+				KBUILD_MODNAME, ret);
+	else
+		ret = actual_length != wlen ? -EIO : 0;
+
+	/* an answer is expected, and no error before */
+	if (!ret && rbuf && rlen) {
+		if (d->props->generic_bulk_ctrl_delay)
+			usleep_range(d->props->generic_bulk_ctrl_delay,
+					d->props->generic_bulk_ctrl_delay
+					+ 20000);
+
+		ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
+				d->props->generic_bulk_ctrl_endpoint_response),
+				rbuf, rlen, &actual_length, 2000);
+		if (ret)
+			dev_err(&d->udev->dev, "%s: 2nd usb_bulk_msg() " \
+					"failed=%d\n", KBUILD_MODNAME, ret);
+
+		dev_dbg(&d->udev->dev, "%s: <<< %*ph\n", __func__,
+				actual_length, rbuf);
+	}
+
+	mutex_unlock(&d->usb_mutex);
+	return ret;
+}
+EXPORT_SYMBOL(dvb_usbv2_generic_rw);
+
+int dvb_usbv2_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len)
+{
+	return dvb_usbv2_generic_rw(d, buf, len, NULL, 0);
+}
+EXPORT_SYMBOL(dvb_usbv2_generic_write);
diff --git a/drivers/media/usb/dvb-usb-v2/ec168.c b/drivers/media/usb/dvb-usb-v2/ec168.c
new file mode 100644
index 0000000..ab77622
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/ec168.c
@@ -0,0 +1,376 @@
+/*
+ * E3C EC168 DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "ec168.h"
+#include "ec100.h"
+#include "mxl5005s.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req)
+{
+	int ret;
+	unsigned int pipe;
+	u8 request, requesttype;
+	u8 *buf;
+
+	switch (req->cmd) {
+	case DOWNLOAD_FIRMWARE:
+	case GPIO:
+	case WRITE_I2C:
+	case STREAMING_CTRL:
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+		request = req->cmd;
+		break;
+	case READ_I2C:
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+		request = req->cmd;
+		break;
+	case GET_CONFIG:
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+		request = CONFIG;
+		break;
+	case SET_CONFIG:
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+		request = CONFIG;
+		break;
+	case WRITE_DEMOD:
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+		request = DEMOD_RW;
+		break;
+	case READ_DEMOD:
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+		request = DEMOD_RW;
+		break;
+	default:
+		pr_err("%s: unknown command=%02x\n", KBUILD_MODNAME, req->cmd);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	buf = kmalloc(req->size, GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
+		/* write */
+		memcpy(buf, req->data, req->size);
+		pipe = usb_sndctrlpipe(d->udev, 0);
+	} else {
+		/* read */
+		pipe = usb_rcvctrlpipe(d->udev, 0);
+	}
+
+	msleep(1); /* avoid I2C errors */
+
+	ret = usb_control_msg(d->udev, pipe, request, requesttype, req->value,
+		req->index, buf, req->size, EC168_USB_TIMEOUT);
+
+	ec168_debug_dump(request, requesttype, req->value, req->index, buf,
+		req->size);
+
+	if (ret < 0)
+		goto err_dealloc;
+	else
+		ret = 0;
+
+	/* read request, copy returned data to return buf */
+	if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
+		memcpy(req->data, buf, req->size);
+
+	kfree(buf);
+	return ret;
+
+err_dealloc:
+	kfree(buf);
+error:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+/* I2C */
+static struct ec100_config ec168_ec100_config;
+
+static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+	int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct ec168_req req;
+	int i = 0;
+	int ret;
+
+	if (num > 2)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	while (i < num) {
+		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+			if (msg[i].addr == ec168_ec100_config.demod_address) {
+				req.cmd = READ_DEMOD;
+				req.value = 0;
+				req.index = 0xff00 + msg[i].buf[0]; /* reg */
+				req.size = msg[i+1].len; /* bytes to read */
+				req.data = &msg[i+1].buf[0];
+				ret = ec168_ctrl_msg(d, &req);
+				i += 2;
+			} else {
+				pr_err("%s: I2C read not implemented\n",
+						KBUILD_MODNAME);
+				ret = -EOPNOTSUPP;
+				i += 2;
+			}
+		} else {
+			if (msg[i].addr == ec168_ec100_config.demod_address) {
+				req.cmd = WRITE_DEMOD;
+				req.value = msg[i].buf[1]; /* val */
+				req.index = 0xff00 + msg[i].buf[0]; /* reg */
+				req.size = 0;
+				req.data = NULL;
+				ret = ec168_ctrl_msg(d, &req);
+				i += 1;
+			} else {
+				req.cmd = WRITE_I2C;
+				req.value = msg[i].buf[0]; /* val */
+				req.index = 0x0100 + msg[i].addr; /* I2C addr */
+				req.size = msg[i].len-1;
+				req.data = &msg[i].buf[1];
+				ret = ec168_ctrl_msg(d, &req);
+				i += 1;
+			}
+		}
+		if (ret)
+			goto error;
+
+	}
+	ret = i;
+
+error:
+	mutex_unlock(&d->i2c_mutex);
+	return i;
+}
+
+static u32 ec168_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm ec168_i2c_algo = {
+	.master_xfer   = ec168_i2c_xfer,
+	.functionality = ec168_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static int ec168_identify_state(struct dvb_usb_device *d, const char **name)
+{
+	int ret;
+	u8 reply;
+	struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply};
+	pr_debug("%s:\n", __func__);
+
+	ret = ec168_ctrl_msg(d, &req);
+	if (ret)
+		goto error;
+
+	pr_debug("%s: reply=%02x\n", __func__, reply);
+
+	if (reply == 0x01)
+		ret = WARM;
+	else
+		ret = COLD;
+
+	return ret;
+error:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int ec168_download_firmware(struct dvb_usb_device *d,
+		const struct firmware *fw)
+{
+	int ret, len, remaining;
+	struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL};
+	pr_debug("%s:\n", __func__);
+
+	#define LEN_MAX 2048 /* max packet size */
+	for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) {
+		len = remaining;
+		if (len > LEN_MAX)
+			len = LEN_MAX;
+
+		req.size = len;
+		req.data = (u8 *) &fw->data[fw->size - remaining];
+		req.index = fw->size - remaining;
+
+		ret = ec168_ctrl_msg(d, &req);
+		if (ret) {
+			pr_err("%s: firmware download failed=%d\n",
+					KBUILD_MODNAME, ret);
+			goto error;
+		}
+	}
+
+	req.size = 0;
+
+	/* set "warm"? */
+	req.cmd = SET_CONFIG;
+	req.value = 0;
+	req.index = 0x0001;
+	ret = ec168_ctrl_msg(d, &req);
+	if (ret)
+		goto error;
+
+	/* really needed - no idea what does */
+	req.cmd = GPIO;
+	req.value = 0;
+	req.index = 0x0206;
+	ret = ec168_ctrl_msg(d, &req);
+	if (ret)
+		goto error;
+
+	/* activate tuner I2C? */
+	req.cmd = WRITE_I2C;
+	req.value = 0;
+	req.index = 0x00c6;
+	ret = ec168_ctrl_msg(d, &req);
+	if (ret)
+		goto error;
+
+	return ret;
+error:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static struct ec100_config ec168_ec100_config = {
+	.demod_address = 0xff, /* not real address, demod is integrated */
+};
+
+static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	pr_debug("%s:\n", __func__);
+	adap->fe[0] = dvb_attach(ec100_attach, &ec168_ec100_config,
+			&adap_to_d(adap)->i2c_adap);
+	if (adap->fe[0] == NULL)
+		return -ENODEV;
+
+	return 0;
+}
+
+static struct mxl5005s_config ec168_mxl5003s_config = {
+	.i2c_address     = 0xc6,
+	.if_freq         = IF_FREQ_4570000HZ,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_OFF,
+	.rssi_enable     = MXL_RSSI_ENABLE,
+	.cap_select      = MXL_CAP_SEL_ENABLE,
+	.div_out         = MXL_DIV_OUT_4,
+	.clock_out       = MXL_CLOCK_OUT_DISABLE,
+	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+	.top		 = MXL5005S_TOP_25P2,
+	.mod_mode        = MXL_DIGITAL_MODE,
+	.if_mode         = MXL_ZERO_IF,
+	.AgcMasterByte   = 0x00,
+};
+
+static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	pr_debug("%s:\n", __func__);
+	return dvb_attach(mxl5005s_attach, adap->fe[0],
+			&adap_to_d(adap)->i2c_adap,
+			&ec168_mxl5003s_config) == NULL ? -ENODEV : 0;
+}
+
+static int ec168_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+	struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL};
+	pr_debug("%s: onoff=%d\n", __func__, onoff);
+	if (onoff)
+		req.index = 0x0102;
+	return ec168_ctrl_msg(fe_to_d(fe), &req);
+}
+
+/* DVB USB Driver stuff */
+/* bInterfaceNumber 0 is HID
+ * bInterfaceNumber 1 is DVB-T */
+static struct dvb_usb_device_properties ec168_props = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+	.bInterfaceNumber = 1,
+
+	.identify_state = ec168_identify_state,
+	.firmware = "dvb-usb-ec168.fw",
+	.download_firmware = ec168_download_firmware,
+
+	.i2c_algo = &ec168_i2c_algo,
+	.frontend_attach = ec168_ec100_frontend_attach,
+	.tuner_attach = ec168_mxl5003s_tuner_attach,
+	.streaming_ctrl = ec168_streaming_ctrl,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.stream = DVB_USB_STREAM_BULK(0x82, 6, 32 * 512),
+		}
+	},
+};
+
+static const struct dvb_usb_driver_info ec168_driver_info = {
+	.name = "E3C EC168 reference design",
+	.props = &ec168_props,
+};
+
+static const struct usb_device_id ec168_id[] = {
+	{ USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168),
+		.driver_info = (kernel_ulong_t) &ec168_driver_info },
+	{ USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2),
+		.driver_info = (kernel_ulong_t) &ec168_driver_info },
+	{ USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3),
+		.driver_info = (kernel_ulong_t) &ec168_driver_info },
+	{ USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4),
+		.driver_info = (kernel_ulong_t) &ec168_driver_info },
+	{ USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5),
+		.driver_info = (kernel_ulong_t) &ec168_driver_info },
+	{}
+};
+MODULE_DEVICE_TABLE(usb, ec168_id);
+
+static struct usb_driver ec168_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = ec168_id,
+	.probe = dvb_usbv2_probe,
+	.disconnect = dvb_usbv2_disconnect,
+	.suspend = dvb_usbv2_suspend,
+	.resume = dvb_usbv2_resume,
+	.no_dynamic_id = 1,
+	.soft_unbind = 1,
+};
+
+module_usb_driver(ec168_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("E3C EC168 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/ec168.h b/drivers/media/usb/dvb-usb-v2/ec168.h
new file mode 100644
index 0000000..9181236
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/ec168.h
@@ -0,0 +1,63 @@
+/*
+ * E3C EC168 DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef EC168_H
+#define EC168_H
+
+#include "dvb_usb.h"
+
+#define ec168_debug_dump(r, t, v, i, b, l) { \
+	char *direction; \
+	if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
+		direction = ">>>"; \
+	else \
+		direction = "<<<"; \
+	pr_debug("%s: %02x %02x %02x %02x %02x %02x %02x %02x %s\n", \
+			 __func__, t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, \
+			l & 0xff, l >> 8, direction); \
+}
+
+#define EC168_USB_TIMEOUT 1000
+
+struct ec168_req {
+	u8  cmd;       /* [1] */
+	u16 value;     /* [2|3] */
+	u16 index;     /* [4|5] */
+	u16 size;      /* [6|7] */
+	u8  *data;
+};
+
+enum ec168_cmd {
+	DOWNLOAD_FIRMWARE    = 0x00,
+	CONFIG               = 0x01,
+	DEMOD_RW             = 0x03,
+	GPIO                 = 0x04,
+	STREAMING_CTRL       = 0x10,
+	READ_I2C             = 0x20,
+	WRITE_I2C            = 0x21,
+	HID_DOWNLOAD         = 0x30,
+	GET_CONFIG,
+	SET_CONFIG,
+	READ_DEMOD,
+	WRITE_DEMOD,
+};
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/gl861.c b/drivers/media/usb/dvb-usb-v2/gl861.c
new file mode 100644
index 0000000..cf29f43
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/gl861.c
@@ -0,0 +1,175 @@
+/* DVB USB compliant linux driver for GL861 USB2.0 devices.
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "gl861.h"
+
+#include "zl10353.h"
+#include "qt1010.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
+			 u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+	u16 index;
+	u16 value = addr << (8 + 1);
+	int wo = (rbuf == NULL || rlen == 0); /* write-only */
+	u8 req, type;
+
+	if (wo) {
+		req = GL861_REQ_I2C_WRITE;
+		type = GL861_WRITE;
+	} else { /* rw */
+		req = GL861_REQ_I2C_READ;
+		type = GL861_READ;
+	}
+
+	switch (wlen) {
+	case 1:
+		index = wbuf[0];
+		break;
+	case 2:
+		index = wbuf[0];
+		value = value + wbuf[1];
+		break;
+	default:
+		pr_err("%s: wlen=%d, aborting\n", KBUILD_MODNAME, wlen);
+		return -EINVAL;
+	}
+
+	msleep(1); /* avoid I2C errors */
+
+	return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type,
+			       value, index, rbuf, rlen, 2000);
+}
+
+/* I2C */
+static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+			  int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int i;
+
+	if (num > 2)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		/* write/read request */
+		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+			if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
+				msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
+				break;
+			i++;
+		} else
+			if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
+					  msg[i].len, NULL, 0) < 0)
+				break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return i;
+}
+
+static u32 gl861_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm gl861_i2c_algo = {
+	.master_xfer   = gl861_i2c_xfer,
+	.functionality = gl861_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static struct zl10353_config gl861_zl10353_config = {
+	.demod_address = 0x0f,
+	.no_tuner = 1,
+	.parallel_ts = 1,
+};
+
+static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
+{
+
+	adap->fe[0] = dvb_attach(zl10353_attach, &gl861_zl10353_config,
+		&adap_to_d(adap)->i2c_adap);
+	if (adap->fe[0] == NULL)
+		return -EIO;
+
+	return 0;
+}
+
+static struct qt1010_config gl861_qt1010_config = {
+	.i2c_address = 0x62
+};
+
+static int gl861_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	return dvb_attach(qt1010_attach,
+			  adap->fe[0], &adap_to_d(adap)->i2c_adap,
+			  &gl861_qt1010_config) == NULL ? -ENODEV : 0;
+}
+
+static int gl861_init(struct dvb_usb_device *d)
+{
+	/*
+	 * There is 2 interfaces. Interface 0 is for TV and interface 1 is
+	 * for HID remote controller. Interface 0 has 2 alternate settings.
+	 * For some reason we need to set interface explicitly, defaulted
+	 * as alternate setting 1?
+	 */
+	return usb_set_interface(d->udev, 0, 0);
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties gl861_props = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+
+	.i2c_algo = &gl861_i2c_algo,
+	.frontend_attach = gl861_frontend_attach,
+	.tuner_attach = gl861_tuner_attach,
+	.init = gl861_init,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.stream = DVB_USB_STREAM_BULK(0x81, 7, 512),
+		}
+	}
+};
+
+static const struct usb_device_id gl861_id_table[] = {
+	{ DVB_USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801,
+		&gl861_props, "MSI Mega Sky 55801 DVB-T USB2.0", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU,
+		&gl861_props, "A-LINK DTU DVB-T USB2.0", NULL) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, gl861_id_table);
+
+static struct usb_driver gl861_usb_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = gl861_id_table,
+	.probe = dvb_usbv2_probe,
+	.disconnect = dvb_usbv2_disconnect,
+	.suspend = dvb_usbv2_suspend,
+	.resume = dvb_usbv2_resume,
+	.no_dynamic_id = 1,
+	.soft_unbind = 1,
+};
+
+module_usb_driver(gl861_usb_driver);
+
+MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>");
+MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/gl861.h b/drivers/media/usb/dvb-usb-v2/gl861.h
new file mode 100644
index 0000000..b0b80d8
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/gl861.h
@@ -0,0 +1,12 @@
+#ifndef _DVB_USB_GL861_H_
+#define _DVB_USB_GL861_H_
+
+#include "dvb_usb.h"
+
+#define GL861_WRITE		0x40
+#define GL861_READ		0xc0
+
+#define GL861_REQ_I2C_WRITE	0x01
+#define GL861_REQ_I2C_READ	0x02
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/it913x.c b/drivers/media/usb/dvb-usb-v2/it913x.c
new file mode 100644
index 0000000..695f910
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/it913x.c
@@ -0,0 +1,799 @@
+/*
+ * DVB USB compliant linux driver for ITE IT9135 and IT9137
+ *
+ * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
+ * IT9135 (C) ITE Tech Inc.
+ * IT9137 (C) ITE Tech Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/dvb/it9137.txt for firmware information
+ *
+ */
+#define DVB_USB_LOG_PREFIX "it913x"
+
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <media/rc-core.h>
+
+#include "dvb_usb.h"
+#include "it913x-fe.h"
+
+/* debug */
+static int dvb_usb_it913x_debug;
+#define it_debug(var, level, args...) \
+	do { if ((var & level)) pr_debug(DVB_USB_LOG_PREFIX": " args); \
+} while (0)
+#define deb_info(level, args...) it_debug(dvb_usb_it913x_debug, level, args)
+#define info(args...) pr_info(DVB_USB_LOG_PREFIX": " args)
+
+module_param_named(debug, dvb_usb_it913x_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
+
+static int dvb_usb_it913x_firmware;
+module_param_named(firmware, dvb_usb_it913x_firmware, int, 0644);
+MODULE_PARM_DESC(firmware, "set firmware 0=auto"\
+	"1=IT9137 2=IT9135 V1 3=IT9135 V2");
+#define FW_IT9137 "dvb-usb-it9137-01.fw"
+#define FW_IT9135_V1 "dvb-usb-it9135-01.fw"
+#define FW_IT9135_V2 "dvb-usb-it9135-02.fw"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct it913x_state {
+	struct ite_config it913x_config;
+	u8 pid_filter_onoff;
+	bool proprietary_ir;
+	int cmd_counter;
+};
+
+static u16 check_sum(u8 *p, u8 len)
+{
+	u16 sum = 0;
+	u8 i = 1;
+	while (i < len)
+		sum += (i++ & 1) ? (*p++) << 8 : *p++;
+	return ~sum;
+}
+
+static int it913x_io(struct dvb_usb_device *d, u8 mode, u8 pro,
+			u8 cmd, u32 reg, u8 addr, u8 *data, u8 len)
+{
+	struct it913x_state *st = d->priv;
+	int ret = 0, i, buf_size = 1;
+	u8 *buff;
+	u8 rlen;
+	u16 chk_sum;
+
+	buff = kzalloc(256, GFP_KERNEL);
+	if (!buff) {
+		info("USB Buffer Failed");
+		return -ENOMEM;
+	}
+
+	buff[buf_size++] = pro;
+	buff[buf_size++] = cmd;
+	buff[buf_size++] = st->cmd_counter;
+
+	switch (mode) {
+	case READ_LONG:
+	case WRITE_LONG:
+		buff[buf_size++] = len;
+		buff[buf_size++] = 2;
+		buff[buf_size++] = (reg >> 24);
+		buff[buf_size++] = (reg >> 16) & 0xff;
+		buff[buf_size++] = (reg >> 8) & 0xff;
+		buff[buf_size++] = reg & 0xff;
+	break;
+	case READ_SHORT:
+		buff[buf_size++] = addr;
+		break;
+	case WRITE_SHORT:
+		buff[buf_size++] = len;
+		buff[buf_size++] = addr;
+		buff[buf_size++] = (reg >> 8) & 0xff;
+		buff[buf_size++] = reg & 0xff;
+	break;
+	case READ_DATA:
+	case WRITE_DATA:
+		break;
+	case WRITE_CMD:
+		mode = 7;
+		break;
+	default:
+		kfree(buff);
+		return -EINVAL;
+	}
+
+	if (mode & 1) {
+		for (i = 0; i < len ; i++)
+			buff[buf_size++] = data[i];
+	}
+	chk_sum = check_sum(&buff[1], buf_size);
+
+	buff[buf_size++] = chk_sum >> 8;
+	buff[0] = buf_size;
+	buff[buf_size++] = (chk_sum & 0xff);
+
+	ret = dvb_usbv2_generic_rw(d, buff, buf_size, buff, (mode & 1) ?
+			5 : len + 5);
+	if (ret < 0)
+		goto error;
+
+	rlen = (mode & 0x1) ? 0x1 : len;
+
+	if (mode & 1)
+		ret = buff[2];
+	else
+		memcpy(data, &buff[3], rlen);
+
+	st->cmd_counter++;
+
+error:	kfree(buff);
+
+	return ret;
+}
+
+static int it913x_wr_reg(struct dvb_usb_device *d, u8 pro, u32 reg , u8 data)
+{
+	int ret;
+	u8 b[1];
+	b[0] = data;
+	ret = it913x_io(d, WRITE_LONG, pro,
+			CMD_DEMOD_WRITE, reg, 0, b, sizeof(b));
+
+	return ret;
+}
+
+static int it913x_read_reg(struct dvb_usb_device *d, u32 reg)
+{
+	int ret;
+	u8 data[1];
+
+	ret = it913x_io(d, READ_LONG, DEV_0,
+			CMD_DEMOD_READ, reg, 0, &data[0], sizeof(data));
+
+	return (ret < 0) ? ret : data[0];
+}
+
+static int it913x_query(struct dvb_usb_device *d, u8 pro)
+{
+	struct it913x_state *st = d->priv;
+	int ret, i;
+	u8 data[4];
+	u8 ver;
+
+	for (i = 0; i < 5; i++) {
+		ret = it913x_io(d, READ_LONG, pro, CMD_DEMOD_READ,
+			0x1222, 0, &data[0], 3);
+		ver = data[0];
+		if (ver > 0 && ver < 3)
+			break;
+		msleep(100);
+	}
+
+	if (ver < 1 || ver > 2) {
+		info("Failed to identify chip version applying 1");
+		st->it913x_config.chip_ver = 0x1;
+		st->it913x_config.chip_type = 0x9135;
+		return 0;
+	}
+
+	st->it913x_config.chip_ver = ver;
+	st->it913x_config.chip_type = (u16)(data[2] << 8) + data[1];
+
+	info("Chip Version=%02x Chip Type=%04x", st->it913x_config.chip_ver,
+		st->it913x_config.chip_type);
+
+	ret = it913x_io(d, READ_SHORT, pro,
+			CMD_QUERYINFO, 0, 0x1, &data[0], 4);
+
+	st->it913x_config.firmware = (data[0] << 24) | (data[1] << 16) |
+			(data[2] << 8) | data[3];
+
+	return ret;
+}
+
+static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct it913x_state *st = adap_to_priv(adap);
+	int ret;
+	u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
+
+	mutex_lock(&d->i2c_mutex);
+
+	deb_info(1, "PID_C  (%02x)", onoff);
+
+	ret = it913x_wr_reg(d, pro, PID_EN, st->pid_filter_onoff);
+
+	mutex_unlock(&d->i2c_mutex);
+	return ret;
+}
+
+static int it913x_pid_filter(struct dvb_usb_adapter *adap,
+		int index, u16 pid, int onoff)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct it913x_state *st = adap_to_priv(adap);
+	int ret;
+	u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
+
+	mutex_lock(&d->i2c_mutex);
+
+	deb_info(1, "PID_F  (%02x)", onoff);
+
+	ret = it913x_wr_reg(d, pro, PID_LSB, (u8)(pid & 0xff));
+
+	ret |= it913x_wr_reg(d, pro, PID_MSB, (u8)(pid >> 8));
+
+	ret |= it913x_wr_reg(d, pro, PID_INX_EN, (u8)onoff);
+
+	ret |= it913x_wr_reg(d, pro, PID_INX, (u8)(index & 0x1f));
+
+	if (d->udev->speed == USB_SPEED_HIGH && pid == 0x2000) {
+			ret |= it913x_wr_reg(d , pro, PID_EN, !onoff);
+			st->pid_filter_onoff = !onoff;
+	} else
+		st->pid_filter_onoff =
+			adap->pid_filtering;
+
+	mutex_unlock(&d->i2c_mutex);
+	return 0;
+}
+
+
+static int it913x_return_status(struct dvb_usb_device *d)
+{
+	struct it913x_state *st = d->priv;
+	int ret = it913x_query(d, DEV_0);
+	if (st->it913x_config.firmware > 0)
+		info("Firmware Version %d", st->it913x_config.firmware);
+
+	return ret;
+}
+
+static int it913x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+				 int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	static u8 data[256];
+	int ret;
+	u32 reg;
+	u8 pro;
+
+	mutex_lock(&d->i2c_mutex);
+
+	deb_info(2, "num of messages %d address %02x", num, msg[0].addr);
+
+	pro = (msg[0].addr & 0x2) ?  DEV_0_DMOD : 0x0;
+	pro |= (msg[0].addr & 0x20) ? DEV_1 : DEV_0;
+	memcpy(data, msg[0].buf, msg[0].len);
+	reg = (data[0] << 24) + (data[1] << 16) +
+			(data[2] << 8) + data[3];
+	if (num == 2) {
+		ret = it913x_io(d, READ_LONG, pro,
+			CMD_DEMOD_READ, reg, 0, data, msg[1].len);
+		memcpy(msg[1].buf, data, msg[1].len);
+	} else
+		ret = it913x_io(d, WRITE_LONG, pro, CMD_DEMOD_WRITE,
+			reg, 0, &data[4], msg[0].len - 4);
+
+	mutex_unlock(&d->i2c_mutex);
+
+	return ret;
+}
+
+static u32 it913x_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm it913x_i2c_algo = {
+	.master_xfer   = it913x_i2c_xfer,
+	.functionality = it913x_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+#define IT913X_POLL 250
+static int it913x_rc_query(struct dvb_usb_device *d)
+{
+	u8 ibuf[4];
+	int ret;
+	u32 key;
+	/* Avoid conflict with frontends*/
+	mutex_lock(&d->i2c_mutex);
+
+	ret = it913x_io(d, READ_LONG, PRO_LINK, CMD_IR_GET,
+		0, 0, &ibuf[0], sizeof(ibuf));
+
+	if ((ibuf[2] + ibuf[3]) == 0xff) {
+		key = ibuf[2];
+		key += ibuf[0] << 16;
+		key += ibuf[1] << 8;
+		deb_info(1, "NEC Extended Key =%08x", key);
+		if (d->rc_dev != NULL)
+			rc_keydown(d->rc_dev, key, 0);
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+
+	return ret;
+}
+
+/* Firmware sets raw */
+static const char fw_it9135_v1[] = FW_IT9135_V1;
+static const char fw_it9135_v2[] = FW_IT9135_V2;
+static const char fw_it9137[] = FW_IT9137;
+
+static void ite_get_firmware_name(struct dvb_usb_device *d,
+	const char **name)
+{
+	struct it913x_state *st = d->priv;
+	int sw;
+	/* auto switch */
+	if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_KWORLD_2)
+		sw = IT9137_FW;
+	else if (st->it913x_config.chip_ver == 1)
+		sw = IT9135_V1_FW;
+	else
+		sw = IT9135_V2_FW;
+
+	/* force switch */
+	if (dvb_usb_it913x_firmware != IT9135_AUTO)
+		sw = dvb_usb_it913x_firmware;
+
+	switch (sw) {
+	case IT9135_V1_FW:
+		st->it913x_config.firmware_ver = 1;
+		st->it913x_config.adc_x2 = 1;
+		st->it913x_config.read_slevel = false;
+		*name = fw_it9135_v1;
+		break;
+	case IT9135_V2_FW:
+		st->it913x_config.firmware_ver = 1;
+		st->it913x_config.adc_x2 = 1;
+		st->it913x_config.read_slevel = false;
+		*name = fw_it9135_v2;
+		switch (st->it913x_config.tuner_id_0) {
+		case IT9135_61:
+		case IT9135_62:
+			break;
+		default:
+			info("Unknown tuner ID applying default 0x60");
+		case IT9135_60:
+			st->it913x_config.tuner_id_0 = IT9135_60;
+		}
+		break;
+	case IT9137_FW:
+	default:
+		st->it913x_config.firmware_ver = 0;
+		st->it913x_config.adc_x2 = 0;
+		st->it913x_config.read_slevel = true;
+		*name = fw_it9137;
+	}
+
+	return;
+}
+
+#define TS_MPEG_PKT_SIZE	188
+#define EP_LOW			21
+#define TS_BUFFER_SIZE_PID	(EP_LOW*TS_MPEG_PKT_SIZE)
+#define EP_HIGH			348
+#define TS_BUFFER_SIZE_MAX	(EP_HIGH*TS_MPEG_PKT_SIZE)
+
+static int it913x_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
+		struct usb_data_stream_properties *stream)
+{
+	struct dvb_usb_adapter *adap = fe_to_adap(fe);
+	if (adap->pid_filtering)
+		stream->u.bulk.buffersize = TS_BUFFER_SIZE_PID;
+	else
+		stream->u.bulk.buffersize = TS_BUFFER_SIZE_MAX;
+
+	return 0;
+}
+
+static int it913x_select_config(struct dvb_usb_device *d)
+{
+	struct it913x_state *st = d->priv;
+	int ret, reg;
+
+	ret = it913x_return_status(d);
+	if (ret < 0)
+		return ret;
+
+	if (st->it913x_config.chip_ver == 0x02
+			&& st->it913x_config.chip_type == 0x9135)
+		reg = it913x_read_reg(d, 0x461d);
+	else
+		reg = it913x_read_reg(d, 0x461b);
+
+	if (reg < 0)
+		return reg;
+
+	if (reg == 0) {
+		st->it913x_config.dual_mode = 0;
+		st->it913x_config.tuner_id_0 = IT9135_38;
+		st->proprietary_ir = true;
+	} else {
+		/* TS mode */
+		reg =  it913x_read_reg(d, 0x49c5);
+		if (reg < 0)
+			return reg;
+		st->it913x_config.dual_mode = reg;
+
+		/* IR mode type */
+		reg = it913x_read_reg(d, 0x49ac);
+		if (reg < 0)
+			return reg;
+		if (reg == 5) {
+			info("Remote propriety (raw) mode");
+			st->proprietary_ir = true;
+		} else if (reg == 1) {
+			info("Remote HID mode NOT SUPPORTED");
+			st->proprietary_ir = false;
+		}
+
+		/* Tuner_id */
+		reg = it913x_read_reg(d, 0x49d0);
+		if (reg < 0)
+			return reg;
+		st->it913x_config.tuner_id_0 = reg;
+	}
+
+	info("Dual mode=%x Tuner Type=%x", st->it913x_config.dual_mode,
+		st->it913x_config.tuner_id_0);
+
+	return ret;
+}
+
+static int it913x_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+	struct dvb_usb_adapter *adap = fe_to_adap(fe);
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct it913x_state *st = fe_to_priv(fe);
+	int ret = 0;
+	u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
+
+	deb_info(1, "STM  (%02x)", onoff);
+
+	if (!onoff) {
+		mutex_lock(&d->i2c_mutex);
+
+		ret = it913x_wr_reg(d, pro, PID_RST, 0x1);
+
+		mutex_unlock(&d->i2c_mutex);
+		st->pid_filter_onoff =
+			adap->pid_filtering;
+
+	}
+
+	return ret;
+}
+
+static int it913x_identify_state(struct dvb_usb_device *d, const char **name)
+{
+	struct it913x_state *st = d->priv;
+	int ret;
+	u8 reg;
+
+	/* Read and select config */
+	ret = it913x_select_config(d);
+	if (ret < 0)
+		return ret;
+
+	ite_get_firmware_name(d, name);
+
+	if (st->it913x_config.firmware > 0)
+		return WARM;
+
+	if (st->it913x_config.dual_mode) {
+		st->it913x_config.tuner_id_1 = it913x_read_reg(d, 0x49e0);
+		ret = it913x_wr_reg(d, DEV_0, GPIOH1_EN, 0x1);
+		ret |= it913x_wr_reg(d, DEV_0, GPIOH1_ON, 0x1);
+		ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x1);
+		msleep(50);
+		ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x0);
+		msleep(50);
+		reg = it913x_read_reg(d, GPIOH1_O);
+		if (reg == 0) {
+			ret |= it913x_wr_reg(d, DEV_0,  GPIOH1_O, 0x1);
+			ret |= it913x_return_status(d);
+			if (ret != 0)
+				ret = it913x_wr_reg(d, DEV_0,
+					GPIOH1_O, 0x0);
+		}
+	}
+
+	reg = it913x_read_reg(d, IO_MUX_POWER_CLK);
+
+	if (st->it913x_config.dual_mode) {
+		ret |= it913x_wr_reg(d, DEV_0, 0x4bfb, CHIP2_I2C_ADDR);
+		if (st->it913x_config.firmware_ver == 1)
+			ret |= it913x_wr_reg(d, DEV_0,  0xcfff, 0x1);
+		else
+			ret |= it913x_wr_reg(d, DEV_0,  CLK_O_EN, 0x1);
+	} else {
+		ret |= it913x_wr_reg(d, DEV_0, 0x4bfb, 0x0);
+		if (st->it913x_config.firmware_ver == 1)
+			ret |= it913x_wr_reg(d, DEV_0,  0xcfff, 0x0);
+		else
+			ret |= it913x_wr_reg(d, DEV_0,  CLK_O_EN, 0x0);
+	}
+
+	ret |= it913x_wr_reg(d, DEV_0,  I2C_CLK, I2C_CLK_100);
+
+	return (ret < 0) ? ret : COLD;
+}
+
+static int it913x_download_firmware(struct dvb_usb_device *d,
+					const struct firmware *fw)
+{
+	struct it913x_state *st = d->priv;
+	int ret = 0, i = 0, pos = 0;
+	u8 packet_size, min_pkt;
+	u8 *fw_data;
+
+	ret = it913x_wr_reg(d, DEV_0,  I2C_CLK, I2C_CLK_100);
+
+	info("FRM Starting Firmware Download");
+
+	/* Multi firmware loader */
+	/* This uses scatter write firmware headers */
+	/* The firmware must start with 03 XX 00 */
+	/* and be the extact firmware length */
+
+	if (st->it913x_config.chip_ver == 2)
+		min_pkt = 0x11;
+	else
+		min_pkt = 0x19;
+
+	while (i <= fw->size) {
+		if (((fw->data[i] == 0x3) && (fw->data[i + 2] == 0x0))
+			|| (i == fw->size)) {
+			packet_size = i - pos;
+			if ((packet_size > min_pkt) || (i == fw->size)) {
+				fw_data = (u8 *)(fw->data + pos);
+				pos += packet_size;
+				if (packet_size > 0) {
+					ret = it913x_io(d, WRITE_DATA,
+						DEV_0, CMD_SCATTER_WRITE, 0,
+						0, fw_data, packet_size);
+					if (ret < 0)
+						break;
+				}
+				udelay(1000);
+			}
+		}
+		i++;
+	}
+
+	if (ret < 0)
+		info("FRM Firmware Download Failed (%d)" , ret);
+	else
+		info("FRM Firmware Download Completed - Resetting Device");
+
+	msleep(30);
+
+	ret = it913x_io(d, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0);
+	if (ret < 0)
+		info("FRM Device not responding to reboot");
+
+	ret = it913x_return_status(d);
+	if (st->it913x_config.firmware == 0) {
+		info("FRM Failed to reboot device");
+		return -ENODEV;
+	}
+
+	msleep(30);
+
+	ret = it913x_wr_reg(d, DEV_0,  I2C_CLK, I2C_CLK_400);
+
+	msleep(30);
+
+	/* Tuner function */
+	if (st->it913x_config.dual_mode)
+		ret |= it913x_wr_reg(d, DEV_0_DMOD , 0xec4c, 0xa0);
+	else
+		ret |= it913x_wr_reg(d, DEV_0_DMOD , 0xec4c, 0x68);
+
+	if ((st->it913x_config.chip_ver == 1) &&
+		(st->it913x_config.chip_type == 0x9135)) {
+		ret |= it913x_wr_reg(d, DEV_0,  PADODPU, 0x0);
+		ret |= it913x_wr_reg(d, DEV_0,  AGC_O_D, 0x0);
+		if (st->it913x_config.dual_mode) {
+			ret |= it913x_wr_reg(d, DEV_1,  PADODPU, 0x0);
+			ret |= it913x_wr_reg(d, DEV_1,  AGC_O_D, 0x0);
+		}
+	}
+
+	return (ret < 0) ? -ENODEV : 0;
+}
+
+static int it913x_name(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	const char *desc = d->name;
+	char *fe_name[] = {"_1", "_2", "_3", "_4"};
+	char *name = adap->fe[0]->ops.info.name;
+
+	strlcpy(name, desc, 128);
+	strlcat(name, fe_name[adap->id], 128);
+
+	return 0;
+}
+
+static int it913x_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct it913x_state *st = d->priv;
+	int ret = 0;
+	u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5);
+	u16 ep_size = adap->stream.buf_size / 4;
+	u8 pkt_size = 0x80;
+
+	if (d->udev->speed != USB_SPEED_HIGH)
+		pkt_size = 0x10;
+
+	st->it913x_config.adf = it913x_read_reg(d, IO_MUX_POWER_CLK);
+
+	adap->fe[0] = dvb_attach(it913x_fe_attach,
+		&d->i2c_adap, adap_addr, &st->it913x_config);
+
+	if (adap->id == 0 && adap->fe[0]) {
+		it913x_wr_reg(d, DEV_0_DMOD, MP2_SW_RST, 0x1);
+		it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_SW_RST, 0x1);
+		it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x0f);
+		it913x_wr_reg(d, DEV_0, EP0_TX_NAK, 0x1b);
+		it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x2f);
+		it913x_wr_reg(d, DEV_0, EP4_TX_LEN_LSB,
+					ep_size & 0xff);
+		it913x_wr_reg(d, DEV_0, EP4_TX_LEN_MSB, ep_size >> 8);
+		ret = it913x_wr_reg(d, DEV_0, EP4_MAX_PKT, pkt_size);
+	} else if (adap->id == 1 && adap->fe[0]) {
+		it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x6f);
+		it913x_wr_reg(d, DEV_0, EP5_TX_LEN_LSB,
+					ep_size & 0xff);
+		it913x_wr_reg(d, DEV_0, EP5_TX_LEN_MSB, ep_size >> 8);
+		it913x_wr_reg(d, DEV_0, EP5_MAX_PKT, pkt_size);
+		it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_EN, 0x1);
+		it913x_wr_reg(d, DEV_1_DMOD, MP2IF_SERIAL, 0x1);
+		it913x_wr_reg(d, DEV_1, TOP_HOSTB_SER_MODE, 0x1);
+		it913x_wr_reg(d, DEV_0_DMOD, TSIS_ENABLE, 0x1);
+		it913x_wr_reg(d, DEV_0_DMOD, MP2_SW_RST, 0x0);
+		it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_SW_RST, 0x0);
+		it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_HALF_PSB, 0x0);
+		it913x_wr_reg(d, DEV_0_DMOD, MP2IF_STOP_EN, 0x1);
+		it913x_wr_reg(d, DEV_1_DMOD, MPEG_FULL_SPEED, 0x0);
+		ret = it913x_wr_reg(d, DEV_1_DMOD, MP2IF_STOP_EN, 0x0);
+	} else
+		return -ENODEV;
+
+	ret |= it913x_name(adap);
+
+	return ret;
+}
+
+/* DVB USB Driver */
+static int it913x_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+	struct it913x_state *st = d->priv;
+
+	if (st->proprietary_ir == false) {
+		rc->map_name = NULL;
+		return 0;
+	}
+
+	rc->allowed_protos = RC_TYPE_NEC;
+	rc->query = it913x_rc_query;
+	rc->interval = 250;
+
+	return 0;
+}
+
+static int it913x_get_adapter_count(struct dvb_usb_device *d)
+{
+	struct it913x_state *st = d->priv;
+	if (st->it913x_config.dual_mode)
+		return 2;
+	return 1;
+}
+
+static struct dvb_usb_device_properties it913x_properties = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.bInterfaceNumber = 0,
+	.generic_bulk_ctrl_endpoint = 0x02,
+	.generic_bulk_ctrl_endpoint_response = 0x81,
+
+	.adapter_nr = adapter_nr,
+	.size_of_priv = sizeof(struct it913x_state),
+
+	.identify_state = it913x_identify_state,
+	.i2c_algo = &it913x_i2c_algo,
+
+	.download_firmware = it913x_download_firmware,
+
+	.frontend_attach  = it913x_frontend_attach,
+	.get_rc_config = it913x_get_rc_config,
+	.get_stream_config = it913x_get_stream_config,
+	.get_adapter_count = it913x_get_adapter_count,
+	.streaming_ctrl   = it913x_streaming_ctrl,
+
+
+	.adapter = {
+		{
+			.caps = DVB_USB_ADAP_HAS_PID_FILTER|
+				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+			.pid_filter_count = 32,
+			.pid_filter = it913x_pid_filter,
+			.pid_filter_ctrl  = it913x_pid_filter_ctrl,
+			.stream =
+			DVB_USB_STREAM_BULK(0x84, 10, TS_BUFFER_SIZE_MAX),
+		},
+		{
+			.caps = DVB_USB_ADAP_HAS_PID_FILTER|
+				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+			.pid_filter_count = 32,
+			.pid_filter = it913x_pid_filter,
+			.pid_filter_ctrl  = it913x_pid_filter_ctrl,
+			.stream =
+			DVB_USB_STREAM_BULK(0x85, 10, TS_BUFFER_SIZE_MAX),
+		}
+	}
+};
+
+static const struct usb_device_id it913x_id_table[] = {
+	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09,
+		&it913x_properties, "Kworld UB499-2T T09(IT9137)",
+			RC_MAP_IT913X_V1) },
+	{ DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135,
+		&it913x_properties, "ITE 9135 Generic",
+			RC_MAP_IT913X_V1) },
+	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22_IT9137,
+		&it913x_properties, "Sveon STV22 Dual DVB-T HDTV(IT9137)",
+			RC_MAP_IT913X_V1) },
+	{ DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9005,
+		&it913x_properties, "ITE 9135(9005) Generic",
+			RC_MAP_IT913X_V2) },
+	{ DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9006,
+		&it913x_properties, "ITE 9135(9006) Generic",
+			RC_MAP_IT913X_V1) },
+	{}		/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, it913x_id_table);
+
+static struct usb_driver it913x_driver = {
+	.name		= KBUILD_MODNAME,
+	.probe		= dvb_usbv2_probe,
+	.disconnect	= dvb_usbv2_disconnect,
+	.suspend	= dvb_usbv2_suspend,
+	.resume		= dvb_usbv2_resume,
+	.id_table	= it913x_id_table,
+};
+
+module_usb_driver(it913x_driver);
+
+MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
+MODULE_DESCRIPTION("it913x USB 2 Driver");
+MODULE_VERSION("1.32");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(FW_IT9135_V1);
+MODULE_FIRMWARE(FW_IT9135_V2);
+MODULE_FIRMWARE(FW_IT9137);
+
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
new file mode 100644
index 0000000..c41d9d9
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -0,0 +1,1369 @@
+/* DVB USB compliant linux driver for
+ *
+ * DM04/QQBOX DVB-S USB BOX	LME2510C + SHARP:BS2F7HZ7395
+ *				LME2510C + LG TDQY-P001F
+ *				LME2510C + BS2F7HZ0194
+ *				LME2510 + LG TDQY-P001F
+ *				LME2510 + BS2F7HZ0194
+ *
+ * MVB7395 (LME2510C+SHARP:BS2F7HZ7395)
+ * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V)
+ *
+ * MV001F (LME2510+LGTDQY-P001F)
+ * LG TDQY - P001F =(TDA8263 + TDA10086H)
+ *
+ * MVB0001F (LME2510C+LGTDQT-P001F)
+ *
+ * MV0194 (LME2510+SHARP:BS2F7HZ0194)
+ * SHARP:BS2F7HZ0194 = (STV0299+IX2410)
+ *
+ * MVB0194 (LME2510C+SHARP0194)
+ *
+ * LME2510C + M88RS2000
+ *
+ * For firmware see Documentation/dvb/lmedm04.txt
+ *
+ * I2C addresses:
+ * 0xd0 - STV0288	- Demodulator
+ * 0xc0 - Sharp IX2505V	- Tuner
+ * --
+ * 0x1c - TDA10086   - Demodulator
+ * 0xc0 - TDA8263    - Tuner
+ * --
+ * 0xd0 - STV0299	- Demodulator
+ * 0xc0 - IX2410	- Tuner
+ *
+ *
+ * VID = 3344  PID LME2510=1122 LME2510C=1120
+ *
+ * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com)
+ * LME2510(C)(C) Leaguerme (Shenzhen) MicroElectronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ *
+ * Known Issues :
+ *	LME2510: Non Intel USB chipsets fail to maintain High Speed on
+ * Boot or Hot Plug.
+ *
+ * QQbox suffers from noise on LNB voltage.
+ *
+ *	LME2510: SHARP:BS2F7HZ0194(MV0194) cannot cold reset and share system
+ * with other tuners. After a cold reset streaming will not start.
+ *
+ * M88RS2000 suffers from loss of lock.
+ */
+#define DVB_USB_LOG_PREFIX "LME2510(C)"
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <media/rc-core.h>
+
+#include "dvb_usb.h"
+#include "lmedm04.h"
+#include "tda826x.h"
+#include "tda10086.h"
+#include "stv0288.h"
+#include "ix2505v.h"
+#include "stv0299.h"
+#include "dvb-pll.h"
+#include "z0194a.h"
+#include "m88rs2000.h"
+
+
+#define LME2510_C_S7395	"dvb-usb-lme2510c-s7395.fw";
+#define LME2510_C_LG	"dvb-usb-lme2510c-lg.fw";
+#define LME2510_C_S0194	"dvb-usb-lme2510c-s0194.fw";
+#define LME2510_C_RS2000 "dvb-usb-lme2510c-rs2000.fw";
+#define LME2510_LG	"dvb-usb-lme2510-lg.fw";
+#define LME2510_S0194	"dvb-usb-lme2510-s0194.fw";
+
+/* debug */
+static int dvb_usb_lme2510_debug;
+#define lme_debug(var, level, args...) do { \
+	if ((var >= level)) \
+		pr_debug(DVB_USB_LOG_PREFIX": " args); \
+} while (0)
+#define deb_info(level, args...) lme_debug(dvb_usb_lme2510_debug, level, args)
+#define debug_data_snipet(level, name, p) \
+	 deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \
+		*p, *(p+1), *(p+2), *(p+3), *(p+4), \
+			*(p+5), *(p+6), *(p+7));
+#define info(args...) pr_info(DVB_USB_LOG_PREFIX": "args)
+
+module_param_named(debug, dvb_usb_lme2510_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
+
+static int dvb_usb_lme2510_firmware;
+module_param_named(firmware, dvb_usb_lme2510_firmware, int, 0644);
+MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG");
+
+static int pid_filter;
+module_param_named(pid, pid_filter, int, 0644);
+MODULE_PARM_DESC(pid, "set default 0=default 1=off 2=on");
+
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define TUNER_DEFAULT	0x0
+#define TUNER_LG	0x1
+#define TUNER_S7395	0x2
+#define TUNER_S0194	0x3
+#define TUNER_RS2000	0x4
+
+struct lme2510_state {
+	u8 id;
+	u8 tuner_config;
+	u8 signal_lock;
+	u8 signal_level;
+	u8 signal_sn;
+	u8 time_key;
+	u8 last_key;
+	u8 key_timeout;
+	u8 i2c_talk_onoff;
+	u8 i2c_gate;
+	u8 i2c_tuner_gate_w;
+	u8 i2c_tuner_gate_r;
+	u8 i2c_tuner_addr;
+	u8 stream_on;
+	u8 pid_size;
+	u8 pid_off;
+	void *buffer;
+	struct urb *lme_urb;
+	void *usb_buffer;
+	int (*fe_set_voltage)(struct dvb_frontend *, fe_sec_voltage_t);
+	u8 dvb_usb_lme2510_firmware;
+};
+
+static int lme2510_bulk_write(struct usb_device *dev,
+				u8 *snd, int len, u8 pipe)
+{
+	int ret, actual_l;
+
+	ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
+				snd, len , &actual_l, 100);
+	return ret;
+}
+
+static int lme2510_bulk_read(struct usb_device *dev,
+				u8 *rev, int len, u8 pipe)
+{
+	int ret, actual_l;
+
+	ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
+				 rev, len , &actual_l, 200);
+	return ret;
+}
+
+static int lme2510_usb_talk(struct dvb_usb_device *d,
+		u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+	struct lme2510_state *st = d->priv;
+	u8 *buff;
+	int ret = 0;
+
+	if (st->usb_buffer == NULL) {
+		st->usb_buffer = kmalloc(64, GFP_KERNEL);
+		if (st->usb_buffer == NULL) {
+			info("MEM Error no memory");
+			return -ENOMEM;
+		}
+	}
+	buff = st->usb_buffer;
+
+	ret = mutex_lock_interruptible(&d->usb_mutex);
+
+	if (ret < 0)
+		return -EAGAIN;
+
+	/* the read/write capped at 64 */
+	memcpy(buff, wbuf, (wlen < 64) ? wlen : 64);
+
+	ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01);
+
+	ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ?
+			rlen : 64 , 0x01);
+
+	if (rlen > 0)
+		memcpy(rbuf, buff, rlen);
+
+	mutex_unlock(&d->usb_mutex);
+
+	return (ret < 0) ? -ENODEV : 0;
+}
+
+static int lme2510_stream_restart(struct dvb_usb_device *d)
+{
+	struct lme2510_state *st = d->priv;
+	u8 all_pids[] = LME_ALL_PIDS;
+	u8 stream_on[] = LME_ST_ON_W;
+	int ret;
+	u8 rbuff[1];
+	if (st->pid_off)
+		ret = lme2510_usb_talk(d, all_pids, sizeof(all_pids),
+			rbuff, sizeof(rbuff));
+	/*Restart Stream Command*/
+	ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on),
+			rbuff, sizeof(rbuff));
+	return ret;
+}
+
+static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out)
+{
+	struct lme2510_state *st = d->priv;
+	static u8 pid_buff[] = LME_ZERO_PID;
+	static u8 rbuf[1];
+	u8 pid_no = index * 2;
+	u8 pid_len = pid_no + 2;
+	int ret = 0;
+	deb_info(1, "PID Setting Pid %04x", pid_out);
+
+	if (st->pid_size == 0)
+		ret |= lme2510_stream_restart(d);
+
+	pid_buff[2] = pid_no;
+	pid_buff[3] = (u8)pid_out & 0xff;
+	pid_buff[4] = pid_no + 1;
+	pid_buff[5] = (u8)(pid_out >> 8);
+
+	if (pid_len > st->pid_size)
+		st->pid_size = pid_len;
+	pid_buff[7] = 0x80 + st->pid_size;
+
+	ret |= lme2510_usb_talk(d, pid_buff ,
+		sizeof(pid_buff) , rbuf, sizeof(rbuf));
+
+	if (st->stream_on)
+		ret |= lme2510_stream_restart(d);
+
+	return ret;
+}
+
+static void lme2510_int_response(struct urb *lme_urb)
+{
+	struct dvb_usb_adapter *adap = lme_urb->context;
+	struct lme2510_state *st = adap_to_priv(adap);
+	static u8 *ibuf, *rbuf;
+	int i = 0, offset;
+	u32 key;
+
+	switch (lme_urb->status) {
+	case 0:
+	case -ETIMEDOUT:
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	default:
+		info("Error %x", lme_urb->status);
+		break;
+	}
+
+	rbuf = (u8 *) lme_urb->transfer_buffer;
+
+	offset = ((lme_urb->actual_length/8) > 4)
+			? 4 : (lme_urb->actual_length/8) ;
+
+	for (i = 0; i < offset; ++i) {
+		ibuf = (u8 *)&rbuf[i*8];
+		deb_info(5, "INT O/S C =%02x C/O=%02x Type =%02x%02x",
+		offset, i, ibuf[0], ibuf[1]);
+
+		switch (ibuf[0]) {
+		case 0xaa:
+			debug_data_snipet(1, "INT Remote data snipet", ibuf);
+			if ((ibuf[4] + ibuf[5]) == 0xff) {
+				key = ibuf[5];
+				key += (ibuf[3] > 0)
+					? (ibuf[3] ^ 0xff) << 8 : 0;
+				key += (ibuf[2] ^ 0xff) << 16;
+				deb_info(1, "INT Key =%08x", key);
+				if (adap_to_d(adap)->rc_dev != NULL)
+					rc_keydown(adap_to_d(adap)->rc_dev,
+						key, 0);
+			}
+			break;
+		case 0xbb:
+			switch (st->tuner_config) {
+			case TUNER_LG:
+				if (ibuf[2] > 0)
+					st->signal_lock = ibuf[2];
+				st->signal_level = ibuf[4];
+				st->signal_sn = ibuf[3];
+				st->time_key = ibuf[7];
+				break;
+			case TUNER_S7395:
+			case TUNER_S0194:
+				/* Tweak for earlier firmware*/
+				if (ibuf[1] == 0x03) {
+					if (ibuf[2] > 1)
+						st->signal_lock = ibuf[2];
+					st->signal_level = ibuf[3];
+					st->signal_sn = ibuf[4];
+				} else {
+					st->signal_level = ibuf[4];
+					st->signal_sn = ibuf[5];
+					st->signal_lock =
+						(st->signal_lock & 0xf7) +
+						((ibuf[2] & 0x01) << 0x03);
+				}
+				break;
+			case TUNER_RS2000:
+				if (ibuf[1] == 0x3 &&  ibuf[6] == 0xff)
+					st->signal_lock = 0xff;
+				else
+					st->signal_lock = 0x00;
+				st->signal_level = ibuf[5];
+				st->signal_sn = ibuf[4];
+				st->time_key = ibuf[7];
+			default:
+				break;
+			}
+			debug_data_snipet(5, "INT Remote data snipet in", ibuf);
+		break;
+		case 0xcc:
+			debug_data_snipet(1, "INT Control data snipet", ibuf);
+			break;
+		default:
+			debug_data_snipet(1, "INT Unknown data snipet", ibuf);
+		break;
+		}
+	}
+	usb_submit_urb(lme_urb, GFP_ATOMIC);
+}
+
+static int lme2510_int_read(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct lme2510_state *lme_int = adap_to_priv(adap);
+
+	lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC);
+
+	if (lme_int->lme_urb == NULL)
+			return -ENOMEM;
+
+	lme_int->buffer = usb_alloc_coherent(d->udev, 128, GFP_ATOMIC,
+					&lme_int->lme_urb->transfer_dma);
+
+	if (lme_int->buffer == NULL)
+			return -ENOMEM;
+
+	usb_fill_int_urb(lme_int->lme_urb,
+				d->udev,
+				usb_rcvintpipe(d->udev, 0xa),
+				lme_int->buffer,
+				128,
+				lme2510_int_response,
+				adap,
+				8);
+
+	lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC);
+	info("INT Interrupt Service Started");
+
+	return 0;
+}
+
+static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct lme2510_state *st = adap_to_priv(adap);
+	static u8 clear_pid_reg[] = LME_ALL_PIDS;
+	static u8 rbuf[1];
+	int ret = 0;
+
+	deb_info(1, "PID Clearing Filter");
+
+	mutex_lock(&d->i2c_mutex);
+
+	if (!onoff) {
+		ret |= lme2510_usb_talk(d, clear_pid_reg,
+			sizeof(clear_pid_reg), rbuf, sizeof(rbuf));
+		st->pid_off = true;
+	} else
+		st->pid_off = false;
+
+	st->pid_size = 0;
+
+	mutex_unlock(&d->i2c_mutex);
+
+	return 0;
+}
+
+static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+	int onoff)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	int ret = 0;
+
+	deb_info(3, "%s PID=%04x Index=%04x onoff=%02x", __func__,
+		pid, index, onoff);
+
+	if (onoff) {
+		mutex_lock(&d->i2c_mutex);
+		ret |= lme2510_enable_pid(d, index, pid);
+		mutex_unlock(&d->i2c_mutex);
+	}
+
+
+	return ret;
+}
+
+
+static int lme2510_return_status(struct dvb_usb_device *d)
+{
+	int ret = 0;
+	u8 *data;
+
+	data = kzalloc(10, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	ret |= usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
+			0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
+	info("Firmware Status: %x (%x)", ret , data[2]);
+
+	ret = (ret < 0) ? -ENODEV : data[2];
+	kfree(data);
+	return ret;
+}
+
+static int lme2510_msg(struct dvb_usb_device *d,
+		u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+	int ret = 0;
+	struct lme2510_state *st = d->priv;
+
+	if (st->i2c_talk_onoff == 1) {
+
+		ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+
+		switch (st->tuner_config) {
+		case TUNER_LG:
+			if (wbuf[2] == 0x1c) {
+				if (wbuf[3] == 0x0e) {
+					st->signal_lock = rbuf[1];
+					if ((st->stream_on & 1) &&
+						(st->signal_lock & 0x10)) {
+						lme2510_stream_restart(d);
+						st->i2c_talk_onoff = 0;
+					}
+					msleep(80);
+				}
+			}
+			break;
+		case TUNER_S7395:
+			if (wbuf[2] == 0xd0) {
+				if (wbuf[3] == 0x24) {
+					st->signal_lock = rbuf[1];
+					if ((st->stream_on & 1) &&
+						(st->signal_lock & 0x8)) {
+						lme2510_stream_restart(d);
+						st->i2c_talk_onoff = 0;
+					}
+				}
+			}
+			break;
+		case TUNER_S0194:
+			if (wbuf[2] == 0xd0) {
+				if (wbuf[3] == 0x1b) {
+					st->signal_lock = rbuf[1];
+					if ((st->stream_on & 1) &&
+						(st->signal_lock & 0x8)) {
+						lme2510_stream_restart(d);
+						st->i2c_talk_onoff = 0;
+					}
+				}
+			}
+			break;
+		case TUNER_RS2000:
+		default:
+			break;
+		}
+	} else {
+		/* TODO rewrite this section */
+		switch (st->tuner_config) {
+		case TUNER_LG:
+			switch (wbuf[3]) {
+			case 0x0e:
+				rbuf[0] = 0x55;
+				rbuf[1] = st->signal_lock;
+				break;
+			case 0x43:
+				rbuf[0] = 0x55;
+				rbuf[1] = st->signal_level;
+				break;
+			case 0x1c:
+				rbuf[0] = 0x55;
+				rbuf[1] = st->signal_sn;
+				break;
+			case 0x15:
+			case 0x16:
+			case 0x17:
+			case 0x18:
+				rbuf[0] = 0x55;
+				rbuf[1] = 0x00;
+				break;
+			default:
+				lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+				st->i2c_talk_onoff = 1;
+				break;
+			}
+			break;
+		case TUNER_S7395:
+			switch (wbuf[3]) {
+			case 0x10:
+				rbuf[0] = 0x55;
+				rbuf[1] = (st->signal_level & 0x80)
+						? 0 : (st->signal_level * 2);
+				break;
+			case 0x2d:
+				rbuf[0] = 0x55;
+				rbuf[1] = st->signal_sn;
+				break;
+			case 0x24:
+				rbuf[0] = 0x55;
+				rbuf[1] = st->signal_lock;
+				break;
+			case 0x2e:
+			case 0x26:
+			case 0x27:
+				rbuf[0] = 0x55;
+				rbuf[1] = 0x00;
+				break;
+			default:
+				lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+				st->i2c_talk_onoff = 1;
+				break;
+			}
+			break;
+		case TUNER_S0194:
+			switch (wbuf[3]) {
+			case 0x18:
+				rbuf[0] = 0x55;
+				rbuf[1] = (st->signal_level & 0x80)
+						? 0 : (st->signal_level * 2);
+				break;
+			case 0x24:
+				rbuf[0] = 0x55;
+				rbuf[1] = st->signal_sn;
+				break;
+			case 0x1b:
+				rbuf[0] = 0x55;
+				rbuf[1] = st->signal_lock;
+				break;
+			case 0x19:
+			case 0x25:
+			case 0x1e:
+			case 0x1d:
+				rbuf[0] = 0x55;
+				rbuf[1] = 0x00;
+				break;
+			default:
+				lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+				st->i2c_talk_onoff = 1;
+				break;
+			}
+			break;
+		case TUNER_RS2000:
+			switch (wbuf[3]) {
+			case 0x8c:
+				rbuf[0] = 0x55;
+				rbuf[1] = 0xff;
+				if (st->last_key == st->time_key) {
+					st->key_timeout++;
+					if (st->key_timeout > 5)
+						rbuf[1] = 0;
+				} else
+					st->key_timeout = 0;
+				st->last_key = st->time_key;
+				break;
+			default:
+				lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+				st->i2c_talk_onoff = 1;
+				break;
+			}
+		default:
+			break;
+		}
+
+		deb_info(4, "I2C From Interrupt Message out(%02x) in(%02x)",
+				wbuf[3], rbuf[1]);
+
+	}
+
+	return ret;
+}
+
+
+static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+				 int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct lme2510_state *st = d->priv;
+	static u8 obuf[64], ibuf[64];
+	int i, read, read_o;
+	u16 len;
+	u8 gate = st->i2c_gate;
+
+	mutex_lock(&d->i2c_mutex);
+
+	if (gate == 0)
+		gate = 5;
+
+	for (i = 0; i < num; i++) {
+		read_o = 1 & (msg[i].flags & I2C_M_RD);
+		read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
+		read |= read_o;
+		gate = (msg[i].addr == st->i2c_tuner_addr)
+			? (read)	? st->i2c_tuner_gate_r
+					: st->i2c_tuner_gate_w
+			: st->i2c_gate;
+		obuf[0] = gate | (read << 7);
+
+		if (gate == 5)
+			obuf[1] = (read) ? 2 : msg[i].len + 1;
+		else
+			obuf[1] = msg[i].len + read + 1;
+
+		obuf[2] = msg[i].addr;
+		if (read) {
+			if (read_o)
+				len = 3;
+			else {
+				memcpy(&obuf[3], msg[i].buf, msg[i].len);
+				obuf[msg[i].len+3] = msg[i+1].len;
+				len = msg[i].len+4;
+			}
+		} else {
+			memcpy(&obuf[3], msg[i].buf, msg[i].len);
+			len = msg[i].len+3;
+		}
+
+		if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) {
+			deb_info(1, "i2c transfer failed.");
+			mutex_unlock(&d->i2c_mutex);
+			return -EAGAIN;
+		}
+
+		if (read) {
+			if (read_o)
+				memcpy(msg[i].buf, &ibuf[1], msg[i].len);
+			else {
+				memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
+				i++;
+			}
+		}
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return i;
+}
+
+static u32 lme2510_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm lme2510_i2c_algo = {
+	.master_xfer   = lme2510_i2c_xfer,
+	.functionality = lme2510_i2c_func,
+};
+
+static int lme2510_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+	struct dvb_usb_adapter *adap = fe_to_adap(fe);
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct lme2510_state *st = adap_to_priv(adap);
+	static u8 clear_reg_3[] = LME_ALL_PIDS;
+	static u8 rbuf[1];
+	int ret = 0, rlen = sizeof(rbuf);
+
+	deb_info(1, "STM  (%02x)", onoff);
+
+	/* Streaming is started by FE_HAS_LOCK */
+	if (onoff == 1)
+		st->stream_on = 1;
+	else {
+		deb_info(1, "STM Steam Off");
+		/* mutex is here only to avoid collision with I2C */
+		mutex_lock(&d->i2c_mutex);
+
+		ret = lme2510_usb_talk(d, clear_reg_3,
+				sizeof(clear_reg_3), rbuf, rlen);
+		st->stream_on = 0;
+		st->i2c_talk_onoff = 1;
+
+		mutex_unlock(&d->i2c_mutex);
+	}
+
+	return (ret < 0) ? -ENODEV : 0;
+}
+
+static u8 check_sum(u8 *p, u8 len)
+{
+	u8 sum = 0;
+	while (len--)
+		sum += *p++;
+	return sum;
+}
+
+static int lme2510_download_firmware(struct dvb_usb_device *d,
+					const struct firmware *fw)
+{
+	int ret = 0;
+	u8 *data;
+	u16 j, wlen, len_in, start, end;
+	u8 packet_size, dlen, i;
+	u8 *fw_data;
+
+	packet_size = 0x31;
+	len_in = 1;
+
+	data = kzalloc(128, GFP_KERNEL);
+	if (!data) {
+		info("FRM Could not start Firmware Download"\
+			"(Buffer allocation failed)");
+		return -ENOMEM;
+	}
+
+	info("FRM Starting Firmware Download");
+
+	for (i = 1; i < 3; i++) {
+		start = (i == 1) ? 0 : 512;
+		end = (i == 1) ? 512 : fw->size;
+		for (j = start; j < end; j += (packet_size+1)) {
+			fw_data = (u8 *)(fw->data + j);
+			if ((end - j) > packet_size) {
+				data[0] = i;
+				dlen = packet_size;
+			} else {
+				data[0] = i | 0x80;
+				dlen = (u8)(end - j)-1;
+			}
+			data[1] = dlen;
+			memcpy(&data[2], fw_data, dlen+1);
+			wlen = (u8) dlen + 4;
+			data[wlen-1] = check_sum(fw_data, dlen+1);
+			deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3],
+				data[dlen+2], data[dlen+3]);
+			lme2510_usb_talk(d, data, wlen, data, len_in);
+			ret |= (data[0] == 0x88) ? 0 : -1;
+		}
+	}
+
+	data[0] = 0x8a;
+	len_in = 1;
+	msleep(2000);
+	lme2510_usb_talk(d, data, len_in, data, len_in);
+	msleep(400);
+
+	if (ret < 0)
+		info("FRM Firmware Download Failed (%04x)" , ret);
+	else
+		info("FRM Firmware Download Completed - Resetting Device");
+
+	kfree(data);
+	return RECONNECTS_USB;
+}
+
+static void lme_coldreset(struct dvb_usb_device *d)
+{
+	u8 data[1] = {0};
+	data[0] = 0x0a;
+	info("FRM Firmware Cold Reset");
+
+	lme2510_usb_talk(d, data, sizeof(data), data, sizeof(data));
+
+	return;
+}
+
+static const char fw_c_s7395[] = LME2510_C_S7395;
+static const char fw_c_lg[] = LME2510_C_LG;
+static const char fw_c_s0194[] = LME2510_C_S0194;
+static const char fw_c_rs2000[] = LME2510_C_RS2000;
+static const char fw_lg[] = LME2510_LG;
+static const char fw_s0194[] = LME2510_S0194;
+
+const char *lme_firmware_switch(struct dvb_usb_device *d, int cold)
+{
+	struct lme2510_state *st = d->priv;
+	struct usb_device *udev = d->udev;
+	const struct firmware *fw = NULL;
+	const char *fw_lme;
+	int ret = 0;
+
+	cold = (cold > 0) ? (cold & 1) : 0;
+
+	switch (le16_to_cpu(udev->descriptor.idProduct)) {
+	case 0x1122:
+		switch (st->dvb_usb_lme2510_firmware) {
+		default:
+			st->dvb_usb_lme2510_firmware = TUNER_S0194;
+		case TUNER_S0194:
+			fw_lme = fw_s0194;
+			ret = request_firmware(&fw, fw_lme, &udev->dev);
+			if (ret == 0) {
+				cold = 0;
+				break;
+			}
+			st->dvb_usb_lme2510_firmware = TUNER_LG;
+		case TUNER_LG:
+			fw_lme = fw_lg;
+			ret = request_firmware(&fw, fw_lme, &udev->dev);
+			if (ret == 0)
+				break;
+			st->dvb_usb_lme2510_firmware = TUNER_DEFAULT;
+			break;
+		}
+		break;
+	case 0x1120:
+		switch (st->dvb_usb_lme2510_firmware) {
+		default:
+			st->dvb_usb_lme2510_firmware = TUNER_S7395;
+		case TUNER_S7395:
+			fw_lme = fw_c_s7395;
+			ret = request_firmware(&fw, fw_lme, &udev->dev);
+			if (ret == 0) {
+				cold = 0;
+				break;
+			}
+			st->dvb_usb_lme2510_firmware = TUNER_LG;
+		case TUNER_LG:
+			fw_lme = fw_c_lg;
+			ret = request_firmware(&fw, fw_lme, &udev->dev);
+			if (ret == 0)
+				break;
+			st->dvb_usb_lme2510_firmware = TUNER_S0194;
+		case TUNER_S0194:
+			fw_lme = fw_c_s0194;
+			ret = request_firmware(&fw, fw_lme, &udev->dev);
+			if (ret == 0)
+				break;
+			st->dvb_usb_lme2510_firmware = TUNER_DEFAULT;
+			cold = 0;
+			break;
+		}
+		break;
+	case 0x22f0:
+		fw_lme = fw_c_rs2000;
+		st->dvb_usb_lme2510_firmware = TUNER_RS2000;
+		break;
+	default:
+		fw_lme = fw_c_s7395;
+	}
+
+	release_firmware(fw);
+
+	if (cold) {
+		dvb_usb_lme2510_firmware = st->dvb_usb_lme2510_firmware;
+		info("FRM Changing to %s firmware", fw_lme);
+		lme_coldreset(d);
+		return NULL;
+	}
+
+	return fw_lme;
+}
+
+static int lme2510_kill_urb(struct usb_data_stream *stream)
+{
+	int i;
+
+	for (i = 0; i < stream->urbs_submitted; i++) {
+		deb_info(3, "killing URB no. %d.", i);
+		/* stop the URB */
+		usb_kill_urb(stream->urb_list[i]);
+	}
+	stream->urbs_submitted = 0;
+
+	return 0;
+}
+
+static struct tda10086_config tda10086_config = {
+	.demod_address = 0x1c,
+	.invert = 0,
+	.diseqc_tone = 1,
+	.xtal_freq = TDA10086_XTAL_16M,
+};
+
+static struct stv0288_config lme_config = {
+	.demod_address = 0xd0,
+	.min_delay_ms = 15,
+	.inittab = s7395_inittab,
+};
+
+static struct ix2505v_config lme_tuner = {
+	.tuner_address = 0xc0,
+	.min_delay_ms = 100,
+	.tuner_gain = 0x0,
+	.tuner_chargepump = 0x3,
+};
+
+static struct stv0299_config sharp_z0194_config = {
+	.demod_address = 0xd0,
+	.inittab = sharp_z0194a_inittab,
+	.mclk = 88000000UL,
+	.invert = 0,
+	.skip_reinit = 0,
+	.lock_output = STV0299_LOCKOUTPUT_1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = sharp_z0194a_set_symbol_rate,
+};
+
+static int dm04_rs2000_set_ts_param(struct dvb_frontend *fe,
+	int caller)
+{
+	struct dvb_usb_adapter *adap = fe_to_adap(fe);
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct lme2510_state *st = d->priv;
+
+	mutex_lock(&d->i2c_mutex);
+	if ((st->i2c_talk_onoff == 1) && (st->stream_on & 1)) {
+		st->i2c_talk_onoff = 0;
+		lme2510_stream_restart(d);
+	}
+	mutex_unlock(&d->i2c_mutex);
+
+	return 0;
+}
+
+static struct m88rs2000_config m88rs2000_config = {
+	.demod_addr = 0xd0,
+	.tuner_addr = 0xc0,
+	.set_ts_params = dm04_rs2000_set_ts_param,
+};
+
+static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
+					fe_sec_voltage_t voltage)
+{
+	struct dvb_usb_device *d = fe_to_d(fe);
+	struct lme2510_state *st = fe_to_priv(fe);
+	static u8 voltage_low[] = LME_VOLTAGE_L;
+	static u8 voltage_high[] = LME_VOLTAGE_H;
+	static u8 rbuf[1];
+	int ret = 0, len = 3, rlen = 1;
+
+	mutex_lock(&d->i2c_mutex);
+
+	switch (voltage) {
+	case SEC_VOLTAGE_18:
+		ret |= lme2510_usb_talk(d,
+			voltage_high, len, rbuf, rlen);
+		break;
+
+	case SEC_VOLTAGE_OFF:
+	case SEC_VOLTAGE_13:
+	default:
+		ret |= lme2510_usb_talk(d,
+				voltage_low, len, rbuf, rlen);
+		break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+
+	if (st->tuner_config == TUNER_RS2000)
+		if (st->fe_set_voltage)
+			st->fe_set_voltage(fe, voltage);
+
+
+	return (ret < 0) ? -ENODEV : 0;
+}
+
+static int dm04_rs2000_read_signal_strength(struct dvb_frontend *fe,
+	u16 *strength)
+{
+	struct lme2510_state *st = fe_to_priv(fe);
+
+	*strength = (u16)((u32)st->signal_level * 0xffff / 0xff);
+
+	return 0;
+}
+
+static int dm04_rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct lme2510_state *st = fe_to_priv(fe);
+
+	*snr = (u16)((u32)st->signal_sn * 0xffff / 0x7f);
+
+	return 0;
+}
+
+static int dm04_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	*ber = 0;
+
+	return 0;
+}
+
+static int dm04_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	*ucblocks = 0;
+
+	return 0;
+}
+
+static int lme_name(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct lme2510_state *st = adap_to_priv(adap);
+	const char *desc = d->name;
+	char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395",
+				" SHARP:BS2F7HZ0194", " RS2000"};
+	char *name = adap->fe[0]->ops.info.name;
+
+	strlcpy(name, desc, 128);
+	strlcat(name, fe_name[st->tuner_config], 128);
+
+	return 0;
+}
+
+static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct lme2510_state *st = d->priv;
+	int ret = 0;
+
+	st->i2c_talk_onoff = 1;
+	switch (le16_to_cpu(d->udev->descriptor.idProduct)) {
+	case 0x1122:
+	case 0x1120:
+		st->i2c_gate = 4;
+		adap->fe[0] = dvb_attach(tda10086_attach,
+			&tda10086_config, &d->i2c_adap);
+		if (adap->fe[0]) {
+			info("TUN Found Frontend TDA10086");
+			st->i2c_tuner_gate_w = 4;
+			st->i2c_tuner_gate_r = 4;
+			st->i2c_tuner_addr = 0xc0;
+			st->tuner_config = TUNER_LG;
+			if (st->dvb_usb_lme2510_firmware != TUNER_LG) {
+				st->dvb_usb_lme2510_firmware = TUNER_LG;
+				ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV;
+			}
+			break;
+		}
+
+		st->i2c_gate = 4;
+		adap->fe[0] = dvb_attach(stv0299_attach,
+				&sharp_z0194_config, &d->i2c_adap);
+		if (adap->fe[0]) {
+			info("FE Found Stv0299");
+			st->i2c_tuner_gate_w = 4;
+			st->i2c_tuner_gate_r = 5;
+			st->i2c_tuner_addr = 0xc0;
+			st->tuner_config = TUNER_S0194;
+			if (st->dvb_usb_lme2510_firmware != TUNER_S0194) {
+				st->dvb_usb_lme2510_firmware = TUNER_S0194;
+				ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV;
+			}
+			break;
+		}
+
+		st->i2c_gate = 5;
+		adap->fe[0] = dvb_attach(stv0288_attach, &lme_config,
+			&d->i2c_adap);
+
+		if (adap->fe[0]) {
+			info("FE Found Stv0288");
+			st->i2c_tuner_gate_w = 4;
+			st->i2c_tuner_gate_r = 5;
+			st->i2c_tuner_addr = 0xc0;
+			st->tuner_config = TUNER_S7395;
+			if (st->dvb_usb_lme2510_firmware != TUNER_S7395) {
+				st->dvb_usb_lme2510_firmware = TUNER_S7395;
+				ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV;
+			}
+			break;
+		}
+	case 0x22f0:
+		st->i2c_gate = 5;
+		adap->fe[0] = dvb_attach(m88rs2000_attach,
+			&m88rs2000_config, &d->i2c_adap);
+
+		if (adap->fe[0]) {
+			info("FE Found M88RS2000");
+			st->i2c_tuner_gate_w = 5;
+			st->i2c_tuner_gate_r = 5;
+			st->i2c_tuner_addr = 0xc0;
+			st->tuner_config = TUNER_RS2000;
+			st->fe_set_voltage =
+				adap->fe[0]->ops.set_voltage;
+
+			adap->fe[0]->ops.read_signal_strength =
+				dm04_rs2000_read_signal_strength;
+			adap->fe[0]->ops.read_snr =
+				dm04_rs2000_read_snr;
+			adap->fe[0]->ops.read_ber =
+				dm04_read_ber;
+			adap->fe[0]->ops.read_ucblocks =
+				dm04_read_ucblocks;
+		}
+		break;
+	}
+
+	if (adap->fe[0] == NULL) {
+		info("DM04/QQBOX Not Powered up or not Supported");
+		return -ENODEV;
+	}
+
+	if (ret) {
+		if (adap->fe[0]) {
+			dvb_frontend_detach(adap->fe[0]);
+			adap->fe[0] = NULL;
+		}
+		d->rc_map = NULL;
+		return -ENODEV;
+	}
+
+	adap->fe[0]->ops.set_voltage = dm04_lme2510_set_voltage;
+	ret = lme_name(adap);
+	return ret;
+}
+
+static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct lme2510_state *st = adap_to_priv(adap);
+	char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA", "RS2000"};
+	int ret = 0;
+
+	switch (st->tuner_config) {
+	case TUNER_LG:
+		if (dvb_attach(tda826x_attach, adap->fe[0], 0xc0,
+			&d->i2c_adap, 1))
+			ret = st->tuner_config;
+		break;
+	case TUNER_S7395:
+		if (dvb_attach(ix2505v_attach , adap->fe[0], &lme_tuner,
+			&d->i2c_adap))
+			ret = st->tuner_config;
+		break;
+	case TUNER_S0194:
+		if (dvb_attach(dvb_pll_attach , adap->fe[0], 0xc0,
+			&d->i2c_adap, DVB_PLL_OPERA1))
+			ret = st->tuner_config;
+		break;
+	case TUNER_RS2000:
+		ret = st->tuner_config;
+		break;
+	default:
+		break;
+	}
+
+	if (ret)
+		info("TUN Found %s tuner", tun_msg[ret]);
+	else {
+		info("TUN No tuner found --- resetting device");
+		lme_coldreset(d);
+		return -ENODEV;
+	}
+
+	/* Start the Interrupt*/
+	ret = lme2510_int_read(adap);
+	if (ret < 0) {
+		info("INT Unable to start Interrupt Service");
+		return -ENODEV;
+	}
+
+	return ret;
+}
+
+static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
+{
+	struct lme2510_state *st = d->priv;
+	static u8 lnb_on[] = LNB_ON;
+	static u8 lnb_off[] = LNB_OFF;
+	static u8 rbuf[1];
+	int ret = 0, len = 3, rlen = 1;
+
+	mutex_lock(&d->i2c_mutex);
+
+	if (onoff)
+		ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen);
+	else
+		ret = lme2510_usb_talk(d, lnb_off, len, rbuf, rlen);
+
+	st->i2c_talk_onoff = 1;
+
+	mutex_unlock(&d->i2c_mutex);
+
+	return ret;
+}
+
+static int lme2510_get_adapter_count(struct dvb_usb_device *d)
+{
+	return 1;
+}
+
+static int lme2510_identify_state(struct dvb_usb_device *d, const char **name)
+{
+	struct lme2510_state *st = d->priv;
+
+	usb_reset_configuration(d->udev);
+
+	usb_set_interface(d->udev,
+		d->intf->cur_altsetting->desc.bInterfaceNumber, 1);
+
+	st->dvb_usb_lme2510_firmware = dvb_usb_lme2510_firmware;
+
+	if (lme2510_return_status(d) == 0x44) {
+		*name = lme_firmware_switch(d, 0);
+		return COLD;
+	}
+
+	return 0;
+}
+
+static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
+		struct usb_data_stream_properties *stream)
+{
+	struct dvb_usb_adapter *adap = fe_to_adap(fe);
+	struct dvb_usb_device *d = adap_to_d(adap);
+
+	if (adap == NULL)
+		return 0;
+	/* Turn PID filter on the fly by module option */
+	if (pid_filter == 2) {
+		adap->pid_filtering  = 1;
+		adap->max_feed_count = 15;
+	}
+
+	if (!(le16_to_cpu(d->udev->descriptor.idProduct)
+		== 0x1122))
+		stream->endpoint = 0x8;
+
+	return 0;
+}
+
+static int lme2510_get_rc_config(struct dvb_usb_device *d,
+	struct dvb_usb_rc *rc)
+{
+	rc->allowed_protos = RC_TYPE_NEC;
+	return 0;
+}
+
+static void *lme2510_exit_int(struct dvb_usb_device *d)
+{
+	struct lme2510_state *st = d->priv;
+	struct dvb_usb_adapter *adap = &d->adapter[0];
+	void *buffer = NULL;
+
+	if (adap != NULL) {
+		lme2510_kill_urb(&adap->stream);
+	}
+
+	if (st->usb_buffer != NULL) {
+		st->i2c_talk_onoff = 1;
+		st->signal_lock = 0;
+		st->signal_level = 0;
+		st->signal_sn = 0;
+		buffer = st->usb_buffer;
+	}
+
+	if (st->lme_urb != NULL) {
+		usb_kill_urb(st->lme_urb);
+		usb_free_coherent(d->udev, 128, st->buffer,
+				  st->lme_urb->transfer_dma);
+		info("Interrupt Service Stopped");
+	}
+
+	return buffer;
+}
+
+static void lme2510_exit(struct dvb_usb_device *d)
+{
+	void *usb_buffer;
+
+	if (d != NULL) {
+		usb_buffer = lme2510_exit_int(d);
+		if (usb_buffer != NULL)
+			kfree(usb_buffer);
+	}
+}
+
+static struct dvb_usb_device_properties lme2510_props = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.bInterfaceNumber = 0,
+	.adapter_nr = adapter_nr,
+	.size_of_priv = sizeof(struct lme2510_state),
+
+	.download_firmware = lme2510_download_firmware,
+
+	.power_ctrl       = lme2510_powerup,
+	.identify_state   = lme2510_identify_state,
+	.i2c_algo         = &lme2510_i2c_algo,
+
+	.frontend_attach  = dm04_lme2510_frontend_attach,
+	.tuner_attach = dm04_lme2510_tuner,
+	.get_stream_config = lme2510_get_stream_config,
+	.get_adapter_count = lme2510_get_adapter_count,
+	.streaming_ctrl   = lme2510_streaming_ctrl,
+
+	.get_rc_config = lme2510_get_rc_config,
+
+	.exit = lme2510_exit,
+	.adapter = {
+		{
+			.caps = DVB_USB_ADAP_HAS_PID_FILTER|
+				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+			.pid_filter_count = 15,
+			.pid_filter = lme2510_pid_filter,
+			.pid_filter_ctrl  = lme2510_pid_filter_ctrl,
+			.stream =
+			DVB_USB_STREAM_BULK(0x86, 10, 4096),
+		},
+		{
+		}
+	},
+};
+
+static const struct usb_device_id lme2510_id_table[] = {
+	{	DVB_USB_DEVICE(0x3344, 0x1122, &lme2510_props,
+		"DM04_LME2510_DVB-S", RC_MAP_LME2510)	},
+	{	DVB_USB_DEVICE(0x3344, 0x1120, &lme2510_props,
+		"DM04_LME2510C_DVB-S", RC_MAP_LME2510)	},
+	{	DVB_USB_DEVICE(0x3344, 0x22f0, &lme2510_props,
+		"DM04_LME2510C_DVB-S RS2000", RC_MAP_LME2510)	},
+	{}		/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, lme2510_id_table);
+
+static struct usb_driver lme2510_driver = {
+	.name		= KBUILD_MODNAME,
+	.probe		= dvb_usbv2_probe,
+	.disconnect	= dvb_usbv2_disconnect,
+	.id_table	= lme2510_id_table,
+	.no_dynamic_id = 1,
+	.soft_unbind = 1,
+};
+
+module_usb_driver(lme2510_driver);
+
+MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
+MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
+MODULE_VERSION("2.06");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(LME2510_C_S7395);
+MODULE_FIRMWARE(LME2510_C_LG);
+MODULE_FIRMWARE(LME2510_C_S0194);
+MODULE_FIRMWARE(LME2510_C_RS2000);
+MODULE_FIRMWARE(LME2510_LG);
+MODULE_FIRMWARE(LME2510_S0194);
+
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.h b/drivers/media/usb/dvb-usb-v2/lmedm04.h
new file mode 100644
index 0000000..e9c2072
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.h
@@ -0,0 +1,175 @@
+/* DVB USB compliant linux driver for
+ *
+ * DM04/QQBOX DVB-S USB BOX	LME2510C + SHARP:BS2F7HZ7395
+ *				LME2510C + LG TDQY-P001F
+ *				LME2510 + LG TDQY-P001F
+ *
+ * MVB7395 (LME2510C+SHARP:BS2F7HZ7395)
+ * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V)
+ *
+ * MVB001F (LME2510+LGTDQT-P001F)
+ * LG TDQY - P001F =(TDA8263 + TDA10086H)
+ *
+ * MVB0001F (LME2510C+LGTDQT-P001F)
+ *
+ * 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,  version 2.
+ * *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_LME2510_H_
+#define _DVB_USB_LME2510_H_
+
+/* Streamer &  PID
+ *
+ * Note:	These commands do not actually stop the streaming
+ *		but form some kind of packet filtering/stream count
+ *		or tuning related functions.
+ *  06 XX
+ *  offset 1 = 00 Enable Streaming
+ *
+ *
+ *  PID
+ *  03 XX XX  ----> reg number ---> setting....20 XX
+ *  offset 1 = length
+ *  offset 2 = start of data
+ *  end byte -1 = 20
+ *  end byte = clear pid always a0, other wise 9c, 9a ??
+ *
+*/
+#define LME_ST_ON_W	{0x06, 0x00}
+#define LME_CLEAR_PID   {0x03, 0x02, 0x20, 0xa0}
+#define LME_ZERO_PID	{0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c}
+#define LME_ALL_PIDS	{0x03, 0x06, 0x00, 0xff, 0x01, 0x1f, 0x20, 0x81}
+
+/*  LNB Voltage
+ *  07 XX XX
+ *  offset 1 = 01
+ *  offset 2 = 00=Voltage low 01=Voltage high
+ *
+ *  LNB Power
+ *  03 01 XX
+ *  offset 2 = 00=ON 01=OFF
+ */
+
+#define LME_VOLTAGE_L	{0x07, 0x01, 0x00}
+#define LME_VOLTAGE_H	{0x07, 0x01, 0x01}
+#define LNB_ON		{0x3a, 0x01, 0x00}
+#define LNB_OFF		{0x3a, 0x01, 0x01}
+
+/* Initial stv0288 settings for 7395 Frontend */
+static u8 s7395_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x20,
+	0x03, 0xa0,
+	0x04, 0xa0,
+	0x05, 0x12,
+	0x06, 0x00,
+	0x09, 0x00,
+	0x0a, 0x04,
+	0x0b, 0x00,
+	0x0c, 0x00,
+	0x0d, 0x00,
+	0x0e, 0xc1,
+	0x0f, 0x54,
+	0x11, 0x7a,
+	0x12, 0x03,
+	0x13, 0x48,
+	0x14, 0x84,
+	0x15, 0xc5,
+	0x16, 0xb8,
+	0x17, 0x9c,
+	0x18, 0x00,
+	0x19, 0xa6,
+	0x1a, 0x88,
+	0x1b, 0x8f,
+	0x1c, 0xf0,
+	0x20, 0x0b,
+	0x21, 0x54,
+	0x22, 0xff,
+	0x23, 0x01,
+	0x28, 0x46,
+	0x29, 0x66,
+	0x2a, 0x90,
+	0x2b, 0xfa,
+	0x2c, 0xd9,
+	0x30, 0x0,
+	0x31, 0x1e,
+	0x32, 0x14,
+	0x33, 0x0f,
+	0x34, 0x09,
+	0x35, 0x0c,
+	0x36, 0x05,
+	0x37, 0x2f,
+	0x38, 0x16,
+	0x39, 0xbd,
+	0x3a, 0x0,
+	0x3b, 0x13,
+	0x3c, 0x11,
+	0x3d, 0x30,
+	0x40, 0x63,
+	0x41, 0x04,
+	0x42, 0x20,
+	0x43, 0x00,
+	0x44, 0x00,
+	0x45, 0x00,
+	0x46, 0x00,
+	0x47, 0x00,
+	0x4a, 0x00,
+	0x50, 0x10,
+	0x51, 0x36,
+	0x52, 0x21,
+	0x53, 0x94,
+	0x54, 0xb2,
+	0x55, 0x29,
+	0x56, 0x64,
+	0x57, 0x2b,
+	0x58, 0x54,
+	0x59, 0x86,
+	0x5a, 0x00,
+	0x5b, 0x9b,
+	0x5c, 0x08,
+	0x5d, 0x7f,
+	0x5e, 0xff,
+	0x5f, 0x8d,
+	0x70, 0x0,
+	0x71, 0x0,
+	0x72, 0x0,
+	0x74, 0x0,
+	0x75, 0x0,
+	0x76, 0x0,
+	0x81, 0x0,
+	0x82, 0x3f,
+	0x83, 0x3f,
+	0x84, 0x0,
+	0x85, 0x0,
+	0x88, 0x0,
+	0x89, 0x0,
+	0x8a, 0x0,
+	0x8b, 0x0,
+	0x8c, 0x0,
+	0x90, 0x0,
+	0x91, 0x0,
+	0x92, 0x0,
+	0x93, 0x0,
+	0x94, 0x1c,
+	0x97, 0x0,
+	0xa0, 0x48,
+	0xa1, 0x0,
+	0xb0, 0xb8,
+	0xb1, 0x3a,
+	0xb2, 0x10,
+	0xb3, 0x82,
+	0xb4, 0x80,
+	0xb5, 0x82,
+	0xb6, 0x82,
+	0xb7, 0x82,
+	0xb8, 0x20,
+	0xb9, 0x0,
+	0xf0, 0x0,
+	0xf1, 0x0,
+	0xf2, 0xc0,
+	0xff, 0xff,
+};
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
new file mode 100644
index 0000000..d83df4b
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
@@ -0,0 +1,612 @@
+/*
+ *  mxl111sf-demod.c - driver for the MaxLinear MXL111SF DVB-T demodulator
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "mxl111sf-demod.h"
+#include "mxl111sf-reg.h"
+
+/* debug */
+static int mxl111sf_demod_debug;
+module_param_named(debug, mxl111sf_demod_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
+
+#define mxl_dbg(fmt, arg...) \
+	if (mxl111sf_demod_debug) \
+		mxl_printk(KERN_DEBUG, fmt, ##arg)
+
+/* ------------------------------------------------------------------------ */
+
+struct mxl111sf_demod_state {
+	struct mxl111sf_state *mxl_state;
+
+	struct mxl111sf_demod_config *cfg;
+
+	struct dvb_frontend fe;
+};
+
+/* ------------------------------------------------------------------------ */
+
+static int mxl111sf_demod_read_reg(struct mxl111sf_demod_state *state,
+				   u8 addr, u8 *data)
+{
+	return (state->cfg->read_reg) ?
+		state->cfg->read_reg(state->mxl_state, addr, data) :
+		-EINVAL;
+}
+
+static int mxl111sf_demod_write_reg(struct mxl111sf_demod_state *state,
+				    u8 addr, u8 data)
+{
+	return (state->cfg->write_reg) ?
+		state->cfg->write_reg(state->mxl_state, addr, data) :
+		-EINVAL;
+}
+
+static
+int mxl111sf_demod_program_regs(struct mxl111sf_demod_state *state,
+				struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
+{
+	return (state->cfg->program_regs) ?
+		state->cfg->program_regs(state->mxl_state, ctrl_reg_info) :
+		-EINVAL;
+}
+
+/* ------------------------------------------------------------------------ */
+/* TPS */
+
+static
+int mxl1x1sf_demod_get_tps_code_rate(struct mxl111sf_demod_state *state,
+				     fe_code_rate_t *code_rate)
+{
+	u8 val;
+	int ret = mxl111sf_demod_read_reg(state, V6_CODE_RATE_TPS_REG, &val);
+	/* bit<2:0> - 000:1/2, 001:2/3, 010:3/4, 011:5/6, 100:7/8 */
+	if (mxl_fail(ret))
+		goto fail;
+
+	switch (val & V6_CODE_RATE_TPS_MASK) {
+	case 0:
+		*code_rate = FEC_1_2;
+		break;
+	case 1:
+		*code_rate = FEC_2_3;
+		break;
+	case 2:
+		*code_rate = FEC_3_4;
+		break;
+	case 3:
+		*code_rate = FEC_5_6;
+		break;
+	case 4:
+		*code_rate = FEC_7_8;
+		break;
+	}
+fail:
+	return ret;
+}
+
+static
+int mxl1x1sf_demod_get_tps_modulation(struct mxl111sf_demod_state *state,
+					 fe_modulation_t *modulation)
+{
+	u8 val;
+	int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val);
+	/* Constellation, 00 : QPSK, 01 : 16QAM, 10:64QAM */
+	if (mxl_fail(ret))
+		goto fail;
+
+	switch ((val & V6_PARAM_CONSTELLATION_MASK) >> 4) {
+	case 0:
+		*modulation = QPSK;
+		break;
+	case 1:
+		*modulation = QAM_16;
+		break;
+	case 2:
+		*modulation = QAM_64;
+		break;
+	}
+fail:
+	return ret;
+}
+
+static
+int mxl1x1sf_demod_get_tps_guard_fft_mode(struct mxl111sf_demod_state *state,
+					  fe_transmit_mode_t *fft_mode)
+{
+	u8 val;
+	int ret = mxl111sf_demod_read_reg(state, V6_MODE_TPS_REG, &val);
+	/* FFT Mode, 00:2K, 01:8K, 10:4K */
+	if (mxl_fail(ret))
+		goto fail;
+
+	switch ((val & V6_PARAM_FFT_MODE_MASK) >> 2) {
+	case 0:
+		*fft_mode = TRANSMISSION_MODE_2K;
+		break;
+	case 1:
+		*fft_mode = TRANSMISSION_MODE_8K;
+		break;
+	case 2:
+		*fft_mode = TRANSMISSION_MODE_4K;
+		break;
+	}
+fail:
+	return ret;
+}
+
+static
+int mxl1x1sf_demod_get_tps_guard_interval(struct mxl111sf_demod_state *state,
+					  fe_guard_interval_t *guard)
+{
+	u8 val;
+	int ret = mxl111sf_demod_read_reg(state, V6_CP_TPS_REG, &val);
+	/* 00:1/32, 01:1/16, 10:1/8, 11:1/4 */
+	if (mxl_fail(ret))
+		goto fail;
+
+	switch ((val & V6_PARAM_GI_MASK) >> 4) {
+	case 0:
+		*guard = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		*guard = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		*guard = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		*guard = GUARD_INTERVAL_1_4;
+		break;
+	}
+fail:
+	return ret;
+}
+
+static
+int mxl1x1sf_demod_get_tps_hierarchy(struct mxl111sf_demod_state *state,
+				     fe_hierarchy_t *hierarchy)
+{
+	u8 val;
+	int ret = mxl111sf_demod_read_reg(state, V6_TPS_HIERACHY_REG, &val);
+	/* bit<6:4> - 000:Non hierarchy, 001:1, 010:2, 011:4 */
+	if (mxl_fail(ret))
+		goto fail;
+
+	switch ((val & V6_TPS_HIERARCHY_INFO_MASK) >> 6) {
+	case 0:
+		*hierarchy = HIERARCHY_NONE;
+		break;
+	case 1:
+		*hierarchy = HIERARCHY_1;
+		break;
+	case 2:
+		*hierarchy = HIERARCHY_2;
+		break;
+	case 3:
+		*hierarchy = HIERARCHY_4;
+		break;
+	}
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+/* LOCKS */
+
+static
+int mxl1x1sf_demod_get_sync_lock_status(struct mxl111sf_demod_state *state,
+					int *sync_lock)
+{
+	u8 val = 0;
+	int ret = mxl111sf_demod_read_reg(state, V6_SYNC_LOCK_REG, &val);
+	if (mxl_fail(ret))
+		goto fail;
+	*sync_lock = (val & SYNC_LOCK_MASK) >> 4;
+fail:
+	return ret;
+}
+
+static
+int mxl1x1sf_demod_get_rs_lock_status(struct mxl111sf_demod_state *state,
+				      int *rs_lock)
+{
+	u8 val = 0;
+	int ret = mxl111sf_demod_read_reg(state, V6_RS_LOCK_DET_REG, &val);
+	if (mxl_fail(ret))
+		goto fail;
+	*rs_lock = (val & RS_LOCK_DET_MASK) >> 3;
+fail:
+	return ret;
+}
+
+static
+int mxl1x1sf_demod_get_tps_lock_status(struct mxl111sf_demod_state *state,
+				       int *tps_lock)
+{
+	u8 val = 0;
+	int ret = mxl111sf_demod_read_reg(state, V6_TPS_LOCK_REG, &val);
+	if (mxl_fail(ret))
+		goto fail;
+	*tps_lock = (val & V6_PARAM_TPS_LOCK_MASK) >> 6;
+fail:
+	return ret;
+}
+
+static
+int mxl1x1sf_demod_get_fec_lock_status(struct mxl111sf_demod_state *state,
+				       int *fec_lock)
+{
+	u8 val = 0;
+	int ret = mxl111sf_demod_read_reg(state, V6_IRQ_STATUS_REG, &val);
+	if (mxl_fail(ret))
+		goto fail;
+	*fec_lock = (val & IRQ_MASK_FEC_LOCK) >> 4;
+fail:
+	return ret;
+}
+
+#if 0
+static
+int mxl1x1sf_demod_get_cp_lock_status(struct mxl111sf_demod_state *state,
+				      int *cp_lock)
+{
+	u8 val = 0;
+	int ret = mxl111sf_demod_read_reg(state, V6_CP_LOCK_DET_REG, &val);
+	if (mxl_fail(ret))
+		goto fail;
+	*cp_lock = (val & V6_CP_LOCK_DET_MASK) >> 2;
+fail:
+	return ret;
+}
+#endif
+
+static int mxl1x1sf_demod_reset_irq_status(struct mxl111sf_demod_state *state)
+{
+	return mxl111sf_demod_write_reg(state, 0x0e, 0xff);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe)
+{
+	struct mxl111sf_demod_state *state = fe->demodulator_priv;
+	int ret = 0;
+
+	struct mxl111sf_reg_ctrl_info phy_pll_patch[] = {
+		{0x00, 0xff, 0x01}, /* change page to 1 */
+		{0x40, 0xff, 0x05},
+		{0x40, 0xff, 0x01},
+		{0x41, 0xff, 0xca},
+		{0x41, 0xff, 0xc0},
+		{0x00, 0xff, 0x00}, /* change page to 0 */
+		{0,    0,    0}
+	};
+
+	mxl_dbg("()");
+
+	if (fe->ops.tuner_ops.set_params) {
+		ret = fe->ops.tuner_ops.set_params(fe);
+		if (mxl_fail(ret))
+			goto fail;
+		msleep(50);
+	}
+	ret = mxl111sf_demod_program_regs(state, phy_pll_patch);
+	mxl_fail(ret);
+	msleep(50);
+	ret = mxl1x1sf_demod_reset_irq_status(state);
+	mxl_fail(ret);
+	msleep(100);
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+#if 0
+/* resets TS Packet error count */
+/* After setting 7th bit of V5_PER_COUNT_RESET_REG, it should be reset to 0. */
+static
+int mxl1x1sf_demod_reset_packet_error_count(struct mxl111sf_demod_state *state)
+{
+	struct mxl111sf_reg_ctrl_info reset_per_count[] = {
+		{0x20, 0x01, 0x01},
+		{0x20, 0x01, 0x00},
+		{0,    0,    0}
+	};
+	return mxl111sf_demod_program_regs(state, reset_per_count);
+}
+#endif
+
+/* returns TS Packet error count */
+/* PER Count = FEC_PER_COUNT * (2 ** (FEC_PER_SCALE * 4)) */
+static int mxl111sf_demod_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct mxl111sf_demod_state *state = fe->demodulator_priv;
+	u32 fec_per_count, fec_per_scale;
+	u8 val;
+	int ret;
+
+	*ucblocks = 0;
+
+	/* FEC_PER_COUNT Register */
+	ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_COUNT_REG, &val);
+	if (mxl_fail(ret))
+		goto fail;
+
+	fec_per_count = val;
+
+	/* FEC_PER_SCALE Register */
+	ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_SCALE_REG, &val);
+	if (mxl_fail(ret))
+		goto fail;
+
+	val &= V6_FEC_PER_SCALE_MASK;
+	val *= 4;
+
+	fec_per_scale = 1 << val;
+
+	fec_per_count *= fec_per_scale;
+
+	*ucblocks = fec_per_count;
+fail:
+	return ret;
+}
+
+#ifdef MXL111SF_DEMOD_ENABLE_CALCULATIONS
+/* FIXME: leaving this enabled breaks the build on some architectures,
+ * and we shouldn't have any floating point math in the kernel, anyway.
+ *
+ * These macros need to be re-written, but it's harmless to simply
+ * return zero for now. */
+#define CALCULATE_BER(avg_errors, count) \
+	((u32)(avg_errors * 4)/(count*64*188*8))
+#define CALCULATE_SNR(data) \
+	((u32)((10 * (u32)data / 64) - 2.5))
+#else
+#define CALCULATE_BER(avg_errors, count) 0
+#define CALCULATE_SNR(data) 0
+#endif
+
+static int mxl111sf_demod_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct mxl111sf_demod_state *state = fe->demodulator_priv;
+	u8 val1, val2, val3;
+	int ret;
+
+	*ber = 0;
+
+	ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_LSB_REG, &val1);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_MSB_REG, &val2);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_demod_read_reg(state, V6_N_ACCUMULATE_REG, &val3);
+	if (mxl_fail(ret))
+		goto fail;
+
+	*ber = CALCULATE_BER((val1 | (val2 << 8)), val3);
+fail:
+	return ret;
+}
+
+static int mxl111sf_demod_calc_snr(struct mxl111sf_demod_state *state,
+				   u16 *snr)
+{
+	u8 val1, val2;
+	int ret;
+
+	*snr = 0;
+
+	ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_LSB_REG, &val1);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_MSB_REG, &val2);
+	if (mxl_fail(ret))
+		goto fail;
+
+	*snr = CALCULATE_SNR(val1 | ((val2 & 0x03) << 8));
+fail:
+	return ret;
+}
+
+static int mxl111sf_demod_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct mxl111sf_demod_state *state = fe->demodulator_priv;
+
+	int ret = mxl111sf_demod_calc_snr(state, snr);
+	if (mxl_fail(ret))
+		goto fail;
+
+	*snr /= 10; /* 0.1 dB */
+fail:
+	return ret;
+}
+
+static int mxl111sf_demod_read_status(struct dvb_frontend *fe,
+				      fe_status_t *status)
+{
+	struct mxl111sf_demod_state *state = fe->demodulator_priv;
+	int ret, locked, cr_lock, sync_lock, fec_lock;
+
+	*status = 0;
+
+	ret = mxl1x1sf_demod_get_rs_lock_status(state, &locked);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl1x1sf_demod_get_tps_lock_status(state, &cr_lock);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl1x1sf_demod_get_sync_lock_status(state, &sync_lock);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl1x1sf_demod_get_fec_lock_status(state, &fec_lock);
+	if (mxl_fail(ret))
+		goto fail;
+
+	if (locked)
+		*status |= FE_HAS_SIGNAL;
+	if (cr_lock)
+		*status |= FE_HAS_CARRIER;
+	if (sync_lock)
+		*status |= FE_HAS_SYNC;
+	if (fec_lock) /* false positives? */
+		*status |= FE_HAS_VITERBI;
+
+	if ((locked) && (cr_lock) && (sync_lock))
+		*status |= FE_HAS_LOCK;
+fail:
+	return ret;
+}
+
+static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe,
+					       u16 *signal_strength)
+{
+	struct mxl111sf_demod_state *state = fe->demodulator_priv;
+	fe_modulation_t modulation;
+	u16 snr;
+
+	mxl111sf_demod_calc_snr(state, &snr);
+	mxl1x1sf_demod_get_tps_modulation(state, &modulation);
+
+	switch (modulation) {
+	case QPSK:
+		*signal_strength = (snr >= 1300) ?
+			min(65535, snr * 44) : snr * 38;
+		break;
+	case QAM_16:
+		*signal_strength = (snr >= 1500) ?
+			min(65535, snr * 38) : snr * 33;
+		break;
+	case QAM_64:
+		*signal_strength = (snr >= 2000) ?
+			min(65535, snr * 29) : snr * 25;
+		break;
+	default:
+		*signal_strength = 0;
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct mxl111sf_demod_state *state = fe->demodulator_priv;
+
+	mxl_dbg("()");
+#if 0
+	p->inversion = /* FIXME */ ? INVERSION_ON : INVERSION_OFF;
+#endif
+	if (fe->ops.tuner_ops.get_bandwidth)
+		fe->ops.tuner_ops.get_bandwidth(fe, &p->bandwidth_hz);
+	if (fe->ops.tuner_ops.get_frequency)
+		fe->ops.tuner_ops.get_frequency(fe, &p->frequency);
+	mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_HP);
+	mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_LP);
+	mxl1x1sf_demod_get_tps_modulation(state, &p->modulation);
+	mxl1x1sf_demod_get_tps_guard_fft_mode(state,
+					      &p->transmission_mode);
+	mxl1x1sf_demod_get_tps_guard_interval(state,
+					      &p->guard_interval);
+	mxl1x1sf_demod_get_tps_hierarchy(state,
+					 &p->hierarchy);
+
+	return 0;
+}
+
+static
+int mxl111sf_demod_get_tune_settings(struct dvb_frontend *fe,
+				     struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	return 0;
+}
+
+static void mxl111sf_demod_release(struct dvb_frontend *fe)
+{
+	struct mxl111sf_demod_state *state = fe->demodulator_priv;
+	mxl_dbg("()");
+	kfree(state);
+	fe->demodulator_priv = NULL;
+}
+
+static struct dvb_frontend_ops mxl111sf_demod_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name               = "MaxLinear MxL111SF DVB-T demodulator",
+		.frequency_min      = 177000000,
+		.frequency_max      = 858000000,
+		.frequency_stepsize = 166666,
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
+	},
+	.release              = mxl111sf_demod_release,
+#if 0
+	.init                 = mxl111sf_init,
+	.i2c_gate_ctrl        = mxl111sf_i2c_gate_ctrl,
+#endif
+	.set_frontend         = mxl111sf_demod_set_frontend,
+	.get_frontend         = mxl111sf_demod_get_frontend,
+	.get_tune_settings    = mxl111sf_demod_get_tune_settings,
+	.read_status          = mxl111sf_demod_read_status,
+	.read_signal_strength = mxl111sf_demod_read_signal_strength,
+	.read_ber             = mxl111sf_demod_read_ber,
+	.read_snr             = mxl111sf_demod_read_snr,
+	.read_ucblocks        = mxl111sf_demod_read_ucblocks,
+};
+
+struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
+					   struct mxl111sf_demod_config *cfg)
+{
+	struct mxl111sf_demod_state *state = NULL;
+
+	mxl_dbg("()");
+
+	state = kzalloc(sizeof(struct mxl111sf_demod_state), GFP_KERNEL);
+	if (state == NULL)
+		return NULL;
+
+	state->mxl_state = mxl_state;
+	state->cfg = cfg;
+
+	memcpy(&state->fe.ops, &mxl111sf_demod_ops,
+	       sizeof(struct dvb_frontend_ops));
+
+	state->fe.demodulator_priv = state;
+	return &state->fe;
+}
+EXPORT_SYMBOL_GPL(mxl111sf_demod_attach);
+
+MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver");
+MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
new file mode 100644
index 0000000..432706a
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
@@ -0,0 +1,55 @@
+/*
+ *  mxl111sf-demod.h - driver for the MaxLinear MXL111SF DVB-T demodulator
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MXL111SF_DEMOD_H__
+#define __MXL111SF_DEMOD_H__
+
+#include "dvb_frontend.h"
+#include "mxl111sf.h"
+
+struct mxl111sf_demod_config {
+	int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data);
+	int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data);
+	int (*program_regs)(struct mxl111sf_state *state,
+			    struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
+};
+
+#if defined(CONFIG_DVB_USB_MXL111SF) || \
+	(defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE))
+extern
+struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
+					   struct mxl111sf_demod_config *cfg);
+#else
+static inline
+struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
+					   struct mxl111sf_demod_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_USB_MXL111SF */
+
+#endif /* __MXL111SF_DEMOD_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c
new file mode 100644
index 0000000..e4121cb
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c
@@ -0,0 +1,763 @@
+/*
+ *  mxl111sf-gpio.c - driver for the MaxLinear MXL111SF
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "mxl111sf-gpio.h"
+#include "mxl111sf-i2c.h"
+#include "mxl111sf.h"
+
+/* ------------------------------------------------------------------------- */
+
+#define MXL_GPIO_MUX_REG_0 0x84
+#define MXL_GPIO_MUX_REG_1 0x89
+#define MXL_GPIO_MUX_REG_2 0x82
+
+#define MXL_GPIO_DIR_INPUT  0
+#define MXL_GPIO_DIR_OUTPUT 1
+
+
+static int mxl111sf_set_gpo_state(struct mxl111sf_state *state, u8 pin, u8 val)
+{
+	int ret;
+	u8 tmp;
+
+	mxl_debug_adv("(%d, %d)", pin, val);
+
+	if ((pin > 0) && (pin < 8)) {
+		ret = mxl111sf_read_reg(state, 0x19, &tmp);
+		if (mxl_fail(ret))
+			goto fail;
+		tmp &= ~(1 << (pin - 1));
+		tmp |= (val << (pin - 1));
+		ret = mxl111sf_write_reg(state, 0x19, tmp);
+		if (mxl_fail(ret))
+			goto fail;
+	} else if (pin <= 10) {
+		if (pin == 0)
+			pin += 7;
+		ret = mxl111sf_read_reg(state, 0x30, &tmp);
+		if (mxl_fail(ret))
+			goto fail;
+		tmp &= ~(1 << (pin - 3));
+		tmp |= (val << (pin - 3));
+		ret = mxl111sf_write_reg(state, 0x30, tmp);
+		if (mxl_fail(ret))
+			goto fail;
+	} else
+		ret = -EINVAL;
+fail:
+	return ret;
+}
+
+static int mxl111sf_get_gpi_state(struct mxl111sf_state *state, u8 pin, u8 *val)
+{
+	int ret;
+	u8 tmp;
+
+	mxl_debug("(0x%02x)", pin);
+
+	*val = 0;
+
+	switch (pin) {
+	case 0:
+	case 1:
+	case 2:
+	case 3:
+		ret = mxl111sf_read_reg(state, 0x23, &tmp);
+		if (mxl_fail(ret))
+			goto fail;
+		*val = (tmp >> (pin + 4)) & 0x01;
+		break;
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+		ret = mxl111sf_read_reg(state, 0x2f, &tmp);
+		if (mxl_fail(ret))
+			goto fail;
+		*val = (tmp >> pin) & 0x01;
+		break;
+	case 8:
+	case 9:
+	case 10:
+		ret = mxl111sf_read_reg(state, 0x22, &tmp);
+		if (mxl_fail(ret))
+			goto fail;
+		*val = (tmp >> (pin - 3)) & 0x01;
+		break;
+	default:
+		return -EINVAL; /* invalid pin */
+	}
+fail:
+	return ret;
+}
+
+struct mxl_gpio_cfg {
+	u8 pin;
+	u8 dir;
+	u8 val;
+};
+
+static int mxl111sf_config_gpio_pins(struct mxl111sf_state *state,
+				     struct mxl_gpio_cfg *gpio_cfg)
+{
+	int ret;
+	u8 tmp;
+
+	mxl_debug_adv("(%d, %d)", gpio_cfg->pin, gpio_cfg->dir);
+
+	switch (gpio_cfg->pin) {
+	case 0:
+	case 1:
+	case 2:
+	case 3:
+		ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_0, &tmp);
+		if (mxl_fail(ret))
+			goto fail;
+		tmp &= ~(1 << (gpio_cfg->pin + 4));
+		tmp |= (gpio_cfg->dir << (gpio_cfg->pin + 4));
+		ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_0, tmp);
+		if (mxl_fail(ret))
+			goto fail;
+		break;
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+		ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_1, &tmp);
+		if (mxl_fail(ret))
+			goto fail;
+		tmp &= ~(1 << gpio_cfg->pin);
+		tmp |= (gpio_cfg->dir << gpio_cfg->pin);
+		ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_1, tmp);
+		if (mxl_fail(ret))
+			goto fail;
+		break;
+	case 8:
+	case 9:
+	case 10:
+		ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_2, &tmp);
+		if (mxl_fail(ret))
+			goto fail;
+		tmp &= ~(1 << (gpio_cfg->pin - 3));
+		tmp |= (gpio_cfg->dir << (gpio_cfg->pin - 3));
+		ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_2, tmp);
+		if (mxl_fail(ret))
+			goto fail;
+		break;
+	default:
+		return -EINVAL; /* invalid pin */
+	}
+
+	ret = (MXL_GPIO_DIR_OUTPUT == gpio_cfg->dir) ?
+		mxl111sf_set_gpo_state(state,
+				       gpio_cfg->pin, gpio_cfg->val) :
+		mxl111sf_get_gpi_state(state,
+				       gpio_cfg->pin, &gpio_cfg->val);
+	mxl_fail(ret);
+fail:
+	return ret;
+}
+
+static int mxl111sf_hw_do_set_gpio(struct mxl111sf_state *state,
+				   int gpio, int direction, int val)
+{
+	struct mxl_gpio_cfg gpio_config = {
+		.pin = gpio,
+		.dir = direction,
+		.val = val,
+	};
+
+	mxl_debug("(%d, %d, %d)", gpio, direction, val);
+
+	return mxl111sf_config_gpio_pins(state, &gpio_config);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#define PIN_MUX_MPEG_MODE_MASK          0x40   /* 0x17 <6> */
+#define PIN_MUX_MPEG_PAR_EN_MASK        0x01   /* 0x18 <0> */
+#define PIN_MUX_MPEG_SER_EN_MASK        0x02   /* 0x18 <1> */
+#define PIN_MUX_MPG_IN_MUX_MASK         0x80   /* 0x3D <7> */
+#define PIN_MUX_BT656_ENABLE_MASK       0x04   /* 0x12 <2> */
+#define PIN_MUX_I2S_ENABLE_MASK         0x40   /* 0x15 <6> */
+#define PIN_MUX_SPI_MODE_MASK           0x10   /* 0x3D <4> */
+#define PIN_MUX_MCLK_EN_CTRL_MASK       0x10   /* 0x82 <4> */
+#define PIN_MUX_MPSYN_EN_CTRL_MASK      0x20   /* 0x82 <5> */
+#define PIN_MUX_MDVAL_EN_CTRL_MASK      0x40   /* 0x82 <6> */
+#define PIN_MUX_MPERR_EN_CTRL_MASK      0x80   /* 0x82 <7> */
+#define PIN_MUX_MDAT_EN_0_MASK          0x10   /* 0x84 <4> */
+#define PIN_MUX_MDAT_EN_1_MASK          0x20   /* 0x84 <5> */
+#define PIN_MUX_MDAT_EN_2_MASK          0x40   /* 0x84 <6> */
+#define PIN_MUX_MDAT_EN_3_MASK          0x80   /* 0x84 <7> */
+#define PIN_MUX_MDAT_EN_4_MASK          0x10   /* 0x89 <4> */
+#define PIN_MUX_MDAT_EN_5_MASK          0x20   /* 0x89 <5> */
+#define PIN_MUX_MDAT_EN_6_MASK          0x40   /* 0x89 <6> */
+#define PIN_MUX_MDAT_EN_7_MASK          0x80   /* 0x89 <7> */
+
+int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state,
+				  enum mxl111sf_mux_config pin_mux_config)
+{
+	u8 r12, r15, r17, r18, r3D, r82, r84, r89;
+	int ret;
+
+	mxl_debug("(%d)", pin_mux_config);
+
+	ret = mxl111sf_read_reg(state, 0x17, &r17);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_read_reg(state, 0x18, &r18);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_read_reg(state, 0x12, &r12);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_read_reg(state, 0x15, &r15);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_read_reg(state, 0x82, &r82);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_read_reg(state, 0x84, &r84);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_read_reg(state, 0x89, &r89);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_read_reg(state, 0x3D, &r3D);
+	if (mxl_fail(ret))
+		goto fail;
+
+	switch (pin_mux_config) {
+	case PIN_MUX_TS_OUT_PARALLEL:
+		/* mpeg_mode = 1 */
+		r17 |= PIN_MUX_MPEG_MODE_MASK;
+		/* mpeg_par_en = 1 */
+		r18 |= PIN_MUX_MPEG_PAR_EN_MASK;
+		/* mpeg_ser_en = 0 */
+		r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
+		/* mpg_in_mux = 0 */
+		r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
+		/* bt656_enable = 0 */
+		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+		/* i2s_enable = 0 */
+		r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
+		/* spi_mode = 0 */
+		r3D &= ~PIN_MUX_SPI_MODE_MASK;
+		/* mclk_en_ctrl = 1 */
+		r82 |= PIN_MUX_MCLK_EN_CTRL_MASK;
+		/* mperr_en_ctrl = 1 */
+		r82 |= PIN_MUX_MPERR_EN_CTRL_MASK;
+		/* mdval_en_ctrl = 1 */
+		r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK;
+		/* mpsyn_en_ctrl = 1 */
+		r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK;
+		/* mdat_en_ctrl[3:0] = 0xF */
+		r84 |= 0xF0;
+		/* mdat_en_ctrl[7:4] = 0xF */
+		r89 |= 0xF0;
+		break;
+	case PIN_MUX_TS_OUT_SERIAL:
+		/* mpeg_mode = 1 */
+		r17 |= PIN_MUX_MPEG_MODE_MASK;
+		/* mpeg_par_en = 0 */
+		r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
+		/* mpeg_ser_en = 1 */
+		r18 |= PIN_MUX_MPEG_SER_EN_MASK;
+		/* mpg_in_mux = 0 */
+		r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
+		/* bt656_enable = 0 */
+		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+		/* i2s_enable = 0 */
+		r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
+		/* spi_mode = 0 */
+		r3D &= ~PIN_MUX_SPI_MODE_MASK;
+		/* mclk_en_ctrl = 1 */
+		r82 |= PIN_MUX_MCLK_EN_CTRL_MASK;
+		/* mperr_en_ctrl = 1 */
+		r82 |= PIN_MUX_MPERR_EN_CTRL_MASK;
+		/* mdval_en_ctrl = 1 */
+		r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK;
+		/* mpsyn_en_ctrl = 1 */
+		r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK;
+		/* mdat_en_ctrl[3:0] = 0xF */
+		r84 |= 0xF0;
+		/* mdat_en_ctrl[7:4] = 0xF */
+		r89 |= 0xF0;
+		break;
+	case PIN_MUX_GPIO_MODE:
+		/* mpeg_mode = 0 */
+		r17 &= ~PIN_MUX_MPEG_MODE_MASK;
+		/* mpeg_par_en = 0 */
+		r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
+		/* mpeg_ser_en = 0 */
+		r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
+		/* mpg_in_mux = 0 */
+		r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
+		/* bt656_enable = 0 */
+		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+		/* i2s_enable = 0 */
+		r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
+		/* spi_mode = 0 */
+		r3D &= ~PIN_MUX_SPI_MODE_MASK;
+		/* mclk_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
+		/* mperr_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
+		/* mdval_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
+		/* mpsyn_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
+		/* mdat_en_ctrl[3:0] = 0x0 */
+		r84 &= 0x0F;
+		/* mdat_en_ctrl[7:4] = 0x0 */
+		r89 &= 0x0F;
+		break;
+	case PIN_MUX_TS_SERIAL_IN_MODE_0:
+		/* mpeg_mode = 0 */
+		r17 &= ~PIN_MUX_MPEG_MODE_MASK;
+		/* mpeg_par_en = 0 */
+		r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
+		/* mpeg_ser_en = 1 */
+		r18 |= PIN_MUX_MPEG_SER_EN_MASK;
+		/* mpg_in_mux = 0 */
+		r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
+		/* bt656_enable = 0 */
+		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+		/* i2s_enable = 0 */
+		r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
+		/* spi_mode = 0 */
+		r3D &= ~PIN_MUX_SPI_MODE_MASK;
+		/* mclk_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
+		/* mperr_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
+		/* mdval_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
+		/* mpsyn_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
+		/* mdat_en_ctrl[3:0] = 0x0 */
+		r84 &= 0x0F;
+		/* mdat_en_ctrl[7:4] = 0x0 */
+		r89 &= 0x0F;
+		break;
+	case PIN_MUX_TS_SERIAL_IN_MODE_1:
+		/* mpeg_mode = 0 */
+		r17 &= ~PIN_MUX_MPEG_MODE_MASK;
+		/* mpeg_par_en = 0 */
+		r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
+		/* mpeg_ser_en = 1 */
+		r18 |= PIN_MUX_MPEG_SER_EN_MASK;
+		/* mpg_in_mux = 1 */
+		r3D |= PIN_MUX_MPG_IN_MUX_MASK;
+		/* bt656_enable = 0 */
+		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+		/* i2s_enable = 0 */
+		r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
+		/* spi_mode = 0 */
+		r3D &= ~PIN_MUX_SPI_MODE_MASK;
+		/* mclk_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
+		/* mperr_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
+		/* mdval_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
+		/* mpsyn_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
+		/* mdat_en_ctrl[3:0] = 0x0 */
+		r84 &= 0x0F;
+		/* mdat_en_ctrl[7:4] = 0x0 */
+		r89 &= 0x0F;
+		break;
+	case PIN_MUX_TS_SPI_IN_MODE_1:
+		/* mpeg_mode = 0 */
+		r17 &= ~PIN_MUX_MPEG_MODE_MASK;
+		/* mpeg_par_en = 0 */
+		r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
+		/* mpeg_ser_en = 1 */
+		r18 |= PIN_MUX_MPEG_SER_EN_MASK;
+		/* mpg_in_mux = 1 */
+		r3D |= PIN_MUX_MPG_IN_MUX_MASK;
+		/* bt656_enable = 0 */
+		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+		/* i2s_enable = 1 */
+		r15 |= PIN_MUX_I2S_ENABLE_MASK;
+		/* spi_mode = 1 */
+		r3D |= PIN_MUX_SPI_MODE_MASK;
+		/* mclk_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
+		/* mperr_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
+		/* mdval_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
+		/* mpsyn_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
+		/* mdat_en_ctrl[3:0] = 0x0 */
+		r84 &= 0x0F;
+		/* mdat_en_ctrl[7:4] = 0x0 */
+		r89 &= 0x0F;
+		break;
+	case PIN_MUX_TS_SPI_IN_MODE_0:
+		/* mpeg_mode = 0 */
+		r17 &= ~PIN_MUX_MPEG_MODE_MASK;
+		/* mpeg_par_en = 0 */
+		r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
+		/* mpeg_ser_en = 1 */
+		r18 |= PIN_MUX_MPEG_SER_EN_MASK;
+		/* mpg_in_mux = 0 */
+		r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
+		/* bt656_enable = 0 */
+		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+		/* i2s_enable = 1 */
+		r15 |= PIN_MUX_I2S_ENABLE_MASK;
+		/* spi_mode = 1 */
+		r3D |= PIN_MUX_SPI_MODE_MASK;
+		/* mclk_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
+		/* mperr_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
+		/* mdval_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
+		/* mpsyn_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
+		/* mdat_en_ctrl[3:0] = 0x0 */
+		r84 &= 0x0F;
+		/* mdat_en_ctrl[7:4] = 0x0 */
+		r89 &= 0x0F;
+		break;
+	case PIN_MUX_TS_PARALLEL_IN:
+		/* mpeg_mode = 0 */
+		r17 &= ~PIN_MUX_MPEG_MODE_MASK;
+		/* mpeg_par_en = 1 */
+		r18 |= PIN_MUX_MPEG_PAR_EN_MASK;
+		/* mpeg_ser_en = 0 */
+		r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
+		/* mpg_in_mux = 0 */
+		r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
+		/* bt656_enable = 0 */
+		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+		/* i2s_enable = 0 */
+		r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
+		/* spi_mode = 0 */
+		r3D &= ~PIN_MUX_SPI_MODE_MASK;
+		/* mclk_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
+		/* mperr_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
+		/* mdval_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
+		/* mpsyn_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
+		/* mdat_en_ctrl[3:0] = 0x0 */
+		r84 &= 0x0F;
+		/* mdat_en_ctrl[7:4] = 0x0 */
+		r89 &= 0x0F;
+		break;
+	case PIN_MUX_BT656_I2S_MODE:
+		/* mpeg_mode = 0 */
+		r17 &= ~PIN_MUX_MPEG_MODE_MASK;
+		/* mpeg_par_en = 0 */
+		r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
+		/* mpeg_ser_en = 0 */
+		r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
+		/* mpg_in_mux = 0 */
+		r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
+		/* bt656_enable = 1 */
+		r12 |= PIN_MUX_BT656_ENABLE_MASK;
+		/* i2s_enable = 1 */
+		r15 |= PIN_MUX_I2S_ENABLE_MASK;
+		/* spi_mode = 0 */
+		r3D &= ~PIN_MUX_SPI_MODE_MASK;
+		/* mclk_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
+		/* mperr_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
+		/* mdval_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
+		/* mpsyn_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
+		/* mdat_en_ctrl[3:0] = 0x0 */
+		r84 &= 0x0F;
+		/* mdat_en_ctrl[7:4] = 0x0 */
+		r89 &= 0x0F;
+		break;
+	case PIN_MUX_DEFAULT:
+	default:
+		/* mpeg_mode = 1 */
+		r17 |= PIN_MUX_MPEG_MODE_MASK;
+		/* mpeg_par_en = 0 */
+		r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK;
+		/* mpeg_ser_en = 0 */
+		r18 &= ~PIN_MUX_MPEG_SER_EN_MASK;
+		/* mpg_in_mux = 0 */
+		r3D &= ~PIN_MUX_MPG_IN_MUX_MASK;
+		/* bt656_enable = 0 */
+		r12 &= ~PIN_MUX_BT656_ENABLE_MASK;
+		/* i2s_enable = 0 */
+		r15 &= ~PIN_MUX_I2S_ENABLE_MASK;
+		/* spi_mode = 0 */
+		r3D &= ~PIN_MUX_SPI_MODE_MASK;
+		/* mclk_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK;
+		/* mperr_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK;
+		/* mdval_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK;
+		/* mpsyn_en_ctrl = 0 */
+		r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK;
+		/* mdat_en_ctrl[3:0] = 0x0 */
+		r84 &= 0x0F;
+		/* mdat_en_ctrl[7:4] = 0x0 */
+		r89 &= 0x0F;
+		break;
+	}
+
+	ret = mxl111sf_write_reg(state, 0x17, r17);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_write_reg(state, 0x18, r18);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_write_reg(state, 0x12, r12);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_write_reg(state, 0x15, r15);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_write_reg(state, 0x82, r82);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_write_reg(state, 0x84, r84);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_write_reg(state, 0x89, r89);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_write_reg(state, 0x3D, r3D);
+	if (mxl_fail(ret))
+		goto fail;
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int mxl111sf_hw_set_gpio(struct mxl111sf_state *state, int gpio, int val)
+{
+	return mxl111sf_hw_do_set_gpio(state, gpio, MXL_GPIO_DIR_OUTPUT, val);
+}
+
+static int mxl111sf_hw_gpio_initialize(struct mxl111sf_state *state)
+{
+	u8 gpioval = 0x07; /* write protect enabled, signal LEDs off */
+	int i, ret;
+
+	mxl_debug("()");
+
+	for (i = 3; i < 8; i++) {
+		ret = mxl111sf_hw_set_gpio(state, i, (gpioval >> i) & 0x01);
+		if (mxl_fail(ret))
+			break;
+	}
+
+	return ret;
+}
+
+#define PCA9534_I2C_ADDR (0x40 >> 1)
+static int pca9534_set_gpio(struct mxl111sf_state *state, int gpio, int val)
+{
+	u8 w[2] = { 1, 0 };
+	u8 r = 0;
+	struct i2c_msg msg[] = {
+		{ .addr = PCA9534_I2C_ADDR,
+		  .flags = 0, .buf = w, .len = 1 },
+		{ .addr = PCA9534_I2C_ADDR,
+		  .flags = I2C_M_RD, .buf = &r, .len = 1 },
+	};
+
+	mxl_debug("(%d, %d)", gpio, val);
+
+	/* read current GPIO levels from flip-flop */
+	i2c_transfer(&state->d->i2c_adap, msg, 2);
+
+	/* prepare write buffer with current GPIO levels */
+	msg[0].len = 2;
+#if 0
+	w[0] = 1;
+#endif
+	w[1] = r;
+
+	/* clear the desired GPIO */
+	w[1] &= ~(1 << gpio);
+
+	/* set the desired GPIO value */
+	w[1] |= ((val ? 1 : 0) << gpio);
+
+	/* write new GPIO levels to flip-flop */
+	i2c_transfer(&state->d->i2c_adap, &msg[0], 1);
+
+	return 0;
+}
+
+static int pca9534_init_port_expander(struct mxl111sf_state *state)
+{
+	u8 w[2] = { 1, 0x07 }; /* write protect enabled, signal LEDs off */
+
+	struct i2c_msg msg = {
+		.addr = PCA9534_I2C_ADDR,
+		.flags = 0, .buf = w, .len = 2
+	};
+
+	mxl_debug("()");
+
+	i2c_transfer(&state->d->i2c_adap, &msg, 1);
+
+	/* configure all pins as outputs */
+	w[0] = 3;
+	w[1] = 0;
+
+	i2c_transfer(&state->d->i2c_adap, &msg, 1);
+
+	return 0;
+}
+
+int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val)
+{
+	mxl_debug("(%d, %d)", gpio, val);
+
+	switch (state->gpio_port_expander) {
+	default:
+		mxl_printk(KERN_ERR,
+			   "gpio_port_expander undefined, assuming PCA9534");
+		/* fall-thru */
+	case mxl111sf_PCA9534:
+		return pca9534_set_gpio(state, gpio, val);
+	case mxl111sf_gpio_hw:
+		return mxl111sf_hw_set_gpio(state, gpio, val);
+	}
+}
+
+static int mxl111sf_probe_port_expander(struct mxl111sf_state *state)
+{
+	int ret;
+	u8 w = 1;
+	u8 r = 0;
+	struct i2c_msg msg[] = {
+		{ .flags = 0,        .buf = &w, .len = 1 },
+		{ .flags = I2C_M_RD, .buf = &r, .len = 1 },
+	};
+
+	mxl_debug("()");
+
+	msg[0].addr = 0x70 >> 1;
+	msg[1].addr = 0x70 >> 1;
+
+	/* read current GPIO levels from flip-flop */
+	ret = i2c_transfer(&state->d->i2c_adap, msg, 2);
+	if (ret == 2) {
+		state->port_expander_addr = msg[0].addr;
+		state->gpio_port_expander = mxl111sf_PCA9534;
+		mxl_debug("found port expander at 0x%02x",
+			  state->port_expander_addr);
+		return 0;
+	}
+
+	msg[0].addr = 0x40 >> 1;
+	msg[1].addr = 0x40 >> 1;
+
+	ret = i2c_transfer(&state->d->i2c_adap, msg, 2);
+	if (ret == 2) {
+		state->port_expander_addr = msg[0].addr;
+		state->gpio_port_expander = mxl111sf_PCA9534;
+		mxl_debug("found port expander at 0x%02x",
+			  state->port_expander_addr);
+		return 0;
+	}
+	state->port_expander_addr = 0xff;
+	state->gpio_port_expander = mxl111sf_gpio_hw;
+	mxl_debug("using hardware gpio");
+	return 0;
+}
+
+int mxl111sf_init_port_expander(struct mxl111sf_state *state)
+{
+	mxl_debug("()");
+
+	if (0x00 == state->port_expander_addr)
+		mxl111sf_probe_port_expander(state);
+
+	switch (state->gpio_port_expander) {
+	default:
+		mxl_printk(KERN_ERR,
+			   "gpio_port_expander undefined, assuming PCA9534");
+		/* fall-thru */
+	case mxl111sf_PCA9534:
+		return pca9534_init_port_expander(state);
+	case mxl111sf_gpio_hw:
+		return mxl111sf_hw_gpio_initialize(state);
+	}
+}
+
+/* ------------------------------------------------------------------------ */
+
+int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode)
+{
+/*	GPO:
+ *	3 - ATSC/MH#   | 1 = ATSC transport, 0 = MH transport      | default 0
+ *	4 - ATSC_RST## | 1 = ATSC enable, 0 = ATSC Reset           | default 0
+ *	5 - ATSC_EN    | 1 = ATSC power enable, 0 = ATSC power off | default 0
+ *	6 - MH_RESET#  | 1 = MH enable, 0 = MH Reset               | default 0
+ *	7 - MH_EN      | 1 = MH power enable, 0 = MH power off     | default 0
+ */
+	mxl_debug("(%d)", mode);
+
+	switch (mode) {
+	case MXL111SF_GPIO_MOD_MH:
+		mxl111sf_set_gpio(state, 4, 0);
+		mxl111sf_set_gpio(state, 5, 0);
+		msleep(50);
+		mxl111sf_set_gpio(state, 7, 1);
+		msleep(50);
+		mxl111sf_set_gpio(state, 6, 1);
+		msleep(50);
+
+		mxl111sf_set_gpio(state, 3, 0);
+		break;
+	case MXL111SF_GPIO_MOD_ATSC:
+		mxl111sf_set_gpio(state, 6, 0);
+		mxl111sf_set_gpio(state, 7, 0);
+		msleep(50);
+		mxl111sf_set_gpio(state, 5, 1);
+		msleep(50);
+		mxl111sf_set_gpio(state, 4, 1);
+		msleep(50);
+		mxl111sf_set_gpio(state, 3, 1);
+		break;
+	default: /* DVBT / STANDBY */
+		mxl111sf_init_port_expander(state);
+		break;
+	}
+	return 0;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h
new file mode 100644
index 0000000..0220f54
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h
@@ -0,0 +1,56 @@
+/*
+ *  mxl111sf-gpio.h - driver for the MaxLinear MXL111SF
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _DVB_USB_MXL111SF_GPIO_H_
+#define _DVB_USB_MXL111SF_GPIO_H_
+
+#include "mxl111sf.h"
+
+int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val);
+int mxl111sf_init_port_expander(struct mxl111sf_state *state);
+
+#define MXL111SF_GPIO_MOD_DVBT	0
+#define MXL111SF_GPIO_MOD_MH	1
+#define MXL111SF_GPIO_MOD_ATSC	2
+int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode);
+
+enum mxl111sf_mux_config {
+	PIN_MUX_DEFAULT = 0,
+	PIN_MUX_TS_OUT_PARALLEL,
+	PIN_MUX_TS_OUT_SERIAL,
+	PIN_MUX_GPIO_MODE,
+	PIN_MUX_TS_SERIAL_IN_MODE_0,
+	PIN_MUX_TS_SERIAL_IN_MODE_1,
+	PIN_MUX_TS_SPI_IN_MODE_0,
+	PIN_MUX_TS_SPI_IN_MODE_1,
+	PIN_MUX_TS_PARALLEL_IN,
+	PIN_MUX_BT656_I2S_MODE,
+};
+
+int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state,
+				  enum mxl111sf_mux_config pin_mux_config);
+
+#endif /* _DVB_USB_MXL111SF_GPIO_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c
new file mode 100644
index 0000000..3443455
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c
@@ -0,0 +1,850 @@
+/*
+ *  mxl111sf-i2c.c - driver for the MaxLinear MXL111SF
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "mxl111sf-i2c.h"
+#include "mxl111sf.h"
+
+/* SW-I2C ----------------------------------------------------------------- */
+
+#define SW_I2C_ADDR		0x1a
+#define SW_I2C_EN		0x02
+#define SW_SCL_OUT		0x04
+#define SW_SDA_OUT		0x08
+#define SW_SDA_IN		0x04
+
+#define SW_I2C_BUSY_ADDR	0x2f
+#define SW_I2C_BUSY		0x02
+
+static int mxl111sf_i2c_bitbang_sendbyte(struct mxl111sf_state *state,
+					 u8 byte)
+{
+	int i, ret;
+	u8 data = 0;
+
+	mxl_i2c("(0x%02x)", byte);
+
+	ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
+	if (mxl_fail(ret))
+		goto fail;
+
+	for (i = 0; i < 8; i++) {
+
+		data = (byte & (0x80 >> i)) ? SW_SDA_OUT : 0;
+
+		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+					 0x10 | SW_I2C_EN | data);
+		if (mxl_fail(ret))
+			goto fail;
+
+		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+					 0x10 | SW_I2C_EN | data | SW_SCL_OUT);
+		if (mxl_fail(ret))
+			goto fail;
+
+		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+					 0x10 | SW_I2C_EN | data);
+		if (mxl_fail(ret))
+			goto fail;
+	}
+
+	/* last bit was 0 so we need to release SDA */
+	if (!(byte & 1)) {
+		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+					 0x10 | SW_I2C_EN | SW_SDA_OUT);
+		if (mxl_fail(ret))
+			goto fail;
+	}
+
+	/* CLK high for ACK readback */
+	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
+	if (mxl_fail(ret))
+		goto fail;
+
+	/* drop the CLK after getting ACK, SDA will go high right away */
+	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+				 0x10 | SW_I2C_EN | SW_SDA_OUT);
+	if (mxl_fail(ret))
+		goto fail;
+
+	if (data & SW_SDA_IN)
+		ret = -EIO;
+fail:
+	return ret;
+}
+
+static int mxl111sf_i2c_bitbang_recvbyte(struct mxl111sf_state *state,
+					 u8 *pbyte)
+{
+	int i, ret;
+	u8 byte = 0;
+	u8 data = 0;
+
+	mxl_i2c("()");
+
+	*pbyte = 0;
+
+	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+				 0x10 | SW_I2C_EN | SW_SDA_OUT);
+	if (mxl_fail(ret))
+		goto fail;
+
+	for (i = 0; i < 8; i++) {
+		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+					 0x10 | SW_I2C_EN |
+					 SW_SCL_OUT | SW_SDA_OUT);
+		if (mxl_fail(ret))
+			goto fail;
+
+		ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
+		if (mxl_fail(ret))
+			goto fail;
+
+		if (data & SW_SDA_IN)
+			byte |= (0x80 >> i);
+
+		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+					 0x10 | SW_I2C_EN | SW_SDA_OUT);
+		if (mxl_fail(ret))
+			goto fail;
+	}
+	*pbyte = byte;
+fail:
+	return ret;
+}
+
+static int mxl111sf_i2c_start(struct mxl111sf_state *state)
+{
+	int ret;
+
+	mxl_i2c("()");
+
+	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+				 0x10 | SW_I2C_EN | SW_SCL_OUT);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+				 0x10 | SW_I2C_EN); /* start */
+	mxl_fail(ret);
+fail:
+	return ret;
+}
+
+static int mxl111sf_i2c_stop(struct mxl111sf_state *state)
+{
+	int ret;
+
+	mxl_i2c("()");
+
+	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+				 0x10 | SW_I2C_EN); /* stop */
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+				 0x10 | SW_I2C_EN | SW_SCL_OUT);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+				 0x10 | SW_SCL_OUT | SW_SDA_OUT);
+	mxl_fail(ret);
+fail:
+	return ret;
+}
+
+static int mxl111sf_i2c_ack(struct mxl111sf_state *state)
+{
+	int ret;
+	u8 b = 0;
+
+	mxl_i2c("()");
+
+	ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &b);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+				 0x10 | SW_I2C_EN);
+	if (mxl_fail(ret))
+		goto fail;
+
+	/* pull SDA low */
+	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+				 0x10 | SW_I2C_EN | SW_SCL_OUT);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+				 0x10 | SW_I2C_EN | SW_SDA_OUT);
+	mxl_fail(ret);
+fail:
+	return ret;
+}
+
+static int mxl111sf_i2c_nack(struct mxl111sf_state *state)
+{
+	int ret;
+
+	mxl_i2c("()");
+
+	/* SDA high to signal last byte read from slave */
+	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
+				 0x10 | SW_I2C_EN | SW_SDA_OUT);
+	mxl_fail(ret);
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int mxl111sf_i2c_sw_xfer_msg(struct mxl111sf_state *state,
+				    struct i2c_msg *msg)
+{
+	int i, ret;
+
+	mxl_i2c("()");
+
+	if (msg->flags & I2C_M_RD) {
+
+		ret = mxl111sf_i2c_start(state);
+		if (mxl_fail(ret))
+			goto fail;
+
+		ret = mxl111sf_i2c_bitbang_sendbyte(state,
+						    (msg->addr << 1) | 0x01);
+		if (mxl_fail(ret)) {
+			mxl111sf_i2c_stop(state);
+			goto fail;
+		}
+
+		for (i = 0; i < msg->len; i++) {
+			ret = mxl111sf_i2c_bitbang_recvbyte(state,
+							    &msg->buf[i]);
+			if (mxl_fail(ret)) {
+				mxl111sf_i2c_stop(state);
+				goto fail;
+			}
+
+			if (i < msg->len - 1)
+				mxl111sf_i2c_ack(state);
+		}
+
+		mxl111sf_i2c_nack(state);
+
+		ret = mxl111sf_i2c_stop(state);
+		if (mxl_fail(ret))
+			goto fail;
+
+	} else {
+
+		ret = mxl111sf_i2c_start(state);
+		if (mxl_fail(ret))
+			goto fail;
+
+		ret = mxl111sf_i2c_bitbang_sendbyte(state,
+						    (msg->addr << 1) & 0xfe);
+		if (mxl_fail(ret)) {
+			mxl111sf_i2c_stop(state);
+			goto fail;
+		}
+
+		for (i = 0; i < msg->len; i++) {
+			ret = mxl111sf_i2c_bitbang_sendbyte(state,
+							    msg->buf[i]);
+			if (mxl_fail(ret)) {
+				mxl111sf_i2c_stop(state);
+				goto fail;
+			}
+		}
+
+		/* FIXME: we only want to do this on the last transaction */
+		mxl111sf_i2c_stop(state);
+	}
+fail:
+	return ret;
+}
+
+/* HW-I2C ----------------------------------------------------------------- */
+
+#define USB_WRITE_I2C_CMD     0x99
+#define USB_READ_I2C_CMD      0xdd
+#define USB_END_I2C_CMD       0xfe
+
+#define USB_WRITE_I2C_CMD_LEN   26
+#define USB_READ_I2C_CMD_LEN    24
+
+#define I2C_MUX_REG           0x30
+#define I2C_CONTROL_REG       0x00
+#define I2C_SLAVE_ADDR_REG    0x08
+#define I2C_DATA_REG          0x0c
+#define I2C_INT_STATUS_REG    0x10
+
+static int mxl111sf_i2c_send_data(struct mxl111sf_state *state,
+				  u8 index, u8 *wdata)
+{
+	int ret = mxl111sf_ctrl_msg(state->d, wdata[0],
+				    &wdata[1], 25, NULL, 0);
+	mxl_fail(ret);
+
+	return ret;
+}
+
+static int mxl111sf_i2c_get_data(struct mxl111sf_state *state,
+				 u8 index, u8 *wdata, u8 *rdata)
+{
+	int ret = mxl111sf_ctrl_msg(state->d, wdata[0],
+				    &wdata[1], 25, rdata, 24);
+	mxl_fail(ret);
+
+	return ret;
+}
+
+static u8 mxl111sf_i2c_check_status(struct mxl111sf_state *state)
+{
+	u8 status = 0;
+	u8 buf[26];
+
+	mxl_i2c_adv("()");
+
+	buf[0] = USB_READ_I2C_CMD;
+	buf[1] = 0x00;
+
+	buf[2] = I2C_INT_STATUS_REG;
+	buf[3] = 0x00;
+	buf[4] = 0x00;
+
+	buf[5] = USB_END_I2C_CMD;
+
+	mxl111sf_i2c_get_data(state, 0, buf, buf);
+
+	if (buf[1] & 0x04)
+		status = 1;
+
+	return status;
+}
+
+static u8 mxl111sf_i2c_check_fifo(struct mxl111sf_state *state)
+{
+	u8 status = 0;
+	u8 buf[26];
+
+	mxl_i2c("()");
+
+	buf[0] = USB_READ_I2C_CMD;
+	buf[1] = 0x00;
+
+	buf[2] = I2C_MUX_REG;
+	buf[3] = 0x00;
+	buf[4] = 0x00;
+
+	buf[5] = I2C_INT_STATUS_REG;
+	buf[6] = 0x00;
+	buf[7] = 0x00;
+	buf[8] = USB_END_I2C_CMD;
+
+	mxl111sf_i2c_get_data(state, 0, buf, buf);
+
+	if (0x08 == (buf[1] & 0x08))
+		status = 1;
+
+	if ((buf[5] & 0x02) == 0x02)
+		mxl_i2c("(buf[5] & 0x02) == 0x02"); /* FIXME */
+
+	return status;
+}
+
+static int mxl111sf_i2c_readagain(struct mxl111sf_state *state,
+				  u8 count, u8 *rbuf)
+{
+	u8 i2c_w_data[26];
+	u8 i2c_r_data[24];
+	u8 i = 0;
+	u8 fifo_status = 0;
+	int status = 0;
+
+	mxl_i2c("read %d bytes", count);
+
+	while ((fifo_status == 0) && (i++ < 5))
+		fifo_status = mxl111sf_i2c_check_fifo(state);
+
+	i2c_w_data[0] = 0xDD;
+	i2c_w_data[1] = 0x00;
+
+	for (i = 2; i < 26; i++)
+		i2c_w_data[i] = 0xFE;
+
+	for (i = 0; i < count; i++) {
+		i2c_w_data[2+(i*3)] = 0x0C;
+		i2c_w_data[3+(i*3)] = 0x00;
+		i2c_w_data[4+(i*3)] = 0x00;
+	}
+
+	mxl111sf_i2c_get_data(state, 0, i2c_w_data, i2c_r_data);
+
+	/* Check for I2C NACK status */
+	if (mxl111sf_i2c_check_status(state) == 1) {
+		mxl_i2c("error!");
+	} else {
+		for (i = 0; i < count; i++) {
+			rbuf[i] = i2c_r_data[(i*3)+1];
+			mxl_i2c("%02x\t %02x",
+				i2c_r_data[(i*3)+1],
+				i2c_r_data[(i*3)+2]);
+		}
+
+		status = 1;
+	}
+
+	return status;
+}
+
+#define HWI2C400 1
+static int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state,
+				    struct i2c_msg *msg)
+{
+	int i, k, ret = 0;
+	u16 index = 0;
+	u8 buf[26];
+	u8 i2c_r_data[24];
+	u16 block_len;
+	u16 left_over_len;
+	u8 rd_status[8];
+	u8 ret_status;
+	u8 readbuff[26];
+
+	mxl_i2c("addr: 0x%02x, read buff len: %d, write buff len: %d",
+		msg->addr, (msg->flags & I2C_M_RD) ? msg->len : 0,
+		(!(msg->flags & I2C_M_RD)) ? msg->len : 0);
+
+	for (index = 0; index < 26; index++)
+		buf[index] = USB_END_I2C_CMD;
+
+	/* command to indicate data payload is destined for I2C interface */
+	buf[0] = USB_WRITE_I2C_CMD;
+	buf[1] = 0x00;
+
+	/* enable I2C interface */
+	buf[2] = I2C_MUX_REG;
+	buf[3] = 0x80;
+	buf[4] = 0x00;
+
+	/* enable I2C interface */
+	buf[5] = I2C_MUX_REG;
+	buf[6] = 0x81;
+	buf[7] = 0x00;
+
+	/* set Timeout register on I2C interface */
+	buf[8] = 0x14;
+	buf[9] = 0xff;
+	buf[10] = 0x00;
+#if 0
+	/* enable Interrupts on I2C interface */
+	buf[8] = 0x24;
+	buf[9] = 0xF7;
+	buf[10] = 0x00;
+#endif
+	buf[11] = 0x24;
+	buf[12] = 0xF7;
+	buf[13] = 0x00;
+
+	ret = mxl111sf_i2c_send_data(state, 0, buf);
+
+	/* write data on I2C bus */
+	if (!(msg->flags & I2C_M_RD) && (msg->len > 0)) {
+		mxl_i2c("%d\t%02x", msg->len, msg->buf[0]);
+
+		/* control register on I2C interface to initialize I2C bus */
+		buf[2] = I2C_CONTROL_REG;
+		buf[3] = 0x5E;
+		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+
+		/* I2C Slave device Address */
+		buf[5] = I2C_SLAVE_ADDR_REG;
+		buf[6] = (msg->addr);
+		buf[7] = 0x00;
+		buf[8] = USB_END_I2C_CMD;
+		ret = mxl111sf_i2c_send_data(state, 0, buf);
+
+		/* check for slave device status */
+		if (mxl111sf_i2c_check_status(state) == 1) {
+			mxl_i2c("NACK writing slave address %02x",
+				msg->addr);
+			/* if NACK, stop I2C bus and exit */
+			buf[2] = I2C_CONTROL_REG;
+			buf[3] = 0x4E;
+			buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+			ret = -EIO;
+			goto exit;
+		}
+
+		/* I2C interface can do I2C operations in block of 8 bytes of
+		   I2C data. calculation to figure out number of blocks of i2c
+		   data required to program */
+		block_len = (msg->len / 8);
+		left_over_len = (msg->len % 8);
+		index = 0;
+
+		mxl_i2c("block_len %d, left_over_len %d",
+			block_len, left_over_len);
+
+		for (index = 0; index < block_len; index++) {
+			for (i = 0; i < 8; i++) {
+				/* write data on I2C interface */
+				buf[2+(i*3)] = I2C_DATA_REG;
+				buf[3+(i*3)] = msg->buf[(index*8)+i];
+				buf[4+(i*3)] = 0x00;
+			}
+
+			ret = mxl111sf_i2c_send_data(state, 0, buf);
+
+			/* check for I2C NACK status */
+			if (mxl111sf_i2c_check_status(state) == 1) {
+				mxl_i2c("NACK writing slave address %02x",
+					msg->addr);
+
+				/* if NACK, stop I2C bus and exit */
+				buf[2] = I2C_CONTROL_REG;
+				buf[3] = 0x4E;
+				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+				ret = -EIO;
+				goto exit;
+			}
+
+		}
+
+		if (left_over_len) {
+			for (k = 0; k < 26; k++)
+				buf[k] = USB_END_I2C_CMD;
+
+			buf[0] = 0x99;
+			buf[1] = 0x00;
+
+			for (i = 0; i < left_over_len; i++) {
+				buf[2+(i*3)] = I2C_DATA_REG;
+				buf[3+(i*3)] = msg->buf[(index*8)+i];
+				mxl_i2c("index = %d %d data %d",
+					index, i, msg->buf[(index*8)+i]);
+				buf[4+(i*3)] = 0x00;
+			}
+			ret = mxl111sf_i2c_send_data(state, 0, buf);
+
+			/* check for I2C NACK status */
+			if (mxl111sf_i2c_check_status(state) == 1) {
+				mxl_i2c("NACK writing slave address %02x",
+					msg->addr);
+
+				/* if NACK, stop I2C bus and exit */
+				buf[2] = I2C_CONTROL_REG;
+				buf[3] = 0x4E;
+				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+				ret = -EIO;
+				goto exit;
+			}
+
+		}
+
+		/* issue I2C STOP after write */
+		buf[2] = I2C_CONTROL_REG;
+		buf[3] = 0x4E;
+		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+
+	}
+
+	/* read data from I2C bus */
+	if ((msg->flags & I2C_M_RD) && (msg->len > 0)) {
+		mxl_i2c("read buf len %d", msg->len);
+
+		/* command to indicate data payload is
+		   destined for I2C interface */
+		buf[2] = I2C_CONTROL_REG;
+		buf[3] = 0xDF;
+		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+
+		/* I2C xfer length */
+		buf[5] = 0x14;
+		buf[6] = (msg->len & 0xFF);
+		buf[7] = 0;
+
+		/* I2C slave device Address */
+		buf[8] = I2C_SLAVE_ADDR_REG;
+		buf[9] = msg->addr;
+		buf[10] = 0x00;
+		buf[11] = USB_END_I2C_CMD;
+		ret = mxl111sf_i2c_send_data(state, 0, buf);
+
+		/* check for I2C NACK status */
+		if (mxl111sf_i2c_check_status(state) == 1) {
+			mxl_i2c("NACK reading slave address %02x",
+				msg->addr);
+
+			/* if NACK, stop I2C bus and exit */
+			buf[2] = I2C_CONTROL_REG;
+			buf[3] = 0xC7;
+			buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+			ret = -EIO;
+			goto exit;
+		}
+
+		/* I2C interface can do I2C operations in block of 8 bytes of
+		   I2C data. calculation to figure out number of blocks of
+		   i2c data required to program */
+		block_len = ((msg->len) / 8);
+		left_over_len = ((msg->len) % 8);
+		index = 0;
+
+		mxl_i2c("block_len %d, left_over_len %d",
+			block_len, left_over_len);
+
+		/* command to read data from I2C interface */
+		buf[0] = USB_READ_I2C_CMD;
+		buf[1] = 0x00;
+
+		for (index = 0; index < block_len; index++) {
+			/* setup I2C read request packet on I2C interface */
+			for (i = 0; i < 8; i++) {
+				buf[2+(i*3)] = I2C_DATA_REG;
+				buf[3+(i*3)] = 0x00;
+				buf[4+(i*3)] = 0x00;
+			}
+
+			ret = mxl111sf_i2c_get_data(state, 0, buf, i2c_r_data);
+
+			/* check for I2C NACK status */
+			if (mxl111sf_i2c_check_status(state) == 1) {
+				mxl_i2c("NACK reading slave address %02x",
+					msg->addr);
+
+				/* if NACK, stop I2C bus and exit */
+				buf[2] = I2C_CONTROL_REG;
+				buf[3] = 0xC7;
+				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+				ret = -EIO;
+				goto exit;
+			}
+
+			/* copy data from i2c data payload to read buffer */
+			for (i = 0; i < 8; i++) {
+				rd_status[i] = i2c_r_data[(i*3)+2];
+
+				if (rd_status[i] == 0x04) {
+					if (i < 7) {
+						mxl_i2c("i2c fifo empty!"
+							" @ %d", i);
+						msg->buf[(index*8)+i] =
+							i2c_r_data[(i*3)+1];
+						/* read again */
+						ret_status =
+							mxl111sf_i2c_readagain(
+								state, 8-(i+1),
+								readbuff);
+						if (ret_status == 1) {
+							for (k = 0;
+							     k < 8-(i+1);
+							     k++) {
+
+					msg->buf[(index*8)+(k+i+1)] =
+						readbuff[k];
+					mxl_i2c("read data: %02x\t %02x",
+						msg->buf[(index*8)+(k+i)],
+						(index*8)+(k+i));
+					mxl_i2c("read data: %02x\t %02x",
+						msg->buf[(index*8)+(k+i+1)],
+						readbuff[k]);
+
+							}
+							goto stop_copy;
+						} else {
+							mxl_i2c("readagain "
+								"ERROR!");
+						}
+					} else {
+						msg->buf[(index*8)+i] =
+							i2c_r_data[(i*3)+1];
+					}
+				} else {
+					msg->buf[(index*8)+i] =
+						i2c_r_data[(i*3)+1];
+				}
+			}
+stop_copy:
+			;
+
+		}
+
+		if (left_over_len) {
+			for (k = 0; k < 26; k++)
+				buf[k] = USB_END_I2C_CMD;
+
+			buf[0] = 0xDD;
+			buf[1] = 0x00;
+
+			for (i = 0; i < left_over_len; i++) {
+				buf[2+(i*3)] = I2C_DATA_REG;
+				buf[3+(i*3)] = 0x00;
+				buf[4+(i*3)] = 0x00;
+			}
+			ret = mxl111sf_i2c_get_data(state, 0, buf,
+						    i2c_r_data);
+
+			/* check for I2C NACK status */
+			if (mxl111sf_i2c_check_status(state) == 1) {
+				mxl_i2c("NACK reading slave address %02x",
+					msg->addr);
+
+				/* if NACK, stop I2C bus and exit */
+				buf[2] = I2C_CONTROL_REG;
+				buf[3] = 0xC7;
+				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+				ret = -EIO;
+				goto exit;
+			}
+
+			for (i = 0; i < left_over_len; i++) {
+				msg->buf[(block_len*8)+i] =
+					i2c_r_data[(i*3)+1];
+				mxl_i2c("read data: %02x\t %02x",
+					i2c_r_data[(i*3)+1],
+					i2c_r_data[(i*3)+2]);
+			}
+		}
+
+		/* indicate I2C interface to issue NACK
+		   after next I2C read op */
+		buf[0] = USB_WRITE_I2C_CMD;
+		buf[1] = 0x00;
+
+		/* control register */
+		buf[2] = I2C_CONTROL_REG;
+		buf[3] = 0x17;
+		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+
+		buf[5] = USB_END_I2C_CMD;
+		ret = mxl111sf_i2c_send_data(state, 0, buf);
+
+		/* control register */
+		buf[2] = I2C_CONTROL_REG;
+		buf[3] = 0xC7;
+		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
+
+	}
+exit:
+	/* STOP and disable I2C MUX */
+	buf[0] = USB_WRITE_I2C_CMD;
+	buf[1] = 0x00;
+
+	/* de-initilize I2C BUS */
+	buf[5] = USB_END_I2C_CMD;
+	mxl111sf_i2c_send_data(state, 0, buf);
+
+	/* Control Register */
+	buf[2] = I2C_CONTROL_REG;
+	buf[3] = 0xDF;
+	buf[4] = 0x03;
+
+	/* disable I2C interface */
+	buf[5] = I2C_MUX_REG;
+	buf[6] = 0x00;
+	buf[7] = 0x00;
+
+	/* de-initilize I2C BUS */
+	buf[8] = USB_END_I2C_CMD;
+	mxl111sf_i2c_send_data(state, 0, buf);
+
+	/* disable I2C interface */
+	buf[2] = I2C_MUX_REG;
+	buf[3] = 0x81;
+	buf[4] = 0x00;
+
+	/* disable I2C interface */
+	buf[5] = I2C_MUX_REG;
+	buf[6] = 0x00;
+	buf[7] = 0x00;
+
+	/* disable I2C interface */
+	buf[8] = I2C_MUX_REG;
+	buf[9] = 0x00;
+	buf[10] = 0x00;
+
+	buf[11] = USB_END_I2C_CMD;
+	mxl111sf_i2c_send_data(state, 0, buf);
+
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+int mxl111sf_i2c_xfer(struct i2c_adapter *adap,
+		      struct i2c_msg msg[], int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct mxl111sf_state *state = d->priv;
+	int hwi2c = (state->chip_rev > MXL111SF_V6);
+	int i, ret;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		ret = (hwi2c) ?
+			mxl111sf_i2c_hw_xfer_msg(state, &msg[i]) :
+			mxl111sf_i2c_sw_xfer_msg(state, &msg[i]);
+		if (mxl_fail(ret)) {
+			mxl_debug_adv("failed with error %d on i2c "
+				      "transaction %d of %d, %sing %d bytes "
+				      "to/from 0x%02x", ret, i+1, num,
+				      (msg[i].flags & I2C_M_RD) ?
+				      "read" : "writ",
+				      msg[i].len, msg[i].addr);
+
+			break;
+		}
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+
+	return i == num ? num : -EREMOTEIO;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h
new file mode 100644
index 0000000..a57a45f
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h
@@ -0,0 +1,35 @@
+/*
+ *  mxl111sf-i2c.h - driver for the MaxLinear MXL111SF
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _DVB_USB_MXL111SF_I2C_H_
+#define _DVB_USB_MXL111SF_I2C_H_
+
+#include <linux/i2c.h>
+
+int mxl111sf_i2c_xfer(struct i2c_adapter *adap,
+		      struct i2c_msg msg[], int num);
+
+#endif /* _DVB_USB_MXL111SF_I2C_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c
new file mode 100644
index 0000000..b741b3a
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c
@@ -0,0 +1,343 @@
+/*
+ *  mxl111sf-phy.c - driver for the MaxLinear MXL111SF
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "mxl111sf-phy.h"
+#include "mxl111sf-reg.h"
+
+int mxl111sf_init_tuner_demod(struct mxl111sf_state *state)
+{
+	struct mxl111sf_reg_ctrl_info mxl_111_overwrite_default[] = {
+		{0x07, 0xff, 0x0c},
+		{0x58, 0xff, 0x9d},
+		{0x09, 0xff, 0x00},
+		{0x06, 0xff, 0x06},
+		{0xc8, 0xff, 0x40}, /* ED_LE_WIN_OLD = 0 */
+		{0x8d, 0x01, 0x01}, /* NEGATE_Q */
+		{0x32, 0xff, 0xac}, /* DIG_RFREFSELECT = 12 */
+		{0x42, 0xff, 0x43}, /* DIG_REG_AMP = 4 */
+		{0x74, 0xff, 0xc4}, /* SSPUR_FS_PRIO = 4 */
+		{0x71, 0xff, 0xe6}, /* SPUR_ROT_PRIO_VAL = 1 */
+		{0x83, 0xff, 0x64}, /* INF_FILT1_THD_SC = 100 */
+		{0x85, 0xff, 0x64}, /* INF_FILT2_THD_SC = 100 */
+		{0x88, 0xff, 0xf0}, /* INF_THD = 240 */
+		{0x6f, 0xf0, 0xb0}, /* DFE_DLY = 11 */
+		{0x00, 0xff, 0x01}, /* Change to page 1 */
+		{0x81, 0xff, 0x11}, /* DSM_FERR_BYPASS = 1 */
+		{0xf4, 0xff, 0x07}, /* DIG_FREQ_CORR = 1 */
+		{0xd4, 0x1f, 0x0f}, /* SPUR_TEST_NOISE_TH = 15 */
+		{0xd6, 0xff, 0x0c}, /* SPUR_TEST_NOISE_PAPR = 12 */
+		{0x00, 0xff, 0x00}, /* Change to page 0 */
+		{0,    0,    0}
+	};
+
+	mxl_debug("()");
+
+	return mxl111sf_ctrl_program_regs(state, mxl_111_overwrite_default);
+}
+
+int mxl1x1sf_soft_reset(struct mxl111sf_state *state)
+{
+	int ret;
+	mxl_debug("()");
+
+	ret = mxl111sf_write_reg(state, 0xff, 0x00); /* AIC */
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_write_reg(state, 0x02, 0x01); /* get out of reset */
+	mxl_fail(ret);
+fail:
+	return ret;
+}
+
+int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode)
+{
+	int ret;
+
+	mxl_debug("(%s)", MXL_SOC_MODE == mode ?
+		"MXL_SOC_MODE" : "MXL_TUNER_MODE");
+
+	/* set device mode */
+	ret = mxl111sf_write_reg(state, 0x03,
+				 MXL_SOC_MODE == mode ? 0x01 : 0x00);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_write_reg_mask(state,
+				      0x7d, 0x40, MXL_SOC_MODE == mode ?
+				      0x00 : /* enable impulse noise filter,
+						INF_BYP = 0 */
+				      0x40); /* disable impulse noise filter,
+						INF_BYP = 1 */
+	if (mxl_fail(ret))
+		goto fail;
+
+	state->device_mode = mode;
+fail:
+	return ret;
+}
+
+/* power up tuner */
+int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff)
+{
+	mxl_debug("(%d)", onoff);
+
+	return mxl111sf_write_reg(state, 0x01, onoff ? 0x01 : 0x00);
+}
+
+int mxl111sf_disable_656_port(struct mxl111sf_state *state)
+{
+	mxl_debug("()");
+
+	return mxl111sf_write_reg_mask(state, 0x12, 0x04, 0x00);
+}
+
+int mxl111sf_enable_usb_output(struct mxl111sf_state *state)
+{
+	mxl_debug("()");
+
+	return mxl111sf_write_reg_mask(state, 0x17, 0x40, 0x00);
+}
+
+/* initialize TSIF as input port of MxL1X1SF for MPEG2 data transfer */
+int mxl111sf_config_mpeg_in(struct mxl111sf_state *state,
+			    unsigned int parallel_serial,
+			    unsigned int msb_lsb_1st,
+			    unsigned int clock_phase,
+			    unsigned int mpeg_valid_pol,
+			    unsigned int mpeg_sync_pol)
+{
+	int ret;
+	u8 mode, tmp;
+
+	mxl_debug("(%u,%u,%u,%u,%u)", parallel_serial, msb_lsb_1st,
+		  clock_phase, mpeg_valid_pol, mpeg_sync_pol);
+
+	/* Enable PIN MUX */
+	ret = mxl111sf_write_reg(state, V6_PIN_MUX_MODE_REG, V6_ENABLE_PIN_MUX);
+	mxl_fail(ret);
+
+	/* Configure MPEG Clock phase */
+	mxl111sf_read_reg(state, V6_MPEG_IN_CLK_INV_REG, &mode);
+
+	if (clock_phase == TSIF_NORMAL)
+		mode &= ~V6_INVERTED_CLK_PHASE;
+	else
+		mode |= V6_INVERTED_CLK_PHASE;
+
+	ret = mxl111sf_write_reg(state, V6_MPEG_IN_CLK_INV_REG, mode);
+	mxl_fail(ret);
+
+	/* Configure data input mode, MPEG Valid polarity, MPEG Sync polarity
+	 * Get current configuration */
+	ret = mxl111sf_read_reg(state, V6_MPEG_IN_CTRL_REG, &mode);
+	mxl_fail(ret);
+
+	/* Data Input mode */
+	if (parallel_serial == TSIF_INPUT_PARALLEL) {
+		/* Disable serial mode */
+		mode &= ~V6_MPEG_IN_DATA_SERIAL;
+
+		/* Enable Parallel mode */
+		mode |= V6_MPEG_IN_DATA_PARALLEL;
+	} else {
+		/* Disable Parallel mode */
+		mode &= ~V6_MPEG_IN_DATA_PARALLEL;
+
+		/* Enable Serial Mode */
+		mode |= V6_MPEG_IN_DATA_SERIAL;
+
+		/* If serial interface is chosen, configure
+		   MSB or LSB order in transmission */
+		ret = mxl111sf_read_reg(state,
+					V6_MPEG_INOUT_BIT_ORDER_CTRL_REG,
+					&tmp);
+		mxl_fail(ret);
+
+		if (msb_lsb_1st == MPEG_SER_MSB_FIRST_ENABLED)
+			tmp |= V6_MPEG_SER_MSB_FIRST;
+		else
+			tmp &= ~V6_MPEG_SER_MSB_FIRST;
+
+		ret = mxl111sf_write_reg(state,
+					 V6_MPEG_INOUT_BIT_ORDER_CTRL_REG,
+					 tmp);
+		mxl_fail(ret);
+	}
+
+	/* MPEG Sync polarity */
+	if (mpeg_sync_pol == TSIF_NORMAL)
+		mode &= ~V6_INVERTED_MPEG_SYNC;
+	else
+		mode |= V6_INVERTED_MPEG_SYNC;
+
+	/* MPEG Valid polarity */
+	if (mpeg_valid_pol == 0)
+		mode &= ~V6_INVERTED_MPEG_VALID;
+	else
+		mode |= V6_INVERTED_MPEG_VALID;
+
+	ret = mxl111sf_write_reg(state, V6_MPEG_IN_CTRL_REG, mode);
+	mxl_fail(ret);
+
+	return ret;
+}
+
+int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size)
+{
+	static struct mxl111sf_reg_ctrl_info init_i2s[] = {
+		{0x1b, 0xff, 0x1e}, /* pin mux mode, Choose 656/I2S input */
+		{0x15, 0x60, 0x60}, /* Enable I2S */
+		{0x17, 0xe0, 0x20}, /* Input, MPEG MODE USB,
+				       Inverted 656 Clock, I2S_SOFT_RESET,
+				       0 : Normal operation, 1 : Reset State */
+#if 0
+		{0x12, 0x01, 0x00}, /* AUDIO_IRQ_CLR (Overflow Indicator) */
+#endif
+		{0x00, 0xff, 0x02}, /* Change to Control Page */
+		{0x26, 0x0d, 0x0d}, /* I2S_MODE & BT656_SRC_SEL for FPGA only */
+		{0x00, 0xff, 0x00},
+		{0,    0,    0}
+	};
+	int ret;
+
+	mxl_debug("(0x%02x)", sample_size);
+
+	ret = mxl111sf_ctrl_program_regs(state, init_i2s);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_write_reg(state, V6_I2S_NUM_SAMPLES_REG, sample_size);
+	mxl_fail(ret);
+fail:
+	return ret;
+}
+
+int mxl111sf_disable_i2s_port(struct mxl111sf_state *state)
+{
+	static struct mxl111sf_reg_ctrl_info disable_i2s[] = {
+		{0x15, 0x40, 0x00},
+		{0,    0,    0}
+	};
+
+	mxl_debug("()");
+
+	return mxl111sf_ctrl_program_regs(state, disable_i2s);
+}
+
+int mxl111sf_config_i2s(struct mxl111sf_state *state,
+			u8 msb_start_pos, u8 data_width)
+{
+	int ret;
+	u8 tmp;
+
+	mxl_debug("(0x%02x, 0x%02x)", msb_start_pos, data_width);
+
+	ret = mxl111sf_read_reg(state, V6_I2S_STREAM_START_BIT_REG, &tmp);
+	if (mxl_fail(ret))
+		goto fail;
+
+	tmp &= 0xe0;
+	tmp |= msb_start_pos;
+	ret = mxl111sf_write_reg(state, V6_I2S_STREAM_START_BIT_REG, tmp);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_read_reg(state, V6_I2S_STREAM_END_BIT_REG, &tmp);
+	if (mxl_fail(ret))
+		goto fail;
+
+	tmp &= 0xe0;
+	tmp |= data_width;
+	ret = mxl111sf_write_reg(state, V6_I2S_STREAM_END_BIT_REG, tmp);
+	mxl_fail(ret);
+fail:
+	return ret;
+}
+
+int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff)
+{
+	u8 val;
+	int ret;
+
+	mxl_debug("(%d)", onoff);
+
+	ret = mxl111sf_write_reg(state, 0x00, 0x02);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_read_reg(state, V8_SPI_MODE_REG, &val);
+	if (mxl_fail(ret))
+		goto fail;
+
+	if (onoff)
+		val |= 0x04;
+	else
+		val &= ~0x04;
+
+	ret = mxl111sf_write_reg(state, V8_SPI_MODE_REG, val);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_write_reg(state, 0x00, 0x00);
+	mxl_fail(ret);
+fail:
+	return ret;
+}
+
+int mxl111sf_idac_config(struct mxl111sf_state *state,
+			 u8 control_mode, u8 current_setting,
+			 u8 current_value, u8 hysteresis_value)
+{
+	int ret;
+	u8 val;
+	/* current value will be set for both automatic & manual IDAC control */
+	val = current_value;
+
+	if (control_mode == IDAC_MANUAL_CONTROL) {
+		/* enable manual control of IDAC */
+		val |= IDAC_MANUAL_CONTROL_BIT_MASK;
+
+		if (current_setting == IDAC_CURRENT_SINKING_ENABLE)
+			/* enable current sinking in manual mode */
+			val |= IDAC_CURRENT_SINKING_BIT_MASK;
+		else
+			/* disable current sinking in manual mode */
+			val &= ~IDAC_CURRENT_SINKING_BIT_MASK;
+	} else {
+		/* disable manual control of IDAC */
+		val &= ~IDAC_MANUAL_CONTROL_BIT_MASK;
+
+		/* set hysteresis value  reg: 0x0B<5:0> */
+		ret = mxl111sf_write_reg(state, V6_IDAC_HYSTERESIS_REG,
+					 (hysteresis_value & 0x3F));
+		mxl_fail(ret);
+	}
+
+	ret = mxl111sf_write_reg(state, V6_IDAC_SETTINGS_REG, val);
+	mxl_fail(ret);
+
+	return ret;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h
new file mode 100644
index 0000000..f075607
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h
@@ -0,0 +1,53 @@
+/*
+ *  mxl111sf-phy.h - driver for the MaxLinear MXL111SF
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _DVB_USB_MXL111SF_PHY_H_
+#define _DVB_USB_MXL111SF_PHY_H_
+
+#include "mxl111sf.h"
+
+int mxl1x1sf_soft_reset(struct mxl111sf_state *state);
+int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode);
+int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff);
+int mxl111sf_disable_656_port(struct mxl111sf_state *state);
+int mxl111sf_init_tuner_demod(struct mxl111sf_state *state);
+int mxl111sf_enable_usb_output(struct mxl111sf_state *state);
+int mxl111sf_config_mpeg_in(struct mxl111sf_state *state,
+			    unsigned int parallel_serial,
+			    unsigned int msb_lsb_1st,
+			    unsigned int clock_phase,
+			    unsigned int mpeg_valid_pol,
+			    unsigned int mpeg_sync_pol);
+int mxl111sf_config_i2s(struct mxl111sf_state *state,
+			u8 msb_start_pos, u8 data_width);
+int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size);
+int mxl111sf_disable_i2s_port(struct mxl111sf_state *state);
+int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff);
+int mxl111sf_idac_config(struct mxl111sf_state *state,
+			 u8 control_mode, u8 current_setting,
+			 u8 current_value, u8 hysteresis_value);
+
+#endif /* _DVB_USB_MXL111SF_PHY_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h
new file mode 100644
index 0000000..17831b0
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h
@@ -0,0 +1,179 @@
+/*
+ *  mxl111sf-reg.h - driver for the MaxLinear MXL111SF
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _DVB_USB_MXL111SF_REG_H_
+#define _DVB_USB_MXL111SF_REG_H_
+
+#define CHIP_ID_REG                  0xFC
+#define TOP_CHIP_REV_ID_REG          0xFA
+
+#define V6_SNR_RB_LSB_REG            0x27
+#define V6_SNR_RB_MSB_REG            0x28
+
+#define V6_N_ACCUMULATE_REG          0x11
+#define V6_RS_AVG_ERRORS_LSB_REG     0x2C
+#define V6_RS_AVG_ERRORS_MSB_REG     0x2D
+
+#define V6_IRQ_STATUS_REG            0x24
+#define  IRQ_MASK_FEC_LOCK       0x10
+
+#define V6_SYNC_LOCK_REG             0x28
+#define SYNC_LOCK_MASK           0x10
+
+#define V6_RS_LOCK_DET_REG           0x28
+#define  RS_LOCK_DET_MASK        0x08
+
+#define V6_INITACQ_NODETECT_REG    0x20
+#define V6_FORCE_NFFT_CPSIZE_REG   0x20
+
+#define V6_CODE_RATE_TPS_REG       0x29
+#define V6_CODE_RATE_TPS_MASK      0x07
+
+
+#define V6_CP_LOCK_DET_REG        0x28
+#define V6_CP_LOCK_DET_MASK       0x04
+
+#define V6_TPS_HIERACHY_REG        0x29
+#define V6_TPS_HIERARCHY_INFO_MASK  0x40
+
+#define V6_MODORDER_TPS_REG        0x2A
+#define V6_PARAM_CONSTELLATION_MASK   0x30
+
+#define V6_MODE_TPS_REG            0x2A
+#define V6_PARAM_FFT_MODE_MASK        0x0C
+
+
+#define V6_CP_TPS_REG             0x29
+#define V6_PARAM_GI_MASK              0x30
+
+#define V6_TPS_LOCK_REG           0x2A
+#define V6_PARAM_TPS_LOCK_MASK        0x40
+
+#define V6_FEC_PER_COUNT_REG      0x2E
+#define V6_FEC_PER_SCALE_REG      0x2B
+#define V6_FEC_PER_SCALE_MASK        0x03
+#define V6_FEC_PER_CLR_REG        0x20
+#define V6_FEC_PER_CLR_MASK          0x01
+
+#define V6_PIN_MUX_MODE_REG       0x1B
+#define V6_ENABLE_PIN_MUX            0x1E
+
+#define V6_I2S_NUM_SAMPLES_REG    0x16
+
+#define V6_MPEG_IN_CLK_INV_REG    0x17
+#define V6_MPEG_IN_CTRL_REG       0x18
+
+#define V6_INVERTED_CLK_PHASE       0x20
+#define V6_MPEG_IN_DATA_PARALLEL    0x01
+#define V6_MPEG_IN_DATA_SERIAL      0x02
+
+#define V6_INVERTED_MPEG_SYNC       0x04
+#define V6_INVERTED_MPEG_VALID      0x08
+
+#define TSIF_INPUT_PARALLEL         0
+#define TSIF_INPUT_SERIAL           1
+#define TSIF_NORMAL                 0
+
+#define V6_MPEG_INOUT_BIT_ORDER_CTRL_REG  0x19
+#define V6_MPEG_SER_MSB_FIRST                0x80
+#define MPEG_SER_MSB_FIRST_ENABLED        0x01
+
+#define V6_656_I2S_BUFF_STATUS_REG   0x2F
+#define V6_656_OVERFLOW_MASK_BIT         0x08
+#define V6_I2S_OVERFLOW_MASK_BIT         0x01
+
+#define V6_I2S_STREAM_START_BIT_REG  0x14
+#define V6_I2S_STREAM_END_BIT_REG    0x15
+#define I2S_RIGHT_JUSTIFIED     0
+#define I2S_LEFT_JUSTIFIED      1
+#define I2S_DATA_FORMAT         2
+
+#define V6_TUNER_LOOP_THRU_CONTROL_REG  0x09
+#define V6_ENABLE_LOOP_THRU               0x01
+
+#define TOTAL_NUM_IF_OUTPUT_FREQ       16
+
+#define TUNER_NORMAL_IF_SPECTRUM       0x0
+#define TUNER_INVERT_IF_SPECTRUM       0x10
+
+#define V6_TUNER_IF_SEL_REG              0x06
+#define V6_TUNER_IF_FCW_REG              0x3C
+#define V6_TUNER_IF_FCW_BYP_REG          0x3D
+#define V6_RF_LOCK_STATUS_REG            0x23
+
+#define NUM_DIG_TV_CHANNEL     1000
+
+#define V6_DIG_CLK_FREQ_SEL_REG  0x07
+#define V6_REF_SYNTH_INT_REG     0x5C
+#define V6_REF_SYNTH_REMAIN_REG  0x58
+#define V6_DIG_RFREFSELECT_REG   0x32
+#define V6_XTAL_CLK_OUT_GAIN_REG   0x31
+#define V6_TUNER_LOOP_THRU_CTRL_REG      0x09
+#define V6_DIG_XTAL_ENABLE_REG  0x06
+#define V6_DIG_XTAL_BIAS_REG  0x66
+#define V6_XTAL_CAP_REG    0x08
+
+#define V6_GPO_CTRL_REG     0x18
+#define MXL_GPO_0           0x00
+#define MXL_GPO_1           0x01
+#define V6_GPO_0_MASK       0x10
+#define V6_GPO_1_MASK       0x20
+
+#define V6_111SF_GPO_CTRL_REG     0x19
+#define MXL_111SF_GPO_1               0x00
+#define MXL_111SF_GPO_2               0x01
+#define MXL_111SF_GPO_3               0x02
+#define MXL_111SF_GPO_4               0x03
+#define MXL_111SF_GPO_5               0x04
+#define MXL_111SF_GPO_6               0x05
+#define MXL_111SF_GPO_7               0x06
+
+#define MXL_111SF_GPO_0_MASK          0x01
+#define MXL_111SF_GPO_1_MASK          0x02
+#define MXL_111SF_GPO_2_MASK          0x04
+#define MXL_111SF_GPO_3_MASK          0x08
+#define MXL_111SF_GPO_4_MASK          0x10
+#define MXL_111SF_GPO_5_MASK          0x20
+#define MXL_111SF_GPO_6_MASK          0x40
+
+#define V6_ATSC_CONFIG_REG  0x0A
+
+#define MXL_MODE_REG    0x03
+#define START_TUNE_REG  0x1C
+
+#define V6_IDAC_HYSTERESIS_REG    0x0B
+#define V6_IDAC_SETTINGS_REG      0x0C
+#define IDAC_MANUAL_CONTROL             1
+#define IDAC_CURRENT_SINKING_ENABLE     1
+#define IDAC_MANUAL_CONTROL_BIT_MASK      0x80
+#define IDAC_CURRENT_SINKING_BIT_MASK     0x40
+
+#define V8_SPI_MODE_REG  0xE9
+
+#define V6_DIG_RF_PWR_LSB_REG  0x46
+#define V6_DIG_RF_PWR_MSB_REG  0x47
+
+#endif /* _DVB_USB_MXL111SF_REG_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
new file mode 100644
index 0000000..ef4c65f
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
@@ -0,0 +1,527 @@
+/*
+ *  mxl111sf-tuner.c - driver for the MaxLinear MXL111SF CMOS tuner
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "mxl111sf-tuner.h"
+#include "mxl111sf-phy.h"
+#include "mxl111sf-reg.h"
+
+/* debug */
+static int mxl111sf_tuner_debug;
+module_param_named(debug, mxl111sf_tuner_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
+
+#define mxl_dbg(fmt, arg...) \
+	if (mxl111sf_tuner_debug) \
+		mxl_printk(KERN_DEBUG, fmt, ##arg)
+
+#define err pr_err
+
+/* ------------------------------------------------------------------------ */
+
+struct mxl111sf_tuner_state {
+	struct mxl111sf_state *mxl_state;
+
+	struct mxl111sf_tuner_config *cfg;
+
+	enum mxl_if_freq if_freq;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+static int mxl111sf_tuner_read_reg(struct mxl111sf_tuner_state *state,
+				   u8 addr, u8 *data)
+{
+	return (state->cfg->read_reg) ?
+		state->cfg->read_reg(state->mxl_state, addr, data) :
+		-EINVAL;
+}
+
+static int mxl111sf_tuner_write_reg(struct mxl111sf_tuner_state *state,
+				    u8 addr, u8 data)
+{
+	return (state->cfg->write_reg) ?
+		state->cfg->write_reg(state->mxl_state, addr, data) :
+		-EINVAL;
+}
+
+static int mxl111sf_tuner_program_regs(struct mxl111sf_tuner_state *state,
+			       struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
+{
+	return (state->cfg->program_regs) ?
+		state->cfg->program_regs(state->mxl_state, ctrl_reg_info) :
+		-EINVAL;
+}
+
+static int mxl1x1sf_tuner_top_master_ctrl(struct mxl111sf_tuner_state *state,
+					  int onoff)
+{
+	return (state->cfg->top_master_ctrl) ?
+		state->cfg->top_master_ctrl(state->mxl_state, onoff) :
+		-EINVAL;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static struct mxl111sf_reg_ctrl_info mxl_phy_tune_rf[] = {
+	{0x1d, 0x7f, 0x00}, /* channel bandwidth section 1/2/3,
+			       DIG_MODEINDEX, _A, _CSF, */
+	{0x1e, 0xff, 0x00}, /* channel frequency (lo and fractional) */
+	{0x1f, 0xff, 0x00}, /* channel frequency (hi for integer portion) */
+	{0,    0,    0}
+};
+
+/* ------------------------------------------------------------------------ */
+
+static struct mxl111sf_reg_ctrl_info *mxl111sf_calc_phy_tune_regs(u32 freq,
+								  u8 bw)
+{
+	u8 filt_bw;
+
+	/* set channel bandwidth */
+	switch (bw) {
+	case 0: /* ATSC */
+		filt_bw = 25;
+		break;
+	case 1: /* QAM */
+		filt_bw = 69;
+		break;
+	case 6:
+		filt_bw = 21;
+		break;
+	case 7:
+		filt_bw = 42;
+		break;
+	case 8:
+		filt_bw = 63;
+		break;
+	default:
+		err("%s: invalid bandwidth setting!", __func__);
+		return NULL;
+	}
+
+	/* calculate RF channel */
+	freq /= 1000000;
+
+	freq *= 64;
+#if 0
+	/* do round */
+	freq += 0.5;
+#endif
+	/* set bandwidth */
+	mxl_phy_tune_rf[0].data = filt_bw;
+
+	/* set RF */
+	mxl_phy_tune_rf[1].data = (freq & 0xff);
+	mxl_phy_tune_rf[2].data = (freq >> 8) & 0xff;
+
+	/* start tune */
+	return mxl_phy_tune_rf;
+}
+
+static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state)
+{
+	int ret;
+	u8 ctrl;
+#if 0
+	u16 iffcw;
+	u32 if_freq;
+#endif
+	mxl_dbg("(IF polarity = %d, IF freq = 0x%02x)",
+		state->cfg->invert_spectrum, state->cfg->if_freq);
+
+	/* set IF polarity */
+	ctrl = state->cfg->invert_spectrum;
+
+	ctrl |= state->cfg->if_freq;
+
+	ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_SEL_REG, ctrl);
+	if (mxl_fail(ret))
+		goto fail;
+
+#if 0
+	if_freq /= 1000000;
+
+	/* do round */
+	if_freq += 0.5;
+
+	if (MXL_IF_LO == state->cfg->if_freq) {
+		ctrl = 0x08;
+		iffcw = (u16)(if_freq / (108 * 4096));
+	} else if (MXL_IF_HI == state->cfg->if_freq) {
+		ctrl = 0x08;
+		iffcw = (u16)(if_freq / (216 * 4096));
+	} else {
+		ctrl = 0;
+		iffcw = 0;
+	}
+
+	ctrl |= (iffcw >> 8);
+#endif
+	ret = mxl111sf_tuner_read_reg(state, V6_TUNER_IF_FCW_BYP_REG, &ctrl);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ctrl &= 0xf0;
+	ctrl |= 0x90;
+
+	ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_BYP_REG, ctrl);
+	if (mxl_fail(ret))
+		goto fail;
+
+#if 0
+	ctrl = iffcw & 0x00ff;
+#endif
+	ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl);
+	if (mxl_fail(ret))
+		goto fail;
+
+	state->if_freq = state->cfg->if_freq;
+fail:
+	return ret;
+}
+
+static int mxl1x1sf_tune_rf(struct dvb_frontend *fe, u32 freq, u8 bw)
+{
+	struct mxl111sf_tuner_state *state = fe->tuner_priv;
+	static struct mxl111sf_reg_ctrl_info *reg_ctrl_array;
+	int ret;
+	u8 mxl_mode;
+
+	mxl_dbg("(freq = %d, bw = 0x%x)", freq, bw);
+
+	/* stop tune */
+	ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 0);
+	if (mxl_fail(ret))
+		goto fail;
+
+	/* check device mode */
+	ret = mxl111sf_tuner_read_reg(state, MXL_MODE_REG, &mxl_mode);
+	if (mxl_fail(ret))
+		goto fail;
+
+	/* Fill out registers for channel tune */
+	reg_ctrl_array = mxl111sf_calc_phy_tune_regs(freq, bw);
+	if (!reg_ctrl_array)
+		return -EINVAL;
+
+	ret = mxl111sf_tuner_program_regs(state, reg_ctrl_array);
+	if (mxl_fail(ret))
+		goto fail;
+
+	if ((mxl_mode & MXL_DEV_MODE_MASK) == MXL_TUNER_MODE) {
+		/* IF tuner mode only */
+		mxl1x1sf_tuner_top_master_ctrl(state, 0);
+		mxl1x1sf_tuner_top_master_ctrl(state, 1);
+		mxl1x1sf_tuner_set_if_output_freq(state);
+	}
+
+	ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 1);
+	if (mxl_fail(ret))
+		goto fail;
+
+	if (state->cfg->ant_hunt)
+		state->cfg->ant_hunt(fe);
+fail:
+	return ret;
+}
+
+static int mxl1x1sf_tuner_get_lock_status(struct mxl111sf_tuner_state *state,
+					  int *rf_synth_lock,
+					  int *ref_synth_lock)
+{
+	int ret;
+	u8 data;
+
+	*rf_synth_lock = 0;
+	*ref_synth_lock = 0;
+
+	ret = mxl111sf_tuner_read_reg(state, V6_RF_LOCK_STATUS_REG, &data);
+	if (mxl_fail(ret))
+		goto fail;
+
+	*ref_synth_lock = ((data & 0x03) == 0x03) ? 1 : 0;
+	*rf_synth_lock  = ((data & 0x0c) == 0x0c) ? 1 : 0;
+fail:
+	return ret;
+}
+
+#if 0
+static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state,
+					 int onoff)
+{
+	return mxl111sf_tuner_write_reg(state, V6_TUNER_LOOP_THRU_CTRL_REG,
+					onoff ? 1 : 0);
+}
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static int mxl111sf_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u32 delsys  = c->delivery_system;
+	struct mxl111sf_tuner_state *state = fe->tuner_priv;
+	int ret;
+	u8 bw;
+
+	mxl_dbg("()");
+
+	switch (delsys) {
+	case SYS_ATSC:
+	case SYS_ATSCMH:
+		bw = 0; /* ATSC */
+		break;
+	case SYS_DVBC_ANNEX_B:
+		bw = 1; /* US CABLE */
+		break;
+	case SYS_DVBT:
+		switch (c->bandwidth_hz) {
+		case 6000000:
+			bw = 6;
+			break;
+		case 7000000:
+			bw = 7;
+			break;
+		case 8000000:
+			bw = 8;
+			break;
+		default:
+			err("%s: bandwidth not set!", __func__);
+			return -EINVAL;
+		}
+		break;
+	default:
+		err("%s: modulation type not supported!", __func__);
+		return -EINVAL;
+	}
+	ret = mxl1x1sf_tune_rf(fe, c->frequency, bw);
+	if (mxl_fail(ret))
+		goto fail;
+
+	state->frequency = c->frequency;
+	state->bandwidth = c->bandwidth_hz;
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+#if 0
+static int mxl111sf_tuner_init(struct dvb_frontend *fe)
+{
+	struct mxl111sf_tuner_state *state = fe->tuner_priv;
+	int ret;
+
+	/* wake from standby handled by usb driver */
+
+	return ret;
+}
+
+static int mxl111sf_tuner_sleep(struct dvb_frontend *fe)
+{
+	struct mxl111sf_tuner_state *state = fe->tuner_priv;
+	int ret;
+
+	/* enter standby mode handled by usb driver */
+
+	return ret;
+}
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static int mxl111sf_tuner_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct mxl111sf_tuner_state *state = fe->tuner_priv;
+	int rf_locked, ref_locked, ret;
+
+	*status = 0;
+
+	ret = mxl1x1sf_tuner_get_lock_status(state, &rf_locked, &ref_locked);
+	if (mxl_fail(ret))
+		goto fail;
+	mxl_info("%s%s", rf_locked ? "rf locked " : "",
+		 ref_locked ? "ref locked" : "");
+
+	if ((rf_locked) || (ref_locked))
+		*status |= TUNER_STATUS_LOCKED;
+fail:
+	return ret;
+}
+
+static int mxl111sf_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct mxl111sf_tuner_state *state = fe->tuner_priv;
+	u8 val1, val2;
+	int ret;
+
+	*strength = 0;
+
+	ret = mxl111sf_tuner_write_reg(state, 0x00, 0x02);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_LSB_REG, &val1);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_MSB_REG, &val2);
+	if (mxl_fail(ret))
+		goto fail;
+
+	*strength = val1 | ((val2 & 0x07) << 8);
+fail:
+	ret = mxl111sf_tuner_write_reg(state, 0x00, 0x00);
+	mxl_fail(ret);
+
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int mxl111sf_tuner_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct mxl111sf_tuner_state *state = fe->tuner_priv;
+	*frequency = state->frequency;
+	return 0;
+}
+
+static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct mxl111sf_tuner_state *state = fe->tuner_priv;
+	*bandwidth = state->bandwidth;
+	return 0;
+}
+
+static int mxl111sf_tuner_get_if_frequency(struct dvb_frontend *fe,
+					   u32 *frequency)
+{
+	struct mxl111sf_tuner_state *state = fe->tuner_priv;
+
+	*frequency = 0;
+
+	switch (state->if_freq) {
+	case MXL_IF_4_0:   /* 4.0   MHz */
+		*frequency = 4000000;
+		break;
+	case MXL_IF_4_5:   /* 4.5   MHz */
+		*frequency = 4500000;
+		break;
+	case MXL_IF_4_57:  /* 4.57  MHz */
+		*frequency = 4570000;
+		break;
+	case MXL_IF_5_0:   /* 5.0   MHz */
+		*frequency = 5000000;
+		break;
+	case MXL_IF_5_38:  /* 5.38  MHz */
+		*frequency = 5380000;
+		break;
+	case MXL_IF_6_0:   /* 6.0   MHz */
+		*frequency = 6000000;
+		break;
+	case MXL_IF_6_28:  /* 6.28  MHz */
+		*frequency = 6280000;
+		break;
+	case MXL_IF_7_2:   /* 7.2   MHz */
+		*frequency = 7200000;
+		break;
+	case MXL_IF_35_25: /* 35.25 MHz */
+		*frequency = 35250000;
+		break;
+	case MXL_IF_36:    /* 36    MHz */
+		*frequency = 36000000;
+		break;
+	case MXL_IF_36_15: /* 36.15 MHz */
+		*frequency = 36150000;
+		break;
+	case MXL_IF_44:    /* 44    MHz */
+		*frequency = 44000000;
+		break;
+	}
+	return 0;
+}
+
+static int mxl111sf_tuner_release(struct dvb_frontend *fe)
+{
+	struct mxl111sf_tuner_state *state = fe->tuner_priv;
+	mxl_dbg("()");
+	kfree(state);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = {
+	.info = {
+		.name = "MaxLinear MxL111SF",
+#if 0
+		.frequency_min  = ,
+		.frequency_max  = ,
+		.frequency_step = ,
+#endif
+	},
+#if 0
+	.init              = mxl111sf_tuner_init,
+	.sleep             = mxl111sf_tuner_sleep,
+#endif
+	.set_params        = mxl111sf_tuner_set_params,
+	.get_status        = mxl111sf_tuner_get_status,
+	.get_rf_strength   = mxl111sf_get_rf_strength,
+	.get_frequency     = mxl111sf_tuner_get_frequency,
+	.get_bandwidth     = mxl111sf_tuner_get_bandwidth,
+	.get_if_frequency  = mxl111sf_tuner_get_if_frequency,
+	.release           = mxl111sf_tuner_release,
+};
+
+struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
+					   struct mxl111sf_state *mxl_state,
+					   struct mxl111sf_tuner_config *cfg)
+{
+	struct mxl111sf_tuner_state *state = NULL;
+
+	mxl_dbg("()");
+
+	state = kzalloc(sizeof(struct mxl111sf_tuner_state), GFP_KERNEL);
+	if (state == NULL)
+		return NULL;
+
+	state->mxl_state = mxl_state;
+	state->cfg = cfg;
+
+	memcpy(&fe->ops.tuner_ops, &mxl111sf_tuner_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = state;
+	return fe;
+}
+EXPORT_SYMBOL_GPL(mxl111sf_tuner_attach);
+
+MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver");
+MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
new file mode 100644
index 0000000..ff33396
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
@@ -0,0 +1,89 @@
+/*
+ *  mxl111sf-tuner.h - driver for the MaxLinear MXL111SF CMOS tuner
+ *
+ *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MXL111SF_TUNER_H__
+#define __MXL111SF_TUNER_H__
+
+#include "dvb_frontend.h"
+
+#include "mxl111sf.h"
+
+enum mxl_if_freq {
+#if 0
+	MXL_IF_LO    = 0x00, /* other IF < 9MHz */
+#endif
+	MXL_IF_4_0   = 0x01, /* 4.0   MHz */
+	MXL_IF_4_5   = 0x02, /* 4.5   MHz */
+	MXL_IF_4_57  = 0x03, /* 4.57  MHz */
+	MXL_IF_5_0   = 0x04, /* 5.0   MHz */
+	MXL_IF_5_38  = 0x05, /* 5.38  MHz */
+	MXL_IF_6_0   = 0x06, /* 6.0   MHz */
+	MXL_IF_6_28  = 0x07, /* 6.28  MHz */
+	MXL_IF_7_2   = 0x08, /* 7.2   MHz */
+	MXL_IF_35_25 = 0x09, /* 35.25 MHz */
+	MXL_IF_36    = 0x0a, /* 36    MHz */
+	MXL_IF_36_15 = 0x0b, /* 36.15 MHz */
+	MXL_IF_44    = 0x0c, /* 44    MHz */
+#if 0
+	MXL_IF_HI    = 0x0f, /* other IF > 35 MHz and < 45 MHz */
+#endif
+};
+
+struct mxl111sf_tuner_config {
+	enum mxl_if_freq if_freq;
+	unsigned int invert_spectrum:1;
+
+	int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data);
+	int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data);
+	int (*program_regs)(struct mxl111sf_state *state,
+			    struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
+	int (*top_master_ctrl)(struct mxl111sf_state *state, int onoff);
+	int (*ant_hunt)(struct dvb_frontend *fe);
+};
+
+/* ------------------------------------------------------------------------ */
+
+#if defined(CONFIG_DVB_USB_MXL111SF) || \
+	(defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE))
+extern
+struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
+					   struct mxl111sf_state *mxl_state,
+					   struct mxl111sf_tuner_config *cfg);
+#else
+static inline
+struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
+					   struct mxl111sf_state *mxl_state
+					   struct mxl111sf_tuner_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* __MXL111SF_TUNER_H__ */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
new file mode 100644
index 0000000..efdcb15
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
@@ -0,0 +1,1431 @@
+/*
+ * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com)
+ *
+ *   This program is free software; you can redistribute it and/or modify it
+ *   under the terms of the GNU General Public License as published by the Free
+ *   Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+
+#include <linux/vmalloc.h>
+#include <linux/i2c.h>
+
+#include "mxl111sf.h"
+#include "mxl111sf-reg.h"
+#include "mxl111sf-phy.h"
+#include "mxl111sf-i2c.h"
+#include "mxl111sf-gpio.h"
+
+#include "mxl111sf-demod.h"
+#include "mxl111sf-tuner.h"
+
+#include "lgdt3305.h"
+#include "lg2160.h"
+
+int dvb_usb_mxl111sf_debug;
+module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level "
+		 "(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able)).");
+
+int dvb_usb_mxl111sf_isoc;
+module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644);
+MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc).");
+
+int dvb_usb_mxl111sf_spi;
+module_param_named(spi, dvb_usb_mxl111sf_spi, int, 0644);
+MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi).");
+
+#define ANT_PATH_AUTO 0
+#define ANT_PATH_EXTERNAL 1
+#define ANT_PATH_INTERNAL 2
+
+int dvb_usb_mxl111sf_rfswitch =
+#if 0
+		ANT_PATH_AUTO;
+#else
+		ANT_PATH_EXTERNAL;
+#endif
+
+module_param_named(rfswitch, dvb_usb_mxl111sf_rfswitch, int, 0644);
+MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int).");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define deb_info pr_debug
+#define deb_reg pr_debug
+#define deb_adv pr_debug
+#define err pr_err
+#define info pr_info
+
+int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
+		      u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+	int wo = (rbuf == NULL || rlen == 0); /* write-only */
+	int ret;
+	u8 sndbuf[1+wlen];
+
+	deb_adv("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen);
+
+	memset(sndbuf, 0, 1+wlen);
+
+	sndbuf[0] = cmd;
+	memcpy(&sndbuf[1], wbuf, wlen);
+
+	ret = (wo) ? dvb_usbv2_generic_write(d, sndbuf, 1+wlen) :
+		dvb_usbv2_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen);
+	mxl_fail(ret);
+
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+#define MXL_CMD_REG_READ	0xaa
+#define MXL_CMD_REG_WRITE	0x55
+
+int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data)
+{
+	u8 buf[2];
+	int ret;
+
+	ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_READ, &addr, 1, buf, 2);
+	if (mxl_fail(ret)) {
+		mxl_debug("error reading reg: 0x%02x", addr);
+		goto fail;
+	}
+
+	if (buf[0] == addr)
+		*data = buf[1];
+	else {
+		err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x",
+		    addr, buf[0], buf[1]);
+		ret = -EINVAL;
+	}
+
+	deb_reg("R: (0x%02x, 0x%02x)\n", addr, *data);
+fail:
+	return ret;
+}
+
+int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data)
+{
+	u8 buf[] = { addr, data };
+	int ret;
+
+	deb_reg("W: (0x%02x, 0x%02x)\n", addr, data);
+
+	ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0);
+	if (mxl_fail(ret))
+		err("error writing reg: 0x%02x, val: 0x%02x", addr, data);
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
+				   u8 addr, u8 mask, u8 data)
+{
+	int ret;
+	u8 val;
+
+	if (mask != 0xff) {
+		ret = mxl111sf_read_reg(state, addr, &val);
+#if 1
+		/* dont know why this usually errors out on the first try */
+		if (mxl_fail(ret))
+			err("error writing addr: 0x%02x, mask: 0x%02x, "
+			    "data: 0x%02x, retrying...", addr, mask, data);
+
+		ret = mxl111sf_read_reg(state, addr, &val);
+#endif
+		if (mxl_fail(ret))
+			goto fail;
+	}
+	val &= ~mask;
+	val |= data;
+
+	ret = mxl111sf_write_reg(state, addr, val);
+	mxl_fail(ret);
+fail:
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state,
+			       struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
+{
+	int i, ret = 0;
+
+	for (i = 0;  ctrl_reg_info[i].addr |
+		     ctrl_reg_info[i].mask |
+		     ctrl_reg_info[i].data;  i++) {
+
+		ret = mxl111sf_write_reg_mask(state,
+					      ctrl_reg_info[i].addr,
+					      ctrl_reg_info[i].mask,
+					      ctrl_reg_info[i].data);
+		if (mxl_fail(ret)) {
+			err("failed on reg #%d (0x%02x)", i,
+			    ctrl_reg_info[i].addr);
+			break;
+		}
+	}
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int mxl1x1sf_get_chip_info(struct mxl111sf_state *state)
+{
+	int ret;
+	u8 id, ver;
+	char *mxl_chip, *mxl_rev;
+
+	if ((state->chip_id) && (state->chip_ver))
+		return 0;
+
+	ret = mxl111sf_read_reg(state, CHIP_ID_REG, &id);
+	if (mxl_fail(ret))
+		goto fail;
+	state->chip_id = id;
+
+	ret = mxl111sf_read_reg(state, TOP_CHIP_REV_ID_REG, &ver);
+	if (mxl_fail(ret))
+		goto fail;
+	state->chip_ver = ver;
+
+	switch (id) {
+	case 0x61:
+		mxl_chip = "MxL101SF";
+		break;
+	case 0x63:
+		mxl_chip = "MxL111SF";
+		break;
+	default:
+		mxl_chip = "UNKNOWN MxL1X1";
+		break;
+	}
+	switch (ver) {
+	case 0x36:
+		state->chip_rev = MXL111SF_V6;
+		mxl_rev = "v6";
+		break;
+	case 0x08:
+		state->chip_rev = MXL111SF_V8_100;
+		mxl_rev = "v8_100";
+		break;
+	case 0x18:
+		state->chip_rev = MXL111SF_V8_200;
+		mxl_rev = "v8_200";
+		break;
+	default:
+		state->chip_rev = 0;
+		mxl_rev = "UNKNOWN REVISION";
+		break;
+	}
+	info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver);
+fail:
+	return ret;
+}
+
+#define get_chip_info(state)						\
+({									\
+	int ___ret;							\
+	___ret = mxl1x1sf_get_chip_info(state);				\
+	if (mxl_fail(___ret)) {						\
+		mxl_debug("failed to get chip info"			\
+			  " on first probe attempt");			\
+		___ret = mxl1x1sf_get_chip_info(state);			\
+		if (mxl_fail(___ret))					\
+			err("failed to get chip info during probe");	\
+		else							\
+			mxl_debug("probe needed a retry "		\
+				  "in order to succeed.");		\
+	}								\
+	___ret;								\
+})
+
+/* ------------------------------------------------------------------------ */
+#if 0
+static int mxl111sf_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	/* power control depends on which adapter is being woken:
+	 * save this for init, instead, via mxl111sf_adap_fe_init */
+	return 0;
+}
+#endif
+
+static int mxl111sf_adap_fe_init(struct dvb_frontend *fe)
+{
+	struct dvb_usb_device *d = fe_to_d(fe);
+	struct mxl111sf_state *state = fe_to_priv(fe);
+	struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id];
+	int err;
+
+	/* exit if we didnt initialize the driver yet */
+	if (!state->chip_id) {
+		mxl_debug("driver not yet initialized, exit.");
+		goto fail;
+	}
+
+	deb_info("%s()\n", __func__);
+
+	mutex_lock(&state->fe_lock);
+
+	state->alt_mode = adap_state->alt_mode;
+
+	if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+		err("set interface failed");
+
+	err = mxl1x1sf_soft_reset(state);
+	mxl_fail(err);
+	err = mxl111sf_init_tuner_demod(state);
+	mxl_fail(err);
+	err = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+
+	mxl_fail(err);
+	mxl111sf_enable_usb_output(state);
+	mxl_fail(err);
+	mxl1x1sf_top_master_ctrl(state, 1);
+	mxl_fail(err);
+
+	if ((MXL111SF_GPIO_MOD_DVBT != adap_state->gpio_mode) &&
+	    (state->chip_rev > MXL111SF_V6)) {
+		mxl111sf_config_pin_mux_modes(state,
+					      PIN_MUX_TS_SPI_IN_MODE_1);
+		mxl_fail(err);
+	}
+	err = mxl111sf_init_port_expander(state);
+	if (!mxl_fail(err)) {
+		state->gpio_mode = adap_state->gpio_mode;
+		err = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+		mxl_fail(err);
+#if 0
+		err = fe->ops.init(fe);
+#endif
+		msleep(100); /* add short delay after enabling
+			      * the demod before touching it */
+	}
+
+	return (adap_state->fe_init) ? adap_state->fe_init(fe) : 0;
+fail:
+	return -ENODEV;
+}
+
+static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe)
+{
+	struct mxl111sf_state *state = fe_to_priv(fe);
+	struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id];
+	int err;
+
+	/* exit if we didnt initialize the driver yet */
+	if (!state->chip_id) {
+		mxl_debug("driver not yet initialized, exit.");
+		goto fail;
+	}
+
+	deb_info("%s()\n", __func__);
+
+	err = (adap_state->fe_sleep) ? adap_state->fe_sleep(fe) : 0;
+
+	mutex_unlock(&state->fe_lock);
+
+	return err;
+fail:
+	return -ENODEV;
+}
+
+
+static int mxl111sf_ep6_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+	struct mxl111sf_state *state = fe_to_priv(fe);
+	struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id];
+	int ret = 0;
+
+	deb_info("%s(%d)\n", __func__, onoff);
+
+	if (onoff) {
+		ret = mxl111sf_enable_usb_output(state);
+		mxl_fail(ret);
+		ret = mxl111sf_config_mpeg_in(state, 1, 1,
+					      adap_state->ep6_clockphase,
+					      0, 0);
+		mxl_fail(ret);
+#if 0
+	} else {
+		ret = mxl111sf_disable_656_port(state);
+		mxl_fail(ret);
+#endif
+	}
+
+	return ret;
+}
+
+static int mxl111sf_ep5_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+	struct mxl111sf_state *state = fe_to_priv(fe);
+	int ret = 0;
+
+	deb_info("%s(%d)\n", __func__, onoff);
+
+	if (onoff) {
+		ret = mxl111sf_enable_usb_output(state);
+		mxl_fail(ret);
+
+		ret = mxl111sf_init_i2s_port(state, 200);
+		mxl_fail(ret);
+		ret = mxl111sf_config_i2s(state, 0, 15);
+		mxl_fail(ret);
+	} else {
+		ret = mxl111sf_disable_i2s_port(state);
+		mxl_fail(ret);
+	}
+	if (state->chip_rev > MXL111SF_V6)
+		ret = mxl111sf_config_spi(state, onoff);
+	mxl_fail(ret);
+
+	return ret;
+}
+
+static int mxl111sf_ep4_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+	struct mxl111sf_state *state = fe_to_priv(fe);
+	int ret = 0;
+
+	deb_info("%s(%d)\n", __func__, onoff);
+
+	if (onoff) {
+		ret = mxl111sf_enable_usb_output(state);
+		mxl_fail(ret);
+	}
+
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static struct lgdt3305_config hauppauge_lgdt3305_config = {
+	.i2c_addr           = 0xb2 >> 1,
+	.mpeg_mode          = LGDT3305_MPEG_SERIAL,
+	.tpclk_edge         = LGDT3305_TPCLK_RISING_EDGE,
+	.tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
+	.deny_i2c_rptr      = 1,
+	.spectral_inversion = 0,
+	.qam_if_khz         = 6000,
+	.vsb_if_khz         = 6000,
+};
+
+static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct mxl111sf_state *state = d_to_priv(d);
+	struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
+	int ret;
+
+	deb_adv("%s()\n", __func__);
+
+	/* save a pointer to the dvb_usb_device in device state */
+	state->d = d;
+	adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+	state->alt_mode = adap_state->alt_mode;
+
+	if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+		err("set interface failed");
+
+	state->gpio_mode = MXL111SF_GPIO_MOD_ATSC;
+	adap_state->gpio_mode = state->gpio_mode;
+	adap_state->device_mode = MXL_TUNER_MODE;
+	adap_state->ep6_clockphase = 1;
+
+	ret = mxl1x1sf_soft_reset(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_init_tuner_demod(state);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_enable_usb_output(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl1x1sf_top_master_ctrl(state, 1);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_init_port_expander(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+	if (mxl_fail(ret))
+		goto fail;
+
+	adap->fe[fe_id] = dvb_attach(lgdt3305_attach,
+				 &hauppauge_lgdt3305_config,
+				 &d->i2c_adap);
+	if (adap->fe[fe_id]) {
+		state->num_frontends++;
+		adap_state->fe_init = adap->fe[fe_id]->ops.init;
+		adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init;
+		adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep;
+		adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep;
+		return 0;
+	}
+	ret = -EIO;
+fail:
+	return ret;
+}
+
+static struct lg2160_config hauppauge_lg2160_config = {
+	.lg_chip            = LG2160,
+	.i2c_addr           = 0x1c >> 1,
+	.deny_i2c_rptr      = 1,
+	.spectral_inversion = 0,
+	.if_khz             = 6000,
+};
+
+static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct mxl111sf_state *state = d_to_priv(d);
+	struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
+	int ret;
+
+	deb_adv("%s()\n", __func__);
+
+	/* save a pointer to the dvb_usb_device in device state */
+	state->d = d;
+	adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+	state->alt_mode = adap_state->alt_mode;
+
+	if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+		err("set interface failed");
+
+	state->gpio_mode = MXL111SF_GPIO_MOD_MH;
+	adap_state->gpio_mode = state->gpio_mode;
+	adap_state->device_mode = MXL_TUNER_MODE;
+	adap_state->ep6_clockphase = 1;
+
+	ret = mxl1x1sf_soft_reset(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_init_tuner_demod(state);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_enable_usb_output(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl1x1sf_top_master_ctrl(state, 1);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_init_port_expander(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = get_chip_info(state);
+	if (mxl_fail(ret))
+		goto fail;
+
+	adap->fe[fe_id] = dvb_attach(lg2160_attach,
+			      &hauppauge_lg2160_config,
+			      &d->i2c_adap);
+	if (adap->fe[fe_id]) {
+		state->num_frontends++;
+		adap_state->fe_init = adap->fe[fe_id]->ops.init;
+		adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init;
+		adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep;
+		adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep;
+		return 0;
+	}
+	ret = -EIO;
+fail:
+	return ret;
+}
+
+static struct lg2160_config hauppauge_lg2161_1019_config = {
+	.lg_chip            = LG2161_1019,
+	.i2c_addr           = 0x1c >> 1,
+	.deny_i2c_rptr      = 1,
+	.spectral_inversion = 0,
+	.if_khz             = 6000,
+	.output_if          = 2, /* LG2161_OIF_SPI_MAS */
+};
+
+static struct lg2160_config hauppauge_lg2161_1040_config = {
+	.lg_chip            = LG2161_1040,
+	.i2c_addr           = 0x1c >> 1,
+	.deny_i2c_rptr      = 1,
+	.spectral_inversion = 0,
+	.if_khz             = 6000,
+	.output_if          = 4, /* LG2161_OIF_SPI_MAS */
+};
+
+static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct mxl111sf_state *state = d_to_priv(d);
+	struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
+	int ret;
+
+	deb_adv("%s()\n", __func__);
+
+	/* save a pointer to the dvb_usb_device in device state */
+	state->d = d;
+	adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+	state->alt_mode = adap_state->alt_mode;
+
+	if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+		err("set interface failed");
+
+	state->gpio_mode = MXL111SF_GPIO_MOD_MH;
+	adap_state->gpio_mode = state->gpio_mode;
+	adap_state->device_mode = MXL_TUNER_MODE;
+	adap_state->ep6_clockphase = 1;
+
+	ret = mxl1x1sf_soft_reset(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_init_tuner_demod(state);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_enable_usb_output(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl1x1sf_top_master_ctrl(state, 1);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_init_port_expander(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = get_chip_info(state);
+	if (mxl_fail(ret))
+		goto fail;
+
+	adap->fe[fe_id] = dvb_attach(lg2160_attach,
+			      (MXL111SF_V8_200 == state->chip_rev) ?
+			      &hauppauge_lg2161_1040_config :
+			      &hauppauge_lg2161_1019_config,
+			      &d->i2c_adap);
+	if (adap->fe[fe_id]) {
+		state->num_frontends++;
+		adap_state->fe_init = adap->fe[fe_id]->ops.init;
+		adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init;
+		adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep;
+		adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep;
+		return 0;
+	}
+	ret = -EIO;
+fail:
+	return ret;
+}
+
+static struct lg2160_config hauppauge_lg2161_1019_ep6_config = {
+	.lg_chip            = LG2161_1019,
+	.i2c_addr           = 0x1c >> 1,
+	.deny_i2c_rptr      = 1,
+	.spectral_inversion = 0,
+	.if_khz             = 6000,
+	.output_if          = 1, /* LG2161_OIF_SERIAL_TS */
+};
+
+static struct lg2160_config hauppauge_lg2161_1040_ep6_config = {
+	.lg_chip            = LG2161_1040,
+	.i2c_addr           = 0x1c >> 1,
+	.deny_i2c_rptr      = 1,
+	.spectral_inversion = 0,
+	.if_khz             = 6000,
+	.output_if          = 7, /* LG2161_OIF_SERIAL_TS */
+};
+
+static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct mxl111sf_state *state = d_to_priv(d);
+	struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
+	int ret;
+
+	deb_adv("%s()\n", __func__);
+
+	/* save a pointer to the dvb_usb_device in device state */
+	state->d = d;
+	adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+	state->alt_mode = adap_state->alt_mode;
+
+	if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+		err("set interface failed");
+
+	state->gpio_mode = MXL111SF_GPIO_MOD_MH;
+	adap_state->gpio_mode = state->gpio_mode;
+	adap_state->device_mode = MXL_TUNER_MODE;
+	adap_state->ep6_clockphase = 0;
+
+	ret = mxl1x1sf_soft_reset(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_init_tuner_demod(state);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_enable_usb_output(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl1x1sf_top_master_ctrl(state, 1);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_init_port_expander(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = get_chip_info(state);
+	if (mxl_fail(ret))
+		goto fail;
+
+	adap->fe[fe_id] = dvb_attach(lg2160_attach,
+			      (MXL111SF_V8_200 == state->chip_rev) ?
+			      &hauppauge_lg2161_1040_ep6_config :
+			      &hauppauge_lg2161_1019_ep6_config,
+			      &d->i2c_adap);
+	if (adap->fe[fe_id]) {
+		state->num_frontends++;
+		adap_state->fe_init = adap->fe[fe_id]->ops.init;
+		adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init;
+		adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep;
+		adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep;
+		return 0;
+	}
+	ret = -EIO;
+fail:
+	return ret;
+}
+
+static struct mxl111sf_demod_config mxl_demod_config = {
+	.read_reg        = mxl111sf_read_reg,
+	.write_reg       = mxl111sf_write_reg,
+	.program_regs    = mxl111sf_ctrl_program_regs,
+};
+
+static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap, u8 fe_id)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct mxl111sf_state *state = d_to_priv(d);
+	struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
+	int ret;
+
+	deb_adv("%s()\n", __func__);
+
+	/* save a pointer to the dvb_usb_device in device state */
+	state->d = d;
+	adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 1 : 2;
+	state->alt_mode = adap_state->alt_mode;
+
+	if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+		err("set interface failed");
+
+	state->gpio_mode = MXL111SF_GPIO_MOD_DVBT;
+	adap_state->gpio_mode = state->gpio_mode;
+	adap_state->device_mode = MXL_SOC_MODE;
+	adap_state->ep6_clockphase = 1;
+
+	ret = mxl1x1sf_soft_reset(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl111sf_init_tuner_demod(state);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+	if (mxl_fail(ret))
+		goto fail;
+
+	ret = mxl111sf_enable_usb_output(state);
+	if (mxl_fail(ret))
+		goto fail;
+	ret = mxl1x1sf_top_master_ctrl(state, 1);
+	if (mxl_fail(ret))
+		goto fail;
+
+	/* dont care if this fails */
+	mxl111sf_init_port_expander(state);
+
+	adap->fe[fe_id] = dvb_attach(mxl111sf_demod_attach, state,
+			      &mxl_demod_config);
+	if (adap->fe[fe_id]) {
+		state->num_frontends++;
+		adap_state->fe_init = adap->fe[fe_id]->ops.init;
+		adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init;
+		adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep;
+		adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep;
+		return 0;
+	}
+	ret = -EIO;
+fail:
+	return ret;
+}
+
+static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state,
+					int antpath)
+{
+	return mxl111sf_idac_config(state, 1, 1,
+				    (antpath == ANT_PATH_INTERNAL) ?
+				    0x3f : 0x00, 0);
+}
+
+#define DbgAntHunt(x, pwr0, pwr1, pwr2, pwr3) \
+	err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \
+	    __func__, __LINE__, \
+	    (ANT_PATH_EXTERNAL == x) ? "EXTERNAL" : "INTERNAL", \
+	    pwr0, pwr1, pwr2, pwr3)
+
+#define ANT_HUNT_SLEEP 90
+#define ANT_EXT_TWEAK 0
+
+static int mxl111sf_ant_hunt(struct dvb_frontend *fe)
+{
+	struct mxl111sf_state *state = fe_to_priv(fe);
+	int antctrl = dvb_usb_mxl111sf_rfswitch;
+
+	u16 rxPwrA, rxPwr0, rxPwr1, rxPwr2;
+
+	/* FIXME: must force EXTERNAL for QAM - done elsewhere */
+	mxl111sf_set_ant_path(state, antctrl == ANT_PATH_AUTO ?
+			      ANT_PATH_EXTERNAL : antctrl);
+
+	if (antctrl == ANT_PATH_AUTO) {
+#if 0
+		msleep(ANT_HUNT_SLEEP);
+#endif
+		fe->ops.tuner_ops.get_rf_strength(fe, &rxPwrA);
+
+		mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
+		msleep(ANT_HUNT_SLEEP);
+		fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr0);
+
+		mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
+		msleep(ANT_HUNT_SLEEP);
+		fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr1);
+
+		mxl111sf_set_ant_path(state, ANT_PATH_INTERNAL);
+		msleep(ANT_HUNT_SLEEP);
+		fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr2);
+
+		if (rxPwr1+ANT_EXT_TWEAK >= rxPwr2) {
+			/* return with EXTERNAL enabled */
+			mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
+			DbgAntHunt(ANT_PATH_EXTERNAL, rxPwrA,
+				   rxPwr0, rxPwr1, rxPwr2);
+		} else {
+			/* return with INTERNAL enabled */
+			DbgAntHunt(ANT_PATH_INTERNAL, rxPwrA,
+				   rxPwr0, rxPwr1, rxPwr2);
+		}
+	}
+	return 0;
+}
+
+static struct mxl111sf_tuner_config mxl_tuner_config = {
+	.if_freq         = MXL_IF_6_0, /* applies to external IF output, only */
+	.invert_spectrum = 0,
+	.read_reg        = mxl111sf_read_reg,
+	.write_reg       = mxl111sf_write_reg,
+	.program_regs    = mxl111sf_ctrl_program_regs,
+	.top_master_ctrl = mxl1x1sf_top_master_ctrl,
+	.ant_hunt        = mxl111sf_ant_hunt,
+};
+
+static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap)
+{
+	struct mxl111sf_state *state = adap_to_priv(adap);
+	int i;
+
+	deb_adv("%s()\n", __func__);
+
+	for (i = 0; i < state->num_frontends; i++) {
+		if (dvb_attach(mxl111sf_tuner_attach, adap->fe[i], state,
+				&mxl_tuner_config) == NULL)
+			return -EIO;
+		adap->fe[i]->ops.read_signal_strength = adap->fe[i]->ops.tuner_ops.get_rf_strength;
+	}
+
+	return 0;
+}
+
+static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+struct i2c_algorithm mxl111sf_i2c_algo = {
+	.master_xfer   = mxl111sf_i2c_xfer,
+	.functionality = mxl111sf_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+	.algo_control = dummy_algo_control,
+#endif
+};
+
+static int mxl111sf_init(struct dvb_usb_device *d)
+{
+	struct mxl111sf_state *state = d_to_priv(d);
+	int ret;
+	static u8 eeprom[256];
+	struct i2c_client c;
+
+	ret = get_chip_info(state);
+	if (mxl_fail(ret))
+		err("failed to get chip info during probe");
+
+	mutex_init(&state->fe_lock);
+
+	if (state->chip_rev > MXL111SF_V6)
+		mxl111sf_config_pin_mux_modes(state, PIN_MUX_TS_SPI_IN_MODE_1);
+
+	c.adapter = &d->i2c_adap;
+	c.addr = 0xa0 >> 1;
+
+	ret = tveeprom_read(&c, eeprom, sizeof(eeprom));
+	if (mxl_fail(ret))
+		return 0;
+	tveeprom_hauppauge_analog(&c, &state->tv, (0x84 == eeprom[0xa0]) ?
+			eeprom + 0xa0 : eeprom + 0x80);
+#if 0
+	switch (state->tv.model) {
+	case 117001:
+	case 126001:
+	case 138001:
+		break;
+	default:
+		printk(KERN_WARNING "%s: warning: "
+		       "unknown hauppauge model #%d\n",
+		       __func__, state->tv.model);
+	}
+#endif
+	return 0;
+}
+
+static int mxl111sf_frontend_attach_dvbt(struct dvb_usb_adapter *adap)
+{
+	return mxl111sf_attach_demod(adap, 0);
+}
+
+static int mxl111sf_frontend_attach_atsc(struct dvb_usb_adapter *adap)
+{
+	return mxl111sf_lgdt3305_frontend_attach(adap, 0);
+}
+
+static int mxl111sf_frontend_attach_mh(struct dvb_usb_adapter *adap)
+{
+	return mxl111sf_lg2160_frontend_attach(adap, 0);
+}
+
+static int mxl111sf_frontend_attach_atsc_mh(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	deb_info("%s\n", __func__);
+
+	ret = mxl111sf_lgdt3305_frontend_attach(adap, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = mxl111sf_attach_demod(adap, 1);
+	if (ret < 0)
+		return ret;
+
+	ret = mxl111sf_lg2160_frontend_attach(adap, 2);
+	if (ret < 0)
+		return ret;
+
+	return ret;
+}
+
+static int mxl111sf_frontend_attach_mercury(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	deb_info("%s\n", __func__);
+
+	ret = mxl111sf_lgdt3305_frontend_attach(adap, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = mxl111sf_attach_demod(adap, 1);
+	if (ret < 0)
+		return ret;
+
+	ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 2);
+	if (ret < 0)
+		return ret;
+
+	return ret;
+}
+
+static int mxl111sf_frontend_attach_mercury_mh(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	deb_info("%s\n", __func__);
+
+	ret = mxl111sf_attach_demod(adap, 0);
+	if (ret < 0)
+		return ret;
+
+	if (dvb_usb_mxl111sf_spi)
+		ret = mxl111sf_lg2161_frontend_attach(adap, 1);
+	else
+		ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 1);
+
+	return ret;
+}
+
+static void mxl111sf_stream_config_bulk(struct usb_data_stream_properties *stream, u8 endpoint)
+{
+	deb_info("%s: endpoint=%d size=8192\n", __func__, endpoint);
+	stream->type = USB_BULK;
+	stream->count = 5;
+	stream->endpoint = endpoint;
+	stream->u.bulk.buffersize = 8192;
+}
+
+static void mxl111sf_stream_config_isoc(struct usb_data_stream_properties *stream,
+		u8 endpoint, int framesperurb, int framesize)
+{
+	deb_info("%s: endpoint=%d size=%d\n", __func__, endpoint,
+			framesperurb * framesize);
+	stream->type = USB_ISOC;
+	stream->count = 5;
+	stream->endpoint = endpoint;
+	stream->u.isoc.framesperurb = framesperurb;
+	stream->u.isoc.framesize = framesize;
+	stream->u.isoc.interval = 1;
+}
+
+/* DVB USB Driver stuff */
+
+/* dvbt       mxl111sf
+ * bulk       EP4/BULK/5/8192
+ * isoc       EP4/ISOC/5/96/564
+ */
+static int mxl111sf_get_stream_config_dvbt(struct dvb_frontend *fe,
+		u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+	deb_info("%s: fe=%d\n", __func__, fe->id);
+
+	*ts_type = DVB_USB_FE_TS_TYPE_188;
+	if (dvb_usb_mxl111sf_isoc)
+		mxl111sf_stream_config_isoc(stream, 4, 96, 564);
+	else
+		mxl111sf_stream_config_bulk(stream, 4);
+	return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_dvbt = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+	.size_of_priv = sizeof(struct mxl111sf_state),
+
+	.generic_bulk_ctrl_endpoint = 0x02,
+	.generic_bulk_ctrl_endpoint_response = 0x81,
+
+	.i2c_algo          = &mxl111sf_i2c_algo,
+	.frontend_attach   = mxl111sf_frontend_attach_dvbt,
+	.tuner_attach      = mxl111sf_attach_tuner,
+	.init              = mxl111sf_init,
+	.streaming_ctrl    = mxl111sf_ep4_streaming_ctrl,
+	.get_stream_config = mxl111sf_get_stream_config_dvbt,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+		}
+	}
+};
+
+/* atsc       lgdt3305
+ * bulk       EP6/BULK/5/8192
+ * isoc       EP6/ISOC/5/24/3072
+ */
+static int mxl111sf_get_stream_config_atsc(struct dvb_frontend *fe,
+		u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+	deb_info("%s: fe=%d\n", __func__, fe->id);
+
+	*ts_type = DVB_USB_FE_TS_TYPE_188;
+	if (dvb_usb_mxl111sf_isoc)
+		mxl111sf_stream_config_isoc(stream, 6, 24, 3072);
+	else
+		mxl111sf_stream_config_bulk(stream, 6);
+	return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_atsc = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+	.size_of_priv = sizeof(struct mxl111sf_state),
+
+	.generic_bulk_ctrl_endpoint = 0x02,
+	.generic_bulk_ctrl_endpoint_response = 0x81,
+
+	.i2c_algo          = &mxl111sf_i2c_algo,
+	.frontend_attach   = mxl111sf_frontend_attach_atsc,
+	.tuner_attach      = mxl111sf_attach_tuner,
+	.init              = mxl111sf_init,
+	.streaming_ctrl    = mxl111sf_ep6_streaming_ctrl,
+	.get_stream_config = mxl111sf_get_stream_config_atsc,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+		}
+	}
+};
+
+/* mh         lg2160
+ * bulk       EP5/BULK/5/8192/RAW
+ * isoc       EP5/ISOC/5/96/200/RAW
+ */
+static int mxl111sf_get_stream_config_mh(struct dvb_frontend *fe,
+		u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+	deb_info("%s: fe=%d\n", __func__, fe->id);
+
+	*ts_type = DVB_USB_FE_TS_TYPE_RAW;
+	if (dvb_usb_mxl111sf_isoc)
+		mxl111sf_stream_config_isoc(stream, 5, 96, 200);
+	else
+		mxl111sf_stream_config_bulk(stream, 5);
+	return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_mh = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+	.size_of_priv = sizeof(struct mxl111sf_state),
+
+	.generic_bulk_ctrl_endpoint = 0x02,
+	.generic_bulk_ctrl_endpoint_response = 0x81,
+
+	.i2c_algo          = &mxl111sf_i2c_algo,
+	.frontend_attach   = mxl111sf_frontend_attach_mh,
+	.tuner_attach      = mxl111sf_attach_tuner,
+	.init              = mxl111sf_init,
+	.streaming_ctrl    = mxl111sf_ep5_streaming_ctrl,
+	.get_stream_config = mxl111sf_get_stream_config_mh,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+		}
+	}
+};
+
+/* atsc mh    lgdt3305           mxl111sf          lg2160
+ * bulk       EP6/BULK/5/8192    EP4/BULK/5/8192   EP5/BULK/5/8192/RAW
+ * isoc       EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW
+ */
+static int mxl111sf_get_stream_config_atsc_mh(struct dvb_frontend *fe,
+		u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+	deb_info("%s: fe=%d\n", __func__, fe->id);
+
+	if (fe->id == 0) {
+		*ts_type = DVB_USB_FE_TS_TYPE_188;
+		if (dvb_usb_mxl111sf_isoc)
+			mxl111sf_stream_config_isoc(stream, 6, 24, 3072);
+		else
+			mxl111sf_stream_config_bulk(stream, 6);
+	} else if (fe->id == 1) {
+		*ts_type = DVB_USB_FE_TS_TYPE_188;
+		if (dvb_usb_mxl111sf_isoc)
+			mxl111sf_stream_config_isoc(stream, 4, 96, 564);
+		else
+			mxl111sf_stream_config_bulk(stream, 4);
+	} else if (fe->id == 2) {
+		*ts_type = DVB_USB_FE_TS_TYPE_RAW;
+		if (dvb_usb_mxl111sf_isoc)
+			mxl111sf_stream_config_isoc(stream, 5, 96, 200);
+		else
+			mxl111sf_stream_config_bulk(stream, 5);
+	}
+	return 0;
+}
+
+static int mxl111sf_streaming_ctrl_atsc_mh(struct dvb_frontend *fe, int onoff)
+{
+	deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+
+	if (fe->id == 0)
+		return mxl111sf_ep6_streaming_ctrl(fe, onoff);
+	else if (fe->id == 1)
+		return mxl111sf_ep4_streaming_ctrl(fe, onoff);
+	else if (fe->id == 2)
+		return mxl111sf_ep5_streaming_ctrl(fe, onoff);
+	return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_atsc_mh = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+	.size_of_priv = sizeof(struct mxl111sf_state),
+
+	.generic_bulk_ctrl_endpoint = 0x02,
+	.generic_bulk_ctrl_endpoint_response = 0x81,
+
+	.i2c_algo          = &mxl111sf_i2c_algo,
+	.frontend_attach   = mxl111sf_frontend_attach_atsc_mh,
+	.tuner_attach      = mxl111sf_attach_tuner,
+	.init              = mxl111sf_init,
+	.streaming_ctrl    = mxl111sf_streaming_ctrl_atsc_mh,
+	.get_stream_config = mxl111sf_get_stream_config_atsc_mh,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+		}
+	}
+};
+
+/* mercury    lgdt3305           mxl111sf          lg2161
+ * tp bulk    EP6/BULK/5/8192    EP4/BULK/5/8192   EP6/BULK/5/8192/RAW
+ * tp isoc    EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP6/ISOC/5/24/3072/RAW
+ * spi bulk   EP6/BULK/5/8192    EP4/BULK/5/8192   EP5/BULK/5/8192/RAW
+ * spi isoc   EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW
+ */
+static int mxl111sf_get_stream_config_mercury(struct dvb_frontend *fe,
+		u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+	deb_info("%s: fe=%d\n", __func__, fe->id);
+
+	if (fe->id == 0) {
+		*ts_type = DVB_USB_FE_TS_TYPE_188;
+		if (dvb_usb_mxl111sf_isoc)
+			mxl111sf_stream_config_isoc(stream, 6, 24, 3072);
+		else
+			mxl111sf_stream_config_bulk(stream, 6);
+	} else if (fe->id == 1) {
+		*ts_type = DVB_USB_FE_TS_TYPE_188;
+		if (dvb_usb_mxl111sf_isoc)
+			mxl111sf_stream_config_isoc(stream, 4, 96, 564);
+		else
+			mxl111sf_stream_config_bulk(stream, 4);
+	} else if (fe->id == 2 && dvb_usb_mxl111sf_spi) {
+		*ts_type = DVB_USB_FE_TS_TYPE_RAW;
+		if (dvb_usb_mxl111sf_isoc)
+			mxl111sf_stream_config_isoc(stream, 5, 96, 200);
+		else
+			mxl111sf_stream_config_bulk(stream, 5);
+	} else if (fe->id == 2 && !dvb_usb_mxl111sf_spi) {
+		*ts_type = DVB_USB_FE_TS_TYPE_RAW;
+		if (dvb_usb_mxl111sf_isoc)
+			mxl111sf_stream_config_isoc(stream, 6, 24, 3072);
+		else
+			mxl111sf_stream_config_bulk(stream, 6);
+	}
+	return 0;
+}
+
+static int mxl111sf_streaming_ctrl_mercury(struct dvb_frontend *fe, int onoff)
+{
+	deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+
+	if (fe->id == 0)
+		return mxl111sf_ep6_streaming_ctrl(fe, onoff);
+	else if (fe->id == 1)
+		return mxl111sf_ep4_streaming_ctrl(fe, onoff);
+	else if (fe->id == 2 && dvb_usb_mxl111sf_spi)
+		return mxl111sf_ep5_streaming_ctrl(fe, onoff);
+	else if (fe->id == 2 && !dvb_usb_mxl111sf_spi)
+		return mxl111sf_ep6_streaming_ctrl(fe, onoff);
+	return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_mercury = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+	.size_of_priv = sizeof(struct mxl111sf_state),
+
+	.generic_bulk_ctrl_endpoint = 0x02,
+	.generic_bulk_ctrl_endpoint_response = 0x81,
+
+	.i2c_algo          = &mxl111sf_i2c_algo,
+	.frontend_attach   = mxl111sf_frontend_attach_mercury,
+	.tuner_attach      = mxl111sf_attach_tuner,
+	.init              = mxl111sf_init,
+	.streaming_ctrl    = mxl111sf_streaming_ctrl_mercury,
+	.get_stream_config = mxl111sf_get_stream_config_mercury,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+		}
+	}
+};
+
+/* mercury mh mxl111sf          lg2161
+ * tp bulk    EP4/BULK/5/8192   EP6/BULK/5/8192/RAW
+ * tp isoc    EP4/ISOC/5/96/564 EP6/ISOC/5/24/3072/RAW
+ * spi bulk   EP4/BULK/5/8192   EP5/BULK/5/8192/RAW
+ * spi isoc   EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW
+ */
+static int mxl111sf_get_stream_config_mercury_mh(struct dvb_frontend *fe,
+		u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+	deb_info("%s: fe=%d\n", __func__, fe->id);
+
+	if (fe->id == 0) {
+		*ts_type = DVB_USB_FE_TS_TYPE_188;
+		if (dvb_usb_mxl111sf_isoc)
+			mxl111sf_stream_config_isoc(stream, 4, 96, 564);
+		else
+			mxl111sf_stream_config_bulk(stream, 4);
+	} else if (fe->id == 1 && dvb_usb_mxl111sf_spi) {
+		*ts_type = DVB_USB_FE_TS_TYPE_RAW;
+		if (dvb_usb_mxl111sf_isoc)
+			mxl111sf_stream_config_isoc(stream, 5, 96, 200);
+		else
+			mxl111sf_stream_config_bulk(stream, 5);
+	} else if (fe->id == 1 && !dvb_usb_mxl111sf_spi) {
+		*ts_type = DVB_USB_FE_TS_TYPE_RAW;
+		if (dvb_usb_mxl111sf_isoc)
+			mxl111sf_stream_config_isoc(stream, 6, 24, 3072);
+		else
+			mxl111sf_stream_config_bulk(stream, 6);
+	}
+	return 0;
+}
+
+static int mxl111sf_streaming_ctrl_mercury_mh(struct dvb_frontend *fe, int onoff)
+{
+	deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+
+	if (fe->id == 0)
+		return mxl111sf_ep4_streaming_ctrl(fe, onoff);
+	else if (fe->id == 1  && dvb_usb_mxl111sf_spi)
+		return mxl111sf_ep5_streaming_ctrl(fe, onoff);
+	else if (fe->id == 1 && !dvb_usb_mxl111sf_spi)
+		return mxl111sf_ep6_streaming_ctrl(fe, onoff);
+	return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_mercury_mh = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+	.size_of_priv = sizeof(struct mxl111sf_state),
+
+	.generic_bulk_ctrl_endpoint = 0x02,
+	.generic_bulk_ctrl_endpoint_response = 0x81,
+
+	.i2c_algo          = &mxl111sf_i2c_algo,
+	.frontend_attach   = mxl111sf_frontend_attach_mercury_mh,
+	.tuner_attach      = mxl111sf_attach_tuner,
+	.init              = mxl111sf_init,
+	.streaming_ctrl    = mxl111sf_streaming_ctrl_mercury_mh,
+	.get_stream_config = mxl111sf_get_stream_config_mercury_mh,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+		}
+	}
+};
+
+static const struct usb_device_id mxl111sf_id_table[] = {
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc600, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc601, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc602, &mxl111sf_props_mh, "HCW 126xxx", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc603, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc604, &mxl111sf_props_dvbt, "Hauppauge 126xxx DVBT", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc609, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60a, &mxl111sf_props_mh, "HCW 126xxx", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60b, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60c, &mxl111sf_props_dvbt, "Hauppauge 126xxx DVBT", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc653, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc65b, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb700, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb701, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb702, &mxl111sf_props_mh, "HCW 117xxx", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb703, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb704, &mxl111sf_props_dvbt, "Hauppauge 117xxx DVBT", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb753, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb763, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb764, &mxl111sf_props_dvbt, "Hauppauge 117xxx DVBT", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd853, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd854, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd863, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd864, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d3, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d4, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e3, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e4, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8ff, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc612, &mxl111sf_props_mercury_mh, "Hauppauge 126xxx", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc613, &mxl111sf_props_mercury, "Hauppauge WinTV-Aero-M", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61a, &mxl111sf_props_mercury_mh, "Hauppauge 126xxx", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61b, &mxl111sf_props_mercury, "Hauppauge WinTV-Aero-M", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb757, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb767, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, mxl111sf_id_table);
+
+static struct usb_driver mxl111sf_usb_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = mxl111sf_id_table,
+	.probe = dvb_usbv2_probe,
+	.disconnect = dvb_usbv2_disconnect,
+	.suspend = dvb_usbv2_suspend,
+	.resume = dvb_usbv2_resume,
+	.no_dynamic_id = 1,
+	.soft_unbind = 1,
+};
+
+module_usb_driver(mxl111sf_usb_driver);
+
+MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
+MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.h b/drivers/media/usb/dvb-usb-v2/mxl111sf.h
new file mode 100644
index 0000000..9816de8
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com)
+ *
+ *   This program is free software; you can redistribute it and/or modify it
+ *   under the terms of the GNU General Public License as published by the Free
+ *   Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+
+#ifndef _DVB_USB_MXL111SF_H_
+#define _DVB_USB_MXL111SF_H_
+
+#ifdef DVB_USB_LOG_PREFIX
+#undef DVB_USB_LOG_PREFIX
+#endif
+#define DVB_USB_LOG_PREFIX "mxl111sf"
+#include "dvb_usb.h"
+#include <media/tveeprom.h>
+
+#define MXL_EP1_REG_READ     1
+#define MXL_EP2_REG_WRITE    2
+#define MXL_EP3_INTERRUPT    3
+#define MXL_EP4_MPEG2        4
+#define MXL_EP5_I2S          5
+#define MXL_EP6_656          6
+#define MXL_EP6_MPEG2        6
+
+#ifdef USING_ENUM_mxl111sf_current_mode
+enum mxl111sf_current_mode {
+	mxl_mode_dvbt = MXL_EP4_MPEG2,
+	mxl_mode_mh   = MXL_EP5_I2S,
+	mxl_mode_atsc = MXL_EP6_MPEG2,
+};
+#endif
+
+enum mxl111sf_gpio_port_expander {
+	mxl111sf_gpio_hw,
+	mxl111sf_PCA9534,
+};
+
+struct mxl111sf_adap_state {
+	int alt_mode;
+	int gpio_mode;
+	int device_mode;
+	int ep6_clockphase;
+	int (*fe_init)(struct dvb_frontend *);
+	int (*fe_sleep)(struct dvb_frontend *);
+};
+
+struct mxl111sf_state {
+	struct dvb_usb_device *d;
+
+	enum mxl111sf_gpio_port_expander gpio_port_expander;
+	u8 port_expander_addr;
+
+	u8 chip_id;
+	u8 chip_ver;
+#define MXL111SF_V6     1
+#define MXL111SF_V8_100 2
+#define MXL111SF_V8_200 3
+	u8 chip_rev;
+
+#ifdef USING_ENUM_mxl111sf_current_mode
+	enum mxl111sf_current_mode current_mode;
+#endif
+
+#define MXL_TUNER_MODE         0
+#define MXL_SOC_MODE           1
+#define MXL_DEV_MODE_MASK      0x01
+#if 1
+	int device_mode;
+#endif
+	/* use usb alt setting 1 for EP4 ISOC transfer (dvb-t),
+				     EP5 BULK transfer (atsc-mh),
+				     EP6 BULK transfer (atsc/qam),
+	   use usb alt setting 2 for EP4 BULK transfer (dvb-t),
+				     EP5 ISOC transfer (atsc-mh),
+				     EP6 ISOC transfer (atsc/qam),
+	 */
+	int alt_mode;
+	int gpio_mode;
+	struct tveeprom tv;
+
+	struct mutex fe_lock;
+	u8 num_frontends;
+	struct mxl111sf_adap_state adap_state[3];
+};
+
+int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data);
+int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data);
+
+struct mxl111sf_reg_ctrl_info {
+	u8 addr;
+	u8 mask;
+	u8 data;
+};
+
+int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
+			    u8 addr, u8 mask, u8 data);
+int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state,
+			       struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
+
+/* needed for hardware i2c functions in mxl111sf-i2c.c:
+ * mxl111sf_i2c_send_data / mxl111sf_i2c_get_data */
+int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
+		      u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen);
+
+#define mxl_printk(kern, fmt, arg...) \
+	printk(kern "%s: " fmt "\n", __func__, ##arg)
+
+#define mxl_info(fmt, arg...) \
+	mxl_printk(KERN_INFO, fmt, ##arg)
+
+extern int dvb_usb_mxl111sf_debug;
+#define mxl_debug(fmt, arg...) \
+	if (dvb_usb_mxl111sf_debug) \
+		mxl_printk(KERN_DEBUG, fmt, ##arg)
+
+#define MXL_I2C_DBG 0x04
+#define MXL_ADV_DBG 0x10
+#define mxl_debug_adv(fmt, arg...) \
+	if (dvb_usb_mxl111sf_debug & MXL_ADV_DBG) \
+		mxl_printk(KERN_DEBUG, fmt, ##arg)
+
+#define mxl_i2c(fmt, arg...) \
+	if (dvb_usb_mxl111sf_debug & MXL_I2C_DBG) \
+		mxl_printk(KERN_DEBUG, fmt, ##arg)
+
+#define mxl_i2c_adv(fmt, arg...) \
+	if ((dvb_usb_mxl111sf_debug & (MXL_I2C_DBG | MXL_ADV_DBG)) == \
+		(MXL_I2C_DBG | MXL_ADV_DBG)) \
+			mxl_printk(KERN_DEBUG, fmt, ##arg)
+
+/* The following allows the mxl_fail() macro defined below to work
+ * in externel modules, such as mxl111sf-tuner.ko, even though
+ * dvb_usb_mxl111sf_debug is not defined within those modules */
+#if (defined(__MXL111SF_TUNER_H__)) || (defined(__MXL111SF_DEMOD_H__))
+#define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG
+#else
+#define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug
+#endif
+
+#define mxl_fail(ret)							\
+({									\
+	int __ret;							\
+	__ret = (ret < 0);						\
+	if ((__ret) && (MXL_ADV_DEBUG_ENABLED & MXL_ADV_DBG))		\
+		mxl_printk(KERN_ERR, "error %d on line %d",		\
+			   ret, __LINE__);				\
+	__ret;								\
+})
+
+#endif /* _DVB_USB_MXL111SF_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
new file mode 100644
index 0000000..d2b1505
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -0,0 +1,1260 @@
+/*
+ * Realtek RTL28xxU DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@googlemail.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "rtl28xxu.h"
+
+#include "rtl2830.h"
+#include "rtl2832.h"
+
+#include "qt1010.h"
+#include "mt2060.h"
+#include "mxl5005s.h"
+#include "fc0012.h"
+#include "fc0013.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req)
+{
+	int ret;
+	unsigned int pipe;
+	u8 requesttype;
+	u8 *buf;
+
+	buf = kmalloc(req->size, GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	if (req->index & CMD_WR_FLAG) {
+		/* write */
+		memcpy(buf, req->data, req->size);
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+		pipe = usb_sndctrlpipe(d->udev, 0);
+	} else {
+		/* read */
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+		pipe = usb_rcvctrlpipe(d->udev, 0);
+	}
+
+	ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value,
+			req->index, buf, req->size, 1000);
+	if (ret > 0)
+		ret = 0;
+
+	deb_dump(0, requesttype, req->value, req->index, buf, req->size);
+
+	/* read request, copy returned data to return buf */
+	if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
+		memcpy(req->data, buf, req->size);
+
+	kfree(buf);
+
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int rtl28xx_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
+{
+	struct rtl28xxu_req req;
+
+	if (reg < 0x3000)
+		req.index = CMD_USB_WR;
+	else if (reg < 0x4000)
+		req.index = CMD_SYS_WR;
+	else
+		req.index = CMD_IR_WR;
+
+	req.value = reg;
+	req.size = len;
+	req.data = val;
+
+	return rtl28xxu_ctrl_msg(d, &req);
+}
+
+static int rtl2831_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
+{
+	struct rtl28xxu_req req;
+
+	if (reg < 0x3000)
+		req.index = CMD_USB_RD;
+	else if (reg < 0x4000)
+		req.index = CMD_SYS_RD;
+	else
+		req.index = CMD_IR_RD;
+
+	req.value = reg;
+	req.size = len;
+	req.data = val;
+
+	return rtl28xxu_ctrl_msg(d, &req);
+}
+
+static int rtl28xx_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val)
+{
+	return rtl28xx_wr_regs(d, reg, &val, 1);
+}
+
+static int rtl28xx_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
+{
+	return rtl2831_rd_regs(d, reg, val, 1);
+}
+
+/* I2C */
+static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+	int num)
+{
+	int ret;
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct rtl28xxu_priv *priv = d->priv;
+	struct rtl28xxu_req req;
+
+	/*
+	 * It is not known which are real I2C bus xfer limits, but testing
+	 * with RTL2831U + MT2060 gives max RD 24 and max WR 22 bytes.
+	 * TODO: find out RTL2832U lens
+	 */
+
+	/*
+	 * I2C adapter logic looks rather complicated due to fact it handles
+	 * three different access methods. Those methods are;
+	 * 1) integrated demod access
+	 * 2) old I2C access
+	 * 3) new I2C access
+	 *
+	 * Used method is selected in order 1, 2, 3. Method 3 can handle all
+	 * requests but there is two reasons why not use it always;
+	 * 1) It is most expensive, usually two USB messages are needed
+	 * 2) At least RTL2831U does not support it
+	 *
+	 * Method 3 is needed in case of I2C write+read (typical register read)
+	 * where write is more than one byte.
+	 */
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
+		(msg[1].flags & I2C_M_RD)) {
+		if (msg[0].len > 24 || msg[1].len > 24) {
+			/* TODO: check msg[0].len max */
+			ret = -EOPNOTSUPP;
+			goto err_mutex_unlock;
+		} else if (msg[0].addr == 0x10) {
+			/* method 1 - integrated demod */
+			req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
+			req.index = CMD_DEMOD_RD | priv->page;
+			req.size = msg[1].len;
+			req.data = &msg[1].buf[0];
+			ret = rtl28xxu_ctrl_msg(d, &req);
+		} else if (msg[0].len < 2) {
+			/* method 2 - old I2C */
+			req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
+			req.index = CMD_I2C_RD;
+			req.size = msg[1].len;
+			req.data = &msg[1].buf[0];
+			ret = rtl28xxu_ctrl_msg(d, &req);
+		} else {
+			/* method 3 - new I2C */
+			req.value = (msg[0].addr << 1);
+			req.index = CMD_I2C_DA_WR;
+			req.size = msg[0].len;
+			req.data = msg[0].buf;
+			ret = rtl28xxu_ctrl_msg(d, &req);
+			if (ret)
+				goto err_mutex_unlock;
+
+			req.value = (msg[0].addr << 1);
+			req.index = CMD_I2C_DA_RD;
+			req.size = msg[1].len;
+			req.data = msg[1].buf;
+			ret = rtl28xxu_ctrl_msg(d, &req);
+		}
+	} else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
+		if (msg[0].len > 22) {
+			/* TODO: check msg[0].len max */
+			ret = -EOPNOTSUPP;
+			goto err_mutex_unlock;
+		} else if (msg[0].addr == 0x10) {
+			/* method 1 - integrated demod */
+			if (msg[0].buf[0] == 0x00) {
+				/* save demod page for later demod access */
+				priv->page = msg[0].buf[1];
+				ret = 0;
+			} else {
+				req.value = (msg[0].buf[0] << 8) |
+					(msg[0].addr << 1);
+				req.index = CMD_DEMOD_WR | priv->page;
+				req.size = msg[0].len-1;
+				req.data = &msg[0].buf[1];
+				ret = rtl28xxu_ctrl_msg(d, &req);
+			}
+		} else if (msg[0].len < 23) {
+			/* method 2 - old I2C */
+			req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
+			req.index = CMD_I2C_WR;
+			req.size = msg[0].len-1;
+			req.data = &msg[0].buf[1];
+			ret = rtl28xxu_ctrl_msg(d, &req);
+		} else {
+			/* method 3 - new I2C */
+			req.value = (msg[0].addr << 1);
+			req.index = CMD_I2C_DA_WR;
+			req.size = msg[0].len;
+			req.data = msg[0].buf;
+			ret = rtl28xxu_ctrl_msg(d, &req);
+		}
+	} else {
+		ret = -EINVAL;
+	}
+
+err_mutex_unlock:
+	mutex_unlock(&d->i2c_mutex);
+
+	return ret ? ret : num;
+}
+
+static u32 rtl28xxu_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm rtl28xxu_i2c_algo = {
+	.master_xfer   = rtl28xxu_i2c_xfer,
+	.functionality = rtl28xxu_i2c_func,
+};
+
+static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
+	.i2c_addr = 0x10, /* 0x20 */
+	.xtal = 28800000,
+	.ts_mode = 0,
+	.spec_inv = 1,
+	.if_dvbt = 36150000,
+	.vtop = 0x20,
+	.krf = 0x04,
+	.agc_targ_val = 0x2d,
+
+};
+
+static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
+	.i2c_addr = 0x10, /* 0x20 */
+	.xtal = 28800000,
+	.ts_mode = 0,
+	.spec_inv = 1,
+	.if_dvbt = 36125000,
+	.vtop = 0x20,
+	.krf = 0x04,
+	.agc_targ_val = 0x2d,
+};
+
+static struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = {
+	.i2c_addr = 0x10, /* 0x20 */
+	.xtal = 28800000,
+	.ts_mode = 0,
+	.spec_inv = 0,
+	.if_dvbt = 4570000,
+	.vtop = 0x3f,
+	.krf = 0x04,
+	.agc_targ_val = 0x3e,
+};
+
+static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct rtl28xxu_priv *priv = d_to_priv(d);
+	u8 buf[1];
+	struct rtl2830_config *rtl2830_config;
+	/* open RTL2831U/RTL2830 I2C gate */
+	struct rtl28xxu_req req_gate = { 0x0120, 0x0011, 0x0001, "\x08" };
+	/* for MT2060 tuner probe */
+	struct rtl28xxu_req req_mt2060 = { 0x00c0, CMD_I2C_RD, 1, buf };
+	/* for QT1010 tuner probe */
+	struct rtl28xxu_req req_qt1010 = { 0x0fc4, CMD_I2C_RD, 1, buf };
+
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	/*
+	 * RTL2831U GPIOs
+	 * =========================================================
+	 * GPIO0 | tuner#0 | 0 off | 1 on  | MXL5005S (?)
+	 * GPIO2 | LED     | 0 off | 1 on  |
+	 * GPIO4 | tuner#1 | 0 on  | 1 off | MT2060
+	 */
+
+	/* GPIO direction */
+	ret = rtl28xx_wr_reg(d, SYS_GPIO_DIR, 0x0a);
+	if (ret)
+		goto err;
+
+	/* enable as output GPIO0, GPIO2, GPIO4 */
+	ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_EN, 0x15);
+	if (ret)
+		goto err;
+
+	/*
+	 * Probe used tuner. We need to know used tuner before demod attach
+	 * since there is some demod params needed to set according to tuner.
+	 */
+
+	/* demod needs some time to wake up */
+	msleep(20);
+
+	/* open demod I2C gate */
+	ret = rtl28xxu_ctrl_msg(d, &req_gate);
+	if (ret)
+		goto err;
+
+	/* check QT1010 ID(?) register; reg=0f val=2c */
+	ret = rtl28xxu_ctrl_msg(d, &req_qt1010);
+	if (ret == 0 && buf[0] == 0x2c) {
+		priv->tuner = TUNER_RTL2830_QT1010;
+		rtl2830_config = &rtl28xxu_rtl2830_qt1010_config;
+		dev_dbg(&d->udev->dev, "%s: QT1010\n", __func__);
+		goto found;
+	} else {
+		dev_dbg(&d->udev->dev, "%s: QT1010 probe failed=%d - %02x\n",
+				__func__, ret, buf[0]);
+	}
+
+	/* open demod I2C gate */
+	ret = rtl28xxu_ctrl_msg(d, &req_gate);
+	if (ret)
+		goto err;
+
+	/* check MT2060 ID register; reg=00 val=63 */
+	ret = rtl28xxu_ctrl_msg(d, &req_mt2060);
+	if (ret == 0 && buf[0] == 0x63) {
+		priv->tuner = TUNER_RTL2830_MT2060;
+		rtl2830_config = &rtl28xxu_rtl2830_mt2060_config;
+		dev_dbg(&d->udev->dev, "%s: MT2060\n", __func__);
+		goto found;
+	} else {
+		dev_dbg(&d->udev->dev, "%s: MT2060 probe failed=%d - %02x\n",
+				__func__, ret, buf[0]);
+	}
+
+	/* assume MXL5005S */
+	ret = 0;
+	priv->tuner = TUNER_RTL2830_MXL5005S;
+	rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config;
+	dev_dbg(&d->udev->dev, "%s: MXL5005S\n", __func__);
+	goto found;
+
+found:
+	/* attach demodulator */
+	adap->fe[0] = dvb_attach(rtl2830_attach, rtl2830_config,
+		&d->i2c_adap);
+	if (adap->fe[0] == NULL) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	return ret;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
+	.i2c_addr = 0x10, /* 0x20 */
+	.xtal = 28800000,
+	.if_dvbt = 0,
+	.tuner = TUNER_RTL2832_FC0012
+};
+
+static struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = {
+	.i2c_addr = 0x10, /* 0x20 */
+	.xtal = 28800000,
+	.if_dvbt = 0,
+	.tuner = TUNER_RTL2832_FC0013
+};
+
+static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d,
+		int cmd, int arg)
+{
+	int ret;
+	u8 val;
+
+	dev_dbg(&d->udev->dev, "%s: cmd=%d arg=%d\n", __func__, cmd, arg);
+
+	switch (cmd) {
+	case FC_FE_CALLBACK_VHF_ENABLE:
+		/* set output values */
+		ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+		if (ret)
+			goto err;
+
+		if (arg)
+			val &= 0xbf; /* set GPIO6 low */
+		else
+			val |= 0x40; /* set GPIO6 high */
+
+
+		ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+		if (ret)
+			goto err;
+		break;
+	default:
+		ret = -EINVAL;
+		goto err;
+	}
+	return 0;
+
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+
+static int rtl2832u_fc0013_tuner_callback(struct dvb_usb_device *d,
+		int cmd, int arg)
+{
+	/* TODO implement*/
+	return 0;
+}
+
+static int rtl2832u_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
+{
+	struct rtl28xxu_priv *priv = d->priv;
+
+	switch (priv->tuner) {
+	case TUNER_RTL2832_FC0012:
+		return rtl2832u_fc0012_tuner_callback(d, cmd, arg);
+
+	case TUNER_RTL2832_FC0013:
+		return rtl2832u_fc0013_tuner_callback(d, cmd, arg);
+	default:
+		break;
+	}
+
+	return -ENODEV;
+}
+
+static int rtl2832u_frontend_callback(void *adapter_priv, int component,
+				    int cmd, int arg)
+{
+	struct i2c_adapter *adap = adapter_priv;
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+
+	switch (component) {
+	case DVB_FRONTEND_COMPONENT_TUNER:
+		return rtl2832u_tuner_callback(d, cmd, arg);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct rtl28xxu_priv *priv = d_to_priv(d);
+	struct rtl2832_config *rtl2832_config;
+	u8 buf[2], val;
+	/* open RTL2832U/RTL2832 I2C gate */
+	struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"};
+	/* close RTL2832U/RTL2832 I2C gate */
+	struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"};
+	/* for FC0012 tuner probe */
+	struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf};
+	/* for FC0013 tuner probe */
+	struct rtl28xxu_req req_fc0013 = {0x00c6, CMD_I2C_RD, 1, buf};
+	/* for MT2266 tuner probe */
+	struct rtl28xxu_req req_mt2266 = {0x00c0, CMD_I2C_RD, 1, buf};
+	/* for FC2580 tuner probe */
+	struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf};
+	/* for MT2063 tuner probe */
+	struct rtl28xxu_req req_mt2063 = {0x00c0, CMD_I2C_RD, 1, buf};
+	/* for MAX3543 tuner probe */
+	struct rtl28xxu_req req_max3543 = {0x00c0, CMD_I2C_RD, 1, buf};
+	/* for TUA9001 tuner probe */
+	struct rtl28xxu_req req_tua9001 = {0x7ec0, CMD_I2C_RD, 2, buf};
+	/* for MXL5007T tuner probe */
+	struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf};
+	/* for E4000 tuner probe */
+	struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf};
+	/* for TDA18272 tuner probe */
+	struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf};
+
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	ret = rtl28xx_rd_reg(d, SYS_GPIO_DIR, &val);
+	if (ret)
+		goto err;
+
+	val &= 0xbf;
+
+	ret = rtl28xx_wr_reg(d, SYS_GPIO_DIR, val);
+	if (ret)
+		goto err;
+
+	/* enable as output GPIO3 and GPIO6*/
+	ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_EN, &val);
+	if (ret)
+		goto err;
+
+	val |= 0x48;
+
+	ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_EN, val);
+	if (ret)
+		goto err;
+
+	/*
+	 * Probe used tuner. We need to know used tuner before demod attach
+	 * since there is some demod params needed to set according to tuner.
+	 */
+
+	/* open demod I2C gate */
+	ret = rtl28xxu_ctrl_msg(d, &req_gate_open);
+	if (ret)
+		goto err;
+
+	priv->tuner = TUNER_NONE;
+
+	/* check FC0012 ID register; reg=00 val=a1 */
+	ret = rtl28xxu_ctrl_msg(d, &req_fc0012);
+	if (ret == 0 && buf[0] == 0xa1) {
+		priv->tuner = TUNER_RTL2832_FC0012;
+		rtl2832_config = &rtl28xxu_rtl2832_fc0012_config;
+		dev_info(&d->udev->dev, "%s: FC0012 tuner found",
+				KBUILD_MODNAME);
+		goto found;
+	}
+
+	/* check FC0013 ID register; reg=00 val=a3 */
+	ret = rtl28xxu_ctrl_msg(d, &req_fc0013);
+	if (ret == 0 && buf[0] == 0xa3) {
+		priv->tuner = TUNER_RTL2832_FC0013;
+		rtl2832_config = &rtl28xxu_rtl2832_fc0013_config;
+		dev_info(&d->udev->dev, "%s: FC0013 tuner found",
+				KBUILD_MODNAME);
+		goto found;
+	}
+
+	/* check MT2266 ID register; reg=00 val=85 */
+	ret = rtl28xxu_ctrl_msg(d, &req_mt2266);
+	if (ret == 0 && buf[0] == 0x85) {
+		priv->tuner = TUNER_RTL2832_MT2266;
+		/* TODO implement tuner */
+		dev_info(&d->udev->dev, "%s: MT2266 tuner found",
+				KBUILD_MODNAME);
+		goto unsupported;
+	}
+
+	/* check FC2580 ID register; reg=01 val=56 */
+	ret = rtl28xxu_ctrl_msg(d, &req_fc2580);
+	if (ret == 0 && buf[0] == 0x56) {
+		priv->tuner = TUNER_RTL2832_FC2580;
+		/* TODO implement tuner */
+		dev_info(&d->udev->dev, "%s: FC2580 tuner found",
+				KBUILD_MODNAME);
+		goto unsupported;
+	}
+
+	/* check MT2063 ID register; reg=00 val=9e || 9c */
+	ret = rtl28xxu_ctrl_msg(d, &req_mt2063);
+	if (ret == 0 && (buf[0] == 0x9e || buf[0] == 0x9c)) {
+		priv->tuner = TUNER_RTL2832_MT2063;
+		/* TODO implement tuner */
+		dev_info(&d->udev->dev, "%s: MT2063 tuner found",
+				KBUILD_MODNAME);
+		goto unsupported;
+	}
+
+	/* check MAX3543 ID register; reg=00 val=38 */
+	ret = rtl28xxu_ctrl_msg(d, &req_max3543);
+	if (ret == 0 && buf[0] == 0x38) {
+		priv->tuner = TUNER_RTL2832_MAX3543;
+		/* TODO implement tuner */
+		dev_info(&d->udev->dev, "%s: MAX3534 tuner found",
+				KBUILD_MODNAME);
+		goto unsupported;
+	}
+
+	/* check TUA9001 ID register; reg=7e val=2328 */
+	ret = rtl28xxu_ctrl_msg(d, &req_tua9001);
+	if (ret == 0 && buf[0] == 0x23 && buf[1] == 0x28) {
+		priv->tuner = TUNER_RTL2832_TUA9001;
+		/* TODO implement tuner */
+		dev_info(&d->udev->dev, "%s: TUA9001 tuner found",
+				KBUILD_MODNAME);
+		goto unsupported;
+	}
+
+	/* check MXL5007R ID register; reg=d9 val=14 */
+	ret = rtl28xxu_ctrl_msg(d, &req_mxl5007t);
+	if (ret == 0 && buf[0] == 0x14) {
+		priv->tuner = TUNER_RTL2832_MXL5007T;
+		/* TODO implement tuner */
+		dev_info(&d->udev->dev, "%s: MXL5007T tuner found",
+				KBUILD_MODNAME);
+		goto unsupported;
+	}
+
+	/* check E4000 ID register; reg=02 val=40 */
+	ret = rtl28xxu_ctrl_msg(d, &req_e4000);
+	if (ret == 0 && buf[0] == 0x40) {
+		priv->tuner = TUNER_RTL2832_E4000;
+		/* TODO implement tuner */
+		dev_info(&d->udev->dev, "%s: E4000 tuner found",
+				KBUILD_MODNAME);
+		goto unsupported;
+	}
+
+	/* check TDA18272 ID register; reg=00 val=c760  */
+	ret = rtl28xxu_ctrl_msg(d, &req_tda18272);
+	if (ret == 0 && (buf[0] == 0xc7 || buf[1] == 0x60)) {
+		priv->tuner = TUNER_RTL2832_TDA18272;
+		/* TODO implement tuner */
+		dev_info(&d->udev->dev, "%s: TDA18272 tuner found",
+				KBUILD_MODNAME);
+		goto unsupported;
+	}
+
+unsupported:
+	/* close demod I2C gate */
+	ret = rtl28xxu_ctrl_msg(d, &req_gate_close);
+	if (ret)
+		goto err;
+
+	/* tuner not found */
+	dev_dbg(&d->udev->dev, "%s: No compatible tuner found\n", __func__);
+	ret = -ENODEV;
+	return ret;
+
+found:
+	/* close demod I2C gate */
+	ret = rtl28xxu_ctrl_msg(d, &req_gate_close);
+	if (ret)
+		goto err;
+
+	/* attach demodulator */
+	adap->fe[0] = dvb_attach(rtl2832_attach, rtl2832_config,
+		&d->i2c_adap);
+		if (adap->fe[0] == NULL) {
+			ret = -ENODEV;
+			goto err;
+		}
+
+	/* set fe callbacks */
+	adap->fe[0]->callback = rtl2832u_frontend_callback;
+
+	return ret;
+
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static struct qt1010_config rtl28xxu_qt1010_config = {
+	.i2c_address = 0x62, /* 0xc4 */
+};
+
+static struct mt2060_config rtl28xxu_mt2060_config = {
+	.i2c_address = 0x60, /* 0xc0 */
+	.clock_out = 0,
+};
+
+static struct mxl5005s_config rtl28xxu_mxl5005s_config = {
+	.i2c_address     = 0x63, /* 0xc6 */
+	.if_freq         = IF_FREQ_4570000HZ,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_C_H,
+	.rssi_enable     = MXL_RSSI_ENABLE,
+	.cap_select      = MXL_CAP_SEL_ENABLE,
+	.div_out         = MXL_DIV_OUT_4,
+	.clock_out       = MXL_CLOCK_OUT_DISABLE,
+	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+	.top		 = MXL5005S_TOP_25P2,
+	.mod_mode        = MXL_DIGITAL_MODE,
+	.if_mode         = MXL_ZERO_IF,
+	.AgcMasterByte   = 0x00,
+};
+
+static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct rtl28xxu_priv *priv = d_to_priv(d);
+	struct i2c_adapter *rtl2830_tuner_i2c;
+	struct dvb_frontend *fe;
+
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	/* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */
+	rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe[0]);
+
+	switch (priv->tuner) {
+	case TUNER_RTL2830_QT1010:
+		fe = dvb_attach(qt1010_attach, adap->fe[0],
+				rtl2830_tuner_i2c, &rtl28xxu_qt1010_config);
+		break;
+	case TUNER_RTL2830_MT2060:
+		fe = dvb_attach(mt2060_attach, adap->fe[0],
+				rtl2830_tuner_i2c, &rtl28xxu_mt2060_config,
+				1220);
+		break;
+	case TUNER_RTL2830_MXL5005S:
+		fe = dvb_attach(mxl5005s_attach, adap->fe[0],
+				rtl2830_tuner_i2c, &rtl28xxu_mxl5005s_config);
+		break;
+	default:
+		fe = NULL;
+		dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME,
+				priv->tuner);
+	}
+
+	if (fe == NULL) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	return 0;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct rtl28xxu_priv *priv = d_to_priv(d);
+	struct dvb_frontend *fe;
+
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	switch (priv->tuner) {
+	case TUNER_RTL2832_FC0012:
+		fe = dvb_attach(fc0012_attach, adap->fe[0],
+			&d->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ);
+
+		/* since fc0012 includs reading the signal strength delegate
+		 * that to the tuner driver */
+		adap->fe[0]->ops.read_signal_strength =
+				adap->fe[0]->ops.tuner_ops.get_rf_strength;
+		return 0;
+		break;
+	case TUNER_RTL2832_FC0013:
+		fe = dvb_attach(fc0013_attach, adap->fe[0],
+			&d->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ);
+
+		/* fc0013 also supports signal strength reading */
+		adap->fe[0]->ops.read_signal_strength =
+				adap->fe[0]->ops.tuner_ops.get_rf_strength;
+		return 0;
+	default:
+		fe = NULL;
+		dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME,
+				priv->tuner);
+	}
+
+	if (fe == NULL) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	return 0;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int rtl28xxu_init(struct dvb_usb_device *d)
+{
+	int ret;
+	u8 val;
+
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	/* init USB endpoints */
+	ret = rtl28xx_rd_reg(d, USB_SYSCTL_0, &val);
+	if (ret)
+		goto err;
+
+	/* enable DMA and Full Packet Mode*/
+	val |= 0x09;
+	ret = rtl28xx_wr_reg(d, USB_SYSCTL_0, val);
+	if (ret)
+		goto err;
+
+	/* set EPA maximum packet size to 0x0200 */
+	ret = rtl28xx_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4);
+	if (ret)
+		goto err;
+
+	/* change EPA FIFO length */
+	ret = rtl28xx_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int rtl28xxu_streaming_ctrl(struct dvb_frontend *fe , int onoff)
+{
+	int ret;
+	u8 buf[2];
+	struct dvb_usb_device *d = fe_to_d(fe);
+
+	dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
+
+	if (onoff) {
+		buf[0] = 0x00;
+		buf[1] = 0x00;
+	} else {
+		buf[0] = 0x10; /* stall EPA */
+		buf[1] = 0x02; /* reset EPA */
+	}
+
+	ret = rtl28xx_wr_regs(d, USB_EPA_CTL, buf, 2);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	int ret;
+	u8 gpio, sys0;
+
+	dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
+
+	/* demod adc */
+	ret = rtl28xx_rd_reg(d, SYS_SYS0, &sys0);
+	if (ret)
+		goto err;
+
+	/* tuner power, read GPIOs */
+	ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio);
+	if (ret)
+		goto err;
+
+	dev_dbg(&d->udev->dev, "%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__,
+			sys0, gpio);
+
+	if (onoff) {
+		gpio |= 0x01; /* GPIO0 = 1 */
+		gpio &= (~0x10); /* GPIO4 = 0 */
+		gpio |= 0x04; /* GPIO2 = 1, LED on */
+		sys0 = sys0 & 0x0f;
+		sys0 |= 0xe0;
+	} else {
+		gpio &= (~0x01); /* GPIO0 = 0 */
+		gpio |= 0x10; /* GPIO4 = 1 */
+		gpio &= (~0x04); /* GPIO2 = 1, LED off */
+		sys0 = sys0 & (~0xc0);
+	}
+
+	dev_dbg(&d->udev->dev, "%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__,
+			sys0, gpio);
+
+	/* demod adc */
+	ret = rtl28xx_wr_reg(d, SYS_SYS0, sys0);
+	if (ret)
+		goto err;
+
+	/* tuner power, write GPIOs */
+	ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, gpio);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	int ret;
+	u8 val;
+
+	dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
+
+	if (onoff) {
+		/* set output values */
+		ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+		if (ret)
+			goto err;
+
+		val |= 0x08;
+		val &= 0xef;
+
+		ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+		if (ret)
+			goto err;
+
+		/* demod_ctl_1 */
+		ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val);
+		if (ret)
+			goto err;
+
+		val &= 0xef;
+
+		ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val);
+		if (ret)
+			goto err;
+
+		/* demod control */
+		/* PLL enable */
+		ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
+		if (ret)
+			goto err;
+
+		/* bit 7 to 1 */
+		val |= 0x80;
+
+		ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+		if (ret)
+			goto err;
+
+		/* demod HW reset */
+		ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
+		if (ret)
+			goto err;
+		/* bit 5 to 0 */
+		val &= 0xdf;
+
+		ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+		if (ret)
+			goto err;
+
+		ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
+		if (ret)
+			goto err;
+
+		val |= 0x20;
+
+		ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+		if (ret)
+			goto err;
+
+		mdelay(5);
+
+		/*enable ADC_Q and ADC_I */
+		ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
+		if (ret)
+			goto err;
+
+		val |= 0x48;
+
+		ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+		if (ret)
+			goto err;
+
+
+	} else {
+		/* demod_ctl_1 */
+		ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val);
+		if (ret)
+			goto err;
+
+		val |= 0x0c;
+
+		ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val);
+		if (ret)
+			goto err;
+
+		/* set output values */
+		ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+		if (ret)
+				goto err;
+
+		val |= 0x10;
+
+		ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+		if (ret)
+			goto err;
+
+		/* demod control */
+		ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
+		if (ret)
+			goto err;
+
+		val &= 0x37;
+
+		ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+		if (ret)
+			goto err;
+
+	}
+
+	return ret;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+
+static int rtl2831u_rc_query(struct dvb_usb_device *d)
+{
+	int ret, i;
+	struct rtl28xxu_priv *priv = d->priv;
+	u8 buf[5];
+	u32 rc_code;
+	struct rtl28xxu_reg_val rc_nec_tab[] = {
+		{ 0x3033, 0x80 },
+		{ 0x3020, 0x43 },
+		{ 0x3021, 0x16 },
+		{ 0x3022, 0x16 },
+		{ 0x3023, 0x5a },
+		{ 0x3024, 0x2d },
+		{ 0x3025, 0x16 },
+		{ 0x3026, 0x01 },
+		{ 0x3028, 0xb0 },
+		{ 0x3029, 0x04 },
+		{ 0x302c, 0x88 },
+		{ 0x302e, 0x13 },
+		{ 0x3030, 0xdf },
+		{ 0x3031, 0x05 },
+	};
+
+	/* init remote controller */
+	if (!priv->rc_active) {
+		for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) {
+			ret = rtl28xx_wr_reg(d, rc_nec_tab[i].reg,
+					rc_nec_tab[i].val);
+			if (ret)
+				goto err;
+		}
+		priv->rc_active = true;
+	}
+
+	ret = rtl2831_rd_regs(d, SYS_IRRC_RP, buf, 5);
+	if (ret)
+		goto err;
+
+	if (buf[4] & 0x01) {
+		if (buf[2] == (u8) ~buf[3]) {
+			if (buf[0] == (u8) ~buf[1]) {
+				/* NEC standard (16 bit) */
+				rc_code = buf[0] << 8 | buf[2];
+			} else {
+				/* NEC extended (24 bit) */
+				rc_code = buf[0] << 16 |
+						buf[1] << 8 | buf[2];
+			}
+		} else {
+			/* NEC full (32 bit) */
+			rc_code = buf[0] << 24 | buf[1] << 16 |
+					buf[2] << 8 | buf[3];
+		}
+
+		rc_keydown(d->rc_dev, rc_code, 0);
+
+		ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1);
+		if (ret)
+			goto err;
+
+		/* repeated intentionally to avoid extra keypress */
+		ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1);
+		if (ret)
+			goto err;
+	}
+
+	return ret;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int rtl2831u_get_rc_config(struct dvb_usb_device *d,
+		struct dvb_usb_rc *rc)
+{
+	rc->map_name = RC_MAP_EMPTY;
+	rc->allowed_protos = RC_TYPE_NEC;
+	rc->query = rtl2831u_rc_query;
+	rc->interval = 400;
+
+	return 0;
+}
+
+static int rtl2832u_rc_query(struct dvb_usb_device *d)
+{
+	int ret, i;
+	struct rtl28xxu_priv *priv = d->priv;
+	u8 buf[128];
+	int len;
+	struct rtl28xxu_reg_val rc_nec_tab[] = {
+		{ IR_RX_CTRL,             0x20 },
+		{ IR_RX_BUF_CTRL,         0x80 },
+		{ IR_RX_IF,               0xff },
+		{ IR_RX_IE,               0xff },
+		{ IR_MAX_DURATION0,       0xd0 },
+		{ IR_MAX_DURATION1,       0x07 },
+		{ IR_IDLE_LEN0,           0xc0 },
+		{ IR_IDLE_LEN1,           0x00 },
+		{ IR_GLITCH_LEN,          0x03 },
+		{ IR_RX_CLK,              0x09 },
+		{ IR_RX_CFG,              0x1c },
+		{ IR_MAX_H_TOL_LEN,       0x1e },
+		{ IR_MAX_L_TOL_LEN,       0x1e },
+		{ IR_RX_CTRL,             0x80 },
+	};
+
+	/* init remote controller */
+	if (!priv->rc_active) {
+		for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) {
+			ret = rtl28xx_wr_reg(d, rc_nec_tab[i].reg,
+					rc_nec_tab[i].val);
+			if (ret)
+				goto err;
+		}
+		priv->rc_active = true;
+	}
+
+	ret = rtl28xx_rd_reg(d, IR_RX_IF, &buf[0]);
+	if (ret)
+		goto err;
+
+	if (buf[0] != 0x83)
+		goto exit;
+
+	ret = rtl28xx_rd_reg(d, IR_RX_BC, &buf[0]);
+	if (ret)
+		goto err;
+
+	len = buf[0];
+	ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len);
+
+	/* TODO: pass raw IR to Kernel IR decoder */
+
+	ret = rtl28xx_wr_reg(d, IR_RX_IF, 0x03);
+	ret = rtl28xx_wr_reg(d, IR_RX_BUF_CTRL, 0x80);
+	ret = rtl28xx_wr_reg(d, IR_RX_CTRL, 0x80);
+
+exit:
+	return ret;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
+		struct dvb_usb_rc *rc)
+{
+	rc->map_name = RC_MAP_EMPTY;
+	rc->allowed_protos = RC_TYPE_NEC;
+	rc->query = rtl2832u_rc_query;
+	rc->interval = 400;
+
+	return 0;
+}
+
+static const struct dvb_usb_device_properties rtl2831u_props = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+	.size_of_priv = sizeof(struct rtl28xxu_priv),
+
+	.power_ctrl = rtl2831u_power_ctrl,
+	.i2c_algo = &rtl28xxu_i2c_algo,
+	.frontend_attach = rtl2831u_frontend_attach,
+	.tuner_attach = rtl2831u_tuner_attach,
+	.init = rtl28xxu_init,
+	.get_rc_config = rtl2831u_get_rc_config,
+	.streaming_ctrl = rtl28xxu_streaming_ctrl,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.stream = DVB_USB_STREAM_BULK(0x81, 6, 8 * 512),
+		},
+	},
+};
+
+static const struct dvb_usb_device_properties rtl2832u_props = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+	.size_of_priv = sizeof(struct rtl28xxu_priv),
+
+	.power_ctrl = rtl2832u_power_ctrl,
+	.i2c_algo = &rtl28xxu_i2c_algo,
+	.frontend_attach = rtl2832u_frontend_attach,
+	.tuner_attach = rtl2832u_tuner_attach,
+	.init = rtl28xxu_init,
+	.get_rc_config = rtl2832u_get_rc_config,
+	.streaming_ctrl = rtl28xxu_streaming_ctrl,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.stream = DVB_USB_STREAM_BULK(0x81, 6, 8 * 512),
+		},
+	},
+};
+
+static const struct usb_device_id rtl28xxu_id_table[] = {
+	{ DVB_USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U,
+		&rtl2831u_props, "Realtek RTL2831U reference design", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT,
+		&rtl2831u_props, "Freecom USB2.0 DVB-T", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2,
+		&rtl2831u_props, "Freecom USB2.0 DVB-T", NULL) },
+
+	{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1,
+		&rtl2832u_props, "Terratec Cinergy T Stick Black", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_DELOCK_USB2_DVBT,
+		&rtl2832u_props, "G-Tek Electronics Group Lifeview LV5TDLX DVB-T", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK,
+		&rtl2832u_props, "NOXON DAB/DAB+ USB dongle", NULL) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table);
+
+static struct usb_driver rtl28xxu_usb_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = rtl28xxu_id_table,
+	.probe = dvb_usbv2_probe,
+	.disconnect = dvb_usbv2_disconnect,
+	.suspend = dvb_usbv2_suspend,
+	.resume = dvb_usbv2_resume,
+	.reset_resume = dvb_usbv2_reset_resume,
+	.no_dynamic_id = 1,
+	.soft_unbind = 1,
+};
+
+module_usb_driver(rtl28xxu_usb_driver);
+
+MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_AUTHOR("Thomas Mair <thomas.mair86@googlemail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
new file mode 100644
index 0000000..575edbf
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
@@ -0,0 +1,254 @@
+/*
+ * Realtek RTL28xxU DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RTL28XXU_H
+#define RTL28XXU_H
+
+#include "dvb_usb.h"
+
+#define deb_dump(r, t, v, i, b, l) { \
+	char *direction; \
+	if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
+		direction = ">>>"; \
+	else \
+		direction = "<<<"; \
+	dev_dbg(&d->udev->dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x " \
+			"%s [%d bytes]\n",  __func__, t, r, v & 0xff, v >> 8, \
+			i & 0xff, i >> 8, l & 0xff, l >> 8, direction, l); \
+}
+
+/*
+ * USB commands
+ * (usb_control_msg() index parameter)
+ */
+
+#define DEMOD            0x0000
+#define USB              0x0100
+#define SYS              0x0200
+#define I2C              0x0300
+#define I2C_DA           0x0600
+
+#define CMD_WR_FLAG      0x0010
+#define CMD_DEMOD_RD     0x0000
+#define CMD_DEMOD_WR     0x0010
+#define CMD_USB_RD       0x0100
+#define CMD_USB_WR       0x0110
+#define CMD_SYS_RD       0x0200
+#define CMD_IR_RD        0x0201
+#define CMD_IR_WR        0x0211
+#define CMD_SYS_WR       0x0210
+#define CMD_I2C_RD       0x0300
+#define CMD_I2C_WR       0x0310
+#define CMD_I2C_DA_RD    0x0600
+#define CMD_I2C_DA_WR    0x0610
+
+
+struct rtl28xxu_priv {
+	u8 chip_id;
+	u8 tuner;
+	u8 page; /* integrated demod active register page */
+	bool rc_active;
+};
+
+enum rtl28xxu_chip_id {
+	CHIP_ID_NONE,
+	CHIP_ID_RTL2831U,
+	CHIP_ID_RTL2832U,
+};
+
+enum rtl28xxu_tuner {
+	TUNER_NONE,
+
+	TUNER_RTL2830_QT1010,
+	TUNER_RTL2830_MT2060,
+	TUNER_RTL2830_MXL5005S,
+
+	TUNER_RTL2832_MT2266,
+	TUNER_RTL2832_FC2580,
+	TUNER_RTL2832_MT2063,
+	TUNER_RTL2832_MAX3543,
+	TUNER_RTL2832_TUA9001,
+	TUNER_RTL2832_MXL5007T,
+	TUNER_RTL2832_FC0012,
+	TUNER_RTL2832_E4000,
+	TUNER_RTL2832_TDA18272,
+	TUNER_RTL2832_FC0013,
+};
+
+struct rtl28xxu_req {
+	u16 value;
+	u16 index;
+	u16 size;
+	u8 *data;
+};
+
+struct rtl28xxu_reg_val {
+	u16 reg;
+	u8 val;
+};
+
+/*
+ * memory map
+ *
+ * 0x0000 DEMOD : demodulator
+ * 0x2000 USB   : SIE, USB endpoint, debug, DMA
+ * 0x3000 SYS   : system
+ * 0xfc00 RC    : remote controller (not RTL2831U)
+ */
+
+/*
+ * USB registers
+ */
+/* SIE Control Registers */
+#define USB_SYSCTL         0x2000 /* USB system control */
+#define USB_SYSCTL_0       0x2000 /* USB system control */
+#define USB_SYSCTL_1       0x2001 /* USB system control */
+#define USB_SYSCTL_2       0x2002 /* USB system control */
+#define USB_SYSCTL_3       0x2003 /* USB system control */
+#define USB_IRQSTAT        0x2008 /* SIE interrupt status */
+#define USB_IRQEN          0x200C /* SIE interrupt enable */
+#define USB_CTRL           0x2010 /* USB control */
+#define USB_STAT           0x2014 /* USB status */
+#define USB_DEVADDR        0x2018 /* USB device address */
+#define USB_TEST           0x201C /* USB test mode */
+#define USB_FRAME_NUMBER   0x2020 /* frame number */
+#define USB_FIFO_ADDR      0x2028 /* address of SIE FIFO RAM */
+#define USB_FIFO_CMD       0x202A /* SIE FIFO RAM access command */
+#define USB_FIFO_DATA      0x2030 /* SIE FIFO RAM data */
+/* Endpoint Registers */
+#define EP0_SETUPA         0x20F8 /* EP 0 setup packet lower byte */
+#define EP0_SETUPB         0x20FC /* EP 0 setup packet higher byte */
+#define USB_EP0_CFG        0x2104 /* EP 0 configure */
+#define USB_EP0_CTL        0x2108 /* EP 0 control */
+#define USB_EP0_STAT       0x210C /* EP 0 status */
+#define USB_EP0_IRQSTAT    0x2110 /* EP 0 interrupt status */
+#define USB_EP0_IRQEN      0x2114 /* EP 0 interrupt enable */
+#define USB_EP0_MAXPKT     0x2118 /* EP 0 max packet size */
+#define USB_EP0_BC         0x2120 /* EP 0 FIFO byte counter */
+#define USB_EPA_CFG        0x2144 /* EP A configure */
+#define USB_EPA_CFG_0      0x2144 /* EP A configure */
+#define USB_EPA_CFG_1      0x2145 /* EP A configure */
+#define USB_EPA_CFG_2      0x2146 /* EP A configure */
+#define USB_EPA_CFG_3      0x2147 /* EP A configure */
+#define USB_EPA_CTL        0x2148 /* EP A control */
+#define USB_EPA_CTL_0      0x2148 /* EP A control */
+#define USB_EPA_CTL_1      0x2149 /* EP A control */
+#define USB_EPA_CTL_2      0x214A /* EP A control */
+#define USB_EPA_CTL_3      0x214B /* EP A control */
+#define USB_EPA_STAT       0x214C /* EP A status */
+#define USB_EPA_IRQSTAT    0x2150 /* EP A interrupt status */
+#define USB_EPA_IRQEN      0x2154 /* EP A interrupt enable */
+#define USB_EPA_MAXPKT     0x2158 /* EP A max packet size */
+#define USB_EPA_MAXPKT_0   0x2158 /* EP A max packet size */
+#define USB_EPA_MAXPKT_1   0x2159 /* EP A max packet size */
+#define USB_EPA_MAXPKT_2   0x215A /* EP A max packet size */
+#define USB_EPA_MAXPKT_3   0x215B /* EP A max packet size */
+#define USB_EPA_FIFO_CFG   0x2160 /* EP A FIFO configure */
+#define USB_EPA_FIFO_CFG_0 0x2160 /* EP A FIFO configure */
+#define USB_EPA_FIFO_CFG_1 0x2161 /* EP A FIFO configure */
+#define USB_EPA_FIFO_CFG_2 0x2162 /* EP A FIFO configure */
+#define USB_EPA_FIFO_CFG_3 0x2163 /* EP A FIFO configure */
+/* Debug Registers */
+#define USB_PHYTSTDIS      0x2F04 /* PHY test disable */
+#define USB_TOUT_VAL       0x2F08 /* USB time-out time */
+#define USB_VDRCTRL        0x2F10 /* UTMI vendor signal control */
+#define USB_VSTAIN         0x2F14 /* UTMI vendor signal status in */
+#define USB_VLOADM         0x2F18 /* UTMI load vendor signal status in */
+#define USB_VSTAOUT        0x2F1C /* UTMI vendor signal status out */
+#define USB_UTMI_TST       0x2F80 /* UTMI test */
+#define USB_UTMI_STATUS    0x2F84 /* UTMI status */
+#define USB_TSTCTL         0x2F88 /* test control */
+#define USB_TSTCTL2        0x2F8C /* test control 2 */
+#define USB_PID_FORCE      0x2F90 /* force PID */
+#define USB_PKTERR_CNT     0x2F94 /* packet error counter */
+#define USB_RXERR_CNT      0x2F98 /* RX error counter */
+#define USB_MEM_BIST       0x2F9C /* MEM BIST test */
+#define USB_SLBBIST        0x2FA0 /* self-loop-back BIST */
+#define USB_CNTTEST        0x2FA4 /* counter test */
+#define USB_PHYTST         0x2FC0 /* USB PHY test */
+#define USB_DBGIDX         0x2FF0 /* select individual block debug signal */
+#define USB_DBGMUX         0x2FF4 /* debug signal module mux */
+
+/*
+ * SYS registers
+ */
+/* demod control registers */
+#define SYS_SYS0           0x3000 /* include DEMOD_CTL, GPO, GPI, GPOE */
+#define SYS_DEMOD_CTL      0x3000 /* control register for DVB-T demodulator */
+/* GPIO registers */
+#define SYS_GPIO_OUT_VAL   0x3001 /* output value of GPIO */
+#define SYS_GPIO_IN_VAL    0x3002 /* input value of GPIO */
+#define SYS_GPIO_OUT_EN    0x3003 /* output enable of GPIO */
+#define SYS_SYS1           0x3004 /* include GPD, SYSINTE, SYSINTS, GP_CFG0 */
+#define SYS_GPIO_DIR       0x3004 /* direction control for GPIO */
+#define SYS_SYSINTE        0x3005 /* system interrupt enable */
+#define SYS_SYSINTS        0x3006 /* system interrupt status */
+#define SYS_GPIO_CFG0      0x3007 /* PAD configuration for GPIO0-GPIO3 */
+#define SYS_SYS2           0x3008 /* include GP_CFG1 and 3 reserved bytes */
+#define SYS_GPIO_CFG1      0x3008 /* PAD configuration for GPIO4 */
+#define SYS_DEMOD_CTL1     0x300B
+
+/* IrDA registers */
+#define SYS_IRRC_PSR       0x3020 /* IR protocol selection */
+#define SYS_IRRC_PER       0x3024 /* IR protocol extension */
+#define SYS_IRRC_SF        0x3028 /* IR sampling frequency */
+#define SYS_IRRC_DPIR      0x302C /* IR data package interval */
+#define SYS_IRRC_CR        0x3030 /* IR control */
+#define SYS_IRRC_RP        0x3034 /* IR read port */
+#define SYS_IRRC_SR        0x3038 /* IR status */
+/* I2C master registers */
+#define SYS_I2CCR          0x3040 /* I2C clock */
+#define SYS_I2CMCR         0x3044 /* I2C master control */
+#define SYS_I2CMSTR        0x3048 /* I2C master SCL timing */
+#define SYS_I2CMSR         0x304C /* I2C master status */
+#define SYS_I2CMFR         0x3050 /* I2C master FIFO */
+
+/*
+ * IR registers
+ */
+#define IR_RX_BUF          0xFC00
+#define IR_RX_IE           0xFD00
+#define IR_RX_IF           0xFD01
+#define IR_RX_CTRL         0xFD02
+#define IR_RX_CFG          0xFD03
+#define IR_MAX_DURATION0   0xFD04
+#define IR_MAX_DURATION1   0xFD05
+#define IR_IDLE_LEN0       0xFD06
+#define IR_IDLE_LEN1       0xFD07
+#define IR_GLITCH_LEN      0xFD08
+#define IR_RX_BUF_CTRL     0xFD09
+#define IR_RX_BUF_DATA     0xFD0A
+#define IR_RX_BC           0xFD0B
+#define IR_RX_CLK          0xFD0C
+#define IR_RX_C_COUNT_L    0xFD0D
+#define IR_RX_C_COUNT_H    0xFD0E
+#define IR_SUSPEND_CTRL    0xFD10
+#define IR_ERR_TOL_CTRL    0xFD11
+#define IR_UNIT_LEN        0xFD12
+#define IR_ERR_TOL_LEN     0xFD13
+#define IR_MAX_H_TOL_LEN   0xFD14
+#define IR_MAX_L_TOL_LEN   0xFD15
+#define IR_MASK_CTRL       0xFD16
+#define IR_MASK_DATA       0xFD17
+#define IR_RES_MASK_ADDR   0xFD18
+#define IR_RES_MASK_T_LEN  0xFD19
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/usb_urb.c b/drivers/media/usb/dvb-usb-v2/usb_urb.c
new file mode 100644
index 0000000..eaf673a
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/usb_urb.c
@@ -0,0 +1,357 @@
+/* usb-urb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file keeps functions for initializing and handling the
+ * BULK and ISOC USB data transfers in a generic way.
+ * Can be used for DVB-only and also, that's the plan, for
+ * Hybrid USB devices (analog and DVB).
+ */
+#include "dvb_usb_common.h"
+
+/* URB stuff for streaming */
+
+int usb_urb_reconfig(struct usb_data_stream *stream,
+		struct usb_data_stream_properties *props);
+
+static void usb_urb_complete(struct urb *urb)
+{
+	struct usb_data_stream *stream = urb->context;
+	int ptype = usb_pipetype(urb->pipe);
+	int i;
+	u8 *b;
+
+	dev_dbg(&stream->udev->dev, "%s: %s urb completed status=%d " \
+			"length=%d/%d pack_num=%d errors=%d\n", __func__,
+			ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
+			urb->status, urb->actual_length,
+			urb->transfer_buffer_length,
+			urb->number_of_packets, urb->error_count);
+
+	switch (urb->status) {
+	case 0:         /* success */
+	case -ETIMEDOUT:    /* NAK */
+		break;
+	case -ECONNRESET:   /* kill */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	default:        /* error */
+		dev_dbg(&stream->udev->dev, "%s: urb completition failed=%d\n",
+				__func__, urb->status);
+		break;
+	}
+
+	b = (u8 *) urb->transfer_buffer;
+	switch (ptype) {
+	case PIPE_ISOCHRONOUS:
+		for (i = 0; i < urb->number_of_packets; i++) {
+			if (urb->iso_frame_desc[i].status != 0)
+				dev_dbg(&stream->udev->dev, "%s: iso frame " \
+						"descriptor has an error=%d\n",
+						__func__,
+						urb->iso_frame_desc[i].status);
+			else if (urb->iso_frame_desc[i].actual_length > 0)
+				stream->complete(stream,
+					b + urb->iso_frame_desc[i].offset,
+					urb->iso_frame_desc[i].actual_length);
+
+			urb->iso_frame_desc[i].status = 0;
+			urb->iso_frame_desc[i].actual_length = 0;
+		}
+		break;
+	case PIPE_BULK:
+		if (urb->actual_length > 0)
+			stream->complete(stream, b, urb->actual_length);
+		break;
+	default:
+		dev_err(&stream->udev->dev, "%s: unknown endpoint type in " \
+				"completition handler\n", KBUILD_MODNAME);
+		return;
+	}
+	usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+int usb_urb_killv2(struct usb_data_stream *stream)
+{
+	int i;
+	for (i = 0; i < stream->urbs_submitted; i++) {
+		dev_dbg(&stream->udev->dev, "%s: kill urb=%d\n", __func__, i);
+		/* stop the URB */
+		usb_kill_urb(stream->urb_list[i]);
+	}
+	stream->urbs_submitted = 0;
+	return 0;
+}
+
+int usb_urb_submitv2(struct usb_data_stream *stream,
+		struct usb_data_stream_properties *props)
+{
+	int i, ret;
+
+	if (props) {
+		ret = usb_urb_reconfig(stream, props);
+		if (ret < 0)
+			return ret;
+	}
+
+	for (i = 0; i < stream->urbs_initialized; i++) {
+		dev_dbg(&stream->udev->dev, "%s: submit urb=%d\n", __func__, i);
+		ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC);
+		if (ret) {
+			dev_err(&stream->udev->dev, "%s: could not submit " \
+					"urb no. %d - get them all back\n",
+					KBUILD_MODNAME, i);
+			usb_urb_killv2(stream);
+			return ret;
+		}
+		stream->urbs_submitted++;
+	}
+	return 0;
+}
+
+int usb_urb_free_urbs(struct usb_data_stream *stream)
+{
+	int i;
+
+	usb_urb_killv2(stream);
+
+	for (i = stream->urbs_initialized - 1; i >= 0; i--) {
+		if (stream->urb_list[i]) {
+			dev_dbg(&stream->udev->dev, "%s: free urb=%d\n",
+					__func__, i);
+			/* free the URBs */
+			usb_free_urb(stream->urb_list[i]);
+		}
+	}
+	stream->urbs_initialized = 0;
+
+	return 0;
+}
+
+static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream)
+{
+	int i, j;
+
+	/* allocate the URBs */
+	for (i = 0; i < stream->props.count; i++) {
+		dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i);
+		stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
+		if (!stream->urb_list[i]) {
+			dev_dbg(&stream->udev->dev, "%s: failed\n", __func__);
+			for (j = 0; j < i; j++)
+				usb_free_urb(stream->urb_list[j]);
+			return -ENOMEM;
+		}
+		usb_fill_bulk_urb(stream->urb_list[i],
+				stream->udev,
+				usb_rcvbulkpipe(stream->udev,
+						stream->props.endpoint),
+				stream->buf_list[i],
+				stream->props.u.bulk.buffersize,
+				usb_urb_complete, stream);
+
+		stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+		stream->urb_list[i]->transfer_dma = stream->dma_addr[i];
+		stream->urbs_initialized++;
+	}
+	return 0;
+}
+
+static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream)
+{
+	int i, j;
+
+	/* allocate the URBs */
+	for (i = 0; i < stream->props.count; i++) {
+		struct urb *urb;
+		int frame_offset = 0;
+		dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i);
+		stream->urb_list[i] = usb_alloc_urb(
+				stream->props.u.isoc.framesperurb, GFP_ATOMIC);
+		if (!stream->urb_list[i]) {
+			dev_dbg(&stream->udev->dev, "%s: failed\n", __func__);
+			for (j = 0; j < i; j++)
+				usb_free_urb(stream->urb_list[j]);
+			return -ENOMEM;
+		}
+
+		urb = stream->urb_list[i];
+
+		urb->dev = stream->udev;
+		urb->context = stream;
+		urb->complete = usb_urb_complete;
+		urb->pipe = usb_rcvisocpipe(stream->udev,
+				stream->props.endpoint);
+		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+		urb->interval = stream->props.u.isoc.interval;
+		urb->number_of_packets = stream->props.u.isoc.framesperurb;
+		urb->transfer_buffer_length = stream->props.u.isoc.framesize *
+				stream->props.u.isoc.framesperurb;
+		urb->transfer_buffer = stream->buf_list[i];
+		urb->transfer_dma = stream->dma_addr[i];
+
+		for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
+			urb->iso_frame_desc[j].offset = frame_offset;
+			urb->iso_frame_desc[j].length =
+					stream->props.u.isoc.framesize;
+			frame_offset += stream->props.u.isoc.framesize;
+		}
+
+		stream->urbs_initialized++;
+	}
+	return 0;
+}
+
+int usb_free_stream_buffers(struct usb_data_stream *stream)
+{
+	if (stream->state & USB_STATE_URB_BUF) {
+		while (stream->buf_num) {
+			stream->buf_num--;
+			dev_dbg(&stream->udev->dev, "%s: free buf=%d\n",
+				__func__, stream->buf_num);
+			usb_free_coherent(stream->udev, stream->buf_size,
+					  stream->buf_list[stream->buf_num],
+					  stream->dma_addr[stream->buf_num]);
+		}
+	}
+
+	stream->state &= ~USB_STATE_URB_BUF;
+
+	return 0;
+}
+
+int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num,
+		unsigned long size)
+{
+	stream->buf_num = 0;
+	stream->buf_size = size;
+
+	dev_dbg(&stream->udev->dev, "%s: all in all I will use %lu bytes for " \
+			"streaming\n", __func__,  num * size);
+
+	for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
+		stream->buf_list[stream->buf_num] = usb_alloc_coherent(
+				stream->udev, size, GFP_ATOMIC,
+				&stream->dma_addr[stream->buf_num]);
+		if (!stream->buf_list[stream->buf_num]) {
+			dev_dbg(&stream->udev->dev, "%s: alloc buf=%d failed\n",
+					__func__, stream->buf_num);
+			usb_free_stream_buffers(stream);
+			return -ENOMEM;
+		}
+
+		dev_dbg(&stream->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n",
+				__func__, stream->buf_num,
+				stream->buf_list[stream->buf_num],
+				(long long)stream->dma_addr[stream->buf_num]);
+		memset(stream->buf_list[stream->buf_num], 0, size);
+		stream->state |= USB_STATE_URB_BUF;
+	}
+
+	return 0;
+}
+
+int usb_urb_reconfig(struct usb_data_stream *stream,
+		struct usb_data_stream_properties *props)
+{
+	int buf_size;
+
+	if (!props)
+		return 0;
+
+	/* check allocated buffers are large enough for the request */
+	if (props->type == USB_BULK) {
+		buf_size = stream->props.u.bulk.buffersize;
+	} else if (props->type == USB_ISOC) {
+		buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb;
+	} else {
+		dev_err(&stream->udev->dev, "%s: invalid endpoint type=%d\n",
+				KBUILD_MODNAME, props->type);
+		return -EINVAL;
+	}
+
+	if (stream->buf_num < props->count || stream->buf_size < buf_size) {
+		dev_err(&stream->udev->dev, "%s: cannot reconfigure as " \
+				"allocated buffers are too small\n",
+				KBUILD_MODNAME);
+		return -EINVAL;
+	}
+
+	/* check if all fields are same */
+	if (stream->props.type == props->type &&
+			stream->props.count == props->count &&
+			stream->props.endpoint == props->endpoint) {
+		if (props->type == USB_BULK &&
+				props->u.bulk.buffersize ==
+				stream->props.u.bulk.buffersize)
+			return 0;
+		else if (props->type == USB_ISOC &&
+				props->u.isoc.framesperurb ==
+				stream->props.u.isoc.framesperurb &&
+				props->u.isoc.framesize ==
+				stream->props.u.isoc.framesize &&
+				props->u.isoc.interval ==
+				stream->props.u.isoc.interval)
+			return 0;
+	}
+
+	dev_dbg(&stream->udev->dev, "%s: re-alloc urbs\n", __func__);
+
+	usb_urb_free_urbs(stream);
+	memcpy(&stream->props, props, sizeof(*props));
+	if (props->type == USB_BULK)
+		return usb_urb_alloc_bulk_urbs(stream);
+	else if (props->type == USB_ISOC)
+		return usb_urb_alloc_isoc_urbs(stream);
+
+	return 0;
+}
+
+int usb_urb_initv2(struct usb_data_stream *stream,
+		const struct usb_data_stream_properties *props)
+{
+	int ret;
+
+	if (!stream || !props)
+		return -EINVAL;
+
+	memcpy(&stream->props, props, sizeof(*props));
+
+	if (!stream->complete) {
+		dev_err(&stream->udev->dev, "%s: there is no data callback - " \
+				"this doesn't make sense\n", KBUILD_MODNAME);
+		return -EINVAL;
+	}
+
+	switch (stream->props.type) {
+	case USB_BULK:
+		ret = usb_alloc_stream_buffers(stream, stream->props.count,
+				stream->props.u.bulk.buffersize);
+		if (ret < 0)
+			return ret;
+
+		return usb_urb_alloc_bulk_urbs(stream);
+	case USB_ISOC:
+		ret = usb_alloc_stream_buffers(stream, stream->props.count,
+				stream->props.u.isoc.framesize *
+				stream->props.u.isoc.framesperurb);
+		if (ret < 0)
+			return ret;
+
+		return usb_urb_alloc_isoc_urbs(stream);
+	default:
+		dev_err(&stream->udev->dev, "%s: unknown urb-type for data " \
+				"transfer\n", KBUILD_MODNAME);
+		return -EINVAL;
+	}
+}
+
+int usb_urb_exitv2(struct usb_data_stream *stream)
+{
+	usb_urb_free_urbs(stream);
+	usb_free_stream_buffers(stream);
+
+	return 0;
+}
diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig
new file mode 100644
index 0000000..00173ee
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/Kconfig
@@ -0,0 +1,313 @@
+config DVB_USB
+	tristate "Support for various USB DVB devices"
+	depends on DVB_CORE && USB && I2C && RC_CORE
+	help
+	  By enabling this you will be able to choose the various supported
+	  USB1.1 and USB2.0 DVB devices.
+
+	  Almost every USB device needs a firmware, please look into
+	  <file:Documentation/dvb/README.dvb-usb>.
+
+	  For a complete list of supported USB devices see the LinuxTV DVB Wiki:
+	  <http://www.linuxtv.org/wiki/index.php/DVB_USB>
+
+	  Say Y if you own a USB DVB device.
+
+config DVB_USB_DEBUG
+	bool "Enable extended debug support for all DVB-USB devices"
+	depends on DVB_USB
+	help
+	  Say Y if you want to enable debugging. See modinfo dvb-usb (and the
+	  appropriate drivers) for debug levels.
+
+config DVB_USB_A800
+	tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)"
+	depends on DVB_USB
+	select DVB_DIB3000MC
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
+
+config DVB_USB_DIBUSB_MB
+	tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
+	depends on DVB_USB
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select DVB_DIB3000MB
+	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
+	  DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
+
+	  For an up-to-date list of devices supported by this driver, have a look
+	  on the Linux-DVB Wiki at www.linuxtv.org.
+
+	  Say Y if you own such a device and want to use it. You should build it as
+	  a module.
+
+config DVB_USB_DIBUSB_MB_FAULTY
+	bool "Support faulty USB IDs"
+	depends on DVB_USB_DIBUSB_MB
+	help
+	  Support for faulty USB IDs due to an invalid EEPROM on some Artec devices.
+
+config DVB_USB_DIBUSB_MC
+	tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
+	depends on DVB_USB
+	select DVB_DIB3000MC
+	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Support for USB2.0 DVB-T receivers based on reference designs made by
+	  DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
+
+	  For an up-to-date list of devices supported by this driver, have a look
+	  on the Linux-DVB Wiki at www.linuxtv.org.
+
+	  Say Y if you own such a device and want to use it. You should build it as
+	  a module.
+
+config DVB_USB_DIB0700
+	tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)"
+	depends on DVB_USB
+	select DVB_DIB7000P if !DVB_FE_CUSTOMISE
+	select DVB_DIB7000M if !DVB_FE_CUSTOMISE
+	select DVB_DIB8000 if !DVB_FE_CUSTOMISE
+	select DVB_DIB3000MC if !DVB_FE_CUSTOMISE
+	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
+	select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
+	select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
+	select DVB_TUNER_DIB0090 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
+	  USB bridge is also present in devices having the DiB7700 DVB-T-USB
+	  silicon. This chip can be found in devices offered by Hauppauge,
+	  Avermedia and other big and small companies.
+
+	  For an up-to-date list of devices supported by this driver, have a look
+	  on the LinuxTV Wiki at www.linuxtv.org.
+
+	  Say Y if you own such a device and want to use it. You should build it as
+	  a module.
+
+config DVB_USB_UMT_010
+	tristate "HanfTek UMT-010 DVB-T USB2.0 support"
+	depends on DVB_USB
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select DVB_DIB3000MC
+	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+	select DVB_MT352 if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
+
+config DVB_USB_CXUSB
+	tristate "Conexant USB2.0 hybrid reference design support"
+	depends on DVB_USB
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select DVB_CX22702 if !DVB_FE_CUSTOMISE
+	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+	select DVB_MT352 if !DVB_FE_CUSTOMISE
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select DVB_DIB7000P if !DVB_FE_CUSTOMISE
+	select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
+	select DVB_ATBM8830 if !DVB_FE_CUSTOMISE
+	select DVB_LGS8GXX if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_MAX2165 if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to support the Conexant USB2.0 hybrid reference design.
+	  Currently, only DVB and ATSC modes are supported, analog mode
+	  shall be added in the future. Devices that require this module:
+
+	  Medion MD95700 hybrid USB2.0 device.
+	  DViCO FusionHDTV (Bluebird) USB2.0 devices
+
+config DVB_USB_M920X
+	tristate "Uli m920x DVB-T USB2.0 support"
+	depends on DVB_USB
+	select DVB_MT352 if !DVB_FE_CUSTOMISE
+	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
+	  Currently, only devices with a product id of
+	  "DTV USB MINI" (in cold state) are supported.
+	  Firmware required.
+
+config DVB_USB_DIGITV
+	tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
+	depends on DVB_USB
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select DVB_NXT6000 if !DVB_FE_CUSTOMISE
+	select DVB_MT352 if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver.
+
+config DVB_USB_VP7045
+	tristate "TwinhanDTV Alpha/MagicBoxII, DNTV tinyUSB2, Beetle USB2.0 support"
+	depends on DVB_USB
+	help
+	  Say Y here to support the
+
+	    TwinhanDTV Alpha (stick) (VP-7045),
+		TwinhanDTV MagicBox II (VP-7046),
+		DigitalNow TinyUSB 2 DVB-t,
+		DigitalRise USB 2.0 Ter (Beetle) and
+		TYPHOON DVB-T USB DRIVE
+
+	  DVB-T USB2.0 receivers.
+
+config DVB_USB_VP702X
+	tristate "TwinhanDTV StarBox and clones DVB-S USB2.0 support"
+	depends on DVB_USB
+	help
+	  Say Y here to support the
+
+	    TwinhanDTV StarBox,
+		DigitalRise USB Starbox and
+		TYPHOON DVB-S USB 2.0 BOX
+
+	  DVB-S USB2.0 receivers.
+
+config DVB_USB_GP8PSK
+	tristate "GENPIX 8PSK->USB module support"
+	depends on DVB_USB
+	help
+	  Say Y here to support the
+	    GENPIX 8psk module
+
+	  DVB-S USB2.0 receivers.
+
+config DVB_USB_NOVA_T_USB2
+	tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
+	depends on DVB_USB
+	select DVB_DIB3000MC
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
+
+config DVB_USB_TTUSB2
+	tristate "Pinnacle 400e DVB-S USB2.0 support"
+	depends on DVB_USB
+	select DVB_TDA10086 if !DVB_FE_CUSTOMISE
+	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+	select DVB_TDA826X if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The
+	  firmware protocol used by this module is similar to the one used by the
+	  old ttusb-driver - that's why the module is called dvb-usb-ttusb2.
+
+config DVB_USB_DTT200U
+	tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)"
+	depends on DVB_USB
+	help
+	  Say Y here to support the WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver.
+
+	  The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan).
+
+	  The WT-220U and its clones are pen-sized.
+
+config DVB_USB_OPERA1
+	tristate "Opera1 DVB-S USB2.0 receiver"
+	depends on DVB_USB
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support the Opera DVB-S USB2.0 receiver.
+
+config DVB_USB_AF9005
+	tristate "Afatech AF9005 DVB-T USB1.1 support"
+	depends on DVB_USB && EXPERIMENTAL
+	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
+	  and the TerraTec Cinergy T USB XE (Rev.1)
+
+config DVB_USB_AF9005_REMOTE
+	tristate "Afatech AF9005 default remote control support"
+	depends on DVB_USB_AF9005
+	help
+	  Say Y here to support the default remote control decoding for the
+	  Afatech AF9005 based receiver.
+
+config DVB_USB_PCTV452E
+	tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600"
+	depends on DVB_USB
+	select TTPCI_EEPROM
+	select DVB_LNBP22 if !DVB_FE_CUSTOMISE
+	select DVB_STB0899 if !DVB_FE_CUSTOMISE
+	select DVB_STB6100 if !DVB_FE_CUSTOMISE
+	help
+	  Support for external USB adapter designed by Pinnacle,
+	  shipped under the brand name 'PCTV HDTV Pro USB'.
+	  Also supports TT Connect S2-3600/3650 cards.
+	  Say Y if you own such a device and want to use it.
+
+config DVB_USB_DW2102
+	tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support"
+	depends on DVB_USB
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_STV0288 if !DVB_FE_CUSTOMISE
+	select DVB_STB6000 if !DVB_FE_CUSTOMISE
+	select DVB_CX24116 if !DVB_FE_CUSTOMISE
+	select DVB_SI21XX if !DVB_FE_CUSTOMISE
+	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+	select DVB_MT312 if !DVB_FE_CUSTOMISE
+	select DVB_ZL10039 if !DVB_FE_CUSTOMISE
+	select DVB_DS3000 if !DVB_FE_CUSTOMISE
+	select DVB_STB6100 if !DVB_FE_CUSTOMISE
+	select DVB_STV6110 if !DVB_FE_CUSTOMISE
+	select DVB_STV0900 if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support the DvbWorld, TeVii, Prof DVB-S/S2 USB2.0
+	  receivers.
+
+config DVB_USB_CINERGY_T2
+	tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver"
+	depends on DVB_USB
+	help
+	  Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
+
+	  Say Y if you own such a device and want to use it.
+
+config DVB_USB_DTV5100
+	tristate "AME DTV-5100 USB2.0 DVB-T support"
+	depends on DVB_USB
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver.
+
+config DVB_USB_FRIIO
+	tristate "Friio ISDB-T USB2.0 Receiver support"
+	depends on DVB_USB
+	help
+	  Say Y here to support the Japanese DTV receiver Friio.
+
+config DVB_USB_AZ6027
+	tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support"
+	depends on DVB_USB
+	select DVB_STB0899 if !DVB_FE_CUSTOMISE
+	select DVB_STB6100 if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support the AZ6027 device
+
+config DVB_USB_TECHNISAT_USB2
+	tristate "Technisat DVB-S/S2 USB2.0 support"
+	depends on DVB_USB
+	select DVB_STV090x if !DVB_FE_CUSTOMISE
+	select DVB_STV6110x if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support the Technisat USB2 DVB-S/S2 device
diff --git a/drivers/media/usb/dvb-usb/Makefile b/drivers/media/usb/dvb-usb/Makefile
new file mode 100644
index 0000000..acdd1ef
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/Makefile
@@ -0,0 +1,83 @@
+dvb-usb-objs += dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o
+dvb-usb-objs += dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o
+obj-$(CONFIG_DVB_USB) += dvb-usb.o
+
+dvb-usb-vp7045-objs := vp7045.o vp7045-fe.o
+obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o
+
+dvb-usb-vp702x-objs := vp702x.o vp702x-fe.o
+obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o
+
+dvb-usb-gp8psk-objs := gp8psk.o gp8psk-fe.o
+obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o
+
+dvb-usb-dtt200u-objs := dtt200u.o dtt200u-fe.o
+obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o
+
+dvb-usb-dibusb-common-objs := dibusb-common.o
+
+dvb-usb-a800-objs := a800.o
+obj-$(CONFIG_DVB_USB_A800) += dvb-usb-dibusb-common.o dvb-usb-a800.o
+
+dvb-usb-dibusb-mb-objs := dibusb-mb.o
+obj-$(CONFIG_DVB_USB_DIBUSB_MB) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mb.o
+
+dvb-usb-dibusb-mc-objs := dibusb-mc.o
+obj-$(CONFIG_DVB_USB_DIBUSB_MC) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mc.o
+
+dvb-usb-nova-t-usb2-objs := nova-t-usb2.o
+obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2.o
+
+dvb-usb-umt-010-objs := umt-010.o
+obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o
+
+dvb-usb-m920x-objs := m920x.o
+obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o
+
+dvb-usb-digitv-objs := digitv.o
+obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
+
+dvb-usb-cxusb-objs := cxusb.o
+obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o
+
+dvb-usb-ttusb2-objs := ttusb2.o
+obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-ttusb2.o
+
+dvb-usb-dib0700-objs := dib0700_core.o dib0700_devices.o
+obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o
+
+dvb-usb-opera-objs := opera1.o
+obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o
+
+dvb-usb-af9005-objs := af9005.o af9005-fe.o
+obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o
+
+dvb-usb-af9005-remote-objs := af9005-remote.o
+obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
+
+dvb-usb-pctv452e-objs := pctv452e.o
+obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o
+
+dvb-usb-dw2102-objs := dw2102.o
+obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o
+
+dvb-usb-dtv5100-objs := dtv5100.o
+obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o
+
+dvb-usb-cinergyT2-objs := cinergyT2-core.o cinergyT2-fe.o
+obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
+
+dvb-usb-friio-objs := friio.o friio-fe.o
+obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o
+
+dvb-usb-az6027-objs := az6027.o
+obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
+
+dvb-usb-technisat-usb2-objs := technisat-usb2.o
+obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o
+
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-frontends/
+# due to tuner-xc3028
+ccflags-y += -I$(srctree)/drivers/media/tuners
+ccflags-y += -I$(srctree)/drivers/media/pci/ttpci
diff --git a/drivers/media/usb/dvb-usb/a800.c b/drivers/media/usb/dvb-usb/a800.c
new file mode 100644
index 0000000..8d7fef8
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/a800.c
@@ -0,0 +1,191 @@
+/* DVB USB framework compliant Linux driver for the AVerMedia AverTV DVB-T
+ * USB2.0 (A800) DVB-T receiver.
+ *
+ * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * Thanks to
+ *   - AVerMedia who kindly provided information and
+ *   - Glen Harris who suffered from my mistakes during development.
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (rc=1 (or-able))." DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define deb_rc(args...)   dprintk(debug,0x01,args)
+
+static int a800_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	/* do nothing for the AVerMedia */
+	return 0;
+}
+
+/* assure to put cold to 0 for iManufacturer == 1 */
+static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
+	struct dvb_usb_device_description **desc, int *cold)
+{
+	*cold = udev->descriptor.iManufacturer != 1;
+	return 0;
+}
+
+static struct rc_map_table rc_map_a800_table[] = {
+	{ 0x0201, KEY_MODE },      /* SOURCE */
+	{ 0x0200, KEY_POWER2 },      /* POWER */
+	{ 0x0205, KEY_1 },           /* 1 */
+	{ 0x0206, KEY_2 },           /* 2 */
+	{ 0x0207, KEY_3 },           /* 3 */
+	{ 0x0209, KEY_4 },           /* 4 */
+	{ 0x020a, KEY_5 },           /* 5 */
+	{ 0x020b, KEY_6 },           /* 6 */
+	{ 0x020d, KEY_7 },           /* 7 */
+	{ 0x020e, KEY_8 },           /* 8 */
+	{ 0x020f, KEY_9 },           /* 9 */
+	{ 0x0212, KEY_LEFT },        /* L / DISPLAY */
+	{ 0x0211, KEY_0 },           /* 0 */
+	{ 0x0213, KEY_RIGHT },       /* R / CH RTN */
+	{ 0x0217, KEY_CAMERA },      /* SNAP SHOT */
+	{ 0x0210, KEY_LAST },        /* 16-CH PREV */
+	{ 0x021e, KEY_VOLUMEDOWN },  /* VOL DOWN */
+	{ 0x020c, KEY_ZOOM },        /* FULL SCREEN */
+	{ 0x021f, KEY_VOLUMEUP },    /* VOL UP */
+	{ 0x0214, KEY_MUTE },        /* MUTE */
+	{ 0x0208, KEY_AUDIO },       /* AUDIO */
+	{ 0x0219, KEY_RECORD },      /* RECORD */
+	{ 0x0218, KEY_PLAY },        /* PLAY */
+	{ 0x021b, KEY_STOP },        /* STOP */
+	{ 0x021a, KEY_PLAYPAUSE },   /* TIMESHIFT / PAUSE */
+	{ 0x021d, KEY_BACK },        /* << / RED */
+	{ 0x021c, KEY_FORWARD },     /* >> / YELLOW */
+	{ 0x0203, KEY_TEXT },        /* TELETEXT */
+	{ 0x0204, KEY_EPG },         /* EPG */
+	{ 0x0215, KEY_MENU },        /* MENU */
+
+	{ 0x0303, KEY_CHANNELUP },   /* CH UP */
+	{ 0x0302, KEY_CHANNELDOWN }, /* CH DOWN */
+	{ 0x0301, KEY_FIRST },       /* |<< / GREEN */
+	{ 0x0300, KEY_LAST },        /* >>| / BLUE */
+
+};
+
+static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	int ret;
+	u8 *key = kmalloc(5, GFP_KERNEL);
+	if (!key)
+		return -ENOMEM;
+
+	if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0),
+				0x04, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, key, 5,
+				2000) != 5) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* call the universal NEC remote processor, to find out the key's state and event */
+	dvb_usb_nec_rc_key_to_event(d,key,event,state);
+	if (key[0] != 0)
+		deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
+	ret = 0;
+out:
+	kfree(key);
+	return ret;
+}
+
+/* USB Driver stuff */
+static struct dvb_usb_device_properties a800_properties;
+
+static int a800_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	return dvb_usb_device_init(intf, &a800_properties,
+				   THIS_MODULE, NULL, adapter_nr);
+}
+
+/* do not change the order of the ID table */
+static struct usb_device_id a800_table [] = {
+/* 00 */	{ USB_DEVICE(USB_VID_AVERMEDIA,     USB_PID_AVERMEDIA_DVBT_USB2_COLD) },
+/* 01 */	{ USB_DEVICE(USB_VID_AVERMEDIA,     USB_PID_AVERMEDIA_DVBT_USB2_WARM) },
+			{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, a800_table);
+
+static struct dvb_usb_device_properties a800_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-avertv-a800-02.fw",
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+			.pid_filter_count = 32,
+			.streaming_ctrl   = dibusb2_0_streaming_ctrl,
+			.pid_filter       = dibusb_pid_filter,
+			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+
+			.frontend_attach  = dibusb_dib3000mc_frontend_attach,
+			.tuner_attach     = dibusb_dib3000mc_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+					.stream = {
+						.type = USB_BULK,
+				.count = 7,
+				.endpoint = 0x06,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+			.size_of_priv     = sizeof(struct dibusb_state),
+		},
+	},
+
+	.power_ctrl       = a800_power_ctrl,
+	.identify_state   = a800_identify_state,
+
+	.rc.legacy = {
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_map_table     = rc_map_a800_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_a800_table),
+		.rc_query         = a800_rc_query,
+	},
+
+	.i2c_algo         = &dibusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+	.num_device_descs = 1,
+	.devices = {
+		{   "AVerMedia AverTV DVB-T USB 2.0 (A800)",
+			{ &a800_table[0], NULL },
+			{ &a800_table[1], NULL },
+		},
+	}
+};
+
+static struct usb_driver a800_driver = {
+	.name		= "dvb_usb_a800",
+	.probe		= a800_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table	= a800_table,
+};
+
+module_usb_driver(a800_driver);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("AVerMedia AverTV DVB-T USB 2.0 (A800)");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/af9005-fe.c b/drivers/media/usb/dvb-usb/af9005-fe.c
new file mode 100644
index 0000000..740f3f4
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/af9005-fe.c
@@ -0,0 +1,1487 @@
+/* Frontend part of the Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "af9005.h"
+#include "af9005-script.h"
+#include "mt2060.h"
+#include "qt1010.h"
+#include <asm/div64.h>
+
+struct af9005_fe_state {
+	struct dvb_usb_device *d;
+	fe_status_t stat;
+
+	/* retraining parameters */
+	u32 original_fcw;
+	u16 original_rf_top;
+	u16 original_if_top;
+	u16 original_if_min;
+	u16 original_aci0_if_top;
+	u16 original_aci1_if_top;
+	u16 original_aci0_if_min;
+	u8 original_if_unplug_th;
+	u8 original_rf_unplug_th;
+	u8 original_dtop_if_unplug_th;
+	u8 original_dtop_rf_unplug_th;
+
+	/* statistics */
+	u32 pre_vit_error_count;
+	u32 pre_vit_bit_count;
+	u32 ber;
+	u32 post_vit_error_count;
+	u32 post_vit_bit_count;
+	u32 unc;
+	u16 abort_count;
+
+	int opened;
+	int strong;
+	unsigned long next_status_check;
+	struct dvb_frontend frontend;
+};
+
+static int af9005_write_word_agc(struct dvb_usb_device *d, u16 reghi,
+				 u16 reglo, u8 pos, u8 len, u16 value)
+{
+	int ret;
+
+	if ((ret = af9005_write_ofdm_register(d, reglo, (u8) (value & 0xff))))
+		return ret;
+	return af9005_write_register_bits(d, reghi, pos, len,
+					  (u8) ((value & 0x300) >> 8));
+}
+
+static int af9005_read_word_agc(struct dvb_usb_device *d, u16 reghi,
+				u16 reglo, u8 pos, u8 len, u16 * value)
+{
+	int ret;
+	u8 temp0, temp1;
+
+	if ((ret = af9005_read_ofdm_register(d, reglo, &temp0)))
+		return ret;
+	if ((ret = af9005_read_ofdm_register(d, reghi, &temp1)))
+		return ret;
+	switch (pos) {
+	case 0:
+		*value = ((u16) (temp1 & 0x03) << 8) + (u16) temp0;
+		break;
+	case 2:
+		*value = ((u16) (temp1 & 0x0C) << 6) + (u16) temp0;
+		break;
+	case 4:
+		*value = ((u16) (temp1 & 0x30) << 4) + (u16) temp0;
+		break;
+	case 6:
+		*value = ((u16) (temp1 & 0xC0) << 2) + (u16) temp0;
+		break;
+	default:
+		err("invalid pos in read word agc");
+		return -EINVAL;
+	}
+	return 0;
+
+}
+
+static int af9005_is_fecmon_available(struct dvb_frontend *fe, int *available)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	int ret;
+	u8 temp;
+
+	*available = false;
+
+	ret = af9005_read_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en,
+					fec_vtb_rsd_mon_en_pos,
+					fec_vtb_rsd_mon_en_len, &temp);
+	if (ret)
+		return ret;
+	if (temp & 1) {
+		ret =
+		    af9005_read_register_bits(state->d,
+					      xd_p_reg_ofsm_read_rbc_en,
+					      reg_ofsm_read_rbc_en_pos,
+					      reg_ofsm_read_rbc_en_len, &temp);
+		if (ret)
+			return ret;
+		if ((temp & 1) == 0)
+			*available = true;
+
+	}
+	return 0;
+}
+
+static int af9005_get_post_vit_err_cw_count(struct dvb_frontend *fe,
+					    u32 * post_err_count,
+					    u32 * post_cw_count,
+					    u16 * abort_count)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	int ret;
+	u32 err_count;
+	u32 cw_count;
+	u8 temp, temp0, temp1, temp2;
+	u16 loc_abort_count;
+
+	*post_err_count = 0;
+	*post_cw_count = 0;
+
+	/* check if error bit count is ready */
+	ret =
+	    af9005_read_register_bits(state->d, xd_r_fec_rsd_ber_rdy,
+				      fec_rsd_ber_rdy_pos, fec_rsd_ber_rdy_len,
+				      &temp);
+	if (ret)
+		return ret;
+	if (!temp) {
+		deb_info("rsd counter not ready\n");
+		return 100;
+	}
+	/* get abort count */
+	ret =
+	    af9005_read_ofdm_register(state->d,
+				      xd_r_fec_rsd_abort_packet_cnt_7_0,
+				      &temp0);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_read_ofdm_register(state->d,
+				      xd_r_fec_rsd_abort_packet_cnt_15_8,
+				      &temp1);
+	if (ret)
+		return ret;
+	loc_abort_count = ((u16) temp1 << 8) + temp0;
+
+	/* get error count */
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_7_0,
+				      &temp0);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_15_8,
+				      &temp1);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_23_16,
+				      &temp2);
+	if (ret)
+		return ret;
+	err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0;
+	*post_err_count = err_count - (u32) loc_abort_count *8 * 8;
+
+	/* get RSD packet number */
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0,
+				      &temp0);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8,
+				      &temp1);
+	if (ret)
+		return ret;
+	cw_count = ((u32) temp1 << 8) + temp0;
+	if (cw_count == 0) {
+		err("wrong RSD packet count");
+		return -EIO;
+	}
+	deb_info("POST abort count %d err count %d rsd packets %d\n",
+		 loc_abort_count, err_count, cw_count);
+	*post_cw_count = cw_count - (u32) loc_abort_count;
+	*abort_count = loc_abort_count;
+	return 0;
+
+}
+
+static int af9005_get_post_vit_ber(struct dvb_frontend *fe,
+				   u32 * post_err_count, u32 * post_cw_count,
+				   u16 * abort_count)
+{
+	u32 loc_cw_count = 0, loc_err_count;
+	u16 loc_abort_count = 0;
+	int ret;
+
+	ret =
+	    af9005_get_post_vit_err_cw_count(fe, &loc_err_count, &loc_cw_count,
+					     &loc_abort_count);
+	if (ret)
+		return ret;
+	*post_err_count = loc_err_count;
+	*post_cw_count = loc_cw_count * 204 * 8;
+	*abort_count = loc_abort_count;
+
+	return 0;
+}
+
+static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe,
+					    u32 * pre_err_count,
+					    u32 * pre_bit_count)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	u8 temp, temp0, temp1, temp2;
+	u32 super_frame_count, x, bits;
+	int ret;
+
+	ret =
+	    af9005_read_register_bits(state->d, xd_r_fec_vtb_ber_rdy,
+				      fec_vtb_ber_rdy_pos, fec_vtb_ber_rdy_len,
+				      &temp);
+	if (ret)
+		return ret;
+	if (!temp) {
+		deb_info("viterbi counter not ready\n");
+		return 101;	/* ERR_APO_VTB_COUNTER_NOT_READY; */
+	}
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_7_0,
+				      &temp0);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_15_8,
+				      &temp1);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_23_16,
+				      &temp2);
+	if (ret)
+		return ret;
+	*pre_err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0;
+
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0,
+				      &temp0);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8,
+				      &temp1);
+	if (ret)
+		return ret;
+	super_frame_count = ((u32) temp1 << 8) + temp0;
+	if (super_frame_count == 0) {
+		deb_info("super frame count 0\n");
+		return 102;
+	}
+
+	/* read fft mode */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod,
+				      reg_tpsd_txmod_pos, reg_tpsd_txmod_len,
+				      &temp);
+	if (ret)
+		return ret;
+	if (temp == 0) {
+		/* 2K */
+		x = 1512;
+	} else if (temp == 1) {
+		/* 8k */
+		x = 6048;
+	} else {
+		err("Invalid fft mode");
+		return -EINVAL;
+	}
+
+	/* read modulation mode */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
+				      reg_tpsd_const_pos, reg_tpsd_const_len,
+				      &temp);
+	if (ret)
+		return ret;
+	switch (temp) {
+	case 0:		/* QPSK */
+		bits = 2;
+		break;
+	case 1:		/* QAM_16 */
+		bits = 4;
+		break;
+	case 2:		/* QAM_64 */
+		bits = 6;
+		break;
+	default:
+		err("invalid modulation mode");
+		return -EINVAL;
+	}
+	*pre_bit_count = super_frame_count * 68 * 4 * x * bits;
+	deb_info("PRE err count %d frame count %d bit count %d\n",
+		 *pre_err_count, super_frame_count, *pre_bit_count);
+	return 0;
+}
+
+static int af9005_reset_pre_viterbi(struct dvb_frontend *fe)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	int ret;
+
+	/* set super frame count to 1 */
+	ret =
+	    af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0,
+				       1 & 0xff);
+	if (ret)
+		return ret;
+	ret = af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8,
+					 1 >> 8);
+	if (ret)
+		return ret;
+	/* reset pre viterbi error count */
+	ret =
+	    af9005_write_register_bits(state->d, xd_p_fec_vtb_ber_rst,
+				       fec_vtb_ber_rst_pos, fec_vtb_ber_rst_len,
+				       1);
+
+	return ret;
+}
+
+static int af9005_reset_post_viterbi(struct dvb_frontend *fe)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	int ret;
+
+	/* set packet unit */
+	ret =
+	    af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0,
+				       10000 & 0xff);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8,
+				       10000 >> 8);
+	if (ret)
+		return ret;
+	/* reset post viterbi error count */
+	ret =
+	    af9005_write_register_bits(state->d, xd_p_fec_rsd_ber_rst,
+				       fec_rsd_ber_rst_pos, fec_rsd_ber_rst_len,
+				       1);
+
+	return ret;
+}
+
+static int af9005_get_statistic(struct dvb_frontend *fe)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	int ret, fecavailable;
+	u64 numerator, denominator;
+
+	deb_info("GET STATISTIC\n");
+	ret = af9005_is_fecmon_available(fe, &fecavailable);
+	if (ret)
+		return ret;
+	if (!fecavailable) {
+		deb_info("fecmon not available\n");
+		return 0;
+	}
+
+	ret = af9005_get_pre_vit_err_bit_count(fe, &state->pre_vit_error_count,
+					       &state->pre_vit_bit_count);
+	if (ret == 0) {
+		af9005_reset_pre_viterbi(fe);
+		if (state->pre_vit_bit_count > 0) {
+			/* according to v 0.0.4 of the dvb api ber should be a multiple
+			   of 10E-9 so we have to multiply the error count by
+			   10E9=1000000000 */
+			numerator =
+			    (u64) state->pre_vit_error_count * (u64) 1000000000;
+			denominator = (u64) state->pre_vit_bit_count;
+			state->ber = do_div(numerator, denominator);
+		} else {
+			state->ber = 0xffffffff;
+		}
+	}
+
+	ret = af9005_get_post_vit_ber(fe, &state->post_vit_error_count,
+				      &state->post_vit_bit_count,
+				      &state->abort_count);
+	if (ret == 0) {
+		ret = af9005_reset_post_viterbi(fe);
+		state->unc += state->abort_count;
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+static int af9005_fe_refresh_state(struct dvb_frontend *fe)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	if (time_after(jiffies, state->next_status_check)) {
+		deb_info("REFRESH STATE\n");
+
+		/* statistics */
+		if (af9005_get_statistic(fe))
+			err("get_statistic_failed");
+		state->next_status_check = jiffies + 250 * HZ / 1000;
+	}
+	return 0;
+}
+
+static int af9005_fe_read_status(struct dvb_frontend *fe, fe_status_t * stat)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	u8 temp;
+	int ret;
+
+	if (fe->ops.tuner_ops.release == NULL)
+		return -ENODEV;
+
+	*stat = 0;
+	ret = af9005_read_register_bits(state->d, xd_p_agc_lock,
+					agc_lock_pos, agc_lock_len, &temp);
+	if (ret)
+		return ret;
+	if (temp)
+		*stat |= FE_HAS_SIGNAL;
+
+	ret = af9005_read_register_bits(state->d, xd_p_fd_tpsd_lock,
+					fd_tpsd_lock_pos, fd_tpsd_lock_len,
+					&temp);
+	if (ret)
+		return ret;
+	if (temp)
+		*stat |= FE_HAS_CARRIER;
+
+	ret = af9005_read_register_bits(state->d,
+					xd_r_mp2if_sync_byte_locked,
+					mp2if_sync_byte_locked_pos,
+					mp2if_sync_byte_locked_pos, &temp);
+	if (ret)
+		return ret;
+	if (temp)
+		*stat |= FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_LOCK;
+	if (state->opened)
+		af9005_led_control(state->d, *stat & FE_HAS_LOCK);
+
+	ret =
+	    af9005_read_register_bits(state->d, xd_p_reg_strong_sginal_detected,
+				      reg_strong_sginal_detected_pos,
+				      reg_strong_sginal_detected_len, &temp);
+	if (ret)
+		return ret;
+	if (temp != state->strong) {
+		deb_info("adjust for strong signal %d\n", temp);
+			state->strong = temp;
+	}
+	return 0;
+}
+
+static int af9005_fe_read_ber(struct dvb_frontend *fe, u32 * ber)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	if (fe->ops.tuner_ops.release  == NULL)
+		return -ENODEV;
+	af9005_fe_refresh_state(fe);
+	*ber = state->ber;
+	return 0;
+}
+
+static int af9005_fe_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	if (fe->ops.tuner_ops.release == NULL)
+		return -ENODEV;
+	af9005_fe_refresh_state(fe);
+	*unc = state->unc;
+	return 0;
+}
+
+static int af9005_fe_read_signal_strength(struct dvb_frontend *fe,
+					  u16 * strength)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	int ret;
+	u8 if_gain, rf_gain;
+
+	if (fe->ops.tuner_ops.release == NULL)
+		return -ENODEV;
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_r_reg_aagc_rf_gain,
+				      &rf_gain);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_r_reg_aagc_if_gain,
+				      &if_gain);
+	if (ret)
+		return ret;
+	/* this value has no real meaning, but i don't have the tables that relate
+	   the rf and if gain with the dbm, so I just scale the value */
+	*strength = (512 - rf_gain - if_gain) << 7;
+	return 0;
+}
+
+static int af9005_fe_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+	/* the snr can be derived from the ber and the modulation
+	   but I don't think this kind of complex calculations belong
+	   in the driver. I may be wrong.... */
+	return -ENOSYS;
+}
+
+static int af9005_fe_program_cfoe(struct dvb_usb_device *d, u32 bw)
+{
+	u8 temp0, temp1, temp2, temp3, buf[4];
+	int ret;
+	u32 NS_coeff1_2048Nu;
+	u32 NS_coeff1_8191Nu;
+	u32 NS_coeff1_8192Nu;
+	u32 NS_coeff1_8193Nu;
+	u32 NS_coeff2_2k;
+	u32 NS_coeff2_8k;
+
+	switch (bw) {
+	case 6000000:
+		NS_coeff1_2048Nu = 0x2ADB6DC;
+		NS_coeff1_8191Nu = 0xAB7313;
+		NS_coeff1_8192Nu = 0xAB6DB7;
+		NS_coeff1_8193Nu = 0xAB685C;
+		NS_coeff2_2k = 0x156DB6E;
+		NS_coeff2_8k = 0x55B6DC;
+		break;
+
+	case 7000000:
+		NS_coeff1_2048Nu = 0x3200001;
+		NS_coeff1_8191Nu = 0xC80640;
+		NS_coeff1_8192Nu = 0xC80000;
+		NS_coeff1_8193Nu = 0xC7F9C0;
+		NS_coeff2_2k = 0x1900000;
+		NS_coeff2_8k = 0x640000;
+		break;
+
+	case 8000000:
+		NS_coeff1_2048Nu = 0x3924926;
+		NS_coeff1_8191Nu = 0xE4996E;
+		NS_coeff1_8192Nu = 0xE49249;
+		NS_coeff1_8193Nu = 0xE48B25;
+		NS_coeff2_2k = 0x1C92493;
+		NS_coeff2_8k = 0x724925;
+		break;
+	default:
+		err("Invalid bandwidth %d.", bw);
+		return -EINVAL;
+	}
+
+	/*
+	 *  write NS_coeff1_2048Nu
+	 */
+
+	temp0 = (u8) (NS_coeff1_2048Nu & 0x000000FF);
+	temp1 = (u8) ((NS_coeff1_2048Nu & 0x0000FF00) >> 8);
+	temp2 = (u8) ((NS_coeff1_2048Nu & 0x00FF0000) >> 16);
+	temp3 = (u8) ((NS_coeff1_2048Nu & 0x03000000) >> 24);
+
+	/*  big endian to make 8051 happy */
+	buf[0] = temp3;
+	buf[1] = temp2;
+	buf[2] = temp1;
+	buf[3] = temp0;
+
+	/*  cfoe_NS_2k_coeff1_25_24 */
+	ret = af9005_write_ofdm_register(d, 0xAE00, buf[0]);
+	if (ret)
+		return ret;
+
+	/*  cfoe_NS_2k_coeff1_23_16 */
+	ret = af9005_write_ofdm_register(d, 0xAE01, buf[1]);
+	if (ret)
+		return ret;
+
+	/*  cfoe_NS_2k_coeff1_15_8 */
+	ret = af9005_write_ofdm_register(d, 0xAE02, buf[2]);
+	if (ret)
+		return ret;
+
+	/*  cfoe_NS_2k_coeff1_7_0 */
+	ret = af9005_write_ofdm_register(d, 0xAE03, buf[3]);
+	if (ret)
+		return ret;
+
+	/*
+	 *  write NS_coeff2_2k
+	 */
+
+	temp0 = (u8) ((NS_coeff2_2k & 0x0000003F));
+	temp1 = (u8) ((NS_coeff2_2k & 0x00003FC0) >> 6);
+	temp2 = (u8) ((NS_coeff2_2k & 0x003FC000) >> 14);
+	temp3 = (u8) ((NS_coeff2_2k & 0x01C00000) >> 22);
+
+	/*  big endian to make 8051 happy */
+	buf[0] = temp3;
+	buf[1] = temp2;
+	buf[2] = temp1;
+	buf[3] = temp0;
+
+	ret = af9005_write_ofdm_register(d, 0xAE04, buf[0]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE05, buf[1]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE06, buf[2]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE07, buf[3]);
+	if (ret)
+		return ret;
+
+	/*
+	 *  write NS_coeff1_8191Nu
+	 */
+
+	temp0 = (u8) ((NS_coeff1_8191Nu & 0x000000FF));
+	temp1 = (u8) ((NS_coeff1_8191Nu & 0x0000FF00) >> 8);
+	temp2 = (u8) ((NS_coeff1_8191Nu & 0x00FFC000) >> 16);
+	temp3 = (u8) ((NS_coeff1_8191Nu & 0x03000000) >> 24);
+
+	/*  big endian to make 8051 happy */
+	buf[0] = temp3;
+	buf[1] = temp2;
+	buf[2] = temp1;
+	buf[3] = temp0;
+
+	ret = af9005_write_ofdm_register(d, 0xAE08, buf[0]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE09, buf[1]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE0A, buf[2]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE0B, buf[3]);
+	if (ret)
+		return ret;
+
+	/*
+	 *  write NS_coeff1_8192Nu
+	 */
+
+	temp0 = (u8) (NS_coeff1_8192Nu & 0x000000FF);
+	temp1 = (u8) ((NS_coeff1_8192Nu & 0x0000FF00) >> 8);
+	temp2 = (u8) ((NS_coeff1_8192Nu & 0x00FFC000) >> 16);
+	temp3 = (u8) ((NS_coeff1_8192Nu & 0x03000000) >> 24);
+
+	/*  big endian to make 8051 happy */
+	buf[0] = temp3;
+	buf[1] = temp2;
+	buf[2] = temp1;
+	buf[3] = temp0;
+
+	ret = af9005_write_ofdm_register(d, 0xAE0C, buf[0]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE0D, buf[1]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE0E, buf[2]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE0F, buf[3]);
+	if (ret)
+		return ret;
+
+	/*
+	 *  write NS_coeff1_8193Nu
+	 */
+
+	temp0 = (u8) ((NS_coeff1_8193Nu & 0x000000FF));
+	temp1 = (u8) ((NS_coeff1_8193Nu & 0x0000FF00) >> 8);
+	temp2 = (u8) ((NS_coeff1_8193Nu & 0x00FFC000) >> 16);
+	temp3 = (u8) ((NS_coeff1_8193Nu & 0x03000000) >> 24);
+
+	/*  big endian to make 8051 happy */
+	buf[0] = temp3;
+	buf[1] = temp2;
+	buf[2] = temp1;
+	buf[3] = temp0;
+
+	ret = af9005_write_ofdm_register(d, 0xAE10, buf[0]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE11, buf[1]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE12, buf[2]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE13, buf[3]);
+	if (ret)
+		return ret;
+
+	/*
+	 *  write NS_coeff2_8k
+	 */
+
+	temp0 = (u8) ((NS_coeff2_8k & 0x0000003F));
+	temp1 = (u8) ((NS_coeff2_8k & 0x00003FC0) >> 6);
+	temp2 = (u8) ((NS_coeff2_8k & 0x003FC000) >> 14);
+	temp3 = (u8) ((NS_coeff2_8k & 0x01C00000) >> 22);
+
+	/*  big endian to make 8051 happy */
+	buf[0] = temp3;
+	buf[1] = temp2;
+	buf[2] = temp1;
+	buf[3] = temp0;
+
+	ret = af9005_write_ofdm_register(d, 0xAE14, buf[0]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE15, buf[1]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE16, buf[2]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE17, buf[3]);
+	return ret;
+
+}
+
+static int af9005_fe_select_bw(struct dvb_usb_device *d, u32 bw)
+{
+	u8 temp;
+	switch (bw) {
+	case 6000000:
+		temp = 0;
+		break;
+	case 7000000:
+		temp = 1;
+		break;
+	case 8000000:
+		temp = 2;
+		break;
+	default:
+		err("Invalid bandwidth %d.", bw);
+		return -EINVAL;
+	}
+	return af9005_write_register_bits(d, xd_g_reg_bw, reg_bw_pos,
+					  reg_bw_len, temp);
+}
+
+static int af9005_fe_power(struct dvb_frontend *fe, int on)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	u8 temp = on;
+	int ret;
+	deb_info("power %s tuner\n", on ? "on" : "off");
+	ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0);
+	return ret;
+}
+
+static struct mt2060_config af9005_mt2060_config = {
+	0xC0
+};
+
+static struct qt1010_config af9005_qt1010_config = {
+	0xC4
+};
+
+static int af9005_fe_init(struct dvb_frontend *fe)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	int ret, i, scriptlen;
+	u8 temp, temp0 = 0, temp1 = 0, temp2 = 0;
+	u8 buf[2];
+	u16 if1;
+
+	deb_info("in af9005_fe_init\n");
+
+	/* reset */
+	deb_info("reset\n");
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst_en,
+					4, 1, 0x01)))
+		return ret;
+	if ((ret = af9005_write_ofdm_register(state->d, APO_REG_RESET, 0)))
+		return ret;
+	/* clear ofdm reset */
+	deb_info("clear ofdm reset\n");
+	for (i = 0; i < 150; i++) {
+		if ((ret =
+		     af9005_read_ofdm_register(state->d,
+					       xd_I2C_reg_ofdm_rst, &temp)))
+			return ret;
+		if (temp & (regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos))
+			break;
+		msleep(10);
+	}
+	if (i == 150)
+		return -ETIMEDOUT;
+
+	/*FIXME in the dump
+	   write B200 A9
+	   write xd_g_reg_ofsm_clk 7
+	   read eepr c6 (2)
+	   read eepr c7 (2)
+	   misc ctrl 3 -> 1
+	   read eepr ca (6)
+	   write xd_g_reg_ofsm_clk 0
+	   write B200 a1
+	 */
+	ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa9);
+	if (ret)
+		return ret;
+	ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x07);
+	if (ret)
+		return ret;
+	temp = 0x01;
+	ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0);
+	if (ret)
+		return ret;
+	ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x00);
+	if (ret)
+		return ret;
+	ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa1);
+	if (ret)
+		return ret;
+
+	temp = regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos;
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst,
+					reg_ofdm_rst_pos, reg_ofdm_rst_len, 1)))
+		return ret;
+	ret = af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst,
+					 reg_ofdm_rst_pos, reg_ofdm_rst_len, 0);
+
+	if (ret)
+		return ret;
+	/* don't know what register aefc is, but this is what the windows driver does */
+	ret = af9005_write_ofdm_register(state->d, 0xaefc, 0);
+	if (ret)
+		return ret;
+
+	/* set stand alone chip */
+	deb_info("set stand alone chip\n");
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_p_reg_dca_stand_alone,
+					reg_dca_stand_alone_pos,
+					reg_dca_stand_alone_len, 1)))
+		return ret;
+
+	/* set dca upper & lower chip */
+	deb_info("set dca upper & lower chip\n");
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_p_reg_dca_upper_chip,
+					reg_dca_upper_chip_pos,
+					reg_dca_upper_chip_len, 0)))
+		return ret;
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_p_reg_dca_lower_chip,
+					reg_dca_lower_chip_pos,
+					reg_dca_lower_chip_len, 0)))
+		return ret;
+
+	/* set 2wire master clock to 0x14 (for 60KHz) */
+	deb_info("set 2wire master clock to 0x14 (for 60KHz)\n");
+	if ((ret =
+	     af9005_write_ofdm_register(state->d, xd_I2C_i2c_m_period, 0x14)))
+		return ret;
+
+	/* clear dca enable chip */
+	deb_info("clear dca enable chip\n");
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_p_reg_dca_en,
+					reg_dca_en_pos, reg_dca_en_len, 0)))
+		return ret;
+	/* FIXME these are register bits, but I don't know which ones */
+	ret = af9005_write_ofdm_register(state->d, 0xa16c, 1);
+	if (ret)
+		return ret;
+	ret = af9005_write_ofdm_register(state->d, 0xa3c1, 0);
+	if (ret)
+		return ret;
+
+	/* init other parameters: program cfoe and select bandwidth */
+	deb_info("program cfoe\n");
+	ret = af9005_fe_program_cfoe(state->d, 6000000);
+	if (ret)
+		return ret;
+	/* set read-update bit for modulation */
+	deb_info("set read-update bit for modulation\n");
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_p_reg_feq_read_update,
+					reg_feq_read_update_pos,
+					reg_feq_read_update_len, 1)))
+		return ret;
+
+	/* sample code has a set MPEG TS code here
+	   but sniffing reveals that it doesn't do it */
+
+	/* set read-update bit to 1 for DCA modulation */
+	deb_info("set read-update bit 1 for DCA modulation\n");
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_p_reg_dca_read_update,
+					reg_dca_read_update_pos,
+					reg_dca_read_update_len, 1)))
+		return ret;
+
+	/* enable fec monitor */
+	deb_info("enable fec monitor\n");
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en,
+					fec_vtb_rsd_mon_en_pos,
+					fec_vtb_rsd_mon_en_len, 1)))
+		return ret;
+
+	/* FIXME should be register bits, I don't know which ones */
+	ret = af9005_write_ofdm_register(state->d, 0xa601, 0);
+
+	/* set api_retrain_never_freeze */
+	deb_info("set api_retrain_never_freeze\n");
+	if ((ret = af9005_write_ofdm_register(state->d, 0xaefb, 0x01)))
+		return ret;
+
+	/* load init script */
+	deb_info("load init script\n");
+	scriptlen = sizeof(script) / sizeof(RegDesc);
+	for (i = 0; i < scriptlen; i++) {
+		if ((ret =
+		     af9005_write_register_bits(state->d, script[i].reg,
+						script[i].pos,
+						script[i].len, script[i].val)))
+			return ret;
+		/* save 3 bytes of original fcw */
+		if (script[i].reg == 0xae18)
+			temp2 = script[i].val;
+		if (script[i].reg == 0xae19)
+			temp1 = script[i].val;
+		if (script[i].reg == 0xae1a)
+			temp0 = script[i].val;
+
+		/* save original unplug threshold */
+		if (script[i].reg == xd_p_reg_unplug_th)
+			state->original_if_unplug_th = script[i].val;
+		if (script[i].reg == xd_p_reg_unplug_rf_gain_th)
+			state->original_rf_unplug_th = script[i].val;
+		if (script[i].reg == xd_p_reg_unplug_dtop_if_gain_th)
+			state->original_dtop_if_unplug_th = script[i].val;
+		if (script[i].reg == xd_p_reg_unplug_dtop_rf_gain_th)
+			state->original_dtop_rf_unplug_th = script[i].val;
+
+	}
+	state->original_fcw =
+	    ((u32) temp2 << 16) + ((u32) temp1 << 8) + (u32) temp0;
+
+
+	/* save original TOPs */
+	deb_info("save original TOPs\n");
+
+	/*  RF TOP */
+	ret =
+	    af9005_read_word_agc(state->d,
+				 xd_p_reg_aagc_rf_top_numerator_9_8,
+				 xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2,
+				 &state->original_rf_top);
+	if (ret)
+		return ret;
+
+	/*  IF TOP */
+	ret =
+	    af9005_read_word_agc(state->d,
+				 xd_p_reg_aagc_if_top_numerator_9_8,
+				 xd_p_reg_aagc_if_top_numerator_7_0, 0, 2,
+				 &state->original_if_top);
+	if (ret)
+		return ret;
+
+	/*  ACI 0 IF TOP */
+	ret =
+	    af9005_read_word_agc(state->d, 0xA60E, 0xA60A, 4, 2,
+				 &state->original_aci0_if_top);
+	if (ret)
+		return ret;
+
+	/*  ACI 1 IF TOP */
+	ret =
+	    af9005_read_word_agc(state->d, 0xA60E, 0xA60B, 6, 2,
+				 &state->original_aci1_if_top);
+	if (ret)
+		return ret;
+
+	/* attach tuner and init */
+	if (fe->ops.tuner_ops.release == NULL) {
+		/* read tuner and board id from eeprom */
+		ret = af9005_read_eeprom(adap->dev, 0xc6, buf, 2);
+		if (ret) {
+			err("Impossible to read EEPROM\n");
+			return ret;
+		}
+		deb_info("Tuner id %d, board id %d\n", buf[0], buf[1]);
+		switch (buf[0]) {
+		case 2:	/* MT2060 */
+			/* read if1 from eeprom */
+			ret = af9005_read_eeprom(adap->dev, 0xc8, buf, 2);
+			if (ret) {
+				err("Impossible to read EEPROM\n");
+				return ret;
+			}
+			if1 = (u16) (buf[0] << 8) + buf[1];
+			if (dvb_attach(mt2060_attach, fe, &adap->dev->i2c_adap,
+					 &af9005_mt2060_config, if1) == NULL) {
+				deb_info("MT2060 attach failed\n");
+				return -ENODEV;
+			}
+			break;
+		case 3:	/* QT1010 */
+		case 9:	/* QT1010B */
+			if (dvb_attach(qt1010_attach, fe, &adap->dev->i2c_adap,
+					&af9005_qt1010_config) ==NULL) {
+				deb_info("QT1010 attach failed\n");
+				return -ENODEV;
+			}
+			break;
+		default:
+			err("Unsupported tuner type %d", buf[0]);
+			return -ENODEV;
+		}
+		ret = fe->ops.tuner_ops.init(fe);
+		if (ret)
+			return ret;
+	}
+
+	deb_info("profit!\n");
+	return 0;
+}
+
+static int af9005_fe_sleep(struct dvb_frontend *fe)
+{
+	return af9005_fe_power(fe, 0);
+}
+
+static int af9005_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+
+	if (acquire) {
+		state->opened++;
+	} else {
+
+		state->opened--;
+		if (!state->opened)
+			af9005_led_control(state->d, 0);
+	}
+	return 0;
+}
+
+static int af9005_fe_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	int ret;
+	u8 temp, temp0, temp1, temp2;
+
+	deb_info("af9005_fe_set_frontend freq %d bw %d\n", fep->frequency,
+		 fep->bandwidth_hz);
+	if (fe->ops.tuner_ops.release == NULL) {
+		err("Tuner not attached");
+		return -ENODEV;
+	}
+
+	deb_info("turn off led\n");
+	/* not in the log */
+	ret = af9005_led_control(state->d, 0);
+	if (ret)
+		return ret;
+	/* not sure about the bits */
+	ret = af9005_write_register_bits(state->d, XD_MP2IF_MISC, 2, 1, 0);
+	if (ret)
+		return ret;
+
+	/* set FCW to default value */
+	deb_info("set FCW to default value\n");
+	temp0 = (u8) (state->original_fcw & 0x000000ff);
+	temp1 = (u8) ((state->original_fcw & 0x0000ff00) >> 8);
+	temp2 = (u8) ((state->original_fcw & 0x00ff0000) >> 16);
+	ret = af9005_write_ofdm_register(state->d, 0xae1a, temp0);
+	if (ret)
+		return ret;
+	ret = af9005_write_ofdm_register(state->d, 0xae19, temp1);
+	if (ret)
+		return ret;
+	ret = af9005_write_ofdm_register(state->d, 0xae18, temp2);
+	if (ret)
+		return ret;
+
+	/* restore original TOPs */
+	deb_info("restore original TOPs\n");
+	ret =
+	    af9005_write_word_agc(state->d,
+				  xd_p_reg_aagc_rf_top_numerator_9_8,
+				  xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2,
+				  state->original_rf_top);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_write_word_agc(state->d,
+				  xd_p_reg_aagc_if_top_numerator_9_8,
+				  xd_p_reg_aagc_if_top_numerator_7_0, 0, 2,
+				  state->original_if_top);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_write_word_agc(state->d, 0xA60E, 0xA60A, 4, 2,
+				  state->original_aci0_if_top);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_write_word_agc(state->d, 0xA60E, 0xA60B, 6, 2,
+				  state->original_aci1_if_top);
+	if (ret)
+		return ret;
+
+	/* select bandwidth */
+	deb_info("select bandwidth");
+	ret = af9005_fe_select_bw(state->d, fep->bandwidth_hz);
+	if (ret)
+		return ret;
+	ret = af9005_fe_program_cfoe(state->d, fep->bandwidth_hz);
+	if (ret)
+		return ret;
+
+	/* clear easy mode flag */
+	deb_info("clear easy mode flag\n");
+	ret = af9005_write_ofdm_register(state->d, 0xaefd, 0);
+	if (ret)
+		return ret;
+
+	/* set unplug threshold to original value */
+	deb_info("set unplug threshold to original value\n");
+	ret =
+	    af9005_write_ofdm_register(state->d, xd_p_reg_unplug_th,
+				       state->original_if_unplug_th);
+	if (ret)
+		return ret;
+	/* set tuner */
+	deb_info("set tuner\n");
+	ret = fe->ops.tuner_ops.set_params(fe);
+	if (ret)
+		return ret;
+
+	/* trigger ofsm */
+	deb_info("trigger ofsm\n");
+	temp = 0;
+	ret = af9005_write_tuner_registers(state->d, 0xffff, &temp, 1);
+	if (ret)
+		return ret;
+
+	/* clear retrain and freeze flag */
+	deb_info("clear retrain and freeze flag\n");
+	ret =
+	    af9005_write_register_bits(state->d,
+				       xd_p_reg_api_retrain_request,
+				       reg_api_retrain_request_pos, 2, 0);
+	if (ret)
+		return ret;
+
+	/* reset pre viterbi and post viterbi registers and statistics */
+	af9005_reset_pre_viterbi(fe);
+	af9005_reset_post_viterbi(fe);
+	state->pre_vit_error_count = 0;
+	state->pre_vit_bit_count = 0;
+	state->ber = 0;
+	state->post_vit_error_count = 0;
+	/* state->unc = 0; commented out since it should be ever increasing */
+	state->abort_count = 0;
+
+	state->next_status_check = jiffies;
+	state->strong = -1;
+
+	return 0;
+}
+
+static int af9005_fe_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	int ret;
+	u8 temp;
+
+	/* mode */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
+				      reg_tpsd_const_pos, reg_tpsd_const_len,
+				      &temp);
+	if (ret)
+		return ret;
+	deb_info("===== fe_get_frontend_legacy = =============\n");
+	deb_info("CONSTELLATION ");
+	switch (temp) {
+	case 0:
+		fep->modulation = QPSK;
+		deb_info("QPSK\n");
+		break;
+	case 1:
+		fep->modulation = QAM_16;
+		deb_info("QAM_16\n");
+		break;
+	case 2:
+		fep->modulation = QAM_64;
+		deb_info("QAM_64\n");
+		break;
+	}
+
+	/* tps hierarchy and alpha value */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_hier,
+				      reg_tpsd_hier_pos, reg_tpsd_hier_len,
+				      &temp);
+	if (ret)
+		return ret;
+	deb_info("HIERARCHY ");
+	switch (temp) {
+	case 0:
+		fep->hierarchy = HIERARCHY_NONE;
+		deb_info("NONE\n");
+		break;
+	case 1:
+		fep->hierarchy = HIERARCHY_1;
+		deb_info("1\n");
+		break;
+	case 2:
+		fep->hierarchy = HIERARCHY_2;
+		deb_info("2\n");
+		break;
+	case 3:
+		fep->hierarchy = HIERARCHY_4;
+		deb_info("4\n");
+		break;
+	}
+
+	/*  high/low priority     */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_dec_pri,
+				      reg_dec_pri_pos, reg_dec_pri_len, &temp);
+	if (ret)
+		return ret;
+	/* if temp is set = high priority */
+	deb_info("PRIORITY %s\n", temp ? "high" : "low");
+
+	/* high coderate */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_hpcr,
+				      reg_tpsd_hpcr_pos, reg_tpsd_hpcr_len,
+				      &temp);
+	if (ret)
+		return ret;
+	deb_info("CODERATE HP ");
+	switch (temp) {
+	case 0:
+		fep->code_rate_HP = FEC_1_2;
+		deb_info("FEC_1_2\n");
+		break;
+	case 1:
+		fep->code_rate_HP = FEC_2_3;
+		deb_info("FEC_2_3\n");
+		break;
+	case 2:
+		fep->code_rate_HP = FEC_3_4;
+		deb_info("FEC_3_4\n");
+		break;
+	case 3:
+		fep->code_rate_HP = FEC_5_6;
+		deb_info("FEC_5_6\n");
+		break;
+	case 4:
+		fep->code_rate_HP = FEC_7_8;
+		deb_info("FEC_7_8\n");
+		break;
+	}
+
+	/* low coderate */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_lpcr,
+				      reg_tpsd_lpcr_pos, reg_tpsd_lpcr_len,
+				      &temp);
+	if (ret)
+		return ret;
+	deb_info("CODERATE LP ");
+	switch (temp) {
+	case 0:
+		fep->code_rate_LP = FEC_1_2;
+		deb_info("FEC_1_2\n");
+		break;
+	case 1:
+		fep->code_rate_LP = FEC_2_3;
+		deb_info("FEC_2_3\n");
+		break;
+	case 2:
+		fep->code_rate_LP = FEC_3_4;
+		deb_info("FEC_3_4\n");
+		break;
+	case 3:
+		fep->code_rate_LP = FEC_5_6;
+		deb_info("FEC_5_6\n");
+		break;
+	case 4:
+		fep->code_rate_LP = FEC_7_8;
+		deb_info("FEC_7_8\n");
+		break;
+	}
+
+	/* guard interval */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_gi,
+				      reg_tpsd_gi_pos, reg_tpsd_gi_len, &temp);
+	if (ret)
+		return ret;
+	deb_info("GUARD INTERVAL ");
+	switch (temp) {
+	case 0:
+		fep->guard_interval = GUARD_INTERVAL_1_32;
+		deb_info("1_32\n");
+		break;
+	case 1:
+		fep->guard_interval = GUARD_INTERVAL_1_16;
+		deb_info("1_16\n");
+		break;
+	case 2:
+		fep->guard_interval = GUARD_INTERVAL_1_8;
+		deb_info("1_8\n");
+		break;
+	case 3:
+		fep->guard_interval = GUARD_INTERVAL_1_4;
+		deb_info("1_4\n");
+		break;
+	}
+
+	/* fft */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod,
+				      reg_tpsd_txmod_pos, reg_tpsd_txmod_len,
+				      &temp);
+	if (ret)
+		return ret;
+	deb_info("TRANSMISSION MODE ");
+	switch (temp) {
+	case 0:
+		fep->transmission_mode = TRANSMISSION_MODE_2K;
+		deb_info("2K\n");
+		break;
+	case 1:
+		fep->transmission_mode = TRANSMISSION_MODE_8K;
+		deb_info("8K\n");
+		break;
+	}
+
+	/* bandwidth      */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_bw, reg_bw_pos,
+				      reg_bw_len, &temp);
+	deb_info("BANDWIDTH ");
+	switch (temp) {
+	case 0:
+		fep->bandwidth_hz = 6000000;
+		deb_info("6\n");
+		break;
+	case 1:
+		fep->bandwidth_hz = 7000000;
+		deb_info("7\n");
+		break;
+	case 2:
+		fep->bandwidth_hz = 8000000;
+		deb_info("8\n");
+		break;
+	}
+	return 0;
+}
+
+static void af9005_fe_release(struct dvb_frontend *fe)
+{
+	struct af9005_fe_state *state =
+	    (struct af9005_fe_state *)fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops af9005_fe_ops;
+
+struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d)
+{
+	struct af9005_fe_state *state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct af9005_fe_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	deb_info("attaching frontend af9005\n");
+
+	state->d = d;
+	state->opened = 0;
+
+	memcpy(&state->frontend.ops, &af9005_fe_ops,
+	       sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	return &state->frontend;
+      error:
+	return NULL;
+}
+
+static struct dvb_frontend_ops af9005_fe_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		 .name = "AF9005 USB DVB-T",
+		 .frequency_min = 44250000,
+		 .frequency_max = 867250000,
+		 .frequency_stepsize = 250000,
+		 .caps = FE_CAN_INVERSION_AUTO |
+		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+		 FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+		 FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER |
+		 FE_CAN_HIERARCHY_AUTO,
+		 },
+
+	.release = af9005_fe_release,
+
+	.init = af9005_fe_init,
+	.sleep = af9005_fe_sleep,
+	.ts_bus_ctrl = af9005_ts_bus_ctrl,
+
+	.set_frontend = af9005_fe_set_frontend,
+	.get_frontend = af9005_fe_get_frontend,
+
+	.read_status = af9005_fe_read_status,
+	.read_ber = af9005_fe_read_ber,
+	.read_signal_strength = af9005_fe_read_signal_strength,
+	.read_snr = af9005_fe_read_snr,
+	.read_ucblocks = af9005_fe_read_unc_blocks,
+};
diff --git a/drivers/media/usb/dvb-usb/af9005-remote.c b/drivers/media/usb/dvb-usb/af9005-remote.c
new file mode 100644
index 0000000..7e3961d
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/af9005-remote.c
@@ -0,0 +1,157 @@
+/* DVB USB compliant Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Standard remote decode function
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "af9005.h"
+/* debug */
+static int dvb_usb_af9005_remote_debug;
+module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+		 "enable (1) or disable (0) debug messages."
+		 DVB_USB_DEBUG_STATUS);
+
+#define deb_decode(args...)   dprintk(dvb_usb_af9005_remote_debug,0x01,args)
+
+struct rc_map_table rc_map_af9005_table[] = {
+
+	{0x01b7, KEY_POWER},
+	{0x01a7, KEY_VOLUMEUP},
+	{0x0187, KEY_CHANNELUP},
+	{0x017f, KEY_MUTE},
+	{0x01bf, KEY_VOLUMEDOWN},
+	{0x013f, KEY_CHANNELDOWN},
+	{0x01df, KEY_1},
+	{0x015f, KEY_2},
+	{0x019f, KEY_3},
+	{0x011f, KEY_4},
+	{0x01ef, KEY_5},
+	{0x016f, KEY_6},
+	{0x01af, KEY_7},
+	{0x0127, KEY_8},
+	{0x0107, KEY_9},
+	{0x01cf, KEY_ZOOM},
+	{0x014f, KEY_0},
+	{0x018f, KEY_GOTO},	/* marked jump on the remote */
+
+	{0x00bd, KEY_POWER},
+	{0x007d, KEY_VOLUMEUP},
+	{0x00fd, KEY_CHANNELUP},
+	{0x009d, KEY_MUTE},
+	{0x005d, KEY_VOLUMEDOWN},
+	{0x00dd, KEY_CHANNELDOWN},
+	{0x00ad, KEY_1},
+	{0x006d, KEY_2},
+	{0x00ed, KEY_3},
+	{0x008d, KEY_4},
+	{0x004d, KEY_5},
+	{0x00cd, KEY_6},
+	{0x00b5, KEY_7},
+	{0x0075, KEY_8},
+	{0x00f5, KEY_9},
+	{0x0095, KEY_ZOOM},
+	{0x0055, KEY_0},
+	{0x00d5, KEY_GOTO},	/* marked jump on the remote */
+};
+
+int rc_map_af9005_table_size = ARRAY_SIZE(rc_map_af9005_table);
+
+static int repeatable_keys[] = {
+	KEY_VOLUMEUP,
+	KEY_VOLUMEDOWN,
+	KEY_CHANNELUP,
+	KEY_CHANNELDOWN
+};
+
+int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
+		     int *state)
+{
+	u16 mark, space;
+	u32 result;
+	u8 cust, dat, invdat;
+	int i;
+
+	if (len >= 6) {
+		mark = (u16) (data[0] << 8) + data[1];
+		space = (u16) (data[2] << 8) + data[3];
+		if (space * 3 < mark) {
+			for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) {
+				if (d->last_event == repeatable_keys[i]) {
+					*state = REMOTE_KEY_REPEAT;
+					*event = d->last_event;
+					deb_decode("repeat key, event %x\n",
+						   *event);
+					return 0;
+				}
+			}
+			deb_decode("repeated key ignored (non repeatable)\n");
+			return 0;
+		} else if (len >= 33 * 4) {	/*32 bits + start code */
+			result = 0;
+			for (i = 4; i < 4 + 32 * 4; i += 4) {
+				result <<= 1;
+				mark = (u16) (data[i] << 8) + data[i + 1];
+				mark >>= 1;
+				space = (u16) (data[i + 2] << 8) + data[i + 3];
+				space >>= 1;
+				if (mark * 2 > space)
+					result += 1;
+			}
+			deb_decode("key pressed, raw value %x\n", result);
+			if ((result & 0xff000000) != 0xfe000000) {
+				deb_decode
+				    ("doesn't start with 0xfe, ignored\n");
+				return 0;
+			}
+			cust = (result >> 16) & 0xff;
+			dat = (result >> 8) & 0xff;
+			invdat = (~result) & 0xff;
+			if (dat != invdat) {
+				deb_decode("code != inverted code\n");
+				return 0;
+			}
+			for (i = 0; i < rc_map_af9005_table_size; i++) {
+				if (rc5_custom(&rc_map_af9005_table[i]) == cust
+				    && rc5_data(&rc_map_af9005_table[i]) == dat) {
+					*event = rc_map_af9005_table[i].keycode;
+					*state = REMOTE_KEY_PRESSED;
+					deb_decode
+					    ("key pressed, event %x\n", *event);
+					return 0;
+				}
+			}
+			deb_decode("not found in table\n");
+		}
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(rc_map_af9005_table);
+EXPORT_SYMBOL(rc_map_af9005_table_size);
+EXPORT_SYMBOL(af9005_rc_decode);
+
+MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
+MODULE_DESCRIPTION
+    ("Standard remote control decoder for Afatech 9005 DVB-T USB1.1 stick");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/af9005-script.h b/drivers/media/usb/dvb-usb/af9005-script.h
new file mode 100644
index 0000000..4d69045
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/af9005-script.h
@@ -0,0 +1,203 @@
+/*
+File automatically generated by createinit.py using data
+extracted from AF05BDA.sys (windows driver):
+
+dd if=AF05BDA.sys of=initsequence bs=1 skip=88316 count=1110
+python createinit.py > af9005-script.h
+
+*/
+
+typedef struct {
+	u16 reg;
+	u8 pos;
+	u8 len;
+	u8 val;
+} RegDesc;
+
+static RegDesc script[] = {
+	{0xa180, 0x0, 0x8, 0xa},
+	{0xa181, 0x0, 0x8, 0xd7},
+	{0xa182, 0x0, 0x8, 0xa3},
+	{0xa0a0, 0x0, 0x8, 0x0},
+	{0xa0a1, 0x0, 0x5, 0x0},
+	{0xa0a1, 0x5, 0x1, 0x1},
+	{0xa0c0, 0x0, 0x4, 0x1},
+	{0xa20e, 0x4, 0x4, 0xa},
+	{0xa20f, 0x0, 0x8, 0x40},
+	{0xa210, 0x0, 0x8, 0x8},
+	{0xa32a, 0x0, 0x4, 0xa},
+	{0xa32c, 0x0, 0x8, 0x20},
+	{0xa32b, 0x0, 0x8, 0x15},
+	{0xa1a0, 0x1, 0x1, 0x1},
+	{0xa000, 0x0, 0x1, 0x1},
+	{0xa000, 0x1, 0x1, 0x0},
+	{0xa001, 0x1, 0x1, 0x1},
+	{0xa001, 0x0, 0x1, 0x0},
+	{0xa001, 0x5, 0x1, 0x0},
+	{0xa00e, 0x0, 0x5, 0x10},
+	{0xa00f, 0x0, 0x3, 0x4},
+	{0xa00f, 0x3, 0x3, 0x5},
+	{0xa010, 0x0, 0x3, 0x4},
+	{0xa010, 0x3, 0x3, 0x5},
+	{0xa016, 0x4, 0x4, 0x3},
+	{0xa01f, 0x0, 0x6, 0xa},
+	{0xa020, 0x0, 0x6, 0xa},
+	{0xa2bc, 0x0, 0x1, 0x1},
+	{0xa2bc, 0x5, 0x1, 0x1},
+	{0xa015, 0x0, 0x8, 0x50},
+	{0xa016, 0x0, 0x1, 0x0},
+	{0xa02a, 0x0, 0x8, 0x50},
+	{0xa029, 0x0, 0x8, 0x4b},
+	{0xa614, 0x0, 0x8, 0x46},
+	{0xa002, 0x0, 0x5, 0x19},
+	{0xa003, 0x0, 0x5, 0x1a},
+	{0xa004, 0x0, 0x5, 0x19},
+	{0xa005, 0x0, 0x5, 0x1a},
+	{0xa008, 0x0, 0x8, 0x69},
+	{0xa009, 0x0, 0x2, 0x2},
+	{0xae1b, 0x0, 0x8, 0x69},
+	{0xae1c, 0x0, 0x8, 0x2},
+	{0xae1d, 0x0, 0x8, 0x2a},
+	{0xa022, 0x0, 0x8, 0xaa},
+	{0xa006, 0x0, 0x8, 0xc8},
+	{0xa007, 0x0, 0x2, 0x0},
+	{0xa00c, 0x0, 0x8, 0xba},
+	{0xa00d, 0x0, 0x2, 0x2},
+	{0xa608, 0x0, 0x8, 0xba},
+	{0xa60e, 0x0, 0x2, 0x2},
+	{0xa609, 0x0, 0x8, 0x80},
+	{0xa60e, 0x2, 0x2, 0x3},
+	{0xa00a, 0x0, 0x8, 0xb6},
+	{0xa00b, 0x0, 0x2, 0x0},
+	{0xa011, 0x0, 0x8, 0xb9},
+	{0xa012, 0x0, 0x2, 0x0},
+	{0xa013, 0x0, 0x8, 0xbd},
+	{0xa014, 0x0, 0x2, 0x2},
+	{0xa366, 0x0, 0x1, 0x1},
+	{0xa2bc, 0x3, 0x1, 0x0},
+	{0xa2bd, 0x0, 0x8, 0xa},
+	{0xa2be, 0x0, 0x8, 0x14},
+	{0xa2bf, 0x0, 0x8, 0x8},
+	{0xa60a, 0x0, 0x8, 0xbd},
+	{0xa60e, 0x4, 0x2, 0x2},
+	{0xa60b, 0x0, 0x8, 0x86},
+	{0xa60e, 0x6, 0x2, 0x3},
+	{0xa001, 0x2, 0x2, 0x1},
+	{0xa1c7, 0x0, 0x8, 0xf5},
+	{0xa03d, 0x0, 0x8, 0xb1},
+	{0xa616, 0x0, 0x8, 0xff},
+	{0xa617, 0x0, 0x8, 0xad},
+	{0xa618, 0x0, 0x8, 0xad},
+	{0xa61e, 0x3, 0x1, 0x1},
+	{0xae1a, 0x0, 0x8, 0x0},
+	{0xae19, 0x0, 0x8, 0xc8},
+	{0xae18, 0x0, 0x8, 0x61},
+	{0xa140, 0x0, 0x8, 0x0},
+	{0xa141, 0x0, 0x8, 0xc8},
+	{0xa142, 0x0, 0x7, 0x61},
+	{0xa023, 0x0, 0x8, 0xff},
+	{0xa021, 0x0, 0x8, 0xad},
+	{0xa026, 0x0, 0x1, 0x0},
+	{0xa024, 0x0, 0x8, 0xff},
+	{0xa025, 0x0, 0x8, 0xff},
+	{0xa1c8, 0x0, 0x8, 0xf},
+	{0xa2bc, 0x1, 0x1, 0x0},
+	{0xa60c, 0x0, 0x4, 0x5},
+	{0xa60c, 0x4, 0x4, 0x6},
+	{0xa60d, 0x0, 0x8, 0xa},
+	{0xa371, 0x0, 0x1, 0x1},
+	{0xa366, 0x1, 0x3, 0x7},
+	{0xa338, 0x0, 0x8, 0x10},
+	{0xa339, 0x0, 0x6, 0x7},
+	{0xa33a, 0x0, 0x6, 0x1f},
+	{0xa33b, 0x0, 0x8, 0xf6},
+	{0xa33c, 0x3, 0x5, 0x4},
+	{0xa33d, 0x4, 0x4, 0x0},
+	{0xa33d, 0x1, 0x1, 0x1},
+	{0xa33d, 0x2, 0x1, 0x1},
+	{0xa33d, 0x3, 0x1, 0x1},
+	{0xa16d, 0x0, 0x4, 0xf},
+	{0xa161, 0x0, 0x5, 0x5},
+	{0xa162, 0x0, 0x4, 0x5},
+	{0xa165, 0x0, 0x8, 0xff},
+	{0xa166, 0x0, 0x8, 0x9c},
+	{0xa2c3, 0x0, 0x4, 0x5},
+	{0xa61a, 0x0, 0x6, 0xf},
+	{0xb200, 0x0, 0x8, 0xa1},
+	{0xb201, 0x0, 0x8, 0x7},
+	{0xa093, 0x0, 0x1, 0x0},
+	{0xa093, 0x1, 0x5, 0xf},
+	{0xa094, 0x0, 0x8, 0xff},
+	{0xa095, 0x0, 0x8, 0xf},
+	{0xa080, 0x2, 0x5, 0x3},
+	{0xa081, 0x0, 0x4, 0x0},
+	{0xa081, 0x4, 0x4, 0x9},
+	{0xa082, 0x0, 0x5, 0x1f},
+	{0xa08d, 0x0, 0x8, 0x1},
+	{0xa083, 0x0, 0x8, 0x32},
+	{0xa084, 0x0, 0x1, 0x0},
+	{0xa08e, 0x0, 0x8, 0x3},
+	{0xa085, 0x0, 0x8, 0x32},
+	{0xa086, 0x0, 0x3, 0x0},
+	{0xa087, 0x0, 0x8, 0x6e},
+	{0xa088, 0x0, 0x5, 0x15},
+	{0xa089, 0x0, 0x8, 0x0},
+	{0xa08a, 0x0, 0x5, 0x19},
+	{0xa08b, 0x0, 0x8, 0x92},
+	{0xa08c, 0x0, 0x5, 0x1c},
+	{0xa120, 0x0, 0x8, 0x0},
+	{0xa121, 0x0, 0x5, 0x10},
+	{0xa122, 0x0, 0x8, 0x0},
+	{0xa123, 0x0, 0x7, 0x40},
+	{0xa123, 0x7, 0x1, 0x0},
+	{0xa124, 0x0, 0x8, 0x13},
+	{0xa125, 0x0, 0x7, 0x10},
+	{0xa1c0, 0x0, 0x8, 0x0},
+	{0xa1c1, 0x0, 0x5, 0x4},
+	{0xa1c2, 0x0, 0x8, 0x0},
+	{0xa1c3, 0x0, 0x5, 0x10},
+	{0xa1c3, 0x5, 0x3, 0x0},
+	{0xa1c4, 0x0, 0x6, 0x0},
+	{0xa1c5, 0x0, 0x7, 0x10},
+	{0xa100, 0x0, 0x8, 0x0},
+	{0xa101, 0x0, 0x5, 0x10},
+	{0xa102, 0x0, 0x8, 0x0},
+	{0xa103, 0x0, 0x7, 0x40},
+	{0xa103, 0x7, 0x1, 0x0},
+	{0xa104, 0x0, 0x8, 0x18},
+	{0xa105, 0x0, 0x7, 0xa},
+	{0xa106, 0x0, 0x8, 0x20},
+	{0xa107, 0x0, 0x8, 0x40},
+	{0xa108, 0x0, 0x4, 0x0},
+	{0xa38c, 0x0, 0x8, 0xfc},
+	{0xa38d, 0x0, 0x8, 0x0},
+	{0xa38e, 0x0, 0x8, 0x7e},
+	{0xa38f, 0x0, 0x8, 0x0},
+	{0xa390, 0x0, 0x8, 0x2f},
+	{0xa60f, 0x5, 0x1, 0x1},
+	{0xa170, 0x0, 0x8, 0xdc},
+	{0xa171, 0x0, 0x2, 0x0},
+	{0xa2ae, 0x0, 0x1, 0x1},
+	{0xa2ae, 0x1, 0x1, 0x1},
+	{0xa392, 0x0, 0x1, 0x1},
+	{0xa391, 0x2, 0x1, 0x0},
+	{0xabc1, 0x0, 0x8, 0xff},
+	{0xabc2, 0x0, 0x8, 0x0},
+	{0xabc8, 0x0, 0x8, 0x8},
+	{0xabca, 0x0, 0x8, 0x10},
+	{0xabcb, 0x0, 0x1, 0x0},
+	{0xabc3, 0x5, 0x3, 0x7},
+	{0xabc0, 0x6, 0x1, 0x0},
+	{0xabc0, 0x4, 0x2, 0x0},
+	{0xa344, 0x4, 0x4, 0x1},
+	{0xabc0, 0x7, 0x1, 0x1},
+	{0xabc0, 0x2, 0x1, 0x1},
+	{0xa345, 0x0, 0x8, 0x66},
+	{0xa346, 0x0, 0x8, 0x66},
+	{0xa347, 0x0, 0x4, 0x0},
+	{0xa343, 0x0, 0x4, 0xa},
+	{0xa347, 0x4, 0x4, 0x2},
+	{0xa348, 0x0, 0x4, 0xc},
+	{0xa348, 0x4, 0x4, 0x7},
+	{0xa349, 0x0, 0x6, 0x2},
+};
diff --git a/drivers/media/usb/dvb-usb/af9005.c b/drivers/media/usb/dvb-usb/af9005.c
new file mode 100644
index 0000000..af176b6
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/af9005.c
@@ -0,0 +1,1117 @@
+/* DVB USB compliant Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "af9005.h"
+
+/* debug */
+int dvb_usb_af9005_debug;
+module_param_named(debug, dvb_usb_af9005_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+		 "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))."
+		 DVB_USB_DEBUG_STATUS);
+/* enable obnoxious led */
+bool dvb_usb_af9005_led = 1;
+module_param_named(led, dvb_usb_af9005_led, bool, 0644);
+MODULE_PARM_DESC(led, "enable led (default: 1).");
+
+/* eeprom dump */
+static int dvb_usb_af9005_dump_eeprom;
+module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0);
+MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom.");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* remote control decoder */
+static int (*rc_decode) (struct dvb_usb_device *d, u8 *data, int len,
+		u32 *event, int *state);
+static void *rc_keys;
+static int *rc_keys_size;
+
+u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
+
+struct af9005_device_state {
+	u8 sequence;
+	int led_state;
+};
+
+static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
+			      int readwrite, int type, u8 * values, int len)
+{
+	struct af9005_device_state *st = d->priv;
+	u8 obuf[16] = { 0 };
+	u8 ibuf[17] = { 0 };
+	u8 command;
+	int i;
+	int ret;
+
+	if (len < 1) {
+		err("generic read/write, less than 1 byte. Makes no sense.");
+		return -EINVAL;
+	}
+	if (len > 8) {
+		err("generic read/write, more than 8 bytes. Not supported.");
+		return -EINVAL;
+	}
+
+	obuf[0] = 14;		/* rest of buffer length low */
+	obuf[1] = 0;		/* rest of buffer length high */
+
+	obuf[2] = AF9005_REGISTER_RW;	/* register operation */
+	obuf[3] = 12;		/* rest of buffer length */
+
+	obuf[4] = st->sequence++;	/* sequence number */
+
+	obuf[5] = (u8) (reg >> 8);	/* register address */
+	obuf[6] = (u8) (reg & 0xff);
+
+	if (type == AF9005_OFDM_REG) {
+		command = AF9005_CMD_OFDM_REG;
+	} else {
+		command = AF9005_CMD_TUNER;
+	}
+
+	if (len > 1)
+		command |=
+		    AF9005_CMD_BURST | AF9005_CMD_AUTOINC | (len - 1) << 3;
+	command |= readwrite;
+	if (readwrite == AF9005_CMD_WRITE)
+		for (i = 0; i < len; i++)
+			obuf[8 + i] = values[i];
+	else if (type == AF9005_TUNER_REG)
+		/* read command for tuner, the first byte contains the i2c address */
+		obuf[8] = values[0];
+	obuf[7] = command;
+
+	ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
+	if (ret)
+		return ret;
+
+	/* sanity check */
+	if (ibuf[2] != AF9005_REGISTER_RW_ACK) {
+		err("generic read/write, wrong reply code.");
+		return -EIO;
+	}
+	if (ibuf[3] != 0x0d) {
+		err("generic read/write, wrong length in reply.");
+		return -EIO;
+	}
+	if (ibuf[4] != obuf[4]) {
+		err("generic read/write, wrong sequence in reply.");
+		return -EIO;
+	}
+	/*
+	   Windows driver doesn't check these fields, in fact sometimes
+	   the register in the reply is different that what has been sent
+
+	   if (ibuf[5] != obuf[5] || ibuf[6] != obuf[6]) {
+	   err("generic read/write, wrong register in reply.");
+	   return -EIO;
+	   }
+	   if (ibuf[7] != command) {
+	   err("generic read/write wrong command in reply.");
+	   return -EIO;
+	   }
+	 */
+	if (ibuf[16] != 0x01) {
+		err("generic read/write wrong status code in reply.");
+		return -EIO;
+	}
+	if (readwrite == AF9005_CMD_READ)
+		for (i = 0; i < len; i++)
+			values[i] = ibuf[8 + i];
+
+	return 0;
+
+}
+
+int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 * value)
+{
+	int ret;
+	deb_reg("read register %x ", reg);
+	ret = af9005_generic_read_write(d, reg,
+					AF9005_CMD_READ, AF9005_OFDM_REG,
+					value, 1);
+	if (ret)
+		deb_reg("failed\n");
+	else
+		deb_reg("value %x\n", *value);
+	return ret;
+}
+
+int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+			       u8 * values, int len)
+{
+	int ret;
+	deb_reg("read %d registers %x ", len, reg);
+	ret = af9005_generic_read_write(d, reg,
+					AF9005_CMD_READ, AF9005_OFDM_REG,
+					values, len);
+	if (ret)
+		deb_reg("failed\n");
+	else
+		debug_dump(values, len, deb_reg);
+	return ret;
+}
+
+int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 value)
+{
+	int ret;
+	u8 temp = value;
+	deb_reg("write register %x value %x ", reg, value);
+	ret = af9005_generic_read_write(d, reg,
+					AF9005_CMD_WRITE, AF9005_OFDM_REG,
+					&temp, 1);
+	if (ret)
+		deb_reg("failed\n");
+	else
+		deb_reg("ok\n");
+	return ret;
+}
+
+int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+				u8 * values, int len)
+{
+	int ret;
+	deb_reg("write %d registers %x values ", len, reg);
+	debug_dump(values, len, deb_reg);
+
+	ret = af9005_generic_read_write(d, reg,
+					AF9005_CMD_WRITE, AF9005_OFDM_REG,
+					values, len);
+	if (ret)
+		deb_reg("failed\n");
+	else
+		deb_reg("ok\n");
+	return ret;
+}
+
+int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
+			      u8 len, u8 * value)
+{
+	u8 temp;
+	int ret;
+	deb_reg("read bits %x %x %x", reg, pos, len);
+	ret = af9005_read_ofdm_register(d, reg, &temp);
+	if (ret) {
+		deb_reg(" failed\n");
+		return ret;
+	}
+	*value = (temp >> pos) & regmask[len - 1];
+	deb_reg(" value %x\n", *value);
+	return 0;
+
+}
+
+int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
+			       u8 len, u8 value)
+{
+	u8 temp, mask;
+	int ret;
+	deb_reg("write bits %x %x %x value %x\n", reg, pos, len, value);
+	if (pos == 0 && len == 8)
+		return af9005_write_ofdm_register(d, reg, value);
+	ret = af9005_read_ofdm_register(d, reg, &temp);
+	if (ret)
+		return ret;
+	mask = regmask[len - 1] << pos;
+	temp = (temp & ~mask) | ((value << pos) & mask);
+	return af9005_write_ofdm_register(d, reg, temp);
+
+}
+
+static int af9005_usb_read_tuner_registers(struct dvb_usb_device *d,
+					   u16 reg, u8 * values, int len)
+{
+	return af9005_generic_read_write(d, reg,
+					 AF9005_CMD_READ, AF9005_TUNER_REG,
+					 values, len);
+}
+
+static int af9005_usb_write_tuner_registers(struct dvb_usb_device *d,
+					    u16 reg, u8 * values, int len)
+{
+	return af9005_generic_read_write(d, reg,
+					 AF9005_CMD_WRITE,
+					 AF9005_TUNER_REG, values, len);
+}
+
+int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,
+				 u8 * values, int len)
+{
+	/* don't let the name of this function mislead you: it's just used
+	   as an interface from the firmware to the i2c bus. The actual
+	   i2c addresses are contained in the data */
+	int ret, i, done = 0, fail = 0;
+	u8 temp;
+	ret = af9005_usb_write_tuner_registers(d, reg, values, len);
+	if (ret)
+		return ret;
+	if (reg != 0xffff) {
+		/* check if write done (0xa40d bit 1) or fail (0xa40d bit 2) */
+		for (i = 0; i < 200; i++) {
+			ret =
+			    af9005_read_ofdm_register(d,
+						      xd_I2C_i2c_m_status_wdat_done,
+						      &temp);
+			if (ret)
+				return ret;
+			done = temp & (regmask[i2c_m_status_wdat_done_len - 1]
+				       << i2c_m_status_wdat_done_pos);
+			if (done)
+				break;
+			fail = temp & (regmask[i2c_m_status_wdat_fail_len - 1]
+				       << i2c_m_status_wdat_fail_pos);
+			if (fail)
+				break;
+			msleep(50);
+		}
+		if (i == 200)
+			return -ETIMEDOUT;
+		if (fail) {
+			/* clear write fail bit */
+			af9005_write_register_bits(d,
+						   xd_I2C_i2c_m_status_wdat_fail,
+						   i2c_m_status_wdat_fail_pos,
+						   i2c_m_status_wdat_fail_len,
+						   1);
+			return -EIO;
+		}
+		/* clear write done bit */
+		ret =
+		    af9005_write_register_bits(d,
+					       xd_I2C_i2c_m_status_wdat_fail,
+					       i2c_m_status_wdat_done_pos,
+					       i2c_m_status_wdat_done_len, 1);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, u8 addr,
+				u8 * values, int len)
+{
+	/* don't let the name of this function mislead you: it's just used
+	   as an interface from the firmware to the i2c bus. The actual
+	   i2c addresses are contained in the data */
+	int ret, i;
+	u8 temp, buf[2];
+
+	buf[0] = addr;		/* tuner i2c address */
+	buf[1] = values[0];	/* tuner register */
+
+	values[0] = addr + 0x01;	/* i2c read address */
+
+	if (reg == APO_REG_I2C_RW_SILICON_TUNER) {
+		/* write tuner i2c address to tuner, 0c00c0 undocumented, found by sniffing */
+		ret = af9005_write_tuner_registers(d, 0x00c0, buf, 2);
+		if (ret)
+			return ret;
+	}
+
+	/* send read command to ofsm */
+	ret = af9005_usb_read_tuner_registers(d, reg, values, 1);
+	if (ret)
+		return ret;
+
+	/* check if read done */
+	for (i = 0; i < 200; i++) {
+		ret = af9005_read_ofdm_register(d, 0xa408, &temp);
+		if (ret)
+			return ret;
+		if (temp & 0x01)
+			break;
+		msleep(50);
+	}
+	if (i == 200)
+		return -ETIMEDOUT;
+
+	/* clear read done bit (by writing 1) */
+	ret = af9005_write_ofdm_register(d, xd_I2C_i2c_m_data8, 1);
+	if (ret)
+		return ret;
+
+	/* get read data (available from 0xa400) */
+	for (i = 0; i < len; i++) {
+		ret = af9005_read_ofdm_register(d, 0xa400 + i, &temp);
+		if (ret)
+			return ret;
+		values[i] = temp;
+	}
+	return 0;
+}
+
+static int af9005_i2c_write(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
+			    u8 * data, int len)
+{
+	int ret, i;
+	u8 buf[3];
+	deb_i2c("i2c_write i2caddr %x, reg %x, len %d data ", i2caddr,
+		reg, len);
+	debug_dump(data, len, deb_i2c);
+
+	for (i = 0; i < len; i++) {
+		buf[0] = i2caddr;
+		buf[1] = reg + (u8) i;
+		buf[2] = data[i];
+		ret =
+		    af9005_write_tuner_registers(d,
+						 APO_REG_I2C_RW_SILICON_TUNER,
+						 buf, 3);
+		if (ret) {
+			deb_i2c("i2c_write failed\n");
+			return ret;
+		}
+	}
+	deb_i2c("i2c_write ok\n");
+	return 0;
+}
+
+static int af9005_i2c_read(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
+			   u8 * data, int len)
+{
+	int ret, i;
+	u8 temp;
+	deb_i2c("i2c_read i2caddr %x, reg %x, len %d\n ", i2caddr, reg, len);
+	for (i = 0; i < len; i++) {
+		temp = reg + i;
+		ret =
+		    af9005_read_tuner_registers(d,
+						APO_REG_I2C_RW_SILICON_TUNER,
+						i2caddr, &temp, 1);
+		if (ret) {
+			deb_i2c("i2c_read failed\n");
+			return ret;
+		}
+		data[i] = temp;
+	}
+	deb_i2c("i2c data read: ");
+	debug_dump(data, len, deb_i2c);
+	return 0;
+}
+
+static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+			   int num)
+{
+	/* only implements what the mt2060 module does, don't know how
+	   to make it really generic */
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int ret;
+	u8 reg, addr;
+	u8 *value;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	if (num > 2)
+		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+	if (num == 2) {
+		/* reads a single register */
+		reg = *msg[0].buf;
+		addr = msg[0].addr;
+		value = msg[1].buf;
+		ret = af9005_i2c_read(d, addr, reg, value, 1);
+		if (ret == 0)
+			ret = 2;
+	} else {
+		/* write one or more registers */
+		reg = msg[0].buf[0];
+		addr = msg[0].addr;
+		value = &msg[0].buf[1];
+		ret = af9005_i2c_write(d, addr, reg, value, msg[0].len - 1);
+		if (ret == 0)
+			ret = 1;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return ret;
+}
+
+static u32 af9005_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm af9005_i2c_algo = {
+	.master_xfer = af9005_i2c_xfer,
+	.functionality = af9005_i2c_func,
+};
+
+int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,
+			int wlen, u8 * rbuf, int rlen)
+{
+	struct af9005_device_state *st = d->priv;
+
+	int ret, i, packet_len;
+	u8 buf[64];
+	u8 ibuf[64];
+
+	if (wlen < 0) {
+		err("send command, wlen less than 0 bytes. Makes no sense.");
+		return -EINVAL;
+	}
+	if (wlen > 54) {
+		err("send command, wlen more than 54 bytes. Not supported.");
+		return -EINVAL;
+	}
+	if (rlen > 54) {
+		err("send command, rlen more than 54 bytes. Not supported.");
+		return -EINVAL;
+	}
+	packet_len = wlen + 5;
+	buf[0] = (u8) (packet_len & 0xff);
+	buf[1] = (u8) ((packet_len & 0xff00) >> 8);
+
+	buf[2] = 0x26;		/* packet type */
+	buf[3] = wlen + 3;
+	buf[4] = st->sequence++;
+	buf[5] = command;
+	buf[6] = wlen;
+	for (i = 0; i < wlen; i++)
+		buf[7 + i] = wbuf[i];
+	ret = dvb_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);
+	if (ret)
+		return ret;
+	if (ibuf[2] != 0x27) {
+		err("send command, wrong reply code.");
+		return -EIO;
+	}
+	if (ibuf[4] != buf[4]) {
+		err("send command, wrong sequence in reply.");
+		return -EIO;
+	}
+	if (ibuf[5] != 0x01) {
+		err("send command, wrong status code in reply.");
+		return -EIO;
+	}
+	if (ibuf[6] != rlen) {
+		err("send command, invalid data length in reply.");
+		return -EIO;
+	}
+	for (i = 0; i < rlen; i++)
+		rbuf[i] = ibuf[i + 7];
+	return 0;
+}
+
+int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values,
+		       int len)
+{
+	struct af9005_device_state *st = d->priv;
+	u8 obuf[16], ibuf[14];
+	int ret, i;
+
+	memset(obuf, 0, sizeof(obuf));
+	memset(ibuf, 0, sizeof(ibuf));
+
+	obuf[0] = 14;		/* length of rest of packet low */
+	obuf[1] = 0;		/* length of rest of packer high */
+
+	obuf[2] = 0x2a;		/* read/write eeprom */
+
+	obuf[3] = 12;		/* size */
+
+	obuf[4] = st->sequence++;
+
+	obuf[5] = 0;		/* read */
+
+	obuf[6] = len;
+	obuf[7] = address;
+	ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
+	if (ret)
+		return ret;
+	if (ibuf[2] != 0x2b) {
+		err("Read eeprom, invalid reply code");
+		return -EIO;
+	}
+	if (ibuf[3] != 10) {
+		err("Read eeprom, invalid reply length");
+		return -EIO;
+	}
+	if (ibuf[4] != obuf[4]) {
+		err("Read eeprom, wrong sequence in reply ");
+		return -EIO;
+	}
+	if (ibuf[5] != 1) {
+		err("Read eeprom, wrong status in reply ");
+		return -EIO;
+	}
+	for (i = 0; i < len; i++) {
+		values[i] = ibuf[6 + i];
+	}
+	return 0;
+}
+
+static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply)
+{
+	u8 buf[FW_BULKOUT_SIZE + 2];
+	u16 checksum;
+	int act_len, i, ret;
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
+	buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
+	switch (type) {
+	case FW_CONFIG:
+		buf[2] = 0x11;
+		buf[3] = 0x04;
+		buf[4] = 0x00;	/* sequence number, original driver doesn't increment it here */
+		buf[5] = 0x03;
+		checksum = buf[4] + buf[5];
+		buf[6] = (u8) ((checksum >> 8) & 0xff);
+		buf[7] = (u8) (checksum & 0xff);
+		break;
+	case FW_CONFIRM:
+		buf[2] = 0x11;
+		buf[3] = 0x04;
+		buf[4] = 0x00;	/* sequence number, original driver doesn't increment it here */
+		buf[5] = 0x01;
+		checksum = buf[4] + buf[5];
+		buf[6] = (u8) ((checksum >> 8) & 0xff);
+		buf[7] = (u8) (checksum & 0xff);
+		break;
+	case FW_BOOT:
+		buf[2] = 0x10;
+		buf[3] = 0x08;
+		buf[4] = 0x00;	/* sequence number, original driver doesn't increment it here */
+		buf[5] = 0x97;
+		buf[6] = 0xaa;
+		buf[7] = 0x55;
+		buf[8] = 0xa5;
+		buf[9] = 0x5a;
+		checksum = 0;
+		for (i = 4; i <= 9; i++)
+			checksum += buf[i];
+		buf[10] = (u8) ((checksum >> 8) & 0xff);
+		buf[11] = (u8) (checksum & 0xff);
+		break;
+	default:
+		err("boot packet invalid boot packet type");
+		return -EINVAL;
+	}
+	deb_fw(">>> ");
+	debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
+
+	ret = usb_bulk_msg(udev,
+			   usb_sndbulkpipe(udev, 0x02),
+			   buf, FW_BULKOUT_SIZE + 2, &act_len, 2000);
+	if (ret)
+		err("boot packet bulk message failed: %d (%d/%d)", ret,
+		    FW_BULKOUT_SIZE + 2, act_len);
+	else
+		ret = act_len != FW_BULKOUT_SIZE + 2 ? -1 : 0;
+	if (ret)
+		return ret;
+	memset(buf, 0, 9);
+	ret = usb_bulk_msg(udev,
+			   usb_rcvbulkpipe(udev, 0x01), buf, 9, &act_len, 2000);
+	if (ret) {
+		err("boot packet recv bulk message failed: %d", ret);
+		return ret;
+	}
+	deb_fw("<<< ");
+	debug_dump(buf, act_len, deb_fw);
+	checksum = 0;
+	switch (type) {
+	case FW_CONFIG:
+		if (buf[2] != 0x11) {
+			err("boot bad config header.");
+			return -EIO;
+		}
+		if (buf[3] != 0x05) {
+			err("boot bad config size.");
+			return -EIO;
+		}
+		if (buf[4] != 0x00) {
+			err("boot bad config sequence.");
+			return -EIO;
+		}
+		if (buf[5] != 0x04) {
+			err("boot bad config subtype.");
+			return -EIO;
+		}
+		for (i = 4; i <= 6; i++)
+			checksum += buf[i];
+		if (buf[7] * 256 + buf[8] != checksum) {
+			err("boot bad config checksum.");
+			return -EIO;
+		}
+		*reply = buf[6];
+		break;
+	case FW_CONFIRM:
+		if (buf[2] != 0x11) {
+			err("boot bad confirm header.");
+			return -EIO;
+		}
+		if (buf[3] != 0x05) {
+			err("boot bad confirm size.");
+			return -EIO;
+		}
+		if (buf[4] != 0x00) {
+			err("boot bad confirm sequence.");
+			return -EIO;
+		}
+		if (buf[5] != 0x02) {
+			err("boot bad confirm subtype.");
+			return -EIO;
+		}
+		for (i = 4; i <= 6; i++)
+			checksum += buf[i];
+		if (buf[7] * 256 + buf[8] != checksum) {
+			err("boot bad confirm checksum.");
+			return -EIO;
+		}
+		*reply = buf[6];
+		break;
+	case FW_BOOT:
+		if (buf[2] != 0x10) {
+			err("boot bad boot header.");
+			return -EIO;
+		}
+		if (buf[3] != 0x05) {
+			err("boot bad boot size.");
+			return -EIO;
+		}
+		if (buf[4] != 0x00) {
+			err("boot bad boot sequence.");
+			return -EIO;
+		}
+		if (buf[5] != 0x01) {
+			err("boot bad boot pattern 01.");
+			return -EIO;
+		}
+		if (buf[6] != 0x10) {
+			err("boot bad boot pattern 10.");
+			return -EIO;
+		}
+		for (i = 4; i <= 6; i++)
+			checksum += buf[i];
+		if (buf[7] * 256 + buf[8] != checksum) {
+			err("boot bad boot checksum.");
+			return -EIO;
+		}
+		break;
+
+	}
+
+	return 0;
+}
+
+static int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw)
+{
+	int i, packets, ret, act_len;
+
+	u8 buf[FW_BULKOUT_SIZE + 2];
+	u8 reply;
+
+	ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+	if (ret)
+		return ret;
+	if (reply != 0x01) {
+		err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply);
+		return -EIO;
+	}
+	packets = fw->size / FW_BULKOUT_SIZE;
+	buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
+	buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
+	for (i = 0; i < packets; i++) {
+		memcpy(&buf[2], fw->data + i * FW_BULKOUT_SIZE,
+		       FW_BULKOUT_SIZE);
+		deb_fw(">>> ");
+		debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
+		ret = usb_bulk_msg(udev,
+				   usb_sndbulkpipe(udev, 0x02),
+				   buf, FW_BULKOUT_SIZE + 2, &act_len, 1000);
+		if (ret) {
+			err("firmware download failed at packet %d with code %d", i, ret);
+			return ret;
+		}
+	}
+	ret = af9005_boot_packet(udev, FW_CONFIRM, &reply);
+	if (ret)
+		return ret;
+	if (reply != (u8) (packets & 0xff)) {
+		err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply);
+		return -EIO;
+	}
+	ret = af9005_boot_packet(udev, FW_BOOT, &reply);
+	if (ret)
+		return ret;
+	ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+	if (ret)
+		return ret;
+	if (reply != 0x02) {
+		err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply);
+		return -EIO;
+	}
+
+	return 0;
+
+}
+
+int af9005_led_control(struct dvb_usb_device *d, int onoff)
+{
+	struct af9005_device_state *st = d->priv;
+	int temp, ret;
+
+	if (onoff && dvb_usb_af9005_led)
+		temp = 1;
+	else
+		temp = 0;
+	if (st->led_state != temp) {
+		ret =
+		    af9005_write_register_bits(d, xd_p_reg_top_locken1,
+					       reg_top_locken1_pos,
+					       reg_top_locken1_len, temp);
+		if (ret)
+			return ret;
+		ret =
+		    af9005_write_register_bits(d, xd_p_reg_top_lock1,
+					       reg_top_lock1_pos,
+					       reg_top_lock1_len, temp);
+		if (ret)
+			return ret;
+		st->led_state = temp;
+	}
+	return 0;
+}
+
+static int af9005_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	u8 buf[8];
+	int i;
+
+	/* without these calls the first commands after downloading
+	   the firmware fail. I put these calls here to simulate
+	   what it is done in dvb-usb-init.c.
+	 */
+	struct usb_device *udev = adap->dev->udev;
+	usb_clear_halt(udev, usb_sndbulkpipe(udev, 2));
+	usb_clear_halt(udev, usb_rcvbulkpipe(udev, 1));
+	if (dvb_usb_af9005_dump_eeprom) {
+		printk("EEPROM DUMP\n");
+		for (i = 0; i < 255; i += 8) {
+			af9005_read_eeprom(adap->dev, i, buf, 8);
+			printk("ADDR %x ", i);
+			debug_dump(buf, 8, printk);
+		}
+	}
+	adap->fe_adap[0].fe = af9005_fe_attach(adap->dev);
+	return 0;
+}
+
+static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state)
+{
+	struct af9005_device_state *st = d->priv;
+	int ret, len;
+
+	u8 obuf[5];
+	u8 ibuf[256];
+
+	*state = REMOTE_NO_KEY_PRESSED;
+	if (rc_decode == NULL) {
+		/* it shouldn't never come here */
+		return 0;
+	}
+	/* deb_info("rc_query\n"); */
+	obuf[0] = 3;		/* rest of packet length low */
+	obuf[1] = 0;		/* rest of packet lentgh high */
+	obuf[2] = 0x40;		/* read remote */
+	obuf[3] = 1;		/* rest of packet length */
+	obuf[4] = st->sequence++;	/* sequence number */
+	ret = dvb_usb_generic_rw(d, obuf, 5, ibuf, 256, 0);
+	if (ret) {
+		err("rc query failed");
+		return ret;
+	}
+	if (ibuf[2] != 0x41) {
+		err("rc query bad header.");
+		return -EIO;
+	}
+	if (ibuf[4] != obuf[4]) {
+		err("rc query bad sequence.");
+		return -EIO;
+	}
+	len = ibuf[5];
+	if (len > 246) {
+		err("rc query invalid length");
+		return -EIO;
+	}
+	if (len > 0) {
+		deb_rc("rc data (%d) ", len);
+		debug_dump((ibuf + 6), len, deb_rc);
+		ret = rc_decode(d, &ibuf[6], len, event, state);
+		if (ret) {
+			err("rc_decode failed");
+			return ret;
+		} else {
+			deb_rc("rc_decode state %x event %x\n", *state, *event);
+			if (*state == REMOTE_KEY_REPEAT)
+				*event = d->last_event;
+		}
+	}
+	return 0;
+}
+
+static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+
+	return 0;
+}
+
+static int af9005_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
+{
+	int ret;
+	deb_info("pid filter control  onoff %d\n", onoff);
+	if (onoff) {
+		ret =
+		    af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
+		if (ret)
+			return ret;
+		ret =
+		    af9005_write_register_bits(adap->dev,
+					       XD_MP2IF_DMX_CTRL, 1, 1, 1);
+		if (ret)
+			return ret;
+		ret =
+		    af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
+	} else
+		ret =
+		    af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 0);
+	if (ret)
+		return ret;
+	deb_info("pid filter control ok\n");
+	return 0;
+}
+
+static int af9005_pid_filter(struct dvb_usb_adapter *adap, int index,
+			     u16 pid, int onoff)
+{
+	u8 cmd = index & 0x1f;
+	int ret;
+	deb_info("set pid filter, index %d, pid %x, onoff %d\n", index,
+		 pid, onoff);
+	if (onoff) {
+		/* cannot use it as pid_filter_ctrl since it has to be done
+		   before setting the first pid */
+		if (adap->feedcount == 1) {
+			deb_info("first pid set, enable pid table\n");
+			ret = af9005_pid_filter_control(adap, onoff);
+			if (ret)
+				return ret;
+		}
+		ret =
+		    af9005_write_ofdm_register(adap->dev,
+					       XD_MP2IF_PID_DATA_L,
+					       (u8) (pid & 0xff));
+		if (ret)
+			return ret;
+		ret =
+		    af9005_write_ofdm_register(adap->dev,
+					       XD_MP2IF_PID_DATA_H,
+					       (u8) (pid >> 8));
+		if (ret)
+			return ret;
+		cmd |= 0x20 | 0x40;
+	} else {
+		if (adap->feedcount == 0) {
+			deb_info("last pid unset, disable pid table\n");
+			ret = af9005_pid_filter_control(adap, onoff);
+			if (ret)
+				return ret;
+		}
+	}
+	ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_IDX, cmd);
+	if (ret)
+		return ret;
+	deb_info("set pid ok\n");
+	return 0;
+}
+
+static int af9005_identify_state(struct usb_device *udev,
+				 struct dvb_usb_device_properties *props,
+				 struct dvb_usb_device_description **desc,
+				 int *cold)
+{
+	int ret;
+	u8 reply;
+	ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+	if (ret)
+		return ret;
+	deb_info("result of FW_CONFIG in identify state %d\n", reply);
+	if (reply == 0x01)
+		*cold = 1;
+	else if (reply == 0x02)
+		*cold = 0;
+	else
+		return -EIO;
+	deb_info("Identify state cold = %d\n", *cold);
+	return 0;
+}
+
+static struct dvb_usb_device_properties af9005_properties;
+
+static int af9005_usb_probe(struct usb_interface *intf,
+			    const struct usb_device_id *id)
+{
+	return dvb_usb_device_init(intf, &af9005_properties,
+				   THIS_MODULE, NULL, adapter_nr);
+}
+
+enum af9005_usb_table_entry {
+	AFATECH_AF9005,
+	TERRATEC_AF9005,
+	ANSONIC_AF9005,
+};
+
+static struct usb_device_id af9005_usb_table[] = {
+	[AFATECH_AF9005] = {USB_DEVICE(USB_VID_AFATECH,
+				USB_PID_AFATECH_AF9005)},
+	[TERRATEC_AF9005] = {USB_DEVICE(USB_VID_TERRATEC,
+				USB_PID_TERRATEC_CINERGY_T_USB_XE)},
+	[ANSONIC_AF9005] = {USB_DEVICE(USB_VID_ANSONIC,
+				USB_PID_ANSONIC_DVBT_USB)},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(usb, af9005_usb_table);
+
+static struct dvb_usb_device_properties af9005_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.firmware = "af9005.fw",
+	.download_firmware = af9005_download_firmware,
+	.no_reconnect = 1,
+
+	.size_of_priv = sizeof(struct af9005_device_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		    {
+		    .num_frontends = 1,
+		    .fe = {{
+		     .caps =
+		     DVB_USB_ADAP_HAS_PID_FILTER |
+		     DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+		     .pid_filter_count = 32,
+		     .pid_filter = af9005_pid_filter,
+		     /* .pid_filter_ctrl = af9005_pid_filter_control, */
+		     .frontend_attach = af9005_frontend_attach,
+		     /* .tuner_attach     = af9005_tuner_attach, */
+		     /* parameter for the MPEG2-data transfer */
+		     .stream = {
+				.type = USB_BULK,
+				.count = 10,
+				.endpoint = 0x04,
+				.u = {
+				      .bulk = {
+					       .buffersize = 4096,	/* actual size seen is 3948 */
+					       }
+				      }
+				},
+		     }},
+		     }
+		    },
+	.power_ctrl = af9005_power_ctrl,
+	.identify_state = af9005_identify_state,
+
+	.i2c_algo = &af9005_i2c_algo,
+
+	.rc.legacy = {
+		.rc_interval = 200,
+		.rc_map_table = NULL,
+		.rc_map_size = 0,
+		.rc_query = af9005_rc_query,
+	},
+
+	.generic_bulk_ctrl_endpoint          = 2,
+	.generic_bulk_ctrl_endpoint_response = 1,
+
+	.num_device_descs = 3,
+	.devices = {
+		    {.name = "Afatech DVB-T USB1.1 stick",
+		     .cold_ids = {&af9005_usb_table[AFATECH_AF9005], NULL},
+		     .warm_ids = {NULL},
+		     },
+		    {.name = "TerraTec Cinergy T USB XE",
+		     .cold_ids = {&af9005_usb_table[TERRATEC_AF9005], NULL},
+		     .warm_ids = {NULL},
+		     },
+		    {.name = "Ansonic DVB-T USB1.1 stick",
+		     .cold_ids = {&af9005_usb_table[ANSONIC_AF9005], NULL},
+		     .warm_ids = {NULL},
+		     },
+		    {NULL},
+		    }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver af9005_usb_driver = {
+	.name = "dvb_usb_af9005",
+	.probe = af9005_usb_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table = af9005_usb_table,
+};
+
+/* module stuff */
+static int __init af9005_usb_module_init(void)
+{
+	int result;
+	if ((result = usb_register(&af9005_usb_driver))) {
+		err("usb_register failed. (%d)", result);
+		return result;
+	}
+	rc_decode = symbol_request(af9005_rc_decode);
+	rc_keys = symbol_request(rc_map_af9005_table);
+	rc_keys_size = symbol_request(rc_map_af9005_table_size);
+	if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) {
+		err("af9005_rc_decode function not found, disabling remote");
+		af9005_properties.rc.legacy.rc_query = NULL;
+	} else {
+		af9005_properties.rc.legacy.rc_map_table = rc_keys;
+		af9005_properties.rc.legacy.rc_map_size = *rc_keys_size;
+	}
+
+	return 0;
+}
+
+static void __exit af9005_usb_module_exit(void)
+{
+	/* release rc decode symbols */
+	if (rc_decode != NULL)
+		symbol_put(af9005_rc_decode);
+	if (rc_keys != NULL)
+		symbol_put(rc_map_af9005_table);
+	if (rc_keys_size != NULL)
+		symbol_put(rc_map_af9005_table_size);
+	/* deregister this driver from the USB subsystem */
+	usb_deregister(&af9005_usb_driver);
+}
+
+module_init(af9005_usb_module_init);
+module_exit(af9005_usb_module_exit);
+
+MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
+MODULE_DESCRIPTION("Driver for Afatech 9005 DVB-T USB1.1 stick");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/af9005.h b/drivers/media/usb/dvb-usb/af9005.h
new file mode 100644
index 0000000..6a2bf3d
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/af9005.h
@@ -0,0 +1,3496 @@
+/* Common header-file of the Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_AF9005_H_
+#define _DVB_USB_AF9005_H_
+
+#define DVB_USB_LOG_PREFIX "af9005"
+#include "dvb-usb.h"
+
+extern int dvb_usb_af9005_debug;
+#define deb_info(args...) dprintk(dvb_usb_af9005_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_af9005_debug,0x02,args)
+#define deb_rc(args...)   dprintk(dvb_usb_af9005_debug,0x04,args)
+#define deb_reg(args...)  dprintk(dvb_usb_af9005_debug,0x08,args)
+#define deb_i2c(args...)  dprintk(dvb_usb_af9005_debug,0x10,args)
+#define deb_fw(args...)   dprintk(dvb_usb_af9005_debug,0x20,args)
+
+extern bool dvb_usb_af9005_led;
+
+/* firmware */
+#define FW_BULKOUT_SIZE 250
+enum {
+	FW_CONFIG,
+	FW_CONFIRM,
+	FW_BOOT
+};
+
+/* af9005 commands */
+#define AF9005_OFDM_REG  0
+#define AF9005_TUNER_REG 1
+
+#define AF9005_REGISTER_RW     0x20
+#define AF9005_REGISTER_RW_ACK 0x21
+
+#define AF9005_CMD_OFDM_REG 0x00
+#define AF9005_CMD_TUNER    0x80
+#define AF9005_CMD_BURST    0x02
+#define AF9005_CMD_AUTOINC  0x04
+#define AF9005_CMD_READ     0x00
+#define AF9005_CMD_WRITE    0x01
+
+/* af9005 registers */
+#define APO_REG_RESET					0xAEFF
+
+#define APO_REG_I2C_RW_CAN_TUNER            0xF000
+#define APO_REG_I2C_RW_SILICON_TUNER        0xF001
+#define APO_REG_GPIO_RW_SILICON_TUNER       0xFFFE	/*  also for OFSM */
+#define APO_REG_TRIGGER_OFSM                0xFFFF	/*  also for OFSM */
+
+/***********************************************************************
+ *  Apollo Registers from VLSI					       *
+ ***********************************************************************/
+#define xd_p_reg_aagc_inverted_agc	0xA000
+#define	reg_aagc_inverted_agc_pos 0
+#define	reg_aagc_inverted_agc_len 1
+#define	reg_aagc_inverted_agc_lsb 0
+#define xd_p_reg_aagc_sign_only	0xA000
+#define	reg_aagc_sign_only_pos 1
+#define	reg_aagc_sign_only_len 1
+#define	reg_aagc_sign_only_lsb 0
+#define xd_p_reg_aagc_slow_adc_en	0xA000
+#define	reg_aagc_slow_adc_en_pos 2
+#define	reg_aagc_slow_adc_en_len 1
+#define	reg_aagc_slow_adc_en_lsb 0
+#define xd_p_reg_aagc_slow_adc_scale	0xA000
+#define	reg_aagc_slow_adc_scale_pos 3
+#define	reg_aagc_slow_adc_scale_len 5
+#define	reg_aagc_slow_adc_scale_lsb 0
+#define xd_p_reg_aagc_check_slow_adc_lock	0xA001
+#define	reg_aagc_check_slow_adc_lock_pos 0
+#define	reg_aagc_check_slow_adc_lock_len 1
+#define	reg_aagc_check_slow_adc_lock_lsb 0
+#define xd_p_reg_aagc_init_control	0xA001
+#define	reg_aagc_init_control_pos 1
+#define	reg_aagc_init_control_len 1
+#define	reg_aagc_init_control_lsb 0
+#define xd_p_reg_aagc_total_gain_sel	0xA001
+#define	reg_aagc_total_gain_sel_pos 2
+#define	reg_aagc_total_gain_sel_len 2
+#define	reg_aagc_total_gain_sel_lsb 0
+#define xd_p_reg_aagc_out_inv	0xA001
+#define	reg_aagc_out_inv_pos 5
+#define	reg_aagc_out_inv_len 1
+#define	reg_aagc_out_inv_lsb 0
+#define xd_p_reg_aagc_int_en	0xA001
+#define	reg_aagc_int_en_pos 6
+#define	reg_aagc_int_en_len 1
+#define	reg_aagc_int_en_lsb 0
+#define xd_p_reg_aagc_lock_change_flag	0xA001
+#define	reg_aagc_lock_change_flag_pos 7
+#define	reg_aagc_lock_change_flag_len 1
+#define	reg_aagc_lock_change_flag_lsb 0
+#define xd_p_reg_aagc_rf_loop_bw_scale_acquire	0xA002
+#define	reg_aagc_rf_loop_bw_scale_acquire_pos 0
+#define	reg_aagc_rf_loop_bw_scale_acquire_len 5
+#define	reg_aagc_rf_loop_bw_scale_acquire_lsb 0
+#define xd_p_reg_aagc_rf_loop_bw_scale_track	0xA003
+#define	reg_aagc_rf_loop_bw_scale_track_pos 0
+#define	reg_aagc_rf_loop_bw_scale_track_len 5
+#define	reg_aagc_rf_loop_bw_scale_track_lsb 0
+#define xd_p_reg_aagc_if_loop_bw_scale_acquire	0xA004
+#define	reg_aagc_if_loop_bw_scale_acquire_pos 0
+#define	reg_aagc_if_loop_bw_scale_acquire_len 5
+#define	reg_aagc_if_loop_bw_scale_acquire_lsb 0
+#define xd_p_reg_aagc_if_loop_bw_scale_track	0xA005
+#define	reg_aagc_if_loop_bw_scale_track_pos 0
+#define	reg_aagc_if_loop_bw_scale_track_len 5
+#define	reg_aagc_if_loop_bw_scale_track_lsb 0
+#define xd_p_reg_aagc_max_rf_agc_7_0	0xA006
+#define	reg_aagc_max_rf_agc_7_0_pos 0
+#define	reg_aagc_max_rf_agc_7_0_len 8
+#define	reg_aagc_max_rf_agc_7_0_lsb 0
+#define xd_p_reg_aagc_max_rf_agc_9_8	0xA007
+#define	reg_aagc_max_rf_agc_9_8_pos 0
+#define	reg_aagc_max_rf_agc_9_8_len 2
+#define	reg_aagc_max_rf_agc_9_8_lsb 8
+#define xd_p_reg_aagc_min_rf_agc_7_0	0xA008
+#define	reg_aagc_min_rf_agc_7_0_pos 0
+#define	reg_aagc_min_rf_agc_7_0_len 8
+#define	reg_aagc_min_rf_agc_7_0_lsb 0
+#define xd_p_reg_aagc_min_rf_agc_9_8	0xA009
+#define	reg_aagc_min_rf_agc_9_8_pos 0
+#define	reg_aagc_min_rf_agc_9_8_len 2
+#define	reg_aagc_min_rf_agc_9_8_lsb 8
+#define xd_p_reg_aagc_max_if_agc_7_0	0xA00A
+#define	reg_aagc_max_if_agc_7_0_pos 0
+#define	reg_aagc_max_if_agc_7_0_len 8
+#define	reg_aagc_max_if_agc_7_0_lsb 0
+#define xd_p_reg_aagc_max_if_agc_9_8	0xA00B
+#define	reg_aagc_max_if_agc_9_8_pos 0
+#define	reg_aagc_max_if_agc_9_8_len 2
+#define	reg_aagc_max_if_agc_9_8_lsb 8
+#define xd_p_reg_aagc_min_if_agc_7_0	0xA00C
+#define	reg_aagc_min_if_agc_7_0_pos 0
+#define	reg_aagc_min_if_agc_7_0_len 8
+#define	reg_aagc_min_if_agc_7_0_lsb 0
+#define xd_p_reg_aagc_min_if_agc_9_8	0xA00D
+#define	reg_aagc_min_if_agc_9_8_pos 0
+#define	reg_aagc_min_if_agc_9_8_len 2
+#define	reg_aagc_min_if_agc_9_8_lsb 8
+#define xd_p_reg_aagc_lock_sample_scale	0xA00E
+#define	reg_aagc_lock_sample_scale_pos 0
+#define	reg_aagc_lock_sample_scale_len 5
+#define	reg_aagc_lock_sample_scale_lsb 0
+#define xd_p_reg_aagc_rf_agc_lock_scale_acquire	0xA00F
+#define	reg_aagc_rf_agc_lock_scale_acquire_pos 0
+#define	reg_aagc_rf_agc_lock_scale_acquire_len 3
+#define	reg_aagc_rf_agc_lock_scale_acquire_lsb 0
+#define xd_p_reg_aagc_rf_agc_lock_scale_track	0xA00F
+#define	reg_aagc_rf_agc_lock_scale_track_pos 3
+#define	reg_aagc_rf_agc_lock_scale_track_len 3
+#define	reg_aagc_rf_agc_lock_scale_track_lsb 0
+#define xd_p_reg_aagc_if_agc_lock_scale_acquire	0xA010
+#define	reg_aagc_if_agc_lock_scale_acquire_pos 0
+#define	reg_aagc_if_agc_lock_scale_acquire_len 3
+#define	reg_aagc_if_agc_lock_scale_acquire_lsb 0
+#define xd_p_reg_aagc_if_agc_lock_scale_track	0xA010
+#define	reg_aagc_if_agc_lock_scale_track_pos 3
+#define	reg_aagc_if_agc_lock_scale_track_len 3
+#define	reg_aagc_if_agc_lock_scale_track_lsb 0
+#define xd_p_reg_aagc_rf_top_numerator_7_0	0xA011
+#define	reg_aagc_rf_top_numerator_7_0_pos 0
+#define	reg_aagc_rf_top_numerator_7_0_len 8
+#define	reg_aagc_rf_top_numerator_7_0_lsb 0
+#define xd_p_reg_aagc_rf_top_numerator_9_8	0xA012
+#define	reg_aagc_rf_top_numerator_9_8_pos 0
+#define	reg_aagc_rf_top_numerator_9_8_len 2
+#define	reg_aagc_rf_top_numerator_9_8_lsb 8
+#define xd_p_reg_aagc_if_top_numerator_7_0	0xA013
+#define	reg_aagc_if_top_numerator_7_0_pos 0
+#define	reg_aagc_if_top_numerator_7_0_len 8
+#define	reg_aagc_if_top_numerator_7_0_lsb 0
+#define xd_p_reg_aagc_if_top_numerator_9_8	0xA014
+#define	reg_aagc_if_top_numerator_9_8_pos 0
+#define	reg_aagc_if_top_numerator_9_8_len 2
+#define	reg_aagc_if_top_numerator_9_8_lsb 8
+#define xd_p_reg_aagc_adc_out_desired_7_0	0xA015
+#define	reg_aagc_adc_out_desired_7_0_pos 0
+#define	reg_aagc_adc_out_desired_7_0_len 8
+#define	reg_aagc_adc_out_desired_7_0_lsb 0
+#define xd_p_reg_aagc_adc_out_desired_8	0xA016
+#define	reg_aagc_adc_out_desired_8_pos 0
+#define	reg_aagc_adc_out_desired_8_len 1
+#define	reg_aagc_adc_out_desired_8_lsb 0
+#define xd_p_reg_aagc_fixed_gain	0xA016
+#define	reg_aagc_fixed_gain_pos 3
+#define	reg_aagc_fixed_gain_len 1
+#define	reg_aagc_fixed_gain_lsb 0
+#define xd_p_reg_aagc_lock_count_th	0xA016
+#define	reg_aagc_lock_count_th_pos 4
+#define	reg_aagc_lock_count_th_len 4
+#define	reg_aagc_lock_count_th_lsb 0
+#define xd_p_reg_aagc_fixed_rf_agc_control_7_0	0xA017
+#define	reg_aagc_fixed_rf_agc_control_7_0_pos 0
+#define	reg_aagc_fixed_rf_agc_control_7_0_len 8
+#define	reg_aagc_fixed_rf_agc_control_7_0_lsb 0
+#define xd_p_reg_aagc_fixed_rf_agc_control_15_8	0xA018
+#define	reg_aagc_fixed_rf_agc_control_15_8_pos 0
+#define	reg_aagc_fixed_rf_agc_control_15_8_len 8
+#define	reg_aagc_fixed_rf_agc_control_15_8_lsb 8
+#define xd_p_reg_aagc_fixed_rf_agc_control_23_16	0xA019
+#define	reg_aagc_fixed_rf_agc_control_23_16_pos 0
+#define	reg_aagc_fixed_rf_agc_control_23_16_len 8
+#define	reg_aagc_fixed_rf_agc_control_23_16_lsb 16
+#define xd_p_reg_aagc_fixed_rf_agc_control_30_24	0xA01A
+#define	reg_aagc_fixed_rf_agc_control_30_24_pos 0
+#define	reg_aagc_fixed_rf_agc_control_30_24_len 7
+#define	reg_aagc_fixed_rf_agc_control_30_24_lsb 24
+#define xd_p_reg_aagc_fixed_if_agc_control_7_0	0xA01B
+#define	reg_aagc_fixed_if_agc_control_7_0_pos 0
+#define	reg_aagc_fixed_if_agc_control_7_0_len 8
+#define	reg_aagc_fixed_if_agc_control_7_0_lsb 0
+#define xd_p_reg_aagc_fixed_if_agc_control_15_8	0xA01C
+#define	reg_aagc_fixed_if_agc_control_15_8_pos 0
+#define	reg_aagc_fixed_if_agc_control_15_8_len 8
+#define	reg_aagc_fixed_if_agc_control_15_8_lsb 8
+#define xd_p_reg_aagc_fixed_if_agc_control_23_16	0xA01D
+#define	reg_aagc_fixed_if_agc_control_23_16_pos 0
+#define	reg_aagc_fixed_if_agc_control_23_16_len 8
+#define	reg_aagc_fixed_if_agc_control_23_16_lsb 16
+#define xd_p_reg_aagc_fixed_if_agc_control_30_24	0xA01E
+#define	reg_aagc_fixed_if_agc_control_30_24_pos 0
+#define	reg_aagc_fixed_if_agc_control_30_24_len 7
+#define	reg_aagc_fixed_if_agc_control_30_24_lsb 24
+#define xd_p_reg_aagc_rf_agc_unlock_numerator	0xA01F
+#define	reg_aagc_rf_agc_unlock_numerator_pos 0
+#define	reg_aagc_rf_agc_unlock_numerator_len 6
+#define	reg_aagc_rf_agc_unlock_numerator_lsb 0
+#define xd_p_reg_aagc_if_agc_unlock_numerator	0xA020
+#define	reg_aagc_if_agc_unlock_numerator_pos 0
+#define	reg_aagc_if_agc_unlock_numerator_len 6
+#define	reg_aagc_if_agc_unlock_numerator_lsb 0
+#define xd_p_reg_unplug_th	0xA021
+#define	reg_unplug_th_pos 0
+#define	reg_unplug_th_len 8
+#define	reg_aagc_rf_x0_lsb 0
+#define xd_p_reg_weak_signal_rfagc_thr 0xA022
+#define	reg_weak_signal_rfagc_thr_pos 0
+#define	reg_weak_signal_rfagc_thr_len 8
+#define	reg_weak_signal_rfagc_thr_lsb 0
+#define xd_p_reg_unplug_rf_gain_th 0xA023
+#define	reg_unplug_rf_gain_th_pos 0
+#define	reg_unplug_rf_gain_th_len 8
+#define	reg_unplug_rf_gain_th_lsb 0
+#define xd_p_reg_unplug_dtop_rf_gain_th 0xA024
+#define	reg_unplug_dtop_rf_gain_th_pos 0
+#define	reg_unplug_dtop_rf_gain_th_len 8
+#define	reg_unplug_dtop_rf_gain_th_lsb 0
+#define xd_p_reg_unplug_dtop_if_gain_th 0xA025
+#define	reg_unplug_dtop_if_gain_th_pos 0
+#define	reg_unplug_dtop_if_gain_th_len 8
+#define	reg_unplug_dtop_if_gain_th_lsb 0
+#define xd_p_reg_top_recover_at_unplug_en 0xA026
+#define	reg_top_recover_at_unplug_en_pos 0
+#define	reg_top_recover_at_unplug_en_len 1
+#define	reg_top_recover_at_unplug_en_lsb 0
+#define xd_p_reg_aagc_rf_x6	0xA027
+#define	reg_aagc_rf_x6_pos 0
+#define	reg_aagc_rf_x6_len 8
+#define	reg_aagc_rf_x6_lsb 0
+#define xd_p_reg_aagc_rf_x7	0xA028
+#define	reg_aagc_rf_x7_pos 0
+#define	reg_aagc_rf_x7_len 8
+#define	reg_aagc_rf_x7_lsb 0
+#define xd_p_reg_aagc_rf_x8	0xA029
+#define	reg_aagc_rf_x8_pos 0
+#define	reg_aagc_rf_x8_len 8
+#define	reg_aagc_rf_x8_lsb 0
+#define xd_p_reg_aagc_rf_x9	0xA02A
+#define	reg_aagc_rf_x9_pos 0
+#define	reg_aagc_rf_x9_len 8
+#define	reg_aagc_rf_x9_lsb 0
+#define xd_p_reg_aagc_rf_x10	0xA02B
+#define	reg_aagc_rf_x10_pos 0
+#define	reg_aagc_rf_x10_len 8
+#define	reg_aagc_rf_x10_lsb 0
+#define xd_p_reg_aagc_rf_x11	0xA02C
+#define	reg_aagc_rf_x11_pos 0
+#define	reg_aagc_rf_x11_len 8
+#define	reg_aagc_rf_x11_lsb 0
+#define xd_p_reg_aagc_rf_x12	0xA02D
+#define	reg_aagc_rf_x12_pos 0
+#define	reg_aagc_rf_x12_len 8
+#define	reg_aagc_rf_x12_lsb 0
+#define xd_p_reg_aagc_rf_x13	0xA02E
+#define	reg_aagc_rf_x13_pos 0
+#define	reg_aagc_rf_x13_len 8
+#define	reg_aagc_rf_x13_lsb 0
+#define xd_p_reg_aagc_if_x0	0xA02F
+#define	reg_aagc_if_x0_pos 0
+#define	reg_aagc_if_x0_len 8
+#define	reg_aagc_if_x0_lsb 0
+#define xd_p_reg_aagc_if_x1	0xA030
+#define	reg_aagc_if_x1_pos 0
+#define	reg_aagc_if_x1_len 8
+#define	reg_aagc_if_x1_lsb 0
+#define xd_p_reg_aagc_if_x2	0xA031
+#define	reg_aagc_if_x2_pos 0
+#define	reg_aagc_if_x2_len 8
+#define	reg_aagc_if_x2_lsb 0
+#define xd_p_reg_aagc_if_x3	0xA032
+#define	reg_aagc_if_x3_pos 0
+#define	reg_aagc_if_x3_len 8
+#define	reg_aagc_if_x3_lsb 0
+#define xd_p_reg_aagc_if_x4	0xA033
+#define	reg_aagc_if_x4_pos 0
+#define	reg_aagc_if_x4_len 8
+#define	reg_aagc_if_x4_lsb 0
+#define xd_p_reg_aagc_if_x5	0xA034
+#define	reg_aagc_if_x5_pos 0
+#define	reg_aagc_if_x5_len 8
+#define	reg_aagc_if_x5_lsb 0
+#define xd_p_reg_aagc_if_x6	0xA035
+#define	reg_aagc_if_x6_pos 0
+#define	reg_aagc_if_x6_len 8
+#define	reg_aagc_if_x6_lsb 0
+#define xd_p_reg_aagc_if_x7	0xA036
+#define	reg_aagc_if_x7_pos 0
+#define	reg_aagc_if_x7_len 8
+#define	reg_aagc_if_x7_lsb 0
+#define xd_p_reg_aagc_if_x8	0xA037
+#define	reg_aagc_if_x8_pos 0
+#define	reg_aagc_if_x8_len 8
+#define	reg_aagc_if_x8_lsb 0
+#define xd_p_reg_aagc_if_x9	0xA038
+#define	reg_aagc_if_x9_pos 0
+#define	reg_aagc_if_x9_len 8
+#define	reg_aagc_if_x9_lsb 0
+#define xd_p_reg_aagc_if_x10	0xA039
+#define	reg_aagc_if_x10_pos 0
+#define	reg_aagc_if_x10_len 8
+#define	reg_aagc_if_x10_lsb 0
+#define xd_p_reg_aagc_if_x11	0xA03A
+#define	reg_aagc_if_x11_pos 0
+#define	reg_aagc_if_x11_len 8
+#define	reg_aagc_if_x11_lsb 0
+#define xd_p_reg_aagc_if_x12	0xA03B
+#define	reg_aagc_if_x12_pos 0
+#define	reg_aagc_if_x12_len 8
+#define	reg_aagc_if_x12_lsb 0
+#define xd_p_reg_aagc_if_x13	0xA03C
+#define	reg_aagc_if_x13_pos 0
+#define	reg_aagc_if_x13_len 8
+#define	reg_aagc_if_x13_lsb 0
+#define xd_p_reg_aagc_min_rf_ctl_8bit_for_dca	0xA03D
+#define	reg_aagc_min_rf_ctl_8bit_for_dca_pos 0
+#define	reg_aagc_min_rf_ctl_8bit_for_dca_len 8
+#define	reg_aagc_min_rf_ctl_8bit_for_dca_lsb 0
+#define xd_p_reg_aagc_min_if_ctl_8bit_for_dca	0xA03E
+#define	reg_aagc_min_if_ctl_8bit_for_dca_pos 0
+#define	reg_aagc_min_if_ctl_8bit_for_dca_len 8
+#define	reg_aagc_min_if_ctl_8bit_for_dca_lsb 0
+#define xd_r_reg_aagc_total_gain_7_0	0xA070
+#define	reg_aagc_total_gain_7_0_pos 0
+#define	reg_aagc_total_gain_7_0_len 8
+#define	reg_aagc_total_gain_7_0_lsb 0
+#define xd_r_reg_aagc_total_gain_15_8	0xA071
+#define	reg_aagc_total_gain_15_8_pos 0
+#define	reg_aagc_total_gain_15_8_len 8
+#define	reg_aagc_total_gain_15_8_lsb 8
+#define xd_p_reg_aagc_in_sat_cnt_7_0	0xA074
+#define	reg_aagc_in_sat_cnt_7_0_pos 0
+#define	reg_aagc_in_sat_cnt_7_0_len 8
+#define	reg_aagc_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_aagc_in_sat_cnt_15_8	0xA075
+#define	reg_aagc_in_sat_cnt_15_8_pos 0
+#define	reg_aagc_in_sat_cnt_15_8_len 8
+#define	reg_aagc_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_aagc_in_sat_cnt_23_16	0xA076
+#define	reg_aagc_in_sat_cnt_23_16_pos 0
+#define	reg_aagc_in_sat_cnt_23_16_len 8
+#define	reg_aagc_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_aagc_in_sat_cnt_31_24	0xA077
+#define	reg_aagc_in_sat_cnt_31_24_pos 0
+#define	reg_aagc_in_sat_cnt_31_24_len 8
+#define	reg_aagc_in_sat_cnt_31_24_lsb 24
+#define xd_r_reg_aagc_digital_rf_volt_7_0	0xA078
+#define	reg_aagc_digital_rf_volt_7_0_pos 0
+#define	reg_aagc_digital_rf_volt_7_0_len 8
+#define	reg_aagc_digital_rf_volt_7_0_lsb 0
+#define xd_r_reg_aagc_digital_rf_volt_9_8	0xA079
+#define	reg_aagc_digital_rf_volt_9_8_pos 0
+#define	reg_aagc_digital_rf_volt_9_8_len 2
+#define	reg_aagc_digital_rf_volt_9_8_lsb 8
+#define xd_r_reg_aagc_digital_if_volt_7_0	0xA07A
+#define	reg_aagc_digital_if_volt_7_0_pos 0
+#define	reg_aagc_digital_if_volt_7_0_len 8
+#define	reg_aagc_digital_if_volt_7_0_lsb 0
+#define xd_r_reg_aagc_digital_if_volt_9_8	0xA07B
+#define	reg_aagc_digital_if_volt_9_8_pos 0
+#define	reg_aagc_digital_if_volt_9_8_len 2
+#define	reg_aagc_digital_if_volt_9_8_lsb 8
+#define xd_r_reg_aagc_rf_gain	0xA07C
+#define	reg_aagc_rf_gain_pos 0
+#define	reg_aagc_rf_gain_len 8
+#define	reg_aagc_rf_gain_lsb 0
+#define xd_r_reg_aagc_if_gain	0xA07D
+#define	reg_aagc_if_gain_pos 0
+#define	reg_aagc_if_gain_len 8
+#define	reg_aagc_if_gain_lsb 0
+#define xd_p_tinr_imp_indicator	0xA080
+#define	tinr_imp_indicator_pos 0
+#define	tinr_imp_indicator_len 2
+#define	tinr_imp_indicator_lsb 0
+#define xd_p_reg_tinr_fifo_size	0xA080
+#define	reg_tinr_fifo_size_pos 2
+#define	reg_tinr_fifo_size_len 5
+#define	reg_tinr_fifo_size_lsb 0
+#define xd_p_reg_tinr_saturation_cnt_th	0xA081
+#define	reg_tinr_saturation_cnt_th_pos 0
+#define	reg_tinr_saturation_cnt_th_len 4
+#define	reg_tinr_saturation_cnt_th_lsb 0
+#define xd_p_reg_tinr_saturation_th_3_0	0xA081
+#define	reg_tinr_saturation_th_3_0_pos 4
+#define	reg_tinr_saturation_th_3_0_len 4
+#define	reg_tinr_saturation_th_3_0_lsb 0
+#define xd_p_reg_tinr_saturation_th_8_4	0xA082
+#define	reg_tinr_saturation_th_8_4_pos 0
+#define	reg_tinr_saturation_th_8_4_len 5
+#define	reg_tinr_saturation_th_8_4_lsb 4
+#define xd_p_reg_tinr_imp_duration_th_2k_7_0	0xA083
+#define	reg_tinr_imp_duration_th_2k_7_0_pos 0
+#define	reg_tinr_imp_duration_th_2k_7_0_len 8
+#define	reg_tinr_imp_duration_th_2k_7_0_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_2k_8	0xA084
+#define	reg_tinr_imp_duration_th_2k_8_pos 0
+#define	reg_tinr_imp_duration_th_2k_8_len 1
+#define	reg_tinr_imp_duration_th_2k_8_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_8k_7_0	0xA085
+#define	reg_tinr_imp_duration_th_8k_7_0_pos 0
+#define	reg_tinr_imp_duration_th_8k_7_0_len 8
+#define	reg_tinr_imp_duration_th_8k_7_0_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_8k_10_8	0xA086
+#define	reg_tinr_imp_duration_th_8k_10_8_pos 0
+#define	reg_tinr_imp_duration_th_8k_10_8_len 3
+#define	reg_tinr_imp_duration_th_8k_10_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_6m_7_0	0xA087
+#define	reg_tinr_freq_ratio_6m_7_0_pos 0
+#define	reg_tinr_freq_ratio_6m_7_0_len 8
+#define	reg_tinr_freq_ratio_6m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_6m_12_8	0xA088
+#define	reg_tinr_freq_ratio_6m_12_8_pos 0
+#define	reg_tinr_freq_ratio_6m_12_8_len 5
+#define	reg_tinr_freq_ratio_6m_12_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_7m_7_0	0xA089
+#define	reg_tinr_freq_ratio_7m_7_0_pos 0
+#define	reg_tinr_freq_ratio_7m_7_0_len 8
+#define	reg_tinr_freq_ratio_7m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_7m_12_8	0xA08A
+#define	reg_tinr_freq_ratio_7m_12_8_pos 0
+#define	reg_tinr_freq_ratio_7m_12_8_len 5
+#define	reg_tinr_freq_ratio_7m_12_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_8m_7_0	0xA08B
+#define	reg_tinr_freq_ratio_8m_7_0_pos 0
+#define	reg_tinr_freq_ratio_8m_7_0_len 8
+#define	reg_tinr_freq_ratio_8m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_8m_12_8	0xA08C
+#define	reg_tinr_freq_ratio_8m_12_8_pos 0
+#define	reg_tinr_freq_ratio_8m_12_8_len 5
+#define	reg_tinr_freq_ratio_8m_12_8_lsb 8
+#define xd_p_reg_tinr_imp_duration_th_low_2k	0xA08D
+#define	reg_tinr_imp_duration_th_low_2k_pos 0
+#define	reg_tinr_imp_duration_th_low_2k_len 8
+#define	reg_tinr_imp_duration_th_low_2k_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_low_8k	0xA08E
+#define	reg_tinr_imp_duration_th_low_8k_pos 0
+#define	reg_tinr_imp_duration_th_low_8k_len 8
+#define	reg_tinr_imp_duration_th_low_8k_lsb 0
+#define xd_r_reg_tinr_counter_7_0	0xA090
+#define	reg_tinr_counter_7_0_pos 0
+#define	reg_tinr_counter_7_0_len 8
+#define	reg_tinr_counter_7_0_lsb 0
+#define xd_r_reg_tinr_counter_15_8	0xA091
+#define	reg_tinr_counter_15_8_pos 0
+#define	reg_tinr_counter_15_8_len 8
+#define	reg_tinr_counter_15_8_lsb 8
+#define xd_p_reg_tinr_adative_tinr_en	0xA093
+#define	reg_tinr_adative_tinr_en_pos 0
+#define	reg_tinr_adative_tinr_en_len 1
+#define	reg_tinr_adative_tinr_en_lsb 0
+#define xd_p_reg_tinr_peak_fifo_size	0xA093
+#define	reg_tinr_peak_fifo_size_pos 1
+#define	reg_tinr_peak_fifo_size_len 5
+#define	reg_tinr_peak_fifo_size_lsb 0
+#define xd_p_reg_tinr_counter_rst	0xA093
+#define	reg_tinr_counter_rst_pos 6
+#define	reg_tinr_counter_rst_len 1
+#define	reg_tinr_counter_rst_lsb 0
+#define xd_p_reg_tinr_search_period_7_0	0xA094
+#define	reg_tinr_search_period_7_0_pos 0
+#define	reg_tinr_search_period_7_0_len 8
+#define	reg_tinr_search_period_7_0_lsb 0
+#define xd_p_reg_tinr_search_period_15_8	0xA095
+#define	reg_tinr_search_period_15_8_pos 0
+#define	reg_tinr_search_period_15_8_len 8
+#define	reg_tinr_search_period_15_8_lsb 8
+#define xd_p_reg_ccifs_fcw_7_0	0xA0A0
+#define	reg_ccifs_fcw_7_0_pos 0
+#define	reg_ccifs_fcw_7_0_len 8
+#define	reg_ccifs_fcw_7_0_lsb 0
+#define xd_p_reg_ccifs_fcw_12_8	0xA0A1
+#define	reg_ccifs_fcw_12_8_pos 0
+#define	reg_ccifs_fcw_12_8_len 5
+#define	reg_ccifs_fcw_12_8_lsb 8
+#define xd_p_reg_ccifs_spec_inv	0xA0A1
+#define	reg_ccifs_spec_inv_pos 5
+#define	reg_ccifs_spec_inv_len 1
+#define	reg_ccifs_spec_inv_lsb 0
+#define xd_p_reg_gp_trigger	0xA0A2
+#define	reg_gp_trigger_pos 0
+#define	reg_gp_trigger_len 1
+#define	reg_gp_trigger_lsb 0
+#define xd_p_reg_trigger_sel	0xA0A2
+#define	reg_trigger_sel_pos 1
+#define	reg_trigger_sel_len 2
+#define	reg_trigger_sel_lsb 0
+#define xd_p_reg_debug_ofdm	0xA0A2
+#define	reg_debug_ofdm_pos 3
+#define	reg_debug_ofdm_len 2
+#define	reg_debug_ofdm_lsb 0
+#define xd_p_reg_trigger_module_sel	0xA0A3
+#define	reg_trigger_module_sel_pos 0
+#define	reg_trigger_module_sel_len 6
+#define	reg_trigger_module_sel_lsb 0
+#define xd_p_reg_trigger_set_sel	0xA0A4
+#define	reg_trigger_set_sel_pos 0
+#define	reg_trigger_set_sel_len 6
+#define	reg_trigger_set_sel_lsb 0
+#define xd_p_reg_fw_int_mask_n	0xA0A4
+#define	reg_fw_int_mask_n_pos 6
+#define	reg_fw_int_mask_n_len 1
+#define	reg_fw_int_mask_n_lsb 0
+#define xd_p_reg_debug_group	0xA0A5
+#define	reg_debug_group_pos 0
+#define	reg_debug_group_len 4
+#define	reg_debug_group_lsb 0
+#define xd_p_reg_odbg_clk_sel	0xA0A5
+#define	reg_odbg_clk_sel_pos 4
+#define	reg_odbg_clk_sel_len 2
+#define	reg_odbg_clk_sel_lsb 0
+#define xd_p_reg_ccif_sc	0xA0C0
+#define	reg_ccif_sc_pos 0
+#define	reg_ccif_sc_len 4
+#define	reg_ccif_sc_lsb 0
+#define xd_r_reg_ccif_saturate	0xA0C1
+#define	reg_ccif_saturate_pos 0
+#define	reg_ccif_saturate_len 2
+#define	reg_ccif_saturate_lsb 0
+#define xd_r_reg_antif_saturate	0xA0C1
+#define	reg_antif_saturate_pos 2
+#define	reg_antif_saturate_len 4
+#define	reg_antif_saturate_lsb 0
+#define xd_r_reg_acif_saturate	0xA0C2
+#define	reg_acif_saturate_pos 0
+#define	reg_acif_saturate_len 8
+#define	reg_acif_saturate_lsb 0
+#define xd_p_reg_tmr_timer0_threshold_7_0	0xA0C8
+#define	reg_tmr_timer0_threshold_7_0_pos 0
+#define	reg_tmr_timer0_threshold_7_0_len 8
+#define	reg_tmr_timer0_threshold_7_0_lsb 0
+#define xd_p_reg_tmr_timer0_threshold_15_8	0xA0C9
+#define	reg_tmr_timer0_threshold_15_8_pos 0
+#define	reg_tmr_timer0_threshold_15_8_len 8
+#define	reg_tmr_timer0_threshold_15_8_lsb 8
+#define xd_p_reg_tmr_timer0_enable	0xA0CA
+#define	reg_tmr_timer0_enable_pos 0
+#define	reg_tmr_timer0_enable_len 1
+#define	reg_tmr_timer0_enable_lsb 0
+#define xd_p_reg_tmr_timer0_clk_sel	0xA0CA
+#define	reg_tmr_timer0_clk_sel_pos 1
+#define	reg_tmr_timer0_clk_sel_len 1
+#define	reg_tmr_timer0_clk_sel_lsb 0
+#define xd_p_reg_tmr_timer0_int	0xA0CA
+#define	reg_tmr_timer0_int_pos 2
+#define	reg_tmr_timer0_int_len 1
+#define	reg_tmr_timer0_int_lsb 0
+#define xd_p_reg_tmr_timer0_rst	0xA0CA
+#define	reg_tmr_timer0_rst_pos 3
+#define	reg_tmr_timer0_rst_len 1
+#define	reg_tmr_timer0_rst_lsb 0
+#define xd_r_reg_tmr_timer0_count_7_0	0xA0CB
+#define	reg_tmr_timer0_count_7_0_pos 0
+#define	reg_tmr_timer0_count_7_0_len 8
+#define	reg_tmr_timer0_count_7_0_lsb 0
+#define xd_r_reg_tmr_timer0_count_15_8	0xA0CC
+#define	reg_tmr_timer0_count_15_8_pos 0
+#define	reg_tmr_timer0_count_15_8_len 8
+#define	reg_tmr_timer0_count_15_8_lsb 8
+#define xd_p_reg_suspend	0xA0CD
+#define	reg_suspend_pos 0
+#define	reg_suspend_len 1
+#define	reg_suspend_lsb 0
+#define xd_p_reg_suspend_rdy	0xA0CD
+#define	reg_suspend_rdy_pos 1
+#define	reg_suspend_rdy_len 1
+#define	reg_suspend_rdy_lsb 0
+#define xd_p_reg_resume	0xA0CD
+#define	reg_resume_pos 2
+#define	reg_resume_len 1
+#define	reg_resume_lsb 0
+#define xd_p_reg_resume_rdy	0xA0CD
+#define	reg_resume_rdy_pos 3
+#define	reg_resume_rdy_len 1
+#define	reg_resume_rdy_lsb 0
+#define xd_p_reg_fmf	0xA0CE
+#define	reg_fmf_pos 0
+#define	reg_fmf_len 8
+#define	reg_fmf_lsb 0
+#define xd_p_ccid_accumulate_num_2k_7_0	0xA100
+#define	ccid_accumulate_num_2k_7_0_pos 0
+#define	ccid_accumulate_num_2k_7_0_len 8
+#define	ccid_accumulate_num_2k_7_0_lsb 0
+#define xd_p_ccid_accumulate_num_2k_12_8	0xA101
+#define	ccid_accumulate_num_2k_12_8_pos 0
+#define	ccid_accumulate_num_2k_12_8_len 5
+#define	ccid_accumulate_num_2k_12_8_lsb 8
+#define xd_p_ccid_accumulate_num_8k_7_0	0xA102
+#define	ccid_accumulate_num_8k_7_0_pos 0
+#define	ccid_accumulate_num_8k_7_0_len 8
+#define	ccid_accumulate_num_8k_7_0_lsb 0
+#define xd_p_ccid_accumulate_num_8k_14_8	0xA103
+#define	ccid_accumulate_num_8k_14_8_pos 0
+#define	ccid_accumulate_num_8k_14_8_len 7
+#define	ccid_accumulate_num_8k_14_8_lsb 8
+#define xd_p_ccid_desired_level_0	0xA103
+#define	ccid_desired_level_0_pos 7
+#define	ccid_desired_level_0_len 1
+#define	ccid_desired_level_0_lsb 0
+#define xd_p_ccid_desired_level_8_1	0xA104
+#define	ccid_desired_level_8_1_pos 0
+#define	ccid_desired_level_8_1_len 8
+#define	ccid_desired_level_8_1_lsb 1
+#define xd_p_ccid_apply_delay	0xA105
+#define	ccid_apply_delay_pos 0
+#define	ccid_apply_delay_len 7
+#define	ccid_apply_delay_lsb 0
+#define xd_p_ccid_CCID_Threshold1	0xA106
+#define	ccid_CCID_Threshold1_pos 0
+#define	ccid_CCID_Threshold1_len 8
+#define	ccid_CCID_Threshold1_lsb 0
+#define xd_p_ccid_CCID_Threshold2	0xA107
+#define	ccid_CCID_Threshold2_pos 0
+#define	ccid_CCID_Threshold2_len 8
+#define	ccid_CCID_Threshold2_lsb 0
+#define xd_p_reg_ccid_gain_scale	0xA108
+#define	reg_ccid_gain_scale_pos 0
+#define	reg_ccid_gain_scale_len 4
+#define	reg_ccid_gain_scale_lsb 0
+#define xd_p_reg_ccid2_passband_gain_set	0xA108
+#define	reg_ccid2_passband_gain_set_pos 4
+#define	reg_ccid2_passband_gain_set_len 4
+#define	reg_ccid2_passband_gain_set_lsb 0
+#define xd_r_ccid_multiplier_7_0	0xA109
+#define	ccid_multiplier_7_0_pos 0
+#define	ccid_multiplier_7_0_len 8
+#define	ccid_multiplier_7_0_lsb 0
+#define xd_r_ccid_multiplier_15_8	0xA10A
+#define	ccid_multiplier_15_8_pos 0
+#define	ccid_multiplier_15_8_len 8
+#define	ccid_multiplier_15_8_lsb 8
+#define xd_r_ccid_right_shift_bits	0xA10B
+#define	ccid_right_shift_bits_pos 0
+#define	ccid_right_shift_bits_len 4
+#define	ccid_right_shift_bits_lsb 0
+#define xd_r_reg_ccid_sx_7_0	0xA10C
+#define	reg_ccid_sx_7_0_pos 0
+#define	reg_ccid_sx_7_0_len 8
+#define	reg_ccid_sx_7_0_lsb 0
+#define xd_r_reg_ccid_sx_15_8	0xA10D
+#define	reg_ccid_sx_15_8_pos 0
+#define	reg_ccid_sx_15_8_len 8
+#define	reg_ccid_sx_15_8_lsb 8
+#define xd_r_reg_ccid_sx_21_16	0xA10E
+#define	reg_ccid_sx_21_16_pos 0
+#define	reg_ccid_sx_21_16_len 6
+#define	reg_ccid_sx_21_16_lsb 16
+#define xd_r_reg_ccid_sy_7_0	0xA110
+#define	reg_ccid_sy_7_0_pos 0
+#define	reg_ccid_sy_7_0_len 8
+#define	reg_ccid_sy_7_0_lsb 0
+#define xd_r_reg_ccid_sy_15_8	0xA111
+#define	reg_ccid_sy_15_8_pos 0
+#define	reg_ccid_sy_15_8_len 8
+#define	reg_ccid_sy_15_8_lsb 8
+#define xd_r_reg_ccid_sy_23_16	0xA112
+#define	reg_ccid_sy_23_16_pos 0
+#define	reg_ccid_sy_23_16_len 8
+#define	reg_ccid_sy_23_16_lsb 16
+#define xd_r_reg_ccid2_sz_7_0	0xA114
+#define	reg_ccid2_sz_7_0_pos 0
+#define	reg_ccid2_sz_7_0_len 8
+#define	reg_ccid2_sz_7_0_lsb 0
+#define xd_r_reg_ccid2_sz_15_8	0xA115
+#define	reg_ccid2_sz_15_8_pos 0
+#define	reg_ccid2_sz_15_8_len 8
+#define	reg_ccid2_sz_15_8_lsb 8
+#define xd_r_reg_ccid2_sz_23_16	0xA116
+#define	reg_ccid2_sz_23_16_pos 0
+#define	reg_ccid2_sz_23_16_len 8
+#define	reg_ccid2_sz_23_16_lsb 16
+#define xd_r_reg_ccid2_sz_25_24	0xA117
+#define	reg_ccid2_sz_25_24_pos 0
+#define	reg_ccid2_sz_25_24_len 2
+#define	reg_ccid2_sz_25_24_lsb 24
+#define xd_r_reg_ccid2_sy_7_0	0xA118
+#define	reg_ccid2_sy_7_0_pos 0
+#define	reg_ccid2_sy_7_0_len 8
+#define	reg_ccid2_sy_7_0_lsb 0
+#define xd_r_reg_ccid2_sy_15_8	0xA119
+#define	reg_ccid2_sy_15_8_pos 0
+#define	reg_ccid2_sy_15_8_len 8
+#define	reg_ccid2_sy_15_8_lsb 8
+#define xd_r_reg_ccid2_sy_23_16	0xA11A
+#define	reg_ccid2_sy_23_16_pos 0
+#define	reg_ccid2_sy_23_16_len 8
+#define	reg_ccid2_sy_23_16_lsb 16
+#define xd_r_reg_ccid2_sy_25_24	0xA11B
+#define	reg_ccid2_sy_25_24_pos 0
+#define	reg_ccid2_sy_25_24_len 2
+#define	reg_ccid2_sy_25_24_lsb 24
+#define xd_p_dagc1_accumulate_num_2k_7_0	0xA120
+#define	dagc1_accumulate_num_2k_7_0_pos 0
+#define	dagc1_accumulate_num_2k_7_0_len 8
+#define	dagc1_accumulate_num_2k_7_0_lsb 0
+#define xd_p_dagc1_accumulate_num_2k_12_8	0xA121
+#define	dagc1_accumulate_num_2k_12_8_pos 0
+#define	dagc1_accumulate_num_2k_12_8_len 5
+#define	dagc1_accumulate_num_2k_12_8_lsb 8
+#define xd_p_dagc1_accumulate_num_8k_7_0	0xA122
+#define	dagc1_accumulate_num_8k_7_0_pos 0
+#define	dagc1_accumulate_num_8k_7_0_len 8
+#define	dagc1_accumulate_num_8k_7_0_lsb 0
+#define xd_p_dagc1_accumulate_num_8k_14_8	0xA123
+#define	dagc1_accumulate_num_8k_14_8_pos 0
+#define	dagc1_accumulate_num_8k_14_8_len 7
+#define	dagc1_accumulate_num_8k_14_8_lsb 8
+#define xd_p_dagc1_desired_level_0	0xA123
+#define	dagc1_desired_level_0_pos 7
+#define	dagc1_desired_level_0_len 1
+#define	dagc1_desired_level_0_lsb 0
+#define xd_p_dagc1_desired_level_8_1	0xA124
+#define	dagc1_desired_level_8_1_pos 0
+#define	dagc1_desired_level_8_1_len 8
+#define	dagc1_desired_level_8_1_lsb 1
+#define xd_p_dagc1_apply_delay	0xA125
+#define	dagc1_apply_delay_pos 0
+#define	dagc1_apply_delay_len 7
+#define	dagc1_apply_delay_lsb 0
+#define xd_p_dagc1_bypass_scale_ctl	0xA126
+#define	dagc1_bypass_scale_ctl_pos 0
+#define	dagc1_bypass_scale_ctl_len 2
+#define	dagc1_bypass_scale_ctl_lsb 0
+#define xd_p_reg_dagc1_in_sat_cnt_7_0	0xA127
+#define	reg_dagc1_in_sat_cnt_7_0_pos 0
+#define	reg_dagc1_in_sat_cnt_7_0_len 8
+#define	reg_dagc1_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc1_in_sat_cnt_15_8	0xA128
+#define	reg_dagc1_in_sat_cnt_15_8_pos 0
+#define	reg_dagc1_in_sat_cnt_15_8_len 8
+#define	reg_dagc1_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc1_in_sat_cnt_23_16	0xA129
+#define	reg_dagc1_in_sat_cnt_23_16_pos 0
+#define	reg_dagc1_in_sat_cnt_23_16_len 8
+#define	reg_dagc1_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc1_in_sat_cnt_31_24	0xA12A
+#define	reg_dagc1_in_sat_cnt_31_24_pos 0
+#define	reg_dagc1_in_sat_cnt_31_24_len 8
+#define	reg_dagc1_in_sat_cnt_31_24_lsb 24
+#define xd_p_reg_dagc1_out_sat_cnt_7_0	0xA12B
+#define	reg_dagc1_out_sat_cnt_7_0_pos 0
+#define	reg_dagc1_out_sat_cnt_7_0_len 8
+#define	reg_dagc1_out_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc1_out_sat_cnt_15_8	0xA12C
+#define	reg_dagc1_out_sat_cnt_15_8_pos 0
+#define	reg_dagc1_out_sat_cnt_15_8_len 8
+#define	reg_dagc1_out_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc1_out_sat_cnt_23_16	0xA12D
+#define	reg_dagc1_out_sat_cnt_23_16_pos 0
+#define	reg_dagc1_out_sat_cnt_23_16_len 8
+#define	reg_dagc1_out_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc1_out_sat_cnt_31_24	0xA12E
+#define	reg_dagc1_out_sat_cnt_31_24_pos 0
+#define	reg_dagc1_out_sat_cnt_31_24_len 8
+#define	reg_dagc1_out_sat_cnt_31_24_lsb 24
+#define xd_r_dagc1_multiplier_7_0	0xA136
+#define	dagc1_multiplier_7_0_pos 0
+#define	dagc1_multiplier_7_0_len 8
+#define	dagc1_multiplier_7_0_lsb 0
+#define xd_r_dagc1_multiplier_15_8	0xA137
+#define	dagc1_multiplier_15_8_pos 0
+#define	dagc1_multiplier_15_8_len 8
+#define	dagc1_multiplier_15_8_lsb 8
+#define xd_r_dagc1_right_shift_bits	0xA138
+#define	dagc1_right_shift_bits_pos 0
+#define	dagc1_right_shift_bits_len 4
+#define	dagc1_right_shift_bits_lsb 0
+#define xd_p_reg_bfs_fcw_7_0	0xA140
+#define	reg_bfs_fcw_7_0_pos 0
+#define	reg_bfs_fcw_7_0_len 8
+#define	reg_bfs_fcw_7_0_lsb 0
+#define xd_p_reg_bfs_fcw_15_8	0xA141
+#define	reg_bfs_fcw_15_8_pos 0
+#define	reg_bfs_fcw_15_8_len 8
+#define	reg_bfs_fcw_15_8_lsb 8
+#define xd_p_reg_bfs_fcw_22_16	0xA142
+#define	reg_bfs_fcw_22_16_pos 0
+#define	reg_bfs_fcw_22_16_len 7
+#define	reg_bfs_fcw_22_16_lsb 16
+#define xd_p_reg_antif_sf_7_0	0xA144
+#define	reg_antif_sf_7_0_pos 0
+#define	reg_antif_sf_7_0_len 8
+#define	reg_antif_sf_7_0_lsb 0
+#define xd_p_reg_antif_sf_11_8	0xA145
+#define	reg_antif_sf_11_8_pos 0
+#define	reg_antif_sf_11_8_len 4
+#define	reg_antif_sf_11_8_lsb 8
+#define xd_r_bfs_fcw_q_7_0	0xA150
+#define	bfs_fcw_q_7_0_pos 0
+#define	bfs_fcw_q_7_0_len 8
+#define	bfs_fcw_q_7_0_lsb 0
+#define xd_r_bfs_fcw_q_15_8	0xA151
+#define	bfs_fcw_q_15_8_pos 0
+#define	bfs_fcw_q_15_8_len 8
+#define	bfs_fcw_q_15_8_lsb 8
+#define xd_r_bfs_fcw_q_22_16	0xA152
+#define	bfs_fcw_q_22_16_pos 0
+#define	bfs_fcw_q_22_16_len 7
+#define	bfs_fcw_q_22_16_lsb 16
+#define xd_p_reg_dca_enu	0xA160
+#define	reg_dca_enu_pos 0
+#define	reg_dca_enu_len 1
+#define	reg_dca_enu_lsb 0
+#define xd_p_reg_dca_enl	0xA160
+#define	reg_dca_enl_pos 1
+#define	reg_dca_enl_len 1
+#define	reg_dca_enl_lsb 0
+#define xd_p_reg_dca_lower_chip	0xA160
+#define	reg_dca_lower_chip_pos 2
+#define	reg_dca_lower_chip_len 1
+#define	reg_dca_lower_chip_lsb 0
+#define xd_p_reg_dca_upper_chip	0xA160
+#define	reg_dca_upper_chip_pos 3
+#define	reg_dca_upper_chip_len 1
+#define	reg_dca_upper_chip_lsb 0
+#define xd_p_reg_dca_platch	0xA160
+#define	reg_dca_platch_pos 4
+#define	reg_dca_platch_len 1
+#define	reg_dca_platch_lsb 0
+#define xd_p_reg_dca_th	0xA161
+#define	reg_dca_th_pos 0
+#define	reg_dca_th_len 5
+#define	reg_dca_th_lsb 0
+#define xd_p_reg_dca_scale	0xA162
+#define	reg_dca_scale_pos 0
+#define	reg_dca_scale_len 4
+#define	reg_dca_scale_lsb 0
+#define xd_p_reg_dca_tone_7_0	0xA163
+#define	reg_dca_tone_7_0_pos 0
+#define	reg_dca_tone_7_0_len 8
+#define	reg_dca_tone_7_0_lsb 0
+#define xd_p_reg_dca_tone_12_8	0xA164
+#define	reg_dca_tone_12_8_pos 0
+#define	reg_dca_tone_12_8_len 5
+#define	reg_dca_tone_12_8_lsb 8
+#define xd_p_reg_dca_time_7_0	0xA165
+#define	reg_dca_time_7_0_pos 0
+#define	reg_dca_time_7_0_len 8
+#define	reg_dca_time_7_0_lsb 0
+#define xd_p_reg_dca_time_15_8	0xA166
+#define	reg_dca_time_15_8_pos 0
+#define	reg_dca_time_15_8_len 8
+#define	reg_dca_time_15_8_lsb 8
+#define xd_r_dcasm	0xA167
+#define	dcasm_pos 0
+#define	dcasm_len 3
+#define	dcasm_lsb 0
+#define xd_p_reg_qnt_valuew_7_0	0xA168
+#define	reg_qnt_valuew_7_0_pos 0
+#define	reg_qnt_valuew_7_0_len 8
+#define	reg_qnt_valuew_7_0_lsb 0
+#define xd_p_reg_qnt_valuew_10_8	0xA169
+#define	reg_qnt_valuew_10_8_pos 0
+#define	reg_qnt_valuew_10_8_len 3
+#define	reg_qnt_valuew_10_8_lsb 8
+#define xd_p_dca_sbx_gain_diff_7_0	0xA16A
+#define	dca_sbx_gain_diff_7_0_pos 0
+#define	dca_sbx_gain_diff_7_0_len 8
+#define	dca_sbx_gain_diff_7_0_lsb 0
+#define xd_p_dca_sbx_gain_diff_9_8	0xA16B
+#define	dca_sbx_gain_diff_9_8_pos 0
+#define	dca_sbx_gain_diff_9_8_len 2
+#define	dca_sbx_gain_diff_9_8_lsb 8
+#define xd_p_reg_dca_stand_alone	0xA16C
+#define	reg_dca_stand_alone_pos 0
+#define	reg_dca_stand_alone_len 1
+#define	reg_dca_stand_alone_lsb 0
+#define xd_p_reg_dca_upper_out_en	0xA16C
+#define	reg_dca_upper_out_en_pos 1
+#define	reg_dca_upper_out_en_len 1
+#define	reg_dca_upper_out_en_lsb 0
+#define xd_p_reg_dca_rc_en	0xA16C
+#define	reg_dca_rc_en_pos 2
+#define	reg_dca_rc_en_len 1
+#define	reg_dca_rc_en_lsb 0
+#define xd_p_reg_dca_retrain_send	0xA16C
+#define	reg_dca_retrain_send_pos 3
+#define	reg_dca_retrain_send_len 1
+#define	reg_dca_retrain_send_lsb 0
+#define xd_p_reg_dca_retrain_rec	0xA16C
+#define	reg_dca_retrain_rec_pos 4
+#define	reg_dca_retrain_rec_len 1
+#define	reg_dca_retrain_rec_lsb 0
+#define xd_p_reg_dca_api_tpsrdy	0xA16C
+#define	reg_dca_api_tpsrdy_pos 5
+#define	reg_dca_api_tpsrdy_len 1
+#define	reg_dca_api_tpsrdy_lsb 0
+#define xd_p_reg_dca_symbol_gap	0xA16D
+#define	reg_dca_symbol_gap_pos 0
+#define	reg_dca_symbol_gap_len 4
+#define	reg_dca_symbol_gap_lsb 0
+#define xd_p_reg_qnt_nfvaluew_7_0	0xA16E
+#define	reg_qnt_nfvaluew_7_0_pos 0
+#define	reg_qnt_nfvaluew_7_0_len 8
+#define	reg_qnt_nfvaluew_7_0_lsb 0
+#define xd_p_reg_qnt_nfvaluew_10_8	0xA16F
+#define	reg_qnt_nfvaluew_10_8_pos 0
+#define	reg_qnt_nfvaluew_10_8_len 3
+#define	reg_qnt_nfvaluew_10_8_lsb 8
+#define xd_p_reg_qnt_flatness_thr_7_0	0xA170
+#define	reg_qnt_flatness_thr_7_0_pos 0
+#define	reg_qnt_flatness_thr_7_0_len 8
+#define	reg_qnt_flatness_thr_7_0_lsb 0
+#define xd_p_reg_qnt_flatness_thr_9_8	0xA171
+#define	reg_qnt_flatness_thr_9_8_pos 0
+#define	reg_qnt_flatness_thr_9_8_len 2
+#define	reg_qnt_flatness_thr_9_8_lsb 8
+#define xd_p_reg_dca_tone_idx_5_0	0xA171
+#define	reg_dca_tone_idx_5_0_pos 2
+#define	reg_dca_tone_idx_5_0_len 6
+#define	reg_dca_tone_idx_5_0_lsb 0
+#define xd_p_reg_dca_tone_idx_12_6	0xA172
+#define	reg_dca_tone_idx_12_6_pos 0
+#define	reg_dca_tone_idx_12_6_len 7
+#define	reg_dca_tone_idx_12_6_lsb 6
+#define xd_p_reg_dca_data_vld	0xA173
+#define	reg_dca_data_vld_pos 0
+#define	reg_dca_data_vld_len 1
+#define	reg_dca_data_vld_lsb 0
+#define xd_p_reg_dca_read_update	0xA173
+#define	reg_dca_read_update_pos 1
+#define	reg_dca_read_update_len 1
+#define	reg_dca_read_update_lsb 0
+#define xd_r_reg_dca_data_re_5_0	0xA173
+#define	reg_dca_data_re_5_0_pos 2
+#define	reg_dca_data_re_5_0_len 6
+#define	reg_dca_data_re_5_0_lsb 0
+#define xd_r_reg_dca_data_re_10_6	0xA174
+#define	reg_dca_data_re_10_6_pos 0
+#define	reg_dca_data_re_10_6_len 5
+#define	reg_dca_data_re_10_6_lsb 6
+#define xd_r_reg_dca_data_im_7_0	0xA175
+#define	reg_dca_data_im_7_0_pos 0
+#define	reg_dca_data_im_7_0_len 8
+#define	reg_dca_data_im_7_0_lsb 0
+#define xd_r_reg_dca_data_im_10_8	0xA176
+#define	reg_dca_data_im_10_8_pos 0
+#define	reg_dca_data_im_10_8_len 3
+#define	reg_dca_data_im_10_8_lsb 8
+#define xd_r_reg_dca_data_h2_7_0	0xA178
+#define	reg_dca_data_h2_7_0_pos 0
+#define	reg_dca_data_h2_7_0_len 8
+#define	reg_dca_data_h2_7_0_lsb 0
+#define xd_r_reg_dca_data_h2_9_8	0xA179
+#define	reg_dca_data_h2_9_8_pos 0
+#define	reg_dca_data_h2_9_8_len 2
+#define	reg_dca_data_h2_9_8_lsb 8
+#define xd_p_reg_f_adc_7_0	0xA180
+#define	reg_f_adc_7_0_pos 0
+#define	reg_f_adc_7_0_len 8
+#define	reg_f_adc_7_0_lsb 0
+#define xd_p_reg_f_adc_15_8	0xA181
+#define	reg_f_adc_15_8_pos 0
+#define	reg_f_adc_15_8_len 8
+#define	reg_f_adc_15_8_lsb 8
+#define xd_p_reg_f_adc_23_16	0xA182
+#define	reg_f_adc_23_16_pos 0
+#define	reg_f_adc_23_16_len 8
+#define	reg_f_adc_23_16_lsb 16
+#define xd_r_intp_mu_7_0	0xA190
+#define	intp_mu_7_0_pos 0
+#define	intp_mu_7_0_len 8
+#define	intp_mu_7_0_lsb 0
+#define xd_r_intp_mu_15_8	0xA191
+#define	intp_mu_15_8_pos 0
+#define	intp_mu_15_8_len 8
+#define	intp_mu_15_8_lsb 8
+#define xd_r_intp_mu_19_16	0xA192
+#define	intp_mu_19_16_pos 0
+#define	intp_mu_19_16_len 4
+#define	intp_mu_19_16_lsb 16
+#define xd_p_reg_agc_rst	0xA1A0
+#define	reg_agc_rst_pos 0
+#define	reg_agc_rst_len 1
+#define	reg_agc_rst_lsb 0
+#define xd_p_rf_agc_en	0xA1A0
+#define	rf_agc_en_pos 1
+#define	rf_agc_en_len 1
+#define	rf_agc_en_lsb 0
+#define xd_p_rf_agc_dis	0xA1A0
+#define	rf_agc_dis_pos 2
+#define	rf_agc_dis_len 1
+#define	rf_agc_dis_lsb 0
+#define xd_p_if_agc_rst	0xA1A0
+#define	if_agc_rst_pos 3
+#define	if_agc_rst_len 1
+#define	if_agc_rst_lsb 0
+#define xd_p_if_agc_en	0xA1A0
+#define	if_agc_en_pos 4
+#define	if_agc_en_len 1
+#define	if_agc_en_lsb 0
+#define xd_p_if_agc_dis	0xA1A0
+#define	if_agc_dis_pos 5
+#define	if_agc_dis_len 1
+#define	if_agc_dis_lsb 0
+#define xd_p_agc_lock	0xA1A0
+#define	agc_lock_pos 6
+#define	agc_lock_len 1
+#define	agc_lock_lsb 0
+#define xd_p_reg_tinr_rst	0xA1A1
+#define	reg_tinr_rst_pos 0
+#define	reg_tinr_rst_len 1
+#define	reg_tinr_rst_lsb 0
+#define xd_p_reg_tinr_en	0xA1A1
+#define	reg_tinr_en_pos 1
+#define	reg_tinr_en_len 1
+#define	reg_tinr_en_lsb 0
+#define xd_p_reg_ccifs_en	0xA1A2
+#define	reg_ccifs_en_pos 0
+#define	reg_ccifs_en_len 1
+#define	reg_ccifs_en_lsb 0
+#define xd_p_reg_ccifs_dis	0xA1A2
+#define	reg_ccifs_dis_pos 1
+#define	reg_ccifs_dis_len 1
+#define	reg_ccifs_dis_lsb 0
+#define xd_p_reg_ccifs_rst	0xA1A2
+#define	reg_ccifs_rst_pos 2
+#define	reg_ccifs_rst_len 1
+#define	reg_ccifs_rst_lsb 0
+#define xd_p_reg_ccifs_byp	0xA1A2
+#define	reg_ccifs_byp_pos 3
+#define	reg_ccifs_byp_len 1
+#define	reg_ccifs_byp_lsb 0
+#define xd_p_reg_ccif_en	0xA1A3
+#define	reg_ccif_en_pos 0
+#define	reg_ccif_en_len 1
+#define	reg_ccif_en_lsb 0
+#define xd_p_reg_ccif_dis	0xA1A3
+#define	reg_ccif_dis_pos 1
+#define	reg_ccif_dis_len 1
+#define	reg_ccif_dis_lsb 0
+#define xd_p_reg_ccif_rst	0xA1A3
+#define	reg_ccif_rst_pos 2
+#define	reg_ccif_rst_len 1
+#define	reg_ccif_rst_lsb 0
+#define xd_p_reg_ccif_byp	0xA1A3
+#define	reg_ccif_byp_pos 3
+#define	reg_ccif_byp_len 1
+#define	reg_ccif_byp_lsb 0
+#define xd_p_dagc1_rst	0xA1A4
+#define	dagc1_rst_pos 0
+#define	dagc1_rst_len 1
+#define	dagc1_rst_lsb 0
+#define xd_p_dagc1_en	0xA1A4
+#define	dagc1_en_pos 1
+#define	dagc1_en_len 1
+#define	dagc1_en_lsb 0
+#define xd_p_dagc1_mode	0xA1A4
+#define	dagc1_mode_pos 2
+#define	dagc1_mode_len 2
+#define	dagc1_mode_lsb 0
+#define xd_p_dagc1_done	0xA1A4
+#define	dagc1_done_pos 4
+#define	dagc1_done_len 1
+#define	dagc1_done_lsb 0
+#define xd_p_ccid_rst	0xA1A5
+#define	ccid_rst_pos 0
+#define	ccid_rst_len 1
+#define	ccid_rst_lsb 0
+#define xd_p_ccid_en	0xA1A5
+#define	ccid_en_pos 1
+#define	ccid_en_len 1
+#define	ccid_en_lsb 0
+#define xd_p_ccid_mode	0xA1A5
+#define	ccid_mode_pos 2
+#define	ccid_mode_len 2
+#define	ccid_mode_lsb 0
+#define xd_p_ccid_done	0xA1A5
+#define	ccid_done_pos 4
+#define	ccid_done_len 1
+#define	ccid_done_lsb 0
+#define xd_r_ccid_deted	0xA1A5
+#define	ccid_deted_pos 5
+#define	ccid_deted_len 1
+#define	ccid_deted_lsb 0
+#define xd_p_ccid2_en	0xA1A5
+#define	ccid2_en_pos 6
+#define	ccid2_en_len 1
+#define	ccid2_en_lsb 0
+#define xd_p_ccid2_done	0xA1A5
+#define	ccid2_done_pos 7
+#define	ccid2_done_len 1
+#define	ccid2_done_lsb 0
+#define xd_p_reg_bfs_en	0xA1A6
+#define	reg_bfs_en_pos 0
+#define	reg_bfs_en_len 1
+#define	reg_bfs_en_lsb 0
+#define xd_p_reg_bfs_dis	0xA1A6
+#define	reg_bfs_dis_pos 1
+#define	reg_bfs_dis_len 1
+#define	reg_bfs_dis_lsb 0
+#define xd_p_reg_bfs_rst	0xA1A6
+#define	reg_bfs_rst_pos 2
+#define	reg_bfs_rst_len 1
+#define	reg_bfs_rst_lsb 0
+#define xd_p_reg_bfs_byp	0xA1A6
+#define	reg_bfs_byp_pos 3
+#define	reg_bfs_byp_len 1
+#define	reg_bfs_byp_lsb 0
+#define xd_p_reg_antif_en	0xA1A7
+#define	reg_antif_en_pos 0
+#define	reg_antif_en_len 1
+#define	reg_antif_en_lsb 0
+#define xd_p_reg_antif_dis	0xA1A7
+#define	reg_antif_dis_pos 1
+#define	reg_antif_dis_len 1
+#define	reg_antif_dis_lsb 0
+#define xd_p_reg_antif_rst	0xA1A7
+#define	reg_antif_rst_pos 2
+#define	reg_antif_rst_len 1
+#define	reg_antif_rst_lsb 0
+#define xd_p_reg_antif_byp	0xA1A7
+#define	reg_antif_byp_pos 3
+#define	reg_antif_byp_len 1
+#define	reg_antif_byp_lsb 0
+#define xd_p_intp_en	0xA1A8
+#define	intp_en_pos 0
+#define	intp_en_len 1
+#define	intp_en_lsb 0
+#define xd_p_intp_dis	0xA1A8
+#define	intp_dis_pos 1
+#define	intp_dis_len 1
+#define	intp_dis_lsb 0
+#define xd_p_intp_rst	0xA1A8
+#define	intp_rst_pos 2
+#define	intp_rst_len 1
+#define	intp_rst_lsb 0
+#define xd_p_intp_byp	0xA1A8
+#define	intp_byp_pos 3
+#define	intp_byp_len 1
+#define	intp_byp_lsb 0
+#define xd_p_reg_acif_en	0xA1A9
+#define	reg_acif_en_pos 0
+#define	reg_acif_en_len 1
+#define	reg_acif_en_lsb 0
+#define xd_p_reg_acif_dis	0xA1A9
+#define	reg_acif_dis_pos 1
+#define	reg_acif_dis_len 1
+#define	reg_acif_dis_lsb 0
+#define xd_p_reg_acif_rst	0xA1A9
+#define	reg_acif_rst_pos 2
+#define	reg_acif_rst_len 1
+#define	reg_acif_rst_lsb 0
+#define xd_p_reg_acif_byp	0xA1A9
+#define	reg_acif_byp_pos 3
+#define	reg_acif_byp_len 1
+#define	reg_acif_byp_lsb 0
+#define xd_p_reg_acif_sync_mode	0xA1A9
+#define	reg_acif_sync_mode_pos 4
+#define	reg_acif_sync_mode_len 1
+#define	reg_acif_sync_mode_lsb 0
+#define xd_p_dagc2_rst	0xA1AA
+#define	dagc2_rst_pos 0
+#define	dagc2_rst_len 1
+#define	dagc2_rst_lsb 0
+#define xd_p_dagc2_en	0xA1AA
+#define	dagc2_en_pos 1
+#define	dagc2_en_len 1
+#define	dagc2_en_lsb 0
+#define xd_p_dagc2_mode	0xA1AA
+#define	dagc2_mode_pos 2
+#define	dagc2_mode_len 2
+#define	dagc2_mode_lsb 0
+#define xd_p_dagc2_done	0xA1AA
+#define	dagc2_done_pos 4
+#define	dagc2_done_len 1
+#define	dagc2_done_lsb 0
+#define xd_p_reg_dca_en	0xA1AB
+#define	reg_dca_en_pos 0
+#define	reg_dca_en_len 1
+#define	reg_dca_en_lsb 0
+#define xd_p_dagc2_accumulate_num_2k_7_0	0xA1C0
+#define	dagc2_accumulate_num_2k_7_0_pos 0
+#define	dagc2_accumulate_num_2k_7_0_len 8
+#define	dagc2_accumulate_num_2k_7_0_lsb 0
+#define xd_p_dagc2_accumulate_num_2k_12_8	0xA1C1
+#define	dagc2_accumulate_num_2k_12_8_pos 0
+#define	dagc2_accumulate_num_2k_12_8_len 5
+#define	dagc2_accumulate_num_2k_12_8_lsb 8
+#define xd_p_dagc2_accumulate_num_8k_7_0	0xA1C2
+#define	dagc2_accumulate_num_8k_7_0_pos 0
+#define	dagc2_accumulate_num_8k_7_0_len 8
+#define	dagc2_accumulate_num_8k_7_0_lsb 0
+#define xd_p_dagc2_accumulate_num_8k_12_8	0xA1C3
+#define	dagc2_accumulate_num_8k_12_8_pos 0
+#define	dagc2_accumulate_num_8k_12_8_len 5
+#define	dagc2_accumulate_num_8k_12_8_lsb 8
+#define xd_p_dagc2_desired_level_2_0	0xA1C3
+#define	dagc2_desired_level_2_0_pos 5
+#define	dagc2_desired_level_2_0_len 3
+#define	dagc2_desired_level_2_0_lsb 0
+#define xd_p_dagc2_desired_level_8_3	0xA1C4
+#define	dagc2_desired_level_8_3_pos 0
+#define	dagc2_desired_level_8_3_len 6
+#define	dagc2_desired_level_8_3_lsb 3
+#define xd_p_dagc2_apply_delay	0xA1C5
+#define	dagc2_apply_delay_pos 0
+#define	dagc2_apply_delay_len 7
+#define	dagc2_apply_delay_lsb 0
+#define xd_p_dagc2_bypass_scale_ctl	0xA1C6
+#define	dagc2_bypass_scale_ctl_pos 0
+#define	dagc2_bypass_scale_ctl_len 3
+#define	dagc2_bypass_scale_ctl_lsb 0
+#define xd_p_dagc2_programmable_shift1	0xA1C7
+#define	dagc2_programmable_shift1_pos 0
+#define	dagc2_programmable_shift1_len 8
+#define	dagc2_programmable_shift1_lsb 0
+#define xd_p_dagc2_programmable_shift2	0xA1C8
+#define	dagc2_programmable_shift2_pos 0
+#define	dagc2_programmable_shift2_len 8
+#define	dagc2_programmable_shift2_lsb 0
+#define xd_p_reg_dagc2_in_sat_cnt_7_0	0xA1C9
+#define	reg_dagc2_in_sat_cnt_7_0_pos 0
+#define	reg_dagc2_in_sat_cnt_7_0_len 8
+#define	reg_dagc2_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc2_in_sat_cnt_15_8	0xA1CA
+#define	reg_dagc2_in_sat_cnt_15_8_pos 0
+#define	reg_dagc2_in_sat_cnt_15_8_len 8
+#define	reg_dagc2_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc2_in_sat_cnt_23_16	0xA1CB
+#define	reg_dagc2_in_sat_cnt_23_16_pos 0
+#define	reg_dagc2_in_sat_cnt_23_16_len 8
+#define	reg_dagc2_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc2_in_sat_cnt_31_24	0xA1CC
+#define	reg_dagc2_in_sat_cnt_31_24_pos 0
+#define	reg_dagc2_in_sat_cnt_31_24_len 8
+#define	reg_dagc2_in_sat_cnt_31_24_lsb 24
+#define xd_p_reg_dagc2_out_sat_cnt_7_0	0xA1CD
+#define	reg_dagc2_out_sat_cnt_7_0_pos 0
+#define	reg_dagc2_out_sat_cnt_7_0_len 8
+#define	reg_dagc2_out_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc2_out_sat_cnt_15_8	0xA1CE
+#define	reg_dagc2_out_sat_cnt_15_8_pos 0
+#define	reg_dagc2_out_sat_cnt_15_8_len 8
+#define	reg_dagc2_out_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc2_out_sat_cnt_23_16	0xA1CF
+#define	reg_dagc2_out_sat_cnt_23_16_pos 0
+#define	reg_dagc2_out_sat_cnt_23_16_len 8
+#define	reg_dagc2_out_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc2_out_sat_cnt_31_24	0xA1D0
+#define	reg_dagc2_out_sat_cnt_31_24_pos 0
+#define	reg_dagc2_out_sat_cnt_31_24_len 8
+#define	reg_dagc2_out_sat_cnt_31_24_lsb 24
+#define xd_r_dagc2_multiplier_7_0	0xA1D6
+#define	dagc2_multiplier_7_0_pos 0
+#define	dagc2_multiplier_7_0_len 8
+#define	dagc2_multiplier_7_0_lsb 0
+#define xd_r_dagc2_multiplier_15_8	0xA1D7
+#define	dagc2_multiplier_15_8_pos 0
+#define	dagc2_multiplier_15_8_len 8
+#define	dagc2_multiplier_15_8_lsb 8
+#define xd_r_dagc2_right_shift_bits	0xA1D8
+#define	dagc2_right_shift_bits_pos 0
+#define	dagc2_right_shift_bits_len 4
+#define	dagc2_right_shift_bits_lsb 0
+#define xd_p_cfoe_NS_coeff1_7_0	0xA200
+#define	cfoe_NS_coeff1_7_0_pos 0
+#define	cfoe_NS_coeff1_7_0_len 8
+#define	cfoe_NS_coeff1_7_0_lsb 0
+#define xd_p_cfoe_NS_coeff1_15_8	0xA201
+#define	cfoe_NS_coeff1_15_8_pos 0
+#define	cfoe_NS_coeff1_15_8_len 8
+#define	cfoe_NS_coeff1_15_8_lsb 8
+#define xd_p_cfoe_NS_coeff1_23_16	0xA202
+#define	cfoe_NS_coeff1_23_16_pos 0
+#define	cfoe_NS_coeff1_23_16_len 8
+#define	cfoe_NS_coeff1_23_16_lsb 16
+#define xd_p_cfoe_NS_coeff1_25_24	0xA203
+#define	cfoe_NS_coeff1_25_24_pos 0
+#define	cfoe_NS_coeff1_25_24_len 2
+#define	cfoe_NS_coeff1_25_24_lsb 24
+#define xd_p_cfoe_NS_coeff2_5_0	0xA203
+#define	cfoe_NS_coeff2_5_0_pos 2
+#define	cfoe_NS_coeff2_5_0_len 6
+#define	cfoe_NS_coeff2_5_0_lsb 0
+#define xd_p_cfoe_NS_coeff2_13_6	0xA204
+#define	cfoe_NS_coeff2_13_6_pos 0
+#define	cfoe_NS_coeff2_13_6_len 8
+#define	cfoe_NS_coeff2_13_6_lsb 6
+#define xd_p_cfoe_NS_coeff2_21_14	0xA205
+#define	cfoe_NS_coeff2_21_14_pos 0
+#define	cfoe_NS_coeff2_21_14_len 8
+#define	cfoe_NS_coeff2_21_14_lsb 14
+#define xd_p_cfoe_NS_coeff2_24_22	0xA206
+#define	cfoe_NS_coeff2_24_22_pos 0
+#define	cfoe_NS_coeff2_24_22_len 3
+#define	cfoe_NS_coeff2_24_22_lsb 22
+#define xd_p_cfoe_lf_c1_4_0	0xA206
+#define	cfoe_lf_c1_4_0_pos 3
+#define	cfoe_lf_c1_4_0_len 5
+#define	cfoe_lf_c1_4_0_lsb 0
+#define xd_p_cfoe_lf_c1_12_5	0xA207
+#define	cfoe_lf_c1_12_5_pos 0
+#define	cfoe_lf_c1_12_5_len 8
+#define	cfoe_lf_c1_12_5_lsb 5
+#define xd_p_cfoe_lf_c1_20_13	0xA208
+#define	cfoe_lf_c1_20_13_pos 0
+#define	cfoe_lf_c1_20_13_len 8
+#define	cfoe_lf_c1_20_13_lsb 13
+#define xd_p_cfoe_lf_c1_25_21	0xA209
+#define	cfoe_lf_c1_25_21_pos 0
+#define	cfoe_lf_c1_25_21_len 5
+#define	cfoe_lf_c1_25_21_lsb 21
+#define xd_p_cfoe_lf_c2_2_0	0xA209
+#define	cfoe_lf_c2_2_0_pos 5
+#define	cfoe_lf_c2_2_0_len 3
+#define	cfoe_lf_c2_2_0_lsb 0
+#define xd_p_cfoe_lf_c2_10_3	0xA20A
+#define	cfoe_lf_c2_10_3_pos 0
+#define	cfoe_lf_c2_10_3_len 8
+#define	cfoe_lf_c2_10_3_lsb 3
+#define xd_p_cfoe_lf_c2_18_11	0xA20B
+#define	cfoe_lf_c2_18_11_pos 0
+#define	cfoe_lf_c2_18_11_len 8
+#define	cfoe_lf_c2_18_11_lsb 11
+#define xd_p_cfoe_lf_c2_25_19	0xA20C
+#define	cfoe_lf_c2_25_19_pos 0
+#define	cfoe_lf_c2_25_19_len 7
+#define	cfoe_lf_c2_25_19_lsb 19
+#define xd_p_cfoe_ifod_7_0	0xA20D
+#define	cfoe_ifod_7_0_pos 0
+#define	cfoe_ifod_7_0_len 8
+#define	cfoe_ifod_7_0_lsb 0
+#define xd_p_cfoe_ifod_10_8	0xA20E
+#define	cfoe_ifod_10_8_pos 0
+#define	cfoe_ifod_10_8_len 3
+#define	cfoe_ifod_10_8_lsb 8
+#define xd_p_cfoe_Divg_ctr_th	0xA20E
+#define	cfoe_Divg_ctr_th_pos 4
+#define	cfoe_Divg_ctr_th_len 4
+#define	cfoe_Divg_ctr_th_lsb 0
+#define xd_p_cfoe_FOT_divg_th	0xA20F
+#define	cfoe_FOT_divg_th_pos 0
+#define	cfoe_FOT_divg_th_len 8
+#define	cfoe_FOT_divg_th_lsb 0
+#define xd_p_cfoe_FOT_cnvg_th	0xA210
+#define	cfoe_FOT_cnvg_th_pos 0
+#define	cfoe_FOT_cnvg_th_len 8
+#define	cfoe_FOT_cnvg_th_lsb 0
+#define xd_p_reg_cfoe_offset_7_0	0xA211
+#define	reg_cfoe_offset_7_0_pos 0
+#define	reg_cfoe_offset_7_0_len 8
+#define	reg_cfoe_offset_7_0_lsb 0
+#define xd_p_reg_cfoe_offset_9_8	0xA212
+#define	reg_cfoe_offset_9_8_pos 0
+#define	reg_cfoe_offset_9_8_len 2
+#define	reg_cfoe_offset_9_8_lsb 8
+#define xd_p_reg_cfoe_ifoe_sign_corr	0xA212
+#define	reg_cfoe_ifoe_sign_corr_pos 2
+#define	reg_cfoe_ifoe_sign_corr_len 1
+#define	reg_cfoe_ifoe_sign_corr_lsb 0
+#define xd_r_cfoe_fot_LF_output_7_0	0xA218
+#define	cfoe_fot_LF_output_7_0_pos 0
+#define	cfoe_fot_LF_output_7_0_len 8
+#define	cfoe_fot_LF_output_7_0_lsb 0
+#define xd_r_cfoe_fot_LF_output_15_8	0xA219
+#define	cfoe_fot_LF_output_15_8_pos 0
+#define	cfoe_fot_LF_output_15_8_len 8
+#define	cfoe_fot_LF_output_15_8_lsb 8
+#define xd_r_cfoe_ifo_metric_7_0	0xA21A
+#define	cfoe_ifo_metric_7_0_pos 0
+#define	cfoe_ifo_metric_7_0_len 8
+#define	cfoe_ifo_metric_7_0_lsb 0
+#define xd_r_cfoe_ifo_metric_15_8	0xA21B
+#define	cfoe_ifo_metric_15_8_pos 0
+#define	cfoe_ifo_metric_15_8_len 8
+#define	cfoe_ifo_metric_15_8_lsb 8
+#define xd_r_cfoe_ifo_metric_23_16	0xA21C
+#define	cfoe_ifo_metric_23_16_pos 0
+#define	cfoe_ifo_metric_23_16_len 8
+#define	cfoe_ifo_metric_23_16_lsb 16
+#define xd_p_ste_Nu	0xA220
+#define	ste_Nu_pos 0
+#define	ste_Nu_len 2
+#define	ste_Nu_lsb 0
+#define xd_p_ste_GI	0xA220
+#define	ste_GI_pos 2
+#define	ste_GI_len 3
+#define	ste_GI_lsb 0
+#define xd_p_ste_symbol_num	0xA221
+#define	ste_symbol_num_pos 0
+#define	ste_symbol_num_len 2
+#define	ste_symbol_num_lsb 0
+#define xd_p_ste_sample_num	0xA221
+#define	ste_sample_num_pos 2
+#define	ste_sample_num_len 2
+#define	ste_sample_num_lsb 0
+#define xd_p_reg_ste_buf_en	0xA221
+#define	reg_ste_buf_en_pos 7
+#define	reg_ste_buf_en_len 1
+#define	reg_ste_buf_en_lsb 0
+#define xd_p_ste_FFT_offset_7_0	0xA222
+#define	ste_FFT_offset_7_0_pos 0
+#define	ste_FFT_offset_7_0_len 8
+#define	ste_FFT_offset_7_0_lsb 0
+#define xd_p_ste_FFT_offset_11_8	0xA223
+#define	ste_FFT_offset_11_8_pos 0
+#define	ste_FFT_offset_11_8_len 4
+#define	ste_FFT_offset_11_8_lsb 8
+#define xd_p_reg_ste_tstmod	0xA223
+#define	reg_ste_tstmod_pos 5
+#define	reg_ste_tstmod_len 1
+#define	reg_ste_tstmod_lsb 0
+#define xd_p_ste_adv_start_7_0	0xA224
+#define	ste_adv_start_7_0_pos 0
+#define	ste_adv_start_7_0_len 8
+#define	ste_adv_start_7_0_lsb 0
+#define xd_p_ste_adv_start_10_8	0xA225
+#define	ste_adv_start_10_8_pos 0
+#define	ste_adv_start_10_8_len 3
+#define	ste_adv_start_10_8_lsb 8
+#define xd_p_ste_adv_stop	0xA226
+#define	ste_adv_stop_pos 0
+#define	ste_adv_stop_len 8
+#define	ste_adv_stop_lsb 0
+#define xd_r_ste_P_value_7_0	0xA228
+#define	ste_P_value_7_0_pos 0
+#define	ste_P_value_7_0_len 8
+#define	ste_P_value_7_0_lsb 0
+#define xd_r_ste_P_value_10_8	0xA229
+#define	ste_P_value_10_8_pos 0
+#define	ste_P_value_10_8_len 3
+#define	ste_P_value_10_8_lsb 8
+#define xd_r_ste_M_value_7_0	0xA22A
+#define	ste_M_value_7_0_pos 0
+#define	ste_M_value_7_0_len 8
+#define	ste_M_value_7_0_lsb 0
+#define xd_r_ste_M_value_10_8	0xA22B
+#define	ste_M_value_10_8_pos 0
+#define	ste_M_value_10_8_len 3
+#define	ste_M_value_10_8_lsb 8
+#define xd_r_ste_H1	0xA22C
+#define	ste_H1_pos 0
+#define	ste_H1_len 7
+#define	ste_H1_lsb 0
+#define xd_r_ste_H2	0xA22D
+#define	ste_H2_pos 0
+#define	ste_H2_len 7
+#define	ste_H2_lsb 0
+#define xd_r_ste_H3	0xA22E
+#define	ste_H3_pos 0
+#define	ste_H3_len 7
+#define	ste_H3_lsb 0
+#define xd_r_ste_H4	0xA22F
+#define	ste_H4_pos 0
+#define	ste_H4_len 7
+#define	ste_H4_lsb 0
+#define xd_r_ste_Corr_value_I_7_0	0xA230
+#define	ste_Corr_value_I_7_0_pos 0
+#define	ste_Corr_value_I_7_0_len 8
+#define	ste_Corr_value_I_7_0_lsb 0
+#define xd_r_ste_Corr_value_I_15_8	0xA231
+#define	ste_Corr_value_I_15_8_pos 0
+#define	ste_Corr_value_I_15_8_len 8
+#define	ste_Corr_value_I_15_8_lsb 8
+#define xd_r_ste_Corr_value_I_23_16	0xA232
+#define	ste_Corr_value_I_23_16_pos 0
+#define	ste_Corr_value_I_23_16_len 8
+#define	ste_Corr_value_I_23_16_lsb 16
+#define xd_r_ste_Corr_value_I_27_24	0xA233
+#define	ste_Corr_value_I_27_24_pos 0
+#define	ste_Corr_value_I_27_24_len 4
+#define	ste_Corr_value_I_27_24_lsb 24
+#define xd_r_ste_Corr_value_Q_7_0	0xA234
+#define	ste_Corr_value_Q_7_0_pos 0
+#define	ste_Corr_value_Q_7_0_len 8
+#define	ste_Corr_value_Q_7_0_lsb 0
+#define xd_r_ste_Corr_value_Q_15_8	0xA235
+#define	ste_Corr_value_Q_15_8_pos 0
+#define	ste_Corr_value_Q_15_8_len 8
+#define	ste_Corr_value_Q_15_8_lsb 8
+#define xd_r_ste_Corr_value_Q_23_16	0xA236
+#define	ste_Corr_value_Q_23_16_pos 0
+#define	ste_Corr_value_Q_23_16_len 8
+#define	ste_Corr_value_Q_23_16_lsb 16
+#define xd_r_ste_Corr_value_Q_27_24	0xA237
+#define	ste_Corr_value_Q_27_24_pos 0
+#define	ste_Corr_value_Q_27_24_len 4
+#define	ste_Corr_value_Q_27_24_lsb 24
+#define xd_r_ste_J_num_7_0	0xA238
+#define	ste_J_num_7_0_pos 0
+#define	ste_J_num_7_0_len 8
+#define	ste_J_num_7_0_lsb 0
+#define xd_r_ste_J_num_15_8	0xA239
+#define	ste_J_num_15_8_pos 0
+#define	ste_J_num_15_8_len 8
+#define	ste_J_num_15_8_lsb 8
+#define xd_r_ste_J_num_23_16	0xA23A
+#define	ste_J_num_23_16_pos 0
+#define	ste_J_num_23_16_len 8
+#define	ste_J_num_23_16_lsb 16
+#define xd_r_ste_J_num_31_24	0xA23B
+#define	ste_J_num_31_24_pos 0
+#define	ste_J_num_31_24_len 8
+#define	ste_J_num_31_24_lsb 24
+#define xd_r_ste_J_den_7_0	0xA23C
+#define	ste_J_den_7_0_pos 0
+#define	ste_J_den_7_0_len 8
+#define	ste_J_den_7_0_lsb 0
+#define xd_r_ste_J_den_15_8	0xA23D
+#define	ste_J_den_15_8_pos 0
+#define	ste_J_den_15_8_len 8
+#define	ste_J_den_15_8_lsb 8
+#define xd_r_ste_J_den_18_16	0xA23E
+#define	ste_J_den_18_16_pos 0
+#define	ste_J_den_18_16_len 3
+#define	ste_J_den_18_16_lsb 16
+#define xd_r_ste_Beacon_Indicator	0xA23E
+#define	ste_Beacon_Indicator_pos 4
+#define	ste_Beacon_Indicator_len 1
+#define	ste_Beacon_Indicator_lsb 0
+#define xd_r_tpsd_Frame_Num	0xA250
+#define	tpsd_Frame_Num_pos 0
+#define	tpsd_Frame_Num_len 2
+#define	tpsd_Frame_Num_lsb 0
+#define xd_r_tpsd_Constel	0xA250
+#define	tpsd_Constel_pos 2
+#define	tpsd_Constel_len 2
+#define	tpsd_Constel_lsb 0
+#define xd_r_tpsd_GI	0xA250
+#define	tpsd_GI_pos 4
+#define	tpsd_GI_len 2
+#define	tpsd_GI_lsb 0
+#define xd_r_tpsd_Mode	0xA250
+#define	tpsd_Mode_pos 6
+#define	tpsd_Mode_len 2
+#define	tpsd_Mode_lsb 0
+#define xd_r_tpsd_CR_HP	0xA251
+#define	tpsd_CR_HP_pos 0
+#define	tpsd_CR_HP_len 3
+#define	tpsd_CR_HP_lsb 0
+#define xd_r_tpsd_CR_LP	0xA251
+#define	tpsd_CR_LP_pos 3
+#define	tpsd_CR_LP_len 3
+#define	tpsd_CR_LP_lsb 0
+#define xd_r_tpsd_Hie	0xA252
+#define	tpsd_Hie_pos 0
+#define	tpsd_Hie_len 3
+#define	tpsd_Hie_lsb 0
+#define xd_r_tpsd_Res_Bits	0xA252
+#define	tpsd_Res_Bits_pos 3
+#define	tpsd_Res_Bits_len 5
+#define	tpsd_Res_Bits_lsb 0
+#define xd_r_tpsd_Res_Bits_0	0xA253
+#define	tpsd_Res_Bits_0_pos 0
+#define	tpsd_Res_Bits_0_len 1
+#define	tpsd_Res_Bits_0_lsb 0
+#define xd_r_tpsd_LengthInd	0xA253
+#define	tpsd_LengthInd_pos 1
+#define	tpsd_LengthInd_len 6
+#define	tpsd_LengthInd_lsb 0
+#define xd_r_tpsd_Cell_Id_7_0	0xA254
+#define	tpsd_Cell_Id_7_0_pos 0
+#define	tpsd_Cell_Id_7_0_len 8
+#define	tpsd_Cell_Id_7_0_lsb 0
+#define xd_r_tpsd_Cell_Id_15_8	0xA255
+#define	tpsd_Cell_Id_15_8_pos 0
+#define	tpsd_Cell_Id_15_8_len 8
+#define	tpsd_Cell_Id_15_8_lsb 0
+#define xd_p_reg_fft_mask_tone0_7_0	0xA260
+#define	reg_fft_mask_tone0_7_0_pos 0
+#define	reg_fft_mask_tone0_7_0_len 8
+#define	reg_fft_mask_tone0_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone0_12_8	0xA261
+#define	reg_fft_mask_tone0_12_8_pos 0
+#define	reg_fft_mask_tone0_12_8_len 5
+#define	reg_fft_mask_tone0_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone1_7_0	0xA262
+#define	reg_fft_mask_tone1_7_0_pos 0
+#define	reg_fft_mask_tone1_7_0_len 8
+#define	reg_fft_mask_tone1_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone1_12_8	0xA263
+#define	reg_fft_mask_tone1_12_8_pos 0
+#define	reg_fft_mask_tone1_12_8_len 5
+#define	reg_fft_mask_tone1_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone2_7_0	0xA264
+#define	reg_fft_mask_tone2_7_0_pos 0
+#define	reg_fft_mask_tone2_7_0_len 8
+#define	reg_fft_mask_tone2_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone2_12_8	0xA265
+#define	reg_fft_mask_tone2_12_8_pos 0
+#define	reg_fft_mask_tone2_12_8_len 5
+#define	reg_fft_mask_tone2_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone3_7_0	0xA266
+#define	reg_fft_mask_tone3_7_0_pos 0
+#define	reg_fft_mask_tone3_7_0_len 8
+#define	reg_fft_mask_tone3_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone3_12_8	0xA267
+#define	reg_fft_mask_tone3_12_8_pos 0
+#define	reg_fft_mask_tone3_12_8_len 5
+#define	reg_fft_mask_tone3_12_8_lsb 8
+#define xd_p_reg_fft_mask_from0_7_0	0xA268
+#define	reg_fft_mask_from0_7_0_pos 0
+#define	reg_fft_mask_from0_7_0_len 8
+#define	reg_fft_mask_from0_7_0_lsb 0
+#define xd_p_reg_fft_mask_from0_12_8	0xA269
+#define	reg_fft_mask_from0_12_8_pos 0
+#define	reg_fft_mask_from0_12_8_len 5
+#define	reg_fft_mask_from0_12_8_lsb 8
+#define xd_p_reg_fft_mask_to0_7_0	0xA26A
+#define	reg_fft_mask_to0_7_0_pos 0
+#define	reg_fft_mask_to0_7_0_len 8
+#define	reg_fft_mask_to0_7_0_lsb 0
+#define xd_p_reg_fft_mask_to0_12_8	0xA26B
+#define	reg_fft_mask_to0_12_8_pos 0
+#define	reg_fft_mask_to0_12_8_len 5
+#define	reg_fft_mask_to0_12_8_lsb 8
+#define xd_p_reg_fft_mask_from1_7_0	0xA26C
+#define	reg_fft_mask_from1_7_0_pos 0
+#define	reg_fft_mask_from1_7_0_len 8
+#define	reg_fft_mask_from1_7_0_lsb 0
+#define xd_p_reg_fft_mask_from1_12_8	0xA26D
+#define	reg_fft_mask_from1_12_8_pos 0
+#define	reg_fft_mask_from1_12_8_len 5
+#define	reg_fft_mask_from1_12_8_lsb 8
+#define xd_p_reg_fft_mask_to1_7_0	0xA26E
+#define	reg_fft_mask_to1_7_0_pos 0
+#define	reg_fft_mask_to1_7_0_len 8
+#define	reg_fft_mask_to1_7_0_lsb 0
+#define xd_p_reg_fft_mask_to1_12_8	0xA26F
+#define	reg_fft_mask_to1_12_8_pos 0
+#define	reg_fft_mask_to1_12_8_len 5
+#define	reg_fft_mask_to1_12_8_lsb 8
+#define xd_p_reg_cge_idx0_7_0	0xA280
+#define	reg_cge_idx0_7_0_pos 0
+#define	reg_cge_idx0_7_0_len 8
+#define	reg_cge_idx0_7_0_lsb 0
+#define xd_p_reg_cge_idx0_12_8	0xA281
+#define	reg_cge_idx0_12_8_pos 0
+#define	reg_cge_idx0_12_8_len 5
+#define	reg_cge_idx0_12_8_lsb 8
+#define xd_p_reg_cge_idx1_7_0	0xA282
+#define	reg_cge_idx1_7_0_pos 0
+#define	reg_cge_idx1_7_0_len 8
+#define	reg_cge_idx1_7_0_lsb 0
+#define xd_p_reg_cge_idx1_12_8	0xA283
+#define	reg_cge_idx1_12_8_pos 0
+#define	reg_cge_idx1_12_8_len 5
+#define	reg_cge_idx1_12_8_lsb 8
+#define xd_p_reg_cge_idx2_7_0	0xA284
+#define	reg_cge_idx2_7_0_pos 0
+#define	reg_cge_idx2_7_0_len 8
+#define	reg_cge_idx2_7_0_lsb 0
+#define xd_p_reg_cge_idx2_12_8	0xA285
+#define	reg_cge_idx2_12_8_pos 0
+#define	reg_cge_idx2_12_8_len 5
+#define	reg_cge_idx2_12_8_lsb 8
+#define xd_p_reg_cge_idx3_7_0	0xA286
+#define	reg_cge_idx3_7_0_pos 0
+#define	reg_cge_idx3_7_0_len 8
+#define	reg_cge_idx3_7_0_lsb 0
+#define xd_p_reg_cge_idx3_12_8	0xA287
+#define	reg_cge_idx3_12_8_pos 0
+#define	reg_cge_idx3_12_8_len 5
+#define	reg_cge_idx3_12_8_lsb 8
+#define xd_p_reg_cge_idx4_7_0	0xA288
+#define	reg_cge_idx4_7_0_pos 0
+#define	reg_cge_idx4_7_0_len 8
+#define	reg_cge_idx4_7_0_lsb 0
+#define xd_p_reg_cge_idx4_12_8	0xA289
+#define	reg_cge_idx4_12_8_pos 0
+#define	reg_cge_idx4_12_8_len 5
+#define	reg_cge_idx4_12_8_lsb 8
+#define xd_p_reg_cge_idx5_7_0	0xA28A
+#define	reg_cge_idx5_7_0_pos 0
+#define	reg_cge_idx5_7_0_len 8
+#define	reg_cge_idx5_7_0_lsb 0
+#define xd_p_reg_cge_idx5_12_8	0xA28B
+#define	reg_cge_idx5_12_8_pos 0
+#define	reg_cge_idx5_12_8_len 5
+#define	reg_cge_idx5_12_8_lsb 8
+#define xd_p_reg_cge_idx6_7_0	0xA28C
+#define	reg_cge_idx6_7_0_pos 0
+#define	reg_cge_idx6_7_0_len 8
+#define	reg_cge_idx6_7_0_lsb 0
+#define xd_p_reg_cge_idx6_12_8	0xA28D
+#define	reg_cge_idx6_12_8_pos 0
+#define	reg_cge_idx6_12_8_len 5
+#define	reg_cge_idx6_12_8_lsb 8
+#define xd_p_reg_cge_idx7_7_0	0xA28E
+#define	reg_cge_idx7_7_0_pos 0
+#define	reg_cge_idx7_7_0_len 8
+#define	reg_cge_idx7_7_0_lsb 0
+#define xd_p_reg_cge_idx7_12_8	0xA28F
+#define	reg_cge_idx7_12_8_pos 0
+#define	reg_cge_idx7_12_8_len 5
+#define	reg_cge_idx7_12_8_lsb 8
+#define xd_p_reg_cge_idx8_7_0	0xA290
+#define	reg_cge_idx8_7_0_pos 0
+#define	reg_cge_idx8_7_0_len 8
+#define	reg_cge_idx8_7_0_lsb 0
+#define xd_p_reg_cge_idx8_12_8	0xA291
+#define	reg_cge_idx8_12_8_pos 0
+#define	reg_cge_idx8_12_8_len 5
+#define	reg_cge_idx8_12_8_lsb 8
+#define xd_p_reg_cge_idx9_7_0	0xA292
+#define	reg_cge_idx9_7_0_pos 0
+#define	reg_cge_idx9_7_0_len 8
+#define	reg_cge_idx9_7_0_lsb 0
+#define xd_p_reg_cge_idx9_12_8	0xA293
+#define	reg_cge_idx9_12_8_pos 0
+#define	reg_cge_idx9_12_8_len 5
+#define	reg_cge_idx9_12_8_lsb 8
+#define xd_p_reg_cge_idx10_7_0	0xA294
+#define	reg_cge_idx10_7_0_pos 0
+#define	reg_cge_idx10_7_0_len 8
+#define	reg_cge_idx10_7_0_lsb 0
+#define xd_p_reg_cge_idx10_12_8	0xA295
+#define	reg_cge_idx10_12_8_pos 0
+#define	reg_cge_idx10_12_8_len 5
+#define	reg_cge_idx10_12_8_lsb 8
+#define xd_p_reg_cge_idx11_7_0	0xA296
+#define	reg_cge_idx11_7_0_pos 0
+#define	reg_cge_idx11_7_0_len 8
+#define	reg_cge_idx11_7_0_lsb 0
+#define xd_p_reg_cge_idx11_12_8	0xA297
+#define	reg_cge_idx11_12_8_pos 0
+#define	reg_cge_idx11_12_8_len 5
+#define	reg_cge_idx11_12_8_lsb 8
+#define xd_p_reg_cge_idx12_7_0	0xA298
+#define	reg_cge_idx12_7_0_pos 0
+#define	reg_cge_idx12_7_0_len 8
+#define	reg_cge_idx12_7_0_lsb 0
+#define xd_p_reg_cge_idx12_12_8	0xA299
+#define	reg_cge_idx12_12_8_pos 0
+#define	reg_cge_idx12_12_8_len 5
+#define	reg_cge_idx12_12_8_lsb 8
+#define xd_p_reg_cge_idx13_7_0	0xA29A
+#define	reg_cge_idx13_7_0_pos 0
+#define	reg_cge_idx13_7_0_len 8
+#define	reg_cge_idx13_7_0_lsb 0
+#define xd_p_reg_cge_idx13_12_8	0xA29B
+#define	reg_cge_idx13_12_8_pos 0
+#define	reg_cge_idx13_12_8_len 5
+#define	reg_cge_idx13_12_8_lsb 8
+#define xd_p_reg_cge_idx14_7_0	0xA29C
+#define	reg_cge_idx14_7_0_pos 0
+#define	reg_cge_idx14_7_0_len 8
+#define	reg_cge_idx14_7_0_lsb 0
+#define xd_p_reg_cge_idx14_12_8	0xA29D
+#define	reg_cge_idx14_12_8_pos 0
+#define	reg_cge_idx14_12_8_len 5
+#define	reg_cge_idx14_12_8_lsb 8
+#define xd_p_reg_cge_idx15_7_0	0xA29E
+#define	reg_cge_idx15_7_0_pos 0
+#define	reg_cge_idx15_7_0_len 8
+#define	reg_cge_idx15_7_0_lsb 0
+#define xd_p_reg_cge_idx15_12_8	0xA29F
+#define	reg_cge_idx15_12_8_pos 0
+#define	reg_cge_idx15_12_8_len 5
+#define	reg_cge_idx15_12_8_lsb 8
+#define xd_r_reg_fft_crc	0xA2A8
+#define	reg_fft_crc_pos 0
+#define	reg_fft_crc_len 8
+#define	reg_fft_crc_lsb 0
+#define xd_p_fd_fft_shift_max	0xA2A9
+#define	fd_fft_shift_max_pos 0
+#define	fd_fft_shift_max_len 4
+#define	fd_fft_shift_max_lsb 0
+#define xd_r_fd_fft_shift	0xA2A9
+#define	fd_fft_shift_pos 4
+#define	fd_fft_shift_len 4
+#define	fd_fft_shift_lsb 0
+#define xd_r_fd_fft_frame_num	0xA2AA
+#define	fd_fft_frame_num_pos 0
+#define	fd_fft_frame_num_len 2
+#define	fd_fft_frame_num_lsb 0
+#define xd_r_fd_fft_symbol_count	0xA2AB
+#define	fd_fft_symbol_count_pos 0
+#define	fd_fft_symbol_count_len 7
+#define	fd_fft_symbol_count_lsb 0
+#define xd_r_reg_fft_idx_max_7_0	0xA2AC
+#define	reg_fft_idx_max_7_0_pos 0
+#define	reg_fft_idx_max_7_0_len 8
+#define	reg_fft_idx_max_7_0_lsb 0
+#define xd_r_reg_fft_idx_max_12_8	0xA2AD
+#define	reg_fft_idx_max_12_8_pos 0
+#define	reg_fft_idx_max_12_8_len 5
+#define	reg_fft_idx_max_12_8_lsb 8
+#define xd_p_reg_cge_program	0xA2AE
+#define	reg_cge_program_pos 0
+#define	reg_cge_program_len 1
+#define	reg_cge_program_lsb 0
+#define xd_p_reg_cge_fixed	0xA2AE
+#define	reg_cge_fixed_pos 1
+#define	reg_cge_fixed_len 1
+#define	reg_cge_fixed_lsb 0
+#define xd_p_reg_fft_rotate_en	0xA2AE
+#define	reg_fft_rotate_en_pos 2
+#define	reg_fft_rotate_en_len 1
+#define	reg_fft_rotate_en_lsb 0
+#define xd_p_reg_fft_rotate_base_4_0	0xA2AE
+#define	reg_fft_rotate_base_4_0_pos 3
+#define	reg_fft_rotate_base_4_0_len 5
+#define	reg_fft_rotate_base_4_0_lsb 0
+#define xd_p_reg_fft_rotate_base_12_5	0xA2AF
+#define	reg_fft_rotate_base_12_5_pos 0
+#define	reg_fft_rotate_base_12_5_len 8
+#define	reg_fft_rotate_base_12_5_lsb 5
+#define xd_p_reg_gp_trigger_fd	0xA2B8
+#define	reg_gp_trigger_fd_pos 0
+#define	reg_gp_trigger_fd_len 1
+#define	reg_gp_trigger_fd_lsb 0
+#define xd_p_reg_trigger_sel_fd	0xA2B8
+#define	reg_trigger_sel_fd_pos 1
+#define	reg_trigger_sel_fd_len 2
+#define	reg_trigger_sel_fd_lsb 0
+#define xd_p_reg_trigger_module_sel_fd	0xA2B9
+#define	reg_trigger_module_sel_fd_pos 0
+#define	reg_trigger_module_sel_fd_len 6
+#define	reg_trigger_module_sel_fd_lsb 0
+#define xd_p_reg_trigger_set_sel_fd	0xA2BA
+#define	reg_trigger_set_sel_fd_pos 0
+#define	reg_trigger_set_sel_fd_len 6
+#define	reg_trigger_set_sel_fd_lsb 0
+#define xd_p_reg_fd_noname_7_0	0xA2BC
+#define	reg_fd_noname_7_0_pos 0
+#define	reg_fd_noname_7_0_len 8
+#define	reg_fd_noname_7_0_lsb 0
+#define xd_p_reg_fd_noname_15_8	0xA2BD
+#define	reg_fd_noname_15_8_pos 0
+#define	reg_fd_noname_15_8_len 8
+#define	reg_fd_noname_15_8_lsb 8
+#define xd_p_reg_fd_noname_23_16	0xA2BE
+#define	reg_fd_noname_23_16_pos 0
+#define	reg_fd_noname_23_16_len 8
+#define	reg_fd_noname_23_16_lsb 16
+#define xd_p_reg_fd_noname_31_24	0xA2BF
+#define	reg_fd_noname_31_24_pos 0
+#define	reg_fd_noname_31_24_len 8
+#define	reg_fd_noname_31_24_lsb 24
+#define xd_r_fd_fpcc_cp_corr_signn	0xA2C0
+#define	fd_fpcc_cp_corr_signn_pos 0
+#define	fd_fpcc_cp_corr_signn_len 8
+#define	fd_fpcc_cp_corr_signn_lsb 0
+#define xd_p_reg_feq_s1	0xA2C1
+#define	reg_feq_s1_pos 0
+#define	reg_feq_s1_len 5
+#define	reg_feq_s1_lsb 0
+#define xd_p_fd_fpcc_cp_corr_tone_th	0xA2C2
+#define	fd_fpcc_cp_corr_tone_th_pos 0
+#define	fd_fpcc_cp_corr_tone_th_len 6
+#define	fd_fpcc_cp_corr_tone_th_lsb 0
+#define xd_p_fd_fpcc_cp_corr_symbol_log_th	0xA2C3
+#define	fd_fpcc_cp_corr_symbol_log_th_pos 0
+#define	fd_fpcc_cp_corr_symbol_log_th_len 4
+#define	fd_fpcc_cp_corr_symbol_log_th_lsb 0
+#define xd_p_fd_fpcc_cp_corr_int	0xA2C4
+#define	fd_fpcc_cp_corr_int_pos 0
+#define	fd_fpcc_cp_corr_int_len 1
+#define	fd_fpcc_cp_corr_int_lsb 0
+#define xd_p_reg_sfoe_ns_7_0	0xA320
+#define	reg_sfoe_ns_7_0_pos 0
+#define	reg_sfoe_ns_7_0_len 8
+#define	reg_sfoe_ns_7_0_lsb 0
+#define xd_p_reg_sfoe_ns_14_8	0xA321
+#define	reg_sfoe_ns_14_8_pos 0
+#define	reg_sfoe_ns_14_8_len 7
+#define	reg_sfoe_ns_14_8_lsb 8
+#define xd_p_reg_sfoe_c1_7_0	0xA322
+#define	reg_sfoe_c1_7_0_pos 0
+#define	reg_sfoe_c1_7_0_len 8
+#define	reg_sfoe_c1_7_0_lsb 0
+#define xd_p_reg_sfoe_c1_15_8	0xA323
+#define	reg_sfoe_c1_15_8_pos 0
+#define	reg_sfoe_c1_15_8_len 8
+#define	reg_sfoe_c1_15_8_lsb 8
+#define xd_p_reg_sfoe_c1_17_16	0xA324
+#define	reg_sfoe_c1_17_16_pos 0
+#define	reg_sfoe_c1_17_16_len 2
+#define	reg_sfoe_c1_17_16_lsb 16
+#define xd_p_reg_sfoe_c2_7_0	0xA325
+#define	reg_sfoe_c2_7_0_pos 0
+#define	reg_sfoe_c2_7_0_len 8
+#define	reg_sfoe_c2_7_0_lsb 0
+#define xd_p_reg_sfoe_c2_15_8	0xA326
+#define	reg_sfoe_c2_15_8_pos 0
+#define	reg_sfoe_c2_15_8_len 8
+#define	reg_sfoe_c2_15_8_lsb 8
+#define xd_p_reg_sfoe_c2_17_16	0xA327
+#define	reg_sfoe_c2_17_16_pos 0
+#define	reg_sfoe_c2_17_16_len 2
+#define	reg_sfoe_c2_17_16_lsb 16
+#define xd_r_reg_sfoe_out_9_2	0xA328
+#define	reg_sfoe_out_9_2_pos 0
+#define	reg_sfoe_out_9_2_len 8
+#define	reg_sfoe_out_9_2_lsb 0
+#define xd_r_reg_sfoe_out_1_0	0xA329
+#define	reg_sfoe_out_1_0_pos 0
+#define	reg_sfoe_out_1_0_len 2
+#define	reg_sfoe_out_1_0_lsb 0
+#define xd_p_reg_sfoe_lm_counter_th	0xA32A
+#define	reg_sfoe_lm_counter_th_pos 0
+#define	reg_sfoe_lm_counter_th_len 4
+#define	reg_sfoe_lm_counter_th_lsb 0
+#define xd_p_reg_sfoe_convg_th	0xA32B
+#define	reg_sfoe_convg_th_pos 0
+#define	reg_sfoe_convg_th_len 8
+#define	reg_sfoe_convg_th_lsb 0
+#define xd_p_reg_sfoe_divg_th	0xA32C
+#define	reg_sfoe_divg_th_pos 0
+#define	reg_sfoe_divg_th_len 8
+#define	reg_sfoe_divg_th_lsb 0
+#define xd_p_fd_tpsd_en	0xA330
+#define	fd_tpsd_en_pos 0
+#define	fd_tpsd_en_len 1
+#define	fd_tpsd_en_lsb 0
+#define xd_p_fd_tpsd_dis	0xA330
+#define	fd_tpsd_dis_pos 1
+#define	fd_tpsd_dis_len 1
+#define	fd_tpsd_dis_lsb 0
+#define xd_p_fd_tpsd_rst	0xA330
+#define	fd_tpsd_rst_pos 2
+#define	fd_tpsd_rst_len 1
+#define	fd_tpsd_rst_lsb 0
+#define xd_p_fd_tpsd_lock	0xA330
+#define	fd_tpsd_lock_pos 3
+#define	fd_tpsd_lock_len 1
+#define	fd_tpsd_lock_lsb 0
+#define xd_r_fd_tpsd_s19	0xA330
+#define	fd_tpsd_s19_pos 4
+#define	fd_tpsd_s19_len 1
+#define	fd_tpsd_s19_lsb 0
+#define xd_r_fd_tpsd_s17	0xA330
+#define	fd_tpsd_s17_pos 5
+#define	fd_tpsd_s17_len 1
+#define	fd_tpsd_s17_lsb 0
+#define xd_p_fd_sfr_ste_en	0xA331
+#define	fd_sfr_ste_en_pos 0
+#define	fd_sfr_ste_en_len 1
+#define	fd_sfr_ste_en_lsb 0
+#define xd_p_fd_sfr_ste_dis	0xA331
+#define	fd_sfr_ste_dis_pos 1
+#define	fd_sfr_ste_dis_len 1
+#define	fd_sfr_ste_dis_lsb 0
+#define xd_p_fd_sfr_ste_rst	0xA331
+#define	fd_sfr_ste_rst_pos 2
+#define	fd_sfr_ste_rst_len 1
+#define	fd_sfr_ste_rst_lsb 0
+#define xd_p_fd_sfr_ste_mode	0xA331
+#define	fd_sfr_ste_mode_pos 3
+#define	fd_sfr_ste_mode_len 1
+#define	fd_sfr_ste_mode_lsb 0
+#define xd_p_fd_sfr_ste_done	0xA331
+#define	fd_sfr_ste_done_pos 4
+#define	fd_sfr_ste_done_len 1
+#define	fd_sfr_ste_done_lsb 0
+#define xd_p_reg_cfoe_ffoe_en	0xA332
+#define	reg_cfoe_ffoe_en_pos 0
+#define	reg_cfoe_ffoe_en_len 1
+#define	reg_cfoe_ffoe_en_lsb 0
+#define xd_p_reg_cfoe_ffoe_dis	0xA332
+#define	reg_cfoe_ffoe_dis_pos 1
+#define	reg_cfoe_ffoe_dis_len 1
+#define	reg_cfoe_ffoe_dis_lsb 0
+#define xd_p_reg_cfoe_ffoe_rst	0xA332
+#define	reg_cfoe_ffoe_rst_pos 2
+#define	reg_cfoe_ffoe_rst_len 1
+#define	reg_cfoe_ffoe_rst_lsb 0
+#define xd_p_reg_cfoe_ifoe_en	0xA332
+#define	reg_cfoe_ifoe_en_pos 3
+#define	reg_cfoe_ifoe_en_len 1
+#define	reg_cfoe_ifoe_en_lsb 0
+#define xd_p_reg_cfoe_ifoe_dis	0xA332
+#define	reg_cfoe_ifoe_dis_pos 4
+#define	reg_cfoe_ifoe_dis_len 1
+#define	reg_cfoe_ifoe_dis_lsb 0
+#define xd_p_reg_cfoe_ifoe_rst	0xA332
+#define	reg_cfoe_ifoe_rst_pos 5
+#define	reg_cfoe_ifoe_rst_len 1
+#define	reg_cfoe_ifoe_rst_lsb 0
+#define xd_p_reg_cfoe_fot_en	0xA332
+#define	reg_cfoe_fot_en_pos 6
+#define	reg_cfoe_fot_en_len 1
+#define	reg_cfoe_fot_en_lsb 0
+#define xd_p_reg_cfoe_fot_lm_en	0xA332
+#define	reg_cfoe_fot_lm_en_pos 7
+#define	reg_cfoe_fot_lm_en_len 1
+#define	reg_cfoe_fot_lm_en_lsb 0
+#define xd_p_reg_cfoe_fot_rst	0xA333
+#define	reg_cfoe_fot_rst_pos 0
+#define	reg_cfoe_fot_rst_len 1
+#define	reg_cfoe_fot_rst_lsb 0
+#define xd_r_fd_cfoe_ffoe_done	0xA333
+#define	fd_cfoe_ffoe_done_pos 1
+#define	fd_cfoe_ffoe_done_len 1
+#define	fd_cfoe_ffoe_done_lsb 0
+#define xd_p_fd_cfoe_metric_vld	0xA333
+#define	fd_cfoe_metric_vld_pos 2
+#define	fd_cfoe_metric_vld_len 1
+#define	fd_cfoe_metric_vld_lsb 0
+#define xd_p_reg_cfoe_ifod_vld	0xA333
+#define	reg_cfoe_ifod_vld_pos 3
+#define	reg_cfoe_ifod_vld_len 1
+#define	reg_cfoe_ifod_vld_lsb 0
+#define xd_r_fd_cfoe_ifoe_done	0xA333
+#define	fd_cfoe_ifoe_done_pos 4
+#define	fd_cfoe_ifoe_done_len 1
+#define	fd_cfoe_ifoe_done_lsb 0
+#define xd_r_fd_cfoe_fot_valid	0xA333
+#define	fd_cfoe_fot_valid_pos 5
+#define	fd_cfoe_fot_valid_len 1
+#define	fd_cfoe_fot_valid_lsb 0
+#define xd_p_reg_cfoe_divg_int	0xA333
+#define	reg_cfoe_divg_int_pos 6
+#define	reg_cfoe_divg_int_len 1
+#define	reg_cfoe_divg_int_lsb 0
+#define xd_r_reg_cfoe_divg_flag	0xA333
+#define	reg_cfoe_divg_flag_pos 7
+#define	reg_cfoe_divg_flag_len 1
+#define	reg_cfoe_divg_flag_lsb 0
+#define xd_p_reg_sfoe_en	0xA334
+#define	reg_sfoe_en_pos 0
+#define	reg_sfoe_en_len 1
+#define	reg_sfoe_en_lsb 0
+#define xd_p_reg_sfoe_dis	0xA334
+#define	reg_sfoe_dis_pos 1
+#define	reg_sfoe_dis_len 1
+#define	reg_sfoe_dis_lsb 0
+#define xd_p_reg_sfoe_rst	0xA334
+#define	reg_sfoe_rst_pos 2
+#define	reg_sfoe_rst_len 1
+#define	reg_sfoe_rst_lsb 0
+#define xd_p_reg_sfoe_vld_int	0xA334
+#define	reg_sfoe_vld_int_pos 3
+#define	reg_sfoe_vld_int_len 1
+#define	reg_sfoe_vld_int_lsb 0
+#define xd_p_reg_sfoe_lm_en	0xA334
+#define	reg_sfoe_lm_en_pos 4
+#define	reg_sfoe_lm_en_len 1
+#define	reg_sfoe_lm_en_lsb 0
+#define xd_p_reg_sfoe_divg_int	0xA334
+#define	reg_sfoe_divg_int_pos 5
+#define	reg_sfoe_divg_int_len 1
+#define	reg_sfoe_divg_int_lsb 0
+#define xd_r_reg_sfoe_divg_flag	0xA334
+#define	reg_sfoe_divg_flag_pos 6
+#define	reg_sfoe_divg_flag_len 1
+#define	reg_sfoe_divg_flag_lsb 0
+#define xd_p_reg_fft_rst	0xA335
+#define	reg_fft_rst_pos 0
+#define	reg_fft_rst_len 1
+#define	reg_fft_rst_lsb 0
+#define xd_p_reg_fft_fast_beacon	0xA335
+#define	reg_fft_fast_beacon_pos 1
+#define	reg_fft_fast_beacon_len 1
+#define	reg_fft_fast_beacon_lsb 0
+#define xd_p_reg_fft_fast_valid	0xA335
+#define	reg_fft_fast_valid_pos 2
+#define	reg_fft_fast_valid_len 1
+#define	reg_fft_fast_valid_lsb 0
+#define xd_p_reg_fft_mask_en	0xA335
+#define	reg_fft_mask_en_pos 3
+#define	reg_fft_mask_en_len 1
+#define	reg_fft_mask_en_lsb 0
+#define xd_p_reg_fft_crc_en	0xA335
+#define	reg_fft_crc_en_pos 4
+#define	reg_fft_crc_en_len 1
+#define	reg_fft_crc_en_lsb 0
+#define xd_p_reg_finr_en	0xA336
+#define	reg_finr_en_pos 0
+#define	reg_finr_en_len 1
+#define	reg_finr_en_lsb 0
+#define xd_p_fd_fste_en	0xA337
+#define	fd_fste_en_pos 1
+#define	fd_fste_en_len 1
+#define	fd_fste_en_lsb 0
+#define xd_p_fd_sqi_tps_level_shift	0xA338
+#define	fd_sqi_tps_level_shift_pos 0
+#define	fd_sqi_tps_level_shift_len 8
+#define	fd_sqi_tps_level_shift_lsb 0
+#define xd_p_fd_pilot_ma_len	0xA339
+#define	fd_pilot_ma_len_pos 0
+#define	fd_pilot_ma_len_len 6
+#define	fd_pilot_ma_len_lsb 0
+#define xd_p_fd_tps_ma_len	0xA33A
+#define	fd_tps_ma_len_pos 0
+#define	fd_tps_ma_len_len 6
+#define	fd_tps_ma_len_lsb 0
+#define xd_p_fd_sqi_s3	0xA33B
+#define	fd_sqi_s3_pos 0
+#define	fd_sqi_s3_len 8
+#define	fd_sqi_s3_lsb 0
+#define xd_p_fd_sqi_dummy_reg_0	0xA33C
+#define	fd_sqi_dummy_reg_0_pos 0
+#define	fd_sqi_dummy_reg_0_len 1
+#define	fd_sqi_dummy_reg_0_lsb 0
+#define xd_p_fd_sqi_debug_sel	0xA33C
+#define	fd_sqi_debug_sel_pos 1
+#define	fd_sqi_debug_sel_len 2
+#define	fd_sqi_debug_sel_lsb 0
+#define xd_p_fd_sqi_s2	0xA33C
+#define	fd_sqi_s2_pos 3
+#define	fd_sqi_s2_len 5
+#define	fd_sqi_s2_lsb 0
+#define xd_p_fd_sqi_dummy_reg_1	0xA33D
+#define	fd_sqi_dummy_reg_1_pos 0
+#define	fd_sqi_dummy_reg_1_len 1
+#define	fd_sqi_dummy_reg_1_lsb 0
+#define xd_p_fd_inr_ignore	0xA33D
+#define	fd_inr_ignore_pos 1
+#define	fd_inr_ignore_len 1
+#define	fd_inr_ignore_lsb 0
+#define xd_p_fd_pilot_ignore	0xA33D
+#define	fd_pilot_ignore_pos 2
+#define	fd_pilot_ignore_len 1
+#define	fd_pilot_ignore_lsb 0
+#define xd_p_fd_etps_ignore	0xA33D
+#define	fd_etps_ignore_pos 3
+#define	fd_etps_ignore_len 1
+#define	fd_etps_ignore_lsb 0
+#define xd_p_fd_sqi_s1	0xA33D
+#define	fd_sqi_s1_pos 4
+#define	fd_sqi_s1_len 4
+#define	fd_sqi_s1_lsb 0
+#define xd_p_reg_fste_ehw_7_0	0xA33E
+#define	reg_fste_ehw_7_0_pos 0
+#define	reg_fste_ehw_7_0_len 8
+#define	reg_fste_ehw_7_0_lsb 0
+#define xd_p_reg_fste_ehw_9_8	0xA33F
+#define	reg_fste_ehw_9_8_pos 0
+#define	reg_fste_ehw_9_8_len 2
+#define	reg_fste_ehw_9_8_lsb 8
+#define xd_p_reg_fste_i_adj_vld	0xA33F
+#define	reg_fste_i_adj_vld_pos 2
+#define	reg_fste_i_adj_vld_len 1
+#define	reg_fste_i_adj_vld_lsb 0
+#define xd_p_reg_fste_phase_ini_7_0	0xA340
+#define	reg_fste_phase_ini_7_0_pos 0
+#define	reg_fste_phase_ini_7_0_len 8
+#define	reg_fste_phase_ini_7_0_lsb 0
+#define xd_p_reg_fste_phase_ini_11_8	0xA341
+#define	reg_fste_phase_ini_11_8_pos 0
+#define	reg_fste_phase_ini_11_8_len 4
+#define	reg_fste_phase_ini_11_8_lsb 8
+#define xd_p_reg_fste_phase_inc_3_0	0xA341
+#define	reg_fste_phase_inc_3_0_pos 4
+#define	reg_fste_phase_inc_3_0_len 4
+#define	reg_fste_phase_inc_3_0_lsb 0
+#define xd_p_reg_fste_phase_inc_11_4	0xA342
+#define	reg_fste_phase_inc_11_4_pos 0
+#define	reg_fste_phase_inc_11_4_len 8
+#define	reg_fste_phase_inc_11_4_lsb 4
+#define xd_p_reg_fste_acum_cost_cnt_max	0xA343
+#define	reg_fste_acum_cost_cnt_max_pos 0
+#define	reg_fste_acum_cost_cnt_max_len 4
+#define	reg_fste_acum_cost_cnt_max_lsb 0
+#define xd_p_reg_fste_step_size_std	0xA343
+#define	reg_fste_step_size_std_pos 4
+#define	reg_fste_step_size_std_len 4
+#define	reg_fste_step_size_std_lsb 0
+#define xd_p_reg_fste_step_size_max	0xA344
+#define	reg_fste_step_size_max_pos 0
+#define	reg_fste_step_size_max_len 4
+#define	reg_fste_step_size_max_lsb 0
+#define xd_p_reg_fste_step_size_min	0xA344
+#define	reg_fste_step_size_min_pos 4
+#define	reg_fste_step_size_min_len 4
+#define	reg_fste_step_size_min_lsb 0
+#define xd_p_reg_fste_frac_step_size_7_0	0xA345
+#define	reg_fste_frac_step_size_7_0_pos 0
+#define	reg_fste_frac_step_size_7_0_len 8
+#define	reg_fste_frac_step_size_7_0_lsb 0
+#define xd_p_reg_fste_frac_step_size_15_8	0xA346
+#define	reg_fste_frac_step_size_15_8_pos 0
+#define	reg_fste_frac_step_size_15_8_len 8
+#define	reg_fste_frac_step_size_15_8_lsb 8
+#define xd_p_reg_fste_frac_step_size_19_16	0xA347
+#define	reg_fste_frac_step_size_19_16_pos 0
+#define	reg_fste_frac_step_size_19_16_len 4
+#define	reg_fste_frac_step_size_19_16_lsb 16
+#define xd_p_reg_fste_rpd_dir_cnt_max	0xA347
+#define	reg_fste_rpd_dir_cnt_max_pos 4
+#define	reg_fste_rpd_dir_cnt_max_len 4
+#define	reg_fste_rpd_dir_cnt_max_lsb 0
+#define xd_p_reg_fste_ehs	0xA348
+#define	reg_fste_ehs_pos 0
+#define	reg_fste_ehs_len 4
+#define	reg_fste_ehs_lsb 0
+#define xd_p_reg_fste_frac_cost_cnt_max_3_0	0xA348
+#define	reg_fste_frac_cost_cnt_max_3_0_pos 4
+#define	reg_fste_frac_cost_cnt_max_3_0_len 4
+#define	reg_fste_frac_cost_cnt_max_3_0_lsb 0
+#define xd_p_reg_fste_frac_cost_cnt_max_9_4	0xA349
+#define	reg_fste_frac_cost_cnt_max_9_4_pos 0
+#define	reg_fste_frac_cost_cnt_max_9_4_len 6
+#define	reg_fste_frac_cost_cnt_max_9_4_lsb 4
+#define xd_p_reg_fste_w0_7_0	0xA34A
+#define	reg_fste_w0_7_0_pos 0
+#define	reg_fste_w0_7_0_len 8
+#define	reg_fste_w0_7_0_lsb 0
+#define xd_p_reg_fste_w0_11_8	0xA34B
+#define	reg_fste_w0_11_8_pos 0
+#define	reg_fste_w0_11_8_len 4
+#define	reg_fste_w0_11_8_lsb 8
+#define xd_p_reg_fste_w1_3_0	0xA34B
+#define	reg_fste_w1_3_0_pos 4
+#define	reg_fste_w1_3_0_len 4
+#define	reg_fste_w1_3_0_lsb 0
+#define xd_p_reg_fste_w1_11_4	0xA34C
+#define	reg_fste_w1_11_4_pos 0
+#define	reg_fste_w1_11_4_len 8
+#define	reg_fste_w1_11_4_lsb 4
+#define xd_p_reg_fste_w2_7_0	0xA34D
+#define	reg_fste_w2_7_0_pos 0
+#define	reg_fste_w2_7_0_len 8
+#define	reg_fste_w2_7_0_lsb 0
+#define xd_p_reg_fste_w2_11_8	0xA34E
+#define	reg_fste_w2_11_8_pos 0
+#define	reg_fste_w2_11_8_len 4
+#define	reg_fste_w2_11_8_lsb 8
+#define xd_p_reg_fste_w3_3_0	0xA34E
+#define	reg_fste_w3_3_0_pos 4
+#define	reg_fste_w3_3_0_len 4
+#define	reg_fste_w3_3_0_lsb 0
+#define xd_p_reg_fste_w3_11_4	0xA34F
+#define	reg_fste_w3_11_4_pos 0
+#define	reg_fste_w3_11_4_len 8
+#define	reg_fste_w3_11_4_lsb 4
+#define xd_p_reg_fste_w4_7_0	0xA350
+#define	reg_fste_w4_7_0_pos 0
+#define	reg_fste_w4_7_0_len 8
+#define	reg_fste_w4_7_0_lsb 0
+#define xd_p_reg_fste_w4_11_8	0xA351
+#define	reg_fste_w4_11_8_pos 0
+#define	reg_fste_w4_11_8_len 4
+#define	reg_fste_w4_11_8_lsb 8
+#define xd_p_reg_fste_w5_3_0	0xA351
+#define	reg_fste_w5_3_0_pos 4
+#define	reg_fste_w5_3_0_len 4
+#define	reg_fste_w5_3_0_lsb 0
+#define xd_p_reg_fste_w5_11_4	0xA352
+#define	reg_fste_w5_11_4_pos 0
+#define	reg_fste_w5_11_4_len 8
+#define	reg_fste_w5_11_4_lsb 4
+#define xd_p_reg_fste_w6_7_0	0xA353
+#define	reg_fste_w6_7_0_pos 0
+#define	reg_fste_w6_7_0_len 8
+#define	reg_fste_w6_7_0_lsb 0
+#define xd_p_reg_fste_w6_11_8	0xA354
+#define	reg_fste_w6_11_8_pos 0
+#define	reg_fste_w6_11_8_len 4
+#define	reg_fste_w6_11_8_lsb 8
+#define xd_p_reg_fste_w7_3_0	0xA354
+#define	reg_fste_w7_3_0_pos 4
+#define	reg_fste_w7_3_0_len 4
+#define	reg_fste_w7_3_0_lsb 0
+#define xd_p_reg_fste_w7_11_4	0xA355
+#define	reg_fste_w7_11_4_pos 0
+#define	reg_fste_w7_11_4_len 8
+#define	reg_fste_w7_11_4_lsb 4
+#define xd_p_reg_fste_w8_7_0	0xA356
+#define	reg_fste_w8_7_0_pos 0
+#define	reg_fste_w8_7_0_len 8
+#define	reg_fste_w8_7_0_lsb 0
+#define xd_p_reg_fste_w8_11_8	0xA357
+#define	reg_fste_w8_11_8_pos 0
+#define	reg_fste_w8_11_8_len 4
+#define	reg_fste_w8_11_8_lsb 8
+#define xd_p_reg_fste_w9_3_0	0xA357
+#define	reg_fste_w9_3_0_pos 4
+#define	reg_fste_w9_3_0_len 4
+#define	reg_fste_w9_3_0_lsb 0
+#define xd_p_reg_fste_w9_11_4	0xA358
+#define	reg_fste_w9_11_4_pos 0
+#define	reg_fste_w9_11_4_len 8
+#define	reg_fste_w9_11_4_lsb 4
+#define xd_p_reg_fste_wa_7_0	0xA359
+#define	reg_fste_wa_7_0_pos 0
+#define	reg_fste_wa_7_0_len 8
+#define	reg_fste_wa_7_0_lsb 0
+#define xd_p_reg_fste_wa_11_8	0xA35A
+#define	reg_fste_wa_11_8_pos 0
+#define	reg_fste_wa_11_8_len 4
+#define	reg_fste_wa_11_8_lsb 8
+#define xd_p_reg_fste_wb_3_0	0xA35A
+#define	reg_fste_wb_3_0_pos 4
+#define	reg_fste_wb_3_0_len 4
+#define	reg_fste_wb_3_0_lsb 0
+#define xd_p_reg_fste_wb_11_4	0xA35B
+#define	reg_fste_wb_11_4_pos 0
+#define	reg_fste_wb_11_4_len 8
+#define	reg_fste_wb_11_4_lsb 4
+#define xd_r_fd_fste_i_adj	0xA35C
+#define	fd_fste_i_adj_pos 0
+#define	fd_fste_i_adj_len 5
+#define	fd_fste_i_adj_lsb 0
+#define xd_r_fd_fste_f_adj_7_0	0xA35D
+#define	fd_fste_f_adj_7_0_pos 0
+#define	fd_fste_f_adj_7_0_len 8
+#define	fd_fste_f_adj_7_0_lsb 0
+#define xd_r_fd_fste_f_adj_15_8	0xA35E
+#define	fd_fste_f_adj_15_8_pos 0
+#define	fd_fste_f_adj_15_8_len 8
+#define	fd_fste_f_adj_15_8_lsb 8
+#define xd_r_fd_fste_f_adj_19_16	0xA35F
+#define	fd_fste_f_adj_19_16_pos 0
+#define	fd_fste_f_adj_19_16_len 4
+#define	fd_fste_f_adj_19_16_lsb 16
+#define xd_p_reg_feq_Leak_Bypass	0xA366
+#define	reg_feq_Leak_Bypass_pos 0
+#define	reg_feq_Leak_Bypass_len 1
+#define	reg_feq_Leak_Bypass_lsb 0
+#define xd_p_reg_feq_Leak_Mneg1	0xA366
+#define	reg_feq_Leak_Mneg1_pos 1
+#define	reg_feq_Leak_Mneg1_len 3
+#define	reg_feq_Leak_Mneg1_lsb 0
+#define xd_p_reg_feq_Leak_B_ShiftQ	0xA366
+#define	reg_feq_Leak_B_ShiftQ_pos 4
+#define	reg_feq_Leak_B_ShiftQ_len 4
+#define	reg_feq_Leak_B_ShiftQ_lsb 0
+#define xd_p_reg_feq_Leak_B_Float0	0xA367
+#define	reg_feq_Leak_B_Float0_pos 0
+#define	reg_feq_Leak_B_Float0_len 8
+#define	reg_feq_Leak_B_Float0_lsb 0
+#define xd_p_reg_feq_Leak_B_Float1	0xA368
+#define	reg_feq_Leak_B_Float1_pos 0
+#define	reg_feq_Leak_B_Float1_len 8
+#define	reg_feq_Leak_B_Float1_lsb 0
+#define xd_p_reg_feq_Leak_B_Float2	0xA369
+#define	reg_feq_Leak_B_Float2_pos 0
+#define	reg_feq_Leak_B_Float2_len 8
+#define	reg_feq_Leak_B_Float2_lsb 0
+#define xd_p_reg_feq_Leak_B_Float3	0xA36A
+#define	reg_feq_Leak_B_Float3_pos 0
+#define	reg_feq_Leak_B_Float3_len 8
+#define	reg_feq_Leak_B_Float3_lsb 0
+#define xd_p_reg_feq_Leak_B_Float4	0xA36B
+#define	reg_feq_Leak_B_Float4_pos 0
+#define	reg_feq_Leak_B_Float4_len 8
+#define	reg_feq_Leak_B_Float4_lsb 0
+#define xd_p_reg_feq_Leak_B_Float5	0xA36C
+#define	reg_feq_Leak_B_Float5_pos 0
+#define	reg_feq_Leak_B_Float5_len 8
+#define	reg_feq_Leak_B_Float5_lsb 0
+#define xd_p_reg_feq_Leak_B_Float6	0xA36D
+#define	reg_feq_Leak_B_Float6_pos 0
+#define	reg_feq_Leak_B_Float6_len 8
+#define	reg_feq_Leak_B_Float6_lsb 0
+#define xd_p_reg_feq_Leak_B_Float7	0xA36E
+#define	reg_feq_Leak_B_Float7_pos 0
+#define	reg_feq_Leak_B_Float7_len 8
+#define	reg_feq_Leak_B_Float7_lsb 0
+#define xd_r_reg_feq_data_h2_7_0	0xA36F
+#define	reg_feq_data_h2_7_0_pos 0
+#define	reg_feq_data_h2_7_0_len 8
+#define	reg_feq_data_h2_7_0_lsb 0
+#define xd_r_reg_feq_data_h2_9_8	0xA370
+#define	reg_feq_data_h2_9_8_pos 0
+#define	reg_feq_data_h2_9_8_len 2
+#define	reg_feq_data_h2_9_8_lsb 8
+#define xd_p_reg_feq_leak_use_slice_tps	0xA371
+#define	reg_feq_leak_use_slice_tps_pos 0
+#define	reg_feq_leak_use_slice_tps_len 1
+#define	reg_feq_leak_use_slice_tps_lsb 0
+#define xd_p_reg_feq_read_update	0xA371
+#define	reg_feq_read_update_pos 1
+#define	reg_feq_read_update_len 1
+#define	reg_feq_read_update_lsb 0
+#define xd_p_reg_feq_data_vld	0xA371
+#define	reg_feq_data_vld_pos 2
+#define	reg_feq_data_vld_len 1
+#define	reg_feq_data_vld_lsb 0
+#define xd_p_reg_feq_tone_idx_4_0	0xA371
+#define	reg_feq_tone_idx_4_0_pos 3
+#define	reg_feq_tone_idx_4_0_len 5
+#define	reg_feq_tone_idx_4_0_lsb 0
+#define xd_p_reg_feq_tone_idx_12_5	0xA372
+#define	reg_feq_tone_idx_12_5_pos 0
+#define	reg_feq_tone_idx_12_5_len 8
+#define	reg_feq_tone_idx_12_5_lsb 5
+#define xd_r_reg_feq_data_re_7_0	0xA373
+#define	reg_feq_data_re_7_0_pos 0
+#define	reg_feq_data_re_7_0_len 8
+#define	reg_feq_data_re_7_0_lsb 0
+#define xd_r_reg_feq_data_re_10_8	0xA374
+#define	reg_feq_data_re_10_8_pos 0
+#define	reg_feq_data_re_10_8_len 3
+#define	reg_feq_data_re_10_8_lsb 8
+#define xd_r_reg_feq_data_im_7_0	0xA375
+#define	reg_feq_data_im_7_0_pos 0
+#define	reg_feq_data_im_7_0_len 8
+#define	reg_feq_data_im_7_0_lsb 0
+#define xd_r_reg_feq_data_im_10_8	0xA376
+#define	reg_feq_data_im_10_8_pos 0
+#define	reg_feq_data_im_10_8_len 3
+#define	reg_feq_data_im_10_8_lsb 8
+#define xd_r_reg_feq_y_re	0xA377
+#define	reg_feq_y_re_pos 0
+#define	reg_feq_y_re_len 8
+#define	reg_feq_y_re_lsb 0
+#define xd_r_reg_feq_y_im	0xA378
+#define	reg_feq_y_im_pos 0
+#define	reg_feq_y_im_len 8
+#define	reg_feq_y_im_lsb 0
+#define xd_r_reg_feq_h_re_7_0	0xA379
+#define	reg_feq_h_re_7_0_pos 0
+#define	reg_feq_h_re_7_0_len 8
+#define	reg_feq_h_re_7_0_lsb 0
+#define xd_r_reg_feq_h_re_8	0xA37A
+#define	reg_feq_h_re_8_pos 0
+#define	reg_feq_h_re_8_len 1
+#define	reg_feq_h_re_8_lsb 0
+#define xd_r_reg_feq_h_im_7_0	0xA37B
+#define	reg_feq_h_im_7_0_pos 0
+#define	reg_feq_h_im_7_0_len 8
+#define	reg_feq_h_im_7_0_lsb 0
+#define xd_r_reg_feq_h_im_8	0xA37C
+#define	reg_feq_h_im_8_pos 0
+#define	reg_feq_h_im_8_len 1
+#define	reg_feq_h_im_8_lsb 0
+#define xd_p_fec_super_frm_unit_7_0	0xA380
+#define	fec_super_frm_unit_7_0_pos 0
+#define	fec_super_frm_unit_7_0_len 8
+#define	fec_super_frm_unit_7_0_lsb 0
+#define xd_p_fec_super_frm_unit_15_8	0xA381
+#define	fec_super_frm_unit_15_8_pos 0
+#define	fec_super_frm_unit_15_8_len 8
+#define	fec_super_frm_unit_15_8_lsb 8
+#define xd_r_fec_vtb_err_bit_cnt_7_0	0xA382
+#define	fec_vtb_err_bit_cnt_7_0_pos 0
+#define	fec_vtb_err_bit_cnt_7_0_len 8
+#define	fec_vtb_err_bit_cnt_7_0_lsb 0
+#define xd_r_fec_vtb_err_bit_cnt_15_8	0xA383
+#define	fec_vtb_err_bit_cnt_15_8_pos 0
+#define	fec_vtb_err_bit_cnt_15_8_len 8
+#define	fec_vtb_err_bit_cnt_15_8_lsb 8
+#define xd_r_fec_vtb_err_bit_cnt_23_16	0xA384
+#define	fec_vtb_err_bit_cnt_23_16_pos 0
+#define	fec_vtb_err_bit_cnt_23_16_len 8
+#define	fec_vtb_err_bit_cnt_23_16_lsb 16
+#define xd_p_fec_rsd_packet_unit_7_0	0xA385
+#define	fec_rsd_packet_unit_7_0_pos 0
+#define	fec_rsd_packet_unit_7_0_len 8
+#define	fec_rsd_packet_unit_7_0_lsb 0
+#define xd_p_fec_rsd_packet_unit_15_8	0xA386
+#define	fec_rsd_packet_unit_15_8_pos 0
+#define	fec_rsd_packet_unit_15_8_len 8
+#define	fec_rsd_packet_unit_15_8_lsb 8
+#define xd_r_fec_rsd_bit_err_cnt_7_0	0xA387
+#define	fec_rsd_bit_err_cnt_7_0_pos 0
+#define	fec_rsd_bit_err_cnt_7_0_len 8
+#define	fec_rsd_bit_err_cnt_7_0_lsb 0
+#define xd_r_fec_rsd_bit_err_cnt_15_8	0xA388
+#define	fec_rsd_bit_err_cnt_15_8_pos 0
+#define	fec_rsd_bit_err_cnt_15_8_len 8
+#define	fec_rsd_bit_err_cnt_15_8_lsb 8
+#define xd_r_fec_rsd_bit_err_cnt_23_16	0xA389
+#define	fec_rsd_bit_err_cnt_23_16_pos 0
+#define	fec_rsd_bit_err_cnt_23_16_len 8
+#define	fec_rsd_bit_err_cnt_23_16_lsb 16
+#define xd_r_fec_rsd_abort_packet_cnt_7_0	0xA38A
+#define	fec_rsd_abort_packet_cnt_7_0_pos 0
+#define	fec_rsd_abort_packet_cnt_7_0_len 8
+#define	fec_rsd_abort_packet_cnt_7_0_lsb 0
+#define xd_r_fec_rsd_abort_packet_cnt_15_8	0xA38B
+#define	fec_rsd_abort_packet_cnt_15_8_pos 0
+#define	fec_rsd_abort_packet_cnt_15_8_len 8
+#define	fec_rsd_abort_packet_cnt_15_8_lsb 8
+#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_7_0	0xA38C
+#define	fec_RSD_PKT_NUM_PER_UNIT_7_0_pos 0
+#define	fec_RSD_PKT_NUM_PER_UNIT_7_0_len 8
+#define	fec_RSD_PKT_NUM_PER_UNIT_7_0_lsb 0
+#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_15_8	0xA38D
+#define	fec_RSD_PKT_NUM_PER_UNIT_15_8_pos 0
+#define	fec_RSD_PKT_NUM_PER_UNIT_15_8_len 8
+#define	fec_RSD_PKT_NUM_PER_UNIT_15_8_lsb 8
+#define xd_p_fec_RS_TH_1_7_0	0xA38E
+#define	fec_RS_TH_1_7_0_pos 0
+#define	fec_RS_TH_1_7_0_len 8
+#define	fec_RS_TH_1_7_0_lsb 0
+#define xd_p_fec_RS_TH_1_15_8	0xA38F
+#define	fec_RS_TH_1_15_8_pos 0
+#define	fec_RS_TH_1_15_8_len 8
+#define	fec_RS_TH_1_15_8_lsb 8
+#define xd_p_fec_RS_TH_2	0xA390
+#define	fec_RS_TH_2_pos 0
+#define	fec_RS_TH_2_len 8
+#define	fec_RS_TH_2_lsb 0
+#define xd_p_fec_mon_en	0xA391
+#define	fec_mon_en_pos 0
+#define	fec_mon_en_len 1
+#define	fec_mon_en_lsb 0
+#define xd_p_reg_b8to47	0xA391
+#define	reg_b8to47_pos 1
+#define	reg_b8to47_len 1
+#define	reg_b8to47_lsb 0
+#define xd_p_reg_rsd_sync_rep	0xA391
+#define	reg_rsd_sync_rep_pos 2
+#define	reg_rsd_sync_rep_len 1
+#define	reg_rsd_sync_rep_lsb 0
+#define xd_p_fec_rsd_retrain_rst	0xA391
+#define	fec_rsd_retrain_rst_pos 3
+#define	fec_rsd_retrain_rst_len 1
+#define	fec_rsd_retrain_rst_lsb 0
+#define xd_r_fec_rsd_ber_rdy	0xA391
+#define	fec_rsd_ber_rdy_pos 4
+#define	fec_rsd_ber_rdy_len 1
+#define	fec_rsd_ber_rdy_lsb 0
+#define xd_p_fec_rsd_ber_rst	0xA391
+#define	fec_rsd_ber_rst_pos 5
+#define	fec_rsd_ber_rst_len 1
+#define	fec_rsd_ber_rst_lsb 0
+#define xd_r_fec_vtb_ber_rdy	0xA391
+#define	fec_vtb_ber_rdy_pos 6
+#define	fec_vtb_ber_rdy_len 1
+#define	fec_vtb_ber_rdy_lsb 0
+#define xd_p_fec_vtb_ber_rst	0xA391
+#define	fec_vtb_ber_rst_pos 7
+#define	fec_vtb_ber_rst_len 1
+#define	fec_vtb_ber_rst_lsb 0
+#define xd_p_reg_vtb_clk40en	0xA392
+#define	reg_vtb_clk40en_pos 0
+#define	reg_vtb_clk40en_len 1
+#define	reg_vtb_clk40en_lsb 0
+#define xd_p_fec_vtb_rsd_mon_en	0xA392
+#define	fec_vtb_rsd_mon_en_pos 1
+#define	fec_vtb_rsd_mon_en_len 1
+#define	fec_vtb_rsd_mon_en_lsb 0
+#define xd_p_reg_fec_data_en	0xA392
+#define	reg_fec_data_en_pos 2
+#define	reg_fec_data_en_len 1
+#define	reg_fec_data_en_lsb 0
+#define xd_p_fec_dummy_reg_2	0xA392
+#define	fec_dummy_reg_2_pos 3
+#define	fec_dummy_reg_2_len 3
+#define	fec_dummy_reg_2_lsb 0
+#define xd_p_reg_sync_chk	0xA392
+#define	reg_sync_chk_pos 6
+#define	reg_sync_chk_len 1
+#define	reg_sync_chk_lsb 0
+#define xd_p_fec_rsd_bypass	0xA392
+#define	fec_rsd_bypass_pos 7
+#define	fec_rsd_bypass_len 1
+#define	fec_rsd_bypass_lsb 0
+#define xd_p_fec_sw_rst	0xA393
+#define	fec_sw_rst_pos 0
+#define	fec_sw_rst_len 1
+#define	fec_sw_rst_lsb 0
+#define xd_r_fec_vtb_pm_crc	0xA394
+#define	fec_vtb_pm_crc_pos 0
+#define	fec_vtb_pm_crc_len 8
+#define	fec_vtb_pm_crc_lsb 0
+#define xd_r_fec_vtb_tb_7_crc	0xA395
+#define	fec_vtb_tb_7_crc_pos 0
+#define	fec_vtb_tb_7_crc_len 8
+#define	fec_vtb_tb_7_crc_lsb 0
+#define xd_r_fec_vtb_tb_6_crc	0xA396
+#define	fec_vtb_tb_6_crc_pos 0
+#define	fec_vtb_tb_6_crc_len 8
+#define	fec_vtb_tb_6_crc_lsb 0
+#define xd_r_fec_vtb_tb_5_crc	0xA397
+#define	fec_vtb_tb_5_crc_pos 0
+#define	fec_vtb_tb_5_crc_len 8
+#define	fec_vtb_tb_5_crc_lsb 0
+#define xd_r_fec_vtb_tb_4_crc	0xA398
+#define	fec_vtb_tb_4_crc_pos 0
+#define	fec_vtb_tb_4_crc_len 8
+#define	fec_vtb_tb_4_crc_lsb 0
+#define xd_r_fec_vtb_tb_3_crc	0xA399
+#define	fec_vtb_tb_3_crc_pos 0
+#define	fec_vtb_tb_3_crc_len 8
+#define	fec_vtb_tb_3_crc_lsb 0
+#define xd_r_fec_vtb_tb_2_crc	0xA39A
+#define	fec_vtb_tb_2_crc_pos 0
+#define	fec_vtb_tb_2_crc_len 8
+#define	fec_vtb_tb_2_crc_lsb 0
+#define xd_r_fec_vtb_tb_1_crc	0xA39B
+#define	fec_vtb_tb_1_crc_pos 0
+#define	fec_vtb_tb_1_crc_len 8
+#define	fec_vtb_tb_1_crc_lsb 0
+#define xd_r_fec_vtb_tb_0_crc	0xA39C
+#define	fec_vtb_tb_0_crc_pos 0
+#define	fec_vtb_tb_0_crc_len 8
+#define	fec_vtb_tb_0_crc_lsb 0
+#define xd_r_fec_rsd_bank0_crc	0xA39D
+#define	fec_rsd_bank0_crc_pos 0
+#define	fec_rsd_bank0_crc_len 8
+#define	fec_rsd_bank0_crc_lsb 0
+#define xd_r_fec_rsd_bank1_crc	0xA39E
+#define	fec_rsd_bank1_crc_pos 0
+#define	fec_rsd_bank1_crc_len 8
+#define	fec_rsd_bank1_crc_lsb 0
+#define xd_r_fec_idi_vtb_crc	0xA39F
+#define	fec_idi_vtb_crc_pos 0
+#define	fec_idi_vtb_crc_len 8
+#define	fec_idi_vtb_crc_lsb 0
+#define xd_g_reg_tpsd_txmod	0xA3C0
+#define	reg_tpsd_txmod_pos 0
+#define	reg_tpsd_txmod_len 2
+#define	reg_tpsd_txmod_lsb 0
+#define xd_g_reg_tpsd_gi	0xA3C0
+#define	reg_tpsd_gi_pos 2
+#define	reg_tpsd_gi_len 2
+#define	reg_tpsd_gi_lsb 0
+#define xd_g_reg_tpsd_hier	0xA3C0
+#define	reg_tpsd_hier_pos 4
+#define	reg_tpsd_hier_len 3
+#define	reg_tpsd_hier_lsb 0
+#define xd_g_reg_bw	0xA3C1
+#define	reg_bw_pos 2
+#define	reg_bw_len 2
+#define	reg_bw_lsb 0
+#define xd_g_reg_dec_pri	0xA3C1
+#define	reg_dec_pri_pos 4
+#define	reg_dec_pri_len 1
+#define	reg_dec_pri_lsb 0
+#define xd_g_reg_tpsd_const	0xA3C1
+#define	reg_tpsd_const_pos 6
+#define	reg_tpsd_const_len 2
+#define	reg_tpsd_const_lsb 0
+#define xd_g_reg_tpsd_hpcr	0xA3C2
+#define	reg_tpsd_hpcr_pos 0
+#define	reg_tpsd_hpcr_len 3
+#define	reg_tpsd_hpcr_lsb 0
+#define xd_g_reg_tpsd_lpcr	0xA3C2
+#define	reg_tpsd_lpcr_pos 3
+#define	reg_tpsd_lpcr_len 3
+#define	reg_tpsd_lpcr_lsb 0
+#define xd_g_reg_ofsm_clk	0xA3D0
+#define	reg_ofsm_clk_pos 0
+#define	reg_ofsm_clk_len 3
+#define	reg_ofsm_clk_lsb 0
+#define xd_g_reg_fclk_cfg	0xA3D1
+#define	reg_fclk_cfg_pos 0
+#define	reg_fclk_cfg_len 1
+#define	reg_fclk_cfg_lsb 0
+#define xd_g_reg_fclk_idi	0xA3D1
+#define	reg_fclk_idi_pos 1
+#define	reg_fclk_idi_len 1
+#define	reg_fclk_idi_lsb 0
+#define xd_g_reg_fclk_odi	0xA3D1
+#define	reg_fclk_odi_pos 2
+#define	reg_fclk_odi_len 1
+#define	reg_fclk_odi_lsb 0
+#define xd_g_reg_fclk_rsd	0xA3D1
+#define	reg_fclk_rsd_pos 3
+#define	reg_fclk_rsd_len 1
+#define	reg_fclk_rsd_lsb 0
+#define xd_g_reg_fclk_vtb	0xA3D1
+#define	reg_fclk_vtb_pos 4
+#define	reg_fclk_vtb_len 1
+#define	reg_fclk_vtb_lsb 0
+#define xd_g_reg_fclk_cste	0xA3D1
+#define	reg_fclk_cste_pos 5
+#define	reg_fclk_cste_len 1
+#define	reg_fclk_cste_lsb 0
+#define xd_g_reg_fclk_mp2if	0xA3D1
+#define	reg_fclk_mp2if_pos 6
+#define	reg_fclk_mp2if_len 1
+#define	reg_fclk_mp2if_lsb 0
+#define xd_I2C_i2c_m_slave_addr	0xA400
+#define	i2c_m_slave_addr_pos 0
+#define	i2c_m_slave_addr_len 8
+#define	i2c_m_slave_addr_lsb 0
+#define xd_I2C_i2c_m_data1	0xA401
+#define	i2c_m_data1_pos 0
+#define	i2c_m_data1_len 8
+#define	i2c_m_data1_lsb 0
+#define xd_I2C_i2c_m_data2	0xA402
+#define	i2c_m_data2_pos 0
+#define	i2c_m_data2_len 8
+#define	i2c_m_data2_lsb 0
+#define xd_I2C_i2c_m_data3	0xA403
+#define	i2c_m_data3_pos 0
+#define	i2c_m_data3_len 8
+#define	i2c_m_data3_lsb 0
+#define xd_I2C_i2c_m_data4	0xA404
+#define	i2c_m_data4_pos 0
+#define	i2c_m_data4_len 8
+#define	i2c_m_data4_lsb 0
+#define xd_I2C_i2c_m_data5	0xA405
+#define	i2c_m_data5_pos 0
+#define	i2c_m_data5_len 8
+#define	i2c_m_data5_lsb 0
+#define xd_I2C_i2c_m_data6	0xA406
+#define	i2c_m_data6_pos 0
+#define	i2c_m_data6_len 8
+#define	i2c_m_data6_lsb 0
+#define xd_I2C_i2c_m_data7	0xA407
+#define	i2c_m_data7_pos 0
+#define	i2c_m_data7_len 8
+#define	i2c_m_data7_lsb 0
+#define xd_I2C_i2c_m_data8	0xA408
+#define	i2c_m_data8_pos 0
+#define	i2c_m_data8_len 8
+#define	i2c_m_data8_lsb 0
+#define xd_I2C_i2c_m_data9	0xA409
+#define	i2c_m_data9_pos 0
+#define	i2c_m_data9_len 8
+#define	i2c_m_data9_lsb 0
+#define xd_I2C_i2c_m_data10	0xA40A
+#define	i2c_m_data10_pos 0
+#define	i2c_m_data10_len 8
+#define	i2c_m_data10_lsb 0
+#define xd_I2C_i2c_m_data11	0xA40B
+#define	i2c_m_data11_pos 0
+#define	i2c_m_data11_len 8
+#define	i2c_m_data11_lsb 0
+#define xd_I2C_i2c_m_cmd_rw	0xA40C
+#define	i2c_m_cmd_rw_pos 0
+#define	i2c_m_cmd_rw_len 1
+#define	i2c_m_cmd_rw_lsb 0
+#define xd_I2C_i2c_m_cmd_rwlen	0xA40C
+#define	i2c_m_cmd_rwlen_pos 3
+#define	i2c_m_cmd_rwlen_len 4
+#define	i2c_m_cmd_rwlen_lsb 0
+#define xd_I2C_i2c_m_status_cmd_exe	0xA40D
+#define	i2c_m_status_cmd_exe_pos 0
+#define	i2c_m_status_cmd_exe_len 1
+#define	i2c_m_status_cmd_exe_lsb 0
+#define xd_I2C_i2c_m_status_wdat_done	0xA40D
+#define	i2c_m_status_wdat_done_pos 1
+#define	i2c_m_status_wdat_done_len 1
+#define	i2c_m_status_wdat_done_lsb 0
+#define xd_I2C_i2c_m_status_wdat_fail	0xA40D
+#define	i2c_m_status_wdat_fail_pos 2
+#define	i2c_m_status_wdat_fail_len 1
+#define	i2c_m_status_wdat_fail_lsb 0
+#define xd_I2C_i2c_m_period	0xA40E
+#define	i2c_m_period_pos 0
+#define	i2c_m_period_len 8
+#define	i2c_m_period_lsb 0
+#define xd_I2C_i2c_m_reg_msb_lsb	0xA40F
+#define	i2c_m_reg_msb_lsb_pos 0
+#define	i2c_m_reg_msb_lsb_len 1
+#define	i2c_m_reg_msb_lsb_lsb 0
+#define xd_I2C_reg_ofdm_rst	0xA40F
+#define	reg_ofdm_rst_pos 1
+#define	reg_ofdm_rst_len 1
+#define	reg_ofdm_rst_lsb 0
+#define xd_I2C_reg_sample_period_on_tuner	0xA40F
+#define	reg_sample_period_on_tuner_pos 2
+#define	reg_sample_period_on_tuner_len 1
+#define	reg_sample_period_on_tuner_lsb 0
+#define xd_I2C_reg_rst_i2c	0xA40F
+#define	reg_rst_i2c_pos 3
+#define	reg_rst_i2c_len 1
+#define	reg_rst_i2c_lsb 0
+#define xd_I2C_reg_ofdm_rst_en	0xA40F
+#define	reg_ofdm_rst_en_pos 4
+#define	reg_ofdm_rst_en_len 1
+#define	reg_ofdm_rst_en_lsb 0
+#define xd_I2C_reg_tuner_sda_sync_on	0xA40F
+#define	reg_tuner_sda_sync_on_pos 5
+#define	reg_tuner_sda_sync_on_len 1
+#define	reg_tuner_sda_sync_on_lsb 0
+#define xd_p_mp2if_data_access_disable_ofsm	0xA500
+#define	mp2if_data_access_disable_ofsm_pos 0
+#define	mp2if_data_access_disable_ofsm_len 1
+#define	mp2if_data_access_disable_ofsm_lsb 0
+#define xd_p_reg_mp2_sw_rst_ofsm	0xA500
+#define	reg_mp2_sw_rst_ofsm_pos 1
+#define	reg_mp2_sw_rst_ofsm_len 1
+#define	reg_mp2_sw_rst_ofsm_lsb 0
+#define xd_p_reg_mp2if_clk_en_ofsm	0xA500
+#define	reg_mp2if_clk_en_ofsm_pos 2
+#define	reg_mp2if_clk_en_ofsm_len 1
+#define	reg_mp2if_clk_en_ofsm_lsb 0
+#define xd_r_mp2if_sync_byte_locked	0xA500
+#define	mp2if_sync_byte_locked_pos 3
+#define	mp2if_sync_byte_locked_len 1
+#define	mp2if_sync_byte_locked_lsb 0
+#define xd_r_mp2if_ts_not_188	0xA500
+#define	mp2if_ts_not_188_pos 4
+#define	mp2if_ts_not_188_len 1
+#define	mp2if_ts_not_188_lsb 0
+#define xd_r_mp2if_psb_empty	0xA500
+#define	mp2if_psb_empty_pos 5
+#define	mp2if_psb_empty_len 1
+#define	mp2if_psb_empty_lsb 0
+#define xd_r_mp2if_psb_overflow	0xA500
+#define	mp2if_psb_overflow_pos 6
+#define	mp2if_psb_overflow_len 1
+#define	mp2if_psb_overflow_lsb 0
+#define xd_p_mp2if_keep_sf_sync_byte_ofsm	0xA500
+#define	mp2if_keep_sf_sync_byte_ofsm_pos 7
+#define	mp2if_keep_sf_sync_byte_ofsm_len 1
+#define	mp2if_keep_sf_sync_byte_ofsm_lsb 0
+#define xd_r_mp2if_psb_mp2if_num_pkt	0xA501
+#define	mp2if_psb_mp2if_num_pkt_pos 0
+#define	mp2if_psb_mp2if_num_pkt_len 6
+#define	mp2if_psb_mp2if_num_pkt_lsb 0
+#define xd_p_reg_mpeg_full_speed_ofsm	0xA501
+#define	reg_mpeg_full_speed_ofsm_pos 6
+#define	reg_mpeg_full_speed_ofsm_len 1
+#define	reg_mpeg_full_speed_ofsm_lsb 0
+#define xd_p_mp2if_mpeg_ser_mode_ofsm	0xA501
+#define	mp2if_mpeg_ser_mode_ofsm_pos 7
+#define	mp2if_mpeg_ser_mode_ofsm_len 1
+#define	mp2if_mpeg_ser_mode_ofsm_lsb 0
+#define xd_p_reg_sw_mon51	0xA600
+#define	reg_sw_mon51_pos 0
+#define	reg_sw_mon51_len 8
+#define	reg_sw_mon51_lsb 0
+#define xd_p_reg_top_pcsel	0xA601
+#define	reg_top_pcsel_pos 0
+#define	reg_top_pcsel_len 1
+#define	reg_top_pcsel_lsb 0
+#define xd_p_reg_top_rs232	0xA601
+#define	reg_top_rs232_pos 1
+#define	reg_top_rs232_len 1
+#define	reg_top_rs232_lsb 0
+#define xd_p_reg_top_pcout	0xA601
+#define	reg_top_pcout_pos 2
+#define	reg_top_pcout_len 1
+#define	reg_top_pcout_lsb 0
+#define xd_p_reg_top_debug	0xA601
+#define	reg_top_debug_pos 3
+#define	reg_top_debug_len 1
+#define	reg_top_debug_lsb 0
+#define xd_p_reg_top_adcdly	0xA601
+#define	reg_top_adcdly_pos 4
+#define	reg_top_adcdly_len 2
+#define	reg_top_adcdly_lsb 0
+#define xd_p_reg_top_pwrdw	0xA601
+#define	reg_top_pwrdw_pos 6
+#define	reg_top_pwrdw_len 1
+#define	reg_top_pwrdw_lsb 0
+#define xd_p_reg_top_pwrdw_inv	0xA601
+#define	reg_top_pwrdw_inv_pos 7
+#define	reg_top_pwrdw_inv_len 1
+#define	reg_top_pwrdw_inv_lsb 0
+#define xd_p_reg_top_int_inv	0xA602
+#define	reg_top_int_inv_pos 0
+#define	reg_top_int_inv_len 1
+#define	reg_top_int_inv_lsb 0
+#define xd_p_reg_top_dio_sel	0xA602
+#define	reg_top_dio_sel_pos 1
+#define	reg_top_dio_sel_len 1
+#define	reg_top_dio_sel_lsb 0
+#define xd_p_reg_top_gpioon0	0xA603
+#define	reg_top_gpioon0_pos 0
+#define	reg_top_gpioon0_len 1
+#define	reg_top_gpioon0_lsb 0
+#define xd_p_reg_top_gpioon1	0xA603
+#define	reg_top_gpioon1_pos 1
+#define	reg_top_gpioon1_len 1
+#define	reg_top_gpioon1_lsb 0
+#define xd_p_reg_top_gpioon2	0xA603
+#define	reg_top_gpioon2_pos 2
+#define	reg_top_gpioon2_len 1
+#define	reg_top_gpioon2_lsb 0
+#define xd_p_reg_top_gpioon3	0xA603
+#define	reg_top_gpioon3_pos 3
+#define	reg_top_gpioon3_len 1
+#define	reg_top_gpioon3_lsb 0
+#define xd_p_reg_top_lockon1	0xA603
+#define	reg_top_lockon1_pos 4
+#define	reg_top_lockon1_len 1
+#define	reg_top_lockon1_lsb 0
+#define xd_p_reg_top_lockon2	0xA603
+#define	reg_top_lockon2_pos 5
+#define	reg_top_lockon2_len 1
+#define	reg_top_lockon2_lsb 0
+#define xd_p_reg_top_gpioo0	0xA604
+#define	reg_top_gpioo0_pos 0
+#define	reg_top_gpioo0_len 1
+#define	reg_top_gpioo0_lsb 0
+#define xd_p_reg_top_gpioo1	0xA604
+#define	reg_top_gpioo1_pos 1
+#define	reg_top_gpioo1_len 1
+#define	reg_top_gpioo1_lsb 0
+#define xd_p_reg_top_gpioo2	0xA604
+#define	reg_top_gpioo2_pos 2
+#define	reg_top_gpioo2_len 1
+#define	reg_top_gpioo2_lsb 0
+#define xd_p_reg_top_gpioo3	0xA604
+#define	reg_top_gpioo3_pos 3
+#define	reg_top_gpioo3_len 1
+#define	reg_top_gpioo3_lsb 0
+#define xd_p_reg_top_lock1	0xA604
+#define	reg_top_lock1_pos 4
+#define	reg_top_lock1_len 1
+#define	reg_top_lock1_lsb 0
+#define xd_p_reg_top_lock2	0xA604
+#define	reg_top_lock2_pos 5
+#define	reg_top_lock2_len 1
+#define	reg_top_lock2_lsb 0
+#define xd_p_reg_top_gpioen0	0xA605
+#define	reg_top_gpioen0_pos 0
+#define	reg_top_gpioen0_len 1
+#define	reg_top_gpioen0_lsb 0
+#define xd_p_reg_top_gpioen1	0xA605
+#define	reg_top_gpioen1_pos 1
+#define	reg_top_gpioen1_len 1
+#define	reg_top_gpioen1_lsb 0
+#define xd_p_reg_top_gpioen2	0xA605
+#define	reg_top_gpioen2_pos 2
+#define	reg_top_gpioen2_len 1
+#define	reg_top_gpioen2_lsb 0
+#define xd_p_reg_top_gpioen3	0xA605
+#define	reg_top_gpioen3_pos 3
+#define	reg_top_gpioen3_len 1
+#define	reg_top_gpioen3_lsb 0
+#define xd_p_reg_top_locken1	0xA605
+#define	reg_top_locken1_pos 4
+#define	reg_top_locken1_len 1
+#define	reg_top_locken1_lsb 0
+#define xd_p_reg_top_locken2	0xA605
+#define	reg_top_locken2_pos 5
+#define	reg_top_locken2_len 1
+#define	reg_top_locken2_lsb 0
+#define xd_r_reg_top_gpioi0	0xA606
+#define	reg_top_gpioi0_pos 0
+#define	reg_top_gpioi0_len 1
+#define	reg_top_gpioi0_lsb 0
+#define xd_r_reg_top_gpioi1	0xA606
+#define	reg_top_gpioi1_pos 1
+#define	reg_top_gpioi1_len 1
+#define	reg_top_gpioi1_lsb 0
+#define xd_r_reg_top_gpioi2	0xA606
+#define	reg_top_gpioi2_pos 2
+#define	reg_top_gpioi2_len 1
+#define	reg_top_gpioi2_lsb 0
+#define xd_r_reg_top_gpioi3	0xA606
+#define	reg_top_gpioi3_pos 3
+#define	reg_top_gpioi3_len 1
+#define	reg_top_gpioi3_lsb 0
+#define xd_r_reg_top_locki1	0xA606
+#define	reg_top_locki1_pos 4
+#define	reg_top_locki1_len 1
+#define	reg_top_locki1_lsb 0
+#define xd_r_reg_top_locki2	0xA606
+#define	reg_top_locki2_pos 5
+#define	reg_top_locki2_len 1
+#define	reg_top_locki2_lsb 0
+#define xd_p_reg_dummy_7_0	0xA608
+#define	reg_dummy_7_0_pos 0
+#define	reg_dummy_7_0_len 8
+#define	reg_dummy_7_0_lsb 0
+#define xd_p_reg_dummy_15_8	0xA609
+#define	reg_dummy_15_8_pos 0
+#define	reg_dummy_15_8_len 8
+#define	reg_dummy_15_8_lsb 8
+#define xd_p_reg_dummy_23_16	0xA60A
+#define	reg_dummy_23_16_pos 0
+#define	reg_dummy_23_16_len 8
+#define	reg_dummy_23_16_lsb 16
+#define xd_p_reg_dummy_31_24	0xA60B
+#define	reg_dummy_31_24_pos 0
+#define	reg_dummy_31_24_len 8
+#define	reg_dummy_31_24_lsb 24
+#define xd_p_reg_dummy_39_32	0xA60C
+#define	reg_dummy_39_32_pos 0
+#define	reg_dummy_39_32_len 8
+#define	reg_dummy_39_32_lsb 32
+#define xd_p_reg_dummy_47_40	0xA60D
+#define	reg_dummy_47_40_pos 0
+#define	reg_dummy_47_40_len 8
+#define	reg_dummy_47_40_lsb 40
+#define xd_p_reg_dummy_55_48	0xA60E
+#define	reg_dummy_55_48_pos 0
+#define	reg_dummy_55_48_len 8
+#define	reg_dummy_55_48_lsb 48
+#define xd_p_reg_dummy_63_56	0xA60F
+#define	reg_dummy_63_56_pos 0
+#define	reg_dummy_63_56_len 8
+#define	reg_dummy_63_56_lsb 56
+#define xd_p_reg_dummy_71_64	0xA610
+#define	reg_dummy_71_64_pos 0
+#define	reg_dummy_71_64_len 8
+#define	reg_dummy_71_64_lsb 64
+#define xd_p_reg_dummy_79_72	0xA611
+#define	reg_dummy_79_72_pos 0
+#define	reg_dummy_79_72_len 8
+#define	reg_dummy_79_72_lsb 72
+#define xd_p_reg_dummy_87_80	0xA612
+#define	reg_dummy_87_80_pos 0
+#define	reg_dummy_87_80_len 8
+#define	reg_dummy_87_80_lsb 80
+#define xd_p_reg_dummy_95_88	0xA613
+#define	reg_dummy_95_88_pos 0
+#define	reg_dummy_95_88_len 8
+#define	reg_dummy_95_88_lsb 88
+#define xd_p_reg_dummy_103_96	0xA614
+#define	reg_dummy_103_96_pos 0
+#define	reg_dummy_103_96_len 8
+#define	reg_dummy_103_96_lsb 96
+
+#define xd_p_reg_unplug_flag	0xA615
+#define	reg_unplug_flag_pos 0
+#define	reg_unplug_flag_len 1
+#define	reg_unplug_flag_lsb 104
+
+#define xd_p_reg_api_dca_stes_request   0xA615
+#define reg_api_dca_stes_request_pos 1
+#define reg_api_dca_stes_request_len 1
+#define reg_api_dca_stes_request_lsb 0
+
+#define xd_p_reg_back_to_dca_flag	0xA615
+#define	reg_back_to_dca_flag_pos 2
+#define	reg_back_to_dca_flag_len 1
+#define	reg_back_to_dca_flag_lsb 106
+
+#define xd_p_reg_api_retrain_request    0xA615
+#define reg_api_retrain_request_pos 3
+#define reg_api_retrain_request_len 1
+#define reg_api_retrain_request_lsb 0
+
+#define xd_p_reg_Dyn_Top_Try_flag	0xA615
+#define	reg_Dyn_Top_Try_flag_pos 3
+#define	reg_Dyn_Top_Try_flag_len 1
+#define	reg_Dyn_Top_Try_flag_lsb 107
+
+#define xd_p_reg_API_retrain_freeze_flag	0xA615
+#define	reg_API_retrain_freeze_flag_pos 4
+#define	reg_API_retrain_freeze_flag_len 1
+#define	reg_API_retrain_freeze_flag_lsb 108
+
+#define xd_p_reg_dummy_111_104	0xA615
+#define	reg_dummy_111_104_pos 0
+#define	reg_dummy_111_104_len 8
+#define	reg_dummy_111_104_lsb 104
+#define xd_p_reg_dummy_119_112	0xA616
+#define	reg_dummy_119_112_pos 0
+#define	reg_dummy_119_112_len 8
+#define	reg_dummy_119_112_lsb 112
+#define xd_p_reg_dummy_127_120	0xA617
+#define	reg_dummy_127_120_pos 0
+#define	reg_dummy_127_120_len 8
+#define	reg_dummy_127_120_lsb 120
+#define xd_p_reg_dummy_135_128	0xA618
+#define	reg_dummy_135_128_pos 0
+#define	reg_dummy_135_128_len 8
+#define	reg_dummy_135_128_lsb 128
+
+#define xd_p_reg_dummy_143_136	0xA619
+#define	reg_dummy_143_136_pos 0
+#define	reg_dummy_143_136_len 8
+#define	reg_dummy_143_136_lsb 136
+
+#define xd_p_reg_CCIR_dis	0xA619
+#define	reg_CCIR_dis_pos 0
+#define	reg_CCIR_dis_len 1
+#define	reg_CCIR_dis_lsb 0
+
+#define xd_p_reg_dummy_151_144	0xA61A
+#define	reg_dummy_151_144_pos 0
+#define	reg_dummy_151_144_len 8
+#define	reg_dummy_151_144_lsb 144
+
+#define xd_p_reg_dummy_159_152	0xA61B
+#define	reg_dummy_159_152_pos 0
+#define	reg_dummy_159_152_len 8
+#define	reg_dummy_159_152_lsb 152
+
+#define xd_p_reg_dummy_167_160	0xA61C
+#define	reg_dummy_167_160_pos 0
+#define	reg_dummy_167_160_len 8
+#define	reg_dummy_167_160_lsb 160
+
+#define xd_p_reg_dummy_175_168	0xA61D
+#define	reg_dummy_175_168_pos 0
+#define	reg_dummy_175_168_len 8
+#define	reg_dummy_175_168_lsb 168
+
+#define xd_p_reg_dummy_183_176	0xA61E
+#define	reg_dummy_183_176_pos 0
+#define	reg_dummy_183_176_len 8
+#define	reg_dummy_183_176_lsb 176
+
+#define xd_p_reg_ofsm_read_rbc_en  0xA61E
+#define reg_ofsm_read_rbc_en_pos 2
+#define reg_ofsm_read_rbc_en_len 1
+#define reg_ofsm_read_rbc_en_lsb 0
+
+#define xd_p_reg_ce_filter_selection_dis  0xA61E
+#define reg_ce_filter_selection_dis_pos 1
+#define reg_ce_filter_selection_dis_len 1
+#define reg_ce_filter_selection_dis_lsb 0
+
+#define xd_p_reg_OFSM_version_control_7_0  0xA611
+#define reg_OFSM_version_control_7_0_pos 0
+#define reg_OFSM_version_control_7_0_len 8
+#define reg_OFSM_version_control_7_0_lsb 0
+
+#define xd_p_reg_OFSM_version_control_15_8  0xA61F
+#define reg_OFSM_version_control_15_8_pos 0
+#define reg_OFSM_version_control_15_8_len 8
+#define reg_OFSM_version_control_15_8_lsb 0
+
+#define xd_p_reg_OFSM_version_control_23_16  0xA620
+#define reg_OFSM_version_control_23_16_pos 0
+#define reg_OFSM_version_control_23_16_len 8
+#define reg_OFSM_version_control_23_16_lsb 0
+
+#define xd_p_reg_dummy_191_184	0xA61F
+#define	reg_dummy_191_184_pos 0
+#define	reg_dummy_191_184_len 8
+#define	reg_dummy_191_184_lsb 184
+
+#define xd_p_reg_dummy_199_192	0xA620
+#define	reg_dummy_199_192_pos 0
+#define	reg_dummy_199_192_len 8
+#define	reg_dummy_199_192_lsb 192
+
+#define xd_p_reg_ce_en	0xABC0
+#define	reg_ce_en_pos 0
+#define	reg_ce_en_len 1
+#define	reg_ce_en_lsb 0
+#define xd_p_reg_ce_fctrl_en	0xABC0
+#define	reg_ce_fctrl_en_pos 1
+#define	reg_ce_fctrl_en_len 1
+#define	reg_ce_fctrl_en_lsb 0
+#define xd_p_reg_ce_fste_tdi	0xABC0
+#define	reg_ce_fste_tdi_pos 2
+#define	reg_ce_fste_tdi_len 1
+#define	reg_ce_fste_tdi_lsb 0
+#define xd_p_reg_ce_dynamic	0xABC0
+#define	reg_ce_dynamic_pos 3
+#define	reg_ce_dynamic_len 1
+#define	reg_ce_dynamic_lsb 0
+#define xd_p_reg_ce_conf	0xABC0
+#define	reg_ce_conf_pos 4
+#define	reg_ce_conf_len 2
+#define	reg_ce_conf_lsb 0
+#define xd_p_reg_ce_dyn12	0xABC0
+#define	reg_ce_dyn12_pos 6
+#define	reg_ce_dyn12_len 1
+#define	reg_ce_dyn12_lsb 0
+#define xd_p_reg_ce_derot_en	0xABC0
+#define	reg_ce_derot_en_pos 7
+#define	reg_ce_derot_en_len 1
+#define	reg_ce_derot_en_lsb 0
+#define xd_p_reg_ce_dynamic_th_7_0	0xABC1
+#define	reg_ce_dynamic_th_7_0_pos 0
+#define	reg_ce_dynamic_th_7_0_len 8
+#define	reg_ce_dynamic_th_7_0_lsb 0
+#define xd_p_reg_ce_dynamic_th_15_8	0xABC2
+#define	reg_ce_dynamic_th_15_8_pos 0
+#define	reg_ce_dynamic_th_15_8_len 8
+#define	reg_ce_dynamic_th_15_8_lsb 8
+#define xd_p_reg_ce_s1	0xABC3
+#define	reg_ce_s1_pos 0
+#define	reg_ce_s1_len 5
+#define	reg_ce_s1_lsb 0
+#define xd_p_reg_ce_var_forced_value	0xABC3
+#define	reg_ce_var_forced_value_pos 5
+#define	reg_ce_var_forced_value_len 3
+#define	reg_ce_var_forced_value_lsb 0
+#define xd_p_reg_ce_data_im_7_0	0xABC4
+#define	reg_ce_data_im_7_0_pos 0
+#define	reg_ce_data_im_7_0_len 8
+#define	reg_ce_data_im_7_0_lsb 0
+#define xd_p_reg_ce_data_im_8	0xABC5
+#define	reg_ce_data_im_8_pos 0
+#define	reg_ce_data_im_8_len 1
+#define	reg_ce_data_im_8_lsb 0
+#define xd_p_reg_ce_data_re_6_0	0xABC5
+#define	reg_ce_data_re_6_0_pos 1
+#define	reg_ce_data_re_6_0_len 7
+#define	reg_ce_data_re_6_0_lsb 0
+#define xd_p_reg_ce_data_re_8_7	0xABC6
+#define	reg_ce_data_re_8_7_pos 0
+#define	reg_ce_data_re_8_7_len 2
+#define	reg_ce_data_re_8_7_lsb 7
+#define xd_p_reg_ce_tone_5_0	0xABC6
+#define	reg_ce_tone_5_0_pos 2
+#define	reg_ce_tone_5_0_len 6
+#define	reg_ce_tone_5_0_lsb 0
+#define xd_p_reg_ce_tone_12_6	0xABC7
+#define	reg_ce_tone_12_6_pos 0
+#define	reg_ce_tone_12_6_len 7
+#define	reg_ce_tone_12_6_lsb 6
+#define xd_p_reg_ce_centroid_drift_th	0xABC8
+#define	reg_ce_centroid_drift_th_pos 0
+#define	reg_ce_centroid_drift_th_len 8
+#define	reg_ce_centroid_drift_th_lsb 0
+#define xd_p_reg_ce_centroid_count_max	0xABC9
+#define	reg_ce_centroid_count_max_pos 0
+#define	reg_ce_centroid_count_max_len 4
+#define	reg_ce_centroid_count_max_lsb 0
+#define xd_p_reg_ce_centroid_bias_inc_7_0	0xABCA
+#define	reg_ce_centroid_bias_inc_7_0_pos 0
+#define	reg_ce_centroid_bias_inc_7_0_len 8
+#define	reg_ce_centroid_bias_inc_7_0_lsb 0
+#define xd_p_reg_ce_centroid_bias_inc_8	0xABCB
+#define	reg_ce_centroid_bias_inc_8_pos 0
+#define	reg_ce_centroid_bias_inc_8_len 1
+#define	reg_ce_centroid_bias_inc_8_lsb 0
+#define xd_p_reg_ce_var_th0_7_0	0xABCC
+#define	reg_ce_var_th0_7_0_pos 0
+#define	reg_ce_var_th0_7_0_len 8
+#define	reg_ce_var_th0_7_0_lsb 0
+#define xd_p_reg_ce_var_th0_15_8	0xABCD
+#define	reg_ce_var_th0_15_8_pos 0
+#define	reg_ce_var_th0_15_8_len 8
+#define	reg_ce_var_th0_15_8_lsb 8
+#define xd_p_reg_ce_var_th1_7_0	0xABCE
+#define	reg_ce_var_th1_7_0_pos 0
+#define	reg_ce_var_th1_7_0_len 8
+#define	reg_ce_var_th1_7_0_lsb 0
+#define xd_p_reg_ce_var_th1_15_8	0xABCF
+#define	reg_ce_var_th1_15_8_pos 0
+#define	reg_ce_var_th1_15_8_len 8
+#define	reg_ce_var_th1_15_8_lsb 8
+#define xd_p_reg_ce_var_th2_7_0	0xABD0
+#define	reg_ce_var_th2_7_0_pos 0
+#define	reg_ce_var_th2_7_0_len 8
+#define	reg_ce_var_th2_7_0_lsb 0
+#define xd_p_reg_ce_var_th2_15_8	0xABD1
+#define	reg_ce_var_th2_15_8_pos 0
+#define	reg_ce_var_th2_15_8_len 8
+#define	reg_ce_var_th2_15_8_lsb 8
+#define xd_p_reg_ce_var_th3_7_0	0xABD2
+#define	reg_ce_var_th3_7_0_pos 0
+#define	reg_ce_var_th3_7_0_len 8
+#define	reg_ce_var_th3_7_0_lsb 0
+#define xd_p_reg_ce_var_th3_15_8	0xABD3
+#define	reg_ce_var_th3_15_8_pos 0
+#define	reg_ce_var_th3_15_8_len 8
+#define	reg_ce_var_th3_15_8_lsb 8
+#define xd_p_reg_ce_var_th4_7_0	0xABD4
+#define	reg_ce_var_th4_7_0_pos 0
+#define	reg_ce_var_th4_7_0_len 8
+#define	reg_ce_var_th4_7_0_lsb 0
+#define xd_p_reg_ce_var_th4_15_8	0xABD5
+#define	reg_ce_var_th4_15_8_pos 0
+#define	reg_ce_var_th4_15_8_len 8
+#define	reg_ce_var_th4_15_8_lsb 8
+#define xd_p_reg_ce_var_th5_7_0	0xABD6
+#define	reg_ce_var_th5_7_0_pos 0
+#define	reg_ce_var_th5_7_0_len 8
+#define	reg_ce_var_th5_7_0_lsb 0
+#define xd_p_reg_ce_var_th5_15_8	0xABD7
+#define	reg_ce_var_th5_15_8_pos 0
+#define	reg_ce_var_th5_15_8_len 8
+#define	reg_ce_var_th5_15_8_lsb 8
+#define xd_p_reg_ce_var_th6_7_0	0xABD8
+#define	reg_ce_var_th6_7_0_pos 0
+#define	reg_ce_var_th6_7_0_len 8
+#define	reg_ce_var_th6_7_0_lsb 0
+#define xd_p_reg_ce_var_th6_15_8	0xABD9
+#define	reg_ce_var_th6_15_8_pos 0
+#define	reg_ce_var_th6_15_8_len 8
+#define	reg_ce_var_th6_15_8_lsb 8
+#define xd_p_reg_ce_fctrl_reset	0xABDA
+#define	reg_ce_fctrl_reset_pos 0
+#define	reg_ce_fctrl_reset_len 1
+#define	reg_ce_fctrl_reset_lsb 0
+#define xd_p_reg_ce_cent_auto_clr_en	0xABDA
+#define	reg_ce_cent_auto_clr_en_pos 1
+#define	reg_ce_cent_auto_clr_en_len 1
+#define	reg_ce_cent_auto_clr_en_lsb 0
+#define xd_p_reg_ce_fctrl_auto_reset_en	0xABDA
+#define	reg_ce_fctrl_auto_reset_en_pos 2
+#define	reg_ce_fctrl_auto_reset_en_len 1
+#define	reg_ce_fctrl_auto_reset_en_lsb 0
+#define xd_p_reg_ce_var_forced_en	0xABDA
+#define	reg_ce_var_forced_en_pos 3
+#define	reg_ce_var_forced_en_len 1
+#define	reg_ce_var_forced_en_lsb 0
+#define xd_p_reg_ce_cent_forced_en	0xABDA
+#define	reg_ce_cent_forced_en_pos 4
+#define	reg_ce_cent_forced_en_len 1
+#define	reg_ce_cent_forced_en_lsb 0
+#define xd_p_reg_ce_var_max	0xABDA
+#define	reg_ce_var_max_pos 5
+#define	reg_ce_var_max_len 3
+#define	reg_ce_var_max_lsb 0
+#define xd_p_reg_ce_cent_forced_value_7_0	0xABDB
+#define	reg_ce_cent_forced_value_7_0_pos 0
+#define	reg_ce_cent_forced_value_7_0_len 8
+#define	reg_ce_cent_forced_value_7_0_lsb 0
+#define xd_p_reg_ce_cent_forced_value_11_8	0xABDC
+#define	reg_ce_cent_forced_value_11_8_pos 0
+#define	reg_ce_cent_forced_value_11_8_len 4
+#define	reg_ce_cent_forced_value_11_8_lsb 8
+#define xd_p_reg_ce_fctrl_rd	0xABDD
+#define	reg_ce_fctrl_rd_pos 0
+#define	reg_ce_fctrl_rd_len 1
+#define	reg_ce_fctrl_rd_lsb 0
+#define xd_p_reg_ce_centroid_max_6_0	0xABDD
+#define	reg_ce_centroid_max_6_0_pos 1
+#define	reg_ce_centroid_max_6_0_len 7
+#define	reg_ce_centroid_max_6_0_lsb 0
+#define xd_p_reg_ce_centroid_max_11_7	0xABDE
+#define	reg_ce_centroid_max_11_7_pos 0
+#define	reg_ce_centroid_max_11_7_len 5
+#define	reg_ce_centroid_max_11_7_lsb 7
+#define xd_p_reg_ce_var	0xABDF
+#define	reg_ce_var_pos 0
+#define	reg_ce_var_len 3
+#define	reg_ce_var_lsb 0
+#define xd_p_reg_ce_fctrl_rdy	0xABDF
+#define	reg_ce_fctrl_rdy_pos 3
+#define	reg_ce_fctrl_rdy_len 1
+#define	reg_ce_fctrl_rdy_lsb 0
+#define xd_p_reg_ce_centroid_out_3_0	0xABDF
+#define	reg_ce_centroid_out_3_0_pos 4
+#define	reg_ce_centroid_out_3_0_len 4
+#define	reg_ce_centroid_out_3_0_lsb 0
+#define xd_p_reg_ce_centroid_out_11_4	0xABE0
+#define	reg_ce_centroid_out_11_4_pos 0
+#define	reg_ce_centroid_out_11_4_len 8
+#define	reg_ce_centroid_out_11_4_lsb 4
+#define xd_p_reg_ce_bias_7_0	0xABE1
+#define	reg_ce_bias_7_0_pos 0
+#define	reg_ce_bias_7_0_len 8
+#define	reg_ce_bias_7_0_lsb 0
+#define xd_p_reg_ce_bias_11_8	0xABE2
+#define	reg_ce_bias_11_8_pos 0
+#define	reg_ce_bias_11_8_len 4
+#define	reg_ce_bias_11_8_lsb 8
+#define xd_p_reg_ce_m1_3_0	0xABE2
+#define	reg_ce_m1_3_0_pos 4
+#define	reg_ce_m1_3_0_len 4
+#define	reg_ce_m1_3_0_lsb 0
+#define xd_p_reg_ce_m1_11_4	0xABE3
+#define	reg_ce_m1_11_4_pos 0
+#define	reg_ce_m1_11_4_len 8
+#define	reg_ce_m1_11_4_lsb 4
+#define xd_p_reg_ce_rh0_7_0	0xABE4
+#define	reg_ce_rh0_7_0_pos 0
+#define	reg_ce_rh0_7_0_len 8
+#define	reg_ce_rh0_7_0_lsb 0
+#define xd_p_reg_ce_rh0_15_8	0xABE5
+#define	reg_ce_rh0_15_8_pos 0
+#define	reg_ce_rh0_15_8_len 8
+#define	reg_ce_rh0_15_8_lsb 8
+#define xd_p_reg_ce_rh0_23_16	0xABE6
+#define	reg_ce_rh0_23_16_pos 0
+#define	reg_ce_rh0_23_16_len 8
+#define	reg_ce_rh0_23_16_lsb 16
+#define xd_p_reg_ce_rh0_31_24	0xABE7
+#define	reg_ce_rh0_31_24_pos 0
+#define	reg_ce_rh0_31_24_len 8
+#define	reg_ce_rh0_31_24_lsb 24
+#define xd_p_reg_ce_rh3_real_7_0	0xABE8
+#define	reg_ce_rh3_real_7_0_pos 0
+#define	reg_ce_rh3_real_7_0_len 8
+#define	reg_ce_rh3_real_7_0_lsb 0
+#define xd_p_reg_ce_rh3_real_15_8	0xABE9
+#define	reg_ce_rh3_real_15_8_pos 0
+#define	reg_ce_rh3_real_15_8_len 8
+#define	reg_ce_rh3_real_15_8_lsb 8
+#define xd_p_reg_ce_rh3_real_23_16	0xABEA
+#define	reg_ce_rh3_real_23_16_pos 0
+#define	reg_ce_rh3_real_23_16_len 8
+#define	reg_ce_rh3_real_23_16_lsb 16
+#define xd_p_reg_ce_rh3_real_31_24	0xABEB
+#define	reg_ce_rh3_real_31_24_pos 0
+#define	reg_ce_rh3_real_31_24_len 8
+#define	reg_ce_rh3_real_31_24_lsb 24
+#define xd_p_reg_ce_rh3_imag_7_0	0xABEC
+#define	reg_ce_rh3_imag_7_0_pos 0
+#define	reg_ce_rh3_imag_7_0_len 8
+#define	reg_ce_rh3_imag_7_0_lsb 0
+#define xd_p_reg_ce_rh3_imag_15_8	0xABED
+#define	reg_ce_rh3_imag_15_8_pos 0
+#define	reg_ce_rh3_imag_15_8_len 8
+#define	reg_ce_rh3_imag_15_8_lsb 8
+#define xd_p_reg_ce_rh3_imag_23_16	0xABEE
+#define	reg_ce_rh3_imag_23_16_pos 0
+#define	reg_ce_rh3_imag_23_16_len 8
+#define	reg_ce_rh3_imag_23_16_lsb 16
+#define xd_p_reg_ce_rh3_imag_31_24	0xABEF
+#define	reg_ce_rh3_imag_31_24_pos 0
+#define	reg_ce_rh3_imag_31_24_len 8
+#define	reg_ce_rh3_imag_31_24_lsb 24
+#define xd_p_reg_feq_fix_eh2_7_0	0xABF0
+#define	reg_feq_fix_eh2_7_0_pos 0
+#define	reg_feq_fix_eh2_7_0_len 8
+#define	reg_feq_fix_eh2_7_0_lsb 0
+#define xd_p_reg_feq_fix_eh2_15_8	0xABF1
+#define	reg_feq_fix_eh2_15_8_pos 0
+#define	reg_feq_fix_eh2_15_8_len 8
+#define	reg_feq_fix_eh2_15_8_lsb 8
+#define xd_p_reg_feq_fix_eh2_23_16	0xABF2
+#define	reg_feq_fix_eh2_23_16_pos 0
+#define	reg_feq_fix_eh2_23_16_len 8
+#define	reg_feq_fix_eh2_23_16_lsb 16
+#define xd_p_reg_feq_fix_eh2_31_24	0xABF3
+#define	reg_feq_fix_eh2_31_24_pos 0
+#define	reg_feq_fix_eh2_31_24_len 8
+#define	reg_feq_fix_eh2_31_24_lsb 24
+#define xd_p_reg_ce_m2_central_7_0	0xABF4
+#define	reg_ce_m2_central_7_0_pos 0
+#define	reg_ce_m2_central_7_0_len 8
+#define	reg_ce_m2_central_7_0_lsb 0
+#define xd_p_reg_ce_m2_central_15_8	0xABF5
+#define	reg_ce_m2_central_15_8_pos 0
+#define	reg_ce_m2_central_15_8_len 8
+#define	reg_ce_m2_central_15_8_lsb 8
+#define xd_p_reg_ce_fftshift	0xABF6
+#define	reg_ce_fftshift_pos 0
+#define	reg_ce_fftshift_len 4
+#define	reg_ce_fftshift_lsb 0
+#define xd_p_reg_ce_fftshift1	0xABF6
+#define	reg_ce_fftshift1_pos 4
+#define	reg_ce_fftshift1_len 4
+#define	reg_ce_fftshift1_lsb 0
+#define xd_p_reg_ce_fftshift2	0xABF7
+#define	reg_ce_fftshift2_pos 0
+#define	reg_ce_fftshift2_len 4
+#define	reg_ce_fftshift2_lsb 0
+#define xd_p_reg_ce_top_mobile	0xABF7
+#define	reg_ce_top_mobile_pos 4
+#define	reg_ce_top_mobile_len 1
+#define	reg_ce_top_mobile_lsb 0
+#define xd_p_reg_strong_sginal_detected 0xA2BC
+#define reg_strong_sginal_detected_pos 2
+#define reg_strong_sginal_detected_len 1
+#define reg_strong_sginal_detected_lsb 0
+
+#define XD_MP2IF_BASE                           0xB000
+#define XD_MP2IF_CSR                        (0x00 + XD_MP2IF_BASE)
+#define XD_MP2IF_DMX_CTRL                       (0x03 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_IDX                        (0x04 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_DATA_L                     (0x05 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_DATA_H                     (0x06 + XD_MP2IF_BASE)
+#define XD_MP2IF_MISC                       (0x07 + XD_MP2IF_BASE)
+
+extern struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d);
+extern int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg,
+				     u8 * value);
+extern int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+				      u8 * values, int len);
+extern int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg,
+				      u8 value);
+extern int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+				       u8 * values, int len);
+extern int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg,
+				       u8 addr, u8 * values, int len);
+extern int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,
+					u8 * values, int len);
+extern int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg,
+				     u8 pos, u8 len, u8 * value);
+extern int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg,
+				      u8 pos, u8 len, u8 value);
+extern int af9005_send_command(struct dvb_usb_device *d, u8 command,
+			       u8 * wbuf, int wlen, u8 * rbuf, int rlen);
+extern int af9005_read_eeprom(struct dvb_usb_device *d, u8 address,
+			      u8 * values, int len);
+extern int af9005_tuner_attach(struct dvb_usb_adapter *adap);
+extern int af9005_led_control(struct dvb_usb_device *d, int onoff);
+
+extern u8 regmask[8];
+
+/* remote control decoder */
+extern int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len,
+			    u32 * event, int *state);
+extern struct rc_map_table rc_map_af9005_table[];
+extern int rc_map_af9005_table_size;
+
+#endif
diff --git a/drivers/media/usb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c
new file mode 100644
index 0000000..5e45ae6
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/az6027.c
@@ -0,0 +1,1182 @@
+/* DVB USB compliant Linux driver for the AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)
+ * receiver.
+ *
+ * Copyright (C) 2009 Adams.Xu <adams.xu@azwave.com.cn>
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "az6027.h"
+
+#include "stb0899_drv.h"
+#include "stb0899_reg.h"
+#include "stb0899_cfg.h"
+
+#include "stb6100.h"
+#include "stb6100_cfg.h"
+#include "dvb_ca_en50221.h"
+
+int dvb_usb_az6027_debug;
+module_param_named(debug, dvb_usb_az6027_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct az6027_device_state {
+	struct dvb_ca_en50221 ca;
+	struct mutex ca_mutex;
+	u8 power_state;
+};
+
+static const struct stb0899_s1_reg az6027_stb0899_s1_init_1[] = {
+
+	/* 0x0000000b, SYSREG */
+	{ STB0899_DEV_ID		, 0x30 },
+	{ STB0899_DISCNTRL1		, 0x32 },
+	{ STB0899_DISCNTRL2     	, 0x80 },
+	{ STB0899_DISRX_ST0     	, 0x04 },
+	{ STB0899_DISRX_ST1     	, 0x00 },
+	{ STB0899_DISPARITY     	, 0x00 },
+	{ STB0899_DISSTATUS		, 0x20 },
+	{ STB0899_DISF22        	, 0x99 },
+	{ STB0899_DISF22RX      	, 0xa8 },
+	/* SYSREG ? */
+	{ STB0899_ACRPRESC      	, 0x11 },
+	{ STB0899_ACRDIV1       	, 0x0a },
+	{ STB0899_ACRDIV2       	, 0x05 },
+	{ STB0899_DACR1         	, 0x00 },
+	{ STB0899_DACR2         	, 0x00 },
+	{ STB0899_OUTCFG        	, 0x00 },
+	{ STB0899_MODECFG       	, 0x00 },
+	{ STB0899_IRQSTATUS_3		, 0xfe },
+	{ STB0899_IRQSTATUS_2		, 0x03 },
+	{ STB0899_IRQSTATUS_1		, 0x7c },
+	{ STB0899_IRQSTATUS_0		, 0xf4 },
+	{ STB0899_IRQMSK_3      	, 0xf3 },
+	{ STB0899_IRQMSK_2      	, 0xfc },
+	{ STB0899_IRQMSK_1      	, 0xff },
+	{ STB0899_IRQMSK_0		, 0xff },
+	{ STB0899_IRQCFG		, 0x00 },
+	{ STB0899_I2CCFG        	, 0x88 },
+	{ STB0899_I2CRPT        	, 0x58 },
+	{ STB0899_IOPVALUE5		, 0x00 },
+	{ STB0899_IOPVALUE4		, 0x33 },
+	{ STB0899_IOPVALUE3		, 0x6d },
+	{ STB0899_IOPVALUE2		, 0x90 },
+	{ STB0899_IOPVALUE1		, 0x60 },
+	{ STB0899_IOPVALUE0		, 0x00 },
+	{ STB0899_GPIO00CFG     	, 0x82 },
+	{ STB0899_GPIO01CFG     	, 0x82 },
+	{ STB0899_GPIO02CFG     	, 0x82 },
+	{ STB0899_GPIO03CFG     	, 0x82 },
+	{ STB0899_GPIO04CFG     	, 0x82 },
+	{ STB0899_GPIO05CFG     	, 0x82 },
+	{ STB0899_GPIO06CFG     	, 0x82 },
+	{ STB0899_GPIO07CFG     	, 0x82 },
+	{ STB0899_GPIO08CFG     	, 0x82 },
+	{ STB0899_GPIO09CFG     	, 0x82 },
+	{ STB0899_GPIO10CFG     	, 0x82 },
+	{ STB0899_GPIO11CFG     	, 0x82 },
+	{ STB0899_GPIO12CFG     	, 0x82 },
+	{ STB0899_GPIO13CFG     	, 0x82 },
+	{ STB0899_GPIO14CFG     	, 0x82 },
+	{ STB0899_GPIO15CFG     	, 0x82 },
+	{ STB0899_GPIO16CFG     	, 0x82 },
+	{ STB0899_GPIO17CFG     	, 0x82 },
+	{ STB0899_GPIO18CFG     	, 0x82 },
+	{ STB0899_GPIO19CFG     	, 0x82 },
+	{ STB0899_GPIO20CFG     	, 0x82 },
+	{ STB0899_SDATCFG       	, 0xb8 },
+	{ STB0899_SCLTCFG       	, 0xba },
+	{ STB0899_AGCRFCFG      	, 0x1c }, /* 0x11 */
+	{ STB0899_GPIO22        	, 0x82 }, /* AGCBB2CFG */
+	{ STB0899_GPIO21        	, 0x91 }, /* AGCBB1CFG */
+	{ STB0899_DIRCLKCFG     	, 0x82 },
+	{ STB0899_CLKOUT27CFG   	, 0x7e },
+	{ STB0899_STDBYCFG      	, 0x82 },
+	{ STB0899_CS0CFG        	, 0x82 },
+	{ STB0899_CS1CFG        	, 0x82 },
+	{ STB0899_DISEQCOCFG    	, 0x20 },
+	{ STB0899_GPIO32CFG		, 0x82 },
+	{ STB0899_GPIO33CFG		, 0x82 },
+	{ STB0899_GPIO34CFG		, 0x82 },
+	{ STB0899_GPIO35CFG		, 0x82 },
+	{ STB0899_GPIO36CFG		, 0x82 },
+	{ STB0899_GPIO37CFG		, 0x82 },
+	{ STB0899_GPIO38CFG		, 0x82 },
+	{ STB0899_GPIO39CFG		, 0x82 },
+	{ STB0899_NCOARSE       	, 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
+	{ STB0899_SYNTCTRL      	, 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
+	{ STB0899_FILTCTRL      	, 0x00 },
+	{ STB0899_SYSCTRL       	, 0x01 },
+	{ STB0899_STOPCLK1      	, 0x20 },
+	{ STB0899_STOPCLK2      	, 0x00 },
+	{ STB0899_INTBUFSTATUS		, 0x00 },
+	{ STB0899_INTBUFCTRL    	, 0x0a },
+	{ 0xffff			, 0xff },
+};
+
+static const struct stb0899_s1_reg az6027_stb0899_s1_init_3[] = {
+	{ STB0899_DEMOD         	, 0x00 },
+	{ STB0899_RCOMPC        	, 0xc9 },
+	{ STB0899_AGC1CN        	, 0x01 },
+	{ STB0899_AGC1REF       	, 0x10 },
+	{ STB0899_RTC			, 0x23 },
+	{ STB0899_TMGCFG        	, 0x4e },
+	{ STB0899_AGC2REF       	, 0x34 },
+	{ STB0899_TLSR          	, 0x84 },
+	{ STB0899_CFD           	, 0xf7 },
+	{ STB0899_ACLC			, 0x87 },
+	{ STB0899_BCLC          	, 0x94 },
+	{ STB0899_EQON          	, 0x41 },
+	{ STB0899_LDT           	, 0xf1 },
+	{ STB0899_LDT2          	, 0xe3 },
+	{ STB0899_EQUALREF      	, 0xb4 },
+	{ STB0899_TMGRAMP       	, 0x10 },
+	{ STB0899_TMGTHD        	, 0x30 },
+	{ STB0899_IDCCOMP		, 0xfd },
+	{ STB0899_QDCCOMP		, 0xff },
+	{ STB0899_POWERI		, 0x0c },
+	{ STB0899_POWERQ		, 0x0f },
+	{ STB0899_RCOMP			, 0x6c },
+	{ STB0899_AGCIQIN		, 0x80 },
+	{ STB0899_AGC2I1		, 0x06 },
+	{ STB0899_AGC2I2		, 0x00 },
+	{ STB0899_TLIR			, 0x30 },
+	{ STB0899_RTF			, 0x7f },
+	{ STB0899_DSTATUS		, 0x00 },
+	{ STB0899_LDI			, 0xbc },
+	{ STB0899_CFRM			, 0xea },
+	{ STB0899_CFRL			, 0x31 },
+	{ STB0899_NIRM			, 0x2b },
+	{ STB0899_NIRL			, 0x80 },
+	{ STB0899_ISYMB			, 0x1d },
+	{ STB0899_QSYMB			, 0xa6 },
+	{ STB0899_SFRH          	, 0x2f },
+	{ STB0899_SFRM          	, 0x68 },
+	{ STB0899_SFRL          	, 0x40 },
+	{ STB0899_SFRUPH        	, 0x2f },
+	{ STB0899_SFRUPM        	, 0x68 },
+	{ STB0899_SFRUPL        	, 0x40 },
+	{ STB0899_EQUAI1		, 0x02 },
+	{ STB0899_EQUAQ1		, 0xff },
+	{ STB0899_EQUAI2		, 0x04 },
+	{ STB0899_EQUAQ2		, 0x05 },
+	{ STB0899_EQUAI3		, 0x02 },
+	{ STB0899_EQUAQ3		, 0xfd },
+	{ STB0899_EQUAI4		, 0x03 },
+	{ STB0899_EQUAQ4		, 0x07 },
+	{ STB0899_EQUAI5		, 0x08 },
+	{ STB0899_EQUAQ5		, 0xf5 },
+	{ STB0899_DSTATUS2		, 0x00 },
+	{ STB0899_VSTATUS       	, 0x00 },
+	{ STB0899_VERROR		, 0x86 },
+	{ STB0899_IQSWAP		, 0x2a },
+	{ STB0899_ECNT1M		, 0x00 },
+	{ STB0899_ECNT1L		, 0x00 },
+	{ STB0899_ECNT2M		, 0x00 },
+	{ STB0899_ECNT2L		, 0x00 },
+	{ STB0899_ECNT3M		, 0x0a },
+	{ STB0899_ECNT3L		, 0xad },
+	{ STB0899_FECAUTO1      	, 0x06 },
+	{ STB0899_FECM			, 0x01 },
+	{ STB0899_VTH12         	, 0xb0 },
+	{ STB0899_VTH23         	, 0x7a },
+	{ STB0899_VTH34			, 0x58 },
+	{ STB0899_VTH56         	, 0x38 },
+	{ STB0899_VTH67         	, 0x34 },
+	{ STB0899_VTH78         	, 0x24 },
+	{ STB0899_PRVIT         	, 0xff },
+	{ STB0899_VITSYNC       	, 0x19 },
+	{ STB0899_RSULC         	, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+	{ STB0899_TSULC         	, 0x42 },
+	{ STB0899_RSLLC         	, 0x41 },
+	{ STB0899_TSLPL			, 0x12 },
+	{ STB0899_TSCFGH        	, 0x0c },
+	{ STB0899_TSCFGM        	, 0x00 },
+	{ STB0899_TSCFGL        	, 0x00 },
+	{ STB0899_TSOUT			, 0x69 }, /* 0x0d for CAM */
+	{ STB0899_RSSYNCDEL     	, 0x00 },
+	{ STB0899_TSINHDELH     	, 0x02 },
+	{ STB0899_TSINHDELM		, 0x00 },
+	{ STB0899_TSINHDELL		, 0x00 },
+	{ STB0899_TSLLSTKM		, 0x1b },
+	{ STB0899_TSLLSTKL		, 0xb3 },
+	{ STB0899_TSULSTKM		, 0x00 },
+	{ STB0899_TSULSTKL		, 0x00 },
+	{ STB0899_PCKLENUL		, 0xbc },
+	{ STB0899_PCKLENLL		, 0xcc },
+	{ STB0899_RSPCKLEN		, 0xbd },
+	{ STB0899_TSSTATUS		, 0x90 },
+	{ STB0899_ERRCTRL1      	, 0xb6 },
+	{ STB0899_ERRCTRL2      	, 0x95 },
+	{ STB0899_ERRCTRL3      	, 0x8d },
+	{ STB0899_DMONMSK1		, 0x27 },
+	{ STB0899_DMONMSK0		, 0x03 },
+	{ STB0899_DEMAPVIT      	, 0x5c },
+	{ STB0899_PLPARM		, 0x19 },
+	{ STB0899_PDELCTRL      	, 0x48 },
+	{ STB0899_PDELCTRL2     	, 0x00 },
+	{ STB0899_BBHCTRL1      	, 0x00 },
+	{ STB0899_BBHCTRL2      	, 0x00 },
+	{ STB0899_HYSTTHRESH    	, 0x77 },
+	{ STB0899_MATCSTM		, 0x00 },
+	{ STB0899_MATCSTL		, 0x00 },
+	{ STB0899_UPLCSTM		, 0x00 },
+	{ STB0899_UPLCSTL		, 0x00 },
+	{ STB0899_DFLCSTM		, 0x00 },
+	{ STB0899_DFLCSTL		, 0x00 },
+	{ STB0899_SYNCCST		, 0x00 },
+	{ STB0899_SYNCDCSTM		, 0x00 },
+	{ STB0899_SYNCDCSTL		, 0x00 },
+	{ STB0899_ISI_ENTRY		, 0x00 },
+	{ STB0899_ISI_BIT_EN		, 0x00 },
+	{ STB0899_MATSTRM		, 0xf0 },
+	{ STB0899_MATSTRL		, 0x02 },
+	{ STB0899_UPLSTRM		, 0x45 },
+	{ STB0899_UPLSTRL		, 0x60 },
+	{ STB0899_DFLSTRM		, 0xe3 },
+	{ STB0899_DFLSTRL		, 0x00 },
+	{ STB0899_SYNCSTR		, 0x47 },
+	{ STB0899_SYNCDSTRM		, 0x05 },
+	{ STB0899_SYNCDSTRL		, 0x18 },
+	{ STB0899_CFGPDELSTATUS1	, 0x19 },
+	{ STB0899_CFGPDELSTATUS2	, 0x2b },
+	{ STB0899_BBFERRORM		, 0x00 },
+	{ STB0899_BBFERRORL		, 0x01 },
+	{ STB0899_UPKTERRORM		, 0x00 },
+	{ STB0899_UPKTERRORL		, 0x00 },
+	{ 0xffff			, 0xff },
+};
+
+
+
+struct stb0899_config az6027_stb0899_config = {
+	.init_dev		= az6027_stb0899_s1_init_1,
+	.init_s2_demod		= stb0899_s2_init_2,
+	.init_s1_demod		= az6027_stb0899_s1_init_3,
+	.init_s2_fec		= stb0899_s2_init_4,
+	.init_tst		= stb0899_s1_init_5,
+
+	.demod_address 		= 0xd0, /* 0x68, 0xd0 >> 1 */
+
+	.xtal_freq		= 27000000,
+	.inversion		= IQ_SWAP_ON, /* 1 */
+
+	.lo_clk			= 76500000,
+	.hi_clk			= 99000000,
+
+	.esno_ave		= STB0899_DVBS2_ESNO_AVE,
+	.esno_quant		= STB0899_DVBS2_ESNO_QUANT,
+	.avframes_coarse	= STB0899_DVBS2_AVFRAMES_COARSE,
+	.avframes_fine		= STB0899_DVBS2_AVFRAMES_FINE,
+	.miss_threshold		= STB0899_DVBS2_MISS_THRESHOLD,
+	.uwp_threshold_acq	= STB0899_DVBS2_UWP_THRESHOLD_ACQ,
+	.uwp_threshold_track	= STB0899_DVBS2_UWP_THRESHOLD_TRACK,
+	.uwp_threshold_sof	= STB0899_DVBS2_UWP_THRESHOLD_SOF,
+	.sof_search_timeout	= STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
+
+	.btr_nco_bits		= STB0899_DVBS2_BTR_NCO_BITS,
+	.btr_gain_shift_offset	= STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+	.crl_nco_bits		= STB0899_DVBS2_CRL_NCO_BITS,
+	.ldpc_max_iter		= STB0899_DVBS2_LDPC_MAX_ITER,
+
+	.tuner_get_frequency	= stb6100_get_frequency,
+	.tuner_set_frequency	= stb6100_set_frequency,
+	.tuner_set_bandwidth	= stb6100_set_bandwidth,
+	.tuner_get_bandwidth	= stb6100_get_bandwidth,
+	.tuner_set_rfsiggain	= NULL,
+};
+
+struct stb6100_config az6027_stb6100_config = {
+	.tuner_address	= 0xc0,
+	.refclock	= 27000000,
+};
+
+
+/* check for mutex FIXME */
+int az6027_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
+{
+	int ret = -1;
+	if (mutex_lock_interruptible(&d->usb_mutex))
+		return -EAGAIN;
+
+	ret = usb_control_msg(d->udev,
+			      usb_rcvctrlpipe(d->udev, 0),
+			      req,
+			      USB_TYPE_VENDOR | USB_DIR_IN,
+			      value,
+			      index,
+			      b,
+			      blen,
+			      2000);
+
+	if (ret < 0) {
+		warn("usb in operation failed. (%d)", ret);
+		ret = -EIO;
+	} else
+		ret = 0;
+
+	deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index);
+	debug_dump(b, blen, deb_xfer);
+
+	mutex_unlock(&d->usb_mutex);
+	return ret;
+}
+
+static int az6027_usb_out_op(struct dvb_usb_device *d,
+			     u8 req,
+			     u16 value,
+			     u16 index,
+			     u8 *b,
+			     int blen)
+{
+	int ret;
+
+	deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index);
+	debug_dump(b, blen, deb_xfer);
+
+	if (mutex_lock_interruptible(&d->usb_mutex))
+		return -EAGAIN;
+
+	ret = usb_control_msg(d->udev,
+			      usb_sndctrlpipe(d->udev, 0),
+			      req,
+			      USB_TYPE_VENDOR | USB_DIR_OUT,
+			      value,
+			      index,
+			      b,
+			      blen,
+			      2000);
+
+	if (ret != blen) {
+		warn("usb out operation failed. (%d)", ret);
+		mutex_unlock(&d->usb_mutex);
+		return -EIO;
+	} else{
+		mutex_unlock(&d->usb_mutex);
+		return 0;
+	}
+}
+
+static int az6027_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+
+	deb_info("%s %d", __func__, onoff);
+
+	req = 0xBC;
+	value = onoff;
+	index = 0;
+	blen = 0;
+
+	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+	if (ret != 0)
+		warn("usb out operation failed. (%d)", ret);
+
+	return ret;
+}
+
+/* keys for the enclosed remote control */
+static struct rc_map_table rc_map_az6027_table[] = {
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+};
+
+/* remote control stuff (does not work with my box) */
+static int az6027_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	return 0;
+}
+
+/*
+int az6027_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	u8 v = onoff;
+	return az6027_usb_out_op(d,0xBC,v,3,NULL,1);
+}
+*/
+
+static int az6027_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
+					int slot,
+					int address)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+	u8 *b;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	b = kmalloc(12, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
+
+	mutex_lock(&state->ca_mutex);
+
+	req = 0xC1;
+	value = address;
+	index = 0;
+	blen = 1;
+
+	ret = az6027_usb_in_op(d, req, value, index, b, blen);
+	if (ret < 0) {
+		warn("usb in operation failed. (%d)", ret);
+		ret = -EINVAL;
+	} else {
+		ret = b[0];
+	}
+
+	mutex_unlock(&state->ca_mutex);
+	kfree(b);
+	return ret;
+}
+
+static int az6027_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
+					 int slot,
+					 int address,
+					 u8 value)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+	int ret;
+	u8 req;
+	u16 value1;
+	u16 index;
+	int blen;
+
+	deb_info("%s %d", __func__, slot);
+	if (slot != 0)
+		return -EINVAL;
+
+	mutex_lock(&state->ca_mutex);
+	req = 0xC2;
+	value1 = address;
+	index = value;
+	blen = 0;
+
+	ret = az6027_usb_out_op(d, req, value1, index, NULL, blen);
+	if (ret != 0)
+		warn("usb out operation failed. (%d)", ret);
+
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int az6027_ci_read_cam_control(struct dvb_ca_en50221 *ca,
+				      int slot,
+				      u8 address)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+	u8 *b;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	b = kmalloc(12, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
+
+	mutex_lock(&state->ca_mutex);
+
+	req = 0xC3;
+	value = address;
+	index = 0;
+	blen = 2;
+
+	ret = az6027_usb_in_op(d, req, value, index, b, blen);
+	if (ret < 0) {
+		warn("usb in operation failed. (%d)", ret);
+		ret = -EINVAL;
+	} else {
+		if (b[0] == 0)
+			warn("Read CI IO error");
+
+		ret = b[1];
+		deb_info("read cam data = %x from 0x%x", b[1], value);
+	}
+
+	mutex_unlock(&state->ca_mutex);
+	kfree(b);
+	return ret;
+}
+
+static int az6027_ci_write_cam_control(struct dvb_ca_en50221 *ca,
+				       int slot,
+				       u8 address,
+				       u8 value)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+	int ret;
+	u8 req;
+	u16 value1;
+	u16 index;
+	int blen;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	mutex_lock(&state->ca_mutex);
+	req = 0xC4;
+	value1 = address;
+	index = value;
+	blen = 0;
+
+	ret = az6027_usb_out_op(d, req, value1, index, NULL, blen);
+	if (ret != 0) {
+		warn("usb out operation failed. (%d)", ret);
+		goto failed;
+	}
+
+failed:
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+	u8 *b;
+
+	b = kmalloc(12, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
+
+	req = 0xC8;
+	value = 0;
+	index = 0;
+	blen = 1;
+
+	ret = az6027_usb_in_op(d, req, value, index, b, blen);
+	if (ret < 0) {
+		warn("usb in operation failed. (%d)", ret);
+		ret = -EIO;
+	} else{
+		ret = b[0];
+	}
+	kfree(b);
+	return ret;
+}
+
+static int az6027_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+	int ret, i;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+
+	mutex_lock(&state->ca_mutex);
+
+	req = 0xC6;
+	value = 1;
+	index = 0;
+	blen = 0;
+
+	ret = az6027_usb_out_op(d, req, value, index, NULL, blen);
+	if (ret != 0) {
+		warn("usb out operation failed. (%d)", ret);
+		goto failed;
+	}
+
+	msleep(500);
+	req = 0xC6;
+	value = 0;
+	index = 0;
+	blen = 0;
+
+	ret = az6027_usb_out_op(d, req, value, index, NULL, blen);
+	if (ret != 0) {
+		warn("usb out operation failed. (%d)", ret);
+		goto failed;
+	}
+
+	for (i = 0; i < 15; i++) {
+		msleep(100);
+
+		if (CI_CamReady(ca, slot)) {
+			deb_info("CAM Ready");
+			break;
+		}
+	}
+	msleep(5000);
+
+failed:
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int az6027_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+	return 0;
+}
+
+static int az6027_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+
+	deb_info("%s", __func__);
+	mutex_lock(&state->ca_mutex);
+	req = 0xC7;
+	value = 1;
+	index = 0;
+	blen = 0;
+
+	ret = az6027_usb_out_op(d, req, value, index, NULL, blen);
+	if (ret != 0) {
+		warn("usb out operation failed. (%d)", ret);
+		goto failed;
+	}
+
+failed:
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int az6027_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+	u8 *b;
+
+	b = kmalloc(12, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
+	mutex_lock(&state->ca_mutex);
+
+	req = 0xC5;
+	value = 0;
+	index = 0;
+	blen = 1;
+
+	ret = az6027_usb_in_op(d, req, value, index, b, blen);
+	if (ret < 0) {
+		warn("usb in operation failed. (%d)", ret);
+		ret = -EIO;
+	} else
+		ret = 0;
+
+	if (!ret && b[0] == 1) {
+		ret = DVB_CA_EN50221_POLL_CAM_PRESENT |
+		      DVB_CA_EN50221_POLL_CAM_READY;
+	}
+
+	mutex_unlock(&state->ca_mutex);
+	kfree(b);
+	return ret;
+}
+
+
+static void az6027_ci_uninit(struct dvb_usb_device *d)
+{
+	struct az6027_device_state *state;
+
+	deb_info("%s", __func__);
+
+	if (NULL == d)
+		return;
+
+	state = (struct az6027_device_state *)d->priv;
+	if (NULL == state)
+		return;
+
+	if (NULL == state->ca.data)
+		return;
+
+	dvb_ca_en50221_release(&state->ca);
+
+	memset(&state->ca, 0, sizeof(state->ca));
+}
+
+
+static int az6027_ci_init(struct dvb_usb_adapter *a)
+{
+	struct dvb_usb_device *d = a->dev;
+	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+	int ret;
+
+	deb_info("%s", __func__);
+
+	mutex_init(&state->ca_mutex);
+
+	state->ca.owner			= THIS_MODULE;
+	state->ca.read_attribute_mem	= az6027_ci_read_attribute_mem;
+	state->ca.write_attribute_mem	= az6027_ci_write_attribute_mem;
+	state->ca.read_cam_control	= az6027_ci_read_cam_control;
+	state->ca.write_cam_control	= az6027_ci_write_cam_control;
+	state->ca.slot_reset		= az6027_ci_slot_reset;
+	state->ca.slot_shutdown		= az6027_ci_slot_shutdown;
+	state->ca.slot_ts_enable	= az6027_ci_slot_ts_enable;
+	state->ca.poll_slot_status	= az6027_ci_poll_slot_status;
+	state->ca.data			= d;
+
+	ret = dvb_ca_en50221_init(&a->dvb_adap,
+				  &state->ca,
+				  0, /* flags */
+				  1);/* n_slots */
+	if (ret != 0) {
+		err("Cannot initialize CI: Error %d.", ret);
+		memset(&state->ca, 0, sizeof(state->ca));
+		return ret;
+	}
+
+	deb_info("CI initialized.");
+
+	return 0;
+}
+
+/*
+static int az6027_read_mac_addr(struct dvb_usb_device *d, u8 mac[6])
+{
+	az6027_usb_in_op(d, 0xb7, 6, 0, &mac[0], 6);
+	return 0;
+}
+*/
+
+static int az6027_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+
+	u8 buf;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+	struct i2c_msg i2c_msg = {
+		.addr	= 0x99,
+		.flags	= 0,
+		.buf	= &buf,
+		.len	= 1
+	};
+
+	/*
+	 * 2   --18v
+	 * 1   --13v
+	 * 0   --off
+	 */
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		buf = 1;
+		i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
+		break;
+
+	case SEC_VOLTAGE_18:
+		buf = 2;
+		i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
+		break;
+
+	case SEC_VOLTAGE_OFF:
+		buf = 0;
+		i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+static int az6027_frontend_poweron(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+
+	req = 0xBC;
+	value = 1; /* power on */
+	index = 3;
+	blen = 0;
+
+	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+	if (ret != 0)
+		return -EIO;
+
+	return 0;
+}
+static int az6027_frontend_reset(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+
+	/* reset demodulator */
+	req = 0xC0;
+	value = 1; /* high */
+	index = 3;
+	blen = 0;
+
+	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+	if (ret != 0)
+		return -EIO;
+
+	req = 0xC0;
+	value = 0; /* low */
+	index = 3;
+	blen = 0;
+	msleep_interruptible(200);
+
+	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+	if (ret != 0)
+		return -EIO;
+
+	msleep_interruptible(200);
+
+	req = 0xC0;
+	value = 1; /*high */
+	index = 3;
+	blen = 0;
+
+	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+	if (ret != 0)
+		return -EIO;
+
+	msleep_interruptible(200);
+	return 0;
+}
+
+static int az6027_frontend_tsbypass(struct dvb_usb_adapter *adap, int onoff)
+{
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+
+	/* TS passthrough */
+	req = 0xC7;
+	value = onoff;
+	index = 0;
+	blen = 0;
+
+	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+	if (ret != 0)
+		return -EIO;
+
+	return 0;
+}
+
+static int az6027_frontend_attach(struct dvb_usb_adapter *adap)
+{
+
+	az6027_frontend_poweron(adap);
+	az6027_frontend_reset(adap);
+
+	deb_info("adap = %p, dev = %p\n", adap, adap->dev);
+	adap->fe_adap[0].fe = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap);
+
+	if (adap->fe_adap[0].fe) {
+		deb_info("found STB0899 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb0899_config.demod_address);
+		if (stb6100_attach(adap->fe_adap[0].fe, &az6027_stb6100_config, &adap->dev->i2c_adap)) {
+			deb_info("found STB6100 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb6100_config.tuner_address);
+			adap->fe_adap[0].fe->ops.set_voltage = az6027_set_voltage;
+			az6027_ci_init(adap);
+		} else {
+			adap->fe_adap[0].fe = NULL;
+		}
+	} else
+		warn("no front-end attached\n");
+
+	az6027_frontend_tsbypass(adap, 0);
+
+	return 0;
+}
+
+static struct dvb_usb_device_properties az6027_properties;
+
+static void az6027_usb_disconnect(struct usb_interface *intf)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+	az6027_ci_uninit(d);
+	dvb_usb_device_exit(intf);
+}
+
+
+static int az6027_usb_probe(struct usb_interface *intf,
+			    const struct usb_device_id *id)
+{
+	return dvb_usb_device_init(intf,
+				   &az6027_properties,
+				   THIS_MODULE,
+				   NULL,
+				   adapter_nr);
+}
+
+/* I2C */
+static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int i = 0, j = 0, len = 0;
+	u16 index;
+	u16 value;
+	int length;
+	u8 req;
+	u8 *data;
+
+	data = kmalloc(256, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0) {
+		kfree(data);
+		return -EAGAIN;
+	}
+
+	if (num > 2)
+		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+	for (i = 0; i < num; i++) {
+
+		if (msg[i].addr == 0x99) {
+			req = 0xBE;
+			index = 0;
+			value = msg[i].buf[0] & 0x00ff;
+			length = 1;
+			az6027_usb_out_op(d, req, value, index, data, length);
+		}
+
+		if (msg[i].addr == 0xd0) {
+			/* write/read request */
+			if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) {
+				req = 0xB9;
+				index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
+				value = msg[i].addr + (msg[i].len << 8);
+				length = msg[i + 1].len + 6;
+				az6027_usb_in_op(d, req, value, index, data, length);
+				len = msg[i + 1].len;
+				for (j = 0; j < len; j++)
+					msg[i + 1].buf[j] = data[j + 5];
+
+				i++;
+			} else {
+
+				/* demod 16bit addr */
+				req = 0xBD;
+				index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
+				value = msg[i].addr + (2 << 8);
+				length = msg[i].len - 2;
+				len = msg[i].len - 2;
+				for (j = 0; j < len; j++)
+					data[j] = msg[i].buf[j + 2];
+				az6027_usb_out_op(d, req, value, index, data, length);
+			}
+		}
+
+		if (msg[i].addr == 0xc0) {
+			if (msg[i].flags & I2C_M_RD) {
+
+				req = 0xB9;
+				index = 0x0;
+				value = msg[i].addr;
+				length = msg[i].len + 6;
+				az6027_usb_in_op(d, req, value, index, data, length);
+				len = msg[i].len;
+				for (j = 0; j < len; j++)
+					msg[i].buf[j] = data[j + 5];
+
+			} else {
+
+				req = 0xBD;
+				index = msg[i].buf[0] & 0x00FF;
+				value = msg[i].addr + (1 << 8);
+				length = msg[i].len - 1;
+				len = msg[i].len - 1;
+
+				for (j = 0; j < len; j++)
+					data[j] = msg[i].buf[j + 1];
+
+				az6027_usb_out_op(d, req, value, index, data, length);
+			}
+		}
+	}
+	mutex_unlock(&d->i2c_mutex);
+	kfree(data);
+
+	return i;
+}
+
+
+static u32 az6027_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm az6027_i2c_algo = {
+	.master_xfer   = az6027_i2c_xfer,
+	.functionality = az6027_i2c_func,
+};
+
+int az6027_identify_state(struct usb_device *udev,
+			  struct dvb_usb_device_properties *props,
+			  struct dvb_usb_device_description **desc,
+			  int *cold)
+{
+	u8 *b;
+	s16 ret;
+
+	b = kmalloc(16, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
+
+	ret = usb_control_msg(udev,
+				  usb_rcvctrlpipe(udev, 0),
+				  0xb7,
+				  USB_TYPE_VENDOR | USB_DIR_IN,
+				  6,
+				  0,
+				  b,
+				  6,
+				  USB_CTRL_GET_TIMEOUT);
+
+	*cold = ret <= 0;
+	kfree(b);
+	deb_info("cold: %d\n", *cold);
+	return 0;
+}
+
+
+static struct usb_device_id az6027_usb_table[] = {
+	{ USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_AZ6027) },
+	{ USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_DVBS2CI_V1) },
+	{ USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_DVBS2CI_V2) },
+	{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V1) },
+	{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) },
+	{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(usb, az6027_usb_table);
+
+static struct dvb_usb_device_properties az6027_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware            = "dvb-usb-az6027-03.fw",
+	.no_reconnect        = 1,
+
+	.size_of_priv     = sizeof(struct az6027_device_state),
+	.identify_state		= az6027_identify_state,
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = az6027_streaming_ctrl,
+			.frontend_attach  = az6027_frontend_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 10,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+		}
+	},
+/*
+	.power_ctrl       = az6027_power_ctrl,
+	.read_mac_address = az6027_read_mac_addr,
+ */
+	.rc.legacy = {
+		.rc_map_table     = rc_map_az6027_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_az6027_table),
+		.rc_interval      = 400,
+		.rc_query         = az6027_rc_query,
+	},
+
+	.i2c_algo         = &az6027_i2c_algo,
+
+	.num_device_descs = 6,
+	.devices = {
+		{
+			.name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)",
+			.cold_ids = { &az6027_usb_table[0], NULL },
+			.warm_ids = { NULL },
+		}, {
+			.name = "TERRATEC S7",
+			.cold_ids = { &az6027_usb_table[1], NULL },
+			.warm_ids = { NULL },
+		}, {
+			.name = "TERRATEC S7 MKII",
+			.cold_ids = { &az6027_usb_table[2], NULL },
+			.warm_ids = { NULL },
+		}, {
+			.name = "Technisat SkyStar USB 2 HD CI",
+			.cold_ids = { &az6027_usb_table[3], NULL },
+			.warm_ids = { NULL },
+		}, {
+			.name = "Technisat SkyStar USB 2 HD CI",
+			.cold_ids = { &az6027_usb_table[4], NULL },
+			.warm_ids = { NULL },
+		}, {
+			.name = "Elgato EyeTV Sat",
+			.cold_ids = { &az6027_usb_table[5], NULL },
+			.warm_ids = { NULL },
+		},
+		{ NULL },
+	}
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver az6027_usb_driver = {
+	.name		= "dvb_usb_az6027",
+	.probe 		= az6027_usb_probe,
+	.disconnect 	= az6027_usb_disconnect,
+	.id_table 	= az6027_usb_table,
+};
+
+module_usb_driver(az6027_usb_driver);
+
+MODULE_AUTHOR("Adams Xu <Adams.xu@azwave.com.cn>");
+MODULE_DESCRIPTION("Driver for AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/az6027.h b/drivers/media/usb/dvb-usb/az6027.h
new file mode 100644
index 0000000..f3afe17
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/az6027.h
@@ -0,0 +1,14 @@
+#ifndef _DVB_USB_VP6027_H_
+#define _DVB_USB_VP6027_H_
+
+#define DVB_USB_LOG_PREFIX "az6027"
+#include "dvb-usb.h"
+
+
+extern int dvb_usb_az6027_debug;
+#define deb_info(args...) dprintk(dvb_usb_az6027_debug, 0x01, args)
+#define deb_xfer(args...) dprintk(dvb_usb_az6027_debug, 0x02, args)
+#define deb_rc(args...)   dprintk(dvb_usb_az6027_debug, 0x04, args)
+#define deb_fe(args...)   dprintk(dvb_usb_az6027_debug, 0x08, args)
+
+#endif
diff --git a/drivers/media/usb/dvb-usb/cinergyT2-core.c b/drivers/media/usb/dvb-usb/cinergyT2-core.c
new file mode 100644
index 0000000..0a98548
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/cinergyT2-core.c
@@ -0,0 +1,254 @@
+/*
+ * TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
+ *
+ * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
+ *
+ * Based on the dvb-usb-framework code and the
+ * original Terratec Cinergy T2 driver by:
+ *
+ * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
+ *		    Holger Waechtler <holger@qanu.de>
+ *
+ *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "cinergyT2.h"
+
+
+/* debug */
+int dvb_usb_cinergyt2_debug;
+
+module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 "
+		"(or-able)).");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct cinergyt2_state {
+	u8 rc_counter;
+};
+
+/* We are missing a release hook with usb_device data */
+static struct dvb_usb_device *cinergyt2_usb_device;
+
+static struct dvb_usb_device_properties cinergyt2_properties;
+
+static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable)
+{
+	char buf[] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 };
+	char result[64];
+	return dvb_usb_generic_rw(adap->dev, buf, sizeof(buf), result,
+				sizeof(result), 0);
+}
+
+static int cinergyt2_power_ctrl(struct dvb_usb_device *d, int enable)
+{
+	char buf[] = { CINERGYT2_EP1_SLEEP_MODE, enable ? 0 : 1 };
+	char state[3];
+	return dvb_usb_generic_rw(d, buf, sizeof(buf), state, sizeof(state), 0);
+}
+
+static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	char query[] = { CINERGYT2_EP1_GET_FIRMWARE_VERSION };
+	char state[3];
+	int ret;
+
+	adap->fe_adap[0].fe = cinergyt2_fe_attach(adap->dev);
+
+	ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state,
+				sizeof(state), 0);
+	if (ret < 0) {
+		deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep "
+			"state info\n");
+	}
+
+	/* Copy this pointer as we are gonna need it in the release phase */
+	cinergyt2_usb_device = adap->dev;
+
+	return 0;
+}
+
+static struct rc_map_table rc_map_cinergyt2_table[] = {
+	{ 0x0401, KEY_POWER },
+	{ 0x0402, KEY_1 },
+	{ 0x0403, KEY_2 },
+	{ 0x0404, KEY_3 },
+	{ 0x0405, KEY_4 },
+	{ 0x0406, KEY_5 },
+	{ 0x0407, KEY_6 },
+	{ 0x0408, KEY_7 },
+	{ 0x0409, KEY_8 },
+	{ 0x040a, KEY_9 },
+	{ 0x040c, KEY_0 },
+	{ 0x040b, KEY_VIDEO },
+	{ 0x040d, KEY_REFRESH },
+	{ 0x040e, KEY_SELECT },
+	{ 0x040f, KEY_EPG },
+	{ 0x0410, KEY_UP },
+	{ 0x0414, KEY_DOWN },
+	{ 0x0411, KEY_LEFT },
+	{ 0x0413, KEY_RIGHT },
+	{ 0x0412, KEY_OK },
+	{ 0x0415, KEY_TEXT },
+	{ 0x0416, KEY_INFO },
+	{ 0x0417, KEY_RED },
+	{ 0x0418, KEY_GREEN },
+	{ 0x0419, KEY_YELLOW },
+	{ 0x041a, KEY_BLUE },
+	{ 0x041c, KEY_VOLUMEUP },
+	{ 0x041e, KEY_VOLUMEDOWN },
+	{ 0x041d, KEY_MUTE },
+	{ 0x041b, KEY_CHANNELUP },
+	{ 0x041f, KEY_CHANNELDOWN },
+	{ 0x0440, KEY_PAUSE },
+	{ 0x044c, KEY_PLAY },
+	{ 0x0458, KEY_RECORD },
+	{ 0x0454, KEY_PREVIOUS },
+	{ 0x0448, KEY_STOP },
+	{ 0x045c, KEY_NEXT }
+};
+
+/* Number of keypresses to ignore before detect repeating */
+#define RC_REPEAT_DELAY 3
+
+static int repeatable_keys[] = {
+	KEY_UP,
+	KEY_DOWN,
+	KEY_LEFT,
+	KEY_RIGHT,
+	KEY_VOLUMEUP,
+	KEY_VOLUMEDOWN,
+	KEY_CHANNELUP,
+	KEY_CHANNELDOWN
+};
+
+static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	struct cinergyt2_state *st = d->priv;
+	u8 key[5] = {0, 0, 0, 0, 0}, cmd = CINERGYT2_EP1_GET_RC_EVENTS;
+	int i;
+
+	*state = REMOTE_NO_KEY_PRESSED;
+
+	dvb_usb_generic_rw(d, &cmd, 1, key, sizeof(key), 0);
+	if (key[4] == 0xff) {
+		/* key repeat */
+		st->rc_counter++;
+		if (st->rc_counter > RC_REPEAT_DELAY) {
+			for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) {
+				if (d->last_event == repeatable_keys[i]) {
+					*state = REMOTE_KEY_REPEAT;
+					*event = d->last_event;
+					deb_rc("repeat key, event %x\n",
+						   *event);
+					return 0;
+				}
+			}
+			deb_rc("repeated key (non repeatable)\n");
+		}
+		return 0;
+	}
+
+	/* hack to pass checksum on the custom field */
+	key[2] = ~key[1];
+	dvb_usb_nec_rc_key_to_event(d, key, event, state);
+	if (key[0] != 0) {
+		if (*event != d->last_event)
+			st->rc_counter = 0;
+
+		deb_rc("key: %x %x %x %x %x\n",
+		       key[0], key[1], key[2], key[3], key[4]);
+	}
+	return 0;
+}
+
+static int cinergyt2_usb_probe(struct usb_interface *intf,
+				const struct usb_device_id *id)
+{
+	return dvb_usb_device_init(intf, &cinergyt2_properties,
+					THIS_MODULE, NULL, adapter_nr);
+}
+
+
+static struct usb_device_id cinergyt2_usb_table[] = {
+	{ USB_DEVICE(USB_VID_TERRATEC, 0x0038) },
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table);
+
+static struct dvb_usb_device_properties cinergyt2_properties = {
+	.size_of_priv = sizeof(struct cinergyt2_state),
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = cinergyt2_streaming_ctrl,
+			.frontend_attach  = cinergyt2_frontend_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 512,
+					}
+				}
+			},
+		}},
+		}
+	},
+
+	.power_ctrl       = cinergyt2_power_ctrl,
+
+	.rc.legacy = {
+		.rc_interval      = 50,
+		.rc_map_table     = rc_map_cinergyt2_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_cinergyt2_table),
+		.rc_query         = cinergyt2_rc_query,
+	},
+
+	.generic_bulk_ctrl_endpoint = 1,
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver",
+		  .cold_ids = {NULL},
+		  .warm_ids = { &cinergyt2_usb_table[0], NULL },
+		},
+		{ NULL },
+	}
+};
+
+
+static struct usb_driver cinergyt2_driver = {
+	.name		= "cinergyT2",
+	.probe		= cinergyt2_usb_probe,
+	.disconnect	= dvb_usb_device_exit,
+	.id_table	= cinergyt2_usb_table
+};
+
+module_usb_driver(cinergyt2_driver);
+
+MODULE_DESCRIPTION("Terratec Cinergy T2 DVB-T driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tomi Orava");
diff --git a/drivers/media/usb/dvb-usb/cinergyT2-fe.c b/drivers/media/usb/dvb-usb/cinergyT2-fe.c
new file mode 100644
index 0000000..1efc028
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/cinergyT2-fe.c
@@ -0,0 +1,356 @@
+/*
+ * TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
+ *
+ * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
+ *
+ * Based on the dvb-usb-framework code and the
+ * original Terratec Cinergy T2 driver by:
+ *
+ * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
+ *                  Holger Waechtler <holger@qanu.de>
+ *
+ *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "cinergyT2.h"
+
+
+/**
+ *  convert linux-dvb frontend parameter set into TPS.
+ *  See ETSI ETS-300744, section 4.6.2, table 9 for details.
+ *
+ *  This function is probably reusable and may better get placed in a support
+ *  library.
+ *
+ *  We replace errornous fields by default TPS fields (the ones with value 0).
+ */
+
+static uint16_t compute_tps(struct dtv_frontend_properties *op)
+{
+	uint16_t tps = 0;
+
+	switch (op->code_rate_HP) {
+	case FEC_2_3:
+		tps |= (1 << 7);
+		break;
+	case FEC_3_4:
+		tps |= (2 << 7);
+		break;
+	case FEC_5_6:
+		tps |= (3 << 7);
+		break;
+	case FEC_7_8:
+		tps |= (4 << 7);
+		break;
+	case FEC_1_2:
+	case FEC_AUTO:
+	default:
+		/* tps |= (0 << 7) */;
+	}
+
+	switch (op->code_rate_LP) {
+	case FEC_2_3:
+		tps |= (1 << 4);
+		break;
+	case FEC_3_4:
+		tps |= (2 << 4);
+		break;
+	case FEC_5_6:
+		tps |= (3 << 4);
+		break;
+	case FEC_7_8:
+		tps |= (4 << 4);
+		break;
+	case FEC_1_2:
+	case FEC_AUTO:
+	default:
+		/* tps |= (0 << 4) */;
+	}
+
+	switch (op->modulation) {
+	case QAM_16:
+		tps |= (1 << 13);
+		break;
+	case QAM_64:
+		tps |= (2 << 13);
+		break;
+	case QPSK:
+	default:
+		/* tps |= (0 << 13) */;
+	}
+
+	switch (op->transmission_mode) {
+	case TRANSMISSION_MODE_8K:
+		tps |= (1 << 0);
+		break;
+	case TRANSMISSION_MODE_2K:
+	default:
+		/* tps |= (0 << 0) */;
+	}
+
+	switch (op->guard_interval) {
+	case GUARD_INTERVAL_1_16:
+		tps |= (1 << 2);
+		break;
+	case GUARD_INTERVAL_1_8:
+		tps |= (2 << 2);
+		break;
+	case GUARD_INTERVAL_1_4:
+		tps |= (3 << 2);
+		break;
+	case GUARD_INTERVAL_1_32:
+	default:
+		/* tps |= (0 << 2) */;
+	}
+
+	switch (op->hierarchy) {
+	case HIERARCHY_1:
+		tps |= (1 << 10);
+		break;
+	case HIERARCHY_2:
+		tps |= (2 << 10);
+		break;
+	case HIERARCHY_4:
+		tps |= (3 << 10);
+		break;
+	case HIERARCHY_NONE:
+	default:
+		/* tps |= (0 << 10) */;
+	}
+
+	return tps;
+}
+
+struct cinergyt2_fe_state {
+	struct dvb_frontend fe;
+	struct dvb_usb_device *d;
+};
+
+static int cinergyt2_fe_read_status(struct dvb_frontend *fe,
+					fe_status_t *status)
+{
+	struct cinergyt2_fe_state *state = fe->demodulator_priv;
+	struct dvbt_get_status_msg result;
+	u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
+	int ret;
+
+	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result,
+			sizeof(result), 0);
+	if (ret < 0)
+		return ret;
+
+	*status = 0;
+
+	if (0xffff - le16_to_cpu(result.gain) > 30)
+		*status |= FE_HAS_SIGNAL;
+	if (result.lock_bits & (1 << 6))
+		*status |= FE_HAS_LOCK;
+	if (result.lock_bits & (1 << 5))
+		*status |= FE_HAS_SYNC;
+	if (result.lock_bits & (1 << 4))
+		*status |= FE_HAS_CARRIER;
+	if (result.lock_bits & (1 << 1))
+		*status |= FE_HAS_VITERBI;
+
+	if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
+			(FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
+		*status &= ~FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct cinergyt2_fe_state *state = fe->demodulator_priv;
+	struct dvbt_get_status_msg status;
+	char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
+	int ret;
+
+	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
+				sizeof(status), 0);
+	if (ret < 0)
+		return ret;
+
+	*ber = le32_to_cpu(status.viterbi_error_rate);
+	return 0;
+}
+
+static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
+{
+	struct cinergyt2_fe_state *state = fe->demodulator_priv;
+	struct dvbt_get_status_msg status;
+	u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
+	int ret;
+
+	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&status,
+				sizeof(status), 0);
+	if (ret < 0) {
+		err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n",
+			ret);
+		return ret;
+	}
+	*unc = le32_to_cpu(status.uncorrected_block_count);
+	return 0;
+}
+
+static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe,
+						u16 *strength)
+{
+	struct cinergyt2_fe_state *state = fe->demodulator_priv;
+	struct dvbt_get_status_msg status;
+	char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
+	int ret;
+
+	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
+				sizeof(status), 0);
+	if (ret < 0) {
+		err("cinergyt2_fe_read_signal_strength() Failed!"
+			" (Error=%d)\n", ret);
+		return ret;
+	}
+	*strength = (0xffff - le16_to_cpu(status.gain));
+	return 0;
+}
+
+static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct cinergyt2_fe_state *state = fe->demodulator_priv;
+	struct dvbt_get_status_msg status;
+	char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
+	int ret;
+
+	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
+				sizeof(status), 0);
+	if (ret < 0) {
+		err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret);
+		return ret;
+	}
+	*snr = (status.snr << 8) | status.snr;
+	return 0;
+}
+
+static int cinergyt2_fe_init(struct dvb_frontend *fe)
+{
+	return 0;
+}
+
+static int cinergyt2_fe_sleep(struct dvb_frontend *fe)
+{
+	deb_info("cinergyt2_fe_sleep() Called\n");
+	return 0;
+}
+
+static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe,
+				struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 800;
+	return 0;
+}
+
+static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
+	struct cinergyt2_fe_state *state = fe->demodulator_priv;
+	struct dvbt_set_parameters_msg param;
+	char result[2];
+	int err;
+
+	param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
+	param.tps = cpu_to_le16(compute_tps(fep));
+	param.freq = cpu_to_le32(fep->frequency / 1000);
+	param.flags = 0;
+
+	switch (fep->bandwidth_hz) {
+	default:
+	case 8000000:
+		param.bandwidth = 8;
+		break;
+	case 7000000:
+		param.bandwidth = 7;
+		break;
+	case 6000000:
+		param.bandwidth = 6;
+		break;
+	}
+
+	err = dvb_usb_generic_rw(state->d,
+			(char *)&param, sizeof(param),
+			result, sizeof(result), 0);
+	if (err < 0)
+		err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err);
+
+	return (err < 0) ? err : 0;
+}
+
+static void cinergyt2_fe_release(struct dvb_frontend *fe)
+{
+	struct cinergyt2_fe_state *state = fe->demodulator_priv;
+	if (state != NULL)
+		kfree(state);
+}
+
+static struct dvb_frontend_ops cinergyt2_fe_ops;
+
+struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d)
+{
+	struct cinergyt2_fe_state *s = kzalloc(sizeof(
+					struct cinergyt2_fe_state), GFP_KERNEL);
+	if (s == NULL)
+		return NULL;
+
+	s->d = d;
+	memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops));
+	s->fe.demodulator_priv = s;
+	return &s->fe;
+}
+
+
+static struct dvb_frontend_ops cinergyt2_fe_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name			= DRIVER_NAME,
+		.frequency_min		= 174000000,
+		.frequency_max		= 862000000,
+		.frequency_stepsize	= 166667,
+		.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2
+			| FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4
+			| FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8
+			| FE_CAN_FEC_AUTO | FE_CAN_QPSK
+			| FE_CAN_QAM_16 | FE_CAN_QAM_64
+			| FE_CAN_QAM_AUTO
+			| FE_CAN_TRANSMISSION_MODE_AUTO
+			| FE_CAN_GUARD_INTERVAL_AUTO
+			| FE_CAN_HIERARCHY_AUTO
+			| FE_CAN_RECOVER
+			| FE_CAN_MUTE_TS
+	},
+
+	.release		= cinergyt2_fe_release,
+
+	.init			= cinergyt2_fe_init,
+	.sleep			= cinergyt2_fe_sleep,
+
+	.set_frontend		= cinergyt2_fe_set_frontend,
+	.get_tune_settings	= cinergyt2_fe_get_tune_settings,
+
+	.read_status		= cinergyt2_fe_read_status,
+	.read_ber		= cinergyt2_fe_read_ber,
+	.read_signal_strength	= cinergyt2_fe_read_signal_strength,
+	.read_snr		= cinergyt2_fe_read_snr,
+	.read_ucblocks		= cinergyt2_fe_read_unc_blocks,
+};
diff --git a/drivers/media/usb/dvb-usb/cinergyT2.h b/drivers/media/usb/dvb-usb/cinergyT2.h
new file mode 100644
index 0000000..84efe03
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/cinergyT2.h
@@ -0,0 +1,95 @@
+/*
+ * TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
+ *
+ * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
+ *
+ * Based on the dvb-usb-framework code and the
+ * original Terratec Cinergy T2 driver by:
+ *
+ * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
+ *                  Holger Waechtler <holger@qanu.de>
+ *
+ *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License,  or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not,  write to the Free Software
+ * Foundation,  Inc.,  675 Mass Ave,  Cambridge,  MA 02139,  USA.
+ *
+ */
+
+#ifndef _DVB_USB_CINERGYT2_H_
+#define _DVB_USB_CINERGYT2_H_
+
+#include <linux/usb/input.h>
+
+#define DVB_USB_LOG_PREFIX "cinergyT2"
+#include "dvb-usb.h"
+
+#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver"
+
+extern int dvb_usb_cinergyt2_debug;
+
+#define deb_info(args...)  dprintk(dvb_usb_cinergyt2_debug,  0x001, args)
+#define deb_xfer(args...)  dprintk(dvb_usb_cinergyt2_debug,  0x002, args)
+#define deb_pll(args...)   dprintk(dvb_usb_cinergyt2_debug,  0x004, args)
+#define deb_ts(args...)    dprintk(dvb_usb_cinergyt2_debug,  0x008, args)
+#define deb_err(args...)   dprintk(dvb_usb_cinergyt2_debug,  0x010, args)
+#define deb_rc(args...)    dprintk(dvb_usb_cinergyt2_debug,  0x020, args)
+#define deb_fw(args...)    dprintk(dvb_usb_cinergyt2_debug,  0x040, args)
+#define deb_mem(args...)   dprintk(dvb_usb_cinergyt2_debug,  0x080, args)
+#define deb_uxfer(args...) dprintk(dvb_usb_cinergyt2_debug,  0x100, args)
+
+
+
+enum cinergyt2_ep1_cmd {
+	CINERGYT2_EP1_PID_TABLE_RESET		= 0x01,
+	CINERGYT2_EP1_PID_SETUP			= 0x02,
+	CINERGYT2_EP1_CONTROL_STREAM_TRANSFER	= 0x03,
+	CINERGYT2_EP1_SET_TUNER_PARAMETERS	= 0x04,
+	CINERGYT2_EP1_GET_TUNER_STATUS		= 0x05,
+	CINERGYT2_EP1_START_SCAN		= 0x06,
+	CINERGYT2_EP1_CONTINUE_SCAN		= 0x07,
+	CINERGYT2_EP1_GET_RC_EVENTS		= 0x08,
+	CINERGYT2_EP1_SLEEP_MODE		= 0x09,
+	CINERGYT2_EP1_GET_FIRMWARE_VERSION	= 0x0A
+};
+
+
+struct dvbt_get_status_msg {
+	uint32_t freq;
+	uint8_t bandwidth;
+	uint16_t tps;
+	uint8_t flags;
+	__le16 gain;
+	uint8_t snr;
+	__le32 viterbi_error_rate;
+	uint32_t rs_error_rate;
+	__le32 uncorrected_block_count;
+	uint8_t lock_bits;
+	uint8_t prev_lock_bits;
+} __attribute__((packed));
+
+
+struct dvbt_set_parameters_msg {
+	uint8_t cmd;
+	__le32 freq;
+	uint8_t bandwidth;
+	__le16 tps;
+	uint8_t flags;
+} __attribute__((packed));
+
+
+extern struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d);
+
+#endif /* _DVB_USB_CINERGYT2_H_ */
+
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
new file mode 100644
index 0000000..3940bb0
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/cxusb.c
@@ -0,0 +1,2043 @@
+/* DVB USB compliant linux driver for Conexant USB reference design.
+ *
+ * The Conexant reference design I saw on their website was only for analogue
+ * capturing (using the cx25842). The box I took to write this driver (reverse
+ * engineered) is the one labeled Medion MD95700. In addition to the cx25842
+ * for analogue capturing it also has a cx22702 DVB-T demodulator on the main
+ * board. Besides it has a atiremote (X10) and a USB2.0 hub onboard.
+ *
+ * Maybe it is a little bit premature to call this driver cxusb, but I assume
+ * the USB protocol is identical or at least inherited from the reference
+ * design, so it can be reused for the "analogue-only" device (if it will
+ * appear at all).
+ *
+ * TODO: Use the cx25840-driver for the analogue part
+ *
+ * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org)
+ * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au)
+ *
+ *   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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include <media/tuner.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+
+#include "cxusb.h"
+
+#include "cx22702.h"
+#include "lgdt330x.h"
+#include "mt352.h"
+#include "mt352_priv.h"
+#include "zl10353.h"
+#include "tuner-xc2028.h"
+#include "tuner-simple.h"
+#include "mxl5005s.h"
+#include "max2165.h"
+#include "dib7000p.h"
+#include "dib0070.h"
+#include "lgs8gxx.h"
+#include "atbm8830.h"
+
+/* debug */
+static int dvb_usb_cxusb_debug;
+module_param_named(debug, dvb_usb_cxusb_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define deb_info(args...)   dprintk(dvb_usb_cxusb_debug, 0x03, args)
+#define deb_i2c(args...)    dprintk(dvb_usb_cxusb_debug, 0x02, args)
+
+static int cxusb_ctrl_msg(struct dvb_usb_device *d,
+			  u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+	int wo = (rbuf == NULL || rlen == 0); /* write-only */
+	u8 sndbuf[1+wlen];
+	memset(sndbuf, 0, 1+wlen);
+
+	sndbuf[0] = cmd;
+	memcpy(&sndbuf[1], wbuf, wlen);
+	if (wo)
+		return dvb_usb_generic_write(d, sndbuf, 1+wlen);
+	else
+		return dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
+}
+
+/* GPIO */
+static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff)
+{
+	struct cxusb_state *st = d->priv;
+	u8 o[2], i;
+
+	if (st->gpio_write_state[GPIO_TUNER] == onoff)
+		return;
+
+	o[0] = GPIO_TUNER;
+	o[1] = onoff;
+	cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
+
+	if (i != 0x01)
+		deb_info("gpio_write failed.\n");
+
+	st->gpio_write_state[GPIO_TUNER] = onoff;
+}
+
+static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask,
+				 u8 newval)
+{
+	u8 o[2], gpio_state;
+	int rc;
+
+	o[0] = 0xff & ~changemask;	/* mask of bits to keep */
+	o[1] = newval & changemask;	/* new values for bits  */
+
+	rc = cxusb_ctrl_msg(d, CMD_BLUEBIRD_GPIO_RW, o, 2, &gpio_state, 1);
+	if (rc < 0 || (gpio_state & changemask) != (newval & changemask))
+		deb_info("bluebird_gpio_write failed.\n");
+
+	return rc < 0 ? rc : gpio_state;
+}
+
+static void cxusb_bluebird_gpio_pulse(struct dvb_usb_device *d, u8 pin, int low)
+{
+	cxusb_bluebird_gpio_rw(d, pin, low ? 0 : pin);
+	msleep(5);
+	cxusb_bluebird_gpio_rw(d, pin, low ? pin : 0);
+}
+
+static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff)
+{
+	cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40);
+}
+
+static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d,
+		u8 addr, int onoff)
+{
+	u8  o[2] = {addr, onoff};
+	u8  i;
+	int rc;
+
+	rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
+
+	if (rc < 0)
+		return rc;
+	if (i == 0x01)
+		return 0;
+	else {
+		deb_info("gpio_write failed.\n");
+		return -EIO;
+	}
+}
+
+/* I2C */
+static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+			  int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int i;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+
+		if (d->udev->descriptor.idVendor == USB_VID_MEDION)
+			switch (msg[i].addr) {
+			case 0x63:
+				cxusb_gpio_tuner(d, 0);
+				break;
+			default:
+				cxusb_gpio_tuner(d, 1);
+				break;
+			}
+
+		if (msg[i].flags & I2C_M_RD) {
+			/* read only */
+			u8 obuf[3], ibuf[1+msg[i].len];
+			obuf[0] = 0;
+			obuf[1] = msg[i].len;
+			obuf[2] = msg[i].addr;
+			if (cxusb_ctrl_msg(d, CMD_I2C_READ,
+					   obuf, 3,
+					   ibuf, 1+msg[i].len) < 0) {
+				warn("i2c read failed");
+				break;
+			}
+			memcpy(msg[i].buf, &ibuf[1], msg[i].len);
+		} else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) &&
+			   msg[i].addr == msg[i+1].addr) {
+			/* write to then read from same address */
+			u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len];
+			obuf[0] = msg[i].len;
+			obuf[1] = msg[i+1].len;
+			obuf[2] = msg[i].addr;
+			memcpy(&obuf[3], msg[i].buf, msg[i].len);
+
+			if (cxusb_ctrl_msg(d, CMD_I2C_READ,
+					   obuf, 3+msg[i].len,
+					   ibuf, 1+msg[i+1].len) < 0)
+				break;
+
+			if (ibuf[0] != 0x08)
+				deb_i2c("i2c read may have failed\n");
+
+			memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
+
+			i++;
+		} else {
+			/* write only */
+			u8 obuf[2+msg[i].len], ibuf;
+			obuf[0] = msg[i].addr;
+			obuf[1] = msg[i].len;
+			memcpy(&obuf[2], msg[i].buf, msg[i].len);
+
+			if (cxusb_ctrl_msg(d, CMD_I2C_WRITE, obuf,
+					   2+msg[i].len, &ibuf,1) < 0)
+				break;
+			if (ibuf != 0x08)
+				deb_i2c("i2c write may have failed\n");
+		}
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return i == num ? num : -EREMOTEIO;
+}
+
+static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm cxusb_i2c_algo = {
+	.master_xfer   = cxusb_i2c_xfer,
+	.functionality = cxusb_i2c_func,
+};
+
+static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	u8 b = 0;
+	if (onoff)
+		return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0);
+	else
+		return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0);
+}
+
+static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	int ret;
+	if (!onoff)
+		return cxusb_ctrl_msg(d, CMD_POWER_OFF, NULL, 0, NULL, 0);
+	if (d->state == DVB_USB_STATE_INIT &&
+	    usb_set_interface(d->udev, 0, 0) < 0)
+		err("set interface failed");
+	do {} while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) &&
+		   !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) &&
+		   !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0);
+	if (!ret) {
+		/* FIXME: We don't know why, but we need to configure the
+		 * lgdt3303 with the register settings below on resume */
+		int i;
+		u8 buf, bufs[] = {
+			0x0e, 0x2, 0x00, 0x7f,
+			0x0e, 0x2, 0x02, 0xfe,
+			0x0e, 0x2, 0x02, 0x01,
+			0x0e, 0x2, 0x00, 0x03,
+			0x0e, 0x2, 0x0d, 0x40,
+			0x0e, 0x2, 0x0e, 0x87,
+			0x0e, 0x2, 0x0f, 0x8e,
+			0x0e, 0x2, 0x10, 0x01,
+			0x0e, 0x2, 0x14, 0xd7,
+			0x0e, 0x2, 0x47, 0x88,
+		};
+		msleep(20);
+		for (i = 0; i < sizeof(bufs)/sizeof(u8); i += 4/sizeof(u8)) {
+			ret = cxusb_ctrl_msg(d, CMD_I2C_WRITE,
+					     bufs+i, 4, &buf, 1);
+			if (ret)
+				break;
+			if (buf != 0x8)
+				return -EREMOTEIO;
+		}
+	}
+	return ret;
+}
+
+static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	u8 b = 0;
+	if (onoff)
+		return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0);
+	else
+		return 0;
+}
+
+static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	int rc = 0;
+
+	rc = cxusb_power_ctrl(d, onoff);
+	if (!onoff)
+		cxusb_nano2_led(d, 0);
+
+	return rc;
+}
+
+static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	int ret;
+	u8  b;
+	ret = cxusb_power_ctrl(d, onoff);
+	if (!onoff)
+		return ret;
+
+	msleep(128);
+	cxusb_ctrl_msg(d, CMD_DIGITAL, NULL, 0, &b, 1);
+	msleep(100);
+	return ret;
+}
+
+static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	u8 buf[2] = { 0x03, 0x00 };
+	if (onoff)
+		cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, buf, 2, NULL, 0);
+	else
+		cxusb_ctrl_msg(adap->dev, CMD_STREAMING_OFF, NULL, 0, NULL, 0);
+
+	return 0;
+}
+
+static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	if (onoff)
+		cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_ON, NULL, 0, NULL, 0);
+	else
+		cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_OFF,
+			       NULL, 0, NULL, 0);
+	return 0;
+}
+
+static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d)
+{
+	int       ep = d->props.generic_bulk_ctrl_endpoint;
+	const int timeout = 100;
+	const int junk_len = 32;
+	u8        *junk;
+	int       rd_count;
+
+	/* Discard remaining data in video pipe */
+	junk = kmalloc(junk_len, GFP_KERNEL);
+	if (!junk)
+		return;
+	while (1) {
+		if (usb_bulk_msg(d->udev,
+			usb_rcvbulkpipe(d->udev, ep),
+			junk, junk_len, &rd_count, timeout) < 0)
+			break;
+		if (!rd_count)
+			break;
+	}
+	kfree(junk);
+}
+
+static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d)
+{
+	struct usb_data_stream_properties *p = &d->props.adapter[0].fe[0].stream;
+	const int timeout = 100;
+	const int junk_len = p->u.bulk.buffersize;
+	u8        *junk;
+	int       rd_count;
+
+	/* Discard remaining data in video pipe */
+	junk = kmalloc(junk_len, GFP_KERNEL);
+	if (!junk)
+		return;
+	while (1) {
+		if (usb_bulk_msg(d->udev,
+			usb_rcvbulkpipe(d->udev, p->endpoint),
+			junk, junk_len, &rd_count, timeout) < 0)
+			break;
+		if (!rd_count)
+			break;
+	}
+	kfree(junk);
+}
+
+static int cxusb_d680_dmb_streaming_ctrl(
+		struct dvb_usb_adapter *adap, int onoff)
+{
+	if (onoff) {
+		u8 buf[2] = { 0x03, 0x00 };
+		cxusb_d680_dmb_drain_video(adap->dev);
+		return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON,
+			buf, sizeof(buf), NULL, 0);
+	} else {
+		int ret = cxusb_ctrl_msg(adap->dev,
+			CMD_STREAMING_OFF, NULL, 0, NULL, 0);
+		return ret;
+	}
+}
+
+static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
+	u8 ircode[4];
+	int i;
+
+	cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4);
+
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
+
+	for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
+		if (rc5_custom(&keymap[i]) == ircode[2] &&
+		    rc5_data(&keymap[i]) == ircode[3]) {
+			*event = keymap[i].keycode;
+			*state = REMOTE_KEY_PRESSED;
+
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
+				    int *state)
+{
+	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
+	u8 ircode[4];
+	int i;
+	struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
+			       .buf = ircode, .len = 4 };
+
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
+
+	if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1)
+		return 0;
+
+	for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
+		if (rc5_custom(&keymap[i]) == ircode[1] &&
+		    rc5_data(&keymap[i]) == ircode[2]) {
+			*event = keymap[i].keycode;
+			*state = REMOTE_KEY_PRESSED;
+
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
+		int *state)
+{
+	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
+	u8 ircode[2];
+	int i;
+
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
+
+	if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0)
+		return 0;
+
+	for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
+		if (rc5_custom(&keymap[i]) == ircode[0] &&
+		    rc5_data(&keymap[i]) == ircode[1]) {
+			*event = keymap[i].keycode;
+			*state = REMOTE_KEY_PRESSED;
+
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+static struct rc_map_table rc_map_dvico_mce_table[] = {
+	{ 0xfe02, KEY_TV },
+	{ 0xfe0e, KEY_MP3 },
+	{ 0xfe1a, KEY_DVD },
+	{ 0xfe1e, KEY_FAVORITES },
+	{ 0xfe16, KEY_SETUP },
+	{ 0xfe46, KEY_POWER2 },
+	{ 0xfe0a, KEY_EPG },
+	{ 0xfe49, KEY_BACK },
+	{ 0xfe4d, KEY_MENU },
+	{ 0xfe51, KEY_UP },
+	{ 0xfe5b, KEY_LEFT },
+	{ 0xfe5f, KEY_RIGHT },
+	{ 0xfe53, KEY_DOWN },
+	{ 0xfe5e, KEY_OK },
+	{ 0xfe59, KEY_INFO },
+	{ 0xfe55, KEY_TAB },
+	{ 0xfe0f, KEY_PREVIOUSSONG },/* Replay */
+	{ 0xfe12, KEY_NEXTSONG },	/* Skip */
+	{ 0xfe42, KEY_ENTER	 },	/* Windows/Start */
+	{ 0xfe15, KEY_VOLUMEUP },
+	{ 0xfe05, KEY_VOLUMEDOWN },
+	{ 0xfe11, KEY_CHANNELUP },
+	{ 0xfe09, KEY_CHANNELDOWN },
+	{ 0xfe52, KEY_CAMERA },
+	{ 0xfe5a, KEY_TUNER },	/* Live */
+	{ 0xfe19, KEY_OPEN },
+	{ 0xfe0b, KEY_1 },
+	{ 0xfe17, KEY_2 },
+	{ 0xfe1b, KEY_3 },
+	{ 0xfe07, KEY_4 },
+	{ 0xfe50, KEY_5 },
+	{ 0xfe54, KEY_6 },
+	{ 0xfe48, KEY_7 },
+	{ 0xfe4c, KEY_8 },
+	{ 0xfe58, KEY_9 },
+	{ 0xfe13, KEY_ANGLE },	/* Aspect */
+	{ 0xfe03, KEY_0 },
+	{ 0xfe1f, KEY_ZOOM },
+	{ 0xfe43, KEY_REWIND },
+	{ 0xfe47, KEY_PLAYPAUSE },
+	{ 0xfe4f, KEY_FASTFORWARD },
+	{ 0xfe57, KEY_MUTE },
+	{ 0xfe0d, KEY_STOP },
+	{ 0xfe01, KEY_RECORD },
+	{ 0xfe4e, KEY_POWER },
+};
+
+static struct rc_map_table rc_map_dvico_portable_table[] = {
+	{ 0xfc02, KEY_SETUP },       /* Profile */
+	{ 0xfc43, KEY_POWER2 },
+	{ 0xfc06, KEY_EPG },
+	{ 0xfc5a, KEY_BACK },
+	{ 0xfc05, KEY_MENU },
+	{ 0xfc47, KEY_INFO },
+	{ 0xfc01, KEY_TAB },
+	{ 0xfc42, KEY_PREVIOUSSONG },/* Replay */
+	{ 0xfc49, KEY_VOLUMEUP },
+	{ 0xfc09, KEY_VOLUMEDOWN },
+	{ 0xfc54, KEY_CHANNELUP },
+	{ 0xfc0b, KEY_CHANNELDOWN },
+	{ 0xfc16, KEY_CAMERA },
+	{ 0xfc40, KEY_TUNER },	/* ATV/DTV */
+	{ 0xfc45, KEY_OPEN },
+	{ 0xfc19, KEY_1 },
+	{ 0xfc18, KEY_2 },
+	{ 0xfc1b, KEY_3 },
+	{ 0xfc1a, KEY_4 },
+	{ 0xfc58, KEY_5 },
+	{ 0xfc59, KEY_6 },
+	{ 0xfc15, KEY_7 },
+	{ 0xfc14, KEY_8 },
+	{ 0xfc17, KEY_9 },
+	{ 0xfc44, KEY_ANGLE },	/* Aspect */
+	{ 0xfc55, KEY_0 },
+	{ 0xfc07, KEY_ZOOM },
+	{ 0xfc0a, KEY_REWIND },
+	{ 0xfc08, KEY_PLAYPAUSE },
+	{ 0xfc4b, KEY_FASTFORWARD },
+	{ 0xfc5b, KEY_MUTE },
+	{ 0xfc04, KEY_STOP },
+	{ 0xfc56, KEY_RECORD },
+	{ 0xfc57, KEY_POWER },
+	{ 0xfc41, KEY_UNKNOWN },    /* INPUT */
+	{ 0xfc00, KEY_UNKNOWN },    /* HD */
+};
+
+static struct rc_map_table rc_map_d680_dmb_table[] = {
+	{ 0x0038, KEY_UNKNOWN },	/* TV/AV */
+	{ 0x080c, KEY_ZOOM },
+	{ 0x0800, KEY_0 },
+	{ 0x0001, KEY_1 },
+	{ 0x0802, KEY_2 },
+	{ 0x0003, KEY_3 },
+	{ 0x0804, KEY_4 },
+	{ 0x0005, KEY_5 },
+	{ 0x0806, KEY_6 },
+	{ 0x0007, KEY_7 },
+	{ 0x0808, KEY_8 },
+	{ 0x0009, KEY_9 },
+	{ 0x000a, KEY_MUTE },
+	{ 0x0829, KEY_BACK },
+	{ 0x0012, KEY_CHANNELUP },
+	{ 0x0813, KEY_CHANNELDOWN },
+	{ 0x002b, KEY_VOLUMEUP },
+	{ 0x082c, KEY_VOLUMEDOWN },
+	{ 0x0020, KEY_UP },
+	{ 0x0821, KEY_DOWN },
+	{ 0x0011, KEY_LEFT },
+	{ 0x0810, KEY_RIGHT },
+	{ 0x000d, KEY_OK },
+	{ 0x081f, KEY_RECORD },
+	{ 0x0017, KEY_PLAYPAUSE },
+	{ 0x0816, KEY_PLAYPAUSE },
+	{ 0x000b, KEY_STOP },
+	{ 0x0827, KEY_FASTFORWARD },
+	{ 0x0026, KEY_REWIND },
+	{ 0x081e, KEY_UNKNOWN },    /* Time Shift */
+	{ 0x000e, KEY_UNKNOWN },    /* Snapshot */
+	{ 0x082d, KEY_UNKNOWN },    /* Mouse Cursor */
+	{ 0x000f, KEY_UNKNOWN },    /* Minimize/Maximize */
+	{ 0x0814, KEY_UNKNOWN },    /* Shuffle */
+	{ 0x0025, KEY_POWER },
+};
+
+static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
+{
+	static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x28 };
+	static u8 reset []         = { RESET,      0x80 };
+	static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+	static u8 agc_cfg []       = { AGC_TARGET, 0x28, 0x20 };
+	static u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
+	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(200);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+	return 0;
+}
+
+static int cxusb_mt352_demod_init(struct dvb_frontend* fe)
+{	/* used in both lgz201 and th7579 */
+	static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x29 };
+	static u8 reset []         = { RESET,      0x80 };
+	static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+	static u8 agc_cfg []       = { AGC_TARGET, 0x24, 0x20 };
+	static u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
+	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(200);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+	return 0;
+}
+
+static struct cx22702_config cxusb_cx22702_config = {
+	.demod_address = 0x63,
+	.output_mode = CX22702_PARALLEL_OUTPUT,
+};
+
+static struct lgdt330x_config cxusb_lgdt3303_config = {
+	.demod_address = 0x0e,
+	.demod_chip    = LGDT3303,
+};
+
+static struct lgdt330x_config cxusb_aver_lgdt3303_config = {
+	.demod_address       = 0x0e,
+	.demod_chip          = LGDT3303,
+	.clock_polarity_flip = 2,
+};
+
+static struct mt352_config cxusb_dee1601_config = {
+	.demod_address = 0x0f,
+	.demod_init    = cxusb_dee1601_demod_init,
+};
+
+static struct zl10353_config cxusb_zl10353_dee1601_config = {
+	.demod_address = 0x0f,
+	.parallel_ts = 1,
+};
+
+static struct mt352_config cxusb_mt352_config = {
+	/* used in both lgz201 and th7579 */
+	.demod_address = 0x0f,
+	.demod_init    = cxusb_mt352_demod_init,
+};
+
+static struct zl10353_config cxusb_zl10353_xc3028_config = {
+	.demod_address = 0x0f,
+	.if2 = 45600,
+	.no_tuner = 1,
+	.parallel_ts = 1,
+};
+
+static struct zl10353_config cxusb_zl10353_xc3028_config_no_i2c_gate = {
+	.demod_address = 0x0f,
+	.if2 = 45600,
+	.no_tuner = 1,
+	.parallel_ts = 1,
+	.disable_i2c_gate_ctrl = 1,
+};
+
+static struct mt352_config cxusb_mt352_xc3028_config = {
+	.demod_address = 0x0f,
+	.if2 = 4560,
+	.no_tuner = 1,
+	.demod_init = cxusb_mt352_demod_init,
+};
+
+/* FIXME: needs tweaking */
+static struct mxl5005s_config aver_a868r_tuner = {
+	.i2c_address     = 0x63,
+	.if_freq         = 6000000UL,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_C,
+	.rssi_enable     = MXL_RSSI_ENABLE,
+	.cap_select      = MXL_CAP_SEL_ENABLE,
+	.div_out         = MXL_DIV_OUT_4,
+	.clock_out       = MXL_CLOCK_OUT_DISABLE,
+	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+	.top		 = MXL5005S_TOP_25P2,
+	.mod_mode        = MXL_DIGITAL_MODE,
+	.if_mode         = MXL_ZERO_IF,
+	.AgcMasterByte   = 0x00,
+};
+
+/* FIXME: needs tweaking */
+static struct mxl5005s_config d680_dmb_tuner = {
+	.i2c_address     = 0x63,
+	.if_freq         = 36125000UL,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_C,
+	.rssi_enable     = MXL_RSSI_ENABLE,
+	.cap_select      = MXL_CAP_SEL_ENABLE,
+	.div_out         = MXL_DIV_OUT_4,
+	.clock_out       = MXL_CLOCK_OUT_DISABLE,
+	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+	.top		 = MXL5005S_TOP_25P2,
+	.mod_mode        = MXL_DIGITAL_MODE,
+	.if_mode         = MXL_ZERO_IF,
+	.AgcMasterByte   = 0x00,
+};
+
+static struct max2165_config mygica_d689_max2165_cfg = {
+	.i2c_address = 0x60,
+	.osc_clk = 20
+};
+
+/* Callbacks for DVB USB */
+static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe,
+		   &adap->dev->i2c_adap, 0x61,
+		   TUNER_PHILIPS_FMD1216ME_MK3);
+	return 0;
+}
+
+static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61,
+		   NULL, DVB_PLL_THOMSON_DTT7579);
+	return 0;
+}
+
+static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_LG_Z201);
+	return 0;
+}
+
+static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
+		   NULL, DVB_PLL_THOMSON_DTT7579);
+	return 0;
+}
+
+static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe,
+		   &adap->dev->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF);
+	return 0;
+}
+
+static int dvico_bluebird_xc2028_callback(void *ptr, int component,
+					  int command, int arg)
+{
+	struct dvb_usb_adapter *adap = ptr;
+	struct dvb_usb_device *d = adap->dev;
+
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		deb_info("%s: XC2028_TUNER_RESET %d\n", __func__, arg);
+		cxusb_bluebird_gpio_pulse(d, 0x01, 1);
+		break;
+	case XC2028_RESET_CLK:
+		deb_info("%s: XC2028_RESET_CLK %d\n", __func__, arg);
+		break;
+	default:
+		deb_info("%s: unknown command %d, arg %d\n", __func__,
+			 command, arg);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_frontend	 *fe;
+	struct xc2028_config	  cfg = {
+		.i2c_adap  = &adap->dev->i2c_adap,
+		.i2c_addr  = 0x61,
+	};
+	static struct xc2028_ctrl ctl = {
+		.fname       = XC2028_DEFAULT_FIRMWARE,
+		.max_len     = 64,
+		.demod       = XC3028_FE_ZARLINK456,
+	};
+
+	/* FIXME: generalize & move to common area */
+	adap->fe_adap[0].fe->callback = dvico_bluebird_xc2028_callback;
+
+	fe = dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &cfg);
+	if (fe == NULL || fe->ops.tuner_ops.set_config == NULL)
+		return -EIO;
+
+	fe->ops.tuner_ops.set_config(fe, &ctl);
+
+	return 0;
+}
+
+static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
+		   &adap->dev->i2c_adap, &aver_a868r_tuner);
+	return 0;
+}
+
+static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_frontend *fe;
+	fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
+			&adap->dev->i2c_adap, &d680_dmb_tuner);
+	return (fe == NULL) ? -EIO : 0;
+}
+
+static int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_frontend *fe;
+	fe = dvb_attach(max2165_attach, adap->fe_adap[0].fe,
+			&adap->dev->i2c_adap, &mygica_d689_max2165_cfg);
+	return (fe == NULL) ? -EIO : 0;
+}
+
+static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	u8 b;
+	if (usb_set_interface(adap->dev->udev, 0, 6) < 0)
+		err("set interface failed");
+
+	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1);
+
+	adap->fe_adap[0].fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config,
+					 &adap->dev->i2c_adap);
+	if ((adap->fe_adap[0].fe) != NULL)
+		return 0;
+
+	return -EIO;
+}
+
+static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	if (usb_set_interface(adap->dev->udev, 0, 7) < 0)
+		err("set interface failed");
+
+	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
+
+	adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach,
+					 &cxusb_lgdt3303_config,
+					 &adap->dev->i2c_adap);
+	if ((adap->fe_adap[0].fe) != NULL)
+		return 0;
+
+	return -EIO;
+}
+
+static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config,
+			      &adap->dev->i2c_adap);
+	if (adap->fe_adap[0].fe != NULL)
+		return 0;
+
+	return -EIO;
+}
+
+static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	/* used in both lgz201 and th7579 */
+	if (usb_set_interface(adap->dev->udev, 0, 0) < 0)
+		err("set interface failed");
+
+	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
+
+	adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_mt352_config,
+					 &adap->dev->i2c_adap);
+	if ((adap->fe_adap[0].fe) != NULL)
+		return 0;
+
+	return -EIO;
+}
+
+static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	if (usb_set_interface(adap->dev->udev, 0, 0) < 0)
+		err("set interface failed");
+
+	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
+
+	adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_dee1601_config,
+					 &adap->dev->i2c_adap);
+	if ((adap->fe_adap[0].fe) != NULL)
+		return 0;
+
+	adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
+					 &cxusb_zl10353_dee1601_config,
+					 &adap->dev->i2c_adap);
+	if ((adap->fe_adap[0].fe) != NULL)
+		return 0;
+
+	return -EIO;
+}
+
+static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	u8 ircode[4];
+	int i;
+	struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
+			       .buf = ircode, .len = 4 };
+
+	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
+		err("set interface failed");
+
+	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
+
+	/* reset the tuner and demodulator */
+	cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0);
+	cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
+	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
+
+	adap->fe_adap[0].fe =
+		dvb_attach(zl10353_attach,
+			   &cxusb_zl10353_xc3028_config_no_i2c_gate,
+			   &adap->dev->i2c_adap);
+	if ((adap->fe_adap[0].fe) == NULL)
+		return -EIO;
+
+	/* try to determine if there is no IR decoder on the I2C bus */
+	for (i = 0; adap->dev->props.rc.legacy.rc_map_table != NULL && i < 5; i++) {
+		msleep(20);
+		if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1)
+			goto no_IR;
+		if (ircode[0] == 0 && ircode[1] == 0)
+			continue;
+		if (ircode[2] + ircode[3] != 0xff) {
+no_IR:
+			adap->dev->props.rc.legacy.rc_map_table = NULL;
+			info("No IR receiver detected on this device.");
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static struct dibx000_agc_config dib7070_agc_config = {
+	.band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
+
+	/*
+	 * P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5,
+	 * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+	 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0
+	 */
+	.setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) |
+		 (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+	.inv_gain = 600,
+	.time_stabiliz = 10,
+	.alpha_level = 0,
+	.thlock = 118,
+	.wbd_inv = 0,
+	.wbd_ref = 3530,
+	.wbd_sel = 1,
+	.wbd_alpha = 5,
+	.agc1_max = 65535,
+	.agc1_min = 0,
+	.agc2_max = 65535,
+	.agc2_min = 0,
+	.agc1_pt1 = 0,
+	.agc1_pt2 = 40,
+	.agc1_pt3 = 183,
+	.agc1_slope1 = 206,
+	.agc1_slope2 = 255,
+	.agc2_pt1 = 72,
+	.agc2_pt2 = 152,
+	.agc2_slope1 = 88,
+	.agc2_slope2 = 90,
+	.alpha_mant = 17,
+	.alpha_exp = 27,
+	.beta_mant = 23,
+	.beta_exp = 51,
+	.perform_agc_softsplit = 0,
+};
+
+static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
+	.internal = 60000,
+	.sampling = 15000,
+	.pll_prediv = 1,
+	.pll_ratio = 20,
+	.pll_range = 3,
+	.pll_reset = 1,
+	.pll_bypass = 0,
+	.enable_refdiv = 0,
+	.bypclk_div = 0,
+	.IO_CLK_en_core = 1,
+	.ADClkSrc = 1,
+	.modulo = 2,
+	/* refsel, sel, freq_15k */
+	.sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+	.ifreq = (0 << 25) | 0,
+	.timf = 20452225,
+	.xtal_hz = 12000000,
+};
+
+static struct dib7000p_config cxusb_dualdig4_rev2_config = {
+	.output_mode = OUTMODE_MPEG2_PAR_GATED_CLK,
+	.output_mpeg2_in_188_bytes = 1,
+
+	.agc_config_count = 1,
+	.agc = &dib7070_agc_config,
+	.bw  = &dib7070_bw_config_12_mhz,
+	.tuner_is_baseband = 1,
+	.spur_protect = 1,
+
+	.gpio_dir = 0xfcef,
+	.gpio_val = 0x0110,
+
+	.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+	.hostbus_diversity = 1,
+};
+
+static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
+		err("set interface failed");
+
+	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
+
+	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
+
+	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+				     &cxusb_dualdig4_rev2_config) < 0) {
+		printk(KERN_WARNING "Unable to enumerate dib7000p\n");
+		return -ENODEV;
+	}
+
+	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+			      &cxusb_dualdig4_rev2_config);
+	if (adap->fe_adap[0].fe == NULL)
+		return -EIO;
+
+	return 0;
+}
+
+static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
+{
+	return dib7000p_set_gpio(fe, 8, 0, !onoff);
+}
+
+static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+	return 0;
+}
+
+static struct dib0070_config dib7070p_dib0070_config = {
+	.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+	.reset = dib7070_tuner_reset,
+	.sleep = dib7070_tuner_sleep,
+	.clock_khz = 12000,
+};
+
+struct dib0700_adapter_state {
+	int (*set_param_save) (struct dvb_frontend *);
+};
+
+static int dib7070_set_param_override(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dib0700_adapter_state *state = adap->priv;
+
+	u16 offset;
+	u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
+	switch (band) {
+	case BAND_VHF: offset = 950; break;
+	default:
+	case BAND_UHF: offset = 550; break;
+	}
+
+	dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
+
+	return state->set_param_save(fe);
+}
+
+static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *st = adap->priv;
+	struct i2c_adapter *tun_i2c =
+		dib7000p_get_i2c_master(adap->fe_adap[0].fe,
+					DIBX000_I2C_INTERFACE_TUNER, 1);
+
+	if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
+	    &dib7070p_dib0070_config) == NULL)
+		return -ENODEV;
+
+	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7070_set_param_override;
+	return 0;
+}
+
+static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
+		err("set interface failed");
+
+	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
+
+	/* reset the tuner and demodulator */
+	cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0);
+	cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
+	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
+
+	adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
+					 &cxusb_zl10353_xc3028_config,
+					 &adap->dev->i2c_adap);
+	if ((adap->fe_adap[0].fe) != NULL)
+		return 0;
+
+	adap->fe_adap[0].fe = dvb_attach(mt352_attach,
+					 &cxusb_mt352_xc3028_config,
+					 &adap->dev->i2c_adap);
+	if ((adap->fe_adap[0].fe) != NULL)
+		return 0;
+
+	return -EIO;
+}
+
+static struct lgs8gxx_config d680_lgs8gl5_cfg = {
+	.prod = LGS8GXX_PROD_LGS8GL5,
+	.demod_address = 0x19,
+	.serial_ts = 0,
+	.ts_clk_pol = 0,
+	.ts_clk_gated = 1,
+	.if_clk_freq = 30400, /* 30.4 MHz */
+	.if_freq = 5725, /* 5.725 MHz */
+	.if_neg_center = 0,
+	.ext_adc = 0,
+	.adc_signed = 0,
+	.if_neg_edge = 0,
+};
+
+static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap->dev;
+	int n;
+
+	/* Select required USB configuration */
+	if (usb_set_interface(d->udev, 0, 0) < 0)
+		err("set interface failed");
+
+	/* Unblock all USB pipes */
+	usb_clear_halt(d->udev,
+		usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+	usb_clear_halt(d->udev,
+		usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+	usb_clear_halt(d->udev,
+		usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint));
+
+	/* Drain USB pipes to avoid hang after reboot */
+	for (n = 0;  n < 5;  n++) {
+		cxusb_d680_dmb_drain_message(d);
+		cxusb_d680_dmb_drain_video(d);
+		msleep(200);
+	}
+
+	/* Reset the tuner */
+	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) {
+		err("clear tuner gpio failed");
+		return -EIO;
+	}
+	msleep(100);
+	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) {
+		err("set tuner gpio failed");
+		return -EIO;
+	}
+	msleep(100);
+
+	/* Attach frontend */
+	adap->fe_adap[0].fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap);
+	if (adap->fe_adap[0].fe == NULL)
+		return -EIO;
+
+	return 0;
+}
+
+static struct atbm8830_config mygica_d689_atbm8830_cfg = {
+	.prod = ATBM8830_PROD_8830,
+	.demod_address = 0x40,
+	.serial_ts = 0,
+	.ts_sampling_edge = 1,
+	.ts_clk_gated = 0,
+	.osc_clk_freq = 30400, /* in kHz */
+	.if_freq = 0, /* zero IF */
+	.zif_swap_iq = 1,
+	.agc_min = 0x2E,
+	.agc_max = 0x90,
+	.agc_hold_loop = 0,
+};
+
+static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap->dev;
+
+	/* Select required USB configuration */
+	if (usb_set_interface(d->udev, 0, 0) < 0)
+		err("set interface failed");
+
+	/* Unblock all USB pipes */
+	usb_clear_halt(d->udev,
+		usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+	usb_clear_halt(d->udev,
+		usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+	usb_clear_halt(d->udev,
+		usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint));
+
+
+	/* Reset the tuner */
+	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) {
+		err("clear tuner gpio failed");
+		return -EIO;
+	}
+	msleep(100);
+	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) {
+		err("set tuner gpio failed");
+		return -EIO;
+	}
+	msleep(100);
+
+	/* Attach frontend */
+	adap->fe_adap[0].fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg,
+		&d->i2c_adap);
+	if (adap->fe_adap[0].fe == NULL)
+		return -EIO;
+
+	return 0;
+}
+
+/*
+ * DViCO has shipped two devices with the same USB ID, but only one of them
+ * needs a firmware download.  Check the device class details to see if they
+ * have non-default values to decide whether the device is actually cold or
+ * not, and forget a match if it turns out we selected the wrong device.
+ */
+static int bluebird_fx2_identify_state(struct usb_device *udev,
+				       struct dvb_usb_device_properties *props,
+				       struct dvb_usb_device_description **desc,
+				       int *cold)
+{
+	int wascold = *cold;
+
+	*cold = udev->descriptor.bDeviceClass == 0xff &&
+		udev->descriptor.bDeviceSubClass == 0xff &&
+		udev->descriptor.bDeviceProtocol == 0xff;
+
+	if (*cold && !wascold)
+		*desc = NULL;
+
+	return 0;
+}
+
+/*
+ * DViCO bluebird firmware needs the "warm" product ID to be patched into the
+ * firmware file before download.
+ */
+
+static const int dvico_firmware_id_offsets[] = { 6638, 3204 };
+static int bluebird_patch_dvico_firmware_download(struct usb_device *udev,
+						  const struct firmware *fw)
+{
+	int pos;
+
+	for (pos = 0; pos < ARRAY_SIZE(dvico_firmware_id_offsets); pos++) {
+		int idoff = dvico_firmware_id_offsets[pos];
+
+		if (fw->size < idoff + 4)
+			continue;
+
+		if (fw->data[idoff] == (USB_VID_DVICO & 0xff) &&
+		    fw->data[idoff + 1] == USB_VID_DVICO >> 8) {
+			struct firmware new_fw;
+			u8 *new_fw_data = vmalloc(fw->size);
+			int ret;
+
+			if (!new_fw_data)
+				return -ENOMEM;
+
+			memcpy(new_fw_data, fw->data, fw->size);
+			new_fw.size = fw->size;
+			new_fw.data = new_fw_data;
+
+			new_fw_data[idoff + 2] =
+				le16_to_cpu(udev->descriptor.idProduct) + 1;
+			new_fw_data[idoff + 3] =
+				le16_to_cpu(udev->descriptor.idProduct) >> 8;
+
+			ret = usb_cypress_load_firmware(udev, &new_fw,
+							CYPRESS_FX2);
+			vfree(new_fw_data);
+			return ret;
+		}
+	}
+
+	return -EINVAL;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties cxusb_medion_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
+static struct dvb_usb_device_properties cxusb_aver_a868r_properties;
+static struct dvb_usb_device_properties cxusb_d680_dmb_properties;
+static struct dvb_usb_device_properties cxusb_mygica_d689_properties;
+
+static int cxusb_probe(struct usb_interface *intf,
+		       const struct usb_device_id *id)
+{
+	if (0 == dvb_usb_device_init(intf, &cxusb_medion_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgh064f_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_dee1601_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgz201_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_dtt7579_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_dualdig4_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_nano2_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf,
+				&cxusb_bluebird_nano2_needsfirmware_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf,
+				     &cxusb_bluebird_dualdig4_rev2_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_mygica_d689_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0)
+		return 0;
+
+	return -EINVAL;
+}
+
+static struct usb_device_id cxusb_table [] = {
+	{ USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) },
+	{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) },
+	{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) },
+	{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) },
+	{}		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, cxusb_table);
+
+static struct dvb_usb_device_properties cxusb_medion_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = CYPRESS_FX2,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = cxusb_streaming_ctrl,
+			.frontend_attach  = cxusb_cx22702_frontend_attach,
+			.tuner_attach     = cxusb_fmd1216me_tuner_attach,
+			/* parameter for the MPEG2-data transfer */
+					.stream = {
+						.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		}},
+		},
+	},
+	.power_ctrl       = cxusb_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "Medion MD95700 (MDUSBTV-HYBRID)",
+			{ NULL },
+			{ &cxusb_table[0], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl          = DEVICE_SPECIFIC,
+	.firmware          = "dvb-usb-bluebird-01.fw",
+	.download_firmware = bluebird_patch_dvico_firmware_download,
+	/* use usb alt setting 0 for EP4 transfer (dvb-t),
+	   use usb alt setting 7 for EP2 transfer (atsc) */
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = cxusb_streaming_ctrl,
+			.frontend_attach  = cxusb_lgdt3303_frontend_attach,
+			.tuner_attach     = cxusb_lgh064f_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+					.stream = {
+						.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		}},
+		},
+	},
+
+	.power_ctrl       = cxusb_bluebird_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_map_table     = rc_map_dvico_portable_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_dvico_portable_table),
+		.rc_query         = cxusb_rc_query,
+	},
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "DViCO FusionHDTV5 USB Gold",
+			{ &cxusb_table[1], NULL },
+			{ &cxusb_table[2], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl          = DEVICE_SPECIFIC,
+	.firmware          = "dvb-usb-bluebird-01.fw",
+	.download_firmware = bluebird_patch_dvico_firmware_download,
+	/* use usb alt setting 0 for EP4 transfer (dvb-t),
+	   use usb alt setting 7 for EP2 transfer (atsc) */
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = cxusb_streaming_ctrl,
+			.frontend_attach  = cxusb_dee1601_frontend_attach,
+			.tuner_attach     = cxusb_dee1601_tuner_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x04,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		}},
+		},
+	},
+
+	.power_ctrl       = cxusb_bluebird_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.rc.legacy = {
+		.rc_interval      = 150,
+		.rc_map_table     = rc_map_dvico_mce_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_dvico_mce_table),
+		.rc_query         = cxusb_rc_query,
+	},
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 3,
+	.devices = {
+		{   "DViCO FusionHDTV DVB-T Dual USB",
+			{ &cxusb_table[3], NULL },
+			{ &cxusb_table[4], NULL },
+		},
+		{   "DigitalNow DVB-T Dual USB",
+			{ &cxusb_table[9],  NULL },
+			{ &cxusb_table[10], NULL },
+		},
+		{   "DViCO FusionHDTV DVB-T Dual Digital 2",
+			{ &cxusb_table[11], NULL },
+			{ &cxusb_table[12], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl          = DEVICE_SPECIFIC,
+	.firmware          = "dvb-usb-bluebird-01.fw",
+	.download_firmware = bluebird_patch_dvico_firmware_download,
+	/* use usb alt setting 0 for EP4 transfer (dvb-t),
+	   use usb alt setting 7 for EP2 transfer (atsc) */
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 2,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = cxusb_streaming_ctrl,
+			.frontend_attach  = cxusb_mt352_frontend_attach,
+			.tuner_attach     = cxusb_lgz201_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x04,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		}},
+		},
+	},
+	.power_ctrl       = cxusb_bluebird_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_map_table     = rc_map_dvico_portable_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_dvico_portable_table),
+		.rc_query         = cxusb_rc_query,
+	},
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+	.num_device_descs = 1,
+	.devices = {
+		{   "DViCO FusionHDTV DVB-T USB (LGZ201)",
+			{ &cxusb_table[5], NULL },
+			{ &cxusb_table[6], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl          = DEVICE_SPECIFIC,
+	.firmware          = "dvb-usb-bluebird-01.fw",
+	.download_firmware = bluebird_patch_dvico_firmware_download,
+	/* use usb alt setting 0 for EP4 transfer (dvb-t),
+	   use usb alt setting 7 for EP2 transfer (atsc) */
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = cxusb_streaming_ctrl,
+			.frontend_attach  = cxusb_mt352_frontend_attach,
+			.tuner_attach     = cxusb_dtt7579_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x04,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		}},
+		},
+	},
+	.power_ctrl       = cxusb_bluebird_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_map_table     = rc_map_dvico_portable_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_dvico_portable_table),
+		.rc_query         = cxusb_rc_query,
+	},
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "DViCO FusionHDTV DVB-T USB (TH7579)",
+			{ &cxusb_table[7], NULL },
+			{ &cxusb_table[8], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = CYPRESS_FX2,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = cxusb_streaming_ctrl,
+			.frontend_attach  = cxusb_dualdig4_frontend_attach,
+			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		}},
+		},
+	},
+
+	.power_ctrl       = cxusb_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_map_table     = rc_map_dvico_mce_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_dvico_mce_table),
+		.rc_query         = cxusb_bluebird2_rc_query,
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "DViCO FusionHDTV DVB-T Dual Digital 4",
+			{ NULL },
+			{ &cxusb_table[13], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = CYPRESS_FX2,
+	.identify_state   = bluebird_fx2_identify_state,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = cxusb_streaming_ctrl,
+			.frontend_attach  = cxusb_nano2_frontend_attach,
+			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		}},
+		},
+	},
+
+	.power_ctrl       = cxusb_nano2_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_map_table     = rc_map_dvico_portable_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_dvico_portable_table),
+		.rc_query         = cxusb_bluebird2_rc_query,
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "DViCO FusionHDTV DVB-T NANO2",
+			{ NULL },
+			{ &cxusb_table[14], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl          = DEVICE_SPECIFIC,
+	.firmware          = "dvb-usb-bluebird-02.fw",
+	.download_firmware = bluebird_patch_dvico_firmware_download,
+	.identify_state    = bluebird_fx2_identify_state,
+
+	.size_of_priv      = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = cxusb_streaming_ctrl,
+			.frontend_attach  = cxusb_nano2_frontend_attach,
+			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		}},
+		},
+	},
+
+	.power_ctrl       = cxusb_nano2_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_map_table     = rc_map_dvico_portable_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_dvico_portable_table),
+		.rc_query         = cxusb_rc_query,
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "DViCO FusionHDTV DVB-T NANO2 w/o firmware",
+			{ &cxusb_table[14], NULL },
+			{ &cxusb_table[15], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties cxusb_aver_a868r_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = CYPRESS_FX2,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = cxusb_aver_streaming_ctrl,
+			.frontend_attach  = cxusb_aver_lgdt3303_frontend_attach,
+			.tuner_attach     = cxusb_mxl5003s_tuner_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x04,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		}},
+		},
+	},
+	.power_ctrl       = cxusb_aver_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "AVerMedia AVerTVHD Volar (A868R)",
+			{ NULL },
+			{ &cxusb_table[16], NULL },
+		},
+	}
+};
+
+static
+struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = CYPRESS_FX2,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.size_of_priv    = sizeof(struct dib0700_adapter_state),
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl  = cxusb_streaming_ctrl,
+			.frontend_attach = cxusb_dualdig4_rev2_frontend_attach,
+			.tuner_attach    = cxusb_dualdig4_rev2_tuner_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 7,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+		},
+	},
+
+	.power_ctrl       = cxusb_bluebird_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_map_table     = rc_map_dvico_mce_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_dvico_mce_table),
+		.rc_query         = cxusb_rc_query,
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2)",
+			{ NULL },
+			{ &cxusb_table[17], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = CYPRESS_FX2,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = cxusb_d680_dmb_streaming_ctrl,
+			.frontend_attach  = cxusb_d680_dmb_frontend_attach,
+			.tuner_attach     = cxusb_d680_dmb_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		}},
+		},
+	},
+
+	.power_ctrl       = cxusb_d680_dmb_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_map_table     = rc_map_d680_dmb_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_d680_dmb_table),
+		.rc_query         = cxusb_d680_dmb_rc_query,
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{
+			"Conexant DMB-TH Stick",
+			{ NULL },
+			{ &cxusb_table[18], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = CYPRESS_FX2,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = cxusb_d680_dmb_streaming_ctrl,
+			.frontend_attach  = cxusb_mygica_d689_frontend_attach,
+			.tuner_attach     = cxusb_mygica_d689_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		}},
+		},
+	},
+
+	.power_ctrl       = cxusb_d680_dmb_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_map_table     = rc_map_d680_dmb_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_d680_dmb_table),
+		.rc_query         = cxusb_d680_dmb_rc_query,
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{
+			"Mygica D689 DMB-TH",
+			{ NULL },
+			{ &cxusb_table[19], NULL },
+		},
+	}
+};
+
+static struct usb_driver cxusb_driver = {
+	.name		= "dvb_usb_cxusb",
+	.probe		= cxusb_probe,
+	.disconnect     = dvb_usb_device_exit,
+	.id_table	= cxusb_table,
+};
+
+module_usb_driver(cxusb_driver);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
+MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
+MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design");
+MODULE_VERSION("1.0-alpha");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/cxusb.h b/drivers/media/usb/dvb-usb/cxusb.h
new file mode 100644
index 0000000..1a51eaf
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/cxusb.h
@@ -0,0 +1,35 @@
+#ifndef _DVB_USB_CXUSB_H_
+#define _DVB_USB_CXUSB_H_
+
+#define DVB_USB_LOG_PREFIX "cxusb"
+#include "dvb-usb.h"
+
+/* usb commands - some of it are guesses, don't have a reference yet */
+#define CMD_BLUEBIRD_GPIO_RW 0x05
+
+#define CMD_I2C_WRITE     0x08
+#define CMD_I2C_READ      0x09
+
+#define CMD_GPIO_READ     0x0d
+#define CMD_GPIO_WRITE    0x0e
+#define     GPIO_TUNER         0x02
+
+#define CMD_POWER_OFF     0xdc
+#define CMD_POWER_ON      0xde
+
+#define CMD_STREAMING_ON  0x36
+#define CMD_STREAMING_OFF 0x37
+
+#define CMD_AVER_STREAM_ON  0x18
+#define CMD_AVER_STREAM_OFF 0x19
+
+#define CMD_GET_IR_CODE   0x47
+
+#define CMD_ANALOG        0x50
+#define CMD_DIGITAL       0x51
+
+struct cxusb_state {
+	u8 gpio_write_state[3];
+};
+
+#endif
diff --git a/drivers/media/usb/dvb-usb/dib0700.h b/drivers/media/usb/dvb-usb/dib0700.h
new file mode 100644
index 0000000..7de125c
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dib0700.h
@@ -0,0 +1,75 @@
+/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
+ *
+ *	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, version 2.
+ *
+ *  Copyright (C) 2005-6 DiBcom, SA
+ */
+#ifndef _DIB0700_H_
+#define _DIB0700_H_
+
+#define DVB_USB_LOG_PREFIX "dib0700"
+#include "dvb-usb.h"
+
+#include "dib07x0.h"
+
+extern int dvb_usb_dib0700_debug;
+#define deb_info(args...)   dprintk(dvb_usb_dib0700_debug,0x01,args)
+#define deb_fw(args...)     dprintk(dvb_usb_dib0700_debug,0x02,args)
+#define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args)
+#define deb_data(args...)   dprintk(dvb_usb_dib0700_debug,0x08,args)
+
+#define REQUEST_SET_USB_XFER_LEN    0x0 /* valid only for firmware version */
+					/* higher than 1.21 */
+#define REQUEST_I2C_READ            0x2
+#define REQUEST_I2C_WRITE           0x3
+#define REQUEST_POLL_RC             0x4 /* deprecated in firmware v1.20 */
+#define REQUEST_JUMPRAM             0x8
+#define REQUEST_SET_CLOCK           0xB
+#define REQUEST_SET_GPIO            0xC
+#define REQUEST_ENABLE_VIDEO        0xF
+	// 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog)
+	// 2 Byte: MPEG2 mode:  4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1)
+	// 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines)    4LSB(     "                "           )
+#define REQUEST_SET_I2C_PARAM       0x10
+#define REQUEST_SET_RC              0x11
+#define REQUEST_NEW_I2C_READ        0x12
+#define REQUEST_NEW_I2C_WRITE       0x13
+#define REQUEST_GET_VERSION         0x15
+
+struct dib0700_state {
+	u8 channel_state;
+	u16 mt2060_if1[2];
+	u8 rc_toggle;
+	u8 rc_counter;
+	u8 is_dib7000pc;
+	u8 fw_use_new_i2c_api;
+	u8 disable_streaming_master_mode;
+	u32 fw_version;
+	u32 nb_packet_buffer_size;
+	int (*read_status)(struct dvb_frontend *, fe_status_t *);
+	int (*sleep)(struct dvb_frontend* fe);
+	u8 buf[255];
+};
+
+extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
+			       u32 *romversion, u32 *ramversion, u32 *fwtype);
+extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val);
+extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3);
+extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen);
+extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw);
+extern int dib0700_rc_setup(struct dvb_usb_device *d);
+extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
+extern struct i2c_algorithm dib0700_i2c_algo;
+extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
+			struct dvb_usb_device_description **desc, int *cold);
+extern int dib0700_change_protocol(struct rc_dev *dev, u64 rc_type);
+extern int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz);
+
+extern int dib0700_device_count;
+extern int dvb_usb_dib0700_ir_proto;
+extern struct dvb_usb_device_properties dib0700_devices[];
+extern struct usb_device_id dib0700_usb_id_table[];
+
+#endif
diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c
new file mode 100644
index 0000000..ef87229
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dib0700_core.c
@@ -0,0 +1,845 @@
+/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
+ *
+ *	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, version 2.
+ *
+ *  Copyright (C) 2005-6 DiBcom, SA
+ */
+#include "dib0700.h"
+
+/* debug */
+int dvb_usb_dib0700_debug;
+module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
+
+static int nb_packet_buffer_size = 21;
+module_param(nb_packet_buffer_size, int, 0644);
+MODULE_PARM_DESC(nb_packet_buffer_size,
+	"Set the dib0700 driver data buffer size. This parameter "
+	"corresponds to the number of TS packets. The actual size of "
+	"the data buffer corresponds to this parameter "
+	"multiplied by 188 (default: 21)");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+
+int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
+			u32 *romversion, u32 *ramversion, u32 *fwtype)
+{
+	struct dib0700_state *st = d->priv;
+	int ret;
+
+	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+		err("could not acquire lock");
+		return -EINTR;
+	}
+
+	ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
+				  REQUEST_GET_VERSION,
+				  USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+				  st->buf, 16, USB_CTRL_GET_TIMEOUT);
+	if (hwversion != NULL)
+		*hwversion  = (st->buf[0] << 24)  | (st->buf[1] << 16)  |
+			(st->buf[2] << 8)  | st->buf[3];
+	if (romversion != NULL)
+		*romversion = (st->buf[4] << 24)  | (st->buf[5] << 16)  |
+			(st->buf[6] << 8)  | st->buf[7];
+	if (ramversion != NULL)
+		*ramversion = (st->buf[8] << 24)  | (st->buf[9] << 16)  |
+			(st->buf[10] << 8) | st->buf[11];
+	if (fwtype != NULL)
+		*fwtype     = (st->buf[12] << 24) | (st->buf[13] << 16) |
+			(st->buf[14] << 8) | st->buf[15];
+	mutex_unlock(&d->usb_mutex);
+	return ret;
+}
+
+/* expecting rx buffer: request data[0] data[1] ... data[2] */
+static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
+{
+	int status;
+
+	deb_data(">>> ");
+	debug_dump(tx, txlen, deb_data);
+
+	status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0),
+		tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen,
+		USB_CTRL_GET_TIMEOUT);
+
+	if (status != txlen)
+		deb_data("ep 0 write error (status = %d, len: %d)\n",status,txlen);
+
+	return status < 0 ? status : 0;
+}
+
+/* expecting tx buffer: request data[0] ... data[n] (n <= 4) */
+int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
+{
+	u16 index, value;
+	int status;
+
+	if (txlen < 2) {
+		err("tx buffer length is smaller than 2. Makes no sense.");
+		return -EINVAL;
+	}
+	if (txlen > 4) {
+		err("tx buffer length is larger than 4. Not supported.");
+		return -EINVAL;
+	}
+
+	deb_data(">>> ");
+	debug_dump(tx,txlen,deb_data);
+
+	value = ((txlen - 2) << 8) | tx[1];
+	index = 0;
+	if (txlen > 2)
+		index |= (tx[2] << 8);
+	if (txlen > 3)
+		index |= tx[3];
+
+	status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0],
+			USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen,
+			USB_CTRL_GET_TIMEOUT);
+
+	if (status < 0)
+		deb_info("ep 0 read error (status = %d)\n",status);
+
+	deb_data("<<< ");
+	debug_dump(rx, rxlen, deb_data);
+
+	return status; /* length in case of success */
+}
+
+int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
+{
+	struct dib0700_state *st = d->priv;
+	int ret;
+
+	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+		err("could not acquire lock");
+		return -EINTR;
+	}
+
+	st->buf[0] = REQUEST_SET_GPIO;
+	st->buf[1] = gpio;
+	st->buf[2] = ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6);
+
+	ret = dib0700_ctrl_wr(d, st->buf, 3);
+
+	mutex_unlock(&d->usb_mutex);
+	return ret;
+}
+
+static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
+{
+	struct dib0700_state *st = d->priv;
+	int ret;
+
+	if (st->fw_version >= 0x10201) {
+		if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+			err("could not acquire lock");
+			return -EINTR;
+		}
+
+		st->buf[0] = REQUEST_SET_USB_XFER_LEN;
+		st->buf[1] = (nb_ts_packets >> 8) & 0xff;
+		st->buf[2] = nb_ts_packets & 0xff;
+
+		deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
+
+		ret = dib0700_ctrl_wr(d, st->buf, 3);
+		mutex_unlock(&d->usb_mutex);
+	} else {
+		deb_info("this firmware does not allow to change the USB xfer len\n");
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+/*
+ * I2C master xfer function (supported in 1.20 firmware)
+ */
+static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
+				int num)
+{
+	/* The new i2c firmware messages are more reliable and in particular
+	   properly support i2c read calls not preceded by a write */
+
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct dib0700_state *st = d->priv;
+	uint8_t bus_mode = 1;  /* 0=eeprom bus, 1=frontend bus */
+	uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */
+	uint8_t en_start = 0;
+	uint8_t en_stop = 0;
+	int result, i;
+
+	/* Ensure nobody else hits the i2c bus while we're sending our
+	   sequence of messages, (such as the remote control thread) */
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EINTR;
+
+	for (i = 0; i < num; i++) {
+		if (i == 0) {
+			/* First message in the transaction */
+			en_start = 1;
+		} else if (!(msg[i].flags & I2C_M_NOSTART)) {
+			/* Device supports repeated-start */
+			en_start = 1;
+		} else {
+			/* Not the first packet and device doesn't support
+			   repeated start */
+			en_start = 0;
+		}
+		if (i == (num - 1)) {
+			/* Last message in the transaction */
+			en_stop = 1;
+		}
+
+		if (msg[i].flags & I2C_M_RD) {
+			/* Read request */
+			u16 index, value;
+			uint8_t i2c_dest;
+
+			i2c_dest = (msg[i].addr << 1);
+			value = ((en_start << 7) | (en_stop << 6) |
+				 (msg[i].len & 0x3F)) << 8 | i2c_dest;
+			/* I2C ctrl + FE bus; */
+			index = ((gen_mode << 6) & 0xC0) |
+				((bus_mode << 4) & 0x30);
+
+			result = usb_control_msg(d->udev,
+						 usb_rcvctrlpipe(d->udev, 0),
+						 REQUEST_NEW_I2C_READ,
+						 USB_TYPE_VENDOR | USB_DIR_IN,
+						 value, index, msg[i].buf,
+						 msg[i].len,
+						 USB_CTRL_GET_TIMEOUT);
+			if (result < 0) {
+				deb_info("i2c read error (status = %d)\n", result);
+				break;
+			}
+
+			deb_data("<<< ");
+			debug_dump(msg[i].buf, msg[i].len, deb_data);
+
+		} else {
+			/* Write request */
+			if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+				err("could not acquire lock");
+				mutex_unlock(&d->i2c_mutex);
+				return -EINTR;
+			}
+			st->buf[0] = REQUEST_NEW_I2C_WRITE;
+			st->buf[1] = msg[i].addr << 1;
+			st->buf[2] = (en_start << 7) | (en_stop << 6) |
+				(msg[i].len & 0x3F);
+			/* I2C ctrl + FE bus; */
+			st->buf[3] = ((gen_mode << 6) & 0xC0) |
+				 ((bus_mode << 4) & 0x30);
+			/* The Actual i2c payload */
+			memcpy(&st->buf[4], msg[i].buf, msg[i].len);
+
+			deb_data(">>> ");
+			debug_dump(st->buf, msg[i].len + 4, deb_data);
+
+			result = usb_control_msg(d->udev,
+						 usb_sndctrlpipe(d->udev, 0),
+						 REQUEST_NEW_I2C_WRITE,
+						 USB_TYPE_VENDOR | USB_DIR_OUT,
+						 0, 0, st->buf, msg[i].len + 4,
+						 USB_CTRL_GET_TIMEOUT);
+			mutex_unlock(&d->usb_mutex);
+			if (result < 0) {
+				deb_info("i2c write error (status = %d)\n", result);
+				break;
+			}
+		}
+	}
+	mutex_unlock(&d->i2c_mutex);
+	return i;
+}
+
+/*
+ * I2C master xfer function (pre-1.20 firmware)
+ */
+static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
+				   struct i2c_msg *msg, int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct dib0700_state *st = d->priv;
+	int i,len;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EINTR;
+	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+		err("could not acquire lock");
+		mutex_unlock(&d->i2c_mutex);
+		return -EINTR;
+	}
+
+	for (i = 0; i < num; i++) {
+		/* fill in the address */
+		st->buf[1] = msg[i].addr << 1;
+		/* fill the buffer */
+		memcpy(&st->buf[2], msg[i].buf, msg[i].len);
+
+		/* write/read request */
+		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+			st->buf[0] = REQUEST_I2C_READ;
+			st->buf[1] |= 1;
+
+			/* special thing in the current firmware: when length is zero the read-failed */
+			len = dib0700_ctrl_rd(d, st->buf, msg[i].len + 2,
+					msg[i+1].buf, msg[i+1].len);
+			if (len <= 0) {
+				deb_info("I2C read failed on address 0x%02x\n",
+						msg[i].addr);
+				break;
+			}
+
+			msg[i+1].len = len;
+
+			i++;
+		} else {
+			st->buf[0] = REQUEST_I2C_WRITE;
+			if (dib0700_ctrl_wr(d, st->buf, msg[i].len + 2) < 0)
+				break;
+		}
+	}
+	mutex_unlock(&d->usb_mutex);
+	mutex_unlock(&d->i2c_mutex);
+
+	return i;
+}
+
+static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+			    int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct dib0700_state *st = d->priv;
+
+	if (st->fw_use_new_i2c_api == 1) {
+		/* User running at least fw 1.20 */
+		return dib0700_i2c_xfer_new(adap, msg, num);
+	} else {
+		/* Use legacy calls */
+		return dib0700_i2c_xfer_legacy(adap, msg, num);
+	}
+}
+
+static u32 dib0700_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+struct i2c_algorithm dib0700_i2c_algo = {
+	.master_xfer   = dib0700_i2c_xfer,
+	.functionality = dib0700_i2c_func,
+};
+
+int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
+			struct dvb_usb_device_description **desc, int *cold)
+{
+	s16 ret;
+	u8 *b;
+
+	b = kmalloc(16, GFP_KERNEL);
+	if (!b)
+		return	-ENOMEM;
+
+
+	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+		REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, 16, USB_CTRL_GET_TIMEOUT);
+
+	deb_info("FW GET_VERSION length: %d\n",ret);
+
+	*cold = ret <= 0;
+	deb_info("cold: %d\n", *cold);
+
+	kfree(b);
+	return 0;
+}
+
+static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
+	u8 pll_src, u8 pll_range, u8 clock_gpio3, u16 pll_prediv,
+	u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
+{
+	struct dib0700_state *st = d->priv;
+	int ret;
+
+	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+		err("could not acquire lock");
+		return -EINTR;
+	}
+
+	st->buf[0] = REQUEST_SET_CLOCK;
+	st->buf[1] = (en_pll << 7) | (pll_src << 6) |
+		(pll_range << 5) | (clock_gpio3 << 4);
+	st->buf[2] = (pll_prediv >> 8)  & 0xff; /* MSB */
+	st->buf[3] =  pll_prediv        & 0xff; /* LSB */
+	st->buf[4] = (pll_loopdiv >> 8) & 0xff; /* MSB */
+	st->buf[5] =  pll_loopdiv       & 0xff; /* LSB */
+	st->buf[6] = (free_div >> 8)    & 0xff; /* MSB */
+	st->buf[7] =  free_div          & 0xff; /* LSB */
+	st->buf[8] = (dsuScaler >> 8)   & 0xff; /* MSB */
+	st->buf[9] =  dsuScaler         & 0xff; /* LSB */
+
+	ret = dib0700_ctrl_wr(d, st->buf, 10);
+	mutex_unlock(&d->usb_mutex);
+
+	return ret;
+}
+
+int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz)
+{
+	struct dib0700_state *st = d->priv;
+	u16 divider;
+	int ret;
+
+	if (scl_kHz == 0)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+		err("could not acquire lock");
+		return -EINTR;
+	}
+
+	st->buf[0] = REQUEST_SET_I2C_PARAM;
+	divider = (u16) (30000 / scl_kHz);
+	st->buf[1] = 0;
+	st->buf[2] = (u8) (divider >> 8);
+	st->buf[3] = (u8) (divider & 0xff);
+	divider = (u16) (72000 / scl_kHz);
+	st->buf[4] = (u8) (divider >> 8);
+	st->buf[5] = (u8) (divider & 0xff);
+	divider = (u16) (72000 / scl_kHz); /* clock: 72MHz */
+	st->buf[6] = (u8) (divider >> 8);
+	st->buf[7] = (u8) (divider & 0xff);
+
+	deb_info("setting I2C speed: %04x %04x %04x (%d kHz).",
+		(st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) |
+		st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz);
+
+	ret = dib0700_ctrl_wr(d, st->buf, 8);
+	mutex_unlock(&d->usb_mutex);
+
+	return ret;
+}
+
+
+int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3)
+{
+	switch (clk_MHz) {
+		case 72: dib0700_set_clock(d, 1, 0, 1, clock_out_gp3, 2, 24, 0, 0x4c); break;
+		default: return -EINVAL;
+	}
+	return 0;
+}
+
+static int dib0700_jumpram(struct usb_device *udev, u32 address)
+{
+	int ret = 0, actlen;
+	u8 *buf;
+
+	buf = kmalloc(8, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+	buf[0] = REQUEST_JUMPRAM;
+	buf[1] = 0;
+	buf[2] = 0;
+	buf[3] = 0;
+	buf[4] = (address >> 24) & 0xff;
+	buf[5] = (address >> 16) & 0xff;
+	buf[6] = (address >> 8)  & 0xff;
+	buf[7] =  address        & 0xff;
+
+	if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) {
+		deb_fw("jumpram to 0x%x failed\n",address);
+		goto out;
+	}
+	if (actlen != 8) {
+		deb_fw("jumpram to 0x%x failed\n",address);
+		ret = -EIO;
+		goto out;
+	}
+out:
+	kfree(buf);
+	return ret;
+}
+
+int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw)
+{
+	struct hexline hx;
+	int pos = 0, ret, act_len, i, adap_num;
+	u8 *buf;
+	u32 fw_version;
+
+	buf = kmalloc(260, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) {
+		deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",
+				hx.addr, hx.len, hx.chk);
+
+		buf[0] = hx.len;
+		buf[1] = (hx.addr >> 8) & 0xff;
+		buf[2] =  hx.addr       & 0xff;
+		buf[3] = hx.type;
+		memcpy(&buf[4],hx.data,hx.len);
+		buf[4+hx.len] = hx.chk;
+
+		ret = usb_bulk_msg(udev,
+			usb_sndbulkpipe(udev, 0x01),
+			buf,
+			hx.len + 5,
+			&act_len,
+			1000);
+
+		if (ret < 0) {
+			err("firmware download failed at %d with %d",pos,ret);
+			goto out;
+		}
+	}
+
+	if (ret == 0) {
+		/* start the firmware */
+		if ((ret = dib0700_jumpram(udev, 0x70000000)) == 0) {
+			info("firmware started successfully.");
+			msleep(500);
+		}
+	} else
+		ret = -EIO;
+
+	/* the number of ts packet has to be at least 1 */
+	if (nb_packet_buffer_size < 1)
+		nb_packet_buffer_size = 1;
+
+	/* get the fimware version */
+	usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+				  REQUEST_GET_VERSION,
+				  USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+				  buf, 16, USB_CTRL_GET_TIMEOUT);
+	fw_version = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11];
+
+	/* set the buffer size - DVB-USB is allocating URB buffers
+	 * only after the firwmare download was successful */
+	for (i = 0; i < dib0700_device_count; i++) {
+		for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters;
+				adap_num++) {
+			if (fw_version >= 0x10201) {
+				dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 188*nb_packet_buffer_size;
+			} else {
+				/* for fw version older than 1.20.1,
+				 * the buffersize has to be n times 512 */
+				dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512;
+				if (dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize < 512)
+					dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 512;
+			}
+		}
+	}
+out:
+	kfree(buf);
+	return ret;
+}
+
+int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	struct dib0700_state *st = adap->dev->priv;
+	int ret;
+
+	if ((onoff != 0) && (st->fw_version >= 0x10201)) {
+		/* for firmware later than 1.20.1,
+		 * the USB xfer length can be set  */
+		ret = dib0700_set_usb_xfer_len(adap->dev,
+			st->nb_packet_buffer_size);
+		if (ret < 0) {
+			deb_info("can not set the USB xfer len\n");
+			return ret;
+		}
+	}
+
+	if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) {
+		err("could not acquire lock");
+		return -EINTR;
+	}
+
+	st->buf[0] = REQUEST_ENABLE_VIDEO;
+	/* this bit gives a kind of command,
+	 * rather than enabling something or not */
+	st->buf[1] = (onoff << 4) | 0x00;
+
+	if (st->disable_streaming_master_mode == 1)
+		st->buf[2] = 0x00;
+	else
+		st->buf[2] = 0x01 << 4; /* Master mode */
+
+	st->buf[3] = 0x00;
+
+	deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);
+
+	st->channel_state &= ~0x3;
+	if ((adap->fe_adap[0].stream.props.endpoint != 2)
+			&& (adap->fe_adap[0].stream.props.endpoint != 3)) {
+		deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->fe_adap[0].stream.props.endpoint);
+		if (onoff)
+			st->channel_state |=	1 << (adap->id);
+		else
+			st->channel_state |=	1 << ~(adap->id);
+	} else {
+		if (onoff)
+			st->channel_state |=	1 << (adap->fe_adap[0].stream.props.endpoint-2);
+		else
+			st->channel_state |=	1 << (3-adap->fe_adap[0].stream.props.endpoint);
+	}
+
+	st->buf[2] |= st->channel_state;
+
+	deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]);
+
+	ret = dib0700_ctrl_wr(adap->dev, st->buf, 4);
+	mutex_unlock(&adap->dev->usb_mutex);
+
+	return ret;
+}
+
+int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
+{
+	struct dvb_usb_device *d = rc->priv;
+	struct dib0700_state *st = d->priv;
+	int new_proto, ret;
+
+	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+		err("could not acquire lock");
+		return -EINTR;
+	}
+
+	st->buf[0] = REQUEST_SET_RC;
+	st->buf[1] = 0;
+	st->buf[2] = 0;
+
+	/* Set the IR mode */
+	if (rc_type == RC_TYPE_RC5)
+		new_proto = 1;
+	else if (rc_type == RC_TYPE_NEC)
+		new_proto = 0;
+	else if (rc_type == RC_TYPE_RC6) {
+		if (st->fw_version < 0x10200) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		new_proto = 2;
+	} else {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	st->buf[1] = new_proto;
+
+	ret = dib0700_ctrl_wr(d, st->buf, 3);
+	if (ret < 0) {
+		err("ir protocol setup failed");
+		goto out;
+	}
+
+	d->props.rc.core.protocol = rc_type;
+
+out:
+	mutex_unlock(&d->usb_mutex);
+	return ret;
+}
+
+/* Number of keypresses to ignore before start repeating */
+#define RC_REPEAT_DELAY_V1_20 10
+
+/* This is the structure of the RC response packet starting in firmware 1.20 */
+struct dib0700_rc_response {
+	u8 report_id;
+	u8 data_state;
+	union {
+		u16 system16;
+		struct {
+			u8 not_system;
+			u8 system;
+		};
+	};
+	u8 data;
+	u8 not_data;
+};
+#define RC_MSG_SIZE_V1_20 6
+
+static void dib0700_rc_urb_completion(struct urb *purb)
+{
+	struct dvb_usb_device *d = purb->context;
+	struct dib0700_rc_response *poll_reply;
+	u32 uninitialized_var(keycode);
+	u8 toggle;
+
+	deb_info("%s()\n", __func__);
+	if (d->rc_dev == NULL) {
+		/* This will occur if disable_rc_polling=1 */
+		kfree(purb->transfer_buffer);
+		usb_free_urb(purb);
+		return;
+	}
+
+	poll_reply = purb->transfer_buffer;
+
+	if (purb->status < 0) {
+		deb_info("discontinuing polling\n");
+		kfree(purb->transfer_buffer);
+		usb_free_urb(purb);
+		return;
+	}
+
+	if (purb->actual_length != RC_MSG_SIZE_V1_20) {
+		deb_info("malformed rc msg size=%d\n", purb->actual_length);
+		goto resubmit;
+	}
+
+	deb_data("IR ID = %02X state = %02X System = %02X %02X Cmd = %02X %02X (len %d)\n",
+		 poll_reply->report_id, poll_reply->data_state,
+		 poll_reply->system, poll_reply->not_system,
+		 poll_reply->data, poll_reply->not_data,
+		 purb->actual_length);
+
+	switch (d->props.rc.core.protocol) {
+	case RC_TYPE_NEC:
+		toggle = 0;
+
+		/* NEC protocol sends repeat code as 0 0 0 FF */
+		if ((poll_reply->system == 0x00) && (poll_reply->data == 0x00)
+		    && (poll_reply->not_data == 0xff)) {
+			poll_reply->data_state = 2;
+			break;
+		}
+
+		if ((poll_reply->system ^ poll_reply->not_system) != 0xff) {
+			deb_data("NEC extended protocol\n");
+			/* NEC extended code - 24 bits */
+			keycode = be16_to_cpu(poll_reply->system16) << 8 | poll_reply->data;
+		} else {
+			deb_data("NEC normal protocol\n");
+			/* normal NEC code - 16 bits */
+			keycode = poll_reply->system << 8 | poll_reply->data;
+		}
+
+		break;
+	default:
+		deb_data("RC5 protocol\n");
+		/* RC5 Protocol */
+		toggle = poll_reply->report_id;
+		keycode = poll_reply->system << 8 | poll_reply->data;
+
+		break;
+	}
+
+	if ((poll_reply->data + poll_reply->not_data) != 0xff) {
+		/* Key failed integrity check */
+		err("key failed integrity check: %04x %02x %02x",
+		    poll_reply->system,
+		    poll_reply->data, poll_reply->not_data);
+		goto resubmit;
+	}
+
+	rc_keydown(d->rc_dev, keycode, toggle);
+
+resubmit:
+	/* Clean the buffer before we requeue */
+	memset(purb->transfer_buffer, 0, RC_MSG_SIZE_V1_20);
+
+	/* Requeue URB */
+	usb_submit_urb(purb, GFP_ATOMIC);
+}
+
+int dib0700_rc_setup(struct dvb_usb_device *d)
+{
+	struct dib0700_state *st = d->priv;
+	struct urb *purb;
+	int ret;
+
+	/* Poll-based. Don't initialize bulk mode */
+	if (st->fw_version < 0x10200)
+		return 0;
+
+	/* Starting in firmware 1.20, the RC info is provided on a bulk pipe */
+	purb = usb_alloc_urb(0, GFP_KERNEL);
+	if (purb == NULL) {
+		err("rc usb alloc urb failed");
+		return -ENOMEM;
+	}
+
+	purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL);
+	if (purb->transfer_buffer == NULL) {
+		err("rc kzalloc failed");
+		usb_free_urb(purb);
+		return -ENOMEM;
+	}
+
+	purb->status = -EINPROGRESS;
+	usb_fill_bulk_urb(purb, d->udev, usb_rcvbulkpipe(d->udev, 1),
+			  purb->transfer_buffer, RC_MSG_SIZE_V1_20,
+			  dib0700_rc_urb_completion, d);
+
+	ret = usb_submit_urb(purb, GFP_ATOMIC);
+	if (ret) {
+		err("rc submit urb failed");
+		kfree(purb->transfer_buffer);
+		usb_free_urb(purb);
+	}
+
+	return ret;
+}
+
+static int dib0700_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	int i;
+	struct dvb_usb_device *dev;
+
+	for (i = 0; i < dib0700_device_count; i++)
+		if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE,
+		    &dev, adapter_nr) == 0) {
+			struct dib0700_state *st = dev->priv;
+			u32 hwversion, romversion, fw_version, fwtype;
+
+			dib0700_get_version(dev, &hwversion, &romversion,
+				&fw_version, &fwtype);
+
+			deb_info("Firmware version: %x, %d, 0x%x, %d\n",
+				hwversion, romversion, fw_version, fwtype);
+
+			st->fw_version = fw_version;
+			st->nb_packet_buffer_size = (u32)nb_packet_buffer_size;
+
+			/* Disable polling mode on newer firmwares */
+			if (st->fw_version >= 0x10200)
+				dev->props.rc.core.bulk_mode = true;
+			else
+				dev->props.rc.core.bulk_mode = false;
+
+			dib0700_rc_setup(dev);
+
+			return 0;
+		}
+
+	return -ENODEV;
+}
+
+static struct usb_driver dib0700_driver = {
+	.name       = "dvb_usb_dib0700",
+	.probe      = dib0700_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table   = dib0700_usb_id_table,
+};
+
+module_usb_driver(dib0700_driver);
+
+MODULE_FIRMWARE("dvb-usb-dib0700-1.20.fw");
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for devices based on DiBcom DiB0700 - USB bridge");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
new file mode 100644
index 0000000..510001d
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -0,0 +1,4813 @@
+/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
+ *
+ *	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, version 2.
+ *
+ *  Copyright (C) 2005-9 DiBcom, SA et al
+ */
+#include "dib0700.h"
+
+#include "dib3000mc.h"
+#include "dib7000m.h"
+#include "dib7000p.h"
+#include "dib8000.h"
+#include "dib9000.h"
+#include "mt2060.h"
+#include "mt2266.h"
+#include "tuner-xc2028.h"
+#include "xc5000.h"
+#include "xc4000.h"
+#include "s5h1411.h"
+#include "dib0070.h"
+#include "dib0090.h"
+#include "lgdt3305.h"
+#include "mxl5007t.h"
+
+static int force_lna_activation;
+module_param(force_lna_activation, int, 0644);
+MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), "
+		"if applicable for the device (default: 0=automatic/off).");
+
+struct dib0700_adapter_state {
+	int (*set_param_save) (struct dvb_frontend *);
+	const struct firmware *frontend_firmware;
+};
+
+/* Hauppauge Nova-T 500 (aka Bristol)
+ *  has a LNA on GPIO0 which is enabled by setting 1 */
+static struct mt2060_config bristol_mt2060_config[2] = {
+	{
+		.i2c_address = 0x60,
+		.clock_out   = 3,
+	}, {
+		.i2c_address = 0x61,
+	}
+};
+
+
+static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = {
+	.band_caps = BAND_VHF | BAND_UHF,
+	.setup     = (1 << 8) | (5 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (2 << 0),
+
+	.agc1_max = 42598,
+	.agc1_min = 17694,
+	.agc2_max = 45875,
+	.agc2_min = 0,
+
+	.agc1_pt1 = 0,
+	.agc1_pt2 = 59,
+
+	.agc1_slope1 = 0,
+	.agc1_slope2 = 69,
+
+	.agc2_pt1 = 0,
+	.agc2_pt2 = 59,
+
+	.agc2_slope1 = 111,
+	.agc2_slope2 = 28,
+};
+
+static struct dib3000mc_config bristol_dib3000mc_config[2] = {
+	{	.agc          = &bristol_dib3000p_mt2060_agc_config,
+		.max_time     = 0x196,
+		.ln_adc_level = 0x1cc7,
+		.output_mpeg2_in_188_bytes = 1,
+	},
+	{	.agc          = &bristol_dib3000p_mt2060_agc_config,
+		.max_time     = 0x196,
+		.ln_adc_level = 0x1cc7,
+		.output_mpeg2_in_188_bytes = 1,
+	}
+};
+
+static int bristol_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_state *st = adap->dev->priv;
+	if (adap->id == 0) {
+		dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 0); msleep(10);
+		dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 1); msleep(10);
+		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10);
+		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10);
+
+		if (force_lna_activation)
+			dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+		else
+			dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0);
+
+		if (dib3000mc_i2c_enumeration(&adap->dev->i2c_adap, 2, DEFAULT_DIB3000P_I2C_ADDRESS, bristol_dib3000mc_config) != 0) {
+			dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10);
+			return -ENODEV;
+		}
+	}
+	st->mt2060_if1[adap->id] = 1220;
+	return (adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap,
+		(10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0;
+}
+
+static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = 0x50, .flags = 0,        .buf = &adrs, .len = 1 },
+		{ .addr = 0x50, .flags = I2C_M_RD, .buf = pval,  .len = 1 },
+	};
+	if (i2c_transfer(adap, msg, 2) != 2) return -EREMOTEIO;
+	return 0;
+}
+
+static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
+	struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe_adap[0].fe, 1);
+	s8 a;
+	int if1=1220;
+	if (adap->dev->udev->descriptor.idVendor  == cpu_to_le16(USB_VID_HAUPPAUGE) &&
+		adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_500_2)) {
+		if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a;
+	}
+	return dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c,
+			  &bristol_mt2060_config[adap->id], if1) == NULL ?
+			  -ENODEV : 0;
+}
+
+/* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */
+
+/* MT226x */
+static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = {
+	{
+		BAND_UHF,
+
+		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
+		* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+		(0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8)
+	    | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+
+		1130,
+		21,
+
+		0,
+		118,
+
+		0,
+		3530,
+		1,
+		0,
+
+		65535,
+		33770,
+		65535,
+		23592,
+
+		0,
+		62,
+		255,
+		64,
+		64,
+		132,
+		192,
+		80,
+		80,
+
+		17,
+		27,
+		23,
+		51,
+
+		1,
+	}, {
+		BAND_VHF | BAND_LBAND,
+
+		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
+		* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+		(0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8)
+	    | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
+
+		2372,
+		21,
+
+		0,
+		118,
+
+		0,
+		3530,
+		1,
+		0,
+
+		65535,
+		0,
+		65535,
+		23592,
+
+		0,
+		128,
+		128,
+		128,
+		0,
+		128,
+		253,
+		81,
+		0,
+
+		17,
+		27,
+		23,
+		51,
+
+		1,
+	}
+};
+
+static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = {
+	60000, 30000,
+	1, 8, 3, 1, 0,
+	0, 0, 1, 1, 2,
+	(3 << 14) | (1 << 12) | (524 << 0),
+	0,
+	20452225,
+};
+
+static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = {
+	{	.output_mpeg2_in_188_bytes = 1,
+		.hostbus_diversity = 1,
+		.tuner_is_baseband = 1,
+
+		.agc_config_count = 2,
+		.agc = stk7700d_7000p_mt2266_agc_config,
+		.bw  = &stk7700d_mt2266_pll_config,
+
+		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+		.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+	},
+	{	.output_mpeg2_in_188_bytes = 1,
+		.hostbus_diversity = 1,
+		.tuner_is_baseband = 1,
+
+		.agc_config_count = 2,
+		.agc = stk7700d_7000p_mt2266_agc_config,
+		.bw  = &stk7700d_mt2266_pll_config,
+
+		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+		.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+	}
+};
+
+static struct mt2266_config stk7700d_mt2266_config[2] = {
+	{	.i2c_address = 0x60
+	},
+	{	.i2c_address = 0x60
+	}
+};
+
+static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	if (adap->id == 0) {
+		dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+		msleep(10);
+		dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+		dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+		dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+		msleep(10);
+		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+		msleep(10);
+		if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+					     stk7700d_dib7000p_mt2266_config)
+		    != 0) {
+			err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
+			return -ENODEV;
+		}
+	}
+
+	adap->fe_adap[0].fe =
+		dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
+			   0x80 + (adap->id << 1),
+			   &stk7700d_dib7000p_mt2266_config[adap->id]);
+
+	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	if (adap->id == 0) {
+		dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+		msleep(10);
+		dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+		dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+		dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+		msleep(10);
+		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+		msleep(10);
+		dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+		if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18,
+					     stk7700d_dib7000p_mt2266_config)
+		    != 0) {
+			err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
+			return -ENODEV;
+		}
+	}
+
+	adap->fe_adap[0].fe =
+		dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
+			   0x80 + (adap->id << 1),
+			   &stk7700d_dib7000p_mt2266_config[adap->id]);
+
+	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct i2c_adapter *tun_i2c;
+	tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+	return dvb_attach(mt2266_attach, adap->fe_adap[0].fe, tun_i2c,
+		&stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;
+}
+
+/* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */
+static struct dibx000_agc_config xc3028_agc_config = {
+	BAND_VHF | BAND_UHF,       /* band_caps */
+
+	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0,
+	 * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+	 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+	(0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) |
+	(3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */
+
+	712,	/* inv_gain */
+	21,	/* time_stabiliz */
+
+	0,	/* alpha_level */
+	118,	/* thlock */
+
+	0,	/* wbd_inv */
+	2867,	/* wbd_ref */
+	0,	/* wbd_sel */
+	2,	/* wbd_alpha */
+
+	0,	/* agc1_max */
+	0,	/* agc1_min */
+	39718,	/* agc2_max */
+	9930,	/* agc2_min */
+	0,	/* agc1_pt1 */
+	0,	/* agc1_pt2 */
+	0,	/* agc1_pt3 */
+	0,	/* agc1_slope1 */
+	0,	/* agc1_slope2 */
+	0,	/* agc2_pt1 */
+	128,	/* agc2_pt2 */
+	29,	/* agc2_slope1 */
+	29,	/* agc2_slope2 */
+
+	17,	/* alpha_mant */
+	27,	/* alpha_exp */
+	23,	/* beta_mant */
+	51,	/* beta_exp */
+
+	1,	/* perform_agc_softsplit */
+};
+
+/* PLL Configuration for COFDM BW_MHz = 8.00 with external clock = 30.00 */
+static struct dibx000_bandwidth_config xc3028_bw_config = {
+	60000, 30000, /* internal, sampling */
+	1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */
+	0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc,
+			  modulo */
+	(3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */
+	(1 << 25) | 5816102, /* ifreq = 5.200000 MHz */
+	20452225, /* timf */
+	30000000, /* xtal_hz */
+};
+
+static struct dib7000p_config stk7700ph_dib7700_xc3028_config = {
+	.output_mpeg2_in_188_bytes = 1,
+	.tuner_is_baseband = 1,
+
+	.agc_config_count = 1,
+	.agc = &xc3028_agc_config,
+	.bw  = &xc3028_bw_config,
+
+	.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+	.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+	.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+};
+
+static int stk7700ph_xc3028_callback(void *ptr, int component,
+				     int command, int arg)
+{
+	struct dvb_usb_adapter *adap = ptr;
+
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		/* Send the tuner in then out of reset */
+		dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 0); msleep(10);
+		dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+		break;
+	case XC2028_RESET_CLK:
+		break;
+	default:
+		err("%s: unknown command %d, arg %d\n", __func__,
+			command, arg);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static struct xc2028_ctrl stk7700ph_xc3028_ctrl = {
+	.fname = XC2028_DEFAULT_FIRMWARE,
+	.max_len = 64,
+	.demod = XC3028_FE_DIBCOM52,
+};
+
+static struct xc2028_config stk7700ph_xc3028_config = {
+	.i2c_addr = 0x61,
+	.ctrl = &stk7700ph_xc3028_ctrl,
+};
+
+static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct usb_device_descriptor *desc = &adap->dev->udev->descriptor;
+
+	if (desc->idVendor  == cpu_to_le16(USB_VID_PINNACLE) &&
+	    desc->idProduct == cpu_to_le16(USB_PID_PINNACLE_EXPRESSCARD_320CX))
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
+	else
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+	msleep(10);
+
+	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+				     &stk7700ph_dib7700_xc3028_config) != 0) {
+		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
+		    __func__);
+		return -ENODEV;
+	}
+
+	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+		&stk7700ph_dib7700_xc3028_config);
+
+	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct i2c_adapter *tun_i2c;
+
+	tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe,
+		DIBX000_I2C_INTERFACE_TUNER, 1);
+
+	stk7700ph_xc3028_config.i2c_adap = tun_i2c;
+
+	/* FIXME: generalize & move to common area */
+	adap->fe_adap[0].fe->callback = stk7700ph_xc3028_callback;
+
+	return dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &stk7700ph_xc3028_config)
+		== NULL ? -ENODEV : 0;
+}
+
+#define DEFAULT_RC_INTERVAL 50
+
+static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
+
+/* Number of keypresses to ignore before start repeating */
+#define RC_REPEAT_DELAY 6
+
+/*
+ * This function is used only when firmware is < 1.20 version. Newer
+ * firmwares use bulk mode, with functions implemented at dib0700_core,
+ * at dib0700_rc_urb_completion()
+ */
+static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
+{
+	u8 key[4];
+	u32 keycode;
+	u8 toggle;
+	int i;
+	struct dib0700_state *st = d->priv;
+
+	if (st->fw_version >= 0x10200) {
+		/* For 1.20 firmware , We need to keep the RC polling
+		   callback so we can reuse the input device setup in
+		   dvb-usb-remote.c.  However, the actual work is being done
+		   in the bulk URB completion handler. */
+		return 0;
+	}
+
+	i = dib0700_ctrl_rd(d, rc_request, 2, key, 4);
+	if (i <= 0) {
+		err("RC Query Failed");
+		return -1;
+	}
+
+	/* losing half of KEY_0 events from Philipps rc5 remotes.. */
+	if (key[0] == 0 && key[1] == 0 && key[2] == 0 && key[3] == 0)
+		return 0;
+
+	/* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]);  */
+
+	dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */
+
+	d->last_event = 0;
+	switch (d->props.rc.core.protocol) {
+	case RC_TYPE_NEC:
+		/* NEC protocol sends repeat code as 0 0 0 FF */
+		if ((key[3-2] == 0x00) && (key[3-3] == 0x00) &&
+		    (key[3] == 0xff))
+			keycode = d->last_event;
+		else {
+			keycode = key[3-2] << 8 | key[3-3];
+			d->last_event = keycode;
+		}
+
+		rc_keydown(d->rc_dev, keycode, 0);
+		break;
+	default:
+		/* RC-5 protocol changes toggle bit on new keypress */
+		keycode = key[3-2] << 8 | key[3-3];
+		toggle = key[3-1];
+		rc_keydown(d->rc_dev, keycode, toggle);
+
+		break;
+	}
+	return 0;
+}
+
+/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
+static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
+	BAND_UHF | BAND_VHF,
+
+	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+	 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
+	| (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
+
+	712,
+	41,
+
+	0,
+	118,
+
+	0,
+	4095,
+	0,
+	0,
+
+	42598,
+	17694,
+	45875,
+	2621,
+	0,
+	76,
+	139,
+	52,
+	59,
+	107,
+	172,
+	57,
+	70,
+
+	21,
+	25,
+	28,
+	48,
+
+	1,
+	{  0,
+	   107,
+	   51800,
+	   24700
+	},
+};
+
+static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = {
+	BAND_UHF | BAND_VHF,
+
+	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+	 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
+	| (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
+
+	712,
+	41,
+
+	0,
+	118,
+
+	0,
+	4095,
+	0,
+	0,
+
+	42598,
+	16384,
+	42598,
+	    0,
+
+	  0,
+	137,
+	255,
+
+	  0,
+	255,
+
+	0,
+	0,
+
+	 0,
+	41,
+
+	15,
+	25,
+
+	28,
+	48,
+
+	0,
+};
+
+static struct dibx000_bandwidth_config stk7700p_pll_config = {
+	60000, 30000,
+	1, 8, 3, 1, 0,
+	0, 0, 1, 1, 0,
+	(3 << 14) | (1 << 12) | (524 << 0),
+	60258167,
+	20452225,
+	30000000,
+};
+
+static struct dib7000m_config stk7700p_dib7000m_config = {
+	.dvbt_mode = 1,
+	.output_mpeg2_in_188_bytes = 1,
+	.quartz_direct = 1,
+
+	.agc_config_count = 1,
+	.agc = &stk7700p_7000m_mt2060_agc_config,
+	.bw  = &stk7700p_pll_config,
+
+	.gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
+	.gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
+	.gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
+};
+
+static struct dib7000p_config stk7700p_dib7000p_config = {
+	.output_mpeg2_in_188_bytes = 1,
+
+	.agc_config_count = 1,
+	.agc = &stk7700p_7000p_mt2060_agc_config,
+	.bw  = &stk7700p_pll_config,
+
+	.gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
+	.gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
+	.gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
+};
+
+static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_state *st = adap->dev->priv;
+	/* unless there is no real power management in DVB - we leave the device on GPIO6 */
+
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+	dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 0); msleep(50);
+
+	dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 1); msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO9,  GPIO_OUT, 1);
+
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10);
+	dib0700_ctrl_clock(adap->dev, 72, 1);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(100);
+
+	dib0700_set_gpio(adap->dev,  GPIO0, GPIO_OUT, 1);
+
+	st->mt2060_if1[0] = 1220;
+
+	if (dib7000pc_detection(&adap->dev->i2c_adap)) {
+		adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config);
+		st->is_dib7000pc = 1;
+	} else
+		adap->fe_adap[0].fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config);
+
+	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+static struct mt2060_config stk7700p_mt2060_config = {
+	0x60
+};
+
+static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
+	struct dib0700_state *st = adap->dev->priv;
+	struct i2c_adapter *tun_i2c;
+	s8 a;
+	int if1=1220;
+	if (adap->dev->udev->descriptor.idVendor  == cpu_to_le16(USB_VID_HAUPPAUGE) &&
+		adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_STICK)) {
+		if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a;
+	}
+	if (st->is_dib7000pc)
+		tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+	else
+		tun_i2c = dib7000m_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+
+	return dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, &stk7700p_mt2060_config,
+		if1) == NULL ? -ENODEV : 0;
+}
+
+/* DIB7070 generic */
+static struct dibx000_agc_config dib7070_agc_config = {
+	BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
+	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+	 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
+	| (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+
+	600,
+	10,
+
+	0,
+	118,
+
+	0,
+	3530,
+	1,
+	5,
+
+	65535,
+		0,
+
+	65535,
+	0,
+
+	0,
+	40,
+	183,
+	206,
+	255,
+	72,
+	152,
+	88,
+	90,
+
+	17,
+	27,
+	23,
+	51,
+
+	0,
+};
+
+static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
+{
+	deb_info("reset: %d", onoff);
+	return dib7000p_set_gpio(fe, 8, 0, !onoff);
+}
+
+static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+	deb_info("sleep: %d", onoff);
+	return dib7000p_set_gpio(fe, 9, 0, onoff);
+}
+
+static struct dib0070_config dib7070p_dib0070_config[2] = {
+	{
+		.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+		.reset = dib7070_tuner_reset,
+		.sleep = dib7070_tuner_sleep,
+		.clock_khz = 12000,
+		.clock_pad_drive = 4,
+		.charge_pump = 2,
+	}, {
+		.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+		.reset = dib7070_tuner_reset,
+		.sleep = dib7070_tuner_sleep,
+		.clock_khz = 12000,
+		.charge_pump = 2,
+	}
+};
+
+static struct dib0070_config dib7770p_dib0070_config = {
+	 .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+	 .reset = dib7070_tuner_reset,
+	 .sleep = dib7070_tuner_sleep,
+	 .clock_khz = 12000,
+	 .clock_pad_drive = 0,
+	 .flip_chip = 1,
+	 .charge_pump = 2,
+};
+
+static int dib7070_set_param_override(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dib0700_adapter_state *state = adap->priv;
+
+	u16 offset;
+	u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
+	switch (band) {
+		case BAND_VHF: offset = 950; break;
+		case BAND_UHF:
+		default: offset = 550; break;
+	}
+	deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
+	dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
+	return state->set_param_save(fe);
+}
+
+static int dib7770_set_param_override(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dib0700_adapter_state *state = adap->priv;
+
+	 u16 offset;
+	 u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
+	 switch (band) {
+	 case BAND_VHF:
+		  dib7000p_set_gpio(fe, 0, 0, 1);
+		  offset = 850;
+		  break;
+	 case BAND_UHF:
+	 default:
+		  dib7000p_set_gpio(fe, 0, 0, 0);
+		  offset = 250;
+		  break;
+	 }
+	 deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
+	 dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
+	 return state->set_param_save(fe);
+}
+
+static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	 struct dib0700_adapter_state *st = adap->priv;
+	 struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe,
+			 DIBX000_I2C_INTERFACE_TUNER, 1);
+
+	 if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
+			&dib7770p_dib0070_config) == NULL)
+		 return -ENODEV;
+
+	 st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+	 adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7770_set_param_override;
+	 return 0;
+}
+
+static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *st = adap->priv;
+	struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+
+	if (adap->id == 0) {
+		if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL)
+			return -ENODEV;
+	} else {
+		if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL)
+			return -ENODEV;
+	}
+
+	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7070_set_param_override;
+	return 0;
+}
+
+static int stk7700p_pid_filter(struct dvb_usb_adapter *adapter, int index,
+		u16 pid, int onoff)
+{
+	struct dib0700_state *st = adapter->dev->priv;
+	if (st->is_dib7000pc)
+		return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
+	return dib7000m_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
+}
+
+static int stk7700p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
+{
+	struct dib0700_state *st = adapter->dev->priv;
+	if (st->is_dib7000pc)
+		return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
+	return dib7000m_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
+}
+
+static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
+{
+	return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
+}
+
+static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
+{
+	return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
+}
+
+static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
+	60000, 15000,
+	1, 20, 3, 1, 0,
+	0, 0, 1, 1, 2,
+	(3 << 14) | (1 << 12) | (524 << 0),
+	(0 << 25) | 0,
+	20452225,
+	12000000,
+};
+
+static struct dib7000p_config dib7070p_dib7000p_config = {
+	.output_mpeg2_in_188_bytes = 1,
+
+	.agc_config_count = 1,
+	.agc = &dib7070_agc_config,
+	.bw  = &dib7070_bw_config_12_mhz,
+	.tuner_is_baseband = 1,
+	.spur_protect = 1,
+
+	.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+	.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+	.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+	.hostbus_diversity = 1,
+};
+
+/* STK7070P */
+static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct usb_device_descriptor *p = &adap->dev->udev->descriptor;
+	if (p->idVendor  == cpu_to_le16(USB_VID_PINNACLE) &&
+	    p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E))
+		dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
+	else
+		dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+	dib0700_ctrl_clock(adap->dev, 72, 1);
+
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+				     &dib7070p_dib7000p_config) != 0) {
+		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
+		    __func__);
+		return -ENODEV;
+	}
+
+	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+		&dib7070p_dib7000p_config);
+	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+/* STK7770P */
+static struct dib7000p_config dib7770p_dib7000p_config = {
+	.output_mpeg2_in_188_bytes = 1,
+
+	.agc_config_count = 1,
+	.agc = &dib7070_agc_config,
+	.bw  = &dib7070_bw_config_12_mhz,
+	.tuner_is_baseband = 1,
+	.spur_protect = 1,
+
+	.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+	.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+	.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+	.hostbus_diversity = 1,
+	.enable_current_mirror = 1,
+	.disable_sample_and_hold = 0,
+};
+
+static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct usb_device_descriptor *p = &adap->dev->udev->descriptor;
+	if (p->idVendor  == cpu_to_le16(USB_VID_PINNACLE) &&
+	    p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E))
+		dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
+	else
+		dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+	dib0700_ctrl_clock(adap->dev, 72, 1);
+
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+				     &dib7770p_dib7000p_config) != 0) {
+		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
+		    __func__);
+		return -ENODEV;
+	}
+
+	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+		&dib7770p_dib7000p_config);
+	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+/* DIB807x generic */
+static struct dibx000_agc_config dib807x_agc_config[2] = {
+	{
+		BAND_VHF,
+		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
+		 * P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
+		 * P_agc_inv_pwm2=0,P_agc_inh_dc_rv_est=0,
+		 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
+		 * P_agc_write=0 */
+		(0 << 15) | (0 << 14) | (7 << 11) | (0 << 10) | (0 << 9) |
+			(0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) |
+			(0 << 0), /* setup*/
+
+		600, /* inv_gain*/
+		10,  /* time_stabiliz*/
+
+		0,  /* alpha_level*/
+		118,  /* thlock*/
+
+		0,     /* wbd_inv*/
+		3530,  /* wbd_ref*/
+		1,     /* wbd_sel*/
+		5,     /* wbd_alpha*/
+
+		65535,  /* agc1_max*/
+		0,  /* agc1_min*/
+
+		65535,  /* agc2_max*/
+		0,      /* agc2_min*/
+
+		0,      /* agc1_pt1*/
+		40,     /* agc1_pt2*/
+		183,    /* agc1_pt3*/
+		206,    /* agc1_slope1*/
+		255,    /* agc1_slope2*/
+		72,     /* agc2_pt1*/
+		152,    /* agc2_pt2*/
+		88,     /* agc2_slope1*/
+		90,     /* agc2_slope2*/
+
+		17,  /* alpha_mant*/
+		27,  /* alpha_exp*/
+		23,  /* beta_mant*/
+		51,  /* beta_exp*/
+
+		0,  /* perform_agc_softsplit*/
+	}, {
+		BAND_UHF,
+		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
+		 * P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
+		 * P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+		 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
+		 * P_agc_write=0 */
+		(0 << 15) | (0 << 14) | (1 << 11) | (0 << 10) | (0 << 9) |
+			(0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) |
+			(0 << 0), /* setup */
+
+		600, /* inv_gain*/
+		10,  /* time_stabiliz*/
+
+		0,  /* alpha_level*/
+		118,  /* thlock*/
+
+		0,     /* wbd_inv*/
+		3530,  /* wbd_ref*/
+		1,     /* wbd_sel*/
+		5,     /* wbd_alpha*/
+
+		65535,  /* agc1_max*/
+		0,  /* agc1_min*/
+
+		65535,  /* agc2_max*/
+		0,      /* agc2_min*/
+
+		0,      /* agc1_pt1*/
+		40,     /* agc1_pt2*/
+		183,    /* agc1_pt3*/
+		206,    /* agc1_slope1*/
+		255,    /* agc1_slope2*/
+		72,     /* agc2_pt1*/
+		152,    /* agc2_pt2*/
+		88,     /* agc2_slope1*/
+		90,     /* agc2_slope2*/
+
+		17,  /* alpha_mant*/
+		27,  /* alpha_exp*/
+		23,  /* beta_mant*/
+		51,  /* beta_exp*/
+
+		0,  /* perform_agc_softsplit*/
+	}
+};
+
+static struct dibx000_bandwidth_config dib807x_bw_config_12_mhz = {
+	60000, 15000, /* internal, sampling*/
+	1, 20, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass*/
+	0, 0, 1, 1, 2, /* misc: refdiv, bypclk_div, IO_CLK_en_core,
+			  ADClkSrc, modulo */
+	(3 << 14) | (1 << 12) | (599 << 0), /* sad_cfg: refsel, sel, freq_15k*/
+	(0 << 25) | 0, /* ifreq = 0.000000 MHz*/
+	18179755, /* timf*/
+	12000000, /* xtal_hz*/
+};
+
+static struct dib8000_config dib807x_dib8000_config[2] = {
+	{
+		.output_mpeg2_in_188_bytes = 1,
+
+		.agc_config_count = 2,
+		.agc = dib807x_agc_config,
+		.pll = &dib807x_bw_config_12_mhz,
+		.tuner_is_baseband = 1,
+
+		.gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
+		.gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
+		.gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
+
+		.hostbus_diversity = 1,
+		.div_cfg = 1,
+		.agc_control = &dib0070_ctrl_agc_filter,
+		.output_mode = OUTMODE_MPEG2_FIFO,
+		.drives = 0x2d98,
+	}, {
+		.output_mpeg2_in_188_bytes = 1,
+
+		.agc_config_count = 2,
+		.agc = dib807x_agc_config,
+		.pll = &dib807x_bw_config_12_mhz,
+		.tuner_is_baseband = 1,
+
+		.gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
+		.gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
+		.gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
+
+		.hostbus_diversity = 1,
+		.agc_control = &dib0070_ctrl_agc_filter,
+		.output_mode = OUTMODE_MPEG2_FIFO,
+		.drives = 0x2d98,
+	}
+};
+
+static int dib80xx_tuner_reset(struct dvb_frontend *fe, int onoff)
+{
+	return dib8000_set_gpio(fe, 5, 0, !onoff);
+}
+
+static int dib80xx_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+	return dib8000_set_gpio(fe, 0, 0, onoff);
+}
+
+static const struct dib0070_wbd_gain_cfg dib8070_wbd_gain_cfg[] = {
+    { 240,      7},
+    { 0xffff,   6},
+};
+
+static struct dib0070_config dib807x_dib0070_config[2] = {
+	{
+		.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+		.reset = dib80xx_tuner_reset,
+		.sleep = dib80xx_tuner_sleep,
+		.clock_khz = 12000,
+		.clock_pad_drive = 4,
+		.vga_filter = 1,
+		.force_crystal_mode = 1,
+		.enable_third_order_filter = 1,
+		.charge_pump = 0,
+		.wbd_gain = dib8070_wbd_gain_cfg,
+		.osc_buffer_state = 0,
+		.freq_offset_khz_uhf = -100,
+		.freq_offset_khz_vhf = -100,
+	}, {
+		.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+		.reset = dib80xx_tuner_reset,
+		.sleep = dib80xx_tuner_sleep,
+		.clock_khz = 12000,
+		.clock_pad_drive = 2,
+		.vga_filter = 1,
+		.force_crystal_mode = 1,
+		.enable_third_order_filter = 1,
+		.charge_pump = 0,
+		.wbd_gain = dib8070_wbd_gain_cfg,
+		.osc_buffer_state = 0,
+		.freq_offset_khz_uhf = -25,
+		.freq_offset_khz_vhf = -25,
+	}
+};
+
+static int dib807x_set_param_override(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dib0700_adapter_state *state = adap->priv;
+
+	u16 offset = dib0070_wbd_offset(fe);
+	u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
+	switch (band) {
+	case BAND_VHF:
+		offset += 750;
+		break;
+	case BAND_UHF:  /* fall-thru wanted */
+	default:
+		offset += 250; break;
+	}
+	deb_info("WBD for DiB8000: %d\n", offset);
+	dib8000_set_wbd_ref(fe, offset);
+
+	return state->set_param_save(fe);
+}
+
+static int dib807x_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *st = adap->priv;
+	struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe,
+			DIBX000_I2C_INTERFACE_TUNER, 1);
+
+	if (adap->id == 0) {
+		if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
+				&dib807x_dib0070_config[0]) == NULL)
+			return -ENODEV;
+	} else {
+		if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
+				&dib807x_dib0070_config[1]) == NULL)
+			return -ENODEV;
+	}
+
+	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib807x_set_param_override;
+	return 0;
+}
+
+static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index,
+	u16 pid, int onoff)
+{
+	return dib8000_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
+}
+
+static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter,
+		int onoff)
+{
+	return dib8000_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
+}
+
+/* STK807x */
+static int stk807x_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+	dib0700_ctrl_clock(adap->dev, 72, 1);
+
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+				0x80, 0);
+
+	adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80,
+			      &dib807x_dib8000_config[0]);
+
+	return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
+}
+
+/* STK807xPVR */
+static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap)
+{
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
+	msleep(30);
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(500);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+	dib0700_ctrl_clock(adap->dev, 72, 1);
+
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	/* initialize IC 0 */
+	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80, 0);
+
+	adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80,
+			      &dib807x_dib8000_config[0]);
+
+	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap)
+{
+	/* initialize IC 1 */
+	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82, 0);
+
+	adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82,
+			      &dib807x_dib8000_config[1]);
+
+	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+/* STK8096GP */
+static struct dibx000_agc_config dib8090_agc_config[2] = {
+	{
+	BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
+	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1,
+	 * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+	 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
+	| (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+
+	787,
+	10,
+
+	0,
+	118,
+
+	0,
+	3530,
+	1,
+	5,
+
+	65535,
+	0,
+
+	65535,
+	0,
+
+	0,
+	32,
+	114,
+	143,
+	144,
+	114,
+	227,
+	116,
+	117,
+
+	28,
+	26,
+	31,
+	51,
+
+	0,
+	},
+	{
+	BAND_CBAND,
+	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1,
+	 * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+	 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
+	| (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+
+	787,
+	10,
+
+	0,
+	118,
+
+	0,
+	3530,
+	1,
+	5,
+
+	0,
+	0,
+
+	65535,
+	0,
+
+	0,
+	32,
+	114,
+	143,
+	144,
+	114,
+	227,
+	116,
+	117,
+
+	28,
+	26,
+	31,
+	51,
+
+	0,
+	}
+};
+
+static struct dibx000_bandwidth_config dib8090_pll_config_12mhz = {
+	54000, 13500,
+	1, 18, 3, 1, 0,
+	0, 0, 1, 1, 2,
+	(3 << 14) | (1 << 12) | (599 << 0),
+	(0 << 25) | 0,
+	20199727,
+	12000000,
+};
+
+static int dib8090_get_adc_power(struct dvb_frontend *fe)
+{
+	return dib8000_get_adc_power(fe, 1);
+}
+
+static struct dib8000_config dib809x_dib8000_config[2] = {
+	{
+	.output_mpeg2_in_188_bytes = 1,
+
+	.agc_config_count = 2,
+	.agc = dib8090_agc_config,
+	.agc_control = dib0090_dcc_freq,
+	.pll = &dib8090_pll_config_12mhz,
+	.tuner_is_baseband = 1,
+
+	.gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
+	.gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
+	.gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
+
+	.hostbus_diversity = 1,
+	.div_cfg = 0x31,
+	.output_mode = OUTMODE_MPEG2_FIFO,
+	.drives = 0x2d98,
+	.diversity_delay = 48,
+	.refclksel = 3,
+	}, {
+	.output_mpeg2_in_188_bytes = 1,
+
+	.agc_config_count = 2,
+	.agc = dib8090_agc_config,
+	.agc_control = dib0090_dcc_freq,
+	.pll = &dib8090_pll_config_12mhz,
+	.tuner_is_baseband = 1,
+
+	.gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
+	.gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
+	.gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
+
+	.hostbus_diversity = 1,
+	.div_cfg = 0x31,
+	.output_mode = OUTMODE_DIVERSITY,
+	.drives = 0x2d08,
+	.diversity_delay = 1,
+	.refclksel = 3,
+	}
+};
+
+static struct dib0090_wbd_slope dib8090_wbd_table[] = {
+	/* max freq ; cold slope ; cold offset ; warm slope ; warm offset ; wbd gain */
+	{ 120,     0, 500,  0,   500, 4 }, /* CBAND */
+	{ 170,     0, 450,  0,   450, 4 }, /* CBAND */
+	{ 380,    48, 373, 28,   259, 6 }, /* VHF */
+	{ 860,    34, 700, 36,   616, 6 }, /* high UHF */
+	{ 0xFFFF, 34, 700, 36,   616, 6 }, /* default */
+};
+
+static struct dib0090_config dib809x_dib0090_config = {
+	.io.pll_bypass = 1,
+	.io.pll_range = 1,
+	.io.pll_prediv = 1,
+	.io.pll_loopdiv = 20,
+	.io.adc_clock_ratio = 8,
+	.io.pll_int_loop_filt = 0,
+	.io.clock_khz = 12000,
+	.reset = dib80xx_tuner_reset,
+	.sleep = dib80xx_tuner_sleep,
+	.clkouttobamse = 1,
+	.analog_output = 1,
+	.i2c_address = DEFAULT_DIB0090_I2C_ADDRESS,
+	.use_pwm_agc = 1,
+	.clkoutdrive = 1,
+	.get_adc_power = dib8090_get_adc_power,
+	.freq_offset_khz_uhf = -63,
+	.freq_offset_khz_vhf = -143,
+	.wbd = dib8090_wbd_table,
+	.fref_clock_ratio = 6,
+};
+
+static int dib8096_set_param_override(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dib0700_adapter_state *state = adap->priv;
+	u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
+	u16 target;
+	int ret = 0;
+	enum frontend_tune_state tune_state = CT_SHUTDOWN;
+	u16 ltgain, rf_gain_limit;
+
+	ret = state->set_param_save(fe);
+	if (ret < 0)
+		return ret;
+
+	target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2;
+	dib8000_set_wbd_ref(fe, target);
+
+
+	if (band == BAND_CBAND) {
+		deb_info("tuning in CBAND - soft-AGC startup\n");
+		dib0090_set_tune_state(fe, CT_AGC_START);
+		do {
+			ret = dib0090_gain_control(fe);
+			msleep(ret);
+			tune_state = dib0090_get_tune_state(fe);
+			if (tune_state == CT_AGC_STEP_0)
+				dib8000_set_gpio(fe, 6, 0, 1);
+			else if (tune_state == CT_AGC_STEP_1) {
+				dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, &ltgain);
+				if (rf_gain_limit == 0)
+					dib8000_set_gpio(fe, 6, 0, 0);
+			}
+		} while (tune_state < CT_AGC_STOP);
+		dib0090_pwm_gain_reset(fe);
+		dib8000_pwm_agc_reset(fe);
+		dib8000_set_tune_state(fe, CT_DEMOD_START);
+	} else {
+		deb_info("not tuning in CBAND - standard AGC startup\n");
+		dib0090_pwm_gain_reset(fe);
+	}
+
+	return 0;
+}
+
+static int dib809x_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *st = adap->priv;
+	struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+
+	if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL)
+		return -ENODEV;
+
+	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096_set_param_override;
+	return 0;
+}
+
+static int stk809x_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+	dib0700_ctrl_clock(adap->dev, 72, 1);
+
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80, 0);
+
+	adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
+
+	return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
+}
+
+static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *st = adap->priv;
+	struct i2c_adapter *tun_i2c;
+	struct dvb_frontend *fe_slave  = dib8000_get_slave_frontend(adap->fe_adap[0].fe, 1);
+
+	if (fe_slave) {
+		tun_i2c = dib8000_get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1);
+		if (dvb_attach(dib0090_register, fe_slave, tun_i2c, &dib809x_dib0090_config) == NULL)
+			return -ENODEV;
+		fe_slave->dvb = adap->fe_adap[0].fe->dvb;
+		fe_slave->ops.tuner_ops.set_params = dib8096_set_param_override;
+	}
+	tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+	if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL)
+		return -ENODEV;
+
+	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096_set_param_override;
+
+	return 0;
+}
+
+static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_frontend *fe_slave;
+
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(1000);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+	dib0700_ctrl_clock(adap->dev, 72, 1);
+
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80, 0);
+
+	adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
+	if (adap->fe_adap[0].fe == NULL)
+		return -ENODEV;
+
+	fe_slave = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]);
+	dib8000_set_slave_frontend(adap->fe_adap[0].fe, fe_slave);
+
+	return fe_slave == NULL ?  -ENODEV : 0;
+}
+
+/* TFE8096P */
+static struct dibx000_agc_config dib8096p_agc_config[2] = {
+	{
+		.band_caps		= BAND_UHF,
+		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
+		   P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
+		   P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+		   P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
+		   P_agc_write=0 */
+		.setup			= (0 << 15) | (0 << 14) | (5 << 11)
+			| (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5)
+			| (0 << 4) | (5 << 1) | (0 << 0),
+
+		.inv_gain		= 684,
+		.time_stabiliz	= 10,
+
+		.alpha_level	= 0,
+		.thlock			= 118,
+
+		.wbd_inv		= 0,
+		.wbd_ref		= 1200,
+		.wbd_sel		= 3,
+		.wbd_alpha		= 5,
+
+		.agc1_max		= 65535,
+		.agc1_min		= 0,
+
+		.agc2_max		= 32767,
+		.agc2_min		= 0,
+
+		.agc1_pt1		= 0,
+		.agc1_pt2		= 0,
+		.agc1_pt3		= 105,
+		.agc1_slope1	= 0,
+		.agc1_slope2	= 156,
+		.agc2_pt1		= 105,
+		.agc2_pt2		= 255,
+		.agc2_slope1	= 54,
+		.agc2_slope2	= 0,
+
+		.alpha_mant		= 28,
+		.alpha_exp		= 26,
+		.beta_mant		= 31,
+		.beta_exp		= 51,
+
+		.perform_agc_softsplit = 0,
+	} , {
+		.band_caps		= BAND_FM | BAND_VHF | BAND_CBAND,
+		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
+		   P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
+		   P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+		   P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
+		   P_agc_write=0 */
+		.setup			= (0 << 15) | (0 << 14) | (5 << 11)
+			| (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5)
+			| (0 << 4) | (5 << 1) | (0 << 0),
+
+		.inv_gain		= 732,
+		.time_stabiliz  = 10,
+
+		.alpha_level	= 0,
+		.thlock			= 118,
+
+		.wbd_inv		= 0,
+		.wbd_ref		= 1200,
+		.wbd_sel		= 3,
+		.wbd_alpha		= 5,
+
+		.agc1_max		= 65535,
+		.agc1_min		= 0,
+
+		.agc2_max		= 32767,
+		.agc2_min		= 0,
+
+		.agc1_pt1		= 0,
+		.agc1_pt2		= 0,
+		.agc1_pt3		= 98,
+		.agc1_slope1	= 0,
+		.agc1_slope2	= 167,
+		.agc2_pt1		= 98,
+		.agc2_pt2		= 255,
+		.agc2_slope1	= 52,
+		.agc2_slope2	= 0,
+
+		.alpha_mant		= 28,
+		.alpha_exp		= 26,
+		.beta_mant		= 31,
+		.beta_exp		= 51,
+
+		.perform_agc_softsplit = 0,
+	}
+};
+
+static struct dibx000_bandwidth_config dib8096p_clock_config_12_mhz = {
+	108000, 13500,
+	1, 9, 1, 0, 0,
+	0, 0, 0, 0, 2,
+	(3 << 14) | (1 << 12) | (524 << 0),
+	(0 << 25) | 0,
+	20199729,
+	12000000,
+};
+
+static struct dib8000_config tfe8096p_dib8000_config = {
+	.output_mpeg2_in_188_bytes	= 1,
+	.hostbus_diversity			= 1,
+	.update_lna					= NULL,
+
+	.agc_config_count			= 2,
+	.agc						= dib8096p_agc_config,
+	.pll						= &dib8096p_clock_config_12_mhz,
+
+	.gpio_dir					= DIB8000_GPIO_DEFAULT_DIRECTIONS,
+	.gpio_val					= DIB8000_GPIO_DEFAULT_VALUES,
+	.gpio_pwm_pos				= DIB8000_GPIO_DEFAULT_PWM_POS,
+
+	.agc_control				= NULL,
+	.diversity_delay			= 48,
+	.output_mode				= OUTMODE_MPEG2_FIFO,
+	.enMpegOutput				= 1,
+};
+
+static struct dib0090_wbd_slope dib8096p_wbd_table[] = {
+	{ 380, 81, 850, 64, 540, 4},
+	{ 860, 51, 866, 21, 375, 4},
+	{1700, 0, 250, 0, 100, 6},
+	{2600, 0, 250, 0, 100, 6},
+	{ 0xFFFF, 0, 0, 0, 0, 0},
+};
+
+static const struct dib0090_config tfe8096p_dib0090_config = {
+	.io.clock_khz			= 12000,
+	.io.pll_bypass			= 0,
+	.io.pll_range			= 0,
+	.io.pll_prediv			= 3,
+	.io.pll_loopdiv			= 6,
+	.io.adc_clock_ratio		= 0,
+	.io.pll_int_loop_filt	= 0,
+	.reset					= dib8096p_tuner_sleep,
+	.sleep					= dib8096p_tuner_sleep,
+
+	.freq_offset_khz_uhf	= -143,
+	.freq_offset_khz_vhf	= -143,
+
+	.get_adc_power			= dib8090_get_adc_power,
+
+	.clkouttobamse			= 1,
+	.analog_output			= 0,
+
+	.wbd_vhf_offset			= 0,
+	.wbd_cband_offset		= 0,
+	.use_pwm_agc			= 1,
+	.clkoutdrive			= 0,
+
+	.fref_clock_ratio		= 1,
+
+	.wbd					= dib8096p_wbd_table,
+
+	.ls_cfg_pad_drv			= 0,
+	.data_tx_drv			= 0,
+	.low_if					= NULL,
+	.in_soc					= 1,
+	.force_cband_input		= 0,
+};
+
+struct dibx090p_adc {
+	u32 freq;			/* RF freq MHz */
+	u32 timf;			/* New Timf */
+	u32 pll_loopdiv;	/* New prediv */
+	u32 pll_prediv;		/* New loopdiv */
+};
+
+struct dibx090p_adc dib8090p_adc_tab[] = {
+	{ 50000, 17043521, 16, 3}, /* 64 MHz */
+	{878000, 20199729, 9, 1}, /* 60 MHz */
+	{0xffffffff, 0, 0, 0}, /* 60 MHz */
+};
+
+static int dib8096p_agc_startup(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dib0700_adapter_state *state = adap->priv;
+	struct dibx000_bandwidth_config pll;
+	u16 target;
+	int better_sampling_freq = 0, ret;
+	struct dibx090p_adc *adc_table = &dib8090p_adc_tab[0];
+
+	ret = state->set_param_save(fe);
+	if (ret < 0)
+		return ret;
+	memset(&pll, 0, sizeof(struct dibx000_bandwidth_config));
+
+	dib0090_pwm_gain_reset(fe);
+	/* dib0090_get_wbd_target is returning any possible
+	   temperature compensated wbd-target */
+	target = (dib0090_get_wbd_target(fe) * 8  + 1) / 2;
+	dib8000_set_wbd_ref(fe, target);
+
+
+	while (p->frequency / 1000 > adc_table->freq) {
+		better_sampling_freq = 1;
+		adc_table++;
+	}
+
+	if ((adc_table->freq != 0xffffffff) && better_sampling_freq) {
+		pll.pll_ratio  = adc_table->pll_loopdiv;
+		pll.pll_prediv = adc_table->pll_prediv;
+		dib8000_update_pll(fe, &pll);
+		dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc_table->timf);
+	}
+	return 0;
+}
+
+static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+	dib0700_ctrl_clock(adap->dev, 72, 1);
+
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80, 1);
+
+	adap->fe_adap[0].fe = dvb_attach(dib8000_attach,
+			&adap->dev->i2c_adap, 0x80, &tfe8096p_dib8000_config);
+
+	return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
+}
+
+static int tfe8096p_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *st = adap->priv;
+	struct i2c_adapter *tun_i2c = dib8096p_get_i2c_tuner(adap->fe_adap[0].fe);
+
+	if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
+				&tfe8096p_dib0090_config) == NULL)
+		return -ENODEV;
+
+	dib8000_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+
+	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096p_agc_startup;
+	return 0;
+}
+
+/* STK9090M */
+static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
+{
+	return dib9000_fw_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
+}
+
+static int dib90x0_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
+{
+	return dib9000_fw_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
+}
+
+static int dib90x0_tuner_reset(struct dvb_frontend *fe, int onoff)
+{
+	return dib9000_set_gpio(fe, 5, 0, !onoff);
+}
+
+static int dib90x0_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+	return dib9000_set_gpio(fe, 0, 0, onoff);
+}
+
+static int dib01x0_pmu_update(struct i2c_adapter *i2c, u16 *data, u8 len)
+{
+	u8 wb[4] = { 0xc >> 8, 0xc & 0xff, 0, 0 };
+	u8 rb[2];
+	struct i2c_msg msg[2] = {
+		{.addr = 0x1e >> 1, .flags = 0, .buf = wb, .len = 2},
+		{.addr = 0x1e >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2},
+	};
+	u8 index_data;
+
+	dibx000_i2c_set_speed(i2c, 250);
+
+	if (i2c_transfer(i2c, msg, 2) != 2)
+		return -EIO;
+
+	switch (rb[0] << 8 | rb[1]) {
+	case 0:
+			deb_info("Found DiB0170 rev1: This version of DiB0170 is not supported any longer.\n");
+			return -EIO;
+	case 1:
+			deb_info("Found DiB0170 rev2");
+			break;
+	case 2:
+			deb_info("Found DiB0190 rev2");
+			break;
+	default:
+			deb_info("DiB01x0 not found");
+			return -EIO;
+	}
+
+	for (index_data = 0; index_data < len; index_data += 2) {
+		wb[2] = (data[index_data + 1] >> 8) & 0xff;
+		wb[3] = (data[index_data + 1]) & 0xff;
+
+		if (data[index_data] == 0) {
+			wb[0] = (data[index_data] >> 8) & 0xff;
+			wb[1] = (data[index_data]) & 0xff;
+			msg[0].len = 2;
+			if (i2c_transfer(i2c, msg, 2) != 2)
+				return -EIO;
+			wb[2] |= rb[0];
+			wb[3] |= rb[1] & ~(3 << 4);
+		}
+
+		wb[0] = (data[index_data] >> 8)&0xff;
+		wb[1] = (data[index_data])&0xff;
+		msg[0].len = 4;
+		if (i2c_transfer(i2c, &msg[0], 1) != 1)
+			return -EIO;
+	}
+	return 0;
+}
+
+static struct dib9000_config stk9090m_config = {
+	.output_mpeg2_in_188_bytes = 1,
+	.output_mode = OUTMODE_MPEG2_FIFO,
+	.vcxo_timer = 279620,
+	.timing_frequency = 20452225,
+	.demod_clock_khz = 60000,
+	.xtal_clock_khz = 30000,
+	.if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0),
+	.subband = {
+		2,
+		{
+			{ 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0008 } }, /* GPIO 3 to 1 for VHF */
+			{ 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0000 } }, /* GPIO 3 to 0 for UHF */
+			{ 0 },
+		},
+	},
+	.gpio_function = {
+		{ .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 },
+		{ .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 },
+	},
+};
+
+static struct dib9000_config nim9090md_config[2] = {
+	{
+		.output_mpeg2_in_188_bytes = 1,
+		.output_mode = OUTMODE_MPEG2_FIFO,
+		.vcxo_timer = 279620,
+		.timing_frequency = 20452225,
+		.demod_clock_khz = 60000,
+		.xtal_clock_khz = 30000,
+		.if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0),
+	}, {
+		.output_mpeg2_in_188_bytes = 1,
+		.output_mode = OUTMODE_DIVERSITY,
+		.vcxo_timer = 279620,
+		.timing_frequency = 20452225,
+		.demod_clock_khz = 60000,
+		.xtal_clock_khz = 30000,
+		.if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0),
+		.subband = {
+			2,
+			{
+				{ 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0006 } }, /* GPIO 1 and 2 to 1 for VHF */
+				{ 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0000 } }, /* GPIO 1 and 2 to 0 for UHF */
+				{ 0 },
+			},
+		},
+		.gpio_function = {
+			{ .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 },
+			{ .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 },
+		},
+	}
+};
+
+static struct dib0090_config dib9090_dib0090_config = {
+	.io.pll_bypass = 0,
+	.io.pll_range = 1,
+	.io.pll_prediv = 1,
+	.io.pll_loopdiv = 8,
+	.io.adc_clock_ratio = 8,
+	.io.pll_int_loop_filt = 0,
+	.io.clock_khz = 30000,
+	.reset = dib90x0_tuner_reset,
+	.sleep = dib90x0_tuner_sleep,
+	.clkouttobamse = 0,
+	.analog_output = 0,
+	.use_pwm_agc = 0,
+	.clkoutdrive = 0,
+	.freq_offset_khz_uhf = 0,
+	.freq_offset_khz_vhf = 0,
+};
+
+static struct dib0090_config nim9090md_dib0090_config[2] = {
+	{
+		.io.pll_bypass = 0,
+		.io.pll_range = 1,
+		.io.pll_prediv = 1,
+		.io.pll_loopdiv = 8,
+		.io.adc_clock_ratio = 8,
+		.io.pll_int_loop_filt = 0,
+		.io.clock_khz = 30000,
+		.reset = dib90x0_tuner_reset,
+		.sleep = dib90x0_tuner_sleep,
+		.clkouttobamse = 1,
+		.analog_output = 0,
+		.use_pwm_agc = 0,
+		.clkoutdrive = 0,
+		.freq_offset_khz_uhf = 0,
+		.freq_offset_khz_vhf = 0,
+	}, {
+		.io.pll_bypass = 0,
+		.io.pll_range = 1,
+		.io.pll_prediv = 1,
+		.io.pll_loopdiv = 8,
+		.io.adc_clock_ratio = 8,
+		.io.pll_int_loop_filt = 0,
+		.io.clock_khz = 30000,
+		.reset = dib90x0_tuner_reset,
+		.sleep = dib90x0_tuner_sleep,
+		.clkouttobamse = 0,
+		.analog_output = 0,
+		.use_pwm_agc = 0,
+		.clkoutdrive = 0,
+		.freq_offset_khz_uhf = 0,
+		.freq_offset_khz_vhf = 0,
+	}
+};
+
+
+static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *state = adap->priv;
+	struct dib0700_state *st = adap->dev->priv;
+	u32 fw_version;
+
+	/* Make use of the new i2c functions from FW 1.20 */
+	dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL);
+	if (fw_version >= 0x10200)
+		st->fw_use_new_i2c_api = 1;
+	dib0700_set_i2c_speed(adap->dev, 340);
+
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+	dib0700_ctrl_clock(adap->dev, 72, 1);
+
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80);
+
+	if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) {
+		deb_info("%s: Upload failed. (file not found?)\n", __func__);
+		return -ENODEV;
+	} else {
+		deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size);
+	}
+	stk9090m_config.microcode_B_fe_size = state->frontend_firmware->size;
+	stk9090m_config.microcode_B_fe_buffer = state->frontend_firmware->data;
+
+	adap->fe_adap[0].fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config);
+
+	return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
+}
+
+static int dib9090_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *state = adap->priv;
+	struct i2c_adapter *i2c = dib9000_get_tuner_interface(adap->fe_adap[0].fe);
+	u16 data_dib190[10] = {
+		1, 0x1374,
+		2, 0x01a2,
+		7, 0x0020,
+		0, 0x00ef,
+		8, 0x0486,
+	};
+
+	if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &dib9090_dib0090_config) == NULL)
+		return -ENODEV;
+	i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
+	if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0)
+		return -ENODEV;
+	dib0700_set_i2c_speed(adap->dev, 1500);
+	if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0)
+		return -ENODEV;
+	release_firmware(state->frontend_firmware);
+	return 0;
+}
+
+static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *state = adap->priv;
+	struct dib0700_state *st = adap->dev->priv;
+	struct i2c_adapter *i2c;
+	struct dvb_frontend *fe_slave;
+	u32 fw_version;
+
+	/* Make use of the new i2c functions from FW 1.20 */
+	dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL);
+	if (fw_version >= 0x10200)
+		st->fw_use_new_i2c_api = 1;
+	dib0700_set_i2c_speed(adap->dev, 340);
+
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+	dib0700_ctrl_clock(adap->dev, 72, 1);
+
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) {
+		deb_info("%s: Upload failed. (file not found?)\n", __func__);
+		return -EIO;
+	} else {
+		deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size);
+	}
+	nim9090md_config[0].microcode_B_fe_size = state->frontend_firmware->size;
+	nim9090md_config[0].microcode_B_fe_buffer = state->frontend_firmware->data;
+	nim9090md_config[1].microcode_B_fe_size = state->frontend_firmware->size;
+	nim9090md_config[1].microcode_B_fe_buffer = state->frontend_firmware->data;
+
+	dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, 0x80);
+	adap->fe_adap[0].fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]);
+
+	if (adap->fe_adap[0].fe == NULL)
+		return -ENODEV;
+
+	i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_3_4, 0);
+	dib9000_i2c_enumeration(i2c, 1, 0x12, 0x82);
+
+	fe_slave = dvb_attach(dib9000_attach, i2c, 0x82, &nim9090md_config[1]);
+	dib9000_set_slave_frontend(adap->fe_adap[0].fe, fe_slave);
+
+	return fe_slave == NULL ?  -ENODEV : 0;
+}
+
+static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *state = adap->priv;
+	struct i2c_adapter *i2c;
+	struct dvb_frontend *fe_slave;
+	u16 data_dib190[10] = {
+		1, 0x5374,
+		2, 0x01ae,
+		7, 0x0020,
+		0, 0x00ef,
+		8, 0x0406,
+	};
+	i2c = dib9000_get_tuner_interface(adap->fe_adap[0].fe);
+	if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &nim9090md_dib0090_config[0]) == NULL)
+		return -ENODEV;
+	i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
+	if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0)
+		return -ENODEV;
+
+	dib0700_set_i2c_speed(adap->dev, 1500);
+	if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0)
+		return -ENODEV;
+
+	fe_slave = dib9000_get_slave_frontend(adap->fe_adap[0].fe, 1);
+	if (fe_slave != NULL) {
+		i2c = dib9000_get_component_bus_interface(adap->fe_adap[0].fe);
+		dib9000_set_i2c_adapter(fe_slave, i2c);
+
+		i2c = dib9000_get_tuner_interface(fe_slave);
+		if (dvb_attach(dib0090_fw_register, fe_slave, i2c, &nim9090md_dib0090_config[1]) == NULL)
+			return -ENODEV;
+		fe_slave->dvb = adap->fe_adap[0].fe->dvb;
+		dib9000_fw_set_component_bus_speed(adap->fe_adap[0].fe, 1500);
+		if (dib9000_firmware_post_pll_init(fe_slave) < 0)
+			return -ENODEV;
+	}
+	release_firmware(state->frontend_firmware);
+
+	return 0;
+}
+
+/* NIM7090 */
+struct dib7090p_best_adc {
+	u32 timf;
+	u32 pll_loopdiv;
+	u32 pll_prediv;
+};
+
+static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_best_adc *adc)
+{
+	u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1;
+
+	u16 xtal = 12000;
+	u32 fcp_min = 1900;  /* PLL Minimum Frequency comparator KHz */
+	u32 fcp_max = 20000; /* PLL Maximum Frequency comparator KHz */
+	u32 fdem_max = 76000;
+	u32 fdem_min = 69500;
+	u32 fcp = 0, fs = 0, fdem = 0;
+	u32 harmonic_id = 0;
+
+	adc->pll_loopdiv = loopdiv;
+	adc->pll_prediv = prediv;
+	adc->timf = 0;
+
+	deb_info("bandwidth = %d fdem_min =%d", fe->dtv_property_cache.bandwidth_hz, fdem_min);
+
+	/* Find Min and Max prediv */
+	while ((xtal/max_prediv) >= fcp_min)
+		max_prediv++;
+
+	max_prediv--;
+	min_prediv = max_prediv;
+	while ((xtal/min_prediv) <= fcp_max) {
+		min_prediv--;
+		if (min_prediv == 1)
+			break;
+	}
+	deb_info("MIN prediv = %d : MAX prediv = %d", min_prediv, max_prediv);
+
+	min_prediv = 2;
+
+	for (prediv = min_prediv ; prediv < max_prediv; prediv++) {
+		fcp = xtal / prediv;
+		if (fcp > fcp_min && fcp < fcp_max) {
+			for (loopdiv = 1 ; loopdiv < 64 ; loopdiv++) {
+				fdem = ((xtal/prediv) * loopdiv);
+				fs   = fdem / 4;
+				/* test min/max system restrictions */
+
+				if ((fdem >= fdem_min) && (fdem <= fdem_max) && (fs >= fe->dtv_property_cache.bandwidth_hz/1000)) {
+					spur = 0;
+					/* test fs harmonics positions */
+					for (harmonic_id = (fe->dtv_property_cache.frequency / (1000*fs)) ;  harmonic_id <= ((fe->dtv_property_cache.frequency / (1000*fs))+1) ; harmonic_id++) {
+						if (((fs*harmonic_id) >= ((fe->dtv_property_cache.frequency/1000) - (fe->dtv_property_cache.bandwidth_hz/2000))) &&  ((fs*harmonic_id) <= ((fe->dtv_property_cache.frequency/1000) + (fe->dtv_property_cache.bandwidth_hz/2000)))) {
+							spur = 1;
+							break;
+						}
+					}
+
+					if (!spur) {
+						adc->pll_loopdiv = loopdiv;
+						adc->pll_prediv = prediv;
+						adc->timf = 2396745143UL/fdem*(1 << 9);
+						adc->timf += ((2396745143UL%fdem) << 9)/fdem;
+						deb_info("loopdiv=%i prediv=%i timf=%i", loopdiv, prediv, adc->timf);
+						break;
+					}
+				}
+			}
+		}
+		if (!spur)
+			break;
+	}
+
+
+	if (adc->pll_loopdiv == 0 && adc->pll_prediv == 0)
+		return -EINVAL;
+	else
+		return 0;
+}
+
+static int dib7090_agc_startup(struct dvb_frontend *fe)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dib0700_adapter_state *state = adap->priv;
+	struct dibx000_bandwidth_config pll;
+	u16 target;
+	struct dib7090p_best_adc adc;
+	int ret;
+
+	ret = state->set_param_save(fe);
+	if (ret < 0)
+		return ret;
+
+	memset(&pll, 0, sizeof(struct dibx000_bandwidth_config));
+	dib0090_pwm_gain_reset(fe);
+	target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2;
+	dib7000p_set_wbd_ref(fe, target);
+
+	if (dib7090p_get_best_sampling(fe, &adc) == 0) {
+		pll.pll_ratio  = adc.pll_loopdiv;
+		pll.pll_prediv = adc.pll_prediv;
+
+		dib7000p_update_pll(fe, &pll);
+		dib7000p_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf);
+	}
+	return 0;
+}
+
+static int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
+{
+	deb_info("AGC restart callback: %d", restart);
+	if (restart == 0) /* before AGC startup */
+		dib0090_set_dc_servo(fe, 1);
+	return 0;
+}
+
+static int dib7090e_update_lna(struct dvb_frontend *fe, u16 agc_global)
+{
+	u16 agc1 = 0, agc2, wbd = 0, wbd_target, wbd_offset, threshold_agc1;
+	s16 wbd_delta;
+
+	if ((fe->dtv_property_cache.frequency) < 400000000)
+		threshold_agc1 = 25000;
+	else
+		threshold_agc1 = 30000;
+
+	wbd_target = (dib0090_get_wbd_target(fe)*8+1)/2;
+	wbd_offset = dib0090_get_wbd_offset(fe);
+	dib7000p_get_agc_values(fe, NULL, &agc1, &agc2, &wbd);
+	wbd_delta = (s16)wbd - (((s16)wbd_offset+10)*4) ;
+
+	deb_info("update lna, agc_global=%d agc1=%d agc2=%d",
+			agc_global, agc1, agc2);
+	deb_info("update lna, wbd=%d wbd target=%d wbd offset=%d wbd delta=%d",
+			wbd, wbd_target, wbd_offset, wbd_delta);
+
+	if ((agc1 < threshold_agc1) && (wbd_delta > 0)) {
+		dib0090_set_switch(fe, 1, 1, 1);
+		dib0090_set_vga(fe, 0);
+		dib0090_update_rframp_7090(fe, 0);
+		dib0090_update_tuning_table_7090(fe, 0);
+	} else {
+		dib0090_set_vga(fe, 1);
+		dib0090_update_rframp_7090(fe, 1);
+		dib0090_update_tuning_table_7090(fe, 1);
+		dib0090_set_switch(fe, 0, 0, 0);
+	}
+
+	return 0;
+}
+
+static struct dib0090_wbd_slope dib7090_wbd_table[] = {
+	{ 380,   81, 850, 64, 540,  4},
+	{ 860,   51, 866, 21,  375, 4},
+	{1700,    0, 250, 0,   100, 6},
+	{2600,    0, 250, 0,   100, 6},
+	{ 0xFFFF, 0,   0, 0,   0,   0},
+};
+
+static struct dib0090_wbd_slope dib7090e_wbd_table[] = {
+	{ 380,   81, 850, 64, 540,	4},
+	{ 700,   51, 866, 21,  320,	4},
+	{ 860,   48, 666, 18,  330,	6},
+	{1700,    0, 250, 0,   100, 6},
+	{2600,    0, 250, 0,   100, 6},
+	{ 0xFFFF, 0,   0, 0,   0,	0},
+};
+
+static struct dibx000_agc_config dib7090_agc_config[2] = {
+	{
+		.band_caps      = BAND_UHF,
+		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+		* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+		.setup          = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+
+		.inv_gain       = 687,
+		.time_stabiliz  = 10,
+
+		.alpha_level    = 0,
+		.thlock         = 118,
+
+		.wbd_inv        = 0,
+		.wbd_ref        = 1200,
+		.wbd_sel        = 3,
+		.wbd_alpha      = 5,
+
+		.agc1_max       = 65535,
+		.agc1_min       = 0,
+
+		.agc2_max       = 65535,
+		.agc2_min       = 0,
+
+		.agc1_pt1       = 0,
+		.agc1_pt2       = 32,
+		.agc1_pt3       = 114,
+		.agc1_slope1    = 143,
+		.agc1_slope2    = 144,
+		.agc2_pt1       = 114,
+		.agc2_pt2       = 227,
+		.agc2_slope1    = 116,
+		.agc2_slope2    = 117,
+
+		.alpha_mant     = 18,
+		.alpha_exp      = 0,
+		.beta_mant      = 20,
+		.beta_exp       = 59,
+
+		.perform_agc_softsplit = 0,
+	} , {
+		.band_caps      = BAND_FM | BAND_VHF | BAND_CBAND,
+		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+		* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+		.setup          = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+
+		.inv_gain       = 732,
+		.time_stabiliz  = 10,
+
+		.alpha_level    = 0,
+		.thlock         = 118,
+
+		.wbd_inv        = 0,
+		.wbd_ref        = 1200,
+		.wbd_sel        = 3,
+		.wbd_alpha      = 5,
+
+		.agc1_max       = 65535,
+		.agc1_min       = 0,
+
+		.agc2_max       = 65535,
+		.agc2_min       = 0,
+
+		.agc1_pt1       = 0,
+		.agc1_pt2       = 0,
+		.agc1_pt3       = 98,
+		.agc1_slope1    = 0,
+		.agc1_slope2    = 167,
+		.agc2_pt1       = 98,
+		.agc2_pt2       = 255,
+		.agc2_slope1    = 104,
+		.agc2_slope2    = 0,
+
+		.alpha_mant     = 18,
+		.alpha_exp      = 0,
+		.beta_mant      = 20,
+		.beta_exp       = 59,
+
+		.perform_agc_softsplit = 0,
+	}
+};
+
+static struct dibx000_bandwidth_config dib7090_clock_config_12_mhz = {
+	60000, 15000,
+	1, 5, 0, 0, 0,
+	0, 0, 1, 1, 2,
+	(3 << 14) | (1 << 12) | (524 << 0),
+	(0 << 25) | 0,
+	20452225,
+	15000000,
+};
+
+static struct dib7000p_config nim7090_dib7000p_config = {
+	.output_mpeg2_in_188_bytes  = 1,
+	.hostbus_diversity			= 1,
+	.tuner_is_baseband			= 1,
+	.update_lna					= NULL,
+
+	.agc_config_count			= 2,
+	.agc						= dib7090_agc_config,
+
+	.bw							= &dib7090_clock_config_12_mhz,
+
+	.gpio_dir					= DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+	.gpio_val					= DIB7000P_GPIO_DEFAULT_VALUES,
+	.gpio_pwm_pos				= DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+	.pwm_freq_div				= 0,
+
+	.agc_control				= dib7090_agc_restart,
+
+	.spur_protect				= 0,
+	.disable_sample_and_hold	= 0,
+	.enable_current_mirror		= 0,
+	.diversity_delay			= 0,
+
+	.output_mode				= OUTMODE_MPEG2_FIFO,
+	.enMpegOutput				= 1,
+};
+
+static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = {
+	{
+		.output_mpeg2_in_188_bytes  = 1,
+		.hostbus_diversity			= 1,
+		.tuner_is_baseband			= 1,
+		.update_lna					= NULL,
+
+		.agc_config_count			= 2,
+		.agc						= dib7090_agc_config,
+
+		.bw							= &dib7090_clock_config_12_mhz,
+
+		.gpio_dir					= DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+		.gpio_val					= DIB7000P_GPIO_DEFAULT_VALUES,
+		.gpio_pwm_pos				= DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+		.pwm_freq_div				= 0,
+
+		.agc_control				= dib7090_agc_restart,
+
+		.spur_protect				= 0,
+		.disable_sample_and_hold	= 0,
+		.enable_current_mirror		= 0,
+		.diversity_delay			= 0,
+
+		.output_mode				= OUTMODE_MPEG2_PAR_GATED_CLK,
+		.default_i2c_addr			= 0x90,
+		.enMpegOutput				= 1,
+	}, {
+		.output_mpeg2_in_188_bytes  = 1,
+		.hostbus_diversity			= 1,
+		.tuner_is_baseband			= 1,
+		.update_lna					= NULL,
+
+		.agc_config_count			= 2,
+		.agc						= dib7090_agc_config,
+
+		.bw							= &dib7090_clock_config_12_mhz,
+
+		.gpio_dir					= DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+		.gpio_val					= DIB7000P_GPIO_DEFAULT_VALUES,
+		.gpio_pwm_pos				= DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+		.pwm_freq_div				= 0,
+
+		.agc_control				= dib7090_agc_restart,
+
+		.spur_protect				= 0,
+		.disable_sample_and_hold	= 0,
+		.enable_current_mirror		= 0,
+		.diversity_delay			= 0,
+
+		.output_mode				= OUTMODE_MPEG2_PAR_GATED_CLK,
+		.default_i2c_addr			= 0x92,
+		.enMpegOutput				= 0,
+	}
+};
+
+static struct dib7000p_config tfe7090e_dib7000p_config = {
+	.output_mpeg2_in_188_bytes  = 1,
+	.hostbus_diversity			= 1,
+	.tuner_is_baseband			= 1,
+	.update_lna					= dib7090e_update_lna,
+
+	.agc_config_count			= 2,
+	.agc						= dib7090_agc_config,
+
+	.bw							= &dib7090_clock_config_12_mhz,
+
+	.gpio_dir					= DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+	.gpio_val					= DIB7000P_GPIO_DEFAULT_VALUES,
+	.gpio_pwm_pos				= DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+	.pwm_freq_div				= 0,
+
+	.agc_control				= dib7090_agc_restart,
+
+	.spur_protect				= 0,
+	.disable_sample_and_hold	= 0,
+	.enable_current_mirror		= 0,
+	.diversity_delay			= 0,
+
+	.output_mode				= OUTMODE_MPEG2_FIFO,
+	.enMpegOutput				= 1,
+};
+
+static const struct dib0090_config nim7090_dib0090_config = {
+	.io.clock_khz = 12000,
+	.io.pll_bypass = 0,
+	.io.pll_range = 0,
+	.io.pll_prediv = 3,
+	.io.pll_loopdiv = 6,
+	.io.adc_clock_ratio = 0,
+	.io.pll_int_loop_filt = 0,
+	.reset = dib7090_tuner_sleep,
+	.sleep = dib7090_tuner_sleep,
+
+	.freq_offset_khz_uhf = 0,
+	.freq_offset_khz_vhf = 0,
+
+	.get_adc_power = dib7090_get_adc_power,
+
+	.clkouttobamse = 1,
+	.analog_output = 0,
+
+	.wbd_vhf_offset = 0,
+	.wbd_cband_offset = 0,
+	.use_pwm_agc = 1,
+	.clkoutdrive = 0,
+
+	.fref_clock_ratio = 0,
+
+	.wbd = dib7090_wbd_table,
+
+	.ls_cfg_pad_drv = 0,
+	.data_tx_drv = 0,
+	.low_if = NULL,
+	.in_soc = 1,
+};
+
+static const struct dib0090_config tfe7090e_dib0090_config = {
+	.io.clock_khz = 12000,
+	.io.pll_bypass = 0,
+	.io.pll_range = 0,
+	.io.pll_prediv = 3,
+	.io.pll_loopdiv = 6,
+	.io.adc_clock_ratio = 0,
+	.io.pll_int_loop_filt = 0,
+	.reset = dib7090_tuner_sleep,
+	.sleep = dib7090_tuner_sleep,
+
+	.freq_offset_khz_uhf = 0,
+	.freq_offset_khz_vhf = 0,
+
+	.get_adc_power = dib7090_get_adc_power,
+
+	.clkouttobamse = 1,
+	.analog_output = 0,
+
+	.wbd_vhf_offset = 0,
+	.wbd_cband_offset = 0,
+	.use_pwm_agc = 1,
+	.clkoutdrive = 0,
+
+	.fref_clock_ratio = 0,
+
+	.wbd = dib7090e_wbd_table,
+
+	.ls_cfg_pad_drv = 0,
+	.data_tx_drv = 0,
+	.low_if = NULL,
+	.in_soc = 1,
+	.force_cband_input = 1,
+	.is_dib7090e = 1,
+};
+
+static struct dib7000p_config tfe7790e_dib7000p_config = {
+	.output_mpeg2_in_188_bytes  = 1,
+	.hostbus_diversity			= 1,
+	.tuner_is_baseband			= 1,
+	.update_lna					= dib7090e_update_lna,
+
+	.agc_config_count			= 2,
+	.agc						= dib7090_agc_config,
+
+	.bw							= &dib7090_clock_config_12_mhz,
+
+	.gpio_dir					= DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+	.gpio_val					= DIB7000P_GPIO_DEFAULT_VALUES,
+	.gpio_pwm_pos				= DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+	.pwm_freq_div				= 0,
+
+	.agc_control				= dib7090_agc_restart,
+
+	.spur_protect				= 0,
+	.disable_sample_and_hold	= 0,
+	.enable_current_mirror		= 0,
+	.diversity_delay			= 0,
+
+	.output_mode				= OUTMODE_MPEG2_PAR_GATED_CLK,
+	.enMpegOutput				= 1,
+};
+
+static const struct dib0090_config tfe7790e_dib0090_config = {
+	.io.clock_khz = 12000,
+	.io.pll_bypass = 0,
+	.io.pll_range = 0,
+	.io.pll_prediv = 3,
+	.io.pll_loopdiv = 6,
+	.io.adc_clock_ratio = 0,
+	.io.pll_int_loop_filt = 0,
+	.reset = dib7090_tuner_sleep,
+	.sleep = dib7090_tuner_sleep,
+
+	.freq_offset_khz_uhf = 0,
+	.freq_offset_khz_vhf = 0,
+
+	.get_adc_power = dib7090_get_adc_power,
+
+	.clkouttobamse = 1,
+	.analog_output = 0,
+
+	.wbd_vhf_offset = 0,
+	.wbd_cband_offset = 0,
+	.use_pwm_agc = 1,
+	.clkoutdrive = 0,
+
+	.fref_clock_ratio = 0,
+
+	.wbd = dib7090e_wbd_table,
+
+	.ls_cfg_pad_drv = 0,
+	.data_tx_drv = 0,
+	.low_if = NULL,
+	.in_soc = 1,
+	.force_cband_input = 1,
+	.is_dib7090e = 1,
+	.force_crystal_mode = 1,
+};
+
+static const struct dib0090_config tfe7090pvr_dib0090_config[2] = {
+	{
+		.io.clock_khz = 12000,
+		.io.pll_bypass = 0,
+		.io.pll_range = 0,
+		.io.pll_prediv = 3,
+		.io.pll_loopdiv = 6,
+		.io.adc_clock_ratio = 0,
+		.io.pll_int_loop_filt = 0,
+		.reset = dib7090_tuner_sleep,
+		.sleep = dib7090_tuner_sleep,
+
+		.freq_offset_khz_uhf = 50,
+		.freq_offset_khz_vhf = 70,
+
+		.get_adc_power = dib7090_get_adc_power,
+
+		.clkouttobamse = 1,
+		.analog_output = 0,
+
+		.wbd_vhf_offset = 0,
+		.wbd_cband_offset = 0,
+		.use_pwm_agc = 1,
+		.clkoutdrive = 0,
+
+		.fref_clock_ratio = 0,
+
+		.wbd = dib7090_wbd_table,
+
+		.ls_cfg_pad_drv = 0,
+		.data_tx_drv = 0,
+		.low_if = NULL,
+		.in_soc = 1,
+	}, {
+		.io.clock_khz = 12000,
+		.io.pll_bypass = 0,
+		.io.pll_range = 0,
+		.io.pll_prediv = 3,
+		.io.pll_loopdiv = 6,
+		.io.adc_clock_ratio = 0,
+		.io.pll_int_loop_filt = 0,
+		.reset = dib7090_tuner_sleep,
+		.sleep = dib7090_tuner_sleep,
+
+		.freq_offset_khz_uhf = -50,
+		.freq_offset_khz_vhf = -70,
+
+		.get_adc_power = dib7090_get_adc_power,
+
+		.clkouttobamse = 1,
+		.analog_output = 0,
+
+		.wbd_vhf_offset = 0,
+		.wbd_cband_offset = 0,
+		.use_pwm_agc = 1,
+		.clkoutdrive = 0,
+
+		.fref_clock_ratio = 0,
+
+		.wbd = dib7090_wbd_table,
+
+		.ls_cfg_pad_drv = 0,
+		.data_tx_drv = 0,
+		.low_if = NULL,
+		.in_soc = 1,
+	}
+};
+
+static int nim7090_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) {
+		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
+		return -ENODEV;
+	}
+	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config);
+
+	return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
+}
+
+static int nim7090_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *st = adap->priv;
+	struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
+
+	if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &nim7090_dib0090_config) == NULL)
+		return -ENODEV;
+
+	dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+
+	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+	return 0;
+}
+
+static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_state *st = adap->dev->priv;
+
+	/* The TFE7090 requires the dib0700 to not be in master mode */
+	st->disable_streaming_master_mode = 1;
+
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	/* initialize IC 0 */
+	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) {
+		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
+		return -ENODEV;
+	}
+
+	dib0700_set_i2c_speed(adap->dev, 340);
+	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]);
+	if (adap->fe_adap[0].fe == NULL)
+		return -ENODEV;
+
+	dib7090_slave_reset(adap->fe_adap[0].fe);
+
+	return 0;
+}
+
+static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap)
+{
+	struct i2c_adapter *i2c;
+
+	if (adap->dev->adapter[0].fe_adap[0].fe == NULL) {
+		err("the master dib7090 has to be initialized first");
+		return -ENODEV; /* the master device has not been initialized */
+	}
+
+	i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1);
+	if (dib7000p_i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) {
+		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
+		return -ENODEV;
+	}
+
+	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]);
+	dib0700_set_i2c_speed(adap->dev, 200);
+
+	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+static int tfe7090pvr_tuner0_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *st = adap->priv;
+	struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
+
+	if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL)
+		return -ENODEV;
+
+	dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+
+	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+	return 0;
+}
+
+static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *st = adap->priv;
+	struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
+
+	if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL)
+		return -ENODEV;
+
+	dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+
+	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+	return 0;
+}
+
+static int tfe7090e_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap,
+				1, 0x10, &tfe7090e_dib7000p_config) != 0) {
+		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
+				__func__);
+		return -ENODEV;
+	}
+	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
+			0x80, &tfe7090e_dib7000p_config);
+
+	return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
+}
+
+static int tfe7790e_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_state *st = adap->dev->priv;
+
+	/* The TFE7790E requires the dib0700 to not be in master mode */
+	st->disable_streaming_master_mode = 1;
+
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+	msleep(20);
+	dib0700_ctrl_clock(adap->dev, 72, 1);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap,
+				1, 0x10, &tfe7790e_dib7000p_config) != 0) {
+		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
+				__func__);
+		return -ENODEV;
+	}
+	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
+			0x80, &tfe7790e_dib7000p_config);
+
+	return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
+}
+
+static int tfe7790e_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *st = adap->priv;
+	struct i2c_adapter *tun_i2c =
+		dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
+
+	if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
+				&tfe7790e_dib0090_config) == NULL)
+		return -ENODEV;
+
+	dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+
+	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+	return 0;
+}
+
+static int tfe7090e_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *st = adap->priv;
+	struct i2c_adapter *tun_i2c =
+		dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
+
+	if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
+				&tfe7090e_dib0090_config) == NULL)
+		return -ENODEV;
+
+	dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+
+	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+	return 0;
+}
+
+/* STK7070PD */
+static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
+	{
+		.output_mpeg2_in_188_bytes = 1,
+
+		.agc_config_count = 1,
+		.agc = &dib7070_agc_config,
+		.bw  = &dib7070_bw_config_12_mhz,
+		.tuner_is_baseband = 1,
+		.spur_protect = 1,
+
+		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+		.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+		.hostbus_diversity = 1,
+	}, {
+		.output_mpeg2_in_188_bytes = 1,
+
+		.agc_config_count = 1,
+		.agc = &dib7070_agc_config,
+		.bw  = &dib7070_bw_config_12_mhz,
+		.tuner_is_baseband = 1,
+		.spur_protect = 1,
+
+		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+		.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+		.hostbus_diversity = 1,
+	}
+};
+
+static void stk7070pd_init(struct dvb_usb_device *dev)
+{
+	dib0700_set_gpio(dev, GPIO6, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(dev, GPIO7, GPIO_OUT, 1);
+	dib0700_set_gpio(dev, GPIO10, GPIO_OUT, 0);
+
+	dib0700_ctrl_clock(dev, 72, 1);
+
+	msleep(10);
+	dib0700_set_gpio(dev, GPIO10, GPIO_OUT, 1);
+}
+
+static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap)
+{
+	stk7070pd_init(adap->dev);
+
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18,
+				     stk7070pd_dib7000p_config) != 0) {
+		err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
+		    __func__);
+		return -ENODEV;
+	}
+
+	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]);
+	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap)
+{
+	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]);
+	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+static int novatd_read_status_override(struct dvb_frontend *fe,
+		fe_status_t *stat)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dvb_usb_device *dev = adap->dev;
+	struct dib0700_state *state = dev->priv;
+	int ret;
+
+	ret = state->read_status(fe, stat);
+
+	if (!ret)
+		dib0700_set_gpio(dev, adap->id == 0 ? GPIO1 : GPIO0, GPIO_OUT,
+				!!(*stat & FE_HAS_LOCK));
+
+	return ret;
+}
+
+static int novatd_sleep_override(struct dvb_frontend* fe)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dvb_usb_device *dev = adap->dev;
+	struct dib0700_state *state = dev->priv;
+
+	/* turn off LED */
+	dib0700_set_gpio(dev, adap->id == 0 ? GPIO1 : GPIO0, GPIO_OUT, 0);
+
+	return state->sleep(fe);
+}
+
+/**
+ * novatd_frontend_attach - Nova-TD specific attach
+ *
+ * Nova-TD has GPIO0, 1 and 2 for LEDs. So do not fiddle with them except for
+ * information purposes.
+ */
+static int novatd_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *dev = adap->dev;
+	struct dib0700_state *st = dev->priv;
+
+	if (adap->id == 0) {
+		stk7070pd_init(dev);
+
+		/* turn the power LED on, the other two off (just in case) */
+		dib0700_set_gpio(dev, GPIO0, GPIO_OUT, 0);
+		dib0700_set_gpio(dev, GPIO1, GPIO_OUT, 0);
+		dib0700_set_gpio(dev, GPIO2, GPIO_OUT, 1);
+
+		if (dib7000p_i2c_enumeration(&dev->i2c_adap, 2, 18,
+					     stk7070pd_dib7000p_config) != 0) {
+			err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
+			    __func__);
+			return -ENODEV;
+		}
+	}
+
+	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &dev->i2c_adap,
+			adap->id == 0 ? 0x80 : 0x82,
+			&stk7070pd_dib7000p_config[adap->id]);
+
+	if (adap->fe_adap[0].fe == NULL)
+		return -ENODEV;
+
+	st->read_status = adap->fe_adap[0].fe->ops.read_status;
+	adap->fe_adap[0].fe->ops.read_status = novatd_read_status_override;
+	st->sleep = adap->fe_adap[0].fe->ops.sleep;
+	adap->fe_adap[0].fe->ops.sleep = novatd_sleep_override;
+
+	return 0;
+}
+
+/* S5H1411 */
+static struct s5h1411_config pinnacle_801e_config = {
+	.output_mode   = S5H1411_PARALLEL_OUTPUT,
+	.gpio          = S5H1411_GPIO_OFF,
+	.mpeg_timing   = S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK,
+	.qam_if        = S5H1411_IF_44000,
+	.vsb_if        = S5H1411_IF_44000,
+	.inversion     = S5H1411_INVERSION_OFF,
+	.status_mode   = S5H1411_DEMODLOCKING
+};
+
+/* Pinnacle PCTV HD Pro 801e GPIOs map:
+   GPIO0  - currently unknown
+   GPIO1  - xc5000 tuner reset
+   GPIO2  - CX25843 sleep
+   GPIO3  - currently unknown
+   GPIO4  - currently unknown
+   GPIO6  - currently unknown
+   GPIO7  - currently unknown
+   GPIO9  - currently unknown
+   GPIO10 - CX25843 reset
+ */
+static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_state *st = adap->dev->priv;
+
+	/* Make use of the new i2c functions from FW 1.20 */
+	st->fw_use_new_i2c_api = 1;
+
+	/* The s5h1411 requires the dib0700 to not be in master mode */
+	st->disable_streaming_master_mode = 1;
+
+	/* All msleep values taken from Windows USB trace */
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0);
+	dib0700_set_gpio(adap->dev, GPIO3, GPIO_OUT, 0);
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(400);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+	msleep(60);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(30);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 0);
+	msleep(30);
+
+	/* Put the CX25843 to sleep for now since we're in digital mode */
+	dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1);
+
+	/* GPIOs are initialized, do the attach */
+	adap->fe_adap[0].fe = dvb_attach(s5h1411_attach, &pinnacle_801e_config,
+			      &adap->dev->i2c_adap);
+	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+static int dib0700_xc5000_tuner_callback(void *priv, int component,
+					 int command, int arg)
+{
+	struct dvb_usb_adapter *adap = priv;
+
+	if (command == XC5000_TUNER_RESET) {
+		/* Reset the tuner */
+		dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0);
+		msleep(10);
+		dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1);
+		msleep(10);
+	} else {
+		err("xc5000: unknown tuner callback command: %d\n", command);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct xc5000_config s5h1411_xc5000_tunerconfig = {
+	.i2c_address      = 0x64,
+	.if_khz           = 5380,
+};
+
+static int xc5000_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	/* FIXME: generalize & move to common area */
+	adap->fe_adap[0].fe->callback = dib0700_xc5000_tuner_callback;
+
+	return dvb_attach(xc5000_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
+			  &s5h1411_xc5000_tunerconfig)
+		== NULL ? -ENODEV : 0;
+}
+
+static int dib0700_xc4000_tuner_callback(void *priv, int component,
+					 int command, int arg)
+{
+	struct dvb_usb_adapter *adap = priv;
+
+	if (command == XC4000_TUNER_RESET) {
+		/* Reset the tuner */
+		dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 0);
+		msleep(10);
+		dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+	} else {
+		err("xc4000: unknown tuner callback command: %d\n", command);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct dibx000_agc_config stk7700p_7000p_xc4000_agc_config = {
+	.band_caps = BAND_UHF | BAND_VHF,
+	.setup = 0x64,
+	.inv_gain = 0x02c8,
+	.time_stabiliz = 0x15,
+	.alpha_level = 0x00,
+	.thlock = 0x76,
+	.wbd_inv = 0x01,
+	.wbd_ref = 0x0b33,
+	.wbd_sel = 0x00,
+	.wbd_alpha = 0x02,
+	.agc1_max = 0x00,
+	.agc1_min = 0x00,
+	.agc2_max = 0x9b26,
+	.agc2_min = 0x26ca,
+	.agc1_pt1 = 0x00,
+	.agc1_pt2 = 0x00,
+	.agc1_pt3 = 0x00,
+	.agc1_slope1 = 0x00,
+	.agc1_slope2 = 0x00,
+	.agc2_pt1 = 0x00,
+	.agc2_pt2 = 0x80,
+	.agc2_slope1 = 0x1d,
+	.agc2_slope2 = 0x1d,
+	.alpha_mant = 0x11,
+	.alpha_exp = 0x1b,
+	.beta_mant = 0x17,
+	.beta_exp = 0x33,
+	.perform_agc_softsplit = 0x00,
+};
+
+static struct dibx000_bandwidth_config stk7700p_xc4000_pll_config = {
+	60000, 30000,	/* internal, sampling */
+	1, 8, 3, 1, 0,	/* pll_cfg: prediv, ratio, range, reset, bypass */
+	0, 0, 1, 1, 0,	/* misc: refdiv, bypclk_div, IO_CLK_en_core, */
+			/* ADClkSrc, modulo */
+	(3 << 14) | (1 << 12) | 524,	/* sad_cfg: refsel, sel, freq_15k */
+	39370534,	/* ifreq */
+	20452225,	/* timf */
+	30000000	/* xtal */
+};
+
+/* FIXME: none of these inputs are validated yet */
+static struct dib7000p_config pctv_340e_config = {
+	.output_mpeg2_in_188_bytes = 1,
+
+	.agc_config_count = 1,
+	.agc = &stk7700p_7000p_xc4000_agc_config,
+	.bw  = &stk7700p_xc4000_pll_config,
+
+	.gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
+	.gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
+	.gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
+};
+
+/* PCTV 340e GPIOs map:
+   dib0700:
+   GPIO2  - CX25843 sleep
+   GPIO3  - CS5340 reset
+   GPIO5  - IRD
+   GPIO6  - Power Supply
+   GPIO8  - LNA (1=off 0=on)
+   GPIO10 - CX25843 reset
+   dib7000:
+   GPIO8  - xc4000 reset
+ */
+static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_state *st = adap->dev->priv;
+
+	/* Power Supply on */
+	dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 0);
+	msleep(50);
+	dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 1);
+	msleep(100); /* Allow power supply to settle before probing */
+
+	/* cx25843 reset */
+	dib0700_set_gpio(adap->dev, GPIO10,  GPIO_OUT, 0);
+	msleep(1); /* cx25843 datasheet say 350us required */
+	dib0700_set_gpio(adap->dev, GPIO10,  GPIO_OUT, 1);
+
+	/* LNA off for now */
+	dib0700_set_gpio(adap->dev, GPIO8,  GPIO_OUT, 1);
+
+	/* Put the CX25843 to sleep for now since we're in digital mode */
+	dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1);
+
+	/* FIXME: not verified yet */
+	dib0700_ctrl_clock(adap->dev, 72, 1);
+
+	msleep(500);
+
+	if (dib7000pc_detection(&adap->dev->i2c_adap) == 0) {
+		/* Demodulator not found for some reason? */
+		return -ENODEV;
+	}
+
+	adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12,
+			      &pctv_340e_config);
+	st->is_dib7000pc = 1;
+
+	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+static struct xc4000_config dib7000p_xc4000_tunerconfig = {
+	.i2c_address	  = 0x61,
+	.default_pm	  = 1,
+	.dvb_amplitude	  = 0,
+	.set_smoothedcvbs = 0,
+	.if_khz		  = 5400
+};
+
+static int xc4000_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct i2c_adapter *tun_i2c;
+
+	/* The xc4000 is not on the main i2c bus */
+	tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe,
+					  DIBX000_I2C_INTERFACE_TUNER, 1);
+	if (tun_i2c == NULL) {
+		printk(KERN_ERR "Could not reach tuner i2c bus\n");
+		return 0;
+	}
+
+	/* Setup the reset callback */
+	adap->fe_adap[0].fe->callback = dib0700_xc4000_tuner_callback;
+
+	return dvb_attach(xc4000_attach, adap->fe_adap[0].fe, tun_i2c,
+			  &dib7000p_xc4000_tunerconfig)
+		== NULL ? -ENODEV : 0;
+}
+
+static struct lgdt3305_config hcw_lgdt3305_config = {
+	.i2c_addr           = 0x0e,
+	.mpeg_mode          = LGDT3305_MPEG_PARALLEL,
+	.tpclk_edge         = LGDT3305_TPCLK_FALLING_EDGE,
+	.tpvalid_polarity   = LGDT3305_TP_VALID_LOW,
+	.deny_i2c_rptr      = 0,
+	.spectral_inversion = 1,
+	.qam_if_khz         = 6000,
+	.vsb_if_khz         = 6000,
+	.usref_8vsb         = 0x0500,
+};
+
+static struct mxl5007t_config hcw_mxl5007t_config = {
+	.xtal_freq_hz = MxL_XTAL_25_MHZ,
+	.if_freq_hz = MxL_IF_6_MHZ,
+	.invert_if = 1,
+};
+
+/* TIGER-ATSC map:
+   GPIO0  - LNA_CTR  (H: LNA power enabled, L: LNA power disabled)
+   GPIO1  - ANT_SEL  (H: VPA, L: MCX)
+   GPIO4  - SCL2
+   GPIO6  - EN_TUNER
+   GPIO7  - SDA2
+   GPIO10 - DEM_RST
+
+   MXL is behind LG's i2c repeater.  LG is on SCL2/SDA2 gpios on the DIB
+ */
+static int lgdt3305_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_state *st = adap->dev->priv;
+
+	/* Make use of the new i2c functions from FW 1.20 */
+	st->fw_use_new_i2c_api = 1;
+
+	st->disable_streaming_master_mode = 1;
+
+	/* fe power enable */
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
+	msleep(30);
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(30);
+
+	/* demod reset */
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(30);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+	msleep(30);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(30);
+
+	adap->fe_adap[0].fe = dvb_attach(lgdt3305_attach,
+			      &hcw_lgdt3305_config,
+			      &adap->dev->i2c_adap);
+
+	return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+static int mxl5007t_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	return dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe,
+			  &adap->dev->i2c_adap, 0x60,
+			  &hcw_mxl5007t_config) == NULL ? -ENODEV : 0;
+}
+
+
+/* DVB-USB and USB stuff follows */
+struct usb_device_id dib0700_usb_id_table[] = {
+/* 0 */	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P) },
+	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P_PC) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) },
+/* 5 */	{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
+	{ USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500) },
+	{ USB_DEVICE(USB_VID_UNIWILL,   USB_PID_UNIWILL_STK7700P) },
+	{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) },
+/* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
+	{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV2000E) },
+	{ USB_DEVICE(USB_VID_TERRATEC,
+			USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) },
+	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700D) },
+/* 15 */{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7070P) },
+	{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV_DVB_T_FLASH) },
+	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7070PD) },
+	{ USB_DEVICE(USB_VID_PINNACLE,
+			USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) },
+	{ USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500_PC) },
+/* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) },
+	{ USB_DEVICE(USB_VID_GIGABYTE,  USB_PID_GIGABYTE_U7000) },
+	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) },
+	{ USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3000) },
+	{ USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3100) },
+/* 25 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) },
+	{ USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_CINERGY_HT_USB_XE) },
+	{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_EXPRESSCARD_320CX) },
+	{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV72E) },
+/* 30 */{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV73E) },
+	{ USB_DEVICE(USB_VID_YUAN,	USB_PID_YUAN_EC372S) },
+	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_HT_EXPRESS) },
+	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_T_XXS) },
+	{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) },
+/* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) },
+	{ USB_DEVICE(USB_VID_GIGABYTE,  USB_PID_GIGABYTE_U8000) },
+	{ USB_DEVICE(USB_VID_YUAN,      USB_PID_YUAN_STK7700PH) },
+	{ USB_DEVICE(USB_VID_ASUS,	USB_PID_ASUS_U3000H) },
+/* 40 */{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV801E) },
+	{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV801E_SE) },
+	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_T_EXPRESS) },
+	{ USB_DEVICE(USB_VID_TERRATEC,
+			USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2) },
+	{ USB_DEVICE(USB_VID_SONY,	USB_PID_SONY_PLAYTV) },
+/* 45 */{ USB_DEVICE(USB_VID_YUAN,      USB_PID_YUAN_PD378S) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC_B210) },
+	{ USB_DEVICE(USB_VID_YUAN,	USB_PID_YUAN_MC770) },
+	{ USB_DEVICE(USB_VID_ELGATO,	USB_PID_ELGATO_EYETV_DTT) },
+/* 50 */{ USB_DEVICE(USB_VID_ELGATO,	USB_PID_ELGATO_EYETV_DTT_Dlx) },
+	{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_H) },
+	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_T3) },
+	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_T5) },
+	{ USB_DEVICE(USB_VID_YUAN,      USB_PID_YUAN_STK7700D) },
+/* 55 */{ USB_DEVICE(USB_VID_YUAN,	USB_PID_YUAN_STK7700D_2) },
+	{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV73A) },
+	{ USB_DEVICE(USB_VID_PCTV,	USB_PID_PINNACLE_PCTV73ESE) },
+	{ USB_DEVICE(USB_VID_PCTV,	USB_PID_PINNACLE_PCTV282E) },
+	{ USB_DEVICE(USB_VID_DIBCOM,	USB_PID_DIBCOM_STK7770P) },
+/* 60 */{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_T_XXS_2) },
+	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK807XPVR) },
+	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK807XP) },
+	{ USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x000, 0x3f00) },
+	{ USB_DEVICE(USB_VID_EVOLUTEPC, USB_PID_TVWAY_PLUS) },
+/* 65 */{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV73ESE) },
+	{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV282E) },
+	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK8096GP) },
+	{ USB_DEVICE(USB_VID_ELGATO,    USB_PID_ELGATO_EYETV_DIVERSITY) },
+	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_NIM9090M) },
+/* 70 */{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_NIM8096MD) },
+	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_NIM9090MD) },
+	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_NIM7090) },
+	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE7090PVR) },
+	{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2) },
+/* 75 */{ USB_DEVICE(USB_VID_MEDION,    USB_PID_CREATIX_CTX1921) },
+	{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV340E) },
+	{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV340E_SE) },
+	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE7090E) },
+	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE7790E) },
+/* 80 */{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE8096P) },
+	{ USB_DEVICE(USB_VID_ELGATO,	USB_PID_ELGATO_EYETV_DTT_2) },
+	{ 0 }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
+
+#define DIB0700_DEFAULT_DEVICE_PROPERTIES \
+	.caps              = DVB_USB_IS_AN_I2C_ADAPTER, \
+	.usb_ctrl          = DEVICE_SPECIFIC, \
+	.firmware          = "dvb-usb-dib0700-1.20.fw", \
+	.download_firmware = dib0700_download_firmware, \
+	.no_reconnect      = 1, \
+	.size_of_priv      = sizeof(struct dib0700_state), \
+	.i2c_algo          = &dib0700_i2c_algo, \
+	.identify_state    = dib0700_identify_state
+
+#define DIB0700_DEFAULT_STREAMING_CONFIG(ep) \
+	.streaming_ctrl   = dib0700_streaming_ctrl, \
+	.stream = { \
+		.type = USB_BULK, \
+		.count = 4, \
+		.endpoint = ep, \
+		.u = { \
+			.bulk = { \
+				.buffersize = 39480, \
+			} \
+		} \
+	}
+
+struct dvb_usb_device_properties dib0700_devices[] = {
+	{
+		DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 1,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk7700p_pid_filter,
+				.pid_filter_ctrl  = stk7700p_pid_filter_ctrl,
+				.frontend_attach  = stk7700p_frontend_attach,
+				.tuner_attach     = stk7700p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+			},
+		},
+
+		.num_device_descs = 8,
+		.devices = {
+			{   "DiBcom STK7700P reference design",
+				{ &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] },
+				{ NULL },
+			},
+			{   "Hauppauge Nova-T Stick",
+				{ &dib0700_usb_id_table[4], &dib0700_usb_id_table[9], NULL },
+				{ NULL },
+			},
+			{   "AVerMedia AVerTV DVB-T Volar",
+				{ &dib0700_usb_id_table[5], &dib0700_usb_id_table[10] },
+				{ NULL },
+			},
+			{   "Compro Videomate U500",
+				{ &dib0700_usb_id_table[6], &dib0700_usb_id_table[19] },
+				{ NULL },
+			},
+			{   "Uniwill STK7700P based (Hama and others)",
+				{ &dib0700_usb_id_table[7], NULL },
+				{ NULL },
+			},
+			{   "Leadtek Winfast DTV Dongle (STK7700P based)",
+				{ &dib0700_usb_id_table[8], &dib0700_usb_id_table[34] },
+				{ NULL },
+			},
+			{   "AVerMedia AVerTV DVB-T Express",
+				{ &dib0700_usb_id_table[20] },
+				{ NULL },
+			},
+			{   "Gigabyte U7000",
+				{ &dib0700_usb_id_table[21], NULL },
+				{ NULL },
+			}
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 2,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.frontend_attach  = bristol_frontend_attach,
+				.tuner_attach     = bristol_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+			}, {
+			.num_frontends = 1,
+			.fe = {{
+				.frontend_attach  = bristol_frontend_attach,
+				.tuner_attach     = bristol_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+			}},
+			}
+		},
+
+		.num_device_descs = 1,
+		.devices = {
+			{   "Hauppauge Nova-T 500 Dual DVB-T",
+				{ &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 2,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = stk7700d_frontend_attach,
+				.tuner_attach     = stk7700d_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+			}, {
+			.num_frontends = 1,
+			.fe = {{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = stk7700d_frontend_attach,
+				.tuner_attach     = stk7700d_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+			}},
+			}
+		},
+
+		.num_device_descs = 5,
+		.devices = {
+			{   "Pinnacle PCTV 2000e",
+				{ &dib0700_usb_id_table[11], NULL },
+				{ NULL },
+			},
+			{   "Terratec Cinergy DT XS Diversity",
+				{ &dib0700_usb_id_table[12], NULL },
+				{ NULL },
+			},
+			{   "Hauppauge Nova-TD Stick/Elgato Eye-TV Diversity",
+				{ &dib0700_usb_id_table[13], NULL },
+				{ NULL },
+			},
+			{   "DiBcom STK7700D reference design",
+				{ &dib0700_usb_id_table[14], NULL },
+				{ NULL },
+			},
+			{   "YUAN High-Tech DiBcom STK7700D",
+				{ &dib0700_usb_id_table[55], NULL },
+				{ NULL },
+			},
+
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 1,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = stk7700P2_frontend_attach,
+				.tuner_attach     = stk7700d_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+			},
+		},
+
+		.num_device_descs = 3,
+		.devices = {
+			{   "ASUS My Cinema U3000 Mini DVBT Tuner",
+				{ &dib0700_usb_id_table[23], NULL },
+				{ NULL },
+			},
+			{   "Yuan EC372S",
+				{ &dib0700_usb_id_table[31], NULL },
+				{ NULL },
+			},
+			{   "Terratec Cinergy T Express",
+				{ &dib0700_usb_id_table[42], NULL },
+				{ NULL },
+			}
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 1,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = stk7070p_frontend_attach,
+				.tuner_attach     = dib7070p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv     = sizeof(struct dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 12,
+		.devices = {
+			{   "DiBcom STK7070P reference design",
+				{ &dib0700_usb_id_table[15], NULL },
+				{ NULL },
+			},
+			{   "Pinnacle PCTV DVB-T Flash Stick",
+				{ &dib0700_usb_id_table[16], NULL },
+				{ NULL },
+			},
+			{   "Artec T14BR DVB-T",
+				{ &dib0700_usb_id_table[22], NULL },
+				{ NULL },
+			},
+			{   "ASUS My Cinema U3100 Mini DVBT Tuner",
+				{ &dib0700_usb_id_table[24], NULL },
+				{ NULL },
+			},
+			{   "Hauppauge Nova-T Stick",
+				{ &dib0700_usb_id_table[25], NULL },
+				{ NULL },
+			},
+			{   "Hauppauge Nova-T MyTV.t",
+				{ &dib0700_usb_id_table[26], NULL },
+				{ NULL },
+			},
+			{   "Pinnacle PCTV 72e",
+				{ &dib0700_usb_id_table[29], NULL },
+				{ NULL },
+			},
+			{   "Pinnacle PCTV 73e",
+				{ &dib0700_usb_id_table[30], NULL },
+				{ NULL },
+			},
+			{   "Elgato EyeTV DTT",
+				{ &dib0700_usb_id_table[49], NULL },
+				{ NULL },
+			},
+			{   "Yuan PD378S",
+				{ &dib0700_usb_id_table[45], NULL },
+				{ NULL },
+			},
+			{   "Elgato EyeTV Dtt Dlx PD378S",
+				{ &dib0700_usb_id_table[50], NULL },
+				{ NULL },
+			},
+			{   "Elgato EyeTV DTT rev. 2",
+				{ &dib0700_usb_id_table[81], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 1,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = stk7070p_frontend_attach,
+				.tuner_attach     = dib7070p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv     = sizeof(struct dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 3,
+		.devices = {
+			{   "Pinnacle PCTV 73A",
+				{ &dib0700_usb_id_table[56], NULL },
+				{ NULL },
+			},
+			{   "Pinnacle PCTV 73e SE",
+				{ &dib0700_usb_id_table[57], &dib0700_usb_id_table[65], NULL },
+				{ NULL },
+			},
+			{   "Pinnacle PCTV 282e",
+				{ &dib0700_usb_id_table[58], &dib0700_usb_id_table[66], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 2,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = novatd_frontend_attach,
+				.tuner_attach     = dib7070p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv     = sizeof(struct dib0700_adapter_state),
+			}, {
+			.num_frontends = 1,
+			.fe = {{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = novatd_frontend_attach,
+				.tuner_attach     = dib7070p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+			}},
+				.size_of_priv     = sizeof(struct dib0700_adapter_state),
+			}
+		},
+
+		.num_device_descs = 1,
+		.devices = {
+			{   "Hauppauge Nova-TD Stick (52009)",
+				{ &dib0700_usb_id_table[35], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 2,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = stk7070pd_frontend_attach0,
+				.tuner_attach     = dib7070p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv     = sizeof(struct dib0700_adapter_state),
+			}, {
+			.num_frontends = 1,
+			.fe = {{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = stk7070pd_frontend_attach1,
+				.tuner_attach     = dib7070p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+			}},
+				.size_of_priv     = sizeof(struct dib0700_adapter_state),
+			}
+		},
+
+		.num_device_descs = 5,
+		.devices = {
+			{   "DiBcom STK7070PD reference design",
+				{ &dib0700_usb_id_table[17], NULL },
+				{ NULL },
+			},
+			{   "Pinnacle PCTV Dual DVB-T Diversity Stick",
+				{ &dib0700_usb_id_table[18], NULL },
+				{ NULL },
+			},
+			{   "Hauppauge Nova-TD-500 (84xxx)",
+				{ &dib0700_usb_id_table[36], NULL },
+				{ NULL },
+			},
+			{  "Terratec Cinergy DT USB XS Diversity/ T5",
+				{ &dib0700_usb_id_table[43],
+					&dib0700_usb_id_table[53], NULL},
+				{ NULL },
+			},
+			{  "Sony PlayTV",
+				{ &dib0700_usb_id_table[44], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 2,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = stk7070pd_frontend_attach0,
+				.tuner_attach     = dib7070p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv     = sizeof(struct dib0700_adapter_state),
+			}, {
+			.num_frontends = 1,
+			.fe = {{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = stk7070pd_frontend_attach1,
+				.tuner_attach     = dib7070p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+			}},
+				.size_of_priv     = sizeof(struct dib0700_adapter_state),
+			}
+		},
+
+		.num_device_descs = 1,
+		.devices = {
+			{   "Elgato EyeTV Diversity",
+				{ &dib0700_usb_id_table[68], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_NEC_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 1,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = stk7700ph_frontend_attach,
+				.tuner_attach     = stk7700ph_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv = sizeof(struct
+						dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 9,
+		.devices = {
+			{   "Terratec Cinergy HT USB XE",
+				{ &dib0700_usb_id_table[27], NULL },
+				{ NULL },
+			},
+			{   "Pinnacle Expresscard 320cx",
+				{ &dib0700_usb_id_table[28], NULL },
+				{ NULL },
+			},
+			{   "Terratec Cinergy HT Express",
+				{ &dib0700_usb_id_table[32], NULL },
+				{ NULL },
+			},
+			{   "Gigabyte U8000-RH",
+				{ &dib0700_usb_id_table[37], NULL },
+				{ NULL },
+			},
+			{   "YUAN High-Tech STK7700PH",
+				{ &dib0700_usb_id_table[38], NULL },
+				{ NULL },
+			},
+			{   "Asus My Cinema-U3000Hybrid",
+				{ &dib0700_usb_id_table[39], NULL },
+				{ NULL },
+			},
+			{   "YUAN High-Tech MC770",
+				{ &dib0700_usb_id_table[48], NULL },
+				{ NULL },
+			},
+			{   "Leadtek WinFast DTV Dongle H",
+				{ &dib0700_usb_id_table[51], NULL },
+				{ NULL },
+			},
+			{   "YUAN High-Tech STK7700D",
+				{ &dib0700_usb_id_table[54], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+		.num_adapters = 1,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.frontend_attach  = s5h1411_frontend_attach,
+				.tuner_attach     = xc5000_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv = sizeof(struct
+						dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 2,
+		.devices = {
+			{   "Pinnacle PCTV HD Pro USB Stick",
+				{ &dib0700_usb_id_table[40], NULL },
+				{ NULL },
+			},
+			{   "Pinnacle PCTV HD USB Stick",
+				{ &dib0700_usb_id_table[41], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+		.num_adapters = 1,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.frontend_attach  = lgdt3305_frontend_attach,
+				.tuner_attach     = mxl5007t_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv = sizeof(struct
+						dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 2,
+		.devices = {
+			{   "Hauppauge ATSC MiniCard (B200)",
+				{ &dib0700_usb_id_table[46], NULL },
+				{ NULL },
+			},
+			{   "Hauppauge ATSC MiniCard (B210)",
+				{ &dib0700_usb_id_table[47], NULL },
+				{ NULL },
+			},
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 1,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = stk7770p_frontend_attach,
+				.tuner_attach     = dib7770p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv =
+					sizeof(struct dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 4,
+		.devices = {
+			{   "DiBcom STK7770P reference design",
+				{ &dib0700_usb_id_table[59], NULL },
+				{ NULL },
+			},
+			{   "Terratec Cinergy T USB XXS (HD)/ T3",
+				{ &dib0700_usb_id_table[33],
+					&dib0700_usb_id_table[52],
+					&dib0700_usb_id_table[60], NULL},
+				{ NULL },
+			},
+			{   "TechniSat AirStar TeleStick 2",
+				{ &dib0700_usb_id_table[74], NULL },
+				{ NULL },
+			},
+			{   "Medion CTX1921 DVB-T USB",
+				{ &dib0700_usb_id_table[75], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+		.num_adapters = 1,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps  = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter = stk80xx_pid_filter,
+				.pid_filter_ctrl = stk80xx_pid_filter_ctrl,
+				.frontend_attach  = stk807x_frontend_attach,
+				.tuner_attach     = dib807x_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv =
+					sizeof(struct dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 3,
+		.devices = {
+			{   "DiBcom STK807xP reference design",
+				{ &dib0700_usb_id_table[62], NULL },
+				{ NULL },
+			},
+			{   "Prolink Pixelview SBTVD",
+				{ &dib0700_usb_id_table[63], NULL },
+				{ NULL },
+			},
+			{   "EvolutePC TVWay+",
+				{ &dib0700_usb_id_table[64], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_NEC_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+		.num_adapters = 2,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps  = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter = stk80xx_pid_filter,
+				.pid_filter_ctrl = stk80xx_pid_filter_ctrl,
+				.frontend_attach  = stk807xpvr_frontend_attach0,
+				.tuner_attach     = dib807x_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv =
+					sizeof(struct dib0700_adapter_state),
+			},
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps  = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter = stk80xx_pid_filter,
+				.pid_filter_ctrl = stk80xx_pid_filter_ctrl,
+				.frontend_attach  = stk807xpvr_frontend_attach1,
+				.tuner_attach     = dib807x_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+			}},
+				.size_of_priv =
+					sizeof(struct dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 1,
+		.devices = {
+			{   "DiBcom STK807xPVR reference design",
+				{ &dib0700_usb_id_table[61], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+		.num_adapters = 1,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+					DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter = stk80xx_pid_filter,
+				.pid_filter_ctrl = stk80xx_pid_filter_ctrl,
+				.frontend_attach  = stk809x_frontend_attach,
+				.tuner_attach     = dib809x_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv =
+					sizeof(struct dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 1,
+		.devices = {
+			{   "DiBcom STK8096GP reference design",
+				{ &dib0700_usb_id_table[67], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+		.num_adapters = 1,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+					DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter = dib90x0_pid_filter,
+				.pid_filter_ctrl = dib90x0_pid_filter_ctrl,
+				.frontend_attach  = stk9090m_frontend_attach,
+				.tuner_attach     = dib9090_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv =
+					sizeof(struct dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 1,
+		.devices = {
+			{   "DiBcom STK9090M reference design",
+				{ &dib0700_usb_id_table[69], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+		.num_adapters = 1,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+					DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter = stk80xx_pid_filter,
+				.pid_filter_ctrl = stk80xx_pid_filter_ctrl,
+				.frontend_attach  = nim8096md_frontend_attach,
+				.tuner_attach     = nim8096md_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv =
+					sizeof(struct dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 1,
+		.devices = {
+			{   "DiBcom NIM8096MD reference design",
+				{ &dib0700_usb_id_table[70], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+		.num_adapters = 1,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+					DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter = dib90x0_pid_filter,
+				.pid_filter_ctrl = dib90x0_pid_filter_ctrl,
+				.frontend_attach  = nim9090md_frontend_attach,
+				.tuner_attach     = nim9090md_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv =
+					sizeof(struct dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 1,
+		.devices = {
+			{   "DiBcom NIM9090MD reference design",
+				{ &dib0700_usb_id_table[71], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+		.num_adapters = 1,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+					DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter = stk70x0p_pid_filter,
+				.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = nim7090_frontend_attach,
+				.tuner_attach     = nim7090_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv =
+					sizeof(struct dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 1,
+		.devices = {
+			{   "DiBcom NIM7090 reference design",
+				{ &dib0700_usb_id_table[72], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+		.num_adapters = 2,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+					DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter = stk70x0p_pid_filter,
+				.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = tfe7090pvr_frontend0_attach,
+				.tuner_attach     = tfe7090pvr_tuner0_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+			}},
+				.size_of_priv =
+					sizeof(struct dib0700_adapter_state),
+			},
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+					DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter = stk70x0p_pid_filter,
+				.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = tfe7090pvr_frontend1_attach,
+				.tuner_attach     = tfe7090pvr_tuner1_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv =
+					sizeof(struct dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 1,
+		.devices = {
+			{   "DiBcom TFE7090PVR reference design",
+				{ &dib0700_usb_id_table[73], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+		.num_adapters = 1,
+		.adapter = {
+			{
+			.num_frontends = 1,
+			.fe = {{
+				.frontend_attach  = pctv340e_frontend_attach,
+				.tuner_attach     = xc4000_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}},
+				.size_of_priv = sizeof(struct
+						dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 2,
+		.devices = {
+			{   "Pinnacle PCTV 340e HD Pro USB Stick",
+				{ &dib0700_usb_id_table[76], NULL },
+				{ NULL },
+			},
+			{   "Pinnacle PCTV Hybrid Stick Solo",
+				{ &dib0700_usb_id_table[77], NULL },
+				{ NULL },
+			},
+		},
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+		.num_adapters = 1,
+		.adapter = {
+			{
+				.num_frontends = 1,
+				.fe = {{
+					.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+						DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+					.pid_filter_count = 32,
+					.pid_filter = stk70x0p_pid_filter,
+					.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+					.frontend_attach  = tfe7090e_frontend_attach,
+					.tuner_attach     = tfe7090e_tuner_attach,
+
+					DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+				} },
+
+				.size_of_priv =
+					sizeof(struct dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 1,
+		.devices = {
+			{   "DiBcom TFE7090E reference design",
+				{ &dib0700_usb_id_table[78], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+		.num_adapters = 1,
+		.adapter = {
+			{
+				.num_frontends = 1,
+				.fe = {{
+					.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+						DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+					.pid_filter_count = 32,
+					.pid_filter = stk70x0p_pid_filter,
+					.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+					.frontend_attach  = tfe7790e_frontend_attach,
+					.tuner_attach     = tfe7790e_tuner_attach,
+
+					DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+				} },
+
+				.size_of_priv =
+					sizeof(struct dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 1,
+		.devices = {
+			{   "DiBcom TFE7790E reference design",
+				{ &dib0700_usb_id_table[79], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+		.num_adapters = 1,
+		.adapter = {
+			{
+				.num_frontends = 1,
+				.fe = {{
+					.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+						DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+					.pid_filter_count = 32,
+					.pid_filter = stk80xx_pid_filter,
+					.pid_filter_ctrl = stk80xx_pid_filter_ctrl,
+					.frontend_attach  = tfe8096p_frontend_attach,
+					.tuner_attach     = tfe8096p_tuner_attach,
+
+					DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+				} },
+
+				.size_of_priv =
+					sizeof(struct dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 1,
+		.devices = {
+			{   "DiBcom TFE8096P reference design",
+				{ &dib0700_usb_id_table[80], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.allowed_protos   = RC_TYPE_RC5 |
+					    RC_TYPE_RC6 |
+					    RC_TYPE_NEC,
+			.change_protocol  = dib0700_change_protocol,
+		},
+	},
+};
+
+int dib0700_device_count = ARRAY_SIZE(dib0700_devices);
diff --git a/drivers/media/usb/dvb-usb/dib07x0.h b/drivers/media/usb/dvb-usb/dib07x0.h
new file mode 100644
index 0000000..7e62c10
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dib07x0.h
@@ -0,0 +1,21 @@
+#ifndef _DIB07X0_H_
+#define _DIB07X0_H_
+
+enum dib07x0_gpios {
+	GPIO0  =  0,
+	GPIO1  =  2,
+	GPIO2  =  3,
+	GPIO3  =  4,
+	GPIO4  =  5,
+	GPIO5  =  6,
+	GPIO6  =  8,
+	GPIO7  = 10,
+	GPIO8  = 11,
+	GPIO9  = 14,
+	GPIO10 = 15,
+};
+
+#define GPIO_IN  0
+#define GPIO_OUT 1
+
+#endif
diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c
new file mode 100644
index 0000000..a76bbb2
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dibusb-common.c
@@ -0,0 +1,479 @@
+/* Common methods for dibusb-based-receivers.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the Free
+ *	Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS);
+MODULE_LICENSE("GPL");
+
+#define deb_info(args...) dprintk(debug,0x01,args)
+
+/* common stuff used by the different dibusb modules */
+int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	if (adap->priv != NULL) {
+		struct dibusb_state *st = adap->priv;
+		if (st->ops.fifo_ctrl != NULL)
+			if (st->ops.fifo_ctrl(adap->fe_adap[0].fe, onoff)) {
+				err("error while controlling the fifo of the demod.");
+				return -ENODEV;
+			}
+	}
+	return 0;
+}
+EXPORT_SYMBOL(dibusb_streaming_ctrl);
+
+int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
+{
+	if (adap->priv != NULL) {
+		struct dibusb_state *st = adap->priv;
+		if (st->ops.pid_ctrl != NULL)
+			st->ops.pid_ctrl(adap->fe_adap[0].fe,
+					 index, pid, onoff);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(dibusb_pid_filter);
+
+int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	if (adap->priv != NULL) {
+		struct dibusb_state *st = adap->priv;
+		if (st->ops.pid_parse != NULL)
+			if (st->ops.pid_parse(adap->fe_adap[0].fe, onoff) < 0)
+				err("could not handle pid_parser");
+	}
+	return 0;
+}
+EXPORT_SYMBOL(dibusb_pid_filter_ctrl);
+
+int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	u8 b[3];
+	int ret;
+	b[0] = DIBUSB_REQ_SET_IOCTL;
+	b[1] = DIBUSB_IOCTL_CMD_POWER_MODE;
+	b[2] = onoff ? DIBUSB_IOCTL_POWER_WAKEUP : DIBUSB_IOCTL_POWER_SLEEP;
+	ret = dvb_usb_generic_write(d,b,3);
+	msleep(10);
+	return ret;
+}
+EXPORT_SYMBOL(dibusb_power_ctrl);
+
+int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	u8 b[3] = { 0 };
+	int ret;
+
+	if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0)
+		return ret;
+
+	if (onoff) {
+		b[0] = DIBUSB_REQ_SET_STREAMING_MODE;
+		b[1] = 0x00;
+		if ((ret = dvb_usb_generic_write(adap->dev,b,2)) < 0)
+			return ret;
+	}
+
+	b[0] = DIBUSB_REQ_SET_IOCTL;
+	b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM;
+	return dvb_usb_generic_write(adap->dev,b,3);
+}
+EXPORT_SYMBOL(dibusb2_0_streaming_ctrl);
+
+int dibusb2_0_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	if (onoff) {
+		u8 b[3] = { DIBUSB_REQ_SET_IOCTL, DIBUSB_IOCTL_CMD_POWER_MODE, DIBUSB_IOCTL_POWER_WAKEUP };
+		return dvb_usb_generic_write(d,b,3);
+	} else
+		return 0;
+}
+EXPORT_SYMBOL(dibusb2_0_power_ctrl);
+
+static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr,
+			  u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+	u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */
+	/* write only ? */
+	int wo = (rbuf == NULL || rlen == 0),
+		len = 2 + wlen + (wo ? 0 : 2);
+
+	sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ;
+	sndbuf[1] = (addr << 1) | (wo ? 0 : 1);
+
+	memcpy(&sndbuf[2],wbuf,wlen);
+
+	if (!wo) {
+		sndbuf[wlen+2] = (rlen >> 8) & 0xff;
+		sndbuf[wlen+3] = rlen & 0xff;
+	}
+
+	return dvb_usb_generic_rw(d,sndbuf,len,rbuf,rlen,0);
+}
+
+/*
+ * I2C master xfer function
+ */
+static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int i;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		/* write/read request */
+		if (i+1 < num && (msg[i].flags & I2C_M_RD) == 0
+					  && (msg[i+1].flags & I2C_M_RD)) {
+			if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,
+						msg[i+1].buf,msg[i+1].len) < 0)
+				break;
+			i++;
+		} else if ((msg[i].flags & I2C_M_RD) == 0) {
+			if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
+				break;
+		} else if (msg[i].addr != 0x50) {
+			/* 0x50 is the address of the eeprom - we need to protect it
+			 * from dibusb's bad i2c implementation: reads without
+			 * writing the offset before are forbidden */
+			if (dibusb_i2c_msg(d, msg[i].addr, NULL, 0, msg[i].buf, msg[i].len) < 0)
+				break;
+		}
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return i;
+}
+
+static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+struct i2c_algorithm dibusb_i2c_algo = {
+	.master_xfer   = dibusb_i2c_xfer,
+	.functionality = dibusb_i2c_func,
+};
+EXPORT_SYMBOL(dibusb_i2c_algo);
+
+int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val)
+{
+	u8 wbuf[1] = { offs };
+	return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1);
+}
+EXPORT_SYMBOL(dibusb_read_eeprom_byte);
+
+/* 3000MC/P stuff */
+// Config Adjacent channels  Perf -cal22
+static struct dibx000_agc_config dib3000p_mt2060_agc_config = {
+	.band_caps = BAND_VHF | BAND_UHF,
+	.setup     = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0),
+
+	.agc1_max = 48497,
+	.agc1_min = 23593,
+	.agc2_max = 46531,
+	.agc2_min = 24904,
+
+	.agc1_pt1 = 0x65,
+	.agc1_pt2 = 0x69,
+
+	.agc1_slope1 = 0x51,
+	.agc1_slope2 = 0x27,
+
+	.agc2_pt1 = 0,
+	.agc2_pt2 = 0x33,
+
+	.agc2_slope1 = 0x35,
+	.agc2_slope2 = 0x37,
+};
+
+static struct dib3000mc_config stk3000p_dib3000p_config = {
+	&dib3000p_mt2060_agc_config,
+
+	.max_time     = 0x196,
+	.ln_adc_level = 0x1cc7,
+
+	.output_mpeg2_in_188_bytes = 1,
+
+	.agc_command1 = 1,
+	.agc_command2 = 1,
+};
+
+static struct dibx000_agc_config dib3000p_panasonic_agc_config = {
+	.band_caps = BAND_VHF | BAND_UHF,
+	.setup     = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0),
+
+	.agc1_max = 56361,
+	.agc1_min = 22282,
+	.agc2_max = 47841,
+	.agc2_min = 36045,
+
+	.agc1_pt1 = 0x3b,
+	.agc1_pt2 = 0x6b,
+
+	.agc1_slope1 = 0x55,
+	.agc1_slope2 = 0x1d,
+
+	.agc2_pt1 = 0,
+	.agc2_pt2 = 0x0a,
+
+	.agc2_slope1 = 0x95,
+	.agc2_slope2 = 0x1e,
+};
+
+#if defined(CONFIG_DVB_DIB3000MC) || 					\
+	(defined(CONFIG_DVB_DIB3000MC_MODULE) && defined(MODULE))
+
+static struct dib3000mc_config mod3000p_dib3000p_config = {
+	&dib3000p_panasonic_agc_config,
+
+	.max_time     = 0x51,
+	.ln_adc_level = 0x1cc7,
+
+	.output_mpeg2_in_188_bytes = 1,
+
+	.agc_command1 = 1,
+	.agc_command2 = 1,
+};
+
+int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	if (adap->dev->udev->descriptor.idVendor  == USB_VID_LITEON &&
+			adap->dev->udev->descriptor.idProduct ==
+			USB_PID_LITEON_DVB_T_WARM) {
+		msleep(1000);
+	}
+
+	adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach,
+					 &adap->dev->i2c_adap,
+					 DEFAULT_DIB3000P_I2C_ADDRESS,
+					 &mod3000p_dib3000p_config);
+	if ((adap->fe_adap[0].fe) == NULL)
+		adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach,
+						 &adap->dev->i2c_adap,
+						 DEFAULT_DIB3000MC_I2C_ADDRESS,
+						 &mod3000p_dib3000p_config);
+	if ((adap->fe_adap[0].fe) != NULL) {
+		if (adap->priv != NULL) {
+			struct dibusb_state *st = adap->priv;
+			st->ops.pid_parse = dib3000mc_pid_parse;
+			st->ops.pid_ctrl  = dib3000mc_pid_control;
+		}
+		return 0;
+	}
+	return -ENODEV;
+}
+EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach);
+
+static struct mt2060_config stk3000p_mt2060_config = {
+	0x60
+};
+
+int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dibusb_state *st = adap->priv;
+	u8 a,b;
+	u16 if1 = 1220;
+	struct i2c_adapter *tun_i2c;
+
+	// First IF calibration for Liteon Sticks
+	if (adap->dev->udev->descriptor.idVendor  == USB_VID_LITEON &&
+		adap->dev->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) {
+
+		dibusb_read_eeprom_byte(adap->dev,0x7E,&a);
+		dibusb_read_eeprom_byte(adap->dev,0x7F,&b);
+
+		if (a == 0x00)
+			if1 += b;
+		else if (a == 0x80)
+			if1 -= b;
+		else
+			warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b);
+
+	} else if (adap->dev->udev->descriptor.idVendor  == USB_VID_DIBCOM &&
+		   adap->dev->udev->descriptor.idProduct == USB_PID_DIBCOM_MOD3001_WARM) {
+		u8 desc;
+		dibusb_read_eeprom_byte(adap->dev, 7, &desc);
+		if (desc == 2) {
+			a = 127;
+			do {
+				dibusb_read_eeprom_byte(adap->dev, a, &desc);
+				a--;
+			} while (a > 7 && (desc == 0xff || desc == 0x00));
+			if (desc & 0x80)
+				if1 -= (0xff - desc);
+			else
+				if1 += desc;
+		}
+	}
+
+	tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe_adap[0].fe, 1);
+	if (dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) {
+		/* not found - use panasonic pll parameters */
+		if (dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL)
+			return -ENOMEM;
+	} else {
+		st->mt2060_present = 1;
+		/* set the correct parameters for the dib3000p */
+		dib3000mc_set_config(adap->fe_adap[0].fe, &stk3000p_dib3000p_config);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
+#endif
+
+/*
+ * common remote control stuff
+ */
+struct rc_map_table rc_map_dibusb_table[] = {
+	/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
+	{ 0x0016, KEY_POWER },
+	{ 0x0010, KEY_MUTE },
+	{ 0x0003, KEY_1 },
+	{ 0x0001, KEY_2 },
+	{ 0x0006, KEY_3 },
+	{ 0x0009, KEY_4 },
+	{ 0x001d, KEY_5 },
+	{ 0x001f, KEY_6 },
+	{ 0x000d, KEY_7 },
+	{ 0x0019, KEY_8 },
+	{ 0x001b, KEY_9 },
+	{ 0x0015, KEY_0 },
+	{ 0x0005, KEY_CHANNELUP },
+	{ 0x0002, KEY_CHANNELDOWN },
+	{ 0x001e, KEY_VOLUMEUP },
+	{ 0x000a, KEY_VOLUMEDOWN },
+	{ 0x0011, KEY_RECORD },
+	{ 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */
+	{ 0x0014, KEY_PLAY },
+	{ 0x001a, KEY_STOP },
+	{ 0x0040, KEY_REWIND },
+	{ 0x0012, KEY_FASTFORWARD },
+	{ 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */
+	{ 0x004c, KEY_PAUSE },
+	{ 0x004d, KEY_SCREEN }, /* Full screen mode. */
+	{ 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
+	/* additional keys TwinHan VisionPlus, the Artec seemingly not have */
+	{ 0x000c, KEY_CANCEL }, /* Cancel */
+	{ 0x001c, KEY_EPG }, /* EPG */
+	{ 0x0000, KEY_TAB }, /* Tab */
+	{ 0x0048, KEY_INFO }, /* Preview */
+	{ 0x0004, KEY_LIST }, /* RecordList */
+	{ 0x000f, KEY_TEXT }, /* Teletext */
+	/* Key codes for the KWorld/ADSTech/JetWay remote. */
+	{ 0x8612, KEY_POWER },
+	{ 0x860f, KEY_SELECT }, /* source */
+	{ 0x860c, KEY_UNKNOWN }, /* scan */
+	{ 0x860b, KEY_EPG },
+	{ 0x8610, KEY_MUTE },
+	{ 0x8601, KEY_1 },
+	{ 0x8602, KEY_2 },
+	{ 0x8603, KEY_3 },
+	{ 0x8604, KEY_4 },
+	{ 0x8605, KEY_5 },
+	{ 0x8606, KEY_6 },
+	{ 0x8607, KEY_7 },
+	{ 0x8608, KEY_8 },
+	{ 0x8609, KEY_9 },
+	{ 0x860a, KEY_0 },
+	{ 0x8618, KEY_ZOOM },
+	{ 0x861c, KEY_UNKNOWN }, /* preview */
+	{ 0x8613, KEY_UNKNOWN }, /* snap */
+	{ 0x8600, KEY_UNDO },
+	{ 0x861d, KEY_RECORD },
+	{ 0x860d, KEY_STOP },
+	{ 0x860e, KEY_PAUSE },
+	{ 0x8616, KEY_PLAY },
+	{ 0x8611, KEY_BACK },
+	{ 0x8619, KEY_FORWARD },
+	{ 0x8614, KEY_UNKNOWN }, /* pip */
+	{ 0x8615, KEY_ESC },
+	{ 0x861a, KEY_UP },
+	{ 0x861e, KEY_DOWN },
+	{ 0x861f, KEY_LEFT },
+	{ 0x861b, KEY_RIGHT },
+
+	/* Key codes for the DiBcom MOD3000 remote. */
+	{ 0x8000, KEY_MUTE },
+	{ 0x8001, KEY_TEXT },
+	{ 0x8002, KEY_HOME },
+	{ 0x8003, KEY_POWER },
+
+	{ 0x8004, KEY_RED },
+	{ 0x8005, KEY_GREEN },
+	{ 0x8006, KEY_YELLOW },
+	{ 0x8007, KEY_BLUE },
+
+	{ 0x8008, KEY_DVD },
+	{ 0x8009, KEY_AUDIO },
+	{ 0x800a, KEY_IMAGES },      /* Pictures */
+	{ 0x800b, KEY_VIDEO },
+
+	{ 0x800c, KEY_BACK },
+	{ 0x800d, KEY_UP },
+	{ 0x800e, KEY_RADIO },
+	{ 0x800f, KEY_EPG },
+
+	{ 0x8010, KEY_LEFT },
+	{ 0x8011, KEY_OK },
+	{ 0x8012, KEY_RIGHT },
+	{ 0x8013, KEY_UNKNOWN },    /* SAP */
+
+	{ 0x8014, KEY_TV },
+	{ 0x8015, KEY_DOWN },
+	{ 0x8016, KEY_MENU },       /* DVD Menu */
+	{ 0x8017, KEY_LAST },
+
+	{ 0x8018, KEY_RECORD },
+	{ 0x8019, KEY_STOP },
+	{ 0x801a, KEY_PAUSE },
+	{ 0x801b, KEY_PLAY },
+
+	{ 0x801c, KEY_PREVIOUS },
+	{ 0x801d, KEY_REWIND },
+	{ 0x801e, KEY_FASTFORWARD },
+	{ 0x801f, KEY_NEXT},
+
+	{ 0x8040, KEY_1 },
+	{ 0x8041, KEY_2 },
+	{ 0x8042, KEY_3 },
+	{ 0x8043, KEY_CHANNELUP },
+
+	{ 0x8044, KEY_4 },
+	{ 0x8045, KEY_5 },
+	{ 0x8046, KEY_6 },
+	{ 0x8047, KEY_CHANNELDOWN },
+
+	{ 0x8048, KEY_7 },
+	{ 0x8049, KEY_8 },
+	{ 0x804a, KEY_9 },
+	{ 0x804b, KEY_VOLUMEUP },
+
+	{ 0x804c, KEY_CLEAR },
+	{ 0x804d, KEY_0 },
+	{ 0x804e, KEY_ENTER },
+	{ 0x804f, KEY_VOLUMEDOWN },
+};
+EXPORT_SYMBOL(rc_map_dibusb_table);
+
+int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	u8 key[5],cmd = DIBUSB_REQ_POLL_REMOTE;
+	dvb_usb_generic_rw(d,&cmd,1,key,5,0);
+	dvb_usb_nec_rc_key_to_event(d,key,event,state);
+	if (key[0] != 0)
+		deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
+	return 0;
+}
+EXPORT_SYMBOL(dibusb_rc_query);
diff --git a/drivers/media/usb/dvb-usb/dibusb-mb.c b/drivers/media/usb/dvb-usb/dibusb-mb.c
new file mode 100644
index 0000000..a4ac37e
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dibusb-mb.c
@@ -0,0 +1,471 @@
+/* DVB USB compliant linux driver for mobile DVB-T USB devices based on
+ * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-B)
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * based on GPL code from DiBcom, which has
+ * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int dib3000mb_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dibusb_state *st = adap->priv;
+
+	return st->ops.tuner_pass_ctrl(fe, enable, st->tuner_addr);
+}
+
+static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib3000_config demod_cfg;
+	struct dibusb_state *st = adap->priv;
+
+	demod_cfg.demod_address = 0x8;
+
+	adap->fe_adap[0].fe = dvb_attach(dib3000mb_attach, &demod_cfg,
+					 &adap->dev->i2c_adap, &st->ops);
+	if ((adap->fe_adap[0].fe) == NULL)
+		return -ENODEV;
+
+	adap->fe_adap[0].fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl;
+
+	return 0;
+}
+
+static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dibusb_state *st = adap->priv;
+
+	st->tuner_addr = 0x61;
+
+	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap,
+		   DVB_PLL_TUA6010XS);
+	return 0;
+}
+
+static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dibusb_state *st = adap->priv;
+
+	st->tuner_addr = 0x60;
+
+	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap,
+		   DVB_PLL_TDA665X);
+	return 0;
+}
+
+/* Some of the Artec 1.1 device aren't equipped with the default tuner
+ * (Thomson Cable), but with a Panasonic ENV77H11D5.  This function figures
+ * this out. */
+static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap)
+{
+	u8 b[2] = { 0,0 }, b2[1];
+	int ret = 0;
+	struct i2c_msg msg[2] = {
+		{ .flags = 0,        .buf = b,  .len = 2 },
+		{ .flags = I2C_M_RD, .buf = b2, .len = 1 },
+	};
+	struct dibusb_state *st = adap->priv;
+
+	/* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */
+	msg[0].addr = msg[1].addr = st->tuner_addr = 0x60;
+
+	if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
+		adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1);
+
+	if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) {
+		err("tuner i2c write failed.");
+		ret = -EREMOTEIO;
+	}
+
+	if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
+		adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0);
+
+	if (b2[0] == 0xfe) {
+		info("This device has the Thomson Cable onboard. Which is default.");
+		ret = dibusb_thomson_tuner_attach(adap);
+	} else {
+		info("This device has the Panasonic ENV77H11D5 onboard.");
+		ret = dibusb_panasonic_tuner_attach(adap);
+	}
+
+	return ret;
+}
+
+/* USB Driver stuff */
+static struct dvb_usb_device_properties dibusb1_1_properties;
+static struct dvb_usb_device_properties dibusb1_1_an2235_properties;
+static struct dvb_usb_device_properties dibusb2_0b_properties;
+static struct dvb_usb_device_properties artec_t1_usb2_properties;
+
+static int dibusb_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	if (0 == dvb_usb_device_init(intf, &dibusb1_1_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &dibusb1_1_an2235_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &dibusb2_0b_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &artec_t1_usb2_properties,
+				     THIS_MODULE, NULL, adapter_nr))
+		return 0;
+
+	return -EINVAL;
+}
+
+/* do not change the order of the ID table */
+static struct usb_device_id dibusb_dib3000mb_table [] = {
+/* 00 */	{ USB_DEVICE(USB_VID_WIDEVIEW,		USB_PID_AVERMEDIA_DVBT_USB_COLD) },
+/* 01 */	{ USB_DEVICE(USB_VID_WIDEVIEW,		USB_PID_AVERMEDIA_DVBT_USB_WARM) },
+/* 02 */	{ USB_DEVICE(USB_VID_COMPRO,		USB_PID_COMPRO_DVBU2000_COLD) },
+/* 03 */	{ USB_DEVICE(USB_VID_COMPRO,		USB_PID_COMPRO_DVBU2000_WARM) },
+/* 04 */	{ USB_DEVICE(USB_VID_COMPRO_UNK,	USB_PID_COMPRO_DVBU2000_UNK_COLD) },
+/* 05 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3000_COLD) },
+/* 06 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3000_WARM) },
+/* 07 */	{ USB_DEVICE(USB_VID_EMPIA,		USB_PID_KWORLD_VSTREAM_COLD) },
+/* 08 */	{ USB_DEVICE(USB_VID_EMPIA,		USB_PID_KWORLD_VSTREAM_WARM) },
+/* 09 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_GRANDTEC_DVBT_USB_COLD) },
+/* 10 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_GRANDTEC_DVBT_USB_WARM) },
+/* 11 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_DIBCOM_MOD3000_COLD) },
+/* 12 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_DIBCOM_MOD3000_WARM) },
+/* 13 */	{ USB_DEVICE(USB_VID_HYPER_PALTEK,	USB_PID_UNK_HYPER_PALTEK_COLD) },
+/* 14 */	{ USB_DEVICE(USB_VID_HYPER_PALTEK,	USB_PID_UNK_HYPER_PALTEK_WARM) },
+/* 15 */	{ USB_DEVICE(USB_VID_VISIONPLUS,	USB_PID_TWINHAN_VP7041_COLD) },
+/* 16 */	{ USB_DEVICE(USB_VID_VISIONPLUS,	USB_PID_TWINHAN_VP7041_WARM) },
+/* 17 */	{ USB_DEVICE(USB_VID_TWINHAN,		USB_PID_TWINHAN_VP7041_COLD) },
+/* 18 */	{ USB_DEVICE(USB_VID_TWINHAN,		USB_PID_TWINHAN_VP7041_WARM) },
+/* 19 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_COLD) },
+/* 20 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_WARM) },
+/* 21 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
+/* 22 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
+/* 23 */	{ USB_DEVICE(USB_VID_ADSTECH,		USB_PID_ADSTECH_USB2_COLD) },
+
+/* device ID with default DIBUSB2_0-firmware and with the hacked firmware */
+/* 24 */	{ USB_DEVICE(USB_VID_ADSTECH,		USB_PID_ADSTECH_USB2_WARM) },
+/* 25 */	{ USB_DEVICE(USB_VID_KYE,		USB_PID_KYE_DVB_T_COLD) },
+/* 26 */	{ USB_DEVICE(USB_VID_KYE,		USB_PID_KYE_DVB_T_WARM) },
+
+/* 27 */	{ USB_DEVICE(USB_VID_KWORLD,		USB_PID_KWORLD_VSTREAM_COLD) },
+
+/* 28 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_USB2_COLD) },
+/* 29 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_USB2_WARM) },
+
+/*
+ * XXX: As Artec just 'forgot' to program the EEPROM on some Artec T1 devices
+ *      we don't catch these faulty IDs (namely 'Cypress FX1 USB controller') that
+ *      have been left on the device. If you don't have such a device but an Artec
+ *      device that's supposed to work with this driver but is not detected by it,
+ *      free to enable CONFIG_DVB_USB_DIBUSB_MB_FAULTY via your kernel config.
+ */
+
+#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
+/* 30 */	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
+#endif
+
+			{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table);
+
+static struct dvb_usb_device_properties dibusb1_1_properties = {
+	.caps =  DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = CYPRESS_AN2135,
+
+	.firmware = "dvb-usb-dibusb-5.0.0.11.fw",
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+			.pid_filter_count = 16,
+
+			.streaming_ctrl   = dibusb_streaming_ctrl,
+			.pid_filter       = dibusb_pid_filter,
+			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+			.frontend_attach  = dibusb_dib3000mb_frontend_attach,
+			.tuner_attach     = dibusb_tuner_probe_and_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 7,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+			.size_of_priv     = sizeof(struct dibusb_state),
+		}
+	},
+
+	.power_ctrl       = dibusb_power_ctrl,
+
+	.rc.legacy = {
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_map_table     = rc_map_dibusb_table,
+		.rc_map_size      = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+		.rc_query         = dibusb_rc_query,
+	},
+
+	.i2c_algo         = &dibusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 9,
+	.devices = {
+		{	"AVerMedia AverTV DVBT USB1.1",
+			{ &dibusb_dib3000mb_table[0],  NULL },
+			{ &dibusb_dib3000mb_table[1],  NULL },
+		},
+		{	"Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)",
+			{ &dibusb_dib3000mb_table[2], &dibusb_dib3000mb_table[4], NULL},
+			{ &dibusb_dib3000mb_table[3], NULL },
+		},
+		{	"DiBcom USB1.1 DVB-T reference design (MOD3000)",
+			{ &dibusb_dib3000mb_table[5],  NULL },
+			{ &dibusb_dib3000mb_table[6],  NULL },
+		},
+		{	"KWorld V-Stream XPERT DTV - DVB-T USB1.1",
+			{ &dibusb_dib3000mb_table[7], NULL },
+			{ &dibusb_dib3000mb_table[8], NULL },
+		},
+		{	"Grandtec USB1.1 DVB-T",
+			{ &dibusb_dib3000mb_table[9],  &dibusb_dib3000mb_table[11], NULL },
+			{ &dibusb_dib3000mb_table[10], &dibusb_dib3000mb_table[12], NULL },
+		},
+		{	"Unknown USB1.1 DVB-T device ???? please report the name to the author",
+			{ &dibusb_dib3000mb_table[13], NULL },
+			{ &dibusb_dib3000mb_table[14], NULL },
+		},
+		{	"TwinhanDTV USB-Ter USB1.1 / Magic Box I / HAMA USB1.1 DVB-T device",
+			{ &dibusb_dib3000mb_table[15], &dibusb_dib3000mb_table[17], NULL},
+			{ &dibusb_dib3000mb_table[16], &dibusb_dib3000mb_table[18], NULL},
+		},
+		{	"Artec T1 USB1.1 TVBOX with AN2135",
+			{ &dibusb_dib3000mb_table[19], NULL },
+			{ &dibusb_dib3000mb_table[20], NULL },
+		},
+		{	"VideoWalker DVB-T USB",
+			{ &dibusb_dib3000mb_table[25], NULL },
+			{ &dibusb_dib3000mb_table[26], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties dibusb1_1_an2235_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = CYPRESS_AN2235,
+
+	.firmware = "dvb-usb-dibusb-an2235-01.fw",
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.caps = DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_ADAP_HAS_PID_FILTER,
+			.pid_filter_count = 16,
+
+			.streaming_ctrl   = dibusb_streaming_ctrl,
+			.pid_filter       = dibusb_pid_filter,
+			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+			.frontend_attach  = dibusb_dib3000mb_frontend_attach,
+			.tuner_attach     = dibusb_tuner_probe_and_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 7,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+			.size_of_priv     = sizeof(struct dibusb_state),
+		},
+	},
+	.power_ctrl       = dibusb_power_ctrl,
+
+	.rc.legacy = {
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_map_table     = rc_map_dibusb_table,
+		.rc_map_size      = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+		.rc_query         = dibusb_rc_query,
+	},
+
+	.i2c_algo         = &dibusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
+	.num_device_descs = 2,
+#else
+	.num_device_descs = 1,
+#endif
+	.devices = {
+		{	"Artec T1 USB1.1 TVBOX with AN2235",
+			{ &dibusb_dib3000mb_table[21], NULL },
+			{ &dibusb_dib3000mb_table[22], NULL },
+		},
+#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
+		{	"Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
+			{ &dibusb_dib3000mb_table[30], NULL },
+			{ NULL },
+		},
+		{ NULL },
+#endif
+	}
+};
+
+static struct dvb_usb_device_properties dibusb2_0b_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = CYPRESS_FX2,
+
+	.firmware = "dvb-usb-adstech-usb2-02.fw",
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+			.pid_filter_count = 16,
+
+			.streaming_ctrl   = dibusb2_0_streaming_ctrl,
+			.pid_filter       = dibusb_pid_filter,
+			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+			.frontend_attach  = dibusb_dib3000mb_frontend_attach,
+			.tuner_attach     = dibusb_thomson_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 7,
+				.endpoint = 0x06,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+			.size_of_priv     = sizeof(struct dibusb_state),
+		}
+	},
+	.power_ctrl       = dibusb2_0_power_ctrl,
+
+	.rc.legacy = {
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_map_table     = rc_map_dibusb_table,
+		.rc_map_size      = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+		.rc_query         = dibusb_rc_query,
+	},
+
+	.i2c_algo         = &dibusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 2,
+	.devices = {
+		{	"KWorld/ADSTech Instant DVB-T USB2.0",
+			{ &dibusb_dib3000mb_table[23], NULL },
+			{ &dibusb_dib3000mb_table[24], NULL },
+		},
+		{	"KWorld Xpert DVB-T USB2.0",
+			{ &dibusb_dib3000mb_table[27], NULL },
+			{ NULL }
+		},
+		{ NULL },
+	}
+};
+
+static struct dvb_usb_device_properties artec_t1_usb2_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = CYPRESS_FX2,
+
+	.firmware = "dvb-usb-dibusb-6.0.0.8.fw",
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+			.pid_filter_count = 16,
+
+			.streaming_ctrl   = dibusb2_0_streaming_ctrl,
+			.pid_filter       = dibusb_pid_filter,
+			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+			.frontend_attach  = dibusb_dib3000mb_frontend_attach,
+			.tuner_attach     = dibusb_tuner_probe_and_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 7,
+				.endpoint = 0x06,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+			.size_of_priv     = sizeof(struct dibusb_state),
+		}
+	},
+	.power_ctrl       = dibusb2_0_power_ctrl,
+
+	.rc.legacy = {
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_map_table     = rc_map_dibusb_table,
+		.rc_map_size      = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+		.rc_query         = dibusb_rc_query,
+	},
+
+	.i2c_algo         = &dibusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{	"Artec T1 USB2.0",
+			{ &dibusb_dib3000mb_table[28], NULL },
+			{ &dibusb_dib3000mb_table[29], NULL },
+		},
+		{ NULL },
+	}
+};
+
+static struct usb_driver dibusb_driver = {
+	.name		= "dvb_usb_dibusb_mb",
+	.probe		= dibusb_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table	= dibusb_dib3000mb_table,
+};
+
+module_usb_driver(dibusb_driver);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for DiBcom USB DVB-T devices (DiB3000M-B based)");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/dibusb-mc.c b/drivers/media/usb/dvb-usb/dibusb-mc.c
new file mode 100644
index 0000000..9d1a59d0
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dibusb-mc.c
@@ -0,0 +1,149 @@
+/* DVB USB compliant linux driver for mobile DVB-T USB devices based on
+ * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-C/P)
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * based on GPL code from DiBcom, which has
+ * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* USB Driver stuff */
+static struct dvb_usb_device_properties dibusb_mc_properties;
+
+static int dibusb_mc_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	return dvb_usb_device_init(intf, &dibusb_mc_properties, THIS_MODULE,
+				   NULL, adapter_nr);
+}
+
+/* do not change the order of the ID table */
+static struct usb_device_id dibusb_dib3000mc_table [] = {
+/* 00 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3001_COLD) },
+/* 01 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3001_WARM) },
+/* 02 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_USB2_COLD) },
+/* 03 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_USB2_WARM) }, // ( ? )
+/* 04 */	{ USB_DEVICE(USB_VID_LITEON,		USB_PID_LITEON_DVB_T_COLD) },
+/* 05 */	{ USB_DEVICE(USB_VID_LITEON,		USB_PID_LITEON_DVB_T_WARM) },
+/* 06 */	{ USB_DEVICE(USB_VID_EMPIA,		USB_PID_DIGIVOX_MINI_SL_COLD) },
+/* 07 */	{ USB_DEVICE(USB_VID_EMPIA,		USB_PID_DIGIVOX_MINI_SL_WARM) },
+/* 08 */	{ USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_GRANDTEC_DVBT_USB2_COLD) },
+/* 09 */	{ USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_GRANDTEC_DVBT_USB2_WARM) },
+/* 10 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ARTEC_T14_COLD) },
+/* 11 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ARTEC_T14_WARM) },
+/* 12 */	{ USB_DEVICE(USB_VID_LEADTEK,		USB_PID_WINFAST_DTV_DONGLE_COLD) },
+/* 13 */	{ USB_DEVICE(USB_VID_LEADTEK,		USB_PID_WINFAST_DTV_DONGLE_WARM) },
+/* 14 */	{ USB_DEVICE(USB_VID_HUMAX_COEX,	USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD) },
+/* 15 */	{ USB_DEVICE(USB_VID_HUMAX_COEX,	USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM) },
+			{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, dibusb_dib3000mc_table);
+
+static struct dvb_usb_device_properties dibusb_mc_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-dibusb-6.0.0.8.fw",
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+			.pid_filter_count = 32,
+			.streaming_ctrl   = dibusb2_0_streaming_ctrl,
+			.pid_filter       = dibusb_pid_filter,
+			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+			.frontend_attach  = dibusb_dib3000mc_frontend_attach,
+			.tuner_attach     = dibusb_dib3000mc_tuner_attach,
+
+	/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 8,
+				.endpoint = 0x06,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+			.size_of_priv     = sizeof(struct dibusb_state),
+		}
+	},
+	.power_ctrl       = dibusb2_0_power_ctrl,
+
+	.rc.legacy = {
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_map_table     = rc_map_dibusb_table,
+		.rc_map_size      = 111, /* FIXME */
+		.rc_query         = dibusb_rc_query,
+	},
+
+	.i2c_algo         = &dibusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 8,
+	.devices = {
+		{   "DiBcom USB2.0 DVB-T reference design (MOD3000P)",
+			{ &dibusb_dib3000mc_table[0], NULL },
+			{ &dibusb_dib3000mc_table[1], NULL },
+		},
+		{   "Artec T1 USB2.0 TVBOX (please check the warm ID)",
+			{ &dibusb_dib3000mc_table[2], NULL },
+			{ &dibusb_dib3000mc_table[3], NULL },
+		},
+		{   "LITE-ON USB2.0 DVB-T Tuner",
+		    /* Also rebranded as Intuix S800, Toshiba */
+			{ &dibusb_dib3000mc_table[4], NULL },
+			{ &dibusb_dib3000mc_table[5], NULL },
+		},
+		{   "MSI Digivox Mini SL",
+			{ &dibusb_dib3000mc_table[6], NULL },
+			{ &dibusb_dib3000mc_table[7], NULL },
+		},
+		{   "GRAND - USB2.0 DVB-T adapter",
+			{ &dibusb_dib3000mc_table[8], NULL },
+			{ &dibusb_dib3000mc_table[9], NULL },
+		},
+		{   "Artec T14 - USB2.0 DVB-T",
+			{ &dibusb_dib3000mc_table[10], NULL },
+			{ &dibusb_dib3000mc_table[11], NULL },
+		},
+		{   "Leadtek - USB2.0 Winfast DTV dongle",
+			{ &dibusb_dib3000mc_table[12], NULL },
+			{ &dibusb_dib3000mc_table[13], NULL },
+		},
+		{   "Humax/Coex DVB-T USB Stick 2.0 High Speed",
+			{ &dibusb_dib3000mc_table[14], NULL },
+			{ &dibusb_dib3000mc_table[15], NULL },
+		},
+		{ NULL },
+	}
+};
+
+static struct usb_driver dibusb_mc_driver = {
+	.name		= "dvb_usb_dibusb_mc",
+	.probe		= dibusb_mc_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table	= dibusb_dib3000mc_table,
+};
+
+module_usb_driver(dibusb_mc_driver);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for DiBcom USB2.0 DVB-T (DiB3000M-C/P based) devices");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/dibusb.h b/drivers/media/usb/dvb-usb/dibusb.h
new file mode 100644
index 0000000..e47c321
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dibusb.h
@@ -0,0 +1,131 @@
+/* Header file for all dibusb-based-receivers.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the Free
+ *	Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_DIBUSB_H_
+#define _DVB_USB_DIBUSB_H_
+
+#ifndef DVB_USB_LOG_PREFIX
+ #define DVB_USB_LOG_PREFIX "dibusb"
+#endif
+#include "dvb-usb.h"
+
+#include "dib3000.h"
+#include "dib3000mc.h"
+#include "mt2060.h"
+
+/*
+ * protocol of all dibusb related devices
+ */
+
+/*
+ * bulk msg to/from endpoint 0x01
+ *
+ * general structure:
+ * request_byte parameter_bytes
+ */
+
+#define DIBUSB_REQ_START_READ			0x00
+#define DIBUSB_REQ_START_DEMOD			0x01
+
+/*
+ * i2c read
+ * bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word
+ * bulk read:  byte_buffer (length_word bytes)
+ */
+#define DIBUSB_REQ_I2C_READ			0x02
+
+/*
+ * i2c write
+ * bulk write: 0x03 (7bit i2c_addr << 1) register_bytes value_bytes
+ */
+#define DIBUSB_REQ_I2C_WRITE			0x03
+
+/*
+ * polling the value of the remote control
+ * bulk write: 0x04
+ * bulk read:  byte_buffer (5 bytes)
+ */
+#define DIBUSB_REQ_POLL_REMOTE       0x04
+
+/* additional status values for Hauppauge Remote Control Protocol */
+#define DIBUSB_RC_HAUPPAUGE_KEY_PRESSED	0x01
+#define DIBUSB_RC_HAUPPAUGE_KEY_EMPTY	0x03
+
+/* streaming mode:
+ * bulk write: 0x05 mode_byte
+ *
+ * mode_byte is mostly 0x00
+ */
+#define DIBUSB_REQ_SET_STREAMING_MODE	0x05
+
+/* interrupt the internal read loop, when blocking */
+#define DIBUSB_REQ_INTR_READ			0x06
+
+/* io control
+ * 0x07 cmd_byte param_bytes
+ *
+ * param_bytes can be up to 32 bytes
+ *
+ * cmd_byte function    parameter name
+ * 0x00     power mode
+ *                      0x00      sleep
+ *                      0x01      wakeup
+ *
+ * 0x01     enable streaming
+ * 0x02     disable streaming
+ *
+ *
+ */
+#define DIBUSB_REQ_SET_IOCTL			0x07
+
+/* IOCTL commands */
+
+/* change the power mode in firmware */
+#define DIBUSB_IOCTL_CMD_POWER_MODE		0x00
+#define DIBUSB_IOCTL_POWER_SLEEP			0x00
+#define DIBUSB_IOCTL_POWER_WAKEUP			0x01
+
+/* modify streaming of the FX2 */
+#define DIBUSB_IOCTL_CMD_ENABLE_STREAM	0x01
+#define DIBUSB_IOCTL_CMD_DISABLE_STREAM	0x02
+
+struct dibusb_state {
+	struct dib_fe_xfer_ops ops;
+	int mt2060_present;
+	u8 tuner_addr;
+};
+
+struct dibusb_device_state {
+	/* for RC5 remote control */
+	int old_toggle;
+	int last_repeat_count;
+};
+
+extern struct i2c_algorithm dibusb_i2c_algo;
+
+extern int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *);
+extern int dibusb_dib3000mc_tuner_attach (struct dvb_usb_adapter *);
+
+extern int dibusb_streaming_ctrl(struct dvb_usb_adapter *, int);
+extern int dibusb_pid_filter(struct dvb_usb_adapter *, int, u16, int);
+extern int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *, int);
+extern int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *, int);
+
+extern int dibusb_power_ctrl(struct dvb_usb_device *, int);
+extern int dibusb2_0_power_ctrl(struct dvb_usb_device *, int);
+
+#define DEFAULT_RC_INTERVAL 150
+//#define DEFAULT_RC_INTERVAL 100000
+
+extern struct rc_map_table rc_map_dibusb_table[];
+extern int dibusb_rc_query(struct dvb_usb_device *, u32 *, int *);
+extern int dibusb_read_eeprom_byte(struct dvb_usb_device *, u8, u8 *);
+
+#endif
diff --git a/drivers/media/usb/dvb-usb/digitv.c b/drivers/media/usb/dvb-usb/digitv.c
new file mode 100644
index 0000000..ff34419
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/digitv.c
@@ -0,0 +1,354 @@
+/* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0
+ * receiver
+ *
+ * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * partly based on the SDK published by Nebula Electronics
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "digitv.h"
+
+#include "mt352.h"
+#include "nxt6000.h"
+
+/* debug */
+static int dvb_usb_digitv_debug;
+module_param_named(debug,dvb_usb_digitv_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define deb_rc(args...)   dprintk(dvb_usb_digitv_debug,0x01,args)
+
+static int digitv_ctrl_msg(struct dvb_usb_device *d,
+		u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+	int wo = (rbuf == NULL || rlen == 0); /* write-only */
+	u8 sndbuf[7],rcvbuf[7];
+	memset(sndbuf,0,7); memset(rcvbuf,0,7);
+
+	sndbuf[0] = cmd;
+	sndbuf[1] = vv;
+	sndbuf[2] = wo ? wlen : rlen;
+
+	if (wo) {
+		memcpy(&sndbuf[3],wbuf,wlen);
+		dvb_usb_generic_write(d,sndbuf,7);
+	} else {
+		dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7,10);
+		memcpy(rbuf,&rcvbuf[3],rlen);
+	}
+	return 0;
+}
+
+/* I2C */
+static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int i;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	if (num > 2)
+		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+	for (i = 0; i < num; i++) {
+		/* write/read request */
+		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+			if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0,
+						msg[i+1].buf,msg[i+1].len) < 0)
+				break;
+			i++;
+		} else
+			if (digitv_ctrl_msg(d,USB_WRITE_COFDM, msg[i].buf[0],
+						&msg[i].buf[1],msg[i].len-1,NULL,0) < 0)
+				break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return i;
+}
+
+static u32 digitv_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm digitv_i2c_algo = {
+	.master_xfer   = digitv_i2c_xfer,
+	.functionality = digitv_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static int digitv_identify_state (struct usb_device *udev, struct
+		dvb_usb_device_properties *props, struct dvb_usb_device_description **desc,
+		int *cold)
+{
+	*cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
+	return 0;
+}
+
+static int digitv_mt352_demod_init(struct dvb_frontend *fe)
+{
+	static u8 reset_buf[] = { 0x89, 0x38,  0x8a, 0x2d, 0x50, 0x80 };
+	static u8 init_buf[] = { 0x68, 0xa0,  0x8e, 0x40,  0x53, 0x50,
+			0x67, 0x20,  0x7d, 0x01,  0x7c, 0x00,  0x7a, 0x00,
+			0x79, 0x20,  0x57, 0x05,  0x56, 0x31,  0x88, 0x0f,
+			0x75, 0x32 };
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(reset_buf); i += 2)
+		mt352_write(fe, &reset_buf[i], 2);
+
+	msleep(1);
+
+	for (i = 0; i < ARRAY_SIZE(init_buf); i += 2)
+		mt352_write(fe, &init_buf[i], 2);
+
+	return 0;
+}
+
+static struct mt352_config digitv_mt352_config = {
+	.demod_init = digitv_mt352_demod_init,
+};
+
+static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	u8 b[5];
+
+	fe->ops.tuner_ops.calc_regs(fe, b, sizeof(b));
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0);
+}
+
+static struct nxt6000_config digitv_nxt6000_config = {
+	.clock_inversion = 1,
+};
+
+static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct digitv_state *st = adap->dev->priv;
+
+	adap->fe_adap[0].fe = dvb_attach(mt352_attach, &digitv_mt352_config,
+					 &adap->dev->i2c_adap);
+	if ((adap->fe_adap[0].fe) != NULL) {
+		st->is_nxt6000 = 0;
+		return 0;
+	}
+	adap->fe_adap[0].fe = dvb_attach(nxt6000_attach,
+					 &digitv_nxt6000_config,
+					 &adap->dev->i2c_adap);
+	if ((adap->fe_adap[0].fe) != NULL) {
+		st->is_nxt6000 = 1;
+		return 0;
+	}
+	return -EIO;
+}
+
+static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct digitv_state *st = adap->dev->priv;
+
+	if (!dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, NULL, DVB_PLL_TDED4))
+		return -ENODEV;
+
+	if (st->is_nxt6000)
+		adap->fe_adap[0].fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+
+	return 0;
+}
+
+static struct rc_map_table rc_map_digitv_table[] = {
+	{ 0x5f55, KEY_0 },
+	{ 0x6f55, KEY_1 },
+	{ 0x9f55, KEY_2 },
+	{ 0xaf55, KEY_3 },
+	{ 0x5f56, KEY_4 },
+	{ 0x6f56, KEY_5 },
+	{ 0x9f56, KEY_6 },
+	{ 0xaf56, KEY_7 },
+	{ 0x5f59, KEY_8 },
+	{ 0x6f59, KEY_9 },
+	{ 0x9f59, KEY_TV },
+	{ 0xaf59, KEY_AUX },
+	{ 0x5f5a, KEY_DVD },
+	{ 0x6f5a, KEY_POWER },
+	{ 0x9f5a, KEY_CAMERA },     /* labelled 'Picture' */
+	{ 0xaf5a, KEY_AUDIO },
+	{ 0x5f65, KEY_INFO },
+	{ 0x6f65, KEY_F13 },     /* 16:9 */
+	{ 0x9f65, KEY_F14 },     /* 14:9 */
+	{ 0xaf65, KEY_EPG },
+	{ 0x5f66, KEY_EXIT },
+	{ 0x6f66, KEY_MENU },
+	{ 0x9f66, KEY_UP },
+	{ 0xaf66, KEY_DOWN },
+	{ 0x5f69, KEY_LEFT },
+	{ 0x6f69, KEY_RIGHT },
+	{ 0x9f69, KEY_ENTER },
+	{ 0xaf69, KEY_CHANNELUP },
+	{ 0x5f6a, KEY_CHANNELDOWN },
+	{ 0x6f6a, KEY_VOLUMEUP },
+	{ 0x9f6a, KEY_VOLUMEDOWN },
+	{ 0xaf6a, KEY_RED },
+	{ 0x5f95, KEY_GREEN },
+	{ 0x6f95, KEY_YELLOW },
+	{ 0x9f95, KEY_BLUE },
+	{ 0xaf95, KEY_SUBTITLE },
+	{ 0x5f96, KEY_F15 },     /* AD */
+	{ 0x6f96, KEY_TEXT },
+	{ 0x9f96, KEY_MUTE },
+	{ 0xaf96, KEY_REWIND },
+	{ 0x5f99, KEY_STOP },
+	{ 0x6f99, KEY_PLAY },
+	{ 0x9f99, KEY_FASTFORWARD },
+	{ 0xaf99, KEY_F16 },     /* chapter */
+	{ 0x5f9a, KEY_PAUSE },
+	{ 0x6f9a, KEY_PLAY },
+	{ 0x9f9a, KEY_RECORD },
+	{ 0xaf9a, KEY_F17 },     /* picture in picture */
+	{ 0x5fa5, KEY_KPPLUS },  /* zoom in */
+	{ 0x6fa5, KEY_KPMINUS }, /* zoom out */
+	{ 0x9fa5, KEY_F18 },     /* capture */
+	{ 0xafa5, KEY_F19 },     /* web */
+	{ 0x5fa6, KEY_EMAIL },
+	{ 0x6fa6, KEY_PHONE },
+	{ 0x9fa6, KEY_PC },
+};
+
+static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	int i;
+	u8 key[5];
+	u8 b[4] = { 0 };
+
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
+
+	digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4);
+
+	/* Tell the device we've read the remote. Not sure how necessary
+	   this is, but the Nebula SDK does it. */
+	digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0);
+
+	/* if something is inside the buffer, simulate key press */
+	if (key[1] != 0)
+	{
+		  for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
+			if (rc5_custom(&d->props.rc.legacy.rc_map_table[i]) == key[1] &&
+			    rc5_data(&d->props.rc.legacy.rc_map_table[i]) == key[2]) {
+				*event = d->props.rc.legacy.rc_map_table[i].keycode;
+				*state = REMOTE_KEY_PRESSED;
+				return 0;
+			}
+		}
+	}
+
+	if (key[0] != 0)
+		deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
+	return 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties digitv_properties;
+
+static int digitv_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	struct dvb_usb_device *d;
+	int ret = dvb_usb_device_init(intf, &digitv_properties, THIS_MODULE, &d,
+				      adapter_nr);
+	if (ret == 0) {
+		u8 b[4] = { 0 };
+
+		if (d != NULL) { /* do that only when the firmware is loaded */
+			b[0] = 1;
+			digitv_ctrl_msg(d,USB_WRITE_REMOTE_TYPE,0,b,4,NULL,0);
+
+			b[0] = 0;
+			digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0);
+		}
+	}
+	return ret;
+}
+
+static struct usb_device_id digitv_table [] = {
+		{ USB_DEVICE(USB_VID_ANCHOR, USB_PID_NEBULA_DIGITV) },
+		{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, digitv_table);
+
+static struct dvb_usb_device_properties digitv_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-digitv-02.fw",
+
+	.size_of_priv = sizeof(struct digitv_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.frontend_attach  = digitv_frontend_attach,
+			.tuner_attach     = digitv_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 7,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+		}
+	},
+	.identify_state   = digitv_identify_state,
+
+	.rc.legacy = {
+		.rc_interval      = 1000,
+		.rc_map_table     = rc_map_digitv_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_digitv_table),
+		.rc_query         = digitv_rc_query,
+	},
+
+	.i2c_algo         = &digitv_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "Nebula Electronics uDigiTV DVB-T USB2.0)",
+			{ &digitv_table[0], NULL },
+			{ NULL },
+		},
+		{ NULL },
+	}
+};
+
+static struct usb_driver digitv_driver = {
+	.name		= "dvb_usb_digitv",
+	.probe		= digitv_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table	= digitv_table,
+};
+
+module_usb_driver(digitv_driver);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for Nebula Electronics uDigiTV DVB-T USB2.0");
+MODULE_VERSION("1.0-alpha");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/digitv.h b/drivers/media/usb/dvb-usb/digitv.h
new file mode 100644
index 0000000..908c09f
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/digitv.h
@@ -0,0 +1,66 @@
+#ifndef _DVB_USB_DIGITV_H_
+#define _DVB_USB_DIGITV_H_
+
+#define DVB_USB_LOG_PREFIX "digitv"
+#include "dvb-usb.h"
+
+struct digitv_state {
+    int is_nxt6000;
+};
+
+/* protocol (from usblogging and the SDK:
+ *
+ * Always 7 bytes bulk message(s) for controlling
+ *
+ * First byte describes the command. Reads are 2 consecutive transfer (as always).
+ *
+ * General structure:
+ *
+ * write or first message of a read:
+ * <cmdbyte> VV <len> B0 B1 B2 B3
+ *
+ * second message of a read
+ * <cmdbyte> VV <len> R0 R1 R2 R3
+ *
+ * whereas 0 < len <= 4
+ *
+ * I2C address is stored somewhere inside the device.
+ *
+ * 0x01 read from EEPROM
+ *  VV = offset; B* = 0; R* = value(s)
+ *
+ * 0x02 read register of the COFDM
+ *  VV = register; B* = 0; R* = value(s)
+ *
+ * 0x05 write register of the COFDM
+ *  VV = register; B* = value(s);
+ *
+ * 0x06 write to the tuner (only for NXT6000)
+ *  VV = 0; B* = PLL data; len = 4;
+ *
+ * 0x03 read remote control
+ *  VV = 0; B* = 0; len = 4; R* = key
+ *
+ * 0x07 write to the remote (don't know why one should this, resetting ?)
+ *  VV = 0; B* = key; len = 4;
+ *
+ * 0x08 write remote type
+ *  VV = 0; B[0] = 0x01, len = 4
+ *
+ * 0x09 write device init
+ *  TODO
+ */
+#define USB_READ_EEPROM         1
+
+#define USB_READ_COFDM          2
+#define USB_WRITE_COFDM         5
+
+#define USB_WRITE_TUNER         6
+
+#define USB_READ_REMOTE         3
+#define USB_WRITE_REMOTE        7
+#define USB_WRITE_REMOTE_TYPE   8
+
+#define USB_DEV_INIT            9
+
+#endif
diff --git a/drivers/media/usb/dvb-usb/dtt200u-fe.c b/drivers/media/usb/dvb-usb/dtt200u-fe.c
new file mode 100644
index 0000000..3d81daa
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dtt200u-fe.c
@@ -0,0 +1,210 @@
+/* Frontend part of the Linux driver for the WideView/ Yakumo/ Hama/
+ * Typhoon/ Yuan DVB-T USB2.0 receiver.
+ *
+ * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the Free
+ *	Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dtt200u.h"
+
+struct dtt200u_fe_state {
+	struct dvb_usb_device *d;
+
+	fe_status_t stat;
+
+	struct dtv_frontend_properties fep;
+	struct dvb_frontend frontend;
+};
+
+static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
+{
+	struct dtt200u_fe_state *state = fe->demodulator_priv;
+	u8 st = GET_TUNE_STATUS, b[3];
+
+	dvb_usb_generic_rw(state->d,&st,1,b,3,0);
+
+	switch (b[0]) {
+		case 0x01:
+			*stat = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+			break;
+		case 0x00: /* pending */
+			*stat = FE_TIMEDOUT; /* during set_frontend */
+			break;
+		default:
+		case 0x02: /* failed */
+			*stat = 0;
+			break;
+	}
+	return 0;
+}
+
+static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+	struct dtt200u_fe_state *state = fe->demodulator_priv;
+	u8 bw = GET_VIT_ERR_CNT,b[3];
+	dvb_usb_generic_rw(state->d,&bw,1,b,3,0);
+	*ber = (b[0] << 16) | (b[1] << 8) | b[2];
+	return 0;
+}
+
+static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+	struct dtt200u_fe_state *state = fe->demodulator_priv;
+	u8 bw = GET_RS_UNCOR_BLK_CNT,b[2];
+
+	dvb_usb_generic_rw(state->d,&bw,1,b,2,0);
+	*unc = (b[0] << 8) | b[1];
+	return 0;
+}
+
+static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+	struct dtt200u_fe_state *state = fe->demodulator_priv;
+	u8 bw = GET_AGC, b;
+	dvb_usb_generic_rw(state->d,&bw,1,&b,1,0);
+	*strength = (b << 8) | b;
+	return 0;
+}
+
+static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+	struct dtt200u_fe_state *state = fe->demodulator_priv;
+	u8 bw = GET_SNR,br;
+	dvb_usb_generic_rw(state->d,&bw,1,&br,1,0);
+	*snr = ~((br << 8) | br);
+	return 0;
+}
+
+static int dtt200u_fe_init(struct dvb_frontend* fe)
+{
+	struct dtt200u_fe_state *state = fe->demodulator_priv;
+	u8 b = SET_INIT;
+	return dvb_usb_generic_write(state->d,&b,1);
+}
+
+static int dtt200u_fe_sleep(struct dvb_frontend* fe)
+{
+	return dtt200u_fe_init(fe);
+}
+
+static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1500;
+	tune->step_size = 0;
+	tune->max_drift = 0;
+	return 0;
+}
+
+static int dtt200u_fe_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
+	struct dtt200u_fe_state *state = fe->demodulator_priv;
+	int i;
+	fe_status_t st;
+	u16 freq = fep->frequency / 250000;
+	u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 };
+
+	switch (fep->bandwidth_hz) {
+	case 8000000:
+		bwbuf[1] = 8;
+		break;
+	case 7000000:
+		bwbuf[1] = 7;
+		break;
+	case 6000000:
+		bwbuf[1] = 6;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dvb_usb_generic_write(state->d,bwbuf,2);
+
+	freqbuf[1] = freq & 0xff;
+	freqbuf[2] = (freq >> 8) & 0xff;
+	dvb_usb_generic_write(state->d,freqbuf,3);
+
+	for (i = 0; i < 30; i++) {
+		msleep(20);
+		dtt200u_fe_read_status(fe, &st);
+		if (st & FE_TIMEDOUT)
+			continue;
+	}
+
+	return 0;
+}
+
+static int dtt200u_fe_get_frontend(struct dvb_frontend* fe)
+{
+	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
+	struct dtt200u_fe_state *state = fe->demodulator_priv;
+	memcpy(fep, &state->fep, sizeof(struct dtv_frontend_properties));
+	return 0;
+}
+
+static void dtt200u_fe_release(struct dvb_frontend* fe)
+{
+	struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops dtt200u_fe_ops;
+
+struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d)
+{
+	struct dtt200u_fe_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct dtt200u_fe_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	deb_info("attaching frontend dtt200u\n");
+
+	state->d = d;
+
+	memcpy(&state->frontend.ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	return &state->frontend;
+error:
+	return NULL;
+}
+
+static struct dvb_frontend_ops dtt200u_fe_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name			= "WideView USB DVB-T",
+		.frequency_min		= 44250000,
+		.frequency_max		= 867250000,
+		.frequency_stepsize	= 250000,
+		.caps = FE_CAN_INVERSION_AUTO |
+				FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+				FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+				FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+				FE_CAN_TRANSMISSION_MODE_AUTO |
+				FE_CAN_GUARD_INTERVAL_AUTO |
+				FE_CAN_RECOVER |
+				FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.release = dtt200u_fe_release,
+
+	.init = dtt200u_fe_init,
+	.sleep = dtt200u_fe_sleep,
+
+	.set_frontend = dtt200u_fe_set_frontend,
+	.get_frontend = dtt200u_fe_get_frontend,
+	.get_tune_settings = dtt200u_fe_get_tune_settings,
+
+	.read_status = dtt200u_fe_read_status,
+	.read_ber = dtt200u_fe_read_ber,
+	.read_signal_strength = dtt200u_fe_read_signal_strength,
+	.read_snr = dtt200u_fe_read_snr,
+	.read_ucblocks = dtt200u_fe_read_unc_blocks,
+};
diff --git a/drivers/media/usb/dvb-usb/dtt200u.c b/drivers/media/usb/dvb-usb/dtt200u.c
new file mode 100644
index 0000000..66f205c
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dtt200u.c
@@ -0,0 +1,368 @@
+/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/
+ * Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * Thanks to Steve Chang from WideView for providing support for the WT-220U.
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dtt200u.h"
+
+/* debug */
+int dvb_usb_dtt200u_debug;
+module_param_named(debug,dvb_usb_dtt200u_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	u8 b = SET_INIT;
+
+	if (onoff)
+		dvb_usb_generic_write(d,&b,2);
+
+	return 0;
+}
+
+static int dtt200u_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	u8 b_streaming[2] = { SET_STREAMING, onoff };
+	u8 b_rst_pid = RESET_PID_FILTER;
+
+	dvb_usb_generic_write(adap->dev, b_streaming, 2);
+
+	if (onoff == 0)
+		dvb_usb_generic_write(adap->dev, &b_rst_pid, 1);
+	return 0;
+}
+
+static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
+{
+	u8 b_pid[4];
+	pid = onoff ? pid : 0;
+
+	b_pid[0] = SET_PID_FILTER;
+	b_pid[1] = index;
+	b_pid[2] = pid & 0xff;
+	b_pid[3] = (pid >> 8) & 0x1f;
+
+	return dvb_usb_generic_write(adap->dev, b_pid, 4);
+}
+
+/* remote control */
+/* key list for the tiny remote control (Yakumo, don't know about the others) */
+static struct rc_map_table rc_map_dtt200u_table[] = {
+	{ 0x8001, KEY_MUTE },
+	{ 0x8002, KEY_CHANNELDOWN },
+	{ 0x8003, KEY_VOLUMEDOWN },
+	{ 0x8004, KEY_1 },
+	{ 0x8005, KEY_2 },
+	{ 0x8006, KEY_3 },
+	{ 0x8007, KEY_4 },
+	{ 0x8008, KEY_5 },
+	{ 0x8009, KEY_6 },
+	{ 0x800a, KEY_7 },
+	{ 0x800c, KEY_ZOOM },
+	{ 0x800d, KEY_0 },
+	{ 0x800e, KEY_SELECT },
+	{ 0x8012, KEY_POWER },
+	{ 0x801a, KEY_CHANNELUP },
+	{ 0x801b, KEY_8 },
+	{ 0x801e, KEY_VOLUMEUP },
+	{ 0x801f, KEY_9 },
+};
+
+static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	u8 key[5],cmd = GET_RC_CODE;
+	dvb_usb_generic_rw(d,&cmd,1,key,5,0);
+	dvb_usb_nec_rc_key_to_event(d,key,event,state);
+	if (key[0] != 0)
+		deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
+	return 0;
+}
+
+static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	adap->fe_adap[0].fe = dtt200u_fe_attach(adap->dev);
+	return 0;
+}
+
+static struct dvb_usb_device_properties dtt200u_properties;
+static struct dvb_usb_device_properties wt220u_fc_properties;
+static struct dvb_usb_device_properties wt220u_properties;
+static struct dvb_usb_device_properties wt220u_zl0353_properties;
+static struct dvb_usb_device_properties wt220u_miglia_properties;
+
+static int dtt200u_usb_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	if (0 == dvb_usb_device_init(intf, &dtt200u_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &wt220u_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &wt220u_fc_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &wt220u_zl0353_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &wt220u_miglia_properties,
+				     THIS_MODULE, NULL, adapter_nr))
+		return 0;
+
+	return -ENODEV;
+}
+
+static struct usb_device_id dtt200u_usb_table [] = {
+	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) },
+	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) },
+	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD)  },
+	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM)  },
+	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD)  },
+	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM)  },
+	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD)  },
+	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM)  },
+	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD)  },
+	{ USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD)  },
+	{ 0 },
+};
+MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
+
+static struct dvb_usb_device_properties dtt200u_properties = {
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-dtt200u-01.fw",
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
+			.pid_filter_count = 15,
+
+	.streaming_ctrl  = dtt200u_streaming_ctrl,
+	.pid_filter      = dtt200u_pid_filter,
+	.frontend_attach = dtt200u_frontend_attach,
+	/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+		.count = 7,
+		.endpoint = 0x02,
+		.u = {
+			.bulk = {
+				.buffersize = 4096,
+			}
+		}
+	},
+		}},
+		}
+	},
+	.power_ctrl      = dtt200u_power_ctrl,
+
+	.rc.legacy = {
+		.rc_interval     = 300,
+		.rc_map_table    = rc_map_dtt200u_table,
+		.rc_map_size     = ARRAY_SIZE(rc_map_dtt200u_table),
+		.rc_query        = dtt200u_rc_query,
+	},
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "WideView/Yuan/Yakumo/Hama/Typhoon DVB-T USB2.0 (WT-200U)",
+		  .cold_ids = { &dtt200u_usb_table[0], NULL },
+		  .warm_ids = { &dtt200u_usb_table[1], NULL },
+		},
+		{ NULL },
+	}
+};
+
+static struct dvb_usb_device_properties wt220u_properties = {
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-wt220u-02.fw",
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
+			.pid_filter_count = 15,
+
+	.streaming_ctrl  = dtt200u_streaming_ctrl,
+	.pid_filter      = dtt200u_pid_filter,
+	.frontend_attach = dtt200u_frontend_attach,
+	/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+		.count = 7,
+		.endpoint = 0x02,
+		.u = {
+			.bulk = {
+				.buffersize = 4096,
+			}
+		}
+	},
+		}},
+		}
+	},
+	.power_ctrl      = dtt200u_power_ctrl,
+
+	.rc.legacy = {
+		.rc_interval     = 300,
+		.rc_map_table      = rc_map_dtt200u_table,
+		.rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table),
+		.rc_query        = dtt200u_rc_query,
+	},
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
+		  .cold_ids = { &dtt200u_usb_table[2], &dtt200u_usb_table[8], NULL },
+		  .warm_ids = { &dtt200u_usb_table[3], NULL },
+		},
+		{ NULL },
+	}
+};
+
+static struct dvb_usb_device_properties wt220u_fc_properties = {
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-wt220u-fc03.fw",
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
+			.pid_filter_count = 15,
+
+	.streaming_ctrl  = dtt200u_streaming_ctrl,
+	.pid_filter      = dtt200u_pid_filter,
+	.frontend_attach = dtt200u_frontend_attach,
+	/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+		.count = 7,
+				.endpoint = 0x06,
+		.u = {
+			.bulk = {
+				.buffersize = 4096,
+			}
+		}
+	},
+		}},
+		}
+	},
+	.power_ctrl      = dtt200u_power_ctrl,
+
+	.rc.legacy = {
+		.rc_interval     = 300,
+		.rc_map_table    = rc_map_dtt200u_table,
+		.rc_map_size     = ARRAY_SIZE(rc_map_dtt200u_table),
+		.rc_query        = dtt200u_rc_query,
+	},
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
+		  .cold_ids = { &dtt200u_usb_table[6], NULL },
+		  .warm_ids = { &dtt200u_usb_table[7], NULL },
+		},
+		{ NULL },
+	}
+};
+
+static struct dvb_usb_device_properties wt220u_zl0353_properties = {
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-wt220u-zl0353-01.fw",
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
+			.pid_filter_count = 15,
+
+			.streaming_ctrl  = dtt200u_streaming_ctrl,
+			.pid_filter      = dtt200u_pid_filter,
+			.frontend_attach = dtt200u_frontend_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 7,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+		}
+	},
+	.power_ctrl      = dtt200u_power_ctrl,
+
+	.rc.legacy = {
+		.rc_interval     = 300,
+		.rc_map_table    = rc_map_dtt200u_table,
+		.rc_map_size     = ARRAY_SIZE(rc_map_dtt200u_table),
+		.rc_query        = dtt200u_rc_query,
+	},
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "WideView WT-220U PenType Receiver (based on ZL353)",
+		  .cold_ids = { &dtt200u_usb_table[4], NULL },
+		  .warm_ids = { &dtt200u_usb_table[5], NULL },
+		},
+		{ NULL },
+	}
+};
+
+static struct dvb_usb_device_properties wt220u_miglia_properties = {
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-wt220u-miglia-01.fw",
+
+	.num_adapters = 1,
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "WideView WT-220U PenType Receiver (Miglia)",
+		  .cold_ids = { &dtt200u_usb_table[9], NULL },
+		  /* This device turns into WT220U_ZL0353_WARM when fw
+		     has been uploaded */
+		  .warm_ids = { NULL },
+		},
+		{ NULL },
+	}
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver dtt200u_usb_driver = {
+	.name		= "dvb_usb_dtt200u",
+	.probe		= dtt200u_usb_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table	= dtt200u_usb_table,
+};
+
+module_usb_driver(dtt200u_usb_driver);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/dtt200u.h b/drivers/media/usb/dvb-usb/dtt200u.h
new file mode 100644
index 0000000..005b0a7
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dtt200u.h
@@ -0,0 +1,57 @@
+/* Common header file of Linux driver for the WideView/ Yakumo/ Hama/
+ * Typhoon/ Yuan DVB-T USB2.0 receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the Free
+ *	Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_DTT200U_H_
+#define _DVB_USB_DTT200U_H_
+
+#define DVB_USB_LOG_PREFIX "dtt200u"
+
+#include "dvb-usb.h"
+
+extern int dvb_usb_dtt200u_debug;
+#define deb_info(args...) dprintk(dvb_usb_dtt200u_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_dtt200u_debug,0x02,args)
+
+/* guessed protocol description (reverse engineered):
+ * read
+ *  00 - USB type 0x02 for usb2.0, 0x01 for usb1.1
+ *  88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
+ */
+
+#define GET_SPEED		0x00
+#define GET_TUNE_STATUS		0x81
+#define GET_RC_CODE		0x84
+#define GET_CONFIGURATION	0x88
+#define GET_AGC			0x89
+#define GET_SNR			0x8a
+#define GET_VIT_ERR_CNT		0x8c
+#define GET_RS_ERR_CNT		0x8d
+#define GET_RS_UNCOR_BLK_CNT	0x8e
+
+/* write
+ *  01 - init
+ *  02 - frequency (divided by 250000)
+ *  03 - bandwidth
+ *  04 - pid table (index pid(7:0) pid(12:8))
+ *  05 - reset the pid table
+ *  08 - transfer switch
+ */
+
+#define SET_INIT		0x01
+#define SET_RF_FREQ		0x02
+#define SET_BANDWIDTH		0x03
+#define SET_PID_FILTER		0x04
+#define RESET_PID_FILTER	0x05
+#define SET_STREAMING		0x08
+
+extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d);
+
+#endif
diff --git a/drivers/media/usb/dvb-usb/dtv5100.c b/drivers/media/usb/dvb-usb/dtv5100.c
new file mode 100644
index 0000000..3d11df4
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dtv5100.c
@@ -0,0 +1,224 @@
+/*
+ * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T
+ *
+ * Copyright (C) 2008  Antoine Jacquet <royale@zerezo.com>
+ * http://royale.zerezo.com/dtv5100/
+ *
+ * Inspired by gl861.c and au6610.c drivers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "dtv5100.h"
+#include "zl10353.h"
+#include "qt1010.h"
+
+/* debug */
+static int dvb_usb_dtv5100_debug;
+module_param_named(debug, dvb_usb_dtv5100_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr,
+			   u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+	u8 request;
+	u8 type;
+	u16 value;
+	u16 index;
+
+	switch (wlen) {
+	case 1:
+		/* write { reg }, read { value } */
+		request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ :
+							DTV5100_TUNER_READ);
+		type = USB_TYPE_VENDOR | USB_DIR_IN;
+		value = 0;
+		break;
+	case 2:
+		/* write { reg, value } */
+		request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE :
+							DTV5100_TUNER_WRITE);
+		type = USB_TYPE_VENDOR | USB_DIR_OUT;
+		value = wbuf[1];
+		break;
+	default:
+		warn("wlen = %x, aborting.", wlen);
+		return -EINVAL;
+	}
+	index = (addr << 8) + wbuf[0];
+
+	msleep(1); /* avoid I2C errors */
+	return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), request,
+			       type, value, index, rbuf, rlen,
+			       DTV5100_USB_TIMEOUT);
+}
+
+/* I2C */
+static int dtv5100_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+			    int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int i;
+
+	if (num > 2)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		/* write/read request */
+		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+			if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf,
+					    msg[i].len, msg[i+1].buf,
+					    msg[i+1].len) < 0)
+				break;
+			i++;
+		} else if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf,
+					   msg[i].len, NULL, 0) < 0)
+				break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return i;
+}
+
+static u32 dtv5100_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dtv5100_i2c_algo = {
+	.master_xfer   = dtv5100_i2c_xfer,
+	.functionality = dtv5100_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static struct zl10353_config dtv5100_zl10353_config = {
+	.demod_address = DTV5100_DEMOD_ADDR,
+	.no_tuner = 1,
+	.parallel_ts = 1,
+};
+
+static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config,
+			      &adap->dev->i2c_adap);
+	if (adap->fe_adap[0].fe == NULL)
+		return -EIO;
+
+	/* disable i2c gate, or it won't work... is this safe? */
+	adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL;
+
+	return 0;
+}
+
+static struct qt1010_config dtv5100_qt1010_config = {
+	.i2c_address = DTV5100_TUNER_ADDR
+};
+
+static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	return dvb_attach(qt1010_attach,
+			  adap->fe_adap[0].fe, &adap->dev->i2c_adap,
+			  &dtv5100_qt1010_config) == NULL ? -ENODEV : 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties dtv5100_properties;
+
+static int dtv5100_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	int i, ret;
+	struct usb_device *udev = interface_to_usbdev(intf);
+
+	/* initialize non qt1010/zl10353 part? */
+	for (i = 0; dtv5100_init[i].request; i++) {
+		ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+				      dtv5100_init[i].request,
+				      USB_TYPE_VENDOR | USB_DIR_OUT,
+				      dtv5100_init[i].value,
+				      dtv5100_init[i].index, NULL, 0,
+				      DTV5100_USB_TIMEOUT);
+		if (ret)
+			return ret;
+	}
+
+	ret = dvb_usb_device_init(intf, &dtv5100_properties,
+				  THIS_MODULE, NULL, adapter_nr);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static struct usb_device_id dtv5100_table[] = {
+	{ USB_DEVICE(0x06be, 0xa232) },
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, dtv5100_table);
+
+static struct dvb_usb_device_properties dtv5100_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+
+	.size_of_priv = 0,
+
+	.num_adapters = 1,
+	.adapter = {{
+		.num_frontends = 1,
+		.fe = {{
+		.frontend_attach = dtv5100_frontend_attach,
+		.tuner_attach    = dtv5100_tuner_attach,
+
+		.stream = {
+			.type = USB_BULK,
+			.count = 8,
+			.endpoint = 0x82,
+			.u = {
+				.bulk = {
+					.buffersize = 4096,
+				}
+			}
+		},
+		}},
+	} },
+
+	.i2c_algo = &dtv5100_i2c_algo,
+
+	.num_device_descs = 1,
+	.devices = {
+		{
+			.name = "AME DTV-5100 USB2.0 DVB-T",
+			.cold_ids = { NULL },
+			.warm_ids = { &dtv5100_table[0], NULL },
+		},
+	}
+};
+
+static struct usb_driver dtv5100_driver = {
+	.name		= "dvb_usb_dtv5100",
+	.probe		= dtv5100_probe,
+	.disconnect	= dvb_usb_device_exit,
+	.id_table	= dtv5100_table,
+};
+
+module_usb_driver(dtv5100_driver);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/dtv5100.h b/drivers/media/usb/dvb-usb/dtv5100.h
new file mode 100644
index 0000000..93e96e0
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dtv5100.h
@@ -0,0 +1,51 @@
+/*
+ * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T
+ *
+ * Copyright (C) 2008  Antoine Jacquet <royale@zerezo.com>
+ * http://royale.zerezo.com/dtv5100/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _DVB_USB_DTV5100_H_
+#define _DVB_USB_DTV5100_H_
+
+#define DVB_USB_LOG_PREFIX "dtv5100"
+#include "dvb-usb.h"
+
+#define DTV5100_USB_TIMEOUT 500
+
+#define DTV5100_DEMOD_ADDR	0x00
+#define DTV5100_DEMOD_WRITE	0xc0
+#define DTV5100_DEMOD_READ	0xc1
+
+#define DTV5100_TUNER_ADDR	0xc4
+#define DTV5100_TUNER_WRITE	0xc7
+#define DTV5100_TUNER_READ	0xc8
+
+#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
+#define DRIVER_DESC "AME DTV-5100 USB2.0 DVB-T"
+
+static struct {
+	u8 request;
+	u8 value;
+	u16 index;
+} dtv5100_init[] = {
+	{ 0x000000c5, 0x00000000, 0x00000001 },
+	{ 0x000000c5, 0x00000001, 0x00000001 },
+	{ }		/* Terminating entry */
+};
+
+#endif
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-common.h b/drivers/media/usb/dvb-usb/dvb-usb-common.h
new file mode 100644
index 0000000..6b7b2a8
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dvb-usb-common.h
@@ -0,0 +1,52 @@
+/* dvb-usb-common.h is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * a header file containing prototypes and types for internal use of the dvb-usb-lib
+ */
+#ifndef _DVB_USB_COMMON_H_
+#define _DVB_USB_COMMON_H_
+
+#define DVB_USB_LOG_PREFIX "dvb-usb"
+#include "dvb-usb.h"
+
+extern int dvb_usb_debug;
+extern int dvb_usb_disable_rc_polling;
+
+#define deb_info(args...)  dprintk(dvb_usb_debug,0x001,args)
+#define deb_xfer(args...)  dprintk(dvb_usb_debug,0x002,args)
+#define deb_pll(args...)   dprintk(dvb_usb_debug,0x004,args)
+#define deb_ts(args...)    dprintk(dvb_usb_debug,0x008,args)
+#define deb_err(args...)   dprintk(dvb_usb_debug,0x010,args)
+#define deb_rc(args...)    dprintk(dvb_usb_debug,0x020,args)
+#define deb_fw(args...)    dprintk(dvb_usb_debug,0x040,args)
+#define deb_mem(args...)   dprintk(dvb_usb_debug,0x080,args)
+#define deb_uxfer(args...) dprintk(dvb_usb_debug,0x100,args)
+
+/* commonly used  methods */
+extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_device_properties *);
+
+extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff);
+
+extern int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props);
+extern int usb_urb_exit(struct usb_data_stream *stream);
+extern int usb_urb_submit(struct usb_data_stream *stream);
+extern int usb_urb_kill(struct usb_data_stream *stream);
+
+extern int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap);
+extern int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap);
+
+extern int dvb_usb_i2c_init(struct dvb_usb_device *);
+extern int dvb_usb_i2c_exit(struct dvb_usb_device *);
+
+extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap,
+				    short *adapter_nums);
+extern int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap);
+extern int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap);
+extern int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap);
+
+extern int dvb_usb_remote_init(struct dvb_usb_device *);
+extern int dvb_usb_remote_exit(struct dvb_usb_device *);
+
+#endif
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
new file mode 100644
index 0000000..719413b
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
@@ -0,0 +1,288 @@
+/* dvb-usb-dvb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing and handling the
+ * linux-dvb API.
+ */
+#include "dvb-usb-common.h"
+
+/* does the complete input transfer handling */
+static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
+{
+	struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
+	int newfeedcount, ret;
+
+	if (adap == NULL)
+		return -ENODEV;
+
+	if ((adap->active_fe < 0) ||
+	    (adap->active_fe >= adap->num_frontends_initialized)) {
+		return -EINVAL;
+	}
+
+	newfeedcount = adap->feedcount + (onoff ? 1 : -1);
+
+	/* stop feed before setting a new pid if there will be no pid anymore */
+	if (newfeedcount == 0) {
+		deb_ts("stop feeding\n");
+		usb_urb_kill(&adap->fe_adap[adap->active_fe].stream);
+
+		if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) {
+			ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 0);
+			if (ret < 0) {
+				err("error while stopping stream.");
+				return ret;
+			}
+		}
+	}
+
+	adap->feedcount = newfeedcount;
+
+	/* activate the pid on the device specific pid_filter */
+	deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",
+		adap->fe_adap[adap->active_fe].pid_filtering ?
+		"yes" : "no", dvbdmxfeed->pid, dvbdmxfeed->pid,
+		dvbdmxfeed->index, onoff ? "on" : "off");
+	if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+		adap->fe_adap[adap->active_fe].pid_filtering &&
+		adap->props.fe[adap->active_fe].pid_filter != NULL)
+		adap->props.fe[adap->active_fe].pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, onoff);
+
+	/* start the feed if this was the first feed and there is still a feed
+	 * for reception.
+	 */
+	if (adap->feedcount == onoff && adap->feedcount > 0) {
+		deb_ts("submitting all URBs\n");
+		usb_urb_submit(&adap->fe_adap[adap->active_fe].stream);
+
+		deb_ts("controlling pid parser\n");
+		if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+			adap->props.fe[adap->active_fe].caps &
+			DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
+			adap->props.fe[adap->active_fe].pid_filter_ctrl != NULL) {
+			ret = adap->props.fe[adap->active_fe].pid_filter_ctrl(adap,
+				adap->fe_adap[adap->active_fe].pid_filtering);
+			if (ret < 0) {
+				err("could not handle pid_parser");
+				return ret;
+			}
+		}
+		deb_ts("start feeding\n");
+		if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) {
+			ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 1);
+			if (ret < 0) {
+				err("error while enabling fifo.");
+				return ret;
+			}
+		}
+
+	}
+	return 0;
+}
+
+static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
+	return dvb_usb_ctrl_feed(dvbdmxfeed,1);
+}
+
+static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type);
+	return dvb_usb_ctrl_feed(dvbdmxfeed,0);
+}
+
+int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
+{
+	int i;
+	int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name,
+				       adap->dev->owner, &adap->dev->udev->dev,
+				       adapter_nums);
+
+	if (ret < 0) {
+		deb_info("dvb_register_adapter failed: error %d", ret);
+		goto err;
+	}
+	adap->dvb_adap.priv = adap;
+
+	if (adap->dev->props.read_mac_address) {
+		if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0)
+			info("MAC address: %pM",adap->dvb_adap.proposed_mac);
+		else
+			err("MAC address reading failed.");
+	}
+
+
+	adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+	adap->demux.priv             = adap;
+
+	adap->demux.filternum        = 0;
+	for (i = 0; i < adap->props.num_frontends; i++) {
+		if (adap->demux.filternum < adap->fe_adap[i].max_feed_count)
+			adap->demux.filternum = adap->fe_adap[i].max_feed_count;
+	}
+	adap->demux.feednum          = adap->demux.filternum;
+	adap->demux.start_feed       = dvb_usb_start_feed;
+	adap->demux.stop_feed        = dvb_usb_stop_feed;
+	adap->demux.write_to_decoder = NULL;
+	if ((ret = dvb_dmx_init(&adap->demux)) < 0) {
+		err("dvb_dmx_init failed: error %d",ret);
+		goto err_dmx;
+	}
+
+	adap->dmxdev.filternum       = adap->demux.filternum;
+	adap->dmxdev.demux           = &adap->demux.dmx;
+	adap->dmxdev.capabilities    = 0;
+	if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap)) < 0) {
+		err("dvb_dmxdev_init failed: error %d",ret);
+		goto err_dmx_dev;
+	}
+
+	if ((ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net,
+						&adap->demux.dmx)) < 0) {
+		err("dvb_net_init failed: error %d",ret);
+		goto err_net_init;
+	}
+
+	adap->state |= DVB_USB_ADAP_STATE_DVB;
+	return 0;
+
+err_net_init:
+	dvb_dmxdev_release(&adap->dmxdev);
+err_dmx_dev:
+	dvb_dmx_release(&adap->demux);
+err_dmx:
+	dvb_unregister_adapter(&adap->dvb_adap);
+err:
+	return ret;
+}
+
+int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap)
+{
+	if (adap->state & DVB_USB_ADAP_STATE_DVB) {
+		deb_info("unregistering DVB part\n");
+		dvb_net_release(&adap->dvb_net);
+		adap->demux.dmx.close(&adap->demux.dmx);
+		dvb_dmxdev_release(&adap->dmxdev);
+		dvb_dmx_release(&adap->demux);
+		dvb_unregister_adapter(&adap->dvb_adap);
+		adap->state &= ~DVB_USB_ADAP_STATE_DVB;
+	}
+	return 0;
+}
+
+static int dvb_usb_set_active_fe(struct dvb_frontend *fe, int onoff)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+	int ret = (adap->props.frontend_ctrl) ?
+		adap->props.frontend_ctrl(fe, onoff) : 0;
+
+	if (ret < 0) {
+		err("frontend_ctrl request failed");
+		return ret;
+	}
+	if (onoff)
+		adap->active_fe = fe->id;
+
+	return 0;
+}
+
+static int dvb_usb_fe_wakeup(struct dvb_frontend *fe)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+	dvb_usb_device_power_ctrl(adap->dev, 1);
+
+	dvb_usb_set_active_fe(fe, 1);
+
+	if (adap->fe_adap[fe->id].fe_init)
+		adap->fe_adap[fe->id].fe_init(fe);
+
+	return 0;
+}
+
+static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+	if (adap->fe_adap[fe->id].fe_sleep)
+		adap->fe_adap[fe->id].fe_sleep(fe);
+
+	dvb_usb_set_active_fe(fe, 0);
+
+	return dvb_usb_device_power_ctrl(adap->dev, 0);
+}
+
+int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap)
+{
+	int ret, i;
+
+	/* register all given adapter frontends */
+	for (i = 0; i < adap->props.num_frontends; i++) {
+
+		if (adap->props.fe[i].frontend_attach == NULL) {
+			err("strange: '%s' #%d,%d "
+			    "doesn't want to attach a frontend.",
+			    adap->dev->desc->name, adap->id, i);
+
+			return 0;
+		}
+
+		ret = adap->props.fe[i].frontend_attach(adap);
+		if (ret || adap->fe_adap[i].fe == NULL) {
+			/* only print error when there is no FE at all */
+			if (i == 0)
+				err("no frontend was attached by '%s'",
+					adap->dev->desc->name);
+
+			return 0;
+		}
+
+		adap->fe_adap[i].fe->id = i;
+
+		/* re-assign sleep and wakeup functions */
+		adap->fe_adap[i].fe_init = adap->fe_adap[i].fe->ops.init;
+		adap->fe_adap[i].fe->ops.init  = dvb_usb_fe_wakeup;
+		adap->fe_adap[i].fe_sleep = adap->fe_adap[i].fe->ops.sleep;
+		adap->fe_adap[i].fe->ops.sleep = dvb_usb_fe_sleep;
+
+		if (dvb_register_frontend(&adap->dvb_adap, adap->fe_adap[i].fe)) {
+			err("Frontend %d registration failed.", i);
+			dvb_frontend_detach(adap->fe_adap[i].fe);
+			adap->fe_adap[i].fe = NULL;
+			/* In error case, do not try register more FEs,
+			 * still leaving already registered FEs alive. */
+			if (i == 0)
+				return -ENODEV;
+			else
+				return 0;
+		}
+
+		/* only attach the tuner if the demod is there */
+		if (adap->props.fe[i].tuner_attach != NULL)
+			adap->props.fe[i].tuner_attach(adap);
+
+		adap->num_frontends_initialized++;
+	}
+
+	return 0;
+}
+
+int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap)
+{
+	int i = adap->num_frontends_initialized - 1;
+
+	/* unregister all given adapter frontends */
+	for (; i >= 0; i--) {
+		if (adap->fe_adap[i].fe != NULL) {
+			dvb_unregister_frontend(adap->fe_adap[i].fe);
+			dvb_frontend_detach(adap->fe_adap[i].fe);
+		}
+	}
+	adap->num_frontends_initialized = 0;
+
+	return 0;
+}
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
new file mode 100644
index 0000000..733a7ff
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
@@ -0,0 +1,146 @@
+/* dvb-usb-firmware.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for downloading the firmware to Cypress FX 1 and 2 based devices.
+ *
+ * FIXME: This part does actually not belong to dvb-usb, but to the usb-subsystem.
+ */
+#include "dvb-usb-common.h"
+
+#include <linux/usb.h>
+
+struct usb_cypress_controller {
+	int id;
+	const char *name;       /* name of the usb controller */
+	u16 cpu_cs_register;    /* needs to be restarted, when the firmware has been downloaded. */
+};
+
+static struct usb_cypress_controller cypress[] = {
+	{ .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 },
+	{ .id = CYPRESS_AN2135,  .name = "Cypress AN2135",  .cpu_cs_register = 0x7f92 },
+	{ .id = CYPRESS_AN2235,  .name = "Cypress AN2235",  .cpu_cs_register = 0x7f92 },
+	{ .id = CYPRESS_FX2,     .name = "Cypress FX2",     .cpu_cs_register = 0xe600 },
+};
+
+/*
+ * load a firmware packet to the device
+ */
+static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
+{
+	return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
+			0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
+}
+
+int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
+{
+	struct hexline hx;
+	u8 reset;
+	int ret,pos=0;
+
+	/* stop the CPU */
+	reset = 1;
+	if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
+		err("could not stop the USB controller CPU.");
+
+	while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) {
+		deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk);
+		ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len);
+
+		if (ret != hx.len) {
+			err("error while transferring firmware "
+				"(transferred size: %d, block size: %d)",
+				ret,hx.len);
+			ret = -EINVAL;
+			break;
+		}
+	}
+	if (ret < 0) {
+		err("firmware download failed at %d with %d",pos,ret);
+		return ret;
+	}
+
+	if (ret == 0) {
+		/* restart the CPU */
+		reset = 0;
+		if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
+			err("could not restart the USB controller CPU.");
+			ret = -EINVAL;
+		}
+	} else
+		ret = -EIO;
+
+	return ret;
+}
+EXPORT_SYMBOL(usb_cypress_load_firmware);
+
+int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_device_properties *props)
+{
+	int ret;
+	const struct firmware *fw = NULL;
+
+	if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) {
+		err("did not find the firmware file. (%s) "
+			"Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
+			props->firmware,ret);
+		return ret;
+	}
+
+	info("downloading firmware from file '%s'",props->firmware);
+
+	switch (props->usb_ctrl) {
+		case CYPRESS_AN2135:
+		case CYPRESS_AN2235:
+		case CYPRESS_FX2:
+			ret = usb_cypress_load_firmware(udev, fw, props->usb_ctrl);
+			break;
+		case DEVICE_SPECIFIC:
+			if (props->download_firmware)
+				ret = props->download_firmware(udev,fw);
+			else {
+				err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one.");
+				ret = -EINVAL;
+			}
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+	}
+
+	release_firmware(fw);
+	return ret;
+}
+
+int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx,
+			       int *pos)
+{
+	u8 *b = (u8 *) &fw->data[*pos];
+	int data_offs = 4;
+	if (*pos >= fw->size)
+		return 0;
+
+	memset(hx,0,sizeof(struct hexline));
+
+	hx->len  = b[0];
+
+	if ((*pos + hx->len + 4) >= fw->size)
+		return -EINVAL;
+
+	hx->addr = b[1] | (b[2] << 8);
+	hx->type = b[3];
+
+	if (hx->type == 0x04) {
+		/* b[4] and b[5] are the Extended linear address record data field */
+		hx->addr |= (b[4] << 24) | (b[5] << 16);
+/*		hx->len -= 2;
+		data_offs += 2; */
+	}
+	memcpy(hx->data,&b[data_offs],hx->len);
+	hx->chk = b[hx->len + data_offs];
+
+	*pos += hx->len + 5;
+
+	return *pos;
+}
+EXPORT_SYMBOL(dvb_usb_get_hexline);
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-i2c.c b/drivers/media/usb/dvb-usb/dvb-usb-i2c.c
new file mode 100644
index 0000000..88e4a62
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dvb-usb-i2c.c
@@ -0,0 +1,43 @@
+/* dvb-usb-i2c.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for (de-)initializing an I2C adapter.
+ */
+#include "dvb-usb-common.h"
+
+int dvb_usb_i2c_init(struct dvb_usb_device *d)
+{
+	int ret = 0;
+
+	if (!(d->props.caps & DVB_USB_IS_AN_I2C_ADAPTER))
+		return 0;
+
+	if (d->props.i2c_algo == NULL) {
+		err("no i2c algorithm specified");
+		return -EINVAL;
+	}
+
+	strlcpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
+	d->i2c_adap.algo      = d->props.i2c_algo;
+	d->i2c_adap.algo_data = NULL;
+	d->i2c_adap.dev.parent = &d->udev->dev;
+
+	i2c_set_adapdata(&d->i2c_adap, d);
+
+	if ((ret = i2c_add_adapter(&d->i2c_adap)) < 0)
+		err("could not add i2c adapter");
+
+	d->state |= DVB_USB_STATE_I2C;
+
+	return ret;
+}
+
+int dvb_usb_i2c_exit(struct dvb_usb_device *d)
+{
+	if (d->state & DVB_USB_STATE_I2C)
+		i2c_del_adapter(&d->i2c_adap);
+	d->state &= ~DVB_USB_STATE_I2C;
+	return 0;
+}
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c
new file mode 100644
index 0000000..169196e
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c
@@ -0,0 +1,304 @@
+/*
+ * DVB USB library - provides a generic interface for a DVB USB device driver.
+ *
+ * dvb-usb-init.c
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the Free
+ *	Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dvb-usb-common.h"
+
+/* debug */
+int dvb_usb_debug;
+module_param_named(debug, dvb_usb_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256  (or-able))." DVB_USB_DEBUG_STATUS);
+
+int dvb_usb_disable_rc_polling;
+module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644);
+MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0).");
+
+static int dvb_usb_force_pid_filter_usage;
+module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444);
+MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
+
+static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
+{
+	struct dvb_usb_adapter *adap;
+	int ret, n, o;
+
+	for (n = 0; n < d->props.num_adapters; n++) {
+		adap = &d->adapter[n];
+		adap->dev = d;
+		adap->id  = n;
+
+		memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties));
+
+	for (o = 0; o < adap->props.num_frontends; o++) {
+		struct dvb_usb_adapter_fe_properties *props = &adap->props.fe[o];
+		/* speed - when running at FULL speed we need a HW PID filter */
+		if (d->udev->speed == USB_SPEED_FULL && !(props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
+			err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
+			return -ENODEV;
+		}
+
+		if ((d->udev->speed == USB_SPEED_FULL && props->caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
+			(props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
+			info("will use the device's hardware PID filter (table count: %d).", props->pid_filter_count);
+			adap->fe_adap[o].pid_filtering  = 1;
+			adap->fe_adap[o].max_feed_count = props->pid_filter_count;
+		} else {
+			info("will pass the complete MPEG2 transport stream to the software demuxer.");
+			adap->fe_adap[o].pid_filtering  = 0;
+			adap->fe_adap[o].max_feed_count = 255;
+		}
+
+		if (!adap->fe_adap[o].pid_filtering &&
+			dvb_usb_force_pid_filter_usage &&
+			props->caps & DVB_USB_ADAP_HAS_PID_FILTER) {
+			info("pid filter enabled by module option.");
+			adap->fe_adap[o].pid_filtering  = 1;
+			adap->fe_adap[o].max_feed_count = props->pid_filter_count;
+		}
+
+		if (props->size_of_priv > 0) {
+			adap->fe_adap[o].priv = kzalloc(props->size_of_priv, GFP_KERNEL);
+			if (adap->fe_adap[o].priv == NULL) {
+				err("no memory for priv for adapter %d fe %d.", n, o);
+				return -ENOMEM;
+			}
+		}
+	}
+
+		if (adap->props.size_of_priv > 0) {
+			adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL);
+			if (adap->priv == NULL) {
+				err("no memory for priv for adapter %d.", n);
+				return -ENOMEM;
+			}
+		}
+
+		if ((ret = dvb_usb_adapter_stream_init(adap)) ||
+			(ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs)) ||
+			(ret = dvb_usb_adapter_frontend_init(adap))) {
+			return ret;
+		}
+
+		/* use exclusive FE lock if there is multiple shared FEs */
+		if (adap->fe_adap[1].fe)
+			adap->dvb_adap.mfe_shared = 1;
+
+		d->num_adapters_initialized++;
+		d->state |= DVB_USB_STATE_DVB;
+	}
+
+	/*
+	 * when reloading the driver w/o replugging the device
+	 * sometimes a timeout occures, this helps
+	 */
+	if (d->props.generic_bulk_ctrl_endpoint != 0) {
+		usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+		usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+	}
+
+	return 0;
+}
+
+static int dvb_usb_adapter_exit(struct dvb_usb_device *d)
+{
+	int n;
+
+	for (n = 0; n < d->num_adapters_initialized; n++) {
+		dvb_usb_adapter_frontend_exit(&d->adapter[n]);
+		dvb_usb_adapter_dvb_exit(&d->adapter[n]);
+		dvb_usb_adapter_stream_exit(&d->adapter[n]);
+		kfree(d->adapter[n].priv);
+	}
+	d->num_adapters_initialized = 0;
+	d->state &= ~DVB_USB_STATE_DVB;
+	return 0;
+}
+
+
+/* general initialization functions */
+static int dvb_usb_exit(struct dvb_usb_device *d)
+{
+	deb_info("state before exiting everything: %x\n", d->state);
+	dvb_usb_remote_exit(d);
+	dvb_usb_adapter_exit(d);
+	dvb_usb_i2c_exit(d);
+	deb_info("state should be zero now: %x\n", d->state);
+	d->state = DVB_USB_STATE_INIT;
+	kfree(d->priv);
+	kfree(d);
+	return 0;
+}
+
+static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums)
+{
+	int ret = 0;
+
+	mutex_init(&d->usb_mutex);
+	mutex_init(&d->i2c_mutex);
+
+	d->state = DVB_USB_STATE_INIT;
+
+	if (d->props.size_of_priv > 0) {
+		d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL);
+		if (d->priv == NULL) {
+			err("no memory for priv in 'struct dvb_usb_device'");
+			return -ENOMEM;
+		}
+	}
+
+	/* check the capabilities and set appropriate variables */
+	dvb_usb_device_power_ctrl(d, 1);
+
+	if ((ret = dvb_usb_i2c_init(d)) ||
+		(ret = dvb_usb_adapter_init(d, adapter_nums))) {
+		dvb_usb_exit(d);
+		return ret;
+	}
+
+	if ((ret = dvb_usb_remote_init(d)))
+		err("could not initialize remote control.");
+
+	dvb_usb_device_power_ctrl(d, 0);
+
+	return 0;
+}
+
+/* determine the name and the state of the just found USB device */
+static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *udev, struct dvb_usb_device_properties *props, int *cold)
+{
+	int i, j;
+	struct dvb_usb_device_description *desc = NULL;
+
+	*cold = -1;
+
+	for (i = 0; i < props->num_device_descs; i++) {
+
+		for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) {
+			deb_info("check for cold %x %x\n", props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct);
+			if (props->devices[i].cold_ids[j]->idVendor  == le16_to_cpu(udev->descriptor.idVendor) &&
+				props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
+				*cold = 1;
+				desc = &props->devices[i];
+				break;
+			}
+		}
+
+		if (desc != NULL)
+			break;
+
+		for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) {
+			deb_info("check for warm %x %x\n", props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct);
+			if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
+				props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
+				*cold = 0;
+				desc = &props->devices[i];
+				break;
+			}
+		}
+	}
+
+	if (desc != NULL && props->identify_state != NULL)
+		props->identify_state(udev, props, &desc, cold);
+
+	return desc;
+}
+
+int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	if (onoff)
+		d->powered++;
+	else
+		d->powered--;
+
+	if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */
+		deb_info("power control: %d\n", onoff);
+		if (d->props.power_ctrl)
+			return d->props.power_ctrl(d, onoff);
+	}
+	return 0;
+}
+
+/*
+ * USB
+ */
+int dvb_usb_device_init(struct usb_interface *intf,
+			struct dvb_usb_device_properties *props,
+			struct module *owner, struct dvb_usb_device **du,
+			short *adapter_nums)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct dvb_usb_device *d = NULL;
+	struct dvb_usb_device_description *desc = NULL;
+
+	int ret = -ENOMEM, cold = 0;
+
+	if (du != NULL)
+		*du = NULL;
+
+	if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) {
+		deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
+		return -ENODEV;
+	}
+
+	if (cold) {
+		info("found a '%s' in cold state, will try to load a firmware", desc->name);
+		ret = dvb_usb_download_firmware(udev, props);
+		if (!props->no_reconnect || ret != 0)
+			return ret;
+	}
+
+	info("found a '%s' in warm state.", desc->name);
+	d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL);
+	if (d == NULL) {
+		err("no memory for 'struct dvb_usb_device'");
+		return -ENOMEM;
+	}
+
+	d->udev = udev;
+	memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties));
+	d->desc = desc;
+	d->owner = owner;
+
+	usb_set_intfdata(intf, d);
+
+	if (du != NULL)
+		*du = d;
+
+	ret = dvb_usb_init(d, adapter_nums);
+
+	if (ret == 0)
+		info("%s successfully initialized and connected.", desc->name);
+	else
+		info("%s error while loading driver (%d)", desc->name, ret);
+	return ret;
+}
+EXPORT_SYMBOL(dvb_usb_device_init);
+
+void dvb_usb_device_exit(struct usb_interface *intf)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+	const char *name = "generic DVB-USB module";
+
+	usb_set_intfdata(intf, NULL);
+	if (d != NULL && d->desc != NULL) {
+		name = d->desc->name;
+		dvb_usb_exit(d);
+	}
+	info("%s successfully deinitialized and disconnected.", name);
+
+}
+EXPORT_SYMBOL(dvb_usb_device_exit);
+
+MODULE_VERSION("1.0");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
new file mode 100644
index 0000000..41bacff
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
@@ -0,0 +1,391 @@
+/* dvb-usb-remote.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing the input-device and for handling remote-control-queries.
+ */
+#include "dvb-usb-common.h"
+#include <linux/usb/input.h>
+
+static unsigned int
+legacy_dvb_usb_get_keymap_index(const struct input_keymap_entry *ke,
+				struct rc_map_table *keymap,
+				unsigned int keymap_size)
+{
+	unsigned int index;
+	unsigned int scancode;
+
+	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+		index = ke->index;
+	} else {
+		if (input_scancode_to_scalar(ke, &scancode))
+			return keymap_size;
+
+		/* See if we can match the raw key code. */
+		for (index = 0; index < keymap_size; index++)
+			if (keymap[index].scancode == scancode)
+				break;
+
+		/* See if there is an unused hole in the map */
+		if (index >= keymap_size) {
+			for (index = 0; index < keymap_size; index++) {
+				if (keymap[index].keycode == KEY_RESERVED ||
+				    keymap[index].keycode == KEY_UNKNOWN) {
+					break;
+				}
+			}
+		}
+	}
+
+	return index;
+}
+
+static int legacy_dvb_usb_getkeycode(struct input_dev *dev,
+				     struct input_keymap_entry *ke)
+{
+	struct dvb_usb_device *d = input_get_drvdata(dev);
+	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
+	unsigned int keymap_size = d->props.rc.legacy.rc_map_size;
+	unsigned int index;
+
+	index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);
+	if (index >= keymap_size)
+		return -EINVAL;
+
+	ke->keycode = keymap[index].keycode;
+	if (ke->keycode == KEY_UNKNOWN)
+		ke->keycode = KEY_RESERVED;
+	ke->len = sizeof(keymap[index].scancode);
+	memcpy(&ke->scancode, &keymap[index].scancode, ke->len);
+	ke->index = index;
+
+	return 0;
+}
+
+static int legacy_dvb_usb_setkeycode(struct input_dev *dev,
+				     const struct input_keymap_entry *ke,
+				     unsigned int *old_keycode)
+{
+	struct dvb_usb_device *d = input_get_drvdata(dev);
+	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
+	unsigned int keymap_size = d->props.rc.legacy.rc_map_size;
+	unsigned int index;
+
+	index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);
+	/*
+	 * FIXME: Currently, it is not possible to increase the size of
+	 * scancode table. For it to happen, one possibility
+	 * would be to allocate a table with key_map_size + 1,
+	 * copying data, appending the new key on it, and freeing
+	 * the old one - or maybe just allocating some spare space
+	 */
+	if (index >= keymap_size)
+		return -EINVAL;
+
+	*old_keycode = keymap[index].keycode;
+	keymap->keycode = ke->keycode;
+	__set_bit(ke->keycode, dev->keybit);
+
+	if (*old_keycode != KEY_RESERVED) {
+		__clear_bit(*old_keycode, dev->keybit);
+		for (index = 0; index < keymap_size; index++) {
+			if (keymap[index].keycode == *old_keycode) {
+				__set_bit(*old_keycode, dev->keybit);
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* Remote-control poll function - called every dib->rc_query_interval ms to see
+ * whether the remote control has received anything.
+ *
+ * TODO: Fix the repeat rate of the input device.
+ */
+static void legacy_dvb_usb_read_remote_control(struct work_struct *work)
+{
+	struct dvb_usb_device *d =
+		container_of(work, struct dvb_usb_device, rc_query_work.work);
+	u32 event;
+	int state;
+
+	/* TODO: need a lock here.  We can simply skip checking for the remote control
+	   if we're busy. */
+
+	/* when the parameter has been set to 1 via sysfs while the driver was running */
+	if (dvb_usb_disable_rc_polling)
+		return;
+
+	if (d->props.rc.legacy.rc_query(d,&event,&state)) {
+		err("error while querying for an remote control event.");
+		goto schedule;
+	}
+
+
+	switch (state) {
+		case REMOTE_NO_KEY_PRESSED:
+			break;
+		case REMOTE_KEY_PRESSED:
+			deb_rc("key pressed\n");
+			d->last_event = event;
+		case REMOTE_KEY_REPEAT:
+			deb_rc("key repeated\n");
+			input_event(d->input_dev, EV_KEY, event, 1);
+			input_sync(d->input_dev);
+			input_event(d->input_dev, EV_KEY, d->last_event, 0);
+			input_sync(d->input_dev);
+			break;
+		default:
+			break;
+	}
+
+/* improved repeat handling ???
+	switch (state) {
+		case REMOTE_NO_KEY_PRESSED:
+			deb_rc("NO KEY PRESSED\n");
+			if (d->last_state != REMOTE_NO_KEY_PRESSED) {
+				deb_rc("releasing event %d\n",d->last_event);
+				input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
+				input_sync(d->rc_input_dev);
+			}
+			d->last_state = REMOTE_NO_KEY_PRESSED;
+			d->last_event = 0;
+			break;
+		case REMOTE_KEY_PRESSED:
+			deb_rc("KEY PRESSED\n");
+			deb_rc("pressing event %d\n",event);
+
+			input_event(d->rc_input_dev, EV_KEY, event, 1);
+			input_sync(d->rc_input_dev);
+
+			d->last_event = event;
+			d->last_state = REMOTE_KEY_PRESSED;
+			break;
+		case REMOTE_KEY_REPEAT:
+			deb_rc("KEY_REPEAT\n");
+			if (d->last_state != REMOTE_NO_KEY_PRESSED) {
+				deb_rc("repeating event %d\n",d->last_event);
+				input_event(d->rc_input_dev, EV_KEY, d->last_event, 2);
+				input_sync(d->rc_input_dev);
+				d->last_state = REMOTE_KEY_REPEAT;
+			}
+		default:
+			break;
+	}
+*/
+
+schedule:
+	schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval));
+}
+
+static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d)
+{
+	int i, err, rc_interval;
+	struct input_dev *input_dev;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		return -ENOMEM;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY);
+	input_dev->name = "IR-receiver inside an USB DVB receiver";
+	input_dev->phys = d->rc_phys;
+	usb_to_input_id(d->udev, &input_dev->id);
+	input_dev->dev.parent = &d->udev->dev;
+	d->input_dev = input_dev;
+	d->rc_dev = NULL;
+
+	input_dev->getkeycode = legacy_dvb_usb_getkeycode;
+	input_dev->setkeycode = legacy_dvb_usb_setkeycode;
+
+	/* set the bits for the keys */
+	deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size);
+	for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
+		deb_rc("setting bit for event %d item %d\n",
+			d->props.rc.legacy.rc_map_table[i].keycode, i);
+		set_bit(d->props.rc.legacy.rc_map_table[i].keycode, input_dev->keybit);
+	}
+
+	/* setting these two values to non-zero, we have to manage key repeats */
+	input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval;
+	input_dev->rep[REP_DELAY]  = d->props.rc.legacy.rc_interval + 150;
+
+	input_set_drvdata(input_dev, d);
+
+	err = input_register_device(input_dev);
+	if (err)
+		input_free_device(input_dev);
+
+	rc_interval = d->props.rc.legacy.rc_interval;
+
+	INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control);
+
+	info("schedule remote query interval to %d msecs.", rc_interval);
+	schedule_delayed_work(&d->rc_query_work,
+			      msecs_to_jiffies(rc_interval));
+
+	d->state |= DVB_USB_STATE_REMOTE;
+
+	return err;
+}
+
+/* Remote-control poll function - called every dib->rc_query_interval ms to see
+ * whether the remote control has received anything.
+ *
+ * TODO: Fix the repeat rate of the input device.
+ */
+static void dvb_usb_read_remote_control(struct work_struct *work)
+{
+	struct dvb_usb_device *d =
+		container_of(work, struct dvb_usb_device, rc_query_work.work);
+	int err;
+
+	/* TODO: need a lock here.  We can simply skip checking for the remote control
+	   if we're busy. */
+
+	/* when the parameter has been set to 1 via sysfs while the
+	 * driver was running, or when bulk mode is enabled after IR init
+	 */
+	if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode)
+		return;
+
+	err = d->props.rc.core.rc_query(d);
+	if (err)
+		err("error %d while querying for an remote control event.", err);
+
+	schedule_delayed_work(&d->rc_query_work,
+			      msecs_to_jiffies(d->props.rc.core.rc_interval));
+}
+
+static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
+{
+	int err, rc_interval;
+	struct rc_dev *dev;
+
+	dev = rc_allocate_device();
+	if (!dev)
+		return -ENOMEM;
+
+	dev->driver_name = d->props.rc.core.module_name;
+	dev->map_name = d->props.rc.core.rc_codes;
+	dev->change_protocol = d->props.rc.core.change_protocol;
+	dev->allowed_protos = d->props.rc.core.allowed_protos;
+	dev->driver_type = d->props.rc.core.driver_type;
+	usb_to_input_id(d->udev, &dev->input_id);
+	dev->input_name = "IR-receiver inside an USB DVB receiver";
+	dev->input_phys = d->rc_phys;
+	dev->dev.parent = &d->udev->dev;
+	dev->priv = d;
+
+	err = rc_register_device(dev);
+	if (err < 0) {
+		rc_free_device(dev);
+		return err;
+	}
+
+	d->input_dev = NULL;
+	d->rc_dev = dev;
+
+	if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode)
+		return 0;
+
+	/* Polling mode - initialize a work queue for handling it */
+	INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);
+
+	rc_interval = d->props.rc.core.rc_interval;
+
+	info("schedule remote query interval to %d msecs.", rc_interval);
+	schedule_delayed_work(&d->rc_query_work,
+			      msecs_to_jiffies(rc_interval));
+
+	return 0;
+}
+
+int dvb_usb_remote_init(struct dvb_usb_device *d)
+{
+	int err;
+
+	if (dvb_usb_disable_rc_polling)
+		return 0;
+
+	if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query)
+		d->props.rc.mode = DVB_RC_LEGACY;
+	else if (d->props.rc.core.rc_codes)
+		d->props.rc.mode = DVB_RC_CORE;
+	else
+		return 0;
+
+	usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
+	strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
+
+	/* Start the remote-control polling. */
+	if (d->props.rc.legacy.rc_interval < 40)
+		d->props.rc.legacy.rc_interval = 100; /* default */
+
+	if (d->props.rc.mode == DVB_RC_LEGACY)
+		err = legacy_dvb_usb_remote_init(d);
+	else
+		err = rc_core_dvb_usb_remote_init(d);
+	if (err)
+		return err;
+
+	d->state |= DVB_USB_STATE_REMOTE;
+
+	return 0;
+}
+
+int dvb_usb_remote_exit(struct dvb_usb_device *d)
+{
+	if (d->state & DVB_USB_STATE_REMOTE) {
+		cancel_delayed_work_sync(&d->rc_query_work);
+		if (d->props.rc.mode == DVB_RC_LEGACY)
+			input_unregister_device(d->input_dev);
+		else
+			rc_unregister_device(d->rc_dev);
+	}
+	d->state &= ~DVB_USB_STATE_REMOTE;
+	return 0;
+}
+
+#define DVB_USB_RC_NEC_EMPTY           0x00
+#define DVB_USB_RC_NEC_KEY_PRESSED     0x01
+#define DVB_USB_RC_NEC_KEY_REPEATED    0x02
+int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
+		u8 keybuf[5], u32 *event, int *state)
+{
+	int i;
+	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
+	switch (keybuf[0]) {
+		case DVB_USB_RC_NEC_EMPTY:
+			break;
+		case DVB_USB_RC_NEC_KEY_PRESSED:
+			if ((u8) ~keybuf[1] != keybuf[2] ||
+				(u8) ~keybuf[3] != keybuf[4]) {
+				deb_err("remote control checksum failed.\n");
+				break;
+			}
+			/* See if we can match the raw key code. */
+			for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
+				if (rc5_custom(&keymap[i]) == keybuf[1] &&
+					rc5_data(&keymap[i]) == keybuf[3]) {
+					*event = keymap[i].keycode;
+					*state = REMOTE_KEY_PRESSED;
+					return 0;
+				}
+			deb_err("key mapping failed - no appropriate key found in keymapping\n");
+			break;
+		case DVB_USB_RC_NEC_KEY_REPEATED:
+			*state = REMOTE_KEY_REPEAT;
+			break;
+		default:
+			deb_err("unknown type of remote status: %d\n",keybuf[0]);
+			break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(dvb_usb_nec_rc_key_to_event);
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-urb.c b/drivers/media/usb/dvb-usb/dvb-usb-urb.c
new file mode 100644
index 0000000..5c8f651
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dvb-usb-urb.c
@@ -0,0 +1,121 @@
+/* dvb-usb-urb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file keeps functions for initializing and handling the
+ * USB and URB stuff.
+ */
+#include "dvb-usb-common.h"
+
+int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
+	u16 rlen, int delay_ms)
+{
+	int actlen,ret = -ENOMEM;
+
+	if (!d || wbuf == NULL || wlen == 0)
+		return -EINVAL;
+
+	if (d->props.generic_bulk_ctrl_endpoint == 0) {
+		err("endpoint for generic control not specified.");
+		return -EINVAL;
+	}
+
+	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+		return ret;
+
+	deb_xfer(">>> ");
+	debug_dump(wbuf,wlen,deb_xfer);
+
+	ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev,
+			d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen,
+			2000);
+
+	if (ret)
+		err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
+	else
+		ret = actlen != wlen ? -1 : 0;
+
+	/* an answer is expected, and no error before */
+	if (!ret && rbuf && rlen) {
+		if (delay_ms)
+			msleep(delay_ms);
+
+		ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev,
+				d->props.generic_bulk_ctrl_endpoint_response ?
+				d->props.generic_bulk_ctrl_endpoint_response :
+				d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen,
+				2000);
+
+		if (ret)
+			err("recv bulk message failed: %d",ret);
+		else {
+			deb_xfer("<<< ");
+			debug_dump(rbuf,actlen,deb_xfer);
+		}
+	}
+
+	mutex_unlock(&d->usb_mutex);
+	return ret;
+}
+EXPORT_SYMBOL(dvb_usb_generic_rw);
+
+int dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len)
+{
+	return dvb_usb_generic_rw(d,buf,len,NULL,0,0);
+}
+EXPORT_SYMBOL(dvb_usb_generic_write);
+
+static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, size_t length)
+{
+	struct dvb_usb_adapter *adap = stream->user_priv;
+	if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
+		dvb_dmx_swfilter(&adap->demux, buffer, length);
+}
+
+static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer, size_t length)
+{
+	struct dvb_usb_adapter *adap = stream->user_priv;
+	if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
+		dvb_dmx_swfilter_204(&adap->demux, buffer, length);
+}
+
+static void dvb_usb_data_complete_raw(struct usb_data_stream *stream,
+				      u8 *buffer, size_t length)
+{
+	struct dvb_usb_adapter *adap = stream->user_priv;
+	if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
+		dvb_dmx_swfilter_raw(&adap->demux, buffer, length);
+}
+
+int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap)
+{
+	int i, ret = 0;
+	for (i = 0; i < adap->props.num_frontends; i++) {
+
+		adap->fe_adap[i].stream.udev      = adap->dev->udev;
+		if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS)
+			adap->fe_adap[i].stream.complete =
+				dvb_usb_data_complete_204;
+		else
+		if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD)
+			adap->fe_adap[i].stream.complete =
+				dvb_usb_data_complete_raw;
+		else
+		adap->fe_adap[i].stream.complete  = dvb_usb_data_complete;
+		adap->fe_adap[i].stream.user_priv = adap;
+		ret = usb_urb_init(&adap->fe_adap[i].stream,
+				   &adap->props.fe[i].stream);
+		if (ret < 0)
+			break;
+	}
+	return ret;
+}
+
+int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap)
+{
+	int i;
+	for (i = 0; i < adap->props.num_frontends; i++)
+		usb_urb_exit(&adap->fe_adap[i].stream);
+	return 0;
+}
diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h
new file mode 100644
index 0000000..aab0f99
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dvb-usb.h
@@ -0,0 +1,483 @@
+/* dvb-usb.h is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * the headerfile, all dvb-usb-drivers have to include.
+ *
+ * TODO: clean-up the structures for unused fields and update the comments
+ */
+#ifndef __DVB_USB_H__
+#define __DVB_USB_H__
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/firmware.h>
+#include <linux/mutex.h>
+#include <media/rc-core.h>
+
+#include "dvb_frontend.h"
+#include "dvb_demux.h"
+#include "dvb_net.h"
+#include "dmxdev.h"
+
+#include "dvb-pll.h"
+
+#include "dvb-usb-ids.h"
+
+/* debug */
+#ifdef CONFIG_DVB_USB_DEBUG
+#define dprintk(var,level,args...) \
+	    do { if ((var & level)) { printk(args); } } while (0)
+
+#define debug_dump(b,l,func) {\
+	int loop_; \
+	for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \
+	func("\n");\
+}
+#define DVB_USB_DEBUG_STATUS
+#else
+#define dprintk(args...)
+#define debug_dump(b,l,func)
+
+#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)"
+
+#endif
+
+/* generic log methods - taken from usb.h */
+#ifndef DVB_USB_LOG_PREFIX
+ #define DVB_USB_LOG_PREFIX "dvb-usb (please define a log prefix)"
+#endif
+
+#undef err
+#define err(format, arg...)  printk(KERN_ERR     DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+#undef info
+#define info(format, arg...) printk(KERN_INFO    DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+
+/**
+ * struct dvb_usb_device_description - name and its according USB IDs
+ * @name: real name of the box, regardless which DVB USB device class is in use
+ * @cold_ids: array of struct usb_device_id which describe the device in
+ *  pre-firmware state
+ * @warm_ids: array of struct usb_device_id which describe the device in
+ *  post-firmware state
+ *
+ * Each DVB USB device class can have one or more actual devices, this struct
+ * assigns a name to it.
+ */
+struct dvb_usb_device_description {
+	const char *name;
+
+#define DVB_USB_ID_MAX_NUM 15
+	struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM];
+	struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM];
+};
+
+static inline u8 rc5_custom(struct rc_map_table *key)
+{
+	return (key->scancode >> 8) & 0xff;
+}
+
+static inline u8 rc5_data(struct rc_map_table *key)
+{
+	return key->scancode & 0xff;
+}
+
+static inline u16 rc5_scan(struct rc_map_table *key)
+{
+	return key->scancode & 0xffff;
+}
+
+struct dvb_usb_device;
+struct dvb_usb_adapter;
+struct usb_data_stream;
+
+/**
+ * Properties of USB streaming - TODO this structure should be somewhere else
+ * describes the kind of USB transfer used for data-streaming.
+ *  (BULK or ISOC)
+ */
+struct usb_data_stream_properties {
+#define USB_BULK  1
+#define USB_ISOC  2
+	int type;
+	int count;
+	int endpoint;
+
+	union {
+		struct {
+			int buffersize; /* per URB */
+		} bulk;
+		struct {
+			int framesperurb;
+			int framesize;
+			int interval;
+		} isoc;
+	} u;
+};
+
+/**
+ * struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter.
+ *    A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device.
+ * @caps: capabilities of the DVB USB device.
+ * @pid_filter_count: number of PID filter position in the optional hardware
+ *  PID-filter.
+ * @num_frontends: number of frontends of the DVB USB adapter.
+ * @frontend_ctrl: called to power on/off active frontend.
+ * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the
+ *  device (not URB submitting/killing).
+ * @pid_filter_ctrl: called to en/disable the PID filter, if any.
+ * @pid_filter: called to set/unset a PID for filtering.
+ * @frontend_attach: called to attach the possible frontends (fill fe-field
+ *  of struct dvb_usb_device).
+ * @tuner_attach: called to attach the correct tuner and to fill pll_addr,
+ *  pll_desc and pll_init_buf of struct dvb_usb_device).
+ * @stream: configuration of the USB streaming
+ */
+struct dvb_usb_adapter_fe_properties {
+#define DVB_USB_ADAP_HAS_PID_FILTER               0x01
+#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02
+#define DVB_USB_ADAP_NEED_PID_FILTERING           0x04
+#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS         0x08
+#define DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD         0x10
+	int caps;
+	int pid_filter_count;
+
+	int (*streaming_ctrl)  (struct dvb_usb_adapter *, int);
+	int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int);
+	int (*pid_filter)      (struct dvb_usb_adapter *, int, u16, int);
+
+	int (*frontend_attach) (struct dvb_usb_adapter *);
+	int (*tuner_attach)    (struct dvb_usb_adapter *);
+
+	struct usb_data_stream_properties stream;
+
+	int size_of_priv;
+};
+
+#define MAX_NO_OF_FE_PER_ADAP 3
+struct dvb_usb_adapter_properties {
+	int size_of_priv;
+
+	int (*frontend_ctrl)   (struct dvb_frontend *, int);
+
+	int num_frontends;
+	struct dvb_usb_adapter_fe_properties fe[MAX_NO_OF_FE_PER_ADAP];
+};
+
+/**
+ * struct dvb_rc_legacy - old properties of remote controller
+ * @rc_map_table: a hard-wired array of struct rc_map_table (NULL to disable
+ *  remote control handling).
+ * @rc_map_size: number of items in @rc_map_table.
+ * @rc_query: called to query an event event.
+ * @rc_interval: time in ms between two queries.
+ */
+struct dvb_rc_legacy {
+/* remote control properties */
+#define REMOTE_NO_KEY_PRESSED      0x00
+#define REMOTE_KEY_PRESSED         0x01
+#define REMOTE_KEY_REPEAT          0x02
+	struct rc_map_table  *rc_map_table;
+	int rc_map_size;
+	int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
+	int rc_interval;
+};
+
+/**
+ * struct dvb_rc properties of remote controller, using rc-core
+ * @rc_codes: name of rc codes table
+ * @protocol: type of protocol(s) currently used by the driver
+ * @allowed_protos: protocol(s) supported by the driver
+ * @driver_type: Used to point if a device supports raw mode
+ * @change_protocol: callback to change protocol
+ * @rc_query: called to query an event event.
+ * @rc_interval: time in ms between two queries.
+ * @bulk_mode: device supports bulk mode for RC (disable polling mode)
+ */
+struct dvb_rc {
+	char *rc_codes;
+	u64 protocol;
+	u64 allowed_protos;
+	enum rc_driver_type driver_type;
+	int (*change_protocol)(struct rc_dev *dev, u64 rc_type);
+	char *module_name;
+	int (*rc_query) (struct dvb_usb_device *d);
+	int rc_interval;
+	bool bulk_mode;				/* uses bulk mode */
+};
+
+/**
+ * enum dvb_usb_mode - Specifies if it is using a legacy driver or a new one
+ *		       based on rc-core
+ * This is initialized/used only inside dvb-usb-remote.c.
+ * It shouldn't be set by the drivers.
+ */
+enum dvb_usb_mode {
+	DVB_RC_LEGACY,
+	DVB_RC_CORE,
+};
+
+/**
+ * struct dvb_usb_device_properties - properties of a dvb-usb-device
+ * @usb_ctrl: which USB device-side controller is in use. Needed for firmware
+ *  download.
+ * @firmware: name of the firmware file.
+ * @download_firmware: called to download the firmware when the usb_ctrl is
+ *  DEVICE_SPECIFIC.
+ * @no_reconnect: device doesn't do a reconnect after downloading the firmware,
+ *  so do the warm initialization right after it
+ *
+ * @size_of_priv: how many bytes shall be allocated for the private field
+ *  of struct dvb_usb_device.
+ *
+ * @power_ctrl: called to enable/disable power of the device.
+ * @read_mac_address: called to read the MAC address of the device.
+ * @identify_state: called to determine the state (cold or warm), when it
+ *  is not distinguishable by the USB IDs.
+ *
+ * @rc: remote controller properties
+ *
+ * @i2c_algo: i2c_algorithm if the device has I2CoverUSB.
+ *
+ * @generic_bulk_ctrl_endpoint: most of the DVB USB devices have a generic
+ *  endpoint which received control messages with bulk transfers. When this
+ *  is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write-
+ *  helper functions.
+ *
+ * @generic_bulk_ctrl_endpoint_response: some DVB USB devices use a separate
+ *  endpoint for responses to control messages sent with bulk transfers via
+ *  the generic_bulk_ctrl_endpoint. When this is non-zero, this will be used
+ *  instead of the generic_bulk_ctrl_endpoint when reading usb responses in
+ *  the dvb_usb_generic_rw helper function.
+ *
+ * @num_device_descs: number of struct dvb_usb_device_description in @devices
+ * @devices: array of struct dvb_usb_device_description compatibles with these
+ *  properties.
+ */
+#define MAX_NO_OF_ADAPTER_PER_DEVICE 2
+struct dvb_usb_device_properties {
+
+#define DVB_USB_IS_AN_I2C_ADAPTER            0x01
+	int caps;
+
+#define DEVICE_SPECIFIC 0
+#define CYPRESS_AN2135  1
+#define CYPRESS_AN2235  2
+#define CYPRESS_FX2     3
+	int        usb_ctrl;
+	int        (*download_firmware) (struct usb_device *, const struct firmware *);
+	const char *firmware;
+	int        no_reconnect;
+
+	int size_of_priv;
+
+	int num_adapters;
+	struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
+
+	int (*power_ctrl)       (struct dvb_usb_device *, int);
+	int (*read_mac_address) (struct dvb_usb_device *, u8 []);
+	int (*identify_state)   (struct usb_device *, struct dvb_usb_device_properties *,
+			struct dvb_usb_device_description **, int *);
+
+	struct {
+		enum dvb_usb_mode mode;	/* Drivers shouldn't touch on it */
+		struct dvb_rc_legacy legacy;
+		struct dvb_rc core;
+	} rc;
+
+	struct i2c_algorithm *i2c_algo;
+
+	int generic_bulk_ctrl_endpoint;
+	int generic_bulk_ctrl_endpoint_response;
+
+	int num_device_descs;
+	struct dvb_usb_device_description devices[12];
+};
+
+/**
+ * struct usb_data_stream - generic object of an USB stream
+ * @buf_num: number of buffer allocated.
+ * @buf_size: size of each buffer in buf_list.
+ * @buf_list: array containing all allocate buffers for streaming.
+ * @dma_addr: list of dma_addr_t for each buffer in buf_list.
+ *
+ * @urbs_initialized: number of URBs initialized.
+ * @urbs_submitted: number of URBs submitted.
+ */
+#define MAX_NO_URBS_FOR_DATA_STREAM 10
+struct usb_data_stream {
+	struct usb_device                 *udev;
+	struct usb_data_stream_properties  props;
+
+#define USB_STATE_INIT    0x00
+#define USB_STATE_URB_BUF 0x01
+	int state;
+
+	void (*complete) (struct usb_data_stream *, u8 *, size_t);
+
+	struct urb    *urb_list[MAX_NO_URBS_FOR_DATA_STREAM];
+	int            buf_num;
+	unsigned long  buf_size;
+	u8            *buf_list[MAX_NO_URBS_FOR_DATA_STREAM];
+	dma_addr_t     dma_addr[MAX_NO_URBS_FOR_DATA_STREAM];
+
+	int urbs_initialized;
+	int urbs_submitted;
+
+	void *user_priv;
+};
+
+/**
+ * struct dvb_usb_adapter - a DVB adapter on a USB device
+ * @id: index of this adapter (starting with 0).
+ *
+ * @feedcount: number of reqested feeds (used for streaming-activation)
+ * @pid_filtering: is hardware pid_filtering used or not.
+ *
+ * @pll_addr: I2C address of the tuner for programming
+ * @pll_init: array containing the initialization buffer
+ * @pll_desc: pointer to the appropriate struct dvb_pll_desc
+ * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board
+ *
+ * @dvb_adap: device's dvb_adapter.
+ * @dmxdev: device's dmxdev.
+ * @demux: device's software demuxer.
+ * @dvb_net: device's dvb_net interfaces.
+ * @dvb_frontend: device's frontend.
+ * @max_feed_count: how many feeds can be handled simultaneously by this
+ *  device
+ *
+ * @fe_init:  rerouted frontend-init (wakeup) function.
+ * @fe_sleep: rerouted frontend-sleep function.
+ *
+ * @stream: the usb data stream.
+ */
+struct dvb_usb_fe_adapter {
+	struct dvb_frontend *fe;
+
+	int (*fe_init)  (struct dvb_frontend *);
+	int (*fe_sleep) (struct dvb_frontend *);
+
+	struct usb_data_stream stream;
+
+	int pid_filtering;
+	int max_feed_count;
+
+	void *priv;
+};
+
+struct dvb_usb_adapter {
+	struct dvb_usb_device *dev;
+	struct dvb_usb_adapter_properties props;
+
+#define DVB_USB_ADAP_STATE_INIT 0x000
+#define DVB_USB_ADAP_STATE_DVB  0x001
+	int state;
+
+	u8  id;
+
+	int feedcount;
+
+	/* dvb */
+	struct dvb_adapter   dvb_adap;
+	struct dmxdev        dmxdev;
+	struct dvb_demux     demux;
+	struct dvb_net       dvb_net;
+
+	struct dvb_usb_fe_adapter fe_adap[MAX_NO_OF_FE_PER_ADAP];
+	int active_fe;
+	int num_frontends_initialized;
+
+	void *priv;
+};
+
+/**
+ * struct dvb_usb_device - object of a DVB USB device
+ * @props: copy of the struct dvb_usb_properties this device belongs to.
+ * @desc: pointer to the device's struct dvb_usb_device_description.
+ * @state: initialization and runtime state of the device.
+ *
+ * @powered: indicated whether the device is power or not.
+ *  Powered is in/decremented for each call to modify the state.
+ * @udev: pointer to the device's struct usb_device.
+ *
+ * @usb_mutex: semaphore of USB control messages (reading needs two messages)
+ * @i2c_mutex: semaphore for i2c-transfers
+ *
+ * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
+ *
+ * @rc_dev: rc device for the remote control (rc-core mode)
+ * @input_dev: input device for the remote control (legacy mode)
+ * @rc_query_work: struct work_struct frequent rc queries
+ * @last_event: last triggered event
+ * @last_state: last state (no, pressed, repeat)
+ * @owner: owner of the dvb_adapter
+ * @priv: private data of the actual driver (allocate by dvb-usb, size defined
+ *  in size_of_priv of dvb_usb_properties).
+ */
+struct dvb_usb_device {
+	struct dvb_usb_device_properties props;
+	struct dvb_usb_device_description *desc;
+
+	struct usb_device *udev;
+
+#define DVB_USB_STATE_INIT        0x000
+#define DVB_USB_STATE_I2C         0x001
+#define DVB_USB_STATE_DVB         0x002
+#define DVB_USB_STATE_REMOTE      0x004
+	int state;
+
+	int powered;
+
+	/* locking */
+	struct mutex usb_mutex;
+
+	/* i2c */
+	struct mutex i2c_mutex;
+	struct i2c_adapter i2c_adap;
+
+	int                    num_adapters_initialized;
+	struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
+
+	/* remote control */
+	struct rc_dev *rc_dev;
+	struct input_dev *input_dev;
+	char rc_phys[64];
+	struct delayed_work rc_query_work;
+	u32 last_event;
+	int last_state;
+
+	struct module *owner;
+
+	void *priv;
+};
+
+extern int dvb_usb_device_init(struct usb_interface *,
+			       struct dvb_usb_device_properties *,
+			       struct module *, struct dvb_usb_device **,
+			       short *adapter_nums);
+extern void dvb_usb_device_exit(struct usb_interface *);
+
+/* the generic read/write method for device control */
+extern int dvb_usb_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16,int);
+extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16);
+
+/* commonly used remote control parsing */
+extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
+
+/* commonly used firmware download types and function */
+struct hexline {
+	u8 len;
+	u32 addr;
+	u8 type;
+	u8 data[255];
+	u8 chk;
+};
+extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type);
+extern int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos);
+
+
+#endif
diff --git a/drivers/media/usb/dvb-usb/dvb_usb_dvb.c b/drivers/media/usb/dvb-usb/dvb_usb_dvb.c
new file mode 100644
index 0000000..384fe8e
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dvb_usb_dvb.c
@@ -0,0 +1,403 @@
+/* dvb-usb-dvb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing and handling the
+ * linux-dvb API.
+ */
+#include "dvb_usb_common.h"
+
+static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buf,
+		size_t len)
+{
+	struct dvb_usb_adapter *adap = stream->user_priv;
+	dvb_dmx_swfilter(&adap->demux, buf, len);
+}
+
+static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buf,
+		size_t len)
+{
+	struct dvb_usb_adapter *adap = stream->user_priv;
+	dvb_dmx_swfilter_204(&adap->demux, buf, len);
+}
+
+static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, u8 *buf,
+		size_t len)
+{
+	struct dvb_usb_adapter *adap = stream->user_priv;
+	dvb_dmx_swfilter_raw(&adap->demux, buf, len);
+}
+
+int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap)
+{
+	pr_debug("%s: adap=%d\n", __func__, adap->id);
+
+	adap->stream.udev = adap_to_d(adap)->udev;
+	adap->stream.user_priv = adap;
+	adap->stream.complete = dvb_usb_data_complete;
+
+	return usb_urb_initv2(&adap->stream, &adap->props->stream);
+}
+
+int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap)
+{
+	pr_debug("%s: adap=%d\n", __func__, adap->id);
+	usb_urb_exitv2(&adap->stream);
+
+	return 0;
+}
+
+/* does the complete input transfer handling */
+static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int count)
+{
+	struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
+	struct dvb_usb_device *d = adap_to_d(adap);
+	int ret;
+	pr_debug("%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: " \
+			"%04x (%04d) at index %d '%s'\n", __func__, adap->id,
+			adap->active_fe, dvbdmxfeed->type,
+			adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid,
+			dvbdmxfeed->pid, dvbdmxfeed->index,
+			(count == 1) ? "on" : "off");
+
+	if (adap->active_fe == -1)
+		return -EINVAL;
+
+	adap->feed_count += count;
+
+	/* stop feeding if it is last pid */
+	if (adap->feed_count == 0) {
+		pr_debug("%s: stop feeding\n", __func__);
+		usb_urb_killv2(&adap->stream);
+
+		if (d->props->streaming_ctrl) {
+			ret = d->props->streaming_ctrl(adap, 0);
+			if (ret < 0) {
+				pr_err("%s: streaming_ctrl() failed=%d\n",
+						KBUILD_MODNAME, ret);
+				goto err_mutex_unlock;
+			}
+		}
+		mutex_unlock(&adap->sync_mutex);
+	}
+
+	/* activate the pid on the device pid filter */
+	if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+			adap->pid_filtering &&
+			adap->props->pid_filter)
+		ret = adap->props->pid_filter(adap, dvbdmxfeed->index,
+				dvbdmxfeed->pid, (count == 1) ? 1 : 0);
+			if (ret < 0)
+				pr_err("%s: pid_filter() failed=%d\n",
+						KBUILD_MODNAME, ret);
+
+	/* start feeding if it is first pid */
+	if (adap->feed_count == 1 && count == 1) {
+		struct usb_data_stream_properties stream_props;
+		mutex_lock(&adap->sync_mutex);
+		pr_debug("%s: start feeding\n", __func__);
+
+		/* resolve input and output streaming paramters */
+		if (d->props->get_stream_config) {
+			memcpy(&stream_props, &adap->props->stream,
+				sizeof(struct usb_data_stream_properties));
+			ret = d->props->get_stream_config(
+					adap->fe[adap->active_fe],
+					&adap->ts_type, &stream_props);
+			if (ret < 0)
+				goto err_mutex_unlock;
+		} else {
+			stream_props = adap->props->stream;
+		}
+
+		switch (adap->ts_type) {
+		case DVB_USB_FE_TS_TYPE_204:
+			adap->stream.complete = dvb_usb_data_complete_204;
+			break;
+		case DVB_USB_FE_TS_TYPE_RAW:
+			adap->stream.complete = dvb_usb_data_complete_raw;
+			break;
+		case DVB_USB_FE_TS_TYPE_188:
+		default:
+			adap->stream.complete = dvb_usb_data_complete;
+			break;
+		}
+
+		usb_urb_submitv2(&adap->stream, &stream_props);
+
+		if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+				adap->props->caps &
+				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
+				adap->props->pid_filter_ctrl) {
+			ret = adap->props->pid_filter_ctrl(adap,
+					adap->pid_filtering);
+			if (ret < 0) {
+				pr_err("%s: pid_filter_ctrl() failed=%d\n",
+						KBUILD_MODNAME, ret);
+				goto err_mutex_unlock;
+			}
+		}
+
+		if (d->props->streaming_ctrl) {
+			ret = d->props->streaming_ctrl(adap, 1);
+			if (ret < 0) {
+				pr_err("%s: streaming_ctrl() failed=%d\n",
+						KBUILD_MODNAME, ret);
+				goto err_mutex_unlock;
+			}
+		}
+	}
+
+	return 0;
+err_mutex_unlock:
+	mutex_unlock(&adap->sync_mutex);
+	pr_debug("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	return dvb_usb_ctrl_feed(dvbdmxfeed, 1);
+}
+
+static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	return dvb_usb_ctrl_feed(dvbdmxfeed, -1);
+}
+
+int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	struct dvb_usb_device *d = adap_to_d(adap);
+	pr_debug("%s: adap=%d\n", __func__, adap->id);
+
+	ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner,
+			&d->udev->dev, d->props->adapter_nr);
+	if (ret < 0) {
+		pr_debug("%s: dvb_register_adapter() failed=%d\n", __func__,
+				ret);
+		goto err;
+	}
+
+	adap->dvb_adap.priv = adap;
+
+	if (d->props->read_mac_address) {
+		ret = d->props->read_mac_address(adap,
+				adap->dvb_adap.proposed_mac);
+		if (ret < 0)
+			goto err_dmx;
+
+		pr_info("%s: MAC address: %pM\n", KBUILD_MODNAME,
+				adap->dvb_adap.proposed_mac);
+	}
+
+	adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+	adap->demux.priv             = adap;
+	adap->demux.filternum        = 0;
+	if (adap->demux.filternum < adap->max_feed_count)
+		adap->demux.filternum = adap->max_feed_count;
+	adap->demux.feednum          = adap->demux.filternum;
+	adap->demux.start_feed       = dvb_usb_start_feed;
+	adap->demux.stop_feed        = dvb_usb_stop_feed;
+	adap->demux.write_to_decoder = NULL;
+	ret = dvb_dmx_init(&adap->demux);
+	if (ret < 0) {
+		pr_err("%s: dvb_dmx_init() failed=%d\n", KBUILD_MODNAME, ret);
+		goto err_dmx;
+	}
+
+	adap->dmxdev.filternum       = adap->demux.filternum;
+	adap->dmxdev.demux           = &adap->demux.dmx;
+	adap->dmxdev.capabilities    = 0;
+	ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap);
+	if (ret < 0) {
+		pr_err("%s: dvb_dmxdev_init() failed=%d\n", KBUILD_MODNAME,
+				ret);
+		goto err_dmx_dev;
+	}
+
+	ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx);
+	if (ret < 0) {
+		pr_err("%s: dvb_net_init() failed=%d\n", KBUILD_MODNAME, ret);
+		goto err_net_init;
+	}
+
+	mutex_init(&adap->sync_mutex);
+
+	return 0;
+err_net_init:
+	dvb_dmxdev_release(&adap->dmxdev);
+err_dmx_dev:
+	dvb_dmx_release(&adap->demux);
+err_dmx:
+	dvb_unregister_adapter(&adap->dvb_adap);
+err:
+	adap->dvb_adap.priv = NULL;
+	return ret;
+}
+
+int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap)
+{
+	pr_debug("%s: adap=%d\n", __func__, adap->id);
+
+	if (adap->dvb_adap.priv) {
+		dvb_net_release(&adap->dvb_net);
+		adap->demux.dmx.close(&adap->demux.dmx);
+		dvb_dmxdev_release(&adap->dmxdev);
+		dvb_dmx_release(&adap->demux);
+		dvb_unregister_adapter(&adap->dvb_adap);
+	}
+
+	return 0;
+}
+
+static int dvb_usb_fe_wakeup(struct dvb_frontend *fe)
+{
+	int ret;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dvb_usb_device *d = adap_to_d(adap);
+	mutex_lock(&adap->sync_mutex);
+	pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id);
+
+	ret = dvb_usbv2_device_power_ctrl(d, 1);
+	if (ret < 0)
+		goto err;
+
+	if (d->props->frontend_ctrl) {
+		ret = d->props->frontend_ctrl(fe, 1);
+		if (ret < 0)
+			goto err;
+	}
+
+	if (adap->fe_init[fe->id]) {
+		ret = adap->fe_init[fe->id](fe);
+		if (ret < 0)
+			goto err;
+	}
+
+	adap->active_fe = fe->id;
+	mutex_unlock(&adap->sync_mutex);
+
+	return 0;
+err:
+	mutex_unlock(&adap->sync_mutex);
+	pr_debug("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
+{
+	int ret;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dvb_usb_device *d = adap_to_d(adap);
+	mutex_lock(&adap->sync_mutex);
+	pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id);
+
+	if (adap->fe_sleep[fe->id]) {
+		ret = adap->fe_sleep[fe->id](fe);
+		if (ret < 0)
+			goto err;
+	}
+
+	if (d->props->frontend_ctrl) {
+		ret = d->props->frontend_ctrl(fe, 0);
+		if (ret < 0)
+			goto err;
+	}
+
+	ret = dvb_usbv2_device_power_ctrl(d, 0);
+	if (ret < 0)
+		goto err;
+
+	adap->active_fe = -1;
+	mutex_unlock(&adap->sync_mutex);
+
+	return 0;
+err:
+	mutex_unlock(&adap->sync_mutex);
+	pr_debug("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap)
+{
+	int ret, i, count_registered = 0;
+	struct dvb_usb_device *d = adap_to_d(adap);
+	pr_debug("%s: adap=%d\n", __func__, adap->id);
+
+	memset(adap->fe, 0, sizeof(adap->fe));
+	adap->active_fe = -1;
+
+	if (d->props->frontend_attach) {
+		ret = d->props->frontend_attach(adap);
+		if (ret < 0) {
+			pr_debug("%s: frontend_attach() failed=%d\n", __func__,
+					ret);
+			goto err_dvb_frontend_detach;
+		}
+	} else {
+		pr_debug("%s: frontend_attach() do not exists\n", __func__);
+		ret = 0;
+		goto err;
+	}
+
+	for (i = 0; i < MAX_NO_OF_FE_PER_ADAP && adap->fe[i]; i++) {
+		adap->fe[i]->id = i;
+
+		/* re-assign sleep and wakeup functions */
+		adap->fe_init[i] = adap->fe[i]->ops.init;
+		adap->fe[i]->ops.init  = dvb_usb_fe_wakeup;
+		adap->fe_sleep[i] = adap->fe[i]->ops.sleep;
+		adap->fe[i]->ops.sleep = dvb_usb_fe_sleep;
+
+		ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]);
+		if (ret < 0) {
+			pr_err("%s: frontend%d registration failed\n",
+					KBUILD_MODNAME, i);
+			goto err_dvb_unregister_frontend;
+		}
+
+		count_registered++;
+	}
+
+	if (d->props->tuner_attach) {
+		ret = d->props->tuner_attach(adap);
+		if (ret < 0) {
+			pr_debug("%s: tuner_attach() failed=%d\n", __func__,
+					ret);
+			goto err_dvb_unregister_frontend;
+		}
+	}
+
+	return 0;
+
+err_dvb_unregister_frontend:
+	for (i = count_registered - 1; i >= 0; i--)
+		dvb_unregister_frontend(adap->fe[i]);
+
+err_dvb_frontend_detach:
+	for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) {
+		if (adap->fe[i])
+			dvb_frontend_detach(adap->fe[i]);
+	}
+
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap)
+{
+	int i;
+	pr_debug("%s: adap=%d\n", __func__, adap->id);
+
+	for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) {
+		if (adap->fe[i]) {
+			dvb_unregister_frontend(adap->fe[i]);
+			dvb_frontend_detach(adap->fe[i]);
+		}
+	}
+
+	return 0;
+}
diff --git a/drivers/media/usb/dvb-usb/dvb_usb_remote.c b/drivers/media/usb/dvb-usb/dvb_usb_remote.c
new file mode 100644
index 0000000..f856ab6
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dvb_usb_remote.c
@@ -0,0 +1,117 @@
+/* dvb-usb-remote.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing the input-device and for
+ * handling remote-control-queries.
+ */
+#include "dvb_usb_common.h"
+#include <linux/usb/input.h>
+
+/* Remote-control poll function - called every dib->rc_query_interval ms to see
+ * whether the remote control has received anything.
+ *
+ * TODO: Fix the repeat rate of the input device.
+ */
+static void dvb_usb_read_remote_control(struct work_struct *work)
+{
+	struct dvb_usb_device *d = container_of(work,
+			struct dvb_usb_device, rc_query_work.work);
+	int ret;
+
+	/* TODO: need a lock here.  We can simply skip checking for the remote
+	   control if we're busy. */
+
+	/* when the parameter has been set to 1 via sysfs while the
+	 * driver was running, or when bulk mode is enabled after IR init
+	 */
+	if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode)
+		return;
+
+	ret = d->rc.query(d);
+	if (ret < 0)
+		pr_err("%s: error %d while querying for an remote control " \
+				"event\n", KBUILD_MODNAME, ret);
+
+	schedule_delayed_work(&d->rc_query_work,
+			      msecs_to_jiffies(d->rc.interval));
+}
+
+int dvb_usbv2_remote_init(struct dvb_usb_device *d)
+{
+	int ret;
+	struct rc_dev *dev;
+
+	if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config)
+		return 0;
+
+	ret = d->props->get_rc_config(d, &d->rc);
+	if (ret < 0)
+		goto err;
+
+	dev = rc_allocate_device();
+	if (!dev) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	dev->dev.parent = &d->udev->dev;
+	dev->input_name = "IR-receiver inside an USB DVB receiver";
+	usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
+	strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
+	dev->input_phys = d->rc_phys;
+	usb_to_input_id(d->udev, &dev->input_id);
+	/* TODO: likely RC-core should took const char * */
+	dev->driver_name = (char *) d->props->driver_name;
+	dev->driver_type = d->rc.driver_type;
+	dev->allowed_protos = d->rc.allowed_protos;
+	dev->change_protocol = d->rc.change_protocol;
+	dev->priv = d;
+	/* select used keymap */
+	if (d->rc.map_name)
+		dev->map_name = d->rc.map_name;
+	else if (d->rc_map)
+		dev->map_name = d->rc_map;
+	else
+		dev->map_name = RC_MAP_EMPTY; /* keep rc enabled */
+
+	ret = rc_register_device(dev);
+	if (ret < 0) {
+		rc_free_device(dev);
+		goto err;
+	}
+
+	d->input_dev = NULL;
+	d->rc_dev = dev;
+
+	/* start polling if needed */
+	if (d->rc.query && !d->rc.bulk_mode) {
+		/* initialize a work queue for handling polling */
+		INIT_DELAYED_WORK(&d->rc_query_work,
+				dvb_usb_read_remote_control);
+		pr_info("%s: schedule remote query interval to %d msecs\n",
+				KBUILD_MODNAME, d->rc.interval);
+		schedule_delayed_work(&d->rc_query_work,
+				msecs_to_jiffies(d->rc.interval));
+	}
+
+	d->state |= DVB_USB_STATE_REMOTE;
+
+	return 0;
+err:
+	pr_debug("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+int dvb_usbv2_remote_exit(struct dvb_usb_device *d)
+{
+	if (d->state & DVB_USB_STATE_REMOTE) {
+		cancel_delayed_work_sync(&d->rc_query_work);
+		rc_unregister_device(d->rc_dev);
+	}
+
+	d->state &= ~DVB_USB_STATE_REMOTE;
+
+	return 0;
+}
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c
new file mode 100644
index 0000000..9382895
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dw2102.c
@@ -0,0 +1,1951 @@
+/* DVB USB framework compliant Linux driver for the
+ *	DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
+ *	TeVii S600, S630, S650, S660, S480,
+ *	Prof 1100, 7500,
+ *	Geniatech SU3000 Cards
+ * Copyright (C) 2008-2011 Igor M. Liplianin (liplianin@me.by)
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dw2102.h"
+#include "si21xx.h"
+#include "stv0299.h"
+#include "z0194a.h"
+#include "stv0288.h"
+#include "stb6000.h"
+#include "eds1547.h"
+#include "cx24116.h"
+#include "tda1002x.h"
+#include "mt312.h"
+#include "zl10039.h"
+#include "ds3000.h"
+#include "stv0900.h"
+#include "stv6110.h"
+#include "stb6100.h"
+#include "stb6100_proc.h"
+
+#ifndef USB_PID_DW2102
+#define USB_PID_DW2102 0x2102
+#endif
+
+#ifndef USB_PID_DW2104
+#define USB_PID_DW2104 0x2104
+#endif
+
+#ifndef USB_PID_DW3101
+#define USB_PID_DW3101 0x3101
+#endif
+
+#ifndef USB_PID_CINERGY_S
+#define USB_PID_CINERGY_S 0x0064
+#endif
+
+#ifndef USB_PID_TEVII_S630
+#define USB_PID_TEVII_S630 0xd630
+#endif
+
+#ifndef USB_PID_TEVII_S650
+#define USB_PID_TEVII_S650 0xd650
+#endif
+
+#ifndef USB_PID_TEVII_S660
+#define USB_PID_TEVII_S660 0xd660
+#endif
+
+#ifndef USB_PID_TEVII_S480_1
+#define USB_PID_TEVII_S480_1 0xd481
+#endif
+
+#ifndef USB_PID_TEVII_S480_2
+#define USB_PID_TEVII_S480_2 0xd482
+#endif
+
+#ifndef USB_PID_PROF_1100
+#define USB_PID_PROF_1100 0xb012
+#endif
+
+#define DW210X_READ_MSG 0
+#define DW210X_WRITE_MSG 1
+
+#define REG_1F_SYMBOLRATE_BYTE0 0x1f
+#define REG_20_SYMBOLRATE_BYTE1 0x20
+#define REG_21_SYMBOLRATE_BYTE2 0x21
+/* on my own*/
+#define DW2102_VOLTAGE_CTRL (0x1800)
+#define SU3000_STREAM_CTRL (0x1900)
+#define DW2102_RC_QUERY (0x1a00)
+#define DW2102_LED_CTRL (0x1b00)
+
+#define	err_str "did not find the firmware file. (%s) " \
+		"Please see linux/Documentation/dvb/ for more details " \
+		"on firmware-problems."
+
+struct rc_map_dvb_usb_table_table {
+	struct rc_map_table *rc_keys;
+	int rc_keys_size;
+};
+
+struct su3000_state {
+	u8 initialized;
+};
+
+struct s6x0_state {
+	int (*old_set_voltage)(struct dvb_frontend *f, fe_sec_voltage_t v);
+};
+
+/* debug */
+static int dvb_usb_dw2102_debug;
+module_param_named(debug, dvb_usb_dw2102_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))."
+						DVB_USB_DEBUG_STATUS);
+
+/* keymaps */
+static int ir_keymap;
+module_param_named(keymap, ir_keymap, int, 0644);
+MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs  ..."
+			" 256=none");
+
+/* demod probe */
+static int demod_probe = 1;
+module_param_named(demod, demod_probe, int, 0644);
+MODULE_PARM_DESC(demod, "demod to probe (1=cx24116 2=stv0903+stv6110 "
+			"4=stv0903+stb6100(or-able)).");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
+			u16 index, u8 * data, u16 len, int flags)
+{
+	int ret;
+	u8 *u8buf;
+	unsigned int pipe = (flags == DW210X_READ_MSG) ?
+				usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
+	u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
+
+	u8buf = kmalloc(len, GFP_KERNEL);
+	if (!u8buf)
+		return -ENOMEM;
+
+
+	if (flags == DW210X_WRITE_MSG)
+		memcpy(u8buf, data, len);
+	ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
+				value, index , u8buf, len, 2000);
+
+	if (flags == DW210X_READ_MSG)
+		memcpy(data, u8buf, len);
+
+	kfree(u8buf);
+	return ret;
+}
+
+/* I2C */
+static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+		int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int i = 0;
+	u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0};
+	u16 value;
+
+	if (!d)
+		return -ENODEV;
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	switch (num) {
+	case 2:
+		/* read stv0299 register */
+		value = msg[0].buf[0];/* register */
+		for (i = 0; i < msg[1].len; i++) {
+			dw210x_op_rw(d->udev, 0xb5, value + i, 0,
+					buf6, 2, DW210X_READ_MSG);
+			msg[1].buf[i] = buf6[0];
+		}
+		break;
+	case 1:
+		switch (msg[0].addr) {
+		case 0x68:
+			/* write to stv0299 register */
+			buf6[0] = 0x2a;
+			buf6[1] = msg[0].buf[0];
+			buf6[2] = msg[0].buf[1];
+			dw210x_op_rw(d->udev, 0xb2, 0, 0,
+					buf6, 3, DW210X_WRITE_MSG);
+			break;
+		case 0x60:
+			if (msg[0].flags == 0) {
+			/* write to tuner pll */
+				buf6[0] = 0x2c;
+				buf6[1] = 5;
+				buf6[2] = 0xc0;
+				buf6[3] = msg[0].buf[0];
+				buf6[4] = msg[0].buf[1];
+				buf6[5] = msg[0].buf[2];
+				buf6[6] = msg[0].buf[3];
+				dw210x_op_rw(d->udev, 0xb2, 0, 0,
+						buf6, 7, DW210X_WRITE_MSG);
+			} else {
+			/* read from tuner */
+				dw210x_op_rw(d->udev, 0xb5, 0, 0,
+						buf6, 1, DW210X_READ_MSG);
+				msg[0].buf[0] = buf6[0];
+			}
+			break;
+		case (DW2102_RC_QUERY):
+			dw210x_op_rw(d->udev, 0xb8, 0, 0,
+					buf6, 2, DW210X_READ_MSG);
+			msg[0].buf[0] = buf6[0];
+			msg[0].buf[1] = buf6[1];
+			break;
+		case (DW2102_VOLTAGE_CTRL):
+			buf6[0] = 0x30;
+			buf6[1] = msg[0].buf[0];
+			dw210x_op_rw(d->udev, 0xb2, 0, 0,
+					buf6, 2, DW210X_WRITE_MSG);
+			break;
+		}
+
+		break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return num;
+}
+
+static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
+						struct i2c_msg msg[], int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	u8 buf6[] = {0, 0, 0, 0, 0, 0, 0};
+
+	if (!d)
+		return -ENODEV;
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	switch (num) {
+	case 2:
+		/* read si2109 register by number */
+		buf6[0] = msg[0].addr << 1;
+		buf6[1] = msg[0].len;
+		buf6[2] = msg[0].buf[0];
+		dw210x_op_rw(d->udev, 0xc2, 0, 0,
+				buf6, msg[0].len + 2, DW210X_WRITE_MSG);
+		/* read si2109 register */
+		dw210x_op_rw(d->udev, 0xc3, 0xd0, 0,
+				buf6, msg[1].len + 2, DW210X_READ_MSG);
+		memcpy(msg[1].buf, buf6 + 2, msg[1].len);
+
+		break;
+	case 1:
+		switch (msg[0].addr) {
+		case 0x68:
+			/* write to si2109 register */
+			buf6[0] = msg[0].addr << 1;
+			buf6[1] = msg[0].len;
+			memcpy(buf6 + 2, msg[0].buf, msg[0].len);
+			dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6,
+					msg[0].len + 2, DW210X_WRITE_MSG);
+			break;
+		case(DW2102_RC_QUERY):
+			dw210x_op_rw(d->udev, 0xb8, 0, 0,
+					buf6, 2, DW210X_READ_MSG);
+			msg[0].buf[0] = buf6[0];
+			msg[0].buf[1] = buf6[1];
+			break;
+		case(DW2102_VOLTAGE_CTRL):
+			buf6[0] = 0x30;
+			buf6[1] = msg[0].buf[0];
+			dw210x_op_rw(d->udev, 0xb2, 0, 0,
+					buf6, 2, DW210X_WRITE_MSG);
+			break;
+		}
+		break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return num;
+}
+
+static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+
+	if (!d)
+		return -ENODEV;
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	switch (num) {
+	case 2: {
+		/* read */
+		/* first write first register number */
+		u8 ibuf[msg[1].len + 2], obuf[3];
+		obuf[0] = msg[0].addr << 1;
+		obuf[1] = msg[0].len;
+		obuf[2] = msg[0].buf[0];
+		dw210x_op_rw(d->udev, 0xc2, 0, 0,
+				obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+		/* second read registers */
+		dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0,
+				ibuf, msg[1].len + 2, DW210X_READ_MSG);
+		memcpy(msg[1].buf, ibuf + 2, msg[1].len);
+
+		break;
+	}
+	case 1:
+		switch (msg[0].addr) {
+		case 0x68: {
+			/* write to register */
+			u8 obuf[msg[0].len + 2];
+			obuf[0] = msg[0].addr << 1;
+			obuf[1] = msg[0].len;
+			memcpy(obuf + 2, msg[0].buf, msg[0].len);
+			dw210x_op_rw(d->udev, 0xc2, 0, 0,
+					obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+			break;
+		}
+		case 0x61: {
+			/* write to tuner */
+			u8 obuf[msg[0].len + 2];
+			obuf[0] = msg[0].addr << 1;
+			obuf[1] = msg[0].len;
+			memcpy(obuf + 2, msg[0].buf, msg[0].len);
+			dw210x_op_rw(d->udev, 0xc2, 0, 0,
+					obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+			break;
+		}
+		case(DW2102_RC_QUERY): {
+			u8 ibuf[2];
+			dw210x_op_rw(d->udev, 0xb8, 0, 0,
+					ibuf, 2, DW210X_READ_MSG);
+			memcpy(msg[0].buf, ibuf , 2);
+			break;
+		}
+		case(DW2102_VOLTAGE_CTRL): {
+			u8 obuf[2];
+			obuf[0] = 0x30;
+			obuf[1] = msg[0].buf[0];
+			dw210x_op_rw(d->udev, 0xb2, 0, 0,
+					obuf, 2, DW210X_WRITE_MSG);
+			break;
+		}
+		}
+
+		break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return num;
+}
+
+static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int len, i, j;
+
+	if (!d)
+		return -ENODEV;
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (j = 0; j < num; j++) {
+		switch (msg[j].addr) {
+		case(DW2102_RC_QUERY): {
+			u8 ibuf[2];
+			dw210x_op_rw(d->udev, 0xb8, 0, 0,
+					ibuf, 2, DW210X_READ_MSG);
+			memcpy(msg[j].buf, ibuf , 2);
+			break;
+		}
+		case(DW2102_VOLTAGE_CTRL): {
+			u8 obuf[2];
+			obuf[0] = 0x30;
+			obuf[1] = msg[j].buf[0];
+			dw210x_op_rw(d->udev, 0xb2, 0, 0,
+					obuf, 2, DW210X_WRITE_MSG);
+			break;
+		}
+		/*case 0x55: cx24116
+		case 0x6a: stv0903
+		case 0x68: ds3000, stv0903
+		case 0x60: ts2020, stv6110, stb6100 */
+		default: {
+			if (msg[j].flags == I2C_M_RD) {
+				/* read registers */
+				u8  ibuf[msg[j].len + 2];
+				dw210x_op_rw(d->udev, 0xc3,
+						(msg[j].addr << 1) + 1, 0,
+						ibuf, msg[j].len + 2,
+						DW210X_READ_MSG);
+				memcpy(msg[j].buf, ibuf + 2, msg[j].len);
+			mdelay(10);
+			} else if (((msg[j].buf[0] == 0xb0) &&
+						(msg[j].addr == 0x68)) ||
+						((msg[j].buf[0] == 0xf7) &&
+						(msg[j].addr == 0x55))) {
+				/* write firmware */
+				u8 obuf[19];
+				obuf[0] = msg[j].addr << 1;
+				obuf[1] = (msg[j].len > 15 ? 17 : msg[j].len);
+				obuf[2] = msg[j].buf[0];
+				len = msg[j].len - 1;
+				i = 1;
+				do {
+					memcpy(obuf + 3, msg[j].buf + i,
+							(len > 16 ? 16 : len));
+					dw210x_op_rw(d->udev, 0xc2, 0, 0,
+						obuf, (len > 16 ? 16 : len) + 3,
+						DW210X_WRITE_MSG);
+					i += 16;
+					len -= 16;
+				} while (len > 0);
+			} else {
+				/* write registers */
+				u8 obuf[msg[j].len + 2];
+				obuf[0] = msg[j].addr << 1;
+				obuf[1] = msg[j].len;
+				memcpy(obuf + 2, msg[j].buf, msg[j].len);
+				dw210x_op_rw(d->udev, 0xc2, 0, 0,
+						obuf, msg[j].len + 2,
+						DW210X_WRITE_MSG);
+			}
+			break;
+		}
+		}
+
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return num;
+}
+
+static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+								int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int i;
+
+	if (!d)
+		return -ENODEV;
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	switch (num) {
+	case 2: {
+		/* read */
+		/* first write first register number */
+		u8 ibuf[msg[1].len + 2], obuf[3];
+		obuf[0] = msg[0].addr << 1;
+		obuf[1] = msg[0].len;
+		obuf[2] = msg[0].buf[0];
+		dw210x_op_rw(d->udev, 0xc2, 0, 0,
+				obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+		/* second read registers */
+		dw210x_op_rw(d->udev, 0xc3, 0x19 , 0,
+				ibuf, msg[1].len + 2, DW210X_READ_MSG);
+		memcpy(msg[1].buf, ibuf + 2, msg[1].len);
+
+		break;
+	}
+	case 1:
+		switch (msg[0].addr) {
+		case 0x60:
+		case 0x0c: {
+			/* write to register */
+			u8 obuf[msg[0].len + 2];
+			obuf[0] = msg[0].addr << 1;
+			obuf[1] = msg[0].len;
+			memcpy(obuf + 2, msg[0].buf, msg[0].len);
+			dw210x_op_rw(d->udev, 0xc2, 0, 0,
+					obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+			break;
+		}
+		case(DW2102_RC_QUERY): {
+			u8 ibuf[2];
+			dw210x_op_rw(d->udev, 0xb8, 0, 0,
+					ibuf, 2, DW210X_READ_MSG);
+			memcpy(msg[0].buf, ibuf , 2);
+			break;
+		}
+		}
+
+		break;
+	}
+
+	for (i = 0; i < num; i++) {
+		deb_xfer("%02x:%02x: %s ", i, msg[i].addr,
+				msg[i].flags == 0 ? ">>>" : "<<<");
+		debug_dump(msg[i].buf, msg[i].len, deb_xfer);
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return num;
+}
+
+static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+								int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct usb_device *udev;
+	int len, i, j;
+
+	if (!d)
+		return -ENODEV;
+	udev = d->udev;
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (j = 0; j < num; j++) {
+		switch (msg[j].addr) {
+		case (DW2102_RC_QUERY): {
+			u8 ibuf[5];
+			dw210x_op_rw(d->udev, 0xb8, 0, 0,
+					ibuf, 5, DW210X_READ_MSG);
+			memcpy(msg[j].buf, ibuf + 3, 2);
+			break;
+		}
+		case (DW2102_VOLTAGE_CTRL): {
+			u8 obuf[2];
+
+			obuf[0] = 1;
+			obuf[1] = msg[j].buf[1];/* off-on */
+			dw210x_op_rw(d->udev, 0x8a, 0, 0,
+					obuf, 2, DW210X_WRITE_MSG);
+			obuf[0] = 3;
+			obuf[1] = msg[j].buf[0];/* 13v-18v */
+			dw210x_op_rw(d->udev, 0x8a, 0, 0,
+					obuf, 2, DW210X_WRITE_MSG);
+			break;
+		}
+		case (DW2102_LED_CTRL): {
+			u8 obuf[2];
+
+			obuf[0] = 5;
+			obuf[1] = msg[j].buf[0];
+			dw210x_op_rw(d->udev, 0x8a, 0, 0,
+					obuf, 2, DW210X_WRITE_MSG);
+			break;
+		}
+		/*case 0x55: cx24116
+		case 0x6a: stv0903
+		case 0x68: ds3000, stv0903
+		case 0x60: ts2020, stv6110, stb6100
+		case 0xa0: eeprom */
+		default: {
+			if (msg[j].flags == I2C_M_RD) {
+				/* read registers */
+				u8 ibuf[msg[j].len];
+				dw210x_op_rw(d->udev, 0x91, 0, 0,
+						ibuf, msg[j].len,
+						DW210X_READ_MSG);
+				memcpy(msg[j].buf, ibuf, msg[j].len);
+				break;
+			} else if ((msg[j].buf[0] == 0xb0) &&
+						(msg[j].addr == 0x68)) {
+				/* write firmware */
+				u8 obuf[19];
+				obuf[0] = (msg[j].len > 16 ?
+						18 : msg[j].len + 1);
+				obuf[1] = msg[j].addr << 1;
+				obuf[2] = msg[j].buf[0];
+				len = msg[j].len - 1;
+				i = 1;
+				do {
+					memcpy(obuf + 3, msg[j].buf + i,
+							(len > 16 ? 16 : len));
+					dw210x_op_rw(d->udev, 0x80, 0, 0,
+						obuf, (len > 16 ? 16 : len) + 3,
+						DW210X_WRITE_MSG);
+					i += 16;
+					len -= 16;
+				} while (len > 0);
+			} else if (j < (num - 1)) {
+				/* write register addr before read */
+				u8 obuf[msg[j].len + 2];
+				obuf[0] = msg[j + 1].len;
+				obuf[1] = (msg[j].addr << 1);
+				memcpy(obuf + 2, msg[j].buf, msg[j].len);
+				dw210x_op_rw(d->udev,
+						udev->descriptor.idProduct ==
+						0x7500 ? 0x92 : 0x90, 0, 0,
+						obuf, msg[j].len + 2,
+						DW210X_WRITE_MSG);
+				break;
+			} else {
+				/* write registers */
+				u8 obuf[msg[j].len + 2];
+				obuf[0] = msg[j].len + 1;
+				obuf[1] = (msg[j].addr << 1);
+				memcpy(obuf + 2, msg[j].buf, msg[j].len);
+				dw210x_op_rw(d->udev, 0x80, 0, 0,
+						obuf, msg[j].len + 2,
+						DW210X_WRITE_MSG);
+				break;
+			}
+			break;
+		}
+		}
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return num;
+}
+
+static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+								int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	u8 obuf[0x40], ibuf[0x40];
+
+	if (!d)
+		return -ENODEV;
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	switch (num) {
+	case 1:
+		switch (msg[0].addr) {
+		case SU3000_STREAM_CTRL:
+			obuf[0] = msg[0].buf[0] + 0x36;
+			obuf[1] = 3;
+			obuf[2] = 0;
+			if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 0, 0) < 0)
+				err("i2c transfer failed.");
+			break;
+		case DW2102_RC_QUERY:
+			obuf[0] = 0x10;
+			if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 2, 0) < 0)
+				err("i2c transfer failed.");
+			msg[0].buf[1] = ibuf[0];
+			msg[0].buf[0] = ibuf[1];
+			break;
+		default:
+			/* always i2c write*/
+			obuf[0] = 0x08;
+			obuf[1] = msg[0].addr;
+			obuf[2] = msg[0].len;
+
+			memcpy(&obuf[3], msg[0].buf, msg[0].len);
+
+			if (dvb_usb_generic_rw(d, obuf, msg[0].len + 3,
+						ibuf, 1, 0) < 0)
+				err("i2c transfer failed.");
+
+		}
+		break;
+	case 2:
+		/* always i2c read */
+		obuf[0] = 0x09;
+		obuf[1] = msg[0].len;
+		obuf[2] = msg[1].len;
+		obuf[3] = msg[0].addr;
+		memcpy(&obuf[4], msg[0].buf, msg[0].len);
+
+		if (dvb_usb_generic_rw(d, obuf, msg[0].len + 4,
+					ibuf, msg[1].len + 1, 0) < 0)
+			err("i2c transfer failed.");
+
+		memcpy(msg[1].buf, &ibuf[1], msg[1].len);
+		break;
+	default:
+		warn("more than 2 i2c messages at a time is not handled yet.");
+		break;
+	}
+	mutex_unlock(&d->i2c_mutex);
+	return num;
+}
+
+static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dw2102_i2c_algo = {
+	.master_xfer = dw2102_i2c_transfer,
+	.functionality = dw210x_i2c_func,
+};
+
+static struct i2c_algorithm dw2102_serit_i2c_algo = {
+	.master_xfer = dw2102_serit_i2c_transfer,
+	.functionality = dw210x_i2c_func,
+};
+
+static struct i2c_algorithm dw2102_earda_i2c_algo = {
+	.master_xfer = dw2102_earda_i2c_transfer,
+	.functionality = dw210x_i2c_func,
+};
+
+static struct i2c_algorithm dw2104_i2c_algo = {
+	.master_xfer = dw2104_i2c_transfer,
+	.functionality = dw210x_i2c_func,
+};
+
+static struct i2c_algorithm dw3101_i2c_algo = {
+	.master_xfer = dw3101_i2c_transfer,
+	.functionality = dw210x_i2c_func,
+};
+
+static struct i2c_algorithm s6x0_i2c_algo = {
+	.master_xfer = s6x0_i2c_transfer,
+	.functionality = dw210x_i2c_func,
+};
+
+static struct i2c_algorithm su3000_i2c_algo = {
+	.master_xfer = su3000_i2c_transfer,
+	.functionality = dw210x_i2c_func,
+};
+
+static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+	int i;
+	u8 ibuf[] = {0, 0};
+	u8 eeprom[256], eepromline[16];
+
+	for (i = 0; i < 256; i++) {
+		if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) {
+			err("read eeprom failed.");
+			return -1;
+		} else {
+			eepromline[i%16] = ibuf[0];
+			eeprom[i] = ibuf[0];
+		}
+		if ((i % 16) == 15) {
+			deb_xfer("%02x: ", i - 15);
+			debug_dump(eepromline, 16, deb_xfer);
+		}
+	}
+
+	memcpy(mac, eeprom + 8, 6);
+	return 0;
+};
+
+static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+	int i, ret;
+	u8 ibuf[] = { 0 }, obuf[] = { 0 };
+	u8 eeprom[256], eepromline[16];
+	struct i2c_msg msg[] = {
+		{
+			.addr = 0xa0 >> 1,
+			.flags = 0,
+			.buf = obuf,
+			.len = 1,
+		}, {
+			.addr = 0xa0 >> 1,
+			.flags = I2C_M_RD,
+			.buf = ibuf,
+			.len = 1,
+		}
+	};
+
+	for (i = 0; i < 256; i++) {
+		obuf[0] = i;
+		ret = s6x0_i2c_transfer(&d->i2c_adap, msg, 2);
+		if (ret != 2) {
+			err("read eeprom failed.");
+			return -1;
+		} else {
+			eepromline[i % 16] = ibuf[0];
+			eeprom[i] = ibuf[0];
+		}
+
+		if ((i % 16) == 15) {
+			deb_xfer("%02x: ", i - 15);
+			debug_dump(eepromline, 16, deb_xfer);
+		}
+	}
+
+	memcpy(mac, eeprom + 16, 6);
+	return 0;
+};
+
+static int su3000_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	static u8 command_start[] = {0x00};
+	static u8 command_stop[] = {0x01};
+	struct i2c_msg msg = {
+		.addr = SU3000_STREAM_CTRL,
+		.flags = 0,
+		.buf = onoff ? command_start : command_stop,
+		.len = 1
+	};
+
+	i2c_transfer(&adap->dev->i2c_adap, &msg, 1);
+
+	return 0;
+}
+
+static int su3000_power_ctrl(struct dvb_usb_device *d, int i)
+{
+	struct su3000_state *state = (struct su3000_state *)d->priv;
+	u8 obuf[] = {0xde, 0};
+
+	info("%s: %d, initialized %d\n", __func__, i, state->initialized);
+
+	if (i && !state->initialized) {
+		state->initialized = 1;
+		/* reset board */
+		dvb_usb_generic_rw(d, obuf, 2, NULL, 0, 0);
+	}
+
+	return 0;
+}
+
+static int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+	int i;
+	u8 obuf[] = { 0x1f, 0xf0 };
+	u8 ibuf[] = { 0 };
+	struct i2c_msg msg[] = {
+		{
+			.addr = 0x51,
+			.flags = 0,
+			.buf = obuf,
+			.len = 2,
+		}, {
+			.addr = 0x51,
+			.flags = I2C_M_RD,
+			.buf = ibuf,
+			.len = 1,
+
+		}
+	};
+
+	for (i = 0; i < 6; i++) {
+		obuf[1] = 0xf0 + i;
+		if (i2c_transfer(&d->i2c_adap, msg, 2) != 2)
+			break;
+		else
+			mac[i] = ibuf[0];
+
+		debug_dump(mac, 6, printk);
+	}
+
+	return 0;
+}
+
+static int su3000_identify_state(struct usb_device *udev,
+				 struct dvb_usb_device_properties *props,
+				 struct dvb_usb_device_description **desc,
+				 int *cold)
+{
+	info("%s\n", __func__);
+
+	*cold = 0;
+	return 0;
+}
+
+static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	static u8 command_13v[] = {0x00, 0x01};
+	static u8 command_18v[] = {0x01, 0x01};
+	static u8 command_off[] = {0x00, 0x00};
+	struct i2c_msg msg = {
+		.addr = DW2102_VOLTAGE_CTRL,
+		.flags = 0,
+		.buf = command_off,
+		.len = 2,
+	};
+
+	struct dvb_usb_adapter *udev_adap =
+		(struct dvb_usb_adapter *)(fe->dvb->priv);
+	if (voltage == SEC_VOLTAGE_18)
+		msg.buf = command_18v;
+	else if (voltage == SEC_VOLTAGE_13)
+		msg.buf = command_13v;
+
+	i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1);
+
+	return 0;
+}
+
+static int s660_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct dvb_usb_adapter *d =
+		(struct dvb_usb_adapter *)(fe->dvb->priv);
+	struct s6x0_state *st = (struct s6x0_state *)d->dev->priv;
+
+	dw210x_set_voltage(fe, voltage);
+	if (st->old_set_voltage)
+		st->old_set_voltage(fe, voltage);
+
+	return 0;
+}
+
+static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon)
+{
+	static u8 led_off[] = { 0 };
+	static u8 led_on[] = { 1 };
+	struct i2c_msg msg = {
+		.addr = DW2102_LED_CTRL,
+		.flags = 0,
+		.buf = led_off,
+		.len = 1
+	};
+	struct dvb_usb_adapter *udev_adap =
+		(struct dvb_usb_adapter *)(fe->dvb->priv);
+
+	if (offon)
+		msg.buf = led_on;
+	i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1);
+}
+
+static struct stv0299_config sharp_z0194a_config = {
+	.demod_address = 0x68,
+	.inittab = sharp_z0194a_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.skip_reinit = 0,
+	.lock_output = STV0299_LOCKOUTPUT_1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = sharp_z0194a_set_symbol_rate,
+};
+
+static struct cx24116_config dw2104_config = {
+	.demod_address = 0x55,
+	.mpg_clk_pos_pol = 0x01,
+};
+
+static struct si21xx_config serit_sp1511lhb_config = {
+	.demod_address = 0x68,
+	.min_delay_ms = 100,
+
+};
+
+static struct tda10023_config dw3101_tda10023_config = {
+	.demod_address = 0x0c,
+	.invert = 1,
+};
+
+static struct mt312_config zl313_config = {
+	.demod_address = 0x0e,
+};
+
+static struct ds3000_config dw2104_ds3000_config = {
+	.demod_address = 0x68,
+};
+
+static struct stv0900_config dw2104a_stv0900_config = {
+	.demod_address = 0x6a,
+	.demod_mode = 0,
+	.xtal = 27000000,
+	.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
+	.diseqc_mode = 2,/* 2/3 PWM */
+	.tun1_maddress = 0,/* 0x60 */
+	.tun1_adc = 0,/* 2 Vpp */
+	.path1_mode = 3,
+};
+
+static struct stb6100_config dw2104a_stb6100_config = {
+	.tuner_address = 0x60,
+	.refclock = 27000000,
+};
+
+static struct stv0900_config dw2104_stv0900_config = {
+	.demod_address = 0x68,
+	.demod_mode = 0,
+	.xtal = 8000000,
+	.clkmode = 3,
+	.diseqc_mode = 2,
+	.tun1_maddress = 0,
+	.tun1_adc = 1,/* 1 Vpp */
+	.path1_mode = 3,
+};
+
+static struct stv6110_config dw2104_stv6110_config = {
+	.i2c_address = 0x60,
+	.mclk = 16000000,
+	.clk_div = 1,
+};
+
+static struct stv0900_config prof_7500_stv0900_config = {
+	.demod_address = 0x6a,
+	.demod_mode = 0,
+	.xtal = 27000000,
+	.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
+	.diseqc_mode = 2,/* 2/3 PWM */
+	.tun1_maddress = 0,/* 0x60 */
+	.tun1_adc = 0,/* 2 Vpp */
+	.path1_mode = 3,
+	.tun1_type = 3,
+	.set_lock_led = dw210x_led_ctrl,
+};
+
+static struct ds3000_config su3000_ds3000_config = {
+	.demod_address = 0x68,
+	.ci_mode = 1,
+};
+
+static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
+{
+	struct dvb_tuner_ops *tuner_ops = NULL;
+
+	if (demod_probe & 4) {
+		d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config,
+				&d->dev->i2c_adap, 0);
+		if (d->fe_adap[0].fe != NULL) {
+			if (dvb_attach(stb6100_attach, d->fe_adap[0].fe,
+					&dw2104a_stb6100_config,
+					&d->dev->i2c_adap)) {
+				tuner_ops = &d->fe_adap[0].fe->ops.tuner_ops;
+				tuner_ops->set_frequency = stb6100_set_freq;
+				tuner_ops->get_frequency = stb6100_get_freq;
+				tuner_ops->set_bandwidth = stb6100_set_bandw;
+				tuner_ops->get_bandwidth = stb6100_get_bandw;
+				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+				info("Attached STV0900+STB6100!\n");
+				return 0;
+			}
+		}
+	}
+
+	if (demod_probe & 2) {
+		d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config,
+				&d->dev->i2c_adap, 0);
+		if (d->fe_adap[0].fe != NULL) {
+			if (dvb_attach(stv6110_attach, d->fe_adap[0].fe,
+					&dw2104_stv6110_config,
+					&d->dev->i2c_adap)) {
+				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+				info("Attached STV0900+STV6110A!\n");
+				return 0;
+			}
+		}
+	}
+
+	if (demod_probe & 1) {
+		d->fe_adap[0].fe = dvb_attach(cx24116_attach, &dw2104_config,
+				&d->dev->i2c_adap);
+		if (d->fe_adap[0].fe != NULL) {
+			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+			info("Attached cx24116!\n");
+			return 0;
+		}
+	}
+
+	d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
+			&d->dev->i2c_adap);
+	if (d->fe_adap[0].fe != NULL) {
+		d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+		info("Attached DS3000!\n");
+		return 0;
+	}
+
+	return -EIO;
+}
+
+static struct dvb_usb_device_properties dw2102_properties;
+static struct dvb_usb_device_properties dw2104_properties;
+static struct dvb_usb_device_properties s6x0_properties;
+
+static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
+{
+	if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) {
+		/*dw2102_properties.adapter->tuner_attach = NULL;*/
+		d->fe_adap[0].fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config,
+					&d->dev->i2c_adap);
+		if (d->fe_adap[0].fe != NULL) {
+			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+			info("Attached si21xx!\n");
+			return 0;
+		}
+	}
+
+	if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) {
+		d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config,
+					&d->dev->i2c_adap);
+		if (d->fe_adap[0].fe != NULL) {
+			if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61,
+					&d->dev->i2c_adap)) {
+				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+				info("Attached stv0288!\n");
+				return 0;
+			}
+		}
+	}
+
+	if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) {
+		/*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
+		d->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
+					&d->dev->i2c_adap);
+		if (d->fe_adap[0].fe != NULL) {
+			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+			info("Attached stv0299!\n");
+			return 0;
+		}
+	}
+	return -EIO;
+}
+
+static int dw3101_frontend_attach(struct dvb_usb_adapter *d)
+{
+	d->fe_adap[0].fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config,
+				&d->dev->i2c_adap, 0x48);
+	if (d->fe_adap[0].fe != NULL) {
+		info("Attached tda10023!\n");
+		return 0;
+	}
+	return -EIO;
+}
+
+static int zl100313_frontend_attach(struct dvb_usb_adapter *d)
+{
+	d->fe_adap[0].fe = dvb_attach(mt312_attach, &zl313_config,
+			&d->dev->i2c_adap);
+	if (d->fe_adap[0].fe != NULL) {
+		if (dvb_attach(zl10039_attach, d->fe_adap[0].fe, 0x60,
+				&d->dev->i2c_adap)) {
+			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+			info("Attached zl100313+zl10039!\n");
+			return 0;
+		}
+	}
+
+	return -EIO;
+}
+
+static int stv0288_frontend_attach(struct dvb_usb_adapter *d)
+{
+	u8 obuf[] = {7, 1};
+
+	d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config,
+			&d->dev->i2c_adap);
+
+	if (d->fe_adap[0].fe == NULL)
+		return -EIO;
+
+	if (NULL == dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, &d->dev->i2c_adap))
+		return -EIO;
+
+	d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+
+	dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
+
+	info("Attached stv0288+stb6000!\n");
+
+	return 0;
+
+}
+
+static int ds3000_frontend_attach(struct dvb_usb_adapter *d)
+{
+	struct s6x0_state *st = (struct s6x0_state *)d->dev->priv;
+	u8 obuf[] = {7, 1};
+
+	d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
+			&d->dev->i2c_adap);
+
+	if (d->fe_adap[0].fe == NULL)
+		return -EIO;
+
+	st->old_set_voltage = d->fe_adap[0].fe->ops.set_voltage;
+	d->fe_adap[0].fe->ops.set_voltage = s660_set_voltage;
+
+	dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
+
+	info("Attached ds3000+ds2020!\n");
+
+	return 0;
+}
+
+static int prof_7500_frontend_attach(struct dvb_usb_adapter *d)
+{
+	u8 obuf[] = {7, 1};
+
+	d->fe_adap[0].fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config,
+					&d->dev->i2c_adap, 0);
+	if (d->fe_adap[0].fe == NULL)
+		return -EIO;
+
+	d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+
+	dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
+
+	info("Attached STV0900+STB6100A!\n");
+
+	return 0;
+}
+
+static int su3000_frontend_attach(struct dvb_usb_adapter *d)
+{
+	u8 obuf[3] = { 0xe, 0x80, 0 };
+	u8 ibuf[] = { 0 };
+
+	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+		err("command 0x0e transfer failed.");
+
+	obuf[0] = 0xe;
+	obuf[1] = 0x83;
+	obuf[2] = 0;
+
+	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+		err("command 0x0e transfer failed.");
+
+	obuf[0] = 0xe;
+	obuf[1] = 0x83;
+	obuf[2] = 1;
+
+	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+		err("command 0x0e transfer failed.");
+
+	obuf[0] = 0x51;
+
+	if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
+		err("command 0x51 transfer failed.");
+
+	d->fe_adap[0].fe = dvb_attach(ds3000_attach, &su3000_ds3000_config,
+					&d->dev->i2c_adap);
+	if (d->fe_adap[0].fe == NULL)
+		return -EIO;
+
+	info("Attached DS3000!\n");
+
+	return 0;
+}
+
+static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
+		&adap->dev->i2c_adap, DVB_PLL_OPERA1);
+	return 0;
+}
+
+static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
+		&adap->dev->i2c_adap, DVB_PLL_TUA6034);
+
+	return 0;
+}
+
+static struct rc_map_table rc_map_dw210x_table[] = {
+	{ 0xf80a, KEY_POWER2 },		/*power*/
+	{ 0xf80c, KEY_MUTE },		/*mute*/
+	{ 0xf811, KEY_1 },
+	{ 0xf812, KEY_2 },
+	{ 0xf813, KEY_3 },
+	{ 0xf814, KEY_4 },
+	{ 0xf815, KEY_5 },
+	{ 0xf816, KEY_6 },
+	{ 0xf817, KEY_7 },
+	{ 0xf818, KEY_8 },
+	{ 0xf819, KEY_9 },
+	{ 0xf810, KEY_0 },
+	{ 0xf81c, KEY_CHANNELUP },	/*ch+*/
+	{ 0xf80f, KEY_CHANNELDOWN },	/*ch-*/
+	{ 0xf81a, KEY_VOLUMEUP },	/*vol+*/
+	{ 0xf80e, KEY_VOLUMEDOWN },	/*vol-*/
+	{ 0xf804, KEY_RECORD },		/*rec*/
+	{ 0xf809, KEY_FAVORITES },	/*fav*/
+	{ 0xf808, KEY_REWIND },		/*rewind*/
+	{ 0xf807, KEY_FASTFORWARD },	/*fast*/
+	{ 0xf80b, KEY_PAUSE },		/*pause*/
+	{ 0xf802, KEY_ESC },		/*cancel*/
+	{ 0xf803, KEY_TAB },		/*tab*/
+	{ 0xf800, KEY_UP },		/*up*/
+	{ 0xf81f, KEY_OK },		/*ok*/
+	{ 0xf801, KEY_DOWN },		/*down*/
+	{ 0xf805, KEY_CAMERA },		/*cap*/
+	{ 0xf806, KEY_STOP },		/*stop*/
+	{ 0xf840, KEY_ZOOM },		/*full*/
+	{ 0xf81e, KEY_TV },		/*tvmode*/
+	{ 0xf81b, KEY_LAST },		/*recall*/
+};
+
+static struct rc_map_table rc_map_tevii_table[] = {
+	{ 0xf80a, KEY_POWER },
+	{ 0xf80c, KEY_MUTE },
+	{ 0xf811, KEY_1 },
+	{ 0xf812, KEY_2 },
+	{ 0xf813, KEY_3 },
+	{ 0xf814, KEY_4 },
+	{ 0xf815, KEY_5 },
+	{ 0xf816, KEY_6 },
+	{ 0xf817, KEY_7 },
+	{ 0xf818, KEY_8 },
+	{ 0xf819, KEY_9 },
+	{ 0xf810, KEY_0 },
+	{ 0xf81c, KEY_MENU },
+	{ 0xf80f, KEY_VOLUMEDOWN },
+	{ 0xf81a, KEY_LAST },
+	{ 0xf80e, KEY_OPEN },
+	{ 0xf804, KEY_RECORD },
+	{ 0xf809, KEY_VOLUMEUP },
+	{ 0xf808, KEY_CHANNELUP },
+	{ 0xf807, KEY_PVR },
+	{ 0xf80b, KEY_TIME },
+	{ 0xf802, KEY_RIGHT },
+	{ 0xf803, KEY_LEFT },
+	{ 0xf800, KEY_UP },
+	{ 0xf81f, KEY_OK },
+	{ 0xf801, KEY_DOWN },
+	{ 0xf805, KEY_TUNER },
+	{ 0xf806, KEY_CHANNELDOWN },
+	{ 0xf840, KEY_PLAYPAUSE },
+	{ 0xf81e, KEY_REWIND },
+	{ 0xf81b, KEY_FAVORITES },
+	{ 0xf81d, KEY_BACK },
+	{ 0xf84d, KEY_FASTFORWARD },
+	{ 0xf844, KEY_EPG },
+	{ 0xf84c, KEY_INFO },
+	{ 0xf841, KEY_AB },
+	{ 0xf843, KEY_AUDIO },
+	{ 0xf845, KEY_SUBTITLE },
+	{ 0xf84a, KEY_LIST },
+	{ 0xf846, KEY_F1 },
+	{ 0xf847, KEY_F2 },
+	{ 0xf85e, KEY_F3 },
+	{ 0xf85c, KEY_F4 },
+	{ 0xf852, KEY_F5 },
+	{ 0xf85a, KEY_F6 },
+	{ 0xf856, KEY_MODE },
+	{ 0xf858, KEY_SWITCHVIDEOMODE },
+};
+
+static struct rc_map_table rc_map_tbs_table[] = {
+	{ 0xf884, KEY_POWER },
+	{ 0xf894, KEY_MUTE },
+	{ 0xf887, KEY_1 },
+	{ 0xf886, KEY_2 },
+	{ 0xf885, KEY_3 },
+	{ 0xf88b, KEY_4 },
+	{ 0xf88a, KEY_5 },
+	{ 0xf889, KEY_6 },
+	{ 0xf88f, KEY_7 },
+	{ 0xf88e, KEY_8 },
+	{ 0xf88d, KEY_9 },
+	{ 0xf892, KEY_0 },
+	{ 0xf896, KEY_CHANNELUP },
+	{ 0xf891, KEY_CHANNELDOWN },
+	{ 0xf893, KEY_VOLUMEUP },
+	{ 0xf88c, KEY_VOLUMEDOWN },
+	{ 0xf883, KEY_RECORD },
+	{ 0xf898, KEY_PAUSE  },
+	{ 0xf899, KEY_OK },
+	{ 0xf89a, KEY_SHUFFLE },
+	{ 0xf881, KEY_UP },
+	{ 0xf890, KEY_LEFT },
+	{ 0xf882, KEY_RIGHT },
+	{ 0xf888, KEY_DOWN },
+	{ 0xf895, KEY_FAVORITES },
+	{ 0xf897, KEY_SUBTITLE },
+	{ 0xf89d, KEY_ZOOM },
+	{ 0xf89f, KEY_EXIT },
+	{ 0xf89e, KEY_MENU },
+	{ 0xf89c, KEY_EPG },
+	{ 0xf880, KEY_PREVIOUS },
+	{ 0xf89b, KEY_MODE }
+};
+
+static struct rc_map_table rc_map_su3000_table[] = {
+	{ 0x25, KEY_POWER },	/* right-bottom Red */
+	{ 0x0a, KEY_MUTE },	/* -/-- */
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+	{ 0x00, KEY_0 },
+	{ 0x20, KEY_UP },	/* CH+ */
+	{ 0x21, KEY_DOWN },	/* CH+ */
+	{ 0x12, KEY_VOLUMEUP },	/* Brightness Up */
+	{ 0x13, KEY_VOLUMEDOWN },/* Brightness Down */
+	{ 0x1f, KEY_RECORD },
+	{ 0x17, KEY_PLAY },
+	{ 0x16, KEY_PAUSE },
+	{ 0x0b, KEY_STOP },
+	{ 0x27, KEY_FASTFORWARD },/* >> */
+	{ 0x26, KEY_REWIND },	/* << */
+	{ 0x0d, KEY_OK },	/* Mute */
+	{ 0x11, KEY_LEFT },	/* VOL- */
+	{ 0x10, KEY_RIGHT },	/* VOL+ */
+	{ 0x29, KEY_BACK },	/* button under 9 */
+	{ 0x2c, KEY_MENU },	/* TTX */
+	{ 0x2b, KEY_EPG },	/* EPG */
+	{ 0x1e, KEY_RED },	/* OSD */
+	{ 0x0e, KEY_GREEN },	/* Window */
+	{ 0x2d, KEY_YELLOW },	/* button under << */
+	{ 0x0f, KEY_BLUE },	/* bottom yellow button */
+	{ 0x14, KEY_AUDIO },	/* Snapshot */
+	{ 0x38, KEY_TV },	/* TV/Radio */
+	{ 0x0c, KEY_ESC }	/* upper Red button */
+};
+
+static struct rc_map_dvb_usb_table_table keys_tables[] = {
+	{ rc_map_dw210x_table, ARRAY_SIZE(rc_map_dw210x_table) },
+	{ rc_map_tevii_table, ARRAY_SIZE(rc_map_tevii_table) },
+	{ rc_map_tbs_table, ARRAY_SIZE(rc_map_tbs_table) },
+	{ rc_map_su3000_table, ARRAY_SIZE(rc_map_su3000_table) },
+};
+
+static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
+	int keymap_size = d->props.rc.legacy.rc_map_size;
+	u8 key[2];
+	struct i2c_msg msg = {
+		.addr = DW2102_RC_QUERY,
+		.flags = I2C_M_RD,
+		.buf = key,
+		.len = 2
+	};
+	int i;
+	/* override keymap */
+	if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) {
+		keymap = keys_tables[ir_keymap - 1].rc_keys ;
+		keymap_size = keys_tables[ir_keymap - 1].rc_keys_size;
+	} else if (ir_keymap > ARRAY_SIZE(keys_tables))
+		return 0; /* none */
+
+	*state = REMOTE_NO_KEY_PRESSED;
+	if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) {
+		for (i = 0; i < keymap_size ; i++) {
+			if (rc5_data(&keymap[i]) == msg.buf[0]) {
+				*state = REMOTE_KEY_PRESSED;
+				*event = keymap[i].keycode;
+				break;
+			}
+
+		}
+
+		if ((*state) == REMOTE_KEY_PRESSED)
+			deb_rc("%s: found rc key: %x, %x, event: %x\n",
+					__func__, key[0], key[1], (*event));
+		else if (key[0] != 0xff)
+			deb_rc("%s: unknown rc key: %x, %x\n",
+					__func__, key[0], key[1]);
+
+	}
+
+	return 0;
+}
+
+enum dw2102_table_entry {
+	CYPRESS_DW2102,
+	CYPRESS_DW2101,
+	CYPRESS_DW2104,
+	TEVII_S650,
+	TERRATEC_CINERGY_S,
+	CYPRESS_DW3101,
+	TEVII_S630,
+	PROF_1100,
+	TEVII_S660,
+	PROF_7500,
+	GENIATECH_SU3000,
+	TERRATEC_CINERGY_S2,
+	TEVII_S480_1,
+	TEVII_S480_2,
+	X3M_SPC1400HD,
+};
+
+static struct usb_device_id dw2102_table[] = {
+	[CYPRESS_DW2102] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
+	[CYPRESS_DW2101] = {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
+	[CYPRESS_DW2104] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)},
+	[TEVII_S650] = {USB_DEVICE(0x9022, USB_PID_TEVII_S650)},
+	[TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
+	[CYPRESS_DW3101] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)},
+	[TEVII_S630] = {USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
+	[PROF_1100] = {USB_DEVICE(0x3011, USB_PID_PROF_1100)},
+	[TEVII_S660] = {USB_DEVICE(0x9022, USB_PID_TEVII_S660)},
+	[PROF_7500] = {USB_DEVICE(0x3034, 0x7500)},
+	[GENIATECH_SU3000] = {USB_DEVICE(0x1f4d, 0x3000)},
+	[TERRATEC_CINERGY_S2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)},
+	[TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)},
+	[TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
+	[X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(usb, dw2102_table);
+
+static int dw2102_load_firmware(struct usb_device *dev,
+			const struct firmware *frmwr)
+{
+	u8 *b, *p;
+	int ret = 0, i;
+	u8 reset;
+	u8 reset16[] = {0, 0, 0, 0, 0, 0, 0};
+	const struct firmware *fw;
+	const char *fw_2101 = "dvb-usb-dw2101.fw";
+
+	switch (dev->descriptor.idProduct) {
+	case 0x2101:
+		ret = request_firmware(&fw, fw_2101, &dev->dev);
+		if (ret != 0) {
+			err(err_str, fw_2101);
+			return ret;
+		}
+		break;
+	default:
+		fw = frmwr;
+		break;
+	}
+	info("start downloading DW210X firmware");
+	p = kmalloc(fw->size, GFP_KERNEL);
+	reset = 1;
+	/*stop the CPU*/
+	dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW210X_WRITE_MSG);
+	dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW210X_WRITE_MSG);
+
+	if (p != NULL) {
+		memcpy(p, fw->data, fw->size);
+		for (i = 0; i < fw->size; i += 0x40) {
+			b = (u8 *) p + i;
+			if (dw210x_op_rw(dev, 0xa0, i, 0, b , 0x40,
+					DW210X_WRITE_MSG) != 0x40) {
+				err("error while transferring firmware");
+				ret = -EINVAL;
+				break;
+			}
+		}
+		/* restart the CPU */
+		reset = 0;
+		if (ret || dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1,
+					DW210X_WRITE_MSG) != 1) {
+			err("could not restart the USB controller CPU.");
+			ret = -EINVAL;
+		}
+		if (ret || dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1,
+					DW210X_WRITE_MSG) != 1) {
+			err("could not restart the USB controller CPU.");
+			ret = -EINVAL;
+		}
+		/* init registers */
+		switch (dev->descriptor.idProduct) {
+		case USB_PID_TEVII_S650:
+			dw2104_properties.rc.legacy.rc_map_table = rc_map_tevii_table;
+			dw2104_properties.rc.legacy.rc_map_size =
+					ARRAY_SIZE(rc_map_tevii_table);
+		case USB_PID_DW2104:
+			reset = 1;
+			dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
+					DW210X_WRITE_MSG);
+			/* break omitted intentionally */
+		case USB_PID_DW3101:
+			reset = 0;
+			dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
+					DW210X_WRITE_MSG);
+			break;
+		case USB_PID_CINERGY_S:
+		case USB_PID_DW2102:
+			dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
+					DW210X_WRITE_MSG);
+			dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2,
+					DW210X_READ_MSG);
+			/* check STV0299 frontend  */
+			dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2,
+					DW210X_READ_MSG);
+			if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) {
+				dw2102_properties.i2c_algo = &dw2102_i2c_algo;
+				dw2102_properties.adapter->fe[0].tuner_attach = &dw2102_tuner_attach;
+				break;
+			} else {
+				/* check STV0288 frontend  */
+				reset16[0] = 0xd0;
+				reset16[1] = 1;
+				reset16[2] = 0;
+				dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3,
+						DW210X_WRITE_MSG);
+				dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3,
+						DW210X_READ_MSG);
+				if (reset16[2] == 0x11) {
+					dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo;
+					break;
+				}
+			}
+		case 0x2101:
+			dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2,
+					DW210X_READ_MSG);
+			dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7,
+					DW210X_READ_MSG);
+			dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7,
+					DW210X_READ_MSG);
+			dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2,
+					DW210X_READ_MSG);
+			break;
+		}
+
+		msleep(100);
+		kfree(p);
+	}
+	return ret;
+}
+
+static struct dvb_usb_device_properties dw2102_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.firmware = "dvb-usb-dw2102.fw",
+	.no_reconnect = 1,
+
+	.i2c_algo = &dw2102_serit_i2c_algo,
+
+	.rc.legacy = {
+		.rc_map_table = rc_map_dw210x_table,
+		.rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
+		.rc_interval = 150,
+		.rc_query = dw2102_rc_query,
+	},
+
+	.generic_bulk_ctrl_endpoint = 0x81,
+	/* parameter for the MPEG2-data transfer */
+	.num_adapters = 1,
+	.download_firmware = dw2102_load_firmware,
+	.read_mac_address = dw210x_read_mac_address,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.frontend_attach = dw2102_frontend_attach,
+			.stream = {
+				.type = USB_BULK,
+				.count = 8,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+		}
+	},
+	.num_device_descs = 3,
+	.devices = {
+		{"DVBWorld DVB-S 2102 USB2.0",
+			{&dw2102_table[CYPRESS_DW2102], NULL},
+			{NULL},
+		},
+		{"DVBWorld DVB-S 2101 USB2.0",
+			{&dw2102_table[CYPRESS_DW2101], NULL},
+			{NULL},
+		},
+		{"TerraTec Cinergy S USB",
+			{&dw2102_table[TERRATEC_CINERGY_S], NULL},
+			{NULL},
+		},
+	}
+};
+
+static struct dvb_usb_device_properties dw2104_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.firmware = "dvb-usb-dw2104.fw",
+	.no_reconnect = 1,
+
+	.i2c_algo = &dw2104_i2c_algo,
+	.rc.legacy = {
+		.rc_map_table = rc_map_dw210x_table,
+		.rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
+		.rc_interval = 150,
+		.rc_query = dw2102_rc_query,
+	},
+
+	.generic_bulk_ctrl_endpoint = 0x81,
+	/* parameter for the MPEG2-data transfer */
+	.num_adapters = 1,
+	.download_firmware = dw2102_load_firmware,
+	.read_mac_address = dw210x_read_mac_address,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.frontend_attach = dw2104_frontend_attach,
+			.stream = {
+				.type = USB_BULK,
+				.count = 8,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+		}
+	},
+	.num_device_descs = 2,
+	.devices = {
+		{ "DVBWorld DW2104 USB2.0",
+			{&dw2102_table[CYPRESS_DW2104], NULL},
+			{NULL},
+		},
+		{ "TeVii S650 USB2.0",
+			{&dw2102_table[TEVII_S650], NULL},
+			{NULL},
+		},
+	}
+};
+
+static struct dvb_usb_device_properties dw3101_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.firmware = "dvb-usb-dw3101.fw",
+	.no_reconnect = 1,
+
+	.i2c_algo = &dw3101_i2c_algo,
+	.rc.legacy = {
+		.rc_map_table = rc_map_dw210x_table,
+		.rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
+		.rc_interval = 150,
+		.rc_query = dw2102_rc_query,
+	},
+
+	.generic_bulk_ctrl_endpoint = 0x81,
+	/* parameter for the MPEG2-data transfer */
+	.num_adapters = 1,
+	.download_firmware = dw2102_load_firmware,
+	.read_mac_address = dw210x_read_mac_address,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.frontend_attach = dw3101_frontend_attach,
+			.tuner_attach = dw3101_tuner_attach,
+			.stream = {
+				.type = USB_BULK,
+				.count = 8,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+		}
+	},
+	.num_device_descs = 1,
+	.devices = {
+		{ "DVBWorld DVB-C 3101 USB2.0",
+			{&dw2102_table[CYPRESS_DW3101], NULL},
+			{NULL},
+		},
+	}
+};
+
+static struct dvb_usb_device_properties s6x0_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.size_of_priv = sizeof(struct s6x0_state),
+	.firmware = "dvb-usb-s630.fw",
+	.no_reconnect = 1,
+
+	.i2c_algo = &s6x0_i2c_algo,
+	.rc.legacy = {
+		.rc_map_table = rc_map_tevii_table,
+		.rc_map_size = ARRAY_SIZE(rc_map_tevii_table),
+		.rc_interval = 150,
+		.rc_query = dw2102_rc_query,
+	},
+
+	.generic_bulk_ctrl_endpoint = 0x81,
+	.num_adapters = 1,
+	.download_firmware = dw2102_load_firmware,
+	.read_mac_address = s6x0_read_mac_address,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.frontend_attach = zl100313_frontend_attach,
+			.stream = {
+				.type = USB_BULK,
+				.count = 8,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+		}
+	},
+	.num_device_descs = 1,
+	.devices = {
+		{"TeVii S630 USB",
+			{&dw2102_table[TEVII_S630], NULL},
+			{NULL},
+		},
+	}
+};
+
+struct dvb_usb_device_properties *p1100;
+static struct dvb_usb_device_description d1100 = {
+	"Prof 1100 USB ",
+	{&dw2102_table[PROF_1100], NULL},
+	{NULL},
+};
+
+struct dvb_usb_device_properties *s660;
+static struct dvb_usb_device_description d660 = {
+	"TeVii S660 USB",
+	{&dw2102_table[TEVII_S660], NULL},
+	{NULL},
+};
+
+static struct dvb_usb_device_description d480_1 = {
+	"TeVii S480.1 USB",
+	{&dw2102_table[TEVII_S480_1], NULL},
+	{NULL},
+};
+
+static struct dvb_usb_device_description d480_2 = {
+	"TeVii S480.2 USB",
+	{&dw2102_table[TEVII_S480_2], NULL},
+	{NULL},
+};
+
+struct dvb_usb_device_properties *p7500;
+static struct dvb_usb_device_description d7500 = {
+	"Prof 7500 USB DVB-S2",
+	{&dw2102_table[PROF_7500], NULL},
+	{NULL},
+};
+
+static struct dvb_usb_device_properties su3000_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.size_of_priv = sizeof(struct su3000_state),
+	.power_ctrl = su3000_power_ctrl,
+	.num_adapters = 1,
+	.identify_state	= su3000_identify_state,
+	.i2c_algo = &su3000_i2c_algo,
+
+	.rc.legacy = {
+		.rc_map_table = rc_map_su3000_table,
+		.rc_map_size = ARRAY_SIZE(rc_map_su3000_table),
+		.rc_interval = 150,
+		.rc_query = dw2102_rc_query,
+	},
+
+	.read_mac_address = su3000_read_mac_address,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = su3000_streaming_ctrl,
+			.frontend_attach  = su3000_frontend_attach,
+			.stream = {
+				.type = USB_BULK,
+				.count = 8,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			}
+		}},
+		}
+	},
+	.num_device_descs = 3,
+	.devices = {
+		{ "SU3000HD DVB-S USB2.0",
+			{ &dw2102_table[GENIATECH_SU3000], NULL },
+			{ NULL },
+		},
+		{ "Terratec Cinergy S2 USB HD",
+			{ &dw2102_table[TERRATEC_CINERGY_S2], NULL },
+			{ NULL },
+		},
+		{ "X3M TV SPC1400HD PCI",
+			{ &dw2102_table[X3M_SPC1400HD], NULL },
+			{ NULL },
+		},
+	}
+};
+
+static int dw2102_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	p1100 = kmemdup(&s6x0_properties,
+			sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
+	if (!p1100)
+		return -ENOMEM;
+	/* copy default structure */
+	/* fill only different fields */
+	p1100->firmware = "dvb-usb-p1100.fw";
+	p1100->devices[0] = d1100;
+	p1100->rc.legacy.rc_map_table = rc_map_tbs_table;
+	p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
+	p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach;
+
+	s660 = kmemdup(&s6x0_properties,
+		       sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
+	if (!s660) {
+		kfree(p1100);
+		return -ENOMEM;
+	}
+	s660->firmware = "dvb-usb-s660.fw";
+	s660->num_device_descs = 3;
+	s660->devices[0] = d660;
+	s660->devices[1] = d480_1;
+	s660->devices[2] = d480_2;
+	s660->adapter->fe[0].frontend_attach = ds3000_frontend_attach;
+
+	p7500 = kmemdup(&s6x0_properties,
+			sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
+	if (!p7500) {
+		kfree(p1100);
+		kfree(s660);
+		return -ENOMEM;
+	}
+	p7500->firmware = "dvb-usb-p7500.fw";
+	p7500->devices[0] = d7500;
+	p7500->rc.legacy.rc_map_table = rc_map_tbs_table;
+	p7500->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
+	p7500->adapter->fe[0].frontend_attach = prof_7500_frontend_attach;
+
+	if (0 == dvb_usb_device_init(intf, &dw2102_properties,
+			THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &dw2104_properties,
+			THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &dw3101_properties,
+			THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &s6x0_properties,
+			THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, p1100,
+			THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, s660,
+			THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, p7500,
+			THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &su3000_properties,
+				     THIS_MODULE, NULL, adapter_nr))
+		return 0;
+
+	return -ENODEV;
+}
+
+static struct usb_driver dw2102_driver = {
+	.name = "dw2102",
+	.probe = dw2102_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table = dw2102_table,
+};
+
+module_usb_driver(dw2102_driver);
+
+MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
+MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
+				" DVB-C 3101 USB2.0,"
+				" TeVii S600, S630, S650, S660, S480,"
+				" Prof 1100, 7500 USB2.0,"
+				" Geniatech SU3000 devices");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/dw2102.h b/drivers/media/usb/dvb-usb/dw2102.h
new file mode 100644
index 0000000..5cd0b0e
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dw2102.h
@@ -0,0 +1,9 @@
+#ifndef _DW2102_H_
+#define _DW2102_H_
+
+#define DVB_USB_LOG_PREFIX "dw2102"
+#include "dvb-usb.h"
+
+#define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args)
+#define deb_rc(args...)   dprintk(dvb_usb_dw2102_debug, 0x04, args)
+#endif
diff --git a/drivers/media/usb/dvb-usb/friio-fe.c b/drivers/media/usb/dvb-usb/friio-fe.c
new file mode 100644
index 0000000..90a70c6
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/friio-fe.c
@@ -0,0 +1,473 @@
+/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
+ *
+ * Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
+ *
+ * This module is based off the the gl861 and vp702x modules.
+ *
+ * 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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "friio.h"
+
+struct jdvbt90502_state {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend frontend;
+	struct jdvbt90502_config config;
+};
+
+/* NOTE: TC90502 has 16bit register-address? */
+/* register 0x0100 is used for reading PLL status, so reg is u16 here */
+static int jdvbt90502_reg_read(struct jdvbt90502_state *state,
+			       const u16 reg, u8 *buf, const size_t count)
+{
+	int ret;
+	u8 wbuf[3];
+	struct i2c_msg msg[2];
+
+	wbuf[0] = reg & 0xFF;
+	wbuf[1] = 0;
+	wbuf[2] = reg >> 8;
+
+	msg[0].addr = state->config.demod_address;
+	msg[0].flags = 0;
+	msg[0].buf = wbuf;
+	msg[0].len = sizeof(wbuf);
+
+	msg[1].addr = msg[0].addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].buf = buf;
+	msg[1].len = count;
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+	if (ret != 2) {
+		deb_fe(" reg read failed.\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+/* currently 16bit register-address is not used, so reg is u8 here */
+static int jdvbt90502_single_reg_write(struct jdvbt90502_state *state,
+				       const u8 reg, const u8 val)
+{
+	struct i2c_msg msg;
+	u8 wbuf[2];
+
+	wbuf[0] = reg;
+	wbuf[1] = val;
+
+	msg.addr = state->config.demod_address;
+	msg.flags = 0;
+	msg.buf = wbuf;
+	msg.len = sizeof(wbuf);
+
+	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+		deb_fe(" reg write failed.");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int _jdvbt90502_write(struct dvb_frontend *fe, const u8 buf[], int len)
+{
+	struct jdvbt90502_state *state = fe->demodulator_priv;
+	int err, i;
+	for (i = 0; i < len - 1; i++) {
+		err = jdvbt90502_single_reg_write(state,
+						  buf[0] + i, buf[i + 1]);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/* read pll status byte via the demodulator's I2C register */
+/* note: Win box reads it by 8B block at the I2C addr 0x30 from reg:0x80 */
+static int jdvbt90502_pll_read(struct jdvbt90502_state *state, u8 *result)
+{
+	int ret;
+
+	/* +1 for reading */
+	u8 pll_addr_byte = (state->config.pll_address << 1) + 1;
+
+	*result = 0;
+
+	ret = jdvbt90502_single_reg_write(state, JDVBT90502_2ND_I2C_REG,
+					  pll_addr_byte);
+	if (ret)
+		goto error;
+
+	ret = jdvbt90502_reg_read(state, 0x0100, result, 1);
+	if (ret)
+		goto error;
+
+	deb_fe("PLL read val:%02x\n", *result);
+	return 0;
+
+error:
+	deb_fe("%s:ret == %d\n", __func__, ret);
+	return -EREMOTEIO;
+}
+
+
+/* set pll frequency via the demodulator's I2C register */
+static int jdvbt90502_pll_set_freq(struct jdvbt90502_state *state, u32 freq)
+{
+	int ret;
+	int retry;
+	u8 res1;
+	u8 res2[9];
+
+	u8 pll_freq_cmd[PLL_CMD_LEN];
+	u8 pll_agc_cmd[PLL_CMD_LEN];
+	struct i2c_msg msg[2];
+	u32 f;
+
+	deb_fe("%s: freq=%d, step=%d\n", __func__, freq,
+	       state->frontend.ops.info.frequency_stepsize);
+	/* freq -> oscilator frequency conversion. */
+	/* freq: 473,000,000 + n*6,000,000 [+ 142857 (center freq. shift)] */
+	f = freq / state->frontend.ops.info.frequency_stepsize;
+	/* add 399[1/7 MHZ] = 57MHz for the IF  */
+	f += 399;
+	/* add center frequency shift if necessary */
+	if (f % 7 == 0)
+		f++;
+	pll_freq_cmd[DEMOD_REDIRECT_REG] = JDVBT90502_2ND_I2C_REG; /* 0xFE */
+	pll_freq_cmd[ADDRESS_BYTE] = state->config.pll_address << 1;
+	pll_freq_cmd[DIVIDER_BYTE1] = (f >> 8) & 0x7F;
+	pll_freq_cmd[DIVIDER_BYTE2] = f & 0xFF;
+	pll_freq_cmd[CONTROL_BYTE] = 0xB2; /* ref.divider:28, 4MHz/28=1/7MHz */
+	pll_freq_cmd[BANDSWITCH_BYTE] = 0x08;	/* UHF band */
+
+	msg[0].addr = state->config.demod_address;
+	msg[0].flags = 0;
+	msg[0].buf = pll_freq_cmd;
+	msg[0].len = sizeof(pll_freq_cmd);
+
+	ret = i2c_transfer(state->i2c, &msg[0], 1);
+	if (ret != 1)
+		goto error;
+
+	udelay(50);
+
+	pll_agc_cmd[DEMOD_REDIRECT_REG] = pll_freq_cmd[DEMOD_REDIRECT_REG];
+	pll_agc_cmd[ADDRESS_BYTE] = pll_freq_cmd[ADDRESS_BYTE];
+	pll_agc_cmd[DIVIDER_BYTE1] = pll_freq_cmd[DIVIDER_BYTE1];
+	pll_agc_cmd[DIVIDER_BYTE2] = pll_freq_cmd[DIVIDER_BYTE2];
+	pll_agc_cmd[CONTROL_BYTE] = 0x9A; /*  AGC_CTRL instead of BANDSWITCH */
+	pll_agc_cmd[AGC_CTRL_BYTE] = 0x50;
+	/* AGC Time Constant 2s, AGC take-over point:103dBuV(lowest) */
+
+	msg[1].addr = msg[0].addr;
+	msg[1].flags = 0;
+	msg[1].buf = pll_agc_cmd;
+	msg[1].len = sizeof(pll_agc_cmd);
+
+	ret = i2c_transfer(state->i2c, &msg[1], 1);
+	if (ret != 1)
+		goto error;
+
+	/* I don't know what these cmds are for,  */
+	/* but the USB log on a windows box contains them */
+	ret = jdvbt90502_single_reg_write(state, 0x01, 0x40);
+	ret |= jdvbt90502_single_reg_write(state, 0x01, 0x00);
+	if (ret)
+		goto error;
+	udelay(100);
+
+	/* wait for the demod to be ready? */
+#define RETRY_COUNT 5
+	for (retry = 0; retry < RETRY_COUNT; retry++) {
+		ret = jdvbt90502_reg_read(state, 0x0096, &res1, 1);
+		if (ret)
+			goto error;
+		/* if (res1 != 0x00) goto error; */
+		ret = jdvbt90502_reg_read(state, 0x00B0, res2, sizeof(res2));
+		if (ret)
+			goto error;
+		if (res2[0] >= 0xA7)
+			break;
+		msleep(100);
+	}
+	if (retry >= RETRY_COUNT) {
+		deb_fe("%s: FE does not get ready after freq setting.\n",
+		       __func__);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+error:
+	deb_fe("%s:ret == %d\n", __func__, ret);
+	return -EREMOTEIO;
+}
+
+static int jdvbt90502_read_status(struct dvb_frontend *fe, fe_status_t *state)
+{
+	u8 result;
+	int ret;
+
+	*state = FE_HAS_SIGNAL;
+
+	ret = jdvbt90502_pll_read(fe->demodulator_priv, &result);
+	if (ret) {
+		deb_fe("%s:ret == %d\n", __func__, ret);
+		return -EREMOTEIO;
+	}
+
+	*state = FE_HAS_SIGNAL
+		| FE_HAS_CARRIER
+		| FE_HAS_VITERBI
+		| FE_HAS_SYNC;
+
+	if (result & PLL_STATUS_LOCKED)
+		*state |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int jdvbt90502_read_signal_strength(struct dvb_frontend *fe,
+					   u16 *strength)
+{
+	int ret;
+	u8 rbuf[37];
+
+	*strength = 0;
+
+	/* status register (incl. signal strength) : 0x89  */
+	/* TODO: read just the necessary registers [0x8B..0x8D]? */
+	ret = jdvbt90502_reg_read(fe->demodulator_priv, 0x0089,
+				  rbuf, sizeof(rbuf));
+
+	if (ret) {
+		deb_fe("%s:ret == %d\n", __func__, ret);
+		return -EREMOTEIO;
+	}
+
+	/* signal_strength: rbuf[2-4] (24bit BE), use lower 16bit for now. */
+	*strength = (rbuf[3] << 8) + rbuf[4];
+	if (rbuf[2])
+		*strength = 0xffff;
+
+	return 0;
+}
+
+
+/* filter out un-supported properties to notify users */
+static int jdvbt90502_set_property(struct dvb_frontend *fe,
+				   struct dtv_property *tvp)
+{
+	int r = 0;
+
+	switch (tvp->cmd) {
+	case DTV_DELIVERY_SYSTEM:
+		if (tvp->u.data != SYS_ISDBT)
+			r = -EINVAL;
+		break;
+	case DTV_CLEAR:
+	case DTV_TUNE:
+	case DTV_FREQUENCY:
+		break;
+	default:
+		r = -EINVAL;
+	}
+	return r;
+}
+
+static int jdvbt90502_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	p->inversion = INVERSION_AUTO;
+	p->bandwidth_hz = 6000000;
+	p->code_rate_HP = FEC_AUTO;
+	p->code_rate_LP = FEC_AUTO;
+	p->modulation = QAM_64;
+	p->transmission_mode = TRANSMISSION_MODE_AUTO;
+	p->guard_interval = GUARD_INTERVAL_AUTO;
+	p->hierarchy = HIERARCHY_AUTO;
+	return 0;
+}
+
+static int jdvbt90502_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+	/**
+	 * NOTE: ignore all the parameters except frequency.
+	 *       others should be fixed to the proper value for ISDB-T,
+	 *       but don't check here.
+	 */
+
+	struct jdvbt90502_state *state = fe->demodulator_priv;
+	int ret;
+
+	deb_fe("%s: Freq:%d\n", __func__, p->frequency);
+
+	/* for recovery from DTV_CLEAN */
+	fe->dtv_property_cache.delivery_system = SYS_ISDBT;
+
+	ret = jdvbt90502_pll_set_freq(state, p->frequency);
+	if (ret) {
+		deb_fe("%s:ret == %d\n", __func__, ret);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+
+/**
+ * (reg, val) commad list to initialize this module.
+ *  captured on a Windows box.
+ */
+static u8 init_code[][2] = {
+	{0x01, 0x40},
+	{0x04, 0x38},
+	{0x05, 0x40},
+	{0x07, 0x40},
+	{0x0F, 0x4F},
+	{0x11, 0x21},
+	{0x12, 0x0B},
+	{0x13, 0x2F},
+	{0x14, 0x31},
+	{0x16, 0x02},
+	{0x21, 0xC4},
+	{0x22, 0x20},
+	{0x2C, 0x79},
+	{0x2D, 0x34},
+	{0x2F, 0x00},
+	{0x30, 0x28},
+	{0x31, 0x31},
+	{0x32, 0xDF},
+	{0x38, 0x01},
+	{0x39, 0x78},
+	{0x3B, 0x33},
+	{0x3C, 0x33},
+	{0x48, 0x90},
+	{0x51, 0x68},
+	{0x5E, 0x38},
+	{0x71, 0x00},
+	{0x72, 0x08},
+	{0x77, 0x00},
+	{0xC0, 0x21},
+	{0xC1, 0x10},
+	{0xE4, 0x1A},
+	{0xEA, 0x1F},
+	{0x77, 0x00},
+	{0x71, 0x00},
+	{0x71, 0x00},
+	{0x76, 0x0C},
+};
+
+static const int init_code_len = sizeof(init_code) / sizeof(u8[2]);
+
+static int jdvbt90502_init(struct dvb_frontend *fe)
+{
+	int i = -1;
+	int ret;
+	struct i2c_msg msg;
+
+	struct jdvbt90502_state *state = fe->demodulator_priv;
+
+	deb_fe("%s called.\n", __func__);
+
+	msg.addr = state->config.demod_address;
+	msg.flags = 0;
+	msg.len = 2;
+	for (i = 0; i < init_code_len; i++) {
+		msg.buf = init_code[i];
+		ret = i2c_transfer(state->i2c, &msg, 1);
+		if (ret != 1)
+			goto error;
+	}
+	fe->dtv_property_cache.delivery_system = SYS_ISDBT;
+	msleep(100);
+
+	return 0;
+
+error:
+	deb_fe("%s: init_code[%d] failed. ret==%d\n", __func__, i, ret);
+	return -EREMOTEIO;
+}
+
+
+static void jdvbt90502_release(struct dvb_frontend *fe)
+{
+	struct jdvbt90502_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+
+static struct dvb_frontend_ops jdvbt90502_ops;
+
+struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d)
+{
+	struct jdvbt90502_state *state = NULL;
+
+	deb_info("%s called.\n", __func__);
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct jdvbt90502_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->i2c = &d->i2c_adap;
+	memcpy(&state->config, &friio_fe_config, sizeof(friio_fe_config));
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &jdvbt90502_ops,
+	       sizeof(jdvbt90502_ops));
+	state->frontend.demodulator_priv = state;
+
+	if (jdvbt90502_init(&state->frontend) < 0)
+		goto error;
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops jdvbt90502_ops = {
+	.delsys = { SYS_ISDBT },
+	.info = {
+		.name			= "Comtech JDVBT90502 ISDB-T",
+		.frequency_min		= 473000000, /* UHF 13ch, center */
+		.frequency_max		= 767142857, /* UHF 62ch, center */
+		.frequency_stepsize	= JDVBT90502_PLL_CLK / JDVBT90502_PLL_DIVIDER,
+		.frequency_tolerance	= 0,
+
+		/* NOTE: this driver ignores all parameters but frequency. */
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+			FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
+			FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.release = jdvbt90502_release,
+
+	.init = jdvbt90502_init,
+	.write = _jdvbt90502_write,
+
+	.set_property = jdvbt90502_set_property,
+
+	.set_frontend = jdvbt90502_set_frontend,
+	.get_frontend = jdvbt90502_get_frontend,
+
+	.read_status = jdvbt90502_read_status,
+	.read_signal_strength = jdvbt90502_read_signal_strength,
+};
diff --git a/drivers/media/usb/dvb-usb/friio.c b/drivers/media/usb/dvb-usb/friio.c
new file mode 100644
index 0000000..474a17e
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/friio.c
@@ -0,0 +1,522 @@
+/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
+ *
+ * Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
+ *
+ * This module is based off the the gl861 and vp702x modules.
+ *
+ * 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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "friio.h"
+
+/* debug */
+int dvb_usb_friio_debug;
+module_param_named(debug, dvb_usb_friio_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+		 "set debugging level (1=info,2=xfer,4=rc,8=fe (or-able))."
+		 DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/**
+ * Indirect I2C access to the PLL via FE.
+ * whole I2C protocol data to the PLL is sent via the FE's I2C register.
+ * This is done by a control msg to the FE with the I2C data accompanied, and
+ * a specific USB request number is assigned for that purpose.
+ *
+ * this func sends wbuf[1..] to the I2C register wbuf[0] at addr (= at FE).
+ * TODO: refoctored, smarter i2c functions.
+ */
+static int gl861_i2c_ctrlmsg_data(struct dvb_usb_device *d, u8 addr,
+				  u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+	u16 index = wbuf[0];	/* must be JDVBT90502_2ND_I2C_REG(=0xFE) */
+	u16 value = addr << (8 + 1);
+	int wo = (rbuf == NULL || rlen == 0);	/* write only */
+	u8 req, type;
+
+	deb_xfer("write to PLL:0x%02x via FE reg:0x%02x, len:%d\n",
+		 wbuf[1], wbuf[0], wlen - 1);
+
+	if (wo && wlen >= 2) {
+		req = GL861_REQ_I2C_DATA_CTRL_WRITE;
+		type = GL861_WRITE;
+		udelay(20);
+		return usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
+				       req, type, value, index,
+				       &wbuf[1], wlen - 1, 2000);
+	}
+
+	deb_xfer("not supported ctrl-msg, aborting.");
+	return -EINVAL;
+}
+
+/* normal I2C access (without extra data arguments).
+ * write to the register wbuf[0] at I2C address addr with the value wbuf[1],
+ *  or read from the register wbuf[0].
+ * register address can be 16bit (wbuf[2]<<8 | wbuf[0]) if wlen==3
+ */
+static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
+			 u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+	u16 index;
+	u16 value = addr << (8 + 1);
+	int wo = (rbuf == NULL || rlen == 0);	/* write-only */
+	u8 req, type;
+	unsigned int pipe;
+
+	/* special case for the indirect I2C access to the PLL via FE, */
+	if (addr == friio_fe_config.demod_address &&
+	    wbuf[0] == JDVBT90502_2ND_I2C_REG)
+		return gl861_i2c_ctrlmsg_data(d, addr, wbuf, wlen, rbuf, rlen);
+
+	if (wo) {
+		req = GL861_REQ_I2C_WRITE;
+		type = GL861_WRITE;
+		pipe = usb_sndctrlpipe(d->udev, 0);
+	} else {		/* rw */
+		req = GL861_REQ_I2C_READ;
+		type = GL861_READ;
+		pipe = usb_rcvctrlpipe(d->udev, 0);
+	}
+
+	switch (wlen) {
+	case 1:
+		index = wbuf[0];
+		break;
+	case 2:
+		index = wbuf[0];
+		value = value + wbuf[1];
+		break;
+	case 3:
+		/* special case for 16bit register-address */
+		index = (wbuf[2] << 8) | wbuf[0];
+		value = value + wbuf[1];
+		break;
+	default:
+		deb_xfer("wlen = %x, aborting.", wlen);
+		return -EINVAL;
+	}
+	msleep(1);
+	return usb_control_msg(d->udev, pipe, req, type,
+			       value, index, rbuf, rlen, 2000);
+}
+
+/* I2C */
+static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+			  int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int i;
+
+
+	if (num > 2)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		/* write/read request */
+		if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) {
+			if (gl861_i2c_msg(d, msg[i].addr,
+					  msg[i].buf, msg[i].len,
+					  msg[i + 1].buf, msg[i + 1].len) < 0)
+				break;
+			i++;
+		} else
+			if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
+					  msg[i].len, NULL, 0) < 0)
+				break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return i;
+}
+
+static u32 gl861_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static int friio_ext_ctl(struct dvb_usb_adapter *adap,
+			 u32 sat_color, int lnb_on)
+{
+	int i;
+	int ret;
+	struct i2c_msg msg;
+	u8 *buf;
+	u32 mask;
+	u8 lnb = (lnb_on) ? FRIIO_CTL_LNB : 0;
+
+	buf = kmalloc(2, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	msg.addr = 0x00;
+	msg.flags = 0;
+	msg.len = 2;
+	msg.buf = buf;
+
+	buf[0] = 0x00;
+
+	/* send 2bit header (&B10) */
+	buf[1] = lnb | FRIIO_CTL_LED | FRIIO_CTL_STROBE;
+	ret = gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
+	buf[1] |= FRIIO_CTL_CLK;
+	ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
+
+	buf[1] = lnb | FRIIO_CTL_STROBE;
+	ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
+	buf[1] |= FRIIO_CTL_CLK;
+	ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
+
+	/* send 32bit(satur, R, G, B) data in serial */
+	mask = 1 << 31;
+	for (i = 0; i < 32; i++) {
+		buf[1] = lnb | FRIIO_CTL_STROBE;
+		if (sat_color & mask)
+			buf[1] |= FRIIO_CTL_LED;
+		ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
+		buf[1] |= FRIIO_CTL_CLK;
+		ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
+		mask >>= 1;
+	}
+
+	/* set the strobe off */
+	buf[1] = lnb;
+	ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
+	buf[1] |= FRIIO_CTL_CLK;
+	ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
+
+	kfree(buf);
+	return (ret == 70);
+}
+
+
+static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
+
+/* TODO: move these init cmds to the FE's init routine? */
+static u8 streaming_init_cmds[][2] = {
+	{0x33, 0x08},
+	{0x37, 0x40},
+	{0x3A, 0x1F},
+	{0x3B, 0xFF},
+	{0x3C, 0x1F},
+	{0x3D, 0xFF},
+	{0x38, 0x00},
+	{0x35, 0x00},
+	{0x39, 0x00},
+	{0x36, 0x00},
+};
+static int cmdlen = sizeof(streaming_init_cmds) / 2;
+
+/*
+ * Command sequence in this init function is a replay
+ *  of the captured USB commands from the Windows proprietary driver.
+ */
+static int friio_initialize(struct dvb_usb_device *d)
+{
+	int ret;
+	int i;
+	int retry = 0;
+	u8 *rbuf, *wbuf;
+
+	deb_info("%s called.\n", __func__);
+
+	wbuf = kmalloc(3, GFP_KERNEL);
+	if (!wbuf)
+		return -ENOMEM;
+
+	rbuf = kmalloc(2, GFP_KERNEL);
+	if (!rbuf) {
+		kfree(wbuf);
+		return -ENOMEM;
+	}
+
+	/* use gl861_i2c_msg instead of gl861_i2c_xfer(), */
+	/* because the i2c device is not set up yet. */
+	wbuf[0] = 0x11;
+	wbuf[1] = 0x02;
+	ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
+	if (ret < 0)
+		goto error;
+	msleep(2);
+
+	wbuf[0] = 0x11;
+	wbuf[1] = 0x00;
+	ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
+	if (ret < 0)
+		goto error;
+	msleep(1);
+
+	/* following msgs should be in the FE's init code? */
+	/* cmd sequence to identify the device type? (friio black/white) */
+	wbuf[0] = 0x03;
+	wbuf[1] = 0x80;
+	/* can't use gl861_i2c_cmd, as the register-addr is 16bit(0x0100) */
+	ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
+			      GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE,
+			      0x1200, 0x0100, wbuf, 2, 2000);
+	if (ret < 0)
+		goto error;
+
+	msleep(2);
+	wbuf[0] = 0x00;
+	wbuf[2] = 0x01;		/* reg.0x0100 */
+	wbuf[1] = 0x00;
+	ret = gl861_i2c_msg(d, 0x12 >> 1, wbuf, 3, rbuf, 2);
+	/* my Friio White returns 0xffff. */
+	if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff)
+		goto error;
+
+	msleep(2);
+	wbuf[0] = 0x03;
+	wbuf[1] = 0x80;
+	ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
+			      GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE,
+			      0x9000, 0x0100, wbuf, 2, 2000);
+	if (ret < 0)
+		goto error;
+
+	msleep(2);
+	wbuf[0] = 0x00;
+	wbuf[2] = 0x01;		/* reg.0x0100 */
+	wbuf[1] = 0x00;
+	ret = gl861_i2c_msg(d, 0x90 >> 1, wbuf, 3, rbuf, 2);
+	/* my Friio White returns 0xffff again. */
+	if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff)
+		goto error;
+
+	msleep(1);
+
+restart:
+	/* ============ start DEMOD init cmds ================== */
+	/* read PLL status to clear the POR bit */
+	wbuf[0] = JDVBT90502_2ND_I2C_REG;
+	wbuf[1] = (FRIIO_PLL_ADDR << 1) + 1;	/* +1 for reading */
+	ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, NULL, 0);
+	if (ret < 0)
+		goto error;
+
+	msleep(5);
+	/* note: DEMODULATOR has 16bit register-address. */
+	wbuf[0] = 0x00;
+	wbuf[2] = 0x01;		/* reg addr: 0x0100 */
+	wbuf[1] = 0x00;		/* val: not used */
+	ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 3, rbuf, 1);
+	if (ret < 0)
+		goto error;
+/*
+	msleep(1);
+	wbuf[0] = 0x80;
+	wbuf[1] = 0x00;
+	ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, rbuf, 1);
+	if (ret < 0)
+		goto error;
+ */
+	if (rbuf[0] & 0x80) {	/* still in PowerOnReset state? */
+		if (++retry > 3) {
+			deb_info("failed to get the correct"
+				 " FE demod status:0x%02x\n", rbuf[0]);
+			goto error;
+		}
+		msleep(100);
+		goto restart;
+	}
+
+	/* TODO: check return value in rbuf */
+	/* =========== end DEMOD init cmds ===================== */
+	msleep(1);
+
+	wbuf[0] = 0x30;
+	wbuf[1] = 0x04;
+	ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
+	if (ret < 0)
+		goto error;
+
+	msleep(2);
+	/* following 2 cmds unnecessary? */
+	wbuf[0] = 0x00;
+	wbuf[1] = 0x01;
+	ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
+	if (ret < 0)
+		goto error;
+
+	wbuf[0] = 0x06;
+	wbuf[1] = 0x0F;
+	ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
+	if (ret < 0)
+		goto error;
+
+	/* some streaming ctl cmds (maybe) */
+	msleep(10);
+	for (i = 0; i < cmdlen; i++) {
+		ret = gl861_i2c_msg(d, 0x00, streaming_init_cmds[i], 2,
+				    NULL, 0);
+		if (ret < 0)
+			goto error;
+		msleep(1);
+	}
+	msleep(20);
+
+	/* change the LED color etc. */
+	ret = friio_streaming_ctrl(&d->adapter[0], 0);
+	if (ret < 0)
+		goto error;
+
+	return 0;
+
+error:
+	kfree(wbuf);
+	kfree(rbuf);
+	deb_info("%s:ret == %d\n", __func__, ret);
+	return -EIO;
+}
+
+/* Callbacks for DVB USB */
+
+static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	int ret;
+
+	deb_info("%s called.(%d)\n", __func__, onoff);
+
+	/* set the LED color and saturation (and LNB on) */
+	if (onoff)
+		ret = friio_ext_ctl(adap, 0x6400ff64, 1);
+	else
+		ret = friio_ext_ctl(adap, 0x96ff00ff, 1);
+
+	if (ret != 1) {
+		deb_info("%s failed to send cmdx. ret==%d\n", __func__, ret);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int friio_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	if (friio_initialize(adap->dev) < 0)
+		return -EIO;
+
+	adap->fe_adap[0].fe = jdvbt90502_attach(adap->dev);
+	if (adap->fe_adap[0].fe == NULL)
+		return -EIO;
+
+	return 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties friio_properties;
+
+static int friio_probe(struct usb_interface *intf,
+		       const struct usb_device_id *id)
+{
+	struct dvb_usb_device *d;
+	struct usb_host_interface *alt;
+	int ret;
+
+	if (intf->num_altsetting < GL861_ALTSETTING_COUNT)
+		return -ENODEV;
+
+	alt = usb_altnum_to_altsetting(intf, FRIIO_BULK_ALTSETTING);
+	if (alt == NULL) {
+		deb_rc("not alt found!\n");
+		return -ENODEV;
+	}
+	ret = usb_set_interface(interface_to_usbdev(intf),
+				alt->desc.bInterfaceNumber,
+				alt->desc.bAlternateSetting);
+	if (ret != 0) {
+		deb_rc("failed to set alt-setting!\n");
+		return ret;
+	}
+
+	ret = dvb_usb_device_init(intf, &friio_properties,
+				  THIS_MODULE, &d, adapter_nr);
+	if (ret == 0)
+		friio_streaming_ctrl(&d->adapter[0], 1);
+
+	return ret;
+}
+
+
+struct jdvbt90502_config friio_fe_config = {
+	.demod_address = FRIIO_DEMOD_ADDR,
+	.pll_address = FRIIO_PLL_ADDR,
+};
+
+static struct i2c_algorithm gl861_i2c_algo = {
+	.master_xfer   = gl861_i2c_xfer,
+	.functionality = gl861_i2c_func,
+};
+
+static struct usb_device_id friio_table[] = {
+	{ USB_DEVICE(USB_VID_774, USB_PID_FRIIO_WHITE) },
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, friio_table);
+
+
+static struct dvb_usb_device_properties friio_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+
+	.size_of_priv = 0,
+
+	.num_adapters = 1,
+	.adapter = {
+		/* caps:0 =>  no pid filter, 188B TS packet */
+		/* GL861 has a HW pid filter, but no info available. */
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.caps  = 0,
+
+			.frontend_attach  = friio_frontend_attach,
+			.streaming_ctrl = friio_streaming_ctrl,
+
+			.stream = {
+				.type = USB_BULK,
+				/* count <= MAX_NO_URBS_FOR_DATA_STREAM(10) */
+				.count = 8,
+				.endpoint = 0x01,
+				.u = {
+					/* GL861 has 6KB buf inside */
+					.bulk = {
+						.buffersize = 16384,
+					}
+				}
+			},
+		}},
+		}
+	},
+	.i2c_algo = &gl861_i2c_algo,
+
+	.num_device_descs = 1,
+	.devices = {
+		{
+			.name = "774 Friio ISDB-T USB2.0",
+			.cold_ids = { NULL },
+			.warm_ids = { &friio_table[0], NULL },
+		},
+	}
+};
+
+static struct usb_driver friio_driver = {
+	.name		= "dvb_usb_friio",
+	.probe		= friio_probe,
+	.disconnect	= dvb_usb_device_exit,
+	.id_table	= friio_table,
+};
+
+module_usb_driver(friio_driver);
+
+MODULE_AUTHOR("Akihiro Tsukada <tskd2@yahoo.co.jp>");
+MODULE_DESCRIPTION("Driver for Friio ISDB-T USB2.0 Receiver");
+MODULE_VERSION("0.2");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/friio.h b/drivers/media/usb/dvb-usb/friio.h
new file mode 100644
index 0000000..0f461ca
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/friio.h
@@ -0,0 +1,99 @@
+/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
+ *
+ * Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
+ *
+ * This module is based off the the gl861 and vp702x modules.
+ *
+ * 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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_FRIIO_H_
+#define _DVB_USB_FRIIO_H_
+
+/**
+ *      Friio Components
+ *       USB hub:                                AU4254
+ *         USB controller(+ TS dmx & streaming): GL861
+ *         Frontend:                             comtech JDVBT-90502
+ *             (tuner PLL:                       tua6034, I2C addr:(0xC0 >> 1))
+ *             (OFDM demodulator:                TC90502, I2C addr:(0x30 >> 1))
+ *         LED x3 (+LNB) control:                PIC 16F676
+ *         EEPROM:                               24C08
+ *
+ *        (USB smart card reader:                AU9522)
+ *
+ */
+
+#define DVB_USB_LOG_PREFIX "friio"
+#include "dvb-usb.h"
+
+extern int dvb_usb_friio_debug;
+#define deb_info(args...) dprintk(dvb_usb_friio_debug, 0x01, args)
+#define deb_xfer(args...) dprintk(dvb_usb_friio_debug, 0x02, args)
+#define deb_rc(args...)   dprintk(dvb_usb_friio_debug, 0x04, args)
+#define deb_fe(args...)   dprintk(dvb_usb_friio_debug, 0x08, args)
+
+/* Vendor requests */
+#define GL861_WRITE		0x40
+#define GL861_READ		0xc0
+
+/* command bytes */
+#define GL861_REQ_I2C_WRITE	0x01
+#define GL861_REQ_I2C_READ	0x02
+/* For control msg with data argument */
+/* Used for accessing the PLL on the secondary I2C bus of FE via GL861 */
+#define GL861_REQ_I2C_DATA_CTRL_WRITE	0x03
+
+#define GL861_ALTSETTING_COUNT	2
+#define FRIIO_BULK_ALTSETTING	0
+#define FRIIO_ISOC_ALTSETTING	1
+
+/* LED & LNB control via PIC. */
+/* basically, it's serial control with clock and strobe. */
+/* write the below 4bit control data to the reg 0x00 at the I2C addr 0x00 */
+/* when controlling the LEDs, 32bit(saturation, R, G, B) is sent on the bit3*/
+#define FRIIO_CTL_LNB (1 << 0)
+#define FRIIO_CTL_STROBE (1 << 1)
+#define FRIIO_CTL_CLK (1 << 2)
+#define FRIIO_CTL_LED (1 << 3)
+
+/* Front End related */
+
+#define FRIIO_DEMOD_ADDR  (0x30 >> 1)
+#define FRIIO_PLL_ADDR  (0xC0 >> 1)
+
+#define JDVBT90502_PLL_CLK	4000000
+#define JDVBT90502_PLL_DIVIDER	28
+
+#define JDVBT90502_2ND_I2C_REG 0xFE
+
+/* byte index for pll i2c command data structure*/
+/* see datasheet for tua6034 */
+#define DEMOD_REDIRECT_REG 0
+#define ADDRESS_BYTE       1
+#define DIVIDER_BYTE1      2
+#define DIVIDER_BYTE2      3
+#define CONTROL_BYTE       4
+#define BANDSWITCH_BYTE    5
+#define AGC_CTRL_BYTE      5
+#define PLL_CMD_LEN        6
+
+/* bit masks for PLL STATUS response */
+#define PLL_STATUS_POR_MODE   0x80 /* 1: Power on Reset (test) Mode */
+#define PLL_STATUS_LOCKED     0x40 /* 1: locked */
+#define PLL_STATUS_AGC_ACTIVE 0x08 /* 1:active */
+#define PLL_STATUS_TESTMODE   0x07 /* digital output level (5 level) */
+  /* 0.15Vcc step   0x00: < 0.15Vcc, ..., 0x04: >= 0.6Vcc (<= 1Vcc) */
+
+
+struct jdvbt90502_config {
+	u8 demod_address; /* i2c addr for demodulator IC */
+	u8 pll_address;   /* PLL addr on the secondary i2c*/
+};
+extern struct jdvbt90502_config friio_fe_config;
+
+extern struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d);
+#endif
diff --git a/drivers/media/usb/dvb-usb/gp8psk-fe.c b/drivers/media/usb/dvb-usb/gp8psk-fe.c
new file mode 100644
index 0000000..67957dd
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/gp8psk-fe.c
@@ -0,0 +1,369 @@
+/* DVB USB compliant Linux driver for the
+ *  - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "gp8psk.h"
+
+struct gp8psk_fe_state {
+	struct dvb_frontend fe;
+	struct dvb_usb_device *d;
+	u8 lock;
+	u16 snr;
+	unsigned long next_status_check;
+	unsigned long status_check_interval;
+};
+
+static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe)
+{
+	struct gp8psk_fe_state *st = fe->demodulator_priv;
+	u8 status;
+	gp8psk_usb_in_op(st->d, GET_8PSK_CONFIG, 0, 0, &status, 1);
+	return status & bmDCtuned;
+}
+
+static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode)
+{
+	struct gp8psk_fe_state *state = fe->demodulator_priv;
+	return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0);
+}
+
+static int gp8psk_fe_update_status(struct gp8psk_fe_state *st)
+{
+	u8 buf[6];
+	if (time_after(jiffies,st->next_status_check)) {
+		gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1);
+		gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6);
+		st->snr = (buf[1]) << 8 | buf[0];
+		st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
+	}
+	return 0;
+}
+
+static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
+{
+	struct gp8psk_fe_state *st = fe->demodulator_priv;
+	gp8psk_fe_update_status(st);
+
+	if (st->lock)
+		*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
+	else
+		*status = 0;
+
+	if (*status & FE_HAS_LOCK)
+		st->status_check_interval = 1000;
+	else
+		st->status_check_interval = 100;
+	return 0;
+}
+
+/* not supported by this Frontend */
+static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+	(void) fe;
+	*ber = 0;
+	return 0;
+}
+
+/* not supported by this Frontend */
+static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+	(void) fe;
+	*unc = 0;
+	return 0;
+}
+
+static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+	struct gp8psk_fe_state *st = fe->demodulator_priv;
+	gp8psk_fe_update_status(st);
+	/* snr is reported in dBu*256 */
+	*snr = st->snr;
+	return 0;
+}
+
+static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+	struct gp8psk_fe_state *st = fe->demodulator_priv;
+	gp8psk_fe_update_status(st);
+	/* snr is reported in dBu*256 */
+	/* snr / 38.4 ~= 100% strength */
+	/* snr * 17 returns 100% strength as 65535 */
+	if (st->snr > 0xf00)
+		*strength = 0xffff;
+	else
+		*strength = (st->snr << 4) + st->snr; /* snr*17 */
+	return 0;
+}
+
+static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 800;
+	return 0;
+}
+
+static int gp8psk_fe_set_frontend(struct dvb_frontend *fe)
+{
+	struct gp8psk_fe_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u8 cmd[10];
+	u32 freq = c->frequency * 1000;
+	int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct);
+
+	deb_fe("%s()\n", __func__);
+
+	cmd[4] = freq         & 0xff;
+	cmd[5] = (freq >> 8)  & 0xff;
+	cmd[6] = (freq >> 16) & 0xff;
+	cmd[7] = (freq >> 24) & 0xff;
+
+	/* backwards compatibility: DVB-S + 8-PSK were used for Turbo-FEC */
+	if (c->delivery_system == SYS_DVBS && c->modulation == PSK_8)
+		c->delivery_system = SYS_TURBO;
+
+	switch (c->delivery_system) {
+	case SYS_DVBS:
+		if (c->modulation != QPSK) {
+			deb_fe("%s: unsupported modulation selected (%d)\n",
+				__func__, c->modulation);
+			return -EOPNOTSUPP;
+		}
+		c->fec_inner = FEC_AUTO;
+		break;
+	case SYS_DVBS2: /* kept for backwards compatibility */
+		deb_fe("%s: DVB-S2 delivery system selected\n", __func__);
+		break;
+	case SYS_TURBO:
+		deb_fe("%s: Turbo-FEC delivery system selected\n", __func__);
+		break;
+
+	default:
+		deb_fe("%s: unsupported delivery system selected (%d)\n",
+			__func__, c->delivery_system);
+		return -EOPNOTSUPP;
+	}
+
+	cmd[0] =  c->symbol_rate        & 0xff;
+	cmd[1] = (c->symbol_rate >>  8) & 0xff;
+	cmd[2] = (c->symbol_rate >> 16) & 0xff;
+	cmd[3] = (c->symbol_rate >> 24) & 0xff;
+	switch (c->modulation) {
+	case QPSK:
+		if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+			if (gp8psk_tuned_to_DCII(fe))
+				gp8psk_bcm4500_reload(state->d);
+		switch (c->fec_inner) {
+		case FEC_1_2:
+			cmd[9] = 0; break;
+		case FEC_2_3:
+			cmd[9] = 1; break;
+		case FEC_3_4:
+			cmd[9] = 2; break;
+		case FEC_5_6:
+			cmd[9] = 3; break;
+		case FEC_7_8:
+			cmd[9] = 4; break;
+		case FEC_AUTO:
+			cmd[9] = 5; break;
+		default:
+			cmd[9] = 5; break;
+		}
+		if (c->delivery_system == SYS_TURBO)
+			cmd[8] = ADV_MOD_TURBO_QPSK;
+		else
+			cmd[8] = ADV_MOD_DVB_QPSK;
+		break;
+	case PSK_8: /* PSK_8 is for compatibility with DN */
+		cmd[8] = ADV_MOD_TURBO_8PSK;
+		switch (c->fec_inner) {
+		case FEC_2_3:
+			cmd[9] = 0; break;
+		case FEC_3_4:
+			cmd[9] = 1; break;
+		case FEC_3_5:
+			cmd[9] = 2; break;
+		case FEC_5_6:
+			cmd[9] = 3; break;
+		case FEC_8_9:
+			cmd[9] = 4; break;
+		default:
+			cmd[9] = 0; break;
+		}
+		break;
+	case QAM_16: /* QAM_16 is for compatibility with DN */
+		cmd[8] = ADV_MOD_TURBO_16QAM;
+		cmd[9] = 0;
+		break;
+	default: /* Unknown modulation */
+		deb_fe("%s: unsupported modulation selected (%d)\n",
+			__func__, c->modulation);
+		return -EOPNOTSUPP;
+	}
+
+	if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+		gp8psk_set_tuner_mode(fe, 0);
+	gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10);
+
+	state->lock = 0;
+	state->next_status_check = jiffies;
+	state->status_check_interval = 200;
+
+	return 0;
+}
+
+static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
+				    struct dvb_diseqc_master_cmd *m)
+{
+	struct gp8psk_fe_state *st = fe->demodulator_priv;
+
+	deb_fe("%s\n",__func__);
+
+	if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0,
+			m->msg, m->msg_len)) {
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe,
+				    fe_sec_mini_cmd_t burst)
+{
+	struct gp8psk_fe_state *st = fe->demodulator_priv;
+	u8 cmd;
+
+	deb_fe("%s\n",__func__);
+
+	/* These commands are certainly wrong */
+	cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01;
+
+	if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0,
+			&cmd, 0)) {
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct gp8psk_fe_state* state = fe->demodulator_priv;
+
+	if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE,
+		 (tone == SEC_TONE_ON), 0, NULL, 0)) {
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	struct gp8psk_fe_state* state = fe->demodulator_priv;
+
+	if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE,
+			 voltage == SEC_VOLTAGE_18, 0, NULL, 0)) {
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff)
+{
+	struct gp8psk_fe_state* state = fe->demodulator_priv;
+	return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0);
+}
+
+static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd)
+{
+	struct gp8psk_fe_state* state = fe->demodulator_priv;
+	u8 cmd = sw_cmd & 0x7f;
+
+	if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0,
+			NULL, 0)) {
+		return -EINVAL;
+	}
+	if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80),
+			0, NULL, 0)) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void gp8psk_fe_release(struct dvb_frontend* fe)
+{
+	struct gp8psk_fe_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops gp8psk_fe_ops;
+
+struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d)
+{
+	struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL);
+	if (s == NULL)
+		goto error;
+
+	s->d = d;
+	memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops));
+	s->fe.demodulator_priv = s;
+
+	goto success;
+error:
+	return NULL;
+success:
+	return &s->fe;
+}
+
+
+static struct dvb_frontend_ops gp8psk_fe_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name			= "Genpix DVB-S",
+		.frequency_min		= 800000,
+		.frequency_max		= 2250000,
+		.frequency_stepsize	= 100,
+		.symbol_rate_min        = 1000000,
+		.symbol_rate_max        = 45000000,
+		.symbol_rate_tolerance  = 500,  /* ppm */
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			/*
+			 * FE_CAN_QAM_16 is for compatibility
+			 * (Myth incorrectly detects Turbo-QPSK as plain QAM-16)
+			 */
+			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_TURBO_FEC
+	},
+
+	.release = gp8psk_fe_release,
+
+	.init = NULL,
+	.sleep = NULL,
+
+	.set_frontend = gp8psk_fe_set_frontend,
+
+	.get_tune_settings = gp8psk_fe_get_tune_settings,
+
+	.read_status = gp8psk_fe_read_status,
+	.read_ber = gp8psk_fe_read_ber,
+	.read_signal_strength = gp8psk_fe_read_signal_strength,
+	.read_snr = gp8psk_fe_read_snr,
+	.read_ucblocks = gp8psk_fe_read_unc_blocks,
+
+	.diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg,
+	.diseqc_send_burst = gp8psk_fe_send_diseqc_burst,
+	.set_tone = gp8psk_fe_set_tone,
+	.set_voltage = gp8psk_fe_set_voltage,
+	.dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd,
+	.enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage
+};
diff --git a/drivers/media/usb/dvb-usb/gp8psk.c b/drivers/media/usb/dvb-usb/gp8psk.c
new file mode 100644
index 0000000..5d0384d
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/gp8psk.c
@@ -0,0 +1,328 @@
+/* DVB USB compliant Linux driver for the
+ *  - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "gp8psk.h"
+
+/* debug */
+static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw";
+int dvb_usb_gp8psk_debug;
+module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers)
+{
+	return (gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6));
+}
+
+static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers)
+{
+	return (gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1));
+}
+
+static void gp8psk_info(struct dvb_usb_device *d)
+{
+	u8 fpga_vers, fw_vers[6];
+
+	if (!gp8psk_get_fw_version(d, fw_vers))
+		info("FW Version = %i.%02i.%i (0x%x)  Build %4i/%02i/%02i",
+		fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers),
+		2000 + fw_vers[5], fw_vers[4], fw_vers[3]);
+	else
+		info("failed to get FW version");
+
+	if (!gp8psk_get_fpga_version(d, &fpga_vers))
+		info("FPGA Version = %i", fpga_vers);
+	else
+		info("failed to get FPGA version");
+}
+
+int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
+{
+	int ret = 0,try = 0;
+
+	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+		return ret;
+
+	while (ret >= 0 && ret != blen && try < 3) {
+		ret = usb_control_msg(d->udev,
+			usb_rcvctrlpipe(d->udev,0),
+			req,
+			USB_TYPE_VENDOR | USB_DIR_IN,
+			value,index,b,blen,
+			2000);
+		deb_info("reading number %d (ret: %d)\n",try,ret);
+		try++;
+	}
+
+	if (ret < 0 || ret != blen) {
+		warn("usb in %d operation failed.", req);
+		ret = -EIO;
+	} else
+		ret = 0;
+
+	deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
+	debug_dump(b,blen,deb_xfer);
+
+	mutex_unlock(&d->usb_mutex);
+
+	return ret;
+}
+
+int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+			     u16 index, u8 *b, int blen)
+{
+	int ret;
+
+	deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
+	debug_dump(b,blen,deb_xfer);
+
+	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+		return ret;
+
+	if (usb_control_msg(d->udev,
+			usb_sndctrlpipe(d->udev,0),
+			req,
+			USB_TYPE_VENDOR | USB_DIR_OUT,
+			value,index,b,blen,
+			2000) != blen) {
+		warn("usb out operation failed.");
+		ret = -EIO;
+	} else
+		ret = 0;
+	mutex_unlock(&d->usb_mutex);
+
+	return ret;
+}
+
+static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
+{
+	int ret;
+	const struct firmware *fw = NULL;
+	const u8 *ptr;
+	u8 *buf;
+	if ((ret = request_firmware(&fw, bcm4500_firmware,
+					&d->udev->dev)) != 0) {
+		err("did not find the bcm4500 firmware file. (%s) "
+			"Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
+			bcm4500_firmware,ret);
+		return ret;
+	}
+
+	ret = -EINVAL;
+
+	if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0))
+		goto out_rel_fw;
+
+	info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware);
+
+	ptr = fw->data;
+	buf = kmalloc(64, GFP_KERNEL | GFP_DMA);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto out_rel_fw;
+	}
+
+	while (ptr[0] != 0xff) {
+		u16 buflen = ptr[0] + 4;
+		if (ptr + buflen >= fw->data + fw->size) {
+			err("failed to load bcm4500 firmware.");
+			goto out_free;
+		}
+		memcpy(buf, ptr, buflen);
+		if (dvb_usb_generic_write(d, buf, buflen)) {
+			err("failed to load bcm4500 firmware.");
+			goto out_free;
+		}
+		ptr += buflen;
+	}
+
+	ret = 0;
+
+out_free:
+	kfree(buf);
+out_rel_fw:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	u8 status, buf;
+	int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
+
+	if (onoff) {
+		gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
+		if (! (status & bm8pskStarted)) {  /* started */
+			if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)
+				gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0);
+			if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
+				return -EINVAL;
+			gp8psk_info(d);
+		}
+
+		if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+			if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */
+				if(gp8psk_load_bcm4500fw(d))
+					return -EINVAL;
+
+		if (! (status & bmIntersilOn)) /* LNB Power */
+			if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0,
+					&buf, 1))
+				return -EINVAL;
+
+		/* Set DVB mode to 1 */
+		if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+			if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
+				return -EINVAL;
+		/* Abort possible TS (if previous tune crashed) */
+		if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0))
+			return -EINVAL;
+	} else {
+		/* Turn off LNB power */
+		if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1))
+			return -EINVAL;
+		/* Turn off 8psk power */
+		if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
+			return -EINVAL;
+		if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)
+			gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0);
+	}
+	return 0;
+}
+
+int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
+{
+	u8 buf;
+	int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
+	/* Turn off 8psk power */
+	if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
+		return -EINVAL;
+	/* Turn On 8psk power */
+	if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
+		return -EINVAL;
+	/* load BCM4500 firmware */
+	if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+		if (gp8psk_load_bcm4500fw(d))
+			return -EINVAL;
+	return 0;
+}
+
+static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0);
+}
+
+static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	adap->fe_adap[0].fe = gp8psk_fe_attach(adap->dev);
+	return 0;
+}
+
+static struct dvb_usb_device_properties gp8psk_properties;
+
+static int gp8psk_usb_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	int ret;
+	struct usb_device *udev = interface_to_usbdev(intf);
+	ret = dvb_usb_device_init(intf, &gp8psk_properties,
+				  THIS_MODULE, NULL, adapter_nr);
+	if (ret == 0) {
+		info("found Genpix USB device pID = %x (hex)",
+			le16_to_cpu(udev->descriptor.idProduct));
+	}
+	return ret;
+}
+
+static struct usb_device_id gp8psk_usb_table [] = {
+	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) },
+	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
+	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
+	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
+	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_2) },
+/*	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */
+	    { 0 },
+};
+MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
+
+static struct dvb_usb_device_properties gp8psk_properties = {
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-gp8psk-01.fw",
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = gp8psk_streaming_ctrl,
+			.frontend_attach  = gp8psk_frontend_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 7,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		}},
+		}
+	},
+	.power_ctrl       = gp8psk_power_ctrl,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 4,
+	.devices = {
+		{ .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
+		  .cold_ids = { &gp8psk_usb_table[0], NULL },
+		  .warm_ids = { &gp8psk_usb_table[1], NULL },
+		},
+		{ .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver",
+		  .cold_ids = { NULL },
+		  .warm_ids = { &gp8psk_usb_table[2], NULL },
+		},
+		{ .name = "Genpix SkyWalker-1 DVB-S receiver",
+		  .cold_ids = { NULL },
+		  .warm_ids = { &gp8psk_usb_table[3], NULL },
+		},
+		{ .name = "Genpix SkyWalker-2 DVB-S receiver",
+		  .cold_ids = { NULL },
+		  .warm_ids = { &gp8psk_usb_table[4], NULL },
+		},
+		{ NULL },
+	}
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver gp8psk_usb_driver = {
+	.name		= "dvb_usb_gp8psk",
+	.probe		= gp8psk_usb_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table	= gp8psk_usb_table,
+};
+
+module_usb_driver(gp8psk_usb_driver);
+
+MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");
+MODULE_DESCRIPTION("Driver for Genpix DVB-S");
+MODULE_VERSION("1.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/gp8psk.h b/drivers/media/usb/dvb-usb/gp8psk.h
new file mode 100644
index 0000000..ed32b9d
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/gp8psk.h
@@ -0,0 +1,100 @@
+/* DVB USB compliant Linux driver for the
+ *  - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_GP8PSK_H_
+#define _DVB_USB_GP8PSK_H_
+
+#define DVB_USB_LOG_PREFIX "gp8psk"
+#include "dvb-usb.h"
+
+extern int dvb_usb_gp8psk_debug;
+#define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args)
+#define deb_rc(args...)   dprintk(dvb_usb_gp8psk_debug,0x04,args)
+#define deb_fe(args...)   dprintk(dvb_usb_gp8psk_debug,0x08,args)
+
+/* Twinhan Vendor requests */
+#define TH_COMMAND_IN                     0xC0
+#define TH_COMMAND_OUT                    0xC1
+
+/* gp8psk commands */
+
+#define GET_8PSK_CONFIG                 0x80    /* in */
+#define SET_8PSK_CONFIG                 0x81
+#define I2C_WRITE			0x83
+#define I2C_READ			0x84
+#define ARM_TRANSFER                    0x85
+#define TUNE_8PSK                       0x86
+#define GET_SIGNAL_STRENGTH             0x87    /* in */
+#define LOAD_BCM4500                    0x88
+#define BOOT_8PSK                       0x89    /* in */
+#define START_INTERSIL                  0x8A    /* in */
+#define SET_LNB_VOLTAGE                 0x8B
+#define SET_22KHZ_TONE                  0x8C
+#define SEND_DISEQC_COMMAND             0x8D
+#define SET_DVB_MODE                    0x8E
+#define SET_DN_SWITCH                   0x8F
+#define GET_SIGNAL_LOCK                 0x90    /* in */
+#define GET_FW_VERS			0x92
+#define GET_SERIAL_NUMBER               0x93    /* in */
+#define USE_EXTRA_VOLT                  0x94
+#define GET_FPGA_VERS			0x95
+#define CW3K_INIT			0x9d
+
+/* PSK_configuration bits */
+#define bm8pskStarted                   0x01
+#define bm8pskFW_Loaded                 0x02
+#define bmIntersilOn                    0x04
+#define bmDVBmode                       0x08
+#define bm22kHz                         0x10
+#define bmSEL18V                        0x20
+#define bmDCtuned                       0x40
+#define bmArmed                         0x80
+
+/* Satellite modulation modes */
+#define ADV_MOD_DVB_QPSK 0     /* DVB-S QPSK */
+#define ADV_MOD_TURBO_QPSK 1   /* Turbo QPSK */
+#define ADV_MOD_TURBO_8PSK 2   /* Turbo 8PSK (also used for Trellis 8PSK) */
+#define ADV_MOD_TURBO_16QAM 3  /* Turbo 16QAM (also used for Trellis 8PSK) */
+
+#define ADV_MOD_DCII_C_QPSK 4  /* Digicipher II Combo */
+#define ADV_MOD_DCII_I_QPSK 5  /* Digicipher II I-stream */
+#define ADV_MOD_DCII_Q_QPSK 6  /* Digicipher II Q-stream */
+#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */
+#define ADV_MOD_DSS_QPSK 8     /* DSS (DIRECTV) QPSK */
+#define ADV_MOD_DVB_BPSK 9     /* DVB-S BPSK */
+
+#define GET_USB_SPEED                     0x07
+
+#define RESET_FX2                         0x13
+
+#define FW_VERSION_READ                   0x0B
+#define VENDOR_STRING_READ                0x0C
+#define PRODUCT_STRING_READ               0x0D
+#define FW_BCD_VERSION_READ               0x14
+
+/* firmware revision id's */
+#define GP8PSK_FW_REV1			0x020604
+#define GP8PSK_FW_REV2			0x020704
+#define GP8PSK_FW_VERS(_fw_vers)	((_fw_vers)[2]<<0x10 | (_fw_vers)[1]<<0x08 | (_fw_vers)[0])
+
+extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
+extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
+extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+			     u16 index, u8 *b, int blen);
+extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
+
+#endif
diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c
new file mode 100644
index 0000000..288af29
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/m920x.c
@@ -0,0 +1,1099 @@
+/* DVB USB compliant linux driver for MSI Mega Sky 580 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2006 Aapo Tahkola (aet@rasterburn.org)
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+
+#include "m920x.h"
+
+#include "mt352.h"
+#include "mt352_priv.h"
+#include "qt1010.h"
+#include "tda1004x.h"
+#include "tda827x.h"
+
+#include <media/tuner.h>
+#include "tuner-simple.h"
+#include <asm/unaligned.h>
+
+/* debug */
+static int dvb_usb_m920x_debug;
+module_param_named(debug,dvb_usb_m920x_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid);
+
+static inline int m920x_read(struct usb_device *udev, u8 request, u16 value,
+			     u16 index, void *data, int size)
+{
+	int ret;
+
+	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			      request, USB_TYPE_VENDOR | USB_DIR_IN,
+			      value, index, data, size, 2000);
+	if (ret < 0) {
+		printk(KERN_INFO "m920x_read = error: %d\n", ret);
+		return ret;
+	}
+
+	if (ret != size) {
+		deb("m920x_read = no data\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static inline int m920x_write(struct usb_device *udev, u8 request,
+			      u16 value, u16 index)
+{
+	int ret;
+
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      request, USB_TYPE_VENDOR | USB_DIR_OUT,
+			      value, index, NULL, 0, 2000);
+
+	return ret;
+}
+
+static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
+{
+	int ret = 0, i, epi, flags = 0;
+	int adap_enabled[M9206_MAX_ADAPTERS] = { 0 };
+
+	/* Remote controller init. */
+	if (d->props.rc.legacy.rc_query) {
+		deb("Initialising remote control\n");
+		while (rc_seq->address) {
+			if ((ret = m920x_write(d->udev, M9206_CORE,
+					       rc_seq->data,
+					       rc_seq->address)) != 0) {
+				deb("Initialising remote control failed\n");
+				return ret;
+			}
+
+			rc_seq++;
+		}
+
+		deb("Initialising remote control success\n");
+	}
+
+	for (i = 0; i < d->props.num_adapters; i++)
+		flags |= d->adapter[i].props.fe[0].caps;
+
+	/* Some devices(Dposh) might crash if we attempt touch at all. */
+	if (flags & DVB_USB_ADAP_HAS_PID_FILTER) {
+		for (i = 0; i < d->props.num_adapters; i++) {
+			epi = d->adapter[i].props.fe[0].stream.endpoint - 0x81;
+
+			if (epi < 0 || epi >= M9206_MAX_ADAPTERS) {
+				printk(KERN_INFO "m920x: Unexpected adapter endpoint!\n");
+				return -EINVAL;
+			}
+
+			adap_enabled[epi] = 1;
+		}
+
+		for (i = 0; i < M9206_MAX_ADAPTERS; i++) {
+			if (adap_enabled[i])
+				continue;
+
+			if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x0)) != 0)
+				return ret;
+
+			if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x02f5)) != 0)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int m920x_init_ep(struct usb_interface *intf)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct usb_host_interface *alt;
+
+	if ((alt = usb_altnum_to_altsetting(intf, 1)) == NULL) {
+		deb("No alt found!\n");
+		return -ENODEV;
+	}
+
+	return usb_set_interface(udev, alt->desc.bInterfaceNumber,
+				 alt->desc.bAlternateSetting);
+}
+
+static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	struct m920x_state *m = d->priv;
+	int i, ret = 0;
+	u8 *rc_state;
+
+	rc_state = kmalloc(2, GFP_KERNEL);
+	if (!rc_state)
+		return -ENOMEM;
+
+	if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0)
+		goto out;
+
+	if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
+		goto out;
+
+	for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
+		if (rc5_data(&d->props.rc.legacy.rc_map_table[i]) == rc_state[1]) {
+			*event = d->props.rc.legacy.rc_map_table[i].keycode;
+
+			switch(rc_state[0]) {
+			case 0x80:
+				*state = REMOTE_NO_KEY_PRESSED;
+				goto out;
+
+			case 0x88: /* framing error or "invalid code" */
+			case 0x99:
+			case 0xc0:
+			case 0xd8:
+				*state = REMOTE_NO_KEY_PRESSED;
+				m->rep_count = 0;
+				goto out;
+
+			case 0x93:
+			case 0x92:
+			case 0x83: /* pinnacle PCTV310e */
+			case 0x82:
+				m->rep_count = 0;
+				*state = REMOTE_KEY_PRESSED;
+				goto out;
+
+			case 0x91:
+			case 0x81: /* pinnacle PCTV310e */
+				/* prevent immediate auto-repeat */
+				if (++m->rep_count > 2)
+					*state = REMOTE_KEY_REPEAT;
+				else
+					*state = REMOTE_NO_KEY_PRESSED;
+				goto out;
+
+			default:
+				deb("Unexpected rc state %02x\n", rc_state[0]);
+				*state = REMOTE_NO_KEY_PRESSED;
+				goto out;
+			}
+		}
+
+	if (rc_state[1] != 0)
+		deb("Unknown rc key %02x\n", rc_state[1]);
+
+	*state = REMOTE_NO_KEY_PRESSED;
+
+ out:
+	kfree(rc_state);
+	return ret;
+}
+
+/* I2C */
+static int m920x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int i, j;
+	int ret = 0;
+
+	if (!num)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		if (msg[i].flags & (I2C_M_NO_RD_ACK | I2C_M_IGNORE_NAK | I2C_M_TEN) || msg[i].len == 0) {
+			/* For a 0 byte message, I think sending the address
+			 * to index 0x80|0x40 would be the correct thing to
+			 * do.  However, zero byte messages are only used for
+			 * probing, and since we don't know how to get the
+			 * slave's ack, we can't probe. */
+			ret = -ENOTSUPP;
+			goto unlock;
+		}
+		/* Send START & address/RW bit */
+		if (!(msg[i].flags & I2C_M_NOSTART)) {
+			if ((ret = m920x_write(d->udev, M9206_I2C,
+					(msg[i].addr << 1) |
+					(msg[i].flags & I2C_M_RD ? 0x01 : 0), 0x80)) != 0)
+				goto unlock;
+			/* Should check for ack here, if we knew how. */
+		}
+		if (msg[i].flags & I2C_M_RD) {
+			for (j = 0; j < msg[i].len; j++) {
+				/* Last byte of transaction?
+				 * Send STOP, otherwise send ACK. */
+				int stop = (i+1 == num && j+1 == msg[i].len) ? 0x40 : 0x01;
+
+				if ((ret = m920x_read(d->udev, M9206_I2C, 0x0,
+						      0x20 | stop,
+						      &msg[i].buf[j], 1)) != 0)
+					goto unlock;
+			}
+		} else {
+			for (j = 0; j < msg[i].len; j++) {
+				/* Last byte of transaction? Then send STOP. */
+				int stop = (i+1 == num && j+1 == msg[i].len) ? 0x40 : 0x00;
+
+				if ((ret = m920x_write(d->udev, M9206_I2C, msg[i].buf[j], stop)) != 0)
+					goto unlock;
+				/* Should check for ack here too. */
+			}
+		}
+	}
+	ret = num;
+
+ unlock:
+	mutex_unlock(&d->i2c_mutex);
+
+	return ret;
+}
+
+static u32 m920x_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm m920x_i2c_algo = {
+	.master_xfer   = m920x_i2c_xfer,
+	.functionality = m920x_i2c_func,
+};
+
+/* pid filter */
+static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid)
+{
+	int ret = 0;
+
+	if (pid >= 0x8000)
+		return -EINVAL;
+
+	pid |= 0x8000;
+
+	if ((ret = m920x_write(d->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
+		return ret;
+
+	if ((ret = m920x_write(d->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
+		return ret;
+
+	return ret;
+}
+
+static int m920x_update_filters(struct dvb_usb_adapter *adap)
+{
+	struct m920x_state *m = adap->dev->priv;
+	int enabled = m->filtering_enabled[adap->id];
+	int i, ret = 0, filter = 0;
+	int ep = adap->props.fe[0].stream.endpoint;
+
+	for (i = 0; i < M9206_MAX_FILTERS; i++)
+		if (m->filters[adap->id][i] == 8192)
+			enabled = 0;
+
+	/* Disable all filters */
+	if ((ret = m920x_set_filter(adap->dev, ep, 1, enabled)) != 0)
+		return ret;
+
+	for (i = 0; i < M9206_MAX_FILTERS; i++)
+		if ((ret = m920x_set_filter(adap->dev, ep, i + 2, 0)) != 0)
+			return ret;
+
+	/* Set */
+	if (enabled) {
+		for (i = 0; i < M9206_MAX_FILTERS; i++) {
+			if (m->filters[adap->id][i] == 0)
+				continue;
+
+			if ((ret = m920x_set_filter(adap->dev, ep, filter + 2, m->filters[adap->id][i])) != 0)
+				return ret;
+
+			filter++;
+		}
+	}
+
+	return ret;
+}
+
+static int m920x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	struct m920x_state *m = adap->dev->priv;
+
+	m->filtering_enabled[adap->id] = onoff ? 1 : 0;
+
+	return m920x_update_filters(adap);
+}
+
+static int m920x_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
+{
+	struct m920x_state *m = adap->dev->priv;
+
+	m->filters[adap->id][index] = onoff ? pid : 0;
+
+	return m920x_update_filters(adap);
+}
+
+static int m920x_firmware_download(struct usb_device *udev, const struct firmware *fw)
+{
+	u16 value, index, size;
+	u8 *read, *buff;
+	int i, pass, ret = 0;
+
+	buff = kmalloc(65536, GFP_KERNEL);
+	if (buff == NULL)
+		return -ENOMEM;
+
+	read = kmalloc(4, GFP_KERNEL);
+	if (!read) {
+		kfree(buff);
+		return -ENOMEM;
+	}
+
+	if ((ret = m920x_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0)
+		goto done;
+	deb("%x %x %x %x\n", read[0], read[1], read[2], read[3]);
+
+	if ((ret = m920x_read(udev, M9206_FW, 0x0, 0x0, read, 1)) != 0)
+		goto done;
+	deb("%x\n", read[0]);
+
+	for (pass = 0; pass < 2; pass++) {
+		for (i = 0; i + (sizeof(u16) * 3) < fw->size;) {
+			value = get_unaligned_le16(fw->data + i);
+			i += sizeof(u16);
+
+			index = get_unaligned_le16(fw->data + i);
+			i += sizeof(u16);
+
+			size = get_unaligned_le16(fw->data + i);
+			i += sizeof(u16);
+
+			if (pass == 1) {
+				/* Will stall if using fw->data ... */
+				memcpy(buff, fw->data + i, size);
+
+				ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0),
+						      M9206_FW,
+						      USB_TYPE_VENDOR | USB_DIR_OUT,
+						      value, index, buff, size, 20);
+				if (ret != size) {
+					deb("error while uploading fw!\n");
+					ret = -EIO;
+					goto done;
+				}
+				msleep(3);
+			}
+			i += size;
+		}
+		if (i != fw->size) {
+			deb("bad firmware file!\n");
+			ret = -EINVAL;
+			goto done;
+		}
+	}
+
+	msleep(36);
+
+	/* m920x will disconnect itself from the bus after this. */
+	(void) m920x_write(udev, M9206_CORE, 0x01, M9206_FW_GO);
+	deb("firmware uploaded!\n");
+
+ done:
+	kfree(read);
+	kfree(buff);
+
+	return ret;
+}
+
+/* Callbacks for DVB USB */
+static int m920x_identify_state(struct usb_device *udev,
+				struct dvb_usb_device_properties *props,
+				struct dvb_usb_device_description **desc,
+				int *cold)
+{
+	struct usb_host_interface *alt;
+
+	alt = usb_altnum_to_altsetting(usb_ifnum_to_if(udev, 0), 1);
+	*cold = (alt == NULL) ? 1 : 0;
+
+	return 0;
+}
+
+/* demod configurations */
+static int m920x_mt352_demod_init(struct dvb_frontend *fe)
+{
+	int ret;
+	u8 config[] = { CONFIG, 0x3d };
+	u8 clock[] = { CLOCK_CTL, 0x30 };
+	u8 reset[] = { RESET, 0x80 };
+	u8 adc_ctl[] = { ADC_CTL_1, 0x40 };
+	u8 agc[] = { AGC_TARGET, 0x1c, 0x20 };
+	u8 sec_agc[] = { 0x69, 0x00, 0xff, 0xff, 0x40, 0xff, 0x00, 0x40, 0x40 };
+	u8 unk1[] = { 0x93, 0x1a };
+	u8 unk2[] = { 0xb5, 0x7a };
+
+	deb("Demod init!\n");
+
+	if ((ret = mt352_write(fe, config, ARRAY_SIZE(config))) != 0)
+		return ret;
+	if ((ret = mt352_write(fe, clock, ARRAY_SIZE(clock))) != 0)
+		return ret;
+	if ((ret = mt352_write(fe, reset, ARRAY_SIZE(reset))) != 0)
+		return ret;
+	if ((ret = mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl))) != 0)
+		return ret;
+	if ((ret = mt352_write(fe, agc, ARRAY_SIZE(agc))) != 0)
+		return ret;
+	if ((ret = mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc))) != 0)
+		return ret;
+	if ((ret = mt352_write(fe, unk1, ARRAY_SIZE(unk1))) != 0)
+		return ret;
+	if ((ret = mt352_write(fe, unk2, ARRAY_SIZE(unk2))) != 0)
+		return ret;
+
+	return 0;
+}
+
+static struct mt352_config m920x_mt352_config = {
+	.demod_address = 0x0f,
+	.no_tuner = 1,
+	.demod_init = m920x_mt352_demod_init,
+};
+
+static struct tda1004x_config m920x_tda10046_08_config = {
+	.demod_address = 0x08,
+	.invert = 0,
+	.invert_oclk = 0,
+	.ts_mode = TDA10046_TS_SERIAL,
+	.xtal_freq = TDA10046_XTAL_16M,
+	.if_freq = TDA10046_FREQ_045,
+	.agc_config = TDA10046_AGC_TDA827X,
+	.gpio_config = TDA10046_GPTRI,
+	.request_firmware = NULL,
+};
+
+static struct tda1004x_config m920x_tda10046_0b_config = {
+	.demod_address = 0x0b,
+	.invert = 0,
+	.invert_oclk = 0,
+	.ts_mode = TDA10046_TS_SERIAL,
+	.xtal_freq = TDA10046_XTAL_16M,
+	.if_freq = TDA10046_FREQ_045,
+	.agc_config = TDA10046_AGC_TDA827X,
+	.gpio_config = TDA10046_GPTRI,
+	.request_firmware = NULL, /* uses firmware EEPROM */
+};
+
+/* tuner configurations */
+static struct qt1010_config m920x_qt1010_config = {
+	.i2c_address = 0x62
+};
+
+/* Callbacks for DVB USB */
+static int m920x_mt352_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	deb("%s\n",__func__);
+
+	adap->fe_adap[0].fe = dvb_attach(mt352_attach,
+					 &m920x_mt352_config,
+					 &adap->dev->i2c_adap);
+	if ((adap->fe_adap[0].fe) == NULL)
+		return -EIO;
+
+	return 0;
+}
+
+static int m920x_tda10046_08_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	deb("%s\n",__func__);
+
+	adap->fe_adap[0].fe = dvb_attach(tda10046_attach,
+					 &m920x_tda10046_08_config,
+					 &adap->dev->i2c_adap);
+	if ((adap->fe_adap[0].fe) == NULL)
+		return -EIO;
+
+	return 0;
+}
+
+static int m920x_tda10046_0b_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	deb("%s\n",__func__);
+
+	adap->fe_adap[0].fe = dvb_attach(tda10046_attach,
+					 &m920x_tda10046_0b_config,
+					 &adap->dev->i2c_adap);
+	if ((adap->fe_adap[0].fe) == NULL)
+		return -EIO;
+
+	return 0;
+}
+
+static int m920x_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	deb("%s\n",__func__);
+
+	if (dvb_attach(qt1010_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int m920x_tda8275_60_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	deb("%s\n",__func__);
+
+	if (dvb_attach(tda827x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, NULL) == NULL)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	deb("%s\n",__func__);
+
+	if (dvb_attach(tda827x_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int m920x_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe,
+		   &adap->dev->i2c_adap, 0x61,
+		   TUNER_PHILIPS_FMD1216ME_MK3);
+	return 0;
+}
+
+/* device-specific initialization */
+static struct m920x_inits megasky_rc_init [] = {
+	{ M9206_RC_INIT2, 0xa8 },
+	{ M9206_RC_INIT1, 0x51 },
+	{ } /* terminating entry */
+};
+
+static struct m920x_inits tvwalkertwin_rc_init [] = {
+	{ M9206_RC_INIT2, 0x00 },
+	{ M9206_RC_INIT1, 0xef },
+	{ 0xff28,         0x00 },
+	{ 0xff23,         0x00 },
+	{ 0xff21,         0x30 },
+	{ } /* terminating entry */
+};
+
+static struct m920x_inits pinnacle310e_init[] = {
+	/* without these the tuner don't work */
+	{ 0xff20,         0x9b },
+	{ 0xff22,         0x70 },
+
+	/* rc settings */
+	{ 0xff50,         0x80 },
+	{ M9206_RC_INIT1, 0x00 },
+	{ M9206_RC_INIT2, 0xff },
+	{ } /* terminating entry */
+};
+
+/* ir keymaps */
+static struct rc_map_table rc_map_megasky_table[] = {
+	{ 0x0012, KEY_POWER },
+	{ 0x001e, KEY_CYCLEWINDOWS }, /* min/max */
+	{ 0x0002, KEY_CHANNELUP },
+	{ 0x0005, KEY_CHANNELDOWN },
+	{ 0x0003, KEY_VOLUMEUP },
+	{ 0x0006, KEY_VOLUMEDOWN },
+	{ 0x0004, KEY_MUTE },
+	{ 0x0007, KEY_OK }, /* TS */
+	{ 0x0008, KEY_STOP },
+	{ 0x0009, KEY_MENU }, /* swap */
+	{ 0x000a, KEY_REWIND },
+	{ 0x001b, KEY_PAUSE },
+	{ 0x001f, KEY_FASTFORWARD },
+	{ 0x000c, KEY_RECORD },
+	{ 0x000d, KEY_CAMERA }, /* screenshot */
+	{ 0x000e, KEY_COFFEE }, /* "MTS" */
+};
+
+static struct rc_map_table rc_map_tvwalkertwin_table[] = {
+	{ 0x0001, KEY_ZOOM }, /* Full Screen */
+	{ 0x0002, KEY_CAMERA }, /* snapshot */
+	{ 0x0003, KEY_MUTE },
+	{ 0x0004, KEY_REWIND },
+	{ 0x0005, KEY_PLAYPAUSE }, /* Play/Pause */
+	{ 0x0006, KEY_FASTFORWARD },
+	{ 0x0007, KEY_RECORD },
+	{ 0x0008, KEY_STOP },
+	{ 0x0009, KEY_TIME }, /* Timeshift */
+	{ 0x000c, KEY_COFFEE }, /* Recall */
+	{ 0x000e, KEY_CHANNELUP },
+	{ 0x0012, KEY_POWER },
+	{ 0x0015, KEY_MENU }, /* source */
+	{ 0x0018, KEY_CYCLEWINDOWS }, /* TWIN PIP */
+	{ 0x001a, KEY_CHANNELDOWN },
+	{ 0x001b, KEY_VOLUMEDOWN },
+	{ 0x001e, KEY_VOLUMEUP },
+};
+
+static struct rc_map_table rc_map_pinnacle310e_table[] = {
+	{ 0x16, KEY_POWER },
+	{ 0x17, KEY_FAVORITES },
+	{ 0x0f, KEY_TEXT },
+	{ 0x48, KEY_PROGRAM },		/* preview */
+	{ 0x1c, KEY_EPG },
+	{ 0x04, KEY_LIST },		/* record list */
+	{ 0x03, KEY_1 },
+	{ 0x01, KEY_2 },
+	{ 0x06, KEY_3 },
+	{ 0x09, KEY_4 },
+	{ 0x1d, KEY_5 },
+	{ 0x1f, KEY_6 },
+	{ 0x0d, KEY_7 },
+	{ 0x19, KEY_8 },
+	{ 0x1b, KEY_9 },
+	{ 0x15, KEY_0 },
+	{ 0x0c, KEY_CANCEL },
+	{ 0x4a, KEY_CLEAR },
+	{ 0x13, KEY_BACK },
+	{ 0x00, KEY_TAB },
+	{ 0x4b, KEY_UP },
+	{ 0x4e, KEY_LEFT },
+	{ 0x52, KEY_RIGHT },
+	{ 0x51, KEY_DOWN },
+	{ 0x4f, KEY_ENTER },		/* could also be KEY_OK */
+	{ 0x1e, KEY_VOLUMEUP },
+	{ 0x0a, KEY_VOLUMEDOWN },
+	{ 0x05, KEY_CHANNELUP },
+	{ 0x02, KEY_CHANNELDOWN },
+	{ 0x11, KEY_RECORD },
+	{ 0x14, KEY_PLAY },
+	{ 0x4c, KEY_PAUSE },
+	{ 0x1a, KEY_STOP },
+	{ 0x40, KEY_REWIND },
+	{ 0x12, KEY_FASTFORWARD },
+	{ 0x41, KEY_PREVIOUSSONG },	/* Replay */
+	{ 0x42, KEY_NEXTSONG },		/* Skip */
+	{ 0x54, KEY_CAMERA },		/* Capture */
+/*	{ 0x50, KEY_SAP },	*/		/* Sap */
+	{ 0x47, KEY_CYCLEWINDOWS },	/* Pip */
+	{ 0x4d, KEY_SCREEN },		/* FullScreen */
+	{ 0x08, KEY_SUBTITLE },
+	{ 0x0e, KEY_MUTE },
+/*	{ 0x49, KEY_LR },	*/		/* L/R */
+	{ 0x07, KEY_SLEEP },		/* Hibernate */
+	{ 0x08, KEY_VIDEO },		/* A/V */
+	{ 0x0e, KEY_MENU },		/* Recall */
+	{ 0x45, KEY_ZOOMIN },
+	{ 0x46, KEY_ZOOMOUT },
+	{ 0x18, KEY_RED },		/* Red */
+	{ 0x53, KEY_GREEN },		/* Green */
+	{ 0x5e, KEY_YELLOW },		/* Yellow */
+	{ 0x5f, KEY_BLUE },		/* Blue */
+};
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties megasky_properties;
+static struct dvb_usb_device_properties digivox_mini_ii_properties;
+static struct dvb_usb_device_properties tvwalkertwin_properties;
+static struct dvb_usb_device_properties dposh_properties;
+static struct dvb_usb_device_properties pinnacle_pctv310e_properties;
+
+static int m920x_probe(struct usb_interface *intf,
+		       const struct usb_device_id *id)
+{
+	struct dvb_usb_device *d = NULL;
+	int ret;
+	struct m920x_inits *rc_init_seq = NULL;
+	int bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber;
+
+	deb("Probing for m920x device at interface %d\n", bInterfaceNumber);
+
+	if (bInterfaceNumber == 0) {
+		/* Single-tuner device, or first interface on
+		 * multi-tuner device
+		 */
+
+		ret = dvb_usb_device_init(intf, &megasky_properties,
+					  THIS_MODULE, &d, adapter_nr);
+		if (ret == 0) {
+			rc_init_seq = megasky_rc_init;
+			goto found;
+		}
+
+		ret = dvb_usb_device_init(intf, &digivox_mini_ii_properties,
+					  THIS_MODULE, &d, adapter_nr);
+		if (ret == 0) {
+			/* No remote control, so no rc_init_seq */
+			goto found;
+		}
+
+		/* This configures both tuners on the TV Walker Twin */
+		ret = dvb_usb_device_init(intf, &tvwalkertwin_properties,
+					  THIS_MODULE, &d, adapter_nr);
+		if (ret == 0) {
+			rc_init_seq = tvwalkertwin_rc_init;
+			goto found;
+		}
+
+		ret = dvb_usb_device_init(intf, &dposh_properties,
+					  THIS_MODULE, &d, adapter_nr);
+		if (ret == 0) {
+			/* Remote controller not supported yet. */
+			goto found;
+		}
+
+		ret = dvb_usb_device_init(intf, &pinnacle_pctv310e_properties,
+					  THIS_MODULE, &d, adapter_nr);
+		if (ret == 0) {
+			rc_init_seq = pinnacle310e_init;
+			goto found;
+		}
+
+		return ret;
+	} else {
+		/* Another interface on a multi-tuner device */
+
+		/* The LifeView TV Walker Twin gets here, but struct
+		 * tvwalkertwin_properties already configured both
+		 * tuners, so there is nothing for us to do here
+		 */
+	}
+
+ found:
+	if ((ret = m920x_init_ep(intf)) < 0)
+		return ret;
+
+	if (d && (ret = m920x_init(d, rc_init_seq)) != 0)
+		return ret;
+
+	return ret;
+}
+
+static struct usb_device_id m920x_table [] = {
+		{ USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) },
+		{ USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC,
+			     USB_PID_MSI_DIGI_VOX_MINI_II) },
+		{ USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC,
+			     USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD) },
+		{ USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC,
+			     USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM) },
+		{ USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_COLD) },
+		{ USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_WARM) },
+		{ USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_PINNACLE_PCTV310E) },
+		{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, m920x_table);
+
+static struct dvb_usb_device_properties megasky_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.firmware = "dvb-usb-megasky-02.fw",
+	.download_firmware = m920x_firmware_download,
+
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_map_table     = rc_map_megasky_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_megasky_table),
+		.rc_query         = m920x_rc_query,
+	},
+
+	.size_of_priv     = sizeof(struct m920x_state),
+
+	.identify_state   = m920x_identify_state,
+	.num_adapters = 1,
+	.adapter = {{
+		.num_frontends = 1,
+		.fe = {{
+
+		.caps = DVB_USB_ADAP_HAS_PID_FILTER |
+			DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+		.pid_filter_count = 8,
+		.pid_filter       = m920x_pid_filter,
+		.pid_filter_ctrl  = m920x_pid_filter_ctrl,
+
+		.frontend_attach  = m920x_mt352_frontend_attach,
+		.tuner_attach     = m920x_qt1010_tuner_attach,
+
+		.stream = {
+			.type = USB_BULK,
+			.count = 8,
+			.endpoint = 0x81,
+			.u = {
+				.bulk = {
+					.buffersize = 512,
+				}
+			}
+		},
+		}},
+	}},
+	.i2c_algo         = &m920x_i2c_algo,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "MSI Mega Sky 580 DVB-T USB2.0",
+			{ &m920x_table[0], NULL },
+			{ NULL },
+		}
+	}
+};
+
+static struct dvb_usb_device_properties digivox_mini_ii_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.firmware = "dvb-usb-digivox-02.fw",
+	.download_firmware = m920x_firmware_download,
+
+	.size_of_priv     = sizeof(struct m920x_state),
+
+	.identify_state   = m920x_identify_state,
+	.num_adapters = 1,
+	.adapter = {{
+		.num_frontends = 1,
+		.fe = {{
+
+		.caps = DVB_USB_ADAP_HAS_PID_FILTER |
+			DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+		.pid_filter_count = 8,
+		.pid_filter       = m920x_pid_filter,
+		.pid_filter_ctrl  = m920x_pid_filter_ctrl,
+
+		.frontend_attach  = m920x_tda10046_08_frontend_attach,
+		.tuner_attach     = m920x_tda8275_60_tuner_attach,
+
+		.stream = {
+			.type = USB_BULK,
+			.count = 8,
+			.endpoint = 0x81,
+			.u = {
+				.bulk = {
+					.buffersize = 0x4000,
+				}
+			}
+		},
+		}},
+	}},
+	.i2c_algo         = &m920x_i2c_algo,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "MSI DIGI VOX mini II DVB-T USB2.0",
+			{ &m920x_table[1], NULL },
+			{ NULL },
+		},
+	}
+};
+
+/* LifeView TV Walker Twin support by Nick Andrew <nick@nick-andrew.net>
+ *
+ * LifeView TV Walker Twin has 1 x M9206, 2 x TDA10046, 2 x TDA8275A
+ * TDA10046 #0 is located at i2c address 0x08
+ * TDA10046 #1 is located at i2c address 0x0b
+ * TDA8275A #0 is located at i2c address 0x60
+ * TDA8275A #1 is located at i2c address 0x61
+ */
+static struct dvb_usb_device_properties tvwalkertwin_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.firmware = "dvb-usb-tvwalkert.fw",
+	.download_firmware = m920x_firmware_download,
+
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_map_table     = rc_map_tvwalkertwin_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_tvwalkertwin_table),
+		.rc_query         = m920x_rc_query,
+	},
+
+	.size_of_priv     = sizeof(struct m920x_state),
+
+	.identify_state   = m920x_identify_state,
+	.num_adapters = 2,
+	.adapter = {{
+		.num_frontends = 1,
+		.fe = {{
+
+		.caps = DVB_USB_ADAP_HAS_PID_FILTER |
+			DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+		.pid_filter_count = 8,
+		.pid_filter       = m920x_pid_filter,
+		.pid_filter_ctrl  = m920x_pid_filter_ctrl,
+
+		.frontend_attach  = m920x_tda10046_08_frontend_attach,
+		.tuner_attach     = m920x_tda8275_60_tuner_attach,
+
+		.stream = {
+			.type = USB_BULK,
+			.count = 8,
+			.endpoint = 0x81,
+			.u = {
+				 .bulk = {
+					 .buffersize = 512,
+				 }
+			}
+		}},
+		}},{
+		.num_frontends = 1,
+		.fe = {{
+
+		.caps = DVB_USB_ADAP_HAS_PID_FILTER |
+			DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+		.pid_filter_count = 8,
+		.pid_filter       = m920x_pid_filter,
+		.pid_filter_ctrl  = m920x_pid_filter_ctrl,
+
+		.frontend_attach  = m920x_tda10046_0b_frontend_attach,
+		.tuner_attach     = m920x_tda8275_61_tuner_attach,
+
+		.stream = {
+			.type = USB_BULK,
+			.count = 8,
+			.endpoint = 0x82,
+			.u = {
+				 .bulk = {
+					 .buffersize = 512,
+				 }
+			}
+		}},
+		},
+	}},
+	.i2c_algo         = &m920x_i2c_algo,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   .name = "LifeView TV Walker Twin DVB-T USB2.0",
+		    .cold_ids = { &m920x_table[2], NULL },
+		    .warm_ids = { &m920x_table[3], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties dposh_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.firmware = "dvb-usb-dposh-01.fw",
+	.download_firmware = m920x_firmware_download,
+
+	.size_of_priv     = sizeof(struct m920x_state),
+
+	.identify_state   = m920x_identify_state,
+	.num_adapters = 1,
+	.adapter = {{
+		.num_frontends = 1,
+		.fe = {{
+		/* Hardware pid filters don't work with this device/firmware */
+
+		.frontend_attach  = m920x_mt352_frontend_attach,
+		.tuner_attach     = m920x_qt1010_tuner_attach,
+
+		.stream = {
+			.type = USB_BULK,
+			.count = 8,
+			.endpoint = 0x81,
+			.u = {
+				 .bulk = {
+					 .buffersize = 512,
+				 }
+			}
+		},
+		}},
+	}},
+	.i2c_algo         = &m920x_i2c_algo,
+
+	.num_device_descs = 1,
+	.devices = {
+		 {   .name = "Dposh DVB-T USB2.0",
+		     .cold_ids = { &m920x_table[4], NULL },
+		     .warm_ids = { &m920x_table[5], NULL },
+		 },
+	 }
+};
+
+static struct dvb_usb_device_properties pinnacle_pctv310e_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.download_firmware = NULL,
+
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_map_table     = rc_map_pinnacle310e_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_pinnacle310e_table),
+		.rc_query         = m920x_rc_query,
+	},
+
+	.size_of_priv     = sizeof(struct m920x_state),
+
+	.identify_state   = m920x_identify_state,
+	.num_adapters = 1,
+	.adapter = {{
+		.num_frontends = 1,
+		.fe = {{
+
+		.caps = DVB_USB_ADAP_HAS_PID_FILTER |
+			DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+		.pid_filter_count = 8,
+		.pid_filter       = m920x_pid_filter,
+		.pid_filter_ctrl  = m920x_pid_filter_ctrl,
+
+		.frontend_attach  = m920x_mt352_frontend_attach,
+		.tuner_attach     = m920x_fmd1216me_tuner_attach,
+
+		.stream = {
+			.type = USB_ISOC,
+			.count = 5,
+			.endpoint = 0x84,
+			.u = {
+				.isoc = {
+					.framesperurb = 128,
+					.framesize = 564,
+					.interval = 1,
+				}
+			}
+		},
+		}},
+	} },
+	.i2c_algo         = &m920x_i2c_algo,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "Pinnacle PCTV 310e",
+			{ &m920x_table[6], NULL },
+			{ NULL },
+		}
+	}
+};
+
+static struct usb_driver m920x_driver = {
+	.name		= "dvb_usb_m920x",
+	.probe		= m920x_probe,
+	.disconnect	= dvb_usb_device_exit,
+	.id_table	= m920x_table,
+};
+
+module_usb_driver(m920x_driver);
+
+MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
+MODULE_DESCRIPTION("DVB Driver for ULI M920x");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/usb/dvb-usb/m920x.h b/drivers/media/usb/dvb-usb/m920x.h
new file mode 100644
index 0000000..3c06151
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/m920x.h
@@ -0,0 +1,77 @@
+#ifndef _DVB_USB_M920X_H_
+#define _DVB_USB_M920X_H_
+
+#define DVB_USB_LOG_PREFIX "m920x"
+#include "dvb-usb.h"
+
+#define deb(args...)   dprintk(dvb_usb_m920x_debug,0x01,args)
+
+#define M9206_CORE	0x22
+#define M9206_RC_STATE	0xff51
+#define M9206_RC_KEY	0xff52
+#define M9206_RC_INIT1	0xff54
+#define M9206_RC_INIT2	0xff55
+#define M9206_FW_GO	0xff69
+
+#define M9206_I2C	0x23
+#define M9206_FILTER	0x25
+#define M9206_FW	0x30
+
+#define M9206_MAX_FILTERS 8
+#define M9206_MAX_ADAPTERS 4
+
+/*
+sequences found in logs:
+[index value]
+0x80 write addr
+(0x00 out byte)*
+0x40 out byte
+
+0x80 write addr
+(0x00 out byte)*
+0x80 read addr
+(0x21 in byte)*
+0x60 in byte
+
+this sequence works:
+0x80 read addr
+(0x21 in byte)*
+0x60 in byte
+
+Guess at API of the I2C function:
+I2C operation is done one byte at a time with USB control messages.  The
+index the messages is sent to is made up of a set of flags that control
+the I2C bus state:
+0x80:  Send START condition.  After a START condition, one would normally
+       always send the 7-bit slave I2C address as the 7 MSB, followed by
+       the read/write bit as the LSB.
+0x40:  Send STOP condition.  This should be set on the last byte of an
+       I2C transaction.
+0x20:  Read a byte from the slave.  As opposed to writing a byte to the
+       slave.  The slave will normally not produce any data unless you
+       set the R/W bit to 1 when sending the slave's address after the
+       START condition.
+0x01:  Respond with ACK, as opposed to a NACK.  For a multi-byte read,
+       the master should send an ACK, that is pull SDA low during the 9th
+       clock cycle, after every byte but the last.  This flags only makes
+       sense when bit 0x20 is set, indicating a read.
+
+What any other bits might mean, or how to get the slave's ACK/NACK
+response to a write, is unknown.
+*/
+
+struct m920x_state {
+	u16 filters[M9206_MAX_ADAPTERS][M9206_MAX_FILTERS];
+	int filtering_enabled[M9206_MAX_ADAPTERS];
+	int rep_count;
+};
+
+/* Initialisation data for the m920x
+ */
+
+struct m920x_inits {
+	u16 address;
+	u8  data;
+};
+
+#endif
diff --git a/drivers/media/usb/dvb-usb/nova-t-usb2.c b/drivers/media/usb/dvb-usb/nova-t-usb2.c
new file mode 100644
index 0000000..6c55384
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/nova-t-usb2.c
@@ -0,0 +1,233 @@
+/* DVB USB framework compliant Linux driver for the Hauppauge WinTV-NOVA-T usb2
+ * DVB-T receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the Free
+ *	Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc,2=eeprom (|-able))." DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define deb_rc(args...) dprintk(debug,0x01,args)
+#define deb_ee(args...) dprintk(debug,0x02,args)
+
+/* Hauppauge NOVA-T USB2 keys */
+static struct rc_map_table rc_map_haupp_table[] = {
+	{ 0x1e00, KEY_0 },
+	{ 0x1e01, KEY_1 },
+	{ 0x1e02, KEY_2 },
+	{ 0x1e03, KEY_3 },
+	{ 0x1e04, KEY_4 },
+	{ 0x1e05, KEY_5 },
+	{ 0x1e06, KEY_6 },
+	{ 0x1e07, KEY_7 },
+	{ 0x1e08, KEY_8 },
+	{ 0x1e09, KEY_9 },
+	{ 0x1e0a, KEY_KPASTERISK },
+	{ 0x1e0b, KEY_RED },
+	{ 0x1e0c, KEY_RADIO },
+	{ 0x1e0d, KEY_MENU },
+	{ 0x1e0e, KEY_GRAVE }, /* # */
+	{ 0x1e0f, KEY_MUTE },
+	{ 0x1e10, KEY_VOLUMEUP },
+	{ 0x1e11, KEY_VOLUMEDOWN },
+	{ 0x1e12, KEY_CHANNEL },
+	{ 0x1e14, KEY_UP },
+	{ 0x1e15, KEY_DOWN },
+	{ 0x1e16, KEY_LEFT },
+	{ 0x1e17, KEY_RIGHT },
+	{ 0x1e18, KEY_VIDEO },
+	{ 0x1e19, KEY_AUDIO },
+	{ 0x1e1a, KEY_IMAGES },
+	{ 0x1e1b, KEY_EPG },
+	{ 0x1e1c, KEY_TV },
+	{ 0x1e1e, KEY_NEXT },
+	{ 0x1e1f, KEY_BACK },
+	{ 0x1e20, KEY_CHANNELUP },
+	{ 0x1e21, KEY_CHANNELDOWN },
+	{ 0x1e24, KEY_LAST }, /* Skip backwards */
+	{ 0x1e25, KEY_OK },
+	{ 0x1e29, KEY_BLUE},
+	{ 0x1e2e, KEY_GREEN },
+	{ 0x1e30, KEY_PAUSE },
+	{ 0x1e32, KEY_REWIND },
+	{ 0x1e34, KEY_FASTFORWARD },
+	{ 0x1e35, KEY_PLAY },
+	{ 0x1e36, KEY_STOP },
+	{ 0x1e37, KEY_RECORD },
+	{ 0x1e38, KEY_YELLOW },
+	{ 0x1e3b, KEY_GOTO },
+	{ 0x1e3d, KEY_POWER },
+};
+
+/* Firmware bug? sometimes, when a new key is pressed, the previous pressed key
+ * is delivered. No workaround yet, maybe a new firmware.
+ */
+static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	u8 key[5],cmd[2] = { DIBUSB_REQ_POLL_REMOTE, 0x35 }, data,toggle,custom;
+	u16 raw;
+	int i;
+	struct dibusb_device_state *st = d->priv;
+
+	dvb_usb_generic_rw(d,cmd,2,key,5,0);
+
+	*state = REMOTE_NO_KEY_PRESSED;
+	switch (key[0]) {
+		case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED:
+			raw = ((key[1] << 8) | key[2]) >> 3;
+			toggle = !!(raw & 0x800);
+			data = raw & 0x3f;
+			custom = (raw >> 6) & 0x1f;
+
+			deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle);
+
+			for (i = 0; i < ARRAY_SIZE(rc_map_haupp_table); i++) {
+				if (rc5_data(&rc_map_haupp_table[i]) == data &&
+					rc5_custom(&rc_map_haupp_table[i]) == custom) {
+
+					deb_rc("c: %x, d: %x\n", rc5_data(&rc_map_haupp_table[i]),
+								 rc5_custom(&rc_map_haupp_table[i]));
+
+					*event = rc_map_haupp_table[i].keycode;
+					*state = REMOTE_KEY_PRESSED;
+					if (st->old_toggle == toggle) {
+						if (st->last_repeat_count++ < 2)
+							*state = REMOTE_NO_KEY_PRESSED;
+					} else {
+						st->last_repeat_count = 0;
+						st->old_toggle = toggle;
+					}
+					break;
+				}
+			}
+
+			break;
+		case DIBUSB_RC_HAUPPAUGE_KEY_EMPTY:
+		default:
+			break;
+	}
+
+	return 0;
+}
+
+static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6])
+{
+	int i;
+	u8 b;
+
+	mac[0] = 0x00;
+	mac[1] = 0x0d;
+	mac[2] = 0xfe;
+
+	/* this is a complete guess, but works for my box */
+	for (i = 136; i < 139; i++) {
+		dibusb_read_eeprom_byte(d,i, &b);
+
+		mac[5 - (i - 136)] = b;
+	}
+
+	return 0;
+}
+
+/* USB Driver stuff */
+static struct dvb_usb_device_properties nova_t_properties;
+
+static int nova_t_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	return dvb_usb_device_init(intf, &nova_t_properties,
+				   THIS_MODULE, NULL, adapter_nr);
+}
+
+/* do not change the order of the ID table */
+static struct usb_device_id nova_t_table [] = {
+/* 00 */	{ USB_DEVICE(USB_VID_HAUPPAUGE,     USB_PID_WINTV_NOVA_T_USB2_COLD) },
+/* 01 */	{ USB_DEVICE(USB_VID_HAUPPAUGE,     USB_PID_WINTV_NOVA_T_USB2_WARM) },
+			{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, nova_t_table);
+
+static struct dvb_usb_device_properties nova_t_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-nova-t-usb2-02.fw",
+
+	.num_adapters     = 1,
+	.adapter          = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+			.pid_filter_count = 32,
+
+			.streaming_ctrl   = dibusb2_0_streaming_ctrl,
+			.pid_filter       = dibusb_pid_filter,
+			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+			.frontend_attach  = dibusb_dib3000mc_frontend_attach,
+			.tuner_attach     = dibusb_dib3000mc_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+					.stream = {
+						.type = USB_BULK,
+				.count = 7,
+				.endpoint = 0x06,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+			.size_of_priv     = sizeof(struct dibusb_state),
+		}
+	},
+	.size_of_priv     = sizeof(struct dibusb_device_state),
+
+	.power_ctrl       = dibusb2_0_power_ctrl,
+	.read_mac_address = nova_t_read_mac_address,
+
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_map_table     = rc_map_haupp_table,
+		.rc_map_size      = ARRAY_SIZE(rc_map_haupp_table),
+		.rc_query         = nova_t_rc_query,
+	},
+
+	.i2c_algo         = &dibusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "Hauppauge WinTV-NOVA-T usb2",
+			{ &nova_t_table[0], NULL },
+			{ &nova_t_table[1], NULL },
+		},
+		{ NULL },
+	}
+};
+
+static struct usb_driver nova_t_driver = {
+	.name		= "dvb_usb_nova_t_usb2",
+	.probe		= nova_t_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table	= nova_t_table,
+};
+
+module_usb_driver(nova_t_driver);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Hauppauge WinTV-NOVA-T usb2");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/opera1.c b/drivers/media/usb/dvb-usb/opera1.c
new file mode 100644
index 0000000..c8a9504
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/opera1.c
@@ -0,0 +1,583 @@
+/* DVB USB framework compliant Linux driver for the Opera1 DVB-S Card
+*
+* Copyright (C) 2006 Mario Hlawitschka (dh1pa@amsat.org)
+* Copyright (C) 2006 Marco Gittler (g.marco@freenet.de)
+*
+*	This program is free software; you can redistribute it and/or modify it
+*	under the terms of the GNU General Public License as published by the Free
+*	Software Foundation, version 2.
+*
+* see Documentation/dvb/README.dvb-usb for more information
+*/
+
+#define DVB_USB_LOG_PREFIX "opera"
+
+#include "dvb-usb.h"
+#include "stv0299.h"
+
+#define OPERA_READ_MSG 0
+#define OPERA_WRITE_MSG 1
+#define OPERA_I2C_TUNER 0xd1
+
+#define READ_FX2_REG_REQ  0xba
+#define READ_MAC_ADDR 0x08
+#define OPERA_WRITE_FX2 0xbb
+#define OPERA_TUNER_REQ 0xb1
+#define REG_1F_SYMBOLRATE_BYTE0 0x1f
+#define REG_20_SYMBOLRATE_BYTE1 0x20
+#define REG_21_SYMBOLRATE_BYTE2 0x21
+
+#define ADDR_B600_VOLTAGE_13V (0x02)
+#define ADDR_B601_VOLTAGE_18V (0x03)
+#define ADDR_B1A6_STREAM_CTRL (0x04)
+#define ADDR_B880_READ_REMOTE (0x05)
+
+struct opera1_state {
+	u32 last_key_pressed;
+};
+struct rc_map_opera_table {
+	u32 keycode;
+	u32 event;
+};
+
+static int dvb_usb_opera1_debug;
+module_param_named(debug, dvb_usb_opera1_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+		 "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))."
+		 DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+
+static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value,
+			    u8 * data, u16 len, int flags)
+{
+	int ret;
+	u8 tmp;
+	u8 *buf;
+	unsigned int pipe = (flags == OPERA_READ_MSG) ?
+		usb_rcvctrlpipe(dev,0) : usb_sndctrlpipe(dev, 0);
+	u8 request_type = (flags == OPERA_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
+
+	buf = kmalloc(len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (flags == OPERA_WRITE_MSG)
+		memcpy(buf, data, len);
+	ret = usb_control_msg(dev, pipe, request,
+			request_type | USB_TYPE_VENDOR, value, 0x0,
+			buf, len, 2000);
+
+	if (request == OPERA_TUNER_REQ) {
+		tmp = buf[0];
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+			    OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR,
+			    0x01, 0x0, buf, 1, 2000) < 1 || buf[0] != 0x08) {
+			ret = 0;
+			goto out;
+		}
+		buf[0] = tmp;
+	}
+	if (flags == OPERA_READ_MSG)
+		memcpy(data, buf, len);
+out:
+	kfree(buf);
+	return ret;
+}
+
+/* I2C */
+
+static int opera1_usb_i2c_msgxfer(struct dvb_usb_device *dev, u16 addr,
+				  u8 * buf, u16 len)
+{
+	int ret = 0;
+	u8 request;
+	u16 value;
+
+	if (!dev) {
+		info("no usb_device");
+		return -EINVAL;
+	}
+	if (mutex_lock_interruptible(&dev->usb_mutex) < 0)
+		return -EAGAIN;
+
+	switch (addr>>1){
+		case ADDR_B600_VOLTAGE_13V:
+			request=0xb6;
+			value=0x00;
+			break;
+		case ADDR_B601_VOLTAGE_18V:
+			request=0xb6;
+			value=0x01;
+			break;
+		case ADDR_B1A6_STREAM_CTRL:
+			request=0xb1;
+			value=0xa6;
+			break;
+		case ADDR_B880_READ_REMOTE:
+			request=0xb8;
+			value=0x80;
+			break;
+		default:
+			request=0xb1;
+			value=addr;
+	}
+	ret = opera1_xilinx_rw(dev->udev, request,
+		value, buf, len,
+		addr&0x01?OPERA_READ_MSG:OPERA_WRITE_MSG);
+
+	mutex_unlock(&dev->usb_mutex);
+	return ret;
+}
+
+static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+			   int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int i = 0, tmp = 0;
+
+	if (!d)
+		return -ENODEV;
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		if ((tmp = opera1_usb_i2c_msgxfer(d,
+					(msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0),
+					msg[i].buf,
+					msg[i].len
+					)) != msg[i].len) {
+			break;
+		}
+		if (dvb_usb_opera1_debug & 0x10)
+			info("sending i2c mesage %d %d", tmp, msg[i].len);
+	}
+	mutex_unlock(&d->i2c_mutex);
+	return num;
+}
+
+static u32 opera1_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm opera1_i2c_algo = {
+	.master_xfer = opera1_i2c_xfer,
+	.functionality = opera1_i2c_func,
+};
+
+static int opera1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	static u8 command_13v[1]={0x00};
+	static u8 command_18v[1]={0x01};
+	struct i2c_msg msg[] = {
+		{.addr = ADDR_B600_VOLTAGE_13V,.flags = 0,.buf = command_13v,.len = 1},
+	};
+	struct dvb_usb_adapter *udev_adap =
+	    (struct dvb_usb_adapter *)(fe->dvb->priv);
+	if (voltage == SEC_VOLTAGE_18) {
+		msg[0].addr = ADDR_B601_VOLTAGE_18V;
+		msg[0].buf = command_18v;
+	}
+	i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
+	return 0;
+}
+
+static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate,
+					  u32 ratio)
+{
+	stv0299_writereg(fe, 0x13, 0x98);
+	stv0299_writereg(fe, 0x14, 0x95);
+	stv0299_writereg(fe, REG_1F_SYMBOLRATE_BYTE0, (ratio >> 16) & 0xff);
+	stv0299_writereg(fe, REG_20_SYMBOLRATE_BYTE1, (ratio >> 8) & 0xff);
+	stv0299_writereg(fe, REG_21_SYMBOLRATE_BYTE2, (ratio) & 0xf0);
+	return 0;
+
+}
+static u8 opera1_inittab[] = {
+	0x00, 0xa1,
+	0x01, 0x15,
+	0x02, 0x30,
+	0x03, 0x00,
+	0x04, 0x7d,
+	0x05, 0x05,
+	0x06, 0x02,
+	0x07, 0x00,
+	0x0b, 0x00,
+	0x0c, 0x01,
+	0x0d, 0x81,
+	0x0e, 0x44,
+	0x0f, 0x19,
+	0x10, 0x3f,
+	0x11, 0x84,
+	0x12, 0xda,
+	0x13, 0x98,
+	0x14, 0x95,
+	0x15, 0xc9,
+	0x16, 0xeb,
+	0x17, 0x00,
+	0x18, 0x19,
+	0x19, 0x8b,
+	0x1a, 0x00,
+	0x1b, 0x82,
+	0x1c, 0x7f,
+	0x1d, 0x00,
+	0x1e, 0x00,
+	REG_1F_SYMBOLRATE_BYTE0, 0x06,
+	REG_20_SYMBOLRATE_BYTE1, 0x50,
+	REG_21_SYMBOLRATE_BYTE2, 0x10,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x24, 0x37,
+	0x25, 0xbc,
+	0x26, 0x00,
+	0x27, 0x00,
+	0x28, 0x00,
+	0x29, 0x1e,
+	0x2a, 0x14,
+	0x2b, 0x1f,
+	0x2c, 0x09,
+	0x2d, 0x0a,
+	0x2e, 0x00,
+	0x2f, 0x00,
+	0x30, 0x00,
+	0x31, 0x1f,
+	0x32, 0x19,
+	0x33, 0xfc,
+	0x34, 0x13,
+	0xff, 0xff,
+};
+
+static struct stv0299_config opera1_stv0299_config = {
+	.demod_address = 0xd0>>1,
+	.min_delay_ms = 100,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.skip_reinit = 0,
+	.lock_output = STV0299_LOCKOUTPUT_0,
+	.volt13_op0_op1 = STV0299_VOLT13_OP0,
+	.inittab = opera1_inittab,
+	.set_symbol_rate = opera1_stv0299_set_symbol_rate,
+};
+
+static int opera1_frontend_attach(struct dvb_usb_adapter *d)
+{
+	d->fe_adap[0].fe = dvb_attach(stv0299_attach, &opera1_stv0299_config,
+				      &d->dev->i2c_adap);
+	if ((d->fe_adap[0].fe) != NULL) {
+		d->fe_adap[0].fe->ops.set_voltage = opera1_set_voltage;
+		return 0;
+	}
+	info("not attached stv0299");
+	return -EIO;
+}
+
+static int opera1_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	dvb_attach(
+		dvb_pll_attach, adap->fe_adap[0].fe, 0xc0>>1,
+		&adap->dev->i2c_adap, DVB_PLL_OPERA1
+	);
+	return 0;
+}
+
+static int opera1_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	u8 val = onoff ? 0x01 : 0x00;
+
+	if (dvb_usb_opera1_debug)
+		info("power %s", onoff ? "on" : "off");
+	return opera1_xilinx_rw(d->udev, 0xb7, val,
+				&val, 1, OPERA_WRITE_MSG);
+}
+
+static int opera1_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	static u8 buf_start[2] = { 0xff, 0x03 };
+	static u8 buf_stop[2] = { 0xff, 0x00 };
+	struct i2c_msg start_tuner[] = {
+		{.addr = ADDR_B1A6_STREAM_CTRL,.buf = onoff ? buf_start : buf_stop,.len = 2},
+	};
+	if (dvb_usb_opera1_debug)
+		info("streaming %s", onoff ? "on" : "off");
+	i2c_transfer(&adap->dev->i2c_adap, start_tuner, 1);
+	return 0;
+}
+
+static int opera1_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+			     int onoff)
+{
+	u8 b_pid[3];
+	struct i2c_msg msg[] = {
+		{.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3},
+	};
+	if (dvb_usb_opera1_debug)
+		info("pidfilter index: %d pid: %d %s", index, pid,
+			onoff ? "on" : "off");
+	b_pid[0] = (2 * index) + 4;
+	b_pid[1] = onoff ? (pid & 0xff) : (0x00);
+	b_pid[2] = onoff ? ((pid >> 8) & 0xff) : (0x00);
+	i2c_transfer(&adap->dev->i2c_adap, msg, 1);
+	return 0;
+}
+
+static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
+{
+	int u = 0x04;
+	u8 b_pid[3];
+	struct i2c_msg msg[] = {
+		{.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3},
+	};
+	if (dvb_usb_opera1_debug)
+		info("%s hw-pidfilter", onoff ? "enable" : "disable");
+	for (; u < 0x7e; u += 2) {
+		b_pid[0] = u;
+		b_pid[1] = 0;
+		b_pid[2] = 0x80;
+		i2c_transfer(&adap->dev->i2c_adap, msg, 1);
+	}
+	return 0;
+}
+
+static struct rc_map_table rc_map_opera1_table[] = {
+	{0x5fa0, KEY_1},
+	{0x51af, KEY_2},
+	{0x5da2, KEY_3},
+	{0x41be, KEY_4},
+	{0x0bf5, KEY_5},
+	{0x43bd, KEY_6},
+	{0x47b8, KEY_7},
+	{0x49b6, KEY_8},
+	{0x05fa, KEY_9},
+	{0x45ba, KEY_0},
+	{0x09f6, KEY_CHANNELUP},	/*chanup */
+	{0x1be5, KEY_CHANNELDOWN},	/*chandown */
+	{0x5da3, KEY_VOLUMEDOWN},	/*voldown */
+	{0x5fa1, KEY_VOLUMEUP},		/*volup */
+	{0x07f8, KEY_SPACE},		/*tab */
+	{0x1fe1, KEY_OK},		/*play ok */
+	{0x1be4, KEY_ZOOM},		/*zoom */
+	{0x59a6, KEY_MUTE},		/*mute */
+	{0x5ba5, KEY_RADIO},		/*tv/f */
+	{0x19e7, KEY_RECORD},		/*rec */
+	{0x01fe, KEY_STOP},		/*Stop */
+	{0x03fd, KEY_PAUSE},		/*pause */
+	{0x03fc, KEY_SCREEN},		/*<- -> */
+	{0x07f9, KEY_CAMERA},		/*capture */
+	{0x47b9, KEY_ESC},		/*exit */
+	{0x43bc, KEY_POWER2},		/*power */
+};
+
+static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state)
+{
+	struct opera1_state *opst = dev->priv;
+	u8 rcbuffer[32];
+	const u16 startmarker1 = 0x10ed;
+	const u16 startmarker2 = 0x11ec;
+	struct i2c_msg read_remote[] = {
+		{.addr = ADDR_B880_READ_REMOTE,.buf = rcbuffer,.flags = I2C_M_RD,.len = 32},
+	};
+	int i = 0;
+	u32 send_key = 0;
+
+	if (i2c_transfer(&dev->i2c_adap, read_remote, 1) == 1) {
+		for (i = 0; i < 32; i++) {
+			if (rcbuffer[i])
+				send_key |= 1;
+			if (i < 31)
+				send_key = send_key << 1;
+		}
+		if (send_key & 0x8000)
+			send_key = (send_key << 1) | (send_key >> 15 & 0x01);
+
+		if (send_key == 0xffff && opst->last_key_pressed != 0) {
+			*state = REMOTE_KEY_REPEAT;
+			*event = opst->last_key_pressed;
+			return 0;
+		}
+		for (; send_key != 0;) {
+			if (send_key >> 16 == startmarker2) {
+				break;
+			} else if (send_key >> 16 == startmarker1) {
+				send_key =
+					(send_key & 0xfffeffff) | (startmarker1 << 16);
+				break;
+			} else
+				send_key >>= 1;
+		}
+
+		if (send_key == 0)
+			return 0;
+
+		send_key = (send_key & 0xffff) | 0x0100;
+
+		for (i = 0; i < ARRAY_SIZE(rc_map_opera1_table); i++) {
+			if (rc5_scan(&rc_map_opera1_table[i]) == (send_key & 0xffff)) {
+				*state = REMOTE_KEY_PRESSED;
+				*event = rc_map_opera1_table[i].keycode;
+				opst->last_key_pressed =
+					rc_map_opera1_table[i].keycode;
+				break;
+			}
+			opst->last_key_pressed = 0;
+		}
+	} else
+		*state = REMOTE_NO_KEY_PRESSED;
+	return 0;
+}
+
+static struct usb_device_id opera1_table[] = {
+	{USB_DEVICE(USB_VID_CYPRESS, USB_PID_OPERA1_COLD)},
+	{USB_DEVICE(USB_VID_OPERA1, USB_PID_OPERA1_WARM)},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, opera1_table);
+
+static int opera1_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+	u8 command[] = { READ_MAC_ADDR };
+	opera1_xilinx_rw(d->udev, 0xb1, 0xa0, command, 1, OPERA_WRITE_MSG);
+	opera1_xilinx_rw(d->udev, 0xb1, 0xa1, mac, 6, OPERA_READ_MSG);
+	return 0;
+}
+static int opera1_xilinx_load_firmware(struct usb_device *dev,
+				       const char *filename)
+{
+	const struct firmware *fw = NULL;
+	u8 *b, *p;
+	int ret = 0, i,fpgasize=40;
+	u8 testval;
+	info("start downloading fpga firmware %s",filename);
+
+	if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) {
+		err("did not find the firmware file. (%s) "
+			"Please see linux/Documentation/dvb/ for more details on firmware-problems.",
+			filename);
+		return ret;
+	} else {
+		p = kmalloc(fw->size, GFP_KERNEL);
+		opera1_xilinx_rw(dev, 0xbc, 0x00, &testval, 1, OPERA_READ_MSG);
+		if (p != NULL && testval != 0x67) {
+
+			u8 reset = 0, fpga_command = 0;
+			memcpy(p, fw->data, fw->size);
+			/* clear fpga ? */
+			opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1,
+					 OPERA_WRITE_MSG);
+			for (i = 0; i < fw->size;) {
+				if ( (fw->size - i) <fpgasize){
+				    fpgasize=fw->size-i;
+				}
+				b = (u8 *) p + i;
+				if (opera1_xilinx_rw
+					(dev, OPERA_WRITE_FX2, 0x0, b , fpgasize,
+						OPERA_WRITE_MSG) != fpgasize
+					) {
+					err("error while transferring firmware");
+					ret = -EINVAL;
+					break;
+				}
+				i = i + fpgasize;
+			}
+			/* restart the CPU */
+			if (ret || opera1_xilinx_rw
+					(dev, 0xa0, 0xe600, &reset, 1,
+					OPERA_WRITE_MSG) != 1) {
+				err("could not restart the USB controller CPU.");
+				ret = -EINVAL;
+			}
+		}
+	}
+	kfree(p);
+	release_firmware(fw);
+	return ret;
+}
+
+static struct dvb_usb_device_properties opera1_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-opera-01.fw",
+	.size_of_priv = sizeof(struct opera1_state),
+
+	.power_ctrl = opera1_power_ctrl,
+	.i2c_algo = &opera1_i2c_algo,
+
+	.rc.legacy = {
+		.rc_map_table = rc_map_opera1_table,
+		.rc_map_size = ARRAY_SIZE(rc_map_opera1_table),
+		.rc_interval = 200,
+		.rc_query = opera1_rc_query,
+	},
+	.read_mac_address = opera1_read_mac_address,
+	.generic_bulk_ctrl_endpoint = 0x00,
+	/* parameter for the MPEG2-data transfer */
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.frontend_attach = opera1_frontend_attach,
+			.streaming_ctrl = opera1_streaming_ctrl,
+			.tuner_attach = opera1_tuner_attach,
+			.caps =
+				DVB_USB_ADAP_HAS_PID_FILTER |
+				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+			.pid_filter = opera1_pid_filter,
+			.pid_filter_ctrl = opera1_pid_filter_control,
+			.pid_filter_count = 252,
+			.stream = {
+				.type = USB_BULK,
+				.count = 10,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+		}
+	},
+	.num_device_descs = 1,
+	.devices = {
+		{"Opera1 DVB-S USB2.0",
+			{&opera1_table[0], NULL},
+			{&opera1_table[1], NULL},
+		},
+	}
+};
+
+static int opera1_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+
+	if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM &&
+		udev->descriptor.idVendor == USB_VID_OPERA1 &&
+		opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0
+	    ) {
+		return -EINVAL;
+	}
+
+	if (0 != dvb_usb_device_init(intf, &opera1_properties,
+				     THIS_MODULE, NULL, adapter_nr))
+		return -EINVAL;
+	return 0;
+}
+
+static struct usb_driver opera1_driver = {
+	.name = "opera1",
+	.probe = opera1_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table = opera1_table,
+};
+
+module_usb_driver(opera1_driver);
+
+MODULE_AUTHOR("Mario Hlawitschka (c) dh1pa@amsat.org");
+MODULE_AUTHOR("Marco Gittler (c) g.marco@freenet.de");
+MODULE_DESCRIPTION("Driver for Opera1 DVB-S device");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c
new file mode 100644
index 0000000..02e8785
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/pctv452e.c
@@ -0,0 +1,1063 @@
+/*
+ * PCTV 452e DVB driver
+ *
+ * Copyright (c) 2006-2008 Dominik Kuhlen <dkuhlen@gmx.net>
+ *
+ * TT connect S2-3650-CI Common Interface support, MAC readout
+ * Copyright (C) 2008 Michael H. Schimek <mschimek@gmx.at>
+ *
+ * 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.
+ */
+
+/* dvb usb framework */
+#define DVB_USB_LOG_PREFIX "pctv452e"
+#include "dvb-usb.h"
+
+/* Demodulator */
+#include "stb0899_drv.h"
+#include "stb0899_reg.h"
+#include "stb0899_cfg.h"
+/* Tuner */
+#include "stb6100.h"
+#include "stb6100_cfg.h"
+/* FE Power */
+#include "lnbp22.h"
+
+#include "dvb_ca_en50221.h"
+#include "ttpci-eeprom.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define ISOC_INTERFACE_ALTERNATIVE 3
+
+#define SYNC_BYTE_OUT 0xaa
+#define SYNC_BYTE_IN  0x55
+
+/* guessed: (copied from ttusb-budget) */
+#define PCTV_CMD_RESET 0x15
+/* command to poll IR receiver */
+#define PCTV_CMD_IR    0x1b
+/* command to send I2C  */
+#define PCTV_CMD_I2C   0x31
+
+#define I2C_ADDR_STB0899 (0xd0 >> 1)
+#define I2C_ADDR_STB6100 (0xc0 >> 1)
+#define I2C_ADDR_LNBP22  (0x10 >> 1)
+#define I2C_ADDR_24C16   (0xa0 >> 1)
+#define I2C_ADDR_24C64   (0xa2 >> 1)
+
+
+/* pctv452e sends us this amount of data for each issued usb-command */
+#define PCTV_ANSWER_LEN 64
+/* Wait up to 1000ms for device  */
+#define PCTV_TIMEOUT 1000
+
+
+#define PCTV_LED_GPIO   STB0899_GPIO01
+#define PCTV_LED_GREEN  0x82
+#define PCTV_LED_ORANGE 0x02
+
+#define ci_dbg(format, arg...)				\
+do {							\
+	if (0)						\
+		printk(KERN_DEBUG DVB_USB_LOG_PREFIX	\
+			": " format "\n" , ## arg);	\
+} while (0)
+
+enum {
+	TT3650_CMD_CI_TEST = 0x40,
+	TT3650_CMD_CI_RD_CTRL,
+	TT3650_CMD_CI_WR_CTRL,
+	TT3650_CMD_CI_RD_ATTR,
+	TT3650_CMD_CI_WR_ATTR,
+	TT3650_CMD_CI_RESET,
+	TT3650_CMD_CI_SET_VIDEO_PORT
+};
+
+
+static struct stb0899_postproc pctv45e_postproc[] = {
+	{ PCTV_LED_GPIO, STB0899_GPIOPULLUP },
+	{ 0, 0 }
+};
+
+/*
+ * stores all private variables for communication with the PCTV452e DVB-S2
+ */
+struct pctv452e_state {
+	struct dvb_ca_en50221 ca;
+	struct mutex ca_mutex;
+
+	u8 c;	   /* transaction counter, wraps around...  */
+	u8 initialized; /* set to 1 if 0x15 has been sent */
+	u16 last_rc_key;
+};
+
+static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data,
+			 unsigned int write_len, unsigned int read_len)
+{
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 buf[64];
+	u8 id;
+	unsigned int rlen;
+	int ret;
+
+	BUG_ON(NULL == data && 0 != (write_len | read_len));
+	BUG_ON(write_len > 64 - 4);
+	BUG_ON(read_len > 64 - 4);
+
+	id = state->c++;
+
+	buf[0] = SYNC_BYTE_OUT;
+	buf[1] = id;
+	buf[2] = cmd;
+	buf[3] = write_len;
+
+	memcpy(buf + 4, data, write_len);
+
+	rlen = (read_len > 0) ? 64 : 0;
+	ret = dvb_usb_generic_rw(d, buf, 4 + write_len,
+				  buf, rlen, /* delay_ms */ 0);
+	if (0 != ret)
+		goto failed;
+
+	ret = -EIO;
+	if (SYNC_BYTE_IN != buf[0] || id != buf[1])
+		goto failed;
+
+	memcpy(data, buf + 4, read_len);
+
+	return 0;
+
+failed:
+	err("CI error %d; %02X %02X %02X -> %*ph.",
+	     ret, SYNC_BYTE_OUT, id, cmd, 3, buf);
+
+	return ret;
+}
+
+static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca,
+				u8 cmd, u8 *data, unsigned int write_len,
+				unsigned int read_len)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	int ret;
+
+	mutex_lock(&state->ca_mutex);
+	ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
+	mutex_unlock(&state->ca_mutex);
+
+	return ret;
+}
+
+static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
+				 int slot, int address)
+{
+	u8 buf[3];
+	int ret;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = (address >> 8) & 0x0F;
+	buf[1] = address;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
+
+	ci_dbg("%s %04x -> %d 0x%02x",
+		__func__, address, ret, buf[2]);
+
+	if (ret < 0)
+		return ret;
+
+	return buf[2];
+}
+
+static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
+				 int slot, int address, u8 value)
+{
+	u8 buf[3];
+
+	ci_dbg("%s %d 0x%04x 0x%02x",
+		__func__, slot, address, value);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = (address >> 8) & 0x0F;
+	buf[1] = address;
+	buf[2] = value;
+
+	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
+}
+
+static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 u8			address)
+{
+	u8 buf[2];
+	int ret;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = address & 3;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
+
+	ci_dbg("%s 0x%02x -> %d 0x%02x",
+		__func__, address, ret, buf[1]);
+
+	if (ret < 0)
+		return ret;
+
+	return buf[1];
+}
+
+static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 u8			address,
+				 u8			value)
+{
+	u8 buf[2];
+
+	ci_dbg("%s %d 0x%02x 0x%02x",
+		__func__, slot, address, value);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = address;
+	buf[1] = value;
+
+	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
+}
+
+static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 int			enable)
+{
+	u8 buf[1];
+	int ret;
+
+	ci_dbg("%s %d %d", __func__, slot, enable);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	enable = !!enable;
+	buf[0] = enable;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
+	if (ret < 0)
+		return ret;
+
+	if (enable != buf[0]) {
+		err("CI not %sabled.", enable ? "en" : "dis");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+	return tt3650_ci_set_video_port(ca, slot, /* enable */ 0);
+}
+
+static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+	return tt3650_ci_set_video_port(ca, slot, /* enable */ 1);
+}
+
+static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 buf[1];
+	int ret;
+
+	ci_dbg("%s %d", __func__, slot);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = 0;
+
+	mutex_lock(&state->ca_mutex);
+
+	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
+	if (0 != ret)
+		goto failed;
+
+	msleep(500);
+
+	buf[0] = 1;
+
+	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
+	if (0 != ret)
+		goto failed;
+
+	msleep(500);
+
+	buf[0] = 0; /* FTA */
+
+	ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
+
+ failed:
+	mutex_unlock(&state->ca_mutex);
+
+	return ret;
+}
+
+static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 int			open)
+{
+	u8 buf[1];
+	int ret;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
+	if (0 != ret)
+		return ret;
+
+	if (1 == buf[0])
+		return DVB_CA_EN50221_POLL_CAM_PRESENT |
+			DVB_CA_EN50221_POLL_CAM_READY;
+
+	return 0;
+
+}
+
+static void tt3650_ci_uninit(struct dvb_usb_device *d)
+{
+	struct pctv452e_state *state;
+
+	ci_dbg("%s", __func__);
+
+	if (NULL == d)
+		return;
+
+	state = (struct pctv452e_state *)d->priv;
+	if (NULL == state)
+		return;
+
+	if (NULL == state->ca.data)
+		return;
+
+	/* Error ignored. */
+	tt3650_ci_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0);
+
+	dvb_ca_en50221_release(&state->ca);
+
+	memset(&state->ca, 0, sizeof(state->ca));
+}
+
+static int tt3650_ci_init(struct dvb_usb_adapter *a)
+{
+	struct dvb_usb_device *d = a->dev;
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	int ret;
+
+	ci_dbg("%s", __func__);
+
+	mutex_init(&state->ca_mutex);
+
+	state->ca.owner = THIS_MODULE;
+	state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
+	state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
+	state->ca.read_cam_control = tt3650_ci_read_cam_control;
+	state->ca.write_cam_control = tt3650_ci_write_cam_control;
+	state->ca.slot_reset = tt3650_ci_slot_reset;
+	state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
+	state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
+	state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
+	state->ca.data = d;
+
+	ret = dvb_ca_en50221_init(&a->dvb_adap,
+				   &state->ca,
+				   /* flags */ 0,
+				   /* n_slots */ 1);
+	if (0 != ret) {
+		err("Cannot initialize CI: Error %d.", ret);
+		memset(&state->ca, 0, sizeof(state->ca));
+		return ret;
+	}
+
+	info("CI initialized.");
+
+	return 0;
+}
+
+#define CMD_BUFFER_SIZE 0x28
+static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr,
+				const u8 *snd_buf, u8 snd_len,
+				u8 *rcv_buf, u8 rcv_len)
+{
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 buf[64];
+	u8 id;
+	int ret;
+
+	id = state->c++;
+
+	ret = -EINVAL;
+	if (snd_len > 64 - 7 || rcv_len > 64 - 7)
+		goto failed;
+
+	buf[0] = SYNC_BYTE_OUT;
+	buf[1] = id;
+	buf[2] = PCTV_CMD_I2C;
+	buf[3] = snd_len + 3;
+	buf[4] = addr << 1;
+	buf[5] = snd_len;
+	buf[6] = rcv_len;
+
+	memcpy(buf + 7, snd_buf, snd_len);
+
+	ret = dvb_usb_generic_rw(d, buf, 7 + snd_len,
+				  buf, /* rcv_len */ 64,
+				  /* delay_ms */ 0);
+	if (ret < 0)
+		goto failed;
+
+	/* TT USB protocol error. */
+	ret = -EIO;
+	if (SYNC_BYTE_IN != buf[0] || id != buf[1])
+		goto failed;
+
+	/* I2C device didn't respond as expected. */
+	ret = -EREMOTEIO;
+	if (buf[5] < snd_len || buf[6] < rcv_len)
+		goto failed;
+
+	memcpy(rcv_buf, buf + 7, rcv_len);
+
+	return rcv_len;
+
+failed:
+	err("I2C error %d; %02X %02X  %02X %02X %02X -> "
+	     "%02X %02X  %02X %02X %02X.",
+	     ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len,
+	     buf[0], buf[1], buf[4], buf[5], buf[6]);
+
+	return ret;
+}
+
+static int pctv452e_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg,
+				int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adapter);
+	int i;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf;
+		int ret;
+
+		if (msg[i].flags & I2C_M_RD) {
+			addr = msg[i].addr;
+			snd_buf = NULL;
+			snd_len = 0;
+			rcv_buf = msg[i].buf;
+			rcv_len = msg[i].len;
+		} else {
+			addr = msg[i].addr;
+			snd_buf = msg[i].buf;
+			snd_len = msg[i].len;
+			rcv_buf = NULL;
+			rcv_len = 0;
+		}
+
+		ret = pctv452e_i2c_msg(d, addr, snd_buf, snd_len, rcv_buf,
+					rcv_len);
+		if (ret < rcv_len)
+			break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return i;
+}
+
+static u32 pctv452e_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i)
+{
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 b0[] = { 0xaa, 0, PCTV_CMD_RESET, 1, 0 };
+	u8 rx[PCTV_ANSWER_LEN];
+	int ret;
+
+	info("%s: %d\n", __func__, i);
+
+	if (!i)
+		return 0;
+
+	if (state->initialized)
+		return 0;
+
+	/* hmm where shoud this should go? */
+	ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE);
+	if (ret != 0)
+		info("%s: Warning set interface returned: %d\n",
+			__func__, ret);
+
+	/* this is a one-time initialization, dont know where to put */
+	b0[1] = state->c++;
+	/* reset board */
+	ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0);
+	if (ret)
+		return ret;
+
+	b0[1] = state->c++;
+	b0[4] = 1;
+	/* reset board (again?) */
+	ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0);
+	if (ret)
+		return ret;
+
+	state->initialized = 1;
+
+	return 0;
+}
+
+static int pctv452e_rc_query(struct dvb_usb_device *d)
+{
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 b[CMD_BUFFER_SIZE];
+	u8 rx[PCTV_ANSWER_LEN];
+	int ret, i;
+	u8 id = state->c++;
+
+	/* prepare command header  */
+	b[0] = SYNC_BYTE_OUT;
+	b[1] = id;
+	b[2] = PCTV_CMD_IR;
+	b[3] = 0;
+
+	/* send ir request */
+	ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0);
+	if (ret != 0)
+		return ret;
+
+	if (debug > 3) {
+		info("%s: read: %2d: %*ph: ", __func__, ret, 3, rx);
+		for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++)
+			info(" %02x", rx[i+3]);
+
+		info("\n");
+	}
+
+	if ((rx[3] == 9) &&  (rx[12] & 0x01)) {
+		/* got a "press" event */
+		state->last_rc_key = (rx[7] << 8) | rx[6];
+		if (debug > 2)
+			info("%s: cmd=0x%02x sys=0x%02x\n",
+				__func__, rx[6], rx[7]);
+
+		rc_keydown(d->rc_dev, state->last_rc_key, 0);
+	} else if (state->last_rc_key) {
+		rc_keyup(d->rc_dev);
+		state->last_rc_key = 0;
+	}
+
+	return 0;
+}
+
+static int pctv452e_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+	const u8 mem_addr[] = { 0x1f, 0xcc };
+	u8 encoded_mac[20];
+	int ret;
+
+	ret = -EAGAIN;
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		goto failed;
+
+	ret = pctv452e_i2c_msg(d, I2C_ADDR_24C16,
+				mem_addr + 1, /* snd_len */ 1,
+				encoded_mac, /* rcv_len */ 20);
+	if (-EREMOTEIO == ret)
+		/* Caution! A 24C16 interprets 0xA2 0x1F 0xCC as a
+		   byte write if /WC is low. */
+		ret = pctv452e_i2c_msg(d, I2C_ADDR_24C64,
+					mem_addr, 2,
+					encoded_mac, 20);
+
+	mutex_unlock(&d->i2c_mutex);
+
+	if (20 != ret)
+		goto failed;
+
+	ret = ttpci_eeprom_decode_mac(mac, encoded_mac);
+	if (0 != ret)
+		goto failed;
+
+	return 0;
+
+failed:
+	memset(mac, 0, 6);
+
+	return ret;
+}
+
+static const struct stb0899_s1_reg pctv452e_init_dev[] = {
+	{ STB0899_DISCNTRL1,	0x26 },
+	{ STB0899_DISCNTRL2,	0x80 },
+	{ STB0899_DISRX_ST0,	0x04 },
+	{ STB0899_DISRX_ST1,	0x20 },
+	{ STB0899_DISPARITY,	0x00 },
+	{ STB0899_DISFIFO,	0x00 },
+	{ STB0899_DISF22,	0x99 },
+	{ STB0899_DISF22RX,	0x85 }, /* 0xa8 */
+	{ STB0899_ACRPRESC,	0x11 },
+	{ STB0899_ACRDIV1,	0x0a },
+	{ STB0899_ACRDIV2,	0x05 },
+	{ STB0899_DACR1	,	0x00 },
+	{ STB0899_DACR2	,	0x00 },
+	{ STB0899_OUTCFG,	0x00 },
+	{ STB0899_MODECFG,	0x00 }, /* Inversion */
+	{ STB0899_IRQMSK_3,	0xf3 },
+	{ STB0899_IRQMSK_2,	0xfc },
+	{ STB0899_IRQMSK_1,	0xff },
+	{ STB0899_IRQMSK_0,	0xff },
+	{ STB0899_I2CCFG,	0x88 },
+	{ STB0899_I2CRPT,	0x58 },
+	{ STB0899_GPIO00CFG,	0x82 },
+	{ STB0899_GPIO01CFG,	0x82 }, /* LED: 0x02 green, 0x82 orange */
+	{ STB0899_GPIO02CFG,	0x82 },
+	{ STB0899_GPIO03CFG,	0x82 },
+	{ STB0899_GPIO04CFG,	0x82 },
+	{ STB0899_GPIO05CFG,	0x82 },
+	{ STB0899_GPIO06CFG,	0x82 },
+	{ STB0899_GPIO07CFG,	0x82 },
+	{ STB0899_GPIO08CFG,	0x82 },
+	{ STB0899_GPIO09CFG,	0x82 },
+	{ STB0899_GPIO10CFG,	0x82 },
+	{ STB0899_GPIO11CFG,	0x82 },
+	{ STB0899_GPIO12CFG,	0x82 },
+	{ STB0899_GPIO13CFG,	0x82 },
+	{ STB0899_GPIO14CFG,	0x82 },
+	{ STB0899_GPIO15CFG,	0x82 },
+	{ STB0899_GPIO16CFG,	0x82 },
+	{ STB0899_GPIO17CFG,	0x82 },
+	{ STB0899_GPIO18CFG,	0x82 },
+	{ STB0899_GPIO19CFG,	0x82 },
+	{ STB0899_GPIO20CFG,	0x82 },
+	{ STB0899_SDATCFG,	0xb8 },
+	{ STB0899_SCLTCFG,	0xba },
+	{ STB0899_AGCRFCFG,	0x1c }, /* 0x11 DVB-S; 0x1c DVB-S2 (1c, rjkm) */
+	{ STB0899_GPIO22,	0x82 },
+	{ STB0899_GPIO21,	0x91 },
+	{ STB0899_DIRCLKCFG,	0x82 },
+	{ STB0899_CLKOUT27CFG,	0x7e },
+	{ STB0899_STDBYCFG,	0x82 },
+	{ STB0899_CS0CFG,	0x82 },
+	{ STB0899_CS1CFG,	0x82 },
+	{ STB0899_DISEQCOCFG,	0x20 },
+	{ STB0899_NCOARSE,	0x15 }, /* 0x15 27Mhz, F/3 198MHz, F/6 108MHz */
+	{ STB0899_SYNTCTRL,	0x00 }, /* 0x00 CLKI, 0x02 XTALI */
+	{ STB0899_FILTCTRL,	0x00 },
+	{ STB0899_SYSCTRL,	0x00 },
+	{ STB0899_STOPCLK1,	0x20 }, /* orig: 0x00 budget-ci: 0x20 */
+	{ STB0899_STOPCLK2,	0x00 },
+	{ STB0899_INTBUFCTRL,	0x0a },
+	{ STB0899_AGC2I1,	0x00 },
+	{ STB0899_AGC2I2,	0x00 },
+	{ STB0899_AGCIQIN,	0x00 },
+	{ STB0899_TSTRES,	0x40 }, /* rjkm */
+	{ 0xffff,		0xff },
+};
+
+static const struct stb0899_s1_reg pctv452e_init_s1_demod[] = {
+	{ STB0899_DEMOD,	0x00 },
+	{ STB0899_RCOMPC,	0xc9 },
+	{ STB0899_AGC1CN,	0x01 },
+	{ STB0899_AGC1REF,	0x10 },
+	{ STB0899_RTC,		0x23 },
+	{ STB0899_TMGCFG,	0x4e },
+	{ STB0899_AGC2REF,	0x34 },
+	{ STB0899_TLSR,		0x84 },
+	{ STB0899_CFD,		0xf7 },
+	{ STB0899_ACLC,		0x87 },
+	{ STB0899_BCLC,		0x94 },
+	{ STB0899_EQON,		0x41 },
+	{ STB0899_LDT,		0xf1 },
+	{ STB0899_LDT2,		0xe3 },
+	{ STB0899_EQUALREF,	0xb4 },
+	{ STB0899_TMGRAMP,	0x10 },
+	{ STB0899_TMGTHD,	0x30 },
+	{ STB0899_IDCCOMP,	0xfd },
+	{ STB0899_QDCCOMP,	0xff },
+	{ STB0899_POWERI,	0x0c },
+	{ STB0899_POWERQ,	0x0f },
+	{ STB0899_RCOMP,	0x6c },
+	{ STB0899_AGCIQIN,	0x80 },
+	{ STB0899_AGC2I1,	0x06 },
+	{ STB0899_AGC2I2,	0x00 },
+	{ STB0899_TLIR,		0x30 },
+	{ STB0899_RTF,		0x7f },
+	{ STB0899_DSTATUS,	0x00 },
+	{ STB0899_LDI,		0xbc },
+	{ STB0899_CFRM,		0xea },
+	{ STB0899_CFRL,		0x31 },
+	{ STB0899_NIRM,		0x2b },
+	{ STB0899_NIRL,		0x80 },
+	{ STB0899_ISYMB,	0x1d },
+	{ STB0899_QSYMB,	0xa6 },
+	{ STB0899_SFRH,		0x2f },
+	{ STB0899_SFRM,		0x68 },
+	{ STB0899_SFRL,		0x40 },
+	{ STB0899_SFRUPH,	0x2f },
+	{ STB0899_SFRUPM,	0x68 },
+	{ STB0899_SFRUPL,	0x40 },
+	{ STB0899_EQUAI1,	0x02 },
+	{ STB0899_EQUAQ1,	0xff },
+	{ STB0899_EQUAI2,	0x04 },
+	{ STB0899_EQUAQ2,	0x05 },
+	{ STB0899_EQUAI3,	0x02 },
+	{ STB0899_EQUAQ3,	0xfd },
+	{ STB0899_EQUAI4,	0x03 },
+	{ STB0899_EQUAQ4,	0x07 },
+	{ STB0899_EQUAI5,	0x08 },
+	{ STB0899_EQUAQ5,	0xf5 },
+	{ STB0899_DSTATUS2,	0x00 },
+	{ STB0899_VSTATUS,	0x00 },
+	{ STB0899_VERROR,	0x86 },
+	{ STB0899_IQSWAP,	0x2a },
+	{ STB0899_ECNT1M,	0x00 },
+	{ STB0899_ECNT1L,	0x00 },
+	{ STB0899_ECNT2M,	0x00 },
+	{ STB0899_ECNT2L,	0x00 },
+	{ STB0899_ECNT3M,	0x0a },
+	{ STB0899_ECNT3L,	0xad },
+	{ STB0899_FECAUTO1,	0x06 },
+	{ STB0899_FECM,		0x01 },
+	{ STB0899_VTH12,	0xb0 },
+	{ STB0899_VTH23,	0x7a },
+	{ STB0899_VTH34,	0x58 },
+	{ STB0899_VTH56,	0x38 },
+	{ STB0899_VTH67,	0x34 },
+	{ STB0899_VTH78,	0x24 },
+	{ STB0899_PRVIT,	0xff },
+	{ STB0899_VITSYNC,	0x19 },
+	{ STB0899_RSULC,	0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+	{ STB0899_TSULC,	0x42 },
+	{ STB0899_RSLLC,	0x41 },
+	{ STB0899_TSLPL,	0x12 },
+	{ STB0899_TSCFGH,	0x0c },
+	{ STB0899_TSCFGM,	0x00 },
+	{ STB0899_TSCFGL,	0x00 },
+	{ STB0899_TSOUT,	0x69 }, /* 0x0d for CAM */
+	{ STB0899_RSSYNCDEL,	0x00 },
+	{ STB0899_TSINHDELH,	0x02 },
+	{ STB0899_TSINHDELM,	0x00 },
+	{ STB0899_TSINHDELL,	0x00 },
+	{ STB0899_TSLLSTKM,	0x1b },
+	{ STB0899_TSLLSTKL,	0xb3 },
+	{ STB0899_TSULSTKM,	0x00 },
+	{ STB0899_TSULSTKL,	0x00 },
+	{ STB0899_PCKLENUL,	0xbc },
+	{ STB0899_PCKLENLL,	0xcc },
+	{ STB0899_RSPCKLEN,	0xbd },
+	{ STB0899_TSSTATUS,	0x90 },
+	{ STB0899_ERRCTRL1,	0xb6 },
+	{ STB0899_ERRCTRL2,	0x95 },
+	{ STB0899_ERRCTRL3,	0x8d },
+	{ STB0899_DMONMSK1,	0x27 },
+	{ STB0899_DMONMSK0,	0x03 },
+	{ STB0899_DEMAPVIT,	0x5c },
+	{ STB0899_PLPARM,	0x19 },
+	{ STB0899_PDELCTRL,	0x48 },
+	{ STB0899_PDELCTRL2,	0x00 },
+	{ STB0899_BBHCTRL1,	0x00 },
+	{ STB0899_BBHCTRL2,	0x00 },
+	{ STB0899_HYSTTHRESH,	0x77 },
+	{ STB0899_MATCSTM,	0x00 },
+	{ STB0899_MATCSTL,	0x00 },
+	{ STB0899_UPLCSTM,	0x00 },
+	{ STB0899_UPLCSTL,	0x00 },
+	{ STB0899_DFLCSTM,	0x00 },
+	{ STB0899_DFLCSTL,	0x00 },
+	{ STB0899_SYNCCST,	0x00 },
+	{ STB0899_SYNCDCSTM,	0x00 },
+	{ STB0899_SYNCDCSTL,	0x00 },
+	{ STB0899_ISI_ENTRY,	0x00 },
+	{ STB0899_ISI_BIT_EN,	0x00 },
+	{ STB0899_MATSTRM,	0xf0 },
+	{ STB0899_MATSTRL,	0x02 },
+	{ STB0899_UPLSTRM,	0x45 },
+	{ STB0899_UPLSTRL,	0x60 },
+	{ STB0899_DFLSTRM,	0xe3 },
+	{ STB0899_DFLSTRL,	0x00 },
+	{ STB0899_SYNCSTR,	0x47 },
+	{ STB0899_SYNCDSTRM,	0x05 },
+	{ STB0899_SYNCDSTRL,	0x18 },
+	{ STB0899_CFGPDELSTATUS1, 0x19 },
+	{ STB0899_CFGPDELSTATUS2, 0x2b },
+	{ STB0899_BBFERRORM,	0x00 },
+	{ STB0899_BBFERRORL,	0x01 },
+	{ STB0899_UPKTERRORM,	0x00 },
+	{ STB0899_UPKTERRORL,	0x00 },
+	{ 0xffff,		0xff },
+};
+
+static struct stb0899_config stb0899_config = {
+	.init_dev	= pctv452e_init_dev,
+	.init_s2_demod	= stb0899_s2_init_2,
+	.init_s1_demod	= pctv452e_init_s1_demod,
+	.init_s2_fec	= stb0899_s2_init_4,
+	.init_tst	= stb0899_s1_init_5,
+
+	.demod_address   = I2C_ADDR_STB0899, /* I2C Address */
+	.block_sync_mode = STB0899_SYNC_FORCED, /* ? */
+
+	.xtal_freq       = 27000000,	 /* Assume Hz ? */
+	.inversion       = IQ_SWAP_ON,       /* ? */
+
+	.lo_clk	  = 76500000,
+	.hi_clk	  = 99000000,
+
+	.ts_output_mode  = 0,	/* Use parallel mode */
+	.clock_polarity  = 0,
+	.data_clk_parity = 0,
+	.fec_mode	= 0,
+
+	.esno_ave	    = STB0899_DVBS2_ESNO_AVE,
+	.esno_quant	  = STB0899_DVBS2_ESNO_QUANT,
+	.avframes_coarse     = STB0899_DVBS2_AVFRAMES_COARSE,
+	.avframes_fine       = STB0899_DVBS2_AVFRAMES_FINE,
+	.miss_threshold      = STB0899_DVBS2_MISS_THRESHOLD,
+	.uwp_threshold_acq   = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
+	.uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
+	.uwp_threshold_sof   = STB0899_DVBS2_UWP_THRESHOLD_SOF,
+	.sof_search_timeout  = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
+
+	.btr_nco_bits	  = STB0899_DVBS2_BTR_NCO_BITS,
+	.btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+	.crl_nco_bits	  = STB0899_DVBS2_CRL_NCO_BITS,
+	.ldpc_max_iter	 = STB0899_DVBS2_LDPC_MAX_ITER,
+
+	.tuner_get_frequency	= stb6100_get_frequency,
+	.tuner_set_frequency	= stb6100_set_frequency,
+	.tuner_set_bandwidth	= stb6100_set_bandwidth,
+	.tuner_get_bandwidth	= stb6100_get_bandwidth,
+	.tuner_set_rfsiggain	= NULL,
+
+	/* helper for switching LED green/orange */
+	.postproc = pctv45e_postproc
+};
+
+static struct stb6100_config stb6100_config = {
+	.tuner_address = I2C_ADDR_STB6100,
+	.refclock      = 27000000
+};
+
+
+static struct i2c_algorithm pctv452e_i2c_algo = {
+	.master_xfer   = pctv452e_i2c_xfer,
+	.functionality = pctv452e_i2c_func
+};
+
+static int pctv452e_frontend_attach(struct dvb_usb_adapter *a)
+{
+	struct usb_device_id *id;
+
+	a->fe_adap[0].fe = dvb_attach(stb0899_attach, &stb0899_config,
+						&a->dev->i2c_adap);
+	if (!a->fe_adap[0].fe)
+		return -ENODEV;
+	if ((dvb_attach(lnbp22_attach, a->fe_adap[0].fe,
+					&a->dev->i2c_adap)) == 0)
+		err("Cannot attach lnbp22\n");
+
+	id = a->dev->desc->warm_ids[0];
+	if (USB_VID_TECHNOTREND == id->idVendor
+	    && USB_PID_TECHNOTREND_CONNECT_S2_3650_CI == id->idProduct)
+		/* Error ignored. */
+		tt3650_ci_init(a);
+
+	return 0;
+}
+
+static int pctv452e_tuner_attach(struct dvb_usb_adapter *a)
+{
+	if (!a->fe_adap[0].fe)
+		return -ENODEV;
+	if (dvb_attach(stb6100_attach, a->fe_adap[0].fe, &stb6100_config,
+					&a->dev->i2c_adap) == 0) {
+		err("%s failed\n", __func__);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static struct usb_device_id pctv452e_usb_table[] = {
+	{USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_452E)},
+	{USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3600)},
+	{USB_DEVICE(USB_VID_TECHNOTREND,
+				USB_PID_TECHNOTREND_CONNECT_S2_3650_CI)},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, pctv452e_usb_table);
+
+static struct dvb_usb_device_properties pctv452e_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
+	.usb_ctrl = DEVICE_SPECIFIC,
+
+	.size_of_priv     = sizeof(struct pctv452e_state),
+
+	.power_ctrl       = pctv452e_power_ctrl,
+
+	.rc.core = {
+		.rc_codes	= RC_MAP_DIB0700_RC5_TABLE,
+		.allowed_protos	= RC_TYPE_UNKNOWN,
+		.rc_query	= pctv452e_rc_query,
+		.rc_interval	= 100,
+	},
+
+	.num_adapters     = 1,
+	.adapter = {{
+		.num_frontends = 1,
+		.fe = {{
+			.frontend_attach  = pctv452e_frontend_attach,
+			.tuner_attach     = pctv452e_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type     = USB_ISOC,
+				.count    = 4,
+				.endpoint = 0x02,
+				.u = {
+					.isoc = {
+						.framesperurb = 4,
+						.framesize    = 940,
+						.interval     = 1
+					}
+				}
+			},
+		} },
+	} },
+
+	.i2c_algo = &pctv452e_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 1, /* allow generice rw function */
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "PCTV HDTV USB",
+		  .cold_ids = { NULL, NULL }, /* this is a warm only device */
+		  .warm_ids = { &pctv452e_usb_table[0], NULL }
+		},
+		{ 0 },
+	}
+};
+
+static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
+	.usb_ctrl = DEVICE_SPECIFIC,
+
+	.size_of_priv		= sizeof(struct pctv452e_state),
+
+	.power_ctrl		= pctv452e_power_ctrl,
+	.read_mac_address	= pctv452e_read_mac_address,
+
+	.rc.core = {
+		.rc_codes	= RC_MAP_TT_1500,
+		.allowed_protos	= RC_TYPE_UNKNOWN,
+		.rc_query	= pctv452e_rc_query,
+		.rc_interval	= 100,
+	},
+
+	.num_adapters		= 1,
+	.adapter = {{
+		.num_frontends = 1,
+		.fe = {{
+			.frontend_attach = pctv452e_frontend_attach,
+			.tuner_attach = pctv452e_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_ISOC,
+				.count = 7,
+				.endpoint = 0x02,
+				.u = {
+					.isoc = {
+						.framesperurb = 4,
+						.framesize = 940,
+						.interval = 1
+					}
+				}
+			},
+
+		} },
+	} },
+
+	.i2c_algo = &pctv452e_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 1, /* allow generic rw function*/
+
+	.num_device_descs = 2,
+	.devices = {
+		{ .name = "Technotrend TT Connect S2-3600",
+		  .cold_ids = { NULL, NULL }, /* this is a warm only device */
+		  .warm_ids = { &pctv452e_usb_table[1], NULL }
+		},
+		{ .name = "Technotrend TT Connect S2-3650-CI",
+		  .cold_ids = { NULL, NULL },
+		  .warm_ids = { &pctv452e_usb_table[2], NULL }
+		},
+		{ 0 },
+	}
+};
+
+static void pctv452e_usb_disconnect(struct usb_interface *intf)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+
+	tt3650_ci_uninit(d);
+	dvb_usb_device_exit(intf);
+}
+
+static int pctv452e_usb_probe(struct usb_interface *intf,
+				const struct usb_device_id *id)
+{
+	if (0 == dvb_usb_device_init(intf, &pctv452e_properties,
+					THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &tt_connect_s2_3600_properties,
+					THIS_MODULE, NULL, adapter_nr))
+		return 0;
+
+	return -ENODEV;
+}
+
+static struct usb_driver pctv452e_usb_driver = {
+	.name       = "pctv452e",
+	.probe      = pctv452e_usb_probe,
+	.disconnect = pctv452e_usb_disconnect,
+	.id_table   = pctv452e_usb_table,
+};
+
+module_usb_driver(pctv452e_usb_driver);
+
+MODULE_AUTHOR("Dominik Kuhlen <dkuhlen@gmx.net>");
+MODULE_AUTHOR("Andre Weidemann <Andre.Weidemann@web.de>");
+MODULE_AUTHOR("Michael H. Schimek <mschimek@gmx.at>");
+MODULE_DESCRIPTION("Pinnacle PCTV HDTV USB DVB / TT connect S2-3600 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c
new file mode 100644
index 0000000..acefaa8
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/technisat-usb2.c
@@ -0,0 +1,789 @@
+/*
+ * Linux driver for Technisat DVB-S/S2 USB 2.0 device
+ *
+ * Copyright (C) 2010 Patrick Boettcher,
+ *                    Kernel Labs Inc. PO Box 745, St James, NY 11780
+ *
+ * Development was sponsored by Technisat Digital UK Limited, whose
+ * registered office is Witan Gate House 500 - 600 Witan Gate West,
+ * Milton Keynes, MK9 1SH
+ *
+ * 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.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * THIS PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND
+ * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  NEITHER THE COPYRIGHT HOLDER
+ * NOR TECHNISAT DIGITAL UK LIMITED SHALL BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PROGRAM. See the
+ * GNU General Public License for more details.
+ */
+
+#define DVB_USB_LOG_PREFIX "technisat-usb2"
+#include "dvb-usb.h"
+
+#include "stv6110x.h"
+#include "stv090x.h"
+
+/* module parameters */
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,
+		"set debugging level (bit-mask: 1=info,2=eeprom,4=i2c,8=rc)." \
+		DVB_USB_DEBUG_STATUS);
+
+/* disables all LED control command and
+ * also does not start the signal polling thread */
+static int disable_led_control;
+module_param(disable_led_control, int, 0444);
+MODULE_PARM_DESC(disable_led_control,
+		"disable LED control of the device "
+		"(default: 0 - LED control is active).");
+
+/* device private data */
+struct technisat_usb2_state {
+	struct dvb_usb_device *dev;
+	struct delayed_work green_led_work;
+	u8 power_state;
+
+	u16 last_scan_code;
+};
+
+/* debug print helpers */
+#define deb_info(args...)    dprintk(debug, 0x01, args)
+#define deb_eeprom(args...)  dprintk(debug, 0x02, args)
+#define deb_i2c(args...)     dprintk(debug, 0x04, args)
+#define deb_rc(args...)      dprintk(debug, 0x08, args)
+
+/* vendor requests */
+#define SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST 0xB3
+#define SET_FRONT_END_RESET_VENDOR_REQUEST         0xB4
+#define GET_VERSION_INFO_VENDOR_REQUEST            0xB5
+#define SET_GREEN_LED_VENDOR_REQUEST               0xB6
+#define SET_RED_LED_VENDOR_REQUEST                 0xB7
+#define GET_IR_DATA_VENDOR_REQUEST                 0xB8
+#define SET_LED_TIMER_DIVIDER_VENDOR_REQUEST       0xB9
+#define SET_USB_REENUMERATION                      0xBA
+
+/* i2c-access methods */
+#define I2C_SPEED_100KHZ_BIT 0x40
+
+#define I2C_STATUS_NAK 7
+#define I2C_STATUS_OK 8
+
+static int technisat_usb2_i2c_access(struct usb_device *udev,
+		u8 device_addr, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
+{
+	u8 b[64];
+	int ret, actual_length;
+
+	deb_i2c("i2c-access: %02x, tx: ", device_addr);
+	debug_dump(tx, txlen, deb_i2c);
+	deb_i2c(" ");
+
+	if (txlen > 62) {
+		err("i2c TX buffer can't exceed 62 bytes (dev 0x%02x)",
+				device_addr);
+		txlen = 62;
+	}
+	if (rxlen > 62) {
+		err("i2c RX buffer can't exceed 62 bytes (dev 0x%02x)",
+				device_addr);
+		txlen = 62;
+	}
+
+	b[0] = I2C_SPEED_100KHZ_BIT;
+	b[1] = device_addr << 1;
+
+	if (rx != NULL) {
+		b[0] |= rxlen;
+		b[1] |= 1;
+	}
+
+	memcpy(&b[2], tx, txlen);
+	ret = usb_bulk_msg(udev,
+			usb_sndbulkpipe(udev, 0x01),
+			b, 2 + txlen,
+			NULL, 1000);
+
+	if (ret < 0) {
+		err("i2c-error: out failed %02x = %d", device_addr, ret);
+		return -ENODEV;
+	}
+
+	ret = usb_bulk_msg(udev,
+			usb_rcvbulkpipe(udev, 0x01),
+			b, 64, &actual_length, 1000);
+	if (ret < 0) {
+		err("i2c-error: in failed %02x = %d", device_addr, ret);
+		return -ENODEV;
+	}
+
+	if (b[0] != I2C_STATUS_OK) {
+		err("i2c-error: %02x = %d", device_addr, b[0]);
+		/* handle tuner-i2c-nak */
+		if (!(b[0] == I2C_STATUS_NAK &&
+				device_addr == 0x60
+				/* && device_is_technisat_usb2 */))
+			return -ENODEV;
+	}
+
+	deb_i2c("status: %d, ", b[0]);
+
+	if (rx != NULL) {
+		memcpy(rx, &b[2], rxlen);
+
+		deb_i2c("rx (%d): ", rxlen);
+		debug_dump(rx, rxlen, deb_i2c);
+	}
+
+	deb_i2c("\n");
+
+	return 0;
+}
+
+static int technisat_usb2_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+				int num)
+{
+	int ret = 0, i;
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+
+	/* Ensure nobody else hits the i2c bus while we're sending our
+	   sequence of messages, (such as the remote control thread) */
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		if (i+1 < num && msg[i+1].flags & I2C_M_RD) {
+			ret = technisat_usb2_i2c_access(d->udev, msg[i+1].addr,
+						msg[i].buf, msg[i].len,
+						msg[i+1].buf, msg[i+1].len);
+			if (ret != 0)
+				break;
+			i++;
+		} else {
+			ret = technisat_usb2_i2c_access(d->udev, msg[i].addr,
+						msg[i].buf, msg[i].len,
+						NULL, 0);
+			if (ret != 0)
+				break;
+		}
+	}
+
+	if (ret == 0)
+		ret = i;
+
+	mutex_unlock(&d->i2c_mutex);
+
+	return ret;
+}
+
+static u32 technisat_usb2_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm technisat_usb2_i2c_algo = {
+	.master_xfer   = technisat_usb2_i2c_xfer,
+	.functionality = technisat_usb2_i2c_func,
+};
+
+#if 0
+static void technisat_usb2_frontend_reset(struct usb_device *udev)
+{
+	usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			SET_FRONT_END_RESET_VENDOR_REQUEST,
+			USB_TYPE_VENDOR | USB_DIR_OUT,
+			10, 0,
+			NULL, 0, 500);
+}
+#endif
+
+/* LED control */
+enum technisat_usb2_led_state {
+	LED_OFF,
+	LED_BLINK,
+	LED_ON,
+	LED_UNDEFINED
+};
+
+static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum technisat_usb2_led_state state)
+{
+	int ret;
+
+	u8 led[8] = {
+		red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST,
+		0
+	};
+
+	if (disable_led_control && state != LED_OFF)
+		return 0;
+
+	switch (state) {
+	case LED_ON:
+		led[1] = 0x82;
+		break;
+	case LED_BLINK:
+		led[1] = 0x82;
+		if (red) {
+			led[2] = 0x02;
+			led[3] = 10;
+			led[4] = 10;
+		} else {
+			led[2] = 0xff;
+			led[3] = 50;
+			led[4] = 50;
+		}
+		led[5] = 1;
+		break;
+
+	default:
+	case LED_OFF:
+		led[1] = 0x80;
+		break;
+	}
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
+		red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST,
+		USB_TYPE_VENDOR | USB_DIR_OUT,
+		0, 0,
+		led, sizeof(led), 500);
+
+	mutex_unlock(&d->i2c_mutex);
+	return ret;
+}
+
+static int technisat_usb2_set_led_timer(struct dvb_usb_device *d, u8 red, u8 green)
+{
+	int ret;
+	u8 b = 0;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
+		SET_LED_TIMER_DIVIDER_VENDOR_REQUEST,
+		USB_TYPE_VENDOR | USB_DIR_OUT,
+		(red << 8) | green, 0,
+		&b, 1, 500);
+
+	mutex_unlock(&d->i2c_mutex);
+
+	return ret;
+}
+
+static void technisat_usb2_green_led_control(struct work_struct *work)
+{
+	struct technisat_usb2_state *state =
+		container_of(work, struct technisat_usb2_state, green_led_work.work);
+	struct dvb_frontend *fe = state->dev->adapter[0].fe_adap[0].fe;
+
+	if (state->power_state == 0)
+		goto schedule;
+
+	if (fe != NULL) {
+		enum fe_status status;
+
+		if (fe->ops.read_status(fe, &status) != 0)
+			goto schedule;
+
+		if (status & FE_HAS_LOCK) {
+			u32 ber;
+
+			if (fe->ops.read_ber(fe, &ber) != 0)
+				goto schedule;
+
+			if (ber > 1000)
+				technisat_usb2_set_led(state->dev, 0, LED_BLINK);
+			else
+				technisat_usb2_set_led(state->dev, 0, LED_ON);
+		} else
+			technisat_usb2_set_led(state->dev, 0, LED_OFF);
+	}
+
+schedule:
+	schedule_delayed_work(&state->green_led_work,
+			msecs_to_jiffies(500));
+}
+
+/* method to find out whether the firmware has to be downloaded or not */
+static int technisat_usb2_identify_state(struct usb_device *udev,
+		struct dvb_usb_device_properties *props,
+		struct dvb_usb_device_description **desc, int *cold)
+{
+	int ret;
+	u8 version[3];
+
+	/* first select the interface */
+	if (usb_set_interface(udev, 0, 1) != 0)
+		err("could not set alternate setting to 0");
+	else
+		info("set alternate setting");
+
+	*cold = 0; /* by default do not download a firmware - just in case something is wrong */
+
+	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+		GET_VERSION_INFO_VENDOR_REQUEST,
+		USB_TYPE_VENDOR | USB_DIR_IN,
+		0, 0,
+		version, sizeof(version), 500);
+
+	if (ret < 0)
+		*cold = 1;
+	else {
+		info("firmware version: %d.%d", version[1], version[2]);
+		*cold = 0;
+	}
+
+	return 0;
+}
+
+/* power control */
+static int technisat_usb2_power_ctrl(struct dvb_usb_device *d, int level)
+{
+	struct technisat_usb2_state *state = d->priv;
+
+	state->power_state = level;
+
+	if (disable_led_control)
+		return 0;
+
+	/* green led is turned off in any case - will be turned on when tuning */
+	technisat_usb2_set_led(d, 0, LED_OFF);
+	/* red led is turned on all the time */
+	technisat_usb2_set_led(d, 1, LED_ON);
+	return 0;
+}
+
+/* mac address reading - from the eeprom */
+#if 0
+static void technisat_usb2_eeprom_dump(struct dvb_usb_device *d)
+{
+	u8 reg;
+	u8 b[16];
+	int i, j;
+
+	/* full EEPROM dump */
+	for (j = 0; j < 256 * 4; j += 16) {
+		reg = j;
+		if (technisat_usb2_i2c_access(d->udev, 0x50 + j / 256, &reg, 1, b, 16) != 0)
+			break;
+
+		deb_eeprom("EEPROM: %01x%02x: ", j / 256, reg);
+		for (i = 0; i < 16; i++)
+			deb_eeprom("%02x ", b[i]);
+		deb_eeprom("\n");
+	}
+}
+#endif
+
+static u8 technisat_usb2_calc_lrc(const u8 *b, u16 length)
+{
+	u8 lrc = 0;
+	while (--length)
+		lrc ^= *b++;
+	return lrc;
+}
+
+static int technisat_usb2_eeprom_lrc_read(struct dvb_usb_device *d,
+	u16 offset, u8 *b, u16 length, u8 tries)
+{
+	u8 bo = offset & 0xff;
+	struct i2c_msg msg[] = {
+		{
+			.addr = 0x50 | ((offset >> 8) & 0x3),
+			.buf = &bo,
+			.len = 1
+		}, {
+			.addr = 0x50 | ((offset >> 8) & 0x3),
+			.flags	= I2C_M_RD,
+			.buf = b,
+			.len = length
+		}
+	};
+
+	while (tries--) {
+		int status;
+
+		if (i2c_transfer(&d->i2c_adap, msg, 2) != 2)
+			break;
+
+		status =
+			technisat_usb2_calc_lrc(b, length - 1) == b[length - 1];
+
+		if (status)
+			return 0;
+	}
+
+	return -EREMOTEIO;
+}
+
+#define EEPROM_MAC_START 0x3f8
+#define EEPROM_MAC_TOTAL 8
+static int technisat_usb2_read_mac_address(struct dvb_usb_device *d,
+		u8 mac[])
+{
+	u8 buf[EEPROM_MAC_TOTAL];
+
+	if (technisat_usb2_eeprom_lrc_read(d, EEPROM_MAC_START,
+				buf, EEPROM_MAC_TOTAL, 4) != 0)
+		return -ENODEV;
+
+	memcpy(mac, buf, 6);
+	return 0;
+}
+
+/* frontend attach */
+static int technisat_usb2_set_voltage(struct dvb_frontend *fe,
+		fe_sec_voltage_t voltage)
+{
+	int i;
+	u8 gpio[3] = { 0 }; /* 0 = 2, 1 = 3, 2 = 4 */
+
+	gpio[2] = 1; /* high - voltage ? */
+
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		gpio[0] = 1;
+		break;
+	case SEC_VOLTAGE_18:
+		gpio[0] = 1;
+		gpio[1] = 1;
+		break;
+	default:
+	case SEC_VOLTAGE_OFF:
+		break;
+	}
+
+	for (i = 0; i < 3; i++)
+		if (stv090x_set_gpio(fe, i+2, 0, gpio[i], 0) != 0)
+			return -EREMOTEIO;
+	return 0;
+}
+
+static struct stv090x_config technisat_usb2_stv090x_config = {
+	.device         = STV0903,
+	.demod_mode     = STV090x_SINGLE,
+	.clk_mode       = STV090x_CLK_EXT,
+
+	.xtal           = 8000000,
+	.address        = 0x68,
+
+	.ts1_mode       = STV090x_TSMODE_DVBCI,
+	.ts1_clk        = 13400000,
+	.ts1_tei        = 1,
+
+	.repeater_level = STV090x_RPTLEVEL_64,
+
+	.tuner_bbgain   = 6,
+};
+
+static struct stv6110x_config technisat_usb2_stv6110x_config = {
+	.addr           = 0x60,
+	.refclk         = 16000000,
+	.clk_div        = 2,
+};
+
+static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a)
+{
+	struct usb_device *udev = a->dev->udev;
+	int ret;
+
+	a->fe_adap[0].fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config,
+			&a->dev->i2c_adap, STV090x_DEMODULATOR_0);
+
+	if (a->fe_adap[0].fe) {
+		struct stv6110x_devctl *ctl;
+
+		ctl = dvb_attach(stv6110x_attach,
+				a->fe_adap[0].fe,
+				&technisat_usb2_stv6110x_config,
+				&a->dev->i2c_adap);
+
+		if (ctl) {
+			technisat_usb2_stv090x_config.tuner_init          = ctl->tuner_init;
+			technisat_usb2_stv090x_config.tuner_sleep         = ctl->tuner_sleep;
+			technisat_usb2_stv090x_config.tuner_set_mode      = ctl->tuner_set_mode;
+			technisat_usb2_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
+			technisat_usb2_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
+			technisat_usb2_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+			technisat_usb2_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+			technisat_usb2_stv090x_config.tuner_set_bbgain    = ctl->tuner_set_bbgain;
+			technisat_usb2_stv090x_config.tuner_get_bbgain    = ctl->tuner_get_bbgain;
+			technisat_usb2_stv090x_config.tuner_set_refclk    = ctl->tuner_set_refclk;
+			technisat_usb2_stv090x_config.tuner_get_status    = ctl->tuner_get_status;
+
+			/* call the init function once to initialize
+			   tuner's clock output divider and demod's
+			   master clock */
+			if (a->fe_adap[0].fe->ops.init)
+				a->fe_adap[0].fe->ops.init(a->fe_adap[0].fe);
+
+			if (mutex_lock_interruptible(&a->dev->i2c_mutex) < 0)
+				return -EAGAIN;
+
+			ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+					SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST,
+					USB_TYPE_VENDOR | USB_DIR_OUT,
+					0, 0,
+					NULL, 0, 500);
+			mutex_unlock(&a->dev->i2c_mutex);
+
+			if (ret != 0)
+				err("could not set IF_CLK to external");
+
+			a->fe_adap[0].fe->ops.set_voltage = technisat_usb2_set_voltage;
+
+			/* if everything was successful assign a nice name to the frontend */
+			strlcpy(a->fe_adap[0].fe->ops.info.name, a->dev->desc->name,
+					sizeof(a->fe_adap[0].fe->ops.info.name));
+		} else {
+			dvb_frontend_detach(a->fe_adap[0].fe);
+			a->fe_adap[0].fe = NULL;
+		}
+	}
+
+	technisat_usb2_set_led_timer(a->dev, 1, 1);
+
+	return a->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+/* Remote control */
+
+/* the device is giving providing raw IR-signals to the host mapping
+ * it only to one remote control is just the default implementation
+ */
+#define NOMINAL_IR_BIT_TRANSITION_TIME_US 889
+#define NOMINAL_IR_BIT_TIME_US (2 * NOMINAL_IR_BIT_TRANSITION_TIME_US)
+
+#define FIRMWARE_CLOCK_TICK 83333
+#define FIRMWARE_CLOCK_DIVISOR 256
+
+#define IR_PERCENT_TOLERANCE 15
+
+#define NOMINAL_IR_BIT_TRANSITION_TICKS ((NOMINAL_IR_BIT_TRANSITION_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK)
+#define NOMINAL_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICKS / FIRMWARE_CLOCK_DIVISOR)
+
+#define NOMINAL_IR_BIT_TIME_TICKS ((NOMINAL_IR_BIT_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK)
+#define NOMINAL_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICKS / FIRMWARE_CLOCK_DIVISOR)
+
+#define MINIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT - ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
+#define MAXIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT + ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
+
+#define MINIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT - ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
+#define MAXIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT + ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
+
+static int technisat_usb2_get_ir(struct dvb_usb_device *d)
+{
+	u8 buf[62], *b;
+	int ret;
+	struct ir_raw_event ev;
+
+	buf[0] = GET_IR_DATA_VENDOR_REQUEST;
+	buf[1] = 0x08;
+	buf[2] = 0x8f;
+	buf[3] = MINIMUM_IR_BIT_TRANSITION_TICK_COUNT;
+	buf[4] = MAXIMUM_IR_BIT_TIME_TICK_COUNT;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+	ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
+			GET_IR_DATA_VENDOR_REQUEST,
+			USB_TYPE_VENDOR | USB_DIR_OUT,
+			0, 0,
+			buf, 5, 500);
+	if (ret < 0)
+		goto unlock;
+
+	buf[1] = 0;
+	buf[2] = 0;
+	ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
+			GET_IR_DATA_VENDOR_REQUEST,
+			USB_TYPE_VENDOR | USB_DIR_IN,
+			0x8080, 0,
+			buf, sizeof(buf), 500);
+
+unlock:
+	mutex_unlock(&d->i2c_mutex);
+
+	if (ret < 0)
+		return ret;
+
+	if (ret == 1)
+		return 0; /* no key pressed */
+
+	/* decoding */
+	b = buf+1;
+
+#if 0
+	deb_rc("RC: %d ", ret);
+	debug_dump(b, ret, deb_rc);
+#endif
+
+	ev.pulse = 0;
+	while (1) {
+		ev.pulse = !ev.pulse;
+		ev.duration = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000;
+		ir_raw_event_store(d->rc_dev, &ev);
+
+		b++;
+		if (*b == 0xff) {
+			ev.pulse = 0;
+			ev.duration = 888888*2;
+			ir_raw_event_store(d->rc_dev, &ev);
+			break;
+		}
+	}
+
+	ir_raw_event_handle(d->rc_dev);
+
+	return 1;
+}
+
+static int technisat_usb2_rc_query(struct dvb_usb_device *d)
+{
+	int ret = technisat_usb2_get_ir(d);
+
+	if (ret < 0)
+		return ret;
+
+	if (ret == 0)
+		return 0;
+
+	if (!disable_led_control)
+		technisat_usb2_set_led(d, 1, LED_BLINK);
+
+	return 0;
+}
+
+/* DVB-USB and USB stuff follows */
+static struct usb_device_id technisat_usb2_id_table[] = {
+	{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_DVB_S2) },
+	{ 0 }		/* Terminating entry */
+};
+
+/* device description */
+static struct dvb_usb_device_properties technisat_usb2_devices = {
+	.caps              = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl          = CYPRESS_FX2,
+
+	.identify_state    = technisat_usb2_identify_state,
+	.firmware          = "dvb-usb-SkyStar_USB_HD_FW_v17_63.HEX.fw",
+
+	.size_of_priv      = sizeof(struct technisat_usb2_state),
+
+	.i2c_algo          = &technisat_usb2_i2c_algo,
+
+	.power_ctrl        = technisat_usb2_power_ctrl,
+	.read_mac_address  = technisat_usb2_read_mac_address,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.frontend_attach  = technisat_usb2_frontend_attach,
+
+			.stream = {
+				.type = USB_ISOC,
+				.count = 8,
+				.endpoint = 0x2,
+				.u = {
+					.isoc = {
+						.framesperurb = 32,
+						.framesize = 2048,
+						.interval = 3,
+					}
+				}
+			},
+		}},
+			.size_of_priv = 0,
+		},
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "Technisat SkyStar USB HD (DVB-S/S2)",
+			{ &technisat_usb2_id_table[0], NULL },
+			{ NULL },
+		},
+	},
+
+	.rc.core = {
+		.rc_interval = 100,
+		.rc_codes    = RC_MAP_TECHNISAT_USB2,
+		.module_name = "technisat-usb2",
+		.rc_query    = technisat_usb2_rc_query,
+		.allowed_protos = RC_TYPE_ALL,
+		.driver_type    = RC_DRIVER_IR_RAW,
+	}
+};
+
+static int technisat_usb2_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	struct dvb_usb_device *dev;
+
+	if (dvb_usb_device_init(intf, &technisat_usb2_devices, THIS_MODULE,
+				&dev, adapter_nr) != 0)
+		return -ENODEV;
+
+	if (dev) {
+		struct technisat_usb2_state *state = dev->priv;
+		state->dev = dev;
+
+		if (!disable_led_control) {
+			INIT_DELAYED_WORK(&state->green_led_work,
+					technisat_usb2_green_led_control);
+			schedule_delayed_work(&state->green_led_work,
+					msecs_to_jiffies(500));
+		}
+	}
+
+	return 0;
+}
+
+static void technisat_usb2_disconnect(struct usb_interface *intf)
+{
+	struct dvb_usb_device *dev = usb_get_intfdata(intf);
+
+	/* work and stuff was only created when the device is is hot-state */
+	if (dev != NULL) {
+		struct technisat_usb2_state *state = dev->priv;
+		if (state != NULL)
+			cancel_delayed_work_sync(&state->green_led_work);
+	}
+
+	dvb_usb_device_exit(intf);
+}
+
+static struct usb_driver technisat_usb2_driver = {
+	.name       = "dvb_usb_technisat_usb2",
+	.probe      = technisat_usb2_probe,
+	.disconnect = technisat_usb2_disconnect,
+	.id_table   = technisat_usb2_id_table,
+};
+
+module_usb_driver(technisat_usb2_driver);
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@kernellabs.com>");
+MODULE_DESCRIPTION("Driver for Technisat DVB-S/S2 USB 2.0 device");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/ttusb2.c b/drivers/media/usb/dvb-usb/ttusb2.c
new file mode 100644
index 0000000..e53a106
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/ttusb2.c
@@ -0,0 +1,820 @@
+/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones
+ * (e.g. Pinnacle 400e DVB-S USB2.0).
+ *
+ * The Pinnacle 400e uses the same protocol as the Technotrend USB1.1 boxes.
+ *
+ * TDA8263 + TDA10086
+ *
+ * I2C addresses:
+ * 0x08 - LNBP21PD   - LNB power supply
+ * 0x0e - TDA10086   - Demodulator
+ * 0x50 - FX2 eeprom
+ * 0x60 - TDA8263    - Tuner
+ * 0x78 ???
+ *
+ * Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
+ * Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net>
+ * Copyright (C) 2005-6 Patrick Boettcher <pb@linuxtv.org>
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#define DVB_USB_LOG_PREFIX "ttusb2"
+#include "dvb-usb.h"
+
+#include "ttusb2.h"
+
+#include "tda826x.h"
+#include "tda10086.h"
+#include "tda1002x.h"
+#include "tda10048.h"
+#include "tda827x.h"
+#include "lnbp21.h"
+/* CA */
+#include "dvb_ca_en50221.h"
+
+/* debug */
+static int dvb_usb_ttusb2_debug;
+#define deb_info(args...)   dprintk(dvb_usb_ttusb2_debug,0x01,args)
+module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS);
+static int dvb_usb_ttusb2_debug_ci;
+module_param_named(debug_ci,dvb_usb_ttusb2_debug_ci, int, 0644);
+MODULE_PARM_DESC(debug_ci, "set debugging ci." DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define ci_dbg(format, arg...)                \
+do {                                          \
+	if (dvb_usb_ttusb2_debug_ci)                                    \
+		printk(KERN_DEBUG DVB_USB_LOG_PREFIX \
+			": %s " format "\n" , __func__, ## arg);       \
+} while (0)
+
+enum {
+	TT3650_CMD_CI_TEST = 0x40,
+	TT3650_CMD_CI_RD_CTRL,
+	TT3650_CMD_CI_WR_CTRL,
+	TT3650_CMD_CI_RD_ATTR,
+	TT3650_CMD_CI_WR_ATTR,
+	TT3650_CMD_CI_RESET,
+	TT3650_CMD_CI_SET_VIDEO_PORT
+};
+
+struct ttusb2_state {
+	struct dvb_ca_en50221 ca;
+	struct mutex ca_mutex;
+	u8 id;
+	u16 last_rc_key;
+};
+
+static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd,
+		u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+	struct ttusb2_state *st = d->priv;
+	u8 *s, *r = NULL;
+	int ret = 0;
+
+	s = kzalloc(wlen+4, GFP_KERNEL);
+	if (!s)
+		return -ENOMEM;
+
+	r = kzalloc(64, GFP_KERNEL);
+	if (!r) {
+		kfree(s);
+		return -ENOMEM;
+	}
+
+	s[0] = 0xaa;
+	s[1] = ++st->id;
+	s[2] = cmd;
+	s[3] = wlen;
+	memcpy(&s[4],wbuf,wlen);
+
+	ret = dvb_usb_generic_rw(d, s, wlen+4, r, 64, 0);
+
+	if (ret  != 0 ||
+		r[0] != 0x55 ||
+		r[1] != s[1] ||
+		r[2] != cmd ||
+		(rlen > 0 && r[3] != rlen)) {
+		warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]);
+		kfree(s);
+		kfree(r);
+		return -EIO;
+	}
+
+	if (rlen > 0)
+		memcpy(rbuf, &r[4], rlen);
+
+	kfree(s);
+	kfree(r);
+
+	return 0;
+}
+
+/* ci */
+static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len)
+{
+	int ret;
+	u8 rx[60];/* (64 -4) */
+	ret = ttusb2_msg(d, cmd, data, write_len, rx, read_len);
+	if (!ret)
+		memcpy(data, rx, read_len);
+	return ret;
+}
+
+static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len)
+{
+	struct dvb_usb_device *d = ca->data;
+	struct ttusb2_state *state = d->priv;
+	int ret;
+
+	mutex_lock(&state->ca_mutex);
+	ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
+	mutex_unlock(&state->ca_mutex);
+
+	return ret;
+}
+
+static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
+{
+	u8 buf[3];
+	int ret = 0;
+
+	if (slot)
+		return -EINVAL;
+
+	buf[0] = (address >> 8) & 0x0F;
+	buf[1] = address;
+
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
+
+	ci_dbg("%04x -> %d 0x%02x", address, ret, buf[2]);
+
+	if (ret < 0)
+		return ret;
+
+	return buf[2];
+}
+
+static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
+{
+	u8 buf[3];
+
+	ci_dbg("%d 0x%04x 0x%02x", slot, address, value);
+
+	if (slot)
+		return -EINVAL;
+
+	buf[0] = (address >> 8) & 0x0F;
+	buf[1] = address;
+	buf[2] = value;
+
+	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
+}
+
+static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
+{
+	u8 buf[2];
+	int ret;
+
+	if (slot)
+		return -EINVAL;
+
+	buf[0] = address & 3;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
+
+	ci_dbg("0x%02x -> %d 0x%02x", address, ret, buf[1]);
+
+	if (ret < 0)
+		return ret;
+
+	return buf[1];
+}
+
+static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
+{
+	u8 buf[2];
+
+	ci_dbg("%d 0x%02x 0x%02x", slot, address, value);
+
+	if (slot)
+		return -EINVAL;
+
+	buf[0] = address;
+	buf[1] = value;
+
+	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
+}
+
+static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca, int slot, int enable)
+{
+	u8 buf[1];
+	int ret;
+
+	ci_dbg("%d %d", slot, enable);
+
+	if (slot)
+		return -EINVAL;
+
+	buf[0] = enable;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
+	if (ret < 0)
+		return ret;
+
+	if (enable != buf[0]) {
+		err("CI not %sabled.", enable ? "en" : "dis");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+	return tt3650_ci_set_video_port(ca, slot, 0);
+}
+
+static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+	return tt3650_ci_set_video_port(ca, slot, 1);
+}
+
+static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct dvb_usb_device *d = ca->data;
+	struct ttusb2_state *state = d->priv;
+	u8 buf[1];
+	int ret;
+
+	ci_dbg("%d", slot);
+
+	if (slot)
+		return -EINVAL;
+
+	buf[0] = 0;
+
+	mutex_lock(&state->ca_mutex);
+
+	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
+	if (ret)
+		goto failed;
+
+	msleep(500);
+
+	buf[0] = 1;
+
+	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
+	if (ret)
+		goto failed;
+
+	msleep(500);
+
+	buf[0] = 0; /* FTA */
+
+	ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
+
+	msleep(1100);
+
+ failed:
+	mutex_unlock(&state->ca_mutex);
+
+	return ret;
+}
+
+static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
+{
+	u8 buf[1];
+	int ret;
+
+	if (slot)
+		return -EINVAL;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
+	if (ret)
+		return ret;
+
+	if (1 == buf[0]) {
+		return DVB_CA_EN50221_POLL_CAM_PRESENT |
+			DVB_CA_EN50221_POLL_CAM_READY;
+	}
+	return 0;
+}
+
+static void tt3650_ci_uninit(struct dvb_usb_device *d)
+{
+	struct ttusb2_state *state;
+
+	ci_dbg("");
+
+	if (NULL == d)
+		return;
+
+	state = d->priv;
+	if (NULL == state)
+		return;
+
+	if (NULL == state->ca.data)
+		return;
+
+	dvb_ca_en50221_release(&state->ca);
+
+	memset(&state->ca, 0, sizeof(state->ca));
+}
+
+static int tt3650_ci_init(struct dvb_usb_adapter *a)
+{
+	struct dvb_usb_device *d = a->dev;
+	struct ttusb2_state *state = d->priv;
+	int ret;
+
+	ci_dbg("");
+
+	mutex_init(&state->ca_mutex);
+
+	state->ca.owner = THIS_MODULE;
+	state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
+	state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
+	state->ca.read_cam_control = tt3650_ci_read_cam_control;
+	state->ca.write_cam_control = tt3650_ci_write_cam_control;
+	state->ca.slot_reset = tt3650_ci_slot_reset;
+	state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
+	state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
+	state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
+	state->ca.data = d;
+
+	ret = dvb_ca_en50221_init(&a->dvb_adap,
+				  &state->ca,
+				  /* flags */ 0,
+				  /* n_slots */ 1);
+	if (ret) {
+		err("Cannot initialize CI: Error %d.", ret);
+		memset(&state->ca, 0, sizeof(state->ca));
+		return ret;
+	}
+
+	info("CI initialized.");
+
+	return 0;
+}
+
+static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	static u8 obuf[60], ibuf[60];
+	int i, write_read, read;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	if (num > 2)
+		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+	for (i = 0; i < num; i++) {
+		write_read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
+		read = msg[i].flags & I2C_M_RD;
+
+		obuf[0] = (msg[i].addr << 1) | (write_read | read);
+		if (read)
+			obuf[1] = 0;
+		else
+			obuf[1] = msg[i].len;
+
+		/* read request */
+		if (write_read)
+			obuf[2] = msg[i+1].len;
+		else if (read)
+			obuf[2] = msg[i].len;
+		else
+			obuf[2] = 0;
+
+		memcpy(&obuf[3], msg[i].buf, msg[i].len);
+
+		if (ttusb2_msg(d, CMD_I2C_XFER, obuf, obuf[1]+3, ibuf, obuf[2] + 3) < 0) {
+			err("i2c transfer failed.");
+			break;
+		}
+
+		if (write_read) {
+			memcpy(msg[i+1].buf, &ibuf[3], msg[i+1].len);
+			i++;
+		} else if (read)
+			memcpy(msg[i].buf, &ibuf[3], msg[i].len);
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return i;
+}
+
+static u32 ttusb2_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm ttusb2_i2c_algo = {
+	.master_xfer   = ttusb2_i2c_xfer,
+	.functionality = ttusb2_i2c_func,
+};
+
+/* command to poll IR receiver (copied from pctv452e.c) */
+#define CMD_GET_IR_CODE     0x1b
+
+/* IR */
+static int tt3650_rc_query(struct dvb_usb_device *d)
+{
+	int ret;
+	u8 rx[9]; /* A CMD_GET_IR_CODE reply is 9 bytes long */
+	struct ttusb2_state *st = d->priv;
+	ret = ttusb2_msg(d, CMD_GET_IR_CODE, NULL, 0, rx, sizeof(rx));
+	if (ret != 0)
+		return ret;
+
+	if (rx[8] & 0x01) {
+		/* got a "press" event */
+		st->last_rc_key = (rx[3] << 8) | rx[2];
+		deb_info("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[2], rx[3]);
+		rc_keydown(d->rc_dev, st->last_rc_key, 0);
+	} else if (st->last_rc_key) {
+		rc_keyup(d->rc_dev);
+		st->last_rc_key = 0;
+	}
+
+	return 0;
+}
+
+
+/* Callbacks for DVB USB */
+static int ttusb2_identify_state (struct usb_device *udev, struct
+		dvb_usb_device_properties *props, struct dvb_usb_device_description **desc,
+		int *cold)
+{
+	*cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
+	return 0;
+}
+
+static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	u8 b = onoff;
+	ttusb2_msg(d, CMD_POWER, &b, 0, NULL, 0);
+	return ttusb2_msg(d, CMD_POWER, &b, 1, NULL, 0);
+}
+
+
+static struct tda10086_config tda10086_config = {
+	.demod_address = 0x0e,
+	.invert = 0,
+	.diseqc_tone = 1,
+	.xtal_freq = TDA10086_XTAL_16M,
+};
+
+static struct tda10023_config tda10023_config = {
+	.demod_address = 0x0c,
+	.invert = 0,
+	.xtal = 16000000,
+	.pll_m = 11,
+	.pll_p = 3,
+	.pll_n = 1,
+	.deltaf = 0xa511,
+};
+
+static struct tda10048_config tda10048_config = {
+	.demod_address    = 0x10 >> 1,
+	.output_mode      = TDA10048_PARALLEL_OUTPUT,
+	.inversion        = TDA10048_INVERSION_ON,
+	.dtv6_if_freq_khz = TDA10048_IF_4000,
+	.dtv7_if_freq_khz = TDA10048_IF_4500,
+	.dtv8_if_freq_khz = TDA10048_IF_5000,
+	.clk_freq_khz     = TDA10048_CLK_16000,
+	.no_firmware      = 1,
+	.set_pll          = true ,
+	.pll_m            = 5,
+	.pll_n            = 3,
+	.pll_p            = 0,
+};
+
+static struct tda827x_config tda827x_config = {
+	.config = 0,
+};
+
+static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
+{
+	if (usb_set_interface(adap->dev->udev,0,3) < 0)
+		err("set interface to alts=3 failed");
+
+	if ((adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) {
+		deb_info("TDA10086 attach failed\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int ttusb2_ct3650_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+	return adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, enable);
+}
+
+static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap)
+{
+	if (usb_set_interface(adap->dev->udev, 0, 3) < 0)
+		err("set interface to alts=3 failed");
+
+	if (adap->fe_adap[0].fe == NULL) {
+		/* FE 0 DVB-C */
+		adap->fe_adap[0].fe = dvb_attach(tda10023_attach,
+			&tda10023_config, &adap->dev->i2c_adap, 0x48);
+
+		if (adap->fe_adap[0].fe == NULL) {
+			deb_info("TDA10023 attach failed\n");
+			return -ENODEV;
+		}
+		tt3650_ci_init(adap);
+	} else {
+		adap->fe_adap[1].fe = dvb_attach(tda10048_attach,
+			&tda10048_config, &adap->dev->i2c_adap);
+
+		if (adap->fe_adap[1].fe == NULL) {
+			deb_info("TDA10048 attach failed\n");
+			return -ENODEV;
+		}
+
+		/* tuner is behind TDA10023 I2C-gate */
+		adap->fe_adap[1].fe->ops.i2c_gate_ctrl = ttusb2_ct3650_i2c_gate_ctrl;
+
+	}
+
+	return 0;
+}
+
+static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_frontend *fe;
+
+	/* MFE: select correct FE to attach tuner since that's called twice */
+	if (adap->fe_adap[1].fe == NULL)
+		fe = adap->fe_adap[0].fe;
+	else
+		fe = adap->fe_adap[1].fe;
+
+	/* attach tuner */
+	if (dvb_attach(tda827x_attach, fe, 0x61, &adap->dev->i2c_adap, &tda827x_config) == NULL) {
+		printk(KERN_ERR "%s: No tda827x found!\n", __func__);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap)
+{
+	if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) {
+		deb_info("TDA8263 attach failed\n");
+		return -ENODEV;
+	}
+
+	if (dvb_attach(lnbp21_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, 0, 0) == NULL) {
+		deb_info("LNBP21 attach failed\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties ttusb2_properties;
+static struct dvb_usb_device_properties ttusb2_properties_s2400;
+static struct dvb_usb_device_properties ttusb2_properties_ct3650;
+
+static void ttusb2_usb_disconnect(struct usb_interface *intf)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+
+	tt3650_ci_uninit(d);
+	dvb_usb_device_exit(intf);
+}
+
+static int ttusb2_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	if (0 == dvb_usb_device_init(intf, &ttusb2_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650,
+				     THIS_MODULE, NULL, adapter_nr))
+		return 0;
+	return -ENODEV;
+}
+
+static struct usb_device_id ttusb2_table [] = {
+	{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) },
+	{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) },
+	{ USB_DEVICE(USB_VID_TECHNOTREND,
+		USB_PID_TECHNOTREND_CONNECT_S2400) },
+	{ USB_DEVICE(USB_VID_TECHNOTREND,
+		USB_PID_TECHNOTREND_CONNECT_CT3650) },
+	{}		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, ttusb2_table);
+
+static struct dvb_usb_device_properties ttusb2_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-pctv-400e-01.fw",
+
+	.size_of_priv = sizeof(struct ttusb2_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = NULL, // ttusb2_streaming_ctrl,
+
+			.frontend_attach  = ttusb2_frontend_tda10086_attach,
+			.tuner_attach     = ttusb2_tuner_tda826x_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_ISOC,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.isoc = {
+						.framesperurb = 4,
+						.framesize = 940,
+						.interval = 1,
+					}
+				}
+			}
+		}},
+		}
+	},
+
+	.power_ctrl       = ttusb2_power_ctrl,
+	.identify_state   = ttusb2_identify_state,
+
+	.i2c_algo         = &ttusb2_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 2,
+	.devices = {
+		{   "Pinnacle 400e DVB-S USB2.0",
+			{ &ttusb2_table[0], NULL },
+			{ NULL },
+		},
+		{   "Pinnacle 450e DVB-S USB2.0",
+			{ &ttusb2_table[1], NULL },
+			{ NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-tt-s2400-01.fw",
+
+	.size_of_priv = sizeof(struct ttusb2_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = NULL,
+
+			.frontend_attach  = ttusb2_frontend_tda10086_attach,
+			.tuner_attach     = ttusb2_tuner_tda826x_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_ISOC,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.isoc = {
+						.framesperurb = 4,
+						.framesize = 940,
+						.interval = 1,
+					}
+				}
+			}
+		}},
+		}
+	},
+
+	.power_ctrl       = ttusb2_power_ctrl,
+	.identify_state   = ttusb2_identify_state,
+
+	.i2c_algo         = &ttusb2_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "Technotrend TT-connect S-2400",
+			{ &ttusb2_table[2], NULL },
+			{ NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = CYPRESS_FX2,
+
+	.size_of_priv = sizeof(struct ttusb2_state),
+
+	.rc.core = {
+		.rc_interval      = 150, /* Less than IR_KEYPRESS_TIMEOUT */
+		.rc_codes         = RC_MAP_TT_1500,
+		.rc_query         = tt3650_rc_query,
+		.allowed_protos   = RC_TYPE_UNKNOWN,
+	},
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 2,
+		.fe = {{
+			.streaming_ctrl   = NULL,
+
+			.frontend_attach  = ttusb2_frontend_tda10023_attach,
+			.tuner_attach = ttusb2_tuner_tda827x_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_ISOC,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.isoc = {
+						.framesperurb = 4,
+						.framesize = 940,
+						.interval = 1,
+					}
+				}
+			}
+		}, {
+			.streaming_ctrl   = NULL,
+
+			.frontend_attach  = ttusb2_frontend_tda10023_attach,
+			.tuner_attach = ttusb2_tuner_tda827x_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_ISOC,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.isoc = {
+						.framesperurb = 4,
+						.framesize = 940,
+						.interval = 1,
+					}
+				}
+			}
+		}},
+		},
+	},
+
+	.power_ctrl       = ttusb2_power_ctrl,
+	.identify_state   = ttusb2_identify_state,
+
+	.i2c_algo         = &ttusb2_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "Technotrend TT-connect CT-3650",
+			.warm_ids = { &ttusb2_table[3], NULL },
+		},
+	}
+};
+
+static struct usb_driver ttusb2_driver = {
+	.name		= "dvb_usb_ttusb2",
+	.probe		= ttusb2_probe,
+	.disconnect	= ttusb2_usb_disconnect,
+	.id_table	= ttusb2_table,
+};
+
+module_usb_driver(ttusb2_driver);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/ttusb2.h b/drivers/media/usb/dvb-usb/ttusb2.h
new file mode 100644
index 0000000..52a63af
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/ttusb2.h
@@ -0,0 +1,70 @@
+/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones
+ * (e.g. Pinnacle 400e DVB-S USB2.0).
+ *
+ * Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
+ * Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net>
+ * Copyright (C) 2005-6 Patrick Boettcher <pb@linuxtv.de>
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the Free
+ *	Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_TTUSB2_H_
+#define _DVB_USB_TTUSB2_H_
+
+/* TTUSB protocol
+ *
+ * always to messages (out/in)
+ * out message:
+ * 0xaa <id> <cmdbyte> <datalen> <data...>
+ *
+ * in message (complete block is always 0x40 bytes long)
+ * 0x55 <id> <cmdbyte> <datalen> <data...>
+ *
+ * id is incremented for each transaction
+ */
+
+#define CMD_DSP_DOWNLOAD    0x13
+/* out data: <byte>[28]
+ * last block must be empty */
+
+#define CMD_DSP_BOOT        0x14
+/* out data: nothing */
+
+#define CMD_POWER           0x15
+/* out data: <on=1/off=0> */
+
+#define CMD_LNB             0x16
+/* out data: <power=1> <18V=0,13V=1> <tone> <??=1> <??=1> */
+
+#define CMD_GET_VERSION     0x17
+/* in  data: <version_byte>[5] */
+
+#define CMD_DISEQC          0x18
+/* out data: <master=0xff/burst=??> <cmdlen> <cmdbytes>[cmdlen] */
+
+#define CMD_PID_ENABLE      0x22
+/* out data: <index> <type: ts=1/sec=2> <pid msb> <pid lsb> */
+
+#define CMD_PID_DISABLE     0x23
+/* out data: <index> */
+
+#define CMD_FILTER_ENABLE   0x24
+/* out data: <index> <pid_idx> <filter>[12] <mask>[12] */
+
+#define CMD_FILTER_DISABLE  0x25
+/* out data: <index> */
+
+#define CMD_GET_DSP_VERSION 0x26
+/* in  data: <version_byte>[28] */
+
+#define CMD_I2C_XFER        0x31
+/* out data: <addr << 1> <sndlen> <rcvlen> <data>[sndlen]
+ * in  data: <addr << 1> <sndlen> <rcvlen> <data>[rcvlen] */
+
+#define CMD_I2C_BITRATE     0x32
+/* out data: <default=0> */
+
+#endif
diff --git a/drivers/media/usb/dvb-usb/umt-010.c b/drivers/media/usb/dvb-usb/umt-010.c
new file mode 100644
index 0000000..9b04229
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/umt-010.c
@@ -0,0 +1,151 @@
+/* DVB USB framework compliant Linux driver for the HanfTek UMT-010 USB2.0
+ * DVB-T receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the Free
+ *	Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+#include "mt352.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int umt_mt352_demod_init(struct dvb_frontend *fe)
+{
+	static u8 mt352_clock_config[] = { 0x89, 0xb8, 0x2d };
+	static u8 mt352_reset[] = { 0x50, 0x80 };
+	static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 };
+	static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
+	static u8 mt352_agc_cfg[] = { 0x67, 0x10, 0xa0 };
+
+	static u8 mt352_sec_agc_cfg1[] = { 0x6a, 0xff };
+	static u8 mt352_sec_agc_cfg2[] = { 0x6d, 0xff };
+	static u8 mt352_sec_agc_cfg3[] = { 0x70, 0x40 };
+	static u8 mt352_sec_agc_cfg4[] = { 0x7b, 0x03 };
+	static u8 mt352_sec_agc_cfg5[] = { 0x7d, 0x0f };
+
+	static u8 mt352_acq_ctl[] = { 0x53, 0x50 };
+	static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x06 };
+
+	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+	udelay(2000);
+	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+	mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio));
+
+	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
+
+	mt352_write(fe, mt352_sec_agc_cfg1, sizeof(mt352_sec_agc_cfg1));
+	mt352_write(fe, mt352_sec_agc_cfg2, sizeof(mt352_sec_agc_cfg2));
+	mt352_write(fe, mt352_sec_agc_cfg3, sizeof(mt352_sec_agc_cfg3));
+	mt352_write(fe, mt352_sec_agc_cfg4, sizeof(mt352_sec_agc_cfg4));
+	mt352_write(fe, mt352_sec_agc_cfg5, sizeof(mt352_sec_agc_cfg5));
+
+	mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl));
+	mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1));
+
+	return 0;
+}
+
+static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct mt352_config umt_config;
+
+	memset(&umt_config,0,sizeof(struct mt352_config));
+	umt_config.demod_init = umt_mt352_demod_init;
+	umt_config.demod_address = 0xf;
+
+	adap->fe_adap[0].fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap);
+
+	return 0;
+}
+
+static int umt_tuner_attach (struct dvb_usb_adapter *adap)
+{
+	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_TUA6034);
+	return 0;
+}
+
+/* USB Driver stuff */
+static struct dvb_usb_device_properties umt_properties;
+
+static int umt_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	if (0 == dvb_usb_device_init(intf, &umt_properties,
+				     THIS_MODULE, NULL, adapter_nr))
+		return 0;
+	return -EINVAL;
+}
+
+/* do not change the order of the ID table */
+static struct usb_device_id umt_table [] = {
+/* 00 */	{ USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) },
+/* 01 */	{ USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) },
+			{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, umt_table);
+
+static struct dvb_usb_device_properties umt_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-umt-010-02.fw",
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = dibusb2_0_streaming_ctrl,
+			.frontend_attach  = umt_mt352_frontend_attach,
+			.tuner_attach     = umt_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = MAX_NO_URBS_FOR_DATA_STREAM,
+				.endpoint = 0x06,
+				.u = {
+					.bulk = {
+						.buffersize = 512,
+					}
+				}
+			},
+		}},
+			.size_of_priv     = sizeof(struct dibusb_state),
+		}
+	},
+	.power_ctrl       = dibusb_power_ctrl,
+
+	.i2c_algo         = &dibusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{	"Hanftek UMT-010 DVB-T USB2.0",
+			{ &umt_table[0], NULL },
+			{ &umt_table[1], NULL },
+		},
+	}
+};
+
+static struct usb_driver umt_driver = {
+	.name		= "dvb_usb_umt_010",
+	.probe		= umt_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table	= umt_table,
+};
+
+module_usb_driver(umt_driver);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for HanfTek UMT 010 USB2.0 DVB-T device");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/usb-urb.c b/drivers/media/usb/dvb-usb/usb-urb.c
new file mode 100644
index 0000000..d62ee0f
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/usb-urb.c
@@ -0,0 +1,254 @@
+/* usb-urb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file keeps functions for initializing and handling the
+ * BULK and ISOC USB data transfers in a generic way.
+ * Can be used for DVB-only and also, that's the plan, for
+ * Hybrid USB devices (analog and DVB).
+ */
+#include "dvb-usb-common.h"
+
+/* URB stuff for streaming */
+static void usb_urb_complete(struct urb *urb)
+{
+	struct usb_data_stream *stream = urb->context;
+	int ptype = usb_pipetype(urb->pipe);
+	int i;
+	u8 *b;
+
+	deb_uxfer("'%s' urb completed. status: %d, length: %d/%d, pack_num: %d, errors: %d\n",
+		ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
+		urb->status,urb->actual_length,urb->transfer_buffer_length,
+		urb->number_of_packets,urb->error_count);
+
+	switch (urb->status) {
+		case 0:         /* success */
+		case -ETIMEDOUT:    /* NAK */
+			break;
+		case -ECONNRESET:   /* kill */
+		case -ENOENT:
+		case -ESHUTDOWN:
+			return;
+		default:        /* error */
+			deb_ts("urb completition error %d.\n", urb->status);
+			break;
+	}
+
+	b = (u8 *) urb->transfer_buffer;
+	switch (ptype) {
+		case PIPE_ISOCHRONOUS:
+			for (i = 0; i < urb->number_of_packets; i++) {
+
+				if (urb->iso_frame_desc[i].status != 0)
+					deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status);
+				else if (urb->iso_frame_desc[i].actual_length > 0)
+					stream->complete(stream, b + urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length);
+
+				urb->iso_frame_desc[i].status = 0;
+				urb->iso_frame_desc[i].actual_length = 0;
+			}
+			debug_dump(b,20,deb_uxfer);
+			break;
+		case PIPE_BULK:
+			if (urb->actual_length > 0)
+				stream->complete(stream, b, urb->actual_length);
+			break;
+		default:
+			err("unknown endpoint type in completition handler.");
+			return;
+	}
+	usb_submit_urb(urb,GFP_ATOMIC);
+}
+
+int usb_urb_kill(struct usb_data_stream *stream)
+{
+	int i;
+	for (i = 0; i < stream->urbs_submitted; i++) {
+		deb_ts("killing URB no. %d.\n",i);
+
+		/* stop the URB */
+		usb_kill_urb(stream->urb_list[i]);
+	}
+	stream->urbs_submitted = 0;
+	return 0;
+}
+
+int usb_urb_submit(struct usb_data_stream *stream)
+{
+	int i,ret;
+	for (i = 0; i < stream->urbs_initialized; i++) {
+		deb_ts("submitting URB no. %d\n",i);
+		if ((ret = usb_submit_urb(stream->urb_list[i],GFP_ATOMIC))) {
+			err("could not submit URB no. %d - get them all back",i);
+			usb_urb_kill(stream);
+			return ret;
+		}
+		stream->urbs_submitted++;
+	}
+	return 0;
+}
+
+static int usb_free_stream_buffers(struct usb_data_stream *stream)
+{
+	if (stream->state & USB_STATE_URB_BUF) {
+		while (stream->buf_num) {
+			stream->buf_num--;
+			deb_mem("freeing buffer %d\n",stream->buf_num);
+			usb_free_coherent(stream->udev, stream->buf_size,
+					  stream->buf_list[stream->buf_num],
+					  stream->dma_addr[stream->buf_num]);
+		}
+	}
+
+	stream->state &= ~USB_STATE_URB_BUF;
+
+	return 0;
+}
+
+static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, unsigned long size)
+{
+	stream->buf_num = 0;
+	stream->buf_size = size;
+
+	deb_mem("all in all I will use %lu bytes for streaming\n",num*size);
+
+	for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
+		deb_mem("allocating buffer %d\n",stream->buf_num);
+		if (( stream->buf_list[stream->buf_num] =
+					usb_alloc_coherent(stream->udev, size, GFP_ATOMIC,
+					&stream->dma_addr[stream->buf_num]) ) == NULL) {
+			deb_mem("not enough memory for urb-buffer allocation.\n");
+			usb_free_stream_buffers(stream);
+			return -ENOMEM;
+		}
+		deb_mem("buffer %d: %p (dma: %Lu)\n",
+			stream->buf_num,
+stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]);
+		memset(stream->buf_list[stream->buf_num],0,size);
+		stream->state |= USB_STATE_URB_BUF;
+	}
+	deb_mem("allocation successful\n");
+
+	return 0;
+}
+
+static int usb_bulk_urb_init(struct usb_data_stream *stream)
+{
+	int i, j;
+
+	if ((i = usb_allocate_stream_buffers(stream,stream->props.count,
+					stream->props.u.bulk.buffersize)) < 0)
+		return i;
+
+	/* allocate the URBs */
+	for (i = 0; i < stream->props.count; i++) {
+		stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
+		if (!stream->urb_list[i]) {
+			deb_mem("not enough memory for urb_alloc_urb!.\n");
+			for (j = 0; j < i; j++)
+				usb_free_urb(stream->urb_list[j]);
+			return -ENOMEM;
+		}
+		usb_fill_bulk_urb( stream->urb_list[i], stream->udev,
+				usb_rcvbulkpipe(stream->udev,stream->props.endpoint),
+				stream->buf_list[i],
+				stream->props.u.bulk.buffersize,
+				usb_urb_complete, stream);
+
+		stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+		stream->urb_list[i]->transfer_dma = stream->dma_addr[i];
+		stream->urbs_initialized++;
+	}
+	return 0;
+}
+
+static int usb_isoc_urb_init(struct usb_data_stream *stream)
+{
+	int i,j;
+
+	if ((i = usb_allocate_stream_buffers(stream,stream->props.count,
+					stream->props.u.isoc.framesize*stream->props.u.isoc.framesperurb)) < 0)
+		return i;
+
+	/* allocate the URBs */
+	for (i = 0; i < stream->props.count; i++) {
+		struct urb *urb;
+		int frame_offset = 0;
+
+		stream->urb_list[i] = usb_alloc_urb(stream->props.u.isoc.framesperurb, GFP_ATOMIC);
+		if (!stream->urb_list[i]) {
+			deb_mem("not enough memory for urb_alloc_urb!\n");
+			for (j = 0; j < i; j++)
+				usb_free_urb(stream->urb_list[j]);
+			return -ENOMEM;
+		}
+
+		urb = stream->urb_list[i];
+
+		urb->dev = stream->udev;
+		urb->context = stream;
+		urb->complete = usb_urb_complete;
+		urb->pipe = usb_rcvisocpipe(stream->udev,stream->props.endpoint);
+		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+		urb->interval = stream->props.u.isoc.interval;
+		urb->number_of_packets = stream->props.u.isoc.framesperurb;
+		urb->transfer_buffer_length = stream->buf_size;
+		urb->transfer_buffer = stream->buf_list[i];
+		urb->transfer_dma = stream->dma_addr[i];
+
+		for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
+			urb->iso_frame_desc[j].offset = frame_offset;
+			urb->iso_frame_desc[j].length = stream->props.u.isoc.framesize;
+			frame_offset += stream->props.u.isoc.framesize;
+		}
+
+		stream->urbs_initialized++;
+	}
+	return 0;
+}
+
+int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props)
+{
+	if (stream == NULL || props == NULL)
+		return -EINVAL;
+
+	memcpy(&stream->props, props, sizeof(*props));
+
+	usb_clear_halt(stream->udev,usb_rcvbulkpipe(stream->udev,stream->props.endpoint));
+
+	if (stream->complete == NULL) {
+		err("there is no data callback - this doesn't make sense.");
+		return -EINVAL;
+	}
+
+	switch (stream->props.type) {
+		case USB_BULK:
+			return usb_bulk_urb_init(stream);
+		case USB_ISOC:
+			return usb_isoc_urb_init(stream);
+		default:
+			err("unknown URB-type for data transfer.");
+			return -EINVAL;
+	}
+}
+
+int usb_urb_exit(struct usb_data_stream *stream)
+{
+	int i;
+
+	usb_urb_kill(stream);
+
+	for (i = 0; i < stream->urbs_initialized; i++) {
+		if (stream->urb_list[i] != NULL) {
+			deb_mem("freeing URB no. %d.\n",i);
+			/* free the URBs */
+			usb_free_urb(stream->urb_list[i]);
+		}
+	}
+	stream->urbs_initialized = 0;
+
+	usb_free_stream_buffers(stream);
+	return 0;
+}
diff --git a/drivers/media/usb/dvb-usb/vp702x-fe.c b/drivers/media/usb/dvb-usb/vp702x-fe.c
new file mode 100644
index 0000000..5eab468
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/vp702x-fe.c
@@ -0,0 +1,379 @@
+/* DVB frontend part of the Linux driver for the TwinhanDTV StarBox USB2.0
+ * DVB-S receiver.
+ *
+ * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
+ *                    Metzler Brothers Systementwicklung GbR
+ *
+ * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
+ *
+ * Thanks to Twinhan who kindly provided hardware and information.
+ *
+ * This file can be removed soon, after the DST-driver is rewritten to provice
+ * the frontend-controlling separately.
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ *
+ */
+#include "vp702x.h"
+
+struct vp702x_fe_state {
+	struct dvb_frontend fe;
+	struct dvb_usb_device *d;
+
+	struct dvb_frontend_ops ops;
+
+	fe_sec_voltage_t voltage;
+	fe_sec_tone_mode_t tone_mode;
+
+	u8 lnb_buf[8];
+
+	u8 lock;
+	u8 sig;
+	u8 snr;
+
+	unsigned long next_status_check;
+	unsigned long status_check_interval;
+};
+
+static int vp702x_fe_refresh_state(struct vp702x_fe_state *st)
+{
+	struct vp702x_device_state *dst = st->d->priv;
+	u8 *buf;
+
+	if (time_after(jiffies, st->next_status_check)) {
+		mutex_lock(&dst->buf_mutex);
+		buf = dst->buf;
+
+		vp702x_usb_in_op(st->d, READ_STATUS, 0, 0, buf, 10);
+		st->lock = buf[4];
+
+		vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x11, 0, buf, 1);
+		st->snr = buf[0];
+
+		vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x15, 0, buf, 1);
+		st->sig = buf[0];
+
+		mutex_unlock(&dst->buf_mutex);
+		st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
+	}
+	return 0;
+}
+
+static u8 vp702x_chksum(u8 *buf,int f, int count)
+{
+	u8 s = 0;
+	int i;
+	for (i = f; i < f+count; i++)
+		s += buf[i];
+	return ~s+1;
+}
+
+static int vp702x_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
+{
+	struct vp702x_fe_state *st = fe->demodulator_priv;
+	vp702x_fe_refresh_state(st);
+	deb_fe("%s\n",__func__);
+
+	if (st->lock == 0)
+		*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
+	else
+		*status = 0;
+
+	if (*status & FE_HAS_LOCK)
+		st->status_check_interval = 1000;
+	else
+		st->status_check_interval = 250;
+	return 0;
+}
+
+/* not supported by this Frontend */
+static int vp702x_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+	struct vp702x_fe_state *st = fe->demodulator_priv;
+	vp702x_fe_refresh_state(st);
+	*ber = 0;
+	return 0;
+}
+
+/* not supported by this Frontend */
+static int vp702x_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+	struct vp702x_fe_state *st = fe->demodulator_priv;
+	vp702x_fe_refresh_state(st);
+	*unc = 0;
+	return 0;
+}
+
+static int vp702x_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+	struct vp702x_fe_state *st = fe->demodulator_priv;
+	vp702x_fe_refresh_state(st);
+
+	*strength = (st->sig << 8) | st->sig;
+	return 0;
+}
+
+static int vp702x_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+	u8 _snr;
+	struct vp702x_fe_state *st = fe->demodulator_priv;
+	vp702x_fe_refresh_state(st);
+
+	_snr = (st->snr & 0x1f) * 0xff / 0x1f;
+	*snr = (_snr << 8) | _snr;
+	return 0;
+}
+
+static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+	deb_fe("%s\n",__func__);
+	tune->min_delay_ms = 2000;
+	return 0;
+}
+
+static int vp702x_fe_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
+	struct vp702x_fe_state *st = fe->demodulator_priv;
+	struct vp702x_device_state *dst = st->d->priv;
+	u32 freq = fep->frequency/1000;
+	/*CalFrequency*/
+/*	u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */
+	u64 sr;
+	u8 *cmd;
+
+	mutex_lock(&dst->buf_mutex);
+
+	cmd = dst->buf;
+	memset(cmd, 0, 10);
+
+	cmd[0] = (freq >> 8) & 0x7f;
+	cmd[1] =  freq       & 0xff;
+	cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */
+
+	sr = (u64) (fep->symbol_rate/1000) << 20;
+	do_div(sr,88000);
+	cmd[3] = (sr >> 12) & 0xff;
+	cmd[4] = (sr >> 4)  & 0xff;
+	cmd[5] = (sr << 4)  & 0xf0;
+
+	deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n",
+			fep->frequency, freq, freq, fep->symbol_rate,
+			(unsigned long) sr, (unsigned long) sr);
+
+/*	if (fep->inversion == INVERSION_ON)
+		cmd[6] |= 0x80; */
+
+	if (st->voltage == SEC_VOLTAGE_18)
+		cmd[6] |= 0x40;
+
+/*	if (fep->symbol_rate > 8000000)
+		cmd[6] |= 0x20;
+
+	if (fep->frequency < 1531000)
+		cmd[6] |= 0x04;
+
+	if (st->tone_mode == SEC_TONE_ON)
+		cmd[6] |= 0x01;*/
+
+	cmd[7] = vp702x_chksum(cmd,0,7);
+
+	st->status_check_interval = 250;
+	st->next_status_check = jiffies;
+
+	vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100);
+
+	if (cmd[2] == 0 && cmd[3] == 0)
+		deb_fe("tuning failed.\n");
+	else
+		deb_fe("tuning succeeded.\n");
+
+	mutex_unlock(&dst->buf_mutex);
+
+	return 0;
+}
+
+static int vp702x_fe_init(struct dvb_frontend *fe)
+{
+	struct vp702x_fe_state *st = fe->demodulator_priv;
+	deb_fe("%s\n",__func__);
+	vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0);
+	return 0;
+}
+
+static int vp702x_fe_sleep(struct dvb_frontend *fe)
+{
+	deb_fe("%s\n",__func__);
+	return 0;
+}
+
+static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
+				    struct dvb_diseqc_master_cmd *m)
+{
+	u8 *cmd;
+	struct vp702x_fe_state *st = fe->demodulator_priv;
+	struct vp702x_device_state *dst = st->d->priv;
+
+	deb_fe("%s\n",__func__);
+
+	if (m->msg_len > 4)
+		return -EINVAL;
+
+	mutex_lock(&dst->buf_mutex);
+
+	cmd = dst->buf;
+	cmd[1] = SET_DISEQC_CMD;
+	cmd[2] = m->msg_len;
+	memcpy(&cmd[3], m->msg, m->msg_len);
+	cmd[7] = vp702x_chksum(cmd, 0, 7);
+
+	vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100);
+
+	if (cmd[2] == 0 && cmd[3] == 0)
+		deb_fe("diseqc cmd failed.\n");
+	else
+		deb_fe("diseqc cmd succeeded.\n");
+
+	mutex_unlock(&dst->buf_mutex);
+
+	return 0;
+}
+
+static int vp702x_fe_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
+{
+	deb_fe("%s\n",__func__);
+	return 0;
+}
+
+static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct vp702x_fe_state *st = fe->demodulator_priv;
+	struct vp702x_device_state *dst = st->d->priv;
+	u8 *buf;
+
+	deb_fe("%s\n",__func__);
+
+	st->tone_mode = tone;
+
+	if (tone == SEC_TONE_ON)
+		st->lnb_buf[2] = 0x02;
+	else
+		st->lnb_buf[2] = 0x00;
+
+	st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7);
+
+	mutex_lock(&dst->buf_mutex);
+
+	buf = dst->buf;
+	memcpy(buf, st->lnb_buf, 8);
+
+	vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100);
+	if (buf[2] == 0 && buf[3] == 0)
+		deb_fe("set_tone cmd failed.\n");
+	else
+		deb_fe("set_tone cmd succeeded.\n");
+
+	mutex_unlock(&dst->buf_mutex);
+
+	return 0;
+}
+
+static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t
+		voltage)
+{
+	struct vp702x_fe_state *st = fe->demodulator_priv;
+	struct vp702x_device_state *dst = st->d->priv;
+	u8 *buf;
+	deb_fe("%s\n",__func__);
+
+	st->voltage = voltage;
+
+	if (voltage != SEC_VOLTAGE_OFF)
+		st->lnb_buf[4] = 0x01;
+	else
+		st->lnb_buf[4] = 0x00;
+
+	st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7);
+
+	mutex_lock(&dst->buf_mutex);
+
+	buf = dst->buf;
+	memcpy(buf, st->lnb_buf, 8);
+
+	vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100);
+	if (buf[2] == 0 && buf[3] == 0)
+		deb_fe("set_voltage cmd failed.\n");
+	else
+		deb_fe("set_voltage cmd succeeded.\n");
+
+	mutex_unlock(&dst->buf_mutex);
+	return 0;
+}
+
+static void vp702x_fe_release(struct dvb_frontend* fe)
+{
+	struct vp702x_fe_state *st = fe->demodulator_priv;
+	kfree(st);
+}
+
+static struct dvb_frontend_ops vp702x_fe_ops;
+
+struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d)
+{
+	struct vp702x_fe_state *s = kzalloc(sizeof(struct vp702x_fe_state), GFP_KERNEL);
+	if (s == NULL)
+		goto error;
+
+	s->d = d;
+
+	memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops));
+	s->fe.demodulator_priv = s;
+
+	s->lnb_buf[1] = SET_LNB_POWER;
+	s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */
+
+	return &s->fe;
+error:
+	return NULL;
+}
+
+
+static struct dvb_frontend_ops vp702x_fe_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name           = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S",
+		.frequency_min       = 950000,
+		.frequency_max       = 2150000,
+		.frequency_stepsize  = 1000,   /* kHz for QPSK frontends */
+		.frequency_tolerance = 0,
+		.symbol_rate_min     = 1000000,
+		.symbol_rate_max     = 45000000,
+		.symbol_rate_tolerance = 500,  /* ppm */
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+		FE_CAN_QPSK |
+		FE_CAN_FEC_AUTO
+	},
+	.release = vp702x_fe_release,
+
+	.init  = vp702x_fe_init,
+	.sleep = vp702x_fe_sleep,
+
+	.set_frontend = vp702x_fe_set_frontend,
+	.get_tune_settings = vp702x_fe_get_tune_settings,
+
+	.read_status = vp702x_fe_read_status,
+	.read_ber = vp702x_fe_read_ber,
+	.read_signal_strength = vp702x_fe_read_signal_strength,
+	.read_snr = vp702x_fe_read_snr,
+	.read_ucblocks = vp702x_fe_read_unc_blocks,
+
+	.diseqc_send_master_cmd = vp702x_fe_send_diseqc_msg,
+	.diseqc_send_burst = vp702x_fe_send_diseqc_burst,
+	.set_tone = vp702x_fe_set_tone,
+	.set_voltage = vp702x_fe_set_voltage,
+};
diff --git a/drivers/media/usb/dvb-usb/vp702x.c b/drivers/media/usb/dvb-usb/vp702x.c
new file mode 100644
index 0000000..07c673a
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/vp702x.c
@@ -0,0 +1,444 @@
+/* DVB USB compliant Linux driver for the TwinhanDTV StarBox USB2.0 DVB-S
+ * receiver.
+ *
+ * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
+ *                    Metzler Brothers Systementwicklung GbR
+ *
+ * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
+ *
+ * Thanks to Twinhan who kindly provided hardware and information.
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "vp702x.h"
+#include <linux/mutex.h>
+
+/* debug */
+int dvb_usb_vp702x_debug;
+module_param_named(debug,dvb_usb_vp702x_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct vp702x_adapter_state {
+	int pid_filter_count;
+	int pid_filter_can_bypass;
+	u8  pid_filter_state;
+};
+
+static int vp702x_usb_in_op_unlocked(struct dvb_usb_device *d, u8 req,
+				     u16 value, u16 index, u8 *b, int blen)
+{
+	int ret;
+
+	ret = usb_control_msg(d->udev,
+		usb_rcvctrlpipe(d->udev, 0),
+		req,
+		USB_TYPE_VENDOR | USB_DIR_IN,
+		value, index, b, blen,
+		2000);
+
+	if (ret < 0) {
+		warn("usb in operation failed. (%d)", ret);
+		ret = -EIO;
+	} else
+		ret = 0;
+
+
+	deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
+	debug_dump(b,blen,deb_xfer);
+
+	return ret;
+}
+
+int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value,
+			    u16 index, u8 *b, int blen)
+{
+	int ret;
+
+	mutex_lock(&d->usb_mutex);
+	ret = vp702x_usb_in_op_unlocked(d, req, value, index, b, blen);
+	mutex_unlock(&d->usb_mutex);
+
+	return ret;
+}
+
+int vp702x_usb_out_op_unlocked(struct dvb_usb_device *d, u8 req, u16 value,
+				      u16 index, u8 *b, int blen)
+{
+	int ret;
+	deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
+	debug_dump(b,blen,deb_xfer);
+
+	if ((ret = usb_control_msg(d->udev,
+			usb_sndctrlpipe(d->udev,0),
+			req,
+			USB_TYPE_VENDOR | USB_DIR_OUT,
+			value,index,b,blen,
+			2000)) != blen) {
+		warn("usb out operation failed. (%d)",ret);
+		return -EIO;
+	} else
+		return 0;
+}
+
+int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+			     u16 index, u8 *b, int blen)
+{
+	int ret;
+
+	mutex_lock(&d->usb_mutex);
+	ret = vp702x_usb_out_op_unlocked(d, req, value, index, b, blen);
+	mutex_unlock(&d->usb_mutex);
+
+	return ret;
+}
+
+int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec)
+{
+	int ret;
+
+	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+		return ret;
+
+	ret = vp702x_usb_out_op_unlocked(d, REQUEST_OUT, 0, 0, o, olen);
+	msleep(msec);
+	ret = vp702x_usb_in_op_unlocked(d, REQUEST_IN, 0, 0, i, ilen);
+
+	mutex_unlock(&d->usb_mutex);
+	return ret;
+}
+
+static int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o,
+				int olen, u8 *i, int ilen, int msec)
+{
+	struct vp702x_device_state *st = d->priv;
+	int ret = 0;
+	u8 *buf;
+	int buflen = max(olen + 2, ilen + 1);
+
+	ret = mutex_lock_interruptible(&st->buf_mutex);
+	if (ret < 0)
+		return ret;
+
+	if (buflen > st->buf_len) {
+		buf = kmalloc(buflen, GFP_KERNEL);
+		if (!buf) {
+			mutex_unlock(&st->buf_mutex);
+			return -ENOMEM;
+		}
+		info("successfully reallocated a bigger buffer");
+		kfree(st->buf);
+		st->buf = buf;
+		st->buf_len = buflen;
+	} else {
+		buf = st->buf;
+	}
+
+	buf[0] = 0x00;
+	buf[1] = cmd;
+	memcpy(&buf[2], o, olen);
+
+	ret = vp702x_usb_inout_op(d, buf, olen+2, buf, ilen+1, msec);
+
+	if (ret == 0)
+		memcpy(i, &buf[1], ilen);
+	mutex_unlock(&st->buf_mutex);
+
+	return ret;
+}
+
+static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass)
+{
+	int ret;
+	struct vp702x_device_state *st = adap->dev->priv;
+	u8 *buf;
+
+	mutex_lock(&st->buf_mutex);
+
+	buf = st->buf;
+	memset(buf, 0, 16);
+
+	ret = vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e,
+			0, buf, 16);
+	mutex_unlock(&st->buf_mutex);
+	return ret;
+}
+
+static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state)
+{
+	int ret;
+	struct vp702x_device_state *st = adap->dev->priv;
+	u8 *buf;
+
+	mutex_lock(&st->buf_mutex);
+
+	buf = st->buf;
+	memset(buf, 0, 16);
+	ret = vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f,
+			0, buf, 16);
+
+	mutex_unlock(&st->buf_mutex);
+
+	return ret;
+}
+
+static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff)
+{
+	struct vp702x_adapter_state *st = adap->priv;
+	struct vp702x_device_state *dst = adap->dev->priv;
+	u8 *buf;
+
+	if (onoff)
+		st->pid_filter_state |=  (1 << id);
+	else {
+		st->pid_filter_state &= ~(1 << id);
+		pid = 0xffff;
+	}
+
+	id = 0x10 + id*2;
+
+	vp702x_set_pld_state(adap, st->pid_filter_state);
+
+	mutex_lock(&dst->buf_mutex);
+
+	buf = dst->buf;
+	memset(buf, 0, 16);
+	vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16);
+	vp702x_usb_in_op(adap->dev, 0xe0, (((pid     ) & 0xff) << 8) | (id+1), 0, buf, 16);
+
+	mutex_unlock(&dst->buf_mutex);
+
+	return 0;
+}
+
+
+static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap)
+{
+	struct vp702x_adapter_state *st = adap->priv;
+	struct vp702x_device_state *dst = adap->dev->priv;
+	int i;
+	u8 *b;
+
+	st->pid_filter_count = 8;
+	st->pid_filter_can_bypass = 1;
+	st->pid_filter_state = 0x00;
+
+	vp702x_set_pld_mode(adap, 1); /* bypass */
+
+	for (i = 0; i < st->pid_filter_count; i++)
+		vp702x_set_pid(adap, 0xffff, i, 1);
+
+	mutex_lock(&dst->buf_mutex);
+	b = dst->buf;
+	memset(b, 0, 10);
+	vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10);
+	vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10);
+	vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10);
+	mutex_unlock(&dst->buf_mutex);
+	/*vp702x_set_pld_mode(d, 0); // filter */
+
+	return 0;
+}
+
+static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	return 0;
+}
+
+/* keys for the enclosed remote control */
+static struct rc_map_table rc_map_vp702x_table[] = {
+	{ 0x0001, KEY_1 },
+	{ 0x0002, KEY_2 },
+};
+
+/* remote control stuff (does not work with my box) */
+static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	u8 *key;
+	int i;
+
+/* remove the following return to enabled remote querying */
+	return 0;
+
+	key = kmalloc(10, GFP_KERNEL);
+	if (!key)
+		return -ENOMEM;
+
+	vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
+
+	deb_rc("remote query key: %x %d\n",key[1],key[1]);
+
+	if (key[1] == 0x44) {
+		*state = REMOTE_NO_KEY_PRESSED;
+		kfree(key);
+		return 0;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(rc_map_vp702x_table); i++)
+		if (rc5_custom(&rc_map_vp702x_table[i]) == key[1]) {
+			*state = REMOTE_KEY_PRESSED;
+			*event = rc_map_vp702x_table[i].keycode;
+			break;
+		}
+	kfree(key);
+	return 0;
+}
+
+
+static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
+{
+	u8 i, *buf;
+	struct vp702x_device_state *st = d->priv;
+
+	mutex_lock(&st->buf_mutex);
+	buf = st->buf;
+	for (i = 6; i < 12; i++)
+		vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &buf[i - 6], 1);
+
+	memcpy(mac, buf, 6);
+	mutex_unlock(&st->buf_mutex);
+	return 0;
+}
+
+static int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	u8 buf[10] = { 0 };
+
+	vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
+
+	if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0,
+				   buf, 10, 10))
+		return -EIO;
+
+	buf[9] = '\0';
+	info("system string: %s",&buf[1]);
+
+	vp702x_init_pid_filter(adap);
+
+	adap->fe_adap[0].fe = vp702x_fe_attach(adap->dev);
+	vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
+
+	return 0;
+}
+
+static struct dvb_usb_device_properties vp702x_properties;
+
+static int vp702x_usb_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	struct dvb_usb_device *d;
+	struct vp702x_device_state *st;
+	int ret;
+
+	ret = dvb_usb_device_init(intf, &vp702x_properties,
+				   THIS_MODULE, &d, adapter_nr);
+	if (ret)
+		goto out;
+
+	st = d->priv;
+	st->buf_len = 16;
+	st->buf = kmalloc(st->buf_len, GFP_KERNEL);
+	if (!st->buf) {
+		ret = -ENOMEM;
+		dvb_usb_device_exit(intf);
+		goto out;
+	}
+	mutex_init(&st->buf_mutex);
+
+out:
+	return ret;
+
+}
+
+static void vp702x_usb_disconnect(struct usb_interface *intf)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+	struct vp702x_device_state *st = d->priv;
+	mutex_lock(&st->buf_mutex);
+	kfree(st->buf);
+	mutex_unlock(&st->buf_mutex);
+	dvb_usb_device_exit(intf);
+}
+
+static struct usb_device_id vp702x_usb_table [] = {
+	    { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) },
+//	    { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) },
+//	    { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) },
+	    { 0 },
+};
+MODULE_DEVICE_TABLE(usb, vp702x_usb_table);
+
+static struct dvb_usb_device_properties vp702x_properties = {
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware            = "dvb-usb-vp702x-02.fw",
+	.no_reconnect        = 1,
+
+	.size_of_priv     = sizeof(struct vp702x_device_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.caps             = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
+
+			.streaming_ctrl   = vp702x_streaming_ctrl,
+			.frontend_attach  = vp702x_frontend_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 10,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+			.size_of_priv     = sizeof(struct vp702x_adapter_state),
+		}
+	},
+	.read_mac_address = vp702x_read_mac_addr,
+
+	.rc.legacy = {
+		.rc_map_table       = rc_map_vp702x_table,
+		.rc_map_size  = ARRAY_SIZE(rc_map_vp702x_table),
+		.rc_interval      = 400,
+		.rc_query         = vp702x_rc_query,
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)",
+		  .cold_ids = { &vp702x_usb_table[0], NULL },
+		  .warm_ids = { NULL },
+		},
+/*		{ .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)",
+		  .cold_ids = { &vp702x_usb_table[2], NULL },
+		  .warm_ids = { &vp702x_usb_table[3], NULL },
+		},
+*/		{ NULL },
+	}
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver vp702x_usb_driver = {
+	.name		= "dvb_usb_vp702x",
+	.probe		= vp702x_usb_probe,
+	.disconnect	= vp702x_usb_disconnect,
+	.id_table	= vp702x_usb_table,
+};
+
+module_usb_driver(vp702x_usb_driver);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/vp702x.h b/drivers/media/usb/dvb-usb/vp702x.h
new file mode 100644
index 0000000..20b9005
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/vp702x.h
@@ -0,0 +1,113 @@
+#ifndef _DVB_USB_VP7021_H_
+#define _DVB_USB_VP7021_H_
+
+#define DVB_USB_LOG_PREFIX "vp702x"
+#include "dvb-usb.h"
+
+extern int dvb_usb_vp702x_debug;
+#define deb_info(args...) dprintk(dvb_usb_vp702x_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_vp702x_debug,0x02,args)
+#define deb_rc(args...)   dprintk(dvb_usb_vp702x_debug,0x04,args)
+#define deb_fe(args...)   dprintk(dvb_usb_vp702x_debug,0x08,args)
+
+/* commands are read and written with USB control messages */
+
+/* consecutive read/write operation */
+#define REQUEST_OUT		0xB2
+#define REQUEST_IN		0xB3
+
+/* the out-buffer of these consecutive operations contain sub-commands when b[0] = 0
+ * request: 0xB2; i: 0; v: 0; b[0] = 0, b[1] = subcmd, additional buffer
+ * the returning buffer looks as follows
+ * request: 0xB3; i: 0; v: 0; b[0] = 0xB3, additional buffer */
+
+#define GET_TUNER_STATUS	0x05
+/* additional in buffer:
+ * 0   1   2    3              4   5   6               7       8
+ * N/A N/A 0x05 signal-quality N/A N/A signal-strength lock==0 N/A */
+
+#define GET_SYSTEM_STRING	0x06
+/* additional in buffer:
+ * 0   1   2   3   4   5   6   7   8
+ * N/A 'U' 'S' 'B' '7' '0' '2' 'X' N/A */
+
+#define SET_DISEQC_CMD		0x08
+/* additional out buffer:
+ * 0    1  2  3  4
+ * len  X1 X2 X3 X4
+ * additional in buffer:
+ * 0   1 2
+ * N/A 0 0   b[1] == b[2] == 0 -> success, failure otherwise */
+
+#define SET_LNB_POWER		0x09
+/* additional out buffer:
+ * 0    1    2
+ * 0x00 0xff 1 = on, 0 = off
+ * additional in buffer:
+ * 0   1 2
+ * N/A 0 0   b[1] == b[2] == 0 -> success failure otherwise */
+
+#define GET_MAC_ADDRESS		0x0A
+/* #define GET_MAC_ADDRESS   0x0B */
+/* additional in buffer:
+ * 0   1   2            3    4    5    6    7    8
+ * N/A N/A 0x0A or 0x0B MAC0 MAC1 MAC2 MAC3 MAC4 MAC5 */
+
+#define SET_PID_FILTER		0x11
+/* additional in buffer:
+ * 0        1        ... 14       15       16
+ * PID0_MSB PID0_LSB ... PID7_MSB PID7_LSB PID_active (bits) */
+
+/* request: 0xB2; i: 0; v: 0;
+ * b[0] != 0 -> tune and lock a channel
+ * 0     1     2       3      4      5      6    7
+ * freq0 freq1 divstep srate0 srate1 srate2 flag chksum
+ */
+
+/* one direction requests */
+#define READ_REMOTE_REQ		0xB4
+/* IN  i: 0; v: 0; b[0] == request, b[1] == key */
+
+#define READ_PID_NUMBER_REQ	0xB5
+/* IN  i: 0; v: 0; b[0] == request, b[1] == 0, b[2] = pid number */
+
+#define WRITE_EEPROM_REQ	0xB6
+/* OUT i: offset; v: value to write; no extra buffer */
+
+#define READ_EEPROM_REQ		0xB7
+/* IN  i: bufferlen; v: offset; buffer with bufferlen bytes */
+
+#define READ_STATUS		0xB8
+/* IN  i: 0; v: 0; bufferlen 10 */
+
+#define READ_TUNER_REG_REQ	0xB9
+/* IN  i: 0; v: register; b[0] = value */
+
+#define READ_FX2_REG_REQ	0xBA
+/* IN  i: offset; v: 0; b[0] = value */
+
+#define WRITE_FX2_REG_REQ	0xBB
+/* OUT i: offset; v: value to write; 1 byte extra buffer */
+
+#define SET_TUNER_POWER_REQ	0xBC
+/* IN  i: 0 = power off, 1 = power on */
+
+#define WRITE_TUNER_REG_REQ	0xBD
+/* IN  i: register, v: value to write, no extra buffer */
+
+#define RESET_TUNER		0xBE
+/* IN  i: 0, v: 0, no extra buffer */
+
+struct vp702x_device_state {
+	struct mutex buf_mutex;
+	int buf_len;
+	u8 *buf;
+};
+
+
+extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d);
+
+extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec);
+extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
+
+#endif
diff --git a/drivers/media/usb/dvb-usb/vp7045-fe.c b/drivers/media/usb/dvb-usb/vp7045-fe.c
new file mode 100644
index 0000000..b8825b1
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/vp7045-fe.c
@@ -0,0 +1,190 @@
+/* DVB frontend part of the Linux driver for TwinhanDTV Alpha/MagicBoxII USB2.0
+ * DVB-T receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * Thanks to Twinhan who kindly provided hardware and information.
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ *
+ */
+#include "vp7045.h"
+
+/* It is a Zarlink MT352 within a Samsung Tuner (DNOS404ZH102A) - 040929 - AAT
+ *
+ * Programming is hidden inside the firmware, so set_frontend is very easy.
+ * Even though there is a Firmware command that one can use to access the demod
+ * via its registers. This is used for status information.
+ */
+
+struct vp7045_fe_state {
+	struct dvb_frontend fe;
+	struct dvb_usb_device *d;
+};
+
+static int vp7045_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
+{
+	struct vp7045_fe_state *state = fe->demodulator_priv;
+	u8 s0 = vp7045_read_reg(state->d,0x00),
+	   s1 = vp7045_read_reg(state->d,0x01),
+	   s3 = vp7045_read_reg(state->d,0x03);
+
+	*status = 0;
+	if (s0 & (1 << 4))
+		*status |= FE_HAS_CARRIER;
+	if (s0 & (1 << 1))
+		*status |= FE_HAS_VITERBI;
+	if (s0 & (1 << 5))
+		*status |= FE_HAS_LOCK;
+	if (s1 & (1 << 1))
+		*status |= FE_HAS_SYNC;
+	if (s3 & (1 << 6))
+		*status |= FE_HAS_SIGNAL;
+
+	if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
+			(FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
+		*status &= ~FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int vp7045_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+	struct vp7045_fe_state *state = fe->demodulator_priv;
+	*ber = (vp7045_read_reg(state->d, 0x0D) << 16) |
+	       (vp7045_read_reg(state->d, 0x0E) << 8) |
+		vp7045_read_reg(state->d, 0x0F);
+	return 0;
+}
+
+static int vp7045_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+	struct vp7045_fe_state *state = fe->demodulator_priv;
+	*unc = (vp7045_read_reg(state->d, 0x10) << 8) |
+		    vp7045_read_reg(state->d, 0x11);
+	return 0;
+}
+
+static int vp7045_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+	struct vp7045_fe_state *state = fe->demodulator_priv;
+	u16 signal = (vp7045_read_reg(state->d, 0x14) << 8) |
+		vp7045_read_reg(state->d, 0x15);
+
+	*strength = ~signal;
+	return 0;
+}
+
+static int vp7045_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+	struct vp7045_fe_state *state = fe->demodulator_priv;
+	u8 _snr = vp7045_read_reg(state->d, 0x09);
+	*snr = (_snr << 8) | _snr;
+	return 0;
+}
+
+static int vp7045_fe_init(struct dvb_frontend* fe)
+{
+	return 0;
+}
+
+static int vp7045_fe_sleep(struct dvb_frontend* fe)
+{
+	return 0;
+}
+
+static int vp7045_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 800;
+	return 0;
+}
+
+static int vp7045_fe_set_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
+	struct vp7045_fe_state *state = fe->demodulator_priv;
+	u8 buf[5];
+	u32 freq = fep->frequency / 1000;
+
+	buf[0] = (freq >> 16) & 0xff;
+	buf[1] = (freq >>  8) & 0xff;
+	buf[2] =  freq        & 0xff;
+	buf[3] = 0;
+
+	switch (fep->bandwidth_hz) {
+	case 8000000:
+		buf[4] = 8;
+		break;
+	case 7000000:
+		buf[4] = 7;
+		break;
+	case 6000000:
+		buf[4] = 6;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	vp7045_usb_op(state->d,LOCK_TUNER_COMMAND,buf,5,NULL,0,200);
+	return 0;
+}
+
+static void vp7045_fe_release(struct dvb_frontend* fe)
+{
+	struct vp7045_fe_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops vp7045_fe_ops;
+
+struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d)
+{
+	struct vp7045_fe_state *s = kzalloc(sizeof(struct vp7045_fe_state), GFP_KERNEL);
+	if (s == NULL)
+		goto error;
+
+	s->d = d;
+	memcpy(&s->fe.ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops));
+	s->fe.demodulator_priv = s;
+
+	return &s->fe;
+error:
+	return NULL;
+}
+
+
+static struct dvb_frontend_ops vp7045_fe_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name			= "Twinhan VP7045/46 USB DVB-T",
+		.frequency_min		= 44250000,
+		.frequency_max		= 867250000,
+		.frequency_stepsize	= 1000,
+		.caps = FE_CAN_INVERSION_AUTO |
+				FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+				FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+				FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+				FE_CAN_TRANSMISSION_MODE_AUTO |
+				FE_CAN_GUARD_INTERVAL_AUTO |
+				FE_CAN_RECOVER |
+				FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.release = vp7045_fe_release,
+
+	.init = vp7045_fe_init,
+	.sleep = vp7045_fe_sleep,
+
+	.set_frontend = vp7045_fe_set_frontend,
+	.get_tune_settings = vp7045_fe_get_tune_settings,
+
+	.read_status = vp7045_fe_read_status,
+	.read_ber = vp7045_fe_read_ber,
+	.read_signal_strength = vp7045_fe_read_signal_strength,
+	.read_snr = vp7045_fe_read_snr,
+	.read_ucblocks = vp7045_fe_read_unc_blocks,
+};
diff --git a/drivers/media/usb/dvb-usb/vp7045.c b/drivers/media/usb/dvb-usb/vp7045.c
new file mode 100644
index 0000000..d750724
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/vp7045.c
@@ -0,0 +1,302 @@
+/* DVB USB compliant Linux driver for the
+ *  - TwinhanDTV Alpha/MagicBoxII USB2.0 DVB-T receiver
+ *  - DigitalNow TinyUSB2 DVB-t receiver
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * Thanks to Twinhan who kindly provided hardware and information.
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "vp7045.h"
+
+/* debug */
+static int dvb_usb_vp7045_debug;
+module_param_named(debug,dvb_usb_vp7045_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
+#define deb_rc(args...)   dprintk(dvb_usb_vp7045_debug,0x04,args)
+
+int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec)
+{
+	int ret = 0;
+	u8 *buf = d->priv;
+
+	buf[0] = cmd;
+
+	if (outlen > 19)
+		outlen = 19;
+
+	if (inlen > 11)
+		inlen = 11;
+
+	ret = mutex_lock_interruptible(&d->usb_mutex);
+	if (ret)
+		return ret;
+
+	if (out != NULL && outlen > 0)
+		memcpy(&buf[1], out, outlen);
+
+	deb_xfer("out buffer: ");
+	debug_dump(buf, outlen+1, deb_xfer);
+
+
+	if (usb_control_msg(d->udev,
+			usb_sndctrlpipe(d->udev,0),
+			TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0,
+			buf, 20, 2000) != 20) {
+		err("USB control message 'out' went wrong.");
+		ret = -EIO;
+		goto unlock;
+	}
+
+	msleep(msec);
+
+	if (usb_control_msg(d->udev,
+			usb_rcvctrlpipe(d->udev,0),
+			TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+			buf, 12, 2000) != 12) {
+		err("USB control message 'in' went wrong.");
+		ret = -EIO;
+		goto unlock;
+	}
+
+	deb_xfer("in buffer: ");
+	debug_dump(buf, 12, deb_xfer);
+
+	if (in != NULL && inlen > 0)
+		memcpy(in, &buf[1], inlen);
+
+unlock:
+	mutex_unlock(&d->usb_mutex);
+
+	return ret;
+}
+
+u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg)
+{
+	u8 obuf[2] = { 0 },v;
+	obuf[1] = reg;
+
+	vp7045_usb_op(d,TUNER_REG_READ,obuf,2,&v,1,30);
+
+	return v;
+}
+
+static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	u8 v = onoff;
+	return vp7045_usb_op(d,SET_TUNER_POWER,&v,1,NULL,0,150);
+}
+
+/* remote control stuff */
+
+/* The keymapping struct. Somehow this should be loaded to the driver, but
+ * currently it is hardcoded. */
+static struct rc_map_table rc_map_vp7045_table[] = {
+	{ 0x0016, KEY_POWER },
+	{ 0x0010, KEY_MUTE },
+	{ 0x0003, KEY_1 },
+	{ 0x0001, KEY_2 },
+	{ 0x0006, KEY_3 },
+	{ 0x0009, KEY_4 },
+	{ 0x001d, KEY_5 },
+	{ 0x001f, KEY_6 },
+	{ 0x000d, KEY_7 },
+	{ 0x0019, KEY_8 },
+	{ 0x001b, KEY_9 },
+	{ 0x0015, KEY_0 },
+	{ 0x0005, KEY_CHANNELUP },
+	{ 0x0002, KEY_CHANNELDOWN },
+	{ 0x001e, KEY_VOLUMEUP },
+	{ 0x000a, KEY_VOLUMEDOWN },
+	{ 0x0011, KEY_RECORD },
+	{ 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */
+	{ 0x0014, KEY_PLAY },
+	{ 0x001a, KEY_STOP },
+	{ 0x0040, KEY_REWIND },
+	{ 0x0012, KEY_FASTFORWARD },
+	{ 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */
+	{ 0x004c, KEY_PAUSE },
+	{ 0x004d, KEY_SCREEN }, /* Full screen mode. */
+	{ 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
+	{ 0x000c, KEY_CANCEL }, /* Cancel */
+	{ 0x001c, KEY_EPG }, /* EPG */
+	{ 0x0000, KEY_TAB }, /* Tab */
+	{ 0x0048, KEY_INFO }, /* Preview */
+	{ 0x0004, KEY_LIST }, /* RecordList */
+	{ 0x000f, KEY_TEXT }, /* Teletext */
+	{ 0x0041, KEY_PREVIOUSSONG },
+	{ 0x0042, KEY_NEXTSONG },
+	{ 0x004b, KEY_UP },
+	{ 0x0051, KEY_DOWN },
+	{ 0x004e, KEY_LEFT },
+	{ 0x0052, KEY_RIGHT },
+	{ 0x004f, KEY_ENTER },
+	{ 0x0013, KEY_CANCEL },
+	{ 0x004a, KEY_CLEAR },
+	{ 0x0054, KEY_PRINT }, /* Capture */
+	{ 0x0043, KEY_SUBTITLE }, /* Subtitle/CC */
+	{ 0x0008, KEY_VIDEO }, /* A/V */
+	{ 0x0007, KEY_SLEEP }, /* Hibernate */
+	{ 0x0045, KEY_ZOOM }, /* Zoom+ */
+	{ 0x0018, KEY_RED},
+	{ 0x0053, KEY_GREEN},
+	{ 0x005e, KEY_YELLOW},
+	{ 0x005f, KEY_BLUE}
+};
+
+static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	u8 key;
+	int i;
+	vp7045_usb_op(d,RC_VAL_READ,NULL,0,&key,1,20);
+
+	deb_rc("remote query key: %x %d\n",key,key);
+
+	if (key == 0x44) {
+		*state = REMOTE_NO_KEY_PRESSED;
+		return 0;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(rc_map_vp7045_table); i++)
+		if (rc5_data(&rc_map_vp7045_table[i]) == key) {
+			*state = REMOTE_KEY_PRESSED;
+			*event = rc_map_vp7045_table[i].keycode;
+			break;
+		}
+	return 0;
+}
+
+static int vp7045_read_eeprom(struct dvb_usb_device *d,u8 *buf, int len, int offset)
+{
+	int i = 0;
+	u8 v,br[2];
+	for (i=0; i < len; i++) {
+		v = offset + i;
+		vp7045_usb_op(d,GET_EE_VALUE,&v,1,br,2,5);
+		buf[i] = br[1];
+	}
+	deb_info("VP7045 EEPROM read (offs: %d, len: %d) : ",offset, i);
+	debug_dump(buf,i,deb_info);
+	return 0;
+}
+
+static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
+{
+	return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR);
+}
+
+static int vp7045_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	u8 buf[255] = { 0 };
+
+	vp7045_usb_op(adap->dev,VENDOR_STRING_READ,NULL,0,buf,20,0);
+	buf[10] = '\0';
+	deb_info("firmware says: %s ",buf);
+
+	vp7045_usb_op(adap->dev,PRODUCT_STRING_READ,NULL,0,buf,20,0);
+	buf[10] = '\0';
+	deb_info("%s ",buf);
+
+	vp7045_usb_op(adap->dev,FW_VERSION_READ,NULL,0,buf,20,0);
+	buf[10] = '\0';
+	deb_info("v%s\n",buf);
+
+/*	Dump the EEPROM */
+/*	vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */
+
+	adap->fe_adap[0].fe = vp7045_fe_attach(adap->dev);
+
+	return 0;
+}
+
+static struct dvb_usb_device_properties vp7045_properties;
+
+static int vp7045_usb_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	return dvb_usb_device_init(intf, &vp7045_properties,
+				   THIS_MODULE, NULL, adapter_nr);
+}
+
+static struct usb_device_id vp7045_usb_table [] = {
+	    { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_COLD) },
+	    { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_WARM) },
+	    { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_COLD) },
+	    { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_WARM) },
+	    { 0 },
+};
+MODULE_DEVICE_TABLE(usb, vp7045_usb_table);
+
+static struct dvb_usb_device_properties vp7045_properties = {
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-vp7045-01.fw",
+	.size_of_priv = 20,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.frontend_attach  = vp7045_frontend_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 7,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}},
+		}
+	},
+	.power_ctrl       = vp7045_power_ctrl,
+	.read_mac_address = vp7045_read_mac_addr,
+
+	.rc.legacy = {
+		.rc_interval      = 400,
+		.rc_map_table       = rc_map_vp7045_table,
+		.rc_map_size  = ARRAY_SIZE(rc_map_vp7045_table),
+		.rc_query         = vp7045_rc_query,
+	},
+
+	.num_device_descs = 2,
+	.devices = {
+		{ .name = "Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)",
+		  .cold_ids = { &vp7045_usb_table[0], NULL },
+		  .warm_ids = { &vp7045_usb_table[1], NULL },
+		},
+		{ .name = "DigitalNow TinyUSB 2 DVB-t Receiver",
+		  .cold_ids = { &vp7045_usb_table[2], NULL },
+		  .warm_ids = { &vp7045_usb_table[3], NULL },
+		},
+		{ NULL },
+	}
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver vp7045_usb_driver = {
+	.name		= "dvb_usb_vp7045",
+	.probe		= vp7045_usb_probe,
+	.disconnect	= dvb_usb_device_exit,
+	.id_table	= vp7045_usb_table,
+};
+
+module_usb_driver(vp7045_usb_driver);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/vp7045.h b/drivers/media/usb/dvb-usb/vp7045.h
new file mode 100644
index 0000000..cf5ec46
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/vp7045.h
@@ -0,0 +1,70 @@
+/* Common header-file of the Linux driver for the TwinhanDTV Alpha/MagicBoxII
+ * USB2.0 DVB-T receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * Thanks to Twinhan who kindly provided hardware and information.
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_VP7045_H_
+#define _DVB_USB_VP7045_H_
+
+#define DVB_USB_LOG_PREFIX "vp7045"
+#include "dvb-usb.h"
+
+/* vp7045 commands */
+
+/* Twinhan Vendor requests */
+#define TH_COMMAND_IN                     0xC0
+#define TH_COMMAND_OUT                    0xC1
+
+/* command bytes */
+#define TUNER_REG_READ                    0x03
+#define TUNER_REG_WRITE                   0x04
+
+#define RC_VAL_READ                       0x05
+ #define RC_NO_KEY                        0x44
+
+#define SET_TUNER_POWER                   0x06
+#define CHECK_TUNER_POWER                 0x12
+ #define Tuner_Power_ON                   1
+ #define Tuner_Power_OFF                  0
+
+#define GET_USB_SPEED                     0x07
+
+#define LOCK_TUNER_COMMAND                0x09
+
+#define TUNER_SIGNAL_READ                 0x0A
+
+/* FX2 eeprom */
+#define SET_EE_VALUE                      0x10
+#define GET_EE_VALUE                      0x11
+ #define FX2_ID_ADDR                      0x00
+ #define VID_MSB_ADDR                     0x02
+ #define VID_LSB_ADDR                     0x01
+ #define PID_MSB_ADDR                     0x04
+ #define PID_LSB_ADDR                     0x03
+ #define MAC_0_ADDR                       0x07
+ #define MAC_1_ADDR                       0x08
+ #define MAC_2_ADDR                       0x09
+ #define MAC_3_ADDR                       0x0a
+ #define MAC_4_ADDR                       0x0b
+ #define MAC_5_ADDR                       0x0c
+
+#define RESET_FX2                         0x13
+
+#define FW_VERSION_READ                   0x0B
+#define VENDOR_STRING_READ                0x0C
+#define PRODUCT_STRING_READ               0x0D
+#define FW_BCD_VERSION_READ               0x14
+
+extern struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d);
+extern int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen,int msec);
+extern u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg);
+
+#endif
diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
new file mode 100644
index 0000000..928ef0d
--- /dev/null
+++ b/drivers/media/usb/em28xx/Kconfig
@@ -0,0 +1,58 @@
+config VIDEO_EM28XX
+	tristate "Empia EM28xx USB video capture support"
+	depends on VIDEO_DEV && I2C
+	select VIDEO_TUNER
+	select VIDEO_TVEEPROM
+	select VIDEOBUF_VMALLOC
+	select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_MT9V011 if VIDEO_HELPER_CHIPS_AUTO
+
+	---help---
+	  This is a video4linux driver for Empia 28xx based TV cards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called em28xx
+
+config VIDEO_EM28XX_ALSA
+	depends on VIDEO_EM28XX && SND
+	select SND_PCM
+	tristate "Empia EM28xx ALSA audio module"
+	---help---
+	  This is an ALSA driver for some Empia 28xx based TV cards.
+
+	  This is not required for em2800/em2820/em2821 boards. However,
+	  newer em28xx devices uses Vendor Class for audio, instead of
+	  implementing the USB Audio Class. For those chips, this module
+	  will enable digital audio.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called em28xx-alsa
+
+config VIDEO_EM28XX_DVB
+	tristate "DVB/ATSC Support for em28xx based TV cards"
+	depends on VIDEO_EM28XX && DVB_CORE
+	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+	select DVB_S921 if !DVB_FE_CUSTOMISE
+	select DVB_DRXD if !DVB_FE_CUSTOMISE
+	select DVB_CXD2820R if !DVB_FE_CUSTOMISE
+	select DVB_DRXK if !DVB_FE_CUSTOMISE
+	select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE
+	select DVB_TDA10071 if !DVB_FE_CUSTOMISE
+	select DVB_A8293 if !DVB_FE_CUSTOMISE
+	select VIDEOBUF_DVB
+	---help---
+	  This adds support for DVB cards based on the
+	  Empiatech em28xx chips.
+
+config VIDEO_EM28XX_RC
+        tristate "EM28XX Remote Controller support"
+        depends on RC_CORE
+        depends on VIDEO_EM28XX
+        depends on !(RC_CORE=m && VIDEO_EM28XX=y)
+        default VIDEO_EM28XX
+        ---help---
+          Enables Remote Controller support on em28xx driver.
diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile
new file mode 100644
index 0000000..634fb92
--- /dev/null
+++ b/drivers/media/usb/em28xx/Makefile
@@ -0,0 +1,15 @@
+em28xx-y +=	em28xx-video.o em28xx-i2c.o em28xx-cards.o
+em28xx-y +=	em28xx-core.o  em28xx-vbi.o
+
+em28xx-alsa-objs := em28xx-audio.o
+em28xx-rc-objs := em28xx-input.o
+
+obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
+obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
+obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
+obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o
+
+ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
new file mode 100644
index 0000000..2fdb66e
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -0,0 +1,751 @@
+/*
+ *  Empiatech em28x1 audio extension
+ *
+ *  Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
+ *
+ *  Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *	- Port to work with the in-kernel driver
+ *	- Cleanups, fixes, alsa-controls, etc.
+ *
+ *  This driver is based on my previous au600 usb pstn audio driver
+ *  and inherits all the copyrights
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/init.h>
+#include <linux/sound.h>
+#include <linux/spinlock.h>
+#include <linux/soundcard.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include <sound/ac97_codec.h>
+#include <media/v4l2-common.h>
+#include "em28xx.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "activates debug info");
+
+#define dprintk(fmt, arg...) do {					\
+	    if (debug)							\
+		printk(KERN_INFO "em28xx-audio %s: " fmt,		\
+				  __func__, ##arg); 		\
+	} while (0)
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+
+static int em28xx_deinit_isoc_audio(struct em28xx *dev)
+{
+	int i;
+
+	dprintk("Stopping isoc\n");
+	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+		if (!irqs_disabled())
+			usb_kill_urb(dev->adev.urb[i]);
+		else
+			usb_unlink_urb(dev->adev.urb[i]);
+
+		usb_free_urb(dev->adev.urb[i]);
+		dev->adev.urb[i] = NULL;
+
+		kfree(dev->adev.transfer_buffer[i]);
+		dev->adev.transfer_buffer[i] = NULL;
+	}
+
+	return 0;
+}
+
+static void em28xx_audio_isocirq(struct urb *urb)
+{
+	struct em28xx            *dev = urb->context;
+	int                      i;
+	unsigned int             oldptr;
+	int                      period_elapsed = 0;
+	int                      status;
+	unsigned char            *cp;
+	unsigned int             stride;
+	struct snd_pcm_substream *substream;
+	struct snd_pcm_runtime   *runtime;
+
+	switch (urb->status) {
+	case 0:             /* success */
+	case -ETIMEDOUT:    /* NAK */
+		break;
+	case -ECONNRESET:   /* kill */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	default:            /* error */
+		dprintk("urb completition error %d.\n", urb->status);
+		break;
+	}
+
+	if (atomic_read(&dev->stream_started) == 0)
+		return;
+
+	if (dev->adev.capture_pcm_substream) {
+		substream = dev->adev.capture_pcm_substream;
+		runtime = substream->runtime;
+		stride = runtime->frame_bits >> 3;
+
+		for (i = 0; i < urb->number_of_packets; i++) {
+			int length =
+			    urb->iso_frame_desc[i].actual_length / stride;
+			cp = (unsigned char *)urb->transfer_buffer +
+			    urb->iso_frame_desc[i].offset;
+
+			if (!length)
+				continue;
+
+			oldptr = dev->adev.hwptr_done_capture;
+			if (oldptr + length >= runtime->buffer_size) {
+				unsigned int cnt =
+				    runtime->buffer_size - oldptr;
+				memcpy(runtime->dma_area + oldptr * stride, cp,
+				       cnt * stride);
+				memcpy(runtime->dma_area, cp + cnt * stride,
+				       length * stride - cnt * stride);
+			} else {
+				memcpy(runtime->dma_area + oldptr * stride, cp,
+				       length * stride);
+			}
+
+			snd_pcm_stream_lock(substream);
+
+			dev->adev.hwptr_done_capture += length;
+			if (dev->adev.hwptr_done_capture >=
+			    runtime->buffer_size)
+				dev->adev.hwptr_done_capture -=
+				    runtime->buffer_size;
+
+			dev->adev.capture_transfer_done += length;
+			if (dev->adev.capture_transfer_done >=
+			    runtime->period_size) {
+				dev->adev.capture_transfer_done -=
+				    runtime->period_size;
+				period_elapsed = 1;
+			}
+
+			snd_pcm_stream_unlock(substream);
+		}
+		if (period_elapsed)
+			snd_pcm_period_elapsed(substream);
+	}
+	urb->status = 0;
+
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status < 0) {
+		em28xx_errdev("resubmit of audio urb failed (error=%i)\n",
+			      status);
+	}
+	return;
+}
+
+static int em28xx_init_audio_isoc(struct em28xx *dev)
+{
+	int       i, errCode;
+	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
+			    EM28XX_AUDIO_MAX_PACKET_SIZE;
+
+	dprintk("Starting isoc transfers\n");
+
+	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+		struct urb *urb;
+		int j, k;
+
+		dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
+		if (!dev->adev.transfer_buffer[i])
+			return -ENOMEM;
+
+		memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
+		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
+		if (!urb) {
+			em28xx_errdev("usb_alloc_urb failed!\n");
+			for (j = 0; j < i; j++) {
+				usb_free_urb(dev->adev.urb[j]);
+				kfree(dev->adev.transfer_buffer[j]);
+			}
+			return -ENOMEM;
+		}
+
+		urb->dev = dev->udev;
+		urb->context = dev;
+		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->transfer_buffer = dev->adev.transfer_buffer[i];
+		urb->interval = 1;
+		urb->complete = em28xx_audio_isocirq;
+		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
+		urb->transfer_buffer_length = sb_size;
+
+		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
+			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
+			urb->iso_frame_desc[j].offset = k;
+			urb->iso_frame_desc[j].length =
+			    EM28XX_AUDIO_MAX_PACKET_SIZE;
+		}
+		dev->adev.urb[i] = urb;
+	}
+
+	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+		errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
+		if (errCode) {
+			em28xx_errdev("submit of audio urb failed\n");
+			em28xx_deinit_isoc_audio(dev);
+			atomic_set(&dev->stream_started, 0);
+			return errCode;
+		}
+
+	}
+
+	return 0;
+}
+
+static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
+					size_t size)
+{
+	struct snd_pcm_runtime *runtime = subs->runtime;
+
+	dprintk("Allocating vbuffer\n");
+	if (runtime->dma_area) {
+		if (runtime->dma_bytes > size)
+			return 0;
+
+		vfree(runtime->dma_area);
+	}
+	runtime->dma_area = vmalloc(size);
+	if (!runtime->dma_area)
+		return -ENOMEM;
+
+	runtime->dma_bytes = size;
+
+	return 0;
+}
+
+static struct snd_pcm_hardware snd_em28xx_hw_capture = {
+	.info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		SNDRV_PCM_INFO_MMAP           |
+		SNDRV_PCM_INFO_INTERLEAVED    |
+		SNDRV_PCM_INFO_BATCH	      |
+		SNDRV_PCM_INFO_MMAP_VALID,
+
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+	.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
+
+	.rate_min = 48000,
+	.rate_max = 48000,
+	.channels_min = 2,
+	.channels_max = 2,
+	.buffer_bytes_max = 62720 * 8,	/* just about the value in usbaudio.c */
+	.period_bytes_min = 64,		/* 12544/2, */
+	.period_bytes_max = 12544,
+	.periods_min = 2,
+	.periods_max = 98,		/* 12544, */
+};
+
+static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
+{
+	struct em28xx *dev = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int ret = 0;
+
+	dprintk("opening device and trying to acquire exclusive lock\n");
+
+	if (!dev) {
+		em28xx_err("BUG: em28xx can't find device struct."
+				" Can't proceed with open\n");
+		return -ENODEV;
+	}
+
+	runtime->hw = snd_em28xx_hw_capture;
+	if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) {
+		if (dev->audio_ifnum)
+			dev->alt = 1;
+		else
+			dev->alt = 7;
+
+		dprintk("changing alternate number on interface %d to %d\n",
+			dev->audio_ifnum, dev->alt);
+		usb_set_interface(dev->udev, dev->audio_ifnum, dev->alt);
+
+		/* Sets volume, mute, etc */
+		dev->mute = 0;
+		mutex_lock(&dev->lock);
+		ret = em28xx_audio_analog_set(dev);
+		if (ret < 0)
+			goto err;
+
+		dev->adev.users++;
+		mutex_unlock(&dev->lock);
+	}
+
+	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	dev->adev.capture_pcm_substream = substream;
+
+	return 0;
+err:
+	mutex_unlock(&dev->lock);
+
+	em28xx_err("Error while configuring em28xx mixer\n");
+	return ret;
+}
+
+static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct em28xx *dev = snd_pcm_substream_chip(substream);
+
+	dprintk("closing device\n");
+
+	dev->mute = 1;
+	mutex_lock(&dev->lock);
+	dev->adev.users--;
+	if (atomic_read(&dev->stream_started) > 0) {
+		atomic_set(&dev->stream_started, 0);
+		schedule_work(&dev->wq_trigger);
+	}
+
+	em28xx_audio_analog_set(dev);
+	if (substream->runtime->dma_area) {
+		dprintk("freeing\n");
+		vfree(substream->runtime->dma_area);
+		substream->runtime->dma_area = NULL;
+	}
+	mutex_unlock(&dev->lock);
+
+	return 0;
+}
+
+static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
+					struct snd_pcm_hw_params *hw_params)
+{
+	int ret;
+
+	dprintk("Setting capture parameters\n");
+
+	ret = snd_pcm_alloc_vmalloc_buffer(substream,
+				params_buffer_bytes(hw_params));
+	if (ret < 0)
+		return ret;
+#if 0
+	/* TODO: set up em28xx audio chip to deliver the correct audio format,
+	   current default is 48000hz multiplexed => 96000hz mono
+	   which shouldn't matter since analogue TV only supports mono */
+	unsigned int channels, rate, format;
+
+	format = params_format(hw_params);
+	rate = params_rate(hw_params);
+	channels = params_channels(hw_params);
+#endif
+
+	return 0;
+}
+
+static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream)
+{
+	struct em28xx *dev = snd_pcm_substream_chip(substream);
+
+	dprintk("Stop capture, if needed\n");
+
+	if (atomic_read(&dev->stream_started) > 0) {
+		atomic_set(&dev->stream_started, 0);
+		schedule_work(&dev->wq_trigger);
+	}
+
+	return 0;
+}
+
+static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
+{
+	struct em28xx *dev = snd_pcm_substream_chip(substream);
+
+	dev->adev.hwptr_done_capture = 0;
+	dev->adev.capture_transfer_done = 0;
+
+	return 0;
+}
+
+static void audio_trigger(struct work_struct *work)
+{
+	struct em28xx *dev = container_of(work, struct em28xx, wq_trigger);
+
+	if (atomic_read(&dev->stream_started)) {
+		dprintk("starting capture");
+		em28xx_init_audio_isoc(dev);
+	} else {
+		dprintk("stopping capture");
+		em28xx_deinit_isoc_audio(dev);
+	}
+}
+
+static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
+				      int cmd)
+{
+	struct em28xx *dev = snd_pcm_substream_chip(substream);
+	int retval = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
+	case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
+	case SNDRV_PCM_TRIGGER_START:
+		atomic_set(&dev->stream_started, 1);
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
+	case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
+	case SNDRV_PCM_TRIGGER_STOP:
+		atomic_set(&dev->stream_started, 0);
+		break;
+	default:
+		retval = -EINVAL;
+	}
+	schedule_work(&dev->wq_trigger);
+	return retval;
+}
+
+static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
+						    *substream)
+{
+	unsigned long flags;
+	struct em28xx *dev;
+	snd_pcm_uframes_t hwptr_done;
+
+	dev = snd_pcm_substream_chip(substream);
+	spin_lock_irqsave(&dev->adev.slock, flags);
+	hwptr_done = dev->adev.hwptr_done_capture;
+	spin_unlock_irqrestore(&dev->adev.slock, flags);
+
+	return hwptr_done;
+}
+
+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
+					     unsigned long offset)
+{
+	void *pageptr = subs->runtime->dma_area + offset;
+
+	return vmalloc_to_page(pageptr);
+}
+
+/*
+ * AC97 volume control support
+ */
+static int em28xx_vol_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *info)
+{
+	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	info->count = 2;
+	info->value.integer.min = 0;
+	info->value.integer.max = 0x1f;
+
+	return 0;
+}
+
+static int em28xx_vol_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *value)
+{
+	struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+	u16 val = (0x1f - (value->value.integer.value[0] & 0x1f)) |
+		  (0x1f - (value->value.integer.value[1] & 0x1f)) << 8;
+	int rc;
+
+	mutex_lock(&dev->lock);
+	rc = em28xx_read_ac97(dev, kcontrol->private_value);
+	if (rc < 0)
+		goto err;
+
+	val |= rc & 0x8000;	/* Preserve the mute flag */
+
+	rc = em28xx_write_ac97(dev, kcontrol->private_value, val);
+	if (rc < 0)
+		goto err;
+
+	dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n",
+		(val & 0x8000) ? "muted " : "",
+		0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
+		val, (int)kcontrol->private_value);
+
+err:
+	mutex_unlock(&dev->lock);
+	return rc;
+}
+
+static int em28xx_vol_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *value)
+{
+	struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+	int val;
+
+	mutex_lock(&dev->lock);
+	val = em28xx_read_ac97(dev, kcontrol->private_value);
+	mutex_unlock(&dev->lock);
+	if (val < 0)
+		return val;
+
+	dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n",
+		(val & 0x8000) ? "muted " : "",
+		0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
+		val, (int)kcontrol->private_value);
+
+	value->value.integer.value[0] = 0x1f - (val & 0x1f);
+	value->value.integer.value[1] = 0x1f - ((val << 8) & 0x1f);
+
+	return 0;
+}
+
+static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *value)
+{
+	struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+	u16 val = value->value.integer.value[0];
+	int rc;
+
+	mutex_lock(&dev->lock);
+	rc = em28xx_read_ac97(dev, kcontrol->private_value);
+	if (rc < 0)
+		goto err;
+
+	if (val)
+		rc &= 0x1f1f;
+	else
+		rc |= 0x8000;
+
+	rc = em28xx_write_ac97(dev, kcontrol->private_value, rc);
+	if (rc < 0)
+		goto err;
+
+	dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n",
+		(val & 0x8000) ? "muted " : "",
+		0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
+		val, (int)kcontrol->private_value);
+
+err:
+	mutex_unlock(&dev->lock);
+	return rc;
+}
+
+static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *value)
+{
+	struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+	int val;
+
+	mutex_lock(&dev->lock);
+	val = em28xx_read_ac97(dev, kcontrol->private_value);
+	mutex_unlock(&dev->lock);
+	if (val < 0)
+		return val;
+
+	if (val & 0x8000)
+		value->value.integer.value[0] = 0;
+	else
+		value->value.integer.value[0] = 1;
+
+	dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n",
+		(val & 0x8000) ? "muted " : "",
+		0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
+		val, (int)kcontrol->private_value);
+
+	return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(em28xx_db_scale, -3450, 150, 0);
+
+static int em28xx_cvol_new(struct snd_card *card, struct em28xx *dev,
+			   char *name, int id)
+{
+	int err;
+	char ctl_name[44];
+	struct snd_kcontrol *kctl;
+	struct snd_kcontrol_new tmp;
+
+	memset (&tmp, 0, sizeof(tmp));
+	tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	tmp.private_value = id,
+	tmp.name  = ctl_name,
+
+	/* Add Mute Control */
+	sprintf(ctl_name, "%s Switch", name);
+	tmp.get  = em28xx_vol_get_mute;
+	tmp.put  = em28xx_vol_put_mute;
+	tmp.info = snd_ctl_boolean_mono_info;
+	kctl = snd_ctl_new1(&tmp, dev);
+	err = snd_ctl_add(card, kctl);
+	if (err < 0)
+		return err;
+	dprintk("Added control %s for ac97 volume control 0x%04x\n",
+		ctl_name, id);
+
+	memset (&tmp, 0, sizeof(tmp));
+	tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	tmp.private_value = id,
+	tmp.name  = ctl_name,
+
+	/* Add Volume Control */
+	sprintf(ctl_name, "%s Volume", name);
+	tmp.get   = em28xx_vol_get;
+	tmp.put   = em28xx_vol_put;
+	tmp.info  = em28xx_vol_info;
+	tmp.tlv.p = em28xx_db_scale,
+	kctl = snd_ctl_new1(&tmp, dev);
+	err = snd_ctl_add(card, kctl);
+	if (err < 0)
+		return err;
+	dprintk("Added control %s for ac97 volume control 0x%04x\n",
+		ctl_name, id);
+
+	return 0;
+}
+
+/*
+ * register/unregister code and data
+ */
+static struct snd_pcm_ops snd_em28xx_pcm_capture = {
+	.open      = snd_em28xx_capture_open,
+	.close     = snd_em28xx_pcm_close,
+	.ioctl     = snd_pcm_lib_ioctl,
+	.hw_params = snd_em28xx_hw_capture_params,
+	.hw_free   = snd_em28xx_hw_capture_free,
+	.prepare   = snd_em28xx_prepare,
+	.trigger   = snd_em28xx_capture_trigger,
+	.pointer   = snd_em28xx_capture_pointer,
+	.page      = snd_pcm_get_vmalloc_page,
+};
+
+static int em28xx_audio_init(struct em28xx *dev)
+{
+	struct em28xx_audio *adev = &dev->adev;
+	struct snd_pcm      *pcm;
+	struct snd_card     *card;
+	static int          devnr;
+	int                 err;
+
+	if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
+		/* This device does not support the extension (in this case
+		   the device is expecting the snd-usb-audio module or
+		   doesn't have analog audio support at all) */
+		return 0;
+	}
+
+	printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n");
+	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
+			 "Rechberger\n");
+	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
+
+	err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
+			      &card);
+	if (err < 0)
+		return err;
+
+	spin_lock_init(&adev->slock);
+	err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
+	if (err < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
+	pcm->info_flags = 0;
+	pcm->private_data = dev;
+	strcpy(pcm->name, "Empia 28xx Capture");
+
+	snd_card_set_dev(card, &dev->udev->dev);
+	strcpy(card->driver, "Em28xx-Audio");
+	strcpy(card->shortname, "Em28xx Audio");
+	strcpy(card->longname, "Empia Em28xx Audio");
+
+	INIT_WORK(&dev->wq_trigger, audio_trigger);
+
+	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+		em28xx_cvol_new(card, dev, "Video", AC97_VIDEO);
+		em28xx_cvol_new(card, dev, "Line In", AC97_LINE);
+		em28xx_cvol_new(card, dev, "Phone", AC97_PHONE);
+		em28xx_cvol_new(card, dev, "Microphone", AC97_MIC);
+		em28xx_cvol_new(card, dev, "CD", AC97_CD);
+		em28xx_cvol_new(card, dev, "AUX", AC97_AUX);
+		em28xx_cvol_new(card, dev, "PCM", AC97_PCM);
+
+		em28xx_cvol_new(card, dev, "Master", AC97_MASTER);
+		em28xx_cvol_new(card, dev, "Line", AC97_HEADPHONE);
+		em28xx_cvol_new(card, dev, "Mono", AC97_MASTER_MONO);
+		em28xx_cvol_new(card, dev, "LFE", AC97_CENTER_LFE_MASTER);
+		em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
+	}
+
+	err = snd_card_register(card);
+	if (err < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	adev->sndcard = card;
+	adev->udev = dev->udev;
+
+	return 0;
+}
+
+static int em28xx_audio_fini(struct em28xx *dev)
+{
+	if (dev == NULL)
+		return 0;
+
+	if (dev->has_alsa_audio != 1) {
+		/* This device does not support the extension (in this case
+		   the device is expecting the snd-usb-audio module or
+		   doesn't have analog audio support at all) */
+		return 0;
+	}
+
+	if (dev->adev.sndcard) {
+		snd_card_free(dev->adev.sndcard);
+		dev->adev.sndcard = NULL;
+	}
+
+	return 0;
+}
+
+static struct em28xx_ops audio_ops = {
+	.id   = EM28XX_AUDIO,
+	.name = "Em28xx Audio Extension",
+	.init = em28xx_audio_init,
+	.fini = em28xx_audio_fini,
+};
+
+static int __init em28xx_alsa_register(void)
+{
+	return em28xx_register_extension(&audio_ops);
+}
+
+static void __exit em28xx_alsa_unregister(void)
+{
+	em28xx_unregister_extension(&audio_ops);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_DESCRIPTION("Em28xx Audio driver");
+
+module_init(em28xx_alsa_register);
+module_exit(em28xx_alsa_unregister);
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
new file mode 100644
index 0000000..ca62b99
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -0,0 +1,3417 @@
+/*
+   em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB
+		    video capture devices
+
+   Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+		      Markus Rechberger <mrechberger@gmail.com>
+		      Mauro Carvalho Chehab <mchehab@infradead.org>
+		      Sascha Sommer <saschasommer@freenet.de>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/usb.h>
+#include <media/tuner.h>
+#include <media/msp3400.h>
+#include <media/saa7115.h>
+#include <media/tvp5150.h>
+#include <media/tvaudio.h>
+#include <media/mt9v011.h>
+#include <media/i2c-addr.h>
+#include <media/tveeprom.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "em28xx.h"
+
+#define DRIVER_NAME         "em28xx"
+
+static int tuner = -1;
+module_param(tuner, int, 0444);
+MODULE_PARM_DESC(tuner, "tuner type");
+
+static unsigned int disable_ir;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
+
+static unsigned int disable_usb_speed_check;
+module_param(disable_usb_speed_check, int, 0444);
+MODULE_PARM_DESC(disable_usb_speed_check,
+		 "override min bandwidth requirement of 480M bps");
+
+static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+module_param_array(card,  int, NULL, 0444);
+MODULE_PARM_DESC(card,     "card type");
+
+/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS - 1 */
+static unsigned long em28xx_devused;
+
+struct em28xx_hash_table {
+	unsigned long hash;
+	unsigned int  model;
+	unsigned int  tuner;
+};
+
+static void em28xx_pre_card_setup(struct em28xx *dev);
+
+/*
+ *  Reset sequences for analog/digital modes
+ */
+
+/* Reset for the most [analog] boards */
+static struct em28xx_reg_seq default_analog[] = {
+	{EM28XX_R08_GPIO,	0x6d,   ~EM_GPIO_4,	10},
+	{	-1,		-1,	-1,		-1},
+};
+
+/* Reset for the most [digital] boards */
+static struct em28xx_reg_seq default_digital[] = {
+	{EM28XX_R08_GPIO,	0x6e,	~EM_GPIO_4,	10},
+	{	-1,		-1,	-1,		-1},
+};
+
+/* Board Hauppauge WinTV HVR 900 analog */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
+	{EM28XX_R08_GPIO,	0x2d,	~EM_GPIO_4,	10},
+	{0x05,			0xff,	0x10,		10},
+	{  -1,			-1,	-1,		-1},
+};
+
+/* Board Hauppauge WinTV HVR 900 digital */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
+	{EM28XX_R08_GPIO,	0x2e,	~EM_GPIO_4,	10},
+	{EM2880_R04_GPO,	0x04,	0x0f,		10},
+	{EM2880_R04_GPO,	0x0c,	0x0f,		10},
+	{ -1,			-1,	-1,		-1},
+};
+
+/* Board Hauppauge WinTV HVR 900 (R2) digital */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = {
+	{EM28XX_R08_GPIO,	0x2e,	~EM_GPIO_4,	10},
+	{EM2880_R04_GPO,	0x0c,	0x0f,		10},
+	{ -1,			-1,	-1,		-1},
+};
+
+/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
+static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
+	{EM28XX_R08_GPIO,       0x69,   ~EM_GPIO_4,	 10},
+	{	-1,		-1,	-1,		 -1},
+};
+
+/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
+
+/* Board  - EM2870 Kworld 355u
+   Analog - No input analog */
+
+/* Board - EM2882 Kworld 315U digital */
+static struct em28xx_reg_seq em2882_kworld_315u_digital[] = {
+	{EM28XX_R08_GPIO,	0xff,	0xff,		10},
+	{EM28XX_R08_GPIO,	0xfe,	0xff,		10},
+	{EM2880_R04_GPO,	0x04,	0xff,		10},
+	{EM2880_R04_GPO,	0x0c,	0xff,		10},
+	{EM28XX_R08_GPIO,	0x7e,	0xff,		10},
+	{  -1,			-1,	-1,		-1},
+};
+
+static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = {
+	{EM2880_R04_GPO,	0x08,	0xff,		10},
+	{EM2880_R04_GPO,	0x0c,	0xff,		10},
+	{EM2880_R04_GPO,	0x08,	0xff,		10},
+	{EM2880_R04_GPO,	0x0c,	0xff,		10},
+	{  -1,			-1,	-1,		-1},
+};
+
+static struct em28xx_reg_seq kworld_330u_analog[] = {
+	{EM28XX_R08_GPIO,	0x6d,	~EM_GPIO_4,	10},
+	{EM2880_R04_GPO,	0x00,	0xff,		10},
+	{ -1,			-1,	-1,		-1},
+};
+
+static struct em28xx_reg_seq kworld_330u_digital[] = {
+	{EM28XX_R08_GPIO,	0x6e,	~EM_GPIO_4,	10},
+	{EM2880_R04_GPO,	0x08,	0xff,		10},
+	{ -1,			-1,	-1,		-1},
+};
+
+/* Evga inDtube
+   GPIO0 - Enable digital power (s5h1409) - low to enable
+   GPIO1 - Enable analog power (tvp5150/emp202) - low to enable
+   GPIO4 - xc3028 reset
+   GOP3  - s5h1409 reset
+ */
+static struct em28xx_reg_seq evga_indtube_analog[] = {
+	{EM28XX_R08_GPIO,	0x79,   0xff,		60},
+	{	-1,		-1,	-1,		-1},
+};
+
+static struct em28xx_reg_seq evga_indtube_digital[] = {
+	{EM28XX_R08_GPIO,	0x7a,	0xff,		 1},
+	{EM2880_R04_GPO,	0x04,	0xff,		10},
+	{EM2880_R04_GPO,	0x0c,	0xff,		 1},
+	{ -1,			-1,	-1,		-1},
+};
+
+/*
+ * KWorld PlusTV 340U and UB435-Q (ATSC) GPIOs map:
+ * EM_GPIO_0 - currently unknown
+ * EM_GPIO_1 - LED disable/enable (1 = off, 0 = on)
+ * EM_GPIO_2 - currently unknown
+ * EM_GPIO_3 - currently unknown
+ * EM_GPIO_4 - TDA18271HD/C1 tuner (1 = active, 0 = in reset)
+ * EM_GPIO_5 - LGDT3304 ATSC/QAM demod (1 = active, 0 = in reset)
+ * EM_GPIO_6 - currently unknown
+ * EM_GPIO_7 - currently unknown
+ */
+static struct em28xx_reg_seq kworld_a340_digital[] = {
+	{EM28XX_R08_GPIO,	0x6d,		~EM_GPIO_4,	10},
+	{ -1,			-1,		-1,		-1},
+};
+
+/* Pinnacle Hybrid Pro eb1a:2881 */
+static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = {
+	{EM28XX_R08_GPIO,	0xfd,   ~EM_GPIO_4,	10},
+	{	-1,		-1,	-1,		-1},
+};
+
+static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = {
+	{EM28XX_R08_GPIO,	0x6e,	~EM_GPIO_4,	10},
+	{EM2880_R04_GPO,	0x04,	0xff,	       100},/* zl10353 reset */
+	{EM2880_R04_GPO,	0x0c,	0xff,		 1},
+	{	-1,		-1,	-1,		-1},
+};
+
+static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = {
+	{EM28XX_R08_GPIO,	0x6d,	~EM_GPIO_4,	10},
+	{EM2880_R04_GPO,	0x00,	0xff,		10},
+	{ -1,			-1,	-1,		-1},
+};
+
+static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = {
+	{EM28XX_R08_GPIO,	0x6e,	~EM_GPIO_4,	10},
+	{EM2880_R04_GPO,	0x08,	0xff,		10},
+	{ -1,			-1,	-1,		-1},
+};
+
+/* eb1a:2868 Reddo DVB-C USB TV Box
+   GPIO4 - CU1216L NIM
+   Other GPIOs seems to be don't care. */
+static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = {
+	{EM28XX_R08_GPIO,	0xfe,	0xff,		10},
+	{EM28XX_R08_GPIO,	0xde,	0xff,		10},
+	{EM28XX_R08_GPIO,	0xfe,	0xff,		10},
+	{EM28XX_R08_GPIO,	0xff,	0xff,		10},
+	{EM28XX_R08_GPIO,	0x7f,	0xff,		10},
+	{EM28XX_R08_GPIO,	0x6f,	0xff,		10},
+	{EM28XX_R08_GPIO,	0xff,	0xff,		10},
+	{-1,			-1,	-1,		-1},
+};
+
+/* Callback for the most boards */
+static struct em28xx_reg_seq default_tuner_gpio[] = {
+	{EM28XX_R08_GPIO,	EM_GPIO_4,	EM_GPIO_4,	10},
+	{EM28XX_R08_GPIO,	0,		EM_GPIO_4,	10},
+	{EM28XX_R08_GPIO,	EM_GPIO_4,	EM_GPIO_4,	10},
+	{  -1,			-1,		-1,		-1},
+};
+
+/* Mute/unmute */
+static struct em28xx_reg_seq compro_unmute_tv_gpio[] = {
+	{EM28XX_R08_GPIO,	5,		7,		10},
+	{  -1,			-1,		-1,		-1},
+};
+
+static struct em28xx_reg_seq compro_unmute_svid_gpio[] = {
+	{EM28XX_R08_GPIO,	4,		7,		10},
+	{  -1,			-1,		-1,		-1},
+};
+
+static struct em28xx_reg_seq compro_mute_gpio[] = {
+	{EM28XX_R08_GPIO,	6,		7,		10},
+	{  -1,			-1,		-1,		-1},
+};
+
+/* Terratec AV350 */
+static struct em28xx_reg_seq terratec_av350_mute_gpio[] = {
+	{EM28XX_R08_GPIO,	0xff,	0x7f,		10},
+	{	-1,		-1,	-1,		-1},
+};
+
+static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = {
+	{EM28XX_R08_GPIO,	0xff,	0xff,		10},
+	{	-1,		-1,	-1,		-1},
+};
+
+static struct em28xx_reg_seq silvercrest_reg_seq[] = {
+	{EM28XX_R08_GPIO,	0xff,	0xff,		10},
+	{EM28XX_R08_GPIO,	0x01,	0xf7,		10},
+	{	-1,		-1,	-1,		-1},
+};
+
+static struct em28xx_reg_seq vc211a_enable[] = {
+	{EM28XX_R08_GPIO,	0xff,	0x07,		10},
+	{EM28XX_R08_GPIO,	0xff,	0x0f,		10},
+	{EM28XX_R08_GPIO,	0xff,	0x0b,		10},
+	{	-1,		-1,	-1,		-1},
+};
+
+static struct em28xx_reg_seq dikom_dk300_digital[] = {
+	{EM28XX_R08_GPIO,	0x6e,	~EM_GPIO_4,	10},
+	{EM2880_R04_GPO,	0x08,	0xff,		10},
+	{ -1,			-1,	-1,		-1},
+};
+
+
+/* Reset for the most [digital] boards */
+static struct em28xx_reg_seq leadership_digital[] = {
+	{EM2874_R80_GPIO,	0x70,	0xff,	10},
+	{	-1,		-1,	-1,	-1},
+};
+
+static struct em28xx_reg_seq leadership_reset[] = {
+	{EM2874_R80_GPIO,	0xf0,	0xff,	10},
+	{EM2874_R80_GPIO,	0xb0,	0xff,	10},
+	{EM2874_R80_GPIO,	0xf0,	0xff,	10},
+	{	-1,		-1,	-1,	-1},
+};
+
+/* 2013:024f PCTV nanoStick T2 290e
+ * GPIO_6 - demod reset
+ * GPIO_7 - LED
+ */
+static struct em28xx_reg_seq pctv_290e[] = {
+	{EM2874_R80_GPIO,	0x00,	0xff,		80},
+	{EM2874_R80_GPIO,	0x40,	0xff,		80}, /* GPIO_6 = 1 */
+	{EM2874_R80_GPIO,	0xc0,	0xff,		80}, /* GPIO_7 = 1 */
+	{-1,			-1,	-1,		-1},
+};
+
+#if 0
+static struct em28xx_reg_seq terratec_h5_gpio[] = {
+	{EM28XX_R08_GPIO,	0xff,	0xff,	10},
+	{EM2874_R80_GPIO,	0xf6,	0xff,	100},
+	{EM2874_R80_GPIO,	0xf2,	0xff,	50},
+	{EM2874_R80_GPIO,	0xf6,	0xff,	50},
+	{ -1,			-1,	-1,	-1},
+};
+
+static struct em28xx_reg_seq terratec_h5_digital[] = {
+	{EM2874_R80_GPIO,	0xf6,	0xff,	10},
+	{EM2874_R80_GPIO,	0xe6,	0xff,	100},
+	{EM2874_R80_GPIO,	0xa6,	0xff,	10},
+	{ -1,			-1,	-1,	-1},
+};
+#endif
+
+/* 2013:024f PCTV DVB-S2 Stick 460e
+ * GPIO_0 - POWER_ON
+ * GPIO_1 - BOOST
+ * GPIO_2 - VUV_LNB (red LED)
+ * GPIO_3 - EXT_12V
+ * GPIO_4 - INT_DEM (DEMOD GPIO_0)
+ * GPIO_5 - INT_LNB
+ * GPIO_6 - RESET_DEM
+ * GPIO_7 - LED (green LED)
+ */
+static struct em28xx_reg_seq pctv_460e[] = {
+	{EM2874_R80_GPIO, 0x01, 0xff,  50},
+	{0x0d,            0xff, 0xff,  50},
+	{EM2874_R80_GPIO, 0x41, 0xff,  50}, /* GPIO_6=1 */
+	{0x0d,            0x42, 0xff,  50},
+	{EM2874_R80_GPIO, 0x61, 0xff,  50}, /* GPIO_5=1 */
+	{             -1,   -1,   -1,  -1},
+};
+
+#if 0
+static struct em28xx_reg_seq hauppauge_930c_gpio[] = {
+	{EM2874_R80_GPIO,	0x6f,	0xff,	10},
+	{EM2874_R80_GPIO,	0x4f,	0xff,	10}, /* xc5000 reset */
+	{EM2874_R80_GPIO,	0x6f,	0xff,	10},
+	{EM2874_R80_GPIO,	0x4f,	0xff,	10},
+	{ -1,			-1,	-1,	-1},
+};
+
+static struct em28xx_reg_seq hauppauge_930c_digital[] = {
+	{EM2874_R80_GPIO,	0xf6,	0xff,	10},
+	{EM2874_R80_GPIO,	0xe6,	0xff,	100},
+	{EM2874_R80_GPIO,	0xa6,	0xff,	10},
+	{ -1,			-1,	-1,	-1},
+};
+#endif
+
+/* 1b80:e425 MaxMedia UB425-TC
+ * GPIO_6 - demod reset, 0=active
+ * GPIO_7 - LED, 0=active
+ */
+static struct em28xx_reg_seq maxmedia_ub425_tc[] = {
+	{EM2874_R80_GPIO,  0x83,  0xff,  100},
+	{EM2874_R80_GPIO,  0xc3,  0xff,  100}, /* GPIO_6 = 1 */
+	{EM2874_R80_GPIO,  0x43,  0xff,  000}, /* GPIO_7 = 0 */
+	{-1,                 -1,    -1,   -1},
+};
+
+/* 2304:0242 PCTV QuatroStick (510e)
+ * GPIO_2: decoder reset, 0=active
+ * GPIO_4: decoder suspend, 0=active
+ * GPIO_6: demod reset, 0=active
+ * GPIO_7: LED, 1=active
+ */
+static struct em28xx_reg_seq pctv_510e[] = {
+	{EM2874_R80_GPIO, 0x10, 0xff, 100},
+	{EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
+	{EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
+	{             -1,   -1,   -1,  -1},
+};
+
+/* 2013:0251 PCTV QuatroStick nano (520e)
+ * GPIO_2: decoder reset, 0=active
+ * GPIO_4: decoder suspend, 0=active
+ * GPIO_6: demod reset, 0=active
+ * GPIO_7: LED, 1=active
+ */
+static struct em28xx_reg_seq pctv_520e[] = {
+	{EM2874_R80_GPIO, 0x10, 0xff, 100},
+	{EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
+	{EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
+	{EM2874_R80_GPIO, 0xd4, 0xff, 000}, /* GPIO_7 = 1 */
+	{             -1,   -1,   -1,  -1},
+};
+
+/*
+ *  Board definitions
+ */
+struct em28xx_board em28xx_boards[] = {
+	[EM2750_BOARD_UNKNOWN] = {
+		.name          = "EM2710/EM2750/EM2751 webcam grabber",
+		.xclk          = EM28XX_XCLK_FREQUENCY_20MHZ,
+		.tuner_type    = TUNER_ABSENT,
+		.is_webcam     = 1,
+		.input         = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = 0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = silvercrest_reg_seq,
+		} },
+	},
+	[EM2800_BOARD_UNKNOWN] = {
+		.name         = "Unknown EM2800 video grabber",
+		.is_em2800    = 1,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_SAA711X,
+		.tuner_type   = TUNER_ABSENT,
+		.input        = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2820_BOARD_UNKNOWN] = {
+		.name          = "Unknown EM2750/28xx video grabber",
+		.tuner_type    = TUNER_ABSENT,
+		.is_webcam     = 1,	/* To enable sensor probe */
+	},
+	[EM2750_BOARD_DLCW_130] = {
+		/* Beijing Huaqi Information Digital Technology Co., Ltd */
+		.name          = "Huaqi DLCW-130",
+		.valid         = EM28XX_BOARD_NOT_VALIDATED,
+		.xclk          = EM28XX_XCLK_FREQUENCY_48MHZ,
+		.tuner_type    = TUNER_ABSENT,
+		.is_webcam     = 1,
+		.input         = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = 0,
+			.amux     = EM28XX_AMUX_VIDEO,
+		} },
+	},
+	[EM2820_BOARD_KWORLD_PVRTV2800RF] = {
+		.name         = "Kworld PVR TV 2800 RF",
+		.tuner_type   = TUNER_TEMIC_PAL,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2820_BOARD_GADMEI_TVR200] = {
+		.name         = "Gadmei TVR200",
+		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE2,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2820_BOARD_TERRATEC_CINERGY_250] = {
+		.name         = "Terratec Cinergy 250 USB",
+		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+		.has_ir_i2c   = 1,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE2,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2820_BOARD_PINNACLE_USB_2] = {
+		.name         = "Pinnacle PCTV USB 2",
+		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+		.has_ir_i2c   = 1,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE2,
+			.amux     = EM28XX_AMUX_VIDEO,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = {
+		.name         = "Hauppauge WinTV USB 2",
+		.tuner_type   = TUNER_PHILIPS_FM1236_MK3,
+		.tda9887_conf = TDA9887_PRESENT |
+				TDA9887_PORT1_ACTIVE |
+				TDA9887_PORT2_ACTIVE,
+		.decoder      = EM28XX_TVP5150,
+		.has_msp34xx  = 1,
+		.has_ir_i2c   = 1,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = MSP_INPUT_DEFAULT,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
+					MSP_DSP_IN_SCART, MSP_DSP_IN_SCART),
+		} },
+	},
+	[EM2820_BOARD_DLINK_USB_TV] = {
+		.name         = "D-Link DUB-T210 TV Tuner",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE2,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2820_BOARD_HERCULES_SMART_TV_USB2] = {
+		.name         = "Hercules Smart TV USB 2.0",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE2,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2820_BOARD_PINNACLE_USB_2_FM1216ME] = {
+		.name         = "Pinnacle PCTV USB 2 (Philips FM1216ME)",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_PHILIPS_FM1216ME_MK3,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE2,
+			.amux     = EM28XX_AMUX_VIDEO,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2820_BOARD_GADMEI_UTV310] = {
+		.name         = "Gadmei UTV310",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_TNF_5335MF,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE] = {
+		.name         = "Leadtek Winfast USB II Deluxe",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_PHILIPS_FM1216ME_MK3,
+		.has_ir_i2c   = 1,
+		.tvaudio_addr = 0x58,
+		.tda9887_conf = TDA9887_PRESENT |
+				TDA9887_PORT2_ACTIVE |
+				TDA9887_QSS,
+		.decoder      = EM28XX_SAA711X,
+		.adecoder     = EM28XX_TVAUDIO,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE4,
+			.amux     = EM28XX_AMUX_AUX,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE5,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+			.radio	  = {
+			.type     = EM28XX_RADIO,
+			.amux     = EM28XX_AMUX_AUX,
+			}
+	},
+	[EM2820_BOARD_VIDEOLOGY_20K14XUSB] = {
+		.name         = "Videology 20K14XUSB USB2.0",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_ABSENT,
+		.is_webcam    = 1,
+		.input        = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = 0,
+			.amux     = EM28XX_AMUX_VIDEO,
+		} },
+	},
+	[EM2820_BOARD_SILVERCREST_WEBCAM] = {
+		.name         = "Silvercrest Webcam 1.3mpix",
+		.tuner_type   = TUNER_ABSENT,
+		.is_webcam    = 1,
+		.input        = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = 0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = silvercrest_reg_seq,
+		} },
+	},
+	[EM2821_BOARD_SUPERCOMP_USB_2] = {
+		.name         = "Supercomp USB 2.0 TV",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_PHILIPS_FM1236_MK3,
+		.tda9887_conf = TDA9887_PRESENT |
+				TDA9887_PORT1_ACTIVE |
+				TDA9887_PORT2_ACTIVE,
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE2,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2821_BOARD_USBGEAR_VD204] = {
+		.name         = "Usbgear VD204v9",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_ABSENT,	/* Capture only device */
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type  = EM28XX_VMUX_COMPOSITE1,
+			.vmux  = SAA7115_COMPOSITE0,
+			.amux  = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type  = EM28XX_VMUX_SVIDEO,
+			.vmux  = SAA7115_SVIDEO3,
+			.amux  = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2860_BOARD_NETGMBH_CAM] = {
+		/* Beijing Huaqi Information Digital Technology Co., Ltd */
+		.name         = "NetGMBH Cam",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_ABSENT,
+		.is_webcam    = 1,
+		.input        = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = 0,
+			.amux     = EM28XX_AMUX_VIDEO,
+		} },
+	},
+	[EM2860_BOARD_TYPHOON_DVD_MAKER] = {
+		.name         = "Typhoon DVD Maker",
+		.decoder      = EM28XX_SAA711X,
+		.tuner_type   = TUNER_ABSENT,	/* Capture only device */
+		.input        = { {
+			.type  = EM28XX_VMUX_COMPOSITE1,
+			.vmux  = SAA7115_COMPOSITE0,
+			.amux  = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type  = EM28XX_VMUX_SVIDEO,
+			.vmux  = SAA7115_SVIDEO3,
+			.amux  = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2860_BOARD_GADMEI_UTV330] = {
+		.name         = "Gadmei UTV330",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_TNF_5335MF,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE2,
+			.amux     = EM28XX_AMUX_VIDEO,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2861_BOARD_GADMEI_UTV330PLUS] = {
+		.name         = "Gadmei UTV330+",
+		.tuner_type   = TUNER_TNF_5335MF,
+		.tda9887_conf = TDA9887_PRESENT,
+		.ir_codes     = RC_MAP_GADMEI_RM008Z,
+		.decoder      = EM28XX_SAA711X,
+		.xclk         = EM28XX_XCLK_FREQUENCY_12MHZ,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE2,
+			.amux     = EM28XX_AMUX_VIDEO,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2860_BOARD_TERRATEC_HYBRID_XS] = {
+		.name         = "Terratec Cinergy A Hybrid XS",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.decoder      = EM28XX_TVP5150,
+
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		} },
+	},
+	[EM2861_BOARD_KWORLD_PVRTV_300U] = {
+		.name	      = "KWorld PVRTV 300U",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.decoder      = EM28XX_TVP5150,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2861_BOARD_YAKUMO_MOVIE_MIXER] = {
+		.name          = "Yakumo MovieMixer",
+		.tuner_type    = TUNER_ABSENT,	/* Capture only device */
+		.decoder       = EM28XX_TVP5150,
+		.input         = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2860_BOARD_TVP5150_REFERENCE_DESIGN] = {
+		.name          = "EM2860/TVP5150 Reference Design",
+		.tuner_type    = TUNER_ABSENT,	/* Capture only device */
+		.decoder       = EM28XX_TVP5150,
+		.input         = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2861_BOARD_PLEXTOR_PX_TV100U] = {
+		.name         = "Plextor ConvertX PX-TV100U",
+		.tuner_type   = TUNER_TNF_5335MF,
+		.xclk         = EM28XX_XCLK_I2S_MSB_TIMING |
+				EM28XX_XCLK_FREQUENCY_12MHZ,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_TVP5150,
+		.has_msp34xx  = 1,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = pinnacle_hybrid_pro_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = pinnacle_hybrid_pro_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = pinnacle_hybrid_pro_analog,
+		} },
+	},
+
+	/* Those boards with em2870 are DVB Only*/
+
+	[EM2870_BOARD_TERRATEC_XS] = {
+		.name         = "Terratec Cinergy T XS",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+	},
+	[EM2870_BOARD_TERRATEC_XS_MT2060] = {
+		.name         = "Terratec Cinergy T XS (MT2060)",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_ABSENT, /* MT2060 */
+	},
+	[EM2870_BOARD_KWORLD_350U] = {
+		.name         = "Kworld 350 U DVB-T",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+	},
+	[EM2870_BOARD_KWORLD_355U] = {
+		.name         = "Kworld 355 U DVB-T",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_ABSENT,
+		.tuner_gpio   = default_tuner_gpio,
+		.has_dvb      = 1,
+		.dvb_gpio     = default_digital,
+	},
+	[EM2870_BOARD_PINNACLE_PCTV_DVB] = {
+		.name         = "Pinnacle PCTV DVB-T",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_ABSENT, /* MT2060 */
+		/* djh - I have serious doubts this is right... */
+		.xclk         = EM28XX_XCLK_IR_RC5_MODE |
+				EM28XX_XCLK_FREQUENCY_10MHZ,
+	},
+	[EM2870_BOARD_COMPRO_VIDEOMATE] = {
+		.name         = "Compro, VideoMate U3",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_ABSENT, /* MT2060 */
+	},
+
+	[EM2880_BOARD_TERRATEC_HYBRID_XS_FR] = {
+		.name         = "Terratec Hybrid XS Secam",
+		.has_msp34xx  = 1,
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.decoder      = EM28XX_TVP5150,
+		.has_dvb      = 1,
+		.dvb_gpio     = terratec_cinergy_USB_XS_FR_digital,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = terratec_cinergy_USB_XS_FR_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = terratec_cinergy_USB_XS_FR_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = terratec_cinergy_USB_XS_FR_analog,
+		} },
+	},
+	[EM2884_BOARD_TERRATEC_H5] = {
+		.name         = "Terratec Cinergy H5",
+		.has_dvb      = 1,
+#if 0
+		.tuner_type   = TUNER_PHILIPS_TDA8290,
+		.tuner_addr   = 0x41,
+		.dvb_gpio     = terratec_h5_digital, /* FIXME: probably wrong */
+		.tuner_gpio   = terratec_h5_gpio,
+#else
+		.tuner_type   = TUNER_ABSENT,
+#endif
+		.i2c_speed    = EM2874_I2C_SECONDARY_BUS_SELECT |
+				EM28XX_I2C_CLK_WAIT_ENABLE |
+				EM28XX_I2C_FREQ_400_KHZ,
+	},
+	[EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C] = {
+		.name         = "Hauppauge WinTV HVR 930C",
+		.has_dvb      = 1,
+#if 0 /* FIXME: Add analog support */
+		.tuner_type   = TUNER_XC5000,
+		.tuner_addr   = 0x41,
+		.dvb_gpio     = hauppauge_930c_digital,
+		.tuner_gpio   = hauppauge_930c_gpio,
+#else
+		.tuner_type   = TUNER_ABSENT,
+#endif
+		.ir_codes     = RC_MAP_HAUPPAUGE,
+		.i2c_speed    = EM2874_I2C_SECONDARY_BUS_SELECT |
+				EM28XX_I2C_CLK_WAIT_ENABLE |
+				EM28XX_I2C_FREQ_400_KHZ,
+	},
+	[EM2884_BOARD_CINERGY_HTC_STICK] = {
+		.name         = "Terratec Cinergy HTC Stick",
+		.has_dvb      = 1,
+		.ir_codes     = RC_MAP_NEC_TERRATEC_CINERGY_XS,
+		.tuner_type   = TUNER_ABSENT,
+		.i2c_speed    = EM2874_I2C_SECONDARY_BUS_SELECT |
+				EM28XX_I2C_CLK_WAIT_ENABLE |
+				EM28XX_I2C_FREQ_400_KHZ,
+	},
+	[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = {
+		.name         = "Hauppauge WinTV HVR 900",
+		.tda9887_conf = TDA9887_PRESENT,
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.mts_firmware = 1,
+		.has_dvb      = 1,
+		.dvb_gpio     = hauppauge_wintv_hvr_900_digital,
+		.ir_codes     = RC_MAP_HAUPPAUGE,
+		.decoder      = EM28XX_TVP5150,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		} },
+	},
+	[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2] = {
+		.name         = "Hauppauge WinTV HVR 900 (R2)",
+		.tda9887_conf = TDA9887_PRESENT,
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.mts_firmware = 1,
+		.has_dvb      = 1,
+		.dvb_gpio     = hauppauge_wintv_hvr_900R2_digital,
+		.ir_codes     = RC_MAP_HAUPPAUGE,
+		.decoder      = EM28XX_TVP5150,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		} },
+	},
+	[EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850] = {
+		.name           = "Hauppauge WinTV HVR 850",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_gpio     = default_tuner_gpio,
+		.mts_firmware   = 1,
+		.has_dvb        = 1,
+		.dvb_gpio       = hauppauge_wintv_hvr_900_digital,
+		.ir_codes       = RC_MAP_HAUPPAUGE,
+		.decoder        = EM28XX_TVP5150,
+		.input          = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		} },
+	},
+	[EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950] = {
+		.name           = "Hauppauge WinTV HVR 950",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_gpio     = default_tuner_gpio,
+		.mts_firmware   = 1,
+		.has_dvb        = 1,
+		.dvb_gpio       = hauppauge_wintv_hvr_900_digital,
+		.ir_codes       = RC_MAP_HAUPPAUGE,
+		.decoder        = EM28XX_TVP5150,
+		.input          = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		} },
+	},
+	[EM2880_BOARD_PINNACLE_PCTV_HD_PRO] = {
+		.name           = "Pinnacle PCTV HD Pro Stick",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.mts_firmware   = 1,
+		.has_dvb        = 1,
+		.dvb_gpio       = hauppauge_wintv_hvr_900_digital,
+		.ir_codes       = RC_MAP_PINNACLE_PCTV_HD,
+		.decoder        = EM28XX_TVP5150,
+		.input          = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		} },
+	},
+	[EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = {
+		.name           = "AMD ATI TV Wonder HD 600",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_gpio     = default_tuner_gpio,
+		.mts_firmware   = 1,
+		.has_dvb        = 1,
+		.dvb_gpio       = hauppauge_wintv_hvr_900_digital,
+		.ir_codes       = RC_MAP_ATI_TV_WONDER_HD_600,
+		.decoder        = EM28XX_TVP5150,
+		.input          = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		} },
+	},
+	[EM2880_BOARD_TERRATEC_HYBRID_XS] = {
+		.name           = "Terratec Hybrid XS",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_gpio     = default_tuner_gpio,
+		.decoder        = EM28XX_TVP5150,
+		.has_dvb        = 1,
+		.dvb_gpio       = default_digital,
+		.ir_codes       = RC_MAP_TERRATEC_CINERGY_XS,
+		.xclk           = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */
+		.input          = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = default_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = default_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = default_analog,
+		} },
+	},
+	/* maybe there's a reason behind it why Terratec sells the Hybrid XS
+	   as Prodigy XS with a different PID, let's keep it separated for now
+	   maybe we'll need it lateron */
+	[EM2880_BOARD_TERRATEC_PRODIGY_XS] = {
+		.name         = "Terratec Prodigy XS",
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.decoder      = EM28XX_TVP5150,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		} },
+	},
+	[EM2820_BOARD_MSI_VOX_USB_2] = {
+		.name		   = "MSI VOX USB 2.0",
+		.tuner_type	   = TUNER_LG_PAL_NEW_TAPC,
+		.tda9887_conf	   = TDA9887_PRESENT      |
+				     TDA9887_PORT1_ACTIVE |
+				     TDA9887_PORT2_ACTIVE,
+		.max_range_640_480 = 1,
+		.decoder           = EM28XX_SAA711X,
+		.input             = { {
+			.type      = EM28XX_VMUX_TELEVISION,
+			.vmux      = SAA7115_COMPOSITE4,
+			.amux      = EM28XX_AMUX_VIDEO,
+		}, {
+			.type      = EM28XX_VMUX_COMPOSITE1,
+			.vmux      = SAA7115_COMPOSITE0,
+			.amux      = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type      = EM28XX_VMUX_SVIDEO,
+			.vmux      = SAA7115_SVIDEO3,
+			.amux      = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2800_BOARD_TERRATEC_CINERGY_200] = {
+		.name         = "Terratec Cinergy 200 USB",
+		.is_em2800    = 1,
+		.has_ir_i2c   = 1,
+		.tuner_type   = TUNER_LG_TALN,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE2,
+			.amux     = EM28XX_AMUX_VIDEO,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2800_BOARD_GRABBEEX_USB2800] = {
+		.name       = "eMPIA Technology, Inc. GrabBeeX+ Video Encoder",
+		.is_em2800  = 1,
+		.decoder    = EM28XX_SAA711X,
+		.tuner_type = TUNER_ABSENT, /* capture only board */
+		.input      = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2800_BOARD_VC211A] = {
+		.name         = "Actionmaster/LinXcel/Digitus VC211A",
+		.is_em2800    = 1,
+		.tuner_type   = TUNER_ABSENT,	/* Capture-only board */
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = vc211a_enable,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = vc211a_enable,
+		} },
+	},
+	[EM2800_BOARD_LEADTEK_WINFAST_USBII] = {
+		.name         = "Leadtek Winfast USB II",
+		.is_em2800    = 1,
+		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE2,
+			.amux     = EM28XX_AMUX_VIDEO,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2800_BOARD_KWORLD_USB2800] = {
+		.name         = "Kworld USB2800",
+		.is_em2800    = 1,
+		.tuner_type   = TUNER_PHILIPS_FCV1236D,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE2,
+			.amux     = EM28XX_AMUX_VIDEO,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2820_BOARD_PINNACLE_DVC_90] = {
+		.name         = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker "
+			       "/ Kworld DVD Maker 2 / Plextor ConvertX PX-AV100U",
+		.tuner_type   = TUNER_ABSENT, /* capture only board */
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2800_BOARD_VGEAR_POCKETTV] = {
+		.name         = "V-Gear PocketTV",
+		.is_em2800    = 1,
+		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE2,
+			.amux     = EM28XX_AMUX_VIDEO,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2] = {
+		.name         = "Pixelview PlayTV Box 4 USB 2.0",
+		.tda9887_conf = TDA9887_PRESENT,
+		.tuner_type   = TUNER_YMEC_TVF_5533MF,
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE2,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.aout     = EM28XX_AOUT_MONO | 	/* I2S */
+				    EM28XX_AOUT_MASTER,	/* Line out pin */
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2820_BOARD_PROLINK_PLAYTV_USB2] = {
+		.name         = "SIIG AVTuner-PVR / Pixelview Prolink PlayTV USB 2.0",
+		.has_snapshot_button = 1,
+		.tda9887_conf = TDA9887_PRESENT,
+		.tuner_type   = TUNER_YMEC_TVF_5533MF,
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE2,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.aout     = EM28XX_AOUT_MONO | 	/* I2S */
+				    EM28XX_AOUT_MASTER,	/* Line out pin */
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2860_BOARD_SAA711X_REFERENCE_DESIGN] = {
+		.name                = "EM2860/SAA711X Reference Design",
+		.has_snapshot_button = 1,
+		.tuner_type          = TUNER_ABSENT,
+		.decoder             = EM28XX_SAA711X,
+		.input               = { {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+		} },
+	},
+
+	[EM2874_BOARD_LEADERSHIP_ISDBT] = {
+		.i2c_speed      = EM2874_I2C_SECONDARY_BUS_SELECT |
+				  EM28XX_I2C_CLK_WAIT_ENABLE |
+				  EM28XX_I2C_FREQ_100_KHZ,
+		.xclk		= EM28XX_XCLK_FREQUENCY_10MHZ,
+		.name		= "EM2874 Leadership ISDBT",
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_gpio     = leadership_reset,
+		.dvb_gpio       = leadership_digital,
+		.has_dvb	= 1,
+	},
+
+	[EM2880_BOARD_MSI_DIGIVOX_AD] = {
+		.name         = "MSI DigiVox A/D",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.decoder      = EM28XX_TVP5150,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = em2880_msi_digivox_ad_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = em2880_msi_digivox_ad_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = em2880_msi_digivox_ad_analog,
+		} },
+	},
+	[EM2880_BOARD_MSI_DIGIVOX_AD_II] = {
+		.name         = "MSI DigiVox A/D II",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.decoder      = EM28XX_TVP5150,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = em2880_msi_digivox_ad_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = em2880_msi_digivox_ad_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = em2880_msi_digivox_ad_analog,
+		} },
+	},
+	[EM2880_BOARD_KWORLD_DVB_305U] = {
+		.name	      = "KWorld DVB-T 305U",
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.decoder      = EM28XX_TVP5150,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2880_BOARD_KWORLD_DVB_310U] = {
+		.name	      = "KWorld DVB-T 310U",
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.has_dvb      = 1,
+		.dvb_gpio     = default_digital,
+		.mts_firmware = 1,
+		.decoder      = EM28XX_TVP5150,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = default_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = default_analog,
+		}, {	/* S-video has not been tested yet */
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = default_analog,
+		} },
+	},
+	[EM2882_BOARD_KWORLD_ATSC_315U] = {
+		.name		= "KWorld ATSC 315U HDTV TV Box",
+		.valid		= EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type	= TUNER_THOMSON_DTT761X,
+		.tuner_gpio	= em2882_kworld_315u_tuner_gpio,
+		.tda9887_conf	= TDA9887_PRESENT,
+		.decoder	= EM28XX_SAA711X,
+		.has_dvb	= 1,
+		.dvb_gpio	= em2882_kworld_315u_digital,
+		.ir_codes	= RC_MAP_KWORLD_315U,
+		.xclk		= EM28XX_XCLK_FREQUENCY_12MHZ,
+		.i2c_speed	= EM28XX_I2C_CLK_WAIT_ENABLE,
+		/* Analog mode - still not ready */
+		/*.input        = { {
+			.type = EM28XX_VMUX_TELEVISION,
+			.vmux = SAA7115_COMPOSITE2,
+			.amux = EM28XX_AMUX_VIDEO,
+			.gpio = em2882_kworld_315u_analog,
+			.aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO,
+		}, {
+			.type = EM28XX_VMUX_COMPOSITE1,
+			.vmux = SAA7115_COMPOSITE0,
+			.amux = EM28XX_AMUX_LINE_IN,
+			.gpio = em2882_kworld_315u_analog1,
+			.aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO,
+		}, {
+			.type = EM28XX_VMUX_SVIDEO,
+			.vmux = SAA7115_SVIDEO3,
+			.amux = EM28XX_AMUX_LINE_IN,
+			.gpio = em2882_kworld_315u_analog1,
+			.aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO,
+		} }, */
+	},
+	[EM2880_BOARD_EMPIRE_DUAL_TV] = {
+		.name = "Empire dual TV",
+		.tuner_type = TUNER_XC2028,
+		.tuner_gpio = default_tuner_gpio,
+		.has_dvb = 1,
+		.dvb_gpio = default_digital,
+		.mts_firmware = 1,
+		.decoder = EM28XX_TVP5150,
+		.input = { {
+			.type = EM28XX_VMUX_TELEVISION,
+			.vmux = TVP5150_COMPOSITE0,
+			.amux = EM28XX_AMUX_VIDEO,
+			.gpio = default_analog,
+		}, {
+			.type = EM28XX_VMUX_COMPOSITE1,
+			.vmux = TVP5150_COMPOSITE1,
+			.amux = EM28XX_AMUX_LINE_IN,
+			.gpio = default_analog,
+		}, {
+			.type = EM28XX_VMUX_SVIDEO,
+			.vmux = TVP5150_SVIDEO,
+			.amux = EM28XX_AMUX_LINE_IN,
+			.gpio = default_analog,
+		} },
+	},
+	[EM2881_BOARD_DNT_DA2_HYBRID] = {
+		.name         = "DNT DA2 Hybrid",
+		.valid        = EM28XX_BOARD_NOT_VALIDATED,
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.decoder      = EM28XX_TVP5150,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = default_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = default_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = default_analog,
+		} },
+	},
+	[EM2881_BOARD_PINNACLE_HYBRID_PRO] = {
+		.name         = "Pinnacle Hybrid Pro",
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.decoder      = EM28XX_TVP5150,
+		.has_dvb      = 1,
+		.dvb_gpio     = pinnacle_hybrid_pro_digital,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = pinnacle_hybrid_pro_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = pinnacle_hybrid_pro_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = pinnacle_hybrid_pro_analog,
+		} },
+	},
+	[EM2882_BOARD_PINNACLE_HYBRID_PRO_330E] = {
+		.name         = "Pinnacle Hybrid Pro (330e)",
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.mts_firmware = 1,
+		.has_dvb      = 1,
+		.dvb_gpio     = hauppauge_wintv_hvr_900R2_digital,
+		.ir_codes     = RC_MAP_PINNACLE_PCTV_HD,
+		.decoder      = EM28XX_TVP5150,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		} },
+	},
+	[EM2882_BOARD_KWORLD_VS_DVBT] = {
+		.name         = "Kworld VS-DVB-T 323UR",
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.decoder      = EM28XX_TVP5150,
+		.mts_firmware = 1,
+		.has_dvb      = 1,
+		.dvb_gpio     = kworld_330u_digital,
+		.xclk         = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */
+		.ir_codes     = RC_MAP_KWORLD_315U,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2882_BOARD_TERRATEC_HYBRID_XS] = {
+		.name         = "Terratec Cinnergy Hybrid T USB XS (em2882)",
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.mts_firmware = 1,
+		.decoder      = EM28XX_TVP5150,
+		.has_dvb      = 1,
+		.dvb_gpio     = hauppauge_wintv_hvr_900_digital,
+		.ir_codes     = RC_MAP_TERRATEC_CINERGY_XS,
+		.xclk         = EM28XX_XCLK_FREQUENCY_12MHZ,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = hauppauge_wintv_hvr_900_analog,
+		} },
+	},
+	[EM2882_BOARD_DIKOM_DK300] = {
+		.name         = "Dikom DK300",
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.decoder      = EM28XX_TVP5150,
+		.mts_firmware = 1,
+		.has_dvb      = 1,
+		.dvb_gpio     = dikom_dk300_digital,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = default_analog,
+		} },
+	},
+	[EM2883_BOARD_KWORLD_HYBRID_330U] = {
+		.name         = "Kworld PlusTV HD Hybrid 330",
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.decoder      = EM28XX_TVP5150,
+		.mts_firmware = 1,
+		.has_dvb      = 1,
+		.dvb_gpio     = kworld_330u_digital,
+		.xclk             = EM28XX_XCLK_FREQUENCY_12MHZ,
+		.i2c_speed        = EM28XX_I2C_CLK_WAIT_ENABLE |
+				    EM28XX_I2C_EEPROM_ON_BOARD |
+				    EM28XX_I2C_EEPROM_KEY_VALID,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = kworld_330u_analog,
+			.aout     = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = kworld_330u_analog,
+			.aout     = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = kworld_330u_analog,
+		} },
+	},
+	[EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU] = {
+		.name         = "Compro VideoMate ForYou/Stereo",
+		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+		.tvaudio_addr = 0xb0,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_TVP5150,
+		.adecoder     = EM28XX_TVAUDIO,
+		.mute_gpio    = compro_mute_gpio,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = compro_unmute_tv_gpio,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = compro_unmute_svid_gpio,
+		} },
+	},
+	[EM2860_BOARD_KAIOMY_TVNPC_U2] = {
+		.name	      = "Kaiomy TVnPC U2",
+		.vchannels    = 3,
+		.tuner_type   = TUNER_XC2028,
+		.tuner_addr   = 0x61,
+		.mts_firmware = 1,
+		.decoder      = EM28XX_TVP5150,
+		.tuner_gpio   = default_tuner_gpio,
+		.ir_codes     = RC_MAP_KAIOMY,
+		.input          = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+		.radio		= {
+			.type     = EM28XX_RADIO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}
+	},
+	[EM2860_BOARD_EASYCAP] = {
+		.name         = "Easy Cap Capture DC-60",
+		.vchannels    = 2,
+		.tuner_type   = TUNER_ABSENT,
+		.decoder      = EM28XX_SAA711X,
+		.input           = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2820_BOARD_IODATA_GVMVP_SZ] = {
+		.name       = "IO-DATA GV-MVP/SZ",
+		.tuner_type   = TUNER_PHILIPS_FM1236_MK3,
+		.tuner_gpio   = default_tuner_gpio,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_TVP5150,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+		}, { /* Composite has not been tested yet */
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_VIDEO,
+		}, { /* S-video has not been tested yet */
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_VIDEO,
+		} },
+	},
+	[EM2860_BOARD_TERRATEC_GRABBY] = {
+		.name            = "Terratec Grabby",
+		.vchannels       = 2,
+		.tuner_type      = TUNER_ABSENT,
+		.decoder         = EM28XX_SAA711X,
+		.xclk            = EM28XX_XCLK_FREQUENCY_12MHZ,
+		.input           = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	[EM2860_BOARD_TERRATEC_AV350] = {
+		.name            = "Terratec AV350",
+		.vchannels       = 2,
+		.tuner_type      = TUNER_ABSENT,
+		.decoder         = EM28XX_TVP5150,
+		.xclk            = EM28XX_XCLK_FREQUENCY_12MHZ,
+		.mute_gpio       = terratec_av350_mute_gpio,
+		.input           = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AUDIO_SRC_LINE,
+			.gpio     = terratec_av350_unmute_gpio,
+
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AUDIO_SRC_LINE,
+			.gpio     = terratec_av350_unmute_gpio,
+		} },
+	},
+
+	[EM2860_BOARD_ELGATO_VIDEO_CAPTURE] = {
+		.name         = "Elgato Video Capture",
+		.decoder      = EM28XX_SAA711X,
+		.tuner_type   = TUNER_ABSENT,   /* Capture only device */
+		.input        = { {
+			.type  = EM28XX_VMUX_COMPOSITE1,
+			.vmux  = SAA7115_COMPOSITE0,
+			.amux  = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type  = EM28XX_VMUX_SVIDEO,
+			.vmux  = SAA7115_SVIDEO3,
+			.amux  = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+
+	[EM2882_BOARD_EVGA_INDTUBE] = {
+		.name         = "Evga inDtube",
+		.tuner_type   = TUNER_XC2028,
+		.tuner_gpio   = default_tuner_gpio,
+		.decoder      = EM28XX_TVP5150,
+		.xclk         = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */
+		.mts_firmware = 1,
+		.has_dvb      = 1,
+		.dvb_gpio     = evga_indtube_digital,
+		.ir_codes     = RC_MAP_EVGA_INDTUBE,
+		.input        = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = EM28XX_AMUX_VIDEO,
+			.gpio     = evga_indtube_analog,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = evga_indtube_analog,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = evga_indtube_analog,
+		} },
+	},
+	/* eb1a:2868 Empia EM2870 + Philips CU1216L NIM (Philips TDA10023 +
+	   Infineon TUA6034) */
+	[EM2870_BOARD_REDDO_DVB_C_USB_BOX] = {
+		.name          = "Reddo DVB-C USB TV Box",
+		.tuner_type    = TUNER_ABSENT,
+		.tuner_gpio    = reddo_dvb_c_usb_box,
+		.has_dvb       = 1,
+	},
+	/* 1b80:a340 - Empia EM2870, NXP TDA18271HD and LG DT3304, sold
+	 * initially as the KWorld PlusTV 340U, then as the UB435-Q.
+	 * Early variants have a TDA18271HD/C1, later ones a TDA18271HD/C2 */
+	[EM2870_BOARD_KWORLD_A340] = {
+		.name       = "KWorld PlusTV 340U or UB435-Q (ATSC)",
+		.tuner_type = TUNER_ABSENT,	/* Digital-only TDA18271HD */
+		.has_dvb    = 1,
+		.dvb_gpio   = kworld_a340_digital,
+		.tuner_gpio = default_tuner_gpio,
+	},
+	/* 2013:024f PCTV nanoStick T2 290e.
+	 * Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 */
+	[EM28174_BOARD_PCTV_290E] = {
+		.name          = "PCTV nanoStick T2 290e",
+		.i2c_speed      = EM2874_I2C_SECONDARY_BUS_SELECT |
+			EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ,
+		.tuner_type    = TUNER_ABSENT,
+		.tuner_gpio    = pctv_290e,
+		.has_dvb       = 1,
+		.ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
+	},
+	/* 2013:024f PCTV DVB-S2 Stick 460e
+	 * Empia EM28174, NXP TDA10071, Conexant CX24118A and Allegro A8293 */
+	[EM28174_BOARD_PCTV_460E] = {
+		.i2c_speed     = EM2874_I2C_SECONDARY_BUS_SELECT |
+			EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
+		.name          = "PCTV DVB-S2 Stick (460e)",
+		.tuner_type    = TUNER_ABSENT,
+		.tuner_gpio    = pctv_460e,
+		.has_dvb       = 1,
+		.ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
+	},
+	/* eb1a:5006 Honestech VIDBOX NW03
+	 * Empia EM2860, Philips SAA7113, Empia EMP202, No Tuner */
+	[EM2860_BOARD_HT_VIDBOX_NW03] = {
+		.name                = "Honestech Vidbox NW03",
+		.tuner_type          = TUNER_ABSENT,
+		.decoder             = EM28XX_SAA711X,
+		.input               = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,  /* S-VIDEO needs confirming */
+			.amux     = EM28XX_AMUX_LINE_IN,
+		} },
+	},
+	/* 1b80:e425 MaxMedia UB425-TC
+	 * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 */
+	[EM2874_BOARD_MAXMEDIA_UB425_TC] = {
+		.name          = "MaxMedia UB425-TC",
+		.tuner_type    = TUNER_ABSENT,
+		.tuner_gpio    = maxmedia_ub425_tc,
+		.has_dvb       = 1,
+		.i2c_speed     = EM2874_I2C_SECONDARY_BUS_SELECT |
+				EM28XX_I2C_CLK_WAIT_ENABLE |
+				EM28XX_I2C_FREQ_400_KHZ,
+	},
+	/* 2304:0242 PCTV QuatroStick (510e)
+	 * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */
+	[EM2884_BOARD_PCTV_510E] = {
+		.name          = "PCTV QuatroStick (510e)",
+		.tuner_type    = TUNER_ABSENT,
+		.tuner_gpio    = pctv_510e,
+		.has_dvb       = 1,
+		.ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
+		.i2c_speed     = EM2874_I2C_SECONDARY_BUS_SELECT |
+				EM28XX_I2C_CLK_WAIT_ENABLE |
+				EM28XX_I2C_FREQ_400_KHZ,
+	},
+	/* 2013:0251 PCTV QuatroStick nano (520e)
+	 * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */
+	[EM2884_BOARD_PCTV_520E] = {
+		.name          = "PCTV QuatroStick nano (520e)",
+		.tuner_type    = TUNER_ABSENT,
+		.tuner_gpio    = pctv_520e,
+		.has_dvb       = 1,
+		.ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
+		.i2c_speed     = EM2874_I2C_SECONDARY_BUS_SELECT |
+				EM28XX_I2C_CLK_WAIT_ENABLE |
+				EM28XX_I2C_FREQ_400_KHZ,
+	},
+};
+const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
+
+/* table of devices that work with this driver */
+struct usb_device_id em28xx_id_table[] = {
+	{ USB_DEVICE(0xeb1a, 0x2750),
+			.driver_info = EM2750_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2751),
+			.driver_info = EM2750_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2800),
+			.driver_info = EM2800_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2710),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2820),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2821),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2860),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2861),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2862),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2863),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2870),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2881),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2883),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2868),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2875),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0xe300),
+			.driver_info = EM2861_BOARD_KWORLD_PVRTV_300U },
+	{ USB_DEVICE(0xeb1a, 0xe303),
+			.driver_info = EM2860_BOARD_KAIOMY_TVNPC_U2 },
+	{ USB_DEVICE(0xeb1a, 0xe305),
+			.driver_info = EM2880_BOARD_KWORLD_DVB_305U },
+	{ USB_DEVICE(0xeb1a, 0xe310),
+			.driver_info = EM2880_BOARD_MSI_DIGIVOX_AD },
+	{ USB_DEVICE(0xeb1a, 0xa313),
+		.driver_info = EM2882_BOARD_KWORLD_ATSC_315U },
+	{ USB_DEVICE(0xeb1a, 0xa316),
+			.driver_info = EM2883_BOARD_KWORLD_HYBRID_330U },
+	{ USB_DEVICE(0xeb1a, 0xe320),
+			.driver_info = EM2880_BOARD_MSI_DIGIVOX_AD_II },
+	{ USB_DEVICE(0xeb1a, 0xe323),
+			.driver_info = EM2882_BOARD_KWORLD_VS_DVBT },
+	{ USB_DEVICE(0xeb1a, 0xe350),
+			.driver_info = EM2870_BOARD_KWORLD_350U },
+	{ USB_DEVICE(0xeb1a, 0xe355),
+			.driver_info = EM2870_BOARD_KWORLD_355U },
+	{ USB_DEVICE(0xeb1a, 0x2801),
+			.driver_info = EM2800_BOARD_GRABBEEX_USB2800 },
+	{ USB_DEVICE(0xeb1a, 0xe357),
+			.driver_info = EM2870_BOARD_KWORLD_355U },
+	{ USB_DEVICE(0xeb1a, 0xe359),
+			.driver_info = EM2870_BOARD_KWORLD_355U },
+	{ USB_DEVICE(0x1b80, 0xe302),
+			.driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kaiser Baas Video to DVD maker */
+	{ USB_DEVICE(0x1b80, 0xe304),
+			.driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kworld DVD Maker 2 */
+	{ USB_DEVICE(0x0ccd, 0x0036),
+			.driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
+	{ USB_DEVICE(0x0ccd, 0x004c),
+			.driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS_FR },
+	{ USB_DEVICE(0x0ccd, 0x004f),
+			.driver_info = EM2860_BOARD_TERRATEC_HYBRID_XS },
+	{ USB_DEVICE(0x0ccd, 0x005e),
+			.driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS },
+	{ USB_DEVICE(0x0ccd, 0x0042),
+			.driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS },
+	{ USB_DEVICE(0x0ccd, 0x0043),
+			.driver_info = EM2870_BOARD_TERRATEC_XS },
+	{ USB_DEVICE(0x0ccd, 0x008e),	/* Cinergy HTC USB XS Rev. 1 */
+			.driver_info = EM2884_BOARD_TERRATEC_H5 },
+	{ USB_DEVICE(0x0ccd, 0x00ac),	/* Cinergy HTC USB XS Rev. 2 */
+			.driver_info = EM2884_BOARD_TERRATEC_H5 },
+	{ USB_DEVICE(0x0ccd, 0x10a2),	/* H5 Rev. 1 */
+			.driver_info = EM2884_BOARD_TERRATEC_H5 },
+	{ USB_DEVICE(0x0ccd, 0x10ad),	/* H5 Rev. 2 */
+			.driver_info = EM2884_BOARD_TERRATEC_H5 },
+	{ USB_DEVICE(0x0ccd, 0x0084),
+			.driver_info = EM2860_BOARD_TERRATEC_AV350 },
+	{ USB_DEVICE(0x0ccd, 0x0096),
+			.driver_info = EM2860_BOARD_TERRATEC_GRABBY },
+	{ USB_DEVICE(0x0ccd, 0x10AF),
+			.driver_info = EM2860_BOARD_TERRATEC_GRABBY },
+	{ USB_DEVICE(0x0ccd, 0x00b2),
+			.driver_info = EM2884_BOARD_CINERGY_HTC_STICK },
+	{ USB_DEVICE(0x0fd9, 0x0033),
+			.driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE},
+	{ USB_DEVICE(0x185b, 0x2870),
+			.driver_info = EM2870_BOARD_COMPRO_VIDEOMATE },
+	{ USB_DEVICE(0x185b, 0x2041),
+			.driver_info = EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU },
+	{ USB_DEVICE(0x2040, 0x4200),
+			.driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
+	{ USB_DEVICE(0x2040, 0x4201),
+			.driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
+	{ USB_DEVICE(0x2040, 0x6500),
+			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
+	{ USB_DEVICE(0x2040, 0x6502),
+			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 },
+	{ USB_DEVICE(0x2040, 0x6513), /* HCW HVR-980 */
+			.driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+	{ USB_DEVICE(0x2040, 0x6517), /* HP  HVR-950 */
+			.driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+	{ USB_DEVICE(0x2040, 0x651b), /* RP  HVR-950 */
+			.driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+	{ USB_DEVICE(0x2040, 0x651f),
+			.driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 },
+	{ USB_DEVICE(0x0438, 0xb002),
+			.driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 },
+	{ USB_DEVICE(0x2001, 0xf112),
+			.driver_info = EM2820_BOARD_DLINK_USB_TV },
+	{ USB_DEVICE(0x2304, 0x0207),
+			.driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+	{ USB_DEVICE(0x2304, 0x0208),
+			.driver_info = EM2820_BOARD_PINNACLE_USB_2 },
+	{ USB_DEVICE(0x2304, 0x021a),
+			.driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+	{ USB_DEVICE(0x2304, 0x0226),
+			.driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO_330E },
+	{ USB_DEVICE(0x2304, 0x0227),
+			.driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO },
+	{ USB_DEVICE(0x0413, 0x6023),
+			.driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII },
+	{ USB_DEVICE(0x093b, 0xa003),
+		       .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+	{ USB_DEVICE(0x093b, 0xa005),
+			.driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U },
+	{ USB_DEVICE(0x04bb, 0x0515),
+			.driver_info = EM2820_BOARD_IODATA_GVMVP_SZ },
+	{ USB_DEVICE(0xeb1a, 0x50a6),
+			.driver_info = EM2860_BOARD_GADMEI_UTV330 },
+	{ USB_DEVICE(0x1b80, 0xa340),
+			.driver_info = EM2870_BOARD_KWORLD_A340 },
+	{ USB_DEVICE(0x2013, 0x024f),
+			.driver_info = EM28174_BOARD_PCTV_290E },
+	{ USB_DEVICE(0x2013, 0x024c),
+			.driver_info = EM28174_BOARD_PCTV_460E },
+	{ USB_DEVICE(0x2040, 0x1605),
+			.driver_info = EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C },
+	{ USB_DEVICE(0xeb1a, 0x5006),
+			.driver_info = EM2860_BOARD_HT_VIDBOX_NW03 },
+	{ USB_DEVICE(0x1b80, 0xe309), /* Sveon STV40 */
+			.driver_info = EM2860_BOARD_EASYCAP },
+	{ USB_DEVICE(0x1b80, 0xe425),
+			.driver_info = EM2874_BOARD_MAXMEDIA_UB425_TC },
+	{ USB_DEVICE(0x2304, 0x0242),
+			.driver_info = EM2884_BOARD_PCTV_510E },
+	{ USB_DEVICE(0x2013, 0x0251),
+			.driver_info = EM2884_BOARD_PCTV_520E },
+	{ },
+};
+MODULE_DEVICE_TABLE(usb, em28xx_id_table);
+
+/*
+ * EEPROM hash table for devices with generic USB IDs
+ */
+static struct em28xx_hash_table em28xx_eeprom_hash[] = {
+	/* P/N: SA 60002070465 Tuner: TVF7533-MF */
+	{0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
+	{0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF},
+	{0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028},
+	{0x166a0441, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028},
+	{0xcee44a99, EM2882_BOARD_EVGA_INDTUBE, TUNER_XC2028},
+	{0xb8846b20, EM2881_BOARD_PINNACLE_HYBRID_PRO, TUNER_XC2028},
+	{0x63f653bd, EM2870_BOARD_REDDO_DVB_C_USB_BOX, TUNER_ABSENT},
+	{0x4e913442, EM2882_BOARD_DIKOM_DK300, TUNER_XC2028},
+};
+
+/* I2C devicelist hash table for devices with generic USB IDs */
+static struct em28xx_hash_table em28xx_i2c_hash[] = {
+	{0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC},
+	{0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
+	{0x1ba50080, EM2860_BOARD_SAA711X_REFERENCE_DESIGN, TUNER_ABSENT},
+	{0x77800080, EM2860_BOARD_TVP5150_REFERENCE_DESIGN, TUNER_ABSENT},
+	{0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC},
+	{0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF},
+	{0x6b800080, EM2874_BOARD_LEADERSHIP_ISDBT, TUNER_ABSENT},
+};
+
+/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
+static unsigned short saa711x_addrs[] = {
+	0x4a >> 1, 0x48 >> 1,   /* SAA7111, SAA7111A and SAA7113 */
+	0x42 >> 1, 0x40 >> 1,   /* SAA7114, SAA7115 and SAA7118 */
+	I2C_CLIENT_END };
+
+static unsigned short tvp5150_addrs[] = {
+	0xb8 >> 1,
+	0xba >> 1,
+	I2C_CLIENT_END
+};
+
+static unsigned short msp3400_addrs[] = {
+	0x80 >> 1,
+	0x88 >> 1,
+	I2C_CLIENT_END
+};
+
+int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
+{
+	int rc = 0;
+	struct em28xx *dev = ptr;
+
+	if (dev->tuner_type != TUNER_XC2028 && dev->tuner_type != TUNER_XC5000)
+		return 0;
+
+	if (command != XC2028_TUNER_RESET && command != XC5000_TUNER_RESET)
+		return 0;
+
+	rc = em28xx_gpio_set(dev, dev->board.tuner_gpio);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(em28xx_tuner_callback);
+
+static inline void em28xx_set_model(struct em28xx *dev)
+{
+	memcpy(&dev->board, &em28xx_boards[dev->model], sizeof(dev->board));
+
+	/* Those are the default values for the majority of boards
+	   Use those values if not specified otherwise at boards entry
+	 */
+	if (!dev->board.xclk)
+		dev->board.xclk = EM28XX_XCLK_IR_RC5_MODE |
+				  EM28XX_XCLK_FREQUENCY_12MHZ;
+
+	if (!dev->board.i2c_speed)
+		dev->board.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+				       EM28XX_I2C_FREQ_100_KHZ;
+}
+
+
+/* FIXME: Should be replaced by a proper mt9m111 driver */
+static int em28xx_initialize_mt9m111(struct em28xx *dev)
+{
+	int i;
+	unsigned char regs[][3] = {
+		{ 0x0d, 0x00, 0x01, },  /* reset and use defaults */
+		{ 0x0d, 0x00, 0x00, },
+		{ 0x0a, 0x00, 0x21, },
+		{ 0x21, 0x04, 0x00, },  /* full readout speed, no row/col skipping */
+	};
+
+	for (i = 0; i < ARRAY_SIZE(regs); i++)
+		i2c_master_send(&dev->i2c_client, &regs[i][0], 3);
+
+	return 0;
+}
+
+
+/* FIXME: Should be replaced by a proper mt9m001 driver */
+static int em28xx_initialize_mt9m001(struct em28xx *dev)
+{
+	int i;
+	unsigned char regs[][3] = {
+		{ 0x0d, 0x00, 0x01, },
+		{ 0x0d, 0x00, 0x00, },
+		{ 0x04, 0x05, 0x00, },	/* hres = 1280 */
+		{ 0x03, 0x04, 0x00, },  /* vres = 1024 */
+		{ 0x20, 0x11, 0x00, },
+		{ 0x06, 0x00, 0x10, },
+		{ 0x2b, 0x00, 0x24, },
+		{ 0x2e, 0x00, 0x24, },
+		{ 0x35, 0x00, 0x24, },
+		{ 0x2d, 0x00, 0x20, },
+		{ 0x2c, 0x00, 0x20, },
+		{ 0x09, 0x0a, 0xd4, },
+		{ 0x35, 0x00, 0x57, },
+	};
+
+	for (i = 0; i < ARRAY_SIZE(regs); i++)
+		i2c_master_send(&dev->i2c_client, &regs[i][0], 3);
+
+	return 0;
+}
+
+/* HINT method: webcam I2C chips
+ *
+ * This method works for webcams with Micron sensors
+ */
+static int em28xx_hint_sensor(struct em28xx *dev)
+{
+	int rc;
+	char *sensor_name;
+	unsigned char cmd;
+	__be16 version_be;
+	u16 version;
+
+	/* Micron sensor detection */
+	dev->i2c_client.addr = 0xba >> 1;
+	cmd = 0;
+	i2c_master_send(&dev->i2c_client, &cmd, 1);
+	rc = i2c_master_recv(&dev->i2c_client, (char *)&version_be, 2);
+	if (rc != 2)
+		return -EINVAL;
+
+	version = be16_to_cpu(version_be);
+	switch (version) {
+	case 0x8232:		/* mt9v011 640x480 1.3 Mpix sensor */
+	case 0x8243:		/* mt9v011 rev B 640x480 1.3 Mpix sensor */
+		dev->model = EM2820_BOARD_SILVERCREST_WEBCAM;
+		em28xx_set_model(dev);
+
+		sensor_name = "mt9v011";
+		dev->em28xx_sensor = EM28XX_MT9V011;
+		dev->sensor_xres = 640;
+		dev->sensor_yres = 480;
+		/*
+		 * FIXME: mt9v011 uses I2S speed as xtal clk - at least with
+		 * the Silvercrest cam I have here for testing - for higher
+		 * resolutions, a high clock cause horizontal artifacts, so we
+		 * need to use a lower xclk frequency.
+		 * Yet, it would be possible to adjust xclk depending on the
+		 * desired resolution, since this affects directly the
+		 * frame rate.
+		 */
+		dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ;
+		dev->sensor_xtal = 4300000;
+
+		/* probably means GRGB 16 bit bayer */
+		dev->vinmode = 0x0d;
+		dev->vinctl = 0x00;
+
+		break;
+
+	case 0x143a:    /* MT9M111 as found in the ECS G200 */
+		dev->model = EM2750_BOARD_UNKNOWN;
+		em28xx_set_model(dev);
+
+		sensor_name = "mt9m111";
+		dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ;
+		dev->em28xx_sensor = EM28XX_MT9M111;
+		em28xx_initialize_mt9m111(dev);
+		dev->sensor_xres = 640;
+		dev->sensor_yres = 512;
+
+		dev->vinmode = 0x0a;
+		dev->vinctl = 0x00;
+
+		break;
+
+	case 0x8431:
+		dev->model = EM2750_BOARD_UNKNOWN;
+		em28xx_set_model(dev);
+
+		sensor_name = "mt9m001";
+		dev->em28xx_sensor = EM28XX_MT9M001;
+		em28xx_initialize_mt9m001(dev);
+		dev->sensor_xres = 1280;
+		dev->sensor_yres = 1024;
+
+		/* probably means BGGR 16 bit bayer */
+		dev->vinmode = 0x0c;
+		dev->vinctl = 0x00;
+
+		break;
+	default:
+		printk("Unknown Micron Sensor 0x%04x\n", version);
+		return -EINVAL;
+	}
+
+	/* Setup webcam defaults */
+	em28xx_pre_card_setup(dev);
+
+	em28xx_errdev("Sensor is %s, using model %s entry.\n",
+		      sensor_name, em28xx_boards[dev->model].name);
+
+	return 0;
+}
+
+/* Since em28xx_pre_card_setup() requires a proper dev->model,
+ * this won't work for boards with generic PCI IDs
+ */
+static void em28xx_pre_card_setup(struct em28xx *dev)
+{
+	/* Set the initial XCLK and I2C clock values based on the board
+	   definition */
+	em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk & 0x7f);
+	if (!dev->board.is_em2800)
+		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
+	msleep(50);
+
+	/* request some modules */
+	switch (dev->model) {
+	case EM2861_BOARD_PLEXTOR_PX_TV100U:
+		/* Sets the msp34xx I2S speed */
+		dev->i2s_speed = 2048000;
+		break;
+	case EM2861_BOARD_KWORLD_PVRTV_300U:
+	case EM2880_BOARD_KWORLD_DVB_305U:
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x6d);
+		msleep(10);
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x7d);
+		msleep(10);
+		break;
+	case EM2870_BOARD_COMPRO_VIDEOMATE:
+		/* TODO: someone can do some cleanup here...
+			 not everything's needed */
+		em28xx_write_reg(dev, EM2880_R04_GPO, 0x00);
+		msleep(10);
+		em28xx_write_reg(dev, EM2880_R04_GPO, 0x01);
+		msleep(10);
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+		mdelay(70);
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfc);
+		mdelay(70);
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xdc);
+		mdelay(70);
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfc);
+		mdelay(70);
+		break;
+	case EM2870_BOARD_TERRATEC_XS_MT2060:
+		/* this device needs some gpio writes to get the DVB-T
+		   demod work */
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+		mdelay(70);
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xde);
+		mdelay(70);
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+		mdelay(70);
+		break;
+	case EM2870_BOARD_PINNACLE_PCTV_DVB:
+		/* this device needs some gpio writes to get the
+		   DVB-T demod work */
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+		mdelay(70);
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xde);
+		mdelay(70);
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+		mdelay(70);
+		break;
+	case EM2820_BOARD_GADMEI_UTV310:
+	case EM2820_BOARD_MSI_VOX_USB_2:
+		/* enables audio for that devices */
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+		break;
+
+	case EM2882_BOARD_KWORLD_ATSC_315U:
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+		msleep(10);
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+		msleep(10);
+		em28xx_write_reg(dev, EM2880_R04_GPO, 0x00);
+		msleep(10);
+		em28xx_write_reg(dev, EM2880_R04_GPO, 0x08);
+		msleep(10);
+		break;
+
+	case EM2860_BOARD_KAIOMY_TVNPC_U2:
+		em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x07", 1);
+		em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
+		em28xx_write_regs(dev, 0x0d, "\x42", 1);
+		em28xx_write_regs(dev, 0x08, "\xfd", 1);
+		msleep(10);
+		em28xx_write_regs(dev, 0x08, "\xff", 1);
+		msleep(10);
+		em28xx_write_regs(dev, 0x08, "\x7f", 1);
+		msleep(10);
+		em28xx_write_regs(dev, 0x08, "\x6b", 1);
+
+		break;
+	case EM2860_BOARD_EASYCAP:
+		em28xx_write_regs(dev, 0x08, "\xf8", 1);
+		break;
+
+	case EM2820_BOARD_IODATA_GVMVP_SZ:
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+		msleep(70);
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7);
+		msleep(10);
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+		msleep(70);
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+		msleep(70);
+		break;
+	}
+
+	em28xx_gpio_set(dev, dev->board.tuner_gpio);
+	em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
+
+	/* Unlock device */
+	em28xx_set_mode(dev, EM28XX_SUSPEND);
+}
+
+static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
+{
+	memset(ctl, 0, sizeof(*ctl));
+
+	ctl->fname   = XC2028_DEFAULT_FIRMWARE;
+	ctl->max_len = 64;
+	ctl->mts = em28xx_boards[dev->model].mts_firmware;
+
+	switch (dev->model) {
+	case EM2880_BOARD_EMPIRE_DUAL_TV:
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+	case EM2882_BOARD_TERRATEC_HYBRID_XS:
+		ctl->demod = XC3028_FE_ZARLINK456;
+		break;
+	case EM2880_BOARD_TERRATEC_HYBRID_XS:
+	case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
+	case EM2881_BOARD_PINNACLE_HYBRID_PRO:
+		ctl->demod = XC3028_FE_ZARLINK456;
+		break;
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
+	case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
+		ctl->demod = XC3028_FE_DEFAULT;
+		break;
+	case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
+		ctl->demod = XC3028_FE_DEFAULT;
+		ctl->fname = XC3028L_DEFAULT_FIRMWARE;
+		break;
+	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
+	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
+	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
+		/* FIXME: Better to specify the needed IF */
+		ctl->demod = XC3028_FE_DEFAULT;
+		break;
+	case EM2883_BOARD_KWORLD_HYBRID_330U:
+	case EM2882_BOARD_DIKOM_DK300:
+	case EM2882_BOARD_KWORLD_VS_DVBT:
+		ctl->demod = XC3028_FE_CHINA;
+		ctl->fname = XC2028_DEFAULT_FIRMWARE;
+		break;
+	case EM2882_BOARD_EVGA_INDTUBE:
+		ctl->demod = XC3028_FE_CHINA;
+		ctl->fname = XC3028L_DEFAULT_FIRMWARE;
+		break;
+	default:
+		ctl->demod = XC3028_FE_OREN538;
+	}
+}
+
+static void em28xx_tuner_setup(struct em28xx *dev)
+{
+	struct tuner_setup           tun_setup;
+	struct v4l2_frequency        f;
+
+	if (dev->tuner_type == TUNER_ABSENT)
+		return;
+
+	memset(&tun_setup, 0, sizeof(tun_setup));
+
+	tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+	tun_setup.tuner_callback = em28xx_tuner_callback;
+
+	if (dev->board.radio.type) {
+		tun_setup.type = dev->board.radio.type;
+		tun_setup.addr = dev->board.radio_addr;
+
+		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
+	}
+
+	if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) {
+		tun_setup.type   = dev->tuner_type;
+		tun_setup.addr   = dev->tuner_addr;
+
+		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
+	}
+
+	if (dev->tda9887_conf) {
+		struct v4l2_priv_tun_config tda9887_cfg;
+
+		tda9887_cfg.tuner = TUNER_TDA9887;
+		tda9887_cfg.priv = &dev->tda9887_conf;
+
+		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg);
+	}
+
+	if (dev->tuner_type == TUNER_XC2028) {
+		struct v4l2_priv_tun_config  xc2028_cfg;
+		struct xc2028_ctrl           ctl;
+
+		memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
+		memset(&ctl, 0, sizeof(ctl));
+
+		em28xx_setup_xc3028(dev, &ctl);
+
+		xc2028_cfg.tuner = TUNER_XC2028;
+		xc2028_cfg.priv  = &ctl;
+
+		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg);
+	}
+
+	/* configure tuner */
+	f.tuner = 0;
+	f.type = V4L2_TUNER_ANALOG_TV;
+	f.frequency = 9076;     /* just a magic number */
+	dev->ctl_freq = f.frequency;
+	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+}
+
+static int em28xx_hint_board(struct em28xx *dev)
+{
+	int i;
+
+	/* HINT method: EEPROM
+	 *
+	 * This method works only for boards with eeprom.
+	 * Uses a hash of all eeprom bytes. The hash should be
+	 * unique for a vendor/tuner pair.
+	 * There are a high chance that tuners for different
+	 * video standards produce different hashes.
+	 */
+	for (i = 0; i < ARRAY_SIZE(em28xx_eeprom_hash); i++) {
+		if (dev->hash == em28xx_eeprom_hash[i].hash) {
+			dev->model = em28xx_eeprom_hash[i].model;
+			dev->tuner_type = em28xx_eeprom_hash[i].tuner;
+
+			em28xx_errdev("Your board has no unique USB ID.\n");
+			em28xx_errdev("A hint were successfully done, "
+				      "based on eeprom hash.\n");
+			em28xx_errdev("This method is not 100%% failproof.\n");
+			em28xx_errdev("If the board were missdetected, "
+				      "please email this log to:\n");
+			em28xx_errdev("\tV4L Mailing List "
+				      " <linux-media@vger.kernel.org>\n");
+			em28xx_errdev("Board detected as %s\n",
+				      em28xx_boards[dev->model].name);
+
+			return 0;
+		}
+	}
+
+	/* HINT method: I2C attached devices
+	 *
+	 * This method works for all boards.
+	 * Uses a hash of i2c scanned devices.
+	 * Devices with the same i2c attached chips will
+	 * be considered equal.
+	 * This method is less precise than the eeprom one.
+	 */
+
+	/* user did not request i2c scanning => do it now */
+	if (!dev->i2c_hash)
+		em28xx_do_i2c_scan(dev);
+
+	for (i = 0; i < ARRAY_SIZE(em28xx_i2c_hash); i++) {
+		if (dev->i2c_hash == em28xx_i2c_hash[i].hash) {
+			dev->model = em28xx_i2c_hash[i].model;
+			dev->tuner_type = em28xx_i2c_hash[i].tuner;
+			em28xx_errdev("Your board has no unique USB ID.\n");
+			em28xx_errdev("A hint were successfully done, "
+				      "based on i2c devicelist hash.\n");
+			em28xx_errdev("This method is not 100%% failproof.\n");
+			em28xx_errdev("If the board were missdetected, "
+				      "please email this log to:\n");
+			em28xx_errdev("\tV4L Mailing List "
+				      " <linux-media@vger.kernel.org>\n");
+			em28xx_errdev("Board detected as %s\n",
+				      em28xx_boards[dev->model].name);
+
+			return 0;
+		}
+	}
+
+	em28xx_errdev("Your board has no unique USB ID and thus need a "
+		      "hint to be detected.\n");
+	em28xx_errdev("You may try to use card=<n> insmod option to "
+		      "workaround that.\n");
+	em28xx_errdev("Please send an email with this log to:\n");
+	em28xx_errdev("\tV4L Mailing List <linux-media@vger.kernel.org>\n");
+	em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash);
+	em28xx_errdev("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash);
+
+	em28xx_errdev("Here is a list of valid choices for the card=<n>"
+		      " insmod option:\n");
+	for (i = 0; i < em28xx_bcount; i++) {
+		em28xx_errdev("    card=%d -> %s\n",
+				i, em28xx_boards[i].name);
+	}
+	return -1;
+}
+
+static void em28xx_card_setup(struct em28xx *dev)
+{
+	/*
+	 * If the device can be a webcam, seek for a sensor.
+	 * If sensor is not found, then it isn't a webcam.
+	 */
+	if (dev->board.is_webcam) {
+		if (em28xx_hint_sensor(dev) < 0)
+			dev->board.is_webcam = 0;
+		else
+			dev->progressive = 1;
+	}
+
+	if (!dev->board.is_webcam) {
+		switch (dev->model) {
+		case EM2820_BOARD_UNKNOWN:
+		case EM2800_BOARD_UNKNOWN:
+		/*
+		 * The K-WORLD DVB-T 310U is detected as an MSI Digivox AD.
+		 *
+		 * This occurs because they share identical USB vendor and
+		 * product IDs.
+		 *
+		 * What we do here is look up the EEPROM hash of the K-WORLD
+		 * and if it is found then we decide that we do not have
+		 * a DIGIVOX and reset the device to the K-WORLD instead.
+		 *
+		 * This solution is only valid if they do not share eeprom
+		 * hash identities which has not been determined as yet.
+		 */
+		if (em28xx_hint_board(dev) < 0)
+			em28xx_errdev("Board not discovered\n");
+		else {
+			em28xx_set_model(dev);
+			em28xx_pre_card_setup(dev);
+		}
+		break;
+		default:
+			em28xx_set_model(dev);
+		}
+	}
+
+	em28xx_info("Identified as %s (card=%d)\n",
+		    dev->board.name, dev->model);
+
+	dev->tuner_type = em28xx_boards[dev->model].tuner_type;
+	if (em28xx_boards[dev->model].tuner_addr)
+		dev->tuner_addr = em28xx_boards[dev->model].tuner_addr;
+
+	if (em28xx_boards[dev->model].tda9887_conf)
+		dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
+
+	/* request some modules */
+	switch (dev->model) {
+	case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
+	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
+	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
+	{
+		struct tveeprom tv;
+#if defined(CONFIG_MODULES) && defined(MODULE)
+		request_module("tveeprom");
+#endif
+		/* Call first TVeeprom */
+
+		dev->i2c_client.addr = 0xa0 >> 1;
+		tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
+
+		dev->tuner_type = tv.tuner_type;
+
+		if (tv.audio_processor == V4L2_IDENT_MSPX4XX) {
+			dev->i2s_speed = 2048000;
+			dev->board.has_msp34xx = 1;
+		}
+		break;
+	}
+	case EM2882_BOARD_KWORLD_ATSC_315U:
+		em28xx_write_reg(dev, 0x0d, 0x42);
+		msleep(10);
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+		msleep(10);
+		break;
+	case EM2820_BOARD_KWORLD_PVRTV2800RF:
+		/* GPIO enables sound on KWORLD PVR TV 2800RF */
+		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf9);
+		break;
+	case EM2820_BOARD_UNKNOWN:
+	case EM2800_BOARD_UNKNOWN:
+		/*
+		 * The K-WORLD DVB-T 310U is detected as an MSI Digivox AD.
+		 *
+		 * This occurs because they share identical USB vendor and
+		 * product IDs.
+		 *
+		 * What we do here is look up the EEPROM hash of the K-WORLD
+		 * and if it is found then we decide that we do not have
+		 * a DIGIVOX and reset the device to the K-WORLD instead.
+		 *
+		 * This solution is only valid if they do not share eeprom
+		 * hash identities which has not been determined as yet.
+		 */
+	case EM2880_BOARD_MSI_DIGIVOX_AD:
+		if (!em28xx_hint_board(dev))
+			em28xx_set_model(dev);
+
+		/* In cases where we had to use a board hint, the call to
+		   em28xx_set_mode() in em28xx_pre_card_setup() was a no-op,
+		   so make the call now so the analog GPIOs are set properly
+		   before probing the i2c bus. */
+		em28xx_gpio_set(dev, dev->board.tuner_gpio);
+		em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
+		break;
+
+/*
+		 * The Dikom DK300 is detected as an Kworld VS-DVB-T 323UR.
+		 *
+		 * This occurs because they share identical USB vendor and
+		 * product IDs.
+		 *
+		 * What we do here is look up the EEPROM hash of the Dikom
+		 * and if it is found then we decide that we do not have
+		 * a Kworld and reset the device to the Dikom instead.
+		 *
+		 * This solution is only valid if they do not share eeprom
+		 * hash identities which has not been determined as yet.
+		 */
+	case EM2882_BOARD_KWORLD_VS_DVBT:
+		if (!em28xx_hint_board(dev))
+			em28xx_set_model(dev);
+
+		/* In cases where we had to use a board hint, the call to
+		   em28xx_set_mode() in em28xx_pre_card_setup() was a no-op,
+		   so make the call now so the analog GPIOs are set properly
+		   before probing the i2c bus. */
+		em28xx_gpio_set(dev, dev->board.tuner_gpio);
+		em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
+		break;
+	}
+
+	if (dev->board.valid == EM28XX_BOARD_NOT_VALIDATED) {
+		em28xx_errdev("\n\n");
+		em28xx_errdev("The support for this board weren't "
+			      "valid yet.\n");
+		em28xx_errdev("Please send a report of having this working\n");
+		em28xx_errdev("not to V4L mailing list (and/or to other "
+				"addresses)\n\n");
+	}
+
+	/* Allow override tuner type by a module parameter */
+	if (tuner >= 0)
+		dev->tuner_type = tuner;
+
+	/* request some modules */
+	if (dev->board.has_msp34xx)
+		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+			"msp3400", 0, msp3400_addrs);
+
+	if (dev->board.decoder == EM28XX_SAA711X)
+		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+			"saa7115_auto", 0, saa711x_addrs);
+
+	if (dev->board.decoder == EM28XX_TVP5150)
+		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+			"tvp5150", 0, tvp5150_addrs);
+
+	if (dev->em28xx_sensor == EM28XX_MT9V011) {
+		struct mt9v011_platform_data pdata;
+		struct i2c_board_info mt9v011_info = {
+			.type = "mt9v011",
+			.addr = 0xba >> 1,
+			.platform_data = &pdata,
+		};
+
+		pdata.xtal = dev->sensor_xtal;
+		v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap,
+				&mt9v011_info, NULL);
+	}
+
+
+	if (dev->board.adecoder == EM28XX_TVAUDIO)
+		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+			"tvaudio", dev->board.tvaudio_addr, NULL);
+
+	if (dev->board.tuner_type != TUNER_ABSENT) {
+		int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
+
+		if (dev->board.radio.type)
+			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+				"tuner", dev->board.radio_addr, NULL);
+
+		if (has_demod)
+			v4l2_i2c_new_subdev(&dev->v4l2_dev,
+				&dev->i2c_adap, "tuner",
+				0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+		if (dev->tuner_addr == 0) {
+			enum v4l2_i2c_tuner_type type =
+				has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
+			struct v4l2_subdev *sd;
+
+			sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+				&dev->i2c_adap, "tuner",
+				0, v4l2_i2c_tuner_addrs(type));
+
+			if (sd)
+				dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
+		} else {
+			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+				"tuner", dev->tuner_addr, NULL);
+		}
+	}
+
+	em28xx_tuner_setup(dev);
+}
+
+
+#if defined(CONFIG_MODULES) && defined(MODULE)
+static void request_module_async(struct work_struct *work)
+{
+	struct em28xx *dev = container_of(work,
+			     struct em28xx, request_module_wk);
+
+	if (dev->has_audio_class)
+		request_module("snd-usb-audio");
+	else if (dev->has_alsa_audio)
+		request_module("em28xx-alsa");
+
+	if (dev->board.has_dvb)
+		request_module("em28xx-dvb");
+	if (dev->board.ir_codes && !disable_ir)
+		request_module("em28xx-rc");
+}
+
+static void request_modules(struct em28xx *dev)
+{
+	INIT_WORK(&dev->request_module_wk, request_module_async);
+	schedule_work(&dev->request_module_wk);
+}
+
+static void flush_request_modules(struct em28xx *dev)
+{
+	flush_work_sync(&dev->request_module_wk);
+}
+#else
+#define request_modules(dev)
+#define flush_request_modules(dev)
+#endif /* CONFIG_MODULES */
+
+/*
+ * em28xx_release_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconnected or at module unload
+*/
+void em28xx_release_resources(struct em28xx *dev)
+{
+	/*FIXME: I2C IR should be disconnected */
+
+	em28xx_release_analog_resources(dev);
+
+	em28xx_i2c_unregister(dev);
+
+	v4l2_device_unregister(&dev->v4l2_dev);
+
+	usb_put_dev(dev->udev);
+
+	/* Mark device as unused */
+	clear_bit(dev->devno, &em28xx_devused);
+};
+
+/*
+ * em28xx_init_dev()
+ * allocates and inits the device structs, registers i2c bus and v4l device
+ */
+static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
+			   struct usb_interface *interface,
+			   int minor)
+{
+	int retval;
+
+	dev->udev = udev;
+	mutex_init(&dev->ctrl_urb_lock);
+	spin_lock_init(&dev->slock);
+
+	dev->em28xx_write_regs = em28xx_write_regs;
+	dev->em28xx_read_reg = em28xx_read_reg;
+	dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
+	dev->em28xx_write_regs_req = em28xx_write_regs_req;
+	dev->em28xx_read_reg_req = em28xx_read_reg_req;
+	dev->board.is_em2800 = em28xx_boards[dev->model].is_em2800;
+
+	em28xx_set_model(dev);
+
+	/* Set the default GPO/GPIO for legacy devices */
+	dev->reg_gpo_num = EM2880_R04_GPO;
+	dev->reg_gpio_num = EM28XX_R08_GPIO;
+
+	dev->wait_after_write = 5;
+
+	/* Based on the Chip ID, set the device configuration */
+	retval = em28xx_read_reg(dev, EM28XX_R0A_CHIPID);
+	if (retval > 0) {
+		dev->chip_id = retval;
+
+		switch (dev->chip_id) {
+		case CHIP_ID_EM2800:
+			em28xx_info("chip ID is em2800\n");
+			break;
+		case CHIP_ID_EM2710:
+			em28xx_info("chip ID is em2710\n");
+			break;
+		case CHIP_ID_EM2750:
+			em28xx_info("chip ID is em2750\n");
+			break;
+		case CHIP_ID_EM2820:
+			em28xx_info("chip ID is em2820 (or em2710)\n");
+			break;
+		case CHIP_ID_EM2840:
+			em28xx_info("chip ID is em2840\n");
+			break;
+		case CHIP_ID_EM2860:
+			em28xx_info("chip ID is em2860\n");
+			break;
+		case CHIP_ID_EM2870:
+			em28xx_info("chip ID is em2870\n");
+			dev->wait_after_write = 0;
+			break;
+		case CHIP_ID_EM2874:
+			em28xx_info("chip ID is em2874\n");
+			dev->reg_gpio_num = EM2874_R80_GPIO;
+			dev->wait_after_write = 0;
+			break;
+		case CHIP_ID_EM28174:
+			em28xx_info("chip ID is em28174\n");
+			dev->reg_gpio_num = EM2874_R80_GPIO;
+			dev->wait_after_write = 0;
+			break;
+		case CHIP_ID_EM2883:
+			em28xx_info("chip ID is em2882/em2883\n");
+			dev->wait_after_write = 0;
+			break;
+		case CHIP_ID_EM2884:
+			em28xx_info("chip ID is em2884\n");
+			dev->reg_gpio_num = EM2874_R80_GPIO;
+			dev->wait_after_write = 0;
+			break;
+		default:
+			em28xx_info("em28xx chip ID = %d\n", dev->chip_id);
+		}
+	}
+
+	if (dev->is_audio_only) {
+		retval = em28xx_audio_setup(dev);
+		if (retval)
+			return -ENODEV;
+		em28xx_init_extension(dev);
+
+		return 0;
+	}
+
+	/* Prepopulate cached GPO register content */
+	retval = em28xx_read_reg(dev, dev->reg_gpo_num);
+	if (retval >= 0)
+		dev->reg_gpo = retval;
+
+	em28xx_pre_card_setup(dev);
+
+	if (!dev->board.is_em2800) {
+		/* Resets I2C speed */
+		retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
+		if (retval < 0) {
+			em28xx_errdev("%s: em28xx_write_reg failed!"
+				      " retval [%d]\n",
+				      __func__, retval);
+			return retval;
+		}
+	}
+
+	retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
+	if (retval < 0) {
+		em28xx_errdev("Call to v4l2_device_register() failed!\n");
+		return retval;
+	}
+
+	/* register i2c bus */
+	retval = em28xx_i2c_register(dev);
+	if (retval < 0) {
+		em28xx_errdev("%s: em28xx_i2c_register - error [%d]!\n",
+			__func__, retval);
+		goto unregister_dev;
+	}
+
+	/*
+	 * Default format, used for tvp5150 or saa711x output formats
+	 */
+	dev->vinmode = 0x10;
+	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
+		       EM28XX_VINCTRL_CCIR656_ENABLE;
+
+	/* Do board specific init and eeprom reading */
+	em28xx_card_setup(dev);
+
+	/* Configure audio */
+	retval = em28xx_audio_setup(dev);
+	if (retval < 0) {
+		em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
+			__func__, retval);
+		goto fail;
+	}
+
+	/* wake i2c devices */
+	em28xx_wake_i2c(dev);
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&dev->vidq.active);
+	INIT_LIST_HEAD(&dev->vbiq.active);
+
+	if (dev->board.has_msp34xx) {
+		/* Send a reset to other chips via gpio */
+		retval = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7);
+		if (retval < 0) {
+			em28xx_errdev("%s: em28xx_write_reg - "
+				      "msp34xx(1) failed! error [%d]\n",
+				      __func__, retval);
+			goto fail;
+		}
+		msleep(3);
+
+		retval = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+		if (retval < 0) {
+			em28xx_errdev("%s: em28xx_write_reg - "
+				      "msp34xx(2) failed! error [%d]\n",
+				      __func__, retval);
+			goto fail;
+		}
+		msleep(3);
+	}
+
+	retval = em28xx_register_analog_devices(dev);
+	if (retval < 0) {
+		goto fail;
+	}
+
+	/* Save some power by putting tuner to sleep */
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+
+	return 0;
+
+fail:
+	em28xx_i2c_unregister(dev);
+
+unregister_dev:
+	v4l2_device_unregister(&dev->v4l2_dev);
+
+	return retval;
+}
+
+/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+
+/*
+ * em28xx_usb_probe()
+ * checks for supported devices
+ */
+static int em28xx_usb_probe(struct usb_interface *interface,
+			    const struct usb_device_id *id)
+{
+	struct usb_device *udev;
+	struct em28xx *dev = NULL;
+	int retval;
+	bool has_audio = false, has_video = false, has_dvb = false;
+	int i, nr;
+	const int ifnum = interface->altsetting[0].desc.bInterfaceNumber;
+	char *speed;
+
+	udev = usb_get_dev(interface_to_usbdev(interface));
+
+	/* Check to see next free device and mark as used */
+	do {
+		nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
+		if (nr >= EM28XX_MAXBOARDS) {
+			/* No free device slots */
+			printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
+					EM28XX_MAXBOARDS);
+			retval = -ENOMEM;
+			goto err_no_slot;
+		}
+	} while (test_and_set_bit(nr, &em28xx_devused));
+
+	/* Don't register audio interfaces */
+	if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
+		em28xx_err(DRIVER_NAME " audio device (%04x:%04x): "
+			"interface %i, class %i\n",
+			le16_to_cpu(udev->descriptor.idVendor),
+			le16_to_cpu(udev->descriptor.idProduct),
+			ifnum,
+			interface->altsetting[0].desc.bInterfaceClass);
+
+		retval = -ENODEV;
+		goto err;
+	}
+
+	/* allocate memory for our device state and initialize it */
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL) {
+		em28xx_err(DRIVER_NAME ": out of memory!\n");
+		retval = -ENOMEM;
+		goto err;
+	}
+
+	/* compute alternate max packet sizes */
+	dev->alt_max_pkt_size = kmalloc(sizeof(dev->alt_max_pkt_size[0]) *
+					interface->num_altsetting, GFP_KERNEL);
+	if (dev->alt_max_pkt_size == NULL) {
+		em28xx_errdev("out of memory!\n");
+		kfree(dev);
+		retval = -ENOMEM;
+		goto err;
+	}
+
+	/* Get endpoints */
+	for (i = 0; i < interface->num_altsetting; i++) {
+		int ep;
+
+		for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
+			const struct usb_endpoint_descriptor *e;
+			int sizedescr, size;
+
+			e = &interface->altsetting[i].endpoint[ep].desc;
+
+			sizedescr = le16_to_cpu(e->wMaxPacketSize);
+			size = sizedescr & 0x7ff;
+
+			if (udev->speed == USB_SPEED_HIGH)
+				size = size * hb_mult(sizedescr);
+
+			if (usb_endpoint_xfer_isoc(e) &&
+			    usb_endpoint_dir_in(e)) {
+				switch (e->bEndpointAddress) {
+				case EM28XX_EP_AUDIO:
+					has_audio = true;
+					break;
+				case EM28XX_EP_ANALOG:
+					has_video = true;
+					dev->alt_max_pkt_size[i] = size;
+					break;
+				case EM28XX_EP_DIGITAL:
+					has_dvb = true;
+					if (size > dev->dvb_max_pkt_size) {
+						dev->dvb_max_pkt_size = size;
+						dev->dvb_alt = i;
+					}
+					break;
+				}
+			}
+		}
+	}
+
+	if (!(has_audio || has_video || has_dvb)) {
+		retval = -ENODEV;
+		goto err_free;
+	}
+
+	switch (udev->speed) {
+	case USB_SPEED_LOW:
+		speed = "1.5";
+		break;
+	case USB_SPEED_UNKNOWN:
+	case USB_SPEED_FULL:
+		speed = "12";
+		break;
+	case USB_SPEED_HIGH:
+		speed = "480";
+		break;
+	default:
+		speed = "unknown";
+	}
+
+	printk(KERN_INFO DRIVER_NAME
+		": New device %s %s @ %s Mbps "
+		"(%04x:%04x, interface %d, class %d)\n",
+		udev->manufacturer ? udev->manufacturer : "",
+		udev->product ? udev->product : "",
+		speed,
+		le16_to_cpu(udev->descriptor.idVendor),
+		le16_to_cpu(udev->descriptor.idProduct),
+		ifnum,
+		interface->altsetting->desc.bInterfaceNumber);
+
+	if (has_audio)
+		printk(KERN_INFO DRIVER_NAME
+		       ": Audio Vendor Class interface %i found\n",
+		       ifnum);
+	if (has_video)
+		printk(KERN_INFO DRIVER_NAME
+		       ": Video interface %i found\n",
+		       ifnum);
+	if (has_dvb)
+		printk(KERN_INFO DRIVER_NAME
+		       ": DVB interface %i found\n",
+		       ifnum);
+
+	/*
+	 * Make sure we have 480 Mbps of bandwidth, otherwise things like
+	 * video stream wouldn't likely work, since 12 Mbps is generally
+	 * not enough even for most Digital TV streams.
+	 */
+	if (udev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
+		printk(DRIVER_NAME ": Device initialization failed.\n");
+		printk(DRIVER_NAME ": Device must be connected to a high-speed"
+		       " USB 2.0 port.\n");
+		retval = -ENODEV;
+		goto err_free;
+	}
+
+	snprintf(dev->name, sizeof(dev->name), "em28xx #%d", nr);
+	dev->devno = nr;
+	dev->model = id->driver_info;
+	dev->alt   = -1;
+	dev->is_audio_only = has_audio && !(has_video || has_dvb);
+	dev->has_alsa_audio = has_audio;
+	dev->audio_ifnum = ifnum;
+
+	/* Checks if audio is provided by some interface */
+	for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
+		struct usb_interface *uif = udev->config->interface[i];
+		if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
+			dev->has_audio_class = 1;
+			break;
+		}
+	}
+
+	dev->num_alt = interface->num_altsetting;
+
+	if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
+		dev->model = card[nr];
+
+	/* save our data pointer in this interface device */
+	usb_set_intfdata(interface, dev);
+
+	/* allocate device struct */
+	mutex_init(&dev->lock);
+	mutex_lock(&dev->lock);
+	retval = em28xx_init_dev(dev, udev, interface, nr);
+	if (retval) {
+		goto unlock_and_free;
+	}
+
+	if (has_dvb) {
+		/* pre-allocate DVB isoc transfer buffers */
+		retval = em28xx_alloc_isoc(dev, EM28XX_DIGITAL_MODE,
+					   EM28XX_DVB_MAX_PACKETS,
+					   EM28XX_DVB_NUM_BUFS,
+					   dev->dvb_max_pkt_size);
+		if (retval) {
+			goto unlock_and_free;
+		}
+	}
+
+	request_modules(dev);
+
+	/* Should be the last thing to do, to avoid newer udev's to
+	   open the device before fully initializing it
+	 */
+	mutex_unlock(&dev->lock);
+
+	/*
+	 * These extensions can be modules. If the modules are already
+	 * loaded then we can initialise the device now, otherwise we
+	 * will initialise it when the modules load instead.
+	 */
+	em28xx_init_extension(dev);
+
+	return 0;
+
+unlock_and_free:
+	mutex_unlock(&dev->lock);
+
+err_free:
+	kfree(dev->alt_max_pkt_size);
+	kfree(dev);
+
+err:
+	clear_bit(nr, &em28xx_devused);
+
+err_no_slot:
+	usb_put_dev(udev);
+	return retval;
+}
+
+/*
+ * em28xx_usb_disconnect()
+ * called when the device gets disconnected
+ * video device will be unregistered on v4l2_close in case it is still open
+ */
+static void em28xx_usb_disconnect(struct usb_interface *interface)
+{
+	struct em28xx *dev;
+
+	dev = usb_get_intfdata(interface);
+	usb_set_intfdata(interface, NULL);
+
+	if (!dev)
+		return;
+
+	if (dev->is_audio_only) {
+		mutex_lock(&dev->lock);
+		em28xx_close_extension(dev);
+		mutex_unlock(&dev->lock);
+		return;
+	}
+
+	em28xx_info("disconnecting %s\n", dev->vdev->name);
+
+	flush_request_modules(dev);
+
+	/* wait until all current v4l2 io is finished then deallocate
+	   resources */
+	mutex_lock(&dev->lock);
+
+	v4l2_device_disconnect(&dev->v4l2_dev);
+
+	if (dev->users) {
+		em28xx_warn
+		    ("device %s is open! Deregistration and memory "
+		     "deallocation are deferred on close.\n",
+		     video_device_node_name(dev->vdev));
+
+		dev->state |= DEV_MISCONFIGURED;
+		em28xx_uninit_isoc(dev, dev->mode);
+		dev->state |= DEV_DISCONNECTED;
+	} else {
+		dev->state |= DEV_DISCONNECTED;
+		em28xx_release_resources(dev);
+	}
+
+	/* free DVB isoc buffers */
+	em28xx_uninit_isoc(dev, EM28XX_DIGITAL_MODE);
+
+	mutex_unlock(&dev->lock);
+
+	em28xx_close_extension(dev);
+
+	if (!dev->users) {
+		kfree(dev->alt_max_pkt_size);
+		kfree(dev);
+	}
+}
+
+static struct usb_driver em28xx_usb_driver = {
+	.name = "em28xx",
+	.probe = em28xx_usb_probe,
+	.disconnect = em28xx_usb_disconnect,
+	.id_table = em28xx_id_table,
+};
+
+module_usb_driver(em28xx_usb_driver);
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
new file mode 100644
index 0000000..bed07a6
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -0,0 +1,1260 @@
+/*
+   em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+   Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+		      Markus Rechberger <mrechberger@gmail.com>
+		      Mauro Carvalho Chehab <mchehab@infradead.org>
+		      Sascha Sommer <saschasommer@freenet.de>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/vmalloc.h>
+#include <sound/ac97_codec.h>
+#include <media/v4l2-common.h>
+
+#include "em28xx.h"
+
+/* #define ENABLE_DEBUG_ISOC_FRAMES */
+
+static unsigned int core_debug;
+module_param(core_debug, int, 0644);
+MODULE_PARM_DESC(core_debug, "enable debug messages [core]");
+
+#define em28xx_coredbg(fmt, arg...) do {\
+	if (core_debug) \
+		printk(KERN_INFO "%s %s :"fmt, \
+			 dev->name, __func__ , ##arg); } while (0)
+
+static unsigned int reg_debug;
+module_param(reg_debug, int, 0644);
+MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
+
+#define em28xx_regdbg(fmt, arg...) do {\
+	if (reg_debug) \
+		printk(KERN_INFO "%s %s :"fmt, \
+			 dev->name, __func__ , ##arg); } while (0)
+
+static int alt;
+module_param(alt, int, 0644);
+MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
+
+static unsigned int disable_vbi;
+module_param(disable_vbi, int, 0644);
+MODULE_PARM_DESC(disable_vbi, "disable vbi support");
+
+/* FIXME */
+#define em28xx_isocdbg(fmt, arg...) do {\
+	if (core_debug) \
+		printk(KERN_INFO "%s %s :"fmt, \
+			 dev->name, __func__ , ##arg); } while (0)
+
+/*
+ * em28xx_read_reg_req()
+ * reads data from the usb device specifying bRequest
+ */
+int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
+				   char *buf, int len)
+{
+	int ret;
+	int pipe = usb_rcvctrlpipe(dev->udev, 0);
+
+	if (dev->state & DEV_DISCONNECTED)
+		return -ENODEV;
+
+	if (len > URB_MAX_CTRL_SIZE)
+		return -EINVAL;
+
+	if (reg_debug) {
+		printk(KERN_DEBUG "(pipe 0x%08x): "
+			"IN:  %02x %02x %02x %02x %02x %02x %02x %02x ",
+			pipe,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			req, 0, 0,
+			reg & 0xff, reg >> 8,
+			len & 0xff, len >> 8);
+	}
+
+	mutex_lock(&dev->ctrl_urb_lock);
+	ret = usb_control_msg(dev->udev, pipe, req,
+			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      0x0000, reg, dev->urb_buf, len, HZ);
+	if (ret < 0) {
+		if (reg_debug)
+			printk(" failed!\n");
+		mutex_unlock(&dev->ctrl_urb_lock);
+		return ret;
+	}
+
+	if (len)
+		memcpy(buf, dev->urb_buf, len);
+
+	mutex_unlock(&dev->ctrl_urb_lock);
+
+	if (reg_debug) {
+		int byte;
+
+		printk("<<<");
+		for (byte = 0; byte < len; byte++)
+			printk(" %02x", (unsigned char)buf[byte]);
+		printk("\n");
+	}
+
+	return ret;
+}
+
+/*
+ * em28xx_read_reg_req()
+ * reads data from the usb device specifying bRequest
+ */
+int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg)
+{
+	int ret;
+	u8 val;
+
+	ret = em28xx_read_reg_req_len(dev, req, reg, &val, 1);
+	if (ret < 0)
+		return ret;
+
+	return val;
+}
+
+int em28xx_read_reg(struct em28xx *dev, u16 reg)
+{
+	return em28xx_read_reg_req(dev, USB_REQ_GET_STATUS, reg);
+}
+EXPORT_SYMBOL_GPL(em28xx_read_reg);
+
+/*
+ * em28xx_write_regs_req()
+ * sends data to the usb device, specifying bRequest
+ */
+int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
+				 int len)
+{
+	int ret;
+	int pipe = usb_sndctrlpipe(dev->udev, 0);
+
+	if (dev->state & DEV_DISCONNECTED)
+		return -ENODEV;
+
+	if ((len < 1) || (len > URB_MAX_CTRL_SIZE))
+		return -EINVAL;
+
+	if (reg_debug) {
+		int byte;
+
+		printk(KERN_DEBUG "(pipe 0x%08x): "
+			"OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>",
+			pipe,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			req, 0, 0,
+			reg & 0xff, reg >> 8,
+			len & 0xff, len >> 8);
+
+		for (byte = 0; byte < len; byte++)
+			printk(" %02x", (unsigned char)buf[byte]);
+		printk("\n");
+	}
+
+	mutex_lock(&dev->ctrl_urb_lock);
+	memcpy(dev->urb_buf, buf, len);
+	ret = usb_control_msg(dev->udev, pipe, req,
+			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      0x0000, reg, dev->urb_buf, len, HZ);
+	mutex_unlock(&dev->ctrl_urb_lock);
+
+	if (dev->wait_after_write)
+		msleep(dev->wait_after_write);
+
+	return ret;
+}
+
+int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
+{
+	int rc;
+
+	rc = em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
+
+	/* Stores GPO/GPIO values at the cache, if changed
+	   Only write values should be stored, since input on a GPIO
+	   register will return the input bits.
+	   Not sure what happens on reading GPO register.
+	 */
+	if (rc >= 0) {
+		if (reg == dev->reg_gpo_num)
+			dev->reg_gpo = buf[0];
+		else if (reg == dev->reg_gpio_num)
+			dev->reg_gpio = buf[0];
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(em28xx_write_regs);
+
+/* Write a single register */
+int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val)
+{
+	return em28xx_write_regs(dev, reg, &val, 1);
+}
+EXPORT_SYMBOL_GPL(em28xx_write_reg);
+
+/*
+ * em28xx_write_reg_bits()
+ * sets only some bits (specified by bitmask) of a register, by first reading
+ * the actual value
+ */
+int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
+				 u8 bitmask)
+{
+	int oldval;
+	u8 newval;
+
+	/* Uses cache for gpo/gpio registers */
+	if (reg == dev->reg_gpo_num)
+		oldval = dev->reg_gpo;
+	else if (reg == dev->reg_gpio_num)
+		oldval = dev->reg_gpio;
+	else
+		oldval = em28xx_read_reg(dev, reg);
+
+	if (oldval < 0)
+		return oldval;
+
+	newval = (((u8) oldval) & ~bitmask) | (val & bitmask);
+
+	return em28xx_write_regs(dev, reg, &newval, 1);
+}
+EXPORT_SYMBOL_GPL(em28xx_write_reg_bits);
+
+/*
+ * em28xx_is_ac97_ready()
+ * Checks if ac97 is ready
+ */
+static int em28xx_is_ac97_ready(struct em28xx *dev)
+{
+	int ret, i;
+
+	/* Wait up to 50 ms for AC97 command to complete */
+	for (i = 0; i < 10; i++, msleep(5)) {
+		ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
+		if (ret < 0)
+			return ret;
+
+		if (!(ret & 0x01))
+			return 0;
+	}
+
+	em28xx_warn("AC97 command still being executed: not handled properly!\n");
+	return -EBUSY;
+}
+
+/*
+ * em28xx_read_ac97()
+ * write a 16 bit value to the specified AC97 address (LSB first!)
+ */
+int em28xx_read_ac97(struct em28xx *dev, u8 reg)
+{
+	int ret;
+	u8 addr = (reg & 0x7f) | 0x80;
+	u16 val;
+
+	ret = em28xx_is_ac97_ready(dev);
+	if (ret < 0)
+		return ret;
+
+	ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1);
+	if (ret < 0)
+		return ret;
+
+	ret = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R40_AC97LSB,
+					   (u8 *)&val, sizeof(val));
+
+	if (ret < 0)
+		return ret;
+	return le16_to_cpu(val);
+}
+EXPORT_SYMBOL_GPL(em28xx_read_ac97);
+
+/*
+ * em28xx_write_ac97()
+ * write a 16 bit value to the specified AC97 address (LSB first!)
+ */
+int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val)
+{
+	int ret;
+	u8 addr = reg & 0x7f;
+	__le16 value;
+
+	value = cpu_to_le16(val);
+
+	ret = em28xx_is_ac97_ready(dev);
+	if (ret < 0)
+		return ret;
+
+	ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, (u8 *) &value, 2);
+	if (ret < 0)
+		return ret;
+
+	ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(em28xx_write_ac97);
+
+struct em28xx_vol_itable {
+	enum em28xx_amux mux;
+	u8		 reg;
+};
+
+static struct em28xx_vol_itable inputs[] = {
+	{ EM28XX_AMUX_VIDEO,	AC97_VIDEO	},
+	{ EM28XX_AMUX_LINE_IN,	AC97_LINE	},
+	{ EM28XX_AMUX_PHONE,	AC97_PHONE	},
+	{ EM28XX_AMUX_MIC,	AC97_MIC	},
+	{ EM28XX_AMUX_CD,	AC97_CD		},
+	{ EM28XX_AMUX_AUX,	AC97_AUX	},
+	{ EM28XX_AMUX_PCM_OUT,	AC97_PCM	},
+};
+
+static int set_ac97_input(struct em28xx *dev)
+{
+	int ret, i;
+	enum em28xx_amux amux = dev->ctl_ainput;
+
+	/* EM28XX_AMUX_VIDEO2 is a special case used to indicate that
+	   em28xx should point to LINE IN, while AC97 should use VIDEO
+	 */
+	if (amux == EM28XX_AMUX_VIDEO2)
+		amux = EM28XX_AMUX_VIDEO;
+
+	/* Mute all entres but the one that were selected */
+	for (i = 0; i < ARRAY_SIZE(inputs); i++) {
+		if (amux == inputs[i].mux)
+			ret = em28xx_write_ac97(dev, inputs[i].reg, 0x0808);
+		else
+			ret = em28xx_write_ac97(dev, inputs[i].reg, 0x8000);
+
+		if (ret < 0)
+			em28xx_warn("couldn't setup AC97 register %d\n",
+				     inputs[i].reg);
+	}
+	return 0;
+}
+
+static int em28xx_set_audio_source(struct em28xx *dev)
+{
+	int ret;
+	u8 input;
+
+	if (dev->board.is_em2800) {
+		if (dev->ctl_ainput == EM28XX_AMUX_VIDEO)
+			input = EM2800_AUDIO_SRC_TUNER;
+		else
+			input = EM2800_AUDIO_SRC_LINE;
+
+		ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (dev->board.has_msp34xx)
+		input = EM28XX_AUDIO_SRC_TUNER;
+	else {
+		switch (dev->ctl_ainput) {
+		case EM28XX_AMUX_VIDEO:
+			input = EM28XX_AUDIO_SRC_TUNER;
+			break;
+		default:
+			input = EM28XX_AUDIO_SRC_LINE;
+			break;
+		}
+	}
+
+	if (dev->board.mute_gpio && dev->mute)
+		em28xx_gpio_set(dev, dev->board.mute_gpio);
+	else
+		em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio);
+
+	ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0);
+	if (ret < 0)
+		return ret;
+	msleep(5);
+
+	switch (dev->audio_mode.ac97) {
+	case EM28XX_NO_AC97:
+		break;
+	default:
+		ret = set_ac97_input(dev);
+	}
+
+	return ret;
+}
+
+struct em28xx_vol_otable {
+	enum em28xx_aout mux;
+	u8		 reg;
+};
+
+static const struct em28xx_vol_otable outputs[] = {
+	{ EM28XX_AOUT_MASTER, AC97_MASTER		},
+	{ EM28XX_AOUT_LINE,   AC97_HEADPHONE		},
+	{ EM28XX_AOUT_MONO,   AC97_MASTER_MONO		},
+	{ EM28XX_AOUT_LFE,    AC97_CENTER_LFE_MASTER	},
+	{ EM28XX_AOUT_SURR,   AC97_SURROUND_MASTER	},
+};
+
+int em28xx_audio_analog_set(struct em28xx *dev)
+{
+	int ret, i;
+	u8 xclk;
+
+	if (!dev->audio_mode.has_audio)
+		return 0;
+
+	/* It is assumed that all devices use master volume for output.
+	   It would be possible to use also line output.
+	 */
+	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+		/* Mute all outputs */
+		for (i = 0; i < ARRAY_SIZE(outputs); i++) {
+			ret = em28xx_write_ac97(dev, outputs[i].reg, 0x8000);
+			if (ret < 0)
+				em28xx_warn("couldn't setup AC97 register %d\n",
+				     outputs[i].reg);
+		}
+	}
+
+	xclk = dev->board.xclk & 0x7f;
+	if (!dev->mute)
+		xclk |= EM28XX_XCLK_AUDIO_UNMUTE;
+
+	ret = em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk);
+	if (ret < 0)
+		return ret;
+	msleep(10);
+
+	/* Selects the proper audio input */
+	ret = em28xx_set_audio_source(dev);
+
+	/* Sets volume */
+	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+		int vol;
+
+		em28xx_write_ac97(dev, AC97_POWERDOWN, 0x4200);
+		em28xx_write_ac97(dev, AC97_EXTENDED_STATUS, 0x0031);
+		em28xx_write_ac97(dev, AC97_PCM_LR_ADC_RATE, 0xbb80);
+
+		/* LSB: left channel - both channels with the same level */
+		vol = (0x1f - dev->volume) | ((0x1f - dev->volume) << 8);
+
+		/* Mute device, if needed */
+		if (dev->mute)
+			vol |= 0x8000;
+
+		/* Sets volume */
+		for (i = 0; i < ARRAY_SIZE(outputs); i++) {
+			if (dev->ctl_aoutput & outputs[i].mux)
+				ret = em28xx_write_ac97(dev, outputs[i].reg,
+							vol);
+			if (ret < 0)
+				em28xx_warn("couldn't setup AC97 register %d\n",
+				     outputs[i].reg);
+		}
+
+		if (dev->ctl_aoutput & EM28XX_AOUT_PCM_IN) {
+			int sel = ac97_return_record_select(dev->ctl_aoutput);
+
+			/* Use the same input for both left and right
+			   channels */
+			sel |= (sel << 8);
+
+			em28xx_write_ac97(dev, AC97_REC_SEL, sel);
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);
+
+int em28xx_audio_setup(struct em28xx *dev)
+{
+	int vid1, vid2, feat, cfg;
+	u32 vid;
+
+	if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874
+		|| dev->chip_id == CHIP_ID_EM28174) {
+		/* Digital only device - don't load any alsa module */
+		dev->audio_mode.has_audio = false;
+		dev->has_audio_class = false;
+		dev->has_alsa_audio = false;
+		return 0;
+	}
+
+	dev->audio_mode.has_audio = true;
+
+	/* See how this device is configured */
+	cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
+	em28xx_info("Config register raw data: 0x%02x\n", cfg);
+	if (cfg < 0) {
+		/* Register read error?  */
+		cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */
+	} else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) {
+		/* The device doesn't have vendor audio at all */
+		dev->has_alsa_audio = false;
+		dev->audio_mode.has_audio = false;
+		return 0;
+	} else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+		   EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
+		em28xx_info("I2S Audio (3 sample rates)\n");
+		dev->audio_mode.i2s_3rates = 1;
+	} else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+		   EM28XX_CHIPCFG_I2S_5_SAMPRATES) {
+		em28xx_info("I2S Audio (5 sample rates)\n");
+		dev->audio_mode.i2s_5rates = 1;
+	}
+
+	if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) {
+		/* Skip the code that does AC97 vendor detection */
+		dev->audio_mode.ac97 = EM28XX_NO_AC97;
+		goto init_audio;
+	}
+
+	dev->audio_mode.ac97 = EM28XX_AC97_OTHER;
+
+	vid1 = em28xx_read_ac97(dev, AC97_VENDOR_ID1);
+	if (vid1 < 0) {
+		/*
+		 * Device likely doesn't support AC97
+		 * Note: (some) em2800 devices without eeprom reports 0x91 on
+		 *	 CHIPCFG register, even not having an AC97 chip
+		 */
+		em28xx_warn("AC97 chip type couldn't be determined\n");
+		dev->audio_mode.ac97 = EM28XX_NO_AC97;
+		dev->has_alsa_audio = false;
+		dev->audio_mode.has_audio = false;
+		goto init_audio;
+	}
+
+	vid2 = em28xx_read_ac97(dev, AC97_VENDOR_ID2);
+	if (vid2 < 0)
+		goto init_audio;
+
+	vid = vid1 << 16 | vid2;
+
+	dev->audio_mode.ac97_vendor_id = vid;
+	em28xx_warn("AC97 vendor ID = 0x%08x\n", vid);
+
+	feat = em28xx_read_ac97(dev, AC97_RESET);
+	if (feat < 0)
+		goto init_audio;
+
+	dev->audio_mode.ac97_feat = feat;
+	em28xx_warn("AC97 features = 0x%04x\n", feat);
+
+	/* Try to identify what audio processor we have */
+	if (((vid == 0xffffffff) || (vid == 0x83847650)) && (feat == 0x6a90))
+		dev->audio_mode.ac97 = EM28XX_AC97_EM202;
+	else if ((vid >> 8) == 0x838476)
+		dev->audio_mode.ac97 = EM28XX_AC97_SIGMATEL;
+
+init_audio:
+	/* Reports detected AC97 processor */
+	switch (dev->audio_mode.ac97) {
+	case EM28XX_NO_AC97:
+		em28xx_info("No AC97 audio processor\n");
+		break;
+	case EM28XX_AC97_EM202:
+		em28xx_info("Empia 202 AC97 audio processor detected\n");
+		break;
+	case EM28XX_AC97_SIGMATEL:
+		em28xx_info("Sigmatel audio processor detected(stac 97%02x)\n",
+			    dev->audio_mode.ac97_vendor_id & 0xff);
+		break;
+	case EM28XX_AC97_OTHER:
+		em28xx_warn("Unknown AC97 audio processor detected!\n");
+		break;
+	default:
+		break;
+	}
+
+	return em28xx_audio_analog_set(dev);
+}
+EXPORT_SYMBOL_GPL(em28xx_audio_setup);
+
+int em28xx_colorlevels_set_default(struct em28xx *dev)
+{
+	em28xx_write_reg(dev, EM28XX_R20_YGAIN, 0x10);	/* contrast */
+	em28xx_write_reg(dev, EM28XX_R21_YOFFSET, 0x00);	/* brightness */
+	em28xx_write_reg(dev, EM28XX_R22_UVGAIN, 0x10);	/* saturation */
+	em28xx_write_reg(dev, EM28XX_R23_UOFFSET, 0x00);
+	em28xx_write_reg(dev, EM28XX_R24_VOFFSET, 0x00);
+	em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, 0x00);
+
+	em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
+	em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
+	em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
+	em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
+	em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
+	em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
+	return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
+}
+
+int em28xx_capture_start(struct em28xx *dev, int start)
+{
+	int rc;
+
+	if (dev->chip_id == CHIP_ID_EM2874 ||
+	    dev->chip_id == CHIP_ID_EM2884 ||
+	    dev->chip_id == CHIP_ID_EM28174) {
+		/* The Transport Stream Enable Register moved in em2874 */
+		if (!start) {
+			rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
+						   0x00,
+						   EM2874_TS1_CAPTURE_ENABLE);
+			return rc;
+		}
+
+		/* Enable Transport Stream */
+		rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
+					   EM2874_TS1_CAPTURE_ENABLE,
+					   EM2874_TS1_CAPTURE_ENABLE);
+		return rc;
+	}
+
+
+	/* FIXME: which is the best order? */
+	/* video registers are sampled by VREF */
+	rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP,
+				   start ? 0x10 : 0x00, 0x10);
+	if (rc < 0)
+		return rc;
+
+	if (!start) {
+		/* disable video capture */
+		rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27);
+		return rc;
+	}
+
+	if (dev->board.is_webcam)
+		rc = em28xx_write_reg(dev, 0x13, 0x0c);
+
+	/* enable video capture */
+	rc = em28xx_write_reg(dev, 0x48, 0x00);
+
+	if (dev->mode == EM28XX_ANALOG_MODE)
+		rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67);
+	else
+		rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37);
+
+	msleep(6);
+
+	return rc;
+}
+
+int em28xx_vbi_supported(struct em28xx *dev)
+{
+	/* Modprobe option to manually disable */
+	if (disable_vbi == 1)
+		return 0;
+
+	if (dev->chip_id == CHIP_ID_EM2860 ||
+	    dev->chip_id == CHIP_ID_EM2883)
+		return 1;
+
+	/* Version of em28xx that does not support VBI */
+	return 0;
+}
+
+int em28xx_set_outfmt(struct em28xx *dev)
+{
+	int ret;
+	u8 vinctrl;
+
+	ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT,
+				dev->format->reg | 0x20, 0xff);
+	if (ret < 0)
+			return ret;
+
+	ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
+	if (ret < 0)
+		return ret;
+
+	vinctrl = dev->vinctl;
+	if (em28xx_vbi_supported(dev) == 1) {
+		vinctrl |= EM28XX_VINCTRL_VBI_RAW;
+		em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
+		em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4);
+		em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height);
+		if (dev->norm & V4L2_STD_525_60) {
+			/* NTSC */
+			em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
+		} else if (dev->norm & V4L2_STD_625_50) {
+			/* PAL */
+			em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
+		}
+	}
+
+	return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
+}
+
+static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
+				  u8 ymin, u8 ymax)
+{
+	em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
+			xmin, ymin, xmax, ymax);
+
+	em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
+	em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
+	em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
+	return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
+}
+
+static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+				   u16 width, u16 height)
+{
+	u8 cwidth = width;
+	u8 cheight = height;
+	u8 overflow = (height >> 7 & 0x02) | (width >> 8 & 0x01);
+
+	em28xx_coredbg("em28xx Area Set: (%d,%d)\n",
+			(width | (overflow & 2) << 7),
+			(height | (overflow & 1) << 8));
+
+	em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
+	em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
+	em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
+	em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
+	return em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
+}
+
+static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
+{
+	u8 mode;
+	/* the em2800 scaler only supports scaling down to 50% */
+
+	if (dev->board.is_em2800) {
+		mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
+	} else {
+		u8 buf[2];
+
+		buf[0] = h;
+		buf[1] = h >> 8;
+		em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
+
+		buf[0] = v;
+		buf[1] = v >> 8;
+		em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
+		/* it seems that both H and V scalers must be active
+		   to work correctly */
+		mode = (h || v) ? 0x30 : 0x00;
+	}
+	return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
+}
+
+/* FIXME: this only function read values from dev */
+int em28xx_resolution_set(struct em28xx *dev)
+{
+	int width, height;
+	width = norm_maxw(dev);
+	height = norm_maxh(dev);
+
+	/* Properly setup VBI */
+	dev->vbi_width = 720;
+	if (dev->norm & V4L2_STD_525_60)
+		dev->vbi_height = 12;
+	else
+		dev->vbi_height = 18;
+
+	em28xx_set_outfmt(dev);
+
+	em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
+
+	/* If we don't set the start position to 2 in VBI mode, we end up
+	   with line 20/21 being YUYV encoded instead of being in 8-bit
+	   greyscale.  The core of the issue is that line 21 (and line 23 for
+	   PAL WSS) are inside of active video region, and as a result they
+	   get the pixelformatting associated with that area.  So by cropping
+	   it out, we end up with the same format as the rest of the VBI
+	   region */
+	if (em28xx_vbi_supported(dev) == 1)
+		em28xx_capture_area_set(dev, 0, 2, width >> 2, height >> 2);
+	else
+		em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
+
+	return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
+}
+
+int em28xx_set_alternate(struct em28xx *dev)
+{
+	int errCode, prev_alt = dev->alt;
+	int i;
+	unsigned int min_pkt_size = dev->width * 2 + 4;
+
+	/*
+	 * alt = 0 is used only for control messages, so, only values
+	 * greater than 0 can be used for streaming.
+	 */
+	if (alt && alt < dev->num_alt) {
+		em28xx_coredbg("alternate forced to %d\n", dev->alt);
+		dev->alt = alt;
+		goto set_alt;
+	}
+
+	/* When image size is bigger than a certain value,
+	   the frame size should be increased, otherwise, only
+	   green screen will be received.
+	 */
+	if (dev->width * 2 * dev->height > 720 * 240 * 2)
+		min_pkt_size *= 2;
+
+	for (i = 0; i < dev->num_alt; i++) {
+		/* stop when the selected alt setting offers enough bandwidth */
+		if (dev->alt_max_pkt_size[i] >= min_pkt_size) {
+			dev->alt = i;
+			break;
+		/* otherwise make sure that we end up with the maximum bandwidth
+		   because the min_pkt_size equation might be wrong...
+		*/
+		} else if (dev->alt_max_pkt_size[i] >
+			   dev->alt_max_pkt_size[dev->alt])
+			dev->alt = i;
+	}
+
+set_alt:
+	if (dev->alt != prev_alt) {
+		em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
+				min_pkt_size, dev->alt);
+		dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
+		em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
+			       dev->alt, dev->max_pkt_size);
+		errCode = usb_set_interface(dev->udev, 0, dev->alt);
+		if (errCode < 0) {
+			em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
+					dev->alt, errCode);
+			return errCode;
+		}
+	}
+	return 0;
+}
+
+int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
+{
+	int rc = 0;
+
+	if (!gpio)
+		return rc;
+
+	if (dev->mode != EM28XX_SUSPEND) {
+		em28xx_write_reg(dev, 0x48, 0x00);
+		if (dev->mode == EM28XX_ANALOG_MODE)
+			em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67);
+		else
+			em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37);
+		msleep(6);
+	}
+
+	/* Send GPIO reset sequences specified at board entry */
+	while (gpio->sleep >= 0) {
+		if (gpio->reg >= 0) {
+			rc = em28xx_write_reg_bits(dev,
+						   gpio->reg,
+						   gpio->val,
+						   gpio->mask);
+			if (rc < 0)
+				return rc;
+		}
+		if (gpio->sleep > 0)
+			msleep(gpio->sleep);
+
+		gpio++;
+	}
+	return rc;
+}
+EXPORT_SYMBOL_GPL(em28xx_gpio_set);
+
+int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode)
+{
+	if (dev->mode == set_mode)
+		return 0;
+
+	if (set_mode == EM28XX_SUSPEND) {
+		dev->mode = set_mode;
+
+		/* FIXME: add suspend support for ac97 */
+
+		return em28xx_gpio_set(dev, dev->board.suspend_gpio);
+	}
+
+	dev->mode = set_mode;
+
+	if (dev->mode == EM28XX_DIGITAL_MODE)
+		return em28xx_gpio_set(dev, dev->board.dvb_gpio);
+	else
+		return em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio);
+}
+EXPORT_SYMBOL_GPL(em28xx_set_mode);
+
+/* ------------------------------------------------------------------
+	URB control
+   ------------------------------------------------------------------*/
+
+/*
+ * IRQ callback, called by URB callback
+ */
+static void em28xx_irq_callback(struct urb *urb)
+{
+	struct em28xx *dev = urb->context;
+	int i;
+
+	switch (urb->status) {
+	case 0:             /* success */
+	case -ETIMEDOUT:    /* NAK */
+		break;
+	case -ECONNRESET:   /* kill */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	default:            /* error */
+		em28xx_isocdbg("urb completition error %d.\n", urb->status);
+		break;
+	}
+
+	/* Copy data from URB */
+	spin_lock(&dev->slock);
+	dev->isoc_ctl.isoc_copy(dev, urb);
+	spin_unlock(&dev->slock);
+
+	/* Reset urb buffers */
+	for (i = 0; i < urb->number_of_packets; i++) {
+		urb->iso_frame_desc[i].status = 0;
+		urb->iso_frame_desc[i].actual_length = 0;
+	}
+	urb->status = 0;
+
+	urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (urb->status) {
+		em28xx_isocdbg("urb resubmit failed (error=%i)\n",
+			       urb->status);
+	}
+}
+
+/*
+ * Stop and Deallocate URBs
+ */
+void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode)
+{
+	struct urb *urb;
+	struct em28xx_usb_isoc_bufs *isoc_bufs;
+	int i;
+
+	em28xx_isocdbg("em28xx: called em28xx_uninit_isoc in mode %d\n", mode);
+
+	if (mode == EM28XX_DIGITAL_MODE)
+		isoc_bufs = &dev->isoc_ctl.digital_bufs;
+	else
+		isoc_bufs = &dev->isoc_ctl.analog_bufs;
+
+	for (i = 0; i < isoc_bufs->num_bufs; i++) {
+		urb = isoc_bufs->urb[i];
+		if (urb) {
+			if (!irqs_disabled())
+				usb_kill_urb(urb);
+			else
+				usb_unlink_urb(urb);
+
+			if (isoc_bufs->transfer_buffer[i]) {
+				usb_free_coherent(dev->udev,
+					urb->transfer_buffer_length,
+					isoc_bufs->transfer_buffer[i],
+					urb->transfer_dma);
+			}
+			usb_free_urb(urb);
+			isoc_bufs->urb[i] = NULL;
+		}
+		isoc_bufs->transfer_buffer[i] = NULL;
+	}
+
+	kfree(isoc_bufs->urb);
+	kfree(isoc_bufs->transfer_buffer);
+
+	isoc_bufs->urb = NULL;
+	isoc_bufs->transfer_buffer = NULL;
+	isoc_bufs->num_bufs = 0;
+
+	em28xx_capture_start(dev, 0);
+}
+EXPORT_SYMBOL_GPL(em28xx_uninit_isoc);
+
+/*
+ * Stop URBs
+ */
+void em28xx_stop_urbs(struct em28xx *dev)
+{
+	int i;
+	struct urb *urb;
+	struct em28xx_usb_isoc_bufs *isoc_bufs = &dev->isoc_ctl.digital_bufs;
+
+	em28xx_isocdbg("em28xx: called em28xx_stop_urbs\n");
+
+	for (i = 0; i < isoc_bufs->num_bufs; i++) {
+		urb = isoc_bufs->urb[i];
+		if (urb) {
+			if (!irqs_disabled())
+				usb_kill_urb(urb);
+			else
+				usb_unlink_urb(urb);
+		}
+	}
+
+	em28xx_capture_start(dev, 0);
+}
+EXPORT_SYMBOL_GPL(em28xx_stop_urbs);
+
+/*
+ * Allocate URBs
+ */
+int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode,
+		      int max_packets, int num_bufs, int max_pkt_size)
+{
+	struct em28xx_usb_isoc_bufs *isoc_bufs;
+	int i;
+	int sb_size, pipe;
+	struct urb *urb;
+	int j, k;
+
+	em28xx_isocdbg("em28xx: called em28xx_alloc_isoc in mode %d\n", mode);
+
+	if (mode == EM28XX_DIGITAL_MODE)
+		isoc_bufs = &dev->isoc_ctl.digital_bufs;
+	else
+		isoc_bufs = &dev->isoc_ctl.analog_bufs;
+
+	/* De-allocates all pending stuff */
+	em28xx_uninit_isoc(dev, mode);
+
+	isoc_bufs->num_bufs = num_bufs;
+
+	isoc_bufs->urb = kzalloc(sizeof(void *)*num_bufs,  GFP_KERNEL);
+	if (!isoc_bufs->urb) {
+		em28xx_errdev("cannot alloc memory for usb buffers\n");
+		return -ENOMEM;
+	}
+
+	isoc_bufs->transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
+					     GFP_KERNEL);
+	if (!isoc_bufs->transfer_buffer) {
+		em28xx_errdev("cannot allocate memory for usb transfer\n");
+		kfree(isoc_bufs->urb);
+		return -ENOMEM;
+	}
+
+	isoc_bufs->max_pkt_size = max_pkt_size;
+	isoc_bufs->num_packets = max_packets;
+	dev->isoc_ctl.vid_buf = NULL;
+	dev->isoc_ctl.vbi_buf = NULL;
+
+	sb_size = isoc_bufs->num_packets * isoc_bufs->max_pkt_size;
+
+	/* allocate urbs and transfer buffers */
+	for (i = 0; i < isoc_bufs->num_bufs; i++) {
+		urb = usb_alloc_urb(isoc_bufs->num_packets, GFP_KERNEL);
+		if (!urb) {
+			em28xx_err("cannot alloc isoc_ctl.urb %i\n", i);
+			em28xx_uninit_isoc(dev, mode);
+			return -ENOMEM;
+		}
+		isoc_bufs->urb[i] = urb;
+
+		isoc_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev,
+			sb_size, GFP_KERNEL, &urb->transfer_dma);
+		if (!isoc_bufs->transfer_buffer[i]) {
+			em28xx_err("unable to allocate %i bytes for transfer"
+					" buffer %i%s\n",
+					sb_size, i,
+					in_interrupt() ? " while in int" : "");
+			em28xx_uninit_isoc(dev, mode);
+			return -ENOMEM;
+		}
+		memset(isoc_bufs->transfer_buffer[i], 0, sb_size);
+
+		/* FIXME: this is a hack - should be
+			'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK'
+			should also be using 'desc.bInterval'
+		 */
+		pipe = usb_rcvisocpipe(dev->udev,
+				       mode == EM28XX_ANALOG_MODE ?
+				       EM28XX_EP_ANALOG : EM28XX_EP_DIGITAL);
+
+		usb_fill_int_urb(urb, dev->udev, pipe,
+				 isoc_bufs->transfer_buffer[i], sb_size,
+				 em28xx_irq_callback, dev, 1);
+
+		urb->number_of_packets = isoc_bufs->num_packets;
+		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+
+		k = 0;
+		for (j = 0; j < isoc_bufs->num_packets; j++) {
+			urb->iso_frame_desc[j].offset = k;
+			urb->iso_frame_desc[j].length =
+						isoc_bufs->max_pkt_size;
+			k += isoc_bufs->max_pkt_size;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(em28xx_alloc_isoc);
+
+/*
+ * Allocate URBs and start IRQ
+ */
+int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode,
+		     int max_packets, int num_bufs, int max_pkt_size,
+		     int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
+{
+	struct em28xx_dmaqueue *dma_q = &dev->vidq;
+	struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
+	struct em28xx_usb_isoc_bufs *isoc_bufs;
+	int i;
+	int rc;
+	int alloc;
+
+	em28xx_isocdbg("em28xx: called em28xx_init_isoc in mode %d\n", mode);
+
+	dev->isoc_ctl.isoc_copy = isoc_copy;
+
+	if (mode == EM28XX_DIGITAL_MODE) {
+		isoc_bufs = &dev->isoc_ctl.digital_bufs;
+		/* no need to free/alloc isoc buffers in digital mode */
+		alloc = 0;
+	} else {
+		isoc_bufs = &dev->isoc_ctl.analog_bufs;
+		alloc = 1;
+	}
+
+	if (alloc) {
+		rc = em28xx_alloc_isoc(dev, mode, max_packets,
+				       num_bufs, max_pkt_size);
+		if (rc)
+			return rc;
+	}
+
+	init_waitqueue_head(&dma_q->wq);
+	init_waitqueue_head(&vbi_dma_q->wq);
+
+	em28xx_capture_start(dev, 1);
+
+	/* submit urbs and enables IRQ */
+	for (i = 0; i < isoc_bufs->num_bufs; i++) {
+		rc = usb_submit_urb(isoc_bufs->urb[i], GFP_ATOMIC);
+		if (rc) {
+			em28xx_err("submit of urb %i failed (error=%i)\n", i,
+				   rc);
+			em28xx_uninit_isoc(dev, mode);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(em28xx_init_isoc);
+
+/*
+ * em28xx_wake_i2c()
+ * configure i2c attached devices
+ */
+void em28xx_wake_i2c(struct em28xx *dev)
+{
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core,  reset, 0);
+	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
+			INPUT(dev->ctl_input)->vmux, 0, 0);
+	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+}
+
+/*
+ * Device control list
+ */
+
+static LIST_HEAD(em28xx_devlist);
+static DEFINE_MUTEX(em28xx_devlist_mutex);
+
+/*
+ * Extension interface
+ */
+
+static LIST_HEAD(em28xx_extension_devlist);
+
+int em28xx_register_extension(struct em28xx_ops *ops)
+{
+	struct em28xx *dev = NULL;
+
+	mutex_lock(&em28xx_devlist_mutex);
+	list_add_tail(&ops->next, &em28xx_extension_devlist);
+	list_for_each_entry(dev, &em28xx_devlist, devlist) {
+		ops->init(dev);
+	}
+	mutex_unlock(&em28xx_devlist_mutex);
+	printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
+	return 0;
+}
+EXPORT_SYMBOL(em28xx_register_extension);
+
+void em28xx_unregister_extension(struct em28xx_ops *ops)
+{
+	struct em28xx *dev = NULL;
+
+	mutex_lock(&em28xx_devlist_mutex);
+	list_for_each_entry(dev, &em28xx_devlist, devlist) {
+		ops->fini(dev);
+	}
+	list_del(&ops->next);
+	mutex_unlock(&em28xx_devlist_mutex);
+	printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
+}
+EXPORT_SYMBOL(em28xx_unregister_extension);
+
+void em28xx_init_extension(struct em28xx *dev)
+{
+	const struct em28xx_ops *ops = NULL;
+
+	mutex_lock(&em28xx_devlist_mutex);
+	list_add_tail(&dev->devlist, &em28xx_devlist);
+	list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+		if (ops->init)
+			ops->init(dev);
+	}
+	mutex_unlock(&em28xx_devlist_mutex);
+}
+
+void em28xx_close_extension(struct em28xx *dev)
+{
+	const struct em28xx_ops *ops = NULL;
+
+	mutex_lock(&em28xx_devlist_mutex);
+	list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+		if (ops->fini)
+			ops->fini(dev);
+	}
+	list_del(&dev->devlist);
+	mutex_unlock(&em28xx_devlist_mutex);
+}
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
new file mode 100644
index 0000000..a16531f
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -0,0 +1,1197 @@
+/*
+ DVB device driver for em28xx
+
+ (c) 2008-2011 Mauro Carvalho Chehab <mchehab@infradead.org>
+
+ (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com>
+	- Fixes for the driver to properly work with HVR-950
+	- Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick
+	- Fixes for the driver to properly work with AMD ATI TV Wonder HD 600
+
+ (c) 2008 Aidan Thornton <makosoft@googlemail.com>
+
+ Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by:
+	(c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+	(c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+
+ 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include "em28xx.h"
+#include <media/v4l2-common.h>
+#include <media/videobuf-vmalloc.h>
+#include <media/tuner.h>
+#include "tuner-simple.h"
+
+#include "lgdt330x.h"
+#include "lgdt3305.h"
+#include "zl10353.h"
+#include "s5h1409.h"
+#include "mt352.h"
+#include "mt352_priv.h" /* FIXME */
+#include "tda1002x.h"
+#include "tda18271.h"
+#include "s921.h"
+#include "drxd.h"
+#include "cxd2820r.h"
+#include "tda18271c2dd.h"
+#include "drxk.h"
+#include "tda10071.h"
+#include "a8293.h"
+#include "qt1010.h"
+
+MODULE_DESCRIPTION("driver for em28xx based DVB cards");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages [dvb]");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define dprintk(level, fmt, arg...) do {			\
+if (debug >= level) 						\
+	printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg);	\
+} while (0)
+
+struct em28xx_dvb {
+	struct dvb_frontend        *fe[2];
+
+	/* feed count management */
+	struct mutex               lock;
+	int                        nfeeds;
+
+	/* general boilerplate stuff */
+	struct dvb_adapter         adapter;
+	struct dvb_demux           demux;
+	struct dmxdev              dmxdev;
+	struct dmx_frontend        fe_hw;
+	struct dmx_frontend        fe_mem;
+	struct dvb_net             net;
+
+	/* Due to DRX-K - probably need changes */
+	int (*gate_ctrl)(struct dvb_frontend *, int);
+	struct semaphore      pll_mutex;
+	bool			dont_attach_fe1;
+};
+
+
+static inline void print_err_status(struct em28xx *dev,
+				     int packet, int status)
+{
+	char *errmsg = "Unknown";
+
+	switch (status) {
+	case -ENOENT:
+		errmsg = "unlinked synchronuously";
+		break;
+	case -ECONNRESET:
+		errmsg = "unlinked asynchronuously";
+		break;
+	case -ENOSR:
+		errmsg = "Buffer error (overrun)";
+		break;
+	case -EPIPE:
+		errmsg = "Stalled (device not responding)";
+		break;
+	case -EOVERFLOW:
+		errmsg = "Babble (bad cable?)";
+		break;
+	case -EPROTO:
+		errmsg = "Bit-stuff error (bad cable?)";
+		break;
+	case -EILSEQ:
+		errmsg = "CRC/Timeout (could be anything)";
+		break;
+	case -ETIME:
+		errmsg = "Device does not respond";
+		break;
+	}
+	if (packet < 0) {
+		dprintk(1, "URB status %d [%s].\n", status, errmsg);
+	} else {
+		dprintk(1, "URB packet %d, status %d [%s].\n",
+			packet, status, errmsg);
+	}
+}
+
+static inline int em28xx_dvb_isoc_copy(struct em28xx *dev, struct urb *urb)
+{
+	int i;
+
+	if (!dev)
+		return 0;
+
+	if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+		return 0;
+
+	if (urb->status < 0) {
+		print_err_status(dev, -1, urb->status);
+		if (urb->status == -ENOENT)
+			return 0;
+	}
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		int status = urb->iso_frame_desc[i].status;
+
+		if (status < 0) {
+			print_err_status(dev, i, status);
+			if (urb->iso_frame_desc[i].status != -EPROTO)
+				continue;
+		}
+
+		dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer +
+				 urb->iso_frame_desc[i].offset,
+				 urb->iso_frame_desc[i].actual_length);
+	}
+
+	return 0;
+}
+
+static int em28xx_start_streaming(struct em28xx_dvb *dvb)
+{
+	int rc;
+	struct em28xx *dev = dvb->adapter.priv;
+	int max_dvb_packet_size;
+
+	usb_set_interface(dev->udev, 0, dev->dvb_alt);
+	rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
+	if (rc < 0)
+		return rc;
+
+	max_dvb_packet_size = dev->dvb_max_pkt_size;
+	if (max_dvb_packet_size < 0)
+		return max_dvb_packet_size;
+	dprintk(1, "Using %d buffers each with %d x %d bytes\n",
+		EM28XX_DVB_NUM_BUFS,
+		EM28XX_DVB_MAX_PACKETS,
+		max_dvb_packet_size);
+
+	return em28xx_init_isoc(dev, EM28XX_DIGITAL_MODE,
+				EM28XX_DVB_MAX_PACKETS, EM28XX_DVB_NUM_BUFS,
+				max_dvb_packet_size, em28xx_dvb_isoc_copy);
+}
+
+static int em28xx_stop_streaming(struct em28xx_dvb *dvb)
+{
+	struct em28xx *dev = dvb->adapter.priv;
+
+	em28xx_stop_urbs(dev);
+
+	em28xx_set_mode(dev, EM28XX_SUSPEND);
+
+	return 0;
+}
+
+static int em28xx_start_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux  = feed->demux;
+	struct em28xx_dvb *dvb = demux->priv;
+	int rc, ret;
+
+	if (!demux->dmx.frontend)
+		return -EINVAL;
+
+	mutex_lock(&dvb->lock);
+	dvb->nfeeds++;
+	rc = dvb->nfeeds;
+
+	if (dvb->nfeeds == 1) {
+		ret = em28xx_start_streaming(dvb);
+		if (ret < 0)
+			rc = ret;
+	}
+
+	mutex_unlock(&dvb->lock);
+	return rc;
+}
+
+static int em28xx_stop_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux  = feed->demux;
+	struct em28xx_dvb *dvb = demux->priv;
+	int err = 0;
+
+	mutex_lock(&dvb->lock);
+	dvb->nfeeds--;
+
+	if (0 == dvb->nfeeds)
+		err = em28xx_stop_streaming(dvb);
+
+	mutex_unlock(&dvb->lock);
+	return err;
+}
+
+
+
+/* ------------------------------------------------------------------ */
+static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+	struct em28xx *dev = fe->dvb->priv;
+
+	if (acquire)
+		return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
+	else
+		return em28xx_set_mode(dev, EM28XX_SUSPEND);
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct lgdt330x_config em2880_lgdt3303_dev = {
+	.demod_address = 0x0e,
+	.demod_chip = LGDT3303,
+};
+
+static struct lgdt3305_config em2870_lgdt3304_dev = {
+	.i2c_addr           = 0x0e,
+	.demod_chip         = LGDT3304,
+	.spectral_inversion = 1,
+	.deny_i2c_rptr      = 1,
+	.mpeg_mode          = LGDT3305_MPEG_PARALLEL,
+	.tpclk_edge         = LGDT3305_TPCLK_FALLING_EDGE,
+	.tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
+	.vsb_if_khz         = 3250,
+	.qam_if_khz         = 4000,
+};
+
+static struct s921_config sharp_isdbt = {
+	.demod_address = 0x30 >> 1
+};
+
+static struct zl10353_config em28xx_zl10353_with_xc3028 = {
+	.demod_address = (0x1e >> 1),
+	.no_tuner = 1,
+	.parallel_ts = 1,
+	.if2 = 45600,
+};
+
+static struct s5h1409_config em28xx_s5h1409_with_xc3028 = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_PARALLEL_OUTPUT,
+	.gpio          = S5H1409_GPIO_OFF,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
+};
+
+static struct tda18271_std_map kworld_a340_std_map = {
+	.atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 0,
+		      .if_lvl = 1, .rfagc_top = 0x37, },
+	.qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 1,
+		      .if_lvl = 1, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config kworld_a340_config = {
+	.std_map           = &kworld_a340_std_map,
+};
+
+static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
+	.demod_address = (0x1e >> 1),
+	.no_tuner = 1,
+	.disable_i2c_gate_ctrl = 1,
+	.parallel_ts = 1,
+	.if2 = 45600,
+};
+
+static struct drxd_config em28xx_drxd = {
+	.demod_address = 0x70,
+	.demod_revision = 0xa2,
+	.pll_type = DRXD_PLL_NONE,
+	.clock = 12000,
+	.insert_rs_byte = 1,
+	.IF = 42800000,
+	.disable_i2c_gate_ctrl = 1,
+};
+
+static struct drxk_config terratec_h5_drxk = {
+	.adr = 0x29,
+	.single_master = 1,
+	.no_i2c_bridge = 1,
+	.microcode_name = "dvb-usb-terratec-h5-drxk.fw",
+	.qam_demod_parameter_count = 2,
+};
+
+static struct drxk_config hauppauge_930c_drxk = {
+	.adr = 0x29,
+	.single_master = 1,
+	.no_i2c_bridge = 1,
+	.microcode_name = "dvb-usb-hauppauge-hvr930c-drxk.fw",
+	.chunk_size = 56,
+	.qam_demod_parameter_count = 2,
+};
+
+struct drxk_config terratec_htc_stick_drxk = {
+	.adr = 0x29,
+	.single_master = 1,
+	.no_i2c_bridge = 1,
+	.microcode_name = "dvb-usb-terratec-htc-stick-drxk.fw",
+	.chunk_size = 54,
+	.qam_demod_parameter_count = 2,
+	/* Required for the antenna_gpio to disable LNA. */
+	.antenna_dvbt = true,
+	/* The windows driver uses the same. This will disable LNA. */
+	.antenna_gpio = 0x6,
+};
+
+static struct drxk_config maxmedia_ub425_tc_drxk = {
+	.adr = 0x29,
+	.single_master = 1,
+	.no_i2c_bridge = 1,
+};
+
+static struct drxk_config pctv_520e_drxk = {
+	.adr = 0x29,
+	.single_master = 1,
+	.microcode_name = "dvb-demod-drxk-pctv.fw",
+	.qam_demod_parameter_count = 2,
+	.chunk_size = 58,
+	.antenna_dvbt = true, /* disable LNA */
+	.antenna_gpio = (1 << 2), /* disable LNA */
+};
+
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct em28xx_dvb *dvb = fe->sec_priv;
+	int status;
+
+	if (!dvb)
+		return -EINVAL;
+
+	if (enable) {
+		down(&dvb->pll_mutex);
+		status = dvb->gate_ctrl(fe, 1);
+	} else {
+		status = dvb->gate_ctrl(fe, 0);
+		up(&dvb->pll_mutex);
+	}
+	return status;
+}
+
+static void hauppauge_hvr930c_init(struct em28xx *dev)
+{
+	int i;
+
+	struct em28xx_reg_seq hauppauge_hvr930c_init[] = {
+		{EM2874_R80_GPIO,	0xff,	0xff,	0x65},
+		{EM2874_R80_GPIO,	0xfb,	0xff,	0x32},
+		{EM2874_R80_GPIO,	0xff,	0xff,	0xb8},
+		{ -1,                   -1,     -1,     -1},
+	};
+	struct em28xx_reg_seq hauppauge_hvr930c_end[] = {
+		{EM2874_R80_GPIO,	0xef,	0xff,	0x01},
+		{EM2874_R80_GPIO,	0xaf,	0xff,	0x65},
+		{EM2874_R80_GPIO,	0xef,	0xff,	0x76},
+		{EM2874_R80_GPIO,	0xef,	0xff,	0x01},
+		{EM2874_R80_GPIO,	0xcf,	0xff,	0x0b},
+		{EM2874_R80_GPIO,	0xef,	0xff,	0x40},
+
+		{EM2874_R80_GPIO,	0xcf,	0xff,	0x65},
+		{EM2874_R80_GPIO,	0xef,	0xff,	0x65},
+		{EM2874_R80_GPIO,	0xcf,	0xff,	0x0b},
+		{EM2874_R80_GPIO,	0xef,	0xff,	0x65},
+
+		{ -1,                   -1,     -1,     -1},
+	};
+
+	struct {
+		unsigned char r[4];
+		int len;
+	} regs[] = {
+		{{ 0x06, 0x02, 0x00, 0x31 }, 4},
+		{{ 0x01, 0x02 }, 2},
+		{{ 0x01, 0x02, 0x00, 0xc6 }, 4},
+		{{ 0x01, 0x00 }, 2},
+		{{ 0x01, 0x00, 0xff, 0xaf }, 4},
+		{{ 0x01, 0x00, 0x03, 0xa0 }, 4},
+		{{ 0x01, 0x00 }, 2},
+		{{ 0x01, 0x00, 0x73, 0xaf }, 4},
+		{{ 0x04, 0x00 }, 2},
+		{{ 0x00, 0x04 }, 2},
+		{{ 0x00, 0x04, 0x00, 0x0a }, 4},
+		{{ 0x04, 0x14 }, 2},
+		{{ 0x04, 0x14, 0x00, 0x00 }, 4},
+	};
+
+	em28xx_gpio_set(dev, hauppauge_hvr930c_init);
+	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
+	msleep(10);
+	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
+	msleep(10);
+
+	dev->i2c_client.addr = 0x82 >> 1;
+
+	for (i = 0; i < ARRAY_SIZE(regs); i++)
+		i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+	em28xx_gpio_set(dev, hauppauge_hvr930c_end);
+
+	msleep(100);
+
+	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
+	msleep(30);
+
+	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45);
+	msleep(10);
+
+}
+
+static void terratec_h5_init(struct em28xx *dev)
+{
+	int i;
+	struct em28xx_reg_seq terratec_h5_init[] = {
+		{EM28XX_R08_GPIO,	0xff,	0xff,	10},
+		{EM2874_R80_GPIO,	0xf6,	0xff,	100},
+		{EM2874_R80_GPIO,	0xf2,	0xff,	50},
+		{EM2874_R80_GPIO,	0xf6,	0xff,	100},
+		{ -1,                   -1,     -1,     -1},
+	};
+	struct em28xx_reg_seq terratec_h5_end[] = {
+		{EM2874_R80_GPIO,	0xe6,	0xff,	100},
+		{EM2874_R80_GPIO,	0xa6,	0xff,	50},
+		{EM2874_R80_GPIO,	0xe6,	0xff,	100},
+		{ -1,                   -1,     -1,     -1},
+	};
+	struct {
+		unsigned char r[4];
+		int len;
+	} regs[] = {
+		{{ 0x06, 0x02, 0x00, 0x31 }, 4},
+		{{ 0x01, 0x02 }, 2},
+		{{ 0x01, 0x02, 0x00, 0xc6 }, 4},
+		{{ 0x01, 0x00 }, 2},
+		{{ 0x01, 0x00, 0xff, 0xaf }, 4},
+		{{ 0x01, 0x00, 0x03, 0xa0 }, 4},
+		{{ 0x01, 0x00 }, 2},
+		{{ 0x01, 0x00, 0x73, 0xaf }, 4},
+		{{ 0x04, 0x00 }, 2},
+		{{ 0x00, 0x04 }, 2},
+		{{ 0x00, 0x04, 0x00, 0x0a }, 4},
+		{{ 0x04, 0x14 }, 2},
+		{{ 0x04, 0x14, 0x00, 0x00 }, 4},
+	};
+
+	em28xx_gpio_set(dev, terratec_h5_init);
+	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
+	msleep(10);
+	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45);
+	msleep(10);
+
+	dev->i2c_client.addr = 0x82 >> 1;
+
+	for (i = 0; i < ARRAY_SIZE(regs); i++)
+		i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+	em28xx_gpio_set(dev, terratec_h5_end);
+};
+
+static void terratec_htc_stick_init(struct em28xx *dev)
+{
+	int i;
+
+	/*
+	 * GPIO configuration:
+	 * 0xff: unknown (does not affect DVB-T).
+	 * 0xf6: DRX-K (demodulator).
+	 * 0xe6: unknown (does not affect DVB-T).
+	 * 0xb6: unknown (does not affect DVB-T).
+	 */
+	struct em28xx_reg_seq terratec_htc_stick_init[] = {
+		{EM28XX_R08_GPIO,	0xff,	0xff,	10},
+		{EM2874_R80_GPIO,	0xf6,	0xff,	100},
+		{EM2874_R80_GPIO,	0xe6,	0xff,	50},
+		{EM2874_R80_GPIO,	0xf6,	0xff,	100},
+		{ -1,                   -1,     -1,     -1},
+	};
+	struct em28xx_reg_seq terratec_htc_stick_end[] = {
+		{EM2874_R80_GPIO,	0xb6,	0xff,	100},
+		{EM2874_R80_GPIO,	0xf6,	0xff,	50},
+		{ -1,                   -1,     -1,     -1},
+	};
+
+	/* Init the analog decoder? */
+	struct {
+		unsigned char r[4];
+		int len;
+	} regs[] = {
+		{{ 0x06, 0x02, 0x00, 0x31 }, 4},
+		{{ 0x01, 0x02 }, 2},
+		{{ 0x01, 0x02, 0x00, 0xc6 }, 4},
+		{{ 0x01, 0x00 }, 2},
+		{{ 0x01, 0x00, 0xff, 0xaf }, 4},
+	};
+
+	em28xx_gpio_set(dev, terratec_htc_stick_init);
+
+	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
+	msleep(10);
+	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
+	msleep(10);
+
+	dev->i2c_client.addr = 0x82 >> 1;
+
+	for (i = 0; i < ARRAY_SIZE(regs); i++)
+		i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+
+	em28xx_gpio_set(dev, terratec_htc_stick_end);
+};
+
+static void pctv_520e_init(struct em28xx *dev)
+{
+	/*
+	 * Init AVF4910B analog decoder. Looks like I2C traffic to
+	 * digital demodulator and tuner are routed via AVF4910B.
+	 */
+	int i;
+	struct {
+		unsigned char r[4];
+		int len;
+	} regs[] = {
+		{{ 0x06, 0x02, 0x00, 0x31 }, 4},
+		{{ 0x01, 0x02 }, 2},
+		{{ 0x01, 0x02, 0x00, 0xc6 }, 4},
+		{{ 0x01, 0x00 }, 2},
+		{{ 0x01, 0x00, 0xff, 0xaf }, 4},
+		{{ 0x01, 0x00, 0x03, 0xa0 }, 4},
+		{{ 0x01, 0x00 }, 2},
+		{{ 0x01, 0x00, 0x73, 0xaf }, 4},
+	};
+
+	dev->i2c_client.addr = 0x82 >> 1; /* 0x41 */
+
+	for (i = 0; i < ARRAY_SIZE(regs); i++)
+		i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+};
+
+static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe)
+{
+	/* Values extracted from a USB trace of the Terratec Windows driver */
+	static u8 clock_config[]   = { CLOCK_CTL,  0x38, 0x2c };
+	static u8 reset[]          = { RESET,      0x80 };
+	static u8 adc_ctl_1_cfg[]  = { ADC_CTL_1,  0x40 };
+	static u8 agc_cfg[]        = { AGC_TARGET, 0x28, 0xa0 };
+	static u8 input_freq_cfg[] = { INPUT_FREQ_1, 0x31, 0xb8 };
+	static u8 rs_err_cfg[]     = { RS_ERR_PER_1, 0x00, 0x4d };
+	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+	static u8 trl_nom_cfg[]    = { TRL_NOMINAL_RATE_1, 0x64, 0x00 };
+	static u8 tps_given_cfg[]  = { TPS_GIVEN_1, 0x40, 0x80, 0x50 };
+	static u8 tuner_go[]       = { TUNER_GO, 0x01};
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(200);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	mt352_write(fe, input_freq_cfg, sizeof(input_freq_cfg));
+	mt352_write(fe, rs_err_cfg,     sizeof(rs_err_cfg));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+	mt352_write(fe, trl_nom_cfg,    sizeof(trl_nom_cfg));
+	mt352_write(fe, tps_given_cfg,  sizeof(tps_given_cfg));
+	mt352_write(fe, tuner_go,       sizeof(tuner_go));
+	return 0;
+}
+
+static struct mt352_config terratec_xs_mt352_cfg = {
+	.demod_address = (0x1e >> 1),
+	.no_tuner = 1,
+	.if2 = 45600,
+	.demod_init = em28xx_mt352_terratec_xs_init,
+};
+
+static struct tda10023_config em28xx_tda10023_config = {
+	.demod_address = 0x0c,
+	.invert = 1,
+};
+
+static struct cxd2820r_config em28xx_cxd2820r_config = {
+	.i2c_address = (0xd8 >> 1),
+	.ts_mode = CXD2820R_TS_SERIAL,
+
+	/* enable LNA for DVB-T, DVB-T2 and DVB-C */
+	.gpio_dvbt[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
+	.gpio_dvbt2[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
+	.gpio_dvbc[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
+};
+
+static struct tda18271_config em28xx_cxd2820r_tda18271_config = {
+	.output_opt = TDA18271_OUTPUT_LT_OFF,
+	.gate = TDA18271_GATE_DIGITAL,
+};
+
+static const struct tda10071_config em28xx_tda10071_config = {
+	.i2c_address = 0x55, /* (0xaa >> 1) */
+	.i2c_wr_max = 64,
+	.ts_mode = TDA10071_TS_SERIAL,
+	.spec_inv = 0,
+	.xtal = 40444000, /* 40.444 MHz */
+	.pll_multiplier = 20,
+};
+
+static const struct a8293_config em28xx_a8293_config = {
+	.i2c_addr = 0x08, /* (0x10 >> 1) */
+};
+
+static struct zl10353_config em28xx_zl10353_no_i2c_gate_dev = {
+	.demod_address = (0x1e >> 1),
+	.disable_i2c_gate_ctrl = 1,
+	.no_tuner = 1,
+	.parallel_ts = 1,
+};
+static struct qt1010_config em28xx_qt1010_config = {
+	.i2c_address = 0x62
+
+};
+
+/* ------------------------------------------------------------------ */
+
+static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
+{
+	struct dvb_frontend *fe;
+	struct xc2028_config cfg;
+
+	memset(&cfg, 0, sizeof(cfg));
+	cfg.i2c_adap  = &dev->i2c_adap;
+	cfg.i2c_addr  = addr;
+
+	if (!dev->dvb->fe[0]) {
+		em28xx_errdev("/2: dvb frontend not attached. "
+				"Can't attach xc3028\n");
+		return -EINVAL;
+	}
+
+	fe = dvb_attach(xc2028_attach, dev->dvb->fe[0], &cfg);
+	if (!fe) {
+		em28xx_errdev("/2: xc3028 attach failed\n");
+		dvb_frontend_detach(dev->dvb->fe[0]);
+		dev->dvb->fe[0] = NULL;
+		return -EINVAL;
+	}
+
+	em28xx_info("%s/2: xc3028 attached\n", dev->name);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module,
+			       struct em28xx *dev, struct device *device)
+{
+	int result;
+
+	mutex_init(&dvb->lock);
+
+	/* register adapter */
+	result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
+				      adapter_nr);
+	if (result < 0) {
+		printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
+		       dev->name, result);
+		goto fail_adapter;
+	}
+
+	/* Ensure all frontends negotiate bus access */
+	dvb->fe[0]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
+	if (dvb->fe[1])
+		dvb->fe[1]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
+
+	dvb->adapter.priv = dev;
+
+	/* register frontend */
+	result = dvb_register_frontend(&dvb->adapter, dvb->fe[0]);
+	if (result < 0) {
+		printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
+		       dev->name, result);
+		goto fail_frontend0;
+	}
+
+	/* register 2nd frontend */
+	if (dvb->fe[1]) {
+		result = dvb_register_frontend(&dvb->adapter, dvb->fe[1]);
+		if (result < 0) {
+			printk(KERN_WARNING "%s: 2nd dvb_register_frontend failed (errno = %d)\n",
+				dev->name, result);
+			goto fail_frontend1;
+		}
+	}
+
+	/* register demux stuff */
+	dvb->demux.dmx.capabilities =
+		DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+		DMX_MEMORY_BASED_FILTERING;
+	dvb->demux.priv       = dvb;
+	dvb->demux.filternum  = 256;
+	dvb->demux.feednum    = 256;
+	dvb->demux.start_feed = em28xx_start_feed;
+	dvb->demux.stop_feed  = em28xx_stop_feed;
+
+	result = dvb_dmx_init(&dvb->demux);
+	if (result < 0) {
+		printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
+		       dev->name, result);
+		goto fail_dmx;
+	}
+
+	dvb->dmxdev.filternum    = 256;
+	dvb->dmxdev.demux        = &dvb->demux.dmx;
+	dvb->dmxdev.capabilities = 0;
+	result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+	if (result < 0) {
+		printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
+		       dev->name, result);
+		goto fail_dmxdev;
+	}
+
+	dvb->fe_hw.source = DMX_FRONTEND_0;
+	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	if (result < 0) {
+		printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
+		       dev->name, result);
+		goto fail_fe_hw;
+	}
+
+	dvb->fe_mem.source = DMX_MEMORY_FE;
+	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+	if (result < 0) {
+		printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
+		       dev->name, result);
+		goto fail_fe_mem;
+	}
+
+	result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	if (result < 0) {
+		printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n",
+		       dev->name, result);
+		goto fail_fe_conn;
+	}
+
+	/* register network adapter */
+	dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+	return 0;
+
+fail_fe_conn:
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+fail_fe_mem:
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+fail_fe_hw:
+	dvb_dmxdev_release(&dvb->dmxdev);
+fail_dmxdev:
+	dvb_dmx_release(&dvb->demux);
+fail_dmx:
+	if (dvb->fe[1])
+		dvb_unregister_frontend(dvb->fe[1]);
+	dvb_unregister_frontend(dvb->fe[0]);
+fail_frontend1:
+	if (dvb->fe[1])
+		dvb_frontend_detach(dvb->fe[1]);
+fail_frontend0:
+	dvb_frontend_detach(dvb->fe[0]);
+	dvb_unregister_adapter(&dvb->adapter);
+fail_adapter:
+	return result;
+}
+
+static void em28xx_unregister_dvb(struct em28xx_dvb *dvb)
+{
+	dvb_net_release(&dvb->net);
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	dvb_dmxdev_release(&dvb->dmxdev);
+	dvb_dmx_release(&dvb->demux);
+	if (dvb->fe[1])
+		dvb_unregister_frontend(dvb->fe[1]);
+	dvb_unregister_frontend(dvb->fe[0]);
+	if (dvb->fe[1] && !dvb->dont_attach_fe1)
+		dvb_frontend_detach(dvb->fe[1]);
+	dvb_frontend_detach(dvb->fe[0]);
+	dvb_unregister_adapter(&dvb->adapter);
+}
+
+static int em28xx_dvb_init(struct em28xx *dev)
+{
+	int result = 0, mfe_shared = 0;
+	struct em28xx_dvb *dvb;
+
+	if (!dev->board.has_dvb) {
+		/* This device does not support the extension */
+		printk(KERN_INFO "em28xx_dvb: This device does not support the extension\n");
+		return 0;
+	}
+
+	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
+
+	if (dvb == NULL) {
+		em28xx_info("em28xx_dvb: memory allocation failed\n");
+		return -ENOMEM;
+	}
+	dev->dvb = dvb;
+	dvb->fe[0] = dvb->fe[1] = NULL;
+
+	mutex_lock(&dev->lock);
+	em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
+	/* init frontend */
+	switch (dev->model) {
+	case EM2874_BOARD_LEADERSHIP_ISDBT:
+		dvb->fe[0] = dvb_attach(s921_attach,
+				&sharp_isdbt, &dev->i2c_adap);
+
+		if (!dvb->fe[0]) {
+			result = -EINVAL;
+			goto out_free;
+		}
+
+		break;
+	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
+	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
+	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
+	case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
+		dvb->fe[0] = dvb_attach(lgdt330x_attach,
+					   &em2880_lgdt3303_dev,
+					   &dev->i2c_adap);
+		if (em28xx_attach_xc3028(0x61, dev) < 0) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		break;
+	case EM2880_BOARD_KWORLD_DVB_310U:
+		dvb->fe[0] = dvb_attach(zl10353_attach,
+					   &em28xx_zl10353_with_xc3028,
+					   &dev->i2c_adap);
+		if (em28xx_attach_xc3028(0x61, dev) < 0) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		break;
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+	case EM2882_BOARD_TERRATEC_HYBRID_XS:
+	case EM2880_BOARD_EMPIRE_DUAL_TV:
+		dvb->fe[0] = dvb_attach(zl10353_attach,
+					   &em28xx_zl10353_xc3028_no_i2c_gate,
+					   &dev->i2c_adap);
+		if (em28xx_attach_xc3028(0x61, dev) < 0) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		break;
+	case EM2880_BOARD_TERRATEC_HYBRID_XS:
+	case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
+	case EM2881_BOARD_PINNACLE_HYBRID_PRO:
+	case EM2882_BOARD_DIKOM_DK300:
+	case EM2882_BOARD_KWORLD_VS_DVBT:
+		dvb->fe[0] = dvb_attach(zl10353_attach,
+					   &em28xx_zl10353_xc3028_no_i2c_gate,
+					   &dev->i2c_adap);
+		if (dvb->fe[0] == NULL) {
+			/* This board could have either a zl10353 or a mt352.
+			   If the chip id isn't for zl10353, try mt352 */
+			dvb->fe[0] = dvb_attach(mt352_attach,
+						   &terratec_xs_mt352_cfg,
+						   &dev->i2c_adap);
+		}
+
+		if (em28xx_attach_xc3028(0x61, dev) < 0) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		break;
+	case EM2870_BOARD_KWORLD_355U:
+		dvb->fe[0] = dvb_attach(zl10353_attach,
+					   &em28xx_zl10353_no_i2c_gate_dev,
+					   &dev->i2c_adap);
+		if (dvb->fe[0] != NULL)
+			dvb_attach(qt1010_attach, dvb->fe[0],
+				   &dev->i2c_adap, &em28xx_qt1010_config);
+		break;
+	case EM2883_BOARD_KWORLD_HYBRID_330U:
+	case EM2882_BOARD_EVGA_INDTUBE:
+		dvb->fe[0] = dvb_attach(s5h1409_attach,
+					   &em28xx_s5h1409_with_xc3028,
+					   &dev->i2c_adap);
+		if (em28xx_attach_xc3028(0x61, dev) < 0) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		break;
+	case EM2882_BOARD_KWORLD_ATSC_315U:
+		dvb->fe[0] = dvb_attach(lgdt330x_attach,
+					   &em2880_lgdt3303_dev,
+					   &dev->i2c_adap);
+		if (dvb->fe[0] != NULL) {
+			if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
+				&dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) {
+				result = -EINVAL;
+				goto out_free;
+			}
+		}
+		break;
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
+	case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
+		dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL,
+					   &dev->i2c_adap, &dev->udev->dev);
+		if (em28xx_attach_xc3028(0x61, dev) < 0) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		break;
+	case EM2870_BOARD_REDDO_DVB_C_USB_BOX:
+		/* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */
+		dvb->fe[0] = dvb_attach(tda10023_attach,
+			&em28xx_tda10023_config,
+			&dev->i2c_adap, 0x48);
+		if (dvb->fe[0]) {
+			if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
+				&dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) {
+				result = -EINVAL;
+				goto out_free;
+			}
+		}
+		break;
+	case EM2870_BOARD_KWORLD_A340:
+		dvb->fe[0] = dvb_attach(lgdt3305_attach,
+					   &em2870_lgdt3304_dev,
+					   &dev->i2c_adap);
+		if (dvb->fe[0] != NULL)
+			dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+				   &dev->i2c_adap, &kworld_a340_config);
+		break;
+	case EM28174_BOARD_PCTV_290E:
+		dvb->fe[0] = dvb_attach(cxd2820r_attach,
+					&em28xx_cxd2820r_config,
+					&dev->i2c_adap);
+		if (dvb->fe[0]) {
+			/* FE 0 attach tuner */
+			if (!dvb_attach(tda18271_attach,
+					dvb->fe[0],
+					0x60,
+					&dev->i2c_adap,
+					&em28xx_cxd2820r_tda18271_config)) {
+
+				dvb_frontend_detach(dvb->fe[0]);
+				result = -EINVAL;
+				goto out_free;
+			}
+		}
+		break;
+	case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C:
+	{
+		struct xc5000_config cfg;
+		hauppauge_hvr930c_init(dev);
+
+		dvb->fe[0] = dvb_attach(drxk_attach,
+					&hauppauge_930c_drxk, &dev->i2c_adap);
+		if (!dvb->fe[0]) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		/* FIXME: do we need a pll semaphore? */
+		dvb->fe[0]->sec_priv = dvb;
+		sema_init(&dvb->pll_mutex, 1);
+		dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl;
+		dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+
+		/* Attach xc5000 */
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.i2c_address  = 0x61;
+		cfg.if_khz = 4000;
+
+		if (dvb->fe[0]->ops.i2c_gate_ctrl)
+			dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
+		if (!dvb_attach(xc5000_attach, dvb->fe[0], &dev->i2c_adap,
+				&cfg)) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		if (dvb->fe[0]->ops.i2c_gate_ctrl)
+			dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);
+
+		break;
+	}
+	case EM2884_BOARD_TERRATEC_H5:
+		terratec_h5_init(dev);
+
+		dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap);
+		if (!dvb->fe[0]) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		/* FIXME: do we need a pll semaphore? */
+		dvb->fe[0]->sec_priv = dvb;
+		sema_init(&dvb->pll_mutex, 1);
+		dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl;
+		dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+
+		/* Attach tda18271 to DVB-C frontend */
+		if (dvb->fe[0]->ops.i2c_gate_ctrl)
+			dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
+		if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], &dev->i2c_adap, 0x60)) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		if (dvb->fe[0]->ops.i2c_gate_ctrl)
+			dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);
+
+		break;
+	case EM28174_BOARD_PCTV_460E:
+		/* attach demod */
+		dvb->fe[0] = dvb_attach(tda10071_attach,
+			&em28xx_tda10071_config, &dev->i2c_adap);
+
+		/* attach SEC */
+		if (dvb->fe[0])
+			dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap,
+				&em28xx_a8293_config);
+		break;
+	case EM2874_BOARD_MAXMEDIA_UB425_TC:
+		/* attach demodulator */
+		dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk,
+				&dev->i2c_adap);
+
+		if (dvb->fe[0]) {
+			/* disable I2C-gate */
+			dvb->fe[0]->ops.i2c_gate_ctrl = NULL;
+
+			/* attach tuner */
+			if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0],
+					&dev->i2c_adap, 0x60)) {
+				dvb_frontend_detach(dvb->fe[0]);
+				result = -EINVAL;
+				goto out_free;
+			}
+		}
+
+		/* TODO: we need drx-3913k firmware in order to support DVB-T */
+		em28xx_info("MaxMedia UB425-TC: only DVB-C supported by that " \
+				"driver version\n");
+
+		break;
+	case EM2884_BOARD_PCTV_510E:
+	case EM2884_BOARD_PCTV_520E:
+		pctv_520e_init(dev);
+
+		/* attach demodulator */
+		dvb->fe[0] = dvb_attach(drxk_attach, &pctv_520e_drxk,
+				&dev->i2c_adap);
+
+		if (dvb->fe[0]) {
+			/* attach tuner */
+			if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+					&dev->i2c_adap,
+					&em28xx_cxd2820r_tda18271_config)) {
+				dvb_frontend_detach(dvb->fe[0]);
+				result = -EINVAL;
+				goto out_free;
+			}
+		}
+		break;
+	case EM2884_BOARD_CINERGY_HTC_STICK:
+		terratec_htc_stick_init(dev);
+
+		/* attach demodulator */
+		dvb->fe[0] = dvb_attach(drxk_attach, &terratec_htc_stick_drxk,
+					&dev->i2c_adap);
+		if (!dvb->fe[0]) {
+			result = -EINVAL;
+			goto out_free;
+		}
+
+		/* Attach the demodulator. */
+		if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+				&dev->i2c_adap,
+				&em28xx_cxd2820r_tda18271_config)) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		break;
+	default:
+		em28xx_errdev("/2: The frontend of your DVB/ATSC card"
+				" isn't supported yet\n");
+		break;
+	}
+	if (NULL == dvb->fe[0]) {
+		em28xx_errdev("/2: frontend initialization failed\n");
+		result = -EINVAL;
+		goto out_free;
+	}
+	/* define general-purpose callback pointer */
+	dvb->fe[0]->callback = em28xx_tuner_callback;
+	if (dvb->fe[1])
+		dvb->fe[1]->callback = em28xx_tuner_callback;
+
+	/* register everything */
+	result = em28xx_register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
+
+	if (result < 0)
+		goto out_free;
+
+	/* MFE lock */
+	dvb->adapter.mfe_shared = mfe_shared;
+
+	em28xx_info("Successfully loaded em28xx-dvb\n");
+ret:
+	em28xx_set_mode(dev, EM28XX_SUSPEND);
+	mutex_unlock(&dev->lock);
+	return result;
+
+out_free:
+	kfree(dvb);
+	dev->dvb = NULL;
+	goto ret;
+}
+
+static inline void prevent_sleep(struct dvb_frontend_ops *ops)
+{
+	ops->set_voltage = NULL;
+	ops->sleep = NULL;
+	ops->tuner_ops.sleep = NULL;
+}
+
+static int em28xx_dvb_fini(struct em28xx *dev)
+{
+	if (!dev->board.has_dvb) {
+		/* This device does not support the extension */
+		return 0;
+	}
+
+	if (dev->dvb) {
+		struct em28xx_dvb *dvb = dev->dvb;
+
+		if (dev->state & DEV_DISCONNECTED) {
+			/* We cannot tell the device to sleep
+			 * once it has been unplugged. */
+			if (dvb->fe[0])
+				prevent_sleep(&dvb->fe[0]->ops);
+			if (dvb->fe[1])
+				prevent_sleep(&dvb->fe[1]->ops);
+		}
+
+		em28xx_unregister_dvb(dvb);
+		kfree(dvb);
+		dev->dvb = NULL;
+	}
+
+	return 0;
+}
+
+static struct em28xx_ops dvb_ops = {
+	.id   = EM28XX_DVB,
+	.name = "Em28xx dvb Extension",
+	.init = em28xx_dvb_init,
+	.fini = em28xx_dvb_fini,
+};
+
+static int __init em28xx_dvb_register(void)
+{
+	return em28xx_register_extension(&dvb_ops);
+}
+
+static void __exit em28xx_dvb_unregister(void)
+{
+	em28xx_unregister_extension(&dvb_ops);
+}
+
+module_init(em28xx_dvb_register);
+module_exit(em28xx_dvb_unregister);
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
new file mode 100644
index 0000000..1683bd9
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -0,0 +1,568 @@
+/*
+   em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+   Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+		      Markus Rechberger <mrechberger@gmail.com>
+		      Mauro Carvalho Chehab <mchehab@infradead.org>
+		      Sascha Sommer <saschasommer@freenet.de>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+
+#include "em28xx.h"
+#include "tuner-xc2028.h"
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+
+/* ----------------------------------------------------------- */
+
+static unsigned int i2c_scan;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+static unsigned int i2c_debug;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+#define dprintk2(lvl, fmt, args...)			\
+do {							\
+	if (i2c_debug >= lvl) {				\
+		printk(KERN_DEBUG "%s at %s: " fmt,	\
+		       dev->name, __func__ , ##args);	\
+      } 						\
+} while (0)
+
+/*
+ * em2800_i2c_send_max4()
+ * send up to 4 bytes to the i2c device
+ */
+static int em2800_i2c_send_max4(struct em28xx *dev, unsigned char addr,
+				char *buf, int len)
+{
+	int ret;
+	int write_timeout;
+	unsigned char b2[6];
+	BUG_ON(len < 1 || len > 4);
+	b2[5] = 0x80 + len - 1;
+	b2[4] = addr;
+	b2[3] = buf[0];
+	if (len > 1)
+		b2[2] = buf[1];
+	if (len > 2)
+		b2[1] = buf[2];
+	if (len > 3)
+		b2[0] = buf[3];
+
+	ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
+	if (ret != 2 + len) {
+		em28xx_warn("writing to i2c device failed (error=%i)\n", ret);
+		return -EIO;
+	}
+	for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+	     write_timeout -= 5) {
+		ret = dev->em28xx_read_reg(dev, 0x05);
+		if (ret == 0x80 + len - 1)
+			return len;
+		msleep(5);
+	}
+	em28xx_warn("i2c write timed out\n");
+	return -EIO;
+}
+
+/*
+ * em2800_i2c_send_bytes()
+ */
+static int em2800_i2c_send_bytes(void *data, unsigned char addr, char *buf,
+				 short len)
+{
+	char *bufPtr = buf;
+	int ret;
+	int wrcount = 0;
+	int count;
+	int maxLen = 4;
+	struct em28xx *dev = (struct em28xx *)data;
+	while (len > 0) {
+		count = (len > maxLen) ? maxLen : len;
+		ret = em2800_i2c_send_max4(dev, addr, bufPtr, count);
+		if (ret > 0) {
+			len -= count;
+			bufPtr += count;
+			wrcount += count;
+		} else
+			return (ret < 0) ? ret : -EFAULT;
+	}
+	return wrcount;
+}
+
+/*
+ * em2800_i2c_check_for_device()
+ * check if there is a i2c_device at the supplied address
+ */
+static int em2800_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
+{
+	char msg;
+	int ret;
+	int write_timeout;
+	msg = addr;
+	ret = dev->em28xx_write_regs(dev, 0x04, &msg, 1);
+	if (ret < 0) {
+		em28xx_warn("setting i2c device address failed (error=%i)\n",
+			    ret);
+		return ret;
+	}
+	msg = 0x84;
+	ret = dev->em28xx_write_regs(dev, 0x05, &msg, 1);
+	if (ret < 0) {
+		em28xx_warn("preparing i2c read failed (error=%i)\n", ret);
+		return ret;
+	}
+	for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+	     write_timeout -= 5) {
+		unsigned reg = dev->em28xx_read_reg(dev, 0x5);
+
+		if (reg == 0x94)
+			return -ENODEV;
+		else if (reg == 0x84)
+			return 0;
+		msleep(5);
+	}
+	return -ENODEV;
+}
+
+/*
+ * em2800_i2c_recv_bytes()
+ * read from the i2c device
+ */
+static int em2800_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
+				 char *buf, int len)
+{
+	int ret;
+	/* check for the device and set i2c read address */
+	ret = em2800_i2c_check_for_device(dev, addr);
+	if (ret) {
+		em28xx_warn
+		    ("preparing read at i2c address 0x%x failed (error=%i)\n",
+		     addr, ret);
+		return ret;
+	}
+	ret = dev->em28xx_read_reg_req_len(dev, 0x0, 0x3, buf, len);
+	if (ret < 0) {
+		em28xx_warn("reading from i2c device at 0x%x failed (error=%i)",
+			    addr, ret);
+		return ret;
+	}
+	return ret;
+}
+
+/*
+ * em28xx_i2c_send_bytes()
+ */
+static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf,
+				 short len, int stop)
+{
+	int wrcount = 0;
+	struct em28xx *dev = (struct em28xx *)data;
+	int write_timeout, ret;
+
+	wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
+
+	/* Seems to be required after a write */
+	for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+	     write_timeout -= 5) {
+		ret = dev->em28xx_read_reg(dev, 0x05);
+		if (!ret)
+			break;
+		msleep(5);
+	}
+
+	return wrcount;
+}
+
+/*
+ * em28xx_i2c_recv_bytes()
+ * read a byte from the i2c device
+ */
+static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
+				 char *buf, int len)
+{
+	int ret;
+	ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
+	if (ret < 0) {
+		em28xx_warn("reading i2c device failed (error=%i)\n", ret);
+		return ret;
+	}
+	if (dev->em28xx_read_reg(dev, 0x5) != 0)
+		return -ENODEV;
+	return ret;
+}
+
+/*
+ * em28xx_i2c_check_for_device()
+ * check if there is a i2c_device at the supplied address
+ */
+static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
+{
+	int ret;
+
+	ret = dev->em28xx_read_reg_req(dev, 2, addr);
+	if (ret < 0) {
+		em28xx_warn("reading from i2c device failed (error=%i)\n", ret);
+		return ret;
+	}
+	if (dev->em28xx_read_reg(dev, 0x5) != 0)
+		return -ENODEV;
+	return 0;
+}
+
+/*
+ * em28xx_i2c_xfer()
+ * the main i2c transfer function
+ */
+static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
+			   struct i2c_msg msgs[], int num)
+{
+	struct em28xx *dev = i2c_adap->algo_data;
+	int addr, rc, i, byte;
+
+	if (num <= 0)
+		return 0;
+	for (i = 0; i < num; i++) {
+		addr = msgs[i].addr << 1;
+		dprintk2(2, "%s %s addr=%x len=%d:",
+			 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
+			 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
+		if (!msgs[i].len) { /* no len: check only for device presence */
+			if (dev->board.is_em2800)
+				rc = em2800_i2c_check_for_device(dev, addr);
+			else
+				rc = em28xx_i2c_check_for_device(dev, addr);
+			if (rc < 0) {
+				dprintk2(2, " no device\n");
+				return rc;
+			}
+
+		} else if (msgs[i].flags & I2C_M_RD) {
+			/* read bytes */
+			if (dev->board.is_em2800)
+				rc = em2800_i2c_recv_bytes(dev, addr,
+							   msgs[i].buf,
+							   msgs[i].len);
+			else
+				rc = em28xx_i2c_recv_bytes(dev, addr,
+							   msgs[i].buf,
+							   msgs[i].len);
+			if (i2c_debug >= 2) {
+				for (byte = 0; byte < msgs[i].len; byte++)
+					printk(" %02x", msgs[i].buf[byte]);
+			}
+		} else {
+			/* write bytes */
+			if (i2c_debug >= 2) {
+				for (byte = 0; byte < msgs[i].len; byte++)
+					printk(" %02x", msgs[i].buf[byte]);
+			}
+			if (dev->board.is_em2800)
+				rc = em2800_i2c_send_bytes(dev, addr,
+							   msgs[i].buf,
+							   msgs[i].len);
+			else
+				rc = em28xx_i2c_send_bytes(dev, addr,
+							   msgs[i].buf,
+							   msgs[i].len,
+							   i == num - 1);
+		}
+		if (rc < 0)
+			goto err;
+		if (i2c_debug >= 2)
+			printk("\n");
+	}
+
+	return num;
+err:
+	dprintk2(2, " ERROR: %i\n", rc);
+	return rc;
+}
+
+/* based on linux/sunrpc/svcauth.h and linux/hash.h
+ * The original hash function returns a different value, if arch is x86_64
+ *  or i386.
+ */
+static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
+{
+	unsigned long hash = 0;
+	unsigned long l = 0;
+	int len = 0;
+	unsigned char c;
+	do {
+		if (len == length) {
+			c = (char)len;
+			len = -1;
+		} else
+			c = *buf++;
+		l = (l << 8) | c;
+		len++;
+		if ((len & (32 / 8 - 1)) == 0)
+			hash = ((hash^l) * 0x9e370001UL);
+	} while (len);
+
+	return (hash >> (32 - bits)) & 0xffffffffUL;
+}
+
+static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
+{
+	unsigned char buf, *p = eedata;
+	struct em28xx_eeprom *em_eeprom = (void *)eedata;
+	int i, err, size = len, block;
+
+	if (dev->chip_id == CHIP_ID_EM2874 ||
+	    dev->chip_id == CHIP_ID_EM28174 ||
+	    dev->chip_id == CHIP_ID_EM2884) {
+		/* Empia switched to a 16-bit addressable eeprom in newer
+		   devices.  While we could certainly write a routine to read
+		   the eeprom, there is nothing of use in there that cannot be
+		   accessed through registers, and there is the risk that we
+		   could corrupt the eeprom (since a 16-bit read call is
+		   interpreted as a write call by 8-bit eeproms).
+		*/
+		return 0;
+	}
+
+	dev->i2c_client.addr = 0xa0 >> 1;
+
+	/* Check if board has eeprom */
+	err = i2c_master_recv(&dev->i2c_client, &buf, 0);
+	if (err < 0) {
+		em28xx_errdev("board has no eeprom\n");
+		memset(eedata, 0, len);
+		return -ENODEV;
+	}
+
+	buf = 0;
+
+	err = i2c_master_send(&dev->i2c_client, &buf, 1);
+	if (err != 1) {
+		printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
+		       dev->name, err);
+		return err;
+	}
+	while (size > 0) {
+		if (size > 16)
+			block = 16;
+		else
+			block = size;
+
+		if (block !=
+		    (err = i2c_master_recv(&dev->i2c_client, p, block))) {
+			printk(KERN_WARNING
+			       "%s: i2c eeprom read error (err=%d)\n",
+			       dev->name, err);
+			return err;
+		}
+		size -= block;
+		p += block;
+	}
+	for (i = 0; i < len; i++) {
+		if (0 == (i % 16))
+			printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
+		printk(" %02x", eedata[i]);
+		if (15 == (i % 16))
+			printk("\n");
+	}
+
+	if (em_eeprom->id == 0x9567eb1a)
+		dev->hash = em28xx_hash_mem(eedata, len, 32);
+
+	printk(KERN_INFO "%s: EEPROM ID= 0x%08x, EEPROM hash = 0x%08lx\n",
+	       dev->name, em_eeprom->id, dev->hash);
+
+	printk(KERN_INFO "%s: EEPROM info:\n", dev->name);
+
+	switch (em_eeprom->chip_conf >> 4 & 0x3) {
+	case 0:
+		printk(KERN_INFO "%s:\tNo audio on board.\n", dev->name);
+		break;
+	case 1:
+		printk(KERN_INFO "%s:\tAC97 audio (5 sample rates)\n",
+				 dev->name);
+		break;
+	case 2:
+		printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n",
+				 dev->name);
+		break;
+	case 3:
+		printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n",
+				 dev->name);
+		break;
+	}
+
+	if (em_eeprom->chip_conf & 1 << 3)
+		printk(KERN_INFO "%s:\tUSB Remote wakeup capable\n", dev->name);
+
+	if (em_eeprom->chip_conf & 1 << 2)
+		printk(KERN_INFO "%s:\tUSB Self power capable\n", dev->name);
+
+	switch (em_eeprom->chip_conf & 0x3) {
+	case 0:
+		printk(KERN_INFO "%s:\t500mA max power\n", dev->name);
+		break;
+	case 1:
+		printk(KERN_INFO "%s:\t400mA max power\n", dev->name);
+		break;
+	case 2:
+		printk(KERN_INFO "%s:\t300mA max power\n", dev->name);
+		break;
+	case 3:
+		printk(KERN_INFO "%s:\t200mA max power\n", dev->name);
+		break;
+	}
+	printk(KERN_INFO "%s:\tTable at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
+				dev->name,
+				em_eeprom->string_idx_table,
+				em_eeprom->string1,
+				em_eeprom->string2,
+				em_eeprom->string3);
+
+	return 0;
+}
+
+/* ----------------------------------------------------------- */
+
+/*
+ * functionality()
+ */
+static u32 functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm em28xx_algo = {
+	.master_xfer   = em28xx_i2c_xfer,
+	.functionality = functionality,
+};
+
+static struct i2c_adapter em28xx_adap_template = {
+	.owner = THIS_MODULE,
+	.name = "em28xx",
+	.algo = &em28xx_algo,
+};
+
+static struct i2c_client em28xx_client_template = {
+	.name = "em28xx internal",
+};
+
+/* ----------------------------------------------------------- */
+
+/*
+ * i2c_devs
+ * incomplete list of known devices
+ */
+static char *i2c_devs[128] = {
+	[0x4a >> 1] = "saa7113h",
+	[0x52 >> 1] = "drxk",
+	[0x60 >> 1] = "remote IR sensor",
+	[0x8e >> 1] = "remote IR sensor",
+	[0x86 >> 1] = "tda9887",
+	[0x80 >> 1] = "msp34xx",
+	[0x88 >> 1] = "msp34xx",
+	[0xa0 >> 1] = "eeprom",
+	[0xb0 >> 1] = "tda9874",
+	[0xb8 >> 1] = "tvp5150a",
+	[0xba >> 1] = "webcam sensor or tvp5150a",
+	[0xc0 >> 1] = "tuner (analog)",
+	[0xc2 >> 1] = "tuner (analog)",
+	[0xc4 >> 1] = "tuner (analog)",
+	[0xc6 >> 1] = "tuner (analog)",
+};
+
+/*
+ * do_i2c_scan()
+ * check i2c address range for devices
+ */
+void em28xx_do_i2c_scan(struct em28xx *dev)
+{
+	u8 i2c_devicelist[128];
+	unsigned char buf;
+	int i, rc;
+
+	memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
+
+	for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
+		dev->i2c_client.addr = i;
+		rc = i2c_master_recv(&dev->i2c_client, &buf, 0);
+		if (rc < 0)
+			continue;
+		i2c_devicelist[i] = i;
+		printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n",
+		       dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+	}
+
+	dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
+					ARRAY_SIZE(i2c_devicelist), 32);
+}
+
+/*
+ * em28xx_i2c_register()
+ * register i2c bus
+ */
+int em28xx_i2c_register(struct em28xx *dev)
+{
+	int retval;
+
+	BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
+	BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
+	dev->i2c_adap = em28xx_adap_template;
+	dev->i2c_adap.dev.parent = &dev->udev->dev;
+	strcpy(dev->i2c_adap.name, dev->name);
+	dev->i2c_adap.algo_data = dev;
+	i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
+
+	retval = i2c_add_adapter(&dev->i2c_adap);
+	if (retval < 0) {
+		em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n",
+			__func__, retval);
+		return retval;
+	}
+
+	dev->i2c_client = em28xx_client_template;
+	dev->i2c_client.adapter = &dev->i2c_adap;
+
+	retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
+	if ((retval < 0) && (retval != -ENODEV)) {
+		em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
+			__func__, retval);
+
+		return retval;
+	}
+
+	if (i2c_scan)
+		em28xx_do_i2c_scan(dev);
+
+	return 0;
+}
+
+/*
+ * em28xx_i2c_unregister()
+ * unregister i2c_bus
+ */
+int em28xx_i2c_unregister(struct em28xx *dev)
+{
+	i2c_del_adapter(&dev->i2c_adap);
+	return 0;
+}
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
new file mode 100644
index 0000000..97d36b4
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -0,0 +1,645 @@
+/*
+  handle em28xx IR remotes via linux kernel input layer.
+
+   Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+		      Markus Rechberger <mrechberger@gmail.com>
+		      Mauro Carvalho Chehab <mchehab@infradead.org>
+		      Sascha Sommer <saschasommer@freenet.de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+
+#include "em28xx.h"
+
+#define EM28XX_SNAPSHOT_KEY KEY_CAMERA
+#define EM28XX_SBUTTON_QUERY_INTERVAL 500
+#define EM28XX_R0C_USBSUSP_SNAPSHOT 0x20
+
+static unsigned int ir_debug;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
+
+#define MODULE_NAME "em28xx"
+
+#define i2cdprintk(fmt, arg...) \
+	if (ir_debug) { \
+		printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
+	}
+
+#define dprintk(fmt, arg...) \
+	if (ir_debug) { \
+		printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
+	}
+
+/**********************************************************
+ Polling structure used by em28xx IR's
+ **********************************************************/
+
+struct em28xx_ir_poll_result {
+	unsigned int toggle_bit:1;
+	unsigned int read_count:7;
+	u8 rc_address;
+	u8 rc_data[4]; /* 1 byte on em2860/2880, 4 on em2874 */
+};
+
+struct em28xx_IR {
+	struct em28xx *dev;
+	struct rc_dev *rc;
+	char name[32];
+	char phys[32];
+
+	/* poll external decoder */
+	int polling;
+	struct delayed_work work;
+	unsigned int full_code:1;
+	unsigned int last_readcount;
+
+	int  (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
+};
+
+/**********************************************************
+ I2C IR based get keycodes - should be used with ir-kbd-i2c
+ **********************************************************/
+
+static int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char b;
+
+	/* poll IR chip */
+	if (1 != i2c_master_recv(ir->c, &b, 1)) {
+		i2cdprintk("read error\n");
+		return -EIO;
+	}
+
+	/* it seems that 0xFE indicates that a button is still hold
+	   down, while 0xff indicates that no button is hold
+	   down. 0xfe sequences are sometimes interrupted by 0xFF */
+
+	i2cdprintk("key %02x\n", b);
+
+	if (b == 0xff)
+		return 0;
+
+	if (b == 0xfe)
+		/* keep old data */
+		return 1;
+
+	*ir_key = b;
+	*ir_raw = b;
+	return 1;
+}
+
+static int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char buf[2];
+	u16 code;
+	int size;
+
+	/* poll IR chip */
+	size = i2c_master_recv(ir->c, buf, sizeof(buf));
+
+	if (size != 2)
+		return -EIO;
+
+	/* Does eliminate repeated parity code */
+	if (buf[1] == 0xff)
+		return 0;
+
+	ir->old = buf[1];
+
+	/*
+	 * Rearranges bits to the right order.
+	 * The bit order were determined experimentally by using
+	 * The original Hauppauge Grey IR and another RC5 that uses addr=0x08
+	 * The RC5 code has 14 bits, but we've experimentally determined
+	 * the meaning for only 11 bits.
+	 * So, the code translation is not complete. Yet, it is enough to
+	 * work with the provided RC5 IR.
+	 */
+	code =
+		 ((buf[0] & 0x01) ? 0x0020 : 0) | /* 		0010 0000 */
+		 ((buf[0] & 0x02) ? 0x0010 : 0) | /* 		0001 0000 */
+		 ((buf[0] & 0x04) ? 0x0008 : 0) | /* 		0000 1000 */
+		 ((buf[0] & 0x08) ? 0x0004 : 0) | /* 		0000 0100 */
+		 ((buf[0] & 0x10) ? 0x0002 : 0) | /* 		0000 0010 */
+		 ((buf[0] & 0x20) ? 0x0001 : 0) | /* 		0000 0001 */
+		 ((buf[1] & 0x08) ? 0x1000 : 0) | /* 0001 0000		  */
+		 ((buf[1] & 0x10) ? 0x0800 : 0) | /* 0000 1000		  */
+		 ((buf[1] & 0x20) ? 0x0400 : 0) | /* 0000 0100		  */
+		 ((buf[1] & 0x40) ? 0x0200 : 0) | /* 0000 0010		  */
+		 ((buf[1] & 0x80) ? 0x0100 : 0);  /* 0000 0001		  */
+
+	i2cdprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x%02x)\n",
+			code, buf[1], buf[0]);
+
+	/* return key */
+	*ir_key = code;
+	*ir_raw = code;
+	return 1;
+}
+
+static int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
+				     u32 *ir_raw)
+{
+	unsigned char buf[3];
+
+	/* poll IR chip */
+
+	if (3 != i2c_master_recv(ir->c, buf, 3)) {
+		i2cdprintk("read error\n");
+		return -EIO;
+	}
+
+	i2cdprintk("key %02x\n", buf[2]&0x3f);
+	if (buf[0] != 0x00)
+		return 0;
+
+	*ir_key = buf[2]&0x3f;
+	*ir_raw = buf[2]&0x3f;
+
+	return 1;
+}
+
+static int em28xx_get_key_winfast_usbii_deluxe(struct IR_i2c *ir, u32 *ir_key,
+					u32 *ir_raw)
+{
+	unsigned char subaddr, keydetect, key;
+
+	struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0, .buf = &subaddr, .len = 1},
+
+				{ .addr = ir->c->addr, .flags = I2C_M_RD, .buf = &keydetect, .len = 1} };
+
+	subaddr = 0x10;
+	if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
+		i2cdprintk("read error\n");
+		return -EIO;
+	}
+	if (keydetect == 0x00)
+		return 0;
+
+	subaddr = 0x00;
+	msg[1].buf = &key;
+	if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
+		i2cdprintk("read error\n");
+	return -EIO;
+	}
+	if (key == 0x00)
+		return 0;
+
+	*ir_key = key;
+	*ir_raw = key;
+	return 1;
+}
+
+/**********************************************************
+ Poll based get keycode functions
+ **********************************************************/
+
+/* This is for the em2860/em2880 */
+static int default_polling_getkey(struct em28xx_IR *ir,
+				  struct em28xx_ir_poll_result *poll_result)
+{
+	struct em28xx *dev = ir->dev;
+	int rc;
+	u8 msg[3] = { 0, 0, 0 };
+
+	/* Read key toggle, brand, and key code
+	   on registers 0x45, 0x46 and 0x47
+	 */
+	rc = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R45_IR,
+					  msg, sizeof(msg));
+	if (rc < 0)
+		return rc;
+
+	/* Infrared toggle (Reg 0x45[7]) */
+	poll_result->toggle_bit = (msg[0] >> 7);
+
+	/* Infrared read count (Reg 0x45[6:0] */
+	poll_result->read_count = (msg[0] & 0x7f);
+
+	/* Remote Control Address (Reg 0x46) */
+	poll_result->rc_address = msg[1];
+
+	/* Remote Control Data (Reg 0x47) */
+	poll_result->rc_data[0] = msg[2];
+
+	return 0;
+}
+
+static int em2874_polling_getkey(struct em28xx_IR *ir,
+				 struct em28xx_ir_poll_result *poll_result)
+{
+	struct em28xx *dev = ir->dev;
+	int rc;
+	u8 msg[5] = { 0, 0, 0, 0, 0 };
+
+	/* Read key toggle, brand, and key code
+	   on registers 0x51-55
+	 */
+	rc = dev->em28xx_read_reg_req_len(dev, 0, EM2874_R51_IR,
+					  msg, sizeof(msg));
+	if (rc < 0)
+		return rc;
+
+	/* Infrared toggle (Reg 0x51[7]) */
+	poll_result->toggle_bit = (msg[0] >> 7);
+
+	/* Infrared read count (Reg 0x51[6:0] */
+	poll_result->read_count = (msg[0] & 0x7f);
+
+	/* Remote Control Address (Reg 0x52) */
+	poll_result->rc_address = msg[1];
+
+	/* Remote Control Data (Reg 0x53-55) */
+	poll_result->rc_data[0] = msg[2];
+	poll_result->rc_data[1] = msg[3];
+	poll_result->rc_data[2] = msg[4];
+
+	return 0;
+}
+
+/**********************************************************
+ Polling code for em28xx
+ **********************************************************/
+
+static void em28xx_ir_handle_key(struct em28xx_IR *ir)
+{
+	int result;
+	struct em28xx_ir_poll_result poll_result;
+
+	/* read the registers containing the IR status */
+	result = ir->get_key(ir, &poll_result);
+	if (unlikely(result < 0)) {
+		dprintk("ir->get_key() failed %d\n", result);
+		return;
+	}
+
+	if (unlikely(poll_result.read_count != ir->last_readcount)) {
+		dprintk("%s: toggle: %d, count: %d, key 0x%02x%02x\n", __func__,
+			poll_result.toggle_bit, poll_result.read_count,
+			poll_result.rc_address, poll_result.rc_data[0]);
+		if (ir->full_code)
+			rc_keydown(ir->rc,
+				   poll_result.rc_address << 8 |
+				   poll_result.rc_data[0],
+				   poll_result.toggle_bit);
+		else
+			rc_keydown(ir->rc,
+				   poll_result.rc_data[0],
+				   poll_result.toggle_bit);
+
+		if (ir->dev->chip_id == CHIP_ID_EM2874 ||
+		    ir->dev->chip_id == CHIP_ID_EM2884)
+			/* The em2874 clears the readcount field every time the
+			   register is read.  The em2860/2880 datasheet says that it
+			   is supposed to clear the readcount, but it doesn't.  So with
+			   the em2874, we are looking for a non-zero read count as
+			   opposed to a readcount that is incrementing */
+			ir->last_readcount = 0;
+		else
+			ir->last_readcount = poll_result.read_count;
+	}
+}
+
+static void em28xx_ir_work(struct work_struct *work)
+{
+	struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work.work);
+
+	em28xx_ir_handle_key(ir);
+	schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
+}
+
+static int em28xx_ir_start(struct rc_dev *rc)
+{
+	struct em28xx_IR *ir = rc->priv;
+
+	INIT_DELAYED_WORK(&ir->work, em28xx_ir_work);
+	schedule_delayed_work(&ir->work, 0);
+
+	return 0;
+}
+
+static void em28xx_ir_stop(struct rc_dev *rc)
+{
+	struct em28xx_IR *ir = rc->priv;
+
+	cancel_delayed_work_sync(&ir->work);
+}
+
+static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type)
+{
+	int rc = 0;
+	struct em28xx_IR *ir = rc_dev->priv;
+	struct em28xx *dev = ir->dev;
+	u8 ir_config = EM2874_IR_RC5;
+
+	/* Adjust xclk based o IR table for RC5/NEC tables */
+
+	if (rc_type == RC_TYPE_RC5) {
+		dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE;
+		ir->full_code = 1;
+	} else if (rc_type == RC_TYPE_NEC) {
+		dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE;
+		ir_config = EM2874_IR_NEC;
+		ir->full_code = 1;
+	} else if (rc_type != RC_TYPE_UNKNOWN)
+		rc = -EINVAL;
+
+	em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk,
+			      EM28XX_XCLK_IR_RC5_MODE);
+
+	/* Setup the proper handler based on the chip */
+	switch (dev->chip_id) {
+	case CHIP_ID_EM2860:
+	case CHIP_ID_EM2883:
+		ir->get_key = default_polling_getkey;
+		break;
+	case CHIP_ID_EM2884:
+	case CHIP_ID_EM2874:
+	case CHIP_ID_EM28174:
+		ir->get_key = em2874_polling_getkey;
+		em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1);
+		break;
+	default:
+		printk("Unrecognized em28xx chip id 0x%02x: IR not supported\n",
+			dev->chip_id);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static void em28xx_register_i2c_ir(struct em28xx *dev)
+{
+	/* Leadtek winfast tv USBII deluxe can find a non working IR-device */
+	/* at address 0x18, so if that address is needed for another board in */
+	/* the future, please put it after 0x1f. */
+	struct i2c_board_info info;
+	const unsigned short addr_list[] = {
+		 0x1f, 0x30, 0x47, I2C_CLIENT_END
+	};
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	memset(&dev->init_data, 0, sizeof(dev->init_data));
+	strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+
+	/* detect & configure */
+	switch (dev->model) {
+	case EM2800_BOARD_TERRATEC_CINERGY_200:
+	case EM2820_BOARD_TERRATEC_CINERGY_250:
+		dev->init_data.ir_codes = RC_MAP_EM_TERRATEC;
+		dev->init_data.get_key = em28xx_get_key_terratec;
+		dev->init_data.name = "i2c IR (EM28XX Terratec)";
+		break;
+	case EM2820_BOARD_PINNACLE_USB_2:
+		dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY;
+		dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
+		dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
+		break;
+	case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
+		dev->init_data.ir_codes = RC_MAP_HAUPPAUGE;
+		dev->init_data.get_key = em28xx_get_key_em_haup;
+		dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
+		break;
+	case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
+		dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE;
+		dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe;
+		dev->init_data.name = "i2c IR (EM2820 Winfast TV USBII Deluxe)";
+		break;
+	}
+
+	if (dev->init_data.name)
+		info.platform_data = &dev->init_data;
+	i2c_new_probed_device(&dev->i2c_adap, &info, addr_list, NULL);
+}
+
+/**********************************************************
+ Handle Webcam snapshot button
+ **********************************************************/
+
+static void em28xx_query_sbutton(struct work_struct *work)
+{
+	/* Poll the register and see if the button is depressed */
+	struct em28xx *dev =
+		container_of(work, struct em28xx, sbutton_query_work.work);
+	int ret;
+
+	ret = em28xx_read_reg(dev, EM28XX_R0C_USBSUSP);
+
+	if (ret & EM28XX_R0C_USBSUSP_SNAPSHOT) {
+		u8 cleared;
+		/* Button is depressed, clear the register */
+		cleared = ((u8) ret) & ~EM28XX_R0C_USBSUSP_SNAPSHOT;
+		em28xx_write_regs(dev, EM28XX_R0C_USBSUSP, &cleared, 1);
+
+		/* Not emulate the keypress */
+		input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
+				 1);
+		/* Now unpress the key */
+		input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
+				 0);
+	}
+
+	/* Schedule next poll */
+	schedule_delayed_work(&dev->sbutton_query_work,
+			      msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
+}
+
+static void em28xx_register_snapshot_button(struct em28xx *dev)
+{
+	struct input_dev *input_dev;
+	int err;
+
+	em28xx_info("Registering snapshot button...\n");
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		em28xx_errdev("input_allocate_device failed\n");
+		return;
+	}
+
+	usb_make_path(dev->udev, dev->snapshot_button_path,
+		      sizeof(dev->snapshot_button_path));
+	strlcat(dev->snapshot_button_path, "/sbutton",
+		sizeof(dev->snapshot_button_path));
+	INIT_DELAYED_WORK(&dev->sbutton_query_work, em28xx_query_sbutton);
+
+	input_dev->name = "em28xx snapshot button";
+	input_dev->phys = dev->snapshot_button_path;
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+	set_bit(EM28XX_SNAPSHOT_KEY, input_dev->keybit);
+	input_dev->keycodesize = 0;
+	input_dev->keycodemax = 0;
+	input_dev->id.bustype = BUS_USB;
+	input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+	input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+	input_dev->id.version = 1;
+	input_dev->dev.parent = &dev->udev->dev;
+
+	err = input_register_device(input_dev);
+	if (err) {
+		em28xx_errdev("input_register_device failed\n");
+		input_free_device(input_dev);
+		return;
+	}
+
+	dev->sbutton_input_dev = input_dev;
+	schedule_delayed_work(&dev->sbutton_query_work,
+			      msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
+	return;
+
+}
+
+static void em28xx_deregister_snapshot_button(struct em28xx *dev)
+{
+	if (dev->sbutton_input_dev != NULL) {
+		em28xx_info("Deregistering snapshot button\n");
+		cancel_delayed_work_sync(&dev->sbutton_query_work);
+		input_unregister_device(dev->sbutton_input_dev);
+		dev->sbutton_input_dev = NULL;
+	}
+	return;
+}
+
+static int em28xx_ir_init(struct em28xx *dev)
+{
+	struct em28xx_IR *ir;
+	struct rc_dev *rc;
+	int err = -ENOMEM;
+
+	if (dev->board.ir_codes == NULL) {
+		/* No remote control support */
+		em28xx_warn("Remote control support is not available for "
+				"this card.\n");
+		return 0;
+	}
+
+	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+	rc = rc_allocate_device();
+	if (!ir || !rc)
+		goto err_out_free;
+
+	/* record handles to ourself */
+	ir->dev = dev;
+	dev->ir = ir;
+	ir->rc = rc;
+
+	/*
+	 * em2874 supports more protocols. For now, let's just announce
+	 * the two protocols that were already tested
+	 */
+	rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC;
+	rc->priv = ir;
+	rc->change_protocol = em28xx_ir_change_protocol;
+	rc->open = em28xx_ir_start;
+	rc->close = em28xx_ir_stop;
+
+	/* By default, keep protocol field untouched */
+	err = em28xx_ir_change_protocol(rc, RC_TYPE_UNKNOWN);
+	if (err)
+		goto err_out_free;
+
+	/* This is how often we ask the chip for IR information */
+	ir->polling = 100; /* ms */
+
+	/* init input device */
+	snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)",
+						dev->name);
+
+	usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
+	strlcat(ir->phys, "/input0", sizeof(ir->phys));
+
+	rc->input_name = ir->name;
+	rc->input_phys = ir->phys;
+	rc->input_id.bustype = BUS_USB;
+	rc->input_id.version = 1;
+	rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+	rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+	rc->dev.parent = &dev->udev->dev;
+	rc->map_name = dev->board.ir_codes;
+	rc->driver_name = MODULE_NAME;
+
+	/* all done */
+	err = rc_register_device(rc);
+	if (err)
+		goto err_out_stop;
+
+	em28xx_register_i2c_ir(dev);
+
+#if defined(CONFIG_MODULES) && defined(MODULE)
+	if (dev->board.has_ir_i2c)
+		request_module("ir-kbd-i2c");
+#endif
+	if (dev->board.has_snapshot_button)
+		em28xx_register_snapshot_button(dev);
+
+	return 0;
+
+ err_out_stop:
+	dev->ir = NULL;
+ err_out_free:
+	rc_free_device(rc);
+	kfree(ir);
+	return err;
+}
+
+static int em28xx_ir_fini(struct em28xx *dev)
+{
+	struct em28xx_IR *ir = dev->ir;
+
+	em28xx_deregister_snapshot_button(dev);
+
+	/* skip detach on non attached boards */
+	if (!ir)
+		return 0;
+
+	if (ir->rc)
+		rc_unregister_device(ir->rc);
+
+	/* done */
+	kfree(ir);
+	dev->ir = NULL;
+	return 0;
+}
+
+static struct em28xx_ops rc_ops = {
+	.id   = EM28XX_RC,
+	.name = "Em28xx Input Extension",
+	.init = em28xx_ir_init,
+	.fini = em28xx_ir_fini,
+};
+
+static int __init em28xx_rc_register(void)
+{
+	return em28xx_register_extension(&rc_ops);
+}
+
+static void __exit em28xx_rc_unregister(void)
+{
+	em28xx_unregister_extension(&rc_ops);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_DESCRIPTION("Em28xx Input driver");
+
+module_init(em28xx_rc_register);
+module_exit(em28xx_rc_unregister);
diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h
new file mode 100644
index 0000000..6ff3682
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-reg.h
@@ -0,0 +1,226 @@
+#define EM_GPIO_0  (1 << 0)
+#define EM_GPIO_1  (1 << 1)
+#define EM_GPIO_2  (1 << 2)
+#define EM_GPIO_3  (1 << 3)
+#define EM_GPIO_4  (1 << 4)
+#define EM_GPIO_5  (1 << 5)
+#define EM_GPIO_6  (1 << 6)
+#define EM_GPIO_7  (1 << 7)
+
+#define EM_GPO_0   (1 << 0)
+#define EM_GPO_1   (1 << 1)
+#define EM_GPO_2   (1 << 2)
+#define EM_GPO_3   (1 << 3)
+
+/* em28xx endpoints */
+#define EM28XX_EP_ANALOG	0x82
+#define EM28XX_EP_AUDIO		0x83
+#define EM28XX_EP_DIGITAL	0x84
+
+/* em2800 registers */
+#define EM2800_R08_AUDIOSRC 0x08
+
+/* em28xx registers */
+
+#define EM28XX_R00_CHIPCFG	0x00
+
+/* em28xx Chip Configuration 0x00 */
+#define EM28XX_CHIPCFG_VENDOR_AUDIO		0x80
+#define EM28XX_CHIPCFG_I2S_VOLUME_CAPABLE	0x40
+#define EM28XX_CHIPCFG_I2S_5_SAMPRATES		0x30
+#define EM28XX_CHIPCFG_I2S_3_SAMPRATES		0x20
+#define EM28XX_CHIPCFG_AC97			0x10
+#define EM28XX_CHIPCFG_AUDIOMASK		0x30
+
+#define EM28XX_R01_CHIPCFG2	0x01
+
+/* em28xx Chip Configuration 2 0x01 */
+#define EM28XX_CHIPCFG2_TS_PRESENT		0x10
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_MASK	0x0c /* bits 3-2 */
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_1MF	0x00
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_2MF	0x04
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_4MF	0x08
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_8MF	0x0c
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK	0x03 /* bits 0-1 */
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_188	0x00
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_376	0x01
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_564	0x02
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_752	0x03
+
+
+	/* GPIO/GPO registers */
+#define EM2880_R04_GPO	0x04    /* em2880-em2883 only */
+#define EM28XX_R08_GPIO	0x08	/* em2820 or upper */
+
+#define EM28XX_R06_I2C_CLK	0x06
+
+/* em28xx I2C Clock Register (0x06) */
+#define EM28XX_I2C_CLK_ACK_LAST_READ	0x80
+#define EM28XX_I2C_CLK_WAIT_ENABLE	0x40
+#define EM28XX_I2C_EEPROM_ON_BOARD	0x08
+#define EM28XX_I2C_EEPROM_KEY_VALID	0x04
+#define EM2874_I2C_SECONDARY_BUS_SELECT	0x04 /* em2874 has two i2c busses */
+#define EM28XX_I2C_FREQ_1_5_MHZ		0x03 /* bus frequency (bits [1-0]) */
+#define EM28XX_I2C_FREQ_25_KHZ		0x02
+#define EM28XX_I2C_FREQ_400_KHZ		0x01
+#define EM28XX_I2C_FREQ_100_KHZ		0x00
+
+
+#define EM28XX_R0A_CHIPID	0x0a
+#define EM28XX_R0C_USBSUSP	0x0c	/* */
+
+#define EM28XX_R0E_AUDIOSRC	0x0e
+#define EM28XX_R0F_XCLK	0x0f
+
+/* em28xx XCLK Register (0x0f) */
+#define EM28XX_XCLK_AUDIO_UNMUTE	0x80 /* otherwise audio muted */
+#define EM28XX_XCLK_I2S_MSB_TIMING	0x40 /* otherwise standard timing */
+#define EM28XX_XCLK_IR_RC5_MODE		0x20 /* otherwise NEC mode */
+#define EM28XX_XCLK_IR_NEC_CHK_PARITY	0x10
+#define EM28XX_XCLK_FREQUENCY_30MHZ	0x00 /* Freq. select (bits [3-0]) */
+#define EM28XX_XCLK_FREQUENCY_15MHZ	0x01
+#define EM28XX_XCLK_FREQUENCY_10MHZ	0x02
+#define EM28XX_XCLK_FREQUENCY_7_5MHZ	0x03
+#define EM28XX_XCLK_FREQUENCY_6MHZ	0x04
+#define EM28XX_XCLK_FREQUENCY_5MHZ	0x05
+#define EM28XX_XCLK_FREQUENCY_4_3MHZ	0x06
+#define EM28XX_XCLK_FREQUENCY_12MHZ	0x07
+#define EM28XX_XCLK_FREQUENCY_20MHZ	0x08
+#define EM28XX_XCLK_FREQUENCY_20MHZ_2	0x09
+#define EM28XX_XCLK_FREQUENCY_48MHZ	0x0a
+#define EM28XX_XCLK_FREQUENCY_24MHZ	0x0b
+
+#define EM28XX_R10_VINMODE	0x10
+
+#define EM28XX_R11_VINCTRL	0x11
+
+/* em28xx Video Input Control Register 0x11 */
+#define EM28XX_VINCTRL_VBI_SLICED	0x80
+#define EM28XX_VINCTRL_VBI_RAW		0x40
+#define EM28XX_VINCTRL_VOUT_MODE_IN	0x20 /* HREF,VREF,VACT in output */
+#define EM28XX_VINCTRL_CCIR656_ENABLE	0x10
+#define EM28XX_VINCTRL_VBI_16BIT_RAW	0x08 /* otherwise 8-bit raw */
+#define EM28XX_VINCTRL_FID_ON_HREF	0x04
+#define EM28XX_VINCTRL_DUAL_EDGE_STROBE	0x02
+#define EM28XX_VINCTRL_INTERLACED	0x01
+
+#define EM28XX_R12_VINENABLE	0x12	/* */
+
+#define EM28XX_R14_GAMMA	0x14
+#define EM28XX_R15_RGAIN	0x15
+#define EM28XX_R16_GGAIN	0x16
+#define EM28XX_R17_BGAIN	0x17
+#define EM28XX_R18_ROFFSET	0x18
+#define EM28XX_R19_GOFFSET	0x19
+#define EM28XX_R1A_BOFFSET	0x1a
+
+#define EM28XX_R1B_OFLOW	0x1b
+#define EM28XX_R1C_HSTART	0x1c
+#define EM28XX_R1D_VSTART	0x1d
+#define EM28XX_R1E_CWIDTH	0x1e
+#define EM28XX_R1F_CHEIGHT	0x1f
+
+#define EM28XX_R20_YGAIN	0x20
+#define EM28XX_R21_YOFFSET	0x21
+#define EM28XX_R22_UVGAIN	0x22
+#define EM28XX_R23_UOFFSET	0x23
+#define EM28XX_R24_VOFFSET	0x24
+#define EM28XX_R25_SHARPNESS	0x25
+
+#define EM28XX_R26_COMPR	0x26
+#define EM28XX_R27_OUTFMT	0x27
+
+/* em28xx Output Format Register (0x27) */
+#define EM28XX_OUTFMT_RGB_8_RGRG	0x00
+#define EM28XX_OUTFMT_RGB_8_GRGR	0x01
+#define EM28XX_OUTFMT_RGB_8_GBGB	0x02
+#define EM28XX_OUTFMT_RGB_8_BGBG	0x03
+#define EM28XX_OUTFMT_RGB_16_656	0x04
+#define EM28XX_OUTFMT_RGB_8_BAYER	0x08 /* Pattern in Reg 0x10[1-0] */
+#define EM28XX_OUTFMT_YUV211		0x10
+#define EM28XX_OUTFMT_YUV422_Y0UY1V	0x14
+#define EM28XX_OUTFMT_YUV422_Y1UY0V	0x15
+#define EM28XX_OUTFMT_YUV411		0x18
+
+
+#define EM28XX_R28_XMIN	0x28
+#define EM28XX_R29_XMAX	0x29
+#define EM28XX_R2A_YMIN	0x2a
+#define EM28XX_R2B_YMAX	0x2b
+
+#define EM28XX_R30_HSCALELOW	0x30
+#define EM28XX_R31_HSCALEHIGH	0x31
+#define EM28XX_R32_VSCALELOW	0x32
+#define EM28XX_R33_VSCALEHIGH	0x33
+#define EM28XX_R34_VBI_START_H	0x34
+#define EM28XX_R35_VBI_START_V	0x35
+#define EM28XX_R36_VBI_WIDTH	0x36
+#define EM28XX_R37_VBI_HEIGHT	0x37
+
+#define EM28XX_R40_AC97LSB	0x40
+#define EM28XX_R41_AC97MSB	0x41
+#define EM28XX_R42_AC97ADDR	0x42
+#define EM28XX_R43_AC97BUSY	0x43
+
+#define EM28XX_R45_IR		0x45
+	/* 0x45  bit 7    - parity bit
+		 bits 6-0 - count
+	   0x46  IR brand
+	   0x47  IR data
+	 */
+
+/* em2874 registers */
+#define EM2874_R50_IR_CONFIG    0x50
+#define EM2874_R51_IR           0x51
+#define EM2874_R5F_TS_ENABLE    0x5f
+#define EM2874_R80_GPIO         0x80
+
+/* em2874 IR config register (0x50) */
+#define EM2874_IR_NEC           0x00
+#define EM2874_IR_RC5           0x04
+#define EM2874_IR_RC6_MODE_0    0x08
+#define EM2874_IR_RC6_MODE_6A   0x0b
+
+/* em2874 Transport Stream Enable Register (0x5f) */
+#define EM2874_TS1_CAPTURE_ENABLE (1 << 0)
+#define EM2874_TS1_FILTER_ENABLE  (1 << 1)
+#define EM2874_TS1_NULL_DISCARD   (1 << 2)
+#define EM2874_TS2_CAPTURE_ENABLE (1 << 4)
+#define EM2874_TS2_FILTER_ENABLE  (1 << 5)
+#define EM2874_TS2_NULL_DISCARD   (1 << 6)
+
+/* register settings */
+#define EM2800_AUDIO_SRC_TUNER  0x0d
+#define EM2800_AUDIO_SRC_LINE   0x0c
+#define EM28XX_AUDIO_SRC_TUNER	0xc0
+#define EM28XX_AUDIO_SRC_LINE	0x80
+
+/* FIXME: Need to be populated with the other chip ID's */
+enum em28xx_chip_id {
+	CHIP_ID_EM2800 = 7,
+	CHIP_ID_EM2710 = 17,
+	CHIP_ID_EM2820 = 18,	/* Also used by some em2710 */
+	CHIP_ID_EM2840 = 20,
+	CHIP_ID_EM2750 = 33,
+	CHIP_ID_EM2860 = 34,
+	CHIP_ID_EM2870 = 35,
+	CHIP_ID_EM2883 = 36,
+	CHIP_ID_EM2874 = 65,
+	CHIP_ID_EM2884 = 68,
+	CHIP_ID_EM28174 = 113,
+};
+
+/*
+ * Registers used by em202
+ */
+
+/* EMP202 vendor registers */
+#define EM202_EXT_MODEM_CTRL     0x3e
+#define EM202_GPIO_CONF          0x4c
+#define EM202_GPIO_POLARITY      0x4e
+#define EM202_GPIO_STICKY        0x50
+#define EM202_GPIO_MASK          0x52
+#define EM202_GPIO_STATUS        0x54
+#define EM202_SPDIF_OUT_SEL      0x6a
+#define EM202_ANTIPOP            0x72
+#define EM202_EAPD_GPIO_ACCESS   0x74
diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
new file mode 100644
index 0000000..2b4c9cb
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-vbi.c
@@ -0,0 +1,145 @@
+/*
+   em28xx-vbi.c - VBI driver for em28xx
+
+   Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
+
+   This work was sponsored by EyeMagnet Limited.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/hardirq.h>
+#include <linux/init.h>
+
+#include "em28xx.h"
+
+static unsigned int vbibufs = 5;
+module_param(vbibufs, int, 0644);
+MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
+
+static unsigned int vbi_debug;
+module_param(vbi_debug, int, 0644);
+MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
+
+#define dprintk(level, fmt, arg...)	if (vbi_debug >= level) \
+	printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg)
+
+/* ------------------------------------------------------------------ */
+
+static void
+free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
+{
+	struct em28xx_fh     *fh  = vq->priv_data;
+	struct em28xx        *dev = fh->dev;
+	unsigned long flags = 0;
+	if (in_interrupt())
+		BUG();
+
+	/* We used to wait for the buffer to finish here, but this didn't work
+	   because, as we were keeping the state as VIDEOBUF_QUEUED,
+	   videobuf_queue_cancel marked it as finished for us.
+	   (Also, it could wedge forever if the hardware was misconfigured.)
+
+	   This should be safe; by the time we get here, the buffer isn't
+	   queued anymore. If we ever start marking the buffers as
+	   VIDEOBUF_ACTIVE, it won't be, though.
+	*/
+	spin_lock_irqsave(&dev->slock, flags);
+	if (dev->isoc_ctl.vbi_buf == buf)
+		dev->isoc_ctl.vbi_buf = NULL;
+	spin_unlock_irqrestore(&dev->slock, flags);
+
+	videobuf_vmalloc_free(&buf->vb);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+	struct em28xx_fh     *fh  = q->priv_data;
+	struct em28xx        *dev = fh->dev;
+
+	*size = dev->vbi_width * dev->vbi_height * 2;
+
+	if (0 == *count)
+		*count = vbibufs;
+	if (*count < 2)
+		*count = 2;
+	if (*count > 32)
+		*count = 32;
+	return 0;
+}
+
+static int
+vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+	    enum v4l2_field field)
+{
+	struct em28xx_fh     *fh  = q->priv_data;
+	struct em28xx        *dev = fh->dev;
+	struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+	int                  rc = 0;
+
+	buf->vb.size = dev->vbi_width * dev->vbi_height * 2;
+
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+		return -EINVAL;
+
+	buf->vb.width  = dev->vbi_width;
+	buf->vb.height = dev->vbi_height;
+	buf->vb.field  = field;
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		rc = videobuf_iolock(q, &buf->vb, NULL);
+		if (rc < 0)
+			goto fail;
+	}
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+fail:
+	free_buffer(q, buf);
+	return rc;
+}
+
+static void
+vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct em28xx_buffer    *buf     = container_of(vb,
+							struct em28xx_buffer,
+							vb);
+	struct em28xx_fh        *fh      = vq->priv_data;
+	struct em28xx           *dev     = fh->dev;
+	struct em28xx_dmaqueue  *vbiq    = &dev->vbiq;
+
+	buf->vb.state = VIDEOBUF_QUEUED;
+	list_add_tail(&buf->vb.queue, &vbiq->active);
+}
+
+static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+	free_buffer(q, buf);
+}
+
+struct videobuf_queue_ops em28xx_vbi_qops = {
+	.buf_setup    = vbi_setup,
+	.buf_prepare  = vbi_prepare,
+	.buf_queue    = vbi_queue,
+	.buf_release  = vbi_release,
+};
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
new file mode 100644
index 0000000..78d6ebd
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -0,0 +1,2624 @@
+/*
+   em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
+		    video capture devices
+
+   Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+		      Markus Rechberger <mrechberger@gmail.com>
+		      Mauro Carvalho Chehab <mchehab@infradead.org>
+		      Sascha Sommer <saschasommer@freenet.de>
+
+	Some parts based on SN9C10x PC Camera Controllers GPL driver made
+		by Luca Risolia <luca.risolia@studio.unibo.it>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include "em28xx.h"
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/msp3400.h>
+#include <media/tuner.h>
+
+#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
+		      "Markus Rechberger <mrechberger@gmail.com>, " \
+		      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
+		      "Sascha Sommer <saschasommer@freenet.de>"
+
+#define DRIVER_DESC         "Empia em28xx based USB video device driver"
+
+#define EM28XX_VERSION "0.1.3"
+
+#define em28xx_videodbg(fmt, arg...) do {\
+	if (video_debug) \
+		printk(KERN_INFO "%s %s :"fmt, \
+			 dev->name, __func__ , ##arg); } while (0)
+
+static unsigned int isoc_debug;
+module_param(isoc_debug, int, 0644);
+MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
+
+#define em28xx_isocdbg(fmt, arg...) \
+do {\
+	if (isoc_debug) { \
+		printk(KERN_INFO "%s %s :"fmt, \
+			 dev->name, __func__ , ##arg); \
+	} \
+  } while (0)
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(EM28XX_VERSION);
+
+static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int vbi_nr[]   = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(video_nr, int, NULL, 0444);
+module_param_array(vbi_nr, int, NULL, 0444);
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(video_nr, "video device numbers");
+MODULE_PARM_DESC(vbi_nr,   "vbi device numbers");
+MODULE_PARM_DESC(radio_nr, "radio device numbers");
+
+static unsigned int video_debug;
+module_param(video_debug, int, 0644);
+MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
+
+/* supported video standards */
+static struct em28xx_fmt format[] = {
+	{
+		.name     = "16 bpp YUY2, 4:2:2, packed",
+		.fourcc   = V4L2_PIX_FMT_YUYV,
+		.depth    = 16,
+		.reg	  = EM28XX_OUTFMT_YUV422_Y0UY1V,
+	}, {
+		.name     = "16 bpp RGB 565, LE",
+		.fourcc   = V4L2_PIX_FMT_RGB565,
+		.depth    = 16,
+		.reg      = EM28XX_OUTFMT_RGB_16_656,
+	}, {
+		.name     = "8 bpp Bayer BGBG..GRGR",
+		.fourcc   = V4L2_PIX_FMT_SBGGR8,
+		.depth    = 8,
+		.reg      = EM28XX_OUTFMT_RGB_8_BGBG,
+	}, {
+		.name     = "8 bpp Bayer GRGR..BGBG",
+		.fourcc   = V4L2_PIX_FMT_SGRBG8,
+		.depth    = 8,
+		.reg      = EM28XX_OUTFMT_RGB_8_GRGR,
+	}, {
+		.name     = "8 bpp Bayer GBGB..RGRG",
+		.fourcc   = V4L2_PIX_FMT_SGBRG8,
+		.depth    = 8,
+		.reg      = EM28XX_OUTFMT_RGB_8_GBGB,
+	}, {
+		.name     = "12 bpp YUV411",
+		.fourcc   = V4L2_PIX_FMT_YUV411P,
+		.depth    = 12,
+		.reg      = EM28XX_OUTFMT_YUV411,
+	},
+};
+
+/* supported controls */
+/* Common to all boards */
+static struct v4l2_queryctrl ac97_qctrl[] = {
+	{
+		.id = V4L2_CID_AUDIO_VOLUME,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Volume",
+		.minimum = 0x0,
+		.maximum = 0x1f,
+		.step = 0x1,
+		.default_value = 0x1f,
+		.flags = V4L2_CTRL_FLAG_SLIDER,
+	}, {
+		.id = V4L2_CID_AUDIO_MUTE,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "Mute",
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 1,
+		.flags = 0,
+	}
+};
+
+/* ------------------------------------------------------------------
+	DMA and thread functions
+   ------------------------------------------------------------------*/
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void buffer_filled(struct em28xx *dev,
+				  struct em28xx_dmaqueue *dma_q,
+				  struct em28xx_buffer *buf)
+{
+	/* Advice that buffer was filled */
+	em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+	buf->vb.state = VIDEOBUF_DONE;
+	buf->vb.field_count++;
+	do_gettimeofday(&buf->vb.ts);
+
+	dev->isoc_ctl.vid_buf = NULL;
+
+	list_del(&buf->vb.queue);
+	wake_up(&buf->vb.done);
+}
+
+static inline void vbi_buffer_filled(struct em28xx *dev,
+				     struct em28xx_dmaqueue *dma_q,
+				     struct em28xx_buffer *buf)
+{
+	/* Advice that buffer was filled */
+	em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+
+	buf->vb.state = VIDEOBUF_DONE;
+	buf->vb.field_count++;
+	do_gettimeofday(&buf->vb.ts);
+
+	dev->isoc_ctl.vbi_buf = NULL;
+
+	list_del(&buf->vb.queue);
+	wake_up(&buf->vb.done);
+}
+
+/*
+ * Identify the buffer header type and properly handles
+ */
+static void em28xx_copy_video(struct em28xx *dev,
+			      struct em28xx_dmaqueue  *dma_q,
+			      struct em28xx_buffer *buf,
+			      unsigned char *p,
+			      unsigned char *outp, unsigned long len)
+{
+	void *fieldstart, *startwrite, *startread;
+	int  linesdone, currlinedone, offset, lencopy, remain;
+	int bytesperline = dev->width << 1;
+
+	if (dma_q->pos + len > buf->vb.size)
+		len = buf->vb.size - dma_q->pos;
+
+	startread = p;
+	remain = len;
+
+	if (dev->progressive)
+		fieldstart = outp;
+	else {
+		/* Interlaces two half frames */
+		if (buf->top_field)
+			fieldstart = outp;
+		else
+			fieldstart = outp + bytesperline;
+	}
+
+	linesdone = dma_q->pos / bytesperline;
+	currlinedone = dma_q->pos % bytesperline;
+
+	if (dev->progressive)
+		offset = linesdone * bytesperline + currlinedone;
+	else
+		offset = linesdone * bytesperline * 2 + currlinedone;
+
+	startwrite = fieldstart + offset;
+	lencopy = bytesperline - currlinedone;
+	lencopy = lencopy > remain ? remain : lencopy;
+
+	if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+		em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
+			       ((char *)startwrite + lencopy) -
+			       ((char *)outp + buf->vb.size));
+		remain = (char *)outp + buf->vb.size - (char *)startwrite;
+		lencopy = remain;
+	}
+	if (lencopy <= 0)
+		return;
+	memcpy(startwrite, startread, lencopy);
+
+	remain -= lencopy;
+
+	while (remain > 0) {
+		startwrite += lencopy + bytesperline;
+		startread += lencopy;
+		if (bytesperline > remain)
+			lencopy = remain;
+		else
+			lencopy = bytesperline;
+
+		if ((char *)startwrite + lencopy > (char *)outp +
+		    buf->vb.size) {
+			em28xx_isocdbg("Overflow of %zi bytes past buffer end"
+				       "(2)\n",
+				       ((char *)startwrite + lencopy) -
+				       ((char *)outp + buf->vb.size));
+			lencopy = remain = (char *)outp + buf->vb.size -
+					   (char *)startwrite;
+		}
+		if (lencopy <= 0)
+			break;
+
+		memcpy(startwrite, startread, lencopy);
+
+		remain -= lencopy;
+	}
+
+	dma_q->pos += len;
+}
+
+static void em28xx_copy_vbi(struct em28xx *dev,
+			      struct em28xx_dmaqueue  *dma_q,
+			      struct em28xx_buffer *buf,
+			      unsigned char *p,
+			      unsigned char *outp, unsigned long len)
+{
+	void *startwrite, *startread;
+	int  offset;
+	int bytesperline;
+
+	if (dev == NULL) {
+		em28xx_isocdbg("dev is null\n");
+		return;
+	}
+	bytesperline = dev->vbi_width;
+
+	if (dma_q == NULL) {
+		em28xx_isocdbg("dma_q is null\n");
+		return;
+	}
+	if (buf == NULL) {
+		return;
+	}
+	if (p == NULL) {
+		em28xx_isocdbg("p is null\n");
+		return;
+	}
+	if (outp == NULL) {
+		em28xx_isocdbg("outp is null\n");
+		return;
+	}
+
+	if (dma_q->pos + len > buf->vb.size)
+		len = buf->vb.size - dma_q->pos;
+
+	startread = p;
+
+	startwrite = outp + dma_q->pos;
+	offset = dma_q->pos;
+
+	/* Make sure the bottom field populates the second half of the frame */
+	if (buf->top_field == 0) {
+		startwrite += bytesperline * dev->vbi_height;
+		offset += bytesperline * dev->vbi_height;
+	}
+
+	memcpy(startwrite, startread, len);
+	dma_q->pos += len;
+}
+
+static inline void print_err_status(struct em28xx *dev,
+				     int packet, int status)
+{
+	char *errmsg = "Unknown";
+
+	switch (status) {
+	case -ENOENT:
+		errmsg = "unlinked synchronuously";
+		break;
+	case -ECONNRESET:
+		errmsg = "unlinked asynchronuously";
+		break;
+	case -ENOSR:
+		errmsg = "Buffer error (overrun)";
+		break;
+	case -EPIPE:
+		errmsg = "Stalled (device not responding)";
+		break;
+	case -EOVERFLOW:
+		errmsg = "Babble (bad cable?)";
+		break;
+	case -EPROTO:
+		errmsg = "Bit-stuff error (bad cable?)";
+		break;
+	case -EILSEQ:
+		errmsg = "CRC/Timeout (could be anything)";
+		break;
+	case -ETIME:
+		errmsg = "Device does not respond";
+		break;
+	}
+	if (packet < 0) {
+		em28xx_isocdbg("URB status %d [%s].\n",	status, errmsg);
+	} else {
+		em28xx_isocdbg("URB packet %d, status %d [%s].\n",
+			       packet, status, errmsg);
+	}
+}
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
+					  struct em28xx_buffer **buf)
+{
+	struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
+	char *outp;
+
+	if (list_empty(&dma_q->active)) {
+		em28xx_isocdbg("No active queue to serve\n");
+		dev->isoc_ctl.vid_buf = NULL;
+		*buf = NULL;
+		return;
+	}
+
+	/* Get the next buffer */
+	*buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
+
+	/* Cleans up buffer - Useful for testing for frame/URB loss */
+	outp = videobuf_to_vmalloc(&(*buf)->vb);
+	memset(outp, 0, (*buf)->vb.size);
+
+	dev->isoc_ctl.vid_buf = *buf;
+
+	return;
+}
+
+/*
+ * video-buf generic routine to get the next available VBI buffer
+ */
+static inline void vbi_get_next_buf(struct em28xx_dmaqueue *dma_q,
+				    struct em28xx_buffer **buf)
+{
+	struct em28xx *dev = container_of(dma_q, struct em28xx, vbiq);
+	char *outp;
+
+	if (list_empty(&dma_q->active)) {
+		em28xx_isocdbg("No active queue to serve\n");
+		dev->isoc_ctl.vbi_buf = NULL;
+		*buf = NULL;
+		return;
+	}
+
+	/* Get the next buffer */
+	*buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
+	/* Cleans up buffer - Useful for testing for frame/URB loss */
+	outp = videobuf_to_vmalloc(&(*buf)->vb);
+	memset(outp, 0x00, (*buf)->vb.size);
+
+	dev->isoc_ctl.vbi_buf = *buf;
+
+	return;
+}
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
+{
+	struct em28xx_buffer    *buf;
+	struct em28xx_dmaqueue  *dma_q = &dev->vidq;
+	unsigned char *outp = NULL;
+	int i, len = 0, rc = 1;
+	unsigned char *p;
+
+	if (!dev)
+		return 0;
+
+	if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+		return 0;
+
+	if (urb->status < 0) {
+		print_err_status(dev, -1, urb->status);
+		if (urb->status == -ENOENT)
+			return 0;
+	}
+
+	buf = dev->isoc_ctl.vid_buf;
+	if (buf != NULL)
+		outp = videobuf_to_vmalloc(&buf->vb);
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		int status = urb->iso_frame_desc[i].status;
+
+		if (status < 0) {
+			print_err_status(dev, i, status);
+			if (urb->iso_frame_desc[i].status != -EPROTO)
+				continue;
+		}
+
+		len = urb->iso_frame_desc[i].actual_length - 4;
+
+		if (urb->iso_frame_desc[i].actual_length <= 0) {
+			/* em28xx_isocdbg("packet %d is empty",i); - spammy */
+			continue;
+		}
+		if (urb->iso_frame_desc[i].actual_length >
+						dev->max_pkt_size) {
+			em28xx_isocdbg("packet bigger than packet size");
+			continue;
+		}
+
+		p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+		/* FIXME: incomplete buffer checks where removed to make
+		   logic simpler. Impacts of those changes should be evaluated
+		 */
+		if (p[0] == 0x33 && p[1] == 0x95 && p[2] == 0x00) {
+			em28xx_isocdbg("VBI HEADER!!!\n");
+			/* FIXME: Should add vbi copy */
+			continue;
+		}
+		if (p[0] == 0x22 && p[1] == 0x5a) {
+			em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
+				       len, (p[2] & 1) ? "odd" : "even");
+
+			if (dev->progressive || !(p[2] & 1)) {
+				if (buf != NULL)
+					buffer_filled(dev, dma_q, buf);
+				get_next_buf(dma_q, &buf);
+				if (buf == NULL)
+					outp = NULL;
+				else
+					outp = videobuf_to_vmalloc(&buf->vb);
+			}
+
+			if (buf != NULL) {
+				if (p[2] & 1)
+					buf->top_field = 0;
+				else
+					buf->top_field = 1;
+			}
+
+			dma_q->pos = 0;
+		}
+		if (buf != NULL) {
+			if (p[0] != 0x88 && p[0] != 0x22) {
+				em28xx_isocdbg("frame is not complete\n");
+				len += 4;
+			} else {
+				p += 4;
+			}
+			em28xx_copy_video(dev, dma_q, buf, p, outp, len);
+		}
+	}
+	return rc;
+}
+
+/* Version of isoc handler that takes into account a mixture of video and
+   VBI data */
+static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb)
+{
+	struct em28xx_buffer    *buf, *vbi_buf;
+	struct em28xx_dmaqueue  *dma_q = &dev->vidq;
+	struct em28xx_dmaqueue  *vbi_dma_q = &dev->vbiq;
+	unsigned char *outp = NULL;
+	unsigned char *vbioutp = NULL;
+	int i, len = 0, rc = 1;
+	unsigned char *p;
+	int vbi_size;
+
+	if (!dev)
+		return 0;
+
+	if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+		return 0;
+
+	if (urb->status < 0) {
+		print_err_status(dev, -1, urb->status);
+		if (urb->status == -ENOENT)
+			return 0;
+	}
+
+	buf = dev->isoc_ctl.vid_buf;
+	if (buf != NULL)
+		outp = videobuf_to_vmalloc(&buf->vb);
+
+	vbi_buf = dev->isoc_ctl.vbi_buf;
+	if (vbi_buf != NULL)
+		vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		int status = urb->iso_frame_desc[i].status;
+
+		if (status < 0) {
+			print_err_status(dev, i, status);
+			if (urb->iso_frame_desc[i].status != -EPROTO)
+				continue;
+		}
+
+		len = urb->iso_frame_desc[i].actual_length;
+		if (urb->iso_frame_desc[i].actual_length <= 0) {
+			/* em28xx_isocdbg("packet %d is empty",i); - spammy */
+			continue;
+		}
+		if (urb->iso_frame_desc[i].actual_length >
+						dev->max_pkt_size) {
+			em28xx_isocdbg("packet bigger than packet size");
+			continue;
+		}
+
+		p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+		/* capture type 0 = vbi start
+		   capture type 1 = video start
+		   capture type 2 = video in progress */
+		if (p[0] == 0x33 && p[1] == 0x95) {
+			dev->capture_type = 0;
+			dev->vbi_read = 0;
+			em28xx_isocdbg("VBI START HEADER!!!\n");
+			dev->cur_field = p[2];
+			p += 4;
+			len -= 4;
+		} else if (p[0] == 0x88 && p[1] == 0x88 &&
+			   p[2] == 0x88 && p[3] == 0x88) {
+			/* continuation */
+			p += 4;
+			len -= 4;
+		} else if (p[0] == 0x22 && p[1] == 0x5a) {
+			/* start video */
+			p += 4;
+			len -= 4;
+		}
+
+		vbi_size = dev->vbi_width * dev->vbi_height;
+
+		if (dev->capture_type == 0) {
+			if (dev->vbi_read >= vbi_size) {
+				/* We've already read all the VBI data, so
+				   treat the rest as video */
+				em28xx_isocdbg("dev->vbi_read > vbi_size\n");
+			} else if ((dev->vbi_read + len) < vbi_size) {
+				/* This entire frame is VBI data */
+				if (dev->vbi_read == 0 &&
+				    (!(dev->cur_field & 1))) {
+					/* Brand new frame */
+					if (vbi_buf != NULL)
+						vbi_buffer_filled(dev,
+								  vbi_dma_q,
+								  vbi_buf);
+					vbi_get_next_buf(vbi_dma_q, &vbi_buf);
+					if (vbi_buf == NULL)
+						vbioutp = NULL;
+					else
+						vbioutp = videobuf_to_vmalloc(
+							&vbi_buf->vb);
+				}
+
+				if (dev->vbi_read == 0) {
+					vbi_dma_q->pos = 0;
+					if (vbi_buf != NULL) {
+						if (dev->cur_field & 1)
+							vbi_buf->top_field = 0;
+						else
+							vbi_buf->top_field = 1;
+					}
+				}
+
+				dev->vbi_read += len;
+				em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
+						vbioutp, len);
+			} else {
+				/* Some of this frame is VBI data and some is
+				   video data */
+				int vbi_data_len = vbi_size - dev->vbi_read;
+				dev->vbi_read += vbi_data_len;
+				em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
+						vbioutp, vbi_data_len);
+				dev->capture_type = 1;
+				p += vbi_data_len;
+				len -= vbi_data_len;
+			}
+		}
+
+		if (dev->capture_type == 1) {
+			dev->capture_type = 2;
+			if (dev->progressive || !(dev->cur_field & 1)) {
+				if (buf != NULL)
+					buffer_filled(dev, dma_q, buf);
+				get_next_buf(dma_q, &buf);
+				if (buf == NULL)
+					outp = NULL;
+				else
+					outp = videobuf_to_vmalloc(&buf->vb);
+			}
+			if (buf != NULL) {
+				if (dev->cur_field & 1)
+					buf->top_field = 0;
+				else
+					buf->top_field = 1;
+			}
+
+			dma_q->pos = 0;
+		}
+
+		if (buf != NULL && dev->capture_type == 2) {
+			if (len >= 4 && p[0] == 0x88 && p[1] == 0x88 &&
+			    p[2] == 0x88 && p[3] == 0x88) {
+				p += 4;
+				len -= 4;
+			}
+			if (len >= 4 && p[0] == 0x22 && p[1] == 0x5a) {
+				em28xx_isocdbg("Video frame %d, len=%i, %s\n",
+					       p[2], len, (p[2] & 1) ?
+					       "odd" : "even");
+				p += 4;
+				len -= 4;
+			}
+
+			if (len > 0)
+				em28xx_copy_video(dev, dma_q, buf, p, outp,
+						  len);
+		}
+	}
+	return rc;
+}
+
+
+/* ------------------------------------------------------------------
+	Videobuf operations
+   ------------------------------------------------------------------*/
+
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+{
+	struct em28xx_fh *fh = vq->priv_data;
+	struct em28xx        *dev = fh->dev;
+	struct v4l2_frequency f;
+
+	*size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)
+		>> 3;
+
+	if (0 == *count)
+		*count = EM28XX_DEF_BUF;
+
+	if (*count < EM28XX_MIN_BUF)
+		*count = EM28XX_MIN_BUF;
+
+	/* Ask tuner to go to analog or radio mode */
+	memset(&f, 0, sizeof(f));
+	f.frequency = dev->ctl_freq;
+	f.type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+
+	return 0;
+}
+
+/* This is called *without* dev->slock held; please keep it that way */
+static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
+{
+	struct em28xx_fh     *fh  = vq->priv_data;
+	struct em28xx        *dev = fh->dev;
+	unsigned long flags = 0;
+	if (in_interrupt())
+		BUG();
+
+	/* We used to wait for the buffer to finish here, but this didn't work
+	   because, as we were keeping the state as VIDEOBUF_QUEUED,
+	   videobuf_queue_cancel marked it as finished for us.
+	   (Also, it could wedge forever if the hardware was misconfigured.)
+
+	   This should be safe; by the time we get here, the buffer isn't
+	   queued anymore. If we ever start marking the buffers as
+	   VIDEOBUF_ACTIVE, it won't be, though.
+	*/
+	spin_lock_irqsave(&dev->slock, flags);
+	if (dev->isoc_ctl.vid_buf == buf)
+		dev->isoc_ctl.vid_buf = NULL;
+	spin_unlock_irqrestore(&dev->slock, flags);
+
+	videobuf_vmalloc_free(&buf->vb);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+						enum v4l2_field field)
+{
+	struct em28xx_fh     *fh  = vq->priv_data;
+	struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+	struct em28xx        *dev = fh->dev;
+	int                  rc = 0, urb_init = 0;
+
+	buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth
+			+ 7) >> 3;
+
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+		return -EINVAL;
+
+	buf->vb.width  = dev->width;
+	buf->vb.height = dev->height;
+	buf->vb.field  = field;
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		rc = videobuf_iolock(vq, &buf->vb, NULL);
+		if (rc < 0)
+			goto fail;
+	}
+
+	if (!dev->isoc_ctl.analog_bufs.num_bufs)
+		urb_init = 1;
+
+	if (urb_init) {
+		if (em28xx_vbi_supported(dev) == 1)
+			rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE,
+					      EM28XX_NUM_PACKETS,
+					      EM28XX_NUM_BUFS,
+					      dev->max_pkt_size,
+					      em28xx_isoc_copy_vbi);
+		else
+			rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE,
+					      EM28XX_NUM_PACKETS,
+					      EM28XX_NUM_BUFS,
+					      dev->max_pkt_size,
+					      em28xx_isoc_copy);
+		if (rc < 0)
+			goto fail;
+	}
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+fail:
+	free_buffer(vq, buf);
+	return rc;
+}
+
+static void
+buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct em28xx_buffer    *buf     = container_of(vb,
+							struct em28xx_buffer,
+							vb);
+	struct em28xx_fh        *fh      = vq->priv_data;
+	struct em28xx           *dev     = fh->dev;
+	struct em28xx_dmaqueue  *vidq    = &dev->vidq;
+
+	buf->vb.state = VIDEOBUF_QUEUED;
+	list_add_tail(&buf->vb.queue, &vidq->active);
+
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+				struct videobuf_buffer *vb)
+{
+	struct em28xx_buffer   *buf  = container_of(vb,
+						    struct em28xx_buffer,
+						    vb);
+	struct em28xx_fh       *fh   = vq->priv_data;
+	struct em28xx          *dev  = (struct em28xx *)fh->dev;
+
+	em28xx_isocdbg("em28xx: called buffer_release\n");
+
+	free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops em28xx_video_qops = {
+	.buf_setup      = buffer_setup,
+	.buf_prepare    = buffer_prepare,
+	.buf_queue      = buffer_queue,
+	.buf_release    = buffer_release,
+};
+
+/*********************  v4l2 interface  **************************************/
+
+static void video_mux(struct em28xx *dev, int index)
+{
+	dev->ctl_input = index;
+	dev->ctl_ainput = INPUT(index)->amux;
+	dev->ctl_aoutput = INPUT(index)->aout;
+
+	if (!dev->ctl_aoutput)
+		dev->ctl_aoutput = EM28XX_AOUT_MASTER;
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
+			INPUT(index)->vmux, 0, 0);
+
+	if (dev->board.has_msp34xx) {
+		if (dev->i2s_speed) {
+			v4l2_device_call_all(&dev->v4l2_dev, 0, audio,
+				s_i2s_clock_freq, dev->i2s_speed);
+		}
+		/* Note: this is msp3400 specific */
+		v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
+			 dev->ctl_ainput, MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0);
+	}
+
+	if (dev->board.adecoder != EM28XX_NOADECODER) {
+		v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
+			dev->ctl_ainput, dev->ctl_aoutput, 0);
+	}
+
+	em28xx_audio_analog_set(dev);
+}
+
+/* Usage lock check functions */
+static int res_get(struct em28xx_fh *fh, unsigned int bit)
+{
+	struct em28xx    *dev = fh->dev;
+
+	if (fh->resources & bit)
+		/* have it already allocated */
+		return 1;
+
+	/* is it free? */
+	if (dev->resources & bit) {
+		/* no, someone else uses it */
+		return 0;
+	}
+	/* it's free, grab it */
+	fh->resources  |= bit;
+	dev->resources |= bit;
+	em28xx_videodbg("res: get %d\n", bit);
+	return 1;
+}
+
+static int res_check(struct em28xx_fh *fh, unsigned int bit)
+{
+	return fh->resources & bit;
+}
+
+static int res_locked(struct em28xx *dev, unsigned int bit)
+{
+	return dev->resources & bit;
+}
+
+static void res_free(struct em28xx_fh *fh, unsigned int bits)
+{
+	struct em28xx    *dev = fh->dev;
+
+	BUG_ON((fh->resources & bits) != bits);
+
+	fh->resources  &= ~bits;
+	dev->resources &= ~bits;
+	em28xx_videodbg("res: put %d\n", bits);
+}
+
+static int get_ressource(struct em28xx_fh *fh)
+{
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return EM28XX_RESOURCE_VIDEO;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		return EM28XX_RESOURCE_VBI;
+	default:
+		BUG();
+		return 0;
+	}
+}
+
+/*
+ * ac97_queryctrl()
+ * return the ac97 supported controls
+ */
+static int ac97_queryctrl(struct v4l2_queryctrl *qc)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
+		if (qc->id && qc->id == ac97_qctrl[i].id) {
+			memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
+			return 0;
+		}
+	}
+
+	/* Control is not ac97 related */
+	return 1;
+}
+
+/*
+ * ac97_get_ctrl()
+ * return the current values for ac97 mute and volume
+ */
+static int ac97_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
+{
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		ctrl->value = dev->mute;
+		return 0;
+	case V4L2_CID_AUDIO_VOLUME:
+		ctrl->value = dev->volume;
+		return 0;
+	default:
+		/* Control is not ac97 related */
+		return 1;
+	}
+}
+
+/*
+ * ac97_set_ctrl()
+ * set values for ac97 mute and volume
+ */
+static int ac97_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++)
+		if (ctrl->id == ac97_qctrl[i].id)
+			goto handle;
+
+	/* Announce that hasn't handle it */
+	return 1;
+
+handle:
+	if (ctrl->value < ac97_qctrl[i].minimum ||
+	    ctrl->value > ac97_qctrl[i].maximum)
+		return -ERANGE;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		dev->mute = ctrl->value;
+		break;
+	case V4L2_CID_AUDIO_VOLUME:
+		dev->volume = ctrl->value;
+		break;
+	}
+
+	return em28xx_audio_analog_set(dev);
+}
+
+static int check_dev(struct em28xx *dev)
+{
+	if (dev->state & DEV_DISCONNECTED) {
+		em28xx_errdev("v4l2 ioctl: device not present\n");
+		return -ENODEV;
+	}
+
+	if (dev->state & DEV_MISCONFIGURED) {
+		em28xx_errdev("v4l2 ioctl: device is misconfigured; "
+			      "close and open it again\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static void get_scale(struct em28xx *dev,
+			unsigned int width, unsigned int height,
+			unsigned int *hscale, unsigned int *vscale)
+{
+	unsigned int          maxw = norm_maxw(dev);
+	unsigned int          maxh = norm_maxh(dev);
+
+	*hscale = (((unsigned long)maxw) << 12) / width - 4096L;
+	if (*hscale >= 0x4000)
+		*hscale = 0x3fff;
+
+	*vscale = (((unsigned long)maxh) << 12) / height - 4096L;
+	if (*vscale >= 0x4000)
+		*vscale = 0x3fff;
+}
+
+/* ------------------------------------------------------------------
+	IOCTL vidioc handling
+   ------------------------------------------------------------------*/
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+
+	f->fmt.pix.width = dev->width;
+	f->fmt.pix.height = dev->height;
+	f->fmt.pix.pixelformat = dev->format->fourcc;
+	f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
+	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline  * dev->height;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+	/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
+	if (dev->progressive)
+		f->fmt.pix.field = V4L2_FIELD_NONE;
+	else
+		f->fmt.pix.field = dev->interlaced ?
+			   V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
+	return 0;
+}
+
+static struct em28xx_fmt *format_by_fourcc(unsigned int fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(format); i++)
+		if (format[i].fourcc == fourcc)
+			return &format[i];
+
+	return NULL;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct em28xx_fh      *fh    = priv;
+	struct em28xx         *dev   = fh->dev;
+	unsigned int          width  = f->fmt.pix.width;
+	unsigned int          height = f->fmt.pix.height;
+	unsigned int          maxw   = norm_maxw(dev);
+	unsigned int          maxh   = norm_maxh(dev);
+	unsigned int          hscale, vscale;
+	struct em28xx_fmt     *fmt;
+
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	if (!fmt) {
+		em28xx_videodbg("Fourcc format (%08x) invalid.\n",
+				f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	if (dev->board.is_em2800) {
+		/* the em2800 can only scale down to 50% */
+		height = height > (3 * maxh / 4) ? maxh : maxh / 2;
+		width = width > (3 * maxw / 4) ? maxw : maxw / 2;
+                /* MaxPacketSize for em2800 is too small to capture at full resolution
+                 * use half of maxw as the scaler can only scale to 50% */
+		if (width == maxw && height == maxh)
+			width /= 2;
+	} else {
+		/* width must even because of the YUYV format
+		   height must be even because of interlacing */
+		v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh,
+				      1, 0);
+	}
+
+	get_scale(dev, width, height, &hscale, &vscale);
+
+	width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+	height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+
+	f->fmt.pix.width = width;
+	f->fmt.pix.height = height;
+	f->fmt.pix.pixelformat = fmt->fourcc;
+	f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
+	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	if (dev->progressive)
+		f->fmt.pix.field = V4L2_FIELD_NONE;
+	else
+		f->fmt.pix.field = dev->interlaced ?
+			   V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
+
+	return 0;
+}
+
+static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
+				   unsigned width, unsigned height)
+{
+	struct em28xx_fmt     *fmt;
+
+	fmt = format_by_fourcc(fourcc);
+	if (!fmt)
+		return -EINVAL;
+
+	dev->format = fmt;
+	dev->width  = width;
+	dev->height = height;
+
+	/* set new image size */
+	get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+
+	em28xx_set_alternate(dev);
+	em28xx_resolution_set(dev);
+
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	vidioc_try_fmt_vid_cap(file, priv, f);
+
+	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+		em28xx_errdev("%s queue busy\n", __func__);
+		return -EBUSY;
+	}
+
+	return em28xx_set_video_format(dev, f->fmt.pix.pixelformat,
+				f->fmt.pix.width, f->fmt.pix.height);
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+	struct em28xx_fh   *fh  = priv;
+	struct em28xx      *dev = fh->dev;
+	int                rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	*norm = dev->norm;
+
+	return 0;
+}
+
+static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
+{
+	struct em28xx_fh   *fh  = priv;
+	struct em28xx      *dev = fh->dev;
+	int                rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, video, querystd, norm);
+
+	return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+	struct em28xx_fh   *fh  = priv;
+	struct em28xx      *dev = fh->dev;
+	struct v4l2_format f;
+	int                rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	dev->norm = *norm;
+
+	/* Adjusts width/height, if needed */
+	f.fmt.pix.width = dev->width;
+	f.fmt.pix.height = dev->height;
+	vidioc_try_fmt_vid_cap(file, priv, &f);
+
+	/* set new image size */
+	dev->width = f.fmt.pix.width;
+	dev->height = f.fmt.pix.height;
+	get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+
+	em28xx_resolution_set(dev);
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
+
+	return 0;
+}
+
+static int vidioc_g_parm(struct file *file, void *priv,
+			 struct v4l2_streamparm *p)
+{
+	struct em28xx_fh   *fh  = priv;
+	struct em28xx      *dev = fh->dev;
+	int rc = 0;
+
+	if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (dev->board.is_webcam)
+		rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0,
+						video, g_parm, p);
+	else
+		v4l2_video_std_frame_period(dev->norm,
+						 &p->parm.capture.timeperframe);
+
+	return rc;
+}
+
+static int vidioc_s_parm(struct file *file, void *priv,
+			 struct v4l2_streamparm *p)
+{
+	struct em28xx_fh   *fh  = priv;
+	struct em28xx      *dev = fh->dev;
+
+	if (!dev->board.is_webcam)
+		return -EINVAL;
+
+	if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	return v4l2_device_call_until_err(&dev->v4l2_dev, 0, video, s_parm, p);
+}
+
+static const char *iname[] = {
+	[EM28XX_VMUX_COMPOSITE1] = "Composite1",
+	[EM28XX_VMUX_COMPOSITE2] = "Composite2",
+	[EM28XX_VMUX_COMPOSITE3] = "Composite3",
+	[EM28XX_VMUX_COMPOSITE4] = "Composite4",
+	[EM28XX_VMUX_SVIDEO]     = "S-Video",
+	[EM28XX_VMUX_TELEVISION] = "Television",
+	[EM28XX_VMUX_CABLE]      = "Cable TV",
+	[EM28XX_VMUX_DVB]        = "DVB",
+	[EM28XX_VMUX_DEBUG]      = "for debug only",
+};
+
+static int vidioc_enum_input(struct file *file, void *priv,
+				struct v4l2_input *i)
+{
+	struct em28xx_fh   *fh  = priv;
+	struct em28xx      *dev = fh->dev;
+	unsigned int       n;
+
+	n = i->index;
+	if (n >= MAX_EM28XX_INPUT)
+		return -EINVAL;
+	if (0 == INPUT(n)->type)
+		return -EINVAL;
+
+	i->index = n;
+	i->type = V4L2_INPUT_TYPE_CAMERA;
+
+	strcpy(i->name, iname[INPUT(n)->type]);
+
+	if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
+		(EM28XX_VMUX_CABLE == INPUT(n)->type))
+		i->type = V4L2_INPUT_TYPE_TUNER;
+
+	i->std = dev->vdev->tvnorms;
+
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct em28xx_fh   *fh  = priv;
+	struct em28xx      *dev = fh->dev;
+
+	*i = dev->ctl_input;
+
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct em28xx_fh   *fh  = priv;
+	struct em28xx      *dev = fh->dev;
+	int                rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (i >= MAX_EM28XX_INPUT)
+		return -EINVAL;
+	if (0 == INPUT(i)->type)
+		return -EINVAL;
+
+	video_mux(dev, i);
+	return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	struct em28xx_fh   *fh    = priv;
+	struct em28xx      *dev   = fh->dev;
+
+	if (!dev->audio_mode.has_audio)
+		return -EINVAL;
+
+	switch (a->index) {
+	case EM28XX_AMUX_VIDEO:
+		strcpy(a->name, "Television");
+		break;
+	case EM28XX_AMUX_LINE_IN:
+		strcpy(a->name, "Line In");
+		break;
+	case EM28XX_AMUX_VIDEO2:
+		strcpy(a->name, "Television alt");
+		break;
+	case EM28XX_AMUX_PHONE:
+		strcpy(a->name, "Phone");
+		break;
+	case EM28XX_AMUX_MIC:
+		strcpy(a->name, "Mic");
+		break;
+	case EM28XX_AMUX_CD:
+		strcpy(a->name, "CD");
+		break;
+	case EM28XX_AMUX_AUX:
+		strcpy(a->name, "Aux");
+		break;
+	case EM28XX_AMUX_PCM_OUT:
+		strcpy(a->name, "PCM");
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	a->index = dev->ctl_ainput;
+	a->capability = V4L2_AUDCAP_STEREO;
+
+	return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	struct em28xx_fh   *fh  = priv;
+	struct em28xx      *dev = fh->dev;
+
+
+	if (!dev->audio_mode.has_audio)
+		return -EINVAL;
+
+	if (a->index >= MAX_EM28XX_INPUT)
+		return -EINVAL;
+	if (0 == INPUT(a->index)->type)
+		return -EINVAL;
+
+	dev->ctl_ainput = INPUT(a->index)->amux;
+	dev->ctl_aoutput = INPUT(a->index)->aout;
+
+	if (!dev->ctl_aoutput)
+		dev->ctl_aoutput = EM28XX_AOUT_MASTER;
+
+	return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+				struct v4l2_queryctrl *qc)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   id  = qc->id;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	memset(qc, 0, sizeof(*qc));
+
+	qc->id = id;
+
+	/* enumerate AC97 controls */
+	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+		rc = ac97_queryctrl(qc);
+		if (!rc)
+			return 0;
+	}
+
+	/* enumerate V4L2 device controls */
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
+
+	if (qc->type)
+		return 0;
+	else
+		return -EINVAL;
+}
+
+/*
+ * FIXME: This is an indirect way to check if a control exists at a
+ * subdev. Instead of that hack, maybe the better would be to change all
+ * subdevs to return -ENOIOCTLCMD, if an ioctl is not supported.
+ */
+static int check_subdev_ctrl(struct em28xx *dev, int id)
+{
+	struct v4l2_queryctrl qc;
+
+	memset(&qc, 0, sizeof(qc));
+	qc.id = id;
+
+	/* enumerate V4L2 device controls */
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, &qc);
+
+	if (qc.type)
+		return 0;
+	else
+		return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+	rc = 0;
+
+	/* Set an AC97 control */
+	if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
+		rc = ac97_get_ctrl(dev, ctrl);
+	else
+		rc = 1;
+
+	/* It were not an AC97 control. Sends it to the v4l2 dev interface */
+	if (rc == 1) {
+		if (check_subdev_ctrl(dev, ctrl->id))
+			return -EINVAL;
+
+		v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
+		rc = 0;
+	}
+
+	return rc;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	/* Set an AC97 control */
+	if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
+		rc = ac97_set_ctrl(dev, ctrl);
+	else
+		rc = 1;
+
+	/* It isn't an AC97 control. Sends it to the v4l2 dev interface */
+	if (rc == 1) {
+		rc = check_subdev_ctrl(dev, ctrl->id);
+		if (!rc)
+			v4l2_device_call_all(&dev->v4l2_dev, 0,
+					     core, s_ctrl, ctrl);
+		/*
+		 * In the case of non-AC97 volume controls, we still need
+		 * to do some setups at em28xx, in order to mute/unmute
+		 * and to adjust audio volume. However, the value ranges
+		 * should be checked by the corresponding V4L subdriver.
+		 */
+		switch (ctrl->id) {
+		case V4L2_CID_AUDIO_MUTE:
+			dev->mute = ctrl->value;
+			rc = em28xx_audio_analog_set(dev);
+			break;
+		case V4L2_CID_AUDIO_VOLUME:
+			dev->volume = ctrl->value;
+			rc = em28xx_audio_analog_set(dev);
+		}
+	}
+	return (rc < 0) ? rc : 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (0 != t->index)
+		return -EINVAL;
+
+	strcpy(t->name, "Tuner");
+	t->type = V4L2_TUNER_ANALOG_TV;
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+	return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (0 != t->index)
+		return -EINVAL;
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+	return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+
+	f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+	f->frequency = dev->ctl_freq;
+	return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (0 != f->tuner)
+		return -EINVAL;
+
+	if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
+		return -EINVAL;
+	if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
+		return -EINVAL;
+
+	dev->ctl_freq = f->frequency;
+	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int em28xx_reg_len(int reg)
+{
+	switch (reg) {
+	case EM28XX_R40_AC97LSB:
+	case EM28XX_R30_HSCALELOW:
+	case EM28XX_R32_VSCALELOW:
+		return 2;
+	default:
+		return 1;
+	}
+}
+
+static int vidioc_g_chip_ident(struct file *file, void *priv,
+	       struct v4l2_dbg_chip_ident *chip)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+
+	chip->ident = V4L2_IDENT_NONE;
+	chip->revision = 0;
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
+
+	return 0;
+}
+
+
+static int vidioc_g_register(struct file *file, void *priv,
+			     struct v4l2_dbg_register *reg)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int ret;
+
+	switch (reg->match.type) {
+	case V4L2_CHIP_MATCH_AC97:
+		ret = em28xx_read_ac97(dev, reg->reg);
+		if (ret < 0)
+			return ret;
+
+		reg->val = ret;
+		reg->size = 1;
+		return 0;
+	case V4L2_CHIP_MATCH_I2C_DRIVER:
+		v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
+		return 0;
+	case V4L2_CHIP_MATCH_I2C_ADDR:
+		/* TODO: is this correct? */
+		v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
+		return 0;
+	default:
+		if (!v4l2_chip_match_host(&reg->match))
+			return -EINVAL;
+	}
+
+	/* Match host */
+	reg->size = em28xx_reg_len(reg->reg);
+	if (reg->size == 1) {
+		ret = em28xx_read_reg(dev, reg->reg);
+
+		if (ret < 0)
+			return ret;
+
+		reg->val = ret;
+	} else {
+		__le16 val = 0;
+		ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
+						   reg->reg, (char *)&val, 2);
+		if (ret < 0)
+			return ret;
+
+		reg->val = le16_to_cpu(val);
+	}
+
+	return 0;
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+			     struct v4l2_dbg_register *reg)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	__le16 buf;
+
+	switch (reg->match.type) {
+	case V4L2_CHIP_MATCH_AC97:
+		return em28xx_write_ac97(dev, reg->reg, reg->val);
+	case V4L2_CHIP_MATCH_I2C_DRIVER:
+		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
+		return 0;
+	case V4L2_CHIP_MATCH_I2C_ADDR:
+		/* TODO: is this correct? */
+		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
+		return 0;
+	default:
+		if (!v4l2_chip_match_host(&reg->match))
+			return -EINVAL;
+	}
+
+	/* Match host */
+	buf = cpu_to_le16(reg->val);
+
+	return em28xx_write_regs(dev, reg->reg, (char *)&buf,
+			       em28xx_reg_len(reg->reg));
+}
+#endif
+
+
+static int vidioc_cropcap(struct file *file, void *priv,
+					struct v4l2_cropcap *cc)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+
+	if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	cc->bounds.left = 0;
+	cc->bounds.top = 0;
+	cc->bounds.width = dev->width;
+	cc->bounds.height = dev->height;
+	cc->defrect = cc->bounds;
+	cc->pixelaspect.numerator = 54;	/* 4:3 FIXME: remove magic numbers */
+	cc->pixelaspect.denominator = 59;
+
+	return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc = -EINVAL;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (unlikely(type != fh->type))
+		return -EINVAL;
+
+	em28xx_videodbg("vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
+			fh, type, fh->resources, dev->resources);
+
+	if (unlikely(!res_get(fh, get_ressource(fh))))
+		return -EBUSY;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		rc = videobuf_streamon(&fh->vb_vidq);
+	else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		rc = videobuf_streamon(&fh->vb_vbiq);
+
+	return rc;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
+		return -EINVAL;
+	if (type != fh->type)
+		return -EINVAL;
+
+	em28xx_videodbg("vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
+			fh, type, fh->resources, dev->resources);
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
+			videobuf_streamoff(&fh->vb_vidq);
+			res_free(fh, EM28XX_RESOURCE_VIDEO);
+		}
+	} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+		if (res_check(fh, EM28XX_RESOURCE_VBI)) {
+			videobuf_streamoff(&fh->vb_vbiq);
+			res_free(fh, EM28XX_RESOURCE_VBI);
+		}
+	}
+
+	return 0;
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *cap)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+
+	strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
+	strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
+	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+
+	cap->capabilities =
+			V4L2_CAP_SLICED_VBI_CAPTURE |
+			V4L2_CAP_VIDEO_CAPTURE |
+			V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+
+	if (dev->vbi_dev)
+		cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
+
+	if (dev->audio_mode.has_audio)
+		cap->capabilities |= V4L2_CAP_AUDIO;
+
+	if (dev->tuner_type != TUNER_ABSENT)
+		cap->capabilities |= V4L2_CAP_TUNER;
+
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	if (unlikely(f->index >= ARRAY_SIZE(format)))
+		return -EINVAL;
+
+	strlcpy(f->description, format[f->index].name, sizeof(f->description));
+	f->pixelformat = format[f->index].fourcc;
+
+	return 0;
+}
+
+static int vidioc_enum_framesizes(struct file *file, void *priv,
+				  struct v4l2_frmsizeenum *fsize)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	struct em28xx_fmt     *fmt;
+	unsigned int	      maxw = norm_maxw(dev);
+	unsigned int	      maxh = norm_maxh(dev);
+
+	fmt = format_by_fourcc(fsize->pixel_format);
+	if (!fmt) {
+		em28xx_videodbg("Fourcc format (%08x) invalid.\n",
+				fsize->pixel_format);
+		return -EINVAL;
+	}
+
+	if (dev->board.is_em2800) {
+		if (fsize->index > 1)
+			return -EINVAL;
+		fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+		fsize->discrete.width = maxw / (1 + fsize->index);
+		fsize->discrete.height = maxh / (1 + fsize->index);
+		return 0;
+	}
+
+	if (fsize->index != 0)
+		return -EINVAL;
+
+	/* Report a continuous range */
+	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+	fsize->stepwise.min_width = 48;
+	fsize->stepwise.min_height = 32;
+	fsize->stepwise.max_width = maxw;
+	fsize->stepwise.max_height = maxh;
+	fsize->stepwise.step_width = 1;
+	fsize->stepwise.step_height = 1;
+	return 0;
+}
+
+/* Sliced VBI ioctls */
+static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	f->fmt.sliced.service_set = 0;
+	v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced);
+
+	if (f->fmt.sliced.service_set == 0)
+		rc = -EINVAL;
+
+	return rc;
+}
+
+static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced);
+
+	if (f->fmt.sliced.service_set == 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+/* RAW VBI ioctls */
+
+static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+				struct v4l2_format *format)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+
+	format->fmt.vbi.samples_per_line = dev->vbi_width;
+	format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+	format->fmt.vbi.offset = 0;
+	format->fmt.vbi.flags = 0;
+	format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
+	format->fmt.vbi.count[0] = dev->vbi_height;
+	format->fmt.vbi.count[1] = dev->vbi_height;
+
+	/* Varies by video standard (NTSC, PAL, etc.) */
+	if (dev->norm & V4L2_STD_525_60) {
+		/* NTSC */
+		format->fmt.vbi.start[0] = 10;
+		format->fmt.vbi.start[1] = 273;
+	} else if (dev->norm & V4L2_STD_625_50) {
+		/* PAL */
+		format->fmt.vbi.start[0] = 6;
+		format->fmt.vbi.start[1] = 318;
+	}
+
+	return 0;
+}
+
+static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
+				struct v4l2_format *format)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+
+	format->fmt.vbi.samples_per_line = dev->vbi_width;
+	format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+	format->fmt.vbi.offset = 0;
+	format->fmt.vbi.flags = 0;
+	format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
+	format->fmt.vbi.count[0] = dev->vbi_height;
+	format->fmt.vbi.count[1] = dev->vbi_height;
+
+	/* Varies by video standard (NTSC, PAL, etc.) */
+	if (dev->norm & V4L2_STD_525_60) {
+		/* NTSC */
+		format->fmt.vbi.start[0] = 10;
+		format->fmt.vbi.start[1] = 273;
+	} else if (dev->norm & V4L2_STD_625_50) {
+		/* PAL */
+		format->fmt.vbi.start[0] = 6;
+		format->fmt.vbi.start[1] = 318;
+	}
+
+	return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *rb)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return videobuf_reqbufs(&fh->vb_vidq, rb);
+	else
+		return videobuf_reqbufs(&fh->vb_vbiq, rb);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+			   struct v4l2_buffer *b)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return videobuf_querybuf(&fh->vb_vidq, b);
+	else {
+		/* FIXME: I'm not sure yet whether this is a bug in zvbi or
+		   the videobuf framework, but we probably shouldn't be
+		   returning a buffer larger than that which was asked for.
+		   At a minimum, it causes a crash in zvbi since it does
+		   a memcpy based on the source buffer length */
+		int result = videobuf_querybuf(&fh->vb_vbiq, b);
+		b->length = dev->vbi_width * dev->vbi_height * 2;
+
+		return result;
+	}
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return videobuf_qbuf(&fh->vb_vidq, b);
+	else
+		return videobuf_qbuf(&fh->vb_vbiq, b);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags &
+				      O_NONBLOCK);
+	else
+		return videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags &
+				      O_NONBLOCK);
+}
+
+/* ----------------------------------------------------------- */
+/* RADIO ESPECIFIC IOCTLS                                      */
+/* ----------------------------------------------------------- */
+
+static int radio_querycap(struct file *file, void  *priv,
+			  struct v4l2_capability *cap)
+{
+	struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
+
+	strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
+	strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
+	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+
+	cap->capabilities = V4L2_CAP_TUNER;
+	return 0;
+}
+
+static int radio_g_tuner(struct file *file, void *priv,
+			 struct v4l2_tuner *t)
+{
+	struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
+
+	if (unlikely(t->index > 0))
+		return -EINVAL;
+
+	strcpy(t->name, "Radio");
+	t->type = V4L2_TUNER_RADIO;
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+
+	return 0;
+}
+
+static int radio_enum_input(struct file *file, void *priv,
+			    struct v4l2_input *i)
+{
+	if (i->index != 0)
+		return -EINVAL;
+	strcpy(i->name, "Radio");
+	i->type = V4L2_INPUT_TYPE_TUNER;
+
+	return 0;
+}
+
+static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	if (unlikely(a->index))
+		return -EINVAL;
+
+	strcpy(a->name, "Radio");
+	return 0;
+}
+
+static int radio_s_tuner(struct file *file, void *priv,
+			 struct v4l2_tuner *t)
+{
+	struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
+
+	if (0 != t->index)
+		return -EINVAL;
+
+	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+
+	return 0;
+}
+
+static int radio_s_audio(struct file *file, void *fh,
+			 struct v4l2_audio *a)
+{
+	return 0;
+}
+
+static int radio_s_input(struct file *file, void *fh, unsigned int i)
+{
+	return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+			   struct v4l2_queryctrl *qc)
+{
+	int i;
+
+	if (qc->id <  V4L2_CID_BASE ||
+		qc->id >= V4L2_CID_LASTP1)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
+		if (qc->id && qc->id == ac97_qctrl[i].id) {
+			memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+/*
+ * em28xx_v4l2_open()
+ * inits the device and starts isoc transfer
+ */
+static int em28xx_v4l2_open(struct file *filp)
+{
+	int errCode = 0, radio = 0;
+	struct video_device *vdev = video_devdata(filp);
+	struct em28xx *dev = video_drvdata(filp);
+	enum v4l2_buf_type fh_type = 0;
+	struct em28xx_fh *fh;
+	enum v4l2_field field;
+
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_GRABBER:
+		fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		break;
+	case VFL_TYPE_VBI:
+		fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
+		break;
+	case VFL_TYPE_RADIO:
+		radio = 1;
+		break;
+	}
+
+	em28xx_videodbg("open dev=%s type=%s users=%d\n",
+			video_device_node_name(vdev), v4l2_type_names[fh_type],
+			dev->users);
+
+
+	if (mutex_lock_interruptible(&dev->lock))
+		return -ERESTARTSYS;
+	fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
+	if (!fh) {
+		em28xx_errdev("em28xx-video.c: Out of memory?!\n");
+		mutex_unlock(&dev->lock);
+		return -ENOMEM;
+	}
+	fh->dev = dev;
+	fh->radio = radio;
+	fh->type = fh_type;
+	filp->private_data = fh;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+		em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
+		em28xx_set_alternate(dev);
+		em28xx_resolution_set(dev);
+
+		/* Needed, since GPIO might have disabled power of
+		   some i2c device
+		 */
+		em28xx_wake_i2c(dev);
+
+	}
+	if (fh->radio) {
+		em28xx_videodbg("video_open: setting radio device\n");
+		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
+	}
+
+	dev->users++;
+
+	if (dev->progressive)
+		field = V4L2_FIELD_NONE;
+	else
+		field = V4L2_FIELD_INTERLACED;
+
+	videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
+				    NULL, &dev->slock,
+				    V4L2_BUF_TYPE_VIDEO_CAPTURE, field,
+				    sizeof(struct em28xx_buffer), fh, &dev->lock);
+
+	videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops,
+				    NULL, &dev->slock,
+				    V4L2_BUF_TYPE_VBI_CAPTURE,
+				    V4L2_FIELD_SEQ_TB,
+				    sizeof(struct em28xx_buffer), fh, &dev->lock);
+	mutex_unlock(&dev->lock);
+
+	return errCode;
+}
+
+/*
+ * em28xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+void em28xx_release_analog_resources(struct em28xx *dev)
+{
+
+	/*FIXME: I2C IR should be disconnected */
+
+	if (dev->radio_dev) {
+		if (video_is_registered(dev->radio_dev))
+			video_unregister_device(dev->radio_dev);
+		else
+			video_device_release(dev->radio_dev);
+		dev->radio_dev = NULL;
+	}
+	if (dev->vbi_dev) {
+		em28xx_info("V4L2 device %s deregistered\n",
+			    video_device_node_name(dev->vbi_dev));
+		if (video_is_registered(dev->vbi_dev))
+			video_unregister_device(dev->vbi_dev);
+		else
+			video_device_release(dev->vbi_dev);
+		dev->vbi_dev = NULL;
+	}
+	if (dev->vdev) {
+		em28xx_info("V4L2 device %s deregistered\n",
+			    video_device_node_name(dev->vdev));
+		if (video_is_registered(dev->vdev))
+			video_unregister_device(dev->vdev);
+		else
+			video_device_release(dev->vdev);
+		dev->vdev = NULL;
+	}
+}
+
+/*
+ * em28xx_v4l2_close()
+ * stops streaming and deallocates all resources allocated by the v4l2
+ * calls and ioctls
+ */
+static int em28xx_v4l2_close(struct file *filp)
+{
+	struct em28xx_fh *fh  = filp->private_data;
+	struct em28xx    *dev = fh->dev;
+	int              errCode;
+
+	em28xx_videodbg("users=%d\n", dev->users);
+
+	mutex_lock(&dev->lock);
+	if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
+		videobuf_stop(&fh->vb_vidq);
+		res_free(fh, EM28XX_RESOURCE_VIDEO);
+	}
+
+	if (res_check(fh, EM28XX_RESOURCE_VBI)) {
+		videobuf_stop(&fh->vb_vbiq);
+		res_free(fh, EM28XX_RESOURCE_VBI);
+	}
+
+	if (dev->users == 1) {
+		/* the device is already disconnect,
+		   free the remaining resources */
+		if (dev->state & DEV_DISCONNECTED) {
+			em28xx_release_resources(dev);
+			kfree(dev->alt_max_pkt_size);
+			mutex_unlock(&dev->lock);
+			kfree(dev);
+			kfree(fh);
+			return 0;
+		}
+
+		/* Save some power by putting tuner to sleep */
+		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+
+		/* do this before setting alternate! */
+		em28xx_uninit_isoc(dev, EM28XX_ANALOG_MODE);
+		em28xx_set_mode(dev, EM28XX_SUSPEND);
+
+		/* set alternate 0 */
+		dev->alt = 0;
+		em28xx_videodbg("setting alternate 0\n");
+		errCode = usb_set_interface(dev->udev, 0, 0);
+		if (errCode < 0) {
+			em28xx_errdev("cannot change alternate number to "
+					"0 (error=%i)\n", errCode);
+		}
+	}
+
+	videobuf_mmap_free(&fh->vb_vidq);
+	videobuf_mmap_free(&fh->vb_vbiq);
+	kfree(fh);
+	dev->users--;
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+/*
+ * em28xx_v4l2_read()
+ * will allocate buffers when called for the first time
+ */
+static ssize_t
+em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
+		 loff_t *pos)
+{
+	struct em28xx_fh *fh = filp->private_data;
+	struct em28xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (mutex_lock_interruptible(&dev->lock))
+		return -ERESTARTSYS;
+	/* FIXME: read() is not prepared to allow changing the video
+	   resolution while streaming. Seems a bug at em28xx_set_fmt
+	 */
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		if (res_locked(dev, EM28XX_RESOURCE_VIDEO))
+			rc = -EBUSY;
+		else
+			rc = videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
+					filp->f_flags & O_NONBLOCK);
+	} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+		if (!res_get(fh, EM28XX_RESOURCE_VBI))
+			rc = -EBUSY;
+		else
+			rc = videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
+					filp->f_flags & O_NONBLOCK);
+	}
+	mutex_unlock(&dev->lock);
+
+	return rc;
+}
+
+/*
+ * em28xx_poll()
+ * will allocate buffers when called for the first time
+ */
+static unsigned int em28xx_poll(struct file *filp, poll_table *wait)
+{
+	struct em28xx_fh *fh = filp->private_data;
+	struct em28xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		if (!res_get(fh, EM28XX_RESOURCE_VIDEO))
+			return POLLERR;
+		return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+	} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+		if (!res_get(fh, EM28XX_RESOURCE_VBI))
+			return POLLERR;
+		return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
+	} else {
+		return POLLERR;
+	}
+}
+
+static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait)
+{
+	struct em28xx_fh *fh = filp->private_data;
+	struct em28xx *dev = fh->dev;
+	unsigned int res;
+
+	mutex_lock(&dev->lock);
+	res = em28xx_poll(filp, wait);
+	mutex_unlock(&dev->lock);
+	return res;
+}
+
+/*
+ * em28xx_v4l2_mmap()
+ */
+static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct em28xx_fh *fh    = filp->private_data;
+	struct em28xx	 *dev   = fh->dev;
+	int		 rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (mutex_lock_interruptible(&dev->lock))
+		return -ERESTARTSYS;
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+	else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
+	mutex_unlock(&dev->lock);
+
+	em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
+		(unsigned long)vma->vm_start,
+		(unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+		rc);
+
+	return rc;
+}
+
+static const struct v4l2_file_operations em28xx_v4l_fops = {
+	.owner         = THIS_MODULE,
+	.open          = em28xx_v4l2_open,
+	.release       = em28xx_v4l2_close,
+	.read          = em28xx_v4l2_read,
+	.poll          = em28xx_v4l2_poll,
+	.mmap          = em28xx_v4l2_mmap,
+	.unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+	.vidioc_querycap            = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap    = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap       = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap     = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap       = vidioc_s_fmt_vid_cap,
+	.vidioc_g_fmt_vbi_cap       = vidioc_g_fmt_vbi_cap,
+	.vidioc_s_fmt_vbi_cap       = vidioc_s_fmt_vbi_cap,
+	.vidioc_enum_framesizes     = vidioc_enum_framesizes,
+	.vidioc_g_audio             = vidioc_g_audio,
+	.vidioc_s_audio             = vidioc_s_audio,
+	.vidioc_cropcap             = vidioc_cropcap,
+	.vidioc_g_fmt_sliced_vbi_cap   = vidioc_g_fmt_sliced_vbi_cap,
+	.vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
+	.vidioc_s_fmt_sliced_vbi_cap   = vidioc_try_set_sliced_vbi_cap,
+
+	.vidioc_reqbufs             = vidioc_reqbufs,
+	.vidioc_querybuf            = vidioc_querybuf,
+	.vidioc_qbuf                = vidioc_qbuf,
+	.vidioc_dqbuf               = vidioc_dqbuf,
+	.vidioc_g_std               = vidioc_g_std,
+	.vidioc_querystd            = vidioc_querystd,
+	.vidioc_s_std               = vidioc_s_std,
+	.vidioc_g_parm		    = vidioc_g_parm,
+	.vidioc_s_parm		    = vidioc_s_parm,
+	.vidioc_enum_input          = vidioc_enum_input,
+	.vidioc_g_input             = vidioc_g_input,
+	.vidioc_s_input             = vidioc_s_input,
+	.vidioc_queryctrl           = vidioc_queryctrl,
+	.vidioc_g_ctrl              = vidioc_g_ctrl,
+	.vidioc_s_ctrl              = vidioc_s_ctrl,
+	.vidioc_streamon            = vidioc_streamon,
+	.vidioc_streamoff           = vidioc_streamoff,
+	.vidioc_g_tuner             = vidioc_g_tuner,
+	.vidioc_s_tuner             = vidioc_s_tuner,
+	.vidioc_g_frequency         = vidioc_g_frequency,
+	.vidioc_s_frequency         = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register          = vidioc_g_register,
+	.vidioc_s_register          = vidioc_s_register,
+	.vidioc_g_chip_ident        = vidioc_g_chip_ident,
+#endif
+};
+
+static const struct video_device em28xx_video_template = {
+	.fops                       = &em28xx_v4l_fops,
+	.release                    = video_device_release,
+	.ioctl_ops 		    = &video_ioctl_ops,
+
+	.tvnorms                    = V4L2_STD_ALL,
+	.current_norm               = V4L2_STD_PAL,
+};
+
+static const struct v4l2_file_operations radio_fops = {
+	.owner         = THIS_MODULE,
+	.open          = em28xx_v4l2_open,
+	.release       = em28xx_v4l2_close,
+	.unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops radio_ioctl_ops = {
+	.vidioc_querycap      = radio_querycap,
+	.vidioc_g_tuner       = radio_g_tuner,
+	.vidioc_enum_input    = radio_enum_input,
+	.vidioc_g_audio       = radio_g_audio,
+	.vidioc_s_tuner       = radio_s_tuner,
+	.vidioc_s_audio       = radio_s_audio,
+	.vidioc_s_input       = radio_s_input,
+	.vidioc_queryctrl     = radio_queryctrl,
+	.vidioc_g_ctrl        = vidioc_g_ctrl,
+	.vidioc_s_ctrl        = vidioc_s_ctrl,
+	.vidioc_g_frequency   = vidioc_g_frequency,
+	.vidioc_s_frequency   = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register    = vidioc_g_register,
+	.vidioc_s_register    = vidioc_s_register,
+#endif
+};
+
+static struct video_device em28xx_radio_template = {
+	.name                 = "em28xx-radio",
+	.fops                 = &radio_fops,
+	.ioctl_ops 	      = &radio_ioctl_ops,
+};
+
+/******************************** usb interface ******************************/
+
+
+
+static struct video_device *em28xx_vdev_init(struct em28xx *dev,
+					const struct video_device *template,
+					const char *type_name)
+{
+	struct video_device *vfd;
+
+	vfd = video_device_alloc();
+	if (NULL == vfd)
+		return NULL;
+
+	*vfd		= *template;
+	vfd->v4l2_dev	= &dev->v4l2_dev;
+	vfd->release	= video_device_release;
+	vfd->debug	= video_debug;
+	vfd->lock	= &dev->lock;
+
+	snprintf(vfd->name, sizeof(vfd->name), "%s %s",
+		 dev->name, type_name);
+
+	video_set_drvdata(vfd, dev);
+	return vfd;
+}
+
+int em28xx_register_analog_devices(struct em28xx *dev)
+{
+      u8 val;
+	int ret;
+	unsigned int maxw;
+
+	printk(KERN_INFO "%s: v4l2 driver version %s\n",
+		dev->name, EM28XX_VERSION);
+
+	/* set default norm */
+	dev->norm = em28xx_video_template.current_norm;
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
+	dev->interlaced = EM28XX_INTERLACED_DEFAULT;
+
+	/* Analog specific initialization */
+	dev->format = &format[0];
+
+	maxw = norm_maxw(dev);
+        /* MaxPacketSize for em2800 is too small to capture at full resolution
+         * use half of maxw as the scaler can only scale to 50% */
+        if (dev->board.is_em2800)
+            maxw /= 2;
+
+	em28xx_set_video_format(dev, format[0].fourcc,
+				maxw, norm_maxh(dev));
+
+	video_mux(dev, 0);
+
+	/* Audio defaults */
+	dev->mute = 1;
+	dev->volume = 0x1f;
+
+/*	em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */
+	val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK);
+	em28xx_write_reg(dev, EM28XX_R0F_XCLK,
+			 (EM28XX_XCLK_AUDIO_UNMUTE | val));
+
+	em28xx_set_outfmt(dev);
+	em28xx_colorlevels_set_default(dev);
+	em28xx_compression_disable(dev);
+
+	/* allocate and fill video video_device struct */
+	dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
+	if (!dev->vdev) {
+		em28xx_errdev("cannot allocate video_device.\n");
+		return -ENODEV;
+	}
+
+	/* register v4l2 video video_device */
+	ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
+				       video_nr[dev->devno]);
+	if (ret) {
+		em28xx_errdev("unable to register video device (error=%i).\n",
+			      ret);
+		return ret;
+	}
+
+	/* Allocate and fill vbi video_device struct */
+	if (em28xx_vbi_supported(dev) == 1) {
+		dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
+						"vbi");
+
+		/* register v4l2 vbi video_device */
+		ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+					    vbi_nr[dev->devno]);
+		if (ret < 0) {
+			em28xx_errdev("unable to register vbi device\n");
+			return ret;
+		}
+	}
+
+	if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
+		dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
+						  "radio");
+		if (!dev->radio_dev) {
+			em28xx_errdev("cannot allocate video_device.\n");
+			return -ENODEV;
+		}
+		ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+					    radio_nr[dev->devno]);
+		if (ret < 0) {
+			em28xx_errdev("can't register radio device\n");
+			return ret;
+		}
+		em28xx_info("Registered radio device as %s\n",
+			    video_device_node_name(dev->radio_dev));
+	}
+
+	em28xx_info("V4L2 video device registered as %s\n",
+		    video_device_node_name(dev->vdev));
+
+	if (dev->vbi_dev)
+		em28xx_info("V4L2 VBI device registered as %s\n",
+			    video_device_node_name(dev->vbi_dev));
+
+	return 0;
+}
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
new file mode 100644
index 0000000..8757523
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -0,0 +1,809 @@
+/*
+   em28xx.h - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+   Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
+		      Ludovico Cavedon <cavedon@sssup.it>
+		      Mauro Carvalho Chehab <mchehab@infradead.org>
+
+   Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.de>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _EM28XX_H
+#define _EM28XX_H
+
+#include <linux/workqueue.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+
+#include <media/videobuf-vmalloc.h>
+#include <media/v4l2-device.h>
+#include <media/ir-kbd-i2c.h>
+#include <media/rc-core.h>
+#if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE)
+#include <media/videobuf-dvb.h>
+#endif
+#include "tuner-xc2028.h"
+#include "xc5000.h"
+#include "em28xx-reg.h"
+
+/* Boards supported by driver */
+#define EM2800_BOARD_UNKNOWN			0
+#define EM2820_BOARD_UNKNOWN			1
+#define EM2820_BOARD_TERRATEC_CINERGY_250	2
+#define EM2820_BOARD_PINNACLE_USB_2		3
+#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2      4
+#define EM2820_BOARD_MSI_VOX_USB_2              5
+#define EM2800_BOARD_TERRATEC_CINERGY_200       6
+#define EM2800_BOARD_LEADTEK_WINFAST_USBII      7
+#define EM2800_BOARD_KWORLD_USB2800             8
+#define EM2820_BOARD_PINNACLE_DVC_90		9
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900	10
+#define EM2880_BOARD_TERRATEC_HYBRID_XS		11
+#define EM2820_BOARD_KWORLD_PVRTV2800RF		12
+#define EM2880_BOARD_TERRATEC_PRODIGY_XS	13
+#define EM2820_BOARD_PROLINK_PLAYTV_USB2	14
+#define EM2800_BOARD_VGEAR_POCKETTV             15
+#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950	16
+#define EM2880_BOARD_PINNACLE_PCTV_HD_PRO	17
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2	18
+#define EM2860_BOARD_SAA711X_REFERENCE_DESIGN	19
+#define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600   20
+#define EM2800_BOARD_GRABBEEX_USB2800           21
+#define EM2750_BOARD_UNKNOWN			  22
+#define EM2750_BOARD_DLCW_130			  23
+#define EM2820_BOARD_DLINK_USB_TV		  24
+#define EM2820_BOARD_GADMEI_UTV310		  25
+#define EM2820_BOARD_HERCULES_SMART_TV_USB2	  26
+#define EM2820_BOARD_PINNACLE_USB_2_FM1216ME	  27
+#define EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE 28
+#define EM2860_BOARD_TVP5150_REFERENCE_DESIGN	  29
+#define EM2820_BOARD_VIDEOLOGY_20K14XUSB	  30
+#define EM2821_BOARD_USBGEAR_VD204		  31
+#define EM2821_BOARD_SUPERCOMP_USB_2		  32
+#define EM2860_BOARD_ELGATO_VIDEO_CAPTURE	  33
+#define EM2860_BOARD_TERRATEC_HYBRID_XS		  34
+#define EM2860_BOARD_TYPHOON_DVD_MAKER		  35
+#define EM2860_BOARD_NETGMBH_CAM		  36
+#define EM2860_BOARD_GADMEI_UTV330		  37
+#define EM2861_BOARD_YAKUMO_MOVIE_MIXER		  38
+#define EM2861_BOARD_KWORLD_PVRTV_300U		  39
+#define EM2861_BOARD_PLEXTOR_PX_TV100U		  40
+#define EM2870_BOARD_KWORLD_350U		  41
+#define EM2870_BOARD_KWORLD_355U		  42
+#define EM2870_BOARD_TERRATEC_XS		  43
+#define EM2870_BOARD_TERRATEC_XS_MT2060		  44
+#define EM2870_BOARD_PINNACLE_PCTV_DVB		  45
+#define EM2870_BOARD_COMPRO_VIDEOMATE		  46
+#define EM2880_BOARD_KWORLD_DVB_305U		  47
+#define EM2880_BOARD_KWORLD_DVB_310U		  48
+#define EM2880_BOARD_MSI_DIGIVOX_AD		  49
+#define EM2880_BOARD_MSI_DIGIVOX_AD_II		  50
+#define EM2880_BOARD_TERRATEC_HYBRID_XS_FR	  51
+#define EM2881_BOARD_DNT_DA2_HYBRID		  52
+#define EM2881_BOARD_PINNACLE_HYBRID_PRO	  53
+#define EM2882_BOARD_KWORLD_VS_DVBT		  54
+#define EM2882_BOARD_TERRATEC_HYBRID_XS		  55
+#define EM2882_BOARD_PINNACLE_HYBRID_PRO_330E	  56
+#define EM2883_BOARD_KWORLD_HYBRID_330U                  57
+#define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU	  58
+#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850	  60
+#define EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2	  61
+#define EM2820_BOARD_GADMEI_TVR200		  62
+#define EM2860_BOARD_KAIOMY_TVNPC_U2              63
+#define EM2860_BOARD_EASYCAP                      64
+#define EM2820_BOARD_IODATA_GVMVP_SZ		  65
+#define EM2880_BOARD_EMPIRE_DUAL_TV		  66
+#define EM2860_BOARD_TERRATEC_GRABBY		  67
+#define EM2860_BOARD_TERRATEC_AV350		  68
+#define EM2882_BOARD_KWORLD_ATSC_315U		  69
+#define EM2882_BOARD_EVGA_INDTUBE		  70
+#define EM2820_BOARD_SILVERCREST_WEBCAM           71
+#define EM2861_BOARD_GADMEI_UTV330PLUS           72
+#define EM2870_BOARD_REDDO_DVB_C_USB_BOX          73
+#define EM2800_BOARD_VC211A			  74
+#define EM2882_BOARD_DIKOM_DK300		  75
+#define EM2870_BOARD_KWORLD_A340		  76
+#define EM2874_BOARD_LEADERSHIP_ISDBT		  77
+#define EM28174_BOARD_PCTV_290E                   78
+#define EM2884_BOARD_TERRATEC_H5		  79
+#define EM28174_BOARD_PCTV_460E                   80
+#define EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C	  81
+#define EM2884_BOARD_CINERGY_HTC_STICK		  82
+#define EM2860_BOARD_HT_VIDBOX_NW03 		  83
+#define EM2874_BOARD_MAXMEDIA_UB425_TC            84
+#define EM2884_BOARD_PCTV_510E                    85
+#define EM2884_BOARD_PCTV_520E                    86
+
+/* Limits minimum and default number of buffers */
+#define EM28XX_MIN_BUF 4
+#define EM28XX_DEF_BUF 8
+
+/*Limits the max URB message size */
+#define URB_MAX_CTRL_SIZE 80
+
+/* Params for validated field */
+#define EM28XX_BOARD_NOT_VALIDATED 1
+#define EM28XX_BOARD_VALIDATED	   0
+
+/* Params for em28xx_cmd() audio */
+#define EM28XX_START_AUDIO      1
+#define EM28XX_STOP_AUDIO       0
+
+/* maximum number of em28xx boards */
+#define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */
+
+/* maximum number of frames that can be queued */
+#define EM28XX_NUM_FRAMES 5
+/* number of frames that get used for v4l2_read() */
+#define EM28XX_NUM_READ_FRAMES 2
+
+/* number of buffers for isoc transfers */
+#define EM28XX_NUM_BUFS 5
+#define EM28XX_DVB_NUM_BUFS 5
+
+/* number of packets for each buffer
+   windows requests only 64 packets .. so we better do the same
+   this is what I found out for all alternate numbers there!
+ */
+#define EM28XX_NUM_PACKETS 64
+#define EM28XX_DVB_MAX_PACKETS 64
+
+#define EM28XX_INTERLACED_DEFAULT 1
+
+/*
+#define (use usbview if you want to get the other alternate number infos)
+#define
+#define alternate number 2
+#define 			Endpoint Address: 82
+			Direction: in
+			Attribute: 1
+			Type: Isoc
+			Max Packet Size: 1448
+			Interval: 125us
+
+  alternate number 7
+
+			Endpoint Address: 82
+			Direction: in
+			Attribute: 1
+			Type: Isoc
+			Max Packet Size: 3072
+			Interval: 125us
+*/
+
+/* time to wait when stopping the isoc transfer */
+#define EM28XX_URB_TIMEOUT \
+			msecs_to_jiffies(EM28XX_NUM_BUFS * EM28XX_NUM_PACKETS)
+
+/* time in msecs to wait for i2c writes to finish */
+#define EM2800_I2C_WRITE_TIMEOUT 20
+
+enum em28xx_mode {
+	EM28XX_SUSPEND,
+	EM28XX_ANALOG_MODE,
+	EM28XX_DIGITAL_MODE,
+};
+
+
+struct em28xx;
+
+struct em28xx_usb_isoc_bufs {
+		/* max packet size of isoc transaction */
+	int				max_pkt_size;
+
+		/* number of packets in each buffer */
+	int				num_packets;
+
+		/* number of allocated urbs */
+	int				num_bufs;
+
+		/* urb for isoc transfers */
+	struct urb			**urb;
+
+		/* transfer buffers for isoc transfer */
+	char				**transfer_buffer;
+};
+
+struct em28xx_usb_isoc_ctl {
+		/* isoc transfer buffers for analog mode */
+	struct em28xx_usb_isoc_bufs	analog_bufs;
+
+		/* isoc transfer buffers for digital mode */
+	struct em28xx_usb_isoc_bufs	digital_bufs;
+
+		/* Stores already requested buffers */
+	struct em28xx_buffer    	*vid_buf;
+	struct em28xx_buffer    	*vbi_buf;
+
+		/* isoc urb callback */
+	int (*isoc_copy) (struct em28xx *dev, struct urb *urb);
+
+};
+
+/* Struct to enumberate video formats */
+struct em28xx_fmt {
+	char  *name;
+	u32   fourcc;          /* v4l2 format id */
+	int   depth;
+	int   reg;
+};
+
+/* buffer for one video frame */
+struct em28xx_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+
+	struct list_head frame;
+	int top_field;
+};
+
+struct em28xx_dmaqueue {
+	struct list_head       active;
+
+	wait_queue_head_t          wq;
+
+	/* Counters to control buffer fill */
+	int                        pos;
+};
+
+/* inputs */
+
+#define MAX_EM28XX_INPUT 4
+enum enum28xx_itype {
+	EM28XX_VMUX_COMPOSITE1 = 1,
+	EM28XX_VMUX_COMPOSITE2,
+	EM28XX_VMUX_COMPOSITE3,
+	EM28XX_VMUX_COMPOSITE4,
+	EM28XX_VMUX_SVIDEO,
+	EM28XX_VMUX_TELEVISION,
+	EM28XX_VMUX_CABLE,
+	EM28XX_VMUX_DVB,
+	EM28XX_VMUX_DEBUG,
+	EM28XX_RADIO,
+};
+
+enum em28xx_ac97_mode {
+	EM28XX_NO_AC97 = 0,
+	EM28XX_AC97_EM202,
+	EM28XX_AC97_SIGMATEL,
+	EM28XX_AC97_OTHER,
+};
+
+struct em28xx_audio_mode {
+	enum em28xx_ac97_mode ac97;
+
+	u16 ac97_feat;
+	u32 ac97_vendor_id;
+
+	unsigned int has_audio:1;
+
+	unsigned int i2s_3rates:1;
+	unsigned int i2s_5rates:1;
+};
+
+/* em28xx has two audio inputs: tuner and line in.
+   However, on most devices, an auxiliary AC97 codec device is used.
+   The AC97 device may have several different inputs and outputs,
+   depending on their model. So, it is possible to use AC97 mixer to
+   address more than two different entries.
+ */
+enum em28xx_amux {
+	/* This is the only entry for em28xx tuner input */
+	EM28XX_AMUX_VIDEO,	/* em28xx tuner, AC97 mixer Video */
+
+	EM28XX_AMUX_LINE_IN,	/* AC97 mixer Line In */
+
+	/* Some less-common mixer setups */
+	EM28XX_AMUX_VIDEO2,	/* em28xx Line in, AC97 mixer Video */
+	EM28XX_AMUX_PHONE,
+	EM28XX_AMUX_MIC,
+	EM28XX_AMUX_CD,
+	EM28XX_AMUX_AUX,
+	EM28XX_AMUX_PCM_OUT,
+};
+
+enum em28xx_aout {
+	/* AC97 outputs */
+	EM28XX_AOUT_MASTER = 1 << 0,
+	EM28XX_AOUT_LINE   = 1 << 1,
+	EM28XX_AOUT_MONO   = 1 << 2,
+	EM28XX_AOUT_LFE    = 1 << 3,
+	EM28XX_AOUT_SURR   = 1 << 4,
+
+	/* PCM IN Mixer - used by AC97_RECORD_SELECT register */
+	EM28XX_AOUT_PCM_IN = 1 << 7,
+
+	/* Bits 10-8 are used to indicate the PCM IN record select */
+	EM28XX_AOUT_PCM_MIC_PCM = 0 << 8,
+	EM28XX_AOUT_PCM_CD	= 1 << 8,
+	EM28XX_AOUT_PCM_VIDEO	= 2 << 8,
+	EM28XX_AOUT_PCM_AUX	= 3 << 8,
+	EM28XX_AOUT_PCM_LINE	= 4 << 8,
+	EM28XX_AOUT_PCM_STEREO	= 5 << 8,
+	EM28XX_AOUT_PCM_MONO	= 6 << 8,
+	EM28XX_AOUT_PCM_PHONE	= 7 << 8,
+};
+
+static inline int ac97_return_record_select(int a_out)
+{
+	return (a_out & 0x700) >> 8;
+}
+
+struct em28xx_reg_seq {
+	int reg;
+	unsigned char val, mask;
+	int sleep;
+};
+
+struct em28xx_input {
+	enum enum28xx_itype type;
+	unsigned int vmux;
+	enum em28xx_amux amux;
+	enum em28xx_aout aout;
+	struct em28xx_reg_seq *gpio;
+};
+
+#define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
+
+enum em28xx_decoder {
+	EM28XX_NODECODER = 0,
+	EM28XX_TVP5150,
+	EM28XX_SAA711X,
+};
+
+enum em28xx_sensor {
+	EM28XX_NOSENSOR = 0,
+	EM28XX_MT9V011,
+	EM28XX_MT9M001,
+	EM28XX_MT9M111,
+};
+
+enum em28xx_adecoder {
+	EM28XX_NOADECODER = 0,
+	EM28XX_TVAUDIO,
+};
+
+struct em28xx_board {
+	char *name;
+	int vchannels;
+	int tuner_type;
+	int tuner_addr;
+
+	/* i2c flags */
+	unsigned int tda9887_conf;
+
+	/* GPIO sequences */
+	struct em28xx_reg_seq *dvb_gpio;
+	struct em28xx_reg_seq *suspend_gpio;
+	struct em28xx_reg_seq *tuner_gpio;
+	struct em28xx_reg_seq *mute_gpio;
+
+	unsigned int is_em2800:1;
+	unsigned int has_msp34xx:1;
+	unsigned int mts_firmware:1;
+	unsigned int max_range_640_480:1;
+	unsigned int has_dvb:1;
+	unsigned int has_snapshot_button:1;
+	unsigned int is_webcam:1;
+	unsigned int valid:1;
+	unsigned int has_ir_i2c:1;
+
+	unsigned char xclk, i2c_speed;
+	unsigned char radio_addr;
+	unsigned short tvaudio_addr;
+
+	enum em28xx_decoder decoder;
+	enum em28xx_adecoder adecoder;
+
+	struct em28xx_input       input[MAX_EM28XX_INPUT];
+	struct em28xx_input	  radio;
+	char			  *ir_codes;
+};
+
+struct em28xx_eeprom {
+	u32 id;			/* 0x9567eb1a */
+	u16 vendor_ID;
+	u16 product_ID;
+
+	u16 chip_conf;
+
+	u16 board_conf;
+
+	u16 string1, string2, string3;
+
+	u8 string_idx_table;
+};
+
+/* device states */
+enum em28xx_dev_state {
+	DEV_INITIALIZED = 0x01,
+	DEV_DISCONNECTED = 0x02,
+	DEV_MISCONFIGURED = 0x04,
+};
+
+#define EM28XX_AUDIO_BUFS 5
+#define EM28XX_NUM_AUDIO_PACKETS 64
+#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */
+#define EM28XX_CAPTURE_STREAM_EN 1
+
+/* em28xx extensions */
+#define EM28XX_AUDIO   0x10
+#define EM28XX_DVB     0x20
+#define EM28XX_RC      0x30
+
+/* em28xx resource types (used for res_get/res_lock etc */
+#define EM28XX_RESOURCE_VIDEO 0x01
+#define EM28XX_RESOURCE_VBI   0x02
+
+struct em28xx_audio {
+	char name[50];
+	char *transfer_buffer[EM28XX_AUDIO_BUFS];
+	struct urb *urb[EM28XX_AUDIO_BUFS];
+	struct usb_device *udev;
+	unsigned int capture_transfer_done;
+	struct snd_pcm_substream   *capture_pcm_substream;
+
+	unsigned int hwptr_done_capture;
+	struct snd_card            *sndcard;
+
+	int users;
+	spinlock_t slock;
+};
+
+struct em28xx;
+
+struct em28xx_fh {
+	struct em28xx *dev;
+	int           radio;
+	unsigned int  resources;
+
+	struct videobuf_queue        vb_vidq;
+	struct videobuf_queue        vb_vbiq;
+
+	enum v4l2_buf_type           type;
+};
+
+/* main device struct */
+struct em28xx {
+	/* generic device properties */
+	char name[30];		/* name (including minor) of the device */
+	int model;		/* index in the device_data struct */
+	int devno;		/* marks the number of this device */
+	enum em28xx_chip_id chip_id;
+
+	int audio_ifnum;
+
+	struct v4l2_device v4l2_dev;
+	struct em28xx_board board;
+
+	/* Webcam specific fields */
+	enum em28xx_sensor em28xx_sensor;
+	int sensor_xres, sensor_yres;
+	int sensor_xtal;
+
+	/* Allows progressive (e. g. non-interlaced) mode */
+	int progressive;
+
+	/* Vinmode/Vinctl used at the driver */
+	int vinmode, vinctl;
+
+	unsigned int has_audio_class:1;
+	unsigned int has_alsa_audio:1;
+	unsigned int is_audio_only:1;
+
+	/* Controls audio streaming */
+	struct work_struct wq_trigger;              /* Trigger to start/stop audio for alsa module */
+	 atomic_t       stream_started;      /* stream should be running if true */
+
+	struct em28xx_fmt *format;
+
+	struct em28xx_IR *ir;
+
+	/* Some older em28xx chips needs a waiting time after writing */
+	unsigned int wait_after_write;
+
+	struct list_head	devlist;
+
+	u32 i2s_speed;		/* I2S speed for audio digital stream */
+
+	struct em28xx_audio_mode audio_mode;
+
+	int tuner_type;		/* type of the tuner */
+	int tuner_addr;		/* tuner address */
+	int tda9887_conf;
+	/* i2c i/o */
+	struct i2c_adapter i2c_adap;
+	struct i2c_client i2c_client;
+	/* video for linux */
+	int users;		/* user count for exclusive use */
+	struct video_device *vdev;	/* video for linux device struct */
+	v4l2_std_id norm;	/* selected tv norm */
+	int ctl_freq;		/* selected frequency */
+	unsigned int ctl_input;	/* selected input */
+	unsigned int ctl_ainput;/* selected audio input */
+	unsigned int ctl_aoutput;/* selected audio output */
+	int mute;
+	int volume;
+	/* frame properties */
+	int width;		/* current frame width */
+	int height;		/* current frame height */
+	unsigned hscale;	/* horizontal scale factor (see datasheet) */
+	unsigned vscale;	/* vertical scale factor (see datasheet) */
+	int interlaced;		/* 1=interlace fileds, 0=just top fileds */
+	unsigned int video_bytesread;	/* Number of bytes read */
+
+	unsigned long hash;	/* eeprom hash - for boards with generic ID */
+	unsigned long i2c_hash;	/* i2c devicelist hash -
+				   for boards with generic ID */
+
+	struct em28xx_audio adev;
+
+	/* states */
+	enum em28xx_dev_state state;
+
+	/* vbi related state tracking */
+	int capture_type;
+	int vbi_read;
+	unsigned char cur_field;
+	unsigned int vbi_width;
+	unsigned int vbi_height; /* lines per field */
+
+	struct work_struct         request_module_wk;
+
+	/* locks */
+	struct mutex lock;
+	struct mutex ctrl_urb_lock;	/* protects urb_buf */
+	/* spinlock_t queue_lock; */
+	struct list_head inqueue, outqueue;
+	struct video_device *vbi_dev;
+	struct video_device *radio_dev;
+
+	/* resources in use */
+	unsigned int resources;
+
+	unsigned char eedata[256];
+
+	/* Isoc control struct */
+	struct em28xx_dmaqueue vidq;
+	struct em28xx_dmaqueue vbiq;
+	struct em28xx_usb_isoc_ctl isoc_ctl;
+	spinlock_t slock;
+
+	/* usb transfer */
+	struct usb_device *udev;	/* the usb device */
+	int alt;		/* alternate */
+	int max_pkt_size;	/* max packet size of isoc transaction */
+	int num_alt;		/* Number of alternative settings */
+	unsigned int *alt_max_pkt_size;	/* array of wMaxPacketSize */
+	int dvb_alt;				/* alternate for DVB */
+	unsigned int dvb_max_pkt_size;		/* wMaxPacketSize for DVB */
+	char urb_buf[URB_MAX_CTRL_SIZE];	/* urb control msg buffer */
+
+	/* helper funcs that call usb_control_msg */
+	int (*em28xx_write_regs) (struct em28xx *dev, u16 reg,
+					char *buf, int len);
+	int (*em28xx_read_reg) (struct em28xx *dev, u16 reg);
+	int (*em28xx_read_reg_req_len) (struct em28xx *dev, u8 req, u16 reg,
+					char *buf, int len);
+	int (*em28xx_write_regs_req) (struct em28xx *dev, u8 req, u16 reg,
+				      char *buf, int len);
+	int (*em28xx_read_reg_req) (struct em28xx *dev, u8 req, u16 reg);
+
+	enum em28xx_mode mode;
+
+	/* register numbers for GPO/GPIO registers */
+	u16 reg_gpo_num, reg_gpio_num;
+
+	/* Caches GPO and GPIO registers */
+	unsigned char	reg_gpo, reg_gpio;
+
+	/* Snapshot button */
+	char snapshot_button_path[30];	/* path of the input dev */
+	struct input_dev *sbutton_input_dev;
+	struct delayed_work sbutton_query_work;
+
+	struct em28xx_dvb *dvb;
+
+	/* I2C keyboard data */
+	struct IR_i2c_init_data init_data;
+};
+
+struct em28xx_ops {
+	struct list_head next;
+	char *name;
+	int id;
+	int (*init)(struct em28xx *);
+	int (*fini)(struct em28xx *);
+};
+
+/* Provided by em28xx-i2c.c */
+void em28xx_do_i2c_scan(struct em28xx *dev);
+int  em28xx_i2c_register(struct em28xx *dev);
+int  em28xx_i2c_unregister(struct em28xx *dev);
+
+/* Provided by em28xx-core.c */
+
+u32 em28xx_request_buffers(struct em28xx *dev, u32 count);
+void em28xx_queue_unusedframes(struct em28xx *dev);
+void em28xx_release_buffers(struct em28xx *dev);
+
+int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
+			    char *buf, int len);
+int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg);
+int em28xx_read_reg(struct em28xx *dev, u16 reg);
+int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
+			  int len);
+int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
+int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val);
+int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
+				 u8 bitmask);
+
+int em28xx_read_ac97(struct em28xx *dev, u8 reg);
+int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
+
+int em28xx_audio_analog_set(struct em28xx *dev);
+int em28xx_audio_setup(struct em28xx *dev);
+
+int em28xx_colorlevels_set_default(struct em28xx *dev);
+int em28xx_capture_start(struct em28xx *dev, int start);
+int em28xx_vbi_supported(struct em28xx *dev);
+int em28xx_set_outfmt(struct em28xx *dev);
+int em28xx_resolution_set(struct em28xx *dev);
+int em28xx_set_alternate(struct em28xx *dev);
+int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode,
+		      int max_packets, int num_bufs, int max_pkt_size);
+int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode,
+		     int max_packets, int num_bufs, int max_pkt_size,
+		     int (*isoc_copy) (struct em28xx *dev, struct urb *urb));
+void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode);
+void em28xx_stop_urbs(struct em28xx *dev);
+int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev);
+int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
+int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
+void em28xx_wake_i2c(struct em28xx *dev);
+int em28xx_register_extension(struct em28xx_ops *dev);
+void em28xx_unregister_extension(struct em28xx_ops *dev);
+void em28xx_init_extension(struct em28xx *dev);
+void em28xx_close_extension(struct em28xx *dev);
+
+/* Provided by em28xx-video.c */
+int em28xx_register_analog_devices(struct em28xx *dev);
+void em28xx_release_analog_resources(struct em28xx *dev);
+
+/* Provided by em28xx-cards.c */
+extern int em2800_variant_detect(struct usb_device *udev, int model);
+extern struct em28xx_board em28xx_boards[];
+extern struct usb_device_id em28xx_id_table[];
+extern const unsigned int em28xx_bcount;
+int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
+void em28xx_release_resources(struct em28xx *dev);
+
+/* Provided by em28xx-vbi.c */
+extern struct videobuf_queue_ops em28xx_vbi_qops;
+
+/* printk macros */
+
+#define em28xx_err(fmt, arg...) do {\
+	printk(KERN_ERR fmt , ##arg); } while (0)
+
+#define em28xx_errdev(fmt, arg...) do {\
+	printk(KERN_ERR "%s: "fmt,\
+			dev->name , ##arg); } while (0)
+
+#define em28xx_info(fmt, arg...) do {\
+	printk(KERN_INFO "%s: "fmt,\
+			dev->name , ##arg); } while (0)
+#define em28xx_warn(fmt, arg...) do {\
+	printk(KERN_WARNING "%s: "fmt,\
+			dev->name , ##arg); } while (0)
+
+static inline int em28xx_compression_disable(struct em28xx *dev)
+{
+	/* side effect of disabling scaler and mixer */
+	return em28xx_write_reg(dev, EM28XX_R26_COMPR, 0x00);
+}
+
+static inline int em28xx_contrast_get(struct em28xx *dev)
+{
+	return em28xx_read_reg(dev, EM28XX_R20_YGAIN) & 0x1f;
+}
+
+static inline int em28xx_brightness_get(struct em28xx *dev)
+{
+	return em28xx_read_reg(dev, EM28XX_R21_YOFFSET);
+}
+
+static inline int em28xx_saturation_get(struct em28xx *dev)
+{
+	return em28xx_read_reg(dev, EM28XX_R22_UVGAIN) & 0x1f;
+}
+
+static inline int em28xx_u_balance_get(struct em28xx *dev)
+{
+	return em28xx_read_reg(dev, EM28XX_R23_UOFFSET);
+}
+
+static inline int em28xx_v_balance_get(struct em28xx *dev)
+{
+	return em28xx_read_reg(dev, EM28XX_R24_VOFFSET);
+}
+
+static inline int em28xx_gamma_get(struct em28xx *dev)
+{
+	return em28xx_read_reg(dev, EM28XX_R14_GAMMA) & 0x3f;
+}
+
+static inline int em28xx_contrast_set(struct em28xx *dev, s32 val)
+{
+	u8 tmp = (u8) val;
+	return em28xx_write_regs(dev, EM28XX_R20_YGAIN, &tmp, 1);
+}
+
+static inline int em28xx_brightness_set(struct em28xx *dev, s32 val)
+{
+	u8 tmp = (u8) val;
+	return em28xx_write_regs(dev, EM28XX_R21_YOFFSET, &tmp, 1);
+}
+
+static inline int em28xx_saturation_set(struct em28xx *dev, s32 val)
+{
+	u8 tmp = (u8) val;
+	return em28xx_write_regs(dev, EM28XX_R22_UVGAIN, &tmp, 1);
+}
+
+static inline int em28xx_u_balance_set(struct em28xx *dev, s32 val)
+{
+	u8 tmp = (u8) val;
+	return em28xx_write_regs(dev, EM28XX_R23_UOFFSET, &tmp, 1);
+}
+
+static inline int em28xx_v_balance_set(struct em28xx *dev, s32 val)
+{
+	u8 tmp = (u8) val;
+	return em28xx_write_regs(dev, EM28XX_R24_VOFFSET, &tmp, 1);
+}
+
+static inline int em28xx_gamma_set(struct em28xx *dev, s32 val)
+{
+	u8 tmp = (u8) val;
+	return em28xx_write_regs(dev, EM28XX_R14_GAMMA, &tmp, 1);
+}
+
+/*FIXME: maxw should be dependent of alt mode */
+static inline unsigned int norm_maxw(struct em28xx *dev)
+{
+	if (dev->board.is_webcam)
+		return dev->sensor_xres;
+
+	if (dev->board.max_range_640_480)
+		return 640;
+
+	return 720;
+}
+
+static inline unsigned int norm_maxh(struct em28xx *dev)
+{
+	if (dev->board.is_webcam)
+		return dev->sensor_yres;
+
+	if (dev->board.max_range_640_480)
+		return 480;
+
+	return (dev->norm & V4L2_STD_625_50) ? 576 : 480;
+}
+#endif
diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig
new file mode 100644
index 0000000..6345f93
--- /dev/null
+++ b/drivers/media/usb/gspca/Kconfig
@@ -0,0 +1,425 @@
+menuconfig USB_GSPCA
+	tristate "GSPCA based webcams"
+	depends on VIDEO_V4L2
+	default m
+	---help---
+	  Say Y here if you want to enable selecting webcams based
+	  on the GSPCA framework.
+
+	  See <file:Documentation/video4linux/gspca.txt> for more info.
+
+	  This driver uses the Video For Linux API. You must say Y or M to
+	  "Video For Linux" to use this driver.
+
+	  To compile this driver as modules, choose M here: the
+	  module will be called gspca_main.
+
+
+if USB_GSPCA && VIDEO_V4L2
+
+source "drivers/media/usb/gspca/m5602/Kconfig"
+source "drivers/media/usb/gspca/stv06xx/Kconfig"
+source "drivers/media/usb/gspca/gl860/Kconfig"
+
+config USB_GSPCA_BENQ
+	tristate "Benq USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for the Benq DC E300 camera.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_benq.
+
+config USB_GSPCA_CONEX
+	tristate "Conexant Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the Conexant chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_conex.
+
+config USB_GSPCA_CPIA1
+	tristate "cpia CPiA (version 1) Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for USB cameras based on the cpia
+	  CPiA chip. Note that you need atleast version 0.6.4 of libv4l for
+	  applications to understand the videoformat generated by this driver.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_cpia1.
+
+config USB_GSPCA_ETOMS
+	tristate "Etoms USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the Etoms chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_etoms.
+
+config USB_GSPCA_FINEPIX
+	tristate "Fujifilm FinePix USB V4L2 driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the FinePix chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_finepix.
+
+config USB_GSPCA_JEILINJ
+	tristate "Jeilin JPEG USB V4L2 driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on this Jeilin chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_jeilinj.
+
+config USB_GSPCA_JL2005BCD
+	tristate "JL2005B/C/D USB V4L2 driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based the
+	  JL2005B, JL2005C, or JL2005D chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_jl2005bcd.
+
+config USB_GSPCA_KINECT
+	tristate "Kinect sensor device USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for the Microsoft Kinect sensor device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_kinect.
+
+config USB_GSPCA_KONICA
+	tristate "Konica USB Camera V4L2 driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the Konica chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_konica.
+
+config USB_GSPCA_MARS
+	tristate "Mars USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the Mars chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_mars.
+
+config USB_GSPCA_MR97310A
+	tristate "Mars-Semi MR97310A USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the MR97310A chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_mr97310a.
+
+config USB_GSPCA_NW80X
+	tristate "Divio based (NW80x) USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the NW80x chips.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_nw80x.
+
+config USB_GSPCA_OV519
+	tristate "OV51x / OVFX2 / W996xCF USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on one of these:
+	  OV511(+), OV518(+), OV519, OVFX2, W9967CF, W9968CF
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_ov519.
+
+config USB_GSPCA_OV534
+	tristate "OV534 OV772x USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the OV534 chip
+	  and sensor OV772x (e.g. Sony Playstation EYE)
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_ov534.
+
+config USB_GSPCA_OV534_9
+	tristate "OV534 OV965x USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the OV534 chip
+	  and sensor OV965x (e.g. Hercules Dualpix)
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_ov534_9.
+
+config USB_GSPCA_PAC207
+	tristate "Pixart PAC207 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the PAC207 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_pac207.
+
+config USB_GSPCA_PAC7302
+	tristate "Pixart PAC7302 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the PAC7302 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_pac7302.
+
+config USB_GSPCA_PAC7311
+	tristate "Pixart PAC7311 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the PAC7311 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_pac7311.
+
+config USB_GSPCA_SE401
+	tristate "SE401 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	 Say Y here if you want support for cameras based on the
+	 Endpoints (formerly known as AOX) se401 chip.
+
+	 To compile this driver as a module, choose M here: the
+	 module will be called gspca_se401.
+
+config USB_GSPCA_SN9C2028
+	tristate "SONIX Dual-Mode USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want streaming support for Sonix SN9C2028 cameras.
+	  These are supported as stillcams in libgphoto2/camlibs/sonix.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_sn9c2028.
+
+config USB_GSPCA_SN9C20X
+	tristate "SN9C20X USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	 Say Y here if you want support for cameras based on the
+	 sn9c20x chips (SN9C201 and SN9C202).
+
+	 To compile this driver as a module, choose M here: the
+	 module will be called gspca_sn9c20x.
+
+config USB_GSPCA_SONIXB
+	tristate "SONIX Bayer USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the Sonix
+	  chips with Bayer format (SN9C101, SN9C102 and SN9C103).
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_sonixb.
+
+config USB_GSPCA_SONIXJ
+	tristate "SONIX JPEG USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the Sonix
+	  chips with JPEG format (SN9C102P, SN9C105 and >= SN9C110).
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_sonixj
+
+config USB_GSPCA_SPCA500
+	tristate "SPCA500 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the SPCA500 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_spca500.
+
+config USB_GSPCA_SPCA501
+	tristate "SPCA501 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the SPCA501 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_spca501.
+
+config USB_GSPCA_SPCA505
+	tristate "SPCA505 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the SPCA505 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_spca505.
+
+config USB_GSPCA_SPCA506
+	tristate "SPCA506 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the SPCA506 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_spca506.
+
+config USB_GSPCA_SPCA508
+	tristate "SPCA508 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the SPCA508 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_spca508.
+
+config USB_GSPCA_SPCA561
+	tristate "SPCA561 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the SPCA561 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_spca561.
+
+config USB_GSPCA_SPCA1528
+	tristate "SPCA1528 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the SPCA1528 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_spca1528.
+
+config USB_GSPCA_SQ905
+	tristate "SQ Technologies SQ905 based USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the SQ905 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_sq905.
+
+config USB_GSPCA_SQ905C
+	tristate "SQ Technologies SQ905C based USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the SQ905C chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_sq905c.
+
+config USB_GSPCA_SQ930X
+	tristate "SQ Technologies SQ930X based USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the SQ930X chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_sq930x.
+
+config USB_GSPCA_STK014
+	tristate "Syntek DV4000 (STK014) USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the STK014 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_stk014.
+
+config USB_GSPCA_STV0680
+	tristate "STV0680 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the STV0680 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_stv0680.
+
+config USB_GSPCA_SUNPLUS
+	tristate "SUNPLUS USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the Sunplus
+	  SPCA504(abc) SPCA533 SPCA536 chips.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_sunplus.
+
+config USB_GSPCA_T613
+	tristate "T613 (JPEG Compliance) USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the T613 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_t613.
+
+config USB_GSPCA_TOPRO
+	tristate "TOPRO USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the
+	  TP6800 and TP6810 Topro chips.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_topro.
+
+config USB_GSPCA_TV8532
+	tristate "TV8532 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the TV8531 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_tv8532.
+
+config USB_GSPCA_VC032X
+	tristate "VC032X USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the VC032X chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_vc032x.
+
+config USB_GSPCA_VICAM
+	tristate "ViCam USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for the 3com homeconnect camera
+	  (vicam).
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_vicam.
+
+config USB_GSPCA_XIRLINK_CIT
+	tristate "Xirlink C-It USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for Xirlink C-It bases cameras.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_xirlink_cit.
+
+config USB_GSPCA_ZC3XX
+	tristate "ZC3XX USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the ZC3XX chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_zc3xx.
+
+endif
diff --git a/drivers/media/usb/gspca/Makefile b/drivers/media/usb/gspca/Makefile
new file mode 100644
index 0000000..c901da0
--- /dev/null
+++ b/drivers/media/usb/gspca/Makefile
@@ -0,0 +1,93 @@
+obj-$(CONFIG_USB_GSPCA)          += gspca_main.o
+obj-$(CONFIG_USB_GSPCA_BENQ)     += gspca_benq.o
+obj-$(CONFIG_USB_GSPCA_CONEX)    += gspca_conex.o
+obj-$(CONFIG_USB_GSPCA_CPIA1)    += gspca_cpia1.o
+obj-$(CONFIG_USB_GSPCA_ETOMS)    += gspca_etoms.o
+obj-$(CONFIG_USB_GSPCA_FINEPIX)  += gspca_finepix.o
+obj-$(CONFIG_USB_GSPCA_JEILINJ)  += gspca_jeilinj.o
+obj-$(CONFIG_USB_GSPCA_JL2005BCD) += gspca_jl2005bcd.o
+obj-$(CONFIG_USB_GSPCA_KINECT)   += gspca_kinect.o
+obj-$(CONFIG_USB_GSPCA_KONICA)   += gspca_konica.o
+obj-$(CONFIG_USB_GSPCA_MARS)     += gspca_mars.o
+obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o
+obj-$(CONFIG_USB_GSPCA_NW80X)    += gspca_nw80x.o
+obj-$(CONFIG_USB_GSPCA_OV519)    += gspca_ov519.o
+obj-$(CONFIG_USB_GSPCA_OV534)    += gspca_ov534.o
+obj-$(CONFIG_USB_GSPCA_OV534_9)  += gspca_ov534_9.o
+obj-$(CONFIG_USB_GSPCA_PAC207)   += gspca_pac207.o
+obj-$(CONFIG_USB_GSPCA_PAC7302)  += gspca_pac7302.o
+obj-$(CONFIG_USB_GSPCA_PAC7311)  += gspca_pac7311.o
+obj-$(CONFIG_USB_GSPCA_SE401)    += gspca_se401.o
+obj-$(CONFIG_USB_GSPCA_SN9C2028) += gspca_sn9c2028.o
+obj-$(CONFIG_USB_GSPCA_SN9C20X)  += gspca_sn9c20x.o
+obj-$(CONFIG_USB_GSPCA_SONIXB)   += gspca_sonixb.o
+obj-$(CONFIG_USB_GSPCA_SONIXJ)   += gspca_sonixj.o
+obj-$(CONFIG_USB_GSPCA_SPCA500)  += gspca_spca500.o
+obj-$(CONFIG_USB_GSPCA_SPCA501)  += gspca_spca501.o
+obj-$(CONFIG_USB_GSPCA_SPCA505)  += gspca_spca505.o
+obj-$(CONFIG_USB_GSPCA_SPCA506)  += gspca_spca506.o
+obj-$(CONFIG_USB_GSPCA_SPCA508)  += gspca_spca508.o
+obj-$(CONFIG_USB_GSPCA_SPCA561)  += gspca_spca561.o
+obj-$(CONFIG_USB_GSPCA_SPCA1528) += gspca_spca1528.o
+obj-$(CONFIG_USB_GSPCA_SQ905)    += gspca_sq905.o
+obj-$(CONFIG_USB_GSPCA_SQ905C)   += gspca_sq905c.o
+obj-$(CONFIG_USB_GSPCA_SQ930X)   += gspca_sq930x.o
+obj-$(CONFIG_USB_GSPCA_SUNPLUS)  += gspca_sunplus.o
+obj-$(CONFIG_USB_GSPCA_STK014)   += gspca_stk014.o
+obj-$(CONFIG_USB_GSPCA_STV0680)  += gspca_stv0680.o
+obj-$(CONFIG_USB_GSPCA_T613)     += gspca_t613.o
+obj-$(CONFIG_USB_GSPCA_TOPRO)    += gspca_topro.o
+obj-$(CONFIG_USB_GSPCA_TV8532)   += gspca_tv8532.o
+obj-$(CONFIG_USB_GSPCA_VC032X)   += gspca_vc032x.o
+obj-$(CONFIG_USB_GSPCA_VICAM)    += gspca_vicam.o
+obj-$(CONFIG_USB_GSPCA_XIRLINK_CIT) += gspca_xirlink_cit.o
+obj-$(CONFIG_USB_GSPCA_ZC3XX)    += gspca_zc3xx.o
+
+gspca_main-objs     := gspca.o autogain_functions.o
+gspca_benq-objs     := benq.o
+gspca_conex-objs    := conex.o
+gspca_cpia1-objs    := cpia1.o
+gspca_etoms-objs    := etoms.o
+gspca_finepix-objs  := finepix.o
+gspca_jeilinj-objs  := jeilinj.o
+gspca_jl2005bcd-objs  := jl2005bcd.o
+gspca_kinect-objs   := kinect.o
+gspca_konica-objs   := konica.o
+gspca_mars-objs     := mars.o
+gspca_mr97310a-objs := mr97310a.o
+gspca_nw80x-objs    := nw80x.o
+gspca_ov519-objs    := ov519.o
+gspca_ov534-objs    := ov534.o
+gspca_ov534_9-objs  := ov534_9.o
+gspca_pac207-objs   := pac207.o
+gspca_pac7302-objs  := pac7302.o
+gspca_pac7311-objs  := pac7311.o
+gspca_se401-objs    := se401.o
+gspca_sn9c2028-objs := sn9c2028.o
+gspca_sn9c20x-objs  := sn9c20x.o
+gspca_sonixb-objs   := sonixb.o
+gspca_sonixj-objs   := sonixj.o
+gspca_spca500-objs  := spca500.o
+gspca_spca501-objs  := spca501.o
+gspca_spca505-objs  := spca505.o
+gspca_spca506-objs  := spca506.o
+gspca_spca508-objs  := spca508.o
+gspca_spca561-objs  := spca561.o
+gspca_spca1528-objs := spca1528.o
+gspca_sq905-objs    := sq905.o
+gspca_sq905c-objs   := sq905c.o
+gspca_sq930x-objs   := sq930x.o
+gspca_stk014-objs   := stk014.o
+gspca_stv0680-objs  := stv0680.o
+gspca_sunplus-objs  := sunplus.o
+gspca_t613-objs     := t613.o
+gspca_topro-objs    := topro.o
+gspca_tv8532-objs   := tv8532.o
+gspca_vc032x-objs   := vc032x.o
+gspca_vicam-objs    := vicam.o
+gspca_xirlink_cit-objs := xirlink_cit.o
+gspca_zc3xx-objs    := zc3xx.o
+
+obj-$(CONFIG_USB_M5602)   += m5602/
+obj-$(CONFIG_USB_STV06XX) += stv06xx/
+obj-$(CONFIG_USB_GL860)   += gl860/
diff --git a/drivers/media/usb/gspca/autogain_functions.c b/drivers/media/usb/gspca/autogain_functions.c
new file mode 100644
index 0000000..67db674
--- /dev/null
+++ b/drivers/media/usb/gspca/autogain_functions.c
@@ -0,0 +1,178 @@
+/*
+ * Functions for auto gain.
+ *
+ * Copyright (C) 2010-2012 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "gspca.h"
+
+/* auto gain and exposure algorithm based on the knee algorithm described here:
+   http://ytse.tricolour.net/docs/LowLightOptimization.html
+
+   Returns 0 if no changes were made, 1 if the gain and or exposure settings
+   where changed. */
+int gspca_expo_autogain(
+			struct gspca_dev *gspca_dev,
+			int avg_lum,
+			int desired_avg_lum,
+			int deadzone,
+			int gain_knee,
+			int exposure_knee)
+{
+	s32 gain, orig_gain, exposure, orig_exposure;
+	int i, steps, retval = 0;
+
+	if (v4l2_ctrl_g_ctrl(gspca_dev->autogain) == 0)
+	        return 0;
+
+	orig_gain = gain = v4l2_ctrl_g_ctrl(gspca_dev->gain);
+	orig_exposure = exposure = v4l2_ctrl_g_ctrl(gspca_dev->exposure);
+
+	/* If we are of a multiple of deadzone, do multiple steps to reach the
+	   desired lumination fast (with the risc of a slight overshoot) */
+	steps = abs(desired_avg_lum - avg_lum) / deadzone;
+
+	PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
+		avg_lum, desired_avg_lum, steps);
+
+	for (i = 0; i < steps; i++) {
+		if (avg_lum > desired_avg_lum) {
+			if (gain > gain_knee)
+				gain--;
+			else if (exposure > exposure_knee)
+				exposure--;
+			else if (gain > gspca_dev->gain->default_value)
+				gain--;
+			else if (exposure > gspca_dev->exposure->minimum)
+				exposure--;
+			else if (gain > gspca_dev->gain->minimum)
+				gain--;
+			else
+				break;
+		} else {
+			if (gain < gspca_dev->gain->default_value)
+				gain++;
+			else if (exposure < exposure_knee)
+				exposure++;
+			else if (gain < gain_knee)
+				gain++;
+			else if (exposure < gspca_dev->exposure->maximum)
+				exposure++;
+			else if (gain < gspca_dev->gain->maximum)
+				gain++;
+			else
+				break;
+		}
+	}
+
+	if (gain != orig_gain) {
+	        v4l2_ctrl_s_ctrl(gspca_dev->gain, gain);
+		retval = 1;
+	}
+	if (exposure != orig_exposure) {
+	        v4l2_ctrl_s_ctrl(gspca_dev->exposure, exposure);
+		retval = 1;
+	}
+
+	if (retval)
+		PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d",
+			gain, exposure);
+	return retval;
+}
+EXPORT_SYMBOL(gspca_expo_autogain);
+
+/* Autogain + exposure algorithm for cameras with a coarse exposure control
+   (usually this means we can only control the clockdiv to change exposure)
+   As changing the clockdiv so that the fps drops from 30 to 15 fps for
+   example, will lead to a huge exposure change (it effectively doubles),
+   this algorithm normally tries to only adjust the gain (between 40 and
+   80 %) and if that does not help, only then changes exposure. This leads
+   to a much more stable image then using the knee algorithm which at
+   certain points of the knee graph will only try to adjust exposure,
+   which leads to oscilating as one exposure step is huge.
+
+   Returns 0 if no changes were made, 1 if the gain and or exposure settings
+   where changed. */
+int gspca_coarse_grained_expo_autogain(
+			struct gspca_dev *gspca_dev,
+			int avg_lum,
+			int desired_avg_lum,
+			int deadzone)
+{
+	s32 gain_low, gain_high, gain, orig_gain, exposure, orig_exposure;
+	int steps, retval = 0;
+
+	if (v4l2_ctrl_g_ctrl(gspca_dev->autogain) == 0)
+	        return 0;
+
+	orig_gain = gain = v4l2_ctrl_g_ctrl(gspca_dev->gain);
+	orig_exposure = exposure = v4l2_ctrl_g_ctrl(gspca_dev->exposure);
+
+	gain_low  = (gspca_dev->gain->maximum - gspca_dev->gain->minimum) /
+		    5 * 2 + gspca_dev->gain->minimum;
+	gain_high = (gspca_dev->gain->maximum - gspca_dev->gain->minimum) /
+		    5 * 4 + gspca_dev->gain->minimum;
+
+	/* If we are of a multiple of deadzone, do multiple steps to reach the
+	   desired lumination fast (with the risc of a slight overshoot) */
+	steps = (desired_avg_lum - avg_lum) / deadzone;
+
+	PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
+		avg_lum, desired_avg_lum, steps);
+
+	if ((gain + steps) > gain_high &&
+	    exposure < gspca_dev->exposure->maximum) {
+		gain = gain_high;
+		gspca_dev->exp_too_low_cnt++;
+		gspca_dev->exp_too_high_cnt = 0;
+	} else if ((gain + steps) < gain_low &&
+		   exposure > gspca_dev->exposure->minimum) {
+		gain = gain_low;
+		gspca_dev->exp_too_high_cnt++;
+		gspca_dev->exp_too_low_cnt = 0;
+	} else {
+		gain += steps;
+		if (gain > gspca_dev->gain->maximum)
+			gain = gspca_dev->gain->maximum;
+		else if (gain < gspca_dev->gain->minimum)
+			gain = gspca_dev->gain->minimum;
+		gspca_dev->exp_too_high_cnt = 0;
+		gspca_dev->exp_too_low_cnt = 0;
+	}
+
+	if (gspca_dev->exp_too_high_cnt > 3) {
+		exposure--;
+		gspca_dev->exp_too_high_cnt = 0;
+	} else if (gspca_dev->exp_too_low_cnt > 3) {
+		exposure++;
+		gspca_dev->exp_too_low_cnt = 0;
+	}
+
+	if (gain != orig_gain) {
+	        v4l2_ctrl_s_ctrl(gspca_dev->gain, gain);
+		retval = 1;
+	}
+	if (exposure != orig_exposure) {
+	        v4l2_ctrl_s_ctrl(gspca_dev->exposure, exposure);
+		retval = 1;
+	}
+
+	if (retval)
+		PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d",
+			gain, exposure);
+	return retval;
+}
+EXPORT_SYMBOL(gspca_coarse_grained_expo_autogain);
diff --git a/drivers/media/usb/gspca/autogain_functions.h b/drivers/media/usb/gspca/autogain_functions.h
new file mode 100644
index 0000000..d625eaf
--- /dev/null
+++ b/drivers/media/usb/gspca/autogain_functions.h
@@ -0,0 +1,183 @@
+/*
+ * Functions for auto gain.
+ *
+ * Copyright (C) 2010-2011 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef WANT_REGULAR_AUTOGAIN
+/* auto gain and exposure algorithm based on the knee algorithm described here:
+   http://ytse.tricolour.net/docs/LowLightOptimization.html
+
+   Returns 0 if no changes were made, 1 if the gain and or exposure settings
+   where changed. */
+static inline int auto_gain_n_exposure(
+			struct gspca_dev *gspca_dev,
+			int avg_lum,
+			int desired_avg_lum,
+			int deadzone,
+			int gain_knee,
+			int exposure_knee)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i, steps, gain, orig_gain, exposure, orig_exposure;
+	int retval = 0;
+
+	orig_gain = gain = sd->ctrls[GAIN].val;
+	orig_exposure = exposure = sd->ctrls[EXPOSURE].val;
+
+	/* If we are of a multiple of deadzone, do multiple steps to reach the
+	   desired lumination fast (with the risc of a slight overshoot) */
+	steps = abs(desired_avg_lum - avg_lum) / deadzone;
+
+	PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
+		avg_lum, desired_avg_lum, steps);
+
+	for (i = 0; i < steps; i++) {
+		if (avg_lum > desired_avg_lum) {
+			if (gain > gain_knee)
+				gain--;
+			else if (exposure > exposure_knee)
+				exposure--;
+			else if (gain > sd->ctrls[GAIN].def)
+				gain--;
+			else if (exposure > sd->ctrls[EXPOSURE].min)
+				exposure--;
+			else if (gain > sd->ctrls[GAIN].min)
+				gain--;
+			else
+				break;
+		} else {
+			if (gain < sd->ctrls[GAIN].def)
+				gain++;
+			else if (exposure < exposure_knee)
+				exposure++;
+			else if (gain < gain_knee)
+				gain++;
+			else if (exposure < sd->ctrls[EXPOSURE].max)
+				exposure++;
+			else if (gain < sd->ctrls[GAIN].max)
+				gain++;
+			else
+				break;
+		}
+	}
+
+	if (gain != orig_gain) {
+		sd->ctrls[GAIN].val = gain;
+		setgain(gspca_dev);
+		retval = 1;
+	}
+	if (exposure != orig_exposure) {
+		sd->ctrls[EXPOSURE].val = exposure;
+		setexposure(gspca_dev);
+		retval = 1;
+	}
+
+	if (retval)
+		PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d",
+			gain, exposure);
+	return retval;
+}
+#endif
+
+#ifdef WANT_COARSE_EXPO_AUTOGAIN
+/* Autogain + exposure algorithm for cameras with a coarse exposure control
+   (usually this means we can only control the clockdiv to change exposure)
+   As changing the clockdiv so that the fps drops from 30 to 15 fps for
+   example, will lead to a huge exposure change (it effectively doubles),
+   this algorithm normally tries to only adjust the gain (between 40 and
+   80 %) and if that does not help, only then changes exposure. This leads
+   to a much more stable image then using the knee algorithm which at
+   certain points of the knee graph will only try to adjust exposure,
+   which leads to oscilating as one exposure step is huge.
+
+   Note this assumes that the sd struct for the cam in question has
+   exp_too_low_cnt and exp_too_high_cnt int members for use by this function.
+
+   Returns 0 if no changes were made, 1 if the gain and or exposure settings
+   where changed. */
+static inline int coarse_grained_expo_autogain(
+			struct gspca_dev *gspca_dev,
+			int avg_lum,
+			int desired_avg_lum,
+			int deadzone)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int steps, gain, orig_gain, exposure, orig_exposure;
+	int gain_low, gain_high;
+	int retval = 0;
+
+	orig_gain = gain = sd->ctrls[GAIN].val;
+	orig_exposure = exposure = sd->ctrls[EXPOSURE].val;
+
+	gain_low = (sd->ctrls[GAIN].max - sd->ctrls[GAIN].min) / 5 * 2;
+	gain_low += sd->ctrls[GAIN].min;
+	gain_high = (sd->ctrls[GAIN].max - sd->ctrls[GAIN].min) / 5 * 4;
+	gain_high += sd->ctrls[GAIN].min;
+
+	/* If we are of a multiple of deadzone, do multiple steps to reach the
+	   desired lumination fast (with the risc of a slight overshoot) */
+	steps = (desired_avg_lum - avg_lum) / deadzone;
+
+	PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
+		avg_lum, desired_avg_lum, steps);
+
+	if ((gain + steps) > gain_high &&
+	    exposure < sd->ctrls[EXPOSURE].max) {
+		gain = gain_high;
+		sd->exp_too_low_cnt++;
+		sd->exp_too_high_cnt = 0;
+	} else if ((gain + steps) < gain_low &&
+		   exposure > sd->ctrls[EXPOSURE].min) {
+		gain = gain_low;
+		sd->exp_too_high_cnt++;
+		sd->exp_too_low_cnt = 0;
+	} else {
+		gain += steps;
+		if (gain > sd->ctrls[GAIN].max)
+			gain = sd->ctrls[GAIN].max;
+		else if (gain < sd->ctrls[GAIN].min)
+			gain = sd->ctrls[GAIN].min;
+		sd->exp_too_high_cnt = 0;
+		sd->exp_too_low_cnt = 0;
+	}
+
+	if (sd->exp_too_high_cnt > 3) {
+		exposure--;
+		sd->exp_too_high_cnt = 0;
+	} else if (sd->exp_too_low_cnt > 3) {
+		exposure++;
+		sd->exp_too_low_cnt = 0;
+	}
+
+	if (gain != orig_gain) {
+		sd->ctrls[GAIN].val = gain;
+		setgain(gspca_dev);
+		retval = 1;
+	}
+	if (exposure != orig_exposure) {
+		sd->ctrls[EXPOSURE].val = exposure;
+		setexposure(gspca_dev);
+		retval = 1;
+	}
+
+	if (retval)
+		PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d",
+			gain, exposure);
+	return retval;
+}
+#endif
diff --git a/drivers/media/usb/gspca/benq.c b/drivers/media/usb/gspca/benq.c
new file mode 100644
index 0000000..352f321
--- /dev/null
+++ b/drivers/media/usb/gspca/benq.c
@@ -0,0 +1,289 @@
+/*
+ * Benq DC E300 subdriver
+ *
+ * Copyright (C) 2009 Jean-Francois Moine (http://moinejf.free.fr)
+ *
+ * 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
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define MODULE_NAME "benq"
+
+#include "gspca.h"
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("Benq DC E300 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG},
+};
+
+static void sd_isoc_irq(struct urb *urb);
+
+/* -- write a register -- */
+static void reg_w(struct gspca_dev *gspca_dev,
+			u16 value, u16 index)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret;
+
+	if (gspca_dev->usb_err < 0)
+		return;
+	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+			0x02,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value,
+			index,
+			NULL,
+			0,
+			500);
+	if (ret < 0) {
+		pr_err("reg_w err %d\n", ret);
+		gspca_dev->usb_err = ret;
+	}
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	gspca_dev->cam.cam_mode = vga_mode;
+	gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
+	gspca_dev->cam.no_urb_create = 1;
+	return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+	return 0;
+}
+
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+	struct urb *urb;
+	int i, n;
+
+	/* create 4 URBs - 2 on endpoint 0x83 and 2 on 0x082 */
+#if MAX_NURBS < 4
+#error "Not enough URBs in the gspca table"
+#endif
+#define SD_PKT_SZ 64
+#define SD_NPKT 32
+	for (n = 0; n < 4; n++) {
+		urb = usb_alloc_urb(SD_NPKT, GFP_KERNEL);
+		if (!urb) {
+			pr_err("usb_alloc_urb failed\n");
+			return -ENOMEM;
+		}
+		gspca_dev->urb[n] = urb;
+		urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev,
+						SD_PKT_SZ * SD_NPKT,
+						GFP_KERNEL,
+						&urb->transfer_dma);
+
+		if (urb->transfer_buffer == NULL) {
+			pr_err("usb_alloc_coherent failed\n");
+			return -ENOMEM;
+		}
+		urb->dev = gspca_dev->dev;
+		urb->context = gspca_dev;
+		urb->transfer_buffer_length = SD_PKT_SZ * SD_NPKT;
+		urb->pipe = usb_rcvisocpipe(gspca_dev->dev,
+					n & 1 ? 0x82 : 0x83);
+		urb->transfer_flags = URB_ISO_ASAP
+					| URB_NO_TRANSFER_DMA_MAP;
+		urb->interval = 1;
+		urb->complete = sd_isoc_irq;
+		urb->number_of_packets = SD_NPKT;
+		for (i = 0; i < SD_NPKT; i++) {
+			urb->iso_frame_desc[i].length = SD_PKT_SZ;
+			urb->iso_frame_desc[i].offset = SD_PKT_SZ * i;
+		}
+	}
+
+	return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	struct usb_interface *intf;
+
+	reg_w(gspca_dev, 0x003c, 0x0003);
+	reg_w(gspca_dev, 0x003c, 0x0004);
+	reg_w(gspca_dev, 0x003c, 0x0005);
+	reg_w(gspca_dev, 0x003c, 0x0006);
+	reg_w(gspca_dev, 0x003c, 0x0007);
+
+	intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
+	usb_set_interface(gspca_dev->dev, gspca_dev->iface,
+					intf->num_altsetting - 1);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			u8 *data,		/* isoc packet */
+			int len)		/* iso packet length */
+{
+	/* unused */
+}
+
+/* reception of an URB */
+static void sd_isoc_irq(struct urb *urb)
+{
+	struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
+	struct urb *urb0;
+	u8 *data;
+	int i, st;
+
+	PDEBUG(D_PACK, "sd isoc irq");
+	if (!gspca_dev->streaming)
+		return;
+	if (urb->status != 0) {
+		if (urb->status == -ESHUTDOWN)
+			return;		/* disconnection */
+#ifdef CONFIG_PM
+		if (gspca_dev->frozen)
+			return;
+#endif
+		pr_err("urb status: %d\n", urb->status);
+		return;
+	}
+
+	/* if this is a control URN (ep 0x83), wait */
+	if (urb == gspca_dev->urb[0] || urb == gspca_dev->urb[2])
+		return;
+
+	/* scan both received URBs */
+	if (urb == gspca_dev->urb[1])
+		urb0 = gspca_dev->urb[0];
+	else
+		urb0 = gspca_dev->urb[2];
+	for (i = 0; i < urb->number_of_packets; i++) {
+
+		/* check the packet status and length */
+		if (urb0->iso_frame_desc[i].actual_length != SD_PKT_SZ
+		    || urb->iso_frame_desc[i].actual_length != SD_PKT_SZ) {
+			PDEBUG(D_ERR, "ISOC bad lengths %d / %d",
+				urb0->iso_frame_desc[i].actual_length,
+				urb->iso_frame_desc[i].actual_length);
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+			continue;
+		}
+		st = urb0->iso_frame_desc[i].status;
+		if (st == 0)
+			st = urb->iso_frame_desc[i].status;
+		if (st) {
+			pr_err("ISOC data error: [%d] status=%d\n",
+				i, st);
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+			continue;
+		}
+
+		/*
+		 * The images are received in URBs of different endpoints
+		 * (0x83 and 0x82).
+		 * Image pieces in URBs of ep 0x83 are continuated in URBs of
+		 * ep 0x82 of the same index.
+		 * The packets in the URBs of endpoint 0x83 start with:
+		 *	- 80 ba/bb 00 00 = start of image followed by 'ff d8'
+		 *	- 04 ba/bb oo oo = image piece
+		 *		where 'oo oo' is the image offset
+						(not cheked)
+		 *	- (other -> bad frame)
+		 * The images are JPEG encoded with full header and
+		 * normal ff escape.
+		 * The end of image ('ff d9') may occur in any URB.
+		 * (not cheked)
+		 */
+		data = (u8 *) urb0->transfer_buffer
+					+ urb0->iso_frame_desc[i].offset;
+		if (data[0] == 0x80 && (data[1] & 0xfe) == 0xba) {
+
+			/* new image */
+			gspca_frame_add(gspca_dev, LAST_PACKET,
+					NULL, 0);
+			gspca_frame_add(gspca_dev, FIRST_PACKET,
+					data + 4, SD_PKT_SZ - 4);
+		} else if (data[0] == 0x04 && (data[1] & 0xfe) == 0xba) {
+			gspca_frame_add(gspca_dev, INTER_PACKET,
+					data + 4, SD_PKT_SZ - 4);
+		} else {
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+			continue;
+		}
+		data = (u8 *) urb->transfer_buffer
+					+ urb->iso_frame_desc[i].offset;
+			gspca_frame_add(gspca_dev, INTER_PACKET,
+					data, SD_PKT_SZ);
+	}
+
+	/* resubmit the URBs */
+	st = usb_submit_urb(urb0, GFP_ATOMIC);
+	if (st < 0)
+		pr_err("usb_submit_urb(0) ret %d\n", st);
+	st = usb_submit_urb(urb, GFP_ATOMIC);
+	if (st < 0)
+		pr_err("usb_submit_urb() ret %d\n", st);
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.config = sd_config,
+	.init = sd_init,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+static const struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x04a5, 0x3035)},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+	.reset_resume = gspca_resume,
+#endif
+};
+
+module_usb_driver(sd_driver);
diff --git a/drivers/media/usb/gspca/conex.c b/drivers/media/usb/gspca/conex.c
new file mode 100644
index 0000000..c9052f2
--- /dev/null
+++ b/drivers/media/usb/gspca/conex.c
@@ -0,0 +1,966 @@
+/*
+ *		Connexant Cx11646 library
+ *		Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define MODULE_NAME "conex"
+
+#include "gspca.h"
+#define CONEX_CAM 1		/* special JPEG header */
+#include "jpeg.h"
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA USB Conexant Camera Driver");
+MODULE_LICENSE("GPL");
+
+#define QUALITY 50
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+	struct v4l2_ctrl *brightness;
+	struct v4l2_ctrl *contrast;
+	struct v4l2_ctrl *sat;
+
+	u8 jpeg_hdr[JPEG_HDR_SZ];
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 176,
+		.sizeimage = 176 * 144 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 3},
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 2},
+	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 352,
+		.sizeimage = 352 * 288 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 0},
+};
+
+/* the read bytes are found in gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+		  __u16 index,
+		  __u16 len)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+#ifdef GSPCA_DEBUG
+	if (len > USB_BUF_SZ) {
+		pr_err("reg_r: buffer overflow\n");
+		return;
+	}
+#endif
+	usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			0,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,
+			index, gspca_dev->usb_buf, len,
+			500);
+	PDEBUG(D_USBI, "reg read [%02x] -> %02x ..",
+			index, gspca_dev->usb_buf[0]);
+}
+
+/* the bytes to write are in gspca_dev->usb_buf */
+static void reg_w_val(struct gspca_dev *gspca_dev,
+			__u16 index,
+			__u8 val)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	gspca_dev->usb_buf[0] = val;
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			0,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,
+			index, gspca_dev->usb_buf, 1, 500);
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+		  __u16 index,
+		  const __u8 *buffer,
+		  __u16 len)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+#ifdef GSPCA_DEBUG
+	if (len > USB_BUF_SZ) {
+		pr_err("reg_w: buffer overflow\n");
+		return;
+	}
+	PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer);
+#endif
+	memcpy(gspca_dev->usb_buf, buffer, len);
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			0,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,
+			index, gspca_dev->usb_buf, len, 500);
+}
+
+static const __u8 cx_sensor_init[][4] = {
+	{0x88, 0x11, 0x01, 0x01},
+	{0x88, 0x12, 0x70, 0x01},
+	{0x88, 0x0f, 0x00, 0x01},
+	{0x88, 0x05, 0x01, 0x01},
+	{}
+};
+
+static const __u8 cx11646_fw1[][3] = {
+	{0x00, 0x02, 0x00},
+	{0x01, 0x43, 0x00},
+	{0x02, 0xA7, 0x00},
+	{0x03, 0x8B, 0x01},
+	{0x04, 0xE9, 0x02},
+	{0x05, 0x08, 0x04},
+	{0x06, 0x08, 0x05},
+	{0x07, 0x07, 0x06},
+	{0x08, 0xE7, 0x06},
+	{0x09, 0xC6, 0x07},
+	{0x0A, 0x86, 0x08},
+	{0x0B, 0x46, 0x09},
+	{0x0C, 0x05, 0x0A},
+	{0x0D, 0xA5, 0x0A},
+	{0x0E, 0x45, 0x0B},
+	{0x0F, 0xE5, 0x0B},
+	{0x10, 0x85, 0x0C},
+	{0x11, 0x25, 0x0D},
+	{0x12, 0xC4, 0x0D},
+	{0x13, 0x45, 0x0E},
+	{0x14, 0xE4, 0x0E},
+	{0x15, 0x64, 0x0F},
+	{0x16, 0xE4, 0x0F},
+	{0x17, 0x64, 0x10},
+	{0x18, 0xE4, 0x10},
+	{0x19, 0x64, 0x11},
+	{0x1A, 0xE4, 0x11},
+	{0x1B, 0x64, 0x12},
+	{0x1C, 0xE3, 0x12},
+	{0x1D, 0x44, 0x13},
+	{0x1E, 0xC3, 0x13},
+	{0x1F, 0x24, 0x14},
+	{0x20, 0xA3, 0x14},
+	{0x21, 0x04, 0x15},
+	{0x22, 0x83, 0x15},
+	{0x23, 0xE3, 0x15},
+	{0x24, 0x43, 0x16},
+	{0x25, 0xA4, 0x16},
+	{0x26, 0x23, 0x17},
+	{0x27, 0x83, 0x17},
+	{0x28, 0xE3, 0x17},
+	{0x29, 0x43, 0x18},
+	{0x2A, 0xA3, 0x18},
+	{0x2B, 0x03, 0x19},
+	{0x2C, 0x63, 0x19},
+	{0x2D, 0xC3, 0x19},
+	{0x2E, 0x22, 0x1A},
+	{0x2F, 0x63, 0x1A},
+	{0x30, 0xC3, 0x1A},
+	{0x31, 0x23, 0x1B},
+	{0x32, 0x83, 0x1B},
+	{0x33, 0xE2, 0x1B},
+	{0x34, 0x23, 0x1C},
+	{0x35, 0x83, 0x1C},
+	{0x36, 0xE2, 0x1C},
+	{0x37, 0x23, 0x1D},
+	{0x38, 0x83, 0x1D},
+	{0x39, 0xE2, 0x1D},
+	{0x3A, 0x23, 0x1E},
+	{0x3B, 0x82, 0x1E},
+	{0x3C, 0xC3, 0x1E},
+	{0x3D, 0x22, 0x1F},
+	{0x3E, 0x63, 0x1F},
+	{0x3F, 0xC1, 0x1F},
+	{}
+};
+static void cx11646_fw(struct gspca_dev*gspca_dev)
+{
+	int i = 0;
+
+	reg_w_val(gspca_dev, 0x006a, 0x02);
+	while (cx11646_fw1[i][1]) {
+		reg_w(gspca_dev, 0x006b, cx11646_fw1[i], 3);
+		i++;
+	}
+	reg_w_val(gspca_dev, 0x006a, 0x00);
+}
+
+static const __u8 cxsensor[] = {
+	0x88, 0x12, 0x70, 0x01,
+	0x88, 0x0d, 0x02, 0x01,
+	0x88, 0x0f, 0x00, 0x01,
+	0x88, 0x03, 0x71, 0x01, 0x88, 0x04, 0x00, 0x01,	/* 3 */
+	0x88, 0x02, 0x10, 0x01,
+	0x88, 0x00, 0xD4, 0x01, 0x88, 0x01, 0x01, 0x01,	/* 5 */
+	0x88, 0x0B, 0x00, 0x01,
+	0x88, 0x0A, 0x0A, 0x01,
+	0x88, 0x00, 0x08, 0x01, 0x88, 0x01, 0x00, 0x01,	/* 8 */
+	0x88, 0x05, 0x01, 0x01,
+	0xA1, 0x18, 0x00, 0x01,
+	0x00
+};
+
+static const __u8 reg20[] = { 0x10, 0x42, 0x81, 0x19, 0xd3, 0xff, 0xa7, 0xff };
+static const __u8 reg28[] = { 0x87, 0x00, 0x87, 0x00, 0x8f, 0xff, 0xea, 0xff };
+static const __u8 reg10[] = { 0xb1, 0xb1 };
+static const __u8 reg71a[] = { 0x08, 0x18, 0x0a, 0x1e };	/* 640 */
+static const __u8 reg71b[] = { 0x04, 0x0c, 0x05, 0x0f };
+	/* 352{0x04,0x0a,0x06,0x12}; //352{0x05,0x0e,0x06,0x11}; //352 */
+static const __u8 reg71c[] = { 0x02, 0x07, 0x03, 0x09 };
+					/* 320{0x04,0x0c,0x05,0x0f}; //320 */
+static const __u8 reg71d[] = { 0x02, 0x07, 0x03, 0x09 };	/* 176 */
+static const __u8 reg7b[] = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff };
+
+static void cx_sensor(struct gspca_dev*gspca_dev)
+{
+	int i = 0;
+	int length;
+	const __u8 *ptsensor = cxsensor;
+
+	reg_w(gspca_dev, 0x0020, reg20, 8);
+	reg_w(gspca_dev, 0x0028, reg28, 8);
+	reg_w(gspca_dev, 0x0010, reg10, 2);
+	reg_w_val(gspca_dev, 0x0092, 0x03);
+
+	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+	case 0:
+		reg_w(gspca_dev, 0x0071, reg71a, 4);
+		break;
+	case 1:
+		reg_w(gspca_dev, 0x0071, reg71b, 4);
+		break;
+	default:
+/*	case 2: */
+		reg_w(gspca_dev, 0x0071, reg71c, 4);
+		break;
+	case 3:
+		reg_w(gspca_dev, 0x0071, reg71d, 4);
+		break;
+	}
+	reg_w(gspca_dev, 0x007b, reg7b, 6);
+	reg_w_val(gspca_dev, 0x00f8, 0x00);
+	reg_w(gspca_dev, 0x0010, reg10, 2);
+	reg_w_val(gspca_dev, 0x0098, 0x41);
+	for (i = 0; i < 11; i++) {
+		if (i == 3 || i == 5 || i == 8)
+			length = 8;
+		else
+			length = 4;
+		reg_w(gspca_dev, 0x00e5, ptsensor, length);
+		if (length == 4)
+			reg_r(gspca_dev, 0x00e8, 1);
+		else
+			reg_r(gspca_dev, 0x00e8, length);
+		ptsensor += length;
+	}
+	reg_r(gspca_dev, 0x00e7, 8);
+}
+
+static const __u8 cx_inits_176[] = {
+	0x33, 0x81, 0xB0, 0x00, 0x90, 0x00, 0x0A, 0x03,	/* 176x144 */
+	0x00, 0x03, 0x03, 0x03, 0x1B, 0x05, 0x30, 0x03,
+	0x65, 0x15, 0x18, 0x25, 0x03, 0x25, 0x08, 0x30,
+	0x3B, 0x25, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00,
+	0xDC, 0xFF, 0xEE, 0xFF, 0xC5, 0xFF, 0xBF, 0xFF,
+	0xF7, 0xFF, 0x88, 0xFF, 0x66, 0x02, 0x28, 0x02,
+	0x1E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static const __u8 cx_inits_320[] = {
+	0x7f, 0x7f, 0x40, 0x01, 0xf0, 0x00, 0x02, 0x01,
+	0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x02, 0x01,
+	0x65, 0x45, 0xfa, 0x4c, 0x2c, 0xdf, 0xb9, 0x81,
+	0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+	0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
+	0xf5, 0xff, 0x6d, 0xff, 0xf6, 0x01, 0x43, 0x02,
+	0xd3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static const __u8 cx_inits_352[] = {
+	0x2e, 0x7c, 0x60, 0x01, 0x20, 0x01, 0x05, 0x03,
+	0x00, 0x06, 0x03, 0x06, 0x1b, 0x10, 0x05, 0x3b,
+	0x30, 0x25, 0x18, 0x25, 0x08, 0x30, 0x03, 0x25,
+	0x3b, 0x30, 0x25, 0x1b, 0x10, 0x05, 0x00, 0x00,
+	0xe3, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
+	0xf5, 0xff, 0x6b, 0xff, 0xee, 0x01, 0x43, 0x02,
+	0xe4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static const __u8 cx_inits_640[] = {
+	0x7e, 0x7e, 0x80, 0x02, 0xe0, 0x01, 0x01, 0x01,
+	0x00, 0x02, 0x01, 0x02, 0x10, 0x30, 0x01, 0x01,
+	0x65, 0x45, 0xf7, 0x52, 0x2c, 0xdf, 0xb9, 0x81,
+	0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+	0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
+	0xf6, 0xff, 0x7b, 0xff, 0x01, 0x02, 0x43, 0x02,
+	0x77, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static void cx11646_initsize(struct gspca_dev *gspca_dev)
+{
+	const __u8 *cxinit;
+	static const __u8 reg12[] = { 0x08, 0x05, 0x07, 0x04, 0x24 };
+	static const __u8 reg17[] =
+			{ 0x0a, 0x00, 0xf2, 0x01, 0x0f, 0x00, 0x97, 0x02 };
+
+	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+	case 0:
+		cxinit = cx_inits_640;
+		break;
+	case 1:
+		cxinit = cx_inits_352;
+		break;
+	default:
+/*	case 2: */
+		cxinit = cx_inits_320;
+		break;
+	case 3:
+		cxinit = cx_inits_176;
+		break;
+	}
+	reg_w_val(gspca_dev, 0x009a, 0x01);
+	reg_w_val(gspca_dev, 0x0010, 0x10);
+	reg_w(gspca_dev, 0x0012, reg12, 5);
+	reg_w(gspca_dev, 0x0017, reg17, 8);
+	reg_w_val(gspca_dev, 0x00c0, 0x00);
+	reg_w_val(gspca_dev, 0x00c1, 0x04);
+	reg_w_val(gspca_dev, 0x00c2, 0x04);
+
+	reg_w(gspca_dev, 0x0061, cxinit, 8);
+	cxinit += 8;
+	reg_w(gspca_dev, 0x00ca, cxinit, 8);
+	cxinit += 8;
+	reg_w(gspca_dev, 0x00d2, cxinit, 8);
+	cxinit += 8;
+	reg_w(gspca_dev, 0x00da, cxinit, 6);
+	cxinit += 8;
+	reg_w(gspca_dev, 0x0041, cxinit, 8);
+	cxinit += 8;
+	reg_w(gspca_dev, 0x0049, cxinit, 8);
+	cxinit += 8;
+	reg_w(gspca_dev, 0x0051, cxinit, 2);
+
+	reg_r(gspca_dev, 0x0010, 1);
+}
+
+static const __u8 cx_jpeg_init[][8] = {
+	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x15},	/* 1 */
+	{0x0f, 0x10, 0x12, 0x10, 0x0d, 0x15, 0x12, 0x11},
+	{0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35, 0x22},
+	{0x20, 0x1d, 0x1d, 0x20, 0x41, 0x2e, 0x31, 0x26},
+	{0x35, 0x4d, 0x43, 0x51, 0x4f, 0x4b, 0x43, 0x4a},
+	{0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A, 0x73},
+	{0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73, 0x7D},
+	{0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95, 0xA0},
+	{0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83, 0x01},
+	{0x15, 0x0F, 0x10, 0x12, 0x10, 0x0D, 0x15, 0x12},
+	{0x11, 0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35},
+	{0x22, 0x20, 0x1D, 0x1D, 0x20, 0x41, 0x2E, 0x31},
+	{0x26, 0x35, 0x4D, 0x43, 0x51, 0x4F, 0x4B, 0x43},
+	{0x4A, 0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A},
+	{0x73, 0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73},
+	{0x7D, 0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95},
+	{0xA0, 0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83},
+	{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, 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, 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, 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, 0x20, 0x00, 0x1F},
+	{0x02, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00},
+	{0x00, 0x00, 0x11, 0x00, 0x11, 0x22, 0x00, 0x22},
+	{0x22, 0x11, 0x22, 0x22, 0x11, 0x33, 0x33, 0x11},
+	{0x44, 0x66, 0x22, 0x55, 0x66, 0xFF, 0xDD, 0x00},
+	{0x04, 0x00, 0x14, 0xFF, 0xC0, 0x00, 0x11, 0x08},
+	{0x00, 0xF0, 0x01, 0x40, 0x03, 0x00, 0x21, 0x00},
+	{0x01, 0x11, 0x01, 0x02, 0x11, 0x01, 0xFF, 0xDA},
+	{0x00, 0x0C, 0x03, 0x00, 0x00, 0x01, 0x11, 0x02},
+	{0x11, 0x00, 0x3F, 0x00, 0xFF, 0xD9, 0x00, 0x00}	/* 79 */
+};
+
+
+static const __u8 cxjpeg_640[][8] = {
+	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x10},	/* 1 */
+	{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, 0x01},
+	{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, 0x20, 0x00, 0x1F, 0x00, 0x83, 0x00, 0x00},
+	{0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+	{0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+	{0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+	{0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x28, 0xFF},
+	{0xC0, 0x00, 0x11, 0x08, 0x01, 0xE0, 0x02, 0x80},
+	{0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+	{0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+	{0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+	{0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}	/* 27 */
+};
+static const __u8 cxjpeg_352[][8] = {
+	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d},
+	{0x09, 0x09, 0x0b, 0x09, 0x08, 0x0D, 0x0b, 0x0a},
+	{0x0b, 0x0e, 0x0d, 0x0d, 0x0f, 0x13, 0x1f, 0x14},
+	{0x13, 0x11, 0x11, 0x13, 0x26, 0x1b, 0x1d, 0x17},
+	{0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C},
+	{0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44},
+	{0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A},
+	{0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F},
+	{0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01},
+	{0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B},
+	{0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F},
+	{0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D},
+	{0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28},
+	{0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35},
+	{0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44},
+	{0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58},
+	{0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D},
+	{0xFF, 0x20, 0x00, 0x1F, 0x01, 0x83, 0x00, 0x00},
+	{0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+	{0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+	{0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+	{0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x16, 0xFF},
+	{0xC0, 0x00, 0x11, 0x08, 0x01, 0x20, 0x01, 0x60},
+	{0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+	{0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+	{0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+	{0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+static const __u8 cxjpeg_320[][8] = {
+	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x05},
+	{0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04, 0x04},
+	{0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0c, 0x08},
+	{0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b, 0x0b, 0x09},
+	{0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0f, 0x11},
+	{0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14, 0x1A},
+	{0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A, 0x1D},
+	{0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22, 0x24},
+	{0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E, 0x01},
+	{0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04},
+	{0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0C},
+	{0x08, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0B, 0x0B},
+	{0x09, 0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0F},
+	{0x11, 0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14},
+	{0x1A, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A},
+	{0x1D, 0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22},
+	{0x24, 0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E},
+	{0xFF, 0x20, 0x00, 0x1F, 0x02, 0x0C, 0x00, 0x00},
+	{0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+	{0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+	{0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+	{0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x14, 0xFF},
+	{0xC0, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x01, 0x40},
+	{0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+	{0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+	{0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+	{0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}	/* 27 */
+};
+static const __u8 cxjpeg_176[][8] = {
+	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d},
+	{0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B, 0x0A},
+	{0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F, 0x14},
+	{0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D, 0x17},
+	{0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C},
+	{0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44},
+	{0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A},
+	{0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F},
+	{0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01},
+	{0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B},
+	{0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F},
+	{0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D},
+	{0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28},
+	{0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35},
+	{0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44},
+	{0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58},
+	{0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D},
+	{0xFF, 0x20, 0x00, 0x1F, 0x03, 0xA1, 0x00, 0x00},
+	{0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+	{0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+	{0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+	{0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x0B, 0xFF},
+	{0xC0, 0x00, 0x11, 0x08, 0x00, 0x90, 0x00, 0xB0},
+	{0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+	{0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+	{0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+	{0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+/* 640 take with the zcx30x part */
+static const __u8 cxjpeg_qtable[][8] = {
+	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x08},
+	{0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07, 0x07},
+	{0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14, 0x0a},
+	{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, 0x01},
+	{0x09, 0x09, 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0a},
+	{0x0a, 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, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}	/* 18 */
+};
+
+
+static void cx11646_jpegInit(struct gspca_dev*gspca_dev)
+{
+	int i;
+	int length;
+
+	reg_w_val(gspca_dev, 0x00c0, 0x01);
+	reg_w_val(gspca_dev, 0x00c3, 0x00);
+	reg_w_val(gspca_dev, 0x00c0, 0x00);
+	reg_r(gspca_dev, 0x0001, 1);
+	length = 8;
+	for (i = 0; i < 79; i++) {
+		if (i == 78)
+			length = 6;
+		reg_w(gspca_dev, 0x0008, cx_jpeg_init[i], length);
+	}
+	reg_r(gspca_dev, 0x0002, 1);
+	reg_w_val(gspca_dev, 0x0055, 0x14);
+}
+
+static const __u8 reg12[] = { 0x0a, 0x05, 0x07, 0x04, 0x19 };
+static const __u8 regE5_8[] =
+		{ 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 };
+static const __u8 regE5a[] = { 0x88, 0x0a, 0x0c, 0x01 };
+static const __u8 regE5b[] = { 0x88, 0x0b, 0x12, 0x01 };
+static const __u8 regE5c[] = { 0x88, 0x05, 0x01, 0x01 };
+static const __u8 reg51[] = { 0x77, 0x03 };
+#define reg70 0x03
+
+static void cx11646_jpeg(struct gspca_dev*gspca_dev)
+{
+	int i;
+	int length;
+	__u8 Reg55;
+	int retry;
+
+	reg_w_val(gspca_dev, 0x00c0, 0x01);
+	reg_w_val(gspca_dev, 0x00c3, 0x00);
+	reg_w_val(gspca_dev, 0x00c0, 0x00);
+	reg_r(gspca_dev, 0x0001, 1);
+	length = 8;
+	switch (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv) {
+	case 0:
+		for (i = 0; i < 27; i++) {
+			if (i == 26)
+				length = 2;
+			reg_w(gspca_dev, 0x0008, cxjpeg_640[i], length);
+		}
+		Reg55 = 0x28;
+		break;
+	case 1:
+		for (i = 0; i < 27; i++) {
+			if (i == 26)
+				length = 2;
+			reg_w(gspca_dev, 0x0008, cxjpeg_352[i], length);
+		}
+		Reg55 = 0x16;
+		break;
+	default:
+/*	case 2: */
+		for (i = 0; i < 27; i++) {
+			if (i == 26)
+				length = 2;
+			reg_w(gspca_dev, 0x0008, cxjpeg_320[i], length);
+		}
+		Reg55 = 0x14;
+		break;
+	case 3:
+		for (i = 0; i < 27; i++) {
+			if (i == 26)
+				length = 2;
+			reg_w(gspca_dev, 0x0008, cxjpeg_176[i], length);
+		}
+		Reg55 = 0x0B;
+		break;
+	}
+
+	reg_r(gspca_dev, 0x0002, 1);
+	reg_w_val(gspca_dev, 0x0055, Reg55);
+	reg_r(gspca_dev, 0x0002, 1);
+	reg_w(gspca_dev, 0x0010, reg10, 2);
+	reg_w_val(gspca_dev, 0x0054, 0x02);
+	reg_w_val(gspca_dev, 0x0054, 0x01);
+	reg_w_val(gspca_dev, 0x0000, 0x94);
+	reg_w_val(gspca_dev, 0x0053, 0xc0);
+	reg_w_val(gspca_dev, 0x00fc, 0xe1);
+	reg_w_val(gspca_dev, 0x0000, 0x00);
+	/* wait for completion */
+	retry = 50;
+	do {
+		reg_r(gspca_dev, 0x0002, 1);
+							/* 0x07 until 0x00 */
+		if (gspca_dev->usb_buf[0] == 0x00)
+			break;
+		reg_w_val(gspca_dev, 0x0053, 0x00);
+	} while (--retry);
+	if (retry == 0)
+		PDEBUG(D_ERR, "Damned Errors sending jpeg Table");
+	/* send the qtable now */
+	reg_r(gspca_dev, 0x0001, 1);		/* -> 0x18 */
+	length = 8;
+	for (i = 0; i < 18; i++) {
+		if (i == 17)
+			length = 2;
+		reg_w(gspca_dev, 0x0008, cxjpeg_qtable[i], length);
+
+	}
+	reg_r(gspca_dev, 0x0002, 1);	/* 0x00 */
+	reg_r(gspca_dev, 0x0053, 1);	/* 0x00 */
+	reg_w_val(gspca_dev, 0x0054, 0x02);
+	reg_w_val(gspca_dev, 0x0054, 0x01);
+	reg_w_val(gspca_dev, 0x0000, 0x94);
+	reg_w_val(gspca_dev, 0x0053, 0xc0);
+
+	reg_r(gspca_dev, 0x0038, 1);		/* 0x40 */
+	reg_r(gspca_dev, 0x0038, 1);		/* 0x40 */
+	reg_r(gspca_dev, 0x001f, 1);		/* 0x38 */
+	reg_w(gspca_dev, 0x0012, reg12, 5);
+	reg_w(gspca_dev, 0x00e5, regE5_8, 8);
+	reg_r(gspca_dev, 0x00e8, 8);
+	reg_w(gspca_dev, 0x00e5, regE5a, 4);
+	reg_r(gspca_dev, 0x00e8, 1);		/* 0x00 */
+	reg_w_val(gspca_dev, 0x009a, 0x01);
+	reg_w(gspca_dev, 0x00e5, regE5b, 4);
+	reg_r(gspca_dev, 0x00e8, 1);		/* 0x00 */
+	reg_w(gspca_dev, 0x00e5, regE5c, 4);
+	reg_r(gspca_dev, 0x00e8, 1);		/* 0x00 */
+
+	reg_w(gspca_dev, 0x0051, reg51, 2);
+	reg_w(gspca_dev, 0x0010, reg10, 2);
+	reg_w_val(gspca_dev, 0x0070, reg70);
+}
+
+static void cx11646_init1(struct gspca_dev *gspca_dev)
+{
+	int i = 0;
+
+	reg_w_val(gspca_dev, 0x0010, 0x00);
+	reg_w_val(gspca_dev, 0x0053, 0x00);
+	reg_w_val(gspca_dev, 0x0052, 0x00);
+	reg_w_val(gspca_dev, 0x009b, 0x2f);
+	reg_w_val(gspca_dev, 0x009c, 0x10);
+	reg_r(gspca_dev, 0x0098, 1);
+	reg_w_val(gspca_dev, 0x0098, 0x40);
+	reg_r(gspca_dev, 0x0099, 1);
+	reg_w_val(gspca_dev, 0x0099, 0x07);
+	reg_w_val(gspca_dev, 0x0039, 0x40);
+	reg_w_val(gspca_dev, 0x003c, 0xff);
+	reg_w_val(gspca_dev, 0x003f, 0x1f);
+	reg_w_val(gspca_dev, 0x003d, 0x40);
+/*	reg_w_val(gspca_dev, 0x003d, 0x60); */
+	reg_r(gspca_dev, 0x0099, 1);			/* ->0x07 */
+
+	while (cx_sensor_init[i][0]) {
+		reg_w_val(gspca_dev, 0x00e5, cx_sensor_init[i][0]);
+		reg_r(gspca_dev, 0x00e8, 1);		/* -> 0x00 */
+		if (i == 1) {
+			reg_w_val(gspca_dev, 0x00ed, 0x01);
+			reg_r(gspca_dev, 0x00ed, 1);	/* -> 0x01 */
+		}
+		i++;
+	}
+	reg_w_val(gspca_dev, 0x00c3, 0x00);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct cam *cam;
+
+	cam = &gspca_dev->cam;
+	cam->cam_mode = vga_mode;
+	cam->nmodes = ARRAY_SIZE(vga_mode);
+	return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+	cx11646_init1(gspca_dev);
+	cx11646_initsize(gspca_dev);
+	cx11646_fw(gspca_dev);
+	cx_sensor(gspca_dev);
+	cx11646_jpegInit(gspca_dev);
+	return 0;
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* create the JPEG header */
+	jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+			0x22);		/* JPEG 411 */
+	jpeg_set_qual(sd->jpeg_hdr, QUALITY);
+
+	cx11646_initsize(gspca_dev);
+	cx11646_fw(gspca_dev);
+	cx_sensor(gspca_dev);
+	cx11646_jpeg(gspca_dev);
+	return 0;
+}
+
+/* called on streamoff with alt 0 and on disconnect */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+	int retry = 50;
+
+	if (!gspca_dev->present)
+		return;
+	reg_w_val(gspca_dev, 0x0000, 0x00);
+	reg_r(gspca_dev, 0x0002, 1);
+	reg_w_val(gspca_dev, 0x0053, 0x00);
+
+	while (retry--) {
+/*		reg_r(gspca_dev, 0x0002, 1);*/
+		reg_r(gspca_dev, 0x0053, 1);
+		if (gspca_dev->usb_buf[0] == 0)
+			break;
+	}
+	reg_w_val(gspca_dev, 0x0000, 0x00);
+	reg_r(gspca_dev, 0x0002, 1);
+
+	reg_w_val(gspca_dev, 0x0010, 0x00);
+	reg_r(gspca_dev, 0x0033, 1);
+	reg_w_val(gspca_dev, 0x00fc, 0xe0);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (data[0] == 0xff && data[1] == 0xd8) {
+
+		/* start of frame */
+		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+
+		/* put the JPEG header in the new frame */
+		gspca_frame_add(gspca_dev, FIRST_PACKET,
+				sd->jpeg_hdr, JPEG_HDR_SZ);
+		data += 2;
+		len -= 2;
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev, s32 val, s32 sat)
+{
+	__u8 regE5cbx[] = { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 };
+	__u8 reg51c[2];
+
+	regE5cbx[2] = val;
+	reg_w(gspca_dev, 0x00e5, regE5cbx, 8);
+	reg_r(gspca_dev, 0x00e8, 8);
+	reg_w(gspca_dev, 0x00e5, regE5c, 4);
+	reg_r(gspca_dev, 0x00e8, 1);		/* 0x00 */
+
+	reg51c[0] = 0x77;
+	reg51c[1] = sat;
+	reg_w(gspca_dev, 0x0051, reg51c, 2);
+	reg_w(gspca_dev, 0x0010, reg10, 2);
+	reg_w_val(gspca_dev, 0x0070, reg70);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev, s32 val, s32 sat)
+{
+	__u8 regE5acx[] = { 0x88, 0x0a, 0x0c, 0x01 };	/* seem MSB */
+/*	__u8 regE5bcx[] = { 0x88, 0x0b, 0x12, 0x01};	 * LSB */
+	__u8 reg51c[2];
+
+	regE5acx[2] = val;
+	reg_w(gspca_dev, 0x00e5, regE5acx, 4);
+	reg_r(gspca_dev, 0x00e8, 1);		/* 0x00 */
+	reg51c[0] = 0x77;
+	reg51c[1] = sat;
+	reg_w(gspca_dev, 0x0051, reg51c, 2);
+	reg_w(gspca_dev, 0x0010, reg10, 2);
+	reg_w_val(gspca_dev, 0x0070, reg70);
+}
+
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct gspca_dev *gspca_dev =
+		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+	struct sd *sd = (struct sd *)gspca_dev;
+
+	gspca_dev->usb_err = 0;
+
+	if (!gspca_dev->streaming)
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		setbrightness(gspca_dev, ctrl->val, sd->sat->cur.val);
+		break;
+	case V4L2_CID_CONTRAST:
+		setcontrast(gspca_dev, ctrl->val, sd->sat->cur.val);
+		break;
+	case V4L2_CID_SATURATION:
+		setbrightness(gspca_dev, sd->brightness->cur.val, ctrl->val);
+		setcontrast(gspca_dev, sd->contrast->cur.val, ctrl->val);
+		break;
+	}
+	return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+	.s_ctrl = sd_s_ctrl,
+};
+
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *)gspca_dev;
+	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+
+	gspca_dev->vdev.ctrl_handler = hdl;
+	v4l2_ctrl_handler_init(hdl, 3);
+	sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 255, 1, 0xd4);
+	sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_CONTRAST, 0x0a, 0x1f, 1, 0x0c);
+	sd->sat = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 7, 1, 3);
+	if (hdl->error) {
+		pr_err("Could not initialize controls\n");
+		return hdl->error;
+	}
+	return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.config = sd_config,
+	.init = sd_init,
+	.init_controls = sd_init_controls,
+	.start = sd_start,
+	.stop0 = sd_stop0,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+static const struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x0572, 0x0041)},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+	.reset_resume = gspca_resume,
+#endif
+};
+
+module_usb_driver(sd_driver);
diff --git a/drivers/media/usb/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c
new file mode 100644
index 0000000..2499a88
--- /dev/null
+++ b/drivers/media/usb/gspca/cpia1.c
@@ -0,0 +1,1905 @@
+/*
+ * cpia CPiA (1) gspca driver
+ *
+ * Copyright (C) 2010-2011 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This module is adapted from the in kernel v4l1 cpia driver which is :
+ *
+ * (C) Copyright 1999-2000 Peter Pregler
+ * (C) Copyright 1999-2000 Scott J. Bertin
+ * (C) Copyright 1999-2000 Johannes Erdfelt <johannes@erdfelt.com>
+ * (C) Copyright 2000 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define MODULE_NAME "cpia1"
+
+#include <linux/input.h>
+#include "gspca.h"
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Vision CPiA");
+MODULE_LICENSE("GPL");
+
+/* constant value's */
+#define MAGIC_0		0x19
+#define MAGIC_1		0x68
+#define DATA_IN		0xc0
+#define DATA_OUT	0x40
+#define VIDEOSIZE_QCIF	0	/* 176x144 */
+#define VIDEOSIZE_CIF	1	/* 352x288 */
+#define SUBSAMPLE_420	0
+#define SUBSAMPLE_422	1
+#define YUVORDER_YUYV	0
+#define YUVORDER_UYVY	1
+#define NOT_COMPRESSED	0
+#define COMPRESSED	1
+#define NO_DECIMATION	0
+#define DECIMATION_ENAB	1
+#define EOI		0xff	/* End Of Image */
+#define EOL		0xfd	/* End Of Line */
+#define FRAME_HEADER_SIZE	64
+
+/* Image grab modes */
+#define CPIA_GRAB_SINGLE	0
+#define CPIA_GRAB_CONTINEOUS	1
+
+/* Compression parameters */
+#define CPIA_COMPRESSION_NONE	0
+#define CPIA_COMPRESSION_AUTO	1
+#define CPIA_COMPRESSION_MANUAL	2
+#define CPIA_COMPRESSION_TARGET_QUALITY         0
+#define CPIA_COMPRESSION_TARGET_FRAMERATE       1
+
+/* Return offsets for GetCameraState */
+#define SYSTEMSTATE	0
+#define GRABSTATE	1
+#define STREAMSTATE	2
+#define FATALERROR	3
+#define CMDERROR	4
+#define DEBUGFLAGS	5
+#define VPSTATUS	6
+#define ERRORCODE	7
+
+/* SystemState */
+#define UNINITIALISED_STATE	0
+#define PASS_THROUGH_STATE	1
+#define LO_POWER_STATE		2
+#define HI_POWER_STATE		3
+#define WARM_BOOT_STATE		4
+
+/* GrabState */
+#define GRAB_IDLE		0
+#define GRAB_ACTIVE		1
+#define GRAB_DONE		2
+
+/* StreamState */
+#define STREAM_NOT_READY	0
+#define STREAM_READY		1
+#define STREAM_OPEN		2
+#define STREAM_PAUSED		3
+#define STREAM_FINISHED		4
+
+/* Fatal Error, CmdError, and DebugFlags */
+#define CPIA_FLAG	  1
+#define SYSTEM_FLAG	  2
+#define INT_CTRL_FLAG	  4
+#define PROCESS_FLAG	  8
+#define COM_FLAG	 16
+#define VP_CTRL_FLAG	 32
+#define CAPTURE_FLAG	 64
+#define DEBUG_FLAG	128
+
+/* VPStatus */
+#define VP_STATE_OK			0x00
+
+#define VP_STATE_FAILED_VIDEOINIT	0x01
+#define VP_STATE_FAILED_AECACBINIT	0x02
+#define VP_STATE_AEC_MAX		0x04
+#define VP_STATE_ACB_BMAX		0x08
+
+#define VP_STATE_ACB_RMIN		0x10
+#define VP_STATE_ACB_GMIN		0x20
+#define VP_STATE_ACB_RMAX		0x40
+#define VP_STATE_ACB_GMAX		0x80
+
+/* default (minimum) compensation values */
+#define COMP_RED        220
+#define COMP_GREEN1     214
+#define COMP_GREEN2     COMP_GREEN1
+#define COMP_BLUE       230
+
+/* exposure status */
+#define EXPOSURE_VERY_LIGHT 0
+#define EXPOSURE_LIGHT      1
+#define EXPOSURE_NORMAL     2
+#define EXPOSURE_DARK       3
+#define EXPOSURE_VERY_DARK  4
+
+#define CPIA_MODULE_CPIA			(0 << 5)
+#define CPIA_MODULE_SYSTEM			(1 << 5)
+#define CPIA_MODULE_VP_CTRL			(5 << 5)
+#define CPIA_MODULE_CAPTURE			(6 << 5)
+#define CPIA_MODULE_DEBUG			(7 << 5)
+
+#define INPUT (DATA_IN << 8)
+#define OUTPUT (DATA_OUT << 8)
+
+#define CPIA_COMMAND_GetCPIAVersion	(INPUT | CPIA_MODULE_CPIA | 1)
+#define CPIA_COMMAND_GetPnPID		(INPUT | CPIA_MODULE_CPIA | 2)
+#define CPIA_COMMAND_GetCameraStatus	(INPUT | CPIA_MODULE_CPIA | 3)
+#define CPIA_COMMAND_GotoHiPower	(OUTPUT | CPIA_MODULE_CPIA | 4)
+#define CPIA_COMMAND_GotoLoPower	(OUTPUT | CPIA_MODULE_CPIA | 5)
+#define CPIA_COMMAND_GotoSuspend	(OUTPUT | CPIA_MODULE_CPIA | 7)
+#define CPIA_COMMAND_GotoPassThrough	(OUTPUT | CPIA_MODULE_CPIA | 8)
+#define CPIA_COMMAND_ModifyCameraStatus	(OUTPUT | CPIA_MODULE_CPIA | 10)
+
+#define CPIA_COMMAND_ReadVCRegs		(INPUT | CPIA_MODULE_SYSTEM | 1)
+#define CPIA_COMMAND_WriteVCReg		(OUTPUT | CPIA_MODULE_SYSTEM | 2)
+#define CPIA_COMMAND_ReadMCPorts	(INPUT | CPIA_MODULE_SYSTEM | 3)
+#define CPIA_COMMAND_WriteMCPort	(OUTPUT | CPIA_MODULE_SYSTEM | 4)
+#define CPIA_COMMAND_SetBaudRate	(OUTPUT | CPIA_MODULE_SYSTEM | 5)
+#define CPIA_COMMAND_SetECPTiming	(OUTPUT | CPIA_MODULE_SYSTEM | 6)
+#define CPIA_COMMAND_ReadIDATA		(INPUT | CPIA_MODULE_SYSTEM | 7)
+#define CPIA_COMMAND_WriteIDATA		(OUTPUT | CPIA_MODULE_SYSTEM | 8)
+#define CPIA_COMMAND_GenericCall	(OUTPUT | CPIA_MODULE_SYSTEM | 9)
+#define CPIA_COMMAND_I2CStart		(OUTPUT | CPIA_MODULE_SYSTEM | 10)
+#define CPIA_COMMAND_I2CStop		(OUTPUT | CPIA_MODULE_SYSTEM | 11)
+#define CPIA_COMMAND_I2CWrite		(OUTPUT | CPIA_MODULE_SYSTEM | 12)
+#define CPIA_COMMAND_I2CRead		(INPUT | CPIA_MODULE_SYSTEM | 13)
+
+#define CPIA_COMMAND_GetVPVersion	(INPUT | CPIA_MODULE_VP_CTRL | 1)
+#define CPIA_COMMAND_ResetFrameCounter	(INPUT | CPIA_MODULE_VP_CTRL | 2)
+#define CPIA_COMMAND_SetColourParams	(OUTPUT | CPIA_MODULE_VP_CTRL | 3)
+#define CPIA_COMMAND_SetExposure	(OUTPUT | CPIA_MODULE_VP_CTRL | 4)
+#define CPIA_COMMAND_SetColourBalance	(OUTPUT | CPIA_MODULE_VP_CTRL | 6)
+#define CPIA_COMMAND_SetSensorFPS	(OUTPUT | CPIA_MODULE_VP_CTRL | 7)
+#define CPIA_COMMAND_SetVPDefaults	(OUTPUT | CPIA_MODULE_VP_CTRL | 8)
+#define CPIA_COMMAND_SetApcor		(OUTPUT | CPIA_MODULE_VP_CTRL | 9)
+#define CPIA_COMMAND_SetFlickerCtrl	(OUTPUT | CPIA_MODULE_VP_CTRL | 10)
+#define CPIA_COMMAND_SetVLOffset	(OUTPUT | CPIA_MODULE_VP_CTRL | 11)
+#define CPIA_COMMAND_GetColourParams	(INPUT | CPIA_MODULE_VP_CTRL | 16)
+#define CPIA_COMMAND_GetColourBalance	(INPUT | CPIA_MODULE_VP_CTRL | 17)
+#define CPIA_COMMAND_GetExposure	(INPUT | CPIA_MODULE_VP_CTRL | 18)
+#define CPIA_COMMAND_SetSensorMatrix	(OUTPUT | CPIA_MODULE_VP_CTRL | 19)
+#define CPIA_COMMAND_ColourBars		(OUTPUT | CPIA_MODULE_VP_CTRL | 25)
+#define CPIA_COMMAND_ReadVPRegs		(INPUT | CPIA_MODULE_VP_CTRL | 30)
+#define CPIA_COMMAND_WriteVPReg		(OUTPUT | CPIA_MODULE_VP_CTRL | 31)
+
+#define CPIA_COMMAND_GrabFrame		(OUTPUT | CPIA_MODULE_CAPTURE | 1)
+#define CPIA_COMMAND_UploadFrame	(OUTPUT | CPIA_MODULE_CAPTURE | 2)
+#define CPIA_COMMAND_SetGrabMode	(OUTPUT | CPIA_MODULE_CAPTURE | 3)
+#define CPIA_COMMAND_InitStreamCap	(OUTPUT | CPIA_MODULE_CAPTURE | 4)
+#define CPIA_COMMAND_FiniStreamCap	(OUTPUT | CPIA_MODULE_CAPTURE | 5)
+#define CPIA_COMMAND_StartStreamCap	(OUTPUT | CPIA_MODULE_CAPTURE | 6)
+#define CPIA_COMMAND_EndStreamCap	(OUTPUT | CPIA_MODULE_CAPTURE | 7)
+#define CPIA_COMMAND_SetFormat		(OUTPUT | CPIA_MODULE_CAPTURE | 8)
+#define CPIA_COMMAND_SetROI		(OUTPUT | CPIA_MODULE_CAPTURE | 9)
+#define CPIA_COMMAND_SetCompression	(OUTPUT | CPIA_MODULE_CAPTURE | 10)
+#define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
+#define CPIA_COMMAND_SetYUVThresh	(OUTPUT | CPIA_MODULE_CAPTURE | 12)
+#define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
+#define CPIA_COMMAND_DiscardFrame	(OUTPUT | CPIA_MODULE_CAPTURE | 14)
+#define CPIA_COMMAND_GrabReset		(OUTPUT | CPIA_MODULE_CAPTURE | 15)
+
+#define CPIA_COMMAND_OutputRS232	(OUTPUT | CPIA_MODULE_DEBUG | 1)
+#define CPIA_COMMAND_AbortProcess	(OUTPUT | CPIA_MODULE_DEBUG | 4)
+#define CPIA_COMMAND_SetDramPage	(OUTPUT | CPIA_MODULE_DEBUG | 5)
+#define CPIA_COMMAND_StartDramUpload	(OUTPUT | CPIA_MODULE_DEBUG | 6)
+#define CPIA_COMMAND_StartDummyDtream	(OUTPUT | CPIA_MODULE_DEBUG | 8)
+#define CPIA_COMMAND_AbortStream	(OUTPUT | CPIA_MODULE_DEBUG | 9)
+#define CPIA_COMMAND_DownloadDRAM	(OUTPUT | CPIA_MODULE_DEBUG | 10)
+#define CPIA_COMMAND_Null		(OUTPUT | CPIA_MODULE_DEBUG | 11)
+
+#define ROUND_UP_EXP_FOR_FLICKER 15
+
+/* Constants for automatic frame rate adjustment */
+#define MAX_EXP       302
+#define MAX_EXP_102   255
+#define LOW_EXP       140
+#define VERY_LOW_EXP   70
+#define TC             94
+#define	EXP_ACC_DARK   50
+#define	EXP_ACC_LIGHT  90
+#define HIGH_COMP_102 160
+#define MAX_COMP      239
+#define DARK_TIME       3
+#define LIGHT_TIME      3
+
+#define FIRMWARE_VERSION(x, y) (sd->params.version.firmwareVersion == (x) && \
+				sd->params.version.firmwareRevision == (y))
+
+#define CPIA1_CID_COMP_TARGET (V4L2_CTRL_CLASS_USER + 0x1000)
+#define BRIGHTNESS_DEF 50
+#define CONTRAST_DEF 48
+#define SATURATION_DEF 50
+#define FREQ_DEF V4L2_CID_POWER_LINE_FREQUENCY_50HZ
+#define ILLUMINATORS_1_DEF 0
+#define ILLUMINATORS_2_DEF 0
+#define COMP_TARGET_DEF CPIA_COMPRESSION_TARGET_QUALITY
+
+/* Developer's Guide Table 5 p 3-34
+ * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
+static u8 flicker_jumps[2][2][4] =
+{ { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
+  { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
+};
+
+struct cam_params {
+	struct {
+		u8 firmwareVersion;
+		u8 firmwareRevision;
+		u8 vcVersion;
+		u8 vcRevision;
+	} version;
+	struct {
+		u16 vendor;
+		u16 product;
+		u16 deviceRevision;
+	} pnpID;
+	struct {
+		u8 vpVersion;
+		u8 vpRevision;
+		u16 cameraHeadID;
+	} vpVersion;
+	struct {
+		u8 systemState;
+		u8 grabState;
+		u8 streamState;
+		u8 fatalError;
+		u8 cmdError;
+		u8 debugFlags;
+		u8 vpStatus;
+		u8 errorCode;
+	} status;
+	struct {
+		u8 brightness;
+		u8 contrast;
+		u8 saturation;
+	} colourParams;
+	struct {
+		u8 gainMode;
+		u8 expMode;
+		u8 compMode;
+		u8 centreWeight;
+		u8 gain;
+		u8 fineExp;
+		u8 coarseExpLo;
+		u8 coarseExpHi;
+		u8 redComp;
+		u8 green1Comp;
+		u8 green2Comp;
+		u8 blueComp;
+	} exposure;
+	struct {
+		u8 balanceMode;
+		u8 redGain;
+		u8 greenGain;
+		u8 blueGain;
+	} colourBalance;
+	struct {
+		u8 divisor;
+		u8 baserate;
+	} sensorFps;
+	struct {
+		u8 gain1;
+		u8 gain2;
+		u8 gain4;
+		u8 gain8;
+	} apcor;
+	struct {
+		u8 disabled;
+		u8 flickerMode;
+		u8 coarseJump;
+		u8 allowableOverExposure;
+	} flickerControl;
+	struct {
+		u8 gain1;
+		u8 gain2;
+		u8 gain4;
+		u8 gain8;
+	} vlOffset;
+	struct {
+		u8 mode;
+		u8 decimation;
+	} compression;
+	struct {
+		u8 frTargeting;
+		u8 targetFR;
+		u8 targetQ;
+	} compressionTarget;
+	struct {
+		u8 yThreshold;
+		u8 uvThreshold;
+	} yuvThreshold;
+	struct {
+		u8 hysteresis;
+		u8 threshMax;
+		u8 smallStep;
+		u8 largeStep;
+		u8 decimationHysteresis;
+		u8 frDiffStepThresh;
+		u8 qDiffStepThresh;
+		u8 decimationThreshMod;
+	} compressionParams;
+	struct {
+		u8 videoSize;		/* CIF/QCIF */
+		u8 subSample;
+		u8 yuvOrder;
+	} format;
+	struct {                        /* Intel QX3 specific data */
+		u8 qx3_detected;        /* a QX3 is present */
+		u8 toplight;            /* top light lit , R/W */
+		u8 bottomlight;         /* bottom light lit, R/W */
+		u8 button;              /* snapshot button pressed (R/O) */
+		u8 cradled;             /* microscope is in cradle (R/O) */
+	} qx3;
+	struct {
+		u8 colStart;		/* skip first 8*colStart pixels */
+		u8 colEnd;		/* finish at 8*colEnd pixels */
+		u8 rowStart;		/* skip first 4*rowStart lines */
+		u8 rowEnd;		/* finish at 4*rowEnd lines */
+	} roi;
+	u8 ecpTiming;
+	u8 streamStartLine;
+};
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;		/* !! must be the first item */
+	struct cam_params params;		/* camera settings */
+
+	atomic_t cam_exposure;
+	atomic_t fps;
+	int exposure_count;
+	u8 exposure_status;
+	struct v4l2_ctrl *freq;
+	u8 mainsFreq;				/* 0 = 50hz, 1 = 60hz */
+	u8 first_frame;
+};
+
+static const struct v4l2_pix_format mode[] = {
+	{160, 120, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,
+		/* The sizeimage is trial and error, as with low framerates
+		   the camera will pad out usb frames, making the image
+		   data larger then strictly necessary */
+		.bytesperline = 160,
+		.sizeimage = 65536,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 3},
+	{176, 144, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,
+		.bytesperline = 172,
+		.sizeimage = 65536,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 2},
+	{320, 240, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 262144,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{352, 288, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,
+		.bytesperline = 352,
+		.sizeimage = 262144,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+
+/**********************************************************************
+ *
+ * General functions
+ *
+ **********************************************************************/
+
+static int cpia_usb_transferCmd(struct gspca_dev *gspca_dev, u8 *command)
+{
+	u8 requesttype;
+	unsigned int pipe;
+	int ret, databytes = command[6] | (command[7] << 8);
+	/* Sometimes we see spurious EPIPE errors */
+	int retries = 3;
+
+	if (command[0] == DATA_IN) {
+		pipe = usb_rcvctrlpipe(gspca_dev->dev, 0);
+		requesttype = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+	} else if (command[0] == DATA_OUT) {
+		pipe = usb_sndctrlpipe(gspca_dev->dev, 0);
+		requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+	} else {
+		PDEBUG(D_ERR, "Unexpected first byte of command: %x",
+		       command[0]);
+		return -EINVAL;
+	}
+
+retry:
+	ret = usb_control_msg(gspca_dev->dev, pipe,
+			      command[1],
+			      requesttype,
+			      command[2] | (command[3] << 8),
+			      command[4] | (command[5] << 8),
+			      gspca_dev->usb_buf, databytes, 1000);
+
+	if (ret < 0)
+		pr_err("usb_control_msg %02x, error %d\n", command[1], ret);
+
+	if (ret == -EPIPE && retries > 0) {
+		retries--;
+		goto retry;
+	}
+
+	return (ret < 0) ? ret : 0;
+}
+
+/* send an arbitrary command to the camera */
+static int do_command(struct gspca_dev *gspca_dev, u16 command,
+		      u8 a, u8 b, u8 c, u8 d)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret, datasize;
+	u8 cmd[8];
+
+	switch (command) {
+	case CPIA_COMMAND_GetCPIAVersion:
+	case CPIA_COMMAND_GetPnPID:
+	case CPIA_COMMAND_GetCameraStatus:
+	case CPIA_COMMAND_GetVPVersion:
+	case CPIA_COMMAND_GetColourParams:
+	case CPIA_COMMAND_GetColourBalance:
+	case CPIA_COMMAND_GetExposure:
+		datasize = 8;
+		break;
+	case CPIA_COMMAND_ReadMCPorts:
+	case CPIA_COMMAND_ReadVCRegs:
+		datasize = 4;
+		break;
+	default:
+		datasize = 0;
+		break;
+	}
+
+	cmd[0] = command >> 8;
+	cmd[1] = command & 0xff;
+	cmd[2] = a;
+	cmd[3] = b;
+	cmd[4] = c;
+	cmd[5] = d;
+	cmd[6] = datasize;
+	cmd[7] = 0;
+
+	ret = cpia_usb_transferCmd(gspca_dev, cmd);
+	if (ret)
+		return ret;
+
+	switch (command) {
+	case CPIA_COMMAND_GetCPIAVersion:
+		sd->params.version.firmwareVersion = gspca_dev->usb_buf[0];
+		sd->params.version.firmwareRevision = gspca_dev->usb_buf[1];
+		sd->params.version.vcVersion = gspca_dev->usb_buf[2];
+		sd->params.version.vcRevision = gspca_dev->usb_buf[3];
+		break;
+	case CPIA_COMMAND_GetPnPID:
+		sd->params.pnpID.vendor =
+			gspca_dev->usb_buf[0] | (gspca_dev->usb_buf[1] << 8);
+		sd->params.pnpID.product =
+			gspca_dev->usb_buf[2] | (gspca_dev->usb_buf[3] << 8);
+		sd->params.pnpID.deviceRevision =
+			gspca_dev->usb_buf[4] | (gspca_dev->usb_buf[5] << 8);
+		break;
+	case CPIA_COMMAND_GetCameraStatus:
+		sd->params.status.systemState = gspca_dev->usb_buf[0];
+		sd->params.status.grabState = gspca_dev->usb_buf[1];
+		sd->params.status.streamState = gspca_dev->usb_buf[2];
+		sd->params.status.fatalError = gspca_dev->usb_buf[3];
+		sd->params.status.cmdError = gspca_dev->usb_buf[4];
+		sd->params.status.debugFlags = gspca_dev->usb_buf[5];
+		sd->params.status.vpStatus = gspca_dev->usb_buf[6];
+		sd->params.status.errorCode = gspca_dev->usb_buf[7];
+		break;
+	case CPIA_COMMAND_GetVPVersion:
+		sd->params.vpVersion.vpVersion = gspca_dev->usb_buf[0];
+		sd->params.vpVersion.vpRevision = gspca_dev->usb_buf[1];
+		sd->params.vpVersion.cameraHeadID =
+			gspca_dev->usb_buf[2] | (gspca_dev->usb_buf[3] << 8);
+		break;
+	case CPIA_COMMAND_GetColourParams:
+		sd->params.colourParams.brightness = gspca_dev->usb_buf[0];
+		sd->params.colourParams.contrast = gspca_dev->usb_buf[1];
+		sd->params.colourParams.saturation = gspca_dev->usb_buf[2];
+		break;
+	case CPIA_COMMAND_GetColourBalance:
+		sd->params.colourBalance.redGain = gspca_dev->usb_buf[0];
+		sd->params.colourBalance.greenGain = gspca_dev->usb_buf[1];
+		sd->params.colourBalance.blueGain = gspca_dev->usb_buf[2];
+		break;
+	case CPIA_COMMAND_GetExposure:
+		sd->params.exposure.gain = gspca_dev->usb_buf[0];
+		sd->params.exposure.fineExp = gspca_dev->usb_buf[1];
+		sd->params.exposure.coarseExpLo = gspca_dev->usb_buf[2];
+		sd->params.exposure.coarseExpHi = gspca_dev->usb_buf[3];
+		sd->params.exposure.redComp = gspca_dev->usb_buf[4];
+		sd->params.exposure.green1Comp = gspca_dev->usb_buf[5];
+		sd->params.exposure.green2Comp = gspca_dev->usb_buf[6];
+		sd->params.exposure.blueComp = gspca_dev->usb_buf[7];
+		break;
+
+	case CPIA_COMMAND_ReadMCPorts:
+		/* test button press */
+		a = ((gspca_dev->usb_buf[1] & 0x02) == 0);
+		if (a != sd->params.qx3.button) {
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+			input_report_key(gspca_dev->input_dev, KEY_CAMERA, a);
+			input_sync(gspca_dev->input_dev);
+#endif
+	        	sd->params.qx3.button = a;
+		}
+		if (sd->params.qx3.button) {
+			/* button pressed - unlock the latch */
+			do_command(gspca_dev, CPIA_COMMAND_WriteMCPort,
+				   3, 0xdf, 0xdf, 0);
+			do_command(gspca_dev, CPIA_COMMAND_WriteMCPort,
+				   3, 0xff, 0xff, 0);
+		}
+
+		/* test whether microscope is cradled */
+		sd->params.qx3.cradled = ((gspca_dev->usb_buf[2] & 0x40) == 0);
+		break;
+	}
+
+	return 0;
+}
+
+/* send a command to the camera with an additional data transaction */
+static int do_command_extended(struct gspca_dev *gspca_dev, u16 command,
+			       u8 a, u8 b, u8 c, u8 d,
+			       u8 e, u8 f, u8 g, u8 h,
+			       u8 i, u8 j, u8 k, u8 l)
+{
+	u8 cmd[8];
+
+	cmd[0] = command >> 8;
+	cmd[1] = command & 0xff;
+	cmd[2] = a;
+	cmd[3] = b;
+	cmd[4] = c;
+	cmd[5] = d;
+	cmd[6] = 8;
+	cmd[7] = 0;
+	gspca_dev->usb_buf[0] = e;
+	gspca_dev->usb_buf[1] = f;
+	gspca_dev->usb_buf[2] = g;
+	gspca_dev->usb_buf[3] = h;
+	gspca_dev->usb_buf[4] = i;
+	gspca_dev->usb_buf[5] = j;
+	gspca_dev->usb_buf[6] = k;
+	gspca_dev->usb_buf[7] = l;
+
+	return cpia_usb_transferCmd(gspca_dev, cmd);
+}
+
+/*  find_over_exposure
+ *  Finds a suitable value of OverExposure for use with SetFlickerCtrl
+ *  Some calculation is required because this value changes with the brightness
+ *  set with SetColourParameters
+ *
+ *  Parameters: Brightness - last brightness value set with SetColourParameters
+ *
+ *  Returns: OverExposure value to use with SetFlickerCtrl
+ */
+#define FLICKER_MAX_EXPOSURE                    250
+#define FLICKER_ALLOWABLE_OVER_EXPOSURE         146
+#define FLICKER_BRIGHTNESS_CONSTANT             59
+static int find_over_exposure(int brightness)
+{
+	int MaxAllowableOverExposure, OverExposure;
+
+	MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -
+				   FLICKER_BRIGHTNESS_CONSTANT;
+
+	if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE)
+		OverExposure = MaxAllowableOverExposure;
+	else
+		OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE;
+
+	return OverExposure;
+}
+#undef FLICKER_MAX_EXPOSURE
+#undef FLICKER_ALLOWABLE_OVER_EXPOSURE
+#undef FLICKER_BRIGHTNESS_CONSTANT
+
+/* initialise cam_data structure  */
+static void reset_camera_params(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam_params *params = &sd->params;
+
+	/* The following parameter values are the defaults from
+	 * "Software Developer's Guide for CPiA Cameras".  Any changes
+	 * to the defaults are noted in comments. */
+	params->colourParams.brightness = BRIGHTNESS_DEF;
+	params->colourParams.contrast = CONTRAST_DEF;
+	params->colourParams.saturation = SATURATION_DEF;
+	params->exposure.gainMode = 4;
+	params->exposure.expMode = 2;		/* AEC */
+	params->exposure.compMode = 1;
+	params->exposure.centreWeight = 1;
+	params->exposure.gain = 0;
+	params->exposure.fineExp = 0;
+	params->exposure.coarseExpLo = 185;
+	params->exposure.coarseExpHi = 0;
+	params->exposure.redComp = COMP_RED;
+	params->exposure.green1Comp = COMP_GREEN1;
+	params->exposure.green2Comp = COMP_GREEN2;
+	params->exposure.blueComp = COMP_BLUE;
+	params->colourBalance.balanceMode = 2;	/* ACB */
+	params->colourBalance.redGain = 32;
+	params->colourBalance.greenGain = 6;
+	params->colourBalance.blueGain = 92;
+	params->apcor.gain1 = 0x18;
+	params->apcor.gain2 = 0x16;
+	params->apcor.gain4 = 0x24;
+	params->apcor.gain8 = 0x34;
+	params->vlOffset.gain1 = 20;
+	params->vlOffset.gain2 = 24;
+	params->vlOffset.gain4 = 26;
+	params->vlOffset.gain8 = 26;
+	params->compressionParams.hysteresis = 3;
+	params->compressionParams.threshMax = 11;
+	params->compressionParams.smallStep = 1;
+	params->compressionParams.largeStep = 3;
+	params->compressionParams.decimationHysteresis = 2;
+	params->compressionParams.frDiffStepThresh = 5;
+	params->compressionParams.qDiffStepThresh = 3;
+	params->compressionParams.decimationThreshMod = 2;
+	/* End of default values from Software Developer's Guide */
+
+	/* Set Sensor FPS to 15fps. This seems better than 30fps
+	 * for indoor lighting. */
+	params->sensorFps.divisor = 1;
+	params->sensorFps.baserate = 1;
+
+	params->flickerControl.flickerMode = 0;
+	params->flickerControl.disabled = 1;
+	params->flickerControl.coarseJump =
+		flicker_jumps[sd->mainsFreq]
+			     [params->sensorFps.baserate]
+			     [params->sensorFps.divisor];
+	params->flickerControl.allowableOverExposure =
+		find_over_exposure(params->colourParams.brightness);
+
+	params->yuvThreshold.yThreshold = 6; /* From windows driver */
+	params->yuvThreshold.uvThreshold = 6; /* From windows driver */
+
+	params->format.subSample = SUBSAMPLE_420;
+	params->format.yuvOrder = YUVORDER_YUYV;
+
+	params->compression.mode = CPIA_COMPRESSION_AUTO;
+	params->compression.decimation = NO_DECIMATION;
+
+	params->compressionTarget.frTargeting = COMP_TARGET_DEF;
+	params->compressionTarget.targetFR = 15; /* From windows driver */
+	params->compressionTarget.targetQ = 5; /* From windows driver */
+
+	params->qx3.qx3_detected = 0;
+	params->qx3.toplight = 0;
+	params->qx3.bottomlight = 0;
+	params->qx3.button = 0;
+	params->qx3.cradled = 0;
+}
+
+static void printstatus(struct cam_params *params)
+{
+	PDEBUG(D_PROBE, "status: %02x %02x %02x %02x %02x %02x %02x %02x",
+	       params->status.systemState, params->status.grabState,
+	       params->status.streamState, params->status.fatalError,
+	       params->status.cmdError, params->status.debugFlags,
+	       params->status.vpStatus, params->status.errorCode);
+}
+
+static int goto_low_power(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+
+	ret = do_command(gspca_dev, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0);
+	if (ret)
+		return ret;
+
+	ret = do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
+	if (ret)
+		return ret;
+
+	if (sd->params.status.systemState != LO_POWER_STATE) {
+		if (sd->params.status.systemState != WARM_BOOT_STATE) {
+			PDEBUG(D_ERR,
+			       "unexpected state after lo power cmd: %02x",
+			       sd->params.status.systemState);
+			printstatus(&sd->params);
+		}
+		return -EIO;
+	}
+
+	PDEBUG(D_CONF, "camera now in LOW power state");
+	return 0;
+}
+
+static int goto_high_power(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+
+	ret = do_command(gspca_dev, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0);
+	if (ret)
+		return ret;
+
+	msleep_interruptible(40);	/* windows driver does it too */
+
+	if (signal_pending(current))
+		return -EINTR;
+
+	do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
+	if (ret)
+		return ret;
+
+	if (sd->params.status.systemState != HI_POWER_STATE) {
+		PDEBUG(D_ERR, "unexpected state after hi power cmd: %02x",
+			       sd->params.status.systemState);
+		printstatus(&sd->params);
+		return -EIO;
+	}
+
+	PDEBUG(D_CONF, "camera now in HIGH power state");
+	return 0;
+}
+
+static int get_version_information(struct gspca_dev *gspca_dev)
+{
+	int ret;
+
+	/* GetCPIAVersion */
+	ret = do_command(gspca_dev, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
+	if (ret)
+		return ret;
+
+	/* GetPnPID */
+	return do_command(gspca_dev, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
+}
+
+static int save_camera_state(struct gspca_dev *gspca_dev)
+{
+	int ret;
+
+	ret = do_command(gspca_dev, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
+	if (ret)
+		return ret;
+
+	return do_command(gspca_dev, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+}
+
+static int command_setformat(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+
+	ret = do_command(gspca_dev, CPIA_COMMAND_SetFormat,
+			 sd->params.format.videoSize,
+			 sd->params.format.subSample,
+			 sd->params.format.yuvOrder, 0);
+	if (ret)
+		return ret;
+
+	return do_command(gspca_dev, CPIA_COMMAND_SetROI,
+			  sd->params.roi.colStart, sd->params.roi.colEnd,
+			  sd->params.roi.rowStart, sd->params.roi.rowEnd);
+}
+
+static int command_setcolourparams(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	return do_command(gspca_dev, CPIA_COMMAND_SetColourParams,
+			  sd->params.colourParams.brightness,
+			  sd->params.colourParams.contrast,
+			  sd->params.colourParams.saturation, 0);
+}
+
+static int command_setapcor(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	return do_command(gspca_dev, CPIA_COMMAND_SetApcor,
+			  sd->params.apcor.gain1,
+			  sd->params.apcor.gain2,
+			  sd->params.apcor.gain4,
+			  sd->params.apcor.gain8);
+}
+
+static int command_setvloffset(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	return do_command(gspca_dev, CPIA_COMMAND_SetVLOffset,
+			  sd->params.vlOffset.gain1,
+			  sd->params.vlOffset.gain2,
+			  sd->params.vlOffset.gain4,
+			  sd->params.vlOffset.gain8);
+}
+
+static int command_setexposure(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+
+	ret = do_command_extended(gspca_dev, CPIA_COMMAND_SetExposure,
+				  sd->params.exposure.gainMode,
+				  1,
+				  sd->params.exposure.compMode,
+				  sd->params.exposure.centreWeight,
+				  sd->params.exposure.gain,
+				  sd->params.exposure.fineExp,
+				  sd->params.exposure.coarseExpLo,
+				  sd->params.exposure.coarseExpHi,
+				  sd->params.exposure.redComp,
+				  sd->params.exposure.green1Comp,
+				  sd->params.exposure.green2Comp,
+				  sd->params.exposure.blueComp);
+	if (ret)
+		return ret;
+
+	if (sd->params.exposure.expMode != 1) {
+		ret = do_command_extended(gspca_dev, CPIA_COMMAND_SetExposure,
+					  0,
+					  sd->params.exposure.expMode,
+					  0, 0,
+					  sd->params.exposure.gain,
+					  sd->params.exposure.fineExp,
+					  sd->params.exposure.coarseExpLo,
+					  sd->params.exposure.coarseExpHi,
+					  0, 0, 0, 0);
+	}
+
+	return ret;
+}
+
+static int command_setcolourbalance(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->params.colourBalance.balanceMode == 1) {
+		int ret;
+
+		ret = do_command(gspca_dev, CPIA_COMMAND_SetColourBalance,
+				 1,
+				 sd->params.colourBalance.redGain,
+				 sd->params.colourBalance.greenGain,
+				 sd->params.colourBalance.blueGain);
+		if (ret)
+			return ret;
+
+		return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance,
+				  3, 0, 0, 0);
+	}
+	if (sd->params.colourBalance.balanceMode == 2) {
+		return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance,
+				  2, 0, 0, 0);
+	}
+	if (sd->params.colourBalance.balanceMode == 3) {
+		return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance,
+				  3, 0, 0, 0);
+	}
+
+	return -EINVAL;
+}
+
+static int command_setcompressiontarget(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	return do_command(gspca_dev, CPIA_COMMAND_SetCompressionTarget,
+			  sd->params.compressionTarget.frTargeting,
+			  sd->params.compressionTarget.targetFR,
+			  sd->params.compressionTarget.targetQ, 0);
+}
+
+static int command_setyuvtresh(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	return do_command(gspca_dev, CPIA_COMMAND_SetYUVThresh,
+			  sd->params.yuvThreshold.yThreshold,
+			  sd->params.yuvThreshold.uvThreshold, 0, 0);
+}
+
+static int command_setcompressionparams(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	return do_command_extended(gspca_dev,
+			    CPIA_COMMAND_SetCompressionParams,
+			    0, 0, 0, 0,
+			    sd->params.compressionParams.hysteresis,
+			    sd->params.compressionParams.threshMax,
+			    sd->params.compressionParams.smallStep,
+			    sd->params.compressionParams.largeStep,
+			    sd->params.compressionParams.decimationHysteresis,
+			    sd->params.compressionParams.frDiffStepThresh,
+			    sd->params.compressionParams.qDiffStepThresh,
+			    sd->params.compressionParams.decimationThreshMod);
+}
+
+static int command_setcompression(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	return do_command(gspca_dev, CPIA_COMMAND_SetCompression,
+			  sd->params.compression.mode,
+			  sd->params.compression.decimation, 0, 0);
+}
+
+static int command_setsensorfps(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	return do_command(gspca_dev, CPIA_COMMAND_SetSensorFPS,
+			  sd->params.sensorFps.divisor,
+			  sd->params.sensorFps.baserate, 0, 0);
+}
+
+static int command_setflickerctrl(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	return do_command(gspca_dev, CPIA_COMMAND_SetFlickerCtrl,
+			  sd->params.flickerControl.flickerMode,
+			  sd->params.flickerControl.coarseJump,
+			  sd->params.flickerControl.allowableOverExposure,
+			  0);
+}
+
+static int command_setecptiming(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	return do_command(gspca_dev, CPIA_COMMAND_SetECPTiming,
+			  sd->params.ecpTiming, 0, 0, 0);
+}
+
+static int command_pause(struct gspca_dev *gspca_dev)
+{
+	return do_command(gspca_dev, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
+}
+
+static int command_resume(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	return do_command(gspca_dev, CPIA_COMMAND_InitStreamCap,
+			  0, sd->params.streamStartLine, 0, 0);
+}
+
+static int command_setlights(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret, p1, p2;
+
+	p1 = (sd->params.qx3.bottomlight == 0) << 1;
+	p2 = (sd->params.qx3.toplight == 0) << 3;
+
+	ret = do_command(gspca_dev, CPIA_COMMAND_WriteVCReg,
+			 0x90, 0x8f, 0x50, 0);
+	if (ret)
+		return ret;
+
+	return do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, 2, 0,
+			  p1 | p2 | 0xe0, 0);
+}
+
+static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply)
+{
+	/* Everything in here is from the Windows driver */
+/* define for compgain calculation */
+#if 0
+#define COMPGAIN(base, curexp, newexp) \
+    (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
+#define EXP_FROM_COMP(basecomp, curcomp, curexp) \
+    (u16)((float)curexp * (float)(u8)(curcomp + 128) / \
+    (float)(u8)(basecomp - 128))
+#else
+  /* equivalent functions without floating point math */
+#define COMPGAIN(base, curexp, newexp) \
+    (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2 * newexp)))
+#define EXP_FROM_COMP(basecomp, curcomp, curexp) \
+    (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
+#endif
+
+	struct sd *sd = (struct sd *) gspca_dev;
+	int currentexp = sd->params.exposure.coarseExpLo +
+			 sd->params.exposure.coarseExpHi * 256;
+	int ret, startexp;
+
+	if (on) {
+		int cj = sd->params.flickerControl.coarseJump;
+		sd->params.flickerControl.flickerMode = 1;
+		sd->params.flickerControl.disabled = 0;
+		if (sd->params.exposure.expMode != 2) {
+			sd->params.exposure.expMode = 2;
+			sd->exposure_status = EXPOSURE_NORMAL;
+		}
+		currentexp = currentexp << sd->params.exposure.gain;
+		sd->params.exposure.gain = 0;
+		/* round down current exposure to nearest value */
+		startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj;
+		if (startexp < 1)
+			startexp = 1;
+		startexp = (startexp * cj) - 1;
+		if (FIRMWARE_VERSION(1, 2))
+			while (startexp > MAX_EXP_102)
+				startexp -= cj;
+		else
+			while (startexp > MAX_EXP)
+				startexp -= cj;
+		sd->params.exposure.coarseExpLo = startexp & 0xff;
+		sd->params.exposure.coarseExpHi = startexp >> 8;
+		if (currentexp > startexp) {
+			if (currentexp > (2 * startexp))
+				currentexp = 2 * startexp;
+			sd->params.exposure.redComp =
+				COMPGAIN(COMP_RED, currentexp, startexp);
+			sd->params.exposure.green1Comp =
+				COMPGAIN(COMP_GREEN1, currentexp, startexp);
+			sd->params.exposure.green2Comp =
+				COMPGAIN(COMP_GREEN2, currentexp, startexp);
+			sd->params.exposure.blueComp =
+				COMPGAIN(COMP_BLUE, currentexp, startexp);
+		} else {
+			sd->params.exposure.redComp = COMP_RED;
+			sd->params.exposure.green1Comp = COMP_GREEN1;
+			sd->params.exposure.green2Comp = COMP_GREEN2;
+			sd->params.exposure.blueComp = COMP_BLUE;
+		}
+		if (FIRMWARE_VERSION(1, 2))
+			sd->params.exposure.compMode = 0;
+		else
+			sd->params.exposure.compMode = 1;
+
+		sd->params.apcor.gain1 = 0x18;
+		sd->params.apcor.gain2 = 0x18;
+		sd->params.apcor.gain4 = 0x16;
+		sd->params.apcor.gain8 = 0x14;
+	} else {
+		sd->params.flickerControl.flickerMode = 0;
+		sd->params.flickerControl.disabled = 1;
+		/* Average equivalent coarse for each comp channel */
+		startexp = EXP_FROM_COMP(COMP_RED,
+				sd->params.exposure.redComp, currentexp);
+		startexp += EXP_FROM_COMP(COMP_GREEN1,
+				sd->params.exposure.green1Comp, currentexp);
+		startexp += EXP_FROM_COMP(COMP_GREEN2,
+				sd->params.exposure.green2Comp, currentexp);
+		startexp += EXP_FROM_COMP(COMP_BLUE,
+				sd->params.exposure.blueComp, currentexp);
+		startexp = startexp >> 2;
+		while (startexp > MAX_EXP && sd->params.exposure.gain <
+		       sd->params.exposure.gainMode - 1) {
+			startexp = startexp >> 1;
+			++sd->params.exposure.gain;
+		}
+		if (FIRMWARE_VERSION(1, 2) && startexp > MAX_EXP_102)
+			startexp = MAX_EXP_102;
+		if (startexp > MAX_EXP)
+			startexp = MAX_EXP;
+		sd->params.exposure.coarseExpLo = startexp & 0xff;
+		sd->params.exposure.coarseExpHi = startexp >> 8;
+		sd->params.exposure.redComp = COMP_RED;
+		sd->params.exposure.green1Comp = COMP_GREEN1;
+		sd->params.exposure.green2Comp = COMP_GREEN2;
+		sd->params.exposure.blueComp = COMP_BLUE;
+		sd->params.exposure.compMode = 1;
+		sd->params.apcor.gain1 = 0x18;
+		sd->params.apcor.gain2 = 0x16;
+		sd->params.apcor.gain4 = 0x24;
+		sd->params.apcor.gain8 = 0x34;
+	}
+	sd->params.vlOffset.gain1 = 20;
+	sd->params.vlOffset.gain2 = 24;
+	sd->params.vlOffset.gain4 = 26;
+	sd->params.vlOffset.gain8 = 26;
+
+	if (apply) {
+		ret = command_setexposure(gspca_dev);
+		if (ret)
+			return ret;
+
+		ret = command_setapcor(gspca_dev);
+		if (ret)
+			return ret;
+
+		ret = command_setvloffset(gspca_dev);
+		if (ret)
+			return ret;
+
+		ret = command_setflickerctrl(gspca_dev);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+#undef EXP_FROM_COMP
+#undef COMPGAIN
+}
+
+/* monitor the exposure and adjust the sensor frame rate if needed */
+static void monitor_exposure(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 exp_acc, bcomp, cmd[8];
+	int ret, light_exp, dark_exp, very_dark_exp;
+	int old_exposure, new_exposure, framerate;
+	int setfps = 0, setexp = 0, setflicker = 0;
+
+	/* get necessary stats and register settings from camera */
+	/* do_command can't handle this, so do it ourselves */
+	cmd[0] = CPIA_COMMAND_ReadVPRegs >> 8;
+	cmd[1] = CPIA_COMMAND_ReadVPRegs & 0xff;
+	cmd[2] = 30;
+	cmd[3] = 4;
+	cmd[4] = 9;
+	cmd[5] = 8;
+	cmd[6] = 8;
+	cmd[7] = 0;
+	ret = cpia_usb_transferCmd(gspca_dev, cmd);
+	if (ret) {
+		pr_err("ReadVPRegs(30,4,9,8) - failed: %d\n", ret);
+		return;
+	}
+	exp_acc = gspca_dev->usb_buf[0];
+	bcomp = gspca_dev->usb_buf[1];
+
+	light_exp = sd->params.colourParams.brightness +
+		    TC - 50 + EXP_ACC_LIGHT;
+	if (light_exp > 255)
+		light_exp = 255;
+	dark_exp = sd->params.colourParams.brightness +
+		   TC - 50 - EXP_ACC_DARK;
+	if (dark_exp < 0)
+		dark_exp = 0;
+	very_dark_exp = dark_exp / 2;
+
+	old_exposure = sd->params.exposure.coarseExpHi * 256 +
+		       sd->params.exposure.coarseExpLo;
+
+	if (!sd->params.flickerControl.disabled) {
+		/* Flicker control on */
+		int max_comp = FIRMWARE_VERSION(1, 2) ? MAX_COMP :
+							HIGH_COMP_102;
+		bcomp += 128;	/* decode */
+		if (bcomp >= max_comp && exp_acc < dark_exp) {
+			/* dark */
+			if (exp_acc < very_dark_exp) {
+				/* very dark */
+				if (sd->exposure_status == EXPOSURE_VERY_DARK)
+					++sd->exposure_count;
+				else {
+					sd->exposure_status =
+						EXPOSURE_VERY_DARK;
+					sd->exposure_count = 1;
+				}
+			} else {
+				/* just dark */
+				if (sd->exposure_status == EXPOSURE_DARK)
+					++sd->exposure_count;
+				else {
+					sd->exposure_status = EXPOSURE_DARK;
+					sd->exposure_count = 1;
+				}
+			}
+		} else if (old_exposure <= LOW_EXP || exp_acc > light_exp) {
+			/* light */
+			if (old_exposure <= VERY_LOW_EXP) {
+				/* very light */
+				if (sd->exposure_status == EXPOSURE_VERY_LIGHT)
+					++sd->exposure_count;
+				else {
+					sd->exposure_status =
+						EXPOSURE_VERY_LIGHT;
+					sd->exposure_count = 1;
+				}
+			} else {
+				/* just light */
+				if (sd->exposure_status == EXPOSURE_LIGHT)
+					++sd->exposure_count;
+				else {
+					sd->exposure_status = EXPOSURE_LIGHT;
+					sd->exposure_count = 1;
+				}
+			}
+		} else {
+			/* not dark or light */
+			sd->exposure_status = EXPOSURE_NORMAL;
+		}
+	} else {
+		/* Flicker control off */
+		if (old_exposure >= MAX_EXP && exp_acc < dark_exp) {
+			/* dark */
+			if (exp_acc < very_dark_exp) {
+				/* very dark */
+				if (sd->exposure_status == EXPOSURE_VERY_DARK)
+					++sd->exposure_count;
+				else {
+					sd->exposure_status =
+						EXPOSURE_VERY_DARK;
+					sd->exposure_count = 1;
+				}
+			} else {
+				/* just dark */
+				if (sd->exposure_status == EXPOSURE_DARK)
+					++sd->exposure_count;
+				else {
+					sd->exposure_status = EXPOSURE_DARK;
+					sd->exposure_count = 1;
+				}
+			}
+		} else if (old_exposure <= LOW_EXP || exp_acc > light_exp) {
+			/* light */
+			if (old_exposure <= VERY_LOW_EXP) {
+				/* very light */
+				if (sd->exposure_status == EXPOSURE_VERY_LIGHT)
+					++sd->exposure_count;
+				else {
+					sd->exposure_status =
+						EXPOSURE_VERY_LIGHT;
+					sd->exposure_count = 1;
+				}
+			} else {
+				/* just light */
+				if (sd->exposure_status == EXPOSURE_LIGHT)
+					++sd->exposure_count;
+				else {
+					sd->exposure_status = EXPOSURE_LIGHT;
+					sd->exposure_count = 1;
+				}
+			}
+		} else {
+			/* not dark or light */
+			sd->exposure_status = EXPOSURE_NORMAL;
+		}
+	}
+
+	framerate = atomic_read(&sd->fps);
+	if (framerate > 30 || framerate < 1)
+		framerate = 1;
+
+	if (!sd->params.flickerControl.disabled) {
+		/* Flicker control on */
+		if ((sd->exposure_status == EXPOSURE_VERY_DARK ||
+		     sd->exposure_status == EXPOSURE_DARK) &&
+		    sd->exposure_count >= DARK_TIME * framerate &&
+		    sd->params.sensorFps.divisor < 2) {
+
+			/* dark for too long */
+			++sd->params.sensorFps.divisor;
+			setfps = 1;
+
+			sd->params.flickerControl.coarseJump =
+				flicker_jumps[sd->mainsFreq]
+					     [sd->params.sensorFps.baserate]
+					     [sd->params.sensorFps.divisor];
+			setflicker = 1;
+
+			new_exposure = sd->params.flickerControl.coarseJump-1;
+			while (new_exposure < old_exposure / 2)
+				new_exposure +=
+					sd->params.flickerControl.coarseJump;
+			sd->params.exposure.coarseExpLo = new_exposure & 0xff;
+			sd->params.exposure.coarseExpHi = new_exposure >> 8;
+			setexp = 1;
+			sd->exposure_status = EXPOSURE_NORMAL;
+			PDEBUG(D_CONF, "Automatically decreasing sensor_fps");
+
+		} else if ((sd->exposure_status == EXPOSURE_VERY_LIGHT ||
+			    sd->exposure_status == EXPOSURE_LIGHT) &&
+			   sd->exposure_count >= LIGHT_TIME * framerate &&
+			   sd->params.sensorFps.divisor > 0) {
+
+			/* light for too long */
+			int max_exp = FIRMWARE_VERSION(1, 2) ? MAX_EXP_102 :
+							       MAX_EXP;
+			--sd->params.sensorFps.divisor;
+			setfps = 1;
+
+			sd->params.flickerControl.coarseJump =
+				flicker_jumps[sd->mainsFreq]
+					     [sd->params.sensorFps.baserate]
+					     [sd->params.sensorFps.divisor];
+			setflicker = 1;
+
+			new_exposure = sd->params.flickerControl.coarseJump-1;
+			while (new_exposure < 2 * old_exposure &&
+			       new_exposure +
+			       sd->params.flickerControl.coarseJump < max_exp)
+				new_exposure +=
+					sd->params.flickerControl.coarseJump;
+			sd->params.exposure.coarseExpLo = new_exposure & 0xff;
+			sd->params.exposure.coarseExpHi = new_exposure >> 8;
+			setexp = 1;
+			sd->exposure_status = EXPOSURE_NORMAL;
+			PDEBUG(D_CONF, "Automatically increasing sensor_fps");
+		}
+	} else {
+		/* Flicker control off */
+		if ((sd->exposure_status == EXPOSURE_VERY_DARK ||
+		     sd->exposure_status == EXPOSURE_DARK) &&
+		    sd->exposure_count >= DARK_TIME * framerate &&
+		    sd->params.sensorFps.divisor < 2) {
+
+			/* dark for too long */
+			++sd->params.sensorFps.divisor;
+			setfps = 1;
+
+			if (sd->params.exposure.gain > 0) {
+				--sd->params.exposure.gain;
+				setexp = 1;
+			}
+			sd->exposure_status = EXPOSURE_NORMAL;
+			PDEBUG(D_CONF, "Automatically decreasing sensor_fps");
+
+		} else if ((sd->exposure_status == EXPOSURE_VERY_LIGHT ||
+			    sd->exposure_status == EXPOSURE_LIGHT) &&
+			   sd->exposure_count >= LIGHT_TIME * framerate &&
+			   sd->params.sensorFps.divisor > 0) {
+
+			/* light for too long */
+			--sd->params.sensorFps.divisor;
+			setfps = 1;
+
+			if (sd->params.exposure.gain <
+			    sd->params.exposure.gainMode - 1) {
+				++sd->params.exposure.gain;
+				setexp = 1;
+			}
+			sd->exposure_status = EXPOSURE_NORMAL;
+			PDEBUG(D_CONF, "Automatically increasing sensor_fps");
+		}
+	}
+
+	if (setexp)
+		command_setexposure(gspca_dev);
+
+	if (setfps)
+		command_setsensorfps(gspca_dev);
+
+	if (setflicker)
+		command_setflickerctrl(gspca_dev);
+}
+
+/*-----------------------------------------------------------------*/
+/* if flicker is switched off, this function switches it back on.It checks,
+   however, that conditions are suitable before restarting it.
+   This should only be called for firmware version 1.2.
+
+   It also adjust the colour balance when an exposure step is detected - as
+   long as flicker is running
+*/
+static void restart_flicker(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int cam_exposure, old_exp;
+
+	if (!FIRMWARE_VERSION(1, 2))
+		return;
+
+	cam_exposure = atomic_read(&sd->cam_exposure);
+
+	if (sd->params.flickerControl.flickerMode == 0 ||
+	    cam_exposure == 0)
+		return;
+
+	old_exp = sd->params.exposure.coarseExpLo +
+		  sd->params.exposure.coarseExpHi*256;
+	/*
+	  see how far away camera exposure is from a valid
+	  flicker exposure value
+	*/
+	cam_exposure %= sd->params.flickerControl.coarseJump;
+	if (!sd->params.flickerControl.disabled &&
+	    cam_exposure <= sd->params.flickerControl.coarseJump - 3) {
+		/* Flicker control auto-disabled */
+		sd->params.flickerControl.disabled = 1;
+	}
+
+	if (sd->params.flickerControl.disabled &&
+	    old_exp > sd->params.flickerControl.coarseJump +
+		      ROUND_UP_EXP_FOR_FLICKER) {
+		/* exposure is now high enough to switch
+		   flicker control back on */
+		set_flicker(gspca_dev, 1, 1);
+	}
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+
+	sd->mainsFreq = FREQ_DEF == V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
+	reset_camera_params(gspca_dev);
+
+	PDEBUG(D_PROBE, "cpia CPiA camera detected (vid/pid 0x%04X:0x%04X)",
+	       id->idVendor, id->idProduct);
+
+	cam = &gspca_dev->cam;
+	cam->cam_mode = mode;
+	cam->nmodes = ARRAY_SIZE(mode);
+
+	goto_low_power(gspca_dev);
+	/* Check the firmware version. */
+	sd->params.version.firmwareVersion = 0;
+	get_version_information(gspca_dev);
+	if (sd->params.version.firmwareVersion != 1) {
+		PDEBUG(D_ERR, "only firmware version 1 is supported (got: %d)",
+		       sd->params.version.firmwareVersion);
+		return -ENODEV;
+	}
+
+	/* A bug in firmware 1-02 limits gainMode to 2 */
+	if (sd->params.version.firmwareRevision <= 2 &&
+	    sd->params.exposure.gainMode > 2) {
+		sd->params.exposure.gainMode = 2;
+	}
+
+	/* set QX3 detected flag */
+	sd->params.qx3.qx3_detected = (sd->params.pnpID.vendor == 0x0813 &&
+				       sd->params.pnpID.product == 0x0001);
+	return 0;
+}
+
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int priv, ret;
+
+	/* Start the camera in low power mode */
+	if (goto_low_power(gspca_dev)) {
+		if (sd->params.status.systemState != WARM_BOOT_STATE) {
+			PDEBUG(D_ERR, "unexpected systemstate: %02x",
+			       sd->params.status.systemState);
+			printstatus(&sd->params);
+			return -ENODEV;
+		}
+
+		/* FIXME: this is just dirty trial and error */
+		ret = goto_high_power(gspca_dev);
+		if (ret)
+			return ret;
+
+		ret = do_command(gspca_dev, CPIA_COMMAND_DiscardFrame,
+				 0, 0, 0, 0);
+		if (ret)
+			return ret;
+
+		ret = goto_low_power(gspca_dev);
+		if (ret)
+			return ret;
+	}
+
+	/* procedure described in developer's guide p3-28 */
+
+	/* Check the firmware version. */
+	sd->params.version.firmwareVersion = 0;
+	get_version_information(gspca_dev);
+
+	/* The fatal error checking should be done after
+	 * the camera powers up (developer's guide p 3-38) */
+
+	/* Set streamState before transition to high power to avoid bug
+	 * in firmware 1-02 */
+	ret = do_command(gspca_dev, CPIA_COMMAND_ModifyCameraStatus,
+			 STREAMSTATE, 0, STREAM_NOT_READY, 0);
+	if (ret)
+		return ret;
+
+	/* GotoHiPower */
+	ret = goto_high_power(gspca_dev);
+	if (ret)
+		return ret;
+
+	/* Check the camera status */
+	ret = do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
+	if (ret)
+		return ret;
+
+	if (sd->params.status.fatalError) {
+		PDEBUG(D_ERR, "fatal_error: %04x, vp_status: %04x",
+		       sd->params.status.fatalError,
+		       sd->params.status.vpStatus);
+		return -EIO;
+	}
+
+	/* VPVersion can't be retrieved before the camera is in HiPower,
+	 * so get it here instead of in get_version_information. */
+	ret = do_command(gspca_dev, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
+	if (ret)
+		return ret;
+
+	/* Determine video mode settings */
+	sd->params.streamStartLine = 120;
+
+	priv = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+	if (priv & 0x01) { /* crop */
+		sd->params.roi.colStart = 2;
+		sd->params.roi.rowStart = 6;
+	} else {
+		sd->params.roi.colStart = 0;
+		sd->params.roi.rowStart = 0;
+	}
+
+	if (priv & 0x02) { /* quarter */
+		sd->params.format.videoSize = VIDEOSIZE_QCIF;
+		sd->params.roi.colStart /= 2;
+		sd->params.roi.rowStart /= 2;
+		sd->params.streamStartLine /= 2;
+	} else
+		sd->params.format.videoSize = VIDEOSIZE_CIF;
+
+	sd->params.roi.colEnd = sd->params.roi.colStart +
+				(gspca_dev->width >> 3);
+	sd->params.roi.rowEnd = sd->params.roi.rowStart +
+				(gspca_dev->height >> 2);
+
+	/* And now set the camera to a known state */
+	ret = do_command(gspca_dev, CPIA_COMMAND_SetGrabMode,
+			 CPIA_GRAB_CONTINEOUS, 0, 0, 0);
+	if (ret)
+		return ret;
+	/* We start with compression disabled, as we need one uncompressed
+	   frame to handle later compressed frames */
+	ret = do_command(gspca_dev, CPIA_COMMAND_SetCompression,
+			 CPIA_COMPRESSION_NONE,
+			 NO_DECIMATION, 0, 0);
+	if (ret)
+		return ret;
+	ret = command_setcompressiontarget(gspca_dev);
+	if (ret)
+		return ret;
+	ret = command_setcolourparams(gspca_dev);
+	if (ret)
+		return ret;
+	ret = command_setformat(gspca_dev);
+	if (ret)
+		return ret;
+	ret = command_setyuvtresh(gspca_dev);
+	if (ret)
+		return ret;
+	ret = command_setecptiming(gspca_dev);
+	if (ret)
+		return ret;
+	ret = command_setcompressionparams(gspca_dev);
+	if (ret)
+		return ret;
+	ret = command_setexposure(gspca_dev);
+	if (ret)
+		return ret;
+	ret = command_setcolourbalance(gspca_dev);
+	if (ret)
+		return ret;
+	ret = command_setsensorfps(gspca_dev);
+	if (ret)
+		return ret;
+	ret = command_setapcor(gspca_dev);
+	if (ret)
+		return ret;
+	ret = command_setflickerctrl(gspca_dev);
+	if (ret)
+		return ret;
+	ret = command_setvloffset(gspca_dev);
+	if (ret)
+		return ret;
+
+	/* Start stream */
+	ret = command_resume(gspca_dev);
+	if (ret)
+		return ret;
+
+	/* Wait 6 frames before turning compression on for the sensor to get
+	   all settings and AEC/ACB to settle */
+	sd->first_frame = 6;
+	sd->exposure_status = EXPOSURE_NORMAL;
+	sd->exposure_count = 0;
+	atomic_set(&sd->cam_exposure, 0);
+	atomic_set(&sd->fps, 0);
+
+	return 0;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	command_pause(gspca_dev);
+
+	/* save camera state for later open (developers guide ch 3.5.3) */
+	save_camera_state(gspca_dev);
+
+	/* GotoLoPower */
+	goto_low_power(gspca_dev);
+
+	/* Update the camera status */
+	do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+	/* If the last button state is pressed, release it now! */
+	if (sd->params.qx3.button) {
+		/* The camera latch will hold the pressed state until we reset
+		   the latch, so we do not reset sd->params.qx3.button now, to
+		   avoid a false keypress being reported the next sd_start */
+		input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+		input_sync(gspca_dev->input_dev);
+	}
+#endif
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+
+	/* Start / Stop the camera to make sure we are talking to
+	   a supported camera, and to get some information from it
+	   to print. */
+	ret = sd_start(gspca_dev);
+	if (ret)
+		return ret;
+
+	/* Ensure the QX3 illuminators' states are restored upon resume,
+	   or disable the illuminator controls, if this isn't a QX3 */
+	if (sd->params.qx3.qx3_detected)
+		command_setlights(gspca_dev);
+
+	sd_stopN(gspca_dev);
+
+	PDEBUG(D_PROBE, "CPIA Version:             %d.%02d (%d.%d)",
+			sd->params.version.firmwareVersion,
+			sd->params.version.firmwareRevision,
+			sd->params.version.vcVersion,
+			sd->params.version.vcRevision);
+	PDEBUG(D_PROBE, "CPIA PnP-ID:              %04x:%04x:%04x",
+			sd->params.pnpID.vendor, sd->params.pnpID.product,
+			sd->params.pnpID.deviceRevision);
+	PDEBUG(D_PROBE, "VP-Version:               %d.%d %04x",
+			sd->params.vpVersion.vpVersion,
+			sd->params.vpVersion.vpRevision,
+			sd->params.vpVersion.cameraHeadID);
+
+	return 0;
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			u8 *data,
+			int len)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* Check for SOF */
+	if (len >= 64 &&
+	    data[0] == MAGIC_0 && data[1] == MAGIC_1 &&
+	    data[16] == sd->params.format.videoSize &&
+	    data[17] == sd->params.format.subSample &&
+	    data[18] == sd->params.format.yuvOrder &&
+	    data[24] == sd->params.roi.colStart &&
+	    data[25] == sd->params.roi.colEnd &&
+	    data[26] == sd->params.roi.rowStart &&
+	    data[27] == sd->params.roi.rowEnd) {
+		u8 *image;
+
+		atomic_set(&sd->cam_exposure, data[39] * 2);
+		atomic_set(&sd->fps, data[41]);
+
+		/* Check for proper EOF for last frame */
+		image = gspca_dev->image;
+		if (image != NULL &&
+		    gspca_dev->image_len > 4 &&
+		    image[gspca_dev->image_len - 4] == 0xff &&
+		    image[gspca_dev->image_len - 3] == 0xff &&
+		    image[gspca_dev->image_len - 2] == 0xff &&
+		    image[gspca_dev->image_len - 1] == 0xff)
+			gspca_frame_add(gspca_dev, LAST_PACKET,
+						NULL, 0);
+
+		gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
+		return;
+	}
+
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+static void sd_dq_callback(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* Set the normal compression settings once we have captured a
+	   few uncompressed frames (and AEC has hopefully settled) */
+	if (sd->first_frame) {
+		sd->first_frame--;
+		if (sd->first_frame == 0)
+			command_setcompression(gspca_dev);
+	}
+
+	/* Switch flicker control back on if it got turned off */
+	restart_flicker(gspca_dev);
+
+	/* If AEC is enabled, monitor the exposure and
+	   adjust the sensor frame rate if needed */
+	if (sd->params.exposure.expMode == 2)
+		monitor_exposure(gspca_dev);
+
+	/* Update our knowledge of the camera state */
+	do_command(gspca_dev, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+	do_command(gspca_dev, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
+}
+
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct gspca_dev *gspca_dev =
+		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+	struct sd *sd = (struct sd *)gspca_dev;
+
+	gspca_dev->usb_err = 0;
+
+	if (!gspca_dev->streaming && ctrl->id != V4L2_CID_POWER_LINE_FREQUENCY)
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		sd->params.colourParams.brightness = ctrl->val;
+		sd->params.flickerControl.allowableOverExposure =
+			find_over_exposure(sd->params.colourParams.brightness);
+		gspca_dev->usb_err = command_setcolourparams(gspca_dev);
+		if (!gspca_dev->usb_err)
+			gspca_dev->usb_err = command_setflickerctrl(gspca_dev);
+		break;
+	case V4L2_CID_CONTRAST:
+		sd->params.colourParams.contrast = ctrl->val;
+		gspca_dev->usb_err = command_setcolourparams(gspca_dev);
+		break;
+	case V4L2_CID_SATURATION:
+		sd->params.colourParams.saturation = ctrl->val;
+		gspca_dev->usb_err = command_setcolourparams(gspca_dev);
+		break;
+	case V4L2_CID_POWER_LINE_FREQUENCY:
+		sd->mainsFreq = ctrl->val == V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
+		sd->params.flickerControl.coarseJump =
+			flicker_jumps[sd->mainsFreq]
+			[sd->params.sensorFps.baserate]
+			[sd->params.sensorFps.divisor];
+
+		gspca_dev->usb_err = set_flicker(gspca_dev,
+			ctrl->val != V4L2_CID_POWER_LINE_FREQUENCY_DISABLED,
+			gspca_dev->streaming);
+		break;
+	case V4L2_CID_ILLUMINATORS_1:
+		sd->params.qx3.bottomlight = ctrl->val;
+		gspca_dev->usb_err = command_setlights(gspca_dev);
+		break;
+	case V4L2_CID_ILLUMINATORS_2:
+		sd->params.qx3.toplight = ctrl->val;
+		gspca_dev->usb_err = command_setlights(gspca_dev);
+		break;
+	case CPIA1_CID_COMP_TARGET:
+		sd->params.compressionTarget.frTargeting = ctrl->val;
+		gspca_dev->usb_err = command_setcompressiontarget(gspca_dev);
+		break;
+	}
+	return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+	.s_ctrl = sd_s_ctrl,
+};
+
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *)gspca_dev;
+	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+	static const char * const comp_target_menu[] = {
+		"Quality",
+		"Framerate",
+		NULL
+	};
+	static const struct v4l2_ctrl_config comp_target = {
+		.ops = &sd_ctrl_ops,
+		.id = CPIA1_CID_COMP_TARGET,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.name = "Compression Target",
+		.qmenu = comp_target_menu,
+		.max = 1,
+		.def = COMP_TARGET_DEF,
+	};
+
+	gspca_dev->vdev.ctrl_handler = hdl;
+	v4l2_ctrl_handler_init(hdl, 7);
+	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 100, 1, BRIGHTNESS_DEF);
+	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 96, 8, CONTRAST_DEF);
+	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 100, 1, SATURATION_DEF);
+	sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
+			V4L2_CID_POWER_LINE_FREQUENCY,
+			V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
+			FREQ_DEF);
+	if (sd->params.qx3.qx3_detected) {
+		v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+				V4L2_CID_ILLUMINATORS_1, 0, 1, 1,
+				ILLUMINATORS_1_DEF);
+		v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+				V4L2_CID_ILLUMINATORS_2, 0, 1, 1,
+				ILLUMINATORS_2_DEF);
+	}
+	v4l2_ctrl_new_custom(hdl, &comp_target, NULL);
+
+	if (hdl->error) {
+		pr_err("Could not initialize controls\n");
+		return hdl->error;
+	}
+	return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.config = sd_config,
+	.init = sd_init,
+	.init_controls = sd_init_controls,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.dq_callback = sd_dq_callback,
+	.pkt_scan = sd_pkt_scan,
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+	.other_input = 1,
+#endif
+};
+
+/* -- module initialisation -- */
+static const struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x0553, 0x0002)},
+	{USB_DEVICE(0x0813, 0x0001)},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+	.reset_resume = gspca_resume,
+#endif
+};
+
+module_usb_driver(sd_driver);
diff --git a/drivers/media/usb/gspca/etoms.c b/drivers/media/usb/gspca/etoms.c
new file mode 100644
index 0000000..38f68e1
--- /dev/null
+++ b/drivers/media/usb/gspca/etoms.c
@@ -0,0 +1,799 @@
+/*
+ * Etoms Et61x151 GPL Linux driver by Michel Xhaard (09/09/2004)
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define MODULE_NAME "etoms"
+
+#include "gspca.h"
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("Etoms USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	unsigned char autogain;
+
+	char sensor;
+#define SENSOR_PAS106 0
+#define SENSOR_TAS5130CXX 1
+	signed char ag_cnt;
+#define AG_CNT_START 13
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+	{320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+/*	{640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0}, */
+};
+
+static const struct v4l2_pix_format sif_mode[] = {
+	{176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 176,
+		.sizeimage = 176 * 144,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 352,
+		.sizeimage = 352 * 288,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+
+#define ETOMS_ALT_SIZE_1000   12
+
+#define ET_GPIO_DIR_CTRL 0x04	/* Control IO bit[0..5] (0 in  1 out) */
+#define ET_GPIO_OUT 0x05	/* Only IO data */
+#define ET_GPIO_IN 0x06		/* Read Only IO data */
+#define ET_RESET_ALL 0x03
+#define ET_ClCK 0x01
+#define ET_CTRL 0x02		/* enable i2c OutClck Powerdown mode */
+
+#define ET_COMP 0x12		/* Compression register */
+#define ET_MAXQt 0x13
+#define ET_MINQt 0x14
+#define ET_COMP_VAL0 0x02
+#define ET_COMP_VAL1 0x03
+
+#define ET_REG1d 0x1d
+#define ET_REG1e 0x1e
+#define ET_REG1f 0x1f
+#define ET_REG20 0x20
+#define ET_REG21 0x21
+#define ET_REG22 0x22
+#define ET_REG23 0x23
+#define ET_REG24 0x24
+#define ET_REG25 0x25
+/* base registers for luma calculation */
+#define ET_LUMA_CENTER 0x39
+
+#define ET_G_RED 0x4d
+#define ET_G_GREEN1 0x4e
+#define ET_G_BLUE 0x4f
+#define ET_G_GREEN2 0x50
+#define ET_G_GR_H 0x51
+#define ET_G_GB_H 0x52
+
+#define ET_O_RED 0x34
+#define ET_O_GREEN1 0x35
+#define ET_O_BLUE 0x36
+#define ET_O_GREEN2 0x37
+
+#define ET_SYNCHRO 0x68
+#define ET_STARTX 0x69
+#define ET_STARTY 0x6a
+#define ET_WIDTH_LOW 0x6b
+#define ET_HEIGTH_LOW 0x6c
+#define ET_W_H_HEIGTH 0x6d
+
+#define ET_REG6e 0x6e		/* OBW */
+#define ET_REG6f 0x6f		/* OBW */
+#define ET_REG70 0x70		/* OBW_AWB */
+#define ET_REG71 0x71		/* OBW_AWB */
+#define ET_REG72 0x72		/* OBW_AWB */
+#define ET_REG73 0x73		/* Clkdelay ns */
+#define ET_REG74 0x74		/* test pattern */
+#define ET_REG75 0x75		/* test pattern */
+
+#define ET_I2C_CLK 0x8c
+#define ET_PXL_CLK 0x60
+
+#define ET_I2C_BASE 0x89
+#define ET_I2C_COUNT 0x8a
+#define ET_I2C_PREFETCH 0x8b
+#define ET_I2C_REG 0x88
+#define ET_I2C_DATA7 0x87
+#define ET_I2C_DATA6 0x86
+#define ET_I2C_DATA5 0x85
+#define ET_I2C_DATA4 0x84
+#define ET_I2C_DATA3 0x83
+#define ET_I2C_DATA2 0x82
+#define ET_I2C_DATA1 0x81
+#define ET_I2C_DATA0 0x80
+
+#define PAS106_REG2 0x02	/* pxlClk = systemClk/(reg2) */
+#define PAS106_REG3 0x03	/* line/frame H [11..4] */
+#define PAS106_REG4 0x04	/* line/frame L [3..0] */
+#define PAS106_REG5 0x05	/* exposure time line offset(default 5) */
+#define PAS106_REG6 0x06	/* exposure time pixel offset(default 6) */
+#define PAS106_REG7 0x07	/* signbit Dac (default 0) */
+#define PAS106_REG9 0x09
+#define PAS106_REG0e 0x0e	/* global gain [4..0](default 0x0e) */
+#define PAS106_REG13 0x13	/* end i2c write */
+
+static const __u8 GainRGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 };
+
+static const __u8 I2c2[] = { 0x08, 0x08, 0x08, 0x08, 0x0d };
+
+static const __u8 I2c3[] = { 0x12, 0x05 };
+
+static const __u8 I2c4[] = { 0x41, 0x08 };
+
+/* read 'len' bytes to gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+		  __u16 index,
+		  __u16 len)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+#ifdef GSPCA_DEBUG
+	if (len > USB_BUF_SZ) {
+		pr_err("reg_r: buffer overflow\n");
+		return;
+	}
+#endif
+	usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			0,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			0,
+			index, gspca_dev->usb_buf, len, 500);
+	PDEBUG(D_USBI, "reg read [%02x] -> %02x ..",
+			index, gspca_dev->usb_buf[0]);
+}
+
+static void reg_w_val(struct gspca_dev *gspca_dev,
+			__u16 index,
+			__u8 val)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	gspca_dev->usb_buf[0] = val;
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			0,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			0,
+			index, gspca_dev->usb_buf, 1, 500);
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+		  __u16 index,
+		  const __u8 *buffer,
+		  __u16 len)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+#ifdef GSPCA_DEBUG
+	if (len > USB_BUF_SZ) {
+		pr_err("reg_w: buffer overflow\n");
+		return;
+	}
+	PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer);
+#endif
+	memcpy(gspca_dev->usb_buf, buffer, len);
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			0,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			0, index, gspca_dev->usb_buf, len, 500);
+}
+
+static int i2c_w(struct gspca_dev *gspca_dev,
+		 __u8 reg,
+		 const __u8 *buffer,
+		 int len, __u8 mode)
+{
+	/* buffer should be [D0..D7] */
+	__u8 ptchcount;
+
+	/* set the base address */
+	reg_w_val(gspca_dev, ET_I2C_BASE, 0x40);
+					 /* sensor base for the pas106 */
+	/* set count and prefetch */
+	ptchcount = ((len & 0x07) << 4) | (mode & 0x03);
+	reg_w_val(gspca_dev, ET_I2C_COUNT, ptchcount);
+	/* set the register base */
+	reg_w_val(gspca_dev, ET_I2C_REG, reg);
+	while (--len >= 0)
+		reg_w_val(gspca_dev, ET_I2C_DATA0 + len, buffer[len]);
+	return 0;
+}
+
+static int i2c_r(struct gspca_dev *gspca_dev,
+			__u8 reg)
+{
+	/* set the base address */
+	reg_w_val(gspca_dev, ET_I2C_BASE, 0x40);
+					/* sensor base for the pas106 */
+	/* set count and prefetch (cnd: 4 bits - mode: 4 bits) */
+	reg_w_val(gspca_dev, ET_I2C_COUNT, 0x11);
+	reg_w_val(gspca_dev, ET_I2C_REG, reg);	/* set the register base */
+	reg_w_val(gspca_dev, ET_I2C_PREFETCH, 0x02);	/* prefetch */
+	reg_w_val(gspca_dev, ET_I2C_PREFETCH, 0x00);
+	reg_r(gspca_dev, ET_I2C_DATA0, 1);	/* read one byte */
+	return 0;
+}
+
+static int Et_WaitStatus(struct gspca_dev *gspca_dev)
+{
+	int retry = 10;
+
+	while (retry--) {
+		reg_r(gspca_dev, ET_ClCK, 1);
+		if (gspca_dev->usb_buf[0] != 0)
+			return 1;
+	}
+	return 0;
+}
+
+static int et_video(struct gspca_dev *gspca_dev,
+		    int on)
+{
+	int ret;
+
+	reg_w_val(gspca_dev, ET_GPIO_OUT,
+		  on ? 0x10		/* startvideo - set Bit5 */
+		     : 0);		/* stopvideo */
+	ret = Et_WaitStatus(gspca_dev);
+	if (ret != 0)
+		PDEBUG(D_ERR, "timeout video on/off");
+	return ret;
+}
+
+static void Et_init2(struct gspca_dev *gspca_dev)
+{
+	__u8 value;
+	static const __u8 FormLine[] = { 0x84, 0x03, 0x14, 0xf4, 0x01, 0x05 };
+
+	PDEBUG(D_STREAM, "Open Init2 ET");
+	reg_w_val(gspca_dev, ET_GPIO_DIR_CTRL, 0x2f);
+	reg_w_val(gspca_dev, ET_GPIO_OUT, 0x10);
+	reg_r(gspca_dev, ET_GPIO_IN, 1);
+	reg_w_val(gspca_dev, ET_ClCK, 0x14); /* 0x14 // 0x16 enabled pattern */
+	reg_w_val(gspca_dev, ET_CTRL, 0x1b);
+
+	/*  compression et subsampling */
+	if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv)
+		value = ET_COMP_VAL1;	/* 320 */
+	else
+		value = ET_COMP_VAL0;	/* 640 */
+	reg_w_val(gspca_dev, ET_COMP, value);
+	reg_w_val(gspca_dev, ET_MAXQt, 0x1f);
+	reg_w_val(gspca_dev, ET_MINQt, 0x04);
+	/* undocumented registers */
+	reg_w_val(gspca_dev, ET_REG1d, 0xff);
+	reg_w_val(gspca_dev, ET_REG1e, 0xff);
+	reg_w_val(gspca_dev, ET_REG1f, 0xff);
+	reg_w_val(gspca_dev, ET_REG20, 0x35);
+	reg_w_val(gspca_dev, ET_REG21, 0x01);
+	reg_w_val(gspca_dev, ET_REG22, 0x00);
+	reg_w_val(gspca_dev, ET_REG23, 0xff);
+	reg_w_val(gspca_dev, ET_REG24, 0xff);
+	reg_w_val(gspca_dev, ET_REG25, 0x0f);
+	/* colors setting */
+	reg_w_val(gspca_dev, 0x30, 0x11);		/* 0x30 */
+	reg_w_val(gspca_dev, 0x31, 0x40);
+	reg_w_val(gspca_dev, 0x32, 0x00);
+	reg_w_val(gspca_dev, ET_O_RED, 0x00);		/* 0x34 */
+	reg_w_val(gspca_dev, ET_O_GREEN1, 0x00);
+	reg_w_val(gspca_dev, ET_O_BLUE, 0x00);
+	reg_w_val(gspca_dev, ET_O_GREEN2, 0x00);
+	/*************/
+	reg_w_val(gspca_dev, ET_G_RED, 0x80);		/* 0x4d */
+	reg_w_val(gspca_dev, ET_G_GREEN1, 0x80);
+	reg_w_val(gspca_dev, ET_G_BLUE, 0x80);
+	reg_w_val(gspca_dev, ET_G_GREEN2, 0x80);
+	reg_w_val(gspca_dev, ET_G_GR_H, 0x00);
+	reg_w_val(gspca_dev, ET_G_GB_H, 0x00);		/* 0x52 */
+	/* Window control registers */
+	reg_w_val(gspca_dev, 0x61, 0x80);		/* use cmc_out */
+	reg_w_val(gspca_dev, 0x62, 0x02);
+	reg_w_val(gspca_dev, 0x63, 0x03);
+	reg_w_val(gspca_dev, 0x64, 0x14);
+	reg_w_val(gspca_dev, 0x65, 0x0e);
+	reg_w_val(gspca_dev, 0x66, 0x02);
+	reg_w_val(gspca_dev, 0x67, 0x02);
+
+	/**************************************/
+	reg_w_val(gspca_dev, ET_SYNCHRO, 0x8f);		/* 0x68 */
+	reg_w_val(gspca_dev, ET_STARTX, 0x69);		/* 0x6a //0x69 */
+	reg_w_val(gspca_dev, ET_STARTY, 0x0d);		/* 0x0d //0x0c */
+	reg_w_val(gspca_dev, ET_WIDTH_LOW, 0x80);
+	reg_w_val(gspca_dev, ET_HEIGTH_LOW, 0xe0);
+	reg_w_val(gspca_dev, ET_W_H_HEIGTH, 0x60);	/* 6d */
+	reg_w_val(gspca_dev, ET_REG6e, 0x86);
+	reg_w_val(gspca_dev, ET_REG6f, 0x01);
+	reg_w_val(gspca_dev, ET_REG70, 0x26);
+	reg_w_val(gspca_dev, ET_REG71, 0x7a);
+	reg_w_val(gspca_dev, ET_REG72, 0x01);
+	/* Clock Pattern registers ***************** */
+	reg_w_val(gspca_dev, ET_REG73, 0x00);
+	reg_w_val(gspca_dev, ET_REG74, 0x18);		/* 0x28 */
+	reg_w_val(gspca_dev, ET_REG75, 0x0f);		/* 0x01 */
+	/**********************************************/
+	reg_w_val(gspca_dev, 0x8a, 0x20);
+	reg_w_val(gspca_dev, 0x8d, 0x0f);
+	reg_w_val(gspca_dev, 0x8e, 0x08);
+	/**************************************/
+	reg_w_val(gspca_dev, 0x03, 0x08);
+	reg_w_val(gspca_dev, ET_PXL_CLK, 0x03);
+	reg_w_val(gspca_dev, 0x81, 0xff);
+	reg_w_val(gspca_dev, 0x80, 0x00);
+	reg_w_val(gspca_dev, 0x81, 0xff);
+	reg_w_val(gspca_dev, 0x80, 0x20);
+	reg_w_val(gspca_dev, 0x03, 0x01);
+	reg_w_val(gspca_dev, 0x03, 0x00);
+	reg_w_val(gspca_dev, 0x03, 0x08);
+	/********************************************/
+
+/*	reg_r(gspca_dev, ET_I2C_BASE, 1);
+					 always 0x40 as the pas106 ??? */
+	/* set the sensor */
+	if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv)
+		value = 0x04;		/* 320 */
+	else				/* 640 */
+		value = 0x1e;	/* 0x17	 * setting PixelClock
+					 * 0x03 mean 24/(3+1) = 6 Mhz
+					 * 0x05 -> 24/(5+1) = 4 Mhz
+					 * 0x0b -> 24/(11+1) = 2 Mhz
+					 * 0x17 -> 24/(23+1) = 1 Mhz
+					 */
+	reg_w_val(gspca_dev, ET_PXL_CLK, value);
+	/* now set by fifo the FormatLine setting */
+	reg_w(gspca_dev, 0x62, FormLine, 6);
+
+	/* set exposure times [ 0..0x78] 0->longvalue 0x78->shortvalue */
+	reg_w_val(gspca_dev, 0x81, 0x47);	/* 0x47; */
+	reg_w_val(gspca_dev, 0x80, 0x40);	/* 0x40; */
+	/* Pedro change */
+	/* Brightness change Brith+ decrease value */
+	/* Brigth- increase value */
+	/* original value = 0x70; */
+	reg_w_val(gspca_dev, 0x81, 0x30);	/* 0x20; - set brightness */
+	reg_w_val(gspca_dev, 0x80, 0x20);	/* 0x20; */
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
+{
+	int i;
+
+	for (i = 0; i < 4; i++)
+		reg_w_val(gspca_dev, ET_O_RED + i, val);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
+{
+	__u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 };
+
+	memset(RGBG, val, sizeof(RGBG) - 2);
+	reg_w(gspca_dev, ET_G_RED, RGBG, 6);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev, s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 I2cc[] = { 0x05, 0x02, 0x02, 0x05, 0x0d };
+	__u8 i2cflags = 0x01;
+	/* __u8 green = 0; */
+
+	I2cc[3] = val;	/* red */
+	I2cc[0] = 15 - val;	/* blue */
+	/* green = 15 - ((((7*I2cc[0]) >> 2 ) + I2cc[3]) >> 1); */
+	/* I2cc[1] = I2cc[2] = green; */
+	if (sd->sensor == SENSOR_PAS106) {
+		i2c_w(gspca_dev, PAS106_REG13, &i2cflags, 1, 3);
+		i2c_w(gspca_dev, PAS106_REG9, I2cc, sizeof I2cc, 1);
+	}
+/*	PDEBUG(D_CONF , "Etoms red %d blue %d green %d",
+		I2cc[3], I2cc[0], green); */
+}
+
+static s32 getcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->sensor == SENSOR_PAS106) {
+/*		i2c_r(gspca_dev, PAS106_REG9);		 * blue */
+		i2c_r(gspca_dev, PAS106_REG9 + 3);	/* red */
+		return gspca_dev->usb_buf[0] & 0x0f;
+	}
+	return 0;
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->autogain)
+		sd->ag_cnt = AG_CNT_START;
+	else
+		sd->ag_cnt = -1;
+}
+
+static void Et_init1(struct gspca_dev *gspca_dev)
+{
+	__u8 value;
+/*	__u8 I2c0 [] = {0x0a, 0x12, 0x05, 0x22, 0xac, 0x00, 0x01, 0x00}; */
+	__u8 I2c0[] = { 0x0a, 0x12, 0x05, 0x6d, 0xcd, 0x00, 0x01, 0x00 };
+						/* try 1/120 0x6d 0xcd 0x40 */
+/*	__u8 I2c0 [] = {0x0a, 0x12, 0x05, 0xfe, 0xfe, 0xc0, 0x01, 0x00};
+						 * 1/60000 hmm ?? */
+
+	PDEBUG(D_STREAM, "Open Init1 ET");
+	reg_w_val(gspca_dev, ET_GPIO_DIR_CTRL, 7);
+	reg_r(gspca_dev, ET_GPIO_IN, 1);
+	reg_w_val(gspca_dev, ET_RESET_ALL, 1);
+	reg_w_val(gspca_dev, ET_RESET_ALL, 0);
+	reg_w_val(gspca_dev, ET_ClCK, 0x10);
+	reg_w_val(gspca_dev, ET_CTRL, 0x19);
+	/*   compression et subsampling */
+	if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv)
+		value = ET_COMP_VAL1;
+	else
+		value = ET_COMP_VAL0;
+	PDEBUG(D_STREAM, "Open mode %d Compression %d",
+	       gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv,
+	       value);
+	reg_w_val(gspca_dev, ET_COMP, value);
+	reg_w_val(gspca_dev, ET_MAXQt, 0x1d);
+	reg_w_val(gspca_dev, ET_MINQt, 0x02);
+	/* undocumented registers */
+	reg_w_val(gspca_dev, ET_REG1d, 0xff);
+	reg_w_val(gspca_dev, ET_REG1e, 0xff);
+	reg_w_val(gspca_dev, ET_REG1f, 0xff);
+	reg_w_val(gspca_dev, ET_REG20, 0x35);
+	reg_w_val(gspca_dev, ET_REG21, 0x01);
+	reg_w_val(gspca_dev, ET_REG22, 0x00);
+	reg_w_val(gspca_dev, ET_REG23, 0xf7);
+	reg_w_val(gspca_dev, ET_REG24, 0xff);
+	reg_w_val(gspca_dev, ET_REG25, 0x07);
+	/* colors setting */
+	reg_w_val(gspca_dev, ET_G_RED, 0x80);
+	reg_w_val(gspca_dev, ET_G_GREEN1, 0x80);
+	reg_w_val(gspca_dev, ET_G_BLUE, 0x80);
+	reg_w_val(gspca_dev, ET_G_GREEN2, 0x80);
+	reg_w_val(gspca_dev, ET_G_GR_H, 0x00);
+	reg_w_val(gspca_dev, ET_G_GB_H, 0x00);
+	/* Window control registers */
+	reg_w_val(gspca_dev, ET_SYNCHRO, 0xf0);
+	reg_w_val(gspca_dev, ET_STARTX, 0x56);		/* 0x56 */
+	reg_w_val(gspca_dev, ET_STARTY, 0x05);		/* 0x04 */
+	reg_w_val(gspca_dev, ET_WIDTH_LOW, 0x60);
+	reg_w_val(gspca_dev, ET_HEIGTH_LOW, 0x20);
+	reg_w_val(gspca_dev, ET_W_H_HEIGTH, 0x50);
+	reg_w_val(gspca_dev, ET_REG6e, 0x86);
+	reg_w_val(gspca_dev, ET_REG6f, 0x01);
+	reg_w_val(gspca_dev, ET_REG70, 0x86);
+	reg_w_val(gspca_dev, ET_REG71, 0x14);
+	reg_w_val(gspca_dev, ET_REG72, 0x00);
+	/* Clock Pattern registers */
+	reg_w_val(gspca_dev, ET_REG73, 0x00);
+	reg_w_val(gspca_dev, ET_REG74, 0x00);
+	reg_w_val(gspca_dev, ET_REG75, 0x0a);
+	reg_w_val(gspca_dev, ET_I2C_CLK, 0x04);
+	reg_w_val(gspca_dev, ET_PXL_CLK, 0x01);
+	/* set the sensor */
+	if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+		I2c0[0] = 0x06;
+		i2c_w(gspca_dev, PAS106_REG2, I2c0, sizeof I2c0, 1);
+		i2c_w(gspca_dev, PAS106_REG9, I2c2, sizeof I2c2, 1);
+		value = 0x06;
+		i2c_w(gspca_dev, PAS106_REG2, &value, 1, 1);
+		i2c_w(gspca_dev, PAS106_REG3, I2c3, sizeof I2c3, 1);
+		/* value = 0x1f; */
+		value = 0x04;
+		i2c_w(gspca_dev, PAS106_REG0e, &value, 1, 1);
+	} else {
+		I2c0[0] = 0x0a;
+
+		i2c_w(gspca_dev, PAS106_REG2, I2c0, sizeof I2c0, 1);
+		i2c_w(gspca_dev, PAS106_REG9, I2c2, sizeof I2c2, 1);
+		value = 0x0a;
+		i2c_w(gspca_dev, PAS106_REG2, &value, 1, 1);
+		i2c_w(gspca_dev, PAS106_REG3, I2c3, sizeof I2c3, 1);
+		value = 0x04;
+		/* value = 0x10; */
+		i2c_w(gspca_dev, PAS106_REG0e, &value, 1, 1);
+		/* bit 2 enable bit 1:2 select 0 1 2 3
+		   value = 0x07;                                * curve 0 *
+		   i2c_w(gspca_dev, PAS106_REG0f, &value, 1, 1);
+		 */
+	}
+
+/*	value = 0x01; */
+/*	value = 0x22; */
+/*	i2c_w(gspca_dev, PAS106_REG5, &value, 1, 1); */
+	/* magnetude and sign bit for DAC */
+	i2c_w(gspca_dev, PAS106_REG7, I2c4, sizeof I2c4, 1);
+	/* now set by fifo the whole colors setting */
+	reg_w(gspca_dev, ET_G_RED, GainRGBG, 6);
+	setcolors(gspca_dev, getcolors(gspca_dev));
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+		     const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+
+	cam = &gspca_dev->cam;
+	sd->sensor = id->driver_info;
+	if (sd->sensor == SENSOR_PAS106) {
+		cam->cam_mode = sif_mode;
+		cam->nmodes = ARRAY_SIZE(sif_mode);
+	} else {
+		cam->cam_mode = vga_mode;
+		cam->nmodes = ARRAY_SIZE(vga_mode);
+	}
+	sd->ag_cnt = -1;
+	return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->sensor == SENSOR_PAS106)
+		Et_init1(gspca_dev);
+	else
+		Et_init2(gspca_dev);
+	reg_w_val(gspca_dev, ET_RESET_ALL, 0x08);
+	et_video(gspca_dev, 0);		/* video off */
+	return 0;
+}
+
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->sensor == SENSOR_PAS106)
+		Et_init1(gspca_dev);
+	else
+		Et_init2(gspca_dev);
+
+	setautogain(gspca_dev);
+
+	reg_w_val(gspca_dev, ET_RESET_ALL, 0x08);
+	et_video(gspca_dev, 1);		/* video on */
+	return 0;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	et_video(gspca_dev, 0);		/* video off */
+}
+
+static __u8 Et_getgainG(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->sensor == SENSOR_PAS106) {
+		i2c_r(gspca_dev, PAS106_REG0e);
+		PDEBUG(D_CONF, "Etoms gain G %d", gspca_dev->usb_buf[0]);
+		return gspca_dev->usb_buf[0];
+	}
+	return 0x1f;
+}
+
+static void Et_setgainG(struct gspca_dev *gspca_dev, __u8 gain)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->sensor == SENSOR_PAS106) {
+		__u8 i2cflags = 0x01;
+
+		i2c_w(gspca_dev, PAS106_REG13, &i2cflags, 1, 3);
+		i2c_w(gspca_dev, PAS106_REG0e, &gain, 1, 1);
+	}
+}
+
+#define BLIMIT(bright) \
+	(u8)((bright > 0x1f) ? 0x1f : ((bright < 4) ? 3 : bright))
+#define LIMIT(color) \
+	(u8)((color > 0xff) ? 0xff : ((color < 0) ? 0 : color))
+
+static void do_autogain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 luma;
+	__u8 luma_mean = 128;
+	__u8 luma_delta = 20;
+	__u8 spring = 4;
+	int Gbright;
+	__u8 r, g, b;
+
+	if (sd->ag_cnt < 0)
+		return;
+	if (--sd->ag_cnt >= 0)
+		return;
+	sd->ag_cnt = AG_CNT_START;
+
+	Gbright = Et_getgainG(gspca_dev);
+	reg_r(gspca_dev, ET_LUMA_CENTER, 4);
+	g = (gspca_dev->usb_buf[0] + gspca_dev->usb_buf[3]) >> 1;
+	r = gspca_dev->usb_buf[1];
+	b = gspca_dev->usb_buf[2];
+	r = ((r << 8) - (r << 4) - (r << 3)) >> 10;
+	b = ((b << 7) >> 10);
+	g = ((g << 9) + (g << 7) + (g << 5)) >> 10;
+	luma = LIMIT(r + g + b);
+	PDEBUG(D_FRAM, "Etoms luma G %d", luma);
+	if (luma < luma_mean - luma_delta || luma > luma_mean + luma_delta) {
+		Gbright += (luma_mean - luma) >> spring;
+		Gbright = BLIMIT(Gbright);
+		PDEBUG(D_FRAM, "Etoms Gbright %d", Gbright);
+		Et_setgainG(gspca_dev, (__u8) Gbright);
+	}
+}
+
+#undef BLIMIT
+#undef LIMIT
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	int seqframe;
+
+	seqframe = data[0] & 0x3f;
+	len = (int) (((data[0] & 0xc0) << 2) | data[1]);
+	if (seqframe == 0x3f) {
+		PDEBUG(D_FRAM,
+		       "header packet found datalength %d !!", len);
+		PDEBUG(D_FRAM, "G %d R %d G %d B %d",
+		       data[2], data[3], data[4], data[5]);
+		data += 30;
+		/* don't change datalength as the chips provided it */
+		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
+		return;
+	}
+	if (len) {
+		data += 8;
+		gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+	} else {			/* Drop Packet */
+		gspca_dev->last_packet_type = DISCARD_PACKET;
+	}
+}
+
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct gspca_dev *gspca_dev =
+		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+	struct sd *sd = (struct sd *)gspca_dev;
+
+	gspca_dev->usb_err = 0;
+
+	if (!gspca_dev->streaming)
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		setbrightness(gspca_dev, ctrl->val);
+		break;
+	case V4L2_CID_CONTRAST:
+		setcontrast(gspca_dev, ctrl->val);
+		break;
+	case V4L2_CID_SATURATION:
+		setcolors(gspca_dev, ctrl->val);
+		break;
+	case V4L2_CID_AUTOGAIN:
+		sd->autogain = ctrl->val;
+		setautogain(gspca_dev);
+		break;
+	}
+	return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+	.s_ctrl = sd_s_ctrl,
+};
+
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *)gspca_dev;
+	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+
+	gspca_dev->vdev.ctrl_handler = hdl;
+	v4l2_ctrl_handler_init(hdl, 4);
+	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 1, 127, 1, 63);
+	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 255, 1, 127);
+	if (sd->sensor == SENSOR_PAS106)
+		v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 15, 1, 7);
+	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+	if (hdl->error) {
+		pr_err("Could not initialize controls\n");
+		return hdl->error;
+	}
+	return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.config = sd_config,
+	.init = sd_init,
+	.init_controls = sd_init_controls,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.pkt_scan = sd_pkt_scan,
+	.dq_callback = do_autogain,
+};
+
+/* -- module initialisation -- */
+static const struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106},
+#if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE
+	{USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX},
+#endif
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+		    const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+			       THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+	.reset_resume = gspca_resume,
+#endif
+};
+
+module_usb_driver(sd_driver);
diff --git a/drivers/media/usb/gspca/finepix.c b/drivers/media/usb/gspca/finepix.c
new file mode 100644
index 0000000..c8f2201
--- /dev/null
+++ b/drivers/media/usb/gspca/finepix.c
@@ -0,0 +1,306 @@
+/*
+ * Fujifilm Finepix subdriver
+ *
+ * Copyright (C) 2008 Frank Zago
+ *
+ * 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
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define MODULE_NAME "finepix"
+
+#include "gspca.h"
+
+MODULE_AUTHOR("Frank Zago <frank@zago.net>");
+MODULE_DESCRIPTION("Fujifilm FinePix USB V4L2 driver");
+MODULE_LICENSE("GPL");
+
+/* Default timeout, in ms */
+#define FPIX_TIMEOUT 250
+
+/* Maximum transfer size to use. The windows driver reads by chunks of
+ * 0x2000 bytes, so do the same. Note: reading more seems to work
+ * too. */
+#define FPIX_MAX_TRANSFER 0x2000
+
+/* Structure to hold all of our device specific stuff */
+struct usb_fpix {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	struct work_struct work_struct;
+	struct workqueue_struct *work_thread;
+};
+
+/* Delay after which claim the next frame. If the delay is too small,
+ * the camera will return old frames. On the 4800Z, 20ms is bad, 25ms
+ * will fail every 4 or 5 frames, but 30ms is perfect. On the A210,
+ * 30ms is bad while 35ms is perfect. */
+#define NEXT_FRAME_DELAY 35
+
+/* These cameras only support 320x200. */
+static const struct v4l2_pix_format fpix_mode[1] = {
+	{ 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0}
+};
+
+/* send a command to the webcam */
+static int command(struct gspca_dev *gspca_dev,
+		int order)	/* 0: reset, 1: frame request */
+{
+	static u8 order_values[2][12] = {
+		{0xc6, 0, 0, 0, 0, 0, 0,    0, 0x20, 0, 0, 0},	/* reset */
+		{0xd3, 0, 0, 0, 0, 0, 0, 0x01,    0, 0, 0, 0},	/* fr req */
+	};
+
+	memcpy(gspca_dev->usb_buf, order_values[order], 12);
+	return usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			USB_REQ_GET_STATUS,
+			USB_DIR_OUT | USB_TYPE_CLASS |
+			USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
+			12, FPIX_TIMEOUT);
+}
+
+/* workqueue */
+static void dostream(struct work_struct *work)
+{
+	struct usb_fpix *dev = container_of(work, struct usb_fpix, work_struct);
+	struct gspca_dev *gspca_dev = &dev->gspca_dev;
+	struct urb *urb = gspca_dev->urb[0];
+	u8 *data = urb->transfer_buffer;
+	int ret = 0;
+	int len;
+
+	/* synchronize with the main driver */
+	mutex_lock(&gspca_dev->usb_lock);
+	mutex_unlock(&gspca_dev->usb_lock);
+	PDEBUG(D_STREAM, "dostream started");
+
+	/* loop reading a frame */
+again:
+	while (gspca_dev->dev && gspca_dev->streaming) {
+#ifdef CONFIG_PM
+		if (gspca_dev->frozen)
+			break;
+#endif
+
+		/* request a frame */
+		mutex_lock(&gspca_dev->usb_lock);
+		ret = command(gspca_dev, 1);
+		mutex_unlock(&gspca_dev->usb_lock);
+		if (ret < 0)
+			break;
+#ifdef CONFIG_PM
+		if (gspca_dev->frozen)
+			break;
+#endif
+		if (!gspca_dev->dev || !gspca_dev->streaming)
+			break;
+
+		/* the frame comes in parts */
+		for (;;) {
+			ret = usb_bulk_msg(gspca_dev->dev,
+					urb->pipe,
+					data,
+					FPIX_MAX_TRANSFER,
+					&len, FPIX_TIMEOUT);
+			if (ret < 0) {
+				/* Most of the time we get a timeout
+				 * error. Just restart. */
+				goto again;
+			}
+#ifdef CONFIG_PM
+			if (gspca_dev->frozen)
+				goto out;
+#endif
+			if (!gspca_dev->dev || !gspca_dev->streaming)
+				goto out;
+			if (len < FPIX_MAX_TRANSFER ||
+				(data[len - 2] == 0xff &&
+					data[len - 1] == 0xd9)) {
+
+				/* If the result is less than what was asked
+				 * for, then it's the end of the
+				 * frame. Sometimes the jpeg is not complete,
+				 * but there's nothing we can do. We also end
+				 * here if the the jpeg ends right at the end
+				 * of the frame. */
+				gspca_frame_add(gspca_dev, LAST_PACKET,
+						data, len);
+				break;
+			}
+
+			/* got a partial image */
+			gspca_frame_add(gspca_dev,
+					gspca_dev->last_packet_type
+						== LAST_PACKET
+					? FIRST_PACKET : INTER_PACKET,
+					data, len);
+		}
+
+		/* We must wait before trying reading the next
+		 * frame. If we don't, or if the delay is too short,
+		 * the camera will disconnect. */
+		msleep(NEXT_FRAME_DELAY);
+	}
+
+out:
+	PDEBUG(D_STREAM, "dostream stopped");
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+		const struct usb_device_id *id)
+{
+	struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+	struct cam *cam = &gspca_dev->cam;
+
+	cam->cam_mode = fpix_mode;
+	cam->nmodes = 1;
+	cam->bulk = 1;
+	cam->bulk_size = FPIX_MAX_TRANSFER;
+
+	INIT_WORK(&dev->work_struct, dostream);
+
+	return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+	return 0;
+}
+
+/* start the camera */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+	struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+	int ret, len;
+
+	/* Init the device */
+	ret = command(gspca_dev, 0);
+	if (ret < 0) {
+		pr_err("init failed %d\n", ret);
+		return ret;
+	}
+
+	/* Read the result of the command. Ignore the result, for it
+	 * varies with the device. */
+	ret = usb_bulk_msg(gspca_dev->dev,
+			gspca_dev->urb[0]->pipe,
+			gspca_dev->urb[0]->transfer_buffer,
+			FPIX_MAX_TRANSFER, &len,
+			FPIX_TIMEOUT);
+	if (ret < 0) {
+		pr_err("usb_bulk_msg failed %d\n", ret);
+		return ret;
+	}
+
+	/* Request a frame, but don't read it */
+	ret = command(gspca_dev, 1);
+	if (ret < 0) {
+		pr_err("frame request failed %d\n", ret);
+		return ret;
+	}
+
+	/* Again, reset bulk in endpoint */
+	usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe);
+
+	/* Start the workqueue function to do the streaming */
+	dev->work_thread = create_singlethread_workqueue(MODULE_NAME);
+	queue_work(dev->work_thread, &dev->work_struct);
+
+	return 0;
+}
+
+/* called on streamoff with alt==0 and on disconnect */
+/* the usb_lock is held at entry - restore on exit */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+	struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+
+	/* wait for the work queue to terminate */
+	mutex_unlock(&gspca_dev->usb_lock);
+	destroy_workqueue(dev->work_thread);
+	mutex_lock(&gspca_dev->usb_lock);
+	dev->work_thread = NULL;
+}
+
+/* Table of supported USB devices */
+static const struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x04cb, 0x0104)},
+	{USB_DEVICE(0x04cb, 0x0109)},
+	{USB_DEVICE(0x04cb, 0x010b)},
+	{USB_DEVICE(0x04cb, 0x010f)},
+	{USB_DEVICE(0x04cb, 0x0111)},
+	{USB_DEVICE(0x04cb, 0x0113)},
+	{USB_DEVICE(0x04cb, 0x0115)},
+	{USB_DEVICE(0x04cb, 0x0117)},
+	{USB_DEVICE(0x04cb, 0x0119)},
+	{USB_DEVICE(0x04cb, 0x011b)},
+	{USB_DEVICE(0x04cb, 0x011d)},
+	{USB_DEVICE(0x04cb, 0x0121)},
+	{USB_DEVICE(0x04cb, 0x0123)},
+	{USB_DEVICE(0x04cb, 0x0125)},
+	{USB_DEVICE(0x04cb, 0x0127)},
+	{USB_DEVICE(0x04cb, 0x0129)},
+	{USB_DEVICE(0x04cb, 0x012b)},
+	{USB_DEVICE(0x04cb, 0x012d)},
+	{USB_DEVICE(0x04cb, 0x012f)},
+	{USB_DEVICE(0x04cb, 0x0131)},
+	{USB_DEVICE(0x04cb, 0x013b)},
+	{USB_DEVICE(0x04cb, 0x013d)},
+	{USB_DEVICE(0x04cb, 0x013f)},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name   = MODULE_NAME,
+	.config = sd_config,
+	.init   = sd_init,
+	.start  = sd_start,
+	.stop0  = sd_stop0,
+};
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id,
+			&sd_desc,
+			sizeof(struct usb_fpix),
+			THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name       = MODULE_NAME,
+	.id_table   = device_table,
+	.probe      = sd_probe,
+	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume  = gspca_resume,
+	.reset_resume = gspca_resume,
+#endif
+};
+
+module_usb_driver(sd_driver);
diff --git a/drivers/media/usb/gspca/gl860/Kconfig b/drivers/media/usb/gspca/gl860/Kconfig
new file mode 100644
index 0000000..22772f5
--- /dev/null
+++ b/drivers/media/usb/gspca/gl860/Kconfig
@@ -0,0 +1,8 @@
+config USB_GL860
+	tristate "GL860 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the GL860 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_gl860.
diff --git a/drivers/media/usb/gspca/gl860/Makefile b/drivers/media/usb/gspca/gl860/Makefile
new file mode 100644
index 0000000..cf63974
--- /dev/null
+++ b/drivers/media/usb/gspca/gl860/Makefile
@@ -0,0 +1,10 @@
+obj-$(CONFIG_USB_GL860) += gspca_gl860.o
+
+gspca_gl860-objs := gl860.o \
+		    gl860-mi1320.o \
+		    gl860-ov2640.o \
+		    gl860-ov9655.o \
+		    gl860-mi2020.o
+
+ccflags-y += -I$(srctree)/drivers/media/usb/gspca
+
diff --git a/drivers/media/usb/gspca/gl860/gl860-mi1320.c b/drivers/media/usb/gspca/gl860/gl860-mi1320.c
new file mode 100644
index 0000000..b57160e
--- /dev/null
+++ b/drivers/media/usb/gspca/gl860/gl860-mi1320.c
@@ -0,0 +1,536 @@
+/* Subdriver for the GL860 chip with the MI1320 sensor
+ * Author Olivier LORIN from own logs
+ *
+ * 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
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Sensor : MI1320 */
+
+#include "gl860.h"
+
+static struct validx tbl_common[] = {
+	{0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba51, 0x0066}, {0xba02, 0x00f1},
+	{0xba05, 0x0067}, {0xba05, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1},
+	{0xffff, 0xffff},
+	{0xba00, 0x00f0}, {0xba02, 0x00f1}, {0xbafa, 0x0028}, {0xba02, 0x00f1},
+	{0xba00, 0x00f0}, {0xba01, 0x00f1}, {0xbaf0, 0x0006}, {0xba0e, 0x00f1},
+	{0xba70, 0x0006}, {0xba0e, 0x00f1},
+	{0xffff, 0xffff},
+	{0xba74, 0x0006}, {0xba0e, 0x00f1},
+	{0xffff, 0xffff},
+	{0x0061, 0x0000}, {0x0068, 0x000d},
+};
+
+static struct validx tbl_init_at_startup[] = {
+	{0x0000, 0x0000}, {0x0010, 0x0010},
+	{35, 0xffff},
+	{0x0008, 0x00c0}, {0x0001, 0x00c1}, {0x0001, 0x00c2}, {0x0020, 0x0006},
+	{0x006a, 0x000d},
+};
+
+static struct validx tbl_sensor_settings_common[] = {
+	{0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, {0x0040, 0x0000},
+	{0x006a, 0x0007}, {0x006a, 0x000d}, {0x0063, 0x0006},
+};
+static struct validx tbl_sensor_settings_1280[] = {
+	{0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba5a, 0x0066}, {0xba02, 0x00f1},
+	{0xba05, 0x0067}, {0xba05, 0x00f1}, {0xba20, 0x0065}, {0xba00, 0x00f1},
+};
+static struct validx tbl_sensor_settings_800[] = {
+	{0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba5a, 0x0066}, {0xba02, 0x00f1},
+	{0xba05, 0x0067}, {0xba05, 0x00f1}, {0xba20, 0x0065}, {0xba00, 0x00f1},
+};
+static struct validx tbl_sensor_settings_640[] = {
+	{0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1},
+	{0xba51, 0x0066}, {0xba02, 0x00f1}, {0xba05, 0x0067}, {0xba05, 0x00f1},
+	{0xba20, 0x0065}, {0xba00, 0x00f1},
+};
+static struct validx tbl_post_unset_alt[] = {
+	{0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1},
+	{0x0061, 0x0000}, {0x0068, 0x000d},
+};
+
+static u8 *tbl_1280[] = {
+	"\x0d\x80\xf1\x08\x03\x04\xf1\x00" "\x04\x05\xf1\x02\x05\x00\xf1\xf1"
+	"\x06\x00\xf1\x0d\x20\x01\xf1\x00" "\x21\x84\xf1\x00\x0d\x00\xf1\x08"
+	"\xf0\x00\xf1\x01\x34\x00\xf1\x00" "\x9b\x43\xf1\x00\xa6\x05\xf1\x00"
+	"\xa9\x04\xf1\x00\xa1\x05\xf1\x00" "\xa4\x04\xf1\x00\xae\x0a\xf1\x08"
+	,
+	"\xf0\x00\xf1\x02\x3a\x05\xf1\xf1" "\x3c\x05\xf1\xf1\x59\x01\xf1\x47"
+	"\x5a\x01\xf1\x88\x5c\x0a\xf1\x06" "\x5d\x0e\xf1\x0a\x64\x5e\xf1\x1c"
+	"\xd2\x00\xf1\xcf\xcb\x00\xf1\x01"
+	,
+	"\xd3\x02\xd4\x28\xd5\x01\xd0\x02" "\xd1\x18\xd2\xc1"
+};
+
+static u8 *tbl_800[] = {
+	"\x0d\x80\xf1\x08\x03\x03\xf1\xc0" "\x04\x05\xf1\x02\x05\x00\xf1\xf1"
+	"\x06\x00\xf1\x0d\x20\x01\xf1\x00" "\x21\x84\xf1\x00\x0d\x00\xf1\x08"
+	"\xf0\x00\xf1\x01\x34\x00\xf1\x00" "\x9b\x43\xf1\x00\xa6\x05\xf1\x00"
+	"\xa9\x03\xf1\xc0\xa1\x03\xf1\x20" "\xa4\x02\xf1\x5a\xae\x0a\xf1\x08"
+	,
+	"\xf0\x00\xf1\x02\x3a\x05\xf1\xf1" "\x3c\x05\xf1\xf1\x59\x01\xf1\x47"
+	"\x5a\x01\xf1\x88\x5c\x0a\xf1\x06" "\x5d\x0e\xf1\x0a\x64\x5e\xf1\x1c"
+	"\xd2\x00\xf1\xcf\xcb\x00\xf1\x01"
+	,
+	"\xd3\x02\xd4\x18\xd5\x21\xd0\x02" "\xd1\x10\xd2\x59"
+};
+
+static u8 *tbl_640[] = {
+	"\x0d\x80\xf1\x08\x03\x04\xf1\x04" "\x04\x05\xf1\x02\x07\x01\xf1\x7c"
+	"\x08\x00\xf1\x0e\x21\x80\xf1\x00" "\x0d\x00\xf1\x08\xf0\x00\xf1\x01"
+	"\x34\x10\xf1\x10\x3a\x43\xf1\x00" "\xa6\x05\xf1\x02\xa9\x04\xf1\x04"
+	"\xa7\x02\xf1\x81\xaa\x01\xf1\xe2" "\xae\x0c\xf1\x09"
+	,
+	"\xf0\x00\xf1\x02\x39\x03\xf1\xfc" "\x3b\x04\xf1\x04\x57\x01\xf1\xb6"
+	"\x58\x02\xf1\x0d\x5c\x1f\xf1\x19" "\x5d\x24\xf1\x1e\x64\x5e\xf1\x1c"
+	"\xd2\x00\xf1\x00\xcb\x00\xf1\x01"
+	,
+	"\xd3\x02\xd4\x10\xd5\x81\xd0\x02" "\xd1\x08\xd2\xe1"
+};
+
+static s32 tbl_sat[] = {0x25, 0x1d, 0x15, 0x0d, 0x05, 0x4d, 0x55, 0x5d, 0x2d};
+static s32 tbl_bright[] = {0, 8, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70};
+static s32 tbl_backlight[] = {0x0e, 0x06, 0x02};
+
+static s32 tbl_cntr1[] = {
+	0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0, 0xc8, 0xd0, 0xe0, 0xf0};
+static s32 tbl_cntr2[] = {
+	0x70, 0x68, 0x60, 0x58, 0x50, 0x48, 0x40, 0x38, 0x30, 0x20, 0x10};
+
+static u8 dat_wbalNL[] =
+	"\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x3b\x04\xf1\x2a\x47\x10\xf1\x10"
+	"\x9d\x3c\xf1\xae\xaf\x10\xf1\x00" "\xf0\x00\xf1\x02\x2f\x91\xf1\x20"
+	"\x9c\x91\xf1\x20\x37\x03\xf1\x00" "\x9d\xc5\xf1\x0f\xf0\x00\xf1\x00";
+
+static u8 dat_wbalLL[] =
+	"\xf0\x00\xf1\x01\x05\x00\xf1\x0c" "\x3b\x04\xf1\x2a\x47\x40\xf1\x40"
+	"\x9d\x20\xf1\xae\xaf\x10\xf1\x00" "\xf0\x00\xf1\x02\x2f\xd1\xf1\x00"
+	"\x9c\xd1\xf1\x00\x37\x03\xf1\x00" "\x9d\xc5\xf1\x3f\xf0\x00\xf1\x00";
+
+static u8 dat_wbalBL[] =
+	"\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x47\x10\xf1\x30\x9d\x3c\xf1\xae"
+	"\xaf\x10\xf1\x00\xf0\x00\xf1\x02" "\x2f\x91\xf1\x20\x9c\x91\xf1\x20"
+	"\x37\x03\xf1\x00\x9d\xc5\xf1\x2f" "\xf0\x00\xf1\x00";
+
+static u8 dat_hvflip1[] = {0xf0, 0x00, 0xf1, 0x00};
+
+static u8 dat_common00[] =
+	"\x00\x01\x07\x6a\x06\x63\x0d\x6a" "\xc0\x00\x10\x10\xc1\x03\xc2\x42"
+	"\xd8\x04\x58\x00\x04\x02";
+static u8 dat_common01[] =
+	"\x0d\x00\xf1\x0b\x0d\x00\xf1\x08" "\x35\x00\xf1\x22\x68\x00\xf1\x5d"
+	"\xf0\x00\xf1\x01\x06\x70\xf1\x0e" "\xf0\x00\xf1\x02\xdd\x18\xf1\xe0";
+static u8 dat_common02[] =
+	"\x05\x01\xf1\x84\x06\x00\xf1\x44" "\x07\x00\xf1\xbe\x08\x00\xf1\x1e"
+	"\x20\x01\xf1\x03\x21\x84\xf1\x00" "\x22\x0d\xf1\x0f\x24\x80\xf1\x00"
+	"\x34\x18\xf1\x2d\x35\x00\xf1\x22" "\x43\x83\xf1\x83\x59\x00\xf1\xff";
+static u8 dat_common03[] =
+	"\xf0\x00\xf1\x02\x39\x06\xf1\x8c" "\x3a\x06\xf1\x8c\x3b\x03\xf1\xda"
+	"\x3c\x05\xf1\x30\x57\x01\xf1\x0c" "\x58\x01\xf1\x42\x59\x01\xf1\x0c"
+	"\x5a\x01\xf1\x42\x5c\x13\xf1\x0e" "\x5d\x17\xf1\x12\x64\x1e\xf1\x1c";
+static u8 dat_common04[] =
+	"\xf0\x00\xf1\x02\x24\x5f\xf1\x20" "\x28\xea\xf1\x02\x5f\x41\xf1\x43";
+static u8 dat_common05[] =
+	"\x02\x00\xf1\xee\x03\x29\xf1\x1a" "\x04\x02\xf1\xa4\x09\x00\xf1\x68"
+	"\x0a\x00\xf1\x2a\x0b\x00\xf1\x04" "\x0c\x00\xf1\x93\x0d\x00\xf1\x82"
+	"\x0e\x00\xf1\x40\x0f\x00\xf1\x5f" "\x10\x00\xf1\x4e\x11\x00\xf1\x5b";
+static u8 dat_common06[] =
+	"\x15\x00\xf1\xc9\x16\x00\xf1\x5e" "\x17\x00\xf1\x9d\x18\x00\xf1\x06"
+	"\x19\x00\xf1\x89\x1a\x00\xf1\x12" "\x1b\x00\xf1\xa1\x1c\x00\xf1\xe4"
+	"\x1d\x00\xf1\x7a\x1e\x00\xf1\x64" "\xf6\x00\xf1\x5f";
+static u8 dat_common07[] =
+	"\xf0\x00\xf1\x01\x53\x09\xf1\x03" "\x54\x3d\xf1\x1c\x55\x99\xf1\x72"
+	"\x56\xc1\xf1\xb1\x57\xd8\xf1\xce" "\x58\xe0\xf1\x00\xdc\x0a\xf1\x03"
+	"\xdd\x45\xf1\x20\xde\xae\xf1\x82" "\xdf\xdc\xf1\xc9\xe0\xf6\xf1\xea"
+	"\xe1\xff\xf1\x00";
+static u8 dat_common08[] =
+	"\xf0\x00\xf1\x01\x80\x00\xf1\x06" "\x81\xf6\xf1\x08\x82\xfb\xf1\xf7"
+	"\x83\x00\xf1\xfe\xb6\x07\xf1\x03" "\xb7\x18\xf1\x0c\x84\xfb\xf1\x06"
+	"\x85\xfb\xf1\xf9\x86\x00\xf1\xff" "\xb8\x07\xf1\x04\xb9\x16\xf1\x0a";
+static u8 dat_common09[] =
+	"\x87\xfa\xf1\x05\x88\xfc\xf1\xf9" "\x89\x00\xf1\xff\xba\x06\xf1\x03"
+	"\xbb\x17\xf1\x09\x8a\xe8\xf1\x14" "\x8b\xf7\xf1\xf0\x8c\xfd\xf1\xfa"
+	"\x8d\x00\xf1\x00\xbc\x05\xf1\x01" "\xbd\x0c\xf1\x08\xbe\x00\xf1\x14";
+static u8 dat_common10[] =
+	"\x8e\xea\xf1\x13\x8f\xf7\xf1\xf2" "\x90\xfd\xf1\xfa\x91\x00\xf1\x00"
+	"\xbf\x05\xf1\x01\xc0\x0a\xf1\x08" "\xc1\x00\xf1\x0c\x92\xed\xf1\x0f"
+	"\x93\xf9\xf1\xf4\x94\xfe\xf1\xfb" "\x95\x00\xf1\x00\xc2\x04\xf1\x01"
+	"\xc3\x0a\xf1\x07\xc4\x00\xf1\x10";
+static u8 dat_common11[] =
+	"\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x25\x00\xf1\x55\x34\x10\xf1\x10"
+	"\x35\xf0\xf1\x10\x3a\x02\xf1\x03" "\x3b\x04\xf1\x2a\x9b\x43\xf1\x00"
+	"\xa4\x03\xf1\xc0\xa7\x02\xf1\x81";
+
+static int  mi1320_init_at_startup(struct gspca_dev *gspca_dev);
+static int  mi1320_configure_alt(struct gspca_dev *gspca_dev);
+static int  mi1320_init_pre_alt(struct gspca_dev *gspca_dev);
+static int  mi1320_init_post_alt(struct gspca_dev *gspca_dev);
+static void mi1320_post_unset_alt(struct gspca_dev *gspca_dev);
+static int  mi1320_sensor_settings(struct gspca_dev *gspca_dev);
+static int  mi1320_camera_settings(struct gspca_dev *gspca_dev);
+/*==========================================================================*/
+
+void mi1320_init_settings(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->vcur.backlight  =  0;
+	sd->vcur.brightness =  0;
+	sd->vcur.sharpness  =  6;
+	sd->vcur.contrast   = 10;
+	sd->vcur.gamma      = 20;
+	sd->vcur.hue        =  0;
+	sd->vcur.saturation =  6;
+	sd->vcur.whitebal   =  0;
+	sd->vcur.mirror     = 0;
+	sd->vcur.flip       = 0;
+	sd->vcur.AC50Hz     = 1;
+
+	sd->vmax.backlight  =  2;
+	sd->vmax.brightness =  8;
+	sd->vmax.sharpness  =  7;
+	sd->vmax.contrast   =  0; /* 10 but not working with this driver */
+	sd->vmax.gamma      = 40;
+	sd->vmax.hue        =  5 + 1;
+	sd->vmax.saturation =  8;
+	sd->vmax.whitebal   =  2;
+	sd->vmax.mirror     = 1;
+	sd->vmax.flip       = 1;
+	sd->vmax.AC50Hz     = 1;
+
+	sd->dev_camera_settings = mi1320_camera_settings;
+	sd->dev_init_at_startup = mi1320_init_at_startup;
+	sd->dev_configure_alt   = mi1320_configure_alt;
+	sd->dev_init_pre_alt    = mi1320_init_pre_alt;
+	sd->dev_post_unset_alt  = mi1320_post_unset_alt;
+}
+
+/*==========================================================================*/
+
+static void common(struct gspca_dev *gspca_dev)
+{
+	s32 n; /* reserved for FETCH functions */
+
+	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 22, dat_common00);
+	ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 32, dat_common01);
+	n = fetch_validx(gspca_dev, tbl_common, ARRAY_SIZE(tbl_common));
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common02);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common03);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 16, dat_common04);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common05);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 44, dat_common06);
+	keep_on_fetching_validx(gspca_dev, tbl_common,
+					ARRAY_SIZE(tbl_common), n);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 52, dat_common07);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common08);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common09);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 56, dat_common10);
+	keep_on_fetching_validx(gspca_dev, tbl_common,
+					ARRAY_SIZE(tbl_common), n);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, dat_common11);
+	keep_on_fetching_validx(gspca_dev, tbl_common,
+					ARRAY_SIZE(tbl_common), n);
+}
+
+static int mi1320_init_at_startup(struct gspca_dev *gspca_dev)
+{
+	fetch_validx(gspca_dev, tbl_init_at_startup,
+				ARRAY_SIZE(tbl_init_at_startup));
+
+	common(gspca_dev);
+
+/*	ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */
+
+	return 0;
+}
+
+static int mi1320_init_pre_alt(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->mirrorMask = 0;
+
+	sd->vold.backlight  = -1;
+	sd->vold.brightness = -1;
+	sd->vold.sharpness  = -1;
+	sd->vold.contrast   = -1;
+	sd->vold.saturation = -1;
+	sd->vold.gamma    = -1;
+	sd->vold.hue      = -1;
+	sd->vold.whitebal = -1;
+	sd->vold.mirror   = -1;
+	sd->vold.flip     = -1;
+	sd->vold.AC50Hz   = -1;
+
+	common(gspca_dev);
+
+	mi1320_sensor_settings(gspca_dev);
+
+	mi1320_init_post_alt(gspca_dev);
+
+	return 0;
+}
+
+static int mi1320_init_post_alt(struct gspca_dev *gspca_dev)
+{
+	mi1320_camera_settings(gspca_dev);
+
+	return 0;
+}
+
+static int mi1320_sensor_settings(struct gspca_dev *gspca_dev)
+{
+	s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
+
+	ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
+
+	fetch_validx(gspca_dev, tbl_sensor_settings_common,
+				ARRAY_SIZE(tbl_sensor_settings_common));
+
+	switch (reso) {
+	case IMAGE_1280:
+		fetch_validx(gspca_dev, tbl_sensor_settings_1280,
+					ARRAY_SIZE(tbl_sensor_settings_1280));
+		ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 64, tbl_1280[0]);
+		ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_1280[1]);
+		ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_1280[2]);
+		break;
+
+	case IMAGE_800:
+		fetch_validx(gspca_dev, tbl_sensor_settings_800,
+					ARRAY_SIZE(tbl_sensor_settings_800));
+		ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 64, tbl_800[0]);
+		ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_800[1]);
+		ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_800[2]);
+		break;
+
+	default:
+		fetch_validx(gspca_dev, tbl_sensor_settings_640,
+					ARRAY_SIZE(tbl_sensor_settings_640));
+		ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 60, tbl_640[0]);
+		ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_640[1]);
+		ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_640[2]);
+		break;
+	}
+	return 0;
+}
+
+static int mi1320_configure_alt(struct gspca_dev *gspca_dev)
+{
+	s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
+
+	switch (reso) {
+	case IMAGE_640:
+		gspca_dev->alt = 3 + 1;
+		break;
+
+	case IMAGE_800:
+	case IMAGE_1280:
+		gspca_dev->alt = 1 + 1;
+		break;
+	}
+	return 0;
+}
+
+static int mi1320_camera_settings(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	s32 backlight = sd->vcur.backlight;
+	s32 bright = sd->vcur.brightness;
+	s32 sharp  = sd->vcur.sharpness;
+	s32 cntr   = sd->vcur.contrast;
+	s32 gam	   = sd->vcur.gamma;
+	s32 hue    = sd->vcur.hue;
+	s32 sat	   = sd->vcur.saturation;
+	s32 wbal   = sd->vcur.whitebal;
+	s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0);
+	s32 flip   = (((sd->vcur.flip   > 0) ^ sd->mirrorMask) > 0);
+	s32 freq   = (sd->vcur.AC50Hz > 0);
+	s32 i;
+
+	if (freq != sd->vold.AC50Hz) {
+		sd->vold.AC50Hz = freq;
+
+		freq = 2 * (freq == 0);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba02, 0x00f1, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00       , 0x005b, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba01 + freq, 0x00f1, 0, NULL);
+	}
+
+	if (wbal != sd->vold.whitebal) {
+		sd->vold.whitebal = wbal;
+		if (wbal < 0 || wbal > sd->vmax.whitebal)
+			wbal = 0;
+
+		for (i = 0; i < 2; i++) {
+			if (wbal == 0) { /* Normal light */
+				ctrl_out(gspca_dev, 0x40, 1,
+						0x0010, 0x0010, 0, NULL);
+				ctrl_out(gspca_dev, 0x40, 1,
+						0x0003, 0x00c1, 0, NULL);
+				ctrl_out(gspca_dev, 0x40, 1,
+						0x0042, 0x00c2, 0, NULL);
+				ctrl_out(gspca_dev, 0x40, 3,
+						0xba00, 0x0200, 48, dat_wbalNL);
+			}
+
+			if (wbal == 1) { /* Low light */
+				ctrl_out(gspca_dev, 0x40, 1,
+						0x0010, 0x0010, 0, NULL);
+				ctrl_out(gspca_dev, 0x40, 1,
+						0x0004, 0x00c1, 0, NULL);
+				ctrl_out(gspca_dev, 0x40, 1,
+						0x0043, 0x00c2, 0, NULL);
+				ctrl_out(gspca_dev, 0x40, 3,
+						0xba00, 0x0200, 48, dat_wbalLL);
+			}
+
+			if (wbal == 2) { /* Back light */
+				ctrl_out(gspca_dev, 0x40, 1,
+						0x0010, 0x0010, 0, NULL);
+				ctrl_out(gspca_dev, 0x40, 1,
+						0x0003, 0x00c1, 0, NULL);
+				ctrl_out(gspca_dev, 0x40, 1,
+						0x0042, 0x00c2, 0, NULL);
+				ctrl_out(gspca_dev, 0x40, 3,
+						0xba00, 0x0200, 44, dat_wbalBL);
+			}
+		}
+	}
+
+	if (bright != sd->vold.brightness) {
+		sd->vold.brightness = bright;
+		if (bright < 0 || bright > sd->vmax.brightness)
+			bright = 0;
+
+		bright = tbl_bright[bright];
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00 + bright, 0x0034, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00 + bright, 0x00f1, 0, NULL);
+	}
+
+	if (sat != sd->vold.saturation) {
+		sd->vold.saturation = sat;
+		if (sat < 0 || sat > sd->vmax.saturation)
+			sat = 0;
+
+		sat = tbl_sat[sat];
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00      , 0x0025, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00 + sat, 0x00f1, 0, NULL);
+	}
+
+	if (sharp != sd->vold.sharpness) {
+		sd->vold.sharpness = sharp;
+		if (sharp < 0 || sharp > sd->vmax.sharpness)
+			sharp = 0;
+
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00        , 0x0005, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00 + sharp, 0x00f1, 0, NULL);
+	}
+
+	if (hue != sd->vold.hue) {
+		/* 0=normal  1=NB  2="sepia"  3=negative  4=other  5=other2 */
+		if (hue < 0 || hue > sd->vmax.hue)
+			hue = 0;
+		if (hue == sd->vmax.hue)
+			sd->swapRB = 1;
+		else
+			sd->swapRB = 0;
+
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba70, 0x00e2, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00 + hue * (hue < 6), 0x00f1,
+							0, NULL);
+	}
+
+	if (backlight != sd->vold.backlight) {
+		sd->vold.backlight = backlight;
+		if (backlight < 0 || backlight > sd->vmax.backlight)
+			backlight = 0;
+
+		backlight = tbl_backlight[backlight];
+		for (i = 0; i < 2; i++) {
+			ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
+			ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
+			ctrl_out(gspca_dev, 0x40, 1, 0xba74, 0x0006, 0, NULL);
+			ctrl_out(gspca_dev, 0x40, 1, 0xba80 + backlight, 0x00f1,
+								0, NULL);
+		}
+	}
+
+	if (hue != sd->vold.hue) {
+		sd->vold.hue = hue;
+
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba70, 0x00e2, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00 + hue * (hue < 6), 0x00f1,
+							0, NULL);
+	}
+
+	if (mirror != sd->vold.mirror || flip != sd->vold.flip) {
+		u8 dat_hvflip2[4] = {0x20, 0x01, 0xf1, 0x00};
+		sd->vold.mirror = mirror;
+		sd->vold.flip = flip;
+
+		dat_hvflip2[3] = flip + 2 * mirror;
+		ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 4, dat_hvflip1);
+		ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 4, dat_hvflip2);
+	}
+
+	if (gam != sd->vold.gamma) {
+		sd->vold.gamma = gam;
+		if (gam < 0 || gam > sd->vmax.gamma)
+			gam = 0;
+
+		gam = 2 * gam;
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba04      , 0x003b, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba02 + gam, 0x00f1, 0, NULL);
+	}
+
+	if (cntr != sd->vold.contrast) {
+		sd->vold.contrast = cntr;
+		if (cntr < 0 || cntr > sd->vmax.contrast)
+			cntr = 0;
+
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00 + tbl_cntr1[cntr], 0x0035,
+							0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0xba00 + tbl_cntr2[cntr], 0x00f1,
+							0, NULL);
+	}
+
+	return 0;
+}
+
+static void mi1320_post_unset_alt(struct gspca_dev *gspca_dev)
+{
+	ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL);
+
+	fetch_validx(gspca_dev, tbl_post_unset_alt,
+				ARRAY_SIZE(tbl_post_unset_alt));
+}
diff --git a/drivers/media/usb/gspca/gl860/gl860-mi2020.c b/drivers/media/usb/gspca/gl860/gl860-mi2020.c
new file mode 100644
index 0000000..2edda6b
--- /dev/null
+++ b/drivers/media/usb/gspca/gl860/gl860-mi2020.c
@@ -0,0 +1,733 @@
+/* Subdriver for the GL860 chip with the MI2020 sensor
+ * Author Olivier LORIN, from logs by Iceman/Soro2005 + Fret_saw/Hulkie/Tricid
+ * with the help of Kytrix/BUGabundo/Blazercist.
+ * Driver achieved thanks to a webcam gift by Kytrix.
+ *
+ * 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
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Sensor : MI2020 */
+
+#include "gl860.h"
+
+static u8 dat_wbal1[] = {0x8c, 0xa2, 0x0c};
+
+static u8 dat_bright1[] = {0x8c, 0xa2, 0x06};
+static u8 dat_bright3[] = {0x8c, 0xa1, 0x02};
+static u8 dat_bright4[] = {0x90, 0x00, 0x0f};
+static u8 dat_bright5[] = {0x8c, 0xa1, 0x03};
+static u8 dat_bright6[] = {0x90, 0x00, 0x05};
+
+static u8 dat_hvflip1[] = {0x8c, 0x27, 0x19};
+static u8 dat_hvflip3[] = {0x8c, 0x27, 0x3b};
+static u8 dat_hvflip5[] = {0x8c, 0xa1, 0x03};
+static u8 dat_hvflip6[] = {0x90, 0x00, 0x06};
+
+static struct idxdata tbl_middle_hvflip_low[] = {
+	{0x33, "\x90\x00\x06"},
+	{6, "\xff\xff\xff"},
+	{0x33, "\x90\x00\x06"},
+	{6, "\xff\xff\xff"},
+	{0x33, "\x90\x00\x06"},
+	{6, "\xff\xff\xff"},
+	{0x33, "\x90\x00\x06"},
+	{6, "\xff\xff\xff"},
+};
+
+static struct idxdata tbl_middle_hvflip_big[] = {
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa1\x20"},
+	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
+	{102, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x20"},
+	{0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+};
+
+static struct idxdata tbl_end_hvflip[] = {
+	{0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+	{6, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+	{6, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+	{6, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+};
+
+static u8 dat_freq1[] = { 0x8c, 0xa4, 0x04 };
+
+static u8 dat_multi5[] = { 0x8c, 0xa1, 0x03 };
+static u8 dat_multi6[] = { 0x90, 0x00, 0x05 };
+
+static struct validx tbl_init_at_startup[] = {
+	{0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1},
+	{0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d},
+	{53, 0xffff},
+	{0x0040, 0x0000}, {0x0063, 0x0006},
+};
+
+static struct validx tbl_common_0B[] = {
+	{0x0002, 0x0004}, {0x006a, 0x0007}, {0x00ef, 0x0006}, {0x006a, 0x000d},
+	{0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2},
+	{0x0004, 0x00d8}, {0x0000, 0x0058}, {0x0041, 0x0000},
+};
+
+static struct idxdata tbl_common_3B[] = {
+	{0x33, "\x86\x25\x01"}, {0x33, "\x86\x25\x00"},
+	{2, "\xff\xff\xff"},
+	{0x30, "\x1a\x0a\xcc"}, {0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"},
+	{6, "\xff\xff\xff"}, /* 12 */
+	{0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
+	{2, "\xff\xff\xff"}, /* - */
+	{0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\x22\x23"},
+	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0f"}, {0x33, "\x90\x00\x0d"},
+	{0x33, "\x8c\xa2\x10"}, {0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x11"},
+	{0x33, "\x90\x00\x07"}, {0x33, "\xf4\x03\x1d"}, {0x35, "\xa2\x00\xe2"},
+	{0x33, "\x8c\xab\x05"}, {0x33, "\x90\x00\x01"}, {0x32, "\x6e\x00\x86"},
+	{0x32, "\x70\x0f\xaa"}, {0x32, "\x72\x0f\xe4"}, {0x33, "\x8c\xa3\x4a"},
+	{0x33, "\x90\x00\x5a"}, {0x33, "\x8c\xa3\x4b"}, {0x33, "\x90\x00\xa6"},
+	{0x33, "\x8c\xa3\x61"}, {0x33, "\x90\x00\xc8"}, {0x33, "\x8c\xa3\x62"},
+	{0x33, "\x90\x00\xe1"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
+	{0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
+	{0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
+	{0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"},
+	{0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"},
+	{0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"},
+	{0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"},
+	{0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"},
+	{0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"},
+	{0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"},
+	{0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"},
+	{0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"},
+	{0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"},
+	{0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"},
+	{0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"},
+	{0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"},
+	{0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"},
+	{0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"},
+	{0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"},
+	{0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"},
+	{0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"},
+	{0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"},
+	{0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"},
+	{0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"},
+	{0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"},
+	{0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"},
+	{0x33, "\x78\x00\x00"},
+	{2, "\xff\xff\xff"},
+	{0x35, "\xb8\x1f\x20"}, {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x10"},
+	{0x33, "\x8c\xa2\x07"}, {0x33, "\x90\x00\x08"}, {0x33, "\x8c\xa2\x42"},
+	{0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x4a"}, {0x33, "\x90\x00\x8c"},
+	{0x35, "\xba\xfa\x08"}, {0x33, "\x8c\xa2\x02"}, {0x33, "\x90\x00\x22"},
+	{0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"}, {0x33, "\x8c\xa4\x04"},
+	{0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"}, {0x33, "\x90\x00\x00"},
+	{0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0c"},
+	{0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"}, {0x33, "\x90\x00\x04"},
+	{0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"}, {0x33, "\x8c\xa1\x03"},
+	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"},
+	{0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x25"},
+	{0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"},
+	{0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x47"},
+	{0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"}, {0x33, "\x90\x02\x84"},
+	{0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"}, {0x33, "\x8c\x27\x07"},
+	{0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"}, {0x33, "\x90\x04\xb0"},
+	{0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x0f"},
+	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"}, {0x33, "\x90\x04\xbd"},
+	{0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"}, {0x33, "\x8c\x27\x15"},
+	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"},
+	{0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"}, {0x33, "\x8c\x27\x1b"},
+	{0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"}, {0x33, "\x90\x01\x02"},
+	{0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"}, {0x33, "\x8c\x27\x21"},
+	{0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"}, {0x33, "\x90\x02\x85"},
+	{0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x27"},
+	{0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"}, {0x33, "\x90\x20\x20"},
+	{0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"}, {0x33, "\x8c\x27\x2d"},
+	{0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"}, {0x33, "\x90\x00\x04"},
+	{0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x33"},
+	{0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"}, {0x33, "\x90\x06\x4b"},
+	{0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x39"},
+	{0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"},
+	{0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x41"},
+	{0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"}, {0x33, "\x90\x04\xed"},
+	{0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x51"},
+	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"}, {0x33, "\x90\x03\x20"},
+	{0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x57"},
+	{0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"}, {0x33, "\x90\x00\x00"},
+	{0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x63"},
+	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"}, {0x33, "\x90\x04\xb0"},
+	{0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"}, {0x33, "\x8c\xa4\x08"},
+	{0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x21"},
+	{0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\xa4\x0b"},
+	{0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa1"},
+	{0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"}, {0x33, "\x8c\x24\x15"},
+	{0x33, "\x90\x00\x6a"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\x80"},
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
+	{2, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
+	{3, "\xff\xff\xff"},
+};
+
+static struct idxdata tbl_init_post_alt_low1[] = {
+	{0x33, "\x8c\x27\x15"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\x22\x2e"},
+	{0x33, "\x90\x00\x81"}, {0x33, "\x8c\xa4\x08"}, {0x33, "\x90\x00\x17"},
+	{0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x1a"}, {0x33, "\x8c\xa4\x0a"},
+	{0x33, "\x90\x00\x1d"}, {0x33, "\x8c\xa4\x0b"}, {0x33, "\x90\x00\x20"},
+	{0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\x81"}, {0x33, "\x8c\x24\x13"},
+	{0x33, "\x90\x00\x9b"},
+};
+
+static struct idxdata tbl_init_post_alt_low2[] = {
+	{0x33, "\x8c\x27\x03"}, {0x33, "\x90\x03\x24"}, {0x33, "\x8c\x27\x05"},
+	{0x33, "\x90\x02\x58"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
+	{2, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
+	{2, "\xff\xff\xff"},
+};
+
+static struct idxdata tbl_init_post_alt_low3[] = {
+	{0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
+	{2, "\xff\xff\xff"},
+	{0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x20"},
+	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"},
+	{0x33, "\x2e\x01\x00"}, {0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"},
+	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x95"}, {0x33, "\x90\x01\x00"},
+	{2, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"},
+	{0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+	{2, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"},
+	{0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
+	{2, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
+	{2, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
+	{2, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
+	{2, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
+};
+
+static struct idxdata tbl_init_post_alt_big[] = {
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
+	{2, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
+	{2, "\xff\xff\xff"},
+	{0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
+	{2, "\xff\xff\xff"},
+	{0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x03"},
+	{0x33, "\x90\x00\x05"},
+	{2, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
+	{2, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
+	{2, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, {0x33, "\x8c\xa1\x20"},
+	{0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x30"}, {0x33, "\x90\x00\x03"},
+	{0x33, "\x8c\xa1\x31"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x32"},
+	{0x33, "\x90\x00\x03"}, {0x33, "\x8c\xa1\x34"}, {0x33, "\x90\x00\x03"},
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x2e\x01\x00"},
+	{0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+	{0x33, "\x8c\x27\x97"}, {0x33, "\x90\x01\x00"},
+	{51, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"},
+	{0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
+	{51, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"},
+	{0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+	{51, "\xff\xff\xff"},
+};
+
+static struct idxdata tbl_init_post_alt_3B[] = {
+	{0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
+	{0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
+	{0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
+	{0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"},
+	{0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"},
+	{0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"},
+	{0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"},
+	{0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"},
+	{0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"},
+	{0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"},
+	{0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"},
+	{0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"},
+	{0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"},
+	{0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"},
+	{0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"},
+	{0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"},
+	{0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"},
+	{0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"},
+	{0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"},
+	{0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"},
+	{0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"},
+	{0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"},
+	{0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"},
+	{0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"},
+	{0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"},
+	{0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"},
+};
+
+static u8 *dat_640  = "\xd0\x02\xd1\x08\xd2\xe1\xd3\x02\xd4\x10\xd5\x81";
+static u8 *dat_800  = "\xd0\x02\xd1\x10\xd2\x57\xd3\x02\xd4\x18\xd5\x21";
+static u8 *dat_1280 = "\xd0\x02\xd1\x20\xd2\x01\xd3\x02\xd4\x28\xd5\x01";
+static u8 *dat_1600 = "\xd0\x02\xd1\x20\xd2\xaf\xd3\x02\xd4\x30\xd5\x41";
+
+static int  mi2020_init_at_startup(struct gspca_dev *gspca_dev);
+static int  mi2020_configure_alt(struct gspca_dev *gspca_dev);
+static int  mi2020_init_pre_alt(struct gspca_dev *gspca_dev);
+static int  mi2020_init_post_alt(struct gspca_dev *gspca_dev);
+static void mi2020_post_unset_alt(struct gspca_dev *gspca_dev);
+static int  mi2020_camera_settings(struct gspca_dev *gspca_dev);
+/*==========================================================================*/
+
+void mi2020_init_settings(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->vcur.backlight  =  0;
+	sd->vcur.brightness = 70;
+	sd->vcur.sharpness  = 20;
+	sd->vcur.contrast   =  0;
+	sd->vcur.gamma      =  0;
+	sd->vcur.hue        =  0;
+	sd->vcur.saturation = 60;
+	sd->vcur.whitebal   =  0; /* 50, not done by hardware */
+	sd->vcur.mirror = 0;
+	sd->vcur.flip   = 0;
+	sd->vcur.AC50Hz = 1;
+
+	sd->vmax.backlight  =  64;
+	sd->vmax.brightness = 128;
+	sd->vmax.sharpness  =  40;
+	sd->vmax.contrast   =   3;
+	sd->vmax.gamma      =   2;
+	sd->vmax.hue        =   0 + 1; /* 200, not done by hardware */
+	sd->vmax.saturation =   0;     /* 100, not done by hardware */
+	sd->vmax.whitebal   =   2;     /* 100, not done by hardware */
+	sd->vmax.mirror = 1;
+	sd->vmax.flip   = 1;
+	sd->vmax.AC50Hz = 1;
+
+	sd->dev_camera_settings = mi2020_camera_settings;
+	sd->dev_init_at_startup = mi2020_init_at_startup;
+	sd->dev_configure_alt   = mi2020_configure_alt;
+	sd->dev_init_pre_alt    = mi2020_init_pre_alt;
+	sd->dev_post_unset_alt  = mi2020_post_unset_alt;
+}
+
+/*==========================================================================*/
+
+static void common(struct gspca_dev *gspca_dev)
+{
+	fetch_validx(gspca_dev, tbl_common_0B, ARRAY_SIZE(tbl_common_0B));
+	fetch_idxdata(gspca_dev, tbl_common_3B, ARRAY_SIZE(tbl_common_3B));
+	ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL);
+}
+
+static int mi2020_init_at_startup(struct gspca_dev *gspca_dev)
+{
+	u8 c;
+
+	ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &c);
+	ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &c);
+
+	fetch_validx(gspca_dev, tbl_init_at_startup,
+			ARRAY_SIZE(tbl_init_at_startup));
+
+	ctrl_out(gspca_dev, 0x40,  1, 0x7a00, 0x8030,  0, NULL);
+	ctrl_in(gspca_dev, 0xc0,  2, 0x7a00, 0x8030,  1, &c);
+
+	common(gspca_dev);
+
+	msleep(61);
+/*	ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000,  0, NULL); */
+/*	msleep(36); */
+	ctrl_out(gspca_dev, 0x40,  1, 0x0001, 0x0000,  0, NULL);
+
+	return 0;
+}
+
+static int mi2020_init_pre_alt(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->mirrorMask =  0;
+	sd->vold.hue   = -1;
+
+	/* These controls need to be reset */
+	sd->vold.brightness = -1;
+	sd->vold.sharpness  = -1;
+
+	/* If not different from default, they do not need to be set */
+	sd->vold.contrast  = 0;
+	sd->vold.gamma     = 0;
+	sd->vold.backlight = 0;
+
+	mi2020_init_post_alt(gspca_dev);
+
+	return 0;
+}
+
+static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
+
+	s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0);
+	s32 flip   = (((sd->vcur.flip   > 0) ^ sd->mirrorMask) > 0);
+	s32 freq   = (sd->vcur.AC50Hz  > 0);
+	s32 wbal   = sd->vcur.whitebal;
+
+	u8 dat_freq2[] = {0x90, 0x00, 0x80};
+	u8 dat_multi1[] = {0x8c, 0xa7, 0x00};
+	u8 dat_multi2[] = {0x90, 0x00, 0x00};
+	u8 dat_multi3[] = {0x8c, 0xa7, 0x00};
+	u8 dat_multi4[] = {0x90, 0x00, 0x00};
+	u8 dat_hvflip2[] = {0x90, 0x04, 0x6c};
+	u8 dat_hvflip4[] = {0x90, 0x00, 0x24};
+	u8 dat_wbal2[] = {0x90, 0x00, 0x00};
+	u8 c;
+
+	sd->nbIm = -1;
+
+	dat_freq2[2] = freq ? 0xc0 : 0x80;
+	dat_multi1[2] = 0x9d;
+	dat_multi3[2] = dat_multi1[2] + 1;
+	if (wbal == 0) {
+		dat_multi4[2] = dat_multi2[2] = 0;
+		dat_wbal2[2] = 0x17;
+	} else if (wbal == 1) {
+		dat_multi4[2] = dat_multi2[2] = 0;
+		dat_wbal2[2] = 0x35;
+	} else if (wbal == 2) {
+		dat_multi4[2] = dat_multi2[2] = 0x20;
+		dat_wbal2[2] = 0x17;
+	}
+	dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror);
+	dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror);
+
+	msleep(200);
+	ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
+	msleep(2);
+
+	common(gspca_dev);
+
+	msleep(142);
+	ctrl_out(gspca_dev, 0x40,  1, 0x0010, 0x0010,  0, NULL);
+	ctrl_out(gspca_dev, 0x40,  1, 0x0003, 0x00c1,  0, NULL);
+	ctrl_out(gspca_dev, 0x40,  1, 0x0042, 0x00c2,  0, NULL);
+	ctrl_out(gspca_dev, 0x40,  1, 0x006a, 0x000d,  0, NULL);
+
+	switch (reso) {
+	case IMAGE_640:
+	case IMAGE_800:
+		if (reso != IMAGE_800)
+			ctrl_out(gspca_dev, 0x40,  3, 0x0000, 0x0200,
+				12, dat_640);
+		else
+			ctrl_out(gspca_dev, 0x40,  3, 0x0000, 0x0200,
+				12, dat_800);
+
+		fetch_idxdata(gspca_dev, tbl_init_post_alt_low1,
+					ARRAY_SIZE(tbl_init_post_alt_low1));
+
+		if (reso == IMAGE_800)
+			fetch_idxdata(gspca_dev, tbl_init_post_alt_low2,
+					ARRAY_SIZE(tbl_init_post_alt_low2));
+
+		fetch_idxdata(gspca_dev, tbl_init_post_alt_low3,
+				ARRAY_SIZE(tbl_init_post_alt_low3));
+
+		ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
+		msleep(120);
+		break;
+
+	case IMAGE_1280:
+	case IMAGE_1600:
+		if (reso == IMAGE_1280) {
+			ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
+					12, dat_1280);
+			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
+					3, "\x8c\x27\x07");
+			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
+					3, "\x90\x05\x04");
+			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
+					3, "\x8c\x27\x09");
+			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
+					3, "\x90\x04\x02");
+		} else {
+			ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
+					12, dat_1600);
+			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
+					3, "\x8c\x27\x07");
+			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
+					3, "\x90\x06\x40");
+			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
+					3, "\x8c\x27\x09");
+			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
+					3, "\x90\x04\xb0");
+		}
+
+		fetch_idxdata(gspca_dev, tbl_init_post_alt_big,
+				ARRAY_SIZE(tbl_init_post_alt_big));
+
+		ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
+		msleep(1850);
+	}
+
+	ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
+	msleep(40);
+
+	/* AC power frequency */
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2);
+	msleep(33);
+	/* light source */
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal1);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal2);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
+	msleep(7);
+	ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c);
+
+	fetch_idxdata(gspca_dev, tbl_init_post_alt_3B,
+			ARRAY_SIZE(tbl_init_post_alt_3B));
+
+	/* hvflip */
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6);
+	msleep(250);
+
+	if (reso == IMAGE_640 || reso == IMAGE_800)
+		fetch_idxdata(gspca_dev, tbl_middle_hvflip_low,
+				ARRAY_SIZE(tbl_middle_hvflip_low));
+	else
+		fetch_idxdata(gspca_dev, tbl_middle_hvflip_big,
+				ARRAY_SIZE(tbl_middle_hvflip_big));
+
+	fetch_idxdata(gspca_dev, tbl_end_hvflip,
+			ARRAY_SIZE(tbl_end_hvflip));
+
+	sd->nbIm = 0;
+
+	sd->vold.mirror    = mirror;
+	sd->vold.flip      = flip;
+	sd->vold.AC50Hz    = freq;
+	sd->vold.whitebal  = wbal;
+
+	mi2020_camera_settings(gspca_dev);
+
+	return 0;
+}
+
+static int mi2020_configure_alt(struct gspca_dev *gspca_dev)
+{
+	s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
+
+	switch (reso) {
+	case IMAGE_640:
+		gspca_dev->alt = 3 + 1;
+		break;
+
+	case IMAGE_800:
+	case IMAGE_1280:
+	case IMAGE_1600:
+		gspca_dev->alt = 1 + 1;
+		break;
+	}
+	return 0;
+}
+
+static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
+
+	s32 backlight = sd->vcur.backlight;
+	s32 bright =  sd->vcur.brightness;
+	s32 sharp  =  sd->vcur.sharpness;
+	s32 cntr   =  sd->vcur.contrast;
+	s32 gam	   =  sd->vcur.gamma;
+	s32 hue    = (sd->vcur.hue > 0);
+	s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0);
+	s32 flip   = (((sd->vcur.flip   > 0) ^ sd->mirrorMask) > 0);
+	s32 freq   = (sd->vcur.AC50Hz > 0);
+	s32 wbal   = sd->vcur.whitebal;
+
+	u8 dat_sharp[] = {0x6c, 0x00, 0x08};
+	u8 dat_bright2[] = {0x90, 0x00, 0x00};
+	u8 dat_freq2[] = {0x90, 0x00, 0x80};
+	u8 dat_multi1[] = {0x8c, 0xa7, 0x00};
+	u8 dat_multi2[] = {0x90, 0x00, 0x00};
+	u8 dat_multi3[] = {0x8c, 0xa7, 0x00};
+	u8 dat_multi4[] = {0x90, 0x00, 0x00};
+	u8 dat_hvflip2[] = {0x90, 0x04, 0x6c};
+	u8 dat_hvflip4[] = {0x90, 0x00, 0x24};
+	u8 dat_wbal2[] = {0x90, 0x00, 0x00};
+
+	/* Less than 4 images received -> too early to set the settings */
+	if (sd->nbIm < 4) {
+		sd->waitSet = 1;
+		return 0;
+	}
+	sd->waitSet = 0;
+
+	if (freq != sd->vold.AC50Hz) {
+		sd->vold.AC50Hz = freq;
+
+		dat_freq2[2] = freq ? 0xc0 : 0x80;
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2);
+		msleep(20);
+	}
+
+	if (wbal != sd->vold.whitebal) {
+		sd->vold.whitebal = wbal;
+		if (wbal < 0 || wbal > sd->vmax.whitebal)
+			wbal = 0;
+
+		dat_multi1[2] = 0x9d;
+		dat_multi3[2] = dat_multi1[2] + 1;
+		if (wbal == 0) {
+			dat_multi4[2] = dat_multi2[2] = 0;
+			dat_wbal2[2] = 0x17;
+		} else if (wbal == 1) {
+			dat_multi4[2] = dat_multi2[2] = 0;
+			dat_wbal2[2] = 0x35;
+		} else if (wbal == 2) {
+			dat_multi4[2] = dat_multi2[2] = 0x20;
+			dat_wbal2[2] = 0x17;
+		}
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal1);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal2);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
+	}
+
+	if (mirror != sd->vold.mirror || flip != sd->vold.flip) {
+		sd->vold.mirror = mirror;
+		sd->vold.flip   = flip;
+
+		dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror);
+		dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror);
+
+		fetch_idxdata(gspca_dev, tbl_init_post_alt_3B,
+				ARRAY_SIZE(tbl_init_post_alt_3B));
+
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6);
+		msleep(40);
+
+		if (reso == IMAGE_640 || reso == IMAGE_800)
+			fetch_idxdata(gspca_dev, tbl_middle_hvflip_low,
+					ARRAY_SIZE(tbl_middle_hvflip_low));
+		else
+			fetch_idxdata(gspca_dev, tbl_middle_hvflip_big,
+					ARRAY_SIZE(tbl_middle_hvflip_big));
+
+		fetch_idxdata(gspca_dev, tbl_end_hvflip,
+				ARRAY_SIZE(tbl_end_hvflip));
+	}
+
+	if (bright != sd->vold.brightness) {
+		sd->vold.brightness = bright;
+		if (bright < 0 || bright > sd->vmax.brightness)
+			bright = 0;
+
+		dat_bright2[2] = bright;
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright1);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright2);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright3);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright4);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright5);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright6);
+	}
+
+	if (cntr != sd->vold.contrast || gam != sd->vold.gamma) {
+		sd->vold.contrast = cntr;
+		if (cntr < 0 || cntr > sd->vmax.contrast)
+			cntr = 0;
+		sd->vold.gamma = gam;
+		if (gam < 0 || gam > sd->vmax.gamma)
+			gam = 0;
+
+		dat_multi1[2] = 0x6d;
+		dat_multi3[2] = dat_multi1[2] + 1;
+		if (cntr == 0)
+			cntr = 4;
+		dat_multi4[2] = dat_multi2[2] = cntr * 0x10 + 2 - gam;
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
+	}
+
+	if (backlight != sd->vold.backlight) {
+		sd->vold.backlight = backlight;
+		if (backlight < 0 || backlight > sd->vmax.backlight)
+			backlight = 0;
+
+		dat_multi1[2] = 0x9d;
+		dat_multi3[2] = dat_multi1[2] + 1;
+		dat_multi4[2] = dat_multi2[2] = backlight;
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
+	}
+
+	if (sharp != sd->vold.sharpness) {
+		sd->vold.sharpness = sharp;
+		if (sharp < 0 || sharp > sd->vmax.sharpness)
+			sharp = 0;
+
+		dat_sharp[1] = sharp;
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0032, 3, dat_sharp);
+	}
+
+	if (hue != sd->vold.hue) {
+		sd->swapRB = hue;
+		sd->vold.hue = hue;
+	}
+
+	return 0;
+}
+
+static void mi2020_post_unset_alt(struct gspca_dev *gspca_dev)
+{
+	ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL);
+	msleep(40);
+	ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL);
+}
diff --git a/drivers/media/usb/gspca/gl860/gl860-ov2640.c b/drivers/media/usb/gspca/gl860/gl860-ov2640.c
new file mode 100644
index 0000000..768cac5
--- /dev/null
+++ b/drivers/media/usb/gspca/gl860/gl860-ov2640.c
@@ -0,0 +1,489 @@
+/* Subdriver for the GL860 chip with the OV2640 sensor
+ * Author Olivier LORIN, from Malmostoso's logs
+ *
+ * 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
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Sensor : OV2640 */
+
+#include "gl860.h"
+
+static u8 dat_init1[] = "\x00\x41\x07\x6a\x06\x61\x0d\x6a" "\x10\x10\xc1\x01";
+
+static u8 c61[] = {0x61}; /* expected */
+static u8 c51[] = {0x51}; /* expected */
+static u8 c50[] = {0x50}; /* expected */
+static u8 c28[] = {0x28}; /* expected */
+static u8 ca8[] = {0xa8}; /* expected */
+
+static u8 dat_post[] =
+	"\x00\x41\x07\x6a\x06\xef\x0d\x6a" "\x10\x10\xc1\x01";
+
+static u8 dat_640[]  = "\xd0\x01\xd1\x08\xd2\xe0\xd3\x02\xd4\x10\xd5\x81";
+static u8 dat_800[]  = "\xd0\x01\xd1\x10\xd2\x58\xd3\x02\xd4\x18\xd5\x21";
+static u8 dat_1280[] = "\xd0\x01\xd1\x18\xd2\xc0\xd3\x02\xd4\x28\xd5\x01";
+static u8 dat_1600[] = "\xd0\x01\xd1\x20\xd2\xb0\xd3\x02\xd4\x30\xd5\x41";
+
+static struct validx tbl_init_at_startup[] = {
+	{0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1},
+	{0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d},
+	{0x0050, 0x0000}, {0x0041, 0x0000}, {0x006a, 0x0007}, {0x0061, 0x0006},
+	{0x006a, 0x000d}, {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1},
+	{0x0041, 0x00c2}, {0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058},
+	{0x0041, 0x0000}, {0x0061, 0x0000},
+};
+
+static struct validx tbl_common[] = {
+	{0x6000, 0x00ff}, {0x60ff, 0x002c}, {0x60df, 0x002e}, {0x6001, 0x00ff},
+	{0x6080, 0x0012}, {0x6000, 0x0000}, {0x6000, 0x0045}, {0x6000, 0x0010},
+	{0x6035, 0x003c}, {0x6000, 0x0011}, {0x6028, 0x0004}, {0x60e5, 0x0013},
+	{0x6088, 0x0014}, {0x600c, 0x002c}, {0x6078, 0x0033}, {0x60f7, 0x003b},
+	{0x6000, 0x003e}, {0x6011, 0x0043}, {0x6010, 0x0016}, {0x6082, 0x0039},
+	{0x6088, 0x0035}, {0x600a, 0x0022}, {0x6040, 0x0037}, {0x6000, 0x0023},
+	{0x60a0, 0x0034}, {0x601a, 0x0036}, {0x6002, 0x0006}, {0x60c0, 0x0007},
+	{0x60b7, 0x000d}, {0x6001, 0x000e}, {0x6000, 0x004c}, {0x6081, 0x004a},
+	{0x6099, 0x0021}, {0x6002, 0x0009}, {0x603e, 0x0024}, {0x6034, 0x0025},
+	{0x6081, 0x0026}, {0x6000, 0x0000}, {0x6000, 0x0045}, {0x6000, 0x0010},
+	{0x6000, 0x005c}, {0x6000, 0x0063}, {0x6000, 0x007c}, {0x6070, 0x0061},
+	{0x6080, 0x0062}, {0x6080, 0x0020}, {0x6030, 0x0028}, {0x6000, 0x006c},
+	{0x6000, 0x006e}, {0x6002, 0x0070}, {0x6094, 0x0071}, {0x60c1, 0x0073},
+	{0x6034, 0x003d}, {0x6057, 0x005a}, {0x60bb, 0x004f}, {0x609c, 0x0050},
+	{0x6080, 0x006d}, {0x6002, 0x0039}, {0x6033, 0x003a}, {0x60f1, 0x003b},
+	{0x6031, 0x003c}, {0x6000, 0x00ff}, {0x6014, 0x00e0}, {0x60ff, 0x0076},
+	{0x60a0, 0x0033}, {0x6020, 0x0042}, {0x6018, 0x0043}, {0x6000, 0x004c},
+	{0x60d0, 0x0087}, {0x600f, 0x0088}, {0x6003, 0x00d7}, {0x6010, 0x00d9},
+	{0x6005, 0x00da}, {0x6082, 0x00d3}, {0x60c0, 0x00f9}, {0x6006, 0x0044},
+	{0x6007, 0x00d1}, {0x6002, 0x00d2}, {0x6000, 0x00d2}, {0x6011, 0x00d8},
+	{0x6008, 0x00c8}, {0x6080, 0x00c9}, {0x6008, 0x007c}, {0x6020, 0x007d},
+	{0x6020, 0x007d}, {0x6000, 0x0090}, {0x600e, 0x0091}, {0x601a, 0x0091},
+	{0x6031, 0x0091}, {0x605a, 0x0091}, {0x6069, 0x0091}, {0x6075, 0x0091},
+	{0x607e, 0x0091}, {0x6088, 0x0091}, {0x608f, 0x0091}, {0x6096, 0x0091},
+	{0x60a3, 0x0091}, {0x60af, 0x0091}, {0x60c4, 0x0091}, {0x60d7, 0x0091},
+	{0x60e8, 0x0091}, {0x6020, 0x0091}, {0x6000, 0x0092}, {0x6006, 0x0093},
+	{0x60e3, 0x0093}, {0x6005, 0x0093}, {0x6005, 0x0093}, {0x6000, 0x0093},
+	{0x6004, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093},
+	{0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093},
+	{0x6000, 0x0096}, {0x6008, 0x0097}, {0x6019, 0x0097}, {0x6002, 0x0097},
+	{0x600c, 0x0097}, {0x6024, 0x0097}, {0x6030, 0x0097}, {0x6028, 0x0097},
+	{0x6026, 0x0097}, {0x6002, 0x0097}, {0x6098, 0x0097}, {0x6080, 0x0097},
+	{0x6000, 0x0097}, {0x6000, 0x0097}, {0x60ed, 0x00c3}, {0x609a, 0x00c4},
+	{0x6000, 0x00a4}, {0x6011, 0x00c5}, {0x6051, 0x00c6}, {0x6010, 0x00c7},
+	{0x6066, 0x00b6}, {0x60a5, 0x00b8}, {0x6064, 0x00b7}, {0x607c, 0x00b9},
+	{0x60af, 0x00b3}, {0x6097, 0x00b4}, {0x60ff, 0x00b5}, {0x60c5, 0x00b0},
+	{0x6094, 0x00b1}, {0x600f, 0x00b2}, {0x605c, 0x00c4}, {0x6000, 0x00a8},
+	{0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x601d, 0x0086}, {0x6000, 0x0050},
+	{0x6090, 0x0051}, {0x6018, 0x0052}, {0x6000, 0x0053}, {0x6000, 0x0054},
+	{0x6088, 0x0055}, {0x6000, 0x0057}, {0x6090, 0x005a}, {0x6018, 0x005b},
+	{0x6005, 0x005c}, {0x60ed, 0x00c3}, {0x6000, 0x007f}, {0x6005, 0x00da},
+	{0x601f, 0x00e5}, {0x6067, 0x00e1}, {0x6000, 0x00e0}, {0x60ff, 0x00dd},
+	{0x6000, 0x0005}, {0x6001, 0x00ff}, {0x6000, 0x0000}, {0x6000, 0x0045},
+	{0x6000, 0x0010},
+};
+
+static struct validx tbl_sensor_settings_common1[] = {
+	{0x0041, 0x0000}, {0x006a, 0x0007}, {0x00ef, 0x0006}, {0x006a, 0x000d},
+	{0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1}, {0x0041, 0x00c2},
+	{0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058}, {0x0041, 0x0000},
+	{50, 0xffff},
+	{0x0061, 0x0000},
+	{0xffff, 0xffff},
+	{0x6000, 0x00ff}, {0x6000, 0x007c}, {0x6007, 0x007d},
+	{30, 0xffff},
+	{0x0040, 0x0000},
+};
+
+static struct validx tbl_sensor_settings_common2[] = {
+	{0x6001, 0x00ff}, {0x6038, 0x000c},
+	{10, 0xffff},
+	{0x6000, 0x0011},
+};
+
+static struct validx tbl_640[] = {
+	{0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, {0x6067, 0x00e1},
+	{0x6004, 0x00da}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0},
+	{0x6001, 0x00ff}, {0x6000, 0x0012}, {0x6000, 0x0011}, {0x6011, 0x0017},
+	{0x6075, 0x0018}, {0x6001, 0x0019}, {0x6097, 0x001a}, {0x6036, 0x0032},
+	{0x60bb, 0x004f}, {0x6057, 0x005a}, {0x609c, 0x0050}, {0x6080, 0x006d},
+	{0x6092, 0x0026}, {0x60ff, 0x0020}, {0x6000, 0x0027}, {0x6000, 0x00ff},
+	{0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x6000, 0x008c}, {0x603d, 0x0086},
+	{0x6089, 0x0050}, {0x6090, 0x0051}, {0x602c, 0x0052}, {0x6000, 0x0053},
+	{0x6000, 0x0054}, {0x6088, 0x0055}, {0x6000, 0x0057}, {0x60a0, 0x005a},
+	{0x6078, 0x005b}, {0x6000, 0x005c}, {0x6004, 0x00d3}, {0x6000, 0x00e0},
+	{0x60ff, 0x00dd}, {0x60a1, 0x005a},
+};
+
+static struct validx tbl_800[] = {
+	{0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, {0x6067, 0x00e1},
+	{0x6004, 0x00da}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0},
+	{0x6001, 0x00ff}, {0x6040, 0x0012}, {0x6000, 0x0011}, {0x6011, 0x0017},
+	{0x6043, 0x0018}, {0x6000, 0x0019}, {0x604b, 0x001a}, {0x6009, 0x0032},
+	{0x60ca, 0x004f}, {0x60a8, 0x0050}, {0x6000, 0x006d}, {0x6038, 0x003d},
+	{0x60c8, 0x0035}, {0x6000, 0x0022}, {0x6092, 0x0026}, {0x60ff, 0x0020},
+	{0x6000, 0x0027}, {0x6000, 0x00ff}, {0x6064, 0x00c0}, {0x604b, 0x00c1},
+	{0x6000, 0x008c}, {0x601d, 0x0086}, {0x6082, 0x00d3}, {0x6000, 0x00e0},
+	{0x60ff, 0x00dd}, {0x6020, 0x008c}, {0x6001, 0x00ff}, {0x6044, 0x0018},
+};
+
+static struct validx tbl_big1[] = {
+	{0x0002, 0x00c1}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0},
+	{0x6001, 0x00ff}, {0x6000, 0x0012}, {0x6000, 0x0000}, {0x6000, 0x0045},
+	{0x6000, 0x0010}, {0x6000, 0x0011}, {0x6011, 0x0017}, {0x6075, 0x0018},
+	{0x6001, 0x0019}, {0x6097, 0x001a}, {0x6036, 0x0032}, {0x60bb, 0x004f},
+	{0x609c, 0x0050}, {0x6057, 0x005a}, {0x6080, 0x006d}, {0x6043, 0x000f},
+	{0x608f, 0x0003}, {0x6005, 0x007c}, {0x6081, 0x0026}, {0x6000, 0x00ff},
+	{0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x6000, 0x008c},
+};
+
+static struct validx tbl_big2[] = {
+	{0x603d, 0x0086}, {0x6000, 0x0050}, {0x6090, 0x0051}, {0x602c, 0x0052},
+	{0x6000, 0x0053}, {0x6000, 0x0054}, {0x6088, 0x0055}, {0x6000, 0x0057},
+	{0x6040, 0x005a}, {0x60f0, 0x005b}, {0x6001, 0x005c}, {0x6082, 0x00d3},
+	{0x6000, 0x008e},
+};
+
+static struct validx tbl_big3[] = {
+	{0x6004, 0x00da}, {0x6000, 0x00e0}, {0x6067, 0x00e1}, {0x60ff, 0x00dd},
+	{0x6001, 0x00ff}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0},
+	{0x6001, 0x00ff}, {0x6000, 0x0011}, {0x6000, 0x00ff}, {0x6010, 0x00c7},
+	{0x6000, 0x0092}, {0x6006, 0x0093}, {0x60e3, 0x0093}, {0x6005, 0x0093},
+	{0x6005, 0x0093}, {0x60ed, 0x00c3}, {0x6000, 0x00a4}, {0x60d0, 0x0087},
+	{0x6003, 0x0096}, {0x600c, 0x0097}, {0x6024, 0x0097}, {0x6030, 0x0097},
+	{0x6028, 0x0097}, {0x6026, 0x0097}, {0x6002, 0x0097}, {0x6001, 0x00ff},
+	{0x6043, 0x000f}, {0x608f, 0x0003}, {0x6000, 0x002d}, {0x6000, 0x002e},
+	{0x600a, 0x0022}, {0x6002, 0x0070}, {0x6008, 0x0014}, {0x6048, 0x0014},
+	{0x6000, 0x00ff}, {0x6000, 0x00e0}, {0x60ff, 0x00dd},
+};
+
+static struct validx tbl_post_unset_alt[] = {
+	{0x006a, 0x000d}, {0x6001, 0x00ff}, {0x6081, 0x0026}, {0x6000, 0x0000},
+	{0x6000, 0x0045}, {0x6000, 0x0010}, {0x6068, 0x000d},
+	{50, 0xffff},
+	{0x0021, 0x0000},
+};
+
+static int  ov2640_init_at_startup(struct gspca_dev *gspca_dev);
+static int  ov2640_configure_alt(struct gspca_dev *gspca_dev);
+static int  ov2640_init_pre_alt(struct gspca_dev *gspca_dev);
+static int  ov2640_init_post_alt(struct gspca_dev *gspca_dev);
+static void ov2640_post_unset_alt(struct gspca_dev *gspca_dev);
+static int  ov2640_camera_settings(struct gspca_dev *gspca_dev);
+/*==========================================================================*/
+
+void ov2640_init_settings(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->vcur.backlight  =  32;
+	sd->vcur.brightness =   0;
+	sd->vcur.sharpness  =   6;
+	sd->vcur.contrast   =   0;
+	sd->vcur.gamma      =  32;
+	sd->vcur.hue        =   0;
+	sd->vcur.saturation = 128;
+	sd->vcur.whitebal   =  64;
+	sd->vcur.mirror     =   0;
+	sd->vcur.flip       =   0;
+
+	sd->vmax.backlight  =  64;
+	sd->vmax.brightness = 255;
+	sd->vmax.sharpness  =  31;
+	sd->vmax.contrast   = 255;
+	sd->vmax.gamma      =  64;
+	sd->vmax.hue        = 254 + 2;
+	sd->vmax.saturation = 255;
+	sd->vmax.whitebal   = 128;
+	sd->vmax.mirror     = 1;
+	sd->vmax.flip       = 1;
+	sd->vmax.AC50Hz     = 0;
+
+	sd->dev_camera_settings = ov2640_camera_settings;
+	sd->dev_init_at_startup = ov2640_init_at_startup;
+	sd->dev_configure_alt   = ov2640_configure_alt;
+	sd->dev_init_pre_alt    = ov2640_init_pre_alt;
+	sd->dev_post_unset_alt  = ov2640_post_unset_alt;
+}
+
+/*==========================================================================*/
+
+static void common(struct gspca_dev *gspca_dev)
+{
+	fetch_validx(gspca_dev, tbl_common, ARRAY_SIZE(tbl_common));
+}
+
+static int ov2640_init_at_startup(struct gspca_dev *gspca_dev)
+{
+	fetch_validx(gspca_dev, tbl_init_at_startup,
+			ARRAY_SIZE(tbl_init_at_startup));
+
+	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_init1);
+
+	common(gspca_dev);
+
+	ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0006, 1, c61);
+
+	ctrl_out(gspca_dev, 0x40, 1, 0x00ef, 0x0006, 0, NULL);
+
+	ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, c51);
+
+	ctrl_out(gspca_dev, 0x40, 1, 0x0051, 0x0000, 0, NULL);
+/*	ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */
+
+	return 0;
+}
+
+static int ov2640_init_pre_alt(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->mirrorMask = 0;
+
+	sd->vold.backlight  = -1;
+	sd->vold.brightness = -1;
+	sd->vold.sharpness  = -1;
+	sd->vold.contrast   = -1;
+	sd->vold.saturation = -1;
+	sd->vold.gamma    = -1;
+	sd->vold.hue      = -1;
+	sd->vold.whitebal = -1;
+	sd->vold.mirror = -1;
+	sd->vold.flip   = -1;
+
+	ov2640_init_post_alt(gspca_dev);
+
+	return 0;
+}
+
+static int ov2640_init_post_alt(struct gspca_dev *gspca_dev)
+{
+	s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
+	s32 n; /* reserved for FETCH functions */
+
+	ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
+
+	n = fetch_validx(gspca_dev, tbl_sensor_settings_common1,
+			ARRAY_SIZE(tbl_sensor_settings_common1));
+	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_post);
+	common(gspca_dev);
+	keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common1,
+				ARRAY_SIZE(tbl_sensor_settings_common1), n);
+
+	switch (reso) {
+	case IMAGE_640:
+		n = fetch_validx(gspca_dev, tbl_640, ARRAY_SIZE(tbl_640));
+		ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_640);
+		break;
+
+	case IMAGE_800:
+		n = fetch_validx(gspca_dev, tbl_800, ARRAY_SIZE(tbl_800));
+		ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_800);
+		break;
+
+	case IMAGE_1600:
+	case IMAGE_1280:
+		n = fetch_validx(gspca_dev, tbl_big1, ARRAY_SIZE(tbl_big1));
+
+		if (reso == IMAGE_1280) {
+			n = fetch_validx(gspca_dev, tbl_big2,
+					ARRAY_SIZE(tbl_big2));
+		} else {
+			ctrl_out(gspca_dev, 0x40, 1, 0x601d, 0x0086, 0, NULL);
+			ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00d7, 0, NULL);
+			ctrl_out(gspca_dev, 0x40, 1, 0x6082, 0x00d3, 0, NULL);
+		}
+
+		n = fetch_validx(gspca_dev, tbl_big3, ARRAY_SIZE(tbl_big3));
+
+		if (reso == IMAGE_1280) {
+			ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL);
+			ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
+					12, dat_1280);
+		} else {
+			ctrl_out(gspca_dev, 0x40, 1, 0x6020, 0x008c, 0, NULL);
+			ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL);
+			ctrl_out(gspca_dev, 0x40, 1, 0x6076, 0x0018, 0, NULL);
+			ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
+					12, dat_1600);
+		}
+		break;
+	}
+
+	n = fetch_validx(gspca_dev, tbl_sensor_settings_common2,
+			ARRAY_SIZE(tbl_sensor_settings_common2));
+
+	ov2640_camera_settings(gspca_dev);
+
+	return 0;
+}
+
+static int ov2640_configure_alt(struct gspca_dev *gspca_dev)
+{
+	s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
+
+	switch (reso) {
+	case IMAGE_640:
+		gspca_dev->alt = 3 + 1;
+		break;
+
+	case IMAGE_800:
+	case IMAGE_1280:
+	case IMAGE_1600:
+		gspca_dev->alt = 1 + 1;
+		break;
+	}
+	return 0;
+}
+
+static int ov2640_camera_settings(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	s32 backlight = sd->vcur.backlight;
+	s32 bright = sd->vcur.brightness;
+	s32 sharp  = sd->vcur.sharpness;
+	s32 gam    = sd->vcur.gamma;
+	s32 cntr   = sd->vcur.contrast;
+	s32 sat    = sd->vcur.saturation;
+	s32 hue    = sd->vcur.hue;
+	s32 wbal   = sd->vcur.whitebal;
+	s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) == 0);
+	s32 flip   = (((sd->vcur.flip   > 0) ^ sd->mirrorMask) == 0);
+
+	if (backlight != sd->vold.backlight) {
+		/* No sd->vold.backlight=backlight; (to be done again later) */
+		if (backlight < 0 || backlight > sd->vmax.backlight)
+			backlight = 0;
+
+		ctrl_out(gspca_dev, 0x40, 1, 0x6001                 , 0x00ff,
+				0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight     , 0x0024,
+				0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight - 10, 0x0025,
+				0, NULL);
+	}
+
+	if (bright != sd->vold.brightness) {
+		sd->vold.brightness = bright;
+		if (bright < 0 || bright > sd->vmax.brightness)
+			bright = 0;
+
+		ctrl_out(gspca_dev, 0x40, 1, 0x6000         , 0x00ff, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6009         , 0x007c, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6000 + bright, 0x007d, 0, NULL);
+	}
+
+	if (wbal != sd->vold.whitebal) {
+		sd->vold.whitebal = wbal;
+		if (wbal < 0 || wbal > sd->vmax.whitebal)
+			wbal = 0;
+
+		ctrl_out(gspca_dev, 0x40, 1, 0x6000       , 0x00ff, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6003       , 0x007c, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6000 + wbal, 0x007d, 0, NULL);
+	}
+
+	if (cntr != sd->vold.contrast) {
+		sd->vold.contrast = cntr;
+		if (cntr < 0 || cntr > sd->vmax.contrast)
+			cntr = 0;
+
+		ctrl_out(gspca_dev, 0x40, 1, 0x6000       , 0x00ff, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6007       , 0x007c, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6000 + cntr, 0x007d, 0, NULL);
+	}
+
+	if (sat != sd->vold.saturation) {
+		sd->vold.saturation = sat;
+		if (sat < 0 || sat > sd->vmax.saturation)
+			sat = 0;
+
+		ctrl_out(gspca_dev, 0x40, 1, 0x6000      , 0x00ff, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6001      , 0x007c, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6000 + sat, 0x007d, 0, NULL);
+	}
+
+	if (sharp != sd->vold.sharpness) {
+		sd->vold.sharpness = sharp;
+		if (sharp < 0 || sharp > sd->vmax.sharpness)
+			sharp = 0;
+
+		ctrl_out(gspca_dev, 0x40, 1, 0x6000        , 0x00ff, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6001        , 0x0092, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x60c0 + sharp, 0x0093, 0, NULL);
+	}
+
+	if (hue != sd->vold.hue) {
+		sd->vold.hue = hue;
+		if (hue < 0 || hue > sd->vmax.hue)
+			hue = 0;
+
+		ctrl_out(gspca_dev, 0x40, 1, 0x6000     , 0x00ff, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6002     , 0x007c, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6000 + hue * (hue < 255), 0x007d,
+				0, NULL);
+		if (hue >= 255)
+			sd->swapRB = 1;
+		else
+			sd->swapRB = 0;
+	}
+
+	if (gam != sd->vold.gamma) {
+		sd->vold.gamma = gam;
+		if (gam < 0 || gam > sd->vmax.gamma)
+			gam = 0;
+
+		ctrl_out(gspca_dev, 0x40, 1, 0x6000      , 0x00ff, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6008      , 0x007c, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6000 + gam, 0x007d, 0, NULL);
+	}
+
+	if (mirror != sd->vold.mirror || flip != sd->vold.flip) {
+		sd->vold.mirror = mirror;
+		sd->vold.flip   = flip;
+
+		mirror = 0x80 * mirror;
+		ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6000, 0x8004, 0, NULL);
+		ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x8004, 1, c28);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6028 + mirror, 0x0004, 0, NULL);
+
+		flip = 0x50 * flip + mirror;
+		ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6000, 0x8004, 0, NULL);
+		ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x8004, 1, ca8);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6028 + flip, 0x0004, 0, NULL);
+
+		ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, c50);
+	}
+
+	if (backlight != sd->vold.backlight) {
+		sd->vold.backlight = backlight;
+
+		ctrl_out(gspca_dev, 0x40, 1, 0x6001                 , 0x00ff,
+				0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight     , 0x0024,
+				0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight - 10, 0x0025,
+				0, NULL);
+	}
+
+	return 0;
+}
+
+static void ov2640_post_unset_alt(struct gspca_dev *gspca_dev)
+{
+	ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL);
+	msleep(20);
+	fetch_validx(gspca_dev, tbl_post_unset_alt,
+			ARRAY_SIZE(tbl_post_unset_alt));
+}
diff --git a/drivers/media/usb/gspca/gl860/gl860-ov9655.c b/drivers/media/usb/gspca/gl860/gl860-ov9655.c
new file mode 100644
index 0000000..5ae9619
--- /dev/null
+++ b/drivers/media/usb/gspca/gl860/gl860-ov9655.c
@@ -0,0 +1,336 @@
+/* Subdriver for the GL860 chip with the OV9655 sensor
+ * Author Olivier LORIN, from logs done by Simon (Sur3) and Almighurt
+ * on dsd's weblog
+ *
+ * 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
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Sensor : OV9655 */
+
+#include "gl860.h"
+
+static struct validx tbl_init_at_startup[] = {
+	{0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1},
+	{0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d},
+
+	{0x0040, 0x0000},
+};
+
+static struct validx tbl_commmon[] = {
+	{0x0041, 0x0000}, {0x006a, 0x0007}, {0x0063, 0x0006}, {0x006a, 0x000d},
+	{0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1}, {0x0041, 0x00c2},
+	{0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058}, {0x0040, 0x0000},
+	{0x00f3, 0x0006}, {0x0058, 0x0000}, {0x0048, 0x0000}, {0x0061, 0x0000},
+};
+
+static s32 tbl_length[] = {12, 56, 52, 54, 56, 42, 32, 12};
+
+static u8 *tbl_640[] = {
+	"\x00\x40\x07\x6a\x06\xf3\x0d\x6a" "\x10\x10\xc1\x01"
+	,
+	"\x12\x80\x00\x00\x01\x98\x02\x80" "\x03\x12\x04\x03\x0b\x57\x0e\x61"
+	"\x0f\x42\x11\x01\x12\x60\x13\x00" "\x14\x3a\x16\x24\x17\x14\x18\x00"
+	"\x19\x01\x1a\x3d\x1e\x04\x24\x3c" "\x25\x36\x26\x72\x27\x08\x28\x08"
+	"\x29\x15\x2a\x00\x2b\x00\x2c\x08"
+	,
+	"\x32\xff\x33\x00\x34\x3d\x35\x00" "\x36\xfa\x38\x72\x39\x57\x3a\x00"
+	"\x3b\x0c\x3d\x99\x3e\x0c\x3f\xc1" "\x40\xc0\x41\x00\x42\xc0\x43\x0a"
+	"\x44\xf0\x45\x46\x46\x62\x47\x2a" "\x48\x3c\x4a\xee\x4b\xe7\x4c\xe7"
+	"\x4d\xe7\x4e\xe7"
+	,
+	"\x4f\x98\x50\x98\x51\x00\x52\x28" "\x53\x70\x54\x98\x58\x1a\x59\x85"
+	"\x5a\xa9\x5b\x64\x5c\x84\x5d\x53" "\x5e\x0e\x5f\xf0\x60\xf0\x61\xf0"
+	"\x62\x00\x63\x00\x64\x02\x65\x20" "\x66\x00\x69\x0a\x6b\x5a\x6c\x04"
+	"\x6d\x55\x6e\x00\x6f\x9d"
+	,
+	"\x70\x15\x71\x78\x72\x00\x73\x00" "\x74\x3a\x75\x35\x76\x01\x77\x02"
+	"\x7a\x24\x7b\x04\x7c\x07\x7d\x10" "\x7e\x28\x7f\x36\x80\x44\x81\x52"
+	"\x82\x60\x83\x6c\x84\x78\x85\x8c" "\x86\x9e\x87\xbb\x88\xd2\x89\xe5"
+	"\x8a\x23\x8c\x8d\x90\x7c\x91\x7b"
+	,
+	"\x9d\x02\x9e\x02\x9f\x74\xa0\x73" "\xa1\x40\xa4\x50\xa5\x68\xa6\x70"
+	"\xa8\xc1\xa9\xef\xaa\x92\xab\x04" "\xac\x80\xad\x80\xae\x80\xaf\x80"
+	"\xb2\xf2\xb3\x20\xb4\x20\xb5\x00" "\xb6\xaf"
+	,
+	"\xbb\xae\xbc\x4f\xbd\x4e\xbe\x6a" "\xbf\x68\xc0\xaa\xc1\xc0\xc2\x01"
+	"\xc3\x4e\xc6\x85\xc7\x81\xc9\xe0" "\xca\xe8\xcb\xf0\xcc\xd8\xcd\x93"
+	,
+	"\xd0\x01\xd1\x08\xd2\xe0\xd3\x01" "\xd4\x10\xd5\x80"
+};
+
+static u8 *tbl_1280[] = {
+	"\x00\x40\x07\x6a\x06\xf3\x0d\x6a" "\x10\x10\xc1\x01"
+	,
+	"\x12\x80\x00\x00\x01\x98\x02\x80" "\x03\x12\x04\x01\x0b\x57\x0e\x61"
+	"\x0f\x42\x11\x00\x12\x00\x13\x00" "\x14\x3a\x16\x24\x17\x1b\x18\xbb"
+	"\x19\x01\x1a\x81\x1e\x04\x24\x3c" "\x25\x36\x26\x72\x27\x08\x28\x08"
+	"\x29\x15\x2a\x00\x2b\x00\x2c\x08"
+	,
+	"\x32\xa4\x33\x00\x34\x3d\x35\x00" "\x36\xf8\x38\x72\x39\x57\x3a\x00"
+	"\x3b\x0c\x3d\x99\x3e\x0c\x3f\xc2" "\x40\xc0\x41\x00\x42\xc0\x43\x0a"
+	"\x44\xf0\x45\x46\x46\x62\x47\x2a" "\x48\x3c\x4a\xec\x4b\xe8\x4c\xe8"
+	"\x4d\xe8\x4e\xe8"
+	,
+	"\x4f\x98\x50\x98\x51\x00\x52\x28" "\x53\x70\x54\x98\x58\x1a\x59\x85"
+	"\x5a\xa9\x5b\x64\x5c\x84\x5d\x53" "\x5e\x0e\x5f\xf0\x60\xf0\x61\xf0"
+	"\x62\x00\x63\x00\x64\x02\x65\x20" "\x66\x00\x69\x02\x6b\x5a\x6c\x04"
+	"\x6d\x55\x6e\x00\x6f\x9d"
+	,
+	"\x70\x08\x71\x78\x72\x00\x73\x01" "\x74\x3a\x75\x35\x76\x01\x77\x02"
+	"\x7a\x24\x7b\x04\x7c\x07\x7d\x10" "\x7e\x28\x7f\x36\x80\x44\x81\x52"
+	"\x82\x60\x83\x6c\x84\x78\x85\x8c" "\x86\x9e\x87\xbb\x88\xd2\x89\xe5"
+	"\x8a\x23\x8c\x0d\x90\x90\x91\x90"
+	,
+	"\x9d\x02\x9e\x02\x9f\x94\xa0\x94" "\xa1\x01\xa4\x50\xa5\x68\xa6\x70"
+	"\xa8\xc1\xa9\xef\xaa\x92\xab\x04" "\xac\x80\xad\x80\xae\x80\xaf\x80"
+	"\xb2\xf2\xb3\x20\xb4\x20\xb5\x00" "\xb6\xaf"
+	,
+	"\xbb\xae\xbc\x38\xbd\x39\xbe\x01" "\xbf\x01\xc0\xe2\xc1\xc0\xc2\x01"
+	"\xc3\x4e\xc6\x85\xc7\x81\xc9\xe0" "\xca\xe8\xcb\xf0\xcc\xd8\xcd\x93"
+	,
+	"\xd0\x21\xd1\x18\xd2\xe0\xd3\x01" "\xd4\x28\xd5\x00"
+};
+
+static u8 c04[] = {0x04};
+static u8 dat_post1[] = "\x04\x00\x10\x20\xa1\x00\x00\x02";
+static u8 dat_post2[] = "\x10\x10\xc1\x02";
+static u8 dat_post3[] = "\x04\x00\x10\x7c\xa1\x00\x00\x04";
+static u8 dat_post4[] = "\x10\x02\xc1\x06";
+static u8 dat_post5[] = "\x04\x00\x10\x7b\xa1\x00\x00\x08";
+static u8 dat_post6[] = "\x10\x10\xc1\x05";
+static u8 dat_post7[] = "\x04\x00\x10\x7c\xa1\x00\x00\x08";
+static u8 dat_post8[] = "\x04\x00\x10\x7c\xa1\x00\x00\x09";
+
+static struct validx tbl_init_post_alt[] = {
+	{0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x603c, 0x00ff},
+	{0x6003, 0x00ff}, {0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x6001, 0x00ff},
+	{0x6000, 0x801e},
+	{0xffff, 0xffff},
+	{0x6004, 0x001e}, {0x6000, 0x801e},
+	{0xffff, 0xffff},
+	{0x6004, 0x001e}, {0x6012, 0x0003}, {0x6000, 0x801e},
+	{0xffff, 0xffff},
+	{0x6004, 0x001e}, {0x6000, 0x801e},
+	{0xffff, 0xffff},
+	{0x6004, 0x001e}, {0x6012, 0x0003},
+	{0xffff, 0xffff},
+	{0x6000, 0x801e},
+	{0xffff, 0xffff},
+	{0x6004, 0x001e}, {0x6000, 0x801e},
+	{0xffff, 0xffff},
+	{0x6004, 0x001e}, {0x6012, 0x0003}, {0x6000, 0x801e},
+	{0xffff, 0xffff},
+	{0x6004, 0x001e}, {0x6000, 0x801e},
+	{0xffff, 0xffff},
+	{0x6004, 0x001e}, {0x6012, 0x0003},
+	{0xffff, 0xffff},
+	{0x6000, 0x801e},
+	{0xffff, 0xffff},
+	{0x6004, 0x001e}, {0x6000, 0x801e},
+	{0xffff, 0xffff},
+	{0x6004, 0x001e}, {0x6012, 0x0003},
+};
+
+static int  ov9655_init_at_startup(struct gspca_dev *gspca_dev);
+static int  ov9655_configure_alt(struct gspca_dev *gspca_dev);
+static int  ov9655_init_pre_alt(struct gspca_dev *gspca_dev);
+static int  ov9655_init_post_alt(struct gspca_dev *gspca_dev);
+static void ov9655_post_unset_alt(struct gspca_dev *gspca_dev);
+static int  ov9655_camera_settings(struct gspca_dev *gspca_dev);
+/*==========================================================================*/
+
+void ov9655_init_settings(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->vcur.backlight  =   0;
+	sd->vcur.brightness = 128;
+	sd->vcur.sharpness  =   0;
+	sd->vcur.contrast   =   0;
+	sd->vcur.gamma      =   0;
+	sd->vcur.hue        =   0;
+	sd->vcur.saturation =   0;
+	sd->vcur.whitebal   =   0;
+
+	sd->vmax.backlight  =   0;
+	sd->vmax.brightness = 255;
+	sd->vmax.sharpness  =   0;
+	sd->vmax.contrast   =   0;
+	sd->vmax.gamma      =   0;
+	sd->vmax.hue        =   0 + 1;
+	sd->vmax.saturation =   0;
+	sd->vmax.whitebal   =   0;
+	sd->vmax.mirror     = 0;
+	sd->vmax.flip       = 0;
+	sd->vmax.AC50Hz     = 0;
+
+	sd->dev_camera_settings = ov9655_camera_settings;
+	sd->dev_init_at_startup = ov9655_init_at_startup;
+	sd->dev_configure_alt   = ov9655_configure_alt;
+	sd->dev_init_pre_alt    = ov9655_init_pre_alt;
+	sd->dev_post_unset_alt  = ov9655_post_unset_alt;
+}
+
+/*==========================================================================*/
+
+static int ov9655_init_at_startup(struct gspca_dev *gspca_dev)
+{
+	fetch_validx(gspca_dev, tbl_init_at_startup,
+			ARRAY_SIZE(tbl_init_at_startup));
+	fetch_validx(gspca_dev, tbl_commmon, ARRAY_SIZE(tbl_commmon));
+/*	ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL);*/
+
+	return 0;
+}
+
+static int ov9655_init_pre_alt(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->vold.brightness = -1;
+	sd->vold.hue = -1;
+
+	fetch_validx(gspca_dev, tbl_commmon, ARRAY_SIZE(tbl_commmon));
+
+	ov9655_init_post_alt(gspca_dev);
+
+	return 0;
+}
+
+static int ov9655_init_post_alt(struct gspca_dev *gspca_dev)
+{
+	s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
+	s32 n; /* reserved for FETCH functions */
+	s32 i;
+	u8 **tbl;
+
+	ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
+
+	tbl = (reso == IMAGE_640) ? tbl_640 : tbl_1280;
+
+	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
+			tbl_length[0], tbl[0]);
+	for (i = 1; i < 7; i++)
+		ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200,
+				tbl_length[i], tbl[i]);
+	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
+			tbl_length[7], tbl[7]);
+
+	n = fetch_validx(gspca_dev, tbl_init_post_alt,
+			ARRAY_SIZE(tbl_init_post_alt));
+
+	ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
+	keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
+					ARRAY_SIZE(tbl_init_post_alt), n);
+	ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
+	keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
+					ARRAY_SIZE(tbl_init_post_alt), n);
+	ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
+	keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
+					ARRAY_SIZE(tbl_init_post_alt), n);
+	ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
+	keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
+					ARRAY_SIZE(tbl_init_post_alt), n);
+	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post1);
+	keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
+					ARRAY_SIZE(tbl_init_post_alt), n);
+
+	ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
+	keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
+					ARRAY_SIZE(tbl_init_post_alt), n);
+	ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
+	keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
+					ARRAY_SIZE(tbl_init_post_alt), n);
+	ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
+	keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
+					ARRAY_SIZE(tbl_init_post_alt), n);
+	ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
+	keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
+					ARRAY_SIZE(tbl_init_post_alt), n);
+	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post1);
+	keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
+					ARRAY_SIZE(tbl_init_post_alt), n);
+
+	ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
+	keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
+					ARRAY_SIZE(tbl_init_post_alt), n);
+	ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
+	keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
+					ARRAY_SIZE(tbl_init_post_alt), n);
+
+	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post1);
+
+	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post2);
+	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post3);
+
+	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post4);
+	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post5);
+
+	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post6);
+	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post7);
+
+	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post8);
+
+	ov9655_camera_settings(gspca_dev);
+
+	return 0;
+}
+
+static int ov9655_configure_alt(struct gspca_dev *gspca_dev)
+{
+	s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
+
+	switch (reso) {
+	case IMAGE_640:
+		gspca_dev->alt = 1 + 1;
+		break;
+
+	default:
+		gspca_dev->alt = 1 + 1;
+		break;
+	}
+	return 0;
+}
+
+static int ov9655_camera_settings(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	u8 dat_bright[] = "\x04\x00\x10\x7c\xa1\x00\x00\x70";
+
+	s32 bright = sd->vcur.brightness;
+	s32 hue    = sd->vcur.hue;
+
+	if (bright != sd->vold.brightness) {
+		sd->vold.brightness = bright;
+		if (bright < 0 || bright > sd->vmax.brightness)
+			bright = 0;
+
+		dat_bright[3] = bright;
+		ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_bright);
+	}
+
+	if (hue != sd->vold.hue) {
+		sd->vold.hue = hue;
+		sd->swapRB = (hue != 0);
+	}
+
+	return 0;
+}
+
+static void ov9655_post_unset_alt(struct gspca_dev *gspca_dev)
+{
+	ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL);
+	ctrl_out(gspca_dev, 0x40, 1, 0x0061, 0x0000, 0, NULL);
+}
diff --git a/drivers/media/usb/gspca/gl860/gl860.c b/drivers/media/usb/gspca/gl860/gl860.c
new file mode 100644
index 0000000..ced3b71
--- /dev/null
+++ b/drivers/media/usb/gspca/gl860/gl860.c
@@ -0,0 +1,725 @@
+/* GSPCA subdrivers for Genesys Logic webcams with the GL860 chip
+ * Subdriver core
+ *
+ * 2009/09/24 Olivier Lorin <o.lorin@laposte.net>
+ * GSPCA by Jean-Francois Moine <http://moinejf.free.fr>
+ * Thanks BUGabundo and Malmostoso for your amazing help!
+ *
+ * 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
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "gspca.h"
+#include "gl860.h"
+
+MODULE_AUTHOR("Olivier Lorin <o.lorin@laposte.net>");
+MODULE_DESCRIPTION("Genesys Logic USB PC Camera Driver");
+MODULE_LICENSE("GPL");
+
+/*======================== static function declarations ====================*/
+
+static void (*dev_init_settings)(struct gspca_dev *gspca_dev);
+
+static int  sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id);
+static int  sd_init(struct gspca_dev *gspca_dev);
+static int  sd_isoc_init(struct gspca_dev *gspca_dev);
+static int  sd_start(struct gspca_dev *gspca_dev);
+static void sd_stop0(struct gspca_dev *gspca_dev);
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			u8 *data, int len);
+static void sd_callback(struct gspca_dev *gspca_dev);
+
+static int gl860_guess_sensor(struct gspca_dev *gspca_dev,
+				u16 vendor_id, u16 product_id);
+
+/*============================ driver options ==============================*/
+
+static s32 AC50Hz = 0xff;
+module_param(AC50Hz, int, 0644);
+MODULE_PARM_DESC(AC50Hz, " Does AC power frequency is 50Hz? (0/1)");
+
+static char sensor[7];
+module_param_string(sensor, sensor, sizeof(sensor), 0644);
+MODULE_PARM_DESC(sensor,
+		" Driver sensor ('MI1320'/'MI2020'/'OV9655'/'OV2640')");
+
+/*============================ webcam controls =============================*/
+
+/* Functions to get and set a control value */
+#define SD_SETGET(thename) \
+static int sd_set_##thename(struct gspca_dev *gspca_dev, s32 val)\
+{\
+	struct sd *sd = (struct sd *) gspca_dev;\
+\
+	sd->vcur.thename = val;\
+	if (gspca_dev->streaming)\
+		sd->waitSet = 1;\
+	return 0;\
+} \
+static int sd_get_##thename(struct gspca_dev *gspca_dev, s32 *val)\
+{\
+	struct sd *sd = (struct sd *) gspca_dev;\
+\
+	*val = sd->vcur.thename;\
+	return 0;\
+}
+
+SD_SETGET(mirror)
+SD_SETGET(flip)
+SD_SETGET(AC50Hz)
+SD_SETGET(backlight)
+SD_SETGET(brightness)
+SD_SETGET(gamma)
+SD_SETGET(hue)
+SD_SETGET(saturation)
+SD_SETGET(sharpness)
+SD_SETGET(whitebal)
+SD_SETGET(contrast)
+
+#define GL860_NCTRLS 11
+
+/* control table */
+static struct ctrl sd_ctrls_mi1320[GL860_NCTRLS];
+static struct ctrl sd_ctrls_mi2020[GL860_NCTRLS];
+static struct ctrl sd_ctrls_ov2640[GL860_NCTRLS];
+static struct ctrl sd_ctrls_ov9655[GL860_NCTRLS];
+
+#define SET_MY_CTRL(theid, \
+	thetype, thelabel, thename) \
+	if (sd->vmax.thename != 0) {\
+		sd_ctrls[nCtrls].qctrl.id   = theid;\
+		sd_ctrls[nCtrls].qctrl.type = thetype;\
+		strcpy(sd_ctrls[nCtrls].qctrl.name, thelabel);\
+		sd_ctrls[nCtrls].qctrl.minimum = 0;\
+		sd_ctrls[nCtrls].qctrl.maximum = sd->vmax.thename;\
+		sd_ctrls[nCtrls].qctrl.default_value = sd->vcur.thename;\
+		sd_ctrls[nCtrls].qctrl.step = \
+			(sd->vmax.thename < 16) ? 1 : sd->vmax.thename/16;\
+		sd_ctrls[nCtrls].set = sd_set_##thename;\
+		sd_ctrls[nCtrls].get = sd_get_##thename;\
+		nCtrls++;\
+	}
+
+static int gl860_build_control_table(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct ctrl *sd_ctrls;
+	int nCtrls = 0;
+
+	if (_MI1320_)
+		sd_ctrls = sd_ctrls_mi1320;
+	else if (_MI2020_)
+		sd_ctrls = sd_ctrls_mi2020;
+	else if (_OV2640_)
+		sd_ctrls = sd_ctrls_ov2640;
+	else if (_OV9655_)
+		sd_ctrls = sd_ctrls_ov9655;
+	else
+		return 0;
+
+	memset(sd_ctrls, 0, GL860_NCTRLS * sizeof(struct ctrl));
+
+	SET_MY_CTRL(V4L2_CID_BRIGHTNESS,
+		V4L2_CTRL_TYPE_INTEGER, "Brightness", brightness)
+	SET_MY_CTRL(V4L2_CID_SHARPNESS,
+		V4L2_CTRL_TYPE_INTEGER, "Sharpness", sharpness)
+	SET_MY_CTRL(V4L2_CID_CONTRAST,
+		V4L2_CTRL_TYPE_INTEGER, "Contrast", contrast)
+	SET_MY_CTRL(V4L2_CID_GAMMA,
+		V4L2_CTRL_TYPE_INTEGER, "Gamma", gamma)
+	SET_MY_CTRL(V4L2_CID_HUE,
+		V4L2_CTRL_TYPE_INTEGER, "Palette", hue)
+	SET_MY_CTRL(V4L2_CID_SATURATION,
+		V4L2_CTRL_TYPE_INTEGER, "Saturation", saturation)
+	SET_MY_CTRL(V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+		V4L2_CTRL_TYPE_INTEGER, "White Bal.", whitebal)
+	SET_MY_CTRL(V4L2_CID_BACKLIGHT_COMPENSATION,
+		V4L2_CTRL_TYPE_INTEGER, "Backlight" , backlight)
+
+	SET_MY_CTRL(V4L2_CID_HFLIP,
+		V4L2_CTRL_TYPE_BOOLEAN, "Mirror", mirror)
+	SET_MY_CTRL(V4L2_CID_VFLIP,
+		V4L2_CTRL_TYPE_BOOLEAN, "Flip", flip)
+	SET_MY_CTRL(V4L2_CID_POWER_LINE_FREQUENCY,
+		V4L2_CTRL_TYPE_BOOLEAN, "AC power 50Hz", AC50Hz)
+
+	return nCtrls;
+}
+
+/*==================== sud-driver structure initialisation =================*/
+
+static const struct sd_desc sd_desc_mi1320 = {
+	.name        = MODULE_NAME,
+	.ctrls       = sd_ctrls_mi1320,
+	.nctrls      = GL860_NCTRLS,
+	.config      = sd_config,
+	.init        = sd_init,
+	.isoc_init   = sd_isoc_init,
+	.start       = sd_start,
+	.stop0       = sd_stop0,
+	.pkt_scan    = sd_pkt_scan,
+	.dq_callback = sd_callback,
+};
+
+static const struct sd_desc sd_desc_mi2020 = {
+	.name        = MODULE_NAME,
+	.ctrls       = sd_ctrls_mi2020,
+	.nctrls      = GL860_NCTRLS,
+	.config      = sd_config,
+	.init        = sd_init,
+	.isoc_init   = sd_isoc_init,
+	.start       = sd_start,
+	.stop0       = sd_stop0,
+	.pkt_scan    = sd_pkt_scan,
+	.dq_callback = sd_callback,
+};
+
+static const struct sd_desc sd_desc_ov2640 = {
+	.name        = MODULE_NAME,
+	.ctrls       = sd_ctrls_ov2640,
+	.nctrls      = GL860_NCTRLS,
+	.config      = sd_config,
+	.init        = sd_init,
+	.isoc_init   = sd_isoc_init,
+	.start       = sd_start,
+	.stop0       = sd_stop0,
+	.pkt_scan    = sd_pkt_scan,
+	.dq_callback = sd_callback,
+};
+
+static const struct sd_desc sd_desc_ov9655 = {
+	.name        = MODULE_NAME,
+	.ctrls       = sd_ctrls_ov9655,
+	.nctrls      = GL860_NCTRLS,
+	.config      = sd_config,
+	.init        = sd_init,
+	.isoc_init   = sd_isoc_init,
+	.start       = sd_start,
+	.stop0       = sd_stop0,
+	.pkt_scan    = sd_pkt_scan,
+	.dq_callback = sd_callback,
+};
+
+/*=========================== sub-driver image sizes =======================*/
+
+static struct v4l2_pix_format mi2020_mode[] = {
+	{ 640,  480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0
+	},
+	{ 800,  598, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 800,
+		.sizeimage = 800 * 598,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1
+	},
+	{1280, 1024, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 1280,
+		.sizeimage = 1280 * 1024,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 2
+	},
+	{1600, 1198, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 1600,
+		.sizeimage = 1600 * 1198,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 3
+	},
+};
+
+static struct v4l2_pix_format ov2640_mode[] = {
+	{ 640,  480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0
+	},
+	{ 800,  600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 800,
+		.sizeimage = 800 * 600,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1
+	},
+	{1280,  960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 1280,
+		.sizeimage = 1280 * 960,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 2
+	},
+	{1600, 1200, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 1600,
+		.sizeimage = 1600 * 1200,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 3
+	},
+};
+
+static struct v4l2_pix_format mi1320_mode[] = {
+	{ 640,  480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0
+	},
+	{ 800,  600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 800,
+		.sizeimage = 800 * 600,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1
+	},
+	{1280,  960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 1280,
+		.sizeimage = 1280 * 960,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 2
+	},
+};
+
+static struct v4l2_pix_format ov9655_mode[] = {
+	{ 640,  480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0
+	},
+	{1280,  960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 1280,
+		.sizeimage = 1280 * 960,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1
+	},
+};
+
+/*========================= sud-driver functions ===========================*/
+
+/* This function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+	u16 vendor_id, product_id;
+
+	/* Get USB VendorID and ProductID */
+	vendor_id  = id->idVendor;
+	product_id = id->idProduct;
+
+	sd->nbRightUp = 1;
+	sd->nbIm = -1;
+
+	sd->sensor = 0xff;
+	if (strcmp(sensor, "MI1320") == 0)
+		sd->sensor = ID_MI1320;
+	else if (strcmp(sensor, "OV2640") == 0)
+		sd->sensor = ID_OV2640;
+	else if (strcmp(sensor, "OV9655") == 0)
+		sd->sensor = ID_OV9655;
+	else if (strcmp(sensor, "MI2020") == 0)
+		sd->sensor = ID_MI2020;
+
+	/* Get sensor and set the suitable init/start/../stop functions */
+	if (gl860_guess_sensor(gspca_dev, vendor_id, product_id) == -1)
+		return -1;
+
+	cam = &gspca_dev->cam;
+
+	switch (sd->sensor) {
+	case ID_MI1320:
+		gspca_dev->sd_desc = &sd_desc_mi1320;
+		cam->cam_mode = mi1320_mode;
+		cam->nmodes = ARRAY_SIZE(mi1320_mode);
+		dev_init_settings   = mi1320_init_settings;
+		break;
+
+	case ID_MI2020:
+		gspca_dev->sd_desc = &sd_desc_mi2020;
+		cam->cam_mode = mi2020_mode;
+		cam->nmodes = ARRAY_SIZE(mi2020_mode);
+		dev_init_settings   = mi2020_init_settings;
+		break;
+
+	case ID_OV2640:
+		gspca_dev->sd_desc = &sd_desc_ov2640;
+		cam->cam_mode = ov2640_mode;
+		cam->nmodes = ARRAY_SIZE(ov2640_mode);
+		dev_init_settings   = ov2640_init_settings;
+		break;
+
+	case ID_OV9655:
+		gspca_dev->sd_desc = &sd_desc_ov9655;
+		cam->cam_mode = ov9655_mode;
+		cam->nmodes = ARRAY_SIZE(ov9655_mode);
+		dev_init_settings   = ov9655_init_settings;
+		break;
+	}
+
+	dev_init_settings(gspca_dev);
+	if (AC50Hz != 0xff)
+		((struct sd *) gspca_dev)->vcur.AC50Hz = AC50Hz;
+	gl860_build_control_table(gspca_dev);
+
+	return 0;
+}
+
+/* This function is called at probe time after sd_config */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	return sd->dev_init_at_startup(gspca_dev);
+}
+
+/* This function is called before to choose the alt setting */
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	return sd->dev_configure_alt(gspca_dev);
+}
+
+/* This function is called to start the webcam */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	return sd->dev_init_pre_alt(gspca_dev);
+}
+
+/* This function is called to stop the webcam */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (!sd->gspca_dev.present)
+		return;
+
+	return sd->dev_post_unset_alt(gspca_dev);
+}
+
+/* This function is called when an image is being received */
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			u8 *data, int len)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	static s32 nSkipped;
+
+	s32 mode = (s32) gspca_dev->curr_mode;
+	s32 nToSkip =
+		sd->swapRB * (gspca_dev->cam.cam_mode[mode].bytesperline + 1);
+
+	/* Test only against 0202h, so endianess does not matter */
+	switch (*(s16 *) data) {
+	case 0x0202:		/* End of frame, start a new one */
+		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+		nSkipped = 0;
+		if (sd->nbIm >= 0 && sd->nbIm < 10)
+			sd->nbIm++;
+		gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
+		break;
+
+	default:
+		data += 2;
+		len  -= 2;
+		if (nSkipped + len <= nToSkip)
+			nSkipped += len;
+		else {
+			if (nSkipped < nToSkip && nSkipped + len > nToSkip) {
+				data += nToSkip - nSkipped;
+				len  -= nToSkip - nSkipped;
+				nSkipped = nToSkip + 1;
+			}
+			gspca_frame_add(gspca_dev,
+				INTER_PACKET, data, len);
+		}
+		break;
+	}
+}
+
+/* This function is called when an image has been read */
+/* This function is used to monitor webcam orientation */
+static void sd_callback(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (!_OV9655_) {
+		u8 state;
+		u8 upsideDown;
+
+		/* Probe sensor orientation */
+		ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, (void *)&state);
+
+		/* C8/40 means upside-down (looking backwards) */
+		/* D8/50 means right-up (looking onwards) */
+		upsideDown = (state == 0xc8 || state == 0x40);
+
+		if (upsideDown && sd->nbRightUp > -4) {
+			if (sd->nbRightUp > 0)
+				sd->nbRightUp = 0;
+			if (sd->nbRightUp == -3) {
+				sd->mirrorMask = 1;
+				sd->waitSet = 1;
+			}
+			sd->nbRightUp--;
+		}
+		if (!upsideDown && sd->nbRightUp < 4) {
+			if (sd->nbRightUp  < 0)
+				sd->nbRightUp = 0;
+			if (sd->nbRightUp == 3) {
+				sd->mirrorMask = 0;
+				sd->waitSet = 1;
+			}
+			sd->nbRightUp++;
+		}
+	}
+
+	if (sd->waitSet)
+		sd->dev_camera_settings(gspca_dev);
+}
+
+/*=================== USB driver structure initialisation ==================*/
+
+static const struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x05e3, 0x0503)},
+	{USB_DEVICE(0x05e3, 0xf191)},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+static int sd_probe(struct usb_interface *intf,
+				const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id,
+			&sd_desc_mi1320, sizeof(struct sd), THIS_MODULE);
+}
+
+static void sd_disconnect(struct usb_interface *intf)
+{
+	gspca_disconnect(intf);
+}
+
+static struct usb_driver sd_driver = {
+	.name       = MODULE_NAME,
+	.id_table   = device_table,
+	.probe      = sd_probe,
+	.disconnect = sd_disconnect,
+#ifdef CONFIG_PM
+	.suspend    = gspca_suspend,
+	.resume     = gspca_resume,
+	.reset_resume = gspca_resume,
+#endif
+};
+
+/*====================== Init and Exit module functions ====================*/
+
+module_usb_driver(sd_driver);
+
+/*==========================================================================*/
+
+int gl860_RTx(struct gspca_dev *gspca_dev,
+		unsigned char pref, u32 req, u16 val, u16 index,
+		s32 len, void *pdata)
+{
+	struct usb_device *udev = gspca_dev->dev;
+	s32 r = 0;
+
+	if (pref == 0x40) { /* Send */
+		if (len > 0) {
+			memcpy(gspca_dev->usb_buf, pdata, len);
+			r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+					req, pref, val, index,
+					gspca_dev->usb_buf,
+					len, 400 + 200 * (len > 1));
+		} else {
+			r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+					req, pref, val, index, NULL, len, 400);
+		}
+	} else { /* Receive */
+		if (len > 0) {
+			r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+					req, pref, val, index,
+					gspca_dev->usb_buf,
+					len, 400 + 200 * (len > 1));
+			memcpy(pdata, gspca_dev->usb_buf, len);
+		} else {
+			r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+					req, pref, val, index, NULL, len, 400);
+		}
+	}
+
+	if (r < 0)
+		pr_err("ctrl transfer failed %4d [p%02x r%d v%04x i%04x len%d]\n",
+		       r, pref, req, val, index, len);
+	else if (len > 1 && r < len)
+		PDEBUG(D_ERR, "short ctrl transfer %d/%d", r, len);
+
+	msleep(1);
+
+	return r;
+}
+
+int fetch_validx(struct gspca_dev *gspca_dev, struct validx *tbl, int len)
+{
+	int n;
+
+	for (n = 0; n < len; n++) {
+		if (tbl[n].idx != 0xffff)
+			ctrl_out(gspca_dev, 0x40, 1, tbl[n].val,
+					tbl[n].idx, 0, NULL);
+		else if (tbl[n].val == 0xffff)
+			break;
+		else
+			msleep(tbl[n].val);
+	}
+	return n;
+}
+
+int keep_on_fetching_validx(struct gspca_dev *gspca_dev, struct validx *tbl,
+				int len, int n)
+{
+	while (++n < len) {
+		if (tbl[n].idx != 0xffff)
+			ctrl_out(gspca_dev, 0x40, 1, tbl[n].val, tbl[n].idx,
+					0, NULL);
+		else if (tbl[n].val == 0xffff)
+			break;
+		else
+			msleep(tbl[n].val);
+	}
+	return n;
+}
+
+void fetch_idxdata(struct gspca_dev *gspca_dev, struct idxdata *tbl, int len)
+{
+	int n;
+
+	for (n = 0; n < len; n++) {
+		if (memcmp(tbl[n].data, "\xff\xff\xff", 3) != 0)
+			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, tbl[n].idx,
+					3, tbl[n].data);
+		else
+			msleep(tbl[n].idx);
+	}
+}
+
+static int gl860_guess_sensor(struct gspca_dev *gspca_dev,
+				u16 vendor_id, u16 product_id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 probe, nb26, nb96, nOV, ntry;
+
+	if (product_id == 0xf191)
+		sd->sensor = ID_MI1320;
+
+	if (sd->sensor == 0xff) {
+		ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &probe);
+		ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &probe);
+
+		ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x0000, 0, NULL);
+		msleep(3);
+		ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL);
+		msleep(3);
+		ctrl_out(gspca_dev, 0x40, 1, 0x0008, 0x00c0, 0, NULL);
+		msleep(3);
+		ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x00c1, 0, NULL);
+		msleep(3);
+		ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x00c2, 0, NULL);
+		msleep(3);
+		ctrl_out(gspca_dev, 0x40, 1, 0x0020, 0x0006, 0, NULL);
+		msleep(3);
+		ctrl_out(gspca_dev, 0x40, 1, 0x006a, 0x000d, 0, NULL);
+		msleep(56);
+
+		PDEBUG(D_PROBE, "probing for sensor MI2020 or OVXXXX");
+		nOV = 0;
+		for (ntry = 0; ntry < 4; ntry++) {
+			ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
+			msleep(3);
+			ctrl_out(gspca_dev, 0x40, 1, 0x0063, 0x0006, 0, NULL);
+			msleep(3);
+			ctrl_out(gspca_dev, 0x40, 1, 0x7a00, 0x8030, 0, NULL);
+			msleep(10);
+			ctrl_in(gspca_dev, 0xc0, 2, 0x7a00, 0x8030, 1, &probe);
+			PDEBUG(D_PROBE, "probe=0x%02x", probe);
+			if (probe == 0xff)
+				nOV++;
+		}
+
+		if (nOV) {
+			PDEBUG(D_PROBE, "0xff -> OVXXXX");
+			PDEBUG(D_PROBE, "probing for sensor OV2640 or OV9655");
+
+			nb26 = nb96 = 0;
+			for (ntry = 0; ntry < 4; ntry++) {
+				ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000,
+						0, NULL);
+				msleep(3);
+				ctrl_out(gspca_dev, 0x40, 1, 0x6000, 0x800a,
+						0, NULL);
+				msleep(10);
+
+				/* Wait for 26(OV2640) or 96(OV9655) */
+				ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x800a,
+						1, &probe);
+
+				if (probe == 0x26 || probe == 0x40) {
+					PDEBUG(D_PROBE,
+						"probe=0x%02x -> OV2640",
+						probe);
+					sd->sensor = ID_OV2640;
+					nb26 += 4;
+					break;
+				}
+				if (probe == 0x96 || probe == 0x55) {
+					PDEBUG(D_PROBE,
+						"probe=0x%02x -> OV9655",
+						probe);
+					sd->sensor = ID_OV9655;
+					nb96 += 4;
+					break;
+				}
+				PDEBUG(D_PROBE, "probe=0x%02x", probe);
+				if (probe == 0x00)
+					nb26++;
+				if (probe == 0xff)
+					nb96++;
+				msleep(3);
+			}
+			if (nb26 < 4 && nb96 < 4)
+				return -1;
+		} else {
+			PDEBUG(D_PROBE, "Not any 0xff -> MI2020");
+			sd->sensor = ID_MI2020;
+		}
+	}
+
+	if (_MI1320_) {
+		PDEBUG(D_PROBE, "05e3:f191 sensor MI1320 (1.3M)");
+	} else if (_MI2020_) {
+		PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 (2.0M)");
+	} else if (_OV9655_) {
+		PDEBUG(D_PROBE, "05e3:0503 sensor OV9655 (1.3M)");
+	} else if (_OV2640_) {
+		PDEBUG(D_PROBE, "05e3:0503 sensor OV2640 (2.0M)");
+	} else {
+		PDEBUG(D_PROBE, "***** Unknown sensor *****");
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/drivers/media/usb/gspca/gl860/gl860.h b/drivers/media/usb/gspca/gl860/gl860.h
new file mode 100644
index 0000000..0330a02
--- /dev/null
+++ b/drivers/media/usb/gspca/gl860/gl860.h
@@ -0,0 +1,105 @@
+/* GSPCA subdrivers for Genesys Logic webcams with the GL860 chip
+ * Subdriver declarations
+ *
+ * 2009/10/14 Olivier LORIN <o.lorin@laposte.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
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef GL860_DEV_H
+#define GL860_DEV_H
+
+#include "gspca.h"
+
+#define MODULE_NAME "gspca_gl860"
+#define DRIVER_VERSION "0.9d10"
+
+#define ctrl_in  gl860_RTx
+#define ctrl_out gl860_RTx
+
+#define ID_MI1320   1
+#define ID_OV2640   2
+#define ID_OV9655   4
+#define ID_MI2020   8
+
+#define _MI1320_  (((struct sd *) gspca_dev)->sensor == ID_MI1320)
+#define _MI2020_  (((struct sd *) gspca_dev)->sensor == ID_MI2020)
+#define _OV2640_  (((struct sd *) gspca_dev)->sensor == ID_OV2640)
+#define _OV9655_  (((struct sd *) gspca_dev)->sensor == ID_OV9655)
+
+#define IMAGE_640   0
+#define IMAGE_800   1
+#define IMAGE_1280  2
+#define IMAGE_1600  3
+
+struct sd_gl860 {
+	u16 backlight;
+	u16 brightness;
+	u16 sharpness;
+	u16 contrast;
+	u16 gamma;
+	u16 hue;
+	u16 saturation;
+	u16 whitebal;
+	u8  mirror;
+	u8  flip;
+	u8  AC50Hz;
+};
+
+/* Specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	struct sd_gl860 vcur;
+	struct sd_gl860 vold;
+	struct sd_gl860 vmax;
+
+	int  (*dev_configure_alt)  (struct gspca_dev *);
+	int  (*dev_init_at_startup)(struct gspca_dev *);
+	int  (*dev_init_pre_alt)   (struct gspca_dev *);
+	void (*dev_post_unset_alt) (struct gspca_dev *);
+	int  (*dev_camera_settings)(struct gspca_dev *);
+
+	u8   swapRB;
+	u8   mirrorMask;
+	u8   sensor;
+	s32  nbIm;
+	s32  nbRightUp;
+	u8   waitSet;
+};
+
+struct validx {
+	u16 val;
+	u16 idx;
+};
+
+struct idxdata {
+	u8 idx;
+	u8 data[3];
+};
+
+int fetch_validx(struct gspca_dev *gspca_dev, struct validx *tbl, int len);
+int keep_on_fetching_validx(struct gspca_dev *gspca_dev, struct validx *tbl,
+				int len, int n);
+void fetch_idxdata(struct gspca_dev *gspca_dev, struct idxdata *tbl, int len);
+
+int gl860_RTx(struct gspca_dev *gspca_dev,
+			unsigned char pref, u32 req, u16 val, u16 index,
+			s32 len, void *pdata);
+
+void mi1320_init_settings(struct gspca_dev *);
+void ov2640_init_settings(struct gspca_dev *);
+void ov9655_init_settings(struct gspca_dev *);
+void mi2020_init_settings(struct gspca_dev *);
+
+#endif
diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c
new file mode 100644
index 0000000..d4e8343
--- /dev/null
+++ b/drivers/media/usb/gspca/gspca.c
@@ -0,0 +1,2456 @@
+/*
+ * Main USB camera driver
+ *
+ * Copyright (C) 2008-2011 Jean-François Moine <http://moinejf.free.fr>
+ *
+ * Camera button input handling by Márton Németh
+ * Copyright (C) 2009-2010 Márton Németh <nm127@freemail.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define GSPCA_VERSION	"2.14.0"
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pagemap.h>
+#include <linux/io.h>
+#include <asm/page.h>
+#include <linux/uaccess.h>
+#include <linux/ktime.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+
+#include "gspca.h"
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#include <linux/input.h>
+#include <linux/usb/input.h>
+#endif
+
+/* global values */
+#define DEF_NURBS 3		/* default number of URBs */
+#if DEF_NURBS > MAX_NURBS
+#error "DEF_NURBS too big"
+#endif
+
+MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("GSPCA USB Camera Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(GSPCA_VERSION);
+
+#ifdef GSPCA_DEBUG
+int gspca_debug = D_ERR | D_PROBE;
+EXPORT_SYMBOL(gspca_debug);
+
+static void PDEBUG_MODE(char *txt, __u32 pixfmt, int w, int h)
+{
+	if ((pixfmt >> 24) >= '0' && (pixfmt >> 24) <= 'z') {
+		PDEBUG(D_CONF|D_STREAM, "%s %c%c%c%c %dx%d",
+			txt,
+			pixfmt & 0xff,
+			(pixfmt >> 8) & 0xff,
+			(pixfmt >> 16) & 0xff,
+			pixfmt >> 24,
+			w, h);
+	} else {
+		PDEBUG(D_CONF|D_STREAM, "%s 0x%08x %dx%d",
+			txt,
+			pixfmt,
+			w, h);
+	}
+}
+#else
+#define PDEBUG_MODE(txt, pixfmt, w, h)
+#endif
+
+/* specific memory types - !! should be different from V4L2_MEMORY_xxx */
+#define GSPCA_MEMORY_NO 0	/* V4L2_MEMORY_xxx starts from 1 */
+#define GSPCA_MEMORY_READ 7
+
+#define BUF_ALL_FLAGS (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE)
+
+/*
+ * VMA operations.
+ */
+static void gspca_vm_open(struct vm_area_struct *vma)
+{
+	struct gspca_frame *frame = vma->vm_private_data;
+
+	frame->vma_use_count++;
+	frame->v4l2_buf.flags |= V4L2_BUF_FLAG_MAPPED;
+}
+
+static void gspca_vm_close(struct vm_area_struct *vma)
+{
+	struct gspca_frame *frame = vma->vm_private_data;
+
+	if (--frame->vma_use_count <= 0)
+		frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_MAPPED;
+}
+
+static const struct vm_operations_struct gspca_vm_ops = {
+	.open		= gspca_vm_open,
+	.close		= gspca_vm_close,
+};
+
+/*
+ * Input and interrupt endpoint handling functions
+ */
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+static void int_irq(struct urb *urb)
+{
+	struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
+	int ret;
+
+	ret = urb->status;
+	switch (ret) {
+	case 0:
+		if (gspca_dev->sd_desc->int_pkt_scan(gspca_dev,
+		    urb->transfer_buffer, urb->actual_length) < 0) {
+			PDEBUG(D_ERR, "Unknown packet received");
+		}
+		break;
+
+	case -ENOENT:
+	case -ECONNRESET:
+	case -ENODEV:
+	case -ESHUTDOWN:
+		/* Stop is requested either by software or hardware is gone,
+		 * keep the ret value non-zero and don't resubmit later.
+		 */
+		break;
+
+	default:
+		PDEBUG(D_ERR, "URB error %i, resubmitting", urb->status);
+		urb->status = 0;
+		ret = 0;
+	}
+
+	if (ret == 0) {
+		ret = usb_submit_urb(urb, GFP_ATOMIC);
+		if (ret < 0)
+			pr_err("Resubmit URB failed with error %i\n", ret);
+	}
+}
+
+static int gspca_input_connect(struct gspca_dev *dev)
+{
+	struct input_dev *input_dev;
+	int err = 0;
+
+	dev->input_dev = NULL;
+	if (dev->sd_desc->int_pkt_scan || dev->sd_desc->other_input)  {
+		input_dev = input_allocate_device();
+		if (!input_dev)
+			return -ENOMEM;
+
+		usb_make_path(dev->dev, dev->phys, sizeof(dev->phys));
+		strlcat(dev->phys, "/input0", sizeof(dev->phys));
+
+		input_dev->name = dev->sd_desc->name;
+		input_dev->phys = dev->phys;
+
+		usb_to_input_id(dev->dev, &input_dev->id);
+
+		input_dev->evbit[0] = BIT_MASK(EV_KEY);
+		input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
+		input_dev->dev.parent = &dev->dev->dev;
+
+		err = input_register_device(input_dev);
+		if (err) {
+			pr_err("Input device registration failed with error %i\n",
+			       err);
+			input_dev->dev.parent = NULL;
+			input_free_device(input_dev);
+		} else {
+			dev->input_dev = input_dev;
+		}
+	}
+
+	return err;
+}
+
+static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev,
+			  struct usb_endpoint_descriptor *ep)
+{
+	unsigned int buffer_len;
+	int interval;
+	struct urb *urb;
+	struct usb_device *dev;
+	void *buffer = NULL;
+	int ret = -EINVAL;
+
+	buffer_len = le16_to_cpu(ep->wMaxPacketSize);
+	interval = ep->bInterval;
+	PDEBUG(D_CONF, "found int in endpoint: 0x%x, "
+		"buffer_len=%u, interval=%u",
+		ep->bEndpointAddress, buffer_len, interval);
+
+	dev = gspca_dev->dev;
+
+	urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!urb) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	buffer = usb_alloc_coherent(dev, buffer_len,
+				GFP_KERNEL, &urb->transfer_dma);
+	if (!buffer) {
+		ret = -ENOMEM;
+		goto error_buffer;
+	}
+	usb_fill_int_urb(urb, dev,
+		usb_rcvintpipe(dev, ep->bEndpointAddress),
+		buffer, buffer_len,
+		int_irq, (void *)gspca_dev, interval);
+	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	ret = usb_submit_urb(urb, GFP_KERNEL);
+	if (ret < 0) {
+		PDEBUG(D_ERR, "submit int URB failed with error %i", ret);
+		goto error_submit;
+	}
+	gspca_dev->int_urb = urb;
+	return ret;
+
+error_submit:
+	usb_free_coherent(dev,
+			  urb->transfer_buffer_length,
+			  urb->transfer_buffer,
+			  urb->transfer_dma);
+error_buffer:
+	usb_free_urb(urb);
+error:
+	return ret;
+}
+
+static void gspca_input_create_urb(struct gspca_dev *gspca_dev)
+{
+	struct usb_interface *intf;
+	struct usb_host_interface *intf_desc;
+	struct usb_endpoint_descriptor *ep;
+	int i;
+
+	if (gspca_dev->sd_desc->int_pkt_scan)  {
+		intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
+		intf_desc = intf->cur_altsetting;
+		for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) {
+			ep = &intf_desc->endpoint[i].desc;
+			if (usb_endpoint_dir_in(ep) &&
+			    usb_endpoint_xfer_int(ep)) {
+
+				alloc_and_submit_int_urb(gspca_dev, ep);
+				break;
+			}
+		}
+	}
+}
+
+static void gspca_input_destroy_urb(struct gspca_dev *gspca_dev)
+{
+	struct urb *urb;
+
+	urb = gspca_dev->int_urb;
+	if (urb) {
+		gspca_dev->int_urb = NULL;
+		usb_kill_urb(urb);
+		usb_free_coherent(gspca_dev->dev,
+				  urb->transfer_buffer_length,
+				  urb->transfer_buffer,
+				  urb->transfer_dma);
+		usb_free_urb(urb);
+	}
+}
+#else
+static inline void gspca_input_destroy_urb(struct gspca_dev *gspca_dev)
+{
+}
+
+static inline void gspca_input_create_urb(struct gspca_dev *gspca_dev)
+{
+}
+
+static inline int gspca_input_connect(struct gspca_dev *dev)
+{
+	return 0;
+}
+#endif
+
+/*
+ * fill a video frame from an URB and resubmit
+ */
+static void fill_frame(struct gspca_dev *gspca_dev,
+			struct urb *urb)
+{
+	u8 *data;		/* address of data in the iso message */
+	int i, len, st;
+	cam_pkt_op pkt_scan;
+
+	if (urb->status != 0) {
+		if (urb->status == -ESHUTDOWN)
+			return;		/* disconnection */
+#ifdef CONFIG_PM
+		if (gspca_dev->frozen)
+			return;
+#endif
+		PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+		urb->status = 0;
+		goto resubmit;
+	}
+	pkt_scan = gspca_dev->sd_desc->pkt_scan;
+	for (i = 0; i < urb->number_of_packets; i++) {
+		len = urb->iso_frame_desc[i].actual_length;
+
+		/* check the packet status and length */
+		st = urb->iso_frame_desc[i].status;
+		if (st) {
+			pr_err("ISOC data error: [%d] len=%d, status=%d\n",
+			       i, len, st);
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+			continue;
+		}
+		if (len == 0) {
+			if (gspca_dev->empty_packet == 0)
+				gspca_dev->empty_packet = 1;
+			continue;
+		}
+
+		/* let the packet be analyzed by the subdriver */
+		PDEBUG(D_PACK, "packet [%d] o:%d l:%d",
+			i, urb->iso_frame_desc[i].offset, len);
+		data = (u8 *) urb->transfer_buffer
+					+ urb->iso_frame_desc[i].offset;
+		pkt_scan(gspca_dev, data, len);
+	}
+
+resubmit:
+	/* resubmit the URB */
+	st = usb_submit_urb(urb, GFP_ATOMIC);
+	if (st < 0)
+		pr_err("usb_submit_urb() ret %d\n", st);
+}
+
+/*
+ * ISOC message interrupt from the USB device
+ *
+ * Analyse each packet and call the subdriver for copy to the frame buffer.
+ */
+static void isoc_irq(struct urb *urb)
+{
+	struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
+
+	PDEBUG(D_PACK, "isoc irq");
+	if (!gspca_dev->streaming)
+		return;
+	fill_frame(gspca_dev, urb);
+}
+
+/*
+ * bulk message interrupt from the USB device
+ */
+static void bulk_irq(struct urb *urb)
+{
+	struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
+	int st;
+
+	PDEBUG(D_PACK, "bulk irq");
+	if (!gspca_dev->streaming)
+		return;
+	switch (urb->status) {
+	case 0:
+		break;
+	case -ESHUTDOWN:
+		return;		/* disconnection */
+	default:
+#ifdef CONFIG_PM
+		if (gspca_dev->frozen)
+			return;
+#endif
+		PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+		urb->status = 0;
+		goto resubmit;
+	}
+
+	PDEBUG(D_PACK, "packet l:%d", urb->actual_length);
+	gspca_dev->sd_desc->pkt_scan(gspca_dev,
+				urb->transfer_buffer,
+				urb->actual_length);
+
+resubmit:
+	/* resubmit the URB */
+	if (gspca_dev->cam.bulk_nurbs != 0) {
+		st = usb_submit_urb(urb, GFP_ATOMIC);
+		if (st < 0)
+			pr_err("usb_submit_urb() ret %d\n", st);
+	}
+}
+
+/*
+ * add data to the current frame
+ *
+ * This function is called by the subdrivers at interrupt level.
+ *
+ * To build a frame, these ones must add
+ *	- one FIRST_PACKET
+ *	- 0 or many INTER_PACKETs
+ *	- one LAST_PACKET
+ * DISCARD_PACKET invalidates the whole frame.
+ */
+void gspca_frame_add(struct gspca_dev *gspca_dev,
+			enum gspca_packet_type packet_type,
+			const u8 *data,
+			int len)
+{
+	struct gspca_frame *frame;
+	int i, j;
+
+	PDEBUG(D_PACK, "add t:%d l:%d",	packet_type, len);
+
+	if (packet_type == FIRST_PACKET) {
+		i = atomic_read(&gspca_dev->fr_i);
+
+		/* if there are no queued buffer, discard the whole frame */
+		if (i == atomic_read(&gspca_dev->fr_q)) {
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+			gspca_dev->sequence++;
+			return;
+		}
+		j = gspca_dev->fr_queue[i];
+		frame = &gspca_dev->frame[j];
+		frame->v4l2_buf.timestamp = ktime_to_timeval(ktime_get());
+		frame->v4l2_buf.sequence = gspca_dev->sequence++;
+		gspca_dev->image = frame->data;
+		gspca_dev->image_len = 0;
+	} else {
+		switch (gspca_dev->last_packet_type) {
+		case DISCARD_PACKET:
+			if (packet_type == LAST_PACKET) {
+				gspca_dev->last_packet_type = packet_type;
+				gspca_dev->image = NULL;
+				gspca_dev->image_len = 0;
+			}
+			return;
+		case LAST_PACKET:
+			return;
+		}
+	}
+
+	/* append the packet to the frame buffer */
+	if (len > 0) {
+		if (gspca_dev->image_len + len > gspca_dev->frsz) {
+			PDEBUG(D_ERR|D_PACK, "frame overflow %d > %d",
+				gspca_dev->image_len + len,
+				gspca_dev->frsz);
+			packet_type = DISCARD_PACKET;
+		} else {
+/* !! image is NULL only when last pkt is LAST or DISCARD
+			if (gspca_dev->image == NULL) {
+				pr_err("gspca_frame_add() image == NULL\n");
+				return;
+			}
+ */
+			memcpy(gspca_dev->image + gspca_dev->image_len,
+				data, len);
+			gspca_dev->image_len += len;
+		}
+	}
+	gspca_dev->last_packet_type = packet_type;
+
+	/* if last packet, invalidate packet concatenation until
+	 * next first packet, wake up the application and advance
+	 * in the queue */
+	if (packet_type == LAST_PACKET) {
+		i = atomic_read(&gspca_dev->fr_i);
+		j = gspca_dev->fr_queue[i];
+		frame = &gspca_dev->frame[j];
+		frame->v4l2_buf.bytesused = gspca_dev->image_len;
+		frame->v4l2_buf.flags = (frame->v4l2_buf.flags
+					 | V4L2_BUF_FLAG_DONE)
+					& ~V4L2_BUF_FLAG_QUEUED;
+		i = (i + 1) % GSPCA_MAX_FRAMES;
+		atomic_set(&gspca_dev->fr_i, i);
+		wake_up_interruptible(&gspca_dev->wq);	/* event = new frame */
+		PDEBUG(D_FRAM, "frame complete len:%d",
+			frame->v4l2_buf.bytesused);
+		gspca_dev->image = NULL;
+		gspca_dev->image_len = 0;
+	}
+}
+EXPORT_SYMBOL(gspca_frame_add);
+
+static int frame_alloc(struct gspca_dev *gspca_dev, struct file *file,
+			enum v4l2_memory memory, unsigned int count)
+{
+	struct gspca_frame *frame;
+	unsigned int frsz;
+	int i;
+
+	i = gspca_dev->curr_mode;
+	frsz = gspca_dev->cam.cam_mode[i].sizeimage;
+	PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz);
+	frsz = PAGE_ALIGN(frsz);
+	if (count >= GSPCA_MAX_FRAMES)
+		count = GSPCA_MAX_FRAMES - 1;
+	gspca_dev->frbuf = vmalloc_32(frsz * count);
+	if (!gspca_dev->frbuf) {
+		pr_err("frame alloc failed\n");
+		return -ENOMEM;
+	}
+	gspca_dev->capt_file = file;
+	gspca_dev->memory = memory;
+	gspca_dev->frsz = frsz;
+	gspca_dev->nframes = count;
+	for (i = 0; i < count; i++) {
+		frame = &gspca_dev->frame[i];
+		frame->v4l2_buf.index = i;
+		frame->v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		frame->v4l2_buf.flags = 0;
+		frame->v4l2_buf.field = V4L2_FIELD_NONE;
+		frame->v4l2_buf.length = frsz;
+		frame->v4l2_buf.memory = memory;
+		frame->v4l2_buf.sequence = 0;
+		frame->data = gspca_dev->frbuf + i * frsz;
+		frame->v4l2_buf.m.offset = i * frsz;
+	}
+	atomic_set(&gspca_dev->fr_q, 0);
+	atomic_set(&gspca_dev->fr_i, 0);
+	gspca_dev->fr_o = 0;
+	return 0;
+}
+
+static void frame_free(struct gspca_dev *gspca_dev)
+{
+	int i;
+
+	PDEBUG(D_STREAM, "frame free");
+	if (gspca_dev->frbuf != NULL) {
+		vfree(gspca_dev->frbuf);
+		gspca_dev->frbuf = NULL;
+		for (i = 0; i < gspca_dev->nframes; i++)
+			gspca_dev->frame[i].data = NULL;
+	}
+	gspca_dev->nframes = 0;
+	gspca_dev->frsz = 0;
+	gspca_dev->capt_file = NULL;
+	gspca_dev->memory = GSPCA_MEMORY_NO;
+}
+
+static void destroy_urbs(struct gspca_dev *gspca_dev)
+{
+	struct urb *urb;
+	unsigned int i;
+
+	PDEBUG(D_STREAM, "kill transfer");
+	for (i = 0; i < MAX_NURBS; i++) {
+		urb = gspca_dev->urb[i];
+		if (urb == NULL)
+			break;
+
+		gspca_dev->urb[i] = NULL;
+		usb_kill_urb(urb);
+		if (urb->transfer_buffer != NULL)
+			usb_free_coherent(gspca_dev->dev,
+					  urb->transfer_buffer_length,
+					  urb->transfer_buffer,
+					  urb->transfer_dma);
+		usb_free_urb(urb);
+	}
+}
+
+static int gspca_set_alt0(struct gspca_dev *gspca_dev)
+{
+	int ret;
+
+	if (gspca_dev->alt == 0)
+		return 0;
+	ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0);
+	if (ret < 0)
+		pr_err("set alt 0 err %d\n", ret);
+	return ret;
+}
+
+/* Note: both the queue and the usb locks should be held when calling this */
+static void gspca_stream_off(struct gspca_dev *gspca_dev)
+{
+	gspca_dev->streaming = 0;
+	gspca_dev->usb_err = 0;
+	if (gspca_dev->sd_desc->stopN)
+		gspca_dev->sd_desc->stopN(gspca_dev);
+	destroy_urbs(gspca_dev);
+	gspca_input_destroy_urb(gspca_dev);
+	gspca_set_alt0(gspca_dev);
+	gspca_input_create_urb(gspca_dev);
+	if (gspca_dev->sd_desc->stop0)
+		gspca_dev->sd_desc->stop0(gspca_dev);
+	PDEBUG(D_STREAM, "stream off OK");
+}
+
+/*
+ * look for an input transfer endpoint in an alternate setting
+ */
+static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt,
+					  int xfer)
+{
+	struct usb_host_endpoint *ep;
+	int i, attr;
+
+	for (i = 0; i < alt->desc.bNumEndpoints; i++) {
+		ep = &alt->endpoint[i];
+		attr = ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+		if (attr == xfer
+		    && ep->desc.wMaxPacketSize != 0
+		    && usb_endpoint_dir_in(&ep->desc))
+			return ep;
+	}
+	return NULL;
+}
+
+/* compute the minimum bandwidth for the current transfer */
+static u32 which_bandwidth(struct gspca_dev *gspca_dev)
+{
+	u32 bandwidth;
+	int i;
+
+	/* get the (max) image size */
+	i = gspca_dev->curr_mode;
+	bandwidth = gspca_dev->cam.cam_mode[i].sizeimage;
+
+	/* if the image is compressed, estimate its mean size */
+	if (!gspca_dev->cam.needs_full_bandwidth &&
+	    bandwidth < gspca_dev->cam.cam_mode[i].width *
+				gspca_dev->cam.cam_mode[i].height)
+		bandwidth = bandwidth * 3 / 8;	/* 0.375 */
+
+	/* estimate the frame rate */
+	if (gspca_dev->sd_desc->get_streamparm) {
+		struct v4l2_streamparm parm;
+
+		gspca_dev->sd_desc->get_streamparm(gspca_dev, &parm);
+		bandwidth *= parm.parm.capture.timeperframe.denominator;
+		bandwidth /= parm.parm.capture.timeperframe.numerator;
+	} else {
+
+		/* don't hope more than 15 fps with USB 1.1 and
+		 * image resolution >= 640x480 */
+		if (gspca_dev->width >= 640
+		 && gspca_dev->dev->speed == USB_SPEED_FULL)
+			bandwidth *= 15;		/* 15 fps */
+		else
+			bandwidth *= 30;		/* 30 fps */
+	}
+
+	PDEBUG(D_STREAM, "min bandwidth: %d", bandwidth);
+	return bandwidth;
+}
+
+/* endpoint table */
+#define MAX_ALT 16
+struct ep_tb_s {
+	u32 alt;
+	u32 bandwidth;
+};
+
+/*
+ * build the table of the endpoints
+ * and compute the minimum bandwidth for the image transfer
+ */
+static int build_isoc_ep_tb(struct gspca_dev *gspca_dev,
+			struct usb_interface *intf,
+			struct ep_tb_s *ep_tb)
+{
+	struct usb_host_endpoint *ep;
+	int i, j, nbalt, psize, found;
+	u32 bandwidth, last_bw;
+
+	nbalt = intf->num_altsetting;
+	if (nbalt > MAX_ALT)
+		nbalt = MAX_ALT;	/* fixme: should warn */
+
+	/* build the endpoint table */
+	i = 0;
+	last_bw = 0;
+	for (;;) {
+		ep_tb->bandwidth = 2000 * 2000 * 120;
+		found = 0;
+		for (j = 0; j < nbalt; j++) {
+			ep = alt_xfer(&intf->altsetting[j],
+				      USB_ENDPOINT_XFER_ISOC);
+			if (ep == NULL)
+				continue;
+			if (ep->desc.bInterval == 0) {
+				pr_err("alt %d iso endp with 0 interval\n", j);
+				continue;
+			}
+			psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+			psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+			bandwidth = psize * 1000;
+			if (gspca_dev->dev->speed == USB_SPEED_HIGH
+			 || gspca_dev->dev->speed == USB_SPEED_SUPER)
+				bandwidth *= 8;
+			bandwidth /= 1 << (ep->desc.bInterval - 1);
+			if (bandwidth <= last_bw)
+				continue;
+			if (bandwidth < ep_tb->bandwidth) {
+				ep_tb->bandwidth = bandwidth;
+				ep_tb->alt = j;
+				found = 1;
+			}
+		}
+		if (!found)
+			break;
+		PDEBUG(D_STREAM, "alt %d bandwidth %d",
+				ep_tb->alt, ep_tb->bandwidth);
+		last_bw = ep_tb->bandwidth;
+		i++;
+		ep_tb++;
+	}
+
+	/*
+	 * If the camera:
+	 * has a usb audio class interface (a built in usb mic); and
+	 * is a usb 1 full speed device; and
+	 * uses the max full speed iso bandwidth; and
+	 * and has more than 1 alt setting
+	 * then skip the highest alt setting to spare bandwidth for the mic
+	 */
+	if (gspca_dev->audio &&
+			gspca_dev->dev->speed == USB_SPEED_FULL &&
+			last_bw >= 1000000 &&
+			i > 1) {
+		PDEBUG(D_STREAM, "dev has usb audio, skipping highest alt");
+		i--;
+		ep_tb--;
+	}
+
+	/* get the requested bandwidth and start at the highest atlsetting */
+	bandwidth = which_bandwidth(gspca_dev);
+	ep_tb--;
+	while (i > 1) {
+		ep_tb--;
+		if (ep_tb->bandwidth < bandwidth)
+			break;
+		i--;
+	}
+	return i;
+}
+
+/*
+ * create the URBs for image transfer
+ */
+static int create_urbs(struct gspca_dev *gspca_dev,
+			struct usb_host_endpoint *ep)
+{
+	struct urb *urb;
+	int n, nurbs, i, psize, npkt, bsize;
+
+	/* calculate the packet size and the number of packets */
+	psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+
+	if (!gspca_dev->cam.bulk) {		/* isoc */
+
+		/* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
+		if (gspca_dev->pkt_size == 0)
+			psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+		else
+			psize = gspca_dev->pkt_size;
+		npkt = gspca_dev->cam.npkt;
+		if (npkt == 0)
+			npkt = 32;		/* default value */
+		bsize = psize * npkt;
+		PDEBUG(D_STREAM,
+			"isoc %d pkts size %d = bsize:%d",
+			npkt, psize, bsize);
+		nurbs = DEF_NURBS;
+	} else {				/* bulk */
+		npkt = 0;
+		bsize = gspca_dev->cam.bulk_size;
+		if (bsize == 0)
+			bsize = psize;
+		PDEBUG(D_STREAM, "bulk bsize:%d", bsize);
+		if (gspca_dev->cam.bulk_nurbs != 0)
+			nurbs = gspca_dev->cam.bulk_nurbs;
+		else
+			nurbs = 1;
+	}
+
+	for (n = 0; n < nurbs; n++) {
+		urb = usb_alloc_urb(npkt, GFP_KERNEL);
+		if (!urb) {
+			pr_err("usb_alloc_urb failed\n");
+			return -ENOMEM;
+		}
+		gspca_dev->urb[n] = urb;
+		urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev,
+						bsize,
+						GFP_KERNEL,
+						&urb->transfer_dma);
+
+		if (urb->transfer_buffer == NULL) {
+			pr_err("usb_alloc_coherent failed\n");
+			return -ENOMEM;
+		}
+		urb->dev = gspca_dev->dev;
+		urb->context = gspca_dev;
+		urb->transfer_buffer_length = bsize;
+		if (npkt != 0) {		/* ISOC */
+			urb->pipe = usb_rcvisocpipe(gspca_dev->dev,
+						    ep->desc.bEndpointAddress);
+			urb->transfer_flags = URB_ISO_ASAP
+					| URB_NO_TRANSFER_DMA_MAP;
+			urb->interval = 1 << (ep->desc.bInterval - 1);
+			urb->complete = isoc_irq;
+			urb->number_of_packets = npkt;
+			for (i = 0; i < npkt; i++) {
+				urb->iso_frame_desc[i].length = psize;
+				urb->iso_frame_desc[i].offset = psize * i;
+			}
+		} else {		/* bulk */
+			urb->pipe = usb_rcvbulkpipe(gspca_dev->dev,
+						ep->desc.bEndpointAddress);
+			urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+			urb->complete = bulk_irq;
+		}
+	}
+	return 0;
+}
+
+/*
+ * start the USB transfer
+ */
+static int gspca_init_transfer(struct gspca_dev *gspca_dev)
+{
+	struct usb_interface *intf;
+	struct usb_host_endpoint *ep;
+	struct urb *urb;
+	struct ep_tb_s ep_tb[MAX_ALT];
+	int n, ret, xfer, alt, alt_idx;
+
+	/* reset the streaming variables */
+	gspca_dev->image = NULL;
+	gspca_dev->image_len = 0;
+	gspca_dev->last_packet_type = DISCARD_PACKET;
+	gspca_dev->sequence = 0;
+
+	gspca_dev->usb_err = 0;
+
+	/* do the specific subdriver stuff before endpoint selection */
+	intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
+	gspca_dev->alt = gspca_dev->cam.bulk ? intf->num_altsetting : 0;
+	if (gspca_dev->sd_desc->isoc_init) {
+		ret = gspca_dev->sd_desc->isoc_init(gspca_dev);
+		if (ret < 0)
+			return ret;
+	}
+	xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK
+				   : USB_ENDPOINT_XFER_ISOC;
+
+	/* if bulk or the subdriver forced an altsetting, get the endpoint */
+	if (gspca_dev->alt != 0) {
+		gspca_dev->alt--;	/* (previous version compatibility) */
+		ep = alt_xfer(&intf->altsetting[gspca_dev->alt], xfer);
+		if (ep == NULL) {
+			pr_err("bad altsetting %d\n", gspca_dev->alt);
+			return -EIO;
+		}
+		ep_tb[0].alt = gspca_dev->alt;
+		alt_idx = 1;
+	} else {
+
+	/* else, compute the minimum bandwidth
+	 * and build the endpoint table */
+		alt_idx = build_isoc_ep_tb(gspca_dev, intf, ep_tb);
+		if (alt_idx <= 0) {
+			pr_err("no transfer endpoint found\n");
+			return -EIO;
+		}
+	}
+
+	/* set the highest alternate setting and
+	 * loop until urb submit succeeds */
+	gspca_input_destroy_urb(gspca_dev);
+
+	gspca_dev->alt = ep_tb[--alt_idx].alt;
+	alt = -1;
+	for (;;) {
+		if (alt != gspca_dev->alt) {
+			alt = gspca_dev->alt;
+			if (intf->num_altsetting > 1) {
+				ret = usb_set_interface(gspca_dev->dev,
+							gspca_dev->iface,
+							alt);
+				if (ret < 0) {
+					if (ret == -ENOSPC)
+						goto retry; /*fixme: ugly*/
+					pr_err("set alt %d err %d\n", alt, ret);
+					goto out;
+				}
+			}
+		}
+		if (!gspca_dev->cam.no_urb_create) {
+			PDEBUG(D_STREAM, "init transfer alt %d", alt);
+			ret = create_urbs(gspca_dev,
+				alt_xfer(&intf->altsetting[alt], xfer));
+			if (ret < 0) {
+				destroy_urbs(gspca_dev);
+				goto out;
+			}
+		}
+
+		/* clear the bulk endpoint */
+		if (gspca_dev->cam.bulk)
+			usb_clear_halt(gspca_dev->dev,
+					gspca_dev->urb[0]->pipe);
+
+		/* start the cam */
+		ret = gspca_dev->sd_desc->start(gspca_dev);
+		if (ret < 0) {
+			destroy_urbs(gspca_dev);
+			goto out;
+		}
+		gspca_dev->streaming = 1;
+		v4l2_ctrl_handler_setup(gspca_dev->vdev.ctrl_handler);
+
+		/* some bulk transfers are started by the subdriver */
+		if (gspca_dev->cam.bulk && gspca_dev->cam.bulk_nurbs == 0)
+			break;
+
+		/* submit the URBs */
+		for (n = 0; n < MAX_NURBS; n++) {
+			urb = gspca_dev->urb[n];
+			if (urb == NULL)
+				break;
+			ret = usb_submit_urb(urb, GFP_KERNEL);
+			if (ret < 0)
+				break;
+		}
+		if (ret >= 0)
+			break;			/* transfer is started */
+
+		/* something when wrong
+		 * stop the webcam and free the transfer resources */
+		gspca_stream_off(gspca_dev);
+		if (ret != -ENOSPC) {
+			pr_err("usb_submit_urb alt %d err %d\n",
+			       gspca_dev->alt, ret);
+			goto out;
+		}
+
+		/* the bandwidth is not wide enough
+		 * negotiate or try a lower alternate setting */
+retry:
+		PDEBUG(D_ERR|D_STREAM,
+			"alt %d - bandwidth not wide enough - trying again",
+			alt);
+		msleep(20);	/* wait for kill complete */
+		if (gspca_dev->sd_desc->isoc_nego) {
+			ret = gspca_dev->sd_desc->isoc_nego(gspca_dev);
+			if (ret < 0)
+				goto out;
+		} else {
+			if (alt_idx <= 0) {
+				pr_err("no transfer endpoint found\n");
+				ret = -EIO;
+				goto out;
+			}
+			gspca_dev->alt = ep_tb[--alt_idx].alt;
+		}
+	}
+out:
+	gspca_input_create_urb(gspca_dev);
+	return ret;
+}
+
+static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
+{
+	struct gspca_ctrl *ctrl;
+	int i;
+
+	i = gspca_dev->cam.nmodes - 1;	/* take the highest mode */
+	gspca_dev->curr_mode = i;
+	gspca_dev->width = gspca_dev->cam.cam_mode[i].width;
+	gspca_dev->height = gspca_dev->cam.cam_mode[i].height;
+	gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixelformat;
+
+	/* set the current control values to their default values
+	 * which may have changed in sd_init() */
+	/* does nothing if ctrl_handler == NULL */
+	v4l2_ctrl_handler_setup(gspca_dev->vdev.ctrl_handler);
+	ctrl = gspca_dev->cam.ctrls;
+	if (ctrl != NULL) {
+		for (i = 0;
+		     i < gspca_dev->sd_desc->nctrls;
+		     i++, ctrl++)
+			ctrl->val = ctrl->def;
+	}
+}
+
+static int wxh_to_mode(struct gspca_dev *gspca_dev,
+			int width, int height)
+{
+	int i;
+
+	for (i = gspca_dev->cam.nmodes; --i > 0; ) {
+		if (width >= gspca_dev->cam.cam_mode[i].width
+		    && height >= gspca_dev->cam.cam_mode[i].height)
+			break;
+	}
+	return i;
+}
+
+/*
+ * search a mode with the right pixel format
+ */
+static int gspca_get_mode(struct gspca_dev *gspca_dev,
+			int mode,
+			int pixfmt)
+{
+	int modeU, modeD;
+
+	modeU = modeD = mode;
+	while ((modeU < gspca_dev->cam.nmodes) || modeD >= 0) {
+		if (--modeD >= 0) {
+			if (gspca_dev->cam.cam_mode[modeD].pixelformat
+								== pixfmt)
+				return modeD;
+		}
+		if (++modeU < gspca_dev->cam.nmodes) {
+			if (gspca_dev->cam.cam_mode[modeU].pixelformat
+								== pixfmt)
+				return modeU;
+		}
+	}
+	return -EINVAL;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *priv,
+			struct v4l2_dbg_register *reg)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+
+	gspca_dev->usb_err = 0;
+	return gspca_dev->sd_desc->get_register(gspca_dev, reg);
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+			struct v4l2_dbg_register *reg)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+
+	gspca_dev->usb_err = 0;
+	return gspca_dev->sd_desc->set_register(gspca_dev, reg);
+}
+#endif
+
+static int vidioc_g_chip_ident(struct file *file, void *priv,
+			struct v4l2_dbg_chip_ident *chip)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+
+	gspca_dev->usb_err = 0;
+	return gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip);
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+				struct v4l2_fmtdesc *fmtdesc)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	int i, j, index;
+	__u32 fmt_tb[8];
+
+	/* give an index to each format */
+	index = 0;
+	j = 0;
+	for (i = gspca_dev->cam.nmodes; --i >= 0; ) {
+		fmt_tb[index] = gspca_dev->cam.cam_mode[i].pixelformat;
+		j = 0;
+		for (;;) {
+			if (fmt_tb[j] == fmt_tb[index])
+				break;
+			j++;
+		}
+		if (j == index) {
+			if (fmtdesc->index == index)
+				break;		/* new format */
+			index++;
+			if (index >= ARRAY_SIZE(fmt_tb))
+				return -EINVAL;
+		}
+	}
+	if (i < 0)
+		return -EINVAL;		/* no more format */
+
+	fmtdesc->pixelformat = fmt_tb[index];
+	if (gspca_dev->cam.cam_mode[i].sizeimage <
+			gspca_dev->cam.cam_mode[i].width *
+				gspca_dev->cam.cam_mode[i].height)
+		fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED;
+	fmtdesc->description[0] = fmtdesc->pixelformat & 0xff;
+	fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff;
+	fmtdesc->description[2] = (fmtdesc->pixelformat >> 16) & 0xff;
+	fmtdesc->description[3] = fmtdesc->pixelformat >> 24;
+	fmtdesc->description[4] = '\0';
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+			    struct v4l2_format *fmt)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	int mode;
+
+	mode = gspca_dev->curr_mode;
+	fmt->fmt.pix = gspca_dev->cam.cam_mode[mode];
+	/* some drivers use priv internally, zero it before giving it to
+	   userspace */
+	fmt->fmt.pix.priv = 0;
+	return 0;
+}
+
+static int try_fmt_vid_cap(struct gspca_dev *gspca_dev,
+			struct v4l2_format *fmt)
+{
+	int w, h, mode, mode2;
+
+	w = fmt->fmt.pix.width;
+	h = fmt->fmt.pix.height;
+
+#ifdef GSPCA_DEBUG
+	if (gspca_debug & D_CONF)
+		PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h);
+#endif
+	/* search the closest mode for width and height */
+	mode = wxh_to_mode(gspca_dev, w, h);
+
+	/* OK if right palette */
+	if (gspca_dev->cam.cam_mode[mode].pixelformat
+						!= fmt->fmt.pix.pixelformat) {
+
+		/* else, search the closest mode with the same pixel format */
+		mode2 = gspca_get_mode(gspca_dev, mode,
+					fmt->fmt.pix.pixelformat);
+		if (mode2 >= 0)
+			mode = mode2;
+/*		else
+			;		 * no chance, return this mode */
+	}
+	fmt->fmt.pix = gspca_dev->cam.cam_mode[mode];
+	/* some drivers use priv internally, zero it before giving it to
+	   userspace */
+	fmt->fmt.pix.priv = 0;
+	return mode;			/* used when s_fmt */
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file,
+			      void *priv,
+			      struct v4l2_format *fmt)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	int ret;
+
+	ret = try_fmt_vid_cap(gspca_dev, fmt);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+			    struct v4l2_format *fmt)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	int ret;
+
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+		return -ERESTARTSYS;
+
+	ret = try_fmt_vid_cap(gspca_dev, fmt);
+	if (ret < 0)
+		goto out;
+
+	if (gspca_dev->nframes != 0
+	    && fmt->fmt.pix.sizeimage > gspca_dev->frsz) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (ret == gspca_dev->curr_mode) {
+		ret = 0;
+		goto out;			/* same mode */
+	}
+
+	if (gspca_dev->streaming) {
+		ret = -EBUSY;
+		goto out;
+	}
+	gspca_dev->width = fmt->fmt.pix.width;
+	gspca_dev->height = fmt->fmt.pix.height;
+	gspca_dev->pixfmt = fmt->fmt.pix.pixelformat;
+	gspca_dev->curr_mode = ret;
+
+	ret = 0;
+out:
+	mutex_unlock(&gspca_dev->queue_lock);
+	return ret;
+}
+
+static int vidioc_enum_framesizes(struct file *file, void *priv,
+				  struct v4l2_frmsizeenum *fsize)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	int i;
+	__u32 index = 0;
+
+	for (i = 0; i < gspca_dev->cam.nmodes; i++) {
+		if (fsize->pixel_format !=
+				gspca_dev->cam.cam_mode[i].pixelformat)
+			continue;
+
+		if (fsize->index == index) {
+			fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+			fsize->discrete.width =
+				gspca_dev->cam.cam_mode[i].width;
+			fsize->discrete.height =
+				gspca_dev->cam.cam_mode[i].height;
+			return 0;
+		}
+		index++;
+	}
+
+	return -EINVAL;
+}
+
+static int vidioc_enum_frameintervals(struct file *filp, void *priv,
+				      struct v4l2_frmivalenum *fival)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(filp);
+	int mode = wxh_to_mode(gspca_dev, fival->width, fival->height);
+	__u32 i;
+
+	if (gspca_dev->cam.mode_framerates == NULL ||
+			gspca_dev->cam.mode_framerates[mode].nrates == 0)
+		return -EINVAL;
+
+	if (fival->pixel_format !=
+			gspca_dev->cam.cam_mode[mode].pixelformat)
+		return -EINVAL;
+
+	for (i = 0; i < gspca_dev->cam.mode_framerates[mode].nrates; i++) {
+		if (fival->index == i) {
+			fival->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+			fival->discrete.numerator = 1;
+			fival->discrete.denominator =
+				gspca_dev->cam.mode_framerates[mode].rates[i];
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static void gspca_release(struct v4l2_device *v4l2_device)
+{
+	struct gspca_dev *gspca_dev =
+		container_of(v4l2_device, struct gspca_dev, v4l2_dev);
+
+	v4l2_ctrl_handler_free(gspca_dev->vdev.ctrl_handler);
+	v4l2_device_unregister(&gspca_dev->v4l2_dev);
+	kfree(gspca_dev->usb_buf);
+	kfree(gspca_dev);
+}
+
+static int dev_open(struct file *file)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+
+	PDEBUG(D_STREAM, "[%s] open", current->comm);
+
+	/* protect the subdriver against rmmod */
+	if (!try_module_get(gspca_dev->module))
+		return -ENODEV;
+
+#ifdef GSPCA_DEBUG
+	/* activate the v4l2 debug */
+	if (gspca_debug & D_V4L2)
+		gspca_dev->vdev.debug |= V4L2_DEBUG_IOCTL
+					| V4L2_DEBUG_IOCTL_ARG;
+	else
+		gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL
+					| V4L2_DEBUG_IOCTL_ARG);
+#endif
+	return v4l2_fh_open(file);
+}
+
+static int dev_close(struct file *file)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+
+	PDEBUG(D_STREAM, "[%s] close", current->comm);
+
+	/* Needed for gspca_stream_off, always lock before queue_lock! */
+	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+		return -ERESTARTSYS;
+
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock)) {
+		mutex_unlock(&gspca_dev->usb_lock);
+		return -ERESTARTSYS;
+	}
+
+	/* if the file did the capture, free the streaming resources */
+	if (gspca_dev->capt_file == file) {
+		if (gspca_dev->streaming)
+			gspca_stream_off(gspca_dev);
+		frame_free(gspca_dev);
+	}
+	module_put(gspca_dev->module);
+	mutex_unlock(&gspca_dev->queue_lock);
+	mutex_unlock(&gspca_dev->usb_lock);
+
+	PDEBUG(D_STREAM, "close done");
+
+	return v4l2_fh_release(file);
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+			   struct v4l2_capability *cap)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+
+	strlcpy((char *) cap->driver, gspca_dev->sd_desc->name,
+			sizeof cap->driver);
+	if (gspca_dev->dev->product != NULL) {
+		strlcpy((char *) cap->card, gspca_dev->dev->product,
+			sizeof cap->card);
+	} else {
+		snprintf((char *) cap->card, sizeof cap->card,
+			"USB Camera (%04x:%04x)",
+			le16_to_cpu(gspca_dev->dev->descriptor.idVendor),
+			le16_to_cpu(gspca_dev->dev->descriptor.idProduct));
+	}
+	usb_make_path(gspca_dev->dev, (char *) cap->bus_info,
+			sizeof(cap->bus_info));
+	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE
+			  | V4L2_CAP_STREAMING
+			  | V4L2_CAP_READWRITE;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+	return 0;
+}
+
+static int get_ctrl(struct gspca_dev *gspca_dev,
+				   int id)
+{
+	const struct ctrl *ctrls;
+	int i;
+
+	for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;
+	     i < gspca_dev->sd_desc->nctrls;
+	     i++, ctrls++) {
+		if (gspca_dev->ctrl_dis & (1 << i))
+			continue;
+		if (id == ctrls->qctrl.id)
+			return i;
+	}
+	return -1;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+			   struct v4l2_queryctrl *q_ctrl)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	const struct ctrl *ctrls;
+	struct gspca_ctrl *gspca_ctrl;
+	int i, idx;
+	u32 id;
+
+	id = q_ctrl->id;
+	if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+		id &= V4L2_CTRL_ID_MASK;
+		id++;
+		idx = -1;
+		for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
+			if (gspca_dev->ctrl_dis & (1 << i))
+				continue;
+			if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id)
+				continue;
+			if (idx >= 0
+			 && gspca_dev->sd_desc->ctrls[i].qctrl.id
+				    > gspca_dev->sd_desc->ctrls[idx].qctrl.id)
+				continue;
+			idx = i;
+		}
+	} else {
+		idx = get_ctrl(gspca_dev, id);
+	}
+	if (idx < 0)
+		return -EINVAL;
+	ctrls = &gspca_dev->sd_desc->ctrls[idx];
+	memcpy(q_ctrl, &ctrls->qctrl, sizeof *q_ctrl);
+	if (gspca_dev->cam.ctrls != NULL) {
+		gspca_ctrl = &gspca_dev->cam.ctrls[idx];
+		q_ctrl->default_value = gspca_ctrl->def;
+		q_ctrl->minimum = gspca_ctrl->min;
+		q_ctrl->maximum = gspca_ctrl->max;
+	}
+	if (gspca_dev->ctrl_inac & (1 << idx))
+		q_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+	return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *ctrl)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	const struct ctrl *ctrls;
+	struct gspca_ctrl *gspca_ctrl;
+	int idx;
+
+	idx = get_ctrl(gspca_dev, ctrl->id);
+	if (idx < 0)
+		return -EINVAL;
+	if (gspca_dev->ctrl_inac & (1 << idx))
+		return -EINVAL;
+	ctrls = &gspca_dev->sd_desc->ctrls[idx];
+	if (gspca_dev->cam.ctrls != NULL) {
+		gspca_ctrl = &gspca_dev->cam.ctrls[idx];
+		if (ctrl->value < gspca_ctrl->min
+		    || ctrl->value > gspca_ctrl->max)
+			return -ERANGE;
+	} else {
+		gspca_ctrl = NULL;
+		if (ctrl->value < ctrls->qctrl.minimum
+		    || ctrl->value > ctrls->qctrl.maximum)
+			return -ERANGE;
+	}
+	PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
+	gspca_dev->usb_err = 0;
+	if (ctrls->set != NULL)
+		return ctrls->set(gspca_dev, ctrl->value);
+	if (gspca_ctrl != NULL) {
+		gspca_ctrl->val = ctrl->value;
+		if (ctrls->set_control != NULL
+		 && gspca_dev->streaming)
+			ctrls->set_control(gspca_dev);
+	}
+	return gspca_dev->usb_err;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *ctrl)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	const struct ctrl *ctrls;
+	int idx;
+
+	idx = get_ctrl(gspca_dev, ctrl->id);
+	if (idx < 0)
+		return -EINVAL;
+	ctrls = &gspca_dev->sd_desc->ctrls[idx];
+
+	gspca_dev->usb_err = 0;
+	if (ctrls->get != NULL)
+		return ctrls->get(gspca_dev, &ctrl->value);
+	if (gspca_dev->cam.ctrls != NULL)
+		ctrl->value = gspca_dev->cam.ctrls[idx].val;
+	return 0;
+}
+
+static int vidioc_querymenu(struct file *file, void *priv,
+			    struct v4l2_querymenu *qmenu)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+
+	if (!gspca_dev->sd_desc->querymenu)
+		return -ENOTTY;
+	return gspca_dev->sd_desc->querymenu(gspca_dev, qmenu);
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+				struct v4l2_input *input)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+
+	if (input->index != 0)
+		return -EINVAL;
+	input->type = V4L2_INPUT_TYPE_CAMERA;
+	input->status = gspca_dev->cam.input_flags;
+	strlcpy(input->name, gspca_dev->sd_desc->name,
+		sizeof input->name);
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	if (i > 0)
+		return -EINVAL;
+	return (0);
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *rb)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	int i, ret = 0, streaming;
+
+	i = rb->memory;			/* (avoid compilation warning) */
+	switch (i) {
+	case GSPCA_MEMORY_READ:			/* (internal call) */
+	case V4L2_MEMORY_MMAP:
+	case V4L2_MEMORY_USERPTR:
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+		return -ERESTARTSYS;
+
+	if (gspca_dev->memory != GSPCA_MEMORY_NO
+	    && gspca_dev->memory != GSPCA_MEMORY_READ
+	    && gspca_dev->memory != rb->memory) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	/* only one file may do the capture */
+	if (gspca_dev->capt_file != NULL
+	    && gspca_dev->capt_file != file) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	/* if allocated, the buffers must not be mapped */
+	for (i = 0; i < gspca_dev->nframes; i++) {
+		if (gspca_dev->frame[i].vma_use_count) {
+			ret = -EBUSY;
+			goto out;
+		}
+	}
+
+	/* stop streaming */
+	streaming = gspca_dev->streaming;
+	if (streaming) {
+		gspca_stream_off(gspca_dev);
+
+		/* Don't restart the stream when switching from read
+		 * to mmap mode */
+		if (gspca_dev->memory == GSPCA_MEMORY_READ)
+			streaming = 0;
+	}
+
+	/* free the previous allocated buffers, if any */
+	if (gspca_dev->nframes != 0)
+		frame_free(gspca_dev);
+	if (rb->count == 0)			/* unrequest */
+		goto out;
+	ret = frame_alloc(gspca_dev, file, rb->memory, rb->count);
+	if (ret == 0) {
+		rb->count = gspca_dev->nframes;
+		if (streaming)
+			ret = gspca_init_transfer(gspca_dev);
+	}
+out:
+	mutex_unlock(&gspca_dev->queue_lock);
+	PDEBUG(D_STREAM, "reqbufs st:%d c:%d", ret, rb->count);
+	return ret;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+			   struct v4l2_buffer *v4l2_buf)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	struct gspca_frame *frame;
+
+	if (v4l2_buf->index < 0
+	    || v4l2_buf->index >= gspca_dev->nframes)
+		return -EINVAL;
+
+	frame = &gspca_dev->frame[v4l2_buf->index];
+	memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
+	return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type buf_type)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	int ret;
+
+	if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+		return -ERESTARTSYS;
+
+	/* check the capture file */
+	if (gspca_dev->capt_file != file) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	if (gspca_dev->nframes == 0
+	    || !(gspca_dev->frame[0].v4l2_buf.flags & V4L2_BUF_FLAG_QUEUED)) {
+		ret = -EINVAL;
+		goto out;
+	}
+	if (!gspca_dev->streaming) {
+		ret = gspca_init_transfer(gspca_dev);
+		if (ret < 0)
+			goto out;
+	}
+#ifdef GSPCA_DEBUG
+	if (gspca_debug & D_STREAM) {
+		PDEBUG_MODE("stream on OK",
+			gspca_dev->pixfmt,
+			gspca_dev->width,
+			gspca_dev->height);
+	}
+#endif
+	ret = 0;
+out:
+	mutex_unlock(&gspca_dev->queue_lock);
+	return ret;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+				enum v4l2_buf_type buf_type)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	int i, ret;
+
+	if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+		return -ERESTARTSYS;
+
+	if (!gspca_dev->streaming) {
+		ret = 0;
+		goto out;
+	}
+
+	/* check the capture file */
+	if (gspca_dev->capt_file != file) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	/* stop streaming */
+	gspca_stream_off(gspca_dev);
+	/* In case another thread is waiting in dqbuf */
+	wake_up_interruptible(&gspca_dev->wq);
+
+	/* empty the transfer queues */
+	for (i = 0; i < gspca_dev->nframes; i++)
+		gspca_dev->frame[i].v4l2_buf.flags &= ~BUF_ALL_FLAGS;
+	atomic_set(&gspca_dev->fr_q, 0);
+	atomic_set(&gspca_dev->fr_i, 0);
+	gspca_dev->fr_o = 0;
+	ret = 0;
+out:
+	mutex_unlock(&gspca_dev->queue_lock);
+	return ret;
+}
+
+static int vidioc_g_jpegcomp(struct file *file, void *priv,
+			struct v4l2_jpegcompression *jpegcomp)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+
+	gspca_dev->usb_err = 0;
+	return gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp);
+}
+
+static int vidioc_s_jpegcomp(struct file *file, void *priv,
+			struct v4l2_jpegcompression *jpegcomp)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+
+	gspca_dev->usb_err = 0;
+	return gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);
+}
+
+static int vidioc_g_parm(struct file *filp, void *priv,
+			struct v4l2_streamparm *parm)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(filp);
+
+	parm->parm.capture.readbuffers = gspca_dev->nbufread;
+
+	if (gspca_dev->sd_desc->get_streamparm) {
+		gspca_dev->usb_err = 0;
+		gspca_dev->sd_desc->get_streamparm(gspca_dev, parm);
+		return gspca_dev->usb_err;
+	}
+	return 0;
+}
+
+static int vidioc_s_parm(struct file *filp, void *priv,
+			struct v4l2_streamparm *parm)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(filp);
+	int n;
+
+	n = parm->parm.capture.readbuffers;
+	if (n == 0 || n >= GSPCA_MAX_FRAMES)
+		parm->parm.capture.readbuffers = gspca_dev->nbufread;
+	else
+		gspca_dev->nbufread = n;
+
+	if (gspca_dev->sd_desc->set_streamparm) {
+		gspca_dev->usb_err = 0;
+		gspca_dev->sd_desc->set_streamparm(gspca_dev, parm);
+		return gspca_dev->usb_err;
+	}
+
+	return 0;
+}
+
+static int dev_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	struct gspca_frame *frame;
+	struct page *page;
+	unsigned long addr, start, size;
+	int i, ret;
+
+	start = vma->vm_start;
+	size = vma->vm_end - vma->vm_start;
+	PDEBUG(D_STREAM, "mmap start:%08x size:%d", (int) start, (int) size);
+
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+		return -ERESTARTSYS;
+	if (gspca_dev->capt_file != file) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	frame = NULL;
+	for (i = 0; i < gspca_dev->nframes; ++i) {
+		if (gspca_dev->frame[i].v4l2_buf.memory != V4L2_MEMORY_MMAP) {
+			PDEBUG(D_STREAM, "mmap bad memory type");
+			break;
+		}
+		if ((gspca_dev->frame[i].v4l2_buf.m.offset >> PAGE_SHIFT)
+						== vma->vm_pgoff) {
+			frame = &gspca_dev->frame[i];
+			break;
+		}
+	}
+	if (frame == NULL) {
+		PDEBUG(D_STREAM, "mmap no frame buffer found");
+		ret = -EINVAL;
+		goto out;
+	}
+	if (size != frame->v4l2_buf.length) {
+		PDEBUG(D_STREAM, "mmap bad size");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/*
+	 * - VM_IO marks the area as being a mmaped region for I/O to a
+	 *   device. It also prevents the region from being core dumped.
+	 */
+	vma->vm_flags |= VM_IO;
+
+	addr = (unsigned long) frame->data;
+	while (size > 0) {
+		page = vmalloc_to_page((void *) addr);
+		ret = vm_insert_page(vma, start, page);
+		if (ret < 0)
+			goto out;
+		start += PAGE_SIZE;
+		addr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+
+	vma->vm_ops = &gspca_vm_ops;
+	vma->vm_private_data = frame;
+	gspca_vm_open(vma);
+	ret = 0;
+out:
+	mutex_unlock(&gspca_dev->queue_lock);
+	return ret;
+}
+
+static int frame_ready_nolock(struct gspca_dev *gspca_dev, struct file *file,
+				enum v4l2_memory memory)
+{
+	if (!gspca_dev->present)
+		return -ENODEV;
+	if (gspca_dev->capt_file != file || gspca_dev->memory != memory ||
+			!gspca_dev->streaming)
+		return -EINVAL;
+
+	/* check if a frame is ready */
+	return gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i);
+}
+
+static int frame_ready(struct gspca_dev *gspca_dev, struct file *file,
+			enum v4l2_memory memory)
+{
+	int ret;
+
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+		return -ERESTARTSYS;
+	ret = frame_ready_nolock(gspca_dev, file, memory);
+	mutex_unlock(&gspca_dev->queue_lock);
+	return ret;
+}
+
+/*
+ * dequeue a video buffer
+ *
+ * If nonblock_ing is false, block until a buffer is available.
+ */
+static int vidioc_dqbuf(struct file *file, void *priv,
+			struct v4l2_buffer *v4l2_buf)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	struct gspca_frame *frame;
+	int i, j, ret;
+
+	PDEBUG(D_FRAM, "dqbuf");
+
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+		return -ERESTARTSYS;
+
+	for (;;) {
+		ret = frame_ready_nolock(gspca_dev, file, v4l2_buf->memory);
+		if (ret < 0)
+			goto out;
+		if (ret > 0)
+			break;
+
+		mutex_unlock(&gspca_dev->queue_lock);
+
+		if (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+
+		/* wait till a frame is ready */
+		ret = wait_event_interruptible_timeout(gspca_dev->wq,
+			frame_ready(gspca_dev, file, v4l2_buf->memory),
+			msecs_to_jiffies(3000));
+		if (ret < 0)
+			return ret;
+		if (ret == 0)
+			return -EIO;
+
+		if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+			return -ERESTARTSYS;
+	}
+
+	i = gspca_dev->fr_o;
+	j = gspca_dev->fr_queue[i];
+	frame = &gspca_dev->frame[j];
+
+	gspca_dev->fr_o = (i + 1) % GSPCA_MAX_FRAMES;
+
+	frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
+	memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
+	PDEBUG(D_FRAM, "dqbuf %d", j);
+	ret = 0;
+
+	if (gspca_dev->memory == V4L2_MEMORY_USERPTR) {
+		if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr,
+				 frame->data,
+				 frame->v4l2_buf.bytesused)) {
+			PDEBUG(D_ERR|D_STREAM,
+				"dqbuf cp to user failed");
+			ret = -EFAULT;
+		}
+	}
+out:
+	mutex_unlock(&gspca_dev->queue_lock);
+
+	if (ret == 0 && gspca_dev->sd_desc->dq_callback) {
+		mutex_lock(&gspca_dev->usb_lock);
+		gspca_dev->usb_err = 0;
+		if (gspca_dev->present)
+			gspca_dev->sd_desc->dq_callback(gspca_dev);
+		mutex_unlock(&gspca_dev->usb_lock);
+	}
+
+	return ret;
+}
+
+/*
+ * queue a video buffer
+ *
+ * Attempting to queue a buffer that has already been
+ * queued will return -EINVAL.
+ */
+static int vidioc_qbuf(struct file *file, void *priv,
+			struct v4l2_buffer *v4l2_buf)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	struct gspca_frame *frame;
+	int i, index, ret;
+
+	PDEBUG(D_FRAM, "qbuf %d", v4l2_buf->index);
+
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+		return -ERESTARTSYS;
+
+	index = v4l2_buf->index;
+	if ((unsigned) index >= gspca_dev->nframes) {
+		PDEBUG(D_FRAM,
+			"qbuf idx %d >= %d", index, gspca_dev->nframes);
+		ret = -EINVAL;
+		goto out;
+	}
+	if (v4l2_buf->memory != gspca_dev->memory) {
+		PDEBUG(D_FRAM, "qbuf bad memory type");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	frame = &gspca_dev->frame[index];
+	if (frame->v4l2_buf.flags & BUF_ALL_FLAGS) {
+		PDEBUG(D_FRAM, "qbuf bad state");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	frame->v4l2_buf.flags |= V4L2_BUF_FLAG_QUEUED;
+
+	if (frame->v4l2_buf.memory == V4L2_MEMORY_USERPTR) {
+		frame->v4l2_buf.m.userptr = v4l2_buf->m.userptr;
+		frame->v4l2_buf.length = v4l2_buf->length;
+	}
+
+	/* put the buffer in the 'queued' queue */
+	i = atomic_read(&gspca_dev->fr_q);
+	gspca_dev->fr_queue[i] = index;
+	atomic_set(&gspca_dev->fr_q, (i + 1) % GSPCA_MAX_FRAMES);
+
+	v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
+	v4l2_buf->flags &= ~V4L2_BUF_FLAG_DONE;
+	ret = 0;
+out:
+	mutex_unlock(&gspca_dev->queue_lock);
+	return ret;
+}
+
+/*
+ * allocate the resources for read()
+ */
+static int read_alloc(struct gspca_dev *gspca_dev,
+			struct file *file)
+{
+	struct v4l2_buffer v4l2_buf;
+	int i, ret;
+
+	PDEBUG(D_STREAM, "read alloc");
+
+	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+		return -ERESTARTSYS;
+
+	if (gspca_dev->nframes == 0) {
+		struct v4l2_requestbuffers rb;
+
+		memset(&rb, 0, sizeof rb);
+		rb.count = gspca_dev->nbufread;
+		rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		rb.memory = GSPCA_MEMORY_READ;
+		ret = vidioc_reqbufs(file, gspca_dev, &rb);
+		if (ret != 0) {
+			PDEBUG(D_STREAM, "read reqbuf err %d", ret);
+			goto out;
+		}
+		memset(&v4l2_buf, 0, sizeof v4l2_buf);
+		v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		v4l2_buf.memory = GSPCA_MEMORY_READ;
+		for (i = 0; i < gspca_dev->nbufread; i++) {
+			v4l2_buf.index = i;
+			ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf);
+			if (ret != 0) {
+				PDEBUG(D_STREAM, "read qbuf err: %d", ret);
+				goto out;
+			}
+		}
+	}
+
+	/* start streaming */
+	ret = vidioc_streamon(file, gspca_dev, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	if (ret != 0)
+		PDEBUG(D_STREAM, "read streamon err %d", ret);
+out:
+	mutex_unlock(&gspca_dev->usb_lock);
+	return ret;
+}
+
+static unsigned int dev_poll(struct file *file, poll_table *wait)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	unsigned long req_events = poll_requested_events(wait);
+	int ret = 0;
+
+	PDEBUG(D_FRAM, "poll");
+
+	if (req_events & POLLPRI)
+		ret |= v4l2_ctrl_poll(file, wait);
+
+	if (req_events & (POLLIN | POLLRDNORM)) {
+		/* if reqbufs is not done, the user would use read() */
+		if (gspca_dev->memory == GSPCA_MEMORY_NO) {
+			if (read_alloc(gspca_dev, file) != 0) {
+				ret |= POLLERR;
+				goto out;
+			}
+		}
+
+		poll_wait(file, &gspca_dev->wq, wait);
+
+		/* check if an image has been received */
+		if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0) {
+			ret |= POLLERR;
+			goto out;
+		}
+		if (gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i))
+			ret |= POLLIN | POLLRDNORM;
+		mutex_unlock(&gspca_dev->queue_lock);
+	}
+
+out:
+	if (!gspca_dev->present)
+		ret |= POLLHUP;
+
+	return ret;
+}
+
+static ssize_t dev_read(struct file *file, char __user *data,
+		    size_t count, loff_t *ppos)
+{
+	struct gspca_dev *gspca_dev = video_drvdata(file);
+	struct gspca_frame *frame;
+	struct v4l2_buffer v4l2_buf;
+	struct timeval timestamp;
+	int n, ret, ret2;
+
+	PDEBUG(D_FRAM, "read (%zd)", count);
+	if (gspca_dev->memory == GSPCA_MEMORY_NO) { /* first time ? */
+		ret = read_alloc(gspca_dev, file);
+		if (ret != 0)
+			return ret;
+	}
+
+	/* get a frame */
+	timestamp = ktime_to_timeval(ktime_get());
+	timestamp.tv_sec--;
+	n = 2;
+	for (;;) {
+		memset(&v4l2_buf, 0, sizeof v4l2_buf);
+		v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		v4l2_buf.memory = GSPCA_MEMORY_READ;
+		ret = vidioc_dqbuf(file, gspca_dev, &v4l2_buf);
+		if (ret != 0) {
+			PDEBUG(D_STREAM, "read dqbuf err %d", ret);
+			return ret;
+		}
+
+		/* if the process slept for more than 1 second,
+		 * get a newer frame */
+		frame = &gspca_dev->frame[v4l2_buf.index];
+		if (--n < 0)
+			break;			/* avoid infinite loop */
+		if (frame->v4l2_buf.timestamp.tv_sec >= timestamp.tv_sec)
+			break;
+		ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf);
+		if (ret != 0) {
+			PDEBUG(D_STREAM, "read qbuf err %d", ret);
+			return ret;
+		}
+	}
+
+	/* copy the frame */
+	if (count > frame->v4l2_buf.bytesused)
+		count = frame->v4l2_buf.bytesused;
+	ret = copy_to_user(data, frame->data, count);
+	if (ret != 0) {
+		PDEBUG(D_ERR|D_STREAM,
+			"read cp to user lack %d / %zd", ret, count);
+		ret = -EFAULT;
+		goto out;
+	}
+	ret = count;
+out:
+	/* in each case, requeue the buffer */
+	ret2 = vidioc_qbuf(file, gspca_dev, &v4l2_buf);
+	if (ret2 != 0)
+		return ret2;
+	return ret;
+}
+
+static struct v4l2_file_operations dev_fops = {
+	.owner = THIS_MODULE,
+	.open = dev_open,
+	.release = dev_close,
+	.read = dev_read,
+	.mmap = dev_mmap,
+	.unlocked_ioctl = video_ioctl2,
+	.poll	= dev_poll,
+};
+
+static const struct v4l2_ioctl_ops dev_ioctl_ops = {
+	.vidioc_querycap	= vidioc_querycap,
+	.vidioc_dqbuf		= vidioc_dqbuf,
+	.vidioc_qbuf		= vidioc_qbuf,
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,
+	.vidioc_streamon	= vidioc_streamon,
+	.vidioc_queryctrl	= vidioc_queryctrl,
+	.vidioc_g_ctrl		= vidioc_g_ctrl,
+	.vidioc_s_ctrl		= vidioc_s_ctrl,
+	.vidioc_querymenu	= vidioc_querymenu,
+	.vidioc_enum_input	= vidioc_enum_input,
+	.vidioc_g_input		= vidioc_g_input,
+	.vidioc_s_input		= vidioc_s_input,
+	.vidioc_reqbufs		= vidioc_reqbufs,
+	.vidioc_querybuf	= vidioc_querybuf,
+	.vidioc_streamoff	= vidioc_streamoff,
+	.vidioc_g_jpegcomp	= vidioc_g_jpegcomp,
+	.vidioc_s_jpegcomp	= vidioc_s_jpegcomp,
+	.vidioc_g_parm		= vidioc_g_parm,
+	.vidioc_s_parm		= vidioc_s_parm,
+	.vidioc_enum_framesizes = vidioc_enum_framesizes,
+	.vidioc_enum_frameintervals = vidioc_enum_frameintervals,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register	= vidioc_g_register,
+	.vidioc_s_register	= vidioc_s_register,
+#endif
+	.vidioc_g_chip_ident	= vidioc_g_chip_ident,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct video_device gspca_template = {
+	.name = "gspca main driver",
+	.fops = &dev_fops,
+	.ioctl_ops = &dev_ioctl_ops,
+	.release = video_device_release_empty, /* We use v4l2_dev.release */
+};
+
+/* initialize the controls */
+static void ctrls_init(struct gspca_dev *gspca_dev)
+{
+	struct gspca_ctrl *ctrl;
+	int i;
+
+	for (i = 0, ctrl = gspca_dev->cam.ctrls;
+	     i < gspca_dev->sd_desc->nctrls;
+	     i++, ctrl++) {
+		ctrl->def = gspca_dev->sd_desc->ctrls[i].qctrl.default_value;
+		ctrl->val = ctrl->def;
+		ctrl->min = gspca_dev->sd_desc->ctrls[i].qctrl.minimum;
+		ctrl->max = gspca_dev->sd_desc->ctrls[i].qctrl.maximum;
+	}
+}
+
+/*
+ * probe and create a new gspca device
+ *
+ * This function must be called by the sub-driver when it is
+ * called for probing a new device.
+ */
+int gspca_dev_probe2(struct usb_interface *intf,
+		const struct usb_device_id *id,
+		const struct sd_desc *sd_desc,
+		int dev_size,
+		struct module *module)
+{
+	struct gspca_dev *gspca_dev;
+	struct usb_device *dev = interface_to_usbdev(intf);
+	int ret;
+
+	pr_info("%s-" GSPCA_VERSION " probing %04x:%04x\n",
+		sd_desc->name, id->idVendor, id->idProduct);
+
+	/* create the device */
+	if (dev_size < sizeof *gspca_dev)
+		dev_size = sizeof *gspca_dev;
+	gspca_dev = kzalloc(dev_size, GFP_KERNEL);
+	if (!gspca_dev) {
+		pr_err("couldn't kza